diff --git a/.cargo/config.toml b/.cargo/config.toml index f113e9114ace..1b8ffe1a1c82 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -8,3 +8,4 @@ rustdocflags = [ # Needed for musl builds so user doesn't have to install musl-tools. CC_x86_64_unknown_linux_musl = { value = ".cargo/musl-gcc", force = true, relative = true } CXX_x86_64_unknown_linux_musl = { value = ".cargo/musl-g++", force = true, relative = true } +CARGO_WORKSPACE_ROOT_DIR = { value = "", relative = true } diff --git a/.config/lychee.toml b/.config/lychee.toml index 1de9fcd559dd..b1f08de33340 100644 --- a/.config/lychee.toml +++ b/.config/lychee.toml @@ -18,7 +18,10 @@ accept = [ "429", ] -exclude_path = ["./target"] +exclude_path = [ + "./prdoc", + "./target", +] exclude = [ # Place holders (no need to fix these): @@ -32,7 +35,6 @@ exclude = [ "https://github.com/paritytech/polkadot-sdk/substrate/frame/timestamp", "https://github.com/paritytech/substrate/frame/fast-unstake", "https://github.com/zkcrypto/bls12_381/blob/e224ad4ea1babfc582ccd751c2bf128611d10936/src/test-data/mod.rs", - "https://polkadot-try-runtime-node.parity-chains.parity.io/", "https://polkadot.network/the-path-of-a-parachain-block/", "https://research.web3.foundation/en/latest/polkadot/NPoS/3.%20Balancing.html", "https://research.web3.foundation/en/latest/polkadot/Token%20Economics.html#inflation-model", @@ -41,6 +43,7 @@ exclude = [ "https://research.web3.foundation/en/latest/polkadot/overview/2-token-economics.html#inflation-model", "https://research.web3.foundation/en/latest/polkadot/slashing/npos.html", "https://rpc.polkadot.io/", + "https://try-runtime.polkadot.io/", "https://w3f.github.io/parachain-implementers-guide/node/approval/approval-distribution.html", "https://w3f.github.io/parachain-implementers-guide/node/index.html", "https://w3f.github.io/parachain-implementers-guide/protocol-chain-selection.html", diff --git a/.config/zepter.yaml b/.config/zepter.yaml index 9b3bd9d618c1..7a67ba2695cf 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,riscv,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/CODEOWNERS b/.github/CODEOWNERS index 4fc5b97caae0..d13add97d419 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -64,7 +64,8 @@ /substrate/primitives/merkle-mountain-range/ @acatangiu # Contracts -/substrate/frame/contracts/ @athei @paritytech/docs-audit +/substrate/frame/contracts/ @paritytech/smart-contracts @paritytech/docs-audit +/substrate/frame/revive/ @paritytech/smart-contracts @paritytech/docs-audit # NPoS and election /substrate/frame/election-provider-multi-phase/ @paritytech/staking-core @paritytech/docs-audit diff --git a/.github/actions/build-push-image/action.yml b/.github/actions/build-push-image/action.yml new file mode 100644 index 000000000000..fead9cfe3369 --- /dev/null +++ b/.github/actions/build-push-image/action.yml @@ -0,0 +1,47 @@ +name: 'build and push image' +inputs: + dockerfile: + description: "dockerfile to build" + required: true + image-name: + description: "" + required: true +outputs: + branch: + description: 'Branch name for the PR' + value: ${{ steps.branch.outputs.branch }} + + +runs: + using: "composite" + steps: + + # gcloud + # https://github.com/paritytech/ci_cd/wiki/GitHub:-Push-Docker-image-to-GCP-Registry + - name: "Set up Cloud SDK" + uses: "google-github-actions/setup-gcloud@v2" + - name: "gcloud info" + shell: bash + run: "gcloud info" + - name: "Auth in gcloud registry" + shell: bash + run: "gcloud auth configure-docker europe-docker.pkg.dev --quiet" + + - name: build + shell: bash + env: + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.105" + run: | + export BRANCH_NAME=${{ github.head_ref || github.ref_name }} + export DOCKER_IMAGES_VERSION=${BRANCH_NAME/\//-} + if [[ ${{ github.event_name }} == "merge_group" ]]; then export DOCKER_IMAGES_VERSION="${GITHUB_SHA::8}"; fi + docker build \ + --build-arg VCS_REF="${GITHUB_SHA}" \ + --build-arg BUILD_DATE="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" \ + --build-arg IMAGE_NAME="${{ inputs.image-name }}" \ + --build-arg ZOMBIENET_IMAGE="${ZOMBIENET_IMAGE}" \ + -t "${{ inputs.image-name }}:$DOCKER_IMAGES_VERSION" \ + -f ${{ inputs.dockerfile }} \ + . + docker push "${{ inputs.image-name }}:$DOCKER_IMAGES_VERSION" + diff --git a/.github/actions/cargo-check-runtimes/action.yml b/.github/actions/cargo-check-runtimes/action.yml new file mode 100644 index 000000000000..869f17661e4a --- /dev/null +++ b/.github/actions/cargo-check-runtimes/action.yml @@ -0,0 +1,22 @@ +name: 'cargo check runtimes' +description: 'Runs `cargo check` for every directory in provided root.' +inputs: + root: + description: "Root directory. Expected to contain several cargo packages inside." + required: true +runs: + using: "composite" + steps: + - name: Check + shell: bash + run: | + mkdir -p ~/.forklift + cp .forklift/config.toml ~/.forklift/config.toml + cd ${{ inputs.root }} + for directory in $(echo */); do + echo "_____Running cargo check for ${directory} ______"; + cd ${directory}; + pwd; + SKIP_WASM_BUILD=1 forklift cargo check --locked; + cd ..; + done diff --git a/.github/actions/set-up-gh/action.yml b/.github/actions/set-up-gh/action.yml index fc16ce0b2633..4dc3af4a19f2 100644 --- a/.github/actions/set-up-gh/action.yml +++ b/.github/actions/set-up-gh/action.yml @@ -1,5 +1,5 @@ -name: 'install gh' -description: 'Install the gh cli in a debian based distro and switches to the PR branch.' +name: "install gh" +description: "Install the gh cli in a debian based distro and switches to the PR branch." inputs: pr-number: description: "Number of the PR" @@ -9,28 +9,20 @@ inputs: required: true outputs: branch: - description: 'Branch name for the PR' + description: "Branch name for the PR" value: ${{ steps.branch.outputs.branch }} runs: using: "composite" steps: - - name: Instal gh cli - shell: bash - # Here it would get the script from previous step - run: | - (type -p wget >/dev/null || (apt update && apt-get install wget -y)) - mkdir -p -m 755 /etc/apt/keyrings - wget -qO- https://cli.github.com/packages/githubcli-archive-keyring.gpg | tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null - chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg - echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list > /dev/null - apt update - apt install gh -y - git config --global --add safe.directory '*' - - run: gh pr checkout ${{ inputs.pr-number }} - shell: bash - env: - GITHUB_TOKEN: ${{ inputs.GH_TOKEN }} - - name: Export branch name - shell: bash - run: echo "branch=$(git rev-parse --abbrev-ref HEAD)" >> "$GITHUB_OUTPUT" - id: branch + - name: Set up git + shell: bash + # Here it would get the script from previous step + run: git config --global --add safe.directory '*' + - run: gh pr checkout ${{ inputs.pr-number }} + shell: bash + env: + GITHUB_TOKEN: ${{ inputs.GH_TOKEN }} + - name: Export branch name + shell: bash + run: echo "branch=$(git rev-parse --abbrev-ref HEAD)" >> "$GITHUB_OUTPUT" + id: branch diff --git a/.github/codecov.yml b/.github/codecov.yml index ceceb9e63654..b237c9fe6b04 100644 --- a/.github/codecov.yml +++ b/.github/codecov.yml @@ -6,4 +6,10 @@ coverage: project: default: target: 1.0 - threshold: 2.0 \ No newline at end of file + threshold: 2.0 + +comment: + behavior: new + +fixes: + - "/__w/polkadot-sdk/polkadot-sdk/::" \ No newline at end of file diff --git a/.github/command-screnshot.png b/.github/command-screnshot.png deleted file mode 100644 index 1451fabca8b9..000000000000 Binary files a/.github/command-screnshot.png and /dev/null differ diff --git a/.github/commands-readme.md b/.github/commands-readme.md deleted file mode 100644 index 20644c048c60..000000000000 --- a/.github/commands-readme.md +++ /dev/null @@ -1,200 +0,0 @@ -# Running commands - -Command bot has been migrated, it is no longer a comment parser and now it is a GitHub action that works as a [`workflow_dispatch`](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch) event. - -## How to run an action - -To run an action, you need to go to the [_actions tab_](https://github.com/paritytech/polkadot-sdk/actions) and pick the one you desire to run. - -The current available command actions are: - -- [Command FMT](https://github.com/paritytech/polkadot-sdk/actions/workflows/command-fmt.yml) -- [Command Update UI](https://github.com/paritytech/polkadot-sdk/actions/workflows/command-update-ui.yml) -- [Command Sync](https://github.com/paritytech/polkadot-sdk/actions/workflows/command-sync.yml) -- [Command Bench](https://github.com/paritytech/polkadot-sdk/actions/workflows/command-bench.yml) -- [Command Bench All](https://github.com/paritytech/polkadot-sdk/actions/workflows/command-bench-all.yml) -- [Command Bench Overhead](https://github.com/paritytech/polkadot-sdk/actions/workflows/command-bench-overhead.yml) - -You need to select the action, and click on the dropdown that says: `Run workflow`. It is located in the upper right. - -If this dropdown is not visible, you may not have permission to run the action. Contact IT for help. - -![command screenshot](command-screnshot.png) - -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) - -### 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 - -### Bench - -Runs `benchmark pallet` or `benchmark overhead` against your PR and commits back updated weights. - -Posible combinations based on the `benchmark` dropdown. - -- `substrate-pallet`: Pallet Benchmark for Substrate for specific pallet - - Requires `Subcommand` to be `pallet` - - Requires `Runtime` to be `dev` - - Requires field `Pallet` to have an input that applies to `^([a-z_]+)([:]{2}[a-z_]+)?$` - - Requires `Target Directory` to be `substrate` -- `polkadot-pallet`: Pallet Benchmark for Polkadot for specific pallet - - Requires `Subcommand` to be one of the following: - - `pallet` - - `xcm` - - Requires `Runtime` to be one of the following: - - `rococo` - - `westend` - - Requires field `Pallet` to have an input that applies to `^([a-z_]+)([:]{2}[a-z_]+)?$` - - Requires `Target Directory` to be `polkadot` -- `cumulus-assets`: Pallet Benchmark for Cumulus assets - - Requires `Subcommand` to be one of the following: - - `pallet` - - `xcm` - - Requires `Runtime` to be one of the following: - - `asset-hub-westend` - - `asset-hub-rococo` - - Requires field `Pallet` to have an input that applies to `^([a-z_]+)([:]{2}[a-z_]+)?$` - - Requires `Runtime Dir` to be `assets` - - Requires `Target Directory` to be `cumulus` -- `cumulus-collectives`: Pallet Benchmark for Cumulus collectives - - Requires `Subcommand` to be one of the following: - - `pallet` - - `xcm` - - Requires `Runtime` to be `collectives-westend` - - Requires field `Pallet` to have an input that applies to `^([a-z_]+)([:]{2}[a-z_]+)?$` - - Requires `Runtime Dir` to be `collectives` - - Requires `Target Directory` to be `cumulus` -- `cumulus-coretime`: Pallet Benchmark for Cumulus coretime - - Requires `Subcommand` to be one of the following: - - `pallet` - - `xcm` - - Requires `Runtime` to be one of the following: - - `coretime-rococo` - - `coretime-westend` - - Requires field `Pallet` to have an input that applies to `^([a-z_]+)([:]{2}[a-z_]+)?$` - - Requires `Runtime Dir` to be `coretime` - - Requires `Target Directory` to be `cumulus` -- `cumulus-bridge-hubs`: Pallet Benchmark for Cumulus bridge-hubs - - Requires `Subcommand` to be one of the following: - - `pallet` - - `xcm` - - Requires `Runtime` to be one of the following: - - `bridge-hub-rococo` - - `bridge-hub-westend` - - Requires field `Pallet` to have an input that applies to `^([a-z_]+)([:]{2}[a-z_]+)?$` - - Requires `Runtime Dir` to be `bridge-hub` - - Requires `Target Directory` to be `cumulus` -- `cumulus-contracts`: Pallet Benchmark for Cumulus contracts - - Requires `Subcommand` to be one of the following: - - `pallet` - - `xcm` - - Requires `Runtime` to be one `contracts-rococo` - - Requires field `Pallet` to have an input that applies to `^([a-z_]+)([:]{2}[a-z_]+)?$` - - Requires `Runtime Dir` to be `contracts` - - Requires `Target Directory` to be `cumulus` -- `cumulus-glutton`: Pallet Benchmark for Cumulus glutton - - Requires `Subcommand` to be `pallet` - - Requires `Runtime` to be one of the following: - - `glutton-westend` - - `glutton-westend-dev-1300` - - Requires field `Pallet` to have an input that applies to `^([a-z_]+)([:]{2}[a-z_]+)?$` - - Requires `Runtime Dir` to be `glutton` - - Requires `Target Directory` to be `cumulus` -- `cumulus-starters`: Pallet Benchmark for Cumulus starters - - Requires `Subcommand` to be one of the following: - - `pallet` - - `xcm` - - Requires `Runtime` to be one of the following: - - `seedling` - - `shell` - - Requires field `Pallet` to have an input that applies to `^([a-z_]+)([:]{2}[a-z_]+)?$` - - Requires `Runtime Dir` to be `starters` - - Requires `Target Directory` to be `cumulus` -- `cumulus-people`: Pallet Benchmark for Cumulus people - - Requires `Subcommand` to be one of the following: - - `pallet` - - `xcm` - - Requires `Runtime` to be one of the following: - - `people-westend` - - `people-rococo` - - Requires field `Pallet` to have an input that applies to `^([a-z_]+)([:]{2}[a-z_]+)?$` - - Requires `Runtime Dir` to be `people` - - Requires `Target Directory` to be `cumulus` -- `cumulus-testing`: Pallet Benchmark for Cumulus testing - - Requires `Subcommand` to be one of the following: - - `pallet` - - `xcm` - - Requires `Runtime` to be one of the following: - - `penpal` - - `rococo-parachain` - - Requires field `Pallet` to have an input that applies to `^([a-z_]+)([:]{2}[a-z_]+)?$` - - Requires `Runtime Dir` to be `testing` - - Requires `Target Directory` to be `cumulus` - -### Bench-all - -This is a wrapper to run `bench` for all pallets. - -Posible combinations based on the `benchmark` dropdown. - -- `pallet`: Benchmark for Substrate/Polkadot/Cumulus/Trappist for specific pallet - - Requires field `Pallet` to have an input that applies to `^([a-z_]+)([:]{2}[a-z_]+)?$` -- `substrate`: Pallet + Overhead + Machine Benchmark for Substrate for all pallets - - Requires `Target Directory` to be `substrate` -- `polkadot`: Pallet + Overhead Benchmark for Polkadot - - Requires `Runtime` to be one of the following: - - `rococo` - - `westend` - - Requires `Target Directory` to be `polkadot` -- `cumulus`: Pallet Benchmark for Cumulus - - Requires `Runtime` to be one of the following: - - `rococo` - - `westend` - - `asset-hub-kusama` - - `asset-hub-polkadot` - - `asset-hub-rococo` - - `asset-hub-westend` - - `bridge-hub-kusama` - - `bridge-hub-polkadot` - - `bridge-hub-rococo` - - `bridge-hub-westend` - - `collectives-polkadot` - - `collectives-westend` - - `coretime-rococo` - - `coretime-westend` - - `contracts-rococo` - - `glutton-kusama` - - `glutton-westend` - - `people-rococo` - - `people-westend` - - Requires `Target Directory` to be `cumulus` - -### Bench-overhead - -Run benchmarks overhead and commit back results to PR. - -Posible combinations based on the `benchmark` dropdown. - -- `default`: Runs `benchmark overhead` and commits back to PR the updated `extrinsic_weights.rs` files - - Requires `Runtime` to be one of the following: - - `rococo` - - `westend` - - Requires `Target directory` to be `polkadot` -- `substrate`: Runs `benchmark overhead` and commits back to PR the updated `extrinsic_weights.rs` files - - Requires `Target directory` to be `substrate` -- `cumulus`: Runs `benchmark overhead` and commits back to PR the updated `extrinsic_weights.rs` files - - Requires `Runtime` to be one of the following: - - `asset-hub-rococo` - - `asset-hub-westend` - - Requires `Target directory` to be `cumulus` - -## 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. - -This will use a file from a specified branch. diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3277a6e4607a..12f81b04d3a1 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,13 +5,17 @@ updates: directory: '/' labels: ["A1-insubstantial", "R0-silent"] schedule: - interval: daily + interval: weekly + groups: + ci_dependencies: + patterns: + - "*" # Update Rust dependencies: - package-ecosystem: "cargo" directory: "/" labels: ["A1-insubstantial", "R0-silent"] schedule: - interval: "daily" + interval: "weekly" groups: # We assume these crates to be semver abiding and can therefore group them together. known_good_semver: diff --git a/.github/env b/.github/env index 2e4d5b48100d..bb61e1f4cd99 100644 --- a/.github/env +++ b/.github/env @@ -1 +1 @@ -IMAGE="docker.io/paritytech/ci-unified:bullseye-1.77.0-2024-04-10-v202407161507" +IMAGE="docker.io/paritytech/ci-unified:bullseye-1.81.0-2024-09-11-v202409111034" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 120000 index 000000000000..7b6b3498755f --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1 @@ +../docs/contributor/PULL_REQUEST_TEMPLATE.md \ No newline at end of file diff --git a/.github/review-bot.yml b/.github/review-bot.yml index adbc480c6ba1..c2080142f506 100644 --- a/.github/review-bot.yml +++ b/.github/review-bot.yml @@ -29,7 +29,7 @@ rules: # excluding files from 'Runtime files' and 'CI files' rules exclude: - ^cumulus/parachains/common/src/[^/]+\.rs$ - - ^substrate/frame/(?!.*(nfts/.*|uniques/.*|babe/.*|grandpa/.*|beefy|merkle-mountain-range/.*|contracts/.*|election|nomination-pools/.*|staking/.*|aura/.*)) + - ^substrate/frame/(?!.*(nfts/.*|uniques/.*|babe/.*|grandpa/.*|beefy|merkle-mountain-range/.*|contracts/.*|revive/.*|election|nomination-pools/.*|staking/.*|aura/.*)) - ^\.gitlab-ci\.yml - ^docker/.* - ^\.github/.* @@ -56,7 +56,7 @@ rules: - name: FRAME coders substrate condition: include: - - ^substrate/frame/(?!.*(nfts/.*|uniques/.*|babe/.*|grandpa/.*|beefy|merkle-mountain-range/.*|contracts/.*|election|nomination-pools/.*|staking/.*|aura/.*)) + - ^substrate/frame/(?!.*(nfts/.*|uniques/.*|babe/.*|grandpa/.*|beefy|merkle-mountain-range/.*|contracts/.*|revive/.*|election|nomination-pools/.*|staking/.*|aura/.*)) type: "and" reviewers: - minApprovals: 2 @@ -66,6 +66,17 @@ rules: teams: - frame-coders + # Smart Contracts + - name: Smart Contracts + type: basic + condition: + include: + - ^substrate/frame/contracts/.* + - ^substrate/frame/revive/.* + minApprovals: 2 + teams: + - smart-contracts + # Protection of THIS file - name: Review Bot countAuthor: true diff --git a/.gitlab/check-each-crate.py b/.github/scripts/check-each-crate.py similarity index 81% rename from .gitlab/check-each-crate.py rename to .github/scripts/check-each-crate.py index 9b654f8071ac..7a53e812ddfc 100755 --- a/.gitlab/check-each-crate.py +++ b/.github/scripts/check-each-crate.py @@ -9,6 +9,7 @@ # # - `target_group`: Integer starting from 1, the group this script should execute. # - `groups_total`: Integer starting from 1, total number of groups. +# - `disable_forklift`: Boolean, whether to disable forklift or not. import subprocess, sys @@ -31,6 +32,9 @@ target_group = int(sys.argv[1]) - 1 groups_total = int(sys.argv[2]) +disable_forklift = bool(sys.argv[3] if len(sys.argv) > 3 else False) + +print(f"Target group: {target_group}, Total groups: {groups_total}, Disable forklift: {disable_forklift}", file=sys.stderr) if len(crates) == 0: print("No crates detected!", file=sys.stderr) @@ -55,7 +59,11 @@ print(f"Checking {crates[crate][0]}", file=sys.stderr) - res = subprocess.run(["forklift", "cargo", "check", "--locked"], cwd = crates[crate][1]) + cmd = ["cargo", "check", "--locked"] + + cmd.insert(0, 'forklift') if not disable_forklift else None + + res = subprocess.run(cmd, cwd = crates[crate][1]) if res.returncode != 0: sys.exit(1) diff --git a/.github/scripts/cmd/_help.py b/.github/scripts/cmd/_help.py new file mode 100644 index 000000000000..8ad49dad8461 --- /dev/null +++ b/.github/scripts/cmd/_help.py @@ -0,0 +1,26 @@ +import argparse + +""" + +Custom help action for argparse, it prints the help message for the main parser and all subparsers. + +""" + + +class _HelpAction(argparse._HelpAction): + def __call__(self, parser, namespace, values, option_string=None): + parser.print_help() + + # retrieve subparsers from parser + subparsers_actions = [ + action for action in parser._actions + if isinstance(action, argparse._SubParsersAction)] + # there will probably only be one subparser_action, + # but better save than sorry + for subparsers_action in subparsers_actions: + # get all subparsers and print help + for choice, subparser in subparsers_action.choices.items(): + print("\n### Command '{}'".format(choice)) + print(subparser.format_help()) + + parser.exit() diff --git a/.github/scripts/cmd/cmd.py b/.github/scripts/cmd/cmd.py new file mode 100755 index 000000000000..6a624bf4237b --- /dev/null +++ b/.github/scripts/cmd/cmd.py @@ -0,0 +1,254 @@ +#!/usr/bin/env python3 + +import os +import sys +import json +import argparse +import _help +import importlib.util + +_HelpAction = _help._HelpAction + +f = open('.github/workflows/runtimes-matrix.json', 'r') +runtimesMatrix = json.load(f) + +runtimeNames = list(map(lambda x: x['name'], runtimesMatrix)) + +common_args = { + '--quiet': {"action": "store_true", "help": "Won't print start/end/failed messages in PR"}, + '--clean': {"action": "store_true", "help": "Clean up the previous bot's & author's comments in PR"}, + '--image': {"help": "Override docker image '--image docker.io/paritytech/ci-unified:latest'"}, +} + +def print_and_log(message, output_file='/tmp/cmd/command_output.log'): + print(message) + with open(output_file, 'a') as f: + f.write(message + '\n') + +def setup_logging(): + if not os.path.exists('/tmp/cmd'): + os.makedirs('/tmp/cmd') + open('/tmp/cmd/command_output.log', 'w') + +parser = argparse.ArgumentParser(prog="/cmd ", description='A command runner for polkadot-sdk repo', add_help=False) +parser.add_argument('--help', action=_HelpAction, help='help for help if you need some help') # help for help +for arg, config in common_args.items(): + parser.add_argument(arg, **config) + +subparsers = parser.add_subparsers(help='a command to run', dest='command') + +setup_logging() + +""" +BENCH +""" + +bench_example = '''**Examples**: + Runs all benchmarks + %(prog)s + + Runs benchmarks for pallet_balances and pallet_multisig for all runtimes which have these pallets. **--quiet** makes it to output nothing to PR but reactions + %(prog)s --pallet pallet_balances pallet_xcm_benchmarks::generic --quiet + + Runs bench for all pallets for westend runtime and fails fast on first failed benchmark + %(prog)s --runtime westend --fail-fast + + Does not output anything and cleans up the previous bot's & author command triggering comments in PR + %(prog)s --runtime westend rococo --pallet pallet_balances pallet_multisig --quiet --clean +''' + +parser_bench = subparsers.add_parser('bench', help='Runs benchmarks', epilog=bench_example, formatter_class=argparse.RawDescriptionHelpFormatter) + +for arg, config in common_args.items(): + parser_bench.add_argument(arg, **config) + +parser_bench.add_argument('--runtime', help='Runtime(s) space separated', choices=runtimeNames, nargs='*', default=runtimeNames) +parser_bench.add_argument('--pallet', help='Pallet(s) space separated', nargs='*', default=[]) +parser_bench.add_argument('--fail-fast', help='Fail fast on first failed benchmark', action='store_true') + +""" +FMT +""" +parser_fmt = subparsers.add_parser('fmt', help='Formats code (cargo +nightly-VERSION fmt) and configs (taplo format)') +for arg, config in common_args.items(): + parser_fmt.add_argument(arg, **config) + +""" +Update UI +""" +parser_ui = subparsers.add_parser('update-ui', help='Updates UI tests') +for arg, config in common_args.items(): + parser_ui.add_argument(arg, **config) + +""" +PRDOC +""" +# Import generate-prdoc.py dynamically +spec = importlib.util.spec_from_file_location("generate_prdoc", ".github/scripts/generate-prdoc.py") +generate_prdoc = importlib.util.module_from_spec(spec) +spec.loader.exec_module(generate_prdoc) + +parser_prdoc = subparsers.add_parser('prdoc', help='Generates PR documentation') +generate_prdoc.setup_parser(parser_prdoc, pr_required=False) + +def main(): + global args, unknown, runtimesMatrix + args, unknown = parser.parse_known_args() + + print(f'args: {args}') + + if args.command == 'bench': + runtime_pallets_map = {} + failed_benchmarks = {} + successful_benchmarks = {} + + profile = "release" + + print(f'Provided runtimes: {args.runtime}') + # convert to mapped dict + runtimesMatrix = list(filter(lambda x: x['name'] in args.runtime, runtimesMatrix)) + runtimesMatrix = {x['name']: x for x in runtimesMatrix} + print(f'Filtered out runtimes: {runtimesMatrix}') + + # loop over remaining runtimes to collect available pallets + for runtime in runtimesMatrix.values(): + os.system(f"forklift cargo build -p {runtime['package']} --profile {profile} --features={runtime['bench_features']}") + print(f'-- listing pallets for benchmark for {runtime["name"]}') + wasm_file = f"target/{profile}/wbuild/{runtime['package']}/{runtime['package'].replace('-', '_')}.wasm" + output = os.popen( + f"frame-omni-bencher v1 benchmark pallet --no-csv-header --no-storage-info --no-min-squares --no-median-slopes --all --list --runtime={wasm_file} {runtime['bench_flags']}").read() + raw_pallets = output.strip().split('\n') + + all_pallets = set() + for pallet in raw_pallets: + if pallet: + all_pallets.add(pallet.split(',')[0].strip()) + + pallets = list(all_pallets) + print(f'Pallets in {runtime["name"]}: {pallets}') + runtime_pallets_map[runtime['name']] = pallets + + print(f'\n') + + # filter out only the specified pallets from collected runtimes/pallets + if args.pallet: + print(f'Pallets: {args.pallet}') + new_pallets_map = {} + # keep only specified pallets if they exist in the runtime + for runtime in runtime_pallets_map: + if set(args.pallet).issubset(set(runtime_pallets_map[runtime])): + new_pallets_map[runtime] = args.pallet + + runtime_pallets_map = new_pallets_map + + print(f'Filtered out runtimes & pallets: {runtime_pallets_map}\n') + + if not runtime_pallets_map: + if args.pallet and not args.runtime: + print(f"No pallets {args.pallet} found in any runtime") + elif args.runtime and not args.pallet: + print(f"{args.runtime} runtime does not have any pallets") + elif args.runtime and args.pallet: + print(f"No pallets {args.pallet} found in {args.runtime}") + else: + print('No runtimes found') + sys.exit(1) + + for runtime in runtime_pallets_map: + for pallet in runtime_pallets_map[runtime]: + config = runtimesMatrix[runtime] + header_path = os.path.abspath(config['header']) + template = None + + print(f'-- config: {config}') + if runtime == 'dev': + # to support sub-modules (https://github.com/paritytech/command-bot/issues/275) + search_manifest_path = f"cargo metadata --locked --format-version 1 --no-deps | jq -r '.packages[] | select(.name == \"{pallet.replace('_', '-')}\") | .manifest_path'" + print(f'-- running: {search_manifest_path}') + manifest_path = os.popen(search_manifest_path).read() + if not manifest_path: + print(f'-- pallet {pallet} not found in dev runtime') + if args.fail_fast: + print_and_log(f'Error: {pallet} not found in dev runtime') + sys.exit(1) + package_dir = os.path.dirname(manifest_path) + print(f'-- package_dir: {package_dir}') + print(f'-- manifest_path: {manifest_path}') + output_path = os.path.join(package_dir, "src", "weights.rs") + template = config['template'] + else: + default_path = f"./{config['path']}/src/weights" + xcm_path = f"./{config['path']}/src/weights/xcm" + output_path = default_path + if pallet.startswith("pallet_xcm_benchmarks"): + template = config['template'] + output_path = xcm_path + + print(f'-- benchmarking {pallet} in {runtime} into {output_path}') + cmd = f"frame-omni-bencher v1 benchmark pallet " \ + f"--extrinsic=* " \ + f"--runtime=target/{profile}/wbuild/{config['package']}/{config['package'].replace('-', '_')}.wasm " \ + f"--pallet={pallet} " \ + f"--header={header_path} " \ + f"--output={output_path} " \ + f"--wasm-execution=compiled " \ + f"--steps=50 " \ + f"--repeat=20 " \ + f"--heap-pages=4096 " \ + f"{f'--template={template} ' if template else ''}" \ + f"--no-storage-info --no-min-squares --no-median-slopes " \ + f"{config['bench_flags']}" + print(f'-- Running: {cmd} \n') + status = os.system(cmd) + + if status != 0 and args.fail_fast: + print_and_log(f'❌ Failed to benchmark {pallet} in {runtime}') + sys.exit(1) + + # Otherwise collect failed benchmarks and print them at the end + # push failed pallets to failed_benchmarks + if status != 0: + failed_benchmarks[f'{runtime}'] = failed_benchmarks.get(f'{runtime}', []) + [pallet] + else: + successful_benchmarks[f'{runtime}'] = successful_benchmarks.get(f'{runtime}', []) + [pallet] + + if failed_benchmarks: + print_and_log('❌ Failed benchmarks of runtimes/pallets:') + for runtime, pallets in failed_benchmarks.items(): + print_and_log(f'-- {runtime}: {pallets}') + + if successful_benchmarks: + print_and_log('✅ Successful benchmarks of runtimes/pallets:') + for runtime, pallets in successful_benchmarks.items(): + print_and_log(f'-- {runtime}: {pallets}') + + elif args.command == 'fmt': + command = f"cargo +nightly fmt" + print(f'Formatting with `{command}`') + nightly_status = os.system(f'{command}') + taplo_status = os.system('taplo format --config .config/taplo.toml') + + if (nightly_status != 0 or taplo_status != 0): + print_and_log('❌ Failed to format code') + sys.exit(1) + + elif args.command == 'update-ui': + command = 'sh ./scripts/update-ui-tests.sh' + print(f'Updating ui with `{command}`') + status = os.system(f'{command}') + + if status != 0: + print_and_log('❌ Failed to update ui') + sys.exit(1) + + elif args.command == 'prdoc': + # Call the main function from ./github/scripts/generate-prdoc.py module + exit_code = generate_prdoc.main(args) + if exit_code != 0: + print_and_log('❌ Failed to generate prdoc') + sys.exit(exit_code) + + print('🚀 Done') + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/.github/scripts/cmd/test_cmd.py b/.github/scripts/cmd/test_cmd.py new file mode 100644 index 000000000000..faad3f261b9a --- /dev/null +++ b/.github/scripts/cmd/test_cmd.py @@ -0,0 +1,432 @@ +import unittest +from unittest.mock import patch, mock_open, MagicMock, call +import json +import sys +import os +import argparse + +# Mock data for runtimes-matrix.json +mock_runtimes_matrix = [ + { + "name": "dev", + "package": "kitchensink-runtime", + "path": "substrate/frame", + "header": "substrate/HEADER-APACHE2", + "template": "substrate/.maintain/frame-weight-template.hbs", + "bench_features": "runtime-benchmarks,riscv", + "bench_flags": "--flag1 --flag2" + }, + { + "name": "westend", + "package": "westend-runtime", + "path": "polkadot/runtime/westend", + "header": "polkadot/file_header.txt", + "template": "polkadot/xcm/pallet-xcm-benchmarks/template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "--flag3 --flag4" + }, + { + "name": "rococo", + "package": "rococo-runtime", + "path": "polkadot/runtime/rococo", + "header": "polkadot/file_header.txt", + "template": "polkadot/xcm/pallet-xcm-benchmarks/template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "" + }, + { + "name": "asset-hub-westend", + "package": "asset-hub-westend-runtime", + "path": "cumulus/parachains/runtimes/assets/asset-hub-westend", + "header": "cumulus/file_header.txt", + "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "--flag7 --flag8" + } +] + +def get_mock_bench_output(runtime, pallets, output_path, header, bench_flags, template = None): + return f"frame-omni-bencher v1 benchmark pallet --extrinsic=* " \ + f"--runtime=target/release/wbuild/{runtime}-runtime/{runtime.replace('-', '_')}_runtime.wasm " \ + f"--pallet={pallets} --header={header} " \ + f"--output={output_path} " \ + f"--wasm-execution=compiled " \ + f"--steps=50 --repeat=20 --heap-pages=4096 " \ + f"{f'--template={template} ' if template else ''}" \ + f"--no-storage-info --no-min-squares --no-median-slopes " \ + f"{bench_flags}" + +class TestCmd(unittest.TestCase): + + def setUp(self): + self.patcher1 = patch('builtins.open', new_callable=mock_open, read_data=json.dumps(mock_runtimes_matrix)) + self.patcher2 = patch('json.load', return_value=mock_runtimes_matrix) + self.patcher3 = patch('argparse.ArgumentParser.parse_known_args') + self.patcher4 = patch('os.system', return_value=0) + self.patcher5 = patch('os.popen') + self.patcher6 = patch('importlib.util.spec_from_file_location', return_value=MagicMock()) + self.patcher7 = patch('importlib.util.module_from_spec', return_value=MagicMock()) + self.patcher8 = patch('cmd.generate_prdoc.main', return_value=0) + + self.mock_open = self.patcher1.start() + self.mock_json_load = self.patcher2.start() + self.mock_parse_args = self.patcher3.start() + self.mock_system = self.patcher4.start() + self.mock_popen = self.patcher5.start() + self.mock_spec_from_file_location = self.patcher6.start() + self.mock_module_from_spec = self.patcher7.start() + self.mock_generate_prdoc_main = self.patcher8.start() + + # Ensure that cmd.py uses the mock_runtimes_matrix + import cmd + cmd.runtimesMatrix = mock_runtimes_matrix + + def tearDown(self): + self.patcher1.stop() + self.patcher2.stop() + self.patcher3.stop() + self.patcher4.stop() + self.patcher5.stop() + self.patcher6.stop() + self.patcher7.stop() + self.patcher8.stop() + + def test_bench_command_normal_execution_all_runtimes(self): + self.mock_parse_args.return_value = (argparse.Namespace( + command='bench', + runtime=list(map(lambda x: x['name'], mock_runtimes_matrix)), + pallet=['pallet_balances'], + fail_fast=True, + quiet=False, + clean=False, + image=None + ), []) + + self.mock_popen.return_value.read.side_effect = [ + "pallet_balances\npallet_staking\npallet_something\n", # Output for dev runtime + "pallet_balances\npallet_staking\npallet_something\n", # Output for westend runtime + "pallet_staking\npallet_something\n", # Output for rococo runtime - no pallet here + "pallet_balances\npallet_staking\npallet_something\n", # Output for asset-hub-westend runtime + "./substrate/frame/balances/Cargo.toml\n", # Mock manifest path for dev -> pallet_balances + ] + + with patch('sys.exit') as mock_exit: + import cmd + cmd.main() + mock_exit.assert_not_called() + + expected_calls = [ + # Build calls + call("forklift cargo build -p kitchensink-runtime --profile release --features=runtime-benchmarks,riscv"), + call("forklift cargo build -p westend-runtime --profile release --features=runtime-benchmarks"), + call("forklift cargo build -p rococo-runtime --profile release --features=runtime-benchmarks"), + call("forklift cargo build -p asset-hub-westend-runtime --profile release --features=runtime-benchmarks"), + + call(get_mock_bench_output( + runtime='kitchensink', + pallets='pallet_balances', + output_path='./substrate/frame/balances/src/weights.rs', + header=os.path.abspath('substrate/HEADER-APACHE2'), + bench_flags='--flag1 --flag2', + template="substrate/.maintain/frame-weight-template.hbs" + )), + call(get_mock_bench_output( + runtime='westend', + pallets='pallet_balances', + output_path='./polkadot/runtime/westend/src/weights', + header=os.path.abspath('polkadot/file_header.txt'), + bench_flags='--flag3 --flag4' + )), + # skips rococo benchmark + call(get_mock_bench_output( + runtime='asset-hub-westend', + pallets='pallet_balances', + output_path='./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights', + header=os.path.abspath('cumulus/file_header.txt'), + bench_flags='--flag7 --flag8' + )), + ] + self.mock_system.assert_has_calls(expected_calls, any_order=True) + + def test_bench_command_normal_execution(self): + self.mock_parse_args.return_value = (argparse.Namespace( + command='bench', + runtime=['westend'], + pallet=['pallet_balances', 'pallet_staking'], + fail_fast=True, + quiet=False, + clean=False, + image=None + ), []) + header_path = os.path.abspath('polkadot/file_header.txt') + self.mock_popen.return_value.read.side_effect = [ + "pallet_balances\npallet_staking\npallet_something\n", # Output for westend runtime + ] + + with patch('sys.exit') as mock_exit: + import cmd + cmd.main() + mock_exit.assert_not_called() + + expected_calls = [ + # Build calls + call("forklift cargo build -p westend-runtime --profile release --features=runtime-benchmarks"), + + # Westend runtime calls + call(get_mock_bench_output( + runtime='westend', + pallets='pallet_balances', + output_path='./polkadot/runtime/westend/src/weights', + header=header_path, + bench_flags='--flag3 --flag4' + )), + call(get_mock_bench_output( + runtime='westend', + pallets='pallet_staking', + output_path='./polkadot/runtime/westend/src/weights', + header=header_path, + bench_flags='--flag3 --flag4' + )), + ] + self.mock_system.assert_has_calls(expected_calls, any_order=True) + + + def test_bench_command_normal_execution_xcm(self): + self.mock_parse_args.return_value = (argparse.Namespace( + command='bench', + runtime=['westend'], + pallet=['pallet_xcm_benchmarks::generic'], + fail_fast=True, + quiet=False, + clean=False, + image=None + ), []) + header_path = os.path.abspath('polkadot/file_header.txt') + self.mock_popen.return_value.read.side_effect = [ + "pallet_balances\npallet_staking\npallet_something\npallet_xcm_benchmarks::generic\n", # Output for westend runtime + ] + + with patch('sys.exit') as mock_exit: + import cmd + cmd.main() + mock_exit.assert_not_called() + + expected_calls = [ + # Build calls + call("forklift cargo build -p westend-runtime --profile release --features=runtime-benchmarks"), + + # Westend runtime calls + call(get_mock_bench_output( + runtime='westend', + pallets='pallet_xcm_benchmarks::generic', + output_path='./polkadot/runtime/westend/src/weights/xcm', + header=header_path, + bench_flags='--flag3 --flag4', + template="polkadot/xcm/pallet-xcm-benchmarks/template.hbs" + )), + ] + self.mock_system.assert_has_calls(expected_calls, any_order=True) + + def test_bench_command_two_runtimes_two_pallets(self): + self.mock_parse_args.return_value = (argparse.Namespace( + command='bench', + runtime=['westend', 'rococo'], + pallet=['pallet_balances', 'pallet_staking'], + fail_fast=True, + quiet=False, + clean=False, + image=None + ), []) + self.mock_popen.return_value.read.side_effect = [ + "pallet_staking\npallet_balances\n", # Output for westend runtime + "pallet_staking\npallet_balances\n", # Output for rococo runtime + ] + + with patch('sys.exit') as mock_exit: + import cmd + cmd.main() + mock_exit.assert_not_called() + header_path = os.path.abspath('polkadot/file_header.txt') + + expected_calls = [ + # Build calls + call("forklift cargo build -p westend-runtime --profile release --features=runtime-benchmarks"), + call("forklift cargo build -p rococo-runtime --profile release --features=runtime-benchmarks"), + # Westend runtime calls + call(get_mock_bench_output( + runtime='westend', + pallets='pallet_staking', + output_path='./polkadot/runtime/westend/src/weights', + header=header_path, + bench_flags='--flag3 --flag4' + )), + call(get_mock_bench_output( + runtime='westend', + pallets='pallet_balances', + output_path='./polkadot/runtime/westend/src/weights', + header=header_path, + bench_flags='--flag3 --flag4' + )), + # Rococo runtime calls + call(get_mock_bench_output( + runtime='rococo', + pallets='pallet_staking', + output_path='./polkadot/runtime/rococo/src/weights', + header=header_path, + bench_flags='' + )), + call(get_mock_bench_output( + runtime='rococo', + pallets='pallet_balances', + output_path='./polkadot/runtime/rococo/src/weights', + header=header_path, + bench_flags='' + )), + ] + self.mock_system.assert_has_calls(expected_calls, any_order=True) + + def test_bench_command_one_dev_runtime(self): + self.mock_parse_args.return_value = (argparse.Namespace( + command='bench', + runtime=['dev'], + pallet=['pallet_balances'], + fail_fast=True, + quiet=False, + clean=False, + image=None + ), []) + manifest_dir = "substrate/frame/kitchensink" + self.mock_popen.return_value.read.side_effect = [ + "pallet_balances\npallet_something", # Output for dev runtime + manifest_dir + "/Cargo.toml" # Output for manifest path in dev runtime + ] + header_path = os.path.abspath('substrate/HEADER-APACHE2') + + with patch('sys.exit') as mock_exit: + import cmd + cmd.main() + mock_exit.assert_not_called() + + expected_calls = [ + # Build calls + call("forklift cargo build -p kitchensink-runtime --profile release --features=runtime-benchmarks,riscv"), + # Westend runtime calls + call(get_mock_bench_output( + runtime='kitchensink', + pallets='pallet_balances', + output_path=manifest_dir + "/src/weights.rs", + header=header_path, + bench_flags='--flag1 --flag2', + template="substrate/.maintain/frame-weight-template.hbs" + )), + ] + self.mock_system.assert_has_calls(expected_calls, any_order=True) + + def test_bench_command_one_cumulus_runtime(self): + self.mock_parse_args.return_value = (argparse.Namespace( + command='bench', + runtime=['asset-hub-westend'], + pallet=['pallet_assets'], + fail_fast=True, + quiet=False, + clean=False, + image=None + ), []) + self.mock_popen.return_value.read.side_effect = [ + "pallet_assets\n", # Output for asset-hub-westend runtime + ] + header_path = os.path.abspath('cumulus/file_header.txt') + + with patch('sys.exit') as mock_exit: + import cmd + cmd.main() + mock_exit.assert_not_called() + + expected_calls = [ + # Build calls + call("forklift cargo build -p asset-hub-westend-runtime --profile release --features=runtime-benchmarks"), + # Asset-hub-westend runtime calls + call(get_mock_bench_output( + runtime='asset-hub-westend', + pallets='pallet_assets', + output_path='./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights', + header=header_path, + bench_flags='--flag7 --flag8' + )), + ] + + self.mock_system.assert_has_calls(expected_calls, any_order=True) + + def test_bench_command_one_cumulus_runtime_xcm(self): + self.mock_parse_args.return_value = (argparse.Namespace( + command='bench', + runtime=['asset-hub-westend'], + pallet=['pallet_xcm_benchmarks::generic', 'pallet_assets'], + fail_fast=True, + quiet=False, + clean=False, + image=None + ), []) + self.mock_popen.return_value.read.side_effect = [ + "pallet_assets\npallet_xcm_benchmarks::generic\n", # Output for asset-hub-westend runtime + ] + header_path = os.path.abspath('cumulus/file_header.txt') + + with patch('sys.exit') as mock_exit: + import cmd + cmd.main() + mock_exit.assert_not_called() + + expected_calls = [ + # Build calls + call("forklift cargo build -p asset-hub-westend-runtime --profile release --features=runtime-benchmarks"), + # Asset-hub-westend runtime calls + call(get_mock_bench_output( + runtime='asset-hub-westend', + pallets='pallet_xcm_benchmarks::generic', + output_path='./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm', + header=header_path, + bench_flags='--flag7 --flag8', + template="cumulus/templates/xcm-bench-template.hbs" + )), + call(get_mock_bench_output( + runtime='asset-hub-westend', + pallets='pallet_assets', + output_path='./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights', + header=header_path, + bench_flags='--flag7 --flag8' + )), + ] + + self.mock_system.assert_has_calls(expected_calls, any_order=True) + + @patch('argparse.ArgumentParser.parse_known_args', return_value=(argparse.Namespace(command='fmt'), [])) + @patch('os.system', return_value=0) + def test_fmt_command(self, mock_system, mock_parse_args): + with patch('sys.exit') as mock_exit: + import cmd + cmd.main() + mock_exit.assert_not_called() + mock_system.assert_any_call('cargo +nightly fmt') + mock_system.assert_any_call('taplo format --config .config/taplo.toml') + + @patch('argparse.ArgumentParser.parse_known_args', return_value=(argparse.Namespace(command='update-ui'), [])) + @patch('os.system', return_value=0) + def test_update_ui_command(self, mock_system, mock_parse_args): + with patch('sys.exit') as mock_exit: + import cmd + cmd.main() + mock_exit.assert_not_called() + mock_system.assert_called_with('sh ./scripts/update-ui-tests.sh') + + @patch('argparse.ArgumentParser.parse_known_args', return_value=(argparse.Namespace(command='prdoc'), [])) + @patch('os.system', return_value=0) + def test_prdoc_command(self, mock_system, mock_parse_args): + with patch('sys.exit') as mock_exit: + import cmd + cmd.main() + mock_exit.assert_not_called() + self.mock_generate_prdoc_main.assert_called_with(mock_parse_args.return_value[0]) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/.github/scripts/common/lib.sh b/.github/scripts/common/lib.sh index 33ef2d3e7eda..56d0371d678e 100755 --- a/.github/scripts/common/lib.sh +++ b/.github/scripts/common/lib.sh @@ -242,6 +242,7 @@ fetch_release_artifacts() { # - GITHUB_TOKEN # - REPO in the form paritytech/polkadot fetch_release_artifacts_from_s3() { + BINARY=$1 echo "Version : $VERSION" echo "Repo : $REPO" echo "Binary : $BINARY" @@ -299,22 +300,23 @@ function check_sha256() { } # Import GPG keys of the release team members -# This is done in parallel as it can take a while sometimes function import_gpg_keys() { - GPG_KEYSERVER=${GPG_KEYSERVER:-"keyserver.ubuntu.com"} + GPG_KEYSERVER=${GPG_KEYSERVER:-"hkps://keyserver.ubuntu.com"} SEC="9D4B2B6EB8F97156D19669A9FF0812D491B96798" EGOR="E6FC4D4782EB0FA64A4903CCDB7D3555DD3932D3" MORGAN="2E92A9D8B15D7891363D1AE8AF9E6C43F7F8C4CF" + PARITY_RELEASES="90BD75EBBB8E95CB3DA6078F94A4029AB4B35DAE" - echo "Importing GPG keys from $GPG_KEYSERVER in parallel" - for key in $SEC $EGOR $MORGAN; do + echo "Importing GPG keys from $GPG_KEYSERVER" + for key in $SEC $EGOR $MORGAN $PARITY_RELEASES; do ( echo "Importing GPG key $key" gpg --no-tty --quiet --keyserver $GPG_KEYSERVER --recv-keys $key echo -e "5\ny\n" | gpg --no-tty --command-fd 0 --expert --edit-key $key trust; - ) & + ) done wait + gpg -k } # Check the GPG signature for a given binary @@ -403,14 +405,10 @@ function find_runtimes() { # output: none filter_version_from_input() { version=$1 - regex="(^v[0-9]+\.[0-9]+\.[0-9]+)$|(^v[0-9]+\.[0-9]+\.[0-9]+-rc[0-9]+)$" + regex="^(v)?[0-9]+\.[0-9]+\.[0-9]+(-rc[0-9]+)?$" if [[ $version =~ $regex ]]; then - if [ -n "${BASH_REMATCH[1]}" ]; then - echo "${BASH_REMATCH[1]}" - elif [ -n "${BASH_REMATCH[2]}" ]; then - echo "${BASH_REMATCH[2]}" - fi + echo $version else echo "Invalid version: $version" exit 1 @@ -457,3 +455,15 @@ function get_polkadot_node_version_from_code() { # Remove the semicolon sed 's/;//g' } + +validate_stable_tag() { + tag="$1" + pattern="^(polkadot-)?stable[0-9]{4}(-[0-9]+)?(-rc[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/deny-git-deps.py b/.github/scripts/deny-git-deps.py index 622fc64c4881..bd4fcf1f9237 100644 --- a/.github/scripts/deny-git-deps.py +++ b/.github/scripts/deny-git-deps.py @@ -15,6 +15,7 @@ 'simple-mermaid': ['xcm-docs'], # Fix in 'bandersnatch_vrfs': ['sp-core'], + 'subwasmlib': ['polkadot-zombienet-sdk-tests'], } root = sys.argv[1] if len(sys.argv) > 1 else os.getcwd() @@ -24,7 +25,7 @@ def check_dep(dep, used_by): if dep.location != DependencyLocation.GIT: return - + if used_by in KNOWN_BAD_GIT_DEPS.get(dep.name, []): print(f'🤨 Ignoring git dependency {dep.name} in {used_by}') else: diff --git a/.github/scripts/generate-prdoc.py b/.github/scripts/generate-prdoc.py new file mode 100644 index 000000000000..780fa0012976 --- /dev/null +++ b/.github/scripts/generate-prdoc.py @@ -0,0 +1,144 @@ +#!/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 node_dev --bump patch +""" + +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 = { "title": title, "doc": [{}], "crates": [] } + + prdoc["doc"][0]["audience"] = audience + prdoc["doc"][0]["description"] = description + + workspace = Workspace.from_path(".") + + modified_paths = [] + for diff in whatthepatch.parse_patch(patch): + new_path = diff.header.new_path + # Sometimes this lib returns `/dev/null` as the new path... + if not new_path.startswith("/dev"): + modified_paths.append(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")): + if p == '/': + exit(1) + p = os.path.dirname(p) + + with open(os.path.join(p, "Cargo.toml")) as f: + manifest = toml.load(f) + + if not "package" in manifest: + 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}") + + 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, sort_keys=False) + print(f"PrDoc for PR {pr} written to {path}") + +# Make the `description` a multiline string instead of escaping \r\n. +def setup_yaml(): + def yaml_multiline_string_presenter(dumper, data): + if len(data.splitlines()) > 1: + data = '\n'.join([line.rstrip() for line in data.strip().splitlines()]) + return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|') + return dumper.represent_scalar('tag:yaml.org,2002:str', data) + + yaml.add_representer(str, yaml_multiline_string_presenter) + +# parse_args is also used by cmd/cmd.py +# if pr_required is False, then --pr is optional, as it can be derived from the PR comment body +def setup_parser(parser=None, pr_required=True): + allowed_audiences = ["runtime_dev", "runtime_user", "node_dev", "node_operator"] + if parser is None: + parser = argparse.ArgumentParser() + parser.add_argument("--pr", type=int, required=pr_required, help="The PR number to generate the PrDoc for.") + parser.add_argument("--audience", type=str, nargs='*', choices=allowed_audiences, default=["todo"], help="The audience of whom the changes may concern. Example: --audience runtime_dev node_dev") + parser.add_argument("--bump", type=str, default="major", choices=["patch", "minor", "major", "silent", "ignore", "no_change"], help="A default bump level for all crates. Example: --bump patch") + parser.add_argument("--force", action="store_true", help="Whether to overwrite any existing PrDoc.") + return parser + +def snake_to_title(s): + return ' '.join(word.capitalize() for word in s.split('_')) + +def main(args): + print(f"Args: {args}, force: {args.force}") + setup_yaml() + try: + # Convert snake_case audience arguments to title case + mapped_audiences = [snake_to_title(a) for a in args.audience] + if len(mapped_audiences) == 1: + mapped_audiences = mapped_audiences[0] + from_pr_number(args.pr, mapped_audiences, args.bump, args.force) + return 0 + except Exception as e: + print(f"Error generating prdoc: {e}") + return 1 + +if __name__ == "__main__": + parser = setup_parser() + args = parser.parse_args() + main(args) diff --git a/.github/scripts/generate-prdoc.requirements.txt b/.github/scripts/generate-prdoc.requirements.txt new file mode 100644 index 000000000000..c17aceff63a0 --- /dev/null +++ b/.github/scripts/generate-prdoc.requirements.txt @@ -0,0 +1,6 @@ +requests +cargo-workspace +PyGithub +whatthepatch +pyyaml +toml \ No newline at end of file diff --git a/.github/scripts/generate-readmes.py b/.github/scripts/generate-readmes.py new file mode 100755 index 000000000000..f838eaa29a74 --- /dev/null +++ b/.github/scripts/generate-readmes.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 + +""" +A script to generate READMEs for all public crates, +if they do not already have one. + +It relies on functions from the `check-workspace.py` script. + +The resulting README is based on a template defined below, +and includes the crate name, description, license, +and optionally - the SDK release version. + +# Example + +```sh +python3 -m pip install toml +.github/scripts/generate-readmes.py . --sdk-version 1.15.0 +``` +""" + +import os +import toml +import importlib +import argparse + +check_workspace = importlib.import_module("check-workspace") + +README_TEMPLATE = """
+ +Polkadot logo + +# {name} + +This crate is part of the [Polkadot SDK](https://github.com/paritytech/polkadot-sdk/). + +
+ +## Description + +{description} + +## Additional Resources + +In order to learn about Polkadot SDK, head over to the [Polkadot SDK Developer Documentation](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/index.html). + +To learn about Polkadot, visit [polkadot.com](https://polkadot.com/). + +## License + +This crate is licensed with {license}. +""" + +VERSION_TEMPLATE = """ +## Version + +This version of `{name}` is associated with Polkadot {sdk_version} release. +""" + + +def generate_readme(member, *, workspace_dir, workspace_license, sdk_version): + print(f"Loading manifest for: {member}") + manifest = toml.load(os.path.join(workspace_dir, member, "Cargo.toml")) + if manifest["package"].get("publish", True) == False: + print(f"⏩ Skipping un-published crate: {member}") + return + if os.path.exists(os.path.join(workspace_dir, member, "README.md")): + print(f"⏩ Skipping crate with an existing readme: {member}") + return + print(f"📝 Generating README for: {member}") + + license = manifest["package"]["license"] + if isinstance(license, dict): + if not license.get("workspace", False): + print( + f"❌ License for {member} is unexpectedly declared as workspace=false." + ) + # Skipping this crate as it is not clear what license it should use. + return + license = workspace_license + + name = manifest["package"]["name"] + description = manifest["package"]["description"] + description = description + "." if not description.endswith(".") else description + + filled_readme = README_TEMPLATE.format( + name=name, description=description, license=license + ) + + if sdk_version: + filled_readme += VERSION_TEMPLATE.format(name=name, sdk_version=sdk_version) + + with open(os.path.join(workspace_dir, member, "README.md"), "w") as new_readme: + new_readme.write(filled_readme) + + +def parse_args(): + parser = argparse.ArgumentParser( + description="Generate readmes for published crates." + ) + + parser.add_argument( + "workspace_dir", + help="The directory to check", + metavar="workspace_dir", + type=str, + nargs=1, + ) + parser.add_argument( + "--sdk-version", + help="Optional SDK release version", + metavar="sdk_version", + type=str, + nargs=1, + required=False, + ) + + args = parser.parse_args() + return (args.workspace_dir[0], args.sdk_version[0] if args.sdk_version else None) + + +def main(): + (workspace_dir, sdk_version) = parse_args() + root_manifest = toml.load(os.path.join(workspace_dir, "Cargo.toml")) + workspace_license = root_manifest["workspace"]["package"]["license"] + members = check_workspace.get_members(workspace_dir, []) + for member in members: + generate_readme( + member, + workspace_dir=workspace_dir, + workspace_license=workspace_license, + sdk_version=sdk_version, + ) + + +if __name__ == "__main__": + main() diff --git a/.github/scripts/release/build-deb.sh b/.github/scripts/release/build-deb.sh new file mode 100755 index 000000000000..6cb833f98a4e --- /dev/null +++ b/.github/scripts/release/build-deb.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -e + +PRODUCT=$1 +VERSION=$2 +PROFILE=${PROFILE:-production} + +cargo install --version 2.7.0 cargo-deb --locked -q +echo "Using cargo-deb v$(cargo-deb --version)" +echo "Building a Debian package for '$PRODUCT' in '$PROFILE' profile" + +# we need to start the custom version with a didgit as requires it cargo-deb +cargo deb --profile $PROFILE --no-strip --no-build -p $PRODUCT --deb-version 1-$VERSION + +deb=target/debian/$PRODUCT_*_amd64.deb + +cp $deb target/production/ diff --git a/.github/scripts/release/build-linux-release.sh b/.github/scripts/release/build-linux-release.sh new file mode 100755 index 000000000000..a6bd658d292a --- /dev/null +++ b/.github/scripts/release/build-linux-release.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +# This is used to build our binaries: +# - polkadot +# - polkadot-parachain +# set -e + +BIN=$1 +PACKAGE=${2:-$BIN} + +PROFILE=${PROFILE:-production} +ARTIFACTS=/artifacts/$BIN +VERSION=$(git tag -l --contains HEAD | grep -E "^v.*") + +echo "Artifacts will be copied into $ARTIFACTS" +mkdir -p "$ARTIFACTS" + +git log --pretty=oneline -n 1 +time cargo build --profile $PROFILE --locked --verbose --bin $BIN --package $PACKAGE + +echo "Artifact target: $ARTIFACTS" + +cp ./target/$PROFILE/$BIN "$ARTIFACTS" +pushd "$ARTIFACTS" > /dev/nul +sha256sum "$BIN" | tee "$BIN.sha256" + +EXTRATAG="$($ARTIFACTS/$BIN --version | + sed -n -r 's/^'$BIN' ([0-9.]+.*-[0-9a-f]{7,13})-.*$/\1/p')" + +EXTRATAG="${VERSION}-${EXTRATAG}-$(cut -c 1-8 $ARTIFACTS/$BIN.sha256)" + +echo "$BIN version = ${VERSION} (EXTRATAG = ${EXTRATAG})" +echo -n ${VERSION} > "$ARTIFACTS/VERSION" +echo -n ${EXTRATAG} > "$ARTIFACTS/EXTRATAG" diff --git a/.github/scripts/release/release_lib.sh b/.github/scripts/release/release_lib.sh new file mode 100644 index 000000000000..f5032073b617 --- /dev/null +++ b/.github/scripts/release/release_lib.sh @@ -0,0 +1,139 @@ +#!/usr/bin/env bash + +# Set the new version by replacing the value of the constant given as patetrn +# in the file. +# +# input: pattern, version, file +#output: none +set_version() { + pattern=$1 + version=$2 + file=$3 + + sed -i "s/$pattern/\1\"${version}\"/g" $file + return 0 +} + +# Commit changes to git with specific message. +# "|| true" does not let script to fail with exit code 1, +# in case there is nothing to commit. +# +# input: MESSAGE (any message which should be used for the commit) +# output: none +commit_with_message() { + MESSAGE=$1 + git commit -a -m "$MESSAGE" || true +} + +# Retun list of the runtimes filterd +# input: none +# output: list of filtered runtimes +get_filtered_runtimes_list() { + grep_filters=("runtime.*" "test|template|starters|substrate") + + git grep spec_version: | grep .rs: | grep -e "${grep_filters[0]}" | grep "lib.rs" | grep -vE "${grep_filters[1]}" | cut -d: -f1 +} + +# Sets provided spec version +# input: version +set_spec_versions() { + NEW_VERSION=$1 + runtimes_list=(${@:2}) + + printf "Setting spec_version to $NEW_VERSION\n" + + for f in ${runtimes_list[@]}; do + printf " processing $f" + sed -ri "s/spec_version: [0-9]+_[0-9]+_[0-9]+,/spec_version: $NEW_VERSION,/" $f + done + + commit_with_message "Bump spec_version to $NEW_VERSION" + + git_show_log 'spec_version' +} + +# Displays formated results of the git log command +# for the given pattern which needs to be found in logs +# input: pattern, count (optional, default is 10) +git_show_log() { + PATTERN="$1" + COUNT=${2:-10} + git log --pretty=format:"%h %ad | %s%d [%an]" --graph --date=iso-strict | \ + head -n $COUNT | grep -iE "$PATTERN" --color=always -z +} + +# Get a spec_version number from the crate version +# +# ## inputs +# - v1.12.0 or 1.12.0 +# +# ## output: +# 1_012_000 or 1_012_001 if SUFFIX is set +function get_spec_version() { + INPUT=$1 + SUFFIX=${SUFFIX:-000} #this variable makes it possible to set a specific ruuntime version like 93826 it can be intialised as sestem variable + [[ $INPUT =~ .*([0-9]+\.[0-9]+\.[0-9]{1,2}).* ]] + VERSION="${BASH_REMATCH[1]}" + MATCH="${BASH_REMATCH[0]}" + if [ -z $MATCH ]; then + return 1 + else + SPEC_VERSION="$(sed -e "s/\./_0/g" -e "s/_[^_]*\$/_$SUFFIX/" <<< $VERSION)" + echo "$SPEC_VERSION" + return 0 + fi +} + +# Reorganize the prdoc files for the release +# +# input: VERSION (e.g. v1.0.0) +# output: none +reorder_prdocs() { + VERSION="$1" + + printf "[+] ℹ️ Reordering prdocs:" + + VERSION=$(sed -E 's/^v([0-9]+\.[0-9]+\.[0-9]+).*$/\1/' <<< "$VERSION") #getting reed of the 'v' prefix + mkdir -p "prdoc/$VERSION" + mv prdoc/pr_*.prdoc prdoc/$VERSION + git add -A + commit_with_message "Reordering prdocs for the release $VERSION" +} + +# Bump the binary version of the polkadot-parachain binary with the +# new bumped version and commit changes. +# +# input: version e.g. 1.16.0 +set_polkadot_parachain_binary_version() { + bumped_version="$1" + cargo_toml_file="$2" + + set_version "\(^version = \)\".*\"" $bumped_version $cargo_toml_file + + cargo update --workspace --offline # we need this to update Cargo.loc with the new versions as well + + MESSAGE="Bump versions in: ${cargo_toml_file}" + commit_with_message "$MESSAGE" + git_show_log "$MESSAGE" +} + + +upload_s3_release() { + alias aws='podman run --rm -it docker.io/paritytech/awscli -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_BUCKET aws' + + product=$1 + version=$2 + + echo "Working on product: $product " + echo "Working on version: $version " + + echo "Current content, should be empty on new uploads:" + aws s3 ls "s3://releases.parity.io/polkadot/${version}/" --recursive --human-readable --summarize || true + echo "Content to be uploaded:" + artifacts="artifacts/$product/" + ls "$artifacts" + aws s3 sync --acl public-read "$artifacts" "s3://releases.parity.io/polkadot/${version}/" + echo "Uploaded files:" + aws s3 ls "s3://releases.parity.io/polkadot/${version}/" --recursive --human-readable --summarize + echo "✅ The release should be at https://releases.parity.io/polkadot/${version}" +} diff --git a/.github/scripts/update-wishlist-leaderboard.py b/.github/scripts/update-wishlist-leaderboard.py new file mode 100644 index 000000000000..82d108514484 --- /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/build-misc.yml b/.github/workflows/build-misc.yml new file mode 100644 index 000000000000..2a8e81b97878 --- /dev/null +++ b/.github/workflows/build-misc.yml @@ -0,0 +1,84 @@ +name: Build Misc + +on: + push: + branches: + - master + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + merge_group: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + + preflight: + uses: ./.github/workflows/reusable-preflight.yml + + build-runtimes-polkavm: + timeout-minutes: 20 + needs: [preflight] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + container: + image: ${{ needs.preflight.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Check Rust + run: | + rustup show + rustup +nightly show + + - name: Build + env: + SUBSTRATE_RUNTIME_TARGET: riscv + run: | + forklift cargo check -p minimal-template-runtime + forklift cargo check -p westend-runtime + forklift cargo check -p rococo-runtime + forklift cargo check -p polkadot-test-runtime + + build-subkey: + timeout-minutes: 20 + needs: [preflight] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + container: + image: ${{ needs.preflight.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Check Rust + run: | + rustup show + rustup +nightly show + + - name: Build + env: + SKIP_WASM_BUILD: 1 + run: | + cd ./substrate/bin/utils/subkey + forklift cargo build --locked --release + + confirm-required-build-misc-jobs-passed: + runs-on: ubuntu-latest + name: All build misc jobs passed + # If any new job gets added, be sure to add it to this array + needs: [build-runtimes-polkavm, build-subkey] + if: always() && !cancelled() + steps: + - run: | + tee resultfile <<< '${{ toJSON(needs) }}' + FAILURES=$(cat resultfile | grep '"result": "failure"' | wc -l) + if [ $FAILURES -gt 0 ]; then + echo "### At least one required job failed ❌" >> $GITHUB_STEP_SUMMARY + exit 1 + else + echo '### Good job! All the required jobs passed 🚀' >> $GITHUB_STEP_SUMMARY + fi diff --git a/.github/workflows/build-publish-images.yml b/.github/workflows/build-publish-images.yml new file mode 100644 index 000000000000..874b5d37469c --- /dev/null +++ b/.github/workflows/build-publish-images.yml @@ -0,0 +1,494 @@ +# GHA for build-* +name: Build and push images + +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: + COMMIT_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + +jobs: + # + # + # + preflight: + ## TODO: remove when ready + if: contains(github.event.label.name, 'GHA-migration') || contains(github.event.pull_request.labels.*.name, 'GHA-migration') + uses: ./.github/workflows/reusable-preflight.yml + + ### Build ######################## + + # + # + # + build-linux-stable: + needs: [preflight] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + timeout-minutes: 60 + container: + image: ${{ needs.preflight.outputs.IMAGE }} + 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: build + run: | + forklift cargo build --locked --profile testnet --features pyroscope,fast-runtime --bin polkadot --bin polkadot-prepare-worker --bin polkadot-execute-worker + ROCOCO_EPOCH_DURATION=10 ./polkadot/scripts/build-only-wasm.sh rococo-runtime $(pwd)/runtimes/rococo-runtime-10/ + ROCOCO_EPOCH_DURATION=100 ./polkadot/scripts/build-only-wasm.sh rococo-runtime $(pwd)/runtimes/rococo-runtime-100/ + ROCOCO_EPOCH_DURATION=600 ./polkadot/scripts/build-only-wasm.sh rococo-runtime $(pwd)/runtimes/rococo-runtime-600/ + pwd + ls -alR runtimes + - name: pack artifacts + run: | + mkdir -p ./artifacts + VERSION="${{ needs.preflight.outputs.SOURCE_REF_NAME }}" # will be tag or branch name + mv ./target/testnet/polkadot ./artifacts/. + mv ./target/testnet/polkadot-prepare-worker ./artifacts/. + mv ./target/testnet/polkadot-execute-worker ./artifacts/. + mv ./runtimes/ ./artifacts/. + cd artifacts/ + sha256sum polkadot | tee polkadot.sha256 + shasum -c polkadot.sha256 + cd ../ + EXTRATAG="${{ needs.preflight.outputs.SOURCE_REF_NAME }}-${COMMIT_SHA}" + echo "Polkadot version = ${VERSION} (EXTRATAG = ${EXTRATAG})" + echo -n ${VERSION} > ./artifacts/VERSION + echo -n ${EXTRATAG} > ./artifacts/EXTRATAG + echo -n ${GITHUB_RUN_ID} > ./artifacts/BUILD_LINUX_JOB_ID + RELEASE_VERSION=$(./artifacts/polkadot -V | awk '{print $2}'| awk -F "-" '{print $1}') + echo -n "v${RELEASE_VERSION}" > ./artifacts/BUILD_RELEASE_VERSION + cp -r docker/* ./artifacts + + - name: tar + run: tar -cvf artifacts.tar artifacts + + - name: upload artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ github.job }}-${{ needs.preflight.outputs.SOURCE_REF_NAME }} + path: artifacts.tar + retention-days: 1 + + # + # + # + build-linux-stable-cumulus: + needs: [preflight] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + timeout-minutes: 60 + container: + image: ${{ needs.preflight.outputs.IMAGE }} + env: + RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: build + run: | + echo "___Building a binary, please refrain from using it in production since it goes with the debug assertions.___" + forklift cargo build --release --locked -p polkadot-parachain-bin --bin polkadot-parachain + echo "___Packing the artifacts___" + mkdir -p ./artifacts + mv ./target/release/polkadot-parachain ./artifacts/. + echo "___The VERSION is either a tag name or the curent branch if triggered not by a tag___" + echo ${{ needs.preflight.outputs.SOURCE_REF_NAME }} | tee ./artifacts/VERSION + + - name: tar + run: tar -cvf artifacts.tar artifacts + + - name: upload artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ github.job }}-${{ needs.preflight.outputs.SOURCE_REF_NAME }} + path: artifacts.tar + retention-days: 1 + + # + # + # + build-test-parachain: + needs: [preflight] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + timeout-minutes: 60 + container: + image: ${{ needs.preflight.outputs.IMAGE }} + env: + RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: build + run: | + echo "___Building a binary, please refrain from using it in production since it goes with the debug assertions.___" + forklift cargo build --release --locked -p cumulus-test-service --bin test-parachain + - name: pack artifacts + run: | + echo "___Packing the artifacts___" + mkdir -p ./artifacts + mv ./target/release/test-parachain ./artifacts/. + mkdir -p ./artifacts/zombienet + mv ./target/release/wbuild/cumulus-test-runtime/wasm_binary_spec_version_incremented.rs.compact.compressed.wasm ./artifacts/zombienet/. + + - name: tar + run: tar -cvf artifacts.tar artifacts + + - name: upload artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ github.job }}-${{ needs.preflight.outputs.SOURCE_REF_NAME }} + path: artifacts.tar + retention-days: 1 + + # + # + # + build-test-collators: + needs: [preflight] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + timeout-minutes: 60 + container: + image: ${{ needs.preflight.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: build + run: | + forklift cargo build --locked --profile testnet -p test-parachain-adder-collator + forklift cargo build --locked --profile testnet -p test-parachain-undying-collator + - name: pack artifacts + run: | + mkdir -p ./artifacts + mv ./target/testnet/adder-collator ./artifacts/. + mv ./target/testnet/undying-collator ./artifacts/. + echo -n "${{ needs.preflight.outputs.SOURCE_REF_NAME }}" > ./artifacts/VERSION + echo -n "${{ needs.preflight.outputs.SOURCE_REF_NAME }}-${COMMIT_SHA}" > ./artifacts/EXTRATAG + echo "adder-collator version = $(cat ./artifacts/VERSION) (EXTRATAG = $(cat ./artifacts/EXTRATAG))" + echo "undying-collator version = $(cat ./artifacts/VERSION) (EXTRATAG = $(cat ./artifacts/EXTRATAG))" + cp -r ./docker/* ./artifacts + + - name: tar + run: tar -cvf artifacts.tar artifacts + + - name: upload artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ github.job }}-${{ needs.preflight.outputs.SOURCE_REF_NAME }} + path: artifacts.tar + retention-days: 1 + + # + # + # + build-malus: + needs: [preflight] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + timeout-minutes: 60 + container: + image: ${{ needs.preflight.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: build + run: | + forklift cargo build --locked --profile testnet -p polkadot-test-malus --bin malus --bin polkadot-prepare-worker --bin polkadot-execute-worker + - name: pack artifacts + run: | + mkdir -p ./artifacts + mv ./target/testnet/malus ./artifacts/. + mv ./target/testnet/polkadot-execute-worker ./artifacts/. + mv ./target/testnet/polkadot-prepare-worker ./artifacts/. + echo -n "${{ needs.preflight.outputs.SOURCE_REF_NAME }}" > ./artifacts/VERSION + echo -n "${{ needs.preflight.outputs.SOURCE_REF_NAME }}-${COMMIT_SHA}" > ./artifacts/EXTRATAG + echo "polkadot-test-malus = $(cat ./artifacts/VERSION) (EXTRATAG = $(cat ./artifacts/EXTRATAG))" + cp -r ./docker/* ./artifacts + + - name: tar + run: tar -cvf artifacts.tar artifacts + + - name: upload artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ github.job }}-${{ needs.preflight.outputs.SOURCE_REF_NAME }} + path: artifacts.tar + retention-days: 1 + + # + # + # + build-linux-substrate: + needs: [preflight] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + timeout-minutes: 60 + container: + image: ${{ needs.preflight.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # tldr: we need to checkout the branch HEAD explicitly because of our dynamic versioning approach while building the substrate binary + # see https://github.com/paritytech/ci_cd/issues/682#issuecomment-1340953589 + ref: ${{ github.head_ref || github.ref_name }} + - name: build + run: | + mkdir -p ./artifacts/substrate/ + WASM_BUILD_NO_COLOR=1 forklift cargo build --locked --release -p staging-node-cli + ls -la target/release/ + - name: pack artifacts + run: | + mv target/release/substrate-node ./artifacts/substrate/substrate + echo -n "Substrate version = " + if [[ "${{ github.ref }}" == "refs/tags/"* ]]; then + echo "${{ github.ref_name }}" | tee ./artifacts/substrate/VERSION; + else + ./artifacts/substrate/substrate --version | + cut -d ' ' -f 2 | tee ./artifacts/substrate/VERSION; + fi + sha256sum ./artifacts/substrate/substrate | tee ./artifacts/substrate/substrate.sha256 + cp -r ./docker/dockerfiles/substrate_injected.Dockerfile ./artifacts/substrate/ + + - name: tar + run: tar -cvf artifacts.tar artifacts + + - name: upload artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ github.job }}-${{ needs.preflight.outputs.SOURCE_REF_NAME }} + path: artifacts.tar + retention-days: 1 + + # + # + # + prepare-bridges-zombienet-artifacts: + needs: [preflight] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + timeout-minutes: 60 + container: + image: ${{ needs.preflight.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: build + run: | + forklift cargo build --locked --profile testnet -p polkadot-test-malus --bin malus --bin polkadot-prepare-worker --bin polkadot-execute-worker + - name: pack artifacts + run: | + mkdir -p ./artifacts/bridges-polkadot-sdk/bridges + cp -r bridges/testing ./artifacts/bridges-polkadot-sdk/bridges/testing + + - name: tar + run: tar -cvf artifacts.tar artifacts + + - name: upload artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ github.job }}-${{ needs.preflight.outputs.SOURCE_REF_NAME }} + path: artifacts.tar + retention-days: 1 + + ### Publish ######################## + + # + # + # + build-push-image-test-parachain: + needs: [preflight, build-test-parachain] + runs-on: ${{ needs.preflight.outputs.RUNNER_DEFAULT }} + timeout-minutes: 60 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4.1.8 + with: + name: build-test-parachain-${{ needs.preflight.outputs.SOURCE_REF_NAME }} + + - name: tar + run: tar -xvf artifacts.tar + + - name: build and push image + uses: ./.github/actions/build-push-image + with: + image-name: "europe-docker.pkg.dev/parity-ci-2024/temp-images/test-parachain" + dockerfile: "docker/dockerfiles/test-parachain_injected.Dockerfile" + + # + # + # + build-push-image-polkadot-debug: + needs: [preflight, build-linux-stable] + runs-on: ${{ needs.preflight.outputs.RUNNER_DEFAULT }} + timeout-minutes: 60 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4.1.8 + with: + name: build-linux-stable-${{ needs.preflight.outputs.SOURCE_REF_NAME }} + + - name: tar + run: tar -xvf artifacts.tar + + - name: build and push image + uses: ./.github/actions/build-push-image + with: + image-name: "europe-docker.pkg.dev/parity-ci-2024/temp-images/polkadot-debug" + dockerfile: "docker/dockerfiles/polkadot/polkadot_injected_debug.Dockerfile" + + # + # + # + build-push-image-colander: + needs: [preflight, build-test-collators] + runs-on: ${{ needs.preflight.outputs.RUNNER_DEFAULT }} + timeout-minutes: 60 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4.1.8 + with: + name: build-test-collators-${{ needs.preflight.outputs.SOURCE_REF_NAME }} + + - name: tar + run: tar -xvf artifacts.tar + + - name: build and push image + uses: ./.github/actions/build-push-image + with: + image-name: "europe-docker.pkg.dev/parity-ci-2024/temp-images/colander" + dockerfile: "docker/dockerfiles/collator_injected.Dockerfile" + + # + # + # + build-push-image-malus: + needs: [preflight, build-malus] + runs-on: ${{ needs.preflight.outputs.RUNNER_DEFAULT }} + timeout-minutes: 60 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4.1.8 + with: + name: build-malus-${{ needs.preflight.outputs.SOURCE_REF_NAME }} + + - name: tar + run: tar -xvf artifacts.tar + + - name: build and push image + uses: ./.github/actions/build-push-image + with: + image-name: "europe-docker.pkg.dev/parity-ci-2024/temp-images/malus" + dockerfile: "docker/dockerfiles/malus_injected.Dockerfile" + + # + # + # + build-push-image-substrate-pr: + needs: [preflight, build-linux-substrate] + runs-on: ${{ needs.preflight.outputs.RUNNER_DEFAULT }} + timeout-minutes: 60 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4.1.8 + with: + name: build-linux-substrate-${{ needs.preflight.outputs.SOURCE_REF_NAME }} + + - name: tar + run: tar -xvf artifacts.tar + + - name: build and push image + uses: ./.github/actions/build-push-image + with: + image-name: "europe-docker.pkg.dev/parity-ci-2024/temp-images/substrate" + dockerfile: "docker/dockerfiles/substrate_injected.Dockerfile" + + # + # + # + # unlike other images, bridges+zombienet image is based on Zombienet image that pulls required binaries + # from other fresh images (polkadot and cumulus) + build-push-image-bridges-zombienet-tests: + needs: + [ + preflight, + build-linux-stable, + build-linux-stable-cumulus, + prepare-bridges-zombienet-artifacts, + ] + runs-on: ${{ needs.preflight.outputs.RUNNER_DEFAULT }} + timeout-minutes: 60 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4.1.8 + with: + name: build-linux-stable-${{ needs.preflight.outputs.SOURCE_REF_NAME }} + - name: tar + run: | + tar -xvf artifacts.tar + rm artifacts.tar + + - uses: actions/download-artifact@v4.1.8 + with: + name: build-linux-stable-cumulus-${{ needs.preflight.outputs.SOURCE_REF_NAME }} + - name: tar + run: | + tar -xvf artifacts.tar + rm artifacts.tar + + - uses: actions/download-artifact@v4.1.8 + with: + name: prepare-bridges-zombienet-artifacts-${{ needs.preflight.outputs.SOURCE_REF_NAME }} + - name: tar + run: | + tar -xvf artifacts.tar + rm artifacts.tar + + - name: build and push image + uses: ./.github/actions/build-push-image + with: + image-name: "europe-docker.pkg.dev/parity-ci-2024/temp-images/bridges-zombienet-tests" + dockerfile: "docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile" + + # + # + # + build-push-image-polkadot-parachain-debug: + needs: [preflight, build-linux-stable-cumulus] + runs-on: ${{ needs.preflight.outputs.RUNNER_DEFAULT }} + timeout-minutes: 60 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4.1.8 + with: + name: build-linux-stable-cumulus-${{ needs.preflight.outputs.SOURCE_REF_NAME }} + + - name: tar + run: tar -xvf artifacts.tar + + - name: build and push image + uses: ./.github/actions/build-push-image + with: + image-name: "europe-docker.pkg.dev/parity-ci-2024/temp-images/polkadot-parachain-debug" + dockerfile: "docker/dockerfiles/polkadot-parachain/polkadot-parachain-debug_unsigned_injected.Dockerfile" diff --git a/.github/workflows/check-cargo-check-runtimes.yml b/.github/workflows/check-cargo-check-runtimes.yml new file mode 100644 index 000000000000..376c34d1f25f --- /dev/null +++ b/.github/workflows/check-cargo-check-runtimes.yml @@ -0,0 +1,124 @@ +name: Check Cargo Check Runtimes + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + paths: + - "cumulus/parachains/runtimes/*" + +# Jobs in this workflow depend on each other, only for limiting peak amount of spawned workers + +jobs: + preflight: + uses: ./.github/workflows/reusable-preflight.yml + + check-runtime-assets: + runs-on: ${{ needs.preflight.outputs.RUNNER }} + needs: [preflight] + timeout-minutes: 20 + container: + image: ${{ needs.preflight.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Run cargo check + uses: ./.github/actions/cargo-check-runtimes + with: + root: cumulus/parachains/runtimes/assets + + check-runtime-collectives: + runs-on: ${{ needs.preflight.outputs.RUNNER }} + needs: [check-runtime-assets, preflight] + timeout-minutes: 20 + container: + image: ${{ needs.preflight.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Run cargo check + uses: ./.github/actions/cargo-check-runtimes + with: + root: cumulus/parachains/runtimes/collectives + + check-runtime-coretime: + runs-on: ${{ needs.preflight.outputs.RUNNER }} + container: + image: ${{ needs.preflight.outputs.IMAGE }} + needs: [check-runtime-assets, preflight] + timeout-minutes: 20 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Run cargo check + uses: ./.github/actions/cargo-check-runtimes + with: + root: cumulus/parachains/runtimes/coretime + + check-runtime-bridge-hubs: + runs-on: ${{ needs.preflight.outputs.RUNNER }} + container: + image: ${{ needs.preflight.outputs.IMAGE }} + needs: [preflight] + timeout-minutes: 20 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Run cargo check + uses: ./.github/actions/cargo-check-runtimes + with: + root: cumulus/parachains/runtimes/bridge-hubs + + check-runtime-contracts: + runs-on: ${{ needs.preflight.outputs.RUNNER }} + container: + image: ${{ needs.preflight.outputs.IMAGE }} + needs: [check-runtime-collectives, preflight] + timeout-minutes: 20 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Run cargo check + uses: ./.github/actions/cargo-check-runtimes + with: + root: cumulus/parachains/runtimes/contracts + + check-runtime-testing: + runs-on: ${{ needs.preflight.outputs.RUNNER }} + container: + image: ${{ needs.preflight.outputs.IMAGE }} + needs: [preflight] + timeout-minutes: 20 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Run cargo check + uses: ./.github/actions/cargo-check-runtimes + with: + root: cumulus/parachains/runtimes/testing + + confirm-required-jobs-passed: + runs-on: ubuntu-latest + name: All check-runtime-* tests passed + # If any new job gets added, be sure to add it to this array + needs: + - check-runtime-assets + - check-runtime-collectives + - check-runtime-coretime + - check-runtime-bridge-hubs + - check-runtime-contracts + - check-runtime-testing + if: always() && !cancelled() + steps: + - run: | + tee resultfile <<< '${{ toJSON(needs) }}' + FAILURES=$(cat resultfile | grep '"result": "failure"' | wc -l) + if [ $FAILURES -gt 0 ]; then + echo "### At least one required job failed ❌" >> $GITHUB_STEP_SUMMARY + exit 1 + else + echo '### Good job! All the required jobs passed 🚀' >> $GITHUB_STEP_SUMMARY + fi diff --git a/.github/workflows/check-changed-files.yml b/.github/workflows/check-changed-files.yml deleted file mode 100644 index 657c05cd047d..000000000000 --- 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-features.yml b/.github/workflows/check-features.yml deleted file mode 100644 index d34b3d52c533..000000000000 --- a/.github/workflows/check-features.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Check Features - -on: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - -jobs: - check-features: - runs-on: ubuntu-latest - steps: - - name: Fetch latest code - uses: actions/checkout@v4 - - name: Check - uses: hack-ink/cargo-featalign-action@bea88a864d6ca7d0c53c26f1391ce1d431dc7f34 # v0.1.1 - with: - crate: templates/parachain/runtime/ - features: std,runtime-benchmarks,try-runtime - ignore: sc-executor - default-std: true diff --git a/.github/workflows/check-frame-omni-bencher.yml b/.github/workflows/check-frame-omni-bencher.yml new file mode 100644 index 000000000000..924a8b7f712f --- /dev/null +++ b/.github/workflows/check-frame-omni-bencher.yml @@ -0,0 +1,107 @@ +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: + preflight: + uses: ./.github/workflows/reusable-preflight.yml + + quick-benchmarks-omni: + runs-on: ${{ needs.preflight.outputs.RUNNER_BENCHMARK }} + needs: [preflight] + if: ${{ needs.preflight.outputs.changes_rust }} + env: + RUSTFLAGS: "-C debug-assertions" + RUST_BACKTRACE: "full" + WASM_BUILD_NO_COLOR: 1 + WASM_BUILD_RUSTFLAGS: "-C debug-assertions" + RUST_LOG: "frame_omni_bencher=info,polkadot_sdk_frame=info" + timeout-minutes: 30 + container: + image: ${{ needs.preflight.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: script + run: | + forklift cargo build --locked --quiet --release -p asset-hub-westend-runtime --features runtime-benchmarks + forklift cargo run --locked --release -p frame-omni-bencher --quiet -- v1 benchmark pallet --runtime target/release/wbuild/asset-hub-westend-runtime/asset_hub_westend_runtime.compact.compressed.wasm --all --steps 2 --repeat 1 --quiet + + runtime-matrix: + runs-on: ubuntu-latest + needs: [preflight] + if: ${{ needs.preflight.outputs.changes_rust }} + timeout-minutes: 30 + outputs: + runtime: ${{ steps.runtime.outputs.runtime }} + container: + image: ${{ needs.preflight.outputs.IMAGE }} + name: Extract runtimes from matrix + steps: + - uses: actions/checkout@v4 + - id: runtime + run: | + RUNTIMES=$(jq '[.[] | select(.package != null)]' .github/workflows/runtimes-matrix.json) + + RUNTIMES=$(echo $RUNTIMES | jq -c .) + echo "runtime=$RUNTIMES" + echo "runtime=$RUNTIMES" >> $GITHUB_OUTPUT + + run-frame-omni-bencher: + runs-on: ${{ needs.preflight.outputs.RUNNER_BENCHMARK }} + needs: [preflight, runtime-matrix] + if: ${{ needs.preflight.outputs.changes_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: ${{ fromJSON(needs.runtime-matrix.outputs.runtime) }} + container: + image: ${{ needs.preflight.outputs.IMAGE }} + env: + PACKAGE_NAME: ${{ matrix.runtime.package }} + FLAGS: ${{ matrix.runtime.bench_flags }} + RUST_LOG: "frame_omni_bencher=info,polkadot_sdk_frame=info" + 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=${{ matrix.runtime.bench_features }} --quiet + echo "Running short benchmarking for PACKAGE_NAME=$PACKAGE_NAME and RUNTIME_BLOB_PATH=$RUNTIME_BLOB_PATH" + ls -lrt $RUNTIME_BLOB_PATH + + cmd="./target/release/frame-omni-bencher v1 benchmark pallet --runtime $RUNTIME_BLOB_PATH --all --steps 2 --repeat 1 $FLAGS" + echo "Running command: $cmd" + eval "$cmd" + confirm-frame-omni-benchers-passed: + runs-on: ubuntu-latest + name: All benchmarks passed + needs: [quick-benchmarks-omni, run-frame-omni-bencher] + if: always() && !cancelled() + steps: + - run: | + tee resultfile <<< '${{ toJSON(needs) }}' + FAILURES=$(cat resultfile | grep '"result": "failure"' | wc -l) + if [ $FAILURES -gt 0 ]; then + echo "### At least one required job failed ❌" >> $GITHUB_STEP_SUMMARY + exit 1 + else + echo '### Good job! All the required jobs passed 🚀' >> $GITHUB_STEP_SUMMARY + fi diff --git a/.github/workflows/check-getting-started.yml b/.github/workflows/check-getting-started.yml new file mode 100644 index 000000000000..0661fa144348 --- /dev/null +++ b/.github/workflows/check-getting-started.yml @@ -0,0 +1,296 @@ +name: Check the getting-started.sh script + +# This workflow aims to make sure that the `getting-started.sh` script +# is functional and allows to build the templates +# on different operating systems. +# +# There are two jobs inside. +# One for systems that can run in a docker container, and one for macOS. +# +# Each job consists of: +# 1. Some necessary prerequisites for the workflow itself. +# 2. A first pass of the script, which will install dependencies and clone a template. +# 3. A second pass of the script, to make sure the behaviour is as expected. +# 4. Building the template - making sure it's buildable and runnable. +# +# The script is interacted with using the `expect` tool, which is available on all relevant systems. +# The steps are not re-used between macOS and other systems, +# because they are very similar but a little different. +# Additionally, macOS does NOT start from scratch here - for example, we have homebrew already installed. +# +# There are many combinations of systems, shells and templates. +# We test a selected handful of combinations here. + +on: + pull_request: + paths: + - ".github/workflows/check-getting-started.yml" + - "scripts/getting-started.sh" + schedule: + - cron: "0 5 * * *" + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + check-getting-started: + strategy: + fail-fast: true + matrix: + include: + - name: ubuntu + container: ubuntu + template: minimal + shell: bash + - name: debian + container: debian + template: parachain + shell: sh + - name: arch + container: archlinux + template: solochain + shell: sh + - name: fedora + container: fedora + template: parachain + shell: sh + - name: opensuse + container: opensuse/tumbleweed + template: solochain + shell: sh + runs-on: parity-large + container: ${{ matrix.container }}:latest + steps: + # A minimal amount of prerequisites required before we can run the actual getting-started script, + # which will install the rest of requirements. + - name: Install ubuntu/debian prerequisites + run: apt update && apt install -y expect sudo git + if: contains(matrix.name, 'ubuntu') || contains(matrix.name, 'debian') + - name: Install arch prerequisites + run: pacman -Syu --needed --noconfirm expect sudo git + if: contains(matrix.name, 'arch') + - name: Install fedora prerequisites + run: dnf --assumeyes install expect sudo git + if: contains(matrix.name, 'fedora') + - name: Install opensuse prerequisites + run: zypper install --no-confirm expect sudo git + if: contains(matrix.name, 'opensuse') + + - name: Checkout + uses: actions/checkout@v4 + + - name: Set additional expect flags if necessary + run: | + # Add a debug flag to expect, if github is re-run with debug logging enabled. + [ "${{ runner.debug }}" = "1" ] && EXPECT_FLAGS="-d" || EXPECT_FLAGS="" + echo "EXPECT_FLAGS=${EXPECT_FLAGS}" >> $GITHUB_ENV + + - name: Check the first run of the script + run: | + expect $EXPECT_FLAGS -c ' + set timeout 240 + + spawn ${{ matrix.shell }} scripts/getting-started.sh + + expect_after { + timeout { puts stderr "Timed out on an expect"; exit 1 } + eof { puts stderr "EOF received on an expect"; exit 1 } + } + + expect -nocase "Detected ${{ matrix.name }}" + + expect "Rust is not installed. Install it?" { + send "y\r" + expect "Proceed with standard installation (default - just press enter)" { + send "\r" + expect "Rust is installed now" + } + } + + expect "Setup the Rust environment" { + send "y\r" + } + + expect "start with one of the templates" { + send "y\r" + } + + expect -re "(.)\\) ${{ matrix.template }} template" { + send "$expect_out(1,string)\r" + } + + expect "compile the node?" { + send "n\r" + } + + expect eof + ' + timeout-minutes: 15 + + - name: Check the second run of the script + run: | + expect $EXPECT_FLAGS -c ' + set timeout 120 + + spawn ${{ matrix.shell }} scripts/getting-started.sh + + expect_after { + timeout { puts stderr "Timed out on an expect"; exit 1 } + eof { puts stderr "EOF received on an expect"; exit 1 } + } + + expect "Rust already installed" {} + + expect "Setup the Rust environment" { + send "n\r" + } + + expect "start with one of the templates" { + send "y\r" + } + + expect -re "(.)\\) ${{ matrix.template }} template" { + send "$expect_out(1,string)\r" + expect "directory already exists" {} + } + + expect "compile the node?" { + send "n\r" + } + + expect eof + ' + timeout-minutes: 15 + + - name: Compile the node outside of the script + run: | + . "$HOME/.cargo/env" + cd ${{ matrix.template }}-template + cargo build --release + timeout-minutes: 120 + + - name: Check that the binary is executable + run: | + . "$HOME/.cargo/env" + cd ${{ matrix.template }}-template + cargo run --release -- --help + timeout-minutes: 5 + + check-getting-started-macos: + strategy: + fail-fast: true + matrix: + include: + - template: parachain + shell: sh + - template: solochain + shell: bash + runs-on: macos-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set additional expect flags if necessary + run: | + # Add a debug flag to expect, if github is re-run with debug logging enabled. + [ "${{ runner.debug }}" = "1" ] && EXPECT_FLAGS="-d" || EXPECT_FLAGS="" + echo "EXPECT_FLAGS=${EXPECT_FLAGS}" >> $GITHUB_ENV + + - name: Check the first run of the script + run: | + expect $EXPECT_FLAGS -c ' + set timeout 120 + + spawn ${{ matrix.shell }} scripts/getting-started.sh + + expect_after { + timeout { puts stderr "Timed out on an expect"; exit 1 } + eof { puts stderr "EOF received on an expect"; exit 1 } + } + + expect -nocase "Detected macOS" + + expect "Homebrew already installed" + + expect "Install cmake" { + send "y\r" + } + + expect "Rust already installed" {} + + expect "Setup the Rust environment" { + send "y\r" + } + + expect "start with one of the templates" { + send "y\r" + } + + expect -re "(.)\\) ${{ matrix.template }} template" { + send "$expect_out(1,string)\r" + } + + expect "compile the node?" { + send "n\r" + } + + expect eof + ' + timeout-minutes: 15 + + - name: Check the second run of the script + run: | + expect $EXPECT_FLAGS -c ' + set timeout 120 + + spawn ${{ matrix.shell }} scripts/getting-started.sh + + expect_after { + timeout { puts stderr "Timed out on an expect"; exit 1 } + eof { puts stderr "EOF received on an expect"; exit 1 } + } + + expect "Homebrew already installed" + + expect "Install cmake" { + send "y\r" + } + + expect "Rust already installed" {} + + expect "Setup the Rust environment" { + send "n\r" + } + + expect "start with one of the templates" { + send "y\r" + } + + expect -re "(.)\\) ${{ matrix.template }} template" { + send "$expect_out(1,string)\r" + expect "directory already exists" {} + } + + expect "compile the node?" { + send "n\r" + } + + expect eof + ' + timeout-minutes: 15 + + - name: Compile the node outside of the script + run: | + . "$HOME/.cargo/env" + cd ${{ matrix.template }}-template + cargo build --release + timeout-minutes: 120 + + - name: Check that the binary is executable + run: | + . "$HOME/.cargo/env" + cd ${{ matrix.template }}-template + cargo run --release -- --help + timeout-minutes: 5 diff --git a/.github/workflows/check-labels.yml b/.github/workflows/check-labels.yml index 1d1a8770058d..d5c91e7f55e2 100644 --- a/.github/workflows/check-labels.yml +++ b/.github/workflows/check-labels.yml @@ -1,5 +1,9 @@ name: Check labels +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + on: pull_request: types: [labeled, opened, synchronize, unlabeled] @@ -8,6 +12,7 @@ on: jobs: check-labels: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - name: Check labels env: diff --git a/.github/workflows/check-licenses.yml b/.github/workflows/check-licenses.yml index 3bc95305f746..8bd87118201a 100644 --- a/.github/workflows/check-licenses.yml +++ b/.github/workflows/check-licenses.yml @@ -4,6 +4,10 @@ on: pull_request: merge_group: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + permissions: packages: read @@ -16,8 +20,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@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 + - uses: actions/setup-node@v4.0.4 with: node-version: "18.x" registry-url: "https://npm.pkg.github.com" @@ -35,7 +39,6 @@ jobs: shopt -s globstar npx @paritytech/license-scanner scan \ --ensure-licenses ${{ env.LICENSES }} \ - --exclude ./cumulus/parachain-template \ -- ./cumulus/**/*.rs - name: Check the licenses in Substrate @@ -44,3 +47,38 @@ jobs: npx @paritytech/license-scanner scan \ --ensure-licenses ${{ env.LICENSES }} \ -- ./substrate/**/*.rs + + check-product-references: + runs-on: ubuntu-latest + timeout-minutes: 10 + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - name: Checkout sources + uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 + - uses: actions/setup-node@v4.0.4 + with: + node-version: "18.x" + registry-url: "https://npm.pkg.github.com" + scope: "@paritytech" + + - name: Check the product references in Polkadot + run: | + shopt -s globstar + npx @paritytech/license-scanner scan \ + --ensure-product 'Polkadot' \ + -- ./polkadot/**/*.rs + + - name: Check the product references in Cumulus + run: | + shopt -s globstar + npx @paritytech/license-scanner scan \ + --ensure-product 'Cumulus' \ + -- ./cumulus/**/*.rs + + - name: Check the product references in Substrate + run: | + shopt -s globstar + npx @paritytech/license-scanner scan \ + --ensure-product 'Substrate' \ + -- ./substrate/**/*.rs diff --git a/.github/workflows/check-links.yml b/.github/workflows/check-links.yml index 58065f369c9c..3bbb9baba46e 100644 --- a/.github/workflows/check-links.yml +++ b/.github/workflows/check-links.yml @@ -10,25 +10,30 @@ on: types: [opened, synchronize, reopened, ready_for_review] merge_group: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + permissions: packages: read jobs: link-checker: runs-on: ubuntu-latest + timeout-minutes: 10 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@6d193bf28034eafb982f37bd894289fe649468fc # 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@2bb232618be239862e31382c5c0eaeba12e5e966 # 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 5df03f1044d8..8af1dd8cef70 100644 --- a/.github/workflows/check-prdoc.yml +++ b/.github/workflows/check-prdoc.yml @@ -1,12 +1,16 @@ name: Check PRdoc +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + on: pull_request: types: [labeled, opened, synchronize, unlabeled] merge_group: env: - IMAGE: docker.io/paritytech/prdoc:v0.0.8 + IMAGE: docker.io/paritytech/prdoc:v0.1.1 API_BASE: https://api.github.com/repos REPO: ${{ github.repository }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -17,10 +21,11 @@ env: jobs: check-prdoc: runs-on: ubuntu-latest + timeout-minutes: 10 if: github.event.pull_request.number != '' steps: - name: Checkout repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 #v4.1.1 + uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc #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 33da5a8ecd59..758de0e7b433 100644 --- a/.github/workflows/check-runtime-migration.yml +++ b/.github/workflows/check-runtime-migration.yml @@ -6,110 +6,130 @@ 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 jobs: - 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 - outputs: - IMAGE: ${{ steps.set_image.outputs.IMAGE }} - steps: - - name: Checkout - uses: actions/checkout@v4 - - id: set_image - run: cat .github/env >> $GITHUB_OUTPUT - # rococo and westend are disabled for now (no access to parity-chains.parity.io) + preflight: + uses: ./.github/workflows/reusable-preflight.yml + + # More info can be found here: https://github.com/paritytech/polkadot/pull/5865 check-runtime-migration: - runs-on: arc-runners-polkadot-sdk-beefy - timeout-minutes: 40 - needs: [set-image] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} + # 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: [preflight] container: - image: ${{ needs.set-image.outputs.IMAGE }} + image: ${{ needs.preflight.outputs.IMAGE }} strategy: fail-fast: false matrix: - network: [ - # westend, - # rococo, + network: + [ + westend, asset-hub-westend, - asset-hub-rococo, bridge-hub-westend, - bridge-hub-rococo, - contracts-rococo, collectives-westend, - coretime-rococo, + coretime-westend, ] include: - # - network: westend - # package: westend-runtime - # wasm: westend_runtime.compact.compressed.wasm - # uri: "wss://westend-try-runtime-node.parity-chains.parity.io:443" - # subcommand_extra_args: "--no-weight-warnings" - # command_extra_args: "" - # - network: rococo - # package: rococo-runtime - # wasm: rococo_runtime.compact.compressed.wasm - # uri: "wss://rococo-try-runtime-node.parity-chains.parity.io:443" - # subcommand_extra_args: "--no-weight-warnings" - # command_extra_args: "" + - network: westend + package: westend-runtime + wasm: westend_runtime.compact.compressed.wasm + uri: "wss://try-runtime-westend.polkadot.io:443" + subcommand_extra_args: "--no-weight-warnings --blocktime 6000" + command_extra_args: "" - network: asset-hub-westend package: asset-hub-westend-runtime wasm: asset_hub_westend_runtime.compact.compressed.wasm uri: "wss://westend-asset-hub-rpc.polkadot.io:443" - subcommand_extra_args: "" - command_extra_args: "" - - network: "asset-hub-rococo" - package: "asset-hub-rococo-runtime" - wasm: "asset_hub_rococo_runtime.compact.compressed.wasm" - uri: "wss://rococo-asset-hub-rpc.polkadot.io:443" - subcommand_extra_args: "" + subcommand_extra_args: " --blocktime 6000" command_extra_args: "" - - network: "bridge-hub-westend" - package: "bridge-hub-westend-runtime" - wasm: "bridge_hub_westend_runtime.compact.compressed.wasm" + - network: bridge-hub-westend + package: bridge-hub-westend-runtime + wasm: bridge_hub_westend_runtime.compact.compressed.wasm uri: "wss://westend-bridge-hub-rpc.polkadot.io:443" - - network: "bridge-hub-rococo" - package: "bridge-hub-rococo-runtime" - wasm: "bridge_hub_rococo_runtime.compact.compressed.wasm" - uri: "wss://rococo-bridge-hub-rpc.polkadot.io:443" - - network: "contracts-rococo" - package: "contracts-rococo-runtime" - wasm: "contracts_rococo_runtime.compact.compressed.wasm" - uri: "wss://rococo-contracts-rpc.polkadot.io:443" - - network: "collectives-westend" - package: "collectives-westend-runtime" - wasm: "collectives_westend_runtime.compact.compressed.wasm" + subcommand_extra_args: " --blocktime 6000" + - network: collectives-westend + package: collectives-westend-runtime + wasm: collectives_westend_runtime.compact.compressed.wasm uri: "wss://westend-collectives-rpc.polkadot.io:443" command_extra_args: "--disable-spec-name-check" - - network: "coretime-rococo" - package: "coretime-rococo-runtime" - wasm: "coretime_rococo_runtime.compact.compressed.wasm" - uri: "wss://rococo-coretime-rpc.polkadot.io:443" + subcommand_extra_args: " --blocktime 6000" + - network: coretime-westend + package: coretime-westend-runtime + wasm: coretime_westend_runtime.compact.compressed.wasm + uri: "wss://westend-coretime-rpc.polkadot.io:443" + subcommand_extra_args: " --blocktime 6000" 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.8.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 + # name of this job must be unique across all workflows + # otherwise GitHub will mark all these jobs as required + confirm-required-checks-passed: + runs-on: ubuntu-latest + name: All runtime migrations passed + # If any new job gets added, be sure to add it to this array + needs: [check-runtime-migration] + if: always() && !cancelled() + steps: + - run: | + tee resultfile <<< '${{ toJSON(needs) }}' + FAILURES=$(cat resultfile | grep '"result": "failure"' | wc -l) + if [ $FAILURES -gt 0 ]; then + echo "### At least one required job failed ❌" >> $GITHUB_STEP_SUMMARY + exit 1 + else + echo '### Good job! All the required jobs passed 🚀' >> $GITHUB_STEP_SUMMARY + fi diff --git a/.github/workflows/check-semver.yml b/.github/workflows/check-semver.yml index 47f9e5061b4a..65f3339b7ac7 100644 --- a/.github/workflows/check-semver.yml +++ b/.github/workflows/check-semver.yml @@ -3,45 +3,86 @@ 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: + preflight: + uses: ./.github/workflows/reusable-preflight.yml check-semver: runs-on: ubuntu-latest + timeout-minutes: 90 + needs: [preflight] container: - image: docker.io/paritytech/ci-unified:bullseye-1.77.0-2024-04-10-v20240408 + image: ${{ needs.preflight.outputs.IMAGE }} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 + with: + fetch-depth: 2 + + - name: extra git setup + run: | + git config --global --add safe.directory '*' + + git branch old HEAD^1 + + - 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." + + 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 + uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2.7.5 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 --locked -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 <> $GITHUB_OUTPUT + + preflight: + uses: ./.github/workflows/reusable-preflight.yml + fmt: runs-on: ubuntu-latest timeout-minutes: 20 - needs: [set-image] + needs: [preflight] container: - image: ${{ needs.set-image.outputs.IMAGE }} + image: ${{ needs.preflight.outputs.IMAGE }} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - name: Cargo fmt run: cargo +nightly fmt --all -- --check check-dependency-rules: runs-on: ubuntu-latest timeout-minutes: 20 steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - name: check dependency rules run: | cd substrate/ @@ -50,11 +41,11 @@ jobs: check-rust-feature-propagation: runs-on: ubuntu-latest timeout-minutes: 20 - needs: [set-image] + needs: [preflight] container: - image: ${{ needs.set-image.outputs.IMAGE }} + image: ${{ needs.preflight.outputs.IMAGE }} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - name: fetch deps run: | # Pull all dependencies eagerly: @@ -66,21 +57,21 @@ jobs: test-rust-features: runs-on: ubuntu-latest timeout-minutes: 20 - needs: [set-image] + needs: [preflight] container: - image: ${{ needs.set-image.outputs.IMAGE }} + image: ${{ needs.preflight.outputs.IMAGE }} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - name: run rust features run: bash .gitlab/rust-features.sh . check-toml-format: runs-on: ubuntu-latest timeout-minutes: 20 - needs: [set-image] + needs: [preflight] container: - image: ${{ needs.set-image.outputs.IMAGE }} + image: ${{ needs.preflight.outputs.IMAGE }} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - name: check toml format run: | taplo format --check --config .config/taplo.toml @@ -89,7 +80,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 20 steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.0 (22. Sep 2023) + - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.0 (22. Sep 2023) - name: install python deps run: | sudo apt-get update && sudo apt-get install -y python3-pip python3 @@ -100,6 +91,8 @@ jobs: --exclude "substrate/frame/contracts/fixtures/build" "substrate/frame/contracts/fixtures/contracts/common" + "substrate/frame/revive/fixtures/build" + "substrate/frame/revive/fixtures/contracts/common" - name: deny git deps run: python3 .github/scripts/deny-git-deps.py . check-markdown: @@ -107,9 +100,9 @@ jobs: timeout-minutes: 20 steps: - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - name: Setup Node.js - uses: actions/setup-node@v4.0.1 + uses: actions/setup-node@v4.0.4 with: node-version: "18.x" registry-url: "https://npm.pkg.github.com" @@ -128,11 +121,11 @@ jobs: check-umbrella: runs-on: ubuntu-latest timeout-minutes: 20 - needs: [set-image] + needs: [preflight] container: - image: ${{ needs.set-image.outputs.IMAGE }} + image: ${{ needs.preflight.outputs.IMAGE }} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.0 (22. Sep 2023) + - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.0 (22. Sep 2023) - name: install python deps run: pip3 install "cargo-workspace>=1.2.4" toml - name: check umbrella correctness @@ -154,3 +147,54 @@ jobs: git diff exit 1 fi + check-fail-ci: + runs-on: ubuntu-latest + container: + # there's no "rg" in ci-unified, and tools is a smaller image anyway + image: "paritytech/tools:latest" + # paritytech/tools uses "nonroot" user by default, which doesn't have enough + # permissions to create GHA context + options: --user root + steps: + - name: Fetch latest code + uses: actions/checkout@v4 + - name: Check + run: | + set +e + rg --line-number --hidden --type rust --glob '!{.git,target}' "$ASSERT_REGEX" .; exit_status=$? + if [ $exit_status -eq 0 ]; then + echo "$ASSERT_REGEX was found, exiting with 1"; + exit 1; + else + echo "No $ASSERT_REGEX was found, exiting with 0"; + exit 0; + fi + env: + ASSERT_REGEX: "FAIL-CI" + GIT_DEPTH: 1 + + confirm-required-checks-quick-jobs-passed: + runs-on: ubuntu-latest + name: All quick checks passed + # If any new job gets added, be sure to add it to this array + needs: + - fmt + - check-dependency-rules + - check-rust-feature-propagation + - test-rust-features + - check-toml-format + - check-workspace + - check-markdown + - check-umbrella + - check-fail-ci + if: always() && !cancelled() + steps: + - run: | + tee resultfile <<< '${{ toJSON(needs) }}' + FAILURES=$(cat resultfile | grep '"result": "failure"' | wc -l) + if [ $FAILURES -gt 0 ]; then + echo "### At least one required job failed ❌" >> $GITHUB_STEP_SUMMARY + exit 1 + else + echo '### Good job! All the required jobs passed 🚀' >> $GITHUB_STEP_SUMMARY + fi diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml new file mode 100644 index 000000000000..0793c31dbb87 --- /dev/null +++ b/.github/workflows/checks.yml @@ -0,0 +1,93 @@ +name: Checks + +on: + push: + branches: + - master + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + merge_group: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: {} + +jobs: + preflight: + uses: ./.github/workflows/reusable-preflight.yml + + cargo-clippy: + runs-on: ${{ needs.preflight.outputs.RUNNER }} + needs: [preflight] + if: ${{ needs.preflight.outputs.changes_rust }} + timeout-minutes: 40 + container: + image: ${{ needs.preflight.outputs.IMAGE }} + env: + RUSTFLAGS: "-D warnings" + SKIP_WASM_BUILD: 1 + steps: + - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 + - name: script + run: | + forklift cargo clippy --all-targets --locked --workspace --quiet + forklift cargo clippy --all-targets --all-features --locked --workspace --quiet + check-try-runtime: + runs-on: ${{ needs.preflight.outputs.RUNNER }} + needs: [preflight] + if: ${{ needs.preflight.outputs.changes_rust }} + timeout-minutes: 40 + container: + image: ${{ needs.preflight.outputs.IMAGE }} + steps: + - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 + - name: script + run: | + forklift cargo check --locked --all --features try-runtime --quiet + # 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 --quiet + # check-core-crypto-features works fast without forklift + check-core-crypto-features: + runs-on: ${{ needs.preflight.outputs.RUNNER }} + needs: [preflight] + if: ${{ needs.preflight.outputs.changes_rust }} + timeout-minutes: 30 + container: + image: ${{ needs.preflight.outputs.IMAGE }} + steps: + - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # 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 - + # name of this job must be unique across all workflows + # otherwise GitHub will mark all these jobs as required + confirm-required-checks-passed: + runs-on: ubuntu-latest + name: All checks passed + # If any new job gets added, be sure to add it to this array + needs: [cargo-clippy, check-try-runtime, check-core-crypto-features] + if: always() && !cancelled() + steps: + - run: | + tee resultfile <<< '${{ toJSON(needs) }}' + FAILURES=$(cat resultfile | grep '"result": "failure"' | wc -l) + if [ $FAILURES -gt 0 ]; then + echo "### At least one required job failed ❌" >> $GITHUB_STEP_SUMMARY + exit 1 + else + echo '### Good job! All the required jobs passed 🚀' >> $GITHUB_STEP_SUMMARY + fi diff --git a/.github/workflows/cmd-tests.yml b/.github/workflows/cmd-tests.yml new file mode 100644 index 000000000000..af73c6a5b2d3 --- /dev/null +++ b/.github/workflows/cmd-tests.yml @@ -0,0 +1,18 @@ +name: Command Bot Tests + +on: + pull_request: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + test-cmd-bot: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: python3 .github/scripts/cmd/test_cmd.py diff --git a/.github/workflows/cmd.yml b/.github/workflows/cmd.yml new file mode 100644 index 000000000000..525ab0c0fc23 --- /dev/null +++ b/.github/workflows/cmd.yml @@ -0,0 +1,504 @@ +name: Command + +on: + issue_comment: # listen for comments on issues + types: [created] + +permissions: # allow the action to comment on the PR + contents: write + issues: write + pull-requests: write + actions: read + +jobs: + is-org-member: + if: startsWith(github.event.comment.body, '/cmd') + runs-on: ubuntu-latest + outputs: + member: ${{ steps.is-member.outputs.result }} + steps: + - name: Generate token + id: generate_token + uses: tibdex/github-app-token@v2.1.0 + with: + app_id: ${{ secrets.CMD_BOT_APP_ID }} + private_key: ${{ secrets.CMD_BOT_APP_KEY }} + + - name: Check if user is a member of the organization + id: is-member + uses: actions/github-script@v7 + with: + github-token: ${{ steps.generate_token.outputs.token }} + result-encoding: string + script: | + const fs = require("fs"); + try { + const org = '${{ github.event.repository.owner.login }}'; + const username = '${{ github.event.comment.user.login }}'; + + const membership = await github.rest.orgs.checkMembershipForUser({ + org: org, + username: username + }); + + console.log(membership, membership.status, membership.status === 204); + + if (membership.status === 204) { + return 'true'; + } else { + console.log(membership); + fs.appendFileSync(process.env["GITHUB_STEP_SUMMARY"], `${membership.data && membership.data.message || 'Unknown error happened, please check logs'}`); + } + } catch (error) { + console.log(error) + } + + return 'false'; + + reject-non-members: + needs: is-org-member + if: ${{ startsWith(github.event.comment.body, '/cmd') && needs.is-org-member.outputs.member != 'true' }} + runs-on: ubuntu-latest + steps: + - name: Add reaction to rejected comment + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + github.rest.reactions.createForIssueComment({ + comment_id: ${{ github.event.comment.id }}, + owner: context.repo.owner, + repo: context.repo.repo, + content: 'confused' + }) + + - name: Comment PR (Rejected) + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `Sorry, only members of the organization ${{ github.event.repository.owner.login }} members can run commands.` + }) + + acknowledge: + needs: is-org-member + if: ${{ startsWith(github.event.comment.body, '/cmd') && needs.is-org-member.outputs.member == 'true' }} + runs-on: ubuntu-latest + steps: + - name: Add reaction to triggered comment + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + github.rest.reactions.createForIssueComment({ + comment_id: ${{ github.event.comment.id }}, + owner: context.repo.owner, + repo: context.repo.repo, + content: 'eyes' + }) + + clean: + needs: is-org-member + runs-on: ubuntu-latest + steps: + - name: Clean previous comments + if: ${{ startsWith(github.event.comment.body, '/cmd') && contains(github.event.comment.body, '--clean') && needs.is-org-member.outputs.member == 'true' }} + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + github.rest.issues.listComments({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo + }).then(comments => { + for (let comment of comments.data) { + console.log(comment) + if ( + ${{ github.event.comment.id }} !== comment.id && + ( + ( + ( + comment.body.startsWith('Command') || + comment.body.startsWith('
Command') || + comment.body.startsWith('Sorry, only ') + ) && comment.user.type === 'Bot' + ) || + (comment.body.startsWith('/cmd') && comment.user.login === context.actor) + ) + ) { + github.rest.issues.deleteComment({ + comment_id: comment.id, + owner: context.repo.owner, + repo: context.repo.repo + }) + } + } + }) + help: + needs: [clean, is-org-member] + if: ${{ startsWith(github.event.comment.body, '/cmd') && contains(github.event.comment.body, '--help') && needs.is-org-member.outputs.member == 'true' }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Get command + uses: actions-ecosystem/action-regex-match@v2 + id: get-pr-comment + with: + text: ${{ github.event.comment.body }} + regex: "^(\\/cmd )([-\\/\\s\\w.=:]+)$" # see explanation in docs/contributor/commands-readme.md#examples + + - name: Save output of help + id: help + env: + CMD: ${{ steps.get-pr-comment.outputs.group2 }} # to avoid "" around the command + run: | + python3 -m pip install -r .github/scripts/generate-prdoc.requirements.txt + echo 'help<> $GITHUB_OUTPUT + python3 .github/scripts/cmd/cmd.py $CMD >> $GITHUB_OUTPUT + echo 'EOF' >> $GITHUB_OUTPUT + + - name: Comment PR (Help) + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `
Command help: + + \`\`\` + ${{ steps.help.outputs.help }} + \`\`\` + +
` + }) + + - name: Add confused reaction on failure + uses: actions/github-script@v7 + if: ${{ failure() }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + github.rest.reactions.createForIssueComment({ + comment_id: ${{ github.event.comment.id }}, + owner: context.repo.owner, + repo: context.repo.repo, + content: 'confused' + }) + + - name: Add 👍 reaction on success + uses: actions/github-script@v7 + if: ${{ !failure() }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + github.rest.reactions.createForIssueComment({ + comment_id: ${{ github.event.comment.id }}, + owner: context.repo.owner, + repo: context.repo.repo, + content: '+1' + }) + + set-image: + needs: [clean, is-org-member] + if: ${{ startsWith(github.event.comment.body, '/cmd') && !contains(github.event.comment.body, '--help') && needs.is-org-member.outputs.member == 'true' }} + runs-on: ubuntu-latest + outputs: + IMAGE: ${{ steps.set-image.outputs.IMAGE }} + RUNNER: ${{ steps.set-image.outputs.RUNNER }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - id: set-image + run: | + BODY=$(echo "${{ github.event.comment.body }}" | xargs) + IMAGE_OVERRIDE=$(echo $BODY | grep -oe 'docker.io/paritytech/ci-unified:.*\s' | xargs) + + cat .github/env >> $GITHUB_OUTPUT + + if [ -n "$IMAGE_OVERRIDE" ]; then + echo "IMAGE=$IMAGE_OVERRIDE" >> $GITHUB_OUTPUT + fi + + if [[ $BODY == "/cmd bench"* ]]; then + echo "RUNNER=parity-weights" >> $GITHUB_OUTPUT + elif [[ $BODY == "/cmd update-ui"* ]]; then + echo "RUNNER=parity-large" >> $GITHUB_OUTPUT + else + echo "RUNNER=ubuntu-latest" >> $GITHUB_OUTPUT + fi + + # Get PR branch name, because the issue_comment event does not contain the PR branch name + get-pr-branch: + needs: [set-image] + runs-on: ubuntu-latest + outputs: + pr-branch: ${{ steps.get-pr.outputs.pr_branch }} + repo: ${{ steps.get-pr.outputs.repo }} + steps: + - name: Check if the issue is a PR + id: check-pr + run: | + if [ -n "${{ github.event.issue.pull_request.url }}" ]; then + echo "This is a pull request comment" + else + echo "This is not a pull request comment" + exit 1 + fi + + - name: Get PR Branch Name and Repo + if: steps.check-pr.outcome == 'success' + id: get-pr + uses: actions/github-script@v7 + with: + script: | + const pr = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + }); + const prBranch = pr.data.head.ref; + const repo = pr.data.head.repo.full_name; + console.log(prBranch, repo) + core.setOutput('pr_branch', prBranch); + core.setOutput('repo', repo); + + - name: Use PR Branch Name and Repo + run: | + echo "The PR branch is ${{ steps.get-pr.outputs.pr_branch }}" + echo "The repository is ${{ steps.get-pr.outputs.repo }}" + + cmd: + needs: [set-image, get-pr-branch] + env: + JOB_NAME: "cmd" + runs-on: ${{ needs.set-image.outputs.RUNNER }} + timeout-minutes: 4320 # 72 hours -> 3 days; as it could take a long time to run all the runtimes/pallets + container: + image: ${{ needs.set-image.outputs.IMAGE }} + steps: + - name: Get command + uses: actions-ecosystem/action-regex-match@v2 + id: get-pr-comment + with: + text: ${{ github.event.comment.body }} + regex: "^(\\/cmd )([-\\/\\s\\w.=:]+)$" # see explanation in docs/contributor/commands-readme.md#examples + + # In order to run prdoc without specifying the PR number, we need to add the PR number as an argument automatically + - name: Prepare PR Number argument + id: pr-arg + run: | + CMD="${{ steps.get-pr-comment.outputs.group2 }}" + if echo "$CMD" | grep -q "prdoc" && ! echo "$CMD" | grep -qE "\-\-pr[[:space:]=][0-9]+"; then + echo "arg=--pr ${{ github.event.issue.number }}" >> $GITHUB_OUTPUT + else + echo "arg=" >> $GITHUB_OUTPUT + fi + + - name: Build workflow link + if: ${{ !contains(github.event.comment.body, '--quiet') }} + id: build-link + run: | + # Get exactly the CMD job link, filtering out the other jobs + jobLink=$(curl -s \ + -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + -H "Accept: application/vnd.github.v3+json" \ + https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/jobs | jq '.jobs[] | select(.name | contains("${{ env.JOB_NAME }}")) | .html_url') + + runLink=$(curl -s \ + -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + -H "Accept: application/vnd.github.v3+json" \ + https://api.github.com/repos/${{ github.repository }}/actions/runs/${{ github.run_id }} | jq '.html_url') + + echo "job_url=${jobLink}" + echo "run_url=${runLink}" + echo "job_url=$jobLink" >> $GITHUB_OUTPUT + echo "run_url=$runLink" >> $GITHUB_OUTPUT + + - name: Comment PR (Start) + # No need to comment on prdoc start or if --quiet + if: ${{ !contains(github.event.comment.body, '--quiet') && !contains(github.event.comment.body, 'prdoc') }} + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + let job_url = ${{ steps.build-link.outputs.job_url }} + + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `Command "${{ steps.get-pr-comment.outputs.group2 }}" has started 🚀 [See logs here](${job_url})` + }) + + - name: Checkout + uses: actions/checkout@v4 + with: + repository: ${{ needs.get-pr-branch.outputs.repo }} + ref: ${{ needs.get-pr-branch.outputs.pr-branch }} + + - name: Install dependencies for bench + if: startsWith(steps.get-pr-comment.outputs.group2, 'bench') + run: | + cargo install subweight --locked + cargo install --path substrate/utils/frame/omni-bencher --locked + + - name: Run cmd + id: cmd + env: + CMD: ${{ steps.get-pr-comment.outputs.group2 }} # to avoid "" around the command + PR_ARG: ${{ steps.pr-arg.outputs.arg }} + run: | + echo "Running command: '$CMD $PR_ARG' on '${{ needs.set-image.outputs.RUNNER }}' runner, container: '${{ needs.set-image.outputs.IMAGE }}'" + echo "RUST_NIGHTLY_VERSION: $RUST_NIGHTLY_VERSION" + # Fixes "detected dubious ownership" error in the ci + git config --global --add safe.directory '*' + git remote -v + python3 -m pip install -r .github/scripts/generate-prdoc.requirements.txt + python3 .github/scripts/cmd/cmd.py $CMD $PR_ARG + git status + git diff + + if [ -f /tmp/cmd/command_output.log ]; then + CMD_OUTPUT=$(cat /tmp/cmd/command_output.log) + # export to summary to display in the PR + echo "$CMD_OUTPUT" >> $GITHUB_STEP_SUMMARY + # should be multiline, otherwise it captures the first line only + echo 'cmd_output<> $GITHUB_OUTPUT + echo "$CMD_OUTPUT" >> $GITHUB_OUTPUT + echo 'EOF' >> $GITHUB_OUTPUT + fi + + - name: Upload command output + if: ${{ always() }} + uses: actions/upload-artifact@v4 + with: + name: command-output + path: /tmp/cmd/command_output.log + + - name: Commit changes + run: | + if [ -n "$(git status --porcelain)" ]; then + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + + git add . + git restore --staged Cargo.lock # ignore changes in Cargo.lock + git commit -m "Update from ${{ github.actor }} running command '${{ steps.get-pr-comment.outputs.group2 }}'" || true + + git pull --rebase origin ${{ needs.get-pr-branch.outputs.pr-branch }} + + git push origin ${{ needs.get-pr-branch.outputs.pr-branch }} + else + echo "Nothing to commit"; + fi + + - name: Run Subweight + id: subweight + if: startsWith(steps.get-pr-comment.outputs.group2, 'bench') + shell: bash + run: | + git fetch + result=$(subweight compare commits \ + --path-pattern "./**/weights/**/*.rs,./**/weights.rs" \ + --method asymptotic \ + --format markdown \ + --no-color \ + --change added changed \ + --ignore-errors \ + refs/remotes/origin/master refs/heads/${{ needs.get-pr-branch.outputs.pr-branch }}) + + # Save the multiline result to the output + { + echo "result<> $GITHUB_OUTPUT + + - name: Comment PR (End) + # No need to comment on prdoc success or --quiet + if: ${{ !failure() && !contains(github.event.comment.body, '--quiet') && !contains(github.event.comment.body, 'prdoc') }} + uses: actions/github-script@v7 + env: + SUBWEIGHT: "${{ steps.subweight.outputs.result }}" + CMD_OUTPUT: "${{ steps.cmd.outputs.cmd_output }}" + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + let runUrl = ${{ steps.build-link.outputs.run_url }} + let subweight = process.env.SUBWEIGHT; + let cmdOutput = process.env.CMD_OUTPUT; + console.log(cmdOutput); + + let subweightCollapsed = subweight.trim() !== '' + ? `
\n\nSubweight results:\n\n${subweight}\n\n
` + : ''; + + let cmdOutputCollapsed = cmdOutput.trim() !== '' + ? `
\n\nCommand output:\n\n${cmdOutput}\n\n
` + : ''; + + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `Command "${{ steps.get-pr-comment.outputs.group2 }}" has finished ✅ [See logs here](${runUrl})${subweightCollapsed}${cmdOutputCollapsed}` + }) + + - name: Comment PR (Failure) + if: ${{ failure() && !contains(github.event.comment.body, '--quiet') }} + uses: actions/github-script@v7 + env: + CMD_OUTPUT: "${{ steps.cmd.outputs.cmd_output }}" + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + let jobUrl = ${{ steps.build-link.outputs.job_url }} + let cmdOutput = process.env.CMD_OUTPUT; + + let cmdOutputCollapsed = cmdOutput.trim() !== '' + ? `
\n\nCommand output:\n\n${cmdOutput}\n\n
` + : ''; + + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `Command "${{ steps.get-pr-comment.outputs.group2 }}" has failed ❌! [See logs here](${jobUrl})${cmdOutputCollapsed}` + }) + + - name: Add 😕 reaction on failure + uses: actions/github-script@v7 + if: ${{ failure() }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + github.rest.reactions.createForIssueComment({ + comment_id: ${{ github.event.comment.id }}, + owner: context.repo.owner, + repo: context.repo.repo, + content: 'confused' + }) + + - name: Add 👍 reaction on success + uses: actions/github-script@v7 + if: ${{ !failure() }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + github.rest.reactions.createForIssueComment({ + comment_id: ${{ github.event.comment.id }}, + owner: context.repo.owner, + repo: context.repo.repo, + content: '+1' + }) diff --git a/.github/workflows/command-backport.yml b/.github/workflows/command-backport.yml new file mode 100644 index 000000000000..8f23bcd75f01 --- /dev/null +++ b/.github/workflows/command-backport.yml @@ -0,0 +1,96 @@ +name: Backport into stable + +on: + # This trigger can be problematic, see: https://securitylab.github.com/resources/github-actions-preventing-pwn-requests/ + # In our case it is fine since we only run it on merged Pull Requests and do not execute any of the repo code itself. + pull_request_target: + types: [closed, labeled] + +permissions: + contents: write # so it can comment + pull-requests: write # so it can create pull requests + issues: write + actions: write # It may have to backport changes to the CI as well. + +jobs: + backport: + name: Backport pull request + runs-on: ubuntu-latest + + # The 'github.event.pull_request.merged' ensures that it got into master: + if: > + ( !startsWith(github.event.pull_request.base.ref, 'stable') ) && + ( + github.event_name == 'pull_request_target' && + github.event.pull_request.merged && + github.event.pull_request.base.ref == 'master' && + contains(github.event.pull_request.labels.*.name, 'A4-needs-backport') + ) + steps: + - uses: actions/checkout@v4 + + - name: Generate token + id: generate_token + uses: tibdex/github-app-token@v2.1.0 + with: + app_id: ${{ secrets.CMD_BOT_APP_ID }} + private_key: ${{ secrets.CMD_BOT_APP_KEY }} + + - name: Create backport pull requests + uses: korthout/backport-action@v3 + id: backport + with: + target_branches: stable2407 stable2409 + merge_commits: skip + github_token: ${{ steps.generate_token.outputs.token }} + pull_description: | + Backport #${pull_number} into `${target_branch}` from ${pull_author}. + + See the [documentation](https://github.com/paritytech/polkadot-sdk/blob/master/docs/BACKPORT.md) on how to use this bot. + + + pull_title: | + [${target_branch}] Backport #${pull_number} + experimental: > + { + "conflict_resolution": "draft_commit_conflicts" + } + copy_assignees: true + + - name: Label Backports + if: ${{ steps.backport.outputs.created_pull_numbers != '' }} + uses: actions/github-script@v7 + with: + script: | + const pullNumbers = '${{ steps.backport.outputs.created_pull_numbers }}'.split(' '); + + for (const pullNumber of pullNumbers) { + await github.rest.issues.addLabels({ + issue_number: parseInt(pullNumber), + owner: context.repo.owner, + repo: context.repo.repo, + labels: ['A3-backport'] + }); + console.log(`Added A3-backport label to PR #${pullNumber}`); + } + + - name: Request Review + if: ${{ steps.backport.outputs.created_pull_numbers != '' }} + uses: actions/github-script@v7 + with: + script: | + const pullNumbers = '${{ steps.backport.outputs.created_pull_numbers }}'.split(' '); + const reviewer = '${{ github.event.pull_request.user.login }}'; + + for (const pullNumber of pullNumbers) { + await github.pulls.createReviewRequest({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: parseInt(pullNumber), + reviewers: [ reviewer ] + }); + console.log(`Requested review from ${reviewer} for PR #${pullNumber}`); + } diff --git a/.github/workflows/command-bench-all.yml b/.github/workflows/command-bench-all.yml deleted file mode 100644 index 4128f86fb7c8..000000000000 --- a/.github/workflows/command-bench-all.yml +++ /dev/null @@ -1,99 +0,0 @@ -name: Command Bench All - -on: - workflow_dispatch: - inputs: - pr: - description: Number of the Pull Request - required: true - benchmark: - description: Pallet benchmark - type: choice - required: true - options: - - pallet - - substrate - - polkadot - - cumulus - pallet: - description: Pallet - required: false - type: string - default: pallet_name - target_dir: - description: Target directory - type: choice - options: - - substrate - - polkadot - - cumulus - runtime: - description: Runtime - type: choice - options: - - rococo - - westend - - asset-hub-kusama - - asset-hub-polkadot - - asset-hub-rococo - - asset-hub-westend - - bridge-hub-kusama - - bridge-hub-polkadot - - bridge-hub-rococo - - bridge-hub-westend - - collectives-polkadot - - collectives-westend - - coretime-rococo - - coretime-westend - - contracts-rococo - - glutton-kusama - - glutton-westend - - people-rococo - - people-westend - -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-bench-all: - needs: [set-image] - runs-on: arc-runners-polkadot-sdk-weights - container: - image: ${{ needs.set-image.outputs.IMAGE }} - permissions: - contents: write - pull-requests: write - steps: - - name: Download repo - uses: actions/checkout@v4 - - name: Install gh cli - id: gh - uses: ./.github/actions/set-up-gh - with: - pr-number: ${{ inputs.pr }} - GH_TOKEN: ${{ github.token }} - - name: Run bench all - run: | - "./scripts/bench-all.sh" "${{ inputs.benchmark }}" --runtime "${{ inputs.runtime }}" --pallet "${{ inputs.pallet }}" --target_dir "${{ inputs.target_dir }}" - - name: Report failure - if: ${{ failure() }} - run: gh pr comment ${{ inputs.pr }} --body "

Command failed ❌

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

Action completed 🎉🎉

Run by @${{ github.actor }} for ${{ github.workflow }} completed 🎉. See logs here." - env: - RUN: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - GH_TOKEN: ${{ github.token }} diff --git a/.github/workflows/command-bench-overhead.yml b/.github/workflows/command-bench-overhead.yml deleted file mode 100644 index fec8d37bb9ef..000000000000 --- a/.github/workflows/command-bench-overhead.yml +++ /dev/null @@ -1,78 +0,0 @@ -name: Command Bench Overhead - -on: - workflow_dispatch: - inputs: - pr: - description: Number of the Pull Request - required: true - benchmark: - description: Pallet benchmark - type: choice - required: true - options: - - default - - substrate - - cumulus - runtime: - description: Runtime - type: choice - options: - - rococo - - westend - - asset-hub-rococo - - asset-hub-westend - target_dir: - description: Target directory - type: choice - options: - - polkadot - - substrate - - cumulus - -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-bench-overhead: - needs: [set-image] - runs-on: arc-runners-polkadot-sdk-benchmark - container: - image: ${{ needs.set-image.outputs.IMAGE }} - permissions: - contents: write - pull-requests: write - steps: - - name: Download repo - uses: actions/checkout@v4 - - name: Install gh cli - id: gh - uses: ./.github/actions/set-up-gh - with: - pr-number: ${{ inputs.pr }} - GH_TOKEN: ${{ github.token }} - - name: Run bench overhead - run: | - "./scripts/bench.sh" "${{ inputs.benchmark }}" --subcommand "overhead" --runtime "${{ inputs.runtime }}" --target_dir "${{ inputs.target_dir }}" - - name: Report failure - if: ${{ failure() }} - run: gh pr comment ${{ inputs.pr }} --body "

Command failed ❌

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

Action completed 🎉🎉

Run by @${{ github.actor }} for ${{ github.workflow }} completed 🎉. See logs here." - env: - RUN: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - GH_TOKEN: ${{ github.token }} diff --git a/.github/workflows/command-bench.yml b/.github/workflows/command-bench.yml deleted file mode 100644 index ac879f443755..000000000000 --- a/.github/workflows/command-bench.yml +++ /dev/null @@ -1,124 +0,0 @@ -name: Command Bench - -on: - workflow_dispatch: - inputs: - pr: - description: Number of the Pull Request - required: true - benchmark: - description: Pallet benchmark - type: choice - required: true - options: - - substrate-pallet - - polkadot-pallet - - cumulus-assets - - cumulus-collectives - - cumulus-coretime - - cumulus-bridge-hubs - - cumulus-contracts - - cumulus-glutton - - cumulus-starters - - cumulus-people - - cumulus-testing - subcommand: - description: Subcommand - type: choice - required: true - options: - - pallet - - xcm - runtime: - description: Runtime - type: choice - options: - - dev - - rococo - - westend - - asset-hub-westend - - asset-hub-rococo - - collectives-westend - - coretime-rococo - - coretime-westend - - bridge-hub-rococo - - bridge-hub-westend - - contracts-rococo - - glutton-westend - - glutton-westend-dev-1300 - - seedling - - shell - - people-westend - - people-rococo - - penpal - - rococo-parachain - pallet: - description: Pallet - type: string - default: pallet_name - target_dir: - description: Target directory - type: choice - options: - - substrate - - polkadot - - cumulus - runtime_dir: - description: Runtime directory - type: choice - options: - - people - - collectives - - coretime - - bridge-hubs - - contracts - - glutton - - starters - - testing - -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-bench: - needs: [set-image] - runs-on: arc-runners-polkadot-sdk-benchmark - container: - image: ${{ needs.set-image.outputs.IMAGE }} - permissions: - contents: write - pull-requests: write - steps: - - name: Download repo - uses: actions/checkout@v4 - - name: Install gh cli - id: gh - uses: ./.github/actions/set-up-gh - with: - pr-number: ${{ inputs.pr }} - GH_TOKEN: ${{ github.token }} - - name: Run bench - run: | - "./scripts/bench.sh" "${{ inputs.benchmark }}" --runtime "${{ inputs.runtime }}" --pallet "${{ inputs.pallet }}" --target_dir "${{ inputs.target_dir }}" --subcommand "${{ inputs.subcommand }}" --runtime_dir "${{ inputs.runtime_dir }}" - - name: Report failure - if: ${{ failure() }} - run: gh pr comment ${{ inputs.pr }} --body "

Command failed ❌

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

Action completed 🎉🎉

Run by @${{ github.actor }} for ${{ github.workflow }} completed 🎉. See logs here." - env: - RUN: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - GH_TOKEN: ${{ github.token }} diff --git a/.github/workflows/command-fmt.yml b/.github/workflows/command-fmt.yml deleted file mode 100644 index 586b8c77f274..000000000000 --- a/.github/workflows/command-fmt.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Command FMT - -on: - workflow_dispatch: - inputs: - pr: - description: Number of the Pull Request - required: 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-fmt: - needs: [set-image] - runs-on: ubuntu-latest - timeout-minutes: 20 - container: - image: ${{ needs.set-image.outputs.IMAGE }} - permissions: - contents: write - pull-requests: write - steps: - - name: Download repo - uses: actions/checkout@v4 - - name: Install gh cli - id: gh - uses: ./.github/actions/set-up-gh - with: - pr-number: ${{ inputs.pr }} - GH_TOKEN: ${{ github.token }} - - name: Run FMT - run: | - # format toml. - # since paritytech/ci-unified:bullseye-1.73.0-2023-11-01-v20231204 includes taplo-cli - taplo format --config .config/taplo.toml - - name: Report failure - if: ${{ failure() }} - run: gh pr comment ${{ inputs.pr }} --body "

Command failed ❌

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

Action completed 🎉🎉

Run by @${{ github.actor }} for ${{ github.workflow }} completed 🎉. See logs here." - env: - RUN: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - GH_TOKEN: ${{ github.token }} diff --git a/.github/workflows/command-inform.yml b/.github/workflows/command-inform.yml index 2825f4a60460..973463953193 100644 --- a/.github/workflows/command-inform.yml +++ b/.github/workflows/command-inform.yml @@ -2,20 +2,21 @@ name: Inform of new command action on: issue_comment: - types: [created] + types: [ created ] 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 # disabled for now, until tested steps: - - name: Inform that the new command exist - uses: actions/github-script@v7 - with: - script: | - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: 'We are migrating the command bot to be a GitHub Action

Please, see the documentation on how to use it' - }) + - name: Inform that the new command exist + uses: actions/github-script@v7 + with: + script: | + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: 'We have migrated the command bot to GHA

Please, see the new usage instructions here. Soon the old commands will be disabled.' + }) \ No newline at end of file diff --git a/.github/workflows/command-prdoc.yml b/.github/workflows/command-prdoc.yml new file mode 100644 index 000000000000..7022e8e0e006 --- /dev/null +++ b/.github/workflows/command-prdoc.yml @@ -0,0 +1,81 @@ +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_operator" + overwrite: + type: boolean + description: Overwrite existing PrDoc + default: true + required: true + +concurrency: + group: command-prdoc + cancel-in-progress: true + +jobs: + preflight: + uses: ./.github/workflows/reusable-preflight.yml + + cmd-prdoc: + needs: [preflight] + runs-on: ubuntu-latest + timeout-minutes: 20 + container: + image: ${{ needs.preflight.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/command-sync.yml b/.github/workflows/command-sync.yml deleted file mode 100644 index c610f4066a87..000000000000 --- a/.github/workflows/command-sync.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: Command Sync - -on: - workflow_dispatch: - inputs: - pr: - description: Number of the Pull Request - required: true - chain: - description: Chain - type: choice - required: true - options: - - westend - - rococo - sync-type: - description: Sync type - type: choice - required: true - options: - - warp - - full - - fast - - fast-unsafe - -jobs: - set-image: - runs-on: ubuntu-latest - outputs: - IMAGE: ${{ steps.set_image.outputs.IMAGE }} - steps: - - name: Checkout - uses: actions/checkout@v4 - - id: set_image - run: cat .github/env >> $GITHUB_OUTPUT - cmd-sync: - needs: [set-image] - runs-on: arc-runners-polkadot-sdk-warpsync - container: - image: ${{ needs.set-image.outputs.IMAGE }} - permissions: - contents: write - pull-requests: write - steps: - - name: Download repo - uses: actions/checkout@v4 - - name: Install gh cli - id: gh - uses: ./.github/actions/set-up-gh - with: - pr-number: ${{ inputs.pr }} - GH_TOKEN: ${{ github.token }} - - name: Run sync - run: | - "./scripts/sync.sh" --chain "${{ inputs.chain }}" --type "${{ inputs.sync-type }}" - - name: Report failure - if: ${{ failure() }} - run: gh pr comment ${{ inputs.pr }} --body "

Command failed ❌

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

Action completed 🎉🎉

Run by @${{ github.actor }} for ${{ github.workflow }} completed 🎉. See logs here." - env: - RUN: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - GH_TOKEN: ${{ github.token }} diff --git a/.github/workflows/command-update-ui.yml b/.github/workflows/command-update-ui.yml deleted file mode 100644 index 860177adc879..000000000000 --- a/.github/workflows/command-update-ui.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Command Update UI - -on: - workflow_dispatch: - inputs: - pr: - description: Number of the Pull Request - required: true - rust-version: - description: Version of rust. Example 1.70 - required: false - -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-update-ui: - needs: [set-image] - runs-on: arc-runners-polkadot-sdk-beefy - timeout-minutes: 90 - container: - image: ${{ needs.set-image.outputs.IMAGE }} - permissions: - contents: write - pull-requests: write - steps: - - name: Download repo - uses: actions/checkout@v4 - - name: Install gh cli - id: gh - uses: ./.github/actions/set-up-gh - with: - pr-number: ${{ inputs.pr }} - GH_TOKEN: ${{ github.token }} - - name: Run update-ui - run: | - "./scripts/update-ui-tests.sh" "${{ inputs.rust-version }}" - - name: Report failure - if: ${{ failure() }} - run: gh pr comment ${{ inputs.pr }} --body "

Command failed ❌

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

Action completed 🎉🎉

Run by @${{ github.actor }} for ${{ github.workflow }} completed 🎉. See logs here." - env: - RUN: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - GH_TOKEN: ${{ github.token }} diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000000..a257c8229598 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,157 @@ +name: Docs + +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 + +jobs: + preflight: + uses: ./.github/workflows/reusable-preflight.yml + + test-doc: + runs-on: ${{ needs.preflight.outputs.RUNNER }} + timeout-minutes: 60 + needs: [preflight] + container: + image: ${{ needs.preflight.outputs.IMAGE }} + steps: + - uses: actions/checkout@v4 + - run: forklift cargo test --doc --workspace + env: + RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" + + build-rustdoc: + runs-on: ${{ needs.preflight.outputs.RUNNER }} + timeout-minutes: 40 + if: ${{ needs.preflight.outputs.changes_rust }} + needs: [preflight] + container: + image: ${{ needs.preflight.outputs.IMAGE }} + steps: + - uses: actions/checkout@v4 + - run: forklift cargo doc --all-features --workspace --no-deps + env: + SKIP_WASM_BUILD: 1 + RUSTDOCFLAGS: "-Dwarnings --default-theme=ayu --html-in-header ./docs/sdk/assets/header.html --extend-css ./docs/sdk/assets/theme.css --html-after-content ./docs/sdk/assets/after-content.html" + - run: rm -f ./target/doc/.lock + - run: mv ./target/doc ./crate-docs + - name: Inject Simple Analytics script + run: | + script_content="" + docs_dir="./crate-docs" + + inject_simple_analytics() { + find "$1" -name '*.html' | xargs -I {} -P "$(nproc)" bash -c 'file="{}"; echo "Adding Simple Analytics script to $file"; sed -i "s||'"$2"'|" "$file";' + } + + inject_simple_analytics "$docs_dir" "$script_content" + - run: echo "" > ./crate-docs/index.html + - uses: actions/upload-artifact@v4 + with: + name: ${{ github.sha }}-doc + path: ./crate-docs/ + retention-days: 1 + if-no-files-found: error + + build-implementers-guide: + runs-on: ubuntu-latest + container: + image: paritytech/mdbook-utils:e14aae4a-20221123 + options: --user root + steps: + - uses: actions/checkout@v4 + - run: mdbook build ./polkadot/roadmap/implementers-guide + - run: mkdir -p artifacts + - run: mv polkadot/roadmap/implementers-guide/book artifacts/ + - uses: actions/upload-artifact@v4 + with: + name: ${{ github.sha }}-guide + path: ./artifacts/ + retention-days: 1 + if-no-files-found: error + + confirm-required-jobs-passed: + runs-on: ubuntu-latest + name: All docs jobs passed + # If any new job gets added, be sure to add it to this array + needs: [test-doc, build-rustdoc, build-implementers-guide] + if: always() && !cancelled() + steps: + - run: | + tee resultfile <<< '${{ toJSON(needs) }}' + FAILURES=$(cat resultfile | grep '"result": "failure"' | wc -l) + if [ $FAILURES -gt 0 ]; then + echo "### At least one required job failed ❌" >> $GITHUB_STEP_SUMMARY + exit 1 + else + echo '### Good job! All the required jobs passed 🚀' >> $GITHUB_STEP_SUMMARY + fi + + publish-rustdoc: + if: github.ref == 'refs/heads/master' + runs-on: ubuntu-latest + environment: subsystem-benchmarks + needs: [build-rustdoc, build-implementers-guide] + steps: + - uses: actions/checkout@v4 + with: + ref: gh-pages + - uses: actions/create-github-app-token@v1 + id: app-token + with: + app-id: ${{ secrets.POLKADOTSDK_GHPAGES_APP_ID }} + private-key: ${{ secrets.POLKADOTSDK_GHPAGES_APP_KEY }} + - name: Ensure destination dir does not exist + run: | + rm -rf book/ + rm -rf ${REF_NAME} + env: + REF_NAME: ${{ github.head_ref || github.ref_name }} + - name: Download rustdocs + uses: actions/download-artifact@v4 + with: + name: ${{ github.sha }}-doc + path: ${{ github.head_ref || github.ref_name }} + - name: Download guide + uses: actions/download-artifact@v4 + with: + name: ${{ github.sha }}-guide + path: /tmp + - run: mkdir -p book + - name: Move book files + run: mv /tmp/book/html/* book/ + - name: Push changes to gh-pages + env: + TOKEN: ${{ steps.app-token.outputs.token }} + APP_NAME: "paritytech-upd-ghpages-polkadotsdk" + REF_NAME: ${{ github.head_ref || github.ref_name }} + Green: "\e[32m" + NC: "\e[0m" + run: | + echo "${Green}Git add${NC}" + git add book/ + git add ${REF_NAME}/ + + echo "${Green}git status | wc -l${NC}" + git status | wc -l + + echo "${Green}Add new remote with gh app token${NC}" + git remote set-url origin $(git config remote.origin.url | sed "s/github.com/${APP_NAME}:${TOKEN}@github.com/g") + + echo "${Green}Remove http section that causes issues with gh app auth token${NC}" + sed -i.bak '/\[http/d' ./.git/config + sed -i.bak '/extraheader/d' ./.git/config + + echo "${Green}Git push${NC}" + git config user.email "ci@parity.io" + git config user.name "${APP_NAME}" + git commit --amend -m "___Updated docs" || echo "___Nothing to commit___" + git push origin gh-pages --force diff --git a/.github/workflows/fork-sync-action.yml b/.github/workflows/fork-sync-action.yml new file mode 100644 index 000000000000..50774e910527 --- /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@main + 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 d80270148639..b5db0538569b 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@5e914681df9dc83aa4e4905692ca88beb2f9e91f # 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@5e914681df9dc83aa4e4905692ca88beb2f9e91f # 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 000000000000..326168717674 --- /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 33cf93169200..3fad3b641474 100644 --- a/.github/workflows/publish-check-crates.yml +++ b/.github/workflows/publish-check-crates.yml @@ -8,19 +8,23 @@ on: types: [opened, synchronize, reopened, ready_for_review] merge_group: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: check-publish: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - name: Rust Cache - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2.7.5 with: cache-on-failure: true - name: install parity-publish - run: cargo install parity-publish@0.6.0 + run: cargo install parity-publish@0.8.0 --locked -q - 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 08c50638267b..37bf06bb82d8 100644 --- a/.github/workflows/publish-claim-crates.yml +++ b/.github/workflows/publish-claim-crates.yml @@ -10,15 +10,15 @@ jobs: runs-on: ubuntu-latest environment: master steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - name: Rust Cache - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3 + uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab # v2.7.5 with: cache-on-failure: true - name: install parity-publish - run: cargo install parity-publish@0.6.0 + run: cargo install parity-publish@0.8.0 --locked -q - name: parity-publish claim env: diff --git a/.github/workflows/publish-subsystem-benchmarks.yml b/.github/workflows/publish-subsystem-benchmarks.yml deleted file mode 100644 index 1a726b669e90..000000000000 --- a/.github/workflows/publish-subsystem-benchmarks.yml +++ /dev/null @@ -1,55 +0,0 @@ -# The actions takes json file as input and runs github-action-benchmark for it. - -on: - workflow_dispatch: - inputs: - benchmark-data-dir-path: - description: "Path to the benchmark data directory" - required: true - type: string - output-file-path: - description: "Path to the benchmark data file" - required: true - type: string - -jobs: - subsystem-benchmarks: - runs-on: ubuntu-latest - environment: subsystem-benchmarks - steps: - - name: Validate inputs - run: | - echo "${{ github.event.inputs.benchmark-data-dir-path }}" | grep -P '^[a-z\-]' - echo "${{ github.event.inputs.output-file-path }}" | grep -P '^[a-z\-]+\.json' - - - name: Checkout Sources - uses: actions/checkout@v4.1.2 - with: - fetch-depth: 0 - ref: "gh-pages" - - - name: Copy bench results - id: step_one - run: | - cp bench/gitlab/${{ github.event.inputs.output-file-path }} ${{ github.event.inputs.output-file-path }} - - - name: Switch branch - id: step_two - run: | - git checkout master -- - - - uses: actions/create-github-app-token@v1 - id: app-token - with: - app-id: ${{ secrets.POLKADOTSDK_GHPAGES_APP_ID }} - private-key: ${{ secrets.POLKADOTSDK_GHPAGES_APP_KEY }} - - - name: Store benchmark result - uses: benchmark-action/github-action-benchmark@v1 - with: - tool: "customSmallerIsBetter" - name: ${{ github.event.inputs.benchmark-data-dir-path }} - output-file-path: ${{ github.event.inputs.output-file-path }} - benchmark-data-dir-path: "bench/${{ github.event.inputs.benchmark-data-dir-path }}" - github-token: ${{ steps.app-token.outputs.token }} - auto-push: true diff --git a/.github/workflows/release-10_rc-automation.yml b/.github/workflows/release-10_rc-automation.yml index f5c5de8d0da9..41783f6cc721 100644 --- a/.github/workflows/release-10_rc-automation.yml +++ b/.github/workflows/release-10_rc-automation.yml @@ -12,7 +12,7 @@ on: workflow_dispatch: inputs: version: - description: Current release/rc version in format vX.X.X + description: Current release/rc version in format polkadot-stableYYMM jobs: tag_rc: @@ -26,7 +26,7 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 with: fetch-depth: 0 @@ -41,7 +41,7 @@ jobs: if [[ -z "${{ inputs.version }}" ]]; then version=v$(get_polkadot_node_version_from_code) else - version=$(filter_version_from_input ${{ inputs.version }}) + version=$(validate_stable_tag ${{ inputs.version }}) fi echo "$version" echo "version=$version" >> $GITHUB_OUTPUT diff --git a/.github/workflows/release-30_publish_release_draft.yml b/.github/workflows/release-30_publish_release_draft.yml index 20492f2d3a91..2a5d92ed167a 100644 --- a/.github/workflows/release-30_publish_release_draft.yml +++ b/.github/workflows/release-30_publish_release_draft.yml @@ -5,6 +5,7 @@ on: tags: # Catches v1.2.3 and v1.2.3-rc1 - v[0-9]+.[0-9]+.[0-9]+* + # - polkadot-stable[0-9]+* Activate when the release process from release org is setteled workflow_dispatch: inputs: @@ -25,7 +26,8 @@ jobs: build-runtimes: uses: "./.github/workflows/release-srtool.yml" with: - excluded_runtimes: "substrate-test bp cumulus-test kitchensink minimal-template parachain-template penpal polkadot-test seedling shell frame-try sp solochain-template" + excluded_runtimes: "asset-hub-rococo bridge-hub-rococo contracts-rococo coretime-rococo people-rococo rococo rococo-parachain substrate-test bp cumulus-test kitchensink minimal-template parachain-template penpal polkadot-test seedling shell frame-try sp solochain-template" + build_opts: "--features on-chain-release-build" build-binaries: runs-on: ubuntu-latest @@ -35,7 +37,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@6d193bf28034eafb982f37bd894289fe649468fc # v4.0.0 - name: Install protobuf-compiler run: | @@ -62,10 +64,10 @@ jobs: asset_upload_url: ${{ steps.create-release.outputs.upload_url }} steps: - name: Checkout - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # 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: | @@ -78,30 +80,27 @@ jobs: env: RUSTC_STABLE: ${{ needs.get-rust-versions.outputs.rustc-stable }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ASSET_HUB_ROCOCO_DIGEST: ${{ github.workspace}}/asset-hub-rococo-runtime/asset-hub-rococo-srtool-digest.json ASSET_HUB_WESTEND_DIGEST: ${{ github.workspace}}/asset-hub-westend-runtime/asset-hub-westend-srtool-digest.json - BRIDGE_HUB_ROCOCO_DIGEST: ${{ github.workspace}}/bridge-hub-rococo-runtime/bridge-hub-rococo-srtool-digest.json BRIDGE_HUB_WESTEND_DIGEST: ${{ github.workspace}}/bridge-hub-westend-runtime/bridge-hub-westend-srtool-digest.json COLLECTIVES_WESTEND_DIGEST: ${{ github.workspace}}/collectives-westend-runtime/collectives-westend-srtool-digest.json - CONTRACTS_ROCOCO_DIGEST: ${{ github.workspace}}/contracts-rococo-runtime/contracts-rococo-srtool-digest.json - CORETIME_ROCOCO_DIGEST: ${{ github.workspace}}/coretime-rococo-runtime/coretime-rococo-srtool-digest.json CORETIME_WESTEND_DIGEST: ${{ github.workspace}}/coretime-westend-runtime/coretime-westend-srtool-digest.json GLUTTON_WESTEND_DIGEST: ${{ github.workspace}}/glutton-westend-runtime/glutton-westend-srtool-digest.json - PEOPLE_ROCOCO_DIGEST: ${{ github.workspace}}/people-rococo-runtime/people-rococo-srtool-digest.json PEOPLE_WESTEND_DIGEST: ${{ github.workspace}}/people-westend-runtime/people-westend-srtool-digest.json - ROCOCO_DIGEST: ${{ github.workspace}}/rococo-runtime/rococo-srtool-digest.json WESTEND_DIGEST: ${{ github.workspace}}/westend-runtime/westend-srtool-digest.json + shell: bash run: | . ./.github/scripts/common/lib.sh export REF1=$(get_latest_release_tag) if [[ -z "${{ inputs.version }}" ]]; then export REF2="${{ github.ref_name }}" + echo "REF2: ${REF2}" else export REF2="${{ inputs.version }}" + echo "REF2: ${REF2}" fi echo "REL_TAG=$REF2" >> $GITHUB_ENV - export VERSION=$(echo "$REF2" | sed -E 's/^v([0-9]+\.[0-9]+\.[0-9]+).*$/\1/') + export VERSION=$(echo "$REF2" | sed -E 's/.*(stable[0-9]+).*$/\1/') ./scripts/release/build-changelogs.sh @@ -133,10 +132,10 @@ jobs: steps: - name: Checkout sources - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # 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 +165,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 723883eaf64c..6e0e8f20aa5e 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 @@ -71,16 +75,43 @@ env: # EVENT_ACTION: ${{ github.event.action }} EVENT_NAME: ${{ github.event_name }} IMAGE_TYPE: ${{ inputs.image_type }} - VERSION: ${{ inputs.version }} jobs: + validate-inputs: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.validate_inputs.outputs.VERSION }} + release_id: ${{ steps.validate_inputs.outputs.RELEASE_ID }} + stable_tag: ${{ steps.validate_inputs.outputs.stable_tag }} + + steps: + - name: Checkout sources + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + + - name: Validate inputs + id: validate_inputs + run: | + . ./.github/scripts/common/lib.sh + + VERSION=$(filter_version_from_input "${{ inputs.version }}") + echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT + + RELEASE_ID=$(check_release_id "${{ inputs.release_id }}") + echo "RELEASE_ID=${RELEASE_ID}" >> $GITHUB_OUTPUT + + echo "Release ID: $RELEASE_ID" + + 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 + needs: [validate-inputs] steps: - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 #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,17 +133,23 @@ jobs: run: | . ./.github/scripts/common/lib.sh - VERSION=$(filter_version_from_input "${{ inputs.version }}") - echo "VERSION=${VERSION}" >> $GITHUB_ENV - - fetch_release_artifacts_from_s3 + VERSION="${{ needs.validate-inputs.outputs.VERSION }}" + if [[ ${{ inputs.binary }} == 'polkadot' ]]; then + bins=(polkadot polkadot-prepare-worker polkadot-execute-worker) + for bin in "${bins[@]}"; do + fetch_release_artifacts_from_s3 $bin + done + else + fetch_release_artifacts_from_s3 $BINARY + fi - name: Fetch chain-spec-builder rc artifacts or release artifacts based on release id #this step runs only if the workflow is triggered manually and only for chain-spec-builder 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 }}") + + RELEASE_ID="${{ needs.validate-inputs.outputs.RELEASE_ID }}" fetch_release_artifacts - name: Upload artifacts @@ -124,15 +161,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@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - 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' }} @@ -157,16 +194,12 @@ jobs: run: | . ./.github/scripts/common/lib.sh - RELEASE_ID=$(check_release_id "${{ inputs.release_id }}") - release=release-$RELEASE_ID && \ - echo "release=${release}" >> $GITHUB_OUTPUT + echo "release=${{ needs.validate-inputs.outputs.stable_tag }}" >> $GITHUB_OUTPUT commit=$(git rev-parse --short HEAD) && \ echo "commit=${commit}" >> $GITHUB_OUTPUT - tag=$(git name-rev --tags --name-only $(git rev-parse HEAD)) && \ - [ "${tag}" != "undefined" ] && echo "tag=${tag}" >> $GITHUB_OUTPUT || \ - echo "No tag, doing without" + echo "tag=${{ needs.validate-inputs.outputs.version }}" >> $GITHUB_OUTPUT - name: Fetch release tags working-directory: release-artifacts @@ -174,15 +207,32 @@ jobs: id: fetch_release_refs run: | chmod a+rx $BINARY - [[ $BINARY != 'chain-spec-builder' ]] && VERSION=$(./$BINARY --version | awk '{ print $2 }' ) - release=$( echo $VERSION | cut -f1 -d- ) + if [[ $BINARY != 'chain-spec-builder' ]]; then + VERSION=$(./$BINARY --version | awk '{ print $2 }' ) + release=$( echo $VERSION | cut -f1 -d- ) + else + release=$(echo ${{ needs.validate-inputs.outputs.VERSION }} | sed 's/^v//') + fi + echo "tag=latest" >> $GITHUB_OUTPUT echo "release=${release}" >> $GITHUB_OUTPUT - echo "stable=stable" >> $GITHUB_OUTPUT + echo "stable=${{ needs.validate-inputs.outputs.stable_tag }}" >> $GITHUB_OUTPUT + + - name: Build Injected Container image for polkadot rc + if: ${{ env.BINARY == 'polkadot' }} + env: + ARTIFACTS_FOLDER: release-artifacts + IMAGE_NAME: ${{ env.BINARY }} + OWNER: ${{ env.DOCKER_OWNER }} + TAGS: ${{ join(steps.fetch_rc_refs.outputs.*, ',') || join(steps.fetch_release_refs.outputs.*, ',') }} + run: | + ls -al + echo "Building container for $BINARY" + ./docker/scripts/polkadot/build-injected.sh $ARTIFACTS_FOLDER - - name: Build Injected Container image for polkadot rc or chain-spec-builder - if: ${{ env.BINARY == 'polkadot' || env.BINARY == 'chain-spec-builder' }} + - name: Build Injected Container image chain-spec-builder + if: ${{ env.BINARY == 'chain-spec-builder' }} env: ARTIFACTS_FOLDER: release-artifacts IMAGE_NAME: ${{ env.BINARY }} @@ -209,8 +259,16 @@ jobs: echo "Building container for $BINARY" ./docker/scripts/build-injected.sh - - name: Login to Dockerhub - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + - name: Login to Dockerhub to publish polkadot + if: ${{ env.BINARY == 'polkadot' }} + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 + with: + username: ${{ secrets.POLKADOT_DOCKERHUB_USERNAME }} + password: ${{ secrets.POLKADOT_DOCKERHUB_TOKEN }} + + - name: Login to Dockerhub to puiblish polkadot-parachain/chain-spec-builder + if: ${{ env.BINARY == 'polkadot-parachain' || env.BINARY == 'chain-spec-builder' }} + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: username: ${{ secrets.CUMULUS_DOCKERHUB_USERNAME }} password: ${{ secrets.CUMULUS_DOCKERHUB_TOKEN }} @@ -257,17 +315,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@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 + uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1 - 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 }} @@ -275,7 +333,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 }} @@ -288,14 +346,14 @@ jobs: - name: Build and push id: docker_build - uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0 + uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 with: push: true file: docker/dockerfiles/polkadot/polkadot_injected_debian.Dockerfile # TODO: The owner should be used below but buildx does not resolve the VARs # TODO: It would be good to get rid of this GHA that we don't really need. tags: | - parity/polkadot:stable + parity/polkadot:${{ 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-branchoff-stable.yml b/.github/workflows/release-branchoff-stable.yml new file mode 100644 index 000000000000..3086c0d21f42 --- /dev/null +++ b/.github/workflows/release-branchoff-stable.yml @@ -0,0 +1,104 @@ +name: Release - Branch off stable branch + +on: + workflow_dispatch: + inputs: + stable_version: + description: New stable version in the format stableYYMM + required: true + type: string + + node_version: + description: Version of the polkadot node in the format X.XX.X (e.g. 1.15.0) + required: true + +jobs: + check-workflow-can-run: + uses: paritytech-release/sync-workflows/.github/workflows/check-syncronization.yml@main + + + prepare-tooling: + needs: [check-workflow-can-run] + if: needs.check-workflow-can-run.outputs.checks_passed == 'true' + runs-on: ubuntu-latest + outputs: + node_version: ${{ steps.validate_inputs.outputs.node_version }} + stable_version: ${{ steps.validate_inputs.outputs.stable_version }} + + steps: + - name: Checkout sources + uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 + + - name: Validate inputs + id: validate_inputs + run: | + . ./.github/scripts/common/lib.sh + + node_version=$(filter_version_from_input "${{ inputs.node_version }}") + echo "node_version=${node_version}" >> $GITHUB_OUTPUT + + stable_version=$(validate_stable_tag ${{ inputs.stable_version }}) + echo "stable_version=${stable_version}" >> $GITHUB_OUTPUT + + create-stable-branch: + needs: [prepare-tooling] + runs-on: ubuntu-latest + environment: release + env: + PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }} + PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + STABLE_BRANCH_NAME: ${{ needs.prepare-tooling.outputs.stable_version }} + + steps: + - name: Install pgpkkms + run: | + # Install pgpkms that is used to sign commits + pip install git+https://github.com/paritytech-release/pgpkms.git@5a8f82fbb607ea102d8c178e761659de54c7af69 + + - name: Checkout sources + uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 + with: + ref: master + + - name: Import gpg keys + run: | + . ./.github/scripts/common/lib.sh + + import_gpg_keys + + + - name: Config git + run: | + git config --global commit.gpgsign true + git config --global gpg.program /home/runner/.local/bin/pgpkms-git + git config --global user.name "ParityReleases" + git config --global user.email "release-team@parity.io" + git config --global user.signingKey "90BD75EBBB8E95CB3DA6078F94A4029AB4B35DAE" + + - name: Create stable branch + run: | + git checkout -b "$STABLE_BRANCH_NAME" + git show-ref "$STABLE_BRANCH_NAME" + + - name: Bump versions, reorder prdocs and push stable branch + run: | + . ./.github/scripts/release/release_lib.sh + + NODE_VERSION="${{ needs.prepare-tooling.outputs.node_version }}" + set_version "\(NODE_VERSION[^=]*= \)\".*\"" $NODE_VERSION "polkadot/node/primitives/src/lib.rs" + commit_with_message "Bump node version to $NODE_VERSION in polkadot-cli" + + SPEC_VERSION=$(get_spec_version $NODE_VERSION) + runtimes_list=$(get_filtered_runtimes_list) + set_spec_versions $SPEC_VERSION "${runtimes_list[@]}" + + # TODO: clarify what to do with the polkadot-parachain binary + # Set new version for polkadot-parachain binary to match the polkadot node binary + # set_polkadot_parachain_binary_version $NODE_VERSION "cumulus/polkadot-parachain/Cargo.toml" + + reorder_prdocs $STABLE_BRANCH_NAME + + git push origin "$STABLE_BRANCH_NAME" diff --git a/.github/workflows/release-build-rc.yml b/.github/workflows/release-build-rc.yml new file mode 100644 index 000000000000..5c25e3c749b8 --- /dev/null +++ b/.github/workflows/release-build-rc.yml @@ -0,0 +1,74 @@ +name: Release - Build node release candidate + +on: + workflow_dispatch: + inputs: + binary: + description: Binary to be build for the release + default: all + type: choice + options: + - polkadot + - polkadot-parachain + - all + + release_tag: + description: Tag matching the actual release candidate with the format stableYYMM-rcX or stableYYMM + type: string + +jobs: + check-synchronization: + uses: paritytech-release/sync-workflows/.github/workflows/check-syncronization.yml@main + + validate-inputs: + needs: [check-synchronization] + if: ${{ needs.check-synchronization.outputs.checks_passed }} == 'true' + runs-on: ubuntu-latest + outputs: + release_tag: ${{ steps.validate_inputs.outputs.release_tag }} + + steps: + - name: Checkout sources + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + + - name: Validate inputs + id: validate_inputs + run: | + . ./.github/scripts/common/lib.sh + + RELEASE_TAG=$(validate_stable_tag ${{ inputs.release_tag }}) + echo "release_tag=${RELEASE_TAG}" >> $GITHUB_OUTPUT + + build-polkadot-binary: + needs: [validate-inputs] + if: ${{ inputs.binary == 'polkadot' || inputs.binary == 'all' }} + uses: "./.github/workflows/release-reusable-rc-buid.yml" + with: + binary: '["polkadot", "polkadot-prepare-worker", "polkadot-execute-worker"]' + package: polkadot + release_tag: ${{ needs.validate-inputs.outputs.release_tag }} + secrets: + PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }} + PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + + build-polkadot-parachain-binary: + needs: [validate-inputs] + if: ${{ inputs.binary == 'polkadot-parachain' || inputs.binary == 'all' }} + uses: "./.github/workflows/release-reusable-rc-buid.yml" + with: + binary: '["polkadot-parachain"]' + package: "polkadot-parachain-bin" + release_tag: ${{ needs.validate-inputs.outputs.release_tag }} + secrets: + PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }} + PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/release-check-runtimes.yml b/.github/workflows/release-check-runtimes.yml index 0e5ad104766a..6666c115562f 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@6d193bf28034eafb982f37bd894289fe649468fc # 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@6d193bf28034eafb982f37bd894289fe649468fc # 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 643c14daa15b..0d2ce78ab781 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@6d193bf28034eafb982f37bd894289fe649468fc # v4.1.7 - name: Prechecks run: | diff --git a/.github/workflows/release-reusable-rc-buid.yml b/.github/workflows/release-reusable-rc-buid.yml new file mode 100644 index 000000000000..ae6c430b6d37 --- /dev/null +++ b/.github/workflows/release-reusable-rc-buid.yml @@ -0,0 +1,191 @@ +name: RC Build + +on: + workflow_call: + inputs: + binary: + description: Binary to be build for the release + required: true + default: polkadot + type: string + + package: + description: Package to be built, for now is either polkadot or polkadot-parachain-bin + required: true + type: string + + release_tag: + description: Tag matching the actual release candidate with the format stableYYMM-rcX or stableYYMM + required: true + type: string + + secrets: + PGP_KMS_KEY: + required: true + PGP_KMS_HASH: + required: true + AWS_ACCESS_KEY_ID: + required: true + AWS_SECRET_ACCESS_KEY: + required: true + AWS_DEFAULT_REGION: + required: true + AWS_RELEASE_ACCESS_KEY_ID: + required: true + AWS_RELEASE_SECRET_ACCESS_KEY: + required: true + +permissions: + id-token: write + contents: read + attestations: write + +jobs: + + 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 + outputs: + IMAGE: ${{ steps.set_image.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + + - id: set_image + run: cat .github/env >> $GITHUB_OUTPUT + + build-rc: + needs: [set-image] + runs-on: ubuntu-latest + environment: release + container: + image: ${{ needs.set-image.outputs.IMAGE }} + strategy: + matrix: + binaries: ${{ fromJSON(inputs.binary) }} + env: + PGP_KMS_KEY: ${{ secrets.PGP_KMS_KEY }} + PGP_KMS_HASH: ${{ secrets.PGP_KMS_HASH }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + + steps: + - name: Install pgpkkms + run: | + # Install pgpkms that is used to sign built artifacts + python3 -m pip install "pgpkms @ git+https://github.com/paritytech-release/pgpkms.git@5a8f82fbb607ea102d8c178e761659de54c7af69" + which pgpkms + + - name: Checkout sources + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + with: + ref: ${{ inputs.release_tag }} + fetch-depth: 0 + + - name: Import gpg keys + shell: bash + run: | + . ./.github/scripts/common/lib.sh + + import_gpg_keys + + - name: Build binary + run: | + git config --global --add safe.directory "${GITHUB_WORKSPACE}" #avoid "detected dubious ownership" error + ./.github/scripts/release/build-linux-release.sh ${{ matrix.binaries }} ${{ inputs.package }} + + - name: Generate artifact attestation + uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3 + with: + subject-path: /artifacts/${{ matrix.binaries }}/${{ matrix.binaries }} + + - name: Sign artifacts + working-directory: /artifacts/${{ matrix.binaries }} + run: | + python3 -m pgpkms sign --input ${{matrix.binaries }} -o ${{ matrix.binaries }}.asc + + - name: Check sha256 ${{ matrix.binaries }} + working-directory: /artifacts/${{ matrix.binaries }} + shell: bash + run: | + . "${GITHUB_WORKSPACE}"/.github/scripts/common/lib.sh + + echo "Checking binary ${{ matrix.binaries }}" + check_sha256 ${{ matrix.binaries }} + + - name: Check GPG ${{ matrix.binaries }} + working-directory: /artifacts/${{ matrix.binaries }} + shell: bash + run: | + . "${GITHUB_WORKSPACE}"/.github/scripts/common/lib.sh + + check_gpg ${{ matrix.binaries }} + + - name: Upload ${{ matrix.binaries }} artifacts + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + with: + name: ${{ matrix.binaries }} + path: /artifacts/${{ matrix.binaries }} + + build-polkadot-deb-package: + if: ${{ inputs.package == 'polkadot' }} + needs: [build-rc] + runs-on: ubuntu-latest + + steps: + - name: Checkout sources + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + with: + ref: ${{ inputs.release_tag }} + fetch-depth: 0 + + - name: Download artifacts + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + path: target/production + merge-multiple: true + + - name: Build polkadot deb package + shell: bash + run: | + . "${GITHUB_WORKSPACE}"/.github/scripts/release/build-deb.sh ${{ inputs.package }} ${{ inputs.release_tag }} + + - name: Generate artifact attestation + uses: actions/attest-build-provenance@1c608d11d69870c2092266b3f9a6f3abbf17002c # v1.4.3 + with: + subject-path: target/production/*.deb + + - name: Upload ${{inputs.package }} artifacts + uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + with: + name: ${{ inputs.package }} + path: target/production + overwrite: true + + upload-polkadot-artifacts-to-s3: + if: ${{ inputs.package == 'polkadot' }} + needs: [build-polkadot-deb-package] + uses: ./.github/workflows/release-reusable-s3-upload.yml + with: + package: ${{ inputs.package }} + release_tag: ${{ inputs.release_tag }} + secrets: + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + + + upload-polkadot-parachain-artifacts-to-s3: + if: ${{ inputs.package == 'polkadot-parachain-bin' }} + needs: [build-rc] + uses: ./.github/workflows/release-reusable-s3-upload.yml + with: + package: polkadot-parachain + release_tag: ${{ inputs.release_tag }} + secrets: + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + AWS_RELEASE_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_RELEASE_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/release-reusable-s3-upload.yml b/.github/workflows/release-reusable-s3-upload.yml new file mode 100644 index 000000000000..6776b78da8e6 --- /dev/null +++ b/.github/workflows/release-reusable-s3-upload.yml @@ -0,0 +1,53 @@ +name: Upload to s3 + +on: + workflow_call: + inputs: + package: + description: Package to be built, for now is either polkadot or polkadot-parachain-bin + required: true + type: string + + release_tag: + description: Tag matching the actual release candidate with the format stableYYMM-rcX or stableYYMM-rcX + required: true + type: string + + secrets: + AWS_DEFAULT_REGION: + required: true + AWS_RELEASE_ACCESS_KEY_ID: + required: true + AWS_RELEASE_SECRET_ACCESS_KEY: + required: true + +jobs: + upload-artifacts-to-s3: + runs-on: ubuntu-latest + environment: release + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_RELEASE_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_RELEASE_SECRET_ACCESS_KEY }} + AWS_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + + steps: + - name: Checkout + uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 + + - name: Download artifacts + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + with: + name: ${{ inputs.package }} + path: artifacts/${{ inputs.package }} + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 + with: + aws-access-key-id: ${{ env.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ env.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ env.AWS_REGION }} + + - name: Upload ${{ inputs.package }} artifacts to s3 + run: | + . ./.github/scripts/release/release_lib.sh + upload_s3_release ${{ inputs.package }} ${{ inputs.release_tag }} diff --git a/.github/workflows/release-srtool.yml b/.github/workflows/release-srtool.yml index e98269fecab0..9a29b46d2fc3 100644 --- a/.github/workflows/release-srtool.yml +++ b/.github/workflows/release-srtool.yml @@ -9,6 +9,8 @@ on: inputs: excluded_runtimes: type: string + build_opts: + type: string outputs: published_runtimes: value: ${{ jobs.find-runtimes.outputs.runtime }} @@ -26,7 +28,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.0.0 with: fetch-depth: 0 @@ -37,7 +39,8 @@ jobs: sudo dpkg -i toml.deb toml --version; jq --version - - name: Scan runtimes + - name: Scan and get runtimes list + id: get_runtimes_list env: EXCLUDED_RUNTIMES: ${{ inputs.excluded_runtimes }}:"substrate-test" run: | @@ -49,13 +52,6 @@ jobs: MATRIX=$(find_runtimes | tee runtimes_list.json) echo $MATRIX - - - name: Get runtimes list - id: get_runtimes_list - run: | - ls -al - MATRIX=$(cat runtimes_list.json) - echo $MATRIX echo "runtime=$MATRIX" >> $GITHUB_OUTPUT srtool: @@ -67,13 +63,15 @@ jobs: matrix: ${{ fromJSON(needs.find-runtimes.outputs.runtime) }} steps: - - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: actions/checkout@6d193bf28034eafb982f37bd894289fe649468fc # v4.0.0 with: fetch-depth: 0 - name: Srtool build id: srtool_build uses: chevdor/srtool-actions@v0.9.2 + env: + BUILD_OPTS: ${{ inputs.build_opts }} with: chain: ${{ matrix.chain }} runtime_dir: ${{ matrix.runtime_dir }} diff --git a/.github/workflows/reusable-preflight.yml b/.github/workflows/reusable-preflight.yml new file mode 100644 index 000000000000..e1799adddcaf --- /dev/null +++ b/.github/workflows/reusable-preflight.yml @@ -0,0 +1,221 @@ +# Reusable workflow to set various useful variables +# and 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: +# preflight: +# uses: ./.github/workflows/reusable-preflight.yml +# some-job: +# needs: changes +# if: ${{ needs.preflight.outputs.changes_rust }} +# ....... + +name: Preflight + +on: + workflow_call: + # Map the workflow outputs to job outputs + outputs: + changes_rust: + value: ${{ jobs.preflight.outputs.changes_rust }} + changes_currentWorkflow: + value: ${{ jobs.preflight.outputs.changes_currentWorkflow }} + + IMAGE: + value: ${{ jobs.preflight.outputs.IMAGE }} + description: "CI image" + + # Runners + # https://github.com/paritytech/ci_cd/wiki/GitHub#paritytech-self-hosted-runners + RUNNER: + value: ${{ jobs.preflight.outputs.RUNNER }} + description: | + Main runner for resource-intensive tasks + By default we use spot machines that can be terminated at any time. + Merge queues use persistent runners to avoid kicking off from queue when the runner is terminated. + RUNNER_OLDLINUX: + value: ${{ jobs.preflight.outputs.RUNNER_OLDLINUX }} + description: | + parity-oldlinux + By default we use spot machines that can be terminated at any time. + Merge queues use persistent runners to avoid kicking off from queue when the runner is terminated. + RUNNER_DEFAULT: + value: ${{ jobs.preflight.outputs.RUNNER_DEFAULT }} + description: "Relatively lightweight runner. When `ubuntu-latest` is not enough" + RUNNER_WEIGHTS: + value: ${{ jobs.preflight.outputs.RUNNER_WEIGHTS }} + RUNNER_BENCHMARK: + value: ${{ jobs.preflight.outputs.RUNNER_BENCHMARK }} + RUNNER_MACOS: + value: ${{ jobs.preflight.outputs.RUNNER_MACOS }} + + # Vars + SOURCE_REF_SLUG: + value: ${{ jobs.preflight.outputs.SOURCE_REF_SLUG }} + description: "Name of the current branch for `push` or source branch for `pull_request` with `/` replaced by `_`. Does not exists in merge_group" + REF_SLUG: + value: ${{ jobs.preflight.outputs.REF_SLUG }} + description: | + Name of the current revision (depending on the event) with `/` replaced by `_`, e.g: + push - master + pull_request - 49_merge + merge_group - gh-readonly-queue_master_pr-49-38d43798a986430231c828b2c762997f818ac012 + + COMMIT_SHA: + value: ${{ jobs.preflight.outputs.COMMIT_SHA }} + description: "Sha of the current revision" + COMMIT_SHA_SHORT: + value: ${{ jobs.preflight.outputs.COMMIT_SHA_SHORT }} + description: "Sha of the current revision, 8-symbols long" + +jobs: + + # + # + # + preflight: + runs-on: ubuntu-latest + outputs: + changes_rust: ${{ steps.set_changes.outputs.rust_any_changed || steps.set_changes.outputs.currentWorkflow_any_changed }} + changes_currentWorkflow: ${{ steps.set_changes.outputs.currentWorkflow_any_changed }} + + IMAGE: ${{ steps.set_image.outputs.IMAGE }} + + # Runners + # https://github.com/paritytech/ci_cd/wiki/GitHub#paritytech-self-hosted-runners + RUNNER: ${{ steps.set_runner.outputs.RUNNER }} + RUNNER_OLDLINUX: ${{ steps.set_runner.outputs.RUNNER_OLDLINUX }} + RUNNER_DEFAULT: ${{ steps.set_runner.outputs.RUNNER_DEFAULT }} + RUNNER_WEIGHTS: ${{ steps.set_runner.outputs.RUNNER_WEIGHTS }} + RUNNER_BENCHMARK: ${{ steps.set_runner.outputs.RUNNER_BENCHMARK }} + RUNNER_MACOS: ${{ steps.set_runner.outputs.RUNNER_MACOS }} + + SOURCE_REF_SLUG: ${{ steps.set_vars.outputs.SOURCE_REF_SLUG }} + REF_SLUG: ${{ steps.set_vars.outputs.REF_SLUG }} + + COMMIT_SHA: ${{ steps.set_vars.outputs.COMMIT_SHA }} + COMMIT_SHA_SHORT: ${{ steps.set_vars.outputs.COMMIT_SHA_SHORT }} + + steps: + + - uses: actions/checkout@v4 + + # + # Set changes + # + - name: Current file + id: current_file + shell: bash + run: | + echo "currentWorkflowFile=$(echo ${{ github.workflow_ref }} | sed -nE "s/.*(\.github\/workflows\/[a-zA-Z0-9_-]*\.y[a]?ml)@refs.*/\1/p")" >> $GITHUB_OUTPUT + echo "currentActionDir=$(echo ${{ github.action_path }} | sed -nE "s/.*(\.github\/actions\/[a-zA-Z0-9_-]*)/\1/p")" >> $GITHUB_OUTPUT + + - name: Set changes + id: set_changes + uses: tj-actions/changed-files@v45 + with: + files_yaml: | + rust: + - '**/*' + - '!.github/**/*' + - '!prdoc/**/*' + - '!docs/**/*' + currentWorkflow: + - '${{ steps.current_file.outputs.currentWorkflowFile }}' + - '.github/workflows/reusable-preflight.yml' + + # + # Set image + # + - name: Set image + id: set_image + shell: bash + run: cat .github/env >> $GITHUB_OUTPUT + + # + # Set runner + # + # By default we use spot machines that can be terminated at any time. + # Merge queues use persistent runners to avoid kicking off from queue when the runner is terminated. + # + - name: Set runner + id: set_runner + shell: bash + run: | + echo "RUNNER_DEFAULT=parity-default" >> $GITHUB_OUTPUT + echo "RUNNER_WEIGHTS=parity-weights" >> $GITHUB_OUTPUT + echo "RUNNER_BENCHMARK=parity-benchmark" >> $GITHUB_OUTPUT + echo "RUNNER_MACOS=parity-macos" >> $GITHUB_OUTPUT + # + # Run merge queues on persistent runners + if [[ $GITHUB_REF_NAME == *"gh-readonly-queue"* ]]; then + echo "RUNNER=parity-large-persistent" >> $GITHUB_OUTPUT + echo "RUNNER_OLDLINUX=parity-oldlinux-persistent" >> $GITHUB_OUTPUT + else + echo "RUNNER=parity-large" >> $GITHUB_OUTPUT + echo "RUNNER_OLDLINUX=parity-oldlinux" >> $GITHUB_OUTPUT + fi + + # + # Set vars + # + - name: Set vars + id: set_vars + shell: bash + run: | + export SOURCE_REF_NAME=${{ github.head_ref || github.ref_name }} + echo "SOURCE_REF_SLUG=${SOURCE_REF_NAME//\//_}" >> $GITHUB_OUTPUT + # + export COMMIT_SHA=${{ github.sha }} + echo "COMMIT_SHA=$COMMIT_SHA" >> $GITHUB_OUTPUT + echo "COMMIT_SHA_SHORT=${COMMIT_SHA:0:8}" >> $GITHUB_OUTPUT + # + export REF_NAME=${{ github.ref_name }} + echo "REF_SLUG=${REF_NAME//\//_}" >> $GITHUB_OUTPUT + + + - name: log + shell: bash + run: | + echo "workflow file: ${{ steps.current_file.outputs.currentWorkflowFile }}" + echo "Modified: ${{ steps.set_changes.outputs.modified_keys }}" + + # + # + # + ci-versions: + needs: [preflight] + runs-on: ubuntu-latest + container: + image: ${{ needs.preflight.outputs.IMAGE }} + steps: + - uses: actions/checkout@v4 + + - name: Info rust + run: | + rustup show + cargo --version + cargo +nightly --version + cargo clippy --version + echo "yarn version: $(yarn --version)" + echo $( substrate-contracts-node --version | awk 'NF' ) + estuary --version + cargo-contract --version + + - name: Info forklift + run: forklift version + + - name: Info vars + run: | + echo "COMMIT_SHA: ${{ needs.preflight.outputs.COMMIT_SHA }}" + echo "COMMIT_SHA_SHORT: ${{ needs.preflight.outputs.COMMIT_SHA_SHORT }}" + echo "SOURCE_REF_SLUG: ${{ needs.preflight.outputs.SOURCE_REF_SLUG }}" + echo "REF_SLUG: ${{ needs.preflight.outputs.REF_SLUG }}" + echo "RUNNER: ${{ needs.preflight.outputs.RUNNER }}" + echo "IMAGE: ${{ needs.preflight.outputs.IMAGE }}" + # + echo "github.ref: ${{ github.ref }}" + echo "github.ref_name: ${{ github.ref_name }}" + echo "github.sha: ${{ github.sha }}" \ No newline at end of file diff --git a/.github/workflows/review-bot.yml b/.github/workflows/review-bot.yml index f1401406ae47..3dd5b1114813 100644 --- a/.github/workflows/review-bot.yml +++ b/.github/workflows/review-bot.yml @@ -15,7 +15,6 @@ on: jobs: review-approvals: runs-on: ubuntu-latest - environment: master steps: - name: Generate token id: app_token @@ -30,7 +29,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/runtimes-matrix.json b/.github/workflows/runtimes-matrix.json new file mode 100644 index 000000000000..e4e3a2dbe6d1 --- /dev/null +++ b/.github/workflows/runtimes-matrix.json @@ -0,0 +1,155 @@ +[ + { + "name": "dev", + "package": "kitchensink-runtime", + "path": "substrate/frame", + "header": "substrate/HEADER-APACHE2", + "template": "substrate/.maintain/frame-weight-template.hbs", + "bench_features": "runtime-benchmarks,riscv", + "bench_flags": "--genesis-builder-policy=none --exclude-pallets=pallet_xcm,pallet_xcm_benchmarks::fungible,pallet_xcm_benchmarks::generic,pallet_nomination_pools,pallet_remark,pallet_transaction_storage", + "uri": null, + "is_relay": false + }, + { + "name": "westend", + "package": "westend-runtime", + "path": "polkadot/runtime/westend", + "header": "polkadot/file_header.txt", + "template": "polkadot/xcm/pallet-xcm-benchmarks/template.hbs", + "bench_flags": "", + "bench_features": "runtime-benchmarks", + "uri": "wss://try-runtime-westend.polkadot.io:443", + "is_relay": true + }, + { + "name": "rococo", + "package": "rococo-runtime", + "path": "polkadot/runtime/rococo", + "header": "polkadot/file_header.txt", + "template": "polkadot/xcm/pallet-xcm-benchmarks/template.hbs", + "uri": "wss://try-runtime-rococo.polkadot.io:443", + "bench_features": "runtime-benchmarks", + "bench_flags": "", + "is_relay": true + }, + { + "name": "asset-hub-westend", + "package": "asset-hub-westend-runtime", + "path": "cumulus/parachains/runtimes/assets/asset-hub-westend", + "header": "cumulus/file_header.txt", + "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "", + "uri": "wss://westend-asset-hub-rpc.polkadot.io:443", + "is_relay": false + }, + { + "name": "asset-hub-rococo", + "package": "asset-hub-rococo-runtime", + "path": "cumulus/parachains/runtimes/assets/asset-hub-rococo", + "header": "cumulus/file_header.txt", + "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "", + "uri": "wss://rococo-asset-hub-rpc.polkadot.io:443", + "is_relay": false + }, + { + "name": "bridge-hub-rococo", + "package": "bridge-hub-rococo-runtime", + "path": "cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo", + "header": "cumulus/file_header.txt", + "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "", + "uri": "wss://rococo-bridge-hub-rpc.polkadot.io:443", + "is_relay": false + }, + { + "name": "bridge-hub-westend", + "package": "bridge-hub-rococo-runtime", + "path": "cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend", + "header": "cumulus/file_header.txt", + "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "", + "uri": "wss://westend-bridge-hub-rpc.polkadot.io:443", + "is_relay": false + }, + { + "name": "collectives-westend", + "package": "collectives-westend-runtime", + "path": "cumulus/parachains/runtimes/collectives/collectives-westend", + "header": "cumulus/file_header.txt", + "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "", + "uri": "wss://westend-collectives-rpc.polkadot.io:443" + }, + { + "name": "contracts-rococo", + "package": "contracts-rococo-runtime", + "path": "cumulus/parachains/runtimes/contracts/contracts-rococo", + "header": "cumulus/file_header.txt", + "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "--genesis-builder-policy=none --exclude-pallets=pallet_xcm", + "uri": "wss://rococo-contracts-rpc.polkadot.io:443", + "is_relay": false + }, + { + "name": "coretime-rococo", + "package": "coretime-rococo-runtime", + "path": "cumulus/parachains/runtimes/coretime/coretime-rococo", + "header": "cumulus/file_header.txt", + "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "--genesis-builder-policy=none --exclude-pallets=pallet_xcm,pallet_xcm_benchmarks::fungible,pallet_xcm_benchmarks::generic", + "uri": "wss://rococo-coretime-rpc.polkadot.io:443", + "is_relay": false + }, + { + "name": "coretime-westend", + "package": "coretime-westend-runtime", + "path": "cumulus/parachains/runtimes/coretime/coretime-westend", + "header": "cumulus/file_header.txt", + "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "--genesis-builder-policy=none --exclude-pallets=pallet_xcm,pallet_xcm_benchmarks::fungible,pallet_xcm_benchmarks::generic", + "uri": "wss://westend-coretime-rpc.polkadot.io:443", + "is_relay": false + }, + { + "name": "glutton-westend", + "package": "glutton-westend-runtime", + "path": "cumulus/parachains/runtimes/gluttons/glutton-westend", + "header": "cumulus/file_header.txt", + "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "--genesis-builder-policy=none", + "uri": null, + "is_relay": false + }, + { + "name": "people-rococo", + "package": "people-rococo-runtime", + "path": "cumulus/parachains/runtimes/people/people-rococo", + "header": "cumulus/file_header.txt", + "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "--genesis-builder-policy=none --exclude-pallets=pallet_xcm,pallet_xcm_benchmarks::fungible,pallet_xcm_benchmarks::generic", + "uri": "wss://rococo-people-rpc.polkadot.io:443", + "is_relay": false + }, + { + "name": "people-westend", + "package": "people-westend-runtime", + "path": "cumulus/parachains/runtimes/people/people-westend", + "header": "cumulus/file_header.txt", + "template": "cumulus/templates/xcm-bench-template.hbs", + "bench_features": "runtime-benchmarks", + "bench_flags": "--genesis-builder-policy=none --exclude-pallets=pallet_xcm,pallet_xcm_benchmarks::fungible,pallet_xcm_benchmarks::generic", + "uri": "wss://westend-people-rpc.polkadot.io:443", + "is_relay": false + } +] diff --git a/.github/workflows/subsystem-benchmarks.yml b/.github/workflows/subsystem-benchmarks.yml new file mode 100644 index 000000000000..210714d847ff --- /dev/null +++ b/.github/workflows/subsystem-benchmarks.yml @@ -0,0 +1,149 @@ +name: Subsystem Benchmarks + +on: + push: + branches: + - master + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + merge_group: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + preflight: + uses: ./.github/workflows/reusable-preflight.yml + + build: + timeout-minutes: 80 + needs: [preflight] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + container: + image: ${{ needs.preflight.outputs.IMAGE }} + 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 + id: run-benchmarks + run: | + forklift cargo bench -p ${{ matrix.features.name }} --bench ${{ matrix.features.bench }} --features subsystem-benchmarks || echo "Benchmarks failed" + ls -lsa ./charts + + - name: Upload artifacts + uses: actions/upload-artifact@v4.3.6 + with: + name: ${{matrix.features.bench}} + path: ./charts + + publish-benchmarks: + timeout-minutes: 60 + needs: [build] + if: github.ref == 'refs/heads/master' + environment: subsystem-benchmarks + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: gh-pages + fetch-depth: 0 + + - run: git checkout master -- + + - name: Download artifacts + uses: actions/download-artifact@v4.1.8 + with: + path: ./charts + + - name: Setup git + run: | + # Fixes "detected dubious ownership" error in the ci + git config --global --add safe.directory '*' + ls -lsR ./charts + + - uses: actions/create-github-app-token@v1 + id: app-token + with: + app-id: ${{ secrets.POLKADOTSDK_GHPAGES_APP_ID }} + private-key: ${{ secrets.POLKADOTSDK_GHPAGES_APP_KEY }} + + - name: Generate ${{ env.BENCH }} + env: + BENCH: availability-recovery-regression-bench + uses: benchmark-action/github-action-benchmark@v1 + with: + tool: "customSmallerIsBetter" + name: ${{ env.BENCH }} + output-file-path: ./charts/${{ env.BENCH }}/${{ env.BENCH }}.json + benchmark-data-dir-path: ./bench/${{ env.BENCH }} + github-token: ${{ steps.app-token.outputs.token }} + auto-push: true + + - name: Generate ${{ env.BENCH }} + env: + BENCH: availability-distribution-regression-bench + uses: benchmark-action/github-action-benchmark@v1 + with: + tool: "customSmallerIsBetter" + name: ${{ env.BENCH }} + output-file-path: ./charts/${{ env.BENCH }}/${{ env.BENCH }}.json + benchmark-data-dir-path: ./bench/${{ env.BENCH }} + github-token: ${{ steps.app-token.outputs.token }} + auto-push: true + + - name: Generate ${{ env.BENCH }} + env: + BENCH: approval-voting-regression-bench + uses: benchmark-action/github-action-benchmark@v1 + with: + tool: "customSmallerIsBetter" + name: ${{ env.BENCH }} + output-file-path: ./charts/${{ env.BENCH }}/${{ env.BENCH }}.json + benchmark-data-dir-path: ./bench/${{ env.BENCH }} + github-token: ${{ steps.app-token.outputs.token }} + auto-push: true + + - name: Generate ${{ env.BENCH }} + env: + BENCH: statement-distribution-regression-bench + uses: benchmark-action/github-action-benchmark@v1 + with: + tool: "customSmallerIsBetter" + name: ${{ env.BENCH }} + output-file-path: ./charts/${{ env.BENCH }}/${{ env.BENCH }}.json + benchmark-data-dir-path: ./bench/${{ env.BENCH }} + github-token: ${{ steps.app-token.outputs.token }} + auto-push: true diff --git a/.github/workflows/tests-linux-stable-coverage.yml b/.github/workflows/tests-linux-stable-coverage.yml new file mode 100644 index 000000000000..90d7bc34a926 --- /dev/null +++ b/.github/workflows/tests-linux-stable-coverage.yml @@ -0,0 +1,123 @@ +# GHA for test-linux-stable-int, test-linux-stable, test-linux-stable-oldkernel +name: tests linux stable coverage + +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 + +jobs: + preflight: + uses: ./.github/workflows/reusable-preflight.yml + if: contains(github.event.label.name, 'GHA-coverage') || contains(github.event.pull_request.labels.*.name, 'GHA-coverage') + + # + # + # + test-linux-stable-coverage: + needs: [preflight] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + timeout-minutes: 120 + container: + image: ${{ needs.preflight.outputs.IMAGE }} + env: + RUST_TOOLCHAIN: stable + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + # + # -Cinstrument-coverage slows everything down but it is necessary for code coverage + # https://doc.rust-lang.org/rustc/instrument-coverage.html + RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings -Cinstrument-coverage" + LLVM_PROFILE_FILE: "/__w/polkadot-sdk/polkadot-sdk/target/coverage/cargo-test-${{ matrix.ci_node_index }}-%p-%m.profraw" + strategy: + fail-fast: false + matrix: + ci_node_index: [1, 2, 3, 4, 5] + ci_node_total: [5] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - run: rustup component add llvm-tools-preview + - run: cargo install cargo-llvm-cov + + - run: mkdir -p target/coverage + + # Some tests are excluded because they run very slowly or fail with -Cinstrument-coverage + - name: run tests + run: > + time cargo llvm-cov nextest + --no-report --release + --workspace + --locked --no-fail-fast + --features try-runtime,ci-only-tests,experimental,riscv + --filter-expr " + !test(/.*benchmark.*/) + - test(/recovers_from_only_chunks_if_pov_large::case_1/) + - test(/participation_requests_reprioritized_for_newly_included/) + - test(/availability_is_recovered_from_chunks_if_no_group_provided::case_1/) + - test(/rejects_missing_inherent_digest/) + - test(/availability_is_recovered_from_chunks_even_if_backing_group_supplied_if_chunks_only::case_1/) + - test(/availability_is_recovered_from_chunks_if_no_group_provided::case_2/) + - test(/all_security_features_work/) + - test(/nonexistent_cache_dir/) + - test(/recovers_from_only_chunks_if_pov_large::case_3/) + - test(/recovers_from_only_chunks_if_pov_large::case_2/) + - test(/authoring_blocks/) + - test(/rejects_missing_seals/) + - test(/generate_chain_spec/) + - test(/get_preset/) + - test(/list_presets/) + - test(/tests::receive_rate_limit_is_enforced/) + - test(/polkadot-availability-recovery/) + " + --partition count:${{ matrix.ci_node_index }}/${{ matrix.ci_node_total }} + + - name: generate report + run: cargo llvm-cov report --release --codecov --output-path coverage-${{ matrix.ci_node_index }}.lcov + - name: upload report + uses: actions/upload-artifact@v4 + with: + name: coverage-report-${{ matrix.ci_node_index }}.lcov + path: coverage-${{ matrix.ci_node_index }}.lcov + + # + # + # Upload to codecov + upload-reports: + needs: [test-linux-stable-coverage] + runs-on: ubuntu-latest + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + path: reports + pattern: coverage-report-* + merge-multiple: true + - run: ls -al reports/ + - name: Upload to Codecov + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + verbose: true + directory: reports + root_dir: /__w/polkadot-sdk/polkadot-sdk/ + + # + # + # + remove-label: + runs-on: ubuntu-latest + needs: [upload-reports] + if: github.event_name == 'pull_request' + steps: + - uses: actions/checkout@v4 + - uses: actions-ecosystem/action-remove-labels@v1 + with: + labels: GHA-coverage \ No newline at end of file diff --git a/.github/workflows/tests-linux-stable.yml b/.github/workflows/tests-linux-stable.yml index 55addf11de06..dd292d55e201 100644 --- a/.github/workflows/tests-linux-stable.yml +++ b/.github/workflows/tests-linux-stable.yml @@ -13,33 +13,16 @@ concurrency: cancel-in-progress: true jobs: - changes: - permissions: - pull-requests: read - uses: ./.github/workflows/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. - needs: changes - if: ${{ needs.changes.outputs.rust }} - 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 + preflight: + uses: ./.github/workflows/reusable-preflight.yml test-linux-stable-int: - needs: [set-image, changes] - if: ${{ needs.changes.outputs.rust }} - runs-on: arc-runners-polkadot-sdk-beefy + needs: [preflight] + if: ${{ needs.preflight.outputs.changes_rust }} + runs-on: ${{ needs.preflight.outputs.RUNNER }} timeout-minutes: 60 container: - image: ${{ needs.set-image.outputs.IMAGE }} + image: ${{ needs.preflight.outputs.IMAGE }} env: RUSTFLAGS: "-C debug-assertions -D warnings" RUST_BACKTRACE: 1 @@ -51,16 +34,86 @@ 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: - needs: [set-image, changes] - if: ${{ needs.changes.outputs.rust }} - runs-on: arc-runners-polkadot-sdk-beefy + needs: [preflight] + if: ${{ needs.preflight.outputs.changes_rust }} + runs-on: ${{ needs.preflight.outputs.RUNNER }} + timeout-minutes: 60 + container: + image: ${{ needs.preflight.outputs.IMAGE }} + 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: forklift cargo nextest run --workspace --features runtime-benchmarks benchmark --locked --cargo-profile testnet --cargo-quiet + + test-linux-stable: + needs: [preflight] + if: ${{ needs.preflight.outputs.changes_rust }} + runs-on: ${{ matrix.runners }} + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + partition: [1/3, 2/3, 3/3] + runners: + [ + "${{ needs.preflight.outputs.RUNNER }}", + "${{ needs.preflight.outputs.RUNNER_OLDLINUX }}", + ] + container: + image: ${{ needs.preflight.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 \ + --cargo-quiet \ + --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 --cargo-quiet + + # some tests do not run with `try-runtime` feature enabled + # https://github.com/paritytech/polkadot-sdk/pull/4251#discussion_r1624282143 + # + # all_security_features_work and nonexistent_cache_dir are currently skipped + # becuase runners don't have the necessary permissions to run them + test-linux-stable-no-try-runtime: + needs: [preflight] + if: ${{ needs.preflight.outputs.changes_rust }} + runs-on: ${{ needs.preflight.outputs.RUNNER }} timeout-minutes: 60 container: - image: ${{ needs.set-image.outputs.IMAGE }} + image: ${{ needs.preflight.outputs.IMAGE }} + strategy: + fail-fast: false + matrix: + partition: [1/2, 2/2] env: RUST_TOOLCHAIN: stable # Enable debug assertions since we are running optimized builds for testing @@ -70,4 +123,35 @@ 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 \ + --locked \ + --release \ + --no-fail-fast \ + --cargo-quiet \ + --features experimental,riscv,ci-only-tests \ + --filter-expr " !test(/all_security_features_work/) - test(/nonexistent_cache_dir/)" \ + --partition count:${{ matrix.partition }} \ + + 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, + test-linux-stable-no-try-runtime, + ] + if: always() && !cancelled() + steps: + - run: | + tee resultfile <<< '${{ toJSON(needs) }}' + FAILURES=$(cat resultfile | grep '"result": "failure"' | wc -l) + if [ $FAILURES -gt 0 ]; then + echo "### At least one required job failed ❌" >> $GITHUB_STEP_SUMMARY + exit 1 + else + echo '### Good job! All the required jobs passed 🚀' >> $GITHUB_STEP_SUMMARY + fi diff --git a/.github/workflows/tests-misc.yml b/.github/workflows/tests-misc.yml new file mode 100644 index 000000000000..cca32650b106 --- /dev/null +++ b/.github/workflows/tests-misc.yml @@ -0,0 +1,394 @@ +name: tests misc + +on: + push: + branches: + - master + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + merge_group: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +# Jobs in this workflow depend on each other, only for limiting peak amount of spawned workers + +jobs: + preflight: + uses: ./.github/workflows/reusable-preflight.yml + + # more information about this job can be found here: + # https://github.com/paritytech/substrate/pull/3778 + test-full-crypto-feature: + needs: [preflight] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} + timeout-minutes: 60 + container: + image: ${{ needs.preflight.outputs.IMAGE }} + env: + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: "-C debug-assertions" + RUST_BACKTRACE: 1 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: script + run: | + cd substrate/primitives/core/ + forklift cargo build --locked --no-default-features --features full_crypto + cd ../application-crypto + forklift cargo build --locked --no-default-features --features full_crypto + + test-frame-examples-compile-to-wasm: + timeout-minutes: 20 + # into one job + needs: [preflight, test-full-crypto-feature] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} + container: + image: ${{ needs.preflight.outputs.IMAGE }} + env: + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: "-C debug-assertions" + RUST_BACKTRACE: 1 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: script + run: | + cd substrate/frame/examples/offchain-worker/ + forklift cargo build --locked --target=wasm32-unknown-unknown --no-default-features + cd ../basic + forklift cargo build --locked --target=wasm32-unknown-unknown --no-default-features + + test-frame-ui: + timeout-minutes: 60 + needs: [preflight] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} + container: + image: ${{ needs.preflight.outputs.IMAGE }} + env: + # Enable debug assertions since we are running optimized builds for testing + # but still want to have debug assertions. + RUSTFLAGS: "-C debug-assertions -D warnings" + RUST_BACKTRACE: 1 + SKIP_WASM_BUILD: 1 + # Ensure we run the UI tests. + RUN_UI_TESTS: 1 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: script + run: | + cargo version + forklift cargo test --locked -q --profile testnet -p frame-support-test --features=frame-feature-testing,no-metadata-docs,try-runtime,experimental ui + forklift cargo test --locked -q --profile testnet -p frame-support-test --features=frame-feature-testing,frame-feature-testing-2,no-metadata-docs,try-runtime,experimental ui + forklift cargo test --locked -q --profile testnet -p xcm-procedural ui + forklift cargo test --locked -q --profile testnet -p frame-election-provider-solution-type ui + forklift cargo test --locked -q --profile testnet -p sp-api-test ui + # There is multiple version of sp-runtime-interface in the repo. So we point to the manifest. + forklift cargo test --locked -q --profile testnet --manifest-path substrate/primitives/runtime-interface/Cargo.toml ui + + test-deterministic-wasm: + timeout-minutes: 20 + needs: [preflight, test-frame-examples-compile-to-wasm] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} + container: + image: ${{ needs.preflight.outputs.IMAGE }} + env: + WASM_BUILD_NO_COLOR: 1 + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: script + run: | + # build runtime + forklift cargo build -q --locked --release -p westend-runtime -p rococo-runtime + # make checksum + sha256sum target/release/wbuild/*-runtime/target/wasm32-unknown-unknown/release/*.wasm > checksum.sha256 + cargo clean + # build again + forklift cargo build -q --locked --release -p westend-runtime -p rococo-runtime + # confirm checksum + sha256sum -c checksum.sha256 + + cargo-check-benches: + needs: [preflight] + if: ${{ github.event_name == 'pull_request' || github.event_name == 'merge_group' }} + timeout-minutes: 60 + strategy: + matrix: + branch: [master, current] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + container: + image: ${{ needs.preflight.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # if branch is master, use the branch, otherwise set empty string, so it uses the current context + # either PR (including forks) or merge group (main repo) + ref: ${{ matrix.branch == 'master' && matrix.branch || '' }} + + - name: script + run: | + ARTIFACTS_DIR=./artifacts + BENCH_TRIE_READ=::trie::read::small + BENCH_NODE_IMPORT=::node::import::sr25519::transfer_keep_alive::paritydb::small + mkdir -p $ARTIFACTS_DIR + + SKIP_WASM_BUILD=1 forklift cargo check --locked --benches --all; + forklift cargo run --locked --release -p node-bench -- $BENCH_TRIE_READ --json | tee $ARTIFACTS_DIR/bench_trie_read_small.json; + forklift cargo run --locked --release -p node-bench -- $BENCH_NODE_IMPORT --json | tee $ARTIFACTS_DIR/bench_transfer_keep_alive.json + + - name: Upload artifacts + uses: actions/upload-artifact@v4.3.6 + with: + path: ./artifacts + name: cargo-check-benches-${{ matrix.branch }}-${{ github.sha }} + retention-days: 1 + + node-bench-regression-guard: + timeout-minutes: 20 + if: always() && !cancelled() + runs-on: ubuntu-latest + needs: [preflight, cargo-check-benches] + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download artifact (master run) + uses: actions/download-artifact@v4.1.8 + with: + name: cargo-check-benches-master-${{ github.sha }} + path: ./artifacts/master + + - name: Download artifact (current run) + uses: actions/download-artifact@v4.1.8 + with: + name: cargo-check-benches-current-${{ github.sha }} + path: ./artifacts/current + + - name: script + id: compare + run: | + if [ "${{ github.ref_name }}" = "master" ]; then + echo -e "Exiting on master branch" + exit 0 + fi + + docker run --rm \ + -v $PWD/artifacts/master:/artifacts/master \ + -v $PWD/artifacts/current:/artifacts/current \ + paritytech/node-bench-regression-guard:latest \ + node-bench-regression-guard --reference /artifacts/master --compare-with /artifacts/current + + if [ $? -ne 0 ]; then + FAILED_MSG='### node-bench-regression-guard failed ❌, check the regression in *cargo-check-benches* job' + echo $FAILED_MSG + echo $FAILED_MSG >> $GITHUB_STEP_SUMMARY + exit 1 + else + echo "### node-bench-regression-guard passed ✅" >> $GITHUB_STEP_SUMMARY + fi + + test-node-metrics: + needs: [preflight] + timeout-minutes: 30 + runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} + container: + image: ${{ needs.preflight.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Run tests + id: tests + 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" + run: | + forklift cargo build --bin polkadot-execute-worker --bin polkadot-prepare-worker --profile testnet --verbose --locked + mkdir -p ./artifacts + forklift cargo test --profile testnet --locked --features=runtime-metrics -p polkadot-node-metrics > ./artifacts/log.txt + echo "Metrics test passed" + + - name: Upload artifacts if failed + if: ${{ steps.tests.outcome != 'success' }} + uses: actions/upload-artifact@v4.3.6 + with: + name: node-metrics-failed + path: ./artifacts + + # more information about this job can be found here: + # https://github.com/paritytech/substrate/pull/6916 + check-tracing: + timeout-minutes: 20 + needs: [preflight, test-node-metrics] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} + container: + image: ${{ needs.preflight.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: script + run: | + forklift cargo test --locked --manifest-path ./substrate/primitives/tracing/Cargo.toml --no-default-features + forklift cargo test --locked --manifest-path ./substrate/primitives/tracing/Cargo.toml --no-default-features --features=with-tracing + + check-metadata-hash: + timeout-minutes: 20 + needs: [preflight, check-tracing] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} + container: + image: ${{ needs.preflight.outputs.IMAGE }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: script + run: | + forklift cargo build --locked -p westend-runtime --features metadata-hash + + # disabled until https://github.com/paritytech/polkadot-sdk/issues/5812 is resolved + # cargo-hfuzz: + # timeout-minutes: 20 + # needs: [preflight, check-metadata-hash] + # runs-on: ${{ needs.preflight.outputs.RUNNER }} + # container: + # image: ${{ needs.preflight.outputs.IMAGE }} + # env: + # # max 10s per iteration, 60s per file + # HFUZZ_RUN_ARGS: | + # --exit_upon_crash + # --exit_code_upon_crash 1 + # --timeout 10 + # --run_time 60 + + # # use git version of honggfuzz-rs until v0.5.56 is out, we need a few recent changes: + # # https://github.com/rust-fuzz/honggfuzz-rs/pull/75 to avoid breakage on debian + # # https://github.com/rust-fuzz/honggfuzz-rs/pull/81 fix to the above pr + # # https://github.com/rust-fuzz/honggfuzz-rs/pull/82 fix for handling absolute CARGO_TARGET_DIR + # HFUZZ_BUILD_ARGS: | + # --config=patch.crates-io.honggfuzz.git="https://github.com/altaua/honggfuzz-rs" + # --config=patch.crates-io.honggfuzz.rev="205f7c8c059a0d98fe1cb912cdac84f324cb6981" + # steps: + # - name: Checkout + # uses: actions/checkout@v4 + + # - name: Run honggfuzz + # run: | + # cd substrate/primitives/arithmetic/fuzzer + # forklift cargo hfuzz build + # for target in $(cargo read-manifest | jq -r '.targets | .[] | .name'); + # do + # forklift cargo hfuzz run "$target" || { printf "fuzzing failure for %s\n" "$target"; exit 1; }; + # done + + # - name: Upload artifacts + # uses: actions/upload-artifact@v4.3.6 + # with: + # path: substrate/primitives/arithmetic/fuzzer/hfuzz_workspace/ + # name: hfuzz-${{ github.sha }} + + cargo-check-each-crate: + timeout-minutes: 70 + needs: [preflight] + runs-on: ${{ needs.preflight.outputs.RUNNER }} + if: ${{ needs.preflight.outputs.changes_rust }} + container: + image: ${{ needs.preflight.outputs.IMAGE }} + env: + RUSTFLAGS: "-D warnings" + CI_JOB_NAME: cargo-check-each-crate + strategy: + matrix: + index: [1, 2, 3, 4, 5, 6, 7] # 7 parallel jobs + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Check Rust + run: | + rustup show + rustup +nightly show + + - name: script + run: | + mkdir -p /github/home/.forklift + cp .forklift/config.toml /github/home/.forklift/config.toml + PYTHONUNBUFFERED=x .github/scripts/check-each-crate.py ${{ matrix.index }} ${{ strategy.job-total }} + + cargo-check-all-crate-macos: + timeout-minutes: 30 + needs: [preflight] + runs-on: ${{ needs.preflight.outputs.RUNNER_MACOS }} + if: ${{ needs.preflight.outputs.changes_rust }} + env: + SKIP_WASM_BUILD: 1 + steps: + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - name: Set rust version from env file + run: | + RUST_VERSION=$(cat .github/env | sed -E 's/.*ci-unified:([^-]+)-([^-]+).*/\2/') + echo $RUST_VERSION + echo "RUST_VERSION=${RUST_VERSION}" >> $GITHUB_ENV + - name: Set up Homebrew + uses: Homebrew/actions/setup-homebrew@1ccc07ccd54b6048295516a3eb89b192c35057dc # master from 12.09.2024 + - name: Install rust ${{ env.RUST_VERSION }} + uses: actions-rust-lang/setup-rust-toolchain@11df97af8e8102fd60b60a77dfbf58d40cd843b8 # v1.10.1 + with: + cache: false + toolchain: ${{ env.RUST_VERSION }} + target: wasm32-unknown-unknown + components: cargo, clippy, rust-docs, rust-src, rustfmt, rustc, rust-std + - name: Install protobuf + run: brew install protobuf + - name: cargo info + run: | + echo "######## rustup show ########" + rustup show + echo "######## cargo --version ########" + cargo --version + - name: Run cargo check + run: cargo check --workspace --locked + + confirm-required-test-misc-jobs-passed: + runs-on: ubuntu-latest + name: All test misc tests passed + # If any new job gets added, be sure to add it to this array + needs: + - test-full-crypto-feature + - test-frame-examples-compile-to-wasm + - test-frame-ui + - cargo-check-benches + - node-bench-regression-guard + - test-node-metrics + - check-tracing + - cargo-check-each-crate + - test-deterministic-wasm + - cargo-check-all-crate-macos + # - cargo-hfuzz remove from required for now, as it's flaky + if: always() && !cancelled() + steps: + - run: | + tee resultfile <<< '${{ toJSON(needs) }}' + FAILURES=$(cat resultfile | grep '"result": "failure"' | wc -l) + if [ $FAILURES -gt 0 ]; then + echo "### At least one required job failed ❌" >> $GITHUB_STEP_SUMMARY + exit 1 + else + echo '### Good job! All the required jobs passed 🚀' >> $GITHUB_STEP_SUMMARY + fi diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a413d3306159..6d6e393b0410 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,31 +12,17 @@ concurrency: cancel-in-progress: true jobs: - changes: - permissions: - pull-requests: read - uses: ./.github/workflows/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 - outputs: - IMAGE: ${{ steps.set_image.outputs.IMAGE }} - steps: - - name: Checkout - uses: actions/checkout@v4 - - id: set_image - run: cat .github/env >> $GITHUB_OUTPUT + preflight: + uses: ./.github/workflows/reusable-preflight.yml + # This job runs all benchmarks defined in the `/bin/node/runtime` once to check that there are no errors. quick-benchmarks: - needs: [set-image, changes] - if: ${{ needs.changes.outputs.rust }} - runs-on: arc-runners-polkadot-sdk-beefy + needs: [preflight] + if: ${{ needs.preflight.outputs.changes_rust }} + runs-on: ${{ needs.preflight.outputs.RUNNER }} timeout-minutes: 60 container: - image: ${{ needs.set-image.outputs.IMAGE }} + image: ${{ needs.preflight.outputs.IMAGE }} env: RUSTFLAGS: "-C debug-assertions -D warnings" RUST_BACKTRACE: "full" @@ -46,16 +32,16 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: script - run: time forklift cargo run --locked --release -p staging-node-cli --bin substrate-node --features runtime-benchmarks -- benchmark pallet --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 --quiet + run: forklift cargo run --locked --release -p staging-node-cli --bin substrate-node --features runtime-benchmarks --quiet -- benchmark pallet --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 --quiet # cf https://github.com/paritytech/polkadot-sdk/issues/1652 test-syscalls: - needs: [set-image, changes] - if: ${{ needs.changes.outputs.rust }} - runs-on: arc-runners-polkadot-sdk-beefy + needs: [preflight] + if: ${{ needs.preflight.outputs.changes_rust }} + runs-on: ${{ needs.preflight.outputs.RUNNER }} timeout-minutes: 60 container: - image: ${{ needs.set-image.outputs.IMAGE }} + image: ${{ needs.preflight.outputs.IMAGE }} continue-on-error: true # this rarely triggers in practice env: SKIP_WASM_BUILD: 1 @@ -63,28 +49,28 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: script + id: test run: | - forklift cargo build --locked --profile production --target x86_64-unknown-linux-musl --bin polkadot-execute-worker --bin polkadot-prepare-worker + forklift cargo build --locked --profile production --target x86_64-unknown-linux-musl --bin polkadot-execute-worker --bin polkadot-prepare-worker --quiet cd polkadot/scripts/list-syscalls ./list-syscalls.rb ../../../target/x86_64-unknown-linux-musl/production/polkadot-execute-worker --only-used-syscalls | diff -u execute-worker-syscalls - ./list-syscalls.rb ../../../target/x86_64-unknown-linux-musl/production/polkadot-prepare-worker --only-used-syscalls | diff -u prepare-worker-syscalls - - # todo: - # after_script: - # - if [[ "$CI_JOB_STATUS" == "failed" ]]; then - # printf "The x86_64 syscalls used by the worker binaries have changed. Please review if this is expected and update polkadot/scripts/list-syscalls/*-worker-syscalls as needed.\n"; - # fi + - name: on_failure + if: failure() && steps.test.outcome == 'failure' + run: | + echo "The x86_64 syscalls used by the worker binaries have changed. Please review if this is expected and update polkadot/scripts/list-syscalls/*-worker-syscalls as needed." >> $GITHUB_STEP_SUMMARY cargo-check-all-benches: - needs: [set-image, changes] - if: ${{ needs.changes.outputs.rust }} - runs-on: arc-runners-polkadot-sdk-beefy + needs: [preflight] + if: ${{ needs.preflight.outputs.changes_rust }} + runs-on: ${{ needs.preflight.outputs.RUNNER }} timeout-minutes: 60 container: - image: ${{ needs.set-image.outputs.IMAGE }} + image: ${{ needs.preflight.outputs.IMAGE }} env: SKIP_WASM_BUILD: 1 steps: - name: Checkout uses: actions/checkout@v4 - name: script - run: time forklift cargo check --all --benches + run: forklift cargo check --all --benches --quiet diff --git a/.gitignore b/.gitignore index e3e382af6195..28c28cc8ab0e 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ **/node_modules **/target/ **/wip/*.stderr +**/__pycache__/ /.cargo/config /.envrc artifacts @@ -39,3 +40,4 @@ rls*.log runtime/wasm/target/ substrate.code-workspace target/ +*.scale diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7f2babc6bd47..f508404f1efa 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,7 +21,8 @@ workflow: - if: $CI_COMMIT_BRANCH variables: - CI_IMAGE: !reference [.ci-unified, variables, CI_IMAGE] + # CI_IMAGE: !reference [ .ci-unified, variables, CI_IMAGE ] + CI_IMAGE: "docker.io/paritytech/ci-unified:bullseye-1.81.0-2024-09-11-v202409111034" # BUILDAH_IMAGE is defined in group variables BUILDAH_COMMAND: "buildah --storage-driver overlay2" RELENG_SCRIPTS_BRANCH: "master" @@ -224,8 +225,6 @@ include: - .gitlab/pipeline/test.yml # build jobs - .gitlab/pipeline/build.yml - # short-benchmarks jobs - - .gitlab/pipeline/short-benchmarks.yml # publish jobs - .gitlab/pipeline/publish.yml # zombienet jobs @@ -268,82 +267,6 @@ remove-cancel-pipeline-message: PR_NUM: "${CI_COMMIT_REF_NAME}" trigger: project: "parity/infrastructure/ci_cd/pipeline-stopper" -# need to copy jobs this way because otherwise gitlab will wait -# for all 3 jobs to finish instead of cancelling if one fails -cancel-pipeline-test-linux-stable1: - extends: .cancel-pipeline-template - needs: - - job: "test-linux-stable 1/3" - -cancel-pipeline-test-linux-stable2: - extends: .cancel-pipeline-template - needs: - - job: "test-linux-stable 2/3" - -cancel-pipeline-test-linux-stable3: - extends: .cancel-pipeline-template - needs: - - job: "test-linux-stable 3/3" - -cancel-pipeline-cargo-check-benches1: - extends: .cancel-pipeline-template - needs: - - job: "cargo-check-benches 1/2" - -cancel-pipeline-cargo-check-benches2: - extends: .cancel-pipeline-template - needs: - - job: "cargo-check-benches 2/2" - -cancel-pipeline-test-linux-stable-int: - extends: .cancel-pipeline-template - needs: - - job: test-linux-stable-int - -cancel-pipeline-cargo-check-each-crate-1: - extends: .cancel-pipeline-template - needs: - - job: "cargo-check-each-crate 1/6" - -cancel-pipeline-cargo-check-each-crate-2: - extends: .cancel-pipeline-template - needs: - - job: "cargo-check-each-crate 2/6" - -cancel-pipeline-cargo-check-each-crate-3: - extends: .cancel-pipeline-template - needs: - - job: "cargo-check-each-crate 3/6" - -cancel-pipeline-cargo-check-each-crate-4: - extends: .cancel-pipeline-template - needs: - - job: "cargo-check-each-crate 4/6" - -cancel-pipeline-cargo-check-each-crate-5: - extends: .cancel-pipeline-template - needs: - - job: "cargo-check-each-crate 5/6" - -cancel-pipeline-cargo-check-each-crate-6: - extends: .cancel-pipeline-template - needs: - - job: "cargo-check-each-crate 6/6" - -cancel-pipeline-cargo-check-each-crate-macos: - extends: .cancel-pipeline-template - needs: - - job: cargo-check-each-crate-macos - -cancel-pipeline-check-tracing: - extends: .cancel-pipeline-template - needs: - - job: check-tracing - -cancel-pipeline-cargo-clippy: - extends: .cancel-pipeline-template - needs: - - job: cargo-clippy cancel-pipeline-build-linux-stable: extends: .cancel-pipeline-template @@ -359,43 +282,3 @@ cancel-pipeline-build-linux-substrate: extends: .cancel-pipeline-template needs: - job: build-linux-substrate - -cancel-pipeline-test-node-metrics: - extends: .cancel-pipeline-template - needs: - - job: test-node-metrics - -cancel-pipeline-test-frame-ui: - extends: .cancel-pipeline-template - needs: - - job: test-frame-ui - -cancel-pipeline-quick-benchmarks: - extends: .cancel-pipeline-template - needs: - - job: quick-benchmarks - -cancel-pipeline-check-try-runtime: - extends: .cancel-pipeline-template - needs: - - job: check-try-runtime - -cancel-pipeline-test-frame-examples-compile-to-wasm: - extends: .cancel-pipeline-template - needs: - - job: test-frame-examples-compile-to-wasm - -cancel-pipeline-build-short-benchmark: - extends: .cancel-pipeline-template - needs: - - job: build-short-benchmark - -cancel-pipeline-check-runtime-migration-rococo: - extends: .cancel-pipeline-template - needs: - - job: check-runtime-migration-rococo - -cancel-pipeline-check-runtime-migration-westend: - extends: .cancel-pipeline-template - needs: - - job: check-runtime-migration-westend diff --git a/.gitlab/pipeline/build.yml b/.gitlab/pipeline/build.yml index 8658e92efc8f..1bd04ae670f4 100644 --- a/.gitlab/pipeline/build.yml +++ b/.gitlab/pipeline/build.yml @@ -83,48 +83,22 @@ build-malus: - echo "polkadot-test-malus = $(cat ./artifacts/VERSION) (EXTRATAG = $(cat ./artifacts/EXTRATAG))" - cp -r ./docker/* ./artifacts -build-rustdoc: +build-templates-node: stage: build extends: - .docker-env - .common-refs - .run-immediately - variables: - SKIP_WASM_BUILD: 1 - RUSTDOCFLAGS: "-Dwarnings --default-theme=ayu --html-in-header ./docs/sdk/assets/header.html --extend-css ./docs/sdk/assets/theme.css --html-after-content ./docs/sdk/assets/after-content.html" - artifacts: - name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}-doc" - when: on_success - expire_in: 1 days - paths: - - ./crate-docs/ + - .collect-artifacts script: - - time cargo doc --all-features --workspace --no-deps - - rm -f ./target/doc/.lock - - mv ./target/doc ./crate-docs - # Inject Simple Analytics (https://www.simpleanalytics.com/) privacy preserving tracker into - # all .html files - - > - inject_simple_analytics() { - local path="$1"; - local script_content=""; - - # Function that inject script into the head of an html file using sed. - process_file() { - local file="$1"; - echo "Adding Simple Analytics script to $file"; - sed -i "s||$script_content|" "$file"; - }; - export -f process_file; - # xargs runs process_file in separate shells without access to outer variables. - # make script_content available inside process_file, export it as an env var here. - export script_content; - - # Modify .html files in parallel using xargs, otherwise it can take a long time. - find "$path" -name '*.html' | xargs -I {} -P "$(nproc)" bash -c 'process_file "$@"' _ {}; - }; - inject_simple_analytics "./crate-docs"; - - echo "" > ./crate-docs/index.html + - time cargo build --locked --package parachain-template-node --release + - time cargo build --locked --package minimal-template-node --release + - time cargo build --locked --package solochain-template-node --release + # pack artifacts + - mkdir -p ./artifacts + - mv ./target/release/parachain-template-node ./artifacts/. + - mv ./target/release/minimal-template-node ./artifacts/. + - mv ./target/release/solochain-template-node ./artifacts/. build-implementers-guide: stage: build @@ -143,18 +117,23 @@ build-implementers-guide: - mkdir -p artifacts - mv polkadot/roadmap/implementers-guide/book artifacts/ -build-short-benchmark: +build-polkadot-zombienet-tests: stage: build extends: - .docker-env - .common-refs - .run-immediately - .collect-artifacts + needs: + - job: build-linux-stable + artifacts: true + - job: build-linux-stable-cumulus + artifacts: true + script: - - cargo build --profile release --locked --features=runtime-benchmarks,on-chain-release-build --bin polkadot --workspace + - cargo nextest --manifest-path polkadot/zombienet-sdk-tests/Cargo.toml archive --features zombie-metadata --archive-file polkadot-zombienet-tests.tar.zst - mkdir -p artifacts - - target/release/polkadot --version - - cp ./target/release/polkadot ./artifacts/ + - cp polkadot-zombienet-tests.tar.zst ./artifacts # build jobs from cumulus @@ -198,101 +177,6 @@ build-test-parachain: - mkdir -p ./artifacts/zombienet - mv ./target/release/wbuild/cumulus-test-runtime/wasm_binary_spec_version_incremented.rs.compact.compressed.wasm ./artifacts/zombienet/. -# build runtime only if files in $RUNTIME_PATH/$RUNTIME_NAME were changed -.build-runtime-template: &build-runtime-template - stage: build - extends: - - .docker-env - - .test-refs-no-trigger-prs-only - - .run-immediately - variables: - RUNTIME_PATH: "parachains/runtimes/assets" - script: - - cd ${RUNTIME_PATH} - - for directory in $(echo */); do - echo "_____Running cargo check for ${directory} ______"; - cd ${directory}; - pwd; - SKIP_WASM_BUILD=1 cargo check --locked; - cd ..; - done - -# DAG: build-runtime-assets -> build-runtime-collectives -> build-runtime-bridge-hubs -# DAG: build-runtime-assets -> build-runtime-collectives -> build-runtime-contracts -# DAG: build-runtime-assets -> build-runtime-coretime -# DAG: build-runtime-assets -> build-runtime-starters -> build-runtime-testing -build-runtime-assets: - <<: *build-runtime-template - variables: - RUNTIME_PATH: "cumulus/parachains/runtimes/assets" - -build-runtime-collectives: - <<: *build-runtime-template - variables: - RUNTIME_PATH: "cumulus/parachains/runtimes/collectives" - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: build-runtime-assets - artifacts: false - -build-runtime-coretime: - <<: *build-runtime-template - variables: - RUNTIME_PATH: "cumulus/parachains/runtimes/coretime" - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: build-runtime-assets - artifacts: false - -build-runtime-bridge-hubs: - <<: *build-runtime-template - variables: - RUNTIME_PATH: "cumulus/parachains/runtimes/bridge-hubs" - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: build-runtime-collectives - artifacts: false - -build-runtime-contracts: - <<: *build-runtime-template - variables: - RUNTIME_PATH: "cumulus/parachains/runtimes/contracts" - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: build-runtime-collectives - artifacts: false - -build-runtime-starters: - <<: *build-runtime-template - variables: - RUNTIME_PATH: "cumulus/parachains/runtimes/starters" - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: build-runtime-assets - artifacts: false - -build-runtime-testing: - <<: *build-runtime-template - variables: - RUNTIME_PATH: "cumulus/parachains/runtimes/testing" - # this is an artificial job dependency, for pipeline optimization using GitLab's DAGs - needs: - - job: build-runtime-starters - artifacts: false - -build-short-benchmark-cumulus: - stage: build - extends: - - .docker-env - - .common-refs - - .run-immediately - - .collect-artifacts - script: - - cargo build --profile release --locked --features=runtime-benchmarks,on-chain-release-build -p polkadot-parachain-bin --bin polkadot-parachain --workspace - - mkdir -p artifacts - - target/release/polkadot-parachain --version - - cp ./target/release/polkadot-parachain ./artifacts/ - # substrate build-linux-substrate: @@ -329,73 +213,6 @@ build-linux-substrate: # - printf '\n# building node-template\n\n' # - ./scripts/ci/node-template-release.sh ./artifacts/substrate/substrate-node-template.tar.gz -build-runtimes-polkavm: - stage: build - extends: - - .docker-env - - .common-refs - - .run-immediately - script: - - SUBSTRATE_RUNTIME_TARGET=riscv cargo check -p minimal-template-runtime - - SUBSTRATE_RUNTIME_TARGET=riscv cargo check -p westend-runtime - - SUBSTRATE_RUNTIME_TARGET=riscv cargo check -p rococo-runtime - - SUBSTRATE_RUNTIME_TARGET=riscv cargo check -p polkadot-test-runtime - -.build-subkey: - stage: build - extends: - - .docker-env - - .common-refs - - .run-immediately - # - .collect-artifact - variables: - # this variable gets overridden by "rusty-cachier environment inject", use the value as default - CARGO_TARGET_DIR: "$CI_PROJECT_DIR/target" - before_script: - - mkdir -p ./artifacts/subkey - - !reference [.forklift-cache, before_script] - script: - - cd ./substrate/bin/utils/subkey - - time SKIP_WASM_BUILD=1 cargo build --locked --release - # - cd - - # - mv $CARGO_TARGET_DIR/release/subkey ./artifacts/subkey/. - # - echo -n "Subkey version = " - # - ./artifacts/subkey/subkey --version | - # sed -n -E 's/^subkey ([0-9.]+.*)/\1/p' | - # tee ./artifacts/subkey/VERSION; - # - sha256sum ./artifacts/subkey/subkey | tee ./artifacts/subkey/subkey.sha256 - # - cp -r ./scripts/ci/docker/subkey.Dockerfile ./artifacts/subkey/ - -build-subkey-linux: - extends: .build-subkey - # DAG - needs: - - job: build-malus - artifacts: false -# tbd -# build-subkey-macos: -# extends: .build-subkey -# # duplicating before_script & script sections from .build-subkey hidden job -# # to overwrite rusty-cachier integration as it doesn't work on macos -# before_script: -# # skip timestamp script, the osx bash doesn't support printf %()T -# - !reference [.job-switcher, before_script] -# - mkdir -p ./artifacts/subkey -# script: -# - cd ./bin/utils/subkey -# - SKIP_WASM_BUILD=1 time cargo build --locked --release -# - cd - -# - mv ./target/release/subkey ./artifacts/subkey/. -# - echo -n "Subkey version = " -# - ./artifacts/subkey/subkey --version | -# sed -n -E 's/^subkey ([0-9.]+.*)/\1/p' | -# tee ./artifacts/subkey/VERSION; -# - sha256sum ./artifacts/subkey/subkey | tee ./artifacts/subkey/subkey.sha256 -# - cp -r ./scripts/ci/docker/subkey.Dockerfile ./artifacts/subkey/ -# after_script: [""] -# tags: -# - osx - # bridges # we need some non-binary artifacts in our bridges+zombienet image diff --git a/.gitlab/pipeline/check.yml b/.gitlab/pipeline/check.yml index 2b8b90ef19a4..7d1f37dddd51 100644 --- a/.gitlab/pipeline/check.yml +++ b/.gitlab/pipeline/check.yml @@ -1,51 +1,3 @@ -cargo-clippy: - stage: check - extends: - - .docker-env - - .common-refs - - .pipeline-stopper-artifacts - variables: - RUSTFLAGS: "-D warnings" - script: - - SKIP_WASM_BUILD=1 cargo clippy --all-targets --locked --workspace --quiet - - SKIP_WASM_BUILD=1 cargo clippy --all-targets --all-features --locked --workspace --quiet - -check-try-runtime: - stage: check - extends: - - .docker-env - - .common-refs - script: - - time cargo check --locked --all --features try-runtime - # this is taken from cumulus - # Check that parachain-template will compile with `try-runtime` feature flag. - - time 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 - - time cargo check --locked --all --features try-runtime,experimental - -# from substrate -# not sure if it's needed in monorepo -check-dependency-rules: - stage: check - extends: - - .kubernetes-env - - .test-refs-no-trigger-prs-only - variables: - CI_IMAGE: "paritytech/tools:latest" - allow_failure: true - script: - - cd substrate/ - - ../.gitlab/ensure-deps.sh - -test-rust-features: - stage: check - extends: - - .kubernetes-env - - .test-refs-no-trigger-prs-only - script: - - bash .gitlab/rust-features.sh . - job-starter: stage: check image: paritytech/tools:latest @@ -55,105 +7,3 @@ job-starter: allow_failure: true script: - echo ok - -check-rust-feature-propagation: - stage: check - extends: - - .kubernetes-env - - .common-refs - script: - - zepter run check - -check-toml-format: - stage: check - extends: - - .kubernetes-env - - .common-refs - script: - - taplo format --check --config .config/taplo.toml - - echo "Please run `taplo format --config .config/taplo.toml` to fix any toml formatting issues" - -# More info can be found here: https://github.com/paritytech/polkadot/pull/5865 -.check-runtime-migration: - stage: check - extends: - - .docker-env - - .test-pr-refs - script: - - 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 - - chmod +x ./try-runtime - - echo "Using try-runtime-cli version:" - - ./try-runtime --version - - echo "---------- Building ${PACKAGE} runtime ----------" - - time cargo build --release --locked -p "$PACKAGE" --features try-runtime - - echo "---------- Executing on-runtime-upgrade for ${NETWORK} ----------" - - > - time ./try-runtime ${COMMAND_EXTRA_ARGS} \ - --runtime ./target/release/wbuild/"$PACKAGE"/"$WASM" \ - on-runtime-upgrade --disable-spec-version-check --checks=all ${SUBCOMMAND_EXTRA_ARGS} live --uri ${URI} - - sleep 5 - -# Check runtime migrations for Parity managed relay chains -check-runtime-migration-westend: - stage: check - extends: - - .docker-env - - .test-pr-refs - - .check-runtime-migration - variables: - NETWORK: "westend" - PACKAGE: "westend-runtime" - WASM: "westend_runtime.compact.compressed.wasm" - URI: "wss://westend-try-runtime-node.parity-chains.parity.io:443" - SUBCOMMAND_EXTRA_ARGS: "--no-weight-warnings" - -check-runtime-migration-rococo: - stage: check - extends: - - .docker-env - - .test-pr-refs - - .check-runtime-migration - variables: - NETWORK: "rococo" - PACKAGE: "rococo-runtime" - WASM: "rococo_runtime.compact.compressed.wasm" - URI: "wss://rococo-try-runtime-node.parity-chains.parity.io:443" - SUBCOMMAND_EXTRA_ARGS: "--no-weight-warnings" - -find-fail-ci-phrase: - stage: check - variables: - CI_IMAGE: "paritytech/tools:latest" - ASSERT_REGEX: "FAIL-CI" - GIT_DEPTH: 1 - extends: - - .kubernetes-env - - .test-pr-refs - script: - - set +e - - rg --line-number --hidden --type rust --glob '!{.git,target}' "$ASSERT_REGEX" .; exit_status=$? - - if [ $exit_status -eq 0 ]; then - echo "$ASSERT_REGEX was found, exiting with 1"; - exit 1; - else - echo "No $ASSERT_REGEX was found, exiting with 0"; - exit 0; - fi - -check-core-crypto-features: - stage: check - extends: - - .docker-env - - .common-refs - script: - - pushd substrate/primitives/core - - ./check-features-variants.sh - - popd - - pushd substrate/primitives/application-crypto - - ./check-features-variants.sh - - popd - - pushd substrate/primitives/keyring - - ./check-features-variants.sh - - popd diff --git a/.gitlab/pipeline/publish.yml b/.gitlab/pipeline/publish.yml index 44cd1933a9cf..92deaea2f612 100644 --- a/.gitlab/pipeline/publish.yml +++ b/.gitlab/pipeline/publish.yml @@ -1,144 +1,6 @@ # This file is part of .gitlab-ci.yml # Here are all jobs that are executed during "publish" stage -publish-rustdoc: - stage: publish - extends: - - .kubernetes-env - - .publish-gh-pages-refs - variables: - CI_IMAGE: node:18 - GIT_DEPTH: 100 - RUSTDOCS_DEPLOY_REFS: "master" - needs: - - job: build-rustdoc - artifacts: true - - job: build-implementers-guide - artifacts: true - script: - # If $CI_COMMIT_REF_NAME doesn't match one of $RUSTDOCS_DEPLOY_REFS space-separated values, we - # exit immediately. - # Putting spaces at the front and back to ensure we are not matching just any substring, but the - # whole space-separated value. - # setup ssh - - eval $(ssh-agent) - - ssh-add - <<< ${GITHUB_SSH_PRIV_KEY} - - mkdir ~/.ssh && touch ~/.ssh/known_hosts - - ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts - # Set git config - - git config user.email "devops-team@parity.io" - - git config user.name "${GITHUB_USER}" - - git config remote.origin.url "git@github.com:/paritytech/${CI_PROJECT_NAME}.git" - - git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" - - git fetch origin gh-pages - # Save README and docs - - cp -r ./crate-docs/ /tmp/doc/ - - cp -r ./artifacts/book/ /tmp/ - - cp README.md /tmp/doc/ - # we don't need to commit changes because we copy docs to /tmp - - git checkout gh-pages --force - # Enable if docs needed for other refs - # Install `index-tpl-crud` and generate index.html based on RUSTDOCS_DEPLOY_REFS - # - which index-tpl-crud &> /dev/null || yarn global add @substrate/index-tpl-crud - # - index-tpl-crud upsert ./index.html ${CI_COMMIT_REF_NAME} - # Ensure the destination dir doesn't exist. - - rm -rf ${CI_COMMIT_REF_NAME} - - rm -rf book/ - - mv -f /tmp/doc ${CI_COMMIT_REF_NAME} - # dir for implementors guide - - mkdir -p book - - mv /tmp/book/html/* book/ - # Upload files - - git add --all - # `git commit` has an exit code of > 0 if there is nothing to commit. - # This causes GitLab to exit immediately and marks this job failed. - # We don't want to mark the entire job failed if there's nothing to - # publish though, hence the `|| true`. - - git commit -m "___Updated docs for ${CI_COMMIT_REF_NAME}___" || - echo "___Nothing to commit___" - - git push origin gh-pages --force - # artificial sleep to publish gh-pages - - sleep 300 - after_script: - - rm -rf .git/ ./* - -publish-subsystem-benchmarks: - stage: publish - variables: - CI_IMAGE: "paritytech/tools:latest" - extends: - - .kubernetes-env - - .publish-gh-pages-refs - needs: - - job: subsystem-benchmark-availability-recovery - artifacts: true - - job: subsystem-benchmark-availability-distribution - artifacts: true - - job: subsystem-benchmark-approval-voting - artifacts: true - - job: subsystem-benchmark-statement-distribution - artifacts: true - - job: publish-rustdoc - artifacts: false - script: - # setup ssh - - eval $(ssh-agent) - - ssh-add - <<< ${GITHUB_SSH_PRIV_KEY} - - mkdir ~/.ssh && touch ~/.ssh/known_hosts - - ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts - # Set git config - - rm -rf .git/config - - git config user.email "devops-team@parity.io" - - git config user.name "${GITHUB_USER}" - - git config remote.origin.url "git@github.com:/paritytech/${CI_PROJECT_NAME}.git" - - git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" - - git fetch origin gh-pages - # Push result to github - - git checkout gh-pages --force - - mkdir -p bench/gitlab/ || echo "Directory exists" - - rm -rf bench/gitlab/*.json || echo "No json files" - - cp -r charts/*.json bench/gitlab/ - - git add bench/gitlab/ - - git commit -m "Add json files with benchmark results for ${CI_COMMIT_REF_NAME}" - - git push origin gh-pages - # artificial sleep to publish gh-pages - - sleep 300 - allow_failure: true - after_script: - - rm -rf .git/ ./* - -trigger_workflow: - stage: deploy - extends: - - .kubernetes-env - - .publish-gh-pages-refs - needs: - - job: publish-subsystem-benchmarks - artifacts: false - - job: subsystem-benchmark-availability-recovery - artifacts: true - - job: subsystem-benchmark-availability-distribution - artifacts: true - - job: subsystem-benchmark-approval-voting - artifacts: true - - job: subsystem-benchmark-statement-distribution - artifacts: true - script: - - echo "Triggering workflow" - - > - for benchmark in $(ls charts/*.json); do - export benchmark_name=$(basename $benchmark); - echo "Benchmark: $benchmark_name"; - export benchmark_dir=$(echo $benchmark_name | sed 's/\.json//'); - curl -q -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: token $GITHUB_TOKEN" \ - https://api.github.com/repos/paritytech/${CI_PROJECT_NAME}/actions/workflows/publish-subsystem-benchmarks.yml/dispatches \ - -d "{\"ref\":\"refs/heads/master\",\"inputs\":{\"benchmark-data-dir-path\":\"$benchmark_dir\",\"output-file-path\":\"$benchmark_name\"}}"; - sleep 300; - done - allow_failure: true - # note: images are used not only in zombienet but also in rococo, wococo and versi .build-push-image: image: $BUILDAH_IMAGE diff --git a/.gitlab/pipeline/short-benchmarks.yml b/.gitlab/pipeline/short-benchmarks.yml index bc6dd04264c8..ed97d539c095 100644 --- a/.gitlab/pipeline/short-benchmarks.yml +++ b/.gitlab/pipeline/short-benchmarks.yml @@ -1,100 +1 @@ -# This file is part of .gitlab-ci.yml -# Here are all jobs that are executed during "short-benchmarks" stage - -# Run all pallet benchmarks only once to check if there are any errors - -# run short-benchmarks for relay chain runtimes from polkadot - -short-benchmark-westend: &short-bench - stage: short-benchmarks - extends: - - .docker-env - - .common-refs - needs: - - job: build-short-benchmark - artifacts: true - variables: - RUNTIME: westend - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-C debug-assertions -D warnings" - RUST_BACKTRACE: "full" - WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" - tags: - - benchmark - script: - - ./artifacts/polkadot benchmark pallet --chain $RUNTIME-dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 - -# run short-benchmarks for system parachain runtimes from cumulus - -.short-benchmark-cumulus: &short-bench-cumulus - stage: short-benchmarks - extends: - - .common-refs - - .docker-env - needs: - - job: build-short-benchmark-cumulus - artifacts: true - variables: - RUNTIME_CHAIN: benchmarked-runtime-chain - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-C debug-assertions -D warnings" - RUST_BACKTRACE: "full" - WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" - tags: - - benchmark - script: - - ./artifacts/polkadot-parachain benchmark pallet --chain $RUNTIME_CHAIN --pallet "*" --extrinsic "*" --steps 2 --repeat 1 - -short-benchmark-asset-hub-rococo: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: asset-hub-rococo-dev - -short-benchmark-asset-hub-westend: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: asset-hub-westend-dev - -short-benchmark-bridge-hub-rococo: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: bridge-hub-rococo-dev - -short-benchmark-bridge-hub-westend: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: bridge-hub-westend-dev - -short-benchmark-collectives-westend: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: collectives-westend-dev - -short-benchmark-coretime-rococo: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: coretime-rococo-dev - -short-benchmark-coretime-westend: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: coretime-westend-dev - -short-benchmark-people-rococo: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: people-rococo-dev - -short-benchmark-people-westend: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: people-westend-dev - -short-benchmark-glutton-westend: - <<: *short-bench-cumulus - variables: - RUNTIME_CHAIN: glutton-westend-dev-1300 +--- diff --git a/.gitlab/pipeline/test.yml b/.gitlab/pipeline/test.yml index d171a8a19426..8e32a3614679 100644 --- a/.gitlab/pipeline/test.yml +++ b/.gitlab/pipeline/test.yml @@ -109,531 +109,3 @@ test-linux-stable-codecov: else 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: - - .docker-env - - .common-refs - - .run-immediately - - .pipeline-stopper-artifacts - variables: - 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" - parallel: 3 - script: - # Build all but only execute 'runtime' tests. - - echo "Node index - ${CI_NODE_INDEX}. Total amount - ${CI_NODE_TOTAL}" - - > - time cargo nextest run \ - --workspace \ - --locked \ - --release \ - --no-fail-fast \ - --features try-runtime,experimental,riscv,ci-only-tests \ - --partition count:${CI_NODE_INDEX}/${CI_NODE_TOTAL} - # Upload tests results to Elasticsearch - - echo "Upload test results to Elasticsearch" - - cat target/nextest/default/junit.xml | xq . > target/nextest/default/junit.json - - > - curl -v -XPOST --http1.1 \ - -u ${ELASTIC_USERNAME}:${ELASTIC_PASSWORD} \ - https://elasticsearch.parity-build.parity.io/unit-tests/_doc/${CI_JOB_ID} \ - -H 'Content-Type: application/json' \ - -d @target/nextest/default/junit.json || echo "failed to upload junit report" - # run runtime-api tests with `enable-staging-api` feature on the 1st node - - if [ ${CI_NODE_INDEX} == 1 ]; then time cargo nextest run -p sp-api-test --features enable-staging-api; fi - artifacts: - when: always - paths: - - target/nextest/default/junit.xml - reports: - junit: target/nextest/default/junit.xml - timeout: 90m - -test-linux-oldkernel-stable: - extends: test-linux-stable - tags: - - oldkernel-vm - -# https://github.com/paritytech/ci_cd/issues/864 -test-linux-stable-runtime-benchmarks: - stage: test - extends: - - .docker-env - - .common-refs - - .run-immediately - - .pipeline-stopper-artifacts - variables: - 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" - script: - - time cargo nextest run --workspace --features runtime-benchmarks benchmark --locked --cargo-profile testnet - -# can be used to run all tests -# test-linux-stable-all: -# stage: test -# extends: -# - .docker-env -# - .common-refs -# - .run-immediately -# variables: -# 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" -# parallel: 3 -# script: -# # Build all but only execute 'runtime' tests. -# - echo "Node index - ${CI_NODE_INDEX}. Total amount - ${CI_NODE_TOTAL}" -# - > -# time cargo nextest run \ -# --workspace \ -# --locked \ -# --release \ -# --no-fail-fast \ -# --features runtime-benchmarks,try-runtime \ -# --partition count:${CI_NODE_INDEX}/${CI_NODE_TOTAL} -# # todo: add flacky-test collector - -# takes about 1,5h without cache -# can be used to check that nextest works correctly -# test-linux-stable-polkadot: -# stage: test -# timeout: 2h -# extends: -# - .docker-env -# - .common-refs -# - .run-immediately -# - .collect-artifacts-short -# variables: -# 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" -# script: -# - mkdir -p artifacts -# - time cargo test --workspace -# --locked -# --profile testnet -# --features=runtime-benchmarks,runtime-metrics,try-runtime -- -# --skip upgrade_version_checks_should_work - -test-doc: - stage: test - extends: - - .docker-env - - .common-refs - # DAG - needs: - - job: test-rustdoc - artifacts: false - variables: - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-Cdebug-assertions=y -Dwarnings" - script: - - time cargo test --doc --workspace - -test-rustdoc: - stage: test - extends: - - .docker-env - - .common-refs - - .run-immediately - variables: - SKIP_WASM_BUILD: 1 - script: - - time cargo doc --workspace --all-features --no-deps - -test-node-metrics: - stage: test - extends: - - .docker-env - - .common-refs - - .run-immediately - - .collect-artifacts-short - variables: - 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" - script: - # Build the required workers. - - cargo build --bin polkadot-execute-worker --bin polkadot-prepare-worker --profile testnet --verbose --locked - - mkdir -p artifacts - - time cargo test --profile testnet - --locked - --features=runtime-metrics -p polkadot-node-metrics > artifacts/log.txt - -test-deterministic-wasm: - stage: test - extends: - - .docker-env - - .common-refs - # DAG - needs: - - job: test-frame-ui - artifacts: false - script: - # build runtime - - WASM_BUILD_NO_COLOR=1 cargo build -q --locked --release -p westend-runtime -p rococo-runtime - # make checksum - - sha256sum target/release/wbuild/*-runtime/target/wasm32-unknown-unknown/release/*.wasm > checksum.sha256 - - cargo clean - # build again - - WASM_BUILD_NO_COLOR=1 cargo build -q --locked --release -p westend-runtime -p rococo-runtime - # confirm checksum - - sha256sum -c checksum.sha256 - -cargo-check-benches: - stage: test - artifacts: - expire_in: 10 days - variables: - CI_JOB_NAME: "cargo-check-benches" - extends: - - .docker-env - - .common-refs - - .run-immediately - - .collect-artifacts - - .pipeline-stopper-artifacts - before_script: - # TODO: DON'T FORGET TO CHANGE FOR PROD VALUES!!! - # merges in the master branch on PRs. skip if base is not master - - 'if [ $CI_COMMIT_REF_NAME != "master" ]; then - BASE=$(curl -s -H "Authorization: Bearer ${GITHUB_PR_TOKEN}" https://api.github.com/repos/paritytech-stg/polkadot-sdk/pulls/${CI_COMMIT_REF_NAME} | jq -r .base.ref); - printf "Merging base branch %s\n" "${BASE:=master}"; - if [ $BASE != "master" ]; then - echo "$BASE is not master, skipping merge"; - else - git config user.email "ci@gitlab.parity.io"; - git fetch origin "refs/heads/${BASE}"; - git merge --verbose --no-edit FETCH_HEAD; - fi - fi' - - !reference [.forklift-cache, before_script] - parallel: 2 - script: - - mkdir -p ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA - # this job is executed in parallel on two runners - - echo "___Running benchmarks___"; - - case ${CI_NODE_INDEX} in - 1) - SKIP_WASM_BUILD=1 time cargo check --locked --benches --all; - cargo run --locked --release -p node-bench -- ::trie::read::small --json - | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::trie::read::small.json; - echo "___Cache could be uploaded___"; - ;; - 2) - cargo run --locked --release -p node-bench -- ::node::import::sr25519::transfer_keep_alive::paritydb::small --json - | tee ./artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA/::node::import::sr25519::transfer_keep_alive::paritydb::small.json - ;; - esac - -node-bench-regression-guard: - # it's not belong to `build` semantically, but dag jobs can't depend on each other - # within the single stage - https://gitlab.com/gitlab-org/gitlab/-/issues/30632 - # more: https://github.com/paritytech/substrate/pull/8519#discussion_r608012402 - stage: build - extends: - - .docker-env - - .common-refs - needs: - # this is a DAG - - job: cargo-check-benches - artifacts: true - # polls artifact from master to compare with current result - # need to specify both parallel jobs from master because of the bug - # https://gitlab.com/gitlab-org/gitlab/-/issues/39063 - - project: $CI_PROJECT_PATH - job: "cargo-check-benches 1/2" - ref: master - artifacts: true - - project: $CI_PROJECT_PATH - job: "cargo-check-benches 2/2" - ref: master - artifacts: true - variables: - CI_IMAGE: "paritytech/node-bench-regression-guard:latest" - before_script: [""] - script: - - if [ $(ls -la artifacts/benches/ | grep master | wc -l) == 0 ]; then - echo "Couldn't find master artifacts"; - exit 1; - fi - - echo "------- IMPORTANT -------" - - echo "node-bench-regression-guard depends on the results of a cargo-check-benches job" - - echo "In case of this job failure, check your pipeline's cargo-check-benches" - - "node-bench-regression-guard --reference artifacts/benches/master-* - --compare-with artifacts/benches/$CI_COMMIT_REF_NAME-$CI_COMMIT_SHORT_SHA" - after_script: [""] - -# if this fails run `bot update-ui` in the Pull Request or "./scripts/update-ui-tests.sh" locally -# see ./docs/contributor/CONTRIBUTING.md#ui-tests -test-frame-ui: - stage: test - extends: - - .docker-env - - .common-refs - # DAG - needs: - - job: test-frame-examples-compile-to-wasm - artifacts: false - variables: - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-C debug-assertions -D warnings" - RUST_BACKTRACE: 1 - WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" - # Ensure we run the UI tests. - RUN_UI_TESTS: 1 - 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 - - 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. -quick-benchmarks: - stage: test - extends: - - .docker-env - - .common-refs - - .run-immediately - variables: - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-C debug-assertions -D warnings" - RUST_BACKTRACE: "full" - WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" - script: - - time cargo run --locked --release -p staging-node-cli --bin substrate-node --features runtime-benchmarks --quiet -- benchmark pallet --chain dev --pallet "*" --extrinsic "*" --steps 2 --repeat 1 --quiet - -quick-benchmarks-omni: - stage: test - extends: - - .docker-env - - .common-refs - - .run-immediately - variables: - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-C debug-assertions" - RUST_BACKTRACE: "full" - WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-C debug-assertions" - script: - - time cargo build --locked --quiet --release -p asset-hub-westend-runtime --features runtime-benchmarks - - time cargo run --locked --release -p frame-omni-bencher --quiet -- v1 benchmark pallet --runtime target/release/wbuild/asset-hub-westend-runtime/asset_hub_westend_runtime.compact.compressed.wasm --all --steps 2 --repeat 1 --quiet - -test-frame-examples-compile-to-wasm: - # into one job - stage: test - extends: - - .docker-env - - .common-refs - # DAG - needs: - - job: test-full-crypto-feature - artifacts: false - variables: - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-C debug-assertions" - RUST_BACKTRACE: 1 - script: - - cd ./substrate/frame/examples/offchain-worker/ - - cargo build --locked --target=wasm32-unknown-unknown --no-default-features - - cd ../basic - - cargo build --locked --target=wasm32-unknown-unknown --no-default-features - # FIXME - allow_failure: true - -test-linux-stable-int: - stage: test - extends: - - .docker-env - - .common-refs - - .run-immediately - - .pipeline-stopper-artifacts - variables: - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-C debug-assertions -D warnings" - RUST_BACKTRACE: 1 - WASM_BUILD_NO_COLOR: 1 - WASM_BUILD_RUSTFLAGS: "-C debug-assertions -D warnings" - # Ensure we run the UI tests. - RUN_UI_TESTS: 1 - script: - - WASM_BUILD_NO_COLOR=1 - time cargo test -p staging-node-cli --release --locked -- --ignored - -# more information about this job can be found here: -# https://github.com/paritytech/substrate/pull/6916 -check-tracing: - stage: test - extends: - - .docker-env - - .common-refs - - .run-immediately - - .pipeline-stopper-artifacts - script: - # with-tracing must be explicitly activated, we run a test to ensure this works as expected in both cases - - time cargo test --locked --manifest-path ./substrate/primitives/tracing/Cargo.toml --no-default-features - - time cargo test --locked --manifest-path ./substrate/primitives/tracing/Cargo.toml --no-default-features --features=with-tracing - -# Check that `westend-runtime` compiles with the `metadata-hash` feature enabled. -check-metadata-hash: - stage: test - extends: - - .docker-env - - .common-refs - - .run-immediately - - .pipeline-stopper-artifacts - script: - - time cargo build --locked -p westend-runtime --features metadata-hash - -# more information about this job can be found here: -# https://github.com/paritytech/substrate/pull/3778 -test-full-crypto-feature: - stage: test - extends: - - .docker-env - - .common-refs - - .run-immediately - variables: - # Enable debug assertions since we are running optimized builds for testing - # but still want to have debug assertions. - RUSTFLAGS: "-C debug-assertions" - RUST_BACKTRACE: 1 - script: - - cd substrate/primitives/core/ - - time cargo build --locked --no-default-features --features full_crypto - - cd ../application-crypto - - time cargo build --locked --no-default-features --features full_crypto - -cargo-check-each-crate: - stage: test - extends: - - .docker-env - - .common-refs - - .run-immediately - # - .collect-artifacts - variables: - RUSTFLAGS: "-D warnings" - # $CI_JOB_NAME is set manually so that cache could be shared for all jobs - # "cargo-check-each-crate I/N" jobs - CI_JOB_NAME: cargo-check-each-crate - timeout: 2h - script: - - PYTHONUNBUFFERED=x time .gitlab/check-each-crate.py "$CI_NODE_INDEX" "$CI_NODE_TOTAL" - parallel: 6 - -cargo-check-each-crate-macos: - stage: test - extends: - - .docker-env - - .common-refs - - .run-immediately - # - .collect-artifacts - before_script: - # skip timestamp script, the osx bash doesn't support printf %()T - - !reference [.job-switcher, before_script] - - !reference [.rust-info-script, script] - - !reference [.pipeline-stopper-vars, script] - variables: - SKIP_WASM_BUILD: 1 - script: - # TODO: use parallel jobs, as per cargo-check-each-crate, once more Mac runners are available - # - time ./scripts/ci/gitlab/check-each-crate.py 1 1 - - time cargo check --workspace --locked - timeout: 2h - tags: - - osx - -cargo-hfuzz: - stage: test - extends: - - .docker-env - - .common-refs - # DAG - needs: - - job: check-tracing - artifacts: false - variables: - # max 10s per iteration, 60s per file - HFUZZ_RUN_ARGS: > - --exit_upon_crash - --exit_code_upon_crash 1 - --timeout 10 - --run_time 60 - # use git version of honggfuzz-rs until v0.5.56 is out, we need a few recent changes: - # https://github.com/rust-fuzz/honggfuzz-rs/pull/75 to avoid breakage on debian - # https://github.com/rust-fuzz/honggfuzz-rs/pull/81 fix to the above pr - # https://github.com/rust-fuzz/honggfuzz-rs/pull/82 fix for handling absolute CARGO_TARGET_DIR - HFUZZ_BUILD_ARGS: > - --config=patch.crates-io.honggfuzz.git="https://github.com/altaua/honggfuzz-rs" - --config=patch.crates-io.honggfuzz.rev="205f7c8c059a0d98fe1cb912cdac84f324cb6981" - artifacts: - name: "hfuzz-$CI_COMMIT_SHORT_SHA" - expire_in: 7 days - when: on_failure - paths: - - substrate/primitives/arithmetic/fuzzer/hfuzz_workspace/ - script: - - cd ./substrate/primitives/arithmetic/fuzzer - - cargo hfuzz build - - for target in $(cargo read-manifest | jq -r '.targets | .[] | .name'); do - cargo hfuzz run "$target" || { printf "fuzzing failure for %s\n" "$target"; exit 1; }; done - -.subsystem-benchmark-template: - stage: test - artifacts: - name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" - when: always - expire_in: 1 hour - paths: - - charts/ - extends: - - .docker-env - - .common-refs - - .run-immediately - tags: - - benchmark - -subsystem-benchmark-availability-recovery: - extends: - - .subsystem-benchmark-template - script: - - cargo bench -p polkadot-availability-recovery --bench availability-recovery-regression-bench --features subsystem-benchmarks - allow_failure: true - -subsystem-benchmark-availability-distribution: - extends: - - .subsystem-benchmark-template - script: - - cargo bench -p polkadot-availability-distribution --bench availability-distribution-regression-bench --features subsystem-benchmarks - allow_failure: true - -subsystem-benchmark-approval-voting: - extends: - - .subsystem-benchmark-template - script: - - cargo bench -p polkadot-node-core-approval-voting --bench approval-voting-regression-bench --features subsystem-benchmarks - allow_failure: true - -subsystem-benchmark-statement-distribution: - extends: - - .subsystem-benchmark-template - script: - - cargo bench -p polkadot-statement-distribution --bench statement-distribution-regression-bench --features subsystem-benchmarks - allow_failure: true diff --git a/.gitlab/pipeline/zombienet.yml b/.gitlab/pipeline/zombienet.yml index 7897e55e291b..08bfed2e24ce 100644 --- a/.gitlab/pipeline/zombienet.yml +++ b/.gitlab/pipeline/zombienet.yml @@ -1,9 +1,15 @@ .zombienet-refs: extends: .build-refs variables: - ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.105" + ZOMBIENET_IMAGE: "docker.io/paritytech/zombienet:v1.3.116" PUSHGATEWAY_URL: "http://zombienet-prometheus-pushgateway.managed-monitoring:9091/metrics/job/zombie-metrics" DEBUG: "zombie,zombie::network-node,zombie::kube::client::logs" + ZOMBIE_PROVIDER: "k8s" + RUST_LOG: "info,zombienet_orchestrator=debug" + RUN_IN_CI: "1" + KUBERNETES_CPU_REQUEST: "512m" + KUBERNETES_MEMORY_REQUEST: "1Gi" + timeout: 60m include: # substrate tests @@ -14,3 +20,5 @@ include: - .gitlab/pipeline/zombienet/polkadot.yml # bridges tests - .gitlab/pipeline/zombienet/bridges.yml + # parachain-template-node tests + - .gitlab/pipeline/zombienet/parachain-template.yml diff --git a/.gitlab/pipeline/zombienet/bridges.yml b/.gitlab/pipeline/zombienet/bridges.yml index 9d7a8b931193..0472601a6a2b 100644 --- a/.gitlab/pipeline/zombienet/bridges.yml +++ b/.gitlab/pipeline/zombienet/bridges.yml @@ -47,17 +47,19 @@ - cp -r /tmp/bridges-tests-run-*/bridge_hub_rococo_local_network/*.log ./zombienet-logs/ # copy logs of westend nodes - cp -r /tmp/bridges-tests-run-*/bridge_hub_westend_local_network/*.log ./zombienet-logs/ + tags: + - zombienet-polkadot-integration-test zombienet-bridges-0001-asset-transfer-works: extends: - .zombienet-bridges-common script: - - /home/nonroot/bridges-polkadot-sdk/bridges/testing/run-new-test.sh 0001-asset-transfer --docker + - /home/nonroot/bridges-polkadot-sdk/bridges/testing/run-test.sh 0001-asset-transfer --docker - echo "Done" zombienet-bridges-0002-free-headers-synced-while-idle: extends: - .zombienet-bridges-common script: - - /home/nonroot/bridges-polkadot-sdk/bridges/testing/run-new-test.sh 0002-free-headers-synced-while-idle --docker + - /home/nonroot/bridges-polkadot-sdk/bridges/testing/run-test.sh 0002-free-headers-synced-while-idle --docker - echo "Done" diff --git a/.gitlab/pipeline/zombienet/cumulus.yml b/.gitlab/pipeline/zombienet/cumulus.yml index 6e2b53fae619..fc88e1ff1450 100644 --- a/.gitlab/pipeline/zombienet/cumulus.yml +++ b/.gitlab/pipeline/zombienet/cumulus.yml @@ -46,7 +46,9 @@ paths: - ./zombienet-logs allow_failure: true - retry: 2 + retry: + max: 1 + when: runner_system_failure tags: - zombienet-polkadot-integration-test diff --git a/.gitlab/pipeline/zombienet/parachain-template.yml b/.gitlab/pipeline/zombienet/parachain-template.yml new file mode 100644 index 000000000000..896ba7913be7 --- /dev/null +++ b/.gitlab/pipeline/zombienet/parachain-template.yml @@ -0,0 +1,46 @@ +# common settings for all zombienet jobs +.zombienet-parachain-template-common: + before_script: + # add `./artifacts` to the PATH + - export PATH=$(pwd)/artifacts:$PATH + stage: zombienet + needs: + - job: build-linux-stable # polkadot binaries + artifacts: true + - job: build-templates-node # templates + artifacts: true + extends: + - .docker-env + - .zombienet-refs + variables: + ZOMBIE_PROVIDER: "native" + RUST_LOG: "info,zombienet_orchestrator=debug" + FF_DISABLE_UMASK_FOR_DOCKER_EXECUTOR: 1 + RUN_IN_CONTAINER: "1" + RUNNER_SCRIPT_TIMEOUT: 15m + RUNNER_AFTER_SCRIPT_TIMEOUT: 5m + artifacts: + name: "${CI_JOB_NAME}_${CI_COMMIT_REF_NAME}" + when: always + expire_in: 2 days + paths: + - ./zombienet-logs + after_script: + - mkdir -p ./zombienet-logs + - cp /tmp/zombie*/*/*.log ./zombienet-logs/ + retry: + max: 1 + when: runner_system_failure + timeout: 20m + tags: + - linux-docker + +zombienet-parachain-template-smoke: + extends: + - .zombienet-parachain-template-common + script: + - echo $PATH + - ls -ltr $(pwd)/artifacts + - cargo test -p template-zombienet-tests --features zombienet --tests minimal_template_block_production_test + - cargo test -p template-zombienet-tests --features zombienet --tests parachain_template_block_production_test + # - cargo test -p template-zombienet-tests --features zombienet --tests solochain_template_block_production_test diff --git a/.gitlab/pipeline/zombienet/polkadot.yml b/.gitlab/pipeline/zombienet/polkadot.yml index 90251082077c..60870caf26c8 100644 --- a/.gitlab/pipeline/zombienet/polkadot.yml +++ b/.gitlab/pipeline/zombienet/polkadot.yml @@ -31,6 +31,12 @@ - echo "colander image ${COL_IMAGE}" - echo "cumulus image ${CUMULUS_IMAGE}" - echo "malus image ${MALUS_IMAGE}" + # RUN_IN_CONTAINER is env var that is set in the dockerfile + - if [[ -v RUN_IN_CONTAINER ]]; then + echo "Initializing zombie cluster"; + gcloud auth activate-service-account --key-file "/etc/zombie-net/sa-zombie.json"; + gcloud container clusters get-credentials parity-zombienet --zone europe-west3-b --project parity-zombienet; + fi stage: zombienet image: "${ZOMBIENET_IMAGE}" needs: @@ -54,6 +60,7 @@ MALUS_IMAGE: "docker.io/paritypr/malus" GH_DIR: "https://github.com/paritytech/substrate/tree/${CI_COMMIT_SHA}/zombienet" LOCAL_DIR: "/builds/parity/mirrors/polkadot-sdk/polkadot/zombienet_tests" + LOCAL_SDK_TEST: "/builds/parity/mirrors/polkadot-sdk/polkadot/zombienet-sdk-tests" FF_DISABLE_UMASK_FOR_DOCKER_EXECUTOR: 1 RUN_IN_CONTAINER: "1" artifacts: @@ -65,7 +72,9 @@ after_script: - mkdir -p ./zombienet-logs - cp /tmp/zombie*/logs/* ./zombienet-logs/ - retry: 2 + retry: + max: 1 + when: runner_system_failure tags: - zombienet-polkadot-integration-test @@ -101,7 +110,7 @@ zombienet-polkadot-functional-0004-parachains-disputes-garbage-candidate: --local-dir="${LOCAL_DIR}/functional" --test="0004-parachains-garbage-candidate.zndsl" -zombienet-polkadot-functional-0005-parachains-disputes-past-session: +.zombienet-polkadot-functional-0005-parachains-disputes-past-session: extends: - .zombienet-polkadot-common script: @@ -163,7 +172,7 @@ zombienet-polkadot-elastic-scaling-0001-basic-3cores-6s-blocks: variables: FORCED_INFRA_INSTANCE: "spot-iops" before_script: - - !reference [.zombienet-polkadot-common, before_script] + - !reference [ .zombienet-polkadot-common, before_script ] - cp --remove-destination ${LOCAL_DIR}/assign-core.js ${LOCAL_DIR}/elastic_scaling script: - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh @@ -174,14 +183,14 @@ zombienet-polkadot-elastic-scaling-0002-elastic-scaling-doesnt-break-parachains: extends: - .zombienet-polkadot-common before_script: - - !reference [.zombienet-polkadot-common, before_script] + - !reference [ .zombienet-polkadot-common, before_script ] - cp --remove-destination ${LOCAL_DIR}/assign-core.js ${LOCAL_DIR}/elastic_scaling script: - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh --local-dir="${LOCAL_DIR}/elastic_scaling" --test="0002-elastic-scaling-doesnt-break-parachains.zndsl" -zombienet-polkadot-functional-0012-spam-statement-distribution-requests: +.zombienet-polkadot-functional-0012-spam-statement-distribution-requests: extends: - .zombienet-polkadot-common script: @@ -209,13 +218,40 @@ zombienet-polkadot-functional-0015-coretime-shared-core: extends: - .zombienet-polkadot-common before_script: - - !reference [.zombienet-polkadot-common, before_script] + - !reference [ .zombienet-polkadot-common, before_script ] - cp --remove-destination ${LOCAL_DIR}/assign-core.js ${LOCAL_DIR}/functional script: - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh --local-dir="${LOCAL_DIR}/functional" --test="0015-coretime-shared-core.zndsl" +zombienet-polkadot-functional-0016-approval-voting-parallel: + extends: + - .zombienet-polkadot-common + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh + --local-dir="${LOCAL_DIR}/functional" + --test="0016-approval-voting-parallel.zndsl" + +zombienet-polkadot-functional-0017-sync-backing: + extends: + - .zombienet-polkadot-common + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh + --local-dir="${LOCAL_DIR}/functional" + --test="0017-sync-backing.zndsl" + +zombienet-polkadot-functional-0018-shared-core-idle-parachain: + extends: + - .zombienet-polkadot-common + before_script: + - !reference [ .zombienet-polkadot-common, before_script ] + - cp --remove-destination ${LOCAL_DIR}/assign-core.js ${LOCAL_DIR}/functional + script: + - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh + --local-dir="${LOCAL_DIR}/functional" + --test="0018-shared-core-idle-parachain.zndsl" + zombienet-polkadot-smoke-0001-parachains-smoke-test: extends: - .zombienet-polkadot-common @@ -260,7 +296,7 @@ zombienet-polkadot-smoke-0002-parachains-parachains-upgrade-smoke: --local-dir="${LOCAL_DIR}/smoke" --test="0002-parachains-upgrade-smoke-test.zndsl" -zombienet-polkadot-smoke-0003-deregister-register-validator: +.zombienet-polkadot-smoke-0003-deregister-register-validator: extends: - .zombienet-polkadot-common script: @@ -276,6 +312,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 @@ -327,3 +371,18 @@ zombienet-polkadot-malus-0001-dispute-valid: - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh --local-dir="${LOCAL_DIR}/integrationtests" --test="0001-dispute-valid-block.zndsl" + +.zombienet-polkadot-coretime-revenue: + extends: + - .zombienet-polkadot-common + needs: + - job: build-polkadot-zombienet-tests + artifacts: true + before_script: + - !reference [ ".zombienet-polkadot-common", "before_script" ] + - export POLKADOT_IMAGE="${ZOMBIENET_INTEGRATION_TEST_IMAGE}" + script: + # we want to use `--no-capture` in zombienet tests. + - unset NEXTEST_FAILURE_OUTPUT + - unset NEXTEST_SUCCESS_OUTPUT + - cargo nextest run --archive-file ./artifacts/polkadot-zombienet-tests.tar.zst --no-capture -- smoke::coretime_revenue::coretime_revenue_test diff --git a/.gitlab/pipeline/zombienet/substrate.yml b/.gitlab/pipeline/zombienet/substrate.yml index 2013ffd571cf..52118307e6a0 100644 --- a/.gitlab/pipeline/zombienet/substrate.yml +++ b/.gitlab/pipeline/zombienet/substrate.yml @@ -38,7 +38,9 @@ after_script: - mkdir -p ./zombienet-logs - cp /tmp/zombie*/logs/* ./zombienet-logs/ - retry: 2 + retry: + max: 1 + when: runner_system_failure tags: - zombienet-polkadot-integration-test @@ -72,7 +74,7 @@ zombienet-substrate-0002-validators-warp-sync: extends: - .zombienet-substrate-warp-sync-common before_script: - - !reference [.zombienet-substrate-warp-sync-common, before_script] + - !reference [ .zombienet-substrate-warp-sync-common, before_script ] - cp --remove-destination ${LOCAL_DIR}/0001-basic-warp-sync/chain-spec.json ${LOCAL_DIR}/0002-validators-warp-sync script: - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh @@ -83,7 +85,7 @@ zombienet-substrate-0003-block-building-warp-sync: extends: - .zombienet-substrate-warp-sync-common before_script: - - !reference [.zombienet-substrate-warp-sync-common, before_script] + - !reference [ .zombienet-substrate-warp-sync-common, before_script ] - cp --remove-destination ${LOCAL_DIR}/0001-basic-warp-sync/chain-spec.json ${LOCAL_DIR}/0003-block-building-warp-sync script: - /home/nonroot/zombie-net/scripts/ci/run-test-local-env-manager.sh diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 120000 index 000000000000..63b2a0dc1abc --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1 @@ +docs/contributor/CODE_OF_CONDUCT.md \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 120000 index 000000000000..0f645512e8e4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1 @@ +docs/contributor/CONTRIBUTING.md \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 160e7031af70..a42f5baa4765 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -77,6 +77,15 @@ dependencies = [ "subtle 2.5.0", ] +[[package]] +name = "affix" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e7ea84d3fa2009f355f8429a0b418a96849135a4188fadf384f59127d5d4bc" +dependencies = [ + "convert_case 0.5.0", +] + [[package]] name = "ahash" version = "0.7.8" @@ -157,9 +166,9 @@ dependencies = [ "dunce", "heck 0.4.1", "proc-macro-error", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", "syn-solidity", "tiny-keccak", ] @@ -262,9 +271,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" @@ -284,9 +293,9 @@ dependencies = [ "include_dir", "itertools 0.10.5", "proc-macro-error", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -484,7 +493,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.37", "syn 1.0.109", ] @@ -494,7 +503,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.37", "syn 1.0.109", ] @@ -506,7 +515,7 @@ checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" dependencies = [ "num-bigint", "num-traits", - "quote 1.0.35", + "quote 1.0.37", "syn 1.0.109", ] @@ -518,8 +527,8 @@ checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ "num-bigint", "num-traits", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -580,7 +589,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", @@ -620,8 +629,8 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -649,14 +658,14 @@ 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", "ark-std 0.4.0", "digest 0.10.7", - "rand_core", - "sha3", + "rand_core 0.6.4", + "sha3 0.10.8", ] [[package]] @@ -680,6 +689,12 @@ dependencies = [ "nodrop", ] +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "arrayvec" version = "0.7.4" @@ -724,8 +739,8 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", "synstructure 0.12.6", ] @@ -736,9 +751,9 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", "synstructure 0.13.1", ] @@ -748,8 +763,8 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -759,16 +774,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[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", @@ -790,12 +805,14 @@ name = "asset-hub-rococo-emulated-chain" version = "0.0.0" dependencies = [ "asset-hub-rococo-runtime", + "bp-bridge-hub-rococo", "cumulus-primitives-core", "emulated-integration-tests-common", "frame-support", "parachains-common", "rococo-emulated-chain", - "sp-core", + "sp-core 28.0.0", + "sp-keyring", "staging-xcm", "testnet-parachains-constants", ] @@ -821,9 +838,11 @@ dependencies = [ "polkadot-runtime-common", "rococo-runtime-constants", "rococo-system-emulated-network", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "staging-xcm", "staging-xcm-executor", + "xcm-runtime-apis", ] [[package]] @@ -883,23 +902,25 @@ dependencies = [ "parity-scale-codec", "polkadot-parachain-primitives", "polkadot-runtime-common", - "primitive-types", + "primitive-types 0.13.1", "rococo-runtime-constants", "scale-info", + "serde_json", "snowbridge-router-primitives", - "sp-api", + "sp-api 26.0.0", "sp-block-builder", "sp-consensus-aura", - "sp-core", + "sp-core 28.0.0", "sp-genesis-builder", "sp-inherents", + "sp-keyring", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-storage 19.0.0", "sp-transaction-pool", - "sp-version", - "sp-weights", + "sp-version 29.0.0", + "sp-weights 27.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -914,11 +935,13 @@ name = "asset-hub-westend-emulated-chain" version = "0.0.0" dependencies = [ "asset-hub-westend-runtime", + "bp-bridge-hub-westend", "cumulus-primitives-core", "emulated-integration-tests-common", "frame-support", "parachains-common", - "sp-core", + "sp-core 28.0.0", + "sp-keyring", "staging-xcm", "testnet-parachains-constants", "westend-emulated-chain", @@ -947,9 +970,8 @@ dependencies = [ "parachains-common", "parity-scale-codec", "polkadot-runtime-common", - "sp-core", - "sp-keyring", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "staging-xcm", "staging-xcm-executor", "westend-system-emulated-network", @@ -1014,20 +1036,24 @@ dependencies = [ "parity-scale-codec", "polkadot-parachain-primitives", "polkadot-runtime-common", - "primitive-types", + "primitive-types 0.13.1", "scale-info", - "sp-api", + "serde_json", + "snowbridge-router-primitives", + "sp-api 26.0.0", "sp-block-builder", "sp-consensus-aura", - "sp-core", + "sp-core 28.0.0", "sp-genesis-builder", "sp-inherents", + "sp-keyring", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", + "sp-std 14.0.0", "sp-storage 19.0.0", "sp-transaction-pool", - "sp-version", + "sp-version 29.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -1058,8 +1084,8 @@ dependencies = [ "parachains-common", "parachains-runtimes-test-utils", "parity-scale-codec", - "sp-io", - "sp-runtime", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -1076,12 +1102,13 @@ dependencies = [ "impl-trait-for-tuples", "log", "pallet-asset-conversion", + "pallet-assets", "pallet-xcm", "parachains-common", "parity-scale-codec", "scale-info", - "sp-api", - "sp-runtime", + "sp-api 26.0.0", + "sp-runtime 31.0.1", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -1094,7 +1121,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.37", "syn 1.0.109", ] @@ -1109,6 +1136,19 @@ dependencies = [ "futures-core", ] +[[package]] +name = "async-channel" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f2776ead772134d55b62dd45e59a79e21612d85d0af729b8b7d3967d601a62a" +dependencies = [ + "concurrent-queue", + "event-listener 5.2.0", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + [[package]] name = "async-executor" version = "1.5.1" @@ -1135,13 +1175,24 @@ dependencies = [ "futures-lite 1.13.0", ] +[[package]] +name = "async-fs" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +dependencies = [ + "async-lock 3.4.0", + "blocking", + "futures-lite 2.3.0", +] + [[package]] name = "async-global-executor" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" dependencies = [ - "async-channel", + "async-channel 1.9.0", "async-executor", "async-io 1.13.0", "async-lock 2.8.0", @@ -1183,7 +1234,7 @@ dependencies = [ "futures-lite 2.3.0", "parking", "polling 3.4.0", - "rustix 0.38.21", + "rustix 0.38.25", "slab", "tracing", "windows-sys 0.52.0", @@ -1221,6 +1272,17 @@ dependencies = [ "futures-lite 1.13.0", ] +[[package]] +name = "async-net" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" +dependencies = [ + "async-io 2.3.3", + "blocking", + "futures-lite 2.3.0", +] + [[package]] name = "async-process" version = "1.7.0" @@ -1239,6 +1301,43 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "async-process" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +dependencies = [ + "async-channel 2.3.0", + "async-io 2.3.3", + "async-lock 3.4.0", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener 5.2.0", + "futures-lite 2.3.0", + "rustix 0.38.25", + "tracing", +] + +[[package]] +name = "async-signal" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb3634b73397aa844481f814fad23bbf07fdb0eabec10f2eb95e58944b1ec32" +dependencies = [ + "async-io 2.3.3", + "async-lock 3.4.0", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix 0.38.25", + "signal-hook-registry", + "slab", + "windows-sys 0.52.0", +] + [[package]] name = "async-std" version = "1.12.0" @@ -1246,7 +1345,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" dependencies = [ "async-attributes", - "async-channel", + "async-channel 1.9.0", "async-global-executor", "async-io 1.13.0", "async-lock 2.8.0", @@ -1283,26 +1382,26 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] name = "async-task" -version = "4.4.0" +version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -1359,8 +1458,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" dependencies = [ "proc-macro-error", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -1383,9 +1482,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 +1498,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,10 +1507,8 @@ dependencies = [ "ark-serialize 0.4.2", "ark-std 0.4.0", "dleq_vrf", - "fflonk", - "merlin", "rand_chacha", - "rand_core", + "rand_core 0.6.4", "ring 0.1.0", "sha2 0.10.8", "sp-ark-bls12-381", @@ -1431,6 +1528,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +[[package]] +name = "base58" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6107fe1be6682a68940da878d9e9f5e90ca5745b3dec9fd1bb393c8777d4f581" + [[package]] name = "base64" version = "0.13.1" @@ -1439,9 +1542,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.2" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" @@ -1478,11 +1581,12 @@ name = "binary-merkle-tree" version = "13.0.0" dependencies = [ "array-bytes", - "env_logger 0.11.3", "hash-db", "log", - "sp-core", - "sp-runtime", + "parity-scale-codec", + "sp-core 28.0.0", + "sp-runtime 31.0.1", + "sp-tracing 16.0.0", ] [[package]] @@ -1506,13 +1610,29 @@ dependencies = [ "lazy_static", "lazycell", "peeking_take_while", - "prettyplease 0.2.12", - "proc-macro2 1.0.82", - "quote 1.0.35", + "prettyplease", + "proc-macro2 1.0.86", + "quote 1.0.37", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "shlex", - "syn 2.0.61", + "syn 2.0.82", +] + +[[package]] +name = "bip32" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa13fae8b6255872fd86f7faf4b41168661d7d78609f7bfe6771b85c6739a15b" +dependencies = [ + "bs58", + "hmac 0.12.1", + "k256", + "rand_core 0.6.4", + "ripemd", + "sha2 0.10.8", + "subtle 2.5.0", + "zeroize", ] [[package]] @@ -1621,13 +1741,35 @@ dependencies = [ [[package]] name = "blake2b_simd" -version = "1.0.1" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" +dependencies = [ + "arrayref", + "arrayvec 0.5.2", + "constant_time_eq 0.1.5", +] + +[[package]] +name = "blake2b_simd" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" +checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" dependencies = [ "arrayref", "arrayvec 0.7.4", - "constant_time_eq 0.2.6", + "constant_time_eq 0.3.0", +] + +[[package]] +name = "blake2s_simd" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e461a7034e85b211a4acb57ee2e6730b32912b06c08cc242243c39fc21ae6a2" +dependencies = [ + "arrayref", + "arrayvec 0.5.2", + "constant_time_eq 0.1.5", ] [[package]] @@ -1643,9 +1785,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.0" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" dependencies = [ "arrayref", "arrayvec 0.7.4", @@ -1660,6 +1802,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ + "block-padding", "generic-array 0.14.7", ] @@ -1672,13 +1815,19 @@ dependencies = [ "generic-array 0.14.7", ] +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + [[package]] name = "blocking" version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77231a1c8f801696fc0123ec6150ce92cffb8e164a02afb9c8ddee0e9b65ad65" dependencies = [ - "async-channel", + "async-channel 1.9.0", "async-lock 2.8.0", "async-task", "atomic-waker", @@ -1742,7 +1891,7 @@ dependencies = [ "scale-info", "serde", "sp-consensus-beefy", - "sp-runtime", + "sp-runtime 31.0.1", "sp-std 14.0.0", ] @@ -1756,7 +1905,7 @@ dependencies = [ "frame-support", "frame-system", "polkadot-primitives", - "sp-api", + "sp-api 26.0.0", "sp-std 14.0.0", ] @@ -1768,8 +1917,8 @@ dependencies = [ "bp-messages", "bp-runtime", "frame-support", - "sp-api", - "sp-runtime", + "sp-api 26.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", ] @@ -1781,8 +1930,8 @@ dependencies = [ "bp-messages", "bp-runtime", "frame-support", - "sp-api", - "sp-runtime", + "sp-api 26.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", ] @@ -1793,9 +1942,11 @@ dependencies = [ "bp-bridge-hub-cumulus", "bp-messages", "bp-runtime", + "bp-xcm-bridge-hub", "frame-support", - "sp-api", - "sp-runtime", + "parity-scale-codec", + "sp-api 26.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", ] @@ -1806,9 +1957,11 @@ dependencies = [ "bp-bridge-hub-cumulus", "bp-messages", "bp-runtime", + "bp-xcm-bridge-hub", "frame-support", - "sp-api", - "sp-runtime", + "parity-scale-codec", + "sp-api 26.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", ] @@ -1826,8 +1979,8 @@ dependencies = [ "scale-info", "serde", "sp-consensus-grandpa", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", ] @@ -1839,7 +1992,7 @@ dependencies = [ "bp-polkadot-core", "bp-runtime", "frame-support", - "sp-api", + "sp-api 26.0.0", "sp-std 14.0.0", ] @@ -1855,7 +2008,8 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-std 14.0.0", ] @@ -1870,8 +2024,8 @@ dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", "scale-info", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", ] @@ -1883,7 +2037,7 @@ dependencies = [ "bp-polkadot-core", "bp-runtime", "frame-support", - "sp-api", + "sp-api 26.0.0", "sp-std 14.0.0", ] @@ -1899,8 +2053,8 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-api", - "sp-runtime", + "sp-api 26.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", ] @@ -1914,11 +2068,10 @@ dependencies = [ "frame-system", "hex", "parity-scale-codec", - "parity-util-mem", "scale-info", "serde", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", ] @@ -1926,14 +2079,18 @@ dependencies = [ name = "bp-relayers" version = "0.7.0" dependencies = [ + "bp-header-chain", "bp-messages", + "bp-parachains", "bp-runtime", "frame-support", + "frame-system", "hex", "hex-literal", + "pallet-utility", "parity-scale-codec", "scale-info", - "sp-runtime", + "sp-runtime 31.0.1", "sp-std 14.0.0", ] @@ -1945,7 +2102,7 @@ dependencies = [ "bp-polkadot-core", "bp-runtime", "frame-support", - "sp-api", + "sp-api 26.0.0", "sp-std 14.0.0", ] @@ -1963,13 +2120,13 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core", - "sp-io", - "sp-runtime", - "sp-state-machine", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "sp-std 14.0.0", - "sp-trie", - "trie-db", + "sp-trie 29.0.0", + "trie-db 0.29.1", ] [[package]] @@ -1983,12 +2140,12 @@ dependencies = [ "ed25519-dalek", "finality-grandpa", "parity-scale-codec", - "sp-application-crypto", + "sp-application-crypto 30.0.0", "sp-consensus-grandpa", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", - "sp-trie", + "sp-trie 29.0.0", ] [[package]] @@ -1999,7 +2156,7 @@ dependencies = [ "bp-polkadot-core", "bp-runtime", "frame-support", - "sp-api", + "sp-api 26.0.0", "sp-std 14.0.0", ] @@ -2007,7 +2164,16 @@ dependencies = [ name = "bp-xcm-bridge-hub" version = "0.2.0" dependencies = [ + "bp-messages", + "bp-runtime", + "frame-support", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-std 14.0.0", + "staging-xcm", ] [[package]] @@ -2016,8 +2182,9 @@ version = "0.6.0" dependencies = [ "parity-scale-codec", "scale-info", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", + "staging-xcm", ] [[package]] @@ -2030,8 +2197,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "snowbridge-core", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", + "sp-std 14.0.0", "staging-xcm", ] @@ -2039,12 +2207,15 @@ dependencies = [ name = "bridge-hub-rococo-emulated-chain" version = "0.0.0" dependencies = [ + "bp-messages", "bridge-hub-common", "bridge-hub-rococo-runtime", "emulated-integration-tests-common", "frame-support", "parachains-common", - "sp-core", + "sp-core 28.0.0", + "sp-keyring", + "staging-xcm", "testnet-parachains-constants", ] @@ -2062,6 +2233,7 @@ dependencies = [ "pallet-bridge-messages", "pallet-message-queue", "pallet-xcm", + "pallet-xcm-bridge-hub", "parachains-common", "parity-scale-codec", "rococo-system-emulated-network", @@ -2072,11 +2244,12 @@ dependencies = [ "snowbridge-pallet-outbound-queue", "snowbridge-pallet-system", "snowbridge-router-primitives", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "staging-xcm", "staging-xcm-executor", "testnet-parachains-constants", + "xcm-runtime-apis", ] [[package]] @@ -2111,6 +2284,7 @@ dependencies = [ "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", + "frame-metadata-hash-extension", "frame-support", "frame-system", "frame-system-benchmarking", @@ -2143,6 +2317,7 @@ dependencies = [ "rococo-runtime-constants", "scale-info", "serde", + "serde_json", "snowbridge-beacon-primitives", "snowbridge-core", "snowbridge-outbound-queue-runtime-api", @@ -2154,26 +2329,25 @@ dependencies = [ "snowbridge-runtime-common", "snowbridge-runtime-test-common", "snowbridge-system-runtime-api", - "sp-api", + "sp-api 26.0.0", "sp-block-builder", "sp-consensus-aura", - "sp-core", + "sp-core 28.0.0", "sp-genesis-builder", "sp-inherents", - "sp-io", + "sp-io 30.0.0", "sp-keyring", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-std 14.0.0", "sp-storage 19.0.0", "sp-transaction-pool", - "sp-version", + "sp-version 29.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", - "static_assertions", "substrate-wasm-builder", "testnet-parachains-constants", "xcm-runtime-apis", @@ -2186,10 +2360,12 @@ dependencies = [ "asset-test-utils", "bp-header-chain", "bp-messages", + "bp-parachains", "bp-polkadot-core", "bp-relayers", "bp-runtime", "bp-test-utils", + "bp-xcm-bridge-hub", "bridge-runtime-common", "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", @@ -2204,13 +2380,15 @@ dependencies = [ "pallet-bridge-relayers", "pallet-timestamp", "pallet-utility", + "pallet-xcm", + "pallet-xcm-bridge-hub", "parachains-common", "parachains-runtimes-test-utils", "parity-scale-codec", - "sp-core", - "sp-io", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-keyring", - "sp-runtime", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", "staging-xcm", "staging-xcm-builder", @@ -2221,12 +2399,15 @@ dependencies = [ name = "bridge-hub-westend-emulated-chain" version = "0.0.0" dependencies = [ + "bp-messages", "bridge-hub-common", "bridge-hub-westend-runtime", "emulated-integration-tests-common", "frame-support", "parachains-common", - "sp-core", + "sp-core 28.0.0", + "sp-keyring", + "staging-xcm", "testnet-parachains-constants", ] @@ -2234,26 +2415,41 @@ 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", "pallet-bridge-messages", "pallet-message-queue", "pallet-xcm", + "pallet-xcm-bridge-hub", "parachains-common", + "parity-scale-codec", "rococo-westend-system-emulated-network", - "sp-runtime", + "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 28.0.0", + "sp-runtime 31.0.1", "staging-xcm", "staging-xcm-executor", + "testnet-parachains-constants", + "xcm-runtime-apis", ] [[package]] name = "bridge-hub-westend-runtime" -version = "0.2.0" +version = "0.3.0" dependencies = [ "bp-asset-hub-rococo", "bp-asset-hub-westend", @@ -2281,6 +2477,7 @@ dependencies = [ "cumulus-primitives-utility", "frame-benchmarking", "frame-executive", + "frame-metadata-hash-extension", "frame-support", "frame-system", "frame-system-benchmarking", @@ -2312,26 +2509,37 @@ dependencies = [ "polkadot-runtime-common", "scale-info", "serde", - "sp-api", + "serde_json", + "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 26.0.0", "sp-block-builder", "sp-consensus-aura", - "sp-core", + "sp-core 28.0.0", "sp-genesis-builder", "sp-inherents", - "sp-io", + "sp-io 30.0.0", "sp-keyring", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-std 14.0.0", "sp-storage 19.0.0", "sp-transaction-pool", - "sp-version", + "sp-version 29.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", - "static_assertions", "substrate-wasm-builder", "testnet-parachains-constants", "westend-runtime-constants", @@ -2350,7 +2558,6 @@ dependencies = [ "bp-runtime", "bp-test-utils", "bp-xcm-bridge-hub", - "bp-xcm-bridge-hub-router", "frame-support", "frame-system", "log", @@ -2363,28 +2570,24 @@ dependencies = [ "pallet-utility", "parity-scale-codec", "scale-info", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", - "sp-trie", + "sp-trie 29.0.0", + "sp-weights 27.0.0", "staging-xcm", - "staging-xcm-builder", "static_assertions", "tuplex", ] [[package]] name = "bs58" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -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 = [ + "sha2 0.10.8", "tinyvec", ] @@ -2434,15 +2637,15 @@ checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "bzip2-sys" @@ -2465,6 +2668,25 @@ dependencies = [ "ppv-lite86", ] +[[package]] +name = "calm_io" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ea0608700fe42d90ec17ad0f86335cf229b67df2e34e7f463e8241ce7b8fa5f" +dependencies = [ + "calmio_filters", +] + +[[package]] +name = "calmio_filters" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "846501f4575cd66766a40bb7ab6d8e960adc7eb49f753c8232bd8e0e09cf6ca2" +dependencies = [ + "quote 1.0.37", + "syn 1.0.109", +] + [[package]] name = "camino" version = "1.1.6" @@ -2511,12 +2733,13 @@ checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" [[package]] name = "cc" -version = "1.0.83" +version = "1.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" dependencies = [ "jobserver", "libc", + "shlex", ] [[package]] @@ -2555,6 +2778,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chacha" version = "0.3.0" @@ -2605,11 +2834,11 @@ dependencies = [ "scale-info", "serde", "serde_json", - "sp-application-crypto", - "sp-core", + "sp-application-crypto 30.0.0", + "sp-core 28.0.0", "sp-genesis-builder", "sp-keyring", - "sp-runtime", + "sp-runtime 31.0.1", "staging-chain-spec-builder", "substrate-wasm-builder", ] @@ -2624,6 +2853,7 @@ dependencies = [ "iana-time-zone", "js-sys", "num-traits", + "serde", "wasm-bindgen", "windows-targets 0.48.5", ] @@ -2655,6 +2885,17 @@ dependencies = [ "half", ] +[[package]] +name = "cid" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8709d481fb78b9808f34a1b4b4fadd08a15a0971052c18bc2b751faefaed595e" +dependencies = [ + "multibase 0.8.0", + "multihash 0.11.4", + "unsigned-varint 0.3.3", +] + [[package]] name = "cid" version = "0.9.0" @@ -2662,7 +2903,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9b68e3193982cd54187d71afdb2a271ad4cf8af157858e9cb911b91321de143" dependencies = [ "core2", - "multibase", + "multibase 0.9.1", "multihash 0.17.0", "serde", "unsigned-varint 0.7.2", @@ -2675,7 +2916,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd94671561e36e4e7de75f753f577edafb0e7c05d6e4547229fdf7938fbcd2c3" dependencies = [ "core2", - "multibase", + "multibase 0.9.1", "multihash 0.18.1", "serde", "unsigned-varint 0.7.2", @@ -2755,12 +2996,12 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.3" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" +checksum = "0fbb260a053428790f3de475e304ff84cdbc4face759ea7a3e64c1edd938a7fc" dependencies = [ "clap_builder", - "clap_derive 4.5.3", + "clap_derive 4.5.13", ] [[package]] @@ -2774,24 +3015,24 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "64b17d7ea74e9f833c7dbf2cbe4fb12ff26783eda4782a8975b72f895c9b4d99" dependencies = [ "anstream", "anstyle", "clap_lex 0.7.0", - "strsim 0.11.0", + "strsim 0.11.1", "terminal_size", ] [[package]] name = "clap_complete" -version = "4.4.0" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "586a385f7ef2f8b4d86bddaa0c094794e7ccbfe5ffef1f434fe928143fc783a5" +checksum = "aa3c596da3cf0983427b0df0dba359df9182c13bd5b519b585a482b0c351f4e8" dependencies = [ - "clap 4.5.3", + "clap 4.5.13", ] [[package]] @@ -2802,21 +3043,21 @@ checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" dependencies = [ "heck 0.4.1", "proc-macro-error", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] [[package]] name = "clap_derive" -version = "4.5.3" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck 0.5.0", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -2865,7 +3106,7 @@ dependencies = [ "emulated-integration-tests-common", "frame-support", "parachains-common", - "sp-core", + "sp-core 28.0.0", "testnet-parachains-constants", ] @@ -2884,11 +3125,12 @@ dependencies = [ "pallet-message-queue", "pallet-treasury", "pallet-utility", + "pallet-whitelist", "pallet-xcm", "parachains-common", "parity-scale-codec", "polkadot-runtime-common", - "sp-runtime", + "sp-runtime 31.0.1", "staging-xcm", "staging-xcm-executor", "testnet-parachains-constants", @@ -2948,20 +3190,23 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-runtime-common", "scale-info", - "sp-api", - "sp-arithmetic", + "serde_json", + "sp-api 26.0.0", + "sp-arithmetic 23.0.0", "sp-block-builder", "sp-consensus-aura", - "sp-core", + "sp-core 28.0.0", "sp-genesis-builder", "sp-inherents", - "sp-io", + "sp-io 30.0.0", + "sp-keyring", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", + "sp-std 14.0.0", "sp-storage 19.0.0", "sp-transaction-pool", - "sp-version", + "sp-version 29.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -2974,9 +3219,9 @@ dependencies = [ [[package]] name = "color-eyre" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" +checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" dependencies = [ "backtrace", "eyre", @@ -3001,8 +3246,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d51beaa537d73d2d1ff34ee70bc095f170420ab2ec5d687ecd3ec2b0d092514b" dependencies = [ "nom", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -3047,7 +3292,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", @@ -3067,22 +3312,58 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101" [[package]] -name = "concurrent-queue" -version = "2.2.0" +name = "comparable" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" +checksum = "eb513ee8037bf08c5270ecefa48da249f4c58e57a71ccfce0a5b0877d2a20eb2" dependencies = [ - "crossbeam-utils", + "comparable_derive", + "comparable_helper", + "pretty_assertions", + "serde", ] [[package]] -name = "console" -version = "0.15.8" +name = "comparable_derive" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "a54b9c40054eb8999c5d1d36fdc90e4e5f7ff0d1d9621706f360b3cbc8beb828" dependencies = [ - "encode_unicode", - "lazy_static", + "convert_case 0.4.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 1.0.109", +] + +[[package]] +name = "comparable_helper" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5437e327e861081c91270becff184859f706e3e50f5301a9d4dc8eb50752c3" +dependencies = [ + "convert_case 0.6.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 1.0.109", +] + +[[package]] +name = "concurrent-queue" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", "libc", "unicode-width", "windows-sys 0.52.0", @@ -3206,18 +3487,18 @@ dependencies = [ "polkadot-runtime-common", "rococo-runtime-constants", "scale-info", - "sp-api", + "sp-api 26.0.0", "sp-block-builder", "sp-consensus-aura", - "sp-core", + "sp-core 28.0.0", "sp-genesis-builder", "sp-inherents", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-storage 19.0.0", "sp-transaction-pool", - "sp-version", + "sp-version 29.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -3233,6 +3514,21 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "convert_case" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4a24b1aaf0fd0ce8b45161144d6f42cd91677fd5940fd431183eb023b3a2b8" + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -3258,6 +3554,39 @@ dependencies = [ "memchr", ] +[[package]] +name = "coretime-rococo-emulated-chain" +version = "0.1.0" +dependencies = [ + "coretime-rococo-runtime", + "cumulus-primitives-core", + "emulated-integration-tests-common", + "frame-support", + "parachains-common", + "sp-core 28.0.0", + "testnet-parachains-constants", +] + +[[package]] +name = "coretime-rococo-integration-tests" +version = "0.0.0" +dependencies = [ + "cumulus-pallet-parachain-system", + "emulated-integration-tests-common", + "frame-support", + "pallet-balances", + "pallet-broker", + "pallet-identity", + "pallet-message-queue", + "polkadot-runtime-common", + "polkadot-runtime-parachains", + "rococo-runtime-constants", + "rococo-system-emulated-network", + "sp-runtime 31.0.1", + "staging-xcm", + "staging-xcm-executor", +] + [[package]] name = "coretime-rococo-runtime" version = "0.1.0" @@ -3288,6 +3617,7 @@ dependencies = [ "pallet-collator-selection", "pallet-message-queue", "pallet-multisig", + "pallet-proxy", "pallet-session", "pallet-sudo", "pallet-timestamp", @@ -3303,18 +3633,18 @@ dependencies = [ "rococo-runtime-constants", "scale-info", "serde", - "sp-api", + "sp-api 26.0.0", "sp-block-builder", "sp-consensus-aura", - "sp-core", + "sp-core 28.0.0", "sp-genesis-builder", "sp-inherents", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-storage 19.0.0", "sp-transaction-pool", - "sp-version", + "sp-version 29.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -3324,6 +3654,39 @@ dependencies = [ "xcm-runtime-apis", ] +[[package]] +name = "coretime-westend-emulated-chain" +version = "0.1.0" +dependencies = [ + "coretime-westend-runtime", + "cumulus-primitives-core", + "emulated-integration-tests-common", + "frame-support", + "parachains-common", + "sp-core 28.0.0", + "testnet-parachains-constants", +] + +[[package]] +name = "coretime-westend-integration-tests" +version = "0.0.0" +dependencies = [ + "cumulus-pallet-parachain-system", + "emulated-integration-tests-common", + "frame-support", + "pallet-balances", + "pallet-broker", + "pallet-identity", + "pallet-message-queue", + "polkadot-runtime-common", + "polkadot-runtime-parachains", + "sp-runtime 31.0.1", + "staging-xcm", + "staging-xcm-executor", + "westend-runtime-constants", + "westend-system-emulated-network", +] + [[package]] name = "coretime-westend-runtime" version = "0.1.0" @@ -3354,6 +3717,7 @@ dependencies = [ "pallet-collator-selection", "pallet-message-queue", "pallet-multisig", + "pallet-proxy", "pallet-session", "pallet-timestamp", "pallet-transaction-payment", @@ -3367,18 +3731,18 @@ dependencies = [ "polkadot-runtime-common", "scale-info", "serde", - "sp-api", + "sp-api 26.0.0", "sp-block-builder", "sp-consensus-aura", - "sp-core", + "sp-core 28.0.0", "sp-genesis-builder", "sp-inherents", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-storage 19.0.0", "sp-transaction-pool", - "sp-version", + "sp-version 29.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -3524,21 +3888,6 @@ dependencies = [ "wasmtime-types", ] -[[package]] -name = "crc" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2b432c56615136f8dba245fed7ec3d5518c500a31108661067e61e72fe7e6bc" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - [[package]] name = "crc32fast" version = "1.3.2" @@ -3557,7 +3906,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.5.3", + "clap 4.5.13", "criterion-plot", "futures", "is-terminal", @@ -3642,7 +3991,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" dependencies = [ "generic-array 0.14.7", - "rand_core", + "rand_core 0.6.4", "subtle 2.5.0", "zeroize", ] @@ -3654,7 +4003,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array 0.14.7", - "rand_core", + "rand_core 0.6.4", "typenum", ] @@ -3691,15 +4040,15 @@ dependencies = [ name = "cumulus-client-cli" version = "0.7.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.13", "parity-scale-codec", "sc-chain-spec", "sc-cli", "sc-client-api", "sc-service", "sp-blockchain", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "url", ] @@ -3723,12 +4072,12 @@ dependencies = [ "polkadot-overseer", "polkadot-primitives", "sc-client-api", - "sp-api", + "sp-api 26.0.0", "sp-consensus", - "sp-core", - "sp-maybe-compressed-blob", - "sp-runtime", - "sp-state-machine", + "sp-core 28.0.0", + "sp-maybe-compressed-blob 11.0.0", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "sp-tracing 16.0.0", "tracing", ] @@ -3750,6 +4099,7 @@ dependencies = [ "parking_lot 0.12.3", "polkadot-node-primitives", "polkadot-node-subsystem", + "polkadot-node-subsystem-util", "polkadot-overseer", "polkadot-primitives", "sc-client-api", @@ -3760,17 +4110,17 @@ dependencies = [ "sc-telemetry", "sc-utils", "schnellru", - "sp-api", - "sp-application-crypto", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", "sp-block-builder", "sp-blockchain", "sp-consensus", "sp-consensus-aura", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-keystore", - "sp-runtime", - "sp-state-machine", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "sp-timestamp", "substrate-prometheus-endpoint", "tokio", @@ -3800,12 +4150,12 @@ dependencies = [ "sp-blockchain", "sp-consensus", "sp-consensus-slots", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "sp-timestamp", "sp-tracing 16.0.0", - "sp-trie", - "sp-version", + "sp-trie 29.0.0", + "sp-version 29.0.0", "substrate-prometheus-endpoint", "tracing", ] @@ -3819,8 +4169,8 @@ dependencies = [ "cumulus-primitives-parachain-inherent", "sp-consensus", "sp-inherents", - "sp-runtime", - "sp-state-machine", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "thiserror", ] @@ -3835,13 +4185,13 @@ dependencies = [ "futures", "parking_lot 0.12.3", "sc-consensus", - "sp-api", + "sp-api 26.0.0", "sp-block-builder", "sp-blockchain", "sp-consensus", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-runtime", + "sp-runtime 31.0.1", "substrate-prometheus-endpoint", "tracing", ] @@ -3868,15 +4218,15 @@ dependencies = [ "rstest", "sc-cli", "sc-client-api", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", "sp-consensus", - "sp-core", + "sp-core 28.0.0", "sp-keyring", - "sp-keystore", - "sp-runtime", - "sp-state-machine", - "sp-version", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", + "sp-version 29.0.0", "substrate-test-utils", "tokio", "tracing", @@ -3894,13 +4244,13 @@ dependencies = [ "cumulus-test-relay-sproof-builder", "parity-scale-codec", "sc-client-api", - "sp-api", - "sp-crypto-hashing", + "sp-api 26.0.0", + "sp-crypto-hashing 0.1.0", "sp-inherents", - "sp-runtime", - "sp-state-machine", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "sp-storage 19.0.0", - "sp-trie", + "sp-trie 29.0.0", "tracing", ] @@ -3928,13 +4278,13 @@ dependencies = [ "sc-client-api", "sc-consensus", "sc-utils", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", "sp-consensus", - "sp-maybe-compressed-blob", - "sp-runtime", + "sp-maybe-compressed-blob 11.0.0", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", - "sp-version", + "sp-version 29.0.0", "substrate-test-utils", "tokio", "tracing", @@ -3967,12 +4317,12 @@ dependencies = [ "sc-telemetry", "sc-transaction-pool", "sc-utils", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", "sp-consensus", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-transaction-pool", ] @@ -3987,9 +4337,9 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-application-crypto", + "sp-application-crypto 30.0.0", "sp-consensus-aura", - "sp-runtime", + "sp-runtime 31.0.1", ] [[package]] @@ -4003,9 +4353,9 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", "staging-xcm", ] @@ -4030,7 +4380,6 @@ dependencies = [ "futures", "hex-literal", "impl-trait-for-tuples", - "lazy_static", "log", "pallet-message-queue", "parity-scale-codec", @@ -4041,21 +4390,21 @@ dependencies = [ "sc-client-api", "scale-info", "sp-consensus-slots", - "sp-core", - "sp-crypto-hashing", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", "sp-externalities 0.25.0", "sp-inherents", - "sp-io", + "sp-io 30.0.0", "sp-keyring", - "sp-runtime", - "sp-state-machine", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "sp-std 14.0.0", "sp-tracing 16.0.0", - "sp-trie", - "sp-version", + "sp-trie 29.0.0", + "sp-version 29.0.0", "staging-xcm", "staging-xcm-builder", - "trie-db", + "trie-db 0.29.1", "trie-standardmap", ] @@ -4064,9 +4413,9 @@ name = "cumulus-pallet-parachain-system-proc-macro" version = "0.6.0" dependencies = [ "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -4078,7 +4427,7 @@ dependencies = [ "frame-system", "pallet-session", "parity-scale-codec", - "sp-runtime", + "sp-runtime 31.0.1", ] [[package]] @@ -4092,7 +4441,7 @@ dependencies = [ "parity-scale-codec", "polkadot-primitives", "scale-info", - "sp-runtime", + "sp-runtime 31.0.1", ] [[package]] @@ -4104,8 +4453,8 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-io", - "sp-runtime", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "staging-xcm", ] @@ -4127,9 +4476,9 @@ dependencies = [ "polkadot-runtime-common", "polkadot-runtime-parachains", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -4145,20 +4494,34 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-runtime", + "sp-runtime 31.0.1", "staging-xcm", ] [[package]] -name = "cumulus-primitives-aura" -version = "0.7.0" +name = "cumulus-pov-validator" +version = "0.1.0" dependencies = [ + "anyhow", + "clap 4.5.13", "parity-scale-codec", - "polkadot-core-primitives", + "polkadot-node-primitives", + "polkadot-parachain-primitives", "polkadot-primitives", - "sp-api", + "sc-executor 0.32.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-maybe-compressed-blob 11.0.0", + "tracing", + "tracing-subscriber 0.3.18", +] + +[[package]] +name = "cumulus-primitives-aura" +version = "0.7.0" +dependencies = [ + "sp-api 26.0.0", "sp-consensus-aura", - "sp-runtime", ] [[package]] @@ -4170,9 +4533,9 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-primitives", "scale-info", - "sp-api", - "sp-runtime", - "sp-trie", + "sp-api 26.0.0", + "sp-runtime 31.0.1", + "sp-trie 29.0.0", "staging-xcm", ] @@ -4184,23 +4547,21 @@ dependencies = [ "cumulus-primitives-core", "parity-scale-codec", "scale-info", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-runtime", - "sp-state-machine", - "sp-trie", + "sp-trie 29.0.0", ] [[package]] name = "cumulus-primitives-proof-size-hostfunction" version = "0.2.0" dependencies = [ - "sp-core", + "sp-core 28.0.0", "sp-externalities 0.25.0", - "sp-io", + "sp-io 30.0.0", "sp-runtime-interface 24.0.0", - "sp-state-machine", - "sp-trie", + "sp-state-machine 0.35.0", + "sp-trie 29.0.0", ] [[package]] @@ -4211,14 +4572,15 @@ dependencies = [ "cumulus-primitives-proof-size-hostfunction", "cumulus-test-runtime", "docify", + "frame-benchmarking", "frame-support", "frame-system", "log", "parity-scale-codec", "scale-info", - "sp-io", - "sp-runtime", - "sp-trie", + "sp-io 30.0.0", + "sp-runtime 31.0.1", + "sp-trie 29.0.0", ] [[package]] @@ -4226,8 +4588,6 @@ name = "cumulus-primitives-timestamp" version = "0.7.0" dependencies = [ "cumulus-primitives-core", - "futures", - "parity-scale-codec", "sp-inherents", "sp-timestamp", ] @@ -4242,9 +4602,7 @@ dependencies = [ "pallet-asset-conversion", "parity-scale-codec", "polkadot-runtime-common", - "polkadot-runtime-parachains", - "sp-io", - "sp-runtime", + "sp-runtime 31.0.1", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -4270,12 +4628,12 @@ dependencies = [ "sc-sysinfo", "sc-telemetry", "sc-tracing", - "sp-api", + "sp-api 26.0.0", "sp-consensus", - "sp-core", + "sp-core 28.0.0", "sp-keyring", - "sp-runtime", - "sp-state-machine", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", ] [[package]] @@ -4285,14 +4643,14 @@ dependencies = [ "async-trait", "cumulus-primitives-core", "futures", - "jsonrpsee-core", + "jsonrpsee-core 0.24.3", "parity-scale-codec", "polkadot-overseer", "sc-client-api", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", - "sp-state-machine", - "sp-version", + "sp-state-machine 0.35.0", + "sp-version 29.0.0", "thiserror", ] @@ -4320,11 +4678,11 @@ dependencies = [ "sc-service", "sc-tracing", "sc-utils", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", "sp-consensus", "sp-consensus-babe", - "sp-runtime", + "sp-runtime 31.0.1", "substrate-prometheus-endpoint", "tokio", "tracing", @@ -4340,10 +4698,12 @@ dependencies = [ "either", "futures", "futures-timer", - "jsonrpsee", + "jsonrpsee 0.24.3", "parity-scale-codec", "pin-project", "polkadot-overseer", + "portpicker", + "prometheus", "rand", "sc-client-api", "sc-rpc-api", @@ -4351,16 +4711,17 @@ dependencies = [ "schnellru", "serde", "serde_json", - "smoldot", - "smoldot-light", - "sp-api", + "smoldot 0.11.0", + "smoldot-light 0.9.0", + "sp-api 26.0.0", "sp-authority-discovery", "sp-consensus-babe", - "sp-core", - "sp-runtime", - "sp-state-machine", + "sp-core 28.0.0", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "sp-storage 19.0.0", - "sp-version", + "sp-version 29.0.0", + "substrate-prometheus-endpoint", "thiserror", "tokio", "tokio-util", @@ -4388,19 +4749,19 @@ dependencies = [ "sc-block-builder", "sc-consensus", "sc-consensus-aura", - "sc-executor", - "sc-executor-common", + "sc-executor 0.32.0", + "sc-executor-common 0.29.0", "sc-service", - "sp-api", - "sp-application-crypto", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", "sp-blockchain", "sp-consensus-aura", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-io", + "sp-io 30.0.0", "sp-keyring", - "sp-keystore", - "sp-runtime", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", "sp-timestamp", "substrate-test-client", ] @@ -4412,9 +4773,9 @@ dependencies = [ "cumulus-primitives-core", "parity-scale-codec", "polkadot-primitives", - "sp-runtime", - "sp-state-machine", - "sp-trie", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", + "sp-trie 29.0.0", ] [[package]] @@ -4442,18 +4803,18 @@ dependencies = [ "pallet-transaction-payment", "parity-scale-codec", "scale-info", - "sp-api", + "sp-api 26.0.0", "sp-block-builder", "sp-consensus-aura", - "sp-core", + "sp-core 28.0.0", "sp-genesis-builder", "sp-inherents", - "sp-io", + "sp-io 30.0.0", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-transaction-pool", - "sp-version", + "sp-version 29.0.0", "staging-parachain-info", "substrate-wasm-builder", ] @@ -4463,7 +4824,7 @@ name = "cumulus-test-service" version = "0.1.0" dependencies = [ "async-trait", - "clap 4.5.3", + "clap 4.5.13", "criterion", "cumulus-client-cli", "cumulus-client-collator", @@ -4486,7 +4847,7 @@ dependencies = [ "frame-system", "frame-system-rpc-runtime-api", "futures", - "jsonrpsee", + "jsonrpsee 0.24.3", "pallet-timestamp", "pallet-transaction-payment", "parachains-common", @@ -4498,6 +4859,7 @@ dependencies = [ "polkadot-service", "polkadot-test-service", "portpicker", + "prometheus", "rand", "sc-basic-authorship", "sc-block-builder", @@ -4506,9 +4868,9 @@ dependencies = [ "sc-client-api", "sc-consensus", "sc-consensus-aura", - "sc-executor", - "sc-executor-common", - "sc-executor-wasmtime", + "sc-executor 0.32.0", + "sc-executor-common 0.29.0", + "sc-executor-wasmtime 0.29.0", "sc-network", "sc-service", "sc-telemetry", @@ -4517,17 +4879,17 @@ dependencies = [ "sc-transaction-pool-api", "serde", "serde_json", - "sp-api", - "sp-arithmetic", + "sp-api 26.0.0", + "sp-arithmetic 23.0.0", "sp-authority-discovery", "sp-blockchain", "sp-consensus", "sp-consensus-aura", - "sp-core", - "sp-io", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-keyring", - "sp-runtime", - "sp-state-machine", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "sp-timestamp", "sp-tracing 16.0.0", "substrate-test-client", @@ -4569,6 +4931,19 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle 2.5.0", + "zeroize", +] + [[package]] name = "curve25519-dalek" version = "4.1.3" @@ -4591,9 +4966,9 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -4604,7 +4979,7 @@ checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8" dependencies = [ "byteorder", "digest 0.9.0", - "rand_core", + "rand_core 0.6.4", "subtle-ng", "zeroize", ] @@ -4630,10 +5005,10 @@ dependencies = [ "cc", "codespan-reporting", "once_cell", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "scratch", - "syn 2.0.61", + "syn 2.0.82", ] [[package]] @@ -4648,9 +5023,79 @@ version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50c49547d73ba8dcfd4ad7325d64c6d5391ff4224d498fc39a6f3f49825a530d" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core 0.20.10", + "darling_macro 0.20.10", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2 1.0.86", + "quote 1.0.37", + "strsim 0.10.0", + "syn 1.0.109", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2 1.0.86", + "quote 1.0.37", + "strsim 0.11.1", + "syn 2.0.82", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core 0.14.4", + "quote 1.0.37", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core 0.20.10", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -4660,7 +5105,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edd72493923899c6f10c641bdbdeddc7183d6396641d99c1a0d1597f37f92e28" dependencies = [ "cfg-if", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "lock_api", "once_cell", "parking_lot_core 0.9.8", @@ -4741,9 +5186,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" @@ -4751,8 +5199,8 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -4762,9 +5210,20 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d65d7ce8132b7c0e54497a4d9a55a1c2a0912a0d786cf894472ba818fba45762" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", +] + +[[package]] +name = "derive-where" +version = "1.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -4773,9 +5232,9 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -4784,9 +5243,9 @@ version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ - "convert_case", - "proc-macro2 1.0.82", - "quote 1.0.35", + "convert_case 0.4.0", + "proc-macro2 1.0.86", + "quote 1.0.37", "rustc_version 0.4.0", "syn 1.0.109", ] @@ -4881,9 +5340,9 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -4895,7 +5354,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", @@ -4941,15 +5400,24 @@ dependencies = [ "common-path", "derive-syn-parse", "once_cell", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "regex", - "syn 2.0.61", + "syn 2.0.82", "termcolor", - "toml 0.8.8", + "toml 0.8.12", "walkdir", ] +[[package]] +name = "document-features" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0" +dependencies = [ + "litrs", +] + [[package]] name = "downcast" version = "0.11.0" @@ -4990,8 +5458,8 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "558e40ea573c374cf53507fd240b7ee2f5477df7cfebdb97323ec61c719399c5" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -5032,35 +5500,49 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 4.1.3", "ed25519", - "rand_core", + "rand_core 0.6.4", "serde", "sha2 0.10.8", "subtle 2.5.0", "zeroize", ] +[[package]] +name = "ed25519-zebra" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c24f403d068ad0b359e577a77f92392118be3f3c927538f2bb544a5ecd828c6" +dependencies = [ + "curve25519-dalek 3.2.0", + "hashbrown 0.12.3", + "hex", + "rand_core 0.6.4", + "sha2 0.9.9", + "zeroize", +] + [[package]] name = "ed25519-zebra" version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d9ce6874da5d4415896cd45ffbc4d1cfc0c4f9c079427bd870742c30f2f65a9" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 4.1.3", "ed25519", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "hex", - "rand_core", + "rand_core 0.6.4", "sha2 0.10.8", "zeroize", ] [[package]] name = "either" -version = "1.9.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "elliptic-curve" @@ -5075,7 +5557,7 @@ dependencies = [ "generic-array 0.14.7", "group", "pkcs8", - "rand_core", + "rand_core 0.6.4", "sec1", "serdect", "subtle 2.5.0", @@ -5088,6 +5570,7 @@ version = "3.0.0" dependencies = [ "asset-test-utils", "bp-messages", + "bp-xcm-bridge-hub", "bridge-runtime-common", "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", @@ -5098,6 +5581,7 @@ dependencies = [ "pallet-bridge-messages", "pallet-message-queue", "pallet-xcm", + "pallet-xcm-bridge-hub", "parachains-common", "parity-scale-codec", "paste", @@ -5108,8 +5592,9 @@ dependencies = [ "sp-authority-discovery", "sp-consensus-babe", "sp-consensus-beefy", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-keyring", + "sp-runtime 31.0.1", "staging-xcm", "xcm-emulator", ] @@ -5136,8 +5621,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -5148,9 +5633,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -5168,20 +5653,20 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[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", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -5299,9 +5784,9 @@ dependencies = [ [[package]] name = "ethabi-decode" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d398648d65820a727d6a81e58b962f874473396a047e4c30bafe3240953417" +checksum = "f9af52ec57c5147716872863c2567c886e7d62f539465b94352dbc0108fe5293" dependencies = [ "ethereum-types", "tiny-keccak", @@ -5309,33 +5794,33 @@ dependencies = [ [[package]] name = "ethbloom" -version = "0.13.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +checksum = "8c321610643004cf908ec0f5f2aa0d8f1f8e14b540562a2887a1111ff1ecbf7b" dependencies = [ "crunchy", "fixed-hash", - "impl-codec", + "impl-codec 0.7.0", "impl-rlp", - "impl-serde", + "impl-serde 0.5.0", "scale-info", "tiny-keccak", ] [[package]] name = "ethereum-types" -version = "0.14.1" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +checksum = "1ab15ed80916029f878e0267c3a9f92b67df55e79af370bf66199059ae2b4ee3" dependencies = [ "ethbloom", "fixed-hash", - "impl-codec", + "impl-codec 0.7.0", "impl-rlp", - "impl-serde", - "primitive-types", + "impl-serde 0.5.0", + "primitive-types 0.13.1", "scale-info", - "uint", + "uint 0.10.0", ] [[package]] @@ -5344,6 +5829,16 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "event-listener" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" +dependencies = [ + "concurrent-queue", + "pin-project-lite", +] + [[package]] name = "event-listener" version = "5.2.0" @@ -5383,10 +5878,10 @@ dependencies = [ "blake2 0.10.6", "file-guard", "fs-err", - "prettyplease 0.2.12", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "prettyplease", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -5456,9 +5951,9 @@ dependencies = [ "expander", "indexmap 2.2.3", "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -5493,7 +5988,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core", + "rand_core 0.6.4", "subtle 2.5.0", ] @@ -5592,6 +6087,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "finito" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2384245d85162258a14b43567a9ee3598f5ae746a1581fb5d3d2cb780f0dbf95" +dependencies = [ + "futures-timer", + "pin-project", +] + [[package]] name = "fixed-hash" version = "0.8.0" @@ -5707,12 +6212,12 @@ dependencies = [ "rusty-fork", "scale-info", "serde", - "sp-api", - "sp-application-crypto", - "sp-core", - "sp-io", - "sp-keystore", - "sp-runtime", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", "sp-runtime-interface 24.0.0", "sp-storage 19.0.0", "static_assertions", @@ -5725,7 +6230,7 @@ dependencies = [ "Inflector", "array-bytes", "chrono", - "clap 4.5.3", + "clap 4.5.13", "comfy-table", "frame-benchmarking", "frame-support", @@ -5733,7 +6238,6 @@ dependencies = [ "gethostname", "handlebars", "itertools 0.11.0", - "lazy_static", "linked-hash-map", "log", "parity-scale-codec", @@ -5744,24 +6248,24 @@ dependencies = [ "sc-cli", "sc-client-api", "sc-client-db", - "sc-executor", + "sc-executor 0.32.0", "sc-service", "sc-sysinfo", "serde", "serde_json", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", - "sp-core", + "sp-core 28.0.0", "sp-database", "sp-externalities 0.25.0", "sp-genesis-builder", "sp-inherents", - "sp-io", - "sp-keystore", - "sp-runtime", - "sp-state-machine", + "sp-io 30.0.0", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "sp-storage 19.0.0", - "sp-trie", + "sp-trie 29.0.0", "sp-wasm-interface 20.0.0", "thiserror", "thousands", @@ -5776,8 +6280,8 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-io", - "sp-runtime", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -5788,11 +6292,11 @@ dependencies = [ "frame-support", "parity-scale-codec", "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "scale-info", - "sp-arithmetic", - "syn 2.0.61", + "sp-arithmetic 23.0.0", + "syn 2.0.82", "trybuild", ] @@ -5806,18 +6310,18 @@ dependencies = [ "parity-scale-codec", "rand", "scale-info", - "sp-arithmetic", - "sp-core", - "sp-io", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-npos-elections", - "sp-runtime", + "sp-runtime 31.0.1", ] [[package]] name = "frame-election-solution-type-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.5.3", + "clap 4.5.13", "frame-election-provider-solution-type", "frame-election-provider-support", "frame-support", @@ -5825,9 +6329,9 @@ dependencies = [ "parity-scale-codec", "rand", "scale-info", - "sp-arithmetic", + "sp-arithmetic 23.0.0", "sp-npos-elections", - "sp-runtime", + "sp-runtime 31.0.1", ] [[package]] @@ -5844,12 +6348,23 @@ dependencies = [ "pallet-transaction-payment", "parity-scale-codec", "scale-info", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-io", - "sp-runtime", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", - "sp-version", + "sp-version 29.0.0", +] + +[[package]] +name = "frame-metadata" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "878babb0b136e731cc77ec2fd883ff02745ff21e6fb662729953d44923df009c" +dependencies = [ + "cfg-if", + "parity-scale-codec", + "scale-info", ] [[package]] @@ -5869,16 +6384,17 @@ name = "frame-metadata-hash-extension" version = "0.1.0" dependencies = [ "array-bytes", + "const-hex", "docify", - "frame-metadata", + "frame-metadata 16.0.0", "frame-support", "frame-system", "log", "merkleized-metadata", "parity-scale-codec", "scale-info", - "sp-api", - "sp-runtime", + "sp-api 26.0.0", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", "sp-transaction-pool", "substrate-test-runtime-client", @@ -5889,14 +6405,14 @@ dependencies = [ name = "frame-omni-bencher" version = "0.1.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.13", "cumulus-primitives-proof-size-hostfunction", - "env_logger 0.11.3", "frame-benchmarking-cli", "log", "sc-cli", - "sp-runtime", + "sp-runtime 31.0.1", "sp-statement-store", + "tracing-subscriber 0.3.18", ] [[package]] @@ -5905,15 +6421,15 @@ version = "0.35.0" dependencies = [ "futures", "indicatif", - "jsonrpsee", + "jsonrpsee 0.24.3", "log", "parity-scale-codec", "serde", - "sp-core", - "sp-crypto-hashing", - "sp-io", - "sp-runtime", - "sp-state-machine", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "sp-tracing 16.0.0", "spinners", "substrate-rpc-client", @@ -5928,10 +6444,11 @@ dependencies = [ "aquamarine", "array-bytes", "assert_matches", + "binary-merkle-tree", "bitflags 1.3.2", "docify", "environmental", - "frame-metadata", + "frame-metadata 16.0.0", "frame-support-procedural", "frame-system", "impl-trait-for-tuples", @@ -5945,23 +6462,24 @@ dependencies = [ "serde", "serde_json", "smallvec", - "sp-api", - "sp-arithmetic", - "sp-core", - "sp-crypto-hashing", - "sp-crypto-hashing-proc-macro", + "sp-api 26.0.0", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", + "sp-crypto-hashing-proc-macro 0.1.0", "sp-debug-derive 14.0.0", "sp-genesis-builder", "sp-inherents", - "sp-io", - "sp-metadata-ir", - "sp-runtime", + "sp-io 30.0.0", + "sp-metadata-ir 0.6.0", + "sp-runtime 31.0.1", "sp-staking", - "sp-state-machine", + "sp-state-machine 0.35.0", "sp-std 14.0.0", "sp-timestamp", "sp-tracing 16.0.0", - "sp-weights", + "sp-trie 29.0.0", + "sp-weights 27.0.0", "static_assertions", "tt-call", ] @@ -5973,17 +6491,28 @@ 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", + "proc-macro2 1.0.86", + "quote 1.0.37", "regex", - "sp-crypto-hashing", - "syn 2.0.61", -] + "scale-info", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", + "sp-io 30.0.0", + "sp-metadata-ir 0.6.0", + "sp-runtime 31.0.1", + "static_assertions", + "syn 2.0.82", +] [[package]] name = "frame-support-procedural-tools" @@ -5991,18 +6520,18 @@ version = "10.0.0" dependencies = [ "frame-support-procedural-tools-derive", "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] name = "frame-support-procedural-tools-derive" version = "11.0.0" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -6011,7 +6540,7 @@ version = "3.0.0" dependencies = [ "frame-benchmarking", "frame-executive", - "frame-metadata", + "frame-metadata 16.0.0", "frame-support", "frame-support-test-pallet", "frame-system", @@ -6020,14 +6549,14 @@ dependencies = [ "rustversion", "scale-info", "serde", - "sp-api", - "sp-arithmetic", - "sp-core", - "sp-io", - "sp-metadata-ir", - "sp-runtime", - "sp-state-machine", - "sp-version", + "sp-api 26.0.0", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-metadata-ir 0.6.0", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", + "sp-version 29.0.0", "static_assertions", "trybuild", ] @@ -6040,9 +6569,9 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-core", - "sp-runtime", - "sp-version", + "sp-core 28.0.0", + "sp-runtime 31.0.1", + "sp-version 29.0.0", ] [[package]] @@ -6054,7 +6583,7 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-runtime", + "sp-runtime 31.0.1", ] [[package]] @@ -6078,13 +6607,13 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core", + "sp-core 28.0.0", "sp-externalities 0.25.0", - "sp-io", - "sp-runtime", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", - "sp-version", - "sp-weights", + "sp-version 29.0.0", + "sp-weights 27.0.0", "substrate-test-runtime-client", ] @@ -6097,11 +6626,11 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-core", + "sp-core 28.0.0", "sp-externalities 0.25.0", - "sp-io", - "sp-runtime", - "sp-version", + "sp-io 30.0.0", + "sp-runtime 31.0.1", + "sp-version 29.0.0", ] [[package]] @@ -6110,7 +6639,7 @@ version = "26.0.0" dependencies = [ "docify", "parity-scale-codec", - "sp-api", + "sp-api 26.0.0", ] [[package]] @@ -6119,8 +6648,8 @@ version = "0.34.0" dependencies = [ "frame-support", "parity-scale-codec", - "sp-api", - "sp-runtime", + "sp-api 26.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -6145,7 +6674,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29f9df8a11882c4e3335eb2d18a0137c505d9ca927470b0cac9c6f0ae07d28f7" dependencies = [ - "rustix 0.38.21", + "rustix 0.38.25", "windows-sys 0.48.0", ] @@ -6241,7 +6770,10 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ + "fastrand 2.1.0", "futures-core", + "futures-io", + "parking", "pin-project-lite", ] @@ -6251,9 +6783,9 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -6283,6 +6815,10 @@ name = "futures-timer" version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +dependencies = [ + "gloo-timers", + "send_wrapper 0.4.0", +] [[package]] name = "futures-util" @@ -6372,7 +6908,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ea1015b5a70616b688dc230cfe50c8af89d972cb132d5a622814d29773b10b9" dependencies = [ "rand", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -6412,6 +6948,33 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "glob-match" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985c9503b412198aa4197559e9a318524ebc4519c229bfa05a535828c950b9d" + +[[package]] +name = "gloo-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06f627b1a58ca3d42b45d6104bf1e1a03799df472df00988b6ba21accc10580" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils", + "http 1.1.0", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "gloo-timers" version = "0.2.6" @@ -6424,6 +6987,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gloo-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "glutton-westend-runtime" version = "3.0.0" @@ -6449,18 +7025,18 @@ dependencies = [ "parachains-common", "parity-scale-codec", "scale-info", - "sp-api", + "sp-api 26.0.0", "sp-block-builder", "sp-consensus-aura", - "sp-core", + "sp-core 28.0.0", "sp-genesis-builder", "sp-inherents", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-storage 19.0.0", "sp-transaction-pool", - "sp-version", + "sp-version 29.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -6494,7 +7070,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core", + "rand_core 0.6.4", "subtle 2.5.0", ] @@ -6591,9 +7167,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash 0.8.11", "allocator-api2", @@ -6606,7 +7182,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -6641,9 +7217,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.2" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -6663,11 +7239,56 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "hickory-proto" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner 0.6.0", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.4.0", + "ipnet", + "once_cell", + "rand", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot 0.12.3", + "rand", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "tracing", +] + [[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", ] @@ -6702,6 +7323,15 @@ dependencies = [ "hmac 0.8.1", ] +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "honggfuzz" version = "0.5.55" @@ -6781,6 +7411,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-range-header" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" + [[package]] name = "httparse" version = "1.8.0" @@ -6876,6 +7512,32 @@ dependencies = [ "tokio", "tokio-rustls 0.26.0", "tower-service", + "webpki-roots 0.26.3", +] + +[[package]] +name = "hyper-timeout" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" +dependencies = [ + "hyper 0.14.29", + "pin-project-lite", + "tokio", + "tokio-io-timeout", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.29", + "native-tls", + "tokio", + "tokio-native-tls", ] [[package]] @@ -6921,6 +7583,12 @@ dependencies = [ "cc", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.2.3" @@ -7009,6 +7677,15 @@ dependencies = [ "parity-scale-codec", ] +[[package]] +name = "impl-codec" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67aa010c1e3da95bf151bd8b4c059b2ed7e75387cdb969b4f8f2723a43f9941" +dependencies = [ + "parity-scale-codec", +] + [[package]] name = "impl-num-traits" version = "0.1.2" @@ -7017,16 +7694,27 @@ checksum = "951641f13f873bff03d4bf19ae8bec531935ac0ac2cc775f84d7edfdcfed3f17" dependencies = [ "integer-sqrt", "num-traits", - "uint", + "uint 0.9.5", +] + +[[package]] +name = "impl-num-traits" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "803d15461ab0dcc56706adf266158acbc44ccf719bf7d0af30705f58b90a4b8c" +dependencies = [ + "integer-sqrt", + "num-traits", + "uint 0.10.0", ] [[package]] name = "impl-rlp" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +checksum = "54ed8ad1f3877f7e775b8cbf30ed1bd3209a95401817f19a0eb4402d13f8cf90" dependencies = [ - "rlp", + "rlp 0.6.1", ] [[package]] @@ -7038,14 +7726,23 @@ dependencies = [ "serde", ] +[[package]] +name = "impl-serde" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a143eada6a1ec4aefa5049037a26a6d597bfd64f8c026d07b77133e02b7dd0b" +dependencies = [ + "serde", +] + [[package]] name = "impl-trait-for-tuples" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -7064,8 +7761,8 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", ] [[package]] @@ -7092,7 +7789,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -7125,19 +7822,13 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] -[[package]] -name = "integer-encoding" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb03732005da905c88227371639bf1ad885cc712789c011c31c5fb3ab3ccf02" - [[package]] name = "integer-sqrt" version = "0.1.5" @@ -7153,7 +7844,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi 0.3.9", "libc", "windows-sys 0.48.0", ] @@ -7173,7 +7864,30 @@ dependencies = [ "socket2 0.5.7", "widestring", "windows-sys 0.48.0", - "winreg", + "winreg 0.50.0", +] + +[[package]] +name = "ipfs-hasher" +version = "0.21.3" +source = "git+https://github.com/chevdor/subwasm?rev=v0.21.3#aa8acb6fdfb34144ac51ab95618a9b37fa251295" +dependencies = [ + "ipfs-unixfs", + "thiserror", +] + +[[package]] +name = "ipfs-unixfs" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67d1cf65363f3d01682283456651d1cea436019de5be7a974bb61716c940d44f" +dependencies = [ + "cid 0.5.1", + "either", + "filetime", + "multihash 0.11.4", + "quick-protobuf 0.7.0", + "sha2 0.9.9", ] [[package]] @@ -7188,8 +7902,8 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi 0.3.2", - "rustix 0.38.21", + "hermit-abi 0.3.9", + "rustix 0.38.25", "windows-sys 0.48.0", ] @@ -7208,7 +7922,7 @@ version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "334e04b4d781f436dc315cb1e7515bd96826426345d498149e4bde36b67f8ee9" dependencies = [ - "async-channel", + "async-channel 1.9.0", "castaway", "crossbeam-utils", "curl", @@ -7247,12 +7961,38 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "jemalloc_pprof" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96368c0fc161a0a1a20b3952b6fd31ee342fffc87ed9e48ac1ed49fb25686655" +dependencies = [ + "anyhow", + "libc", + "mappings", + "once_cell", + "pprof_util", + "tempfile", + "tikv-jemalloc-ctl", + "tokio", + "tracing", +] + [[package]] name = "jni" version = "0.19.0" @@ -7275,9 +8015,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] @@ -7297,6 +8037,30 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" +[[package]] +name = "json-patch" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec9ad60d674508f3ca8f380a928cfe7b096bc729c4e2dbfe3852bc45da3ab30b" +dependencies = [ + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "jsonpath-rust" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06cc127b7c3d270be504572364f9569761a180b981919dd0d87693a7f5fb7829" +dependencies = [ + "pest", + "pest_derive", + "regex", + "serde_json", + "thiserror", +] + [[package]] name = "jsonpath_lib" version = "0.3.0" @@ -7308,20 +8072,66 @@ dependencies = [ "serde_json", ] +[[package]] +name = "jsonrpsee" +version = "0.22.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfdb12a2381ea5b2e68c3469ec604a007b367778cdb14d09612c8069ebd616ad" +dependencies = [ + "jsonrpsee-client-transport 0.22.5", + "jsonrpsee-core 0.22.5", + "jsonrpsee-http-client 0.22.5", + "jsonrpsee-types 0.22.5", +] + [[package]] name = "jsonrpsee" version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62b089779ad7f80768693755a031cc14a7766aba707cbe886674e3f79e9b7e47" dependencies = [ - "jsonrpsee-core", - "jsonrpsee-http-client", + "jsonrpsee-core 0.23.2", + "jsonrpsee-types 0.23.2", + "jsonrpsee-ws-client 0.23.2", +] + +[[package]] +name = "jsonrpsee" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ec465b607a36dc5dd45d48b7689bc83f679f66a3ac6b6b21cc787a11e0f8685" +dependencies = [ + "jsonrpsee-client-transport 0.24.3", + "jsonrpsee-core 0.24.3", + "jsonrpsee-http-client 0.24.3", "jsonrpsee-proc-macros", "jsonrpsee-server", - "jsonrpsee-types", - "jsonrpsee-ws-client", + "jsonrpsee-types 0.24.3", + "jsonrpsee-wasm-client", + "jsonrpsee-ws-client 0.24.3", + "tokio", + "tracing", +] + +[[package]] +name = "jsonrpsee-client-transport" +version = "0.22.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4978087a58c3ab02efc5b07c5e5e2803024536106fd5506f558db172c889b3aa" +dependencies = [ + "futures-util", + "http 0.2.9", + "jsonrpsee-core 0.22.5", + "pin-project", + "rustls-native-certs 0.7.0", + "rustls-pki-types", + "soketto 0.7.1", + "thiserror", "tokio", + "tokio-rustls 0.25.0", + "tokio-util", "tracing", + "url", ] [[package]] @@ -7333,7 +8143,7 @@ dependencies = [ "base64 0.22.1", "futures-util", "http 1.1.0", - "jsonrpsee-core", + "jsonrpsee-core 0.23.2", "pin-project", "rustls 0.23.10", "rustls-pki-types", @@ -7348,27 +8158,47 @@ dependencies = [ ] [[package]] -name = "jsonrpsee-core" -version = "0.23.2" +name = "jsonrpsee-client-transport" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79712302e737d23ca0daa178e752c9334846b08321d439fd89af9a384f8c830b" +checksum = "90f0977f9c15694371b8024c35ab58ca043dbbf4b51ccb03db8858a021241df1" dependencies = [ - "anyhow", - "async-trait", - "beef", - "bytes", - "futures-timer", + "base64 0.22.1", + "futures-channel", "futures-util", + "gloo-net", "http 1.1.0", - "http-body 1.0.0", - "http-body-util", - "jsonrpsee-types", - "parking_lot 0.12.3", + "jsonrpsee-core 0.24.3", "pin-project", - "rand", - "rustc-hash", - "serde", - "serde_json", + "rustls 0.23.10", + "rustls-pki-types", + "rustls-platform-verifier", + "soketto 0.8.0", + "thiserror", + "tokio", + "tokio-rustls 0.26.0", + "tokio-util", + "tracing", + "url", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.22.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b257e1ec385e07b0255dde0b933f948b5c8b8c28d42afda9587c3a967b896d" +dependencies = [ + "anyhow", + "async-trait", + "beef", + "futures-timer", + "futures-util", + "hyper 0.14.29", + "jsonrpsee-types 0.22.5", + "pin-project", + "rustc-hash 1.1.0", + "serde", + "serde_json", "thiserror", "tokio", "tokio-stream", @@ -7376,10 +8206,79 @@ dependencies = [ ] [[package]] -name = "jsonrpsee-http-client" +name = "jsonrpsee-core" version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d90064e04fb9d7282b1c71044ea94d0bbc6eff5621c66f1a0bce9e9de7cf3ac" +checksum = "79712302e737d23ca0daa178e752c9334846b08321d439fd89af9a384f8c830b" +dependencies = [ + "anyhow", + "async-trait", + "beef", + "futures-timer", + "futures-util", + "jsonrpsee-types 0.23.2", + "pin-project", + "rustc-hash 1.1.0", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", + "tracing", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e942c55635fbf5dc421938b8558a8141c7e773720640f4f1dbe1f4164ca4e221" +dependencies = [ + "async-trait", + "bytes", + "futures-timer", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "jsonrpsee-types 0.24.3", + "parking_lot 0.12.3", + "pin-project", + "rand", + "rustc-hash 2.0.0", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "wasm-bindgen-futures", +] + +[[package]] +name = "jsonrpsee-http-client" +version = "0.22.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ccf93fc4a0bfe05d851d37d7c32b7f370fe94336b52a2f0efc5f1981895c2e5" +dependencies = [ + "async-trait", + "hyper 0.14.29", + "hyper-rustls 0.24.2", + "jsonrpsee-core 0.22.5", + "jsonrpsee-types 0.22.5", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "tracing", + "url", +] + +[[package]] +name = "jsonrpsee-http-client" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33774602df12b68a2310b38a535733c477ca4a498751739f89fe8dbbb62ec4c" dependencies = [ "async-trait", "base64 0.22.1", @@ -7387,8 +8286,8 @@ dependencies = [ "hyper 1.3.1", "hyper-rustls 0.27.2", "hyper-util", - "jsonrpsee-core", - "jsonrpsee-types", + "jsonrpsee-core 0.24.3", + "jsonrpsee-types 0.24.3", "rustls 0.23.10", "rustls-platform-verifier", "serde", @@ -7402,32 +8301,31 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.23.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7895f186d5921065d96e16bd795e5ca89ac8356ec423fafc6e3d7cf8ec11aee4" +checksum = "6b07a2daf52077ab1b197aea69a5c990c060143835bf04c77070e98903791715" dependencies = [ "heck 0.5.0", "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] name = "jsonrpsee-server" -version = "0.23.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "654afab2e92e5d88ebd8a39d6074483f3f2bfdf91c5ac57fe285e7127cdd4f51" +checksum = "038fb697a709bec7134e9ccbdbecfea0e2d15183f7140254afef7c5610a3f488" dependencies = [ - "anyhow", "futures-util", "http 1.1.0", "http-body 1.0.0", "http-body-util", "hyper 1.3.1", "hyper-util", - "jsonrpsee-core", - "jsonrpsee-types", + "jsonrpsee-core 0.24.3", + "jsonrpsee-types 0.24.3", "pin-project", "route-recognizer", "serde", @@ -7441,6 +8339,19 @@ dependencies = [ "tracing", ] +[[package]] +name = "jsonrpsee-types" +version = "0.22.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "150d6168405890a7a3231a3c74843f58b8959471f6df76078db2619ddee1d07d" +dependencies = [ + "anyhow", + "beef", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "jsonrpsee-types" version = "0.23.2" @@ -7454,6 +8365,29 @@ dependencies = [ "thiserror", ] +[[package]] +name = "jsonrpsee-types" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b67d6e008164f027afbc2e7bb79662650158d26df200040282d2aa1cbb093b" +dependencies = [ + "http 1.1.0", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "jsonrpsee-wasm-client" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0470d0ae043ffcb0cd323797a631e637fb4b55fe3eaa6002934819458bba62a7" +dependencies = [ + "jsonrpsee-client-transport 0.24.3", + "jsonrpsee-core 0.24.3", + "jsonrpsee-types 0.24.3", +] + [[package]] name = "jsonrpsee-ws-client" version = "0.23.2" @@ -7461,17 +8395,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c28759775f5cb2f1ea9667672d3fe2b0e701d1f4b7b67954e60afe7fd058b5e" dependencies = [ "http 1.1.0", - "jsonrpsee-client-transport", - "jsonrpsee-core", - "jsonrpsee-types", + "jsonrpsee-client-transport 0.23.2", + "jsonrpsee-core 0.23.2", + "jsonrpsee-types 0.23.2", + "url", +] + +[[package]] +name = "jsonrpsee-ws-client" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "992bf67d1132f88edf4a4f8cff474cf01abb2be203004a2b8e11c2b20795b99e" +dependencies = [ + "http 1.1.0", + "jsonrpsee-client-transport 0.24.3", + "jsonrpsee-core 0.24.3", + "jsonrpsee-types 0.24.3", "url", ] [[package]] name = "k256" -version = "0.13.3" +version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ "cfg-if", "ecdsa", @@ -7481,6 +8428,20 @@ dependencies = [ "sha2 0.10.8", ] +[[package]] +name = "k8s-openapi" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edc3606fd16aca7989db2f84bb25684d0270c6d6fa1dbcd0025af7b4130523a6" +dependencies = [ + "base64 0.21.7", + "bytes", + "chrono", + "serde", + "serde-value", + "serde_json", +] + [[package]] name = "keccak" version = "0.1.4" @@ -7490,6 +8451,16 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "keccak-hash" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b286e6b663fb926e1eeb68528e69cb70ed46c6d65871a21b2215ae8154c6d3c" +dependencies = [ + "primitive-types 0.12.2", + "tiny-keccak", +] + [[package]] name = "keccak-hasher" version = "0.16.0" @@ -7517,13 +8488,107 @@ dependencies = [ "pallet-example-tasks", "parity-scale-codec", "polkadot-sdk", - "primitive-types", + "primitive-types 0.13.1", "scale-info", "serde_json", + "sp-debug-derive 14.0.0", "static_assertions", "substrate-wasm-builder", ] +[[package]] +name = "kube" +version = "0.87.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3499c8d60c763246c7a213f51caac1e9033f46026904cb89bc8951ae8601f26e" +dependencies = [ + "k8s-openapi", + "kube-client", + "kube-core", + "kube-runtime", +] + +[[package]] +name = "kube-client" +version = "0.87.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "033450dfa0762130565890dadf2f8835faedf749376ca13345bcd8ecd6b5f29f" +dependencies = [ + "base64 0.21.7", + "bytes", + "chrono", + "either", + "futures", + "home", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.29", + "hyper-rustls 0.24.2", + "hyper-timeout", + "jsonpath-rust", + "k8s-openapi", + "kube-core", + "pem 3.0.4", + "pin-project", + "rand", + "rustls 0.21.7", + "rustls-pemfile 1.0.3", + "secrecy", + "serde", + "serde_json", + "serde_yaml", + "thiserror", + "tokio", + "tokio-tungstenite", + "tokio-util", + "tower", + "tower-http 0.4.4", + "tracing", +] + +[[package]] +name = "kube-core" +version = "0.87.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5bba93d054786eba7994d03ce522f368ef7d48c88a1826faa28478d85fb63ae" +dependencies = [ + "chrono", + "form_urlencoded", + "http 0.2.9", + "json-patch", + "k8s-openapi", + "once_cell", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "kube-runtime" +version = "0.87.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d8893eb18fbf6bb6c80ef6ee7dd11ec32b1dc3c034c988ac1b3a84d46a230ae" +dependencies = [ + "ahash 0.8.11", + "async-trait", + "backoff", + "derivative", + "futures", + "hashbrown 0.14.5", + "json-patch", + "k8s-openapi", + "kube-client", + "parking_lot 0.12.3", + "pin-project", + "serde", + "serde_json", + "smallvec", + "thiserror", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "kv-log-macro" version = "1.0.7" @@ -7588,9 +8653,9 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "lazycell" @@ -7606,9 +8671,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libflate" @@ -7747,7 +8812,7 @@ dependencies = [ "once_cell", "parking_lot 0.12.3", "pin-project", - "quick-protobuf", + "quick-protobuf 0.8.1", "rand", "rw-stream-sink", "smallvec", @@ -7788,7 +8853,7 @@ dependencies = [ "libp2p-swarm", "log", "lru 0.12.3", - "quick-protobuf", + "quick-protobuf 0.8.1", "quick-protobuf-codec", "smallvec", "thiserror", @@ -7797,15 +8862,15 @@ 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", "ed25519-dalek", "hkdf", "multihash 0.19.1", - "quick-protobuf", + "quick-protobuf 0.8.1", "rand", "sha2 0.10.8", "thiserror", @@ -7831,13 +8896,13 @@ dependencies = [ "libp2p-identity", "libp2p-swarm", "log", - "quick-protobuf", + "quick-protobuf 0.8.1", "quick-protobuf-codec", "rand", "sha2 0.10.8", "smallvec", "thiserror", - "uint", + "uint 0.9.5", "unsigned-varint 0.7.2", "void", ] @@ -7887,7 +8952,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2eeec39ad3ad0677551907dd304b2f13f17208ccebe333bef194076cd2e8921" dependencies = [ "bytes", - "curve25519-dalek", + "curve25519-dalek 4.1.3", "futures", "libp2p-core", "libp2p-identity", @@ -7895,7 +8960,7 @@ dependencies = [ "multiaddr 0.18.1", "multihash 0.19.1", "once_cell", - "quick-protobuf", + "quick-protobuf 0.8.1", "rand", "sha2 0.10.8", "snow", @@ -7996,9 +9061,9 @@ checksum = "c4d5ec2a3df00c7836d7696c136274c9c59705bac69133253696a6c932cd1d74" dependencies = [ "heck 0.4.1", "proc-macro-warning 0.4.2", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -8062,7 +9127,7 @@ dependencies = [ "futures", "js-sys", "libp2p-core", - "send_wrapper", + "send_wrapper 0.6.0", "wasm-bindgen", "wasm-bindgen-futures", ] @@ -8223,9 +9288,9 @@ checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "linux-raw-sys" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" +checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" [[package]] name = "lioness" @@ -8259,21 +9324,22 @@ dependencies = [ [[package]] name = "litep2p" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f46c51c205264b834ceed95c8b195026e700494bc3991aaba3b4ea9e20626d9" +checksum = "d4ab2528b02b6dbbc3e6ec4b55ccde885647c622a315b7da45081ed2dfe4b813" dependencies = [ "async-trait", - "bs58 0.4.0", + "bs58", "bytes", "cid 0.10.1", "ed25519-dalek", "futures", "futures-timer", "hex-literal", + "hickory-resolver", "indexmap 2.2.3", "libc", - "mockall 0.12.1", + "mockall 0.13.0", "multiaddr 0.17.1", "multihash 0.17.0", "network-interface", @@ -8281,8 +9347,7 @@ dependencies = [ "parking_lot 0.12.3", "pin-project", "prost 0.12.6", - "prost-build 0.11.9", - "quinn 0.9.4", + "prost-build", "rand", "rcgen", "ring 0.16.20", @@ -8294,24 +9359,27 @@ dependencies = [ "snow", "socket2 0.5.7", "static_assertions", - "str0m", "thiserror", "tokio", "tokio-stream", "tokio-tungstenite", "tokio-util", "tracing", - "trust-dns-resolver", - "uint", + "uint 0.9.5", "unsigned-varint 0.8.0", "url", - "webpki", "x25519-dalek", "x509-parser 0.16.0", "yasna", "zeroize", ] +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + [[package]] name = "lock_api" version = "0.4.10" @@ -8324,23 +9392,14 @@ 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", ] -[[package]] -name = "lru" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6e8aaa3f231bb4bd57b84b2d5dc3ae7f350265df8aa96492e0bc394a1571909" -dependencies = [ - "hashbrown 0.12.3", -] - [[package]] name = "lru" version = "0.11.0" @@ -8353,7 +9412,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" dependencies = [ - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -8411,8 +9470,8 @@ checksum = "cc33f9f0351468d26fbc53d9ce00a096c8522ecb42f19b50f34f2c422f76d21d" dependencies = [ "macro_magic_core", "macro_magic_macros", - "quote 1.0.35", - "syn 2.0.61", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -8424,9 +9483,9 @@ dependencies = [ "const-random", "derive-syn-parse", "macro_magic_core_macros", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -8435,9 +9494,9 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b02abfe41815b5bd98dbd4260173db2c116dda171dc0fe7838cb206333b83308" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -8447,8 +9506,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73ea28ee64b88876bf45277ed9a5817c1817df061a74f2b988971a12570e5869" dependencies = [ "macro_magic_core", - "quote 1.0.35", - "syn 2.0.61", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -8457,6 +9516,19 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" +[[package]] +name = "mappings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fa2605f461115ef6336342b12f0d8cabdfd7b258fed86f5f98c725535843601" +dependencies = [ + "anyhow", + "libc", + "once_cell", + "pprof_util", + "tracing", +] + [[package]] name = "match_cfg" version = "0.1.0" @@ -8499,9 +9571,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" @@ -8565,7 +9637,7 @@ checksum = "f313fcff1d2a4bcaa2deeaa00bf7530d77d5f7bd0467a117dde2e29a75a7a17a" dependencies = [ "array-bytes", "blake3", - "frame-metadata", + "frame-metadata 16.0.0", "parity-scale-codec", "scale-decode", "scale-info", @@ -8579,7 +9651,7 @@ checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" dependencies = [ "byteorder", "keccak", - "rand_core", + "rand_core 0.6.4", "zeroize", ] @@ -8597,18 +9669,8 @@ dependencies = [ "num-traits", "parking_lot 0.12.3", "relay-utils", - "sp-arithmetic", -] - -[[package]] -name = "mick-jaeger" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69672161530e8aeca1d1400fbf3f1a1747ff60ea604265a4e906c2442df20532" -dependencies = [ - "futures", - "rand", - "thrift", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", ] [[package]] @@ -8624,70 +9686,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] -name = "minimal-template" +name = "minimal-template-node" version = "0.0.0" dependencies = [ + "clap 4.5.13", "docify", - "minimal-template-node", + "futures", + "futures-timer", + "jsonrpsee 0.24.3", "minimal-template-runtime", - "pallet-minimal-template", - "polkadot-sdk-docs", - "polkadot-sdk-frame", - "simple-mermaid 0.1.1", -] - -[[package]] -name = "minimal-template-node" -version = "0.0.0" -dependencies = [ - "clap 4.5.3", - "docify", - "futures", - "futures-timer", - "jsonrpsee", - "minimal-template-runtime", - "polkadot-sdk-frame", - "sc-basic-authorship", - "sc-cli", - "sc-client-api", - "sc-consensus", - "sc-consensus-manual-seal", - "sc-executor", - "sc-network", - "sc-offchain", - "sc-rpc-api", - "sc-service", - "sc-telemetry", - "sc-transaction-pool", - "sc-transaction-pool-api", + "polkadot-sdk", "serde_json", - "sp-api", - "sp-block-builder", - "sp-blockchain", - "sp-io", - "sp-keyring", - "sp-runtime", - "sp-timestamp", - "substrate-build-script-utils", - "substrate-frame-rpc-system", ] [[package]] name = "minimal-template-runtime" version = "0.0.0" dependencies = [ - "pallet-balances", "pallet-minimal-template", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", "parity-scale-codec", - "polkadot-sdk-frame", + "polkadot-sdk", "scale-info", - "sp-genesis-builder", - "sp-runtime", - "substrate-wasm-builder", + "serde_json", ] [[package]] @@ -8701,13 +9721,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi 0.3.9", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -8721,7 +9742,7 @@ dependencies = [ "bitflags 1.3.2", "blake2 0.10.6", "c2-chacha", - "curve25519-dalek", + "curve25519-dalek 4.1.3", "either", "hashlink", "lioness", @@ -8746,13 +9767,13 @@ dependencies = [ "sc-block-builder", "sc-client-api", "sc-offchain", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", "sp-consensus", "sp-consensus-beefy", - "sp-core", + "sp-core 28.0.0", "sp-mmr-primitives", - "sp-runtime", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", "substrate-test-runtime-client", "tokio", @@ -8762,15 +9783,15 @@ dependencies = [ name = "mmr-rpc" version = "28.0.0" dependencies = [ - "jsonrpsee", + "jsonrpsee 0.24.3", "parity-scale-codec", "serde", "serde_json", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", - "sp-core", + "sp-core 28.0.0", "sp-mmr-primitives", - "sp-runtime", + "sp-runtime 31.0.1", ] [[package]] @@ -8790,15 +9811,14 @@ dependencies = [ [[package]] name = "mockall" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43766c2b5203b10de348ffe19f7e54564b64f3d6018ff7648d1e2d6d3a0f0a48" +checksum = "d4c28b3fb6d753d28c20e826cd46ee611fda1cf3cde03a443a974043247c065a" dependencies = [ "cfg-if", "downcast", "fragile", - "lazy_static", - "mockall_derive 0.12.1", + "mockall_derive 0.13.0", "predicates 3.0.3", "predicates-tree", ] @@ -8810,21 +9830,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" dependencies = [ "cfg-if", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] [[package]] name = "mockall_derive" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af7cbce79ec385a1d4f54baa90a76401eb15d9cab93685f62e7e9f942aa00ae2" +checksum = "341014e7f530314e9a1fdbc7400b244efea7122662c96bfa248c31da5bfb2020" dependencies = [ "cfg-if", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -8843,7 +9863,7 @@ dependencies = [ "byteorder", "data-encoding", "log", - "multibase", + "multibase 0.9.1", "multihash 0.17.0", "percent-encoding", "serde", @@ -8862,7 +9882,7 @@ dependencies = [ "byteorder", "data-encoding", "libp2p-identity", - "multibase", + "multibase 0.9.1", "multihash 0.19.1", "percent-encoding", "serde", @@ -8871,6 +9891,17 @@ dependencies = [ "url", ] +[[package]] +name = "multibase" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b78c60039650ff12e140ae867ef5299a58e19dded4d334c849dc7177083667e2" +dependencies = [ + "base-x", + "data-encoding", + "data-encoding-macro", +] + [[package]] name = "multibase" version = "0.9.1" @@ -8882,20 +9913,35 @@ dependencies = [ "data-encoding-macro", ] +[[package]] +name = "multihash" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567122ab6492f49b59def14ecc36e13e64dca4188196dd0cd41f9f3f979f3df6" +dependencies = [ + "blake2b_simd 0.5.11", + "blake2s_simd 0.5.11", + "digest 0.9.0", + "sha-1", + "sha2 0.9.9", + "sha3 0.9.1", + "unsigned-varint 0.5.1", +] + [[package]] name = "multihash" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835d6ff01d610179fbce3de1694d007e500bf33a7f29689838941d6bf783ae40" dependencies = [ - "blake2b_simd", - "blake2s_simd", + "blake2b_simd 1.0.2", + "blake2s_simd 1.0.1", "blake3", "core2", "digest 0.10.7", "multihash-derive", "sha2 0.10.8", - "sha3", + "sha3 0.10.8", "unsigned-varint 0.7.2", ] @@ -8905,14 +9951,14 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfd8a792c1694c6da4f68db0a9d707c72bd260994da179e6030a5dcee00bb815" dependencies = [ - "blake2b_simd", - "blake2s_simd", + "blake2b_simd 1.0.2", + "blake2s_simd 1.0.1", "blake3", "core2", "digest 0.10.7", "multihash-derive", "sha2 0.10.8", - "sha3", + "sha3 0.10.8", "unsigned-varint 0.7.2", ] @@ -8934,8 +9980,8 @@ checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro-error", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", "synstructure 0.12.6", ] @@ -8982,8 +10028,8 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -9003,6 +10049,23 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "netlink-packet-core" version = "0.4.2" @@ -9104,6 +10167,17 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "libc", +] + [[package]] name = "nix" version = "0.28.0" @@ -9112,7 +10186,7 @@ checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ "bitflags 2.6.0", "cfg-if", - "cfg_aliases", + "cfg_aliases 0.1.1", "libc", ] @@ -9133,7 +10207,7 @@ name = "node-bench" version = "0.9.0-dev" dependencies = [ "array-bytes", - "clap 4.5.3", + "clap 4.5.13", "derive_more", "fs_extra", "futures", @@ -9141,7 +10215,6 @@ dependencies = [ "kitchensink-runtime", "kvdb", "kvdb-rocksdb", - "lazy_static", "log", "node-primitives", "node-testing", @@ -9154,13 +10227,13 @@ dependencies = [ "serde", "serde_json", "sp-consensus", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-runtime", - "sp-state-machine", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "sp-timestamp", "sp-tracing 16.0.0", - "sp-trie", + "sp-trie 29.0.0", "tempfile", ] @@ -9168,15 +10241,15 @@ dependencies = [ name = "node-primitives" version = "2.0.0" dependencies = [ - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", ] [[package]] name = "node-rpc" version = "3.0.0-dev" dependencies = [ - "jsonrpsee", + "jsonrpsee 0.24.3", "mmr-rpc", "node-primitives", "pallet-transaction-payment-rpc", @@ -9190,19 +10263,17 @@ dependencies = [ "sc-consensus-grandpa-rpc", "sc-mixnet", "sc-rpc", - "sc-rpc-api", - "sc-rpc-spec-v2", "sc-sync-state-rpc", "sc-transaction-pool-api", - "sp-api", - "sp-application-crypto", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", "sp-block-builder", "sp-blockchain", "sp-consensus", "sp-consensus-babe", "sp-consensus-beefy", - "sp-keystore", - "sp-runtime", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", "sp-statement-store", "substrate-frame-rpc-system", "substrate-state-trie-migration-rpc", @@ -9212,7 +10283,7 @@ dependencies = [ name = "node-runtime-generate-bags" version = "3.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.13", "generate-bags", "kitchensink-runtime", ] @@ -9221,7 +10292,7 @@ dependencies = [ name = "node-template-release" version = "3.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.13", "flate2", "fs_extra", "glob", @@ -9246,24 +10317,25 @@ dependencies = [ "pallet-asset-conversion-tx-payment", "pallet-asset-tx-payment", "pallet-assets", + "pallet-revive", "pallet-skip-feeless-payment", "parity-scale-codec", "sc-block-builder", "sc-client-api", "sc-client-db", "sc-consensus", - "sc-executor", + "sc-executor 0.32.0", "sc-service", - "sp-api", + "sp-api 26.0.0", "sp-block-builder", "sp-blockchain", "sp-consensus", - "sp-core", - "sp-crypto-hashing", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", "sp-inherents", - "sp-io", + "sp-io 30.0.0", "sp-keyring", - "sp-runtime", + "sp-runtime 31.0.1", "sp-timestamp", "staging-node-cli", "substrate-test-client", @@ -9363,15 +10435,21 @@ 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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -9433,7 +10511,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi 0.3.9", "libc", ] @@ -9473,6 +10551,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "object" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" +dependencies = [ + "memchr", +] + [[package]] name = "oid-registry" version = "0.6.1" @@ -9536,9 +10623,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -9547,15 +10634,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" -[[package]] -name = "openssl-src" -version = "300.2.3+3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cff92b6f71555b61bb9315f7c64da3ca43d87531622120fea0195fc761b4843" -dependencies = [ - "cc", -] - [[package]] name = "openssl-sys" version = "0.9.102" @@ -9564,7 +10642,6 @@ checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" dependencies = [ "cc", "libc", - "openssl-src", "pkg-config", "vcpkg", ] @@ -9603,16 +10680,16 @@ dependencies = [ "itertools 0.11.0", "petgraph", "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] [[package]] name = "ordered-float" -version = "1.1.1" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3305af35278dd29f46fcdd139e0b1fbfae2153f0e5928b39b035542dd31e37b7" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" dependencies = [ "num-traits", ] @@ -9649,10 +10726,10 @@ dependencies = [ "pallet-identity", "parity-scale-codec", "scale-info", - "sp-core", - "sp-crypto-hashing", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -9666,13 +10743,13 @@ dependencies = [ "pallet-assets", "pallet-balances", "parity-scale-codec", - "primitive-types", + "primitive-types 0.13.1", "scale-info", - "sp-api", - "sp-arithmetic", - "sp-core", - "sp-io", - "sp-runtime", + "sp-api 26.0.0", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -9687,18 +10764,19 @@ dependencies = [ "pallet-assets", "pallet-balances", "parity-scale-codec", - "primitive-types", + "primitive-types 0.13.1", "scale-info", - "sp-arithmetic", - "sp-core", - "sp-io", - "sp-runtime", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] name = "pallet-asset-conversion-tx-payment" version = "10.0.0" dependencies = [ + "frame-benchmarking", "frame-support", "frame-system", "pallet-asset-conversion", @@ -9707,9 +10785,9 @@ dependencies = [ "pallet-transaction-payment", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-storage 19.0.0", ] @@ -9723,9 +10801,9 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -9743,9 +10821,9 @@ dependencies = [ "scale-info", "serde", "serde_json", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-storage 19.0.0", ] @@ -9761,10 +10839,9 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", - "sp-std 14.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -9779,9 +10856,9 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -9793,9 +10870,9 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -9808,11 +10885,11 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-application-crypto", + "sp-application-crypto 30.0.0", "sp-consensus-aura", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -9824,11 +10901,11 @@ dependencies = [ "pallet-session", "parity-scale-codec", "scale-info", - "sp-application-crypto", + "sp-application-crypto 30.0.0", "sp-authority-discovery", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -9840,9 +10917,9 @@ dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -9863,11 +10940,11 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-application-crypto", + "sp-application-crypto 30.0.0", "sp-consensus-babe", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-session", "sp-staking", ] @@ -9886,9 +10963,9 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", ] @@ -9913,8 +10990,8 @@ dependencies = [ "log", "pallet-bags-list", "pallet-staking", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", "sp-storage 19.0.0", "sp-tracing 16.0.0", @@ -9933,9 +11010,9 @@ dependencies = [ "parity-scale-codec", "paste", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -9957,12 +11034,12 @@ dependencies = [ "scale-info", "serde", "sp-consensus-beefy", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-session", "sp-staking", - "sp-state-machine", + "sp-state-machine 0.35.0", ] [[package]] @@ -9971,6 +11048,7 @@ version = "28.0.0" dependencies = [ "array-bytes", "binary-merkle-tree", + "frame-benchmarking", "frame-support", "frame-system", "log", @@ -9980,13 +11058,13 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-api", + "sp-api 26.0.0", "sp-consensus-beefy", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-staking", - "sp-state-machine", + "sp-state-machine 0.35.0", ] [[package]] @@ -10001,9 +11079,9 @@ dependencies = [ "pallet-treasury", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10024,9 +11102,9 @@ dependencies = [ "scale-info", "serde", "sp-consensus-beefy", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", ] @@ -10044,9 +11122,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-consensus-grandpa", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", ] @@ -10066,11 +11144,11 @@ dependencies = [ "pallet-bridge-grandpa", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", - "sp-trie", + "sp-trie 29.0.0", ] [[package]] @@ -10089,9 +11167,9 @@ dependencies = [ "pallet-bridge-grandpa", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", ] @@ -10099,20 +11177,29 @@ dependencies = [ name = "pallet-bridge-relayers" version = "0.7.0" dependencies = [ + "bp-header-chain", "bp-messages", + "bp-parachains", + "bp-polkadot-core", "bp-relayers", "bp-runtime", + "bp-test-utils", "frame-benchmarking", "frame-support", "frame-system", "log", "pallet-balances", + "pallet-bridge-grandpa", "pallet-bridge-messages", + "pallet-bridge-parachains", + "pallet-transaction-payment", + "pallet-utility", "parity-scale-codec", "scale-info", - "sp-arithmetic", - "sp-io", - "sp-runtime", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", ] @@ -10128,11 +11215,11 @@ dependencies = [ "parity-scale-codec", "pretty_assertions", "scale-info", - "sp-api", - "sp-arithmetic", - "sp-core", - "sp-io", - "sp-runtime", + "sp-api 26.0.0", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", ] @@ -10149,9 +11236,9 @@ dependencies = [ "pallet-treasury", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10171,9 +11258,9 @@ dependencies = [ "rand", "scale-info", "sp-consensus-aura", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-staking", "sp-tracing 16.0.0", ] @@ -10182,15 +11269,17 @@ dependencies = [ name = "pallet-collective" version = "28.0.0" dependencies = [ + "docify", "frame-benchmarking", "frame-support", "frame-system", "log", + "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10202,9 +11291,9 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10214,7 +11303,6 @@ dependencies = [ "array-bytes", "assert_matches", "bitflags 1.3.2", - "env_logger 0.11.3", "environmental", "frame-benchmarking", "frame-support", @@ -10239,11 +11327,11 @@ dependencies = [ "scale-info", "serde", "smallvec", - "sp-api", - "sp-core", - "sp-io", - "sp-keystore", - "sp-runtime", + "sp-api 26.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", "sp-tracing 16.0.0", "staging-xcm", @@ -10260,10 +11348,9 @@ dependencies = [ "anyhow", "frame-system", "parity-wasm", - "polkavm-linker", - "sp-runtime", + "sp-runtime 31.0.1", "tempfile", - "toml 0.8.8", + "toml 0.8.12", "twox-hash", ] @@ -10292,11 +11379,11 @@ dependencies = [ "polkadot-runtime-parachains", "pretty_assertions", "scale-info", - "sp-api", - "sp-core", - "sp-io", - "sp-keystore", - "sp-runtime", + "sp-api 26.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", "staging-xcm", "staging-xcm-builder", @@ -10308,9 +11395,9 @@ dependencies = [ name = "pallet-contracts-proc-macro" version = "18.0.0" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -10320,7 +11407,6 @@ dependencies = [ "bitflags 1.3.2", "parity-scale-codec", "paste", - "polkavm-derive", "scale-info", ] @@ -10337,9 +11423,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10353,10 +11439,10 @@ dependencies = [ "pallet-ranked-collective", "parity-scale-codec", "scale-info", - "sp-arithmetic", - "sp-core", - "sp-io", - "sp-runtime", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10368,8 +11454,8 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-io", - "sp-runtime", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10379,6 +11465,7 @@ dependencies = [ "frame-election-provider-support", "frame-support", "frame-system", + "log", "pallet-balances", "pallet-nomination-pools", "pallet-staking", @@ -10386,9 +11473,9 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-staking", "sp-tracing 16.0.0", "substrate-test-utils", @@ -10408,9 +11495,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10423,9 +11510,9 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10446,10 +11533,10 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.3", "scale-info", - "sp-core", - "sp-io", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-npos-elections", - "sp-runtime", + "sp-runtime 31.0.1", "sp-staking", "sp-std 14.0.0", "sp-tracing 16.0.0", @@ -10470,13 +11557,13 @@ dependencies = [ "parking_lot 0.12.3", "rand", "scale-info", - "sp-arithmetic", - "sp-core", - "sp-io", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-npos-elections", - "sp-runtime", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", - "strum 0.26.2", + "strum 0.26.3", ] [[package]] @@ -10488,7 +11575,7 @@ dependencies = [ "frame-system", "parity-scale-codec", "sp-npos-elections", - "sp-runtime", + "sp-runtime 31.0.1", ] [[package]] @@ -10502,15 +11589,33 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-npos-elections", - "sp-runtime", + "sp-runtime 31.0.1", "sp-staking", "sp-tracing 16.0.0", "substrate-test-utils", ] +[[package]] +name = "pallet-example-authorization-tx-extension" +version = "1.0.0" +dependencies = [ + "docify", + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "pallet-verify-signature", + "parity-scale-codec", + "scale-info", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-keyring", + "sp-runtime 31.0.1", +] + [[package]] name = "pallet-example-basic" version = "27.0.0" @@ -10522,9 +11627,9 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10547,9 +11652,9 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10563,7 +11668,7 @@ dependencies = [ "pallet-migrations", "parity-scale-codec", "scale-info", - "sp-io", + "sp-io 30.0.0", ] [[package]] @@ -10576,10 +11681,10 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-keystore", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10595,10 +11700,10 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", - "sp-version", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", + "sp-version 29.0.0", ] [[package]] @@ -10611,8 +11716,8 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", + "sp-core 28.0.0", + "sp-io 30.0.0", ] [[package]] @@ -10625,9 +11730,9 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10636,6 +11741,7 @@ version = "4.0.0-dev" dependencies = [ "pallet-default-config-example", "pallet-dev-mode", + "pallet-example-authorization-tx-extension", "pallet-example-basic", "pallet-example-frame-crate", "pallet-example-kitchensink", @@ -10661,9 +11767,9 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-staking", "sp-tracing 16.0.0", "substrate-test-utils", @@ -10681,10 +11787,10 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-io", - "sp-runtime", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10706,12 +11812,12 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-application-crypto", + "sp-application-crypto 30.0.0", "sp-consensus-grandpa", - "sp-core", - "sp-io", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-keyring", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-staking", ] @@ -10728,10 +11834,10 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-keystore", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10746,10 +11852,10 @@ dependencies = [ "pallet-session", "parity-scale-codec", "scale-info", - "sp-application-crypto", - "sp-core", - "sp-io", - "sp-runtime", + "sp-application-crypto 30.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-staking", ] @@ -10763,10 +11869,10 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-keyring", - "sp-runtime", + "sp-runtime 31.0.1", ] [[package]] @@ -10778,9 +11884,9 @@ dependencies = [ "parity-scale-codec", "safe-mix", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10794,9 +11900,9 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10809,9 +11915,9 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10828,19 +11934,20 @@ dependencies = [ "rand_distr", "scale-info", "serde", - "sp-arithmetic", - "sp-core", - "sp-crypto-hashing", - "sp-io", - "sp-runtime", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", - "sp-weights", + "sp-weights 27.0.0", ] [[package]] name = "pallet-migrations" version = "1.0.0" dependencies = [ + "cfg-if", "docify", "frame-benchmarking", "frame-executive", @@ -10851,13 +11958,13 @@ dependencies = [ "parity-scale-codec", "pretty_assertions", "scale-info", - "sp-api", + "sp-api 26.0.0", "sp-block-builder", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", - "sp-version", + "sp-version 29.0.0", ] [[package]] @@ -10865,7 +11972,7 @@ name = "pallet-minimal-template" version = "0.0.0" dependencies = [ "parity-scale-codec", - "polkadot-sdk-frame", + "polkadot-sdk", "scale-info", ] @@ -10880,11 +11987,11 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-application-crypto", - "sp-arithmetic", - "sp-io", + "sp-application-crypto 30.0.0", + "sp-arithmetic 23.0.0", + "sp-io 30.0.0", "sp-mixnet", - "sp-runtime", + "sp-runtime 31.0.1", ] [[package]] @@ -10892,7 +11999,6 @@ name = "pallet-mmr" version = "27.0.0" dependencies = [ "array-bytes", - "env_logger 0.11.3", "frame-benchmarking", "frame-support", "frame-system", @@ -10900,10 +12006,11 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-mmr-primitives", - "sp-runtime", + "sp-runtime 31.0.1", + "sp-tracing 16.0.0", ] [[package]] @@ -10917,8 +12024,8 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-io", - "sp-runtime", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10934,9 +12041,9 @@ dependencies = [ "pallet-nfts", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", ] @@ -10952,10 +12059,10 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-keystore", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10964,7 +12071,7 @@ version = "14.0.0" dependencies = [ "pallet-nfts", "parity-scale-codec", - "sp-api", + "sp-api 26.0.0", ] [[package]] @@ -10977,10 +12084,10 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-arithmetic", - "sp-core", - "sp-io", - "sp-runtime", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -10992,9 +12099,9 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11007,9 +12114,9 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-staking", "sp-tracing 16.0.0", ] @@ -11031,9 +12138,9 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-runtime-interface 24.0.0", "sp-staking", ] @@ -11048,8 +12155,8 @@ dependencies = [ "log", "pallet-nomination-pools", "rand", - "sp-io", - "sp-runtime", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", ] @@ -11059,7 +12166,7 @@ version = "23.0.0" dependencies = [ "pallet-nomination-pools", "parity-scale-codec", - "sp-api", + "sp-api 26.0.0", ] [[package]] @@ -11079,9 +12186,9 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-staking", "sp-std 14.0.0", "sp-tracing 16.0.0", @@ -11103,9 +12210,9 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-staking", "sp-std 14.0.0", "sp-tracing 16.0.0", @@ -11122,9 +12229,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-staking", ] @@ -11148,9 +12255,9 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-staking", ] @@ -11164,10 +12271,10 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-metadata-ir", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-metadata-ir 0.6.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11178,21 +12285,16 @@ dependencies = [ "frame-support", "honggfuzz", "pallet-paged-list", - "sp-io", + "sp-io 30.0.0", ] [[package]] name = "pallet-parachain-template" version = "0.0.0" dependencies = [ - "frame-benchmarking", - "frame-support", - "frame-system", "parity-scale-codec", + "polkadot-sdk-frame", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", ] [[package]] @@ -11209,9 +12311,9 @@ dependencies = [ "paste", "scale-info", "serde", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11225,9 +12327,9 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11241,9 +12343,9 @@ dependencies = [ "pallet-utility", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11257,10 +12359,10 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-arithmetic", - "sp-core", - "sp-io", - "sp-runtime", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11273,9 +12375,9 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11293,10 +12395,10 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-arithmetic", - "sp-core", - "sp-io", - "sp-runtime", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11309,9 +12411,133 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", +] + +[[package]] +name = "pallet-revive" +version = "0.1.0" +dependencies = [ + "array-bytes", + "assert_matches", + "bitflags 1.3.2", + "derive_more", + "environmental", + "ethereum-types", + "frame-benchmarking", + "frame-support", + "frame-system", + "hex", + "hex-literal", + "impl-trait-for-tuples", + "jsonrpsee 0.24.3", + "log", + "pallet-assets", + "pallet-balances", + "pallet-message-queue", + "pallet-proxy", + "pallet-revive-fixtures", + "pallet-revive-proc-macro", + "pallet-revive-uapi", + "pallet-timestamp", + "pallet-transaction-payment", + "pallet-utility", + "parity-scale-codec", + "paste", + "polkavm 0.13.0", + "polkavm-common 0.13.0", + "pretty_assertions", + "rlp 0.6.1", + "scale-info", + "secp256k1", + "serde", + "serde_json", + "sp-api 26.0.0", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", + "sp-std 14.0.0", + "sp-tracing 16.0.0", + "sp-weights 27.0.0", + "staging-xcm", + "staging-xcm-builder", + "subxt-signer", +] + +[[package]] +name = "pallet-revive-fixtures" +version = "0.1.0" +dependencies = [ + "anyhow", + "frame-system", + "log", + "parity-wasm", + "polkavm-linker 0.13.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", + "tempfile", + "toml 0.8.12", +] + +[[package]] +name = "pallet-revive-mock-network" +version = "0.1.0" +dependencies = [ + "assert_matches", + "frame-support", + "frame-system", + "pallet-assets", + "pallet-balances", + "pallet-message-queue", + "pallet-proxy", + "pallet-revive", + "pallet-revive-fixtures", + "pallet-revive-proc-macro", + "pallet-revive-uapi", + "pallet-timestamp", + "pallet-utility", + "pallet-xcm", + "parity-scale-codec", + "polkadot-parachain-primitives", + "polkadot-primitives", + "polkadot-runtime-parachains", + "pretty_assertions", + "scale-info", + "sp-api 26.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", + "sp-tracing 16.0.0", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", + "xcm-simulator", +] + +[[package]] +name = "pallet-revive-proc-macro" +version = "0.1.0" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", +] + +[[package]] +name = "pallet-revive-uapi" +version = "0.1.0" +dependencies = [ + "bitflags 1.3.2", + "parity-scale-codec", + "paste", + "polkavm-derive 0.13.0", + "scale-info", ] [[package]] @@ -11328,9 +12554,9 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-staking", "sp-std 14.0.0", ] @@ -11343,9 +12569,9 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11361,10 +12587,10 @@ dependencies = [ "pallet-utility", "parity-scale-codec", "scale-info", - "sp-arithmetic", - "sp-core", - "sp-io", - "sp-runtime", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11378,10 +12604,10 @@ dependencies = [ "pallet-ranked-collective", "parity-scale-codec", "scale-info", - "sp-arithmetic", - "sp-core", - "sp-io", - "sp-runtime", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11396,10 +12622,10 @@ dependencies = [ "parity-scale-codec", "scale-info", "sp-consensus-sassafras", - "sp-core", - "sp-crypto-hashing", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11414,10 +12640,10 @@ dependencies = [ "pallet-preimage", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", - "sp-weights", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", + "sp-weights 27.0.0", "substrate-test-utils", ] @@ -11430,9 +12656,9 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11446,13 +12672,13 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-session", "sp-staking", - "sp-state-machine", - "sp-trie", + "sp-state-machine 0.35.0", + "sp-trie 29.0.0", ] [[package]] @@ -11471,9 +12697,9 @@ dependencies = [ "parity-scale-codec", "rand", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-session", ] @@ -11485,7 +12711,7 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-runtime", + "sp-runtime 31.0.1", ] [[package]] @@ -11501,11 +12727,11 @@ dependencies = [ "parity-scale-codec", "rand_chacha", "scale-info", - "sp-arithmetic", - "sp-core", - "sp-crypto-hashing", - "sp-io", - "sp-runtime", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11527,11 +12753,11 @@ dependencies = [ "rand_chacha", "scale-info", "serde", - "sp-application-crypto", - "sp-core", - "sp-io", + "sp-application-crypto 30.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-npos-elections", - "sp-runtime", + "sp-runtime 31.0.1", "sp-staking", "sp-tracing 16.0.0", "substrate-test-utils", @@ -11542,10 +12768,10 @@ name = "pallet-staking-reward-curve" version = "11.0.0" dependencies = [ "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", - "quote 1.0.35", - "sp-runtime", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "sp-runtime 31.0.1", + "syn 2.0.82", ] [[package]] @@ -11553,7 +12779,7 @@ name = "pallet-staking-reward-fn" version = "19.0.0" dependencies = [ "log", - "sp-arithmetic", + "sp-arithmetic 23.0.0", ] [[package]] @@ -11561,7 +12787,7 @@ name = "pallet-staking-runtime-api" version = "14.0.0" dependencies = [ "parity-scale-codec", - "sp-api", + "sp-api 26.0.0", "sp-staking", ] @@ -11579,9 +12805,9 @@ dependencies = [ "parking_lot 0.12.3", "scale-info", "serde", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", "substrate-state-trie-migration-rpc", "thousands", @@ -11599,10 +12825,10 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-api", - "sp-core", - "sp-io", - "sp-runtime", + "sp-api 26.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-statement-store", ] @@ -11616,9 +12842,9 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11630,9 +12856,9 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11646,10 +12872,10 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-io", - "sp-runtime", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-storage 19.0.0", "sp-timestamp", ] @@ -11667,9 +12893,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-storage 19.0.0", ] @@ -11677,6 +12903,7 @@ dependencies = [ name = "pallet-transaction-payment" version = "28.0.0" dependencies = [ + "frame-benchmarking", "frame-support", "frame-system", "pallet-balances", @@ -11684,24 +12911,24 @@ dependencies = [ "scale-info", "serde", "serde_json", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] name = "pallet-transaction-payment-rpc" version = "30.0.0" dependencies = [ - "jsonrpsee", + "jsonrpsee 0.24.3", "pallet-transaction-payment-rpc-runtime-api", "parity-scale-codec", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", - "sp-core", + "sp-core 28.0.0", "sp-rpc", - "sp-runtime", - "sp-weights", + "sp-runtime 31.0.1", + "sp-weights 27.0.0", ] [[package]] @@ -11710,9 +12937,9 @@ version = "28.0.0" dependencies = [ "pallet-transaction-payment", "parity-scale-codec", - "sp-api", - "sp-runtime", - "sp-weights", + "sp-api 26.0.0", + "sp-runtime 31.0.1", + "sp-weights 27.0.0", ] [[package]] @@ -11728,10 +12955,10 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-io", - "sp-runtime", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-transaction-storage-proof", ] @@ -11744,14 +12971,15 @@ dependencies = [ "frame-support", "frame-system", "impl-trait-for-tuples", + "log", "pallet-balances", "pallet-utility", "parity-scale-codec", "scale-info", "serde", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11767,9 +12995,9 @@ dependencies = [ "pallet-utility", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11783,9 +13011,9 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", ] @@ -11802,9 +13030,28 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", +] + +[[package]] +name = "pallet-verify-signature" +version = "1.0.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-balances", + "pallet-collective", + "pallet-root-testing", + "pallet-timestamp", + "parity-scale-codec", + "scale-info", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", + "sp-weights 27.0.0", ] [[package]] @@ -11818,9 +13065,9 @@ dependencies = [ "pallet-balances", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11834,10 +13081,10 @@ dependencies = [ "pallet-preimage", "parity-scale-codec", "scale-info", - "sp-api", - "sp-core", - "sp-io", - "sp-runtime", + "sp-api 26.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -11848,7 +13095,6 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "log", "pallet-assets", "pallet-balances", "parity-scale-codec", @@ -11856,12 +13102,13 @@ dependencies = [ "polkadot-runtime-parachains", "scale-info", "serde", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", + "tracing", "xcm-runtime-apis", ] @@ -11880,8 +13127,8 @@ dependencies = [ "polkadot-primitives", "polkadot-runtime-common", "scale-info", - "sp-io", - "sp-runtime", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", "staging-xcm", "staging-xcm-builder", @@ -11896,17 +13143,18 @@ dependencies = [ "bp-messages", "bp-runtime", "bp-xcm-bridge-hub", - "bridge-runtime-common", "frame-support", "frame-system", "log", "pallet-balances", "pallet-bridge-messages", + "pallet-xcm-bridge-hub-router", "parity-scale-codec", + "polkadot-parachain-primitives", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", "staging-xcm", "staging-xcm-builder", @@ -11924,9 +13172,9 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", "staging-xcm", "staging-xcm-builder", @@ -11936,58 +13184,18 @@ dependencies = [ name = "parachain-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.13", "color-print", - "cumulus-client-cli", - "cumulus-client-collator", - "cumulus-client-consensus-aura", - "cumulus-client-consensus-common", - "cumulus-client-consensus-proposer", - "cumulus-client-service", - "cumulus-primitives-core", - "cumulus-primitives-parachain-inherent", - "cumulus-relay-chain-interface", "docify", - "frame-benchmarking", - "frame-benchmarking-cli", "futures", - "jsonrpsee", + "jsonrpsee 0.24.3", "log", - "pallet-transaction-payment-rpc", "parachain-template-runtime", "parity-scale-codec", - "polkadot-cli", - "polkadot-primitives", - "sc-basic-authorship", - "sc-chain-spec", - "sc-cli", - "sc-client-api", - "sc-consensus", - "sc-executor", - "sc-network", - "sc-network-sync", - "sc-offchain", - "sc-rpc", - "sc-service", - "sc-sysinfo", - "sc-telemetry", + "polkadot-sdk", "sc-tracing", - "sc-transaction-pool", - "sc-transaction-pool-api", "serde", "serde_json", - "sp-api", - "sp-block-builder", - "sp-blockchain", - "sp-consensus-aura", - "sp-core", - "sp-io", - "sp-keystore", - "sp-runtime", - "sp-timestamp", - "staging-xcm", - "substrate-build-script-utils", - "substrate-frame-rpc-system", "substrate-prometheus-endpoint", ] @@ -11995,59 +13203,16 @@ dependencies = [ name = "parachain-template-runtime" version = "0.0.0" dependencies = [ - "cumulus-pallet-aura-ext", "cumulus-pallet-parachain-system", - "cumulus-pallet-session-benchmarking", - "cumulus-pallet-xcm", - "cumulus-pallet-xcmp-queue", - "cumulus-primitives-aura", - "cumulus-primitives-core", - "cumulus-primitives-storage-weight-reclaim", - "cumulus-primitives-utility", "docify", - "frame-benchmarking", - "frame-executive", - "frame-metadata-hash-extension", - "frame-support", - "frame-system", - "frame-system-benchmarking", - "frame-system-rpc-runtime-api", - "frame-try-runtime", "hex-literal", "log", - "pallet-aura", - "pallet-authorship", - "pallet-balances", - "pallet-collator-selection", - "pallet-message-queue", "pallet-parachain-template", - "pallet-session", - "pallet-sudo", - "pallet-timestamp", - "pallet-transaction-payment", - "pallet-transaction-payment-rpc-runtime-api", - "pallet-xcm", - "parachains-common", "parity-scale-codec", - "polkadot-parachain-primitives", - "polkadot-runtime-common", + "polkadot-sdk", "scale-info", + "serde_json", "smallvec", - "sp-api", - "sp-block-builder", - "sp-consensus-aura", - "sp-core", - "sp-genesis-builder", - "sp-inherents", - "sp-offchain", - "sp-runtime", - "sp-session", - "sp-transaction-pool", - "sp-version", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", "substrate-wasm-builder", ] @@ -12071,9 +13236,9 @@ dependencies = [ "polkadot-primitives", "scale-info", "sp-consensus-aura", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "staging-parachain-info", "staging-xcm", "staging-xcm-executor", @@ -12092,7 +13257,7 @@ dependencies = [ "parity-scale-codec", "relay-substrate-client", "relay-utils", - "sp-core", + "sp-core 28.0.0", ] [[package]] @@ -12115,9 +13280,9 @@ dependencies = [ "parity-scale-codec", "polkadot-parachain-primitives", "sp-consensus-aura", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", "staging-parachain-info", "staging-xcm", @@ -12133,7 +13298,7 @@ checksum = "4e69bf016dc406eff7d53a7d3f7cf1c2e72c82b9088aac1118591e36dd2cd3e9" dependencies = [ "bitcoin_hashes 0.13.0", "rand", - "rand_core", + "rand_core 0.6.4", "serde", "unicode-normalization", ] @@ -12160,7 +13325,7 @@ dependencies = [ "memmap2 0.5.10", "parking_lot 0.12.3", "rand", - "siphasher", + "siphasher 0.3.11", "snap", ] @@ -12186,38 +13351,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 1.0.109", -] - -[[package]] -name = "parity-util-mem" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d32c34f4f5ca7f9196001c0aba5a1f9a5a12382c8944b8b0f90233282d1e8f8" -dependencies = [ - "cfg-if", - "ethereum-types", - "hashbrown 0.12.3", - "impl-trait-for-tuples", - "lru 0.8.1", - "parity-util-mem-derive", - "parking_lot 0.12.3", - "primitive-types", - "smallvec", - "winapi", -] - -[[package]] -name = "parity-util-mem-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f557c32c6d268a07c921471619c0295f5efad3a0e76d4f97a05c091a51d110b2" -dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", - "synstructure 0.12.6", ] [[package]] @@ -12228,9 +13364,9 @@ checksum = "e1ad0aff30c1da14b1254fcb2af73e1fa9a28670e584a626f53a369d0e157304" [[package]] name = "parking" -version = "2.1.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -12293,15 +13429,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", - "rand_core", + "rand_core 0.6.4", "subtle 2.5.0", ] [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pbkdf2" @@ -12328,6 +13464,16 @@ dependencies = [ "base64 0.13.1", ] +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.1", + "serde", +] + [[package]] name = "penpal-emulated-chain" version = "0.0.0" @@ -12337,7 +13483,8 @@ dependencies = [ "frame-support", "parachains-common", "penpal-runtime", - "sp-core", + "sp-core 28.0.0", + "sp-keyring", "staging-xcm", ] @@ -12362,6 +13509,7 @@ dependencies = [ "frame-try-runtime", "hex-literal", "log", + "pallet-asset-conversion", "pallet-asset-tx-payment", "pallet-assets", "pallet-aura", @@ -12380,20 +13528,21 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-common", + "primitive-types 0.12.2", "scale-info", "smallvec", - "sp-api", + "sp-api 26.0.0", "sp-block-builder", "sp-consensus-aura", - "sp-core", + "sp-core 28.0.0", "sp-genesis-builder", "sp-inherents", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-storage 19.0.0", "sp-transaction-pool", - "sp-version", + "sp-version 29.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -12411,7 +13560,7 @@ dependencies = [ "frame-support", "parachains-common", "people-rococo-runtime", - "sp-core", + "sp-core 28.0.0", "testnet-parachains-constants", ] @@ -12430,7 +13579,7 @@ dependencies = [ "polkadot-runtime-common", "rococo-runtime-constants", "rococo-system-emulated-network", - "sp-runtime", + "sp-runtime 31.0.1", "staging-xcm", "staging-xcm-executor", ] @@ -12465,6 +13614,7 @@ dependencies = [ "pallet-identity", "pallet-message-queue", "pallet-multisig", + "pallet-proxy", "pallet-session", "pallet-timestamp", "pallet-transaction-payment", @@ -12479,18 +13629,18 @@ dependencies = [ "rococo-runtime-constants", "scale-info", "serde", - "sp-api", + "sp-api 26.0.0", "sp-block-builder", "sp-consensus-aura", - "sp-core", + "sp-core 28.0.0", "sp-genesis-builder", "sp-inherents", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-storage 19.0.0", "sp-transaction-pool", - "sp-version", + "sp-version 29.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -12509,7 +13659,7 @@ dependencies = [ "frame-support", "parachains-common", "people-westend-runtime", - "sp-core", + "sp-core 28.0.0", "testnet-parachains-constants", ] @@ -12523,10 +13673,11 @@ dependencies = [ "pallet-balances", "pallet-identity", "pallet-message-queue", + "pallet-xcm", "parachains-common", "parity-scale-codec", "polkadot-runtime-common", - "sp-runtime", + "sp-runtime 31.0.1", "staging-xcm", "staging-xcm-executor", "westend-runtime-constants", @@ -12563,6 +13714,7 @@ dependencies = [ "pallet-identity", "pallet-message-queue", "pallet-multisig", + "pallet-proxy", "pallet-session", "pallet-timestamp", "pallet-transaction-payment", @@ -12576,18 +13728,18 @@ dependencies = [ "polkadot-runtime-common", "scale-info", "serde", - "sp-api", + "sp-api 26.0.0", "sp-block-builder", "sp-consensus-aura", - "sp-core", + "sp-core 28.0.0", "sp-genesis-builder", "sp-inherents", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-storage 19.0.0", "sp-transaction-pool", - "sp-version", + "sp-version 29.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -12632,9 +13784,9 @@ checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -12673,9 +13825,9 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -12708,9 +13860,9 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "platforms" -version = "3.0.2" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" +checksum = "0e4c7666f2019727f9e8e14bf14456e99c707d780922869f1ba473eee101fa49" [[package]] name = "plotters" @@ -12767,12 +13919,10 @@ version = "7.0.0" dependencies = [ "assert_matches", "bitvec", - "env_logger 0.11.3", "futures", "futures-timer", "itertools 0.11.0", "log", - "polkadot-node-jaeger", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -12783,10 +13933,13 @@ dependencies = [ "polkadot-primitives-test-helpers", "rand", "rand_chacha", - "rand_core", + "rand_core 0.6.4", + "sc-keystore", "schnorrkel 0.11.4", + "sp-application-crypto 30.0.0", "sp-authority-discovery", - "sp-core", + "sp-core 28.0.0", + "sp-tracing 16.0.0", "tracing-gum", ] @@ -12797,10 +13950,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,11 +13960,12 @@ dependencies = [ "polkadot-primitives", "rand", "rand_chacha", - "sp-application-crypto", + "sp-application-crypto 30.0.0", "sp-authority-discovery", - "sp-core", + "sp-core 28.0.0", "sp-keyring", - "sp-keystore", + "sp-keystore 0.34.0", + "sp-tracing 16.0.0", "tracing-gum", ] @@ -12840,9 +13992,9 @@ dependencies = [ "rstest", "sc-network", "schnellru", - "sp-core", + "sp-core 28.0.0", "sp-keyring", - "sp-keystore", + "sp-keystore 0.34.0", "sp-tracing 16.0.0", "thiserror", "tracing-gum", @@ -12872,8 +14024,8 @@ dependencies = [ "rstest", "sc-network", "schnellru", - "sp-application-crypto", - "sp-core", + "sp-application-crypto 30.0.0", + "sp-core 28.0.0", "sp-keyring", "sp-tracing 16.0.0", "thiserror", @@ -12896,7 +14048,7 @@ name = "polkadot-cli" version = "7.0.0" dependencies = [ "cfg-if", - "clap 4.5.3", + "clap 4.5.13", "frame-benchmarking-cli", "futures", "log", @@ -12906,16 +14058,16 @@ dependencies = [ "pyroscope", "pyroscope_pprofrs", "sc-cli", - "sc-executor", + "sc-executor 0.32.0", "sc-service", "sc-storage-monitor", "sc-sysinfo", "sc-tracing", - "sp-core", - "sp-io", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-keyring", - "sp-maybe-compressed-blob", - "sp-runtime", + "sp-maybe-compressed-blob 11.0.0", + "sp-runtime 31.0.1", "substrate-build-script-utils", "thiserror", ] @@ -12926,11 +14078,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", @@ -12942,10 +14092,12 @@ dependencies = [ "rstest", "sc-keystore", "sc-network", - "sp-core", + "schnellru", + "sp-core 28.0.0", "sp-keyring", - "sp-keystore", - "sp-runtime", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", + "sp-tracing 16.0.0", "thiserror", "tokio-util", "tracing-gum", @@ -12957,8 +14109,8 @@ version = "7.0.0" dependencies = [ "parity-scale-codec", "scale-info", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -12966,14 +14118,13 @@ name = "polkadot-dispute-distribution" version = "7.0.0" dependencies = [ "assert_matches", - "async-channel", + "async-channel 1.9.0", "async-trait", "derive_more", "fatality", "futures", "futures-timer", "indexmap 2.2.3", - "lazy_static", "parity-scale-codec", "polkadot-erasure-coding", "polkadot-node-network-protocol", @@ -12986,9 +14137,9 @@ dependencies = [ "sc-keystore", "sc-network", "schnellru", - "sp-application-crypto", + "sp-application-crypto 30.0.0", "sp-keyring", - "sp-keystore", + "sp-keystore 0.34.0", "sp-tracing 16.0.0", "thiserror", "tracing-gum", @@ -13004,8 +14155,8 @@ dependencies = [ "polkadot-primitives", "quickcheck", "reed-solomon-novelpoly", - "sp-core", - "sp-trie", + "sp-core 28.0.0", + "sp-trie 29.0.0", "thiserror", ] @@ -13017,7 +14168,6 @@ dependencies = [ "async-trait", "futures", "futures-timer", - "lazy_static", "parking_lot 0.12.3", "polkadot-node-network-protocol", "polkadot-node-subsystem", @@ -13029,13 +14179,13 @@ dependencies = [ "rand_chacha", "sc-network", "sc-network-common", - "sp-application-crypto", + "sp-application-crypto 30.0.0", "sp-authority-discovery", "sp-consensus-babe", - "sp-core", - "sp-crypto-hashing", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", "sp-keyring", - "sp-keystore", + "sp-keystore 0.34.0", "sp-tracing 16.0.0", "tracing-gum", ] @@ -13063,7 +14213,7 @@ dependencies = [ "polkadot-primitives-test-helpers", "sc-network", "sp-consensus", - "sp-core", + "sp-core 28.0.0", "sp-keyring", "thiserror", "tracing-gum", @@ -13084,9 +14234,9 @@ dependencies = [ "polkadot-primitives", "polkadot-primitives-test-helpers", "rstest", - "sp-core", + "sp-core 28.0.0", "sp-keyring", - "sp-maybe-compressed-blob", + "sp-maybe-compressed-blob 11.0.0", "thiserror", "tracing-gum", ] @@ -13099,7 +14249,6 @@ dependencies = [ "async-trait", "bitvec", "derive_more", - "env_logger 0.11.3", "futures", "futures-timer", "itertools 0.11.0", @@ -13109,7 +14258,6 @@ dependencies = [ "merlin", "parity-scale-codec", "parking_lot 0.12.3", - "polkadot-node-jaeger", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -13120,18 +14268,61 @@ dependencies = [ "polkadot-subsystem-bench", "rand", "rand_chacha", - "rand_core", + "rand_core 0.6.4", "sc-keystore", "schnellru", "schnorrkel 0.11.4", - "sp-application-crypto", + "sp-application-crypto 30.0.0", + "sp-consensus", + "sp-consensus-babe", + "sp-consensus-slots", + "sp-core 28.0.0", + "sp-keyring", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", + "sp-tracing 16.0.0", + "thiserror", + "tracing-gum", +] + +[[package]] +name = "polkadot-node-core-approval-voting-parallel" +version = "7.0.0" +dependencies = [ + "assert_matches", + "async-trait", + "futures", + "futures-timer", + "itertools 0.11.0", + "kvdb-memorydb", + "log", + "parking_lot 0.12.3", + "polkadot-approval-distribution", + "polkadot-node-core-approval-voting", + "polkadot-node-metrics", + "polkadot-node-network-protocol", + "polkadot-node-primitives", + "polkadot-node-subsystem", + "polkadot-node-subsystem-test-helpers", + "polkadot-node-subsystem-util", + "polkadot-overseer", + "polkadot-primitives", + "polkadot-primitives-test-helpers", + "polkadot-subsystem-bench", + "rand", + "rand_chacha", + "rand_core 0.6.4", + "sc-keystore", + "schnorrkel 0.11.4", + "sp-application-crypto 30.0.0", "sp-consensus", "sp-consensus-babe", "sp-consensus-slots", - "sp-core", + "sp-core 28.0.0", "sp-keyring", - "sp-keystore", - "sp-runtime", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", + "sp-tracing 16.0.0", "thiserror", "tracing-gum", ] @@ -13142,7 +14333,6 @@ version = "7.0.0" dependencies = [ "assert_matches", "bitvec", - "env_logger 0.11.3", "futures", "futures-timer", "kvdb", @@ -13151,7 +14341,6 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.3", "polkadot-erasure-coding", - "polkadot-node-jaeger", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", @@ -13160,8 +14349,9 @@ dependencies = [ "polkadot-primitives", "polkadot-primitives-test-helpers", "sp-consensus", - "sp-core", + "sp-core 28.0.0", "sp-keyring", + "sp-tracing 16.0.0", "thiserror", "tracing-gum", ] @@ -13179,16 +14369,17 @@ dependencies = [ "polkadot-node-subsystem", "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", + "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-primitives-test-helpers", "polkadot-statement-table", "rstest", "sc-keystore", "schnellru", - "sp-application-crypto", - "sp-core", + "sp-application-crypto 30.0.0", + "sp-core 28.0.0", "sp-keyring", - "sp-keystore", + "sp-keystore 0.34.0", "sp-tracing 16.0.0", "thiserror", "tracing-gum", @@ -13204,7 +14395,7 @@ dependencies = [ "polkadot-node-subsystem-util", "polkadot-primitives", "polkadot-primitives-test-helpers", - "sp-keystore", + "sp-keystore 0.34.0", "thiserror", "tracing-gum", "wasm-timer", @@ -13229,9 +14420,11 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-primitives-test-helpers", - "sp-core", + "sp-application-crypto 30.0.0", + "sp-core 28.0.0", "sp-keyring", - "sp-maybe-compressed-blob", + "sp-keystore 0.34.0", + "sp-maybe-compressed-blob 11.0.0", "tracing-gum", ] @@ -13251,7 +14444,7 @@ dependencies = [ "sc-client-api", "sc-consensus-babe", "sp-blockchain", - "sp-core", + "sp-core 28.0.0", "tracing-gum", ] @@ -13271,7 +14464,7 @@ dependencies = [ "polkadot-node-subsystem-test-helpers", "polkadot-node-subsystem-util", "polkadot-primitives", - "sp-core", + "sp-core 28.0.0", "thiserror", "tracing-gum", ] @@ -13295,10 +14488,10 @@ dependencies = [ "polkadot-primitives-test-helpers", "sc-keystore", "schnellru", - "sp-application-crypto", - "sp-core", + "sp-application-crypto 30.0.0", + "sp-core 28.0.0", "sp-keyring", - "sp-keystore", + "sp-keystore 0.34.0", "sp-tracing 16.0.0", "thiserror", "tracing-gum", @@ -13325,23 +14518,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-core 28.0.0", + "sp-tracing 16.0.0", "thiserror", "tracing-gum", ] @@ -13362,8 +14549,8 @@ dependencies = [ "polkadot-primitives-test-helpers", "rstest", "schnellru", - "sp-application-crypto", - "sp-keystore", + "sp-application-crypto 30.0.0", + "sp-keystore 0.34.0", "thiserror", "tracing-gum", ] @@ -13401,8 +14588,9 @@ dependencies = [ "rusty-fork", "sc-sysinfo", "slotmap", - "sp-core", - "sp-maybe-compressed-blob", + "sp-core 28.0.0", + "sp-maybe-compressed-blob 11.0.0", + "strum 0.26.3", "tempfile", "test-parachain-adder", "test-parachain-halt", @@ -13425,11 +14613,11 @@ dependencies = [ "polkadot-primitives", "polkadot-primitives-test-helpers", "sc-keystore", - "sp-application-crypto", - "sp-core", + "sp-application-crypto 30.0.0", + "sp-core 28.0.0", "sp-keyring", - "sp-keystore", - "sp-runtime", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", "thiserror", "tracing-gum", ] @@ -13447,14 +14635,14 @@ dependencies = [ "parity-scale-codec", "polkadot-parachain-primitives", "polkadot-primitives", - "sc-executor", - "sc-executor-common", - "sc-executor-wasmtime", + "sc-executor 0.32.0", + "sc-executor-common 0.29.0", + "sc-executor-wasmtime 0.29.0", "seccompiler", - "sp-core", - "sp-crypto-hashing", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", "sp-externalities 0.25.0", - "sp-io", + "sp-io 30.0.0", "sp-tracing 16.0.0", "tempfile", "thiserror", @@ -13471,8 +14659,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 11.0.0", "tracing-gum", ] @@ -13487,12 +14677,13 @@ dependencies = [ "nix 0.28.0", "parity-scale-codec", "polkadot-node-core-pvf-common", + "polkadot-node-primitives", "polkadot-primitives", "rayon", "rococo-runtime", - "sc-executor-common", - "sc-executor-wasmtime", - "sp-maybe-compressed-blob", + "sc-executor-common 0.29.0", + "sc-executor-wasmtime 0.29.0", + "sp-maybe-compressed-blob 11.0.0", "staging-tracking-allocator", "tikv-jemalloc-ctl", "tikv-jemallocator", @@ -13513,37 +14704,19 @@ dependencies = [ "polkadot-primitives", "polkadot-primitives-test-helpers", "schnellru", - "sp-api", + "sp-api 26.0.0", "sp-consensus-babe", - "sp-core", + "sp-core 28.0.0", "sp-keyring", "tracing-gum", ] -[[package]] -name = "polkadot-node-jaeger" -version = "7.0.0" -dependencies = [ - "lazy_static", - "log", - "mick-jaeger", - "parity-scale-codec", - "parking_lot 0.12.3", - "polkadot-node-primitives", - "polkadot-primitives", - "sc-network", - "sc-network-types", - "sp-core", - "thiserror", - "tokio", -] - [[package]] name = "polkadot-node-metrics" version = "7.0.0" dependencies = [ "assert_cmd", - "bs58 0.5.0", + "bs58", "futures", "futures-timer", "http-body-util", @@ -13570,7 +14743,7 @@ dependencies = [ name = "polkadot-node-network-protocol" version = "7.0.0" dependencies = [ - "async-channel", + "async-channel 1.9.0", "async-trait", "bitvec", "derive_more", @@ -13578,7 +14751,6 @@ dependencies = [ "futures", "hex", "parity-scale-codec", - "polkadot-node-jaeger", "polkadot-node-primitives", "polkadot-primitives", "rand", @@ -13586,8 +14758,8 @@ dependencies = [ "sc-authority-discovery", "sc-network", "sc-network-types", - "sp-runtime", - "strum 0.26.2", + "sp-runtime 31.0.1", + "strum 0.26.3", "thiserror", "tracing-gum", ] @@ -13599,18 +14771,21 @@ dependencies = [ "bitvec", "bounded-vec", "futures", + "futures-timer", "parity-scale-codec", "polkadot-erasure-coding", "polkadot-parachain-primitives", "polkadot-primitives", + "sc-keystore", "schnorrkel 0.11.4", "serde", - "sp-application-crypto", + "sp-application-crypto 30.0.0", "sp-consensus-babe", - "sp-core", - "sp-keystore", - "sp-maybe-compressed-blob", - "sp-runtime", + "sp-consensus-slots", + "sp-core 28.0.0", + "sp-keystore 0.34.0", + "sp-maybe-compressed-blob 11.0.0", + "sp-runtime 31.0.1", "thiserror", "zstd 0.12.4", ] @@ -13619,7 +14794,6 @@ dependencies = [ name = "polkadot-node-subsystem" version = "7.0.0" dependencies = [ - "polkadot-node-jaeger", "polkadot-node-subsystem-types", "polkadot-overseer", ] @@ -13639,10 +14813,10 @@ dependencies = [ "sc-client-api", "sc-keystore", "sc-utils", - "sp-application-crypto", - "sp-core", + "sp-application-crypto 30.0.0", + "sp-core 28.0.0", "sp-keyring", - "sp-keystore", + "sp-keystore 0.34.0", ] [[package]] @@ -13655,7 +14829,6 @@ dependencies = [ "fatality", "futures", "orchestra", - "polkadot-node-jaeger", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-primitives", @@ -13665,11 +14838,12 @@ dependencies = [ "sc-network-types", "sc-transaction-pool-api", "smallvec", - "sp-api", + "sp-api 26.0.0", "sp-authority-discovery", "sp-blockchain", "sp-consensus-babe", - "sp-runtime", + "sp-runtime 31.0.1", + "strum 0.26.3", "substrate-prometheus-endpoint", "thiserror", ] @@ -13681,7 +14855,6 @@ dependencies = [ "assert_matches", "async-trait", "derive_more", - "env_logger 0.11.3", "fatality", "futures", "futures-channel", @@ -13689,14 +14862,12 @@ dependencies = [ "kvdb", "kvdb-memorydb", "kvdb-shared-tests", - "lazy_static", "log", "parity-db", "parity-scale-codec", "parking_lot 0.12.3", "pin-project", "polkadot-erasure-coding", - "polkadot-node-jaeger", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", @@ -13710,56 +14881,31 @@ dependencies = [ "rand", "sc-client-api", "schnellru", - "sp-application-crypto", - "sp-core", - "sp-keystore", + "sp-application-crypto 30.0.0", + "sp-core 28.0.0", + "sp-keystore 0.34.0", "tempfile", "thiserror", "tracing-gum", ] [[package]] -name = "polkadot-overseer" -version = "7.0.0" +name = "polkadot-omni-node" +version = "0.1.0" dependencies = [ - "assert_matches", - "async-trait", - "femme", - "futures", - "futures-timer", - "orchestra", - "parking_lot 0.12.3", - "polkadot-node-metrics", - "polkadot-node-network-protocol", - "polkadot-node-primitives", - "polkadot-node-subsystem-test-helpers", - "polkadot-node-subsystem-types", - "polkadot-primitives", - "polkadot-primitives-test-helpers", - "prioritized-metered-channel", - "sc-client-api", - "sp-api", - "sp-core", - "tikv-jemalloc-ctl", - "tracing-gum", + "color-eyre", + "polkadot-omni-node-lib", + "substrate-build-script-utils", ] [[package]] -name = "polkadot-parachain-bin" -version = "4.0.0" +name = "polkadot-omni-node-lib" +version = "0.1.0" dependencies = [ "assert_cmd", - "asset-hub-rococo-runtime", - "asset-hub-westend-runtime", "async-trait", - "bridge-hub-rococo-runtime", - "bridge-hub-westend-runtime", - "clap 4.5.3", - "collectives-westend-runtime", + "clap 4.5.13", "color-print", - "contracts-rococo-runtime", - "coretime-rococo-runtime", - "coretime-westend-runtime", "cumulus-client-cli", "cumulus-client-collator", "cumulus-client-consensus-aura", @@ -13778,9 +14924,8 @@ dependencies = [ "frame-system-rpc-runtime-api", "frame-try-runtime", "futures", - "glutton-westend-runtime", - "hex-literal", - "jsonrpsee", + "futures-timer", + "jsonrpsee 0.24.3", "log", "nix 0.28.0", "pallet-transaction-payment", @@ -13788,63 +14933,109 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "parachains-common", "parity-scale-codec", - "penpal-runtime", - "people-rococo-runtime", - "people-westend-runtime", "polkadot-cli", "polkadot-primitives", - "polkadot-service", - "rococo-parachain-runtime", "sc-basic-authorship", "sc-chain-spec", "sc-cli", "sc-client-api", + "sc-client-db", "sc-consensus", - "sc-executor", + "sc-consensus-manual-seal", + "sc-executor 0.32.0", "sc-network", - "sc-network-sync", "sc-rpc", "sc-service", "sc-sysinfo", "sc-telemetry", "sc-tracing", "sc-transaction-pool", - "sc-transaction-pool-api", - "seedling-runtime", "serde", "serde_json", - "shell-runtime", - "sp-api", + "sp-api 26.0.0", "sp-block-builder", - "sp-blockchain", "sp-consensus-aura", - "sp-core", + "sp-core 28.0.0", "sp-genesis-builder", "sp-inherents", - "sp-io", - "sp-keystore", - "sp-offchain", - "sp-runtime", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", "sp-session", - "sp-std 14.0.0", "sp-timestamp", - "sp-tracing 16.0.0", "sp-transaction-pool", - "sp-version", - "staging-xcm", - "substrate-build-script-utils", + "sp-version 29.0.0", + "sp-weights 27.0.0", "substrate-frame-rpc-system", "substrate-prometheus-endpoint", "substrate-state-trie-migration-rpc", - "tempfile", - "testnet-parachains-constants", "tokio", "wait-timeout", ] [[package]] -name = "polkadot-parachain-primitives" -version = "6.0.0" +name = "polkadot-overseer" +version = "7.0.0" +dependencies = [ + "assert_matches", + "async-trait", + "femme", + "futures", + "futures-timer", + "orchestra", + "parking_lot 0.12.3", + "polkadot-node-metrics", + "polkadot-node-network-protocol", + "polkadot-node-primitives", + "polkadot-node-subsystem-test-helpers", + "polkadot-node-subsystem-types", + "polkadot-primitives", + "polkadot-primitives-test-helpers", + "prioritized-metered-channel", + "sc-client-api", + "sp-api 26.0.0", + "sp-core 28.0.0", + "tikv-jemalloc-ctl", + "tracing-gum", +] + +[[package]] +name = "polkadot-parachain-bin" +version = "4.0.0" +dependencies = [ + "asset-hub-rococo-runtime", + "asset-hub-westend-runtime", + "bridge-hub-rococo-runtime", + "bridge-hub-westend-runtime", + "collectives-westend-runtime", + "color-eyre", + "contracts-rococo-runtime", + "coretime-rococo-runtime", + "coretime-westend-runtime", + "cumulus-primitives-core", + "glutton-westend-runtime", + "hex-literal", + "log", + "parachains-common", + "penpal-runtime", + "people-rococo-runtime", + "people-westend-runtime", + "polkadot-omni-node-lib", + "rococo-parachain-runtime", + "sc-chain-spec", + "sc-cli", + "sc-service", + "serde", + "serde_json", + "sp-core 28.0.0", + "sp-genesis-builder", + "sp-keyring", + "staging-xcm", + "substrate-build-script-utils", +] + +[[package]] +name = "polkadot-parachain-primitives" +version = "6.0.0" dependencies = [ "bounded-collections", "derive_more", @@ -13852,9 +15043,9 @@ dependencies = [ "polkadot-core-primitives", "scale-info", "serde", - "sp-core", - "sp-runtime", - "sp-weights", + "sp-core 28.0.0", + "sp-runtime 31.0.1", + "sp-weights 27.0.0", ] [[package]] @@ -13867,19 +15058,21 @@ dependencies = [ "parity-scale-codec", "polkadot-core-primitives", "polkadot-parachain-primitives", + "polkadot-primitives-test-helpers", "scale-info", "serde", - "sp-api", - "sp-application-crypto", - "sp-arithmetic", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", + "sp-arithmetic 23.0.0", "sp-authority-discovery", "sp-consensus-slots", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-io", - "sp-keystore", - "sp-runtime", + "sp-io 30.0.0", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", "sp-staking", + "sp-std 14.0.0", ] [[package]] @@ -13888,17 +15081,17 @@ version = "1.0.0" dependencies = [ "polkadot-primitives", "rand", - "sp-application-crypto", - "sp-core", + "sp-application-crypto 30.0.0", + "sp-core 28.0.0", "sp-keyring", - "sp-runtime", + "sp-runtime 31.0.1", ] [[package]] name = "polkadot-rpc" version = "7.0.0" dependencies = [ - "jsonrpsee", + "jsonrpsee 0.24.3", "mmr-rpc", "pallet-transaction-payment-rpc", "polkadot-primitives", @@ -13915,15 +15108,15 @@ dependencies = [ "sc-rpc-spec-v2", "sc-sync-state-rpc", "sc-transaction-pool-api", - "sp-api", - "sp-application-crypto", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", "sp-block-builder", "sp-blockchain", "sp-consensus", "sp-consensus-babe", "sp-consensus-beefy", - "sp-keystore", - "sp-runtime", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", "substrate-frame-rpc-system", "substrate-state-trie-migration-rpc", ] @@ -13967,14 +15160,14 @@ dependencies = [ "serde_derive", "serde_json", "slot-range-helper", - "sp-api", - "sp-core", + "sp-api 26.0.0", + "sp-core 28.0.0", "sp-inherents", - "sp-io", + "sp-io 30.0.0", "sp-keyring", - "sp-keystore", + "sp-keystore 0.34.0", "sp-npos-elections", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-staking", "staging-xcm", @@ -13987,7 +15180,7 @@ dependencies = [ name = "polkadot-runtime-metrics" version = "7.0.0" dependencies = [ - "bs58 0.5.0", + "bs58", "frame-benchmarking", "parity-scale-codec", "polkadot-primitives", @@ -14016,6 +15209,7 @@ dependencies = [ "pallet-balances", "pallet-broker", "pallet-message-queue", + "pallet-mmr", "pallet-session", "pallet-staking", "pallet-timestamp", @@ -14033,18 +15227,19 @@ dependencies = [ "scale-info", "serde", "serde_json", - "sp-api", - "sp-application-crypto", - "sp-arithmetic", - "sp-core", - "sp-crypto-hashing", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", "sp-inherents", - "sp-io", + "sp-io 30.0.0", "sp-keyring", - "sp-keystore", - "sp-runtime", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", "sp-session", "sp-staking", + "sp-std 14.0.0", "sp-tracing 16.0.0", "staging-xcm", "staging-xcm-executor", @@ -14059,25 +15254,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", @@ -14206,6 +15390,11 @@ dependencies = [ "pallet-recovery", "pallet-referenda", "pallet-remark", + "pallet-revive", + "pallet-revive-fixtures", + "pallet-revive-mock-network", + "pallet-revive-proc-macro", + "pallet-revive-uapi", "pallet-root-offences", "pallet-root-testing", "pallet-safe-mode", @@ -14233,6 +15422,7 @@ dependencies = [ "pallet-tx-pause", "pallet-uniques", "pallet-utility", + "pallet-verify-signature", "pallet-vesting", "pallet-whitelist", "pallet-xcm", @@ -14254,6 +15444,7 @@ dependencies = [ "polkadot-network-bridge", "polkadot-node-collation-generation", "polkadot-node-core-approval-voting", + "polkadot-node-core-approval-voting-parallel", "polkadot-node-core-av-store", "polkadot-node-core-backing", "polkadot-node-core-bitfield-signing", @@ -14270,13 +15461,13 @@ dependencies = [ "polkadot-node-core-pvf-execute-worker", "polkadot-node-core-pvf-prepare-worker", "polkadot-node-core-runtime-api", - "polkadot-node-jaeger", "polkadot-node-metrics", "polkadot-node-network-protocol", "polkadot-node-primitives", "polkadot-node-subsystem", "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", + "polkadot-omni-node-lib", "polkadot-overseer", "polkadot-parachain-primitives", "polkadot-primitives", @@ -14288,8 +15479,7 @@ dependencies = [ "polkadot-service", "polkadot-statement-distribution", "polkadot-statement-table", - "rococo-runtime-constants", - "sc-allocator", + "sc-allocator 23.0.0", "sc-authority-discovery", "sc-basic-authorship", "sc-block-builder", @@ -14310,10 +15500,10 @@ dependencies = [ "sc-consensus-manual-seal", "sc-consensus-pow", "sc-consensus-slots", - "sc-executor", - "sc-executor-common", - "sc-executor-polkavm", - "sc-executor-wasmtime", + "sc-executor 0.32.0", + "sc-executor-common 0.29.0", + "sc-executor-polkavm 0.29.0", + "sc-executor-wasmtime 0.29.0", "sc-informant", "sc-keystore", "sc-mixnet", @@ -14359,10 +15549,10 @@ dependencies = [ "snowbridge-runtime-common", "snowbridge-runtime-test-common", "snowbridge-system-runtime-api", - "sp-api", - "sp-api-proc-macro", - "sp-application-crypto", - "sp-arithmetic", + "sp-api 26.0.0", + "sp-api-proc-macro 15.0.0", + "sp-application-crypto 30.0.0", + "sp-arithmetic 23.0.0", "sp-authority-discovery", "sp-block-builder", "sp-blockchain", @@ -14373,34 +15563,34 @@ dependencies = [ "sp-consensus-grandpa", "sp-consensus-pow", "sp-consensus-slots", - "sp-core", + "sp-core 28.0.0", "sp-core-hashing", "sp-core-hashing-proc-macro", "sp-crypto-ec-utils 0.10.0", - "sp-crypto-hashing", - "sp-crypto-hashing-proc-macro", + "sp-crypto-hashing 0.1.0", + "sp-crypto-hashing-proc-macro 0.1.0", "sp-database", "sp-debug-derive 14.0.0", "sp-externalities 0.25.0", "sp-genesis-builder", "sp-inherents", - "sp-io", + "sp-io 30.0.0", "sp-keyring", - "sp-keystore", - "sp-maybe-compressed-blob", - "sp-metadata-ir", + "sp-keystore 0.34.0", + "sp-maybe-compressed-blob 11.0.0", + "sp-metadata-ir 0.6.0", "sp-mixnet", "sp-mmr-primitives", "sp-npos-elections", "sp-offchain", - "sp-panic-handler", + "sp-panic-handler 13.0.0", "sp-rpc", - "sp-runtime", + "sp-runtime 31.0.1", "sp-runtime-interface 24.0.0", "sp-runtime-interface-proc-macro 17.0.0", "sp-session", "sp-staking", - "sp-state-machine", + "sp-state-machine 0.35.0", "sp-statement-store", "sp-std 14.0.0", "sp-storage 19.0.0", @@ -14408,11 +15598,11 @@ dependencies = [ "sp-tracing 16.0.0", "sp-transaction-pool", "sp-transaction-storage-proof", - "sp-trie", - "sp-version", - "sp-version-proc-macro", + "sp-trie 29.0.0", + "sp-version 29.0.0", + "sp-version-proc-macro 13.0.0", "sp-wasm-interface 20.0.0", - "sp-weights", + "sp-weights 27.0.0", "staging-chain-spec-builder", "staging-node-inspect", "staging-parachain-info", @@ -14421,7 +15611,7 @@ dependencies = [ "staging-xcm-builder", "staging-xcm-executor", "subkey", - "substrate-bip39", + "substrate-bip39 0.4.7", "substrate-build-script-utils", "substrate-frame-rpc-support", "substrate-frame-rpc-system", @@ -14432,7 +15622,6 @@ dependencies = [ "testnet-parachains-constants", "tracing-gum", "tracing-gum-proc-macro", - "westend-runtime-constants", "xcm-emulator", "xcm-procedural", "xcm-runtime-apis", @@ -14455,6 +15644,7 @@ dependencies = [ "frame-support", "frame-system", "kitchensink-runtime", + "log", "minimal-template-runtime", "pallet-asset-conversion-tx-payment", "pallet-asset-tx-payment", @@ -14465,8 +15655,10 @@ dependencies = [ "pallet-balances", "pallet-broker", "pallet-collective", + "pallet-contracts", "pallet-default-config-example", "pallet-democracy", + "pallet-example-authorization-tx-extension", "pallet-example-offchain-worker", "pallet-example-single-block-migrations", "pallet-examples", @@ -14481,6 +15673,7 @@ dependencies = [ "pallet-transaction-payment", "pallet-uniques", "pallet-utility", + "pallet-xcm", "parachain-template-runtime", "parity-scale-codec", "polkadot-sdk", @@ -14494,7 +15687,7 @@ dependencies = [ "sc-consensus-grandpa", "sc-consensus-manual-seal", "sc-consensus-pow", - "sc-executor", + "sc-executor 0.32.0", "sc-network", "sc-rpc", "sc-rpc-api", @@ -14502,25 +15695,28 @@ dependencies = [ "scale-info", "simple-mermaid 0.1.1", "solochain-template-runtime", - "sp-api", - "sp-arithmetic", - "sp-core", + "sp-api 26.0.0", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", "sp-genesis-builder", - "sp-io", + "sp-io 30.0.0", "sp-keyring", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-runtime-interface 24.0.0", "sp-std 14.0.0", "sp-tracing 16.0.0", - "sp-version", + "sp-version 29.0.0", "staging-chain-spec-builder", "staging-node-cli", "staging-parachain-info", "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", "subkey", "substrate-wasm-builder", "xcm-docs", + "xcm-simulator", ] [[package]] @@ -14539,20 +15735,20 @@ dependencies = [ "pallet-examples", "parity-scale-codec", "scale-info", - "sp-api", - "sp-arithmetic", + "sp-api 26.0.0", + "sp-arithmetic 23.0.0", "sp-block-builder", "sp-consensus-aura", "sp-consensus-grandpa", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-io", + "sp-io 30.0.0", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-storage 19.0.0", "sp-transaction-pool", - "sp-version", + "sp-version 29.0.0", ] [[package]] @@ -14561,23 +15757,17 @@ version = "7.0.0" dependencies = [ "assert_matches", "async-trait", - "bitvec", - "env_logger 0.11.3", "frame-benchmarking", "frame-benchmarking-cli", "frame-metadata-hash-extension", - "frame-support", "frame-system", "frame-system-rpc-runtime-api", "futures", - "hex-literal", "is_executable", "kvdb", "kvdb-rocksdb", "log", "mmr-gadget", - "pallet-babe", - "pallet-staking", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "parity-db", @@ -14594,6 +15784,7 @@ dependencies = [ "polkadot-network-bridge", "polkadot-node-collation-generation", "polkadot-node-core-approval-voting", + "polkadot-node-core-approval-voting-parallel", "polkadot-node-core-av-store", "polkadot-node-core-backing", "polkadot-node-core-bitfield-signing", @@ -14614,7 +15805,6 @@ dependencies = [ "polkadot-node-subsystem-types", "polkadot-node-subsystem-util", "polkadot-overseer", - "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-primitives-test-helpers", "polkadot-rpc", @@ -14625,19 +15815,16 @@ dependencies = [ "rococo-runtime-constants", "sc-authority-discovery", "sc-basic-authorship", - "sc-block-builder", "sc-chain-spec", "sc-client-api", - "sc-client-db", "sc-consensus", "sc-consensus-babe", "sc-consensus-beefy", "sc-consensus-grandpa", "sc-consensus-slots", - "sc-executor", + "sc-executor 0.32.0", "sc-keystore", "sc-network", - "sc-network-common", "sc-network-sync", "sc-offchain", "sc-service", @@ -14646,11 +15833,10 @@ dependencies = [ "sc-telemetry", "sc-transaction-pool", "sc-transaction-pool-api", - "schnellru", "serde", "serde_json", "serial_test", - "sp-api", + "sp-api 26.0.0", "sp-authority-discovery", "sp-block-builder", "sp-blockchain", @@ -14658,21 +15844,20 @@ dependencies = [ "sp-consensus-babe", "sp-consensus-beefy", "sp-consensus-grandpa", - "sp-core", + "sp-core 28.0.0", + "sp-genesis-builder", "sp-inherents", - "sp-io", + "sp-io 30.0.0", "sp-keyring", - "sp-keystore", "sp-mmr-primitives", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", - "sp-state-machine", - "sp-storage 19.0.0", "sp-timestamp", + "sp-tracing 16.0.0", "sp-transaction-pool", - "sp-version", - "sp-weights", + "sp-version 29.0.0", + "sp-weights 27.0.0", "staging-xcm", "substrate-prometheus-endpoint", "tempfile", @@ -14689,7 +15874,7 @@ version = "7.0.0" dependencies = [ "arrayvec 0.7.4", "assert_matches", - "async-channel", + "async-channel 1.9.0", "bitvec", "fatality", "futures", @@ -14707,11 +15892,11 @@ dependencies = [ "rand_chacha", "sc-keystore", "sc-network", - "sp-application-crypto", + "sp-application-crypto 30.0.0", "sp-authority-discovery", - "sp-core", + "sp-core 28.0.0", "sp-keyring", - "sp-keystore", + "sp-keystore 0.34.0", "sp-staking", "sp-tracing 16.0.0", "thiserror", @@ -14724,7 +15909,7 @@ version = "7.0.0" dependencies = [ "parity-scale-codec", "polkadot-primitives", - "sp-core", + "sp-core 28.0.0", "tracing-gum", ] @@ -14736,15 +15921,15 @@ dependencies = [ "async-trait", "bincode", "bitvec", - "clap 4.5.3", + "clap 4.5.13", "clap-num", "color-eyre", "colored", - "env_logger 0.11.3", "futures", "futures-timer", "hex", "itertools 0.11.0", + "jemalloc_pprof", "kvdb-memorydb", "log", "orchestra", @@ -14756,6 +15941,7 @@ dependencies = [ "polkadot-availability-recovery", "polkadot-erasure-coding", "polkadot-node-core-approval-voting", + "polkadot-node-core-approval-voting-parallel", "polkadot-node-core-av-store", "polkadot-node-core-chain-api", "polkadot-node-metrics", @@ -14768,13 +15954,14 @@ dependencies = [ "polkadot-overseer", "polkadot-primitives", "polkadot-primitives-test-helpers", + "polkadot-service", "polkadot-statement-distribution", "prometheus", "pyroscope", "pyroscope_pprofrs", "rand", "rand_chacha", - "rand_core", + "rand_core 0.6.4", "rand_distr", "sc-keystore", "sc-network", @@ -14785,16 +15972,18 @@ dependencies = [ "serde_json", "serde_yaml", "sha1", - "sp-application-crypto", + "sp-application-crypto 30.0.0", "sp-consensus", "sp-consensus-babe", - "sp-core", + "sp-core 28.0.0", "sp-keyring", - "sp-keystore", - "sp-runtime", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", "sp-timestamp", - "strum 0.26.2", + "sp-tracing 16.0.0", + "strum 0.26.3", "substrate-prometheus-endpoint", + "tikv-jemallocator", "tokio", "tracing-gum", ] @@ -14814,16 +16003,16 @@ dependencies = [ "sc-consensus", "sc-offchain", "sc-service", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", "sp-consensus", "sp-consensus-babe", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-io", + "sp-io 30.0.0", "sp-keyring", - "sp-runtime", - "sp-state-machine", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "sp-timestamp", "substrate-test-client", ] @@ -14834,7 +16023,7 @@ version = "1.0.0" dependencies = [ "assert_matches", "async-trait", - "clap 4.5.3", + "clap 4.5.13", "color-eyre", "futures", "futures-timer", @@ -14854,8 +16043,8 @@ dependencies = [ "polkadot-node-subsystem-util", "polkadot-primitives", "rand", - "sp-core", - "sp-keystore", + "sp-core 28.0.0", + "sp-keystore 0.34.0", "substrate-build-script-utils", "tracing-gum", ] @@ -14894,24 +16083,24 @@ dependencies = [ "scale-info", "serde", "serde_json", - "sp-api", + "sp-api 26.0.0", "sp-authority-discovery", "sp-block-builder", "sp-consensus-babe", "sp-consensus-beefy", - "sp-core", + "sp-core 28.0.0", "sp-genesis-builder", "sp-inherents", - "sp-io", + "sp-io 30.0.0", "sp-keyring", "sp-mmr-primitives", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-staking", "sp-transaction-pool", - "sp-trie", - "sp-version", + "sp-trie 29.0.0", + "sp-version 29.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -14953,17 +16142,17 @@ dependencies = [ "sc-tracing", "sc-transaction-pool", "serde_json", - "sp-arithmetic", + "sp-arithmetic 23.0.0", "sp-authority-discovery", "sp-blockchain", "sp-consensus", "sp-consensus-babe", "sp-consensus-grandpa", - "sp-core", + "sp-core 28.0.0", "sp-inherents", "sp-keyring", - "sp-runtime", - "sp-state-machine", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "substrate-test-client", "substrate-test-utils", "tempfile", @@ -14976,12 +16165,30 @@ dependencies = [ name = "polkadot-voter-bags" version = "7.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.13", "generate-bags", - "sp-io", + "sp-io 30.0.0", "westend-runtime", ] +[[package]] +name = "polkadot-zombienet-sdk-tests" +version = "0.1.0" +dependencies = [ + "anyhow", + "env_logger 0.11.3", + "log", + "parity-scale-codec", + "serde", + "serde_json", + "substrate-build-script-utils", + "subwasmlib", + "subxt", + "subxt-signer", + "tokio", + "zombienet-sdk", +] + [[package]] name = "polkavm" version = "0.9.3" @@ -14990,9 +16197,22 @@ checksum = "8a3693e5efdb2bf74e449cd25fd777a28bd7ed87e41f5d5da75eb31b4de48b94" dependencies = [ "libc", "log", - "polkavm-assembler", - "polkavm-common", - "polkavm-linux-raw", + "polkavm-assembler 0.9.0", + "polkavm-common 0.9.0", + "polkavm-linux-raw 0.9.0", +] + +[[package]] +name = "polkavm" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57e79a14b15ed38cb5b9a1e38d02e933f19e3d180ae5b325fed606c5e5b9177e" +dependencies = [ + "libc", + "log", + "polkavm-assembler 0.13.0", + "polkavm-common 0.13.0", + "polkavm-linux-raw 0.13.0", ] [[package]] @@ -15004,6 +16224,21 @@ dependencies = [ "log", ] +[[package]] +name = "polkavm-assembler" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e8da55465000feb0a61bbf556ed03024db58f3420eca37721fc726b3b2136bf" +dependencies = [ + "log", +] + +[[package]] +name = "polkavm-common" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92c99f7eee94e7be43ba37eef65ad0ee8cbaf89b7c00001c3f6d2be985cb1817" + [[package]] name = "polkavm-common" version = "0.9.0" @@ -15013,13 +16248,54 @@ dependencies = [ "log", ] +[[package]] +name = "polkavm-common" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084b4339aae7dfdaaa5aa7d634110afd95970e0737b6fb2a0cb10db8b56b753c" +dependencies = [ + "blake3", + "log", + "polkavm-assembler 0.13.0", +] + +[[package]] +name = "polkavm-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79fa916f7962348bd1bb1a65a83401675e6fc86c51a0fdbcf92a3108e58e6125" +dependencies = [ + "polkavm-derive-impl-macro 0.8.0", +] + [[package]] name = "polkavm-derive" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae8c4bea6f3e11cd89bb18bcdddac10bd9a24015399bd1c485ad68a985a19606" dependencies = [ - "polkavm-derive-impl-macro", + "polkavm-derive-impl-macro 0.9.0", +] + +[[package]] +name = "polkavm-derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4456b9657b2abd04ac41a61c99e206b7410f93daf0e9b42b49089508d836c40" +dependencies = [ + "polkavm-derive-impl-macro 0.13.0", +] + +[[package]] +name = "polkavm-derive-impl" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c10b2654a8a10a83c260bfb93e97b262cf0017494ab94a65d389e0eda6de6c9c" +dependencies = [ + "polkavm-common 0.8.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -15028,10 +16304,32 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c4fdfc49717fb9a196e74a5d28e0bc764eb394a2c803eb11133a31ac996c60c" dependencies = [ - "polkavm-common", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "polkavm-common 0.9.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", +] + +[[package]] +name = "polkavm-derive-impl" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e4f2c19e7ccc53d8e21429e83b6589bd4139d15481e455a90ba4335a4decb5a" +dependencies = [ + "polkavm-common 0.13.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", +] + +[[package]] +name = "polkavm-derive-impl-macro" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15e85319a0d5129dc9f021c62607e0804f5fb777a05cdda44d750ac0732def66" +dependencies = [ + "polkavm-derive-impl 0.8.0", + "syn 2.0.82", ] [[package]] @@ -15040,8 +16338,18 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ba81f7b5faac81e528eb6158a6f3c9e0bb1008e0ffa19653bc8dea925ecb429" dependencies = [ - "polkavm-derive-impl", - "syn 2.0.61", + "polkavm-derive-impl 0.9.0", + "syn 2.0.82", +] + +[[package]] +name = "polkavm-derive-impl-macro" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6f3ad876ca1855038c21d48cbe35164552208a54b21f8295a7d76bc33ef1e38" +dependencies = [ + "polkavm-derive-impl 0.13.0", + "syn 2.0.82", ] [[package]] @@ -15051,10 +16359,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7be503e60cf56c0eb785f90aaba4b583b36bff00e93997d93fef97f9553c39" dependencies = [ "gimli 0.28.0", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "log", "object 0.32.2", - "polkavm-common", + "polkavm-common 0.9.0", + "regalloc2 0.9.3", + "rustc-demangle", +] + +[[package]] +name = "polkavm-linker" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa6e5a396abf195289d6d63d70182e59a7c27b9b06d0b7361317df05c07c8a8" +dependencies = [ + "gimli 0.28.0", + "hashbrown 0.14.5", + "log", + "object 0.36.1", + "polkavm-common 0.13.0", "regalloc2 0.9.3", "rustc-demangle", ] @@ -15065,6 +16388,12 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26e85d3456948e650dff0cfc85603915847faf893ed1e66b020bb82ef4557120" +[[package]] +name = "polkavm-linux-raw" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686c4dd9c9c16cc22565b51bdbb269792318d0fd2e6b966b5f6c788534cad0e9" + [[package]] name = "polling" version = "2.8.0" @@ -15090,7 +16419,7 @@ dependencies = [ "cfg-if", "concurrent-queue", "pin-project-lite", - "rustix 0.38.21", + "rustix 0.38.25", "tracing", "windows-sys 0.52.0", ] @@ -15133,6 +16462,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" @@ -15153,6 +16488,19 @@ dependencies = [ "thiserror", ] +[[package]] +name = "pprof_util" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c620a1858d6ebf10d7c60256629078b2d106968d0e6ff63b850d9ecd84008fbe" +dependencies = [ + "anyhow", + "flate2", + "num", + "paste", + "prost 0.11.9", +] + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -15213,37 +16561,41 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.1.25" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" dependencies = [ - "proc-macro2 1.0.82", - "syn 1.0.109", + "proc-macro2 1.0.86", + "syn 2.0.82", ] [[package]] -name = "prettyplease" -version = "0.2.12" +name = "primitive-types" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ - "proc-macro2 1.0.82", - "syn 2.0.61", + "fixed-hash", + "impl-codec 0.6.0", + "impl-num-traits 0.1.2", + "impl-serde 0.4.0", + "scale-info", + "uint 0.9.5", ] [[package]] name = "primitive-types" -version = "0.12.1" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +checksum = "d15600a7d856470b7d278b3fe0e311fe28c2526348549f8ef2ff7db3299c87f5" dependencies = [ "fixed-hash", - "impl-codec", - "impl-num-traits", + "impl-codec 0.7.0", + "impl-num-traits 0.2.0", "impl-rlp", - "impl-serde", + "impl-serde 0.5.0", "scale-info", - "uint", + "uint 0.10.0", ] [[package]] @@ -15288,8 +16640,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", "version_check", ] @@ -15300,8 +16652,8 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "version_check", ] @@ -15317,9 +16669,9 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1eaa7fa0aa1929ffdf7eeb6eac234dde6268914a14ad44d23521ab6a9b258e" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -15328,9 +16680,9 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b698b0b09d40e9b7c1a47b132d66a8b54bcd20583d9b6d06e4535e383b4405c" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -15344,9 +16696,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -15363,7 +16715,7 @@ dependencies = [ "hex", "lazy_static", "procfs-core", - "rustix 0.38.21", + "rustix 0.38.25", ] [[package]] @@ -15409,9 +16761,9 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -15467,45 +16819,33 @@ dependencies = [ ] [[package]] -name = "prost-build" -version = "0.11.9" +name = "prost" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +checksum = "3b2ecbe40f08db5c006b5764a2645f7f3f141ce756412ac9e1dd6087e6d32995" dependencies = [ "bytes", - "heck 0.4.1", - "itertools 0.10.5", - "lazy_static", - "log", - "multimap", - "petgraph", - "prettyplease 0.1.25", - "prost 0.11.9", - "prost-types 0.11.9", - "regex", - "syn 1.0.109", - "tempfile", - "which", + "prost-derive 0.13.2", ] [[package]] name = "prost-build" -version = "0.12.4" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80b776a1b2dc779f5ee0641f8ade0125bc1298dd41a9a0c16d8bd57b42d222b1" +checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" dependencies = [ "bytes", - "heck 0.5.0", - "itertools 0.11.0", + "heck 0.4.1", + "itertools 0.10.5", "log", "multimap", "once_cell", "petgraph", - "prettyplease 0.2.12", - "prost 0.12.6", - "prost-types 0.12.4", + "prettyplease", + "prost 0.13.2", + "prost-types", "regex", - "syn 2.0.61", + "syn 2.0.82", "tempfile", ] @@ -15517,8 +16857,8 @@ checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", "itertools 0.10.5", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -15529,28 +16869,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.11.0", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "itertools 0.10.5", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] -name = "prost-types" -version = "0.11.9" +name = "prost-derive" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" dependencies = [ - "prost 0.11.9", -] + "anyhow", + "itertools 0.10.5", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", +] [[package]] name = "prost-types" -version = "0.12.4" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3235c33eb02c1f1e212abdbe34c78b264b038fb58ca612664343271e36e55ffe" +checksum = "60caa6738c7369b940c3d49246a8d1749323674c65cb13010134f5c9bad5b519" dependencies = [ - "prost 0.12.6", + "prost 0.13.2", ] [[package]] @@ -15574,7 +16918,7 @@ dependencies = [ "log", "names", "prost 0.11.9", - "reqwest", + "reqwest 0.11.20", "thiserror", "url", "winapi", @@ -15614,6 +16958,15 @@ version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +[[package]] +name = "quick-protobuf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e489d4a83c17ea69b0291630229b5d4c92a94a3bf0165f7f72f506e94cda8b4b" +dependencies = [ + "byteorder", +] + [[package]] name = "quick-protobuf" version = "0.8.1" @@ -15631,7 +16984,7 @@ checksum = "f8ededb1cd78531627244d51dd0c7139fbe736c7d57af0092a76f0ffb2f56e98" dependencies = [ "asynchronous-codec", "bytes", - "quick-protobuf", + "quick-protobuf 0.8.1", "thiserror", "unsigned-varint 0.7.2", ] @@ -15660,35 +17013,35 @@ dependencies = [ [[package]] name = "quinn" -version = "0.9.4" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e8b432585672228923edbbf64b8b12c14e1112f62e88737655b4a083dbcd78e" +checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" dependencies = [ "bytes", + "futures-io", "pin-project-lite", - "quinn-proto 0.9.6", - "quinn-udp 0.3.2", - "rustc-hash", - "rustls 0.20.9", + "quinn-proto 0.10.6", + "quinn-udp 0.4.1", + "rustc-hash 1.1.0", + "rustls 0.21.7", "thiserror", "tokio", "tracing", - "webpki", ] [[package]] name = "quinn" -version = "0.10.2" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ "bytes", - "futures-io", "pin-project-lite", - "quinn-proto 0.10.6", - "quinn-udp 0.4.1", - "rustc-hash", - "rustls 0.21.7", + "quinn-proto 0.11.8", + "quinn-udp 0.5.4", + "rustc-hash 2.0.0", + "rustls 0.23.10", + "socket2 0.5.7", "thiserror", "tokio", "tracing", @@ -15696,33 +17049,32 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.9.6" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b0b33c13a79f669c85defaf4c275dc86a0c0372807d0ca3d78e0bb87274863" +checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" dependencies = [ "bytes", "rand", "ring 0.16.20", - "rustc-hash", - "rustls 0.20.9", + "rustc-hash 1.1.0", + "rustls 0.21.7", "slab", "thiserror", "tinyvec", "tracing", - "webpki", ] [[package]] name = "quinn-proto" -version = "0.10.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes", "rand", - "ring 0.16.20", - "rustc-hash", - "rustls 0.21.7", + "ring 0.17.7", + "rustc-hash 2.0.0", + "rustls 0.23.10", "slab", "thiserror", "tinyvec", @@ -15731,28 +17083,28 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.3.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "641538578b21f5e5c8ea733b736895576d0fe329bb883b937db6f4d163dbaaf4" +checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" dependencies = [ + "bytes", "libc", - "quinn-proto 0.9.6", - "socket2 0.4.9", + "socket2 0.5.7", "tracing", - "windows-sys 0.42.0", + "windows-sys 0.48.0", ] [[package]] name = "quinn-udp" -version = "0.4.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" +checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" dependencies = [ - "bytes", "libc", + "once_cell", "socket2 0.5.7", "tracing", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -15766,11 +17118,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ - "proc-macro2 1.0.82", + "proc-macro2 1.0.86", ] [[package]] @@ -15787,7 +17139,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -15797,9 +17149,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" + [[package]] name = "rand_core" version = "0.6.4" @@ -15825,7 +17183,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e" dependencies = [ - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -15834,7 +17192,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -15898,12 +17256,28 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ - "pem", + "pem 1.1.1", "ring 0.16.20", "time", "yasna", ] +[[package]] +name = "reconnecting-jsonrpsee-ws-client" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06fa4f17e09edfc3131636082faaec633c7baa269396b4004040bc6c52f49f65" +dependencies = [ + "cfg_aliases 0.2.1", + "finito", + "futures", + "jsonrpsee 0.23.2", + "serde_json", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -15956,22 +17330,22 @@ 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", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -15994,20 +17368,20 @@ checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" dependencies = [ "hashbrown 0.13.2", "log", - "rustc-hash", + "rustc-hash 1.1.0", "slice-group-by", "smallvec", ] [[package]] name = "regex" -version = "1.10.2" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.3", + "regex-automata 0.4.7", "regex-syntax 0.8.2", ] @@ -16028,9 +17402,9 @@ checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -16068,7 +17442,7 @@ dependencies = [ "finality-relay", "frame-support", "futures", - "jsonrpsee", + "jsonrpsee 0.24.3", "log", "num-traits", "pallet-transaction-payment", @@ -16084,12 +17458,12 @@ dependencies = [ "scale-info", "serde_json", "sp-consensus-grandpa", - "sp-core", + "sp-core 28.0.0", "sp-rpc", - "sp-runtime", + "sp-runtime 31.0.1", "sp-std 14.0.0", - "sp-trie", - "sp-version", + "sp-trie 29.0.0", + "sp-version 29.0.0", "staging-xcm", "thiserror", "tokio", @@ -16099,13 +17473,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", @@ -16113,7 +17486,8 @@ dependencies = [ "num-traits", "parking_lot 0.12.3", "serde_json", - "sp-runtime", + "sp-runtime 31.0.1", + "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "sysinfo", "thiserror", @@ -16125,11 +17499,11 @@ dependencies = [ name = "remote-ext-tests-bags-list" version = "1.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.13", "frame-system", "log", "pallet-bags-list-remote-tests", - "sp-core", + "sp-core 28.0.0", "sp-tracing 16.0.0", "tokio", "westend-runtime", @@ -16142,7 +17516,7 @@ version = "0.11.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" dependencies = [ - "base64 0.21.2", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -16152,10 +17526,12 @@ dependencies = [ "http-body 0.4.5", "hyper 0.14.29", "hyper-rustls 0.24.2", + "hyper-tls", "ipnet", "js-sys", "log", "mime", + "native-tls", "once_cell", "percent-encoding", "pin-project-lite", @@ -16165,6 +17541,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "tokio", + "tokio-native-tls", "tokio-rustls 0.24.1", "tower-service", "url", @@ -16172,7 +17549,50 @@ dependencies = [ "wasm-bindgen-futures", "web-sys", "webpki-roots 0.25.2", - "winreg", + "winreg 0.50.0", +] + +[[package]] +name = "reqwest" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.3.1", + "hyper-rustls 0.27.2", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "quinn 0.11.5", + "rustls 0.23.10", + "rustls-pemfile 2.0.0", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls 0.26.0", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 0.26.3", + "winreg 0.52.0", ] [[package]] @@ -16198,13 +17618,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", @@ -16240,6 +17661,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "rle-decode-fast" version = "1.0.3" @@ -16256,6 +17686,16 @@ dependencies = [ "rustc-hex", ] +[[package]] +name = "rlp" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa24e92bb2a83198bb76d661a71df9f7076b8c420b8696e4d3d97d50d94479e3" +dependencies = [ + "bytes", + "rustc-hex", +] + [[package]] name = "rocksdb" version = "0.21.0" @@ -16279,7 +17719,8 @@ dependencies = [ "sp-authority-discovery", "sp-consensus-babe", "sp-consensus-beefy", - "sp-core", + "sp-core 28.0.0", + "sp-keyring", ] [[package]] @@ -16314,17 +17755,17 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-runtime-common", "scale-info", - "sp-api", + "sp-api 26.0.0", "sp-block-builder", "sp-consensus-aura", - "sp-core", + "sp-core 28.0.0", "sp-genesis-builder", "sp-inherents", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-transaction-pool", - "sp-version", + "sp-version 29.0.0", "staging-parachain-info", "staging-xcm", "staging-xcm-builder", @@ -16407,28 +17848,28 @@ dependencies = [ "serde_derive", "serde_json", "smallvec", - "sp-api", - "sp-arithmetic", + "sp-api 26.0.0", + "sp-arithmetic 23.0.0", "sp-authority-discovery", "sp-block-builder", "sp-consensus-babe", "sp-consensus-beefy", "sp-consensus-grandpa", - "sp-core", + "sp-core 28.0.0", "sp-genesis-builder", "sp-inherents", - "sp-io", + "sp-io 30.0.0", "sp-keyring", "sp-mmr-primitives", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-staking", "sp-storage 19.0.0", "sp-tracing 16.0.0", "sp-transaction-pool", - "sp-trie", - "sp-version", + "sp-trie 29.0.0", + "sp-version 29.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -16447,9 +17888,9 @@ dependencies = [ "polkadot-primitives", "polkadot-runtime-common", "smallvec", - "sp-core", - "sp-runtime", - "sp-weights", + "sp-core 28.0.0", + "sp-runtime 31.0.1", + "sp-weights 27.0.0", "staging-xcm", "staging-xcm-builder", ] @@ -16460,6 +17901,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", @@ -16517,12 +17959,12 @@ checksum = "d428f8247852f894ee1be110b375111b586d4fa431f6c46e64ba5a0dcccbe605" dependencies = [ "cfg-if", "glob", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "regex", "relative-path", "rustc_version 0.4.0", - "syn 2.0.61", + "syn 2.0.82", "unicode-ident", ] @@ -16553,9 +17995,9 @@ dependencies = [ [[package]] name = "ruint" -version = "1.11.1" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608a5726529f2f0ef81b8fde9873c4bb829d6b5b5ca6be4d97345ddf0749c825" +checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", @@ -16565,10 +18007,10 @@ dependencies = [ "num-bigint", "num-traits", "parity-scale-codec", - "primitive-types", + "primitive-types 0.12.2", "proptest", "rand", - "rlp", + "rlp 0.5.2", "ruint-macro", "serde", "valuable", @@ -16577,9 +18019,9 @@ dependencies = [ [[package]] name = "ruint-macro" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e666a5496a0b2186dbcd0ff6106e29e093c15591bde62c20d3842007c6978a09" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" [[package]] name = "rustc-demangle" @@ -16593,6 +18035,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "rustc-hex" version = "2.1.0" @@ -16665,14 +18113,14 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.21" +version = "0.38.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" dependencies = [ "bitflags 2.6.0", "errno", "libc", - "linux-raw-sys 0.4.10", + "linux-raw-sys 0.4.11", "windows-sys 0.48.0", ] @@ -16699,6 +18147,20 @@ dependencies = [ "sct", ] +[[package]] +name = "rustls" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring 0.17.7", + "rustls-pki-types", + "rustls-webpki 0.102.4", + "subtle 2.5.0", + "zeroize", +] + [[package]] name = "rustls" version = "0.23.10" @@ -16745,7 +18207,7 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.2", + "base64 0.21.7", ] [[package]] @@ -16754,7 +18216,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4" dependencies = [ - "base64 0.21.2", + "base64 0.21.7", "rustls-pki-types", ] @@ -16814,9 +18276,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "rusty-fork" @@ -16841,6 +18303,17 @@ dependencies = [ "twox-hash", ] +[[package]] +name = "ruzstd" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d" +dependencies = [ + "byteorder", + "derive_more", + "twox-hash", +] + [[package]] name = "rw-stream-sink" version = "0.4.0" @@ -16890,11 +18363,23 @@ name = "sc-allocator" version = "23.0.0" dependencies = [ "log", - "sp-core", + "sp-core 28.0.0", "sp-wasm-interface 20.0.0", "thiserror", ] +[[package]] +name = "sc-allocator" +version = "28.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f01218e73ea57916be5f08987995ac802d6f4ede4ea5ce0242e468c590e4e2" +dependencies = [ + "log", + "sp-core 33.0.1", + "sp-wasm-interface 21.0.0", + "thiserror", +] + [[package]] name = "sc-authority-discovery" version = "0.34.0" @@ -16909,18 +18394,18 @@ dependencies = [ "multihash 0.19.1", "parity-scale-codec", "prost 0.12.6", - "prost-build 0.12.4", + "prost-build", "quickcheck", "rand", "sc-client-api", "sc-network", "sc-network-types", - "sp-api", + "sp-api 26.0.0", "sp-authority-discovery", "sp-blockchain", - "sp-core", - "sp-keystore", - "sp-runtime", + "sp-core 28.0.0", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", @@ -16942,12 +18427,12 @@ dependencies = [ "sc-telemetry", "sc-transaction-pool", "sc-transaction-pool-api", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", "sp-consensus", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-runtime", + "sp-runtime 31.0.1", "substrate-prometheus-endpoint", "substrate-test-runtime-client", ] @@ -16957,14 +18442,14 @@ name = "sc-block-builder" version = "0.33.0" dependencies = [ "parity-scale-codec", - "sp-api", + "sp-api 26.0.0", "sp-block-builder", "sp-blockchain", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-runtime", - "sp-state-machine", - "sp-trie", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", + "sp-trie 29.0.0", "substrate-test-runtime-client", ] @@ -16973,7 +18458,7 @@ name = "sc-chain-spec" version = "28.0.0" dependencies = [ "array-bytes", - "clap 4.5.3", + "clap 4.5.13", "docify", "log", "memmap2 0.9.3", @@ -16981,21 +18466,21 @@ dependencies = [ "regex", "sc-chain-spec-derive", "sc-client-api", - "sc-executor", + "sc-executor 0.32.0", "sc-network", "sc-telemetry", "serde", "serde_json", - "sp-application-crypto", + "sp-application-crypto 30.0.0", "sp-blockchain", "sp-consensus-babe", - "sp-core", - "sp-crypto-hashing", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", "sp-genesis-builder", - "sp-io", + "sp-io 30.0.0", "sp-keyring", - "sp-runtime", - "sp-state-machine", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "sp-tracing 16.0.0", "substrate-test-runtime", ] @@ -17005,9 +18490,9 @@ name = "sc-chain-spec-derive" version = "11.0.0" dependencies = [ "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -17016,7 +18501,7 @@ version = "0.36.0" dependencies = [ "array-bytes", "chrono", - "clap 4.5.3", + "clap 4.5.13", "fdlimit", "futures", "futures-timer", @@ -17037,17 +18522,18 @@ dependencies = [ "sc-service", "sc-telemetry", "sc-tracing", + "sc-transaction-pool", "sc-utils", "serde", "serde_json", "sp-blockchain", - "sp-core", + "sp-core 28.0.0", "sp-keyring", - "sp-keystore", - "sp-panic-handler", - "sp-runtime", + "sp-keystore 0.34.0", + "sp-panic-handler 13.0.0", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", - "sp-version", + "sp-version 29.0.0", "tempfile", "thiserror", "tokio", @@ -17062,21 +18548,21 @@ dependencies = [ "log", "parity-scale-codec", "parking_lot 0.12.3", - "sc-executor", + "sc-executor 0.32.0", "sc-transaction-pool-api", "sc-utils", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", "sp-consensus", - "sp-core", + "sp-core 28.0.0", "sp-database", "sp-externalities 0.25.0", - "sp-runtime", - "sp-state-machine", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "sp-statement-store", "sp-storage 19.0.0", "sp-test-primitives", - "sp-trie", + "sp-trie 29.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime", "thiserror", @@ -17103,14 +18589,14 @@ dependencies = [ "sc-client-api", "sc-state-db", "schnellru", - "sp-arithmetic", + "sp-arithmetic 23.0.0", "sp-blockchain", - "sp-core", + "sp-core 28.0.0", "sp-database", - "sp-runtime", - "sp-state-machine", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "sp-tracing 16.0.0", - "sp-trie", + "sp-trie 29.0.0", "substrate-test-runtime-client", "tempfile", ] @@ -17128,12 +18614,12 @@ dependencies = [ "sc-network-types", "sc-utils", "serde", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", "sp-consensus", - "sp-core", - "sp-runtime", - "sp-state-machine", + "sp-core 28.0.0", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "sp-test-primitives", "substrate-prometheus-endpoint", "thiserror", @@ -17156,18 +18642,18 @@ dependencies = [ "sc-network", "sc-network-test", "sc-telemetry", - "sp-api", - "sp-application-crypto", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", "sp-block-builder", "sp-blockchain", "sp-consensus", "sp-consensus-aura", "sp-consensus-slots", - "sp-core", + "sp-core 28.0.0", "sp-inherents", "sp-keyring", - "sp-keystore", - "sp-runtime", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", "sp-timestamp", "sp-tracing 16.0.0", "substrate-prometheus-endpoint", @@ -17198,19 +18684,19 @@ dependencies = [ "sc-network-test", "sc-telemetry", "sc-transaction-pool-api", - "sp-api", - "sp-application-crypto", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", "sp-block-builder", "sp-blockchain", "sp-consensus", "sp-consensus-babe", "sp-consensus-slots", - "sp-core", - "sp-crypto-hashing", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", "sp-inherents", "sp-keyring", - "sp-keystore", - "sp-runtime", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", "sp-timestamp", "sp-tracing 16.0.0", "substrate-prometheus-endpoint", @@ -17224,7 +18710,7 @@ name = "sc-consensus-babe-rpc" version = "0.34.0" dependencies = [ "futures", - "jsonrpsee", + "jsonrpsee 0.24.3", "sc-consensus", "sc-consensus-babe", "sc-consensus-epochs", @@ -17233,15 +18719,15 @@ dependencies = [ "sc-transaction-pool-api", "serde", "serde_json", - "sp-api", - "sp-application-crypto", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", "sp-blockchain", "sp-consensus", "sp-consensus-babe", - "sp-core", + "sp-core 28.0.0", "sp-keyring", - "sp-keystore", - "sp-runtime", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", "substrate-test-runtime-client", "thiserror", "tokio", @@ -17252,7 +18738,7 @@ name = "sc-consensus-beefy" version = "13.0.0" dependencies = [ "array-bytes", - "async-channel", + "async-channel 1.9.0", "async-trait", "fnv", "futures", @@ -17269,19 +18755,19 @@ dependencies = [ "sc-network-types", "sc-utils", "serde", - "sp-api", - "sp-application-crypto", - "sp-arithmetic", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", + "sp-arithmetic 23.0.0", "sp-blockchain", "sp-consensus", "sp-consensus-beefy", "sp-consensus-grandpa", - "sp-core", - "sp-crypto-hashing", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", "sp-keyring", - "sp-keystore", + "sp-keystore 0.34.0", "sp-mmr-primitives", - "sp-runtime", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", @@ -17296,7 +18782,7 @@ name = "sc-consensus-beefy-rpc" version = "13.0.0" dependencies = [ "futures", - "jsonrpsee", + "jsonrpsee 0.24.3", "log", "parity-scale-codec", "parking_lot 0.12.3", @@ -17304,10 +18790,10 @@ dependencies = [ "sc-rpc", "serde", "serde_json", - "sp-application-crypto", + "sp-application-crypto 30.0.0", "sp-consensus-beefy", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "substrate-test-runtime-client", "thiserror", "tokio", @@ -17322,7 +18808,7 @@ dependencies = [ "sc-client-api", "sc-consensus", "sp-blockchain", - "sp-runtime", + "sp-runtime 31.0.1", ] [[package]] @@ -17357,17 +18843,17 @@ dependencies = [ "sc-utils", "serde", "serde_json", - "sp-api", - "sp-application-crypto", - "sp-arithmetic", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", + "sp-arithmetic 23.0.0", "sp-blockchain", "sp-consensus", "sp-consensus-grandpa", - "sp-core", - "sp-crypto-hashing", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", "sp-keyring", - "sp-keystore", - "sp-runtime", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "substrate-test-runtime-client", @@ -17381,7 +18867,7 @@ version = "0.19.0" dependencies = [ "finality-grandpa", "futures", - "jsonrpsee", + "jsonrpsee 0.24.3", "log", "parity-scale-codec", "sc-block-builder", @@ -17391,9 +18877,9 @@ dependencies = [ "serde", "sp-blockchain", "sp-consensus-grandpa", - "sp-core", + "sp-core 28.0.0", "sp-keyring", - "sp-runtime", + "sp-runtime 31.0.1", "substrate-test-runtime-client", "thiserror", "tokio", @@ -17407,7 +18893,7 @@ dependencies = [ "async-trait", "futures", "futures-timer", - "jsonrpsee", + "jsonrpsee 0.24.3", "log", "parity-scale-codec", "sc-basic-authorship", @@ -17419,16 +18905,16 @@ dependencies = [ "sc-transaction-pool", "sc-transaction-pool-api", "serde", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", "sp-consensus", "sp-consensus-aura", "sp-consensus-babe", "sp-consensus-slots", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-keystore", - "sp-runtime", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", "sp-timestamp", "substrate-prometheus-endpoint", "substrate-test-runtime-client", @@ -17449,14 +18935,14 @@ dependencies = [ "parking_lot 0.12.3", "sc-client-api", "sc-consensus", - "sp-api", + "sp-api 26.0.0", "sp-block-builder", "sp-blockchain", "sp-consensus", "sp-consensus-pow", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-runtime", + "sp-runtime 31.0.1", "substrate-prometheus-endpoint", "thiserror", ] @@ -17473,14 +18959,14 @@ dependencies = [ "sc-client-api", "sc-consensus", "sc-telemetry", - "sp-arithmetic", + "sp-arithmetic 23.0.0", "sp-blockchain", "sp-consensus", "sp-consensus-slots", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-runtime", - "sp-state-machine", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "substrate-test-runtime-client", ] @@ -17491,31 +18977,30 @@ dependencies = [ "array-bytes", "assert_matches", "criterion", - "env_logger 0.11.3", "num_cpus", "parity-scale-codec", "parking_lot 0.12.3", "paste", "regex", - "sc-executor-common", - "sc-executor-polkavm", - "sc-executor-wasmtime", + "sc-executor-common 0.29.0", + "sc-executor-polkavm 0.29.0", + "sc-executor-wasmtime 0.29.0", "sc-runtime-test", "sc-tracing", "schnellru", - "sp-api", - "sp-core", - "sp-crypto-hashing", + "sp-api 26.0.0", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", "sp-externalities 0.25.0", - "sp-io", - "sp-maybe-compressed-blob", - "sp-panic-handler", - "sp-runtime", + "sp-io 30.0.0", + "sp-maybe-compressed-blob 11.0.0", + "sp-panic-handler 13.0.0", + "sp-runtime 31.0.1", "sp-runtime-interface 24.0.0", - "sp-state-machine", + "sp-state-machine 0.35.0", "sp-tracing 16.0.0", - "sp-trie", - "sp-version", + "sp-trie 29.0.0", + "sp-version 29.0.0", "sp-wasm-interface 20.0.0", "substrate-test-runtime", "tempfile", @@ -17524,28 +19009,78 @@ dependencies = [ "wat", ] +[[package]] +name = "sc-executor" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "321e9431a3d5c95514b1ba775dd425efd4b18bd79dfdb6d8e397f0c96d6831e9" +dependencies = [ + "parity-scale-codec", + "parking_lot 0.12.3", + "sc-executor-common 0.34.0", + "sc-executor-polkavm 0.31.0", + "sc-executor-wasmtime 0.34.0", + "schnellru", + "sp-api 32.0.0", + "sp-core 33.0.1", + "sp-externalities 0.28.0", + "sp-io 36.0.0", + "sp-panic-handler 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-runtime-interface 27.0.0", + "sp-trie 35.0.0", + "sp-version 35.0.0", + "sp-wasm-interface 21.0.0", + "tracing", +] + [[package]] name = "sc-executor-common" version = "0.29.0" dependencies = [ - "polkavm", - "sc-allocator", - "sp-maybe-compressed-blob", + "polkavm 0.9.3", + "sc-allocator 23.0.0", + "sp-maybe-compressed-blob 11.0.0", "sp-wasm-interface 20.0.0", "thiserror", "wasm-instrument", ] +[[package]] +name = "sc-executor-common" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aad16187c613f81feab35f0d6c12c15c1d88eea0794c886b5dca3495d26746de" +dependencies = [ + "polkavm 0.9.3", + "sc-allocator 28.0.0", + "sp-maybe-compressed-blob 11.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-wasm-interface 21.0.0", + "thiserror", + "wasm-instrument", +] + [[package]] name = "sc-executor-polkavm" version = "0.29.0" dependencies = [ "log", - "polkavm", - "sc-executor-common", + "polkavm 0.9.3", + "sc-executor-common 0.29.0", "sp-wasm-interface 20.0.0", ] +[[package]] +name = "sc-executor-polkavm" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db336a08ea53b6a89972a6ad6586e664c15db2add9d1cfb508afc768de387304" +dependencies = [ + "log", + "polkavm 0.9.3", + "sc-executor-common 0.34.0", + "sp-wasm-interface 21.0.0", +] + [[package]] name = "sc-executor-wasmtime" version = "0.29.0" @@ -17559,10 +19094,10 @@ dependencies = [ "parking_lot 0.12.3", "paste", "rustix 0.36.15", - "sc-allocator", - "sc-executor-common", + "sc-allocator 23.0.0", + "sc-executor-common 0.29.0", "sc-runtime-test", - "sp-io", + "sp-io 30.0.0", "sp-runtime-interface 24.0.0", "sp-wasm-interface 20.0.0", "tempfile", @@ -17570,11 +19105,30 @@ dependencies = [ "wat", ] +[[package]] +name = "sc-executor-wasmtime" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b97b324b2737447b7b208e913fef4988d5c38ecc21f57c3dd33e3f1e1e3bb08" +dependencies = [ + "anyhow", + "cfg-if", + "libc", + "log", + "parking_lot 0.12.3", + "rustix 0.36.15", + "sc-allocator 28.0.0", + "sc-executor-common 0.34.0", + "sp-runtime-interface 27.0.0", + "sp-wasm-interface 21.0.0", + "wasmtime", +] + [[package]] name = "sc-informant" version = "0.33.0" dependencies = [ - "ansi_term", + "console", "futures", "futures-timer", "log", @@ -17583,7 +19137,7 @@ dependencies = [ "sc-network-common", "sc-network-sync", "sp-blockchain", - "sp-runtime", + "sp-runtime 31.0.1", ] [[package]] @@ -17593,9 +19147,9 @@ dependencies = [ "array-bytes", "parking_lot 0.12.3", "serde_json", - "sp-application-crypto", - "sp-core", - "sp-keystore", + "sp-application-crypto 30.0.0", + "sp-core 28.0.0", + "sp-keystore 0.34.0", "tempfile", "thiserror", ] @@ -17619,12 +19173,12 @@ dependencies = [ "sc-network", "sc-network-types", "sc-transaction-pool-api", - "sp-api", + "sp-api 26.0.0", "sp-consensus", - "sp-core", - "sp-keystore", + "sp-core 28.0.0", + "sp-keystore 0.34.0", "sp-mixnet", - "sp-runtime", + "sp-runtime 31.0.1", "thiserror", ] @@ -17634,7 +19188,7 @@ version = "0.34.0" dependencies = [ "array-bytes", "assert_matches", - "async-channel", + "async-channel 1.9.0", "async-trait", "asynchronous-codec", "bytes", @@ -17656,7 +19210,7 @@ dependencies = [ "partial_sort", "pin-project", "prost 0.12.6", - "prost-build 0.12.4", + "prost-build", "rand", "sc-block-builder", "sc-client-api", @@ -17669,12 +19223,12 @@ dependencies = [ "serde", "serde_json", "smallvec", - "sp-arithmetic", + "sp-arithmetic 23.0.0", "sp-blockchain", "sp-consensus", - "sp-core", - "sp-crypto-hashing", - "sp-runtime", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", + "sp-runtime 31.0.1", "sp-test-primitives", "sp-tracing 16.0.0", "substrate-prometheus-endpoint", @@ -17701,12 +19255,12 @@ dependencies = [ "futures", "libp2p-identity", "parity-scale-codec", - "prost-build 0.12.4", + "prost-build", "sc-consensus", "sc-network-types", "sp-consensus", "sp-consensus-grandpa", - "sp-runtime", + "sp-runtime 31.0.1", "tempfile", ] @@ -17726,7 +19280,7 @@ dependencies = [ "sc-network-sync", "sc-network-types", "schnellru", - "sp-runtime", + "sp-runtime 31.0.1", "substrate-prometheus-endpoint", "substrate-test-runtime-client", "tokio", @@ -17738,18 +19292,18 @@ name = "sc-network-light" version = "0.33.0" dependencies = [ "array-bytes", - "async-channel", + "async-channel 1.9.0", "futures", "log", "parity-scale-codec", "prost 0.12.6", - "prost-build 0.12.4", + "prost-build", "sc-client-api", "sc-network", "sc-network-types", "sp-blockchain", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "thiserror", ] @@ -17758,7 +19312,7 @@ name = "sc-network-statement" version = "0.16.0" dependencies = [ "array-bytes", - "async-channel", + "async-channel 1.9.0", "futures", "log", "parity-scale-codec", @@ -17767,7 +19321,7 @@ dependencies = [ "sc-network-sync", "sc-network-types", "sp-consensus", - "sp-runtime", + "sp-runtime 31.0.1", "sp-statement-store", "substrate-prometheus-endpoint", ] @@ -17777,17 +19331,16 @@ name = "sc-network-sync" version = "0.33.0" dependencies = [ "array-bytes", - "async-channel", + "async-channel 1.9.0", "async-trait", "fork-tree", "futures", "futures-timer", - "libp2p", "log", "mockall 0.11.4", "parity-scale-codec", "prost 0.12.6", - "prost-build 0.12.4", + "prost-build", "quickcheck", "sc-block-builder", "sc-client-api", @@ -17798,12 +19351,12 @@ dependencies = [ "sc-utils", "schnellru", "smallvec", - "sp-arithmetic", + "sp-arithmetic 23.0.0", "sp-blockchain", "sp-consensus", "sp-consensus-grandpa", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "sp-test-primitives", "sp-tracing 16.0.0", "substrate-prometheus-endpoint", @@ -17836,8 +19389,8 @@ dependencies = [ "sc-utils", "sp-blockchain", "sp-consensus", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", "substrate-test-runtime", "substrate-test-runtime-client", @@ -17858,7 +19411,7 @@ dependencies = [ "sc-network-types", "sc-utils", "sp-consensus", - "sp-runtime", + "sp-runtime 31.0.1", "substrate-prometheus-endpoint", ] @@ -17866,7 +19419,7 @@ dependencies = [ name = "sc-network-types" version = "0.10.0" dependencies = [ - "bs58 0.5.0", + "bs58", "ed25519-dalek", "libp2p-identity", "litep2p", @@ -17891,7 +19444,6 @@ dependencies = [ "futures-timer", "hyper 0.14.29", "hyper-rustls 0.24.2", - "lazy_static", "log", "num_cpus", "once_cell", @@ -17907,13 +19459,13 @@ dependencies = [ "sc-transaction-pool", "sc-transaction-pool-api", "sc-utils", - "sp-api", + "sp-api 26.0.0", "sp-consensus", - "sp-core", + "sp-core 28.0.0", "sp-externalities 0.25.0", - "sp-keystore", + "sp-keystore 0.34.0", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", "substrate-test-runtime-client", "threadpool", @@ -17934,9 +19486,8 @@ name = "sc-rpc" version = "29.0.0" dependencies = [ "assert_matches", - "env_logger 0.11.3", "futures", - "jsonrpsee", + "jsonrpsee 0.24.3", "log", "parity-scale-codec", "parking_lot 0.12.3", @@ -17953,29 +19504,28 @@ dependencies = [ "sc-transaction-pool-api", "sc-utils", "serde_json", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", "sp-consensus", - "sp-core", - "sp-crypto-hashing", - "sp-io", - "sp-keystore", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", + "sp-io 30.0.0", + "sp-keystore 0.34.0", "sp-offchain", "sp-rpc", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-statement-store", - "sp-version", + "sp-version 29.0.0", "substrate-test-runtime-client", "tokio", - "tracing-subscriber 0.3.18", ] [[package]] name = "sc-rpc-api" version = "0.33.0" dependencies = [ - "jsonrpsee", + "jsonrpsee 0.24.3", "parity-scale-codec", "sc-chain-spec", "sc-mixnet", @@ -17983,10 +19533,10 @@ dependencies = [ "scale-info", "serde", "serde_json", - "sp-core", + "sp-core 28.0.0", "sp-rpc", - "sp-runtime", - "sp-version", + "sp-runtime 31.0.1", + "sp-version 29.0.0", "thiserror", ] @@ -17994,6 +19544,7 @@ dependencies = [ name = "sc-rpc-server" version = "11.0.0" dependencies = [ + "dyn-clone", "forwarded-header-value", "futures", "governor", @@ -18001,14 +19552,15 @@ dependencies = [ "http-body-util", "hyper 1.3.1", "ip_network", - "jsonrpsee", + "jsonrpsee 0.24.3", "log", + "sc-rpc-api", "serde", "serde_json", "substrate-prometheus-endpoint", "tokio", "tower", - "tower-http", + "tower-http 0.5.2", ] [[package]] @@ -18020,7 +19572,7 @@ dependencies = [ "futures", "futures-util", "hex", - "jsonrpsee", + "jsonrpsee 0.24.3", "log", "parity-scale-codec", "parking_lot 0.12.3", @@ -18037,15 +19589,15 @@ dependencies = [ "schnellru", "serde", "serde_json", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", "sp-consensus", - "sp-core", + "sp-core 28.0.0", "sp-externalities 0.25.0", - "sp-maybe-compressed-blob", + "sp-maybe-compressed-blob 11.0.0", "sp-rpc", - "sp-runtime", - "sp-version", + "sp-runtime 31.0.1", + "sp-version 29.0.0", "substrate-test-runtime", "substrate-test-runtime-client", "substrate-test-runtime-transaction-pool", @@ -18058,9 +19610,9 @@ dependencies = [ name = "sc-runtime-test" version = "2.0.0" dependencies = [ - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-runtime-interface 24.0.0", "substrate-wasm-builder", ] @@ -18074,7 +19626,7 @@ dependencies = [ "exit-future", "futures", "futures-timer", - "jsonrpsee", + "jsonrpsee 0.24.3", "log", "parity-scale-codec", "parking_lot 0.12.3", @@ -18084,7 +19636,7 @@ dependencies = [ "sc-client-api", "sc-client-db", "sc-consensus", - "sc-executor", + "sc-executor 0.32.0", "sc-informant", "sc-keystore", "sc-network", @@ -18105,20 +19657,20 @@ dependencies = [ "schnellru", "serde", "serde_json", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", "sp-consensus", - "sp-core", + "sp-core 28.0.0", "sp-externalities 0.25.0", - "sp-keystore", - "sp-runtime", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", "sp-session", - "sp-state-machine", + "sp-state-machine 0.35.0", "sp-storage 19.0.0", "sp-transaction-pool", "sp-transaction-storage-proof", - "sp-trie", - "sp-version", + "sp-trie 29.0.0", + "sp-version 29.0.0", "static_init", "substrate-prometheus-endpoint", "substrate-test-runtime", @@ -18135,7 +19687,7 @@ name = "sc-service-test" version = "2.0.0" dependencies = [ "array-bytes", - "async-channel", + "async-channel 1.9.0", "fdlimit", "futures", "log", @@ -18145,21 +19697,21 @@ dependencies = [ "sc-client-api", "sc-client-db", "sc-consensus", - "sc-executor", + "sc-executor 0.32.0", "sc-network", "sc-network-sync", "sc-service", "sc-transaction-pool-api", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", "sp-consensus", - "sp-core", - "sp-io", - "sp-runtime", - "sp-state-machine", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "sp-storage 19.0.0", "sp-tracing 16.0.0", - "sp-trie", + "sp-trie 29.0.0", "substrate-test-runtime", "substrate-test-runtime-client", "tempfile", @@ -18173,24 +19725,24 @@ dependencies = [ "log", "parity-scale-codec", "parking_lot 0.12.3", - "sp-core", + "sp-core 28.0.0", ] [[package]] name = "sc-statement-store" version = "10.0.0" dependencies = [ - "env_logger 0.11.3", "log", "parity-db", "parking_lot 0.12.3", "sc-client-api", "sc-keystore", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "sp-statement-store", + "sp-tracing 16.0.0", "substrate-prometheus-endpoint", "tempfile", "tokio", @@ -18200,10 +19752,10 @@ dependencies = [ name = "sc-storage-monitor" version = "0.16.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.13", "fs4", "log", - "sp-core", + "sp-core 28.0.0", "thiserror", "tokio", ] @@ -18212,7 +19764,7 @@ dependencies = [ name = "sc-sync-state-rpc" version = "0.34.0" dependencies = [ - "jsonrpsee", + "jsonrpsee 0.24.3", "parity-scale-codec", "sc-chain-spec", "sc-client-api", @@ -18222,7 +19774,7 @@ dependencies = [ "serde", "serde_json", "sp-blockchain", - "sp-runtime", + "sp-runtime 31.0.1", "thiserror", ] @@ -18240,10 +19792,10 @@ dependencies = [ "sc-telemetry", "serde", "serde_json", - "sp-core", - "sp-crypto-hashing", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", ] @@ -18270,25 +19822,24 @@ dependencies = [ name = "sc-tracing" version = "28.0.0" dependencies = [ - "ansi_term", "chrono", + "console", "criterion", "is-terminal", - "lazy_static", "libc", "log", "parity-scale-codec", "parking_lot 0.12.3", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "sc-client-api", "sc-tracing-proc-macro", "serde", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", - "sp-core", + "sp-core 28.0.0", "sp-rpc", - "sp-runtime", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", "thiserror", "tracing", @@ -18301,9 +19852,9 @@ name = "sc-tracing-proc-macro" version = "11.0.0" dependencies = [ "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -18316,6 +19867,8 @@ dependencies = [ "criterion", "futures", "futures-timer", + "indexmap 2.2.3", + "itertools 0.11.0", "linked-hash-map", "log", "parity-scale-codec", @@ -18325,12 +19878,12 @@ dependencies = [ "sc-transaction-pool-api", "sc-utils", "serde", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", "sp-consensus", - "sp-core", - "sp-crypto-hashing", - "sp-runtime", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", "sp-transaction-pool", "substrate-prometheus-endpoint", @@ -18338,6 +19891,8 @@ dependencies = [ "substrate-test-runtime-client", "substrate-test-runtime-transaction-pool", "thiserror", + "tokio", + "tokio-stream", ] [[package]] @@ -18351,8 +19906,8 @@ dependencies = [ "serde", "serde_json", "sp-blockchain", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "thiserror", ] @@ -18360,14 +19915,13 @@ dependencies = [ name = "sc-utils" version = "14.0.0" dependencies = [ - "async-channel", + "async-channel 1.9.0", "futures", "futures-timer", - "lazy_static", "log", "parking_lot 0.12.3", "prometheus", - "sp-arithmetic", + "sp-arithmetic 23.0.0", "tokio-test", ] @@ -18378,7 +19932,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e57b1e7f6b65ed1f04e79a85a57d755ad56d76fdf1e9bddcc9ae14f71fcdcf54" dependencies = [ "parity-scale-codec", + "scale-info", "scale-type-resolver", + "serde", ] [[package]] @@ -18389,42 +19945,122 @@ checksum = "e98f3262c250d90e700bb802eb704e1f841e03331c2eb815e46516c4edbf5b27" dependencies = [ "derive_more", "parity-scale-codec", + "primitive-types 0.12.2", "scale-bits", + "scale-decode-derive", "scale-type-resolver", "smallvec", ] [[package]] -name = "scale-info" -version = "2.11.3" +name = "scale-decode-derive" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +checksum = "9bb22f574168103cdd3133b19281639ca65ad985e24612728f727339dcaf4021" dependencies = [ - "bitvec", - "cfg-if", - "derive_more", - "parity-scale-codec", - "scale-info-derive", - "serde", + "darling 0.14.4", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 1.0.109", ] [[package]] -name = "scale-info-derive" -version = "2.11.3" +name = "scale-encode" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +checksum = "4ba0b9c48dc0eb20c60b083c29447c0c4617cb7c4a4c9fef72aa5c5bc539e15e" dependencies = [ - "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 1.0.109", -] - -[[package]] + "derive_more", + "parity-scale-codec", + "primitive-types 0.12.2", + "scale-bits", + "scale-encode-derive", + "scale-type-resolver", + "smallvec", +] + +[[package]] +name = "scale-encode-derive" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82ab7e60e2d9c8d47105f44527b26f04418e5e624ffc034f6b4a86c0ba19c5bf" +dependencies = [ + "darling 0.14.4", + "proc-macro-crate 1.3.1", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 1.0.109", +] + +[[package]] +name = "scale-info" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca070c12893629e2cc820a9761bedf6ce1dcddc9852984d1dc734b8bd9bd024" +dependencies = [ + "bitvec", + "cfg-if", + "derive_more", + "parity-scale-codec", + "scale-info-derive", + "serde", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d35494501194174bda522a32605929eefc9ecf7e0a326c26db1fdd85881eb62" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 1.0.109", +] + +[[package]] name = "scale-type-resolver" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0cded6518aa0bd6c1be2b88ac81bf7044992f0f154bfbabd5ad34f43512abcb" +dependencies = [ + "scale-info", + "smallvec", +] + +[[package]] +name = "scale-typegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498d1aecf2ea61325d4511787c115791639c0fd21ef4f8e11e49dd09eff2bbac" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "scale-info", + "syn 2.0.82", + "thiserror", +] + +[[package]] +name = "scale-value" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4d772cfb7569e03868400344a1695d16560bf62b86b918604773607d39ec84" +dependencies = [ + "base58", + "blake2 0.10.6", + "derive_more", + "either", + "frame-metadata 15.1.0", + "parity-scale-codec", + "scale-bits", + "scale-decode", + "scale-encode", + "scale-info", + "scale-type-resolver", + "serde", + "yap", +] [[package]] name = "schannel" @@ -18453,17 +20089,17 @@ version = "0.8.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0f696e21e10fa546b7ffb1c9672c6de8fbc7a81acf59524386d8639bf12737" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "serde_derive_internals", "syn 1.0.109", ] [[package]] name = "schnellru" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "772575a524feeb803e5b0fcbc6dd9f367e579488197c94c6e4023aad2305774d" +checksum = "c9a8ef13a93c54d20580de1e5c413e624e53121d42fc7e2c11d10ef7f8b02367" dependencies = [ "ahash 0.8.11", "cfg-if", @@ -18480,7 +20116,7 @@ dependencies = [ "arrayvec 0.7.4", "curve25519-dalek-ng", "merlin", - "rand_core", + "rand_core 0.6.4", "sha2 0.9.9", "subtle-ng", "zeroize", @@ -18495,10 +20131,10 @@ dependencies = [ "aead", "arrayref", "arrayvec 0.7.4", - "curve25519-dalek", + "curve25519-dalek 4.1.3", "getrandom_or_panic", "merlin", - "rand_core", + "rand_core 0.6.4", "serde_bytes", "sha2 0.10.8", "subtle 2.5.0", @@ -18533,21 +20169,6 @@ dependencies = [ "untrusted 0.7.1", ] -[[package]] -name = "sctp-proto" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6220f78bb44c15f326b0596113305f6101097a18755d53727a575c97e09fb24" -dependencies = [ - "bytes", - "crc", - "fxhash", - "log", - "rand", - "slab", - "thiserror", -] - [[package]] name = "sec1" version = "0.7.3" @@ -18596,6 +20217,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" dependencies = [ + "serde", "zeroize", ] @@ -18623,40 +20245,6 @@ dependencies = [ "libc", ] -[[package]] -name = "seedling-runtime" -version = "0.7.0" -dependencies = [ - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-pallet-solo-to-para", - "cumulus-primitives-core", - "cumulus-primitives-timestamp", - "frame-executive", - "frame-support", - "frame-system", - "pallet-aura", - "pallet-balances", - "pallet-sudo", - "pallet-timestamp", - "parachains-common", - "parity-scale-codec", - "scale-info", - "sp-api", - "sp-block-builder", - "sp-consensus-aura", - "sp-core", - "sp-genesis-builder", - "sp-inherents", - "sp-offchain", - "sp-runtime", - "sp-session", - "sp-transaction-pool", - "sp-version", - "staging-parachain-info", - "substrate-wasm-builder", -] - [[package]] name = "semver" version = "0.6.0" @@ -18708,6 +20296,12 @@ dependencies = [ "pest", ] +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + [[package]] name = "send_wrapper" version = "0.6.0" @@ -18722,9 +20316,9 @@ checksum = "f97841a747eef040fcd2e7b3b9a220a7205926e60488e673d9e4926d27772ce5" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] @@ -18738,6 +20332,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + [[package]] name = "serde_bytes" version = "0.11.12" @@ -18749,13 +20353,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -18764,8 +20368,8 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -18780,21 +20384,22 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "indexmap 2.2.3", "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" -version = "0.6.4" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] @@ -18813,9 +20418,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", @@ -18854,9 +20459,9 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -18872,18 +20477,6 @@ dependencies = [ "opaque-debug 0.3.0", ] -[[package]] -name = "sha-1" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", - "sha1-asm", -] - [[package]] name = "sha1" version = "0.10.6" @@ -18895,15 +20488,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "sha1-asm" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ba6947745e7f86be3b8af00b7355857085dbdf8901393c89514510eb61f4e21" -dependencies = [ - "cc", -] - [[package]] name = "sha2" version = "0.9.9" @@ -18928,6 +20512,18 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug 0.3.0", +] + [[package]] name = "sha3" version = "0.10.8" @@ -18947,42 +20543,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shell-runtime" -version = "0.7.0" -dependencies = [ - "cumulus-pallet-aura-ext", - "cumulus-pallet-parachain-system", - "cumulus-pallet-xcm", - "cumulus-primitives-core", - "frame-executive", - "frame-support", - "frame-system", - "frame-try-runtime", - "pallet-aura", - "pallet-message-queue", - "pallet-timestamp", - "parachains-common", - "parity-scale-codec", - "scale-info", - "sp-api", - "sp-block-builder", - "sp-consensus-aura", - "sp-core", - "sp-genesis-builder", - "sp-inherents", - "sp-offchain", - "sp-runtime", - "sp-session", - "sp-transaction-pool", - "sp-version", - "staging-parachain-info", - "staging-xcm", - "staging-xcm-builder", - "staging-xcm-executor", - "substrate-wasm-builder", -] - [[package]] name = "shlex" version = "1.3.0" @@ -19015,7 +20575,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ "digest 0.10.7", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -19033,9 +20593,9 @@ dependencies = [ [[package]] name = "simple-dns" -version = "0.5.7" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cae9a3fcdadafb6d97f4c0e007e4247b114ee0f119f650c3cbf3a8b3a1479694" +checksum = "4c80e565e7dcc4f1ef247e2f395550d4cf7d777746d5988e7e4e3156b71077fc" dependencies = [ "bitflags 2.6.0", ] @@ -19057,6 +20617,12 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "slab" version = "0.4.9" @@ -19079,7 +20645,7 @@ dependencies = [ "enumn", "parity-scale-codec", "paste", - "sp-runtime", + "sp-runtime 31.0.1", ] [[package]] @@ -19097,7 +20663,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d7400c0eff44aa2fcb5e31a5f24ba9716ed90138769e4977a2ba6014ae63eb5" dependencies = [ - "async-channel", + "async-channel 1.9.0", "futures-core", "futures-io", ] @@ -19114,17 +20680,34 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13f2b548cd8447f8de0fdf1c592929f70f4fc7039a05e47404b0d096ec6987a1" dependencies = [ - "async-channel", + "async-channel 1.9.0", "async-executor", - "async-fs", + "async-fs 1.6.0", "async-io 1.13.0", "async-lock 2.8.0", - "async-net", - "async-process", + "async-net 1.7.0", + "async-process 1.7.0", "blocking", "futures-lite 1.13.0", ] +[[package]] +name = "smol" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f" +dependencies = [ + "async-channel 2.3.0", + "async-executor", + "async-fs 2.1.2", + "async-io 2.3.3", + "async-lock 3.4.0", + "async-net 2.0.0", + "async-process 2.3.0", + "blocking", + "futures-lite 2.3.0", +] + [[package]] name = "smol_str" version = "0.2.0" @@ -19143,20 +20726,20 @@ dependencies = [ "arrayvec 0.7.4", "async-lock 2.8.0", "atomic-take", - "base64 0.21.2", + "base64 0.21.7", "bip39", "blake2-rfc", - "bs58 0.5.0", + "bs58", "chacha20", "crossbeam-queue", "derive_more", - "ed25519-zebra", + "ed25519-zebra 4.0.3", "either", "event-listener 2.5.3", "fnv", "futures-lite 1.13.0", "futures-util", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "hex", "hmac 0.12.1", "itertools 0.11.0", @@ -19172,13 +20755,68 @@ dependencies = [ "poly1305", "rand", "rand_chacha", - "ruzstd", + "ruzstd 0.4.0", "schnorrkel 0.10.2", "serde", "serde_json", "sha2 0.10.8", - "sha3", - "siphasher", + "sha3 0.10.8", + "siphasher 0.3.11", + "slab", + "smallvec", + "soketto 0.7.1", + "twox-hash", + "wasmi 0.31.2", + "x25519-dalek", + "zeroize", +] + +[[package]] +name = "smoldot" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d1eaa97d77be4d026a1e7ffad1bb3b78448763b357ea6f8188d3e6f736a9b9" +dependencies = [ + "arrayvec 0.7.4", + "async-lock 3.4.0", + "atomic-take", + "base64 0.21.7", + "bip39", + "blake2-rfc", + "bs58", + "chacha20", + "crossbeam-queue", + "derive_more", + "ed25519-zebra 4.0.3", + "either", + "event-listener 4.0.3", + "fnv", + "futures-lite 2.3.0", + "futures-util", + "hashbrown 0.14.5", + "hex", + "hmac 0.12.1", + "itertools 0.12.1", + "libm", + "libsecp256k1", + "merlin", + "no-std-net", + "nom", + "num-bigint", + "num-rational", + "num-traits", + "pbkdf2", + "pin-project", + "poly1305", + "rand", + "rand_chacha", + "ruzstd 0.5.0", + "schnorrkel 0.11.4", + "serde", + "serde_json", + "sha2 0.10.8", + "sha3 0.10.8", + "siphasher 1.0.1", "slab", "smallvec", "soketto 0.7.1", @@ -19194,9 +20832,9 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "256b5bad1d6b49045e95fe87492ce73d5af81545d8b4d8318a872d2007024c33" dependencies = [ - "async-channel", + "async-channel 1.9.0", "async-lock 2.8.0", - "base64 0.21.2", + "base64 0.21.7", "blake2-rfc", "derive_more", "either", @@ -19205,7 +20843,7 @@ dependencies = [ "futures-channel", "futures-lite 1.13.0", "futures-util", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "hex", "itertools 0.11.0", "log", @@ -19217,20 +20855,56 @@ dependencies = [ "rand_chacha", "serde", "serde_json", - "siphasher", + "siphasher 0.3.11", "slab", - "smol", - "smoldot", + "smol 1.3.0", + "smoldot 0.11.0", "zeroize", ] [[package]] -name = "snap" -version = "1.1.0" +name = "smoldot-light" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" - -[[package]] +checksum = "5496f2d116b7019a526b1039ec2247dd172b8670633b1a64a614c9ea12c9d8c7" +dependencies = [ + "async-channel 2.3.0", + "async-lock 3.4.0", + "base64 0.21.7", + "blake2-rfc", + "derive_more", + "either", + "event-listener 4.0.3", + "fnv", + "futures-channel", + "futures-lite 2.3.0", + "futures-util", + "hashbrown 0.14.5", + "hex", + "itertools 0.12.1", + "log", + "lru 0.12.3", + "no-std-net", + "parking_lot 0.12.3", + "pin-project", + "rand", + "rand_chacha", + "serde", + "serde_json", + "siphasher 1.0.1", + "slab", + "smol 2.0.2", + "smoldot 0.16.0", + "zeroize", +] + +[[package]] +name = "snap" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e9f0ab6ef7eb7353d9119c170a436d1bf248eea575ac42d19d12f4e34130831" + +[[package]] name = "snow" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -19239,8 +20913,8 @@ dependencies = [ "aes-gcm", "blake2 0.10.6", "chacha20poly1305", - "curve25519-dalek", - "rand_core", + "curve25519-dalek 4.1.3", + "rand_core 0.6.4", "ring 0.17.7", "rustc_version 0.4.0", "sha2 0.10.8", @@ -19266,14 +20940,14 @@ dependencies = [ "hex", "hex-literal", "parity-scale-codec", - "rlp", + "rlp 0.6.1", "scale-info", "serde", "snowbridge-ethereum", "snowbridge-milagro-bls", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", "ssz_rs", "ssz_rs_derive", @@ -19293,13 +20967,14 @@ dependencies = [ "scale-info", "serde", "snowbridge-beacon-primitives", - "sp-arithmetic", - "sp-core", - "sp-io", - "sp-runtime", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", "staging-xcm", "staging-xcm-builder", + "staging-xcm-executor", ] [[package]] @@ -19313,13 +20988,13 @@ dependencies = [ "parity-bytes", "parity-scale-codec", "rand", - "rlp", + "rlp 0.6.1", "scale-info", "serde", "serde-big-array", "serde_json", - "sp-io", - "sp-runtime", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", "wasm-bindgen-test", ] @@ -19344,14 +21019,14 @@ name = "snowbridge-outbound-queue-merkle-tree" version = "0.3.0" dependencies = [ "array-bytes", - "env_logger 0.11.3", "hex", "hex-literal", "parity-scale-codec", "scale-info", - "sp-core", - "sp-crypto-hashing", - "sp-runtime", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", + "sp-runtime 31.0.1", + "sp-tracing 16.0.0", ] [[package]] @@ -19362,7 +21037,7 @@ dependencies = [ "parity-scale-codec", "snowbridge-core", "snowbridge-outbound-queue-merkle-tree", - "sp-api", + "sp-api 26.0.0", "sp-std 14.0.0", ] @@ -19385,10 +21060,10 @@ dependencies = [ "snowbridge-core", "snowbridge-ethereum", "snowbridge-pallet-ethereum-client-fixtures", - "sp-core", - "sp-io", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-keyring", - "sp-runtime", + "sp-runtime 31.0.1", "sp-std 14.0.0", "static_assertions", ] @@ -19400,7 +21075,7 @@ dependencies = [ "hex-literal", "snowbridge-beacon-primitives", "snowbridge-core", - "sp-core", + "sp-core 28.0.0", "sp-std 14.0.0", ] @@ -19424,10 +21099,10 @@ dependencies = [ "snowbridge-pallet-ethereum-client", "snowbridge-pallet-inbound-queue-fixtures", "snowbridge-router-primitives", - "sp-core", - "sp-io", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-keyring", - "sp-runtime", + "sp-runtime 31.0.1", "sp-std 14.0.0", "staging-xcm", "staging-xcm-executor", @@ -19440,7 +21115,7 @@ dependencies = [ "hex-literal", "snowbridge-beacon-primitives", "snowbridge-core", - "sp-core", + "sp-core 28.0.0", "sp-std 14.0.0", ] @@ -19459,11 +21134,11 @@ dependencies = [ "serde", "snowbridge-core", "snowbridge-outbound-queue-merkle-tree", - "sp-arithmetic", - "sp-core", - "sp-io", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-keyring", - "sp-runtime", + "sp-runtime 31.0.1", "sp-std 14.0.0", ] @@ -19484,10 +21159,10 @@ dependencies = [ "scale-info", "snowbridge-core", "snowbridge-pallet-outbound-queue", - "sp-core", - "sp-io", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-keyring", - "sp-runtime", + "sp-runtime 31.0.1", "sp-std 14.0.0", "staging-xcm", "staging-xcm-executor", @@ -19503,9 +21178,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "snowbridge-core", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", "staging-xcm", "staging-xcm-executor", @@ -19519,7 +21194,7 @@ dependencies = [ "log", "parity-scale-codec", "snowbridge-core", - "sp-arithmetic", + "sp-arithmetic 23.0.0", "sp-std 14.0.0", "staging-xcm", "staging-xcm-builder", @@ -19547,10 +21222,10 @@ dependencies = [ "snowbridge-pallet-ethereum-client-fixtures", "snowbridge-pallet-outbound-queue", "snowbridge-pallet-system", - "sp-core", - "sp-io", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-keyring", - "sp-runtime", + "sp-runtime 31.0.1", "staging-parachain-info", "staging-xcm", "staging-xcm-executor", @@ -19562,7 +21237,7 @@ version = "0.2.0" dependencies = [ "parity-scale-codec", "snowbridge-core", - "sp-api", + "sp-api 26.0.0", "sp-std 14.0.0", "staging-xcm", ] @@ -19599,7 +21274,7 @@ dependencies = [ "httparse", "log", "rand", - "sha-1 0.9.8", + "sha-1", ] [[package]] @@ -19622,11 +21297,12 @@ dependencies = [ name = "solochain-template-node" version = "0.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.13", "frame-benchmarking-cli", + "frame-metadata-hash-extension", "frame-system", "futures", - "jsonrpsee", + "jsonrpsee 0.24.3", "pallet-transaction-payment", "pallet-transaction-payment-rpc", "sc-basic-authorship", @@ -19635,26 +21311,26 @@ dependencies = [ "sc-consensus", "sc-consensus-aura", "sc-consensus-grandpa", - "sc-executor", + "sc-executor 0.32.0", "sc-network", "sc-offchain", - "sc-rpc-api", "sc-service", "sc-telemetry", "sc-transaction-pool", "sc-transaction-pool-api", "serde_json", "solochain-template-runtime", - "sp-api", + "sp-api 26.0.0", "sp-block-builder", "sp-blockchain", "sp-consensus-aura", "sp-consensus-grandpa", - "sp-core", + "sp-core 28.0.0", + "sp-genesis-builder", "sp-inherents", - "sp-io", + "sp-io 30.0.0", "sp-keyring", - "sp-runtime", + "sp-runtime 31.0.1", "sp-timestamp", "substrate-build-script-utils", "substrate-frame-rpc-system", @@ -19666,6 +21342,7 @@ version = "0.0.0" dependencies = [ "frame-benchmarking", "frame-executive", + "frame-metadata-hash-extension", "frame-support", "frame-system", "frame-system-benchmarking", @@ -19681,19 +21358,21 @@ dependencies = [ "pallet-transaction-payment-rpc-runtime-api", "parity-scale-codec", "scale-info", - "sp-api", + "serde_json", + "sp-api 26.0.0", "sp-block-builder", "sp-consensus-aura", "sp-consensus-grandpa", - "sp-core", + "sp-core 28.0.0", "sp-genesis-builder", "sp-inherents", + "sp-keyring", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-storage 19.0.0", "sp-transaction-pool", - "sp-version", + "sp-version 29.0.0", "substrate-wasm-builder", ] @@ -19706,16 +21385,39 @@ dependencies = [ "log", "parity-scale-codec", "scale-info", - "sp-api-proc-macro", - "sp-core", + "sp-api-proc-macro 15.0.0", + "sp-core 28.0.0", "sp-externalities 0.25.0", - "sp-metadata-ir", - "sp-runtime", + "sp-metadata-ir 0.6.0", + "sp-runtime 31.0.1", "sp-runtime-interface 24.0.0", - "sp-state-machine", + "sp-state-machine 0.35.0", "sp-test-primitives", - "sp-trie", - "sp-version", + "sp-trie 29.0.0", + "sp-version 29.0.0", + "thiserror", +] + +[[package]] +name = "sp-api" +version = "32.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f84f09c4b928e814e07dede0ece91f1f6eae1bff946a0e5e4a76bed19a095f1" +dependencies = [ + "hash-db", + "log", + "parity-scale-codec", + "scale-info", + "sp-api-proc-macro 19.0.0", + "sp-core 33.0.1", + "sp-externalities 0.28.0", + "sp-metadata-ir 0.7.0", + "sp-runtime 37.0.0", + "sp-runtime-interface 27.0.0", + "sp-state-machine 0.41.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-trie 35.0.0", + "sp-version 35.0.0", "thiserror", ] @@ -19728,9 +21430,24 @@ dependencies = [ "blake2 0.10.6", "expander", "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", +] + +[[package]] +name = "sp-api-proc-macro" +version = "19.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213a4bec1b18bd0750e7b81d11d8276c24f68b53cde83950b00b178ecc9ab24a" +dependencies = [ + "Inflector", + "blake2 0.10.6", + "expander", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -19744,13 +21461,13 @@ dependencies = [ "rustversion", "sc-block-builder", "scale-info", - "sp-api", + "sp-api 26.0.0", "sp-consensus", - "sp-core", - "sp-runtime", - "sp-state-machine", + "sp-core 28.0.0", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "sp-tracing 16.0.0", - "sp-version", + "sp-version 29.0.0", "static_assertions", "substrate-test-runtime-client", "trybuild", @@ -19763,18 +21480,60 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core", - "sp-io", + "sp-core 28.0.0", + "sp-io 30.0.0", +] + +[[package]] +name = "sp-application-crypto" +version = "33.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13ca6121c22c8bd3d1dce1f05c479101fd0d7b159bef2a3e8c834138d839c75c" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-core 31.0.0", + "sp-io 33.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sp-application-crypto" +version = "35.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57541120624a76379cc993cbb85064a5148957a92da032567e54bce7977f51fc" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-core 32.0.0", + "sp-io 35.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sp-application-crypto" +version = "36.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "296282f718f15d4d812664415942665302a484d3495cf8d2e2ab3192b32d2c73" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde", + "sp-core 33.0.1", + "sp-io 36.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "sp-application-crypto-test" version = "2.0.0" dependencies = [ - "sp-api", - "sp-application-crypto", - "sp-core", - "sp-keystore", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", + "sp-core 28.0.0", + "sp-keystore 0.34.0", "substrate-test-runtime-client", ] @@ -19787,11 +21546,42 @@ dependencies = [ "integer-sqrt", "num-traits", "parity-scale-codec", - "primitive-types", + "primitive-types 0.13.1", "rand", "scale-info", "serde", - "sp-crypto-hashing", + "sp-crypto-hashing 0.1.0", + "static_assertions", +] + +[[package]] +name = "sp-arithmetic" +version = "25.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "910c07fa263b20bf7271fdd4adcb5d3217dfdac14270592e0780223542e7e114" +dependencies = [ + "integer-sqrt", + "num-traits", + "parity-scale-codec", + "scale-info", + "serde", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "static_assertions", +] + +[[package]] +name = "sp-arithmetic" +version = "26.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46d0d0a4c591c421d3231ddd5e27d828618c24456d51445d21a1f79fcee97c23" +dependencies = [ + "docify", + "integer-sqrt", + "num-traits", + "parity-scale-codec", + "scale-info", + "serde", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "static_assertions", ] @@ -19803,7 +21593,7 @@ dependencies = [ "fraction", "honggfuzz", "num-bigint", - "sp-arithmetic", + "sp-arithmetic 23.0.0", ] [[package]] @@ -19830,18 +21620,18 @@ version = "26.0.0" dependencies = [ "parity-scale-codec", "scale-info", - "sp-api", - "sp-application-crypto", - "sp-runtime", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", + "sp-runtime 31.0.1", ] [[package]] name = "sp-block-builder" version = "26.0.0" dependencies = [ - "sp-api", + "sp-api 26.0.0", "sp-inherents", - "sp-runtime", + "sp-runtime 31.0.1", ] [[package]] @@ -19852,12 +21642,12 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.3", "schnellru", - "sp-api", + "sp-api 26.0.0", "sp-consensus", - "sp-core", + "sp-core 28.0.0", "sp-database", - "sp-runtime", - "sp-state-machine", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "thiserror", "tracing", ] @@ -19869,10 +21659,10 @@ dependencies = [ "async-trait", "futures", "log", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-runtime", - "sp-state-machine", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "sp-test-primitives", "thiserror", ] @@ -19884,11 +21674,11 @@ dependencies = [ "async-trait", "parity-scale-codec", "scale-info", - "sp-api", - "sp-application-crypto", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", "sp-consensus-slots", "sp-inherents", - "sp-runtime", + "sp-runtime 31.0.1", "sp-timestamp", ] @@ -19900,12 +21690,12 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-api", - "sp-application-crypto", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", "sp-consensus-slots", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-runtime", + "sp-runtime 31.0.1", "sp-timestamp", ] @@ -19914,19 +21704,19 @@ name = "sp-consensus-beefy" version = "13.0.0" dependencies = [ "array-bytes", - "lazy_static", "parity-scale-codec", "scale-info", "serde", - "sp-api", - "sp-application-crypto", - "sp-core", - "sp-crypto-hashing", - "sp-io", - "sp-keystore", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", + "sp-io 30.0.0", + "sp-keystore 0.34.0", "sp-mmr-primitives", - "sp-runtime", - "strum 0.26.2", + "sp-runtime 31.0.1", + "sp-weights 27.0.0", + "strum 0.26.3", "w3f-bls", ] @@ -19939,11 +21729,11 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-api", - "sp-application-crypto", - "sp-core", - "sp-keystore", - "sp-runtime", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", + "sp-core 28.0.0", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", ] [[package]] @@ -19951,9 +21741,9 @@ name = "sp-consensus-pow" version = "0.32.0" dependencies = [ "parity-scale-codec", - "sp-api", - "sp-core", - "sp-runtime", + "sp-api 26.0.0", + "sp-core 28.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -19963,11 +21753,11 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-api", - "sp-application-crypto", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", "sp-consensus-slots", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -19989,17 +21779,16 @@ dependencies = [ "bitflags 1.3.2", "blake2 0.10.6", "bounded-collections", - "bs58 0.5.0", + "bs58", "criterion", "dyn-clonable", - "ed25519-zebra", + "ed25519-zebra 4.0.3", "futures", "hash-db", "hash256-std-hasher", - "impl-serde", + "impl-serde 0.5.0", "itertools 0.11.0", "k256", - "lazy_static", "libsecp256k1", "log", "merlin", @@ -20007,7 +21796,7 @@ dependencies = [ "parity-scale-codec", "parking_lot 0.12.3", "paste", - "primitive-types", + "primitive-types 0.13.1", "rand", "regex", "scale-info", @@ -20016,14 +21805,155 @@ dependencies = [ "secrecy", "serde", "serde_json", - "sp-crypto-hashing", + "sp-crypto-hashing 0.1.0", "sp-debug-derive 14.0.0", "sp-externalities 0.25.0", "sp-runtime-interface 24.0.0", "sp-std 14.0.0", "sp-storage 19.0.0", "ss58-registry", - "substrate-bip39", + "substrate-bip39 0.4.7", + "thiserror", + "tracing", + "w3f-bls", + "zeroize", +] + +[[package]] +name = "sp-core" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d7a0fd8f16dcc3761198fc83be12872f823b37b749bc72a3a6a1f702509366" +dependencies = [ + "array-bytes", + "bitflags 1.3.2", + "blake2 0.10.6", + "bounded-collections", + "bs58", + "dyn-clonable", + "ed25519-zebra 3.1.0", + "futures", + "hash-db", + "hash256-std-hasher", + "impl-serde 0.4.0", + "itertools 0.10.5", + "k256", + "libsecp256k1", + "log", + "merlin", + "parity-bip39", + "parity-scale-codec", + "parking_lot 0.12.3", + "paste", + "primitive-types 0.12.2", + "rand", + "scale-info", + "schnorrkel 0.11.4", + "secp256k1", + "secrecy", + "serde", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-externalities 0.27.0", + "sp-runtime-interface 26.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-storage 20.0.0", + "ss58-registry", + "substrate-bip39 0.5.0", + "thiserror", + "tracing", + "w3f-bls", + "zeroize", +] + +[[package]] +name = "sp-core" +version = "32.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2dac7e47c7ddbb61efe196d5cce99f6ea88926c961fa39909bfeae46fc5a7b" +dependencies = [ + "array-bytes", + "bitflags 1.3.2", + "blake2 0.10.6", + "bounded-collections", + "bs58", + "dyn-clonable", + "ed25519-zebra 3.1.0", + "futures", + "hash-db", + "hash256-std-hasher", + "impl-serde 0.4.0", + "itertools 0.10.5", + "k256", + "libsecp256k1", + "log", + "merlin", + "parity-bip39", + "parity-scale-codec", + "parking_lot 0.12.3", + "paste", + "primitive-types 0.12.2", + "rand", + "scale-info", + "schnorrkel 0.11.4", + "secp256k1", + "secrecy", + "serde", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-externalities 0.28.0", + "sp-runtime-interface 27.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-storage 21.0.0", + "ss58-registry", + "substrate-bip39 0.6.0", + "thiserror", + "tracing", + "w3f-bls", + "zeroize", +] + +[[package]] +name = "sp-core" +version = "33.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3368e32f6fda6e20b8af51f94308d033ab70a021e87f6abbd3fed5aca942b745" +dependencies = [ + "array-bytes", + "bitflags 1.3.2", + "blake2 0.10.6", + "bounded-collections", + "bs58", + "dyn-clonable", + "ed25519-zebra 4.0.3", + "futures", + "hash-db", + "hash256-std-hasher", + "impl-serde 0.4.0", + "itertools 0.11.0", + "k256", + "libsecp256k1", + "log", + "merlin", + "parity-bip39", + "parity-scale-codec", + "parking_lot 0.12.3", + "paste", + "primitive-types 0.12.2", + "rand", + "scale-info", + "schnorrkel 0.11.4", + "secp256k1", + "secrecy", + "serde", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-externalities 0.28.0", + "sp-runtime-interface 27.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-storage 21.0.0", + "ss58-registry", + "substrate-bip39 0.6.0", "thiserror", "tracing", "w3f-bls", @@ -20034,30 +21964,29 @@ dependencies = [ name = "sp-core-fuzz" version = "0.0.0" dependencies = [ - "lazy_static", "libfuzzer-sys", "regex", - "sp-core", + "sp-core 28.0.0", ] [[package]] name = "sp-core-hashing" version = "15.0.0" dependencies = [ - "sp-crypto-hashing", + "sp-crypto-hashing 0.1.0", ] [[package]] name = "sp-core-hashing-proc-macro" version = "15.0.0" dependencies = [ - "sp-crypto-hashing-proc-macro", + "sp-crypto-hashing-proc-macro 0.1.0", ] [[package]] name = "sp-crypto-ec-utils" version = "0.4.1" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +source = "git+https://github.com/paritytech/polkadot-sdk#838a534da874cf6071fba1df07643c6c5b033ae0" dependencies = [ "ark-bls12-377", "ark-bls12-377-ext", @@ -20098,23 +22027,48 @@ dependencies = [ name = "sp-crypto-hashing" version = "0.1.0" dependencies = [ - "blake2b_simd", + "blake2b_simd 1.0.2", "byteorder", "criterion", "digest 0.10.7", "sha2 0.10.8", - "sha3", - "sp-crypto-hashing-proc-macro", + "sha3 0.10.8", + "sp-crypto-hashing-proc-macro 0.1.0", "twox-hash", ] +[[package]] +name = "sp-crypto-hashing" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc9927a7f81334ed5b8a98a4a978c81324d12bd9713ec76b5c68fd410174c5eb" +dependencies = [ + "blake2b_simd 1.0.2", + "byteorder", + "digest 0.10.7", + "sha2 0.10.8", + "sha3 0.10.8", + "twox-hash", +] + +[[package]] +name = "sp-crypto-hashing-proc-macro" +version = "0.1.0" +dependencies = [ + "quote 1.0.37", + "sp-crypto-hashing 0.1.0", + "syn 2.0.82", +] + [[package]] name = "sp-crypto-hashing-proc-macro" version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b85d0f1f1e44bd8617eb2a48203ee854981229e3e79e6f468c7175d5fd37489b" dependencies = [ - "quote 1.0.35", - "sp-crypto-hashing", - "syn 2.0.61", + "quote 1.0.37", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 2.0.82", ] [[package]] @@ -20130,18 +22084,29 @@ name = "sp-debug-derive" version = "8.0.0" source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", +] + +[[package]] +name = "sp-debug-derive" +version = "14.0.0" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] name = "sp-debug-derive" version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d09fa0a5f7299fb81ee25ae3853d26200f7a348148aed6de76be905c007dbe" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -20165,14 +22130,37 @@ dependencies = [ ] [[package]] -name = "sp-genesis-builder" -version = "0.8.0" +name = "sp-externalities" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d6a4572eadd4a63cff92509a210bf425501a0c5e76574b30a366ac77653787" dependencies = [ + "environmental", "parity-scale-codec", - "scale-info", - "serde_json", - "sp-api", - "sp-runtime", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-storage 20.0.0", +] + +[[package]] +name = "sp-externalities" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33abaec4be69b1613796bbf430decbbcaaf978756379e2016e683a4d6379cd02" +dependencies = [ + "environmental", + "parity-scale-codec", + "sp-storage 21.0.0", +] + +[[package]] +name = "sp-genesis-builder" +version = "0.8.0" +dependencies = [ + "parity-scale-codec", + "scale-info", + "serde_json", + "sp-api 26.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -20184,7 +22172,7 @@ dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", "scale-info", - "sp-runtime", + "sp-runtime 31.0.1", "thiserror", ] @@ -20198,17 +22186,98 @@ dependencies = [ "libsecp256k1", "log", "parity-scale-codec", - "polkavm-derive", + "polkavm-derive 0.9.1", "rustversion", "secp256k1", - "sp-core", - "sp-crypto-hashing", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", "sp-externalities 0.25.0", - "sp-keystore", + "sp-keystore 0.34.0", "sp-runtime-interface 24.0.0", - "sp-state-machine", + "sp-state-machine 0.35.0", "sp-tracing 16.0.0", - "sp-trie", + "sp-trie 29.0.0", + "tracing", + "tracing-core", +] + +[[package]] +name = "sp-io" +version = "33.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e09bba780b55bd9e67979cd8f654a31e4a6cf45426ff371394a65953d2177f2" +dependencies = [ + "bytes", + "ed25519-dalek", + "libsecp256k1", + "log", + "parity-scale-codec", + "polkavm-derive 0.9.1", + "rustversion", + "secp256k1", + "sp-core 31.0.0", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-externalities 0.27.0", + "sp-keystore 0.37.0", + "sp-runtime-interface 26.0.0", + "sp-state-machine 0.38.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-tracing 16.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-trie 32.0.0", + "tracing", + "tracing-core", +] + +[[package]] +name = "sp-io" +version = "35.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b64ab18a0e29def6511139a8c45a59c14a846105aab6f9cc653523bd3b81f55" +dependencies = [ + "bytes", + "ed25519-dalek", + "libsecp256k1", + "log", + "parity-scale-codec", + "polkavm-derive 0.9.1", + "rustversion", + "secp256k1", + "sp-core 32.0.0", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-externalities 0.28.0", + "sp-keystore 0.38.0", + "sp-runtime-interface 27.0.0", + "sp-state-machine 0.40.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-tracing 17.0.0", + "sp-trie 34.0.0", + "tracing", + "tracing-core", +] + +[[package]] +name = "sp-io" +version = "36.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a31ce27358b73656a09b4933f09a700019d63afa15ede966f7c9893c1d4db5" +dependencies = [ + "bytes", + "ed25519-dalek", + "libsecp256k1", + "log", + "parity-scale-codec", + "polkavm-derive 0.9.1", + "rustversion", + "secp256k1", + "sp-core 33.0.1", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-externalities 0.28.0", + "sp-keystore 0.39.0", + "sp-runtime-interface 27.0.0", + "sp-state-machine 0.41.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-tracing 17.0.0", + "sp-trie 35.0.0", "tracing", "tracing-core", ] @@ -20217,9 +22286,9 @@ dependencies = [ name = "sp-keyring" version = "31.0.0" dependencies = [ - "sp-core", - "sp-runtime", - "strum 0.26.2", + "sp-core 28.0.0", + "sp-runtime 31.0.1", + "strum 0.26.3", ] [[package]] @@ -20230,13 +22299,59 @@ dependencies = [ "parking_lot 0.12.3", "rand", "rand_chacha", - "sp-core", + "sp-core 28.0.0", "sp-externalities 0.25.0", ] +[[package]] +name = "sp-keystore" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdbab8b61bd61d5f8625a0c75753b5d5a23be55d3445419acd42caf59cf6236b" +dependencies = [ + "parity-scale-codec", + "parking_lot 0.12.3", + "sp-core 31.0.0", + "sp-externalities 0.27.0", +] + +[[package]] +name = "sp-keystore" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e6c7a7abd860a5211a356cf9d5fcabf0eb37d997985e5d722b6b33dcc815528" +dependencies = [ + "parity-scale-codec", + "parking_lot 0.12.3", + "sp-core 32.0.0", + "sp-externalities 0.28.0", +] + +[[package]] +name = "sp-keystore" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92a909528663a80829b95d582a20dd4c9acd6e575650dee2bcaf56f4740b305e" +dependencies = [ + "parity-scale-codec", + "parking_lot 0.12.3", + "sp-core 33.0.1", + "sp-externalities 0.28.0", +] + +[[package]] +name = "sp-maybe-compressed-blob" +version = "11.0.0" +dependencies = [ + "thiserror", + "zstd 0.12.4", +] + [[package]] name = "sp-maybe-compressed-blob" version = "11.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c768c11afbe698a090386876911da4236af199cd38a5866748df4d8628aeff" dependencies = [ "thiserror", "zstd 0.12.4", @@ -20246,7 +22361,18 @@ dependencies = [ name = "sp-metadata-ir" version = "0.6.0" dependencies = [ - "frame-metadata", + "frame-metadata 16.0.0", + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "sp-metadata-ir" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a616fa51350b35326682a472ee8e6ba742fdacb18babac38ecd46b3e05ead869" +dependencies = [ + "frame-metadata 16.0.0", "parity-scale-codec", "scale-info", ] @@ -20257,8 +22383,8 @@ version = "0.4.0" dependencies = [ "parity-scale-codec", "scale-info", - "sp-api", - "sp-application-crypto", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", ] [[package]] @@ -20271,10 +22397,10 @@ dependencies = [ "polkadot-ckb-merkle-mountain-range", "scale-info", "serde", - "sp-api", - "sp-core", + "sp-api 26.0.0", + "sp-core 28.0.0", "sp-debug-derive 14.0.0", - "sp-runtime", + "sp-runtime 31.0.1", "thiserror", ] @@ -20286,9 +22412,9 @@ dependencies = [ "rand", "scale-info", "serde", - "sp-arithmetic", - "sp-core", - "sp-runtime", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "substrate-test-utils", ] @@ -20296,25 +22422,35 @@ dependencies = [ name = "sp-npos-elections-fuzzer" version = "2.0.0-alpha.5" dependencies = [ - "clap 4.5.3", + "clap 4.5.13", "honggfuzz", "rand", "sp-npos-elections", - "sp-runtime", + "sp-runtime 31.0.1", ] [[package]] name = "sp-offchain" version = "26.0.0" dependencies = [ - "sp-api", - "sp-core", - "sp-runtime", + "sp-api 26.0.0", + "sp-core 28.0.0", + "sp-runtime 31.0.1", +] + +[[package]] +name = "sp-panic-handler" +version = "13.0.0" +dependencies = [ + "backtrace", + "regex", ] [[package]] name = "sp-panic-handler" version = "13.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8f5a17a0a11de029a8b811cb6e8b32ce7e02183cc04a3e965c383246798c416" dependencies = [ "backtrace", "lazy_static", @@ -20325,16 +22461,17 @@ dependencies = [ name = "sp-rpc" version = "26.0.0" dependencies = [ - "rustc-hash", + "rustc-hash 1.1.0", "serde", "serde_json", - "sp-core", + "sp-core 28.0.0", ] [[package]] name = "sp-runtime" version = "31.0.1" dependencies = [ + "binary-merkle-tree", "docify", "either", "hash256-std-hasher", @@ -20348,20 +22485,98 @@ dependencies = [ "serde", "serde_json", "simple-mermaid 0.1.1", - "sp-api", - "sp-application-crypto", - "sp-arithmetic", - "sp-core", - "sp-io", - "sp-state-machine", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-state-machine 0.35.0", "sp-std 14.0.0", "sp-tracing 16.0.0", - "sp-weights", + "sp-trie 29.0.0", + "sp-weights 27.0.0", "substrate-test-runtime-client", "tracing", + "tuplex", "zstd 0.12.4", ] +[[package]] +name = "sp-runtime" +version = "34.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3cb126971e7db2f0fcf8053dce740684c438c7180cfca1959598230f342c58" +dependencies = [ + "docify", + "either", + "hash256-std-hasher", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "paste", + "rand", + "scale-info", + "serde", + "simple-mermaid 0.1.1", + "sp-application-crypto 33.0.0", + "sp-arithmetic 25.0.0", + "sp-core 31.0.0", + "sp-io 33.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-weights 30.0.0", +] + +[[package]] +name = "sp-runtime" +version = "36.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6b85cb874b78ebb17307a910fc27edf259a0455ac5155d87eaed8754c037e07" +dependencies = [ + "docify", + "either", + "hash256-std-hasher", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "paste", + "rand", + "scale-info", + "serde", + "simple-mermaid 0.1.1", + "sp-application-crypto 35.0.0", + "sp-arithmetic 26.0.0", + "sp-core 32.0.0", + "sp-io 35.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-weights 31.0.0", +] + +[[package]] +name = "sp-runtime" +version = "37.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c2a6148bf0ba74999ecfea9b4c1ade544f0663e0baba19630bb7761b2142b19" +dependencies = [ + "docify", + "either", + "hash256-std-hasher", + "impl-trait-for-tuples", + "log", + "num-traits", + "parity-scale-codec", + "paste", + "rand", + "scale-info", + "serde", + "simple-mermaid 0.1.1", + "sp-application-crypto 36.0.0", + "sp-arithmetic 26.0.0", + "sp-core 33.0.1", + "sp-io 36.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-weights 31.0.0", +] + [[package]] name = "sp-runtime-interface" version = "17.0.0" @@ -20370,7 +22585,7 @@ dependencies = [ "bytes", "impl-trait-for-tuples", "parity-scale-codec", - "primitive-types", + "primitive-types 0.12.2", "sp-externalities 0.19.0", "sp-runtime-interface-proc-macro 11.0.0", "sp-std 8.0.0", @@ -20387,15 +22602,15 @@ dependencies = [ "bytes", "impl-trait-for-tuples", "parity-scale-codec", - "polkavm-derive", - "primitive-types", + "polkavm-derive 0.9.1", + "primitive-types 0.13.1", "rustversion", - "sp-core", + "sp-core 28.0.0", "sp-externalities 0.25.0", - "sp-io", + "sp-io 30.0.0", "sp-runtime-interface-proc-macro 17.0.0", "sp-runtime-interface-test-wasm", - "sp-state-machine", + "sp-state-machine 0.35.0", "sp-std 14.0.0", "sp-storage 19.0.0", "sp-tracing 16.0.0", @@ -20404,16 +22619,56 @@ dependencies = [ "trybuild", ] +[[package]] +name = "sp-runtime-interface" +version = "26.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a675ea4858333d4d755899ed5ed780174aa34fec15953428d516af5452295" +dependencies = [ + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec", + "polkavm-derive 0.8.0", + "primitive-types 0.12.2", + "sp-externalities 0.27.0", + "sp-runtime-interface-proc-macro 18.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-storage 20.0.0", + "sp-tracing 16.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-wasm-interface 20.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "static_assertions", +] + +[[package]] +name = "sp-runtime-interface" +version = "27.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "647db5e1dc481686628b41554e832df6ab400c4b43a6a54e54d3b0a71ca404aa" +dependencies = [ + "bytes", + "impl-trait-for-tuples", + "parity-scale-codec", + "polkavm-derive 0.9.1", + "primitive-types 0.12.2", + "sp-externalities 0.28.0", + "sp-runtime-interface-proc-macro 18.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-storage 21.0.0", + "sp-tracing 17.0.0", + "sp-wasm-interface 21.0.0", + "static_assertions", +] + [[package]] name = "sp-runtime-interface-proc-macro" version = "11.0.0" -source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" +source = "git+https://github.com/paritytech/polkadot-sdk#838a534da874cf6071fba1df07643c6c5b033ae0" dependencies = [ "Inflector", "proc-macro-crate 1.3.1", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -20423,23 +22678,37 @@ dependencies = [ "Inflector", "expander", "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", +] + +[[package]] +name = "sp-runtime-interface-proc-macro" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0195f32c628fee3ce1dfbbf2e7e52a30ea85f3589da9fe62a8b816d70fc06294" +dependencies = [ + "Inflector", + "expander", + "proc-macro-crate 3.1.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] name = "sp-runtime-interface-test" version = "2.0.0" dependencies = [ - "sc-executor", - "sc-executor-common", - "sp-io", - "sp-runtime", + "sc-executor 0.32.0", + "sc-executor-common 0.29.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-runtime-interface 24.0.0", "sp-runtime-interface-test-wasm", "sp-runtime-interface-test-wasm-deprecated", - "sp-state-machine", + "sp-state-machine 0.35.0", "tracing", "tracing-core", ] @@ -20449,8 +22718,8 @@ name = "sp-runtime-interface-test-wasm" version = "2.0.0" dependencies = [ "bytes", - "sp-core", - "sp-io", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-runtime-interface 24.0.0", "substrate-wasm-builder", ] @@ -20459,8 +22728,8 @@ dependencies = [ name = "sp-runtime-interface-test-wasm-deprecated" version = "2.0.0" dependencies = [ - "sp-core", - "sp-io", + "sp-core 28.0.0", + "sp-io 30.0.0", "sp-runtime-interface 24.0.0", "substrate-wasm-builder", ] @@ -20471,10 +22740,10 @@ version = "27.0.0" dependencies = [ "parity-scale-codec", "scale-info", - "sp-api", - "sp-core", - "sp-keystore", - "sp-runtime", + "sp-api 26.0.0", + "sp-core 28.0.0", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", "sp-staking", ] @@ -20486,8 +22755,8 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -20504,14 +22773,78 @@ dependencies = [ "pretty_assertions", "rand", "smallvec", - "sp-core", + "sp-core 28.0.0", "sp-externalities 0.25.0", - "sp-panic-handler", - "sp-runtime", - "sp-trie", + "sp-panic-handler 13.0.0", + "sp-runtime 31.0.1", + "sp-trie 29.0.0", + "thiserror", + "tracing", + "trie-db 0.29.1", +] + +[[package]] +name = "sp-state-machine" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1eae0eac8034ba14437e772366336f579398a46d101de13dbb781ab1e35e67c5" +dependencies = [ + "hash-db", + "log", + "parity-scale-codec", + "parking_lot 0.12.3", + "rand", + "smallvec", + "sp-core 31.0.0", + "sp-externalities 0.27.0", + "sp-panic-handler 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-trie 32.0.0", + "thiserror", + "tracing", + "trie-db 0.28.0", +] + +[[package]] +name = "sp-state-machine" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18084cb996c27d5d99a88750e0a8eb4af6870a40df97872a5923e6d293d95fb9" +dependencies = [ + "hash-db", + "log", + "parity-scale-codec", + "parking_lot 0.12.3", + "rand", + "smallvec", + "sp-core 32.0.0", + "sp-externalities 0.28.0", + "sp-panic-handler 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-trie 34.0.0", + "thiserror", + "tracing", + "trie-db 0.29.1", +] + +[[package]] +name = "sp-state-machine" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f6ac196ea92c4d0613c071e1a050765dbfa30107a990224a4aba02c7dbcd063" +dependencies = [ + "hash-db", + "log", + "parity-scale-codec", + "parking_lot 0.12.3", + "rand", + "smallvec", + "sp-core 33.0.1", + "sp-externalities 0.28.0", + "sp-panic-handler 13.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-trie 35.0.0", "thiserror", "tracing", - "trie-db", + "trie-db 0.29.1", ] [[package]] @@ -20519,19 +22852,19 @@ name = "sp-statement-store" version = "10.0.0" dependencies = [ "aes-gcm", - "curve25519-dalek", + "curve25519-dalek 4.1.3", "ed25519-dalek", "hkdf", "parity-scale-codec", "rand", "scale-info", "sha2 0.10.8", - "sp-api", - "sp-application-crypto", - "sp-core", - "sp-crypto-hashing", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", "sp-externalities 0.25.0", - "sp-runtime", + "sp-runtime 31.0.1", "sp-runtime-interface 24.0.0", "thiserror", "x25519-dalek", @@ -20546,12 +22879,18 @@ source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf5 name = "sp-std" version = "14.0.0" +[[package]] +name = "sp-std" +version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8ee986414b0a9ad741776762f4083cd3a5128449b982a3919c4df36874834" + [[package]] name = "sp-storage" version = "13.0.0" source = "git+https://github.com/paritytech/polkadot-sdk#82912acb33a9030c0ef3bf590a34fca09b72dc5f" dependencies = [ - "impl-serde", + "impl-serde 0.4.0", "parity-scale-codec", "ref-cast", "serde", @@ -20563,13 +22902,40 @@ dependencies = [ name = "sp-storage" version = "19.0.0" dependencies = [ - "impl-serde", + "impl-serde 0.5.0", "parity-scale-codec", "ref-cast", "serde", "sp-debug-derive 14.0.0", ] +[[package]] +name = "sp-storage" +version = "20.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dba5791cb3978e95daf99dad919ecb3ec35565604e88cd38d805d9d4981e8bd" +dependencies = [ + "impl-serde 0.4.0", + "parity-scale-codec", + "ref-cast", + "serde", + "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sp-storage" +version = "21.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99c82989b3a4979a7e1ad848aad9f5d0b4388f1f454cc131766526601ab9e8f8" +dependencies = [ + "impl-serde 0.4.0", + "parity-scale-codec", + "ref-cast", + "serde", + "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "sp-test-primitives" version = "2.0.0" @@ -20577,9 +22943,9 @@ dependencies = [ "parity-scale-codec", "scale-info", "serde", - "sp-application-crypto", - "sp-core", - "sp-runtime", + "sp-application-crypto 30.0.0", + "sp-core 28.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -20589,7 +22955,7 @@ dependencies = [ "async-trait", "parity-scale-codec", "sp-inherents", - "sp-runtime", + "sp-runtime 31.0.1", "thiserror", ] @@ -20615,12 +22981,37 @@ dependencies = [ "tracing-subscriber 0.3.18", ] +[[package]] +name = "sp-tracing" +version = "16.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0351810b9d074df71c4514c5228ed05c250607cba131c1c9d1526760ab69c05c" +dependencies = [ + "parity-scale-codec", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tracing", + "tracing-core", + "tracing-subscriber 0.2.25", +] + +[[package]] +name = "sp-tracing" +version = "17.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90b3decf116db9f1dfaf1f1597096b043d0e12c952d3bcdc018c6d6b77deec7e" +dependencies = [ + "parity-scale-codec", + "tracing", + "tracing-core", + "tracing-subscriber 0.2.25", +] + [[package]] name = "sp-transaction-pool" version = "26.0.0" dependencies = [ - "sp-api", - "sp-runtime", + "sp-api 26.0.0", + "sp-runtime 31.0.1", ] [[package]] @@ -20630,10 +23021,10 @@ dependencies = [ "async-trait", "parity-scale-codec", "scale-info", - "sp-core", + "sp-core 28.0.0", "sp-inherents", - "sp-runtime", - "sp-trie", + "sp-runtime 31.0.1", + "sp-trie 29.0.0", ] [[package]] @@ -20644,7 +23035,6 @@ dependencies = [ "array-bytes", "criterion", "hash-db", - "lazy_static", "memory-db", "nohash-hasher", "parity-scale-codec", @@ -20652,30 +23042,121 @@ dependencies = [ "rand", "scale-info", "schnellru", - "sp-core", + "sp-core 28.0.0", "sp-externalities 0.25.0", - "sp-runtime", + "sp-runtime 31.0.1", "thiserror", "tracing", "trie-bench", - "trie-db", + "trie-db 0.29.1", "trie-root", "trie-standardmap", ] +[[package]] +name = "sp-trie" +version = "32.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1aa91ad26c62b93d73e65f9ce7ebd04459c4bad086599348846a81988d6faa4" +dependencies = [ + "ahash 0.8.11", + "hash-db", + "lazy_static", + "memory-db", + "nohash-hasher", + "parity-scale-codec", + "parking_lot 0.12.3", + "rand", + "scale-info", + "schnellru", + "sp-core 31.0.0", + "sp-externalities 0.27.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror", + "tracing", + "trie-db 0.28.0", + "trie-root", +] + +[[package]] +name = "sp-trie" +version = "34.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87727eced997f14d0f79e3a5186a80e38a9de87f6e9dc0baea5ebf8b7f9d8b66" +dependencies = [ + "ahash 0.8.11", + "hash-db", + "lazy_static", + "memory-db", + "nohash-hasher", + "parity-scale-codec", + "parking_lot 0.12.3", + "rand", + "scale-info", + "schnellru", + "sp-core 32.0.0", + "sp-externalities 0.28.0", + "thiserror", + "tracing", + "trie-db 0.29.1", + "trie-root", +] + +[[package]] +name = "sp-trie" +version = "35.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a61ab0c3e003f457203702e4753aa5fe9e762380543fada44650b1217e4aa5a5" +dependencies = [ + "ahash 0.8.11", + "hash-db", + "lazy_static", + "memory-db", + "nohash-hasher", + "parity-scale-codec", + "parking_lot 0.12.3", + "rand", + "scale-info", + "schnellru", + "sp-core 33.0.1", + "sp-externalities 0.28.0", + "thiserror", + "tracing", + "trie-db 0.29.1", + "trie-root", +] + [[package]] name = "sp-version" version = "29.0.0" dependencies = [ - "impl-serde", + "impl-serde 0.5.0", "parity-scale-codec", "parity-wasm", "scale-info", "serde", - "sp-crypto-hashing-proc-macro", - "sp-runtime", + "sp-crypto-hashing-proc-macro 0.1.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", - "sp-version-proc-macro", + "sp-version-proc-macro 13.0.0", + "thiserror", +] + +[[package]] +name = "sp-version" +version = "35.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff74bf12b4f7d29387eb1caeec5553209a505f90a2511d2831143b970f89659" +dependencies = [ + "impl-serde 0.4.0", + "parity-scale-codec", + "parity-wasm", + "scale-info", + "serde", + "sp-crypto-hashing-proc-macro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-runtime 37.0.0", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-version-proc-macro 14.0.0", "thiserror", ] @@ -20684,10 +23165,23 @@ name = "sp-version-proc-macro" version = "13.0.0" dependencies = [ "parity-scale-codec", - "proc-macro2 1.0.82", - "quote 1.0.35", - "sp-version", - "syn 2.0.61", + "proc-macro-warning 1.0.0", + "proc-macro2 1.0.86", + "quote 1.0.37", + "sp-version 29.0.0", + "syn 2.0.82", +] + +[[package]] +name = "sp-version-proc-macro" +version = "14.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aee8f6730641a65fcf0c8f9b1e448af4b3bb083d08058b47528188bccc7b7a7" +dependencies = [ + "parity-scale-codec", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -20714,6 +23208,33 @@ dependencies = [ "wasmtime", ] +[[package]] +name = "sp-wasm-interface" +version = "20.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef97172c42eb4c6c26506f325f48463e9bc29b2034a587f1b9e48c751229bee" +dependencies = [ + "anyhow", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmtime", +] + +[[package]] +name = "sp-wasm-interface" +version = "21.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b04b919e150b4736d85089d49327eab65507deb1485eec929af69daa2278eb3" +dependencies = [ + "anyhow", + "impl-trait-for-tuples", + "log", + "parity-scale-codec", + "wasmtime", +] + [[package]] name = "sp-weights" version = "27.0.0" @@ -20724,10 +23245,41 @@ dependencies = [ "schemars", "serde", "smallvec", - "sp-arithmetic", + "sp-arithmetic 23.0.0", "sp-debug-derive 14.0.0", ] +[[package]] +name = "sp-weights" +version = "30.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9af6c661fe3066b29f9e1d258000f402ff5cc2529a9191972d214e5871d0ba87" +dependencies = [ + "bounded-collections", + "parity-scale-codec", + "scale-info", + "serde", + "smallvec", + "sp-arithmetic 25.0.0", + "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-std 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sp-weights" +version = "31.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93cdaf72a1dad537bbb130ba4d47307ebe5170405280ed1aa31fa712718a400e" +dependencies = [ + "bounded-collections", + "parity-scale-codec", + "scale-info", + "serde", + "smallvec", + "sp-arithmetic 26.0.0", + "sp-debug-derive 14.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "spin" version = "0.5.2" @@ -20742,9 +23294,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", @@ -20769,8 +23321,8 @@ checksum = "5e6915280e2d0db8911e5032a5c275571af6bdded2916abd691a659be25d3439" dependencies = [ "Inflector", "num-format", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "serde", "serde_json", "unicode-xid 0.2.4", @@ -20794,8 +23346,8 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f07d54c4d01a1713eb363b55ba51595da15f6f1211435b71466460da022aa140" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -20809,11 +23361,13 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" name = "staging-chain-spec-builder" version = "1.6.1" dependencies = [ - "clap 4.5.3", + "clap 4.5.13", "log", "sc-chain-spec", + "serde", "serde_json", "sp-tracing 16.0.0", + "substrate-test-runtime", ] [[package]] @@ -20822,11 +23376,11 @@ version = "3.0.0-dev" dependencies = [ "array-bytes", "assert_cmd", - "clap 4.5.3", + "clap 4.5.13", "clap_complete", "criterion", "futures", - "jsonrpsee", + "jsonrpsee 0.24.3", "kitchensink-runtime", "log", "nix 0.28.0", @@ -20836,15 +23390,18 @@ dependencies = [ "parity-scale-codec", "platforms", "polkadot-sdk", + "pretty_assertions", "rand", "regex", "sc-service-test", "scale-info", "serde", "serde_json", - "soketto 0.7.1", + "soketto 0.8.0", + "sp-keyring", "staging-node-inspect", "substrate-cli-test-utils", + "subxt-signer", "tempfile", "tokio", "tokio-util", @@ -20856,15 +23413,15 @@ dependencies = [ name = "staging-node-inspect" version = "0.12.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.13", "parity-scale-codec", "sc-cli", "sc-client-api", "sc-service", "sp-blockchain", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-statement-store", "thiserror", ] @@ -20878,7 +23435,7 @@ dependencies = [ "frame-system", "parity-scale-codec", "scale-info", - "sp-runtime", + "sp-runtime 31.0.1", ] [[package]] @@ -20901,8 +23458,9 @@ dependencies = [ "scale-info", "schemars", "serde", - "sp-io", - "sp-weights", + "sp-io 30.0.0", + "sp-runtime 31.0.1", + "sp-weights 27.0.0", "xcm-procedural", ] @@ -20915,6 +23473,7 @@ dependencies = [ "frame-system", "impl-trait-for-tuples", "log", + "pallet-asset-conversion", "pallet-assets", "pallet-balances", "pallet-salary", @@ -20925,12 +23484,13 @@ dependencies = [ "polkadot-primitives", "polkadot-runtime-parachains", "polkadot-test-runtime", - "primitive-types", + "primitive-types 0.13.1", "scale-info", - "sp-arithmetic", - "sp-io", - "sp-runtime", - "sp-weights", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", + "sp-weights 27.0.0", "staging-xcm", "staging-xcm-executor", ] @@ -20945,11 +23505,11 @@ dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", "scale-info", - "sp-arithmetic", - "sp-core", - "sp-io", - "sp-runtime", - "sp-weights", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", + "sp-weights 27.0.0", "staging-xcm", "tracing", ] @@ -20967,7 +23527,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a2a1c578e98c1c16fc3b8ec1328f7659a500737d7a0c6d625e73e830ff9c1f6" dependencies = [ "bitflags 1.3.2", - "cfg_aliases", + "cfg_aliases 0.1.1", "libc", "parking_lot 0.11.2", "parking_lot_core 0.8.6", @@ -20981,33 +23541,13 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70a2595fc3aa78f2d0e45dd425b22282dd863273761cc77780914b2cf3003acf" dependencies = [ - "cfg_aliases", + "cfg_aliases 0.1.1", "memchr", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] -[[package]] -name = "str0m" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6706347e49b13373f7ddfafad47df7583ed52083d6fc8a594eb2c80497ef959d" -dependencies = [ - "combine", - "crc", - "fastrand 2.1.0", - "hmac 0.12.1", - "once_cell", - "openssl", - "openssl-sys", - "sctp-proto", - "serde", - "sha-1 0.10.1", - "thiserror", - "tracing", -] - [[package]] name = "string-interner" version = "0.17.0" @@ -21015,7 +23555,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c6a0d765f5807e98a091107bae0a56ea3799f66a5de47b2c84c94a39c09974e" dependencies = [ "cfg-if", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "serde", ] @@ -21033,9 +23573,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strsim" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "structopt" @@ -21056,8 +23596,8 @@ checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" dependencies = [ "heck 0.3.3", "proc-macro-error", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] @@ -21078,11 +23618,11 @@ checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" [[package]] name = "strum" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ - "strum_macros 0.26.2", + "strum_macros 0.26.4", ] [[package]] @@ -21092,8 +23632,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "rustversion", "syn 1.0.109", ] @@ -21105,33 +23645,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "rustversion", - "syn 2.0.61", + "syn 2.0.82", ] [[package]] name = "strum_macros" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.4.1", - "proc-macro2 1.0.82", - "quote 1.0.35", + "heck 0.5.0", + "proc-macro2 1.0.86", + "quote 1.0.37", "rustversion", - "syn 2.0.61", + "syn 2.0.82", ] [[package]] name = "subkey" version = "9.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.13", "sc-cli", ] +[[package]] +name = "subrpcer" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a00780fcd4ebedf099da78a562744c6f17bda08d1223928c3104dd26081b44" +dependencies = [ + "affix", + "serde", + "serde_json", +] + [[package]] name = "substrate-bip39" version = "0.4.7" @@ -21145,6 +23696,32 @@ dependencies = [ "zeroize", ] +[[package]] +name = "substrate-bip39" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2b564c293e6194e8b222e52436bcb99f60de72043c7f845cf6c4406db4df121" +dependencies = [ + "hmac 0.12.1", + "pbkdf2", + "schnorrkel 0.11.4", + "sha2 0.10.8", + "zeroize", +] + +[[package]] +name = "substrate-bip39" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca58ffd742f693dc13d69bdbb2e642ae239e0053f6aab3b104252892f856700a" +dependencies = [ + "hmac 0.12.1", + "pbkdf2", + "schnorrkel 0.11.4", + "sha2 0.10.8", + "zeroize", +] + [[package]] name = "substrate-build-script-utils" version = "11.0.0" @@ -21166,19 +23743,36 @@ dependencies = [ "tokio", ] +[[package]] +name = "substrate-differ" +version = "0.21.3" +source = "git+https://github.com/chevdor/subwasm?rev=v0.21.3#aa8acb6fdfb34144ac51ab95618a9b37fa251295" +dependencies = [ + "comparable", + "document-features", + "frame-metadata 16.0.0", + "log", + "num-format", + "scale-info", + "serde", + "serde_json", + "thiserror", + "wasm-testbed", +] + [[package]] name = "substrate-frame-rpc-support" version = "29.0.0" dependencies = [ "frame-support", "frame-system", - "jsonrpsee", + "jsonrpsee 0.24.3", "parity-scale-codec", "sc-rpc-api", "scale-info", "serde", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "sp-storage 19.0.0", "tokio", ] @@ -21191,17 +23785,17 @@ dependencies = [ "docify", "frame-system-rpc-runtime-api", "futures", - "jsonrpsee", + "jsonrpsee 0.24.3", "log", "parity-scale-codec", "sc-rpc-api", "sc-transaction-pool", "sc-transaction-pool-api", - "sp-api", + "sp-api 26.0.0", "sp-block-builder", "sp-blockchain", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "sp-tracing 16.0.0", "substrate-test-runtime-client", "tokio", @@ -21255,11 +23849,11 @@ dependencies = [ "relay-utils", "scale-info", "sp-consensus-grandpa", - "sp-core", - "sp-runtime", - "sp-trie", + "sp-core 28.0.0", + "sp-runtime 31.0.1", + "sp-trie 29.0.0", "structopt", - "strum 0.26.2", + "strum 0.26.3", "thiserror", ] @@ -21268,30 +23862,46 @@ name = "substrate-rpc-client" version = "0.33.0" dependencies = [ "async-trait", - "jsonrpsee", + "jsonrpsee 0.24.3", "log", "sc-rpc-api", "serde", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "tokio", ] +[[package]] +name = "substrate-runtime-proposal-hash" +version = "0.21.3" +source = "git+https://github.com/chevdor/subwasm?rev=v0.21.3#aa8acb6fdfb34144ac51ab95618a9b37fa251295" +dependencies = [ + "blake2 0.10.6", + "frame-metadata 16.0.0", + "hex", + "parity-scale-codec", + "sp-core 32.0.0", + "sp-io 35.0.0", + "sp-runtime 36.0.0", + "sp-wasm-interface 21.0.0", + "thiserror", +] + [[package]] name = "substrate-state-trie-migration-rpc" version = "27.0.0" dependencies = [ - "jsonrpsee", + "jsonrpsee 0.24.3", "parity-scale-codec", "sc-client-api", "sc-rpc-api", "serde", "serde_json", - "sp-core", - "sp-runtime", - "sp-state-machine", - "sp-trie", - "trie-db", + "sp-core 28.0.0", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", + "sp-trie 29.0.0", + "trie-db 0.29.1", ] [[package]] @@ -21305,18 +23915,18 @@ dependencies = [ "sc-client-api", "sc-client-db", "sc-consensus", - "sc-executor", + "sc-executor 0.32.0", "sc-offchain", "sc-service", "serde", "serde_json", "sp-blockchain", "sp-consensus", - "sp-core", + "sp-core 28.0.0", "sp-keyring", - "sp-keystore", - "sp-runtime", - "sp-state-machine", + "sp-keystore 0.34.0", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "tokio", ] @@ -21338,38 +23948,38 @@ dependencies = [ "parity-scale-codec", "sc-block-builder", "sc-chain-spec", - "sc-executor", - "sc-executor-common", + "sc-executor 0.32.0", + "sc-executor-common 0.29.0", "sc-service", "scale-info", "serde", "serde_json", - "sp-api", - "sp-application-crypto", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", "sp-block-builder", "sp-consensus", "sp-consensus-aura", "sp-consensus-babe", "sp-consensus-grandpa", - "sp-core", - "sp-crypto-hashing", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", "sp-externalities 0.25.0", "sp-genesis-builder", "sp-inherents", - "sp-io", + "sp-io 30.0.0", "sp-keyring", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", - "sp-state-machine", + "sp-state-machine 0.35.0", "sp-tracing 16.0.0", "sp-transaction-pool", - "sp-trie", - "sp-version", + "sp-trie 29.0.0", + "sp-version 29.0.0", "substrate-test-runtime-client", "substrate-wasm-builder", "tracing", - "trie-db", + "trie-db 0.29.1", ] [[package]] @@ -21380,11 +23990,11 @@ dependencies = [ "sc-block-builder", "sc-client-api", "sc-consensus", - "sp-api", + "sp-api 26.0.0", "sp-blockchain", "sp-consensus", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "substrate-test-client", "substrate-test-runtime", ] @@ -21394,12 +24004,13 @@ name = "substrate-test-runtime-transaction-pool" version = "2.0.0" dependencies = [ "futures", + "log", "parity-scale-codec", "parking_lot 0.12.3", "sc-transaction-pool", "sc-transaction-pool-api", "sp-blockchain", - "sp-runtime", + "sp-runtime 31.0.1", "substrate-test-runtime-client", "thiserror", ] @@ -21423,20 +24034,22 @@ dependencies = [ "cargo_metadata", "console", "filetime", - "frame-metadata", + "frame-metadata 16.0.0", + "jobserver", "merkleized-metadata", "parity-scale-codec", "parity-wasm", - "polkavm-linker", - "sc-executor", - "sp-core", - "sp-io", - "sp-maybe-compressed-blob", + "polkavm-linker 0.9.2", + "sc-executor 0.32.0", + "shlex", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-maybe-compressed-blob 11.0.0", "sp-tracing 16.0.0", - "sp-version", - "strum 0.26.2", + "sp-version 29.0.0", + "strum 0.26.3", "tempfile", - "toml 0.8.8", + "toml 0.8.12", "walkdir", "wasm-opt", ] @@ -21459,6 +24072,187 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142" +[[package]] +name = "subwasmlib" +version = "0.21.3" +source = "git+https://github.com/chevdor/subwasm?rev=v0.21.3#aa8acb6fdfb34144ac51ab95618a9b37fa251295" +dependencies = [ + "calm_io", + "frame-metadata 16.0.0", + "hex", + "ipfs-hasher", + "log", + "num-format", + "rand", + "reqwest 0.12.5", + "scale-info", + "semver 1.0.18", + "serde", + "serde_json", + "sp-version 35.0.0", + "substrate-differ", + "thiserror", + "url", + "uuid", + "wasm-loader", + "wasm-testbed", +] + +[[package]] +name = "subxt" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a160cba1edbf3ec4fbbeaea3f1a185f70448116a6bccc8276bb39adb3b3053bd" +dependencies = [ + "async-trait", + "derive-where", + "either", + "frame-metadata 16.0.0", + "futures", + "hex", + "impl-serde 0.4.0", + "instant", + "jsonrpsee 0.22.5", + "parity-scale-codec", + "primitive-types 0.12.2", + "reconnecting-jsonrpsee-ws-client", + "scale-bits", + "scale-decode", + "scale-encode", + "scale-info", + "scale-value", + "serde", + "serde_json", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subxt-core", + "subxt-lightclient", + "subxt-macro", + "subxt-metadata", + "thiserror", + "tokio-util", + "tracing", + "url", +] + +[[package]] +name = "subxt-codegen" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d703dca0905cc5272d7cc27a4ac5f37dcaae7671acc7fef0200057cc8c317786" +dependencies = [ + "frame-metadata 16.0.0", + "heck 0.5.0", + "hex", + "jsonrpsee 0.22.5", + "parity-scale-codec", + "proc-macro2 1.0.86", + "quote 1.0.37", + "scale-info", + "scale-typegen", + "subxt-metadata", + "syn 2.0.82", + "thiserror", + "tokio", +] + +[[package]] +name = "subxt-core" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59f41eb2e2eea6ed45649508cc735f92c27f1fcfb15229e75f8270ea73177345" +dependencies = [ + "base58", + "blake2 0.10.6", + "derive-where", + "frame-metadata 16.0.0", + "hashbrown 0.14.5", + "hex", + "impl-serde 0.4.0", + "parity-scale-codec", + "primitive-types 0.12.2", + "scale-bits", + "scale-decode", + "scale-encode", + "scale-info", + "scale-value", + "serde", + "serde_json", + "sp-core 31.0.0", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sp-runtime 34.0.0", + "subxt-metadata", + "tracing", +] + +[[package]] +name = "subxt-lightclient" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d9406fbdb9548c110803cb8afa750f8b911d51eefdf95474b11319591d225d9" +dependencies = [ + "futures", + "futures-util", + "serde", + "serde_json", + "smoldot-light 0.14.0", + "thiserror", + "tokio", + "tokio-stream", + "tracing", +] + +[[package]] +name = "subxt-macro" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c195f803d70687e409aba9be6c87115b5da8952cd83c4d13f2e043239818fcd" +dependencies = [ + "darling 0.20.10", + "parity-scale-codec", + "proc-macro-error", + "quote 1.0.37", + "scale-typegen", + "subxt-codegen", + "syn 2.0.82", +] + +[[package]] +name = "subxt-metadata" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "738be5890fdeff899bbffff4d9c0f244fe2a952fb861301b937e3aa40ebb55da" +dependencies = [ + "frame-metadata 16.0.0", + "hashbrown 0.14.5", + "parity-scale-codec", + "scale-info", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "subxt-signer" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49888ae6ae90fe01b471193528eea5bd4ed52d8eecd2d13f4a2333b87388850" +dependencies = [ + "bip32", + "bip39", + "cfg-if", + "hex", + "hmac 0.12.1", + "keccak-hash", + "parity-scale-codec", + "pbkdf2", + "regex", + "schnorrkel 0.11.4", + "secp256k1", + "secrecy", + "sha2 0.10.8", + "sp-crypto-hashing 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subxt-core", + "zeroize", +] + [[package]] name = "sval" version = "2.6.1" @@ -21567,19 +24361,19 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.61" +version = "2.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" +checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "unicode-ident", ] @@ -21590,19 +24384,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b837ef12ab88835251726eb12237655e61ec8dc8a280085d1961cdc3dfd047" dependencies = [ "paste", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" + [[package]] name = "synstructure" version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", "unicode-xid 0.2.4", ] @@ -21613,9 +24413,9 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -21686,10 +24486,21 @@ dependencies = [ "cfg-if", "fastrand 2.1.0", "redox_syscall 0.4.1", - "rustix 0.38.21", + "rustix 0.38.25", "windows-sys 0.48.0", ] +[[package]] +name = "template-zombienet-tests" +version = "0.0.0" +dependencies = [ + "anyhow", + "env_logger 0.11.3", + "log", + "tokio", + "zombienet-sdk", +] + [[package]] name = "termcolor" version = "1.2.0" @@ -21705,7 +24516,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ - "rustix 0.38.21", + "rustix 0.38.25", "windows-sys 0.48.0", ] @@ -21732,9 +24543,9 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -21744,7 +24555,7 @@ dependencies = [ "dlmalloc", "parity-scale-codec", "polkadot-parachain-primitives", - "sp-io", + "sp-io 30.0.0", "substrate-wasm-builder", "tiny-keccak", ] @@ -21753,7 +24564,7 @@ dependencies = [ name = "test-parachain-adder-collator" version = "1.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.13", "futures", "futures-timer", "log", @@ -21768,7 +24579,7 @@ dependencies = [ "polkadot-test-service", "sc-cli", "sc-service", - "sp-core", + "sp-core 28.0.0", "sp-keyring", "substrate-test-utils", "test-parachain-adder", @@ -21791,7 +24602,7 @@ dependencies = [ "log", "parity-scale-codec", "polkadot-parachain-primitives", - "sp-io", + "sp-io 30.0.0", "substrate-wasm-builder", "tiny-keccak", ] @@ -21800,7 +24611,7 @@ dependencies = [ name = "test-parachain-undying-collator" version = "1.0.0" dependencies = [ - "clap 4.5.3", + "clap 4.5.13", "futures", "futures-timer", "log", @@ -21815,7 +24626,7 @@ dependencies = [ "polkadot-test-service", "sc-cli", "sc-service", - "sp-core", + "sp-core 28.0.0", "sp-keyring", "substrate-test-utils", "test-parachain-undying", @@ -21827,7 +24638,7 @@ name = "test-parachains" version = "1.0.0" dependencies = [ "parity-scale-codec", - "sp-core", + "sp-core 28.0.0", "test-parachain-adder", "test-parachain-halt", "tiny-keccak", @@ -21840,7 +24651,7 @@ dependencies = [ "frame-support", "polkadot-primitives", "smallvec", - "sp-runtime", + "sp-runtime 31.0.1", ] [[package]] @@ -21852,7 +24663,7 @@ dependencies = [ "polkadot-core-primitives", "rococo-runtime-constants", "smallvec", - "sp-runtime", + "sp-runtime 31.0.1", "staging-xcm", "westend-runtime-constants", ] @@ -21874,9 +24685,9 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] @@ -21896,20 +24707,20 @@ version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "syn 1.0.109", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -21937,19 +24748,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "thrift" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b82ca8f46f95b3ce96081fe3dd89160fdea970c254bb72925255d1b62aae692e" -dependencies = [ - "byteorder", - "integer-encoding", - "log", - "ordered-float", - "threadpool", -] - [[package]] name = "tikv-jemalloc-ctl" version = "0.5.4" @@ -21983,14 +24781,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", @@ -21998,16 +24798,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", ] @@ -22047,32 +24848,51 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", "socket2 0.5.7", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-io-timeout" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" +dependencies = [ + "pin-project-lite", + "tokio", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "native-tls", + "tokio", ] [[package]] @@ -22096,6 +24916,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls 0.22.4", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.0" @@ -22109,9 +24940,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -22121,9 +24952,9 @@ dependencies = [ [[package]] name = "tokio-test" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89b3cbabd3ae862100094ae433e1def582cf86451b4e9bf83aa7ac1d8a7d719" +checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" dependencies = [ "async-stream", "bytes", @@ -22144,7 +24975,7 @@ dependencies = [ "rustls-native-certs 0.6.3", "tokio", "tokio-rustls 0.24.1", - "tungstenite", + "tungstenite 0.20.1", ] [[package]] @@ -22158,6 +24989,7 @@ dependencies = [ "futures-io", "futures-sink", "pin-project-lite", + "slab", "tokio", ] @@ -22172,14 +25004,26 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.8" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.21.0", + "toml_edit 0.19.15", +] + +[[package]] +name = "toml" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.12", ] [[package]] @@ -22198,8 +25042,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap 2.2.3", + "serde", + "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.5.15", ] [[package]] @@ -22207,25 +25053,58 @@ name = "toml_edit" version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +dependencies = [ + "indexmap 2.2.3", + "toml_datetime", + "winnow 0.5.15", +] + +[[package]] +name = "toml_edit" +version = "0.22.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" dependencies = [ "indexmap 2.2.3", "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.6.18", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", ] [[package]] -name = "tower" -version = "0.4.13" +name = "tower-http" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" dependencies = [ + "base64 0.21.7", + "bitflags 2.6.0", + "bytes", "futures-core", "futures-util", - "pin-project", + "http 0.2.9", + "http-body 0.4.5", + "http-range-header", + "mime", "pin-project-lite", - "tokio", "tower-layer", "tower-service", "tracing", @@ -22277,9 +25156,9 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -22319,9 +25198,9 @@ dependencies = [ "assert_matches", "expander", "proc-macro-crate 3.1.0", - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -22393,6 +25272,7 @@ dependencies = [ "sharded-slab", "smallvec", "thread_local", + "time", "tracing", "tracing-core", "tracing-log 0.2.0", @@ -22409,16 +25289,29 @@ dependencies = [ "keccak-hasher", "memory-db", "parity-scale-codec", - "trie-db", + "trie-db 0.29.1", "trie-root", "trie-standardmap", ] [[package]] name = "trie-db" -version = "0.29.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65ed83be775d85ebb0e272914fff6462c39b3ddd6dc67b5c1c41271aad280c69" +checksum = "ff28e0f815c2fea41ebddf148e008b077d2faddb026c9555b29696114d602642" +dependencies = [ + "hash-db", + "hashbrown 0.13.2", + "log", + "rustc-hex", + "smallvec", +] + +[[package]] +name = "trie-db" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c992b4f40c234a074d48a757efeabb1a6be88af84c0c23f7ca158950cb0ae7f" dependencies = [ "hash-db", "log", @@ -22565,6 +25458,28 @@ dependencies = [ "utf-8", ] +[[package]] +name = "tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "rand", + "rustls 0.22.4", + "rustls-native-certs 0.7.0", + "rustls-pki-types", + "sha1", + "thiserror", + "url", + "utf-8", +] + [[package]] name = "tuplex" version = "0.1.2" @@ -22607,6 +25522,18 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "uint" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "909988d098b2f738727b161a106cfc7cab00c539c2687a8836f8e565976fb53e" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + [[package]] name = "unarray" version = "0.1.4" @@ -22674,6 +25601,18 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" +[[package]] +name = "unsigned-varint" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f67332660eb59a6f1eb24ff1220c9e8d01738a8503c6002e30bcfe4bd9f2b4a9" + +[[package]] +name = "unsigned-varint" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fdeedbf205afadfe39ae559b75c3240f24e257d0ca27e85f85cb82aa19ac35" + [[package]] name = "unsigned-varint" version = "0.7.2" @@ -22708,6 +25647,24 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "ureq" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" +dependencies = [ + "base64 0.22.1", + "flate2", + "log", + "once_cell", + "rustls 0.23.10", + "rustls-pki-types", + "serde", + "serde_json", + "url", + "webpki-roots 0.26.3", +] + [[package]] name = "url" version = "2.5.2" @@ -22717,6 +25674,7 @@ dependencies = [ "form_urlencoded", "idna 0.5.0", "percent-encoding", + "serde", ] [[package]] @@ -22736,6 +25694,9 @@ name = "uuid" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +dependencies = [ + "getrandom", +] [[package]] name = "valuable" @@ -22820,9 +25781,9 @@ dependencies = [ "digest 0.10.7", "rand", "rand_chacha", - "rand_core", + "rand_core 0.6.4", "sha2 0.10.8", - "sha3", + "sha3 0.10.8", "thiserror", "zeroize", ] @@ -22844,9 +25805,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", @@ -22869,11 +25830,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", @@ -22881,16 +25843,16 @@ 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", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", "wasm-bindgen-shared", ] @@ -22908,32 +25870,32 @@ 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.37", "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", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[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" @@ -22955,8 +25917,8 @@ version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", ] [[package]] @@ -22977,6 +25939,25 @@ dependencies = [ "parity-wasm", ] +[[package]] +name = "wasm-loader" +version = "0.21.3" +source = "git+https://github.com/chevdor/subwasm?rev=v0.21.3#aa8acb6fdfb34144ac51ab95618a9b37fa251295" +dependencies = [ + "array-bytes", + "log", + "multibase 0.9.1", + "multihash 0.19.1", + "serde", + "serde_json", + "sp-maybe-compressed-blob 11.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "subrpcer", + "thiserror", + "tungstenite 0.21.0", + "ureq", + "url", +] + [[package]] name = "wasm-opt" version = "0.116.0" @@ -23017,6 +25998,29 @@ dependencies = [ "cxx-build", ] +[[package]] +name = "wasm-testbed" +version = "0.21.3" +source = "git+https://github.com/chevdor/subwasm?rev=v0.21.3#aa8acb6fdfb34144ac51ab95618a9b37fa251295" +dependencies = [ + "frame-metadata 16.0.0", + "hex", + "log", + "parity-scale-codec", + "sc-executor 0.38.0", + "sc-executor-common 0.34.0", + "scale-info", + "sp-core 33.0.1", + "sp-io 36.0.0", + "sp-runtime 37.0.0", + "sp-state-machine 0.41.0", + "sp-version 35.0.0", + "sp-wasm-interface 21.0.0", + "substrate-runtime-proposal-hash", + "thiserror", + "wasm-loader", +] + [[package]] name = "wasm-timer" version = "0.2.5" @@ -23075,7 +26079,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c128c039340ffd50d4195c3f8ce31aac357f06804cfc494c8b9508d4b30dca4" dependencies = [ "ahash 0.8.11", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "string-interner", ] @@ -23166,7 +26170,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c86437fa68626fe896e5afc69234bb2b5894949083586535f200385adfd71213" dependencies = [ "anyhow", - "base64 0.21.2", + "base64 0.21.7", "bincode", "directories-next", "file-per-thread-logger", @@ -23385,8 +26389,8 @@ dependencies = [ "sp-authority-discovery", "sp-consensus-babe", "sp-consensus-beefy", - "sp-core", - "sp-runtime", + "sp-core 28.0.0", + "sp-runtime 31.0.1", "staging-xcm", "westend-runtime", "westend-runtime-constants", @@ -23397,6 +26401,7 @@ dependencies = [ name = "westend-runtime" version = "7.0.0" dependencies = [ + "approx", "binary-merkle-tree", "bitvec", "frame-benchmarking", @@ -23439,6 +26444,7 @@ dependencies = [ "pallet-nomination-pools-runtime-api", "pallet-offences", "pallet-offences-benchmarking", + "pallet-parameters", "pallet-preimage", "pallet-proxy", "pallet-recovery", @@ -23449,7 +26455,6 @@ dependencies = [ "pallet-session-benchmarking", "pallet-society", "pallet-staking", - "pallet-staking-reward-curve", "pallet-staking-runtime-api", "pallet-state-trie-migration", "pallet-sudo", @@ -23472,28 +26477,29 @@ dependencies = [ "serde_derive", "serde_json", "smallvec", - "sp-api", - "sp-application-crypto", - "sp-arithmetic", + "sp-api 26.0.0", + "sp-application-crypto 30.0.0", + "sp-arithmetic 23.0.0", "sp-authority-discovery", "sp-block-builder", "sp-consensus-babe", "sp-consensus-beefy", - "sp-core", + "sp-consensus-grandpa", + "sp-core 28.0.0", "sp-genesis-builder", "sp-inherents", - "sp-io", + "sp-io 30.0.0", "sp-keyring", "sp-mmr-primitives", "sp-npos-elections", "sp-offchain", - "sp-runtime", + "sp-runtime 31.0.1", "sp-session", "sp-staking", "sp-storage 19.0.0", "sp-tracing 16.0.0", "sp-transaction-pool", - "sp-version", + "sp-version 29.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -23512,9 +26518,9 @@ dependencies = [ "polkadot-primitives", "polkadot-runtime-common", "smallvec", - "sp-core", - "sp-runtime", - "sp-weights", + "sp-core 28.0.0", + "sp-runtime 31.0.1", + "sp-weights 27.0.0", "staging-xcm", "staging-xcm-builder", ] @@ -23526,23 +26532,13 @@ 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", "westend-emulated-chain", ] -[[package]] -name = "which" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" -dependencies = [ - "either", - "libc", - "once_cell", -] - [[package]] name = "wide" version = "0.7.11" @@ -23637,21 +26633,6 @@ dependencies = [ "windows-targets 0.52.0", ] -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-sys" version = "0.45.0" @@ -23859,6 +26840,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" @@ -23869,6 +26859,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "wyz" version = "0.5.1" @@ -23884,8 +26884,8 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" dependencies = [ - "curve25519-dalek", - "rand_core", + "curve25519-dalek 4.1.3", + "rand_core 0.6.4", "serde", "zeroize", ] @@ -23948,8 +26948,8 @@ dependencies = [ "polkadot-sdk-frame", "scale-info", "simple-mermaid 0.1.0", - "sp-io", - "sp-runtime", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", "staging-xcm", "staging-xcm-builder", @@ -23962,6 +26962,7 @@ dependencies = [ name = "xcm-emulator" version = "0.5.0" dependencies = [ + "array-bytes", "cumulus-pallet-parachain-system", "cumulus-pallet-xcmp-queue", "cumulus-primitives-core", @@ -23970,7 +26971,6 @@ dependencies = [ "frame-support", "frame-system", "impl-trait-for-tuples", - "lazy_static", "log", "pallet-balances", "pallet-message-queue", @@ -23980,11 +26980,11 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-primitives", "polkadot-runtime-parachains", - "sp-arithmetic", - "sp-core", - "sp-crypto-hashing", - "sp-io", - "sp-runtime", + "sp-arithmetic 23.0.0", + "sp-core 28.0.0", + "sp-crypto-hashing 0.1.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", "sp-tracing 16.0.0", "staging-xcm", @@ -23996,20 +26996,18 @@ name = "xcm-executor-integration-tests" version = "1.0.0" dependencies = [ "frame-support", - "frame-system", "futures", "pallet-transaction-payment", "pallet-xcm", "parity-scale-codec", - "polkadot-service", "polkadot-test-client", "polkadot-test-runtime", "polkadot-test-service", "sp-consensus", - "sp-core", + "sp-core 28.0.0", "sp-keyring", - "sp-runtime", - "sp-state-machine", + "sp-runtime 31.0.1", + "sp-state-machine 0.35.0", "sp-tracing 16.0.0", "staging-xcm", "staging-xcm-executor", @@ -24020,10 +27018,10 @@ name = "xcm-procedural" version = "7.0.0" dependencies = [ "Inflector", - "proc-macro2 1.0.82", - "quote 1.0.35", + "proc-macro2 1.0.86", + "quote 1.0.37", "staging-xcm", - "syn 2.0.61", + "syn 2.0.82", "trybuild", ] @@ -24031,7 +27029,6 @@ dependencies = [ name = "xcm-runtime-apis" version = "0.1.0" dependencies = [ - "env_logger 0.11.3", "frame-executive", "frame-support", "frame-system", @@ -24042,9 +27039,10 @@ dependencies = [ "pallet-xcm", "parity-scale-codec", "scale-info", - "sp-api", - "sp-io", - "sp-weights", + "sp-api 26.0.0", + "sp-io 30.0.0", + "sp-tracing 16.0.0", + "sp-weights 27.0.0", "staging-xcm", "staging-xcm-builder", "staging-xcm-executor", @@ -24063,8 +27061,8 @@ dependencies = [ "polkadot-primitives", "polkadot-runtime-parachains", "scale-info", - "sp-io", - "sp-runtime", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", "staging-xcm", "staging-xcm-builder", @@ -24087,9 +27085,9 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-runtime-parachains", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", "sp-tracing 16.0.0", "staging-xcm", @@ -24116,9 +27114,9 @@ dependencies = [ "polkadot-parachain-primitives", "polkadot-runtime-parachains", "scale-info", - "sp-core", - "sp-io", - "sp-runtime", + "sp-core 28.0.0", + "sp-io 30.0.0", + "sp-runtime 31.0.1", "sp-std 14.0.0", "staging-xcm", "staging-xcm-builder", @@ -24162,6 +27160,12 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +[[package]] +name = "yap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4524214bc4629eba08d78ceb1d6507070cc0bcbbed23af74e19e6e924a24cf" + [[package]] name = "yasna" version = "0.5.2" @@ -24186,9 +27190,9 @@ version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -24206,9 +27210,9 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.82", - "quote 1.0.35", - "syn 2.0.61", + "proc-macro2 1.0.86", + "quote 1.0.37", + "syn 2.0.82", ] [[package]] @@ -24216,9 +27220,8 @@ name = "zombienet-backchannel" version = "1.0.0" dependencies = [ "futures-util", - "lazy_static", "parity-scale-codec", - "reqwest", + "reqwest 0.11.20", "serde", "serde_json", "thiserror", @@ -24228,6 +27231,137 @@ dependencies = [ "url", ] +[[package]] +name = "zombienet-configuration" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebbfc98adb25076777967f7aad078e74029e129b102eb0812c425432f8c2be7b" +dependencies = [ + "anyhow", + "lazy_static", + "multiaddr 0.18.1", + "regex", + "reqwest 0.11.20", + "serde", + "serde_json", + "thiserror", + "tokio", + "toml 0.7.8", + "url", + "zombienet-support", +] + +[[package]] +name = "zombienet-orchestrator" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b17f4d1d05b3aedf02818eb0f4d5a76664da0e07bb2f7e7d02613e0ef0f316a" +dependencies = [ + "anyhow", + "async-trait", + "futures", + "glob-match", + "hex", + "libp2p", + "libsecp256k1", + "multiaddr 0.18.1", + "rand", + "regex", + "reqwest 0.11.20", + "serde", + "serde_json", + "sha2 0.10.8", + "sp-core 31.0.0", + "subxt", + "subxt-signer", + "thiserror", + "tokio", + "tracing", + "uuid", + "zombienet-configuration", + "zombienet-prom-metrics-parser", + "zombienet-provider", + "zombienet-support", +] + +[[package]] +name = "zombienet-prom-metrics-parser" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7203390ab88919240da3a3eb06b625b6e300e94f98e04ba5141e9138dc663b7d" +dependencies = [ + "pest", + "pest_derive", + "thiserror", +] + +[[package]] +name = "zombienet-provider" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee02ee957ec39b698798fa6dc2a0d5ba4524198471c37d57755e9685b67fb50c" +dependencies = [ + "anyhow", + "async-trait", + "flate2", + "futures", + "hex", + "k8s-openapi", + "kube", + "nix 0.27.1", + "regex", + "reqwest 0.11.20", + "serde", + "serde_json", + "serde_yaml", + "sha2 0.10.8", + "tar", + "thiserror", + "tokio", + "tokio-util", + "tracing", + "url", + "uuid", + "zombienet-configuration", + "zombienet-support", +] + +[[package]] +name = "zombienet-sdk" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f594e67922182277a3da0926f21b693eb5a0c38b32ca7fd6ef16167809fe5064" +dependencies = [ + "async-trait", + "futures", + "lazy_static", + "subxt", + "tokio", + "zombienet-configuration", + "zombienet-orchestrator", + "zombienet-provider", + "zombienet-support", +] + +[[package]] +name = "zombienet-support" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d3144537df7c8939bbb355cc5245a6dc0078446a6cdaf9272268bd1043c788" +dependencies = [ + "anyhow", + "async-trait", + "futures", + "nix 0.27.1", + "rand", + "regex", + "reqwest 0.11.20", + "thiserror", + "tokio", + "tracing", + "uuid", +] + [[package]] name = "zstd" version = "0.11.2+zstd.1.5.2" diff --git a/Cargo.toml b/Cargo.toml index 0999d6304013..049de32b54cf 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", @@ -125,11 +130,11 @@ members = [ "cumulus/parachains/runtimes/glutton/glutton-westend", "cumulus/parachains/runtimes/people/people-rococo", "cumulus/parachains/runtimes/people/people-westend", - "cumulus/parachains/runtimes/starters/seedling", - "cumulus/parachains/runtimes/starters/shell", "cumulus/parachains/runtimes/test-utils", "cumulus/parachains/runtimes/testing/penpal", "cumulus/parachains/runtimes/testing/rococo-parachain", + "cumulus/polkadot-omni-node", + "cumulus/polkadot-omni-node/lib", "cumulus/polkadot-parachain", "cumulus/primitives/aura", "cumulus/primitives/core", @@ -152,6 +157,7 @@ members = [ "polkadot/erasure-coding/fuzzer", "polkadot/node/collation-generation", "polkadot/node/core/approval-voting", + "polkadot/node/core/approval-voting-parallel", "polkadot/node/core/av-store", "polkadot/node/core/backing", "polkadot/node/core/bitfield-signing", @@ -170,7 +176,6 @@ members = [ "polkadot/node/core/runtime-api", "polkadot/node/gum", "polkadot/node/gum/proc-macro", - "polkadot/node/jaeger", "polkadot/node/malus", "polkadot/node/metrics", "polkadot/node/network/approval-distribution", @@ -230,6 +235,7 @@ members = [ "polkadot/xcm/xcm-simulator", "polkadot/xcm/xcm-simulator/example", "polkadot/xcm/xcm-simulator/fuzzer", + "polkadot/zombienet-sdk-tests", "substrate/bin/node/bench", "substrate/bin/node/cli", "substrate/bin/node/inspect", @@ -341,6 +347,7 @@ members = [ "substrate/frame/election-provider-support/solution-type/fuzzer", "substrate/frame/elections-phragmen", "substrate/frame/examples", + "substrate/frame/examples/authorization-tx-extension", "substrate/frame/examples/basic", "substrate/frame/examples/default-config", "substrate/frame/examples/dev-mode", @@ -389,6 +396,11 @@ members = [ "substrate/frame/recovery", "substrate/frame/referenda", "substrate/frame/remark", + "substrate/frame/revive", + "substrate/frame/revive/fixtures", + "substrate/frame/revive/mock-network", + "substrate/frame/revive/proc-macro", + "substrate/frame/revive/uapi", "substrate/frame/root-offences", "substrate/frame/root-testing", "substrate/frame/safe-mode", @@ -431,6 +443,7 @@ members = [ "substrate/frame/tx-pause", "substrate/frame/uniques", "substrate/frame/utility", + "substrate/frame/verify-signature", "substrate/frame/vesting", "substrate/frame/whitelist", "substrate/primitives/api", @@ -517,7 +530,6 @@ members = [ "substrate/utils/prometheus", "substrate/utils/substrate-bip39", "substrate/utils/wasm-builder", - "templates/minimal", "templates/minimal/node", "templates/minimal/pallets/template", "templates/minimal/runtime", @@ -527,42 +539,47 @@ members = [ "templates/solochain/node", "templates/solochain/pallets/template", "templates/solochain/runtime", + "templates/zombienet", "umbrella", ] default-members = [ + "cumulus/polkadot-omni-node", + "cumulus/polkadot-parachain", "polkadot", "substrate/bin/node/cli", ] [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(build_opt_level, values("3"))', 'cfg(build_profile, values("debug", "release"))', 'cfg(enable_alloc_error_handler)', 'cfg(fuzzing)', '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,8 +588,8 @@ 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" } +anyhow = { version = "1.0.81", default-features = false } +approx = { version = "0.5.1" } aquamarine = { version = "0.5.0" } arbitrary = { version = "1.3.2" } ark-bls12-377 = { version = "0.4.0", default-features = false } @@ -589,7 +606,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,14 +619,14 @@ 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" } bitflags = { version = "1.3.2" } bitvec = { version = "1.0.1", default-features = false } blake2 = { version = "0.10.4", default-features = false } -blake2b_simd = { version = "1.0.1", default-features = false } +blake2b_simd = { version = "1.0.2", default-features = false } blake3 = { version = "1.5" } bounded-collections = { version = "0.2.0", default-features = false } bounded-vec = { version = "0.7" } @@ -642,7 +659,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,20 +671,23 @@ 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.13" } clap-num = { version = "1.0.2" } -clap_complete = { version = "4.0.2" } +clap_complete = { version = "4.5.13" } coarsetime = { version = "0.1.22" } codec = { version = "3.6.12", default-features = false, package = "parity-scale-codec" } collectives-westend-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/collectives/collectives-westend" } collectives-westend-runtime = { path = "cumulus/parachains/runtimes/collectives/collectives-westend" } -color-eyre = { version = "0.6.1", default-features = false } +color-eyre = { version = "0.6.3", default-features = false } color-print = { version = "0.3.4" } colored = { version = "2.0.4" } comfy-table = { version = "7.1.0", default-features = false } console = { version = "0.15.8" } +const-hex = { version = "1.10.0", default-features = false } 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,13 +740,13 @@ 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" } +env_logger = { version = "0.11.2" } environmental = { version = "1.1.4", default-features = false } equivocation-detector = { path = "bridges/relays/equivocation" } ethabi = { version = "1.0.0", default-features = false, package = "ethabi-decode" } -ethbloom = { version = "0.13.0", default-features = false } -ethereum-types = { version = "0.14.1", default-features = false } +ethbloom = { version = "0.14.1", default-features = false } +ethereum-types = { version = "0.15.1", default-features = false } exit-future = { version = "0.2.0" } expander = { version = "2.0.0" } fatality = { version = "0.1.1" } @@ -787,7 +807,7 @@ hyper-rustls = { version = "0.24.2" } hyper-util = { version = "0.1.5", default-features = false } # TODO: remove hyper v0.14 https://github.com/paritytech/polkadot-sdk/issues/4896 hyperv14 = { package = "hyper", version = "0.14.29", default-features = false } -impl-serde = { version = "0.4.0", default-features = false } +impl-serde = { version = "0.5.0", default-features = false } impl-trait-for-tuples = { version = "0.2.2" } indexmap = { version = "2.0.0" } indicatif = { version = "0.17.7" } @@ -797,28 +817,29 @@ is-terminal = { version = "0.4.9" } is_executable = { version = "1.0.1" } isahc = { version = "1.2" } itertools = { version = "0.11" } +jemalloc_pprof = { version = "0.4" } +jobserver = { version = "0.1.26" } jsonpath_lib = { version = "0.3" } -jsonrpsee = { version = "0.23.2" } -jsonrpsee-core = { version = "0.23.2" } -k256 = { version = "0.13.3", default-features = false } +jsonrpsee = { version = "0.24.3" } +jsonrpsee-core = { version = "0.24.3" } +k256 = { version = "0.13.4", default-features = false } kitchensink-runtime = { path = "substrate/bin/node/runtime" } kvdb = { version = "0.13.0" } kvdb-memorydb = { version = "0.13.0" } kvdb-rocksdb = { version = "0.19.0" } kvdb-shared-tests = { version = "0.11.0" } landlock = { version = "0.3.0" } -lazy_static = { version = "1.4.0" } -libc = { version = "0.2.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 } +litep2p = { version = "0.7.0", features = ["websocket"] } +log = { version = "0.4.22", default-features = false } macro_magic = { version = "0.5.1" } maplit = { version = "1.0.2" } memmap2 = { version = "0.9.3" } @@ -827,7 +848,6 @@ merkleized-metadata = { version = "0.1.0" } merlin = { version = "3.0", default-features = false } messages-relay = { path = "bridges/relays/messages" } metered = { version = "0.6.1", default-features = false, package = "prioritized-metered-channel" } -mick-jaeger = { version = "0.1.8" } milagro-bls = { version = "1.5.4", default-features = false, package = "snowbridge-milagro-bls" } minimal-template-node = { path = "templates/minimal/node" } minimal-template-runtime = { path = "templates/minimal/runtime" } @@ -885,7 +905,7 @@ pallet-collator-selection = { path = "cumulus/pallets/collator-selection", defau pallet-collective = { path = "substrate/frame/collective", default-features = false } pallet-collective-content = { path = "cumulus/parachains/pallets/collective-content", default-features = false } pallet-contracts = { path = "substrate/frame/contracts", default-features = false } -pallet-contracts-fixtures = { path = "substrate/frame/contracts/fixtures" } +pallet-contracts-fixtures = { path = "substrate/frame/contracts/fixtures", default-features = false } pallet-contracts-mock-network = { default-features = false, path = "substrate/frame/contracts/mock-network" } pallet-contracts-proc-macro = { path = "substrate/frame/contracts/proc-macro", default-features = false } pallet-contracts-uapi = { path = "substrate/frame/contracts/uapi", default-features = false } @@ -898,6 +918,7 @@ pallet-dev-mode = { path = "substrate/frame/examples/dev-mode", default-features pallet-election-provider-multi-phase = { path = "substrate/frame/election-provider-multi-phase", default-features = false } pallet-election-provider-support-benchmarking = { path = "substrate/frame/election-provider-support/benchmarking", default-features = false } pallet-elections-phragmen = { path = "substrate/frame/elections-phragmen", default-features = false } +pallet-example-authorization-tx-extension = { path = "substrate/frame/examples/authorization-tx-extension", default-features = false } pallet-example-basic = { path = "substrate/frame/examples/basic", default-features = false } pallet-example-frame-crate = { path = "substrate/frame/examples/frame-crate", default-features = false } pallet-example-kitchensink = { path = "substrate/frame/examples/kitchensink", default-features = false } @@ -941,6 +962,11 @@ pallet-ranked-collective = { path = "substrate/frame/ranked-collective", default pallet-recovery = { path = "substrate/frame/recovery", default-features = false } pallet-referenda = { path = "substrate/frame/referenda", default-features = false } pallet-remark = { default-features = false, path = "substrate/frame/remark" } +pallet-revive = { path = "substrate/frame/revive", default-features = false } +pallet-revive-fixtures = { path = "substrate/frame/revive/fixtures", default-features = false } +pallet-revive-mock-network = { default-features = false, path = "substrate/frame/revive/mock-network" } +pallet-revive-proc-macro = { path = "substrate/frame/revive/proc-macro", default-features = false } +pallet-revive-uapi = { path = "substrate/frame/revive/uapi", default-features = false } pallet-root-offences = { default-features = false, path = "substrate/frame/root-offences" } pallet-root-testing = { path = "substrate/frame/root-testing", default-features = false } pallet-safe-mode = { default-features = false, path = "substrate/frame/safe-mode" } @@ -969,6 +995,7 @@ pallet-treasury = { path = "substrate/frame/treasury", default-features = false pallet-tx-pause = { default-features = false, path = "substrate/frame/tx-pause" } pallet-uniques = { path = "substrate/frame/uniques", default-features = false } pallet-utility = { path = "substrate/frame/utility", default-features = false } +pallet-verify-signature = { path = "substrate/frame/verify-signature", default-features = false } pallet-vesting = { path = "substrate/frame/vesting", default-features = false } pallet-whitelist = { path = "substrate/frame/whitelist", default-features = false } pallet-xcm = { path = "polkadot/xcm/pallet-xcm", default-features = false } @@ -982,11 +1009,10 @@ parachains-relay = { path = "bridges/relays/parachains" } parachains-runtimes-test-utils = { path = "cumulus/parachains/runtimes/test-utils", default-features = false } parity-bytes = { version = "0.1.2", default-features = false } parity-db = { version = "0.4.12" } -parity-util-mem = { version = "0.12.0" } parity-wasm = { version = "0.45.0" } parking_lot = { version = "0.12.1", default-features = false } partial_sort = { version = "0.2.0" } -paste = { version = "1.0.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" } @@ -995,7 +1021,7 @@ people-rococo-runtime = { path = "cumulus/parachains/runtimes/people/people-roco people-westend-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/parachains/people/people-westend" } people-westend-runtime = { path = "cumulus/parachains/runtimes/people/people-westend" } pin-project = { version = "1.1.3" } -platforms = { version = "3.0" } +platforms = { version = "3.4" } polkadot-approval-distribution = { path = "polkadot/node/network/approval-distribution", default-features = false } polkadot-availability-bitfield-distribution = { path = "polkadot/node/network/bitfield-distribution", default-features = false } polkadot-availability-distribution = { path = "polkadot/node/network/availability-distribution", default-features = false } @@ -1009,6 +1035,7 @@ polkadot-gossip-support = { path = "polkadot/node/network/gossip-support", defau polkadot-network-bridge = { path = "polkadot/node/network/bridge", default-features = false } polkadot-node-collation-generation = { path = "polkadot/node/collation-generation", default-features = false } polkadot-node-core-approval-voting = { path = "polkadot/node/core/approval-voting", default-features = false } +polkadot-node-core-approval-voting-parallel = { path = "polkadot/node/core/approval-voting-parallel", default-features = false } polkadot-node-core-av-store = { path = "polkadot/node/core/av-store", default-features = false } polkadot-node-core-backing = { path = "polkadot/node/core/backing", default-features = false } polkadot-node-core-bitfield-signing = { path = "polkadot/node/core/bitfield-signing", default-features = false } @@ -1025,7 +1052,6 @@ polkadot-node-core-pvf-common = { path = "polkadot/node/core/pvf/common", defaul polkadot-node-core-pvf-execute-worker = { path = "polkadot/node/core/pvf/execute-worker", default-features = false } polkadot-node-core-pvf-prepare-worker = { path = "polkadot/node/core/pvf/prepare-worker", default-features = false } polkadot-node-core-runtime-api = { path = "polkadot/node/core/runtime-api", default-features = false } -polkadot-node-jaeger = { path = "polkadot/node/jaeger", default-features = false } polkadot-node-metrics = { path = "polkadot/node/metrics", default-features = false } polkadot-node-network-protocol = { path = "polkadot/node/network/protocol", default-features = false } polkadot-node-primitives = { path = "polkadot/node/primitives", default-features = false } @@ -1033,6 +1059,8 @@ polkadot-node-subsystem = { path = "polkadot/node/subsystem", default-features = polkadot-node-subsystem-test-helpers = { path = "polkadot/node/subsystem-test-helpers" } polkadot-node-subsystem-types = { path = "polkadot/node/subsystem-types", default-features = false } polkadot-node-subsystem-util = { path = "polkadot/node/subsystem-util", default-features = false } +polkadot-omni-node = { path = "cumulus/polkadot-omni-node", default-features = false } +polkadot-omni-node-lib = { path = "cumulus/polkadot-omni-node/lib", default-features = false } polkadot-overseer = { path = "polkadot/node/overseer", default-features = false } polkadot-parachain-primitives = { path = "polkadot/parachain", default-features = false } polkadot-primitives = { path = "polkadot/primitives", default-features = false } @@ -1050,26 +1078,26 @@ polkadot-subsystem-bench = { path = "polkadot/node/subsystem-bench" } polkadot-test-client = { path = "polkadot/node/test/client" } polkadot-test-runtime = { path = "polkadot/runtime/test-runtime" } polkadot-test-service = { path = "polkadot/node/test/service" } -polkavm = "0.9.3" +polkavm = { version = "0.9.3", default-features = false } polkavm-derive = "0.9.1" polkavm-linker = "0.9.2" portpicker = { version = "0.1.1" } pretty_assertions = { version = "1.3.0" } -primitive-types = { version = "0.12.1", default-features = false } +primitive-types = { version = "0.13.1", default-features = false, features = ["num-traits"] } proc-macro-crate = { version = "3.0.0" } proc-macro-warning = { version = "1.0.0", default-features = false } -proc-macro2 = { version = "1.0.64" } +proc-macro2 = { version = "1.0.86" } procfs = { version = "0.16.0" } prometheus = { version = "0.13.0", default-features = false } prometheus-endpoint = { path = "substrate/utils/prometheus", default-features = false, package = "substrate-prometheus-endpoint" } prometheus-parse = { version = "0.2.2" } prost = { version = "0.12.4" } -prost-build = { version = "0.12.4" } +prost-build = { version = "0.13.2" } 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.37" } rand = { version = "0.8.5", default-features = false } rand_chacha = { version = "0.3.1", default-features = false } rand_core = { version = "0.6.2" } @@ -1077,13 +1105,13 @@ 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" } remote-externalities = { path = "substrate/utils/frame/remote-externalities", default-features = false, package = "frame-remote-externalities" } reqwest = { version = "0.11", default-features = false } -rlp = { version = "0.5.2", default-features = false } +rlp = { version = "0.6.1", default-features = false } rococo-emulated-chain = { path = "cumulus/parachains/integration-tests/emulated/chains/relays/rococo" } rococo-parachain-runtime = { path = "cumulus/parachains/runtimes/testing/rococo-parachain" } rococo-runtime = { path = "polkadot/runtime/rococo" } @@ -1095,7 +1123,7 @@ rstest = { version = "0.18.2" } rustc-hash = { version = "1.1.0" } rustc-hex = { version = "2.1.0", default-features = false } rustix = { version = "0.36.7", default-features = false } -rustversion = { version = "1.0.6" } +rustversion = { version = "1.0.17" } rusty-fork = { version = "0.3.0", default-features = false } safe-mix = { version = "1.0", default-features = false } sc-allocator = { path = "substrate/client/allocator", default-features = false } @@ -1157,23 +1185,22 @@ sc-transaction-pool-api = { path = "substrate/client/transaction-pool/api", defa sc-utils = { path = "substrate/client/utils", default-features = false } scale-info = { version = "2.11.1", default-features = false } schemars = { version = "0.8.13", default-features = false } -schnellru = { version = "0.2.1" } +schnellru = { version = "0.2.3" } schnorrkel = { version = "0.11.4", default-features = false } seccompiler = { version = "0.4.0" } secp256k1 = { version = "0.28.0", default-features = false } secrecy = { version = "0.8.0", default-features = false } -seedling-runtime = { path = "cumulus/parachains/runtimes/starters/seedling" } separator = { version = "0.4.1" } -serde = { version = "1.0.197", default-features = false } +serde = { version = "1.0.210", 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.132", default-features = false } serde_yaml = { version = "0.9" } serial_test = { version = "2.0.0" } sha1 = { version = "0.10.6" } sha2 = { version = "0.10.7", default-features = false } sha3 = { version = "0.10.0", default-features = false } -shell-runtime = { path = "cumulus/parachains/runtimes/starters/shell" } +shlex = { version = "1.3.0" } slot-range-helper = { path = "polkadot/runtime/common/slot_range_helper", default-features = false } slotmap = { version = "1.0" } smallvec = { version = "1.11.0", default-features = false } @@ -1194,7 +1221,7 @@ snowbridge-router-primitives = { path = "bridges/snowbridge/primitives/router", snowbridge-runtime-common = { path = "bridges/snowbridge/runtime/runtime-common", default-features = false } snowbridge-runtime-test-common = { path = "bridges/snowbridge/runtime/test-common", default-features = false } snowbridge-system-runtime-api = { path = "bridges/snowbridge/pallets/system/runtime-api", default-features = false } -soketto = { version = "0.7.1" } +soketto = { version = "0.8.0" } solochain-template-runtime = { path = "templates/solochain/runtime" } sp-api = { path = "substrate/primitives/api", default-features = false } sp-api-proc-macro = { path = "substrate/primitives/api/proc-macro", default-features = false } @@ -1254,14 +1281,14 @@ 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 } static_assertions = { version = "1.1.0", default-features = false } static_init = { version = "1.0.3" } structopt = { version = "0.3" } -strum = { version = "0.26.2", default-features = false } +strum = { version = "0.26.3", default-features = false } subkey = { path = "substrate/bin/utils/subkey", default-features = false } substrate-bip39 = { path = "substrate/utils/substrate-bip39", default-features = false } substrate-build-script-utils = { path = "substrate/utils/build-script-utils", default-features = false } @@ -1276,7 +1303,9 @@ substrate-test-runtime-client = { path = "substrate/test-utils/runtime/client" } substrate-test-runtime-transaction-pool = { path = "substrate/test-utils/runtime/transaction-pool" } substrate-test-utils = { path = "substrate/test-utils" } substrate-wasm-builder = { path = "substrate/utils/wasm-builder", default-features = false } -syn = { version = "2.0.53" } +subxt = { version = "0.37", default-features = false } +subxt-signer = { version = "0.37" } +syn = { version = "2.0.82" } sysinfo = { version = "0.30" } tar = { version = "0.4" } tempfile = { version = "3.8.1" } @@ -1287,20 +1316,20 @@ test-parachain-halt = { path = "polkadot/parachain/test-parachains/halt" } test-parachain-undying = { path = "polkadot/parachain/test-parachains/undying" } test-runtime-constants = { path = "polkadot/runtime/test-runtime/constants", default-features = false } testnet-parachains-constants = { path = "cumulus/parachains/runtimes/constants", default-features = false } -thiserror = { version = "1.0.48" } +thiserror = { version = "1.0.64" } thousands = { version = "0.2.0" } threadpool = { version = "1.7" } tikv-jemalloc-ctl = { version = "0.5.0" } tikv-jemallocator = { version = "0.5.0" } time = { version = "0.3" } tiny-keccak = { version = "2.0.2" } -tokio = { version = "1.37.0", default-features = false } +tokio = { version = "1.40.0", default-features = false } tokio-retry = { version = "0.3.0" } tokio-stream = { version = "0.1.14" } -tokio-test = { version = "0.4.2" } +tokio-test = { version = "0.4.4" } tokio-tungstenite = { version = "0.20.1" } tokio-util = { version = "0.7.8" } -toml = { version = "0.8.8" } +toml = { version = "0.8.12" } toml_edit = { version = "0.19" } tower = { version = "0.4.13" } tower-http = { version = "0.5.2" } @@ -1311,10 +1340,10 @@ tracing-log = { version = "0.2.0" } tracing-subscriber = { version = "0.3.18" } tracking-allocator = { path = "polkadot/node/tracking-allocator", default-features = false, package = "staging-tracking-allocator" } trie-bench = { version = "0.39.0" } -trie-db = { version = "0.29.0", default-features = false } +trie-db = { version = "0.29.1", 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 +1352,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" } @@ -1345,26 +1374,27 @@ xcm-procedural = { path = "polkadot/xcm/procedural", default-features = false } xcm-runtime-apis = { path = "polkadot/xcm/xcm-runtime-apis", default-features = false } xcm-simulator = { path = "polkadot/xcm/xcm-simulator", default-features = false } zeroize = { version = "1.7.0", default-features = false } +zombienet-sdk = { version = "0.2.13" } 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 92901d070db0..6c0dfbb2e7e4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ -
![SDK Logo](./docs/images/Polkadot_Logo_Horizontal_Pink_White.png#gh-dark-mode-only) @@ -10,10 +9,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,41 +17,35 @@ 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) * [Introduction](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/index.html) to each component of the Polkadot SDK: Substrate, FRAME, Cumulus, and XCM * [Guides](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/guides/index.html), - namely how to build your first FRAME pallet. + namely how to build your first FRAME pallet * [Templates](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/templates/index.html) for starting a new project. -* Other Resources: - * [Polkadot Wiki -> Build](https://wiki.polkadot.network/docs/build-guide) + * [External Resources](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/external_resources/index.html) ## 🚀 Releases -> [!NOTE] -> Our release process is still Work-In-Progress and may not yet reflect the aspired outline -> here. - -The Polkadot-SDK has two release channels: `stable` and `nightly`. Production software is advised to -only use `stable`. `nightly` is meant for tinkerers to try out the latest features. The detailed -release process is described in [RELEASE.md](docs/RELEASE.md). - -You can use [`psvm`](https://github.com/paritytech/psvm) to manage your Polkadot-SDK dependency -versions in downstream projects. - -### 😌 Stable - -`stable` releases have a support duration of **three months**. In this period, the release will not -have any breaking changes. It will receive bug fixes, security fixes, performance fixes and new -non-breaking features on a **two week** cadence. + +![Current Stable Release](https://raw.githubusercontent.com/paritytech/release-registry/main/badges/polkadot-sdk-latest.svg)  ![Next Stable Release](https://raw.githubusercontent.com/paritytech/release-registry/main/badges/polkadot-sdk-next.svg) -### 🤠 Nightly +The Polkadot SDK is released every three months as a `stableYYMMDD` release. They are supported for +one year with patches. See the next upcoming versions in the [Release +Registry](https://github.com/paritytech/release-registry/). -`nightly` releases are released every night from the `master` branch, potentially with breaking -changes. They have pre-release version numbers in the format `major.0.0-nightlyYYMMDD`. +You can use [`psvm`](https://github.com/paritytech/psvm) to update all dependencies to a specific +version without needing to manually select the correct version for each crate. ## 🛠️ Tooling diff --git a/bridges/bin/runtime-common/Cargo.toml b/bridges/bin/runtime-common/Cargo.toml index 36f27b6aa035..37b56140c289 100644 --- a/bridges/bin/runtime-common/Cargo.toml +++ b/bridges/bin/runtime-common/Cargo.toml @@ -25,7 +25,6 @@ bp-polkadot-core = { workspace = true } bp-relayers = { workspace = true } bp-runtime = { workspace = true } bp-xcm-bridge-hub = { workspace = true } -bp-xcm-bridge-hub-router = { workspace = true } pallet-bridge-grandpa = { workspace = true } pallet-bridge-messages = { workspace = true } pallet-bridge-parachains = { workspace = true } @@ -40,15 +39,19 @@ sp-io = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } sp-trie = { optional = true, workspace = true } +sp-weights = { workspace = true } # Polkadot dependencies xcm = { workspace = true } -xcm-builder = { workspace = true } [dev-dependencies] bp-test-utils = { workspace = true } pallet-balances = { workspace = true } -pallet-bridge-messages = { features = ["std", "test-helpers"], workspace = true } +pallet-bridge-messages = { features = [ + "std", + "test-helpers", +], workspace = true } +sp-core = { workspace = true } [features] default = ["std"] @@ -60,7 +63,6 @@ std = [ "bp-relayers/std", "bp-runtime/std", "bp-test-utils/std", - "bp-xcm-bridge-hub-router/std", "bp-xcm-bridge-hub/std", "codec/std", "frame-support/std", @@ -74,12 +76,13 @@ std = [ "pallet-transaction-payment/std", "pallet-utility/std", "scale-info/std", + "sp-core/std", "sp-io/std", "sp-runtime/std", "sp-std/std", "sp-trie/std", + "sp-weights/std", "tuplex/std", - "xcm-builder/std", "xcm/std", ] runtime-benchmarks = [ @@ -92,13 +95,10 @@ runtime-benchmarks = [ "pallet-bridge-messages/test-helpers", "pallet-bridge-parachains/runtime-benchmarks", "pallet-bridge-relayers/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "sp-trie", - "xcm-builder/runtime-benchmarks", ] integrity-test = ["static_assertions"] -test-helpers = [ - "bp-runtime/test-helpers", - "sp-trie", -] +test-helpers = ["bp-runtime/test-helpers", "sp-trie"] diff --git a/bridges/bin/runtime-common/src/extensions/check_obsolete_extension.rs b/bridges/bin/runtime-common/src/extensions.rs similarity index 66% rename from bridges/bin/runtime-common/src/extensions/check_obsolete_extension.rs rename to bridges/bin/runtime-common/src/extensions.rs index df75092af6e8..19d1554c668b 100644 --- a/bridges/bin/runtime-common/src/extensions/check_obsolete_extension.rs +++ b/bridges/bin/runtime-common/src/extensions.rs @@ -18,23 +18,20 @@ //! obsolete (duplicated) data or do not pass some additional pallet-specific //! checks. -use crate::{ - extensions::refund_relayer_extension::RefundableParachainId, - messages_call_ext::MessagesCallSubType, -}; +use bp_parachains::SubmitParachainHeadsInfo; use bp_relayers::ExplicitOrAccountParams; use bp_runtime::Parachain; use pallet_bridge_grandpa::{ BridgedBlockNumber, CallSubType as GrandpaCallSubType, SubmitFinalityProofHelper, }; -use pallet_bridge_parachains::{ - CallSubType as ParachainsCallSubtype, SubmitParachainHeadsHelper, SubmitParachainHeadsInfo, -}; +use pallet_bridge_messages::CallSubType as MessagesCallSubType; +use pallet_bridge_parachains::{CallSubType as ParachainsCallSubtype, SubmitParachainHeadsHelper}; use pallet_bridge_relayers::Pallet as RelayersPallet; use sp_runtime::{ - traits::{Get, PhantomData, UniqueSaturatedInto}, + traits::{Get, UniqueSaturatedInto}, transaction_validity::{TransactionPriority, TransactionValidity, ValidTransactionBuilder}, }; +use sp_std::marker::PhantomData; // Re-export to avoid include tuplex dependency everywhere. #[doc(hidden)] @@ -50,8 +47,7 @@ pub trait BridgeRuntimeFilterCall { /// Data that may be passed from the validate to `post_dispatch`. type ToPostDispatch; /// Called during validation. Needs to checks whether a runtime call, submitted - /// by the `who` is valid. `who` may be `None` if transaction is not signed - /// by a regular account. + /// by the `who` is valid. Transactions not signed are not validated. fn validate(who: &AccountId, call: &Call) -> (Self::ToPostDispatch, TransactionValidity); /// Called after transaction is dispatched. fn post_dispatch(_who: &AccountId, _has_failed: bool, _to_post_dispatch: Self::ToPostDispatch) { @@ -126,17 +122,27 @@ where /// `(BundledHeaderNumber - 1 - BestKnownHeaderNumber) * Priority::get()`. /// The boost is only applied if submitter has active registration in the relayers /// pallet. -pub struct CheckAndBoostBridgeParachainsTransactions( - PhantomData<(T, RefPara, Priority, SlashAccount)>, -); - -impl, SlashAccount: Get> - BridgeRuntimeFilterCall - for CheckAndBoostBridgeParachainsTransactions +pub struct CheckAndBoostBridgeParachainsTransactions< + T, + ParachainsInstance, + Para, + Priority, + SlashAccount, +>(PhantomData<(T, ParachainsInstance, Para, Priority, SlashAccount)>); + +impl< + T, + ParachainsInstance, + Para, + Priority: Get, + SlashAccount: Get, + > BridgeRuntimeFilterCall + for CheckAndBoostBridgeParachainsTransactions where - T: pallet_bridge_relayers::Config + pallet_bridge_parachains::Config, - RefPara: RefundableParachainId, - T::RuntimeCall: ParachainsCallSubtype, + T: pallet_bridge_relayers::Config + pallet_bridge_parachains::Config, + ParachainsInstance: 'static, + Para: Parachain, + T::RuntimeCall: ParachainsCallSubtype, { // bridged header number, bundled in transaction type ToPostDispatch = Option; @@ -145,10 +151,10 @@ where who: &T::AccountId, call: &T::RuntimeCall, ) -> (Self::ToPostDispatch, TransactionValidity) { - match ParachainsCallSubtype::::check_obsolete_submit_parachain_heads( + match ParachainsCallSubtype::::check_obsolete_submit_parachain_heads( call, ) { - Ok(Some(our_tx)) if our_tx.base.para_id.0 == RefPara::BridgedChain::PARACHAIN_ID => { + Ok(Some(our_tx)) if our_tx.base.para_id.0 == Para::PARACHAIN_ID => { let to_post_dispatch = Some(our_tx.base); let total_priority_boost = compute_priority_boost::(&who, our_tx.improved_by); @@ -167,7 +173,7 @@ where let Some(update) = maybe_update else { return }; // we are only interested in failed or unneeded transactions let has_failed = has_failed || - !SubmitParachainHeadsHelper::::was_successful(&update); + !SubmitParachainHeadsHelper::::was_successful(&update); if !has_failed { return @@ -267,94 +273,97 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { ($call:ty, $account_id:ty, $($filter_call:ty),*) => { #[derive(Clone, codec::Decode, Default, codec::Encode, Eq, PartialEq, sp_runtime::RuntimeDebug, scale_info::TypeInfo)] pub struct BridgeRejectObsoleteHeadersAndMessages; - impl sp_runtime::traits::SignedExtension for BridgeRejectObsoleteHeadersAndMessages { + impl sp_runtime::traits::TransactionExtension<$call> for BridgeRejectObsoleteHeadersAndMessages { const IDENTIFIER: &'static str = "BridgeRejectObsoleteHeadersAndMessages"; - type AccountId = $account_id; - type Call = $call; - type AdditionalSigned = (); - type Pre = ( + type Implicit = (); + type Val = Option<( $account_id, ( $( - <$filter_call as $crate::extensions::check_obsolete_extension::BridgeRuntimeFilterCall< + <$filter_call as $crate::extensions::BridgeRuntimeFilterCall< $account_id, $call, >>::ToPostDispatch, )* ), - ); + )>; + type Pre = Self::Val; - fn additional_signed(&self) -> sp_std::result::Result< - (), - sp_runtime::transaction_validity::TransactionValidityError, - > { - Ok(()) + fn weight(&self, _: &$call) -> frame_support::pallet_prelude::Weight { + frame_support::pallet_prelude::Weight::zero() } - #[allow(unused_variables)] fn validate( &self, - who: &Self::AccountId, - call: &Self::Call, - _info: &sp_runtime::traits::DispatchInfoOf, + origin: <$call as sp_runtime::traits::Dispatchable>::RuntimeOrigin, + call: &$call, + _info: &sp_runtime::traits::DispatchInfoOf<$call>, _len: usize, - ) -> sp_runtime::transaction_validity::TransactionValidity { + _self_implicit: Self::Implicit, + _inherited_implication: &impl codec::Encode, + ) -> Result< + ( + sp_runtime::transaction_validity::ValidTransaction, + Self::Val, + <$call as sp_runtime::traits::Dispatchable>::RuntimeOrigin, + ), sp_runtime::transaction_validity::TransactionValidityError + > { + use $crate::extensions::__private::tuplex::PushBack; + use sp_runtime::traits::AsSystemOriginSigner; + + let Some(who) = origin.as_system_origin_signer() else { + return Ok((Default::default(), None, origin)); + }; + + let to_post_dispatch = (); let tx_validity = sp_runtime::transaction_validity::ValidTransaction::default(); - let to_prepare = (); $( let (from_validate, call_filter_validity) = < $filter_call as - $crate::extensions::check_obsolete_extension::BridgeRuntimeFilterCall< - Self::AccountId, + $crate::extensions::BridgeRuntimeFilterCall< + $account_id, $call, - >>::validate(&who, call); + >>::validate(who, call); + let to_post_dispatch = to_post_dispatch.push_back(from_validate); let tx_validity = tx_validity.combine_with(call_filter_validity?); )* - Ok(tx_validity) + Ok((tx_validity, Some((who.clone(), to_post_dispatch)), origin)) } - #[allow(unused_variables)] - fn pre_dispatch( + fn prepare( self, - relayer: &Self::AccountId, - call: &Self::Call, - info: &sp_runtime::traits::DispatchInfoOf, - len: usize, + val: Self::Val, + _origin: &<$call as sp_runtime::traits::Dispatchable>::RuntimeOrigin, + _call: &$call, + _info: &sp_runtime::traits::DispatchInfoOf<$call>, + _len: usize, ) -> Result { - use $crate::extensions::check_obsolete_extension::__private::tuplex::PushBack; - let to_post_dispatch = (); - $( - let (from_validate, call_filter_validity) = < - $filter_call as - $crate::extensions::check_obsolete_extension::BridgeRuntimeFilterCall< - $account_id, - $call, - >>::validate(&relayer, call); - let _ = call_filter_validity?; - let to_post_dispatch = to_post_dispatch.push_back(from_validate); - )* - Ok((relayer.clone(), to_post_dispatch)) + Ok(val) } #[allow(unused_variables)] - fn post_dispatch( - to_post_dispatch: Option, - info: &sp_runtime::traits::DispatchInfoOf, - post_info: &sp_runtime::traits::PostDispatchInfoOf, + fn post_dispatch_details( + to_post_dispatch: Self::Pre, + info: &sp_runtime::traits::DispatchInfoOf<$call>, + post_info: &sp_runtime::traits::PostDispatchInfoOf<$call>, len: usize, result: &sp_runtime::DispatchResult, - ) -> Result<(), sp_runtime::transaction_validity::TransactionValidityError> { - use $crate::extensions::check_obsolete_extension::__private::tuplex::PopFront; - let Some((relayer, to_post_dispatch)) = to_post_dispatch else { return Ok(()) }; + ) -> Result { + use $crate::extensions::__private::tuplex::PopFront; + + let Some((relayer, to_post_dispatch)) = to_post_dispatch else { + return Ok(frame_support::pallet_prelude::Weight::zero()) + }; + let has_failed = result.is_err(); $( let (item, to_post_dispatch) = to_post_dispatch.pop_front(); < $filter_call as - $crate::extensions::check_obsolete_extension::BridgeRuntimeFilterCall< + $crate::extensions::BridgeRuntimeFilterCall< $account_id, $call, >>::post_dispatch(&relayer, has_failed, item); )* - Ok(()) + Ok(frame_support::pallet_prelude::Weight::zero()) } } }; @@ -363,31 +372,69 @@ macro_rules! generate_bridge_reject_obsolete_headers_and_messages { #[cfg(test)] mod tests { use super::*; - use crate::{ - extensions::refund_relayer_extension::{ - tests::{ - initialize_environment, relayer_account_at_this_chain, - submit_parachain_head_call_ex, submit_relay_header_call_ex, - }, - RefundableParachain, - }, - mock::*, - }; - use bp_polkadot_core::parachains::ParaId; + use crate::mock::*; + use bp_header_chain::StoredHeaderDataBuilder; + use bp_messages::{InboundLaneData, MessageNonce, OutboundLaneData}; + use bp_parachains::{BestParaHeadHash, ParaInfo}; + use bp_polkadot_core::parachains::{ParaHeadsProof, ParaId}; + use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; use bp_runtime::HeaderId; - use frame_support::{assert_err, assert_ok}; + use bp_test_utils::{make_default_justification, test_keyring, TEST_GRANDPA_SET_ID}; + use codec::{Decode, Encode, MaxEncodedLen}; + use frame_support::{assert_err, assert_ok, traits::fungible::Mutate}; + use pallet_bridge_grandpa::{Call as GrandpaCall, StoredAuthoritySet}; + use pallet_bridge_parachains::Call as ParachainsCall; + use scale_info::TypeInfo; use sp_runtime::{ - traits::{ConstU64, SignedExtension}, + traits::{ + parameter_types, AsSystemOriginSigner, AsTransactionAuthorizedOrigin, ConstU64, + DispatchTransaction, Header as _, TransactionExtension, + }, transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, DispatchError, }; + parameter_types! { + pub MsgProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( + test_lane_id(), + TEST_BRIDGED_CHAIN_ID, + RewardsAccountOwner::ThisChain, + ); + pub MsgDeliveryProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( + test_lane_id(), + TEST_BRIDGED_CHAIN_ID, + RewardsAccountOwner::BridgedChain, + ); + } + + #[derive(Debug, Clone, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen)] pub struct MockCall { data: u32, } + #[derive(Debug, Clone, PartialEq, Encode, Decode, TypeInfo, MaxEncodedLen)] + pub struct MockOrigin(pub u64); + + impl AsSystemOriginSigner for MockOrigin { + fn as_system_origin_signer(&self) -> Option<&u64> { + Some(&self.0) + } + } + + impl AsTransactionAuthorizedOrigin for MockOrigin { + fn is_transaction_authorized(&self) -> bool { + true + } + } + + impl From for MockOrigin { + fn from(o: u64) -> Self { + Self(o) + } + } + impl sp_runtime::traits::Dispatchable for MockCall { - type RuntimeOrigin = u64; + type RuntimeOrigin = MockOrigin; type Config = (); type Info = (); type PostInfo = (); @@ -455,6 +502,99 @@ mod tests { } } + fn initial_balance_of_relayer_account_at_this_chain() -> ThisChainBalance { + let test_stake: ThisChainBalance = TestStake::get(); + ExistentialDeposit::get().saturating_add(test_stake * 100) + } + + // in tests, the following accounts are equal (because of how `into_sub_account_truncating` + // works) + + fn delivery_rewards_account() -> ThisChainAccountId { + TestPaymentProcedure::rewards_account(MsgProofsRewardsAccount::get()) + } + + fn confirmation_rewards_account() -> ThisChainAccountId { + TestPaymentProcedure::rewards_account(MsgDeliveryProofsRewardsAccount::get()) + } + + fn relayer_account_at_this_chain() -> ThisChainAccountId { + 0 + } + + fn initialize_environment( + best_relay_header_number: BridgedChainBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, + best_message: MessageNonce, + ) { + let authorities = test_keyring().into_iter().map(|(a, w)| (a.into(), w)).collect(); + let best_relay_header = HeaderId(best_relay_header_number, BridgedChainHash::default()); + pallet_bridge_grandpa::CurrentAuthoritySet::::put( + StoredAuthoritySet::try_new(authorities, TEST_GRANDPA_SET_ID).unwrap(), + ); + pallet_bridge_grandpa::BestFinalized::::put(best_relay_header); + pallet_bridge_grandpa::ImportedHeaders::::insert( + best_relay_header.hash(), + bp_test_utils::test_header::(0).build(), + ); + + let para_id = ParaId(BridgedUnderlyingParachain::PARACHAIN_ID); + let para_info = ParaInfo { + best_head_hash: BestParaHeadHash { + at_relay_block_number: parachain_head_at_relay_header_number, + head_hash: [parachain_head_at_relay_header_number as u8; 32].into(), + }, + next_imported_hash_position: 0, + }; + pallet_bridge_parachains::ParasInfo::::insert(para_id, para_info); + + let lane_id = test_lane_id(); + let in_lane_data = + InboundLaneData { last_confirmed_nonce: best_message, ..Default::default() }; + pallet_bridge_messages::InboundLanes::::insert(lane_id, in_lane_data); + + let out_lane_data = + OutboundLaneData { latest_received_nonce: best_message, ..Default::default() }; + pallet_bridge_messages::OutboundLanes::::insert(lane_id, out_lane_data); + + Balances::mint_into(&delivery_rewards_account(), ExistentialDeposit::get()).unwrap(); + Balances::mint_into(&confirmation_rewards_account(), ExistentialDeposit::get()).unwrap(); + Balances::mint_into( + &relayer_account_at_this_chain(), + initial_balance_of_relayer_account_at_this_chain(), + ) + .unwrap(); + } + + fn submit_relay_header_call(relay_header_number: BridgedChainBlockNumber) -> RuntimeCall { + let relay_header = BridgedChainHeader::new( + relay_header_number, + Default::default(), + Default::default(), + Default::default(), + Default::default(), + ); + let relay_justification = make_default_justification(&relay_header); + + RuntimeCall::BridgeGrandpa(GrandpaCall::submit_finality_proof { + finality_target: Box::new(relay_header), + justification: relay_justification, + }) + } + + fn submit_parachain_head_call( + parachain_head_at_relay_header_number: BridgedChainBlockNumber, + ) -> RuntimeCall { + RuntimeCall::BridgeParachains(ParachainsCall::submit_parachain_heads { + at_relay_block: (parachain_head_at_relay_header_number, BridgedChainHash::default()), + parachains: vec![( + ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), + [parachain_head_at_relay_header_number as u8; 32].into(), + )], + parachain_heads_proof: ParaHeadsProof { storage_proof: Default::default() }, + }) + } + #[test] fn test_generated_obsolete_extension() { generate_bridge_reject_obsolete_headers_and_messages!( @@ -466,12 +606,17 @@ mod tests { run_test(|| { assert_err!( - BridgeRejectObsoleteHeadersAndMessages.validate(&42, &MockCall { data: 1 }, &(), 0), + BridgeRejectObsoleteHeadersAndMessages.validate_only( + 42u64.into(), + &MockCall { data: 1 }, + &(), + 0 + ), InvalidTransaction::Custom(1) ); assert_err!( - BridgeRejectObsoleteHeadersAndMessages.pre_dispatch( - &42, + BridgeRejectObsoleteHeadersAndMessages.validate_and_prepare( + 42u64.into(), &MockCall { data: 1 }, &(), 0 @@ -480,12 +625,17 @@ mod tests { ); assert_err!( - BridgeRejectObsoleteHeadersAndMessages.validate(&42, &MockCall { data: 2 }, &(), 0), + BridgeRejectObsoleteHeadersAndMessages.validate_only( + 42u64.into(), + &MockCall { data: 2 }, + &(), + 0 + ), InvalidTransaction::Custom(2) ); assert_err!( - BridgeRejectObsoleteHeadersAndMessages.pre_dispatch( - &42, + BridgeRejectObsoleteHeadersAndMessages.validate_and_prepare( + 42u64.into(), &MockCall { data: 2 }, &(), 0 @@ -495,37 +645,40 @@ mod tests { assert_eq!( BridgeRejectObsoleteHeadersAndMessages - .validate(&42, &MockCall { data: 3 }, &(), 0) - .unwrap(), + .validate_only(42u64.into(), &MockCall { data: 3 }, &(), 0) + .unwrap() + .0, ValidTransaction { priority: 3, ..Default::default() }, ); assert_eq!( BridgeRejectObsoleteHeadersAndMessages - .pre_dispatch(&42, &MockCall { data: 3 }, &(), 0) + .validate_and_prepare(42u64.into(), &MockCall { data: 3 }, &(), 0) + .unwrap() + .0 .unwrap(), (42, (1, 2)), ); // when post_dispatch is called with `Ok(())`, it is propagated to all "nested" // extensions - assert_ok!(BridgeRejectObsoleteHeadersAndMessages::post_dispatch( + assert_ok!(BridgeRejectObsoleteHeadersAndMessages::post_dispatch_details( Some((0, (1, 2))), &(), &(), 0, - &Ok(()) + &Ok(()), )); FirstFilterCall::verify_post_dispatch_called_with(true); SecondFilterCall::verify_post_dispatch_called_with(true); // when post_dispatch is called with `Err(())`, it is propagated to all "nested" // extensions - assert_ok!(BridgeRejectObsoleteHeadersAndMessages::post_dispatch( + assert_ok!(BridgeRejectObsoleteHeadersAndMessages::post_dispatch_details( Some((0, (1, 2))), &(), &(), 0, - &Err(DispatchError::BadOrigin) + &Err(DispatchError::BadOrigin), )); FirstFilterCall::verify_post_dispatch_called_with(false); SecondFilterCall::verify_post_dispatch_called_with(false); @@ -546,7 +699,7 @@ mod tests { let priority_boost = BridgeGrandpaWrapper::validate( &relayer_account_at_this_chain(), - &submit_relay_header_call_ex(200), + &submit_relay_header_call(200), ) .1 .unwrap() @@ -564,7 +717,7 @@ mod tests { let priority_boost = BridgeGrandpaWrapper::validate( &relayer_account_at_this_chain(), - &submit_relay_header_call_ex(200), + &submit_relay_header_call(200), ) .1 .unwrap() @@ -601,7 +754,8 @@ mod tests { type BridgeParachainsWrapper = CheckAndBoostBridgeParachainsTransactions< TestRuntime, - RefundableParachain<(), BridgedUnderlyingParachain>, + (), + BridgedUnderlyingParachain, ConstU64<1_000>, SlashDestination, >; @@ -613,7 +767,7 @@ mod tests { let priority_boost = BridgeParachainsWrapper::validate( &relayer_account_at_this_chain(), - &submit_parachain_head_call_ex(200), + &submit_parachain_head_call(200), ) .1 .unwrap() @@ -631,7 +785,7 @@ mod tests { let priority_boost = BridgeParachainsWrapper::validate( &relayer_account_at_this_chain(), - &submit_parachain_head_call_ex(200), + &submit_parachain_head_call(200), ) .1 .unwrap() diff --git a/bridges/bin/runtime-common/src/integrity.rs b/bridges/bin/runtime-common/src/integrity.rs index f661db8a2205..2ff6c4c9165a 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,20 +68,21 @@ macro_rules! assert_bridge_messages_pallet_types( bridged_chain: $bridged:path, ) => { { + use $crate::integrity::__private::bp_xcm_bridge_hub::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 BridgeMessagesConfig; + // 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 bp_messages::ChainWithMessages; - use bp_runtime::Chain; - use pallet_bridge_messages::Config as MessagesConfig; - use static_assertions::assert_type_eq_all; - assert_type_eq_all!(<$r as MessagesConfig<$i>>::ThisChain, $this); - assert_type_eq_all!(<$r as MessagesConfig<$i>>::BridgedChain, $bridged); + assert_type_eq_all!(<$r as BridgeMessagesConfig<$i>>::ThisChain, $this); + assert_type_eq_all!(<$r as BridgeMessagesConfig<$i>>::BridgedChain, $bridged); - assert_type_eq_all!(<$r as MessagesConfig<$i>>::OutboundPayload, XcmAsPlainPayload); - assert_type_eq_all!(<$r as MessagesConfig<$i>>::InboundPayload, XcmAsPlainPayload); + assert_type_eq_all!(<$r as BridgeMessagesConfig<$i>>::OutboundPayload, XcmAsPlainPayload); + assert_type_eq_all!(<$r as BridgeMessagesConfig<$i>>::InboundPayload, XcmAsPlainPayload); } } ); @@ -165,12 +174,6 @@ where R: pallet_bridge_messages::Config, MI: 'static, { - assert!( - !R::ActiveOutboundLanes::get().is_empty(), - "ActiveOutboundLanes ({:?}) must not be empty", - R::ActiveOutboundLanes::get(), - ); - assert!( pallet_bridge_messages::BridgedChainOf::::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX <= pallet_bridge_messages::BridgedChainOf::::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, diff --git a/bridges/bin/runtime-common/src/lib.rs b/bridges/bin/runtime-common/src/lib.rs index b65bb6041d56..ac8b013086b1 100644 --- a/bridges/bin/runtime-common/src/lib.rs +++ b/bridges/bin/runtime-common/src/lib.rs @@ -20,16 +20,11 @@ #![cfg_attr(not(feature = "std"), no_std)] pub mod extensions; - pub mod messages_api; pub mod messages_benchmarking; -pub mod messages_call_ext; -pub mod messages_xcm_extension; pub mod parachains_benchmarking; mod mock; #[cfg(feature = "integrity-test")] pub mod integrity; - -const LOG_TARGET_BRIDGE_DISPATCH: &str = "runtime::bridge-dispatch"; diff --git a/bridges/bin/runtime-common/src/messages_api.rs b/bridges/bin/runtime-common/src/messages_api.rs index 7fbdeb366124..c8522d4d1f27 100644 --- a/bridges/bin/runtime-common/src/messages_api.rs +++ b/bridges/bin/runtime-common/src/messages_api.rs @@ -16,14 +16,12 @@ //! Helpers for implementing various message-related runtime API methods. -use bp_messages::{ - InboundMessageDetails, LaneId, MessageNonce, MessagePayload, OutboundMessageDetails, -}; +use bp_messages::{InboundMessageDetails, MessageNonce, MessagePayload, OutboundMessageDetails}; use sp_std::vec::Vec; /// Implementation of the `To*OutboundLaneApi::message_details`. pub fn outbound_message_details( - lane: LaneId, + lane: Runtime::LaneId, begin: MessageNonce, end: MessageNonce, ) -> Vec @@ -48,7 +46,7 @@ where /// Implementation of the `To*InboundLaneApi::message_details`. pub fn inbound_message_details( - lane: LaneId, + lane: Runtime::LaneId, messages: Vec<(MessagePayload, OutboundMessageDetails)>, ) -> Vec where diff --git a/bridges/bin/runtime-common/src/messages_benchmarking.rs b/bridges/bin/runtime-common/src/messages_benchmarking.rs index 1880e65547fe..acbdbcda8dea 100644 --- a/bridges/bin/runtime-common/src/messages_benchmarking.rs +++ b/bridges/bin/runtime-common/src/messages_benchmarking.rs @@ -33,15 +33,15 @@ use pallet_bridge_messages::{ encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof, prepare_messages_storage_proof, }, - BridgedChainOf, ThisChainOf, + BridgedChainOf, LaneIdOf, ThisChainOf, }; use sp_runtime::traits::{Header, Zero}; use sp_std::prelude::*; use xcm::latest::prelude::*; /// Prepare inbound bridge message according to given message proof parameters. -fn prepare_inbound_message( - params: &MessageProofParams, +fn prepare_inbound_message( + params: &MessageProofParams, successful_dispatch_message_generator: impl Fn(usize) -> MessagePayload, ) -> MessagePayload { let expected_size = params.proof_params.db_size.unwrap_or(0) as usize; @@ -71,9 +71,9 @@ fn prepare_inbound_message( /// uses GRANDPA finality. For parachains, please use the `prepare_message_proof_from_parachain` /// function. pub fn prepare_message_proof_from_grandpa_chain( - params: MessageProofParams, + params: MessageProofParams>, message_generator: impl Fn(usize) -> MessagePayload, -) -> (FromBridgedChainMessagesProof>>, Weight) +) -> (FromBridgedChainMessagesProof>, LaneIdOf>, Weight) where R: pallet_bridge_grandpa::Config> + pallet_bridge_messages::Config< @@ -84,18 +84,21 @@ where MI: 'static, { // prepare storage proof - let (state_root, storage_proof) = - prepare_messages_storage_proof::, ThisChainOf>( - params.lane, - params.message_nonces.clone(), - params.outbound_lane_data.clone(), - params.proof_params, - |_| prepare_inbound_message(¶ms, &message_generator), - encode_all_messages, - encode_lane_data, - false, - false, - ); + let (state_root, storage_proof) = prepare_messages_storage_proof::< + BridgedChainOf, + ThisChainOf, + LaneIdOf, + >( + params.lane, + params.message_nonces.clone(), + params.outbound_lane_data.clone(), + params.proof_params, + |_| prepare_inbound_message(¶ms, &message_generator), + encode_all_messages, + encode_lane_data, + false, + false, + ); // update runtime storage let (_, bridged_header_hash) = insert_header_to_grandpa_pallet::(state_root); @@ -121,9 +124,9 @@ where /// uses parachain finality. For GRANDPA chains, please use the /// `prepare_message_proof_from_grandpa_chain` function. pub fn prepare_message_proof_from_parachain( - params: MessageProofParams, + params: MessageProofParams>, message_generator: impl Fn(usize) -> MessagePayload, -) -> (FromBridgedChainMessagesProof>>, Weight) +) -> (FromBridgedChainMessagesProof>, LaneIdOf>, Weight) where R: pallet_bridge_parachains::Config + pallet_bridge_messages::Config, PI: 'static, @@ -131,18 +134,21 @@ where BridgedChainOf: Chain + Parachain, { // prepare storage proof - let (state_root, storage_proof) = - prepare_messages_storage_proof::, ThisChainOf>( - params.lane, - params.message_nonces.clone(), - params.outbound_lane_data.clone(), - params.proof_params, - |_| prepare_inbound_message(¶ms, &message_generator), - encode_all_messages, - encode_lane_data, - false, - false, - ); + let (state_root, storage_proof) = prepare_messages_storage_proof::< + BridgedChainOf, + ThisChainOf, + LaneIdOf, + >( + params.lane, + params.message_nonces.clone(), + params.outbound_lane_data.clone(), + params.proof_params, + |_| prepare_inbound_message(¶ms, &message_generator), + encode_all_messages, + encode_lane_data, + false, + false, + ); // update runtime storage let (_, bridged_header_hash) = @@ -166,8 +172,8 @@ where /// uses GRANDPA finality. For parachains, please use the /// `prepare_message_delivery_proof_from_parachain` function. pub fn prepare_message_delivery_proof_from_grandpa_chain( - params: MessageDeliveryProofParams>>, -) -> FromBridgedChainMessagesDeliveryProof>> + params: MessageDeliveryProofParams>, LaneIdOf>, +) -> FromBridgedChainMessagesDeliveryProof>, LaneIdOf> where R: pallet_bridge_grandpa::Config> + pallet_bridge_messages::Config< @@ -182,6 +188,7 @@ where let (state_root, storage_proof) = prepare_message_delivery_storage_proof::< BridgedChainOf, ThisChainOf, + LaneIdOf, >(params.lane, params.inbound_lane_data, params.proof_params); // update runtime storage @@ -200,8 +207,8 @@ where /// uses parachain finality. For GRANDPA chains, please use the /// `prepare_message_delivery_proof_from_grandpa_chain` function. pub fn prepare_message_delivery_proof_from_parachain( - params: MessageDeliveryProofParams>>, -) -> FromBridgedChainMessagesDeliveryProof>> + params: MessageDeliveryProofParams>, LaneIdOf>, +) -> FromBridgedChainMessagesDeliveryProof>, LaneIdOf> where R: pallet_bridge_parachains::Config + pallet_bridge_messages::Config, PI: 'static, @@ -213,6 +220,7 @@ where let (state_root, storage_proof) = prepare_message_delivery_storage_proof::< BridgedChainOf, ThisChainOf, + LaneIdOf, >(params.lane, params.inbound_lane_data, params.proof_params); // update runtime storage diff --git a/bridges/bin/runtime-common/src/messages_xcm_extension.rs b/bridges/bin/runtime-common/src/messages_xcm_extension.rs deleted file mode 100644 index 46ed4da0d854..000000000000 --- a/bridges/bin/runtime-common/src/messages_xcm_extension.rs +++ /dev/null @@ -1,502 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity Bridges Common is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity Bridges Common. If not, see . - -//! Module provides utilities for easier XCM handling, e.g: -//! `XcmExecutor` -> `MessageSender` -> `OutboundMessageQueue` -//! | -//! `Relayer` -//! | -//! `XcmRouter` <- `MessageDispatch` <- `InboundMessageQueue` - -use bp_messages::{ - source_chain::OnMessagesDelivered, - target_chain::{DispatchMessage, MessageDispatch}, - LaneId, MessageNonce, -}; -use bp_runtime::messages::MessageDispatchResult; -pub use bp_xcm_bridge_hub::XcmAsPlainPayload; -use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; -use codec::{Decode, Encode}; -use frame_support::{traits::Get, weights::Weight, CloneNoBound, EqNoBound, PartialEqNoBound}; -use pallet_bridge_messages::{ - Config as MessagesConfig, OutboundLanesCongestedSignals, WeightInfoExt as MessagesPalletWeights, -}; -use scale_info::TypeInfo; -use sp_runtime::SaturatedConversion; -use sp_std::{fmt::Debug, marker::PhantomData}; -use xcm::prelude::*; -use xcm_builder::{DispatchBlob, DispatchBlobError}; - -/// Message dispatch result type for single message. -#[derive(CloneNoBound, EqNoBound, PartialEqNoBound, Encode, Decode, Debug, TypeInfo)] -pub enum XcmBlobMessageDispatchResult { - /// We've been unable to decode message payload. - InvalidPayload, - /// Message has been dispatched. - Dispatched, - /// Message has **NOT** been dispatched because of given error. - NotDispatched(#[codec(skip)] Option), -} - -/// [`XcmBlobMessageDispatch`] is responsible for dispatching received messages -/// -/// It needs to be used at the target bridge hub. -pub struct XcmBlobMessageDispatch { - _marker: sp_std::marker::PhantomData<(DispatchBlob, Weights, Channel)>, -} - -impl< - BlobDispatcher: DispatchBlob, - Weights: MessagesPalletWeights, - Channel: XcmChannelStatusProvider, - > MessageDispatch for XcmBlobMessageDispatch -{ - type DispatchPayload = XcmAsPlainPayload; - type DispatchLevelResult = XcmBlobMessageDispatchResult; - - fn is_active() -> bool { - !Channel::is_congested() - } - - fn dispatch_weight(message: &mut DispatchMessage) -> Weight { - match message.data.payload { - Ok(ref payload) => { - let payload_size = payload.encoded_size().saturated_into(); - Weights::message_dispatch_weight(payload_size) - }, - Err(_) => Weight::zero(), - } - } - - fn dispatch( - message: DispatchMessage, - ) -> MessageDispatchResult { - let payload = match message.data.payload { - Ok(payload) => payload, - Err(e) => { - log::error!( - target: crate::LOG_TARGET_BRIDGE_DISPATCH, - "[XcmBlobMessageDispatch] payload error: {:?} - message_nonce: {:?}", - e, - message.key.nonce - ); - return MessageDispatchResult { - unspent_weight: Weight::zero(), - dispatch_level_result: XcmBlobMessageDispatchResult::InvalidPayload, - } - }, - }; - let dispatch_level_result = match BlobDispatcher::dispatch_blob(payload) { - Ok(_) => { - log::debug!( - target: crate::LOG_TARGET_BRIDGE_DISPATCH, - "[XcmBlobMessageDispatch] DispatchBlob::dispatch_blob was ok - message_nonce: {:?}", - message.key.nonce - ); - XcmBlobMessageDispatchResult::Dispatched - }, - Err(e) => { - log::error!( - target: crate::LOG_TARGET_BRIDGE_DISPATCH, - "[XcmBlobMessageDispatch] DispatchBlob::dispatch_blob failed, error: {:?} - message_nonce: {:?}", - e, message.key.nonce - ); - XcmBlobMessageDispatchResult::NotDispatched(Some(e)) - }, - }; - MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result } - } -} - -/// A pair of sending chain location and message lane, used by this chain to send messages -/// over the bridge. -#[cfg_attr(feature = "std", derive(Debug, Eq, PartialEq))] -pub struct SenderAndLane { - /// Sending chain relative location. - pub location: Location, - /// Message lane, used by the sending chain. - pub lane: LaneId, -} - -impl SenderAndLane { - /// Create new object using provided location and lane. - pub fn new(location: Location, lane: LaneId) -> Self { - SenderAndLane { location, lane } - } -} - -/// [`XcmBlobHauler`] is responsible for sending messages to the bridge "point-to-point link" from -/// one side, where on the other it can be dispatched by [`XcmBlobMessageDispatch`]. -pub trait XcmBlobHauler { - /// Runtime that has messages pallet deployed. - type Runtime: MessagesConfig; - /// Instance of the messages pallet that is used to send messages. - type MessagesInstance: 'static; - - /// Actual XCM message sender (`HRMP` or `UMP`) to the source chain - /// location (`Self::SenderAndLane::get().location`). - type ToSourceChainSender: SendXcm; - /// An XCM message that is sent to the sending chain when the bridge queue becomes congested. - type CongestedMessage: Get>>; - /// An XCM message that is sent to the sending chain when the bridge queue becomes not - /// congested. - type UncongestedMessage: Get>>; - - /// Returns `true` if we want to handle congestion. - fn supports_congestion_detection() -> bool { - Self::CongestedMessage::get().is_some() || Self::UncongestedMessage::get().is_some() - } -} - -/// XCM bridge adapter which connects [`XcmBlobHauler`] with [`pallet_bridge_messages`] and -/// makes sure that XCM blob is sent to the outbound lane to be relayed. -/// -/// It needs to be used at the source bridge hub. -pub struct XcmBlobHaulerAdapter( - sp_std::marker::PhantomData<(XcmBlobHauler, Lanes)>, -); - -impl< - H: XcmBlobHauler, - Lanes: Get>, - > OnMessagesDelivered for XcmBlobHaulerAdapter -{ - fn on_messages_delivered(lane: LaneId, enqueued_messages: MessageNonce) { - if let Some(sender_and_lane) = - Lanes::get().iter().find(|link| link.0.lane == lane).map(|link| &link.0) - { - // notify XCM queue manager about updated lane state - LocalXcmQueueManager::::on_bridge_messages_delivered( - sender_and_lane, - enqueued_messages, - ); - } - } -} - -/// Manager of local XCM queues (and indirectly - underlying transport channels) that -/// controls the queue state. -/// -/// It needs to be used at the source bridge hub. -pub struct LocalXcmQueueManager(PhantomData); - -/// Maximal number of messages in the outbound bridge queue. Once we reach this limit, we -/// send a "congestion" XCM message to the sending chain. -const OUTBOUND_LANE_CONGESTED_THRESHOLD: MessageNonce = 8_192; - -/// After we have sent "congestion" XCM message to the sending chain, we wait until number -/// of messages in the outbound bridge queue drops to this count, before sending `uncongestion` -/// XCM message. -const OUTBOUND_LANE_UNCONGESTED_THRESHOLD: MessageNonce = 1_024; - -impl LocalXcmQueueManager { - /// Must be called whenever we push a message to the bridge lane. - pub fn on_bridge_message_enqueued( - sender_and_lane: &SenderAndLane, - enqueued_messages: MessageNonce, - ) { - // skip if we dont want to handle congestion - if !H::supports_congestion_detection() { - return - } - - // if we have already sent the congestion signal, we don't want to do anything - if Self::is_congested_signal_sent(sender_and_lane.lane) { - return - } - - // if the bridge queue is not congested, we don't want to do anything - let is_congested = enqueued_messages > OUTBOUND_LANE_CONGESTED_THRESHOLD; - if !is_congested { - return - } - - log::info!( - target: crate::LOG_TARGET_BRIDGE_DISPATCH, - "Sending 'congested' XCM message to {:?} to avoid overloading lane {:?}: there are\ - {} messages queued at the bridge queue", - sender_and_lane.location, - sender_and_lane.lane, - enqueued_messages, - ); - - if let Err(e) = Self::send_congested_signal(sender_and_lane) { - log::info!( - target: crate::LOG_TARGET_BRIDGE_DISPATCH, - "Failed to send the 'congested' XCM message to {:?}: {:?}", - sender_and_lane.location, - e, - ); - } - } - - /// Must be called whenever we receive a message delivery confirmation. - pub fn on_bridge_messages_delivered( - sender_and_lane: &SenderAndLane, - enqueued_messages: MessageNonce, - ) { - // skip if we don't want to handle congestion - if !H::supports_congestion_detection() { - return - } - - // if we have not sent the congestion signal before, we don't want to do anything - if !Self::is_congested_signal_sent(sender_and_lane.lane) { - return - } - - // if the bridge queue is still congested, we don't want to do anything - let is_congested = enqueued_messages > OUTBOUND_LANE_UNCONGESTED_THRESHOLD; - if is_congested { - return - } - - log::info!( - target: crate::LOG_TARGET_BRIDGE_DISPATCH, - "Sending 'uncongested' XCM message to {:?}. Lane {:?}: there are\ - {} messages queued at the bridge queue", - sender_and_lane.location, - sender_and_lane.lane, - enqueued_messages, - ); - - if let Err(e) = Self::send_uncongested_signal(sender_and_lane) { - log::info!( - target: crate::LOG_TARGET_BRIDGE_DISPATCH, - "Failed to send the 'uncongested' XCM message to {:?}: {:?}", - sender_and_lane.location, - e, - ); - } - } - - /// Returns true if we have sent "congested" signal to the `sending_chain_location`. - fn is_congested_signal_sent(lane: LaneId) -> bool { - OutboundLanesCongestedSignals::::get(lane) - } - - /// Send congested signal to the `sending_chain_location`. - fn send_congested_signal(sender_and_lane: &SenderAndLane) -> Result<(), SendError> { - if let Some(msg) = H::CongestedMessage::get() { - send_xcm::(sender_and_lane.location.clone(), msg)?; - OutboundLanesCongestedSignals::::insert( - sender_and_lane.lane, - true, - ); - } - Ok(()) - } - - /// Send `uncongested` signal to the `sending_chain_location`. - fn send_uncongested_signal(sender_and_lane: &SenderAndLane) -> Result<(), SendError> { - if let Some(msg) = H::UncongestedMessage::get() { - send_xcm::(sender_and_lane.location.clone(), msg)?; - OutboundLanesCongestedSignals::::remove( - sender_and_lane.lane, - ); - } - Ok(()) - } -} - -/// Adapter for the implementation of `GetVersion`, which attempts to find the minimal -/// configured XCM version between the destination `dest` and the bridge hub location provided as -/// `Get`. -pub struct XcmVersionOfDestAndRemoteBridge( - sp_std::marker::PhantomData<(Version, RemoteBridge)>, -); -impl> GetVersion - for XcmVersionOfDestAndRemoteBridge -{ - fn get_version_for(dest: &Location) -> Option { - let dest_version = Version::get_version_for(dest); - let bridge_hub_version = Version::get_version_for(&RemoteBridge::get()); - - match (dest_version, bridge_hub_version) { - (Some(dv), Some(bhv)) => Some(sp_std::cmp::min(dv, bhv)), - (Some(dv), None) => Some(dv), - (None, Some(bhv)) => Some(bhv), - (None, None) => None, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::mock::*; - - use bp_messages::OutboundLaneData; - use frame_support::parameter_types; - use pallet_bridge_messages::OutboundLanes; - - parameter_types! { - pub TestSenderAndLane: SenderAndLane = SenderAndLane { - location: Location::new(1, [Parachain(1000)]), - lane: TEST_LANE_ID, - }; - pub TestLanes: sp_std::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = sp_std::vec![ - (TestSenderAndLane::get(), (NetworkId::ByGenesis([0; 32]), InteriorLocation::Here)) - ]; - pub DummyXcmMessage: Xcm<()> = Xcm::new(); - } - - struct DummySendXcm; - - impl DummySendXcm { - fn messages_sent() -> u32 { - frame_support::storage::unhashed::get(b"DummySendXcm").unwrap_or(0) - } - } - - impl SendXcm for DummySendXcm { - type Ticket = (); - - fn validate( - _destination: &mut Option, - _message: &mut Option>, - ) -> SendResult { - Ok(((), Default::default())) - } - - fn deliver(_ticket: Self::Ticket) -> Result { - let messages_sent: u32 = Self::messages_sent(); - frame_support::storage::unhashed::put(b"DummySendXcm", &(messages_sent + 1)); - Ok(XcmHash::default()) - } - } - - struct TestBlobHauler; - - impl XcmBlobHauler for TestBlobHauler { - type Runtime = TestRuntime; - type MessagesInstance = (); - - type ToSourceChainSender = DummySendXcm; - type CongestedMessage = DummyXcmMessage; - type UncongestedMessage = DummyXcmMessage; - } - - type TestBlobHaulerAdapter = XcmBlobHaulerAdapter; - - fn fill_up_lane_to_congestion() -> MessageNonce { - let latest_generated_nonce = OUTBOUND_LANE_CONGESTED_THRESHOLD; - OutboundLanes::::insert( - TEST_LANE_ID, - OutboundLaneData { - oldest_unpruned_nonce: 0, - latest_received_nonce: 0, - latest_generated_nonce, - }, - ); - latest_generated_nonce - } - - #[test] - fn congested_signal_is_not_sent_twice() { - run_test(|| { - let enqueued = fill_up_lane_to_congestion(); - - // next sent message leads to congested signal - LocalXcmQueueManager::::on_bridge_message_enqueued( - &TestSenderAndLane::get(), - enqueued + 1, - ); - assert_eq!(DummySendXcm::messages_sent(), 1); - - // next sent message => we don't sent another congested signal - LocalXcmQueueManager::::on_bridge_message_enqueued( - &TestSenderAndLane::get(), - enqueued, - ); - assert_eq!(DummySendXcm::messages_sent(), 1); - }); - } - - #[test] - fn congested_signal_is_not_sent_when_outbound_lane_is_not_congested() { - run_test(|| { - LocalXcmQueueManager::::on_bridge_message_enqueued( - &TestSenderAndLane::get(), - 1, - ); - assert_eq!(DummySendXcm::messages_sent(), 0); - }); - } - - #[test] - fn congested_signal_is_sent_when_outbound_lane_is_congested() { - run_test(|| { - let enqueued = fill_up_lane_to_congestion(); - - // next sent message leads to congested signal - LocalXcmQueueManager::::on_bridge_message_enqueued( - &TestSenderAndLane::get(), - enqueued + 1, - ); - assert_eq!(DummySendXcm::messages_sent(), 1); - assert!(LocalXcmQueueManager::::is_congested_signal_sent(TEST_LANE_ID)); - }); - } - - #[test] - fn uncongested_signal_is_not_sent_when_messages_are_delivered_at_other_lane() { - run_test(|| { - LocalXcmQueueManager::::send_congested_signal(&TestSenderAndLane::get()).unwrap(); - assert_eq!(DummySendXcm::messages_sent(), 1); - - // when we receive a delivery report for other lane, we don't send an uncongested signal - TestBlobHaulerAdapter::on_messages_delivered(LaneId([42, 42, 42, 42]), 0); - assert_eq!(DummySendXcm::messages_sent(), 1); - }); - } - - #[test] - fn uncongested_signal_is_not_sent_when_we_havent_send_congested_signal_before() { - run_test(|| { - TestBlobHaulerAdapter::on_messages_delivered(TEST_LANE_ID, 0); - assert_eq!(DummySendXcm::messages_sent(), 0); - }); - } - - #[test] - fn uncongested_signal_is_not_sent_if_outbound_lane_is_still_congested() { - run_test(|| { - LocalXcmQueueManager::::send_congested_signal(&TestSenderAndLane::get()).unwrap(); - assert_eq!(DummySendXcm::messages_sent(), 1); - - TestBlobHaulerAdapter::on_messages_delivered( - TEST_LANE_ID, - OUTBOUND_LANE_UNCONGESTED_THRESHOLD + 1, - ); - assert_eq!(DummySendXcm::messages_sent(), 1); - }); - } - - #[test] - fn uncongested_signal_is_sent_if_outbound_lane_is_uncongested() { - run_test(|| { - LocalXcmQueueManager::::send_congested_signal(&TestSenderAndLane::get()).unwrap(); - assert_eq!(DummySendXcm::messages_sent(), 1); - - TestBlobHaulerAdapter::on_messages_delivered( - TEST_LANE_ID, - OUTBOUND_LANE_UNCONGESTED_THRESHOLD, - ); - assert_eq!(DummySendXcm::messages_sent(), 2); - }); - } -} diff --git a/bridges/bin/runtime-common/src/mock.rs b/bridges/bin/runtime-common/src/mock.rs index 2f248a7162a6..6cf04b452da7 100644 --- a/bridges/bin/runtime-common/src/mock.rs +++ b/bridges/bin/runtime-common/src/mock.rs @@ -18,16 +18,15 @@ #![cfg(test)] -use crate::messages_xcm_extension::XcmAsPlainPayload; - use bp_header_chain::ChainWithGrandpa; use bp_messages::{ target_chain::{DispatchMessage, MessageDispatch}, - ChainWithMessages, LaneId, MessageNonce, + ChainWithMessages, HashedLaneId, LaneIdType, MessageNonce, }; use bp_parachains::SingleParaStoredHeaderDataBuilder; use bp_relayers::PayRewardFromAccount; use bp_runtime::{messages::MessageDispatchResult, Chain, ChainId, Parachain}; +use codec::Encode; use frame_support::{ derive_impl, parameter_types, weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight}, @@ -71,7 +70,7 @@ pub type BridgedChainHeader = sp_runtime::generic::Header; /// Rewards payment procedure. -pub type TestPaymentProcedure = PayRewardFromAccount; +pub type TestPaymentProcedure = PayRewardFromAccount; /// Stake that we are using in tests. pub type TestStake = ConstU64<5_000>; /// Stake and slash mechanism to use in tests. @@ -84,8 +83,13 @@ pub type TestStakeAndSlash = pallet_bridge_relayers::StakeAndSlashNamed< ConstU32<8>, >; -/// Message lane used in tests. -pub const TEST_LANE_ID: LaneId = LaneId([0, 0, 0, 0]); +/// Lane identifier type used for tests. +pub type TestLaneIdType = HashedLaneId; +/// Lane that we're using in tests. +pub fn test_lane_id() -> TestLaneIdType { + TestLaneIdType::try_new(1, 2).unwrap() +} + /// Bridged chain id used in tests. pub const TEST_BRIDGED_CHAIN_ID: ChainId = *b"brdg"; /// Maximal extrinsic size at the `BridgedChain`. @@ -111,7 +115,6 @@ crate::generate_bridge_reject_obsolete_headers_and_messages! { } parameter_types! { - pub const ActiveOutboundLanes: &'static [LaneId] = &[TEST_LANE_ID]; pub const BridgedParasPalletName: &'static str = "Paras"; pub const ExistentialDeposit: ThisChainBalance = 500; pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 1, write: 2 }; @@ -159,7 +162,6 @@ impl pallet_transaction_payment::Config for TestRuntime { MinimumMultiplier, MaximumMultiplier, >; - type RuntimeEvent = RuntimeEvent; } impl pallet_bridge_grandpa::Config for TestRuntime { @@ -185,13 +187,12 @@ impl pallet_bridge_parachains::Config for TestRuntime { impl pallet_bridge_messages::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type WeightInfo = pallet_bridge_messages::weights::BridgeWeight; - type ActiveOutboundLanes = ActiveOutboundLanes; - - type OutboundPayload = XcmAsPlainPayload; + type OutboundPayload = Vec; type InboundPayload = Vec; - type DeliveryPayments = (); + type LaneId = TestLaneIdType; + type DeliveryPayments = (); type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< TestRuntime, (), @@ -212,31 +213,36 @@ impl pallet_bridge_relayers::Config for TestRuntime { type PaymentProcedure = TestPaymentProcedure; type StakeAndSlash = TestStakeAndSlash; type WeightInfo = (); + type LaneId = TestLaneIdType; } /// Dummy message dispatcher. pub struct DummyMessageDispatch; impl DummyMessageDispatch { - pub fn deactivate() { - frame_support::storage::unhashed::put(&b"inactive"[..], &false); + pub fn deactivate(lane: TestLaneIdType) { + frame_support::storage::unhashed::put(&(b"inactive", lane).encode()[..], &false); } } impl MessageDispatch for DummyMessageDispatch { type DispatchPayload = Vec; type DispatchLevelResult = (); + type LaneId = TestLaneIdType; - fn is_active() -> bool { - frame_support::storage::unhashed::take::(&b"inactive"[..]) != Some(false) + fn is_active(lane: Self::LaneId) -> bool { + frame_support::storage::unhashed::take::(&(b"inactive", lane).encode()[..]) != + Some(false) } - fn dispatch_weight(_message: &mut DispatchMessage) -> Weight { + fn dispatch_weight( + _message: &mut DispatchMessage, + ) -> Weight { Weight::zero() } fn dispatch( - _: DispatchMessage, + _: DispatchMessage, ) -> MessageDispatchResult { MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result: () } } diff --git a/bridges/bin/runtime-common/src/parachains_benchmarking.rs b/bridges/bin/runtime-common/src/parachains_benchmarking.rs index bcbd779b44de..e48a5664e31a 100644 --- a/bridges/bin/runtime-common/src/parachains_benchmarking.rs +++ b/bridges/bin/runtime-common/src/parachains_benchmarking.rs @@ -20,12 +20,13 @@ use crate::messages_benchmarking::insert_header_to_grandpa_pallet; -use bp_parachains::parachain_head_storage_key_at_source; +use bp_parachains::{ + parachain_head_storage_key_at_source, RelayBlockHash, RelayBlockHasher, RelayBlockNumber, +}; use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}; use bp_runtime::{grow_storage_value, record_all_trie_keys, Chain, UnverifiedStorageProofParams}; use codec::Encode; use frame_support::traits::Get; -use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; use sp_std::prelude::*; use sp_trie::{trie_types::TrieDBMutBuilderV1, LayoutV1, MemoryDB, TrieMut}; diff --git a/bridges/chains/chain-asset-hub-rococo/Cargo.toml b/bridges/chains/chain-asset-hub-rococo/Cargo.toml index b765fbc57bb0..363a869048aa 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 ff89864fb2db..430d9b6116cf 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 5609398385f9..99ba721991ee 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-cumulus/src/lib.rs b/bridges/chains/chain-bridge-hub-cumulus/src/lib.rs index a5c90ceba111..f626fa6df010 100644 --- a/bridges/chains/chain-bridge-hub-cumulus/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-cumulus/src/lib.rs @@ -26,7 +26,7 @@ pub use bp_polkadot_core::{ }; use bp_messages::*; -use bp_polkadot_core::SuffixedCommonSignedExtension; +use bp_polkadot_core::SuffixedCommonTransactionExtension; use bp_runtime::extensions::{ BridgeRejectObsoleteHeadersAndMessages, RefundBridgedParachainMessagesSchema, }; @@ -167,7 +167,7 @@ pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 1024; pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 4096; /// Signed extension that is used by all bridge hubs. -pub type SignedExtension = SuffixedCommonSignedExtension<( +pub type TransactionExtension = SuffixedCommonTransactionExtension<( BridgeRejectObsoleteHeadersAndMessages, RefundBridgedParachainMessagesSchema, )>; diff --git a/bridges/chains/chain-bridge-hub-kusama/Cargo.toml b/bridges/chains/chain-bridge-hub-kusama/Cargo.toml index 605643b0a4eb..39f7b44daa55 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-kusama/src/lib.rs b/bridges/chains/chain-bridge-hub-kusama/src/lib.rs index c990e8a12f36..485fb3d31f20 100644 --- a/bridges/chains/chain-bridge-hub-kusama/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-kusama/src/lib.rs @@ -93,4 +93,4 @@ pub const WITH_BRIDGE_HUB_KUSAMA_MESSAGES_PALLET_NAME: &str = "BridgeKusamaMessa pub const WITH_BRIDGE_HUB_KUSAMA_RELAYERS_PALLET_NAME: &str = "BridgeRelayers"; decl_bridge_finality_runtime_apis!(bridge_hub_kusama); -decl_bridge_messages_runtime_apis!(bridge_hub_kusama); +decl_bridge_messages_runtime_apis!(bridge_hub_kusama, LegacyLaneId); diff --git a/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml b/bridges/chains/chain-bridge-hub-polkadot/Cargo.toml index 97e36a19c748..3b0ac96e7cd3 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-polkadot/src/lib.rs b/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs index 7379b8863b1d..7a1793b4da4a 100644 --- a/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-polkadot/src/lib.rs @@ -85,4 +85,4 @@ pub const WITH_BRIDGE_HUB_POLKADOT_MESSAGES_PALLET_NAME: &str = "BridgePolkadotM pub const WITH_BRIDGE_HUB_POLKADOT_RELAYERS_PALLET_NAME: &str = "BridgeRelayers"; decl_bridge_finality_runtime_apis!(bridge_hub_polkadot); -decl_bridge_messages_runtime_apis!(bridge_hub_polkadot); +decl_bridge_messages_runtime_apis!(bridge_hub_polkadot, LegacyLaneId); diff --git a/bridges/chains/chain-bridge-hub-rococo/Cargo.toml b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml index 5c9184703223..23fbd9a2742f 100644 --- a/bridges/chains/chain-bridge-hub-rococo/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-rococo/Cargo.toml @@ -7,18 +7,22 @@ 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 [dependencies] -# Bridge Dependencies +codec = { features = ["derive"], workspace = true } +# Bridge Dependencies bp-bridge-hub-cumulus = { workspace = true } bp-runtime = { workspace = true } bp-messages = { workspace = true } +bp-xcm-bridge-hub = { workspace = true } # Substrate Based Dependencies - frame-support = { workspace = true } sp-api = { workspace = true } sp-runtime = { workspace = true } @@ -30,6 +34,8 @@ std = [ "bp-bridge-hub-cumulus/std", "bp-messages/std", "bp-runtime/std", + "bp-xcm-bridge-hub/std", + "codec/std", "frame-support/std", "sp-api/std", "sp-runtime/std", diff --git a/bridges/chains/chain-bridge-hub-rococo/src/lib.rs b/bridges/chains/chain-bridge-hub-rococo/src/lib.rs index 73af997b9950..fda6a5f0b722 100644 --- a/bridges/chains/chain-bridge-hub-rococo/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-rococo/src/lib.rs @@ -25,6 +25,7 @@ use bp_messages::*; use bp_runtime::{ decl_bridge_finality_runtime_apis, decl_bridge_messages_runtime_apis, Chain, ChainId, Parachain, }; +use codec::{Decode, Encode}; use frame_support::{ dispatch::DispatchClass, sp_runtime::{MultiAddress, MultiSigner, RuntimeDebug, StateVersion}, @@ -98,19 +99,27 @@ pub const WITH_BRIDGE_ROCOCO_TO_WESTEND_MESSAGES_PALLET_INDEX: u8 = 51; pub const WITH_BRIDGE_ROCOCO_TO_BULLETIN_MESSAGES_PALLET_INDEX: u8 = 61; decl_bridge_finality_runtime_apis!(bridge_hub_rococo); -decl_bridge_messages_runtime_apis!(bridge_hub_rococo); +decl_bridge_messages_runtime_apis!(bridge_hub_rococo, LegacyLaneId); frame_support::parameter_types! { /// The XCM fee that is paid for executing XCM program (with `ExportMessage` instruction) at the Rococo /// BridgeHub. /// (initially was calculated by test `BridgeHubRococo::can_calculate_weight_for_paid_export_message_with_reserve_transfer` + `33%`) - pub const BridgeHubRococoBaseXcmFeeInRocs: u128 = 59_034_266; + pub const BridgeHubRococoBaseXcmFeeInRocs: u128 = 57_145_832; /// Transaction fee that is paid at the Rococo BridgeHub for delivering single inbound message. /// (initially was calculated by test `BridgeHubRococo::can_calculate_fee_for_standalone_message_delivery_transaction` + `33%`) - pub const BridgeHubRococoBaseDeliveryFeeInRocs: u128 = 314_037_860; + pub const BridgeHubRococoBaseDeliveryFeeInRocs: u128 = 297_685_840; /// Transaction fee that is paid at the Rococo BridgeHub for delivering single outbound message confirmation. /// (initially was calculated by test `BridgeHubRococo::can_calculate_fee_for_standalone_message_confirmation_transaction` + `33%`) - pub const BridgeHubRococoBaseConfirmationFeeInRocs: u128 = 57_414_813; + pub const BridgeHubRococoBaseConfirmationFeeInRocs: u128 = 56_782_099; +} + +/// Wrapper over `BridgeHubRococo`'s `RuntimeCall` that can be used without a runtime. +#[derive(Decode, Encode)] +pub enum RuntimeCall { + /// Points to the `pallet_xcm_bridge_hub` pallet instance for `BridgeHubWestend`. + #[codec(index = 52)] + XcmOverBridgeHubWestend(bp_xcm_bridge_hub::XcmBridgeHubCall), } diff --git a/bridges/chains/chain-bridge-hub-westend/Cargo.toml b/bridges/chains/chain-bridge-hub-westend/Cargo.toml index 0b429ab9a0bd..61357e6aa6c8 100644 --- a/bridges/chains/chain-bridge-hub-westend/Cargo.toml +++ b/bridges/chains/chain-bridge-hub-westend/Cargo.toml @@ -7,19 +7,22 @@ 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 [dependencies] +codec = { features = ["derive"], workspace = true } # Bridge Dependencies - bp-bridge-hub-cumulus = { workspace = true } bp-runtime = { workspace = true } bp-messages = { workspace = true } +bp-xcm-bridge-hub = { workspace = true } # Substrate Based Dependencies - frame-support = { workspace = true } sp-api = { workspace = true } sp-runtime = { workspace = true } @@ -31,6 +34,8 @@ std = [ "bp-bridge-hub-cumulus/std", "bp-messages/std", "bp-runtime/std", + "bp-xcm-bridge-hub/std", + "codec/std", "frame-support/std", "sp-api/std", "sp-runtime/std", diff --git a/bridges/chains/chain-bridge-hub-westend/src/lib.rs b/bridges/chains/chain-bridge-hub-westend/src/lib.rs index 17ff2c858a1d..e941b5840238 100644 --- a/bridges/chains/chain-bridge-hub-westend/src/lib.rs +++ b/bridges/chains/chain-bridge-hub-westend/src/lib.rs @@ -24,6 +24,7 @@ use bp_messages::*; use bp_runtime::{ decl_bridge_finality_runtime_apis, decl_bridge_messages_runtime_apis, Chain, ChainId, Parachain, }; +use codec::{Decode, Encode}; use frame_support::dispatch::DispatchClass; use sp_runtime::{RuntimeDebug, StateVersion}; @@ -87,19 +88,27 @@ pub const WITH_BRIDGE_HUB_WESTEND_RELAYERS_PALLET_NAME: &str = "BridgeRelayers"; pub const WITH_BRIDGE_WESTEND_TO_ROCOCO_MESSAGES_PALLET_INDEX: u8 = 44; decl_bridge_finality_runtime_apis!(bridge_hub_westend); -decl_bridge_messages_runtime_apis!(bridge_hub_westend); +decl_bridge_messages_runtime_apis!(bridge_hub_westend, LegacyLaneId); frame_support::parameter_types! { /// The XCM fee that is paid for executing XCM program (with `ExportMessage` instruction) at the Westend /// BridgeHub. /// (initially was calculated by test `BridgeHubWestend::can_calculate_weight_for_paid_export_message_with_reserve_transfer` + `33%`) - pub const BridgeHubWestendBaseXcmFeeInWnds: u128 = 17_756_830_000; + pub const BridgeHubWestendBaseXcmFeeInWnds: u128 = 18_191_740_000; /// Transaction fee that is paid at the Westend BridgeHub for delivering single inbound message. /// (initially was calculated by test `BridgeHubWestend::can_calculate_fee_for_standalone_message_delivery_transaction` + `33%`) - pub const BridgeHubWestendBaseDeliveryFeeInWnds: u128 = 94_211_536_452; + pub const BridgeHubWestendBaseDeliveryFeeInWnds: u128 = 89_305_927_116; /// Transaction fee that is paid at the Westend BridgeHub for delivering single outbound message confirmation. /// (initially was calculated by test `BridgeHubWestend::can_calculate_fee_for_standalone_message_confirmation_transaction` + `33%`) - pub const BridgeHubWestendBaseConfirmationFeeInWnds: u128 = 17_224_486_452; + pub const BridgeHubWestendBaseConfirmationFeeInWnds: u128 = 17_034_677_116; +} + +/// Wrapper over `BridgeHubWestend`'s `RuntimeCall` that can be used without a runtime. +#[derive(Decode, Encode)] +pub enum RuntimeCall { + /// Points to the `pallet_xcm_bridge_hub` pallet instance for `BridgeHubRococo`. + #[codec(index = 45)] + XcmOverBridgeHubRococo(bp_xcm_bridge_hub::XcmBridgeHubCall), } diff --git a/bridges/chains/chain-kusama/Cargo.toml b/bridges/chains/chain-kusama/Cargo.toml index ec45c1eddce5..aec4041f7d57 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-kusama/src/lib.rs b/bridges/chains/chain-kusama/src/lib.rs index dcd0b23abbbe..f1f30c4484eb 100644 --- a/bridges/chains/chain-kusama/src/lib.rs +++ b/bridges/chains/chain-kusama/src/lib.rs @@ -61,8 +61,8 @@ impl ChainWithGrandpa for Kusama { const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } -// The SignedExtension used by Kusama. -pub use bp_polkadot_core::CommonSignedExtension as SignedExtension; +// The TransactionExtension used by Kusama. +pub use bp_polkadot_core::CommonTransactionExtension as TransactionExtension; /// Name of the parachains pallet in the Kusama runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; diff --git a/bridges/chains/chain-polkadot-bulletin/Cargo.toml b/bridges/chains/chain-polkadot-bulletin/Cargo.toml index ea5f4d2e7759..aecf93142736 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-polkadot-bulletin/src/lib.rs b/bridges/chains/chain-polkadot-bulletin/src/lib.rs index 88980a957501..c5c18beb2cad 100644 --- a/bridges/chains/chain-polkadot-bulletin/src/lib.rs +++ b/bridges/chains/chain-polkadot-bulletin/src/lib.rs @@ -25,7 +25,7 @@ use bp_runtime::{ decl_bridge_finality_runtime_apis, decl_bridge_messages_runtime_apis, extensions::{ CheckEra, CheckGenesis, CheckNonZeroSender, CheckNonce, CheckSpecVersion, CheckTxVersion, - CheckWeight, GenericSignedExtension, GenericSignedExtensionSchema, + CheckWeight, GenericTransactionExtension, GenericTransactionExtensionSchema, }, Chain, ChainId, TransactionEra, }; @@ -38,7 +38,8 @@ use frame_support::{ use frame_system::limits; use scale_info::TypeInfo; use sp_runtime::{ - traits::DispatchInfoOf, transaction_validity::TransactionValidityError, Perbill, StateVersion, + impl_tx_ext_default, traits::Dispatchable, transaction_validity::TransactionValidityError, + Perbill, StateVersion, }; // This chain reuses most of Polkadot primitives. @@ -73,10 +74,10 @@ pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 1024; pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 4096; /// This signed extension is used to ensure that the chain transactions are signed by proper -pub type ValidateSigned = GenericSignedExtensionSchema<(), ()>; +pub type ValidateSigned = GenericTransactionExtensionSchema<(), ()>; /// Signed extension schema, used by Polkadot Bulletin. -pub type SignedExtensionSchema = GenericSignedExtension<( +pub type TransactionExtensionSchema = GenericTransactionExtension<( ( CheckNonZeroSender, CheckSpecVersion, @@ -89,34 +90,30 @@ pub type SignedExtensionSchema = GenericSignedExtension<( ValidateSigned, )>; -/// Signed extension, used by Polkadot Bulletin. +/// Transaction extension, used by Polkadot Bulletin. #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub struct SignedExtension(SignedExtensionSchema); +pub struct TransactionExtension(TransactionExtensionSchema); -impl sp_runtime::traits::SignedExtension for SignedExtension { +impl sp_runtime::traits::TransactionExtension for TransactionExtension +where + C: Dispatchable, +{ const IDENTIFIER: &'static str = "Not needed."; - type AccountId = (); - type Call = (); - type AdditionalSigned = - ::AdditionalSigned; - type Pre = (); + type Implicit = + >::Implicit; - fn additional_signed(&self) -> Result { - self.0.additional_signed() + fn implicit(&self) -> Result { + >::implicit( + &self.0, + ) } + type Pre = (); + type Val = (); - fn pre_dispatch( - self, - _who: &Self::AccountId, - _call: &Self::Call, - _info: &DispatchInfoOf, - _len: usize, - ) -> Result { - Ok(()) - } + impl_tx_ext_default!(C; weight validate prepare); } -impl SignedExtension { +impl TransactionExtension { /// Create signed extension from its components. pub fn from_params( spec_version: u32, @@ -125,7 +122,7 @@ impl SignedExtension { genesis_hash: Hash, nonce: Nonce, ) -> Self { - Self(GenericSignedExtension::new( + Self(GenericTransactionExtension::new( ( ( (), // non-zero sender @@ -228,4 +225,4 @@ impl ChainWithMessages for PolkadotBulletin { } decl_bridge_finality_runtime_apis!(polkadot_bulletin, grandpa); -decl_bridge_messages_runtime_apis!(polkadot_bulletin); +decl_bridge_messages_runtime_apis!(polkadot_bulletin, bp_messages::HashedLaneId); diff --git a/bridges/chains/chain-polkadot/src/lib.rs b/bridges/chains/chain-polkadot/src/lib.rs index f4b262d40735..5d2f9e4aa9e0 100644 --- a/bridges/chains/chain-polkadot/src/lib.rs +++ b/bridges/chains/chain-polkadot/src/lib.rs @@ -63,8 +63,8 @@ impl ChainWithGrandpa for Polkadot { const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } -/// The SignedExtension used by Polkadot. -pub type SignedExtension = SuffixedCommonSignedExtension; +/// The TransactionExtension used by Polkadot. +pub type TransactionExtension = SuffixedCommonTransactionExtension; /// Name of the parachains pallet in the Polkadot runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; diff --git a/bridges/chains/chain-rococo/Cargo.toml b/bridges/chains/chain-rococo/Cargo.toml index 49a1a397ee09..8a99267691dc 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-rococo/src/lib.rs b/bridges/chains/chain-rococo/src/lib.rs index bfcafdf41ea2..2827d1f137b0 100644 --- a/bridges/chains/chain-rococo/src/lib.rs +++ b/bridges/chains/chain-rococo/src/lib.rs @@ -61,8 +61,8 @@ impl ChainWithGrandpa for Rococo { const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } -// The SignedExtension used by Rococo. -pub use bp_polkadot_core::CommonSignedExtension as SignedExtension; +// The TransactionExtension used by Rococo. +pub use bp_polkadot_core::CommonTransactionExtension as TransactionExtension; /// Name of the parachains pallet in the Rococo runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; diff --git a/bridges/chains/chain-westend/Cargo.toml b/bridges/chains/chain-westend/Cargo.toml index 5e27bc647bfc..cd6abe8abe6d 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/chains/chain-westend/src/lib.rs b/bridges/chains/chain-westend/src/lib.rs index 2a247e03e59d..2b0a609115bc 100644 --- a/bridges/chains/chain-westend/src/lib.rs +++ b/bridges/chains/chain-westend/src/lib.rs @@ -61,8 +61,8 @@ impl ChainWithGrandpa for Westend { const AVERAGE_HEADER_SIZE: u32 = AVERAGE_HEADER_SIZE; } -// The SignedExtension used by Westend. -pub use bp_polkadot_core::CommonSignedExtension as SignedExtension; +// The TransactionExtension used by Westend. +pub use bp_polkadot_core::CommonTransactionExtension as TransactionExtension; /// Name of the parachains pallet in the Rococo runtime. pub const PARAS_PALLET_NAME: &str = "Paras"; diff --git a/bridges/docs/polkadot-kusama-bridge-overview.md b/bridges/docs/polkadot-kusama-bridge-overview.md index 08036f0b0722..b1812e4caf12 100644 --- a/bridges/docs/polkadot-kusama-bridge-overview.md +++ b/bridges/docs/polkadot-kusama-bridge-overview.md @@ -25,8 +25,9 @@ You won't be able to directly use bridge hub transactions to send XCM messages o use other parachains transactions, which will use HRMP to deliver messages to the Bridge Hub. The Bridge Hub will just queue these messages in its outbound lane, which is dedicated to deliver messages between two parachains. -Our first planned bridge will connect the Polkadot and Kusama Asset Hubs. A bridge between those two parachains would -allow Asset Hub Polkadot accounts to hold wrapped KSM tokens and Asset Hub Kusama accounts to hold wrapped DOT tokens. +Our first planned bridge will connect the Polkadot and Kusama Asset Hubs. A bridge between those two +parachains would allow Asset Hub Polkadot accounts to hold wrapped KSM tokens and Asset Hub Kusama +accounts to hold wrapped DOT tokens. For that bridge (pair of parachains under different consensus systems) we'll be using the lane 00000000. Later, when other parachains will join the bridge, they will be using other lanes for their messages. @@ -92,13 +93,14 @@ Obviously, there should be someone who is paying relayer rewards. We want bridge can't use fees for rewards. Instead, the parachains using the bridge, use sovereign accounts on both sides of the bridge to cover relayer rewards. -Bridged Parachains will have sovereign accounts at bridge hubs. For example, the Kusama Asset Hub will have an account -at the Polkadot Bridge Hub. The Polkadot Asset Hub will have an account at the Kusama Bridge Hub. The sovereign accounts -are used as a source of funds when the relayer is calling the `pallet_bridge_relayers::claim_rewards`. +Bridged Parachains will have sovereign accounts at bridge hubs. For example, the Kusama Asset Hub will +have an account at the Polkadot Bridge Hub. The Polkadot Asset Hub will have an account at the Kusama +Bridge Hub. The sovereign accounts are used as a source of funds when the relayer is calling the +`pallet_bridge_relayers::claim_rewards`. -Since messages lane is only used by the pair of parachains, there's no collision between different bridges. E.g. Kusama -Asset Hub will only reward relayers that are delivering messages from Kusama Asset Hub. The Kusama Asset Hub sovereign -account is not used to cover rewards of bridging with some other Polkadot Parachain. +Since messages lane is only used by the pair of parachains, there's no collision between different bridges. E.g. +Kusama Asset Hub will only reward relayers that are delivering messages from Kusama Asset Hub. +The Kusama Asset Hub sovereign account is not used to cover rewards of bridging with some other Polkadot Parachain. ### Multiple Relayers and Rewards diff --git a/bridges/modules/grandpa/src/call_ext.rs b/bridges/modules/grandpa/src/call_ext.rs index f08eb4c5d1ab..d964901ba4bc 100644 --- a/bridges/modules/grandpa/src/call_ext.rs +++ b/bridges/modules/grandpa/src/call_ext.rs @@ -18,7 +18,10 @@ use crate::{ weights::WeightInfo, BestFinalized, BridgedBlockNumber, BridgedHeader, Config, CurrentAuthoritySet, Error, FreeHeadersRemaining, Pallet, }; -use bp_header_chain::{justification::GrandpaJustification, submit_finality_proof_limits_extras}; +use bp_header_chain::{ + justification::GrandpaJustification, submit_finality_proof_limits_extras, + SubmitFinalityProofInfo, +}; use bp_runtime::{BlockNumberOf, Chain, OwnedBridgeModule}; use frame_support::{ dispatch::CallableCallFor, @@ -31,37 +34,11 @@ use sp_runtime::{ transaction_validity::{InvalidTransaction, TransactionValidityError}, RuntimeDebug, SaturatedConversion, }; - -/// Info about a `SubmitParachainHeads` call which tries to update a single parachain. -#[derive(Copy, Clone, PartialEq, RuntimeDebug)] -pub struct SubmitFinalityProofInfo { - /// Number of the finality target. - pub block_number: N, - /// An identifier of the validators set that has signed the submitted justification. - /// It might be `None` if deprecated version of the `submit_finality_proof` is used. - pub current_set_id: Option, - /// If `true`, then the call proves new **mandatory** header. - pub is_mandatory: bool, - /// If `true`, then the call must be free (assuming that everything else is valid) to - /// be treated as valid. - pub is_free_execution_expected: bool, - /// Extra weight that we assume is included in the call. - /// - /// We have some assumptions about headers and justifications of the bridged chain. - /// We know that if our assumptions are correct, then the call must not have the - /// weight above some limit. The fee paid for weight above that limit, is never refunded. - pub extra_weight: Weight, - /// Extra size (in bytes) that we assume are included in the call. - /// - /// We have some assumptions about headers and justifications of the bridged chain. - /// We know that if our assumptions are correct, then the call must not have the - /// weight above some limit. The fee paid for bytes above that limit, is never refunded. - pub extra_size: u32, -} +use sp_std::fmt::Debug; /// Verified `SubmitFinalityProofInfo`. #[derive(Copy, Clone, PartialEq, RuntimeDebug)] -pub struct VerifiedSubmitFinalityProofInfo { +pub struct VerifiedSubmitFinalityProofInfo { /// Base call information. pub base: SubmitFinalityProofInfo, /// A difference between bundled bridged header and best bridged header known to us @@ -69,13 +46,6 @@ pub struct VerifiedSubmitFinalityProofInfo { pub improved_by: N, } -impl SubmitFinalityProofInfo { - /// Returns `true` if call size/weight is below our estimations for regular calls. - pub fn fits_limits(&self) -> bool { - self.extra_weight.is_zero() && self.extra_size.is_zero() - } -} - /// Helper struct that provides methods for working with the `SubmitFinalityProof` call. pub struct SubmitFinalityProofHelper, I: 'static> { _phantom_data: sp_std::marker::PhantomData<(T, I)>, @@ -336,9 +306,9 @@ mod tests { TestRuntime, }, BestFinalized, Config, CurrentAuthoritySet, FreeHeadersRemaining, PalletOperatingMode, - StoredAuthoritySet, SubmitFinalityProofInfo, WeightInfo, + StoredAuthoritySet, WeightInfo, }; - use bp_header_chain::ChainWithGrandpa; + use bp_header_chain::{ChainWithGrandpa, SubmitFinalityProofInfo}; use bp_runtime::{BasicOperatingMode, HeaderId}; use bp_test_utils::{ make_default_justification, make_justification_for_header, JustificationGeneratorParams, diff --git a/bridges/modules/grandpa/src/lib.rs b/bridges/modules/grandpa/src/lib.rs index c62951b74656..22a15ec4062f 100644 --- a/bridges/modules/grandpa/src/lib.rs +++ b/bridges/modules/grandpa/src/lib.rs @@ -117,7 +117,7 @@ pub mod pallet { /// /// However, if the bridged chain gets compromised, its validators may generate as many /// "free" headers as they want. And they may fill the whole block (at this chain) for - /// free. This constants limits number of calls that we may refund in a single block. + /// free. This constant limits number of calls that we may refund in a single block. /// All calls above this limit are accepted, but are not refunded. #[pallet::constant] type MaxFreeHeadersPerBlock: Get; @@ -728,15 +728,13 @@ pub mod pallet { init_params; let authority_set_length = authority_list.len(); let authority_set = StoredAuthoritySet::::try_new(authority_list, set_id) - .map_err(|e| { + .inspect_err(|_| { log::error!( target: LOG_TARGET, "Failed to initialize bridge. Number of authorities in the set {} is larger than the configured value {}", authority_set_length, T::BridgedChain::MAX_AUTHORITIES_COUNT, ); - - e })?; let initial_hash = header.hash(); diff --git a/bridges/modules/messages/Cargo.toml b/bridges/modules/messages/Cargo.toml index 33f524030d26..9df318587e38 100644 --- a/bridges/modules/messages/Cargo.toml +++ b/bridges/modules/messages/Cargo.toml @@ -73,7 +73,4 @@ try-runtime = [ "pallet-bridge-grandpa/try-runtime", "sp-runtime/try-runtime", ] -test-helpers = [ - "bp-runtime/test-helpers", - "sp-trie", -] +test-helpers = ["bp-runtime/test-helpers", "sp-trie"] diff --git a/bridges/modules/messages/README.md b/bridges/modules/messages/README.md index 80fd92eb0e5a..a78c86802498 100644 --- a/bridges/modules/messages/README.md +++ b/bridges/modules/messages/README.md @@ -28,9 +28,10 @@ Single message lane may be seen as a transport channel for single application (o time the module itself never dictates any lane or message rules. In the end, it is the runtime developer who defines what message lane and message mean for this runtime. -In our [Kusama<>Polkadot bridge](../../docs/polkadot-kusama-bridge-overview.md) we are using lane as a channel of -communication between two parachains of different relay chains. For example, lane `[0, 0, 0, 0]` is used for Polkadot <> -Kusama Asset Hub communications. Other lanes may be used to bridge other parachains. +In our [Kusama<>Polkadot bridge](../../docs/polkadot-kusama-bridge-overview.md) we are using lane +as a channel of communication between two parachains of different relay chains. For example, lane +`[0, 0, 0, 0]` is used for Polkadot <> Kusama Asset Hub communications. Other lanes may be used to +bridge other parachains. ## Message Workflow @@ -142,10 +143,9 @@ and will simply reject all transactions, related to inbound messages. ### What about other Constants in the Messages Module Configuration Trait? -Two settings that are used to check messages in the `send_message()` function. The -`pallet_bridge_messages::Config::ActiveOutboundLanes` is an array of all message lanes, that -may be used to send messages. All messages sent using other lanes are rejected. All messages that have -size above `pallet_bridge_messages::Config::MaximalOutboundPayloadSize` will also be rejected. +`pallet_bridge_messages::Config::MaximalOutboundPayloadSize` constant defines the maximal size +of outbound message that may be sent. If the message size is above this limit, the message is +rejected. To be able to reward the relayer for delivering messages, we store a map of message nonces range => identifier of the relayer that has delivered this range at the target chain runtime storage. If a diff --git a/bridges/modules/messages/src/benchmarking.rs b/bridges/modules/messages/src/benchmarking.rs index d38aaf32dc94..355fb08ab28a 100644 --- a/bridges/modules/messages/src/benchmarking.rs +++ b/bridges/modules/messages/src/benchmarking.rs @@ -19,14 +19,14 @@ #![cfg(feature = "runtime-benchmarks")] use crate::{ - inbound_lane::InboundLaneStorage, outbound_lane, weights_ext::EXPECTED_DEFAULT_MESSAGE_LENGTH, - BridgedChainOf, Call, OutboundLanes, RuntimeInboundLaneStorage, + active_outbound_lane, weights_ext::EXPECTED_DEFAULT_MESSAGE_LENGTH, BridgedChainOf, Call, + InboundLanes, OutboundLanes, }; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, target_chain::FromBridgedChainMessagesProof, ChainWithMessages, DeliveredMessages, - InboundLaneData, LaneId, MessageNonce, OutboundLaneData, UnrewardedRelayer, + InboundLaneData, LaneState, MessageNonce, OutboundLaneData, UnrewardedRelayer, UnrewardedRelayersState, }; use bp_runtime::{AccountIdOf, HashOf, UnverifiedStorageProofParams}; @@ -44,7 +44,7 @@ pub struct Pallet, I: 'static = ()>(crate::Pallet); /// Benchmark-specific message proof parameters. #[derive(Debug)] -pub struct MessageProofParams { +pub struct MessageProofParams { /// Id of the lane. pub lane: LaneId, /// Range of messages to include in the proof. @@ -62,7 +62,7 @@ pub struct MessageProofParams { /// Benchmark-specific message delivery proof parameters. #[derive(Debug)] -pub struct MessageDeliveryProofParams { +pub struct MessageDeliveryProofParams { /// Id of the lane. pub lane: LaneId, /// The proof needs to include this inbound lane data. @@ -74,10 +74,8 @@ pub struct MessageDeliveryProofParams { /// Trait that must be implemented by runtime. pub trait Config: crate::Config { /// Lane id to use in benchmarks. - /// - /// By default, lane 00000000 is used. - fn bench_lane_id() -> LaneId { - LaneId([0, 0, 0, 0]) + fn bench_lane_id() -> Self::LaneId { + Self::LaneId::default() } /// Return id of relayer account at the bridged chain. @@ -96,12 +94,12 @@ pub trait Config: crate::Config { /// Prepare messages proof to receive by the module. fn prepare_message_proof( - params: MessageProofParams, - ) -> (FromBridgedChainMessagesProof>>, Weight); + params: MessageProofParams, + ) -> (FromBridgedChainMessagesProof>, Self::LaneId>, Weight); /// Prepare messages delivery proof to receive by the module. fn prepare_message_delivery_proof( - params: MessageDeliveryProofParams, - ) -> FromBridgedChainMessagesDeliveryProof>>; + params: MessageDeliveryProofParams, + ) -> FromBridgedChainMessagesDeliveryProof>, Self::LaneId>; /// Returns true if message has been successfully dispatched or not. fn is_message_successfully_dispatched(_nonce: MessageNonce) -> bool { @@ -113,22 +111,32 @@ pub trait Config: crate::Config { } fn send_regular_message, I: 'static>() { - let mut outbound_lane = outbound_lane::(T::bench_lane_id()); + OutboundLanes::::insert( + T::bench_lane_id(), + OutboundLaneData { + state: LaneState::Opened, + latest_generated_nonce: 1, + ..Default::default() + }, + ); + + let mut outbound_lane = active_outbound_lane::(T::bench_lane_id()).unwrap(); outbound_lane.send_message(BoundedVec::try_from(vec![]).expect("We craft valid messages")); } fn receive_messages, I: 'static>(nonce: MessageNonce) { - let mut inbound_lane_storage = - RuntimeInboundLaneStorage::::from_lane_id(T::bench_lane_id()); - inbound_lane_storage.set_data(InboundLaneData { - relayers: vec![UnrewardedRelayer { - relayer: T::bridged_relayer_id(), - messages: DeliveredMessages::new(nonce), - }] - .into_iter() - .collect(), - last_confirmed_nonce: 0, - }); + InboundLanes::::insert( + T::bench_lane_id(), + InboundLaneData { + state: LaneState::Opened, + relayers: vec![UnrewardedRelayer { + relayer: T::bridged_relayer_id(), + messages: DeliveredMessages::new(nonce), + }] + .into(), + last_confirmed_nonce: 0, + }, + ); } struct ReceiveMessagesProofSetup, I: 'static> { @@ -173,8 +181,8 @@ impl, I: 'static> ReceiveMessagesProofSetup { fn check_last_nonce(&self) { assert_eq!( - crate::InboundLanes::::get(&T::bench_lane_id()).last_delivered_nonce(), - self.last_nonce(), + crate::InboundLanes::::get(&T::bench_lane_id()).map(|d| d.last_delivered_nonce()), + Some(self.last_nonce()), ); } } @@ -277,6 +285,7 @@ mod benchmarks { lane: T::bench_lane_id(), message_nonces: setup.nonces(), outbound_lane_data: Some(OutboundLaneData { + state: LaneState::Opened, oldest_unpruned_nonce: setup.last_nonce(), latest_received_nonce: ReceiveMessagesProofSetup::::LATEST_RECEIVED_NONCE, latest_generated_nonce: setup.last_nonce(), @@ -356,6 +365,7 @@ mod benchmarks { let proof = T::prepare_message_delivery_proof(MessageDeliveryProofParams { lane: T::bench_lane_id(), inbound_lane_data: InboundLaneData { + state: LaneState::Opened, relayers: vec![UnrewardedRelayer { relayer: relayer_id.clone(), messages: DeliveredMessages::new(1), @@ -374,7 +384,10 @@ mod benchmarks { relayers_state, ); - assert_eq!(OutboundLanes::::get(T::bench_lane_id()).latest_received_nonce, 1); + assert_eq!( + OutboundLanes::::get(T::bench_lane_id()).map(|s| s.latest_received_nonce), + Some(1) + ); assert!(T::is_relayer_rewarded(&relayer_id)); } @@ -404,6 +417,7 @@ mod benchmarks { let proof = T::prepare_message_delivery_proof(MessageDeliveryProofParams { lane: T::bench_lane_id(), inbound_lane_data: InboundLaneData { + state: LaneState::Opened, relayers: vec![UnrewardedRelayer { relayer: relayer_id.clone(), messages: delivered_messages, @@ -422,7 +436,10 @@ mod benchmarks { relayers_state, ); - assert_eq!(OutboundLanes::::get(T::bench_lane_id()).latest_received_nonce, 2); + assert_eq!( + OutboundLanes::::get(T::bench_lane_id()).map(|s| s.latest_received_nonce), + Some(2) + ); assert!(T::is_relayer_rewarded(&relayer_id)); } @@ -451,6 +468,7 @@ mod benchmarks { let proof = T::prepare_message_delivery_proof(MessageDeliveryProofParams { lane: T::bench_lane_id(), inbound_lane_data: InboundLaneData { + state: LaneState::Opened, relayers: vec![ UnrewardedRelayer { relayer: relayer1_id.clone(), @@ -475,7 +493,10 @@ mod benchmarks { relayers_state, ); - assert_eq!(OutboundLanes::::get(T::bench_lane_id()).latest_received_nonce, 2); + assert_eq!( + OutboundLanes::::get(T::bench_lane_id()).map(|s| s.latest_received_nonce), + Some(2) + ); assert!(T::is_relayer_rewarded(&relayer1_id)); assert!(T::is_relayer_rewarded(&relayer2_id)); } diff --git a/bridges/bin/runtime-common/src/messages_call_ext.rs b/bridges/modules/messages/src/call_ext.rs similarity index 56% rename from bridges/bin/runtime-common/src/messages_call_ext.rs rename to bridges/modules/messages/src/call_ext.rs index a9ee1969ae0c..9e5f5f8d1129 100644 --- a/bridges/bin/runtime-common/src/messages_call_ext.rs +++ b/bridges/modules/messages/src/call_ext.rs @@ -16,121 +16,18 @@ //! Helpers for easier manipulation of call processing with signed extensions. +use crate::{BridgedChainOf, Config, InboundLanes, OutboundLanes, Pallet, LOG_TARGET}; + use bp_messages::{ - target_chain::MessageDispatch, ChainWithMessages, InboundLaneData, LaneId, MessageNonce, + target_chain::MessageDispatch, BaseMessagesProofInfo, ChainWithMessages, InboundLaneData, + MessageNonce, MessagesCallInfo, ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, + UnrewardedRelayerOccupation, }; use bp_runtime::{AccountIdOf, OwnedBridgeModule}; use frame_support::{dispatch::CallableCallFor, traits::IsSubType}; -use pallet_bridge_messages::{BridgedChainOf, Config, Pallet}; -use sp_runtime::{transaction_validity::TransactionValidity, RuntimeDebug}; -use sp_std::ops::RangeInclusive; - -/// Generic info about a messages delivery/confirmation proof. -#[derive(PartialEq, RuntimeDebug)] -pub struct BaseMessagesProofInfo { - /// Message lane, used by the call. - pub lane_id: LaneId, - /// Nonces of messages, included in the call. - /// - /// For delivery transaction, it is nonces of bundled messages. For confirmation - /// transaction, it is nonces that are to be confirmed during the call. - pub bundled_range: RangeInclusive, - /// Nonce of the best message, stored by this chain before the call is dispatched. - /// - /// For delivery transaction, it is the nonce of best delivered message before the call. - /// For confirmation transaction, it is the nonce of best confirmed message before the call. - pub best_stored_nonce: MessageNonce, -} - -impl BaseMessagesProofInfo { - /// Returns true if `bundled_range` continues the `0..=best_stored_nonce` range. - fn appends_to_stored_nonce(&self) -> bool { - Some(*self.bundled_range.start()) == self.best_stored_nonce.checked_add(1) - } -} - -/// Occupation state of the unrewarded relayers vector. -#[derive(PartialEq, RuntimeDebug)] -#[cfg_attr(test, derive(Default))] -pub struct UnrewardedRelayerOccupation { - /// The number of remaining unoccupied entries for new relayers. - pub free_relayer_slots: MessageNonce, - /// The number of messages that we are ready to accept. - pub free_message_slots: MessageNonce, -} - -/// Info about a `ReceiveMessagesProof` call which tries to update a single lane. -#[derive(PartialEq, RuntimeDebug)] -pub struct ReceiveMessagesProofInfo { - /// Base messages proof info - pub base: BaseMessagesProofInfo, - /// State of unrewarded relayers vector. - pub unrewarded_relayers: UnrewardedRelayerOccupation, -} - -impl ReceiveMessagesProofInfo { - /// Returns true if: - /// - /// - either inbound lane is ready to accept bundled messages; - /// - /// - or there are no bundled messages, but the inbound lane is blocked by too many unconfirmed - /// messages and/or unrewarded relayers. - fn is_obsolete(&self, is_dispatcher_active: bool) -> bool { - // if dispatcher is inactive, we don't accept any delivery transactions - if !is_dispatcher_active { - return true - } - - // transactions with zero bundled nonces are not allowed, unless they're message - // delivery transactions, which brings reward confirmations required to unblock - // the lane - if self.base.bundled_range.is_empty() { - let empty_transactions_allowed = - // we allow empty transactions when we can't accept delivery from new relayers - self.unrewarded_relayers.free_relayer_slots == 0 || - // or if we can't accept new messages at all - self.unrewarded_relayers.free_message_slots == 0; - - return !empty_transactions_allowed - } +use sp_runtime::transaction_validity::TransactionValidity; - // otherwise we require bundled messages to continue stored range - !self.base.appends_to_stored_nonce() - } -} - -/// Info about a `ReceiveMessagesDeliveryProof` call which tries to update a single lane. -#[derive(PartialEq, RuntimeDebug)] -pub struct ReceiveMessagesDeliveryProofInfo(pub BaseMessagesProofInfo); - -impl ReceiveMessagesDeliveryProofInfo { - /// Returns true if outbound lane is ready to accept confirmations of bundled messages. - fn is_obsolete(&self) -> bool { - self.0.bundled_range.is_empty() || !self.0.appends_to_stored_nonce() - } -} - -/// Info about a `ReceiveMessagesProof` or a `ReceiveMessagesDeliveryProof` call -/// which tries to update a single lane. -#[derive(PartialEq, RuntimeDebug)] -pub enum CallInfo { - /// Messages delivery call info. - ReceiveMessagesProof(ReceiveMessagesProofInfo), - /// Messages delivery confirmation call info. - ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo), -} - -impl CallInfo { - /// Returns range of messages, bundled with the call. - pub fn bundled_messages(&self) -> RangeInclusive { - match *self { - Self::ReceiveMessagesProof(ref info) => info.base.bundled_range.clone(), - Self::ReceiveMessagesDeliveryProof(ref info) => info.0.bundled_range.clone(), - } - } -} - -/// Helper struct that provides methods for working with a call supported by `CallInfo`. +/// Helper struct that provides methods for working with a call supported by `MessagesCallInfo`. pub struct CallHelper, I: 'static> { _phantom_data: sp_std::marker::PhantomData<(T, I)>, } @@ -142,11 +39,13 @@ impl, I: 'static> CallHelper { /// /// - call is `receive_messages_delivery_proof` and all messages confirmations have been /// received. - pub fn was_successful(info: &CallInfo) -> bool { + pub fn was_successful(info: &MessagesCallInfo) -> bool { match info { - CallInfo::ReceiveMessagesProof(info) => { - let inbound_lane_data = - pallet_bridge_messages::InboundLanes::::get(info.base.lane_id); + MessagesCallInfo::ReceiveMessagesProof(info) => { + let inbound_lane_data = match InboundLanes::::get(info.base.lane_id) { + Some(inbound_lane_data) => inbound_lane_data, + None => return false, + }; if info.base.bundled_range.is_empty() { let post_occupation = unrewarded_relayers_occupation::(&inbound_lane_data); @@ -160,9 +59,11 @@ impl, I: 'static> CallHelper { inbound_lane_data.last_delivered_nonce() == *info.base.bundled_range.end() }, - CallInfo::ReceiveMessagesDeliveryProof(info) => { - let outbound_lane_data = - pallet_bridge_messages::OutboundLanes::::get(info.0.lane_id); + MessagesCallInfo::ReceiveMessagesDeliveryProof(info) => { + let outbound_lane_data = match OutboundLanes::::get(info.0.lane_id) { + Some(outbound_lane_data) => outbound_lane_data, + None => return false, + }; outbound_lane_data.latest_received_nonce == *info.0.bundled_range.end() }, } @@ -170,23 +71,25 @@ impl, I: 'static> CallHelper { } /// Trait representing a call that is a sub type of `pallet_bridge_messages::Call`. -pub trait MessagesCallSubType, I: 'static>: +pub trait CallSubType, I: 'static>: IsSubType, T>> { /// Create a new instance of `ReceiveMessagesProofInfo` from a `ReceiveMessagesProof` call. - fn receive_messages_proof_info(&self) -> Option; + fn receive_messages_proof_info(&self) -> Option>; /// Create a new instance of `ReceiveMessagesDeliveryProofInfo` from /// a `ReceiveMessagesDeliveryProof` call. - fn receive_messages_delivery_proof_info(&self) -> Option; + fn receive_messages_delivery_proof_info( + &self, + ) -> Option>; - /// Create a new instance of `CallInfo` from a `ReceiveMessagesProof` + /// Create a new instance of `MessagesCallInfo` from a `ReceiveMessagesProof` /// or a `ReceiveMessagesDeliveryProof` call. - fn call_info(&self) -> Option; + fn call_info(&self) -> Option>; - /// Create a new instance of `CallInfo` from a `ReceiveMessagesProof` + /// Create a new instance of `MessagesCallInfo` from a `ReceiveMessagesProof` /// or a `ReceiveMessagesDeliveryProof` call, if the call is for the provided lane. - fn call_info_for(&self, lane_id: LaneId) -> Option; + fn call_info_for(&self, lane_id: T::LaneId) -> Option>; /// Ensures that a `ReceiveMessagesProof` or a `ReceiveMessagesDeliveryProof` call: /// @@ -211,15 +114,13 @@ impl< Call: IsSubType, T>>, T: frame_system::Config + Config, I: 'static, - > MessagesCallSubType for T::RuntimeCall + > CallSubType for T::RuntimeCall { - fn receive_messages_proof_info(&self) -> Option { - if let Some(pallet_bridge_messages::Call::::receive_messages_proof { - ref proof, - .. - }) = self.is_sub_type() + fn receive_messages_proof_info(&self) -> Option> { + if let Some(crate::Call::::receive_messages_proof { ref proof, .. }) = + self.is_sub_type() { - let inbound_lane_data = pallet_bridge_messages::InboundLanes::::get(proof.lane); + let inbound_lane_data = InboundLanes::::get(proof.lane)?; return Some(ReceiveMessagesProofInfo { base: BaseMessagesProofInfo { @@ -236,14 +137,16 @@ impl< None } - fn receive_messages_delivery_proof_info(&self) -> Option { - if let Some(pallet_bridge_messages::Call::::receive_messages_delivery_proof { + fn receive_messages_delivery_proof_info( + &self, + ) -> Option> { + if let Some(crate::Call::::receive_messages_delivery_proof { ref proof, ref relayers_state, .. }) = self.is_sub_type() { - let outbound_lane_data = pallet_bridge_messages::OutboundLanes::::get(proof.lane); + let outbound_lane_data = OutboundLanes::::get(proof.lane)?; return Some(ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo { lane_id: proof.lane, @@ -260,23 +163,23 @@ impl< None } - fn call_info(&self) -> Option { + fn call_info(&self) -> Option> { if let Some(info) = self.receive_messages_proof_info() { - return Some(CallInfo::ReceiveMessagesProof(info)) + return Some(MessagesCallInfo::ReceiveMessagesProof(info)) } if let Some(info) = self.receive_messages_delivery_proof_info() { - return Some(CallInfo::ReceiveMessagesDeliveryProof(info)) + return Some(MessagesCallInfo::ReceiveMessagesDeliveryProof(info)) } None } - fn call_info_for(&self, lane_id: LaneId) -> Option { + fn call_info_for(&self, lane_id: T::LaneId) -> Option> { self.call_info().filter(|info| { let actual_lane_id = match info { - CallInfo::ReceiveMessagesProof(info) => info.base.lane_id, - CallInfo::ReceiveMessagesDeliveryProof(info) => info.0.lane_id, + MessagesCallInfo::ReceiveMessagesProof(info) => info.base.lane_id, + MessagesCallInfo::ReceiveMessagesDeliveryProof(info) => info.0.lane_id, }; actual_lane_id == lane_id }) @@ -287,29 +190,30 @@ impl< match self.call_info() { Some(proof_info) if is_pallet_halted => { log::trace!( - target: pallet_bridge_messages::LOG_TARGET, + target: LOG_TARGET, "Rejecting messages transaction on halted pallet: {:?}", proof_info ); return sp_runtime::transaction_validity::InvalidTransaction::Call.into() }, - Some(CallInfo::ReceiveMessagesProof(proof_info)) - if proof_info.is_obsolete(T::MessageDispatch::is_active()) => + Some(MessagesCallInfo::ReceiveMessagesProof(proof_info)) + if proof_info + .is_obsolete(T::MessageDispatch::is_active(proof_info.base.lane_id)) => { log::trace!( - target: pallet_bridge_messages::LOG_TARGET, + target: LOG_TARGET, "Rejecting obsolete messages delivery transaction: {:?}", proof_info ); return sp_runtime::transaction_validity::InvalidTransaction::Stale.into() }, - Some(CallInfo::ReceiveMessagesDeliveryProof(proof_info)) + Some(MessagesCallInfo::ReceiveMessagesDeliveryProof(proof_info)) if proof_info.is_obsolete() => { log::trace!( - target: pallet_bridge_messages::LOG_TARGET, + target: LOG_TARGET, "Rejecting obsolete messages confirmation transaction: {:?}", proof_info, ); @@ -343,52 +247,45 @@ fn unrewarded_relayers_occupation, I: 'static>( #[cfg(test)] mod tests { use super::*; - use crate::{ - messages_call_ext::MessagesCallSubType, - mock::{BridgedUnderlyingChain, DummyMessageDispatch, TestRuntime, ThisChainRuntimeCall}, - }; + use crate::tests::mock::*; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, DeliveredMessages, UnrewardedRelayer, - UnrewardedRelayersState, + target_chain::FromBridgedChainMessagesProof, DeliveredMessages, InboundLaneData, LaneState, + OutboundLaneData, UnrewardedRelayer, UnrewardedRelayersState, }; use sp_std::ops::RangeInclusive; fn fill_unrewarded_relayers() { - let mut inbound_lane_state = - pallet_bridge_messages::InboundLanes::::get(LaneId([0, 0, 0, 0])); - for n in 0..BridgedUnderlyingChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX { + let mut inbound_lane_state = InboundLanes::::get(test_lane_id()).unwrap(); + for n in 0..BridgedChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX { inbound_lane_state.relayers.push_back(UnrewardedRelayer { relayer: Default::default(), messages: DeliveredMessages { begin: n + 1, end: n + 1 }, }); } - pallet_bridge_messages::InboundLanes::::insert( - LaneId([0, 0, 0, 0]), - inbound_lane_state, - ); + InboundLanes::::insert(test_lane_id(), inbound_lane_state); } fn fill_unrewarded_messages() { - let mut inbound_lane_state = - pallet_bridge_messages::InboundLanes::::get(LaneId([0, 0, 0, 0])); + let mut inbound_lane_state = InboundLanes::::get(test_lane_id()).unwrap(); inbound_lane_state.relayers.push_back(UnrewardedRelayer { relayer: Default::default(), messages: DeliveredMessages { begin: 1, - end: BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + end: BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, }, }); - pallet_bridge_messages::InboundLanes::::insert( - LaneId([0, 0, 0, 0]), - inbound_lane_state, - ); + InboundLanes::::insert(test_lane_id(), inbound_lane_state); } fn deliver_message_10() { - pallet_bridge_messages::InboundLanes::::insert( - LaneId([0, 0, 0, 0]), - bp_messages::InboundLaneData { relayers: Default::default(), last_confirmed_nonce: 10 }, + InboundLanes::::insert( + test_lane_id(), + bp_messages::InboundLaneData { + state: LaneState::Opened, + relayers: Default::default(), + last_confirmed_nonce: 10, + }, ); } @@ -396,28 +293,33 @@ mod tests { nonces_start: bp_messages::MessageNonce, nonces_end: bp_messages::MessageNonce, ) -> bool { - ThisChainRuntimeCall::BridgeMessages( - pallet_bridge_messages::Call::::receive_messages_proof { - relayer_id_at_bridged_chain: 42, - messages_count: nonces_end.checked_sub(nonces_start).map(|x| x + 1).unwrap_or(0) - as u32, - dispatch_weight: frame_support::weights::Weight::zero(), - proof: Box::new(FromBridgedChainMessagesProof { - bridged_header_hash: Default::default(), - storage_proof: Default::default(), - lane: LaneId([0, 0, 0, 0]), - nonces_start, - nonces_end, - }), - }, - ) + RuntimeCall::Messages(crate::Call::::receive_messages_proof { + relayer_id_at_bridged_chain: 42, + messages_count: nonces_end.checked_sub(nonces_start).map(|x| x + 1).unwrap_or(0) as u32, + dispatch_weight: frame_support::weights::Weight::zero(), + proof: Box::new(FromBridgedChainMessagesProof { + bridged_header_hash: Default::default(), + storage_proof: Default::default(), + lane: test_lane_id(), + nonces_start, + nonces_end, + }), + }) .check_obsolete_call() .is_ok() } + fn run_test(test: impl Fn() -> T) -> T { + sp_io::TestExternalities::new(Default::default()).execute_with(|| { + InboundLanes::::insert(test_lane_id(), InboundLaneData::opened()); + OutboundLanes::::insert(test_lane_id(), OutboundLaneData::opened()); + test() + }) + } + #[test] fn extension_rejects_obsolete_messages() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { // when current best delivered is message#10 and we're trying to deliver messages 8..=9 // => tx is rejected deliver_message_10(); @@ -427,7 +329,7 @@ mod tests { #[test] fn extension_rejects_same_message() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { // when current best delivered is message#10 and we're trying to import messages 10..=10 // => tx is rejected deliver_message_10(); @@ -437,7 +339,7 @@ mod tests { #[test] fn extension_rejects_call_with_some_obsolete_messages() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { // when current best delivered is message#10 and we're trying to deliver messages // 10..=15 => tx is rejected deliver_message_10(); @@ -447,7 +349,7 @@ mod tests { #[test] fn extension_rejects_call_with_future_messages() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { // when current best delivered is message#10 and we're trying to deliver messages // 13..=15 => tx is rejected deliver_message_10(); @@ -457,12 +359,12 @@ mod tests { #[test] fn extension_reject_call_when_dispatcher_is_inactive() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { // when current best delivered is message#10 and we're trying to deliver message 11..=15 // => tx is accepted, but we have inactive dispatcher, so... deliver_message_10(); - DummyMessageDispatch::deactivate(); + TestMessageDispatch::deactivate(test_lane_id()); assert!(!validate_message_delivery(11, 15)); }); } @@ -470,7 +372,7 @@ mod tests { #[test] fn extension_rejects_empty_delivery_with_rewards_confirmations_if_there_are_free_relayer_and_message_slots( ) { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { deliver_message_10(); assert!(!validate_message_delivery(10, 9)); }); @@ -479,7 +381,7 @@ mod tests { #[test] fn extension_accepts_empty_delivery_with_rewards_confirmations_if_there_are_no_free_relayer_slots( ) { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { deliver_message_10(); fill_unrewarded_relayers(); assert!(validate_message_delivery(10, 9)); @@ -489,18 +391,18 @@ mod tests { #[test] fn extension_accepts_empty_delivery_with_rewards_confirmations_if_there_are_no_free_message_slots( ) { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { fill_unrewarded_messages(); assert!(validate_message_delivery( - BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, - BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX - 1 + BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX - 1 )); }); } #[test] fn extension_accepts_new_messages() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { // when current best delivered is message#10 and we're trying to deliver message 11..=15 // => tx is accepted deliver_message_10(); @@ -509,9 +411,10 @@ mod tests { } fn confirm_message_10() { - pallet_bridge_messages::OutboundLanes::::insert( - LaneId([0, 0, 0, 0]), + OutboundLanes::::insert( + test_lane_id(), bp_messages::OutboundLaneData { + state: LaneState::Opened, oldest_unpruned_nonce: 0, latest_received_nonce: 10, latest_generated_nonce: 10, @@ -520,26 +423,21 @@ mod tests { } fn validate_message_confirmation(last_delivered_nonce: bp_messages::MessageNonce) -> bool { - ThisChainRuntimeCall::BridgeMessages( - pallet_bridge_messages::Call::::receive_messages_delivery_proof { - proof: FromBridgedChainMessagesDeliveryProof { - bridged_header_hash: Default::default(), - storage_proof: Default::default(), - lane: LaneId([0, 0, 0, 0]), - }, - relayers_state: UnrewardedRelayersState { - last_delivered_nonce, - ..Default::default() - }, + RuntimeCall::Messages(crate::Call::::receive_messages_delivery_proof { + proof: FromBridgedChainMessagesDeliveryProof { + bridged_header_hash: Default::default(), + storage_proof: Default::default(), + lane: test_lane_id(), }, - ) + relayers_state: UnrewardedRelayersState { last_delivered_nonce, ..Default::default() }, + }) .check_obsolete_call() .is_ok() } #[test] fn extension_rejects_obsolete_confirmations() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { // when current best confirmed is message#10 and we're trying to confirm message#5 => tx // is rejected confirm_message_10(); @@ -549,7 +447,7 @@ mod tests { #[test] fn extension_rejects_same_confirmation() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { // when current best confirmed is message#10 and we're trying to confirm message#10 => // tx is rejected confirm_message_10(); @@ -559,7 +457,7 @@ mod tests { #[test] fn extension_rejects_empty_confirmation_even_if_there_are_no_free_unrewarded_entries() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { confirm_message_10(); fill_unrewarded_relayers(); assert!(!validate_message_confirmation(10)); @@ -568,7 +466,7 @@ mod tests { #[test] fn extension_accepts_new_confirmation() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { // when current best confirmed is message#10 and we're trying to confirm message#15 => // tx is accepted confirm_message_10(); @@ -580,10 +478,10 @@ mod tests { bundled_range: RangeInclusive, is_empty: bool, ) -> bool { - CallHelper::::was_successful(&CallInfo::ReceiveMessagesProof( + CallHelper::::was_successful(&MessagesCallInfo::ReceiveMessagesProof( ReceiveMessagesProofInfo { base: BaseMessagesProofInfo { - lane_id: LaneId([0, 0, 0, 0]), + lane_id: test_lane_id(), bundled_range, best_stored_nonce: 0, // doesn't matter for `was_successful` }, @@ -592,7 +490,7 @@ mod tests { free_message_slots: if is_empty { 0 } else { - BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX + BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX }, }, }, @@ -602,7 +500,7 @@ mod tests { #[test] #[allow(clippy::reversed_empty_ranges)] fn was_successful_returns_false_for_failed_reward_confirmation_transaction() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { fill_unrewarded_messages(); assert!(!was_message_delivery_successful(10..=9, true)); }); @@ -611,14 +509,14 @@ mod tests { #[test] #[allow(clippy::reversed_empty_ranges)] fn was_successful_returns_true_for_successful_reward_confirmation_transaction() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { assert!(was_message_delivery_successful(10..=9, true)); }); } #[test] fn was_successful_returns_false_for_failed_delivery() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { deliver_message_10(); assert!(!was_message_delivery_successful(10..=12, false)); }); @@ -626,7 +524,7 @@ mod tests { #[test] fn was_successful_returns_false_for_partially_successful_delivery() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { deliver_message_10(); assert!(!was_message_delivery_successful(9..=12, false)); }); @@ -634,25 +532,27 @@ mod tests { #[test] fn was_successful_returns_true_for_successful_delivery() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { deliver_message_10(); assert!(was_message_delivery_successful(9..=10, false)); }); } fn was_message_confirmation_successful(bundled_range: RangeInclusive) -> bool { - CallHelper::::was_successful(&CallInfo::ReceiveMessagesDeliveryProof( - ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo { - lane_id: LaneId([0, 0, 0, 0]), - bundled_range, - best_stored_nonce: 0, // doesn't matter for `was_successful` - }), - )) + CallHelper::::was_successful( + &MessagesCallInfo::ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo( + BaseMessagesProofInfo { + lane_id: test_lane_id(), + bundled_range, + best_stored_nonce: 0, // doesn't matter for `was_successful` + }, + )), + ) } #[test] fn was_successful_returns_false_for_failed_confirmation() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { confirm_message_10(); assert!(!was_message_confirmation_successful(10..=12)); }); @@ -660,7 +560,7 @@ mod tests { #[test] fn was_successful_returns_false_for_partially_successful_confirmation() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { confirm_message_10(); assert!(!was_message_confirmation_successful(9..=12)); }); @@ -668,7 +568,7 @@ mod tests { #[test] fn was_successful_returns_true_for_successful_confirmation() { - sp_io::TestExternalities::new(Default::default()).execute_with(|| { + run_test(|| { confirm_message_10(); assert!(was_message_confirmation_successful(9..=10)); }); diff --git a/bridges/modules/messages/src/inbound_lane.rs b/bridges/modules/messages/src/inbound_lane.rs index 7ef4599a93c4..91f1159f8f91 100644 --- a/bridges/modules/messages/src/inbound_lane.rs +++ b/bridges/modules/messages/src/inbound_lane.rs @@ -20,7 +20,7 @@ use crate::{BridgedChainOf, Config}; use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, - ChainWithMessages, DeliveredMessages, InboundLaneData, LaneId, MessageKey, MessageNonce, + ChainWithMessages, DeliveredMessages, InboundLaneData, LaneState, MessageKey, MessageNonce, OutboundLaneData, ReceptionResult, UnrewardedRelayer, }; use bp_runtime::AccountIdOf; @@ -33,17 +33,21 @@ use sp_std::prelude::PartialEq; pub trait InboundLaneStorage { /// Id of relayer on source chain. type Relayer: Clone + PartialEq; + /// Lane identifier type. + type LaneId: Encode; /// Lane id. - fn id(&self) -> LaneId; + fn id(&self) -> Self::LaneId; /// Return maximal number of unrewarded relayer entries in inbound lane. fn max_unrewarded_relayer_entries(&self) -> MessageNonce; /// Return maximal number of unconfirmed messages in inbound lane. fn max_unconfirmed_messages(&self) -> MessageNonce; /// Get lane data from the storage. - fn get_or_init_data(&mut self) -> InboundLaneData; + fn data(&self) -> InboundLaneData; /// Update lane data in the storage. fn set_data(&mut self, data: InboundLaneData); + /// Purge lane data from the storage. + fn purge(self); } /// Inbound lane data wrapper that implements `MaxEncodedLen`. @@ -120,9 +124,21 @@ impl InboundLane { InboundLane { storage } } - /// Returns `mut` storage reference. - pub fn storage_mut(&mut self) -> &mut S { - &mut self.storage + /// Get lane state. + pub fn state(&self) -> LaneState { + self.storage.data().state + } + + /// Returns storage reference. + pub fn storage(&self) -> &S { + &self.storage + } + + /// Set lane state. + pub fn set_state(&mut self, state: LaneState) { + let mut data = self.storage.data(); + data.state = state; + self.storage.set_data(data); } /// Receive state of the corresponding outbound lane. @@ -130,7 +146,7 @@ impl InboundLane { &mut self, outbound_lane_data: OutboundLaneData, ) -> Option { - let mut data = self.storage.get_or_init_data(); + let mut data = self.storage.data(); let last_delivered_nonce = data.last_delivered_nonce(); if outbound_lane_data.latest_received_nonce > last_delivered_nonce { @@ -167,13 +183,13 @@ impl InboundLane { } /// Receive new message. - pub fn receive_message( + pub fn receive_message>( &mut self, relayer_at_bridged_chain: &S::Relayer, nonce: MessageNonce, message_data: DispatchMessageData, ) -> ReceptionResult { - let mut data = self.storage.get_or_init_data(); + let mut data = self.storage.data(); if Some(nonce) != data.last_delivered_nonce().checked_add(1) { return ReceptionResult::InvalidNonce } @@ -211,20 +227,17 @@ impl InboundLane { ReceptionResult::Dispatched(dispatch_result) } + + /// Purge lane state from the storage. + pub fn purge(self) { + self.storage.purge() + } } #[cfg(test)] mod tests { use super::*; - use crate::{ - inbound_lane, - tests::mock::{ - dispatch_result, inbound_message_data, inbound_unrewarded_relayers_state, run_test, - unrewarded_relayer, BridgedChain, TestMessageDispatch, TestRuntime, REGULAR_PAYLOAD, - TEST_LANE_ID, TEST_RELAYER_A, TEST_RELAYER_B, TEST_RELAYER_C, - }, - RuntimeInboundLaneStorage, - }; + use crate::{active_inbound_lane, lanes_manager::RuntimeInboundLaneStorage, tests::mock::*}; use bp_messages::UnrewardedRelayersState; fn receive_regular_message( @@ -244,7 +257,7 @@ mod tests { #[test] fn receive_status_update_ignores_status_from_the_future() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); receive_regular_message(&mut lane, 1); assert_eq!( lane.receive_state_update(OutboundLaneData { @@ -254,14 +267,14 @@ mod tests { None, ); - assert_eq!(lane.storage.get_or_init_data().last_confirmed_nonce, 0); + assert_eq!(lane.storage.data().last_confirmed_nonce, 0); }); } #[test] fn receive_status_update_ignores_obsolete_status() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); receive_regular_message(&mut lane, 1); receive_regular_message(&mut lane, 2); receive_regular_message(&mut lane, 3); @@ -272,7 +285,7 @@ mod tests { }), Some(3), ); - assert_eq!(lane.storage.get_or_init_data().last_confirmed_nonce, 3); + assert_eq!(lane.storage.data().last_confirmed_nonce, 3); assert_eq!( lane.receive_state_update(OutboundLaneData { @@ -281,20 +294,20 @@ mod tests { }), None, ); - assert_eq!(lane.storage.get_or_init_data().last_confirmed_nonce, 3); + assert_eq!(lane.storage.data().last_confirmed_nonce, 3); }); } #[test] fn receive_status_update_works() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); receive_regular_message(&mut lane, 1); receive_regular_message(&mut lane, 2); receive_regular_message(&mut lane, 3); - assert_eq!(lane.storage.get_or_init_data().last_confirmed_nonce, 0); + assert_eq!(lane.storage.data().last_confirmed_nonce, 0); assert_eq!( - lane.storage.get_or_init_data().relayers, + lane.storage.data().relayers, vec![unrewarded_relayer(1, 3, TEST_RELAYER_A)] ); @@ -305,9 +318,9 @@ mod tests { }), Some(2), ); - assert_eq!(lane.storage.get_or_init_data().last_confirmed_nonce, 2); + assert_eq!(lane.storage.data().last_confirmed_nonce, 2); assert_eq!( - lane.storage.get_or_init_data().relayers, + lane.storage.data().relayers, vec![unrewarded_relayer(3, 3, TEST_RELAYER_A)] ); @@ -318,16 +331,16 @@ mod tests { }), Some(3), ); - assert_eq!(lane.storage.get_or_init_data().last_confirmed_nonce, 3); - assert_eq!(lane.storage.get_or_init_data().relayers, vec![]); + assert_eq!(lane.storage.data().last_confirmed_nonce, 3); + assert_eq!(lane.storage.data().relayers, vec![]); }); } #[test] fn receive_status_update_works_with_batches_from_relayers() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); - let mut seed_storage_data = lane.storage.get_or_init_data(); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); + let mut seed_storage_data = lane.storage.data(); // Prepare data seed_storage_data.last_confirmed_nonce = 0; seed_storage_data.relayers.push_back(unrewarded_relayer(1, 1, TEST_RELAYER_A)); @@ -343,9 +356,9 @@ mod tests { }), Some(3), ); - assert_eq!(lane.storage.get_or_init_data().last_confirmed_nonce, 3); + assert_eq!(lane.storage.data().last_confirmed_nonce, 3); assert_eq!( - lane.storage.get_or_init_data().relayers, + lane.storage.data().relayers, vec![ unrewarded_relayer(4, 4, TEST_RELAYER_B), unrewarded_relayer(5, 5, TEST_RELAYER_C) @@ -357,7 +370,7 @@ mod tests { #[test] fn fails_to_receive_message_with_incorrect_nonce() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); assert_eq!( lane.receive_message::( &TEST_RELAYER_A, @@ -366,14 +379,14 @@ mod tests { ), ReceptionResult::InvalidNonce ); - assert_eq!(lane.storage.get_or_init_data().last_delivered_nonce(), 0); + assert_eq!(lane.storage.data().last_delivered_nonce(), 0); }); } #[test] fn fails_to_receive_messages_above_unrewarded_relayer_entries_limit_per_lane() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); let max_nonce = BridgedChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; for current_nonce in 1..max_nonce + 1 { assert_eq!( @@ -409,7 +422,7 @@ mod tests { #[test] fn fails_to_receive_messages_above_unconfirmed_messages_limit_per_lane() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); let max_nonce = BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; for current_nonce in 1..=max_nonce { assert_eq!( @@ -445,7 +458,7 @@ mod tests { #[test] fn correctly_receives_following_messages_from_two_relayers_alternately() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); assert_eq!( lane.receive_message::( &TEST_RELAYER_A, @@ -471,7 +484,7 @@ mod tests { ReceptionResult::Dispatched(dispatch_result(0)) ); assert_eq!( - lane.storage.get_or_init_data().relayers, + lane.storage.data().relayers, vec![ unrewarded_relayer(1, 1, TEST_RELAYER_A), unrewarded_relayer(2, 2, TEST_RELAYER_B), @@ -484,7 +497,7 @@ mod tests { #[test] fn rejects_same_message_from_two_different_relayers() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); assert_eq!( lane.receive_message::( &TEST_RELAYER_A, @@ -507,16 +520,16 @@ mod tests { #[test] fn correct_message_is_processed_instantly() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); receive_regular_message(&mut lane, 1); - assert_eq!(lane.storage.get_or_init_data().last_delivered_nonce(), 1); + assert_eq!(lane.storage.data().last_delivered_nonce(), 1); }); } #[test] fn unspent_weight_is_returned_by_receive_message() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); let mut payload = REGULAR_PAYLOAD; *payload.dispatch_result.unspent_weight.ref_time_mut() = 1; assert_eq!( @@ -533,7 +546,7 @@ mod tests { #[test] fn first_message_is_confirmed_correctly() { run_test(|| { - let mut lane = inbound_lane::(TEST_LANE_ID); + let mut lane = active_inbound_lane::(test_lane_id()).unwrap(); receive_regular_message(&mut lane, 1); receive_regular_message(&mut lane, 2); assert_eq!( @@ -544,7 +557,7 @@ mod tests { Some(1), ); assert_eq!( - inbound_unrewarded_relayers_state(TEST_LANE_ID), + inbound_unrewarded_relayers_state(test_lane_id()), UnrewardedRelayersState { unrewarded_relayer_entries: 1, messages_in_oldest_entry: 1, diff --git a/bridges/modules/messages/src/lanes_manager.rs b/bridges/modules/messages/src/lanes_manager.rs new file mode 100644 index 000000000000..27cab48535d7 --- /dev/null +++ b/bridges/modules/messages/src/lanes_manager.rs @@ -0,0 +1,285 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +use crate::{ + BridgedChainOf, Config, InboundLane, InboundLaneStorage, InboundLanes, OutboundLane, + OutboundLaneStorage, OutboundLanes, OutboundMessages, StoredInboundLaneData, + StoredMessagePayload, +}; + +use bp_messages::{ + target_chain::MessageDispatch, ChainWithMessages, InboundLaneData, LaneState, MessageKey, + MessageNonce, OutboundLaneData, +}; +use bp_runtime::AccountIdOf; +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{ensure, sp_runtime::RuntimeDebug, PalletError}; +use scale_info::TypeInfo; +use sp_std::marker::PhantomData; + +/// Lanes manager errors. +#[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, PalletError, TypeInfo)] +pub enum LanesManagerError { + /// Inbound lane already exists. + InboundLaneAlreadyExists, + /// Outbound lane already exists. + OutboundLaneAlreadyExists, + /// No inbound lane with given id. + UnknownInboundLane, + /// No outbound lane with given id. + UnknownOutboundLane, + /// Inbound lane with given id is closed. + ClosedInboundLane, + /// Outbound lane with given id is closed. + ClosedOutboundLane, + /// Message dispatcher is inactive at given inbound lane. This is logical equivalent + /// of the [`Self::ClosedInboundLane`] variant. + LaneDispatcherInactive, +} + +/// Message lanes manager. +pub struct LanesManager(PhantomData<(T, I)>); + +impl, I: 'static> Default for LanesManager { + fn default() -> Self { + Self::new() + } +} + +impl, I: 'static> LanesManager { + /// Create new lanes manager. + pub fn new() -> Self { + Self(PhantomData) + } + + /// Create new inbound lane in `Opened` state. + pub fn create_inbound_lane( + &self, + lane_id: T::LaneId, + ) -> Result>, LanesManagerError> { + InboundLanes::::try_mutate(lane_id, |lane| match lane { + Some(_) => Err(LanesManagerError::InboundLaneAlreadyExists), + None => { + *lane = Some(StoredInboundLaneData(InboundLaneData { + state: LaneState::Opened, + ..Default::default() + })); + Ok(()) + }, + })?; + + self.active_inbound_lane(lane_id) + } + + /// Create new outbound lane in `Opened` state. + pub fn create_outbound_lane( + &self, + lane_id: T::LaneId, + ) -> Result>, LanesManagerError> { + OutboundLanes::::try_mutate(lane_id, |lane| match lane { + Some(_) => Err(LanesManagerError::OutboundLaneAlreadyExists), + None => { + *lane = Some(OutboundLaneData { state: LaneState::Opened, ..Default::default() }); + Ok(()) + }, + })?; + + self.active_outbound_lane(lane_id) + } + + /// Get existing inbound lane, checking that it is in usable state. + pub fn active_inbound_lane( + &self, + lane_id: T::LaneId, + ) -> Result>, LanesManagerError> { + Ok(InboundLane::new(RuntimeInboundLaneStorage::from_lane_id(lane_id, true)?)) + } + + /// Get existing outbound lane, checking that it is in usable state. + pub fn active_outbound_lane( + &self, + lane_id: T::LaneId, + ) -> Result>, LanesManagerError> { + Ok(OutboundLane::new(RuntimeOutboundLaneStorage::from_lane_id(lane_id, true)?)) + } + + /// Get existing inbound lane without any additional state checks. + pub fn any_state_inbound_lane( + &self, + lane_id: T::LaneId, + ) -> Result>, LanesManagerError> { + Ok(InboundLane::new(RuntimeInboundLaneStorage::from_lane_id(lane_id, false)?)) + } + + /// Get existing outbound lane without any additional state checks. + pub fn any_state_outbound_lane( + &self, + lane_id: T::LaneId, + ) -> Result>, LanesManagerError> { + Ok(OutboundLane::new(RuntimeOutboundLaneStorage::from_lane_id(lane_id, false)?)) + } +} + +/// Runtime inbound lane storage. +pub struct RuntimeInboundLaneStorage, I: 'static = ()> { + pub(crate) lane_id: T::LaneId, + pub(crate) cached_data: InboundLaneData>>, +} + +impl, I: 'static> RuntimeInboundLaneStorage { + /// Creates new runtime inbound lane storage for given **existing** lane. + fn from_lane_id( + lane_id: T::LaneId, + check_active: bool, + ) -> Result, LanesManagerError> { + let cached_data = + InboundLanes::::get(lane_id).ok_or(LanesManagerError::UnknownInboundLane)?; + + if check_active { + // check that the lane is not explicitly closed + ensure!(cached_data.state.is_active(), LanesManagerError::ClosedInboundLane); + // apart from the explicit closure, the lane may be unable to receive any messages. + // Right now we do an additional check here, but it may be done later (e.g. by + // explicitly closing the lane and reopening it from + // `pallet-xcm-bridge-hub::on-initialize`) + // + // The fact that we only check it here, means that the `MessageDispatch` may switch + // to inactive state during some message dispatch in the middle of message delivery + // transaction. But we treat result of `MessageDispatch::is_active()` as a hint, so + // we know that it won't drop messages - just it experiences problems with processing. + // This would allow us to check that in our signed extensions, and invalidate + // transaction early, thus avoiding losing honest relayers funds. This problem should + // gone with relayers coordination protocol. + // + // There's a limit on number of messages in the message delivery transaction, so even + // if we dispatch (enqueue) some additional messages, we'll know the maximal queue + // length; + ensure!( + T::MessageDispatch::is_active(lane_id), + LanesManagerError::LaneDispatcherInactive + ); + } + + Ok(RuntimeInboundLaneStorage { lane_id, cached_data: cached_data.into() }) + } + + /// Returns number of bytes that may be subtracted from the PoV component of + /// `receive_messages_proof` call, because the actual inbound lane state is smaller than the + /// maximal configured. + /// + /// Maximal inbound lane state set size is configured by the + /// `MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX` constant from the pallet configuration. The PoV + /// of the call includes the maximal size of inbound lane state. If the actual size is smaller, + /// we may subtract extra bytes from this component. + pub fn extra_proof_size_bytes(&self) -> u64 { + let max_encoded_len = StoredInboundLaneData::::max_encoded_len(); + let relayers_count = self.data().relayers.len(); + let actual_encoded_len = + InboundLaneData::>>::encoded_size_hint(relayers_count) + .unwrap_or(usize::MAX); + max_encoded_len.saturating_sub(actual_encoded_len) as _ + } +} + +impl, I: 'static> InboundLaneStorage for RuntimeInboundLaneStorage { + type Relayer = AccountIdOf>; + type LaneId = T::LaneId; + + fn id(&self) -> Self::LaneId { + self.lane_id + } + + fn max_unrewarded_relayer_entries(&self) -> MessageNonce { + BridgedChainOf::::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX + } + + fn max_unconfirmed_messages(&self) -> MessageNonce { + BridgedChainOf::::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX + } + + fn data(&self) -> InboundLaneData>> { + self.cached_data.clone() + } + + fn set_data(&mut self, data: InboundLaneData>>) { + self.cached_data = data.clone(); + InboundLanes::::insert(self.lane_id, StoredInboundLaneData::(data)) + } + + fn purge(self) { + InboundLanes::::remove(self.lane_id) + } +} + +/// Runtime outbound lane storage. +#[derive(Debug, PartialEq, Eq)] +pub struct RuntimeOutboundLaneStorage, I: 'static> { + pub(crate) lane_id: T::LaneId, + pub(crate) cached_data: OutboundLaneData, + pub(crate) _phantom: PhantomData<(T, I)>, +} + +impl, I: 'static> RuntimeOutboundLaneStorage { + /// Creates new runtime outbound lane storage for given **existing** lane. + fn from_lane_id(lane_id: T::LaneId, check_active: bool) -> Result { + let cached_data = + OutboundLanes::::get(lane_id).ok_or(LanesManagerError::UnknownOutboundLane)?; + ensure!( + !check_active || cached_data.state.is_active(), + LanesManagerError::ClosedOutboundLane + ); + Ok(Self { lane_id, cached_data, _phantom: PhantomData }) + } +} + +impl, I: 'static> OutboundLaneStorage for RuntimeOutboundLaneStorage { + type StoredMessagePayload = StoredMessagePayload; + type LaneId = T::LaneId; + + fn id(&self) -> Self::LaneId { + self.lane_id + } + + fn data(&self) -> OutboundLaneData { + self.cached_data.clone() + } + + fn set_data(&mut self, data: OutboundLaneData) { + self.cached_data = data.clone(); + OutboundLanes::::insert(self.lane_id, data) + } + + #[cfg(test)] + fn message(&self, nonce: &MessageNonce) -> Option { + OutboundMessages::::get(MessageKey { lane_id: self.lane_id, nonce: *nonce }) + .map(Into::into) + } + + fn save_message(&mut self, nonce: MessageNonce, message_payload: Self::StoredMessagePayload) { + OutboundMessages::::insert( + MessageKey { lane_id: self.lane_id, nonce }, + message_payload, + ); + } + + fn remove_message(&mut self, nonce: &MessageNonce) { + OutboundMessages::::remove(MessageKey { lane_id: self.lane_id, nonce: *nonce }); + } + + fn purge(self) { + OutboundLanes::::remove(self.lane_id) + } +} diff --git a/bridges/modules/messages/src/lib.rs b/bridges/modules/messages/src/lib.rs index bf105b140401..af14257db99c 100644 --- a/bridges/modules/messages/src/lib.rs +++ b/bridges/modules/messages/src/lib.rs @@ -36,8 +36,13 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -pub use inbound_lane::StoredInboundLaneData; -pub use outbound_lane::StoredMessagePayload; +pub use inbound_lane::{InboundLane, InboundLaneStorage, StoredInboundLaneData}; +pub use lanes_manager::{ + LanesManager, LanesManagerError, RuntimeInboundLaneStorage, RuntimeOutboundLaneStorage, +}; +pub use outbound_lane::{ + OutboundLane, OutboundLaneStorage, ReceptionConfirmationError, StoredMessagePayload, +}; pub use weights::WeightInfo; pub use weights_ext::{ ensure_able_to_receive_confirmation, ensure_able_to_receive_message, @@ -45,11 +50,6 @@ pub use weights_ext::{ EXPECTED_DEFAULT_MESSAGE_LENGTH, EXTRA_STORAGE_PROOF_SIZE, }; -use crate::{ - inbound_lane::{InboundLane, InboundLaneStorage}, - outbound_lane::{OutboundLane, OutboundLaneStorage, ReceptionConfirmationError}, -}; - use bp_header_chain::HeaderChain; use bp_messages::{ source_chain::{ @@ -60,20 +60,21 @@ use bp_messages::{ DeliveryPayments, DispatchMessage, FromBridgedChainMessagesProof, MessageDispatch, ProvedLaneMessages, ProvedMessages, }, - ChainWithMessages, DeliveredMessages, InboundLaneData, InboundMessageDetails, LaneId, - MessageKey, MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData, - OutboundMessageDetails, UnrewardedRelayersState, VerificationError, + ChainWithMessages, DeliveredMessages, InboundLaneData, InboundMessageDetails, MessageKey, + MessageNonce, MessagePayload, MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails, + UnrewardedRelayersState, VerificationError, }; use bp_runtime::{ AccountIdOf, BasicOperatingMode, HashOf, OwnedBridgeModule, PreComputedSize, RangeInclusiveExt, Size, }; -use codec::{Decode, Encode, MaxEncodedLen}; +use codec::{Decode, Encode}; use frame_support::{dispatch::PostDispatchInfo, ensure, fail, traits::Get, DefaultNoBound}; -use sp_runtime::traits::UniqueSaturatedFrom; use sp_std::{marker::PhantomData, prelude::*}; +mod call_ext; mod inbound_lane; +mod lanes_manager; mod outbound_lane; mod proofs; mod tests; @@ -83,7 +84,9 @@ pub mod weights; #[cfg(feature = "runtime-benchmarks")] pub mod benchmarking; +pub mod migration; +pub use call_ext::*; pub use pallet::*; #[cfg(feature = "test-helpers")] pub use tests::*; @@ -94,7 +97,7 @@ pub const LOG_TARGET: &str = "runtime::bridge-messages"; #[frame_support::pallet] pub mod pallet { use super::*; - use bp_messages::{ReceivedMessages, ReceptionResult}; + use bp_messages::{LaneIdType, ReceivedMessages, ReceptionResult}; use bp_runtime::RangeInclusiveExt; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; @@ -116,24 +119,29 @@ pub mod pallet { /// Bridged chain headers provider. type BridgedHeaderChain: HeaderChain; - /// Get all active outbound lanes that the message pallet is serving. - type ActiveOutboundLanes: Get<&'static [LaneId]>; - /// Payload type of outbound messages. This payload is dispatched on the bridged chain. type OutboundPayload: Parameter + Size; /// Payload type of inbound messages. This payload is dispatched on this chain. type InboundPayload: Decode; + /// Lane identifier type. + type LaneId: LaneIdType; /// Handler for relayer payments that happen during message delivery transaction. type DeliveryPayments: DeliveryPayments; /// Handler for relayer payments that happen during message delivery confirmation /// transaction. - type DeliveryConfirmationPayments: DeliveryConfirmationPayments; + type DeliveryConfirmationPayments: DeliveryConfirmationPayments< + Self::AccountId, + Self::LaneId, + >; /// Delivery confirmation callback. - type OnMessagesDelivered: OnMessagesDelivered; + type OnMessagesDelivered: OnMessagesDelivered; /// Message dispatch handler. - type MessageDispatch: MessageDispatch; + type MessageDispatch: MessageDispatch< + DispatchPayload = Self::InboundPayload, + LaneId = Self::LaneId, + >; } /// Shortcut to this chain type for Config. @@ -142,8 +150,11 @@ pub mod pallet { pub type BridgedChainOf = >::BridgedChain; /// Shortcut to bridged header chain type for Config. pub type BridgedHeaderChainOf = >::BridgedHeaderChain; + /// Shortcut to lane identifier type for Config. + pub type LaneIdOf = >::LaneId; #[pallet::pallet] + #[pallet::storage_version(migration::STORAGE_VERSION)] pub struct Pallet(PhantomData<(T, I)>); impl, I: 'static> OwnedBridgeModule for Pallet { @@ -153,40 +164,6 @@ pub mod pallet { type OperatingModeStorage = PalletOperatingMode; } - #[pallet::hooks] - impl, I: 'static> Hooks> for Pallet - where - u32: TryFrom>, - { - fn on_idle(_block: BlockNumberFor, remaining_weight: Weight) -> Weight { - // we'll need at least to read outbound lane state, kill a message and update lane state - let db_weight = T::DbWeight::get(); - if !remaining_weight.all_gte(db_weight.reads_writes(1, 2)) { - return Weight::zero() - } - - // messages from lane with index `i` in `ActiveOutboundLanes` are pruned when - // `System::block_number() % lanes.len() == i`. Otherwise we need to read lane states on - // every block, wasting the whole `remaining_weight` for nothing and causing starvation - // of the last lane pruning - let active_lanes = T::ActiveOutboundLanes::get(); - let active_lanes_len = (active_lanes.len() as u32).into(); - let active_lane_index = u32::unique_saturated_from( - frame_system::Pallet::::block_number() % active_lanes_len, - ); - let active_lane_id = active_lanes[active_lane_index as usize]; - - // first db read - outbound lane state - let mut active_lane = outbound_lane::(active_lane_id); - let mut used_weight = db_weight.reads(1); - // and here we'll have writes - used_weight += active_lane.prune_messages(db_weight, remaining_weight - used_weight); - - // we already checked we have enough `remaining_weight` to cover this `used_weight` - used_weight - } - } - #[pallet::call] impl, I: 'static> Pallet { /// Change `PalletOwner`. @@ -236,7 +213,7 @@ pub mod pallet { pub fn receive_messages_proof( origin: OriginFor, relayer_id_at_bridged_chain: AccountIdOf>, - proof: Box>>>, + proof: Box>, T::LaneId>>, messages_count: u32, dispatch_weight: Weight, ) -> DispatchResultWithPostInfo { @@ -250,9 +227,6 @@ pub mod pallet { Error::::TooManyMessagesInTheProof ); - // if message dispatcher is currently inactive, we won't accept any messages - ensure!(T::MessageDispatch::is_active(), Error::::MessageDispatchInactive); - // why do we need to know the weight of this (`receive_messages_proof`) call? Because // we may want to return some funds for not-dispatching (or partially dispatching) some // messages to the call origin (relayer). And this is done by returning actual weight @@ -271,92 +245,89 @@ pub mod pallet { let mut actual_weight = declared_weight; // verify messages proof && convert proof into messages - let messages = verify_and_decode_messages_proof::(*proof, messages_count) - .map_err(|err| { - log::trace!(target: LOG_TARGET, "Rejecting invalid messages proof: {:?}", err,); + let (lane_id, lane_data) = + verify_and_decode_messages_proof::(*proof, messages_count).map_err( + |err| { + log::trace!(target: LOG_TARGET, "Rejecting invalid messages proof: {:?}", err,); - Error::::InvalidMessagesProof - })?; + Error::::InvalidMessagesProof + }, + )?; // dispatch messages and (optionally) update lane(s) state(s) let mut total_messages = 0; let mut valid_messages = 0; - let mut messages_received_status = Vec::with_capacity(messages.len()); let mut dispatch_weight_left = dispatch_weight; - for (lane_id, lane_data) in messages { - let mut lane = inbound_lane::(lane_id); - - // subtract extra storage proof bytes from the actual PoV size - there may be - // less unrewarded relayers than the maximal configured value - let lane_extra_proof_size_bytes = lane.storage_mut().extra_proof_size_bytes(); - actual_weight = actual_weight.set_proof_size( - actual_weight.proof_size().saturating_sub(lane_extra_proof_size_bytes), - ); + let mut lane = active_inbound_lane::(lane_id)?; - if let Some(lane_state) = lane_data.lane_state { - let updated_latest_confirmed_nonce = lane.receive_state_update(lane_state); - if let Some(updated_latest_confirmed_nonce) = updated_latest_confirmed_nonce { - log::trace!( - target: LOG_TARGET, - "Received lane {:?} state update: latest_confirmed_nonce={}. Unrewarded relayers: {:?}", - lane_id, - updated_latest_confirmed_nonce, - UnrewardedRelayersState::from(&lane.storage_mut().get_or_init_data()), - ); - } - } + // subtract extra storage proof bytes from the actual PoV size - there may be + // less unrewarded relayers than the maximal configured value + let lane_extra_proof_size_bytes = lane.storage().extra_proof_size_bytes(); + actual_weight = actual_weight.set_proof_size( + actual_weight.proof_size().saturating_sub(lane_extra_proof_size_bytes), + ); - let mut lane_messages_received_status = - ReceivedMessages::new(lane_id, Vec::with_capacity(lane_data.messages.len())); - for mut message in lane_data.messages { - debug_assert_eq!(message.key.lane_id, lane_id); - total_messages += 1; - - // ensure that relayer has declared enough weight for dispatching next message - // on this lane. We can't dispatch lane messages out-of-order, so if declared - // weight is not enough, let's move to next lane - let message_dispatch_weight = T::MessageDispatch::dispatch_weight(&mut message); - if message_dispatch_weight.any_gt(dispatch_weight_left) { - log::trace!( - target: LOG_TARGET, - "Cannot dispatch any more messages on lane {:?}. Weight: declared={}, left={}", - lane_id, - message_dispatch_weight, - dispatch_weight_left, - ); - - fail!(Error::::InsufficientDispatchWeight); - } + if let Some(lane_state) = lane_data.lane_state { + let updated_latest_confirmed_nonce = lane.receive_state_update(lane_state); + if let Some(updated_latest_confirmed_nonce) = updated_latest_confirmed_nonce { + log::trace!( + target: LOG_TARGET, + "Received lane {:?} state update: latest_confirmed_nonce={}. Unrewarded relayers: {:?}", + lane_id, + updated_latest_confirmed_nonce, + UnrewardedRelayersState::from(&lane.storage().data()), + ); + } + } - let receival_result = lane.receive_message::( - &relayer_id_at_bridged_chain, - message.key.nonce, - message.data, + let mut messages_received_status = + ReceivedMessages::new(lane_id, Vec::with_capacity(lane_data.messages.len())); + for mut message in lane_data.messages { + debug_assert_eq!(message.key.lane_id, lane_id); + total_messages += 1; + + // ensure that relayer has declared enough weight for dispatching next message + // on this lane. We can't dispatch lane messages out-of-order, so if declared + // weight is not enough, let's move to next lane + let message_dispatch_weight = T::MessageDispatch::dispatch_weight(&mut message); + if message_dispatch_weight.any_gt(dispatch_weight_left) { + log::trace!( + target: LOG_TARGET, + "Cannot dispatch any more messages on lane {:?}. Weight: declared={}, left={}", + lane_id, + message_dispatch_weight, + dispatch_weight_left, ); - // note that we're returning unspent weight to relayer even if message has been - // rejected by the lane. This allows relayers to submit spam transactions with - // e.g. the same set of already delivered messages over and over again, without - // losing funds for messages dispatch. But keep in mind that relayer pays base - // delivery transaction cost anyway. And base cost covers everything except - // dispatch, so we have a balance here. - let unspent_weight = match &receival_result { - ReceptionResult::Dispatched(dispatch_result) => { - valid_messages += 1; - dispatch_result.unspent_weight - }, - ReceptionResult::InvalidNonce | - ReceptionResult::TooManyUnrewardedRelayers | - ReceptionResult::TooManyUnconfirmedMessages => message_dispatch_weight, - }; - lane_messages_received_status.push(message.key.nonce, receival_result); - - let unspent_weight = unspent_weight.min(message_dispatch_weight); - dispatch_weight_left -= message_dispatch_weight - unspent_weight; - actual_weight = actual_weight.saturating_sub(unspent_weight); + fail!(Error::::InsufficientDispatchWeight); } - messages_received_status.push(lane_messages_received_status); + let receival_result = lane.receive_message::( + &relayer_id_at_bridged_chain, + message.key.nonce, + message.data, + ); + + // note that we're returning unspent weight to relayer even if message has been + // rejected by the lane. This allows relayers to submit spam transactions with + // e.g. the same set of already delivered messages over and over again, without + // losing funds for messages dispatch. But keep in mind that relayer pays base + // delivery transaction cost anyway. And base cost covers everything except + // dispatch, so we have a balance here. + let unspent_weight = match &receival_result { + ReceptionResult::Dispatched(dispatch_result) => { + valid_messages += 1; + dispatch_result.unspent_weight + }, + ReceptionResult::InvalidNonce | + ReceptionResult::TooManyUnrewardedRelayers | + ReceptionResult::TooManyUnconfirmedMessages => message_dispatch_weight, + }; + messages_received_status.push(message.key.nonce, receival_result); + + let unspent_weight = unspent_weight.min(message_dispatch_weight); + dispatch_weight_left -= message_dispatch_weight - unspent_weight; + actual_weight = actual_weight.saturating_sub(unspent_weight); } // let's now deal with relayer payments @@ -389,7 +360,7 @@ pub mod pallet { ))] pub fn receive_messages_delivery_proof( origin: OriginFor, - proof: FromBridgedChainMessagesDeliveryProof>>, + proof: FromBridgedChainMessagesDeliveryProof>, T::LaneId>, mut relayers_state: UnrewardedRelayersState, ) -> DispatchResultWithPostInfo { Self::ensure_not_halted().map_err(Error::::BridgeModule)?; @@ -412,7 +383,7 @@ pub mod pallet { ); // mark messages as delivered - let mut lane = outbound_lane::(lane_id); + let mut lane = any_state_outbound_lane::(lane_id)?; let last_delivered_nonce = lane_data.last_delivered_nonce(); let confirmed_messages = lane .confirm_delivery( @@ -426,7 +397,7 @@ pub mod pallet { // emit 'delivered' event let received_range = confirmed_messages.begin..=confirmed_messages.end; Self::deposit_event(Event::MessagesDelivered { - lane_id, + lane_id: lane_id.into(), messages: confirmed_messages, }); @@ -480,19 +451,22 @@ pub mod pallet { /// Message has been accepted and is waiting to be delivered. MessageAccepted { /// Lane, which has accepted the message. - lane_id: LaneId, + lane_id: T::LaneId, /// Nonce of accepted message. nonce: MessageNonce, }, /// Messages have been received from the bridged chain. MessagesReceived( /// Result of received messages dispatch. - Vec::DispatchLevelResult>>, + ReceivedMessages< + ::DispatchLevelResult, + T::LaneId, + >, ), /// Messages in the inclusive range have been delivered to the bridged chain. MessagesDelivered { /// Lane for which the delivery has been confirmed. - lane_id: LaneId, + lane_id: T::LaneId, /// Delivered messages. messages: DeliveredMessages, }, @@ -503,14 +477,10 @@ pub mod pallet { pub enum Error { /// Pallet is not in Normal operating mode. NotOperatingNormally, - /// The outbound lane is inactive. - InactiveOutboundLane, - /// The inbound message dispatcher is inactive. - MessageDispatchInactive, + /// Error that is reported by the lanes manager. + LanesManager(LanesManagerError), /// Message has been treated as invalid by the pallet logic. MessageRejectedByPallet(VerificationError), - /// Submitter has failed to pay fee for delivering and dispatching messages. - FailedToWithdrawMessageFee, /// The transaction brings too many messages. TooManyMessagesInTheProof, /// Invalid messages has been submitted. @@ -523,8 +493,6 @@ pub mod pallet { /// The cumulative dispatch weight, passed by relayer is not enough to cover dispatch /// of all bundled messages. InsufficientDispatchWeight, - /// The message someone is trying to work with (i.e. increase fee) is not yet sent. - MessageIsNotYetSent, /// Error confirming messages receival. ReceptionConfirmation(ReceptionConfirmationError), /// Error generated by the `OwnedBridgeModule` trait. @@ -549,45 +517,27 @@ pub mod pallet { pub type PalletOperatingMode, I: 'static = ()> = StorageValue<_, MessagesOperatingMode, ValueQuery>; + // TODO: https://github.com/paritytech/parity-bridges-common/pull/2213: let's limit number of + // possible opened lanes && use it to constraint maps below + /// Map of lane id => inbound lane data. #[pallet::storage] pub type InboundLanes, I: 'static = ()> = - StorageMap<_, Blake2_128Concat, LaneId, StoredInboundLaneData, ValueQuery>; + StorageMap<_, Blake2_128Concat, T::LaneId, StoredInboundLaneData, OptionQuery>; /// Map of lane id => outbound lane data. #[pallet::storage] pub type OutboundLanes, I: 'static = ()> = StorageMap< Hasher = Blake2_128Concat, - Key = LaneId, + Key = T::LaneId, Value = OutboundLaneData, - QueryKind = ValueQuery, - OnEmpty = GetDefault, - MaxValues = MaybeOutboundLanesCount, - >; - - /// Map of lane id => is congested signal sent. It is managed by the - /// `bridge_runtime_common::LocalXcmQueueManager`. - /// - /// **bridges-v1**: this map is a temporary hack and will be dropped in the `v2`. We can emulate - /// a storage map using `sp_io::unhashed` storage functions, but then benchmarks are not - /// accounting its `proof_size`, so it is missing from the final weights. So we need to make it - /// a map inside some pallet. We could use a simply value instead of map here, because - /// in `v1` we'll only have a single lane. But in the case of adding another lane before `v2`, - /// it'll be easier to deal with the isolated storage map instead. - #[pallet::storage] - pub type OutboundLanesCongestedSignals, I: 'static = ()> = StorageMap< - Hasher = Blake2_128Concat, - Key = LaneId, - Value = bool, - QueryKind = ValueQuery, - OnEmpty = GetDefault, - MaxValues = MaybeOutboundLanesCount, + QueryKind = OptionQuery, >; /// All queued outbound messages. #[pallet::storage] pub type OutboundMessages, I: 'static = ()> = - StorageMap<_, Blake2_128Concat, MessageKey, StoredMessagePayload>; + StorageMap<_, Blake2_128Concat, MessageKey, StoredMessagePayload>; #[pallet::genesis_config] #[derive(DefaultNoBound)] @@ -596,8 +546,11 @@ pub mod pallet { pub operating_mode: MessagesOperatingMode, /// Initial pallet owner. pub owner: Option, + /// Opened lanes. + pub opened_lanes: Vec, /// Dummy marker. - pub phantom: sp_std::marker::PhantomData, + #[serde(skip)] + pub _phantom: sp_std::marker::PhantomData, } #[pallet::genesis_build] @@ -607,18 +560,34 @@ pub mod pallet { if let Some(ref owner) = self.owner { PalletOwner::::put(owner); } + + for lane_id in &self.opened_lanes { + InboundLanes::::insert(lane_id, InboundLaneData::opened()); + OutboundLanes::::insert(lane_id, OutboundLaneData::opened()); + } + } + } + + #[pallet::hooks] + impl, I: 'static> Hooks> for Pallet { + #[cfg(feature = "try-runtime")] + fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { + Self::do_try_state() } } impl, I: 'static> Pallet { /// Get stored data of the outbound message with given nonce. - pub fn outbound_message_data(lane: LaneId, nonce: MessageNonce) -> Option { + pub fn outbound_message_data( + lane: T::LaneId, + nonce: MessageNonce, + ) -> Option { OutboundMessages::::get(MessageKey { lane_id: lane, nonce }).map(Into::into) } /// Prepare data, related to given inbound message. pub fn inbound_message_data( - lane: LaneId, + lane: T::LaneId, payload: MessagePayload, outbound_details: OutboundMessageDetails, ) -> InboundMessageDetails { @@ -632,24 +601,67 @@ pub mod pallet { } /// Return outbound lane data. - pub fn outbound_lane_data(lane: LaneId) -> OutboundLaneData { + pub fn outbound_lane_data(lane: T::LaneId) -> Option { OutboundLanes::::get(lane) } /// Return inbound lane data. pub fn inbound_lane_data( - lane: LaneId, - ) -> InboundLaneData>> { - InboundLanes::::get(lane).0 + lane: T::LaneId, + ) -> Option>>> { + InboundLanes::::get(lane).map(|lane| lane.0) } } - /// Get-parameter that returns number of active outbound lanes that the pallet maintains. - pub struct MaybeOutboundLanesCount(PhantomData<(T, I)>); + #[cfg(any(feature = "try-runtime", test))] + impl, I: 'static> Pallet { + /// Ensure the correctness of the state of this pallet. + pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { + Self::do_try_state_for_outbound_lanes() + } - impl, I: 'static> Get> for MaybeOutboundLanesCount { - fn get() -> Option { - Some(T::ActiveOutboundLanes::get().len() as u32) + /// Ensure the correctness of the state of outbound lanes. + pub fn do_try_state_for_outbound_lanes() -> Result<(), sp_runtime::TryRuntimeError> { + use sp_runtime::traits::One; + use sp_std::vec::Vec; + + // collect unpruned lanes + let mut unpruned_lanes = Vec::new(); + for (lane_id, lane_data) in OutboundLanes::::iter() { + let Some(expected_last_prunned_nonce) = + lane_data.oldest_unpruned_nonce.checked_sub(One::one()) + else { + continue; + }; + + // collect message_nonces that were supposed to be pruned + let mut unpruned_message_nonces = Vec::new(); + const MAX_MESSAGES_ITERATION: u64 = 16; + let start_nonce = + expected_last_prunned_nonce.checked_sub(MAX_MESSAGES_ITERATION).unwrap_or(0); + for current_nonce in start_nonce..=expected_last_prunned_nonce { + // check a message for current_nonce + if OutboundMessages::::contains_key(MessageKey { + lane_id, + nonce: current_nonce, + }) { + unpruned_message_nonces.push(current_nonce); + } + } + + if !unpruned_message_nonces.is_empty() { + log::warn!( + target: LOG_TARGET, + "do_try_state_for_outbound_lanes for lane_id: {lane_id:?} with lane_data: {lane_data:?} found unpruned_message_nonces: {unpruned_message_nonces:?}", + ); + unpruned_lanes.push((lane_id, lane_data, unpruned_message_nonces)); + } + } + + // ensure messages before `oldest_unpruned_nonce` are really pruned. + ensure!(unpruned_lanes.is_empty(), "Found unpruned lanes!"); + + Ok(()) } } } @@ -658,11 +670,12 @@ pub mod pallet { /// to send it on the bridge. #[derive(Debug, PartialEq, Eq)] pub struct SendMessageArgs, I: 'static> { - lane_id: LaneId, + lane_id: T::LaneId, + lane: OutboundLane>, payload: StoredMessagePayload, } -impl bp_messages::source_chain::MessagesBridge for Pallet +impl bp_messages::source_chain::MessagesBridge for Pallet where T: Config, I: 'static, @@ -671,16 +684,18 @@ where type SendMessageArgs = SendMessageArgs; fn validate_message( - lane: LaneId, + lane_id: T::LaneId, message: &T::OutboundPayload, ) -> Result, Self::Error> { + // we can't accept any messages if the pallet is halted ensure_normal_operating_mode::()?; - // let's check if outbound lane is active - ensure!(T::ActiveOutboundLanes::get().contains(&lane), Error::::InactiveOutboundLane); + // check lane + let lane = active_outbound_lane::(lane_id)?; Ok(SendMessageArgs { - lane_id: lane, + lane_id, + lane, payload: StoredMessagePayload::::try_from(message.encode()).map_err(|_| { Error::::MessageRejectedByPallet(VerificationError::MessageTooLarge) })?, @@ -689,7 +704,7 @@ where fn send_message(args: SendMessageArgs) -> SendMessageArtifacts { // save message in outbound storage and emit event - let mut lane = outbound_lane::(args.lane_id); + let mut lane = args.lane; let message_len = args.payload.len(); let nonce = lane.send_message(args.payload); @@ -704,7 +719,10 @@ where message_len, ); - Pallet::::deposit_event(Event::MessageAccepted { lane_id: args.lane_id, nonce }); + Pallet::::deposit_event(Event::MessageAccepted { + lane_id: args.lane_id.into(), + nonce, + }); SendMessageArtifacts { nonce, enqueued_messages } } @@ -721,144 +739,51 @@ fn ensure_normal_operating_mode, I: 'static>() -> Result<(), Error< Err(Error::::NotOperatingNormally) } -/// Creates new inbound lane object, backed by runtime storage. -fn inbound_lane, I: 'static>( - lane_id: LaneId, -) -> InboundLane> { - InboundLane::new(RuntimeInboundLaneStorage::from_lane_id(lane_id)) -} - -/// Creates new outbound lane object, backed by runtime storage. -fn outbound_lane, I: 'static>( - lane_id: LaneId, -) -> OutboundLane> { - OutboundLane::new(RuntimeOutboundLaneStorage { lane_id, _phantom: Default::default() }) -} - -/// Runtime inbound lane storage. -struct RuntimeInboundLaneStorage, I: 'static = ()> { - lane_id: LaneId, - cached_data: Option>>>, - _phantom: PhantomData, +/// Creates new inbound lane object, backed by runtime storage. Lane must be active. +fn active_inbound_lane, I: 'static>( + lane_id: T::LaneId, +) -> Result>, Error> { + LanesManager::::new() + .active_inbound_lane(lane_id) + .map_err(Error::LanesManager) } -impl, I: 'static> RuntimeInboundLaneStorage { - /// Creates new runtime inbound lane storage. - fn from_lane_id(lane_id: LaneId) -> RuntimeInboundLaneStorage { - RuntimeInboundLaneStorage { lane_id, cached_data: None, _phantom: Default::default() } - } +/// Creates new outbound lane object, backed by runtime storage. Lane must be active. +fn active_outbound_lane, I: 'static>( + lane_id: T::LaneId, +) -> Result>, Error> { + LanesManager::::new() + .active_outbound_lane(lane_id) + .map_err(Error::LanesManager) } -impl, I: 'static> RuntimeInboundLaneStorage { - /// Returns number of bytes that may be subtracted from the PoV component of - /// `receive_messages_proof` call, because the actual inbound lane state is smaller than the - /// maximal configured. - /// - /// Maximal inbound lane state set size is configured by the - /// `MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX` constant from the pallet configuration. The PoV - /// of the call includes the maximal size of inbound lane state. If the actual size is smaller, - /// we may subtract extra bytes from this component. - pub fn extra_proof_size_bytes(&mut self) -> u64 { - let max_encoded_len = StoredInboundLaneData::::max_encoded_len(); - let relayers_count = self.get_or_init_data().relayers.len(); - let actual_encoded_len = - InboundLaneData::>>::encoded_size_hint(relayers_count) - .unwrap_or(usize::MAX); - max_encoded_len.saturating_sub(actual_encoded_len) as _ - } -} - -impl, I: 'static> InboundLaneStorage for RuntimeInboundLaneStorage { - type Relayer = AccountIdOf>; - - fn id(&self) -> LaneId { - self.lane_id - } - - fn max_unrewarded_relayer_entries(&self) -> MessageNonce { - BridgedChainOf::::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX - } - - fn max_unconfirmed_messages(&self) -> MessageNonce { - BridgedChainOf::::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX - } - - fn get_or_init_data(&mut self) -> InboundLaneData>> { - match self.cached_data { - Some(ref data) => data.clone(), - None => { - let data: InboundLaneData>> = - InboundLanes::::get(self.lane_id).into(); - self.cached_data = Some(data.clone()); - data - }, - } - } - - fn set_data(&mut self, data: InboundLaneData>>) { - self.cached_data = Some(data.clone()); - InboundLanes::::insert(self.lane_id, StoredInboundLaneData::(data)) - } -} - -/// Runtime outbound lane storage. -struct RuntimeOutboundLaneStorage { - lane_id: LaneId, - _phantom: PhantomData<(T, I)>, -} - -impl, I: 'static> OutboundLaneStorage for RuntimeOutboundLaneStorage { - type StoredMessagePayload = StoredMessagePayload; - - fn id(&self) -> LaneId { - self.lane_id - } - - fn data(&self) -> OutboundLaneData { - OutboundLanes::::get(self.lane_id) - } - - fn set_data(&mut self, data: OutboundLaneData) { - OutboundLanes::::insert(self.lane_id, data) - } - - #[cfg(test)] - fn message(&self, nonce: &MessageNonce) -> Option { - OutboundMessages::::get(MessageKey { lane_id: self.lane_id, nonce: *nonce }) - } - - fn save_message(&mut self, nonce: MessageNonce, message_payload: Self::StoredMessagePayload) { - OutboundMessages::::insert( - MessageKey { lane_id: self.lane_id, nonce }, - message_payload, - ); - } - - fn remove_message(&mut self, nonce: &MessageNonce) { - OutboundMessages::::remove(MessageKey { lane_id: self.lane_id, nonce: *nonce }); - } +/// Creates new outbound lane object, backed by runtime storage. +fn any_state_outbound_lane, I: 'static>( + lane_id: T::LaneId, +) -> Result>, Error> { + LanesManager::::new() + .any_state_outbound_lane(lane_id) + .map_err(Error::LanesManager) } /// Verify messages proof and return proved messages with decoded payload. fn verify_and_decode_messages_proof, I: 'static>( - proof: FromBridgedChainMessagesProof>>, + proof: FromBridgedChainMessagesProof>, T::LaneId>, messages_count: u32, -) -> Result>, VerificationError> { +) -> Result< + ProvedMessages>, + VerificationError, +> { // `receive_messages_proof` weight formula and `MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX` // check guarantees that the `message_count` is sane and Vec may be allocated. // (tx with too many messages will either be rejected from the pool, or will fail earlier) - proofs::verify_messages_proof::(proof, messages_count).map(|messages_by_lane| { - messages_by_lane - .into_iter() - .map(|(lane, lane_data)| { - ( - lane, - ProvedLaneMessages { - lane_state: lane_data.lane_state, - messages: lane_data.messages.into_iter().map(Into::into).collect(), - }, - ) - }) - .collect() + proofs::verify_messages_proof::(proof, messages_count).map(|(lane, lane_data)| { + ( + lane, + ProvedLaneMessages { + lane_state: lane_data.lane_state, + messages: lane_data.messages.into_iter().map(Into::into).collect(), + }, + ) }) } diff --git a/bridges/modules/messages/src/migration.rs b/bridges/modules/messages/src/migration.rs new file mode 100644 index 000000000000..dc9a8119079e --- /dev/null +++ b/bridges/modules/messages/src/migration.rs @@ -0,0 +1,146 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! A module that is responsible for migration of storage. + +use crate::{Config, Pallet}; +use frame_support::{ + traits::{Get, StorageVersion}, + weights::Weight, +}; + +/// The in-code storage version. +pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + +/// This module contains data structures that are valid for the initial state of `0`. +/// (used with v1 migration). +pub mod v0 { + use super::Config; + use crate::BridgedChainOf; + use bp_messages::{MessageNonce, UnrewardedRelayer}; + use bp_runtime::AccountIdOf; + use codec::{Decode, Encode}; + use sp_std::collections::vec_deque::VecDeque; + + #[derive(Encode, Decode, Clone, PartialEq, Eq)] + pub(crate) struct StoredInboundLaneData, I: 'static>( + pub(crate) InboundLaneData>>, + ); + #[derive(Encode, Decode, Clone, PartialEq, Eq)] + pub(crate) struct InboundLaneData { + pub(crate) relayers: VecDeque>, + pub(crate) last_confirmed_nonce: MessageNonce, + } + #[derive(Encode, Decode, Clone, PartialEq, Eq)] + pub(crate) struct OutboundLaneData { + pub(crate) oldest_unpruned_nonce: MessageNonce, + pub(crate) latest_received_nonce: MessageNonce, + pub(crate) latest_generated_nonce: MessageNonce, + } +} + +/// This migration to `1` updates the metadata of `InboundLanes` and `OutboundLanes` to the new +/// structures. +pub mod v1 { + use super::*; + use crate::{ + InboundLaneData, InboundLanes, OutboundLaneData, OutboundLanes, StoredInboundLaneData, + }; + use bp_messages::LaneState; + use frame_support::traits::UncheckedOnRuntimeUpgrade; + use sp_std::marker::PhantomData; + + /// Migrates the pallet storage to v1. + pub struct UncheckedMigrationV0ToV1(PhantomData<(T, I)>); + + impl, I: 'static> UncheckedOnRuntimeUpgrade for UncheckedMigrationV0ToV1 { + fn on_runtime_upgrade() -> Weight { + let mut weight = T::DbWeight::get().reads(1); + + // `InboundLanes` - add state to the old structs + let translate_inbound = + |pre: v0::StoredInboundLaneData| -> Option> { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + Some(v1::StoredInboundLaneData(v1::InboundLaneData { + state: LaneState::Opened, + relayers: pre.0.relayers, + last_confirmed_nonce: pre.0.last_confirmed_nonce, + })) + }; + InboundLanes::::translate_values(translate_inbound); + + // `OutboundLanes` - add state to the old structs + let translate_outbound = |pre: v0::OutboundLaneData| -> Option { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + Some(v1::OutboundLaneData { + state: LaneState::Opened, + oldest_unpruned_nonce: pre.oldest_unpruned_nonce, + latest_received_nonce: pre.latest_received_nonce, + latest_generated_nonce: pre.latest_generated_nonce, + }) + }; + OutboundLanes::::translate_values(translate_outbound); + + weight + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::DispatchError> { + use codec::Encode; + + let number_of_inbound_to_migrate = InboundLanes::::iter_keys().count(); + let number_of_outbound_to_migrate = OutboundLanes::::iter_keys().count(); + Ok((number_of_inbound_to_migrate as u32, number_of_outbound_to_migrate as u32).encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: sp_std::vec::Vec) -> Result<(), sp_runtime::DispatchError> { + use codec::Decode; + const LOG_TARGET: &str = "runtime::bridge-messages-migration"; + + let (number_of_inbound_to_migrate, number_of_outbound_to_migrate): (u32, u32) = + Decode::decode(&mut &state[..]).unwrap(); + let number_of_inbound = InboundLanes::::iter_keys().count(); + let number_of_outbound = OutboundLanes::::iter_keys().count(); + + log::info!(target: LOG_TARGET, "post-upgrade expects '{number_of_inbound_to_migrate}' inbound lanes to have been migrated."); + log::info!(target: LOG_TARGET, "post-upgrade expects '{number_of_outbound_to_migrate}' outbound lanes to have been migrated."); + + frame_support::ensure!( + number_of_inbound_to_migrate as usize == number_of_inbound, + "must migrate all `InboundLanes`." + ); + frame_support::ensure!( + number_of_outbound_to_migrate as usize == number_of_outbound, + "must migrate all `OutboundLanes`." + ); + + log::info!(target: LOG_TARGET, "migrated all."); + Ok(()) + } + } + + /// [`UncheckedMigrationV0ToV1`] wrapped in a + /// [`VersionedMigration`](frame_support::migrations::VersionedMigration), ensuring the + /// migration is only performed when on-chain version is 0. + pub type MigrationToV1 = frame_support::migrations::VersionedMigration< + 0, + 1, + UncheckedMigrationV0ToV1, + Pallet, + ::DbWeight, + >; +} diff --git a/bridges/modules/messages/src/outbound_lane.rs b/bridges/modules/messages/src/outbound_lane.rs index fcdddf199dc6..c72713e7455a 100644 --- a/bridges/modules/messages/src/outbound_lane.rs +++ b/bridges/modules/messages/src/outbound_lane.rs @@ -19,24 +19,24 @@ use crate::{Config, LOG_TARGET}; use bp_messages::{ - ChainWithMessages, DeliveredMessages, LaneId, MessageNonce, OutboundLaneData, UnrewardedRelayer, + ChainWithMessages, DeliveredMessages, LaneState, MessageNonce, OutboundLaneData, + UnrewardedRelayer, }; use codec::{Decode, Encode}; -use frame_support::{ - traits::Get, - weights::{RuntimeDbWeight, Weight}, - BoundedVec, PalletError, -}; +use frame_support::{traits::Get, BoundedVec, PalletError}; use scale_info::TypeInfo; -use sp_runtime::{traits::Zero, RuntimeDebug}; -use sp_std::{collections::vec_deque::VecDeque, marker::PhantomData}; +use sp_runtime::RuntimeDebug; +use sp_std::{collections::vec_deque::VecDeque, marker::PhantomData, ops::RangeInclusive}; /// Outbound lane storage. pub trait OutboundLaneStorage { + /// Stored message payload type. type StoredMessagePayload; + /// Lane identifier type. + type LaneId: Encode; /// Lane id. - fn id(&self) -> LaneId; + fn id(&self) -> Self::LaneId; /// Get lane data from the storage. fn data(&self) -> OutboundLaneData; /// Update lane data in the storage. @@ -48,6 +48,8 @@ pub trait OutboundLaneStorage { fn save_message(&mut self, nonce: MessageNonce, message_payload: Self::StoredMessagePayload); /// Remove outbound message from the storage. fn remove_message(&mut self, nonce: &MessageNonce); + /// Purge lane data from the storage. + fn purge(self); } /// Limit for the `StoredMessagePayload` vector. @@ -79,6 +81,7 @@ pub enum ReceptionConfirmationError { } /// Outbound messages lane. +#[derive(Debug, PartialEq, Eq)] pub struct OutboundLane { storage: S, } @@ -94,6 +97,24 @@ impl OutboundLane { self.storage.data() } + /// Get lane state. + pub fn state(&self) -> LaneState { + self.storage.data().state + } + + /// Set lane state. + pub fn set_state(&mut self, state: LaneState) { + let mut data = self.storage.data(); + data.state = state; + self.storage.set_data(data); + } + + /// Return nonces of all currently queued messages. + pub fn queued_messages(&self) -> RangeInclusive { + let data = self.storage.data(); + data.oldest_unpruned_nonce..=data.latest_generated_nonce + } + /// Send message over lane. /// /// Returns new message nonce. @@ -143,40 +164,29 @@ impl OutboundLane { ensure_unrewarded_relayers_are_correct(confirmed_messages.end, relayers)?; + // prune all confirmed messages + for nonce in confirmed_messages.begin..=confirmed_messages.end { + self.storage.remove_message(&nonce); + } + data.latest_received_nonce = confirmed_messages.end; + data.oldest_unpruned_nonce = data.latest_received_nonce.saturating_add(1); self.storage.set_data(data); Ok(Some(confirmed_messages)) } - /// Prune at most `max_messages_to_prune` already received messages. - /// - /// Returns weight, consumed by messages pruning and lane state update. - pub fn prune_messages( - &mut self, - db_weight: RuntimeDbWeight, - mut remaining_weight: Weight, - ) -> Weight { - let write_weight = db_weight.writes(1); - let two_writes_weight = write_weight + write_weight; - let mut spent_weight = Weight::zero(); + /// Remove message from the storage. Doesn't perform any checks. + pub fn remove_oldest_unpruned_message(&mut self) { let mut data = self.storage.data(); - while remaining_weight.all_gte(two_writes_weight) && - data.oldest_unpruned_nonce <= data.latest_received_nonce - { - self.storage.remove_message(&data.oldest_unpruned_nonce); - - spent_weight += write_weight; - remaining_weight -= write_weight; - data.oldest_unpruned_nonce += 1; - } - - if !spent_weight.is_zero() { - spent_weight += write_weight; - self.storage.set_data(data); - } + self.storage.remove_message(&data.oldest_unpruned_nonce); + data.oldest_unpruned_nonce += 1; + self.storage.set_data(data); + } - spent_weight + /// Purge lane state from the storage. + pub fn purge(self) { + self.storage.purge() } } @@ -215,13 +225,12 @@ fn ensure_unrewarded_relayers_are_correct( mod tests { use super::*; use crate::{ - outbound_lane, + active_outbound_lane, tests::mock::{ - outbound_message_data, run_test, unrewarded_relayer, TestRelayer, TestRuntime, - REGULAR_PAYLOAD, TEST_LANE_ID, + outbound_message_data, run_test, test_lane_id, unrewarded_relayer, TestRelayer, + TestRuntime, REGULAR_PAYLOAD, }, }; - use frame_support::weights::constants::RocksDbWeight; use sp_std::ops::RangeInclusive; fn unrewarded_relayers( @@ -241,7 +250,7 @@ mod tests { relayers: &VecDeque>, ) -> Result, ReceptionConfirmationError> { run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID); + let mut lane = active_outbound_lane::(test_lane_id()).unwrap(); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); @@ -257,7 +266,7 @@ mod tests { #[test] fn send_message_works() { run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID); + let mut lane = active_outbound_lane::(test_lane_id()).unwrap(); assert_eq!(lane.storage.data().latest_generated_nonce, 0); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 1); assert!(lane.storage.message(&1).is_some()); @@ -268,7 +277,7 @@ mod tests { #[test] fn confirm_delivery_works() { run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID); + let mut lane = active_outbound_lane::(test_lane_id()).unwrap(); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 1); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 2); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 3); @@ -281,14 +290,14 @@ mod tests { ); assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 3); - assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 4); }); } #[test] fn confirm_partial_delivery_works() { run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID); + let mut lane = active_outbound_lane::(test_lane_id()).unwrap(); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 1); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 2); assert_eq!(lane.send_message(outbound_message_data(REGULAR_PAYLOAD)), 3); @@ -302,7 +311,7 @@ mod tests { ); assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 2); - assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 3); assert_eq!( lane.confirm_delivery(3, 3, &unrewarded_relayers(3..=3)), @@ -310,14 +319,14 @@ mod tests { ); assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 3); - assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 4); }); } #[test] fn confirm_delivery_rejects_nonce_lesser_than_latest_received() { run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID); + let mut lane = active_outbound_lane::(test_lane_id()).unwrap(); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); @@ -331,12 +340,12 @@ mod tests { assert_eq!(lane.confirm_delivery(3, 3, &unrewarded_relayers(1..=3)), Ok(None),); assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 3); - assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 4); assert_eq!(lane.confirm_delivery(1, 2, &unrewarded_relayers(1..=1)), Ok(None),); assert_eq!(lane.storage.data().latest_generated_nonce, 3); assert_eq!(lane.storage.data().latest_received_nonce, 3); - assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); + assert_eq!(lane.storage.data().oldest_unpruned_nonce, 4); }); } @@ -394,61 +403,10 @@ mod tests { ); } - #[test] - fn prune_messages_works() { - run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID); - // when lane is empty, nothing is pruned - assert_eq!( - lane.prune_messages(RocksDbWeight::get(), RocksDbWeight::get().writes(101)), - Weight::zero() - ); - assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); - // when nothing is confirmed, nothing is pruned - lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); - lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); - lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); - assert!(lane.storage.message(&1).is_some()); - assert!(lane.storage.message(&2).is_some()); - assert!(lane.storage.message(&3).is_some()); - assert_eq!( - lane.prune_messages(RocksDbWeight::get(), RocksDbWeight::get().writes(101)), - Weight::zero() - ); - assert_eq!(lane.storage.data().oldest_unpruned_nonce, 1); - // after confirmation, some messages are received - assert_eq!( - lane.confirm_delivery(2, 2, &unrewarded_relayers(1..=2)), - Ok(Some(delivered_messages(1..=2))), - ); - assert_eq!( - lane.prune_messages(RocksDbWeight::get(), RocksDbWeight::get().writes(101)), - RocksDbWeight::get().writes(3), - ); - assert!(lane.storage.message(&1).is_none()); - assert!(lane.storage.message(&2).is_none()); - assert!(lane.storage.message(&3).is_some()); - assert_eq!(lane.storage.data().oldest_unpruned_nonce, 3); - // after last message is confirmed, everything is pruned - assert_eq!( - lane.confirm_delivery(1, 3, &unrewarded_relayers(3..=3)), - Ok(Some(delivered_messages(3..=3))), - ); - assert_eq!( - lane.prune_messages(RocksDbWeight::get(), RocksDbWeight::get().writes(101)), - RocksDbWeight::get().writes(2), - ); - assert!(lane.storage.message(&1).is_none()); - assert!(lane.storage.message(&2).is_none()); - assert!(lane.storage.message(&3).is_none()); - assert_eq!(lane.storage.data().oldest_unpruned_nonce, 4); - }); - } - #[test] fn confirm_delivery_detects_when_more_than_expected_messages_are_confirmed() { run_test(|| { - let mut lane = outbound_lane::(TEST_LANE_ID); + let mut lane = active_outbound_lane::(test_lane_id()).unwrap(); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); lane.send_message(outbound_message_data(REGULAR_PAYLOAD)); diff --git a/bridges/modules/messages/src/proofs.rs b/bridges/modules/messages/src/proofs.rs index 18367029d72c..dcd642341d77 100644 --- a/bridges/modules/messages/src/proofs.rs +++ b/bridges/modules/messages/src/proofs.rs @@ -22,7 +22,7 @@ use bp_header_chain::{HeaderChain, HeaderChainError}; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, target_chain::{FromBridgedChainMessagesProof, ProvedLaneMessages, ProvedMessages}, - ChainWithMessages, InboundLaneData, LaneId, Message, MessageKey, MessageNonce, MessagePayload, + ChainWithMessages, InboundLaneData, Message, MessageKey, MessageNonce, MessagePayload, OutboundLaneData, VerificationError, }; use bp_runtime::{ @@ -32,8 +32,8 @@ use codec::Decode; use sp_std::vec::Vec; /// 'Parsed' message delivery proof - inbound lane id and its state. -pub(crate) type ParsedMessagesDeliveryProofFromBridgedChain = - (LaneId, InboundLaneData<::AccountId>); +pub(crate) type ParsedMessagesDeliveryProofFromBridgedChain = + (>::LaneId, InboundLaneData<::AccountId>); /// Verify proof of Bridged -> This chain messages. /// @@ -44,9 +44,9 @@ pub(crate) type ParsedMessagesDeliveryProofFromBridgedChain = /// outside of this function. This function only verifies that the proof declares exactly /// `messages_count` messages. pub fn verify_messages_proof, I: 'static>( - proof: FromBridgedChainMessagesProof>>, + proof: FromBridgedChainMessagesProof>, T::LaneId>, messages_count: u32, -) -> Result, VerificationError> { +) -> Result>, VerificationError> { let FromBridgedChainMessagesProof { bridged_header_hash, storage_proof, @@ -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) } @@ -98,17 +98,13 @@ pub fn verify_messages_proof, I: 'static>( // Check that the storage proof doesn't have any untouched keys. parser.ensure_no_unused_keys().map_err(VerificationError::StorageProof)?; - // We only support single lane messages in this generated_schema - let mut proved_messages = ProvedMessages::new(); - proved_messages.insert(lane, proved_lane_messages); - - Ok(proved_messages) + Ok((lane, proved_lane_messages)) } /// Verify proof of This -> Bridged chain messages delivery. pub fn verify_messages_delivery_proof, I: 'static>( - proof: FromBridgedChainMessagesDeliveryProof>>, -) -> Result, VerificationError> { + proof: FromBridgedChainMessagesDeliveryProof>, T::LaneId>, +) -> Result, VerificationError> { let FromBridgedChainMessagesDeliveryProof { bridged_header_hash, storage_proof, lane } = proof; let mut parser: MessagesStorageProofAdapter = MessagesStorageProofAdapter::try_new_with_verified_storage_proof( @@ -147,7 +143,7 @@ trait StorageProofAdapter, I: 'static> { fn read_and_decode_outbound_lane_data( &mut self, - lane_id: &LaneId, + lane_id: &T::LaneId, ) -> Result, StorageProofError> { let storage_outbound_lane_data_key = bp_messages::storage_keys::outbound_lane_data_key( T::ThisChain::WITH_CHAIN_MESSAGES_PALLET_NAME, @@ -158,7 +154,7 @@ trait StorageProofAdapter, I: 'static> { fn read_and_decode_message_payload( &mut self, - message_key: &MessageKey, + message_key: &MessageKey, ) -> Result { let storage_message_key = bp_messages::storage_keys::message_key( T::ThisChain::WITH_CHAIN_MESSAGES_PALLET_NAME, @@ -220,7 +216,8 @@ mod tests { mock::*, }; - use bp_header_chain::StoredHeaderDataBuilder; + use bp_header_chain::{HeaderChainError, StoredHeaderDataBuilder}; + use bp_messages::LaneState; use bp_runtime::{HeaderId, StorageProofError}; use codec::Encode; use sp_runtime::traits::Header; @@ -232,19 +229,20 @@ mod tests { encode_outbound_lane_data: impl Fn(&OutboundLaneData) -> Vec, add_duplicate_key: bool, add_unused_key: bool, - test: impl Fn(FromBridgedChainMessagesProof) -> R, + test: impl Fn(FromBridgedChainMessagesProof) -> R, ) -> R { - let (state_root, storage_proof) = prepare_messages_storage_proof::( - TEST_LANE_ID, - 1..=nonces_end, - outbound_lane_data, - bp_runtime::UnverifiedStorageProofParams::default(), - generate_dummy_message, - encode_message, - encode_outbound_lane_data, - add_duplicate_key, - add_unused_key, - ); + let (state_root, storage_proof) = + prepare_messages_storage_proof::( + test_lane_id(), + 1..=nonces_end, + outbound_lane_data, + bp_runtime::UnverifiedStorageProofParams::default(), + generate_dummy_message, + encode_message, + encode_outbound_lane_data, + add_duplicate_key, + add_unused_key, + ); sp_io::TestExternalities::new(Default::default()).execute_with(move || { let bridged_header = BridgedChainHeader::new( @@ -267,7 +265,7 @@ mod tests { test(FromBridgedChainMessagesProof { bridged_header_hash, storage_proof, - lane: TEST_LANE_ID, + lane: test_lane_id(), nonces_start: 1, nonces_end, }) @@ -440,6 +438,7 @@ mod tests { using_messages_proof( 10, Some(OutboundLaneData { + state: LaneState::Opened, oldest_unpruned_nonce: 1, latest_received_nonce: 1, latest_generated_nonce: 1, @@ -480,6 +479,7 @@ mod tests { using_messages_proof( 0, Some(OutboundLaneData { + state: LaneState::Opened, oldest_unpruned_nonce: 1, latest_received_nonce: 1, latest_generated_nonce: 1, @@ -490,19 +490,18 @@ mod tests { false, |proof| verify_messages_proof::(proof, 0), ), - Ok(vec![( - TEST_LANE_ID, + Ok(( + test_lane_id(), ProvedLaneMessages { lane_state: Some(OutboundLaneData { + state: LaneState::Opened, oldest_unpruned_nonce: 1, latest_received_nonce: 1, latest_generated_nonce: 1, }), messages: Vec::new(), }, - )] - .into_iter() - .collect()), + )), ); } @@ -512,6 +511,7 @@ mod tests { using_messages_proof( 1, Some(OutboundLaneData { + state: LaneState::Opened, oldest_unpruned_nonce: 1, latest_received_nonce: 1, latest_generated_nonce: 1, @@ -522,22 +522,21 @@ mod tests { false, |proof| verify_messages_proof::(proof, 1), ), - Ok(vec![( - TEST_LANE_ID, + Ok(( + test_lane_id(), ProvedLaneMessages { lane_state: Some(OutboundLaneData { + state: LaneState::Opened, oldest_unpruned_nonce: 1, latest_received_nonce: 1, latest_generated_nonce: 1, }), messages: vec![Message { - key: MessageKey { lane_id: TEST_LANE_ID, nonce: 1 }, + key: MessageKey { lane_id: test_lane_id(), nonce: 1 }, payload: vec![42], }], }, - )] - .into_iter() - .collect()), + )) ); } diff --git a/bridges/modules/messages/src/tests/messages_generation.rs b/bridges/modules/messages/src/tests/messages_generation.rs index 6c4867fa6de3..00b1d3eefe43 100644 --- a/bridges/modules/messages/src/tests/messages_generation.rs +++ b/bridges/modules/messages/src/tests/messages_generation.rs @@ -17,8 +17,8 @@ //! Helpers for generating message storage proofs, that are used by tests and by benchmarks. use bp_messages::{ - storage_keys, ChainWithMessages, InboundLaneData, LaneId, MessageKey, MessageNonce, - MessagePayload, OutboundLaneData, + storage_keys, ChainWithMessages, InboundLaneData, MessageKey, MessageNonce, MessagePayload, + OutboundLaneData, }; use bp_runtime::{ grow_storage_value, record_all_trie_keys, AccountIdOf, Chain, HashOf, HasherOf, @@ -47,7 +47,11 @@ pub fn encode_lane_data(d: &OutboundLaneData) -> Vec { /// /// Returns state trie root and nodes with prepared messages. #[allow(clippy::too_many_arguments)] -pub fn prepare_messages_storage_proof( +pub fn prepare_messages_storage_proof< + BridgedChain: Chain, + ThisChain: ChainWithMessages, + LaneId: Encode + Copy, +>( lane: LaneId, message_nonces: RangeInclusive, outbound_lane_data: Option, @@ -132,7 +136,11 @@ where /// Prepare storage proof of given messages delivery. /// /// Returns state trie root and nodes with prepared messages. -pub fn prepare_message_delivery_storage_proof( +pub fn prepare_message_delivery_storage_proof< + BridgedChain: Chain, + ThisChain: ChainWithMessages, + LaneId: Encode, +>( lane: LaneId, inbound_lane_data: InboundLaneData>, proof_params: UnverifiedStorageProofParams, diff --git a/bridges/modules/messages/src/tests/mock.rs b/bridges/modules/messages/src/tests/mock.rs index ffdd536830b5..2935ebd69610 100644 --- a/bridges/modules/messages/src/tests/mock.rs +++ b/bridges/modules/messages/src/tests/mock.rs @@ -35,15 +35,16 @@ use bp_messages::{ DeliveryPayments, DispatchMessage, DispatchMessageData, FromBridgedChainMessagesProof, MessageDispatch, }, - ChainWithMessages, DeliveredMessages, InboundLaneData, LaneId, Message, MessageKey, - MessageNonce, OutboundLaneData, UnrewardedRelayer, UnrewardedRelayersState, + ChainWithMessages, DeliveredMessages, HashedLaneId, InboundLaneData, LaneIdType, LaneState, + Message, MessageKey, MessageNonce, OutboundLaneData, UnrewardedRelayer, + UnrewardedRelayersState, }; use bp_runtime::{ messages::MessageDispatchResult, Chain, ChainId, Size, UnverifiedStorageProofParams, }; use codec::{Decode, Encode}; use frame_support::{ - derive_impl, parameter_types, + derive_impl, weights::{constants::RocksDbWeight, Weight}, }; use scale_info::TypeInfo; @@ -183,12 +184,6 @@ impl pallet_bridge_grandpa::Config for TestRuntime { type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight; } -parameter_types! { - pub const MaxMessagesToPruneAtOnce: u64 = 10; - pub const TestBridgedChainId: bp_runtime::ChainId = *b"test"; - pub const ActiveOutboundLanes: &'static [LaneId] = &[TEST_LANE_ID, TEST_LANE_ID_2]; -} - /// weights of messages pallet calls we use in tests. pub type TestWeightInfo = (); @@ -200,13 +195,11 @@ impl Config for TestRuntime { type BridgedChain = BridgedChain; type BridgedHeaderChain = BridgedChainGrandpa; - type ActiveOutboundLanes = ActiveOutboundLanes; - type OutboundPayload = TestPayload; - type InboundPayload = TestPayload; - type DeliveryPayments = TestDeliveryPayments; + type LaneId = TestLaneIdType; + type DeliveryPayments = TestDeliveryPayments; type DeliveryConfirmationPayments = TestDeliveryConfirmationPayments; type OnMessagesDelivered = TestOnMessagesDelivered; @@ -215,17 +208,17 @@ impl Config for TestRuntime { #[cfg(feature = "runtime-benchmarks")] impl crate::benchmarking::Config<()> for TestRuntime { - fn bench_lane_id() -> LaneId { - TEST_LANE_ID + fn bench_lane_id() -> Self::LaneId { + test_lane_id() } fn prepare_message_proof( - params: crate::benchmarking::MessageProofParams, - ) -> (FromBridgedChainMessagesProof, Weight) { + params: crate::benchmarking::MessageProofParams, + ) -> (FromBridgedChainMessagesProof, Weight) { 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(), @@ -236,8 +229,8 @@ impl crate::benchmarking::Config<()> for TestRuntime { } fn prepare_message_delivery_proof( - params: crate::benchmarking::MessageDeliveryProofParams, - ) -> FromBridgedChainMessagesDeliveryProof { + params: crate::benchmarking::MessageDeliveryProofParams, + ) -> FromBridgedChainMessagesDeliveryProof { // in mock run we only care about benchmarks correctness, not the benchmark results // => ignore size related arguments prepare_messages_delivery_proof(params.lane, params.inbound_lane_data) @@ -266,14 +259,22 @@ pub const TEST_RELAYER_B: AccountId = 101; /// Account id of additional test relayer - C. pub const TEST_RELAYER_C: AccountId = 102; +/// Lane identifier type used for tests. +pub type TestLaneIdType = HashedLaneId; /// Lane that we're using in tests. -pub const TEST_LANE_ID: LaneId = LaneId([0, 0, 0, 1]); +pub fn test_lane_id() -> TestLaneIdType { + TestLaneIdType::try_new(1, 2).unwrap() +} -/// Secondary lane that we're using in tests. -pub const TEST_LANE_ID_2: LaneId = LaneId([0, 0, 0, 2]); +/// Lane that is completely unknown to our runtime. +pub fn unknown_lane_id() -> TestLaneIdType { + TestLaneIdType::try_new(1, 3).unwrap() +} -/// Inactive outbound lane. -pub const TEST_LANE_ID_3: LaneId = LaneId([0, 0, 0, 3]); +/// Lane that is registered, but it is closed. +pub fn closed_lane_id() -> TestLaneIdType { + TestLaneIdType::try_new(1, 4).unwrap() +} /// Regular message payload. pub const REGULAR_PAYLOAD: TestPayload = message_payload(0, 50); @@ -318,11 +319,11 @@ impl TestDeliveryConfirmationPayments { } } -impl DeliveryConfirmationPayments for TestDeliveryConfirmationPayments { +impl DeliveryConfirmationPayments for TestDeliveryConfirmationPayments { type Error = &'static str; fn pay_reward( - _lane_id: LaneId, + _lane_id: TestLaneIdType, messages_relayers: VecDeque>, _confirmation_relayer: &AccountId, received_range: &RangeInclusive, @@ -343,22 +344,33 @@ impl DeliveryConfirmationPayments for TestDeliveryConfirmationPayment pub struct TestMessageDispatch; impl TestMessageDispatch { - pub fn deactivate() { - frame_support::storage::unhashed::put(b"TestMessageDispatch.IsCongested", &true) + pub fn deactivate(lane: TestLaneIdType) { + // "enqueue" enough (to deactivate dispatcher) messages at dispatcher + let latest_received_nonce = BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX + 1; + for _ in 1..=latest_received_nonce { + Self::emulate_enqueued_message(lane); + } + } + + pub fn emulate_enqueued_message(lane: TestLaneIdType) { + let key = (b"dispatched", lane).encode(); + let dispatched = frame_support::storage::unhashed::get_or_default::(&key[..]); + frame_support::storage::unhashed::put(&key[..], &(dispatched + 1)); } } impl MessageDispatch for TestMessageDispatch { type DispatchPayload = TestPayload; type DispatchLevelResult = TestDispatchLevelResult; + type LaneId = TestLaneIdType; - fn is_active() -> bool { - !frame_support::storage::unhashed::get_or_default::( - b"TestMessageDispatch.IsCongested", - ) + fn is_active(lane: Self::LaneId) -> bool { + frame_support::storage::unhashed::get_or_default::( + &(b"dispatched", lane).encode()[..], + ) <= BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX } - fn dispatch_weight(message: &mut DispatchMessage) -> Weight { + fn dispatch_weight(message: &mut DispatchMessage) -> Weight { match message.data.payload.as_ref() { Ok(payload) => payload.declared_weight, Err(_) => Weight::zero(), @@ -366,10 +378,13 @@ impl MessageDispatch for TestMessageDispatch { } fn dispatch( - message: DispatchMessage, + message: DispatchMessage, ) -> MessageDispatchResult { match message.data.payload.as_ref() { - Ok(payload) => payload.dispatch_result.clone(), + Ok(payload) => { + Self::emulate_enqueued_message(message.key.lane_id); + payload.dispatch_result.clone() + }, Err(_) => dispatch_result(0), } } @@ -379,13 +394,13 @@ impl MessageDispatch for TestMessageDispatch { pub struct TestOnMessagesDelivered; impl TestOnMessagesDelivered { - pub fn call_arguments() -> Option<(LaneId, MessageNonce)> { + pub fn call_arguments() -> Option<(TestLaneIdType, MessageNonce)> { frame_support::storage::unhashed::get(b"TestOnMessagesDelivered.OnMessagesDelivered") } } -impl OnMessagesDelivered for TestOnMessagesDelivered { - fn on_messages_delivered(lane: LaneId, enqueued_messages: MessageNonce) { +impl OnMessagesDelivered for TestOnMessagesDelivered { + fn on_messages_delivered(lane: TestLaneIdType, enqueued_messages: MessageNonce) { frame_support::storage::unhashed::put( b"TestOnMessagesDelivered.OnMessagesDelivered", &(lane, enqueued_messages), @@ -394,8 +409,8 @@ impl OnMessagesDelivered for TestOnMessagesDelivered { } /// Return test lane message with given nonce and payload. -pub fn message(nonce: MessageNonce, payload: TestPayload) -> Message { - Message { key: MessageKey { lane_id: TEST_LANE_ID, nonce }, payload: payload.encode() } +pub fn message(nonce: MessageNonce, payload: TestPayload) -> Message { + Message { key: MessageKey { lane_id: test_lane_id(), nonce }, payload: payload.encode() } } /// Return valid outbound message data, constructed from given payload. @@ -438,8 +453,8 @@ pub fn unrewarded_relayer( } /// Returns unrewarded relayers state at given lane. -pub fn inbound_unrewarded_relayers_state(lane: bp_messages::LaneId) -> UnrewardedRelayersState { - let inbound_lane_data = crate::InboundLanes::::get(lane).0; +pub fn inbound_unrewarded_relayers_state(lane: TestLaneIdType) -> UnrewardedRelayersState { + let inbound_lane_data = crate::InboundLanes::::get(lane).unwrap().0; UnrewardedRelayersState::from(&inbound_lane_data) } @@ -454,7 +469,19 @@ pub fn new_test_ext() -> sp_io::TestExternalities { /// Run pallet test. pub fn run_test(test: impl FnOnce() -> T) -> T { - new_test_ext().execute_with(test) + new_test_ext().execute_with(|| { + crate::InboundLanes::::insert(test_lane_id(), InboundLaneData::opened()); + crate::OutboundLanes::::insert(test_lane_id(), OutboundLaneData::opened()); + crate::InboundLanes::::insert( + closed_lane_id(), + InboundLaneData { state: LaneState::Closed, ..Default::default() }, + ); + crate::OutboundLanes::::insert( + closed_lane_id(), + OutboundLaneData { state: LaneState::Closed, ..Default::default() }, + ); + test() + }) } /// Prepare valid storage proof for given messages and insert appropriate header to the @@ -463,24 +490,25 @@ pub fn run_test(test: impl FnOnce() -> T) -> T { /// Since this function changes the runtime storage, you can't "inline" it in the /// `asset_noop` macro calls. pub fn prepare_messages_proof( - messages: Vec, + messages: Vec>, outbound_lane_data: Option, -) -> Box> { +) -> Box> { // first - let's generate storage proof let lane = messages.first().unwrap().key.lane_id; let nonces_start = messages.first().unwrap().key.nonce; let nonces_end = messages.last().unwrap().key.nonce; - let (storage_root, storage_proof) = prepare_messages_storage_proof::( - TEST_LANE_ID, - nonces_start..=nonces_end, - outbound_lane_data, - UnverifiedStorageProofParams::default(), - |nonce| messages[(nonce - nonces_start) as usize].payload.clone(), - encode_all_messages, - encode_lane_data, - false, - false, - ); + let (storage_root, storage_proof) = + prepare_messages_storage_proof::( + lane, + nonces_start..=nonces_end, + outbound_lane_data, + UnverifiedStorageProofParams::default(), + |nonce| messages[(nonce - nonces_start) as usize].payload.clone(), + encode_all_messages, + encode_lane_data, + false, + false, + ); // let's now insert bridged chain header into the storage let bridged_header_hash = Default::default(); @@ -489,7 +517,7 @@ pub fn prepare_messages_proof( StoredHeaderData { number: 0, state_root: storage_root }, ); - Box::new(FromBridgedChainMessagesProof:: { + Box::new(FromBridgedChainMessagesProof:: { bridged_header_hash, storage_proof, lane, @@ -504,12 +532,12 @@ pub fn prepare_messages_proof( /// Since this function changes the runtime storage, you can't "inline" it in the /// `asset_noop` macro calls. pub fn prepare_messages_delivery_proof( - lane: LaneId, + lane: TestLaneIdType, inbound_lane_data: InboundLaneData, -) -> FromBridgedChainMessagesDeliveryProof { +) -> FromBridgedChainMessagesDeliveryProof { // first - let's generate storage proof let (storage_root, storage_proof) = - prepare_message_delivery_storage_proof::( + prepare_message_delivery_storage_proof::( lane, inbound_lane_data, UnverifiedStorageProofParams::default(), @@ -522,7 +550,7 @@ pub fn prepare_messages_delivery_proof( StoredHeaderData { number: 0, state_root: storage_root }, ); - FromBridgedChainMessagesDeliveryProof:: { + FromBridgedChainMessagesDeliveryProof:: { bridged_header_hash, storage_proof, lane, diff --git a/bridges/modules/messages/src/tests/pallet_tests.rs b/bridges/modules/messages/src/tests/pallet_tests.rs index 42e1042717de..9df103a7cf6f 100644 --- a/bridges/modules/messages/src/tests/pallet_tests.rs +++ b/bridges/modules/messages/src/tests/pallet_tests.rs @@ -17,20 +17,20 @@ //! Pallet-level tests. use crate::{ - outbound_lane, + active_outbound_lane, + lanes_manager::RuntimeInboundLaneStorage, outbound_lane::ReceptionConfirmationError, - tests::mock::{self, RuntimeEvent as TestEvent, *}, + tests::mock::{RuntimeEvent as TestEvent, *}, weights_ext::WeightInfoExt, - Call, Config, Error, Event, InboundLanes, MaybeOutboundLanesCount, OutboundLanes, - OutboundMessages, Pallet, PalletOperatingMode, PalletOwner, RuntimeInboundLaneStorage, - StoredInboundLaneData, + Call, Config, Error, Event, InboundLanes, LanesManagerError, OutboundLanes, OutboundMessages, + Pallet, PalletOperatingMode, PalletOwner, StoredInboundLaneData, }; use bp_messages::{ source_chain::{FromBridgedChainMessagesDeliveryProof, MessagesBridge}, - target_chain::FromBridgedChainMessagesProof, + target_chain::{FromBridgedChainMessagesProof, MessageDispatch}, BridgeMessagesCall, ChainWithMessages, DeliveredMessages, InboundLaneData, - InboundMessageDetails, LaneId, MessageKey, MessageNonce, MessagesOperatingMode, + InboundMessageDetails, LaneIdType, LaneState, MessageKey, MessageNonce, MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails, UnrewardedRelayer, UnrewardedRelayersState, VerificationError, }; @@ -38,25 +38,23 @@ use bp_runtime::{BasicOperatingMode, PreComputedSize, RangeInclusiveExt, Size}; use bp_test_utils::generate_owned_bridge_module_tests; use codec::Encode; use frame_support::{ - assert_noop, assert_ok, + assert_err, assert_noop, assert_ok, dispatch::Pays, storage::generator::{StorageMap, StorageValue}, - traits::Hooks, weights::Weight, }; use frame_system::{EventRecord, Pallet as System, Phase}; -use sp_core::Get; -use sp_runtime::DispatchError; +use sp_runtime::{BoundedVec, DispatchError}; fn get_ready_for_events() { System::::set_block_number(1); System::::reset_events(); } -fn send_regular_message(lane_id: LaneId) { +fn send_regular_message(lane_id: TestLaneIdType) { get_ready_for_events(); - let outbound_lane = outbound_lane::(lane_id); + let outbound_lane = active_outbound_lane::(lane_id).unwrap(); let message_nonce = outbound_lane.data().latest_generated_nonce + 1; let prev_enqueued_messages = outbound_lane.data().queued_messages().saturating_len(); let valid_message = Pallet::::validate_message(lane_id, ®ULAR_PAYLOAD) @@ -69,7 +67,10 @@ fn send_regular_message(lane_id: LaneId) { System::::events(), vec![EventRecord { phase: Phase::Initialization, - event: TestEvent::Messages(Event::MessageAccepted { lane_id, nonce: message_nonce }), + event: TestEvent::Messages(Event::MessageAccepted { + lane_id: lane_id.into(), + nonce: message_nonce + }), topics: vec![], }], ); @@ -82,8 +83,9 @@ fn receive_messages_delivery_proof() { assert_ok!(Pallet::::receive_messages_delivery_proof( RuntimeOrigin::signed(1), prepare_messages_delivery_proof( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { + state: LaneState::Opened, last_confirmed_nonce: 1, relayers: vec![UnrewardedRelayer { relayer: 0, @@ -99,13 +101,14 @@ fn receive_messages_delivery_proof() { last_delivered_nonce: 1, }, )); + assert_ok!(Pallet::::do_try_state()); assert_eq!( System::::events(), vec![EventRecord { phase: Phase::Initialization, event: TestEvent::Messages(Event::MessagesDelivered { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id().into(), messages: DeliveredMessages::new(1), }), topics: vec![], @@ -117,14 +120,14 @@ fn receive_messages_delivery_proof() { fn pallet_rejects_transactions_if_halted() { run_test(|| { // send message first to be able to check that delivery_proof fails later - send_regular_message(TEST_LANE_ID); + send_regular_message(test_lane_id()); PalletOperatingMode::::put(MessagesOperatingMode::Basic( BasicOperatingMode::Halted, )); assert_noop!( - Pallet::::validate_message(TEST_LANE_ID, ®ULAR_PAYLOAD), + Pallet::::validate_message(test_lane_id(), ®ULAR_PAYLOAD), Error::::NotOperatingNormally, ); @@ -141,8 +144,9 @@ fn pallet_rejects_transactions_if_halted() { ); let delivery_proof = prepare_messages_delivery_proof( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { + state: LaneState::Opened, last_confirmed_nonce: 1, relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)].into(), }, @@ -160,13 +164,14 @@ fn pallet_rejects_transactions_if_halted() { ), Error::::BridgeModule(bp_runtime::OwnedBridgeModuleError::Halted), ); + assert_ok!(Pallet::::do_try_state()); }); } #[test] fn receive_messages_fails_if_dispatcher_is_inactive() { run_test(|| { - TestMessageDispatch::deactivate(); + TestMessageDispatch::deactivate(test_lane_id()); let proof = prepare_messages_proof(vec![message(1, REGULAR_PAYLOAD)], None); assert_noop!( Pallet::::receive_messages_proof( @@ -176,7 +181,7 @@ fn receive_messages_fails_if_dispatcher_is_inactive() { 1, REGULAR_PAYLOAD.declared_weight, ), - Error::::MessageDispatchInactive, + Error::::LanesManager(LanesManagerError::LaneDispatcherInactive), ); }); } @@ -185,14 +190,14 @@ fn receive_messages_fails_if_dispatcher_is_inactive() { fn pallet_rejects_new_messages_in_rejecting_outbound_messages_operating_mode() { run_test(|| { // send message first to be able to check that delivery_proof fails later - send_regular_message(TEST_LANE_ID); + send_regular_message(test_lane_id()); PalletOperatingMode::::put( MessagesOperatingMode::RejectingOutboundMessages, ); assert_noop!( - Pallet::::validate_message(TEST_LANE_ID, ®ULAR_PAYLOAD), + Pallet::::validate_message(test_lane_id(), ®ULAR_PAYLOAD), Error::::NotOperatingNormally, ); @@ -207,8 +212,9 @@ fn pallet_rejects_new_messages_in_rejecting_outbound_messages_operating_mode() { assert_ok!(Pallet::::receive_messages_delivery_proof( RuntimeOrigin::signed(1), prepare_messages_delivery_proof( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { + state: LaneState::Opened, last_confirmed_nonce: 1, relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)].into(), }, @@ -220,13 +226,14 @@ fn pallet_rejects_new_messages_in_rejecting_outbound_messages_operating_mode() { last_delivered_nonce: 1, }, )); + assert_ok!(Pallet::::do_try_state()); }); } #[test] fn send_message_works() { run_test(|| { - send_regular_message(TEST_LANE_ID); + send_regular_message(test_lane_id()); }); } @@ -241,7 +248,7 @@ fn send_message_rejects_too_large_message() { .extra .extend_from_slice(&vec![0u8; max_outbound_payload_size as usize]); assert_noop!( - Pallet::::validate_message(TEST_LANE_ID, &message_payload.clone(),), + Pallet::::validate_message(test_lane_id(), &message_payload.clone(),), Error::::MessageRejectedByPallet(VerificationError::MessageTooLarge), ); @@ -252,7 +259,7 @@ fn send_message_rejects_too_large_message() { assert_eq!(message_payload.encoded_size() as u32, max_outbound_payload_size); let valid_message = - Pallet::::validate_message(TEST_LANE_ID, &message_payload) + Pallet::::validate_message(test_lane_id(), &message_payload) .expect("validate_message has failed"); Pallet::::send_message(valid_message); }) @@ -269,7 +276,13 @@ fn receive_messages_proof_works() { REGULAR_PAYLOAD.declared_weight, )); - assert_eq!(InboundLanes::::get(TEST_LANE_ID).0.last_delivered_nonce(), 1); + assert_eq!( + InboundLanes::::get(test_lane_id()) + .unwrap() + .0 + .last_delivered_nonce(), + 1 + ); assert!(TestDeliveryPayments::is_reward_paid(1)); }); @@ -280,8 +293,9 @@ fn receive_messages_proof_updates_confirmed_message_nonce() { run_test(|| { // say we have received 10 messages && last confirmed message is 8 InboundLanes::::insert( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { + state: LaneState::Opened, last_confirmed_nonce: 8, relayers: vec![ unrewarded_relayer(9, 9, TEST_RELAYER_A), @@ -291,7 +305,7 @@ fn receive_messages_proof_updates_confirmed_message_nonce() { }, ); assert_eq!( - inbound_unrewarded_relayers_state(TEST_LANE_ID), + inbound_unrewarded_relayers_state(test_lane_id()), UnrewardedRelayersState { unrewarded_relayer_entries: 2, messages_in_oldest_entry: 1, @@ -313,8 +327,9 @@ fn receive_messages_proof_updates_confirmed_message_nonce() { )); assert_eq!( - InboundLanes::::get(TEST_LANE_ID).0, + InboundLanes::::get(test_lane_id()).unwrap().0, InboundLaneData { + state: LaneState::Opened, last_confirmed_nonce: 9, relayers: vec![ unrewarded_relayer(10, 10, TEST_RELAYER_B), @@ -324,7 +339,7 @@ fn receive_messages_proof_updates_confirmed_message_nonce() { }, ); assert_eq!( - inbound_unrewarded_relayers_state(TEST_LANE_ID), + inbound_unrewarded_relayers_state(test_lane_id()), UnrewardedRelayersState { unrewarded_relayer_entries: 2, messages_in_oldest_entry: 1, @@ -335,6 +350,86 @@ fn receive_messages_proof_updates_confirmed_message_nonce() { }); } +#[test] +fn receive_messages_proof_fails_when_dispatcher_is_inactive() { + run_test(|| { + // "enqueue" enough (to deactivate dispatcher) messages at dispatcher + let latest_received_nonce = BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX + 1; + for _ in 1..=latest_received_nonce { + TestMessageDispatch::emulate_enqueued_message(test_lane_id()); + } + assert!(!TestMessageDispatch::is_active(test_lane_id())); + InboundLanes::::insert( + test_lane_id(), + InboundLaneData { + state: LaneState::Opened, + last_confirmed_nonce: latest_received_nonce, + relayers: vec![].into(), + }, + ); + + // try to delvier next message - it should fail because dispatcher is in "suspended" state + // at the beginning of the call + let messages_proof = + prepare_messages_proof(vec![message(latest_received_nonce + 1, REGULAR_PAYLOAD)], None); + assert_noop!( + Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + messages_proof, + 1, + REGULAR_PAYLOAD.declared_weight, + ), + Error::::LanesManager(LanesManagerError::LaneDispatcherInactive) + ); + assert!(!TestMessageDispatch::is_active(test_lane_id())); + }); +} + +#[test] +fn receive_messages_succeeds_when_dispatcher_becomes_inactive_in_the_middle_of_transaction() { + run_test(|| { + // "enqueue" enough (to deactivate dispatcher) messages at dispatcher + let latest_received_nonce = BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX / 2; + for _ in 1..=latest_received_nonce { + TestMessageDispatch::emulate_enqueued_message(test_lane_id()); + } + assert!(TestMessageDispatch::is_active(test_lane_id())); + InboundLanes::::insert( + test_lane_id(), + InboundLaneData { + state: LaneState::Opened, + last_confirmed_nonce: latest_received_nonce, + relayers: vec![].into(), + }, + ); + + // try to delvier next `BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX` messages + // - it will lead to dispatcher deactivation, but the transaction shall not fail and all + // messages must be delivered + let messages_begin = latest_received_nonce + 1; + let messages_end = + messages_begin + BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + let messages_range = messages_begin..messages_end; + let messages_count = BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + assert_ok!(Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + prepare_messages_proof( + messages_range.map(|nonce| message(nonce, REGULAR_PAYLOAD)).collect(), + None, + ), + messages_count as _, + REGULAR_PAYLOAD.declared_weight * messages_count, + ),); + assert_eq!( + inbound_unrewarded_relayers_state(test_lane_id()).last_delivered_nonce, + messages_end - 1, + ); + assert!(!TestMessageDispatch::is_active(test_lane_id())); + }); +} + #[test] fn receive_messages_proof_does_not_accept_message_if_dispatch_weight_is_not_enough() { run_test(|| { @@ -352,7 +447,10 @@ fn receive_messages_proof_does_not_accept_message_if_dispatch_weight_is_not_enou ), Error::::InsufficientDispatchWeight ); - assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 0); + assert_eq!( + InboundLanes::::get(test_lane_id()).unwrap().last_delivered_nonce(), + 0 + ); }); } @@ -395,22 +493,64 @@ fn receive_messages_proof_rejects_proof_with_too_many_messages() { #[test] fn receive_messages_delivery_proof_works() { run_test(|| { - send_regular_message(TEST_LANE_ID); + assert_eq!( + OutboundLanes::::get(test_lane_id()) + .unwrap() + .latest_received_nonce, + 0, + ); + assert_eq!( + OutboundLanes::::get(test_lane_id()) + .unwrap() + .oldest_unpruned_nonce, + 1, + ); + + send_regular_message(test_lane_id()); receive_messages_delivery_proof(); - assert_eq!(OutboundLanes::::get(TEST_LANE_ID).latest_received_nonce, 1,); + assert_eq!( + OutboundLanes::::get(test_lane_id()) + .unwrap() + .latest_received_nonce, + 1, + ); + assert_eq!( + OutboundLanes::::get(test_lane_id()) + .unwrap() + .oldest_unpruned_nonce, + 2, + ); + }); +} + +#[test] +fn receive_messages_delivery_proof_works_on_closed_outbound_lanes() { + run_test(|| { + send_regular_message(test_lane_id()); + active_outbound_lane::(test_lane_id()) + .unwrap() + .set_state(LaneState::Closed); + receive_messages_delivery_proof(); + + assert_eq!( + OutboundLanes::::get(test_lane_id()) + .unwrap() + .latest_received_nonce, + 1, + ); }); } #[test] fn receive_messages_delivery_proof_rewards_relayers() { run_test(|| { - send_regular_message(TEST_LANE_ID); - send_regular_message(TEST_LANE_ID); + send_regular_message(test_lane_id()); + send_regular_message(test_lane_id()); // this reports delivery of message 1 => reward is paid to TEST_RELAYER_A let single_message_delivery_proof = prepare_messages_delivery_proof( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)].into(), ..Default::default() @@ -428,6 +568,7 @@ fn receive_messages_delivery_proof_rewards_relayers() { }, ); assert_ok!(result); + assert_ok!(Pallet::::do_try_state()); assert_eq!( result.unwrap().actual_weight.unwrap(), TestWeightInfo::receive_messages_delivery_proof_weight( @@ -445,7 +586,7 @@ fn receive_messages_delivery_proof_rewards_relayers() { // this reports delivery of both message 1 and message 2 => reward is paid only to // TEST_RELAYER_B let two_messages_delivery_proof = prepare_messages_delivery_proof( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { relayers: vec![ unrewarded_relayer(1, 1, TEST_RELAYER_A), @@ -467,6 +608,7 @@ fn receive_messages_delivery_proof_rewards_relayers() { }, ); assert_ok!(result); + assert_ok!(Pallet::::do_try_state()); // even though the pre-dispatch weight was for two messages, the actual weight is // for single message only assert_eq!( @@ -482,15 +624,15 @@ fn receive_messages_delivery_proof_rewards_relayers() { ); assert!(!TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_A, 1)); assert!(TestDeliveryConfirmationPayments::is_reward_paid(TEST_RELAYER_B, 1)); - assert_eq!(TestOnMessagesDelivered::call_arguments(), Some((TEST_LANE_ID, 0))); + assert_eq!(TestOnMessagesDelivered::call_arguments(), Some((test_lane_id(), 0))); }); } #[test] fn receive_messages_delivery_proof_rejects_invalid_proof() { run_test(|| { - let mut proof = prepare_messages_delivery_proof(TEST_LANE_ID, Default::default()); - proof.lane = bp_messages::LaneId([42, 42, 42, 42]); + let mut proof = prepare_messages_delivery_proof(test_lane_id(), Default::default()); + proof.lane = TestLaneIdType::try_new(42, 84).unwrap(); assert_noop!( Pallet::::receive_messages_delivery_proof( @@ -508,7 +650,7 @@ fn receive_messages_delivery_proof_rejects_proof_if_declared_relayers_state_is_i run_test(|| { // when number of relayers entries is invalid let proof = prepare_messages_delivery_proof( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { relayers: vec![ unrewarded_relayer(1, 1, TEST_RELAYER_A), @@ -534,7 +676,7 @@ fn receive_messages_delivery_proof_rejects_proof_if_declared_relayers_state_is_i // when number of messages is invalid let proof = prepare_messages_delivery_proof( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { relayers: vec![ unrewarded_relayer(1, 1, TEST_RELAYER_A), @@ -560,7 +702,7 @@ fn receive_messages_delivery_proof_rejects_proof_if_declared_relayers_state_is_i // when last delivered nonce is invalid let proof = prepare_messages_delivery_proof( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { relayers: vec![ unrewarded_relayer(1, 1, TEST_RELAYER_A), @@ -601,7 +743,10 @@ fn receive_messages_accepts_single_message_with_invalid_payload() { * improperly encoded) */ ),); - assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 1,); + assert_eq!( + InboundLanes::::get(test_lane_id()).unwrap().last_delivered_nonce(), + 1, + ); }); } @@ -622,7 +767,10 @@ fn receive_messages_accepts_batch_with_message_with_invalid_payload() { REGULAR_PAYLOAD.declared_weight + REGULAR_PAYLOAD.declared_weight, ),); - assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 3,); + assert_eq!( + InboundLanes::::get(test_lane_id()).unwrap().last_delivered_nonce(), + 3, + ); }); } @@ -645,7 +793,10 @@ fn actual_dispatch_weight_does_not_overflow() { ), Error::::InsufficientDispatchWeight ); - assert_eq!(InboundLanes::::get(TEST_LANE_ID).last_delivered_nonce(), 0); + assert_eq!( + InboundLanes::::get(test_lane_id()).unwrap().last_delivered_nonce(), + 0 + ); }); } @@ -722,8 +873,9 @@ fn proof_size_refund_from_receive_messages_proof_works() { REGULAR_PAYLOAD.declared_weight, ); InboundLanes::::insert( - TEST_LANE_ID, + test_lane_id(), StoredInboundLaneData(InboundLaneData { + state: LaneState::Opened, relayers: vec![ UnrewardedRelayer { relayer: 42, @@ -750,8 +902,9 @@ fn proof_size_refund_from_receive_messages_proof_works() { // if count of unrewarded relayer entries is less than maximal, then some `proof_size` // must be refunded InboundLanes::::insert( - TEST_LANE_ID, + test_lane_id(), StoredInboundLaneData(InboundLaneData { + state: LaneState::Opened, relayers: vec![ UnrewardedRelayer { relayer: 42, @@ -787,7 +940,7 @@ fn receive_messages_delivery_proof_rejects_proof_if_trying_to_confirm_more_messa { run_test(|| { // send message first to be able to check that delivery_proof fails later - send_regular_message(TEST_LANE_ID); + send_regular_message(test_lane_id()); // 1) InboundLaneData declares that the `last_confirmed_nonce` is 1; // 2) InboundLaneData has no entries => `InboundLaneData::last_delivered_nonce()` returns @@ -796,8 +949,12 @@ fn receive_messages_delivery_proof_rejects_proof_if_trying_to_confirm_more_messa // 4) so the number of declared messages (see `UnrewardedRelayersState`) is `0` and numer of // actually confirmed messages is `1`. let proof = prepare_messages_delivery_proof( - TEST_LANE_ID, - InboundLaneData { last_confirmed_nonce: 1, relayers: Default::default() }, + test_lane_id(), + InboundLaneData { + state: LaneState::Opened, + last_confirmed_nonce: 1, + relayers: Default::default(), + }, ); assert_noop!( Pallet::::receive_messages_delivery_proof( @@ -821,20 +978,20 @@ fn storage_keys_computed_properly() { assert_eq!( OutboundMessages::::storage_map_final_key(MessageKey { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), nonce: 42 }), - bp_messages::storage_keys::message_key("Messages", &TEST_LANE_ID, 42).0, + bp_messages::storage_keys::message_key("Messages", &test_lane_id(), 42).0, ); assert_eq!( - OutboundLanes::::storage_map_final_key(TEST_LANE_ID), - bp_messages::storage_keys::outbound_lane_data_key("Messages", &TEST_LANE_ID).0, + OutboundLanes::::storage_map_final_key(test_lane_id()), + bp_messages::storage_keys::outbound_lane_data_key("Messages", &test_lane_id()).0, ); assert_eq!( - InboundLanes::::storage_map_final_key(TEST_LANE_ID), - bp_messages::storage_keys::inbound_lane_data_key("Messages", &TEST_LANE_ID).0, + InboundLanes::::storage_map_final_key(test_lane_id()), + bp_messages::storage_keys::inbound_lane_data_key("Messages", &test_lane_id()).0, ); } @@ -843,7 +1000,7 @@ fn inbound_message_details_works() { run_test(|| { assert_eq!( Pallet::::inbound_message_data( - TEST_LANE_ID, + test_lane_id(), REGULAR_PAYLOAD.encode(), OutboundMessageDetails { nonce: 0, dispatch_weight: Weight::zero(), size: 0 }, ), @@ -852,147 +1009,15 @@ fn inbound_message_details_works() { }); } -#[test] -fn on_idle_callback_respects_remaining_weight() { - run_test(|| { - send_regular_message(TEST_LANE_ID); - send_regular_message(TEST_LANE_ID); - send_regular_message(TEST_LANE_ID); - send_regular_message(TEST_LANE_ID); - - assert_ok!(Pallet::::receive_messages_delivery_proof( - RuntimeOrigin::signed(1), - prepare_messages_delivery_proof( - TEST_LANE_ID, - InboundLaneData { - last_confirmed_nonce: 4, - relayers: vec![unrewarded_relayer(1, 4, TEST_RELAYER_A)].into(), - }, - ), - UnrewardedRelayersState { - unrewarded_relayer_entries: 1, - messages_in_oldest_entry: 4, - total_messages: 4, - last_delivered_nonce: 4, - }, - )); - - // all 4 messages may be pruned now - assert_eq!(outbound_lane::(TEST_LANE_ID).data().latest_received_nonce, 4); - assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 1); - System::::set_block_number(2); - - // if passed wight is too low to do anything - let dbw = DbWeight::get(); - assert_eq!(Pallet::::on_idle(0, dbw.reads_writes(1, 1)), Weight::zero(),); - assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 1); - - // if passed wight is enough to prune single message - assert_eq!( - Pallet::::on_idle(0, dbw.reads_writes(1, 2)), - dbw.reads_writes(1, 2), - ); - assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 2); - - // if passed wight is enough to prune two more messages - assert_eq!( - Pallet::::on_idle(0, dbw.reads_writes(1, 3)), - dbw.reads_writes(1, 3), - ); - assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 4); - - // if passed wight is enough to prune many messages - assert_eq!( - Pallet::::on_idle(0, dbw.reads_writes(100, 100)), - dbw.reads_writes(1, 2), - ); - assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 5); - }); -} - -#[test] -fn on_idle_callback_is_rotating_lanes_to_prune() { - run_test(|| { - // send + receive confirmation for lane 1 - send_regular_message(TEST_LANE_ID); - receive_messages_delivery_proof(); - // send + receive confirmation for lane 2 - send_regular_message(TEST_LANE_ID_2); - assert_ok!(Pallet::::receive_messages_delivery_proof( - RuntimeOrigin::signed(1), - prepare_messages_delivery_proof( - TEST_LANE_ID_2, - InboundLaneData { - last_confirmed_nonce: 1, - relayers: vec![unrewarded_relayer(1, 1, TEST_RELAYER_A)].into(), - }, - ), - UnrewardedRelayersState { - unrewarded_relayer_entries: 1, - messages_in_oldest_entry: 1, - total_messages: 1, - last_delivered_nonce: 1, - }, - )); - - // nothing is pruned yet - assert_eq!(outbound_lane::(TEST_LANE_ID).data().latest_received_nonce, 1); - assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 1); - assert_eq!( - outbound_lane::(TEST_LANE_ID_2).data().latest_received_nonce, - 1 - ); - assert_eq!( - outbound_lane::(TEST_LANE_ID_2).data().oldest_unpruned_nonce, - 1 - ); - - // in block#2.on_idle lane messages of lane 1 are pruned - let dbw = DbWeight::get(); - System::::set_block_number(2); - assert_eq!( - Pallet::::on_idle(0, dbw.reads_writes(100, 100)), - dbw.reads_writes(1, 2), - ); - assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 2); - assert_eq!( - outbound_lane::(TEST_LANE_ID_2).data().oldest_unpruned_nonce, - 1 - ); - - // in block#3.on_idle lane messages of lane 2 are pruned - System::::set_block_number(3); - - assert_eq!( - Pallet::::on_idle(0, dbw.reads_writes(100, 100)), - dbw.reads_writes(1, 2), - ); - assert_eq!(outbound_lane::(TEST_LANE_ID).data().oldest_unpruned_nonce, 2); - assert_eq!( - outbound_lane::(TEST_LANE_ID_2).data().oldest_unpruned_nonce, - 2 - ); - }); -} - -#[test] -fn outbound_message_from_unconfigured_lane_is_rejected() { - run_test(|| { - assert_noop!( - Pallet::::validate_message(TEST_LANE_ID_3, ®ULAR_PAYLOAD,), - Error::::InactiveOutboundLane, - ); - }); -} - #[test] fn test_bridge_messages_call_is_correctly_defined() { run_test(|| { let account_id = 1; let message_proof = prepare_messages_proof(vec![message(1, REGULAR_PAYLOAD)], None); let message_delivery_proof = prepare_messages_delivery_proof( - TEST_LANE_ID, + test_lane_id(), InboundLaneData { + state: LaneState::Opened, last_confirmed_nonce: 1, relayers: vec![UnrewardedRelayer { relayer: 0, @@ -1016,8 +1041,8 @@ fn test_bridge_messages_call_is_correctly_defined() { }; let indirect_receive_messages_proof_call = BridgeMessagesCall::< AccountId, - FromBridgedChainMessagesProof, - FromBridgedChainMessagesDeliveryProof, + FromBridgedChainMessagesProof, + FromBridgedChainMessagesDeliveryProof, >::receive_messages_proof { relayer_id_at_bridged_chain: account_id, proof: *message_proof, @@ -1036,8 +1061,8 @@ fn test_bridge_messages_call_is_correctly_defined() { }; let indirect_receive_messages_delivery_proof_call = BridgeMessagesCall::< AccountId, - FromBridgedChainMessagesProof, - FromBridgedChainMessagesDeliveryProof, + FromBridgedChainMessagesProof, + FromBridgedChainMessagesDeliveryProof, >::receive_messages_delivery_proof { proof: message_delivery_proof, relayers_state: unrewarded_relayer_state, @@ -1062,12 +1087,12 @@ fn inbound_storage_extra_proof_size_bytes_works() { fn storage(relayer_entries: usize) -> RuntimeInboundLaneStorage { RuntimeInboundLaneStorage { - lane_id: Default::default(), - cached_data: Some(InboundLaneData { + lane_id: TestLaneIdType::try_new(1, 2).unwrap(), + cached_data: InboundLaneData { + state: LaneState::Opened, relayers: vec![relayer_entry(); relayer_entries].into(), last_confirmed_nonce: 0, - }), - _phantom: Default::default(), + }, } } @@ -1092,9 +1117,116 @@ fn inbound_storage_extra_proof_size_bytes_works() { } #[test] -fn maybe_outbound_lanes_count_returns_correct_value() { - assert_eq!( - MaybeOutboundLanesCount::::get(), - Some(mock::ActiveOutboundLanes::get().len() as u32) - ); +fn send_messages_fails_if_outbound_lane_is_not_opened() { + run_test(|| { + assert_noop!( + Pallet::::validate_message(unknown_lane_id(), ®ULAR_PAYLOAD), + Error::::LanesManager(LanesManagerError::UnknownOutboundLane), + ); + + assert_noop!( + Pallet::::validate_message(closed_lane_id(), ®ULAR_PAYLOAD), + Error::::LanesManager(LanesManagerError::ClosedOutboundLane), + ); + }); +} + +#[test] +fn receive_messages_proof_fails_if_inbound_lane_is_not_opened() { + run_test(|| { + let mut message = message(1, REGULAR_PAYLOAD); + message.key.lane_id = unknown_lane_id(); + let proof = prepare_messages_proof(vec![message.clone()], None); + + assert_noop!( + Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + proof, + 1, + REGULAR_PAYLOAD.declared_weight, + ), + Error::::LanesManager(LanesManagerError::UnknownInboundLane), + ); + + message.key.lane_id = closed_lane_id(); + let proof = prepare_messages_proof(vec![message], None); + + assert_noop!( + Pallet::::receive_messages_proof( + RuntimeOrigin::signed(1), + TEST_RELAYER_A, + proof, + 1, + REGULAR_PAYLOAD.declared_weight, + ), + Error::::LanesManager(LanesManagerError::ClosedInboundLane), + ); + }); +} + +#[test] +fn receive_messages_delivery_proof_fails_if_outbound_lane_is_unknown() { + run_test(|| { + let make_proof = |lane: TestLaneIdType| { + prepare_messages_delivery_proof( + lane, + InboundLaneData { + state: LaneState::Opened, + last_confirmed_nonce: 1, + relayers: vec![UnrewardedRelayer { + relayer: 0, + messages: DeliveredMessages::new(1), + }] + .into(), + }, + ) + }; + + let proof = make_proof(unknown_lane_id()); + assert_noop!( + Pallet::::receive_messages_delivery_proof( + RuntimeOrigin::signed(1), + proof, + UnrewardedRelayersState { + unrewarded_relayer_entries: 1, + messages_in_oldest_entry: 1, + total_messages: 1, + last_delivered_nonce: 1, + }, + ), + Error::::LanesManager(LanesManagerError::UnknownOutboundLane), + ); + }); +} + +#[test] +fn do_try_state_for_outbound_lanes_works() { + run_test(|| { + let lane_id = test_lane_id(); + + // setup delivered nonce 1 + OutboundLanes::::insert( + lane_id, + OutboundLaneData { + state: LaneState::Opened, + oldest_unpruned_nonce: 2, + latest_received_nonce: 1, + latest_generated_nonce: 0, + }, + ); + // store message for nonce 1 + OutboundMessages::::insert( + MessageKey { lane_id, nonce: 1 }, + BoundedVec::default(), + ); + assert_err!( + Pallet::::do_try_state(), + sp_runtime::TryRuntimeError::Other("Found unpruned lanes!") + ); + + // remove message for nonce 1 + OutboundMessages::::remove(MessageKey { lane_id, nonce: 1 }); + assert_ok!(Pallet::::do_try_state()); + }) } diff --git a/bridges/modules/parachains/src/call_ext.rs b/bridges/modules/parachains/src/call_ext.rs index 0f77eaf2c5a9..b67da03a6315 100644 --- a/bridges/modules/parachains/src/call_ext.rs +++ b/bridges/modules/parachains/src/call_ext.rs @@ -14,10 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -use crate::{Config, GrandpaPalletOf, Pallet, RelayBlockHash, RelayBlockNumber}; +use crate::{Config, GrandpaPalletOf, Pallet, RelayBlockNumber}; use bp_header_chain::HeaderChain; -use bp_parachains::BestParaHeadHash; -use bp_polkadot_core::parachains::{ParaHash, ParaId}; +use bp_parachains::{BestParaHeadHash, SubmitParachainHeadsInfo}; use bp_runtime::{HeaderId, OwnedBridgeModule}; use frame_support::{ dispatch::CallableCallFor, @@ -30,21 +29,6 @@ use sp_runtime::{ RuntimeDebug, }; -/// Info about a `SubmitParachainHeads` call which tries to update a single parachain. -#[derive(PartialEq, RuntimeDebug)] -pub struct SubmitParachainHeadsInfo { - /// Number and hash of the finalized relay block that has been used to prove parachain - /// finality. - pub at_relay_block: HeaderId, - /// Parachain identifier. - pub para_id: ParaId, - /// Hash of the bundled parachain head. - pub para_head_hash: ParaHash, - /// If `true`, then the call must be free (assuming that everything else is valid) to - /// be treated as valid. - pub is_free_execution_expected: bool, -} - /// Verified `SubmitParachainHeadsInfo`. #[derive(PartialEq, RuntimeDebug)] pub struct VerifiedSubmitParachainHeadsInfo { diff --git a/bridges/modules/parachains/src/lib.rs b/bridges/modules/parachains/src/lib.rs index e2c30ce9aecc..bbf6a6600d56 100644 --- a/bridges/modules/parachains/src/lib.rs +++ b/bridges/modules/parachains/src/lib.rs @@ -28,7 +28,10 @@ pub use weights::WeightInfo; pub use weights_ext::WeightInfoExt; use bp_header_chain::{HeaderChain, HeaderChainError}; -use bp_parachains::{ParaInfo, ParaStoredHeaderData}; +use bp_parachains::{ + ParaInfo, ParaStoredHeaderData, RelayBlockHash, RelayBlockHasher, RelayBlockNumber, + SubmitParachainHeadsInfo, +}; use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; use bp_runtime::{Chain, HashOf, HeaderId, HeaderIdOf, Parachain}; use frame_support::{dispatch::PostDispatchInfo, DefaultNoBound}; @@ -61,13 +64,6 @@ mod proofs; /// The target that will be used when publishing logs related to this pallet. pub const LOG_TARGET: &str = "runtime::bridge-parachains"; -/// Block hash of the bridged relay chain. -pub type RelayBlockHash = bp_polkadot_core::Hash; -/// Block number of the bridged relay chain. -pub type RelayBlockNumber = bp_polkadot_core::BlockNumber; -/// Hasher of the bridged relay chain. -pub type RelayBlockHasher = bp_polkadot_core::Hasher; - /// Artifacts of the parachains head update. struct UpdateParachainHeadArtifacts { /// New best head of the parachain. @@ -739,7 +735,8 @@ pub mod pallet { /// Initial pallet owner. pub owner: Option, /// Dummy marker. - pub phantom: sp_std::marker::PhantomData, + #[serde(skip)] + pub _phantom: sp_std::marker::PhantomData, } #[pallet::genesis_build] diff --git a/bridges/modules/relayers/Cargo.toml b/bridges/modules/relayers/Cargo.toml index 27a28546afb4..04e7b52ed86c 100644 --- a/bridges/modules/relayers/Cargo.toml +++ b/bridges/modules/relayers/Cargo.toml @@ -16,41 +16,58 @@ log = { workspace = true } scale-info = { features = ["derive"], workspace = true } # Bridge dependencies - +bp-header-chain = { workspace = true } bp-messages = { workspace = true } bp-relayers = { workspace = true } bp-runtime = { workspace = true } +pallet-bridge-grandpa = { workspace = true } pallet-bridge-messages = { workspace = true } +pallet-bridge-parachains = { workspace = true } # Substrate Dependencies - frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } +pallet-transaction-payment = { workspace = true } sp-arithmetic = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } [dev-dependencies] -bp-runtime = { workspace = true, default-features = true } +bp-runtime = { workspace = true } pallet-balances = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } -sp-runtime = { workspace = true, default-features = true } +sp-io = { workspace = true } +sp-runtime = { workspace = true } +bp-parachains = { workspace = true } +bp-polkadot-core = { workspace = true } +bp-test-utils = { workspace = true } +pallet-utility = { workspace = true } +sp-core = { workspace = true } [features] default = ["std"] std = [ + "bp-header-chain/std", "bp-messages/std", + "bp-parachains/std", + "bp-polkadot-core/std", "bp-relayers/std", "bp-runtime/std", + "bp-test-utils/std", "codec/std", "frame-benchmarking/std", "frame-support/std", "frame-system/std", "log/std", + "pallet-bridge-grandpa/std", "pallet-bridge-messages/std", + "pallet-bridge-parachains/std", + "pallet-transaction-payment/std", + "pallet-utility/std", "scale-info/std", "sp-arithmetic/std", + "sp-core/std", + "sp-io/std", "sp-runtime/std", "sp-std/std", ] @@ -59,13 +76,22 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-bridge-grandpa/runtime-benchmarks", "pallet-bridge-messages/runtime-benchmarks", + "pallet-bridge-parachains/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", + "pallet-utility/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "pallet-balances/try-runtime", + "pallet-bridge-grandpa/try-runtime", "pallet-bridge-messages/try-runtime", + "pallet-bridge-parachains/try-runtime", + "pallet-transaction-payment/try-runtime", + "pallet-utility/try-runtime", "sp-runtime/try-runtime", ] +integrity-test = [] diff --git a/bridges/modules/relayers/src/benchmarking.rs b/bridges/modules/relayers/src/benchmarking.rs index ca312d44edfd..8fe3fc11d6ae 100644 --- a/bridges/modules/relayers/src/benchmarking.rs +++ b/bridges/modules/relayers/src/benchmarking.rs @@ -20,9 +20,8 @@ use crate::*; -use bp_messages::LaneId; use bp_relayers::RewardsAccountOwner; -use frame_benchmarking::{benchmarks, whitelisted_caller}; +use frame_benchmarking::{benchmarks_instance_pallet, whitelisted_caller}; use frame_system::RawOrigin; use sp_runtime::traits::One; @@ -30,27 +29,34 @@ use sp_runtime::traits::One; const REWARD_AMOUNT: u32 = u32::MAX; /// Pallet we're benchmarking here. -pub struct Pallet(crate::Pallet); +pub struct Pallet, I: 'static = ()>(crate::Pallet); /// Trait that must be implemented by runtime. -pub trait Config: crate::Config { +pub trait Config: crate::Config { + /// Lane id to use in benchmarks. + fn bench_lane_id() -> Self::LaneId { + Self::LaneId::default() + } /// Prepare environment for paying given reward for serving given lane. - fn prepare_rewards_account(account_params: RewardsAccountParams, reward: Self::Reward); + fn prepare_rewards_account( + account_params: RewardsAccountParams, + reward: Self::Reward, + ); /// Give enough balance to given account. fn deposit_account(account: Self::AccountId, balance: Self::Reward); } -benchmarks! { +benchmarks_instance_pallet! { // Benchmark `claim_rewards` call. claim_rewards { - let lane = LaneId([0, 0, 0, 0]); + let lane = T::bench_lane_id(); let account_params = RewardsAccountParams::new(lane, *b"test", RewardsAccountOwner::ThisChain); let relayer: T::AccountId = whitelisted_caller(); let reward = T::Reward::from(REWARD_AMOUNT); T::prepare_rewards_account(account_params, reward); - RelayerRewards::::insert(&relayer, account_params, reward); + RelayerRewards::::insert(&relayer, account_params, reward); }: _(RawOrigin::Signed(relayer), account_params) verify { // we can't check anything here, because `PaymentProcedure` is responsible for @@ -62,30 +68,30 @@ benchmarks! { register { let relayer: T::AccountId = whitelisted_caller(); let valid_till = frame_system::Pallet::::block_number() - .saturating_add(crate::Pallet::::required_registration_lease()) + .saturating_add(crate::Pallet::::required_registration_lease()) .saturating_add(One::one()) .saturating_add(One::one()); - T::deposit_account(relayer.clone(), crate::Pallet::::required_stake()); + T::deposit_account(relayer.clone(), crate::Pallet::::required_stake()); }: _(RawOrigin::Signed(relayer.clone()), valid_till) verify { - assert!(crate::Pallet::::is_registration_active(&relayer)); + assert!(crate::Pallet::::is_registration_active(&relayer)); } // Benchmark `deregister` call. deregister { let relayer: T::AccountId = whitelisted_caller(); let valid_till = frame_system::Pallet::::block_number() - .saturating_add(crate::Pallet::::required_registration_lease()) + .saturating_add(crate::Pallet::::required_registration_lease()) .saturating_add(One::one()) .saturating_add(One::one()); - T::deposit_account(relayer.clone(), crate::Pallet::::required_stake()); - crate::Pallet::::register(RawOrigin::Signed(relayer.clone()).into(), valid_till).unwrap(); + T::deposit_account(relayer.clone(), crate::Pallet::::required_stake()); + crate::Pallet::::register(RawOrigin::Signed(relayer.clone()).into(), valid_till).unwrap(); frame_system::Pallet::::set_block_number(valid_till.saturating_add(One::one())); }: _(RawOrigin::Signed(relayer.clone())) verify { - assert!(!crate::Pallet::::is_registration_active(&relayer)); + assert!(!crate::Pallet::::is_registration_active(&relayer)); } // Benchmark `slash_and_deregister` method of the pallet. We are adding this weight to @@ -95,36 +101,36 @@ benchmarks! { // prepare and register relayer account let relayer: T::AccountId = whitelisted_caller(); let valid_till = frame_system::Pallet::::block_number() - .saturating_add(crate::Pallet::::required_registration_lease()) + .saturating_add(crate::Pallet::::required_registration_lease()) .saturating_add(One::one()) .saturating_add(One::one()); - T::deposit_account(relayer.clone(), crate::Pallet::::required_stake()); - crate::Pallet::::register(RawOrigin::Signed(relayer.clone()).into(), valid_till).unwrap(); + T::deposit_account(relayer.clone(), crate::Pallet::::required_stake()); + crate::Pallet::::register(RawOrigin::Signed(relayer.clone()).into(), valid_till).unwrap(); // create slash destination account - let lane = LaneId([0, 0, 0, 0]); + let lane = T::bench_lane_id(); let slash_destination = RewardsAccountParams::new(lane, *b"test", RewardsAccountOwner::ThisChain); T::prepare_rewards_account(slash_destination, Zero::zero()); }: { - crate::Pallet::::slash_and_deregister(&relayer, slash_destination.into()) + crate::Pallet::::slash_and_deregister(&relayer, slash_destination.into()) } verify { - assert!(!crate::Pallet::::is_registration_active(&relayer)); + assert!(!crate::Pallet::::is_registration_active(&relayer)); } // Benchmark `register_relayer_reward` method of the pallet. We are adding this weight to // the weight of message delivery call if `RefundBridgedParachainMessages` signed extension // is deployed at runtime level. register_relayer_reward { - let lane = LaneId([0, 0, 0, 0]); + let lane = T::bench_lane_id(); let relayer: T::AccountId = whitelisted_caller(); let account_params = RewardsAccountParams::new(lane, *b"test", RewardsAccountOwner::ThisChain); }: { - crate::Pallet::::register_relayer_reward(account_params, &relayer, One::one()); + crate::Pallet::::register_relayer_reward(account_params, &relayer, One::one()); } verify { - assert_eq!(RelayerRewards::::get(relayer, &account_params), Some(One::one())); + assert_eq!(RelayerRewards::::get(relayer, &account_params), Some(One::one())); } impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::TestRuntime) diff --git a/bridges/modules/relayers/src/extension/grandpa_adapter.rs b/bridges/modules/relayers/src/extension/grandpa_adapter.rs new file mode 100644 index 000000000000..2a8a6e78ef9c --- /dev/null +++ b/bridges/modules/relayers/src/extension/grandpa_adapter.rs @@ -0,0 +1,182 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Adapter that allows using `pallet-bridge-relayers` as a signed extension in the +//! bridge with remote GRANDPA chain. + +use crate::{ + extension::verify_messages_call_succeeded, Config as BridgeRelayersConfig, LOG_TARGET, +}; + +use bp_relayers::{BatchCallUnpacker, ExtensionCallData, ExtensionCallInfo, ExtensionConfig}; +use bp_runtime::{Chain, StaticStrProvider}; +use frame_support::dispatch::{DispatchInfo, PostDispatchInfo}; +use frame_system::Config as SystemConfig; +use pallet_bridge_grandpa::{ + CallSubType as BridgeGrandpaCallSubtype, Config as BridgeGrandpaConfig, + SubmitFinalityProofHelper, +}; +use pallet_bridge_messages::{ + CallSubType as BridgeMessagesCallSubType, Config as BridgeMessagesConfig, LaneIdOf, +}; +use sp_runtime::{ + traits::{Dispatchable, Get}, + transaction_validity::{TransactionPriority, TransactionValidityError}, + Saturating, +}; +use sp_std::marker::PhantomData; + +/// Adapter to be used in signed extension configuration, when bridging with remote +/// chains that are using GRANDPA finality. +pub struct WithGrandpaChainExtensionConfig< + // signed extension identifier + IdProvider, + // runtime that implements `BridgeMessagesConfig`, which + // uses `BridgeGrandpaConfig` to receive messages and + // confirmations from the remote chain. + Runtime, + // batch call unpacker + BatchCallUnpacker, + // instance of the `pallet-bridge-grandpa`, tracked by this extension + BridgeGrandpaPalletInstance, + // instance of BridgedChain `pallet-bridge-messages`, tracked by this extension + BridgeMessagesPalletInstance, + // instance of `pallet-bridge-relayers`, tracked by this extension + BridgeRelayersPalletInstance, + // message delivery transaction priority boost for every additional message + PriorityBoostPerMessage, +>( + PhantomData<( + IdProvider, + Runtime, + BatchCallUnpacker, + BridgeGrandpaPalletInstance, + BridgeMessagesPalletInstance, + BridgeRelayersPalletInstance, + PriorityBoostPerMessage, + )>, +); + +impl ExtensionConfig + for WithGrandpaChainExtensionConfig +where + ID: StaticStrProvider, + R: BridgeRelayersConfig + + BridgeMessagesConfig> + + BridgeGrandpaConfig, + BCU: BatchCallUnpacker, + GI: 'static, + MI: 'static, + RI: 'static, + P: Get, + R::RuntimeCall: Dispatchable + + BridgeGrandpaCallSubtype + + BridgeMessagesCallSubType, +{ + type IdProvider = ID; + type Runtime = R; + type BridgeMessagesPalletInstance = MI; + type BridgeRelayersPalletInstance = RI; + type PriorityBoostPerMessage = P; + type RemoteGrandpaChainBlockNumber = pallet_bridge_grandpa::BridgedBlockNumber; + type LaneId = LaneIdOf; + + fn parse_and_check_for_obsolete_call( + call: &R::RuntimeCall, + ) -> Result< + Option>, + TransactionValidityError, + > { + let calls = BCU::unpack(call, 2); + let total_calls = calls.len(); + let mut calls = calls.into_iter().map(Self::check_obsolete_parsed_call).rev(); + + let msgs_call = calls.next().transpose()?.and_then(|c| c.call_info()); + let relay_finality_call = + calls.next().transpose()?.and_then(|c| c.submit_finality_proof_info()); + + Ok(match (total_calls, relay_finality_call, msgs_call) { + (2, Some(relay_finality_call), Some(msgs_call)) => + Some(ExtensionCallInfo::RelayFinalityAndMsgs(relay_finality_call, msgs_call)), + (1, None, Some(msgs_call)) => Some(ExtensionCallInfo::Msgs(msgs_call)), + _ => None, + }) + } + + fn check_obsolete_parsed_call( + call: &R::RuntimeCall, + ) -> Result<&R::RuntimeCall, TransactionValidityError> { + call.check_obsolete_submit_finality_proof()?; + call.check_obsolete_call()?; + Ok(call) + } + + fn check_call_result( + call_info: &ExtensionCallInfo, + call_data: &mut ExtensionCallData, + relayer: &R::AccountId, + ) -> bool { + verify_submit_finality_proof_succeeded::(call_info, call_data, relayer) && + verify_messages_call_succeeded::(call_info, call_data, relayer) + } +} + +/// If the batch call contains the GRANDPA chain state update call, verify that it +/// has been successful. +/// +/// Only returns false when GRANDPA chain state update call has failed. +pub(crate) fn verify_submit_finality_proof_succeeded( + call_info: &ExtensionCallInfo, + call_data: &mut ExtensionCallData, + relayer: &::AccountId, +) -> bool +where + C: ExtensionConfig, + GI: 'static, + C::Runtime: BridgeGrandpaConfig, + >::BridgedChain: + Chain, +{ + let Some(finality_proof_info) = call_info.submit_finality_proof_info() else { return true }; + + if !SubmitFinalityProofHelper::::was_successful( + finality_proof_info.block_number, + ) { + // we only refund relayer if all calls have updated chain state + log::trace!( + target: LOG_TARGET, + "{}.{:?}: relayer {:?} has submitted invalid GRANDPA chain finality proof", + C::IdProvider::STR, + call_info.messages_call_info().lane_id(), + relayer, + ); + return false + } + + // there's a conflict between how bridge GRANDPA pallet works and a `utility.batchAll` + // transaction. If relay chain header is mandatory, the GRANDPA pallet returns + // `Pays::No`, because such transaction is mandatory for operating the bridge. But + // `utility.batchAll` transaction always requires payment. But in both cases we'll + // refund relayer - either explicitly here, or using `Pays::No` if he's choosing + // to submit dedicated transaction. + + // submitter has means to include extra weight/bytes in the `submit_finality_proof` + // call, so let's subtract extra weight/size to avoid refunding for this extra stuff + call_data.extra_weight.saturating_accrue(finality_proof_info.extra_weight); + call_data.extra_size.saturating_accrue(finality_proof_info.extra_size); + + true +} diff --git a/bridges/modules/relayers/src/extension/messages_adapter.rs b/bridges/modules/relayers/src/extension/messages_adapter.rs new file mode 100644 index 000000000000..e8c2088b7f2d --- /dev/null +++ b/bridges/modules/relayers/src/extension/messages_adapter.rs @@ -0,0 +1,99 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Adapter that allows using `pallet-bridge-relayers` as a signed extension in the +//! bridge with any remote chain. This adapter does not refund any finality transactions. + +use crate::{extension::verify_messages_call_succeeded, Config as BridgeRelayersConfig}; + +use bp_relayers::{ExtensionCallData, ExtensionCallInfo, ExtensionConfig}; +use bp_runtime::StaticStrProvider; +use frame_support::dispatch::{DispatchInfo, PostDispatchInfo}; +use pallet_bridge_messages::{ + CallSubType as BridgeMessagesCallSubType, Config as BridgeMessagesConfig, LaneIdOf, +}; +use sp_runtime::{ + traits::{Dispatchable, Get}, + transaction_validity::{TransactionPriority, TransactionValidityError}, +}; +use sp_std::marker::PhantomData; + +/// Transaction extension that refunds a relayer for standalone messages delivery and confirmation +/// transactions. Finality transactions are not refunded. +pub struct WithMessagesExtensionConfig< + IdProvider, + Runtime, + BridgeMessagesPalletInstance, + BridgeRelayersPalletInstance, + PriorityBoostPerMessage, +>( + PhantomData<( + // signed extension identifier + IdProvider, + // runtime with `pallet-bridge-messages` pallet deployed + Runtime, + // instance of BridgedChain `pallet-bridge-messages`, tracked by this extension + BridgeMessagesPalletInstance, + // instance of `pallet-bridge-relayers`, tracked by this extension + BridgeRelayersPalletInstance, + // message delivery transaction priority boost for every additional message + PriorityBoostPerMessage, + )>, +); + +impl ExtensionConfig for WithMessagesExtensionConfig +where + ID: StaticStrProvider, + R: BridgeRelayersConfig + BridgeMessagesConfig, + MI: 'static, + RI: 'static, + P: Get, + R::RuntimeCall: Dispatchable + + BridgeMessagesCallSubType, +{ + type IdProvider = ID; + type Runtime = R; + type BridgeMessagesPalletInstance = MI; + type BridgeRelayersPalletInstance = RI; + type PriorityBoostPerMessage = P; + type RemoteGrandpaChainBlockNumber = (); + type LaneId = LaneIdOf; + + fn parse_and_check_for_obsolete_call( + call: &R::RuntimeCall, + ) -> Result< + Option>, + TransactionValidityError, + > { + let call = Self::check_obsolete_parsed_call(call)?; + Ok(call.call_info().map(ExtensionCallInfo::Msgs)) + } + + fn check_obsolete_parsed_call( + call: &R::RuntimeCall, + ) -> Result<&R::RuntimeCall, TransactionValidityError> { + call.check_obsolete_call()?; + Ok(call) + } + + fn check_call_result( + call_info: &ExtensionCallInfo, + call_data: &mut ExtensionCallData, + relayer: &R::AccountId, + ) -> bool { + verify_messages_call_succeeded::(call_info, call_data, relayer) + } +} diff --git a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs b/bridges/modules/relayers/src/extension/mod.rs similarity index 57% rename from bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs rename to bridges/modules/relayers/src/extension/mod.rs index 6ba3506377d0..710533c223a0 100644 --- a/bridges/bin/runtime-common/src/extensions/refund_relayer_extension.rs +++ b/bridges/modules/relayers/src/extension/mod.rs @@ -14,307 +14,201 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -//! Signed extension that refunds relayer if he has delivered some new messages. -//! It also refunds transaction cost if the transaction is an `utility.batchAll()` -//! with calls that are: delivering new message and all necessary underlying headers -//! (parachain or relay chain). - -use crate::messages_call_ext::{ - CallHelper as MessagesCallHelper, CallInfo as MessagesCallInfo, MessagesCallSubType, +//! Signed extension, built around `pallet-bridge-relayers`. It is able to: +//! +//! - refund the cost of successful message delivery and confirmation transactions to the submitter +//! by registering corresponding reward in the pallet; +//! +//! - bump priority of messages delivery and confirmation transactions, signed by the registered +//! relayers. + +use crate::{Config as RelayersConfig, Pallet as RelayersPallet, WeightInfoExt, LOG_TARGET}; + +use bp_messages::{ChainWithMessages, MessageNonce}; +use bp_relayers::{ + ExplicitOrAccountParams, ExtensionCallData, ExtensionCallInfo, ExtensionConfig, + RewardsAccountOwner, RewardsAccountParams, }; -use bp_messages::{ChainWithMessages, LaneId, MessageNonce}; -use bp_relayers::{ExplicitOrAccountParams, RewardsAccountOwner, RewardsAccountParams}; -use bp_runtime::{Chain, Parachain, RangeInclusiveExt, StaticStrProvider}; -use codec::{Codec, Decode, Encode}; +use bp_runtime::{Chain, RangeInclusiveExt, StaticStrProvider}; +use codec::{Decode, Encode}; use frame_support::{ - dispatch::{CallableCallFor, DispatchInfo, PostDispatchInfo}, - traits::IsSubType, + dispatch::{DispatchInfo, PostDispatchInfo}, weights::Weight, CloneNoBound, DefaultNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, }; -use pallet_bridge_grandpa::{ - CallSubType as GrandpaCallSubType, SubmitFinalityProofHelper, SubmitFinalityProofInfo, -}; -use pallet_bridge_messages::Config as MessagesConfig; -use pallet_bridge_parachains::{ - BoundedBridgeGrandpaConfig, CallSubType as ParachainsCallSubType, Config as ParachainsConfig, - RelayBlockNumber, SubmitParachainHeadsHelper, SubmitParachainHeadsInfo, +use frame_system::Config as SystemConfig; +use pallet_bridge_messages::{ + CallHelper as MessagesCallHelper, Config as BridgeMessagesConfig, LaneIdOf, }; -use pallet_bridge_relayers::{ - Config as RelayersConfig, Pallet as RelayersPallet, WeightInfoExt as _, +use pallet_transaction_payment::{ + Config as TransactionPaymentConfig, OnChargeTransaction, Pallet as TransactionPaymentPallet, }; -use pallet_transaction_payment::{Config as TransactionPaymentConfig, OnChargeTransaction}; -use pallet_utility::{Call as UtilityCall, Config as UtilityConfig, Pallet as UtilityPallet}; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, Dispatchable, Get, PostDispatchInfoOf, SignedExtension, Zero}, - transaction_validity::{ - TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransactionBuilder, + traits::{ + AsSystemOriginSigner, DispatchInfoOf, Dispatchable, PostDispatchInfoOf, + TransactionExtension, ValidateResult, Zero, }, - DispatchResult, FixedPointOperand, RuntimeDebug, + transaction_validity::{InvalidTransaction, TransactionValidityError, ValidTransactionBuilder}, + DispatchResult, RuntimeDebug, }; -use sp_std::{marker::PhantomData, vec, vec::Vec}; - -type AccountIdOf = ::AccountId; -// without this typedef rustfmt fails with internal err -type BalanceOf = - <::OnChargeTransaction as OnChargeTransaction>::Balance; -type CallOf = ::RuntimeCall; - -/// Trait identifying a bridged parachain. A relayer might be refunded for delivering messages -/// coming from this parachain. -pub trait RefundableParachainId { - /// The instance of the bridge parachains pallet. - type Instance: 'static; - /// The parachain Id. - type BridgedChain: Parachain; -} - -/// Implementation of `RefundableParachainId` for `trait Parachain`. -pub struct RefundableParachain(PhantomData<(Instance, Para)>); - -impl RefundableParachainId for RefundableParachain -where - Instance: 'static, - Para: Parachain, -{ - type Instance = Instance; - type BridgedChain = Para; -} - -/// Trait identifying a bridged messages lane. A relayer might be refunded for delivering messages -/// coming from this lane. -pub trait RefundableMessagesLaneId { - /// The instance of the bridge messages pallet. - type Instance: 'static; - /// The messages lane id. - type Id: Get; -} - -/// Default implementation of `RefundableMessagesLaneId`. -pub struct RefundableMessagesLane(PhantomData<(Instance, Id)>); - -impl RefundableMessagesLaneId for RefundableMessagesLane -where - Instance: 'static, - Id: Get, -{ - type Instance = Instance; - type Id = Id; -} - -/// Refund calculator. -pub trait RefundCalculator { - /// The underlying integer type in which the refund is calculated. - type Balance; - - /// Compute refund for given transaction. - fn compute_refund( - info: &DispatchInfo, - post_info: &PostDispatchInfo, - len: usize, - tip: Self::Balance, - ) -> Self::Balance; -} - -/// `RefundCalculator` implementation which refunds the actual transaction fee. -pub struct ActualFeeRefund(PhantomData); +use sp_std::{fmt::Debug, marker::PhantomData}; -impl RefundCalculator for ActualFeeRefund -where - R: TransactionPaymentConfig, - CallOf: Dispatchable, - BalanceOf: FixedPointOperand, -{ - type Balance = BalanceOf; +pub use grandpa_adapter::WithGrandpaChainExtensionConfig; +pub use messages_adapter::WithMessagesExtensionConfig; +pub use parachain_adapter::WithParachainExtensionConfig; +pub use priority::*; - fn compute_refund( - info: &DispatchInfo, - post_info: &PostDispatchInfo, - len: usize, - tip: BalanceOf, - ) -> BalanceOf { - pallet_transaction_payment::Pallet::::compute_actual_fee(len as _, info, post_info, tip) - } -} +mod grandpa_adapter; +mod messages_adapter; +mod parachain_adapter; +mod priority; -/// Data that is crafted in `pre_dispatch` method and used at `post_dispatch`. +/// Data that is crafted in `validate`, passed to `prepare` and used at `post_dispatch` method. #[cfg_attr(test, derive(Debug, PartialEq))] -pub struct PreDispatchData { +pub struct PreDispatchData< + AccountId, + RemoteGrandpaChainBlockNumber: Debug, + LaneId: Clone + Copy + Debug, +> { /// Transaction submitter (relayer) account. relayer: AccountId, /// Type of the call. - call_info: CallInfo, + call_info: ExtensionCallInfo, } -/// Type of the call that the extension recognizes. -#[derive(RuntimeDebugNoBound, PartialEq)] -pub enum CallInfo { - /// Relay chain finality + parachain finality + message delivery/confirmation calls. - AllFinalityAndMsgs( - SubmitFinalityProofInfo, - SubmitParachainHeadsInfo, - MessagesCallInfo, - ), - /// Relay chain finality + message delivery/confirmation calls. - RelayFinalityAndMsgs(SubmitFinalityProofInfo, MessagesCallInfo), - /// Parachain finality + message delivery/confirmation calls. - /// - /// This variant is used only when bridging with parachain. - ParachainFinalityAndMsgs(SubmitParachainHeadsInfo, MessagesCallInfo), - /// Standalone message delivery/confirmation call. - Msgs(MessagesCallInfo), -} - -impl CallInfo { - /// Returns true if call is a message delivery call (with optional finality calls). - fn is_receive_messages_proof_call(&self) -> bool { - match self.messages_call_info() { - MessagesCallInfo::ReceiveMessagesProof(_) => true, - MessagesCallInfo::ReceiveMessagesDeliveryProof(_) => false, - } - } - - /// Returns the pre-dispatch `finality_target` sent to the `SubmitFinalityProof` call. - fn submit_finality_proof_info(&self) -> Option> { - match *self { - Self::AllFinalityAndMsgs(info, _, _) => Some(info), - Self::RelayFinalityAndMsgs(info, _) => Some(info), - _ => None, - } - } - - /// Returns mutable reference to pre-dispatch `finality_target` sent to the +impl + PreDispatchData +{ + /// Returns mutable reference to `finality_target` sent to the /// `SubmitFinalityProof` call. #[cfg(test)] - fn submit_finality_proof_info_mut( + pub fn submit_finality_proof_info_mut( &mut self, - ) -> Option<&mut SubmitFinalityProofInfo> { - match *self { - Self::AllFinalityAndMsgs(ref mut info, _, _) => Some(info), - Self::RelayFinalityAndMsgs(ref mut info, _) => Some(info), + ) -> Option<&mut bp_header_chain::SubmitFinalityProofInfo> { + match self.call_info { + ExtensionCallInfo::AllFinalityAndMsgs(ref mut info, _, _) => Some(info), + ExtensionCallInfo::RelayFinalityAndMsgs(ref mut info, _) => Some(info), _ => None, } } - - /// Returns the pre-dispatch `SubmitParachainHeadsInfo`. - fn submit_parachain_heads_info(&self) -> Option<&SubmitParachainHeadsInfo> { - match self { - Self::AllFinalityAndMsgs(_, info, _) => Some(info), - Self::ParachainFinalityAndMsgs(info, _) => Some(info), - _ => None, - } - } - - /// Returns the pre-dispatch `ReceiveMessagesProofInfo`. - fn messages_call_info(&self) -> &MessagesCallInfo { - match self { - Self::AllFinalityAndMsgs(_, _, info) => info, - Self::RelayFinalityAndMsgs(_, info) => info, - Self::ParachainFinalityAndMsgs(_, info) => info, - Self::Msgs(info) => info, - } - } } /// The actions on relayer account that need to be performed because of his actions. #[derive(RuntimeDebug, PartialEq)] -pub enum RelayerAccountAction { +pub enum RelayerAccountAction { /// Do nothing with relayer account. None, /// Reward the relayer. - Reward(AccountId, RewardsAccountParams, Reward), + Reward(AccountId, RewardsAccountParams, Reward), /// Slash the relayer. - Slash(AccountId, RewardsAccountParams), + Slash(AccountId, RewardsAccountParams), } -/// Everything common among our refund signed extensions. -pub trait RefundSignedExtension: - 'static + Clone + Codec + sp_std::fmt::Debug + Default + Eq + PartialEq + Send + Sync + TypeInfo +/// A signed extension, built around `pallet-bridge-relayers`. +/// +/// It may be incorporated into runtime to refund relayers for submitting correct +/// message delivery and confirmation transactions, optionally batched with required +/// finality proofs. +#[derive( + DefaultNoBound, + CloneNoBound, + Decode, + Encode, + EqNoBound, + PartialEqNoBound, + RuntimeDebugNoBound, + TypeInfo, +)] +#[scale_info(skip_type_params(Runtime, Config, LaneId))] +pub struct BridgeRelayersTransactionExtension( + PhantomData<(Runtime, Config, LaneId)>, +); + +impl BridgeRelayersTransactionExtension +where + Self: 'static + Send + Sync, + R: RelayersConfig + + BridgeMessagesConfig + + TransactionPaymentConfig, + C: ExtensionConfig, + R::RuntimeCall: Dispatchable, + ::RuntimeOrigin: AsSystemOriginSigner + Clone, + ::OnChargeTransaction: + OnChargeTransaction, + LaneId: Clone + Copy + Decode + Encode + Debug + TypeInfo, { - /// This chain runtime. - type Runtime: MessagesConfig<::Instance> - + RelayersConfig; - /// Messages pallet and lane reference. - type Msgs: RefundableMessagesLaneId; - /// Refund amount calculator. - type Refund: RefundCalculator::Reward>; - /// Priority boost calculator. - type Priority: Get; - /// Signed extension unique identifier. - type Id: StaticStrProvider; - - /// Unpack batch runtime call. - fn expand_call(call: &CallOf) -> Vec<&CallOf>; - - /// Given runtime call, check if it has supported format. Additionally, check if any of - /// (optionally batched) calls are obsolete and we shall reject the transaction. - fn parse_and_check_for_obsolete_call( - call: &CallOf, - ) -> Result, TransactionValidityError>; - - /// Check if parsed call is already obsolete. - fn check_obsolete_parsed_call( - call: &CallOf, - ) -> Result<&CallOf, TransactionValidityError>; - - /// Called from post-dispatch and shall perform additional checks (apart from messages - /// transaction success) of given call result. - fn additional_call_result_check( - relayer: &AccountIdOf, - call_info: &CallInfo, - extra_weight: &mut Weight, - extra_size: &mut u32, - ) -> bool; + /// Returns number of bundled messages `Some(_)`, if the given call info is a: + /// + /// - message delivery transaction; + /// + /// - with reasonable bundled messages that may be accepted by the messages pallet. + /// + /// This function is used to check whether the transaction priority should be + /// virtually boosted. The relayer registration (we only boost priority for registered + /// relayer transactions) must be checked outside. + fn bundled_messages_for_priority_boost( + parsed_call: &ExtensionCallInfo, + ) -> Option { + // we only boost priority of message delivery transactions + if !parsed_call.is_receive_messages_proof_call() { + return None; + } + + // compute total number of messages in transaction + let bundled_messages = parsed_call.messages_call_info().bundled_messages().saturating_len(); + + // a quick check to avoid invalid high-priority transactions + let max_unconfirmed_messages_in_confirmation_tx = >::BridgedChain + ::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + if bundled_messages > max_unconfirmed_messages_in_confirmation_tx { + return None + } + + Some(bundled_messages) + } /// Given post-dispatch information, analyze the outcome of relayer call and return /// actions that need to be performed on relayer account. fn analyze_call_result( - pre: Option>>>, + pre: Option>, info: &DispatchInfo, post_info: &PostDispatchInfo, len: usize, result: &DispatchResult, - ) -> RelayerAccountAction, ::Reward> - { - let mut extra_weight = Weight::zero(); - let mut extra_size = 0; - + ) -> RelayerAccountAction { // We don't refund anything for transactions that we don't support. let (relayer, call_info) = match pre { - Some(Some(pre)) => (pre.relayer, pre.call_info), + Some(pre) => (pre.relayer, pre.call_info), _ => return RelayerAccountAction::None, }; - // now we know that the relayer either needs to be rewarded, or slashed + // now we know that the call is supported and we may need to reward or slash relayer // => let's prepare the correspondent account that pays reward/receives slashed amount - let reward_account_params = - RewardsAccountParams::new( - ::Id::get(), - ::Instance, - >>::BridgedChain::ID, - if call_info.is_receive_messages_proof_call() { - RewardsAccountOwner::ThisChain - } else { - RewardsAccountOwner::BridgedChain - }, - ); + let lane_id = call_info.messages_call_info().lane_id(); + let reward_account_params = RewardsAccountParams::new( + lane_id, + >::BridgedChain::ID, + if call_info.is_receive_messages_proof_call() { + RewardsAccountOwner::ThisChain + } else { + RewardsAccountOwner::BridgedChain + }, + ); // prepare return value for the case if the call has failed or it has not caused // expected side effects (e.g. not all messages have been accepted) // // we are not checking if relayer is registered here - it happens during the slash attempt // - // there are couple of edge cases here: + // there are a couple of edge cases here: // // - when the relayer becomes registered during message dispatch: this is unlikely + relayer // should be ready for slashing after registration; // // - when relayer is registered after `validate` is called and priority is not boosted: // relayer should be ready for slashing after registration. - let may_slash_relayer = - Self::bundled_messages_for_priority_boost(Some(&call_info)).is_some(); + let may_slash_relayer = Self::bundled_messages_for_priority_boost(&call_info).is_some(); let slash_relayer_if_delivery_result = may_slash_relayer .then(|| RelayerAccountAction::Slash(relayer.clone(), reward_account_params)) .unwrap_or(RelayerAccountAction::None); @@ -322,37 +216,19 @@ pub trait RefundSignedExtension: // We don't refund anything if the transaction has failed. if let Err(e) = result { log::trace!( - target: "runtime::bridge", - "{} via {:?}: relayer {:?} has submitted invalid messages transaction: {:?}", - Self::Id::STR, - ::Id::get(), + target: LOG_TARGET, + "{}.{:?}: relayer {:?} has submitted invalid messages transaction: {:?}", + Self::IDENTIFIER, + lane_id, relayer, e, ); return slash_relayer_if_delivery_result } - // Check if the `ReceiveMessagesProof` call delivered at least some of the messages that - // it contained. If this happens, we consider the transaction "helpful" and refund it. - let msgs_call_info = call_info.messages_call_info(); - if !MessagesCallHelper::::Instance>::was_successful(msgs_call_info) { - log::trace!( - target: "runtime::bridge", - "{} via {:?}: relayer {:?} has submitted invalid messages call", - Self::Id::STR, - ::Id::get(), - relayer, - ); - return slash_relayer_if_delivery_result - } - - // do additional checks - if !Self::additional_call_result_check( - &relayer, - &call_info, - &mut extra_weight, - &mut extra_size, - ) { + // check whether the call has succeeded + let mut call_data = ExtensionCallData::default(); + if !C::check_call_result(&call_info, &mut call_data, &relayer) { return slash_relayer_if_delivery_result } @@ -364,654 +240,288 @@ pub trait RefundSignedExtension: let tip = Zero::zero(); // decrease post-dispatch weight/size using extra weight/size that we know now - let post_info_len = len.saturating_sub(extra_size as usize); - let mut post_info_weight = - post_info.actual_weight.unwrap_or(info.weight).saturating_sub(extra_weight); + let post_info_len = len.saturating_sub(call_data.extra_size as usize); + let mut post_info_weight = post_info + .actual_weight + .unwrap_or(info.total_weight()) + .saturating_sub(call_data.extra_weight); // let's also replace the weight of slashing relayer with the weight of rewarding relayer if call_info.is_receive_messages_proof_call() { post_info_weight = post_info_weight.saturating_sub( - ::WeightInfo::extra_weight_of_successful_receive_messages_proof_call(), + ::WeightInfo::extra_weight_of_successful_receive_messages_proof_call(), ); } // compute the relayer refund let mut post_info = *post_info; post_info.actual_weight = Some(post_info_weight); - let refund = Self::Refund::compute_refund(info, &post_info, post_info_len, tip); + let refund = Self::compute_refund(info, &post_info, post_info_len, tip); // we can finally reward relayer RelayerAccountAction::Reward(relayer, reward_account_params, refund) } - /// Returns number of bundled messages `Some(_)`, if the given call info is a: - /// - /// - message delivery transaction; - /// - /// - with reasonable bundled messages that may be accepted by the messages pallet. - /// - /// This function is used to check whether the transaction priority should be - /// virtually boosted. The relayer registration (we only boost priority for registered - /// relayer transactions) must be checked outside. - fn bundled_messages_for_priority_boost(call_info: Option<&CallInfo>) -> Option { - // we only boost priority of message delivery transactions - let parsed_call = match call_info { - Some(parsed_call) if parsed_call.is_receive_messages_proof_call() => parsed_call, - _ => return None, - }; - - // compute total number of messages in transaction - let bundled_messages = parsed_call.messages_call_info().bundled_messages().saturating_len(); - - // a quick check to avoid invalid high-priority transactions - let max_unconfirmed_messages_in_confirmation_tx = ::Instance, - >>::BridgedChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; - if bundled_messages > max_unconfirmed_messages_in_confirmation_tx { - return None - } - - Some(bundled_messages) + /// Compute refund for the successful relayer transaction + fn compute_refund( + info: &DispatchInfo, + post_info: &PostDispatchInfo, + len: usize, + tip: R::Reward, + ) -> R::Reward { + TransactionPaymentPallet::::compute_actual_fee(len as _, info, post_info, tip) } } -/// Adapter that allow implementing `sp_runtime::traits::SignedExtension` for any -/// `RefundSignedExtension`. -#[derive( - DefaultNoBound, - CloneNoBound, - Decode, - Encode, - EqNoBound, - PartialEqNoBound, - RuntimeDebugNoBound, - TypeInfo, -)] -pub struct RefundSignedExtensionAdapter(T); - -impl SignedExtension for RefundSignedExtensionAdapter +impl TransactionExtension + for BridgeRelayersTransactionExtension where - CallOf: Dispatchable - + MessagesCallSubType::Instance>, + Self: 'static + Send + Sync, + R: RelayersConfig + + BridgeMessagesConfig + + TransactionPaymentConfig, + C: ExtensionConfig, + R::RuntimeCall: Dispatchable, + ::RuntimeOrigin: AsSystemOriginSigner + Clone, + ::OnChargeTransaction: + OnChargeTransaction, + LaneId: Clone + Copy + Decode + Encode + Debug + TypeInfo, { - const IDENTIFIER: &'static str = T::Id::STR; - type AccountId = AccountIdOf; - type Call = CallOf; - type AdditionalSigned = (); - type Pre = Option>>; + const IDENTIFIER: &'static str = C::IdProvider::STR; + type Implicit = (); + type Pre = Option>; + type Val = Self::Pre; - fn additional_signed(&self) -> Result<(), TransactionValidityError> { - Ok(()) + fn weight(&self, _call: &R::RuntimeCall) -> Weight { + Weight::zero() } fn validate( &self, - who: &Self::AccountId, - call: &Self::Call, - _info: &DispatchInfoOf, + origin: ::RuntimeOrigin, + call: &R::RuntimeCall, + _info: &DispatchInfoOf, _len: usize, - ) -> TransactionValidity { - // this is the only relevant line of code for the `pre_dispatch` - // - // we're not calling `validate` from `pre_dispatch` directly because of performance - // reasons, so if you're adding some code that may fail here, please check if it needs - // to be added to the `pre_dispatch` as well - let parsed_call = T::parse_and_check_for_obsolete_call(call)?; + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + ) -> ValidateResult { + // Prepare relevant data for `prepare` + let parsed_call = match C::parse_and_check_for_obsolete_call(call)? { + Some(parsed_call) => parsed_call, + None => return Ok((Default::default(), None, origin)), + }; + // Those calls are only for signed transactions. + let relayer = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; - // the following code just plays with transaction priority and never returns an error + let data = PreDispatchData { relayer: relayer.clone(), call_info: parsed_call }; + + // the following code just plays with transaction priority // we only boost priority of presumably correct message delivery transactions - let bundled_messages = match T::bundled_messages_for_priority_boost(parsed_call.as_ref()) { + let bundled_messages = match Self::bundled_messages_for_priority_boost(&data.call_info) { Some(bundled_messages) => bundled_messages, - None => return Ok(Default::default()), + None => return Ok((Default::default(), Some(data), origin)), }; // we only boost priority if relayer has staked required balance - if !RelayersPallet::::is_registration_active(who) { - return Ok(Default::default()) + if !RelayersPallet::::is_registration_active(&data.relayer) { + return Ok((Default::default(), Some(data), origin)) } // compute priority boost - let priority_boost = crate::extensions::priority_calculator::compute_priority_boost::< - T::Priority, - >(bundled_messages); + let priority_boost = + priority::compute_priority_boost::(bundled_messages); let valid_transaction = ValidTransactionBuilder::default().priority(priority_boost); log::trace!( - target: "runtime::bridge", - "{} via {:?} has boosted priority of message delivery transaction \ + target: LOG_TARGET, + "{}.{:?}: has boosted priority of message delivery transaction \ of relayer {:?}: {} messages -> {} priority", Self::IDENTIFIER, - ::Id::get(), - who, + data.call_info.messages_call_info().lane_id(), + data.relayer, bundled_messages, priority_boost, ); - valid_transaction.build() + let validity = valid_transaction.build()?; + Ok((validity, Some(data), origin)) } - fn pre_dispatch( + fn prepare( self, - who: &Self::AccountId, - call: &Self::Call, - _info: &DispatchInfoOf, + val: Self::Val, + _origin: &::RuntimeOrigin, + _call: &R::RuntimeCall, + _info: &DispatchInfoOf, _len: usize, ) -> Result { - // this is a relevant piece of `validate` that we need here (in `pre_dispatch`) - let parsed_call = T::parse_and_check_for_obsolete_call(call)?; - - Ok(parsed_call.map(|call_info| { + Ok(val.inspect(|data| { log::trace!( - target: "runtime::bridge", - "{} via {:?} parsed bridge transaction in pre-dispatch: {:?}", + target: LOG_TARGET, + "{}.{:?}: parsed bridge transaction in prepare: {:?}", Self::IDENTIFIER, - ::Id::get(), - call_info, + data.call_info.messages_call_info().lane_id(), + data.call_info, ); - PreDispatchData { relayer: who.clone(), call_info } })) } - fn post_dispatch( - pre: Option, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + fn post_dispatch_details( + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, len: usize, result: &DispatchResult, - ) -> Result<(), TransactionValidityError> { - let call_result = T::analyze_call_result(pre, info, post_info, len, result); + ) -> Result { + let lane_id = pre.as_ref().map(|p| p.call_info.messages_call_info().lane_id()); + let call_result = Self::analyze_call_result(pre, info, post_info, len, result); match call_result { RelayerAccountAction::None => (), RelayerAccountAction::Reward(relayer, reward_account, reward) => { - RelayersPallet::::register_relayer_reward( - reward_account, - &relayer, - reward, - ); + RelayersPallet::::register_relayer_reward(reward_account, &relayer, reward); log::trace!( - target: "runtime::bridge", - "{} via {:?} has registered reward: {:?} for {:?}", + target: LOG_TARGET, + "{}.{:?}: has registered reward: {:?} for {:?}", Self::IDENTIFIER, - ::Id::get(), + lane_id, reward, relayer, ); }, RelayerAccountAction::Slash(relayer, slash_account) => - RelayersPallet::::slash_and_deregister( + RelayersPallet::::slash_and_deregister( &relayer, ExplicitOrAccountParams::Params(slash_account), ), } - Ok(()) - } -} - -/// Signed extension that refunds a relayer for new messages coming from a parachain. -/// -/// Also refunds relayer for successful finality delivery if it comes in batch (`utility.batchAll`) -/// with message delivery transaction. Batch may deliver either both relay chain header and -/// parachain head, or just parachain head. Corresponding headers must be used in messages -/// proof verification. -/// -/// Extension does not refund transaction tip due to security reasons. -#[derive( - DefaultNoBound, - CloneNoBound, - Decode, - Encode, - EqNoBound, - PartialEqNoBound, - RuntimeDebugNoBound, - TypeInfo, -)] -#[scale_info(skip_type_params(Runtime, Para, Msgs, Refund, Priority, Id))] -pub struct RefundBridgedParachainMessages( - PhantomData<( - // runtime with `frame-utility`, `pallet-bridge-grandpa`, `pallet-bridge-parachains`, - // `pallet-bridge-messages` and `pallet-bridge-relayers` pallets deployed - Runtime, - // implementation of `RefundableParachainId` trait, which specifies the instance of - // the used `pallet-bridge-parachains` pallet and the bridged parachain id - Para, - // implementation of `RefundableMessagesLaneId` trait, which specifies the instance of - // the used `pallet-bridge-messages` pallet and the lane within this pallet - Msgs, - // implementation of the `RefundCalculator` trait, that is used to compute refund that - // we give to relayer for his transaction - Refund, - // getter for per-message `TransactionPriority` boost that we give to message - // delivery transactions - Priority, - // the runtime-unique identifier of this signed extension - Id, - )>, -); - -impl RefundSignedExtension - for RefundBridgedParachainMessages -where - Self: 'static + Send + Sync, - RefundBridgedGrandpaMessages< - Runtime, - Runtime::BridgesGrandpaPalletInstance, - Msgs, - Refund, - Priority, - Id, - >: 'static + Send + Sync, - Runtime: UtilityConfig> - + BoundedBridgeGrandpaConfig - + ParachainsConfig - + MessagesConfig - + RelayersConfig, - Para: RefundableParachainId, - Msgs: RefundableMessagesLaneId, - Refund: RefundCalculator, - Priority: Get, - Id: StaticStrProvider, - CallOf: Dispatchable - + IsSubType, Runtime>> - + GrandpaCallSubType - + ParachainsCallSubType - + MessagesCallSubType, -{ - type Runtime = Runtime; - type Msgs = Msgs; - type Refund = Refund; - type Priority = Priority; - type Id = Id; - - fn expand_call(call: &CallOf) -> Vec<&CallOf> { - match call.is_sub_type() { - Some(UtilityCall::::batch_all { ref calls }) if calls.len() <= 3 => - calls.iter().collect(), - Some(_) => vec![], - None => vec![call], - } - } - - fn parse_and_check_for_obsolete_call( - call: &CallOf, - ) -> Result, TransactionValidityError> { - let calls = Self::expand_call(call); - let total_calls = calls.len(); - let mut calls = calls.into_iter().map(Self::check_obsolete_parsed_call).rev(); - - let msgs_call = calls.next().transpose()?.and_then(|c| c.call_info_for(Msgs::Id::get())); - let para_finality_call = calls - .next() - .transpose()? - .and_then(|c| c.submit_parachain_heads_info_for(Para::BridgedChain::PARACHAIN_ID)); - let relay_finality_call = - calls.next().transpose()?.and_then(|c| c.submit_finality_proof_info()); - - Ok(match (total_calls, relay_finality_call, para_finality_call, msgs_call) { - (3, Some(relay_finality_call), Some(para_finality_call), Some(msgs_call)) => Some( - CallInfo::AllFinalityAndMsgs(relay_finality_call, para_finality_call, msgs_call), - ), - (2, None, Some(para_finality_call), Some(msgs_call)) => - Some(CallInfo::ParachainFinalityAndMsgs(para_finality_call, msgs_call)), - (1, None, None, Some(msgs_call)) => Some(CallInfo::Msgs(msgs_call)), - _ => None, - }) - } - - fn check_obsolete_parsed_call( - call: &CallOf, - ) -> Result<&CallOf, TransactionValidityError> { - call.check_obsolete_submit_finality_proof()?; - call.check_obsolete_submit_parachain_heads()?; - call.check_obsolete_call()?; - Ok(call) - } - - fn additional_call_result_check( - relayer: &Runtime::AccountId, - call_info: &CallInfo, - extra_weight: &mut Weight, - extra_size: &mut u32, - ) -> bool { - // check if relay chain state has been updated - let is_grandpa_call_successful = - RefundBridgedGrandpaMessages::< - Runtime, - Runtime::BridgesGrandpaPalletInstance, - Msgs, - Refund, - Priority, - Id, - >::additional_call_result_check(relayer, call_info, extra_weight, extra_size); - if !is_grandpa_call_successful { - return false - } - - // check if parachain state has been updated - if let Some(para_proof_info) = call_info.submit_parachain_heads_info() { - if !SubmitParachainHeadsHelper::::was_successful( - para_proof_info, - ) { - // we only refund relayer if all calls have updated chain state - log::trace!( - target: "runtime::bridge", - "{} from parachain {} via {:?}: relayer {:?} has submitted invalid parachain finality proof", - Id::STR, - Para::BridgedChain::PARACHAIN_ID, - Msgs::Id::get(), - relayer, - ); - return false - } - } - - true - } -} - -/// Signed extension that refunds a relayer for new messages coming from a standalone (GRANDPA) -/// chain. -/// -/// Also refunds relayer for successful finality delivery if it comes in batch (`utility.batchAll`) -/// with message delivery transaction. Batch may deliver either both relay chain header and -/// parachain head, or just parachain head. Corresponding headers must be used in messages -/// proof verification. -/// -/// Extension does not refund transaction tip due to security reasons. -#[derive( - DefaultNoBound, - CloneNoBound, - Decode, - Encode, - EqNoBound, - PartialEqNoBound, - RuntimeDebugNoBound, - TypeInfo, -)] -#[scale_info(skip_type_params(Runtime, GrandpaInstance, Msgs, Refund, Priority, Id))] -pub struct RefundBridgedGrandpaMessages( - PhantomData<( - // runtime with `frame-utility`, `pallet-bridge-grandpa`, - // `pallet-bridge-messages` and `pallet-bridge-relayers` pallets deployed - Runtime, - // bridge GRANDPA pallet instance, used to track bridged chain state - GrandpaInstance, - // implementation of `RefundableMessagesLaneId` trait, which specifies the instance of - // the used `pallet-bridge-messages` pallet and the lane within this pallet - Msgs, - // implementation of the `RefundCalculator` trait, that is used to compute refund that - // we give to relayer for his transaction - Refund, - // getter for per-message `TransactionPriority` boost that we give to message - // delivery transactions - Priority, - // the runtime-unique identifier of this signed extension - Id, - )>, -); - -impl RefundSignedExtension - for RefundBridgedGrandpaMessages -where - Self: 'static + Send + Sync, - Runtime: UtilityConfig> - + BoundedBridgeGrandpaConfig - + MessagesConfig - + RelayersConfig, - GrandpaInstance: 'static, - Msgs: RefundableMessagesLaneId, - Refund: RefundCalculator, - Priority: Get, - Id: StaticStrProvider, - CallOf: Dispatchable - + IsSubType, Runtime>> - + GrandpaCallSubType - + MessagesCallSubType, -{ - type Runtime = Runtime; - type Msgs = Msgs; - type Refund = Refund; - type Priority = Priority; - type Id = Id; - - fn expand_call(call: &CallOf) -> Vec<&CallOf> { - match call.is_sub_type() { - Some(UtilityCall::::batch_all { ref calls }) if calls.len() <= 2 => - calls.iter().collect(), - Some(_) => vec![], - None => vec![call], - } - } - - fn parse_and_check_for_obsolete_call( - call: &CallOf, - ) -> Result, TransactionValidityError> { - let calls = Self::expand_call(call); - let total_calls = calls.len(); - let mut calls = calls.into_iter().map(Self::check_obsolete_parsed_call).rev(); - - let msgs_call = calls.next().transpose()?.and_then(|c| c.call_info_for(Msgs::Id::get())); - let relay_finality_call = - calls.next().transpose()?.and_then(|c| c.submit_finality_proof_info()); - - Ok(match (total_calls, relay_finality_call, msgs_call) { - (2, Some(relay_finality_call), Some(msgs_call)) => - Some(CallInfo::RelayFinalityAndMsgs(relay_finality_call, msgs_call)), - (1, None, Some(msgs_call)) => Some(CallInfo::Msgs(msgs_call)), - _ => None, - }) - } - - fn check_obsolete_parsed_call( - call: &CallOf, - ) -> Result<&CallOf, TransactionValidityError> { - call.check_obsolete_submit_finality_proof()?; - call.check_obsolete_call()?; - Ok(call) - } - - fn additional_call_result_check( - relayer: &Runtime::AccountId, - call_info: &CallInfo, - extra_weight: &mut Weight, - extra_size: &mut u32, - ) -> bool { - // check if relay chain state has been updated - if let Some(finality_proof_info) = call_info.submit_finality_proof_info() { - if !SubmitFinalityProofHelper::::was_successful( - finality_proof_info.block_number, - ) { - // we only refund relayer if all calls have updated chain state - log::trace!( - target: "runtime::bridge", - "{} via {:?}: relayer {:?} has submitted invalid relay chain finality proof", - Self::Id::STR, - ::Id::get(), - relayer, - ); - return false - } - - // there's a conflict between how bridge GRANDPA pallet works and a `utility.batchAll` - // transaction. If relay chain header is mandatory, the GRANDPA pallet returns - // `Pays::No`, because such transaction is mandatory for operating the bridge. But - // `utility.batchAll` transaction always requires payment. But in both cases we'll - // refund relayer - either explicitly here, or using `Pays::No` if he's choosing - // to submit dedicated transaction. - - // submitter has means to include extra weight/bytes in the `submit_finality_proof` - // call, so let's subtract extra weight/size to avoid refunding for this extra stuff - *extra_weight = (*extra_weight).saturating_add(finality_proof_info.extra_weight); - *extra_size = (*extra_size).saturating_add(finality_proof_info.extra_size); - } - - true + Ok(Weight::zero()) } } -/// Transaction extension that refunds a relayer for standalone messages delivery and confirmation -/// transactions. Finality transactions are not refunded. -#[derive( - DefaultNoBound, - CloneNoBound, - Decode, - Encode, - EqNoBound, - PartialEqNoBound, - RuntimeDebugNoBound, - TypeInfo, -)] -#[scale_info(skip_type_params(Runtime, GrandpaInstance, Msgs, Refund, Priority, Id))] -pub struct RefundBridgedMessages( - PhantomData<( - // runtime with `pallet-bridge-messages` and `pallet-bridge-relayers` pallets deployed - Runtime, - // implementation of `RefundableMessagesLaneId` trait, which specifies the instance of - // the used `pallet-bridge-messages` pallet and the lane within this pallet - Msgs, - // implementation of the `RefundCalculator` trait, that is used to compute refund that - // we give to relayer for his transaction - Refund, - // getter for per-message `TransactionPriority` boost that we give to message - // delivery transactions - Priority, - // the runtime-unique identifier of this signed extension - Id, - )>, -); - -impl RefundSignedExtension - for RefundBridgedMessages +/// Verify that the messages pallet call, supported by extension has succeeded. +pub(crate) fn verify_messages_call_succeeded( + call_info: &ExtensionCallInfo< + C::RemoteGrandpaChainBlockNumber, + LaneIdOf, + >, + _call_data: &mut ExtensionCallData, + relayer: &::AccountId, +) -> bool where - Self: 'static + Send + Sync, - Runtime: MessagesConfig + RelayersConfig, - Msgs: RefundableMessagesLaneId, - Refund: RefundCalculator, - Priority: Get, - Id: StaticStrProvider, - CallOf: Dispatchable - + MessagesCallSubType, + C: ExtensionConfig, + C::Runtime: BridgeMessagesConfig, { - type Runtime = Runtime; - type Msgs = Msgs; - type Refund = Refund; - type Priority = Priority; - type Id = Id; - - fn expand_call(call: &CallOf) -> Vec<&CallOf> { - vec![call] - } - - fn parse_and_check_for_obsolete_call( - call: &CallOf, - ) -> Result, TransactionValidityError> { - let call = Self::check_obsolete_parsed_call(call)?; - Ok(call.call_info_for(Msgs::Id::get()).map(CallInfo::Msgs)) - } + let messages_call = call_info.messages_call_info(); - fn check_obsolete_parsed_call( - call: &CallOf, - ) -> Result<&CallOf, TransactionValidityError> { - call.check_obsolete_call()?; - Ok(call) + if !MessagesCallHelper::::was_successful( + messages_call, + ) { + log::trace!( + target: LOG_TARGET, + "{}.{:?}: relayer {:?} has submitted invalid messages call", + C::IdProvider::STR, + call_info.messages_call_info().lane_id(), + relayer, + ); + return false } - fn additional_call_result_check( - _relayer: &Runtime::AccountId, - _call_info: &CallInfo, - _extra_weight: &mut Weight, - _extra_size: &mut u32, - ) -> bool { - // everything is checked by the `RefundTransactionExtension` - true - } + true } #[cfg(test)] -pub(crate) mod tests { +mod tests { use super::*; - use crate::{ - messages_call_ext::{ - BaseMessagesProofInfo, ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, - UnrewardedRelayerOccupation, - }, - mock::*, - }; - use bp_header_chain::StoredHeaderDataBuilder; + use crate::mock::*; + + use bp_header_chain::{StoredHeaderDataBuilder, SubmitFinalityProofInfo}; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, DeliveredMessages, InboundLaneData, - MessageNonce, MessagesOperatingMode, OutboundLaneData, UnrewardedRelayer, - UnrewardedRelayersState, + target_chain::FromBridgedChainMessagesProof, BaseMessagesProofInfo, DeliveredMessages, + InboundLaneData, MessageNonce, MessagesCallInfo, MessagesOperatingMode, OutboundLaneData, + ReceiveMessagesDeliveryProofInfo, ReceiveMessagesProofInfo, UnrewardedRelayer, + UnrewardedRelayerOccupation, UnrewardedRelayersState, }; - use bp_parachains::{BestParaHeadHash, ParaInfo}; + use bp_parachains::{BestParaHeadHash, ParaInfo, SubmitParachainHeadsInfo}; use bp_polkadot_core::parachains::{ParaHeadsProof, ParaId}; - use bp_runtime::{BasicOperatingMode, HeaderId}; + use bp_relayers::RuntimeWithUtilityPallet; + use bp_runtime::{BasicOperatingMode, HeaderId, Parachain}; use bp_test_utils::{make_default_justification, test_keyring, TEST_GRANDPA_SET_ID}; use frame_support::{ + __private::sp_tracing, assert_storage_noop, parameter_types, traits::{fungible::Mutate, ReservableCurrency}, weights::Weight, }; use pallet_bridge_grandpa::{Call as GrandpaCall, Pallet as GrandpaPallet, StoredAuthoritySet}; use pallet_bridge_messages::{Call as MessagesCall, Pallet as MessagesPallet}; - use pallet_bridge_parachains::{ - Call as ParachainsCall, Pallet as ParachainsPallet, RelayBlockHash, - }; + use pallet_bridge_parachains::{Call as ParachainsCall, Pallet as ParachainsPallet}; + use pallet_utility::Call as UtilityCall; use sp_runtime::{ - traits::{ConstU64, Header as HeaderT}, - transaction_validity::{InvalidTransaction, ValidTransaction}, + traits::{ConstU64, DispatchTransaction, Header as HeaderT}, + transaction_validity::{InvalidTransaction, TransactionValidity, ValidTransaction}, DispatchError, }; parameter_types! { - pub TestLaneId: LaneId = TEST_LANE_ID; - pub MsgProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( - TEST_LANE_ID, + TestParachain: u32 = BridgedUnderlyingParachain::PARACHAIN_ID; + pub MsgProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( + test_lane_id(), TEST_BRIDGED_CHAIN_ID, RewardsAccountOwner::ThisChain, ); - pub MsgDeliveryProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( - TEST_LANE_ID, + pub MsgDeliveryProofsRewardsAccount: RewardsAccountParams = RewardsAccountParams::new( + test_lane_id(), TEST_BRIDGED_CHAIN_ID, RewardsAccountOwner::BridgedChain, ); } + bp_runtime::generate_static_str_provider!(TestGrandpaExtension); bp_runtime::generate_static_str_provider!(TestExtension); + bp_runtime::generate_static_str_provider!(TestMessagesExtension); - type TestMessagesExtensionProvider = RefundBridgedMessages< + type TestGrandpaExtensionConfig = grandpa_adapter::WithGrandpaChainExtensionConfig< + StrTestGrandpaExtension, TestRuntime, - RefundableMessagesLane<(), TestLaneId>, - ActualFeeRefund, + RuntimeWithUtilityPallet, + (), + (), + (), ConstU64<1>, - StrTestExtension, >; - type TestMessagesExtension = RefundSignedExtensionAdapter; - type TestGrandpaExtensionProvider = RefundBridgedGrandpaMessages< + type TestGrandpaExtension = + BridgeRelayersTransactionExtension; + type TestExtensionConfig = parachain_adapter::WithParachainExtensionConfig< + StrTestExtension, TestRuntime, + RuntimeWithUtilityPallet, + (), + (), (), - RefundableMessagesLane<(), TestLaneId>, - ActualFeeRefund, ConstU64<1>, - StrTestExtension, >; - type TestGrandpaExtension = RefundSignedExtensionAdapter; - type TestExtensionProvider = RefundBridgedParachainMessages< + type TestExtension = + BridgeRelayersTransactionExtension; + type TestMessagesExtensionConfig = messages_adapter::WithMessagesExtensionConfig< + StrTestMessagesExtension, TestRuntime, - RefundableParachain<(), BridgedUnderlyingParachain>, - RefundableMessagesLane<(), TestLaneId>, - ActualFeeRefund, + (), + (), ConstU64<1>, - StrTestExtension, >; - type TestExtension = RefundSignedExtensionAdapter; + type TestMessagesExtension = BridgeRelayersTransactionExtension< + TestRuntime, + TestMessagesExtensionConfig, + TestLaneIdType, + >; fn initial_balance_of_relayer_account_at_this_chain() -> ThisChainBalance { - let test_stake: ThisChainBalance = TestStake::get(); + let test_stake: ThisChainBalance = Stake::get(); ExistentialDeposit::get().saturating_add(test_stake * 100) } @@ -1026,7 +536,7 @@ pub(crate) mod tests { TestPaymentProcedure::rewards_account(MsgDeliveryProofsRewardsAccount::get()) } - pub fn relayer_account_at_this_chain() -> ThisChainAccountId { + fn relayer_account_at_this_chain() -> ThisChainAccountId { 0 } @@ -1034,13 +544,13 @@ pub(crate) mod tests { 0 } - pub fn initialize_environment( - best_relay_header_number: RelayBlockNumber, - parachain_head_at_relay_header_number: RelayBlockNumber, + fn initialize_environment( + best_relay_header_number: BridgedChainBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) { let authorities = test_keyring().into_iter().map(|(a, w)| (a.into(), w)).collect(); - let best_relay_header = HeaderId(best_relay_header_number, RelayBlockHash::default()); + let best_relay_header = HeaderId(best_relay_header_number, BridgedChainHash::default()); pallet_bridge_grandpa::CurrentAuthoritySet::::put( StoredAuthoritySet::try_new(authorities, TEST_GRANDPA_SET_ID).unwrap(), ); @@ -1050,7 +560,7 @@ pub(crate) mod tests { bp_test_utils::test_header::(0).build(), ); - let para_id = ParaId(BridgedUnderlyingParachain::PARACHAIN_ID); + let para_id = ParaId(TestParachain::get()); let para_info = ParaInfo { best_head_hash: BestParaHeadHash { at_relay_block_number: parachain_head_at_relay_header_number, @@ -1060,7 +570,7 @@ pub(crate) mod tests { }; pallet_bridge_parachains::ParasInfo::::insert(para_id, para_info); - let lane_id = TestLaneId::get(); + let lane_id = test_lane_id(); let in_lane_data = InboundLaneData { last_confirmed_nonce: best_message, ..Default::default() }; pallet_bridge_messages::InboundLanes::::insert(lane_id, in_lane_data); @@ -1078,7 +588,7 @@ pub(crate) mod tests { .unwrap(); } - fn submit_relay_header_call(relay_header_number: RelayBlockNumber) -> RuntimeCall { + fn submit_relay_header_call(relay_header_number: BridgedChainBlockNumber) -> RuntimeCall { let relay_header = BridgedChainHeader::new( relay_header_number, Default::default(), @@ -1094,7 +604,7 @@ pub(crate) mod tests { }) } - pub fn submit_relay_header_call_ex(relay_header_number: RelayBlockNumber) -> RuntimeCall { + fn submit_relay_header_call_ex(relay_header_number: BridgedChainBlockNumber) -> RuntimeCall { let relay_header = BridgedChainHeader::new( relay_header_number, Default::default(), @@ -1113,12 +623,12 @@ pub(crate) mod tests { } fn submit_parachain_head_call( - parachain_head_at_relay_header_number: RelayBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, ) -> RuntimeCall { RuntimeCall::BridgeParachains(ParachainsCall::submit_parachain_heads { - at_relay_block: (parachain_head_at_relay_header_number, RelayBlockHash::default()), + at_relay_block: (parachain_head_at_relay_header_number, BridgedChainHash::default()), parachains: vec![( - ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), + ParaId(TestParachain::get()), [parachain_head_at_relay_header_number as u8; 32].into(), )], parachain_heads_proof: ParaHeadsProof { storage_proof: Default::default() }, @@ -1126,12 +636,12 @@ pub(crate) mod tests { } pub fn submit_parachain_head_call_ex( - parachain_head_at_relay_header_number: RelayBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, ) -> RuntimeCall { RuntimeCall::BridgeParachains(ParachainsCall::submit_parachain_heads_ex { - at_relay_block: (parachain_head_at_relay_header_number, RelayBlockHash::default()), + at_relay_block: (parachain_head_at_relay_header_number, BridgedChainHash::default()), parachains: vec![( - ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), + ParaId(TestParachain::get()), [parachain_head_at_relay_header_number as u8; 32].into(), )], parachain_heads_proof: ParaHeadsProof { storage_proof: Default::default() }, @@ -1145,10 +655,11 @@ pub(crate) mod tests { proof: Box::new(FromBridgedChainMessagesProof { bridged_header_hash: Default::default(), storage_proof: Default::default(), - lane: TestLaneId::get(), + lane: test_lane_id(), nonces_start: pallet_bridge_messages::InboundLanes::::get( - TEST_LANE_ID, + test_lane_id(), ) + .unwrap() .last_delivered_nonce() + 1, nonces_end: best_message, @@ -1163,7 +674,7 @@ pub(crate) mod tests { proof: FromBridgedChainMessagesDeliveryProof { bridged_header_hash: Default::default(), storage_proof: Default::default(), - lane: TestLaneId::get(), + lane: test_lane_id(), }, relayers_state: UnrewardedRelayersState { last_delivered_nonce: best_message, @@ -1173,7 +684,7 @@ pub(crate) mod tests { } fn parachain_finality_and_delivery_batch_call( - parachain_head_at_relay_header_number: RelayBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1185,7 +696,7 @@ pub(crate) mod tests { } fn parachain_finality_and_confirmation_batch_call( - parachain_head_at_relay_header_number: RelayBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1197,7 +708,7 @@ pub(crate) mod tests { } fn relay_finality_and_delivery_batch_call( - relay_header_number: RelayBlockNumber, + relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1209,7 +720,7 @@ pub(crate) mod tests { } fn relay_finality_and_delivery_batch_call_ex( - relay_header_number: RelayBlockNumber, + relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1221,7 +732,7 @@ pub(crate) mod tests { } fn relay_finality_and_confirmation_batch_call( - relay_header_number: RelayBlockNumber, + relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1233,7 +744,7 @@ pub(crate) mod tests { } fn relay_finality_and_confirmation_batch_call_ex( - relay_header_number: RelayBlockNumber, + relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1245,8 +756,8 @@ pub(crate) mod tests { } fn all_finality_and_delivery_batch_call( - relay_header_number: RelayBlockNumber, - parachain_head_at_relay_header_number: RelayBlockNumber, + relay_header_number: BridgedChainBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1259,8 +770,8 @@ pub(crate) mod tests { } fn all_finality_and_delivery_batch_call_ex( - relay_header_number: RelayBlockNumber, - parachain_head_at_relay_header_number: RelayBlockNumber, + relay_header_number: BridgedChainBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1273,8 +784,8 @@ pub(crate) mod tests { } fn all_finality_and_confirmation_batch_call( - relay_header_number: RelayBlockNumber, - parachain_head_at_relay_header_number: RelayBlockNumber, + relay_header_number: BridgedChainBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1287,8 +798,8 @@ pub(crate) mod tests { } fn all_finality_and_confirmation_batch_call_ex( - relay_header_number: RelayBlockNumber, - parachain_head_at_relay_header_number: RelayBlockNumber, + relay_header_number: BridgedChainBlockNumber, + parachain_head_at_relay_header_number: BridgedChainBlockNumber, best_message: MessageNonce, ) -> RuntimeCall { RuntimeCall::Utility(UtilityCall::batch_all { @@ -1300,10 +811,11 @@ pub(crate) mod tests { }) } - fn all_finality_pre_dispatch_data() -> PreDispatchData { + fn all_finality_pre_dispatch_data( + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), - call_info: CallInfo::AllFinalityAndMsgs( + call_info: ExtensionCallInfo::AllFinalityAndMsgs( SubmitFinalityProofInfo { block_number: 200, current_set_id: None, @@ -1314,38 +826,40 @@ pub(crate) mod tests { }, SubmitParachainHeadsInfo { at_relay_block: HeaderId(200, [0u8; 32].into()), - para_id: ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), + para_id: ParaId(TestParachain::get()), para_head_hash: [200u8; 32].into(), is_free_execution_expected: false, }, MessagesCallInfo::ReceiveMessagesProof(ReceiveMessagesProofInfo { base: BaseMessagesProofInfo { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), bundled_range: 101..=200, best_stored_nonce: 100, }, unrewarded_relayers: UnrewardedRelayerOccupation { free_relayer_slots: - BridgedUnderlyingChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + BridgedUnderlyingParachain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, free_message_slots: - BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + BridgedUnderlyingParachain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, }, }), ), } } - fn all_finality_pre_dispatch_data_ex() -> PreDispatchData { + #[cfg(test)] + fn all_finality_pre_dispatch_data_ex( + ) -> PreDispatchData { let mut data = all_finality_pre_dispatch_data(); - data.call_info.submit_finality_proof_info_mut().unwrap().current_set_id = - Some(TEST_GRANDPA_SET_ID); + data.submit_finality_proof_info_mut().unwrap().current_set_id = Some(TEST_GRANDPA_SET_ID); data } - fn all_finality_confirmation_pre_dispatch_data() -> PreDispatchData { + fn all_finality_confirmation_pre_dispatch_data( + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), - call_info: CallInfo::AllFinalityAndMsgs( + call_info: ExtensionCallInfo::AllFinalityAndMsgs( SubmitFinalityProofInfo { block_number: 200, current_set_id: None, @@ -1356,13 +870,13 @@ pub(crate) mod tests { }, SubmitParachainHeadsInfo { at_relay_block: HeaderId(200, [0u8; 32].into()), - para_id: ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), + para_id: ParaId(TestParachain::get()), para_head_hash: [200u8; 32].into(), is_free_execution_expected: false, }, MessagesCallInfo::ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo( BaseMessagesProofInfo { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), bundled_range: 101..=200, best_stored_nonce: 100, }, @@ -1371,17 +885,18 @@ pub(crate) mod tests { } } - fn all_finality_confirmation_pre_dispatch_data_ex() -> PreDispatchData { + fn all_finality_confirmation_pre_dispatch_data_ex( + ) -> PreDispatchData { let mut data = all_finality_confirmation_pre_dispatch_data(); - data.call_info.submit_finality_proof_info_mut().unwrap().current_set_id = - Some(TEST_GRANDPA_SET_ID); + data.submit_finality_proof_info_mut().unwrap().current_set_id = Some(TEST_GRANDPA_SET_ID); data } - fn relay_finality_pre_dispatch_data() -> PreDispatchData { + fn relay_finality_pre_dispatch_data( + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), - call_info: CallInfo::RelayFinalityAndMsgs( + call_info: ExtensionCallInfo::RelayFinalityAndMsgs( SubmitFinalityProofInfo { block_number: 200, current_set_id: None, @@ -1392,32 +907,33 @@ pub(crate) mod tests { }, MessagesCallInfo::ReceiveMessagesProof(ReceiveMessagesProofInfo { base: BaseMessagesProofInfo { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), bundled_range: 101..=200, best_stored_nonce: 100, }, unrewarded_relayers: UnrewardedRelayerOccupation { free_relayer_slots: - BridgedUnderlyingChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + BridgedUnderlyingParachain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, free_message_slots: - BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + BridgedUnderlyingParachain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, }, }), ), } } - fn relay_finality_pre_dispatch_data_ex() -> PreDispatchData { + fn relay_finality_pre_dispatch_data_ex( + ) -> PreDispatchData { let mut data = relay_finality_pre_dispatch_data(); - data.call_info.submit_finality_proof_info_mut().unwrap().current_set_id = - Some(TEST_GRANDPA_SET_ID); + data.submit_finality_proof_info_mut().unwrap().current_set_id = Some(TEST_GRANDPA_SET_ID); data } - fn relay_finality_confirmation_pre_dispatch_data() -> PreDispatchData { + fn relay_finality_confirmation_pre_dispatch_data( + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), - call_info: CallInfo::RelayFinalityAndMsgs( + call_info: ExtensionCallInfo::RelayFinalityAndMsgs( SubmitFinalityProofInfo { block_number: 200, current_set_id: None, @@ -1428,7 +944,7 @@ pub(crate) mod tests { }, MessagesCallInfo::ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo( BaseMessagesProofInfo { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), bundled_range: 101..=200, best_stored_nonce: 100, }, @@ -1437,53 +953,55 @@ pub(crate) mod tests { } } - fn relay_finality_confirmation_pre_dispatch_data_ex() -> PreDispatchData { + fn relay_finality_confirmation_pre_dispatch_data_ex( + ) -> PreDispatchData { let mut data = relay_finality_confirmation_pre_dispatch_data(); - data.call_info.submit_finality_proof_info_mut().unwrap().current_set_id = - Some(TEST_GRANDPA_SET_ID); + data.submit_finality_proof_info_mut().unwrap().current_set_id = Some(TEST_GRANDPA_SET_ID); data } - fn parachain_finality_pre_dispatch_data() -> PreDispatchData { + fn parachain_finality_pre_dispatch_data( + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), - call_info: CallInfo::ParachainFinalityAndMsgs( + call_info: ExtensionCallInfo::ParachainFinalityAndMsgs( SubmitParachainHeadsInfo { at_relay_block: HeaderId(200, [0u8; 32].into()), - para_id: ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), + para_id: ParaId(TestParachain::get()), para_head_hash: [200u8; 32].into(), is_free_execution_expected: false, }, MessagesCallInfo::ReceiveMessagesProof(ReceiveMessagesProofInfo { base: BaseMessagesProofInfo { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), bundled_range: 101..=200, best_stored_nonce: 100, }, unrewarded_relayers: UnrewardedRelayerOccupation { free_relayer_slots: - BridgedUnderlyingChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + BridgedUnderlyingParachain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, free_message_slots: - BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + BridgedUnderlyingParachain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, }, }), ), } } - fn parachain_finality_confirmation_pre_dispatch_data() -> PreDispatchData { + fn parachain_finality_confirmation_pre_dispatch_data( + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), - call_info: CallInfo::ParachainFinalityAndMsgs( + call_info: ExtensionCallInfo::ParachainFinalityAndMsgs( SubmitParachainHeadsInfo { at_relay_block: HeaderId(200, [0u8; 32].into()), - para_id: ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), + para_id: ParaId(TestParachain::get()), para_head_hash: [200u8; 32].into(), is_free_execution_expected: false, }, MessagesCallInfo::ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo( BaseMessagesProofInfo { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), bundled_range: 101..=200, best_stored_nonce: 100, }, @@ -1492,33 +1010,35 @@ pub(crate) mod tests { } } - fn delivery_pre_dispatch_data() -> PreDispatchData { + fn delivery_pre_dispatch_data( + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), - call_info: CallInfo::Msgs(MessagesCallInfo::ReceiveMessagesProof( + call_info: ExtensionCallInfo::Msgs(MessagesCallInfo::ReceiveMessagesProof( ReceiveMessagesProofInfo { base: BaseMessagesProofInfo { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), bundled_range: 101..=200, best_stored_nonce: 100, }, unrewarded_relayers: UnrewardedRelayerOccupation { free_relayer_slots: - BridgedUnderlyingChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + BridgedUnderlyingParachain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, free_message_slots: - BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + BridgedUnderlyingParachain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, }, }, )), } } - fn confirmation_pre_dispatch_data() -> PreDispatchData { + fn confirmation_pre_dispatch_data( + ) -> PreDispatchData { PreDispatchData { relayer: relayer_account_at_this_chain(), - call_info: CallInfo::Msgs(MessagesCallInfo::ReceiveMessagesDeliveryProof( + call_info: ExtensionCallInfo::Msgs(MessagesCallInfo::ReceiveMessagesDeliveryProof( ReceiveMessagesDeliveryProofInfo(BaseMessagesProofInfo { - lane_id: TEST_LANE_ID, + lane_id: test_lane_id(), bundled_range: 101..=200, best_stored_nonce: 100, }), @@ -1527,14 +1047,18 @@ pub(crate) mod tests { } fn set_bundled_range_end( - mut pre_dispatch_data: PreDispatchData, + mut pre_dispatch_data: PreDispatchData< + ThisChainAccountId, + BridgedChainBlockNumber, + TestLaneIdType, + >, end: MessageNonce, - ) -> PreDispatchData { + ) -> PreDispatchData { let msg_info = match pre_dispatch_data.call_info { - CallInfo::AllFinalityAndMsgs(_, _, ref mut info) => info, - CallInfo::RelayFinalityAndMsgs(_, ref mut info) => info, - CallInfo::ParachainFinalityAndMsgs(_, ref mut info) => info, - CallInfo::Msgs(ref mut info) => info, + ExtensionCallInfo::AllFinalityAndMsgs(_, _, ref mut info) => info, + ExtensionCallInfo::RelayFinalityAndMsgs(_, ref mut info) => info, + ExtensionCallInfo::ParachainFinalityAndMsgs(_, ref mut info) => info, + ExtensionCallInfo::Msgs(ref mut info) => info, }; if let MessagesCallInfo::ReceiveMessagesProof(ref mut msg_info) = msg_info { @@ -1545,21 +1069,39 @@ pub(crate) mod tests { } fn run_validate(call: RuntimeCall) -> TransactionValidity { - let extension: TestExtension = - RefundSignedExtensionAdapter(RefundBridgedParachainMessages(PhantomData)); - extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + let extension: TestExtension = BridgeRelayersTransactionExtension(PhantomData); + extension + .validate_only( + Some(relayer_account_at_this_chain()).into(), + &call, + &DispatchInfo::default(), + 0, + ) + .map(|t| t.0) } fn run_grandpa_validate(call: RuntimeCall) -> TransactionValidity { - let extension: TestGrandpaExtension = - RefundSignedExtensionAdapter(RefundBridgedGrandpaMessages(PhantomData)); - extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + let extension: TestGrandpaExtension = BridgeRelayersTransactionExtension(PhantomData); + extension + .validate_only( + Some(relayer_account_at_this_chain()).into(), + &call, + &DispatchInfo::default(), + 0, + ) + .map(|t| t.0) } fn run_messages_validate(call: RuntimeCall) -> TransactionValidity { - let extension: TestMessagesExtension = - RefundSignedExtensionAdapter(RefundBridgedMessages(PhantomData)); - extension.validate(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + let extension: TestMessagesExtension = BridgeRelayersTransactionExtension(PhantomData); + extension + .validate_only( + Some(relayer_account_at_this_chain()).into(), + &call, + &DispatchInfo::default(), + 0, + ) + .map(|t| t.0) } fn ignore_priority(tx: TransactionValidity) -> TransactionValidity { @@ -1571,34 +1113,63 @@ pub(crate) mod tests { fn run_pre_dispatch( call: RuntimeCall, - ) -> Result>, TransactionValidityError> { - let extension: TestExtension = - RefundSignedExtensionAdapter(RefundBridgedParachainMessages(PhantomData)); - extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + ) -> Result< + Option>, + TransactionValidityError, + > { + sp_tracing::try_init_simple(); + let extension: TestExtension = BridgeRelayersTransactionExtension(PhantomData); + extension + .validate_and_prepare( + Some(relayer_account_at_this_chain()).into(), + &call, + &DispatchInfo::default(), + 0, + ) + .map(|(pre, _)| pre) } fn run_grandpa_pre_dispatch( call: RuntimeCall, - ) -> Result>, TransactionValidityError> { - let extension: TestGrandpaExtension = - RefundSignedExtensionAdapter(RefundBridgedGrandpaMessages(PhantomData)); - extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + ) -> Result< + Option>, + TransactionValidityError, + > { + let extension: TestGrandpaExtension = BridgeRelayersTransactionExtension(PhantomData); + extension + .validate_and_prepare( + Some(relayer_account_at_this_chain()).into(), + &call, + &DispatchInfo::default(), + 0, + ) + .map(|(pre, _)| pre) } fn run_messages_pre_dispatch( call: RuntimeCall, - ) -> Result>, TransactionValidityError> { - let extension: TestMessagesExtension = - RefundSignedExtensionAdapter(RefundBridgedMessages(PhantomData)); - extension.pre_dispatch(&relayer_account_at_this_chain(), &call, &DispatchInfo::default(), 0) + ) -> Result< + Option>, + TransactionValidityError, + > { + let extension: TestMessagesExtension = BridgeRelayersTransactionExtension(PhantomData); + extension + .validate_and_prepare( + Some(relayer_account_at_this_chain()).into(), + &call, + &DispatchInfo::default(), + 0, + ) + .map(|(pre, _)| pre) } fn dispatch_info() -> DispatchInfo { DispatchInfo { - weight: Weight::from_parts( + call_weight: Weight::from_parts( frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND, 0, ), + extension_weight: Weight::zero(), class: frame_support::dispatch::DispatchClass::Normal, pays_fee: frame_support::dispatch::Pays::Yes, } @@ -1609,24 +1180,26 @@ pub(crate) mod tests { } fn run_post_dispatch( - pre_dispatch_data: Option>, + pre_dispatch_data: Option< + PreDispatchData, + >, dispatch_result: DispatchResult, ) { - let post_dispatch_result = TestExtension::post_dispatch( - Some(pre_dispatch_data), + let post_dispatch_result = TestExtension::post_dispatch_details( + pre_dispatch_data, &dispatch_info(), &post_dispatch_info(), 1024, &dispatch_result, ); - assert_eq!(post_dispatch_result, Ok(())); + assert_eq!(post_dispatch_result, Ok(Weight::zero())); } fn expected_delivery_reward() -> ThisChainBalance { let mut post_dispatch_info = post_dispatch_info(); let extra_weight = ::WeightInfo::extra_weight_of_successful_receive_messages_proof_call(); post_dispatch_info.actual_weight = - Some(dispatch_info().weight.saturating_sub(extra_weight)); + Some(dispatch_info().call_weight.saturating_sub(extra_weight)); pallet_transaction_payment::Pallet::::compute_actual_fee( 1024, &dispatch_info(), @@ -1651,46 +1224,28 @@ pub(crate) mod tests { Balances::set_balance(&relayer_account_at_this_chain(), ExistentialDeposit::get()); // message delivery is failing - let fns = [run_validate, run_grandpa_validate, run_messages_validate]; - for f in fns { - assert_eq!(f(message_delivery_call(200)), Ok(Default::default()),); - assert_eq!( - f(parachain_finality_and_delivery_batch_call(200, 200)), - Ok(Default::default()), - ); - assert_eq!( - f(all_finality_and_delivery_batch_call(200, 200, 200)), - Ok(Default::default()), - ); - assert_eq!( - f(all_finality_and_delivery_batch_call_ex(200, 200, 200)), - Ok(Default::default()), - ); - } - - // message confirmation validation is passing + assert_eq!(run_validate(message_delivery_call(200)), Ok(Default::default()),); assert_eq!( - ignore_priority(run_validate(message_confirmation_call(200))), + run_validate(parachain_finality_and_delivery_batch_call(200, 200)), Ok(Default::default()), ); assert_eq!( - ignore_priority(run_messages_validate(message_confirmation_call(200))), + run_validate(all_finality_and_delivery_batch_call(200, 200, 200)), Ok(Default::default()), ); + // message confirmation validation is passing assert_eq!( - ignore_priority(run_validate(parachain_finality_and_confirmation_batch_call( - 200, 200 - ))), + ignore_priority(run_validate(message_confirmation_call(200))), Ok(Default::default()), ); assert_eq!( - ignore_priority(run_validate(all_finality_and_confirmation_batch_call( - 200, 200, 200 + ignore_priority(run_validate(parachain_finality_and_confirmation_batch_call( + 200, 200 ))), Ok(Default::default()), ); assert_eq!( - ignore_priority(run_validate(all_finality_and_confirmation_batch_call_ex( + ignore_priority(run_validate(all_finality_and_confirmation_batch_call( 200, 200, 200 ))), Ok(Default::default()), @@ -1706,28 +1261,25 @@ pub(crate) mod tests { BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000) .unwrap(); - let fns = [run_validate, run_grandpa_validate, run_messages_validate]; - for f in fns { - let priority_of_100_messages_delivery = - f(message_delivery_call(200)).unwrap().priority; - let priority_of_200_messages_delivery = - f(message_delivery_call(300)).unwrap().priority; - assert!( - priority_of_200_messages_delivery > priority_of_100_messages_delivery, - "Invalid priorities: {} for 200 messages vs {} for 100 messages", - priority_of_200_messages_delivery, - priority_of_100_messages_delivery, - ); + let priority_of_100_messages_delivery = + run_validate(message_delivery_call(200)).unwrap().priority; + let priority_of_200_messages_delivery = + run_validate(message_delivery_call(300)).unwrap().priority; + assert!( + priority_of_200_messages_delivery > priority_of_100_messages_delivery, + "Invalid priorities: {} for 200 messages vs {} for 100 messages", + priority_of_200_messages_delivery, + priority_of_100_messages_delivery, + ); - let priority_of_100_messages_confirmation = - f(message_confirmation_call(200)).unwrap().priority; - let priority_of_200_messages_confirmation = - f(message_confirmation_call(300)).unwrap().priority; - assert_eq!( - priority_of_100_messages_confirmation, - priority_of_200_messages_confirmation - ); - } + let priority_of_100_messages_confirmation = + run_validate(message_confirmation_call(200)).unwrap().priority; + let priority_of_200_messages_confirmation = + run_validate(message_confirmation_call(300)).unwrap().priority; + assert_eq!( + priority_of_100_messages_confirmation, + priority_of_200_messages_confirmation + ); }); } @@ -1739,26 +1291,23 @@ pub(crate) mod tests { BridgeRelayers::register(RuntimeOrigin::signed(relayer_account_at_this_chain()), 1000) .unwrap(); - let fns = [run_validate, run_grandpa_validate, run_messages_validate]; - for f in fns { - let priority_of_max_messages_delivery = f(message_delivery_call( - 100 + BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, - )) - .unwrap() - .priority; - let priority_of_more_than_max_messages_delivery = f(message_delivery_call( - 100 + BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX + 1, - )) - .unwrap() - .priority; + let priority_of_max_messages_delivery = run_validate(message_delivery_call( + 100 + BridgedUnderlyingParachain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + )) + .unwrap() + .priority; + let priority_of_more_than_max_messages_delivery = run_validate(message_delivery_call( + 100 + BridgedUnderlyingParachain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX + 1, + )) + .unwrap() + .priority; - assert!( - priority_of_max_messages_delivery > priority_of_more_than_max_messages_delivery, - "Invalid priorities: {} for MAX messages vs {} for MAX+1 messages", - priority_of_max_messages_delivery, - priority_of_more_than_max_messages_delivery, - ); - } + assert!( + priority_of_max_messages_delivery > priority_of_more_than_max_messages_delivery, + "Invalid priorities: {} for MAX messages vs {} for MAX+1 messages", + priority_of_max_messages_delivery, + priority_of_more_than_max_messages_delivery, + ); }); } @@ -1775,15 +1324,10 @@ pub(crate) mod tests { ignore_priority(run_validate(message_confirmation_call(200))), Ok(ValidTransaction::default()), ); - assert_eq!( ignore_priority(run_messages_validate(message_delivery_call(200))), Ok(ValidTransaction::default()), ); - assert_eq!( - ignore_priority(run_messages_validate(message_confirmation_call(200))), - Ok(ValidTransaction::default()), - ); assert_eq!( ignore_priority(run_validate(parachain_finality_and_delivery_batch_call(200, 200))), @@ -1800,24 +1344,12 @@ pub(crate) mod tests { ignore_priority(run_validate(all_finality_and_delivery_batch_call(200, 200, 200))), Ok(ValidTransaction::default()), ); - assert_eq!( - ignore_priority(run_validate(all_finality_and_delivery_batch_call_ex( - 200, 200, 200 - ))), - Ok(ValidTransaction::default()), - ); assert_eq!( ignore_priority(run_validate(all_finality_and_confirmation_batch_call( 200, 200, 200 ))), Ok(ValidTransaction::default()), ); - assert_eq!( - ignore_priority(run_validate(all_finality_and_confirmation_batch_call_ex( - 200, 200, 200 - ))), - Ok(ValidTransaction::default()), - ); }); } @@ -2103,13 +1635,10 @@ pub(crate) mod tests { let call = RuntimeCall::Utility(UtilityCall::batch_all { calls: vec![ RuntimeCall::BridgeParachains(ParachainsCall::submit_parachain_heads { - at_relay_block: (100, RelayBlockHash::default()), + at_relay_block: (100, BridgedChainHash::default()), parachains: vec![ - (ParaId(BridgedUnderlyingParachain::PARACHAIN_ID), [1u8; 32].into()), - ( - ParaId(BridgedUnderlyingParachain::PARACHAIN_ID + 1), - [1u8; 32].into(), - ), + (ParaId(TestParachain::get()), [1u8; 32].into()), + (ParaId(TestParachain::get() + 1), [1u8; 32].into()), ], parachain_heads_proof: ParaHeadsProof { storage_proof: Default::default() }, }), @@ -2230,7 +1759,7 @@ pub(crate) mod tests { initialize_environment(200, 200, 200); let mut dispatch_info = dispatch_info(); - dispatch_info.weight = Weight::from_parts( + dispatch_info.call_weight = Weight::from_parts( frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND * 2, 0, ); @@ -2250,7 +1779,7 @@ pub(crate) mod tests { // now repeat the same with size+weight refund: we expect smaller reward let mut pre_dispatch_data = all_finality_pre_dispatch_data(); match pre_dispatch_data.call_info { - CallInfo::AllFinalityAndMsgs(ref mut info, ..) => { + ExtensionCallInfo::AllFinalityAndMsgs(ref mut info, ..) => { info.extra_weight.set_ref_time( frame_support::weights::constants::WEIGHT_REF_TIME_PER_SECOND, ); @@ -2356,7 +1885,7 @@ pub(crate) mod tests { let delivery_rewards_account_balance = Balances::free_balance(delivery_rewards_account()); - let test_stake: ThisChainBalance = TestStake::get(); + let test_stake: ThisChainBalance = Stake::get(); Balances::set_balance( &relayer_account_at_this_chain(), ExistentialDeposit::get() + test_stake * 10, @@ -2426,11 +1955,15 @@ pub(crate) mod tests { } fn run_analyze_call_result( - pre_dispatch_data: PreDispatchData, + pre_dispatch_data: PreDispatchData< + ThisChainAccountId, + BridgedChainBlockNumber, + TestLaneIdType, + >, dispatch_result: DispatchResult, - ) -> RelayerAccountAction { - TestExtensionProvider::analyze_call_result( - Some(Some(pre_dispatch_data)), + ) -> RelayerAccountAction { + TestExtension::analyze_call_result( + Some(pre_dispatch_data), &dispatch_info(), &post_dispatch_info(), 1024, @@ -2494,41 +2027,29 @@ pub(crate) mod tests { } #[test] - fn messages_ext_only_parses_standalone_transactions() { + fn grandpa_ext_only_parses_valid_batches() { run_test(|| { initialize_environment(100, 100, 100); // relay + parachain + message delivery calls batch is ignored assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + TestGrandpaExtensionConfig::parse_and_check_for_obsolete_call( &all_finality_and_delivery_batch_call(200, 200, 200) ), Ok(None), ); - assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - &all_finality_and_delivery_batch_call_ex(200, 200, 200) - ), - Ok(None), - ); // relay + parachain + message confirmation calls batch is ignored assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + TestGrandpaExtensionConfig::parse_and_check_for_obsolete_call( &all_finality_and_confirmation_batch_call(200, 200, 200) ), Ok(None), ); - assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - &all_finality_and_confirmation_batch_call_ex(200, 200, 200) - ), - Ok(None), - ); // parachain + message delivery call batch is ignored assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + TestGrandpaExtensionConfig::parse_and_check_for_obsolete_call( ¶chain_finality_and_delivery_batch_call(200, 200) ), Ok(None), @@ -2536,43 +2057,31 @@ pub(crate) mod tests { // parachain + message confirmation call batch is ignored assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + TestGrandpaExtensionConfig::parse_and_check_for_obsolete_call( ¶chain_finality_and_confirmation_batch_call(200, 200) ), Ok(None), ); - // relay + message delivery call batch is ignored + // relay + message delivery call batch is accepted assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + TestGrandpaExtensionConfig::parse_and_check_for_obsolete_call( &relay_finality_and_delivery_batch_call(200, 200) ), - Ok(None), - ); - assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - &relay_finality_and_delivery_batch_call_ex(200, 200) - ), - Ok(None), + Ok(Some(relay_finality_pre_dispatch_data().call_info)), ); - // relay + message confirmation call batch is ignored + // relay + message confirmation call batch is accepted assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + TestGrandpaExtensionConfig::parse_and_check_for_obsolete_call( &relay_finality_and_confirmation_batch_call(200, 200) ), - Ok(None), - ); - assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( - &relay_finality_and_confirmation_batch_call_ex(200, 200) - ), - Ok(None), + Ok(Some(relay_finality_confirmation_pre_dispatch_data().call_info)), ); // message delivery call batch is accepted assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + TestGrandpaExtensionConfig::parse_and_check_for_obsolete_call( &message_delivery_call(200) ), Ok(Some(delivery_pre_dispatch_data().call_info)), @@ -2580,7 +2089,7 @@ pub(crate) mod tests { // message confirmation call batch is accepted assert_eq!( - TestMessagesExtensionProvider::parse_and_check_for_obsolete_call( + TestGrandpaExtensionConfig::parse_and_check_for_obsolete_call( &message_confirmation_call(200) ), Ok(Some(confirmation_pre_dispatch_data().call_info)), @@ -2589,66 +2098,19 @@ pub(crate) mod tests { } #[test] - fn messages_ext_rejects_calls_with_obsolete_messages() { - run_test(|| { - initialize_environment(100, 100, 100); - - assert_eq!( - run_messages_pre_dispatch(message_delivery_call(100)), - Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), - ); - assert_eq!( - run_messages_pre_dispatch(message_confirmation_call(100)), - Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), - ); - - assert_eq!( - run_messages_validate(message_delivery_call(100)), - Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), - ); - assert_eq!( - run_messages_validate(message_confirmation_call(100)), - Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), - ); - }); - } - - #[test] - fn messages_ext_accepts_calls_with_new_messages() { - run_test(|| { - initialize_environment(100, 100, 100); - - assert_eq!( - run_messages_pre_dispatch(message_delivery_call(200)), - Ok(Some(delivery_pre_dispatch_data())), - ); - assert_eq!( - run_messages_pre_dispatch(message_confirmation_call(200)), - Ok(Some(confirmation_pre_dispatch_data())), - ); - - assert_eq!(run_messages_validate(message_delivery_call(200)), Ok(Default::default()),); - assert_eq!( - run_messages_validate(message_confirmation_call(200)), - Ok(Default::default()), - ); - }); - } - - #[test] - fn grandpa_ext_only_parses_valid_batches() { + fn messages_ext_only_parses_standalone_transactions() { run_test(|| { initialize_environment(100, 100, 100); // relay + parachain + message delivery calls batch is ignored assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( &all_finality_and_delivery_batch_call(200, 200, 200) ), Ok(None), ); assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( &all_finality_and_delivery_batch_call_ex(200, 200, 200) ), Ok(None), @@ -2656,13 +2118,13 @@ pub(crate) mod tests { // relay + parachain + message confirmation calls batch is ignored assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( &all_finality_and_confirmation_batch_call(200, 200, 200) ), Ok(None), ); assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( &all_finality_and_confirmation_batch_call_ex(200, 200, 200) ), Ok(None), @@ -2670,7 +2132,7 @@ pub(crate) mod tests { // parachain + message delivery call batch is ignored assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( ¶chain_finality_and_delivery_batch_call(200, 200) ), Ok(None), @@ -2678,43 +2140,43 @@ pub(crate) mod tests { // parachain + message confirmation call batch is ignored assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( ¶chain_finality_and_confirmation_batch_call(200, 200) ), Ok(None), ); - // relay + message delivery call batch is accepted + // relay + message delivery call batch is ignored assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( &relay_finality_and_delivery_batch_call(200, 200) ), - Ok(Some(relay_finality_pre_dispatch_data().call_info)), + Ok(None), ); assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( &relay_finality_and_delivery_batch_call_ex(200, 200) ), - Ok(Some(relay_finality_pre_dispatch_data_ex().call_info)), + Ok(None), ); - // relay + message confirmation call batch is accepted + // relay + message confirmation call batch is ignored assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( &relay_finality_and_confirmation_batch_call(200, 200) ), - Ok(Some(relay_finality_confirmation_pre_dispatch_data().call_info)), + Ok(None), ); assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( &relay_finality_and_confirmation_batch_call_ex(200, 200) ), - Ok(Some(relay_finality_confirmation_pre_dispatch_data_ex().call_info)), + Ok(None), ); // message delivery call batch is accepted assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( &message_delivery_call(200) ), Ok(Some(delivery_pre_dispatch_data().call_info)), @@ -2722,7 +2184,7 @@ pub(crate) mod tests { // message confirmation call batch is accepted assert_eq!( - TestGrandpaExtensionProvider::parse_and_check_for_obsolete_call( + TestMessagesExtensionConfig::parse_and_check_for_obsolete_call( &message_confirmation_call(200) ), Ok(Some(confirmation_pre_dispatch_data().call_info)), @@ -2730,6 +2192,53 @@ pub(crate) mod tests { }); } + #[test] + fn messages_ext_rejects_calls_with_obsolete_messages() { + run_test(|| { + initialize_environment(100, 100, 100); + + assert_eq!( + run_messages_pre_dispatch(message_delivery_call(100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + assert_eq!( + run_messages_pre_dispatch(message_confirmation_call(100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + + assert_eq!( + run_messages_validate(message_delivery_call(100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + assert_eq!( + run_messages_validate(message_confirmation_call(100)), + Err(TransactionValidityError::Invalid(InvalidTransaction::Stale)), + ); + }); + } + + #[test] + fn messages_ext_accepts_calls_with_new_messages() { + run_test(|| { + initialize_environment(100, 100, 100); + + assert_eq!( + run_messages_pre_dispatch(message_delivery_call(200)), + Ok(Some(delivery_pre_dispatch_data())), + ); + assert_eq!( + run_messages_pre_dispatch(message_confirmation_call(200)), + Ok(Some(confirmation_pre_dispatch_data())), + ); + + assert_eq!(run_messages_validate(message_delivery_call(200)), Ok(Default::default()),); + assert_eq!( + run_messages_validate(message_confirmation_call(200)), + Ok(Default::default()), + ); + }); + } + #[test] fn grandpa_ext_rejects_batch_with_obsolete_relay_chain_header() { run_test(|| { @@ -2874,7 +2383,7 @@ pub(crate) mod tests { fn does_not_panic_on_boosting_priority_of_empty_message_delivery_transaction() { run_test(|| { let best_delivered_message = - BridgedUnderlyingChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + BridgedUnderlyingParachain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; initialize_environment(100, 100, best_delivered_message); // register relayer so it gets priority boost @@ -2882,7 +2391,7 @@ pub(crate) mod tests { .unwrap(); // allow empty message delivery transactions - let lane_id = TestLaneId::get(); + let lane_id = test_lane_id(); let in_lane_data = InboundLaneData { last_confirmed_nonce: 0, relayers: vec![UnrewardedRelayer { @@ -2890,6 +2399,7 @@ pub(crate) mod tests { messages: DeliveredMessages { begin: 1, end: best_delivered_message }, }] .into(), + ..Default::default() }; pallet_bridge_messages::InboundLanes::::insert(lane_id, in_lane_data); diff --git a/bridges/modules/relayers/src/extension/parachain_adapter.rs b/bridges/modules/relayers/src/extension/parachain_adapter.rs new file mode 100644 index 000000000000..69cf766dd674 --- /dev/null +++ b/bridges/modules/relayers/src/extension/parachain_adapter.rs @@ -0,0 +1,188 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Adapter that allows using `pallet-bridge-relayers` as a signed extension in the +//! bridge with remote parachain. + +use crate::{ + extension::{ + grandpa_adapter::verify_submit_finality_proof_succeeded, verify_messages_call_succeeded, + }, + Config as BridgeRelayersConfig, LOG_TARGET, +}; + +use bp_relayers::{BatchCallUnpacker, ExtensionCallData, ExtensionCallInfo, ExtensionConfig}; +use bp_runtime::{Parachain, StaticStrProvider}; +use frame_support::dispatch::{DispatchInfo, PostDispatchInfo}; +use frame_system::Config as SystemConfig; +use pallet_bridge_grandpa::{ + CallSubType as BridgeGrandpaCallSubtype, Config as BridgeGrandpaConfig, +}; +use pallet_bridge_messages::{ + CallSubType as BridgeMessagesCallSubType, Config as BridgeMessagesConfig, LaneIdOf, +}; +use pallet_bridge_parachains::{ + CallSubType as BridgeParachainsCallSubtype, Config as BridgeParachainsConfig, + SubmitParachainHeadsHelper, +}; +use sp_runtime::{ + traits::{Dispatchable, Get}, + transaction_validity::{TransactionPriority, TransactionValidityError}, +}; +use sp_std::marker::PhantomData; + +/// Adapter to be used in signed extension configuration, when bridging with remote parachains. +pub struct WithParachainExtensionConfig< + // signed extension identifier + IdProvider, + // runtime that implements `BridgeMessagesConfig`, which + // uses `BridgeParachainsConfig` to receive messages and + // confirmations from the remote chain. + Runtime, + // batch call unpacker + BatchCallUnpacker, + // instance of the `pallet-bridge-parachains`, tracked by this extension + BridgeParachainsPalletInstance, + // instance of BridgedChain `pallet-bridge-messages`, tracked by this extension + BridgeMessagesPalletInstance, + // instance of `pallet-bridge-relayers`, tracked by this extension + BridgeRelayersPalletInstance, + // message delivery transaction priority boost for every additional message + PriorityBoostPerMessage, +>( + PhantomData<( + IdProvider, + Runtime, + BatchCallUnpacker, + BridgeParachainsPalletInstance, + BridgeMessagesPalletInstance, + BridgeRelayersPalletInstance, + PriorityBoostPerMessage, + )>, +); + +impl ExtensionConfig + for WithParachainExtensionConfig +where + ID: StaticStrProvider, + R: BridgeRelayersConfig + + BridgeMessagesConfig + + BridgeParachainsConfig + + BridgeGrandpaConfig, + BCU: BatchCallUnpacker, + PI: 'static, + MI: 'static, + RI: 'static, + P: Get, + R::RuntimeCall: Dispatchable + + BridgeGrandpaCallSubtype + + BridgeParachainsCallSubtype + + BridgeMessagesCallSubType, + >::BridgedChain: Parachain, +{ + type IdProvider = ID; + type Runtime = R; + type BridgeMessagesPalletInstance = MI; + type BridgeRelayersPalletInstance = RI; + type PriorityBoostPerMessage = P; + type RemoteGrandpaChainBlockNumber = + pallet_bridge_grandpa::BridgedBlockNumber; + type LaneId = LaneIdOf; + + fn parse_and_check_for_obsolete_call( + call: &R::RuntimeCall, + ) -> Result< + Option>, + TransactionValidityError, + > { + let calls = BCU::unpack(call, 3); + let total_calls = calls.len(); + let mut calls = calls.into_iter().map(Self::check_obsolete_parsed_call).rev(); + + let msgs_call = calls.next().transpose()?.and_then(|c| c.call_info()); + let para_finality_call = calls.next().transpose()?.and_then(|c| { + let r = c.submit_parachain_heads_info_for( + >::BridgedChain::PARACHAIN_ID, + ); + r + }); + let relay_finality_call = + calls.next().transpose()?.and_then(|c| c.submit_finality_proof_info()); + Ok(match (total_calls, relay_finality_call, para_finality_call, msgs_call) { + (3, Some(relay_finality_call), Some(para_finality_call), Some(msgs_call)) => + Some(ExtensionCallInfo::AllFinalityAndMsgs( + relay_finality_call, + para_finality_call, + msgs_call, + )), + (2, None, Some(para_finality_call), Some(msgs_call)) => + Some(ExtensionCallInfo::ParachainFinalityAndMsgs(para_finality_call, msgs_call)), + (1, None, None, Some(msgs_call)) => Some(ExtensionCallInfo::Msgs(msgs_call)), + _ => None, + }) + } + + fn check_obsolete_parsed_call( + call: &R::RuntimeCall, + ) -> Result<&R::RuntimeCall, TransactionValidityError> { + call.check_obsolete_submit_finality_proof()?; + call.check_obsolete_submit_parachain_heads()?; + call.check_obsolete_call()?; + Ok(call) + } + + fn check_call_result( + call_info: &ExtensionCallInfo, + call_data: &mut ExtensionCallData, + relayer: &R::AccountId, + ) -> bool { + verify_submit_finality_proof_succeeded::( + call_info, call_data, relayer, + ) && verify_submit_parachain_head_succeeded::(call_info, call_data, relayer) && + verify_messages_call_succeeded::(call_info, call_data, relayer) + } +} + +/// If the batch call contains the parachain state update call, verify that it +/// has been successful. +/// +/// Only returns false when parachain state update call has failed. +pub(crate) fn verify_submit_parachain_head_succeeded( + call_info: &ExtensionCallInfo, + _call_data: &mut ExtensionCallData, + relayer: &::AccountId, +) -> bool +where + C: ExtensionConfig, + PI: 'static, + C::Runtime: BridgeParachainsConfig, +{ + let Some(para_proof_info) = call_info.submit_parachain_heads_info() else { return true }; + + if !SubmitParachainHeadsHelper::::was_successful(para_proof_info) { + // we only refund relayer if all calls have updated chain state + log::trace!( + target: LOG_TARGET, + "{}.{:?}: relayer {:?} has submitted invalid parachain finality proof", + C::IdProvider::STR, + call_info.messages_call_info().lane_id(), + relayer, + ); + return false + } + + true +} diff --git a/bridges/bin/runtime-common/src/extensions/priority_calculator.rs b/bridges/modules/relayers/src/extension/priority.rs similarity index 90% rename from bridges/bin/runtime-common/src/extensions/priority_calculator.rs rename to bridges/modules/relayers/src/extension/priority.rs index 9f559dc13b64..e09e8627c673 100644 --- a/bridges/bin/runtime-common/src/extensions/priority_calculator.rs +++ b/bridges/modules/relayers/src/extension/priority.rs @@ -50,7 +50,6 @@ mod integrity_tests {} #[cfg(feature = "integrity-test")] mod integrity_tests { use super::{compute_priority_boost, ItemCount}; - use crate::extensions::refund_relayer_extension::RefundableParachainId; use bp_messages::MessageNonce; use bp_runtime::PreComputedSize; @@ -207,14 +206,17 @@ mod integrity_tests { // finally we are able to estimate transaction size and weight let transaction_size = base_tx_size.saturating_add(tx_call_size); - let transaction_weight = Runtime::WeightInfo::submit_finality_proof_weight( + let transaction_weight = >::WeightInfo::submit_finality_proof_weight( Runtime::BridgedChain::MAX_AUTHORITIES_COUNT * 2 / 3 + 1, Runtime::BridgedChain::REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY, ); pallet_transaction_payment::ChargeTransactionPayment::::get_priority( &DispatchInfo { - weight: transaction_weight, + call_weight: transaction_weight, + extension_weight: Default::default(), class: DispatchClass::Normal, pays_fee: Pays::Yes, }, @@ -239,12 +241,18 @@ mod integrity_tests { /// almost the same priority if we'll add `tip_boost_per_header` tip to the `TX1`. We want /// to be sure that if we add plain `PriorityBoostPerHeader` priority to `TX1`, the priority /// will be close to `TX2` as well. - pub fn ensure_priority_boost_is_sane( + pub fn ensure_priority_boost_is_sane< + Runtime, + ParachainsInstance, + Para, + PriorityBoostPerHeader, + >( tip_boost_per_header: BalanceOf, ) where Runtime: pallet_transaction_payment::Config - + pallet_bridge_parachains::Config, - RefundableParachain: RefundableParachainId, + + pallet_bridge_parachains::Config, + ParachainsInstance: 'static, + Para: Parachain, PriorityBoostPerHeader: Get, Runtime::RuntimeCall: Dispatchable, BalanceOf: Send + Sync + FixedPointOperand, @@ -263,7 +271,8 @@ mod integrity_tests { |_n_headers, tip| { estimate_parachain_header_submit_transaction_priority::< Runtime, - RefundableParachain, + ParachainsInstance, + Para, >(tip) }, ); @@ -271,13 +280,18 @@ mod integrity_tests { /// Estimate parachain header delivery transaction priority. #[cfg(feature = "integrity-test")] - fn estimate_parachain_header_submit_transaction_priority( + fn estimate_parachain_header_submit_transaction_priority< + Runtime, + ParachainsInstance, + Para, + >( tip: BalanceOf, ) -> TransactionPriority where Runtime: pallet_transaction_payment::Config - + pallet_bridge_parachains::Config, - RefundableParachain: RefundableParachainId, + + pallet_bridge_parachains::Config, + ParachainsInstance: 'static, + Para: Parachain, Runtime::RuntimeCall: Dispatchable, BalanceOf: Send + Sync + FixedPointOperand, { @@ -287,14 +301,14 @@ mod integrity_tests { let base_tx_size = 512; // let's say we are relaying largest parachain headers and proof takes some more bytes let tx_call_size = >::WeightInfo::expected_extra_storage_proof_size() - .saturating_add(RefundableParachain::BridgedChain::MAX_HEADER_SIZE); + .saturating_add(Para::MAX_HEADER_SIZE); // finally we are able to estimate transaction size and weight let transaction_size = base_tx_size.saturating_add(tx_call_size); let transaction_weight = >::WeightInfo::submit_parachain_heads_weight( Runtime::DbWeight::get(), &PreComputedSize(transaction_size as _), @@ -304,7 +318,8 @@ mod integrity_tests { pallet_transaction_payment::ChargeTransactionPayment::::get_priority( &DispatchInfo { - weight: transaction_weight, + call_weight: transaction_weight, + extension_weight: Default::default(), class: DispatchClass::Normal, pays_fee: Pays::Yes, }, @@ -374,20 +389,27 @@ mod integrity_tests { // trie nodes to the proof (x0.5 because we expect some nodes to be reused) let estimated_message_size = 512; // let's say all our messages have the same dispatch weight - let estimated_message_dispatch_weight = - Runtime::WeightInfo::message_dispatch_weight(estimated_message_size); + let estimated_message_dispatch_weight = >::WeightInfo::message_dispatch_weight( + estimated_message_size + ); // messages proof argument size is (for every message) messages size + some additional // trie nodes. Some of them are reused by different messages, so let's take 2/3 of // default "overhead" constant - let messages_proof_size = Runtime::WeightInfo::expected_extra_storage_proof_size() - .saturating_mul(2) - .saturating_div(3) - .saturating_add(estimated_message_size) - .saturating_mul(messages as _); + let messages_proof_size = >::WeightInfo::expected_extra_storage_proof_size() + .saturating_mul(2) + .saturating_div(3) + .saturating_add(estimated_message_size) + .saturating_mul(messages as _); // finally we are able to estimate transaction size and weight let transaction_size = base_tx_size.saturating_add(messages_proof_size); - let transaction_weight = Runtime::WeightInfo::receive_messages_proof_weight( + let transaction_weight = >::WeightInfo::receive_messages_proof_weight( &PreComputedSize(transaction_size as _), messages as _, estimated_message_dispatch_weight.saturating_mul(messages), @@ -395,7 +417,8 @@ mod integrity_tests { pallet_transaction_payment::ChargeTransactionPayment::::get_priority( &DispatchInfo { - weight: transaction_weight, + call_weight: transaction_weight, + extension_weight: Default::default(), class: DispatchClass::Normal, pays_fee: Pays::Yes, }, diff --git a/bridges/modules/relayers/src/lib.rs b/bridges/modules/relayers/src/lib.rs index 2c86ec01f5b9..f06c2e16ac24 100644 --- a/bridges/modules/relayers/src/lib.rs +++ b/bridges/modules/relayers/src/lib.rs @@ -36,13 +36,14 @@ pub use stake_adapter::StakeAndSlashNamed; pub use weights::WeightInfo; pub use weights_ext::WeightInfoExt; -pub mod benchmarking; - mod mock; mod payment_adapter; mod stake_adapter; mod weights_ext; +pub mod benchmarking; +pub mod extension; +pub mod migration; pub mod weights; /// The target that will be used when publishing logs related to this pallet. @@ -51,46 +52,58 @@ pub const LOG_TARGET: &str = "runtime::bridge-relayers"; #[frame_support::pallet] pub mod pallet { use super::*; + use bp_messages::LaneIdType; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; /// `RelayerRewardsKeyProvider` for given configuration. - type RelayerRewardsKeyProviderOf = - RelayerRewardsKeyProvider<::AccountId, ::Reward>; + type RelayerRewardsKeyProviderOf = RelayerRewardsKeyProvider< + ::AccountId, + >::Reward, + >::LaneId, + >; #[pallet::config] - pub trait Config: frame_system::Config { + pub trait Config: frame_system::Config { /// The overarching event type. - type RuntimeEvent: From> + IsType<::RuntimeEvent>; + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Type of relayer reward. type Reward: AtLeast32BitUnsigned + Copy + Member + Parameter + MaxEncodedLen; /// Pay rewards scheme. - type PaymentProcedure: PaymentProcedure; + type PaymentProcedure: PaymentProcedure< + Self::AccountId, + Self::Reward, + LaneId = Self::LaneId, + >; /// Stake and slash scheme. type StakeAndSlash: StakeAndSlash, Self::Reward>; /// Pallet call weights. type WeightInfo: WeightInfoExt; + /// Lane identifier type. + type LaneId: LaneIdType + Send + Sync; } #[pallet::pallet] - pub struct Pallet(PhantomData); + #[pallet::storage_version(migration::STORAGE_VERSION)] + pub struct Pallet(PhantomData<(T, I)>); #[pallet::call] - impl Pallet { + impl, I: 'static> Pallet { /// Claim accumulated rewards. #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::claim_rewards())] pub fn claim_rewards( origin: OriginFor, - rewards_account_params: RewardsAccountParams, + rewards_account_params: RewardsAccountParams, ) -> DispatchResult { let relayer = ensure_signed(origin)?; - RelayerRewards::::try_mutate_exists( + RelayerRewards::::try_mutate_exists( &relayer, rewards_account_params, |maybe_reward| -> DispatchResult { - let reward = maybe_reward.take().ok_or(Error::::NoRewardForRelayer)?; + let reward = maybe_reward.take().ok_or(Error::::NoRewardForRelayer)?; T::PaymentProcedure::pay_reward(&relayer, rewards_account_params, reward) .map_err(|e| { log::trace!( @@ -100,10 +113,10 @@ pub mod pallet { relayer, e, ); - Error::::FailedToPayReward + Error::::FailedToPayReward })?; - Self::deposit_event(Event::::RewardPaid { + Self::deposit_event(Event::::RewardPaid { relayer: relayer.clone(), rewards_account_params, reward, @@ -125,53 +138,57 @@ pub mod pallet { // than the `RequiredRegistrationLease` let lease = valid_till.saturating_sub(frame_system::Pallet::::block_number()); ensure!( - lease > Pallet::::required_registration_lease(), - Error::::InvalidRegistrationLease + lease > Self::required_registration_lease(), + Error::::InvalidRegistrationLease ); - RegisteredRelayers::::try_mutate(&relayer, |maybe_registration| -> DispatchResult { - let mut registration = maybe_registration - .unwrap_or_else(|| Registration { valid_till, stake: Zero::zero() }); + RegisteredRelayers::::try_mutate( + &relayer, + |maybe_registration| -> DispatchResult { + let mut registration = maybe_registration + .unwrap_or_else(|| Registration { valid_till, stake: Zero::zero() }); + + // new `valid_till` must be larger (or equal) than the old one + ensure!( + valid_till >= registration.valid_till, + Error::::CannotReduceRegistrationLease, + ); + registration.valid_till = valid_till; + + // regarding stake, there are three options: + // - if relayer stake is larger than required stake, we may do unreserve + // - if relayer stake equals to required stake, we do nothing + // - if relayer stake is smaller than required stake, we do additional reserve + let required_stake = Self::required_stake(); + if let Some(to_unreserve) = registration.stake.checked_sub(&required_stake) { + Self::do_unreserve(&relayer, to_unreserve)?; + } else if let Some(to_reserve) = required_stake.checked_sub(®istration.stake) + { + T::StakeAndSlash::reserve(&relayer, to_reserve).map_err(|e| { + log::trace!( + target: LOG_TARGET, + "Failed to reserve {:?} on relayer {:?} account: {:?}", + to_reserve, + relayer, + e, + ); - // new `valid_till` must be larger (or equal) than the old one - ensure!( - valid_till >= registration.valid_till, - Error::::CannotReduceRegistrationLease, - ); - registration.valid_till = valid_till; - - // regarding stake, there are three options: - // - if relayer stake is larger than required stake, we may do unreserve - // - if relayer stake equals to required stake, we do nothing - // - if relayer stake is smaller than required stake, we do additional reserve - let required_stake = Pallet::::required_stake(); - if let Some(to_unreserve) = registration.stake.checked_sub(&required_stake) { - Self::do_unreserve(&relayer, to_unreserve)?; - } else if let Some(to_reserve) = required_stake.checked_sub(®istration.stake) { - T::StakeAndSlash::reserve(&relayer, to_reserve).map_err(|e| { - log::trace!( - target: LOG_TARGET, - "Failed to reserve {:?} on relayer {:?} account: {:?}", - to_reserve, - relayer, - e, - ); - - Error::::FailedToReserve - })?; - } - registration.stake = required_stake; - - log::trace!(target: LOG_TARGET, "Successfully registered relayer: {:?}", relayer); - Self::deposit_event(Event::::RegistrationUpdated { - relayer: relayer.clone(), - registration, - }); - - *maybe_registration = Some(registration); - - Ok(()) - }) + Error::::FailedToReserve + })?; + } + registration.stake = required_stake; + + log::trace!(target: LOG_TARGET, "Successfully registered relayer: {:?}", relayer); + Self::deposit_event(Event::::RegistrationUpdated { + relayer: relayer.clone(), + registration, + }); + + *maybe_registration = Some(registration); + + Ok(()) + }, + ) } /// `Deregister` relayer. @@ -183,34 +200,37 @@ pub mod pallet { pub fn deregister(origin: OriginFor) -> DispatchResult { let relayer = ensure_signed(origin)?; - RegisteredRelayers::::try_mutate(&relayer, |maybe_registration| -> DispatchResult { - let registration = match maybe_registration.take() { - Some(registration) => registration, - None => fail!(Error::::NotRegistered), - }; - - // we can't deregister until `valid_till + 1` - ensure!( - registration.valid_till < frame_system::Pallet::::block_number(), - Error::::RegistrationIsStillActive, - ); + RegisteredRelayers::::try_mutate( + &relayer, + |maybe_registration| -> DispatchResult { + let registration = match maybe_registration.take() { + Some(registration) => registration, + None => fail!(Error::::NotRegistered), + }; + + // we can't deregister until `valid_till + 1` + ensure!( + registration.valid_till < frame_system::Pallet::::block_number(), + Error::::RegistrationIsStillActive, + ); - // if stake is non-zero, we should do unreserve - if !registration.stake.is_zero() { - Self::do_unreserve(&relayer, registration.stake)?; - } + // if stake is non-zero, we should do unreserve + if !registration.stake.is_zero() { + Self::do_unreserve(&relayer, registration.stake)?; + } - log::trace!(target: LOG_TARGET, "Successfully deregistered relayer: {:?}", relayer); - Self::deposit_event(Event::::Deregistered { relayer: relayer.clone() }); + log::trace!(target: LOG_TARGET, "Successfully deregistered relayer: {:?}", relayer); + Self::deposit_event(Event::::Deregistered { relayer: relayer.clone() }); - *maybe_registration = None; + *maybe_registration = None; - Ok(()) - }) + Ok(()) + }, + ) } } - impl Pallet { + impl, I: 'static> Pallet { /// Returns true if given relayer registration is active at current block. /// /// This call respects both `RequiredStake` and `RequiredRegistrationLease`, meaning that @@ -243,9 +263,9 @@ pub mod pallet { /// It may fail inside, but error is swallowed and we only log it. pub fn slash_and_deregister( relayer: &T::AccountId, - slash_destination: ExplicitOrAccountParams, + slash_destination: ExplicitOrAccountParams, ) { - let registration = match RegisteredRelayers::::take(relayer) { + let registration = match RegisteredRelayers::::take(relayer) { Some(registration) => registration, None => { log::trace!( @@ -304,7 +324,7 @@ pub mod pallet { /// Register reward for given relayer. pub fn register_relayer_reward( - rewards_account_params: RewardsAccountParams, + rewards_account_params: RewardsAccountParams, relayer: &T::AccountId, reward: T::Reward, ) { @@ -312,7 +332,7 @@ pub mod pallet { return } - RelayerRewards::::mutate( + RelayerRewards::::mutate( relayer, rewards_account_params, |old_reward: &mut Option| { @@ -327,7 +347,7 @@ pub mod pallet { new_reward, ); - Self::deposit_event(Event::::RewardRegistered { + Self::deposit_event(Event::::RewardRegistered { relayer: relayer.clone(), rewards_account_params, reward, @@ -366,7 +386,7 @@ pub mod pallet { relayer, ); - fail!(Error::::FailedToUnreserve) + fail!(Error::::FailedToUnreserve) } Ok(()) @@ -375,13 +395,13 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event { + pub enum Event, I: 'static = ()> { /// Relayer reward has been registered and may be claimed later. RewardRegistered { /// Relayer account that can claim reward. relayer: T::AccountId, /// Relayer can claim reward from this account. - rewards_account_params: RewardsAccountParams, + rewards_account_params: RewardsAccountParams, /// Reward amount. reward: T::Reward, }, @@ -390,7 +410,7 @@ pub mod pallet { /// Relayer account that has been rewarded. relayer: T::AccountId, /// Relayer has received reward from this account. - rewards_account_params: RewardsAccountParams, + rewards_account_params: RewardsAccountParams, /// Reward amount. reward: T::Reward, }, @@ -416,7 +436,7 @@ pub mod pallet { } #[pallet::error] - pub enum Error { + pub enum Error { /// No reward can be claimed by given relayer. NoRewardForRelayer, /// Reward payment procedure has failed. @@ -439,13 +459,13 @@ pub mod pallet { /// Map of the relayer => accumulated reward. #[pallet::storage] #[pallet::getter(fn relayer_reward)] - pub type RelayerRewards = StorageDoubleMap< + pub type RelayerRewards, I: 'static = ()> = StorageDoubleMap< _, - as StorageDoubleMapKeyProvider>::Hasher1, - as StorageDoubleMapKeyProvider>::Key1, - as StorageDoubleMapKeyProvider>::Hasher2, - as StorageDoubleMapKeyProvider>::Key2, - as StorageDoubleMapKeyProvider>::Value, + as StorageDoubleMapKeyProvider>::Hasher1, + as StorageDoubleMapKeyProvider>::Key1, + as StorageDoubleMapKeyProvider>::Hasher2, + as StorageDoubleMapKeyProvider>::Key2, + as StorageDoubleMapKeyProvider>::Value, OptionQuery, >; @@ -457,7 +477,7 @@ pub mod pallet { /// relayer is present. #[pallet::storage] #[pallet::getter(fn registered_relayer)] - pub type RegisteredRelayers = StorageMap< + pub type RegisteredRelayers, I: 'static = ()> = StorageMap< _, Blake2_128Concat, T::AccountId, @@ -469,10 +489,10 @@ pub mod pallet { #[cfg(test)] mod tests { use super::*; + use bp_messages::LaneIdType; use mock::{RuntimeEvent as TestEvent, *}; use crate::Event::{RewardPaid, RewardRegistered}; - use bp_messages::LaneId; use bp_relayers::RewardsAccountOwner; use frame_support::{ assert_noop, assert_ok, @@ -492,7 +512,7 @@ mod tests { get_ready_for_events(); Pallet::::register_relayer_reward( - TEST_REWARDS_ACCOUNT_PARAMS, + test_reward_account_param(), ®ULAR_RELAYER, 100, ); @@ -502,9 +522,9 @@ mod tests { System::::events().last(), Some(&EventRecord { phase: Phase::Initialization, - event: TestEvent::Relayers(RewardRegistered { + event: TestEvent::BridgeRelayers(RewardRegistered { relayer: REGULAR_RELAYER, - rewards_account_params: TEST_REWARDS_ACCOUNT_PARAMS, + rewards_account_params: test_reward_account_param(), reward: 100 }), topics: vec![], @@ -519,7 +539,7 @@ mod tests { assert_noop!( Pallet::::claim_rewards( RuntimeOrigin::root(), - TEST_REWARDS_ACCOUNT_PARAMS + test_reward_account_param() ), DispatchError::BadOrigin, ); @@ -532,7 +552,7 @@ mod tests { assert_noop!( Pallet::::claim_rewards( RuntimeOrigin::signed(REGULAR_RELAYER), - TEST_REWARDS_ACCOUNT_PARAMS + test_reward_account_param() ), Error::::NoRewardForRelayer, ); @@ -544,13 +564,13 @@ mod tests { run_test(|| { RelayerRewards::::insert( FAILING_RELAYER, - TEST_REWARDS_ACCOUNT_PARAMS, + test_reward_account_param(), 100, ); assert_noop!( Pallet::::claim_rewards( RuntimeOrigin::signed(FAILING_RELAYER), - TEST_REWARDS_ACCOUNT_PARAMS + test_reward_account_param() ), Error::::FailedToPayReward, ); @@ -564,15 +584,15 @@ mod tests { RelayerRewards::::insert( REGULAR_RELAYER, - TEST_REWARDS_ACCOUNT_PARAMS, + test_reward_account_param(), 100, ); assert_ok!(Pallet::::claim_rewards( RuntimeOrigin::signed(REGULAR_RELAYER), - TEST_REWARDS_ACCOUNT_PARAMS + test_reward_account_param() )); assert_eq!( - RelayerRewards::::get(REGULAR_RELAYER, TEST_REWARDS_ACCOUNT_PARAMS), + RelayerRewards::::get(REGULAR_RELAYER, test_reward_account_param()), None ); @@ -581,9 +601,9 @@ mod tests { System::::events().last(), Some(&EventRecord { phase: Phase::Initialization, - event: TestEvent::Relayers(RewardPaid { + event: TestEvent::BridgeRelayers(RewardPaid { relayer: REGULAR_RELAYER, - rewards_account_params: TEST_REWARDS_ACCOUNT_PARAMS, + rewards_account_params: test_reward_account_param(), reward: 100 }), topics: vec![], @@ -595,16 +615,17 @@ mod tests { #[test] fn pay_reward_from_account_actually_pays_reward() { type Balances = pallet_balances::Pallet; - type PayLaneRewardFromAccount = bp_relayers::PayRewardFromAccount; + type PayLaneRewardFromAccount = + bp_relayers::PayRewardFromAccount; run_test(|| { let in_lane_0 = RewardsAccountParams::new( - LaneId([0, 0, 0, 0]), + TestLaneIdType::try_new(1, 2).unwrap(), *b"test", RewardsAccountOwner::ThisChain, ); let out_lane_1 = RewardsAccountParams::new( - LaneId([0, 0, 0, 1]), + TestLaneIdType::try_new(1, 3).unwrap(), *b"test", RewardsAccountOwner::BridgedChain, ); @@ -676,7 +697,7 @@ mod tests { System::::events().last(), Some(&EventRecord { phase: Phase::Initialization, - event: TestEvent::Relayers(Event::RegistrationUpdated { + event: TestEvent::BridgeRelayers(Event::RegistrationUpdated { relayer: REGISTER_RELAYER, registration: Registration { valid_till: 150, stake: Stake::get() }, }), @@ -744,7 +765,7 @@ mod tests { System::::events().last(), Some(&EventRecord { phase: Phase::Initialization, - event: TestEvent::Relayers(Event::RegistrationUpdated { + event: TestEvent::BridgeRelayers(Event::RegistrationUpdated { relayer: REGISTER_RELAYER, registration: Registration { valid_till: 150, stake: Stake::get() } }), @@ -808,7 +829,7 @@ mod tests { System::::events().last(), Some(&EventRecord { phase: Phase::Initialization, - event: TestEvent::Relayers(Event::RegistrationUpdated { + event: TestEvent::BridgeRelayers(Event::RegistrationUpdated { relayer: REGISTER_RELAYER, registration: Registration { valid_till: 150, stake: Stake::get() } }), @@ -870,7 +891,9 @@ mod tests { System::::events().last(), Some(&EventRecord { phase: Phase::Initialization, - event: TestEvent::Relayers(Event::Deregistered { relayer: REGISTER_RELAYER }), + event: TestEvent::BridgeRelayers(Event::Deregistered { + relayer: REGISTER_RELAYER + }), topics: vec![], }), ); diff --git a/bridges/modules/relayers/src/migration.rs b/bridges/modules/relayers/src/migration.rs new file mode 100644 index 000000000000..8bf473b300c2 --- /dev/null +++ b/bridges/modules/relayers/src/migration.rs @@ -0,0 +1,243 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! A module that is responsible for migration of storage. + +use frame_support::{ + traits::{Get, StorageVersion}, + weights::Weight, +}; + +/// The in-code storage version. +pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + +/// This module contains data structures that are valid for the initial state of `0`. +/// (used with v1 migration). +pub mod v0 { + use crate::{Config, Pallet}; + use bp_relayers::RewardsAccountOwner; + use bp_runtime::{ChainId, StorageDoubleMapKeyProvider}; + use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen}; + use frame_support::{pallet_prelude::OptionQuery, Blake2_128Concat, Identity}; + use scale_info::TypeInfo; + use sp_runtime::traits::AccountIdConversion; + use sp_std::marker::PhantomData; + + /// Structure used to identify the account that pays a reward to the relayer. + #[derive(Copy, Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen)] + pub struct RewardsAccountParams { + /// lane_id + pub lane_id: LaneId, + /// bridged_chain_id + pub bridged_chain_id: ChainId, + /// owner + pub owner: RewardsAccountOwner, + } + + impl RewardsAccountParams { + /// Create a new instance of `RewardsAccountParams`. + pub const fn new( + lane_id: LaneId, + bridged_chain_id: ChainId, + owner: RewardsAccountOwner, + ) -> Self { + Self { lane_id, bridged_chain_id, owner } + } + } + + impl sp_runtime::TypeId for RewardsAccountParams { + const TYPE_ID: [u8; 4] = *b"brap"; + } + + pub(crate) struct RelayerRewardsKeyProvider( + PhantomData<(AccountId, Reward, LaneId)>, + ); + + impl StorageDoubleMapKeyProvider + for RelayerRewardsKeyProvider + where + AccountId: 'static + Codec + EncodeLike + Send + Sync, + Reward: 'static + Codec + EncodeLike + Send + Sync, + LaneId: Codec + EncodeLike + Send + Sync, + { + const MAP_NAME: &'static str = "RelayerRewards"; + + type Hasher1 = Blake2_128Concat; + type Key1 = AccountId; + type Hasher2 = Identity; + type Key2 = RewardsAccountParams; + type Value = Reward; + } + + pub(crate) type RelayerRewardsKeyProviderOf = RelayerRewardsKeyProvider< + ::AccountId, + >::Reward, + >::LaneId, + >; + + #[frame_support::storage_alias] + pub(crate) type RelayerRewards, I: 'static> = StorageDoubleMap< + Pallet, + as StorageDoubleMapKeyProvider>::Hasher1, + as StorageDoubleMapKeyProvider>::Key1, + as StorageDoubleMapKeyProvider>::Hasher2, + as StorageDoubleMapKeyProvider>::Key2, + as StorageDoubleMapKeyProvider>::Value, + OptionQuery, + >; + + /// Reward account generator for `v0`. + pub struct PayRewardFromAccount(PhantomData<(Account, LaneId)>); + impl PayRewardFromAccount + where + Account: Decode + Encode, + LaneId: Decode + Encode, + { + /// Return account that pays rewards based on the provided parameters. + pub fn rewards_account(params: RewardsAccountParams) -> Account { + params.into_sub_account_truncating(b"rewards-account") + } + } +} + +/// This migration updates `RelayerRewards` where `RewardsAccountParams` was used as the key with +/// `lane_id` as the first attribute, which affects `into_sub_account_truncating`. We are migrating +/// this key to use the new `RewardsAccountParams` where `lane_id` is the last attribute. +pub mod v1 { + use super::*; + use crate::{Config, Pallet}; + use bp_relayers::RewardsAccountParams; + use frame_support::traits::UncheckedOnRuntimeUpgrade; + use sp_std::marker::PhantomData; + + #[cfg(feature = "try-runtime")] + use crate::RelayerRewards; + + /// Migrates the pallet storage to v1. + pub struct UncheckedMigrationV0ToV1(PhantomData<(T, I)>); + + #[cfg(feature = "try-runtime")] + const LOG_TARGET: &str = "runtime::bridge-relayers-migration"; + + impl, I: 'static> UncheckedOnRuntimeUpgrade for UncheckedMigrationV0ToV1 { + fn on_runtime_upgrade() -> Weight { + let mut weight = T::DbWeight::get().reads(1); + + // list all rewards (we cannot do this as one step because of `drain` limitation) + let mut rewards_to_migrate = + sp_std::vec::Vec::with_capacity(v0::RelayerRewards::::iter().count()); + for (key1, key2, reward) in v0::RelayerRewards::::drain() { + rewards_to_migrate.push((key1, key2, reward)); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + } + + // re-register rewards with new format of `RewardsAccountParams`. + for (key1, key2, reward) in rewards_to_migrate { + // expand old key + let v0::RewardsAccountParams { owner, lane_id, bridged_chain_id } = key2; + + // re-register reward + Pallet::::register_relayer_reward( + v1::RewardsAccountParams::new(lane_id, bridged_chain_id, owner), + &key1, + reward, + ); + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + } + + weight + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::DispatchError> { + use codec::Encode; + use frame_support::BoundedBTreeMap; + use sp_runtime::traits::ConstU32; + + // collect actual rewards + let mut rewards: BoundedBTreeMap< + (T::AccountId, T::LaneId), + T::Reward, + ConstU32<{ u32::MAX }>, + > = BoundedBTreeMap::new(); + for (key1, key2, reward) in v0::RelayerRewards::::iter() { + log::info!(target: LOG_TARGET, "Reward to migrate: {key1:?}::{key2:?} - {reward:?}"); + rewards = rewards + .try_mutate(|inner| { + inner + .entry((key1.clone(), key2.lane_id)) + .and_modify(|value| *value += reward) + .or_insert(reward); + }) + .unwrap(); + } + log::info!(target: LOG_TARGET, "Found total rewards to migrate: {rewards:?}"); + + Ok(rewards.encode()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: sp_std::vec::Vec) -> Result<(), sp_runtime::DispatchError> { + use codec::Decode; + use frame_support::BoundedBTreeMap; + use sp_runtime::traits::ConstU32; + + let rewards_before: BoundedBTreeMap< + (T::AccountId, T::LaneId), + T::Reward, + ConstU32<{ u32::MAX }>, + > = Decode::decode(&mut &state[..]).unwrap(); + + // collect migrated rewards + let mut rewards_after: BoundedBTreeMap< + (T::AccountId, T::LaneId), + T::Reward, + ConstU32<{ u32::MAX }>, + > = BoundedBTreeMap::new(); + for (key1, key2, reward) in v1::RelayerRewards::::iter() { + log::info!(target: LOG_TARGET, "Migrated rewards: {key1:?}::{key2:?} - {reward:?}"); + rewards_after = rewards_after + .try_mutate(|inner| { + inner + .entry((key1.clone(), *key2.lane_id())) + .and_modify(|value| *value += reward) + .or_insert(reward); + }) + .unwrap(); + } + log::info!(target: LOG_TARGET, "Found total migrated rewards: {rewards_after:?}"); + + frame_support::ensure!( + rewards_before == rewards_after, + "The rewards were not migrated correctly!." + ); + + log::info!(target: LOG_TARGET, "migrated all."); + Ok(()) + } + } + + /// [`UncheckedMigrationV0ToV1`] wrapped in a + /// [`VersionedMigration`](frame_support::migrations::VersionedMigration), ensuring the + /// migration is only performed when on-chain version is 0. + pub type MigrationToV1 = frame_support::migrations::VersionedMigration< + 0, + 1, + UncheckedMigrationV0ToV1, + Pallet, + ::DbWeight, + >; +} diff --git a/bridges/modules/relayers/src/mock.rs b/bridges/modules/relayers/src/mock.rs index 3124787896c3..d186e968e648 100644 --- a/bridges/modules/relayers/src/mock.rs +++ b/bridges/modules/relayers/src/mock.rs @@ -18,51 +18,191 @@ use crate as pallet_bridge_relayers; -use bp_messages::LaneId; +use bp_header_chain::ChainWithGrandpa; +use bp_messages::{ + target_chain::{DispatchMessage, MessageDispatch}, + ChainWithMessages, HashedLaneId, LaneIdType, MessageNonce, +}; +use bp_parachains::SingleParaStoredHeaderDataBuilder; use bp_relayers::{ PayRewardFromAccount, PaymentProcedure, RewardsAccountOwner, RewardsAccountParams, }; +use bp_runtime::{messages::MessageDispatchResult, Chain, ChainId, Parachain}; +use codec::Encode; use frame_support::{ - derive_impl, parameter_types, traits::fungible::Mutate, weights::RuntimeDbWeight, + derive_impl, parameter_types, + traits::fungible::Mutate, + weights::{ConstantMultiplier, IdentityFee, RuntimeDbWeight, Weight}, +}; +use pallet_transaction_payment::Multiplier; +use sp_core::{ConstU64, ConstU8, H256}; +use sp_runtime::{ + traits::{BlakeTwo256, ConstU32}, + BuildStorage, FixedPointNumber, Perquintill, StateVersion, }; -use sp_runtime::BuildStorage; -pub type AccountId = u64; -pub type Balance = u64; -pub type BlockNumber = u64; +/// Account identifier at `ThisChain`. +pub type ThisChainAccountId = u64; +/// Balance at `ThisChain`. +pub type ThisChainBalance = u64; +/// Block number at `ThisChain`. +pub type ThisChainBlockNumber = u32; +/// Hash at `ThisChain`. +pub type ThisChainHash = H256; +/// Hasher at `ThisChain`. +pub type ThisChainHasher = BlakeTwo256; +/// Header of `ThisChain`. +pub type ThisChainHeader = sp_runtime::generic::Header; +/// Block of `ThisChain`. +pub type ThisChainBlock = frame_system::mocking::MockBlockU32; + +/// Account identifier at the `BridgedChain`. +pub type BridgedChainAccountId = u128; +/// Balance at the `BridgedChain`. +pub type BridgedChainBalance = u128; +/// Block number at the `BridgedChain`. +pub type BridgedChainBlockNumber = u32; +/// Hash at the `BridgedChain`. +pub type BridgedChainHash = H256; +/// Hasher at the `BridgedChain`. +pub type BridgedChainHasher = BlakeTwo256; +/// Header of the `BridgedChain`. +pub type BridgedChainHeader = + sp_runtime::generic::Header; + +/// Bridged chain id used in tests. +pub const TEST_BRIDGED_CHAIN_ID: ChainId = *b"brdg"; +/// Maximal extrinsic size at the `BridgedChain`. +pub const BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE: u32 = 1024; + +/// Lane identifier type used for tests. +pub type TestLaneIdType = HashedLaneId; +/// Lane that we're using in tests. +pub fn test_lane_id() -> TestLaneIdType { + TestLaneIdType::try_new(1, 2).unwrap() +} + +/// Underlying chain of `ThisChain`. +pub struct ThisUnderlyingChain; + +impl Chain for ThisUnderlyingChain { + const ID: ChainId = *b"tuch"; + + type BlockNumber = ThisChainBlockNumber; + type Hash = ThisChainHash; + type Hasher = ThisChainHasher; + type Header = ThisChainHeader; + type AccountId = ThisChainAccountId; + type Balance = ThisChainBalance; + type Nonce = u32; + type Signature = sp_runtime::MultiSignature; + + const STATE_VERSION: StateVersion = StateVersion::V1; + + fn max_extrinsic_size() -> u32 { + BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE + } + + fn max_extrinsic_weight() -> Weight { + Weight::zero() + } +} + +impl ChainWithMessages for ThisUnderlyingChain { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = ""; + + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1000; +} + +/// Underlying chain of `BridgedChain`. +pub struct BridgedUnderlyingParachain; + +impl Chain for BridgedUnderlyingParachain { + const ID: ChainId = TEST_BRIDGED_CHAIN_ID; + + type BlockNumber = BridgedChainBlockNumber; + type Hash = BridgedChainHash; + type Hasher = BridgedChainHasher; + type Header = BridgedChainHeader; + type AccountId = BridgedChainAccountId; + type Balance = BridgedChainBalance; + type Nonce = u32; + type Signature = sp_runtime::MultiSignature; + + const STATE_VERSION: StateVersion = StateVersion::V1; + + fn max_extrinsic_size() -> u32 { + BRIDGED_CHAIN_MAX_EXTRINSIC_SIZE + } + fn max_extrinsic_weight() -> Weight { + Weight::zero() + } +} + +impl ChainWithGrandpa for BridgedUnderlyingParachain { + const WITH_CHAIN_GRANDPA_PALLET_NAME: &'static str = ""; + const MAX_AUTHORITIES_COUNT: u32 = 16; + const REASONABLE_HEADERS_IN_JUSTIFICATION_ANCESTRY: u32 = 8; + const MAX_MANDATORY_HEADER_SIZE: u32 = 256; + const AVERAGE_HEADER_SIZE: u32 = 64; +} + +impl ChainWithMessages for BridgedUnderlyingParachain { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = ""; + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1000; +} + +impl Parachain for BridgedUnderlyingParachain { + const PARACHAIN_ID: u32 = 42; + const MAX_HEADER_SIZE: u32 = 1_024; +} pub type TestStakeAndSlash = pallet_bridge_relayers::StakeAndSlashNamed< - AccountId, - BlockNumber, + ThisChainAccountId, + ThisChainBlockNumber, Balances, ReserveId, Stake, Lease, >; -type Block = frame_system::mocking::MockBlock; - frame_support::construct_runtime! { pub enum TestRuntime { System: frame_system::{Pallet, Call, Config, Storage, Event}, - Balances: pallet_balances::{Pallet, Event}, - Relayers: pallet_bridge_relayers::{Pallet, Call, Event}, + Utility: pallet_utility, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + TransactionPayment: pallet_transaction_payment::{Pallet, Storage, Event}, + BridgeRelayers: pallet_bridge_relayers::{Pallet, Call, Storage, Event}, + BridgeGrandpa: pallet_bridge_grandpa::{Pallet, Call, Storage, Event}, + BridgeParachains: pallet_bridge_parachains::{Pallet, Call, Storage, Event}, + BridgeMessages: pallet_bridge_messages::{Pallet, Call, Storage, Event, Config}, } } parameter_types! { + pub const BridgedParasPalletName: &'static str = "Paras"; pub const DbWeight: RuntimeDbWeight = RuntimeDbWeight { read: 1, write: 2 }; - pub const ExistentialDeposit: Balance = 1; + pub const ExistentialDeposit: ThisChainBalance = 1; pub const ReserveId: [u8; 8] = *b"brdgrlrs"; - pub const Stake: Balance = 1_000; - pub const Lease: BlockNumber = 8; + pub const Stake: ThisChainBalance = 1_000; + pub const Lease: ThisChainBlockNumber = 8; + pub const TargetBlockFullness: Perquintill = Perquintill::from_percent(25); + pub const TransactionBaseFee: ThisChainBalance = 0; + pub const TransactionByteFee: ThisChainBalance = 1; + pub AdjustmentVariable: Multiplier = Multiplier::saturating_from_rational(3, 100_000); + pub MinimumMultiplier: Multiplier = Multiplier::saturating_from_rational(1, 1_000_000u128); + pub MaximumMultiplier: Multiplier = sp_runtime::traits::Bounded::max_value(); } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { - type Block = Block; - type AccountData = pallet_balances::AccountData; + type Block = ThisChainBlock; + // TODO: remove when https://github.com/paritytech/polkadot-sdk/pull/4543 merged + type BlockHashCount = ConstU32<10>; + type AccountData = pallet_balances::AccountData; type DbWeight = DbWeight; } @@ -72,21 +212,91 @@ impl pallet_balances::Config for TestRuntime { type AccountStore = System; } +impl pallet_utility::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type PalletsOrigin = OriginCaller; + type WeightInfo = (); +} + +#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig)] +impl pallet_transaction_payment::Config for TestRuntime { + type OnChargeTransaction = pallet_transaction_payment::FungibleAdapter; + type OperationalFeeMultiplier = ConstU8<5>; + type WeightToFee = IdentityFee; + type LengthToFee = ConstantMultiplier; + type FeeMultiplierUpdate = pallet_transaction_payment::TargetedFeeAdjustment< + TestRuntime, + TargetBlockFullness, + AdjustmentVariable, + MinimumMultiplier, + MaximumMultiplier, + >; + type RuntimeEvent = RuntimeEvent; +} + +impl pallet_bridge_grandpa::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type BridgedChain = BridgedUnderlyingParachain; + type MaxFreeHeadersPerBlock = ConstU32<4>; + type FreeHeadersInterval = ConstU32<1_024>; + type HeadersToKeep = ConstU32<8>; + type WeightInfo = pallet_bridge_grandpa::weights::BridgeWeight; +} + +impl pallet_bridge_parachains::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type BridgesGrandpaPalletInstance = (); + type ParasPalletName = BridgedParasPalletName; + type ParaStoredHeaderDataBuilder = + SingleParaStoredHeaderDataBuilder; + type HeadsToKeep = ConstU32<8>; + type MaxParaHeadDataSize = ConstU32<1024>; + type WeightInfo = pallet_bridge_parachains::weights::BridgeWeight; +} + +impl pallet_bridge_messages::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = pallet_bridge_messages::weights::BridgeWeight; + + type OutboundPayload = Vec; + type InboundPayload = Vec; + type LaneId = TestLaneIdType; + + type DeliveryPayments = (); + type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< + TestRuntime, + (), + ConstU64<100_000>, + >; + type OnMessagesDelivered = (); + + type MessageDispatch = DummyMessageDispatch; + type ThisChain = ThisUnderlyingChain; + type BridgedChain = BridgedUnderlyingParachain; + type BridgedHeaderChain = BridgeGrandpa; +} + impl pallet_bridge_relayers::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; - type Reward = Balance; + type Reward = ThisChainBalance; type PaymentProcedure = TestPaymentProcedure; type StakeAndSlash = TestStakeAndSlash; type WeightInfo = (); + type LaneId = TestLaneIdType; } #[cfg(feature = "runtime-benchmarks")] impl pallet_bridge_relayers::benchmarking::Config for TestRuntime { - fn prepare_rewards_account(account_params: RewardsAccountParams, reward: Balance) { - let rewards_account = - bp_relayers::PayRewardFromAccount::::rewards_account( - account_params, - ); + fn prepare_rewards_account( + account_params: RewardsAccountParams, + reward: Self::Reward, + ) { + let rewards_account = bp_relayers::PayRewardFromAccount::< + Balances, + ThisChainAccountId, + Self::LaneId, + >::rewards_account(account_params); Self::deposit_account(rewards_account, reward); } @@ -95,35 +305,32 @@ impl pallet_bridge_relayers::benchmarking::Config for TestRuntime { } } -/// Message lane that we're using in tests. -pub const TEST_REWARDS_ACCOUNT_PARAMS: RewardsAccountParams = - RewardsAccountParams::new(LaneId([0, 0, 0, 0]), *b"test", RewardsAccountOwner::ThisChain); - /// Regular relayer that may receive rewards. -pub const REGULAR_RELAYER: AccountId = 1; +pub const REGULAR_RELAYER: ThisChainAccountId = 1; /// Relayer that can't receive rewards. -pub const FAILING_RELAYER: AccountId = 2; +pub const FAILING_RELAYER: ThisChainAccountId = 2; /// Relayer that is able to register. -pub const REGISTER_RELAYER: AccountId = 42; +pub const REGISTER_RELAYER: ThisChainAccountId = 42; /// Payment procedure that rejects payments to the `FAILING_RELAYER`. pub struct TestPaymentProcedure; impl TestPaymentProcedure { - pub fn rewards_account(params: RewardsAccountParams) -> AccountId { - PayRewardFromAccount::<(), AccountId>::rewards_account(params) + pub fn rewards_account(params: RewardsAccountParams) -> ThisChainAccountId { + PayRewardFromAccount::<(), ThisChainAccountId, TestLaneIdType>::rewards_account(params) } } -impl PaymentProcedure for TestPaymentProcedure { +impl PaymentProcedure for TestPaymentProcedure { type Error = (); + type LaneId = TestLaneIdType; fn pay_reward( - relayer: &AccountId, - _lane_id: RewardsAccountParams, - _reward: Balance, + relayer: &ThisChainAccountId, + _lane_id: RewardsAccountParams, + _reward: ThisChainBalance, ) -> Result<(), Self::Error> { match *relayer { FAILING_RELAYER => Err(()), @@ -132,6 +339,47 @@ impl PaymentProcedure for TestPaymentProcedure { } } +/// Dummy message dispatcher. +pub struct DummyMessageDispatch; + +impl DummyMessageDispatch { + pub fn deactivate(lane: TestLaneIdType) { + frame_support::storage::unhashed::put(&(b"inactive", lane).encode()[..], &false); + } +} + +impl MessageDispatch for DummyMessageDispatch { + type DispatchPayload = Vec; + type DispatchLevelResult = (); + type LaneId = TestLaneIdType; + + fn is_active(lane: Self::LaneId) -> bool { + frame_support::storage::unhashed::take::(&(b"inactive", lane).encode()[..]) != + Some(false) + } + + fn dispatch_weight( + _message: &mut DispatchMessage, + ) -> Weight { + Weight::zero() + } + + fn dispatch( + _: DispatchMessage, + ) -> MessageDispatchResult { + MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result: () } + } +} + +/// Reward account params that we are using in tests. +pub fn test_reward_account_param() -> RewardsAccountParams { + RewardsAccountParams::new( + TestLaneIdType::try_new(1, 2).unwrap(), + *b"test", + RewardsAccountOwner::ThisChain, + ) +} + /// Return test externalities to use in tests. pub fn new_test_ext() -> sp_io::TestExternalities { let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); diff --git a/bridges/modules/relayers/src/payment_adapter.rs b/bridges/modules/relayers/src/payment_adapter.rs index f75c409aca4f..5383cba5ecbd 100644 --- a/bridges/modules/relayers/src/payment_adapter.rs +++ b/bridges/modules/relayers/src/payment_adapter.rs @@ -20,11 +20,12 @@ use crate::{Config, Pallet}; use bp_messages::{ source_chain::{DeliveryConfirmationPayments, RelayersRewards}, - LaneId, MessageNonce, + MessageNonce, }; use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; use bp_runtime::Chain; use frame_support::{sp_runtime::SaturatedConversion, traits::Get}; +use pallet_bridge_messages::LaneIdOf; use sp_arithmetic::traits::{Saturating, Zero}; use sp_std::{collections::vec_deque::VecDeque, marker::PhantomData, ops::RangeInclusive}; @@ -34,17 +35,17 @@ pub struct DeliveryConfirmationPaymentsAdapter( PhantomData<(T, MI, DeliveryReward)>, ); -impl DeliveryConfirmationPayments +impl DeliveryConfirmationPayments> for DeliveryConfirmationPaymentsAdapter where - T: Config + pallet_bridge_messages::Config, + T: Config + pallet_bridge_messages::Config::LaneId>, MI: 'static, DeliveryReward: Get, { type Error = &'static str; fn pay_reward( - lane_id: LaneId, + lane_id: LaneIdOf, messages_relayers: VecDeque>, confirmation_relayer: &T::AccountId, received_range: &RangeInclusive, @@ -72,7 +73,7 @@ where fn register_relayers_rewards( confirmation_relayer: &T::AccountId, relayers_rewards: RelayersRewards, - lane_id: RewardsAccountParams, + lane_id: RewardsAccountParams, delivery_fee: T::Reward, ) { // reward every relayer except `confirmation_relayer` @@ -103,11 +104,11 @@ mod tests { use super::*; use crate::{mock::*, RelayerRewards}; - const RELAYER_1: AccountId = 1; - const RELAYER_2: AccountId = 2; - const RELAYER_3: AccountId = 3; + const RELAYER_1: ThisChainAccountId = 1; + const RELAYER_2: ThisChainAccountId = 2; + const RELAYER_3: ThisChainAccountId = 3; - fn relayers_rewards() -> RelayersRewards { + fn relayers_rewards() -> RelayersRewards { vec![(RELAYER_1, 2), (RELAYER_2, 3)].into_iter().collect() } @@ -117,16 +118,16 @@ mod tests { register_relayers_rewards::( &RELAYER_2, relayers_rewards(), - TEST_REWARDS_ACCOUNT_PARAMS, + test_reward_account_param(), 50, ); assert_eq!( - RelayerRewards::::get(RELAYER_1, TEST_REWARDS_ACCOUNT_PARAMS), + RelayerRewards::::get(RELAYER_1, test_reward_account_param()), Some(100) ); assert_eq!( - RelayerRewards::::get(RELAYER_2, TEST_REWARDS_ACCOUNT_PARAMS), + RelayerRewards::::get(RELAYER_2, test_reward_account_param()), Some(150) ); }); @@ -138,20 +139,20 @@ mod tests { register_relayers_rewards::( &RELAYER_3, relayers_rewards(), - TEST_REWARDS_ACCOUNT_PARAMS, + test_reward_account_param(), 50, ); assert_eq!( - RelayerRewards::::get(RELAYER_1, TEST_REWARDS_ACCOUNT_PARAMS), + RelayerRewards::::get(RELAYER_1, test_reward_account_param()), Some(100) ); assert_eq!( - RelayerRewards::::get(RELAYER_2, TEST_REWARDS_ACCOUNT_PARAMS), + RelayerRewards::::get(RELAYER_2, test_reward_account_param()), Some(150) ); assert_eq!( - RelayerRewards::::get(RELAYER_3, TEST_REWARDS_ACCOUNT_PARAMS), + RelayerRewards::::get(RELAYER_3, test_reward_account_param()), None ); }); diff --git a/bridges/modules/relayers/src/stake_adapter.rs b/bridges/modules/relayers/src/stake_adapter.rs index 7ba90d91dfd9..1792f0be8316 100644 --- a/bridges/modules/relayers/src/stake_adapter.rs +++ b/bridges/modules/relayers/src/stake_adapter.rs @@ -18,7 +18,7 @@ //! mechanism of the relayers pallet. use bp_relayers::{ExplicitOrAccountParams, PayRewardFromAccount, StakeAndSlash}; -use codec::Codec; +use codec::{Codec, Decode, Encode}; use frame_support::traits::{tokens::BalanceStatus, NamedReservableCurrency}; use sp_runtime::{traits::Get, DispatchError, DispatchResult}; use sp_std::{fmt::Debug, marker::PhantomData}; @@ -53,15 +53,15 @@ where Currency::unreserve_named(&ReserveId::get(), relayer, amount) } - fn repatriate_reserved( + fn repatriate_reserved( relayer: &AccountId, - beneficiary: ExplicitOrAccountParams, + beneficiary: ExplicitOrAccountParams, amount: Currency::Balance, ) -> Result { let beneficiary_account = match beneficiary { ExplicitOrAccountParams::Explicit(account) => account, ExplicitOrAccountParams::Params(params) => - PayRewardFromAccount::<(), AccountId>::rewards_account(params), + PayRewardFromAccount::<(), AccountId, LaneId>::rewards_account(params), }; Currency::repatriate_reserved_named( &ReserveId::get(), @@ -80,7 +80,7 @@ mod tests { use frame_support::traits::fungible::Mutate; - fn test_stake() -> Balance { + fn test_stake() -> ThisChainBalance { Stake::get() } @@ -130,7 +130,7 @@ mod tests { #[test] fn repatriate_reserved_works() { run_test(|| { - let beneficiary = TEST_REWARDS_ACCOUNT_PARAMS; + let beneficiary = test_reward_account_param(); let beneficiary_account = TestPaymentProcedure::rewards_account(beneficiary); let mut expected_balance = ExistentialDeposit::get(); @@ -186,7 +186,7 @@ mod tests { #[test] fn repatriate_reserved_doesnt_work_when_beneficiary_account_is_missing() { run_test(|| { - let beneficiary = TEST_REWARDS_ACCOUNT_PARAMS; + let beneficiary = test_reward_account_param(); let beneficiary_account = TestPaymentProcedure::rewards_account(beneficiary); Balances::mint_into(&3, test_stake() * 2).unwrap(); diff --git a/bridges/modules/xcm-bridge-hub-router/Cargo.toml b/bridges/modules/xcm-bridge-hub-router/Cargo.toml index ec7c3b562832..55824f6a7fe7 100644 --- a/bridges/modules/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub-router/Cargo.toml @@ -16,11 +16,9 @@ log = { workspace = true } scale-info = { features = ["bit-vec", "derive", "serde"], workspace = true } # Bridge dependencies - bp-xcm-bridge-hub-router = { workspace = true } # Substrate Dependencies - frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } @@ -29,7 +27,6 @@ sp-runtime = { workspace = true } sp-std = { workspace = true } # Polkadot Dependencies - xcm = { workspace = true } xcm-builder = { workspace = true } diff --git a/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs b/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs index c4f9f534c1a4..3c4a10f82e7d 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/benchmarking.rs @@ -18,11 +18,9 @@ #![cfg(feature = "runtime-benchmarks")] -use crate::{Bridge, Call}; - -use bp_xcm_bridge_hub_router::{BridgeState, MINIMAL_DELIVERY_FEE_FACTOR}; +use crate::{DeliveryFeeFactor, MINIMAL_DELIVERY_FEE_FACTOR}; use frame_benchmarking::{benchmarks_instance_pallet, BenchmarkError}; -use frame_support::traits::{EnsureOrigin, Get, Hooks, UnfilteredDispatchable}; +use frame_support::traits::{Get, Hooks}; use sp_runtime::traits::Zero; use xcm::prelude::*; @@ -47,49 +45,16 @@ pub trait Config: crate::Config { benchmarks_instance_pallet! { on_initialize_when_non_congested { - Bridge::::put(BridgeState { - is_congested: false, - delivery_fee_factor: MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR, - }); + DeliveryFeeFactor::::put(MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR); }: { crate::Pallet::::on_initialize(Zero::zero()) } on_initialize_when_congested { - Bridge::::put(BridgeState { - is_congested: false, - delivery_fee_factor: MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR, - }); - + DeliveryFeeFactor::::put(MINIMAL_DELIVERY_FEE_FACTOR + MINIMAL_DELIVERY_FEE_FACTOR); let _ = T::ensure_bridged_target_destination()?; T::make_congested(); }: { crate::Pallet::::on_initialize(Zero::zero()) } - - report_bridge_status { - Bridge::::put(BridgeState::default()); - - let origin: T::RuntimeOrigin = T::BridgeHubOrigin::try_successful_origin().expect("expected valid BridgeHubOrigin"); - let bridge_id = Default::default(); - let is_congested = true; - - let call = Call::::report_bridge_status { bridge_id, is_congested }; - }: { call.dispatch_bypass_filter(origin)? } - verify { - assert!(Bridge::::get().is_congested); - } - - send_message { - let dest = T::ensure_bridged_target_destination()?; - let xcm = sp_std::vec![].into(); - - // make local queue congested, because it means additional db write - T::make_congested(); - }: { - send_xcm::>(dest, xcm).expect("message is sent") - } - verify { - assert!(Bridge::::get().delivery_fee_factor > MINIMAL_DELIVERY_FEE_FACTOR); - } } diff --git a/bridges/modules/xcm-bridge-hub-router/src/lib.rs b/bridges/modules/xcm-bridge-hub-router/src/lib.rs index 607394603466..fe8f5a2efdfb 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/lib.rs @@ -30,12 +30,9 @@ #![cfg_attr(not(feature = "std"), no_std)] -use bp_xcm_bridge_hub_router::{ - BridgeState, XcmChannelStatusProvider, MINIMAL_DELIVERY_FEE_FACTOR, -}; +pub use bp_xcm_bridge_hub_router::XcmChannelStatusProvider; use codec::Encode; use frame_support::traits::Get; -use sp_core::H256; use sp_runtime::{FixedPointNumber, FixedU128, Saturating}; use sp_std::vec::Vec; use xcm::prelude::*; @@ -49,6 +46,9 @@ pub mod weights; mod mock; +/// Minimal delivery fee factor. +pub const MINIMAL_DELIVERY_FEE_FACTOR: FixedU128 = FixedU128::from_u32(1); + /// The factor that is used to increase current message fee factor when bridge experiencing /// some lags. const EXPONENTIAL_FEE_BASE: FixedU128 = FixedU128::from_rational(105, 100); // 1.05 @@ -77,11 +77,16 @@ pub mod pallet { #[pallet::config] pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; /// Benchmarks results from runtime we're plugged into. type WeightInfo: WeightInfo; /// Universal location of this runtime. type UniversalLocation: Get; + /// Relative location of the supported sibling bridge hub. + type SiblingBridgeHubLocation: Get; /// The bridged network that this config is for if specified. /// Also used for filtering `Bridges` by `BridgedNetworkId`. /// If not specified, allows all networks pass through. @@ -93,13 +98,10 @@ pub mod pallet { /// Checks the XCM version for the destination. type DestinationVersion: GetVersion; - /// Origin of the sibling bridge hub that is allowed to report bridge status. - type BridgeHubOrigin: EnsureOrigin; /// Actual message sender (`HRMP` or `DMP`) to the sibling bridge hub location. - type ToBridgeHubSender: SendXcm + InspectMessageQueues; - /// Underlying channel with the sibling bridge hub. It must match the channel, used - /// by the `Self::ToBridgeHubSender`. - type WithBridgeHubChannel: XcmChannelStatusProvider; + type ToBridgeHubSender: SendXcm; + /// Local XCM channel manager. + type LocalXcmChannelManager: XcmChannelStatusProvider; /// Additional fee that is paid for every byte of the outbound message. type ByteFee: Get; @@ -113,118 +115,118 @@ pub mod pallet { #[pallet::hooks] impl, I: 'static> Hooks> for Pallet { fn on_initialize(_n: BlockNumberFor) -> Weight { - // TODO: make sure that `WithBridgeHubChannel::is_congested` returns true if either - // of XCM channels (outbound/inbound) is suspended. Because if outbound is suspended - // that is definitely congestion. If inbound is suspended, then we are not able to - // receive the "report_bridge_status" signal (that maybe sent by the bridge hub). - - // if the channel with sibling/child bridge hub is suspended, we don't change - // anything - if T::WithBridgeHubChannel::is_congested() { + // if XCM channel is still congested, we don't change anything + if T::LocalXcmChannelManager::is_congested(&T::SiblingBridgeHubLocation::get()) { return T::WeightInfo::on_initialize_when_congested() } - // if bridge has reported congestion, we don't change anything - let mut bridge = Self::bridge(); - if bridge.is_congested { + // if we can't decrease the delivery fee factor anymore, we don't change anything + let mut delivery_fee_factor = Self::delivery_fee_factor(); + if delivery_fee_factor == MINIMAL_DELIVERY_FEE_FACTOR { return T::WeightInfo::on_initialize_when_congested() } - // if fee factor is already minimal, we don't change anything - if bridge.delivery_fee_factor == MINIMAL_DELIVERY_FEE_FACTOR { - return T::WeightInfo::on_initialize_when_congested() - } - - let previous_factor = bridge.delivery_fee_factor; - bridge.delivery_fee_factor = - MINIMAL_DELIVERY_FEE_FACTOR.max(bridge.delivery_fee_factor / EXPONENTIAL_FEE_BASE); + let previous_factor = delivery_fee_factor; + delivery_fee_factor = + MINIMAL_DELIVERY_FEE_FACTOR.max(delivery_fee_factor / EXPONENTIAL_FEE_BASE); log::info!( target: LOG_TARGET, - "Bridge queue is uncongested. Decreased fee factor from {} to {}", + "Bridge channel is uncongested. Decreased fee factor from {} to {}", previous_factor, - bridge.delivery_fee_factor, + delivery_fee_factor, ); + Self::deposit_event(Event::DeliveryFeeFactorDecreased { + new_value: delivery_fee_factor, + }); + + DeliveryFeeFactor::::put(delivery_fee_factor); - Bridge::::put(bridge); T::WeightInfo::on_initialize_when_non_congested() } } - #[pallet::call] - impl, I: 'static> Pallet { - /// Notification about congested bridge queue. - #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::report_bridge_status())] - pub fn report_bridge_status( - origin: OriginFor, - // this argument is not currently used, but to ease future migration, we'll keep it - // here - bridge_id: H256, - is_congested: bool, - ) -> DispatchResult { - let _ = T::BridgeHubOrigin::ensure_origin(origin)?; - - log::info!( - target: LOG_TARGET, - "Received bridge status from {:?}: congested = {}", - bridge_id, - is_congested, - ); - - Bridge::::mutate(|bridge| { - bridge.is_congested = is_congested; - }); - Ok(()) - } + /// Initialization value for the delivery fee factor. + #[pallet::type_value] + pub fn InitialFactor() -> FixedU128 { + MINIMAL_DELIVERY_FEE_FACTOR } - /// Bridge that we are using. + /// The number to multiply the base delivery fee by. + /// + /// This factor is shared by all bridges, served by this pallet. For example, if this + /// chain (`Config::UniversalLocation`) opens two bridges ( + /// `X2(GlobalConsensus(Config::BridgedNetworkId::get()), Parachain(1000))` and + /// `X2(GlobalConsensus(Config::BridgedNetworkId::get()), Parachain(2000))`), then they + /// both will be sharing the same fee factor. This is because both bridges are sharing + /// the same local XCM channel with the child/sibling bridge hub, which we are using + /// to detect congestion: /// - /// **bridges-v1** assumptions: all outbound messages through this router are using single lane - /// and to single remote consensus. If there is some other remote consensus that uses the same - /// bridge hub, the separate pallet instance shall be used, In `v2` we'll have all required - /// primitives (lane-id aka bridge-id, derived from XCM locations) to support multiple bridges - /// by the same pallet instance. + /// ```nocompile + /// ThisChain --- Local XCM channel --> Sibling Bridge Hub ------ + /// | | + /// | | + /// | | + /// Lane1 Lane2 + /// | | + /// | | + /// | | + /// \ / | + /// Parachain1 <-- Local XCM channel --- Remote Bridge Hub <------ + /// | + /// | + /// Parachain1 <-- Local XCM channel --------- + /// ``` + /// + /// If at least one of other channels is congested, the local XCM channel with sibling + /// bridge hub eventually becomes congested too. And we have no means to detect - which + /// bridge exactly causes the congestion. So the best solution here is not to make + /// any differences between all bridges, started by this chain. #[pallet::storage] - #[pallet::getter(fn bridge)] - pub type Bridge, I: 'static = ()> = StorageValue<_, BridgeState, ValueQuery>; + #[pallet::getter(fn delivery_fee_factor)] + pub type DeliveryFeeFactor, I: 'static = ()> = + StorageValue<_, FixedU128, ValueQuery, InitialFactor>; impl, I: 'static> Pallet { /// Called when new message is sent (queued to local outbound XCM queue) over the bridge. pub(crate) fn on_message_sent_to_bridge(message_size: u32) { - log::trace!( - target: LOG_TARGET, - "on_message_sent_to_bridge - message_size: {message_size:?}", - ); - let _ = Bridge::::try_mutate(|bridge| { - let is_channel_with_bridge_hub_congested = T::WithBridgeHubChannel::is_congested(); - let is_bridge_congested = bridge.is_congested; - - // if outbound queue is not congested AND bridge has not reported congestion, do - // nothing - if !is_channel_with_bridge_hub_congested && !is_bridge_congested { - return Err(()) - } - - // ok - we need to increase the fee factor, let's do that - let message_size_factor = FixedU128::from_u32(message_size.saturating_div(1024)) - .saturating_mul(MESSAGE_SIZE_FEE_BASE); - let total_factor = EXPONENTIAL_FEE_BASE.saturating_add(message_size_factor); - let previous_factor = bridge.delivery_fee_factor; - bridge.delivery_fee_factor = - bridge.delivery_fee_factor.saturating_mul(total_factor); + // if outbound channel is not congested, do nothing + if !T::LocalXcmChannelManager::is_congested(&T::SiblingBridgeHubLocation::get()) { + return + } + // ok - we need to increase the fee factor, let's do that + let message_size_factor = FixedU128::from_u32(message_size.saturating_div(1024)) + .saturating_mul(MESSAGE_SIZE_FEE_BASE); + let total_factor = EXPONENTIAL_FEE_BASE.saturating_add(message_size_factor); + DeliveryFeeFactor::::mutate(|f| { + let previous_factor = *f; + *f = f.saturating_mul(total_factor); log::info!( target: LOG_TARGET, "Bridge channel is congested. Increased fee factor from {} to {}", previous_factor, - bridge.delivery_fee_factor, + f, ); - - Ok(()) + Self::deposit_event(Event::DeliveryFeeFactorIncreased { new_value: *f }); + *f }); } } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event, I: 'static = ()> { + /// Delivery fee factor has been decreased. + DeliveryFeeFactorDecreased { + /// New value of the `DeliveryFeeFactor`. + new_value: FixedU128, + }, + /// Delivery fee factor has been increased. + DeliveryFeeFactorIncreased { + /// New value of the `DeliveryFeeFactor`. + new_value: FixedU128, + }, + } } /// We'll be using `SovereignPaidRemoteExporter` to send remote messages over the sibling/child @@ -259,17 +261,25 @@ impl, I: 'static> ExporterFor for Pallet { } // ensure that the message is sent to the expected bridged network and location. - let Some((bridge_hub_location, maybe_payment)) = - T::Bridges::exporter_for(network, remote_location, message) - else { - log::trace!( - target: LOG_TARGET, - "Router with bridged_network_id {:?} does not support bridging to network {:?} and remote_location {:?}!", - T::BridgedNetworkId::get(), - network, - remote_location, - ); - return None + let (bridge_hub_location, maybe_payment) = match T::Bridges::exporter_for( + network, + remote_location, + message, + ) { + Some((bridge_hub_location, maybe_payment)) + if bridge_hub_location.eq(&T::SiblingBridgeHubLocation::get()) => + (bridge_hub_location, maybe_payment), + _ => { + log::trace!( + target: LOG_TARGET, + "Router configured with bridged_network_id {:?} and sibling_bridge_hub_location: {:?} does not support bridging to network {:?} and remote_location {:?}!", + T::BridgedNetworkId::get(), + T::SiblingBridgeHubLocation::get(), + network, + remote_location, + ); + return None + }, }; // take `base_fee` from `T::Brides`, but it has to be the same `T::FeeAsset` @@ -279,8 +289,8 @@ impl, I: 'static> ExporterFor for Pallet { invalid_asset => { log::error!( target: LOG_TARGET, - "Router with bridged_network_id {:?} is configured for `T::FeeAsset` {:?} which is not \ - compatible with {:?} for bridge_hub_location: {:?} for bridging to {:?}/{:?}!", + "Router with bridged_network_id {:?} is configured for `T::FeeAsset` {:?} \ + which is not compatible with {:?} for bridge_hub_location: {:?} for bridging to {:?}/{:?}!", T::BridgedNetworkId::get(), T::FeeAsset::get(), invalid_asset, @@ -300,18 +310,18 @@ impl, I: 'static> ExporterFor for Pallet { let message_size = message.encoded_size(); let message_fee = (message_size as u128).saturating_mul(T::ByteFee::get()); let fee_sum = base_fee.saturating_add(message_fee); - let fee_factor = Self::bridge().delivery_fee_factor; - let fee = fee_factor.saturating_mul_int(fee_sum); + let fee_factor = Self::delivery_fee_factor(); + let fee = fee_factor.saturating_mul_int(fee_sum); let fee = if fee > 0 { Some((T::FeeAsset::get(), fee).into()) } else { None }; log::info!( target: LOG_TARGET, - "Validate send message to {:?} ({} bytes) over bridge. Computed bridge fee {:?} using fee factor {}", + "Going to send message to {:?} ({} bytes) over bridge. Computed bridge fee {:?} using fee factor {}", (network, remote_location), message_size, fee, - fee_factor + fee_factor, ); Some((bridge_hub_location, fee)) @@ -398,8 +408,12 @@ impl, I: 'static> SendXcm for Pallet { } impl, I: 'static> InspectMessageQueues for Pallet { + fn clear_messages() {} + + /// This router needs to implement `InspectMessageQueues` but doesn't have to + /// return any messages, since it just reuses the `XcmpQueue` router. fn get_messages() -> Vec<(VersionedLocation, Vec>)> { - ViaBridgeHubExporter::::get_messages() + Vec::new() } } @@ -410,66 +424,57 @@ mod tests { use mock::*; use frame_support::traits::Hooks; + use frame_system::{EventRecord, Phase}; use sp_runtime::traits::One; - fn congested_bridge(delivery_fee_factor: FixedU128) -> BridgeState { - BridgeState { is_congested: true, delivery_fee_factor } - } - - fn uncongested_bridge(delivery_fee_factor: FixedU128) -> BridgeState { - BridgeState { is_congested: false, delivery_fee_factor } - } - #[test] fn initial_fee_factor_is_one() { run_test(|| { - assert_eq!( - Bridge::::get(), - uncongested_bridge(MINIMAL_DELIVERY_FEE_FACTOR), - ); + assert_eq!(DeliveryFeeFactor::::get(), MINIMAL_DELIVERY_FEE_FACTOR); }) } #[test] fn fee_factor_is_not_decreased_from_on_initialize_when_xcm_channel_is_congested() { run_test(|| { - Bridge::::put(uncongested_bridge(FixedU128::from_rational(125, 100))); - TestWithBridgeHubChannel::make_congested(); + DeliveryFeeFactor::::put(FixedU128::from_rational(125, 100)); + TestLocalXcmChannelManager::make_congested(&SiblingBridgeHubLocation::get()); - // it should not decrease, because xcm channel is congested - let old_bridge = XcmBridgeHubRouter::bridge(); + // it should not decrease, because queue is congested + let old_delivery_fee_factor = XcmBridgeHubRouter::delivery_fee_factor(); XcmBridgeHubRouter::on_initialize(One::one()); - assert_eq!(XcmBridgeHubRouter::bridge(), old_bridge); - }) - } + assert_eq!(XcmBridgeHubRouter::delivery_fee_factor(), old_delivery_fee_factor); - #[test] - fn fee_factor_is_not_decreased_from_on_initialize_when_bridge_has_reported_congestion() { - run_test(|| { - Bridge::::put(congested_bridge(FixedU128::from_rational(125, 100))); - - // it should not decrease, because bridge congested - let old_bridge = XcmBridgeHubRouter::bridge(); - XcmBridgeHubRouter::on_initialize(One::one()); - assert_eq!(XcmBridgeHubRouter::bridge(), old_bridge); + assert_eq!(System::events(), vec![]); }) } #[test] fn fee_factor_is_decreased_from_on_initialize_when_xcm_channel_is_uncongested() { run_test(|| { - Bridge::::put(uncongested_bridge(FixedU128::from_rational(125, 100))); + let initial_fee_factor = FixedU128::from_rational(125, 100); + DeliveryFeeFactor::::put(initial_fee_factor); - // it should eventually decreased to one - while XcmBridgeHubRouter::bridge().delivery_fee_factor > MINIMAL_DELIVERY_FEE_FACTOR { + // it shold eventually decreased to one + while XcmBridgeHubRouter::delivery_fee_factor() > MINIMAL_DELIVERY_FEE_FACTOR { XcmBridgeHubRouter::on_initialize(One::one()); } // verify that it doesn't decreases anymore XcmBridgeHubRouter::on_initialize(One::one()); + assert_eq!(XcmBridgeHubRouter::delivery_fee_factor(), MINIMAL_DELIVERY_FEE_FACTOR); + + // check emitted event + let first_system_event = System::events().first().cloned(); assert_eq!( - XcmBridgeHubRouter::bridge(), - uncongested_bridge(MINIMAL_DELIVERY_FEE_FACTOR) + first_system_event, + Some(EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::XcmBridgeHubRouter(Event::DeliveryFeeFactorDecreased { + new_value: initial_fee_factor / EXPONENTIAL_FEE_BASE, + }), + topics: vec![], + }) ); }) } @@ -577,7 +582,7 @@ mod tests { // but when factor is larger than one, it increases the fee, so it becomes: // `(BASE_FEE + BYTE_FEE * msg_size) * F + HRMP_FEE` let factor = FixedU128::from_rational(125, 100); - Bridge::::put(uncongested_bridge(factor)); + DeliveryFeeFactor::::put(factor); let expected_fee = (FixedU128::saturating_from_integer(BASE_FEE + BYTE_FEE * (msg_size as u128)) * factor) @@ -591,45 +596,31 @@ mod tests { } #[test] - fn sent_message_doesnt_increase_factor_if_xcm_channel_is_uncongested() { + fn sent_message_doesnt_increase_factor_if_queue_is_uncongested() { run_test(|| { - let old_bridge = XcmBridgeHubRouter::bridge(); - assert_ok!(send_xcm::( - Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]), - vec![ClearOrigin].into(), - ) - .map(drop)); + let old_delivery_fee_factor = XcmBridgeHubRouter::delivery_fee_factor(); + assert_eq!( + send_xcm::( + Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]), + vec![ClearOrigin].into(), + ) + .map(drop), + Ok(()), + ); assert!(TestToBridgeHubSender::is_message_sent()); - assert_eq!(old_bridge, XcmBridgeHubRouter::bridge()); - }); - } - - #[test] - fn sent_message_increases_factor_if_xcm_channel_is_congested() { - run_test(|| { - TestWithBridgeHubChannel::make_congested(); - - let old_bridge = XcmBridgeHubRouter::bridge(); - assert_ok!(send_xcm::( - Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]), - vec![ClearOrigin].into(), - ) - .map(drop)); + assert_eq!(old_delivery_fee_factor, XcmBridgeHubRouter::delivery_fee_factor()); - assert!(TestToBridgeHubSender::is_message_sent()); - assert!( - old_bridge.delivery_fee_factor < XcmBridgeHubRouter::bridge().delivery_fee_factor - ); + assert_eq!(System::events(), vec![]); }); } #[test] - fn sent_message_increases_factor_if_bridge_has_reported_congestion() { + fn sent_message_increases_factor_if_xcm_channel_is_congested() { run_test(|| { - Bridge::::put(congested_bridge(MINIMAL_DELIVERY_FEE_FACTOR)); + TestLocalXcmChannelManager::make_congested(&SiblingBridgeHubLocation::get()); - let old_bridge = XcmBridgeHubRouter::bridge(); + let old_delivery_fee_factor = XcmBridgeHubRouter::delivery_fee_factor(); assert_ok!(send_xcm::( Location::new(2, [GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)]), vec![ClearOrigin].into(), @@ -637,41 +628,31 @@ mod tests { .map(drop)); assert!(TestToBridgeHubSender::is_message_sent()); - assert!( - old_bridge.delivery_fee_factor < XcmBridgeHubRouter::bridge().delivery_fee_factor - ); + assert!(old_delivery_fee_factor < XcmBridgeHubRouter::delivery_fee_factor()); + + // check emitted event + let first_system_event = System::events().first().cloned(); + assert!(matches!( + first_system_event, + Some(EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::XcmBridgeHubRouter( + Event::DeliveryFeeFactorIncreased { .. } + ), + .. + }) + )); }); } #[test] - fn get_messages_works() { + fn get_messages_does_not_return_anything() { run_test(|| { assert_ok!(send_xcm::( (Parent, Parent, GlobalConsensus(BridgedNetworkId::get()), Parachain(1000)).into(), vec![ClearOrigin].into() )); - assert_eq!( - XcmBridgeHubRouter::get_messages(), - vec![( - VersionedLocation::V4((Parent, Parachain(1002)).into()), - vec![VersionedXcm::V4( - Xcm::builder() - .withdraw_asset((Parent, 1_002_000)) - .buy_execution((Parent, 1_002_000), Unlimited) - .set_appendix( - Xcm::builder_unsafe() - .deposit_asset(AllCounted(1), (Parent, Parachain(1000))) - .build() - ) - .export_message( - Kusama, - Parachain(1000), - Xcm::builder_unsafe().clear_origin().build() - ) - .build() - )], - ),], - ); + assert_eq!(XcmBridgeHubRouter::get_messages(), vec![]); }); } } diff --git a/bridges/modules/xcm-bridge-hub-router/src/mock.rs b/bridges/modules/xcm-bridge-hub-router/src/mock.rs index 3e2c1bb369cb..bb265e1925a2 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/mock.rs @@ -24,13 +24,11 @@ use frame_support::{ construct_runtime, derive_impl, parameter_types, traits::{Contains, Equals}, }; -use frame_system::EnsureRoot; use sp_runtime::{traits::ConstU128, BuildStorage}; use sp_std::cell::RefCell; use xcm::prelude::*; use xcm_builder::{InspectMessageQueues, NetworkExportTable, NetworkExportTableItem}; -pub type AccountId = u64; type Block = frame_system::mocking::MockBlock; /// HRMP fee. @@ -44,7 +42,7 @@ construct_runtime! { pub enum TestRuntime { System: frame_system::{Pallet, Call, Config, Storage, Event}, - XcmBridgeHubRouter: pallet_xcm_bridge_hub_router::{Pallet, Storage}, + XcmBridgeHubRouter: pallet_xcm_bridge_hub_router::{Pallet, Storage, Event}, } } @@ -72,17 +70,18 @@ impl frame_system::Config for TestRuntime { } impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { + type RuntimeEvent = RuntimeEvent; type WeightInfo = (); type UniversalLocation = UniversalLocation; + type SiblingBridgeHubLocation = SiblingBridgeHubLocation; type BridgedNetworkId = BridgedNetworkId; type Bridges = NetworkExportTable; type DestinationVersion = LatestOrNoneForLocationVersionChecker>; - type BridgeHubOrigin = EnsureRoot; type ToBridgeHubSender = TestToBridgeHubSender; - type WithBridgeHubChannel = TestWithBridgeHubChannel; + type LocalXcmChannelManager = TestLocalXcmChannelManager; type ByteFee = ConstU128; type FeeAsset = BridgeFeeAsset; @@ -131,6 +130,10 @@ impl SendXcm for TestToBridgeHubSender { } impl InspectMessageQueues for TestToBridgeHubSender { + fn clear_messages() { + SENT_XCM.with(|q| q.borrow_mut().clear()); + } + fn get_messages() -> Vec<(VersionedLocation, Vec>)> { SENT_XCM.with(|q| { (*q.borrow()) @@ -147,17 +150,22 @@ impl InspectMessageQueues for TestToBridgeHubSender { } } -pub struct TestWithBridgeHubChannel; +pub struct TestLocalXcmChannelManager; -impl TestWithBridgeHubChannel { - pub fn make_congested() { - frame_support::storage::unhashed::put(b"TestWithBridgeHubChannel.Congested", &true); +impl TestLocalXcmChannelManager { + pub fn make_congested(with: &Location) { + frame_support::storage::unhashed::put( + &(b"TestLocalXcmChannelManager.Congested", with).encode()[..], + &true, + ); } } -impl XcmChannelStatusProvider for TestWithBridgeHubChannel { - fn is_congested() -> bool { - frame_support::storage::unhashed::get_or_default(b"TestWithBridgeHubChannel.Congested") +impl XcmChannelStatusProvider for TestLocalXcmChannelManager { + fn is_congested(with: &Location) -> bool { + frame_support::storage::unhashed::get_or_default( + &(b"TestLocalXcmChannelManager.Congested", with).encode()[..], + ) } } @@ -169,7 +177,12 @@ pub fn new_test_ext() -> sp_io::TestExternalities { /// Run pallet test. pub fn run_test(test: impl FnOnce() -> T) -> T { - new_test_ext().execute_with(test) + new_test_ext().execute_with(|| { + System::set_block_number(1); + System::reset_events(); + + test() + }) } pub(crate) fn fake_message_hash(message: &Xcm) -> XcmHash { diff --git a/bridges/modules/xcm-bridge-hub-router/src/weights.rs b/bridges/modules/xcm-bridge-hub-router/src/weights.rs index b0c8fc6252cd..d9a0426fecaf 100644 --- a/bridges/modules/xcm-bridge-hub-router/src/weights.rs +++ b/bridges/modules/xcm-bridge-hub-router/src/weights.rs @@ -52,8 +52,6 @@ use sp_std::marker::PhantomData; pub trait WeightInfo { fn on_initialize_when_non_congested() -> Weight; fn on_initialize_when_congested() -> Weight; - fn report_bridge_status() -> Weight; - fn send_message() -> Weight; } /// Weights for `pallet_xcm_bridge_hub_router` that are generated using one of the Bridge testnets. @@ -61,30 +59,20 @@ pub trait WeightInfo { /// Those weights are test only and must never be used in production. pub struct BridgeWeight(PhantomData); impl WeightInfo for BridgeWeight { - /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) /// - /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: - /// 512, mode: `MaxEncodedLen`) + /// Storage: `XcmBridgeHubRouter::DeliveryFeeFactor` (r:1 w:1) /// - /// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` - /// (r:1 w:0) - /// - /// Proof: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` (r:1 - /// w:0) + /// Proof: `XcmBridgeHubRouter::DeliveryFeeFactor` (`max_values`: Some(1), `max_size`: Some(16), + /// added: 511, mode: `MaxEncodedLen`) fn on_initialize_when_non_congested() -> Weight { // Proof Size summary in bytes: - // Measured: `53` - // Estimated: `3518` - // Minimum execution time: 11_934 nanoseconds. - Weight::from_parts(12_201_000, 3518) + // Measured: `52` + // Estimated: `3517` + // Minimum execution time: 11_141 nanoseconds. + Weight::from_parts(11_339_000, 3517) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } - /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) - /// - /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: - /// 512, mode: `MaxEncodedLen`) - /// /// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` /// (r:1 w:0) /// @@ -92,117 +80,44 @@ impl WeightInfo for BridgeWeight { /// w:0) fn on_initialize_when_congested() -> Weight { // Proof Size summary in bytes: - // Measured: `94` - // Estimated: `3559` - // Minimum execution time: 9_010 nanoseconds. - Weight::from_parts(9_594_000, 3559) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) - /// - /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: - /// 512, mode: `MaxEncodedLen`) - fn report_bridge_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `53` - // Estimated: `1502` - // Minimum execution time: 10_427 nanoseconds. - Weight::from_parts(10_682_000, 1502) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) - /// - /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: - /// 512, mode: `MaxEncodedLen`) - /// - /// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` - /// (r:1 w:0) - /// - /// Proof: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` (r:1 - /// w:0) - fn send_message() -> Weight { - // Proof Size summary in bytes: - // Measured: `52` - // Estimated: `3517` - // Minimum execution time: 19_709 nanoseconds. - Weight::from_parts(20_110_000, 3517) - .saturating_add(T::DbWeight::get().reads(2_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + // Measured: `82` + // Estimated: `3547` + // Minimum execution time: 4_239 nanoseconds. + Weight::from_parts(4_383_000, 3547).saturating_add(T::DbWeight::get().reads(1_u64)) } } // For backwards compatibility and tests impl WeightInfo for () { - /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) - /// - /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: - /// 512, mode: `MaxEncodedLen`) - /// /// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` /// (r:1 w:0) /// /// Proof: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` (r:1 /// w:0) - fn on_initialize_when_non_congested() -> Weight { - // Proof Size summary in bytes: - // Measured: `53` - // Estimated: `3518` - // Minimum execution time: 11_934 nanoseconds. - Weight::from_parts(12_201_000, 3518) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) /// - /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: - /// 512, mode: `MaxEncodedLen`) + /// Storage: `XcmBridgeHubRouter::DeliveryFeeFactor` (r:1 w:1) /// - /// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` - /// (r:1 w:0) - /// - /// Proof: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` (r:1 - /// w:0) - fn on_initialize_when_congested() -> Weight { + /// Proof: `XcmBridgeHubRouter::DeliveryFeeFactor` (`max_values`: Some(1), `max_size`: Some(16), + /// added: 511, mode: `MaxEncodedLen`) + fn on_initialize_when_non_congested() -> Weight { // Proof Size summary in bytes: - // Measured: `94` - // Estimated: `3559` - // Minimum execution time: 9_010 nanoseconds. - Weight::from_parts(9_594_000, 3559) + // Measured: `52` + // Estimated: `3517` + // Minimum execution time: 11_141 nanoseconds. + Weight::from_parts(11_339_000, 3517) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } - /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) - /// - /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: - /// 512, mode: `MaxEncodedLen`) - fn report_bridge_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `53` - // Estimated: `1502` - // Minimum execution time: 10_427 nanoseconds. - Weight::from_parts(10_682_000, 1502) - .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: `XcmBridgeHubRouter::Bridge` (r:1 w:1) - /// - /// Proof: `XcmBridgeHubRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: - /// 512, mode: `MaxEncodedLen`) - /// /// Storage: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` /// (r:1 w:0) /// /// Proof: UNKNOWN KEY `0x456d756c617465645369626c696e6758636d704368616e6e656c2e436f6e6765` (r:1 /// w:0) - fn send_message() -> Weight { + fn on_initialize_when_congested() -> Weight { // Proof Size summary in bytes: - // Measured: `52` - // Estimated: `3517` - // Minimum execution time: 19_709 nanoseconds. - Weight::from_parts(20_110_000, 3517) - .saturating_add(RocksDbWeight::get().reads(2_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + // Measured: `82` + // Estimated: `3547` + // Minimum execution time: 4_239 nanoseconds. + Weight::from_parts(4_383_000, 3547).saturating_add(RocksDbWeight::get().reads(1_u64)) } } diff --git a/bridges/modules/xcm-bridge-hub/Cargo.toml b/bridges/modules/xcm-bridge-hub/Cargo.toml index 092df477265f..fe58b910a94e 100644 --- a/bridges/modules/xcm-bridge-hub/Cargo.toml +++ b/bridges/modules/xcm-bridge-hub/Cargo.toml @@ -20,7 +20,6 @@ bp-messages = { workspace = true } bp-runtime = { workspace = true } bp-xcm-bridge-hub = { workspace = true } pallet-bridge-messages = { workspace = true } -bridge-runtime-common = { workspace = true } # Substrate Dependencies frame-support = { workspace = true } @@ -35,24 +34,31 @@ xcm-builder = { workspace = true } xcm-executor = { workspace = true } [dev-dependencies] -bp-header-chain = { workspace = true, default-features = true } -pallet-balances = { workspace = true, default-features = true } -sp-io = { workspace = true, default-features = true } +pallet-balances = { workspace = true } +sp-io = { workspace = true } +bp-runtime = { workspace = true } +bp-header-chain = { workspace = true } +pallet-xcm-bridge-hub-router = { workspace = true } +polkadot-parachain-primitives = { workspace = true } [features] default = ["std"] std = [ + "bp-header-chain/std", "bp-messages/std", "bp-runtime/std", "bp-xcm-bridge-hub/std", - "bridge-runtime-common/std", "codec/std", "frame-support/std", "frame-system/std", "log/std", + "pallet-balances/std", "pallet-bridge-messages/std", + "pallet-xcm-bridge-hub-router/std", + "polkadot-parachain-primitives/std", "scale-info/std", "sp-core/std", + "sp-io/std", "sp-runtime/std", "sp-std/std", "xcm-builder/std", @@ -60,11 +66,12 @@ std = [ "xcm/std", ] runtime-benchmarks = [ - "bridge-runtime-common/runtime-benchmarks", "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-bridge-messages/runtime-benchmarks", + "pallet-xcm-bridge-hub-router/runtime-benchmarks", + "polkadot-parachain-primitives/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", @@ -74,5 +81,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/dispatcher.rs b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs new file mode 100644 index 000000000000..dd855c7069aa --- /dev/null +++ b/bridges/modules/xcm-bridge-hub/src/dispatcher.rs @@ -0,0 +1,267 @@ +// Copyright 2019-2021 Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! The code that allows to use the pallet (`pallet-xcm-bridge-hub`) as inbound +//! bridge messages dispatcher. Internally, it just forwards inbound blob to the +//! XCM-level blob dispatcher, which pushes message to some other queue (e.g. +//! to HRMP queue with the sibling target chain). +//! +//! This code is executed at the target bridge hub. + +use crate::{Config, Pallet, LOG_TARGET}; + +use bp_messages::target_chain::{DispatchMessage, MessageDispatch}; +use bp_runtime::messages::MessageDispatchResult; +use bp_xcm_bridge_hub::{LocalXcmChannelManager, XcmAsPlainPayload}; +use codec::{Decode, Encode}; +use frame_support::{weights::Weight, CloneNoBound, EqNoBound, PartialEqNoBound}; +use pallet_bridge_messages::{Config as BridgeMessagesConfig, WeightInfoExt}; +use scale_info::TypeInfo; +use sp_runtime::SaturatedConversion; +use xcm::prelude::*; +use xcm_builder::{DispatchBlob, DispatchBlobError}; + +/// Message dispatch result type for single message. +#[derive(CloneNoBound, EqNoBound, PartialEqNoBound, Encode, Decode, Debug, TypeInfo)] +pub enum XcmBlobMessageDispatchResult { + /// We've been unable to decode message payload. + InvalidPayload, + /// Message has been dispatched. + Dispatched, + /// Message has **NOT** been dispatched because of given error. + NotDispatched(#[codec(skip)] Option), +} + +/// An easy way to access associated messages pallet weights. +type MessagesPalletWeights = + >::BridgeMessagesPalletInstance>>::WeightInfo; + +impl, I: 'static> MessageDispatch for Pallet +where + T: BridgeMessagesConfig, +{ + type DispatchPayload = XcmAsPlainPayload; + type DispatchLevelResult = XcmBlobMessageDispatchResult; + type LaneId = T::LaneId; + + fn is_active(lane: Self::LaneId) -> bool { + Pallet::::bridge_by_lane_id(&lane) + .and_then(|(_, bridge)| bridge.bridge_origin_relative_location.try_as().cloned().ok()) + .map(|recipient: Location| !T::LocalXcmChannelManager::is_congested(&recipient)) + .unwrap_or(false) + } + + fn dispatch_weight( + message: &mut DispatchMessage, + ) -> Weight { + match message.data.payload { + Ok(ref payload) => { + let payload_size = payload.encoded_size().saturated_into(); + MessagesPalletWeights::::message_dispatch_weight(payload_size) + }, + Err(_) => Weight::zero(), + } + } + + fn dispatch( + message: DispatchMessage, + ) -> MessageDispatchResult { + let payload = match message.data.payload { + Ok(payload) => payload, + Err(e) => { + log::error!( + target: LOG_TARGET, + "dispatch - payload error: {e:?} for lane_id: {:?} and message_nonce: {:?}", + message.key.lane_id, + message.key.nonce + ); + return MessageDispatchResult { + unspent_weight: Weight::zero(), + dispatch_level_result: XcmBlobMessageDispatchResult::InvalidPayload, + } + }, + }; + let dispatch_level_result = match T::BlobDispatcher::dispatch_blob(payload) { + Ok(_) => { + log::debug!( + target: LOG_TARGET, + "dispatch - `DispatchBlob::dispatch_blob` was ok for lane_id: {:?} and message_nonce: {:?}", + message.key.lane_id, + message.key.nonce + ); + XcmBlobMessageDispatchResult::Dispatched + }, + Err(e) => { + log::error!( + target: LOG_TARGET, + "dispatch - `DispatchBlob::dispatch_blob` failed with error: {e:?} for lane_id: {:?} and message_nonce: {:?}", + message.key.lane_id, + message.key.nonce + ); + XcmBlobMessageDispatchResult::NotDispatched(Some(e)) + }, + }; + MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{mock::*, Bridges, LaneToBridge, LanesManagerOf}; + + use bp_messages::{target_chain::DispatchMessageData, LaneIdType, MessageKey}; + use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState}; + use frame_support::assert_ok; + use pallet_bridge_messages::InboundLaneStorage; + use xcm_executor::traits::ConvertLocation; + + fn bridge() -> (Box, TestLaneIdType) { + let origin = OpenBridgeOrigin::sibling_parachain_origin(); + let with = bridged_asset_hub_universal_location(); + let locations = + XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap(); + let lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap(); + (locations, lane_id) + } + + fn run_test_with_opened_bridge(test: impl FnOnce()) { + run_test(|| { + let (bridge, lane_id) = bridge(); + + if !Bridges::::contains_key(bridge.bridge_id()) { + // insert bridge + Bridges::::insert( + bridge.bridge_id(), + Bridge { + bridge_origin_relative_location: Box::new( + bridge.bridge_origin_relative_location().clone().into(), + ), + bridge_origin_universal_location: Box::new( + bridge.bridge_origin_universal_location().clone().into(), + ), + bridge_destination_universal_location: Box::new( + bridge.bridge_destination_universal_location().clone().into(), + ), + state: BridgeState::Opened, + bridge_owner_account: LocationToAccountId::convert_location( + bridge.bridge_origin_relative_location(), + ) + .expect("valid accountId"), + deposit: 0, + lane_id, + }, + ); + LaneToBridge::::insert(lane_id, bridge.bridge_id()); + + // create lanes + let lanes_manager = LanesManagerOf::::new(); + if lanes_manager.create_inbound_lane(lane_id).is_ok() { + assert_eq!( + 0, + lanes_manager + .active_inbound_lane(lane_id) + .unwrap() + .storage() + .data() + .last_confirmed_nonce + ); + } + if lanes_manager.create_outbound_lane(lane_id).is_ok() { + assert!(lanes_manager + .active_outbound_lane(lane_id) + .unwrap() + .queued_messages() + .is_empty()); + } + } + assert_ok!(XcmOverBridge::do_try_state()); + + test(); + }); + } + + fn invalid_message() -> DispatchMessage, TestLaneIdType> { + DispatchMessage { + key: MessageKey { lane_id: TestLaneIdType::try_new(1, 2).unwrap(), nonce: 1 }, + data: DispatchMessageData { payload: Err(codec::Error::from("test")) }, + } + } + + fn valid_message() -> DispatchMessage, TestLaneIdType> { + DispatchMessage { + key: MessageKey { lane_id: TestLaneIdType::try_new(1, 2).unwrap(), nonce: 1 }, + data: DispatchMessageData { payload: Ok(vec![42]) }, + } + } + + #[test] + fn dispatcher_is_inactive_when_channel_with_target_chain_is_congested() { + run_test_with_opened_bridge(|| { + TestLocalXcmChannelManager::make_congested(); + assert!(!XcmOverBridge::is_active(bridge().1)); + }); + } + + #[test] + fn dispatcher_is_active_when_channel_with_target_chain_is_not_congested() { + run_test_with_opened_bridge(|| { + assert!(XcmOverBridge::is_active(bridge().1)); + }); + } + + #[test] + fn dispatch_weight_is_zero_if_we_have_failed_to_decode_message() { + run_test(|| { + assert_eq!(XcmOverBridge::dispatch_weight(&mut invalid_message()), Weight::zero()); + }); + } + + #[test] + fn dispatch_weight_is_non_zero_if_we_have_decoded_message() { + run_test(|| { + assert_ne!(XcmOverBridge::dispatch_weight(&mut valid_message()), Weight::zero()); + }); + } + + #[test] + fn message_is_not_dispatched_when_we_have_failed_to_decode_message() { + run_test(|| { + assert_eq!( + XcmOverBridge::dispatch(invalid_message()), + MessageDispatchResult { + unspent_weight: Weight::zero(), + dispatch_level_result: XcmBlobMessageDispatchResult::InvalidPayload, + }, + ); + assert!(!TestBlobDispatcher::is_dispatched()); + }); + } + + #[test] + fn message_is_dispatched_when_we_have_decoded_message() { + run_test(|| { + assert_eq!( + XcmOverBridge::dispatch(valid_message()), + MessageDispatchResult { + unspent_weight: Weight::zero(), + dispatch_level_result: XcmBlobMessageDispatchResult::Dispatched, + }, + ); + assert!(TestBlobDispatcher::is_dispatched()); + }); + } +} diff --git a/bridges/modules/xcm-bridge-hub/src/exporter.rs b/bridges/modules/xcm-bridge-hub/src/exporter.rs index 94ec8b5f106f..5afb9f36bc94 100644 --- a/bridges/modules/xcm-bridge-hub/src/exporter.rs +++ b/bridges/modules/xcm-bridge-hub/src/exporter.rs @@ -22,14 +22,29 @@ use crate::{Config, Pallet, LOG_TARGET}; -use bp_messages::source_chain::MessagesBridge; -use bp_xcm_bridge_hub::XcmAsPlainPayload; -use bridge_runtime_common::messages_xcm_extension::{LocalXcmQueueManager, SenderAndLane}; -use pallet_bridge_messages::{Config as BridgeMessagesConfig, Pallet as BridgeMessagesPallet}; +use crate::{BridgeOf, Bridges}; + +use bp_messages::{ + source_chain::{MessagesBridge, OnMessagesDelivered}, + MessageNonce, +}; +use bp_xcm_bridge_hub::{BridgeId, BridgeState, LocalXcmChannelManager, XcmAsPlainPayload}; +use frame_support::{ensure, traits::Get}; +use pallet_bridge_messages::{ + Config as BridgeMessagesConfig, Error, Pallet as BridgeMessagesPallet, +}; use xcm::prelude::*; use xcm_builder::{HaulBlob, HaulBlobError, HaulBlobExporter}; use xcm_executor::traits::ExportXcm; +/// Maximal number of messages in the outbound bridge queue. Once we reach this limit, we +/// suspend a bridge. +const OUTBOUND_LANE_CONGESTED_THRESHOLD: MessageNonce = 8_192; + +/// After we have suspended the bridge, we wait until number of messages in the outbound bridge +/// queue drops to this count, before sending resuming the bridge. +const OUTBOUND_LANE_UNCONGESTED_THRESHOLD: MessageNonce = 1_024; + /// An easy way to access `HaulBlobExporter`. pub type PalletAsHaulBlobExporter = HaulBlobExporter< DummyHaulBlob, @@ -45,8 +60,9 @@ where T: BridgeMessagesConfig, { type Ticket = ( - SenderAndLane, - as MessagesBridge>::SendMessageArgs, + BridgeId, + BridgeOf, + as MessagesBridge>::SendMessageArgs, XcmHash, ); @@ -57,12 +73,72 @@ where destination: &mut Option, message: &mut Option>, ) -> Result<(Self::Ticket, Assets), SendError> { - // Find supported lane_id. - let sender_and_lane = Self::lane_for( - universal_source.as_ref().ok_or(SendError::MissingArgument)?, - (&network, destination.as_ref().ok_or(SendError::MissingArgument)?), + log::trace!( + target: LOG_TARGET, + "Validate for network: {network:?}, channel: {channel:?}, universal_source: {universal_source:?}, destination: {destination:?}" + ); + + // `HaulBlobExporter` may consume the `universal_source` and `destination` arguments, so + // let's save them before + let bridge_origin_universal_location = + universal_source.clone().take().ok_or(SendError::MissingArgument)?; + // Note: watch out this is `ExportMessage::destination`, which is relative to the `network`, + // which means it does not contain `GlobalConsensus`, We need to find `BridgeId` with + // `Self::bridge_locations` which requires **universal** location for destination. + let bridge_destination_universal_location = { + let dest = destination.clone().take().ok_or(SendError::MissingArgument)?; + match dest.global_consensus() { + Ok(dest_network) => { + log::trace!( + target: LOG_TARGET, + "Destination: {dest:?} is already universal, checking dest_network: {dest_network:?} and network: {network:?} if matches: {:?}", + dest_network == network + ); + ensure!(dest_network == network, SendError::NotApplicable); + // ok, `dest` looks like a universal location, so let's use it + dest + }, + Err(_) => { + // `dest` is not a universal location, so we need to prepend it with + // `GlobalConsensus`. + dest.pushed_front_with(GlobalConsensus(network)).map_err(|error_data| { + log::error!( + target: LOG_TARGET, + "Destination: {:?} is not a universal and prepending with {:?} failed!", + error_data.0, + error_data.1, + ); + SendError::NotApplicable + })? + }, + } + }; + + // prepare the origin relative location + let bridge_origin_relative_location = + bridge_origin_universal_location.relative_to(&T::UniversalLocation::get()); + + // then we are able to compute the `BridgeId` and find `LaneId` used to send messages + let locations = Self::bridge_locations( + bridge_origin_relative_location, + bridge_destination_universal_location.into(), ) - .ok_or(SendError::NotApplicable)?; + .map_err(|e| { + log::error!( + target: LOG_TARGET, + "Validate `bridge_locations` with error: {e:?}", + ); + SendError::NotApplicable + })?; + let bridge = Self::bridge(locations.bridge_id()).ok_or_else(|| { + log::error!( + target: LOG_TARGET, + "No opened bridge for requested bridge_origin_relative_location: {:?} and bridge_destination_universal_location: {:?}", + locations.bridge_origin_relative_location(), + locations.bridge_destination_universal_location(), + ); + SendError::NotApplicable + })?; // check if we are able to route the message. We use existing `HaulBlobExporter` for that. // It will make all required changes and will encode message properly, so that the @@ -75,43 +151,197 @@ where message, )?; - let bridge_message = MessagesPallet::::validate_message(sender_and_lane.lane, &blob) + let bridge_message = MessagesPallet::::validate_message(bridge.lane_id, &blob) .map_err(|e| { - log::debug!( + match e { + Error::LanesManager(ref ei) => + log::error!(target: LOG_TARGET, "LanesManager: {ei:?}"), + Error::MessageRejectedByPallet(ref ei) => + log::error!(target: LOG_TARGET, "MessageRejectedByPallet: {ei:?}"), + Error::ReceptionConfirmation(ref ei) => + log::error!(target: LOG_TARGET, "ReceptionConfirmation: {ei:?}"), + _ => (), + }; + + log::error!( target: LOG_TARGET, - "XCM message {:?} cannot be exported because of bridge error {:?} on bridge {:?}", + "XCM message {:?} cannot be exported because of bridge error: {:?} on bridge {:?} and laneId: {:?}", id, e, - sender_and_lane.lane, + locations, + bridge.lane_id, ); SendError::Transport("BridgeValidateError") })?; - Ok(((sender_and_lane, bridge_message, id), price)) + Ok(((*locations.bridge_id(), bridge, bridge_message, id), price)) } - fn deliver((sender_and_lane, bridge_message, id): Self::Ticket) -> Result { - let lane_id = sender_and_lane.lane; + fn deliver( + (bridge_id, bridge, bridge_message, id): Self::Ticket, + ) -> Result { let artifacts = MessagesPallet::::send_message(bridge_message); log::info!( target: LOG_TARGET, - "XCM message {:?} has been enqueued at bridge {:?} with nonce {}", + "XCM message {:?} has been enqueued at bridge {:?} and lane_id: {:?} with nonce {}", id, - lane_id, + bridge_id, + bridge.lane_id, artifacts.nonce, ); - // notify XCM queue manager about updated lane state - LocalXcmQueueManager::::on_bridge_message_enqueued( - &sender_and_lane, - artifacts.enqueued_messages, - ); + // maybe we need switch to congested state + Self::on_bridge_message_enqueued(bridge_id, bridge, artifacts.enqueued_messages); Ok(id) } } +impl, I: 'static> OnMessagesDelivered for Pallet { + fn on_messages_delivered(lane_id: T::LaneId, enqueued_messages: MessageNonce) { + Self::on_bridge_messages_delivered(lane_id, enqueued_messages); + } +} + +impl, I: 'static> Pallet { + /// Called when new message is pushed onto outbound bridge queue. + fn on_bridge_message_enqueued( + bridge_id: BridgeId, + bridge: BridgeOf, + enqueued_messages: MessageNonce, + ) { + // if the bridge queue is not congested, we don't want to do anything + let is_congested = enqueued_messages > OUTBOUND_LANE_CONGESTED_THRESHOLD; + if !is_congested { + return + } + + // TODO: https://github.com/paritytech/parity-bridges-common/issues/2006 we either need fishermens + // to watch this rule violation (suspended, but keep sending new messages), or we need a + // hard limit for that like other XCM queues have + + // check if the lane is already suspended. If it is, do nothing. We still accept new + // messages to the suspended bridge, hoping that it'll be actually resumed soon + if bridge.state == BridgeState::Suspended { + return + } + + // else - suspend the bridge + let bridge_origin_relative_location = match bridge.bridge_origin_relative_location.try_as() + { + Ok(bridge_origin_relative_location) => bridge_origin_relative_location, + Err(_) => { + log::debug!( + target: LOG_TARGET, + "Failed to convert the bridge {:?} origin location {:?}", + bridge_id, + bridge.bridge_origin_relative_location, + ); + + return + }, + }; + let suspend_result = + T::LocalXcmChannelManager::suspend_bridge(bridge_origin_relative_location, bridge_id); + match suspend_result { + Ok(_) => { + log::debug!( + target: LOG_TARGET, + "Suspended the bridge {:?}, originated by the {:?}", + bridge_id, + bridge.bridge_origin_relative_location, + ); + }, + Err(e) => { + log::debug!( + target: LOG_TARGET, + "Failed to suspended the bridge {:?}, originated by the {:?}: {:?}", + bridge_id, + bridge.bridge_origin_relative_location, + e, + ); + + return + }, + } + + // and remember that we have suspended the bridge + Bridges::::mutate_extant(bridge_id, |bridge| { + bridge.state = BridgeState::Suspended; + }); + } + + /// Must be called whenever we receive a message delivery confirmation. + fn on_bridge_messages_delivered(lane_id: T::LaneId, enqueued_messages: MessageNonce) { + // if the bridge queue is still congested, we don't want to do anything + let is_congested = enqueued_messages > OUTBOUND_LANE_UNCONGESTED_THRESHOLD; + if is_congested { + return + } + + // if we have not suspended the bridge before (or it is closed), we don't want to do + // anything + let (bridge_id, bridge) = match Self::bridge_by_lane_id(&lane_id) { + Some(bridge) if bridge.1.state == BridgeState::Suspended => bridge, + _ => { + // if there is no bridge or it has been closed, then we don't need to send resume + // signal to the local origin - it has closed bridge itself, so it should have + // alrady pruned everything else + return + }, + }; + + // else - resume the bridge + let bridge_origin_relative_location = (*bridge.bridge_origin_relative_location).try_into(); + let bridge_origin_relative_location = match bridge_origin_relative_location { + Ok(bridge_origin_relative_location) => bridge_origin_relative_location, + Err(e) => { + log::debug!( + target: LOG_TARGET, + "Failed to convert the bridge {:?} location for lane_id: {:?}, error {:?}", + bridge_id, + lane_id, + e, + ); + + return + }, + }; + + let resume_result = + T::LocalXcmChannelManager::resume_bridge(&bridge_origin_relative_location, bridge_id); + match resume_result { + Ok(_) => { + log::debug!( + target: LOG_TARGET, + "Resumed the bridge {:?} and lane_id: {:?}, originated by the {:?}", + bridge_id, + lane_id, + bridge_origin_relative_location, + ); + }, + Err(e) => { + log::debug!( + target: LOG_TARGET, + "Failed to resume the bridge {:?} and lane_id: {:?}, originated by the {:?}: {:?}", + bridge_id, + lane_id, + bridge_origin_relative_location, + e, + ); + + return + }, + } + + // and forget that we have previously suspended the bridge + Bridges::::mutate_extant(bridge_id, |bridge| { + bridge.state = BridgeState::Opened; + }); + } +} + /// Dummy implementation of the `HaulBlob` trait that is never called. /// /// We are using `HaulBlobExporter`, which requires `HaulBlob` implementation. It assumes that @@ -130,29 +360,203 @@ impl HaulBlob for DummyHaulBlob { #[cfg(test)] mod tests { use super::*; - use crate::mock::*; + use crate::{mock::*, Bridges, LaneToBridge, LanesManagerOf}; + + use bp_runtime::RangeInclusiveExt; + use bp_xcm_bridge_hub::{Bridge, BridgeLocations, BridgeState}; use frame_support::assert_ok; - use xcm_executor::traits::export_xcm; + use pallet_bridge_messages::InboundLaneStorage; + use xcm_builder::{NetworkExportTable, UnpaidRemoteExporter}; + use xcm_executor::traits::{export_xcm, ConvertLocation}; fn universal_source() -> InteriorLocation { - [GlobalConsensus(RelayNetwork::get()), Parachain(SIBLING_ASSET_HUB_ID)].into() + SiblingUniversalLocation::get() + } + + fn bridged_relative_destination() -> InteriorLocation { + BridgedRelativeDestination::get() + } + + fn bridged_universal_destination() -> InteriorLocation { + BridgedUniversalDestination::get() + } + + fn open_lane() -> (BridgeLocations, TestLaneIdType) { + // open expected outbound lane + let origin = OpenBridgeOrigin::sibling_parachain_origin(); + let with = bridged_asset_hub_universal_location(); + let locations = + XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap(); + let lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap(); + + if !Bridges::::contains_key(locations.bridge_id()) { + // insert bridge + Bridges::::insert( + locations.bridge_id(), + Bridge { + bridge_origin_relative_location: Box::new(SiblingLocation::get().into()), + bridge_origin_universal_location: Box::new( + locations.bridge_origin_universal_location().clone().into(), + ), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into(), + ), + state: BridgeState::Opened, + bridge_owner_account: LocationToAccountId::convert_location( + locations.bridge_origin_relative_location(), + ) + .expect("valid accountId"), + deposit: 0, + lane_id, + }, + ); + LaneToBridge::::insert(lane_id, locations.bridge_id()); + + // create lanes + let lanes_manager = LanesManagerOf::::new(); + if lanes_manager.create_inbound_lane(lane_id).is_ok() { + assert_eq!( + 0, + lanes_manager + .active_inbound_lane(lane_id) + .unwrap() + .storage() + .data() + .last_confirmed_nonce + ); + } + if lanes_manager.create_outbound_lane(lane_id).is_ok() { + assert!(lanes_manager + .active_outbound_lane(lane_id) + .unwrap() + .queued_messages() + .is_empty()); + } + } + assert_ok!(XcmOverBridge::do_try_state()); + + (*locations, lane_id) } - fn universal_destination() -> InteriorLocation { - BridgedDestination::get() + fn open_lane_and_send_regular_message() -> (BridgeId, TestLaneIdType) { + let (locations, lane_id) = open_lane(); + + // now let's try to enqueue message using our `ExportXcm` implementation + export_xcm::( + BridgedRelayNetwork::get(), + 0, + locations.bridge_origin_universal_location().clone(), + locations.bridge_destination_universal_location().clone(), + vec![Instruction::ClearOrigin].into(), + ) + .unwrap(); + + (*locations.bridge_id(), lane_id) } #[test] - fn export_works() { + fn exporter_works() { run_test(|| { - assert_ok!(export_xcm::( - BridgedRelayNetwork::get(), - 0, - universal_source(), - universal_destination(), - vec![Instruction::ClearOrigin].into(), - )); - }) + let (_, lane_id) = open_lane_and_send_regular_message(); + + // double check that the message has been pushed to the expected lane + // (it should already been checked during `send_message` call) + assert!(!LanesManagerOf::::new() + .active_outbound_lane(lane_id) + .unwrap() + .queued_messages() + .is_empty()); + }); + } + + #[test] + fn exporter_does_not_suspend_the_bridge_if_outbound_bridge_queue_is_not_congested() { + run_test(|| { + let (bridge_id, _) = open_lane_and_send_regular_message(); + assert!(!TestLocalXcmChannelManager::is_bridge_suspened()); + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); + }); + } + + #[test] + fn exporter_does_not_suspend_the_bridge_if_it_is_already_suspended() { + run_test(|| { + let (bridge_id, _) = open_lane_and_send_regular_message(); + Bridges::::mutate_extant(bridge_id, |bridge| { + bridge.state = BridgeState::Suspended; + }); + for _ in 1..OUTBOUND_LANE_CONGESTED_THRESHOLD { + open_lane_and_send_regular_message(); + } + + open_lane_and_send_regular_message(); + assert!(!TestLocalXcmChannelManager::is_bridge_suspened()); + }); + } + + #[test] + fn exporter_suspends_the_bridge_if_outbound_bridge_queue_is_congested() { + run_test(|| { + let (bridge_id, _) = open_lane_and_send_regular_message(); + for _ in 1..OUTBOUND_LANE_CONGESTED_THRESHOLD { + open_lane_and_send_regular_message(); + } + + assert!(!TestLocalXcmChannelManager::is_bridge_suspened()); + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); + + open_lane_and_send_regular_message(); + assert!(TestLocalXcmChannelManager::is_bridge_suspened()); + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Suspended); + }); + } + + #[test] + fn bridge_is_not_resumed_if_outbound_bridge_queue_is_still_congested() { + run_test(|| { + let (bridge_id, lane_id) = open_lane_and_send_regular_message(); + Bridges::::mutate_extant(bridge_id, |bridge| { + bridge.state = BridgeState::Suspended; + }); + XcmOverBridge::on_bridge_messages_delivered( + lane_id, + OUTBOUND_LANE_UNCONGESTED_THRESHOLD + 1, + ); + + assert!(!TestLocalXcmChannelManager::is_bridge_resumed()); + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Suspended); + }); + } + + #[test] + fn bridge_is_not_resumed_if_it_was_not_suspended_before() { + run_test(|| { + let (bridge_id, lane_id) = open_lane_and_send_regular_message(); + XcmOverBridge::on_bridge_messages_delivered( + lane_id, + OUTBOUND_LANE_UNCONGESTED_THRESHOLD, + ); + + assert!(!TestLocalXcmChannelManager::is_bridge_resumed()); + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); + }); + } + + #[test] + fn bridge_is_resumed_when_enough_messages_are_delivered() { + run_test(|| { + let (bridge_id, lane_id) = open_lane_and_send_regular_message(); + Bridges::::mutate_extant(bridge_id, |bridge| { + bridge.state = BridgeState::Suspended; + }); + XcmOverBridge::on_bridge_messages_delivered( + lane_id, + OUTBOUND_LANE_UNCONGESTED_THRESHOLD, + ); + + assert!(TestLocalXcmChannelManager::is_bridge_resumed()); + assert_eq!(XcmOverBridge::bridge(&bridge_id).unwrap().state, BridgeState::Opened); + }); } #[test] @@ -163,7 +567,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), @@ -185,22 +589,195 @@ mod tests { #[test] fn exporter_computes_correct_lane_id() { run_test(|| { - let expected_lane_id = TEST_LANE_ID; + assert_ne!(bridged_universal_destination(), bridged_relative_destination()); + + let locations = BridgeLocations::bridge_locations( + UniversalLocation::get(), + SiblingLocation::get(), + bridged_universal_destination(), + BridgedRelayNetwork::get(), + ) + .unwrap(); + let expected_bridge_id = locations.bridge_id(); + let expected_lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap(); + + if LanesManagerOf::::new() + .create_outbound_lane(expected_lane_id) + .is_ok() + { + Bridges::::insert( + expected_bridge_id, + Bridge { + bridge_origin_relative_location: Box::new( + locations.bridge_origin_relative_location().clone().into(), + ), + bridge_origin_universal_location: Box::new( + locations.bridge_origin_universal_location().clone().into(), + ), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into(), + ), + state: BridgeState::Opened, + bridge_owner_account: [0u8; 32].into(), + deposit: 0, + lane_id: expected_lane_id, + }, + ); + } + + let ticket = XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + // Note: The `ExportMessage` expects relative `InteriorLocation` in the + // `BridgedRelayNetwork`. + &mut Some(bridged_relative_destination()), + &mut Some(Vec::new().into()), + ) + .unwrap() + .0; + assert_eq!(&ticket.0, expected_bridge_id); + assert_eq!(ticket.1.lane_id, expected_lane_id); + }); + } + + #[test] + fn exporter_is_compatible_with_pallet_xcm_bridge_hub_router() { + run_test(|| { + // valid routable destination + let dest = Location::new(2, BridgedUniversalDestination::get()); + + // open bridge + let (_, expected_lane_id) = open_lane(); + + // check before - no messages + assert_eq!( + pallet_bridge_messages::Pallet::::outbound_lane_data( + expected_lane_id + ) + .unwrap() + .queued_messages() + .saturating_len(), + 0 + ); + + // send `ExportMessage(message)` by `UnpaidRemoteExporter`. + TestExportXcmWithXcmOverBridge::set_origin_for_execute(SiblingLocation::get()); + assert_ok!(send_xcm::< + UnpaidRemoteExporter< + NetworkExportTable, + TestExportXcmWithXcmOverBridge, + UniversalLocation, + >, + >(dest.clone(), Xcm::<()>::default())); + + // send `ExportMessage(message)` by `pallet_xcm_bridge_hub_router`. + TestExportXcmWithXcmOverBridge::set_origin_for_execute(SiblingLocation::get()); + assert_ok!(send_xcm::(dest.clone(), Xcm::<()>::default())); + + // check after - a message ready to be relayed + assert_eq!( + pallet_bridge_messages::Pallet::::outbound_lane_data( + expected_lane_id + ) + .unwrap() + .queued_messages() + .saturating_len(), + 2 + ); + }) + } + + #[test] + fn validate_works() { + run_test(|| { + let xcm: Xcm<()> = vec![ClearOrigin].into(); + + // check that router does not consume when `NotApplicable` + let mut xcm_wrapper = Some(xcm.clone()); + let mut universal_source_wrapper = Some(universal_source()); + + // wrong `NetworkId` + let mut dest_wrapper = Some(bridged_relative_destination()); + assert_eq!( + XcmOverBridge::validate( + NetworkId::ByGenesis([0; 32]), + 0, + &mut universal_source_wrapper, + &mut dest_wrapper, + &mut xcm_wrapper, + ), + Err(SendError::NotApplicable), + ); + // dest and xcm is NOT consumed and untouched + assert_eq!(&Some(xcm.clone()), &xcm_wrapper); + assert_eq!(&Some(universal_source()), &universal_source_wrapper); + assert_eq!(&Some(bridged_relative_destination()), &dest_wrapper); + // dest starts with wrong `NetworkId` + let mut invalid_dest_wrapper = Some( + [GlobalConsensus(NetworkId::ByGenesis([0; 32])), Parachain(BRIDGED_ASSET_HUB_ID)] + .into(), + ); assert_eq!( XcmOverBridge::validate( BridgedRelayNetwork::get(), 0, &mut Some(universal_source()), - &mut Some(universal_destination()), - &mut Some(Vec::new().into()), - ) - .unwrap() - .0 - .0 - .lane, - expected_lane_id, + &mut invalid_dest_wrapper, + &mut xcm_wrapper, + ), + Err(SendError::NotApplicable), ); - }) + // dest and xcm is NOT consumed and untouched + assert_eq!(&Some(xcm.clone()), &xcm_wrapper); + assert_eq!(&Some(universal_source()), &universal_source_wrapper); + assert_eq!( + &Some( + [ + GlobalConsensus(NetworkId::ByGenesis([0; 32]),), + Parachain(BRIDGED_ASSET_HUB_ID) + ] + .into() + ), + &invalid_dest_wrapper + ); + + // no opened lane for dest + let mut dest_without_lane_wrapper = + Some([GlobalConsensus(BridgedRelayNetwork::get()), Parachain(5679)].into()); + assert_eq!( + XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + &mut dest_without_lane_wrapper, + &mut xcm_wrapper, + ), + Err(SendError::NotApplicable), + ); + // dest and xcm is NOT consumed and untouched + assert_eq!(&Some(xcm.clone()), &xcm_wrapper); + assert_eq!(&Some(universal_source()), &universal_source_wrapper); + assert_eq!( + &Some([GlobalConsensus(BridgedRelayNetwork::get(),), Parachain(5679)].into()), + &dest_without_lane_wrapper + ); + + // ok + let _ = open_lane(); + let mut dest_wrapper = Some(bridged_relative_destination()); + assert_ok!(XcmOverBridge::validate( + BridgedRelayNetwork::get(), + 0, + &mut Some(universal_source()), + &mut dest_wrapper, + &mut xcm_wrapper, + )); + // dest and xcm IS consumed + assert_eq!(None, xcm_wrapper); + assert_eq!(&Some(universal_source()), &universal_source_wrapper); + assert_eq!(None, dest_wrapper); + }); } } diff --git a/bridges/modules/xcm-bridge-hub/src/lib.rs b/bridges/modules/xcm-bridge-hub/src/lib.rs index 60b988497fc5..1b2536598a20 100644 --- a/bridges/modules/xcm-bridge-hub/src/lib.rs +++ b/bridges/modules/xcm-bridge-hub/src/lib.rs @@ -14,19 +14,156 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -//! Module that adds XCM support to bridge pallets. +//! Module that adds XCM support to bridge pallets. The pallet allows to dynamically +//! open and close bridges between local (to this pallet location) and remote XCM +//! destinations. +//! +//! The `pallet_xcm_bridge_hub` pallet is used to manage (open, close) bridges between chains from +//! different consensuses. The new extrinsics `fn open_bridge` and `fn close_bridge` are introduced. +//! Other chains can manage channels with different bridged global consensuses. +//! +//! # Concept of `lane` and `LaneId` +//! +//! There is another `pallet_bridge_messages` pallet that handles inbound/outbound lanes for +//! messages. Each lane is a unique connection between two chains from different consensuses and is +//! identified by `LaneId`. `LaneId` is generated once when a new bridge is requested by `fn +//! open_bridge`. It is generated by `BridgeLocations::calculate_lane_id` based on the following +//! parameters: +//! - Source `bridge_origin_universal_location` (latest XCM) +//! - Destination `bridge_destination_universal_location` (latest XCM) +//! - XCM version (both sides of the bridge must use the same parameters to generate the same +//! `LaneId`) +//! - `bridge_origin_universal_location`, `bridge_destination_universal_location` is converted to +//! the `Versioned*` structs +//! +//! `LaneId` is expected to never change because: +//! - We need the same `LaneId` on both sides of the bridge, as `LaneId` is part of the message key +//! proofs. +//! - Runtime upgrades are entirely asynchronous. +//! - We already have a running production Polkadot/Kusama bridge that uses `LaneId([0, 0, 0, 0])`. +//! +//! `LaneId` is backward compatible, meaning it can be encoded/decoded from the older format `[u8; +//! 4]` used for static lanes, as well as the new format `H256` generated by +//! `BridgeLocations::calculate_lane_id`. +//! +//! # Concept of `bridge` and `BridgeId` +//! +//! The `pallet_xcm_bridge_hub` pallet needs to store some metadata about opened bridges. The bridge +//! (or bridge metadata) is stored under the `BridgeId` key. +//! +//! `BridgeId` is generated from `bridge_origin_relative_location` and +//! `bridge_origin_universal_location` using the `latest` XCM structs. `BridgeId` is not transferred +//! over the bridge; it is only important for local consensus. It essentially serves as an index/key +//! to bridge metadata. All the XCM infrastructure around `XcmExecutor`, `SendXcm`, `ExportXcm` use +//! the `latest` XCM, so `BridgeId` must remain compatible with the `latest` XCM. For example, we +//! have an `ExportXcm` implementation in `exporter.rs` that handles the `ExportMessage` instruction +//! with `universal_source` and `destination` (latest XCM), so we need to create `BridgeId` and the +//! corresponding `LaneId`. +//! +//! # Migrations and State +//! +//! This pallet implements `try_state`, ensuring compatibility and checking everything so we know if +//! any migration is needed. `do_try_state` checks for `BridgeId` compatibility, which is +//! recalculated on runtime upgrade. Upgrading to a new XCM version should not break anything, +//! except removing older XCM versions. In such cases, we need to add migration for `BridgeId` and +//! stored `Versioned*` structs and update `LaneToBridge` mapping, but this won't affect `LaneId` +//! over the bridge. +//! +//! # How to Open a Bridge? +//! +//! The `pallet_xcm_bridge_hub` pallet has the extrinsic `fn open_bridge` and an important +//! configuration `pallet_xcm_bridge_hub::Config::OpenBridgeOrigin`, which translates the call's +//! origin to the XCM `Location` and converts it to the `bridge_origin_universal_location`. With the +//! current setup, this origin/location is expected to be either the relay chain or a sibling +//! parachain as one side of the bridge. Another parameter is +//! `bridge_destination_universal_location`, which is the other side of the bridge from a different +//! global consensus. +//! +//! Every bridge between two XCM locations has a dedicated lane in associated +//! messages pallet. Assuming that this pallet is deployed at the bridge hub +//! parachain and there's a similar pallet at the bridged network, the dynamic +//! bridge lifetime is as follows: +//! +//! 1) the sibling parachain opens a XCMP channel with this bridge hub; +//! +//! 2) the sibling parachain funds its sovereign parachain account at this bridge hub. It shall hold +//! enough funds to pay for the bridge (see `BridgeDeposit`); +//! +//! 3) the sibling parachain opens the bridge by sending XCM `Transact` instruction with the +//! `open_bridge` call. The `BridgeDeposit` amount is reserved on the sovereign account of +//! sibling parachain; +//! +//! 4) at the other side of the bridge, the same thing (1, 2, 3) happens. Parachains that need to +//! connect over the bridge need to coordinate the moment when they start sending messages over +//! the bridge. Otherwise they may lose messages and/or bundled assets; +//! +//! 5) when either side wants to close the bridge, it sends the XCM `Transact` with the +//! `close_bridge` call. The bridge is closed immediately if there are no queued messages. +//! Otherwise, the owner must repeat the `close_bridge` call to prune all queued messages first. +//! +//! The pallet doesn't provide any mechanism for graceful closure, because it always involves +//! some contract between two connected chains and the bridge hub knows nothing about that. It +//! is the task for the connected chains to make sure that all required actions are completed +//! before the closure. In the end, the bridge hub can't even guarantee that all messages that +//! are delivered to the destination, are processed in the way their sender expects. So if we +//! can't guarantee that, we shall not care about more complex procedures and leave it to the +//! participating parties. +//! +//! # Example +//! +//! Example of opening a bridge between some random parachains from Polkadot and Kusama: +//! +//! 0. Let's have: +//! - BridgeHubPolkadot with `UniversalLocation` = `[GlobalConsensus(Polkadot), Parachain(1002)]` +//! - BridgeHubKusama with `UniversalLocation` = `[GlobalConsensus(Kusama), Parachain(1002)]` +//! 1. The Polkadot local sibling parachain `Location::new(1, Parachain(1234))` must send some DOTs +//! to its sovereign account on BridgeHubPolkadot to cover `BridgeDeposit`, fees for `Transact`, +//! and the existential deposit. +//! 2. Send a call to the BridgeHubPolkadot from the local sibling parachain: `Location::new(1, +//! Parachain(1234))` ``` xcm::Transact( origin_kind: OriginKind::Xcm, +//! XcmOverBridgeHubKusama::open_bridge( VersionedInteriorLocation::V4([GlobalConsensus(Kusama), +//! Parachain(4567)].into()), ); ) ``` +//! 3. Check the stored bridge metadata and generated `LaneId`. +//! 4. The Kusama local sibling parachain `Location::new(1, Parachain(4567))` must send some KSMs to +//! its sovereign account +//! on BridgeHubKusama to cover `BridgeDeposit`, fees for `Transact`, and the existential deposit. +//! 5. Send a call to the BridgeHubKusama from the local sibling parachain: `Location::new(1, +//! Parachain(4567))` ``` xcm::Transact( origin_kind: OriginKind::Xcm, +//! XcmOverBridgeHubKusama::open_bridge( +//! VersionedInteriorLocation::V4([GlobalConsensus(Polkadot), Parachain(1234)].into()), ); ) ``` +//! 6. Check the stored bridge metadata and generated `LaneId`. +//! 7. Both `LaneId`s from steps 3 and 6 must be the same (see above _Concept of `lane` and +//! `LaneId`_). +//! 8. Run the bridge messages relayer for `LaneId`. +//! 9. Send messages from both sides. +//! +//! The opening bridge holds the configured `BridgeDeposit` from the origin's sovereign account, but +//! this deposit is returned when the bridge is closed with `fn close_bridge`. #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -use bridge_runtime_common::messages_xcm_extension::XcmBlobHauler; -use pallet_bridge_messages::Config as BridgeMessagesConfig; +use bp_messages::{LaneState, MessageNonce}; +use bp_runtime::{AccountIdOf, BalanceOf, RangeInclusiveExt}; +pub use bp_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; +use bp_xcm_bridge_hub::{BridgeLocations, BridgeLocationsError, LocalXcmChannelManager}; +use frame_support::{traits::fungible::MutateHold, DefaultNoBound}; +use frame_system::Config as SystemConfig; +use pallet_bridge_messages::{Config as BridgeMessagesConfig, LanesManagerError}; +use sp_runtime::traits::Zero; +use sp_std::{boxed::Box, vec::Vec}; use xcm::prelude::*; +use xcm_builder::DispatchBlob; +use xcm_executor::traits::ConvertLocation; +pub use bp_xcm_bridge_hub::XcmAsPlainPayload; +pub use dispatcher::XcmBlobMessageDispatchResult; pub use exporter::PalletAsHaulBlobExporter; pub use pallet::*; +mod dispatcher; mod exporter; +pub mod migration; mod mock; /// The target that will be used when publishing logs related to this pallet. @@ -35,15 +172,29 @@ pub const LOG_TARGET: &str = "runtime::bridge-xcm"; #[frame_support::pallet] pub mod pallet { use super::*; - use bridge_runtime_common::messages_xcm_extension::SenderAndLane; - use frame_support::pallet_prelude::*; - use frame_system::pallet_prelude::BlockNumberFor; + use frame_support::{ + pallet_prelude::*, + traits::{tokens::Precision, Contains}, + }; + use frame_system::pallet_prelude::{BlockNumberFor, *}; + + /// The reason for this pallet placing a hold on funds. + #[pallet::composite_enum] + pub enum HoldReason { + /// The funds are held as a deposit for opened bridge. + #[codec(index = 0)] + BridgeDeposit, + } #[pallet::config] #[pallet::disable_frame_system_supertrait_check] pub trait Config: BridgeMessagesConfig { + /// The overarching event type. + type RuntimeEvent: From> + + IsType<::RuntimeEvent>; + /// Runtime's universal location. type UniversalLocation: Get; // TODO: https://github.com/paritytech/parity-bridges-common/issues/1666 remove `ChainId` and @@ -56,63 +207,1495 @@ pub mod pallet { /// `BridgedNetworkId` consensus. type BridgeMessagesPalletInstance: 'static; - /// Price of single message export to the bridged consensus (`Self::BridgedNetworkId`). + /// Price of single message export to the bridged consensus (`Self::BridgedNetwork`). type MessageExportPrice: Get; /// Checks the XCM version for the destination. type DestinationVersion: GetVersion; - /// Get point-to-point links with bridged consensus (`Self::BridgedNetworkId`). - /// (this will be replaced with dynamic on-chain bridges - `Bridges V2`) - type Lanes: Get>; - /// Support for point-to-point links - /// (this will be replaced with dynamic on-chain bridges - `Bridges V2`) - type LanesSupport: XcmBlobHauler; + /// The origin that is allowed to call privileged operations on the pallet, e.g. open/close + /// bridge for locations. + type ForceOrigin: EnsureOrigin<::RuntimeOrigin>; + /// A set of XCM locations within local consensus system that are allowed to open + /// bridges with remote destinations. + type OpenBridgeOrigin: EnsureOrigin< + ::RuntimeOrigin, + Success = Location, + >; + /// A converter between a location and a sovereign account. + type BridgeOriginAccountIdConverter: ConvertLocation>>; + + /// Amount of this chain native tokens that is reserved on the sibling parachain account + /// when bridge open request is registered. + #[pallet::constant] + type BridgeDeposit: Get>>; + /// Currency used to pay for bridge registration. + type Currency: MutateHold< + AccountIdOf>, + Balance = BalanceOf>, + Reason = Self::RuntimeHoldReason, + >; + /// The overarching runtime hold reason. + type RuntimeHoldReason: From>; + /// Do not hold `Self::BridgeDeposit` for the location of `Self::OpenBridgeOrigin`. + /// For example, it is possible to make an exception for a system parachain or relay. + type AllowWithoutBridgeDeposit: Contains; + + /// Local XCM channel manager. + type LocalXcmChannelManager: LocalXcmChannelManager; + /// XCM-level dispatcher for inbound bridge messages. + type BlobDispatcher: DispatchBlob; } + /// An alias for the bridge metadata. + pub type BridgeOf = Bridge, LaneIdOf>; + /// An alias for this chain. + pub type ThisChainOf = + pallet_bridge_messages::ThisChainOf>::BridgeMessagesPalletInstance>; + /// An alias for lane identifier type. + pub type LaneIdOf = + >::BridgeMessagesPalletInstance>>::LaneId; + /// An alias for the associated lanes manager. + pub type LanesManagerOf = + pallet_bridge_messages::LanesManager>::BridgeMessagesPalletInstance>; + #[pallet::pallet] + #[pallet::storage_version(migration::STORAGE_VERSION)] pub struct Pallet(PhantomData<(T, I)>); #[pallet::hooks] impl, I: 'static> Hooks> for Pallet { fn integrity_test() { assert!( - Self::bridged_network_id().is_some(), + Self::bridged_network_id().is_ok(), "Configured `T::BridgedNetwork`: {:?} does not contain `GlobalConsensus` junction with `NetworkId`", T::BridgedNetwork::get() ) } + + #[cfg(feature = "try-runtime")] + fn try_state(_n: BlockNumberFor) -> Result<(), sp_runtime::TryRuntimeError> { + Self::do_try_state() + } + } + + #[pallet::call] + impl, I: 'static> Pallet { + /// Open a bridge between two locations. + /// + /// The caller must be within the `T::OpenBridgeOrigin` filter (presumably: a sibling + /// parachain or a parent relay chain). The `bridge_destination_universal_location` must be + /// a destination within the consensus of the `T::BridgedNetwork` network. + /// + /// The `BridgeDeposit` amount is reserved on the caller account. This deposit + /// is unreserved after bridge is closed. + /// + /// The states after this call: bridge is `Opened`, outbound lane is `Opened`, inbound lane + /// is `Opened`. + #[pallet::call_index(0)] + #[pallet::weight(Weight::zero())] // TODO:(bridges-v2) - https://github.com/paritytech/parity-bridges-common/issues/3046 - add benchmarks impl + pub fn open_bridge( + origin: OriginFor, + bridge_destination_universal_location: Box, + ) -> DispatchResult { + // check and compute required bridge locations and laneId + let xcm_version = bridge_destination_universal_location.identify_version(); + let locations = + Self::bridge_locations_from_origin(origin, bridge_destination_universal_location)?; + let lane_id = locations.calculate_lane_id(xcm_version).map_err(|e| { + log::trace!( + target: LOG_TARGET, + "calculate_lane_id error: {e:?}", + ); + Error::::BridgeLocations(e) + })?; + + Self::do_open_bridge(locations, lane_id, true) + } + + /// Try to close the bridge. + /// + /// Can only be called by the "owner" of this side of the bridge, meaning that the + /// inbound XCM channel with the local origin chain is working. + /// + /// Closed bridge is a bridge without any traces in the runtime storage. So this method + /// first tries to prune all queued messages at the outbound lane. When there are no + /// outbound messages left, outbound and inbound lanes are purged. After that, funds + /// are returned back to the owner of this side of the bridge. + /// + /// The number of messages that we may prune in a single call is limited by the + /// `may_prune_messages` argument. If there are more messages in the queue, the method + /// prunes exactly `may_prune_messages` and exits early. The caller may call it again + /// until outbound queue is depleted and get his funds back. + /// + /// The states after this call: everything is either `Closed`, or purged from the + /// runtime storage. + #[pallet::call_index(1)] + #[pallet::weight(Weight::zero())] // TODO:(bridges-v2) - https://github.com/paritytech/parity-bridges-common/issues/3046 - add benchmarks impl + pub fn close_bridge( + origin: OriginFor, + bridge_destination_universal_location: Box, + may_prune_messages: MessageNonce, + ) -> DispatchResult { + // compute required bridge locations + let locations = + Self::bridge_locations_from_origin(origin, bridge_destination_universal_location)?; + + // TODO: https://github.com/paritytech/parity-bridges-common/issues/1760 - may do refund here, if + // bridge/lanes are already closed + for messages that are not pruned + + // update bridge metadata - this also guarantees that the bridge is in the proper state + let bridge = + Bridges::::try_mutate_exists(locations.bridge_id(), |bridge| match bridge { + Some(bridge) => { + bridge.state = BridgeState::Closed; + Ok(bridge.clone()) + }, + None => Err(Error::::UnknownBridge), + })?; + + // close inbound and outbound lanes + let lanes_manager = LanesManagerOf::::new(); + let mut inbound_lane = lanes_manager + .any_state_inbound_lane(bridge.lane_id) + .map_err(Error::::LanesManager)?; + let mut outbound_lane = lanes_manager + .any_state_outbound_lane(bridge.lane_id) + .map_err(Error::::LanesManager)?; + + // now prune queued messages + let mut pruned_messages = 0; + for _ in outbound_lane.queued_messages() { + if pruned_messages == may_prune_messages { + break + } + + outbound_lane.remove_oldest_unpruned_message(); + pruned_messages += 1; + } + + // if there are outbound messages in the queue, just update states and early exit + if !outbound_lane.queued_messages().is_empty() { + // update lanes state. Under normal circumstances, following calls shall never fail + inbound_lane.set_state(LaneState::Closed); + outbound_lane.set_state(LaneState::Closed); + + // write something to log + let enqueued_messages = outbound_lane.queued_messages().saturating_len(); + log::trace!( + target: LOG_TARGET, + "Bridge {:?} between {:?} and {:?} is closing lane_id: {:?}. {} messages remaining", + locations.bridge_id(), + locations.bridge_origin_universal_location(), + locations.bridge_destination_universal_location(), + bridge.lane_id, + enqueued_messages, + ); + + // deposit the `ClosingBridge` event + Self::deposit_event(Event::::ClosingBridge { + bridge_id: *locations.bridge_id(), + lane_id: bridge.lane_id.into(), + pruned_messages, + enqueued_messages, + }); + + return Ok(()) + } + + // else we have pruned all messages, so lanes and the bridge itself may gone + inbound_lane.purge(); + outbound_lane.purge(); + Bridges::::remove(locations.bridge_id()); + LaneToBridge::::remove(bridge.lane_id); + + // return deposit + let released_deposit = T::Currency::release( + &HoldReason::BridgeDeposit.into(), + &bridge.bridge_owner_account, + bridge.deposit, + Precision::BestEffort, + ) + .inspect_err(|e| { + // we can't do anything here - looks like funds have been (partially) unreserved + // before by someone else. Let's not fail, though - it'll be worse for the caller + log::error!( + target: LOG_TARGET, + "Failed to unreserve during the bridge {:?} closure with error: {e:?}", + locations.bridge_id(), + ); + }) + .ok() + .unwrap_or(BalanceOf::>::zero()); + + // write something to log + log::trace!( + target: LOG_TARGET, + "Bridge {:?} between {:?} and {:?} has closed lane_id: {:?}, the bridge deposit {released_deposit:?} was returned", + locations.bridge_id(), + bridge.lane_id, + locations.bridge_origin_universal_location(), + locations.bridge_destination_universal_location(), + ); + + // deposit the `BridgePruned` event + Self::deposit_event(Event::::BridgePruned { + bridge_id: *locations.bridge_id(), + lane_id: bridge.lane_id.into(), + bridge_deposit: released_deposit, + pruned_messages, + }); + + Ok(()) + } } impl, I: 'static> Pallet { - /// Returns dedicated/configured lane identifier. - pub(crate) fn lane_for( - source: &InteriorLocation, - dest: (&NetworkId, &InteriorLocation), - ) -> Option { - let source = source.clone().relative_to(&T::UniversalLocation::get()); - - // Check that we have configured a point-to-point lane for 'source' and `dest`. - T::Lanes::get() - .into_iter() - .find_map(|(lane_source, (lane_dest_network, lane_dest))| { - if lane_source.location == source && - &lane_dest_network == dest.0 && - Self::bridged_network_id().as_ref() == Some(dest.0) && - &lane_dest == dest.1 - { - Some(lane_source) - } else { - None - } - }) + /// Open bridge for lane. + pub fn do_open_bridge( + locations: Box, + lane_id: T::LaneId, + create_lanes: bool, + ) -> Result<(), DispatchError> { + // reserve balance on the origin's sovereign account (if needed) + let bridge_owner_account = T::BridgeOriginAccountIdConverter::convert_location( + locations.bridge_origin_relative_location(), + ) + .ok_or(Error::::InvalidBridgeOriginAccount)?; + let deposit = if T::AllowWithoutBridgeDeposit::contains( + locations.bridge_origin_relative_location(), + ) { + BalanceOf::>::zero() + } else { + let deposit = T::BridgeDeposit::get(); + T::Currency::hold( + &HoldReason::BridgeDeposit.into(), + &bridge_owner_account, + deposit, + ) + .map_err(|e| { + log::error!( + target: LOG_TARGET, + "Failed to hold bridge deposit: {deposit:?} \ + from bridge_owner_account: {bridge_owner_account:?} derived from \ + bridge_origin_relative_location: {:?} with error: {e:?}", + locations.bridge_origin_relative_location(), + ); + Error::::FailedToReserveBridgeDeposit + })?; + deposit + }; + + // save bridge metadata + Bridges::::try_mutate(locations.bridge_id(), |bridge| match bridge { + Some(_) => Err(Error::::BridgeAlreadyExists), + None => { + *bridge = Some(BridgeOf:: { + bridge_origin_relative_location: Box::new( + locations.bridge_origin_relative_location().clone().into(), + ), + bridge_origin_universal_location: Box::new( + locations.bridge_origin_universal_location().clone().into(), + ), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into(), + ), + state: BridgeState::Opened, + bridge_owner_account, + deposit, + lane_id, + }); + Ok(()) + }, + })?; + // save lane to bridge mapping + LaneToBridge::::try_mutate(lane_id, |bridge| match bridge { + Some(_) => Err(Error::::BridgeAlreadyExists), + None => { + *bridge = Some(*locations.bridge_id()); + Ok(()) + }, + })?; + + if create_lanes { + // create new lanes. Under normal circumstances, following calls shall never fail + let lanes_manager = LanesManagerOf::::new(); + lanes_manager + .create_inbound_lane(lane_id) + .map_err(Error::::LanesManager)?; + lanes_manager + .create_outbound_lane(lane_id) + .map_err(Error::::LanesManager)?; + } + + // write something to log + log::trace!( + target: LOG_TARGET, + "Bridge {:?} between {:?} and {:?} has been opened using lane_id: {lane_id:?}", + locations.bridge_id(), + locations.bridge_origin_universal_location(), + locations.bridge_destination_universal_location(), + ); + + // deposit `BridgeOpened` event + Self::deposit_event(Event::::BridgeOpened { + bridge_id: *locations.bridge_id(), + bridge_deposit: deposit, + local_endpoint: Box::new(locations.bridge_origin_universal_location().clone()), + remote_endpoint: Box::new( + locations.bridge_destination_universal_location().clone(), + ), + lane_id: lane_id.into(), + }); + + Ok(()) + } + } + + impl, I: 'static> Pallet { + /// Return bridge endpoint locations and dedicated lane identifier. This method converts + /// runtime `origin` argument to relative `Location` using the `T::OpenBridgeOrigin` + /// converter. + pub fn bridge_locations_from_origin( + origin: OriginFor, + bridge_destination_universal_location: Box, + ) -> Result, sp_runtime::DispatchError> { + Self::bridge_locations( + T::OpenBridgeOrigin::ensure_origin(origin)?, + (*bridge_destination_universal_location) + .try_into() + .map_err(|_| Error::::UnsupportedXcmVersion)?, + ) + } + + /// Return bridge endpoint locations and dedicated **bridge** identifier (`BridgeId`). + pub fn bridge_locations( + bridge_origin_relative_location: Location, + bridge_destination_universal_location: InteriorLocation, + ) -> Result, sp_runtime::DispatchError> { + BridgeLocations::bridge_locations( + T::UniversalLocation::get(), + bridge_origin_relative_location, + bridge_destination_universal_location, + Self::bridged_network_id()?, + ) + .map_err(|e| { + log::trace!( + target: LOG_TARGET, + "bridge_locations error: {e:?}", + ); + Error::::BridgeLocations(e).into() + }) + } + + /// Return bridge metadata by bridge_id + pub fn bridge(bridge_id: &BridgeId) -> Option> { + Bridges::::get(bridge_id) + } + + /// Return bridge metadata by lane_id + pub fn bridge_by_lane_id(lane_id: &T::LaneId) -> Option<(BridgeId, BridgeOf)> { + LaneToBridge::::get(lane_id) + .and_then(|bridge_id| Self::bridge(&bridge_id).map(|bridge| (bridge_id, bridge))) } + } + impl, I: 'static> Pallet { /// Returns some `NetworkId` if contains `GlobalConsensus` junction. - fn bridged_network_id() -> Option { + fn bridged_network_id() -> Result { match T::BridgedNetwork::get().take_first_interior() { - Some(GlobalConsensus(network)) => Some(network), - _ => None, + Some(GlobalConsensus(network)) => Ok(network), + _ => Err(Error::::BridgeLocations( + BridgeLocationsError::InvalidBridgeDestination, + ) + .into()), + } + } + } + + #[cfg(any(test, feature = "try-runtime", feature = "std"))] + impl, I: 'static> Pallet { + /// Ensure the correctness of the state of this pallet. + pub fn do_try_state() -> Result<(), sp_runtime::TryRuntimeError> { + use sp_std::collections::btree_set::BTreeSet; + + let mut lanes = BTreeSet::new(); + + // check all known bridge configurations + for (bridge_id, bridge) in Bridges::::iter() { + lanes.insert(Self::do_try_state_for_bridge(bridge_id, bridge)?); + } + ensure!( + lanes.len() == Bridges::::iter().count(), + "Invalid `Bridges` configuration, probably two bridges handle the same laneId!" + ); + ensure!( + lanes.len() == LaneToBridge::::iter().count(), + "Invalid `LaneToBridge` configuration, probably missing or not removed laneId!" + ); + + // check connected `pallet_bridge_messages` state. + Self::do_try_state_for_messages() + } + + /// Ensure the correctness of the state of the bridge. + pub fn do_try_state_for_bridge( + bridge_id: BridgeId, + bridge: BridgeOf, + ) -> Result { + log::info!(target: LOG_TARGET, "Checking `do_try_state_for_bridge` for bridge_id: {bridge_id:?} and bridge: {bridge:?}"); + + // check `BridgeId` points to the same `LaneId` and vice versa. + ensure!( + Some(bridge_id) == LaneToBridge::::get(bridge.lane_id), + "Found `LaneToBridge` inconsistency for bridge_id - missing mapping!" + ); + + // check `pallet_bridge_messages` state for that `LaneId`. + let lanes_manager = LanesManagerOf::::new(); + ensure!( + lanes_manager.any_state_inbound_lane(bridge.lane_id).is_ok(), + "Inbound lane not found!", + ); + ensure!( + lanes_manager.any_state_outbound_lane(bridge.lane_id).is_ok(), + "Outbound lane not found!", + ); + + // check that `locations` are convertible to the `latest` XCM. + let bridge_origin_relative_location_as_latest: &Location = + bridge.bridge_origin_relative_location.try_as().map_err(|_| { + "`bridge.bridge_origin_relative_location` cannot be converted to the `latest` XCM, needs migration!" + })?; + let bridge_origin_universal_location_as_latest: &InteriorLocation = bridge.bridge_origin_universal_location + .try_as() + .map_err(|_| "`bridge.bridge_origin_universal_location` cannot be converted to the `latest` XCM, needs migration!")?; + let bridge_destination_universal_location_as_latest: &InteriorLocation = bridge.bridge_destination_universal_location + .try_as() + .map_err(|_| "`bridge.bridge_destination_universal_location` cannot be converted to the `latest` XCM, needs migration!")?; + + // check `BridgeId` does not change + ensure!( + bridge_id == BridgeId::new(bridge_origin_universal_location_as_latest, bridge_destination_universal_location_as_latest), + "`bridge_id` is different than calculated from `bridge_origin_universal_location_as_latest` and `bridge_destination_universal_location_as_latest`, needs migration!" + ); + + // check bridge account owner + ensure!( + T::BridgeOriginAccountIdConverter::convert_location(bridge_origin_relative_location_as_latest) == Some(bridge.bridge_owner_account), + "`bridge.bridge_owner_account` is different than calculated from `bridge.bridge_origin_relative_location`, needs migration!" + ); + + Ok(bridge.lane_id) + } + + /// Ensure the correctness of the state of the connected `pallet_bridge_messages` instance. + pub fn do_try_state_for_messages() -> Result<(), sp_runtime::TryRuntimeError> { + // check that all `InboundLanes` laneIds have mapping to some bridge. + for lane_id in pallet_bridge_messages::InboundLanes::::iter_keys() { + log::info!(target: LOG_TARGET, "Checking `do_try_state_for_messages` for `InboundLanes`'s lane_id: {lane_id:?}..."); + ensure!( + LaneToBridge::::get(lane_id).is_some(), + "Found `LaneToBridge` inconsistency for `InboundLanes`'s lane_id - missing mapping!" + ); + } + + // check that all `OutboundLanes` laneIds have mapping to some bridge. + for lane_id in pallet_bridge_messages::OutboundLanes::::iter_keys() { + log::info!(target: LOG_TARGET, "Checking `do_try_state_for_messages` for `OutboundLanes`'s lane_id: {lane_id:?}..."); + ensure!( + LaneToBridge::::get(lane_id).is_some(), + "Found `LaneToBridge` inconsistency for `OutboundLanes`'s lane_id - missing mapping!" + ); } + + Ok(()) } } + + /// All registered bridges. + #[pallet::storage] + pub type Bridges, I: 'static = ()> = + StorageMap<_, Identity, BridgeId, BridgeOf>; + /// All registered `lane_id` and `bridge_id` mappings. + #[pallet::storage] + pub type LaneToBridge, I: 'static = ()> = + StorageMap<_, Identity, T::LaneId, BridgeId>; + + #[pallet::genesis_config] + #[derive(DefaultNoBound)] + pub struct GenesisConfig, I: 'static = ()> { + /// Opened bridges. + /// + /// Keep in mind that we are **NOT** reserving any amount for the bridges opened at + /// genesis. We are **NOT** opening lanes, used by this bridge. It all must be done using + /// other pallets genesis configuration or some other means. + pub opened_bridges: Vec<(Location, InteriorLocation, Option)>, + /// Dummy marker. + #[serde(skip)] + pub _phantom: sp_std::marker::PhantomData<(T, I)>, + } + + #[pallet::genesis_build] + impl, I: 'static> BuildGenesisConfig for GenesisConfig + where + T: frame_system::Config>>, + { + fn build(&self) { + for ( + bridge_origin_relative_location, + bridge_destination_universal_location, + maybe_lane_id, + ) in &self.opened_bridges + { + let locations = Pallet::::bridge_locations( + bridge_origin_relative_location.clone(), + bridge_destination_universal_location.clone().into(), + ) + .expect("Invalid genesis configuration"); + + let lane_id = match maybe_lane_id { + Some(lane_id) => *lane_id, + None => + locations.calculate_lane_id(xcm::latest::VERSION).expect("Valid locations"), + }; + + Pallet::::do_open_bridge(locations, lane_id, true) + .expect("Valid opened bridge!"); + } + } + } + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event, I: 'static = ()> { + /// The bridge between two locations has been opened. + BridgeOpened { + /// Bridge identifier. + bridge_id: BridgeId, + /// Amount of deposit held. + bridge_deposit: BalanceOf>, + + /// Universal location of local bridge endpoint. + local_endpoint: Box, + /// Universal location of remote bridge endpoint. + remote_endpoint: Box, + /// Lane identifier. + lane_id: T::LaneId, + }, + /// Bridge is going to be closed, but not yet fully pruned from the runtime storage. + ClosingBridge { + /// Bridge identifier. + bridge_id: BridgeId, + /// Lane identifier. + lane_id: T::LaneId, + /// Number of pruned messages during the close call. + pruned_messages: MessageNonce, + /// Number of enqueued messages that need to be pruned in follow up calls. + enqueued_messages: MessageNonce, + }, + /// Bridge has been closed and pruned from the runtime storage. It now may be reopened + /// again by any participant. + BridgePruned { + /// Bridge identifier. + bridge_id: BridgeId, + /// Lane identifier. + lane_id: T::LaneId, + /// Amount of deposit released. + bridge_deposit: BalanceOf>, + /// Number of pruned messages during the close call. + pruned_messages: MessageNonce, + }, + } + + #[pallet::error] + pub enum Error { + /// Bridge locations error. + BridgeLocations(BridgeLocationsError), + /// Invalid local bridge origin account. + InvalidBridgeOriginAccount, + /// The bridge is already registered in this pallet. + BridgeAlreadyExists, + /// The local origin already owns a maximal number of bridges. + TooManyBridgesForLocalOrigin, + /// Trying to close already closed bridge. + BridgeAlreadyClosed, + /// Lanes manager error. + LanesManager(LanesManagerError), + /// Trying to access unknown bridge. + UnknownBridge, + /// The bridge origin can't pay the required amount for opening the bridge. + FailedToReserveBridgeDeposit, + /// The version of XCM location argument is unsupported. + UnsupportedXcmVersion, + } +} + +#[cfg(test)] +mod tests { + use super::*; + use bp_messages::LaneIdType; + use mock::*; + + use frame_support::{assert_err, assert_noop, assert_ok, traits::fungible::Mutate, BoundedVec}; + use frame_system::{EventRecord, Phase}; + use sp_runtime::TryRuntimeError; + + fn fund_origin_sovereign_account(locations: &BridgeLocations, balance: Balance) -> AccountId { + let bridge_owner_account = + LocationToAccountId::convert_location(locations.bridge_origin_relative_location()) + .unwrap(); + assert_ok!(Balances::mint_into(&bridge_owner_account, balance)); + bridge_owner_account + } + + fn mock_open_bridge_from_with( + origin: RuntimeOrigin, + deposit: Balance, + with: InteriorLocation, + ) -> (BridgeOf, BridgeLocations) { + let locations = + XcmOverBridge::bridge_locations_from_origin(origin, Box::new(with.into())).unwrap(); + let lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap(); + let bridge_owner_account = + fund_origin_sovereign_account(&locations, deposit + ExistentialDeposit::get()); + Balances::hold(&HoldReason::BridgeDeposit.into(), &bridge_owner_account, deposit).unwrap(); + + let bridge = Bridge { + bridge_origin_relative_location: Box::new( + locations.bridge_origin_relative_location().clone().into(), + ), + bridge_origin_universal_location: Box::new( + locations.bridge_origin_universal_location().clone().into(), + ), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into(), + ), + state: BridgeState::Opened, + bridge_owner_account, + deposit, + lane_id, + }; + Bridges::::insert(locations.bridge_id(), bridge.clone()); + LaneToBridge::::insert(bridge.lane_id, locations.bridge_id()); + + let lanes_manager = LanesManagerOf::::new(); + lanes_manager.create_inbound_lane(bridge.lane_id).unwrap(); + lanes_manager.create_outbound_lane(bridge.lane_id).unwrap(); + + assert_ok!(XcmOverBridge::do_try_state()); + + (bridge, *locations) + } + + fn mock_open_bridge_from( + origin: RuntimeOrigin, + deposit: Balance, + ) -> (BridgeOf, BridgeLocations) { + mock_open_bridge_from_with(origin, deposit, bridged_asset_hub_universal_location()) + } + + fn enqueue_message(lane: TestLaneIdType) { + let lanes_manager = LanesManagerOf::::new(); + lanes_manager + .active_outbound_lane(lane) + .unwrap() + .send_message(BoundedVec::try_from(vec![42]).expect("We craft valid messages")); + } + + #[test] + fn open_bridge_fails_if_origin_is_not_allowed() { + run_test(|| { + assert_noop!( + XcmOverBridge::open_bridge( + OpenBridgeOrigin::disallowed_origin(), + Box::new(bridged_asset_hub_universal_location().into()), + ), + sp_runtime::DispatchError::BadOrigin, + ); + }) + } + + #[test] + fn open_bridge_fails_if_origin_is_not_relative() { + run_test(|| { + assert_noop!( + XcmOverBridge::open_bridge( + OpenBridgeOrigin::parent_relay_chain_universal_origin(), + Box::new(bridged_asset_hub_universal_location().into()), + ), + Error::::BridgeLocations( + BridgeLocationsError::InvalidBridgeOrigin + ), + ); + + assert_noop!( + XcmOverBridge::open_bridge( + OpenBridgeOrigin::sibling_parachain_universal_origin(), + Box::new(bridged_asset_hub_universal_location().into()), + ), + Error::::BridgeLocations( + BridgeLocationsError::InvalidBridgeOrigin + ), + ); + }) + } + + #[test] + fn open_bridge_fails_if_destination_is_not_remote() { + run_test(|| { + assert_noop!( + XcmOverBridge::open_bridge( + OpenBridgeOrigin::parent_relay_chain_origin(), + Box::new( + [GlobalConsensus(RelayNetwork::get()), Parachain(BRIDGED_ASSET_HUB_ID)] + .into() + ), + ), + Error::::BridgeLocations(BridgeLocationsError::DestinationIsLocal), + ); + }); + } + + #[test] + fn open_bridge_fails_if_outside_of_bridged_consensus() { + run_test(|| { + assert_noop!( + XcmOverBridge::open_bridge( + OpenBridgeOrigin::parent_relay_chain_origin(), + Box::new( + [ + GlobalConsensus(NonBridgedRelayNetwork::get()), + Parachain(BRIDGED_ASSET_HUB_ID) + ] + .into() + ), + ), + Error::::BridgeLocations( + BridgeLocationsError::UnreachableDestination + ), + ); + }); + } + + #[test] + fn open_bridge_fails_if_origin_has_no_sovereign_account() { + run_test(|| { + assert_noop!( + XcmOverBridge::open_bridge( + OpenBridgeOrigin::origin_without_sovereign_account(), + Box::new(bridged_asset_hub_universal_location().into()), + ), + Error::::InvalidBridgeOriginAccount, + ); + }); + } + + #[test] + fn open_bridge_fails_if_origin_sovereign_account_has_no_enough_funds() { + run_test(|| { + assert_noop!( + XcmOverBridge::open_bridge( + OpenBridgeOrigin::sibling_parachain_origin(), + Box::new(bridged_asset_hub_universal_location().into()), + ), + Error::::FailedToReserveBridgeDeposit, + ); + }); + } + + #[test] + fn open_bridge_fails_if_it_already_exists() { + run_test(|| { + let origin = OpenBridgeOrigin::parent_relay_chain_origin(); + let locations = XcmOverBridge::bridge_locations_from_origin( + origin.clone(), + Box::new(bridged_asset_hub_universal_location().into()), + ) + .unwrap(); + let lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap(); + fund_origin_sovereign_account( + &locations, + BridgeDeposit::get() + ExistentialDeposit::get(), + ); + + Bridges::::insert( + locations.bridge_id(), + Bridge { + bridge_origin_relative_location: Box::new( + locations.bridge_origin_relative_location().clone().into(), + ), + bridge_origin_universal_location: Box::new( + locations.bridge_origin_universal_location().clone().into(), + ), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into(), + ), + state: BridgeState::Opened, + bridge_owner_account: [0u8; 32].into(), + deposit: 0, + lane_id, + }, + ); + + assert_noop!( + XcmOverBridge::open_bridge( + origin, + Box::new(bridged_asset_hub_universal_location().into()), + ), + Error::::BridgeAlreadyExists, + ); + }) + } + + #[test] + fn open_bridge_fails_if_its_lanes_already_exists() { + run_test(|| { + let origin = OpenBridgeOrigin::parent_relay_chain_origin(); + let locations = XcmOverBridge::bridge_locations_from_origin( + origin.clone(), + Box::new(bridged_asset_hub_universal_location().into()), + ) + .unwrap(); + let lane_id = locations.calculate_lane_id(xcm::latest::VERSION).unwrap(); + fund_origin_sovereign_account( + &locations, + BridgeDeposit::get() + ExistentialDeposit::get(), + ); + + let lanes_manager = LanesManagerOf::::new(); + + lanes_manager.create_inbound_lane(lane_id).unwrap(); + assert_noop!( + XcmOverBridge::open_bridge( + origin.clone(), + Box::new(bridged_asset_hub_universal_location().into()), + ), + Error::::LanesManager(LanesManagerError::InboundLaneAlreadyExists), + ); + + lanes_manager.active_inbound_lane(lane_id).unwrap().purge(); + lanes_manager.create_outbound_lane(lane_id).unwrap(); + assert_noop!( + XcmOverBridge::open_bridge( + origin, + Box::new(bridged_asset_hub_universal_location().into()), + ), + Error::::LanesManager( + LanesManagerError::OutboundLaneAlreadyExists + ), + ); + }) + } + + #[test] + fn open_bridge_works() { + run_test(|| { + // in our test runtime, we expect that bridge may be opened by parent relay chain + // and any sibling parachain + let origins = [ + (OpenBridgeOrigin::parent_relay_chain_origin(), 0), + (OpenBridgeOrigin::sibling_parachain_origin(), BridgeDeposit::get()), + ]; + + // check that every origin may open the bridge + let lanes_manager = LanesManagerOf::::new(); + let existential_deposit = ExistentialDeposit::get(); + for (origin, expected_deposit) in origins { + // reset events + System::set_block_number(1); + System::reset_events(); + + // compute all other locations + let xcm_version = xcm::latest::VERSION; + let locations = XcmOverBridge::bridge_locations_from_origin( + origin.clone(), + Box::new( + VersionedInteriorLocation::from(bridged_asset_hub_universal_location()) + .into_version(xcm_version) + .expect("valid conversion"), + ), + ) + .unwrap(); + let lane_id = locations.calculate_lane_id(xcm_version).unwrap(); + + // ensure that there's no bridge and lanes in the storage + assert_eq!(Bridges::::get(locations.bridge_id()), None); + assert_eq!( + lanes_manager.active_inbound_lane(lane_id).map(drop), + Err(LanesManagerError::UnknownInboundLane) + ); + assert_eq!( + lanes_manager.active_outbound_lane(lane_id).map(drop), + Err(LanesManagerError::UnknownOutboundLane) + ); + assert_eq!(LaneToBridge::::get(lane_id), None); + + // give enough funds to the sovereign account of the bridge origin + let bridge_owner_account = fund_origin_sovereign_account( + &locations, + expected_deposit + existential_deposit, + ); + assert_eq!( + Balances::free_balance(&bridge_owner_account), + expected_deposit + existential_deposit + ); + assert_eq!(Balances::reserved_balance(&bridge_owner_account), 0); + + // now open the bridge + assert_ok!(XcmOverBridge::open_bridge( + origin, + Box::new(locations.bridge_destination_universal_location().clone().into()), + )); + + // ensure that everything has been set up in the runtime storage + assert_eq!( + Bridges::::get(locations.bridge_id()), + Some(Bridge { + bridge_origin_relative_location: Box::new( + locations.bridge_origin_relative_location().clone().into() + ), + bridge_origin_universal_location: Box::new( + locations.bridge_origin_universal_location().clone().into(), + ), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into(), + ), + state: BridgeState::Opened, + bridge_owner_account: bridge_owner_account.clone(), + deposit: expected_deposit, + lane_id + }), + ); + assert_eq!( + lanes_manager.active_inbound_lane(lane_id).map(|l| l.state()), + Ok(LaneState::Opened) + ); + assert_eq!( + lanes_manager.active_outbound_lane(lane_id).map(|l| l.state()), + Ok(LaneState::Opened) + ); + assert_eq!( + LaneToBridge::::get(lane_id), + Some(*locations.bridge_id()) + ); + assert_eq!(Balances::free_balance(&bridge_owner_account), existential_deposit); + assert_eq!(Balances::reserved_balance(&bridge_owner_account), expected_deposit); + + // ensure that the proper event is deposited + assert_eq!( + System::events().last(), + Some(&EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::XcmOverBridge(Event::BridgeOpened { + bridge_id: *locations.bridge_id(), + bridge_deposit: expected_deposit, + local_endpoint: Box::new( + locations.bridge_origin_universal_location().clone() + ), + remote_endpoint: Box::new( + locations.bridge_destination_universal_location().clone() + ), + lane_id: lane_id.into() + }), + topics: vec![], + }), + ); + + // check state + assert_ok!(XcmOverBridge::do_try_state()); + } + }); + } + + #[test] + fn close_bridge_fails_if_origin_is_not_allowed() { + run_test(|| { + assert_noop!( + XcmOverBridge::close_bridge( + OpenBridgeOrigin::disallowed_origin(), + Box::new(bridged_asset_hub_universal_location().into()), + 0, + ), + sp_runtime::DispatchError::BadOrigin, + ); + }) + } + + #[test] + fn close_bridge_fails_if_origin_is_not_relative() { + run_test(|| { + assert_noop!( + XcmOverBridge::close_bridge( + OpenBridgeOrigin::parent_relay_chain_universal_origin(), + Box::new(bridged_asset_hub_universal_location().into()), + 0, + ), + Error::::BridgeLocations( + BridgeLocationsError::InvalidBridgeOrigin + ), + ); + + assert_noop!( + XcmOverBridge::close_bridge( + OpenBridgeOrigin::sibling_parachain_universal_origin(), + Box::new(bridged_asset_hub_universal_location().into()), + 0, + ), + Error::::BridgeLocations( + BridgeLocationsError::InvalidBridgeOrigin + ), + ); + }) + } + + #[test] + fn close_bridge_fails_if_its_lanes_are_unknown() { + run_test(|| { + let origin = OpenBridgeOrigin::parent_relay_chain_origin(); + let (bridge, locations) = mock_open_bridge_from(origin.clone(), 0); + + let lanes_manager = LanesManagerOf::::new(); + lanes_manager.any_state_inbound_lane(bridge.lane_id).unwrap().purge(); + assert_noop!( + XcmOverBridge::close_bridge( + origin.clone(), + Box::new(locations.bridge_destination_universal_location().clone().into()), + 0, + ), + Error::::LanesManager(LanesManagerError::UnknownInboundLane), + ); + lanes_manager.any_state_outbound_lane(bridge.lane_id).unwrap().purge(); + + let (_, locations) = mock_open_bridge_from(origin.clone(), 0); + lanes_manager.any_state_outbound_lane(bridge.lane_id).unwrap().purge(); + assert_noop!( + XcmOverBridge::close_bridge( + origin, + Box::new(locations.bridge_destination_universal_location().clone().into()), + 0, + ), + Error::::LanesManager(LanesManagerError::UnknownOutboundLane), + ); + }); + } + + #[test] + fn close_bridge_works() { + run_test(|| { + let origin = OpenBridgeOrigin::parent_relay_chain_origin(); + let expected_deposit = BridgeDeposit::get(); + let (bridge, locations) = mock_open_bridge_from(origin.clone(), expected_deposit); + System::set_block_number(1); + + // remember owner balances + let free_balance = Balances::free_balance(&bridge.bridge_owner_account); + let reserved_balance = Balances::reserved_balance(&bridge.bridge_owner_account); + + // enqueue some messages + for _ in 0..32 { + enqueue_message(bridge.lane_id); + } + + // now call the `close_bridge`, which will only partially prune messages + assert_ok!(XcmOverBridge::close_bridge( + origin.clone(), + Box::new(locations.bridge_destination_universal_location().clone().into()), + 16, + ),); + + // as a result, the bridge and lanes are switched to the `Closed` state, some messages + // are pruned, but funds are not unreserved + let lanes_manager = LanesManagerOf::::new(); + assert_eq!( + Bridges::::get(locations.bridge_id()).map(|b| b.state), + Some(BridgeState::Closed) + ); + assert_eq!( + lanes_manager.any_state_inbound_lane(bridge.lane_id).unwrap().state(), + LaneState::Closed + ); + assert_eq!( + lanes_manager.any_state_outbound_lane(bridge.lane_id).unwrap().state(), + LaneState::Closed + ); + assert_eq!( + lanes_manager + .any_state_outbound_lane(bridge.lane_id) + .unwrap() + .queued_messages() + .checked_len(), + Some(16) + ); + assert_eq!( + LaneToBridge::::get(bridge.lane_id), + Some(*locations.bridge_id()) + ); + assert_eq!(Balances::free_balance(&bridge.bridge_owner_account), free_balance); + assert_eq!(Balances::reserved_balance(&bridge.bridge_owner_account), reserved_balance); + assert_eq!( + System::events().last(), + Some(&EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::XcmOverBridge(Event::ClosingBridge { + bridge_id: *locations.bridge_id(), + lane_id: bridge.lane_id.into(), + pruned_messages: 16, + enqueued_messages: 16, + }), + topics: vec![], + }), + ); + + // now call the `close_bridge` again, which will only partially prune messages + assert_ok!(XcmOverBridge::close_bridge( + origin.clone(), + Box::new(locations.bridge_destination_universal_location().clone().into()), + 8, + ),); + + // nothing is changed (apart from the pruned messages) + assert_eq!( + Bridges::::get(locations.bridge_id()).map(|b| b.state), + Some(BridgeState::Closed) + ); + assert_eq!( + lanes_manager.any_state_inbound_lane(bridge.lane_id).unwrap().state(), + LaneState::Closed + ); + assert_eq!( + lanes_manager.any_state_outbound_lane(bridge.lane_id).unwrap().state(), + LaneState::Closed + ); + assert_eq!( + lanes_manager + .any_state_outbound_lane(bridge.lane_id) + .unwrap() + .queued_messages() + .checked_len(), + Some(8) + ); + assert_eq!( + LaneToBridge::::get(bridge.lane_id), + Some(*locations.bridge_id()) + ); + assert_eq!(Balances::free_balance(&bridge.bridge_owner_account), free_balance); + assert_eq!(Balances::reserved_balance(&bridge.bridge_owner_account), reserved_balance); + assert_eq!( + System::events().last(), + Some(&EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::XcmOverBridge(Event::ClosingBridge { + bridge_id: *locations.bridge_id(), + lane_id: bridge.lane_id.into(), + pruned_messages: 8, + enqueued_messages: 8, + }), + topics: vec![], + }), + ); + + // now call the `close_bridge` again that will prune all remaining messages and the + // bridge + assert_ok!(XcmOverBridge::close_bridge( + origin, + Box::new(locations.bridge_destination_universal_location().clone().into()), + 9, + ),); + + // there's no traces of bridge in the runtime storage and funds are unreserved + assert_eq!( + Bridges::::get(locations.bridge_id()).map(|b| b.state), + None + ); + assert_eq!( + lanes_manager.any_state_inbound_lane(bridge.lane_id).map(drop), + Err(LanesManagerError::UnknownInboundLane) + ); + assert_eq!( + lanes_manager.any_state_outbound_lane(bridge.lane_id).map(drop), + Err(LanesManagerError::UnknownOutboundLane) + ); + assert_eq!(LaneToBridge::::get(bridge.lane_id), None); + assert_eq!( + Balances::free_balance(&bridge.bridge_owner_account), + free_balance + reserved_balance + ); + assert_eq!(Balances::reserved_balance(&bridge.bridge_owner_account), 0); + assert_eq!( + System::events().last(), + Some(&EventRecord { + phase: Phase::Initialization, + event: RuntimeEvent::XcmOverBridge(Event::BridgePruned { + bridge_id: *locations.bridge_id(), + lane_id: bridge.lane_id.into(), + bridge_deposit: expected_deposit, + pruned_messages: 8, + }), + topics: vec![], + }), + ); + }); + } + + #[test] + fn do_try_state_works() { + let bridge_origin_relative_location = SiblingLocation::get(); + let bridge_origin_universal_location = SiblingUniversalLocation::get(); + let bridge_destination_universal_location = BridgedUniversalDestination::get(); + let bridge_owner_account = + LocationToAccountId::convert_location(&bridge_origin_relative_location) + .expect("valid accountId"); + let bridge_owner_account_mismatch = + LocationToAccountId::convert_location(&Location::parent()).expect("valid accountId"); + let bridge_id = BridgeId::new( + &bridge_origin_universal_location, + &bridge_destination_universal_location, + ); + let bridge_id_mismatch = BridgeId::new(&InteriorLocation::Here, &InteriorLocation::Here); + let lane_id = TestLaneIdType::try_new(1, 2).unwrap(); + let lane_id_mismatch = TestLaneIdType::try_new(3, 4).unwrap(); + + let test_bridge_state = + |id, + bridge, + (lane_id, bridge_id), + (inbound_lane_id, outbound_lane_id), + expected_error: Option| { + Bridges::::insert(id, bridge); + LaneToBridge::::insert(lane_id, bridge_id); + + let lanes_manager = LanesManagerOf::::new(); + lanes_manager.create_inbound_lane(inbound_lane_id).unwrap(); + lanes_manager.create_outbound_lane(outbound_lane_id).unwrap(); + + let result = XcmOverBridge::do_try_state(); + if let Some(e) = expected_error { + assert_err!(result, e); + } else { + assert_ok!(result); + } + }; + let cleanup = |bridge_id, lane_ids| { + Bridges::::remove(bridge_id); + for lane_id in lane_ids { + LaneToBridge::::remove(lane_id); + let lanes_manager = LanesManagerOf::::new(); + if let Ok(lane) = lanes_manager.any_state_inbound_lane(lane_id) { + lane.purge(); + } + if let Ok(lane) = lanes_manager.any_state_outbound_lane(lane_id) { + lane.purge(); + } + } + assert_ok!(XcmOverBridge::do_try_state()); + }; + + run_test(|| { + // ok state + test_bridge_state( + bridge_id, + Bridge { + bridge_origin_relative_location: Box::new(VersionedLocation::from( + bridge_origin_relative_location.clone(), + )), + bridge_origin_universal_location: Box::new(VersionedInteriorLocation::from( + bridge_origin_universal_location.clone(), + )), + bridge_destination_universal_location: Box::new( + VersionedInteriorLocation::from( + bridge_destination_universal_location.clone(), + ), + ), + state: BridgeState::Opened, + bridge_owner_account: bridge_owner_account.clone(), + deposit: Zero::zero(), + lane_id, + }, + (lane_id, bridge_id), + (lane_id, lane_id), + None, + ); + cleanup(bridge_id, vec![lane_id]); + + // error - missing `LaneToBridge` mapping + test_bridge_state( + bridge_id, + Bridge { + bridge_origin_relative_location: Box::new(VersionedLocation::from( + bridge_origin_relative_location.clone(), + )), + bridge_origin_universal_location: Box::new(VersionedInteriorLocation::from( + bridge_origin_universal_location.clone(), + )), + bridge_destination_universal_location: Box::new( + VersionedInteriorLocation::from( + bridge_destination_universal_location.clone(), + ), + ), + state: BridgeState::Opened, + bridge_owner_account: bridge_owner_account.clone(), + deposit: Zero::zero(), + lane_id, + }, + (lane_id, bridge_id_mismatch), + (lane_id, lane_id), + Some(TryRuntimeError::Other( + "Found `LaneToBridge` inconsistency for bridge_id - missing mapping!", + )), + ); + cleanup(bridge_id, vec![lane_id]); + + // error bridge owner account cannot be calculated + test_bridge_state( + bridge_id, + Bridge { + bridge_origin_relative_location: Box::new(VersionedLocation::from( + bridge_origin_relative_location.clone(), + )), + bridge_origin_universal_location: Box::new(VersionedInteriorLocation::from( + bridge_origin_universal_location.clone(), + )), + bridge_destination_universal_location: Box::new(VersionedInteriorLocation::from( + bridge_destination_universal_location.clone(), + )), + state: BridgeState::Opened, + bridge_owner_account: bridge_owner_account_mismatch.clone(), + deposit: Zero::zero(), + lane_id, + }, + (lane_id, bridge_id), + (lane_id, lane_id), + Some(TryRuntimeError::Other("`bridge.bridge_owner_account` is different than calculated from `bridge.bridge_origin_relative_location`, needs migration!")), + ); + cleanup(bridge_id, vec![lane_id]); + + // error when (bridge_origin_universal_location + bridge_destination_universal_location) + // produces different `BridgeId` + test_bridge_state( + bridge_id_mismatch, + Bridge { + bridge_origin_relative_location: Box::new(VersionedLocation::from( + bridge_origin_relative_location.clone(), + )), + bridge_origin_universal_location: Box::new(VersionedInteriorLocation::from( + bridge_origin_universal_location.clone(), + )), + bridge_destination_universal_location: Box::new(VersionedInteriorLocation::from( + bridge_destination_universal_location.clone(), + )), + state: BridgeState::Opened, + bridge_owner_account: bridge_owner_account_mismatch.clone(), + deposit: Zero::zero(), + lane_id, + }, + (lane_id, bridge_id_mismatch), + (lane_id, lane_id), + Some(TryRuntimeError::Other("`bridge_id` is different than calculated from `bridge_origin_universal_location_as_latest` and `bridge_destination_universal_location_as_latest`, needs migration!")), + ); + cleanup(bridge_id_mismatch, vec![lane_id]); + + // missing inbound lane for a bridge + test_bridge_state( + bridge_id, + Bridge { + bridge_origin_relative_location: Box::new(VersionedLocation::from( + bridge_origin_relative_location.clone(), + )), + bridge_origin_universal_location: Box::new(VersionedInteriorLocation::from( + bridge_origin_universal_location.clone(), + )), + bridge_destination_universal_location: Box::new( + VersionedInteriorLocation::from( + bridge_destination_universal_location.clone(), + ), + ), + state: BridgeState::Opened, + bridge_owner_account: bridge_owner_account.clone(), + deposit: Zero::zero(), + lane_id, + }, + (lane_id, bridge_id), + (lane_id_mismatch, lane_id), + Some(TryRuntimeError::Other("Inbound lane not found!")), + ); + cleanup(bridge_id, vec![lane_id, lane_id_mismatch]); + + // missing outbound lane for a bridge + test_bridge_state( + bridge_id, + Bridge { + bridge_origin_relative_location: Box::new(VersionedLocation::from( + bridge_origin_relative_location.clone(), + )), + bridge_origin_universal_location: Box::new(VersionedInteriorLocation::from( + bridge_origin_universal_location.clone(), + )), + bridge_destination_universal_location: Box::new( + VersionedInteriorLocation::from( + bridge_destination_universal_location.clone(), + ), + ), + state: BridgeState::Opened, + bridge_owner_account: bridge_owner_account.clone(), + deposit: Zero::zero(), + lane_id, + }, + (lane_id, bridge_id), + (lane_id, lane_id_mismatch), + Some(TryRuntimeError::Other("Outbound lane not found!")), + ); + cleanup(bridge_id, vec![lane_id, lane_id_mismatch]); + + // missing bridge for inbound lane + let lanes_manager = LanesManagerOf::::new(); + assert!(lanes_manager.create_inbound_lane(lane_id).is_ok()); + assert_err!(XcmOverBridge::do_try_state(), TryRuntimeError::Other("Found `LaneToBridge` inconsistency for `InboundLanes`'s lane_id - missing mapping!")); + cleanup(bridge_id, vec![lane_id]); + + // missing bridge for outbound lane + let lanes_manager = LanesManagerOf::::new(); + assert!(lanes_manager.create_outbound_lane(lane_id).is_ok()); + assert_err!(XcmOverBridge::do_try_state(), TryRuntimeError::Other("Found `LaneToBridge` inconsistency for `OutboundLanes`'s lane_id - missing mapping!")); + cleanup(bridge_id, vec![lane_id]); + }); + } + + #[test] + fn ensure_encoding_compatibility() { + use codec::Encode; + + let bridge_destination_universal_location = BridgedUniversalDestination::get(); + let may_prune_messages = 13; + + assert_eq!( + bp_xcm_bridge_hub::XcmBridgeHubCall::open_bridge { + bridge_destination_universal_location: Box::new( + bridge_destination_universal_location.clone().into() + ) + } + .encode(), + Call::::open_bridge { + bridge_destination_universal_location: Box::new( + bridge_destination_universal_location.clone().into() + ) + } + .encode() + ); + assert_eq!( + bp_xcm_bridge_hub::XcmBridgeHubCall::close_bridge { + bridge_destination_universal_location: Box::new( + bridge_destination_universal_location.clone().into() + ), + may_prune_messages, + } + .encode(), + Call::::close_bridge { + bridge_destination_universal_location: Box::new( + bridge_destination_universal_location.clone().into() + ), + may_prune_messages, + } + .encode() + ); + } } diff --git a/bridges/modules/xcm-bridge-hub/src/migration.rs b/bridges/modules/xcm-bridge-hub/src/migration.rs new file mode 100644 index 000000000000..ffd5233a917b --- /dev/null +++ b/bridges/modules/xcm-bridge-hub/src/migration.rs @@ -0,0 +1,145 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! A module that is responsible for migration of storage. + +use crate::{Config, Pallet, LOG_TARGET}; +use frame_support::{ + traits::{Get, OnRuntimeUpgrade, StorageVersion}, + weights::Weight, +}; +use xcm::prelude::{InteriorLocation, Location}; + +/// The in-code storage version. +pub const STORAGE_VERSION: StorageVersion = StorageVersion::new(0); + +/// This migration does not modify storage but can be used to open a bridge and link it to the +/// specified LaneId. This is useful when we want to open a bridge and use a custom LaneId instead +/// of the pre-calculated one provided by the `fn open_bridge extrinsic`. +/// Or perhaps if you want to ensure that your runtime (e.g., for testing) always has an open +/// bridge. +pub struct OpenBridgeForLane< + T, + I, + Lane, + CreateLane, + SourceRelativeLocation, + BridgedUniversalLocation, +>( + core::marker::PhantomData<( + T, + I, + Lane, + CreateLane, + SourceRelativeLocation, + BridgedUniversalLocation, + )>, +); +impl< + T: Config, + I: 'static, + Lane: Get, + CreateLane: Get, + SourceRelativeLocation: Get, + BridgedUniversalLocation: Get, + > OnRuntimeUpgrade + for OpenBridgeForLane +{ + fn on_runtime_upgrade() -> Weight { + let bridge_origin_relative_location = SourceRelativeLocation::get(); + let bridge_destination_universal_location = BridgedUniversalLocation::get(); + let lane_id = Lane::get(); + let create_lane = CreateLane::get(); + log::info!( + target: LOG_TARGET, + "OpenBridgeForLane - going to open bridge with lane_id: {lane_id:?} (create_lane: {create_lane:?}) \ + between bridge_origin_relative_location: {bridge_origin_relative_location:?} and \ + bridge_destination_universal_location: {bridge_destination_universal_location:?}", + ); + + let locations = match Pallet::::bridge_locations( + bridge_origin_relative_location.clone(), + bridge_destination_universal_location.clone(), + ) { + Ok(locations) => locations, + Err(e) => { + log::error!( + target: LOG_TARGET, + "OpenBridgeForLane - on_runtime_upgrade failed to construct bridge_locations with error: {e:?}" + ); + return T::DbWeight::get().reads(0) + }, + }; + + // check if already exists + if let Some((bridge_id, bridge)) = Pallet::::bridge_by_lane_id(&lane_id) { + log::info!( + target: LOG_TARGET, + "OpenBridgeForLane - bridge: {bridge:?} with bridge_id: {bridge_id:?} already exist for lane_id: {lane_id:?}!" + ); + if &bridge_id != locations.bridge_id() { + log::warn!( + target: LOG_TARGET, + "OpenBridgeForLane - check you parameters, because a different bridge: {bridge:?} \ + with bridge_id: {bridge_id:?} exist for lane_id: {lane_id:?} for requested \ + bridge_origin_relative_location: {bridge_origin_relative_location:?} and \ + bridge_destination_universal_location: {bridge_destination_universal_location:?} !", + ); + } + + return T::DbWeight::get().reads(2) + } + + if let Err(e) = Pallet::::do_open_bridge(locations, lane_id, create_lane) { + log::error!(target: LOG_TARGET, "OpenBridgeForLane - do_open_bridge failed with error: {e:?}"); + T::DbWeight::get().reads(6) + } else { + log::info!(target: LOG_TARGET, "OpenBridgeForLane - do_open_bridge passed!"); + T::DbWeight::get().reads_writes(6, 4) + } + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(_state: sp_std::vec::Vec) -> Result<(), sp_runtime::DispatchError> { + let bridge_origin_relative_location = SourceRelativeLocation::get(); + let bridge_destination_universal_location = BridgedUniversalLocation::get(); + let lane_id = Lane::get(); + + // check that requested bridge is stored + let Ok(locations) = Pallet::::bridge_locations( + bridge_origin_relative_location.clone(), + bridge_destination_universal_location.clone(), + ) else { + return Err(sp_runtime::DispatchError::Other("Invalid locations!")) + }; + let Some((bridge_id, _)) = Pallet::::bridge_by_lane_id(&lane_id) else { + return Err(sp_runtime::DispatchError::Other("Missing bridge!")) + }; + frame_support::ensure!( + locations.bridge_id() == &bridge_id, + "Bridge is not stored correctly!" + ); + + log::info!( + target: LOG_TARGET, + "OpenBridgeForLane - post_upgrade found opened bridge with lane_id: {lane_id:?} \ + between bridge_origin_relative_location: {bridge_origin_relative_location:?} and \ + bridge_destination_universal_location: {bridge_destination_universal_location:?}", + ); + + Ok(()) + } +} diff --git a/bridges/modules/xcm-bridge-hub/src/mock.rs b/bridges/modules/xcm-bridge-hub/src/mock.rs index df72e7a3c4fc..6511b9fc5b04 100644 --- a/bridges/modules/xcm-bridge-hub/src/mock.rs +++ b/bridges/modules/xcm-bridge-hub/src/mock.rs @@ -20,36 +20,50 @@ use crate as pallet_xcm_bridge_hub; use bp_messages::{ target_chain::{DispatchMessage, MessageDispatch}, - ChainWithMessages, LaneId, MessageNonce, + ChainWithMessages, HashedLaneId, MessageNonce, }; use bp_runtime::{messages::MessageDispatchResult, Chain, ChainId, HashOf}; -use bridge_runtime_common::messages_xcm_extension::{SenderAndLane, XcmBlobHauler}; +use bp_xcm_bridge_hub::{BridgeId, LocalXcmChannelManager}; use codec::Encode; -use frame_support::{derive_impl, parameter_types, weights::RuntimeDbWeight}; +use frame_support::{ + assert_ok, derive_impl, parameter_types, + traits::{EnsureOrigin, Equals, Everything, OriginTrait}, + weights::RuntimeDbWeight, +}; +use polkadot_parachain_primitives::primitives::Sibling; 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, DispatchBlob, DispatchBlobError, FixedWeightBounds, + InspectMessageQueues, NetworkExportTable, NetworkExportTableItem, ParentIsPreset, + SiblingParachainConvertsVia, +}; +use xcm_executor::XcmExecutor; pub type AccountId = AccountId32; pub type Balance = u64; - type Block = frame_system::mocking::MockBlock; +/// Lane identifier type used for tests. +pub type TestLaneIdType = HashedLaneId; + pub const SIBLING_ASSET_HUB_ID: u32 = 2001; pub const THIS_BRIDGE_HUB_ID: u32 = 2002; pub const BRIDGED_ASSET_HUB_ID: u32 = 1001; -pub const TEST_LANE_ID: LaneId = LaneId([0, 0, 0, 1]); frame_support::construct_runtime! { pub enum TestRuntime { System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Event}, Messages: pallet_bridge_messages::{Pallet, Call, Event}, - XcmOverBridge: pallet_xcm_bridge_hub::{Pallet}, + XcmOverBridge: pallet_xcm_bridge_hub::{Pallet, Call, HoldReason, Event}, + XcmOverBridgeRouter: pallet_xcm_bridge_hub_router, } } @@ -71,25 +85,23 @@ impl pallet_balances::Config for TestRuntime { type AccountStore = System; } -parameter_types! { - pub const ActiveOutboundLanes: &'static [LaneId] = &[TEST_LANE_ID]; -} - impl pallet_bridge_messages::Config for TestRuntime { type RuntimeEvent = RuntimeEvent; type WeightInfo = TestMessagesWeights; - type ActiveOutboundLanes = ActiveOutboundLanes; + type ThisChain = ThisUnderlyingChain; + type BridgedChain = BridgedUnderlyingChain; + type BridgedHeaderChain = BridgedHeaderChain; + type OutboundPayload = Vec; type InboundPayload = Vec; + type LaneId = TestLaneIdType; + type DeliveryPayments = (); type DeliveryConfirmationPayments = (); type OnMessagesDelivered = (); - type MessageDispatch = TestMessageDispatch; - type ThisChain = ThisUnderlyingChain; - type BridgedChain = BridgedUnderlyingChain; - type BridgedHeaderChain = BridgedHeaderChain; + type MessageDispatch = TestMessageDispatch; } pub struct TestMessagesWeights; @@ -116,8 +128,8 @@ impl pallet_bridge_messages::WeightInfo for TestMessagesWeights { fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { Weight::zero() } - fn receive_single_n_bytes_message_proof_with_dispatch(_: u32) -> Weight { - Weight::zero() + fn receive_single_n_bytes_message_proof_with_dispatch(_n: u32) -> Weight { + Weight::from_parts(1, 0) } } @@ -137,18 +149,44 @@ 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 const Penalty: Balance = 1_000; + pub SiblingLocation: Location = Location::new(1, [Parachain(SIBLING_ASSET_HUB_ID)]); + pub SiblingUniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get()), Parachain(SIBLING_ASSET_HUB_ID)].into(); + + pub const BridgedRelayNetwork: NetworkId = NetworkId::ByGenesis([1; 32]); + 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; + + // 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); +} + +/// **Universal** `InteriorLocation` of bridged asset hub. +pub fn bridged_asset_hub_universal_location() -> InteriorLocation { + BridgedUniversalDestination::get() } impl pallet_xcm_bridge_hub::Config for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type UniversalLocation = UniversalLocation; type BridgedNetwork = BridgedRelayNetworkLocation; type BridgeMessagesPalletInstance = (); @@ -156,36 +194,268 @@ impl pallet_xcm_bridge_hub::Config for TestRuntime { type MessageExportPrice = (); type DestinationVersion = AlwaysLatest; - type Lanes = TestLanes; - type LanesSupport = TestXcmBlobHauler; + type ForceOrigin = frame_system::EnsureNever<()>; + type OpenBridgeOrigin = OpenBridgeOrigin; + type BridgeOriginAccountIdConverter = LocationToAccountId; + + type BridgeDeposit = BridgeDeposit; + type Currency = Balances; + type RuntimeHoldReason = RuntimeHoldReason; + type AllowWithoutBridgeDeposit = Equals; + + type LocalXcmChannelManager = TestLocalXcmChannelManager; + + type BlobDispatcher = TestBlobDispatcher; } +impl pallet_xcm_bridge_hub_router::Config<()> for TestRuntime { + type RuntimeEvent = RuntimeEvent; + type WeightInfo = (); + + type UniversalLocation = UniversalLocation; + type SiblingBridgeHubLocation = BridgeHubLocation; + type BridgedNetworkId = BridgedRelayNetwork; + type Bridges = NetworkExportTable; + type DestinationVersion = AlwaysLatest; + + type ToBridgeHubSender = TestExportXcmWithXcmOverBridge; + type LocalXcmChannelManager = TestLocalXcmChannelManager; + + type ByteFee = ConstU128<0>; + type FeeAsset = BridgeFeeAsset; +} + +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 clear_messages() { + todo!() + } + + 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)); + } +} + +/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used +/// when determining ownership of accounts for asset transacting and when attempting to use XCM +/// `Transact` in order to determine the dispatch Origin. +pub type LocationToAccountId = ( + // The parent (Relay-chain) origin converts to the parent `AccountId`. + ParentIsPreset, + // Sibling parachain origins convert to AccountId via the `ParaId::into`. + SiblingParachainConvertsVia, +); + parameter_types! { - pub TestSenderAndLane: SenderAndLane = SenderAndLane { - location: Location::new(1, [Parachain(SIBLING_ASSET_HUB_ID)]), - 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())) - ]; + pub ParentRelayChainLocation: Location = Location { parents: 1, interior: Here }; } +pub struct OpenBridgeOrigin; + +impl OpenBridgeOrigin { + pub fn parent_relay_chain_origin() -> RuntimeOrigin { + RuntimeOrigin::signed([0u8; 32].into()) + } + + pub fn parent_relay_chain_universal_origin() -> RuntimeOrigin { + RuntimeOrigin::signed([1u8; 32].into()) + } -pub struct TestXcmBlobHauler; -impl XcmBlobHauler for TestXcmBlobHauler { - type Runtime = TestRuntime; - type MessagesInstance = (); - type ToSourceChainSender = (); - type CongestedMessage = (); - type UncongestedMessage = (); + pub fn sibling_parachain_origin() -> RuntimeOrigin { + let mut account = [0u8; 32]; + account[..4].copy_from_slice(&SIBLING_ASSET_HUB_ID.encode()[..4]); + RuntimeOrigin::signed(account.into()) + } + + pub fn sibling_parachain_universal_origin() -> RuntimeOrigin { + RuntimeOrigin::signed([2u8; 32].into()) + } + + pub fn origin_without_sovereign_account() -> RuntimeOrigin { + RuntimeOrigin::signed([3u8; 32].into()) + } + + pub fn disallowed_origin() -> RuntimeOrigin { + RuntimeOrigin::signed([42u8; 32].into()) + } +} + +impl EnsureOrigin for OpenBridgeOrigin { + type Success = Location; + + fn try_origin(o: RuntimeOrigin) -> Result { + let signer = o.clone().into_signer(); + if signer == Self::parent_relay_chain_origin().into_signer() { + return Ok(ParentRelayChainLocation::get()) + } else if signer == Self::parent_relay_chain_universal_origin().into_signer() { + return Ok(Location { + parents: 2, + interior: GlobalConsensus(RelayNetwork::get()).into(), + }) + } else if signer == Self::sibling_parachain_universal_origin().into_signer() { + return Ok(Location { + parents: 2, + interior: [GlobalConsensus(RelayNetwork::get()), Parachain(SIBLING_ASSET_HUB_ID)] + .into(), + }) + } else if signer == Self::origin_without_sovereign_account().into_signer() { + return Ok(Location { + parents: 1, + interior: [Parachain(SIBLING_ASSET_HUB_ID), OnlyChild].into(), + }) + } + + let mut sibling_account = [0u8; 32]; + sibling_account[..4].copy_from_slice(&SIBLING_ASSET_HUB_ID.encode()[..4]); + if signer == Some(sibling_account.into()) { + return Ok(Location { parents: 1, interior: Parachain(SIBLING_ASSET_HUB_ID).into() }) + } + + Err(o) + } + + #[cfg(feature = "runtime-benchmarks")] + fn try_successful_origin() -> Result { + Ok(Self::parent_relay_chain_origin()) + } +} + +pub struct TestLocalXcmChannelManager; + +impl TestLocalXcmChannelManager { + pub fn make_congested() { + frame_support::storage::unhashed::put(b"TestLocalXcmChannelManager.Congested", &true); + } + + pub fn is_bridge_suspened() -> bool { + frame_support::storage::unhashed::get_or_default(b"TestLocalXcmChannelManager.Suspended") + } + + pub fn is_bridge_resumed() -> bool { + frame_support::storage::unhashed::get_or_default(b"TestLocalXcmChannelManager.Resumed") + } +} + +impl LocalXcmChannelManager for TestLocalXcmChannelManager { + type Error = (); + + fn is_congested(_with: &Location) -> bool { + frame_support::storage::unhashed::get_or_default(b"TestLocalXcmChannelManager.Congested") + } + + fn suspend_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { + frame_support::storage::unhashed::put(b"TestLocalXcmChannelManager.Suspended", &true); + Ok(()) + } + + fn resume_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { + frame_support::storage::unhashed::put(b"TestLocalXcmChannelManager.Resumed", &true); + Ok(()) + } +} + +impl pallet_xcm_bridge_hub_router::XcmChannelStatusProvider for TestLocalXcmChannelManager { + fn is_congested(with: &Location) -> bool { + ::is_congested(with) + } +} + +pub struct TestBlobDispatcher; + +impl TestBlobDispatcher { + pub fn is_dispatched() -> bool { + frame_support::storage::unhashed::get_or_default(b"TestBlobDispatcher.Dispatched") + } +} + +impl DispatchBlob for TestBlobDispatcher { + fn dispatch_blob(_blob: Vec) -> Result<(), DispatchBlobError> { + frame_support::storage::unhashed::put(b"TestBlobDispatcher.Dispatched", &true); + Ok(()) + } } pub struct ThisUnderlyingChain; impl Chain for ThisUnderlyingChain { const ID: ChainId = *b"tuch"; + type BlockNumber = u64; type Hash = H256; type Hasher = BlakeTwo256; @@ -207,16 +477,15 @@ impl Chain for ThisUnderlyingChain { } impl ChainWithMessages for ThisUnderlyingChain { - const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = ""; - + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = "WithThisChainBridgeMessages"; const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16; - const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1000; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 128; } -pub struct BridgedUnderlyingChain; pub type BridgedHeaderHash = H256; pub type BridgedChainHeader = SubstrateHeader; +pub struct BridgedUnderlyingChain; impl Chain for BridgedUnderlyingChain { const ID: ChainId = *b"bgdc"; type BlockNumber = u64; @@ -240,16 +509,25 @@ impl Chain for BridgedUnderlyingChain { } impl ChainWithMessages for BridgedUnderlyingChain { - const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = ""; + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = "WithBridgedChainBridgeMessages"; const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 16; - const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1000; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 128; +} + +pub struct BridgedHeaderChain; +impl bp_header_chain::HeaderChain for BridgedHeaderChain { + fn finalized_header_state_root( + _hash: HashOf, + ) -> Option> { + unreachable!() + } } /// Test message dispatcher. pub struct TestMessageDispatch; impl TestMessageDispatch { - pub fn deactivate(lane: LaneId) { + pub fn deactivate(lane: TestLaneIdType) { frame_support::storage::unhashed::put(&(b"inactive", lane).encode()[..], &false); } } @@ -257,31 +535,26 @@ impl TestMessageDispatch { impl MessageDispatch for TestMessageDispatch { type DispatchPayload = Vec; type DispatchLevelResult = (); + type LaneId = TestLaneIdType; - fn is_active() -> bool { - frame_support::storage::unhashed::take::(&(b"inactive").encode()[..]) != Some(false) + fn is_active(lane: Self::LaneId) -> bool { + frame_support::storage::unhashed::take::(&(b"inactive", lane).encode()[..]) != + Some(false) } - fn dispatch_weight(_message: &mut DispatchMessage) -> Weight { + fn dispatch_weight( + _message: &mut DispatchMessage, + ) -> Weight { Weight::zero() } fn dispatch( - _: DispatchMessage, + _: DispatchMessage, ) -> MessageDispatchResult { MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result: () } } } -pub struct BridgedHeaderChain; -impl bp_header_chain::HeaderChain for BridgedHeaderChain { - fn finalized_header_state_root( - _hash: HashOf, - ) -> Option> { - unreachable!() - } -} - /// Run pallet test. pub fn run_test(test: impl FnOnce() -> T) -> T { sp_io::TestExternalities::new( diff --git a/bridges/primitives/header-chain/src/call_info.rs b/bridges/primitives/header-chain/src/call_info.rs new file mode 100644 index 000000000000..acf7447adabc --- /dev/null +++ b/bridges/primitives/header-chain/src/call_info.rs @@ -0,0 +1,94 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Defines structures related to calls of the `pallet-bridge-grandpa` pallet. + +use crate::{justification, InitializationData}; + +use bp_runtime::HeaderOf; +use codec::{Decode, Encode}; +use frame_support::{weights::Weight, RuntimeDebugNoBound}; +use scale_info::TypeInfo; +use sp_consensus_grandpa::SetId; +use sp_runtime::traits::{Header as HeaderT, Zero}; +use sp_std::{boxed::Box, fmt::Debug}; + +/// A minimized version of `pallet-bridge-grandpa::Call` that can be used without a runtime. +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +#[allow(non_camel_case_types)] +pub enum BridgeGrandpaCall { + /// `pallet-bridge-grandpa::Call::submit_finality_proof` + #[codec(index = 0)] + submit_finality_proof { + /// The header that we are going to finalize. + finality_target: Box
, + /// Finality justification for the `finality_target`. + justification: justification::GrandpaJustification
, + }, + /// `pallet-bridge-grandpa::Call::initialize` + #[codec(index = 1)] + initialize { + /// All data, required to initialize the pallet. + init_data: InitializationData
, + }, + /// `pallet-bridge-grandpa::Call::submit_finality_proof_ex` + #[codec(index = 4)] + submit_finality_proof_ex { + /// The header that we are going to finalize. + finality_target: Box
, + /// Finality justification for the `finality_target`. + justification: justification::GrandpaJustification
, + /// An identifier of the validators set, that have signed the justification. + current_set_id: SetId, + }, +} + +/// The `BridgeGrandpaCall` for a pallet that bridges with given `C`; +pub type BridgeGrandpaCallOf = BridgeGrandpaCall>; + +/// A digest information on the `BridgeGrandpaCall::submit_finality_proof` call. +#[derive(Copy, Clone, PartialEq, RuntimeDebugNoBound)] +pub struct SubmitFinalityProofInfo { + /// Number of the finality target. + pub block_number: N, + /// An identifier of the validators set that has signed the submitted justification. + /// It might be `None` if deprecated version of the `submit_finality_proof` is used. + pub current_set_id: Option, + /// If `true`, then the call proves new **mandatory** header. + pub is_mandatory: bool, + /// If `true`, then the call must be free (assuming that everything else is valid) to + /// be treated as valid. + pub is_free_execution_expected: bool, + /// Extra weight that we assume is included in the call. + /// + /// We have some assumptions about headers and justifications of the bridged chain. + /// We know that if our assumptions are correct, then the call must not have the + /// weight above some limit. The fee paid for weight above that limit, is never refunded. + pub extra_weight: Weight, + /// Extra size (in bytes) that we assume are included in the call. + /// + /// We have some assumptions about headers and justifications of the bridged chain. + /// We know that if our assumptions are correct, then the call must not have the + /// weight above some limit. The fee paid for bytes above that limit, is never refunded. + pub extra_size: u32, +} + +impl SubmitFinalityProofInfo { + /// Returns `true` if call size/weight is below our estimations for regular calls. + pub fn fits_limits(&self) -> bool { + self.extra_weight.is_zero() && self.extra_size.is_zero() + } +} diff --git a/bridges/primitives/header-chain/src/justification/mod.rs b/bridges/primitives/header-chain/src/justification/mod.rs index d7c2cbf429e2..87f53dac6463 100644 --- a/bridges/primitives/header-chain/src/justification/mod.rs +++ b/bridges/primitives/header-chain/src/justification/mod.rs @@ -32,7 +32,6 @@ pub use verification::{ use bp_runtime::{BlockNumberOf, Chain, HashOf, HeaderId}; use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::RuntimeDebugNoBound; use scale_info::TypeInfo; use sp_consensus_grandpa::{AuthorityId, AuthoritySignature}; use sp_runtime::{traits::Header as HeaderT, RuntimeDebug, SaturatedConversion}; @@ -43,7 +42,8 @@ use sp_std::prelude::*; /// /// This particular proof is used to prove that headers on a bridged chain /// (so not our chain) have been finalized correctly. -#[derive(Encode, Decode, Clone, PartialEq, Eq, TypeInfo, RuntimeDebugNoBound)] +#[derive(Encode, Decode, Clone, PartialEq, Eq, TypeInfo)] +#[cfg_attr(feature = "std", derive(Debug))] pub struct GrandpaJustification { /// The round (voting period) this justification is valid for. pub round: u64, @@ -54,6 +54,17 @@ pub struct GrandpaJustification { pub votes_ancestries: Vec
, } +// A proper Debug impl for no-std is not possible for the `GrandpaJustification` since the `Commit` +// type only implements Debug that for `std` here: +// https://github.com/paritytech/finality-grandpa/blob/8c45a664c05657f0c71057158d3ba555ba7d20de/src/lib.rs#L275 +// so we do a manual impl. +#[cfg(not(feature = "std"))] +impl core::fmt::Debug for GrandpaJustification { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "GrandpaJustification {{ round: {:?}, commit: , votes_ancestries: {:?} }}", self.round, self.votes_ancestries) + } +} + impl GrandpaJustification { /// Returns reasonable size of justification using constants from the provided chain. /// diff --git a/bridges/primitives/header-chain/src/justification/verification/equivocation.rs b/bridges/primitives/header-chain/src/justification/verification/equivocation.rs index fbad30128199..bfcd22f8ca6a 100644 --- a/bridges/primitives/header-chain/src/justification/verification/equivocation.rs +++ b/bridges/primitives/header-chain/src/justification/verification/equivocation.rs @@ -34,6 +34,8 @@ use sp_runtime::traits::Header as HeaderT; use sp_std::{ collections::{btree_map::BTreeMap, btree_set::BTreeSet}, prelude::*, + vec, + vec::Vec, }; enum AuthorityVotes { diff --git a/bridges/primitives/header-chain/src/justification/verification/mod.rs b/bridges/primitives/header-chain/src/justification/verification/mod.rs index 9df3511e1035..9941537eb095 100644 --- a/bridges/primitives/header-chain/src/justification/verification/mod.rs +++ b/bridges/primitives/header-chain/src/justification/verification/mod.rs @@ -35,6 +35,8 @@ use sp_std::{ btree_set::BTreeSet, }, prelude::*, + vec, + vec::Vec, }; type SignedPrecommit
= finality_grandpa::SignedPrecommit< diff --git a/bridges/primitives/header-chain/src/justification/verification/optimizer.rs b/bridges/primitives/header-chain/src/justification/verification/optimizer.rs index 3f1e6ab670ca..5098b594db68 100644 --- a/bridges/primitives/header-chain/src/justification/verification/optimizer.rs +++ b/bridges/primitives/header-chain/src/justification/verification/optimizer.rs @@ -26,7 +26,7 @@ use crate::justification::verification::{ }; use sp_consensus_grandpa::AuthorityId; use sp_runtime::traits::Header as HeaderT; -use sp_std::{collections::btree_set::BTreeSet, prelude::*}; +use sp_std::{collections::btree_set::BTreeSet, prelude::*, vec, vec::Vec}; // Verification callbacks for justification optimization. struct JustificationOptimizer { diff --git a/bridges/primitives/header-chain/src/lib.rs b/bridges/primitives/header-chain/src/lib.rs index 26295dee1801..48326bf5c19d 100644 --- a/bridges/primitives/header-chain/src/lib.rs +++ b/bridges/primitives/header-chain/src/lib.rs @@ -38,6 +38,10 @@ use sp_consensus_grandpa::{ use sp_runtime::{traits::Header as HeaderT, Digest, RuntimeDebug, SaturatedConversion}; use sp_std::{boxed::Box, vec::Vec}; +pub use call_info::{BridgeGrandpaCall, BridgeGrandpaCallOf, SubmitFinalityProofInfo}; + +mod call_info; + pub mod justification; pub mod storage_keys; @@ -228,39 +232,6 @@ pub trait FindEquivocations Result, Self::Error>; } -/// A minimized version of `pallet-bridge-grandpa::Call` that can be used without a runtime. -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum BridgeGrandpaCall { - /// `pallet-bridge-grandpa::Call::submit_finality_proof` - #[codec(index = 0)] - submit_finality_proof { - /// The header that we are going to finalize. - finality_target: Box
, - /// Finality justification for the `finality_target`. - justification: justification::GrandpaJustification
, - }, - /// `pallet-bridge-grandpa::Call::initialize` - #[codec(index = 1)] - initialize { - /// All data, required to initialize the pallet. - init_data: InitializationData
, - }, - /// `pallet-bridge-grandpa::Call::submit_finality_proof_ex` - #[codec(index = 4)] - submit_finality_proof_ex { - /// The header that we are going to finalize. - finality_target: Box
, - /// Finality justification for the `finality_target`. - justification: justification::GrandpaJustification
, - /// An identifier of the validators set, that have signed the justification. - current_set_id: SetId, - }, -} - -/// The `BridgeGrandpaCall` used by a chain. -pub type BridgeGrandpaCallOf = BridgeGrandpaCall>; - /// Substrate-based chain that is using direct GRANDPA finality. /// /// Keep in mind that parachains are relying on relay chain GRANDPA, so they should not implement diff --git a/bridges/primitives/messages/Cargo.toml b/bridges/primitives/messages/Cargo.toml index 4a9037342bce..87c8cbe88180 100644 --- a/bridges/primitives/messages/Cargo.toml +++ b/bridges/primitives/messages/Cargo.toml @@ -16,19 +16,19 @@ scale-info = { features = ["bit-vec", "derive"], workspace = true } serde = { features = ["alloc", "derive"], workspace = true } # Bridge dependencies - bp-runtime = { workspace = true } bp-header-chain = { workspace = true } # Substrate Dependencies - frame-support = { workspace = true } sp-core = { workspace = true } sp-std = { workspace = true } +sp-io = { workspace = true } [dev-dependencies] hex = { workspace = true, default-features = true } hex-literal = { workspace = true, default-features = true } +bp-runtime = { workspace = true } [features] default = ["std"] @@ -40,5 +40,6 @@ std = [ "scale-info/std", "serde/std", "sp-core/std", + "sp-io/std", "sp-std/std", ] diff --git a/bridges/primitives/messages/src/call_info.rs b/bridges/primitives/messages/src/call_info.rs new file mode 100644 index 000000000000..dfd076f029b4 --- /dev/null +++ b/bridges/primitives/messages/src/call_info.rs @@ -0,0 +1,164 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Defines structures related to calls of the `pallet-bridge-messages` pallet. + +use crate::{MessageNonce, UnrewardedRelayersState}; + +use codec::{Decode, Encode}; +use frame_support::weights::Weight; +use scale_info::TypeInfo; +use sp_core::RuntimeDebug; +use sp_std::ops::RangeInclusive; + +/// A minimized version of `pallet-bridge-messages::Call` that can be used without a runtime. +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +#[allow(non_camel_case_types)] +pub enum BridgeMessagesCall { + /// `pallet-bridge-messages::Call::receive_messages_proof` + #[codec(index = 2)] + receive_messages_proof { + /// Account id of relayer at the **bridged** chain. + relayer_id_at_bridged_chain: AccountId, + /// Messages proof. + proof: MessagesProof, + /// A number of messages in the proof. + messages_count: u32, + /// Total dispatch weight of messages in the proof. + dispatch_weight: Weight, + }, + /// `pallet-bridge-messages::Call::receive_messages_delivery_proof` + #[codec(index = 3)] + receive_messages_delivery_proof { + /// Messages delivery proof. + proof: MessagesDeliveryProof, + /// "Digest" of unrewarded relayers state at the bridged chain. + relayers_state: UnrewardedRelayersState, + }, +} + +/// Generic info about a messages delivery/confirmation proof. +#[derive(PartialEq, RuntimeDebug)] +pub struct BaseMessagesProofInfo { + /// Message lane, used by the call. + pub lane_id: LaneId, + /// Nonces of messages, included in the call. + /// + /// For delivery transaction, it is nonces of bundled messages. For confirmation + /// transaction, it is nonces that are to be confirmed during the call. + pub bundled_range: RangeInclusive, + /// Nonce of the best message, stored by this chain before the call is dispatched. + /// + /// For delivery transaction, it is the nonce of best delivered message before the call. + /// For confirmation transaction, it is the nonce of best confirmed message before the call. + pub best_stored_nonce: MessageNonce, +} + +impl BaseMessagesProofInfo { + /// Returns true if `bundled_range` continues the `0..=best_stored_nonce` range. + pub fn appends_to_stored_nonce(&self) -> bool { + Some(*self.bundled_range.start()) == self.best_stored_nonce.checked_add(1) + } +} + +/// Occupation state of the unrewarded relayers vector. +#[derive(PartialEq, RuntimeDebug)] +#[cfg_attr(test, derive(Default))] +pub struct UnrewardedRelayerOccupation { + /// The number of remaining unoccupied entries for new relayers. + pub free_relayer_slots: MessageNonce, + /// The number of messages that we are ready to accept. + pub free_message_slots: MessageNonce, +} + +/// Info about a `ReceiveMessagesProof` call which tries to update a single lane. +#[derive(PartialEq, RuntimeDebug)] +pub struct ReceiveMessagesProofInfo { + /// Base messages proof info + pub base: BaseMessagesProofInfo, + /// State of unrewarded relayers vector. + pub unrewarded_relayers: UnrewardedRelayerOccupation, +} + +impl ReceiveMessagesProofInfo { + /// Returns true if: + /// + /// - either inbound lane is ready to accept bundled messages; + /// + /// - or there are no bundled messages, but the inbound lane is blocked by too many unconfirmed + /// messages and/or unrewarded relayers. + pub fn is_obsolete(&self, is_dispatcher_active: bool) -> bool { + // if dispatcher is inactive, we don't accept any delivery transactions + if !is_dispatcher_active { + return true + } + + // transactions with zero bundled nonces are not allowed, unless they're message + // delivery transactions, which brings reward confirmations required to unblock + // the lane + if self.base.bundled_range.is_empty() { + let empty_transactions_allowed = + // we allow empty transactions when we can't accept delivery from new relayers + self.unrewarded_relayers.free_relayer_slots == 0 || + // or if we can't accept new messages at all + self.unrewarded_relayers.free_message_slots == 0; + + return !empty_transactions_allowed + } + + // otherwise we require bundled messages to continue stored range + !self.base.appends_to_stored_nonce() + } +} + +/// Info about a `ReceiveMessagesDeliveryProof` call which tries to update a single lane. +#[derive(PartialEq, RuntimeDebug)] +pub struct ReceiveMessagesDeliveryProofInfo(pub BaseMessagesProofInfo); + +impl ReceiveMessagesDeliveryProofInfo { + /// Returns true if outbound lane is ready to accept confirmations of bundled messages. + pub fn is_obsolete(&self) -> bool { + self.0.bundled_range.is_empty() || !self.0.appends_to_stored_nonce() + } +} + +/// Info about a `ReceiveMessagesProof` or a `ReceiveMessagesDeliveryProof` call +/// which tries to update a single lane. +#[derive(PartialEq, RuntimeDebug)] +pub enum MessagesCallInfo { + /// Messages delivery call info. + ReceiveMessagesProof(ReceiveMessagesProofInfo), + /// Messages delivery confirmation call info. + ReceiveMessagesDeliveryProof(ReceiveMessagesDeliveryProofInfo), +} + +impl MessagesCallInfo { + /// Returns lane, used by the call. + pub fn lane_id(&self) -> LaneId { + match *self { + Self::ReceiveMessagesProof(ref info) => info.base.lane_id, + Self::ReceiveMessagesDeliveryProof(ref info) => info.0.lane_id, + } + } + + /// Returns range of messages, bundled with the call. + pub fn bundled_messages(&self) -> RangeInclusive { + match *self { + Self::ReceiveMessagesProof(ref info) => info.base.bundled_range.clone(), + Self::ReceiveMessagesDeliveryProof(ref info) => info.0.bundled_range.clone(), + } + } +} diff --git a/bridges/primitives/messages/src/lane.rs b/bridges/primitives/messages/src/lane.rs new file mode 100644 index 000000000000..0f14ce93e114 --- /dev/null +++ b/bridges/primitives/messages/src/lane.rs @@ -0,0 +1,334 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Primitives of messages module, that represents lane id. + +use codec::{Codec, Decode, Encode, EncodeLike, MaxEncodedLen}; +use scale_info::TypeInfo; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use sp_core::{RuntimeDebug, TypeId, H256}; +use sp_io::hashing::blake2_256; +use sp_std::fmt::Debug; + +/// Trait representing a generic `LaneId` type. +pub trait LaneIdType: + Clone + + Copy + + Codec + + EncodeLike + + Debug + + Default + + PartialEq + + Eq + + Ord + + TypeInfo + + MaxEncodedLen + + Serialize + + DeserializeOwned +{ + /// Creates a new `LaneId` type (if supported). + fn try_new(endpoint1: E, endpoint2: E) -> Result; +} + +/// Bridge lane identifier (legacy). +/// +/// Note: For backwards compatibility reasons, we also handle the older format `[u8; 4]`. +#[derive( + Clone, + Copy, + Decode, + Default, + Encode, + Eq, + Ord, + PartialOrd, + PartialEq, + TypeInfo, + MaxEncodedLen, + Serialize, + Deserialize, +)] +pub struct LegacyLaneId(pub [u8; 4]); + +impl LaneIdType for LegacyLaneId { + /// Create lane identifier from two locations. + fn try_new(_endpoint1: T, _endpoint2: T) -> Result { + // we don't support this for `LegacyLaneId`, because it was hard-coded before + Err(()) + } +} + +#[cfg(feature = "std")] +impl TryFrom> for LegacyLaneId { + type Error = (); + + fn try_from(value: Vec) -> Result { + if value.len() == 4 { + return <[u8; 4]>::try_from(value).map(Self).map_err(|_| ()); + } + Err(()) + } +} + +impl core::fmt::Debug for LegacyLaneId { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + self.0.fmt(fmt) + } +} + +impl AsRef<[u8]> for LegacyLaneId { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl TypeId for LegacyLaneId { + const TYPE_ID: [u8; 4] = *b"blan"; +} + +/// Bridge lane identifier. +/// +/// Lane connects two endpoints at both sides of the bridge. We assume that every endpoint +/// has its own unique identifier. We want lane identifiers to be **the same on the both sides +/// of the bridge** (and naturally unique across global consensus if endpoints have unique +/// identifiers). So lane id is the hash (`blake2_256`) of **ordered** encoded locations +/// concatenation (separated by some binary data). I.e.: +/// +/// ```nocompile +/// let endpoint1 = X2(GlobalConsensus(NetworkId::Rococo), Parachain(42)); +/// let endpoint2 = X2(GlobalConsensus(NetworkId::Wococo), Parachain(777)); +/// +/// let final_lane_key = if endpoint1 < endpoint2 { +/// (endpoint1, VALUES_SEPARATOR, endpoint2) +/// } else { +/// (endpoint2, VALUES_SEPARATOR, endpoint1) +/// }.using_encoded(blake2_256); +/// ``` +#[derive( + Clone, + Copy, + Decode, + Default, + Encode, + Eq, + Ord, + PartialOrd, + PartialEq, + TypeInfo, + MaxEncodedLen, + Serialize, + Deserialize, +)] +pub struct HashedLaneId(H256); + +impl HashedLaneId { + /// Create lane identifier from given hash. + /// + /// There's no `From` implementation for the `LaneId`, because using this conversion + /// in a wrong way (i.e. computing hash of endpoints manually) may lead to issues. So we + /// want the call to be explicit. + #[cfg(feature = "std")] + pub const fn from_inner(inner: H256) -> Self { + Self(inner) + } + + /// Access the inner lane representation. + pub fn inner(&self) -> &H256 { + &self.0 + } +} + +impl core::fmt::Display for HashedLaneId { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + core::fmt::Display::fmt(&self.0, f) + } +} + +impl core::fmt::Debug for HashedLaneId { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + core::fmt::Debug::fmt(&self.0, f) + } +} + +impl TypeId for HashedLaneId { + const TYPE_ID: [u8; 4] = *b"hlan"; +} + +impl LaneIdType for HashedLaneId { + /// Create lane identifier from two locations. + fn try_new(endpoint1: T, endpoint2: T) -> Result { + const VALUES_SEPARATOR: [u8; 31] = *b"bridges-lane-id-value-separator"; + + Ok(Self( + if endpoint1 < endpoint2 { + (endpoint1, VALUES_SEPARATOR, endpoint2) + } else { + (endpoint2, VALUES_SEPARATOR, endpoint1) + } + .using_encoded(blake2_256) + .into(), + )) + } +} + +#[cfg(feature = "std")] +impl TryFrom> for HashedLaneId { + type Error = (); + + fn try_from(value: Vec) -> Result { + if value.len() == 32 { + return <[u8; 32]>::try_from(value).map(|v| Self(H256::from(v))).map_err(|_| ()); + } + Err(()) + } +} + +/// Lane state. +#[derive(Clone, Copy, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen, RuntimeDebug)] +pub enum LaneState { + /// Lane is opened and messages may be sent/received over it. + Opened, + /// Lane is closed and all attempts to send/receive messages to/from this lane + /// will fail. + /// + /// Keep in mind that the lane has two ends and the state of the same lane at + /// its ends may be different. Those who are controlling/serving the lane + /// and/or sending messages over the lane, have to coordinate their actions on + /// both ends to make sure that lane is operating smoothly on both ends. + Closed, +} + +impl LaneState { + /// Returns true if lane state allows sending/receiving messages. + pub fn is_active(&self) -> bool { + matches!(*self, LaneState::Opened) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::MessageNonce; + + #[test] + fn lane_id_debug_format_matches_inner_hash_format() { + assert_eq!( + format!("{:?}", HashedLaneId(H256::from([1u8; 32]))), + format!("{:?}", H256::from([1u8; 32])), + ); + assert_eq!(format!("{:?}", LegacyLaneId([0, 0, 0, 1])), format!("{:?}", [0, 0, 0, 1]),); + } + + #[test] + fn hashed_encode_decode_works() { + // simple encode/decode - new format + let lane_id = HashedLaneId(H256::from([1u8; 32])); + let encoded_lane_id = lane_id.encode(); + let decoded_lane_id = HashedLaneId::decode(&mut &encoded_lane_id[..]).expect("decodable"); + assert_eq!(lane_id, decoded_lane_id); + assert_eq!( + "0101010101010101010101010101010101010101010101010101010101010101", + hex::encode(encoded_lane_id) + ); + } + + #[test] + fn legacy_encode_decode_works() { + // simple encode/decode - old format + let lane_id = LegacyLaneId([0, 0, 0, 1]); + let encoded_lane_id = lane_id.encode(); + let decoded_lane_id = LegacyLaneId::decode(&mut &encoded_lane_id[..]).expect("decodable"); + assert_eq!(lane_id, decoded_lane_id); + assert_eq!("00000001", hex::encode(encoded_lane_id)); + + // decode sample + let bytes = vec![0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]; + let (lane, nonce_start, nonce_end): (LegacyLaneId, MessageNonce, MessageNonce) = + Decode::decode(&mut &bytes[..]).unwrap(); + assert_eq!(lane, LegacyLaneId([0, 0, 0, 2])); + assert_eq!(nonce_start, 1); + assert_eq!(nonce_end, 1); + + // run encode/decode for `LaneId` with different positions + let expected_lane = LegacyLaneId([0, 0, 0, 1]); + let expected_nonce_start = 1088_u64; + let expected_nonce_end = 9185_u64; + + // decode: LaneId,Nonce,Nonce + let bytes = (expected_lane, expected_nonce_start, expected_nonce_end).encode(); + let (lane, nonce_start, nonce_end): (LegacyLaneId, MessageNonce, MessageNonce) = + Decode::decode(&mut &bytes[..]).unwrap(); + assert_eq!(lane, expected_lane); + assert_eq!(nonce_start, expected_nonce_start); + assert_eq!(nonce_end, expected_nonce_end); + + // decode: Nonce,LaneId,Nonce + let bytes = (expected_nonce_start, expected_lane, expected_nonce_end).encode(); + let (nonce_start, lane, nonce_end): (MessageNonce, LegacyLaneId, MessageNonce) = + Decode::decode(&mut &bytes[..]).unwrap(); + assert_eq!(lane, expected_lane); + assert_eq!(nonce_start, expected_nonce_start); + assert_eq!(nonce_end, expected_nonce_end); + + // decode: Nonce,Nonce,LaneId + let bytes = (expected_nonce_start, expected_nonce_end, expected_lane).encode(); + let (nonce_start, nonce_end, lane): (MessageNonce, MessageNonce, LegacyLaneId) = + Decode::decode(&mut &bytes[..]).unwrap(); + assert_eq!(lane, expected_lane); + assert_eq!(nonce_start, expected_nonce_start); + assert_eq!(nonce_end, expected_nonce_end); + } + + #[test] + fn hashed_lane_id_is_generated_using_ordered_endpoints() { + assert_eq!(HashedLaneId::try_new(1, 2).unwrap(), HashedLaneId::try_new(2, 1).unwrap()); + } + + #[test] + fn hashed_lane_id_is_different_for_different_endpoints() { + assert_ne!(HashedLaneId::try_new(1, 2).unwrap(), HashedLaneId::try_new(1, 3).unwrap()); + } + + #[test] + fn hashed_lane_id_is_different_even_if_arguments_has_partial_matching_encoding() { + /// Some artificial type that generates the same encoding for different values + /// concatenations. I.e. the encoding for `(Either::Two(1, 2), Either::Two(3, 4))` + /// is the same as encoding of `(Either::Three(1, 2, 3), Either::One(4))`. + /// In practice, this type is not useful, because you can't do a proper decoding. + /// But still there may be some collisions even in proper types. + #[derive(Eq, Ord, PartialEq, PartialOrd)] + enum Either { + Three(u64, u64, u64), + Two(u64, u64), + One(u64), + } + + impl codec::Encode for Either { + fn encode(&self) -> Vec { + match *self { + Self::One(a) => a.encode(), + Self::Two(a, b) => (a, b).encode(), + Self::Three(a, b, c) => (a, b, c).encode(), + } + } + } + + assert_ne!( + HashedLaneId::try_new(Either::Two(1, 2), Either::Two(3, 4)).unwrap(), + HashedLaneId::try_new(Either::Three(1, 2, 3), Either::One(4)).unwrap(), + ); + } +} diff --git a/bridges/primitives/messages/src/lib.rs b/bridges/primitives/messages/src/lib.rs index 9984f8ac3222..2776b806cc16 100644 --- a/bridges/primitives/messages/src/lib.rs +++ b/bridges/primitives/messages/src/lib.rs @@ -31,9 +31,17 @@ pub use frame_support::weights::Weight; use scale_info::TypeInfo; use serde::{Deserialize, Serialize}; use source_chain::RelayersRewards; -use sp_core::{RuntimeDebug, TypeId}; +use sp_core::RuntimeDebug; use sp_std::{collections::vec_deque::VecDeque, ops::RangeInclusive, prelude::*}; +pub use call_info::{ + BaseMessagesProofInfo, BridgeMessagesCall, MessagesCallInfo, ReceiveMessagesDeliveryProofInfo, + ReceiveMessagesProofInfo, UnrewardedRelayerOccupation, +}; +pub use lane::{HashedLaneId, LaneIdType, LaneState, LegacyLaneId}; + +mod call_info; +mod lane; pub mod source_chain; pub mod storage_keys; pub mod target_chain; @@ -165,52 +173,15 @@ impl OperatingMode for MessagesOperatingMode { } } -/// Lane id which implements `TypeId`. -#[derive( - Clone, - Copy, - Decode, - Default, - Encode, - Eq, - Ord, - PartialOrd, - PartialEq, - TypeInfo, - MaxEncodedLen, - Serialize, - Deserialize, -)] -pub struct LaneId(pub [u8; 4]); - -impl core::fmt::Debug for LaneId { - fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { - self.0.fmt(fmt) - } -} - -impl AsRef<[u8]> for LaneId { - fn as_ref(&self) -> &[u8] { - &self.0 - } -} - -impl TypeId for LaneId { - const TYPE_ID: [u8; 4] = *b"blan"; -} - /// Message nonce. Valid messages will never have 0 nonce. pub type MessageNonce = u64; -/// Message id as a tuple. -pub type BridgeMessageId = (LaneId, MessageNonce); - /// Opaque message payload. We only decode this payload when it is dispatched. pub type MessagePayload = Vec; /// Message key (unique message identifier) as it is stored in the storage. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo, MaxEncodedLen)] -pub struct MessageKey { +pub struct MessageKey { /// ID of the message lane. pub lane_id: LaneId, /// Message nonce. @@ -219,9 +190,9 @@ pub struct MessageKey { /// Message as it is stored in the storage. #[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] -pub struct Message { +pub struct Message { /// Message key. - pub key: MessageKey, + pub key: MessageKey, /// Message payload. pub payload: MessagePayload, } @@ -257,15 +228,29 @@ pub struct InboundLaneData { /// This value is updated indirectly when an `OutboundLane` state of the source /// chain is received alongside with new messages delivery. pub last_confirmed_nonce: MessageNonce, + + /// Inbound lane state. + /// + /// If state is `Closed`, then all attempts to deliver messages to this end will fail. + pub state: LaneState, } impl Default for InboundLaneData { fn default() -> Self { - InboundLaneData { relayers: VecDeque::new(), last_confirmed_nonce: 0 } + InboundLaneData { + state: LaneState::Closed, + relayers: VecDeque::new(), + last_confirmed_nonce: 0, + } } } impl InboundLaneData { + /// Returns default inbound lane data with opened state. + pub fn opened() -> Self { + InboundLaneData { state: LaneState::Opened, ..Default::default() } + } + /// Returns approximate size of the struct, given a number of entries in the `relayers` set and /// size of each entry. /// @@ -351,21 +336,21 @@ pub struct UnrewardedRelayer { } /// Received messages with their dispatch result. -#[derive(Clone, Default, Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] -pub struct ReceivedMessages { +#[derive(Clone, Encode, Decode, RuntimeDebug, PartialEq, Eq, TypeInfo)] +pub struct ReceivedMessages { /// Id of the lane which is receiving messages. pub lane: LaneId, /// Result of messages which we tried to dispatch pub receive_results: Vec<(MessageNonce, ReceptionResult)>, } -impl ReceivedMessages { +impl ReceivedMessages { /// Creates new `ReceivedMessages` structure from given results. pub fn new( lane: LaneId, receive_results: Vec<(MessageNonce, ReceptionResult)>, ) -> Self { - ReceivedMessages { lane, receive_results } + ReceivedMessages { lane: lane.into(), receive_results } } /// Push `result` of the `message` delivery onto `receive_results` vector. @@ -471,11 +456,23 @@ pub struct OutboundLaneData { pub latest_received_nonce: MessageNonce, /// Nonce of the latest message, generated by us. pub latest_generated_nonce: MessageNonce, + /// Lane state. + /// + /// If state is `Closed`, then all attempts to send messages at this end will fail. + pub state: LaneState, +} + +impl OutboundLaneData { + /// Returns default outbound lane data with opened state. + pub fn opened() -> Self { + OutboundLaneData { state: LaneState::Opened, ..Default::default() } + } } impl Default for OutboundLaneData { fn default() -> Self { OutboundLaneData { + state: LaneState::Closed, // it is 1 because we're pruning everything in [oldest_unpruned_nonce; // latest_received_nonce] oldest_unpruned_nonce: 1, @@ -514,32 +511,6 @@ where relayers_rewards } -/// A minimized version of `pallet-bridge-messages::Call` that can be used without a runtime. -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum BridgeMessagesCall { - /// `pallet-bridge-messages::Call::receive_messages_proof` - #[codec(index = 2)] - receive_messages_proof { - /// Account id of relayer at the **bridged** chain. - relayer_id_at_bridged_chain: AccountId, - /// Messages proof. - proof: MessagesProof, - /// A number of messages in the proof. - messages_count: u32, - /// Total dispatch weight of messages in the proof. - dispatch_weight: Weight, - }, - /// `pallet-bridge-messages::Call::receive_messages_delivery_proof` - #[codec(index = 3)] - receive_messages_delivery_proof { - /// Messages delivery proof. - proof: MessagesDeliveryProof, - /// "Digest" of unrewarded relayers state at the bridged chain. - relayers_state: UnrewardedRelayersState, - }, -} - /// Error that happens during message verification. #[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, PalletError, TypeInfo)] pub enum VerificationError { @@ -569,9 +540,16 @@ pub enum VerificationError { mod tests { use super::*; + #[test] + fn lane_is_closed_by_default() { + assert_eq!(InboundLaneData::<()>::default().state, LaneState::Closed); + assert_eq!(OutboundLaneData::default().state, LaneState::Closed); + } + #[test] fn total_unrewarded_messages_does_not_overflow() { let lane_data = InboundLaneData { + state: LaneState::Opened, relayers: vec![ UnrewardedRelayer { relayer: 1, messages: DeliveredMessages::new(0) }, UnrewardedRelayer { @@ -599,6 +577,7 @@ mod tests { for (relayer_entries, messages_count) in test_cases { let expected_size = InboundLaneData::::encoded_size_hint(relayer_entries as _); let actual_size = InboundLaneData { + state: LaneState::Opened, relayers: (1u8..=relayer_entries) .map(|i| UnrewardedRelayer { relayer: i, @@ -626,9 +605,4 @@ mod tests { assert!(delivered_messages.contains_message(150)); assert!(!delivered_messages.contains_message(151)); } - - #[test] - fn lane_id_debug_format_matches_inner_array_format() { - assert_eq!(format!("{:?}", LaneId([0, 0, 0, 0])), format!("{:?}", [0, 0, 0, 0]),); - } } diff --git a/bridges/primitives/messages/src/source_chain.rs b/bridges/primitives/messages/src/source_chain.rs index 64f015bdb822..1d4a513035c7 100644 --- a/bridges/primitives/messages/src/source_chain.rs +++ b/bridges/primitives/messages/src/source_chain.rs @@ -16,7 +16,7 @@ //! Primitives of messages module, that are used on the source chain. -use crate::{LaneId, MessageNonce, UnrewardedRelayer}; +use crate::{MessageNonce, UnrewardedRelayer}; use bp_runtime::{raw_storage_proof_size, RawStorageProof, Size}; use codec::{Decode, Encode}; @@ -39,7 +39,7 @@ use sp_std::{ /// /// - lane id. #[derive(Clone, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo)] -pub struct FromBridgedChainMessagesDeliveryProof { +pub struct FromBridgedChainMessagesDeliveryProof { /// Hash of the bridge header the proof is for. pub bridged_header_hash: BridgedHeaderHash, /// Storage trie proof generated for [`Self::bridged_header_hash`]. @@ -48,7 +48,9 @@ pub struct FromBridgedChainMessagesDeliveryProof { pub lane: LaneId, } -impl Size for FromBridgedChainMessagesDeliveryProof { +impl Size + for FromBridgedChainMessagesDeliveryProof +{ fn size(&self) -> u32 { use frame_support::sp_runtime::SaturatedConversion; raw_storage_proof_size(&self.storage_proof).saturated_into() @@ -60,7 +62,7 @@ pub type RelayersRewards = BTreeMap; /// Manages payments that are happening at the source chain during delivery confirmation /// transaction. -pub trait DeliveryConfirmationPayments { +pub trait DeliveryConfirmationPayments { /// Error type. type Error: Debug + Into<&'static str>; @@ -78,7 +80,7 @@ pub trait DeliveryConfirmationPayments { ) -> MessageNonce; } -impl DeliveryConfirmationPayments for () { +impl DeliveryConfirmationPayments for () { type Error = &'static str; fn pay_reward( @@ -94,14 +96,14 @@ impl DeliveryConfirmationPayments for () { /// Callback that is called at the source chain (bridge hub) when we get delivery confirmation /// for new messages. -pub trait OnMessagesDelivered { +pub trait OnMessagesDelivered { /// New messages delivery has been confirmed. /// /// The only argument of the function is the number of yet undelivered messages fn on_messages_delivered(lane: LaneId, enqueued_messages: MessageNonce); } -impl OnMessagesDelivered for () { +impl OnMessagesDelivered for () { fn on_messages_delivered(_lane: LaneId, _enqueued_messages: MessageNonce) {} } @@ -115,7 +117,7 @@ pub struct SendMessageArtifacts { } /// Messages bridge API to be used from other pallets. -pub trait MessagesBridge { +pub trait MessagesBridge { /// Error type. type Error: Debug; @@ -141,7 +143,7 @@ pub trait MessagesBridge { /// where outbound messages are forbidden. pub struct ForbidOutboundMessages; -impl DeliveryConfirmationPayments for ForbidOutboundMessages { +impl DeliveryConfirmationPayments for ForbidOutboundMessages { type Error = &'static str; fn pay_reward( diff --git a/bridges/primitives/messages/src/storage_keys.rs b/bridges/primitives/messages/src/storage_keys.rs index 8eedf8fcc7ac..fb3371cb830c 100644 --- a/bridges/primitives/messages/src/storage_keys.rs +++ b/bridges/primitives/messages/src/storage_keys.rs @@ -25,7 +25,7 @@ pub const OUTBOUND_LANES_MAP_NAME: &str = "OutboundLanes"; /// Name of the `InboundLanes` storage map. pub const INBOUND_LANES_MAP_NAME: &str = "InboundLanes"; -use crate::{LaneId, MessageKey, MessageNonce}; +use crate::{MessageKey, MessageNonce}; use codec::Encode; use frame_support::Blake2_128Concat; @@ -43,16 +43,20 @@ pub fn operating_mode_key(pallet_prefix: &str) -> StorageKey { } /// Storage key of the outbound message in the runtime storage. -pub fn message_key(pallet_prefix: &str, lane: &LaneId, nonce: MessageNonce) -> StorageKey { +pub fn message_key( + pallet_prefix: &str, + lane: LaneId, + nonce: MessageNonce, +) -> StorageKey { bp_runtime::storage_map_final_key::( pallet_prefix, OUTBOUND_MESSAGES_MAP_NAME, - &MessageKey { lane_id: *lane, nonce }.encode(), + &MessageKey { lane_id: lane, nonce }.encode(), ) } /// Storage key of the outbound message lane state in the runtime storage. -pub fn outbound_lane_data_key(pallet_prefix: &str, lane: &LaneId) -> StorageKey { +pub fn outbound_lane_data_key(pallet_prefix: &str, lane: &LaneId) -> StorageKey { bp_runtime::storage_map_final_key::( pallet_prefix, OUTBOUND_LANES_MAP_NAME, @@ -61,7 +65,7 @@ pub fn outbound_lane_data_key(pallet_prefix: &str, lane: &LaneId) -> StorageKey } /// Storage key of the inbound message lane state in the runtime storage. -pub fn inbound_lane_data_key(pallet_prefix: &str, lane: &LaneId) -> StorageKey { +pub fn inbound_lane_data_key(pallet_prefix: &str, lane: &LaneId) -> StorageKey { bp_runtime::storage_map_final_key::( pallet_prefix, INBOUND_LANES_MAP_NAME, @@ -72,6 +76,10 @@ pub fn inbound_lane_data_key(pallet_prefix: &str, lane: &LaneId) -> StorageKey { #[cfg(test)] mod tests { use super::*; + use crate::{ + lane::{HashedLaneId, LegacyLaneId}, + LaneIdType, + }; use hex_literal::hex; #[test] @@ -91,7 +99,17 @@ mod tests { fn storage_message_key_computed_properly() { // If this test fails, then something has been changed in module storage that is breaking // all previously crafted messages proofs. - let storage_key = message_key("BridgeMessages", &LaneId(*b"test"), 42).0; + let storage_key = + message_key("BridgeMessages", &HashedLaneId::try_new(1, 2).unwrap(), 42).0; + assert_eq!( + storage_key, + hex!("dd16c784ebd3390a9bc0357c7511ed018a395e6242c6813b196ca31ed0547ea70e9bdb8f50c68d12f06eabb57759ee5eb1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dcf87f9793be208e5ea02a00000000000000").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); + + // check backwards compatibility + let storage_key = message_key("BridgeMessages", &LegacyLaneId(*b"test"), 42).0; assert_eq!( storage_key, hex!("dd16c784ebd3390a9bc0357c7511ed018a395e6242c6813b196ca31ed0547ea79446af0e09063bd4a7874aef8a997cec746573742a00000000000000").to_vec(), @@ -104,7 +122,17 @@ mod tests { fn outbound_lane_data_key_computed_properly() { // If this test fails, then something has been changed in module storage that is breaking // all previously crafted outbound lane state proofs. - let storage_key = outbound_lane_data_key("BridgeMessages", &LaneId(*b"test")).0; + let storage_key = + outbound_lane_data_key("BridgeMessages", &HashedLaneId::try_new(1, 2).unwrap()).0; + assert_eq!( + storage_key, + hex!("dd16c784ebd3390a9bc0357c7511ed0196c246acb9b55077390e3ca723a0ca1fd3bef8b00df8ca7b01813b5e2741950db1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dcf87f9793be208e5ea0").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); + + // check backwards compatibility + let storage_key = outbound_lane_data_key("BridgeMessages", &LegacyLaneId(*b"test")).0; assert_eq!( storage_key, hex!("dd16c784ebd3390a9bc0357c7511ed0196c246acb9b55077390e3ca723a0ca1f44a8995dd50b6657a037a7839304535b74657374").to_vec(), @@ -117,7 +145,17 @@ mod tests { fn inbound_lane_data_key_computed_properly() { // If this test fails, then something has been changed in module storage that is breaking // all previously crafted inbound lane state proofs. - let storage_key = inbound_lane_data_key("BridgeMessages", &LaneId(*b"test")).0; + let storage_key = + inbound_lane_data_key("BridgeMessages", &HashedLaneId::try_new(1, 2).unwrap()).0; + assert_eq!( + storage_key, + hex!("dd16c784ebd3390a9bc0357c7511ed01e5f83cf83f2127eb47afdc35d6e43fabd3bef8b00df8ca7b01813b5e2741950db1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dcf87f9793be208e5ea0").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); + + // check backwards compatibility + let storage_key = inbound_lane_data_key("BridgeMessages", &LegacyLaneId(*b"test")).0; assert_eq!( storage_key, hex!("dd16c784ebd3390a9bc0357c7511ed01e5f83cf83f2127eb47afdc35d6e43fab44a8995dd50b6657a037a7839304535b74657374").to_vec(), diff --git a/bridges/primitives/messages/src/target_chain.rs b/bridges/primitives/messages/src/target_chain.rs index 74fecb9d9f0d..cf07a400933a 100644 --- a/bridges/primitives/messages/src/target_chain.rs +++ b/bridges/primitives/messages/src/target_chain.rs @@ -16,14 +16,14 @@ //! Primitives of messages module, that are used on the target chain. -use crate::{LaneId, Message, MessageKey, MessageNonce, MessagePayload, OutboundLaneData}; +use crate::{Message, MessageKey, MessageNonce, MessagePayload, OutboundLaneData}; use bp_runtime::{messages::MessageDispatchResult, raw_storage_proof_size, RawStorageProof, Size}; use codec::{Decode, Encode, Error as CodecError}; use frame_support::weights::Weight; use scale_info::TypeInfo; use sp_core::RuntimeDebug; -use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, marker::PhantomData, prelude::*}; +use sp_std::{fmt::Debug, marker::PhantomData, prelude::*}; /// Messages proof from bridged chain. /// @@ -38,20 +38,20 @@ use sp_std::{collections::btree_map::BTreeMap, fmt::Debug, marker::PhantomData, /// /// - nonces (inclusive range) of messages which are included in this proof. #[derive(Clone, Decode, Encode, Eq, PartialEq, RuntimeDebug, TypeInfo)] -pub struct FromBridgedChainMessagesProof { +pub struct FromBridgedChainMessagesProof { /// Hash of the finalized bridged header the proof is for. pub bridged_header_hash: BridgedHeaderHash, /// A storage trie proof of messages being delivered. pub storage_proof: RawStorageProof, /// Messages in this proof are sent over this lane. - pub lane: LaneId, + pub lane: Lane, /// Nonce of the first message being delivered. pub nonces_start: MessageNonce, /// Nonce of the last message being delivered. pub nonces_end: MessageNonce, } -impl Size for FromBridgedChainMessagesProof { +impl Size for FromBridgedChainMessagesProof { fn size(&self) -> u32 { use frame_support::sp_runtime::SaturatedConversion; raw_storage_proof_size(&self.storage_proof).saturated_into() @@ -59,7 +59,7 @@ impl Size for FromBridgedChainMessagesProof = BTreeMap>; +pub type ProvedMessages = (LaneId, ProvedLaneMessages); /// Proved messages from single lane of the source chain. #[derive(RuntimeDebug, Encode, Decode, Clone, PartialEq, Eq, TypeInfo)] @@ -79,9 +79,9 @@ pub struct DispatchMessageData { /// Message with decoded dispatch payload. #[derive(RuntimeDebug)] -pub struct DispatchMessage { +pub struct DispatchMessage { /// Message key. - pub key: MessageKey, + pub key: MessageKey, /// Message data with decoded dispatch payload. pub data: DispatchMessageData, } @@ -96,6 +96,9 @@ pub trait MessageDispatch { /// Fine-grained result of single message dispatch (for better diagnostic purposes) type DispatchLevelResult: Clone + sp_std::fmt::Debug + Eq; + /// Lane identifier type. + type LaneId: Encode; + /// Returns `true` if dispatcher is ready to accept additional messages. The `false` should /// be treated as a hint by both dispatcher and its consumers - i.e. dispatcher shall not /// simply drop messages if it returns `false`. The consumer may still call the `dispatch` @@ -103,21 +106,23 @@ pub trait MessageDispatch { /// /// We check it in the messages delivery transaction prologue. So if it becomes `false` /// after some portion of messages is already dispatched, it doesn't fail the whole transaction. - fn is_active() -> bool; + fn is_active(lane: Self::LaneId) -> bool; /// Estimate dispatch weight. /// /// This function must return correct upper bound of dispatch weight. The return value /// of this function is expected to match return value of the corresponding /// `FromInboundLaneApi::message_details().dispatch_weight` call. - fn dispatch_weight(message: &mut DispatchMessage) -> Weight; + fn dispatch_weight( + message: &mut DispatchMessage, + ) -> Weight; /// Called when inbound message is received. /// /// It is up to the implementers of this trait to determine whether the message /// is invalid (i.e. improperly encoded, has too large weight, ...) or not. fn dispatch( - message: DispatchMessage, + message: DispatchMessage, ) -> MessageDispatchResult; } @@ -146,8 +151,10 @@ impl Default for ProvedLaneMessages { } } -impl From for DispatchMessage { - fn from(message: Message) -> Self { +impl From> + for DispatchMessage +{ + fn from(message: Message) -> Self { DispatchMessage { key: message.key, data: message.payload.into() } } } @@ -173,22 +180,27 @@ impl DeliveryPayments for () { /// Structure that may be used in place of `MessageDispatch` on chains, /// where inbound messages are forbidden. -pub struct ForbidInboundMessages(PhantomData); +pub struct ForbidInboundMessages(PhantomData<(DispatchPayload, LaneId)>); -impl MessageDispatch for ForbidInboundMessages { +impl MessageDispatch + for ForbidInboundMessages +{ type DispatchPayload = DispatchPayload; type DispatchLevelResult = (); + type LaneId = LaneId; - fn is_active() -> bool { + fn is_active(_: LaneId) -> bool { false } - fn dispatch_weight(_message: &mut DispatchMessage) -> Weight { + fn dispatch_weight( + _message: &mut DispatchMessage, + ) -> Weight { Weight::MAX } fn dispatch( - _: DispatchMessage, + _: DispatchMessage, ) -> MessageDispatchResult { MessageDispatchResult { unspent_weight: Weight::zero(), dispatch_level_result: () } } diff --git a/bridges/primitives/parachains/src/call_info.rs b/bridges/primitives/parachains/src/call_info.rs new file mode 100644 index 000000000000..fd7cd45a72c8 --- /dev/null +++ b/bridges/primitives/parachains/src/call_info.rs @@ -0,0 +1,59 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Defines structures related to calls of the `pallet-bridge-parachains` pallet. + +use crate::{ParaHash, ParaId, RelayBlockHash, RelayBlockNumber}; + +use bp_polkadot_core::parachains::ParaHeadsProof; +use bp_runtime::HeaderId; +use codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_runtime::RuntimeDebug; +use sp_std::vec::Vec; + +/// A minimized version of `pallet-bridge-parachains::Call` that can be used without a runtime. +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +#[allow(non_camel_case_types)] +pub enum BridgeParachainCall { + /// `pallet-bridge-parachains::Call::submit_parachain_heads` + #[codec(index = 0)] + submit_parachain_heads { + /// Relay chain block, for which we have submitted the `parachain_heads_proof`. + at_relay_block: (RelayBlockNumber, RelayBlockHash), + /// Parachain identifiers and their head hashes. + parachains: Vec<(ParaId, ParaHash)>, + /// Parachain heads proof. + parachain_heads_proof: ParaHeadsProof, + }, +} + +/// Info about a `SubmitParachainHeads` call which tries to update a single parachain. +/// +/// The pallet supports updating multiple parachain heads at once, +#[derive(PartialEq, RuntimeDebug)] +pub struct SubmitParachainHeadsInfo { + /// Number and hash of the finalized relay block that has been used to prove parachain + /// finality. + pub at_relay_block: HeaderId, + /// Parachain identifier. + pub para_id: ParaId, + /// Hash of the bundled parachain head. + pub para_head_hash: ParaHash, + /// If `true`, then the call must be free (assuming that everything else is valid) to + /// be treated as valid. + pub is_free_execution_expected: bool, +} diff --git a/bridges/primitives/parachains/src/lib.rs b/bridges/primitives/parachains/src/lib.rs index 142c6e9b0892..ec3bf9ca3a0a 100644 --- a/bridges/primitives/parachains/src/lib.rs +++ b/bridges/primitives/parachains/src/lib.rs @@ -20,11 +20,9 @@ #![cfg_attr(not(feature = "std"), no_std)] pub use bp_header_chain::StoredHeaderData; +pub use call_info::{BridgeParachainCall, SubmitParachainHeadsInfo}; -use bp_polkadot_core::{ - parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}, - BlockNumber as RelayBlockNumber, Hash as RelayBlockHash, -}; +use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaId}; use bp_runtime::{ BlockNumberOf, Chain, HashOf, HeaderOf, Parachain, StorageDoubleMapKeyProvider, StorageMapKeyProvider, @@ -36,6 +34,15 @@ use sp_core::storage::StorageKey; use sp_runtime::{traits::Header as HeaderT, RuntimeDebug}; use sp_std::{marker::PhantomData, prelude::*}; +/// Block hash of the bridged relay chain. +pub type RelayBlockHash = bp_polkadot_core::Hash; +/// Block number of the bridged relay chain. +pub type RelayBlockNumber = bp_polkadot_core::BlockNumber; +/// Hasher of the bridged relay chain. +pub type RelayBlockHasher = bp_polkadot_core::Hasher; + +mod call_info; + /// Best known parachain head hash. #[derive(Clone, Decode, Encode, MaxEncodedLen, PartialEq, RuntimeDebug, TypeInfo)] pub struct BestParaHeadHash { @@ -185,19 +192,3 @@ impl ParaStoredHeaderDataBuilder for C { None } } - -/// A minimized version of `pallet-bridge-parachains::Call` that can be used without a runtime. -#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -#[allow(non_camel_case_types)] -pub enum BridgeParachainCall { - /// `pallet-bridge-parachains::Call::submit_parachain_heads` - #[codec(index = 0)] - submit_parachain_heads { - /// Relay chain block, for which we have submitted the `parachain_heads_proof`. - at_relay_block: (RelayBlockNumber, RelayBlockHash), - /// Parachain identifiers and their head hashes. - parachains: Vec<(ParaId, ParaHash)>, - /// Parachain heads proof. - parachain_heads_proof: ParaHeadsProof, - }, -} diff --git a/bridges/primitives/polkadot-core/Cargo.toml b/bridges/primitives/polkadot-core/Cargo.toml index acae2f431bf2..295fb281e9bb 100644 --- a/bridges/primitives/polkadot-core/Cargo.toml +++ b/bridges/primitives/polkadot-core/Cargo.toml @@ -12,9 +12,10 @@ workspace = true [dependencies] codec = { features = ["derive"], workspace = true } -parity-util-mem = { optional = true, workspace = true } scale-info = { features = ["derive"], workspace = true } -serde = { optional = true, features = ["derive"], workspace = true, default-features = true } +serde = { optional = true, features = [ + "derive", +], workspace = true, default-features = true } # Bridge Dependencies @@ -40,7 +41,6 @@ std = [ "codec/std", "frame-support/std", "frame-system/std", - "parity-util-mem", "scale-info/std", "serde", "sp-core/std", diff --git a/bridges/primitives/polkadot-core/src/lib.rs b/bridges/primitives/polkadot-core/src/lib.rs index e83be59b2389..a8abdb59bea3 100644 --- a/bridges/primitives/polkadot-core/src/lib.rs +++ b/bridges/primitives/polkadot-core/src/lib.rs @@ -24,8 +24,8 @@ use bp_runtime::{ self, extensions::{ ChargeTransactionPayment, CheckEra, CheckGenesis, CheckNonZeroSender, CheckNonce, - CheckSpecVersion, CheckTxVersion, CheckWeight, GenericSignedExtension, - SignedExtensionSchema, + CheckSpecVersion, CheckTxVersion, CheckWeight, GenericTransactionExtension, + TransactionExtensionSchema, }, EncodedOrDecodedCall, StorageMapKeyProvider, TransactionEra, }; @@ -229,8 +229,12 @@ pub type SignedBlock = generic::SignedBlock; pub type Balance = u128; /// Unchecked Extrinsic type. -pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic, Signature, SignedExt>; +pub type UncheckedExtrinsic = generic::UncheckedExtrinsic< + AccountAddress, + EncodedOrDecodedCall, + Signature, + TransactionExt, +>; /// Account address, used by the Polkadot-like chain. pub type Address = MultiAddress; @@ -275,7 +279,7 @@ impl AccountInfoStorageMapKeyProvider { } /// Extra signed extension data that is used by most chains. -pub type CommonSignedExtra = ( +pub type CommonTransactionExtra = ( CheckNonZeroSender, CheckSpecVersion, CheckTxVersion, @@ -286,12 +290,12 @@ pub type CommonSignedExtra = ( ChargeTransactionPayment, ); -/// Extra signed extension data that starts with `CommonSignedExtra`. -pub type SuffixedCommonSignedExtension = - GenericSignedExtension<(CommonSignedExtra, Suffix)>; +/// Extra transaction extension data that starts with `CommonTransactionExtra`. +pub type SuffixedCommonTransactionExtension = + GenericTransactionExtension<(CommonTransactionExtra, Suffix)>; -/// Helper trait to define some extra methods on `SuffixedCommonSignedExtension`. -pub trait SuffixedCommonSignedExtensionExt { +/// Helper trait to define some extra methods on `SuffixedCommonTransactionExtension`. +pub trait SuffixedCommonTransactionExtensionExt { /// Create signed extension from its components. fn from_params( spec_version: u32, @@ -300,7 +304,7 @@ pub trait SuffixedCommonSignedExtensionExt { genesis_hash: Hash, nonce: Nonce, tip: Balance, - extra: (Suffix::Payload, Suffix::AdditionalSigned), + extra: (Suffix::Payload, Suffix::Implicit), ) -> Self; /// Return transaction nonce. @@ -310,9 +314,10 @@ pub trait SuffixedCommonSignedExtensionExt { fn tip(&self) -> Balance; } -impl SuffixedCommonSignedExtensionExt for SuffixedCommonSignedExtension +impl SuffixedCommonTransactionExtensionExt + for SuffixedCommonTransactionExtension where - Suffix: SignedExtensionSchema, + Suffix: TransactionExtensionSchema, { fn from_params( spec_version: u32, @@ -321,9 +326,9 @@ where genesis_hash: Hash, nonce: Nonce, tip: Balance, - extra: (Suffix::Payload, Suffix::AdditionalSigned), + extra: (Suffix::Payload, Suffix::Implicit), ) -> Self { - GenericSignedExtension::new( + GenericTransactionExtension::new( ( ( (), // non-zero sender @@ -365,7 +370,7 @@ where } /// Signed extension that is used by most chains. -pub type CommonSignedExtension = SuffixedCommonSignedExtension<()>; +pub type CommonTransactionExtension = SuffixedCommonTransactionExtension<()>; #[cfg(test)] mod tests { diff --git a/bridges/primitives/polkadot-core/src/parachains.rs b/bridges/primitives/polkadot-core/src/parachains.rs index d54ee108386e..a8b1cf6eebf4 100644 --- a/bridges/primitives/polkadot-core/src/parachains.rs +++ b/bridges/primitives/polkadot-core/src/parachains.rs @@ -32,9 +32,6 @@ use sp_std::vec::Vec; #[cfg(feature = "std")] use serde::{Deserialize, Serialize}; -#[cfg(feature = "std")] -use parity_util_mem::MallocSizeOf; - /// Parachain id. /// /// This is an equivalent of the `polkadot_parachain_primitives::Id`, which is a compact-encoded @@ -71,7 +68,7 @@ impl From for ParaId { #[derive( PartialEq, Eq, Clone, PartialOrd, Ord, Encode, Decode, RuntimeDebug, TypeInfo, Default, )] -#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash, MallocSizeOf))] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Hash))] pub struct ParaHead(pub Vec); impl ParaHead { diff --git a/bridges/primitives/relayers/Cargo.toml b/bridges/primitives/relayers/Cargo.toml index 3448e8a40963..34be38bed4ac 100644 --- a/bridges/primitives/relayers/Cargo.toml +++ b/bridges/primitives/relayers/Cargo.toml @@ -15,13 +15,15 @@ codec = { features = ["bit-vec", "derive"], workspace = true } scale-info = { features = ["bit-vec", "derive"], workspace = true } # Bridge Dependencies - +bp-header-chain = { workspace = true } bp-messages = { workspace = true } +bp-parachains = { workspace = true } bp-runtime = { workspace = true } # Substrate Dependencies - +frame-system = { workspace = true } frame-support = { workspace = true } +pallet-utility = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } @@ -32,10 +34,14 @@ hex-literal = { workspace = true, default-features = true } [features] default = ["std"] std = [ + "bp-header-chain/std", "bp-messages/std", + "bp-parachains/std", "bp-runtime/std", "codec/std", "frame-support/std", + "frame-system/std", + "pallet-utility/std", "scale-info/std", "sp-runtime/std", "sp-std/std", diff --git a/bridges/primitives/relayers/src/extension.rs b/bridges/primitives/relayers/src/extension.rs new file mode 100644 index 000000000000..8fd0f151e2a5 --- /dev/null +++ b/bridges/primitives/relayers/src/extension.rs @@ -0,0 +1,197 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! All runtime calls, supported by `pallet-bridge-relayers` when it acts as a signed +//! extension. + +use bp_header_chain::SubmitFinalityProofInfo; +use bp_messages::MessagesCallInfo; +use bp_parachains::SubmitParachainHeadsInfo; +use bp_runtime::StaticStrProvider; +use codec::{Decode, Encode}; +use frame_support::{ + dispatch::CallableCallFor, traits::IsSubType, weights::Weight, RuntimeDebugNoBound, +}; +use frame_system::Config as SystemConfig; +use pallet_utility::{Call as UtilityCall, Pallet as UtilityPallet}; +use sp_runtime::{ + traits::Get, + transaction_validity::{TransactionPriority, TransactionValidityError}, + RuntimeDebug, +}; +use sp_std::{fmt::Debug, marker::PhantomData, vec, vec::Vec}; + +/// Type of the call that the signed extension recognizes. +#[derive(PartialEq, RuntimeDebugNoBound)] +pub enum ExtensionCallInfo { + /// Relay chain finality + parachain finality + message delivery/confirmation calls. + AllFinalityAndMsgs( + SubmitFinalityProofInfo, + SubmitParachainHeadsInfo, + MessagesCallInfo, + ), + /// Relay chain finality + message delivery/confirmation calls. + RelayFinalityAndMsgs( + SubmitFinalityProofInfo, + MessagesCallInfo, + ), + /// Parachain finality + message delivery/confirmation calls. + /// + /// This variant is used only when bridging with parachain. + ParachainFinalityAndMsgs(SubmitParachainHeadsInfo, MessagesCallInfo), + /// Standalone message delivery/confirmation call. + Msgs(MessagesCallInfo), +} + +impl + ExtensionCallInfo +{ + /// Returns true if call is a message delivery call (with optional finality calls). + pub fn is_receive_messages_proof_call(&self) -> bool { + match self.messages_call_info() { + MessagesCallInfo::ReceiveMessagesProof(_) => true, + MessagesCallInfo::ReceiveMessagesDeliveryProof(_) => false, + } + } + + /// Returns the pre-dispatch `finality_target` sent to the `SubmitFinalityProof` call. + pub fn submit_finality_proof_info( + &self, + ) -> Option> { + match *self { + Self::AllFinalityAndMsgs(info, _, _) => Some(info), + Self::RelayFinalityAndMsgs(info, _) => Some(info), + _ => None, + } + } + + /// Returns the pre-dispatch `SubmitParachainHeadsInfo`. + pub fn submit_parachain_heads_info(&self) -> Option<&SubmitParachainHeadsInfo> { + match self { + Self::AllFinalityAndMsgs(_, info, _) => Some(info), + Self::ParachainFinalityAndMsgs(info, _) => Some(info), + _ => None, + } + } + + /// Returns the pre-dispatch `ReceiveMessagesProofInfo`. + pub fn messages_call_info(&self) -> &MessagesCallInfo { + match self { + Self::AllFinalityAndMsgs(_, _, info) => info, + Self::RelayFinalityAndMsgs(_, info) => info, + Self::ParachainFinalityAndMsgs(_, info) => info, + Self::Msgs(info) => info, + } + } +} + +/// Extra post-dispatch data, associated with the supported runtime call. +#[derive(Default, RuntimeDebug)] +pub struct ExtensionCallData { + /// Extra weight, consumed by the call. We have some assumptions about normal weight + /// that may be consumed by expected calls. If the actual weight is larger than that, + /// we do not refund relayer for this extra weight. + pub extra_weight: Weight, + /// Extra size, consumed by the call. We have some assumptions about normal size + /// of the encoded call. If the actual size is larger than that, we do not refund relayer + /// for this extra size. + pub extra_size: u32, +} + +/// Signed extension configuration. +/// +/// The single `pallet-bridge-relayers` instance may be shared by multiple messages +/// pallet instances, bridging with different remote networks. We expect every instance +/// of the messages pallet to add a separate signed extension to runtime. So it must +/// have a separate configuration. +pub trait ExtensionConfig { + /// Unique identifier of the signed extension that will use this configuration. + type IdProvider: StaticStrProvider; + /// Runtime that optionally supports batched calls. We assume that batched call + /// succeeds if and only if all of its nested calls succeed. + type Runtime: frame_system::Config; + /// Relayers pallet instance. + type BridgeRelayersPalletInstance: 'static; + /// Messages pallet instance. + type BridgeMessagesPalletInstance: 'static; + /// Additional priority that is added to base message delivery transaction priority + /// for every additional bundled message. + type PriorityBoostPerMessage: Get; + /// Block number for the remote **GRANDPA chain**. Mind that this chain is not + /// necessarily the chain that we are bridging with. If we are bridging with + /// parachain, it must be its parent relay chain. If we are bridging with the + /// GRANDPA chain, it must be it. + type RemoteGrandpaChainBlockNumber: Clone + Copy + Debug; + /// Lane identifier type. + type LaneId: Clone + Copy + Decode + Encode + Debug; + + /// Given runtime call, check if it is supported by the transaction extension. Additionally, + /// check if call (or any of batched calls) are obsolete. + fn parse_and_check_for_obsolete_call( + call: &::RuntimeCall, + ) -> Result< + Option>, + TransactionValidityError, + >; + + /// Check if runtime call is already obsolete. + fn check_obsolete_parsed_call( + call: &::RuntimeCall, + ) -> Result<&::RuntimeCall, TransactionValidityError>; + + /// Given runtime call info, check that this call has been successful and has updated + /// runtime storage accordingly. + fn check_call_result( + call_info: &ExtensionCallInfo, + call_data: &mut ExtensionCallData, + relayer: &::AccountId, + ) -> bool; +} + +/// Something that can unpack batch calls (all-or-nothing flavor) of given size. +pub trait BatchCallUnpacker { + /// Unpack batch call with no more than `max_packed_calls` calls. + fn unpack(call: &Runtime::RuntimeCall, max_packed_calls: u32) -> Vec<&Runtime::RuntimeCall>; +} + +/// An `BatchCallUnpacker` adapter for runtimes with utility pallet. +pub struct RuntimeWithUtilityPallet(PhantomData); + +impl BatchCallUnpacker for RuntimeWithUtilityPallet +where + Runtime: pallet_utility::Config::RuntimeCall>, + ::RuntimeCall: + IsSubType, Runtime>>, +{ + fn unpack( + call: &::RuntimeCall, + max_packed_calls: u32, + ) -> Vec<&::RuntimeCall> { + match call.is_sub_type() { + Some(UtilityCall::::batch_all { ref calls }) + if calls.len() <= max_packed_calls as usize => + calls.iter().collect(), + Some(_) => vec![], + None => vec![call], + } + } +} + +impl BatchCallUnpacker for () { + fn unpack(call: &Runtime::RuntimeCall, _max_packed_calls: u32) -> Vec<&Runtime::RuntimeCall> { + vec![call] + } +} diff --git a/bridges/primitives/relayers/src/lib.rs b/bridges/primitives/relayers/src/lib.rs index 436f33db4008..faa4cb177629 100644 --- a/bridges/primitives/relayers/src/lib.rs +++ b/bridges/primitives/relayers/src/lib.rs @@ -19,9 +19,12 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] +pub use extension::{ + BatchCallUnpacker, ExtensionCallData, ExtensionCallInfo, ExtensionConfig, + RuntimeWithUtilityPallet, +}; pub use registration::{ExplicitOrAccountParams, Registration, StakeAndSlash}; -use bp_messages::LaneId; use bp_runtime::{ChainId, StorageDoubleMapKeyProvider}; use frame_support::{traits::tokens::Preservation, Blake2_128Concat, Identity}; use scale_info::TypeInfo; @@ -32,6 +35,7 @@ use sp_runtime::{ }; use sp_std::{fmt::Debug, marker::PhantomData}; +mod extension; mod registration; /// The owner of the sovereign account that should pay the rewards. @@ -56,13 +60,16 @@ pub enum RewardsAccountOwner { /// of the sovereign accounts will pay rewards for different operations. So we need multiple /// parameters to identify the account that pays a reward to the relayer. #[derive(Copy, Clone, Debug, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen)] -pub struct RewardsAccountParams { - lane_id: LaneId, - bridged_chain_id: ChainId, +pub struct RewardsAccountParams { + // **IMPORTANT NOTE**: the order of fields here matters - we are using + // `into_account_truncating` and lane id is already `32` byte, so if other fields are encoded + // after it, they're simply dropped. So lane id shall be the last field. owner: RewardsAccountOwner, + bridged_chain_id: ChainId, + lane_id: LaneId, } -impl RewardsAccountParams { +impl RewardsAccountParams { /// Create a new instance of `RewardsAccountParams`. pub const fn new( lane_id: LaneId, @@ -71,9 +78,14 @@ impl RewardsAccountParams { ) -> Self { Self { lane_id, bridged_chain_id, owner } } + + /// Getter for `lane_id`. + pub const fn lane_id(&self) -> &LaneId { + &self.lane_id + } } -impl TypeId for RewardsAccountParams { +impl TypeId for RewardsAccountParams { const TYPE_ID: [u8; 4] = *b"brap"; } @@ -81,47 +93,58 @@ impl TypeId for RewardsAccountParams { pub trait PaymentProcedure { /// Error that may be returned by the procedure. type Error: Debug; + /// Lane identifier type. + type LaneId: Decode + Encode; /// Pay reward to the relayer from the account with provided params. fn pay_reward( relayer: &Relayer, - rewards_account_params: RewardsAccountParams, + rewards_account_params: RewardsAccountParams, reward: Reward, ) -> Result<(), Self::Error>; } impl PaymentProcedure for () { type Error = &'static str; + type LaneId = (); - fn pay_reward(_: &Relayer, _: RewardsAccountParams, _: Reward) -> Result<(), Self::Error> { + fn pay_reward( + _: &Relayer, + _: RewardsAccountParams, + _: Reward, + ) -> Result<(), Self::Error> { Ok(()) } } /// Reward payment procedure that does `balances::transfer` call from the account, derived from /// given params. -pub struct PayRewardFromAccount(PhantomData<(T, Relayer)>); +pub struct PayRewardFromAccount(PhantomData<(T, Relayer, LaneId)>); -impl PayRewardFromAccount +impl PayRewardFromAccount where Relayer: Decode + Encode, + LaneId: Decode + Encode, { /// Return account that pays rewards based on the provided parameters. - pub fn rewards_account(params: RewardsAccountParams) -> Relayer { + pub fn rewards_account(params: RewardsAccountParams) -> Relayer { params.into_sub_account_truncating(b"rewards-account") } } -impl PaymentProcedure for PayRewardFromAccount +impl PaymentProcedure + for PayRewardFromAccount where T: frame_support::traits::fungible::Mutate, Relayer: Decode + Encode + Eq, + LaneId: Decode + Encode, { type Error = sp_runtime::DispatchError; + type LaneId = LaneId; fn pay_reward( relayer: &Relayer, - rewards_account_params: RewardsAccountParams, + rewards_account_params: RewardsAccountParams, reward: T::Balance, ) -> Result<(), Self::Error> { T::transfer( @@ -134,49 +157,57 @@ where } } -/// Can be use to access the runtime storage key within the `RelayerRewards` map of the relayers +/// Can be used to access the runtime storage key within the `RelayerRewards` map of the relayers /// pallet. -pub struct RelayerRewardsKeyProvider(PhantomData<(AccountId, Reward)>); +pub struct RelayerRewardsKeyProvider( + PhantomData<(AccountId, Reward, LaneId)>, +); -impl StorageDoubleMapKeyProvider for RelayerRewardsKeyProvider +impl StorageDoubleMapKeyProvider + for RelayerRewardsKeyProvider where AccountId: 'static + Codec + EncodeLike + Send + Sync, Reward: 'static + Codec + EncodeLike + Send + Sync, + LaneId: Codec + EncodeLike + Send + Sync, { const MAP_NAME: &'static str = "RelayerRewards"; type Hasher1 = Blake2_128Concat; type Key1 = AccountId; type Hasher2 = Identity; - type Key2 = RewardsAccountParams; + type Key2 = RewardsAccountParams; type Value = Reward; } #[cfg(test)] mod tests { use super::*; - use bp_messages::LaneId; - use sp_runtime::testing::H256; + use bp_messages::{HashedLaneId, LaneIdType, LegacyLaneId}; + use sp_runtime::{app_crypto::Ss58Codec, testing::H256}; #[test] fn different_lanes_are_using_different_accounts() { assert_eq!( - PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( - LaneId([0, 0, 0, 0]), - *b"test", - RewardsAccountOwner::ThisChain - )), - hex_literal::hex!("62726170000000007465737400726577617264732d6163636f756e7400000000") + PayRewardFromAccount::<(), H256, HashedLaneId>::rewards_account( + RewardsAccountParams::new( + HashedLaneId::try_new(1, 2).unwrap(), + *b"test", + RewardsAccountOwner::ThisChain + ) + ), + hex_literal::hex!("627261700074657374b1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dc") .into(), ); assert_eq!( - PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( - LaneId([0, 0, 0, 1]), - *b"test", - RewardsAccountOwner::ThisChain - )), - hex_literal::hex!("62726170000000017465737400726577617264732d6163636f756e7400000000") + PayRewardFromAccount::<(), H256, HashedLaneId>::rewards_account( + RewardsAccountParams::new( + HashedLaneId::try_new(1, 3).unwrap(), + *b"test", + RewardsAccountOwner::ThisChain + ) + ), + hex_literal::hex!("627261700074657374a43e8951aa302c133beb5f85821a21645f07b487270ef3") .into(), ); } @@ -184,23 +215,101 @@ mod tests { #[test] fn different_directions_are_using_different_accounts() { assert_eq!( - PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( - LaneId([0, 0, 0, 0]), - *b"test", - RewardsAccountOwner::ThisChain - )), - hex_literal::hex!("62726170000000007465737400726577617264732d6163636f756e7400000000") + PayRewardFromAccount::<(), H256, HashedLaneId>::rewards_account( + RewardsAccountParams::new( + HashedLaneId::try_new(1, 2).unwrap(), + *b"test", + RewardsAccountOwner::ThisChain + ) + ), + hex_literal::hex!("627261700074657374b1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dc") .into(), ); assert_eq!( - PayRewardFromAccount::<(), H256>::rewards_account(RewardsAccountParams::new( - LaneId([0, 0, 0, 0]), - *b"test", - RewardsAccountOwner::BridgedChain - )), - hex_literal::hex!("62726170000000007465737401726577617264732d6163636f756e7400000000") + PayRewardFromAccount::<(), H256, HashedLaneId>::rewards_account( + RewardsAccountParams::new( + HashedLaneId::try_new(1, 2).unwrap(), + *b"test", + RewardsAccountOwner::BridgedChain + ) + ), + hex_literal::hex!("627261700174657374b1d3dccd8b3c3a012afe265f3e3c4432129b8aee50c9dc") .into(), ); } + + #[test] + fn pay_reward_from_account_for_legacy_lane_id_works() { + let test_data = vec![ + // Note: these accounts are used for integration tests within + // `bridges_rococo_westend.sh` + ( + LegacyLaneId([0, 0, 0, 1]), + b"bhks", + RewardsAccountOwner::ThisChain, + (0_u16, "13E5fui97x6KTwNnSjaEKZ8s7kJNot5F3aUsy3jUtuoMyUec"), + ), + ( + LegacyLaneId([0, 0, 0, 1]), + b"bhks", + RewardsAccountOwner::BridgedChain, + (0_u16, "13E5fui9Ka9Vz4JbGN3xWjmwDNxnxF1N9Hhhbeu3VCqLChuj"), + ), + ( + LegacyLaneId([0, 0, 0, 1]), + b"bhpd", + RewardsAccountOwner::ThisChain, + (2_u16, "EoQBtnwtXqnSnr9cgBEJpKU7NjeC9EnR4D1VjgcvHz9ZYmS"), + ), + ( + LegacyLaneId([0, 0, 0, 1]), + b"bhpd", + RewardsAccountOwner::BridgedChain, + (2_u16, "EoQBtnx69txxumxSJexVzxYD1Q4LWAuWmRq8LrBWb27nhYN"), + ), + // Note: these accounts are used for integration tests within + // `bridges_polkadot_kusama.sh` from fellows. + ( + LegacyLaneId([0, 0, 0, 2]), + b"bhwd", + RewardsAccountOwner::ThisChain, + (4_u16, "SNihsskf7bFhnHH9HJFMjWD3FJ96ESdAQTFZUAtXudRQbaH"), + ), + ( + LegacyLaneId([0, 0, 0, 2]), + b"bhwd", + RewardsAccountOwner::BridgedChain, + (4_u16, "SNihsskrjeSDuD5xumyYv9H8sxZEbNkG7g5C5LT8CfPdaSE"), + ), + ( + LegacyLaneId([0, 0, 0, 2]), + b"bhro", + RewardsAccountOwner::ThisChain, + (4_u16, "SNihsskf7bF2vWogkC6uFoiqPhd3dUX6TGzYZ1ocJdo3xHp"), + ), + ( + LegacyLaneId([0, 0, 0, 2]), + b"bhro", + RewardsAccountOwner::BridgedChain, + (4_u16, "SNihsskrjeRZ3ScWNfq6SSnw2N3BzQeCAVpBABNCbfmHENB"), + ), + ]; + + for (lane_id, bridged_chain_id, owner, (expected_ss58, expected_account)) in test_data { + assert_eq!( + expected_account, + sp_runtime::AccountId32::new(PayRewardFromAccount::< + [u8; 32], + [u8; 32], + LegacyLaneId, + >::rewards_account(RewardsAccountParams::new( + lane_id, + *bridged_chain_id, + owner + ))) + .to_ss58check_with_version(expected_ss58.into()) + ); + } + } } diff --git a/bridges/primitives/relayers/src/registration.rs b/bridges/primitives/relayers/src/registration.rs index 9d9b7e481220..d74ef18cf706 100644 --- a/bridges/primitives/relayers/src/registration.rs +++ b/bridges/primitives/relayers/src/registration.rs @@ -48,15 +48,17 @@ use sp_runtime::{ /// Either explicit account reference or `RewardsAccountParams`. #[derive(Clone, Debug)] -pub enum ExplicitOrAccountParams { +pub enum ExplicitOrAccountParams { /// Explicit account reference. Explicit(AccountId), /// Account, referenced using `RewardsAccountParams`. - Params(RewardsAccountParams), + Params(RewardsAccountParams), } -impl From for ExplicitOrAccountParams { - fn from(params: RewardsAccountParams) -> Self { +impl From> + for ExplicitOrAccountParams +{ + fn from(params: RewardsAccountParams) -> Self { ExplicitOrAccountParams::Params(params) } } @@ -103,9 +105,9 @@ pub trait StakeAndSlash { /// `beneficiary`. /// /// Returns `Ok(_)` with non-zero balance if we have failed to repatriate some portion of stake. - fn repatriate_reserved( + fn repatriate_reserved( relayer: &AccountId, - beneficiary: ExplicitOrAccountParams, + beneficiary: ExplicitOrAccountParams, amount: Balance, ) -> Result; } @@ -126,9 +128,9 @@ where Zero::zero() } - fn repatriate_reserved( + fn repatriate_reserved( _relayer: &AccountId, - _beneficiary: ExplicitOrAccountParams, + _beneficiary: ExplicitOrAccountParams, _amount: Balance, ) -> Result { Ok(Zero::zero()) diff --git a/bridges/primitives/runtime/Cargo.toml b/bridges/primitives/runtime/Cargo.toml index 117409b37b94..7528f2e5d6ca 100644 --- a/bridges/primitives/runtime/Cargo.toml +++ b/bridges/primitives/runtime/Cargo.toml @@ -20,7 +20,6 @@ scale-info = { features = ["derive"], workspace = true } serde = { features = ["alloc", "derive"], workspace = true } # Substrate Dependencies - frame-support = { workspace = true } frame-system = { workspace = true } sp-core = { workspace = true } diff --git a/bridges/primitives/runtime/src/chain.rs b/bridges/primitives/runtime/src/chain.rs index 0db4eac79a75..eba3bcadfead 100644 --- a/bridges/primitives/runtime/src/chain.rs +++ b/bridges/primitives/runtime/src/chain.rs @@ -365,17 +365,23 @@ macro_rules! decl_bridge_finality_runtime_apis { }; } +// Re-export to avoid include tuplex dependency everywhere. +#[doc(hidden)] +pub mod __private { + pub use codec; +} + /// Convenience macro that declares bridge messages runtime apis and related constants for a chain. /// This includes: /// - chain-specific bridge runtime APIs: -/// - `ToOutboundLaneApi` -/// - `FromInboundLaneApi` +/// - `ToOutboundLaneApi` +/// - `FromInboundLaneApi` /// - constants that are stringified names of runtime API methods: /// - `FROM__MESSAGE_DETAILS_METHOD`, /// The name of the chain has to be specified in snake case (e.g. `bridge_hub_polkadot`). #[macro_export] macro_rules! decl_bridge_messages_runtime_apis { - ($chain: ident) => { + ($chain: ident, $lane_id_type:ty) => { bp_runtime::paste::item! { mod [<$chain _messages_api>] { use super::*; @@ -400,7 +406,7 @@ macro_rules! decl_bridge_messages_runtime_apis { /// If some (or all) messages are missing from the storage, they'll also will /// be missing from the resulting vector. The vector is ordered by the nonce. fn message_details( - lane: bp_messages::LaneId, + lane: $lane_id_type, begin: bp_messages::MessageNonce, end: bp_messages::MessageNonce, ) -> sp_std::vec::Vec; @@ -416,7 +422,7 @@ macro_rules! decl_bridge_messages_runtime_apis { pub trait [] { /// Return details of given inbound messages. fn message_details( - lane: bp_messages::LaneId, + lane: $lane_id_type, messages: sp_std::vec::Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>, ) -> sp_std::vec::Vec; } @@ -433,8 +439,8 @@ macro_rules! decl_bridge_messages_runtime_apis { /// The name of the chain has to be specified in snake case (e.g. `bridge_hub_polkadot`). #[macro_export] macro_rules! decl_bridge_runtime_apis { - ($chain: ident $(, $consensus: ident)?) => { + ($chain: ident $(, $consensus: ident, $lane_id_type:ident)?) => { bp_runtime::decl_bridge_finality_runtime_apis!($chain $(, $consensus)?); - bp_runtime::decl_bridge_messages_runtime_apis!($chain); + bp_runtime::decl_bridge_messages_runtime_apis!($chain, $lane_id_type); }; } diff --git a/bridges/primitives/runtime/src/extensions.rs b/bridges/primitives/runtime/src/extensions.rs index d896bc92efff..25553f9c7b2e 100644 --- a/bridges/primitives/runtime/src/extensions.rs +++ b/bridges/primitives/runtime/src/extensions.rs @@ -20,135 +20,131 @@ use codec::{Compact, Decode, Encode}; use impl_trait_for_tuples::impl_for_tuples; use scale_info::{StaticTypeInfo, TypeInfo}; use sp_runtime::{ - traits::{DispatchInfoOf, SignedExtension}, + impl_tx_ext_default, + traits::{Dispatchable, TransactionExtension}, transaction_validity::TransactionValidityError, }; use sp_std::{fmt::Debug, marker::PhantomData}; -/// Trait that describes some properties of a `SignedExtension` that are needed in order to send a -/// transaction to the chain. -pub trait SignedExtensionSchema: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo { +/// Trait that describes some properties of a `TransactionExtension` that are needed in order to +/// send a transaction to the chain. +pub trait TransactionExtensionSchema: + Encode + Decode + Debug + Eq + Clone + StaticTypeInfo +{ /// A type of the data encoded as part of the transaction. type Payload: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo; /// Parameters which are part of the payload used to produce transaction signature, /// but don't end up in the transaction itself (i.e. inherent part of the runtime). - type AdditionalSigned: Encode + Debug + Eq + Clone + StaticTypeInfo; + type Implicit: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo; } -impl SignedExtensionSchema for () { +impl TransactionExtensionSchema for () { type Payload = (); - type AdditionalSigned = (); + type Implicit = (); } -/// An implementation of `SignedExtensionSchema` using generic params. +/// An implementation of `TransactionExtensionSchema` using generic params. #[derive(Encode, Decode, Clone, Debug, PartialEq, Eq, TypeInfo)] -pub struct GenericSignedExtensionSchema(PhantomData<(P, S)>); +pub struct GenericTransactionExtensionSchema(PhantomData<(P, S)>); -impl SignedExtensionSchema for GenericSignedExtensionSchema +impl TransactionExtensionSchema for GenericTransactionExtensionSchema where P: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo, - S: Encode + Debug + Eq + Clone + StaticTypeInfo, + S: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo, { type Payload = P; - type AdditionalSigned = S; + type Implicit = S; } -/// The `SignedExtensionSchema` for `frame_system::CheckNonZeroSender`. -pub type CheckNonZeroSender = GenericSignedExtensionSchema<(), ()>; +/// The `TransactionExtensionSchema` for `frame_system::CheckNonZeroSender`. +pub type CheckNonZeroSender = GenericTransactionExtensionSchema<(), ()>; -/// The `SignedExtensionSchema` for `frame_system::CheckSpecVersion`. -pub type CheckSpecVersion = GenericSignedExtensionSchema<(), u32>; +/// The `TransactionExtensionSchema` for `frame_system::CheckSpecVersion`. +pub type CheckSpecVersion = GenericTransactionExtensionSchema<(), u32>; -/// The `SignedExtensionSchema` for `frame_system::CheckTxVersion`. -pub type CheckTxVersion = GenericSignedExtensionSchema<(), u32>; +/// The `TransactionExtensionSchema` for `frame_system::CheckTxVersion`. +pub type CheckTxVersion = GenericTransactionExtensionSchema<(), u32>; -/// The `SignedExtensionSchema` for `frame_system::CheckGenesis`. -pub type CheckGenesis = GenericSignedExtensionSchema<(), Hash>; +/// The `TransactionExtensionSchema` for `frame_system::CheckGenesis`. +pub type CheckGenesis = GenericTransactionExtensionSchema<(), Hash>; -/// The `SignedExtensionSchema` for `frame_system::CheckEra`. -pub type CheckEra = GenericSignedExtensionSchema; +/// The `TransactionExtensionSchema` for `frame_system::CheckEra`. +pub type CheckEra = GenericTransactionExtensionSchema; -/// The `SignedExtensionSchema` for `frame_system::CheckNonce`. -pub type CheckNonce = GenericSignedExtensionSchema, ()>; +/// The `TransactionExtensionSchema` for `frame_system::CheckNonce`. +pub type CheckNonce = GenericTransactionExtensionSchema, ()>; -/// The `SignedExtensionSchema` for `frame_system::CheckWeight`. -pub type CheckWeight = GenericSignedExtensionSchema<(), ()>; +/// The `TransactionExtensionSchema` for `frame_system::CheckWeight`. +pub type CheckWeight = GenericTransactionExtensionSchema<(), ()>; -/// The `SignedExtensionSchema` for `pallet_transaction_payment::ChargeTransactionPayment`. -pub type ChargeTransactionPayment = GenericSignedExtensionSchema, ()>; +/// The `TransactionExtensionSchema` for `pallet_transaction_payment::ChargeTransactionPayment`. +pub type ChargeTransactionPayment = + GenericTransactionExtensionSchema, ()>; -/// The `SignedExtensionSchema` for `polkadot-runtime-common::PrevalidateAttests`. -pub type PrevalidateAttests = GenericSignedExtensionSchema<(), ()>; +/// The `TransactionExtensionSchema` for `polkadot-runtime-common::PrevalidateAttests`. +pub type PrevalidateAttests = GenericTransactionExtensionSchema<(), ()>; -/// The `SignedExtensionSchema` for `BridgeRejectObsoleteHeadersAndMessages`. -pub type BridgeRejectObsoleteHeadersAndMessages = GenericSignedExtensionSchema<(), ()>; +/// The `TransactionExtensionSchema` for `BridgeRejectObsoleteHeadersAndMessages`. +pub type BridgeRejectObsoleteHeadersAndMessages = GenericTransactionExtensionSchema<(), ()>; -/// The `SignedExtensionSchema` for `RefundBridgedParachainMessages`. +/// The `TransactionExtensionSchema` for `RefundBridgedParachainMessages`. /// This schema is dedicated for `RefundBridgedParachainMessages` signed extension as /// wildcard/placeholder, which relies on the scale encoding for `()` or `((), ())`, or `((), (), /// ())` is the same. So runtime can contains any kind of tuple: /// `(BridgeRefundBridgeHubRococoMessages)` /// `(BridgeRefundBridgeHubRococoMessages, BridgeRefundBridgeHubWestendMessages)` /// `(BridgeRefundParachainMessages1, ..., BridgeRefundParachainMessagesN)` -pub type RefundBridgedParachainMessagesSchema = GenericSignedExtensionSchema<(), ()>; +pub type RefundBridgedParachainMessagesSchema = GenericTransactionExtensionSchema<(), ()>; #[impl_for_tuples(1, 12)] -impl SignedExtensionSchema for Tuple { +impl TransactionExtensionSchema for Tuple { for_tuples!( type Payload = ( #( Tuple::Payload ),* ); ); - for_tuples!( type AdditionalSigned = ( #( Tuple::AdditionalSigned ),* ); ); + for_tuples!( type Implicit = ( #( Tuple::Implicit ),* ); ); } /// A simplified version of signed extensions meant for producing signed transactions /// and signed payloads in the client code. #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] -pub struct GenericSignedExtension { +pub struct GenericTransactionExtension { /// A payload that is included in the transaction. pub payload: S::Payload, #[codec(skip)] // It may be set to `None` if extensions are decoded. We are never reconstructing transactions - // (and it makes no sense to do that) => decoded version of `SignedExtensions` is only used to - // read fields of the `payload`. And when resigning transaction, we're reconstructing - // `SignedExtensions` from scratch. - additional_signed: Option, + // (and it makes no sense to do that) => decoded version of `TransactionExtensions` is only + // used to read fields of the `payload`. And when resigning transaction, we're reconstructing + // `TransactionExtensions` from scratch. + implicit: Option, } -impl GenericSignedExtension { - /// Create new `GenericSignedExtension` object. - pub fn new(payload: S::Payload, additional_signed: Option) -> Self { - Self { payload, additional_signed } +impl GenericTransactionExtension { + /// Create new `GenericTransactionExtension` object. + pub fn new(payload: S::Payload, implicit: Option) -> Self { + Self { payload, implicit } } } -impl SignedExtension for GenericSignedExtension +impl TransactionExtension for GenericTransactionExtension where - S: SignedExtensionSchema, + C: Dispatchable, + S: TransactionExtensionSchema, S::Payload: Send + Sync, - S::AdditionalSigned: Send + Sync, + S::Implicit: Send + Sync, { const IDENTIFIER: &'static str = "Not needed."; - type AccountId = (); - type Call = (); - type AdditionalSigned = S::AdditionalSigned; - type Pre = (); + type Implicit = S::Implicit; - fn additional_signed(&self) -> Result { + fn implicit(&self) -> Result { // we shall not ever see this error in relay, because we are never signing decoded // transactions. Instead we're constructing and signing new transactions. So the error code // is kinda random here - self.additional_signed.clone().ok_or( - frame_support::unsigned::TransactionValidityError::Unknown( + self.implicit + .clone() + .ok_or(frame_support::unsigned::TransactionValidityError::Unknown( frame_support::unsigned::UnknownTransaction::Custom(0xFF), - ), - ) + )) } + type Pre = (); + type Val = (); - fn pre_dispatch( - self, - _who: &Self::AccountId, - _call: &Self::Call, - _info: &DispatchInfoOf, - _len: usize, - ) -> Result { - Ok(()) - } + impl_tx_ext_default!(C; weight validate prepare); } diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index 8f5040ad9a1b..90eb72922bea 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -36,7 +36,7 @@ use sp_std::{fmt::Debug, ops::RangeInclusive, vec, vec::Vec}; pub use chain::{ AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain, EncodedOrDecodedCall, HashOf, HasherOf, HeaderOf, NonceOf, Parachain, ParachainIdOf, SignatureOf, TransactionEraOf, - UnderlyingChainOf, UnderlyingChainProvider, + UnderlyingChainOf, UnderlyingChainProvider, __private, }; pub use frame_support::storage::storage_prefix as storage_value_final_key; use num_traits::{CheckedAdd, CheckedSub, One, SaturatingAdd, Zero}; @@ -272,7 +272,7 @@ pub trait StorageMapKeyProvider { } } -/// Can be use to access the runtime storage key of a `StorageDoubleMap`. +/// Can be used to access the runtime storage key of a `StorageDoubleMap`. pub trait StorageDoubleMapKeyProvider { /// The name of the variable that holds the `StorageDoubleMap`. const MAP_NAME: &'static str; diff --git a/bridges/primitives/runtime/src/storage_proof.rs b/bridges/primitives/runtime/src/storage_proof.rs index 7bfa0d6fde01..8bd9001f2b6c 100644 --- a/bridges/primitives/runtime/src/storage_proof.rs +++ b/bridges/primitives/runtime/src/storage_proof.rs @@ -18,7 +18,7 @@ use frame_support::PalletError; use sp_core::RuntimeDebug; -use sp_std::{default::Default, vec::Vec}; +use sp_std::vec::Vec; use sp_trie::{ accessed_nodes_tracker::AccessedNodesTracker, read_trie_value, LayoutV1, MemoryDB, StorageProof, }; @@ -280,7 +280,7 @@ where /// Return valid storage proof and state root. /// -/// NOTE: This should only be used for **testing**. +/// Note: This should only be used for **testing**. #[cfg(feature = "std")] pub fn craft_valid_storage_proof() -> (sp_core::H256, RawStorageProof) { use sp_state_machine::{backend::Backend, prove_read, InMemoryBackend}; diff --git a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml index c3cf3356184b..ba0c51152bd2 100644 --- a/bridges/primitives/xcm-bridge-hub-router/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub-router/Cargo.toml @@ -18,6 +18,15 @@ scale-info = { features = ["bit-vec", "derive"], workspace = true } sp-runtime = { workspace = true } sp-core = { workspace = true } +# Polkadot Dependencies +xcm = { workspace = true } + [features] default = ["std"] -std = ["codec/std", "scale-info/std", "sp-core/std", "sp-runtime/std"] +std = [ + "codec/std", + "scale-info/std", + "sp-core/std", + "sp-runtime/std", + "xcm/std", +] diff --git a/bridges/primitives/xcm-bridge-hub-router/src/lib.rs b/bridges/primitives/xcm-bridge-hub-router/src/lib.rs index dbedb7a52c7f..89123b51ef2f 100644 --- a/bridges/primitives/xcm-bridge-hub-router/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub-router/src/lib.rs @@ -22,6 +22,7 @@ use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_core::H256; use sp_runtime::{FixedU128, RuntimeDebug}; +use xcm::latest::prelude::Location; /// Minimal delivery fee factor. pub const MINIMAL_DELIVERY_FEE_FACTOR: FixedU128 = FixedU128::from_u32(1); @@ -32,11 +33,11 @@ pub const MINIMAL_DELIVERY_FEE_FACTOR: FixedU128 = FixedU128::from_u32(1); /// of the bridge queues. pub trait XcmChannelStatusProvider { /// Returns true if the channel is currently congested. - fn is_congested() -> bool; + fn is_congested(with: &Location) -> bool; } impl XcmChannelStatusProvider for () { - fn is_congested() -> bool { + fn is_congested(_with: &Location) -> bool { false } } diff --git a/bridges/primitives/xcm-bridge-hub/Cargo.toml b/bridges/primitives/xcm-bridge-hub/Cargo.toml index 932e9ade0197..79201a8756f9 100644 --- a/bridges/primitives/xcm-bridge-hub/Cargo.toml +++ b/bridges/primitives/xcm-bridge-hub/Cargo.toml @@ -11,10 +11,34 @@ repository.workspace = true workspace = true [dependencies] +codec = { features = ["derive"], workspace = true } +scale-info = { features = ["derive"], workspace = true } +serde = { features = ["alloc", "derive"], workspace = true } + +# Bridge Dependencies +bp-messages = { workspace = true } +bp-runtime = { workspace = true } # Substrate Dependencies sp-std = { workspace = true } +sp-io = { workspace = true } +sp-core = { workspace = true } +frame-support = { workspace = true } + +# Polkadot Dependencies +xcm = { workspace = true } [features] default = ["std"] -std = ["sp-std/std"] +std = [ + "bp-messages/std", + "bp-runtime/std", + "codec/std", + "frame-support/std", + "scale-info/std", + "serde/std", + "sp-core/std", + "sp-io/std", + "sp-std/std", + "xcm/std", +] diff --git a/bridges/primitives/xcm-bridge-hub/src/call_info.rs b/bridges/primitives/xcm-bridge-hub/src/call_info.rs new file mode 100644 index 000000000000..fd4fc67822fe --- /dev/null +++ b/bridges/primitives/xcm-bridge-hub/src/call_info.rs @@ -0,0 +1,43 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Parity Bridges Common. + +// Parity Bridges Common is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity Bridges Common is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity Bridges Common. If not, see . + +//! Defines structures related to calls of the `pallet-xcm-bridge-hub` pallet. + +use bp_messages::MessageNonce; +use codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_std::boxed::Box; +use xcm::prelude::VersionedInteriorLocation; + +/// A minimized version of `pallet_xcm_bridge_hub::Call` that can be used without a runtime. +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +#[allow(non_camel_case_types)] +pub enum XcmBridgeHubCall { + /// `pallet_xcm_bridge_hub::Call::open_bridge` + #[codec(index = 0)] + open_bridge { + /// Universal `InteriorLocation` from the bridged consensus. + bridge_destination_universal_location: Box, + }, + /// `pallet_xcm_bridge_hub::Call::close_bridge` + #[codec(index = 1)] + close_bridge { + /// Universal `InteriorLocation` from the bridged consensus. + bridge_destination_universal_location: Box, + /// The number of messages that we may prune in a single call. + may_prune_messages: MessageNonce, + }, +} diff --git a/bridges/primitives/xcm-bridge-hub/src/lib.rs b/bridges/primitives/xcm-bridge-hub/src/lib.rs index 9745011c902d..061e7a275063 100644 --- a/bridges/primitives/xcm-bridge-hub/src/lib.rs +++ b/bridges/primitives/xcm-bridge-hub/src/lib.rs @@ -19,6 +19,688 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] +use bp_messages::LaneIdType; +use bp_runtime::{AccountIdOf, BalanceOf, Chain}; +pub use call_info::XcmBridgeHubCall; +use codec::{Decode, Encode, MaxEncodedLen}; +use frame_support::{ + ensure, sp_runtime::RuntimeDebug, CloneNoBound, PalletError, PartialEqNoBound, + RuntimeDebugNoBound, +}; +use scale_info::TypeInfo; +use serde::{Deserialize, Serialize}; +use sp_core::H256; +use sp_io::hashing::blake2_256; +use sp_std::boxed::Box; +use xcm::{ + latest::prelude::*, prelude::XcmVersion, IntoVersion, VersionedInteriorLocation, + VersionedLocation, +}; + +mod call_info; + /// Encoded XCM blob. We expect the bridge messages pallet to use this blob type for both inbound /// and outbound payloads. pub type XcmAsPlainPayload = sp_std::vec::Vec; + +/// Bridge identifier - used **only** for communicating with sibling/parent chains in the same +/// consensus. +/// +/// For example, `SendXcm` implementations (which use the `latest` XCM) can use it to identify a +/// bridge and the corresponding `LaneId` that is used for over-consensus communication between +/// bridge hubs. +/// +/// This identifier is constructed from the `latest` XCM, so it is expected to ensure migration to +/// the `latest` XCM version. This could change the `BridgeId`, but it will not affect the `LaneId`. +/// In other words, `LaneId` will never change, while `BridgeId` could change with (every) XCM +/// upgrade. +#[derive( + Clone, + Copy, + Decode, + Encode, + Eq, + Ord, + PartialOrd, + PartialEq, + TypeInfo, + MaxEncodedLen, + Serialize, + Deserialize, +)] +pub struct BridgeId(H256); + +impl BridgeId { + /// Create bridge identifier from two universal locations. + /// + /// Note: The `BridgeId` is constructed from `latest` XCM, so if stored, you need to ensure + /// compatibility with newer XCM versions. + pub fn new( + universal_source: &InteriorLocation, + universal_destination: &InteriorLocation, + ) -> Self { + const VALUES_SEPARATOR: [u8; 33] = *b"bridges-bridge-id-value-separator"; + + BridgeId( + (universal_source, VALUES_SEPARATOR, universal_destination) + .using_encoded(blake2_256) + .into(), + ) + } +} + +impl core::fmt::Debug for BridgeId { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Debug::fmt(&self.0, f) + } +} + +/// Local XCM channel manager. +pub trait LocalXcmChannelManager { + /// Error that may be returned when suspending/resuming the bridge. + type Error: sp_std::fmt::Debug; + + /// Returns true if the channel with given location is currently congested. + /// + /// The `with` is guaranteed to be in the same consensus. However, it may point to something + /// below the chain level - like the contract or pallet instance, for example. + fn is_congested(with: &Location) -> bool; + + /// Suspend the bridge, opened by given origin. + /// + /// The `local_origin` is guaranteed to be in the same consensus. However, it may point to + /// something below the chain level - like the contract or pallet instance, for example. + fn suspend_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error>; + + /// Resume the previously suspended bridge, opened by given origin. + /// + /// The `local_origin` is guaranteed to be in the same consensus. However, it may point to + /// something below the chain level - like the contract or pallet instance, for example. + fn resume_bridge(local_origin: &Location, bridge: BridgeId) -> Result<(), Self::Error>; +} + +impl LocalXcmChannelManager for () { + type Error = (); + + fn is_congested(_with: &Location) -> bool { + false + } + + fn suspend_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { + Ok(()) + } + + fn resume_bridge(_local_origin: &Location, _bridge: BridgeId) -> Result<(), Self::Error> { + Ok(()) + } +} + +/// Bridge state. +#[derive(Clone, Copy, Decode, Encode, Eq, PartialEq, TypeInfo, MaxEncodedLen, RuntimeDebug)] +pub enum BridgeState { + /// Bridge is opened. Associated lanes are also opened. + Opened, + /// Bridge is suspended. Associated lanes are opened. + /// + /// We keep accepting messages to the bridge. The only difference with the `Opened` state + /// is that we have sent the "Suspended" message/signal to the local bridge origin. + Suspended, + /// Bridge is closed. Associated lanes are also closed. + /// After all outbound messages will be pruned, the bridge will vanish without any traces. + Closed, +} + +/// Bridge metadata. +#[derive( + CloneNoBound, Decode, Encode, Eq, PartialEqNoBound, TypeInfo, MaxEncodedLen, RuntimeDebugNoBound, +)] +#[scale_info(skip_type_params(ThisChain, LaneId))] +pub struct Bridge { + /// Relative location of the bridge origin chain. This is expected to be **convertible** to the + /// `latest` XCM, so the check and migration needs to be ensured. + pub bridge_origin_relative_location: Box, + + /// See [`BridgeLocations::bridge_origin_universal_location`]. + /// Stored for `BridgeId` sanity check. + pub bridge_origin_universal_location: Box, + /// See [`BridgeLocations::bridge_destination_universal_location`]. + /// Stored for `BridgeId` sanity check. + pub bridge_destination_universal_location: Box, + + /// Current bridge state. + pub state: BridgeState, + /// Account with the reserved funds. Derived from `self.bridge_origin_relative_location`. + pub bridge_owner_account: AccountIdOf, + /// Reserved amount on the sovereign account of the sibling bridge origin. + pub deposit: BalanceOf, + + /// Mapping to the unique `LaneId`. + pub lane_id: LaneId, +} + +/// Locations of bridge endpoints at both sides of the bridge. +#[derive(Clone, RuntimeDebug, PartialEq, Eq)] +pub struct BridgeLocations { + /// Relative (to this bridge hub) location of this side of the bridge. + bridge_origin_relative_location: Location, + /// Universal (unique) location of this side of the bridge. + bridge_origin_universal_location: InteriorLocation, + /// Universal (unique) location of other side of the bridge. + bridge_destination_universal_location: InteriorLocation, + /// An identifier of the dedicated bridge message lane. + bridge_id: BridgeId, +} + +/// Errors that may happen when we check bridge locations. +#[derive(Encode, Decode, RuntimeDebug, PartialEq, Eq, PalletError, TypeInfo)] +pub enum BridgeLocationsError { + /// Origin or destination locations are not universal. + NonUniversalLocation, + /// Bridge origin location is not supported. + InvalidBridgeOrigin, + /// Bridge destination is not supported (in general). + InvalidBridgeDestination, + /// Destination location is within the same global consensus. + DestinationIsLocal, + /// Destination network is not the network we are bridged with. + UnreachableDestination, + /// Destination location is unsupported. We only support bridges with relay + /// chain or its parachains. + UnsupportedDestinationLocation, + /// The version of XCM location argument is unsupported. + UnsupportedXcmVersion, + /// The `LaneIdType` generator is not supported. + UnsupportedLaneIdType, +} + +impl BridgeLocations { + /// Given XCM locations, generate lane id and universal locations of bridge endpoints. + /// + /// The `here_universal_location` is the universal location of the bridge hub runtime. + /// + /// The `bridge_origin_relative_location` is the relative (to the `here_universal_location`) + /// location of the bridge endpoint at this side of the bridge. It may be the parent relay + /// chain or the sibling parachain. All junctions below parachain level are dropped. + /// + /// The `bridge_destination_universal_location` is the universal location of the bridge + /// destination. It may be the parent relay or the sibling parachain of the **bridged** + /// bridge hub. All junctions below parachain level are dropped. + /// + /// Why we drop all junctions between parachain level - that's because the lane is a bridge + /// between two chains. All routing under this level happens when the message is delivered + /// to the bridge destination. So at bridge level we don't care about low level junctions. + /// + /// Returns error if `bridge_origin_relative_location` is outside of `here_universal_location` + /// local consensus OR if `bridge_destination_universal_location` is not a universal location. + pub fn bridge_locations( + here_universal_location: InteriorLocation, + bridge_origin_relative_location: Location, + bridge_destination_universal_location: InteriorLocation, + expected_remote_network: NetworkId, + ) -> Result, BridgeLocationsError> { + fn strip_low_level_junctions( + location: InteriorLocation, + ) -> Result { + let mut junctions = location.into_iter(); + + let global_consensus = junctions + .next() + .filter(|junction| matches!(junction, GlobalConsensus(_))) + .ok_or(BridgeLocationsError::NonUniversalLocation)?; + + // we only expect `Parachain` junction here. There are other junctions that + // may need to be supported (like `GeneralKey` and `OnlyChild`), but now we + // only support bridges with relay and parachans + // + // if there's something other than parachain, let's strip it + let maybe_parachain = + junctions.next().filter(|junction| matches!(junction, Parachain(_))); + Ok(match maybe_parachain { + Some(parachain) => [global_consensus, parachain].into(), + None => [global_consensus].into(), + }) + } + + // ensure that the `here_universal_location` and `bridge_destination_universal_location` + // are universal locations within different consensus systems + let local_network = here_universal_location + .global_consensus() + .map_err(|_| BridgeLocationsError::NonUniversalLocation)?; + let remote_network = bridge_destination_universal_location + .global_consensus() + .map_err(|_| BridgeLocationsError::NonUniversalLocation)?; + ensure!(local_network != remote_network, BridgeLocationsError::DestinationIsLocal); + ensure!( + remote_network == expected_remote_network, + BridgeLocationsError::UnreachableDestination + ); + + // get universal location of endpoint, located at this side of the bridge + let bridge_origin_universal_location = here_universal_location + .within_global(bridge_origin_relative_location.clone()) + .map_err(|_| BridgeLocationsError::InvalidBridgeOrigin)?; + // strip low-level junctions within universal locations + let bridge_origin_universal_location = + strip_low_level_junctions(bridge_origin_universal_location)?; + let bridge_destination_universal_location = + strip_low_level_junctions(bridge_destination_universal_location)?; + + // we know that the `bridge_destination_universal_location` starts from the + // `GlobalConsensus` and we know that the `bridge_origin_universal_location` + // is also within the `GlobalConsensus`. So we know that the lane id will be + // the same on both ends of the bridge + let bridge_id = BridgeId::new( + &bridge_origin_universal_location, + &bridge_destination_universal_location, + ); + + Ok(Box::new(BridgeLocations { + bridge_origin_relative_location, + bridge_origin_universal_location, + bridge_destination_universal_location, + bridge_id, + })) + } + + /// Getter for `bridge_origin_relative_location` + pub fn bridge_origin_relative_location(&self) -> &Location { + &self.bridge_origin_relative_location + } + + /// Getter for `bridge_origin_universal_location` + pub fn bridge_origin_universal_location(&self) -> &InteriorLocation { + &self.bridge_origin_universal_location + } + + /// Getter for `bridge_destination_universal_location` + pub fn bridge_destination_universal_location(&self) -> &InteriorLocation { + &self.bridge_destination_universal_location + } + + /// Getter for `bridge_id` + pub fn bridge_id(&self) -> &BridgeId { + &self.bridge_id + } + + /// Generates the exact same `LaneId` on the both bridge hubs. + /// + /// Note: Use this **only** when opening a new bridge. + pub fn calculate_lane_id( + &self, + xcm_version: XcmVersion, + ) -> Result { + // a tricky helper struct that adds required `Ord` support for + // `VersionedInteriorLocation` + #[derive(Eq, PartialEq, Ord, PartialOrd)] + struct EncodedVersionedInteriorLocation(sp_std::vec::Vec); + impl Encode for EncodedVersionedInteriorLocation { + fn encode(&self) -> sp_std::vec::Vec { + self.0.clone() + } + } + + let universal_location1 = + VersionedInteriorLocation::from(self.bridge_origin_universal_location.clone()) + .into_version(xcm_version) + .map_err(|_| BridgeLocationsError::UnsupportedXcmVersion); + let universal_location2 = + VersionedInteriorLocation::from(self.bridge_destination_universal_location.clone()) + .into_version(xcm_version) + .map_err(|_| BridgeLocationsError::UnsupportedXcmVersion); + + LaneId::try_new( + EncodedVersionedInteriorLocation(universal_location1.encode()), + EncodedVersionedInteriorLocation(universal_location2.encode()), + ) + .map_err(|_| BridgeLocationsError::UnsupportedLaneIdType) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const LOCAL_NETWORK: NetworkId = Kusama; + const REMOTE_NETWORK: NetworkId = Polkadot; + const UNREACHABLE_NETWORK: NetworkId = Rococo; + const SIBLING_PARACHAIN: u32 = 1000; + const LOCAL_BRIDGE_HUB: u32 = 1001; + const REMOTE_PARACHAIN: u32 = 2000; + + struct SuccessfulTest { + here_universal_location: InteriorLocation, + bridge_origin_relative_location: Location, + + bridge_origin_universal_location: InteriorLocation, + bridge_destination_universal_location: InteriorLocation, + + expected_remote_network: NetworkId, + } + + fn run_successful_test(test: SuccessfulTest) -> BridgeLocations { + let locations = BridgeLocations::bridge_locations( + test.here_universal_location, + test.bridge_origin_relative_location.clone(), + test.bridge_destination_universal_location.clone(), + test.expected_remote_network, + ); + assert_eq!( + locations, + Ok(Box::new(BridgeLocations { + bridge_origin_relative_location: test.bridge_origin_relative_location, + bridge_origin_universal_location: test.bridge_origin_universal_location.clone(), + bridge_destination_universal_location: test + .bridge_destination_universal_location + .clone(), + bridge_id: BridgeId::new( + &test.bridge_origin_universal_location, + &test.bridge_destination_universal_location, + ), + })), + ); + + *locations.unwrap() + } + + // successful tests that with various origins and destinations + + #[test] + fn at_relay_from_local_relay_to_remote_relay_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: Here.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, + }); + } + + #[test] + fn at_relay_from_sibling_parachain_to_remote_relay_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: [Parachain(SIBLING_PARACHAIN)].into(), + + bridge_origin_universal_location: [ + GlobalConsensus(LOCAL_NETWORK), + Parachain(SIBLING_PARACHAIN), + ] + .into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, + }); + } + + #[test] + fn at_relay_from_local_relay_to_remote_parachain_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: Here.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [ + GlobalConsensus(REMOTE_NETWORK), + Parachain(REMOTE_PARACHAIN), + ] + .into(), + + expected_remote_network: REMOTE_NETWORK, + }); + } + + #[test] + fn at_relay_from_sibling_parachain_to_remote_parachain_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: [Parachain(SIBLING_PARACHAIN)].into(), + + bridge_origin_universal_location: [ + GlobalConsensus(LOCAL_NETWORK), + Parachain(SIBLING_PARACHAIN), + ] + .into(), + bridge_destination_universal_location: [ + GlobalConsensus(REMOTE_NETWORK), + Parachain(REMOTE_PARACHAIN), + ] + .into(), + + expected_remote_network: REMOTE_NETWORK, + }); + } + + #[test] + fn at_bridge_hub_from_local_relay_to_remote_relay_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)] + .into(), + bridge_origin_relative_location: Parent.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, + }); + } + + #[test] + fn at_bridge_hub_from_sibling_parachain_to_remote_relay_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)] + .into(), + bridge_origin_relative_location: ParentThen([Parachain(SIBLING_PARACHAIN)].into()) + .into(), + + bridge_origin_universal_location: [ + GlobalConsensus(LOCAL_NETWORK), + Parachain(SIBLING_PARACHAIN), + ] + .into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, + }); + } + + #[test] + fn at_bridge_hub_from_local_relay_to_remote_parachain_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)] + .into(), + bridge_origin_relative_location: Parent.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [ + GlobalConsensus(REMOTE_NETWORK), + Parachain(REMOTE_PARACHAIN), + ] + .into(), + + expected_remote_network: REMOTE_NETWORK, + }); + } + + #[test] + fn at_bridge_hub_from_sibling_parachain_to_remote_parachain_works() { + run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)] + .into(), + bridge_origin_relative_location: ParentThen([Parachain(SIBLING_PARACHAIN)].into()) + .into(), + + bridge_origin_universal_location: [ + GlobalConsensus(LOCAL_NETWORK), + Parachain(SIBLING_PARACHAIN), + ] + .into(), + bridge_destination_universal_location: [ + GlobalConsensus(REMOTE_NETWORK), + Parachain(REMOTE_PARACHAIN), + ] + .into(), + + expected_remote_network: REMOTE_NETWORK, + }); + } + + // successful tests that show that we are ignoring low-level junctions of bridge origins + + #[test] + fn low_level_junctions_at_bridge_origin_are_stripped() { + let locations1 = run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: Here.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, + }); + let locations2 = run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: [PalletInstance(0)].into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, + }); + + assert_eq!(locations1.bridge_id, locations2.bridge_id); + } + + #[test] + fn low_level_junctions_at_bridge_destination_are_stripped() { + let locations1 = run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: Here.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, + }); + let locations2 = run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_origin_relative_location: Here.into(), + + bridge_origin_universal_location: [GlobalConsensus(LOCAL_NETWORK)].into(), + bridge_destination_universal_location: [GlobalConsensus(REMOTE_NETWORK)].into(), + + expected_remote_network: REMOTE_NETWORK, + }); + + assert_eq!(locations1.bridge_id, locations2.bridge_id); + } + + #[test] + fn calculate_lane_id_works() { + type TestLaneId = bp_messages::HashedLaneId; + + let from_local_to_remote = run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(LOCAL_NETWORK), Parachain(LOCAL_BRIDGE_HUB)] + .into(), + bridge_origin_relative_location: ParentThen([Parachain(SIBLING_PARACHAIN)].into()) + .into(), + + bridge_origin_universal_location: [ + GlobalConsensus(LOCAL_NETWORK), + Parachain(SIBLING_PARACHAIN), + ] + .into(), + bridge_destination_universal_location: [ + GlobalConsensus(REMOTE_NETWORK), + Parachain(REMOTE_PARACHAIN), + ] + .into(), + + expected_remote_network: REMOTE_NETWORK, + }); + + let from_remote_to_local = run_successful_test(SuccessfulTest { + here_universal_location: [GlobalConsensus(REMOTE_NETWORK), Parachain(LOCAL_BRIDGE_HUB)] + .into(), + bridge_origin_relative_location: ParentThen([Parachain(REMOTE_PARACHAIN)].into()) + .into(), + + bridge_origin_universal_location: [ + GlobalConsensus(REMOTE_NETWORK), + Parachain(REMOTE_PARACHAIN), + ] + .into(), + bridge_destination_universal_location: [ + GlobalConsensus(LOCAL_NETWORK), + Parachain(SIBLING_PARACHAIN), + ] + .into(), + + expected_remote_network: LOCAL_NETWORK, + }); + + assert_ne!( + from_local_to_remote.calculate_lane_id::(xcm::latest::VERSION), + from_remote_to_local.calculate_lane_id::(xcm::latest::VERSION - 1), + ); + assert_eq!( + from_local_to_remote.calculate_lane_id::(xcm::latest::VERSION), + from_remote_to_local.calculate_lane_id::(xcm::latest::VERSION), + ); + } + + // negative tests + + #[test] + fn bridge_locations_fails_when_here_is_not_universal_location() { + assert_eq!( + BridgeLocations::bridge_locations( + [Parachain(1000)].into(), + Here.into(), + [GlobalConsensus(REMOTE_NETWORK)].into(), + REMOTE_NETWORK, + ), + Err(BridgeLocationsError::NonUniversalLocation), + ); + } + + #[test] + fn bridge_locations_fails_when_computed_destination_is_not_universal_location() { + assert_eq!( + BridgeLocations::bridge_locations( + [GlobalConsensus(LOCAL_NETWORK)].into(), + Here.into(), + [OnlyChild].into(), + REMOTE_NETWORK, + ), + Err(BridgeLocationsError::NonUniversalLocation), + ); + } + + #[test] + fn bridge_locations_fails_when_computed_destination_is_local() { + assert_eq!( + BridgeLocations::bridge_locations( + [GlobalConsensus(LOCAL_NETWORK)].into(), + Here.into(), + [GlobalConsensus(LOCAL_NETWORK), OnlyChild].into(), + REMOTE_NETWORK, + ), + Err(BridgeLocationsError::DestinationIsLocal), + ); + } + + #[test] + fn bridge_locations_fails_when_computed_destination_is_unreachable() { + assert_eq!( + BridgeLocations::bridge_locations( + [GlobalConsensus(LOCAL_NETWORK)].into(), + Here.into(), + [GlobalConsensus(UNREACHABLE_NETWORK)].into(), + REMOTE_NETWORK, + ), + Err(BridgeLocationsError::UnreachableDestination), + ); + } +} diff --git a/bridges/relays/client-substrate/Cargo.toml b/bridges/relays/client-substrate/Cargo.toml index 969cd73d6194..6065c23773e3 100644 --- a/bridges/relays/client-substrate/Cargo.toml +++ b/bridges/relays/client-substrate/Cargo.toml @@ -20,8 +20,12 @@ log = { workspace = true } num-traits = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } serde_json = { workspace = true } -scale-info = { features = ["derive"], workspace = true, default-features = true } -tokio = { features = ["rt-multi-thread"], workspace = true, default-features = true } +scale-info = { features = [ + "derive", +], workspace = true, default-features = true } +tokio = { features = [ + "rt-multi-thread", +], workspace = true, default-features = true } thiserror = { workspace = true } quick_cache = { workspace = true } diff --git a/bridges/relays/client-substrate/src/chain.rs b/bridges/relays/client-substrate/src/chain.rs index 227e9c31c5bf..9856f0d0237e 100644 --- a/bridges/relays/client-substrate/src/chain.rs +++ b/bridges/relays/client-substrate/src/chain.rs @@ -113,9 +113,6 @@ impl Parachain for T where T: UnderlyingChainProvider + Chain + ParachainBase /// Substrate-based chain with messaging support from minimal relay-client point of view. pub trait ChainWithMessages: Chain + ChainWithMessagesBase { - // TODO (https://github.com/paritytech/parity-bridges-common/issues/1692): check all the names - // after the issue is fixed - all names must be changed - /// Name of the bridge relayers pallet (used in `construct_runtime` macro call) that is deployed /// at some other chain to bridge with this `ChainWithMessages`. /// diff --git a/bridges/relays/lib-substrate-relay/src/cli/bridge.rs b/bridges/relays/lib-substrate-relay/src/cli/bridge.rs index 5631285b3c54..9467813f86cc 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/bridge.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/bridge.rs @@ -22,7 +22,7 @@ use crate::{ messages::{MessagesRelayLimits, SubstrateMessageLane}, parachains::SubstrateParachainsPipeline, }; -use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; +use bp_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; use relay_substrate_client::{ Chain, ChainWithRuntimeVersion, ChainWithTransactions, Parachain, RelayChain, }; @@ -108,3 +108,7 @@ pub trait MessagesCliBridge: CliBridgeBase { None } } + +/// An alias for lane identifier type. +pub type MessagesLaneIdOf = + <::MessagesLane as SubstrateMessageLane>::LaneId; diff --git a/bridges/relays/lib-substrate-relay/src/cli/mod.rs b/bridges/relays/lib-substrate-relay/src/cli/mod.rs index ddb3e416dc32..d7aa38f1f2ba 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/mod.rs @@ -16,12 +16,10 @@ //! Deal with CLI args of substrate-to-substrate relay. -use codec::{Decode, Encode}; use rbtag::BuildInfo; +use sp_runtime::traits::TryConvert; +use std::str::FromStr; use structopt::StructOpt; -use strum::{EnumString, VariantNames}; - -use bp_messages::LaneId; pub mod bridge; pub mod chain_schema; @@ -42,45 +40,19 @@ pub type DefaultClient = relay_substrate_client::RpcWithCachingClient; /// Lane id. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct HexLaneId(pub [u8; 4]); +pub struct HexLaneId(Vec); -impl From for LaneId { - fn from(lane_id: HexLaneId) -> LaneId { - LaneId(lane_id.0) +impl>> TryConvert for HexLaneId { + fn try_convert(lane_id: HexLaneId) -> Result { + T::try_from(lane_id.0.clone()).map_err(|_| lane_id) } } -impl std::str::FromStr for HexLaneId { +impl FromStr for HexLaneId { type Err = hex::FromHexError; fn from_str(s: &str) -> Result { - let mut lane_id = [0u8; 4]; - hex::decode_to_slice(s, &mut lane_id)?; - Ok(HexLaneId(lane_id)) - } -} - -/// Nicer formatting for raw bytes vectors. -#[derive(Default, Encode, Decode, PartialEq, Eq)] -pub struct HexBytes(pub Vec); - -impl std::str::FromStr for HexBytes { - type Err = hex::FromHexError; - - fn from_str(s: &str) -> Result { - Ok(Self(hex::decode(s)?)) - } -} - -impl std::fmt::Debug for HexBytes { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(fmt, "0x{self}") - } -} - -impl std::fmt::Display for HexBytes { - fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(fmt, "{}", hex::encode(&self.0)) + hex::decode(s).map(Self) } } @@ -166,31 +138,39 @@ where } } -#[doc = "Runtime version params."] -#[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy, EnumString, VariantNames)] -pub enum RuntimeVersionType { - /// Auto query version from chain - Auto, - /// Custom `spec_version` and `transaction_version` - Custom, - /// Read version from bundle dependencies directly. - Bundle, -} - #[cfg(test)] mod tests { use super::*; + use bp_messages::{HashedLaneId, LegacyLaneId}; + use sp_core::H256; #[test] - fn hex_bytes_display_matches_from_str_for_clap() { - // given - let hex = HexBytes(vec![1, 2, 3, 4]); - let display = format!("{hex}"); - - // when - let hex2: HexBytes = display.parse().unwrap(); - - // then - assert_eq!(hex.0, hex2.0); + fn hex_lane_id_from_str_works() { + // hash variant + assert!(HexLaneId::from_str( + "101010101010101010101010101010101010101010101010101010101010101" + ) + .is_err()); + assert!(HexLaneId::from_str( + "00101010101010101010101010101010101010101010101010101010101010101" + ) + .is_err()); + assert_eq!( + HexLaneId::try_convert( + HexLaneId::from_str( + "0101010101010101010101010101010101010101010101010101010101010101" + ) + .unwrap() + ), + Ok(HashedLaneId::from_inner(H256::from([1u8; 32]))) + ); + + // array variant + assert!(HexLaneId::from_str("0000001").is_err()); + assert!(HexLaneId::from_str("000000001").is_err()); + assert_eq!( + HexLaneId::try_convert(HexLaneId::from_str("00000001").unwrap()), + Ok(LegacyLaneId([0, 0, 0, 1])) + ); } } diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_headers.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_headers.rs index ea92a0c9acce..308b041c46f7 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_headers.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_headers.rs @@ -96,6 +96,7 @@ pub trait HeadersRelayer: RelayToRelayHeadersCliBridge { signer: target_sign, mortality: target_transactions_mortality, }; + Self::Finality::start_relay_guards(&target_client, target_client.can_start_version_guard()) .await?; diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs index 338dda3c6330..bb6c689a76eb 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/mod.rs @@ -31,18 +31,20 @@ pub mod relay_to_relay; pub mod relay_to_parachain; use async_trait::async_trait; -use std::{marker::PhantomData, sync::Arc}; +use std::{fmt::Debug, marker::PhantomData, sync::Arc}; use structopt::StructOpt; use futures::{FutureExt, TryFutureExt}; use crate::{ - cli::{bridge::MessagesCliBridge, DefaultClient, HexLaneId, PrometheusParams}, + cli::{ + bridge::{MessagesCliBridge, MessagesLaneIdOf}, + DefaultClient, HexLaneId, PrometheusParams, + }, messages::{MessagesRelayLimits, MessagesRelayParams}, on_demand::OnDemandRelay, HeadersToRelay, TaggedAccount, TransactionParams, }; -use bp_messages::LaneId; use bp_runtime::BalanceOf; use relay_substrate_client::{ AccountIdOf, AccountKeyPairOf, Chain, ChainWithBalances, ChainWithMessages, @@ -50,12 +52,13 @@ use relay_substrate_client::{ }; use relay_utils::metrics::MetricsParams; use sp_core::Pair; +use sp_runtime::traits::TryConvert; /// Parameters that have the same names across all bridges. #[derive(Debug, PartialEq, StructOpt)] pub struct HeadersAndMessagesSharedParams { /// Hex-encoded lane identifiers that should be served by the complex relay. - #[structopt(long, default_value = "00000000")] + #[structopt(long)] pub lane: Vec, /// If passed, only mandatory headers (headers that are changing the GRANDPA authorities set) /// are relayed. @@ -163,7 +166,7 @@ where &self, source_to_target_headers_relay: Arc>, target_to_source_headers_relay: Arc>, - lane_id: LaneId, + lane_id: MessagesLaneIdOf, maybe_limits: Option, ) -> MessagesRelayParams, DefaultClient> { MessagesRelayParams { @@ -287,36 +290,57 @@ where self.mut_base().start_on_demand_headers_relayers().await?; // add balance-related metrics - let lanes = self + let lanes_l2r: Vec> = self + .base() + .common() + .shared + .lane + .iter() + .cloned() + .map(HexLaneId::try_convert) + .collect::, HexLaneId>>() + .map_err(|e| { + anyhow::format_err!("Conversion failed for L2R lanes with error: {:?}!", e) + })?; + let lanes_r2l: Vec> = self .base() .common() .shared .lane .iter() .cloned() - .map(Into::into) - .collect::>(); + .map(HexLaneId::try_convert) + .collect::, HexLaneId>>() + .map_err(|e| { + anyhow::format_err!("Conversion failed for R2L lanes with error: {:?}!", e) + })?; { let common = self.mut_base().mut_common(); - crate::messages::metrics::add_relay_balances_metrics::<_, Self::Right>( - common.left.client.clone(), - &common.metrics_params, - &common.left.accounts, - &lanes, + crate::messages::metrics::add_relay_balances_metrics::< + _, + Self::Right, + MessagesLaneIdOf, + >( + common.left.client.clone(), &common.metrics_params, &common.left.accounts, &lanes_l2r ) .await?; - crate::messages::metrics::add_relay_balances_metrics::<_, Self::Left>( + crate::messages::metrics::add_relay_balances_metrics::< + _, + Self::Left, + MessagesLaneIdOf, + >( common.right.client.clone(), &common.metrics_params, &common.right.accounts, - &lanes, + &lanes_r2l, ) .await?; } // Need 2x capacity since we consider both directions for each lane - let mut message_relays = Vec::with_capacity(lanes.len() * 2); - for lane in lanes { + let mut message_relays = + Vec::with_capacity(lanes_l2r.len().saturating_add(lanes_r2l.len())); + for lane in lanes_l2r { let left_to_right_messages = crate::messages::run::<::MessagesLane, _, _>( self.left_to_right().messages_relay_params( @@ -329,7 +353,8 @@ where .map_err(|e| anyhow::format_err!("{}", e)) .boxed(); message_relays.push(left_to_right_messages); - + } + for lane in lanes_r2l { let right_to_left_messages = crate::messages::run::<::MessagesLane, _, _>( self.right_to_left().messages_relay_params( @@ -422,7 +447,7 @@ mod tests { "--polkadot-port", "9944", "--lane", - "00000000", + "0000000000000000000000000000000000000000000000000000000000000000", "--prometheus-host", "0.0.0.0", ]); @@ -432,7 +457,7 @@ mod tests { res, BridgeHubKusamaBridgeHubPolkadotHeadersAndMessages { shared: HeadersAndMessagesSharedParams { - lane: vec![HexLaneId([0x00, 0x00, 0x00, 0x00])], + lane: vec![HexLaneId(vec![0x00u8; 32])], only_mandatory_headers: false, only_free_headers: false, prometheus_params: PrometheusParams { diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/parachain_to_parachain.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/parachain_to_parachain.rs index 8104be7af807..e8b797f84fa5 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/parachain_to_parachain.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/parachain_to_parachain.rs @@ -30,8 +30,8 @@ use crate::{ headers::OnDemandHeadersRelay, parachains::OnDemandParachainsRelay, OnDemandRelay, }, }; +use bp_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; use bp_polkadot_core::parachains::ParaHash; -use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; use relay_substrate_client::{ AccountIdOf, AccountKeyPairOf, Chain, ChainWithRuntimeVersion, ChainWithTransactions, Client, Parachain, diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/relay_to_parachain.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/relay_to_parachain.rs index 6c078973fedc..f9884ee197b4 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/relay_to_parachain.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_headers_and_messages/relay_to_parachain.rs @@ -33,8 +33,8 @@ use crate::{ headers::OnDemandHeadersRelay, parachains::OnDemandParachainsRelay, OnDemandRelay, }, }; +use bp_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; use bp_polkadot_core::parachains::ParaHash; -use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; use relay_substrate_client::{ AccountIdOf, AccountKeyPairOf, Chain, ChainWithRuntimeVersion, ChainWithTransactions, Client, Parachain, diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs index 68bbe71ae599..71d3adc078e2 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_messages.rs @@ -33,12 +33,13 @@ use relay_substrate_client::{ ChainWithTransactions, Client, }; use relay_utils::UniqueSaturatedInto; +use sp_runtime::traits::TryConvert; /// Messages relaying params. #[derive(StructOpt)] pub struct RelayMessagesParams { - /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. - #[structopt(long, default_value = "00000000")] + /// Hex-encoded lane id that should be served by the relay. + #[structopt(long)] lane: HexLaneId, #[structopt(flatten)] source: SourceConnectionParams, @@ -59,8 +60,8 @@ pub struct RelayMessagesRangeParams { /// This header must be previously proved to the target chain. #[structopt(long)] at_source_block: u128, - /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. - #[structopt(long, default_value = "00000000")] + /// Hex-encoded lane id that should be served by the relay. + #[structopt(long)] lane: HexLaneId, /// Nonce (inclusive) of the first message to relay. #[structopt(long)] @@ -88,8 +89,8 @@ pub struct RelayMessagesDeliveryConfirmationParams { /// delivery proof. This header must be previously proved to the source chain. #[structopt(long)] at_target_block: u128, - /// Hex-encoded lane id that should be served by the relay. Defaults to `00000000`. - #[structopt(long, default_value = "00000000")] + /// Hex-encoded lane id that should be served by the relay. + #[structopt(long)] lane: HexLaneId, #[structopt(flatten)] source: SourceConnectionParams, @@ -116,6 +117,11 @@ where let target_client = data.target.into_client::().await?; let target_sign = data.target_sign.to_keypair::()?; let target_transactions_mortality = data.target_sign.transactions_mortality()?; + let lane_id = HexLaneId::try_convert(data.lane).map_err(|invalid_lane_id| { + anyhow::format_err!("Invalid laneId: {:?}!", invalid_lane_id) + })?; + + Self::start_relay_guards(&target_client, target_client.can_start_version_guard()).await?; crate::messages::run::(MessagesRelayParams { source_client, @@ -130,7 +136,7 @@ where }, source_to_target_headers_relay: None, target_to_source_headers_relay: None, - lane_id: data.lane.into(), + lane_id, limits: Self::maybe_messages_limits(), metrics_params: data.prometheus_params.into_metrics_params()?, }) @@ -146,6 +152,9 @@ where let source_transactions_mortality = data.source_sign.transactions_mortality()?; let target_sign = data.target_sign.to_keypair::()?; let target_transactions_mortality = data.target_sign.transactions_mortality()?; + let lane_id = HexLaneId::try_convert(data.lane).map_err(|invalid_lane_id| { + anyhow::format_err!("Invalid laneId: {:?}!", invalid_lane_id) + })?; let at_source_block = source_client .header_by_number(data.at_source_block.unique_saturated_into()) @@ -167,7 +176,7 @@ where TransactionParams { signer: source_sign, mortality: source_transactions_mortality }, TransactionParams { signer: target_sign, mortality: target_transactions_mortality }, at_source_block, - data.lane.into(), + lane_id, data.messages_start..=data.messages_end, data.outbound_state_proof_required, ) @@ -182,6 +191,9 @@ where let target_client = data.target.into_client::().await?; let source_sign = data.source_sign.to_keypair::()?; let source_transactions_mortality = data.source_sign.transactions_mortality()?; + let lane_id = HexLaneId::try_convert(data.lane).map_err(|invalid_lane_id| { + anyhow::format_err!("Invalid laneId: {:?}!", invalid_lane_id) + })?; let at_target_block = target_client .header_by_number(data.at_target_block.unique_saturated_into()) @@ -202,8 +214,22 @@ where target_client, TransactionParams { signer: source_sign, mortality: source_transactions_mortality }, at_target_block, - data.lane.into(), + lane_id, ) .await } + + /// Add relay guards if required. + async fn start_relay_guards( + target_client: &impl Client, + enable_version_guard: bool, + ) -> relay_substrate_client::Result<()> { + if enable_version_guard { + relay_substrate_client::guard::abort_on_spec_version_change( + target_client.clone(), + target_client.simple_runtime_version().await?.spec_version, + ); + } + Ok(()) + } } diff --git a/bridges/relays/lib-substrate-relay/src/cli/relay_parachains.rs b/bridges/relays/lib-substrate-relay/src/cli/relay_parachains.rs index 77cd395ff722..83285b69f701 100644 --- a/bridges/relays/lib-substrate-relay/src/cli/relay_parachains.rs +++ b/bridges/relays/lib-substrate-relay/src/cli/relay_parachains.rs @@ -32,6 +32,7 @@ use crate::{ chain_schema::*, DefaultClient, PrometheusParams, }, + finality::SubstrateFinalitySyncPipeline, parachains::{source::ParachainsSource, target::ParachainsTarget, ParachainsPipelineAdapter}, TransactionParams, }; @@ -104,6 +105,12 @@ where data.prometheus_params.into_metrics_params()?; GlobalMetrics::new()?.register_and_spawn(&metrics_params.registry)?; + Self::RelayFinality::start_relay_guards( + target_client.target_client(), + target_client.target_client().can_start_version_guard(), + ) + .await?; + parachains_relay::parachains_loop::run( source_client, target_client, diff --git a/bridges/relays/lib-substrate-relay/src/messages/metrics.rs b/bridges/relays/lib-substrate-relay/src/messages/metrics.rs index 8845f43dcb62..efe429701c41 100644 --- a/bridges/relays/lib-substrate-relay/src/messages/metrics.rs +++ b/bridges/relays/lib-substrate-relay/src/messages/metrics.rs @@ -18,11 +18,11 @@ use crate::TaggedAccount; -use bp_messages::LaneId; use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; use bp_runtime::StorageDoubleMapKeyProvider; -use codec::Decode; +use codec::{Decode, EncodeLike}; use frame_system::AccountInfo; +use messages_relay::Labeled; use pallet_balances::AccountData; use relay_substrate_client::{ metrics::{FloatStorageValue, FloatStorageValueMetric}, @@ -35,7 +35,7 @@ use sp_runtime::{FixedPointNumber, FixedU128}; use std::{fmt::Debug, marker::PhantomData}; /// Add relay accounts balance metrics. -pub async fn add_relay_balances_metrics( +pub async fn add_relay_balances_metrics( client: impl Client, metrics: &MetricsParams, relay_accounts: &Vec>>, @@ -43,6 +43,7 @@ pub async fn add_relay_balances_metrics anyhow::Result<()> where BalanceOf: Into + std::fmt::Debug, + LaneId: Clone + Copy + Decode + EncodeLike + Send + Sync + Labeled, { if relay_accounts.is_empty() { return Ok(()) @@ -52,9 +53,8 @@ where let token_decimals = client .token_decimals() .await? - .map(|token_decimals| { + .inspect(|token_decimals| { log::info!(target: "bridge", "Read `tokenDecimals` for {}: {}", C::NAME, token_decimals); - token_decimals }) .unwrap_or_else(|| { // turns out it is normal not to have this property - e.g. when polkadot binary is @@ -86,25 +86,25 @@ where FloatStorageValueMetric::new( AccountBalance:: { token_decimals, _phantom: Default::default() }, client.clone(), - bp_relayers::RelayerRewardsKeyProvider::, BalanceOf>::final_key( + bp_relayers::RelayerRewardsKeyProvider::, BalanceOf, LaneId>::final_key( relayers_pallet_name, account.id(), &RewardsAccountParams::new(*lane, BC::ID, RewardsAccountOwner::ThisChain), ), - format!("at_{}_relay_{}_reward_for_msgs_from_{}_on_lane_{}", C::NAME, account.tag(), BC::NAME, hex::encode(lane.as_ref())), - format!("Reward of the {} relay account at {} for delivering messages from {} on lane {:?}", account.tag(), C::NAME, BC::NAME, lane), + format!("at_{}_relay_{}_reward_for_msgs_from_{}_on_lane_{}", C::NAME, account.tag(), BC::NAME, lane.label()), + format!("Reward of the {} relay account at {} for delivering messages from {} on lane {:?}", account.tag(), C::NAME, BC::NAME, lane.label()), )?.register_and_spawn(&metrics.registry)?; FloatStorageValueMetric::new( AccountBalance:: { token_decimals, _phantom: Default::default() }, client.clone(), - bp_relayers::RelayerRewardsKeyProvider::, BalanceOf>::final_key( + bp_relayers::RelayerRewardsKeyProvider::, BalanceOf, LaneId>::final_key( relayers_pallet_name, account.id(), &RewardsAccountParams::new(*lane, BC::ID, RewardsAccountOwner::BridgedChain), ), - format!("at_{}_relay_{}_reward_for_msgs_to_{}_on_lane_{}", C::NAME, account.tag(), BC::NAME, hex::encode(lane.as_ref())), - format!("Reward of the {} relay account at {} for delivering messages confirmations from {} on lane {:?}", account.tag(), C::NAME, BC::NAME, lane), + format!("at_{}_relay_{}_reward_for_msgs_to_{}_on_lane_{}", C::NAME, account.tag(), BC::NAME, lane.label()), + format!("Reward of the {} relay account at {} for delivering messages confirmations from {} on lane {:?}", account.tag(), C::NAME, BC::NAME, lane.label()), )?.register_and_spawn(&metrics.registry)?; } } diff --git a/bridges/relays/lib-substrate-relay/src/messages/mod.rs b/bridges/relays/lib-substrate-relay/src/messages/mod.rs index e52b70206669..b4ee57ed7742 100644 --- a/bridges/relays/lib-substrate-relay/src/messages/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/messages/mod.rs @@ -27,19 +27,17 @@ use crate::{ use async_std::sync::Arc; use bp_messages::{ - target_chain::FromBridgedChainMessagesProof, ChainWithMessages as _, LaneId, MessageNonce, + target_chain::FromBridgedChainMessagesProof, ChainWithMessages as _, MessageNonce, }; -use bp_runtime::{ - AccountIdOf, Chain as _, EncodedOrDecodedCall, HeaderIdOf, TransactionEra, WeightExtraOps, -}; -use codec::Encode; +use bp_runtime::{AccountIdOf, EncodedOrDecodedCall, HeaderIdOf, TransactionEra, WeightExtraOps}; +use codec::{Codec, Encode, EncodeLike}; use frame_support::{dispatch::GetDispatchInfo, weights::Weight}; -use messages_relay::{message_lane::MessageLane, message_lane_loop::BatchTransaction}; +use messages_relay::{message_lane::MessageLane, message_lane_loop::BatchTransaction, Labeled}; use pallet_bridge_messages::{Call as BridgeMessagesCall, Config as BridgeMessagesConfig}; use relay_substrate_client::{ transaction_stall_timeout, AccountKeyPairOf, BalanceOf, BlockNumberOf, CallOf, Chain, - ChainWithMessages, ChainWithTransactions, Client, Error as SubstrateError, HashOf, SignParam, - UnsignedTransaction, + ChainBase, ChainWithMessages, ChainWithTransactions, Client, Error as SubstrateError, HashOf, + SignParam, UnsignedTransaction, }; use relay_utils::{ metrics::{GlobalMetrics, MetricsParams, StandaloneMetric}, @@ -60,6 +58,18 @@ pub trait SubstrateMessageLane: 'static + Clone + Debug + Send + Sync { /// Messages from the `SourceChain` are dispatched on this chain. type TargetChain: ChainWithMessages + ChainWithTransactions; + /// Lane identifier type. + type LaneId: Clone + + Copy + + Debug + + Codec + + EncodeLike + + Send + + Sync + + Labeled + + TryFrom> + + Default; + /// How receive messages proof call is built? type ReceiveMessagesProofCallBuilder: ReceiveMessagesProofCallBuilder; /// How receive messages delivery proof call is built? @@ -81,8 +91,10 @@ impl MessageLane for MessageLaneAdapter

{ const SOURCE_NAME: &'static str = P::SourceChain::NAME; const TARGET_NAME: &'static str = P::TargetChain::NAME; - type MessagesProof = SubstrateMessagesProof; - type MessagesReceivingProof = SubstrateMessagesDeliveryProof; + type LaneId = P::LaneId; + + type MessagesProof = SubstrateMessagesProof; + type MessagesReceivingProof = SubstrateMessagesDeliveryProof; type SourceChainBalance = BalanceOf; type SourceHeaderNumber = BlockNumberOf; @@ -109,7 +121,7 @@ pub struct MessagesRelayParams pub target_to_source_headers_relay: Option>>, /// Identifier of lane that needs to be served. - pub lane_id: LaneId, + pub lane_id: P::LaneId, /// Messages relay limits. If not provided, the relay tries to determine it automatically, /// using `TransactionPayment` pallet runtime API. pub limits: Option, @@ -293,7 +305,7 @@ pub async fn relay_messages_range( source_transaction_params: TransactionParams>, target_transaction_params: TransactionParams>, at_source_block: HeaderIdOf, - lane_id: LaneId, + lane_id: P::LaneId, range: RangeInclusive, outbound_state_proof_required: bool, ) -> anyhow::Result<()> @@ -335,7 +347,7 @@ pub async fn relay_messages_delivery_confirmation( target_client: impl Client, source_transaction_params: TransactionParams>, at_target_block: HeaderIdOf, - lane_id: LaneId, + lane_id: P::LaneId, ) -> anyhow::Result<()> where AccountIdOf: From< as Pair>::Public>, @@ -372,7 +384,7 @@ pub trait ReceiveMessagesProofCallBuilder { /// messages module at the target chain. fn build_receive_messages_proof_call( relayer_id_at_source: AccountIdOf, - proof: SubstrateMessagesProof, + proof: SubstrateMessagesProof, messages_count: u32, dispatch_weight: Weight, trace_call: bool, @@ -388,7 +400,7 @@ pub struct DirectReceiveMessagesProofCallBuilder { impl ReceiveMessagesProofCallBuilder

for DirectReceiveMessagesProofCallBuilder where P: SubstrateMessageLane, - R: BridgeMessagesConfig, + R: BridgeMessagesConfig, I: 'static, R::BridgedChain: bp_runtime::Chain, Hash = HashOf>, @@ -396,7 +408,7 @@ where { fn build_receive_messages_proof_call( relayer_id_at_source: AccountIdOf, - proof: SubstrateMessagesProof, + proof: SubstrateMessagesProof, messages_count: u32, dispatch_weight: Weight, trace_call: bool, @@ -416,7 +428,7 @@ where "Prepared {} -> {} messages delivery call. Weight: {}/{}, size: {}/{}", P::SourceChain::NAME, P::TargetChain::NAME, - call.get_dispatch_info().weight, + call.get_dispatch_info().call_weight, P::TargetChain::max_extrinsic_weight(), call.encode().len(), P::TargetChain::max_extrinsic_size(), @@ -444,7 +456,8 @@ macro_rules! generate_receive_message_proof_call_builder { <$pipeline as $crate::messages::SubstrateMessageLane>::SourceChain >, proof: $crate::messages::source::SubstrateMessagesProof< - <$pipeline as $crate::messages::SubstrateMessageLane>::SourceChain + <$pipeline as $crate::messages::SubstrateMessageLane>::SourceChain, + <$pipeline as $crate::messages::SubstrateMessageLane>::LaneId >, messages_count: u32, dispatch_weight: bp_messages::Weight, @@ -470,7 +483,7 @@ pub trait ReceiveMessagesDeliveryProofCallBuilder { /// Given messages delivery proof, build call of `receive_messages_delivery_proof` function of /// bridge messages module at the source chain. fn build_receive_messages_delivery_proof_call( - proof: SubstrateMessagesDeliveryProof, + proof: SubstrateMessagesDeliveryProof, trace_call: bool, ) -> CallOf; } @@ -485,13 +498,13 @@ impl ReceiveMessagesDeliveryProofCallBuilder

for DirectReceiveMessagesDeliveryProofCallBuilder where P: SubstrateMessageLane, - R: BridgeMessagesConfig, + R: BridgeMessagesConfig, I: 'static, R::BridgedChain: bp_runtime::Chain>, CallOf: From> + GetDispatchInfo, { fn build_receive_messages_delivery_proof_call( - proof: SubstrateMessagesDeliveryProof, + proof: SubstrateMessagesDeliveryProof, trace_call: bool, ) -> CallOf { let call: CallOf = @@ -508,7 +521,7 @@ where "Prepared {} -> {} delivery confirmation transaction. Weight: {}/{}, size: {}/{}", P::TargetChain::NAME, P::SourceChain::NAME, - call.get_dispatch_info().weight, + call.get_dispatch_info().call_weight, P::SourceChain::max_extrinsic_weight(), call.encode().len(), P::SourceChain::max_extrinsic_size(), @@ -533,7 +546,8 @@ macro_rules! generate_receive_message_delivery_proof_call_builder { { fn build_receive_messages_delivery_proof_call( proof: $crate::messages::target::SubstrateMessagesDeliveryProof< - <$pipeline as $crate::messages::SubstrateMessageLane>::TargetChain + <$pipeline as $crate::messages::SubstrateMessageLane>::TargetChain, + <$pipeline as $crate::messages::SubstrateMessageLane>::LaneId >, _trace_call: bool, ) -> relay_substrate_client::CallOf< @@ -644,7 +658,7 @@ where FromBridgedChainMessagesProof { bridged_header_hash: Default::default(), storage_proof: Default::default(), - lane: Default::default(), + lane: P::LaneId::default(), nonces_start: 1, nonces_end: messages as u64, }, @@ -674,7 +688,7 @@ where mod tests { use super::*; use bp_messages::{ - source_chain::FromBridgedChainMessagesDeliveryProof, UnrewardedRelayersState, + source_chain::FromBridgedChainMessagesDeliveryProof, LaneIdType, UnrewardedRelayersState, }; use relay_substrate_client::calls::{UtilityCall as MockUtilityCall, UtilityCall}; @@ -687,8 +701,8 @@ mod tests { } pub type CodegenBridgeMessagesCall = bp_messages::BridgeMessagesCall< u64, - Box>, - FromBridgedChainMessagesDeliveryProof, + Box>, + FromBridgedChainMessagesDeliveryProof, >; impl From> for RuntimeCall { @@ -706,7 +720,7 @@ mod tests { let receive_messages_proof = FromBridgedChainMessagesProof { bridged_header_hash: Default::default(), storage_proof: Default::default(), - lane: LaneId([0, 0, 0, 0]), + lane: mock::TestLaneIdType::try_new(1, 2).unwrap(), nonces_start: 0, nonces_end: 0, }; @@ -761,7 +775,7 @@ mod tests { let receive_messages_delivery_proof = FromBridgedChainMessagesDeliveryProof { bridged_header_hash: Default::default(), storage_proof: Default::default(), - lane: LaneId([0, 0, 0, 0]), + lane: mock::TestLaneIdType::try_new(1, 2).unwrap(), }; let relayers_state = UnrewardedRelayersState { unrewarded_relayer_entries: 0, @@ -808,7 +822,7 @@ mod tests { // mock runtime with `pallet_bridge_messages` mod mock { use super::super::*; - use bp_messages::target_chain::ForbidInboundMessages; + use bp_messages::{target_chain::ForbidInboundMessages, HashedLaneId}; use bp_runtime::ChainId; use frame_support::derive_impl; use sp_core::H256; @@ -819,6 +833,9 @@ mod tests { type Block = frame_system::mocking::MockBlock; pub type SignedBlock = generic::SignedBlock; + /// Lane identifier type used for tests. + pub type TestLaneIdType = HashedLaneId; + frame_support::construct_runtime! { pub enum TestRuntime { @@ -838,13 +855,13 @@ mod tests { type ThisChain = ThisUnderlyingChain; type BridgedChain = BridgedUnderlyingChain; type BridgedHeaderChain = BridgedHeaderChain; - type ActiveOutboundLanes = (); type OutboundPayload = Vec; type InboundPayload = Vec; + type LaneId = TestLaneIdType; type DeliveryPayments = (); type DeliveryConfirmationPayments = (); type OnMessagesDelivered = (); - type MessageDispatch = ForbidInboundMessages>; + type MessageDispatch = ForbidInboundMessages, Self::LaneId>; } pub struct ThisUnderlyingChain; @@ -1006,6 +1023,7 @@ mod tests { impl SubstrateMessageLane for ThisChainToBridgedChainMessageLane { type SourceChain = ThisChain; type TargetChain = BridgedChain; + type LaneId = mock::TestLaneIdType; type ReceiveMessagesProofCallBuilder = ThisChainToBridgedChainMessageLaneReceiveMessagesProofCallBuilder; type ReceiveMessagesDeliveryProofCallBuilder = diff --git a/bridges/relays/lib-substrate-relay/src/messages/source.rs b/bridges/relays/lib-substrate-relay/src/messages/source.rs index b75fc86d5eee..3e60ed7abd09 100644 --- a/bridges/relays/lib-substrate-relay/src/messages/source.rs +++ b/bridges/relays/lib-substrate-relay/src/messages/source.rs @@ -34,11 +34,11 @@ use async_trait::async_trait; use bp_messages::{ storage_keys::{operating_mode_key, outbound_lane_data_key}, target_chain::FromBridgedChainMessagesProof, - ChainWithMessages as _, InboundMessageDetails, LaneId, MessageNonce, MessagePayload, - MessagesOperatingMode, OutboundLaneData, OutboundMessageDetails, + ChainWithMessages as _, InboundMessageDetails, MessageNonce, MessagePayload, + MessagesOperatingMode, OutboundMessageDetails, }; use bp_runtime::{BasicOperatingMode, HeaderIdProvider, RangeInclusiveExt}; -use codec::Encode; +use codec::{Decode, Encode}; use frame_support::weights::Weight; use messages_relay::{ message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf}, @@ -60,14 +60,26 @@ use std::ops::RangeInclusive; /// Intermediate message proof returned by the source Substrate node. Includes everything /// required to submit to the target node: cumulative dispatch weight of bundled messages and /// the proof itself. -pub type SubstrateMessagesProof = (Weight, FromBridgedChainMessagesProof>); +pub type SubstrateMessagesProof = (Weight, FromBridgedChainMessagesProof, L>); type MessagesToRefine<'a> = Vec<(MessagePayload, &'a mut OutboundMessageDetails)>; +/// Outbound lane data - for backwards compatibility with `bp_messages::OutboundLaneData` which has +/// additional `lane_state` attribute. +/// +/// TODO: remove - https://github.com/paritytech/polkadot-sdk/issues/5923 +#[derive(Decode)] +struct LegacyOutboundLaneData { + #[allow(unused)] + oldest_unpruned_nonce: MessageNonce, + latest_received_nonce: MessageNonce, + latest_generated_nonce: MessageNonce, +} + /// Substrate client as Substrate messages source. pub struct SubstrateMessagesSource { source_client: SourceClnt, target_client: TargetClnt, - lane_id: LaneId, + lane_id: P::LaneId, transaction_params: TransactionParams>, target_to_source_headers_relay: Option>>, } @@ -79,7 +91,7 @@ impl, TargetClnt> pub fn new( source_client: SourceClnt, target_client: TargetClnt, - lane_id: LaneId, + lane_id: P::LaneId, transaction_params: TransactionParams>, target_to_source_headers_relay: Option< Arc>, @@ -98,7 +110,7 @@ impl, TargetClnt> async fn outbound_lane_data( &self, id: SourceHeaderIdOf>, - ) -> Result, SubstrateError> { + ) -> Result, SubstrateError> { self.source_client .storage_value( id.hash(), @@ -256,8 +268,11 @@ where } let best_target_header_hash = self.target_client.best_header_hash().await?; - for mut msgs_to_refine_batch in - split_msgs_to_refine::(self.lane_id, msgs_to_refine)? + for mut msgs_to_refine_batch in split_msgs_to_refine::< + P::SourceChain, + P::TargetChain, + P::LaneId, + >(self.lane_id, msgs_to_refine)? { let in_msgs_details = self .target_client @@ -542,7 +557,7 @@ fn validate_out_msgs_details( Ok(()) } -fn split_msgs_to_refine( +fn split_msgs_to_refine( lane_id: LaneId, msgs_to_refine: MessagesToRefine, ) -> Result, SubstrateError> { @@ -578,8 +593,12 @@ fn split_msgs_to_refine( #[cfg(test)] mod tests { use super::*; + use bp_messages::{HashedLaneId, LaneIdType}; use relay_substrate_client::test_chain::TestChain; + /// Lane identifier type used for tests. + type TestLaneIdType = HashedLaneId; + fn message_details_from_rpc( nonces: RangeInclusive, ) -> Vec { @@ -660,8 +679,10 @@ mod tests { msgs_to_refine.push((payload, out_msg_details)); } - let maybe_batches = - split_msgs_to_refine::(Default::default(), msgs_to_refine); + let maybe_batches = split_msgs_to_refine::( + TestLaneIdType::try_new(1, 2).unwrap(), + msgs_to_refine, + ); match expected_batches { Ok(expected_batches) => { let batches = maybe_batches.unwrap(); @@ -734,4 +755,38 @@ mod tests { Ok(vec![2, 4, 3]), ); } + + #[test] + fn outbound_lane_data_wrapper_is_compatible() { + let bytes_without_state = + vec![1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0]; + let bytes_with_state = { + // add state byte `bp_messages::LaneState::Opened` + let mut b = bytes_without_state.clone(); + b.push(0); + b + }; + + let full = bp_messages::OutboundLaneData { + oldest_unpruned_nonce: 1, + latest_received_nonce: 2, + latest_generated_nonce: 3, + state: bp_messages::LaneState::Opened, + }; + assert_eq!(full.encode(), bytes_with_state); + assert_ne!(full.encode(), bytes_without_state); + + // decode from `bytes_with_state` + let decoded: LegacyOutboundLaneData = Decode::decode(&mut &bytes_with_state[..]).unwrap(); + assert_eq!(full.oldest_unpruned_nonce, decoded.oldest_unpruned_nonce); + assert_eq!(full.latest_received_nonce, decoded.latest_received_nonce); + assert_eq!(full.latest_generated_nonce, decoded.latest_generated_nonce); + + // decode from `bytes_without_state` + let decoded: LegacyOutboundLaneData = + Decode::decode(&mut &bytes_without_state[..]).unwrap(); + assert_eq!(full.oldest_unpruned_nonce, decoded.oldest_unpruned_nonce); + assert_eq!(full.latest_received_nonce, decoded.latest_received_nonce); + assert_eq!(full.latest_generated_nonce, decoded.latest_generated_nonce); + } } diff --git a/bridges/relays/lib-substrate-relay/src/messages/target.rs b/bridges/relays/lib-substrate-relay/src/messages/target.rs index a6bf169cffb6..214819a1c426 100644 --- a/bridges/relays/lib-substrate-relay/src/messages/target.rs +++ b/bridges/relays/lib-substrate-relay/src/messages/target.rs @@ -36,8 +36,9 @@ use async_std::sync::Arc; use async_trait::async_trait; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, storage_keys::inbound_lane_data_key, - ChainWithMessages as _, InboundLaneData, LaneId, MessageNonce, UnrewardedRelayersState, + ChainWithMessages as _, LaneState, MessageNonce, UnrewardedRelayer, UnrewardedRelayersState, }; +use codec::Decode; use messages_relay::{ message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf}, message_lane_loop::{NoncesSubmitArtifacts, TargetClient, TargetClientState}, @@ -48,17 +49,57 @@ use relay_substrate_client::{ }; use relay_utils::relay_loop::Client as RelayClient; use sp_core::Pair; -use std::{convert::TryFrom, ops::RangeInclusive}; +use std::{collections::VecDeque, convert::TryFrom, ops::RangeInclusive}; /// Message receiving proof returned by the target Substrate node. -pub type SubstrateMessagesDeliveryProof = - (UnrewardedRelayersState, FromBridgedChainMessagesDeliveryProof>); +pub type SubstrateMessagesDeliveryProof = + (UnrewardedRelayersState, FromBridgedChainMessagesDeliveryProof, L>); + +/// Inbound lane data - for backwards compatibility with `bp_messages::InboundLaneData` which has +/// additional `lane_state` attribute. +/// +/// TODO: remove - https://github.com/paritytech/polkadot-sdk/issues/5923 +#[derive(Decode)] +struct LegacyInboundLaneData { + relayers: VecDeque>, + last_confirmed_nonce: MessageNonce, +} +impl Default for LegacyInboundLaneData { + fn default() -> Self { + let full = bp_messages::InboundLaneData::default(); + Self { relayers: full.relayers, last_confirmed_nonce: full.last_confirmed_nonce } + } +} + +impl LegacyInboundLaneData { + pub fn last_delivered_nonce(self) -> MessageNonce { + bp_messages::InboundLaneData { + relayers: self.relayers, + last_confirmed_nonce: self.last_confirmed_nonce, + // we don't care about the state here + state: LaneState::Opened, + } + .last_delivered_nonce() + } +} + +impl From> for UnrewardedRelayersState { + fn from(value: LegacyInboundLaneData) -> Self { + (&bp_messages::InboundLaneData { + relayers: value.relayers, + last_confirmed_nonce: value.last_confirmed_nonce, + // we don't care about the state here + state: LaneState::Opened, + }) + .into() + } +} /// Substrate client as Substrate messages target. pub struct SubstrateMessagesTarget { target_client: TargetClnt, source_client: SourceClnt, - lane_id: LaneId, + lane_id: P::LaneId, relayer_id_at_source: AccountIdOf, transaction_params: Option>>, source_to_target_headers_relay: Option>>, @@ -73,7 +114,7 @@ where pub fn new( target_client: TargetClnt, source_client: SourceClnt, - lane_id: LaneId, + lane_id: P::LaneId, relayer_id_at_source: AccountIdOf, transaction_params: Option>>, source_to_target_headers_relay: Option< @@ -94,7 +135,7 @@ where async fn inbound_lane_data( &self, id: TargetHeaderIdOf>, - ) -> Result>>, SubstrateError> { + ) -> Result>>, SubstrateError> { self.target_client .storage_value( id.hash(), @@ -217,8 +258,8 @@ where ) -> Result<(TargetHeaderIdOf>, UnrewardedRelayersState), SubstrateError> { let inbound_lane_data = - self.inbound_lane_data(id).await?.unwrap_or(InboundLaneData::default()); - Ok((id, (&inbound_lane_data).into())) + self.inbound_lane_data(id).await?.unwrap_or(LegacyInboundLaneData::default()); + Ok((id, inbound_lane_data.into())) } async fn prove_messages_receiving( @@ -308,7 +349,7 @@ where fn make_messages_delivery_call( relayer_id_at_source: AccountIdOf, nonces: RangeInclusive, - proof: SubstrateMessagesProof, + proof: SubstrateMessagesProof, trace_call: bool, ) -> CallOf { let messages_count = nonces.end() - nonces.start() + 1; @@ -321,3 +362,49 @@ fn make_messages_delivery_call( trace_call, ) } + +#[cfg(test)] +mod tests { + use super::*; + use bp_messages::{DeliveredMessages, UnrewardedRelayer}; + use codec::Encode; + + #[test] + fn inbound_lane_data_wrapper_is_compatible() { + let bytes_without_state = + vec![4, 0, 2, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0]; + let bytes_with_state = { + // add state byte `bp_messages::LaneState::Opened` + let mut b = bytes_without_state.clone(); + b.push(0); + b + }; + + let full = bp_messages::InboundLaneData:: { + relayers: vec![UnrewardedRelayer { + relayer: Default::default(), + messages: DeliveredMessages { begin: 2, end: 5 }, + }] + .into_iter() + .collect(), + last_confirmed_nonce: 6, + state: bp_messages::LaneState::Opened, + }; + assert_eq!(full.encode(), bytes_with_state); + assert_ne!(full.encode(), bytes_without_state); + + // decode from `bytes_with_state` + let decoded: LegacyInboundLaneData = + Decode::decode(&mut &bytes_with_state[..]).unwrap(); + assert_eq!(full.relayers, decoded.relayers); + assert_eq!(full.last_confirmed_nonce, decoded.last_confirmed_nonce); + assert_eq!(full.last_delivered_nonce(), decoded.last_delivered_nonce()); + + // decode from `bytes_without_state` + let decoded: LegacyInboundLaneData = + Decode::decode(&mut &bytes_without_state[..]).unwrap(); + assert_eq!(full.relayers, decoded.relayers); + assert_eq!(full.last_confirmed_nonce, decoded.last_confirmed_nonce); + assert_eq!(full.last_delivered_nonce(), decoded.last_delivered_nonce()); + } +} diff --git a/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs b/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs index 4579222a2c68..96eba0af988c 100644 --- a/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs +++ b/bridges/relays/lib-substrate-relay/src/on_demand/parachains.rs @@ -31,11 +31,11 @@ use async_std::{ sync::{Arc, Mutex}, }; use async_trait::async_trait; +use bp_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; use bp_polkadot_core::parachains::{ParaHash, ParaId}; use bp_runtime::HeaderIdProvider; use futures::{select, FutureExt}; use num_traits::Zero; -use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; use parachains_relay::parachains_loop::{AvailableHeader, SourceClient, TargetClient}; use relay_substrate_client::{ is_ancient_block, AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, Client, @@ -664,7 +664,8 @@ impl<'a, P: SubstrateParachainsPipeline, SourceRelayClnt, TargetClnt> for ( &'a OnDemandParachainsRelay, &'a ParachainsSource, - ) where + ) +where SourceRelayClnt: Client, TargetClnt: Client, { diff --git a/bridges/relays/lib-substrate-relay/src/parachains/mod.rs b/bridges/relays/lib-substrate-relay/src/parachains/mod.rs index 8b128bb770dd..08d8e5e2a4f5 100644 --- a/bridges/relays/lib-substrate-relay/src/parachains/mod.rs +++ b/bridges/relays/lib-substrate-relay/src/parachains/mod.rs @@ -18,11 +18,9 @@ //! parachain finality proofs synchronization pipelines. use async_trait::async_trait; +use bp_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber}; use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; -use pallet_bridge_parachains::{ - Call as BridgeParachainsCall, Config as BridgeParachainsConfig, RelayBlockHash, - RelayBlockHasher, RelayBlockNumber, -}; +use pallet_bridge_parachains::{Call as BridgeParachainsCall, Config as BridgeParachainsConfig}; use parachains_relay::ParachainsPipeline; use relay_substrate_client::{ CallOf, Chain, ChainWithTransactions, HeaderIdOf, Parachain, RelayChain, diff --git a/bridges/relays/messages/Cargo.toml b/bridges/relays/messages/Cargo.toml index c7a132bb3bae..f9df73507c75 100644 --- a/bridges/relays/messages/Cargo.toml +++ b/bridges/relays/messages/Cargo.toml @@ -26,3 +26,6 @@ finality-relay = { workspace = true } relay-utils = { workspace = true } sp-arithmetic = { workspace = true, default-features = true } + +[dev-dependencies] +sp-core = { workspace = true } diff --git a/bridges/relays/messages/src/lib.rs b/bridges/relays/messages/src/lib.rs index 78a3237ba4fe..f5e09f4d4684 100644 --- a/bridges/relays/messages/src/lib.rs +++ b/bridges/relays/messages/src/lib.rs @@ -38,3 +38,4 @@ mod message_race_strategy; pub use message_race_delivery::relay_messages_range; pub use message_race_receiving::relay_messages_delivery_confirmation; +pub use metrics::Labeled; diff --git a/bridges/relays/messages/src/message_lane.rs b/bridges/relays/messages/src/message_lane.rs index 5c9728ad93ab..84c1e57ba4eb 100644 --- a/bridges/relays/messages/src/message_lane.rs +++ b/bridges/relays/messages/src/message_lane.rs @@ -19,6 +19,7 @@ //! 1) relay new messages from source to target node; //! 2) relay proof-of-delivery from target to source node. +use crate::metrics::Labeled; use num_traits::{SaturatingAdd, Zero}; use relay_utils::{BlockNumberBase, HeaderId}; use sp_arithmetic::traits::AtLeast32BitUnsigned; @@ -31,6 +32,9 @@ pub trait MessageLane: 'static + Clone + Send + Sync { /// Name of the messages target. const TARGET_NAME: &'static str; + /// Lane identifier type. + type LaneId: Clone + Send + Sync + Labeled; + /// Messages proof. type MessagesProof: Clone + Debug + Send + Sync; /// Messages receiving proof. diff --git a/bridges/relays/messages/src/message_lane_loop.rs b/bridges/relays/messages/src/message_lane_loop.rs index b681d86d2ae8..36de637f04c4 100644 --- a/bridges/relays/messages/src/message_lane_loop.rs +++ b/bridges/relays/messages/src/message_lane_loop.rs @@ -29,7 +29,7 @@ use std::{collections::BTreeMap, fmt::Debug, future::Future, ops::RangeInclusive use async_trait::async_trait; use futures::{channel::mpsc::unbounded, future::FutureExt, stream::StreamExt}; -use bp_messages::{LaneId, MessageNonce, UnrewardedRelayersState, Weight}; +use bp_messages::{MessageNonce, UnrewardedRelayersState, Weight}; use relay_utils::{ interval, metrics::MetricsParams, process_future_result, relay_loop::Client as RelayClient, retry_backoff, FailedClient, TransactionTracker, @@ -39,12 +39,12 @@ use crate::{ message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf}, message_race_delivery::run as run_message_delivery_race, message_race_receiving::run as run_message_receiving_race, - metrics::MessageLaneLoopMetrics, + metrics::{Labeled, MessageLaneLoopMetrics}, }; /// Message lane loop configuration params. #[derive(Debug, Clone)] -pub struct Params { +pub struct Params { /// Id of lane this loop is servicing. pub lane: LaneId, /// Interval at which we ask target node about its updates. @@ -275,13 +275,13 @@ pub struct ClientsState { /// Return prefix that will be used by default to expose Prometheus metrics of the finality proofs /// sync loop. -pub fn metrics_prefix(lane: &LaneId) -> String { - format!("{}_to_{}_MessageLane_{}", P::SOURCE_NAME, P::TARGET_NAME, hex::encode(lane)) +pub fn metrics_prefix(lane: &P::LaneId) -> String { + format!("{}_to_{}_MessageLane_{}", P::SOURCE_NAME, P::TARGET_NAME, lane.label()) } /// Run message lane service loop. pub async fn run( - params: Params, + params: Params, source_client: impl SourceClient

, target_client: impl TargetClient

, metrics_params: MetricsParams, @@ -309,7 +309,7 @@ pub async fn run( /// Run one-way message delivery loop until connection with target or source node is lost, or exit /// signal is received. async fn run_until_connection_lost, TC: TargetClient

>( - params: Params, + params: Params, source_client: SC, target_client: TC, metrics_msg: Option, @@ -471,9 +471,9 @@ async fn run_until_connection_lost, TC: Targ pub(crate) mod tests { use std::sync::Arc; + use bp_messages::{HashedLaneId, LaneIdType, LegacyLaneId}; use futures::stream::StreamExt; use parking_lot::Mutex; - use relay_utils::{HeaderId, MaybeConnectionError, TrackedTransactionStatus}; use super::*; @@ -504,6 +504,9 @@ pub(crate) mod tests { } } + /// Lane identifier type used for tests. + pub type TestLaneIdType = HashedLaneId; + #[derive(Clone)] pub struct TestMessageLane; @@ -520,6 +523,8 @@ pub(crate) mod tests { type TargetHeaderNumber = TestTargetHeaderNumber; type TargetHeaderHash = TestTargetHeaderHash; + + type LaneId = TestLaneIdType; } #[derive(Clone, Debug)] @@ -957,7 +962,7 @@ pub(crate) mod tests { }; let _ = run( Params { - lane: LaneId([0, 0, 0, 0]), + lane: TestLaneIdType::try_new(1, 2).unwrap(), source_tick: Duration::from_millis(100), target_tick: Duration::from_millis(100), reconnect_delay: Duration::from_millis(0), @@ -1274,4 +1279,36 @@ pub(crate) mod tests { assert!(!result.target_to_source_header_requirements.is_empty()); assert!(!result.source_to_target_header_requirements.is_empty()); } + + #[test] + fn metrics_prefix_is_valid() { + assert!(MessageLaneLoopMetrics::new(Some(&metrics_prefix::( + &HashedLaneId::try_new(1, 2).unwrap() + ))) + .is_ok()); + + // with LegacyLaneId + #[derive(Clone)] + pub struct LegacyTestMessageLane; + impl MessageLane for LegacyTestMessageLane { + const SOURCE_NAME: &'static str = "LegacyTestSource"; + const TARGET_NAME: &'static str = "LegacyTestTarget"; + + type MessagesProof = TestMessagesProof; + type MessagesReceivingProof = TestMessagesReceivingProof; + + type SourceChainBalance = TestSourceChainBalance; + type SourceHeaderNumber = TestSourceHeaderNumber; + type SourceHeaderHash = TestSourceHeaderHash; + + type TargetHeaderNumber = TestTargetHeaderNumber; + type TargetHeaderHash = TestTargetHeaderHash; + + type LaneId = LegacyLaneId; + } + assert!(MessageLaneLoopMetrics::new(Some(&metrics_prefix::( + &LegacyLaneId([0, 0, 0, 1]) + ))) + .is_ok()); + } } diff --git a/bridges/relays/messages/src/message_race_delivery.rs b/bridges/relays/messages/src/message_race_delivery.rs index cbb89baabcc5..b09533a4ddc1 100644 --- a/bridges/relays/messages/src/message_race_delivery.rs +++ b/bridges/relays/messages/src/message_race_delivery.rs @@ -59,9 +59,7 @@ pub async fn run( _phantom: Default::default(), }, target_state_updates, - MessageDeliveryStrategy:: { - lane_source_client: source_client, - lane_target_client: target_client, + MessageDeliveryStrategy::

{ max_unrewarded_relayer_entries_at_target: params .max_unrewarded_relayer_entries_at_target, max_unconfirmed_nonces_at_target: params.max_unconfirmed_nonces_at_target, @@ -71,7 +69,6 @@ pub async fn run( latest_confirmed_nonces_at_source: VecDeque::new(), target_nonces: None, strategy: BasicStrategy::new(), - metrics_msg, }, ) .await @@ -300,11 +297,7 @@ struct DeliveryRaceTargetNoncesData { } /// Messages delivery strategy. -struct MessageDeliveryStrategy { - /// The client that is connected to the message lane source node. - lane_source_client: SC, - /// The client that is connected to the message lane target node. - lane_target_client: TC, +struct MessageDeliveryStrategy { /// Maximal unrewarded relayer entries at target client. max_unrewarded_relayer_entries_at_target: MessageNonce, /// Maximal unconfirmed nonces at target client. @@ -322,8 +315,6 @@ struct MessageDeliveryStrategy { target_nonces: Option>, /// Basic delivery strategy. strategy: MessageDeliveryStrategyBase

, - /// Message lane metrics. - metrics_msg: Option, } type MessageDeliveryStrategyBase

= BasicStrategy< @@ -335,7 +326,7 @@ type MessageDeliveryStrategyBase

= BasicStrategy<

::MessagesProof, >; -impl std::fmt::Debug for MessageDeliveryStrategy { +impl std::fmt::Debug for MessageDeliveryStrategy

{ fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { fmt.debug_struct("MessageDeliveryStrategy") .field( @@ -353,11 +344,9 @@ impl std::fmt::Debug for MessageDeliveryStrategy MessageDeliveryStrategy +impl MessageDeliveryStrategy

where P: MessageLane, - SC: MessageLaneSourceClient

, - TC: MessageLaneTargetClient

, { /// Returns true if some race action can be selected (with `select_race_action`) at given /// `best_finalized_source_header_id_at_best_target` source header at target. @@ -465,23 +454,18 @@ where let max_nonces = std::cmp::min(max_nonces, self.max_messages_in_single_batch); let max_messages_weight_in_single_batch = self.max_messages_weight_in_single_batch; let max_messages_size_in_single_batch = self.max_messages_size_in_single_batch; - let lane_source_client = self.lane_source_client.clone(); - let lane_target_client = self.lane_target_client.clone(); // select nonces from nonces, available for delivery let selected_nonces = match self.strategy.available_source_queue_indices(race_state) { Some(available_source_queue_indices) => { let source_queue = self.strategy.source_queue(); - let reference = RelayMessagesBatchReference { + let reference = RelayMessagesBatchReference::

{ max_messages_in_this_batch: max_nonces, max_messages_weight_in_single_batch, max_messages_size_in_single_batch, - lane_source_client: lane_source_client.clone(), - lane_target_client: lane_target_client.clone(), best_target_nonce, nonces_queue: source_queue.clone(), nonces_queue_range: available_source_queue_indices, - metrics: self.metrics_msg.clone(), }; MessageRaceLimits::decide(reference).await @@ -534,12 +518,10 @@ where } #[async_trait] -impl RaceStrategy, TargetHeaderIdOf

, P::MessagesProof> - for MessageDeliveryStrategy +impl

RaceStrategy, TargetHeaderIdOf

, P::MessagesProof> + for MessageDeliveryStrategy

where P: MessageLane, - SC: MessageLaneSourceClient

, - TC: MessageLaneTargetClient

, { type SourceNoncesRange = MessageDetailsMap; type ProofParameters = MessageProofParameters; @@ -707,8 +689,7 @@ mod tests { message_lane_loop::{ tests::{ header_id, TestMessageLane, TestMessagesBatchTransaction, TestMessagesProof, - TestSourceChainBalance, TestSourceClient, TestSourceHeaderId, TestTargetClient, - TestTargetHeaderId, + TestSourceChainBalance, TestSourceHeaderId, TestTargetHeaderId, }, MessageDetails, }, @@ -726,8 +707,7 @@ mod tests { TestMessagesProof, TestMessagesBatchTransaction, >; - type TestStrategy = - MessageDeliveryStrategy; + type TestStrategy = MessageDeliveryStrategy; fn source_nonces( new_nonces: RangeInclusive, @@ -770,9 +750,6 @@ mod tests { max_messages_weight_in_single_batch: Weight::from_parts(4, 0), max_messages_size_in_single_batch: 4, latest_confirmed_nonces_at_source: vec![(header_id(1), 19)].into_iter().collect(), - lane_source_client: TestSourceClient::default(), - lane_target_client: TestTargetClient::default(), - metrics_msg: None, target_nonces: Some(TargetClientNonces { latest_nonce: 19, nonces_data: DeliveryRaceTargetNoncesData { @@ -1167,9 +1144,6 @@ mod tests { max_messages_weight_in_single_batch: Weight::from_parts(4, 0), max_messages_size_in_single_batch: 4, latest_confirmed_nonces_at_source: VecDeque::new(), - lane_source_client: TestSourceClient::default(), - lane_target_client: TestTargetClient::default(), - metrics_msg: None, target_nonces: None, strategy: BasicStrategy::new(), }; diff --git a/bridges/relays/messages/src/message_race_limits.rs b/bridges/relays/messages/src/message_race_limits.rs index 873bb6aad042..8fcd1f911f68 100644 --- a/bridges/relays/messages/src/message_race_limits.rs +++ b/bridges/relays/messages/src/message_race_limits.rs @@ -23,33 +23,16 @@ use bp_messages::{MessageNonce, Weight}; use crate::{ message_lane::MessageLane, - message_lane_loop::{ - MessageDetails, MessageDetailsMap, SourceClient as MessageLaneSourceClient, - TargetClient as MessageLaneTargetClient, - }, + message_lane_loop::{MessageDetails, MessageDetailsMap}, message_race_loop::NoncesRange, message_race_strategy::SourceRangesQueue, - metrics::MessageLaneLoopMetrics, }; /// Reference data for participating in relay -pub struct RelayReference< - P: MessageLane, - SourceClient: MessageLaneSourceClient

, - TargetClient: MessageLaneTargetClient

, -> { - /// The client that is connected to the message lane source node. - pub lane_source_client: SourceClient, - /// The client that is connected to the message lane target node. - pub lane_target_client: TargetClient, - /// Metrics reference. - pub metrics: Option, +pub struct RelayReference { /// Messages size summary pub selected_size: u32, - /// Hard check begin nonce - pub hard_selected_begin_nonce: MessageNonce, - /// Index by all ready nonces pub index: usize, /// Current nonce @@ -59,23 +42,13 @@ pub struct RelayReference< } /// Relay reference data -pub struct RelayMessagesBatchReference< - P: MessageLane, - SourceClient: MessageLaneSourceClient

, - TargetClient: MessageLaneTargetClient

, -> { +pub struct RelayMessagesBatchReference { /// Maximal number of relayed messages in single delivery transaction. pub max_messages_in_this_batch: MessageNonce, /// Maximal cumulative dispatch weight of relayed messages in single delivery transaction. pub max_messages_weight_in_single_batch: Weight, /// Maximal cumulative size of relayed messages in single delivery transaction. pub max_messages_size_in_single_batch: u32, - /// The client that is connected to the message lane source node. - pub lane_source_client: SourceClient, - /// The client that is connected to the message lane target node. - pub lane_target_client: TargetClient, - /// Metrics reference. - pub metrics: Option, /// Best available nonce at the **best** target block. We do not want to deliver nonces /// less than this nonce, even though the block may be retracted. pub best_target_nonce: MessageNonce, @@ -94,12 +67,8 @@ pub struct RelayMessagesBatchReference< pub struct MessageRaceLimits; impl MessageRaceLimits { - pub async fn decide< - P: MessageLane, - SourceClient: MessageLaneSourceClient

, - TargetClient: MessageLaneTargetClient

, - >( - reference: RelayMessagesBatchReference, + pub async fn decide( + reference: RelayMessagesBatchReference

, ) -> Option> { let mut hard_selected_count = 0; @@ -112,15 +81,9 @@ impl MessageRaceLimits { ); // relay reference - let mut relay_reference = RelayReference { - lane_source_client: reference.lane_source_client.clone(), - lane_target_client: reference.lane_target_client.clone(), - metrics: reference.metrics.clone(), - + let mut relay_reference = RelayReference::

{ selected_size: 0, - hard_selected_begin_nonce, - index: 0, nonce: 0, details: MessageDetails { diff --git a/bridges/relays/messages/src/message_race_loop.rs b/bridges/relays/messages/src/message_race_loop.rs index 31341a9a0c0c..ea6a2371dc90 100644 --- a/bridges/relays/messages/src/message_race_loop.rs +++ b/bridges/relays/messages/src/message_race_loop.rs @@ -225,15 +225,9 @@ pub trait RaceState: Clone + Send + Sync { /// client (at the `best_finalized_source_header_id_at_best_target`). fn set_best_finalized_source_header_id_at_best_target(&mut self, id: SourceHeaderId); - /// Best finalized source header id at the source client. - fn best_finalized_source_header_id_at_source(&self) -> Option; /// Best finalized source header id at the best block on the target /// client (at the `best_finalized_source_header_id_at_best_target`). fn best_finalized_source_header_id_at_best_target(&self) -> Option; - /// The best header id at the target client. - fn best_target_header_id(&self) -> Option; - /// Best finalized header id at the target client. - fn best_finalized_target_header_id(&self) -> Option; /// Returns `true` if we have selected nonces to submit to the target node. fn nonces_to_submit(&self) -> Option>; @@ -296,22 +290,10 @@ where self.best_finalized_source_header_id_at_best_target = Some(id); } - fn best_finalized_source_header_id_at_source(&self) -> Option { - self.best_finalized_source_header_id_at_source.clone() - } - fn best_finalized_source_header_id_at_best_target(&self) -> Option { self.best_finalized_source_header_id_at_best_target.clone() } - fn best_target_header_id(&self) -> Option { - self.best_target_header_id.clone() - } - - fn best_finalized_target_header_id(&self) -> Option { - self.best_finalized_target_header_id.clone() - } - fn nonces_to_submit(&self) -> Option> { self.nonces_to_submit.clone().map(|(_, nonces, _)| nonces) } diff --git a/bridges/relays/messages/src/message_race_strategy.rs b/bridges/relays/messages/src/message_race_strategy.rs index 3a532331d79d..1303fcfedebd 100644 --- a/bridges/relays/messages/src/message_race_strategy.rs +++ b/bridges/relays/messages/src/message_race_strategy.rs @@ -67,7 +67,8 @@ impl< TargetHeaderHash, SourceNoncesRange, Proof, - > where + > +where SourceHeaderHash: Clone, SourceHeaderNumber: Clone + Ord, SourceNoncesRange: NoncesRange, @@ -189,7 +190,8 @@ impl< TargetHeaderHash, SourceNoncesRange, Proof, - > where + > +where SourceHeaderHash: Clone + Debug + Send + Sync, SourceHeaderNumber: Clone + Ord + Debug + Send + Sync, SourceNoncesRange: NoncesRange + Debug + Send + Sync, diff --git a/bridges/relays/messages/src/metrics.rs b/bridges/relays/messages/src/metrics.rs index 69d80d178de8..2ca10e56d74a 100644 --- a/bridges/relays/messages/src/metrics.rs +++ b/bridges/relays/messages/src/metrics.rs @@ -21,7 +21,7 @@ use crate::{ message_lane_loop::{SourceClientState, TargetClientState}, }; -use bp_messages::MessageNonce; +use bp_messages::{HashedLaneId, LegacyLaneId, MessageNonce}; use finality_relay::SyncLoopMetrics; use relay_utils::metrics::{ metric_name, register, GaugeVec, Metric, Opts, PrometheusError, Registry, U64, @@ -146,3 +146,32 @@ impl Metric for MessageLaneLoopMetrics { Ok(()) } } + +/// Provides a label for metrics. +pub trait Labeled { + /// Returns a label. + fn label(&self) -> String; +} + +/// `Labeled` implementation for `LegacyLaneId`. +impl Labeled for LegacyLaneId { + fn label(&self) -> String { + hex::encode(self.0) + } +} + +/// `Labeled` implementation for `HashedLaneId`. +impl Labeled for HashedLaneId { + fn label(&self) -> String { + format!("{:?}", self.inner()) + } +} + +#[test] +fn lane_to_label_works() { + assert_eq!( + "0x0101010101010101010101010101010101010101010101010101010101010101", + HashedLaneId::from_inner(sp_core::H256::from([1u8; 32])).label(), + ); + assert_eq!("00000001", LegacyLaneId([0, 0, 0, 1]).label()); +} diff --git a/bridges/relays/parachains/src/parachains_loop.rs b/bridges/relays/parachains/src/parachains_loop.rs index 0fd1d72c7075..dfe6b230ceda 100644 --- a/bridges/relays/parachains/src/parachains_loop.rs +++ b/bridges/relays/parachains/src/parachains_loop.rs @@ -177,6 +177,14 @@ pub async fn run( where P::SourceRelayChain: Chain, { + log::info!( + target: "bridge", + "Starting {} -> {} finality proof relay: relaying (only_free_headers: {:?}) headers", + P::SourceParachain::NAME, + P::TargetChain::NAME, + only_free_headers, + ); + let exit_signal = exit_signal.shared(); relay_utils::relay_loop(source_client, target_client) .with_metrics(metrics_params) @@ -496,7 +504,7 @@ where }, (AvailableHeader::Missing, Some(_)) => { // parachain/parathread has been offboarded removed from the system. It needs to - // be propageted to the target client + // be propagated to the target client true }, (AvailableHeader::Missing, None) => { diff --git a/bridges/relays/utils/Cargo.toml b/bridges/relays/utils/Cargo.toml index 93e42763967b..4c25566607dc 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 } +anyhow = { workspace = true, default-features = 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 64d710242710..564ed1f0e5cc 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/docs/v2.md b/bridges/snowbridge/docs/v2.md new file mode 100644 index 000000000000..8ec440c47cec --- /dev/null +++ b/bridges/snowbridge/docs/v2.md @@ -0,0 +1,356 @@ +# Snowbridge V2 + +This design lowers fees, improves UX, improves relayer decentralization and allows "transacting" over the bridge, making +it a general-purpose bridge rather than just a token bridge. + +We're grateful to Adrian Catangiu, Francisco Aguirre, and others from the Parity XCM/Bridges team for their help and +collaboration on this design. + +## Summary + +- Unordered messaging +- All messages routed through AH +- Off-chain fee estimation +- P→E Fee Asset: WETH +- E→P Fee Asset: ETH +- Relayer rewards for both directions paid out on AH in WETH + +## Polkadot→Ethereum + +Given source parachain $S$, with native token $S^{'}$ and the initial xcm $x_0$ to be executed on $S$. + +### Step 1: User agent constructs initial XCM + +The user agent constructs an initial XCM message $x_0$ that will be executed on S. + +The fee amounts in this message should be high enough to enable dry-running, after which they will be lowered. + +### Step 2: User agent estimates fees + +- Given source parachain $S$, with native token $S^{'}$ and the initial xcm $x_0$ to be executed on $S$. +- The native currency $P^{'}$ (DOT) of the Polkadot relay chain, and $E^{'}$ (ETH) of Ethereum. +- Suppose that the user agent chooses relayer reward $r$ in $E^{'}$. +- Suppose that the exchange rates are $K_{P^{'}/S^{'}}$ and $K_{E^{'}/S^{'}}$. The user agent chooses a multiplier to + $\beta$ to cover volatility in these rates. + +Apply the following sequence operations: + +1. Dry-run $x_0$ on $S$ to receive xcm $x_1$ and cost $a$ in $S^{'}$ +2. Dry-run $x_1$ on AH to receive xcm $x_2$ and cost $b$ in $P^{'}$ (DOT) +3. Dry-run $x_2$ on BH to receive command $m$ and cost $c$ in $P^{'}$ (DOT) +4. Dry-run $m$ on Ethereum to receive cost $d$ in $E^{'}$ (ETH) + +The final cost to the user in $S^{'}$ is given by + +$$ +\beta \left(a + \frac{b + c}{K_{P^{'}/S^{'}}} + \frac{d + r}{K_{E^{'}/S^{'}}}\right) +$$ + +The user agent should perform a final update to xcm $x_0$, substituting the calculated fee amounts. + +### Step 3: User agent initiates bridging operation + +The user agent calls `pallet_xcm::execute` with the initial xcm $x_0$ + +```text +WithdrawAsset (KLT, 100) +PayFees (KLT, 20) +InitiateAssetsTransfer asset=(KLT, 60) remoteFee=(KLT, 20) dest=AH + ExchangeAsset give=(KLT, 20) want=(WETH, 1) + InitiateAssetsTransfer asset=(KLT, 40) remoteFee=(WETH, 1) dest=Ethereum + DepositAsset (KLT, 40) beneficiary=Bob +``` + +### Step 4: AH executes message x1 + +The message $x_1$ is application-specific: + +```text +ReserveAssetDeposited (KLT, 80) +PayFees (KLT, 20) +SetAssetClaimer Kilt/Alice +AliasOrigin Kilt/Alice +ExchangeAsset give=(KLT, 20) want=(WETH, 1) +InitiateAssetsTransfer asset=(KLT, 60) remoteFee=(WETH, 1) dest=Ethereum + DepositAsset (KLT, 60) beneficiary=Bob +``` + +or + +```text +*ReserveAssetDeposited (KLT, 80) +*PayFees (KLT, 20) +*SetAssetClaimer Kilt/Alice +*AliasOrigin Kilt/Alice +ExchangeAsset give=(KLT, 20) want=(WETH, 1) +InitiateAssetsTransfer asset=(KLT, 60) remoteFee=(WETH, 1) dest=Ethereum + DepositAsset (KLT, 60) beneficiary=Bob + Transact Bob.hello() +``` + +Note that the `SetAssetClaimer` instruction is placed before `AliasOrigin` in case AH fails to interpret the latter +instruction. + +In all cases, $x_1$ should contain the necessary instructions to: + +1. Pay fees for local execution using `PaysFees` +2. Obtain WETH for remote delivery fees. + +The XCM bridge-router on AH will charge a small fee to prevent spamming BH with bridge messages. This is necessary since +the `ExportMessage` instruction in message $x_2$ will have no execution fee on BH. For a similar reason, we should also +impose a minimum relayer reward of at least the existential deposit 0.1 DOT, which acts as a deposit to stop spamming +messages with 0 rewards. + +### Step 5: BH executes message x2 + +Message $x_2$ is parsed by the `SnowbridgeMessageExporter` in block $n$ with the following effects: + +- A bridge command $m$ is committed to binary merkle tree $M_n$. + - The transferred asset is parsed from `ReserveAssetDeposited` , `WithdrawAsset` or `TeleportedAssetReceived` + instructions for the local, destination and teleport asset transfer types respectively. + - The original origin is preserved through the `AliasOrigin` instruction. This will allow us to resolve agents for the + case of `Transact`. + - The message exporter must be able to support multiple assets and reserve types in the same message and potentially + multiple `Transacts`. + - The Message Exporter must be able to support multiple Deposited Assets. + - The Message Exporter must be able to parse `SetAssetClaimer` and allow the provided location to claim the assets on + BH in case of errors. +- Given relayer reward $r$ in WETH, set storage $P(\mathrm{hash}(m)) = r$. This is parsed from the `WithdrawAsset` and + `PayFees` instruction within `ExportMessage`. + +Note that WETH on AH & BH is a wrapped derivative of the +[WETH](https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2) ERC20 contract on Ethereum, which is +itself a wrapper over ETH, the native currency of Ethereum. For the purposes of this document you can consider them all +to be of equivalent value. + +```text +!WithdrawAsset(DOT, 10) +!PayFees (DOT, 10) +!ExportMessage dest=Ethereum + *ReserveAssetDeposited (KLT, 60) + *WithdrawAsset (WETH, 1) + *PayFees (WETH, 1) + *SetAssetClaimer Kilt/Alice + *AliasOrigin Kilt/Alice + DepositAsset (KLT, 60) beneficiary=Bob +``` + +or + +```text +!WithdrawAsset(DOT, 10) +!PayFees (DOT, 10) +!ExportMessage dest=Ethereum + *ReserveAssetDeposited (KLT, 80) + *PayFees (KLT, 20) + *SetAssetClaimer Kilt/Alice + *AliasOrigin Kilt/Alice + DepositAsset (KLT, 60) beneficiary=Bob + Transact Bob.hello() +``` + +### Step 6: Relayer relays message to Gateway + +1. A relayer _Charlie_ inspects storage $P$ to look for new messages to relay. Suppose it finds $\mathrm{hash}(m)$ + giving reward $r$. +2. The relayer queries $m$ from $M$ and constructs the necessary proofs. +3. The relayer dry-runs m on Ethereum to decide whether the message is profitable to deliver. +4. The relayer finally delivers the message together with a relayer-controlled address $u$ on AH where the relayer can + claim their reward after proof of delivery. + +### Step 7: Relayer delivers proof of delivery to BH + +The proof of delivery is essentially a merkle proof for the `InboundMessageAccepted` event log. + +When BH processes the proof of delivery: + +1. The command $m$ is removed from storage items $M$ and $P$. +2. The relayer reward is tracked in storage $R$, where $R(u)$ is the accumulated rewards that can be claimed by account + $u$. + +## Ethereum→Polkadot + +### Step 1: Submit send on Gateway + +The interface that the Gateway will use to initiate transfers will be similar to the interface from +`transfer_assets_using_type_and_then` extrinsic that we currently use to initiate transfers from the Polkadot to +Ethereum direction. + +1. It must allow multiple assets to be transferred and specify the transfer type: Local, Destination or Teleport asset + transfer types. It is the job of the User Agent/UX layer to fill in this information correctly. +2. It must allow specifying a destination which is `Address32`, `Address20` or a custom scale-encoded XCM payload that + is executed on the destination. This is how we will support `Transact` , the User Agent/UX layer can build a + scale-encoded payload with an encoded transact call. +3. The same interface is used for both PNA (Polkadot Assets) and ERC20 tokens. Internally we will still look up whether + the token is registered as a PNA or ERC20 for the purpose of minting/locking burning/unlocking logic. The asset + transfer type chosen by the UX layer will inform the XCM that is built from the message on BH. + +```solidity +enum Kind { + Index, + Address32, + Address20, + XCMPayload, +} + +struct Beneficiary { + Kind kind; + bytes data; +} + +enum AssetTransferType { + ReserveDeposit, ReserveWithdraw, Teleport +} + +struct Token { + AssetTransferType type; + address token; + uint128 amount; +} + +function send( + ParaID destinationChain, + Beneficiary calldata beneficiary, + Token[] tokens, + uint128 reward +) external payable; +``` + +Message enqueued $m_0$: + +```solidity +send( + 3022, // KILT Para Id + Address32(0x0000....), + [(ReserveWithdraw, KLT, 100)], + 10, // WETH +) +``` + +```solidity +send { value: 3 }( // Send 3 Eth for fees and reward + 3022, // KILT Para Id + XCMPayload( + DepositAsset (KLT, 100) dest=Bob + Transact Bob.hello() + ), + [(ReserveWithdraw, KLT, 100)], + 1, // 1 ETH of 3 needs to be for the reward, the rest is for fees +) +``` + +The User Agent/UX layer will need to estimate the fee required to be passed into the `send` method. This may be an issue +as we cannot Dry-Run something on Polkadot that has not even been submitted on Ethereum yet. We may need to make RPC API +to DryRun and get back the xcm that would be submitted to asset hub. + +### Step 2: Relayer relays message to Bridge Hub + +On-chain exchange rate is eliminated. Users pay remote delivery costs in ETH, and this amount is sent with the message +as WETH. The delivery fee can be claimed by the relayer on BH. + +The user agent applies a similar dry-running process as with +[Step 2: User agent estimates fees](https://www.notion.so/Step-2-User-agent-estimates-fees-113296aaabef8159bcd0e6dd2e64c3d0?pvs=21). + +The message is converted from $m_0$ to $x_0$ during message submission on BH. Dry-running submission will return $x_0$ +to the relayer so that it can verify it is profitable. + +### Step 3: AH receives $x_0$ from BH + +Submitting the message $m_0$ will cause the following XCM, $x_0$, to be built on BH and dispatched to AH. + +```text +WithdrawAsset (KLT, 100) +ReserveAssetDeposited(WETH, 2) +PayFees (WETH, 1) +SetAssetClaimer Kilt/Bob // derived from beneficiary on final destination +AliasOrigin Ethereum/Alice // derived from msg.sender +InitiateAssetsTransfer asset=(KLT, 100) remoteFee=(WETH, 1) dest=KLT + DepositAsset (KLT, 100) beneficiary=Bob +``` + +```text +WithdrawAsset (KLT, 100) +ReserveAssetDeposited(WETH, 2) +PayFees (WETH, 1) +SetAssetClaimer Kilt/Bob // derived from beneficiary on final destination +AliasOrigin Ethereum/Alice // derived from msg.sender +InitiateAssetsTransfer asset=(KLT, 100) remoteFee=(WETH, 1) dest=KLT + DepositAsset (KLT, 100) beneficiary=Bob + Transact Bob.hello() +``` + +### Step 4: KILT Receives XCM from AH + +The following XCM $x_1$ is received from AH on KILT. + +```text +*WithdrawAsset (KLT, 100) +*ReserveAssetDeposited (WETH, 1) +*PayFees (WETH, 1) +*SetAssetClaimer Ethereum/Alice +*AliasOrigin Ethereum/Alice // origin preserved from AH +SetAssetClaimer Bob +DepositAsset (KLT, 100) beneficiary=Bob +``` + +```text +*WithdrawAsset (KLT, 100) +*ReserveAssetDeposited (WETH, 1) +*PayFees (WETH, 1) +*SetAssetClaimer Ethereum/Alice +*AliasOrigin Ethereum/Alice // origin preserved from AH +SetAssetClaimer Bob +DepositAsset (KLT, 100) beneficiary=Bob +Transact Bob.hello() // executes with the origin from AH +``` + +## Relayer Rewards + +The tracking and disbursement of relayer rewards for both directions has been unified. Rewards are accumulated on BH in +WETH and must be manually claimed. As part of the claims flow, an XCM instruction is sent to AH to mint the WETH into +the deposit account chosen by the relayer. + +To claim, call following extrinsic, where $o$ is rewards account (origin), and $w$ is account on AH where the WETH will +be minted. + +$$ +\mathrm{claim}(o,w) +$$ + +For tax accounting purposes it might be desirable that $o \neq w$. + +## Top-Up + +Top-up of the relayer reward is viable to implement for either direction as extrinsics on Bridge Hub and Ethereum +respectively. + +## Origin Preservation + +Origins for transact will be preserved by use of the `AliasOrigin` instruction. This instruction will have the following +rules that parachain runtimes will need to allow: + +1. `AliasOrigin` can behave like `DescendOrigin`. This is safe because it respects the hierarchy of multi-locations and + does not allow jumping up. Meaning no escalation of privileges. + 1. Example location `Ethereum` can alias into `Ethereum/Alice` because we are descending in origin and this + essentially is how the `DescendOrigin` instruction works. +2. `AliasOrigin` must allow AH to alias into bridged locations such as + `{ parents: 2, interior: GlobalConsensus(Ethereum) }` and all of its internal locations so that AH can act as a proxy + for the bridge on parachains. + +`AliasOrigin` will be inserted by every `InitiateAssetTransfer` instruction on the source parachain, populated with the +contents of the origin register, essentially forwarding the origin of the source to the destination. + +RFCS: + +[https://github.com/polkadot-fellows/RFCs/pull/122](https://github.com/polkadot-fellows/RFCs/pull/122) + +[https://github.com/polkadot-fellows/RFCs/blob/main/text/0100-xcm-multi-type-asset-transfer.md](https://github.com/polkadot-fellows/RFCs/blob/main/text/0100-xcm-multi-type-asset-transfer.md) + +## Parachain Requirements + +1. Pallet-xcm.execute enabled. +2. XCM payment and dry run apis implemented. +3. Must accept WETH needed for fees. Though in future user agents can inject `ExchangeAsset` instructions to obtain + WETH. +4. Trust AH as a reserve for bridged assets. +5. Origin Preservation rules configured which allow asset hub to impersonate bridged addresses. diff --git a/bridges/snowbridge/pallets/ethereum-client/Cargo.toml b/bridges/snowbridge/pallets/ethereum-client/Cargo.toml index 666ac3fbc8a2..262d9a7f380d 100644 --- a/bridges/snowbridge/pallets/ethereum-client/Cargo.toml +++ b/bridges/snowbridge/pallets/ethereum-client/Cargo.toml @@ -49,13 +49,7 @@ serde = { workspace = true, default-features = true } [features] default = ["std"] -fuzzing = [ - "hex-literal", - "pallet-timestamp", - "serde", - "serde_json", - "sp-io", -] +fuzzing = ["hex-literal", "pallet-timestamp", "serde", "serde_json", "sp-io"] std = [ "codec/std", "frame-support/std", diff --git a/bridges/snowbridge/pallets/ethereum-client/fixtures/Cargo.toml b/bridges/snowbridge/pallets/ethereum-client/fixtures/Cargo.toml index bd4176875733..87f0cf9a5513 100644 --- a/bridges/snowbridge/pallets/ethereum-client/fixtures/Cargo.toml +++ b/bridges/snowbridge/pallets/ethereum-client/fixtures/Cargo.toml @@ -29,6 +29,4 @@ std = [ "sp-core/std", "sp-std/std", ] -runtime-benchmarks = [ - "snowbridge-core/runtime-benchmarks", -] +runtime-benchmarks = ["snowbridge-core/runtime-benchmarks"] diff --git a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs index 6894977c21f4..311b54b97dee 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/lib.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/lib.rs @@ -33,7 +33,10 @@ mod tests; mod benchmarking; use frame_support::{ - dispatch::DispatchResult, pallet_prelude::OptionQuery, traits::Get, transactional, + dispatch::{DispatchResult, PostDispatchInfo}, + pallet_prelude::OptionQuery, + traits::Get, + transactional, }; use frame_system::ensure_signed; use snowbridge_beacon_primitives::{ @@ -82,6 +85,9 @@ pub mod pallet { type RuntimeEvent: From> + IsType<::RuntimeEvent>; #[pallet::constant] type ForkVersions: Get; + /// Minimum gap between finalized headers for an update to be free. + #[pallet::constant] + type FreeHeadersInterval: Get; type WeightInfo: WeightInfo; } @@ -173,6 +179,10 @@ pub mod pallet { #[pallet::storage] pub type NextSyncCommittee = StorageValue<_, SyncCommitteePrepared, ValueQuery>; + /// The last period where the next sync committee was updated for free. + #[pallet::storage] + pub type LatestSyncCommitteeUpdatePeriod = StorageValue<_, u64, ValueQuery>; + /// The current operating mode of the pallet. #[pallet::storage] #[pallet::getter(fn operating_mode)] @@ -204,11 +214,10 @@ pub mod pallet { #[transactional] /// Submits a new finalized beacon header update. The update may contain the next /// sync committee. - pub fn submit(origin: OriginFor, update: Box) -> DispatchResult { + pub fn submit(origin: OriginFor, update: Box) -> DispatchResultWithPostInfo { ensure_signed(origin)?; ensure!(!Self::operating_mode().is_halted(), Error::::Halted); - Self::process_update(&update)?; - Ok(()) + Self::process_update(&update) } /// Halt or resume all pallet operations. May only be called by root. @@ -280,10 +289,9 @@ pub mod pallet { Ok(()) } - pub(crate) fn process_update(update: &Update) -> DispatchResult { + pub(crate) fn process_update(update: &Update) -> DispatchResultWithPostInfo { Self::verify_update(update)?; - Self::apply_update(update)?; - Ok(()) + Self::apply_update(update) } /// References and strictly follows @@ -432,11 +440,19 @@ pub mod pallet { /// Reference and strictly follows DispatchResult { + /// SyncCommitteePrepared type. Stores the provided finalized header. Updates are free + /// if the certain conditions specified in `check_refundable` are met. + fn apply_update(update: &Update) -> DispatchResultWithPostInfo { let latest_finalized_state = FinalizedBeaconState::::get(LatestFinalizedBlockRoot::::get()) .ok_or(Error::::NotBootstrapped)?; + + let pays_fee = Self::check_refundable(update, latest_finalized_state.slot); + let actual_weight = match update.next_sync_committee_update { + None => T::WeightInfo::submit(), + Some(_) => T::WeightInfo::submit_with_sync_committee(), + }; + if let Some(next_sync_committee_update) = &update.next_sync_committee_update { let store_period = compute_period(latest_finalized_state.slot); let update_finalized_period = compute_period(update.finalized_header.slot); @@ -460,6 +476,7 @@ pub mod pallet { "💫 SyncCommitteeUpdated at period {}.", update_finalized_period ); + >::set(update_finalized_period); Self::deposit_event(Event::SyncCommitteeUpdated { period: update_finalized_period, }); @@ -469,7 +486,7 @@ pub mod pallet { Self::store_finalized_header(update.finalized_header, update.block_roots_root)?; } - Ok(()) + Ok(PostDispatchInfo { actual_weight: Some(actual_weight), pays_fee }) } /// Computes the signing root for a given beacon header and domain. The hash tree root @@ -634,11 +651,38 @@ pub mod pallet { config::SLOTS_PER_EPOCH as u64, )); let domain_type = config::DOMAIN_SYNC_COMMITTEE.to_vec(); - // Domains are used for for seeds, for signatures, and for selecting aggregators. + // Domains are used for seeds, for signatures, and for selecting aggregators. let domain = Self::compute_domain(domain_type, fork_version, validators_root)?; // Hash tree root of SigningData - object root + domain let signing_root = Self::compute_signing_root(header, domain)?; Ok(signing_root) } + + /// Updates are free if the update is successful and the interval between the latest + /// finalized header in storage and the newly imported header is large enough. All + /// successful sync committee updates are free. + pub(super) fn check_refundable(update: &Update, latest_slot: u64) -> Pays { + // If the sync committee was successfully updated, the update may be free. + let update_period = compute_period(update.finalized_header.slot); + let latest_free_update_period = LatestSyncCommitteeUpdatePeriod::::get(); + // If the next sync committee is not known and this update sets it, the update is free. + // If the sync committee update is in a period that we have not received an update for, + // the update is free. + let refundable = + !>::exists() || update_period > latest_free_update_period; + if update.next_sync_committee_update.is_some() && refundable { + return Pays::No; + } + + // If the latest finalized header is larger than the minimum slot interval, the header + // import transaction is free. + if update.finalized_header.slot >= + latest_slot.saturating_add(T::FreeHeadersInterval::get() as u64) + { + return Pays::No; + } + + Pays::Yes + } } } diff --git a/bridges/snowbridge/pallets/ethereum-client/src/mock.rs b/bridges/snowbridge/pallets/ethereum-client/src/mock.rs index 96298d4fa896..7dbabdee8234 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/mock.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/mock.rs @@ -10,6 +10,7 @@ use sp_std::default::Default; use std::{fs::File, path::PathBuf}; type Block = frame_system::mocking::MockBlock; +use frame_support::traits::ConstU32; use sp_runtime::BuildStorage; fn load_fixture(basename: String) -> Result @@ -58,6 +59,33 @@ pub fn load_next_finalized_header_update_fixture() -> snowbridge_beacon_primitiv load_fixture("next-finalized-header-update.json".to_string()).unwrap() } +pub fn load_sync_committee_update_period_0() -> Box< + snowbridge_beacon_primitives::Update< + { config::SYNC_COMMITTEE_SIZE }, + { config::SYNC_COMMITTEE_BITS_SIZE }, + >, +> { + Box::new(load_fixture("sync-committee-update-period-0.json".to_string()).unwrap()) +} + +pub fn load_sync_committee_update_period_0_older_fixture() -> Box< + snowbridge_beacon_primitives::Update< + { config::SYNC_COMMITTEE_SIZE }, + { config::SYNC_COMMITTEE_BITS_SIZE }, + >, +> { + Box::new(load_fixture("sync-committee-update-period-0-older.json".to_string()).unwrap()) +} + +pub fn load_sync_committee_update_period_0_newer_fixture() -> Box< + snowbridge_beacon_primitives::Update< + { config::SYNC_COMMITTEE_SIZE }, + { config::SYNC_COMMITTEE_BITS_SIZE }, + >, +> { + Box::new(load_fixture("sync-committee-update-period-0-newer.json".to_string()).unwrap()) +} + pub fn get_message_verification_payload() -> (Log, Proof) { let inbound_fixture = snowbridge_pallet_ethereum_client_fixtures::make_inbound_fixture(); (inbound_fixture.message.event_log, inbound_fixture.message.proof) @@ -108,9 +136,12 @@ parameter_types! { }; } +pub const FREE_SLOTS_INTERVAL: u32 = config::SLOTS_PER_EPOCH as u32; + impl ethereum_beacon_client::Config for Test { type RuntimeEvent = RuntimeEvent; type ForkVersions = ChainForkVersions; + type FreeHeadersInterval = ConstU32; type WeightInfo = (); } diff --git a/bridges/snowbridge/pallets/ethereum-client/src/tests.rs b/bridges/snowbridge/pallets/ethereum-client/src/tests.rs index c16743b75ea4..de298ee711d0 100644 --- a/bridges/snowbridge/pallets/ethereum-client/src/tests.rs +++ b/bridges/snowbridge/pallets/ethereum-client/src/tests.rs @@ -1,21 +1,19 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023 Snowfork +pub use crate::mock::*; use crate::{ - functions::compute_period, sync_committee_sum, verify_merkle_branch, BeaconHeader, - CompactBeaconState, Error, FinalizedBeaconState, LatestFinalizedBlockRoot, NextSyncCommittee, - SyncCommitteePrepared, -}; - -use crate::mock::{ - get_message_verification_payload, load_checkpoint_update_fixture, - load_finalized_header_update_fixture, load_next_finalized_header_update_fixture, - load_next_sync_committee_update_fixture, load_sync_committee_update_fixture, + config::{EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT}, + functions::compute_period, + mock::{ + get_message_verification_payload, load_checkpoint_update_fixture, + load_finalized_header_update_fixture, load_next_finalized_header_update_fixture, + load_next_sync_committee_update_fixture, load_sync_committee_update_fixture, + }, + sync_committee_sum, verify_merkle_branch, BeaconHeader, CompactBeaconState, Error, + FinalizedBeaconState, LatestFinalizedBlockRoot, LatestSyncCommitteeUpdatePeriod, + NextSyncCommittee, SyncCommitteePrepared, }; - -pub use crate::mock::*; - -use crate::config::{EPOCHS_PER_SYNC_COMMITTEE_PERIOD, SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT}; -use frame_support::{assert_err, assert_noop, assert_ok}; +use frame_support::{assert_err, assert_noop, assert_ok, pallet_prelude::Pays}; use hex_literal::hex; use snowbridge_beacon_primitives::{ types::deneb, Fork, ForkVersions, NextSyncCommitteeUpdate, VersionedExecutionPayloadHeader, @@ -129,6 +127,39 @@ pub fn compute_domain_bls() { }); } +#[test] +pub fn may_refund_call_fee() { + let finalized_update = Box::new(load_next_finalized_header_update_fixture()); + let sync_committee_update = Box::new(load_sync_committee_update_fixture()); + new_tester().execute_with(|| { + let free_headers_interval: u64 = crate::mock::FREE_SLOTS_INTERVAL as u64; + // Not free, smaller than the allowed free header interval + assert_eq!( + EthereumBeaconClient::check_refundable( + &finalized_update.clone(), + finalized_update.finalized_header.slot + free_headers_interval + ), + Pays::Yes + ); + // Is free, larger than the minimum interval + assert_eq!( + EthereumBeaconClient::check_refundable( + &finalized_update, + finalized_update.finalized_header.slot - (free_headers_interval + 2) + ), + Pays::No + ); + // Is free, valid sync committee update + assert_eq!( + EthereumBeaconClient::check_refundable( + &sync_committee_update, + finalized_update.finalized_header.slot + ), + Pays::No + ); + }); +} + #[test] pub fn verify_merkle_branch_for_finalized_root() { new_tester().execute_with(|| { @@ -340,7 +371,9 @@ fn submit_update_in_current_period() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone())); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone()); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, Pays::No); let block_root: H256 = update.finalized_header.hash_tree_root().unwrap(); assert!(>::contains_key(block_root)); }); @@ -357,7 +390,9 @@ fn submit_update_with_sync_committee_in_current_period() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); assert!(!>::exists()); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update)); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, Pays::No); assert!(>::exists()); }); } @@ -374,20 +409,21 @@ fn reject_submit_update_in_next_period() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit( - RuntimeOrigin::signed(1), - sync_committee_update.clone() - )); + let result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), sync_committee_update.clone()); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, Pays::No); + // check an update in the next period is rejected - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone()), - Error::::SyncCommitteeUpdateRequired - ); + let second_result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone()); + assert_err!(second_result, Error::::SyncCommitteeUpdateRequired); + assert_eq!(second_result.unwrap_err().post_info.pays_fee, Pays::Yes); + // submit update with next sync committee - assert_ok!(EthereumBeaconClient::submit( - RuntimeOrigin::signed(1), - next_sync_committee_update - )); + let third_result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_sync_committee_update); + assert_ok!(third_result); + assert_eq!(third_result.unwrap().pays_fee, Pays::No); // check same header in the next period can now be submitted successfully assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone())); let block_root: H256 = update.finalized_header.clone().hash_tree_root().unwrap(); @@ -407,10 +443,9 @@ fn submit_update_with_invalid_header_proof() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); assert!(!>::exists()); - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update), - Error::::InvalidHeaderMerkleProof - ); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update); + assert_err!(result, Error::::InvalidHeaderMerkleProof); + assert_eq!(result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -426,10 +461,9 @@ fn submit_update_with_invalid_block_roots_proof() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); assert!(!>::exists()); - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update), - Error::::InvalidBlockRootsRootMerkleProof - ); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update); + assert_err!(result, Error::::InvalidBlockRootsRootMerkleProof); + assert_eq!(result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -447,10 +481,9 @@ fn submit_update_with_invalid_next_sync_committee_proof() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); assert!(!>::exists()); - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update), - Error::::InvalidSyncCommitteeMerkleProof - ); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update); + assert_err!(result, Error::::InvalidSyncCommitteeMerkleProof); + assert_eq!(result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -464,14 +497,14 @@ fn submit_update_with_skipped_period() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit( - RuntimeOrigin::signed(1), - sync_committee_update.clone() - )); - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update), - Error::::SkippedSyncCommitteePeriod - ); + let result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), sync_committee_update.clone()); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, Pays::No); + + let second_result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update); + assert_err!(second_result, Error::::SkippedSyncCommitteePeriod); + assert_eq!(second_result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -487,9 +520,16 @@ fn submit_update_with_sync_committee_in_next_period() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); assert!(!>::exists()); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone())); + + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone()); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, Pays::No); assert!(>::exists()); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update.clone())); + + let second_result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update.clone()); + assert_ok!(second_result); + assert_eq!(second_result.unwrap().pays_fee, Pays::No); let last_finalized_state = FinalizedBeaconState::::get(LatestFinalizedBlockRoot::::get()).unwrap(); let last_synced_period = compute_period(last_finalized_state.slot); @@ -505,13 +545,12 @@ fn submit_update_with_sync_committee_invalid_signature_slot() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - // makes a invalid update with signature_slot should be more than attested_slot + // makes an invalid update with signature_slot should be more than attested_slot update.signature_slot = update.attested_header.slot; - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update), - Error::::InvalidUpdateSlot - ); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update); + assert_err!(result, Error::::InvalidUpdateSlot); + assert_eq!(result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -525,10 +564,9 @@ fn submit_update_with_skipped_sync_committee_period() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_update), - Error::::SkippedSyncCommitteePeriod - ); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), finalized_update); + assert_err!(result, Error::::SkippedSyncCommitteePeriod); + assert_eq!(result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -546,10 +584,9 @@ fn submit_irrelevant_update() { update.attested_header.slot = checkpoint.header.slot; update.signature_slot = checkpoint.header.slot + 1; - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update), - Error::::IrrelevantUpdate - ); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update); + assert_err!(result, Error::::IrrelevantUpdate); + assert_eq!(result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -558,10 +595,9 @@ fn submit_update_with_missing_bootstrap() { let update = Box::new(load_next_finalized_header_update_fixture()); new_tester().execute_with(|| { - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update), - Error::::NotBootstrapped - ); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update); + assert_err!(result, Error::::NotBootstrapped); + assert_eq!(result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -574,7 +610,9 @@ fn submit_update_with_invalid_sync_committee_update() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update)); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, Pays::No); // makes update with invalid next_sync_committee >::mutate(>::get(), |x| { @@ -586,10 +624,9 @@ fn submit_update_with_invalid_sync_committee_update() { let next_sync_committee = NextSyncCommitteeUpdate::default(); next_update.next_sync_committee_update = Some(next_sync_committee); - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update), - Error::::InvalidSyncCommitteeUpdate - ); + let second_result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update); + assert_err!(second_result, Error::::InvalidSyncCommitteeUpdate); + assert_eq!(second_result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -612,12 +649,15 @@ fn submit_finalized_header_update_with_too_large_gap() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone())); + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone()); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, Pays::No); assert!(>::exists()); - assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update.clone()), - Error::::InvalidFinalizedHeaderGap - ); + + let second_result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update.clone()); + assert_err!(second_result, Error::::InvalidFinalizedHeaderGap); + assert_eq!(second_result.unwrap_err().post_info.pays_fee, Pays::Yes); }); } @@ -637,14 +677,89 @@ fn submit_finalized_header_update_with_gap_at_limit() { new_tester().execute_with(|| { assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); - assert_ok!(EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone())); + + let result = EthereumBeaconClient::submit(RuntimeOrigin::signed(1), update.clone()); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, Pays::No); assert!(>::exists()); + + let second_result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update.clone()); assert_err!( - EthereumBeaconClient::submit(RuntimeOrigin::signed(1), next_update.clone()), + second_result, // The test should pass the InvalidFinalizedHeaderGap check, and will fail at the // next check, the merkle proof, because we changed the next_update slots. Error::::InvalidHeaderMerkleProof ); + assert_eq!(second_result.unwrap_err().post_info.pays_fee, Pays::Yes); + }); +} + +#[test] +fn duplicate_sync_committee_updates_are_not_free() { + let checkpoint = Box::new(load_checkpoint_update_fixture()); + let sync_committee_update = Box::new(load_sync_committee_update_fixture()); + + new_tester().execute_with(|| { + assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); + let result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), sync_committee_update.clone()); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, Pays::No); + + // Check that if the same update is submitted, the update is not free. + let second_result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), sync_committee_update); + assert_ok!(second_result); + assert_eq!(second_result.unwrap().pays_fee, Pays::Yes); + }); +} + +#[test] +fn sync_committee_update_for_sync_committee_already_imported_are_not_free() { + let checkpoint = Box::new(load_checkpoint_update_fixture()); + let sync_committee_update = Box::new(load_sync_committee_update_fixture()); // slot 129 + let second_sync_committee_update = load_sync_committee_update_period_0(); // slot 128 + let third_sync_committee_update = load_sync_committee_update_period_0_newer_fixture(); // slot 224 + let fourth_sync_committee_update = load_sync_committee_update_period_0_older_fixture(); // slot 96 + let fith_sync_committee_update = Box::new(load_next_sync_committee_update_fixture()); // slot 8259 + + new_tester().execute_with(|| { + assert_ok!(EthereumBeaconClient::process_checkpoint_update(&checkpoint)); + assert_eq!(>::get(), 0); + + // Check that setting the next sync committee for period 0 is free (it is not set yet). + let result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), sync_committee_update.clone()); + assert_ok!(result); + assert_eq!(result.unwrap().pays_fee, Pays::No); + assert_eq!(>::get(), 0); + + // Check that setting the next sync committee for period 0 again is not free. + let second_result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), second_sync_committee_update); + assert_eq!(second_result.unwrap().pays_fee, Pays::Yes); + assert_eq!(>::get(), 0); + + // Check that setting an update with a sync committee that has already been set, but with a + // newer finalized header, is free. + let third_result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), third_sync_committee_update); + assert_eq!(third_result.unwrap().pays_fee, Pays::No); + assert_eq!(>::get(), 0); + + // Check that setting the next sync committee for period 0 again with an earlier slot is not + // free. + let fourth_result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), fourth_sync_committee_update); + assert_err!(fourth_result, Error::::IrrelevantUpdate); + assert_eq!(fourth_result.unwrap_err().post_info.pays_fee, Pays::Yes); + + // Check that setting the next sync committee for period 1 is free. + let fith_result = + EthereumBeaconClient::submit(RuntimeOrigin::signed(1), fith_sync_committee_update); + assert_eq!(fith_result.unwrap().pays_fee, Pays::No); + assert_eq!(>::get(), 1); }); } diff --git a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/initial-checkpoint.json b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/initial-checkpoint.json index a62d646617e4..34e65d20b885 100755 --- a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/initial-checkpoint.json +++ b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/initial-checkpoint.json @@ -1,10 +1,10 @@ { "header": { - "slot": 864, + "slot": 64, "proposer_index": 4, - "parent_root": "0x614e7672f991ac268cd841055973f55e1e42228831a211adef207bb7329be614", - "state_root": "0x5fa8dfca3d760e4242ab46d529144627aa85348a19173b6e081172c701197a4a", - "body_root": "0x0f34c083b1803666bb1ac5e73fa71582731a2cf37d279ff0a3b0cad5a2ff371e" + "parent_root": "0x88e5b7e0dd468b334caf9281e0665184d2d712d7ffe632123ea07631b714920c", + "state_root": "0x82771f834d4d896f4969abdaf45f28f49a7437ecfca7bf2f7db7bfac5ca7224f", + "body_root": "0x8b36f34ceba40a29c9c6fa6266564c7df30ea75fecf1a85e6ec1cb4aabf4dc68" }, "current_sync_committee": { "pubkeys": [ @@ -525,18 +525,18 @@ }, "current_sync_committee_branch": [ "0x3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59", - "0xa9e90f89e7f90fd5d79a6bbcaf40ba5cfc05ab1b561ac51c84867c32248d5b1e", - "0xbd1a76b03e02402bb24a627de1980a80ab17691980271f597b844b89b497ef75", - "0x07bbcd27c7cad089023db046eda17e8209842b7d97add8b873519e84fe6480e7", - "0x94c11eeee4cb6192bf40810f23486d8c75dfbc2b6f28d988d6f74435ede243b0" + "0x058baa5628d6156e55ab99da54244be4a071978528f2eb3b19a4f4d7ab36f870", + "0x5f89984c1068b616e99589e161d2bb73b92c68b3422ef309ace434894b4503ae", + "0x4f1c230cf2bbe39502171956421fbe4f1c0a71a9691944019047b84584b371d5", + "0xbf8d5f6021db16e9b50e639e5c489eb8dc06449bf4ed17045cb949cb89a58a04" ], "validators_root": "0x270d43e74ce340de4bca2b1936beca0f4f5408d9e78aec4850920baf659d5b69", - "block_roots_root": "0xb9aab9c388c4e4fcd899b71f62c498fc73406e38e8eb14aa440e9affa06f2a10", + "block_roots_root": "0x2c453665ba6fc024116daf5246126e36085c61257cfbcce69d0bdcf89c766dc0", "block_roots_branch": [ - "0x733422bd810895dab74cbbe07c69dd440cbb51f573181ad4dddac30fcdd0f41f", - "0x9b9eca73ab01d14549c325ba1b4610bb20bf1f8ec2dbd649f9d8cc7f3cea75fa", - "0xbcc666ad0ad9f9725cbd682bc95589d35b1b53b2a615f1e6e8dd5e086336becf", - "0x3069b547a08f703a1715016e926cbd64e71f93f64fb68d98d8c8f1ab745c46e5", - "0xc2de7e1097239404e17b263cfa0473533cc41e903cb03440d633bc5c27314cb4" + "0xbd04f51e43f63b0be48034920e8f5976111b7717225abccedbc6bcb327b95d00", + "0x758319a3bad11ee10fde1036551d982583c0392f284de5cc429b67fbd74c25d5", + "0xb42179d040c2bec20fa0a2750baf225b8097b5c9e4e22af9250cc773f4259427", + "0x5340ad5877c72dca689ca04bc8fedb78d67a4801d99887937edd8ccd29f87e82", + "0x9f03be8e70f74fc6b51e6ed03c96aabb544b5c50e5cdb8c0ab5001d1249d55f0" ] -} \ No newline at end of file +} diff --git a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/sync-committee-update-period-0-newer.json b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/sync-committee-update-period-0-newer.json new file mode 100755 index 000000000000..7139589acbce --- /dev/null +++ b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/sync-committee-update-period-0-newer.json @@ -0,0 +1,565 @@ +{ + "attested_header": { + "slot": 224, + "proposer_index": 0, + "parent_root": "0xecfba5f579f43f474039f6f9abce51eb5607f6295aa45e1c353fa20245ab4efb", + "state_root": "0x10b21ccac4df114a9c30eaaff57f064b692e957a52eb43a8264702da76ba81f7", + "body_root": "0x6bd1768f675673b4ae32a197f569f7d279568fd5f60d32bd6ea11ecff559fc35" + }, + "sync_aggregate": { + "sync_committee_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000", + "sync_committee_signature": "0xb8f4800cb32edf6d05e9cace783d663719f7750f0438b8481c89895809c5430005df25b73393133c9df595e5998d6a540449d8840f8bd16474608bb0b9daa349b76429d8d7e314f2fb6e628c4f68c5469bc8c698bb232a767a4b080b8909aa53" + }, + "signature_slot": 225, + "next_sync_committee_update": { + "next_sync_committee": { + "pubkeys": [ + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b" + ], + "aggregate_pubkey": "0x8fbd66eeec2ff69ef0b836f04b1d67d88bcd4dfd495061964ad757c77abe822a39fa1cd8ed0d4d9bc9276cea73fd745c" + }, + "next_sync_committee_branch": [ + "0x3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59", + "0xaad994f17223061c45fb5ec4930b2da08512e221ca6857bde8929eda92dc115c", + "0x61145312b89c006c2d1406285a9f2f826679d20b00239f65f76d40e28abe3bca", + "0x37977cb0ebd513f5123ede3a57b228f31eb98ecaad7757cf8e405fee8224982e", + "0x8c24e3a8ddb0bad93d5dcd240f566c5d08bc381a58b94e337bed63f75104fe45" + ] + }, + "finalized_header": { + "slot": 160, + "proposer_index": 0, + "parent_root": "0x6b536af592b64a337ae033b9646c4a10fd3369be72fcdaf53ae37797df8ec581", + "state_root": "0x1ed5990e4a1188a49ee64cdeb0ee9e480f29ce4d8020a0c5407471771a76ef2d", + "body_root": "0x73fb27d7521c84855007a824231d3b2b1650cd9ee34d914625f692c36b8112ef" + }, + "finality_branch": [ + "0x0500000000000000000000000000000000000000000000000000000000000000", + "0x10c726fac935bf9657cc7476d3cfa7bedec5983dcfb59e8a7df6d0a619e108d7", + "0x98e9116c6bb7f20de18800dc63e73e689d06d6a47d35b5e2b32cf093d475840d", + "0x61145312b89c006c2d1406285a9f2f826679d20b00239f65f76d40e28abe3bca", + "0x37977cb0ebd513f5123ede3a57b228f31eb98ecaad7757cf8e405fee8224982e", + "0x8c24e3a8ddb0bad93d5dcd240f566c5d08bc381a58b94e337bed63f75104fe45" + ], + "block_roots_root": "0xa626dafac4b71585a5b18d18198d7e7c0a09c43b0fb3f2e68e04304d3be94b91", + "block_roots_branch": [ + "0x1a4ced7954adc2f360994137f07d1ae456b008d5ff81f40f252da770a0cd70c9", + "0xa6d595807cef4f868a03813aceb42f07fadf37f93d5b30a3603f55c1eab0081d", + "0x50f2310554199f26d4a326c940dd6e014db55bb8f18bf3642fed22e58ddb5dd6", + "0xd8a7fed47a6e1934c5a5750a44aa70de9898c42e877fc87f0acb0e1b9d236091", + "0xad421833151ec4b8fd8269f16b4b41f15e7e0b82d561553ed5a50e5d6c5f2190" + ], + "execution_header": null, + "execution_branch": null +} \ No newline at end of file diff --git a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/sync-committee-update-period-0-older.json b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/sync-committee-update-period-0-older.json new file mode 100755 index 000000000000..b0eff7cac1b0 --- /dev/null +++ b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/sync-committee-update-period-0-older.json @@ -0,0 +1,565 @@ +{ + "attested_header": { + "slot": 96, + "proposer_index": 5, + "parent_root": "0x711c0cbebb834c0cd47d74732d78bc9f4794be2d7805176a4613ebaa9546569e", + "state_root": "0xe5ee40ae4ce991c927de404f3aea3209a55f29b54ee96d146c1e9fb733e14018", + "body_root": "0x57953c9bb22c5231b07078e6a3d82bd85ccdf48f55b4bb410c20af4cf4c3b03e" + }, + "sync_aggregate": { + "sync_committee_bits": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sync_committee_signature": "0xa8a01929a4018d7f5cf3d0511b68ae6af1e32320a263d282ff85bf56860154bd70cd9b0b0f4aa7a956d0375b9b4ba6700c723fcaaeb577acd9a0a88baf0bb418e39f97b17b1edcaeb95fa086d4c5d410addc9f29c0b6c6c14775216cdcb828db" + }, + "signature_slot": 97, + "next_sync_committee_update": { + "next_sync_committee": { + "pubkeys": [ + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b" + ], + "aggregate_pubkey": "0x8fbd66eeec2ff69ef0b836f04b1d67d88bcd4dfd495061964ad757c77abe822a39fa1cd8ed0d4d9bc9276cea73fd745c" + }, + "next_sync_committee_branch": [ + "0x3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59", + "0x48118ce24b62eda9ed2d37108f94efe223e6a385d84bcec6b2a53584271ea001", + "0xd72abb2443691ce25174da082c4c60880775d67f83802afd73cc2bf0edd06f73", + "0x0de609b4a50cd2729a8f9d9b6a505b008555dc121b18fb99c148be86ae08a53e", + "0xfb86aae7b54b08642d51132227e409e5247fa9ddb24287deab442ebf5dd9146c" + ] + }, + "finalized_header": { + "slot": 64, + "proposer_index": 4, + "parent_root": "0x60e496771388130ba1dc1d5d447bd43b4a5026a5d17d20f34d5352c0a97e5585", + "state_root": "0x7007a070c06dbd1c6de2f6fb1288f6569a13a00a1ed7505a8b1ede38827dd39c", + "body_root": "0xbccefd80ea680aa944837ec75d660651f369f72724f125e871b787c3dab18ea4" + }, + "finality_branch": [ + "0x0200000000000000000000000000000000000000000000000000000000000000", + "0x10c726fac935bf9657cc7476d3cfa7bedec5983dcfb59e8a7df6d0a619e108d7", + "0x98e9116c6bb7f20de18800dc63e73e689d06d6a47d35b5e2b32cf093d475840d", + "0xd72abb2443691ce25174da082c4c60880775d67f83802afd73cc2bf0edd06f73", + "0x0de609b4a50cd2729a8f9d9b6a505b008555dc121b18fb99c148be86ae08a53e", + "0xfb86aae7b54b08642d51132227e409e5247fa9ddb24287deab442ebf5dd9146c" + ], + "block_roots_root": "0xf70c00c84139e631f8d4a69120f5837e5d14db26aee6aa29f5a6a100b53f820b", + "block_roots_branch": [ + "0x3c2f0c8588c1501bcd371de7103ad74ae93fe72b4703a1bd00fd77acefd90c76", + "0x8ac33e1bd9a7fa543236bf6f385b6082bb6e68ec344d0bc03e620dd908df4b07", + "0x56e652a369b875c2f28e96d341ed76ca453e2f5a0ee2ca571a9ae19d92e842df", + "0x5340ad5877c72dca689ca04bc8fedb78d67a4801d99887937edd8ccd29f87e82", + "0x91eee53bd353a3e021e2c382d9502503b7f9f1198b042ff36e8abdc74fd920dc" + ], + "execution_header": null, + "execution_branch": null +} \ No newline at end of file diff --git a/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/sync-committee-update-period-0.json b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/sync-committee-update-period-0.json new file mode 100644 index 000000000000..916deb7513c8 --- /dev/null +++ b/bridges/snowbridge/pallets/ethereum-client/tests/fixtures/sync-committee-update-period-0.json @@ -0,0 +1,565 @@ +{ + "attested_header": { + "slot": 128, + "proposer_index": 1, + "parent_root": "0x2161b169bc9dda1785a8c087e6455d9648d8df8c6d5f98f75d29c1c1c9e13ceb", + "state_root": "0x044bb5ec8eabc0ba7a74646cb92e4c6bd96f5d2974e0e191d3fd05de4eb1acea", + "body_root": "0x2b52b7dbe94cd1c024431064486880f2093480498f2b8a704fec9edc34f68eb8" + }, + "sync_aggregate": { + "sync_committee_bits": "0x00000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sync_committee_signature": "0x95ceea859d98d209441120821af32fa7ceb6080cf62db7a00a0f578ac83a4a1c619104474e715d1688732e8fe5b19f2417a4f6ba957b3cd2b8c817c8d8c42fc822062385269858feb955cd010744d8357dffef00535cf2e7a1017e58b22c4423" + }, + "signature_slot": 129, + "next_sync_committee_update": { + "next_sync_committee": { + "pubkeys": [ + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b", + "0xab0bdda0f85f842f431beaccf1250bf1fd7ba51b4100fd64364b6401fda85bb0069b3e715b58819684e7fc0b10a72a34", + "0xa8d4c7c27795a725961317ef5953a7032ed6d83739db8b0e8a72353d1b8b4439427f7efa2c89caa03cc9f28f8cbab8ac", + "0x9977f1c8b731a8d5558146bfb86caea26434f3c5878b589bf280a42c9159e700e9df0e4086296c20b011d2e78c27d373", + "0xb89bebc699769726a318c8e9971bd3171297c61aea4a6578a7a4f94b547dcba5bac16a89108b6b6a1fe3695d1a874a0b", + "0x81283b7a20e1ca460ebd9bbd77005d557370cabb1f9a44f530c4c4c66230f675f8df8b4c2818851aa7d77a80ca5a4a5e", + "0x88c141df77cd9d8d7a71a75c826c41a9c9f03c6ee1b180f3e7852f6a280099ded351b58d66e653af8e42816a4d8f532e", + "0xa99a76ed7796f7be22d5b7e85deeb7c5677e88e511e0b337618f8c4eb61349b4bf2d153f649f7b53359fe8b94a38e44c", + "0xa3a32b0f8b4ddb83f1a0a853d81dd725dfe577d4f4c3db8ece52ce2b026eca84815c1a7e8e92a4de3d755733bf7e4a9b" + ], + "aggregate_pubkey": "0x8fbd66eeec2ff69ef0b836f04b1d67d88bcd4dfd495061964ad757c77abe822a39fa1cd8ed0d4d9bc9276cea73fd745c" + }, + "next_sync_committee_branch": [ + "0x3ade38d498a062b50880a9409e1ca3a7fd4315d91eeb3bb83e56ac6bfe8d6a59", + "0x028330a337168f77730425239a3abdfe336671cf5047fd03ea84eb668a0bad9e", + "0xe2b84cae247ad985d1d089df0f668f7f29ba1db750e5f32159e002dcda2d3f5f", + "0xecf54973b62af22f2620c37c14138021e5ea274f80815a52b3ed6c6234e039da", + "0x63a9c666a4d51dbfceda9b1c9dac57019fce464fd5733e6a6598dde49cc4ea23" + ] + }, + "finalized_header": { + "slot": 64, + "proposer_index": 4, + "parent_root": "0x88e5b7e0dd468b334caf9281e0665184d2d712d7ffe632123ea07631b714920c", + "state_root": "0x82771f834d4d896f4969abdaf45f28f49a7437ecfca7bf2f7db7bfac5ca7224f", + "body_root": "0x8b36f34ceba40a29c9c6fa6266564c7df30ea75fecf1a85e6ec1cb4aabf4dc68" + }, + "finality_branch": [ + "0x0200000000000000000000000000000000000000000000000000000000000000", + "0x10c726fac935bf9657cc7476d3cfa7bedec5983dcfb59e8a7df6d0a619e108d7", + "0x98e9116c6bb7f20de18800dc63e73e689d06d6a47d35b5e2b32cf093d475840d", + "0xe2b84cae247ad985d1d089df0f668f7f29ba1db750e5f32159e002dcda2d3f5f", + "0xecf54973b62af22f2620c37c14138021e5ea274f80815a52b3ed6c6234e039da", + "0x63a9c666a4d51dbfceda9b1c9dac57019fce464fd5733e6a6598dde49cc4ea23" + ], + "block_roots_root": "0x2c453665ba6fc024116daf5246126e36085c61257cfbcce69d0bdcf89c766dc0", + "block_roots_branch": [ + "0xbd04f51e43f63b0be48034920e8f5976111b7717225abccedbc6bcb327b95d00", + "0x758319a3bad11ee10fde1036551d982583c0392f284de5cc429b67fbd74c25d5", + "0xb42179d040c2bec20fa0a2750baf225b8097b5c9e4e22af9250cc773f4259427", + "0x5340ad5877c72dca689ca04bc8fedb78d67a4801d99887937edd8ccd29f87e82", + "0x9f03be8e70f74fc6b51e6ed03c96aabb544b5c50e5cdb8c0ab5001d1249d55f0" + ], + "execution_header": null, + "execution_branch": null +} \ No newline at end of file diff --git a/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml b/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml index b66b57c3620a..6162a17728b6 100644 --- a/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml +++ b/bridges/snowbridge/pallets/inbound-queue/fixtures/Cargo.toml @@ -29,6 +29,4 @@ std = [ "sp-core/std", "sp-std/std", ] -runtime-benchmarks = [ - "snowbridge-core/runtime-benchmarks", -] +runtime-benchmarks = ["snowbridge-core/runtime-benchmarks"] diff --git a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs index 4a1486204eb0..423b92b9fae0 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/lib.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/lib.rs @@ -48,12 +48,11 @@ use frame_support::{ }; use frame_system::ensure_signed; use scale_info::TypeInfo; -use sp_core::{H160, H256}; +use sp_core::H160; use sp_runtime::traits::Zero; use sp_std::vec; use xcm::prelude::{ - send_xcm, Instruction::SetTopic, Junction::*, Location, SendError as XcmpSendError, SendXcm, - Xcm, XcmContext, XcmHash, + send_xcm, Junction::*, Location, SendError as XcmpSendError, SendXcm, Xcm, XcmContext, XcmHash, }; use xcm_executor::traits::TransactAsset; @@ -62,9 +61,8 @@ use snowbridge_core::{ sibling_sovereign_account, BasicOperatingMode, Channel, ChannelId, ParaId, PricingParameters, StaticLookup, }; -use snowbridge_router_primitives::{ - inbound, - inbound::{ConvertMessage, ConvertMessageError}, +use snowbridge_router_primitives::inbound::{ + ConvertMessage, ConvertMessageError, VersionedMessage, }; use sp_runtime::{traits::Saturating, SaturatedConversion, TokenError}; @@ -86,6 +84,7 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + use sp_core::H256; #[pallet::pallet] pub struct Pallet(_); @@ -276,12 +275,12 @@ pub mod pallet { T::Token::transfer(&sovereign_account, &who, amount, Preservation::Preserve)?; } + // Decode payload into `VersionedMessage` + let message = VersionedMessage::decode_all(&mut envelope.payload.as_ref()) + .map_err(|_| Error::::InvalidPayload)?; + // Decode message into XCM - let (xcm, fee) = - match inbound::VersionedMessage::decode_all(&mut envelope.payload.as_ref()) { - Ok(message) => Self::do_convert(envelope.message_id, message)?, - Err(_) => return Err(Error::::InvalidPayload.into()), - }; + let (xcm, fee) = Self::do_convert(envelope.message_id, message.clone())?; log::info!( target: LOG_TARGET, @@ -323,12 +322,10 @@ pub mod pallet { impl Pallet { pub fn do_convert( message_id: H256, - message: inbound::VersionedMessage, + message: VersionedMessage, ) -> Result<(Xcm<()>, BalanceOf), Error> { - let (mut xcm, fee) = - T::MessageConverter::convert(message).map_err(|e| Error::::ConvertMessage(e))?; - // Append the message id as an XCM topic - xcm.inner_mut().extend(vec![SetTopic(message_id.into())]); + let (xcm, fee) = T::MessageConverter::convert(message_id, message) + .map_err(|e| Error::::ConvertMessage(e))?; Ok((xcm, fee)) } diff --git a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs index a031676c6076..3e67d5ab738b 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/mock.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/mock.rs @@ -10,12 +10,12 @@ use snowbridge_beacon_primitives::{ use snowbridge_core::{ gwei, inbound::{Log, Proof, VerificationError}, - meth, Channel, ChannelId, PricingParameters, Rewards, StaticLookup, + meth, Channel, ChannelId, PricingParameters, Rewards, StaticLookup, TokenId, }; use snowbridge_router_primitives::inbound::MessageToXcm; use sp_core::{H160, H256}; use sp_runtime::{ - traits::{IdentifyAccount, IdentityLookup, Verify}, + traits::{IdentifyAccount, IdentityLookup, MaybeEquivalence, Verify}, BuildStorage, FixedU128, MultiSignature, }; use sp_std::{convert::From, default::Default}; @@ -88,6 +88,7 @@ parameter_types! { impl snowbridge_pallet_ethereum_client::Config for Test { type RuntimeEvent = RuntimeEvent; type ForkVersions = ChainForkVersions; + type FreeHeadersInterval = ConstU32<32>; type WeightInfo = (); } @@ -111,6 +112,9 @@ parameter_types! { pub const SendTokenExecutionFee: u128 = 1_000_000_000; pub const InitialFund: u128 = 1_000_000_000_000; pub const InboundQueuePalletInstance: u8 = 80; + pub UniversalLocation: InteriorLocation = + [GlobalConsensus(Westend), Parachain(1002)].into(); + pub AssetHubFromEthereum: Location = Location::new(1,[GlobalConsensus(Westend),Parachain(1000)]); } #[cfg(feature = "runtime-benchmarks")] @@ -204,6 +208,16 @@ impl TransactAsset for SuccessfulTransactor { } } +pub struct MockTokenIdConvert; +impl MaybeEquivalence for MockTokenIdConvert { + fn convert(_id: &TokenId) -> Option { + Some(Location::parent()) + } + fn convert_back(_loc: &Location) -> Option { + None + } +} + impl inbound_queue::Config for Test { type RuntimeEvent = RuntimeEvent; type Verifier = MockVerifier; @@ -217,6 +231,9 @@ impl inbound_queue::Config for Test { InboundQueuePalletInstance, AccountId, Balance, + MockTokenIdConvert, + UniversalLocation, + AssetHubFromEthereum, >; type PricingParameters = Parameters; type ChannelLookup = MockChannelLookup; diff --git a/bridges/snowbridge/pallets/inbound-queue/src/test.rs b/bridges/snowbridge/pallets/inbound-queue/src/test.rs index bd993c968df7..41c38460aabf 100644 --- a/bridges/snowbridge/pallets/inbound-queue/src/test.rs +++ b/bridges/snowbridge/pallets/inbound-queue/src/test.rs @@ -40,8 +40,8 @@ fn test_submit_happy_path() { .into(), nonce: 1, message_id: [ - 57, 61, 232, 3, 66, 61, 25, 190, 234, 188, 193, 174, 13, 186, 1, 64, 237, 94, 73, - 83, 14, 18, 209, 213, 78, 121, 43, 108, 251, 245, 107, 67, + 255, 125, 48, 71, 174, 185, 100, 26, 159, 43, 108, 6, 116, 218, 55, 155, 223, 143, + 141, 22, 124, 110, 241, 18, 122, 217, 130, 29, 139, 76, 97, 201, ], fee_burned: 110000000000, } diff --git a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml index 00cc700fbe83..16241428df80 100644 --- a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml +++ b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/Cargo.toml @@ -23,16 +23,11 @@ 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"] -std = [ - "codec/std", - "scale-info/std", - "sp-core/std", - "sp-runtime/std", -] +std = ["codec/std", "scale-info/std", "sp-core/std", "sp-runtime/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 8c91ccd04d9a..eeeaa6e68cf9 100644 --- a/bridges/snowbridge/pallets/outbound-queue/merkle-tree/src/lib.rs +++ b/bridges/snowbridge/pallets/outbound-queue/merkle-tree/src/lib.rs @@ -182,12 +182,6 @@ where let root = merkelize::(hashes.into_iter(), &mut collect_proof); let leaf = leaf.expect("Requested `leaf_index` is greater than number of leaves."); - #[cfg(feature = "debug")] - log::debug!( - "[merkle_proof] Proof: {:?}", - collect_proof.proof.iter().map(hex::encode).collect::>() - ); - MerkleProof { root, proof: collect_proof.proof, number_of_leaves, leaf_index, leaf } } @@ -274,8 +268,6 @@ where V: Visitor, I: Iterator, { - #[cfg(feature = "debug")] - log::debug!("[merkelize_row]"); next.clear(); let hash_len = ::LENGTH; @@ -286,9 +278,6 @@ where let b = iter.next(); visitor.visit(index, &a, &b); - #[cfg(feature = "debug")] - log::debug!(" {:?}\n {:?}", a.as_ref().map(hex::encode), b.as_ref().map(hex::encode)); - index += 2; match (a, b) { (Some(a), Some(b)) => { @@ -309,14 +298,7 @@ where // Last item = root. (Some(a), None) => return Ok(a), // Finish up, no more items. - _ => { - #[cfg(feature = "debug")] - log::debug!( - "[merkelize_row] Next: {:?}", - next.iter().map(hex::encode).collect::>() - ); - return Err(next) - }, + _ => return Err(next), } } } @@ -335,7 +317,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 +333,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 +349,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 +364,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 +383,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 +440,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/bridges/snowbridge/pallets/outbound-queue/src/mock.rs b/bridges/snowbridge/pallets/outbound-queue/src/mock.rs index d65a96e2702d..0b34893333e4 100644 --- a/bridges/snowbridge/pallets/outbound-queue/src/mock.rs +++ b/bridges/snowbridge/pallets/outbound-queue/src/mock.rs @@ -164,13 +164,11 @@ pub fn mock_message(sibling_para_id: u32) -> Message { Message { id: None, channel_id: ParaId::from(sibling_para_id).into(), - command: Command::AgentExecute { + command: Command::TransferNativeToken { agent_id: Default::default(), - command: AgentExecuteCommand::TransferToken { - token: Default::default(), - recipient: Default::default(), - amount: 0, - }, + token: Default::default(), + recipient: Default::default(), + amount: 0, }, } } diff --git a/bridges/snowbridge/pallets/system/src/benchmarking.rs b/bridges/snowbridge/pallets/system/src/benchmarking.rs index ef908ad6a3f9..20798b7c3493 100644 --- a/bridges/snowbridge/pallets/system/src/benchmarking.rs +++ b/bridges/snowbridge/pallets/system/src/benchmarking.rs @@ -159,6 +159,29 @@ mod benchmarks { Ok(()) } + #[benchmark] + fn register_token() -> Result<(), BenchmarkError> { + let caller: T::AccountId = whitelisted_caller(); + + let amount: BalanceOf = + (10_000_000_000_000_u128).saturated_into::().saturated_into(); + + T::Token::mint_into(&caller, amount)?; + + let relay_token_asset_id: Location = Location::parent(); + let asset = Box::new(VersionedLocation::V4(relay_token_asset_id)); + let asset_metadata = AssetMetadata { + name: "wnd".as_bytes().to_vec().try_into().unwrap(), + symbol: "wnd".as_bytes().to_vec().try_into().unwrap(), + decimals: 12, + }; + + #[extrinsic_call] + _(RawOrigin::Root, asset, asset_metadata); + + Ok(()) + } + impl_benchmark_test_suite!( SnowbridgeControl, crate::mock::new_test_ext(true), diff --git a/bridges/snowbridge/pallets/system/src/lib.rs b/bridges/snowbridge/pallets/system/src/lib.rs index 39c73e3630e7..1e8a788b7a5a 100644 --- a/bridges/snowbridge/pallets/system/src/lib.rs +++ b/bridges/snowbridge/pallets/system/src/lib.rs @@ -35,8 +35,14 @@ //! //! Typically, Polkadot governance will use the `force_transfer_native_from_agent` and //! `force_update_channel` and extrinsics to manage agents and channels for system parachains. +//! +//! ## Polkadot-native tokens on Ethereum +//! +//! Tokens deposited on AssetHub pallet can be bridged to Ethereum as wrapped ERC20 tokens. As a +//! prerequisite, the token should be registered first. +//! +//! * [`Call::register_token`]: Register a token location as a wrapped ERC20 contract on Ethereum. #![cfg_attr(not(feature = "std"), no_std)] - #[cfg(test)] mod mock; @@ -63,13 +69,16 @@ use frame_system::pallet_prelude::*; use snowbridge_core::{ meth, outbound::{Command, Initializer, Message, OperatingMode, SendError, SendMessage}, - sibling_sovereign_account, AgentId, Channel, ChannelId, ParaId, - PricingParameters as PricingParametersRecord, PRIMARY_GOVERNANCE_CHANNEL, + sibling_sovereign_account, AgentId, AssetMetadata, Channel, ChannelId, ParaId, + PricingParameters as PricingParametersRecord, TokenId, TokenIdOf, PRIMARY_GOVERNANCE_CHANNEL, SECONDARY_GOVERNANCE_CHANNEL, }; use sp_core::{RuntimeDebug, H160, H256}; use sp_io::hashing::blake2_256; -use sp_runtime::{traits::BadOrigin, DispatchError, SaturatedConversion}; +use sp_runtime::{ + traits::{BadOrigin, MaybeEquivalence}, + DispatchError, SaturatedConversion, +}; use sp_std::prelude::*; use xcm::prelude::*; use xcm_executor::traits::ConvertLocation; @@ -99,7 +108,7 @@ where } /// Hash the location to produce an agent id -fn agent_id_of(location: &Location) -> Result { +pub fn agent_id_of(location: &Location) -> Result { T::AgentIdOf::convert_location(location).ok_or(Error::::LocationConversionFailed.into()) } @@ -127,6 +136,7 @@ where #[frame_support::pallet] pub mod pallet { + use frame_support::dispatch::PostDispatchInfo; use snowbridge_core::StaticLookup; use sp_core::U256; @@ -164,6 +174,12 @@ pub mod pallet { type WeightInfo: WeightInfo; + /// This chain's Universal Location. + type UniversalLocation: Get; + + // The bridges configured Ethereum location + type EthereumLocation: Get; + #[cfg(feature = "runtime-benchmarks")] type Helper: BenchmarkHelper; } @@ -211,6 +227,13 @@ pub mod pallet { PricingParametersChanged { params: PricingParametersOf, }, + /// Register Polkadot-native token as a wrapped ERC20 token on Ethereum + RegisterToken { + /// Location of Polkadot-native token + location: VersionedLocation, + /// ID of Polkadot-native token on Ethereum + foreign_token_id: H256, + }, } #[pallet::error] @@ -243,6 +266,16 @@ pub mod pallet { pub type PricingParameters = StorageValue<_, PricingParametersOf, ValueQuery, T::DefaultPricingParameters>; + /// Lookup table for foreign token ID to native location relative to ethereum + #[pallet::storage] + pub type ForeignToNativeId = + StorageMap<_, Blake2_128Concat, TokenId, xcm::v4::Location, OptionQuery>; + + /// Lookup table for native location relative to ethereum to foreign token ID + #[pallet::storage] + pub type NativeToForeignId = + StorageMap<_, Blake2_128Concat, xcm::v4::Location, TokenId, OptionQuery>; + #[pallet::genesis_config] #[derive(frame_support::DefaultNoBound)] pub struct GenesisConfig { @@ -574,6 +607,34 @@ pub mod pallet { }); Ok(()) } + + /// Registers a Polkadot-native token as a wrapped ERC20 token on Ethereum. + /// Privileged. Can only be called by root. + /// + /// Fee required: No + /// + /// - `origin`: Must be root + /// - `location`: Location of the asset (relative to this chain) + /// - `metadata`: Metadata to include in the instantiated ERC20 contract on Ethereum + #[pallet::call_index(10)] + #[pallet::weight(T::WeightInfo::register_token())] + pub fn register_token( + origin: OriginFor, + location: Box, + metadata: AssetMetadata, + ) -> DispatchResultWithPostInfo { + ensure_root(origin)?; + + let location: Location = + (*location).try_into().map_err(|_| Error::::UnsupportedLocationVersion)?; + + Self::do_register_token(&location, metadata, PaysFee::::No)?; + + Ok(PostDispatchInfo { + actual_weight: Some(T::WeightInfo::register_token()), + pays_fee: Pays::No, + }) + } } impl Pallet { @@ -663,6 +724,42 @@ pub mod pallet { let secondary_exists = Channels::::contains_key(SECONDARY_GOVERNANCE_CHANNEL); primary_exists && secondary_exists } + + pub(crate) fn do_register_token( + location: &Location, + metadata: AssetMetadata, + pays_fee: PaysFee, + ) -> Result<(), DispatchError> { + let ethereum_location = T::EthereumLocation::get(); + // reanchor to Ethereum context + let location = location + .clone() + .reanchored(ðereum_location, &T::UniversalLocation::get()) + .map_err(|_| Error::::LocationConversionFailed)?; + + let token_id = TokenIdOf::convert_location(&location) + .ok_or(Error::::LocationConversionFailed)?; + + if !ForeignToNativeId::::contains_key(token_id) { + NativeToForeignId::::insert(location.clone(), token_id); + ForeignToNativeId::::insert(token_id, location.clone()); + } + + let command = Command::RegisterForeignToken { + token_id, + name: metadata.name.into_inner(), + symbol: metadata.symbol.into_inner(), + decimals: metadata.decimals, + }; + Self::send(SECONDARY_GOVERNANCE_CHANNEL, command, pays_fee)?; + + Self::deposit_event(Event::::RegisterToken { + location: location.clone().into(), + foreign_token_id: token_id, + }); + + Ok(()) + } } impl StaticLookup for Pallet { @@ -684,4 +781,13 @@ pub mod pallet { PricingParameters::::get() } } + + impl MaybeEquivalence for Pallet { + fn convert(foreign_id: &TokenId) -> Option { + ForeignToNativeId::::get(foreign_id) + } + fn convert_back(location: &Location) -> Option { + NativeToForeignId::::get(location) + } + } } diff --git a/bridges/snowbridge/pallets/system/src/mock.rs b/bridges/snowbridge/pallets/system/src/mock.rs index 98bd3da9ab27..47b089866a53 100644 --- a/bridges/snowbridge/pallets/system/src/mock.rs +++ b/bridges/snowbridge/pallets/system/src/mock.rs @@ -166,10 +166,12 @@ impl snowbridge_pallet_outbound_queue::Config for Test { parameter_types! { pub const SS58Prefix: u8 = 42; pub const AnyNetwork: Option = None; - pub const RelayNetwork: Option = Some(NetworkId::Kusama); + pub const RelayNetwork: Option = Some(NetworkId::Polkadot); pub const RelayLocation: Location = Location::parent(); pub UniversalLocation: InteriorLocation = [GlobalConsensus(RelayNetwork::get().unwrap()), Parachain(1013)].into(); + pub EthereumNetwork: NetworkId = NetworkId::Ethereum { chain_id: 11155111 }; + pub EthereumDestination: Location = Location::new(2,[GlobalConsensus(EthereumNetwork::get())]); } pub const DOT: u128 = 10_000_000_000; @@ -177,8 +179,8 @@ pub const DOT: u128 = 10_000_000_000; parameter_types! { pub TreasuryAccount: AccountId = PalletId(*b"py/trsry").into_account_truncating(); pub Fee: u64 = 1000; - pub const RococoNetwork: NetworkId = NetworkId::Rococo; pub const InitialFunding: u128 = 1_000_000_000_000; + pub BridgeHubParaId: ParaId = ParaId::new(1002); pub AssetHubParaId: ParaId = ParaId::new(1000); pub TestParaId: u32 = 2000; pub Parameters: PricingParameters = PricingParameters { @@ -188,7 +190,6 @@ parameter_types! { multiplier: FixedU128::from_rational(4, 3) }; pub const InboundDeliveryCost: u128 = 1_000_000_000; - } #[cfg(feature = "runtime-benchmarks")] @@ -208,6 +209,8 @@ impl crate::Config for Test { type DefaultPricingParameters = Parameters; type WeightInfo = (); type InboundDeliveryCost = InboundDeliveryCost; + type UniversalLocation = UniversalLocation; + type EthereumLocation = EthereumDestination; #[cfg(feature = "runtime-benchmarks")] type Helper = (); } diff --git a/bridges/snowbridge/pallets/system/src/tests.rs b/bridges/snowbridge/pallets/system/src/tests.rs index 09f24195a30a..d0286e04abdf 100644 --- a/bridges/snowbridge/pallets/system/src/tests.rs +++ b/bridges/snowbridge/pallets/system/src/tests.rs @@ -248,7 +248,7 @@ fn create_channel() { let _ = Balances::mint_into(&sovereign_account, 10000); assert_ok!(EthereumSystem::create_agent(origin.clone())); - assert_ok!(EthereumSystem::create_channel(origin, OperatingMode::Normal)); + assert_ok!(EthereumSystem::create_channel(origin, OperatingMode::Normal,)); }); } @@ -264,10 +264,10 @@ fn create_channel_fail_already_exists() { let _ = Balances::mint_into(&sovereign_account, 10000); assert_ok!(EthereumSystem::create_agent(origin.clone())); - assert_ok!(EthereumSystem::create_channel(origin.clone(), OperatingMode::Normal)); + assert_ok!(EthereumSystem::create_channel(origin.clone(), OperatingMode::Normal,)); assert_noop!( - EthereumSystem::create_channel(origin, OperatingMode::Normal), + EthereumSystem::create_channel(origin, OperatingMode::Normal,), Error::::ChannelAlreadyCreated ); }); @@ -334,10 +334,10 @@ fn update_channel() { // First create the channel let _ = Balances::mint_into(&sovereign_account, 10000); assert_ok!(EthereumSystem::create_agent(origin.clone())); - assert_ok!(EthereumSystem::create_channel(origin.clone(), OperatingMode::Normal)); + assert_ok!(EthereumSystem::create_channel(origin.clone(), OperatingMode::Normal,)); // Now try to update it - assert_ok!(EthereumSystem::update_channel(origin, OperatingMode::Normal)); + assert_ok!(EthereumSystem::update_channel(origin, OperatingMode::Normal,)); System::assert_last_event(RuntimeEvent::EthereumSystem(crate::Event::UpdateChannel { channel_id: ParaId::from(2000).into(), @@ -383,12 +383,12 @@ fn update_channel_bad_origin() { // Signed origin not allowed assert_noop!( - EthereumSystem::update_channel(RuntimeOrigin::signed([14; 32].into()), mode), + EthereumSystem::update_channel(RuntimeOrigin::signed([14; 32].into()), mode,), BadOrigin ); // None origin not allowed - assert_noop!(EthereumSystem::update_channel(RuntimeOrigin::none(), mode), BadOrigin); + assert_noop!(EthereumSystem::update_channel(RuntimeOrigin::none(), mode,), BadOrigin); }); } @@ -400,7 +400,7 @@ fn update_channel_fails_not_exist() { // Now try to update it assert_noop!( - EthereumSystem::update_channel(origin, OperatingMode::Normal), + EthereumSystem::update_channel(origin, OperatingMode::Normal,), Error::::NoChannel ); }); @@ -419,7 +419,7 @@ fn force_update_channel() { // First create the channel let _ = Balances::mint_into(&sovereign_account, 10000); assert_ok!(EthereumSystem::create_agent(origin.clone())); - assert_ok!(EthereumSystem::create_channel(origin.clone(), OperatingMode::Normal)); + assert_ok!(EthereumSystem::create_channel(origin.clone(), OperatingMode::Normal,)); // Now try to force update it let force_origin = RuntimeOrigin::root(); @@ -463,7 +463,7 @@ fn transfer_native_from_agent() { // First create the agent and channel assert_ok!(EthereumSystem::create_agent(origin.clone())); - assert_ok!(EthereumSystem::create_channel(origin, OperatingMode::Normal)); + assert_ok!(EthereumSystem::create_channel(origin, OperatingMode::Normal,)); let origin = make_xcm_origin(origin_location.clone()); assert_ok!(EthereumSystem::transfer_native_from_agent(origin, recipient, amount),); @@ -584,7 +584,7 @@ fn charge_fee_for_transfer_native_from_agent() { // create_agent & create_channel first assert_ok!(EthereumSystem::create_agent(origin.clone())); - assert_ok!(EthereumSystem::create_channel(origin.clone(), OperatingMode::Normal)); + assert_ok!(EthereumSystem::create_channel(origin.clone(), OperatingMode::Normal,)); // assert sovereign_balance decreased by only the base_fee let sovereign_balance_before = Balances::balance(&sovereign_account); @@ -631,3 +631,116 @@ fn no_genesis_build_is_uninitialized() { assert!(!EthereumSystem::is_initialized(), "Ethereum initialized."); }); } + +#[test] +fn register_token_with_signed_yields_bad_origin() { + new_test_ext(true).execute_with(|| { + let origin = RuntimeOrigin::signed([14; 32].into()); + let location = Location::new(1, [Parachain(2000)]); + let versioned_location: Box = Box::new(location.clone().into()); + assert_noop!( + EthereumSystem::register_token(origin, versioned_location, Default::default()), + BadOrigin + ); + }); +} + +pub struct RegisterTokenTestCase { + /// Input: Location of Polkadot-native token relative to BH + pub native: Location, + /// Output: Reanchored, canonicalized location + pub reanchored: Location, + /// Output: Stable hash of reanchored location + pub foreign: TokenId, +} + +#[test] +fn register_all_tokens_succeeds() { + let test_cases = vec![ + // DOT + RegisterTokenTestCase { + native: Location::parent(), + reanchored: Location::new(1, GlobalConsensus(Polkadot)), + foreign: hex!("4e241583d94b5d48a27a22064cd49b2ed6f5231d2d950e432f9b7c2e0ade52b2") + .into(), + }, + // GLMR (Some Polkadot parachain currency) + RegisterTokenTestCase { + native: Location::new(1, [Parachain(2004)]), + reanchored: Location::new(1, [GlobalConsensus(Polkadot), Parachain(2004)]), + foreign: hex!("34c08fc90409b6924f0e8eabb7c2aaa0c749e23e31adad9f6d217b577737fafb") + .into(), + }, + // USDT + RegisterTokenTestCase { + native: Location::new(1, [Parachain(1000), PalletInstance(50), GeneralIndex(1984)]), + reanchored: Location::new( + 1, + [ + GlobalConsensus(Polkadot), + Parachain(1000), + PalletInstance(50), + GeneralIndex(1984), + ], + ), + foreign: hex!("14b0579be12d7d7f9971f1d4b41f0e88384b9b74799b0150d4aa6cd01afb4444") + .into(), + }, + // KSM + RegisterTokenTestCase { + native: Location::new(2, [GlobalConsensus(Kusama)]), + reanchored: Location::new(1, [GlobalConsensus(Kusama)]), + foreign: hex!("03b6054d0c576dd8391e34e1609cf398f68050c23009d19ce93c000922bcd852") + .into(), + }, + // KAR (Some Kusama parachain currency) + RegisterTokenTestCase { + native: Location::new(2, [GlobalConsensus(Kusama), Parachain(2000)]), + reanchored: Location::new(1, [GlobalConsensus(Kusama), Parachain(2000)]), + foreign: hex!("d3e39ad6ea4cee68c9741181e94098823b2ea34a467577d0875c036f0fce5be0") + .into(), + }, + ]; + for tc in test_cases.iter() { + new_test_ext(true).execute_with(|| { + let origin = RuntimeOrigin::root(); + let versioned_location: VersionedLocation = tc.native.clone().into(); + + assert_ok!(EthereumSystem::register_token( + origin, + Box::new(versioned_location), + Default::default() + )); + + assert_eq!(NativeToForeignId::::get(tc.reanchored.clone()), Some(tc.foreign)); + assert_eq!(ForeignToNativeId::::get(tc.foreign), Some(tc.reanchored.clone())); + + System::assert_last_event(RuntimeEvent::EthereumSystem(Event::::RegisterToken { + location: tc.reanchored.clone().into(), + foreign_token_id: tc.foreign, + })); + }); + } +} + +#[test] +fn register_ethereum_native_token_fails() { + new_test_ext(true).execute_with(|| { + let origin = RuntimeOrigin::root(); + let location = Location::new( + 2, + [ + GlobalConsensus(Ethereum { chain_id: 11155111 }), + AccountKey20 { + network: None, + key: hex!("87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d"), + }, + ], + ); + let versioned_location: Box = Box::new(location.clone().into()); + assert_noop!( + EthereumSystem::register_token(origin, versioned_location, Default::default()), + Error::::LocationConversionFailed + ); + }); +} diff --git a/bridges/snowbridge/pallets/system/src/weights.rs b/bridges/snowbridge/pallets/system/src/weights.rs index 6e532a0d8a8c..3513097f8b55 100644 --- a/bridges/snowbridge/pallets/system/src/weights.rs +++ b/bridges/snowbridge/pallets/system/src/weights.rs @@ -42,6 +42,7 @@ pub trait WeightInfo { fn force_transfer_native_from_agent() -> Weight; fn set_token_transfer_fees() -> Weight; fn set_pricing_parameters() -> Weight; + fn register_token() -> Weight; } // For backwards compatibility and tests. @@ -246,4 +247,14 @@ impl WeightInfo for () { .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } + + fn register_token() -> Weight { + // Proof Size summary in bytes: + // Measured: `256` + // Estimated: `6044` + // Minimum execution time: 45_000_000 picoseconds. + Weight::from_parts(45_000_000, 6044) + .saturating_add(RocksDbWeight::get().reads(5_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } } diff --git a/bridges/snowbridge/primitives/core/Cargo.toml b/bridges/snowbridge/primitives/core/Cargo.toml index f9bee1ff4959..fa37c795b2d1 100644 --- a/bridges/snowbridge/primitives/core/Cargo.toml +++ b/bridges/snowbridge/primitives/core/Cargo.toml @@ -35,6 +35,7 @@ ethabi = { workspace = true } [dev-dependencies] hex = { workspace = true, default-features = true } +xcm-executor = { workspace = true, default-features = true } [features] default = ["std"] @@ -62,4 +63,5 @@ runtime-benchmarks = [ "polkadot-parachain-primitives/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "xcm-builder/runtime-benchmarks", + "xcm-executor/runtime-benchmarks", ] diff --git a/bridges/snowbridge/primitives/core/src/lib.rs b/bridges/snowbridge/primitives/core/src/lib.rs index ed1af4225d24..7ad129a52542 100644 --- a/bridges/snowbridge/primitives/core/src/lib.rs +++ b/bridges/snowbridge/primitives/core/src/lib.rs @@ -9,11 +9,13 @@ mod tests; pub mod inbound; +pub mod location; pub mod operating_mode; pub mod outbound; pub mod pricing; pub mod ringbuffer; +pub use location::{AgentId, AgentIdOf, TokenId, TokenIdOf}; pub use polkadot_parachain_primitives::primitives::{ Id as ParaId, IsSystem, Sibling as SiblingParaId, }; @@ -21,18 +23,16 @@ pub use ringbuffer::{RingBufferMap, RingBufferMapImpl}; pub use sp_core::U256; use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::traits::Contains; +use frame_support::{traits::Contains, BoundedVec}; use hex_literal::hex; use scale_info::TypeInfo; -use sp_core::H256; +use sp_core::{ConstU32, H256}; use sp_io::hashing::keccak_256; use sp_runtime::{traits::AccountIdConversion, RuntimeDebug}; use sp_std::prelude::*; use xcm::prelude::{Junction::Parachain, Location}; -use xcm_builder::{DescribeAllTerminal, DescribeFamily, DescribeLocation, HashedDescription}; /// The ID of an agent contract -pub type AgentId = H256; pub use operating_mode::BasicOperatingMode; pub use pricing::{PricingParameters, Rewards}; @@ -151,16 +151,24 @@ pub const PRIMARY_GOVERNANCE_CHANNEL: ChannelId = pub const SECONDARY_GOVERNANCE_CHANNEL: ChannelId = ChannelId::new(hex!("0000000000000000000000000000000000000000000000000000000000000002")); -pub struct DescribeHere; -impl DescribeLocation for DescribeHere { - fn describe_location(l: &Location) -> Option> { - match l.unpack() { - (0, []) => Some(Vec::::new().encode()), - _ => None, +/// Metadata to include in the instantiated ERC20 token contract +#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug, TypeInfo)] +pub struct AssetMetadata { + pub name: BoundedVec>, + pub symbol: BoundedVec>, + pub decimals: u8, +} + +#[cfg(any(test, feature = "std", feature = "runtime-benchmarks"))] +impl Default for AssetMetadata { + fn default() -> Self { + AssetMetadata { + name: BoundedVec::truncate_from(vec![]), + symbol: BoundedVec::truncate_from(vec![]), + decimals: 0, } } } -/// Creates an AgentId from a Location. An AgentId is a unique mapping to a Agent contract on -/// Ethereum which acts as the sovereign account for the Location. -pub type AgentIdOf = HashedDescription)>; +/// Maximum length of a string field in ERC20 token metada +const METADATA_FIELD_MAX_LEN: u32 = 32; diff --git a/bridges/snowbridge/primitives/core/src/location.rs b/bridges/snowbridge/primitives/core/src/location.rs new file mode 100644 index 000000000000..aad1c9ece05c --- /dev/null +++ b/bridges/snowbridge/primitives/core/src/location.rs @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023 Snowfork +//! # Location +//! +//! Location helpers for dealing with Tokens and Agents + +pub use polkadot_parachain_primitives::primitives::{ + Id as ParaId, IsSystem, Sibling as SiblingParaId, +}; +pub use sp_core::U256; + +use codec::Encode; +use sp_core::H256; +use sp_std::prelude::*; +use xcm::prelude::{ + AccountId32, AccountKey20, GeneralIndex, GeneralKey, GlobalConsensus, Location, PalletInstance, +}; +use xcm_builder::{ + DescribeAllTerminal, DescribeFamily, DescribeLocation, DescribeTerminus, HashedDescription, +}; + +pub type AgentId = H256; + +/// Creates an AgentId from a Location. An AgentId is a unique mapping to a Agent contract on +/// Ethereum which acts as the sovereign account for the Location. +#[allow(deprecated)] +pub type AgentIdOf = + HashedDescription)>; + +pub type TokenId = H256; + +/// Convert a token location (relative to Ethereum) to a stable ID that can be used on the Ethereum +/// side +pub type TokenIdOf = HashedDescription< + TokenId, + DescribeGlobalPrefix<(DescribeTerminus, DescribeFamily)>, +>; + +/// This looks like DescribeTerminus that was added to xcm-builder. However this does an extra +/// `encode` to the Vector producing a different output to DescribeTerminus. `DescribeHere` +/// should NOT be used for new code. This is left here for backwards compatibility of channels and +/// agents. +#[deprecated(note = "Use DescribeTerminus from xcm-builder instead.")] +pub struct DescribeHere; +#[allow(deprecated)] +impl DescribeLocation for DescribeHere { + fn describe_location(l: &Location) -> Option> { + match l.unpack() { + (0, []) => Some(Vec::::new().encode()), + _ => None, + } + } +} +pub struct DescribeGlobalPrefix(sp_std::marker::PhantomData); +impl DescribeLocation for DescribeGlobalPrefix { + fn describe_location(l: &Location) -> Option> { + match (l.parent_count(), l.first_interior()) { + (1, Some(GlobalConsensus(network))) => { + let mut tail = l.clone().split_first_interior().0; + tail.dec_parent(); + let interior = Suffix::describe_location(&tail)?; + Some((b"GlobalConsensus", network, interior).encode()) + }, + _ => None, + } + } +} + +pub struct DescribeTokenTerminal; +impl DescribeLocation for DescribeTokenTerminal { + fn describe_location(l: &Location) -> Option> { + match l.unpack().1 { + [] => Some(Vec::::new().encode()), + [GeneralIndex(index)] => Some((b"GeneralIndex", *index).encode()), + [GeneralKey { data, .. }] => Some((b"GeneralKey", *data).encode()), + [AccountKey20 { key, .. }] => Some((b"AccountKey20", *key).encode()), + [AccountId32 { id, .. }] => Some((b"AccountId32", *id).encode()), + + // Pallet + [PalletInstance(instance)] => Some((b"PalletInstance", *instance).encode()), + [PalletInstance(instance), GeneralIndex(index)] => + Some((b"PalletInstance", *instance, b"GeneralIndex", *index).encode()), + [PalletInstance(instance), GeneralKey { data, .. }] => + Some((b"PalletInstance", *instance, b"GeneralKey", *data).encode()), + + [PalletInstance(instance), AccountKey20 { key, .. }] => + Some((b"PalletInstance", *instance, b"AccountKey20", *key).encode()), + [PalletInstance(instance), AccountId32 { id, .. }] => + Some((b"PalletInstance", *instance, b"AccountId32", *id).encode()), + + // Reject all other locations + _ => None, + } + } +} + +#[cfg(test)] +mod tests { + use crate::TokenIdOf; + use xcm::prelude::{ + GeneralIndex, GeneralKey, GlobalConsensus, Junction::*, Location, NetworkId::*, + PalletInstance, Parachain, + }; + use xcm_executor::traits::ConvertLocation; + + #[test] + fn test_token_of_id() { + let token_locations = [ + // Relay Chain cases + // Relay Chain relative to Ethereum + Location::new(1, [GlobalConsensus(Westend)]), + // Parachain cases + // Parachain relative to Ethereum + Location::new(1, [GlobalConsensus(Westend), Parachain(2000)]), + // Parachain general index + Location::new(1, [GlobalConsensus(Westend), Parachain(2000), GeneralIndex(1)]), + // Parachain general key + Location::new( + 1, + [ + GlobalConsensus(Westend), + Parachain(2000), + GeneralKey { length: 32, data: [0; 32] }, + ], + ), + // Parachain account key 20 + Location::new( + 1, + [ + GlobalConsensus(Westend), + Parachain(2000), + AccountKey20 { network: None, key: [0; 20] }, + ], + ), + // Parachain account id 32 + Location::new( + 1, + [ + GlobalConsensus(Westend), + Parachain(2000), + AccountId32 { network: None, id: [0; 32] }, + ], + ), + // Parchain Pallet instance cases + // Parachain pallet instance + Location::new(1, [GlobalConsensus(Westend), Parachain(2000), PalletInstance(8)]), + // Parachain Pallet general index + Location::new( + 1, + [GlobalConsensus(Westend), Parachain(2000), PalletInstance(8), GeneralIndex(1)], + ), + // Parachain Pallet general key + Location::new( + 1, + [ + GlobalConsensus(Westend), + Parachain(2000), + PalletInstance(8), + GeneralKey { length: 32, data: [0; 32] }, + ], + ), + // Parachain Pallet account key 20 + Location::new( + 1, + [ + GlobalConsensus(Westend), + Parachain(2000), + PalletInstance(8), + AccountKey20 { network: None, key: [0; 20] }, + ], + ), + // Parachain Pallet account id 32 + Location::new( + 1, + [ + GlobalConsensus(Westend), + Parachain(2000), + PalletInstance(8), + AccountId32 { network: None, id: [0; 32] }, + ], + ), + ]; + + for token in token_locations { + assert!( + TokenIdOf::convert_location(&token).is_some(), + "Valid token = {token:?} yeilds no TokenId." + ); + } + + let non_token_locations = [ + // Relative location for a token should fail. + Location::new(1, []), + // Relative location for a token should fail. + Location::new(1, [Parachain(1000)]), + ]; + + for token in non_token_locations { + assert!( + TokenIdOf::convert_location(&token).is_none(), + "Invalid token = {token:?} yeilds a TokenId." + ); + } + } +} diff --git a/bridges/snowbridge/primitives/core/src/outbound.rs b/bridges/snowbridge/primitives/core/src/outbound.rs index 0ba0fdb61089..77770761822a 100644 --- a/bridges/snowbridge/primitives/core/src/outbound.rs +++ b/bridges/snowbridge/primitives/core/src/outbound.rs @@ -139,6 +139,37 @@ mod v1 { // Fee multiplier multiplier: UD60x18, }, + /// Transfer ERC20 tokens + TransferNativeToken { + /// ID of the agent + agent_id: H256, + /// Address of the ERC20 token + token: H160, + /// The recipient of the tokens + recipient: H160, + /// The amount of tokens to transfer + amount: u128, + }, + /// Register foreign token from Polkadot + RegisterForeignToken { + /// ID for the token + token_id: H256, + /// Name of the token + name: Vec, + /// Short symbol for the token + symbol: Vec, + /// Number of decimal places + decimals: u8, + }, + /// Mint foreign token from Polkadot + MintForeignToken { + /// ID for the token + token_id: H256, + /// The recipient of the newly minted tokens + recipient: H160, + /// The amount of tokens to mint + amount: u128, + }, } impl Command { @@ -154,6 +185,9 @@ mod v1 { Command::TransferNativeFromAgent { .. } => 6, Command::SetTokenTransferFees { .. } => 7, Command::SetPricingParameters { .. } => 8, + Command::TransferNativeToken { .. } => 9, + Command::RegisterForeignToken { .. } => 10, + Command::MintForeignToken { .. } => 11, } } @@ -211,6 +245,26 @@ mod v1 { Token::Uint(U256::from(*delivery_cost)), Token::Uint(multiplier.clone().into_inner()), ])]), + Command::TransferNativeToken { agent_id, token, recipient, amount } => + ethabi::encode(&[Token::Tuple(vec![ + Token::FixedBytes(agent_id.as_bytes().to_owned()), + Token::Address(*token), + Token::Address(*recipient), + Token::Uint(U256::from(*amount)), + ])]), + Command::RegisterForeignToken { token_id, name, symbol, decimals } => + ethabi::encode(&[Token::Tuple(vec![ + Token::FixedBytes(token_id.as_bytes().to_owned()), + Token::String(name.to_owned()), + Token::String(symbol.to_owned()), + Token::Uint(U256::from(*decimals)), + ])]), + Command::MintForeignToken { token_id, recipient, amount } => + ethabi::encode(&[Token::Tuple(vec![ + Token::FixedBytes(token_id.as_bytes().to_owned()), + Token::Address(*recipient), + Token::Uint(U256::from(*amount)), + ])]), } } } @@ -403,6 +457,9 @@ impl GasMeter for ConstantGasMeter { }, Command::SetTokenTransferFees { .. } => 60_000, Command::SetPricingParameters { .. } => 60_000, + Command::TransferNativeToken { .. } => 100_000, + Command::RegisterForeignToken { .. } => 1_200_000, + Command::MintForeignToken { .. } => 100_000, } } } diff --git a/bridges/snowbridge/primitives/router/src/inbound/mod.rs b/bridges/snowbridge/primitives/router/src/inbound/mod.rs index 54e47a7a8b6a..fbfc52d01c83 100644 --- a/bridges/snowbridge/primitives/router/src/inbound/mod.rs +++ b/bridges/snowbridge/primitives/router/src/inbound/mod.rs @@ -9,9 +9,10 @@ use codec::{Decode, Encode}; use core::marker::PhantomData; use frame_support::{traits::tokens::Balance as BalanceT, weights::Weight, PalletError}; use scale_info::TypeInfo; -use sp_core::{Get, RuntimeDebug, H160}; +use snowbridge_core::TokenId; +use sp_core::{Get, RuntimeDebug, H160, H256}; use sp_io::hashing::blake2_256; -use sp_runtime::MultiAddress; +use sp_runtime::{traits::MaybeEquivalence, MultiAddress}; use sp_std::prelude::*; use xcm::prelude::{Junction::AccountKey20, *}; use xcm_executor::traits::ConvertLocation; @@ -45,7 +46,7 @@ pub enum Command { /// XCM execution fee on AssetHub fee: u128, }, - /// Send a token to AssetHub or another parachain + /// Send Ethereum token to AssetHub or another parachain SendToken { /// The address of the ERC20 token to be bridged over to AssetHub token: H160, @@ -56,6 +57,17 @@ pub enum Command { /// XCM execution fee on AssetHub fee: u128, }, + /// Send Polkadot token back to the original parachain + SendNativeToken { + /// The Id of the token + token_id: TokenId, + /// The destination for the transfer + destination: Destination, + /// Amount to transfer + amount: u128, + /// XCM execution fee on AssetHub + fee: u128, + }, } /// Destination for bridged tokens @@ -89,10 +101,16 @@ pub struct MessageToXcm< InboundQueuePalletInstance, AccountId, Balance, + ConvertAssetId, + EthereumUniversalLocation, + GlobalAssetHubLocation, > where CreateAssetCall: Get, CreateAssetDeposit: Get, Balance: BalanceT, + ConvertAssetId: MaybeEquivalence, + EthereumUniversalLocation: Get, + GlobalAssetHubLocation: Get, { _phantom: PhantomData<( CreateAssetCall, @@ -100,6 +118,9 @@ pub struct MessageToXcm< InboundQueuePalletInstance, AccountId, Balance, + ConvertAssetId, + EthereumUniversalLocation, + GlobalAssetHubLocation, )>, } @@ -108,6 +129,11 @@ pub struct MessageToXcm< pub enum ConvertMessageError { /// The message version is not supported for conversion. UnsupportedVersion, + InvalidDestination, + InvalidToken, + /// The fee asset is not supported for conversion. + UnsupportedFeeAsset, + CannotReanchor, } /// convert the inbound message to xcm which will be forwarded to the destination chain @@ -115,51 +141,109 @@ pub trait ConvertMessage { type Balance: BalanceT + From; type AccountId; /// Converts a versioned message into an XCM message and an optional topicID - fn convert(message: VersionedMessage) -> Result<(Xcm<()>, Self::Balance), ConvertMessageError>; + fn convert( + message_id: H256, + message: VersionedMessage, + ) -> Result<(Xcm<()>, Self::Balance), ConvertMessageError>; } pub type CallIndex = [u8; 2]; -impl - ConvertMessage +impl< + CreateAssetCall, + CreateAssetDeposit, + InboundQueuePalletInstance, + AccountId, + Balance, + ConvertAssetId, + EthereumUniversalLocation, + GlobalAssetHubLocation, + > ConvertMessage for MessageToXcm< CreateAssetCall, CreateAssetDeposit, InboundQueuePalletInstance, AccountId, Balance, - > where + ConvertAssetId, + EthereumUniversalLocation, + GlobalAssetHubLocation, + > +where CreateAssetCall: Get, CreateAssetDeposit: Get, InboundQueuePalletInstance: Get, Balance: BalanceT + From, AccountId: Into<[u8; 32]>, + ConvertAssetId: MaybeEquivalence, + EthereumUniversalLocation: Get, + GlobalAssetHubLocation: Get, { type Balance = Balance; type AccountId = AccountId; - fn convert(message: VersionedMessage) -> Result<(Xcm<()>, Self::Balance), ConvertMessageError> { + fn convert( + message_id: H256, + message: VersionedMessage, + ) -> Result<(Xcm<()>, Self::Balance), ConvertMessageError> { use Command::*; use VersionedMessage::*; match message { V1(MessageV1 { chain_id, command: RegisterToken { token, fee } }) => - Ok(Self::convert_register_token(chain_id, token, fee)), + Ok(Self::convert_register_token(message_id, chain_id, token, fee)), V1(MessageV1 { chain_id, command: SendToken { token, destination, amount, fee } }) => - Ok(Self::convert_send_token(chain_id, token, destination, amount, fee)), + Ok(Self::convert_send_token(message_id, chain_id, token, destination, amount, fee)), + V1(MessageV1 { + chain_id, + command: SendNativeToken { token_id, destination, amount, fee }, + }) => Self::convert_send_native_token( + message_id, + chain_id, + token_id, + destination, + amount, + fee, + ), } } } -impl - MessageToXcm +impl< + CreateAssetCall, + CreateAssetDeposit, + InboundQueuePalletInstance, + AccountId, + Balance, + ConvertAssetId, + EthereumUniversalLocation, + GlobalAssetHubLocation, + > + MessageToXcm< + CreateAssetCall, + CreateAssetDeposit, + InboundQueuePalletInstance, + AccountId, + Balance, + ConvertAssetId, + EthereumUniversalLocation, + GlobalAssetHubLocation, + > where CreateAssetCall: Get, CreateAssetDeposit: Get, InboundQueuePalletInstance: Get, Balance: BalanceT + From, AccountId: Into<[u8; 32]>, + ConvertAssetId: MaybeEquivalence, + EthereumUniversalLocation: Get, + GlobalAssetHubLocation: Get, { - fn convert_register_token(chain_id: u64, token: H160, fee: u128) -> (Xcm<()>, Balance) { + fn convert_register_token( + message_id: H256, + chain_id: u64, + token: H160, + fee: u128, + ) -> (Xcm<()>, Balance) { let network = Ethereum { chain_id }; let xcm_fee: Asset = (Location::parent(), fee).into(); let deposit: Asset = (Location::parent(), CreateAssetDeposit::get()).into(); @@ -167,7 +251,7 @@ where let total_amount = fee + CreateAssetDeposit::get(); let total: Asset = (Location::parent(), total_amount).into(); - let bridge_location: Location = (Parent, Parent, GlobalConsensus(network)).into(); + let bridge_location = Location::new(2, GlobalConsensus(network)); let owner = GlobalConsensusEthereumConvertsFor::<[u8; 32]>::from_chain_id(&chain_id); let asset_id = Self::convert_token_address(network, token); @@ -180,8 +264,15 @@ where // Pay for execution. BuyExecution { fees: xcm_fee, weight_limit: Unlimited }, // Fund the snowbridge sovereign with the required deposit for creation. - DepositAsset { assets: Definite(deposit.into()), beneficiary: bridge_location }, - // Only our inbound-queue pallet is allowed to invoke `UniversalOrigin` + DepositAsset { assets: Definite(deposit.into()), beneficiary: bridge_location.clone() }, + // This `SetAppendix` ensures that `xcm_fee` not spent by `Transact` will be + // deposited to snowbridge sovereign, instead of being trapped, regardless of + // `Transact` success or not. + SetAppendix(Xcm(vec![ + RefundSurplus, + DepositAsset { assets: AllCounted(1).into(), beneficiary: bridge_location }, + ])), + // Only our inbound-queue pallet is allowed to invoke `UniversalOrigin`. DescendOrigin(PalletInstance(inbound_queue_pallet_index).into()), // Change origin to the bridge. UniversalOrigin(GlobalConsensus(network)), @@ -198,10 +289,10 @@ where .encode() .into(), }, - RefundSurplus, - // Clear the origin so that remaining assets in holding - // are claimable by the physical origin (BridgeHub) - ClearOrigin, + // Forward message id to Asset Hub + SetTopic(message_id.into()), + // Once the program ends here, appendix program will run, which will deposit any + // leftover fee to snowbridge sovereign. ] .into(); @@ -209,6 +300,7 @@ where } fn convert_send_token( + message_id: H256, chain_id: u64, token: H160, destination: Destination, @@ -255,17 +347,26 @@ where match dest_para_id { Some(dest_para_id) => { let dest_para_fee_asset: Asset = (Location::parent(), dest_para_fee).into(); + let bridge_location = Location::new(2, GlobalConsensus(network)); instructions.extend(vec![ + // After program finishes deposit any leftover assets to the snowbridge + // sovereign. + SetAppendix(Xcm(vec![DepositAsset { + assets: Wild(AllCounted(2)), + beneficiary: bridge_location, + }])), // Perform a deposit reserve to send to destination chain. DepositReserveAsset { - assets: Definite(vec![dest_para_fee_asset.clone(), asset.clone()].into()), + assets: Definite(vec![dest_para_fee_asset.clone(), asset].into()), dest: Location::new(1, [Parachain(dest_para_id)]), xcm: vec![ // Buy execution on target. BuyExecution { fees: dest_para_fee_asset, weight_limit: Unlimited }, - // Deposit asset to beneficiary. - DepositAsset { assets: Definite(asset.into()), beneficiary }, + // Deposit assets to beneficiary. + DepositAsset { assets: Wild(AllCounted(2)), beneficiary }, + // Forward message id to destination parachain. + SetTopic(message_id.into()), ] .into(), }, @@ -281,6 +382,11 @@ where }, } + // Forward message id to Asset Hub. + instructions.push(SetTopic(message_id.into())); + + // The `instructions` to forward to AssetHub, and the `total_fees` to locally burn (since + // they are teleported within `instructions`). (instructions.into(), total_fees.into()) } @@ -291,6 +397,59 @@ where [GlobalConsensus(network), AccountKey20 { network: None, key: token.into() }], ) } + + /// Constructs an XCM message destined for AssetHub that withdraws assets from the sovereign + /// account of the Gateway contract and either deposits those assets into a recipient account or + /// forwards the assets to another parachain. + fn convert_send_native_token( + message_id: H256, + chain_id: u64, + token_id: TokenId, + destination: Destination, + amount: u128, + asset_hub_fee: u128, + ) -> Result<(Xcm<()>, Balance), ConvertMessageError> { + let network = Ethereum { chain_id }; + let asset_hub_fee_asset: Asset = (Location::parent(), asset_hub_fee).into(); + + let beneficiary = match destination { + // Final destination is a 32-byte account on AssetHub + Destination::AccountId32 { id } => + Ok(Location::new(0, [AccountId32 { network: None, id }])), + _ => Err(ConvertMessageError::InvalidDestination), + }?; + + let total_fee_asset: Asset = (Location::parent(), asset_hub_fee).into(); + + let asset_loc = + ConvertAssetId::convert(&token_id).ok_or(ConvertMessageError::InvalidToken)?; + + let mut reanchored_asset_loc = asset_loc.clone(); + reanchored_asset_loc + .reanchor(&GlobalAssetHubLocation::get(), &EthereumUniversalLocation::get()) + .map_err(|_| ConvertMessageError::CannotReanchor)?; + + let asset: Asset = (reanchored_asset_loc, amount).into(); + + let inbound_queue_pallet_index = InboundQueuePalletInstance::get(); + + let instructions = vec![ + ReceiveTeleportedAsset(total_fee_asset.clone().into()), + BuyExecution { fees: asset_hub_fee_asset, weight_limit: Unlimited }, + DescendOrigin(PalletInstance(inbound_queue_pallet_index).into()), + UniversalOrigin(GlobalConsensus(network)), + WithdrawAsset(asset.clone().into()), + // Deposit both asset and fees to beneficiary so the fees will not get + // trapped. Another benefit is when fees left more than ED on AssetHub could be + // used to create the beneficiary account in case it does not exist. + DepositAsset { assets: Wild(AllCounted(2)), beneficiary }, + SetTopic(message_id.into()), + ]; + + // `total_fees` to burn on this chain when sending `instructions` to run on AH (which also + // teleport fees) + Ok((instructions.into(), asset_hub_fee.into())) + } } pub struct GlobalConsensusEthereumConvertsFor(PhantomData); diff --git a/bridges/snowbridge/primitives/router/src/inbound/tests.rs b/bridges/snowbridge/primitives/router/src/inbound/tests.rs index 75670b05c100..e0e90e516be1 100644 --- a/bridges/snowbridge/primitives/router/src/inbound/tests.rs +++ b/bridges/snowbridge/primitives/router/src/inbound/tests.rs @@ -1,6 +1,6 @@ use super::GlobalConsensusEthereumConvertsFor; use crate::inbound::CallIndex; -use frame_support::parameter_types; +use frame_support::{assert_ok, parameter_types}; use hex_literal::hex; use xcm::prelude::*; use xcm_executor::traits::ConvertLocation; @@ -38,3 +38,32 @@ fn test_contract_location_with_incorrect_location_fails_convert() { None, ); } + +#[test] +fn test_reanchor_all_assets() { + let ethereum_context: InteriorLocation = [GlobalConsensus(Ethereum { chain_id: 1 })].into(); + let ethereum = Location::new(2, ethereum_context.clone()); + let ah_context: InteriorLocation = [GlobalConsensus(Polkadot), Parachain(1000)].into(); + let global_ah = Location::new(1, ah_context.clone()); + let assets = vec![ + // DOT + Location::new(1, []), + // GLMR (Some Polkadot parachain currency) + Location::new(1, [Parachain(2004)]), + // AH asset + Location::new(0, [PalletInstance(50), GeneralIndex(42)]), + // KSM + Location::new(2, [GlobalConsensus(Kusama)]), + // KAR (Some Kusama parachain currency) + Location::new(2, [GlobalConsensus(Kusama), Parachain(2000)]), + ]; + for asset in assets.iter() { + // reanchor logic in pallet_xcm on AH + let mut reanchored_asset = asset.clone(); + assert_ok!(reanchored_asset.reanchor(ðereum, &ah_context)); + // reanchor back to original location in context of Ethereum + let mut reanchored_asset_with_ethereum_context = reanchored_asset.clone(); + assert_ok!(reanchored_asset_with_ethereum_context.reanchor(&global_ah, ðereum_context)); + assert_eq!(reanchored_asset_with_ethereum_context, asset.clone()); + } +} diff --git a/bridges/snowbridge/primitives/router/src/outbound/mod.rs b/bridges/snowbridge/primitives/router/src/outbound/mod.rs index ddc36ce8cb61..efc1ef56f304 100644 --- a/bridges/snowbridge/primitives/router/src/outbound/mod.rs +++ b/bridges/snowbridge/primitives/router/src/outbound/mod.rs @@ -12,9 +12,10 @@ use codec::{Decode, Encode}; use frame_support::{ensure, traits::Get}; use snowbridge_core::{ outbound::{AgentExecuteCommand, Command, Message, SendMessage}, - ChannelId, ParaId, + AgentId, ChannelId, ParaId, TokenId, TokenIdOf, }; use sp_core::{H160, H256}; +use sp_runtime::traits::MaybeEquivalence; use sp_std::{iter::Peekable, marker::PhantomData, prelude::*}; use xcm::prelude::*; use xcm_executor::traits::{ConvertLocation, ExportXcm}; @@ -24,15 +25,32 @@ pub struct EthereumBlobExporter< EthereumNetwork, OutboundQueue, AgentHashedDescription, ->(PhantomData<(UniversalLocation, EthereumNetwork, OutboundQueue, AgentHashedDescription)>); - -impl ExportXcm - for EthereumBlobExporter + ConvertAssetId, +>( + PhantomData<( + UniversalLocation, + EthereumNetwork, + OutboundQueue, + AgentHashedDescription, + ConvertAssetId, + )>, +); + +impl + ExportXcm + for EthereumBlobExporter< + UniversalLocation, + EthereumNetwork, + OutboundQueue, + AgentHashedDescription, + ConvertAssetId, + > where UniversalLocation: Get, EthereumNetwork: Get, OutboundQueue: SendMessage, AgentHashedDescription: ConvertLocation, + ConvertAssetId: MaybeEquivalence, { type Ticket = (Vec, XcmHash); @@ -51,13 +69,15 @@ where return Err(SendError::NotApplicable) } - let dest = destination.take().ok_or(SendError::MissingArgument)?; + // Cloning destination to avoid modifying the value so subsequent exporters can use it. + let dest = destination.clone().take().ok_or(SendError::MissingArgument)?; if dest != Here { log::trace!(target: "xcm::ethereum_blob_exporter", "skipped due to unmatched remote destination {dest:?}."); return Err(SendError::NotApplicable) } - let (local_net, local_sub) = universal_source + // Cloning universal_source to avoid modifying the value so subsequent exporters can use it. + let (local_net, local_sub) = universal_source.clone() .take() .ok_or_else(|| { log::error!(target: "xcm::ethereum_blob_exporter", "universal source not provided."); @@ -66,7 +86,7 @@ where .split_global() .map_err(|()| { log::error!(target: "xcm::ethereum_blob_exporter", "could not get global consensus from universal source '{universal_source:?}'."); - SendError::Unroutable + SendError::NotApplicable })?; if Ok(local_net) != universal_location.global_consensus() { @@ -78,7 +98,17 @@ where [Parachain(para_id)] => *para_id, _ => { log::error!(target: "xcm::ethereum_blob_exporter", "could not get parachain id from universal source '{local_sub:?}'."); - return Err(SendError::MissingArgument) + return Err(SendError::NotApplicable) + }, + }; + + let source_location = Location::new(1, local_sub.clone()); + + let agent_id = match AgentHashedDescription::convert_location(&source_location) { + Some(id) => id, + None => { + log::error!(target: "xcm::ethereum_blob_exporter", "unroutable due to not being able to create agent id. '{source_location:?}'"); + return Err(SendError::NotApplicable) }, }; @@ -87,28 +117,16 @@ where SendError::MissingArgument })?; - let mut converter = XcmConverter::new(&message, &expected_network); - let (agent_execute_command, message_id) = converter.convert().map_err(|err|{ + let mut converter = + XcmConverter::::new(&message, expected_network, agent_id); + let (command, message_id) = converter.convert().map_err(|err|{ log::error!(target: "xcm::ethereum_blob_exporter", "unroutable due to pattern matching error '{err:?}'."); SendError::Unroutable })?; - let source_location = Location::new(1, local_sub.clone()); - let agent_id = match AgentHashedDescription::convert_location(&source_location) { - Some(id) => id, - None => { - log::error!(target: "xcm::ethereum_blob_exporter", "unroutable due to not being able to create agent id. '{source_location:?}'"); - return Err(SendError::Unroutable) - }, - }; - let channel_id: ChannelId = ParaId::from(para_id).into(); - let outbound_message = Message { - id: Some(message_id.into()), - channel_id, - command: Command::AgentExecute { agent_id, command: agent_execute_command }, - }; + let outbound_message = Message { id: Some(message_id.into()), channel_id, command }; // validate the message let (ticket, fee) = OutboundQueue::validate(&outbound_message).map_err(|err| { @@ -154,6 +172,9 @@ enum XcmConverterError { AssetResolutionFailed, InvalidFeeAsset, SetTopicExpected, + ReserveAssetDepositedExpected, + InvalidAsset, + UnexpectedInstruction, } macro_rules! match_expression { @@ -165,18 +186,33 @@ macro_rules! match_expression { }; } -struct XcmConverter<'a, Call> { +struct XcmConverter<'a, ConvertAssetId, Call> { iter: Peekable>>, - ethereum_network: &'a NetworkId, + ethereum_network: NetworkId, + agent_id: AgentId, + _marker: PhantomData, } -impl<'a, Call> XcmConverter<'a, Call> { - fn new(message: &'a Xcm, ethereum_network: &'a NetworkId) -> Self { - Self { iter: message.inner().iter().peekable(), ethereum_network } +impl<'a, ConvertAssetId, Call> XcmConverter<'a, ConvertAssetId, Call> +where + ConvertAssetId: MaybeEquivalence, +{ + fn new(message: &'a Xcm, ethereum_network: NetworkId, agent_id: AgentId) -> Self { + Self { + iter: message.inner().iter().peekable(), + ethereum_network, + agent_id, + _marker: Default::default(), + } } - fn convert(&mut self) -> Result<(AgentExecuteCommand, [u8; 32]), XcmConverterError> { - // Get withdraw/deposit and make native tokens create message. - let result = self.native_tokens_unlock_message()?; + fn convert(&mut self) -> Result<(Command, [u8; 32]), XcmConverterError> { + let result = match self.peek() { + Ok(ReserveAssetDeposited { .. }) => self.send_native_tokens_message(), + // Get withdraw/deposit and make native tokens create message. + Ok(WithdrawAsset { .. }) => self.send_tokens_message(), + Err(e) => Err(e), + _ => return Err(XcmConverterError::UnexpectedInstruction), + }?; // All xcm instructions must be consumed before exit. if self.next().is_ok() { @@ -186,9 +222,7 @@ impl<'a, Call> XcmConverter<'a, Call> { Ok(result) } - fn native_tokens_unlock_message( - &mut self, - ) -> Result<(AgentExecuteCommand, [u8; 32]), XcmConverterError> { + fn send_tokens_message(&mut self) -> Result<(Command, [u8; 32]), XcmConverterError> { use XcmConverterError::*; // Get the reserve assets from WithdrawAsset. @@ -262,7 +296,13 @@ impl<'a, Call> XcmConverter<'a, Call> { // Check if there is a SetTopic and skip over it if found. let topic_id = match_expression!(self.next()?, SetTopic(id), id).ok_or(SetTopicExpected)?; - Ok((AgentExecuteCommand::TransferToken { token, recipient, amount }, *topic_id)) + Ok(( + Command::AgentExecute { + agent_id: self.agent_id, + command: AgentExecuteCommand::TransferToken { token, recipient, amount }, + }, + *topic_id, + )) } fn next(&mut self) -> Result<&'a Instruction, XcmConverterError> { @@ -275,9 +315,95 @@ impl<'a, Call> XcmConverter<'a, Call> { fn network_matches(&self, network: &Option) -> bool { if let Some(network) = network { - network == self.ethereum_network + *network == self.ethereum_network } else { true } } + + /// Convert the xcm for Polkadot-native token from AH into the Command + /// To match transfers of Polkadot-native tokens, we expect an input of the form: + /// # ReserveAssetDeposited + /// # ClearOrigin + /// # BuyExecution + /// # DepositAsset + /// # SetTopic + fn send_native_tokens_message(&mut self) -> Result<(Command, [u8; 32]), XcmConverterError> { + use XcmConverterError::*; + + // Get the reserve assets. + let reserve_assets = + match_expression!(self.next()?, ReserveAssetDeposited(reserve_assets), reserve_assets) + .ok_or(ReserveAssetDepositedExpected)?; + + // Check if clear origin exists and skip over it. + if match_expression!(self.peek(), Ok(ClearOrigin), ()).is_some() { + let _ = self.next(); + } + + // Get the fee asset item from BuyExecution or continue parsing. + let fee_asset = match_expression!(self.peek(), Ok(BuyExecution { fees, .. }), fees); + if fee_asset.is_some() { + let _ = self.next(); + } + + let (deposit_assets, beneficiary) = match_expression!( + self.next()?, + DepositAsset { assets, beneficiary }, + (assets, beneficiary) + ) + .ok_or(DepositAssetExpected)?; + + // assert that the beneficiary is AccountKey20. + let recipient = match_expression!( + beneficiary.unpack(), + (0, [AccountKey20 { network, key }]) + if self.network_matches(network), + H160(*key) + ) + .ok_or(BeneficiaryResolutionFailed)?; + + // Make sure there are reserved assets. + if reserve_assets.len() == 0 { + return Err(NoReserveAssets) + } + + // Check the the deposit asset filter matches what was reserved. + if reserve_assets.inner().iter().any(|asset| !deposit_assets.matches(asset)) { + return Err(FilterDoesNotConsumeAllAssets) + } + + // We only support a single asset at a time. + ensure!(reserve_assets.len() == 1, TooManyAssets); + let reserve_asset = reserve_assets.get(0).ok_or(AssetResolutionFailed)?; + + // If there was a fee specified verify it. + if let Some(fee_asset) = fee_asset { + // The fee asset must be the same as the reserve asset. + if fee_asset.id != reserve_asset.id || fee_asset.fun > reserve_asset.fun { + return Err(InvalidFeeAsset) + } + } + + let (asset_id, amount) = match reserve_asset { + Asset { id: AssetId(inner_location), fun: Fungible(amount) } => + Some((inner_location.clone(), *amount)), + _ => None, + } + .ok_or(AssetResolutionFailed)?; + + // transfer amount must be greater than 0. + ensure!(amount > 0, ZeroAssetTransfer); + + let token_id = TokenIdOf::convert_location(&asset_id).ok_or(InvalidAsset)?; + + let expected_asset_id = ConvertAssetId::convert(&token_id).ok_or(InvalidAsset)?; + + ensure!(asset_id == expected_asset_id, InvalidAsset); + + // Check if there is a SetTopic and skip over it if found. + let topic_id = match_expression!(self.next()?, SetTopic(id), id).ok_or(SetTopicExpected)?; + + Ok((Command::MintForeignToken { token_id, recipient, amount }, *topic_id)) + } } diff --git a/bridges/snowbridge/primitives/router/src/outbound/tests.rs b/bridges/snowbridge/primitives/router/src/outbound/tests.rs index 111243bb45a7..8bd3fa24df5b 100644 --- a/bridges/snowbridge/primitives/router/src/outbound/tests.rs +++ b/bridges/snowbridge/primitives/router/src/outbound/tests.rs @@ -4,7 +4,8 @@ use snowbridge_core::{ outbound::{Fee, SendError, SendMessageFeeProvider}, AgentIdOf, }; -use xcm::v3::prelude::SendError as XcmSendError; +use sp_std::default::Default; +use xcm::prelude::SendError as XcmSendError; use super::*; @@ -57,6 +58,16 @@ impl SendMessageFeeProvider for MockErrOutboundQueue { } } +pub struct MockTokenIdConvert; +impl MaybeEquivalence for MockTokenIdConvert { + fn convert(_id: &TokenId) -> Option { + Some(Location::new(1, [GlobalConsensus(Westend)])) + } + fn convert_back(_loc: &Location) -> Option { + None + } +} + #[test] fn exporter_validate_with_unknown_network_yields_not_applicable() { let network = Ethereum { chain_id: 1337 }; @@ -65,14 +76,14 @@ fn exporter_validate_with_unknown_network_yields_not_applicable() { let mut destination: Option = None; let mut message: Option> = None; - let result = EthereumBlobExporter::< - UniversalLocation, - BridgedNetwork, - MockOkOutboundQueue, - AgentIdOf, - >::validate( - network, channel, &mut universal_source, &mut destination, &mut message - ); + let result = + EthereumBlobExporter::< + UniversalLocation, + BridgedNetwork, + MockOkOutboundQueue, + AgentIdOf, + MockTokenIdConvert, + >::validate(network, channel, &mut universal_source, &mut destination, &mut message); assert_eq!(result, Err(XcmSendError::NotApplicable)); } @@ -84,14 +95,14 @@ fn exporter_validate_with_invalid_destination_yields_missing_argument() { let mut destination: Option = None; let mut message: Option> = None; - let result = EthereumBlobExporter::< - UniversalLocation, - BridgedNetwork, - MockOkOutboundQueue, - AgentIdOf, - >::validate( - network, channel, &mut universal_source, &mut destination, &mut message - ); + let result = + EthereumBlobExporter::< + UniversalLocation, + BridgedNetwork, + MockOkOutboundQueue, + AgentIdOf, + MockTokenIdConvert, + >::validate(network, channel, &mut universal_source, &mut destination, &mut message); assert_eq!(result, Err(XcmSendError::MissingArgument)); } @@ -106,14 +117,14 @@ fn exporter_validate_with_x8_destination_yields_not_applicable() { ); let mut message: Option> = None; - let result = EthereumBlobExporter::< - UniversalLocation, - BridgedNetwork, - MockOkOutboundQueue, - AgentIdOf, - >::validate( - network, channel, &mut universal_source, &mut destination, &mut message - ); + let result = + EthereumBlobExporter::< + UniversalLocation, + BridgedNetwork, + MockOkOutboundQueue, + AgentIdOf, + MockTokenIdConvert, + >::validate(network, channel, &mut universal_source, &mut destination, &mut message); assert_eq!(result, Err(XcmSendError::NotApplicable)); } @@ -125,34 +136,34 @@ fn exporter_validate_without_universal_source_yields_missing_argument() { let mut destination: Option = Here.into(); let mut message: Option> = None; - let result = EthereumBlobExporter::< - UniversalLocation, - BridgedNetwork, - MockOkOutboundQueue, - AgentIdOf, - >::validate( - network, channel, &mut universal_source, &mut destination, &mut message - ); + let result = + EthereumBlobExporter::< + UniversalLocation, + BridgedNetwork, + MockOkOutboundQueue, + AgentIdOf, + MockTokenIdConvert, + >::validate(network, channel, &mut universal_source, &mut destination, &mut message); assert_eq!(result, Err(XcmSendError::MissingArgument)); } #[test] -fn exporter_validate_without_global_universal_location_yields_unroutable() { +fn exporter_validate_without_global_universal_location_yields_not_applicable() { let network = BridgedNetwork::get(); let channel: u32 = 0; let mut universal_source: Option = Here.into(); let mut destination: Option = Here.into(); let mut message: Option> = None; - let result = EthereumBlobExporter::< - UniversalLocation, - BridgedNetwork, - MockOkOutboundQueue, - AgentIdOf, - >::validate( - network, channel, &mut universal_source, &mut destination, &mut message - ); - assert_eq!(result, Err(XcmSendError::Unroutable)); + let result = + EthereumBlobExporter::< + UniversalLocation, + BridgedNetwork, + MockOkOutboundQueue, + AgentIdOf, + MockTokenIdConvert, + >::validate(network, channel, &mut universal_source, &mut destination, &mut message); + assert_eq!(result, Err(XcmSendError::NotApplicable)); } #[test] @@ -163,14 +174,14 @@ fn exporter_validate_without_global_bridge_location_yields_not_applicable() { let mut destination: Option = Here.into(); let mut message: Option> = None; - let result = EthereumBlobExporter::< - UniversalLocation, - BridgedNetwork, - MockOkOutboundQueue, - AgentIdOf, - >::validate( - network, channel, &mut universal_source, &mut destination, &mut message - ); + let result = + EthereumBlobExporter::< + UniversalLocation, + BridgedNetwork, + MockOkOutboundQueue, + AgentIdOf, + MockTokenIdConvert, + >::validate(network, channel, &mut universal_source, &mut destination, &mut message); assert_eq!(result, Err(XcmSendError::NotApplicable)); } @@ -183,38 +194,38 @@ fn exporter_validate_with_remote_universal_source_yields_not_applicable() { let mut destination: Option = Here.into(); let mut message: Option> = None; - let result = EthereumBlobExporter::< - UniversalLocation, - BridgedNetwork, - MockOkOutboundQueue, - AgentIdOf, - >::validate( - network, channel, &mut universal_source, &mut destination, &mut message - ); + let result = + EthereumBlobExporter::< + UniversalLocation, + BridgedNetwork, + MockOkOutboundQueue, + AgentIdOf, + MockTokenIdConvert, + >::validate(network, channel, &mut universal_source, &mut destination, &mut message); assert_eq!(result, Err(XcmSendError::NotApplicable)); } #[test] -fn exporter_validate_without_para_id_in_source_yields_missing_argument() { +fn exporter_validate_without_para_id_in_source_yields_not_applicable() { let network = BridgedNetwork::get(); let channel: u32 = 0; let mut universal_source: Option = Some(GlobalConsensus(Polkadot).into()); let mut destination: Option = Here.into(); let mut message: Option> = None; - let result = EthereumBlobExporter::< - UniversalLocation, - BridgedNetwork, - MockOkOutboundQueue, - AgentIdOf, - >::validate( - network, channel, &mut universal_source, &mut destination, &mut message - ); - assert_eq!(result, Err(XcmSendError::MissingArgument)); + let result = + EthereumBlobExporter::< + UniversalLocation, + BridgedNetwork, + MockOkOutboundQueue, + AgentIdOf, + MockTokenIdConvert, + >::validate(network, channel, &mut universal_source, &mut destination, &mut message); + assert_eq!(result, Err(XcmSendError::NotApplicable)); } #[test] -fn exporter_validate_complex_para_id_in_source_yields_missing_argument() { +fn exporter_validate_complex_para_id_in_source_yields_not_applicable() { let network = BridgedNetwork::get(); let channel: u32 = 0; let mut universal_source: Option = @@ -222,15 +233,15 @@ fn exporter_validate_complex_para_id_in_source_yields_missing_argument() { let mut destination: Option = Here.into(); let mut message: Option> = None; - let result = EthereumBlobExporter::< - UniversalLocation, - BridgedNetwork, - MockOkOutboundQueue, - AgentIdOf, - >::validate( - network, channel, &mut universal_source, &mut destination, &mut message - ); - assert_eq!(result, Err(XcmSendError::MissingArgument)); + let result = + EthereumBlobExporter::< + UniversalLocation, + BridgedNetwork, + MockOkOutboundQueue, + AgentIdOf, + MockTokenIdConvert, + >::validate(network, channel, &mut universal_source, &mut destination, &mut message); + assert_eq!(result, Err(XcmSendError::NotApplicable)); } #[test] @@ -242,14 +253,14 @@ fn exporter_validate_without_xcm_message_yields_missing_argument() { let mut destination: Option = Here.into(); let mut message: Option> = None; - let result = EthereumBlobExporter::< - UniversalLocation, - BridgedNetwork, - MockOkOutboundQueue, - AgentIdOf, - >::validate( - network, channel, &mut universal_source, &mut destination, &mut message - ); + let result = + EthereumBlobExporter::< + UniversalLocation, + BridgedNetwork, + MockOkOutboundQueue, + AgentIdOf, + MockTokenIdConvert, + >::validate(network, channel, &mut universal_source, &mut destination, &mut message); assert_eq!(result, Err(XcmSendError::MissingArgument)); } @@ -289,14 +300,14 @@ fn exporter_validate_with_max_target_fee_yields_unroutable() { .into(), ); - let result = EthereumBlobExporter::< - UniversalLocation, - BridgedNetwork, - MockOkOutboundQueue, - AgentIdOf, - >::validate( - network, channel, &mut universal_source, &mut destination, &mut message - ); + let result = + EthereumBlobExporter::< + UniversalLocation, + BridgedNetwork, + MockOkOutboundQueue, + AgentIdOf, + MockTokenIdConvert, + >::validate(network, channel, &mut universal_source, &mut destination, &mut message); assert_eq!(result, Err(XcmSendError::Unroutable)); } @@ -316,14 +327,14 @@ fn exporter_validate_with_unparsable_xcm_yields_unroutable() { let mut message: Option> = Some(vec![WithdrawAsset(fees), BuyExecution { fees: fee, weight_limit: Unlimited }].into()); - let result = EthereumBlobExporter::< - UniversalLocation, - BridgedNetwork, - MockOkOutboundQueue, - AgentIdOf, - >::validate( - network, channel, &mut universal_source, &mut destination, &mut message - ); + let result = + EthereumBlobExporter::< + UniversalLocation, + BridgedNetwork, + MockOkOutboundQueue, + AgentIdOf, + MockTokenIdConvert, + >::validate(network, channel, &mut universal_source, &mut destination, &mut message); assert_eq!(result, Err(XcmSendError::Unroutable)); } @@ -362,14 +373,14 @@ fn exporter_validate_xcm_success_case_1() { .into(), ); - let result = EthereumBlobExporter::< - UniversalLocation, - BridgedNetwork, - MockOkOutboundQueue, - AgentIdOf, - >::validate( - network, channel, &mut universal_source, &mut destination, &mut message - ); + let result = + EthereumBlobExporter::< + UniversalLocation, + BridgedNetwork, + MockOkOutboundQueue, + AgentIdOf, + MockTokenIdConvert, + >::validate(network, channel, &mut universal_source, &mut destination, &mut message); assert!(result.is_ok()); } @@ -381,6 +392,7 @@ fn exporter_deliver_with_submit_failure_yields_unroutable() { BridgedNetwork, MockErrOutboundQueue, AgentIdOf, + MockTokenIdConvert, >::deliver((hex!("deadbeef").to_vec(), XcmHash::default())); assert_eq!(result, Err(XcmSendError::Transport("other transport error"))) } @@ -410,11 +422,15 @@ fn xcm_converter_convert_success() { SetTopic([0; 32]), ] .into(); - let mut converter = XcmConverter::new(&message, &network); - let expected_payload = AgentExecuteCommand::TransferToken { - token: token_address.into(), - recipient: beneficiary_address.into(), - amount: 1000, + let mut converter = + XcmConverter::::new(&message, network, Default::default()); + let expected_payload = Command::AgentExecute { + agent_id: Default::default(), + command: AgentExecuteCommand::TransferToken { + token: token_address.into(), + recipient: beneficiary_address.into(), + amount: 1000, + }, }; let result = converter.convert(); assert_eq!(result, Ok((expected_payload, [0; 32]))); @@ -443,11 +459,15 @@ fn xcm_converter_convert_without_buy_execution_yields_success() { SetTopic([0; 32]), ] .into(); - let mut converter = XcmConverter::new(&message, &network); - let expected_payload = AgentExecuteCommand::TransferToken { - token: token_address.into(), - recipient: beneficiary_address.into(), - amount: 1000, + let mut converter = + XcmConverter::::new(&message, network, Default::default()); + let expected_payload = Command::AgentExecute { + agent_id: Default::default(), + command: AgentExecuteCommand::TransferToken { + token: token_address.into(), + recipient: beneficiary_address.into(), + amount: 1000, + }, }; let result = converter.convert(); assert_eq!(result, Ok((expected_payload, [0; 32]))); @@ -478,11 +498,15 @@ fn xcm_converter_convert_with_wildcard_all_asset_filter_succeeds() { SetTopic([0; 32]), ] .into(); - let mut converter = XcmConverter::new(&message, &network); - let expected_payload = AgentExecuteCommand::TransferToken { - token: token_address.into(), - recipient: beneficiary_address.into(), - amount: 1000, + let mut converter = + XcmConverter::::new(&message, network, Default::default()); + let expected_payload = Command::AgentExecute { + agent_id: Default::default(), + command: AgentExecuteCommand::TransferToken { + token: token_address.into(), + recipient: beneficiary_address.into(), + amount: 1000, + }, }; let result = converter.convert(); assert_eq!(result, Ok((expected_payload, [0; 32]))); @@ -513,11 +537,15 @@ fn xcm_converter_convert_with_fees_less_than_reserve_yields_success() { SetTopic([0; 32]), ] .into(); - let mut converter = XcmConverter::new(&message, &network); - let expected_payload = AgentExecuteCommand::TransferToken { - token: token_address.into(), - recipient: beneficiary_address.into(), - amount: 1000, + let mut converter = + XcmConverter::::new(&message, network, Default::default()); + let expected_payload = Command::AgentExecute { + agent_id: Default::default(), + command: AgentExecuteCommand::TransferToken { + token: token_address.into(), + recipient: beneficiary_address.into(), + amount: 1000, + }, }; let result = converter.convert(); assert_eq!(result, Ok((expected_payload, [0; 32]))); @@ -547,7 +575,8 @@ fn xcm_converter_convert_without_set_topic_yields_set_topic_expected() { ClearTopic, ] .into(); - let mut converter = XcmConverter::new(&message, &network); + let mut converter = + XcmConverter::::new(&message, network, Default::default()); let result = converter.convert(); assert_eq!(result.err(), Some(XcmConverterError::SetTopicExpected)); } @@ -564,7 +593,8 @@ fn xcm_converter_convert_with_partial_message_yields_unexpected_end_of_xcm() { .into(); let message: Xcm<()> = vec![WithdrawAsset(assets)].into(); - let mut converter = XcmConverter::new(&message, &network); + let mut converter = + XcmConverter::::new(&message, network, Default::default()); let result = converter.convert(); assert_eq!(result.err(), Some(XcmConverterError::UnexpectedEndOfXcm)); } @@ -595,7 +625,8 @@ fn xcm_converter_with_different_fee_asset_fails() { SetTopic([0; 32]), ] .into(); - let mut converter = XcmConverter::new(&message, &network); + let mut converter = + XcmConverter::::new(&message, network, Default::default()); let result = converter.convert(); assert_eq!(result.err(), Some(XcmConverterError::InvalidFeeAsset)); } @@ -625,7 +656,8 @@ fn xcm_converter_with_fees_greater_than_reserve_fails() { SetTopic([0; 32]), ] .into(); - let mut converter = XcmConverter::new(&message, &network); + let mut converter = + XcmConverter::::new(&message, network, Default::default()); let result = converter.convert(); assert_eq!(result.err(), Some(XcmConverterError::InvalidFeeAsset)); } @@ -636,7 +668,8 @@ fn xcm_converter_convert_with_empty_xcm_yields_unexpected_end_of_xcm() { let message: Xcm<()> = vec![].into(); - let mut converter = XcmConverter::new(&message, &network); + let mut converter = + XcmConverter::::new(&message, network, Default::default()); let result = converter.convert(); assert_eq!(result.err(), Some(XcmConverterError::UnexpectedEndOfXcm)); @@ -668,7 +701,8 @@ fn xcm_converter_convert_with_extra_instructions_yields_end_of_xcm_message_expec ClearError, ] .into(); - let mut converter = XcmConverter::new(&message, &network); + let mut converter = + XcmConverter::::new(&message, network, Default::default()); let result = converter.convert(); assert_eq!(result.err(), Some(XcmConverterError::EndOfXcmMessageExpected)); @@ -698,10 +732,11 @@ fn xcm_converter_convert_without_withdraw_asset_yields_withdraw_expected() { SetTopic([0; 32]), ] .into(); - let mut converter = XcmConverter::new(&message, &network); + let mut converter = + XcmConverter::::new(&message, network, Default::default()); let result = converter.convert(); - assert_eq!(result.err(), Some(XcmConverterError::WithdrawAssetExpected)); + assert_eq!(result.err(), Some(XcmConverterError::UnexpectedInstruction)); } #[test] @@ -723,7 +758,8 @@ fn xcm_converter_convert_without_withdraw_asset_yields_deposit_expected() { SetTopic([0; 32]), ] .into(); - let mut converter = XcmConverter::new(&message, &network); + let mut converter = + XcmConverter::::new(&message, network, Default::default()); let result = converter.convert(); assert_eq!(result.err(), Some(XcmConverterError::DepositAssetExpected)); @@ -756,7 +792,8 @@ fn xcm_converter_convert_without_assets_yields_no_reserve_assets() { SetTopic([0; 32]), ] .into(); - let mut converter = XcmConverter::new(&message, &network); + let mut converter = + XcmConverter::::new(&message, network, Default::default()); let result = converter.convert(); assert_eq!(result.err(), Some(XcmConverterError::NoReserveAssets)); @@ -794,7 +831,8 @@ fn xcm_converter_convert_with_two_assets_yields_too_many_assets() { SetTopic([0; 32]), ] .into(); - let mut converter = XcmConverter::new(&message, &network); + let mut converter = + XcmConverter::::new(&message, network, Default::default()); let result = converter.convert(); assert_eq!(result.err(), Some(XcmConverterError::TooManyAssets)); @@ -825,7 +863,8 @@ fn xcm_converter_convert_without_consuming_filter_yields_filter_does_not_consume SetTopic([0; 32]), ] .into(); - let mut converter = XcmConverter::new(&message, &network); + let mut converter = + XcmConverter::::new(&message, network, Default::default()); let result = converter.convert(); assert_eq!(result.err(), Some(XcmConverterError::FilterDoesNotConsumeAllAssets)); @@ -856,7 +895,8 @@ fn xcm_converter_convert_with_zero_amount_asset_yields_zero_asset_transfer() { SetTopic([0; 32]), ] .into(); - let mut converter = XcmConverter::new(&message, &network); + let mut converter = + XcmConverter::::new(&message, network, Default::default()); let result = converter.convert(); assert_eq!(result.err(), Some(XcmConverterError::ZeroAssetTransfer)); @@ -886,7 +926,8 @@ fn xcm_converter_convert_non_ethereum_asset_yields_asset_resolution_failed() { SetTopic([0; 32]), ] .into(); - let mut converter = XcmConverter::new(&message, &network); + let mut converter = + XcmConverter::::new(&message, network, Default::default()); let result = converter.convert(); assert_eq!(result.err(), Some(XcmConverterError::AssetResolutionFailed)); @@ -919,7 +960,8 @@ fn xcm_converter_convert_non_ethereum_chain_asset_yields_asset_resolution_failed SetTopic([0; 32]), ] .into(); - let mut converter = XcmConverter::new(&message, &network); + let mut converter = + XcmConverter::::new(&message, network, Default::default()); let result = converter.convert(); assert_eq!(result.err(), Some(XcmConverterError::AssetResolutionFailed)); @@ -952,7 +994,8 @@ fn xcm_converter_convert_non_ethereum_chain_yields_asset_resolution_failed() { SetTopic([0; 32]), ] .into(); - let mut converter = XcmConverter::new(&message, &network); + let mut converter = + XcmConverter::::new(&message, network, Default::default()); let result = converter.convert(); assert_eq!(result.err(), Some(XcmConverterError::AssetResolutionFailed)); @@ -989,7 +1032,8 @@ fn xcm_converter_convert_with_non_ethereum_beneficiary_yields_beneficiary_resolu SetTopic([0; 32]), ] .into(); - let mut converter = XcmConverter::new(&message, &network); + let mut converter = + XcmConverter::::new(&message, network, Default::default()); let result = converter.convert(); assert_eq!(result.err(), Some(XcmConverterError::BeneficiaryResolutionFailed)); @@ -1025,7 +1069,8 @@ fn xcm_converter_convert_with_non_ethereum_chain_beneficiary_yields_beneficiary_ SetTopic([0; 32]), ] .into(); - let mut converter = XcmConverter::new(&message, &network); + let mut converter = + XcmConverter::::new(&message, network, Default::default()); let result = converter.convert(); assert_eq!(result.err(), Some(XcmConverterError::BeneficiaryResolutionFailed)); @@ -1056,3 +1101,169 @@ fn test_describe_here() { hex!("03170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c111314").into() ) } + +#[test] +fn xcm_converter_transfer_native_token_success() { + let network = BridgedNetwork::get(); + + let beneficiary_address: [u8; 20] = hex!("2000000000000000000000000000000000000000"); + + let amount = 1000000; + let asset_location = Location::new(1, [GlobalConsensus(Westend)]); + let token_id = TokenIdOf::convert_location(&asset_location).unwrap(); + + let assets: Assets = vec![Asset { id: AssetId(asset_location), fun: Fungible(amount) }].into(); + let filter: AssetFilter = assets.clone().into(); + + let message: Xcm<()> = vec![ + ReserveAssetDeposited(assets.clone()), + ClearOrigin, + BuyExecution { fees: assets.get(0).unwrap().clone(), weight_limit: Unlimited }, + DepositAsset { + assets: filter, + beneficiary: AccountKey20 { network: None, key: beneficiary_address }.into(), + }, + SetTopic([0; 32]), + ] + .into(); + let mut converter = + XcmConverter::::new(&message, network, Default::default()); + let expected_payload = + Command::MintForeignToken { recipient: beneficiary_address.into(), amount, token_id }; + let result = converter.convert(); + assert_eq!(result, Ok((expected_payload, [0; 32]))); +} + +#[test] +fn xcm_converter_transfer_native_token_with_invalid_location_will_fail() { + let network = BridgedNetwork::get(); + + let beneficiary_address: [u8; 20] = hex!("2000000000000000000000000000000000000000"); + + let amount = 1000000; + // Invalid asset location from a different consensus + let asset_location = Location { parents: 2, interior: [GlobalConsensus(Rococo)].into() }; + + let assets: Assets = vec![Asset { id: AssetId(asset_location), fun: Fungible(amount) }].into(); + let filter: AssetFilter = assets.clone().into(); + + let message: Xcm<()> = vec![ + ReserveAssetDeposited(assets.clone()), + ClearOrigin, + BuyExecution { fees: assets.get(0).unwrap().clone(), weight_limit: Unlimited }, + DepositAsset { + assets: filter, + beneficiary: AccountKey20 { network: None, key: beneficiary_address }.into(), + }, + SetTopic([0; 32]), + ] + .into(); + let mut converter = + XcmConverter::::new(&message, network, Default::default()); + let result = converter.convert(); + assert_eq!(result.err(), Some(XcmConverterError::InvalidAsset)); +} + +#[test] +fn exporter_validate_with_invalid_dest_does_not_alter_destination() { + let network = BridgedNetwork::get(); + let destination: InteriorLocation = Parachain(1000).into(); + + let universal_source: InteriorLocation = [GlobalConsensus(Polkadot), Parachain(1000)].into(); + + let token_address: [u8; 20] = hex!("1000000000000000000000000000000000000000"); + let beneficiary_address: [u8; 20] = hex!("2000000000000000000000000000000000000000"); + + let channel: u32 = 0; + let assets: Assets = vec![Asset { + id: AssetId([AccountKey20 { network: None, key: token_address }].into()), + fun: Fungible(1000), + }] + .into(); + let fee = assets.clone().get(0).unwrap().clone(); + let filter: AssetFilter = assets.clone().into(); + let msg: Xcm<()> = vec![ + WithdrawAsset(assets.clone()), + ClearOrigin, + BuyExecution { fees: fee, weight_limit: Unlimited }, + DepositAsset { + assets: filter, + beneficiary: AccountKey20 { network: None, key: beneficiary_address }.into(), + }, + SetTopic([0; 32]), + ] + .into(); + let mut msg_wrapper: Option> = Some(msg.clone()); + let mut dest_wrapper = Some(destination.clone()); + let mut universal_source_wrapper = Some(universal_source.clone()); + + let result = + EthereumBlobExporter::< + UniversalLocation, + BridgedNetwork, + MockOkOutboundQueue, + AgentIdOf, + MockTokenIdConvert, + >::validate( + network, channel, &mut universal_source_wrapper, &mut dest_wrapper, &mut msg_wrapper + ); + + assert_eq!(result, Err(XcmSendError::NotApplicable)); + + // ensure mutable variables are not changed + assert_eq!(Some(destination), dest_wrapper); + assert_eq!(Some(msg), msg_wrapper); + assert_eq!(Some(universal_source), universal_source_wrapper); +} + +#[test] +fn exporter_validate_with_invalid_universal_source_does_not_alter_universal_source() { + let network = BridgedNetwork::get(); + let destination: InteriorLocation = Here.into(); + + let universal_source: InteriorLocation = [GlobalConsensus(Westend), Parachain(1000)].into(); + + let token_address: [u8; 20] = hex!("1000000000000000000000000000000000000000"); + let beneficiary_address: [u8; 20] = hex!("2000000000000000000000000000000000000000"); + + let channel: u32 = 0; + let assets: Assets = vec![Asset { + id: AssetId([AccountKey20 { network: None, key: token_address }].into()), + fun: Fungible(1000), + }] + .into(); + let fee = assets.clone().get(0).unwrap().clone(); + let filter: AssetFilter = assets.clone().into(); + let msg: Xcm<()> = vec![ + WithdrawAsset(assets.clone()), + ClearOrigin, + BuyExecution { fees: fee, weight_limit: Unlimited }, + DepositAsset { + assets: filter, + beneficiary: AccountKey20 { network: None, key: beneficiary_address }.into(), + }, + SetTopic([0; 32]), + ] + .into(); + let mut msg_wrapper: Option> = Some(msg.clone()); + let mut dest_wrapper = Some(destination.clone()); + let mut universal_source_wrapper = Some(universal_source.clone()); + + let result = + EthereumBlobExporter::< + UniversalLocation, + BridgedNetwork, + MockOkOutboundQueue, + AgentIdOf, + MockTokenIdConvert, + >::validate( + network, channel, &mut universal_source_wrapper, &mut dest_wrapper, &mut msg_wrapper + ); + + assert_eq!(result, Err(XcmSendError::NotApplicable)); + + // ensure mutable variables are not changed + assert_eq!(Some(destination), dest_wrapper); + assert_eq!(Some(msg), msg_wrapper); + assert_eq!(Some(universal_source), universal_source_wrapper); +} diff --git a/bridges/snowbridge/runtime/runtime-common/src/lib.rs b/bridges/snowbridge/runtime/runtime-common/src/lib.rs index aae45520ff4b..0b1a74b232a0 100644 --- a/bridges/snowbridge/runtime/runtime-common/src/lib.rs +++ b/bridges/snowbridge/runtime/runtime-common/src/lib.rs @@ -50,7 +50,8 @@ impl where + > +where Balance: BaseArithmetic + Unsigned + Copy + From + Into + Debug, AccountId: Clone + FullCodec, FeeAssetLocation: Get, diff --git a/bridges/snowbridge/runtime/test-common/src/lib.rs b/bridges/snowbridge/runtime/test-common/src/lib.rs index 8f36313e360f..b157ad4356bd 100644 --- a/bridges/snowbridge/runtime/test-common/src/lib.rs +++ b/bridges/snowbridge/runtime/test-common/src/lib.rs @@ -12,7 +12,7 @@ use parachains_runtimes_test_utils::{ }; use snowbridge_core::{ChannelId, ParaId}; use snowbridge_pallet_ethereum_client_fixtures::*; -use sp_core::{H160, U256}; +use sp_core::{Get, H160, U256}; use sp_keyring::AccountKeyring::*; use sp_runtime::{traits::Header, AccountId32, DigestItem, SaturatedConversion, Saturating}; use xcm::{ @@ -466,23 +466,37 @@ pub fn ethereum_extrinsic( let initial_checkpoint = make_checkpoint(); let update = make_finalized_header_update(); let sync_committee_update = make_sync_committee_update(); + let mut invalid_update = make_finalized_header_update(); + let mut invalid_sync_committee_update = make_sync_committee_update(); + invalid_update.finalized_header.slot = 4354; + invalid_sync_committee_update.finalized_header.slot = 4354; let alice = Alice; let alice_account = alice.to_account_id(); >::mint_into( - &alice_account.into(), + &alice_account.clone().into(), 10_000_000_000_000_u128.saturated_into::>(), ) .unwrap(); + let balance_before = + >::free_balance(&alice_account.clone().into()); assert_ok!(>::force_checkpoint( RuntimeHelper::::root_origin(), - initial_checkpoint, + initial_checkpoint.clone(), )); + let balance_after_checkpoint = + >::free_balance(&alice_account.clone().into()); let update_call: ::RuntimeCall = snowbridge_pallet_ethereum_client::Call::::submit { - update: Box::new(*update), + update: Box::new(*update.clone()), + } + .into(); + + let invalid_update_call: ::RuntimeCall = + snowbridge_pallet_ethereum_client::Call::::submit { + update: Box::new(*invalid_update), } .into(); @@ -492,12 +506,63 @@ pub fn ethereum_extrinsic( } .into(); + let invalid_update_sync_committee_call: ::RuntimeCall = + snowbridge_pallet_ethereum_client::Call::::submit { + update: Box::new(*invalid_sync_committee_update), + } + .into(); + + // Finalized header update let update_outcome = construct_and_apply_extrinsic(alice, update_call.into()); assert_ok!(update_outcome); + let balance_after_update = + >::free_balance(&alice_account.clone().into()); + + // Invalid finalized header update + let invalid_update_outcome = + construct_and_apply_extrinsic(alice, invalid_update_call.into()); + assert_err!( + invalid_update_outcome, + snowbridge_pallet_ethereum_client::Error::::InvalidUpdateSlot + ); + let balance_after_invalid_update = + >::free_balance(&alice_account.clone().into()); + // Sync committee update let sync_committee_outcome = construct_and_apply_extrinsic(alice, update_sync_committee_call.into()); assert_ok!(sync_committee_outcome); + let balance_after_sync_com_update = + >::free_balance(&alice_account.clone().into()); + + // Invalid sync committee update + let invalid_sync_committee_outcome = + construct_and_apply_extrinsic(alice, invalid_update_sync_committee_call.into()); + assert_err!( + invalid_sync_committee_outcome, + snowbridge_pallet_ethereum_client::Error::::InvalidUpdateSlot + ); + let balance_after_invalid_sync_com_update = + >::free_balance(&alice_account.clone().into()); + + // Assert paid operations are charged and free operations are free + // Checkpoint is a free operation + assert!(balance_before == balance_after_checkpoint); + let gap = + ::FreeHeadersInterval::get(); + // Large enough header gap is free + if update.finalized_header.slot >= initial_checkpoint.header.slot + gap as u64 { + assert!(balance_after_checkpoint == balance_after_update); + } else { + // Otherwise paid + assert!(balance_after_checkpoint > balance_after_update); + } + // An invalid update is paid + assert!(balance_after_update > balance_after_invalid_update); + // A successful sync committee update is free + assert!(balance_after_invalid_update == balance_after_sync_com_update); + // An invalid sync committee update is paid + assert!(balance_after_sync_com_update > balance_after_invalid_sync_com_update); }); } diff --git a/bridges/testing/README.md b/bridges/testing/README.md index bd467a410d01..89a07c421e3e 100644 --- a/bridges/testing/README.md +++ b/bridges/testing/README.md @@ -1,31 +1,29 @@ # Bridges Tests for Local Rococo <> Westend Bridge This folder contains [zombienet](https://github.com/paritytech/zombienet/) based integration tests for both -onchain and offchain bridges code. Due to some -[technical difficulties](https://github.com/paritytech/parity-bridges-common/pull/2649#issue-1965339051), we -are using native zombienet provider, which means that you need to build some binaries locally. +onchain and offchain bridges code. -To start those tests, you need to: +Prerequisites for running the tests locally: - download latest [zombienet release](https://github.com/paritytech/zombienet/releases); - build Polkadot binary by running `cargo build -p polkadot --release --features fast-runtime` command in the -[`polkadot-sdk`](https://github.com/paritytech/polkadot-sdk) repository clone; + [`polkadot-sdk`](https://github.com/paritytech/polkadot-sdk) repository clone; - build Polkadot Parachain binary by running `cargo build -p polkadot-parachain-bin --release` command in the -[`polkadot-sdk`](https://github.com/paritytech/polkadot-sdk) repository clone; + [`polkadot-sdk`](https://github.com/paritytech/polkadot-sdk) repository clone; - ensure that you have [`node`](https://nodejs.org/en) installed. Additionally, we'll need globally installed -`polkadot/api-cli` package (use `npm install -g @polkadot/api-cli@beta` to install it); + `polkadot/api-cli` package (use `npm install -g @polkadot/api-cli@beta` to install it); - build Substrate relay by running `cargo build -p substrate-relay --release` command in the -[`parity-bridges-common`](https://github.com/paritytech/parity-bridges-common) repository clone. + [`parity-bridges-common`](https://github.com/paritytech/parity-bridges-common) repository clone; -- copy fresh `substrate-relay` binary, built in previous point, to the `~/local_bridge_testing/bin/substrate-relay`; +- copy the `substrate-relay` binary, built in the previous step, to `~/local_bridge_testing/bin/substrate-relay`; -- change the `POLKADOT_SDK_PATH` and `ZOMBIENET_BINARY_PATH` (and ensure that the nearby variables -have correct values) in the `./run-tests.sh`. +After that, any test can be run using the `run-test.sh` command. +Example: `./run-test.sh 0001-asset-transfer` -After that, you could run tests with the `./run-tests.sh` command. Hopefully, it'll show the +Hopefully, it'll show the "All tests have completed successfully" message in the end. Otherwise, it'll print paths to zombienet process logs, which, in turn, may be used to track locations of all spinned relay and parachain nodes. diff --git a/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh b/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh index ef4a5597902f..e7848fe7163c 100755 --- a/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh +++ b/bridges/testing/environments/rococo-westend/bridges_rococo_westend.sh @@ -53,66 +53,66 @@ ASSET_HUB_ROCOCO_SOVEREIGN_ACCOUNT_AT_BRIDGE_HUB_ROCOCO="5Eg2fntNprdN3FgH4sfEaaZ # Expected sovereign accounts for rewards on BridgeHubs. # # Generated by: -# #[test] -# fn generate_sovereign_accounts_for_rewards() { -# use bp_messages::LaneId; -# use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams}; -# use sp_core::crypto::Ss58Codec; +##[test] +#fn generate_sovereign_accounts_for_rewards() { +# use bp_messages::LegacyLaneId; +# use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams}; +# use sp_core::crypto::Ss58Codec; # -# // SS58=42 -# println!( -# "ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_ThisChain=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( -# LaneId([0, 0, 0, 2]), -# *b"bhwd", -# RewardsAccountOwner::ThisChain -# )) -# ) -# .to_ss58check_with_version(42_u16.into()) -# ); -# // SS58=42 -# println!( -# "ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_BridgedChain=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( -# LaneId([0, 0, 0, 2]), -# *b"bhwd", -# RewardsAccountOwner::BridgedChain -# )) -# ) -# .to_ss58check_with_version(42_u16.into()) -# ); +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_ThisChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32], LegacyLaneId>::rewards_account(RewardsAccountParams::new( +# LegacyLaneId([0, 0, 0, 2]), +# *b"bhwd", +# RewardsAccountOwner::ThisChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_BridgedChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32], LegacyLaneId>::rewards_account(RewardsAccountParams::new( +# LegacyLaneId([0, 0, 0, 2]), +# *b"bhwd", +# RewardsAccountOwner::BridgedChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); # -# // SS58=42 -# println!( -# "ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_ThisChain=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( -# LaneId([0, 0, 0, 2]), -# *b"bhro", -# RewardsAccountOwner::ThisChain -# )) -# ) -# .to_ss58check_with_version(42_u16.into()) -# ); -# // SS58=42 -# println!( -# "ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain=\"{}\"", -# frame_support::sp_runtime::AccountId32::new( -# PayRewardFromAccount::<[u8; 32], [u8; 32]>::rewards_account(RewardsAccountParams::new( -# LaneId([0, 0, 0, 2]), -# *b"bhro", -# RewardsAccountOwner::BridgedChain -# )) -# ) -# .to_ss58check_with_version(42_u16.into()) -# ); -# } -ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_ThisChain="5EHnXaT5BhiSGP5hbdsoVGtzi2sQVgpDNToTxLYeQvKoMPEm" -ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_BridgedChain="5EHnXaT5BhiSGP5hbdt5EJSapXYbxEv678jyWHEUskCXcjqo" -ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_ThisChain="5EHnXaT5BhiSGP5h9Rg8sgUJqoLym3iEaWUiboT8S9AT5xFh" -ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain="5EHnXaT5BhiSGP5h9RgQci1txJ2BDbp7KBRE9k8xty3BMUSi" +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_ThisChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32], LegacyLaneId>::rewards_account(RewardsAccountParams::new( +# LegacyLaneId([0, 0, 0, 2]), +# *b"bhro", +# RewardsAccountOwner::ThisChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); +# // SS58=42 +# println!( +# "ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain=\"{}\"", +# frame_support::sp_runtime::AccountId32::new( +# PayRewardFromAccount::<[u8; 32], [u8; 32], LegacyLaneId>::rewards_account(RewardsAccountParams::new( +# LegacyLaneId([0, 0, 0, 2]), +# *b"bhro", +# RewardsAccountOwner::BridgedChain +# )) +# ) +# .to_ss58check_with_version(42_u16.into()) +# ); +#} +ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_ThisChain="5EHnXaT5GApse1euZWj9hycMbgjKBCNQL9WEwScL8QDx6mhK" +ON_BRIDGE_HUB_ROCOCO_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhwd_BridgedChain="5EHnXaT5Tnt4A8aiP9CsuAFRhKPjKZJXRrj4a3mtihFvKpTi" +ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_ThisChain="5EHnXaT5GApry9tS6yd1FVusPq8o8bQJGCKyvXTFCoEKk5Z9" +ON_BRIDGE_HUB_WESTEND_SOVEREIGN_ACCOUNT_FOR_LANE_00000002_bhro_BridgedChain="5EHnXaT5Tnt3VGpEvc6jSgYwVToDGxLRMuYoZ8coo6GHyWbR" LANE_ID="00000002" XCM_VERSION=3 @@ -270,7 +270,7 @@ case "$1" in "//Alice" \ 1000 \ "ws://127.0.0.1:9910" \ - "$(jq --null-input '{ "parents": 2, "interior": { "X1": { "GlobalConsensus": "Westend" } } }')" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X1": [{ "GlobalConsensus": "Westend" }] } }')" \ "$GLOBAL_CONSENSUS_WESTEND_SOVEREIGN_ACCOUNT" \ 10000000000 \ true @@ -329,7 +329,7 @@ case "$1" in "//Alice" \ 1000 \ "ws://127.0.0.1:9010" \ - "$(jq --null-input '{ "parents": 2, "interior": { "X1": { "GlobalConsensus": "Rococo" } } }')" \ + "$(jq --null-input '{ "parents": 2, "interior": { "X1": [{ "GlobalConsensus": "Rococo" }] } }')" \ "$GLOBAL_CONSENSUS_ROCOCO_SOVEREIGN_ACCOUNT" \ 10000000000 \ true diff --git a/bridges/testing/framework/js-helpers/only-required-headers-synced-when-idle.js b/bridges/testing/framework/js-helpers/only-required-headers-synced-when-active.js similarity index 94% rename from bridges/testing/framework/js-helpers/only-required-headers-synced-when-idle.js rename to bridges/testing/framework/js-helpers/only-required-headers-synced-when-active.js index 8c3130e4fd96..61738a21e38e 100644 --- a/bridges/testing/framework/js-helpers/only-required-headers-synced-when-idle.js +++ b/bridges/testing/framework/js-helpers/only-required-headers-synced-when-active.js @@ -65,8 +65,12 @@ async function run(nodeName, networkInfo, args) { // wait until we have received + delivered messages OR until timeout await utils.pollUntil( exitAfterSeconds, - () => { return atLeastOneMessageReceived && atLeastOneMessageDelivered; }, - () => { unsubscribe(); }, + () => { + return atLeastOneMessageReceived && atLeastOneMessageDelivered; + }, + () => { + unsubscribe(); + }, () => { if (!atLeastOneMessageReceived) { throw new Error("No messages received from bridged chain"); @@ -78,4 +82,4 @@ async function run(nodeName, networkInfo, args) { ); } -module.exports = { run } +module.exports = {run} diff --git a/bridges/testing/framework/js-helpers/wrapped-assets-balance.js b/bridges/testing/framework/js-helpers/wrapped-assets-balance.js index 27287118547f..7b343ed97a88 100644 --- a/bridges/testing/framework/js-helpers/wrapped-assets-balance.js +++ b/bridges/testing/framework/js-helpers/wrapped-assets-balance.js @@ -8,7 +8,7 @@ async function run(nodeName, networkInfo, args) { const bridgedNetworkName = args[2]; while (true) { const foreignAssetAccount = await api.query.foreignAssets.account( - { parents: 2, interior: { X1: { GlobalConsensus: bridgedNetworkName } } }, + { parents: 2, interior: { X1: [{ GlobalConsensus: bridgedNetworkName }] } }, accountAddress ); if (foreignAssetAccount.isSome) { diff --git a/bridges/testing/framework/utils/generate_hex_encoded_call/package-lock.json b/bridges/testing/framework/utils/generate_hex_encoded_call/package-lock.json deleted file mode 100644 index ca3abcc528cf..000000000000 --- a/bridges/testing/framework/utils/generate_hex_encoded_call/package-lock.json +++ /dev/null @@ -1,759 +0,0 @@ -{ - "name": "y", - "version": "y", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "y", - "version": "y", - "license": "MIT", - "dependencies": { - "@polkadot/api": "^10.11", - "@polkadot/util": "^12.6" - } - }, - "node_modules/@noble/curves": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.3.0.tgz", - "integrity": "sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==", - "dependencies": { - "@noble/hashes": "1.3.3" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", - "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@polkadot/api": { - "version": "10.11.2", - "resolved": "https://registry.npmjs.org/@polkadot/api/-/api-10.11.2.tgz", - "integrity": "sha512-AorCZxCWCoTtdbl4DPUZh+ACe/pbLIS1BkdQY0AFJuZllm0x/yWzjgampcPd5jQAA/O3iKShRBkZqj6Mk9yG/A==", - "dependencies": { - "@polkadot/api-augment": "10.11.2", - "@polkadot/api-base": "10.11.2", - "@polkadot/api-derive": "10.11.2", - "@polkadot/keyring": "^12.6.2", - "@polkadot/rpc-augment": "10.11.2", - "@polkadot/rpc-core": "10.11.2", - "@polkadot/rpc-provider": "10.11.2", - "@polkadot/types": "10.11.2", - "@polkadot/types-augment": "10.11.2", - "@polkadot/types-codec": "10.11.2", - "@polkadot/types-create": "10.11.2", - "@polkadot/types-known": "10.11.2", - "@polkadot/util": "^12.6.2", - "@polkadot/util-crypto": "^12.6.2", - "eventemitter3": "^5.0.1", - "rxjs": "^7.8.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@polkadot/api-augment": { - "version": "10.11.2", - "resolved": "https://registry.npmjs.org/@polkadot/api-augment/-/api-augment-10.11.2.tgz", - "integrity": "sha512-PTpnqpezc75qBqUtgrc0GYB8h9UHjfbHSRZamAbecIVAJ2/zc6CqtnldeaBlIu1IKTgBzi3FFtTyYu+ZGbNT2Q==", - "dependencies": { - "@polkadot/api-base": "10.11.2", - "@polkadot/rpc-augment": "10.11.2", - "@polkadot/types": "10.11.2", - "@polkadot/types-augment": "10.11.2", - "@polkadot/types-codec": "10.11.2", - "@polkadot/util": "^12.6.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@polkadot/api-base": { - "version": "10.11.2", - "resolved": "https://registry.npmjs.org/@polkadot/api-base/-/api-base-10.11.2.tgz", - "integrity": "sha512-4LIjaUfO9nOzilxo7XqzYKCNMtmUypdk8oHPdrRnSjKEsnK7vDsNi+979z2KXNXd2KFSCFHENmI523fYnMnReg==", - "dependencies": { - "@polkadot/rpc-core": "10.11.2", - "@polkadot/types": "10.11.2", - "@polkadot/util": "^12.6.2", - "rxjs": "^7.8.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@polkadot/api-derive": { - "version": "10.11.2", - "resolved": "https://registry.npmjs.org/@polkadot/api-derive/-/api-derive-10.11.2.tgz", - "integrity": "sha512-m3BQbPionkd1iSlknddxnL2hDtolPIsT+aRyrtn4zgMRPoLjHFmTmovvg8RaUyYofJtZeYrnjMw0mdxiSXx7eA==", - "dependencies": { - "@polkadot/api": "10.11.2", - "@polkadot/api-augment": "10.11.2", - "@polkadot/api-base": "10.11.2", - "@polkadot/rpc-core": "10.11.2", - "@polkadot/types": "10.11.2", - "@polkadot/types-codec": "10.11.2", - "@polkadot/util": "^12.6.2", - "@polkadot/util-crypto": "^12.6.2", - "rxjs": "^7.8.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@polkadot/keyring": { - "version": "12.6.2", - "resolved": "https://registry.npmjs.org/@polkadot/keyring/-/keyring-12.6.2.tgz", - "integrity": "sha512-O3Q7GVmRYm8q7HuB3S0+Yf/q/EB2egKRRU3fv9b3B7V+A52tKzA+vIwEmNVaD1g5FKW9oB97rmpggs0zaKFqHw==", - "dependencies": { - "@polkadot/util": "12.6.2", - "@polkadot/util-crypto": "12.6.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@polkadot/util": "12.6.2", - "@polkadot/util-crypto": "12.6.2" - } - }, - "node_modules/@polkadot/networks": { - "version": "12.6.2", - "resolved": "https://registry.npmjs.org/@polkadot/networks/-/networks-12.6.2.tgz", - "integrity": "sha512-1oWtZm1IvPWqvMrldVH6NI2gBoCndl5GEwx7lAuQWGr7eNL+6Bdc5K3Z9T0MzFvDGoi2/CBqjX9dRKo39pDC/w==", - "dependencies": { - "@polkadot/util": "12.6.2", - "@substrate/ss58-registry": "^1.44.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@polkadot/rpc-augment": { - "version": "10.11.2", - "resolved": "https://registry.npmjs.org/@polkadot/rpc-augment/-/rpc-augment-10.11.2.tgz", - "integrity": "sha512-9AhT0WW81/8jYbRcAC6PRmuxXqNhJje8OYiulBQHbG1DTCcjAfz+6VQBke9BwTStzPq7d526+yyBKD17O3zlAA==", - "dependencies": { - "@polkadot/rpc-core": "10.11.2", - "@polkadot/types": "10.11.2", - "@polkadot/types-codec": "10.11.2", - "@polkadot/util": "^12.6.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@polkadot/rpc-core": { - "version": "10.11.2", - "resolved": "https://registry.npmjs.org/@polkadot/rpc-core/-/rpc-core-10.11.2.tgz", - "integrity": "sha512-Ot0CFLWx8sZhLZog20WDuniPA01Bk2StNDsdAQgcFKPwZw6ShPaZQCHuKLQK6I6DodOrem9FXX7c1hvoKJP5Ww==", - "dependencies": { - "@polkadot/rpc-augment": "10.11.2", - "@polkadot/rpc-provider": "10.11.2", - "@polkadot/types": "10.11.2", - "@polkadot/util": "^12.6.2", - "rxjs": "^7.8.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@polkadot/rpc-provider": { - "version": "10.11.2", - "resolved": "https://registry.npmjs.org/@polkadot/rpc-provider/-/rpc-provider-10.11.2.tgz", - "integrity": "sha512-he5jWMpDJp7e+vUzTZDzpkB7ps3H8psRally+/ZvZZScPvFEjfczT7I1WWY9h58s8+ImeVP/lkXjL9h/gUOt3Q==", - "dependencies": { - "@polkadot/keyring": "^12.6.2", - "@polkadot/types": "10.11.2", - "@polkadot/types-support": "10.11.2", - "@polkadot/util": "^12.6.2", - "@polkadot/util-crypto": "^12.6.2", - "@polkadot/x-fetch": "^12.6.2", - "@polkadot/x-global": "^12.6.2", - "@polkadot/x-ws": "^12.6.2", - "eventemitter3": "^5.0.1", - "mock-socket": "^9.3.1", - "nock": "^13.4.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@substrate/connect": "0.7.35" - } - }, - "node_modules/@polkadot/types": { - "version": "10.11.2", - "resolved": "https://registry.npmjs.org/@polkadot/types/-/types-10.11.2.tgz", - "integrity": "sha512-d52j3xXni+C8GdYZVTSfu8ROAnzXFMlyRvXtor0PudUc8UQHOaC4+mYAkTBGA2gKdmL8MHSfRSbhcxHhsikY6Q==", - "dependencies": { - "@polkadot/keyring": "^12.6.2", - "@polkadot/types-augment": "10.11.2", - "@polkadot/types-codec": "10.11.2", - "@polkadot/types-create": "10.11.2", - "@polkadot/util": "^12.6.2", - "@polkadot/util-crypto": "^12.6.2", - "rxjs": "^7.8.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@polkadot/types-augment": { - "version": "10.11.2", - "resolved": "https://registry.npmjs.org/@polkadot/types-augment/-/types-augment-10.11.2.tgz", - "integrity": "sha512-8eB8ew04wZiE5GnmFvEFW1euJWmF62SGxb1O+8wL3zoUtB9Xgo1vB6w6xbTrd+HLV6jNSeXXnbbF1BEUvi9cNg==", - "dependencies": { - "@polkadot/types": "10.11.2", - "@polkadot/types-codec": "10.11.2", - "@polkadot/util": "^12.6.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@polkadot/types-codec": { - "version": "10.11.2", - "resolved": "https://registry.npmjs.org/@polkadot/types-codec/-/types-codec-10.11.2.tgz", - "integrity": "sha512-3xjOQL+LOOMzYqlgP9ROL0FQnzU8lGflgYewzau7AsDlFziSEtb49a9BpYo6zil4koC+QB8zQ9OHGFumG08T8w==", - "dependencies": { - "@polkadot/util": "^12.6.2", - "@polkadot/x-bigint": "^12.6.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@polkadot/types-create": { - "version": "10.11.2", - "resolved": "https://registry.npmjs.org/@polkadot/types-create/-/types-create-10.11.2.tgz", - "integrity": "sha512-SJt23NxYvefRxVZZm6mT9ed1pR6FDoIGQ3xUpbjhTLfU2wuhpKjekMVorYQ6z/gK2JLMu2kV92Ardsz+6GX5XQ==", - "dependencies": { - "@polkadot/types-codec": "10.11.2", - "@polkadot/util": "^12.6.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@polkadot/types-known": { - "version": "10.11.2", - "resolved": "https://registry.npmjs.org/@polkadot/types-known/-/types-known-10.11.2.tgz", - "integrity": "sha512-kbEIX7NUQFxpDB0FFGNyXX/odY7jbp56RGD+Z4A731fW2xh/DgAQrI994xTzuh0c0EqPE26oQm3kATSpseqo9w==", - "dependencies": { - "@polkadot/networks": "^12.6.2", - "@polkadot/types": "10.11.2", - "@polkadot/types-codec": "10.11.2", - "@polkadot/types-create": "10.11.2", - "@polkadot/util": "^12.6.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@polkadot/types-support": { - "version": "10.11.2", - "resolved": "https://registry.npmjs.org/@polkadot/types-support/-/types-support-10.11.2.tgz", - "integrity": "sha512-X11hoykFYv/3efg4coZy2hUOUc97JhjQMJLzDhHniFwGLlYU8MeLnPdCVGkXx0xDDjTo4/ptS1XpZ5HYcg+gRw==", - "dependencies": { - "@polkadot/util": "^12.6.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@polkadot/util": { - "version": "12.6.2", - "resolved": "https://registry.npmjs.org/@polkadot/util/-/util-12.6.2.tgz", - "integrity": "sha512-l8TubR7CLEY47240uki0TQzFvtnxFIO7uI/0GoWzpYD/O62EIAMRsuY01N4DuwgKq2ZWD59WhzsLYmA5K6ksdw==", - "dependencies": { - "@polkadot/x-bigint": "12.6.2", - "@polkadot/x-global": "12.6.2", - "@polkadot/x-textdecoder": "12.6.2", - "@polkadot/x-textencoder": "12.6.2", - "@types/bn.js": "^5.1.5", - "bn.js": "^5.2.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@polkadot/util-crypto": { - "version": "12.6.2", - "resolved": "https://registry.npmjs.org/@polkadot/util-crypto/-/util-crypto-12.6.2.tgz", - "integrity": "sha512-FEWI/dJ7wDMNN1WOzZAjQoIcCP/3vz3wvAp5QQm+lOrzOLj0iDmaIGIcBkz8HVm3ErfSe/uKP0KS4jgV/ib+Mg==", - "dependencies": { - "@noble/curves": "^1.3.0", - "@noble/hashes": "^1.3.3", - "@polkadot/networks": "12.6.2", - "@polkadot/util": "12.6.2", - "@polkadot/wasm-crypto": "^7.3.2", - "@polkadot/wasm-util": "^7.3.2", - "@polkadot/x-bigint": "12.6.2", - "@polkadot/x-randomvalues": "12.6.2", - "@scure/base": "^1.1.5", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@polkadot/util": "12.6.2" - } - }, - "node_modules/@polkadot/wasm-bridge": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/@polkadot/wasm-bridge/-/wasm-bridge-7.3.2.tgz", - "integrity": "sha512-AJEXChcf/nKXd5Q/YLEV5dXQMle3UNT7jcXYmIffZAo/KI394a+/24PaISyQjoNC0fkzS1Q8T5pnGGHmXiVz2g==", - "dependencies": { - "@polkadot/wasm-util": "7.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@polkadot/util": "*", - "@polkadot/x-randomvalues": "*" - } - }, - "node_modules/@polkadot/wasm-crypto": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto/-/wasm-crypto-7.3.2.tgz", - "integrity": "sha512-+neIDLSJ6jjVXsjyZ5oLSv16oIpwp+PxFqTUaZdZDoA2EyFRQB8pP7+qLsMNk+WJuhuJ4qXil/7XiOnZYZ+wxw==", - "dependencies": { - "@polkadot/wasm-bridge": "7.3.2", - "@polkadot/wasm-crypto-asmjs": "7.3.2", - "@polkadot/wasm-crypto-init": "7.3.2", - "@polkadot/wasm-crypto-wasm": "7.3.2", - "@polkadot/wasm-util": "7.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@polkadot/util": "*", - "@polkadot/x-randomvalues": "*" - } - }, - "node_modules/@polkadot/wasm-crypto-asmjs": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-asmjs/-/wasm-crypto-asmjs-7.3.2.tgz", - "integrity": "sha512-QP5eiUqUFur/2UoF2KKKYJcesc71fXhQFLT3D4ZjG28Mfk2ZPI0QNRUfpcxVQmIUpV5USHg4geCBNuCYsMm20Q==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@polkadot/util": "*" - } - }, - "node_modules/@polkadot/wasm-crypto-init": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-init/-/wasm-crypto-init-7.3.2.tgz", - "integrity": "sha512-FPq73zGmvZtnuJaFV44brze3Lkrki3b4PebxCy9Fplw8nTmisKo9Xxtfew08r0njyYh+uiJRAxPCXadkC9sc8g==", - "dependencies": { - "@polkadot/wasm-bridge": "7.3.2", - "@polkadot/wasm-crypto-asmjs": "7.3.2", - "@polkadot/wasm-crypto-wasm": "7.3.2", - "@polkadot/wasm-util": "7.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@polkadot/util": "*", - "@polkadot/x-randomvalues": "*" - } - }, - "node_modules/@polkadot/wasm-crypto-wasm": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/@polkadot/wasm-crypto-wasm/-/wasm-crypto-wasm-7.3.2.tgz", - "integrity": "sha512-15wd0EMv9IXs5Abp1ZKpKKAVyZPhATIAHfKsyoWCEFDLSOA0/K0QGOxzrAlsrdUkiKZOq7uzSIgIDgW8okx2Mw==", - "dependencies": { - "@polkadot/wasm-util": "7.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@polkadot/util": "*" - } - }, - "node_modules/@polkadot/wasm-util": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/@polkadot/wasm-util/-/wasm-util-7.3.2.tgz", - "integrity": "sha512-bmD+Dxo1lTZyZNxbyPE380wd82QsX+43mgCm40boyKrRppXEyQmWT98v/Poc7chLuskYb6X8IQ6lvvK2bGR4Tg==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@polkadot/util": "*" - } - }, - "node_modules/@polkadot/x-bigint": { - "version": "12.6.2", - "resolved": "https://registry.npmjs.org/@polkadot/x-bigint/-/x-bigint-12.6.2.tgz", - "integrity": "sha512-HSIk60uFPX4GOFZSnIF7VYJz7WZA7tpFJsne7SzxOooRwMTWEtw3fUpFy5cYYOeLh17/kHH1Y7SVcuxzVLc74Q==", - "dependencies": { - "@polkadot/x-global": "12.6.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@polkadot/x-fetch": { - "version": "12.6.2", - "resolved": "https://registry.npmjs.org/@polkadot/x-fetch/-/x-fetch-12.6.2.tgz", - "integrity": "sha512-8wM/Z9JJPWN1pzSpU7XxTI1ldj/AfC8hKioBlUahZ8gUiJaOF7K9XEFCrCDLis/A1BoOu7Ne6WMx/vsJJIbDWw==", - "dependencies": { - "@polkadot/x-global": "12.6.2", - "node-fetch": "^3.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@polkadot/x-global": { - "version": "12.6.2", - "resolved": "https://registry.npmjs.org/@polkadot/x-global/-/x-global-12.6.2.tgz", - "integrity": "sha512-a8d6m+PW98jmsYDtAWp88qS4dl8DyqUBsd0S+WgyfSMtpEXu6v9nXDgPZgwF5xdDvXhm+P0ZfVkVTnIGrScb5g==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@polkadot/x-randomvalues": { - "version": "12.6.2", - "resolved": "https://registry.npmjs.org/@polkadot/x-randomvalues/-/x-randomvalues-12.6.2.tgz", - "integrity": "sha512-Vr8uG7rH2IcNJwtyf5ebdODMcr0XjoCpUbI91Zv6AlKVYOGKZlKLYJHIwpTaKKB+7KPWyQrk4Mlym/rS7v9feg==", - "dependencies": { - "@polkadot/x-global": "12.6.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@polkadot/util": "12.6.2", - "@polkadot/wasm-util": "*" - } - }, - "node_modules/@polkadot/x-textdecoder": { - "version": "12.6.2", - "resolved": "https://registry.npmjs.org/@polkadot/x-textdecoder/-/x-textdecoder-12.6.2.tgz", - "integrity": "sha512-M1Bir7tYvNappfpFWXOJcnxUhBUFWkUFIdJSyH0zs5LmFtFdbKAeiDXxSp2Swp5ddOZdZgPac294/o2TnQKN1w==", - "dependencies": { - "@polkadot/x-global": "12.6.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@polkadot/x-textencoder": { - "version": "12.6.2", - "resolved": "https://registry.npmjs.org/@polkadot/x-textencoder/-/x-textencoder-12.6.2.tgz", - "integrity": "sha512-4N+3UVCpI489tUJ6cv3uf0PjOHvgGp9Dl+SZRLgFGt9mvxnvpW/7+XBADRMtlG4xi5gaRK7bgl5bmY6OMDsNdw==", - "dependencies": { - "@polkadot/x-global": "12.6.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@polkadot/x-ws": { - "version": "12.6.2", - "resolved": "https://registry.npmjs.org/@polkadot/x-ws/-/x-ws-12.6.2.tgz", - "integrity": "sha512-cGZWo7K5eRRQCRl2LrcyCYsrc3lRbTlixZh3AzgU8uX4wASVGRlNWi/Hf4TtHNe1ExCDmxabJzdIsABIfrr7xw==", - "dependencies": { - "@polkadot/x-global": "12.6.2", - "tslib": "^2.6.2", - "ws": "^8.15.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@scure/base": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.5.tgz", - "integrity": "sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ==", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@substrate/connect": { - "version": "0.7.35", - "resolved": "https://registry.npmjs.org/@substrate/connect/-/connect-0.7.35.tgz", - "integrity": "sha512-Io8vkalbwaye+7yXfG1Nj52tOOoJln2bMlc7Q9Yy3vEWqZEVkgKmcPVzbwV0CWL3QD+KMPDA2Dnw/X7EdwgoLw==", - "hasInstallScript": true, - "optional": true, - "dependencies": { - "@substrate/connect-extension-protocol": "^1.0.1", - "smoldot": "2.0.7" - } - }, - "node_modules/@substrate/connect-extension-protocol": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@substrate/connect-extension-protocol/-/connect-extension-protocol-1.0.1.tgz", - "integrity": "sha512-161JhCC1csjH3GE5mPLEd7HbWtwNSPJBg3p1Ksz9SFlTzj/bgEwudiRN2y5i0MoLGCIJRYKyKGMxVnd29PzNjg==", - "optional": true - }, - "node_modules/@substrate/ss58-registry": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/@substrate/ss58-registry/-/ss58-registry-1.44.0.tgz", - "integrity": "sha512-7lQ/7mMCzVNSEfDS4BCqnRnKCFKpcOaPrxMeGTXHX1YQzM/m2BBHjbK2C3dJvjv7GYxMiaTq/HdWQj1xS6ss+A==" - }, - "node_modules/@types/bn.js": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.5.tgz", - "integrity": "sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/node": { - "version": "20.10.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", - "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" - }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "engines": { - "node": ">= 12" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" - }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" - }, - "node_modules/mock-socket": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.3.1.tgz", - "integrity": "sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/nock": { - "version": "13.4.0", - "resolved": "https://registry.npmjs.org/nock/-/nock-13.4.0.tgz", - "integrity": "sha512-W8NVHjO/LCTNA64yxAPHV/K47LpGYcVzgKd3Q0n6owhwvD0Dgoterc25R4rnZbckJEb6Loxz1f5QMuJpJnbSyQ==", - "dependencies": { - "debug": "^4.1.0", - "json-stringify-safe": "^5.0.1", - "propagate": "^2.0.0" - }, - "engines": { - "node": ">= 10.13" - } - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, - "node_modules/propagate": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", - "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/smoldot": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/smoldot/-/smoldot-2.0.7.tgz", - "integrity": "sha512-VAOBqEen6vises36/zgrmAT1GWk2qE3X8AGnO7lmQFdskbKx8EovnwS22rtPAG+Y1Rk23/S22kDJUdPANyPkBA==", - "optional": true, - "dependencies": { - "ws": "^8.8.1" - } - }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" - }, - "node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - } - } -} diff --git a/bridges/testing/framework/utils/generate_hex_encoded_call/package.json b/bridges/testing/framework/utils/generate_hex_encoded_call/package.json index ecf0a2483db1..d3406c97c61a 100644 --- a/bridges/testing/framework/utils/generate_hex_encoded_call/package.json +++ b/bridges/testing/framework/utils/generate_hex_encoded_call/package.json @@ -5,7 +5,7 @@ "main": "index.js", "license": "MIT", "dependencies": { - "@polkadot/api": "^10.11", - "@polkadot/util": "^12.6" + "@polkadot/api": "^14.0", + "@polkadot/util": "^13.1" } } diff --git a/bridges/testing/run-new-test.sh b/bridges/testing/run-test.sh similarity index 100% rename from bridges/testing/run-new-test.sh rename to bridges/testing/run-test.sh diff --git a/bridges/testing/run-tests.sh b/bridges/testing/run-tests.sh deleted file mode 100755 index fd12b57f5334..000000000000 --- a/bridges/testing/run-tests.sh +++ /dev/null @@ -1,138 +0,0 @@ -#!/bin/bash -set -x -shopt -s nullglob - -trap "trap - SIGINT SIGTERM EXIT && killall -q -9 substrate-relay && kill -- -$$" SIGINT SIGTERM EXIT - -# run tests in range [TESTS_BEGIN; TESTS_END) -TESTS_BEGIN=1 -TESTS_END=1000 -# whether to use paths for zombienet+bridges tests container or for local testing -ZOMBIENET_DOCKER_PATHS=0 -while [ $# -ne 0 ] -do - arg="$1" - case "$arg" in - --docker) - ZOMBIENET_DOCKER_PATHS=1 - ;; - --test) - shift - TESTS_BEGIN="$1" - TESTS_END="$1" - ;; - esac - shift -done - -# assuming that we'll be using native provide && all processes will be executing locally -# (we need absolute paths here, because they're used when scripts are called by zombienet from tmp folders) -export POLKADOT_SDK_PATH=`realpath $(dirname "$0")/../..` -export BRIDGE_TESTS_FOLDER=$POLKADOT_SDK_PATH/bridges/testing/tests - -# set path to binaries -if [ "$ZOMBIENET_DOCKER_PATHS" -eq 1 ]; then - export POLKADOT_BINARY=/usr/local/bin/polkadot - export POLKADOT_PARACHAIN_BINARY=/usr/local/bin/polkadot-parachain - - export SUBSTRATE_RELAY_BINARY=/usr/local/bin/substrate-relay - export ZOMBIENET_BINARY_PATH=/usr/local/bin/zombie -else - export POLKADOT_BINARY=$POLKADOT_SDK_PATH/target/release/polkadot - export POLKADOT_PARACHAIN_BINARY=$POLKADOT_SDK_PATH/target/release/polkadot-parachain - - export SUBSTRATE_RELAY_BINARY=~/local_bridge_testing/bin/substrate-relay - export ZOMBIENET_BINARY_PATH=~/local_bridge_testing/bin/zombienet-linux -fi - -# check if `wait` supports -p flag -if [ `printf "$BASH_VERSION\n5.1" | sort -V | head -n 1` = "5.1" ]; then IS_BASH_5_1=1; else IS_BASH_5_1=0; fi - -# bridge configuration -export LANE_ID="00000002" - -# tests configuration -ALL_TESTS_FOLDER=`mktemp -d /tmp/bridges-zombienet-tests.XXXXX` - -function start_coproc() { - local command=$1 - local name=$2 - local logname=`basename $name` - local coproc_log=`mktemp -p $TEST_FOLDER $logname.XXXXX` - coproc COPROC { - # otherwise zombienet uses some hardcoded paths - unset RUN_IN_CONTAINER - unset ZOMBIENET_IMAGE - - $command >$coproc_log 2>&1 - } - TEST_COPROCS[$COPROC_PID, 0]=$name - TEST_COPROCS[$COPROC_PID, 1]=$coproc_log - echo "Spawned $name coprocess. StdOut + StdErr: $coproc_log" - - return $COPROC_PID -} - -# execute every test from tests folder -TEST_INDEX=$TESTS_BEGIN -while true -do - declare -A TEST_COPROCS - TEST_COPROCS_COUNT=0 - TEST_PREFIX=$(printf "%04d" $TEST_INDEX) - - # it'll be used by the `sync-exit.sh` script - export TEST_FOLDER=`mktemp -d -p $ALL_TESTS_FOLDER test-$TEST_PREFIX.XXXXX` - - # check if there are no more tests - zndsl_files=($BRIDGE_TESTS_FOLDER/$TEST_PREFIX-*.zndsl) - if [ ${#zndsl_files[@]} -eq 0 ]; then - break - fi - - # start tests - for zndsl_file in "${zndsl_files[@]}"; do - start_coproc "$ZOMBIENET_BINARY_PATH --provider native test $zndsl_file" "$zndsl_file" - echo -n "1">>$TEST_FOLDER/exit-sync - ((TEST_COPROCS_COUNT++)) - done - # wait until all tests are completed - for n in `seq 1 $TEST_COPROCS_COUNT`; do - if [ "$IS_BASH_5_1" -eq 1 ]; then - wait -n -p COPROC_PID - exit_code=$? - coproc_name=${TEST_COPROCS[$COPROC_PID, 0]} - coproc_log=${TEST_COPROCS[$COPROC_PID, 1]} - coproc_stdout=$(cat $coproc_log) - else - wait -n - exit_code=$? - coproc_name="" - coproc_stdout="" - fi - echo "Process $coproc_name has finished with exit code: $exit_code" - - # if exit code is not zero, exit - if [ $exit_code -ne 0 ]; then - echo "=====================================================================" - echo "=== Shutting down. Log of failed process below ===" - echo "=====================================================================" - echo "$coproc_stdout" - - exit 1 - fi - done - - # proceed to next index - ((TEST_INDEX++)) - if [ "$TEST_INDEX" -ge "$TESTS_END" ]; then - break - fi - - # kill relay here - it is started manually by tests - killall substrate-relay -done - -echo "=====================================================================" -echo "=== All tests have completed successfully ===" -echo "=====================================================================" diff --git a/bridges/testing/tests/0003-required-headers-synced-while-active-rococo-to-westend.zndsl b/bridges/testing/tests/0003-required-headers-synced-while-active-rococo-to-westend.zndsl deleted file mode 100644 index 07b91481dc7c..000000000000 --- a/bridges/testing/tests/0003-required-headers-synced-while-active-rococo-to-westend.zndsl +++ /dev/null @@ -1,26 +0,0 @@ -Description: While relayer is active, we only sync mandatory and required Rococo (and Rococo BH) headers to Westend BH. -Network: ../environments/rococo-westend/bridge_hub_westend_local_network.toml -Creds: config - -# step 1: initialize Westend AH -asset-hub-westend-collator1: run ../scripts/invoke-script.sh with "init-asset-hub-westend-local" within 60 seconds - -# step 2: initialize Westend bridge hub -bridge-hub-westend-collator1: run ../scripts/invoke-script.sh with "init-bridge-hub-westend-local" within 60 seconds - -# step 3: ensure that initialization has completed -asset-hub-westend-collator1: js-script ../js-helpers/wait-hrmp-channel-opened.js with "1002" within 600 seconds - -# step 4: send message from Westend to Rococo -asset-hub-westend-collator1: run ../scripts/invoke-script.sh with "reserve-transfer-assets-from-asset-hub-westend-local" within 60 seconds - -# step 5: start relayer -# (we are starting it after sending the message to be sure that relayer won't relay messages before our js script -# will be started at step 6) -# (it is started by sibling 0003-required-headers-synced-while-active-westend-to-rococo.zndsl) - -# step 6: ensure that relayer won't sync any extra headers while delivering messages and confirmations -bridge-hub-westend-collator1: js-script ../js-helpers/only-required-headers-synced-when-active.js with "500,rococo-at-westend" within 600 seconds - -# wait until other network test has completed OR exit with an error too -asset-hub-westend-collator1: run ../scripts/sync-exit.sh within 600 seconds diff --git a/bridges/testing/tests/0003-required-headers-synced-while-active-westend-to-rococo.zndsl b/bridges/testing/tests/0003-required-headers-synced-while-active-westend-to-rococo.zndsl deleted file mode 100644 index a6b11fc24052..000000000000 --- a/bridges/testing/tests/0003-required-headers-synced-while-active-westend-to-rococo.zndsl +++ /dev/null @@ -1,26 +0,0 @@ -Description: While relayer is active, we only sync mandatory and required Westend (and Westend BH) headers to Rococo BH. -Network: ../environments/rococo-westend/bridge_hub_rococo_local_network.toml -Creds: config - -# step 1: initialize Rococo AH -asset-hub-rococo-collator1: run ../scripts/invoke-script.sh with "init-asset-hub-rococo-local" within 60 seconds - -# step 2: initialize Rococo bridge hub -bridge-hub-rococo-collator1: run ../scripts/invoke-script.sh with "init-bridge-hub-rococo-local" within 60 seconds - -# step 3: ensure that initialization has completed -asset-hub-rococo-collator1: js-script ../js-helpers/wait-hrmp-channel-opened.js with "1013" within 600 seconds - -# step 4: send message from Rococo to Westend -asset-hub-rococo-collator1: run ../scripts/invoke-script.sh with "reserve-transfer-assets-from-asset-hub-rococo-local" within 60 seconds - -# step 5: start relayer -# (we are starting it after sending the message to be sure that relayer won't relay messages before our js script -# will be started at step 6) -bridge-hub-rococo-collator1: run ../scripts/start-relayer.sh within 60 seconds - -# step 6: ensure that relayer won't sync any extra headers while delivering messages and confirmations -bridge-hub-rococo-collator1: js-script ../js-helpers/only-required-headers-synced-when-active.js with "500,westend-at-rococo" within 600 seconds - -# wait until other network test has completed OR exit with an error too -asset-hub-rococo-collator1: run ../scripts/sync-exit.sh within 600 seconds diff --git a/bridges/testing/tests/0003-required-headers-synced-while-active/rococo-to-westend.zndsl b/bridges/testing/tests/0003-required-headers-synced-while-active/rococo-to-westend.zndsl new file mode 100644 index 000000000000..897b79eeff23 --- /dev/null +++ b/bridges/testing/tests/0003-required-headers-synced-while-active/rococo-to-westend.zndsl @@ -0,0 +1,7 @@ +Description: While relayer is active, we only sync mandatory and required Rococo (and Rococo BH) headers to Westend BH. +Network: {{ENV_PATH}}/bridge_hub_westend_local_network.toml +Creds: config + +# ensure that relayer won't sync any extra headers while delivering messages and confirmations +bridge-hub-westend-collator1: js-script {{FRAMEWORK_PATH}}/js-helpers/only-required-headers-synced-when-active.js with "500,rococo-at-westend" within 600 seconds + diff --git a/bridges/testing/tests/0003-required-headers-synced-while-active/run.sh b/bridges/testing/tests/0003-required-headers-synced-while-active/run.sh new file mode 100755 index 000000000000..8fad38f22052 --- /dev/null +++ b/bridges/testing/tests/0003-required-headers-synced-while-active/run.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +set -e + +# TODO: This test doesn't work. It was added at a time when we couldn't run it because we didn't have the scafolding. +# It needs to be fixed. For the moment we keep it in the repo as it is since the idea has value. +# But we don't run it in the CI. + +source "${BASH_SOURCE%/*}/../../framework/utils/common.sh" +source "${BASH_SOURCE%/*}/../../framework/utils/zombienet.sh" + +export ENV_PATH=`realpath ${BASH_SOURCE%/*}/../../environments/rococo-westend` + +logs_dir=$TEST_DIR/logs + +$ENV_PATH/spawn.sh --init & +env_pid=$! + +ensure_process_file $env_pid $TEST_DIR/rococo.env 600 +rococo_dir=`cat $TEST_DIR/rococo.env` +echo + +ensure_process_file $env_pid $TEST_DIR/westend.env 300 +westend_dir=`cat $TEST_DIR/westend.env` +echo + +echo "Sending message from Rococo to Westend" +$ENV_PATH/helper.sh auto-log reserve-transfer-assets-from-asset-hub-rococo-local 5000000000000 +echo + +echo "Sending message from Westend to Rococo" +$ENV_PATH/helper.sh auto-log reserve-transfer-assets-from-asset-hub-westend-local 5000000000000 +echo + + +# Start the relayer with a 30s delay +# We want to be sure that the messages won't be relayed before starting the js script in `rococo-to-westend.zndsl` +start_relayer_log=$logs_dir/start_relayer.log +echo -e "The rococo-westend relayer will be started in 30s. Logs will be available at: $start_relayer_log\n" +(sleep 30 && $ENV_PATH/start_relayer.sh \ + $rococo_dir $westend_dir finality_relayer_pid parachains_relayer_pid messages_relayer_pid > $start_relayer_log)& + +run_zndsl ${BASH_SOURCE%/*}/rococo-to-westend.zndsl $westend_dir + diff --git a/cumulus/bin/pov-validator/Cargo.toml b/cumulus/bin/pov-validator/Cargo.toml new file mode 100644 index 000000000000..9be92960ad77 --- /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 000000000000..1c08f218f6b8 --- /dev/null +++ b/cumulus/bin/pov-validator/src/main.rs @@ -0,0 +1,154 @@ +// This file is part of Cumulus. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use clap::Parser; +use codec::{Decode, Encode}; +use polkadot_node_primitives::{BlockData, PoV, POV_BOMB_LIMIT, VALIDATION_CODE_BOMB_LIMIT}; +use polkadot_parachain_primitives::primitives::ValidationParams; +use polkadot_primitives::{BlockNumber as RBlockNumber, Hash as RHash, HeadData}; +use sc_executor::WasmExecutor; +use sp_core::traits::{CallContext, CodeExecutor, RuntimeCode, WrappedRuntimeCode}; +use std::{fs, path::PathBuf, time::Instant}; +use tracing::level_filters::LevelFilter; + +/// Tool for validating a `PoV` locally. +#[derive(Parser)] +struct Cli { + /// The path to the validation code that should be used to validate the `PoV`. + /// + /// The validation code can either be downloaded from the relay chain that the parachain is + /// connected to or by building the runtime manually to obtain the WASM binary. + #[arg(long)] + validation_code: PathBuf, + + /// The path to the `PoV` to validate. + /// + /// The `PoV`'s can be obtained by running `polkadot-parachains --collator --chain YOUR_CHAIN + /// --export-pov-to-path PATH_TO_EXPORT` and then choose one of the exported `PoV`'s. + #[arg(long)] + pov: PathBuf, +} + +fn main() -> anyhow::Result<()> { + let _ = tracing_subscriber::fmt() + .with_env_filter( + tracing_subscriber::EnvFilter::from_default_env() + .add_directive(LevelFilter::INFO.into()), + ) + .with_writer(std::io::stderr) + .try_init(); + + let cli = Cli::parse(); + + let validation_code = fs::read(&cli.validation_code).map_err(|error| { + tracing::error!(%error, path = %cli.validation_code.display(), "Failed to read validation code"); + anyhow::anyhow!("Failed to read validation code") + })?; + + let validation_code = + sp_maybe_compressed_blob::decompress(&validation_code, VALIDATION_CODE_BOMB_LIMIT) + .map_err(|error| { + tracing::error!(%error, "Failed to decompress validation code"); + anyhow::anyhow!("Failed to decompress validation code") + })?; + + let pov_file = fs::read(&cli.pov).map_err(|error| { + tracing::error!(%error, path = %cli.pov.display(), "Failed to read PoV"); + anyhow::anyhow!("Failed to read PoV") + })?; + + let executor = WasmExecutor::::builder() + .with_allow_missing_host_functions(true) + .build(); + + let runtime_code = RuntimeCode { + code_fetcher: &WrappedRuntimeCode(validation_code.into()), + heap_pages: None, + // The hash is used for caching, which we need here, but we only use one wasm file. So, the + // actual hash is not that important. + hash: vec![1, 2, 3], + }; + + // We are calling `Core_version` to get the wasm file compiled. We don't care about the result. + let _ = executor + .call( + &mut sp_io::TestExternalities::default().ext(), + &runtime_code, + "Core_version", + &[], + CallContext::Offchain, + ) + .0; + + let pov_file_ptr = &mut &pov_file[..]; + let pov = PoV::decode(pov_file_ptr).map_err(|error| { + tracing::error!(%error, "Failed to decode `PoV`"); + anyhow::anyhow!("Failed to decode `PoV`") + })?; + let head_data = HeadData::decode(pov_file_ptr).map_err(|error| { + tracing::error!(%error, "Failed to `HeadData`"); + anyhow::anyhow!("Failed to decode `HeadData`") + })?; + let relay_parent_storage_root = RHash::decode(pov_file_ptr).map_err(|error| { + tracing::error!(%error, "Failed to relay storage root"); + anyhow::anyhow!("Failed to decode relay storage root") + })?; + let relay_parent_number = RBlockNumber::decode(pov_file_ptr).map_err(|error| { + tracing::error!(%error, "Failed to relay block number"); + anyhow::anyhow!("Failed to decode relay block number") + })?; + + let pov = sp_maybe_compressed_blob::decompress(&pov.block_data.0, POV_BOMB_LIMIT).map_err( + |error| { + tracing::error!(%error, "Failed to decompress `PoV`"); + anyhow::anyhow!("Failed to decompress `PoV`") + }, + )?; + + let validation_params = ValidationParams { + relay_parent_number, + relay_parent_storage_root, + parent_head: head_data, + block_data: BlockData(pov.into()), + }; + + tracing::info!("Starting validation"); + + let start = Instant::now(); + + let res = executor + .call( + &mut sp_io::TestExternalities::default().ext(), + &runtime_code, + "validate_block", + &validation_params.encode(), + CallContext::Offchain, + ) + .0; + + let duration = start.elapsed(); + + match res { + Ok(_) => tracing::info!("Validation was successful"), + Err(error) => tracing::error!(%error, "Validation failed"), + } + + tracing::info!("Validation took {}ms", duration.as_millis()); + + Ok(()) +} diff --git a/cumulus/client/cli/src/lib.rs b/cumulus/client/cli/src/lib.rs index a7b2eb19de88..b08ad75c430d 100644 --- a/cumulus/client/cli/src/lib.rs +++ b/cumulus/client/cli/src/lib.rs @@ -21,13 +21,13 @@ use std::{ fs, io::{self, Write}, - net::SocketAddr, path::PathBuf, sync::Arc, }; use codec::Encode; use sc_chain_spec::ChainSpec; +use sc_cli::RpcEndpoint; use sc_client_api::HeaderBackend; use sc_service::{ config::{PrometheusConfig, RpcBatchRequestConfig, TelemetryEndpoints}, @@ -96,7 +96,7 @@ impl PurgeChainCmd { Some('y') | Some('Y') => {}, _ => { println!("Aborted"); - return Ok(()) + return Ok(()); }, } } @@ -423,7 +423,7 @@ impl sc_cli::CliConfiguration for NormalizedRunCmd { self.base.rpc_cors(is_dev) } - fn rpc_addr(&self, default_listen_port: u16) -> sc_cli::Result> { + fn rpc_addr(&self, default_listen_port: u16) -> sc_cli::Result>> { self.base.rpc_addr(default_listen_port) } @@ -432,19 +432,19 @@ impl sc_cli::CliConfiguration for NormalizedRunCmd { } fn rpc_max_request_size(&self) -> sc_cli::Result { - Ok(self.base.rpc_max_request_size) + self.base.rpc_max_request_size() } fn rpc_max_response_size(&self) -> sc_cli::Result { - Ok(self.base.rpc_max_response_size) + self.base.rpc_max_response_size() } fn rpc_max_subscriptions_per_connection(&self) -> sc_cli::Result { - Ok(self.base.rpc_max_subscriptions_per_connection) + self.base.rpc_max_subscriptions_per_connection() } fn rpc_buffer_capacity_per_connection(&self) -> sc_cli::Result { - Ok(self.base.rpc_message_buffer_capacity_per_connection) + Ok(self.base.rpc_params.rpc_message_buffer_capacity_per_connection) } fn rpc_batch_config(&self) -> sc_cli::Result { diff --git a/cumulus/client/collator/src/lib.rs b/cumulus/client/collator/src/lib.rs index 47da0f6d96f2..91ff913f263d 100644 --- a/cumulus/client/collator/src/lib.rs +++ b/cumulus/client/collator/src/lib.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/cumulus/client/consensus/aura/Cargo.toml b/cumulus/client/consensus/aura/Cargo.toml index 01e07cb395a9..0bb2de6bb9b8 100644 --- a/cumulus/client/consensus/aura/Cargo.toml +++ b/cumulus/client/consensus/aura/Cargo.toml @@ -53,4 +53,9 @@ cumulus-client-collator = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } polkadot-overseer = { workspace = true, default-features = true } + +[features] +# Allows collator to use full PoV size for block building +full-pov-size = [] diff --git a/cumulus/client/consensus/aura/src/collators/basic.rs b/cumulus/client/consensus/aura/src/collators/basic.rs index 4efd50a04ec6..d843483b79fa 100644 --- a/cumulus/client/consensus/aura/src/collators/basic.rs +++ b/cumulus/client/consensus/aura/src/collators/basic.rs @@ -138,6 +138,7 @@ where }; let mut last_processed_slot = 0; + let mut last_relay_chain_block = Default::default(); while let Some(request) = collation_requests.next().await { macro_rules! reject_with_error { @@ -215,11 +216,13 @@ where // // Most parachains currently run with 12 seconds slots and thus, they would try to // produce multiple blocks per slot which very likely would fail on chain. Thus, we have - // this "hack" to only produce on block per slot. + // this "hack" to only produce one block per slot per relay chain fork. // // With https://github.com/paritytech/polkadot-sdk/issues/3168 this implementation will be // obsolete and also the underlying issue will be fixed. - if last_processed_slot >= *claim.slot() { + if last_processed_slot >= *claim.slot() && + last_relay_chain_block < *relay_parent_header.number() + { continue } @@ -234,6 +237,16 @@ where .await ); + let allowed_pov_size = if cfg!(feature = "full-pov-size") { + validation_data.max_pov_size + } else { + // Set the block limit to 50% of the maximum PoV size. + // + // TODO: If we got benchmarking that includes the proof size, + // we should be able to use the maximum pov size. + validation_data.max_pov_size / 2 + } as usize; + let maybe_collation = try_request!( collator .collate( @@ -242,11 +255,7 @@ where None, (parachain_inherent_data, other_inherent_data), params.authoring_duration, - // Set the block limit to 50% of the maximum PoV size. - // - // TODO: If we got benchmarking that includes the proof size, - // we should be able to use the maximum pov size. - (validation_data.max_pov_size / 2) as usize, + allowed_pov_size, ) .await ); @@ -261,6 +270,7 @@ where } last_processed_slot = *claim.slot(); + last_relay_chain_block = *relay_parent_header.number(); } } } diff --git a/cumulus/client/consensus/aura/src/collators/lookahead.rs b/cumulus/client/consensus/aura/src/collators/lookahead.rs index 749b13112394..8ac43fbd116e 100644 --- a/cumulus/client/consensus/aura/src/collators/lookahead.rs +++ b/cumulus/client/consensus/aura/src/collators/lookahead.rs @@ -36,13 +36,18 @@ use cumulus_client_collator::service::ServiceInterface as CollatorServiceInterfa use cumulus_client_consensus_common::{self as consensus_common, ParachainBlockImportMarker}; use cumulus_client_consensus_proposer::ProposerInterface; use cumulus_primitives_aura::AuraUnincludedSegmentApi; -use cumulus_primitives_core::{CollectCollationInfo, PersistedValidationData}; +use cumulus_primitives_core::{ + ClaimQueueOffset, CollectCollationInfo, PersistedValidationData, DEFAULT_CLAIM_QUEUE_OFFSET, +}; 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 +59,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 +141,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, @@ -167,6 +262,7 @@ where relay_parent, params.para_id, &mut params.relay_client, + ClaimQueueOffset(DEFAULT_CLAIM_QUEUE_OFFSET), ) .await .get(0) @@ -319,6 +415,16 @@ where ) .await; + let allowed_pov_size = if cfg!(feature = "full-pov-size") { + validation_data.max_pov_size + } else { + // Set the block limit to 50% of the maximum PoV size. + // + // TODO: If we got benchmarking that includes the proof size, + // we should be able to use the maximum pov size. + validation_data.max_pov_size / 2 + } as usize; + match collator .collate( &parent_header, @@ -326,11 +432,7 @@ where None, (parachain_inherent_data, other_inherent_data), params.authoring_duration, - // Set the block limit to 50% of the maximum PoV size. - // - // TODO: If we got benchmarking that includes the proof size, - // we should be able to use the maximum pov size. - (validation_data.max_pov_size / 2) as usize, + allowed_pov_size, ) .await { @@ -339,6 +441,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/consensus/aura/src/collators/mod.rs b/cumulus/client/consensus/aura/src/collators/mod.rs index 7d430ecdc727..89070607fbab 100644 --- a/cumulus/client/consensus/aura/src/collators/mod.rs +++ b/cumulus/client/consensus/aura/src/collators/mod.rs @@ -26,11 +26,12 @@ use cumulus_client_consensus_common::{ self as consensus_common, load_abridged_host_configuration, ParentSearchParams, }; use cumulus_primitives_aura::{AuraUnincludedSegmentApi, Slot}; -use cumulus_primitives_core::{relay_chain::Hash as ParaHash, BlockT}; +use cumulus_primitives_core::{relay_chain::Hash as ParaHash, BlockT, ClaimQueueOffset}; use cumulus_relay_chain_interface::RelayChainInterface; +use polkadot_node_subsystem_util::runtime::ClaimQueueSnapshot; use polkadot_primitives::{ - AsyncBackingParams, CoreIndex, CoreState, Hash as RelayHash, Id as ParaId, - OccupiedCoreAssumption, ValidationCodeHash, + AsyncBackingParams, CoreIndex, Hash as RelayHash, Id as ParaId, OccupiedCoreAssumption, + ValidationCodeHash, }; use sc_consensus_aura::{standalone as aura_internal, AuraApi}; use sp_api::ProvideRuntimeApi; @@ -126,50 +127,33 @@ async fn async_backing_params( } } -// Return all the cores assigned to the para at the provided relay parent. +// Return all the cores assigned to the para at the provided relay parent, using the claim queue +// offset. +// Will return an empty vec if the provided offset is higher than the claim queue length (which +// corresponds to the scheduling_lookahead on the relay chain). async fn cores_scheduled_for_para( relay_parent: RelayHash, para_id: ParaId, relay_client: &impl RelayChainInterface, + claim_queue_offset: ClaimQueueOffset, ) -> Vec { - // Get `AvailabilityCores` from runtime - let cores = match relay_client.availability_cores(relay_parent).await { - Ok(cores) => cores, + // Get `ClaimQueue` from runtime + let claim_queue: ClaimQueueSnapshot = match relay_client.claim_queue(relay_parent).await { + Ok(claim_queue) => claim_queue.into(), Err(error) => { tracing::error!( target: crate::LOG_TARGET, ?error, ?relay_parent, - "Failed to query availability cores runtime API", + "Failed to query claim queue runtime API", ); return Vec::new() }, }; - let max_candidate_depth = async_backing_params(relay_parent, relay_client) - .await - .map(|c| c.max_candidate_depth) - .unwrap_or(0); - - cores - .iter() - .enumerate() - .filter_map(|(index, core)| { - let core_para_id = match core { - CoreState::Scheduled(scheduled_core) => Some(scheduled_core.para_id), - CoreState::Occupied(occupied_core) if max_candidate_depth > 0 => occupied_core - .next_up_on_available - .as_ref() - .map(|scheduled_core| scheduled_core.para_id), - CoreState::Free | CoreState::Occupied(_) => None, - }; - - if core_para_id == Some(para_id) { - Some(CoreIndex(index as u32)) - } else { - None - } - }) + claim_queue + .iter_claims_at_depth(claim_queue_offset.0 as usize) + .filter_map(|(core_index, core_para_id)| (core_para_id == para_id).then_some(core_index)) .collect() } diff --git a/cumulus/client/consensus/aura/src/collators/slot_based/block_builder_task.rs b/cumulus/client/consensus/aura/src/collators/slot_based/block_builder_task.rs index 1fbc0689da86..e75b52aeebd3 100644 --- a/cumulus/client/consensus/aura/src/collators/slot_based/block_builder_task.rs +++ b/cumulus/client/consensus/aura/src/collators/slot_based/block_builder_task.rs @@ -20,10 +20,13 @@ use cumulus_client_collator::service::ServiceInterface as CollatorServiceInterfa use cumulus_client_consensus_common::{self as consensus_common, ParachainBlockImportMarker}; use cumulus_client_consensus_proposer::ProposerInterface; use cumulus_primitives_aura::AuraUnincludedSegmentApi; -use cumulus_primitives_core::{CollectCollationInfo, PersistedValidationData}; +use cumulus_primitives_core::{ + GetCoreSelectorApi, PersistedValidationData, DEFAULT_CLAIM_QUEUE_OFFSET, +}; use cumulus_relay_chain_interface::RelayChainInterface; use polkadot_primitives::{ + vstaging::{ClaimQueueOffset, CoreSelector}, BlockId, CoreIndex, Hash as RelayHash, Header as RelayHeader, Id as ParaId, OccupiedCoreAssumption, }; @@ -31,16 +34,16 @@ use polkadot_primitives::{ use futures::prelude::*; use sc_client_api::{backend::AuxStore, BlockBackend, BlockOf, UsageProvider}; use sc_consensus::BlockImport; -use sp_api::ProvideRuntimeApi; +use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_application_crypto::AppPublic; use sp_blockchain::HeaderBackend; -use sp_consensus_aura::{AuraApi, Slot, SlotDuration}; -use sp_core::crypto::Pair; +use sp_consensus_aura::{AuraApi, Slot}; +use sp_core::{crypto::Pair, U256}; use sp_inherents::CreateInherentDataProviders; use sp_keystore::KeystorePtr; -use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Member}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, Member, One}; use sp_timestamp::Timestamp; -use std::{sync::Arc, time::Duration}; +use std::{collections::BTreeSet, sync::Arc, time::Duration}; use super::CollatorMessage; use crate::{ @@ -87,8 +90,6 @@ pub struct BuilderTaskParams< pub authoring_duration: Duration, /// Channel to send built blocks to the collation task. pub collator_sender: sc_utils::mpsc::TracingUnboundedSender>, - /// Slot duration of the relay chain - pub relay_chain_slot_duration: Duration, /// Drift every slot by this duration. /// This is a time quantity that is subtracted from the actual timestamp when computing /// the time left to enter a new slot. In practice, this *left-shifts* the clock time with the @@ -102,7 +103,6 @@ pub struct BuilderTaskParams< struct SlotInfo { pub timestamp: Timestamp, pub slot: Slot, - pub slot_duration: SlotDuration, } #[derive(Debug)] @@ -153,11 +153,7 @@ where let time_until_next_slot = time_until_next_slot(slot_duration.as_duration(), self.drift); tokio::time::sleep(time_until_next_slot).await; let timestamp = sp_timestamp::Timestamp::current(); - Ok(SlotInfo { - slot: Slot::from_timestamp(timestamp, slot_duration), - timestamp, - slot_duration, - }) + Ok(SlotInfo { slot: Slot::from_timestamp(timestamp, slot_duration), timestamp }) } } @@ -177,7 +173,7 @@ where + Sync + 'static, Client::Api: - AuraApi + CollectCollationInfo + AuraUnincludedSegmentApi, + AuraApi + GetCoreSelectorApi + AuraUnincludedSegmentApi, Backend: sc_client_api::Backend + 'static, RelayClient: RelayChainInterface + Clone + 'static, CIDP: CreateInherentDataProviders + 'static, @@ -205,7 +201,6 @@ where code_hash_provider, authoring_duration, para_backend, - relay_chain_slot_duration, slot_drift, } = params; @@ -233,18 +228,42 @@ where return; }; - let Some(expected_cores) = - expected_core_count(relay_chain_slot_duration, para_slot.slot_duration) + let Ok(relay_parent) = relay_client.best_block_hash().await else { + tracing::warn!(target: crate::LOG_TARGET, "Unable to fetch latest relay chain block hash."); + continue + }; + + let Some((included_block, parent)) = + crate::collators::find_parent(relay_parent, para_id, &*para_backend, &relay_client) + .await else { - return + continue }; + let parent_hash = parent.hash; + + // Retrieve the core selector. + let (core_selector, claim_queue_offset) = + match core_selector(&*para_client, &parent).await { + Ok(core_selector) => core_selector, + Err(err) => { + tracing::trace!( + target: crate::LOG_TARGET, + "Unable to retrieve the core selector from the runtime API: {}", + err + ); + continue + }, + }; + let Ok(RelayChainData { relay_parent_header, max_pov_size, - relay_parent_hash: relay_parent, scheduled_cores, - }) = relay_chain_fetcher.get_relay_chain_data().await + claimed_cores, + }) = relay_chain_fetcher + .get_mut_relay_chain_data(relay_parent, claim_queue_offset) + .await else { continue; }; @@ -252,23 +271,32 @@ where if scheduled_cores.is_empty() { tracing::debug!(target: LOG_TARGET, "Parachain not scheduled, skipping slot."); continue; + } else { + tracing::debug!( + target: LOG_TARGET, + ?relay_parent, + "Parachain is scheduled on cores: {:?}", + scheduled_cores + ); } - let core_index_in_scheduled: u64 = *para_slot.slot % expected_cores; - let Some(core_index) = scheduled_cores.get(core_index_in_scheduled as usize) else { - tracing::debug!(target: LOG_TARGET, core_index_in_scheduled, core_len = scheduled_cores.len(), "Para is scheduled, but not enough cores available."); + let core_selector = core_selector.0 as usize % scheduled_cores.len(); + let Some(core_index) = scheduled_cores.get(core_selector) else { + // This cannot really happen, as we modulo the core selector with the + // scheduled_cores length and we check that the scheduled_cores is not empty. continue; }; - let Some((included_block, parent)) = - crate::collators::find_parent(relay_parent, para_id, &*para_backend, &relay_client) - .await - else { + if !claimed_cores.insert(*core_index) { + tracing::debug!( + target: LOG_TARGET, + "Core {:?} was already claimed at this relay chain slot", + core_index + ); continue - }; + } let parent_header = parent.header; - let parent_hash = parent.hash; // We mainly call this to inform users at genesis if there is a mismatch with the // on-chain data. @@ -315,7 +343,7 @@ where parent_head: parent_header.encode().into(), relay_parent_number: *relay_parent_header.number(), relay_parent_storage_root: *relay_parent_header.state_root(), - max_pov_size, + max_pov_size: *max_pov_size, }; let (parachain_inherent_data, other_inherent_data) = match collator @@ -350,6 +378,16 @@ where ) .await; + let allowed_pov_size = if cfg!(feature = "full-pov-size") { + validation_data.max_pov_size + } else { + // Set the block limit to 50% of the maximum PoV size. + // + // TODO: If we got benchmarking that includes the proof size, + // we should be able to use the maximum pov size. + validation_data.max_pov_size / 2 + } as usize; + let Ok(Some(candidate)) = collator .build_block_and_import( &parent_header, @@ -357,11 +395,7 @@ where None, (parachain_inherent_data, other_inherent_data), authoring_duration, - // Set the block limit to 50% of the maximum PoV size. - // - // TODO: If we got benchmarking that includes the proof size, - // we should be able to use the maximum pov size. - (validation_data.max_pov_size / 2) as usize, + allowed_pov_size, ) .await else { @@ -388,34 +422,17 @@ where } } -/// Calculate the expected core count based on the slot duration of the relay and parachain. -/// -/// If `slot_duration` is smaller than `relay_chain_slot_duration` that means that we produce more -/// than one parachain block per relay chain block. In order to get these backed, we need multiple -/// cores. This method calculates how many cores we should expect to have scheduled under the -/// assumption that we have a fixed number of cores assigned to our parachain. -fn expected_core_count( - relay_chain_slot_duration: Duration, - slot_duration: SlotDuration, -) -> Option { - let slot_duration_millis = slot_duration.as_millis(); - u64::try_from(relay_chain_slot_duration.as_millis()) - .map_err(|e| tracing::error!("Unable to calculate expected parachain core count: {e}")) - .map(|relay_slot_duration| (relay_slot_duration / slot_duration_millis).max(1)) - .ok() -} - /// Contains relay chain data necessary for parachain block building. #[derive(Clone)] struct RelayChainData { /// Current relay chain parent header. pub relay_parent_header: RelayHeader, - /// The cores this para is scheduled on in the context of the relay parent. + /// The cores on which the para is scheduled at the configured claim queue offset. pub scheduled_cores: Vec, /// Maximum configured PoV size on the relay chain. pub max_pov_size: u32, - /// Current relay chain parent header. - pub relay_parent_hash: RelayHash, + /// The claimed cores at a relay parent. + pub claimed_cores: BTreeSet, } /// Simple helper to fetch relay chain data and cache it based on the current relay chain best block @@ -437,30 +454,39 @@ where /// Fetch required [`RelayChainData`] from the relay chain. /// If this data has been fetched in the past for the incoming hash, it will reuse /// cached data. - pub async fn get_relay_chain_data(&mut self) -> Result { - let Ok(relay_parent) = self.relay_client.best_block_hash().await else { - tracing::warn!(target: crate::LOG_TARGET, "Unable to fetch latest relay chain block hash."); - return Err(()) - }; - + pub async fn get_mut_relay_chain_data( + &mut self, + relay_parent: RelayHash, + claim_queue_offset: ClaimQueueOffset, + ) -> Result<&mut RelayChainData, ()> { match &self.last_data { - Some((last_seen_hash, data)) if *last_seen_hash == relay_parent => { + Some((last_seen_hash, _)) if *last_seen_hash == relay_parent => { tracing::trace!(target: crate::LOG_TARGET, %relay_parent, "Using cached data for relay parent."); - Ok(data.clone()) + Ok(&mut self.last_data.as_mut().expect("last_data is Some").1) }, _ => { tracing::trace!(target: crate::LOG_TARGET, %relay_parent, "Relay chain best block changed, fetching new data from relay chain."); - let data = self.update_for_relay_parent(relay_parent).await?; - self.last_data = Some((relay_parent, data.clone())); - Ok(data) + let data = self.update_for_relay_parent(relay_parent, claim_queue_offset).await?; + self.last_data = Some((relay_parent, data)); + Ok(&mut self.last_data.as_mut().expect("last_data was just set above").1) }, } } /// Fetch fresh data from the relay chain for the given relay parent hash. - async fn update_for_relay_parent(&self, relay_parent: RelayHash) -> Result { - let scheduled_cores = - cores_scheduled_for_para(relay_parent, self.para_id, &self.relay_client).await; + async fn update_for_relay_parent( + &self, + relay_parent: RelayHash, + claim_queue_offset: ClaimQueueOffset, + ) -> Result { + let scheduled_cores = cores_scheduled_for_para( + relay_parent, + self.para_id, + &self.relay_client, + claim_queue_offset, + ) + .await; + let Ok(Some(relay_parent_header)) = self.relay_client.header(BlockId::Hash(relay_parent)).await else { @@ -482,10 +508,32 @@ where }; Ok(RelayChainData { - relay_parent_hash: relay_parent, relay_parent_header, scheduled_cores, max_pov_size, + claimed_cores: BTreeSet::new(), }) } } + +async fn core_selector( + para_client: &Client, + parent: &consensus_common::PotentialParent, +) -> Result<(CoreSelector, ClaimQueueOffset), sp_api::ApiError> +where + Client: ProvideRuntimeApi + Send + Sync, + Client::Api: GetCoreSelectorApi, +{ + let block_hash = parent.hash; + let runtime_api = para_client.runtime_api(); + + if runtime_api.has_api::>(block_hash)? { + Ok(runtime_api.core_selector(block_hash)?) + } else { + let next_block_number: U256 = (*parent.header.number() + One::one()).into(); + + // If the runtime API does not support the core selector API, fallback to some default + // values. + Ok((CoreSelector(next_block_number.byte(0)), ClaimQueueOffset(DEFAULT_CLAIM_QUEUE_OFFSET))) + } +} diff --git a/cumulus/client/consensus/aura/src/collators/slot_based/mod.rs b/cumulus/client/consensus/aura/src/collators/slot_based/mod.rs index 0fe49d58d25b..7453d3c89d08 100644 --- a/cumulus/client/consensus/aura/src/collators/slot_based/mod.rs +++ b/cumulus/client/consensus/aura/src/collators/slot_based/mod.rs @@ -34,7 +34,7 @@ use cumulus_client_collator::service::ServiceInterface as CollatorServiceInterfa use cumulus_client_consensus_common::{self as consensus_common, ParachainBlockImportMarker}; use cumulus_client_consensus_proposer::ProposerInterface; use cumulus_primitives_aura::AuraUnincludedSegmentApi; -use cumulus_primitives_core::CollectCollationInfo; +use cumulus_primitives_core::GetCoreSelectorApi; use cumulus_relay_chain_interface::RelayChainInterface; use polkadot_primitives::{ CollatorPair, CoreIndex, Hash as RelayHash, Id as ParaId, ValidationCodeHash, @@ -82,8 +82,6 @@ pub struct Params { pub collator_key: CollatorPair, /// The para's ID. pub para_id: ParaId, - /// The length of slots in the relay chain. - pub relay_chain_slot_duration: Duration, /// The underlying block proposer this should call into. pub proposer: Proposer, /// The generic collator service used to plug into this consensus engine. @@ -113,7 +111,7 @@ where + Sync + 'static, Client::Api: - AuraApi + CollectCollationInfo + AuraUnincludedSegmentApi, + AuraApi + GetCoreSelectorApi + AuraUnincludedSegmentApi, Backend: sc_client_api::Backend + 'static, RClient: RelayChainInterface + Clone + 'static, CIDP: CreateInherentDataProviders + 'static, @@ -151,7 +149,6 @@ where collator_service: params.collator_service, authoring_duration: params.authoring_duration, collator_sender: tx, - relay_chain_slot_duration: params.relay_chain_slot_duration, slot_drift: params.slot_drift, }; diff --git a/cumulus/client/consensus/common/src/lib.rs b/cumulus/client/consensus/common/src/lib.rs index e12750dcc553..6766c2409c38 100644 --- a/cumulus/client/consensus/common/src/lib.rs +++ b/cumulus/client/consensus/common/src/lib.rs @@ -185,7 +185,7 @@ where } async fn import_block( - &mut self, + &self, mut params: sc_consensus::BlockImportParams, ) -> Result { // Blocks are stored within the backend by using POST hash. diff --git a/cumulus/client/consensus/common/src/parachain_consensus.rs b/cumulus/client/consensus/common/src/parachain_consensus.rs index 944917673b11..861354ed63c3 100644 --- a/cumulus/client/consensus/common/src/parachain_consensus.rs +++ b/cumulus/client/consensus/common/src/parachain_consensus.rs @@ -433,11 +433,8 @@ async fn handle_new_best_parachain_head( } } -async fn import_block_as_new_best( - hash: Block::Hash, - header: Block::Header, - mut parachain: &P, -) where +async fn import_block_as_new_best(hash: Block::Hash, header: Block::Header, parachain: &P) +where Block: BlockT, P: UsageProvider + Send + Sync + BlockBackend, for<'a> &'a P: BlockImport, diff --git a/cumulus/client/consensus/common/src/tests.rs b/cumulus/client/consensus/common/src/tests.rs index 284fa39ed1e7..94e2304011be 100644 --- a/cumulus/client/consensus/common/src/tests.rs +++ b/cumulus/client/consensus/common/src/tests.rs @@ -24,7 +24,7 @@ use cumulus_primitives_core::{ CumulusDigestItem, InboundDownwardMessage, InboundHrmpMessage, }; use cumulus_relay_chain_interface::{ - CommittedCandidateReceipt, OccupiedCoreAssumption, OverseerHandle, PHeader, ParaId, + CommittedCandidateReceipt, CoreIndex, OccupiedCoreAssumption, OverseerHandle, PHeader, ParaId, RelayChainInterface, RelayChainResult, SessionIndex, StorageValue, ValidatorId, }; use cumulus_test_client::{ @@ -41,7 +41,7 @@ use sp_blockchain::Backend as BlockchainBackend; use sp_consensus::{BlockOrigin, BlockStatus}; use sp_version::RuntimeVersion; use std::{ - collections::{BTreeMap, HashMap}, + collections::{BTreeMap, HashMap, VecDeque}, pin::Pin, sync::{Arc, Mutex}, time::Duration, @@ -268,6 +268,22 @@ impl RelayChainInterface for Relaychain { async fn version(&self, _: PHash) -> RelayChainResult { unimplemented!("Not needed for test") } + + async fn claim_queue( + &self, + _: PHash, + ) -> RelayChainResult>> { + unimplemented!("Not needed for test"); + } + + async fn call_runtime_api( + &self, + _method_name: &'static str, + _hash: PHash, + _payload: &[u8], + ) -> RelayChainResult> { + unimplemented!("Not needed for test") + } } fn sproof_with_best_parent(client: &Client) -> RelayStateSproofBuilder { @@ -321,7 +337,7 @@ fn build_block( } async fn import_block>( - importer: &mut I, + importer: &I, block: Block, origin: BlockOrigin, import_as_best: bool, @@ -568,7 +584,7 @@ fn follow_finalized_does_not_stop_on_unknown_block() { fn follow_new_best_sets_best_after_it_is_imported() { sp_tracing::try_init_simple(); - let mut client = Arc::new(TestClientBuilder::default().build()); + let client = Arc::new(TestClientBuilder::default().build()); let block = build_and_import_block(client.clone(), false); diff --git a/cumulus/client/consensus/proposer/Cargo.toml b/cumulus/client/consensus/proposer/Cargo.toml index ce91d48bf589..bb760ae03f4d 100644 --- a/cumulus/client/consensus/proposer/Cargo.toml +++ b/cumulus/client/consensus/proposer/Cargo.toml @@ -10,7 +10,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" workspace = true [dependencies] -anyhow = { workspace = true } +anyhow = { workspace = true, default-features = true } async-trait = { workspace = true } thiserror = { workspace = true } diff --git a/cumulus/client/network/src/lib.rs b/cumulus/client/network/src/lib.rs index dab15bba590a..01ad15bed4da 100644 --- a/cumulus/client/network/src/lib.rs +++ b/cumulus/client/network/src/lib.rs @@ -1,18 +1,18 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// This file is part of Cumulus. -// Polkadot is free software: you can redistribute it and/or modify +// 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. -// Polkadot is distributed in the hope that it will be useful, +// 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 Polkadot. If not, see . +// along with Cumulus. If not, see . //! Parachain specific networking //! diff --git a/cumulus/client/network/src/tests.rs b/cumulus/client/network/src/tests.rs index 18d121c41d16..4b3473645210 100644 --- a/cumulus/client/network/src/tests.rs +++ b/cumulus/client/network/src/tests.rs @@ -1,22 +1,22 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// This file is part of Cumulus. -// Polkadot is free software: you can redistribute it and/or modify +// 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. -// Polkadot is distributed in the hope that it will be useful, +// 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 Polkadot. If not, see . +// along with Cumulus. If not, see . use super::*; use async_trait::async_trait; -use cumulus_primitives_core::relay_chain::BlockId; +use cumulus_primitives_core::relay_chain::{BlockId, CoreIndex}; use cumulus_relay_chain_inprocess_interface::{check_block_in_chain, BlockCheckStatus}; use cumulus_relay_chain_interface::{ OverseerHandle, PHeader, ParaId, RelayChainError, RelayChainResult, @@ -45,7 +45,11 @@ use sp_keystore::{testing::MemoryKeystore, Keystore, KeystorePtr}; use sp_runtime::RuntimeAppPublic; use sp_state_machine::StorageValue; use sp_version::RuntimeVersion; -use std::{borrow::Cow, collections::BTreeMap, time::Duration}; +use std::{ + borrow::Cow, + collections::{BTreeMap, VecDeque}, + time::Duration, +}; fn check_error(error: crate::BoxedError, check_error: impl Fn(&BlockAnnounceError) -> bool) { let error = *error @@ -323,9 +327,25 @@ impl RelayChainInterface for DummyRelayChainInterface { impl_version: 0, apis: Cow::Owned(apis), transaction_version: 5, - state_version: 1, + system_version: 1, }) } + + async fn claim_queue( + &self, + _: PHash, + ) -> RelayChainResult>> { + unimplemented!("Not needed for test"); + } + + async fn call_runtime_api( + &self, + _method_name: &'static str, + _hash: PHash, + _payload: &[u8], + ) -> RelayChainResult> { + unimplemented!("Not needed for test") + } } fn make_validator_and_api() -> ( @@ -612,7 +632,7 @@ fn relay_parent_not_imported_when_block_announce_is_processed() { block_on(async move { let (mut validator, api) = make_validator_and_api(); - let mut client = api.relay_client.clone(); + let client = api.relay_client.clone(); let block = client.init_polkadot_block_builder().build().expect("Build new block").block; let (signal, header) = make_gossip_message_and_header(api, block.hash(), 0).await; diff --git a/cumulus/client/parachain-inherent/src/lib.rs b/cumulus/client/parachain-inherent/src/lib.rs index 051eb6764c8c..0bb436a876b4 100644 --- a/cumulus/client/parachain-inherent/src/lib.rs +++ b/cumulus/client/parachain-inherent/src/lib.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/cumulus/client/parachain-inherent/src/mock.rs b/cumulus/client/parachain-inherent/src/mock.rs index dfe4a66c3dc1..a3f881e6ef9d 100644 --- a/cumulus/client/parachain-inherent/src/mock.rs +++ b/cumulus/client/parachain-inherent/src/mock.rs @@ -6,7 +6,7 @@ // 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, +// 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. diff --git a/cumulus/client/pov-recovery/Cargo.toml b/cumulus/client/pov-recovery/Cargo.toml index a95b24bc2933..3127dd26fcaa 100644 --- a/cumulus/client/pov-recovery/Cargo.toml +++ b/cumulus/client/pov-recovery/Cargo.toml @@ -2,7 +2,7 @@ name = "cumulus-client-pov-recovery" version = "0.7.0" authors.workspace = true -description = "Cumulus-specific networking protocol" +description = "Parachain PoV recovery" edition.workspace = true license = "GPL-3.0-or-later WITH Classpath-exception-2.0" diff --git a/cumulus/client/pov-recovery/src/active_candidate_recovery.rs b/cumulus/client/pov-recovery/src/active_candidate_recovery.rs index 50de98909ea4..9badc69fe816 100644 --- a/cumulus/client/pov-recovery/src/active_candidate_recovery.rs +++ b/cumulus/client/pov-recovery/src/active_candidate_recovery.rs @@ -1,18 +1,18 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// This file is part of Cumulus. -// Polkadot is free software: you can redistribute it and/or modify +// 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. -// Polkadot is distributed in the hope that it will be useful, +// 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 Polkadot. If not, see . +// along with Cumulus. If not, see . use sp_runtime::traits::Block as BlockT; diff --git a/cumulus/client/pov-recovery/src/lib.rs b/cumulus/client/pov-recovery/src/lib.rs index 6ace18155e87..043cba12d193 100644 --- a/cumulus/client/pov-recovery/src/lib.rs +++ b/cumulus/client/pov-recovery/src/lib.rs @@ -6,7 +6,7 @@ // 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, +// 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. diff --git a/cumulus/client/pov-recovery/src/tests.rs b/cumulus/client/pov-recovery/src/tests.rs index 6f274ed18b6b..94dec32485cc 100644 --- a/cumulus/client/pov-recovery/src/tests.rs +++ b/cumulus/client/pov-recovery/src/tests.rs @@ -1,24 +1,24 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// This file is part of Cumulus. -// Polkadot is free software: you can redistribute it and/or modify +// 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. -// Polkadot is distributed in the hope that it will be useful, +// 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 Polkadot. If not, see . +// along with Cumulus. If not, see . use super::*; use assert_matches::assert_matches; use codec::{Decode, Encode}; use cumulus_primitives_core::relay_chain::{ - BlockId, CandidateCommitments, CandidateDescriptor, CoreState, + BlockId, CandidateCommitments, CandidateDescriptor, CoreIndex, CoreState, }; use cumulus_relay_chain_interface::{ InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, PHash, PHeader, @@ -43,7 +43,7 @@ use sp_runtime::{generic::SignedBlock, Justifications}; use sp_version::RuntimeVersion; use std::{ borrow::Cow, - collections::BTreeMap, + collections::{BTreeMap, VecDeque}, ops::Range, sync::{Arc, Mutex}, }; @@ -329,7 +329,7 @@ impl RelayChainInterface for Relaychain { impl_version: 0, apis: Cow::Owned(apis), transaction_version: 5, - state_version: 1, + system_version: 1, }) } @@ -487,6 +487,22 @@ impl RelayChainInterface for Relaychain { ) -> RelayChainResult>>> { unimplemented!("Not needed for test"); } + + async fn claim_queue( + &self, + _: PHash, + ) -> RelayChainResult>> { + unimplemented!("Not needed for test"); + } + + async fn call_runtime_api( + &self, + _method_name: &'static str, + _hash: PHash, + _payload: &[u8], + ) -> RelayChainResult> { + unimplemented!("Not needed for test") + } } fn make_candidate_chain(candidate_number_range: Range) -> Vec { diff --git a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs index 38ba84748c1e..3a204b0f383a 100644 --- a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs +++ b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs @@ -14,14 +14,19 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use std::{collections::btree_map::BTreeMap, pin::Pin, sync::Arc, time::Duration}; +use std::{ + collections::{BTreeMap, VecDeque}, + pin::Pin, + sync::Arc, + time::Duration, +}; use async_trait::async_trait; use cumulus_primitives_core::{ relay_chain::{ runtime_api::ParachainHost, Block as PBlock, BlockId, BlockNumber, - CommittedCandidateReceipt, CoreState, Hash as PHash, Header as PHeader, InboundHrmpMessage, - OccupiedCoreAssumption, SessionIndex, ValidationCodeHash, ValidatorId, + CommittedCandidateReceipt, CoreIndex, CoreState, Hash as PHash, Header as PHeader, + InboundHrmpMessage, OccupiedCoreAssumption, SessionIndex, ValidationCodeHash, ValidatorId, }, InboundDownwardMessage, ParaId, PersistedValidationData, }; @@ -36,7 +41,7 @@ use sc_client_api::{ StorageProof, }; use sc_telemetry::TelemetryWorkerHandle; -use sp_api::ProvideRuntimeApi; +use sp_api::{CallApiAt, CallApiAtParams, CallContext, ProvideRuntimeApi}; use sp_consensus::SyncOracle; use sp_core::Pair; use sp_state_machine::{Backend as StateBackend, StorageValue}; @@ -137,7 +142,11 @@ impl RelayChainInterface for RelayChainInProcessInterface { hash: PHash, para_id: ParaId, ) -> RelayChainResult> { - Ok(self.full_client.runtime_api().candidate_pending_availability(hash, para_id)?) + Ok(self + .full_client + .runtime_api() + .candidate_pending_availability(hash, para_id)? + .map(|receipt| receipt.into())) } async fn session_index_for_child(&self, hash: PHash) -> RelayChainResult { @@ -176,6 +185,23 @@ impl RelayChainInterface for RelayChainInProcessInterface { Ok(self.backend.blockchain().info().finalized_hash) } + async fn call_runtime_api( + &self, + method_name: &'static str, + hash: PHash, + payload: &[u8], + ) -> RelayChainResult> { + Ok(self.full_client.call_api_at(CallApiAtParams { + at: hash, + function: method_name, + arguments: payload.to_vec(), + overlayed_changes: &Default::default(), + call_context: CallContext::Offchain, + recorder: &None, + extensions: &Default::default(), + })?) + } + async fn is_major_syncing(&self) -> RelayChainResult { Ok(self.sync_oracle.is_major_syncing()) } @@ -260,7 +286,13 @@ impl RelayChainInterface for RelayChainInProcessInterface { &self, relay_parent: PHash, ) -> RelayChainResult>> { - Ok(self.full_client.runtime_api().availability_cores(relay_parent)?) + Ok(self + .full_client + .runtime_api() + .availability_cores(relay_parent)? + .into_iter() + .map(|core_state| core_state.into()) + .collect::>()) } async fn candidates_pending_availability( @@ -268,7 +300,20 @@ impl RelayChainInterface for RelayChainInProcessInterface { hash: PHash, para_id: ParaId, ) -> RelayChainResult> { - Ok(self.full_client.runtime_api().candidates_pending_availability(hash, para_id)?) + Ok(self + .full_client + .runtime_api() + .candidates_pending_availability(hash, para_id)? + .into_iter() + .map(|receipt| receipt.into()) + .collect::>()) + } + + async fn claim_queue( + &self, + hash: PHash, + ) -> RelayChainResult>> { + Ok(self.full_client.runtime_api().claim_queue(hash)?) } } @@ -318,7 +363,6 @@ fn build_polkadot_full_node( // Disable BEEFY. It should not be required by the internal relay chain node. enable_beefy: false, force_authoring_backoff: false, - jaeger_agent: None, telemetry_worker_handle, // Cumulus doesn't spawn PVF workers, so we can disable version checks. @@ -334,6 +378,7 @@ fn build_polkadot_full_node( execute_workers_max_num: None, prepare_workers_hard_max_num: None, prepare_workers_soft_max_num: None, + enable_approval_voting_parallel: false, }, )?; @@ -423,7 +468,7 @@ mod tests { #[test] fn returns_directly_for_available_block() { - let (mut client, block, relay_chain_interface) = build_client_backend_and_block(); + let (client, block, relay_chain_interface) = build_client_backend_and_block(); let hash = block.hash(); block_on(client.import(BlockOrigin::Own, block)).expect("Imports the block"); @@ -439,7 +484,7 @@ mod tests { #[test] fn resolve_after_block_import_notification_was_received() { - let (mut client, block, relay_chain_interface) = build_client_backend_and_block(); + let (client, block, relay_chain_interface) = build_client_backend_and_block(); let hash = block.hash(); block_on(async move { @@ -468,7 +513,7 @@ mod tests { #[test] fn do_not_resolve_after_different_block_import_notification_was_received() { - let (mut client, block, relay_chain_interface) = build_client_backend_and_block(); + let (client, block, relay_chain_interface) = build_client_backend_and_block(); let hash = block.hash(); let ext = construct_transfer_extrinsic( diff --git a/cumulus/client/relay-chain-interface/src/lib.rs b/cumulus/client/relay-chain-interface/src/lib.rs index d02035e84e92..2eed71c4d7d6 100644 --- a/cumulus/client/relay-chain-interface/src/lib.rs +++ b/cumulus/client/relay-chain-interface/src/lib.rs @@ -14,7 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use std::{collections::BTreeMap, pin::Pin, sync::Arc}; +use std::{ + collections::{BTreeMap, VecDeque}, + pin::Pin, + sync::Arc, +}; use futures::Stream; use polkadot_overseer::prometheus::PrometheusError; @@ -22,15 +26,16 @@ use sc_client_api::StorageProof; use sp_version::RuntimeVersion; use async_trait::async_trait; -use codec::Error as CodecError; +use codec::{Decode, Encode, Error as CodecError}; use jsonrpsee_core::ClientError as JsonRpcError; use sp_api::ApiError; -use cumulus_primitives_core::relay_chain::BlockId; +use cumulus_primitives_core::relay_chain::{BlockId, Hash as RelayHash}; pub use cumulus_primitives_core::{ relay_chain::{ - BlockNumber, CommittedCandidateReceipt, CoreState, Hash as PHash, Header as PHeader, - InboundHrmpMessage, OccupiedCoreAssumption, SessionIndex, ValidationCodeHash, ValidatorId, + BlockNumber, CommittedCandidateReceipt, CoreIndex, CoreState, Hash as PHash, + Header as PHeader, InboundHrmpMessage, OccupiedCoreAssumption, SessionIndex, + ValidationCodeHash, ValidatorId, }, InboundDownwardMessage, ParaId, PersistedValidationData, }; @@ -117,6 +122,14 @@ pub trait RelayChainInterface: Send + Sync { /// Get the hash of the finalized block. async fn finalized_block_hash(&self) -> RelayChainResult; + /// Call an arbitrary runtime api. The input and output are SCALE-encoded. + async fn call_runtime_api( + &self, + method_name: &'static str, + hash: RelayHash, + payload: &[u8], + ) -> RelayChainResult>; + /// Returns the whole contents of the downward message queue for the parachain we are collating /// for. /// @@ -225,6 +238,12 @@ pub trait RelayChainInterface: Send + Sync { &self, relay_parent: PHash, ) -> RelayChainResult>>; + + /// Fetch the claim queue. + async fn claim_queue( + &self, + relay_parent: PHash, + ) -> RelayChainResult>>; } #[async_trait] @@ -296,6 +315,15 @@ where (**self).finalized_block_hash().await } + async fn call_runtime_api( + &self, + method_name: &'static str, + hash: RelayHash, + payload: &[u8], + ) -> RelayChainResult> { + (**self).call_runtime_api(method_name, hash, payload).await + } + async fn is_major_syncing(&self) -> RelayChainResult { (**self).is_major_syncing().await } @@ -363,4 +391,27 @@ where async fn version(&self, relay_parent: PHash) -> RelayChainResult { (**self).version(relay_parent).await } + + async fn claim_queue( + &self, + relay_parent: PHash, + ) -> RelayChainResult>> { + (**self).claim_queue(relay_parent).await + } +} + +/// Helper function to call an arbitrary runtime API using a `RelayChainInterface` client. +/// Unlike the trait method, this function can be generic, so it handles the encoding of input and +/// output params. +pub async fn call_runtime_api( + client: &(impl RelayChainInterface + ?Sized), + method_name: &'static str, + hash: RelayHash, + payload: impl Encode, +) -> RelayChainResult +where + R: Decode, +{ + let res = client.call_runtime_api(method_name, hash, &payload.encode()).await?; + Decode::decode(&mut &*res).map_err(Into::into) } diff --git a/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs b/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs index 06f19941165a..7d6b5bfe3ec7 100644 --- a/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs +++ b/cumulus/client/relay-chain-minimal-node/src/blockchain_rpc_client.rs @@ -19,6 +19,7 @@ use std::{ pin::Pin, }; +use cumulus_primitives_core::{InboundDownwardMessage, ParaId, PersistedValidationData}; use cumulus_relay_chain_interface::{RelayChainError, RelayChainResult}; use cumulus_relay_chain_rpc_interface::RelayChainRpcClient; use futures::{Stream, StreamExt}; @@ -132,7 +133,7 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { ) -> Result< ( Vec>, - polkadot_primitives::GroupRotationInfo, + polkadot_primitives::GroupRotationInfo, ), sp_api::ApiError, > { @@ -142,27 +143,16 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { async fn availability_cores( &self, at: Hash, - ) -> Result< - Vec>, - sp_api::ApiError, - > { + ) -> Result>, sp_api::ApiError> { Ok(self.rpc_client.parachain_host_availability_cores(at).await?) } async fn persisted_validation_data( &self, at: Hash, - para_id: cumulus_primitives_core::ParaId, + para_id: ParaId, assumption: polkadot_primitives::OccupiedCoreAssumption, - ) -> Result< - Option< - cumulus_primitives_core::PersistedValidationData< - Hash, - polkadot_core_primitives::BlockNumber, - >, - >, - sp_api::ApiError, - > { + ) -> Result>, sp_api::ApiError> { Ok(self .rpc_client .parachain_host_persisted_validation_data(at, para_id, assumption) @@ -172,14 +162,11 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { async fn assumed_validation_data( &self, at: Hash, - para_id: cumulus_primitives_core::ParaId, + para_id: ParaId, expected_persisted_validation_data_hash: Hash, ) -> Result< Option<( - cumulus_primitives_core::PersistedValidationData< - Hash, - polkadot_core_primitives::BlockNumber, - >, + PersistedValidationData, polkadot_primitives::ValidationCodeHash, )>, sp_api::ApiError, @@ -197,7 +184,7 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { async fn check_validation_outputs( &self, at: Hash, - para_id: cumulus_primitives_core::ParaId, + para_id: ParaId, outputs: polkadot_primitives::CandidateCommitments, ) -> Result { Ok(self @@ -216,7 +203,7 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { async fn validation_code( &self, at: Hash, - para_id: cumulus_primitives_core::ParaId, + para_id: ParaId, assumption: polkadot_primitives::OccupiedCoreAssumption, ) -> Result, sp_api::ApiError> { Ok(self.rpc_client.parachain_host_validation_code(at, para_id, assumption).await?) @@ -225,7 +212,7 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { async fn candidate_pending_availability( &self, at: Hash, - para_id: cumulus_primitives_core::ParaId, + para_id: ParaId, ) -> Result>, sp_api::ApiError> { Ok(self .rpc_client @@ -243,24 +230,19 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { async fn dmq_contents( &self, at: Hash, - recipient: cumulus_primitives_core::ParaId, - ) -> Result< - Vec>, - sp_api::ApiError, - > { + recipient: ParaId, + ) -> Result>, sp_api::ApiError> { Ok(self.rpc_client.parachain_host_dmq_contents(recipient, at).await?) } async fn inbound_hrmp_channels_contents( &self, at: Hash, - recipient: cumulus_primitives_core::ParaId, + recipient: ParaId, ) -> Result< std::collections::BTreeMap< - cumulus_primitives_core::ParaId, - Vec< - polkadot_core_primitives::InboundHrmpMessage, - >, + ParaId, + Vec>, >, sp_api::ApiError, > { @@ -329,7 +311,7 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { async fn validation_code_hash( &self, at: Hash, - para_id: cumulus_primitives_core::ParaId, + para_id: ParaId, assumption: polkadot_primitives::OccupiedCoreAssumption, ) -> Result, sp_api::ApiError> { Ok(self @@ -424,7 +406,7 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { async fn para_backing_state( &self, at: Hash, - para_id: cumulus_primitives_core::ParaId, + para_id: ParaId, ) -> Result, ApiError> { Ok(self.rpc_client.parachain_host_para_backing_state(at, para_id).await?) } @@ -448,14 +430,14 @@ impl RuntimeApiSubsystemClient for BlockChainRpcClient { async fn claim_queue( &self, at: Hash, - ) -> Result>, ApiError> { + ) -> Result>, ApiError> { Ok(self.rpc_client.parachain_host_claim_queue(at).await?) } async fn candidates_pending_availability( &self, at: Hash, - para_id: cumulus_primitives_core::ParaId, + para_id: ParaId, ) -> Result>, sp_api::ApiError> { Ok(self .rpc_client diff --git a/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs b/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs index f01ef8b05ecb..5acc30537080 100644 --- a/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs +++ b/cumulus/client/relay-chain-minimal-node/src/collator_overseer.rs @@ -1,18 +1,18 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// This file is part of Cumulus. -// Polkadot is free software: you can redistribute it and/or modify +// 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. -// Polkadot is distributed in the hope that it will be useful, +// 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 Polkadot. If not, see . +// along with Cumulus. If not, see . use futures::{select, StreamExt}; use std::sync::Arc; diff --git a/cumulus/client/relay-chain-minimal-node/src/lib.rs b/cumulus/client/relay-chain-minimal-node/src/lib.rs index 9101b8154aa7..a3d858ea40c9 100644 --- a/cumulus/client/relay-chain-minimal-node/src/lib.rs +++ b/cumulus/client/relay-chain-minimal-node/src/lib.rs @@ -1,18 +1,18 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// This file is part of Cumulus. -// Polkadot is free software: you can redistribute it and/or modify +// 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. -// Polkadot is distributed in the hope that it will be useful, +// 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 Polkadot. If not, see . +// along with Cumulus. If not, see . use collator_overseer::NewMinimalNode; @@ -96,19 +96,20 @@ async fn build_interface( client: RelayChainRpcClient, ) -> RelayChainResult<(Arc<(dyn RelayChainInterface + 'static)>, Option)> { let collator_pair = CollatorPair::generate().0; + let blockchain_rpc_client = Arc::new(BlockChainRpcClient::new(client.clone())); let collator_node = match polkadot_config.network.network_backend { sc_network::config::NetworkBackendType::Libp2p => new_minimal_relay_chain::>( polkadot_config, collator_pair.clone(), - Arc::new(BlockChainRpcClient::new(client.clone())), + blockchain_rpc_client, ) .await?, sc_network::config::NetworkBackendType::Litep2p => new_minimal_relay_chain::( polkadot_config, collator_pair.clone(), - Arc::new(BlockChainRpcClient::new(client.clone())), + blockchain_rpc_client, ) .await?, }; @@ -120,17 +121,19 @@ async fn build_interface( } pub async fn build_minimal_relay_chain_node_with_rpc( - polkadot_config: Configuration, + relay_chain_config: Configuration, + parachain_prometheus_registry: Option<&Registry>, task_manager: &mut TaskManager, relay_chain_url: Vec, ) -> RelayChainResult<(Arc<(dyn RelayChainInterface + 'static)>, Option)> { let client = cumulus_relay_chain_rpc_interface::create_client_and_start_worker( relay_chain_url, task_manager, + parachain_prometheus_registry, ) .await?; - build_interface(polkadot_config, task_manager, client).await + build_interface(relay_chain_config, task_manager, client).await } pub async fn build_minimal_relay_chain_node_light_client( @@ -175,9 +178,11 @@ 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 role = config.role; + let mut net_config = sc_network::config::FullNetworkConfiguration::<_, _, Network>::new( + &config.network, + config.prometheus_config.as_ref().map(|cfg| cfg.registry.clone()), + ); let metrics = Network::register_notification_metrics( config.prometheus_config.as_ref().map(|cfg| &cfg.registry), ); diff --git a/cumulus/client/relay-chain-minimal-node/src/network.rs b/cumulus/client/relay-chain-minimal-node/src/network.rs index 025ac7a81a21..afe83a2a12f9 100644 --- a/cumulus/client/relay-chain-minimal-node/src/network.rs +++ b/cumulus/client/relay-chain-minimal-node/src/network.rs @@ -65,7 +65,7 @@ pub(crate) fn build_collator_network>( spawn_handle.spawn("peer-store", Some("networking"), peer_store.run()); let network_params = sc_network::config::Params:: { - role: config.role.clone(), + role: config.role, executor: { let spawn_handle = Clone::clone(&spawn_handle); Box::new(move |fut| { diff --git a/cumulus/client/relay-chain-rpc-interface/Cargo.toml b/cumulus/client/relay-chain-rpc-interface/Cargo.toml index 6c0730a56a26..fb4cb4ceed4e 100644 --- a/cumulus/client/relay-chain-rpc-interface/Cargo.toml +++ b/cumulus/client/relay-chain-rpc-interface/Cargo.toml @@ -9,6 +9,9 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" [lints] workspace = true +[dev-dependencies] +portpicker = "0.1.1" + [dependencies] polkadot-overseer = { workspace = true, default-features = true } @@ -26,6 +29,7 @@ sp-version = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } sc-rpc-api = { workspace = true, default-features = true } sc-service = { workspace = true, default-features = true } +prometheus-endpoint = { workspace = true, default-features = true } tokio = { features = ["sync"], workspace = true, default-features = true } tokio-util = { features = ["compat"], workspace = true } @@ -46,3 +50,4 @@ either = { workspace = true, default-features = true } thiserror = { workspace = true } rand = { workspace = true, default-features = true } pin-project = { workspace = true } +prometheus = { workspace = true } diff --git a/cumulus/client/relay-chain-rpc-interface/src/lib.rs b/cumulus/client/relay-chain-rpc-interface/src/lib.rs index e32ec6a41a4b..f53cdeffea94 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/lib.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/lib.rs @@ -39,6 +39,7 @@ use cumulus_primitives_core::relay_chain::BlockId; pub use url::Url; mod light_client_worker; +mod metrics; mod reconnecting_ws_client; mod rpc_client; mod tokio_platform; @@ -87,12 +88,13 @@ impl RelayChainInterface for RelayChainRpcInterface { async fn header(&self, block_id: BlockId) -> RelayChainResult> { let hash = match block_id { BlockId::Hash(hash) => hash, - BlockId::Number(num) => + BlockId::Number(num) => { if let Some(hash) = self.rpc_client.chain_get_block_hash(Some(num)).await? { hash } else { return Ok(None) - }, + } + }, }; let header = self.rpc_client.chain_get_header(Some(hash)).await?; @@ -163,6 +165,18 @@ impl RelayChainInterface for RelayChainRpcInterface { self.rpc_client.chain_get_finalized_head().await } + async fn call_runtime_api( + &self, + method_name: &'static str, + hash: RelayHash, + payload: &[u8], + ) -> RelayChainResult> { + self.rpc_client + .call_remote_runtime_function_encoded(method_name, hash, payload) + .await + .map(|bytes| bytes.to_vec()) + } + async fn is_major_syncing(&self) -> RelayChainResult { self.rpc_client.system_health().await.map(|h| h.is_syncing) } @@ -258,4 +272,13 @@ impl RelayChainInterface for RelayChainRpcInterface { ) -> RelayChainResult>> { self.rpc_client.parachain_host_availability_cores(relay_parent).await } + + async fn claim_queue( + &self, + relay_parent: RelayHash, + ) -> RelayChainResult< + BTreeMap>, + > { + self.rpc_client.parachain_host_claim_queue(relay_parent).await + } } diff --git a/cumulus/client/relay-chain-rpc-interface/src/metrics.rs b/cumulus/client/relay-chain-rpc-interface/src/metrics.rs new file mode 100644 index 000000000000..4d09464d237c --- /dev/null +++ b/cumulus/client/relay-chain-rpc-interface/src/metrics.rs @@ -0,0 +1,49 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +use prometheus::{Error as PrometheusError, HistogramTimer, Registry}; +use prometheus_endpoint::{HistogramOpts, HistogramVec, Opts}; + +/// Gathers metrics about the blockchain RPC client. +#[derive(Clone)] +pub(crate) struct RelaychainRpcMetrics { + rpc_request: HistogramVec, +} + +impl RelaychainRpcMetrics { + pub(crate) fn register(registry: &Registry) -> Result { + Ok(Self { + rpc_request: prometheus_endpoint::register( + HistogramVec::new( + HistogramOpts { + common_opts: Opts::new( + "relay_chain_rpc_interface", + "Tracks stats about cumulus relay chain RPC interface", + ), + buckets: prometheus::exponential_buckets(0.001, 4.0, 9) + .expect("function parameters are constant and always valid; qed"), + }, + &["method"], + )?, + registry, + )?, + }) + } + + pub(crate) fn start_request_timer(&self, method: &str) -> HistogramTimer { + self.rpc_request.with_label_values(&[method]).start_timer() + } +} diff --git a/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs b/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs index 48d35dd3a55e..dc0e9d697b46 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/reconnecting_ws_client.rs @@ -34,7 +34,7 @@ use jsonrpsee::{ use sc_rpc_api::chain::ChainApiClient; use schnellru::{ByLength, LruMap}; use sp_runtime::generic::SignedBlock; -use std::sync::Arc; +use std::{sync::Arc, time::Duration}; use tokio::sync::mpsc::{ channel as tokio_channel, Receiver as TokioReceiver, Sender as TokioSender, }; @@ -43,6 +43,9 @@ use url::Url; use crate::rpc_client::{distribute_header, RpcDispatcherMessage}; const LOG_TARGET: &str = "reconnecting-websocket-client"; +const DEFAULT_EXTERNAL_RPC_CONN_RETRIES: usize = 5; +const DEFAULT_SLEEP_TIME_MS_BETWEEN_RETRIES: u64 = 1000; +const DEFAULT_SLEEP_EXP_BACKOFF_BETWEEN_RETRIES: i32 = 2; /// Worker that should be used in combination with [`RelayChainRpcClient`]. /// @@ -93,16 +96,45 @@ struct RelayChainSubscriptions { best_subscription: Subscription, } -/// Try to find a new RPC server to connect to. +/// Try to find a new RPC server to connect to. Uses a naive retry +/// logic that does an exponential backoff in between iterations +/// through all URLs from the list. It uses a constant to tell how +/// many iterations of connection attempts to all URLs we allow. We +/// return early when a connection is made. async fn connect_next_available_rpc_server( urls: &Vec, starting_position: usize, ) -> Result<(usize, Arc), ()> { tracing::debug!(target: LOG_TARGET, starting_position, "Connecting to RPC server."); - for (counter, url) in urls.iter().cycle().skip(starting_position).take(urls.len()).enumerate() { + + let mut prev_iteration: u32 = 0; + for (counter, url) in urls + .iter() + .cycle() + .skip(starting_position) + .take(urls.len() * DEFAULT_EXTERNAL_RPC_CONN_RETRIES) + .enumerate() + { + // If we reached the end of the urls list, backoff before retrying + // connections to the entire list once more. + let Ok(current_iteration) = (counter / urls.len()).try_into() else { + tracing::error!(target: LOG_TARGET, "Too many connection attempts to the RPC servers, aborting..."); + break; + }; + if current_iteration > prev_iteration { + // Safe conversion given we convert positive i32s which are lower than u64::MAX. + tokio::time::sleep(Duration::from_millis( + DEFAULT_SLEEP_TIME_MS_BETWEEN_RETRIES * + DEFAULT_SLEEP_EXP_BACKOFF_BETWEEN_RETRIES.pow(prev_iteration) as u64, + )) + .await; + prev_iteration = current_iteration; + } + let index = (starting_position + counter) % urls.len(); tracing::info!( target: LOG_TARGET, + attempt = current_iteration, index, url, "Trying to connect to next external relaychain node.", @@ -112,6 +144,8 @@ async fn connect_next_available_rpc_server( Err(err) => tracing::debug!(target: LOG_TARGET, url, ?err, "Unable to connect."), }; } + + tracing::error!(target: LOG_TARGET, "Retrying to connect to any external relaychain node failed."); Err(()) } @@ -431,9 +465,14 @@ impl ReconnectingWebsocketWorker { #[cfg(test)] mod test { - use super::url_to_string_with_port; + use std::time::Duration; + + use super::{url_to_string_with_port, ClientManager}; + use jsonrpsee::Methods; use url::Url; + const SERVER_STARTUP_DELAY_SECONDS: u64 = 10; + #[test] fn url_to_string_works() { let url = Url::parse("wss://something/path").unwrap(); @@ -460,4 +499,29 @@ mod test { url_to_string_with_port(url) ); } + + #[tokio::test] + // Testing the retry logic at full means increasing CI with half a minute according + // to the current logic, so lets test it best effort. + async fn client_manager_retry_logic() { + let port = portpicker::pick_unused_port().unwrap(); + let server = jsonrpsee::server::Server::builder() + .build(format!("0.0.0.0:{}", port)) + .await + .unwrap(); + + // Start the server. + let server = tokio::spawn(async { + tokio::time::sleep(Duration::from_secs(SERVER_STARTUP_DELAY_SECONDS)).await; + server.start(Methods::default()) + }); + + // Start the client. Not exitting right away with an error means it + // is handling gracefully received connections refused while the server + // is starting. + let res = ClientManager::new(vec![format!("ws://127.0.0.1:{}", port)]).await; + assert!(res.is_ok()); + + server.await.unwrap(); + } } diff --git a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs index c7eaa45958b0..d8e5abaddc6b 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs @@ -22,7 +22,8 @@ use jsonrpsee::{ core::{params::ArrayParams, ClientError as JsonRpseeError}, rpc_params, }; -use serde::de::DeserializeOwned; +use prometheus::Registry; +use serde::{de::DeserializeOwned, Serialize}; use serde_json::Value as JsonValue; use std::collections::{btree_map::BTreeMap, VecDeque}; use tokio::sync::mpsc::Sender as TokioSender; @@ -52,6 +53,7 @@ use sp_version::RuntimeVersion; use crate::{ light_client_worker::{build_smoldot_client, LightClientRpcWorker}, + metrics::RelaychainRpcMetrics, reconnecting_ws_client::ReconnectingWebsocketWorker, }; pub use url::Url; @@ -87,6 +89,7 @@ pub enum RpcDispatcherMessage { pub async fn create_client_and_start_worker( urls: Vec, task_manager: &mut TaskManager, + prometheus_registry: Option<&Registry>, ) -> RelayChainResult { let (worker, sender) = ReconnectingWebsocketWorker::new(urls).await; @@ -94,7 +97,7 @@ pub async fn create_client_and_start_worker( .spawn_essential_handle() .spawn("relay-chain-rpc-worker", None, worker.run()); - let client = RelayChainRpcClient::new(sender); + let client = RelayChainRpcClient::new(sender, prometheus_registry); Ok(client) } @@ -113,16 +116,21 @@ pub async fn create_client_and_start_light_client_worker( .spawn_essential_handle() .spawn("relay-light-client-worker", None, worker.run()); - let client = RelayChainRpcClient::new(sender); + // We'll not setup prometheus exporter metrics for the light client worker. + let client = RelayChainRpcClient::new(sender, None); Ok(client) } +#[derive(Serialize)] +struct PayloadToHex<'a>(#[serde(with = "sp_core::bytes")] &'a [u8]); + /// Client that maps RPC methods and deserializes results #[derive(Clone)] pub struct RelayChainRpcClient { /// Sender to send messages to the worker. worker_channel: TokioSender, + metrics: Option, } impl RelayChainRpcClient { @@ -130,8 +138,44 @@ impl RelayChainRpcClient { /// /// This client expects a channel connected to a worker that processes /// requests sent via this channel. - pub(crate) fn new(worker_channel: TokioSender) -> Self { - RelayChainRpcClient { worker_channel } + pub(crate) fn new( + worker_channel: TokioSender, + prometheus_registry: Option<&Registry>, + ) -> Self { + RelayChainRpcClient { + worker_channel, + metrics: prometheus_registry + .and_then(|inner| RelaychainRpcMetrics::register(inner).map_err(|err| { + tracing::warn!(target: LOG_TARGET, error = %err, "Unable to instantiate the RPC client metrics, continuing w/o metrics setup."); + }).ok()), + } + } + + /// Same as `call_remote_runtime_function` but work on encoded data + pub async fn call_remote_runtime_function_encoded( + &self, + method_name: &str, + hash: RelayHash, + payload: &[u8], + ) -> RelayChainResult { + let payload = PayloadToHex(payload); + + let params = rpc_params! { + method_name, + payload, + hash + }; + + self.request_tracing::("state_call", params, |err| { + tracing::trace!( + target: LOG_TARGET, + %method_name, + %hash, + error = %err, + "Error during call to 'state_call'.", + ); + }) + .await } /// Call a call to `state_call` rpc method. @@ -143,21 +187,8 @@ impl RelayChainRpcClient { ) -> RelayChainResult { let payload_bytes = payload.map_or(sp_core::Bytes(Vec::new()), |v| sp_core::Bytes(v.encode())); - let params = rpc_params! { - method_name, - payload_bytes, - hash - }; let res = self - .request_tracing::("state_call", params, |err| { - tracing::trace!( - target: LOG_TARGET, - %method_name, - %hash, - error = %err, - "Error during call to 'state_call'.", - ); - }) + .call_remote_runtime_function_encoded(method_name, hash, &payload_bytes) .await?; Decode::decode(&mut &*res.0).map_err(Into::into) } @@ -190,6 +221,8 @@ impl RelayChainRpcClient { R: DeserializeOwned + std::fmt::Debug, OR: Fn(&RelayChainError), { + let _timer = self.metrics.as_ref().map(|inner| inner.start_request_timer(method)); + let (tx, rx) = futures::channel::oneshot::channel(); let message = RpcDispatcherMessage::Request(method.into(), params, tx); diff --git a/cumulus/client/service/src/lib.rs b/cumulus/client/service/src/lib.rs index 9b5f0bec5387..25b8ee10a931 100644 --- a/cumulus/client/service/src/lib.rs +++ b/cumulus/client/service/src/lib.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. @@ -28,10 +28,7 @@ use cumulus_relay_chain_interface::{RelayChainInterface, RelayChainResult}; use cumulus_relay_chain_minimal_node::{ build_minimal_relay_chain_node_light_client, build_minimal_relay_chain_node_with_rpc, }; -use futures::{ - channel::{mpsc, oneshot}, - FutureExt, StreamExt, -}; +use futures::{channel::mpsc, StreamExt}; use polkadot_primitives::{CollatorPair, OccupiedCoreAssumption}; use sc_client_api::{ Backend as BackendT, BlockBackend, BlockchainEvents, Finalizer, ProofProvider, UsageProvider, @@ -43,7 +40,10 @@ use sc_consensus::{ use sc_network::{config::SyncMode, service::traits::NetworkService, NetworkBackend}; use sc_network_sync::SyncingService; use sc_network_transactions::TransactionsHandlerController; -use sc_service::{Configuration, NetworkStarter, SpawnTaskHandle, TaskManager, WarpSyncParams}; +use sc_service::{ + build_polkadot_syncing_strategy, Configuration, NetworkStarter, SpawnTaskHandle, TaskManager, + WarpSyncConfig, +}; use sc_telemetry::{log, TelemetryWorkerHandle}; use sc_utils::mpsc::TracingUnboundedSender; use sp_api::ProvideRuntimeApi; @@ -373,6 +373,7 @@ pub async fn build_relay_chain_interface( cumulus_client_cli::RelayChainMode::ExternalRpc(rpc_target_urls) => build_minimal_relay_chain_node_with_rpc( relay_chain_config, + parachain_config.prometheus_registry(), task_manager, rpc_target_urls, ) @@ -416,7 +417,7 @@ pub struct BuildNetworkParams< pub net_config: sc_network::config::FullNetworkConfiguration::Hash, Network>, pub client: Arc, - pub transaction_pool: Arc>, + pub transaction_pool: Arc>, pub para_id: ParaId, pub relay_chain_interface: RCInterface, pub spawn_handle: SpawnTaskHandle, @@ -428,7 +429,7 @@ pub struct BuildNetworkParams< pub async fn build_network<'a, Block, Client, RCInterface, IQ, Network>( BuildNetworkParams { parachain_config, - net_config, + mut net_config, client, transaction_pool, para_id, @@ -465,14 +466,21 @@ where IQ: ImportQueue + 'static, Network: NetworkBackend::Hash>, { - let warp_sync_params = match parachain_config.network.sync_mode { + let warp_sync_config = match parachain_config.network.sync_mode { SyncMode::Warp => { - let target_block = warp_sync_get::( - para_id, - relay_chain_interface.clone(), - spawn_handle.clone(), - ); - Some(WarpSyncParams::WaitForTarget(target_block)) + log::debug!(target: LOG_TARGET_SYNC, "waiting for announce block..."); + + let target_block = + wait_for_finalized_para_head::(para_id, relay_chain_interface.clone()) + .await + .inspect_err(|e| { + log::error!( + target: LOG_TARGET_SYNC, + "Unable to determine parachain target block {:?}", + e + ); + })?; + Some(WarpSyncConfig::WithTarget(target_block)) }, _ => None, }; @@ -489,9 +497,19 @@ where }, }; let metrics = Network::register_notification_metrics( - parachain_config.prometheus_config.as_ref().map(|cfg| &cfg.registry), + parachain_config.prometheus_config.as_ref().map(|config| &config.registry), ); + let syncing_strategy = build_polkadot_syncing_strategy( + parachain_config.protocol_id(), + parachain_config.chain_spec.fork_id(), + &mut net_config, + warp_sync_config, + client.clone(), + &spawn_handle, + parachain_config.prometheus_config.as_ref().map(|config| &config.registry), + )?; + sc_service::build_network(sc_service::BuildNetworkParams { config: parachain_config, net_config, @@ -500,67 +518,37 @@ where spawn_handle, import_queue, block_announce_validator_builder: Some(Box::new(move |_| block_announce_validator)), - warp_sync_params, + syncing_strategy, block_relay: None, metrics, }) } -/// Creates a new background task to wait for the relay chain to sync up and retrieve the parachain -/// header -fn warp_sync_get( - para_id: ParaId, - relay_chain_interface: RCInterface, - spawner: SpawnTaskHandle, -) -> oneshot::Receiver<::Header> -where - B: BlockT + 'static, - RCInterface: RelayChainInterface + 'static, -{ - let (sender, receiver) = oneshot::channel::(); - spawner.spawn( - "cumulus-parachain-wait-for-target-block", - None, - async move { - log::debug!( - target: LOG_TARGET_SYNC, - "waiting for announce block in a background task...", - ); - - let _ = wait_for_finalized_para_head::(sender, para_id, relay_chain_interface) - .await - .map_err(|e| { - log::error!( - target: LOG_TARGET_SYNC, - "Unable to determine parachain target block {:?}", - e - ) - }); - } - .boxed(), - ); - - receiver -} - /// Waits for the relay chain to have finished syncing and then gets the parachain header that /// corresponds to the last finalized relay chain block. async fn wait_for_finalized_para_head( - sender: oneshot::Sender<::Header>, para_id: ParaId, relay_chain_interface: RCInterface, -) -> Result<(), Box> +) -> sc_service::error::Result<::Header> where B: BlockT + 'static, RCInterface: RelayChainInterface + Send + 'static, { - let mut imported_blocks = relay_chain_interface.import_notification_stream().await?.fuse(); - while imported_blocks.next().await.is_some() { - let is_syncing = relay_chain_interface.is_major_syncing().await.map_err(|e| { - Box::::from(format!( - "Unable to determine sync status. {e}" + let mut imported_blocks = relay_chain_interface + .import_notification_stream() + .await + .map_err(|error| { + sc_service::Error::Other(format!( + "Relay chain import notification stream error when waiting for parachain head: \ + {error}" )) - })?; + })? + .fuse(); + while imported_blocks.next().await.is_some() { + let is_syncing = relay_chain_interface + .is_major_syncing() + .await + .map_err(|e| format!("Unable to determine sync status: {e}"))?; if !is_syncing { let relay_chain_best_hash = relay_chain_interface @@ -586,8 +574,7 @@ where finalized_header.number(), finalized_header.hash() ); - let _ = sender.send(finalized_header); - return Ok(()) + return Ok(finalized_header) } } diff --git a/cumulus/pallets/aura-ext/src/lib.rs b/cumulus/pallets/aura-ext/src/lib.rs index 4c9e61458a87..dc854eb82018 100644 --- a/cumulus/pallets/aura-ext/src/lib.rs +++ b/cumulus/pallets/aura-ext/src/lib.rs @@ -16,7 +16,7 @@ //! Cumulus extension pallet for AuRa //! -//! This pallets extends the Substrate AuRa pallet to make it compatible with parachains. It +//! This pallet extends the Substrate AuRa pallet to make it compatible with parachains. It //! provides the [`Pallet`], the [`Config`] and the [`GenesisConfig`]. //! //! It is also required that the parachain runtime uses the provided [`BlockExecutor`] to properly diff --git a/cumulus/pallets/collator-selection/Cargo.toml b/cumulus/pallets/collator-selection/Cargo.toml index b3512dc2ae6c..8d67db3daf8b 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/lib.rs b/cumulus/pallets/collator-selection/src/lib.rs index 17dc1a552c2d..9d7e62af3c68 100644 --- a/cumulus/pallets/collator-selection/src/lib.rs +++ b/cumulus/pallets/collator-selection/src/lib.rs @@ -972,7 +972,7 @@ pub mod pallet { let result = Self::assemble_collators(); frame_system::Pallet::::register_extra_weight_unchecked( - T::WeightInfo::new_session(candidates_len_before, removed), + T::WeightInfo::new_session(removed, candidates_len_before), DispatchClass::Mandatory, ); Some(result) diff --git a/cumulus/pallets/collator-selection/src/migration.rs b/cumulus/pallets/collator-selection/src/migration.rs index c52016948069..34f914297082 100644 --- a/cumulus/pallets/collator-selection/src/migration.rs +++ b/cumulus/pallets/collator-selection/src/migration.rs @@ -1,18 +1,18 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// This file is part of Cumulus. -// Polkadot is free software: you can redistribute it and/or modify +// 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. -// Polkadot is distributed in the hope that it will be useful, +// 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 Polkadot. If not, see . +// along with Cumulus. If not, see . //! A module that is responsible for migration of storage for Collator Selection. diff --git a/cumulus/pallets/collator-selection/src/mock.rs b/cumulus/pallets/collator-selection/src/mock.rs index 459b1cb5fdf2..d13f9e9d8c44 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/collator-selection/src/weights.rs b/cumulus/pallets/collator-selection/src/weights.rs index 12e6b755e976..0ac4a085754a 100644 --- a/cumulus/pallets/collator-selection/src/weights.rs +++ b/cumulus/pallets/collator-selection/src/weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/pallets/dmp-queue/src/migration.rs b/cumulus/pallets/dmp-queue/src/migration.rs index b1945e8eb37b..1b83fea710a3 100644 --- a/cumulus/pallets/dmp-queue/src/migration.rs +++ b/cumulus/pallets/dmp-queue/src/migration.rs @@ -1,18 +1,18 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// This file is part of Cumulus. -// Polkadot is free software: you can redistribute it and/or modify +// 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. -// Polkadot is distributed in the hope that it will be useful, +// 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 Polkadot. If not, see . +// along with Cumulus. If not, see . //! Migrates the storage from the previously deleted DMP pallet. diff --git a/cumulus/pallets/dmp-queue/src/mock.rs b/cumulus/pallets/dmp-queue/src/mock.rs index ed72ce678e3e..a46a6ba6c8ba 100644 --- a/cumulus/pallets/dmp-queue/src/mock.rs +++ b/cumulus/pallets/dmp-queue/src/mock.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/pallets/dmp-queue/src/tests.rs b/cumulus/pallets/dmp-queue/src/tests.rs index a157d0584f25..70d542ea2ed2 100644 --- a/cumulus/pallets/dmp-queue/src/tests.rs +++ b/cumulus/pallets/dmp-queue/src/tests.rs @@ -1,12 +1,12 @@ // Copyright Parity Technologies (UK) Ltd. // This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/cumulus/pallets/parachain-system/Cargo.toml b/cumulus/pallets/parachain-system/Cargo.toml index 30a232f01b3e..3cb0394c4b95 100644 --- a/cumulus/pallets/parachain-system/Cargo.toml +++ b/cumulus/pallets/parachain-system/Cargo.toml @@ -49,7 +49,6 @@ cumulus-primitives-proof-size-hostfunction = { workspace = true } [dev-dependencies] assert_matches = { workspace = true } hex-literal = { workspace = true, default-features = true } -lazy_static = { workspace = true } trie-standardmap = { workspace = true } rand = { workspace = true, default-features = true } futures = { workspace = true } @@ -122,3 +121,5 @@ try-runtime = [ "polkadot-runtime-parachains/try-runtime", "sp-runtime/try-runtime", ] + +experimental-ump-signals = [] diff --git a/cumulus/pallets/parachain-system/src/benchmarking.rs b/cumulus/pallets/parachain-system/src/benchmarking.rs index 5cde8eb5b788..8f97d12a4809 100644 --- a/cumulus/pallets/parachain-system/src/benchmarking.rs +++ b/cumulus/pallets/parachain-system/src/benchmarking.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/pallets/parachain-system/src/lib.rs b/cumulus/pallets/parachain-system/src/lib.rs index 9e0a68d09a14..98989a852b8d 100644 --- a/cumulus/pallets/parachain-system/src/lib.rs +++ b/cumulus/pallets/parachain-system/src/lib.rs @@ -31,12 +31,16 @@ extern crate alloc; use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec}; use codec::{Decode, Encode}; -use core::cmp; +use core::{cmp, marker::PhantomData}; use cumulus_primitives_core::{ - relay_chain, AbridgedHostConfiguration, ChannelInfo, ChannelStatus, CollationInfo, - GetChannelInfo, InboundDownwardMessage, InboundHrmpMessage, ListChannelInfos, MessageSendError, + relay_chain::{ + self, + vstaging::{ClaimQueueOffset, CoreSelector}, + }, + AbridgedHostConfiguration, ChannelInfo, ChannelStatus, CollationInfo, GetChannelInfo, + InboundDownwardMessage, InboundHrmpMessage, ListChannelInfos, MessageSendError, OutboundHrmpMessage, ParaId, PersistedValidationData, UpwardMessage, UpwardMessageSender, - XcmpMessageHandler, XcmpMessageSource, + XcmpMessageHandler, XcmpMessageSource, DEFAULT_CLAIM_QUEUE_OFFSET, }; use cumulus_primitives_parachain_inherent::{MessageQueueChain, ParachainInherentData}; use frame_support::{ @@ -51,11 +55,9 @@ use frame_system::{ensure_none, ensure_root, pallet_prelude::HeaderFor}; use polkadot_parachain_primitives::primitives::RelayChainBlockNumber; use polkadot_runtime_parachains::FeeTracker; use scale_info::TypeInfo; +use sp_core::U256; use sp_runtime::{ - traits::{Block as BlockT, BlockNumberProvider, Hash}, - transaction_validity::{ - InvalidTransaction, TransactionSource, TransactionValidity, ValidTransaction, - }, + traits::{Block as BlockT, BlockNumberProvider, Hash, One}, BoundedSlice, FixedU128, RuntimeDebug, Saturating, }; use xcm::{latest::XcmHash, VersionedLocation, VersionedXcm}; @@ -189,11 +191,53 @@ pub mod ump_constants { pub const MESSAGE_SIZE_FEE_BASE: FixedU128 = FixedU128::from_rational(1, 1000); // 0.001 } +/// Trait for selecting the next core to build the candidate for. +pub trait SelectCore { + /// Core selector information for the current block. + fn selected_core() -> (CoreSelector, ClaimQueueOffset); + /// Core selector information for the next block. + fn select_next_core() -> (CoreSelector, ClaimQueueOffset); +} + +/// The default core selection policy. +pub struct DefaultCoreSelector(PhantomData); + +impl SelectCore for DefaultCoreSelector { + fn selected_core() -> (CoreSelector, ClaimQueueOffset) { + let core_selector: U256 = frame_system::Pallet::::block_number().into(); + + (CoreSelector(core_selector.byte(0)), ClaimQueueOffset(DEFAULT_CLAIM_QUEUE_OFFSET)) + } + + fn select_next_core() -> (CoreSelector, ClaimQueueOffset) { + let core_selector: U256 = (frame_system::Pallet::::block_number() + One::one()).into(); + + (CoreSelector(core_selector.byte(0)), ClaimQueueOffset(DEFAULT_CLAIM_QUEUE_OFFSET)) + } +} + +/// Core selection policy that builds on claim queue offset 1. +pub struct LookaheadCoreSelector(PhantomData); + +impl SelectCore for LookaheadCoreSelector { + fn selected_core() -> (CoreSelector, ClaimQueueOffset) { + let core_selector: U256 = frame_system::Pallet::::block_number().into(); + + (CoreSelector(core_selector.byte(0)), ClaimQueueOffset(1)) + } + + fn select_next_core() -> (CoreSelector, ClaimQueueOffset) { + let core_selector: U256 = (frame_system::Pallet::::block_number() + One::one()).into(); + + (CoreSelector(core_selector.byte(0)), ClaimQueueOffset(1)) + } +} + #[frame_support::pallet] pub mod pallet { use super::*; use frame_support::pallet_prelude::*; - use frame_system::{pallet_prelude::*, WeightInfo as SystemWeightInfo}; + use frame_system::pallet_prelude::*; #[pallet::pallet] #[pallet::storage_version(migration::STORAGE_VERSION)] @@ -249,6 +293,9 @@ pub mod pallet { /// that collators aren't expected to have node versions that supply the included block /// in the relay-chain state proof. type ConsensusHook: ConsensusHook; + + /// Select core. + type SelectCore: SelectCore; } #[pallet::hooks] @@ -344,6 +391,11 @@ pub mod pallet { UpwardMessages::::put(&up[..num as usize]); *up = up.split_off(num as usize); + // Send the core selector UMP signal. This is experimental until relay chain + // validators are upgraded to handle ump signals. + #[cfg(feature = "experimental-ump-signals")] + Self::send_ump_signal(); + // If the total size of the pending messages is less than the threshold, // we decrease the fee factor, since the queue is less congested. // This makes delivery of new messages cheaper. @@ -369,7 +421,8 @@ pub mod pallet { let maximum_channels = host_config .hrmp_max_message_num_per_candidate - .min(>::take()) as usize; + .min(>::take()) + as usize; // Note: this internally calls the `GetChannelInfo` implementation for this // pallet, which draws on the `RelevantMessagingState`. That in turn has @@ -653,52 +706,8 @@ pub mod pallet { Ok(()) } - /// Authorize an upgrade to a given `code_hash` for the runtime. The runtime can be supplied - /// later. - /// - /// The `check_version` parameter sets a boolean flag for whether or not the runtime's spec - /// version and name should be verified on upgrade. Since the authorization only has a hash, - /// it cannot actually perform the verification. - /// - /// This call requires Root origin. - #[pallet::call_index(2)] - #[pallet::weight(::SystemWeightInfo::authorize_upgrade())] - #[allow(deprecated)] - #[deprecated( - note = "To be removed after June 2024. Migrate to `frame_system::authorize_upgrade`." - )] - pub fn authorize_upgrade( - origin: OriginFor, - code_hash: T::Hash, - check_version: bool, - ) -> DispatchResult { - ensure_root(origin)?; - frame_system::Pallet::::do_authorize_upgrade(code_hash, check_version); - Ok(()) - } - - /// Provide the preimage (runtime binary) `code` for an upgrade that has been authorized. - /// - /// If the authorization required a version check, this call will ensure the spec name - /// remains unchanged and that the spec version has increased. - /// - /// Note that this function will not apply the new `code`, but only attempt to schedule the - /// upgrade with the Relay Chain. - /// - /// All origins are allowed. - #[pallet::call_index(3)] - #[pallet::weight(::SystemWeightInfo::apply_authorized_upgrade())] - #[allow(deprecated)] - #[deprecated( - note = "To be removed after June 2024. Migrate to `frame_system::apply_authorized_upgrade`." - )] - pub fn enact_authorized_upgrade( - _: OriginFor, - code: Vec, - ) -> DispatchResultWithPostInfo { - let post = frame_system::Pallet::::do_apply_authorize_upgrade(code)?; - Ok(post) - } + // WARNING: call indices 2 and 3 were used in a former version of this pallet. Using them + // again will require to bump the transaction version of runtimes using this pallet. } #[pallet::event] @@ -951,30 +960,6 @@ pub mod pallet { sp_io::storage::set(b":c", &[]); } } - - #[pallet::validate_unsigned] - impl sp_runtime::traits::ValidateUnsigned for Pallet { - type Call = Call; - - fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity { - if let Call::enact_authorized_upgrade { ref code } = call { - if let Ok(hash) = frame_system::Pallet::::validate_authorized_upgrade(&code[..]) - { - return Ok(ValidTransaction { - priority: 100, - requires: Vec::new(), - provides: vec![hash.as_ref().to_vec()], - longevity: TransactionLongevity::max_value(), - propagate: true, - }) - } - } - if let Call::set_validation_data { .. } = call { - return Ok(Default::default()) - } - Err(InvalidTransaction::Call.into()) - } - } } impl Pallet { @@ -1443,6 +1428,11 @@ impl Pallet { } } + /// Returns the core selector for the next block. + pub fn core_selector() -> (CoreSelector, ClaimQueueOffset) { + T::SelectCore::select_next_core() + } + /// Set a custom head data that should be returned as result of `validate_block`. /// /// This will overwrite the head data that is returned as result of `validate_block` while @@ -1459,6 +1449,20 @@ impl Pallet { CustomValidationHeadData::::put(head_data); } + /// Send the ump signals + #[cfg(feature = "experimental-ump-signals")] + fn send_ump_signal() { + use cumulus_primitives_core::relay_chain::vstaging::{UMPSignal, UMP_SEPARATOR}; + + UpwardMessages::::mutate(|up| { + up.push(UMP_SEPARATOR); + + // Send the core selector signal. + let core_selector = T::SelectCore::selected_core(); + up.push(UMPSignal::SelectCore(core_selector.0, core_selector.1).encode()); + }); + } + /// Open HRMP channel for using it in benchmarks or tests. /// /// The caller assumes that the pallet will accept regular outbound message to the sibling @@ -1611,6 +1615,10 @@ impl UpwardMessageSender for Pallet { } impl InspectMessageQueues for Pallet { + fn clear_messages() { + PendingUpwardMessages::::kill(); + } + fn get_messages() -> Vec<(VersionedLocation, Vec>)> { use xcm::prelude::*; @@ -1619,7 +1627,11 @@ impl InspectMessageQueues for Pallet { .map(|encoded_message| VersionedXcm::<()>::decode(&mut &encoded_message[..]).unwrap()) .collect(); - vec![(VersionedLocation::V4(Parent.into()), messages)] + if messages.is_empty() { + vec![] + } else { + vec![(VersionedLocation::from(Location::parent()), messages)] + } } } diff --git a/cumulus/pallets/parachain-system/src/mock.rs b/cumulus/pallets/parachain-system/src/mock.rs index 7bea72224b8b..1f5e4f4dbcf3 100644 --- a/cumulus/pallets/parachain-system/src/mock.rs +++ b/cumulus/pallets/parachain-system/src/mock.rs @@ -49,9 +49,9 @@ type Block = frame_system::mocking::MockBlock; frame_support::construct_runtime!( pub enum Test { - System: frame_system::{Pallet, Call, Config, Storage, Event}, - ParachainSystem: parachain_system::{Pallet, Call, Config, Storage, Inherent, Event, ValidateUnsigned}, - MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event}, + System: frame_system, + ParachainSystem: parachain_system, + MessageQueue: pallet_message_queue, } ); @@ -64,7 +64,7 @@ parameter_types! { impl_version: 1, apis: sp_version::create_apis_vec!([]), transaction_version: 1, - state_version: 1, + system_version: 1, }; pub const ParachainId: ParaId = ParaId::new(200); pub const ReservedXcmpWeight: Weight = Weight::zero(); @@ -94,6 +94,7 @@ impl Config for Test { type CheckAssociatedRelayNumber = AnyRelayNumber; type ConsensusHook = TestConsensusHook; type WeightInfo = (); + type SelectCore = DefaultCoreSelector; } std::thread_local! { diff --git a/cumulus/pallets/parachain-system/src/tests.rs b/cumulus/pallets/parachain-system/src/tests.rs index 51c6e83c1131..23223627ebca 100755 --- a/cumulus/pallets/parachain-system/src/tests.rs +++ b/cumulus/pallets/parachain-system/src/tests.rs @@ -754,12 +754,8 @@ fn message_queue_chain() { #[test] #[cfg(not(feature = "runtime-benchmarks"))] fn receive_dmp() { - lazy_static::lazy_static! { - static ref MSG: InboundDownwardMessage = InboundDownwardMessage { - sent_at: 1, - msg: b"down".to_vec(), - }; - } + static MSG: std::sync::LazyLock = + std::sync::LazyLock::new(|| InboundDownwardMessage { sent_at: 1, msg: b"down".to_vec() }); BlockTests::new() .with_relay_sproof_builder(|_, relay_block_num, sproof| match relay_block_num { @@ -771,14 +767,14 @@ fn receive_dmp() { }) .with_inherent_data(|_, relay_block_num, data| match relay_block_num { 1 => { - data.downward_messages.push(MSG.clone()); + data.downward_messages.push((*MSG).clone()); }, _ => unreachable!(), }) .add(1, || { HANDLED_DMP_MESSAGES.with(|m| { let mut m = m.borrow_mut(); - assert_eq!(&*m, &[(MSG.msg.clone())]); + assert_eq!(&*m, &[MSG.msg.clone()]); m.clear(); }); }); @@ -1127,10 +1123,8 @@ fn upgrade_version_checks_should_work() { let new_code = vec![1, 2, 3, 4]; let new_code_hash = H256(sp_crypto_hashing::blake2_256(&new_code)); - #[allow(deprecated)] - let _authorize = ParachainSystem::authorize_upgrade(RawOrigin::Root.into(), new_code_hash, true); - #[allow(deprecated)] - let res = ParachainSystem::enact_authorized_upgrade(RawOrigin::None.into(), new_code); + let _authorize = System::authorize_upgrade(RawOrigin::Root.into(), new_code_hash); + let res = System::apply_authorized_upgrade(RawOrigin::None.into(), new_code); assert_eq!(expected.map_err(DispatchErrorWithPostInfo::from), res); }); diff --git a/cumulus/pallets/parachain-system/src/validate_block/implementation.rs b/cumulus/pallets/parachain-system/src/validate_block/implementation.rs index 42311ca9d834..2c531c39accd 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/implementation.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/implementation.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Substrate. +// This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. @@ -33,7 +33,7 @@ use frame_support::traits::{ExecuteBlock, ExtrinsicCall, Get, IsSubType}; use sp_core::storage::{ChildInfo, StateVersion}; use sp_externalities::{set_and_run_with_externalities, Externalities}; use sp_io::KillStorageResult; -use sp_runtime::traits::{Block as BlockT, Extrinsic, HashingFor, Header as HeaderT}; +use sp_runtime::traits::{Block as BlockT, ExtrinsicLike, HashingFor, Header as HeaderT}; use sp_trie::{MemoryDB, ProofSizeProvider}; use trie_recorder::SizeOnlyRecorderProvider; @@ -96,7 +96,7 @@ pub fn validate_block< ) -> ValidationResult where B::Extrinsic: ExtrinsicCall, - ::Call: IsSubType>, + ::Call: IsSubType>, { let block_data = codec::decode_from_bytes::>(block_data) .expect("Invalid parachain block data"); @@ -240,16 +240,13 @@ fn extract_parachain_inherent_data( ) -> &ParachainInherentData where B::Extrinsic: ExtrinsicCall, - ::Call: IsSubType>, + ::Call: IsSubType>, { block .extrinsics() .iter() // Inherents are at the front of the block and are unsigned. - // - // If `is_signed` is returning `None`, we keep it safe and assume that it is "signed". - // We are searching for unsigned transactions anyway. - .take_while(|e| !e.is_signed().unwrap_or(true)) + .take_while(|e| e.is_bare()) .filter_map(|e| e.call().is_sub_type()) .find_map(|c| match c { crate::Call::set_validation_data { data: validation_data } => Some(validation_data), diff --git a/cumulus/pallets/parachain-system/src/validate_block/mod.rs b/cumulus/pallets/parachain-system/src/validate_block/mod.rs index 3a00d4d352a6..2d210f4bac2b 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/mod.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/mod.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Substrate. +// This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/cumulus/pallets/parachain-system/src/validate_block/tests.rs b/cumulus/pallets/parachain-system/src/validate_block/tests.rs index 1527492f5784..871ce5c1710e 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/tests.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/tests.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Substrate. +// This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. @@ -312,7 +312,7 @@ fn validation_params_and_memory_optimized_validation_params_encode_and_decode() fn validate_block_works_with_child_tries() { sp_tracing::try_init_simple(); - let (mut client, parent_head) = create_test_client(); + let (client, parent_head) = create_test_client(); let TestBlockData { block, .. } = build_block_with_witness( &client, vec![generate_extrinsic(&client, Charlie, TestPalletCall::read_and_write_child_tries {})], diff --git a/cumulus/pallets/parachain-system/src/validate_block/trie_cache.rs b/cumulus/pallets/parachain-system/src/validate_block/trie_cache.rs index 5999b3ce87f9..035541fb17b1 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/trie_cache.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/trie_cache.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/pallets/parachain-system/src/validate_block/trie_recorder.rs b/cumulus/pallets/parachain-system/src/validate_block/trie_recorder.rs index 198013407195..4a478d047f1b 100644 --- a/cumulus/pallets/parachain-system/src/validate_block/trie_recorder.rs +++ b/cumulus/pallets/parachain-system/src/validate_block/trie_recorder.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Substrate. +// This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/cumulus/pallets/session-benchmarking/Cargo.toml b/cumulus/pallets/session-benchmarking/Cargo.toml index e182ac45edeb..5af94434e0af 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/pallets/session-benchmarking/src/lib.rs b/cumulus/pallets/session-benchmarking/src/lib.rs index f5bfef006169..7d3a9ff70e7e 100644 --- a/cumulus/pallets/session-benchmarking/src/lib.rs +++ b/cumulus/pallets/session-benchmarking/src/lib.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/pallets/xcmp-queue/src/bridging.rs b/cumulus/pallets/xcmp-queue/src/bridging.rs index eff4a37b0cef..8ed11505a27a 100644 --- a/cumulus/pallets/xcmp-queue/src/bridging.rs +++ b/cumulus/pallets/xcmp-queue/src/bridging.rs @@ -15,48 +15,52 @@ use crate::{pallet, OutboundState}; use cumulus_primitives_core::ParaId; -use frame_support::pallet_prelude::Get; +use xcm::latest::prelude::*; /// Adapter implementation for `bp_xcm_bridge_hub_router::XcmChannelStatusProvider` which checks -/// both `OutboundXcmpStatus` and `InboundXcmpStatus` for defined `ParaId` if any of those is +/// both `OutboundXcmpStatus` and `InboundXcmpStatus` for defined `Location` if any of those is /// suspended. -pub struct InAndOutXcmpChannelStatusProvider( - core::marker::PhantomData<(SiblingBridgeHubParaId, Runtime)>, -); -impl, Runtime: crate::Config> - bp_xcm_bridge_hub_router::XcmChannelStatusProvider - for InAndOutXcmpChannelStatusProvider +pub struct InAndOutXcmpChannelStatusProvider(core::marker::PhantomData); +impl bp_xcm_bridge_hub_router::XcmChannelStatusProvider + for InAndOutXcmpChannelStatusProvider { - fn is_congested() -> bool { + fn is_congested(with: &Location) -> bool { + // handle congestion only for a sibling parachain locations. + let sibling_para_id: ParaId = match with.unpack() { + (_, [Parachain(para_id)]) => (*para_id).into(), + _ => return false, + }; + // if the inbound channel with recipient is suspended, it means that we are unable to - // receive congestion reports from the bridge hub. So we assume the bridge pipeline is - // congested too - if pallet::Pallet::::is_inbound_channel_suspended(SiblingBridgeHubParaId::get()) { + // receive congestion reports from the `with` location. So we assume the pipeline is + // congested too. + if pallet::Pallet::::is_inbound_channel_suspended(sibling_para_id) { return true } // if the outbound channel with recipient is suspended, it means that one of further - // bridge queues (e.g. bridge queue between two bridge hubs) is overloaded, so we shall + // queues (e.g. bridge queue between two bridge hubs) is overloaded, so we shall // take larger fee for our outbound messages - OutXcmpChannelStatusProvider::::is_congested() + OutXcmpChannelStatusProvider::::is_congested(with) } } /// Adapter implementation for `bp_xcm_bridge_hub_router::XcmChannelStatusProvider` which checks /// only `OutboundXcmpStatus` for defined `SiblingParaId` if is suspended. -pub struct OutXcmpChannelStatusProvider( - core::marker::PhantomData<(SiblingBridgeHubParaId, Runtime)>, -); -impl, Runtime: crate::Config> - bp_xcm_bridge_hub_router::XcmChannelStatusProvider - for OutXcmpChannelStatusProvider +pub struct OutXcmpChannelStatusProvider(core::marker::PhantomData); +impl bp_xcm_bridge_hub_router::XcmChannelStatusProvider + for OutXcmpChannelStatusProvider { - fn is_congested() -> bool { - let sibling_bridge_hub_id: ParaId = SiblingBridgeHubParaId::get(); + fn is_congested(with: &Location) -> bool { + // handle congestion only for a sibling parachain locations. + let sibling_para_id: ParaId = match with.unpack() { + (_, [Parachain(para_id)]) => (*para_id).into(), + _ => return false, + }; // let's find the channel's state with the sibling parachain, let Some((outbound_state, queued_pages)) = - pallet::Pallet::::outbound_channel_state(sibling_bridge_hub_id) + pallet::Pallet::::outbound_channel_state(sibling_para_id) else { return false }; diff --git a/cumulus/pallets/xcmp-queue/src/lib.rs b/cumulus/pallets/xcmp-queue/src/lib.rs index 8c4446a925d4..6bb7395f6553 100644 --- a/cumulus/pallets/xcmp-queue/src/lib.rs +++ b/cumulus/pallets/xcmp-queue/src/lib.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. @@ -1008,6 +1008,11 @@ impl SendXcm for Pallet { } impl InspectMessageQueues for Pallet { + fn clear_messages() { + // Best effort. + let _ = OutboundXcmpMessages::::clear(u32::MAX, None); + } + fn get_messages() -> Vec<(VersionedLocation, Vec>)> { use xcm::prelude::*; diff --git a/cumulus/pallets/xcmp-queue/src/migration.rs b/cumulus/pallets/xcmp-queue/src/migration.rs index d0657aaea9fd..6e41c9d9a878 100644 --- a/cumulus/pallets/xcmp-queue/src/migration.rs +++ b/cumulus/pallets/xcmp-queue/src/migration.rs @@ -1,18 +1,18 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// This file is part of Cumulus. -// Polkadot is free software: you can redistribute it and/or modify +// 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. -// Polkadot is distributed in the hope that it will be useful, +// 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 Polkadot. If not, see . +// along with Cumulus. If not, see . //! A module that is responsible for migration of storage. diff --git a/cumulus/pallets/xcmp-queue/src/migration/v5.rs b/cumulus/pallets/xcmp-queue/src/migration/v5.rs index 818365f36f60..0bf3303bd7d0 100644 --- a/cumulus/pallets/xcmp-queue/src/migration/v5.rs +++ b/cumulus/pallets/xcmp-queue/src/migration/v5.rs @@ -1,18 +1,18 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// This file is part of Cumulus. -// Polkadot is free software: you can redistribute it and/or modify +// 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. -// Polkadot is distributed in the hope that it will be useful, +// 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 Polkadot. If not, see . +// along with Cumulus. If not, see . //! Migrates the storage to version 5. diff --git a/cumulus/pallets/xcmp-queue/src/mock.rs b/cumulus/pallets/xcmp-queue/src/mock.rs index 7fb96de7a4ea..3964ecf28cac 100644 --- a/cumulus/pallets/xcmp-queue/src/mock.rs +++ b/cumulus/pallets/xcmp-queue/src/mock.rs @@ -20,7 +20,7 @@ use cumulus_pallet_parachain_system::AnyRelayNumber; use cumulus_primitives_core::{ChannelInfo, IsSystem, ParaId}; use frame_support::{ derive_impl, parameter_types, - traits::{ConstU32, Everything, Nothing, OriginTrait}, + traits::{ConstU32, Everything, OriginTrait}, BoundedSlice, }; use frame_system::EnsureRoot; @@ -30,10 +30,6 @@ use sp_runtime::{ BuildStorage, }; use xcm::prelude::*; -use xcm_builder::{ - FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, IsConcrete, NativeAsset, - ParentIsPreset, -}; use xcm_executor::traits::ConvertOrigin; type Block = frame_system::mocking::MockBlock; @@ -45,7 +41,7 @@ frame_support::construct_runtime!( System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, ParachainSystem: cumulus_pallet_parachain_system::{ - Pallet, Call, Config, Storage, Inherent, Event, ValidateUnsigned, + Pallet, Call, Config, Storage, Inherent, Event, }, XcmpQueue: xcmp_queue::{Pallet, Call, Storage, Event}, } @@ -108,6 +104,7 @@ impl cumulus_pallet_parachain_system::Config for Test { type ReservedXcmpWeight = (); type CheckAssociatedRelayNumber = AnyRelayNumber; type ConsensusHook = cumulus_pallet_parachain_system::consensus_hook::ExpectParentIncluded; + type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector; } parameter_types! { @@ -118,61 +115,6 @@ parameter_types! { pub const MaxAssetsIntoHolding: u32 = 64; } -/// Means for transacting assets on this chain. -pub type LocalAssetTransactor = FungibleAdapter< - // Use this currency: - Balances, - // Use this currency when it is a fungible asset matching the given location or name: - IsConcrete, - // Do a simple punn to convert an AccountId32 Location into a native chain account ID: - LocationToAccountId, - // Our chain's account ID type (we can't get away without mentioning it explicitly): - AccountId, - // We don't track any teleports. - (), ->; - -pub type LocationToAccountId = (ParentIsPreset,); - -pub struct XcmConfig; -impl xcm_executor::Config for XcmConfig { - type RuntimeCall = RuntimeCall; - type XcmSender = XcmRouter; - // How to withdraw and deposit an asset. - type AssetTransactor = LocalAssetTransactor; - type OriginConverter = (); - type IsReserve = NativeAsset; - type IsTeleporter = NativeAsset; - type UniversalLocation = UniversalLocation; - type Barrier = (); - type Weigher = FixedWeightBounds; - type Trader = (); - type ResponseHandler = (); - type AssetTrap = (); - type AssetClaims = (); - type SubscriptionService = (); - type PalletInstancesInfo = AllPalletsWithSystem; - type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type AssetLocker = (); - type AssetExchanger = (); - type FeeManager = (); - type MessageExporter = (); - type UniversalAliases = Nothing; - type CallDispatcher = RuntimeCall; - type SafeCallFilter = Everything; - type Aliasers = Nothing; - type TransactionalProcessor = FrameTransactionalProcessor; - type HrmpNewChannelOpenRequestHandler = (); - type HrmpChannelAcceptedHandler = (); - type HrmpChannelClosingHandler = (); - type XcmRecorder = (); -} - -pub type XcmRouter = ( - // XCMP to communicate with the sibling chains. - XcmpQueue, -); - pub struct SystemParachainAsSuperuser(PhantomData); impl ConvertOrigin for SystemParachainAsSuperuser diff --git a/cumulus/parachains/chain-specs/coretime-polkadot.json b/cumulus/parachains/chain-specs/coretime-polkadot.json new file mode 100644 index 000000000000..e4f947d2afc9 --- /dev/null +++ b/cumulus/parachains/chain-specs/coretime-polkadot.json @@ -0,0 +1,96 @@ +{ + "name": "Polkadot Coretime", + "id": "coretime-polkadot", + "chainType": "Live", + "bootNodes": [ + "/dns/polkadot-coretime-connect-a-0.polkadot.io/tcp/30334/p2p/12D3KooWKjnixAHbKMsPTJwGx8SrBeGEJLHA8KmKcEDYMp3YmWgR", + "/dns/polkadot-coretime-connect-a-1.polkadot.io/tcp/30334/p2p/12D3KooWQ7B7p4DFv1jWqaKfhrZBcMmi5g8bWFnmskguLaGEmT6n", + "/dns/polkadot-coretime-connect-a-0.polkadot.io/tcp/443/wss/p2p/12D3KooWKjnixAHbKMsPTJwGx8SrBeGEJLHA8KmKcEDYMp3YmWgR", + "/dns/polkadot-coretime-connect-a-1.polkadot.io/tcp/443/wss/p2p/12D3KooWQ7B7p4DFv1jWqaKfhrZBcMmi5g8bWFnmskguLaGEmT6n", + "/dns4/coretime-polkadot.boot.stake.plus/tcp/30332/wss/p2p/12D3KooWFJ2yBTKFKYwgKUjfY3F7XfaxHV8hY6fbJu5oMkpP7wZ9", + "/dns4/coretime-polkadot.boot.stake.plus/tcp/31332/wss/p2p/12D3KooWCy5pToLafcQzPHn5kadxAftmF6Eh8ZJGPXhSeXSUDfjv", + "/dns/coretime-polkadot-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWGpmytHjdthrkKgkXDZyKm9ABtJ2PtGk9NStJDG4pChy9", + "/dns/coretime-polkadot-boot-ng.dwellir.com/tcp/30361/p2p/12D3KooWGpmytHjdthrkKgkXDZyKm9ABtJ2PtGk9NStJDG4pChy9", + "/dns/coretime-polkadot-bootnode.radiumblock.com/tcp/30333/p2p/12D3KooWFsQphSqvqjVyKcEdR1D7LPcXHqjmy6ASuJrTr5isk9JU", + "/dns/coretime-polkadot-bootnode.radiumblock.com/tcp/30336/wss/p2p/12D3KooWFsQphSqvqjVyKcEdR1D7LPcXHqjmy6ASuJrTr5isk9JU" + ], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "ss58Format": 0, + "tokenDecimals": 10, + "tokenSymbol": "DOT" + }, + "relay_chain": "polkadot", + "para_id": 1005, + "codeSubstitutes": {}, + "genesis": { + "raw": { + "top": { + "0x0d715f2646c8f85767b5d2764bb2782604a74d81251e398fd8a0a4d55023bb3f": "0xed030000", + "0x0d715f2646c8f85767b5d2764bb278264e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x15464cac3378d46f113cd5b7a4d71c84476f594316a7dfe49c1f352d95abdaf1": "0x00000000", + "0x15464cac3378d46f113cd5b7a4d71c844e7b9012096b41c4eb3aaf947f6ea429": "0x0200", + "0x15464cac3378d46f113cd5b7a4d71c845579297f4dfb9609e7e4c2ebab9ce40a": "0x1c00f379b621bd73c45c7d155d2a1fe6a04649e3ece7c7e03b70b3a6242bc7c127049bec59fb5fe6adea4578250578e89dd7e51ad88c7c92493d6f451c6680925c20d8c795eef2620fba2bde74dbc36461c07998ebf600ed265b746c1e05c706064c0aa0240b2d7485675e52cdb283a87973652f6acb42c830a5a5faa80f7a707e6610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38689e1a66fa33b75f66415021aacc4fa23f49306a3c21407748b8b2d39b4abf6380b6f570f356fef7b891afa2e1c30fca89bc7a2cddd545fd8a173106fce3a11f", + "0x15464cac3378d46f113cd5b7a4d71c84579f5a43435b04a98d64da0cefe18505": "0x00a0acb9030000000000000000000000", + "0x1809d78346727a0ef58c0fa03bafa3234e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96": "0x000000008200e17579c4", + "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746b4def25cfda6ef3a00000000": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9381ca18820b278a00faeab03d52440be00f379b621bd73c45c7d155d2a1fe6a04649e3ece7c7e03b70b3a6242bc7c127": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da944098499b5de4f5677804569aeadeb5e4c0aa0240b2d7485675e52cdb283a87973652f6acb42c830a5a5faa80f7a707e": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94c4f030742ff8899655335ad1e54ca6a6610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94d2dbb242ff048066ba7c14ef24678cf20d8c795eef2620fba2bde74dbc36461c07998ebf600ed265b746c1e05c70606": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da956f8d5eba063b801102d640867bbb26f689e1a66fa33b75f66415021aacc4fa23f49306a3c21407748b8b2d39b4abf63": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da96684268ab336f4623df9eab07c482056049bec59fb5fe6adea4578250578e89dd7e51ad88c7c92493d6f451c6680925c": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9784e05d1b3afe91a143e23fe5983f63080b6f570f356fef7b891afa2e1c30fca89bc7a2cddd545fd8a173106fce3a11f": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da994eb9f87cb79eefab94a8a6ffcb94bfe6d6f646c70792f62726f6b650000000000000000000000000000000000000000": "0x0000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0xe2373d0044636f726574696d652d706f6c6b61646f74", + "0x3a63": "0x", + "0x3a636f6465": "0x52bc537646db8e0528b52ffd0058b40805be8e467714531068689474e824c10a8cc53774726667883ec05d802d901643e234ed8170f89bac708c7155821d498f97282e09dca01e2231f2d04dc75ed1ff328c8cb9dcb66ec66356fc03a1ff37d21a2184104208d95b4a1924164e147013536e28ea9568e6424433bf39eaf5749ad799e3bcdebcc62baa8b99b5bb1045972edcdc7cca0dbd79253a5d88e8f499df68e0ac0d450d80e0c5cccccce93399579a75cf70040f84703a9d4e9c877dc8db66a56206344470c4ebf6d36be937afe0675e636cb07b17ba3e84ddf3bc4fb941bd77b35289620b6264b15d8868f36695b98e5d08fcd0750cc3b06bb3b292e88214cc28954adb4bb362b39aaeebbaae67b312f1043020c8b26d9bf66dd66bd68e9b758823c8308533689aa6bdc6bce6953bf6aa8136b36623406307660c4066d66b8a2aca0004ed42441ac9346bb340081ff881f681ddacdc0408706084a669da6bf6ee35e632afdc6d5eb52360e9436091598b385201129cc82e44943de63b940e5e68fb50e920087eca0d0a7e00b366a08b177c8004ee4244dcb3c7cc0ace5a647be942f143db4ba552e9a4598950e20c56a2c8b24fb9a1d92b51cc858862ce3d9bb534eb005e8784e2b70b19f950fcf66dfb941b74fb37eb65842d5ce0058efb941bcabd12811722021f73eeb574d22bf8ef35e6da2b37eb362bf74a348593a1f1536ed0f821a17823171a8a3772a01f993576d1842a4d88898979252a5d88a874f031b3c6f9b3c3ac54be50420e5e0082e02b51bc10517ce9e0ac46e6008accaa811970600c4628954aaf443ac49766059a3b746a3f805933249c80841234c64fb9a1f195687521221dbe7a7ca5df5e578f79d5e1e06b9c5500b300b3ca26a6808213b412d10be970a2d5f4a1537b3a1df03325403425a33a9c68ca0cd5e1536ea80eb3874eedb9979edd74efa8db78ce737cc77b5ec3879cc873780000000000e490430e38e0800311229f52a2446eb8e186214386d860c3a794a80daf3caf397676765e6978d5c183078fd71faf3b7af4e8f11ae435e5c3c7a7d8501faf425e7b7878785e55af4068a0e1536c280daf3e2a954a88102141827c4a8906f9f1e3534af4c76bcfab4e8e1c395e81bceee8d0f1293654c76b0daf3c76ecf8141bbae3d5861a6af89412ade1d5c7eb75743ec586eabcf648a53ec586a65e6b000204484f4f4f2af529259a7add79b51186e12b8fd71b737e8a0d9daf3d5e7370e0f8141b8ae3c78f4fb1a13f68a081061e1e1e1f3e7cf4e8f12925da83070f1e3b3b3b3a3a9f52a23aaf375e4f373737af39af332814eaf5af34383838af395e6bd8b0f12936d4c6ab8ed7f0c68d1baf3b5e674ecea7d8d09cd7d48e1d3b74e8d09123c7a794688eff534af4afe1ab773a9d5ee7ebcdcccca7d8d099571caf281a9a4fb1a134af3a38707c4a89e278b5f17a79dea7d850ef15a7468d4fb1a1355e71cc39c330ac51e3534ab4c6ebcd6b272323f38a7ab531993ec5869a5e715e6b30ec536c28f67f8a0d7d4e4ece8d1b376cd8b08183f329258a8342a16e6e6e3cef534ad47bb5798d0141f0b5e6b54422915eafd74fd33ec5866aafa7d7aceb3ec58676af33af323636363e685e4d35359f62436b82d4a0a1a1999999399d3ea5444fd7f529257abdcaa4b6989818cdd4037aa552097c259dbeefabf1662592c251ec44533e8a7d4a8962af9d0eb7dbb6490d27cb3ec58666efd4be62433ab5279212e975a229247a7d8a0dbde6d090941a1a2f45a3f143451a158a6730a2f1453534ce1c3ab5423a2869559c555e49a756eefbe361b3a0d7acf172a28e3489534807aae488fec4fd80ba6584034006197ce101767c8c8f315a41638c310e75cb03dc219ce009fa56a55a5525d8aabece91952b91369fb6f67ebf47888e2e185594d8efd71d63e4d8dcddc789ccd7284f1412be3cc7b99ddaca34320fa15bda7133771cf6d1d7de2e11ad5595697c10301a8953ebdae350526f890c31182a94512931a52e7a1c46fa49c13c2f548a475a22436c448574a0fcfe7e3c4823fe8e804694ef19517e77e956a79eee00cf5f91218c8c8c8ca0fcae3dd92afe7e5bd55aa7e27f9a43af53f1a534c07aa2af1a8def4ead929d5aa6f138ade2d7b44a86527228514ba37d8df64421e9cbf7e52c62ca73bf23fc9eb5cf8fcd4c846ea9d6aa7a138302b0cfaffb2e863580fdf8fd7e3cf49bc4a9756a7fbac53c80eea23b861457e809a75b1ea07c4fabaa36a455157cabae076995a4d76b5ab5472230835ec76955d38b568fd61e7a7ddba757d5a3b5865e075bd5bf7e6a55fcf5eb5eabf8d757e79a4df6882e8e163357e9f8ab537bc2a51d7b0c243bc5f2ff7890cfe6d675ef598b22e5733fb5ca7b7c4dab344fc3b059b173c734edf160abb0c7775ac8b4c3c2edd476ea3b7f469aca4e7db37ee7ae854bbfb0e35e8e24be162ef5c2a55898aaa1fc5d9e781c90f2acd9afc77791b90b9772a1a6037f0b8b2eca7ca2fd6ebbf6f633829d6798859569f6f82d66e2578fc677f2db68f23aa5d3a978eddba9fd3ba549baffe99f98854b37dc4ef56558990a71983061c2d0daa27b2cac4591ee796a9deaf307b4b3bfdf35c14ef57fda3bb56a697ca438ad3a8df7b144228ddf56f1ab0e8d5f9dd8f1b5836e752ab89daa1aed578deeb77db677fafb6e7780f1ddee80ddfe00f7a84a15ba471ca8426b89f66da07bb4012eb43f201a407e7f5b15df97adcaded75ab5b4dff50794cd05e36f7cc8c204cbb394bf02b4687cc75e0c976621d38ebff82e86452c04243b257f04a4f1fcedb0347e3fa0ed54f5285fb3b6e8a5c52cac9256f9a248b1ef0774fda7bb6e3f23d8ac9262d79e85f5347b0c6bad350611a50e41b36fa7b2ff442d1462d1f82cac3854be630f0b97c670e97e3c481affd33f7d854291c6cb703bc5df0f284ed929fe4faf4ecf26205d1cad8ce311dd2a00ac3894afd32a3e1f877f7eaa557bb48123caf7c1382ce56ff4d9ded9f337fa6cef548deeab46f91b7db6772a48f715a4fcd5e1d9a4872e8e167393ae01209fe9b690fd7edd2a00ac1eed7badda31a4b842fb60abf628044dd0fea955fb7e4dabf87d1cc681697f757a36395d1c2de60074cb03dc232392a055a37bb0553b861457e85e6bd516e10c69d0bdd72aa6fb6d9f5dd513ddafcece26a78ba3c5ac43b73ec00a527eaa55d5a37c7e4dab6a8af2f93e5ac5940fb66a8f36b085f24fad6acadff6e155c5a17caf557bfeeaf06cd24317478b3901dda6c0fd662632b0108e500617f381180fc424110302d317d3144c523069c1e405d3174c603099610a83490ca6334c6598ac600263c2820906a618805e00c1805d00b9006e01d4029805100be015c032402b805500a9007e01a7004601f40242017c02e8049009e0124025805d4030c02e4022804500bd008f401a802f00a500a3003950c2822904252494c62889514a4249097104b189c8445c222a21c120bf20bd20af20cb9056c854f0edc0fb80678477a5234357061212242c4860484f208d411283940512164a2328355162a2a444294b498a52074a564a1c286da064440a433a43898a120cb2116062c40f805f605cba33b82cdc141c0c382a382da62b60570057909d202b41f480d701ef08cf8a57858b02e704ce0bc90892d117e63bc367862f8daf0c1f1adf19df183e33be2f7c5df8b4f095f155e1a3c2f7e59bc227858f8c8f095f123e247c637c627c617c5c3e30be2ebe217c41f8b4f88e3e2cbe1f7c3e284df11df15df1e5e0bbc167056605d007de06b21490c440fa02c90b243390d22095814406121aa5284a2e2895a04482af0ae94ae9090f09508bd881d295120a4a554a272819513241c909ae0a8c0bac0adc0c38293a2e7038e06e509904611a830f0438b2831103140009d000563a20a0071e0ea0eae9b620c4062031213075c1c405d3164c593055c14405d3134c64988c60fac2e485a90b93104c5b987a60fa816907a61b987060b2c26403530d4c4f98a83081c0944412300c60124024805c4023804060238a1802b3b01168a574855219252b94aa50a242490a2528949e506a428909a52e19a00286211d7d3af870f075c00be39dc13383978657068f0c1e1ade19de183c317861f0ccf0c0e07dc1f38207c6eb82c7056f0b9e16bc2c7858f0aee09501c513418706f883ce0c100b308b6e091d153a31b8343833381b7035e068c0c9808b017704b701d315a61c987860aac2e403930e38a32dcc7686cd0c5b1adb184c5a9882602282a908262eb6306c666c60d8beb0796103b371c17464c2c2b4840d0b26304c4d30753129c1940413124c6398c43085613ac27685ad8c8d0adb976d0a5b14362f1b14b62c6c676c4dd898b029614bc286846d09db185b97ed099b13363236317046701ce0aa806880677056402c26266c5ad8d0d8ac6072c256854d0aa52fa52980660087008e014c03dc007785f30087049704f7010e045c08382c9c08b62d6c64e0942879e19600c5e098e046c091a0b404ae049c13601940326c626c616c5c4a51d8bed8c0d88cb079b11561eb6223c2c6c536844d08db165b10b62e6c653071310d6103c2a6c576b465b161b1fd60f30138c6c6836d071b0e361d6c576c39d86c104fb055b16dd968b0cd60abc1a6657bc116c5e682ad051b0b3628b6156c2ad864b0c560a36283c136c5966593627b6243c19682cd041b093627b612704d804c804b804a6c37d846b035b131b12db129b161d944b0856003c196c4f6810d89edcad681ed88cdca56058462e3c0b681cd88cd480ba39d413383968656068d0c1a1ada19da1834316861d0ccd0c0a07d41f3820646ebc276028d0bda164018949c5022c3e4014d0b5a16342c68656856d0aaa051c1f401b00a78c47684cd0a6d0a9a1440316851d0bc6850d09ea0394123436b82c6046d095a174d095a1234246863686268616847d0b86846d0c0d0bed0bcd08aa075a11141e3421b8226042d08da161a10342db42cb4230d0bed079a0fb41e683cd076a0e940bb42cb818603ed069a159a0db41a6855685b341a6833d0b46832d062a051a1c1409b42cba249a1bd408b427381d6028d051a14da0a34156829d09ed050a09d403381e68456028d04da08b4263426b4253425342c9a08b4106820d092d03ea079404342bba275403b42b3a255d138a06d40334233cac26467c8cc90a591952123438646764636864c0c591832333230645fc8bc9081c9ba907121db42a6852c0b1916b22b64656456c8aa905121fb924d2193421685cc4b0685ec0999133232b226644cc896104b9075c99490252143423646164676848c4b66840c8cec8bcc8bac0859171911322e32216441c8b6c88090699165911d6558643fc87c90f520db41a683ec8a2c07190eb21b64566455645b321a6433c8b46432c8a8c8609065c95e904591b52063014845e60476042c0ccc081818d81798175811b02e30226c1e8826882158828d114110932062880afc4001100c139040027a6021e8982e7765d83a06112da94092284b82824892a4e308c493a0244b8a9600912409b7fc44080b2429fa21688809104f98244962c3c3e38141f2be58a2200c2c799204e575b14541444143519214055dc0c623c206152d292222624214f424c8c88dc7c53e81c22449d15090942750a0f8f0039402e4f086f0431228167872c48913280228fa21c889132802e8e1096131f0c31033de16fb4488a124440c0191844914fa448804103134001a0f084b1414648124440c054961e2240888d0d36231f0c31037bc2c7678582c51511011d1922451920439a9c092a228413ffcb004033f3880c7fb418fe703274e96fce0c4c91201f42088a20b3c0972c2830d0ab240122845498a82b80093a0293b9e0e96c809932545414024090ab2c00e0f070bc5024f98242162284808212296f470ef061bf4c313284f922c49c2240a0dfae1099403143d1102ca0f3f501b9e154040f92108881caf064b44445093244444440421790285091151900242af8a9dc2240a1d0a6a3204a5013c841e0d36a86809104c9c2c9192244888202110e003104117b8c0121f7a783358a2263f0405f1430c96a8e849d05050104f98dca3e209130ba0bc29f60726444f980c150d119484082751a22c4932140484132642ac9afc00c5c90ac7cbb244371e0a7649121caf048b81244b8a9600b1a428c800266f041960e264099322264f98cc784a6c931fa038a94092a022217e081a2228c6c3b2435004e07921d82750a208910408274c84a84092274b7e48c2240a2d7a1284810b0429008820208470f2c313264f16b0644808bac303c1120531296232042588222196c87849ec13284c8a960c0901449222284e8892308942970c09416776b82c64508c91c509e8b6ba3d3232a2dc8a361826024c041c8533194d269349472772e7f04aac9725b618cbd5b48e3b0cc330896dcbddc532d9d92663b2acf3e425fb9ad998b16ba6b3968cad5c6c33de666e8cbb71601b316c3199652d7baf2b36ef4a6ed6b869b028773dde6ed9516a51ca28b9939c3126637794d815802d46665994b21bcb64dc96b11bebed4d4a2fcb9a59669eecade5caedbd5a7a5df3769671b3646c25d69c71b327bd6cf3322fdb0df3b2de4dee26b965b7e4665e996198a6692c97a564c9383100c830acbd2ddb4cca2e4ace64b66d9994524acebef96158672da5a669dd1d19a3699949afcbe416935dd7c59c75632cb7cdba97e52ec771dc0d77d31c731c37c735c735f372dccd35d7dd1c87711c87450cc3b0b8ad35866198d61ac69dd5d4608be55053d3ac6158776b58478e8d615ad43a4c6b0de3d8bba4dda8f576b6bcddbc196fafc65d7fe0f72d7f4c62de355d5fd738607d35efb5d7455a6c1bc3b0edd2f676b6d862bdbd18d68c3586ed2ecf485ec6969b799b33ce564ac66878b398e5ee6e5ead35c91863dddd758c75cb53e3586ed981b26327b9376652c6ccbddb2dbb9b4863cdccdb3277866a790373044b33bbccccdd729bbb872cb36c1f8c5b4a660c5be665d912c3b65b8569cd9259322f7393b26e6ec9429825f7aeec65ac7136eb1966ce5a0bb2dd9d79ddbd4d6ad2c7ddbb4c026d905a2f5fabf52e6fb3a6691a336bdcdcecedeed7bccd1d57f62eb8bbcc58770d40b85bdbd9bc2137694d2b9b9b7bbbbb9731eed6b8a75b62dbccdc65bdcddbadc9dde5eeeeeee6edd696f43573dfd8b0bb4b18c61896358661d933eeb0ffc062e4c5b088e25d6c8b281a78987b31295993925993f2da24fbc8616e6e0c6b8c2396c55eacaf5d13194c69449a6d2286a06020080318b8402e00c549920b3c6172810b40716253fa698820209e3049f284c992207eb08005a04c1b9c3861d2a4e7c68e1e291ea91a3e6aecd8e191ea2901e18449103f24297222c4120b0401b133b4a488684789c8e6e6a6c90f4b2ae0c40994211e3b96040dddd8043549523444d0931b4117b091212a2262324410ce55f4c312a2274b868a921431c10006a0a46a6c0d4c2c103414659e86960439f901555a204f82a2445982a3a368c950d093a00be4a009ca0013a22416800265284a92a00b2c1982524464430d434436160811166032142425c90d408408a90188201c1c104144444143513000e58724434152a0fc103494640911103f042501d24425a486283f0411258152148588a11f7c726c0d4550a00c2501226828088821284954426a08623254c46388a020704e1628122249d1132643516c16080698143d116228c90f444c303083a86ca884d450435093254e2a7099213500493204942945492ef0844910444b82b8b141414316c091f224286a0b24c913284c888682a424c140922128454b7e80e2c4c99224454304dd90f22428a63c347a5bad8e6b492a545aad8b4a0b53b254a850a14285a92c152a58cc946cabd5a2125b5953914a5a54b845a5d52d956c8b0a152aad16a6645b54a82c95562b462a9b9216b75a2d564285a950a1c2545aad64a9b0921653e196a664a950a142a57545254b854a2b69f12a592a545a2dd9ca94b4980a634a5adce2d6a5a4c5db924a5adc6a25db6ab5a2926db1121d6217de5dc600d1920ddf100320f6eb1800e5e3aba4d965ab9666ff96c8d22cbbb744b2af4ea60525b8501cba474a58417b5a2d2fe52f2a345e5fa89c42314c18d9c4c97cb26060a971f2b1fd785830b0506c66e9a8d07a85d79305030bbd5e3340b10b7b02802a47f49a598aa0a2cd1d82c6f3bb9661fc7e10c8520495fdb2dabe598c6c80e0054d403194030a1a7061541465bfd02c463f94a08591140054391aa266805e1bd82fab6d1aed97153f3e8b11cd13aae0c0158c8c563b8ba0a24d23a992b346a1f1a6283c418a335431325aed6700197a3546458785f6f73b68dd0d97062d91a11e9a45beb55578fcca79cd2a47f0acae5f915925d1aa13eddfc43001562774df43eb89d6a5420f55ae9093e8543f0a583909daaf4b05da67c98371270c4fe4600539d8e2c5c868753dbe82b4573134923108810b36d0021facaa1cc1b38abf22b392558ee815f62b0158c55fe19500ac583dc49d7ee442fbd7595a7cc07e4dd64fdce96393a5c587eb71b2aed953f7e828be2e971543078890650b4ca0220a61c49000dc556b045ef840052ac8a24b0dc0b0da957ceda1fdfd7cb891d12a26d1aa1db42fc3186edca91a5dc642170715d9e2965aa294e162a6fe755ecc945d57765d97c4e9d4f5fe98ee11161afc34d04693d7d725901087a1f2d8c4e9d4256594dd46d86b4be4fabebb2247ed117bc41eb3c76b587cc41e63ec3019c82b5c0c3b6347c9336d8a9231c07e858c4dd9a9d5ae90a90cf7a882343e4a1ae34f1187c66b5e04de83ee11087e4097d4d100f23113bf084799e97e401d3776330f1df6aee30f887b77b94be4fbf5ee0b5bb476d9d724fbbe0b6b768e2649f708cb13542ecfd51bf6bd30fb1632ed6fa8dd0bb56f46f8fb9fd666dd6bef36acddf75df4b4b0bff336d1dea47b9f0bbbb8bd3380f7ae3bef0a11b5e8f73aa50c6608438996cb144d78807eb3765d77795ad8db6587795ad8dfcf08126fd621e8f66e67fdf515e1cefd276eb8943fa06e36e18a70dfc97dbf231add6613edfdaa21e96bfc6de152196eab6379846ebf3a759708f6fdd56161904e5d58a4a03d9dbabe5fc5a1d7e37e41781e4efb70bf9ec312f9f268bfeea35560a7b4edd7b9707b47bb4efb6828af7d4ebda3fd3a962ab406a1d7514b84e9d56d214ea7b447ba47585cc0613093bcf678ba472200436bf8d38eca1e6953543685380ccdbe4758a0a0eb859722d053c8dbc4e9949685d7f2ecf79358c83466a155a35d341267effa88ef3886952976f6a9c2bd8a96f8edfbaedbc23deaeeda8bde16ae17a3eb2b80fc7888349e0b77d5ddb54de309d01201d578e8593007f8a1dae387a44b347bc717a952c1c25e7f3bfc78f1dbe1876aefcfc8132a448566dfef885773bae8f54780d60aa8f62e7af22bd282820a29a1dabb6612a952818262eba3cb3ceccb348fd3b67057dde671e1aeb67057fd1de963b372f34652a5427779ea1e31018662e742700b6f64646464b43a221f67fc8486a8b201238ce810366bec8f07f9489bc45fdf6f87a5d914a28616d5506ceef2d4788e315c7a854df8324421a944d0fe522addc2fa3a43b3c200af5efd41595575283f3b020116aea1062075e128892f1b6e0bd1c12e00dc2325a2a06c44e3bbd2bedff9b0b7a103c0266c04bdde74bf08630565caef0f091b51ec1b4a914740ba8fdf2552e55147382aa75089ee5709b467caf786a15d7b1b3600e433d5b2e74fe84220bf7571c3a05302761d0de0fe24d341009460b798c9eb94ecd4e93bf4c0456263c8cb6bda469fed9d0ad27a8abd5b1ee0f59a9f56550d54d22aec396077c01314bb045a152916b70bc586506cbda0d8e57f3a0465500cc3300cfbea60b3c982692d7447b2cb77320c33f9eca7a5b6fda765c8543bf6edb5b5615a97855298ca500ad3ec1dcb307bd7fde5914d320364efe4857064b75df4649885cf5a9b5552edd8b330b69c553b3ffb4fcc8458b4b3ce5ad3a6d655764a7b7f45987a97a1d4e67e40deb3b06697025227d2c8085ab50b65691811864ad1a87619d6eff157d884fbf5ae935393f2425a950d184187a46074bb948c12b5e83665bc56d49474d214e23428f785454db97ba150a4dc441de1237a5d7e40d76328ff13b95fa194a6f15d37af8fad08d3eb5c28b3599966dfc2ca5b58316fdbb66f53fb4fc4b0482b518bf2e5bd59449ecf854b67cd6613398558b446cae72320edff741796f61451f27cf90e51f2fdec9d0cf91d7f3bfc64e7ae3dfe8af4b3cb23fd2c13e2304345de7e47a21c5142b56bfb26f2d93b2dac92cac76d0e092d1823235a1443b5c758e4518d87285c3824a403ede5912fc228f7da547e0b87b817614892d0ed3fad854239743b170ae9407979b65088c3d0ed5a5899ca6deefa90fd15b92ecf1f10366b8b6297a1a685fc2c5cbabfc2daf23fbd1fd050f4d86b4257bade5de152fe7e15d92d565de948f7ee1d7bdcd73be77d3bc785a74eedb7100cf7fcae0ba530e5500ad3aeebde4912cf9f6e827d035bd53dfb9ebf12d36e3fa0c54c60a7b8f750efdca2cc6165da04fbf625c2340bbf3c7bb0553d74df8560a756a31912ecdb9425eed7e5bdf3f700ed9c374fdba9c5ceefbafdb6595b74bb1772e8859503dab85925e5de9dc3d895a9f74a80161674d787372bf7c8854bb970296fdb429266ffe99feeb0b05ee76b218aa710d36ce26c6164447bf0d02cc4e9d41e0b2bd3ab95f175854ecad0016013f91db4d225527be8d5ba8e70f4baae57392b152a5f3703ec14e835b368df50fb1532e08712b208b3dacbb0b2a86ce264bfd0ecd82b157a7d1787dd1f75bd908215b48869369fec172a14c384a1d8cc5204950503cb4a9b46fbcaa2d7acf275a3f13f51863b68c79e16eef783c0828165b53b28156e5ddd61a45a15822ebd8415d1678b3085078cc4d88285175a582d1653d8820bbe700215472bf00ba0d7297e46f78b1294419982668015a4fc2a2f30360086b749d7add78a37dbddd29552ca90e97ef111e89aa0fb0dbf743c067f04408100927c61f99f96539b3af1025d11a69a00c04e953aa6e07e04685129678b7900b5a606275e468fdec8973162dcedb7c7e0bebf02b468ed37d92944857e40a0141dbfe3b008534d88e9326d31e340e20bdd2324b6a0b544e57bd0058303576849b62abe6390cfa0fc0ad0a22dcaef3006055dfc80aef6b655d86352707dcf20ff0a43698429d62a5411a6d8b1a951fe15325d1d399b8067e804c0df37e93387312960fee92dd26d11708f3e7005bde81e79a00b5d53b7d4a35d8941ecfd9ef1f2c2faf13fbdad4215e9c747ec7cd9aa7abd49bc3c865d6b556373418ffef44fb7981907dd52b02b6dabf6080933e85eb6aa1fbff75a250bd09297ef4a3f607c5f880a95424ce5dc4e710598b8c2bfde6d00c03dba72855e6f19d1aeb43a958de8f68d3e33ef6bd1e7f43e187d64deaf893e31ef3ffa98de4f451ff0fd9ee8537a7f48f421bddfed67e4faf718ce6be17599d04acdadc8dce6a5d0ca8e5be9f1d249a115d4adcc845670260bc7716e65e63a3f8556e2ad9c7ee331a1951e9365e33d6e25e63c0e86566a704c968ee3e078cd5938af99ac9b9db3fe1cb7021e09d641d51c7556ea289db350a7e1a6d04a8f1ebf11dec664ed4c560daff1798f9cf738abe63d262bdcb9cd64dd787896cd7bdc4a9cacf81d13891e1b3e1e274b67b2748e03c77be84c568fe388c771968de398ac9b9be3384be73ddfb1b3f31b938563b2789ee361f81b67e1f88dc9da11722067ed1cc864f9d031593a9e9343c3754c968fe700392be740268b861e61781aceea1144c77bfe23c744a2e7e6e63c39729c75e33926eb664890e823c654dca9e9a18303651386378e0327b573a363e306c7a62627e2c49a540f1d14ea46b8f31e386e727470d8f4b07163c3c6070e2a95f358b373836373a34688eac60e0e540cdf23654388901e38efb92aea5c9523448810214370e8e4f4dce73e3754aab35257a96a50a9bfe7435043767c7cceb2711f213e373670543aaa3864c859361f32e4c68e1021393df7b9a9b90f0e214284a8ceb25109d1c9410d49c50ff90d67d9f80d3e417cceba711f06e28343a5bad979cf85842772567822ac1a7216ea43264b85f31f67fd370001c2731f67d99ca7e73e349ce73c7ef4f80df7394be73e1c44c864d960c3834c96902067d97890c9b221c8814c960d40ee73a387c764d5c0e3ac9af398ac1d3bcee32c9bf75cc5c39323070f1ee7e1392b751e9eb350579dc859f144b8e786b3707e03d7f01f379cc859ff8fb370dcc786c9e2992c9efbf0c133593df7e1e3369c65e33e72dcc7593ae739101e3cfe83061a0ee43c7e9cc75938cee3ac1bdf719fb376eec34254931524c8854c968f90b3722e64b2820879cf6405f98f1f579d15bee7ac1e2732594386bc86c9f231593eae8367b278f0b88fc9e2b90e1f677d3ac0c764f1f0711e67d5f09cd9c3ee60bf01488ed330593c268bc769f86fcc1d720079cf59396e63feec0ef69cb36e9e3359436cdcc7861bdf31593676fc860dbf7156fc8dc9b291739ec9baf1dbf8cfe2796a2a893388ddc1ae9a2c21a90799ac9ec9eab90df1354c16909e68454e96161fe2e7e57bceda99353d93553341f0a7ffa0a1e63c93e5a3741e353c5e73568f99e231593af3a5cb7ce72c1c73889dc90a6794d48ec9c2711da1e938c239595ab2c78767a1a6b63bd89a3ef34f560ee9376c5841dde62c9c396477b0a326eb66f6ec0e7616e93137bdb3097795856c446bc25d6161d5be8f1f12fef5fe8ab4f62ba29dfb4fdb84355e13d23c0bbd6361f74bfb4ffce99fae3184fd3a4dc86aadb460ffc2ca46947bd785312800bd77dfdeb1e7856c44f733c086a1de6c929dbbb066137584cf9dcf4da196114521e167cfe6d2fd16c63001b2115d9acd841b77faa7508b3b7d99108c3bfd98b026eef44de1e34e1f0c5371a75f0a7be24e9f140e893bfdd5c9661336a28b830a4f2beb1e1974d9e9a56fdce1711e7ff4b1e2dd0a127c1bdfbe951adfb8d3e33d48b782047fe38e8ffb784df4b1529aac997ba5cbdccab7d1c74a8dc9024faab9951be7bed7a28f153959d29bac182f274b3ef3cef2262b4e24f8ac789c936e4566b24ea7cf4c96cc4b353e73d6cc649dc29fce9a79f7d269be07a38f956db2b6779f3b4d56ceb35fe79dfd7456ff345918763959dbe559a773b772bd66b262620e4e16a74d96f61adc5935ce4d96e79dc5dde62629df4d16867d9b2c6fb250df2ebdcbb3bacbc9c24c6761d7f17996fc9cac9898cb4c96ccb3ec3893158373994ce6f3acec73b270340fe72c2d9c48a44c9365ba8ccc6d4c323239ffb61d07b56ddca6d59039cd903c99b5b6cd789193c14a35b0aee38954ea5823939edc32190eeb664e33b14689846d9ae671329321757246eb4ea4ac636fa51a988c87c99cbca8b343725daac13d459a9b8e8ee9c4799a0e1d67f575e8d06666729e43c6e7e876ec386bfb8e1d35b2acf49cebe8b6ebc072e438abc673e8e4882519f99cef3891bee3a9b3669ed2a1e32cee3aa68ea7ced2301d1daec6739e0393798ed6d1d1d97156f61d93a5a343f29e9a1375567794f69cebc039ea33a9eb38eb741d3972e0f89cac1cffbc8eb3b6ff2c9913de64ead373ae8342fd3838b739ea479d453a2a5ee73b6795bec33d374f9d557a8ac33ff59db366feb3e275e4b8b9c9f98d8edf9c55e3377c16f79b4f1b9b1f67b2509385fa6f83739bb3badbf059d8e7739c259f8371e89c955d67b270e83c67b2701c07e739cef29e7396f69dc9dab1e3e164d94c96cd4da6df4c564dcd6d26ebe626d36dce92b9cd64d5d8bce6ac6efeec0e3f7cea1d78d464d54c56cd51efbae79cb53d67b2c03fe72c6e46d91d3ef8d459db1c6277f8a9c9da3191601ddce7646ddb63262be6dc3c7796361dc04dd6c6fd66b2b677dabbb36acc1e76877f7396ccdc6177f839264b47e638262b67b2723ec3c9ba8de74cd662a10a1a5e8449011896b8b2aa71840e3461043274e104568eb0b252e33f716767e6de981b77f636e6e3cefe34b5dde1e3a06afc66b26c665e33592d1ed8200b5cba484105183c58d568a160034c50428b25a0d16505ab1a67d598acd20469a61677f63373e38e8f5953744f9a3567793388dde19f264b6622c12b2bde6326ab74d344a26765857470b23cefa5c96abd208b19b2bce00c33b6e08515699b00c6062e500205676881c68a741669b2b2d9f3cd9ab8b3f7e6c69d1eb30ea17b3987f454b23bfc6eb2b889446a65457e9bac1c72d0032ed0c00c31c0c460a54d24beb2929385186e8005138e2043165656fad959d96461f3bbc3675d138c3b7b3937eef098b587eee34ced0e7fdf8a5476340d569618a37100f7a8034dd03da2d7bb52d7edd7b3897c9fc32acfef7e5a55bdd7530fadaadeac2c1b04c10b5fa0a1a19939cd6b8de73064c8a7d8d0210ff2aac3bdef07d02ad4c9fbd0c9c8f73eb4aad2ccaa813154610863989999b9f9cc2bcd0310804f29d1000409f2293634c86df8eafb1d5a753a9d4e9f72839e0ef4bd035a556766cd400bb25842166e6e6e6e7070705e7178fd61830d9f62436d38fdbe00adaaa7596fcc6a63d69c594f02f85e02adaa3fbfb98761181156ca10860c4354e1892a57686868664e632367d621a46001982666666666724eb36641188110ba70f33a7300bcd21ce7e6e6e6f586571e20403ec586027925f24a430d357c8a0dade1b5c6cd67cda2f881152e6059e8000a60b8c800431346b09133ab148314c6e8c2e775e638bcd21ce5e3f32925eaf33ae4d5474fcfa7d8d09ed71a910b3026b0417c811668dca077c0022e78c15e7042972b425e677ec32bcd55af35f80b26364002e6001547605a505c91052b4558f12589287ebccedc86579a0779ad914411b898800755b8c005ac25664002301938ba821745e0799d3990579ad3f05a6304618ec0821b4c70b1042b368608c1079698012ab3c11423e0418fd799a75e69eee3b5c60d36050caa3006ce8d592f1378390113376ccc2aaf504513d2b0819ab5c168418b2b765e67aee395e63c5e6ba06e666d1f9031022b3738b3320ba208c30a38376655c1400847b86163d622b4a8a00543c0f13a739dd71a3650b3b27260540230a06e66d50019a8106608352e4454e30667560d182561042e682e4444f31a3fe1dc983503590c21892dd4a85183e6355e4f0f5f677ee395e6f3b5468c8d5989c8028d16844143434303a266cd725005259880ba1011aa7433eb45052dc420e3e642443747fdb4e1cc2ac50803092a50a807b36e7c0e6d12af181380fc0e65b819cee36beb23dfaa1ed0277bbcb63e1848e54bb489d4b48d535eceae7b4ddcd9cf78a74f8614533281a0a9c42499efe4cdd474345c8dad46b3e96e3cd40eb331d485236dc41b43e89e3be71eb30004691f7b5f0b6bc299934c0c0de7794df7bcd7f7d5805180fc282429b6e4c5f8f3c2e5d947c918ed77248f4179d207a44df990ee65e903925749d27e077acc02f0b49abc8e718194f1b805209f590032ed9f32d239d4d8ebb88d448aa0ec1f5ca02520ae54d00db50908e07edfa23b3b2edc503498782419cbb55efa6dda02d61ed31630f338346d01f79d966197b69178a28ed42c4c983060a0cd8567ad00955b96678f81d1f1bbcaef1863eceed27ed1554923a9a7d7a94d498a558c44bbc676483c24a993215462a49ea82318ed37ed591b40b999c1d0550659431de1788e4b6cb4eb4e91fa3ffd9a668e523ecaa945d49148e399c6591d407bc62f1d073a1f6c418b9aee97a6ab4d2b33874da4449a8588f88deee783343292743f1fd8c868157dd8a35564cadd7c44b7cd1de5f515d9281460f7bbddb849b102945fb5731f907702570056f97d4072c81335453d6ed2768a9f002b48bfafc84655003e01568dc178f003aae914cfdaaadb85f6390560c7531c7e02dc7726d9bc34a4daa225dab326a13c23674be8b8b9e71d671619a453fbfdca7d3ddd479f3502172d608841088ee86203ab960cb2084307300823085dc458ed77afed5767990af2dbaaf5a972c490d5f72bdacac6156df5a556df90d5b76df4d91a4a3acf2c365876007440944b250eb42fbf114c7c05b1a73a25df31a805c9a153f2da1cf2ab06a1527e87e873a3321690afa05ef70c9c5736ca795d2e355eb74bcdeb7ab1f9cdbb9c7057376ae074d1475ed69a6cf6f84851799d3fa01f930f3f30a3534b771840a7e45113fcf560ca4cf2594e68fa8d10ec42a6a4504b02765525be5ff31af7a9c2010eb3d272995eaf0054b9326465fa11da07802b35ab7e35e57025b5ea5719ba27ba974bc4333d8677e46fdc50f96e3f900b901fbd9c30fe46d8ef8f3b49889b282e5b6a0a57bc23df7dddf7eb81748f14fec41df92e092aeff110407e9523be5ab6a1925848dd2ea83c7f4548d49b3fcb23cf4238faaeeb9dd0f56e1a59aadd0ac84771b38718fb442d1be18ffc15f650a5cacd6b5ec5e635defd2c111235bd43f05bd843a7e4390860a4df6ddc01df6d4cd4751bdf950348475d138500d36d9c01a6db984568f1a10fbe8878d31900dec66dcc22fae077c5540b13c05f0230540fa6276057a6332092910526c2acc0778d0a777513eeca26dc55cd529cb0872a564aa7f94fcffc446b84bb628a13968e0a697e13cedc263cbd2694798d30e608d8551599c7fca7ab980e1e043b05863bc41d7913172a1fd385cacb78a1f2a732a8fc4c284f235fa209773513eeea14ee4a26dc554cb82b53b82b30dc55693fa01e7ee2ce07c09a4ec95ff3d429296f780b904f0abf7023030164f9d59132adad413174bdd3d78670911a5293e242d767879f9ff5e9e9599f7f7dc0b8c33e1bb92c17364207762af521945f7be82e1794b726fa3c157d7a7627faf04a5e5876500bb3d0db141f0bb54df16e6a8f7a0e523985a2d0a6422cda5452497b66d14e9d8a07a3cfceed9d187dbeeddf88c7c0aeb417464ed017e10c69d0d6a1fdcb8b5d941d5f6a916793f86b97085f765758f9174f2fc6eedd66e5cb63b3f2bbff44166251ec5d58af677c226c3691e7cbee0ab3103402b7576fbbbe23d7b759afebfc26f1dafb03e250865ea7fae0e9c28e615dfc8e5cc7666d127f3589c7c2ebfcc94be95de1528fbff8fd64a8e9343685aee346ad1a7b9f017b9e45f0f73d8bd0e2037f5f441ffb2e86edeefbf143e23e48a7624ff4c1e6b6f67c1f96274b8b9c3e60efc9e26367f5f7ad558c31f6742ad61c687c87ed35b360e1ae7aa2cf7b273ec615f64ec518638ce7af872a7dceb2dd8aad65e956a77650809c179de2a253bc2700b32fe6f109c05eed0392df2ecf66f24c2f995139ab112aaf581e1180d93bcd63f00848fbae2bb26b03c3261f7e00a6534b6b878503137d382f5e3a2c4a683c83cbdb6b8df60a5eafdabebf84d829f61cda0493df66ad99d7dc63215746c879f980f627c6b0e8a2fb9f6613801d16caefb0b46a27c7a5537cce0bca6727c0ca7165744de5120959d27ddd735f3ac595d1297e0da0a4cc95d12aa6bc4b642f2bd60bf7852ba3550b24e7822b2f8b2e8e0bea88fcbe45a7e818a31d739e0eeda2f43af46877791d82b4c332afc3e5423bcdeb10b59d0242370bda6d9cd7610ced3aaf438d769ed76110da7d5c90b492d761d30ef43a3cd1cee4755843bb18afc31edac9781d5626cc5021b43b1d7199f13a441da992ded09d4e4e5cd0781dee16b4ab41337392f9bc6e71482b04dac52d9400b1631d1663f35ea428b70cba6fd16e9500fbfb152151210eb357a01b05da655236c56615a22dbd2deaaeaf0889c6d9b4c31d830a2b68c75e1a3486cd9b65596324d4918b625f5a99627388c6b963c0600b7a6df4421de92f94cf437768d77c7901134b00d6ab0cca472161322edac933817d479ad605640c4517e535d498b761f568ad4e964b0c64408bbacb341280f53adab8f008c0ec4318edba21d40b8c7a43177512832668516fd12d8d76a4a312155aa045ed05e5578e565e02ac35949700b377266fc39ddc0498bd45bb186fc3218e3a592e743b25e36d78ba1375648f1d9bb54b17cadf39246975b25c9c2c177a5d415bb43b791b321360f66e4f323126b044fabc991939139bb7a6a644b15993d0788e76dae66d181e81769db7610884769fb7a18976246fc38b76256fc39076a0b7e1d0458bae6b0bcaef4c197649199b7939a61de76db859d0ae43e980f29986b4e32524ed62f3c68d98e7edbbd3aa04d803ca8c05acd751dc8c745db11db76919767d32b6c74b2261cf2836ab111a3730941f86340beb75c5185378d962147d960a36c8a205540053061818adf8dd95e8d3802f64687125064720d183159f03c39d714d214febb5652907a655fb6ef3580460bfe33c066b803e7079b64f28005da0457ba6fd21f1e8a28e906846775623928b9d95e9a6e4d265309de2caa541292643ce8c4ef13930d187f3e2a5537c2f94bb48010d318a3006316cf1c0727922066788810355cc2007f2ccbfa0883e205f532cbdb0d0959f9148e5e3fb9d0c9b76ec5d9beaf777e4a2f1f19abb3c1d69ccc2451f0e4ceff059a3fc7160f895034399268c2e625839c216621066c53736c0c10978f0840778c0c48a7f6d893e4a9c188113a2f04215c69062c5bfae883e53ac408225b850410758d2587108409e4d3a28b6ced1d25ddfae55f2ab5119ca4e5dcfc2eb1d83bbda70a9167d50323e3b03fada2c427b3f9b456829227bfcae2a48f7deaf0f117db65fddb3702fead41525fa74930352d2a90bb5dabc7767c0766e16c17d7b378bd0e203f7ed4574f7beab2bcaa641af779bc733cbf79ff68a3a7545893e4a7ae7faf5558dae36259dbaaed7f542af83d76baeef75edeae6c61d6ef6f0d3fd6da7ae3308c0783d7bbc15eda81ee244618f6fad260a9b18d65a5d7d45320eb20374df1f10aa87f8a53e4432b2d084d1aabf1f0a01d9e37dc81e274b8b3c2b3ebb9c3e68efc9ea6bf228ecda779585286cf6b03dfbae3a06a374ead2422dee5cfc0170884e5dc76651a7ae5fe72a2067ad6e0d092f71c7b8c89857974ef59300ab768d41fb3fd18757fd1da28f0682758fc03d0273c6425fb909aabdee19f4958d288adfa21753ee0048f7678944da97672c911b34228047a0bd4b18da5f5768a72a3741fb5a7806ed676c4477883b7db0067c4d8ad6d30a2e18daaf295ac1d5864baf56cd533db45775480276f5d3fc0150eeaba45e645f5d74bb037c0fa8d3a9f6b946755e63e4c737897faa5539dedb6bc9e635877b25ddbcdee85e3fd4ab0defd5c379c5a1b176365e51a457eec6eb4de975cb79b5a1f1da12913fbdd680afd95f6b985eb1f09526e6f5a2f375e6facceb89cabc461caf3234be9708f61aaf269ad79825923d1e5c22358fb3e6b88e7739421da18e07c0d3a5f5f48892a8e3fd94fc8074cc05e373844be3db07eca7663de5a9133218cf488055d2530d4e3f6abbc3338255a4517c6b1a08d61a1abf712e781c337cce0d1b38a81b9b9a1a3433273041d0a20994c17899988bc69bc08cc697481c8dff3a1aef751f8de748346ae12e4f7c16f2f2c463612f4ffc15cae58997a1b63c71365865a56587f0451834076b3fe8fabb3ed8ab56419f8d3bd7e3f9d8ac5acdac3571474e1fedb3abde14cf9a03ed07a17db93ebb3b2a6c0a4a3c610b347ebfb84759e856a75e5ca4c9072c9ce8d452f0b47edfbfb8883efc2cd8b35cbf8ea20f36af2d9d42c9ef77c521763e03aeef2c6216a1c587d5b2c9ebd47574f97a79417b77e4b150c69925fb4a86d7169dea5fe1aeaea3e8736de99d7e36b777b6d07a1dd1feaeae6bcbb2c9072caa746ae969bdb6d0e5020a33a071061728018b12562d23295e70851a58e183207c59b5ac88c00a3a18c2162ebed062f5630632988110c2a001129c58f51510255f8496f822f8d88bd0e2c3f57d11d8f928f922f6d78bb8be47c98942001fbb0f7cec71fab0bfde2b5ef1d743152b7cec56f6d7b903b42fbb2c111c687f485fd78e402e68efce461f6c6edc915798face47804bb9de0ad8ef83f7010ba34e2d4d75aa1fa74e15b0cf1c00b9a00327c01082097cf00530abbeb8d0c54125b662635858406bd52f22de4a9c1dd061d5ef49a539e7480916340b31dd5fe978656d55271c8d97ef8f87ebd7cc825d7e469666b9f21536a9702b2df1f143b251396b0f749767a3cdb42b03f5ac2dda1b497501b4b4bc44965bb1bb894e1a808da8fc78002936a38c51ce1899896ebf2d54de83824a1ce4371218d1edda470086ca7f24c042e5b577a520745f73a05bfaf7fd698f739d5679dfa75ab57ddf33a4555b28af2b5e19c7854b334dbbb6b4a4fda75148ba63f25d47fa7e06e83a8ed43d7b77795f7a79b348f6eb17f72c647a61bf6665da79def6f120efcd26d8ab3c518b6ed73e1e885a947b93edf2ddacdbb97961e16e2d8a85dfbdb0854272fdfbf5efdcac2dca9542ed5c93eff27a29ac52a54a95d28fd805c2bc3a6217488d749b75f5138558b414ee4a8b40315080dfe387447e7bfc8e7cd7266a7b77ecfd1df9266a9b48bc67f79e5dbef3ba269e01daf3985eb36ed7b8a3ae2fd5be85a86b16c1ae5d9b4bb96f94bbb62659dd34edf1d714e230d7230ff2daacd9b773ccf40a9952e116d75d13ddf200f967a2cbe93266022100aea49f47921253fa987a4b647777dfef8f07c97b0f6848eb2cfbae04eea0b27779b0cb7398bd1fbf22fc3db744b259cf5f11d64214926cf239ca57b77d0e65a71aeb637beee3a19bdcf2748685bb3cdd46d0bd26d8a91d54ce5367d1c5c75009c897348055a30d264106ed7bad0a999ee8eaf450b74248132441b147cd738012127ca12c7b70801355a22423a65a85c27ebd87eb574a4910adaa35cb45015ac57b54822de84539cac546eb92f1855eb4ae167cae559534824d2fc61eb1eff28b30ba4c755a25c46186f64518c5ce1f9224b48ff5977beefae059e3377e408c7d05387f45623c671aa0d85945144145a342b16fd75601fa4db459b122d823927e9c457018df71732389676c22e19a5665c78400e5d90c74c790e20a78da23121c512cbc28d8aac57ebdebaf006630c319ce40f70bb33ef658c861e87e46eba38d8ca0fc8e60b6a34e88697bbfde2111d36d36d926e01e9dc0095a9b5ee7708897e77a914685360cedbe5f11ef1cd7f164cad40b2bf6eb5bb8ef160779ef0453d0f8ed1c56bebcdeafebf6f8fe9020f1bebd931e7f46b2ee5be85d7e48b433cf5d1efe4f7b61edc9cbc3dfde85b529ef372945dcc2b8a5d0ed94fe16f45202bd8cfa039202360de81eb9c00aed15d03d82a20a3445f7080a1250be14306a41f7e88931286f41f7080558a80fba4727b8822e9126c2d1e51ff2a525b266a0f1bb3e18efc4ef972fb19f2c41589ea59fa43f5980b03f96ca597b562a544ad30b0c31e56f270eec3c6f897811660b2a54a25234ca8fc71887a54b6bd38ad1f82e7ad777a44b030bad46d2c07204a355082584f085172aa48432181550212a245a8ba4f0849a15d05a34c50a3a29d05af401295cb4122de1063d76c08556a22bb8503e7f473423a323f13bb26128fffa8e9c0ac93093b3327f48b0f7ac539041bf22f2d77f62d716cd7e8528249712a83c1636a9442d2a9f5d68c3840913d6566764d04b0a2b6898859712688739943f23973273cda24672da6fec57d8a427ea88c4260a897c76ecd7f92b229fcda26e8fb274a1454daf59fb52985ec7c2905e6148bba8eb2f186db45b000949a3b85ee4151719d897651cb80c32e8bed967577b8e71904674df655efc8a2c1999a6691ad69a16f94a91f8dd06bc507e7696efae70d2e68ec326d9190bef59c8f7c2f819c99064e76c8500f7480930947b7606807b94850bca51ef5d173dfe8c68dfce85757b932cacdcb37759883a228d8ce8774923ddef59d8f4fb4f67deb5cb537a3f0b492f8535935f91eca4f9fe8a6407ff13c11085243be9d949334421e168768e66f3667924f6ecfd0e8c3ebb92cfc253a7e44b27854b97a77acf3e1e38eafd6689c85f1f0fa8e591f7e60d8964848db298fed360f4314dd93bf2b234ab462bd8243bf79a7d0bd0c282e338ee3fdd498fbf22fc2c7e47b2734d48cb235f5a1e6944e5f2c822501a1941bf775bf7cdd27779b6d2495b5823ed4eea485bf72f1c2295bcff74c93ba9fbbc6f9d37777d74738b4bb7709f55c626d8a9f849fb5f674974100025dd2ebcd003088017dd2eb0e0b28b030cbd48e38c8e7b06fdc5599efe7ecb9375a8752afb7e211b592ac461b8436f79b23678cd04c8b7e1ebe127ee28a105f17a044dd4e8f084ecd091daf1543c767af8f0783ea0e5f14103f7784380f4d4e06dab96006ff07a891e01d84d803878bd440e1e5fd71580dd8d2b375e54c6b031a65778ed27c3489b12f1647843d3ed54878327c3cadb4c805adc690078f4030a80b700d84e074ff6122baf97e077dd36bd62bce2526fa3cf156d65ba00bc5d8e3691595d1922d33d31a1cc4d61ccafa456a6772bcf145ea9599962c22b5f99a200bc6d55bda83c472a4d8fa609c61d090454a4c876465a09902f3b231f50b7aaa28e30462fda1929b51031babbbb5952be3c27a1db567169c17ed797ec90bf5f4f2f457a7a227f8b60ef0e0143e2cebe93f13ad13ae40332a100ac1a2d827d46ba52115e1e3ef750c58a152deef0b5b8b3d967245c1e7eb83cdae61929e245a97d4652d54477fb8c34a9b668f61901c112028c64549efb1250028a81023cad1be5d74dbef3daf33ccfe3d548f233323b6e99e348d78d60d7e4b8a87531e684ae6390b9232e605bb6a0b11730745b3524c461e8f5a2ea615f2e362e269b9fb8d3e7ec0bc57e855c2836b177517007c0ca5eb25ca959d59cbf3000aebc0a9bc3959e554d006adec79c58223ad03e77617d86883b6d85cdc2aab2f79530b4c71006c861800c76ffe9293a05c451fca7b1f307744269bf796b85d2260a02a7d3dc8799df4c9616ed33d7a60fa7d39c66b248442081163354118591d1eaf4d6cae635be5dab11da68356cb69985e63472b217d8642e9a006aa7993045fbac0570573c051a60418a131819ad6ae24ebfa6565aa47094bb0d7f0620bdca3bf98e42827dfb36bfb40343a69c05b072144d640e1e0be0b90ae076eda04c184b60e908768511b40b77f9e6de9dc7e85477612edc9956e6c2bdb668696639459fd3642f4c31ee421b3b33c51807f012fc7ea56f21c63f402b3ab585bf74aa04ca3016c0989b2e2ff34eb62783cd98b0142eedb88c96973926fb32217fb902286f643f24580ec250d97d0b3924dfabdce59199594ea7ff347f699fd399b29732b07bf9f60e63ef1432175d006cf2165c0698430fb6a043ac0056ee01ed730f5ab54dfec247ad9233cbe9cce5c45cb8742ac634d90ae642fb5c05b0b62a6f3180e41fe0b789f10ff03f9d7959e802dd5465300c1581fc05da5ffee104dc20a47105ad816e10d2a842bbebc364507ad3aa51f02038ab138f96bebd2b854c05b0f4d27ffafa906c185aba0c398a5a44b753b262dfce5f11ec204fd1a97ee8c4a3a5c932f8029242294ccba852e588af6afc889e15cd678e7d48be893a72ec0a23ba4d2d601f909c58d8b4cb3cf6d2a92980dacc72ba17b297900bb90c4de3273ad59741969a3396e85333c14dc35e23dcb5a14a8a9d26dc0552318a7d26dc1582fd0ab34d61cfc26e53d887883ea5ddc1de39b406c5b6fe115f71192da4f70cf6c204b0b29721d9672ffc85cb686c0e5d14c3a6932b68515320ae24fa9ca6d73bfc3e51ee891989548a46af7759286f062ac312fdc2892050195eb46b8f0bb48bcd72e345e2282c4f3f93f40af7480b2a50196e943f20f6b23c7d9602c8edf39e2e189898a69142b717181adfedb903208ee46289a868d4a18c5dd7f43aa5752adedb6d8b02185324452f2e62183f01d62b8aab4ba7e239f6025690c61d68768602786d893e9ad6f5da7271e9543c3f01ac5714dcd4c22149ebc585c667a193219e13c02b0a7a45d1aa292e192c918b0c709b9a36a5eccbc3302ffb0a804d6d79f81718ba385a1a6333e856a7f6118d59560aab68d1ce812846469da6bde2d414ddda1339566d671fdef2f58972795d5829e42f5b488fa46b738b9785f21d06d87506f4fda7b332b4d02aee114c77d2ac6c4629beebbc2e5cfa5d1e180ea1ed79dbaa4b7a5fb8d48bb4fbbc2a5ab0ebddf60171374b3cbb92cc5b2b3093097b86947ac0cbbcf498d71e1ac19005ded458b47e22a61453d2669652696eefc4f09129e4426687b8137f455bd1296e02c8c597c25d31f37eddd43e231ed596479b594aef48dbaacde3baed9afb8e64b452a117cd4259a54aefc467a11666291d0c3910a503bd2c0c3fa0befc8c645d85c637d14e740acb10cc04b0b17413ed44abd603c35d31b89d9f006b8a6eef3a9494c3002b1ff5fbcbe6823d872edadb7492e5ca57e065408b9a9700563e3ae22d5ad54d742a3e9eb9681f70b613bd1323cd6663e954a4dc05acbda50a169476f98bc6b715adbaa255d763bfb5025f41baf5cc627a6b25f36ddbdeb34418689b0b0ea1a6180f864a007775d3650ebe6a7cd4a9e8058defc0705706a4d9cc02fea7b7e8546f017b4bdc2213ee0a0c3f305a92b0031e6031325ac5842c2d3e80374d168be0082118adc0f9b813bfb1b140117d7480b1c413a8d84017aa28c22abea7883ead2b27d8828c315c21892844b08a6f2cd1a7f3c011d030820eccf81284557c3b117d648ea0c51738c8c1152f3a58450c0450ac76a5a55fdf583a159f04b036960fe87a636955636915ea08a38ec8eb1795b47f5a9b1d5e94bf04801cc801c35fbfaf74953e475930609cb4ea9a710a1b28687c355176627db867c5de5da1931088209000ca782f07b1d0782fdb7f9ac13e7be9a69798b197382558458bf623bed2c279692c8d25eec4cf2e0bc3ec95bdd098cd6db2974ec52c0bf6ec622f5b687c6f69d5953d62b13bab5a6519c2a6965670952507bbb3b467cdaebdcb422ea3535f3a159756f6824486f6b90cec03d2e6827d7969d597f6e19e75086d2cd1878fe24efcf6aa55b0b1d0f8dd4c3e609144a7962ebd0cdd2cca2004ca47d16757dbac9a362b98cd5a53c407dde5c92af6ce527a5f33cb95af4a0fa27d4a8f07a255f251be14cadee93ef21a0707f1f25774b25d286bb428d223dd1176e004dd2eb14bd7ef4adc71bb6c978e728a2962949794f2c2aeebbab0cc0927300cc3b0acc46280555e41a356068dd189e84473d15c9c71064fc1537c402c0658645bee282f2cd3da48ff3243b75ce8f5eeddf655127db6f904d81f10a63d110618bf22910e5db60aa37b04b09e5e45cbc3053c296995f6eb40b42af67b5a257ffdd72f2d642b3a753d867c45c83de8d4f520edc3577ae73a0e8e8e8e0f1f4182d07a7ae55073a04aa24f91195ca553d79f002b1f15d9281f75ea7a0a4099a53a75e974ea323202785d7c446b7096c8d2ebd94d4c0a4027db856acf320986d43ad558a67d05c83e02b46896cdfe46f90bf0fad2bec75c343094baebd18bd3fb77a20158a54a46795d525e5ce3a4e0a6454c8b3bad6920586be4ac97a7f5751daba157cc302c4a958c1dd6a6dcb1f907df6bcda355d2965dd0ebb2555e17c31a68b73b207f0468d1386b53d411d4a95371468ec6e9c4a318ed22f746499273f9075fd2ad0bddea7801d6ddc20ccae72f652d11a6fca201ec50805635dde81e7400e380d11dc309a860b4aaeb85aed12a0dbae7228055a3bcdf42f7dbb9206fa13fad310e4bf91ce3b037ea8263947c052b41c9b7e8e932de3fee9d967da34fcc4ddf56954efab68ae633608dd79834e1766a669ec2ed94cc8c09b753a659190adaaf0937ee80b33296d2dc4e91e6372be8cdaa75b3d670b382dbd46636b179cdca5762649a965abad5a998118df724d8718859d4a9c84980ad9ae8c3abf8ee925f30345ee8519688a4f1d7144be4061abf68b0118c048def2e4f8692f607e4a453f1d704a2531109d35873e22a98518bb185f2bd4ef1a3e814cb80a7e8147f871ea24f4ddce16b20585373e626aef3bb2be4c7104bbcbc9cfca535d1a787b8c30719aca9a172156b987987b8c357cfd3043be5f116f9a55b9dca47b177bfa0fdbad13daf0fd0eef449b46390d90aee014fbea20b5b41fb0e50d2a54b972e50548e227b6527683f9301ed33145814b4cf2146af39056d255dba74e972510774613ec25a4aa1db1d20d32d94f842f7880763d022d03d02c215f4d42a795d0646347e0c1a675153216a688d626464448b6a68896e35d157120ea6fd01528feebe93024aa9a191db88a47156ee382bf6f80b9b4491325d244d99c65f7d9dafd984a9a44d98cacb4ed12cdb3cc516e5ac63986e01add575d40110c865194b0407caef592224cabc5950fe0d2c753ac53e66aa873f24fa706736aa7b86f7ba657caf0ba63b17db99e3f4b42fac72754fa77848904ef554894d0470cf85a81eba8ee3b8b31570bfef3f1dbfb08d283f66c7b66b0ad8d5f59fe6217187b570e3c6c7f819df8b3bdc1377f8d42906afad253b2343b73aa8888a138580aee38ecd22b073d8b91791bdfbae503d6447256057d9510cc09030e5f30714cf3d0695e7eece19f97ad0b4b823b9bf1eaaa0e25157ccbe9d0118f60d7b11bb02a2533204e533b95a65ab3909a253f2555b3058ab5b3ea149d9b2a38c12884f424698f68f70b4af0fa827d8298961b119d3bcd075dbdcac814eb6684a7e77e557bec96a9dc2a4bc24b6cda579b7638c314a23ae48238d2964eca8826ed332ec92dd732f2d24c76e13f06eac751631795d526ea8231cd1104646464654cb628c1293cbb3f20732fea033eff107209f774b8392aa745c4515ddbd85eebdd07d16b1d03dd647747f498682ee631555d41a74bc03adbba1a0fb0c0cdd6347747fc9b80390df3be8eeee65461dc962d0e303b0d6d0aec1b90eaa87ed4b391966e9ae459f6c563962c86a7b37af682beedac66959b2c7b04641c5b3f66845447622b4db405552c6fee3513b7bd01e670276a5cd8d3b54aed6d5b20835357fce05768c60496a598c327694524629a5945276dd1d27eb40ca6b0aba456e74a1fb9fde6020a594584dcd9f7345b024a59645197be680b178bea49432a3712e632159aba2e3362dc32e191be452bf7bb98e9445a125c718399a2064292e2fcb962766d98c52caaba3c4f68a987ca472d629f4c2a494bb9ed4564a0c0bddd6031ec41863dcdd0eb14b6eea749219c2dddb4397ad30d22d4785384c9187836e23006e172b7082f2104ae005c5423b078f2ee3a0bd32f39bbffc83999959fb3565a7b450d3348c997972b70cab138ff2f7044ea8bc2655da2bd6d81bc3e666929b434d36cfaa512c9b55a37b4d8ef237da447372a2ccfdead108832eee8d60dd492f46da5d9ef42eec2b125b88c3502c749ad4c115af00f9db8fd1687958723442b743478eeeeec631c3e7dcb08183bab1a9a941e313dfadc59deeee934c8c092c913eafe3362dc32e199b773745e29629a3eb9a9a3fe7aa31bea5e6c3bba3659137b597b1670eb8d431e66031dafdcebae85676062e1c5cacc5c8e242f706710bddb7e418e3c61d743600f9d5bbae5953f4baa6739c13d637819cf5ba9ca4e44f1928a59432c6958f534a19e5253962e15eefa43c662485b194f29252ca9304a594524a29a5c41a40352c98c1b8f3836988717968dddd8d31c618d90795e7e5e971f1c076b218638cd2a36207b77d40fb8d3f56441db4c618235701f273ac0eadbbbb1e0e5a638c11cbaef30cab31418c314649f25eb34ff580f1d7ab94f132be898c570c698d31c692c736883146d0e318802c00a5c98b33c714734326c6c649e603da2fcea9eeeeced418639451d49035357577f7c68606b5df18638ca8babb8bc3653d2a34191b5eea3d436a62726e989e03dee3e5893528cd50c707489a5e4d0d628c31e2f0a200efe9c41863ccb1bb3ab61d5ed4525e94d7b3dd2ab56e671fbf977f932e72470febe1edb7fb9865f73c228eced5c393d2c9102aa5f4e1c57bcce36d517c8a5404290d3cfd83068eb1eb8931fef062ecf941038f8f1e3c76523b74e4d0c131c3e7dcb0d183f10d45e8e41594af9541f9597482f2b1e682f2af33285ff214941ff9cd5580ddbb5beae6f746da6734e838065ac7e035dc5dea591d40af6c01bb58c115f0d43ebb6aa395f66ebf78455b69ef2cdaeb1e7bb7a1b61b66435079bdc6631b632c6a2a677619aa9232760c130687f8babb3bc474c3845965f1454db364df8f013aacb20886ee63af7777777757f24a5e9eddaec678b5184ba525b26524d212d1b4ef5b22d9e6794b04e33ada44ae8ee39688f4b66d89c44fa34da44959b644b862d8d61863cc30adeeee6e7577376e948f31c618bbdddddddddddd5dcf051dc7cb7731c6b7a99b99c832b83c7bee2e5dc75a800d0583c1b83414608e188b16ac05b8ef36d334d214ba8d5b687c17312ae74ffb905080f23b823e8325730bba8e3bc5f1f3427e02e41418b12661186317097504a3fca63c6b03688ba0eb4a0cca2143b03d3a4ea738ceeb3e20f69a243bef034be0694f25197e42e63473024f383520cd0724754ee009a706ac7902d47a7b0a8d67d0a371caeee606f50181db25053538fb01d960158035752367088de727c0585394b753e15764a39f73e6dcb081839af3c6a6a6c6a49939cd3965668c69ce39e70f92cc966eb9a3bc4ad811987d4698728ba7d4345273e9f8d7f9ea5587417a85317f25999999f97bc45fe83a0f4863ade307f40179401a26b1c87b43aa2dca24e8765552f6ac3586ab9232760c1306876eda67da6488e9860943fbfbda6f1d68cf4ea384a24d831b9b58236bd060dc4c76d2643692d79c3c1a1263eac0d247921fd8938a3bab79606792dca6653206f4309a8b47eaa6e6c46954e2b099cbc33e6c17cb058d33905cfcf40c9a511cada4e51fd5a3aba570503736353835b01c40a7628c1d37e3b0e21f5a403e2f4f63f2e2d131fe3419390c39b5dc02884ef1b5598498944de5ac4234ce9d2849544a4fc666179ca44c494f7a5a4aa7c747a7f698c73d390c69d6bc2836b627658aea746acfdf2ecfbc649451c618638c35151be3378d6f1a675d003d5623f368366fbf5d2743e87e67b61327d3d5c4783aa9ef271cd307926400722906356f92d7a9cf84b3c3102a869c6a3ae5c100e48335344a1c9a8edb7098ca79d2366db31a5814bb93ba3639c5234a6b0dc7d3a1fbd614345e869c05e44b27db257a9daa279602e44b8d5f00f2f735684a54e6641ef30dcdd356155ff7b2534d7669368f37aef338f3b08b548acddbc9784ae815a44fa8e4e956c863a19c441d63caccd08c268004731540403824180e48e371a249de0714801198a2484c9c0aa3b1200b72180521630c21c01003084286c018e10600791dc89d2509890a5cff6e97debd4071d54cd3e3cd9430493078d579552cc9a67f2718ef8071f81e77092537b35aab78c60d0a77b0014e52538ce35525e533b00c8754df5f03e9852e377e773bd9905ac41f28848402f14cf84335bf94e4608212b263c09eff2047502b2b894193fbbb47c596116c8ddb7f67b45398a242407eccd60b973c5dc294648e9ca080671e1adf5b0760b0b13f336e06e681819ad10c41ea831a9ecc3394a504310ee2b105185987f52b8879f98b82450385073df563387cc1ade3ef79d3e3532b8a74b616af185ced04b1628b4d7104d2db5dc4e7ba7d36ab9d9064072ee4fa1538ba191e27f0ab6f3778f48c477d532424444ea7579f4a73e562d5e24bf6d1509d1ced29dd4a1b4a688a01a4fb3b349b96e8bf674584ee93e4fc08f395e26b84816e917db2749fabdc13f35fa44ed13537a6ef564fee6063e921afd15de1bf32a1f17c3a1e30790d366425aeffc2f8e091929531ad42679c9471df5a00a8b97631cb46fa2382986dd4e9f3ef758e11f9fde940e32f60c68c632950dfb9281a3cd2cd288aeece0d5cecf0685357bbbf2d8d9269caf5ad057a455d7c3b86e329d10f26125a570a7fad0c0c4a9d776dd545ff1d83f51ecf9d51c0505970ef7b583a4b43c3177971f501669c4f5fae0b01a4e95b2131394f0731e725d371578c1e09ddc51958037e0ceb40e93ed11c43d98471092ea4eb0fd16acd502d3d08d42814c908c3a2f40491e7946d4a7b70075caa1e9c73a5e115404165edb883a45a22a6114d2a14af8a6edaae2096d57f7874d0ed88db8614d8735036e1a0eaa0a9f3fd334f643883f08ec353121005c92cfbc42d24774a4d281cd79a220f10b557932cb53f55d782b6e1a04d6cd34cd944a4d54ca1741500cc09ab09ae27e4aabda847571b5afd2e79b6ef3be082e06e4aab99da1f6698c4cfbfb3b074cf5dd1e556364259c157df24098747af98dc69bce17e32e01f562c5c5bcf477404756ac7b95c26da6f1ef3c008bdf5dd80c36eb1709018272ac06fc390b6f2466f29578d3c85ae0686922d3e68b448429b45a40a3004ccd7f54d1baed2fa5e035c99602dd73e67b9ce84b69b483dcd3b017444585390b9294e54904a6c99000b519f376ec1d4685684c265c8c5211effa9c6ec34b048a2ba10de4cd581c5cb7c7b49b822414f5d41f7a3f89ea5985bedfb9de4d76d8dd3a94c2b5be04e0981c0d6b1a71809d7650f6719127eac39b8b708da6dc63a26da5221a8a4a10955cb2d73734bd192485989a2c3d22b665a49461c3298dab3662c4fdb73cb4fbcdd80cf81404324bbd1793d826d5804783bb65ef891426c6b24a90990ab249c213dc48418b02f85bb130a748f3787031a970bc0c7a36b02a544c3485d834d6faf5461d1029aeff1365f1e193c1b6c4813f741a2f0dcd182c01e3c9d19da6b1e314cf37dc75a9629e813360d40570101772aef5954302f9358048d850c0e2952420e0742506c41a15ec1e5aa6a8d26588a739ca71dacd851b00c3f397dc086057716a27e461cc91bc4c30b5788251fa0858324b9f820f1f717ff8b6a6666fdb00dc2e0acd1926ee8f8fcc425985b52dd5a93682640885aebbf93293e07bb07f453f7a927b7fb5fdd60b4d09aa24f030ce91fa3c3831be59c71638ee70f6e7869931b0f21b9de597380e6bdfacfa84e13b39485a00842a1c7370f5cd064bfef54278dd993fee22dceee9298697f9059b4930ca3f4b650b9421596c5361dc5985c5c12ccb34070fd426bb04f929254988e0022830a2300e9a8c4c46074b46f5f43e7a27203e7d5b781c37230b749bf97b04c7d6e4c736575a64ac80dcf7a921161b5d2cb42c798e7c8d23d86bc8273016b48947a1d225d4508aa8ab84668fd07bc8353be35bd184f9ea1dc3918eb5947a67a52fc4ec789da931d42efbb1e3b54dc54f946e8d33e608989529533413045510261d2e890dbc1e22f89e01d04bf54229ce8f37f7e0b51c1fc114d13b510c351c80cda5a43c16a1304f24b1684702e60bf9186d884504131d0131741f2dad11bce06adffbd5c57fc3e26845a7c9bdd66a5a7ed48b31e8b57cd6b96427572d45fded05e44c866ce5575ddcc212936e8a675a94ecbf3572c8c6d53bfde23bbad71a5a6e781e541646b0551921b8be3fd6f1f7a2d03e8ef15afdc51cd310d6d514e9dff144e7cd4a6f80e9fe21fb99f5b92603feae1b5c802f615fe2fa8a30eab191138740ac02488e90f295ceb82eecf5b1b6bfcd15b1224a344f12c4cae34c493ff4241175d173c7864363789dc09da143544a61e9d595adf92451f99d2df886024dc03172dd9853a7ace9644ceeeba82f42a62508327975680f179a50bc168e8400d779a8792ea15f48c4fa52587f9914c1c64d3385f23dd5dfe60d19c838508321412f4cc0ab67c9fe297ba7e311eb7a081782e5ff77cb99c4c8ab403479ca136ac42276ac27de0fbd23f392e5e3f24185fb6cda3f05212cdb0a65246f108583051bf405f215c7d39426596eca0c6ab7d29572d08fe1a01f9af23e9536895ddff46e6b7baf73fe370aa317d8ff9058d9c1c4d1706bb782ca35c9e1c142745d85e368c4b50ef753c11955e6282012e0e10225308e4bdb846f2196906a6a2bce412ae3b8c85f219ccf14ce077aa9d1dab51cfddb17e44cc39861ee61c0edd45f9d4927b0e2edd13a22f44e005c59166096e34dc0f32d1af67db0c0c35711f5b88ba8a4c4b1bca259c4ec6a7facfe396d76d3d6383eccd9f06a3b8de6c1cfbf60bc7b301af1ee8fedcd9c01471155522f3389583c62768eaf8ff2cf8e08bf1bf886d7578f81afd1e2868a71bac6903b52b984f7aafc46db05407692973488d2a09e667a0174ac312def493cfffdd446fa11a5e3ce98a3a90302273e2128051ce1345ab2e3e42bb975c59eaf8dd4164090a24320a59d05d4b46ff7aef0a88c2e5b87c417fff48d2176f18abc4c08f32f091bdbd5c50e1a801bc4807bf9092457992acbc833f215fa744d116b69164e67d5688993cb7919ac12df8954887c31c1853d3ebbc418ace4108fc16e81d7490cd3078f3d567079134251bbc32c912107bc4b08fd15256bc04ca90ac92b147c15a84fb22f2588ff4319b695e5f233a331bfa63db43144619f4a8be87139de9fb94d747aebde1c7e1a96cca21275abda4756934c36e1601071c8e41b235b1080aa4c38e85eecffb930d4459be65ebfe760f6a77a8beaded5eff74e30b09d025cd97d07533acb25b6909f4518fca43341a32f0efb05e2cdefe178a75a2d01e4e27a2e64b3d7f9aa44adc4dd2f31c1c14b7744d2e3525cc2582ba4b44bdb496b64338486aab537b99749298f467423e79d5c04042528f01ac8ea7eaa502a2c0ee83d32742fd812788afa5ae6eb6753286beb8befafe328b349c107147e4b21d6d6950aad82775611a1a6d99f9b0c09fa235f9b0cccf833d1a706734d0934d964513c12b85f882aeb661e72a879fa6929fad2bdf908657e618e1fb900f9ce0d9c2585c0589ad1aa88d83387f94a0c753327b73c8196bd9fc6940e2773ed439ea4776c3e7c4f4602fe7e7eb7bac0a1203b204448e78e579d063061c1b27e02b7a61ff4b8853942d4f8936f1cdefbafcaeaa177b5d90f8adf1c3a3962c4a0c686b298a873c09c398658621e889baa6066f8b27a80a3a9ae6a0707aa34f2fb82b34fdd5717d34fb8925d1af1944c7cf90d2b7db53c66457b055473bf86a9b44e7bd7a1908aeb7b06fbd85fdad577acea0ca2eadf0673279f956bcc8dabc4ad67eb5c72acca3628444ae88174e9fb0343711a83995b7745aaea61b26d6b8f13b934a19180c12e8dcf25502ca1dac0c89335a59b4a19c4089ff329f88b9a46864f33d7b1056f21c8bb055b3bcea13214324d91c8ed854f33c3fd00561e91a7be3f5f61402957a425460892211dc74ea7114518b81bbd25e887b292b175c6f0d4532c24c005a1e0d6306805f90ad5dd263dc39bb64ad100d97d1eae8c09ef41dcf883c81c1033449cd8df3937d9c7d5ab21f67e4fd5885140b67add9d5972f0ba7b5f654ccaaacc2351293bd2ea044260615e3c75a03444e1bc024f9ae29d25a19564919cd91821474e52c79bb0eea29540b44ea9b127998b23b3ee024378173494b9744137831077539b9d2788af1401f74f1f01e3bd0a0127aba22f0b0827615970bdd49440d290e33dac44e5aac5e11727b7a4990e96e20d47822b41ba68daddca82e629a3bac20bdf518353330f846b2627e3251e8b1d00f0246d43f5750c63efe8b4614108285c249d37c5701d7e00f3d393880f4bffcd854e25dc8a9a0f380f018f240e286e1a196e0b301898182a94df40c3b3ccd9d26621d561ff1440af57a0c6f3e1c86ffb883d70f67e8ea164ba4dadb0dd56634738cb89c8f9f1fdaacb34cab97a14ce9407aab422e1510c3907d3d527d3811c23162a25f108ab0b3ce6f101bf6678a6569dd7b5859e1634641a5351990cd641496bdd85dd201aa8c05a6e3e52f4f70edd892141bedd9df0e45d9b02c491094d1862a878c818af03080973d347c389b321399f1bfdaca36c9899aed2c7844e45806f9d486d0be34f41156a0886c3d192229b66a7d0db8381108286ea91bca4038438e6e967c3e3a71fa0c1668a1f108ee9f233c0c8ff2227ff535de05f20d8a8a73aed649df16fce3bacda616e4ef9e850f8c798763bb5ce555fa50af7fd902dfa6dcd8c8671a5159bd1e40a2dba6b19fe351cfa7461f388b28c688a22898b453796b0409630035ff9c35b4685b10de730744e4ead1e79ff4630813b22a1c96039cdbf0d203589ed3829f2ff407ccb8997bf0b9efdc7406dd962267589467e6190613367d7355a604d01032bb0373ef0b75ceb67fccea1e51057b5980614bcb90b9442bd13eb1f22a0bc3efa60441c46de3a95463bdd12096cc413c027bc9dbc313fda3e5d4c16dda9e3ecec86f6534c9d5d152de6beee95193c5e7678290c4f7f72c5d8154186b693f0148a34a851054dd284d48e173c7b8c91106f1c76529b8a337b849826cfdf31598518a546af68fcd9809c1b99269616d10f12e8106a3f1c8c184be42e8cc82d4ea674e33294ac1f23e82418606f4faa4420949b839e0b1f11351bac82564cbf9fb24c5dfe9b0e5e7d53aeb2a06c154baf852e958b2545b1913ad590c3d9942b7de86acff8f652ff56ab86f59f525a707e97b41351447c54a7150aaddb958d3344ac2be97626aeb29d4f0c0c1d704601356c5d918eccc78208371cd93f0de7d51db060403efca47bc1f0b2fefa3f940e3886108ceb46c284028d8179a221cdfa7ce465256511a47dcf796ffd35e39a4c1eca114c405f455342f8b9ffd40b326e94d1cfa1d7e8896c23426134c9f79d478f9ecc241eeca4a886af66f7bdab898b8bf4bbcb66fdcc07a69425ebb60fbf3c3ab734f3b090464787ac1f607a4e0f6fd2d2c230e0b13d849ce04ddb6db8b4a06544271f8f42d5329e5033ec8c785a7f8199e23568bc0fb0d28d7f686a6cadfca326e68354eda74d9bb8843d0cc0c92f1d4023c0feb08dc56a74384c8ad6ec846397509c9ef7f3dc990d2a9e279bad4401e191fbf2c3c69f8f17c190164ece18cbca632f465997065a7643beeae1fc29b9b3404ee889beaf231800bc2d3f34ab89ae752912699e765582a53b03b4f697d2a79b9604ab3f011647a485c50c079bd1c943b3e9f7b0797e802f9334251accfb8fd9e0d703b6f4541b56b6e608c38b59c05dec585b990aa8f33ab3d49697fca8d908355fc4e5fdd6ef9911a079619a3882fd0bf1ca7e31bacf7023f945b3cd12794216ebe7f53fc95ff36627dcf7f4f4eabf5e389c6eda8165754d93f4aa1f1892dc2cf2baa3b0dccc7b3c5901b04f0100ab4dc3fa4ccc93c16324b9f9b8532e738a8cdae0a7c8b64e654be959de5715fcaea775ab894d1320a335de884eadd2c38ba0d0683dee422a4d9629996d2ededdee1e614232e9db0f5566a69548226140ade76a12c958f7f764467cf8b14a2711c31fd2fd9088e6a81adc96fe00844a5de21644cfcd2c317460509ccad2795712f473795a563c5d123c7e71173f075f37df0b75c4670fe46ccd6a8936c37141b2591ca0f136f651fba444ee333c496f094d1aebd8c05e3b73b93b57076d13737dfaad19365cbf9c7a0fccbf9ec74d2d53cee7ce0510643b2400b395c6ff0d9c96437321811b7b825bf25d926cc471fa225a802a08a969c19562dde88db321c92ee568df49ddae9b1e396aa9e6765f06a29504e5e9ba2fb0361bc245e9ba35d25c64f606bcb4237a19593bb63d034bdd68b23734f8c5332584917243ff3271fd4a69ce55c01232600d380059d24bb415fde00b0eafa7b5d0c9a8904e1d4ffc60d4e6ae393b514caf1b1a40c75a184455b113b078a40857f82f217b47828dcdf8273fe32abc397f4632e34af0eabd1a1d24af449c6955b605446f7b22fb19075c31b24ae52096fa2d623719aa65270504790e30086ef2baacc0fbbd5e4e57ad9ab156ad03b66503eb906ada4ea718f42139aa34c00f2afc5472f81f9317dc9cc919651750d751515971314f517f060eb84d67b1045f55fa1dd6fb91abd35b0016b0b76fc7014616fb4a1cf897a3fb4f67c5cb5f171ec6ca55226d0439c8f245fcf0ebe8d449e38f57a02de6d853d3fffbf22d969a4eb6af9a76552ea72d5a0cb47b4a35cbbf5a510ac0653098bf08b99729ad75200d59004ed6d287d12e1e3f2110734df6bb88e2e2ffaddb666a06a0e2bdd74e2c0de796562ecd3b96d89c5aa7a36b00732845c05019b3037285bbafa39a7dc25961b3734058896bbd9c21aff474ba076be2a01cc0981dfa224c5ca86feb11f90929a841ff12fa2de895c5cb4420143af693225053e62540bbb0a9fd3a2bdc29ee511461329e3dad933afac0a29dafe91f3b2dedfedd3abfad124cd36521992ebce8bcaed0f1a5e0cf2103998f92af73b2bd20496646f91de18a03d78873e090e005dae45db326d51099d2c6b6ad4ac78f6d5a391c00fd34320a3908461ed9b86a1cc0cf8dec400ea5f4f65b4bf3f91032c345782ca3b432bfd5e9c3708c4008148acd7de1281f98fd65880556e54a404ca1883795182999f6dff0a1d621e727d39514255a9edf5a6a06be0e1e6288d0496db677943db035b8e0cd4ef4c22da808c6f978903250338670e735874c79373ced9c661f25ed11b58a3863821ebadf7c8c0618856d2d26f95aacc81f37a7e4e9335f0d65891f9f989bd3f1e3daddf58017b35a5a0a544f295c1c6ed25e337a492608370d28ad6c089df94f306c1cd129c0d8813f9c8717214667edf73e8aec0a715afe279f492e64322bae3c066e6eb21ba19541d33d382a82934064096fff511889bfe969cebfeb9f4a897c32b4867533a18c76b253a38850aec251432576ff6dde0ee9549ae9041b23b5c2d00b00dceaa151e8410e46a45004b403cb4f526038032589e7846ee5b50b42a4897354bf9d968588ea8ac63f5bab12096588dbe9e1765fca76d534ee1f59f4a575db62bdd28405e9a744126a1ed28647e176628aadc770abaa6255f1f3f60ae1d659ab31a65d86d76dde97e17e9e67a0b16a0d92652c4d02407a82b626f7c9f50e73b1c5fba9565b6f72ce0e6d24a5d1628f59958e07ef48d90cd81dc1dd967501151a97e4ac25d69f5049a5669cf3f5f355b6f63a559e350321bfd0cfe33b4b529e76c40a1208d678be3b0b6b99a5f72f5c9c6e9664a8b52032e0376be136647b2785a0b7ee8009fe4509d910582d95c806b9a229961747d3498fdce57dcb7a18b9916797091384810208571a9b17049a4050adea81cc324f10853c68770be025bf91441c32a1fbc6572a19817bb722102818cf02ef2b88062ee46e8191c7f66a0715e08d5a582c3f234c992334233e298672534e7baa1364db69e817c5c15c76787aa21c0b3ca5e18ae14041e8ce9e2f2c9b8dd4bba858a96b175f55b6707663ab5fb771d05819f20340a13131c2c466b7b2981d04338d6dd4b66d562bf46da1778c42a70a2ad01627a300408db584fb35e14af3eb1c91d4326ee291964e5ecaba0d98591f30f15f93266a3a5bf6d5bfdf7f4637d0f79f3f093f86220dd11bbc9750868dbb2bde695902303aa69f8af827af1ebddda42c105505272d109fb1247d0f830534dafa429f534a27b760dab4aac5f42863bd23575ae302409ffdbe9f70acf57602f7316b66261f3d877ece80e13c999d61c5187ac216f46e73a5322a0be706125abea7fe2e087868eda3f804d9591c1f03afc6c311fd507dbb47246c35edd49fd72b80f0cfff383c8d01a53906721afbb5cc4c2afdec2182301ed818aa3520bbadbb344b3325712340875319cda665ecfcab8a310fbc1f25dfd5aa2cbad8e2fba01b2cbb661ef7e02d71f24a5b059bc2b37c81a6d8cccb712d3081ee64284cf56454514d8cf03e4b162796b9d9d6559960911fbc18ebb02e0be393f6e32d05eb60c23d4e2028cdc32b4af08da922578fbfad6c8717d00de6a7a963b1c777e7725e81b6bebf9fba6646885bbe143ec15a6ffbcc516d03fdeb5f40b07996b5adac4b781a3a03b987931e21a529953526211870a7019378dd4fc0f42ab9db2d0fd270ab72db3dd4455193677625f2eb7b6bd123267ad2233f5c39adfbad0d88538fdc94bbc660ffd184d3d3ec08efee158bfa53e4238992301c5bd5224471f7ce28e51430885986d112b6ad4f91a1265d042dab6de76444b7d26515e55f2d8a5a2abe24cb6a810450ddec558957de7f89ebe5553883662a8425fc180f8f922f7bd5992a7574c2755982749626ca7e13a3dd26120ead3bcb2f8df17d707d29408a022e4a8b89cd3d53cb7ab7786c5968b59f12b252c7fe2fcf120cbaa2aa9fc441cd2007e1e18459e664b202ec9fb863b701a10ca1b03ee0779c19903d323e15c02cd52fd12ac28c1e62f197992265e0c4f6d7645d35c055a39b70b9a43e6d6acf85799d584d99c02a6fb43c9055c4d81a59a106373562dd435af8200a09d7a4884ae64a0a98903d95cc7aa7a077eabf82f45ec0ea40a477ecabde0aa66c8a68c3fc71df5ea54a8cffbeadb6ebc1b7e3a30fdc21788066e121c25bc2cb77daf43a5312cdd2ce0e8bd7f80dba97e83df0ceed5309a4e8f4a8b6a506f3b979a8fd0db78a8c77e4baa769c0f58d6c44f550cb6501f3678aea9cc97d115110c3a0d358ceb48330f1716d47e6db1ddd7dc7cd9575dacfd709729b7b58f65ff8820da9958d4570a155a3566ddec186b3c05a477f3a831d7a3b46b8be13ee6eecbb6e662edcbbbbcd4ad6c6cff18172bfb358b71f9a8a324700491f63d760f7ac064a2b1e10807d038eecf488007d2f5a8b0de6bb6b549632ba7f464d16c886d6bf37f87f0f9d20029e560c45a831588dc767d141291648cd40045ecae6b22e98a4966891531fc862e4c2062bcffe26a8ef4cc18bb069563da40e02026e3d960140ab0386e2342d86f27835ad399bf34b54e02012fc46f570a5ab2c5db6a8a53b7e07ecb230b71237227d065340d778c6795130644ca5be124a93c5d2d51f0db09729ba67a497e08fbb7a56aac1998f27ffc37f22495d24bec96b985851038f9f33a167c0a5d16f68cba3c2c2272a7f8fd15510048cb683f1ed910abc379dafa50c8662486ab405de058039c68463d55af338ea1bace733d8271648435751528ddd05e6f40f8cd532568e1842cbc32491b71daf796bc896bb2d2b8212fd8d4366afa2d4e800a2744c02b9e8158b1091c154924ca96935d02e301649793f0fc532fcbe99fcae1ac38424c215902e1767f04a714620e669847cd8e785f03b9dbbd31be501cc03c4c3ccc01b6700702424fa70c982c6c2d8990251c62381312c50543166b49b4c909d02831ba8aa52979d16974dcc00cd29438622fd146efbcaae2e6031cec15a09739f3cfbb1d9f7a4c5291a821e9894455da09ee884d7783e2055c210a70091c8136ca895ef2c856f148c0c6e08b1a7b63b1a5917626d246781e32482cc6da833d06726f0200036c870470a0c0a857e49675edcc808d4eef7162a93d7ce2c47136c84c731841c844ce42d1909d2ed6e1c89049fb1ecf3ee80d62874e05e1bfc4e856b428ebc36d11eab21cee5c79464390537d10141545c82e888dbd127cc903ffccab16f1f615af0b21ac56541b8b7397f26159b842977a52cb1a7d07043b0c71794ba02f6f249644a395c058f8a67c6ed19378506878daefdf486dd78f1dc1efa550eed31b046d8a7e260f9599d46589af0ba12b33efa1ec1f0ac17eaff0255fc3b1d5b702aecedacd9f1dc809289572b73079098d84376a4f4e6a39cc9a56c546350329827dcfcfdf232988d7aafc35e3ab0df7e591d87ed8b02706e69968f8a6b41a0b2091d8f8a3db1f517ff35d45765fbc46804e9297092f47f36069947d59e8ff556ef0980dbd1cfe361a834932e444b32d0e0a4e5349e9816f85bba527ccb400a6b2f03bea379095392d38994656810e5b318f0be587e2c9a17f46b21437d2ba839829bf6c666ca10cdd8fdbfac9fe4673a3ecfb21fa22d7e4cc0fa371e8b3a2eb05d527d1636907f3f6a5aa51746cdfb8680f4fcbd2e854fa77e7a21a0ef5a11b02383f318471caca8539285b1f877f6bed1c5b6ef7ea682cd9308c14265e4b53a82bd4c19fd1eefca0612832e14b0b466177e7a9824dffd676a15d799b317ebf9f8d593b80200d28ddc828a30c30aa7a7165287d67a9de311b79f06a456a84c663da78fb3e3690b0e15a34461480422bc8ccacfbc00633007e7321151c1195acbd7956af0b0cb7a68aa80ecce7550d7087c0899ab5ee507d08edb35d4c5cc7d3dd1f55b601544de78018277743123ee1dd440c2076d8982b6ca07cd47ffd23fd15440b889b8547cfdf3017a26ea61d7b7ec583e00679cc578ef2ba426632bd229eba307b43a5d825b08f0cb444c893141087024088a154ca2b73dbc1444d6f962e879629e340d0746e15723fbe5f1932360bc080dad440687f81630d54a88417b8652442a05c685b6d16f3f3d9394ad86824f4ead8bc2e8d2dd9e45f247cdcd303fb3281d483cfacdaca01fa6aa7f177669a75930c74f068c385ef30d4f1b8d60ed28ba6cbd8c588015b43e208d585a5e65f19a96100cc6abe263e1eb31879e7a049cbc43942a07d2a312c8ca8d414be886c807934f31e32f184348477a0e0950cd171b9a186d50b4ac399d3ec37eaf2b123d4585f8782b0a379aa105d88a171c911bcaaca77555c149fb2dbf8d5c2d233dfb2b8270626662fa28b14a9092f3259c7609ebf55cf89d8114a487df7bdee816416e8d551017bae1f57da28a08ca677b056b291ad96913b7c8387849d9a0015c4875e93d4851eb904b038b60f563e44e96f1483acde7f4098d085288b4d3493b499edda59f3017ac930d3055133353cce8a7aa8a7c6132b4d60fcf18e39b5817be7960a6a52c4568650909a21639ffa248e0c27efcb1af87e28b82994af3bc8f91a05623cbb9ebc2e4dfe89af3200ebce2d2da5fd78aa0f0e4bbead85d80ad340c52931b317007fc3430381a4913608e15d8ef24f71ce0b28fb2b9139f3979fac26c2d82fad785f62e505a5c6c626565ec0868763c7c20942c16295121ebbb7f7702b0378fe5a5e6f1f8c045fec95b20a848845b5e4a05221660e587bc73a445037d9885d23c670b1c88fb28c563bf90225fe57247350c111d66527d47bae6d999b804d2c02f7b870879124e8cf3604d42d50e0a60a87026edb566a28c074382167ef8784fa69287e30ae96eafc0edb8c2ebd63503cccb1e6e29c12b56c220cf4ed762b3263721bb164b803b2964232a2f52b2f21b0aed6270b571bcb99f1b910d27c7b26496039fd94c8f444e7908a1594d63331857a4f5e729499bc1789e97c909c23caa98070941bcd52470ac2fa9f78b224311b70f4b7fa9ceb2d56749612ac5d472749dd8dc04537e019a5423e8952c85f35c784beaeab7a0dd9090b08ab5be435e49efeaa7bca8147f209131145a211eb214b01158681efa6aa4a169baf569d9430a3f408cc6b8f37e8249b3b2b51012f7fe9a073426ebab5c92a88536b9b3bb03209d5567b9ff4fbb8a76f2798e8cfc8f74f4463995a51dda75717f8db63f0a996f18046ff660436870ed779519802ee5011fdfac3feca749cc913aab4cb1ada6cefed2b7e6777ca7a886d865565dccfc41a4808b3f9f1a8d5de4b3e7bfb4736085ce9dd187da1b4eafd10adb225c14f43cb476b19d2d3339a073279e48c33fc5bc8cb8faa15b4072628d10e45e8c68fddbed540e024bbd6e5cc1b03f89e5072190ae3434145fb80c4aec8fdd5e87de21bb90d8fb8bec35d86610b3e6504194c7e4a05c3a4ff195966e9c0588d562e2dfe3c1101dad6e00e5c18f2a136a663cb32a2d715021f7c72218028c3dd797595dc6461e43a857ff4340c2981ebc0e47d0dbba03de46822d26f14fc4adebf4ee1be92c33ddcc3adb80adca29fc7251913b4a7f50825f6d1856c7e50d897d0df0b5ae7a0b6b2d014904203d23d058fc03f012afecc95cdc9013b326aa17ee0e897301685a50e7ae751408a948b8d875a237cc711cb89c23482949a8173cc882c628a81e19727c6f9b1d2e9bc77782b3cf1c91e1115dc3d4603cc3ee6ee5f4b5088dae1a09d7f7390e5a9e8d1e71d5ccec47d2f5005b311da91245f2883b446373eda118150c3579765d7c3124c4d49449f022f487c592c517685550c63028a00e92dedab1e98129b67a9656ca4180cf1e0a42a86fc051aecac1c19c6c763732064832ae1ac0df25946b3b1494a083597534855e953c546c41f0e4e7d74da677bcc87ae715479611fa089311bd7d3f9f719bdf7189aa9360be91d9189bf1eedfd15ae6f2de4eb596cd5a71ee7008a10087f35ff5133eaed32c29135e75e2ca2cd773843bf69bb12670afe36e903ae76b117f6ae04aa97aa3e5810c9a7fe0fa55f519cc18e8a30f9e2aeae9995b13d55891f91abff5e68c2dbcc9162b4a1143c214af587a88ec983f75b001ef8f5c3d3d3f38202329c713174fbc5b90f3a99ef6707b87f8c6d540167e905c176939309b916fb0d584c1d99fd06b5098f83434fd1d0f2a1876c7651debd3bee5b77c12f5888f2ff481947b80ba0ef3bcc8be5e02f67b8b552901a5a13de4900488d58dae6b483e6318d51e5c4e55b545fc3b20886d105e12397fcffe65c27d3e0b685b080e2ffa5743aba5c56c2e2d88c3a6be0804766867eafc3724a38b65cf3e1f6cae395c7a9a7f7f3c383e90eb8bbc18e1ae45aab100987b053090ac03e35b658e3933ff94aa7165462c46520faf5fdea372cdd8a111e31662a3bf42121d27dcd38caf086f4b79a7b008175fd51a939ff4e77642c562e07a6515120bfa83fc44a43ca98ef2468d949421df21fb25342fed2cea45b1e5b992272ec506cdce8b4d43c30f2d09b5330350bcd7988fce8d1246d607411ee5b00cf58f2304a363739a9fdc832d6f837d42ef9a632594cc0d47a6bfca2bc4c98a9a9f1ed814b7d637cdc287433ba8f04afffa3e59af3db9cb8219219da3cfcb02efc2b3aeb8f19167cb6fda90d60d9de1b270c7796404f23715ef164185e4a89da3f2d86a580732008e2aed741d7b52231c088597678ace3f6511ef6238ba48e6010076ad8da2fdbe20d130f903fcda5e1c9484934cd11009f89686615ec24520b8242196ac6044e516c7f59164f2b6d3823fae5db8609d3a3fc92b8c5b8d8d4462f3998f1ed621436564567a2a2f9f065ffadd7b8304df993051cb631bedcaff116cd418eb2e322bebea100abb72a86248986cb3321c22356518dc4fd9cd01e7031c18a09c167d5dfd1ad530302760d15a05378d2805f36412ca0746cafd4f9458c706dd67cdd980c819ea8f1193d3577fa71692493e71ba6172e60066d7c5d283637a3d1289c63c8406969156179a1801d29e103f582d5bc64a2778b952080d00a81a536117e8286115e81a19b0d0a14160e7bda929522c879aa39479de1564555c93d3f8958c5a59566f88c46980e42d1233f5d962fa2210f7c62092ecf70f175d8bc94021e97a59a85fd34717fe4ebd6d6cd2a634e62e0583ba4e7d237c07ee257750f63a9f525e3e60defcc9f745da059506b04fe42569b349b239921f9903cfdd45f17154a4b58fb00045cb3483c69070291184b245ede9a1b026a5a5191cef620398921241343375badf112c87ad5ae0994f474353cbdbf6c9f1b3c71edee95b42d905b62c79a46369b2347f6b3bb19c3c435368a1d7dc01d4aa7243fd027558dde8068e9695ec1de7621ea7d57982622db2b5c5dfabe49aae72cc633f72bd19e8c867cfc5cb96d08021ce0dcdb19c11054801bf296893d80372e7e829072462def57682179a217ee9bf10c8efee0ec141c393faf6178816a798af1f2841af3d60533af31ba7c19a278f16d40c28ceb60e9b206c33df44fddf50dda114f804559728ab0debbaab2e6a6a75b30dee2a9f455b1242add26edf310caf8cd11a16cd1d4d98db1e7594ca5827351dfdd65d101b40b36995c6ddc3f3c0d9e5020c8c3f184847115b79af821f200cd7fd142a83dcc0478b8674891239e003480091a16e3f7cb006d35503626dacfc691e64a15f368601affab3d7544ac8f88d491c89589b3ee30d5ece8004605f439e83ad8e0100cb9452477229c60a512de919071f6e2fbf268133239b50367a6b0efa8701812ca6aa25df542edf8c1587cd40c6c3947f43e59b52b85ce4a850376a12dc32d747bdc8f60f1fee9a1a2239cd3ad5dba247a1ff010b0ed56a970e438e8308d29ade283512ba0dbaa516f0dc26b494087a8f323dfdb27ea3ff09991250a8cc6c89fb383746dc3891a4f8f6bab964ce593cb96c9b47b971c867b14c2b669dadb71ad9c6f095ba4a42950446e14afac00dc45dbc2ef199ed8e44f8b0df72986b4974138bbd4a52c21a00d9e5d1f6a613e6606526342f92484003cc056c0fcaa746d47b7cd0220d6afb0e24cca68fe076528b064cc0465e108cfe18c29e96293e883042275be39108666c6f2e4b209eeccbd8053e095c8fcfdeab518043ea3a10eb87422f024cd08da258dbbd7ba5c474e0df5994e9805c2c351a65d2095d8ff0abb416e9e007fef9318e924129bba580793d4ff04596e061d2d7eeeaf7e78dbf312e2a777366b25726a9696eea9ea65d67abb5568537b100ab542e90a247d3c30d7bdb56ed7ac84d9f2983698965034bae3627b902030d4dfe51368e98f53ae57adea90df63cbbc727efe9d27783cfac332f9f2a4e5f3f71ea88606bb2564f0b5b03735f366998c0fb65b13bd638822d27ef54cc909215fdc40e23e6f2084eeb0bd0aae8145889ca2f4bfaa07ddb5000a304f1915fbca6b1c27a2e6089a48621a1ccf5f21a09db7f30e625da52b88a1b5e694bd17ed4a75ea2c083a41904bda2982cb812d678394227e14f6ecca142022e5e1d70e0890071a304ab860db43dd28b77c983e58020ffb2238955055ee30d9809f8bd058249a232f4e3c3d7da44b098d70431e4171f5419d9aecbbc3b69a2a9104840729233d939e71c2164d0a2fdcdbc29b79336a97aba41308c3f5380741b01423b5b266e93d37e9566052ae15b08369e630106a0826c7e4135f1bf25901136553bcacd23ab5522305163c3e042ee534e5c2fd95902419820db5593476cdb2c7b530d891e3f0cca2a6941b930b47f0715e795c50be7f019da5d185b153336276dd05bbd0b4bf391585d9eac5b04d54129810d8962d16517ad862688b990a6a7c0f54eb15bbb0f02be44bea0bb5dd634706e7a9e54c229d33126592c0fe8f4820fb9a02d3cd81cf3badcbe91e5c9029e31415b5d5a8c3cc8c188150f28aebf27f43b49f42c2cee0c0c243e19bf207641c34ec1b16162b4b2793f39e2f6f2aaf14c38818905e914716955fc95064930bab293eb24d2962e7871953a2a015e6482da92fe54f71eb07136fe617f9ce44a378840ca50ba45bb5462449e8a682f1e57da15775cacf36f73218eba3884551971ea1ff9c2af707d388f4195431ec6c5203ca08ecaef0a5098034d925dcf47467d42cbb821465adda7be0cb76d9f83e0c3a87326a53cf91b30fdaebde11f9647356c444d0baccd495c315f2be44e77aed1848fb98b0804c791fd8ed17968cc41f423317ca34ab858b304ef6f2cc9a8306e59e185708d05a8e822225be8d4ba83191cee382fd935a00079e2cee3a648c8033bff83308143256baf32c0fd17b60e60300487b00dc18dee3e70a0c7cc8f959c441a4a8a2418ed88edacdad9bdab6c033546b8371dabbb0a696e83e5b18a9406803b90246271561cce043d74be022505e3f350637ca4f4230046b425d916081bcb563bcd05f84a85904876b288adea78902cac325c75fc900a10c5c9d13068f0c4249c68c23758ab4ba563c4d06f39959490ddf2ff939b99ac30d586c4b5391a62f8e1420bcb16bff8843d748df8877230bfc4216ac257e0e1600d7538e564c0b66042d0fa6dc05a0543ef5d396e70fe6fd5de19afb4ae641009bbb8295188662d277c951fde8087b6ec027c2f952a5167c3546e2528e103ba4ec94697620200dfc8941ac8456ee136f4c60d993ab7c294735f8de09c09858bd901f3f45015c7226ce8b4c7b05b8fdb7545bfe106c0bbdbb63afd5b46da4b9b6328fe4fa72a9a04144c2f1962cde85a323f7225dcbfc5a29d269db35767f20062a735bb6377287799ab062f08c7954bde7ff2ec6cf96bd52fed6a5ac984619f3c50f01c38ae45dad4499fb68e1031b8aa7f4b82f27456753e415f1165f2aaf54bbc349d6720a57bdcaf46f83d8904bfdd4a24466c6f0196b1a255cc67200ffd1893b54421d3194aaae12fcba8fd5fa8ce5b84f86a9c9c2b7d56f9f07b3356324db95dca42ddebbfd96c72a7f8813f7b158f859c65948557056b89f19d48ab762d278145f8c5a0e68ee996a224811fab5bc815def380d9b4a7106ec3306e71bc616cfc5b8f6fdc3e9361448eb0b300a652890b94fc1fc81b9d80514ef91548e65a9ba0c252067b711175971cef44ea42598b479822522e768ca7ba3ede02f32cb02dff888aaca28283394508ef94645e1f7bf6c76980d9c1c454f758afd145f2e7c945a4771565ceaefe70274170ffdd5f5f38a2ddb1f341b1d34fb0403dfc9528ed5d53edafe15f0984c7fcc25a007606b44d6017a295bf83d3d0ce219ff430cc944ba901fe1cdfbc6226e001f7a7ff5aa25b15dd6ec7aabe96d46a606943c714458d80c4f14e32b5dd69c0a4490b114b578ae3cb63b90e61de9a642fbd71f3f9ab2fff44fcaeb78d3aa3b36e2cc2d5081b6eeeb98c4f549797b369648b2b021b3447cf89b63235ef28f80d352b4366b3f54825ba15deaac858f572647546e58436e8c64cb4ac2066b7594f8d6ae700825a19fb30c0d5f2ab8278a0de516f6c65f21a38365de12fdeb2c742bc4e67857203e4b0ae745fd4c66f80da9b5c03608c35db04048d620debfe2a583c6d5e6a946b0875636701a8c0c0ee8e7abab2d6ba78c0b6d8c835f8a7c3893249c272c85e87847e3653d587f2225de4339fd21144f8ddd45a3a8890c476a81b13b72f395ca5b24e9689e52fc53c6250b00170c6dd5b00b35b82a201f89628782093d9d6455a268381365e04a765816f6358d4d372a342059f6b901e86de072a2ea91fd127a35123499cac026f15e4612dc7f7114d5859b4142876c3b8107e8be9f79e19c46ac2c8cbb21c01b2e95ca85fd852986a1827d2f6160d7b6ea4534e6d84c79b52a6c4c69ebad19ce1365c607d045f490a8a29cb0e94d02eaa70bff4340bca9860d389db9dc05fdcbc972eda3d6031c5f6bf0993e8222548b114e05ca76517abf424b9e09110af726bca6bf83696726ae854351f783aabb657949ff7e93c0676a272bdb496da1c70f4efd8c97e12607ef6b1d423489f11e8fdd6e92f56bdfd347bb40f7b121ff2dfbd7f1fbea4e1a0a2e6ea82ca4c4959bafbe251399146f818cc7e08008a2a9b38dfe95f586fb28837876bb5573cb21875d433f261d02494789b18849d5b331551dbb57e4a3cff5818fb7ba7cab44e1a4f42347e6d699b0535057140e1c565e0abf385ad263d61b49e3fd8613fa24c424d27d8a06c925401673b45c3258ddb207da6e954a93bf485c0e6f4b63145609cd54b88c223ccfc1785861f2929a3cda462fc067e0eacad4f95647b9311bdba2d0d8d73747907679c274a8e6c3573bc94ee61639fdb874de2599abf0af3055705b13863cc633e7b21e7d6340518269d0a51c9ebc7477e9cc2aa303b152fce1617c2c5509d4ac023d2fdaa05a29fa415abb244140a87247d46f82fcb563fd44a3247ac5ec893dff908a2c630be725f03c99d24d19a9239c91700309abb3d982f1edaca6b683b140aeab7110f0d5b668f6da6224755fdb84db348fc47e5a75e0e360ed4c94fe4effd1fbf05b3083cd927bb932a80e8eb7c153f07c8a5753a8011725a93a4f514a854bf555a2090e6bb008aae0b4755df20dbead8b6046be886dbef05f38e95b8b5e3f9220f2acc1bcefb515b34e8bdd0c8e48fc9835a323ede4a59099701be98fef4c44f2a8c51f57a30db6cae0e2f878c51e089e1404aa5e9c13de110982354352de33b4c153a095680083773c1186fa2c0f642a71cf56b8fc6394fe93a9a8939a865d3d309c2ac0210dc42987c6a6c7a5eaab03029a281f956b0ced7738f383a04a05780101804a2e8ac9336d9cc8c020098cb823af74aa3f7deb2f401084a0c50922633d629e900c321071e19b79a9801d4680c6aaaec5c4563a2c6e235b9e3b942367385e19517564be11e408bea8948c0ae1158b5543587fa4d090ebadeafdd1b1e99aa50b99d0dc5f6e9ed9ab3247abb8e81b33a3238e8a97f053558314ba8887359a81856313948ef471e5d0ff3a2e7a5dd30f489213d95c263513fcb174e08ca5c0eeaaa18d7c90c992a183e76044f51d988bd7a9c7bd48321f4a8439a3164412752078e740f63d02ecd38f290db995978ccda1031835758a1c9d9713dcb5dffa8a8ff9c2bada3a7480b76570f50d7016a1fb335b482f82e1d0ab09cdfb84f009c77bcebfc8757d5498e3d6e8e41b84e2f1c0d666cecfb6b43a8a245156b52f0c3c0e0b023febab92c5f669ce5b4e9d8abaf182a0e58514876700b403d14ad2eca456e73185e536a8b2ad49f150a0be24da251c4813ee4f518f49c00bb35882c58ab64cf15d3a99d478430db02dc5cbb6496f7697f5f628415f1d8cb4c43a8b9788e4085254b28b82aee5090a5708fba060734c899f336e96fc382318f2b4a44f1828ec03fd31b7471103c87d13ebf2f5f9c6cfcd6aaa92bd83c6c1d17180a62850907207d482c5bf883310cbc039b173e45bed0742931896ba90585f685cc3dda8604477f0c615f893b1a51ab801400e42e0012291b9c5475d1d05f2028a5171c3b916f87cd98758531e8c3152be6d99bc15469e8ffa79826363017ecbd2fed0c3954fdddcd1614c692e2226503487abd706da76d85043d7ae62d87fb1b22285c90c9d2658aa23aabd62c2a19632b21aafab8f87de9dd78d030401d61d0e0717c017e4c9034b0c88249b44019ba521fc38498eae10325da06ab0bf2b0a54a58244ab0a0f5accf8bdd7cb7252cf51039e02b9673d45c8ea9cb09f68951aa534806996acd0330cd1b7780b95a05bc99758bcdf13ba94560f25f7f880e2dc76e882efec2b93c1dff16b59340799214e0b1f34b58eb06e2166a07a26175d7bad7ce8bc633a922656a400cb1ae556ec13ba5c90c01f7a3995825233db3e117c7b5556c76095e46a620d36ebb63f303cddc46ce454236a6b81b96854804c0994f27e4a0ef9566e8409f9993c7db2737f4cb589a70d8b1c2f2f26870e65cae6169765ed9bf607c7257c005ba671a00d328411960bf1955ba1c2d1dd776650ddfe9aba72f77438f279fd7c116a6ce17dd68273306ad3325c0b88c3ceda3a07763d9c5d133ddd9a6e48628b02c4488e978d15914ea1704bcab88d6b523db15c4a182ea78bc09715cd9893980c0e813ac5f820aa307ad0d6e51138c88f092c5a958aa04964a421593b2c3621190c817b11ceb088f65d02cdb1fe07881b826719154c46379751d171a34d9fe741b56b83b59a9fa58e0f26207ba68cce6ac54e8f4da84a0cb914baf6eeb1edf0cfe0ee601b1fa077f7c626943d7e501e20a6dfd6ab3bd8ab89142819096efea790d23b141991ba7bf1c067701c2cfa0ba20c75a32d01af89ca4509b781970b359b7731a91aba2374a10bb012336217d5418752785130768d028d07426f0518b7e65801fcc7da955eeaf3329050e4271ac27425d1530e9f281afb2ab6555531de9cd6a8a342a2a802205115db1812ed31d75a35ee8b112a7a184de69f4a1ab779ce2d558a8886fe8dbf08480e3a1b60cd5b8a8b17127c75d6272d9f5a141d7a52b241fb64c0917bb02f7c0d81acb607b7c054ae32ed77b1498fed3ec2d565a142e0e12dc1338de0a38cc8ec10d9e29fb1617a315029b55e271dc8d9406e5c8719e51b54d45cb2f66db06ae5196ad46676b71abec620d40bad2ecb0883e3f08bd1e5fc43a17a522c699784582ce9f33d674659880183b0cb7fee56930e62c49173c87407f1856d9ad94420521857a8445d8e41f0931f81dcc30b934a8848d1afc47b387ffb9ac8d2201d7d88ae0d7b4e0e709426ea685603d10851ff95cf562824dc380a5cbc558e5e466f0450a510de1631db533a127a0b12c2e031e2f2f52c6202ea120f971c768333294f10fdc11b0ac8350971d2b40576aec716c216bc91530beb5eab61a58c98821cd8395e4b6fe5bcefce826c85e0da278297ef566c2b2007009f72d96264ef664b482ce73bf05ac1351e643b7c334a74bac0f40df02b18230f993b4684216ef8e8952b25ce90ad6080e612a8bec8c9a9462e305d67309a84013f2a1bb80e38471c0a7f9005dbf31181ad8836dd71cfea8e504be8ab9b75c49f1752fc6a2178e8c8e9770dbc2342e796be5644c662076af425358dad93432f217ac2b1a76847e36e5b26c0f084ca8347799bd8c1f69db1ff6bf8377c49e2b98513ff11f2bd04d8e00557355cd6045e933eea799dcb804aebebaedf7f0d5502e4dd7259ba170585cfdd82cf571c70e0cbab187c41f699e00094188f47ef75b79d6af8aadbe10fb9b1a544e6058d83cfc3fb50c863093d1ac62850919afac705805786e2636ae51d0b14629a3fa5acf80a1321b539753f1bf8beaf84f2111dc50596a8b719939465c18b01a76abdf9d2926695d73cf45ec7c577d3dc58d3e8de453161bb1ae6c10108ba28d443869e2a2e61017ded30ff00a455015658e37d66f4601f826b388559e016d362e2e9ad927b269491972552349bcc217805e2e30e6d1fef6b84eedc18dce1560220c48c5cbfab8f4da917e15403b3e9dff94cebd6a4051cc5283f1f37fd8d8987ce4c71b5113f2e8081be470b4567cdacd6072207964646fa0b35722d259765c89f37005b8f7e9e7af447eeb796b5e59a7c8f4a63f9136ded3d266c8063625104bebd1d6742caeaa550f3a3b77b2d8a4ce24080046e5f2b2e93d35deb194b370b6ed14141da38bd3f1cdb2569ceb063dea5d9958b5f20a44e78c6848ac1a2c34c77766218a44ca410f0ae31381c322563d63602065f43c63df1721ba2b6e4da113b0b54ee5af8ea61ab251154af68b6967d444000cbe20c919f1ad9afedb3e9e1fdd0793f0ae11be578a57c73d279ec3aad1f109395d55534edb07f1be7129c8613ddfb02d974816da6f8e1b66f92e5e08f9b483d415010b31c84525b27ee00beba4f12bb633bbeffc21f089bdb9210a44e3399227ffb34583182997657026f6612f89c85aacb27fafd92b4335bd66afed6a31b038743cc912b932c6487f7d9e038116cbfdb259d4a0d2437b748a7e1e606c65ceb872c3a5584767d17db45e91fe9b07260ba230c2c40619b22a92f91995231eb019941424cd53399d96839451e134b9773f3d8bcdcc3f06e83458a5a0f01f270d42b4d00fa0e69b30b5bb52666e660d70543f6388a79a9a4606d10d3467615385574aa8b07b9b0486c54ebf3593792d49f1408b12c652c2e981db68d9aec07d8f710027f0a53cafb419c96453f5a2188cb7307ff68af6e56fe9c2038c94168c816ce4af15eda7380122486d060895119f3a21de520a4472091c12c5c54f59ad15472161a85800c6ff639b1cc098cf082e980d2631f30ddf77536524a720d3766ed3f4318ee086d0ef42cd66a32fc7c99b4c667e915f110f7bbff05ae9f000c3d0a18b93b738381f85f9d56b0ae49d76fc97e6381b38d6a15661b816d5935237d262d688b4528b5b204a89a4eab826ecac202187e266b7bf0b0d71398855996f8c3ba3d2ce2d21cd99af2c6f6d12c668394d5cf826b31f7a622ed617280b2539c4c35f3fd9c0ca11cd2c083cdee47a5aae141d19bc1be5ff98e17a34bef1c4efbe6d3c2205f0844ae86c9c02bf493a3c78036b90d7463f65685986e1070daccee9b853fc876937b68cbd055ac62d8fd70f7a64a36cb130733f4c9e54beb4519a00f7eed35c30072fdb5c1b28087f608ecdcf6c275c4ad09179cd8a2906e23551ca027165930c00c0950121038432dcc04d4231517aa8095d487bc740ba4d97af534a1a93ebc3fd8a30237c18768375c4e10980dd1454292a190e612772f7a7a632a66a139bba921f67aaf75b62a364a3eea4297a24ebcebbd8b65726b994234db8c74313ef4db43c0ec3b8b46d3b7e76a355475751f51b2603567fb6e9cd16537b85b99b88c643d53569be8ecf5b46271d288f8edf231efa4bd790e0be0168063e399d1014f297621ab7aeb14d679ddc92bc0dded2bcec286fd3d5aa9d3636ee0b25c849d02f2a63623a27e2e7467397a3f05bd01a55107a4185c4cca004c228c0f905e7e2f939c98192f7ebe1343b3e9d9f2dd6933c26a505ba78bd2e41d389d22abe7c99e0c3abf901563a1fa32de144d0b5491d584bf71c094a8321a6212c28232e9d4e89b06282c0b64fffc4459d996ce35f38236ec449dee19e26c94ef52c6b4e4482919ea694162a9c1c2e850e048fbf201b4a4df764890cc6e815309bcee496c1daec89dbd62f082c8a202dbc7fd0a7046a7554725161c7b78a40036d4be46f40eea149c52dd5b440845d653664e5a5c04b5459c5a2a9111641fb87f2a3140ec58c0e7e1e20460cc4eb4e2d9efe603bcf41e7a07ceebb9d809e59532d450afecc514da3fd6f1cdf16919cacd52491808c8b79439090e3eb8eb03e68848ff58929689862ea5b84be053b5b8f8c462550c18020d1c7250d681f7e703d93dbe5589fce6e26f38873fece57d3c05286220d22718d4f28abcd69b797d11976944dd44c1d95d19424ca7190183e14b7148882418c50d7eda529de5a3ff33a3c26ecf8708c29fe785fd4b622627489f02833ecc42e4e0101cf84781f6306d5c4f51f45e9cd529f357ff7a4617510b1fea8a85088ae019b8dbdc3c50f88454674e013afaebf0fd3c489758255e32646256cb13e6b0156e83293c62dd01ee76a280b9604e4eaddec52b0448c42eed8c54a010d4a1c44b267674780567cb31bcf636e2860d294a0bdea7b0cba7c5d29f88f77c5b9e94ea136ba4d94ba254d609eb659e78feb071e5d3ead02c4febe85c34e01368c8832857e2faff087e599064be6a1110209bbffbb7f2daaf76a0ef6e5315787291f8667eb5d58376e7c062bca17b9836e334fe70c171d25908ecebf2af2da6fc332cbcc5f1c452814c917ab162a0c2ba9f6168048000a10ef7ef31573c3a8b3da00ab78f4dbf592e72f306ee39b79e51ceacb61873dae2b115592792f41a4b6e7e4c365f1d26b9eb54b187270528eaf07ae41a5dbfb287c78f62ad8a0d21d06b53f9c18e35cdc5e13a316536b0a95a5d61c9ebe97ed6f18982468195c762a5894a468bfa5051fef1c5d0c404f448ee2dec17366164ec16fafbec94ed4828345d8c69ca0e14d3bdcd74112dc3c9620dfb38f726bbd7e9e3298176d8949f14bee1816028e230059a5156ba884cc2385d8d4addd56515551dd95bcea47c517d0b57ddea723321c4649a5f8961071a19b4899958726d25617e4f9c8414f3538a26f0aea0761400e451e02b2a786c6ebffac84bd0e0e67fe2f1c9af3232248bbb4c0dc4cadfea33ecbaee15287e1170d90858b4bed8c3a49154929d7186b56f6a38e409382cd031873fc928945461f7395266f64f628ef3bed0a4f6791cfcadc4716de80ed10faf860d32738153a6304e810b149206be3f4a52359571a417d4290067f6b3db79faa3d60be8a92bc36c532c586131dc4743fa9495e5642e63367f847646e53999db3b931fb1bb73e6f4253884cb9a1d3fa23b51d91ce26e66e68faf0e3f71da129cca65cf880f114ebc248771b833c207c42741611be4cf690e6e76fe98ea444b730a873f3b7e5cc4703efb78d4369c7716e368b8cd7b7447dacc44ceab4281cc75794943b68024fdffa39da848fa3243f08eec301429e1af92d812d1f9bfc9a230ead069b08747085a165f23e74de61cc6d8b2c358d49cab6a6d948642e9f7209df3e8afefa6090134bdded7d123b3a9aba227645a8e5d23f76680e34ba17e1aa86b20788df1b4f20db233cd51e0f43b532b71efbbedba4fa7026682cad493e670ba9e0219c062edfa1317a383333d3d66afceb42505a7b187c2c1aebad3da07bd469c5da3c2e91d8222c7ce138a09e3f7ab16efeb27e314b3256cfba1129ff6303ab7b0066ebe740d65d11fa18c8a0a9b9d07b0293341bd1dea74928b0f7dc5b12d063af5d69a0907d8ed3b11e280fe5242ced362cd2ae16fe53d919f18be3fc54565a874247551cdadceeaa7128eead45125a41a4c6bdd57cee39f8655b5079ed7548ef57d7184f8b24d45c458c1e32e62c8192e12ff92663f75c1090cb9ce0672009755ebe68a1bb7442e069f880bcfe8dc49efedb7d093a42ee5baffb82be8b179955969ed16a866acf6027d4d5fee26ffb420408bd1764ceeddbef71c8f2703df5dc7254136d9a1210a7b88a2b25c3f6f9f808f6f52fb07e6711ed33a1a41279a3999fa829acce9daa87d504eb9368daca2b0c665068116a3fc00f9ed0e60eb976c3f13c563adffa63a11dd9711f47fb4ec457c90a5473de3321cc5fdcda40fd0cfb81c47e51e66e2e3a93356c6c939b799f871c20995e7244e63267f9074424b3908c73c131f449cf0520ec671ce840f904fa81407719e33e903c91352c2c1395049cc621f8dd2ffa362637b86d8459d4e667166199973354c9353fd7dcedea608347db2649fabfc20ac99b06d3e10edf2ea49878522e96c3592ce13fd60085a41dbe5d02a2acfa9323111e1679f3aa24359c0889f90acac385ce18b5691b14834c87890ae038e79d36949a9c60d2cd3190136bdb2d0306d6af2d4f0171104e9188b0c7513e01e7e8b9363f32999fe51da560b0977884de2bd6493f129fd427ee9a1f232dda09d9d0a0dc47d8d2eab141b35952dac590cae870899ea172b57bc3785fe33de8cb7bb9d0a680e3d587d573743a41e9f9724188511ecbe12c480bdd68575f2904646f6b107e7eab03e6422e85ef6a7c103299ff2b9e7f792bcbc712936c20ce78578d872d062b0d86e4bf45aec7fe77de0546e7897de3870f1a4861b0df07b037dc2c07be1010d402577bb96c686d90e6ddfd6c3c7f62e11c9f5755216e45892b2548ef523bc2bfea9cfd8e170ad97ba560285e93816af74abf64bfd5a6d0fc7e2898c9bfcadfd8336ea70c4ea84581d17bb8f4bf818dfdc5110e5cc3e695bbd8c46b9d11892a24d3e2f3a46e154dd76f96711c199109bf5932e60c96e020c9a915b8ed332a69ea681def7082c41fb3d071ade4387af4d3f39dad7f8c3835a5efcc3cd4b811428ec0c810a9475666014f43bf381cd495337f392d8d7159d416c76d5ce4cbcba4a6784889274de935d4e70d0a399265050b5990329a8d90c050627696dec1274013c1ccdf4d9f680df8cfdee0ce4cdc43e38e92514bacbb8e17818f96b72d29c01cccf3ae901cc0fd63292232824cdc4cb03777fac225d1ab8fb599919c07cca42497cbc60d466ab96f6900798bf69cd935b4e7ea415491e1d313e7aca5af249d24dab3add2bb4933afdd1fca65f32c522f0352d97e4ee28f153390445dd081a7549ffbc319cfef3e3b3e0664aa376d12e9fbcdad28ae07ac1fe88c05f75073474ab1f3f6740dcca787b08c83a5ac8760894b141d26d05d05276f593f508102bf56fc0faeb3a08f311a40418871eb4264ea27c6dc2bf4b847a62db541df9b876c61d32b69c3a325f011960d291b74c3e93e186ed8f471090e76ba63c4f81bf63ffe7b4a168b135bae257bceaeb7f71a724c4da88a4bf01a46edf5e1feeb2f4e8a70eb4ef7873c1cfa81b774730c67af9acf1f661b6d1af16394404261cfc5c1be1f8ba4417f73f7536725c7f8e5aa1fbed70ecf91eed7c375617f8cfec6e97eca18341a01287c25fa49455dd4a3f7ce0165ec7bf9751c34bd1d8928491bba706f2ab2079759cd8f1d12b70dec16398306c2bb37491ec5377a1c379faa817badf0f61cfebd54ef6b1bae1e986be78c91e2a18052a7528fc472a4965bc76e507e9d14dfd7919053895ed214b4864fcd463b29af86cb5aef61aa44b55cc01fe844ddfa7ddc2bfd188fe1fb814b77a6616b1debc7934effbe5b42c2f25b7e12f321f28fe776b965a401752d93fb264ab81e272c9b83f6f36ea70d383bd857be8601071d887b63229c5380abba249128cbb31cc8e2766d182b080d2e464eccfa52055331b5cae30dcb8e95b14542658a316387790e50868f4eb69dc3290901ee1608067ff58587eb92e35eb471a8ab87c81e0a15e2a631264262afaaca72e3242b0079958f12a01f0a7280eb8af5cf201102ceb909a520b3ad8f92e933d82560859dcfa2a036069c3e41d7e3c99a29947705d82e9b9cb00056f07907738d1ac259f1f9d2aac1f67729694247ffca6987644eb11ca583d8a1371a5038921056fdbf25b2c42071d2f0983d3c3d987e4e233144815076b8c6af0ded6fc2a513289a47cd1d554aa7758c7fff089fa6f56da14b7b2e358288eb6c28d98bc4ab27f6d634c8f271c8a098a34542b2e3e59bcd365851604b55805a5b09ed2d7636ba3507c039967aba755eb7fcc301d152313044fd1a891da04ffa0445219b8e1ae525c473aa86961c497aace11bfacdf8299df314e157443c0d1a8507cde63f381161ec7bfb0b002ffc241af156658ee264cd79fafbd5581996f70ffa47ddc1854dbfbfa050f78e8d78841a96270a32ff8365a6ab302291d7e869dd3b1d6c7601c56184a85976cdfc18a1fd702b1a38723521b4ff079c34a1823d2163084d5b41ce5e9ec17a92fe5a89d8476d605f48cc491d4da87009f1420c347ff414346cb5a190ec3c54d12781002506e07aeb90f9cf56f86d1fd4c4c5c9c911081e445f72f0fdfc04e0a9411e99f855491a1bed6b092be56953703ae45432918cb9515cdef481b24f31f2982a2bf7ca4702d51a1dca1cc5831dea9dab25bf797f7e0d80e413d228528b42432ab35d53c35cf97d4fa3462847e7463e5c3f22ecd7a5f0fcea9f3f22c62baa1099aa9e5ca13d180c6dc071770580492026d9e4911ca77fbdee16d2f27996cd4106b570818c27aaad8a8d307bac59b26f9b157ad7d38a4c0d28b0aa3a237904a149516fec5507f3d623dbd677df2da9d6e6fe1e71a46800084b18681db72ab1a352ad64d44ba4973dc0dfacb80d84c30acd43ba216c85c9834fdbe5a2d57207de396ee817e5d4b93a4dd281412059efea767109c4b16e674ad94ae16380ca6b1129d4e41f2b6415d3d11ffdd1845f6c50231e09ed3177aaa518ac4a4de7be3797dd68e7a496dbe62e535a9704b565629c21754cfb2f16f02f5a870e5d20768843027a40f00d6b008bc9f8c513f586d14c4541154309aa8f60c17535831c8a80a5acae4b5a4e22bdfe43ae4b51ee1341ad34aa51433fd2c95183449fa6b7e84ef2b81ce3d9e91b46e53441c76024f04818b52630c8976bd200109b11a559ead04e67a82810a7692d5a072cb0602fbb3266abdec54fcb392e295d4463d77a10a954ce81c7fb08481ee19f91432ad091215171cea58d45e49bbcbd786bdd23147338de47ae81de9c0400e14b00d99608235c2669de26ab6a31bc9c40688042b654b8590eb4e2844d2d464d83d8e2ea635b20e792b98270b6e1e43fd144e6674aa49405693d3a439165469c820e04449a08d7bb0076af2e2f6d4be797767040fa60b0bb071084176cbb5bb3b9bb58ed8251108c4c3d57d623a04901d66306d92fa12253f76197ef1aa4b147edb04d574f94189cd3be768e5e8098300d5ed05f59050fa6ef4def15504e82e03af3aa0c87ac7030bdf2b5a1f3c76c3c1b8294b7efb2f0427cd6f074bf780c0a720d6ca5363742697b134ab74888dc92751950570d5a439ddc2b4219a3b20dc08bca8040eae04660f591058c86ad201680df19b76216b9ea56ee87707924b8f027d0593c20e11acf49cb6d9ea0ac2cb7d9529e5997ee8ece122437a07e3fd2f07666460177e884ed49d311b8e2f359f92e57b78d4ef600ce946885a238410b2e5de019c0e870e5610e30d4728f8eb2c1138d599790afe8ebf0cc33d9633dd59a11762685a2880adb5e60f42b8ebb3cfae7fc21405a3b27e48b07608f86ae6f1bbdd876b7ff69e49bbae6d0ad7ead50fd7be0a36b41fadb59dc964c47ddba180d5219050bfbef0e012dac5c2eaccbaeaab15edaa67b1ca59b5a2ab52bda2cd6a8512ca4ca33e22fa95cf29fdca3674d7990dc3b2a4c79d9994fa502fb1301b9c724ddad067bd0fac003158020b86e0451318909d1ad8e2082a982801133f90d5fb007957aa6843aa351d3cdecee702b5a89da11629a8525b6441291d6fb26eed77e6c4843499a51a32647066b6f0983c1ca638de92165e64726ac43c27019e165ee705c6bc6358435a99342f657df66a5bfc0bbfc5c7b3b3c5165e023c2dbcdb169e0df7d4e89ab01556d42694f5d6da1c09f0b4f07a7424c0d3c2cbe1a301b15569506a858ded28a59f940f099f3703fc404a69682ba5d4e2ec927579c05a6bedf7c988aa98511c439b8d0925393201664596e3a76495561f13482b90ba3197982e9531945299948cb14e21ce8034236be6eb6a28edaced9db5d6da9ad1d6caaeebba8eb5844ac3a65b346e5af42d10a90ecc3bbd778bb4ab02f5594d189c5066fa05aeb7a15fd61442d2af3693bc9f9ef964459f3cbaee40427dd6ab50f2c0423c4e1e40fdf25e2fd47515775d9f3a61502007504988c04909a31b184a48d0e204961b00a1b32861c030a5123f92abd3e3e897501dfbf4b42faf0e3ded61ee494ffbd5bda1a73d7959f4b41fef0c3dedc55bd2d35e75477adaa76e483b7a7e3af8fb0d6ba61c3dafebcca4181e313d9a8006658417554c6082121c91a3312d71399a81ac9ed687655b18d4dbd51dd4b65faf3aef03c3d49822c20dd3abaec0f42a25da432f8ee44cb922893a22849e0dd353240f89e84a87bd5a1943129544902942993d253c43338324aaa1a9a9a999912153531353d6d4d4c0d4acc89a9a9a14c22088224c598580443e6c2db5d6ce307dd9819e6de6a954bac9d18bb64aa0b46d574270c2acb11c82ad9440993b1872c80d96212323a6942143860c1936a92f9eb0f7dd48664f3fb3c81112f5aa2351cd22b2b48cf4eb8bfa35bc91cc2c126fcd29a22783545259eae0bd15f955ea45f5a914684e016fbf5aad562569f6c72b5e15f68bbab72d1a2f9a53fae3ab7d51bd85fa4c27d6e5dd3e7c18bebe28fcc29a8f596bd6e5b539c5f35eab3965e8de55e5bd293e50040758a0369b3dc9c8a88cca64a428656454567f040d7401811510d0801740905199f7213b5e2a9385ef4fc95264c3db7baf66ca9c5271d6e5bdbefbd69df55e9baccbf33c1b1a75832a686a8feb6b12cab064d1b046c0fb6eb37755e8bcaeeb3aaf7a1dae754ba300a66bd8d1d7a7593c1fdabb9d0c14659fe2aeab8c924da46dd728cc4a4f4f01b88978b88974b327df9fe8f00e8585bb29b85f9b48cf707d359f7c8712e24a7bbc7b990aeed7182cfeec10dd5da5ddcab3b5eb6a79c3dab0bf8de7ee3a7d9eddf6c673d7d9ce763685c3e02e07772bdcd5c01d893b1cdc8db8bbc19d88bb16ee54b8a381bb14ee6c704703e2ae06771fee66e0cec31d0deeba19dc59dcc9c0dd9bc6c07731b893c13416be7b496336efcc9cc2cf8b29dcd3e6e0eeef5777de76295c8abb3bce6db26e5c1b77a6cf535c0964bdf2e8ab550dea971968c6de0a617b1b5257675a20201d14ccfb9c1a38372d1a36ac9a19345de386e005ae65f7191932dd63ba97dd61baafba936377b17baaebba7fd7ebec8d9a4a1abbc644a80c3020830c8c3210a98e780aa3b8872df4595fa4cf7a18b6e07ab15cd2a778975893873eeb99743548e5dddaa7becb64890fca8f87ebb02a25fdca43a8ee4775582121063168064125e5d11eebe1c6a1d9024f714b48c5a0d9d11e6b22e91357524887bd579248873d5389e5610913d16432626bb688b4357f18b1923e5fa833dce6185230703d9286c1d08285010175398404802083183c610a21e840567f5ad80c4fb0000a1ba4008ba324c8ea4b0b33c2e24b174948d8028c309a20ab4248620b0a3860042582a0029977a3de37627b6b662642df0bd6076bb688d4f0e0bb874c843cdcf5d95f39d3e71865bf91f86e1e2dc32ba9418d04ee7b483416c3fd01542a06a54cf83e646129b36479f62a13ec30ec937edf052f7eb64fc9c2ca97df656e24c3a17ccc8b602e03f3cf2c2a1ff31823d9eae4fbb3f5d9ffaef8befacace884ace5062959914f3ef7e56d82cecabc57cb6afd667ffabe1fe37eb7fb4be07d5f7a2fae53dcccb77640ce3551747d5079ec988c5212aee4473fc77b30ffeae5221c1df77fc7dfc6ec6814792e8eb5aaca990240a4d21a02394d50865f6a070df83ea57172fea2349a26f8c7ac10beedb7e852a337d0abf9bd8aa0ae04aa0a4015c96272272e8960d48004761d96e099bb5e050536adf9dde1f80b00fe17b5652dbb09409bebbdec39bcf8ca3bbbda079a919d2686c76e402118b0e4a51801b08365b45684f1f670aa328404116b87e2933ed02858829d6565bb70491ea3001f2b8a0f4523a6681339311e3e8b3be4d9d0694e5ed0d6ffad566c76ad347cb0cdbd0c276bc571ed7456fbc293b2750fa24a297386159d705eaed2bb8f3aab4055b1e0f1c47fa8177f5bdbb6eed422b73ed825de74f93962e33b78ac4e08a5b550bedb1f7b08df23c25896a54973eedcfe7eeeeddaf5e8e5d87c19d837b85bb066e12370eee1bdc22ee166e156e1ab86d703fa4b1f0ac67d6cc33a8f35c83fbc36de379066e0ff7334d2cf59ec16d713fcbc0fda631d55b0677bfd298f87e4963376f33bb5cb77ab929dcf5dae0910165a65a84ac709024b4607bb17649914494e0eeb54b54bf3c2f2049e4b92ec55f9b15eabc950b12396c9fc20d1b3a2898f73935706e5a346c58bd846bd9afe9cfe8d3f467fa32fa32fd9812a6bfea93fdb12ff655fd543f6c15f00057250b5b625df66158962cd67f9e3eb92ad15c55a2312a6343e202d81ed11e18b6ef7c40c081dcb85e80c6bcdb2fb1301cf5160485552ca8cb1e0868c70e97eb5e33dbd8c4e05c9532cd1969190eb32a59977ded7254562f35aacf3ea2ccd4a90bb6b7a17fd02ee3b93d921a344489fbf63af09ce799ea00db9dfbece0e401b697ed3cd31eb0c2288708719b493bcff407423b6608046ccf435e6a02a622609e6b23dbb954268ee3cea5329e9ba52f961ed0028bed010a60d18e5160191e58006ef575e017aeb7d566cdc2822c2080290bb2f8028b5f16a62d1d95c586db84d2b866a13df6325f603135f61d711a9879005691d51cc7beaada0ddb2c46714557ab7a05edb12771bd94051d38028babd1bbd7b927cfc5d12efb9d4bfba7be1750fe6c1895d9535389c63e6c5f9bfaf59de776cbce735dc2f6621923634719dd38e38d34df388384a1c6ab4a469414ef9cc72ea131fb03d019a54ba046c05689e7ee5c98b15ff1079a6755ead715371aa3d8be1fd6201a46adbd5b2f407bec6148211fee7e0c60eb050c04d8560e60fb2689aa12edb1af5fcabe12595950da53ec99f59f79de6ad7b314fac608224da1a44e5884f98e858adf15d2e125b4c706018f7dce601b688f3df568ad765504fdad2c28e92bb66f5cad1132fab006dda8617a4b9d70ed867c9852332300534c04a6098f7ddab6ef3739a40aa9d8a3dd2bcfa421eda1519f505292c86640a4de773310fef289471c78f4c1e3f3f1f8ccaa2f19f41c4f2d6cf55ce2f13126cb5ad6d932e88b879e3603e1f0e2591676daf37478bc1dbfbaa399bf57d2a4b4274c7da348c2308e63ea29d13cfb0caf0afbedfd7a2613f205192b52f004ee1053d2476caf0421eb372cd67fc362dddc36ebe5d88077f6e9d3f4ca238acb9267ba2645ad7d8103100849b4eb28384cbba8a47c48f8ac08c4ee5b8f6bd22dac33cb76d5ae3028fbd5309d3ce25c0ab1b8cd53a0cc3c703d8f7ee510a8eb49afce6d50d6ebf4cbbe56ca01280ca56f0053bbc2c4ee9ec0043a1b8cadd2aee255796955544b204a15652b9f74301e8c0dc66661de9576590f4b47a0ccaa285594ca4bc35456802a9b04ca279d0ddb08944fba24f1350b134d30c4d6ae3295f01d0e8fedc78689b72d5edaae0ec33749e441a0ac0f431ae699172ceecc24f1f58ea185a9a2b22aca68045930b1c45481a513f42088131e0001135734598089cf48acb6b26229c3571c9a7900ddcd0b8f1b02650dc6262a554c039c55362c707d77a3b1e36a05ce23ae3012c0f659c4f5291a040301aac3beaa5e53304a7d3616181b8c0d7bb47ed13213af86c37bb66ea45eed7a2117573385a33df62a241ace612d06da03dc79355cff3dbcb9e2f0956c2aca1cde63e2d5700763058c0dc686ed431c8efd4addbe5ba2b1637b189b85d5198c52bf1e5066af866d6e2cb000088cb8428b0a64f69e92850900a90a1cc840055834a1019951084cf0846d8c1a0f24d00399bd87646136d460065acc96d0850460c8ec45dba367c7af1bc16f4c913080a40b26a832536017e561c1f66247e9099a49e2bd2b350b0b4593b6ad614b8a3395973e6daba2b085b9852d3304314b9123fbfe38254b910803031ee62ab368f5d19c4257174fb6283e4bd1cced6b7dbfa8bebb88e6a339653c8df972c604df5d98977775f24ec95294a565a43bcc8b3ad5556651f99539458975812f5f5f4dd19c327498c39853b214c1dc9a538a58177818935a90a6c45bd3c7bac04f214fad2b8c29632ec347c6a94ce654067ec89297cac44b65dda5b212bc8c3b254b1119734a95c1bc7ccc2dc2c965a4284d18b3ceac0b042f8354c4942c00a032af338bf04e65b9ce30b8ba54461e1539fa8e449579b89ba5a8deac0b7c7dd79953b2147536eb02df99b829598aeaad39a5be9a536acdbac05b935a1b065f6b5b07d6531978f1529968d4f57784caaad64c3dbc79f50cf3ac7a1e9f4971d5adba2e87ff2ec294e5614a13af54abd555ab8e1cc999f156ac12c57ba24af54f65d23eed2b1eb296c989bb8be1cd1fb69de7f5d891449d996dd799ddd852802325adb5de459024f22caea719a47dd68e76a1b5244c8cccd85058178d39b5309919b68676971629ad8bbe59b735f60d4e8d32e7a26a6ca4b2a43d776c0798230a3ad67ab7b73f1b635fa9d67a3752a0d4e2c6e239d27ed5aecfce6c29c27ea2dbd9e1e1b13c2c4bc3da789eb5b136d6c65a1a3468dcd01c14c75a8a4371280ea55ecd31d27ed52e878e71c70e156650d6772ad441374912b4a75fe42661000e6839dc96853789114916407bfa3f6e9223684fdfc74d72447b72b85536c395e126d17c64471ec34da201c98e1c86178edc853b4488532772872871ea2ddc215866124a57c8140751e07e123e324a77648a0307e07e1227e84f0f790e45370928b3e10e3193cc684f43cdf88ce7108827209c80d80284121057007103220b209610b0829af711c054c37a9fb2cefa0d2924880944d396d206c9a559ea9f3e0d9706675d7dc33fcf1407b332761c92283c0e39a413fa8a1ce2c34482fb719fcc68cf11d671a3b9a24f25dad31fc0cdc7e743260f6e388721b762167cc4783cfb20ed40a23d56d0d868b0b85c392339430f5d24857458e8e18dfd3cf3d4f00c9f4297a6467bfab14b83850669e8d25c81aa4194eab0f1b6416760633c7271308f8efc082a33190e34d0709c10d05700aaa04bfd0a800d0767614772210e2ee338e1be906bc489f6f46fb8469aacab4f748d7cd1673fc835c2d4679f856bc4d6675f768d085d234a7df6f13512802a6c006c30ef1fc97559a6cc1cb6122e6fc395e14986a02b03973efb355c19a0acabff21d3c82d06e591fb644677b40a4597865b22ddfcb825adcfbe8f5b56e933bce511905b1a417b90acab6fc32d6dfdd3ff71938aeea3c81475c65a1e471205dd186b11cafcdbce18bba98b35dc23606ab8683d5b7956a91aee71d6d50fbae7c235b69863ec2187ece0d403708fb208fd082701b828741fbb35b098638c5d1ad892434e9cfa91fb5bffc4ee0daee136396a5707994d66302855ffba52db856f1c9a39003865261d390db7a45957bfe89635ebeac76e0bffb6e33b9e5976c7ed88b9e339a4c1a34ad9f0b06a7842906646c6e775258f6d5b6156941cc59b558fdfbc9cd1588f2e70ae18e8d9f302f75340af37c3fef53029ed0132f3ebdf2fc5af4bf1cfcd218f9bcb15ee930ee752859bbfe3661a25dcf7b999e602b8afe3669a2c703fc7cd63cfcd3448b88fe3e690e7e6efdcdc60b86ea69902f7cf9b696cb89fc2cdac1b373fd338917bcb939acfdc61e43206b97ce60ee349c5b99ce17eebe692c6cdb4085fe413678a8359a645e002f76b6ea645d801eecfb89916212af7964c5fb003dc975103a8dc5b626ea6602c21b3722f6175736fc199b6e029d3221801f7c79b2fdedc60e04c8730c37dd56fb8bff0d6cc4485c3d534bb1fbe1bee4c262a1cb62655026964a40b904427f64d8f86ebeb15a57dedceab4cbc5a17af5651008423af767bd1c64851d6dbd9aceb6e4450504dc600e227dcdd6d6bd812596b3b72c8d7b8c6755de791433cef238774d5863f901c02d384439228ac1f92732bc47688379bc56429bb3e2d3924a4b5edaabb6776b736419baa0977d7755d05ea13a85dfd168898cd660bc09d29d4afead1e82b7cd7bdbb99f50a016129eb330f1e7df6d71e5388a3f3e9deb652ec3cda2b3b000c9aa928dad3ef177458e0ec31611e4042b59a5e67b688d8d71fbc1af6e9b36918d89a1d0e1c0dbb695787edeaab9abc16d4a61ba30dd650a3701bcff5415a4001059dd7b7ce6f3cd7aa739dfb503fd442bf6af80c836b0eae2b5c6be04ae28a83eb0dae2a5c69e09ac2d50683b8d6e0fae13a03d74a836bb5b869cc7b8dc15506d7fabdd6bcb670de20f54341fa2d741d6aa1a260ea98337db60d9d0694d907b74fbf9a360109f52ba3f0aaf3219df75bd0316d7994a59a679f8d8289a39b4a9f16fa050443d6c17d1f6b7a3ae67d4e0d9c9b160d1b56cd0c9a19197526035ccb7a9998fa12a67e45d68fa2aa3e157eb7deaeb7f506031c1aa5505330f8da76f7bd3fcfebbcafab5fa5e207862955155df8aa522128bec3e276739dfe4019fb811f188617044122c07fdf876cd7755d7829df4b2cda91f6789ff53c0f14c391d6b69dd71f387637db775eae6377c5d4d8795df789a1edc2d07eefbe303563c390be53594b555445559476a22802219555c49d19365269474ae98a01624351d66f55a96be535218a63df5cadbdd6daeefe486db54874777fdfe779dff77ddff77ddfbbaed556c05a6b6bada9063db07d64157cbdd43b65f534960c5fda65d5abb57ea8adfd58ced4004496c23e74240e3d93517bd152db85ed23a3e1e9054f69a78cc6925dda65f4b4ebdaf443ed4521b603da0130dd1522d5a132b5b430f02d03fbe0819716ca520faf099e16ca5466f8d18064e155f7288950169e464478f07b102c6cc919402c040cf61e0488ade983f75d0af8128b6d5a994ee57d1dd881d6be9a35d82f5f443b7e20587e4f74fd2521ec6e4c569f7d5a49cddc2a42adabded09e3ad4f48ef68892fe0362aeddb46d63ebadaa9542a43a95c495c439c431880102da43711e5f3188a1053d29ee256c01010d68b14414616c9135494bb24a11bfafbec5dbd730da31f5ef956661e13ff249aa93a6ea539dcac2d4c9d7108627c31741d62af8bb18a6561fea549d599893767dff5629277d660a85bfeffb48f32bc2b2aeb2cfcf2c224bf722ecc5b759442ecd96f7b0a83f9a2dcf2ca27aaa6fcbfb28debe687c5f7ccb88bdf8a2fe784a7657bcd4d61294b4cefafc6e5ddf5397655ddf1265a5f5f91dfc5e8fca5a6b600f78c08b5e9de9aaedae1d4dd5b041fb759e57c31c83eb58d29efa9b7e75b857e0440e4880edbdafad949d0aa7c0990fa7f0978bc09f59d21e0f9b39c441d42f334d9479a6cfcaa23d75e6bf19290ce807610e0ec38359ed6a1ecc84426ee1faef5906ae17bfd71884808b41085b5017c5f51e0ff63c2898d29e6f48f5fecdccccb0700c608c4175501c031846a027c5df3dd06c3dc4e067a6684f3d0bc030428969ad35a40d2bbfe08f0ce8967216a999a270550a9f7065834fd87637db2d2dd5b0fd538ff5b3b5a71c88c3f6d66b9cad59248b0485ed1b673ba8c6355333d9b03d94ad36a8a828dcb75d6db62a55257b1a5fa54e37dc9920499b30a5f5e1d308824fa4fdf23a100471984aa5cc20400c662ab8fb70384369fcddeb2e0758300b724bb89528fb9624d220a83abc5b7b7ba9ea68d3bb0d82aaa36f1b4665f56dbb695fefb5ec7bb7defa6c22b0f7beb83e9b48886de3b211f6ec830031d10dfb24a20fab970331a4dd430aa31ea53456434cad8b7618b258dd1907d3eaddd01e6a5ffdaeb3b69b422c71b70cdc2d7b1df885fbb6ac59694f15c1154b960b30b07d8be008dbd0de11b7bd32b8ed9dc1ddf6aa707725711b75ed1c9020085e6e576c60890815caae0c7359b27a85eb3f0afb280deaaa8e7adb6789295972a0e959373406dac83d98fe607a1c0abb4c752b75794fa5b01723bb850d59977d183ee76003f7872c8ec8f19715d0d5da7dfae47567c4676e5833333737ac9919d6cdcc0d1277804875c453b36524f5f045296a52eb328b545352579946b26a66281da6afe00d4a96859dd6557f9f3087d8070765f8d473883b5b61aa2e2566ca347483f4d9f7c02841f39f892315d2a6afed0944ef54fcea9db1307b7a5aef258d89d80bc2de5916664befd6f7feb36479370b13cd9498baea35f445b308fbbeca2c224b11e153a7b2ef5da73e334925ebda5e56d94c94dd2bb65fcb887dbf28f5f0d6a7c7c525a2fa50b7175e2af36e16e6d9549ecd7be8d9faf4ee79ff59b252b7f5fdb63eb3f5bdc83ef5a27e78fb81adcf34629f3a0ef62913877e6896a0a4b87bf570b6c325885427c4f43d5e128bded8d7068b762cb5a0803746018697f6d89453181ca071e076c52fc6b1c9b1af8c0656e558ef19034361564994f5de3d71d7cafc5b984ae8b4df930865a9d7c8a06cc109b03dad3fb0f5818f6840b2d4930865e093f09185179f4b2dde092aac0619e1ecb5e0046a1775d19fb006fcc1150bdd155699af1ece63f2b4dcbbd19e450d6a338956ca52b7f7b4484aa59ebd0f845ba89e55387bb7ec85800b4f04d54c523d7b23503d7b5d5c5b6355f8aad4908abb7a9dd3f3bc9497c262555d1b596a4c65f12e7a75f4da8e5ecbf3ccf6a0bc7858d8b08705539419184ae985a3971a3dd55859d08107e0ee33f8bb288ede38d6dbddbb1f49576d7adfb51755a355616b0f647fe2fc13dba76e55b7e393c48fa668ad6dd58b3792a96eab9aa239657cea53c4ab6e242349a09fe33dadcb5e041fdeaa9e7a91ea29734a96fa29e055af6651ea53c2370d7bd94b5d5ac5cbeaf5b488d65a1fa09f26b6efc15261c7d29e83f7f5bcd7d4350d9448ed29ec00d9e6009e995338d39c35abac33b30d26bf8b5f509aa4caa918b32b55b314132729264e96e49c2cc9657102f4a438830f48dd24274cc49c0adb3b01534b98c0e05ab1f479185f2ce4a4a06713a338d2e0199998264c26edeafa45118d51d812ebeaaf60ca1819193358427389926e0553c6c8c89801471a1206520814277dd67be1b377247db60d4a6ce8b3bb0f43bf2e9429ca4c9db8e0be122f88855c959085dc1175516ccdec3dbce85d254828ced4e9aff07d252a1b9034ac5a4fa684c1f526d12e539d89937e555a82dc91ea3924edead76b43957249c354ef3b51dd254b649a5b9531323248186646901c32624a7bbc7795f6cabed589a1f79cf27ca8cb3bad6d3b2f87a118aa56990a062f8ee4908a433343c1a049698f67e6108b2269bf5a62bd25d633739d5933d3a8ce6c000c9080eb3b1ae28e1cbf4be411d9ee29af5cb2a45ff69dcbe57ea8302aebe7ae26f1042ccb3409b8cd1696c8d193e26ab6b00417aa83e2dce16ad2f2c3b4a7da58200c4cc95bc182022d4e4a68d182232038601283892c4f78e124a334f0c2011a0f38e0041e3071838b2b52f0012d54200610aa103e63ad65cdccdc84e293b84cf5d0de1b96cd125e75b37c17bfa7bea7be535a7e0743229fd9991d498150563cc3bae9c817a80c3020030c746177468853745d67bbeb68d8afca6285e19f533b4bab5dd77da813e069e1515514ddd9759dd7751d092c8df6d0d72eca7a6aad145dd7750ec09ed94d33f0baaeb36996ade96678e1fb34df0c28239449c5a84a11665c91e46a84114b5518ca84a18c309c09439a309c11863561c8b209431a614863654fc1af69745d67bbaeebaeebbaaeeb7a5079211443d35285d0964f2cfb9ce91768f669f80c84ed0e6c5de5f3c5f63614c6b2aebe1547f22b98dbb3682ce6e0676a5409f6d92c1b96660e532cd690edd453a9f7c07608fe7e5c5eec68ed558cc9a23dd6a634b30160ee0c3d594b56b79c6142deb1741259ea029a10aaa1ddd05a4caddbbdf7de7baf699a28bca6a6c60903915499b8b843e5265954ce663393044027f2a430d6286e2c675d312a3756afdcd817ed22b1143306460c876f6a1354fa35e5fda05a10521096205b90154204dd829682a8c0fda029625c1a769445caade4a45c1e32339f9a194c336e3838383838383838356ad4c8b9cc4c86265393416ac240bc66e5c640592962ba34ec284bf86ac58c81ea970a87a932cf7c62250bab4dd4082c595865220781261b1b1b1b1b1b1b1b1a3468b45ea758da19ebeca270176844a074e8c03366cc983163c68c9a9a1ad68970968889a889c8c9c2aa959e226e832412c2c8a8885392c8e8432da6d038629e8e6897d528c2c784d1b098a77e09f12d5508f3a7690265d0ac5f421cf5ab887e19bd5a318fb23c893db937acd18925c44daa4e8c5fc430c534c53859580cad84922143860c193264c8989999a1f9e8347e313635ac3e91e3064924850a157167ac57ee88b3a3ead58a39e2fa15ce804b36c02bc625314a7c2acbb22ccbb28c898991390882e015e04d4711cafc23ee18c34b63384c85fe34c5b434ec284b9d3d8923ea17590cd72f291f7dc66ae55628eec413558a1b34b3aea02a3748881bf4e40661e9b3bf430ad181ab116610ed06650669e0126003401a5805ac81574024100b6853ddacc20d516129efb0671fd41705cebe1b8d2180244992244972b55ac1fc27063db3b06a45015bfa358453bfa2fc3cfd84f193a308e049a14b97281ca3152be629c50c9ad9a0cc3587fb35d72f29ef572e2dde48c1559bac28d5a62b4a504041e1b464c992254b962c597280031c20bf5a51b272b3b2640597428e5a1b7069d5e1c3c58da58ac46ca92a310b79e0e14b0dbed8e0cb0dbe80f105075f72f045075f9e8c64603403231a7c71327a81110c8c6260b4c5c8c9c8e9cb93161b38023c575c3d8aa23d7d1d52480d5c8f941ac0d480db0e3becb0c30e3becb08312254a04f08ac40c091a123524900670a327a3262327a39c11172328a32e4651465efaf5645667b42f42c07da320ecb8424789094c4a464ca10e3a8c318131283046156358314605c6b0c01849632845814094084491c018b62853447940142aa26089628b621b43290b146e499eeb2d0138530a94518d4ad40d37dc70c30d37dc70030e38e090c313c09480a6043825e009c9a32845418a628b728b924594a5285c44c145d11285294ad3181dc0fd2858a880c54482aa2145a98536d8204610c410430c2188c1458c21884104318a200654f641fe41068218b9bc83cc83dc831c46cee59c1850565c5b009eabcd09ed402c417182823b72e4c89123478e1c292a2aa2e14e6a4e909cd89c28d5f00c959f722e47652f3ecc7c38f281e643151f6a3e2089d104dccf4b5861acb35bab48312b8dcacd4e4a415734ac4a6161358a3f8718862b87810a7af6b3c5a312487d2a41b3b07ac58ce5ac0ba95fb50aa656820afaaa55ac80e6a01aee29cc9c12342bf74707d4f543832a56405f3f31a0b50aa67efd34f5a9839f1cfce0e0078c9f1bfcd8e0a7063f4e3f3488e52c2c86fb99c18f0c7eb6fcc480c6ea02deff81018d5523deff79c14f138d3d792c96c36108e59f1fe0fecf53ff10a584311c000010c311f184c513079e3af094c593079eb478fa00ee1b2d592559946840c9069e6ef8c9557201daa30403465c2519a03dfdba80abe40ada6394041465083389082947c01da2c452ae803b040b4b31936a14a6929b757ddfcab4c2c4c53a525172b3f2b4d4c415219e536b462ec4eda189f6f46b90426ae01eb22dd3628821861862882186186490418619de83530f4f3de47a8082c240bcc8952c5998122525372538255a943029f9424953bf84785fc9967e3d795f899385d52aef2b79b2b0bac45309705f891722d018d6d97d48222954a8d4d9294944e5435d831c92c242987546bb4f5e197085784de2427945e246f9ad4cbc46e0d6da2b046e13af58ee103faa513c89507604f8e5cb1759961f5e91b84f82a032c315898bd45adb49b589ef90dba1890811224488102142c405175c78e13928e570cb61298b022ebec62ac50d3a6a5743f16a2589a099851d552b6696297df693b86c0729248543938821c7018703130e4d38cc6ec805091224489020418210111109390d4b34e06860a2a1e967ac579cb85843059c5e651b705275e2e20dce0abdca08c02a7349ae576e53dce88e7e458aaa484f3f7efcf8f1e3c78f1f408000197abd72b3b0fac49285552770f50a130e29a486949bc2a28f1f546e3d7ab5722bd2ab14b73ae0958a5b97787dc0ad555ea7b83f5bdaf5e488ff34595895e2ca0d62401437a81e1171282cacfa218867a1f27ac4adb35331a1b0b01329541e6485c68a783fa8091a337a3f88091a03e2fda02a3406e5fda025682ccafb414ad0d810ef0735208816c480a0248290a0b11fde0f3aa2b120de0f3a82c69cbc1fb4001aabb3f7838ca03129ef07cd688c4a8de239480adc0faaf58f1a05d2ad565e1d708f866ed501172b02a6c07d053c00f787a002f7a360c17d2810c07d202280fb4612c0fd226c1dc41d8ae2873b24051177c8012a1c12953be404ede94bb9434fccee10144eeed0952280a8566e7493684050a298568e00d515708728b1ea43dc2158586526552be610927525d5274e0b65158a2b7728bc1fae51509ced931d51bfc8ea1397e21e65a90b30910451bfe028af469836d4a0149fa9530d1c2447846461b589f7896c16566bef1329595865e27da21b8d29e07da22cfa35c4fb444bfd8af23e1117fd82f2fee1999aa003b84f84050dfae1fd204e348680f783e0688c88370ce6e3739ec7e1f331d0330b03019d52580e3110100c76f20c837b38790e710f27ef51c3413cf6219b855528de1faa59587de2fd21240bab4ebc3fa46461d5cafba2d068a55ab9f833aae043f4a1e3c3f3814267bb068e0f1f3e6e7cb468f8a83e7cf8f0417f7c564d1ec5ad50bc5eb9d589d7d94daa4fdce82655284c2a4f984538614ea9351309d72be052da93804b698f945bad5c222ea53d08b84dd498b0e1fa216e7d142859e07a212eedf309175596b8d4ba54415c2737775be4ee05b81e889bbda6cce4df7ff032a0237b17c0b589e9c3bf33b914fb7029ce37ff004bac28e1be016e7e017a50c286fb3cdccc22c0cde700be34e1be006ebe921d9098e1be0e37b3f289640ca47c1c6e6002536605e0e6b306319e709f869b5f7404aa86fb00b89965e4e6b3087d52ca9721061f38e13e0c41b3cc7281c80d946ce084fb436e66e5130591c112eeb370334b869b90707fe8e603b9b9c3e247bd72cbacdc5d2088aa2087fbb19bdfe3e60e0ba09bbb14c06e0e5f3f11c0c570413c4b2c1f1d3e4cb89fa3e7da583c3b376eb8ef62e17c53bba9ddd43a9c83747e9a32cbbc3534209c8366efb0c091c914877350d84d6153a7587a874597029ca90970e18c8cd189d55da0f302677029eca620c7205c0df7f71475aa55d030aa0de80a813070d55a227495f6f46ffa54e5fa6ca83ebbaeeb4c151753d5a54f1dcfe89e063737e2027077f742c80edc999f3995aaa83efb5995537981c1abcaa93a54e5745cb8ebbfcf0b570dbbb443e87ca8e6687d707d52713e8d173b7035ef5466307fd6652634d6e19044aa9377a054b88675a7f455e5a9ea2b11ca7af0962a958a62d567544e2a959999a82e8a4d83b2f3ae3233751ab203871f6ad00b77907690682c543d75d52d29c4078726a53daa5a31b883e4bd8addad587c25894493962a1ca699a2962a7c7fa04ed807a7213bb02a751fac32739c68cf0ccaacca71aaf566eae48355e6907d2a47e584bbd26e47553f22f4a04ae81a76940528755a4ba05b2af5dd860054451a3254943dfe1de84d120199b4ecd11de8861be86132f96ed87b77a0fb01ddefa91e406636c2404fa55e8950a684a40e1ee8fea0c2611f5207dfe3faf0bd9a30d85f2f265c73f6d639ab44c3b3c5c1903cdb25d891678bb4c3b3b535815ec1517da69ead135e70ed8267cd25c8b39dbd889eed11ec86674b8b0979b635169edb49f6dc60083df7137eee30869e3b876bead907f73890e78a6b97c37358f45cc26c7866c59e8f839e756a78eac78f949969e08eb2fcf0f1ce59188e92753581be704240cf8eea17ce52db9985e1e4b09de1d8198e13b6e106400cc03d3a42b1088e4428c52e9ebe602840af98922fb0309059ca4e4922164ec921176bf9e39424f2f14314c5cebb01ea479475751728a62fb6dc00258aff61e6521c3fa3d5ae20c510a154e1702e67a238440808514ca23a18e4801095cb819e939353f891422250660a04260330512030cdcc868e7284b4a101dc7cfca8012a080896b1500314911964e6308809c4cc2536334b66e6b360e69306361898b286a6c04906272d4c34054e544b59c6621769edb6ac275ca30952139b9126331c388e703992bb01ea862e3744f52be62368c88160190b411ec66048119a0ba13911cd8398f904820bba4170b4078899c3109bb92c656666b158304333761b0282c33dcfb15b4c8ccc584b19c268c1d3eb3324910c4f7d768f1e30180c067b9d92443d4c1972af2b43187d368d506924675d4f4e5b9a94ae30928591a599999d9d1d9e671c27199eac2b07d5e5862eed1212c220463372eb97501896258bf5e713af7cb0ccb30f967906c2ab1f5b181be2f1fc63c33f3ed440801c08e87508a58f53920848d1cd0224876f1c899a21814212852487e4090918489c90dcb258e242860c1a1a9a146e80ba21ea062fb321166440ee0d5137749119f2a3c9ac5f3ede3f62407011214441828a08210a1254023181f041c2f70789f6f487dc211d16b29539e4e084739e69e08a8a8edc23b923384a7f9f1e49141228245c90e4906841c284e40b244d7d764cccbdd7cce1de00655d51d685c30c071a0e5570a85924cc8289042783b2f52647fd1aa2f5eb47bf621885531a540354d5d147a186a51a7201b0e9e8e8e8e8e804c026232323232353fef80c4934f419724887854ec9213c359f9a8d97a82d4e603ce1e0e0d46842b3ae26b526484db0f469238500d1c403a6190f98686848a21f426636c24207224229f4a1166b6aaaedc74da221cac98c67665d4040019103220c209e96b8c06961eab36db8b4cb8a8e130292a4f19206ae55c36d42e3396a58d1fb3cb3a27b43172a64de0015815286a77efd785f8630fa35f4be0cb97e09bd0f4453bf5878dfc98cc67c04790e839e4b20cf2c2c839f8f6564cf27960962e670f52033972cbc3a1033b38e57c766feea32339f4d446f22164c23b78e41996d44f9b83b51443672b5f24a89d4a78d28dcb791b391c35d0e7d0649143e163b101010508f1e40403d7a00f5b8f9c4401fb24077e894248a7da857e410211388a63fd9786a72d484860b430a69fa5353934c69b3d9624821b55a4d063924cc9fe1fe6c85f757f8ec8eb10b80075d23afe126f98f9b7494c39308653a1c0992fbd0e1384a163680db004a30005c006c31251ca60670b3b01aa0acab04f4858015d001e0fa8500a63e3b66e630a434b0d5000a88dc0e1708a8a2db8401b48915eaeaeb50241504e4599e3c8152fe381416f67128218ebd89151a9be1fd264dd0580cef376182c66478bf49151a83e1fd264bd0d80bef375182c65a78bf4903688cc8fb4d6834e6c2fb4d18d024091a2bf27e1324682ce8fd26473406e4fd2647d0988ff79b2c80c67ebcdfc4081a8bbddf644663a10fdaafe02e7aa6439002f79bd4fa47d1fb22006e12a43efb466e921cae97e41e25b1d11d9d2487dbb9d000dc27a204eeb7b004eebf5005f7616002f7656802f763b082fb33d4700ed702b94990a03dfd483a725431e3b5e4794d2d799c92443b176b46ef123dbc4244f09ab8c6eda3d9acab346d85deb9d2b5aee13e0f0e1a2ea4466a2bc8b6b5add5a23182f7f2708f34ab59570e13ede9a26ce1542fb4cf1659a3a25a6f55b15994b4cf9b1cb385a54f1776992d5a074ada678d2bc373ee0c77dd18ce7361f8ce75e138ee0be771897c85db82cf1df25f23d7718b3cbc3486168cdc1ca62237674986db3a8ae1b660b8ad176ecb85db22725b482ddc16969c1cdf905b69cff71c92a875f15e8e5b0383b7066e99f61e491482172707bc37a78171dc241d6ed626ebba645265b22ea6fae4e454a16e2ec52d1b1cf6f01a15975497acab511851508d2cfc8128ccd0b919c14b836de0cca8cda8f52b3ff71c0a423b2ebe0a57f615aecd79dc9fe3b83fbe735fe7a1f19cdbe3352ed079b84b4e807b808357060d1bda1202b8f906b85556805b6d49f55614c8ea23c9ede1e11572ef12bd7583fce6b270035c2a0b7d8407b857bacdba647846f409f500a251bb8284a54fd08b92f699e3c6aee306fdd7dee70a7dc7f57115eed057b8df795c1ac7715fdfb93fe7b93feeba36cfb940af716107af0ceeb9493afcdea41d747868f3edd08335a3d5906c3fd2fd95d7faa409ddcf826ece52ece6dc6464c850f5306fcc96e999614e2637b3f951fbb9ad2bb785d427965b9d7b6fc404c56e5a1e88877c0805c56e5a1e78c1eb834d338511e7ca9ee3fa18bacfc54241b19b9627c3433e84ccace33c7f16ab2cb16792423c5ce2f80e49c4f31d7248875d17e9ce98e4f670f0c2ac405be226fc770aa405b63c5ae5b4df96a0852e1ad721896cae430ee95c23cec5cf7185aee3dafffab8cf1dfa00ae012e80bbc30b7075f8aec2b579cffd59e186e7717f1cc705face859de7f6b8ebbecec33dc00970977c855f61921b121541b19b96f79c534e0dace345c74b139a40633427ca87d06f41e66f31f3b71bf3b796e999bf81e66fcfe11eb7750454a555b3e14f789392d4b468d635b3b9ada3032c31c00e3a78b8963b8e83240a8f831cd2e11e12df9bd4430f4dfd27504adaf269cd789e516b7db715ded6d16dd15a3ddc160fb785d4b2b5945a05b82d1ca4100ff798ad19ae1c71cf4deae1f726e9f01df7b5fb2bf733dad3c3c31ecc27b9b450a6837924eba2a1790f531725edd3137f7398684f5fc7cd59929121432523232323233383c595735bb3a32ab52b4839728037856bdc7a349bd52ab44aab3ac85a036f8873a7f89044f08ce005718dcb83929ccb6409ce0ed209d48757b814eff0d041051c666b0604d442d29075d9605d7d15c8227daa40be603110202a883a749044f6e0f5c1e28e11e7dae7b83daee3c6fefb739f1bf47b697cc715ba0ad7c757b8aff3b8b0bbee8fe7dcef35aecd935c2a03af877b6e5292240f7fbc90a8f8077ea32d01f4ace3e6f96c0969cd6ccc703feb78f1426334c74b929b03450552acc73ff0db123420f3c66c999e199aa0d99abd6eebe807a4716d42f073591e632d73ce8324c2b9d81ac1db619f9b13457b7a85833158bd0f36addeffcdc1d19e7e8e9b033ac1a8aa284b18d009067482019d604027189898e750a975c5755bb3db3ac2715bb4dbaac2e3b66a544736ea016dce6d1df15861e47151f80ad7bc0a3785efb8e793dc1eee736f5cc7b5f11c57e7e0b5b8e7262979ce4d4a721c376987f3707f23c0fdd200ee7102b867b2aebe779368a14cc94325af91e43c3a7c6787dfdc2142ec32937478eb0e1162f36053bf6ccc3a06f465e3087a824e16f69c750085d9b0426b166683665db67ed940eab30afab241053d5bc779fe2c5659824e79464dc9cd81ba3929dc1c2f3939dad3b771446a967adfc6cdd1b93948391b34f17d1b54f46d208d3a749ce7b12aa77a4e957b0e37f93ca3d69af190426ae09b39b71194e0edbd95f680e72189bc8b3868ed55f85b03d3873bdc92e8db09bf43b26e16d60ac3b2fc2185e8c02d9a0892fc90e0ed17782b0e6139b755e3b68070ccd68c8bb23eb77af4e080f1c04c58cd0c1ad88c0c180c7c924b65e147c3cc46d8e6d6c6a4ac9b5b4aada5d68d68d972b6c849410b29e702395ee42ca145cb9922670239078b9c20b4d3b7a55fd6a95f2018a1d981adc2bd4077508224c01bde9a3fa87018e4c2e5fb3e10043bf0a02deaa24b1710b45ebe2eb80b089a455d74b19db52d1aeed6ac5d6d6d51175c72ad19ee2f6cdbb0618a021518a31cba22b5004af76c369b416956231db44c38c2224da9c63014492c3e9e3f25a1e76f02b8fb37058585b7fc5d017afeaaf478fe8e3c2f5e17dcdde3426121937521d1988e77f772f4e5f3aebb5da230fcee164761b277af677bfb79b617e0f16c27b0c2b39d0277b74e509888f4caf6c8f5dc5e76a8d0bdc3a03011675d340a1b7a775ba3311cefde4ff4d5f3cefe86c678602b25ebea8739debda3af9d1fef4cf08d04dec6b282127cee2bb8af34961ff7280b18de2cac6dd6c56461bd645dedc3cc3042b7b02c7b98998573c8046432c1cc7ce21c32e58ec27d11c9c23c9a75e12cccbb5957bfcc9cc3fa3133abe461e67205a450053387e50e33972e33b3441c6ecfc907b8bf52b2b05009d3a850d64526d59c75e57a46d6a83ea370dbd4279b549daccbc963e11e1cde9df1859706ec57a641a241a2315acb5518ae9648a2551844aba7fa843be686fb326a5839b8e639a7e69955f35cd6b0582c968d28bbb5a9ca2a599956297ca9ec16ce3ca9a0ec4e436bdb2b93939393a3d27159b41a271b376cd8387f162b97394c81e646a3645d3448406ebd5525255a9363215dbc78f1e2c5a73a5c2a45d6a525954a1cc91b83c350258a23b9026fd20f0ad2eea9936868686868509099c95836b0a4c112de128be348ae602eccd28d766f599665696aa13d5cda6547925cc1942b164c169ec465407e9e5218ebbc8e3be3d3b65e6a5bdbf289f3dcb99828eb62d9626e314a31b31a39357298939393a3fa6aa97fbabb3436eba241a241faff9f06a926478394b2c26623575cf4d95f9144aba53e574be5128e89a1f5d997c4716370314b31b525fa45e959c362b1582c9bd517ab25eba241a397c2b02c59ac8bbd64c3adcbae0cbe3234ebea30bc89c9dd9cd29b531f53c7cead58ea6a662905e393d3cd0a88673ef3a6c9cfac195c684f4cae81dc3a23222a8409533f6ead595768c2909526f6dc195c9f1df3989898189967cf2926675d5e64c828c39bc2a9cb839225392831a413a8f08678e722b1c129bc204edd2043e085a105a622b2c887792e0dad68580c9776751b2871e498dc8981b27b3e817c66c8172ccef1ce5472dc4a12b92ed28c5502658e09af9769909c669c684f9375f57bee8c128d7cdf6b9246d25699b56a98ffb82c2bdad5dfb92c5b9fbd5aea90ae96faaca2cc2c2eb8e85766850087606669264763a9f262299662298aa5d89931b4d5520a0c59acf0763b77b534f3645dbde2a25d7def168665c912bd5b09f0f8ec39c574b1c58436dca7e9316798caee200e9086240a6754099479a565c80d5ee1fab43c77c505ede987360b03f2bee7a47a3f54ead76aa96160544ea54d0aadeb8a92f659574b161693cb313952480e8e8142c12deb8ab2bbcd0a6fb549faf1d40f3386cb8e19933b41599f6372ac9a1934ac19192c56784cadcbcc46a13d6ff624f01b3668903c07c8d470df5c2dc56c4183b45a5a2d1de7989c67450609f769ac56aba5182f707f464cee0b9c6372bd041931391a9c637231b9150d15ad05e7985c1b01e7985c26718ec9f516d57de2e1bc5ac25dbf52af8dd46778a5911a4b5771caecc093301861d06412922f545b9312eebc77f7de993f7c373c03f5011e6ab3452488fa058737c2dd3f32ecb3bb91471285af537066c2152cf6181e5712a498863150b86372edea0f045366ee52ffc02f2687bb1b03a53569d370b370427d24091c0d47c32161c1d570b50be06ab81a161c1216dc15dc152c17c082abe168381a8e8643c2d570557057b0e090705570341c0d7784ab82a371e1d2a54b879b75e9a2d4a50b6ee605378b8ac2cdba28e1665db870e1e2a50b54146ee6058a0b971c1417123c3555c10526c1d353152c521e4a8a822660c122eda1a42868c215381b89455d38e50e3c35c266f7ee238bba70b24051174efd720ae3141775f104dea22ec2482ac1d32d5d80812939043469775d77afc420d959a0ac77ea93e2a22e9ab068c919c0a22e9a7051174f4eb8a88b2db8a80b30ca0e8337c26651176178b7a88ba73e8bba68ea9711a6b8c9a22e9a684c51175ff4498bbad8d227c5e0972f5f9e803bb3a88ba63e29b61e0944aa639b56a0562b1a169a63bbcc1eab286bab4563b43b23d0b4f8d601b556c144c5843a418049ea3b1326262d2b134a836a32a14e4ceef75dc544a552a90e9ec9f5e163727d60c284c97df0e194c69a3c754a63097818541bf0dc529ebb3a7b0ea93c8f579ecb289e59569e2fc5f369c4b30f4e2de099079010cf14f77af24cb53c204545ea629d5da3a01992ad4f2b94ac4bfc404b0e01a382519f3c266a4ddc0a2bacb84759ea16f00bcba4848dc98aad895c134d3df4d0430f3df4d0430f052840010cf0aa844d0925256e4a902b98324646c60ccd8c152ed6b06c5812880004cc2308607935e256245e17706b12ffd9d2aea32c9501b49fa609fc3409f1d713b352b941345bb32e24296e90cdba8294fabce2b6c4c5036e108e8a1bc464c31b4175f4a1b070900c2964060ecd201c9499dac009071c9e70c8e10015c4f3895bc02d04f1ccc22d04f15ce21682780e710ba741bc858b2d1935465c05bc4a71a13811e234d040030d371ab2e8d71032a0a1a808638c31c65826935d88cbc28b2015b115518aa28a5badbc5240895bc4eb046e7da2885ac52b14b752e045dcaac4eb13b74ee01398c0451b9beda294ab7ab5dda32c4c5a35558a542952bb6135cd8acc8a1c99346acc0035439719a07850d267dfc60660cc909b4169865a50505050505050909090908fbb907301ca852817c078aa41a3c9852617b6e4b4a80ab4b8a0c505261b518650c0c51b3c2e9a4f5c8a296eec890b54975cd02c965be1414704fd303ba255a95d41b259585de2fd18180b8831c59a624efdaa461415c95571ab62a90a1c05a028e0f4f3f3f3f3f3f3f3f37abd60af11c05958b572a3464e8e1386167c989872e4e059fa61faa1f180d2a143870e1d3a74e8f0f1f1d9711f269f261f2715ceb3c483e361e2f982a789670b8f130f183c4f3c399e15e03e4f0a68d00f29e4904452a85039392485c38b2e217c7865c2c407263e08f1a1ae52ae934f318519d3f2f34449214e9ac8051912c2e512e2da786e3b503b4e3b3b3b3b3b3b3b3b3c3c3c387ee37663e906aee7f72a59d8bddd2ceed2e5e2e2ae96cb749b6e0770ff6271dec5e42293ab73b1a24051b0f51657332300874c2e939b24d1cf963e3b0c99fc3431b93f4e52bc5eb93f4dd6e5647f9efaa7a530635ada25c406366c5c2734836637b55bbb486ffad28d1b376edcb871e3460a29a470fea676837463b3b06ac565c42f4934e5b7a6c21141ca879a0a15a6761dc59afaa7eb957b9445882771594c4bff0861c6704eaf5523926897d5ae2061b159a1748302f7839ca0413f3ca6a55d1d9b80943aab52984701a740a854aad68e9341ec989a111140000000b315003030140e87c4a2e170a4e9ca0714800f85ac5e6044980793248f619062c6184308000000801100c268da000213c7708f8a8415793ec03a432131e00d107f000ded1ada506550f6ce59756a7aa02a638511f40086048d988b6f924a3e00ac0553ca5fe0b845356fd845ce22592c3440b650b2cb2d0e8c790e326edfe3c2fc03737c5053855dfc521ef1e51fc2c6f8106d1cf2e9fdef4876d23f64de721dd3cb0a2573ac7d996fd408dbb20393d3d343f86ba4f6691a43383048f2c34cefbc066a47279f1cb2a96862ee2d88cb948065551d43b44f1150ba173e5364448052915502faa5fad7c93ccd215e52a9a2bd7cb844940f162b6f64502451a8e40c5ba71b5eb5b5d59a80074dd1d20f86c9a7931b8b835b0e6f5f14de9f91f3832d6fcddbb5ea607a8439213649f498057d74c396113b7dd9f68bcda020c5616fa5944b0a301d51120cf5faade7721bd97833a8b9b913df30ba7bc3f125b071700fd8c953da80641475e23156565a880d39335669da00c2e4f448904008b6ec6a207158f0ce8c0a21439052a4530c024d952f06c11f843b2ce6e14e12d5d7ca88f894e213595120d379576406a0f1ac56bb52480cfb23ee23235afb7c0c30b696ee5dc8e694079668308621f4243ea505267afcd591388820eacd5b02facbbb2e2d44e0052f35d3043292bcd03345098c99388a9bf9b93bc690a3920a36890117f0cc60f8e497efc6dea7e3fda8c9bf9b1e50590ea42614fc6977a6c18368bcdf45a301dba18d06f201740785570bd660b83a5b238bef353488b133ee03ca92a432ffa559ddd39cf176091b514218d99688d8d780abc57246b281439aaa127480f33da584c42c4e7583c1491c93ec4d0e496328b709e6c498873531038b199ca67fa71833b5f55927821809f75dbcbb92e1b515f03aaafd4d0d1c4e8f9b93383571fc017cfe656f4d5db4d2b11abab7e69407ae7cacdbe0a6da2ee66675d4591d2c375b4dcdacf47d0e02d7d3ad6aa9c65fded05537cdcd5cf9c1c30faeb1723e44f7dd635fcf73b466dd0276f353c447756326a6db082b0c3930ebca9d484f4c7cec6a0c8d05926ab8144aa77215b0d4c8c4b2805e83b6f2da361918133ad2159ad0453a8e48acda8291c1bdad4955e8d6f266d367d23943eb7756e707223370a013b1d3e8471c12547424dcad5cfbe7abad8b990f117ae444c8a18d154552d5755a43205402463ac7565b51275c34db3fe24d26a3e58ad584d038378182afe6d534138bfbc17a29308d21d592cdfda4fcca9eb083daa0ede6e0577064ba140c8f478c74871f25386c991d8c127c0797ce658613e8ed7cfa4f4350edae109d4373eb041900f3088a36aa0f04eef31a58d8f7c41b0b7cadc61298ea5672c0499c80943a894f484b8f5208ebc6786d4cbfd79fd05f258c500ff6e5b90a87d255c8908165510b6a941486a3e80eced037a33ac50fe2fa1435390782111aa20c34ca3baf1c7d71569b98426545257ef1beb1556012811e70e8ca01539e4d6b863e4230104259f697e868e861684cf15d5bb6507a5e838643df941f84d4acb39a70c694e8c77813dfe4ed7e12653b872eb27138b08e6cc64818d335554f35e9ad7a8de315d83c65bc567605054cbc93b695107b725478ea56108b375953408d542a472ff98a4c64535411a67ced6f10d7b87abd6b1478a90610519296760157179c548d10504bb644b635b1b20e4821d104540259700fc1f40586a6721e80b8627b74ab3e32f0da32a364eb80a33d051fda483c65977d96f1d6c696a324d89166999e84fa84153b18836261305c444ea4390a9002a4a0af3e4dfa9744a302493e697dba25e963152d8497d3c6cde7c2f22971b760704c4cef3a834d27301e2ee04c7ec16ce0090442d309520e304574eed3f066052afc0dffbab33a600c420234b92ed15f880dea565e1502fe2f6404d32b117b4d45f3cd90c1c32e2f1dba724d0c4c2db0e8e849aaeddb7498c573d29c727c5ae32c4be1607fc37b505f46ed4694040361b0814e23dd8706cf1b5b814929455cd2d75a395682117a0a964ea2c79ee0d5d4f8d3fdae9f18d6a50b0e7f46aa30b8cc65fcf31a0262f429b9783a4abcedf153770a8a2886b0eb16474a158b14e76746b39083f2104e10e0a3c1e093b6d96bc5803a3bf38525664acde0d800a84d0bf2574878dc3d875d2c7ed44877bffb49848991b817085fd6b7487129f23abc1a4b017c4bd902cd3cd23eb4a2a09e3b50eab2be291a30f8804511d55dbf03b9aad0b788e4688596c3c6812a3b9036a0d9cf8518819d63854e9430d9c9dc8390c58e949a18efbc448889599d635311f48178f9b29c12bc7ff7807bf116f39b912553307265f6d6b14539f91b667aa36b1734412048d9a52371ed3863d4261e09a804da9126024615e0e9b5e73ba1adbcb55d7df7d1d1beec751fe4ba9227545c3f4cf3fc64e26affb0ca7155c33ad27498716a80469b9db770dd81a7be3b9e8f6ed83e80d562c00e3eee80b31ca45b8639e826f304af2907751de5fa5835ee983fe9c25dea6331663acea19ca446bedcca137eed78d497b8a279410afb5cf887bab02e923a9449ddfd2e58235ed869fb51a1a5166e2f84eefd9a1653c1cad4a2d2d46859bd4132e5ebf4cd35b28917c0062ffdfdf12753c7da9298739b6e5bf178c835ea404de2ff9823a30e03e53f100e7fd25fa649b46a5b3e71ea8f16a00f917d6b0e50949dbef0eb8380ec2e85f5205518e187323bb64186d8c33a041ed95d4a08cfce655a99f39052ddca63973aef4ed35616901e0afd8f0a68e899ffb51f930ccd300af899436210fda5160b014bbcd036b1dc912040bdf8c9ba7d93227b46980aff91654a6eae613791f18b1bd4e9794d4e78501991d77f700003a9c81441dac04d20bacb09d7bbd06f7411a240b064fc5e321c0b3e4ed0703464cd01be0b51c1cb933941ea1c8d4d7aca7140cbbd7c8d9f1e501af69e7a33aa8e4c285b1cee99e842346c94451931401304fcd4dca0dd966a88e1891e4343845e1f095df7b0455024b31022affd3006c80d1a2862252353f40a450857ca14a8872cf1beec177ee99341c8e5a51fbabb1f0cae6abf126acee9651500d7b108321fe3cad141cf47895cfb86c71874631b4f0ec2db3f8969f0ffec6f1f40504aff5b56cad5fabbcd6678be6ac786f6f847de4ffe1b6cf60e16eea16b4be80475721fc8fffd542c033df0594f226e901f09ec97501df5b16fe3f9728e16ff0cd07e71fd2b767f643d74d5104f95a5fd194fde03282022dd5bcf1cfbe0902d0e6f1459d77cf15fe3647698e6b1c76dca6c902bf8ccbca14e39f593117c42c058d1b160b72517e3b551a0a8f71a7863d2ff5a8c61f88afa37272079ae742c51dffff40d0434ede3351bb98d677bf168a0acad58cdf88ed72b08071320f34217617a4807777dc557aa3c2d2030d8ac5205a2a4834daa65704207b2e826167268102eb29b591f22601ee3ea499b5903d0aebc7ec48d5625d2a311c64924d81701a3ff40717c482862630e825b17d719780a533bbe2b4106a43f209593d1bd639a4ee24ba96fe1a17df9389054d2a25b64e1378009c3cef12fec5697ae1e9db9989e658f6764a6dc7c22c43acb0af2141a69cd5085aa774dc32330bc3658788045d21ff20c74a833abaef162e091540cf0b20518837130c80b91e4ebf9e2c49957d83a1dd21b9c5c743b923ff7c15aa7501a12eef94c5ab3fed62d08a5dcf603f0cc660e5bec0c791e7f3d1cfd267d2f7d8dc0f400ed1e1e223d45558f7253ba19271b94b4a1cbe9bf1a85ddbb9093d3a878f47378b76843a229c8d75c316949dadb35e247975c081fc353c8b14d8adffa7436f91f131735189ed1bd08e8e18b2be53f446dcdc1f1b910c79e04130ff47b6888d4a28d83b1f3a66985988d2d38082f859a06718d893749d487b040eed9099ff07fb2b0639a4e679ffa18f49417c95e1644a0cb1f17b5f37d596925fa928370c4745462a954201b02d111b0f63b943da5ea3e51a7c24fa0a85a8748ec4cb8c33f3c211d08ff320a64cd37ba6dbd108e786a7d054332de00e446daf1f8553ab9785e4836761eadcbaed735caf75784edc343dc0f76a76016435133d5a8311931d4ab02f213d8fba78928876aff48717371d6d2789f89ed2082e9f919801c45ebe88fa399571ecb9e010f0d50fece70d4dabf43f75d75d8e7cb8d6a6086f2a11fb59380b87f68e6b283aa9b6a2db18059e2dda22c9674f4751eedc96eec38031239d2f34a639b30230692f01010cafdfa6c05c4f051253a0214042fc1bcb97509c6851975dbe45cfe7efaf2b9a2a243fd5f5dab7c38c52472d134e9ecf57d60c3e434b0d42dde0f2d090df6eb050ccc007b4c115e89e87b5bb2c0e40d7a087d443f01f806a2a3762dfb540fd2f2a05a31f42743f5bd511b1edf00c66daf672c1a03c4cb1f577dd609fe510d5bd3be201a2905df1435006df727bdd53cc76e65bb13d2f642c3131256a2542329324866069841ac0b058f9c728f93bd22d42eeced609be4ea7faf1f2c723ba9cfd37116998e257b3e960fd53a849543c488dac893c118644d8e0629459e2b518c24686ae8809eee99f10b3c9c4d44ed41513641048911cfec658e4de752a97beba20781c923e90172ac1d2169c26ca730b74de59e09d47c6936f485a30c2c1b225b2ee066cb703c5f762abc08311a4e441349bd5c6d09fbf6e4fd022819a353ae3e1c91c7d3c201994fd08ee03c9d70ea3e39ad8cb4c289e4e50fecf7965ceec05a4ce40313832706caf490e363d14c86abd120732675c2f7667c7ae07084ae1a988443a8f524161a1a43ea7f3de052d500993dee678ea469b12cb7773a8016b8f7a97cac81839d29fb227de10ebf930464c717505010bd08208965984d58c513fa34dc5a6c54b9c16365e565523602ba2e4b792b8ae36497e1ba8f2ead8f7da9c76d464b4148f4f6096d318e306cf05a367c1e83b3d9c9a329a99d32e30c37194a2534f14858610046a609ff200208349259bbd519c0e748786a36d3cd3f301fbfbf0a03070f56d91e0d0e27bd8e7ae31affc649b234c37533b79490849a5718ceaf8d422eb5afeffde0481b6767bc0a90e201a15fae479d3172fdbfcf73a172b3f7d75f4aff00d321540269de7619bcaf44050510b1707456f9328d95315f54e8026ec440b81903212a6e12905e04e4438cdb0d16adb051d1cb51219dfb693043eb2dcb8032979ca90075729b58c71a51969bf77d2fcda1919cee87c955ef20d6dddf2b8aee588e50550e40540c82fa018638d0ea484529cffb7d866f51e9c11dd2f5cc3a1439f17c9f89ce77d4b9313c01ca60fc0a22c09b10ea885d676af006c08e1ad641f8bb4e3a0f791e2a8133c2160b9afb3d4530b18bed49741fd84a2f8d8d41c018173da8f7924b9e4f7e14038caa9c86886d520451fce0b2fba06d5b279e0f2d9bbe1170f76da2e2f81c34e95f060dbc8b61813b76c9e34311bea0b0f0d02bcb1fa66d0e0e563dad8cf7c2466541efe74640e12d67f83c64093e6d888a48a0ae0e1fb0b7e64c4c03891389669d5053b14167a4e2c5fdb8ae61263ac5a64c5e71a3594051fc031925a40757d8be8f29ab3cab486874a1a59bb84c788b102818c64e0c5609a4b4f980557166f1b9890780567991e106fa315dd7921f12c3672228c6ac487587825067858951c7251c383ac67533e6ae8616e647384f8f98e0f62497c306c774f0162ff9e64d2571cd80aeb82ba90d3eca7348eebac4753fd78a69bfaa0a5c3cf20eae81539cd4567de18f08ddab183167dbb939da44e2039c1785c645efb702a35e43c5eeab0f69a2ff61b1b943213b19d091a818850404db0fdedde625c54330b28889b7aabe3699aab5d0d7d0561198883756e7437b6dad3110e6fc4d6099b88b0a8684569fb38ab308c708e0392c36abad2a26c982feb0386b48b55aa97e64e5242c39c15b276d5f1993158348a0efb1304d0b9489ae55e9727787662cfd942cce33ed8650ef04b000321be2f47641895cb083cc44a2fcdb3d713c8bc5c12898ca0ef6e5734e8978362d4fe0b11cfc6c8d51496ae92c37f5484c92a41c63cbfef92026f645ffa474553746b775c793245fc88f9fe0651aabc02d7499ae42401ea47b6efa018e926c8e1d17fe40e629257495d16653013d9578baead9a78f16a523d84f096156c9e57e7e06b08ee294dad929c3b72b17db081d3be2063b722bd817e2b83c4e55fb16fe10f1563d95815c8e88c2b0e76543241cd81b58467594364bcb1c04f82790ad3e56df26e245a7737d6150b16e84f5c673cc9ee4325e3ae3c48efd033b1acf94d7ac1d2a1c9616350a386cd8cedca007663cdd389a94e8759ebe991701e8ae110bde27a231ed56fa3483791aa04d244992ee99a782ddcb5073d711e90443d9e61d4816327eeb0e9bae672d0fce680baaf457e708d3eb26371ce91937d569b937c55a7f6c3d54a96f38ff731e875d3b9f261e676b4aae7d4d0477bd84169d8b3b052fb37e8d3c0a04c8c70f6a2341587573b75134ed5658e686e211d965766497cb65dd09ddee7bccb80379e2df88281af0f03f6cbd4a2ee85c1599e82ee95ff9cff85de929686edcda5ccede3d90ab1edbb6d9e430e2549ae9c33516ec5cddcac69ca0c8927f9cd127c76e434ceb8d3c22131190d52a9b2accb10088570aebfe73a6e6488d35452ca0c83c0751d08eb86a173e01c5d93cf50bd64d451ca3dc8851d53cd2d3bce63ccbe6771ccceb47efc379dd645e5f78336a0f79c35759dbd4fc9a5e722880099d8e9326f2641d52e05ddc691ab2c9aeb7cb05ae37978ad084f6cc89e3bb854003e81045f142eff8cee4395279d7b4889a13b2e462fd8a8e1d01711034adeb3e38000e4bbf3f3ed858a9b7a5df53798c33d23e5724498c2be08dd6ad469c9d33e64fb20cbd69ec5fc9a720ad8498ce3040321b53c333c6b67b938bd5274fd1ce16d6665c801ead46467daca640a99abc48970178a288adbc93862e684a3962cc867af0bdbd72aa3664ff83118d828c5e364c7b254281d8dbf77fcedfc640b5054aee2a55cd0f331d74bcc353eb7a8a9fd77ca115920f53b0d59866a57faa439213d5c1d9e89370f58d777630277363b35589561dfbc6bbab3543228847a88a625a1daa71f3969f1dc75adc3979d5479f728e0627bd87557d9a8cdc657fb21107a42d1ffa5ef8f157605d3ed1e9431467b2b86d8a02cf8deafb0c1da9b47e7c5c807079be84440dc28a689df4cd87d28eaed853cfd7c8c8626a78acd727def0ee23de021fa928a686918578472a3d18ef97dbde8e1310f514bb637b68b611b74f2a159075d565c57aaa1e35e1c8f31e56ba60d28d9604b949314126251e892d19d168609947fd00b5063461fd5779ddb4bb3ff84646d340eff874c4960b86e88af3b9a1e3c332a739c77c1c440ce01a60dd5241b19caa3048b6e755550309b5ecb27c62e64d0821e4ca3d27c6f9e4d8151653b82b0ddbd2b42d3ea205ce5d34092362cde6aecdfc64704014cd2413693110c8c78286b773de30a5159d0c3bf9f9189185b253210b45a9fac641ebd1ccfa68bfae63d84698f794704ce74ad13daa8dd15b19011aacc65e0fb098c297eec84d49a300734d8583a526136124f86643aad9b6f511ccc1d7f4aa64c1f749c73db26daa63da34d61308b6581601494aa85d7d2d751bda5e12cd210c58f20e654794ed735d82dcb80ede6efabcd2080c3ed0ad42a4aa5c01b41fc31616c0f8921ca19098800a7c1654ed38a913679c42526c26bfa9ec55de13f51f6f45af55d83fbf2057eeed76933ab06f0a4d6813aaa1ff7d3400f9b1330a2212533f1116fe3c717105a902a75200680d8d15608d626d3d64055ca3acd08853563ba04555db8d9b48407868fecdf61342a4b06ccc02189dfded841f43c2e9152e8ef5662eaa3055835aafeedda78c96c3777e803018f34e2c4040301855c231c4b27a918ab09229136360960c70b40c446f62e97589bb209ba5d35f069ea4643a2147d66545e21d3a8bae44c01806b93601a983e534e286292b58191727daf8231bccbfb1c2862f1a82b6af5a3f6910b9902e8986bd1b5799e0bc0cd331a436d50836aa45fc2cf01b3891d9f3ad472757a7508e17587bd5788d78e36374fabdd9222cf171522394809f3f4adaed9a981441c8a1f497a61382d8ec1682361cb83cfdf8c68d6db48baaa967aa2dccd91d7f178e9585b178be319c37b11440b05d81042f0c1b2a38160d3504889831f0014f35af84d204bebf09c515db097a20356ee42dce5b28a0c79f57d83580731f0c1d210eb6f6ad167ae3ba15f654c797a28794ddd0afb1ba2641bda43b6d7c00403657c4892807d521170bae5b742f065fb4331d29c718c258794809aa45b061a122cb919ad9c83344bf8deb6651dd3aa12cfccbb7d5a5cd1ab12c4331fdfc11e15c333c27c0dc9111e035d668a52dbc3731bf54fc25f046590df512ac4f12d44bbad3069f0eb2b1224e043950097209d450dc598219c031c2b2a180603a538be650cbc2132cac8c3c1002374bed032c33948e6ecc75b218eae9e10faa73aec21c0243478804acfda685b6113d0a7aabf5adec42ca6e48f770bdc9704fd29c1a2b6a908d953bb1e484229153a442e2c4106c0cc618d6060506eb9422029f322b8f656460f682695c380a3f60d3a774ee5a5cd584550d3a14268dda70d5cc454646cd0d3edb4cbde289149b5295a67c417589906d3210b801b4cfcada0cebbb1bf4117b2ec5c23cac33954d4925f688fdc657763d856b66909f65296e9068e9b2a542ecb2914ccc0057a4bb408072fd7bcc0772b9a7fa8eb34277ab9da2da8be032e138fca4adb90253412418debc97ad005649c67c771e9e016bf97c5b21bf372dfb9e7fea7a2eb851b62902a0980f35365b98c122814a66bc97eeb7a76120bbca976165bf80f8fd09f1ce060e7e0041e6f365e3f1708b1c0e36069e46a0061bc48f6ceb23242881bad8405c56d3fef16c30854d543b510db2f9a81aae7196fd9b5cac3eca65abec28b91282a7088289266cf1107a1b5bd81c23f17ab8db434808ccc5b67f823dd499795a5185c33ce9629300e87d9a622675d6416d22405ff8e422e170aa87bebc55284d8ae98863da071cc332c4b2a582623955e1902abfacf1b273a4e13c48a3ab51f1da05c1bec7d7e77f61a232494e6da4334229d49713cb2e0a49f5c2b4a38467d3504762e017b1c81ad8181b246319a9f2eabad6f46ec9db4491b6b18278fe4b8e621b60d852c1b19cab2c067d595ca55181961ce675a88c8473d1e0348312c778187f65e7ceece6945e528473ae985b06d1c4b160775389e7f715c41bb1c5269038204e406bd8eaacee2aec96b3783eb9afc24bd16986112bbf3ed8a939114fd59738cf6d5657551e689d6235aa1e4b5cbd04b2f53297f105fe39a96f8031a47f36a7b40d634eadacc5738ce396b481c8aded28b258b9cff168b54743ac6eb6661653801dc1397b23dca8eec331658c9ac13f0699a891308a5d3d13f5c419f7812822b3cd8e2c9a27d543c278322f9f3bbba5e793d0165aec518beee8ccbdfdb5e827f33d25d02759f710469a79f8b172e213e856dcea32c6b0e8d87d8c08889d2803a9892e75e9daa39ee88140d6f20086fac814ce821c541b44004d78ccf7c2c304cf776d36de93d3d583f1ee9b79137bda1e3d87bc8503101df0b705e68ecb46564f774e568c81450cbcd9153767643002af322ab433550b2f0e6b16533243fc0f702533808ea61481473f50bb7470e43b1300b49c6a61ba8670fbf8cc673d815289a1178e040313aed02f1828b283c1835160772a80683915437515e1fae154e01f57e8933a8348e5219048060047724d30f6866401216605b8e5591621cbf817dd4c639ad98c43b762b82daea0195a0b0bd41f8ffcfdc28d10b3822c4cbe61dd50b82d52fa821ba12f9c300c1c9202e07334ef6981b80eeb3aa83c2135e7f1e9df7a27819ba696254c8c339ffce3d5f3382a0e8a0fc866de87279fdb343706667672f4c76a2ef3ac5ff81d77ebd91533f342334738dccc62fab8b5afe6cc2e3633a463336f0f77d85459e6f8d7641605fdf631372f66ebbd5e8d1febc97b31239d68ccc00e9f1433e514c62c9647d60a6af18f3a9d4ab5986d673cbe37351262a2ddf4f8326b870e7a1fea384b114cd47e8fec54e0c9729eec384263e7ef9daf0a1a1da519f9e52084f37703bc45d5bbf252431a005615875380ec1ff87dd1e1ea159ec8621ae0baba41243e98c5dcf13d17bda765e3a19560efa3133e6f9f4c93b55688fd869fe8d1c080e0fc871d5fcf8022df02bbd21cf5e6a7b13875554babd0663a331ca188796e669a72b10fce92d6dc482205a24d67e8fb1c3bba4add41767862145928b23c9e8f4b5fe23725dd47891b4351e988a42b45f32bb5fd15fdeb1b7d6a63f8ec088a6cfc5cb1a08f37170d9ccd55e7d4e7c623040412516ca9904f032f4e6715582c3e707fc5223681f5ebe4fabb0472d1dae9cacea07622ae03d0f76405665d26cac5e95657cc4b5aa24fa868823b1cbd421a71513bf59b4b50a4f55004b841b947828372f9348e9021f33912b0bbb06643aa832b8491cf515c8c0a51929e5624b0620db5c62f010842c53448d7d4241b858344bb0aa0accfc0b1c23f65070ebdb6037802fdc2da45d995de0d46214a8e3274f489861a12528634970bc165dd1e2e18c83fa9d113992364c9c2986f63cea92c99b7110895181cbe076113552aea4951df126bd19d6b3f4eca1d9d1d81f2279f8ecc084f5a2cd788ba3e28cce1c935b2cb12610873f972b044803d3c657bdc0caa69734cc63283f10e46240f8899e1b47d979d2cf756e92a87aa0ecd96abb05cebc42460bf2f1d39c87a38ccd17b5ff395449e34b0663547c64d39adb14166948703a5e2dae25c6c6124b09e7943cb91cb50f5acb56e356d195a04170dce8eedb12a4b83a8d66ecee731f3a8e27dec77d1825760feeac75aaa535a7d79249332a3c04691e37fdd5b2b4846238340ae38a8fd5f10feedeb53e91266b97e3463735280711808341b0fca14b88a8dac03f86eb8e678e1daa7d0977e45ac8462e899690f18aec0d4318380a88c8d25b284eed4c44959f410f66ea2db3aefb178e79254447acf0556683a7c401bae564d4b158af36425a43d3c3a10f3e40b13e172bfeb35ee041fe73014e92d311f57e4673794f97ef79308a051040066cb74c2633bc2c057088cfe98b700b0576c6d4648e22ef33d7c201cf09028a269d4a547b0a7f636f4421b33f24abfcbbdf23417385ad1d893f2af6fc8f5e2de67f979f2c0560d78e8ad78644e0485febc25e9f80bf80ae82f7148dac5bfc4197b1e9a609fcddaeccb03004c460eb11cf851b7058d12911e96d21421a97c8ddcaeac84bdcfc638620da86e4f68d9f81e221270dca39522f46ab68dd5c3498a87941023f5c4225b125dac7a4212c4273e410402f0394520010876a50a04e1960d820915ca0082e5ee60006a869b40cdedada15ec3c6143331f828a5de9c988b831b21f22385328f925af94f0f56c723aeb99a5bc81bda215d070127e33a739c40a8f37d3960ab012f8306a55f930387a8a4306310d0771098cc3fcaa3040e880ee23b834c068e7b09101792b2701933ca71828f3d42aa1ead2235fa9121d4a26459344d0ee55e9745161f8350afc9919993cb08f7e5eb3bb8f7ef9e8fa844c0ebe70012c4ee28ece5c3fb143cbe2e870b9cc0d8d3d8935d962c3eca9cdb21e7b982ed5fb3fdcb0bbc219f0063d7e102cd17be1315036faf0dcdfce8e2e2efe2d9f3133bed9f4f0ffe0cd256f14c2560af3bb12d7010c6ccf37ba0b5a11289212e17b701b03b15d69f5cc23018d1bac3d0b6785ca17eecad39c9f5faa82da42ebc91e63c0d8995c1d092e499788edbe0d6738dd01979968ac89ccd1ae3a292c6a5a9d3db7da15aeec76834c545bfa83667b69e8d792f296d14c9b9814412614258837fce136f8ef50fee357e17dce30d15f94c7096d7aeba782ac50c3d6764b35d42d36926f29556eab6c81c539d559d00b1d8e831f638f1412b8cb55bbf369a0c0f113e522fdce00617c32ddcc5f86390e8ae9a6c77b6b5b724ffb31a210a71abf2c96ca67ce580fdc9e1064da5cab12799f37571bbe664ec4c1f85089d83abe9da53e163f4a2fa0fc1eef6500e5e2529ea19b9c693dcacbfe520cc556a692814c9aaa1b3aaeadedd391396deee2c7871d137e6f6f0ed4bc69784d77e9df8259584cd8035eb04189bda26eae7d104d1ac203af097e8f94f38b076d992e40bb5ee7982748d9a15c746290933ea84b3bbebe02b30f0d7b640cada4aeaf905c4addc44ecd2ec06f6fc4e2b69bfd47208c02ab2d5c809812bd136cfc2bab9a0a788e02d424160eb21c620d9bb145b12e5368f076033d9a7ff485b4303ab424c6f6f5379d32b74ea27229c96f1c6f3aeb5438e2da436cb4a27139c395460c36599874307b237c3bd79d282f92a764118fa2b4f6b1098ce409fc241f42a5087b0c44404938dff51268a289c3cd3c054afcd2adfe98eccf43c3ea091a417a0441b2cbc04e56620d32d08d097ce40238265c328c0b1b082457d5ee4a52bf3580191f898d6e1f79fdffcf3fc601133bb6b472b22ca25c3eddd0fba1dc7ea987611e474e3cba20bbc5c2f6a651181283ed275f169104ee38bb7be44f00c987c5a580f4fd53cacab616432975a03f2b7d3cc68431e38baa001617781b6694a96112a5942575aef3912a569c8395bcd78bd3a025b78b83e357f33d9bb33f469d48580a7dfbd1f25bc9fa7d1253e68dfc3024edf03fd47b026f5ebde43d7ff8679a4a3434eb2663c70390991ddaf451a34a972f448375b0260690ec190390a76aed0702c3a509bc2f253a189ead35027140ab0f62b064ddcb82cdc0848b0a4b74073a5da26519844399b149ff94a4b98272eae3fba0fafe94863b33c0e9def807d5bbfe420e5a1bd847753632690374237ee1f4feeae03a73de26382054142590cecb469fea3982a8fdd3c615d56a311973ca88d502dbc2ba3bf7a82146c7a0ef96612bbbc071721ac8aeb56356493e4d2404a95958055affa0eb94ca16e0cbade353dd27494042ec79d91fbe6e58104bab1dcd5e5bf579db8d95b510857b17f7646bc2aa08de50806e58f9829af5260a909e2ca0f5a572da2b6bbdb1017f21d1390bfd879dce0784264297e8528b14e780f827ba6ab16c7a38ba7cd76be22cf29831ffba55181a7cbf2b05e8e895ec074f9efb77ffcbbeda5b9c3a19d26417ea9af0caa65473753fac59146be4f31f1639a45d08e5672b2b825a0bb2693cf34a8d5d672c50197a6a8dd97bf2f7b07a7cac0b1b00a85ede3c4049a2c9a18a85b05aae8ab35bb3c7c955d382cb8965e9fe080180fd0d7de0e8fb73512129c1e27c0b2f1c6737cf2fc27ffa145e3f80deae6db378d6bd365197c9960a8d0438b34fcf788ba3ee8ec3d2ebcd827898bb15eac0d8f7a9f49b7ce616acbe8c53ae160a6c63189a81bb757dc1a8a0e38f1cb9b2ab526b374fad5cf5acf52f0ed557dec972c7d93adbf91950b92c3e4c4c9f2dd1c30f7ada10bb992fea3824adc12743a20c2b9f301b16f5f2f5760ef44daeb050180ee7a9d837673bd541148b65efe3ea4f5c61303a691f54e5a60bd20967264ab17f93ba2ac74243d201485f0582ff9ec30ae5e4a2703b37a91b00758f248a703d5db001c9a15512fe5d840a92b7b1c6013083c3ccba91b7d84f51bbe224e62d4e953f45e83ed7ba8c3f6847bfc84fbc87012b8df872bd7279a9751a5486b34cda37d79f8db3d19d7172031cadbfa232584bd31cfc4d7d15528e95710be96bff3d06594a8d47c531a216061d0e6eebf4bdb0bd32ff949fdb021ce6da35160cbab1c9f399b44481851ef1d3934ac3b45339e3dd1a6cae4d3f4b9c0eab8fef167d9ea7c5a24fd44ea00a44433eae1cdad78dd9baaa3b45b21fe33414bfa191af7b0795ea2a12013c2afac0b8345a5a1e0a56f85aae11221f20eb0a9d92415fe24d572a3da1e0ba2a573eadf9ae57af3e937cb3f7b2ec9fdc11edea67b26849b171c904c4f535bb1be78d0dee3109bceecaceb9ea26963d44fd57923c8a88cc949de7a0834f8f60cf60de618dd561cfa2b50944d3845f7a938ad8c94e64db0fc6d7e1611c3309b2f5caf76512f6fd1fa43dc895285da7a0cc297088715032d2525885c09943834d69966a2f01a032a58051e672591a28e5f41e1489bfee140eaec9e060ddd1720d291318cfe3e4c243c553ca8a944cf7b80ed482b779d09349d566b27fc59c64ab39e7c66f24abc52bbf2125e9ef68116ac2626a9333cdc5a6c8199c640023059274e615b3e84e0bffe263edb559f8e4a2181dc713f45c1172e54ef94d261bde092abf3c5c51c23d7a06ec741903bffc23357dac4c10c47764ca5a9e044d6439d34644439cb9fdfaf2a33dce1b5f82282cf371b33240cce7a9ac3ad192e6bca4e21f3916b8b2d58b9c735823fc20815c2b97087de95b86e80db38c3913b6207f7e737b43f4ee063f0e91812b974b11bd3ae969fb222f248c1c8be0fe1cf4d9525b4816aaae140f9236caac109d2913cbb19fe49dfe78677a627543e7e3fbacdab7a9cdb6cd3c240f0c8b4449085c437a57e3697810293e2ed0dec10edbb8495bda1779085e8b764cd53197d2f19250eec143df901602c5070b17b8d5e74878de4dfc55f7876ba56c19c771b58f4ce6e5d2a23aaca9c3b3b4840577257c3637f2fd4ce8ef68804a96e67d7d942fb7a355d8ef593dd991c6c9f9c5f7ab42fd3387dd4fd6f6ff10f31e1aea54f5bbc8f31f8fc08960b8bf9b7ef6b2b07f34e97a90305e4c18be670d4b10076073301988cf21abb88466192f780c86adb8f870f0681c9220262df509df7ca0ee8de72da41b1c3771b6aec620ec083014149759dd7e6055af9a126795854f70f124729dc3716413442887599d0e1160603132b2eaa2e83deef0fa55914412c06f4868d4f6a1e7df2468174367b1ea584dcad13d6856b610d4aaf638558faf09c5cb32377ac0db56405c769639adad8855301509d1648ade5473b00566d4e5e56d94d5aff86eae666422bf7ea31cefe69ee4665a09792929ff2640dd4d0bd4020b1ff2879cd1228774915bb483434646653f70b81994fd77b24d2b642eaa8912b1e5e2d0879ac46da8a8f9fbf49b1906811e90cc6bf931ab9df8b1043491c6c3809a6857a6bbc59f9ba51ae0076f9e226c578491320acaa5a68416056331572c8b2cf3fc26b66da5832674a6162956afd767234a3d26be513011276b907c80a007beb60b533a63e22a87dcdf037490752889bf61e72d67d3546d0781c64834610cb0e0f00c5329f37d7ec50f3da7571bfd01451509940498b1738870427ce05bed00d3d356ea324b6f086d8f0506237d5a3ea44018382007c809328568040c498f8b8f1e8f8e5faff1b4faa7a6707a224c331332df87e09d63927c3db798e9765e74d6835e00bbc1b94160822e84dfd9fe874d04fec48f6c8447288e41d18cf0681fbb768fdf42f77a591036fb97dc990fb48e95117d11f65abba31c2ed9479e17141b571b3090a5bacb63bbda038ab77ee40e8074d8fad6aff99c6df566114520fc853083e265bfa7cfd9d17f14cb147763e07a15f867696934a7512e7acd0d84b22b583afd4ec72b9556bd576c18ad713bbabd862a20022a11b7e4067cf42d544890b6546154b6d7f601920789a0c116e2f817565e6b7006a9553b14e10e63f7d8a28d33d85f9abeaa3bfcc1a53c27c377e6a9cd47985724bdf9860fa0c19191522343c54087076a6ee7edd05143f4efc19c6d941dec516d3bac64080e83edde49f49087c07d7a2a18b5304557f0679275b66df6194abaa6df1ee889864cd98453f5c632c22a81bdb87cd41c543bc3c8d2284e0c716e9b286b086840e04b60ed491fdce60694b2c1e7aaa56b3098d013bed5eb1ff5a2bb49518431a903bf6bab86f5b525595c50c7ec9cab5cfc25a763bd4b0a74c855aff846fa42ed2343879512cd2b956424bcc79a8d4b3491d2e177e45ad6f9af62c98aa3833e809fdc3e36e94ed33572720c2bf3c7375680dc28ba4b194f1065d016d99b3488929ea6d4848ba27fdb4fb2be9ae879075daa41b94d28d1494a2b229a786292d94f3d86c95a238c8dda88cc5619655811639f0f87c69619fbb548ee87bbe7355e6023c54dfb3efe74e2fafce52a05a9f43da6ea512b2d4313740163e0e50774d8c866432c40bd39c55ad907e3f95722ee4c818bcb009fd6fa9025cef5bdc3a0727812428710f5f68b3c0a94e26c23d52428c2b03c19cf2ed0542ba50b6dbf1dd7b06fdf9348cf7d891bcdbd10205d4ef1a6a8acb017ccbf6e49f38e8723a9582fe62702489160a54cd32fa36dccb0ef1af1fe9e1b56ce198bf7b1235e234bbe0875afe8932f3b9c4c25f4fa5e4ebfd0b2bda4fe441d8e3e85f4b0f873ce9203685a56830fde82d5c24a8e843d05ab8436b2c6b09757b00e0e8ea713b5c98467c6f62de396fb0af78c344f54a4569eeacae5fbc0cd230aa131dd5d89d399643c009a89e7b05b35bccf809a34e3503ce1efb87dbb554d7aed64658bd0111507ba1c2933f2a9526405bcb301b1033e22d5a3127cdc98d9db6196257c751c850b2482439b77749f34e6a76061fddf4683c0b6cf41146df00bb2eea4976d0d3ad9081d3354bfb01e8b7b256c90e636b3321dee024e95a0907ab8536565a500884a15e95b98adf0ea0e0f70f825e33adcd29b27deb62073539e0ba3759e16eedd1755cff0eb2b5ac6ce78090062b65ccc7c9f0521008de5e91e3e8a844969dab1cc0f3c62d39e0f666c10e1d23b4c27f1e34fe3a589f969c1c02e7db83d785a6eeb4817ff1efe7f75e445f22d6fb9220c3bbee804496f0f8cd80f4086bc5100c9249a6adc888d424828abdfc86687ada82fbce8596b7221160ee8e6e65b9326887667ed36691a343b6413e353f7abccdc876b469b5af3343e54531736f8ffb7fc41ec65bad5c727932681399ca53a71c164b241fb0989e4271bb385644491e262fb4c89a1a6704a3855c01d5fcabfb53c37f26491887754801f8c5c92db221e5bed89c82ac0a9559ec729359e9699c8d8159405643162eadd15e23baea6490a1af61ac5f3a2e9e879d214ae15e22090679a28bc696ad9cb2eeb17c57b6b6bb18e01e94a21813357918b10c75220f16271c00a280b9b8ae69d6ed63053abe38564489c8005e35ebe450ee1773028d63d70d6ceee2e114e0434b6a48513d0f6ab81fc7474c04c5d709ec75a8f825940206c09eb4efb0e92abcb7c551b4302db6eb8830b10088b298b9136c42ff7d348acdc887f7ffb97468354f28897e958d7e356e6e84f48790a8ab848ed4bf95ccb8b3290e7510e0a56e20485587f18548c5e1b52d8ecfeb5bc2d3789e09f5ff4a9cbd743eab07d7fce805258d028acd1c8952a270be0625ff1eed7f2ecc2cf1e70155479dbdf0c2622d973352be399f0f99e9f38b9f05470dba4c05f58f1e15c5b879b0c37140655543a408bf3afbcf1bd3659bfc0b2cdcdde4818102ce2128ab2df86804b032076d4230448d3940d7a387f86e4a76adc1dc100b2d8c4140f4e85fbffba80b553756914ee4d144fe0adb01d2d3016b84e73625274a874721c6d28c123586121720ba2c1f5d0da543276c21a9616822ae94c6ca8f615b07498fdf43a4f0cf1253a990e9f307df0f5c889a71987c2915abdac7e8a8200303ae49a4471b3c1cc4bcd5d6c67ddf2f616ea1b8aecf3bfd3b60d592becd4207646016474b82490967355e80acd29e516673815ac900eb81dd4f4957472e862824ec0aba03d38f8fdc140c53f7e0307328bc35460d2863b4182cec87b8e7b24d09be60e68b6dbd9d29921cc53a0213179717cb659e5bf7a2cf17a9d5209826623ab868dcf828425f1ba1113dfec87ad6936ef76de2ae33004367ca0e121b8d66209c4df06907ce9768da1e56aa5ce702d2672d04d098fe0f5503f150dfdd0c120f39f4f27b4bcbd877478653965079f4c26fb4d8e02f756ce4cff2d6fc120cf0386d85c51f5964ce3a5b316552afd2ff28f2a775d68dec2e7f8aa479bfa11ff19cde15a0ba48ce19237f9d77f5e4056030cb4d12942d24777a8ef2bb9233da60347743d9e8adc78b6ab5bf371e452bd106e0d6d0ae86805436381d40099a4188e562243d99d787214212df971fca14910a1c28a8f01ecdd248c488da94d338432223104a30fbd74be107d82c8640043395319404f4f01394f88aa02123afcb243073291a2cb7a054c299ae514083f7480d4a7bc7f7b3ef61e22f7a5002b50c4e6ed499112e9426a502a33fd41588526c8c909bbecf524c3866fb990bff22034b22ed262a660a836206ab6fe0f4f10538f1958527c73c4a19c97e03a514e889b20f03cd03ab41108fc56c55f715c68202097e763686d6f1cf6515d7aeeaca682dbc6616e8099620105943f00427c271cdc8d5638f9c691d8fbcc6f452dbf8b9c0bbc4579579039a05630b2f02ede646e92026f08054523063e9af8115f0121994f73aed290f19beffe2a5839bc0858a804fb2debcd3217fa1c1d3b08e163871bd18bc3a6f456e37a288fbec4a70a85d55d299d808d1f90050511f617e513f004a039e054e2bb526c524cb1569ea768f3a60bcf181b14320385060dba61b54af07ecc710ae9fd0430b09f4d0c36c793844891b10b23e2a5e97e0afb54dc08d54cf6138ba536730729fa2f75b118dbbc3a812d407b26206e7591414eb076a838f9a1ad398c066ad846edf04e3e28d990f3dfe08bc112ba4ff2e65e5433a1c103014d040e099a714294a42867c814242e329e0f8093c05efd82c976f0cc1a3b737314286e17a58eac1834232e8e01c27f3003b6c1a79a2e58e54ffde00c93c2be732bce0b2b35600e07a0511eda9074dda748adf99cec7ac39e6ff0e954f584643eb2df0212d9b27acce666ffc2756a7d8413d988bfe701c58b49ac1233d71514eed4532bc2b469000c6f0aa77285e46770358e9d16cf90510ddbf2e6b07ea76e56737c8535bcfa82166b810fbac58cc0a41dfd2031c3d1eb2eb6c89b91a22bd6577a8f305e57fb83ce146345c031722596b7fb26afef4175f282df57df0bace42e24157706679b397d69dda4d26084ebd425716aa5dbdff78784f4bece97d7a478047eaa1d4609693b97a3564f395fda7ca546bc71b3fb3c4f3edb314d579316fe7fb1aaec614bacbf8c7c1d5120c25e316bc7eb73cf71de0f1fb522ff98f45e225600652c2ad36b74069be59583cabe22d384c780a5569b50f568c9783a35cf77c290d580441d5b49730249376d0e3c32ccbf2660945876cb0efdf502c52b289eab1fd246a6cb270604b29191836b775b410917aba6b51d21a1d730ee8452903951daa7e4622f4376d6992400663375ada3dbdd06833f19a76518ec9ae93906054f6c3092e575d501c910a9a9b58dbae1418b90bb2ae78b1b6de75f7e8dd3fe05987d223e5891a8603034be0d0d4f09a9db9248899b519f62f3eb9595e8588a4d3f727220247d5fe302b8624223f7e6055880c82d6a94341fdd9d5085288a0136ce4428403f8d3edbc61c462849d0121126bcd10ba33c3ca48b0f97d7ffc839db69e279d8cf4a926a9e5501294d4d13998286b60f431a99c8b33e3b3ce5004a4fcea39895b99957b1a4a1e8c94900871a1c9864d41379a6e41c0f71101a8a935eab29085b996b254fba32cc74dde01be4f1081c07a03fa150259697fe4c5582bac5f3cff015ef4de3352c0abe2b36a07a41c41ff8cccd1301b2090251708b1f870d36d4e88717c2f540ee4bce9978659487a854c88d6e40110120168589dd6000e038c97999bfd051fef803ad4245aada59a0224ad5842d1fedcc24889d6badcefec6dbc165f5946f2e43d361a7854856f2c47cceb7c24daff51d197674388900f212e20e7d821c7ced98ecdea9bf1931d8b67eb26fbacdf7634c5cf7a10af1f66f973e3dd4cd85e69dd5c8a80056850b7d5b5ac562d308cc59bd493fdbc1f3e2806270bf99dac0ab201d4a6be1641eb1abf347650db9cf4ae3c7122b94372dc07edee329b60e00e7c9c8f1d886bc2965bc40a394cc657998e8ad8ebee8843eff0a1295ee79cc276348e6a45b5da7150804354b6e3deb3e42680201cdf2073b6e363a19aa22a9caa34fe1893e8adc9da7ecb0ff9f8a97cef4752612d842d8b7844a0cdbbd2c4acc8663bf6a84087407236a801b5c37e3c7ac59bbdac74edd4f015306b929a4ba298bd6ac450e62c14e71fa3770cbaa4ef290bf44743a472a8be6a492aa78188f16671c13743239df15575568128e327d24b553870eec4f3d17924fd25f4782bd16a737a7fc8fe9156bb83be73474545c5bab38fd6252f02e23f2e2e4dbac025ff9633e7fecb7a37ed29a5947d75bc7ef736c78ff288b170f2f375df49fe6edabb3d99d280e14b332275d5a90eb028073ed8c10f72f083ede02a96937a00aee361700a4bdc7ad6d38c8b2c902a0e4d147d6619235c7fd0811c7850071c94b64f6e90770ea4bd37f73ffd2806c9279d62123967f48f6c9c9848715535ef19cf1f605b88e0f726fef34ee7dda1c63dedb329424366605751d91d93bb1ee3a2124022bf080858ad2ca30c1ee66907b6b87aacb993e51a53e87c9ac076db60e7a921c72ee520496f10c26808b6c20411972aaccbdc2545a9313f4c1cb7b77676ef17d7d36a360130c45616264ebc873cd95740678e7d3c8d153b40409c79d5b566f67ff5720bda3968db4b1d43c945e79fb4ca01b2b55e8c16f214b15ac1ff46746fb39b6af82d7710610452558e0eff10fb7eea518bbae0d7bd00844f1ea0bb0213971eaffd745bef6b30e73c50a63c35877db4bb98e7cfc03b8ad3134a912975d5d7f3b59d88bd835f48b9ca484529023a6228d32b91ac60c5ff94f5f3523b2a204b1f9d0d173111e59ed6e319fc3068b8d9bb61446b48f43da280c40be3da1ffb3320ae24450401a23ff7c1d6ba9e5635cb8880183ce47530b49b97d1ae04f835c15b422e4f749e65613ef588ddc39471e6de57b4c1b4573f7b9afd6e355ee6d12f4eecb0857dd76e2a63c03a8c4bb217ccd3ac290d1572f3c44f59f7099b1bd0b07502cfed2f79228775e66c9eee114cb21ad9a09739aa44f6825e46782c773bbb477f35fbfcbc2220e2fc1f00bd66772df5a721402f799893d8bac1fb91e6cf34b46d1ac1a9d949e104c06f54b522f576a04cef8b461573543218c36ec6145b17f49a48cbf83ddebb0954182464b1e9c18049d35235d8c0a48cdb7097278a7b1192e2b9e1ac94cbea66d228d306a2fe2a93130ea5070c1ea26e01afd602c831e143e9c2a8929325c616f903ca948f4b5e6f8a4c1779a49097fd4726dc1ebf8eb98bc59bf6bfdac705cf1be1ec05060a9b090e923b423792feb7311383d2efa9cf7bbffcf51a0b7508030c03058587e3e76bf03d68ac8351e0af9bc595e9e0f6e66bb0aece507eb4d78a17ec0a059d0fc58cc731f4b950af0686900929682a866ae0badb35c9cc655facc4f03ea4c95355374c9b1d7c374d9738112e80126bf563bf469767ba2ce49cbd0bf258b860a715c3d4aafa0c6d04524752a318cf019c24650a4499c77df3aa2b9f9cc91a5e9b9146006c9ae218bf0047656365cab0311fd82f8a456491aecb890b5ca66adce2a91636b96f175f43c0015b23ecdbe41a3d3780859b672404ffc40325706e1b321efc0dd87b06d4073a86121fd50d4234251906a1a0d004e91aab6675edc183edd0ff65c36f0f4eb5b2bb5f49813850dfa0968e745a5600ee5793bf478167767d3c9c61d06838802bc1ee938dc1bebb8846fad81e6dbc3ec20fa8bac07c941e1edbc5de235934184238b4ea732d63559a90e054cc556b4300533555a50b014ed5d054e7537d07d75d1fc51d1fc1839fe80a9dc48d0ea8b9c23dbc60cec15a848613e760737f0aada74d11185f14b8f32ed5b50c0335f942bb25ffc57883ead49ebe58fa2e301d8d0337b82d0835d22ae3d8dcbb9c60ee01dbd2c9e596c04a0cdff4fd7f291601ba4fa0b2e73e0d8b2c247c20079d39e06ca36a80fec6432d46117968540878a706aa8880dc564e43748ff6aeb46232016b51b334aa1cded1ab4d0fe5f0563efe94a6020c4ccbb532b328cc345a4d58413f95821342b0d8f1fb0fdf7db365d526f9c1a443c3e2d482d3ad611e462896085541ac3cc570fa1ea654868044a9046d3ab3d97fd20422b487c2bc84fcfe9a9ea1aa69f2ad5ca4be79f4d4697a324cdf5d84a920d3bde41ea20e5ad514b98b026beaa24c2f776a04440f96fa247f1848e8b076d92f97198c1c1089aeca974d4cfdd101d5cecc85edb71931ac0fe3d5d70738a226949574e3229366c6c1a350bf6d1c570395f18130d038f249c6b8cb7f40973d7c98977499cfe76d1305b0895d604f622fa78256b2cf388dc49529cbab87fe80cc6a5251cb3057bc60e20ff2d4cb84dc8e0b11c284353eb898e590f61f0a94200e988707988e87a60a94410366ff295927495069598cfc366e2fcc89a6d8abde8f619c0b1abb447417b5c8e1f921d961a120e76ea011132c9ffbdff13329895ff644a897278ce893cc26a178f8696b6cbe398190e7510c4a07bb0c5e81663e39da4f380feab5d6905cb25e147b4ec375dddaf3db4df8a29c41a45c27ce229ca3b51c9d92a0994bb29ada66a6a58be82acf51f125bcd9ca3342adf8c051759a22edc9d03dfaaaa8edf91cc75f874820cbc670c729273f7da75c3096c41401551ada194b742d651db3cace0d42c4b385af23d41fc41d82762234a008635b448f3c8efcdba84ddf5c2254fdb8ac28b92d6474e04b3994207e878ba27efb102eb25aa27222a6a2cdde81d3e28da89a34682d6857ea2b009e898eaee1688493af5eaa7b9fe56ead952a2007a4ffc74747b303578cdb4b2cdc08fc04ebdd7ee15d762e3fb32d7c947a4eb265365d22152c323bd323b3033d3e33d6b4c5b1f101dc33c7754040049fa9993eb4431bbad26ad6c13f97a0c878490a6b87a735e2bf1d9882615e822947574ad70864849b09d716ba227b50d41065f4ade46927bea4935e025d39f4c3c787543aea879beab4e5fce126a498c2075d80f92d2a2f91be83740c22c12f6dac0ce55e2cc8478ade7ba0f2412a2f51fda30be38a59235324a18ea1415e827d4f3554444c1e74fbd12ae27e99d8cfd0dfa2dcfd13baaee8c3ea259d70c17a63df1e0307e090f63048389cfb27184c0b2c1bf40a1becd14c042eff317574f4e75637bbf0b5f5124321a7d089d1b466dd5914d0e82a5c97d3caf1bb7a2d27b47b094468f3bb87f625499fef8d5a9f6294f8e3dc81d7c4fe046df7bd9f2e063bd4ab830320881f07b89ef8fb2c723f0f1d3ebcb7cad8977003ba87a90c2866618c7d49de2a138edb155f22b279d93870b5a2fc28e4c4122ba93a84d80ae2ed92a33a446825b640a93692dfd3cb9df9659e3383d1d33c42f4472bbe0996bf11dc4b8e6624d01605650443514136fcc1a547e1b60093411a633604a39edda8f5700ce14a58ad9581b7c52912c6c9fa91891fe2da87c7b796ab9b07fe18c589b5c52e4ed1cd2e102864e587de12b7f50fed844ad08a79c65962901ec27b50e6ef44da75b68f5677965da71cfc1a2ff9b8da31cdb4f4214eb85523fe1eba7946ef0d9c39e80f5ad898e7fd3f4df1c9b82d8f4e5cfe20ce3a729a9072822c569fd080051793d8915b549fc41c32208396b01841f305ea4fe2612e48b8073c4a1b469066fca563c5a68e1df2d2c472d5704418f7da76f318dc6dd5e2a900ac1f2eb9af007a800a9cd47e6855e351277663d121930e23c21b3426c5698f406fa52840ef5abc156003a040baa1a1e2d11a29e1bc4cc53ad63a69054c836655f7600c9a47bc9853debe9517d166a99c5cf74ef7a089f20bdebe6198e911063e4c530ecaf5f8d67159641b80eb3f3d87a0cd76fb41062e6b9f278ac6bf08fa6154895f4285ad32b53fab6d2d3267423a89ca8fe7fb3ddd2c1fe4868d315c279c64f3adc5a5be85b4f5a1f4bb9eb50aff375114ab8fb3d3221ecf3a24e7b87a3069c56d3acc14c28f17e3141846c25870ea5e6d19702039ebf5dc109b8ebe82826757c4c555acc924b889c410c6416009d2ce8095258758b07d01b711d2d5aa483971f250a8bea41f66b91d4d0da933213b84841d1107a477b23f0d89e18f11b57c5c9af8548a6a00100fc91b3587856bc9575ab61556ce0bb3800645929e8a6ac3e42033aee1657d4c090085a2570b8677f083049dad8a70c1f56d6bce86c1093d1a56a259d2ba68ed5eac3367c51f82a5bcf6d59ac4060d21fd92d3f91d90e5ebe4515c6ae39499195fae132c304a1252d7a2b0dee641d6d19498d8cd1ea451fc3760b79579fbbd9e3db674ef55fceee754ec2ef4e95d0633b9fda697052eef838f3e3fac02924efc0a44cb7b0b5c86f5f41072025821b922c50f359d4584e0c09027d15a213736cdfc17226f41e978c5512aca98e413795031c061862e0f91e89cdaa14871ed814cc259cf4092993df78f9888f811dbe1e1e9451d92fc48ebc28a426d18bf2b0223f7fb684bf5ea1263fc8e62d96ddbed8aa2740a860e53fbf00ae2fc83114c76ee4f0a9fd4882c6f83330abce71a64b27426f03bc18444d4a12b293a7dc900c47e3b16e279681408a9dc521b6beb3e302c1d2515a2368d4e9392a3b69132ee32d978b7bed1130dfe56287c3e3d47000ecff48573a7116b8ae96b3f7c6f264d5c0f33678e7010603b8e16f45d1ea3fc3630515722a679e5ff4e22900b9d7856361c83063945381d89a84a9341400a0d7a251cd60ce52589d69623c81ac12cbc8c2ff668f9751f630fcdbcaeccb14f426f68c8df4927526f63fcbd3c134a512384c9a371339dc628a4fcc2260023e7af178c31389ab46b9ab2ed3586f6b5d80654a0c77624dc698317d1c74925c710d2f691a8f8d13fe8e1b1da4aa383dd8c12998e11c2cd42dd2d6400aae8a42f4b7040fea50bf263cfa373acf90ffe8e663ef9a033a7b7606012816ccd18199e2b138fac84f4034c0cab2f06fe0a239c50e4e855bd0c654c8819247fc8e786d0a5040e5b4c53e82db768dafcb69d67789343c19e28547df8fb4e4fe244ef242c8e69da471a02643b3ccbdd60596c8c87357fc80c08cb068a83d55f417a3f6077da12670551de7b03f69920d58c76586ac358cd38aa0388ae1915d993562cf535eb1ad19954d9a2d2a8c3c8b0a22656aba08d455b4e4582be908ecfd175f3cbdd17f5e71ac9dfd2c3af4b539f047ad6798e77afb17cb2941018e175f8cf834fc9be6a869afa180779f5c0c2e13bbb397c56fa7d959b8156767f146e065b27bcf37d91a1bb81639420b9c5b1a73e553e5c4ca9a91bf87b259bd905a54faf64e5e263caabd2bb8bbad6adaa366915f5b808f2df818dd15c730d2c40381a56f5d67e37089f9db5a8b8c4da6868555f3ce3f50f993a2e9f3092ed41ef2133ca597bc6910ca863d1289f2ba1bc468dcb26b3a976dc3e0027de8e6d7652145dcb2d3abacb5850b59708c47ae2650935f309813b32e4536ceb115927d73171950bf352bdc4ad30ab6dd49be686aebedcad6721cb2c3366e54f5e3d5ac47d9ca69db48489e3792f5b9929bc460037773c1c297b865ff21ada962468b81bb530faa6b70f55b351e13f4d8f1a0f9808b11d5d5acb65607dfbd8f13e055a1fc90549c81e859829ee59f25bd19f229b28d3565596e2ea000ac0e0ec37053a72a0eaba19c59d9c38675aac05d11bbe37b5321d3d7420c7a62a13317c6ff4d05a55b93d0d8d41ae496f0f65a930c83b719f8cd90384413ec451c6f24e34a6bcd242222a630e8a4a19beb556d4080dd5fd1129536e8b612c3d6b42f64ae5004aa5cc3fe88d1e8283ea698f469443b38d123584d9e82154cb66b41d0aaae37dbd43a01dcee4f8757d10a7469487dccecdd893e45e62ec26d58cb0e1e7a335b768b681da34135961e9a97388e35d6ac30d1cd89d36a03013992bb328e590056e65dc57660aa25fbb59f7db0f808324128164402108f1882a88fd670a3e40b0e692b6c57907cd5502a3e4fcadb630e1618748bc18993bf50315178ac25249c3b832509b4467322a51f2482b91252d3fa3a844e093b21285ff1de71697a9c359a621f1c408d852c34e476c74b3b5fa5404e3f1d380d08ead9d9fa4e38c44e108c51fb31f39bea1196806a7fc685191a8832cb25da77749d2842739674397ded5723ad4922374fc92e7d139ff377ef3a6996731e3513bfad7ad77a15ccf8228c8a1f3587d80013881ff94e4a1f2ea339f397ff709c6c807c2e6a5284c31b0123ad346449a999c7cbc6128d10c211548912b8c823841952be7d358a6502f6b4eb9176ba18e3305305a9d134dc85371860c227ce5e429df02de72d08dac3f412f7e4e17ba086e733b0299202fe80ff232e645c78774f10139d6ebcc7122560bc746f4e24d9145292fa2db3ee039f86a26e4101a4dbe2527f49a82be52d972cfaf16077f45ba4212d54d9ff9f15f3c187158683c43a66241eca3eca1eb7cef0d73774bd42ec058b2d4e08352fbb2620d3e7e97bc35201c70ee5b499c350a6da974e5fcf0663fb7d079817eb9a750b573bdc014a746c9c2416ebb4ff4e36d2fc532c0e8d6a42d4e51ca64b00eab98816d536ed5c7ccaa206c475544fbd146c76bd1186e0fc113b0caf2110eb15a2666c19a017f65a39c7c0464cf0da2957eeb5e721998a963f573046245e892c222a52279abd1258cd6fcc07717e3b5910282831f54b68bf3d4dac20f0b5b2482148a1d94bec2cb0409d53987698c29e34899425f2f1635ab74911dbebcc9c420c3937302b5bdd82d97a7e07835e7f24f30af1201cea95205c9d442b051e3314a982c29f7ffcfce1aeaac1942301a58e383cec37b33943ad990b6a2613146e483bb2a35d1a63447cde15f969843aa3bd9692b2101f5770cd28ca15d81072e434bf770013a804e6ff5990d4d426da8525fe384ba8204983fd2e6f1b902d5f317ce518fd3f459c3e139c5aeffc485e800797257839d1c80a24347de67d605155f26a1c6c5b7ba222a2e35571e2d6fe995594c02149093a77f0333f227d707784c38042c3bcec7d10624954b59f43a4075ac5bda7a170cc38bd80760078bcd8c54195be49dfb670fb7e6b0dec7fd11c47915adec57253c26180a0a67c046122bc2ff9bc903db460021833a9c548da4d3d2cf3d679b8c7fe75ac658469b1dada8776d389267b20c39c3d0d01194ab7982036b2b46949a4a0b7671b7912dc7e58ed218264714bb47fe296fb741b56620c017a902fbe8492736f171a88881d3ebe1c453578207a497de7d02d859b964ea33188e0323198861483a790c87e89a7b0ccdc9bda6177cddeb5dd509dd8a1c74d141d4036a86485b624774240b479834e46c84aab05c0446471762c00562c30940ef49a18812460864fad93342ce58682ddd1566a3a2730b989d291d484a6c4e55dcc45be0051ba9abb879de23674bdfafd14b63617704aad1fc31d96c3599a2e36804c05e59e094ad5b10dbfc78b6b50267c00a4cba65010869bd5613d9f222fc28abc34610c6e9f62c8235c0f0a2ce24050c32044ae8a4e13f6b6a1a600e4a4d6c4ab10c8d13903740569f91be2e22db7bd549baf4b8245fcb4b0b9f1dd8463d4080168b6b371603a52a4924661479f54232869be05d4846902a504d12b6015a78899452a16b460df13d9d05e2481daa96243200e60c928e64e314ad083830b2f9483f71a7bf8f998bdb7689f44d06ab3e9bed549c8c7f7089c7bebb0a7112b345f231a0a8be42812659b41507d1c48ebf8a136ec7f9da3270a31c8b16e776f31cb9931727ee86f6ae19dbc441e390a8b8af49dcf276d21d670c1c6b45e24e0eb33600b71c51c529a4059c9c0315b8dfec490bae07b92920a5085a8810533c41ada00d745e2f2c9d8d088bd092093490092cd872d2166279d241b7676d7bd3ba15e6d62a59d3a17eee0ead4701fe83679c100bb308c9276cc9d12c9652fb78fe6010982c2248dcb1848af5e5a2ec88f68b1102ae4dd4ad95e48f95f93010fb61462aa40590a6276e02b832429e0c839d4206596ebfc90dc48303462cea247c6ec00c1382082dc552fbe0e5e610491d4e5eb558ea2c08955de1aa1e2ee78ac332beb5305b2e037f31083adbbc0e54d0fbd623d093aec2b63021cac281552cc1300d0ec43af2dba72a62e3a4eca689ea03b232467d2dbf82f683bf621953393ef5a00853e98e77ad24eede8aa8879dc0851e8ee4634a5e5e1b14deed14c90d610a6b990c58805009808c2fce172e72df087ac604e16d3d695449cc8cf81be21b3a2cf8e1a695df8c09004dab10e33369852ff8ddd7ecaf3b749e23ce1564bffa74069c6fc20cf34c00de9f4ec28df4cee886d5380d432c4b039d04353e6355b6fa27b3fa69fdcf83f1dfe15a1fd2fc95021598e0109f802b1bd6909f0a17eec20d71e1c7c534c660987763e27126474600fa058b9e125a85f106c58cfc587127e21ec2386e475d5c27211a6b5cf38546b792ac7ee7f21ae7e33f2bdf44983d1bd12a4e9dfc550f96f15a6ba5ab50a53a5407cda39aa5cfe1c5b89e67bc876dbab0300ab34f68e10244b5d900225771266b0bfd2388edd50967abd044522b0399ab7a486018161dadc227b8ea37d8217a26332f2bef1c041ef233279e458f599d169be85d4e1ffc7d566cfe954154fce091e80a54c8b2f8ae37c9d8eeb79f8abbfd428bc4a0ebec9fe50a2c9108fa49fb01230ada07cefce9b4eddc31cab0a8b4d5da12131d6edcc37a1de372163e41696e5f2c8a23c4bbf1fc526b6583944bd3308c7f49c400a69c2c634cee0e1de85762969cb5fdaf2a2b456e927e93475ef2cade8db1bc113980be3517b04cae4788fc7384493ed6725d353c3080f251e9cd848b7478ed266187ad670b26b8684ea74e63ab4dd02711a01182d6b081f770941199c941700fd0819d2dd43b785fcf0f90c810b67e02bc9c071c352e48462064522bac4d0f6b0703b24a27acac1aaf54c08f8d9addedad6cd0e93b99cc3ddc5fd9e0012b007febefe64d96580a13c7362336fdf40007f7b3031addaf49dfcc7c8705ffe0f6f6294300cb21238e49e9c9296afe62ca909d690d710794b77c7076880c45d49ab8e6fb06b34291b1db601ac696d29a82085d51a4465e35f5df966610f54d819528e4b95821c31b8d82d9e6fd70ba8ae633962bce011376566f8ce4244e020ca35d95fe382591092b29e1e2e0f62cb9b515b51e79f63fb092918a45ffd7d07020a42d8f4137865949ddbd0dd1e85b30e2f813bab14899f066dc18aa6454f3c67f0f2b3a13b882a054bad416b3a2e4f30b292580fad01fae98fd7c8f15ba960e8f243f45a271efc9902c1431a36e7cba1b282587f969de83cd6fe18a82be7b540010f63e10d3cd0b17e765df6b880ee7a9acc4b081013a4ce228b4c41b31ccc71aefee580bd92d8dbc9c15ce69be616c1264a62da039c50444ba54546393e97bb39edeab42f2bd60151108841c335e41fbf7bde5c98d39152565cb0374b2442a442bd3527896cc3dc0cbee6761d988132830d95154c3605cd5a53a3505dea47719b1f3e383c29f45daa8789d289b6d0f690d4cf80c4752c7c847a75dc6fb29493ec5991b99f2f64dd340ccac84b5131b2284b94f4ee881baf9269ca14ed79f22a60220dd646d82e1647de9664431d41a4571f0ca0df4572b92de3e471bd901ea742f2b2c455f3ba64232b6ff6224163e12133b59326b09cd68536833ea2f8c5bce176272d24610e5673466e5fa41d2b55a528a6943100d2c4f33c962bd96cfac3a2b782fe689e6d40db6d982909af88de25dcf107290b3b8480d6daae31ec8805c3878dbb9d87a4268b2cf0df1abd33b100c758c476fca1136ec378f51a6aadf99f7139c55ba3677856b5148e1ab233e47b0ada2e1f2b434f23c88af2e0a29cedf9e8fdc1183f9210234f0965ef2d0801436f7d3be2d7ff4d4922842ea838ac8225e6d635bea50d0bc600eb4ea1e37be7fb8a9264c5813916b89f6d863ce70b27a0b03f7f663961655ac033fcaf76ef235b26d6e7394dd703d7f98aba354b37f3cb232473432b829aec3d18b02e8f8317bfcb4f310bea396dec5245ed5b3d5c9f9fc2ac18546421983635dd3d4032f8c63f5d51d02205e4909ed460da32477de22310df606aa9e73184194d41144dc2e4054036fbc086eb0ea109a84b1f5f33b49dc18e8d2384a5daeded52dff169668bd13ba687f8a8b83e1bb9df4ced0d3683c1fc39ae177573bbca6c8577c09eead6cc38209f969c76621b0009b476b49bc2ff60d215c99f9d728fbc8c732826a8b2b0c75fa297f9f29091f1b95aa3074dae4c05f06423c163212fba90aebf45fb16ebe4333a88191a7a778d2bb2de3d0a7d3867127d590ad6efbbf747b2a3493d606fd1c4daf62366120671ce8d8c894988bea3317473a9209aa11716eb4c7c88dd71464de8cbd2698d0e5c54f0949073d9b1376e5fd1f503a4343464aa898324122a08bcc90cb2d425f7dd890f95d293c94dcda68548358c9418655a6a9a0c7ff102e416c10e38dab7946c30628523de9cf950d1f408e196bdb4ee51a3ee1a7798354ce2ab5818a461a94531c83ade93de24efda7de46b56b0e0a1965a2a902d75d63c6251d8c38d663a43424d0ac02372ef7299739aac862bba8f8e785021c976459ba0753c58014a379623ca81239c27eb02da0c62663aaf0b67b74f4e2a201d2a03fd7a001d894464f925b45f41114336483008616cd83ec045e4e3118cdbd57a29b4aa81c1e7fcd1a388a6a574b47b671f1dfe8ad7f5c0113d71af65e098aecf79135847c967f4329705d8e4fc2313b74b757754153c8d2d7d8a6d3e6d130dbaa52e43ef97c67b74724d72809622708cc7edbf2613eacd68d750cfc19095aaea8dca1b2cfe9edb8c38464f42f44f289180157aaea9bb7ec104f9593600e2c77685ee4fe1ed499d275b73509372bac089b7d000284e0323caf0394a36e6910bc938c64ad627b8895c3897a84f24101ceb80485d3d23f4ead73485cb564544ab6d3f603bb51a28d45782175aea10f96658504f169bf647e2aa5b10671b6a1f3792f698aa891f9e6294beff19503585b494c90e465f616d718b2b5210823be48c2eda80dd5d429e3484fe588d3f7420812f20f5913b848ae92de1d347ccf17778c6e2e05d9e62d55467461ae5bcb20d0e6b6d920f40468b20058680f833c6dbb5576fab8929aa4009d482504702f7cfc9dd8277e19ee5c78abdb7e7cfe6c7160a97672b4aeaa66ab115a11a212854b090e9c07f6b4ac24685d80ca8fbc56e508dad760780b9a5c0d8fb4464068ea5d6083b6490b8aa4a06e0431a63ff424fcc96b16448223b5b34c157ea45fd4bcffa46b8738c016a168b64cf76769a80502441a04ead42bc65620da516d0ec99c4a72a94057bb98ed4504e6d6e4b29698774dcd5085f9e9ba868d9b8219274ec8d706402196923cc0db4a21e8ae4e593f15e96736adb51ec5fa1f53f8185b51ae7fafec7eb535db2bbbbbb794324919040cd20bca0c3b93d4cbcf43b2bbe766bb7bee3159b43b4bde01ec21729cd2afde2be498fcd062891c23f9f3ba4c9fd31ddd36bdfee55c7e8a019eb7edb66db46a30e72f8ff0d36b44757bbad45495a9d7234a2c99399e0edf57d2a45cc86f522c806fd2293c618fdea44b18755d288ae038961fa0364210f1c6816289aeb8d72187da401f85dab03d4dd9f4233ff026cd62c37611c40f8880ae2c69630b551c17e6b8bbfbdc7dde9138dcd968eb0455f2287d2d818df32cebcb4f37fdacdfa6c64a41907ed7e5a8521ae59986308129d5a69f43dffb8074dc86afcddbc31168a98ad2526f8adab4b46985bd19c4b60fb3ac0fd8947fd789e348691536b34d4a9bb901a029ff2b684d0b1717dba9b0fd674d6cff2f27276fea2beb8d482009a4b475cadf087f95756ef222bbc50e76ceeae9ec53db596badb59db56fc94bebfbb6a38de26bc53232285a564ff7ded30feb992db36360be0d88a7479106b9f5fe17979d3f10eb96cdb2330862bdb2730862ad82da9904623dee2c8258a7ec5c02b13e6d94dd79a310787a4331ed6c02b13ed91905c4da64e7138875698b3b8f20d6a49d5120d6a39d5540acc39d5740acc19d5940acf3ce2d20d6dfce2ee00bf820d6dcce3448106bbc338d0c03626d778e01b1f69d6540acebce3552e508ff0930b5c128d8f63e2ddd56eb3ec2153b5e82df145937f80daa21cb1a80ad7405849774f5005afa0fc0b282b029ffc003e84a0460ed21963ef47cdfbd873cdbc6ff7d1f846595c0a6dc4704745591a0a57f75209af2f7749d82e2f897c0b2eacba67c7c556148d055f551d33d554815c2f6af31bfe15f5f9655a740533e0525057158d8eea2484a60dbaf9c075dcb729aba261db0307bedd7d4fd1be6e8f676826dbf96f77198e37eba4e4159400e34e2f74a6dee6ffb233b4a04b156ea234bdec0830d559d7167f01e14692b3ffdfce91b34cb386ecee3348cf5c8ffbc396dbaa128621b9efe3698c9955a6bcdb171036d6d204776d65481531b8cef687b6ffb0a6cb8136e56f8f44d10dca56585a48d4a6d845e7db43d4766c753187de511f136e53aaf088b07f73a5adf1c55a597951c000f04a0adedfdaff527ae0d722f97c31f93e6bdd6d61554af40c81466d3dea6b29d6da532221a04dbf93a2cc8870aabb49db1dd34181495e6e7cedb1daa343f7f5e3b73f8f5e3e7cbce76eeb69712762674633b7b9c9ddd98cf76ed95fbdeeef6767d6e8cb62e1537e4997d615f56093ffd0a5a1d0356a1f0e14dcac5c69121a8270f8268dfb16be3cef346db63fb1bbe27a04c617cf0d26d36fe1f381a7c70bb7d10d261d20720eabebe0afffef6a0e8abd16fdb8fbe027f7b165f917efbf795f8dbc3f8aaf41b690e516eec568838e4f1c15a6badf75eb883dfd33f78198e3ee370a7eb4ca2c8328edc97b817b92f91b81749dcd33d7a30dc199154e4461cc79130ff2421ee8f3e3f89fb11c9699325c4fb7487ef853b2149c550d79d233f0d7b50ed4bd66c6f9636545efa6fa40a9b77a77b2eece17df801085f7de40d77bc21ca8d5772748fbf7b4c76a0bcbb0b7ba0e7eec81bec9b3919bfaeb4acd9345bd6b87db0294f6d20aa1043d034b14cbec6a6bf836599903e788aec7cf0556a535fdd6cfa79e3b61147374c9a97f6292153cb0ab23de7e1027c828020670b4184ddf8cb5d840ef79ba620a867f4706f441010e46c22ecb6dfbd6bd32c62e3984514b1b7e74c3757b01d5ffdc3c528b861bffe5075388f04db3f573cc2e4087c5f7b5dae6badbd3b87bbee13d1ed6d05180c3202dff7377ce975413679e9f85f4834bb108789257cd3c6b65fe32c20ac2d4b5ad4d4a6bc27e991a69eb3b7cd87206e4070efbf01cb0a49f069d1d3a27f9316a9dc0e1e2267db1cd3be0e3ad6c276ef86efbd9bbdd4e6e26dc3f88bc024f5920aecb2d608f5c0cf92fae461b4e9b5c6ffba7bfb4203e5a45d565e452cb1ca99b79f4359326f7f071ee88ae5ed0f80b26abc7d1f288bc6da1a056bed11bd9dfc8fa617539e886ee32fa19e886e779f4d1ae673054d1c17863b1c698f58a21c88377b05a8e6b79a98542a26f5b946f704b13f6ade2dccc26adc729b8bae3ba56d0cc8da186d3db4d6bab8d4eea46d0fb73ff6877ba1a19dde941e455f5a96fea43b5a96de458bb42cfd8a36d1b2f42a9a8596a54fd14f6d4a202d4b232d4b25f1f5163f77e089a6fbbe94c4d2df70c7e433fe6af078bdf0965349f8f86c1c58da1eebb22eae0bc1134d3ea76786644433244227112f97d46adbbfdbba4e0685e55bde9f45bb9216d269b4ed4f53e2f2f1ec8cd3312e9fd74f8f0bbb41366567241a595c7930dc71f95cc594a7e18e0ae9459e863ee446bc94c9b67f0a8aaa1c7122a2edbf32822e339f79122f8b8ac2d0c445db99456293d85a114d494c0c51dc4f3f3b2b84d32f35920b698b3a4d4f1ac8e6379bcf36ba27880f99f9920bcd944c3831dcd94e5a4a2cdb44a5a686f41790fbd894c380a44e420ff2723c69a099df4e487701d51a10141414c8e9b12aa934da88723a711a654b41e1813882b587e87d6e01397db2596e4c68889744bc7419d1cca6849c43455a74dd34ba120155994dc96a91adb33af396162b8e5fdad918e2f0f6f50142ed21923ebb809c36d932faca866ceab44292d0623865c8a3421cdeb6b598cae87365a12c2b2b9c2e15191aea5456c2cfb585b6b0b08844ce738505fc5c5da84b4b0b25c14ebf8bbe31215ebe600e772852b0b4e4cff585beb8b824e1f46897fad2fc0e8915dd1365c9125f99d78c6bc6a5f9ca3eeafdaf12daeaea1014598584ba961ee2f7b93efd1bdb42bc748e1be2a5d3d01f6e147d63fa0ab943eee9e515aa42e848d6586c4bd9dcc36d675460709fb49dd9a2156d935825d76553342fdd2ef1d253485bf39878d215480df274edf1f3c34b18acdb28ba26517d7c64689c68a0d0f8e7f4b6519aaa688be44403f994b6086624ed8c005efadb010c01e1834d6d00084cd883dd2fdbcb0613ee70313131bc57be43915788ba9076e6250f44f326d9fe3789afccbb64096d09f155cafbdf98af54def1fba7681e54c81d704c154f2f13eea0fcb69db693157d830b99d38d1d77d216898cdd270d947a170d14f3a5beb1197d8564f43df51d62d1b748ea57625e45e65133a5cecc9bf408ba3d9240328ff508ba9d4202cd7c4ee99e20b7fc991087b75148fa03b17ea92bc5e17ea644d1de8c8c8c8ccc8d5996edee8dd9d94c88e366dba220313335bca4a9a99a93b648485b44da991462aabcb979b94939a1dc984e6e6e4c279a964cc4b7cf9548dabc43db7f1482f98b5da2acadb59612652e88d0c4b64b10826be3b0e912847cb1e27ee7d1b594080c7ba048e8f9dace9ffae238cf5a969d79ca3fb7dfe9635d341c014f888159224f39108e33e2a5d70a926e44009ae579d02bbfa3f1e3d0dd634047e0fd88834252d0d2dfc4496cfbf808ba2a0579e9949581b78f4fcaa2c0dbc742945581b78f63946581675de0ed63186561e0ede31e740580b78f7fe80ae7ede3176549e0ed631fda52bdca9bd82580376f19770cf38661de2f506f5e2a704159a518ab04069af237efd0b67faf289941876cfbd70aba2ad564b4f56fff9eb47543c35b1317a7c3db776a0302562d6fbfa3ab97b70fd295cbdb17e96af5f64d7445f3f647baaa79fb2c7455e3ed3f5dd978fb307475e32db9bd136dda8f60216e6fba11237e440236df8331a0f51bd1e944e057a927a2db2c7fa38627a2db2b3e0bf215277329e88aeb829631cbe2882c1828ab6b82165956f7b2a99aaf3a58c90cbaea7cd0d25548f3a67c1e48f3c71dd21c7190a5188a2cc53a13578843b5b9cfd9410bb2680138ce18fc4017dd807fd10ef89406e2693403be8656c0d7e805bc0dfdc3d7a013f018027fa31f8003800722013e48dc6c083cc0010d0082010b50c00f7ae527017aa50748830a0c69e03609688f0179904d053918ba10109b1cee70346c5caed10101dae9cdf62dfad272fb17ddd1727b170dd2727b1a6da2e5f6357aa4e5f635340b2db7b7a19fda6c222db7d71308c31c7aa33e8320cd2691c21d95cf610d10dc46a91d861c6902b4728f461d0d37be029a034f01bd81cf80ca05b4106f016d3ea767684fb23748341594107ae547afc082624238b8bde2baa245e3f0a87f6d4305b406ecd7a055de865e7d8d667d0d9dc3d3e89c4fe91b9c96b9a112801797108797da6874b690f00940114bd14a112eea8a4a37725839ac545c368a7c891d61c56527f0030b431c5908628c4f1764327d90a90b327d90e94d719bbaa0531044eaa5a611afd72b8336a834da79dacfefd5b3ab673db94adb6cf6babc7d2791f33c4f87c160f5d268b44aabb4adc23ec76eda2676966d62f73e5fe14bbbb44bbbb44b73992ddd6555e630efdd619bc3be1fee9126089a4c1c69b2b06ca409035353e332cbc2463ce57f8408c96c498d2cd1a0fee66ac00ffeb5dd57a80f15dbf7b1aeb572351c576e14f7426c5ffffbed5128928a1fca7ee4103686d2dbf699abda44752a8fd2a68d6dd487dac4b11dd250596a4b75a92ff5eb4a7d15f2355a58ade1cd8e0500fd4f9add0b698a2fef429aa3cbb7902dcfc2f23478f66559a3229bb2305f8d6a5efaa0ab9119b4749234bb0d009d6bd0990b34e53f3283ae3218b4f49aaff2cc4b30d0568df7cf5fa0adf2fdb317682bf5fe39096dcdbc7f1683b664de3f7781b668bc7f0e83b660de3f17d156ccfb672ed016f9fea322cb22b9b6405b37ef9fb5405baaf7cf48680be7fd3318b445f3fe390bb455f3fef90bdab279ff3ca32d1a46007812007ef499e63900e0fd33c9e579ae4aa9cdf8309a529b94a7a129b539bd8ca6d406e56734a536a64f694a6d4ebed494da987c0dd171b40d627f60a7b04134681b05b5f1b7d1d607d4c6bf465b1a6d81509b1a9a529b540d5fd6f03332357c0cf930e4d32049a01a481b0380587a6b05e69edb35681bd3411cd1a73ba2ef885e3aa2ef5d3aa2968e48b5cd8e28cf56c8512cbf9967dbdf06d11657b70a0e4e8534c3dfbe6a13f5db0e8ed2748fdab4545820d82aac101b042b043b048b046b84ac248f816e1b64834642b6bfa78386d87e7b1bdb97f45239e98c97eee88395ecc0d069972952b192f7fcc2d517933ef302bedafaad97dae07ac9d71572716c3b7efc66774921f077a3d884ff5f4cf2d02d8a3f22c658638d6b9090fb10d5a0da8f688eded799e3c578db38aeeb3ceffb4e11932c60371abdc4d5f1506759f807fed184b515149960a288893b54dbfe9c65a288898d0967a28809cc0413454c30c14411134c1431c18467f1b66ddb7dd38bb8bb61bc5dce762eda4034f18f8a81f8ca1bddeff67520267e1c843506e2a5e31ff687da600c0407e11fdbada67b332bb0edefe038c857407c453ddcb9e3ae7b7cda1aa2addfb116306436e34e07b1f7da6bafddb1f6de4e665d7ee408122449b6295657e24bb629569f0d3111a4d26f57520435894dbbe7eeee74ed7125e1a58f4fa789f8002d0525f04e5f2088d9101b80001044dbefe05d57dd5e9d37d0eadc815667ef05398320882f18d6307395477d8d2a257da3edf17691f062b06b90d71f3ff880cae0884dffd33b7839393e39c360d3bf1d681ac26443a57210046560c4b677fbd15a0b96a5d7cf7177254510863bf647302cf6e22dbb60670b6efa7a640df214a534c423b3fe984234815ee9bd5bd723831ae35cbc225318d3be7420d6af16d3b0d48468769bc879ea16431d45ec213cdb06faf3600eb422cfedc4cf9ea562dbf7421edfe2e78fe77bf16998e37bf133066b48529bfa81da94698578b8fd7de9b3f891dfd710c7e74ff3d0fdfd47ae842f04f8df87e07f0f7ed5fb5c0df07d767777776badb5f6de7b2fc6186fdbc6711ff9e9120f91fb0e0443f0bb0d72218fc98726e10d458023fc5cc1a721cf0e9e718883dbdc36f991e6b68906413da344f2705b2429b5b14fa90d89346d6cdbd18b2be20b41fad18ba4094c5cc941fad193c899b547b6fdfa65ef736d88524a696ddbafb5d65addda7777778b7facb5f682235d24742fc67833afcfb6f6b7901c8d74c90991fb6e441249f1bb2d823fd2a4ef3689f4a3b7610e1249b4ed8fc8a06ddf7e4fc390c491498f34b7a06dbfd366695aa26dcd14c8b67d1d88f6b5290d141fd6a710b284dd60b22836ee861ccfb13e3526ec26dbbcd836a28d0cdb1914c77f1bb2ac6d665344beda685e7a41571b19b4f41fdac86097b0dd9ed46641591c8f87511e5b6c7fcbf1b0e125c763fb5b15d7c319b1fd39d736b32cbb9d61b799b5b7b6d1b00537da46e3b6ed8c8d0c9d87af1d61ee565bed49b7d7134e2e5694298ce9c1ac0f6d197196786444e249ac6ac9b64e9ebbe299978ec453fe1b8f9c24545b4fb9e495e0242e5a1e5efacbcb179e55ebb3cdeda72b7a8268dfdc7eae8faa7b133fdbcfcff6f3e3c1ae70d248a02b6667af130bd1bc7eb7ee5b0949a513143daab0b8c8681a3135ca1a36372a1cb0a506d0e5300ff2980bf9493bcff33ccf582c168bc55c36e572b95c2e279a15d16a2c2b2aa831168bc562292e97cbe582b1c183567397fbf8ebd2ea908c88363bcff33ccfd7ebf57abdec2c66531e8bc562310ff2980b9d3e74a2d168341aca799ee7697abd5eafd789492c168bc562dbbf54e3c612671daab24a34abaff33ccff3f57abd5e2f3ba3d5dce53efef29f92789ee779925eafd7eb35b2b3d92cbc59d5a0beba1f58508d05719ee7799ee7ebf57abdea90ac12cd8a421a099ee7799ef9f57abd5eafedffd5c05222085a446bd57569e7eb3ccfb3fe54580daab12af479e7799ee72ae7a5ea72c4731cfa4bb34194e5ff388a625724d2c67789e37797c65dda7669f8d2eea5d95bb1100340836df28488613665966e52190649b3eb3ed214c58e34c78d34ff2f96951c963901cb66402db5d44beaa5135a32d8f4b30da0cb7c5573d5d1e3a5dec72ef7c5ed86dae34eb9a78db24920d897a329fc5b98a3dbd5b4f3066efac464e70edc7469670fdcb448da1904bbd1ce20b8e910dc79046e3aef4c0237fded5c2a819beeb89d4fc04d6f3b9bc04de39d51c04ddf9d4fe0a6edce29e008aea88cb6e74cb0519bfa27f0b4d31b9853e1aa7db91dcb264da6954dff055baff73725380cb3d55a2b696e8f7509824d10cdd1963035beeabaef4d0bc4b43f4cdb237cd3f218bd6993d89664df9778cd57de5bf20e6163bbfb9ab288d8bd0903e3a5dbd9f6db8834c590dc1eb433df3edbd9f61f59dba6ea7aa40db24060ca9a8dc336d6834f21a406d8c6b8d7a6348a18d54d091e4751a44fbfbaeaa5623b69f284782fb62fb6fa08fb50cea48a637b7bfbc30f7b14e2d83608ea19fee2a81b7dee407cb789a9f0d1670f8fcc22f6e877701eef473ffabc81360c010ff85bb87200d39fbc034c24b5a91307086d7ff079b6ed3df879b43d52e87d0d717cf6340fddde7bfeee6badb5d6eaa1014e5bfceceeeeeed65a6beded7eeebd1863bc6d1bc779640907e1e70ef4740907e1875da94486df853c265f3229955e043870e45024439d2ff71b496f9b8620c9b3ed1149c1e70640b7f7dfd79087277f6729a534574fe8fa6cff5a6bad152cb242eeee60f75364adc5971bba17d730decc2d08041d0885e8fdf75ec85337d803b7c3cf9923b9ef36c7fd4a8e6e87dfedd0439ef0c1b7618e9024f2b798cba4f9f994983437fc97bc2790ed2170ace4261fc48e7005126252f84efa451630f8ce22f93ccb4ff60d7d449f17df90657d339b22f2d547f3d20bbafac818dace71dfccb2be9a4dd17c957d3e32e82a7f5fce5fcdb272f6f155ce48d055ce5fce39bf2ccb0039673a859c939373ce39035156a9faef9c0839f8bc49c8e71032853149315c5bf45eb7d87dabda37eebea04baedc7befce1b58434cdebbcd2fe8657b324f8268dfc430af74bb23b7c17b7f537c41540a8a6196d591e357851df110520c13890d0d0dd1968b1dc23f385a6cfa2aae8e8e62f9a6f7c5f6377162d492deac7acc85328531bfeaf6e28debbc2f83e18824964c4e4c28a79411a5b2c2d2e202ce60ae1b635951418d292e2f2d302c9b9d504c2726a5976781d95749248dc2d72bf5b5d14230fb7f9a54797127edf3fc3b9206ea556a255fdbdf2bac7bd18019f76c5399179bedd3f64c2f96b24d9e1029a536fef56f4c06bc31da72d9f4bdcf85e23324bb462f3d5b6d2262622e70ccb39862776f622e70707b23dfe2188e65970543f56b43a5ba2127c7ad85f9af294bebabead407e38831c6d7d6d306714fdfe3be1f2ef63ccfabdc47963c50da36dc593940feef1790c9ef17409fd3749bd8400401ad754f8b76113a458439f09366edf1fed33ddf9bf01041406b9b089b2dce0d716cda1cf7b6daf41598b7868d3fd36ac351478ec0397cefb5f6f30573b88b73cee220d639cef1901255640b42cadc753bd8aed68dbc9b0d794a40448e347376f7dde78ca39e91bb2e578ef39087f36ddb66c7b3598c6fc883efbd38e4b9d8da2de4b19bfb0e793890d3a52944efebee429ebab9cf1ec8e56f6416114b76f7260e916d1fc73ece199e4452507af4808d208cf6799d18724789a7ec9f76685810cdf0f50a79384bbffd8cca2b2c608cd60fa349edb24b7d5d2e9d19bd43b329fba0de91d1385c3665df45e3f0b129fb2b218e9b9dc99dda1544330c4a026ddb0f81d80f83866c1b0ad9f6738a8bf5930b8ac9e5c4a5bad4b1e3e886535846f56334d58101faa7a13d4df6d81d69b26cfd5ab4a97bff455b219bbaefa2ed6953b79294da5c903a012c62c53970a4eefa9576d185b1e97b45b475fac1b24dc7a78f7bf84ae5e96398af509e3efee12bd4d3c7419625f334e5e96321be0a9ffed397a72e4f1f3b416d1899f8894daf193c367dac045ddd9a97fe3e30cc829f32b06b0c9f1dc61794855df8455be0d3bf33dae2aaa0e5112ad0158e795904235cd01516c24ba0f8a4b80b8a655e127d4fbda7ddd3ceaebc39b329e9e97bb5417cf2f5d37f5fb53c7d18da628979fa31d48615bfc9f1cab144d7893f380cf1296568c8572befbfa388b368f871e2acddddb8cefb32d8435cf970045a2db3470de4f25803bdbccbabbca8707070707070707046154cc2092a12e345ab6424958c0a954c4505854ae6844a86e3021c170e12383e384de0bc707ce0c0704824d0ea98dd43fe0a4d12680d24497305bd41e353ab71d16a449b86b6fda4a3ad209a9d68358dbda59c7018e253ca36235a528692318abe3842057165542a853b9bd57ab768a07f96ff9567f9f0e78951caa9e55554c484080d39abd8fe608dda0089a20cd29c39a51c31ba2922922919234918332a18e1e29a34e7994b6df2b3c5508e2e72c872602107519118b4f4ef3a511c7f3ec7cf1674b5438a215fed08ea82ae7654414b99af76c4bcc40265ed40024d59d68e1c45beda31cb21065ded00431cdf1c5f8b9fea3e322bd069975d809a65a99c38ad184973149ba06f68d46687143b827654b123b603099bcc883ac1c87623be1abdff0e226759dd7202ad664919c77067fb28c67143e1848ccc68f5490728ab5174209a57a50b627dab4d64748f8c112a9d99a7214324e385cc6c668999d7cc13333f334033b099d84c15e29d1152b1e0544493045a83ff8ca65902c5f1a7a169aea037fc536636e54fa3a7e101b08e0cce2945c60b19229999cc4c664692992921339399cd2c31f39a7962e6670668063653c54c6c4668fbaf8c543064666969b1bab4354d93a16ba41464105905192391400a9143e4165624659a0c4dd3b5195db3a429ea1a290519445641c648249042e416e410296b7141197f0777015b7c5a906879b564d172b66cd132d432851659cbaca5eb4a2d5dd789e238bed9e98b9f6e2d48b4f8b4bc2c4ba58450cb8b6b79b5bc5e6c7989fbd59245cb162d432d536891b580d1326b29dafef71c921921aa53f068434057c0acf85151f12069aaa21837728534554e90f038f22462ad2290fe9770e7f42f21cfdd296f35893c7d4f90940f0111e2463d4a175ef14b2a2d868a885b9caf192a3e0aece3a2d5c64812c6a35056f449d310f1526684680a2924cde96188a6b85f40ef828b215a3d1a613efa1883462f46a2118c713682612c1a6b63d78928d74b091d541d4d2d8b2be80d91212f8bc86c8ac8cb235ece8a5c52c61d453b92380be65d361f236c0c1a9f30068de71834c6462f46a2118c71e62b150b4630d4c622cbba19633423c958f3d54d188f5a19c17817c23d3a394fc838a19d98715233c1c0e432bd4c4bd0d2df964c3faa1fd615dbbffb7fb3db352e3ad382ded468365564533448686634443446686434456886a8cd16db69aea0344468e9bf0292346718e2c969ce88a43d39555490487c729ec8ede43c21e3847662c649cd040393cbf4322d61fa197575d456832a2be8cde8ab102a581004f44a1cf12111cddf32246975fe71e2659bd8e51a0dc9888ecc5e3ad78278bda4e15b10473030e1cef6be0571f4b98a98d4275afbbc8e1e0d8db618c9482e20b94848907c484d905e2418c947ca29245d52d0891067e9f73f89f9aaf444dcbeb8f2f56b4907a21d6d311a1ac9b639929146b29034c76d8e64a791ec0819c90524170909920fa909d28be4830423056dff95fa91e4a8875863c29ded41ad3a5fd4c665467fcd20b2555750258480a280c2091f57511247f4b0e0a6b67f9b34e748d34481de9c4332234453d83bb82311633ccf2bfa9ef87e3e1f1fec9b82a6be20fb09f957045afa97deecec78face11e96ff878e681e1157d4f7c3f9f8f0ff64df1055956016a42becaf15304bacaf1448934bb8d34459134c71369fee92de9157da7ca0a7a23446d869c5e12d145d8316ae3a23642a850b12068fb9f4873268534df8915b236235a528692318abe3842055a8a4bd03449a03727914fbb6cabedc61ac8e56534cda9698a782923b22977791ae2b8d92924cd5091387a93e6cc8138facf458ba34dbd8c0c68b5cfcc8056574a694b95593692ae7ab4a96a35a5214273724134ef4cc8e3ed15d265a3348c97f551f47b595f45b3e811456fea8f722c91e3e5ab122deb5b6db3b30d68758d8c8cd842b349ba521bab6b6c224e10a1e54022874fe9046dfbe7f0c98144caead4d6010a1d6a3c2cc1c36b46072874a86d7f1e5e3c2c51e2b4a2b0c1a5c3133afc9c40dbbfdc26cd6975b9655a51e8f0a3c313335803c1fc85f995fa2b37a850fd509b960fda82b9ca099af23f67b615302a7ea2d8ee82c247f552f9d4aae0b1554ad024b6ea08eada3765d09b31a8925d4463057ae30f436a9a212ba321a239a269663458d8fe31ddca0d2a7e563edbbf05f355016adef24157053083a26820f2470d4492053083ae68b2a0a5af68ce4b0a314b4be6502a28dfe875a0c6fbeece1b3f1415d488cb2abb7ecb0a0e5daab6bbf3c60f4505953282da77e78d9f09d47587a48b59b8dc32c6cce85db71fe95741e9710422c9df4871db3763d07eb639d2bc689a21174d230b71b8ecd34ace1644d5a61f13f2b86c4f0be2e84f6fd29c289a7a393eea6574a85f579da2fd7788418ad466072feb7f30bb9a36cc1c6a03b41a66e71ba0d5e40ab4fa1f6b204dfa0d1668f50ba963e84da75d364cc8e3ed91cbce0100ad5ed9b9055aadb2b1069279528b365565c8cea6b20da0d5a88d3590feabc9cea6eae71b40ab5376c601b4dab4730e5803f5d078233a1d98bf1ac867d481f95bf3d58e9997ab1d60b82c2b07cda6aaa0ab1c5ed0d27d9583081781ae7614010bf96a8790977809945580330a50c3325fe5c05dd0558eae13c571c42e73863aa148156a1511d5a94269951014ad8aa980a8463a04db839f494db3049af2d79ae60934e50fa35d40cf38e38c33f008a5724249799a27d096c9fbd33881b64ede9fa609b4657a7f9a22b4557a7f9a2d684b7c7f1a26d0967d7f1a2d68eb92de9f6609b4357a7f1a25d0167e7f9a24d016eafd6988d096cafbd364415b28ef4f83056d9dde9fe60ada4a797f9a93b6c637a2dfa491c2ce41bf7fa6a1b14e8ba65eb2c0ec8ab3327363c6d0d09774ad68daf54ba6d3ae7f92b22b0d6d75c694138a0a0a8f6868d719534e283474d531917f42be89a6d4a624924f1afdd52310f7e8ad1ec1b8472410499a2dbbbedc3051bb86346034d5a1a1371d52aba2a037fe9b26425449b1fd7780a1fab1fd5550d0d22deb660c9aba29438b1a0bc423b4a059255edb7f98d0c44dd1cdeca6d33739bc489283c8573761d072471190ec10f2d5cd17b43c83a80035cbbae182a69eb82992e3c757375ad0d27db649733aa168fbc370e40d0d894873ee6053f55f5cb20ea0d5de0ea0d55ddea0d5dc06534e38d4100200c4c99f6753d3711b0dae91ba56c72b1d5f5c5a58565254a36fd32e5c2c5e87a090298c39726dff0caa7c5c6683b32cafd9947fd789e238fe97a6d74c1b35cb0a8b78cadf88eb880f925792eda192ede192dc0364fb5ffdd5be259ec2643864625aadb3d4de11a7b1124f61daa56d27472e1c455e3226a94f6bb6edebe3cf58dbdf34c61b75bb69682fde34c41bb769c875dea6a1f76d1a7e79d330839b8660b869188e360d47a44d4312b5a96269d3b0446daac9c9a6e18969d3d084b2698872da343ca56c1aa68c9b86236ad310a5b269a8b2b269b8c2b269c8d2b269d8e2b269e8a25f360d5fa8cd6f4ca48891b124b24d5fe23457e2b54ae2b30bdaf6633b69d5ed8d61eea475a7f7cd326883f0a48d4e92089a9cb493132d055459a1b4a3221d95d07799ff70960ac816a21aa222a22ab2e93bac2a7156104b66dee349cc9c87f7a0f9ca23e2acfa7a157919791d79217925d9f4eb597938ab9e67ed71d61f6705720aa17f0167d52e89a8645cd2b3e9d797afb8a71f84afb63ff246c622222562deb069cdc38c2c2e33c96c38eb93a9542a95ca457a53dce3db1bcba45108b6648fe524729ee7b9f2e2f17abd5e2a1b2a2624168bc546574f4a1031954aa552a9b29d792168738ad79d4e22e7799e282f1eafd7eb65fa4e624262b158cca4be5eafd7eb7cd95910e1837466e92cd3199d79f6d585a0cd261d573a899ce7798a2f1eafd7eb45b248ecccceecccce6cc542ace7799ee7ebf57abd5eafce4fce66af1b715b781239cff3045f3c5e01f9892ac5f7d5700a9e17fa6cffb0abaf0b5ab1fd412e7761fbd78dcb4f6caf67fd1f13acc24cb01a6482d5980956854cb0ed7f42ab5fd4519a486b23cd87b6733a3b129d9ce318f29c36fe8a85c87dc542ec567691ed9e19bc1f7458a865f0be229d6786ed9f39ef4def07db9f7a1d16eaab9e2895fde2aed8c2a0455749ee4d948bbb62fb7f1bb98561fb7b75565f2ad7c77623dcdd7c7046e86cd7c742a4e37e81e5c2865f505950ae2b044ca25cd4e606623d6d94acc6cb6bfbe7122c75a7734b3f28e7ce162c754f908aab58ff597e4413131df115f7be4d78b8f7fe6aefbbee617c8549f33bb26f1528153ea27dbf38e2f3d99708cb506636e5f7e945a13915fbbe8985ca4b9add8f3e8f4a3a10312a8a2f506696e512e422e452045a3acaacd4798a94ce402e45a0abecc345c8571936056dc9fc80b66682d0560c10da829182b6481f44415b9ab6de25c8b25c4e9bea41e641fe917de41dd056f8fe190ada5aa12d1697a032c3ca374fdbccb01c4a32f536341f53f333350f43d6fcdfd7f792403540357f431f6a2e974ba7a7c607090111e356799677395d4e6e646df4e6f21b8e83fa52d35ac3f8353d34a411af3343e233c890f88c18129b0186c44ba88d3f0d12978124b1199ac46590d82747a70669c4ebbc90780cd4e692980cd4c65d482c06122ba136fe2c1ad3f018980c1c869a2a516a675097330a54ad8a36bb6c4cb3ac0ca329ffaecb305a860971ffb79961a71ffa04f3d24d1b3bb9b6ffbd28356a83b2e4f4e304bbe429487cd3e5dc9e61204992cdc4d29b1986828d345fd98a623ad9503c6a1da3b479da26a699b68969a2154c124acd1437d21c95e022941a890b2731127cc44b222bde516a8f464f51cebd83a7b63fe8abad92660a64765fee4d4c03b94b6618b50143345135da124fddef7af6fd5112fb7ec863df077becfbd9fed8f73f0b64dff7ee9b28af99ddee3ed4a0cedafcdd992a25db9fcbb0edf8e525e32744b7c705a40e7fe6f0670cae6a6c5ab36ddbe6f7dabb32b2badc7e43ecac750f42a6f62beb5453fe66b97700c9ca12356d795c97f3c699ddf63a8cefc5f8de0deb917d233a9dfc9feef1c9d1c96f44a7f37d0ee8790e7ed63d46e4e880a268dfff5459ab2a7abda960a8f34a25da94eb6fe70a7ab6f9e29db7cce5ce5ad22445ba45fa559a47f77dd35bd63d41b6cf7faaacada65c6553ee3da8e9a7c1cf59539dbc5516ad2973db5d4d7d6f844a277ff8b6aa426f7fe1bdd7691e6da0deaa3d92bb7eee367df3e7694d6dbeb4b3ee6c4adc5ec893f74676d446abe849dad903bb90479baa5d79b2999337ae20edb8d2f67d4408416f119d8b47c0acedb9bf1ac4376a88c365f76c4f75f2a6a98ecdfb6e8ff5b7ef2529f6c141dd03f7a64793c99d0b8fb3da667fba2788c7fda63b505eb1391a768e92e3bcdf7ee3381ae2a81d28b710dee3e7bedb6a980367d7b0fb0dd4a297389bdbdeb71d2cd7914394bbbee791d8d3f4be078a23cbf6e9ee9a17932603f625535bdcb680a5bc11af130485faec293928540af728dd811cd46f9f9242521195d2030b450e91939292327e8a367376ca73dc8ab85279b386c6dbbc88896cca7191d3a02b2c86c667504c0631e80a93414b2ff215a67979063e036de9f7c766c04b68ebdf1f9b415b2fef8fcb405b2c65d0560b6db9bc3f26036dadfcf6b2a9316031d0560a9381c380c7c034da9a798d683efccde5396cafede5d2c2f2f2a4feec35b40db5f14f691af4cd4a39a353ba460db5019fb4796df3ff42baac7c8b66d12318f70a09644392c40f00ca46aba84d81a81add1304a451f9deecb08ce2b86c5cd2166afc8c1a49934bf9cd04400d27dabcb162e980c3d6b319216eb32ccdb2ccd96c1129cf5548896dff6bafb601749a29d18958782432483fb8511446467ca72fb63fbdb18f2cd18e348989586c7f4a2263fb53d28fed4f4751d8fe7464c4f6a7e110b63ff5ab6b7a50d2562df24027b6cc84cf8c0fc84989ed5f676f821e6912039dd8fe353361fbd7cf8ced5f3f20dbbf7a56d8fed55e0dc303d13489a19cb4557f065b87048ea37150746e5f9d3783edef1b6912eb90b0fd7de33828b6bf6f50d8fecef263a46d2ee0b090ab8531b6bff5f3cdcd05dbdf72a4490c0bd9fef66a61fbdbcbc4f6b7f86a930f13cc2ec17a6d33415169a5d976dda3d8fef7da7d35b803b193d156ad020bb6ff898bb6b0498cb6eefb9f70b1fd71695685ed8fb1252b12db1f5f6edf07e206fbdb25375b9ad156fdfb9e69529ad5cd55d22456df348979234ba6c4bc7a02c3099cfeb224a284a3a78f79f8caf4be4a31b92733199471493dc5b225367d4a71824e4fb9805d65108d210b63e80b9c73db372f155838423665532a9a97b68ca15ac7d8a08e47bde97ebcec9ea06507b31d1668aa2bf2b2bb29cbff710c5df526ab36ddf287717e1aee8827f5b5892c3c526fc299972118b4b4a8b0680434828d62a32a46afe340969190891167fd9b14a926325fe5951a1e99ac797df948b521240a67be52158560d0954a0c14191ed9f6c322cb52d14640948533c50866593841a398af760c8daaa0ab1d5b78615158c485456058c442864523a190e8081546bf429a145109897ca0f8512289236437e573e0e84403c5fcc5d9f433fe2f69fc22887bc29ed0076f9b479d3064c790b3db623b623b84789c137eecf8b123e80353a0eea1470f3f3dbc7a48a2071f2f7be8e9c1b5a426a3832080eabc7c4cea61b4cfa89322754a4719f446898e31ccd033a903703a32608826c5e2ec8185916d5fe7d419d291893843bcb4f9d30168c3c74bfba5d61fa3ff61348dcf33ba6706e68d50e9c47cf93814c1418643173810e5d0440eaf1c6039f8283b580e413a429e59c2e81d31d01ac84071c6a037ec67bd53f3f2151e00ebcc903b348a637184702882830c872ee86ac7161f0e45b67d1c726882b25464c8e165592a5a0e305fe104e5e083ae70a4f8381207220e07a2131c8836d21471207ae510b47584aa0daa229d219e50f7697185155444b1d5d689c3496d70847c85bf256b11b54efb1904c1302cdd68c20dd98d2e6e34e106d1aa89d56b055bf95805b586dc90dde8e206d1aa89d56b055bf9b8417483e806d10da21b4437885641ad21ad213135999e6d3fa626e30ac1301c8d52b8cd64e24cd944bf40fb6824f40bf44b3f410f6922edc54bcf6294a47c78e34c6f5ffb6824f44b3f410f6922ed857ee9977ee9977ee9979ec5288951f2e114ce9405d16c99c56041af1f58cb926dbf85d652d30150f9a47027dfcf269fbf27c8e51e54418d5ef7e113156d49cd4b25346aa3630cca0432b67d15186af4ba0f8f63d09b7c72b3209a2a3325ced26faa24d9f655662a4524904412431ebc4d9fab98f27d26a6cf26142f50141a0a19285ed816a5664f43a0a953cc9e4e3f65817af3669b1d0cd6b59c86548eb010e10cf194fd141d0213f78e23b443f355cadbdf51b25343a1f94a558442065da9c440a99d86708a9da72ce86ac71628d2bc1949b3f448f3516a2d244aed34a472a4daa033442586af7484d16221558eac90e68d0a699628d27cafd31972228da8128276c6d82183da28d9a99de89d25aeac71f878998497af9f9489dca1511b9ba281f46f1a887cff42346b5e35af1b5851d00f2c099898f2a570c7f4251328b33caa0d3a43eacda6a2e14c8113b46368c716a3d77d98c311c2996254d13c92d6d13e1aa671341c214749f9d4f8501b4b95104b691c41309bfac1c1c371bc4e348e9eab71b87696ec98f48ece906ac3ce18646c580cd97644eed0be104d1c213d6463c857db5befcd94d0b69f0ab2ac97b79f8a5996cb5b1f4fd97fbd7e7eb6b53058916d79e004e148f1753c368e508a06291f154d4506e6c093bc99b40e245eda4fd13a8abcb46fa27524711d336a43b463a8ded8d7f105bd394205670218dbfef7f2a136f671845234f8d9f695a029151949f84ac711b4946dfb98346fb689c3e108813842273842546cfb1947288a6d7fc311ea76683b4aa88dfd1d43d5861d31d01bbb4306d2f46dbf149acc5066d4a667771f82bb4d93d9b66f323381a1d641d23a745841635b4714540714f4c72e7ac217431d8c0b212d62411f53c3e1f24902870c68b0ed9b610bb67d13149f8926dd029664776fd22d846cfb3dc06c0f413dc47c650296429e229734533e45641a88064c048a79947067fbeec7573b86bc7c82ae766c414bfb36e563b140592a325022cb52d16caac85738415e7662d0158e14e64d69fe68f2a66876b46dffa47514511bfba1abdaa02aaa373bb648b2ed5b1d61d0f2865a078ad6f1436deca77c2c4b07153445061aa4a259960e28684a0a26f4d8f6ede304f94a8713b4b4b36ddf449a3754d8f641d22cb9305f8b6d3f93e678c5b66f429a22658215dbbea77c76126a5edbfe977aa7a671b81c470fb5b1af2aaa36e07801bdb16f9500836ddf54156d4b2275c0a8cd4c34718446da8610b5b11fa3e919a594a8148b16f0aa9e656a4600800000009316002028140c87c4a2c13850e3d03e14800d729856564e2608e45992a5200c330c21650c00800100191818481c00b0700f9057d44896031ce9978412c352a1522c12efc191843f78751a7c290e5e74d8f9d8f1522462c98e12598657979cf36e2faf349fbf6338cfd1d16325ac3500e8a62316b1d14f0353c94400592dc6da33978eed09b8f3a176265145749e9de3d981e8723b7d2ae5944e2173336ec3d090aba66b10ff59304166c553a3469c9437798edc8794150c3ca75e20e05f39b078e179d5366b395d0658ac743adaee4b417691f553118584ddd98b6a2f887d2981677a8a49ddc60fdfcc2b2ffddc2a95caf5c0c833ad595c1f2134499a2f7e2f405a20bdf9a4c4e8843f0aa6c7094f6c63981437171a99f1c882f07b1c07c8154653a5a099730fb55907fd5e3fe17ab9d417fa99f0b31c6b6cf9939ef13d28a2a0130348532773f1c236c2286102709c200568f3c35214586c7d97d02649e7b53500d82e0a5c9ba5788d4de9248da4ee27c993c4485ccc0be2289ec2a2f9b6bdebdd1f8f1fea8b23dc0e77abf579038d64af88b3d94b01d60d43ea42d8bed594500c40dc1a717534e2e143e4f4b14613c0f6a9d1ee31acccb60ca107ea536a4930a85658ddb194b0a83b4558a8826c6c43c81f2d38b5914251323469dee9967b06ffab12b4f4aa11947cd12f16b12e1864ebc336f5911e803cc3d6e5ee53d0c7f533061adaa91c82dd0e1dbcc2d294acf04303e3fc78f2504baf152ebc4d677ed63e74317d95c59116b084d0d2afa5be6eb0ae1da2625de0061a6e65d86a1602e4386dcde25d4bd7aad4c3ca01bf6dcf56d886d5b17b8370c96a37321a99b45c19057626976bb257548743b2bb92eababcb375a6572173014b13078e7873014a2777c6bab476c7781a28ed75c26689884c503366a1fbc3f512be41e219a8cf5a2e7d1d2f7f9dafeb31c1b9c4f8fd59a45e7a6c0b622e3c84f1cfc15ea139c149fcc65bc9b75ffa29426c4e710257b1b9d5595dbeb7f2942018de3c48447a6c72e3618cd0ffc48d58177cbba42ec0582a6eeddbafd961d7198f759abf4d8f5e94184df24a3e742bf82fea424687565dda8d0b15a866726323f9a4d71d838f3ca8f9234eed3a1e411bca1a617416a6a6408457b7fde17476623d9c8da4d3110eed5d7aca4f5f6630e0fb2f8070b877e4e72f9edef8be28942b79914d8fe4a763e1a411fd71d0b5324f32554ed4b504e5f8f8269be8fc7bd9b207396a23cb9020a13c69a6848883ea9c13fe095082e0db10ac39621bedac746a23504902f48e3caee619f5968a4a896c162223e05065571591c3b92e4def6b630ed558fd5bdbfe9baaf0f42e3c19f95b0745ac9a0706ab71d501f503380ce40a757f6ae1e0a6e69152e6f772245565ed67cacc830ea06941d915f49eaa85330f7562b6dc37ed31c05f1d9a26af009aa674c6e2141b151b7dfb5c3b1bdfb566d1b9c72cd51a0805b239e80e8cae6ba8fbff4e035dc81595e8450fd17e63402a6e3455029aba93eba70a76bdd64b3ac188751594a7623fe99a83d3bf792a0f2ea95a40f02ab5ac1ce34a2c02ae9d126dfaa9219ce55417dff5c250b90ea09ebe51ac0d0c2c73aa22f526bf28edff42c8a9c64f262544117813e866519f27cac39603c71f46f9abab9a305bac047c71a52dcaaa2b16021b6a5aba4d7851864594b8358a35d9409f718f9e7f3a215bd7a459a11ceda9db20a567f923fc1b3c11f6abf3f78073c7a34611a20f813768d67a8d934b1366b01a27d3f880ea727b6455986fb6500c3f725e87f8ce3fa8ef5de85713a6dd0a36d830d0f24462004c20966b14ea41d0249b4329c7f6c605fc385441ab7a3bb7a7dc24e4db8d4d756a6a343829d526e8f16b0e585578b1654bff0f94b282fb33ca5c9d66ad1d35b5377162c06b5e5ff55256a0f51d579aa5d6a1756cebf7b213f16d6cd033fd6d9026ab25454b17e0b43363efc55c8b5a31d795e1eb04c6535623d9e0b193522dc8e3bd22af8042374721e0d825decaabb98dc131f98aa393805a1a56bd17216e9418967b0c2d92dc485ac8f0c86f6c19422d28657490f261632693b1d643c08c52cedeb65ce60ae7decec40eefdfc25fa1215fda01e820c52671a26e069b9291536542780acd18e361bec2fb59d6933b3c8f42b3067e9750342a9477ef2b75a430e5585e828acb4c25bdab430f8543d2a831709e7ad783d6f4e2916f7549c47a2d551d7e1cfd5dc1639a79120f1eb88012d704e7c9637520bcf09fafebf1dff5fb3862ff55756eba19eb8d0c18258db0b014ae520a06136ceca5f8952419bb988b6e62547c63fa9fc02bd84a61a7efb278d235def88375ed02b8e79822da0a1117a7b8859aaab431b346a33127fb947361050fb98e01e4f445b5b7651f1c724f5b0ccd6af25fb0645a8eb62410d72b356c05670c5bb8e983cb5ca4f71f0912be2622b3b0826ad046e397440f038ae08c60401a702399a861ae9cefdbd9e908794defe3f92f26743a1f36ed784b4eb57f19ac711f6815265435fed2246de3e2a151c5104b0db1e44716e749360507b809da40c1729f1c93c6d5440ef3316fa1e17e62ff4e14e370897507509246b141b965d093f7c9c57dc64c1418cd6a4cc38c9dfd0fe3e39c3909e26ea16ba158a4143aa6eafa15b74b60d9d79189992478eef29283ecc5630056bff4b50a99956eb215bcb64c8a01e3116743bbc6f0950a5117157ad5275d80354bfc45125eb85c38b0e912fc26f30553e441e12a1d999c09426e8796e4361914070fb7c57b7e972a1e2cb916396597bafdb2b5a38f170b58d7d808c7dfcf7896cf9d6cc2dff1298f17c6e8426abe4ae557f94861a923aa48cc975d52340f196410d21dda014240c85ad5b6700364c5c14bc42aa829dcf9acce46a22f1a8dab96008accaa270a2318bda6d0d4d787bc539abec7bc246842c86e5685e1d1cd4969521b53f5b233ad7815c5e1ee6b76416240ccc92702b4b8762fee2531988cdbe099739c5c12db2eb6413e9dd9e9be7c7f51308b970351d77e68f1e26fb878539fe3bf52f1f2af78cfeaaa5e3b57bd13a22843ef41054c2b0ca487e9d5cbf44297d046d7166fbc148a4e9d354cc8795ae83c9d0467e0926802114ba981aafe5ed982855d2e98400f0582c52d195e7cfd4f5fed8d575fad9f9072a1f37f0b9425a001e76d6fcb2734c487bdde42d7bdd67ad93b5216c35356a028d1085907b61eaaeca37adb5b72c13a41074d63ab8bf9b64b0c38130551e706b9e16c6b062458cfcfcef372b9836f5ffb07b221b289a05913f46d8143393becaa2562068144c1ed057a32f582ce4bf7e8508a44b56a329c8f4a709304763cfcf8e6e1986f800e5f4fdfc38837552f20fd52931043539d95f6108dd9c9ddcf621468a1132d929a8cdd8f7f9b09782f2dc09ce2f4df96f55fb5dc4e40a0195045332027cd807e9a01118df5d40cec898f9ec19574deb4e8e5f9af7232fa2f9cf5dfa6d03858bcc607d35472fd6816c5743c883a6aca8814143fe55ebfe7e81a37a30ece8f6411f9343d99570fa0e01832d028745d38cf1d368d74747dfecba36c61e4859cab72c43f78ac82ff4060e5379f2eb08a1f029b3e5af4dbb8d3f9b6484935230ff0c77d5539c08c839a78d39c237a83a866137b1badd7dde590d796c5bf05da25d08af8072fab60f4a13c521d43d0887ba0a2dcc8c4c19374e7e19987fd3a79d5c08184aee8b2e1fda3430ea8fc28d42f61b6a92db8b5b189c2a45107145a05c307b42a35aeebb6607746ac574100d2b7d29fad7b674098be4397672d6556ee7554b08ba6cca7758cd71b599dc5c79af17e645805bfa8e81cadb9286e39fac934f4f9236b2b6d09e9f617f232d2128dc8470a0004bf87441ed76c4bbb363da97adb0f863b61a523599a5d6be934fd7794fb297de80408122e12fa8ff3005a94e0205fe74a53f486c94c5dcbedc639da62296e52234e07cc0251edb17fc90045ad9672082ba5386c7dd1abdb121d07bd97cb43c8cf9e8df2364c1089a9fd2bb8c9f4745f8b651ba00105f1ecf5eb67d014d16bb0dc8dc70b040b8b753caae84755af65f022ffa73ea27eff3aba930ca75d8c12a298cdd93edb2d67d2626ead45714f3bf847b779cc2c6c978bfe50e7b5f172dd3e6e6decb660e6aea30c5a7132b553e71db357b1863552a8118e2174595b2e1e1af56f5e011a12ab013f58d0bf856b02260a21dc98879f6183c7b16b3ee1dcac90f8b1a23a5dd4bcf2576227562c2b912012f1a575afbd3a9d2956372bbbc3c18fa0cfbcec7b6b1593ea53fab3cfe539696ab7676ea3efa48e89ca95e567af7b37be17bb9ba0f7d76b4bead4c0250a3167c8977a1a52f6c345382eae8a19646f29c44078bd5f6ccc0a8e5162d8ba5e9c29459b833ffc4ca1668af02da031d5f716b8dbe4e9372aade826f4a30eb58a52f0c90012d04f977ca29cd3cde7151ec77e56c52ed6062e98f9d59fdd6785534162b8cacbe31c29beecfc3c881ab3ae2aa069d9ebe6a97103608371b03a4daa172b9fa3206cd1592dc07a6264362c787b8017ddc77135000111c260e908893e1b3dafcced95582d46444981d4f0c8cde99fe4393a0ae9c7ff15d39db4c66302ca96a19f02b2fd1ad6e7d28100b4c393623c170c51faf841139d920a4e06cdc5e66aa94e88ee23c28625a565e5630635974d3effd5cbc4f57a2e2c3d36a020a4b9089e661f18ce9064de015fdcd55414b98d5849494a3b4e5d05b79c79a15c9c846486bc21f9f96fdd813947df0a49f6c7cb11f3cbd0afe2943f7ee7724eba17cd12870fa2506cd97bed10ec227ef14900ef7227dda4360b3ad8c5aa1f2e59d3aadb7c709ca907167c48a8dd95bb35078d159f37809fab386357b48408f212c1089df076a3608f4a70debe4eb8bbb2aa7344f5d8495609964fbb52613671acb1aa8df0b6b9a0ab9f84205b1c1d87a9a60355a4fe65f7932ce4e69a6c61053746e9e61e9c4b772511bdb6bfbb6b4434eadbf9cf4b8bc6ca781a1d8bbb5aca091ac6ad17e5d294c3b745208fac95a78e253a4721d7cf59800f9f64ced5690272ed1f2e4cb5e1cdce39e49af844dad146b675e8942ff70e1b1141a8928df6928067e3ab2ab43b8032a48f86e7359fe3f1a645a02b84fead0fc3ea0f6fb2be2af9043bf46888471258e55a0d2ed6f3bb165b05dceaccabd63ffe97a364248db40600688469a04bcf00ece18783d1da9cecc7e0ad00fa56827b498ef95162ae6e3438ae1e6fb6191fad9f9b26ff5d555a950a1402e8dbd7e63c7288b6a8432d8fd3cfca14d05f48a45fd1ac5de8c9e68991095f108196a2f060a7b868da01a3f7cbd7a3b37f5fd9852e7ca80b7de8c2af7aa0bfbcd57f77e18a423308d21b740e96ab4d7c7d05c3874870c885cbccb95d7b9cd87b4c3d85459436b6c0291e5f499d64f7ca48040d5a32f6946119857848280a718806aa62a067afea5dd1850d0e41e89dbf6fe85231000945e6964326008e8041fe3f1e15f966624538f41b585584c1f5524787dc2bee879163c5ca9ac01fc9e52289efaf00e9d406a06e400e073350870e27bc7095b6890323d150e2300a852d1c87194e24b8dae0857d4dab3dc5b43093892d1ed5cb445f485de206b1c2fc574a276e4830b28f04045f900083815296fa29e5603c9808e8964640110992c2f71d71c24a4ea0d50a37005bd3acc9ee09d379e9f5830d1423851a641980c3b8aaae8a6fb95a1279c85de65aeb82b3d93227298695dbcf4dcf3ff65f512b7286679b86b998438a1ec363c4301cae8430a738b3b458ee1aebca11f04a9733188e2e30de253243bd7956864e740a4048d4d6c3ffd5afffafed587678bdc7997082215f5dcc36ae4c03adfc8cf9c77defe808b4d7633cda82535a5d4e90f54a9dec90aac4736e7dd0d1cf43a4c2a827449b9a63b4e499d2487bf0f5985f63a05de02d7c6cf64759d63e3f816687a2e36542f372aadf5758054e3f851c517b88fc87e9b6d0f50eae7dccb1cfaef329509b240604e0545eb4d0c6648ad35325b34e4bb21c8af35ffb89c92b0fe77c755f2b2ba32a17655326c8f6d30a2527a7f66c3a06132890ee4ab27334e61d2750d9e356bf915b17d9d36a8a4c42f49778a3224d25b4b764bc99a5654d6720a8f78b177b90ccfa446a706f133e8678f50145690ce9237eba09d05905165207306fca7efe80bf3e96a97597eb19b49a0c0fcec08ac9667b5dcc92c9d675194a26ca5186267c5eb286d01d123487e0638bf717143012e630441873bac40d595ac31cf5c31ffab364a1d50d7403d845ba5b26ee3a967750b73aa7b67878143bbdf50a001a28fa2f4c84d9a791dbc8563f8f545e6883f77b3237d48dcc01944066118eb890424b673ec9cbc6cf33541875560041c729df86760bb54351e50ee9e66e2fe1b98642e0ac6db64785f989564e9ea619237ffe68ac6bad3c02906b4233c311fc4614c541c0e6ebd9b2799eaa528e91a370921d94b7f2bb5e223006301fd139ca7cf9b04d8c4a06701ecbcd8d0958714fe671efb857bcdead4dd1c376d79ace35aee8e6e8ee7a267b239fa08f07e0ad6a46e91f0438e2c0d911dddcb288b3f3212fb37e6c4e4ba8bd1209011fbdd5085a020eabd806439c59e7da51eb2926a6cce997c6f258b25d7c463585ca22d405d85ce7318f39cc3f1c2048efa0946380db3c2f3d7b806da4f35d4dba4640522c278c36c667d65cf29d3d5d37d8b2d2fa7dd1a2f9b4c1bb630a4651959d09cae977d178271998686c51af23adef2d5467a3aa95f90998a562b8bf07e31039b781a60fcbb445c02ef2b05a73c9d08aa5f3c18b784194e50bd7c5eb6dedfec6ec94b6e713e467bb6b2e787a8d1472aa16a39b55336e8914d4b4667d8a4d90365a95d1b7ce4c300df4d2678af487952f8459cd3a87f22c4487761672bffc63a0c2c6786c65d274fd35a6bdf837c3dbb42eea4e2f01e05421c9593ce24f9e8df7e6250a4cd0d80b1f05dd0eec5bf1b06191bd1bff259092242df3b8acf325920196396ed12bca1c55c16a76187b2e4fad53c98aeadb7956f6dbd07eee15d1c57f50a4b8f75036d30fc02fed6ab811336560ca5898e4c50357a4acb6c020b1ec94f7492392bbc8ac8160e5ec1f86aceba6951a5d9bbbd9d64f9e2b15dcc57bb414542813ff63be71dc152ba5aa762309404f3a86adb9176658c295d6773e139515f9db535950d387a24e94cf20c9c4e08828a5a06f763190121e4a8818051180872739693bacc4baba1c124c4929a454c4354dfd94138434315819f60a61e1619af8f87ab47428247f10190ef4f8f5f81b9b77f6e6af73de55e11e1024afbaf5dbfd1501408696aeeb70565745582f1918b4a679f6375d934f0644374b29eedcd43282ff7c02cc088477458e59837bb9764f2f2a5d6d32741efb75399053fe1fd98f570027c6b75c6f7fd28e6bfddff9415e38af975aa70c800e3ba25a390700c34440082b3fae3587f48b1931062ad685cdf0a2a1e2aababf222c1ba658099c96a400bf983a6b998d60afa40cc586ce2b448a1bafc8d424210b7453dc06d05bfa0a77e360641da34be00cfa7ce29f5a3c6f447693213f0abc31790669d4dc5653cbb6075ddfbacc1b96e0edc0e8a8a484b8d7a60b75476017b5f959371f117a3adcf91a3538f5c4e214a54164a36f7632865d371a9df3a1c14edb09cb955bd8d9b8c130d29e7e1fbe72ce8669a795d3fcc757a072ec836424aae1d7c0374e4eefb8c154d7872b032b1ee5b8c5f92c3494f26dfaa36e67394d26c0ea03cbf9a3bf46dc510e6297bd638765898740e168dfe63fad34f8a62f0ede1d8975da2c8206dc26888dbb84a4c10b407abc4eed3469e6fad67760e13d25cec9e3b353890fe3c3640c51bd94f99dc65561230acffeee4ccb49abc18ee64e1d6411cf288327c72edb32452358ea14345df34daaa868e544b4d199f659563de511779367da8563d5fe4aaa7c0edbd48117c257153f6134742b1dc08a9d4a5fd8ac20dbc3906949d8169fa1b1852b9073157f1608543190376b3e01b9402a7023eab8e8e7c825be230b789b9bddcf4f56869352e77ad74c2e77fdbf5c3ee4ea3cc1013d26a376491c6d136f4782108b8815a9bb0432f3a380f853a98d3136934f08a0f66d225807c681e24a7f744036e57337db5c028e67cf42c95178eb19a016cfa40580fed0d5da4985209a038320f288038215ecb8034e439418207600fdbf1bf457c0dee4f6ca48a64dcb6f414d31f0a2c0ed68ebcbf812f2fccf608fddbd3d825969aa2c64fde0757d61f20addd79e3c972a7f513c3f18e03bf08f6231dfd2de9de7b7b4b56458bb8d6ccc4523ea1a81c62a7e045ff354d69e63bce9035301c1111a31df36abbfcab9ab2cab6a91e711b3927746a8d70187c851e5d916d7dc9e6ad344163729c12a2868cc3f38ac20b87e5c078f232b738f5503215d5597a7b77b106d7e3f2c02b7ee1a1c97f4002fa343f72e1d2b2a88dcf4cd167c04cce54344d1aac9cb6e48a0bd7ff8ca04771fa2fc002ce5f6c35b45cf304f19b9ccb4192340f64aa92d4343413dfb7df4fceb35bb69d073eb4d8eb71fcea627410336dec6d68011f18b8dd4ae1ba1fde0234761a2e24e2165a21678022278f6ea76db968efaabaed3ab58cb05a22f92e85ace73a886142d775189748c85d506f60cec333067c1a71a1db9d152b20ec279d61a8846784ca757208a6fae2132dab1803f28490efadfcfe9d1dbfd4326220aebbb920a91e3bc44bc78db2d485050c9cfd1f4326d90d23ee2ebcf5c441ea07c6436b2de33843779c2cb130213afe69d7439648487b2d1639ae03b87e1054e71fea3bc57858ce47797e07b43515d0fb2e1a29cd8bb8f54387d92e747701a81bc0cd6c670a97d96c9eb60f69894f08960560dea6b4a2ce0e4c0cb0527f7402aeb81a5f4c0e483427fc954b3668fb0bcd6e1284309adb2afb909ce732b2a497dfd28674720373e7bbe0268e8e441e5ec6bfaf1142e886b35bfeb9378b1412955e34af698376cb5ad8a74c6dce5aa05950d50e13883b686a99aca8b4c03f4d6eb1c47feb106eaa68bd881a4ae1f82f76015e443d2ecc31b79437240418817d705b3a93f936aba31d9cf6ad6e7ac0ae139e2686928bdc70a3edca2a7bbf1a14934fb430ce6328ab72aaa9c06611e3a402ad50a9bfca1095e39ec3d9253e5ee7a87f876887f5fd79cbb809fad051cbb0055f74e1a8464a4e4c9865cffc605cf995067c9a3e7f786256ea0990c8030787b20b3aa146c4193403ee0c878a36be433bc22e0efd44a0d3eaed767a70bc7644cead2de26e0d76480c4251f4e96492123b0fe2db0457b0fb305edf44c4fafe939515ea23a79a983896e00a97f98dc7ed1eed5d21c5fef55adbb624ad71155acdf1028d532010133491383d208f1d444efd38749aa22d9831e22bd67a9025e5dd902004e951cb6f685401661e97abe4a93c3dc16769f2a2dae668c321f6b2ad7c2041adf286317fadc16ca7890a7abef979b1ecd04b4c54c5df62737a4934f3990d7704b3177d29849e9bb21500168a7043d52df4ef18d83547e83fa0c10200b9920458dde5613c648b80dfa73d2d13e06d0ee54835eaa171fdd343e8ac410eff713176ebbe362939cffc4333488b1f21876de887fac64f7672b0bfe88a7d85dd8eaf929cc3b085242bebd121b76a84eb526ebc4980c01c9f5de311cf4723075f1a8cbd61aea14f45350d78f89b7bbfb036fe20fca4b704363286f35663de3d399443f16172db211974c4544cb9959de83c16efb9b8fdd4c351670e2512f95cfb098805e342dcd5632e4a02175810d4c9758921d8e3bfae16dc1d2defe32183970751ce99219c24e2c64b6e142e0b3ad00708290cda652b8fd819241d5dcfc95b64b373ed0b13eacf4275f545d59c8e8d42e5b7707df115ac31dd302999884280fc707805aa6ecb99296ec0e6a82fb6101d7f60617b66ef63ea6466d73500d3029a14af1abdad675a59bfd9c941295c2541b84c61729802dcd6c82ff71fb47660c6574532045830e05ca04b977217fc57f4102de4f9b592434dbc339077f0efe398213a92443d5fb425324973f01c2a39001406eef65cb37674e369b6de23a0bd2770c6d842b1a5d7ac652f4514813c0cbbb2f67c8d809400ca43a32fb867b683b7f23a754c792c345d34528b6c8aa63e17cc53bf1638faad8f02a843b43b1467334d2d88e0ed277288b2cd0256951e00fbf6293e7a1bb83d2fb9d7a5236bf820ddea769452dc5da7ef936c07c3cb7f03c8c82322f545ef321c74e47995e0a1121ae9cd6836c46815a21c1cc50ccda94d6d0d01fc1b68a06dbc4830c9362810112abfb5654a9f4138af4ede0f2a7ef07acd33a74ac4459231b0c703408a5348836375866858c58b51dba327481132a39a4adab40067d20f46de0a70b58395578f023901303e77c9b52c74e6ec41229889736632d8eb89fa79fb9495e46c4b81b12acca4f1a12668bc48923ae0825b7573dc48f91e2c29241c1088026b93d0697fbd4564db47233b56d74ae2c31b714b68898a0e4d387278be776bc46d825082e9da9efe9391e00a6ce64093311ffd111084f6c92b5e170380d5589e0ea0244383e35f2964146d107845bdca4f4165062672fceb6358e3b28d23f68d56a00db5b0d9571c0af9e194aa39db054b3bfd1ee87837a746ffc30b81f0001dc48c36fa39da242d509dc5c791ec478d6ffdfb41f863ee99cfb6cbe928b037fe6903697851b8817fc6bfe184da9b469298c5402fe29ff4d351cd5d1fc44a2feaa4216f061e146c4916005383d71ccc1cd0fc7a95411a495f2982011ec268d361feb1c592fdfb85d09ca0a43ef500ece9f3e87242162afb363e715163c99ca8ad9542185dee11fdb48489635ece3c6e00807349f1d938549f8ee3ab01402e676aa5ddd20cc3784d956a591099635287058077c660ac639afad78c40f58c364e54e49b560212d56cdd4b0d59486f9326dd981319574f51b4054ffd9350d8cfcf42a0b0d525a33d27325a886f56c441c6dd7ee423ce293f05ea10c4c85890d8471e192b2f138884700573d8ea21b3cc000329707c9713eff37177ec03465e6e195895d5ab3744171a4914cdbfd960ce8f88bb6e8d1edcba96eaa5f19b177fb10581629e435ccd5cbaaa328a645aa8b0e20e6bda55a60f99afc98cf114a95f703405a1e57e433a87e905cdd4aa5aa5c6c2aa33a2b30489bdda0f7a98082642fd783c52a908f838ee2efd1445ff4272a20be990dc93852c1e9795ed93d6dfd3b0fe3ffaf7bf1ba0aebd9a29f3979fc342cd03b07a8451ee4b248f89afa32a8fd1514b44321595f7be8f0f2fed38e29f56f37be48fc6966805c431989a858640d4ff0c6ad8f92627d642f3a4fff3fb41d3623b6a932ee1b37d36c4ec85809410435ef12adebe92f6db9009c1a22ad03998935f93215338b1c08d3770538bafaca928eec13b8af124260f623b89502f274cca8e82775d6599d9f57461b64fbe77137597dad48d971f3c66ca889b8516be230cd7f798e947fb13517fc8391c7813e1b4b9764681d68a88e672f10c64cc5cbd2625f3585fd81d8080420e7f73c9aae26471b743a990a1b4cac2a5269f392e43e337fdd0c0ef1d2643b7823d9fb17022d1fe08710f2d236abb1c3253e70041b010a44dd5dc5f0d1f4855d5af5d7bb598908423eef949ed1dee1ddd7349a34733828f58ad0885daf019b1bb3a71bd56bef6877ea5de59e0c52836c05a911b8dca7c12acd16a6f1da742c962a949b3b72b1a8fee40695e74603ca0631468991e55d2bb7c18695fdabf7baf789af9b975baed6e380481335ac5b9eadec7fb6cd5db30fe5ba506e6c511c101e32bb9f6a44343a1254a2faa10b7516fe14fd2e1ea63e01ce49cbc2fab2f6aa0fcd76cc53cd7552e63202a746aa0f360f3c3bf319f09ca091031cb341d4e5cf891e605f0ea549a3f1a453a8c22032a4d1fd17f7e022c42df751fc5d9b3668d3b3811bc7f52c43a6de01934ba982ea629e603a706af35feb7a633a9212ce479bfd92f86d192eff285700d9ed07d2d096260385fb3a3cdb84d26e60b1a74895348271d3c6256b86a918db89a35e4e46289addd92b469f5ca6a4524bc8c22bc4973fd257217cec9112db1ce4f937969296fd32480e77a46cc151966147aa6f0cc96a67955df7a6f5d6a92b300c51ad005251a7d8cd7fabd472c1fb08cedd8598926a5abfe130111b6ecc535ddc3fcb7d26a0c9ba5e3af35c7f297191241d5272c8096e19549ae353fc93e8d04977fa327f2346665c299041c3e76ea72b518f8820d7eea0e9881bae5c53f5e2dc3a2956e4a9b67f8671b057702816d2c19d016c5fd0ce53a88c404fc6a826a185bd029fbde67a03c0d7a1a3aa8d116aa69c9a20a93ca50050fd2f0c2e71e3bb417ad3be6094a67a6cfc9a815cfc33f6ca3ed6cfc58e0c74937cd538ed61b1a69711d3b609dffa79edc225a675bd087275545e91a7a8ae98c73e51e1ed8e8ee70e91dce8c34d471fc036f8e5552069924117d956cd781e55a6ed5e9858afacad678cc64f26bbfd5c80700f1eaa2c047b1d7dbf5fc3f79e647fe43da44dfd6dbc77137b0533aa68091430867e74a922cdff80b55b0359f1dd53db3965bbea82782aff92a888f1e8a0114ea16cc8776b38855ed2643e416da48d9f305db061b2a88589185dc80d8f5e5526ed177e2ca706870e7eb865e9f0ca8f24b172967494421c6a682e2b8d2786e0ca7a5f3ab70686cc2503a3a210708873079d9db8bd4f4581f8066fb9a0fe4332e51e828b88eb3ba12994b9861c7f8a7e5da71fcd44f14d65bdf143cffaaeaffdbc068c080d332044506c5fd957262e9da29c1a57aa19797854c5dc27bef8564d24e49d24396627da80a892418944611edbe40c54b3184d44ba393804520602bd32e5525e82c142057fa2bc85617fb46afd0c700d119fb54b99ca0dfdc531e434a63784dd8153bef6a124b8db24ce6fe5897cad7bcfd7e8fc0bc3f8fef99970685d8310557b7c58146afc8696090ea9350ea44e0ef7640e6cbd330653bad501a0fde77d55771d0c69ee782f2e10857c5b07176c890da09f3a3842cf4e5d0b7b722c1c42e1830e5c0ce14f9465cb8107f3c1069203969ed996423b263e861ba9ef562934a951b867efd8f19b32087df328bd18aadf1a76fe7bc61f201a290484303300ea4f0471308fd2c48071c1f9b97ebe3a46cd5e0350ab57040283dd6310cc08f4b77734f86dc060f507d1343ad62ac02a5e110cd8398abd675c1fde7aba7bbeabbb936bb6f782632c03a292f68e2d5da742316c676993dc9078681b1a14b361d007367d93ec3c48e310d52da2c1bd40c16d81193ed950a3fc66b784ec653cf8b2e1fe32cd02937883f99fb29d7251aa03aa5b557b9a21e31093386e170369614a9cb35bae3445cdba06407f47e1011ba2785200b8e190d42d1ff417ddf2e3c3dc83b0770f3bf0fd701bf02952e1590c5dc7a40071e11e8ab98ae8544239970c1bce981f59b28fcf08db5d3a54ecc5f713e52e59251494a722d79210a7dcd0f4cc8b4f97a908caa2d2c6f854d9392c0daa8049f8506cdfdedafd016110fa6553d682b29b35ee10f7906b6eb28975039edf05e5a3378ea7a89814202edc23edc677f3a858ab81687fd113d032472ba27ef14f7d6496eacb547618d0980e25b6941b730aed94d25f3726d49d7f70c5e446826b0eb38497929e7abe74b55b4a8bc432efa03fa5a851ee726ee8b8a04268de8ec845590db06ef5ea698619424cc5f05d6ca48320f1989dbcd2342ad61a0228508fa3cc801fa3385900b8703cc56d4914022f038fc4a80b502d801af03abed5863b439c913bfa614ae20f63beff3c650ab5361816b00e3e55824a166887226a329b00aa73f2cce9a3ad71c6e36f621026548a74e227f047719ffbb00f004a0e479c33aad7eca383f5d730262fad0cbde31937f136e5308d0a3e08ba7ec28170189c788c52e7d86630ab7d0cc661baf8111d125b50137ccb87ce173803e975af20565e74f8233485aa7a24a6e042b76fd2d03a41e0543bf431fcfb90228d1e787b8c93d24e6e4f2d8920bcca375cd0979fddbfbce179c405cf5041e98292560dc27500d53f9a5e89dcebe7049cd6ed4aa40a673885e5e73a97a13a818c69309a1fc4f5f06f5456f83fc1f8ddc49b22f9807d88e6f94203f7b3953e11f37916228b9227426f70f82f5cf87e027b0ea484044f9b4f52d7d99e1cee09950ab327c1d78c696dcc242f55ffcbe4ec26ccb2b9226a8a7f9b2fcbc59eb6786cf82c1e3247635c1006ccdf2d22ca76dd0b9be864ac3d2f358160d051865f3fae08adbc0804d5c587422ed186b8f570d58bd8dcc7715dfe028d26693d046e7e7c3bb71813c1c7d1b062a30da5adc16aa80a0ba24640d1c5e6c21afd55b108bff57d5c5762f4bed7f3e9e5f0c682e368c34c0084977a5810e982b2e7d1cc628ae3bb8ed01df4ed058a4a871c702977b39fe7a8fda4dd3829c48b1f1a7e60b23bfb4f8b333eaf104641f1c029e5e90ae4d26b7650a056ed119900b25da30e8e5ad35fe9c81ee3d2878aa13dbcb6b89b8e37a4afc5825d93a66cda4b1205e2a41b84454a349b88cf73b181cc56afbacd228caee73bfedb6c91a13ff463c36991e0dce2a5701b9e2635dbfb9d468a5a1307d4c3b355a181afa0e2c2bf3e17987cab465ce43856ba986ec38bc7641cf6a8b3def287e6cacfa79b36a6ec734e5b08a23b34d257594c4a44d12040fd86dfbb1fa2e133742ec0935e8449840b601181a38299c57ae854ea0eb1c44bc28c3dd6c20470df1344a74d214c5dbaf9a73620aee559b432697292a85c2f40e3b410f8aaeec95174b9308d48facf99c3c9f7764f990e9a0837ce0d5c22ca5f294b2c7f218e029e1280ad8d1a179b94e41f8deb0f6a7001e47ad63041288fe57301cda224850e5fb293dcbf380b084d26afd56075b66e6e16accfc0f3aea5654b7e37704a4c79862d6908b6c6e9b90ac8c6a505945566c2e2712cf6bca1803cff60c835645969e983f621bedd6dd3b5eafa0622a788d75fe618ac8727b6823389f528b234aae47b8092c878656986b6d27449e45fef94168a7f5004685adc501ab93fa2087923b3a40c6088d6c473a5db5000aa9f95216fb20cfb0a68d02ec8c6b0c15cf6a272d8fadc9a9b0f8ca05016a1960de49a3474b2715b3fb9cc3fe49549648a55b76242e0e490e255a2ab08a33d5e8f033d2b6880c4c87495a76098671b8c2a5f49583f56b8e1f026110aa8d1c8c5304593e1529f9ed07dddbc9111da564f95122591a1b67518943d65e93e8a60347cd4b8a76a1402033d61b8f896f19092f0418114385e79dfa2d928b090c8e2005f0e8432f9884d9167c9bddd2a73ef8eba970d6c06cbd2a62c581f76e176b45bd0b250cbc296855b16b48f251d04f066d62a837a83446b72abc476ca8e238989e503f65c588b1102e05f9f09176d69fe99c8d536daf37c1f7f0a3781341d434f021b0f15b044fea16d78fba390b1428391aa790df1dcf953fbacd8f1d4e26ba2bb48d7ed9535627358821ad4e022cc0bfb471da833de4aab9aa71667030c07cc0ebe6baa772da1d37426345a212e7c9b0225afdf5fd068947c9501801a6994f72959e9fdf92b76156c1208b642fdae85ec805e18cba60c0c04ca955fbe1b9e1b8dad52a45186d69224b53c0b973adc52ad754e946a1e7b497f2eb03fe4835302a75e07916f788e26cc22c3e9d28de72ec2a4319c32577a649e25fff5e42be5fdda340cac38f163ed7bd3d2623955fee749f4d3bf6a52dc25496041e2a223a6651e2fd070b0d38b8c76c06481a1141f711e8c83cbfd364b2c1ec54660dc01bafe53ec152c34c626e6b77c1c87bcf1e60006894f4674301a24032144150b7c44461f432388f4ce04d68c26e6378109ad42287a19494ecbb5da961dc0b5bf81629938d5532510dc21038d1286d34b470c8d9187f306ad2a847d5da46c236441b64eb46f657ba06b221b2e23f228a5bb92fabe92decec70f74a85b1e42f0e623c96b171928f94953a743ea4478ee44b76fa50a0954a3ac3715e0e14d4511a159051bce217d0d38efa9c0678c8c10e7f19856f9d53a4f865edca6e6f63e89a7934dd4594f9c2b5f132be03ca3cca32ef43572c0ebf34dbfa18896be4356f75306a1b4b03dfb3a82f4e79a230c9c1c4cbe2ee1f4565e3d36e969e0eb5898b4fce7edc2fa1a59f8999b408b20781d41aacb8f293ddc105ce90f613e422eafdc6e31cbec7802527815675cf3907eccf59f183c88b68fd7ce1c70ba3c022d7827a17038bacb9ea51a275bb4e2bd9a55435c7953fecf73b5fb05fd2726014abdb229edc1318ef959f23dfc971490982b6f6c8722784e50884e7282b978e78c668682176313d8c869a3479328742436440ae28652ba218a15964595b6ba8c98f7504159ab0f4202cb244f210958a59610fdcc55a89bb750053e8a66264199bfd62add334ec037c7b5217011b4160908288a4de07c3937925bd9df4d9664b2c0d28e05ae70fa0f44ca7870bb579bf29f5682c5643c9759aebabbec5d5db569f0cc9287a2347085b977f12cf861e5b1e084dd5c419e597478e16a20d114b9ee6a93bd875d236155a93aa809aae1f4ff78d0a50a3a4012ef6a7d9c79fd80c21334debcf41dcc7459466646a5c6068f2a636cca75974c3d7da2361c8f41b2b7bca2e99b0e8261597915c1bea422b949a3d1ab4f28b57bc9e6721f69e3cb5c396a0443e280adb0757131c904ccc302f02ed03f4a37cf85b371691b8dd8c6faf89cb574fa88e0d1590a9e9ef0d7e0dc096a0049af2bf01f227d653509c2f3e344edd1af6e96fd3ea5052858d5afb8ffba3dc24455e2e84784d3e6d62f00ac39a689a6a1aee4ff05986a8ba37ea0a2cec2f59bde44f62533609da840628b5107a8e496c67a7d6a7e5d37a7b2c15ff2a96821df4f8a0d3316bb7f99562c463a05a0af0acb3138c7b2905bd9d37b54d552082f86255a9a19200322b2cf816d2b1f1e82ea20ed6ef9c3c4fafd41c4f147d28d07acf5f72d07ab1d42ccea59c9207519b545db425463a78cf091c154c8113ea217c78bd9dd4fc1f6195945ea7655b3d18d10c5b7164c8ebfeb155a989c3794b97e87dab89d66645b18a218bc72410bab0855bb72eed69a1661a2d8451d1e9df77cd3d5c1ffa77bd4213a946e4b22f971e0b0bc33183776b8b095a044b27e94cc21f58c6fc221fbf03af3eb6ffb5fdd8effc0954a697cfe453432afa36cb757f202acea396044380df2f32f6de006fd850a984fa5a4eaa33b029945ea705df58e5a09b29e8376e2df4303a5745dc3f1ba2ef36a7b11331110f2cc6a8e6f39912f0ae33bbcc2aa6d82e1ca2f144bd1487e2dde4e7ddd780d031bfde62b0025111852de6a1bccccfd4adc2081923dba1329dc656adb59ae6cead04d2865d0d021635cb66d07f1f3034ce1d0992d422bb7d876d5de490eca70150fae41132366648f18cc0c3f52585db42398383722fb9f7268d5bb6a73cf0fe9815ede89231713b1d820c1af64e2fc47898306c952f187d89adf24c68da8d0f86cdb9e79e32f15df09fb96fe83c13c3d1ec021c2d4a41d6dc4789d04c75e322ede5ea6953209e47fb42295f4a214766df210ccc4c4fa6207d52fd42a9b1dc3fc6b2336a3d396673654fff8dc58a31b03b82feb8e0ec08e4fcf182d7b313fd83ddd6f8ca44e1146c6d4f623c214f78c9ebe47dd91f89243c13b92635fbf6adabc9581812cf8aefa973b846a4a5bca311fc2ba55ce7b07be6b59d1454c94ed0b8424a5bb72f6a40a6ef0f82fd5abc3154bb595b1cb7bf760bf668e6a3eff47c57bc2811f55540bfc720715e506a8a30307b310a241d8d7b7fc9b7d49112ca0f4129a6d3de215230f393bd37058645ac4347d9c0cd6ee7b304ba387458e1e7d30693c2e438f6d4c062ad49ac6e0a2db67c6b3328f5f24ed7d883160e43552bafb5f194d6a0f3dc70f9f18602785a96577add00dab1726ac5ecbe0d95eb10d2df09bf20287598a5636201dc10396f86772fcbf6e6450f1021963e2c8af1e7fd30ecb45d713dd8609a7087a1826383aee873589a578b805362a8c54baff678a93aab8ab2fe8a6b934d20c53646e5d46125283bc3421a5787346697e424ea63b906f6f47f3d252dab229ad87087ffdd1f79a5d01ac13e4e0a3a6aa495304c79dab45bc02e0b90e15911f51203da88c749c02f181c28403ca648f9411983f683d27a1e5c60c7eaf9e0835341aa62be51181a140ed780aa3e8f840491a772ce844bf476ef9d0984e1ee1d21d047a6eef366844dfe38ce04df215c251b7cf0dad767c44786de61bc132730337c8cb6102a180efc71c67b20366c2ba134def3d3612bdd76e3ad8965ee7b80e92c3d9eb090c573dcec407fce09303850b972158be1187590e216f0c1fbfbddc240da52100b916cd237c2bc00635f43aa5e20a22b34adcda2077837341c5238d468ed865cec4b33326c6e01544fdd8f2013dbd2aa5cece3349bd6ec14a46371b1f7e2779ced7f10379a1e022817faa9929729e43a5073e29509c89cbe46618fbe200cb35603a9d5d0ee80027058e03e7197d875103bf5cd5b5dcfcef2bd155403b4942972f95b80904c01d77e09a986cacdaf81787f80c17caf14cdfc4baddebf60982d2f1c5b92eeacede2fe78c722c2545e551aceafcc6bc0859ee52e4c74d76907ed592e044708472946fd8e6e46e9a52e10d769cb6a5613d07677caa7c41147126061e177150a3e9a97d7f88855a00f250db9b2f81f01d99f38e3910cd3b3c6d5d0f53c3e99110162722f011cf89b967c94e83f00f4da98217398bfb83df3bd8a112b9c1b058f70fa89cfaafb49963307ab616ca5402b23f2c737e020fed5d53554b31efcfb9cfe2dd501427b33b0ad0e74dc0e32bc20717daac3802d33dccb20e88fa0b0a013de0e40071c1f1b8272ac3180b35d3aeaa20a43f9830f63f19ffc9c227e55d27e25eb155421efa028c51045084b43ff09eb20a72d5ab27d470d1cdc607df2aa9883cf5f677847140fd75ea2ff46a301afd20f4c6f920ae63529d67eb7a1a6c766b708cd73fb84981e3c23d289adad8414e17e3b19d81df26a7711f9ee8f71ef99da2925102bce6d8522ca8bf0e7fb29de45514984f1d092edd72a3f96738e37fbe54a347482082d012652d45f5a381dcbf5289f3699530ee3d7c4ae24a927642fb6c749e48c059259f7c4f724bfd4d4abf84642dc3b5fe608ef80dae39dfd0038a0b76152d6e35522051e3dbb537d449d30b76b86e669544471cf321fa1b01ef79138c5d8192358e1bd6f8ea54bcc3d372813ffcaa50599e56a27c67de57e3cd278368badcc953f2e7587db98985a47b0dbd72a72e9eb70d469e9748cec43321485b8f7545b05031f69020ddc7dfae8e07ff3d30d698d376a8b4c1f65f2c52145aeb20d24306f630cf4e355a70e81a4d198b81e8e0ff66a13df252188058d2117d87d12bb76c751c6b7685c1ec37c00a6484587fa57f73891e078cb936e30f163f18a975d079a1acdd9d57efae1d537132d233e9d4ccc003554ee191997e28ebc759608e3dde844a008e384b8ed7f7e5cf768192f476a58158c05f827ce295ee6f1e70a5d6fc6214f1d7ff730c2133422de09743d673edcebf6091f83e7f8717cb8ace7b07cf71768f6411bb37ec73f5d9e9c10a1aa82cbcf8c69fea267c9b7387155399c06827713a8c73d5fc24f21fe71c4fedafa3017f30e3f019774f4984bd6ed08a7f057b23da5822e7e1acc411436c68f6966b8ebe8020fc7b3d77b61dc6cc2ffdd01217e8085a23a294f79b5d80e055da57fb1c37f13dbdd7d272612e0bb872056e3fc5f7f29c873752907ad55be0bd41a7668fd79f3511e02fd77ff4d96daa02fc88848c72b3dc9f8b40eccd2ebef600cb3ddeb87eadac9bf100d962f147670058b3807244034f0569c4212800f5cf6aa454f64b9a384d1f29707a768d346d80a2d8eef3423b48086c271078760bc6d8b18e061a07d04b71b5f9c21a25fe244ca2c0b055a41b983858c6fffb07d5cb6cc2f41a85af6222b46142078234de699c66b369ee2bb1099a1d780d0a87b918e4cc722722e4dd392f7b59a0bf7ffc3f4ee793ce83f01d2a6a0eb90b51831a0d40f1a83dc2a3afe190c3b1c57a3360e65c036930a840254f02f6cb1e23879c6fad50eb673d34eff652c06a657546f5d65d5556deee7f74667e6bc887da8fd4a83cba2444a8d2723c006e1f12e7ab124310fb599c72cc8f15cdcc11a1b0613f1c76ca430678decd6cc2034f7ec3ef37020bd2f3054455b5ed0e949ef849aef678f3be95c4d739c25c8c03c67b5fc58b055b0faa0ec990cc6f9e201e396de115dd4da6f420683c5ed7359ed48bc36440a2c7d975650db39538808c291ceb37417cbd6b1a0fac70103d51117ab1eaf235f78d5901b254211ca6bc6544173277cb8a384c1c1125d4789e370a6385f8141cc4cc0d52bbe36e513ca2ddf82d3e6116b44ff5d2616d7815e2eb09402943773d2600be9c256631a713bc9eba122154085f28e8a6fc9e3bb2cdfe5eaaf5fa25344cc5fccaa7e1e633f17eaf63989287502200658a457794b6561e6dfe04a6afbda6618c738c69c36720a1e3efbaba061a26c2fd185995a7fce1bd570cca93e115b553af9475668c9931559ac640d061e06e29b8a8550d8edc0e71ca5c6e7a2a8a35dafe8262202a623ccf8eb0d75260234419b4180f2300d86fea0e20b235e1896499ed880b84bef8ff97813c25c1308071d8595b0f6aeeb1b7962100fe600ccf9e8cd793d63b03027a66a4c6115a9bdbad39ae483996a672dc3ba7fc6eae8e6bc8ff58b0a0c2e7bf8444e35d947d05932d1654c20b68e7e386b4a9363cc4eb39baf734dc4ddcb03b540fa7d5bdee0d9d216ae2b788d442044b507ccda37b4d9f77cdea0fd7ec6475bcfde6ca6a46720aebe616be58d86b5a691d03eb0a249c9b465aad29bd67a262bd49cc17cf9a130fdbae126cd49a98b35b932d15feb8cb475425a6c853f2e69a7905b8a05dd780f024664d31b81c90f80f2f990b1f67e99cda405f855bf78d08cc63f6b802e68c34ce713ded97a353dc3dca00d6dd4b207de4633712f721e6276e68e68fa9e4f0916a0ea507af1625ad94d2b491e4a42da2190d6b1c1a5ac0c2a13ee665d931d51f74babd0b3cac65c0b1ed5a758ae45548d90c0b85dbf4461723b020238e172ac7102fbfb7275aea4a2e439b2a3caf9fdb18bd621ffd06e8dfe9ef6d93192d6d692f8023b000e55f929eeba05976ab206c00780170f247d29e8a6c3a08e16005a428e26fb5752231dc1048a7bfd04303eaf4edbdb47a2005c0e9b41acb041d240e6f16cfc7fb79cd0807097b6b237c599cd307f12e751e690770851643093dacb4c9db4c2053d5d400c308bf9ecd5c92f79342b437edef5124f67b94f5fbc974a427a0ef2d6042ae79b992643c0525650f6574ad97e968f62f8775230d0de97a6481427a5b4e6cd68faed2a1ae65727ebd98665ea6329f32c536f333ca277a83ca417021432f67d362f8baf3e6b029fa8fe27e6e22ee39733b842179ed4c0beb9513058923321772570ecb49f9b56294b9c924d8ccad3c1449abf932d60de8b5d6e5191b7e9fc40e55e16862d3cc93c86cd9ffa57ad71910648f72cd8ba7dc2007061fa2e346382f4f7db7a9a97ecb3c6cdbaf8b49765d1e545d124daba2fb6b829857f340d09a1eeb0fa79e74e7c4e8c4433858f118d664c2334a5da03cf0e3e17e180364300c8ea07cfe3fa712947f4bdc88a72eddd3ca7c97221b4ab9784e914dd19ac441acb6fd273547d4b205e72dc2e96b73cb1295b7f2682175f0675a19ef985252b8f62d100c71b3a92d0b9556ec57081da5f2a81be58897d3413a2cbe318e1b66fc7a134b785f60b1c24352936c1fdcb7dd60fbd23eed2ba015b24bbe9b7b83940945759fb566ee0346fde466691f2c5996ad77ef32e4953ccfcd9132a83b441e856c8056668be110cc34a52d03a977ec24738871d4e3536a1e18af1495cc88c2b6a7ecd5a73f1f20f366f5335b0a76c7648e25a2c253e199d942bfe7d35ab66d5289ecf054a36f5f1d6a808ccbb1f1994220949a4301a3294115459974204317030b485d7523366b3908f46af016ab8fecf0a7c0b2088318ef4bcdfc478b549e33b7044a9232f424f56001e7f54bd1ead6bf28fa7501da8e86c21069f81fa7b9bda01fdc20c6b63cdd7d636af406cf4314a2a9880b6ed8cef48419de52fc1ecb9be9e8086d94066185c592ea1d5b9063184bbd9749abd2fc7db8523e4d803deaa318dcb6e11b278ff7645a594e76a3c1a62b305c9a7d91edf4a38e62d0749c1f6f8e912d0666315c95c4007871148a9b8e8bfd635198441148fee499d4bea664b409df834579a95b0896b7fd38980479d9e1270e76e1515379aa2681feae1ce1460c45e485638de41ca4ec42df4f80a89ecf8856b24fbd62a074b258cca83d845278837973e304452820f047fa25814744ad86907e7b90b19bc6819a358956a2085c8bff5bc6b3f66d9e8aaf1e41f197c8d6f6b75ad6a0549af42b0890f14f44f52b88e04126238b7b5731d61c9884813825e5a32a0545708b80399054f6a1d71c0d85e19573af4cb8c04bb7d0482854a84051f13e634d24c3ea660121c8e74145df474f0b5bea9fd2ab74b8d97dc13e64c8de2fccd538dd3cf05d58c9cc8f828949591c40b34732f2cb530e5b6b9658244671136e81594af65e8dea2da6f2ae317cd60922f59515c67716a40b4bda2f9317b3284fb55dbb97c8552ead21992343ed2d608702e4d0edb2370f9b13cc6464bc085aa36a5d968853c61dc45b3ad66af7d29459d004565fde92e34385a92083566f9ca3ba159fc61c5c1bf160b6ccf002c9225bc987017c49672d15e89631ffa3641d8de1213e73df49dbc18ff95e792638e7654a937ad0d7a1c2787a2e34c9a4c55749255003271989689f5fefe2d471b2a96765d4ceaecfd81dd9da185df8bf11cb04442109b823e354f01c711e49f4a813fb99789eb2c64f47168909bed3be24ddb8fb3ad3239fc192be26954432a7d3ac8cc506611aa8a0f48a1f3a5c452cda9de64c5f3e1f3eadcffa5fafb873f1b341e531e0254e2fe0e19c0aa7480ac0e0881392e4270cfbfb362f558e4af7d9e3d42cce0d0c6c0b0e7d2a64898653d577bb0c3ab8c0640abba6af034c5e8aef22fbe2955cb142deef21f39687429302fe2e2ffe40f45efbf7ce3dbf47c6dd004049c22b6f861b04ab2160956529b3fb0bfff00662fb0b9e980b8dd4a5cbbdab97b5b4a473ae3a1c18afbaeb60ed5a7af73d0551154d917754d55c4636fad7b4151bec486f35431827d23eb8a1ec570a2bf0247feb68935a6442de00839ac2b76187dd454123b713a88e8efa28db0133f51c15378e034bf78209a3b795c3bdc820ef2a67a38cc4aa1a6e6ecee2635c2b7c95bc2782036320a827e78c3389605563dfb33f0be2869bf27b89bd72a9b4af2b52f3d727e407f3cad926f993e8589068fedaaad6eca771c39aaf04039e712ca2fc7684250aefd611afa67b7ce27db1d47504f7f8f141382a2cf5a0ee27ec865b41040410a347ebe61684164b49802aef890c5037da3c17354dc26ddd538e17330b07689af88b873067d9f1fc49a59033878be7f276ac20f579066fd262a44cdff66481c35c0d94d179c5fa9562f37cc2b5135d4f18c79932155ce9d409a2a5aca54fcda5e9d4a5cac1ed52167bbed4cfff980dd47c3b623c244404c4a8115c9e33c15afe5b8cb19c3fbd04778f5b432ae657f486be8ab3df5b59bb3e34324a452359ee66ffb612cdeef5054c3bae08d62f42256aa01eee941474f2d2ba6a65669e4c293f8022baefe8375e114671dea68b2c6c5339a2e0d1213538577e3f7abeb31ce7b13f5ae7336da46bcf89d3b733ba41955ad55ac68fcda227efb90f360dfe5c0e7e8d92e1b0839a10492db9848e06925953ce88092a9af8d8e7c7f56b7a9cb1224f79abaae58028c9b76216e98f7e4c830bc0d005f87fb001cc0844f189188076ec9eca351abd349c15ee5ae54eb7f5e2449984332a88089e467899a30ebd864acf914b9922fdb5191bf993999430460f4fc254a6930fca1263579727725745ca9028aab5c8c33692e7eb42f4404ea6ab83661d8204cf1d0ad68ae1de70e4a2d9cdd50fea953ce2babc0f61350fa3563170debad7e7607d6b72a1ef485a60408fbb50a9733f2f21e9c7d941bbe9eecb5c12a611e395698d5e05abfcf0ba8f63051f9ad21d9325dab33f91033cc21938031dadd49c5eec55a57149194ee3a04a226db9669087ce09cc0550d82369495b68c5970524e3c859894186f6db7157be2a3f8b3fa17aa861f64314afc92b64374ca4fd7e84dfa22b7c5378041f43a0dc0b9a7c3d939bb9405f10986334d33315f2de6f825e8e06256d9f5c48250386b2649b0d12ab8069d22fa8ed0dbc1d645a53173aa88fedfc3330b87634d7ba2d460960130ad411817254006d635d628dfb6bec88f49e384cbb6551b4437a693554cb71a1d6a308eb9c53fce7d316525e459a3745d3b49ed0000a8d11445ab9a7613c446f0a969b98d97576f8af1f13df910e06627d5b1725b37d3352124f052672a6fb03cfed3eb3fec529d81f64cec2d8c5c70800c6c97e2da8cb5e8bab2e047cc14544cabd0d971dadb52096a6a95e3a9d3d408327b152c81b102d5ae06f68414766078dbf6d2b903980f4c442d05950d251296d3dc2333cf600db218c2de9d8cae9519f748a414f77c7c02d19d15ee692154b20d885aa068f4ae4428657fc14dc957e55c29337768d8bb0f0f3f44dc2c76209aa6a6c0e7cf31c96bb99dbe8faa3470d3bf903f7e80a39eb7c119daae65ea116c42f8c0af59048b597db298a7b9f274737683b5e1ad751c7ae5c57cb2ce598a7ecb617feb640232abced902ace9699ab82960afd950b6f7e0c576f767a2d3c4900b8f4d2343df437c89028ae6b6476daf20138879bcfa4b5a872772da802359c71bf77d3ae10423d2273d787845b2603637147829a95149ceccc4028b4307c454c743f816be9f6aba3a8fe2a6fa5bfc02cd488b9c3ff481822036e3878acab5f92b5789fb9b6cf37d5b6c57a00ae40db11a59591b259c142b76f1ea60d0304e5a5925296a9903355b9d74e5168f7df38b0fda4dc4203ca97b315bd9e1dbf7285093537d8f31c60991efd775f128aef6acb18560f484106e8af0c733bd180416a40a99f942a35cc27163b3730680f22eeadb3e53a9950dfd4d42eea1c4e7fec0dec1d0d61c6bbb25606e1446f81bae583788b7bc8a4177133a808d5334ac4a4bc3c2a962d33f9f1eca61f1329e1025269472ba649d6eec5b539b9956128a04504622061fab93f99016f419df8917a919f617974de9d16986d4e42bb43f55dc0b639b544eddda318f13b1f37473b58c78bc3fb17de996d65edfc163d3bd7ba054070f0b15646960784df1233ae53fc16caf216215f429b4acd91939dbbc916f73546387b98148157105a918922f35199c02c24351c34b101d2590ddfcd317e9f77a415bab88491068cddba2634b0fc3e2bcc2ee9915ed8897db895ed2a570056e22cc857f477bd77e1cc03d89c720b1abc8d27ab8b33947f8c9bff00c3428e0765b1b23eac44d22490f38d48eed1ac69021b500cec21ad825c408175d2afb0e80e7e527d32b190e8653c8037910875419933489e3804f28d1f0a19717231ed4595084a87952df1e10e19fffc291abe91fd063d287531cbdcc6ce23182d37ad90a2a4ee5360d02b8b91e07f8c17008e3e0b732d1d2839d496732a76f2d1b6fcd2e03c38e38b287135748b867c3b261365320e6ccfdf171e96f581d63163c9b1670c341169340d1b5e9069a4ce3f9ba1410b6a43c943444e1d769b663e1b402ffecc9dbc908a3492d6bde70420fea1cd888a528b7c905c58e53478a9f98bab4bb5eca60293c097735fb26b92d0e33130f7424860dd0ce3f36a9d9f4658f244433aec9a63e33c4be8bf2fe130593607b8bb43417287923fcbbc4b6407f555294de2dff0b721807837b86190b7e1433981b50758b9e5efab661577f49efc83fb794e193810460b8c132ded83a7076b42e18fb3e533be30b8719b836e59d87a08d029fdae3064b9f529ec5d3de43823b0e3608cfc4f7786260045615b816c8ccac2c6819cc897e6781969d6053c50e8a5afcb21e81e384c68c31daac593660df0114ac21d2715ee5cb099d09c4312f5b3f2fa670653baae30cbb9d4ebe9f5edaebc52c0fe04833f5e9f0774d9a86b5e0f7a991e9fd6c3fd5dbf4ee4e26da06830e4a69ec16c9671549d383fc276d727be798a2aa16564dbc5a0947d042735e3dfe1ef8d525c71cc3999ee5f2652297b6fb0d85360552bd820826564085cafff05aadd4e485bacd8d5174855b7cd43bd5afed79c46b894a9027f5003e88165aa52cfe76f383e89347b53b3cb1ed76cd488a87cd6846d70f50ce74619e8089d5137e0680a81322ec087015126847d8833ec32fef086b5c33f21a8bb2df23833bd8285c8a8be5444e689d06d627ee4ef90b0c00b4d25fd10823298eb776ce1e8f23583b92c01c38fb9e8ef0c6a2824964a82e63d0a1b0432464162b31eba01f4738c85a5cda707f0ce226c4cc63524b1e7c9ae2089a8825a9bc6bf95a731255f0379f1bf166c052b3de3c90c1c19e2ec0c7d04693fe701e3a5e80faef8cec8f39ef72d92d8ac915003023089e4c11fd735f0f54454bec6233f301d6742912eebf59032dbaa48f3a9c6339115ee71ea4f68411d43207bbc717f9f69cfdea29ee7b52d56ec0714d557db34c9f9310477ee47514b2448c259f49d037285affa9ce0c600ca1bed642b6f091d5685a3b3f6f23216b4298273ea4e0bac3e232ecf766c08433722568533417666e08964050679540e5cd17d96581601aacdc13a7530b957c68d221b88c0599e0570b48df17cd655976b3b217b6d6d1a65ac404756c2125b9e33a49a7a3bb6f5d462ecd4d083b4ad5e537ea6aed5393cfcab47e81e3739da5832e8cad3f7c4e87d81410b7fe95b3c344a1c140540711ab44bfa973188f7f47301fe71596da35d188b2e104d7d3acd640a659398dd24f6495b29a00d80478fef31dea480ce6e258f58fbcb8bfbff99791610858b8bb2c9c772f708fc07a156a0d8ab6c28c5b9a09c7001fc01ea1193c187fda790b7cdc8eb926c1a907288b4c28a769cd2cbcbf770dbe0ea8870e94f2a2b9bec22b238a3d545cee4d789fed3d11fb1a09e401321da47cc1be425144fd0e52c201aa886593be3c3d99a5a06fd1f095a445d3957fd746cc9a2a064200aa55f9704f63bfabaf123f331283c4a08b3e63260b3c329f0cf121bf9a6c63d0f7301ee09acc28c9e38fbd1e8a9384c9b223d5a34d09b1ce633b10b4d9b8717f41e81f2d5ce1090b4b30b140366626eff9fedd461a52a3d04734b87574935c5c31b77c174e01af6a89c5f27d945b14af900f2351883c7db467b2561d70d000b8ef916e2c8491041820238745d77756061afb25462cf1e45f7bdfef50ceb9dd87a7d0a1686afdf98f06e1aa1eb60af2797c025cd6639cbe3fd0090c7e7a8e24d204f6ef568e262ee347ae9bfac045be0762c0dafae56157e32301bbc29ef83bc55471c1141ab36b2ad377ff4d4f0965ee550cdf80bcd67c5b284443a58576a8e4a5276a10aaf8823aa5a65cb005b3ec3c155d108eb3a88d4dfd45fd08b73e9ffa57c2da2bb0ede74f32080d3f5a3ff7baac013d6a6e78f01e107edceb6f370411f319c5a8a9a875439cd67f574bfa111686afab577488b89d24028cb29cb85259250c9fb486fd9f917a4c66ccc742c97211535473863081da01d8737c51b110285330885583ccba23abf29856109dcadb1661d35febc7b9e42301a3d800aae0287021ecd61d3abcd81c66b7da835f28ac18d313debb3b3836512d020e384688ef02f1cd878c30fbb6087111911c0685490ab4bbed9e1bea4aabd365402626124f42fe4396c3f11f3823c4d0c7efad01aca8a59662a35c96d3e2e142a6d448c2cee133560411efd328722f0d8afa7f86cc16c8060445f5e04b1ce0d307d7508aadc09359e7f203401fc43371bbbb146c0d8fdca6391424b99d16a7b196a50dc951f5998bdee0b52d652d1e33cfc84233a5ff8b00d0d71c2f2505f74ad712d6261c84c1974c9e3adeefe890b2cc2302dc071c9b64e42d8970e52027df6abfea1077c0142669f61e333da1dcc1b01b37f3bf6eac064d0751121070f2cf8ebc0e3a23a53e0dcf41cbb6454d4fd886c23f2a4231a0836c6304087fd111c333b209471726b113c0af61722f5aba3ccaae8f6de304627c8db6f507e3e140ac4d4e4e411f00b4bf761de1eeae49d733c4efd0d32a7571586cd2b84312978afe7bac17d5e137518c34ae43dd7dc8c5e4743353f9b0eb46018f316ef4f9d62d0cece2487aed7cb0bf37afcb8579ae10aebe26b1a2979191e27107ef8180d5a01cd18766d7dc2c54a3315af54e2453a760b4c884fd30ff429225faf0cee60b416d73463f382902eaa41344490f2aa8709411aa59f80adf9fe7aa954ea5ea16840ecb774de62ff25cdea1608a067b6f3fa3fa00367e5fb492f43d1e9a4a4d19e517ea31c6be5affed70efacc88a0c58ee9a998d8e6360a2892c1c2e44fa5347f1ba298f77ddc033867c5b34ec6c7deb2513d44c7362a05d4daf9c2ad222486bb8c8170e81f60073f224308d4680a3b0b34a0d4e8363fadbf0908773c83016c49c6c460fc026ed8a305e27154d1b63e490eb609fee5d7f83c0029206d4e4969c262589f0d1daa3f8b118f443bd67e3120c57ddab151c9720bf229ab68084a8f87f44915bee3e888cbc4c644e48df516cacabf9ff13ff78b17b0b58878f8480b2cc2cf47448b8403aca165de31a4dd8b2d8e2b7511ee966d91128db07a473fad904d04cd195808f5923be5814aea3d28f297eaabc4ec7ff90752085f16f8de2a9acee6ad6b8bc22434f5462c8587a00d0aa32229dc913ee8cc53be46663521f470eaf1d099b7cba702b1dc693ef4c2b9d797346303ee080956465a6459a63923bd1e42a7bc7b9f99bfe4c37acebd7d8979b108e170a99ef8c635d3421e7680062a285dedd9503c796ed60ba2c541371c2933a433aaeb99094530346c6f8a75a6894a0a15ae3169b630a1989c3fb36250b4f4a6ac3956832e834d7085b1c97cde9bd2e6f5031f76d28103b66dbf3491db875eb45f54a805d7510fec39edbe3583578fd8bccc2a5aaf0aee025b170875f44f500fa6813cc00c0bbb94b2b144d64741e052b68d8286fe046a0d775792917849d18901d9f6cd56b160f1625a607aefbc48a72ec02811da19cf9d033611a36540f2da2cf8364090368b76ff2d30ddbd440cde292038522775374529716501cc5e03aad0ba8f5a30181aa5033e72e52aa9613b6b14906a3e1430d0d7ea3653763155a1913c320899390e1b9de0f87683bf6d49a9eb69bc7b03ffdcd7d943cd89526121fbfd6c000493f451de8fb782cdac95d78d104236215bcabdf79652ca24532209780806090418805754ea45068c2a4626861d020cc07b54ea45068c2a4666e6fe70152e10203ee3bee03137000e736170d215808d0e0c0178c16b4a003004e0851f3aa9171930aa18999999cbc355b82eb8e0336e0f8fb9380e73739c747dac5ac8711a35ea8b0c18558ccc0c8dbdb602f8c8c1e9c1a3851718558ccc0ccd8c997be32a5c16ba2297efe0d37a167cc6cde1315787c35c9693ee0ebf61e34faa1a1cb5a406e770e0e0322c1d39bcc2dcb8b1498bc3ada1eeb8cc2c1d39ee0d0e948983691b23edccb434d4cea031e70abe028d0f156edcf0aa823626da196969a69d412d8d1ad6da701b2a74dce57a55ba289a19ac1456b8d455b8d46d7435ae11ec6ffc70e1a957522d01608666068d1a7e3bae74399fb7fb17ce53272338944f37a1bcca6c3ba68e3914ca79db41d538e7d3495e555ccc46c3cf73a40bdf244d76bb9acb5c569dba1aadce8096468d685dda3b6d472d006a623c06a663be89996ebdaab61ddb31a7c96c34fcbca675f564b9bb727b57ae5d1baf155a68e331db8e4dc7dc8a66a3e1e7575e7be5d3e1dbace6dd3ad9ab193433326f2fc6c1a86ccd75a5705d2a5c978deb5a5d97cd75ddb8aecbae70915230325e66581bd7616ee7a70b0037dd1ad76e0a5e03f52a5c203838aa06e7ee121c3a8e363750b7812ea9a1e36863af7b4dc15335ae0280cb74d76b0a97b90600ddbddc2baf4fb3a73f3bacdadc5801c74d0e1d2c1ab6c6a96a34622e8e5e513fdd9ad255991cda15dae288f646da1cd3eaa096b563c6676674d467783cf55ac3b4028e9b1c3a583b58505dc661ed8db539acd5612dcbda1dd6b2606d0bd65e3b6f896f288eceaa488fba96c435ab94a9e36460e4d31cd0ea68cb8a7687b42c4cdb02b53c7ac038cca92606c7538759bd6ccf5dcb551dd0b2daee889605695b989607b53d70508ee21b543781b36f2f86ba34aa6b04fb935716b43bdab2106d0bd2f2e8412d4ecec94f265a53b03b586881478f6971727c58b7990d3b2f5657db95bdb2bd32dd92a7ee4b6704fb929fe8977c3aca6b8e6d07d531577216361a7ebe84ba50c68558afa86b977453bda2cedd7a83bb7ca511ec4b1d66f26602f77138d0e6b4f511ad0bd2ea4cfb83da172e1b808d06939b501d75207da26ef279e57bcd81d6870bd1eafc7821001b0d30cc497212e96ab76fecbc30c776591ac15eeb302e38ee15cd718343c70adac32d06ec72482765d1d00c40a20448e99c7352d971624c25b3650f4a6707d98652ea93d279512ae7a4ce1e9c92ceebbae6452915d2ad8b5239af8b5217484c5e98cb38bb0f1ec1a633efa0524a29e34587c81e330312eb20dbcc79514cd239a713232da45bd349ec08c645a5e442e5f47975906f3019639a72ca2540e92345244b493995206794ab9b493020df480d8a6bca8b4e39e5947276cc37d3a5a4d74525dcb20497578c314a87984df160b1e4a5846b0b8763b592578c3146e9f09297a4704b4bc2217460898c12ca083be806d68141310809092750120844e316a00fc4a20bca3b132127658c502ef132c286c2081e0541246ef08fad90b32b02bf9d79b61e484b225496a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a39723464646464646464646464646464646464646464646464646464646464646464646464646cc373126e98e0109151e21a19720d70e63ec08a1066a76d189699115c918993483a901cd220d09090a27616429b1ab09a1216997412cd01319e3d32e4e7a5d43c8322ee60b8473c58a32ca0e070f79e56a0afd2ae660d80ac209b197d207105310e7437a4180ca359f0ca3961fa5152f3da49840694185e084035313a494505eac78e921c5044a0b2a041fbd4f38f8e86d6ac247ef194c3e725b7041946840fa826402bea26e3131e1b6e08228d180f405c90472d25061c7b042f507950898022d26d9a8b06358a1fa834ac4a43336f89871c9548065018fb2aea2d920e392a900cb825e323f5c5028118630d805fbe182428970613125f838a788435c90092dc19c22062c5385117d40b38451b720435c6f314079611e7632829c7c9411c43731e8a38c9761a432a2722dc12338387dced9c94e0a514a29a594524a29a5b493b36bf5112ad77ca9169318150f1a928f9157d13fd982aa5b1a826da2c7dcd20f8c53d2c010acf3e2d14b1e601d191ebdd401d64979f49210ac83f2e8250eb08ec9a39782609d93472f01c13a9c472f21619d92472ffdc03a9b47d75a31e78658f28175481ebdb401d6b11ebd748475aa472f69a0d44389072fb55847f388c5147f32a297801a0655a7721f585e8ccfb830fe32e3291a9741e328138d97609cbb46b887f1d335a27a181977528447f558e66d6f8874c6d58aba47f41819ff6944b0852f151de62ea1e96664749a0ff826be745a177c13539dd603be898eea342ef8269e3a6d077c134d9dc603be895ca76dc137d14b9d96856fa20ca9d3b2e09be83caadf3a4d0bbe89b6d3b0e09be8b5d3b0f04d74ed6a447c133dbb9a157c131dbbda157c13fdba9a0ef826d28fb99a166c135d75b52ed826d28eb52e98cb125d238a3970f220143b8d88238dd788624ea9a511955a1a91469dd2156d1869875ae2db4badd9a1a27fa5164cb564b4160395d1a645531110338bc6c3044223223941e3a154452382126554aa1273505d5248be4b559ee8db65a2fbcbab42c209dfa82ea52a28235510f40f651491f00de4785d14179411c74e65248340d39adfcdab9ec15326d049806df99637fef6018c045bd1b79f80d83e70cab215d1f8539698038324da34cc290b4cab08a635ddfd8369cd23b30551c0419f475abd9add4432b304104cfe83419205a645bb1921bee9d96af14d6348f8e622c2805a12e6084cab0b0efa07d37a2c02f50a3a4d2b06b6cc1c4ee1e4a9b50591b1c1290df4d56e18dda057ba6557e6bc49672e7e50c43a953d02b18ec6de52c0a3980409d6b9d86f502d01e3050c086444f102c6cb0a525a48a85a226349afcbf0af19195f61bce86040f0adf927238a6fc7b41730fa6505584a8b6fbfa4949fcbee6ba2a12a44598ab6b44ead53ebd46ab54e9bf47adaa00f6d198a3f6606e705078252142430482ba8fe9996f8e69734ac8cd78c2ae7c5b74be8311b7ac881e0db5b96a2803f49609056d041cda4851a4a0f75156804bb74ab91345027815e0512c12cb0086e4101a1805040282014100ae8db4f45a7a253d1a9e8545474123a099d844e42272178e16b34afc586c4cea016210655487cbbc9a79a974a5dfc1c4a1bfcc1996c989da9fbfa4bde515e73eeaed68ebb1f7c3afdd35cf3d9e55072ead52b855f9a5a3733596d00cdb7ee13a2f9e69a93b6feed6bff76913c5e5b4ff783af914cdde5248dfaa5512791b42d88e6395092671aed4e235dd817a5393f0cfcb66d5eb94e5b8add73014abb2aff5d2e3721f1eb06851a0afca16d5f0ffdc7d3f13ff81548cbcd8652a77594bffcea7ecd69f77594bf9ca77f736df3ea54f3129643b99c9457a7b7b45df9a5bb39dc6c98bff9ac57b74d0712b99b79eaa2dc5eebf1f2c328bde49bd67dd84b4ddb7ae37c2391485d7212d72412a9b4917aeb66daadcf98237df3e9f69e8ce03e1e8911b14f72eb1f7cf29867a82b89d8dfdcfadc82903c8752f7c1df3c73b9d9609fe42c59da7c4a52f76198c76d07abf37bbbf4fbc3c05727e08fd9f1c82ff9c7233f1ef9249f2e7332019743f5cc37ff88d8277576db9cb719aa67fe11b15f3b36e9cb40f5b80999f25b48fd4cc26ddba2fce6f049e368be39146a1cfecddb09f803fee6bded6c1d731de5e9c5b85ee8f35e5ac72653cfea7307aba46e46067e9207e127753325cf81e4d44b24a74e2af9e53fbfddcffea6dd8fe7352fdd4ffee69b66bb0f3ef9e9f5febc7689d8cfba7602eae8952c758c0aa6d3340e8f7c1e097be05acad8d95eb58c3e70ec9fac810d8015423138592f7fec81fb64addde5f25e18e63e5f7fb228984be9bc5507d2f0665e33bf5cdeec92de42bd92ed04d421fdf27ab3cca5acddf7f3d5e5ed2859cd5cbbf0e1a651cb1be6d9c51c72996399038917b828f5ec76945e658e61f4caa4e6d3e5e5d764e60c3bce39bb8f876621e7fce8e595ded9e530ddc6d7b6f1d3c6db780968cefa8f89e0d4bf4929f5e9c11cd3baac3be2c38d9739129487fdfc256fea3fd433eb7caceb93dde7c3b35b029da1f0d1db04dbdbbf52eabbbb1ee8aa68937acc3f9587ddd6111f6ebc7624280f1ef1a13dcc91c0e0b56717090c1ed6e364487b8f0264883611f351a56384ed10280341e51f1c5f01eaf2d1fb610a08eef36fbef20197b75fb519007eec689070d0a57fa9ef1ac6d87db3e32c7cf8379a8b2b3d64799ae72b3dcce021a9b25e5ed0b499e46fd55be8233d9d3a0cfbd86a9b18c4e3a7cfe8a0c621e1903e26f15628417f9290d4ea832053823053610a00dc420f1f1d6a699bd82dd611bd8873adfbfc33875ba2b45bb4c0a2220c72699b18dfe45f4de79cfc5bfdd0fcbb3f9d35ff00f0d39d75aa4faf5a75534dadd5a45552fc6af2e8dda4a5cde83e9275dd9245f0f041392045117ef0d565b69dda3127bb344e7fa99f341f392dd33ccb3453f7f96bb04b0c4d845d6058da85a40b8b1a476ad9723f225cf422235d46422d9d23bd28738a48721911841c18e1a7a34acedbce06e4b38f8b8a4cce8a392f1e310ceb300cd531db90fcd4b1344d730dc3660781ea6af5d33f968f929b2e748df5d1df08fd0fc8671d0ffdcb51db0ee4220d0b1660f1574af5b105bc629c0204c105bce2375df74e8710abb5d61a35c0f1f36f4b4e3e2f8f29fba3f3f0f102eba7cb8026930b64b0f385941753c7e0fdb80283a19677ea2ae6401a8915a0b0ae058ff828735a490799bacf016ff266c239e41f2cd611dd624e72ed56ec3693568205f52adae995d3a4632c7c74d36d92ef9064643a688345c02276be2041dd80306ccefaf1ccd75cfabc1f0f7dcd4b58d62dd8cad285c8a8ca96a1a2d610922a405ffd63a221afb22262d53a4bda0e3d7f5d3bc4bfbcf2ccbf5cbb1d563299ae6081e90499d203bee1cf4cefc3210198352f8f17da267a077510048240acd332c9118d233f2a3154b4c44fc7e477ab71ea47ef239dc3a36d264edd910209dbf0cf1d298698f5598dc3bf6d1f87d886834cb901dbf07ff3a7d3ed211004627d8cde42f5e83bf847d59958cec92396a457d16b6c31d0a7628328cf537e20f41f8bd538d5375804dfc48baa4b4e8e3a29e91ed1bb7610a8087844db44afb107ae5b9107eeeba0a2235a41ac239530e91cc8a5ce0b8d7a1584e458f7b11ed3ba387f3ad639279f9a5bafda855d209716a7f9078d1e1af52abae640fa74bb882439acb6893e6111d37b0c8e05e4861afd051a1a070be2e183003274f008edf24f875cc9e7854062446f31b8af5951e038dac08fd325d638a6ea9365ba2723b8ea999bbcdaeabed1f0f3a6daf108838b9d44db762676a56b9f8f25272e8d63fd93457c746cdbb13478e45f4e639b4100638c31c65f4631878718fb53078b2822494325d5bb8f67ceee23c27acc65d67dfd986b5eabcfcb5578c8c78b7f2c267ab9cc2b968faf27ff309433e7a4fc53cd10c216419fff4cddca5c2ff579a5633bf8fce5d9dd01fe855d7e19d65f2eb3cdf0c2022c58f05707b3402e9600832c471002079698e28537318c6ba152e33851d906c7591afb0aa1c46c4be9bd7a7965d52b685947c6ee2120f615c2e8f0258ca4ee224a8634df399ebd9dc07d9662dc389b63d6fac7e168fea5240dc9bf9a974e9d6403dd5e895ddab6232f7be1d7abcae89ddddc6688b12204267ecad4653b07fb1b998c3db79e5354ae25db3845a6f46c079fd65f9d8d0eeb63da67d3528cc6d94d8f3fb367875c703f189c5a2a574671daaac4b25a75e8aad28b437753caa1d79c9c077b95435f358e8c43c7d138341c3aab718aec00c7f819ce837d0d8737fcfb316538f4863f647008a1738dc3915033ac43b3028e0a0e9d008d63c36f70e837c41c1b1cba0bfce386c3fb5db7922ebf8ee7ee1204b8bd4b0ee0381ca0e2808357bb914a9ce984c20187cb1e020e20c44db7008eba3378e9d2e0a46b009fb746a5a10042bcd670b16843dd0034cc50002135aba741b2b6642d67adc9da93b5286b53d6be585be3dbbba4069fb9964ba9686eb49b58478d1935dc1abc965e644c9fbc636e9dace1b267badd85fb56dce5727c2dcdc9cd699af334276aced49c2f73ca98f3e671c87099756c167b4e31aff015b333d773156e90203ee30ec0632e011ce6ee38e9c670e37702438d451b08a4dee0004d869904689eb9d6294002d16609175dae808b1e55c0c52e2ae1ba0b449bd6a1ebe129403ce109cf278ae139894a38e83f5e3c0107bbd49094a0ffd88887986012c68c10f9f1bf9f97ddb495c62578e00452c800e88a4b3cc188c3e6104964a10507b004800956087999ff78ad0be87002ce723b3140783f152701495d5e22aabf9c24c50842f07a32f78155ae5081e764fa8f57b59bddee23a27ae9b4c26d0793ceba5a373344d3b2dbcd0cc9fcc7fbf180448dbacf0ef0bd4bbbba0bf4aa9d27096e4a971d06754007d2746688e6d56bd70395a02205483c4d1ae1840a02fd008b91975d6984131e6f41e263bdca6e069278da6526f24194214fbb3340f06a3fa106423009450461a89398e244cbd3ee0c27dd830efc30c4720212402db0a009a29921996bae753db3c996202feb7ebc9a611746273633d290cdab4efa0ffe92daf5f878401a32018229429e7667aef02a0661f06188c8cb6eddc2ab9099219ca4ef478716535a9965d8eae28996c74a58c203431efb0c26bc1948789986a580632d5b54918507a6a20a0f7461f94082632d8f821c28c109c6f0b2bb6308af4eab5d5f0571ace53f7fed72d126a280632dcf5afee332259e0f0a0a3ca678f2010f0e418824bcace38c052022a06a6734264984bc520b86803c521843439e766b0fbcda36bb7c8321292dafe7f281e7936a81a779767b30120ca1a569ee73bda00a263c8da360e209208fb1d0c08b20af8a2c4300f23e90440e843cedb29e7858940082249e766980f0aab51be041908785c7cec11f6d621dfeed8798a343059421dee2b107b1efe719193ed869376e7105172a435e76b71f74a88032e46597bd4ab2daede9221100793e9b12bcecf6f015cf8771e0653e0650508f4f05c368c8cbdc87adb0e2022feb9ccc40ff79d3911900ad9a64f1b22eeb813cc060c8ebf1d1a1c5949697b90f8f2552bcac8b39c0c2064924f1b26b8fbc8ab2daed812d2d429e4f8be171f7f85217852f5c49dfcf11826062c8cb6ebde255ae9039362c955ebeec3e23403537e8978d6d1a420821841072dde43ebb2a06cb6a1ae7e59452ca181b87a95849f29ffdee4e418da48172a485480d16a7179c0209469b609a5b4ad20b1ab5a84daf8ae3482507562a9c7309c63107ebb8b6918e750e7bd2b9ce919ebca20323bc7c59f3d2088effe3727828765c2a7b9eb2040aff711716d3950e7429310fa03c31020f47b4c04a142c2879c2500e3c40840e94683f70369eaf74c08aa7cf573a30851256b8b0f26c8507555878b6c203113c44d238995f0e85986d8dfe9ad0ff46e70d2302073338ef1129bb6fb65cc0cdc0a219a8e5fba97f1c46909e5e5d100914a257975f0e9d7059763fecb75cded338f22f872d78c4a743bf5707ee14c4358c974772975f4e38cc3fecafeb72052ca071a45fee00f803fee512681cf89713691ce897ebd0385c3f5be141112f3d3ad619cd2358eadf0b569ebd8fb13cfbf441808945055cdef48c4505ade7e67e42d103237e3a8d370e53a9f2819f5ed3393bbce9383a477a354871a509308cf0c00a80f0669115536400042b5c1891c09bddd704c7ffc91cd8b20d6da0c7245ccc33152a5dbe3e43b10325fe935c0c206c082184b06574f9b1e381df0ea180cfb24810fe1d32f09f910fa27a8e29d5c48e4ddcabd87535bd628790ca14430f39092112956b3ed87ab9721f2cd6e279b7fb70799d0018dd87cb8bfee3c16da71570830c408624d105749080039ccc08612d0f9db53cec6cafa4d7485271f1ce1c80bd1f8fca8ebb87d7b0d51db5e81863e49b76d8d04e80632a236812c685f2f9ca962e49949cf80870a467af2fc856208f50a50b7daa57dcc95e4d8c6fda6528c06dff59eb19eb70076a70e3c56a1ad6a042e72120261102290121dcf85abe698f37029ce5c1083e025ce52b4044ff6130f266035bd370cb15a0249fa2e921ba3c5319c111ffe9d0b8eb0ad096672a26f8e23fd5374de71c7172516f57d5740ee74b38afd9bd1c6e41b84bd336ed9773d709850047bb1921d42fff5458e69cfd68375a3fcdbaaf3ff3e8dafd7c5efb2ce0f39993dc5667d629f9d47620b976ddde1c489d11f8d44b4f9330799dd7b618b28ec2d67f9ac7195c78adcbfc82f2585b4869763ff859841bf38d74cd3aa91ba2ca6309e0f8ca10591ef352dcaa6757f37a85e87ce654f38ffa052496ee0c9695ea6b9fe69ad3aaddcd99757220a2f35947019dcf3ceb8a64ce83fd75518a39954eedfda6cbeab5de4ff32bebf8ab675a777599f36704fe0781341673b8568bb3a4c6c4a85cf3c9a28fcc17eb21f310248a36d1210f713cf4409a2846a7dde743761f6be52a0d1241a28f1e8b624efbf0d140acd54a28da4455033df7dd87fd0bdc8fd7310beb4087ad183aa7c709ec882011acc23a977f97b7be5bb007b63c9eeb673b6c7d5f3fbb1c76badb81c7f87623d777f7fdfcf002c79eec3eae0224e6c096179d50c5c72718808829d10044dc80a7f8e81facf21088e7221c7182953142d00422aa78cec59ce8ac9813dd47cc892e8bae2b2ae4986d448912258a95af505cd14473eceb970d9f8bef2d48f79857e8c5d7d6f2350ae1abdcf21f7dc9031445e08275308f1dfd19e61b919f39768b1e8a2ba27c3bad57474d6a9a363588c990be1f258f79bc0cc5153ef8ebd68f3aacb5cb817af51c48d5619016d2a44d062006a05ebb2f3addc1d8ca18583e63e666a6576e34fc3c410d40312011485f17ca8e3b180453276a8d1be08682e2111d4a37c04dcf5c7a6b9aa66914ca4b9f515e761f112bab3c47b809b93e63f6392bb3cbe696cedd7781e748e58990962fbe969899f9da76a8531bb097fdb3c3f552f6ddb2e5e5366f109e891dfff4befc58e344a17b42e13f29a5ec01c63df88f9939f2bd4564eb77e8e1618c6f8f4738e8fc4de975ca2dc8ecb018bad5ddfa7879e447e6c1c397dec5db925dba0d9c83e41660a1858b8c0578028bfc7e828857fcdd6153f6e512c6be441190c032d2864c7f32b8a1a07e18c3f698622ef5315c5d8bd1dddd31768cb1bbfb78e44561e390315a2927892f28add05891b2a2ecb4eec9fbf3952ea2f88192673d5f29e2f239707ca58b2749defec935ffe22bc7c0f1152fbafceaf98a17440f04245f9f1425ca57128651c77cdb48ce9d8322751fed3e48da6ca8af6d5b900837d7f835e72876dbd9e8953bdae5f692fce4cdc2b6eea3b506338bccb4d0e2944516335860512314b158b9b5b78d583887b03ba2c9039a40e0852b7e04e00a175cf08123000108400052881021422014042000010860e21ca6e218c00006304088a8ca109408d8084460dbe16d8894a08fc036448a12d8e174518c90e889e0e8a0478e0e5a68810556d709b0acd0b1c38a9b1b1c37a016c622db06ba63b1d290e621c4c1a2c00d229b15886cd850a1c6a8088b4515a8a90200295471afd3e82410098615b17410a241c58c1a54cccc70980ca66a22040546698e7507d51598982b2f2fa95303c19603ba632bcbd722365ae1be0e92122425480a932a2f07fbf6691b228549e33079d2380d7d8814a15ef1cb1ba7e060674df076935ea1b6ce0127e54937440a935ef1f3d7d21029418dd35282864811ea1c6e269dd34252944869d22bfe4f7292d29e43a43c91222445899420d236444a9094235a488a925ef10369bbcdd05f37f938444a50afba49e304350e3f165931c75da5e2b88e31c621062ca9cc10e208d2afe2a49cd3078fca7fd129312c36cc5ed861e768d8ee4c49ea96828b55b8cfc6218e672a0a8eb53a82e38e0af7798c824bb1431d70dcf160e180c371032e46c1d5d880e35e69a50cbb68694a929445e6a414c3b24cd3583b75c56caddcb83885db61ad616c2c65bbfb46ce6e24e6380e6adc4e7fe50cbb348d6a53464d6b482aed008a308e78f204097311145cfb10077b7277c71dd62bfe796c0738c6abe2131cfdcf9f53bdea6a7ad54560d111685cd52ba803ca1c7dc3ec3862645f61dea036578c31461f2cb0a165588aa379975292a053b170c4183f6b4dab1a966952332f988c8c9814a762669918991966a661d5a9060d93d7b0ccccec920606a5eeae481d848112550accac4266035b598e31c6688359d8bae192053e525c8c296ec8076be537ad23478c91a563db616716694608eba3d38f3af4cac7085250c1c6ca06b6c210329d50a917ee980b518cb1a36c39bdc6ec19cc16dfb0cf8e1d430d09e5086a77773733737bfcfe1a90c4a74b0d20921825d2a0327777b74bd92d39bee11ab014394687ddb3fb62d73b087ae87c3f2e6a672ec2a132e340ff66777777430dd438e3a4133690033e7f86b0578dcdc933a32841ae55b073660cfbeee85254e8842b358448b8540a25619c73ce39e79c334266292177df9c5e634aaaa4521a1a6337a57f734e0cc2863ae6e418539152ae578c33a59cd74ea7734e9f9d9c702a71f947bd2d335f2804865d981093af4983a0f4422450879441401dd22914623a14822ff6eb46e98452cae22476c1abfb28a558f761fedc4be6d8865d5e8ec9d9ab4e32a55d179fa851ca6e4e0947d944cd2886b14bd62ada7013424d34b1921b76456d62f4ba289c32b625cd6ddb615226a594918b31b294524e4c66180d4cc565d681348fe8449c414d4a09ce6a755535bb6d16f260e1586117e552a6694af5ea04c523aa697aa50407bd09dc01073dd52b76d88483b6ab914529a594d1ed84cc1c779a6d326b131c8c24be5693418a632aa5949226062f286161f14914432f28e194c4264f7844264cb16124c94e4a29a5942c9b95300e061c744a8249657c6927d5f28d4b70d0a3904a4a09046b6fea4f281377e24a24df64a4381b23032b849cb596c9a8321929eca2e156e3aab763575e8f9d0b38e830bec0a62083859ab270c33a1d7e467629a5e4287164ecfe218bc0e7e9e731c6782979fa999923c6239f27339491e5d2afeb7a7a5decf333bba60d500650077bbcf009d4217d4e8632803ae494377339b32c5ef162396d3b980e4fe5f4cbbf397dc60b8bee327a7401073d3ae1a07f92339da4ec20aaa652adbdbc64ed5266322e988eaa148de1b12f999959ca0fdb7658029f8a1d93a12c709287ea70bf1411959489334dc3d02109382dc3bec2492facb2dd48258e4d0d4b2569a4b3b6e1873a239f7e2d113dc637ecfdddf30dc3508bc4d2d77fbbff81d0abf079dbb98193542cd54fbfca49532f325fabdd2ce9f495b37de55753ea67667c8dafa89389e34aa46d3b35641910c217200b769433369c1de5a472f2880d2f9e240921f6ed34dc5f5fe935bf1d9b89e17a6eef5675d645723c77b00855e1bb2bc2336720a6a25f8467fe0cfcec7fbe25f4f84c20138e7b155b10bbc884abd33217b17fedb05bb57df6734e21fdad3dfd9ed2b90b8347afbc618c2ce070c49f8f33b8ecfa1ad55c5ab02c99152d2ac10d41c8c2b1aa5604dc4c11caf593e7e9778e89493e7747745004dca9c87c224c003d4f7faa8322e0b86dceaec7c7ebf23cfd35cfd70ed3354dd2943192480d39cb2c33f7e921845cf3cc973f4faf1ba20d3b843ce08a6fd87f7ee600ecd1e918a06e92add60c84b7bfe368f3ab97afb06ddf6ffefd2a2749f20d7b7661d0f674edb56d88d4b621b06f7c6df6edaff56ef02bc9f6fd4ab6ef077f4648161ef9ddcd086987ff753723e483dd67bf2d11fbdcab867d25ecee3eecf9e76b246255935e9f7c2c63ffd267e4a16c1b48804088c00359804199b8228a31a200946508472eb822055e8f4f1df29cb4fbc8304ae039813d8cf0d85985c67a159bd48e4c388630888e537a11166da237f650764744f5b29d025cf439c038458bc0074010c2f3c18c5002af7801172ebc1e9f79a50b124a7aa4e0024ce2c8104bf07c280f4478ed83e33584abca31a787ad84a18222e93d3d3ed17dba28074d78d27d1a093008a267c7105e8fcfb5014f764eda7dae0d78b17302dd868ab114c09427803ced967c60711123280843b46080032a47786104196c814850b10328618811c5d015af5e5ba638c982d9ecb2154640d1ca584f3c1f54965e428b1fb278bc032954dc8ee2030f803cede6f8c2abf504475250e469b7460aaf5a9b5da8a4075b84362e4bb668916c76d90645404290a7dd992ebc5ab2d9ed265cbe08f2b45bb303af725570c14190c966b7472546932c5ee0f9c02ca86030c0f07c805ed6f53014da1649e0d2f2b45ba2e2555415217c3194b2d965296a3025c8d32e13618a575f64b0c42002086249120223e098228b4210c4f4a18b2164a1500441d0e20438a65c5486a0040cac4a12a02421a3c204133d68465088a855b0a0e0488d175e155766108597f94f8d179ee63f1ef6fdbcec6184077b788a2bbe10f27c260aa0c03dec61042b732d0a195c1103cf471e1de165533891822b3c9f5902202fe39eb8a8c42c1785450c19a219003000000173154020281410894583e160928579a40f14800d7992485e52349347034990a3380ee218460820c01060802188d0d08c5401964c002d4c17d2bb544f46cfd03da53d32f584ec598a1eebde56f8ed270749132f6648a8d29035bd16c66bec1147e0c93273e147107524f6d3d0b0c9b15c6881a4e304db1c302b24f009461ea8c1c9f493b0e3239a34fefbda471c7ce1e1815323a75b582867485f2491f4edebfec75a5857579b4ed0890cbdeb78d1736ab9b119a7df402ad7ebde8ff00bf68850ac95620d33ff05b41c9a59a16c158b3631448dbe25540419e63a3f13562885e5ff9420846dd191a43ce6a762bbe984ce0ae51f849fcebceb20db59c8424a89bd8258bb89a56f76b888327dee8722cfadced625e9407c2801a5ea01f654d44daf3f96e18b93a0aa6595d4485705d32349433b30e896171863142baeb4b70badf10f5522602c005c4ffd920c24d0e3684bf10747ee9e520cd6bd432a156b88599c0cf9f5079ccc33f26d027ec4004a421e7b4088db5fb44e5add768cf3fba0487a297ca1a2ba16b66c97ee82163a651ffe0d88323d79fee10a5456a184b4c0b8610bf862c84c35d5712002b743cf08e57da4a0deda209a23ccc625b1cf7575bcf06cad98bb3f83c27f2e5f0136f4a63ff21b10e57af346478a04f114e78b9c2218d12226a5d6fa0badb1b14bec5c4f611cb32e6c992aa4e5f4fcd13ab9dc9db4bbe51ae7f74195f5d093871702324b5d3e240613bb488eda377d18a970e18c401f5d2f070b10e45e96db99f1fe7da00dd24b85146071f7439aa02ec9a53dbc4c7fd9602c8634e6039403e4df7c3895722146a3882c435e99944796cd368e647e28d0eb0bff4a96fdbd5e681d7e745ca47bb3dce68cfb77a0caf4e4f5c33e0147bae5ab2660b2ccaabff9790265506504a217cbe31a270aa54f062c0e704785dfb5b78047450cdb62b6cb1c8267a7e1ac63c79208db38b52947a7b0453d931d3b4412fb5f10d1c735a72ffd4dc685fc363da953a447eed332c2c25a7094d1f2603a54eba6454f0270eb32df83d5adf239a8b8417a405d536da93e1f1b74b3c8c23f1f3e88ff938a64f563728987e27e8a9eeb40821854aaaef73007577e99818555fab8810f96e18539b45440ae5e83f9b848d1383c80fd873fd6ea9a3a1b5a6bf7ca02a9650bb8441afbb63ee912f83afadc3b73378d5e1042d046fd9904d707f1e2086c3a382c3d7c254074513f7c851b585c2c6e8cc415cc906c737bfcebe6d99e778e436bfa966df6660378225087b452bac477c0a2795d94654962113016d032e9553fd54a99e915a3ebd3cffcd14435b212c668194565ee579f92248583d018731dfd0f4654543e8dfeb4676afea6830087c4218e657323037401d604689d347e6ba742e226a961a2977cfb2829b155e48e26d36c2797bf9923711479b7854f0e04fc9a0c28898e4ece4b837fd42ee98c23346dc21062e5f3d20b785f0140a85afac2222fc801d4a7cdebae5031c2c8e8c42c2be342699e68c39e287cc1516d475c361a0061368010fc957a2a92fb43a7f562463fbeff7ed104aee38b1a8dc21e3f224b52b162eb46c0bc309632a01b30c76b58b0192cbac8e661d8307b2245e6ba6c362b81369ae670c9400c1db60a4982e6f999e5157305b217299b9b31c98ecc2bffa0529fc9f3e9527bdfe5ad71f244180bfd184cb36adee11e55c174cd8ee8bbed3631585288e0647996f6a8d3f36e5e72facd144e0ca6258e0d63eea40667ad316afaf0e772211bbe9eea361e7bbb3dd726c8be3a9326efb7d2ba8db6eae433703c2c30418534633b9a9c0eb185048dcab8b6c24a781683140180ec2bd7721d6974b2e798a2c48921b593843cd7c52fbbd0516eebabc27c98fd13666cbfaeada7b3dc4ead0fbf52d1a79bb4ed2c0fe9a71326210817369b5192dcfb9480d9b382df7a687ebff1b2cb84e56a88c7e859d47131a09f96ee043ce2061135078ccf93a55e2488b1c2b5fbd380e52ce73e9760069373d5d8c3d2ae43b6405a27d5bdb83a948cbfa43bb084a16f74b14375c54e63afc1e7f1a8914e8438f09c27ff0c9fdb9c74559904474ce32e94755e9365b98009511e9bc5692b5254965c1d17a4575988d38f05d10ae0d5fc345202d6bd6b894eb6c1e113034e74e9e0e886408c6a1443046d982b971a2812c0de06a6b62f332d3b89d1f315a96a59b0892f208015b7985e86c70f7764a538d18780f797ff4103742ab7b29c5bce93e219fdcbf7f7cfe4b9823b68c672fca403bafa4f220baaf52f09d759687fa7584cbd2bcd4a046919f4ccb2a8fa2f8f46f5162eb3283a296920f1bf5ca6d42f87c861dd743d23449b94e2ef2214d938e9196eff1191aed0f2f44c50fd116b22b60e00606237afe3386d00a6d20b948752608cdb5df80a29b1dc992165e3581552ea87f2965dd5c49f2fef03a1b2ba179d6c869ea51e0d92221c7f560a755c92b1e18ece3bab7d747c882b69a90a5a1a4d81d1fa8eb0174f03abbabd2a60fe342871c242152e4e3a1d399440f15b3d86a2361f4c58c122ee3924f1adeb01734e64ae6248e74d3c2871d82df39eac707020b99213616b38c990fc7ba0bff7af97edbabf4ca5582e378b0844fe2788fd3b6691e924b3fe3cd4af4600d4a4debd4d604e34136fabedfc122d3c2333de2585379699b5d40bd3aec08830ab46a07c34044f2e01012589524115651d04323073cd5fa06cb9428a51906c606a8c8d720d8f623e00d7c09498da21fb3795534b14139f6b832ff249608f681a096bf08d6775177a04172f7d13dfe9cc4fa799a91a12209497daabd63c2b1a627bf1050ceec0a4d78722ffd3894b03c20f140b50670766f944ae50a7dc90f6078db8375180fd119d0f4e0c6598a5e87d8591ede265592ab5ed233bfd8815028b60f673d0164a717646876a1d412e6819bda2d5b2e897f6e1b748068ddba65075d1faddd1fc2ef3590fb9299fc36efaf7ed03610647fef0c5be0532c8dc7988d53db5bba3f3b54cc72a70abfe0876f37386aa518d109ecb51a7a725ac3b36daeea8f925011a38b7ece60af38c41d177f35568a914590d6887e7e6d1d2181c518065f43ae44cac314405fedc771201c3cd2aa1f75ce8ff01000673ee7c0daa65915b62471e1e8700db4abd51120cae99f03ac4450a87f999b6ff61f68feddc6694b11adc80beec14e5e78e610986020e0d28b0bd6f8466d23bd3d93d7d01fd1a042e11fa82428784f7277515c12fbffa22ff773df968f6f13646dbaef3a7513fdbcf245048a5ec1af3c1f51fbf5b4d5a7d40b1e7b060d3c046723e9f67eb7be4686030d9c0eeb5addf65d626ad26044a25b738fbaa90913248ca308b7605918ea159a35bd1b6a451744f51da7c0cdb1cb754677b00026beba99ca72d1e2a9036317c4f321b48f061a997c8e9b413309c7430487cd8fd7858c6115596bb1e34e1bdad7dbf7364f5e5e7e4d58b67e014404abf7ebe211a5f1890fe0f5dc08295e1e4018e974a92b30c11ec0076db9d26a240c74806682cfc8aab35657ee4971c3b2c87fda34839792a1a3eb55656c781afee68434376fcc38dafea3af2d3ddbe1b455f04b77dc609b7a9ec4c67989306f47557fcf5410e02c2be31e26529fa9092ae3fa88718b19121cd695f9dafb3d7146179379439c6bdb659d8791c6020522810f12c5416384ac658f561a06e8d6f998662f17f4b28c9a9c8344ce0b2444e263abf41589ef1609258289cdb27cc1a743a85510e8be01b90643c9e9c68b71f0a02b694145784a05e89457b1cb4b1a60177db6d136dded40a5274bd9897bedfbe22dc736b16a586df010b2663ca5ef84199b5c99d5e732b753a3e5faadd8abfc1798a496e6694e9404f7a571d83f6a5e6245e6e75784ae9e2253aa3ea6f008d669aa9a1618443fe13cc9a7fc663f652a03817978b52064ce46316711002c88cfd0202006b10f3f6b4f71921a1edfeca1aeab81bc98c8aeeb9cf67bcada1e310f4616fa2df4add63e8d85a8268fe68049ed585ac5b6af39a3204e3f4a108e8ece61eeb5b5b2d98df46a34e823bb97b39f601a850362b61cb602fc80a9ceb2ab919665316de2550ef67eabdd4b374f043c2fa6a4ae16a3891f7ba1545070ba276c20282a75cb7b048cde52c30466d84a847f013b778cb8f11d59eafceb25e1d8dcf9cdf5be5b7eb29ec38836b3b7ad45c6940d408347fd02e44f2f37ca806596519d774fde23d73081855d344192dc0d4b69705ed3c33869720b0d9172d1eead465413019d8ab9e3490139124bbf91e2922fdac82923244d6fe470c3057c1f96b8bc847c0fee1f67a11d875e16c50a635602c721416d184b0310defa5292d2417d3f035e886d2a5d9c748dc862a0afda5e46e12ef0aed29ab12c2abc52b1fa537df578b86b52aaf999285ae6b1117d0919738ebec81cfdbdb3461f4c47688fe921d5a4627a5b760636003b17274b531fa42cb71aeb1ea5630c42b8932b8510974dc28eac633512c21bfab5314e30f1b70d1e8cbbbe079302add1eed65a4b2030e62bf0dec24ed191bdafc68778dbe80267e002ec1a42546ad4e8806674e312e4f9fd4d170d1975f5615db12c76d47cef6c7639741b7f476765ba84494070504bd3b437be21bf516cffa52a2addb2a24cae1b7fadf70f3d74acb4d95478e671bba57593583927003ca6013175a1e30a25f128296666fb7215906298986ea60a794d904ad964834be3b7503eb21bea27e3df4ed1ab29d120e1ba490a51b32fc83edd4d55d543b303a93cd3077748b0ad0ff7ce0f923ba64103dfbe621a5189cf0a24189519f622c62bfc859af545b002e488dc6f75e4512c635a3a9f736ff15e889468840d1212c2417583769ffb856962d73163802baa681fe441d7ed205a205e1c962277a886c2aac7ee489637a6e24b77b28ac30186d42e3d5795564cb194e14300fbba7f889874ecda9531a7bad2c4e49a350250f73ba58c965b7ecc65a0078bae20056343ab3166b4519e5e0cda6ffeaeb5e25782c2baea4dedd44a1db6f4d65910d39b250d1f3e594ba040da47c9270bf1b6b0d891b411cceb48b2a4640bd5e341b83e3877ffac1875dc2f3bc6333e0d56e64f320ade7591bc2d45e4335f128a1a8040bd674f41e7e62523a2720bc24d615e3e8485d496287885f8a2004c792cd12a19915bc55a2f62d5927c51144520ed83d105c9fb2f5196a6dd50bf7f44646dad2d0bf7d8fdedee0491e6546a6e4edb41da5aea049898fc27d649a099638ded242d7e8c5c639e706cbee3428c6127176fa2a99fb8c1644afbba8169502252c40940eb29a433f8b1c23f3652b45e9e622edf0368d1fa6ae9da44550c6a2eb8e4269300a5dd92762588a54a4e6ebc620b1d535cbf304a61a2608b33fa767a5e4ee3cb064594d6b3f2d44614403a140b61f22c05c60222fb0cd1e33bac13749767a5be6d5e381985400d2b6fd1eae2727b827c669929edfba0179c9a02c87c8adf80a3c3ed6d594f03109b329a4ac8b210904bd75ec077a8d2cbcc61931490a57f33d9616d3a65f41157596858c15cd58f40ff607d142b2a84c8441ada57049b62b289459c56203292ceda2741f0810f308d5f350e0c12ae52f70e9202d5c12643b1e92b14d21366fdba8767bea171f5bbec296f060a2faa6113628abe1ee07bf5666dc7df46d2eb4244e48d0faeb810577dff6e67a5736ffe1635aeb2225821e2c162fa97f6ec27a3556337e8461b55ce431b33cb143fe1a2dc6201fe1b723ec3d22e78cf5fa244a3b4e6eb3d1a3c5c17e9e73f7d05466e3d4edfa68ed48e9f66275fbdfab429afd3d15c58e4a7d3bc9d82ef305e9b227132dc94a639b71ae8c6c32c8b57897a0c706e2a50bc6242d1d9d8191c0b0b9288ef92e8c83c3841c76da99e14951c1baf4a9523a197de202d20646977651a710c7b902deb19d49fa1134fe157ca1ac4b3b04cc5202a6879c091ef987f5919df7e480af466d04866647e66c8ae99ac765f775c88f2816407ff4c8387f4600016f43ea3f1be53bc2b349977460c862fa0b6d0550f077364a60cb9f3c810f76f163362ecd0ec6887f09f1d14faa86065383760ad95f8099860431592ad4d34913bf4ea27e02584cb9b57972cc82aecd45aa4ca2bc1f40cc4b62263dc888d9299a985fb6fe42a9b45d582a48d2ca48d13e4396f0efec37968245b90348f1cc4c80b32a574d66bf21be6a8b3ef829f98198f1a6465415886fa05fb56188305b199757d7bed7f009707346b6c35053cac9bfcc677bf9968aa06fc94f64877444532e0efd443c2357c610de2990490b3438c556251cf83e2d651eb368fd61b63827ccb67d05f3f4894ccbbe1665ac5fec0e179476809583cc43aadef18a7bbb630e7c23a985222e77600ad54af83790aca42750f80c1cff067502db0496875796800fb4203ef3359a03948dd931e42550846b05b1a7b8a6c9e1aadebde5b45bb5c92a06187f692d739a065f61bd71793946ad32bd7174c98202ea7876404e369d7fac85d881c62c2375cdc2c637f484ac4ea8b341137e05ed01e8880c339354fdc82f7e87e2fcb80587dee3e79854460f1568674d6cee225ff598b76d93d6872ad7c65a6f955b44f24a2475cdc495b85916fcb1c9a0e5d683af49beab7f5c278bb5459750c1a0857e83157272fb16282f65c1f45547f811e1beb61d0c5e86eacf29b2de59b3eb44eb70e9790f65f29c2a1be890cfa026cf595b9e73449f9219ea680f92c2f3c5b42209df68741c27b0a67266ee9220240037ae45d3436b5324f4c414295fab598ac5ba35ef98c8fcfea3e40bf591ef5679556b330a3e500178a0f1559dcca9dca8a023bf251681b42a5306b676996bad07bd7a840f2979e6de5efa5cab0ad8ebabf47a35c69c6f931ea83430e23426b9b81efee074b443aaca3a279ff6ce0f8ea40e6d91053487f7501448a18ff287021f3877e5c220b8b13df0e1d3e56928648f22184af163c4d111aeb7897d429fe921a1806bd930c35645a262a2bc773d94c6dfa45464dd9aaf2f1ab686f2c4b5c5afb1fa25aa85dcc8659d327a140d2ca1babb3d744e45c3cb463cceaf48965c7771552fa42eed09905ec854a933c96c4e464406018cff2291f3e6d68246f9330b166dd8bdbc0c366b9efcd698dcb73b5fcef754c115443cb223d06291a0fa8d44205d234050325c31cd94095c018392541d0cbac3c8b83e91d7b964a0f09b59485f260bec1b85c6384a923af4b8d2749c404d9e35416b7df8cd5883e91de5cb8442e734b58d5a177ed8dbf71cff179b3bb109f6a17ebe0734c98d144db15ff4a5407260ca26afe95d7a63c13be099b2630ead8a928745b425b71894f25407eee51dbbbeff2b6da80f643515f72c6264548fe8c528bc4c0deacc5a2bffcd51a1ed00c4b6d2d44651fd6bdac8cf77ed747cc3c82f36331ef733cb09f87ad22c15691b0a063d7a4cc86f4351191263ec16c5fbe122baaed47940efb45a7674ddc00c8f9100c37822158daab77af24edac03c7b44947b3516c4d4750455834b16568b1c096893fe68e24cbd249851925887481044cbd4c418cfa2497721880236defb8791ce759102bdaa3eace4002948ae842f8cc4efb06e6023a2c1540e1e94d49240d34bf2817642209472f848a2720525a30dfdb745e8933279ada141e22176ac7230da9bde360312baca62ab15d92ecb07fce14eb7cc243a139253e6415e86c2d5fd4a7fc22d5a6f41ce12250f6ffa43509b5d3a04771f16244f856eadf26d3464f64a7b3587212050b99511c7419d2c873d04b4a9feda1e4264d2b8350a4ead215bf91fcf8f0b85b07d0e1a34958b38e242f9e381fe999e584520f6b3522fbc273778fc3ddf994c4be8b845c9a5fd39905323f06edb7b307ad0171c22974ac79c3eab1eab227fe30bd00d3105656fcdda865f150142f90540907d65813cf08612bff9a1e93aaf8984a275d648afdd9254f2f2bc9e7d7d4a9402019118f28c32191ba9f21b44ce3b3c12729d069adf88eb4886123a71f3aa478e911c02172e8d30a2fa601c2ed02cfc19c911a58a2dd78393fc71253663d93d0c1a1c995c7882ace05735407baa5a8f4a12f547586c826b95eb274988462a791701f5b020bc0c0d2248d034f7c6ddd823eec4a026895295c1024178f2987b9dcd1cbfe91cd8924fee462c3349a0a772b805356dce30b02de9cce804833ce603a720f59b823195200142600274115b0549e05f74443f2b125422471669b42b6eb064a4d6c4f167a32623789fc3e5951680197475eb43be6788c075f6b1ca4ab43ce62b7414f247839ca093baa889b00c4614682ff24db5052f3d5ee6f194f9467edc32966a5351f0e10ffaab230af2ccf047d17ab34b6dfb81e3f3acb224ae7ceb3b63df4bd586a0043fb20d9c11b9d6ca084acb877a65784aae71357022695c65302be5da4bfbb81b21d81596ed79a57be74b5e4831490a20b6da2cf38dc0e2d13832f59f5a49ccfc1fac643877644029976deca69e6dd27b63591373d25f159c47ab27ce1958c8274dc696ced1f68953a9a9b0aeae217c70bd1731f2ceb41e2d825b858618d90e2e89bfaf4330c578fef003544c87f9ef8dc009b245a2e4030110dadf5c079f7e992def0402556061a58c128d96e042d0e87c993da560103645d26daa75e1a99cc6769f47c0d3a7fe48e2181d9c70aa9086adc8e7b8b67a1c48aa31a80db1f064838d93217691156b82297f12dd743bf378d99b4c8b8fa4f83d41f94c2119375f8f7f456b4c1abbc9ec0db9d889f63e3d9ac708e2a514e132c5e482a275614516d7a290413fedc74ba8e14ee36b67ebad38b18ca940216c8684a593ddd229f5c8d39b041a4296fe40993f9052865a66bfd3c6e26f54e97864985fcb3ffe0fbfc9a5a3a3513f4051f705d512c5e95ae551fd3cd4d283049529a2d5454e835c053ed4b5e226a3de655c20e2ea90c2f446133ce3e9ba19b3b9774da9b484170fda7397fc791a8d9e799afd09094698bbe9c090c0e516dc2c1010f00d8befd155ecbd774417ae1979fb9b1c228c39c531674a10c8a727bfa33558e135ae3f7c730749a620b5bfec5b9682f59b4cc4f5627f4b17c7424daeedde98f688260508af49d19bb97e8dafd46333f758623c5bbff4be121a7bbf0c50bd7266730a59c458878789e8380edc00e357e79bed31418c2004f0cdc5fadb41d745a86e89f6a680e026e090f94588693bc8af2783f2179ae44ecde3a3348222875c1b0162659cb484ae6745b9f0c9983a5bc1f03bada53e9d6eb5cb3e8210887eb33a846a1ecdc1cda3104b7b937b23fcd9697e33fc7f4f44c32709aeda400ee3dcc1a0b7c1ab393e62839b3fcc32d91d6c039e73c6d38dcf10991b4a55193f1fa69bf5cc1c255cb166408710f04ffcf228011453c12a9730142be085f01fed751bf7ba9959078b55e1904b4eb5a82302d4853ea416ed13729a6aafc81002b07eb8ff2ab224087641b7435ad16998b4868132a4e527282da505214b7f18f5f94ffc44d92c54e55681ace276364c47e07bb7896106953f4859c8f3f7a06afc7a77611addd280452aacc8ddb6cae647c8965f017edde527545562f5a2a14a8906960b5123798c466d973dde8e9ccef313ea0e29e1f8d90ed90017b3f41635026664739f7aa111e85f71f57b0893fd5b53ff06e0b02940c2ea24468130ec96536ba00124bcb03f793c81142618d8714a0d45381d48351806eee66fa7f5439906e4a22b4b949342ce33c021ea0bf4f50e24320c0f332665aed552a5d231cf8dfe58d3cd2f0b8bfdcb1d6e68239fc7a38c1e18e69b64942454cee124f79721e0f239dce4b6e974bc0f18f312fb0fe1cb6231b438e93459f5d37afdc63ef7d799283a8a8d0afe090432fc4f56e1ff77e93a483b83bb9908a2a02e800e7ca2ae92bed28fe041987cb5b628ff8016c38321b09559bcd11bcd8c3cfb01c419d8e2a4ff012fed5e3346fec627255737105fcebc31be40cdc0c6d87a5c2e119da95a414d19e55d087c46d38950f1071f91bba5ec2f301ab603f699b3f7e5994a62b55feccf20e47b3de9830dfdc5963a398c835cbdacd29ff9056f1cbea8afd908087dc83861b173e40232ae54f4e91b8e917139ae6f238f869ff47d510cd288879035ad8b6d071f0a0084083ce6c277e61b7ec043a2be4d02c9d64a69af64e362c57e9cf99735fdef82ab13f73993eb51ee274f4aeaa71add604019fa5854086a0b8559b0f7f571c0bd4bfd7d17e83215655f064f992d297ba4f33b5180fdc4ea0a4f3f22f7f889c60acaf5aeb5a59307c4004f9c3b1cc210bf619377b0838aa32aff619dceb16834919c01ed4f12ba10eaa11ef5ccd4c4fcf4dd5b5ed2f14ee4f48821471535bf0b100750aac2f6fa1a923cbb1d2072ba3874c2ca6dc2b9ac13a8d3c8354c41ffdd2eb658584c3bddb39b391aa31d25e2dde24172326d86ab2500fff8701bce0eb719b18f55100eacdde3dabd6be6a29e9e881aa1021c268a7dc7179a8066f84db34d4fb3a68c1f1915871d7cce3fe2be9e5529111fb0bc411c45e309f9c985ad807b4ad9de7bfd86b0660be7561ed8e92fa6f7fa136945430573481f792ec0c497703eae671815ca523a72f0ed6c0202dfbeb8db4b1cb24410389208a879eb0b097404b93938ecd8e2eb045d4963340bdf2192a902f4b77ebad98476b9bf9da5788827b4c2873f9bbcc1e36292fbb2c32ed9ad01f8eef32f1b9ddae623d0ab61e0d296cde5f01261ee7804cac0a35c179d7a0a323e4226834a1b0887376c77f0efd78e32b6a9084f34c7e527df1d62f432158c248ec6e6252005bff2c3b824ae9ec24a78f42eddab878b4651c50ca6eed5ceb9ea3e622e2c224f16c3dac79ec7567a60f63559c4291402f9dd54eaed68cd6d5112a2c0d717d6c11d0f4969d85645a2d2d9b4ee219bec7184124a394ab5d3615a80a278c7d2b84d198e8ec1a991fc9a90a9bf73970f8c9aa4d33a9d7cd04bb1216785a22c75cd592ab6c851ecae743fb24774b73a3b69ab84a3b91e42674171961f7721cc1b7b231259f1ac1664eb45ca1901fac0c505c0e12ce1049c3f0d8a0a8616384366b2ff2aa84432398440fff17a6013379386eb9395c4ecb75cee9b2e27620d1827bf2f573cf46ab98884417e65ad382fb659dc03dfed6f7962c597c8ddadb0e23b246566473b619cf6968b70ee82373cccbd7298333b8e109ddda9457f23ce46d5a6c5a6130d042e13de467326e75b5b81bdd5426c0ba73c43f73ca38a6dd5c3e6b528d5ee01fccda08b0a6e75e86fafc20f20d9c0f01efea767e15af7ba1f38e0eb84f087b1a886d58170d6221927bc00315ef95324ec574e754d626df44674d3304f4411823ba4af9c1bdec24577e6c6a7c603a7ee24e368d7550d26d38bfb90cc5230e056d3a21718aad7283b0015f16733e813526c55370f3603f633664d9254056c199992c83ab1d7f29c620c7a64e632c4ab9846c9b83f990800f66f1ba04e13165b7b944aa8877182f9ecf934536da5ca61bd818a8397cea7758811d6dd4ab274c2c2210a3b08d64a32873c082ecda3ae82c6ba147321a2e8056b21eccfc7511bcca8e4ef1b8603a5b0a1653f4c47c4a0ee999aa537d417195e414e0a4018aca321c141efc7cf4c3f85985338b48de3a759efa52c1a7fe38ed850ca3b791e39a8af32c9ea2e5111f267894186620f2023e63ff08468b46aa17c713fe07f5ef367ad744187f702c01142ff59c3209186807ce3c7e21abc489b0f8f3ed335089f7c2f0f72a9974aa93b591326507aad61c0c61969713cef0a5082200059365dbc9f020cf6327ff0240cb31c14f530dddc82d65abc5df875505f0eef8dd17b024d9297e1ebf3b9310a8b23c86344a11241dfec1da8076372c2442f3714cf198a427eb11352704415cad99f02f352c060a26b08b44b99fffe8def18385f3cedf3299545182f7f42d11e4ade339e76ad8350e61b6874de35ce81f2654f5e671a64561d4a9e7c296ec9d438531b99f4838d4656ec4393d49f0a3b31a24513882c7ad9def71b03dc438b1cb0ad5f9aa3123591212c55500cc85e78a0003c95d573e001c9662b9b8d18681575e3c736405f3eb788938a19c4c6cef569560a26be1fa2e4279011ee25963441a43ae0d0b7b8924ab4457fe45a743c6ae7d49fc06fdf5135ac0a6d9dd5797efc4bcd788c6b3a7d292a55413ce34cad7a990f594370b20591fd10f1e87cbc5d808b1db14c5f4fa5b035f6d5194a94687c3b21d9302b34483020f7453f201404e5135ce28a1fd82cf29d24b40a72a5a782bad814901532def034bacd7f97948a6243bb1727ea829790b8c751da2f7c80db76d105a8fd5f5057467ee33b27179078d6531848a211128eb01f462926668c2463524e6be7c1aec5cd05c5391c68b69de9a36e59f96839b1a3937512d6e16ba0b1d6c73a3050ad99ee8cabacd852aae937970aae624c387d4aa78f781d9b36288015d3bca9c0448f69f9af586fd66de013e3df2bf45253e3ea6fb08d10156e178f12278641c7c285cbb6286d4c10b20705fd6f5a3f11a5b94a3b5b403873aca381add236a16a94b9ff0d8b5b446ad226ff0c540394b6b69e64f9a359b2cff13353c2563b13c252097461e7bacf35be6b26a7c7a454a4b316e04e628d8803f82b21421310339bc8bbbbeafd1d625cee2cbf7b38f88dc6ee1109a197554a05076b173437aa8cf8ee4ab473699996e07236ffd9ca604a490c82a244e751f1010aaeab2a0cb1aa2c7879981147fa846097a7c3d16b9258cc070013912600d58fc8b07882ccd59cf5ed32919bcc240470c34d8b6938452a34dfc193ee81c44fdbb3e7ca1a101c18ebc12852b7b9741ae440d46abe99cea4f1d15f09a0ab19dbe54110fe481ccc00764c0ec40675c0fdfc057dba8c2db509d55ce518e136c42b7fd50f7236ee7be7587827143e084b61c2800bcdf04a08ca86758c0dc5a898f7bc80868e07c405322e77c764094781624a505b90a6aa91e897543c100ced8791b6bb13a4c21c10a0f96be94ebc34d220da14e47237a7f44c02bd69a5b63850fb8bed09589e22d5471594a0b3d7248a5558fb9b3233af52d78ca3d81b61e56e982c1f2f403c76db8d152ecc2e02647bf5a51a7afe25b93a181b94010892a0e2382a9d75e4e2e80383b0047b97677bf5368388b9ac2303a66924d7c1e9bb7b0ccbc819acda77a01e622fdc9cf508e6c098347ca10186d18b8daca162c88d1a63b0be094f54ae4e3d87f7dd90e456a0829e18182c2bc3490c32c5a92f90a1526914541bac6c964db9a90c68024625f4e2fcf086a11457d3e4b49a88dac0545ef1144ab71f512bc232a326f9f2f766856138051c1e87c32078e871dafc7a0f4b65bd1eb204e0aa8b5851a0502ccf30715782f1c734b65ceedf3d46afcc0f73d58263cf85f76a7ee5b083d8325e1aa249f4e8e19f0e2180af9c61dac15ebcd1f5026e47134f93af4d607b83383ffc43ea81051fb8a5f08635e68c438975c625ace557a7c37d3285799990b81615cab4f16be81824594ae3c7ab22e631cf236d6f584182a43e26491e0ffcd96ca75b3924e2c225067d2080d861191bdc7ca901a3992d3d33d74dd2729dcac28c3f4ba5a173878fb484d540b100e0eb1abef0430df852ef68f9b3f5fa86b6eaf4c240ea0cbaf2cfd6a52842a3ae63f36cec1e7bc4306ffe4ea1c5675b19b134678518292bd6a4fb4180cb7cee77e6ce3d3ba55af65c69fc4e9e7904021324296d974a08d7416393139c479b6aa64bc0d012ffed5db95ab3d60327efff65320ddcc7ecad01c81c08db84ecc7244f3f279c1880cfd32813fe2dffce52195cec08774fcfd183b18f6d347c105ff7c80f97350cd894e2766a4af07d0238ea867ae4dc00d7ea9edaaf311a1b4f54bd0d36417e4f9a9cb85f8316eb300283184c1f9d8c7f6a1f2765f612b6f6d5d2d85311819882b289d42b2f513b7501f9b72e96d008019ac12943d71f3b49aac980256c0fa897b5af8e3f3440117024540a36c0b2233a8c7a838645ec62976d88518c15a51e0e54cc38d5a0bc8197ceb72004beb220a83c294372f39948fb0a20e18dd888dd5bf5b84c315a6523ff0c12cab299bb3cef83106dd67332b45c912a6780d0c0ea1351e018098a2a987a744d4c6370d40f42459d86765476c07fc1897d727e1a4d1b986f59584c6c10eea240f5ab763d5b79c4e12301e16c61c76bc9e5a01a177752c2d55dcfdfe5f737858a86b0c75bbe0aa2014d91ee3424201a7db2006116b7ab4cb3f1c0b5e81154864c0222738850a7604794393f69769dc7d30df07c9babc6608faccda4c618c9ac472ad7c00594fbd8e3e72b6685ca234d6c91db6da31cc44a891c089c1506ad8d0a815b488635259859b452f5c70f4789007d9020dcad22f58e3c61e4783f38da1b0bb5bbd52e55e020837c2ac7ed0cfc48e1d6e71ce7b8bc639345da1b166816015cb19a7ac3e76e9bc2902d6085e96295a838418de933590492f636248b4bf1a02386def01a096048b8f19e3ed1485554d2655277e49c5ea061b2eb4051ebd9b6f0670e3309a3a2b9218c5bdaa75befa4ab9bc498beafbf98a41704fe96e62cc7bbd8b0156ce0acc81173e36a3e561ca8e76328592cb81c111ed69dcd57e830462b6de37ddd4c71c7004086f684f448bc8df0feaa0ea83d90fb5dcc3b417c7471c3523aec0de7d654a5c01e8911834a385c53a2c0efe0511afb6e81848003ef9bd78a9bc30223afbbb699fbdc49555ab2902220f51a6e59e65306d2c3b36ff39294e9ff52bde937bbc0c995ee3dd4993fdaaf3ed1f34546a03f370afafc195d57b0660244366563e0820209d5caa5835f417d670a85a17e02d9dbf60c148690a4392291d5145bc2a4b13cf1a7a36581790546a078a534c7b02a0ebf614c2934d66156e05d1144fb46fc5ac35ce57ff1bd021088992e694099ac827b8dc716bdd4c479b06ac088d68f752ca55507e15891a5256b4bea6795c423582983cfebc51449401e0c8512cf9f380c1572f672249cf828ccd5b4a7248011d46ab568d2027a0383fbc9b702b6bb87065bc817f04234d712f024ece91630619dfe54c42bb8a3f7c5cefdc21932bf5f98d18e90f7befab52dead4429313a00b81132af7003aa9d17ce61706e05ee69ad46be6982ff8a35f182089b735e5fd8180d5086b267840c7139a046ee0f497bf83bdc858046a0c1df8c3bcf41144d7a7431006b8a2dd7c36d8d173b51f0906284d42192a7d37f7d22ff8c51dce68af591929c3fbc30645da3838e90df05117c8aa75183ee1c3a52df42327515a78c8ea02055f85b7ebeed907dce57cd6611012d7bcbfe0e37e3bf925ddc4e53d0b8464e7117ae9492b8ba298ce0b1868003c6e1fa277358f7f9822c2c8cb60393ec12911f12fe68e8f530b6fda679c4247e8f189993c6d792441b0133e487e0790f7ee841ecb1bda59b228051d25213881b12bd1438c8e5a76811f18a18d03f09aa728141381ca74bd495e57ba934ea193b200c4bb5d7c775de9cba52acb773b0a2607688d76a09e75d9f1e476584ee95e55a8e3c4eef6eb6861cc6213427eed06c6c20d3e263f58097340b3f8ccb4b57b788e9bd127b2f96aeda1af8c6c67c19c717647ffe22ac56877fc5d7f20ea7cc7f9f5eb143905eb43914f2661331041bdc23b13b81daed78b574f9d6f4fd0bf927c26c01ae0f6ed0baf7e34936b0df09d3c8f4056a2f2ab86ae4ce52afe1b5ef80e09ad3572d3cb10f52cfd49aebe90bae3c2113deba714140a785d65be9d1be7c1989003e59e5cefbd026920788cb580109ea3a2ea7116936c51a117d83fdc0e702dcdd5df0ecdb586dcb7ef70c3a4520a394e2d6713f7837cd891aece79ea97a710ac58097a96484f09bebf63540cf6f6a7cd437422cc8b4e4b5beeed0aad26121395760119378c3148f14946ca35d34ba0aa6fe0363e9f27cec582782a3414ada834e32265e9aa77ae8ffa02f09c2af31ac62f0243f882227f490e70257e97ff8f118e31a87785f81c5b8bae4efaa9dbe1c8bf29f9e6975aeaa35089b1d94571536aa1cec3d7969aa13093e7a322586ee8b8265757923b74eac9cec780c1c55044275d39e3e87eede93f490af88d2b179496dc48bf012eb2e0c991b9db81c1d7d20a06385aee70c698d36f3dafe2ef556284200aca68aa0aaa005b9e27687279c8738d16aa19ad3d392624b2011de059eb71b7d013d259f118bdb15de610041f04a68db9fbd76fc5671341ded16a618915dc871fc07af1000d3039fecd4cc048a4aa41268a60887e9d184b708481bf646ba9751429429246e408039092a1496c45b09c91a52268d15cace08143041f61f0331dd363d04368255bc2b8ee635a95ac98db9896566c8564ccb712275dcc92b1468158e79f06dcb08a471f903528a3ecf5240873f68671b2f3985e3043762cd36e88bb02b031c611f679aa85ad05aa12624737035b25ff15912dff998a07c48d8687def1af0c11f00c98601ec60c4009e448d187a71eb62f5588dbf09f2c4ecbd92da0a959d7ed515ef3124f8f7e790e4e1bba592d90cbb6fd5e08759f05fa9aa503df1cb9b67e469b57f65f4c18432ec1e55981cb3583dec10072313d070256ef24b361ee0bb5b8be5c48e20050cb3d34a23314c87fa81885887a18e059ea920efd7abc836232436f9ad5088cb5b5c28d681a1679a6758613f260ad62ebfb008b61b9dc032d270ef47dad26dea8b2bcab0edbbcfa3e03539c55ee20bfffb3621ec1eb3099158199466c50b438187a693051365ee296e3077bdc231e52c08683bb57830b0142b72d9dc6a3a45a5af434f54a1a21f69160a7a9829320eceb1bb285d8a7e922ae08e60b6873a710ffc0e23b4a94ced12f71914cec21812981c6b80959cc60ed404644de18e2e0644fe8f573fbacf219efb09c368d691d68f9178933b009e30906ab7bc1da163c2911c1466e0417bf3fde4c4f76acb8822c4bf8d33ecf4fa6afcd16aa97996f641a15b926ada03bb56984a23083be752ea9f419f1affbd7060e3c24ce9e1c62349294444be1aff9039ec62088b29922eb73c45002bc6a1c752d2ba79040e002445236b9d84fc76eb6520599485f2e2ffc8f3f5deb28a47740ec1c207295ad800f476a5245037909b4c840c9782e526738971f7b5c1b0bda442d020ff12be86f537680f404e1bf505efcf8bbd13bad0b621b15069dfe7dfcf03fed1783bf40a1004672b1d1f65c6c4a8da698ac3baeca7840290f0350b426a3353ee232a36e3f6e46dd0adf8d1c22afec8a7254b3655ce1df1d95cd06a6ba34ea11a756913c2cf34be4a8fd8b4e5fd6722ec21a72bb0f98f16c181780d0b0d243e274254e47ea413872d23f57e1a3207a8750c6e36949439e2b8b614ae9ef9190d4be0c78968bd1b0ed1a9dc3e849ef1b208474b558468deaa3d2a24369d0c508bcb56286767d0809b7aee6dce61ea1941ee2c41840c1b5f1101198a06379a2cf4645fdd984f476519b3c4c28ce132bedf5c9155511aa324d436ef96d50a1d8094bec50bca2f39afaa722d21f89e1f473f52606e80fa8acd06140a2e88d125234013a73d83c4535919c62f561f803e7a0a560c36d0c7fc4a884ac0cea5c764c7764787615c7af15a55e461fa3a8a2e8c1a2ddb5004ff64ff18736f22eaba8015d484257927096df8d3fb0bd70b4d818f30fc92fc422bcf3dfff24668d2a089a64d054a29c5dcc795e9025688430912e79be78aae18839d70c1f3983dea6285140fa25f06b4cd6282e6bcdf1194c38ea78ecf5732ee61765cc43da3b04d08fe38c0c931e14c13fa741f9d758969c4996761c656422b4c54f108b634552bae8810f029d1ea841ea98ab268dde1a94ede48eab9a5a45b213b5c8c920060dee675361262ea1d742728d83dfba6728344f0e785adaab31c14c6b68ea55319c539cae0e5d007c4909d2c87d406481a4dfed2b103d576783ef782b0f24121792cc107654e42bed61252f13541b4ea4ef44c406911ae718eb537ce75c8fd8eeb54ec51a34e04feb1299dd12f47042d53dab55b4fae89f974ebd903baacd78d1b3918f7f6fde934d8c64fd9f418f378d11d63a6054a0d725eba7ce86ee6b01c82ab63eb9743a4e1de2d25fe035741f4e124849f13851c069b2aa3309006f85bf751065d43fe8a41a20bfda2fa4d55f4885d6913a7217fe84c310563150092b09b59c06153d7987fa404e89de7c043c062670eb0539c600a2d4a186e76d16a1639945c49620c4c4215b1f0984ab9afbc9b0b49ad25b80dc4f1d036106022e823e023db7724455791c6ecb89dc8c823e70dd36ba2d3f58125e346cab54b414c1dfa4e06f0e24dc3e5b406ced312619ff341547e820d4c4044c0d223e0c22b43189f7c72e8a9be93cb80c2e42b9c5fac33504d68e8fd100dc59968302512ea2535a1363c1e65df9c36bda2895afbd97f372bae26776942976312f14183c1a6747704fcbc800a93e282a311c9a7452f8db3d9e0ce88c046b8ad50553d29e4ef8633b711ac4f69f24fb7b98ee37e822a9d1119c33914b61f1fb1842b755b77d31b3465051e803976cbdd2e5435cd51822fb53f89e8b6d7289fcf9f721a663d4b78146b0557039238f0013057aac82d20902c9f1b27508853754074cd2e0b0a63528bdddb9012d29aabf1c9f68e32abe2ee5c7a89163ab5eb7050a23824739d0de2472f8538bab89c0c68502fdae470e629342393569383afb864f3efa8ca22a821dcb487d146936e61e80b7fb2e1869b9cd54ab7add25e12d64e5220f65cfef49d27e2e44f8910593f32fe943afeca48854e57afc6f4b6f37da8c5d984b099eed4cf2d2bbb0728b739c60c7c00bccdd240f3265cfb8485fb9615ed611fab2ba074833e2ed5b5c1784b5037cf061326deb9f2b4ed444597142f5d645de5819c15a8c9dcc9e6d6ab0290c115191c7e39bef68287aaaf127712b1b8273171c6353a1bb700a0e219810fd6941b72384a73ef71fe7ff1f1e914efb032e2fdb395a45115cc6f170227d5782557e09eaeee88b1b8d6b07a5b1f97ab6d630fafe4adcd3fb5c7630b93a48efb099396d818574ffbdd01a6866bc92778af5fca4a1fd2950ef14a2878efea245be10881fb2a0cb516ce438e1f011adc4e97476791d8f0617ed9c6d68f669fec1a842d67ac0fed0ed21c1ac305350f175b12711ce0b7c402c74e00c721a8b5f71271a468d0169132c92542952209977169d12ac7ffa7a56e1d1558ca4268ac9b4d5e5d7d893496ef6a750106a1c67576660b739f06d127833013e6660e739d0e908e0180740fcca8aeb192eb4ecf4a806bd60b25a2c96cd29d7ecc5830613231f79330f2f1f7dae456ca4140d1ae9c9367782df88fdb91b1cb6488bb49493e80b11b6a463d2788d0bd480bdbdbca3681623b094039f0f35bfdb581c3a07e4642d5aec683f5393f6ed35b57eece2d61506cb668c6664ac3b8bae08d14b1d8be2eea82f75d81845394820bbc4d8bf9453ee29184496711c5521048d5f6cfe462bc280debdcc5174c5115cca0e0cbb79b0bc81c984fcc7e24e2b953b90abf089a40d235e3362c66054ba9c054f192f0de1f8584d9a2fabb1f9e4729329be341d9b7925c3296e82ca6b487f2ced3f9de336f99ddd6ab3bc29dfe6ea7d7e4493d955b1b19bf2a8e423f56cb98d2bf297fdcbf391c32acc1cac3c6c9625e12336d9e143d74b111ac6f204ae6ac42c83f0a2688536bb13a996956262d4185aceb833593b97bec41578542895ec61e6e0c8968239c303bfcfba73e960ebf72313dbbd914c50f8672faf85454e632e31d1cc574ed0b8d90b0bc0f78b1d2730b768a5e067783914815755398a9cdcaa13ebc3117aba8cbbb0d8783f8e28845d23cfb172c9c7be6348823083e75c542c0208cc5e636015b622f063de724b9d8373bc1604382c9406c4148e60790e512f1c62800e20a34a28970ad1beb11b03bfda1f9363c0fdc18ba78852d5daa0170ae06a15d8edb3335779a980e5e21960e4d0b4edac9e4f1d33dbde03cf501a6c40959eaa2c7bcec186c5ed5cd2db384acbe618bcb03613995faeb72f865d909409efc4c0d1b73505a1e53555e9ef47794c36c559a61406a81ef99af83a9c66bd8a6057a5c8509a240a13d0a2a7ce50732cc9d1920a832b8d3bd5cf18714fbce9788f8d6e00ad181a6689b2d6868693a754fd0faf1a3b1f111cd0703cd33521b79024dad0088d192cdf5bb2190f9776f5e9d94f7f1ada478d7c23227e68e81f5a90cdf7251a05ea249e78e920fbe6cf008fedcdaba3fd375146891c67b9cb64643700570c0a2e539f7a16bcb8800c00ca5422ef96842961af18bc11f0b0c5659c862e72a9ae7af42306ac3a90d5a2a342f9ccec97d591c6fe1546c841f783bc2fba9b91655db93228a968677231a29774105d112226b02c325a33a593913424e8858880f3eae8bb135ae41d192dfa374a57133d98f7d147d2def30ec75b6e461e1c2b186eb824c11e7677cd49059b910c9cd855ec4656d7253b8bba10424b387e540796534223a2d10bacb72f0dea9d40f450a35fb4e80702f14786fa26077dc47b6ef0bae293f167b45a7387b96511ca25319a4542c93323bbcc958fa7d2887071df3b33cccddb79b2bb7ada50bd0e2e5ee0451bcd353c6e2b9b7358808b5e593f091519427a4b7c3979ca507e73ed7159482fb383b4da3de3e1ac45cfe4c1b31a23d2255731d9045ff23ae24a3150c9a939c60172fd0ccabd5acadfa9e6de53cee2159bef9dbe8b41d4aef1464e6ebd52348963578b13ccddac1a1ae48c6612a525756fb026edb89837ee70f4906179779507aee5e7d518c44e7cfb80c8f8e23047217efc146791244eb1836c2b0f51f4720c0e795d20f09c26906792f1af1a286581aba0fddcbadd4121a43e3d0e7e58890dd07f22faeca7775d444cef39de006781b9e350a1934a50c4f5b8ce30983136a725cc7dfe29cdc5fa8e12ec339aa538c0bcd4793a17b4d41cc0e96f437eee91c16700af1de0070fcfe680a470183e10db2d93dfb884e99694bd755cd9d67c750dd7e8ee7a6c1116afaa7d16f23627508f7db7d6212817af8874585c288ebec51bdd2cbad48280892ba1b29777516a6e0151986807a4ea2a2102e1f2062a1ae274d662408cf05290bd6942401111fba0e33ba507d0e8ed5bfff625ca8d87cefc0e6f94f9a9335cf7b0d364924479d22b27629d62cb0f2c1ad06c2f0e3a711d3b0d483fcbafc1514bc550847f721a3298ff5e777673587a9e392a024e5e2220ecf450a0084e98f9149a5803a880ea0484c290de5104a9e622246d9e7b40501f6d566cf627b64d11f6ebd938656a2dc49827af4caec7e7bab76d76c6f847f0d9807b44cd3147de0c50afa7ac7e433ac502318082ceea4f3e6530688ae4b4013d6687ecd5be93db137236c01e38ad3610cd35b401f38a9b2cb340bfeb33f41fb0886b0371dc0d84166d200e767189eac4c418daee11a40fae4807b86d20ffc30c8f23d3adad181eab4f6970cbfe6d807f7f5f447f20297f111712128870030941c4ff9c36ab411754a0cc775726d96635426a27633542ca955531ab81f484e884ffffcd5cb31ad1a5f3a0addeb6398756a35864e911768074adb11ab72c720f19a4921fa55a8dfc11790bb193d8f14fbd20f538abc1b7421ad30d263301a0573caf17029ae7f1cf9b154d207b070319ae06555a70bbd4851b97b48f8e5cf7ce24c488ba212e58a8afc036370d4d28e715a8b4eb2bc87907757cd30ec073f81550804796537440700dae8d1b131958a12b30a231cd1463be02fe93d1450016f0e75d84fe774feef608163cf7e0b0a04f2413f285ccd96dd719e461b3acda6e3c0a61c1e4e6bac9ffb460415c6a67d6ce8561013fafac0e906441029ad7111044e34ebb650584e3c502fae615105d0ec30274a6cd5178484046c202a27b801f493a0bb624823779432c884f7016e038a35830c7e66620130b8c1cdd851967b44d9a04ffe55f065fb82c7c697e1cf02fb10d945802e0fc68229e6e3982864622e8ed165b6dd10be6da7fe2d0d03619c158c2cb89689d2c032781abc9bda42db13fda0896cc52411145801ec7df8bcf3c6c6092b0a4882bb48b18b1bd17111d6ed4c750fa7101b4e224bca0c4a94f868a38a34ebe5ce3f892669650e1e861c07de4ecb0d53d21581185c54e30e29e8f1d3e8085254ef1ff0b1977a948e07c8515712af92d18770d7e1ddeb4917fdb1eda6d2759e2362c6264cd293928aa7b9bae468b98d7a63bef08211608b32cd7c2e947b32e600b02b898f3a2ed6031af7d9610e487f01642ca4c4a1ceb63b4a402fd372a90774851a8e211824348300111ffc321507df42ef144a91f3a049e104c889030c122fc142250953ee1c1add95894421111c10454321160cb3ff927675233545b84a8f04e0ab7224096175c1120445fdff6d7db75aebd189930423869bf242b8c6045e2e472d6c85c54095ac608da3b2c3227b546f8c335429b05ae0b68539231e11a61e86aa07c009b60014a0bb7e8a3f225cdd5460825976d2b2cb060e5b427687d9c6396ac7f813dd8fea02702162b3b1b9ebffa9e90d7c15e796e88f047c9e06021c02dcf3a024a77fcd74bef13fd97bdcb96779fbd32748b97df7bb04c08faed5fbdf6866bebda33dcd5977ddbbee1aeeef7c765751f6fdf1f5cd5ff5e3819e9a9cef7c6757559f7ef05b7eacd6eed1d6ea1f471e52ceba421e2e6091d823c69b3d2b0054512e777a97fc726a5778d4daa7f8949a257dcf55c68a4f45db1a4f5eed8a4f4b6a51e57bd4b0c12fd7b4c12bd0fa5ef4223adff8e25a51766f75cf52fb149f4ea7cff85464aef189deb1e8feb35cd1dd24d7db2d130e33a91bb4379a398d632e7a740541123d794361d7e86ae0868e4f07482d487760cac1af27623b842d2895a5f981837c9ab8d8f27693a514249e5640dd383be25bb708baa54c948cd0267ef1e2dca71aa3d21cfbfc6da8ef421b3a086274bc28c507b73f2e3365e9654804b6a734f062e69edb435ad9f7347f53ca5044f869cc3f8510504e22c0174c50e0ecd726d35700f194b53ee8bba8cd2332a0f23c8d49e11972243efd8f2814e94932b838fa28b7c7c81829157b21f610c1dda97fe42eac37c4a2c788fa9e05a194af7a82e30c56cdc0392aecfbbea8f80171921bbdf310edc72f04fadbc13ab604ee1cbefa74916453404894e91284f771a5e66b23d3e11ba4ddd81034d84babd0377d80c113c52aeb8b47e070e36c420383d47bbb9e1d924055ed982cb421c16f0cd552fbac69a2583c61e2f26eb7c2b40d6591d2c10bb18e028b4504d63594434c61bce1b5c7974b1ada6e92d81508b36590d3b54c194546c7068930d0e4168d8af74014a19c4b096371110cef604c295435d46d90a0b73f61cfc913c611c4342f31c4f559dfbab9e542f247565b744ba86d4215e6ce7c73b1f038b4ac3b2950ef59516c926a7ce2ff2fedf48b5df674f59cddbd1c4b1a1c301b24086a256b1f62d28cc2701ba33eb3c434f57a338d2bcb38aa15a160ef0ce337136beaeae8af0a5de3bc7ce8b7a3a62f5f1fdc517a6ff8df07522acd8d98261ee341e291691f009905dec6c65d4cb1586962197062ba6f2c368ecee2e948bd50f2e0dec5a4b7a7c755e5c081f17f2953e7c648d689f5b23a5a31e9da4c6f56091252b037917606567bfda98734b920a31bdf23003d1bdc101221ad2426437533efbf81ac9ff23250ab4c93672566ed0f45e8da7ebc054a8e5e75cc981a85020d3363a7cf41b7b19167551ddb2608730c7333e36706460ba20c08e12d204c9870e35ed25fbdc1ac995f49204602b6e0d94190e208c842c9fe0ea7695ba234213c834b36af9352a263de5d1da50b4f70542fa52c133c052038732df3a0a3ab3f0195ea866ecbf98de028103a1e4bb4b998c0c7cf635d158d897ef49446179f1274281d7d7e0919ec156d78b4c5400d14ba2707ac4be14cd2210ff93a85132bc44de20c51b037303012c3ab72d0bf31a9b9174351fa76ad4fa9946be06590ace9ec99ec894ca9ecf96cd9a900ede908d6fe2972cf513137a97e350d17aad149eb0d80cc74c5b458a4ced47147d3a58f822e27e61c92c01a009d4ade87df27d7f857840f9cd7be5f5ae5908b222832509b7bd274c3027a9d432caf37f9bfcdbb3dc796769788df5a2af8c024125e9a4295645a582a4cf8adfec5fb6d184506fe5f6488607a340cc1fa27e8e1e967780bc51086722b96744d0adefda67229683f66857351183102cd64ade5a00d2519e633472893704cf62e2aa7929e67e89104861535b955df7bd02ab36bf2dff82746698b8f9e544d26880ff977b40d8fe13805dfd14b8a5efc1e6cd6ec3cb81640707dd875b3b4677d0511009b9e6180e4f0be06f9d17c145de575c208659e2d4a7e209102ad0a1e310166183d359849e6d31a4ab0e941de234535d0a6b6af4538c27a65e67d331afe47f51a2f9b670b833cd44edc28998cd83816a2cd55da17f7727bd3d94aef4ea7ce47efb218af6b6a30173f6f8e510436bf233f4c2c0c31b82a8b9e14b5792f34a0d1d62500de3b83cc98b5ae5f176ef682728c9de86e04ee0d19d94564fbdefa0e882b89feb8319e81ba5a06685fe98ad62e02cc54410276ec54fc1216aeef673f3c9ef4735147865b1a83d1a437d2e230f0fb5c535e08ea63a68580f14a0b735a6c0c3af0f806488181d681fde70eb1dc1c539f960eadea185a4a2818e54183e8eb5ba2463a9b98a97c843d4123a3eeb84506fbcbba9c1ed2f799eb7853206e1dd20e4f0a3a227f335e586ad041f36833cc69927a48b5f5638b1969ce526619a7d08a65537895e4e4771a68085e5d93a1d0cdb8daba195de774ddce051e1ce080c08066a2f52424f5308e2f217b7976a736ed88312d35431310c48c8245118c16ef3a818967dcfd3e377be15ad8aee6d0ad274c53a4ad832a380b0458e1eed3f779cf048c8a770a581b6b8148a6b7d6139556cbf286b03d2038f2988b3bb7772abd3a9779dc7ee11906db206f07815931db144ca54b23328764a97a17c4293cc2fc5a5d3a2b47b112a51827440d211c1410977e700ace3eb05342e295bf3fc4bc4770722d9df7a58fffc72fa4326a03291ea9d7da193b2da904feb3eaf81eb1d7fd979476f5fb67a27fd90b0a8b0c4c9342d4f78636d65fc126e2899052d2fce18836fa916ba1063aa0d9c9846683550531df246ee770a130639815eb00ded61c56660a47699095bea142ed02ef05c0148e8c3b0b1a5298c1547c73496d4e9da9a2fd9cdc5775c7dd9b340251902167ae130e3f9b85e90de87f1948e46e58791b06a9dcd77f90c75d643c50be9d4229bc75dd7d7677a3af49d1e6771a5efbd827f178b498c8c8a4ebd2fc2c97972d39529b33c5e5b656ac22e945a820c5041908b8b7e5310cf07b7a8e53fe9f7e77f9e4c0e56b5a663bb96756c4d21e04026c9797faec926b9e2134709f21f0bcf0e049ab42c04253fb7a0242960a83059607c1902e96bf1461a626197e24154e872c7caef3d9065f36934b56c37d0a67ad5e188226116d1a6082d4daab8175648e48d9ba2f19a422dc92e071adaf484a6836bb959756a0600ad338d8ddd9a8b4646836eebe2d54228a7cb0b1357c02bd26992a8049b5b2e6909daf1c024fb1d949e7478b09cc351711f5bf15379dad5553e8ea5a3d6d6fa0a40c7eb94e8500c7db8acedb49223991cc2d85489ef525e5f5ad9f6997b807a8bac4cbe7c42ce309455ee4ec72089c54529250dd51daa289d064b0249901e995029cda1d55735e90d2062a486f3a132ec8eb2e3c1c33edae1eec10e7fbc5db002f436c0c86860397b3a8025af6cb80f68d87d9ca9e32103cd27c6256d10de47021511a89912e063ec94a07c85913dc5cb2d3325cd3fb03a441f4f396b3f001968014c6304ba7bbbb15c30523a4e07971f6bcf7449858f4f9fd945a7649ab6a8e28996548b34adc20dfb7d99b665daf52bce2a9e3e82e75ecbaafe8608848160188639624e58baf007ec0dc35abef443ca39c4ca5ef8879db5c13ea271d326bbdb9632a52403120b120bfa0a3a7061441535891a0e8ab26869020534e03603beaebbdce54fb6d77d792ae6fb3798a764646278dcdda3b0560b70a246f1cf2e00042d5a10e9e0832c9880e107320882145a868e68e2384a3d25b6a4ae237928943a1a85b59a390aa838be149ed5b67a0e6eac8dc90facafb6f249e177e1567e291c4d97065b4e9e6ef22ce0b647ea463f3f5a6a8132bf11c984ee72b95a748515a8b7d8b167cecde6ac0b47d3ccb772db72fb3daa830e093968d51bcb07cdf5f71650f22e6cdfb1575702f48e3db3e9512f7fbd1ca250efe8aead747f72fbb7224fcd305200054c064a860002cae4c10db0c0d2c5115818e1846a02810b172421420b2094a840d5bfd13c75c4c78621b83c61c4506d89aa59a867b767a98d7439dc4a2eec4857e5ddcaaddcca6d4bcc46d462cf62663deb192cb65aad562baf4846330d38de46a54fc69bd9b6ca26bfc2da38ccea08e9813cc9fb2f2c62e42b62044af747acc90aa9cefcfd54b50d7bff794f0a8dc0fcf7de17296284f4a5870204e63ff079073bfeb5e10742fad27f361cc2bc375bc627167d9f245655e3672f5812abba99f139daa7c50d841768b159896555f70df319cd8f2e24e34797ddfe1f1d76fb478f75323898a766b7bf61b12d74253f3eec2c67d222d1cfef87693381beda48df81df7320dfa99adfc8bb01a76aaa3cf72781cda54fece5f63be8a4f381b27d17fa24b150dce76747d57d12ab22a5b45013c1a7fea6d249dc7e8fcad70d138a016dde8224fc0c38c2cb80a69701d2781ab0e6e9c74f412730ef307f03fe5855e9678033b06ac6d7007d92eca84aff6355303f3f18ea7398a36db61268b385be64e6b440bf814ffddec66d603fc78425b90e770b7d45c58e2dfb74d0f979374a93df845b33c0a77e1feea9e110d6e9ffe119e0140b21171fa7c17d66161762260f3f0b3c847bb8cbd4e9672ef8d45f63daccd1b284a5b56a063bb64c8b85c19c6ece34d5374a8890ed2b03a60977be891e60f6f06f3077e3de1814027387703b6a455aacfc11416287f0ed533f09e6a91f0957c312ea531ad5b0c9e3df9168b0be1a0939cb5d2df314ccf7f7cc53df8f3e9b15be2f3d0b30ef3d83de957925b6afe29679aa6116e6ab96a78ee0e0a505839f2376d0a189aadf5d9ea24012188c8105084045f4a0eaf755bfb34a3f619e85ee614223df931e26340205c8f7a43702f35d0906e68fa83e20dd7fcfff911e262cf23de98bc0cc6f0433a77fa78b78073beedc064b3e397a74c73984db4ffafe114c1eb79604763b75f33cefd351fffb6cf8e705d2bd67034ed5680253e533c29b9e0470aa3c07b982363f48a46faa46d0f1c3678623a48ca7f919e05479b4c63c09a0fd11c0993781324f0394f13520cdcf0059e5316f493f3c528ccc0c8d0c1949067884e4b1653ffc44bd3616fa559fb529abe974dd0372b8bb77a00f8782431463dceb84f4f3ab8025a1705f0228ece0f8361c64fdf96db63f72b707b4c8f1a81d972a91592342c4a7488b341ad398066b94afba9a9a4f07fd9aa75162902f4fe61cc6df3d0683c56c7018885b4d5a2489d8d8d8e0d0ef9ef4be83e330512c98a8ca4f7c601e7c75539d04f3ddb3f03d293442faefbbd0081420a4d0e647d78536f4bd9faaef8d74a10d0d6d56207de959f0befb5268040a10efbb37527ad24f15cc4f55c35afc4067b9aebf3c3655a5ce577eea8ef5941659093beff4259e030ffe83afb8c540ecf295af7ce54d9c89af7cc5414c2b3af58a694ca375ab5dfd0a031086610068df389540545a398dfef4e9a87ffa76f4cd71af231ad33c1c1d8b1246d5afd8bebfa798554c143773c7966d2d638e5a61475f51cecacc299d8892456c6d50a76677111371c9435c65a77befc22926946a77e96cd1a7dc865177eaee519ce5ab9d92adbff3e9f0dff976f4e537a1c4e0fc1a46b3f3169d6460308d0261a2ea7f340f12e3b6140f01a50d64fe1c2df3146b99a7fe2f6e7f974622a36561475fd11c3673a678ac45a6d1b8745b689e6a5927a3b5ccad34aaca1d67adc8531d11af79cd6bb5135c28bc6e50c7b5ee044009661c19b506a070b57ef24eab724cb1616438c5f1a9dfddbd04cbf916762281858603092ce5546d5fbd3a1ad2a26a8401222e76c0418b2d3248c2012982c4c8c10f5f96d0b285134f4ed0c317308aaa50f50d48908011430b7a50c31692138b52c55f1f48110314a9b6afe1f453d0171e8d9a415f68b7ff01a193211ff0940b6567996581848bc9112f3852c41716b47270032690f099dffff0d408828801104d5a3ef85084aabf054f4d1fbc584535c0e20822d0a0faa28b1548f1b2030b682852f5f3f0d4036a90d5a01586161f74a1ca6247ae7ea07ea0c5feb9d3a8c9b56d537f8b4c7a346fde189d7bc475ef26ecdcb80ec8e1240778ab3d4a3d4a49f3bab7664efba9590b3b768c04837f21a993d2c884286e7b69b16b958e400b802df0007fb8121e53a2512be4e89a8333169bb198cc7946bb56a93b75178acd1c39e60326d31a3576ec6e69d4e82d6f4d1eff99c3759ef83f6e86bd898d1e906316cda10854b9b1183373d76a1ceb5aaaf4a658c762a590963dd46da59ba8b7fc7c90773c89c8a9fed25dcf2bd51f0580e2c219a73c76a20af0853b5e58a7bf72d556faf5e90997861c7acb0776ec580eef58a3b804f97a152b8d82dd0e126ad4d0aca3301777eb443628e6eede40f7879c395d0a3bd657baec59cd53ad051760ec9815536c21ef224fd25cd41c8b1d672c168bc5c6aec24e833ae6296f79ab63ec2d6fcd580ea122d2532df489bf36ce58118bb69a2547e95404fa87a080422c16f398fb0bd4e2b1fd61fe392965d041a6cc51f875997e3a789b7374a457dbf6397ab4f58ae9db6095b0cee4b68175f869f7aa45eefb15e4a7608fb89a808118f16a543f69d4fc799b691a05c48817d37e9fef6362e1cd1b63c76def943aa54c67f59a4e15e3d0b04eff28803b5f44d91679b689bc53024771f09603059257e2bf214e9e0ee6e79b502f4cb1ff345137a69862ff081345bf8711525f888c4e3151ec03c7791ce7711c7b3d41983b5a2d2c5f8eb356668655d37e208d5db123a5345ae4291297220ca10aad798a8b582d4fcd180c15299c58c93cd531929c959ef22886a408a2796aca6a51ad0979aa270741c464354f7511a6acc86de62919190b884855ff565617b9b13c355553557f3c3555ddba2395d162b0976b6bd5d56dbfc2561086222409837f21bd824e4a4f0269232d6f29a4b30db8facaed3a07bb0da45b5aa4cd405afa30513d8329b6abc51950227a658adf0aadfa422a035be5a51db9a8d6ed69a51bad5cc49140b0bb5dabd56af11f4001260bb4d0627ff419ecba4abfda35739a69b02395753f934701b7df7b605d68b19bbf98a7feae8b89196184a22c2c95b56cd62e57bbdad5420927ccc02f4da055a508f0d828ddba12e98bc0914f0757e728068811b5d6a5e18fca3c9f7a6954e5d13131313225885fa314f3f5f0cbfde8fdfa28440106d7e1610e191c3870d06c5b48f3d5efee8c5238ee5ce69bc32b380631ddfaa3f79c866bd16ff5b0041898e6d351c39d16878cf0724b60abe6d0112b4a65ed02678b9ea2e1b147033ba0d69399d36c99cba7838b2a48a398798a4a41b5b83d521edcfe52702cec3869320edd8ae59a0eb7c28eece57691a736e0a7fea2a2a2a2a2222aa332aeb45a6b32fd8bb421cfdd256ca084cb8cf3a069f2cc2becaac569b956ae957269b1df9b51d9cc01afb0b3c60031c20b0f6cbbee44a208b33b3f1dfcb915b6c6003962d2182047b0dae583bf5c6e578b738ab5b988632ebab4d6a8d2f75319957d09e45beaeecda7027fb9f5a9cc8ab8854e4a43324f753795dd9eb9d38924e41ddb75fbab3873f8bb92d42ae4c0633ba78dc79a14cb81b717abce60e7e770e62d4dac8d3b47e0b087c7d6320d1eb72c8739bc8d654f7027b2e38c19693af31c02d4c9b1befc290a4f83ad652522b126cfa472fb69cc569697fc693369f18aebb3d949d80b7fe15a8b3fa4d7fcd45f4362e674122d851394ecba2a3119e18e1de3f7b0b2eaeac2805a744742ce1c865d58a39c2449925c808ccae814b40b59a3bc466934897b19f22f5eb8d6ae56d23e5ef394cfdc67359fd5ea129f79aade507bb85507067c29ac664ead250f794a8b3277ac0bf852f01850e2d87cae74f9794a8b1cab3f320c566968280d4777907b1a9f8e2e9c96740a83d05cee4f9f0f1372a892a5e33876841d19e63f3ed65d89a3e0f6bb9299d32479e3a493a49335e75aad56ab592b1d3b8101b456256aac2a51a7b835d6a82a9ba20b2a13d689523dc85b2b4fddfc4d68476b6134b762e6380fd8b910d2e2768e59125be38e7e4b6cfdefa7837fd6e21095d5c08e5446678d9a43237068e335d6e9bfb936649e9a4147447142288a214c49a2cae992e4862b548a98c10f2a1a5160c1850a9c5062053950f5b790a742209bc10f0f52ccb00a43d5eff4c753b5a84f3e8daaa5d7ea964a69dd809a3f1d140576dcc82b04c9eddfc899536bade596e9e486a8bca925d758b057d7bc56abd1308d40824d8d1b1c1b0f92ba9a229b6e58179389ee05260f077901136511183880c14501aa9032e50b952e5852bcde41f1abc60eaac68b85e0176aa7c424ffd4e09e5963fab4a802bf874cf20f9317984417f0aa023fa51ba0ec1ccc343d0ca704b04d8e7fd8875f7664a012ac0841040e53f4e005142a1e53bc64e1e14a14162851f5f3ab9f61409dba409f7a0b3f31718f0bacf30101704a043c4b531317810b538b0bc3776425fc1b68d1c32017a031d89177fab6d0a8b1c6ed4af2e79e2d649275fe8ae003ce24f770acd3cf2d1701a738061cd95d068263879bc480c9e51e6ec1d4611b5ea00405486c939695b0125e758aa3f06b0c3beef08b5ffce2174f61252356c22f56a2e436cbc4209cbd6e269c211ff22a7c08c7d46257983b5575eb1811eed9421ad6692a9cc2a9348dc3298f017b6bd6440c64564c1d76e28a564d318834958e390b79b1f48e2ce495a845a11833d172017db16393edd3a871d62e3f91c943bf9f0433d5a4f70f92dbbdaaa159b01a6ad239ced2b834eed875b63cc5f3c47d03debc1c955e866e65568a43b75f3ccd940321fa4bf497c8852498b5578c3b361247622c269b9534dce34d5827069cf22c7c6a6f4273db6eb56e5bad11d811b564f12662b8e0f653a605f5a97ba8ab3095db4874ac0896e35e2303bdbcd86ac3efafd58f8e8d7d02eb308fd2220b9113050ec94c71132c44b29090a7b8b09198a7fe2ec60aa18e89e288c8a84664fe68d4c8ddfe12fac45f65c670702788b3a8b669076fde18bd970d2ac93da49096ac63034e552a6825ab0c95e497773d631d2a38b565e95907733b0a762b0bf7340f53a77de041f7aa97cc9c55a9a76f5b1ae5dff173efe57012e8a57048bdee7917ebcfbd8b6119ac77d463c6f56dd5321ff34564626442283426b481e2fd54ad7ae5a99e4d18181af372feee4777eda83270f41e69f361f7361f06838b28f52aab64a575fba9a44702c245597eea27a56a8b7fa4312a4506841457ecd61a3889797f4aa9bbcbf5631ba7acf64ac64ba7399117d576bc66ceeb02b1f1ac511ecc9db457947a4f7fdcb9b43f1f130be97665d72befd5fc76f84bc1bd90672e4c30ec8abeb84c9e5ecd1c2b66aa97c4c4f4aa67254a7bd533bcc452f2f6f276818ca85750e394ddd9bb8e597e721eac3f03b55afef57ac84f5caea25a497b8d95dc984c611849fa94349e6509a424fd6954291cf996be396e2bdd7b81bf94b2a5e7e72f05f6c143eae5f7de2382a5e46dd229cbb8b658e629af34f00a2462b95dae605bd528aeccdeb4cced8bb975f12e76f45ef784115aaae8028320ec801404272a30228b1334b1454963ef48db6a5b012db987147ac93ab5e5a71570aac6a0f392d672e64411833abbdc53af4c9d7e29f8d45fb16881e33576a7650a2ec89455944e2a7ac061095509280cb650c598b6bbd52a47ba463fae9d4a56a04e0075eeee72eca25a492b8b6a25adb62a10cf1a45da7cf34ddc64fcbd67effdbdf77ec8fb1db643af6d346c3eecbebd9a86896230a6b8f9348a8b9a969b11a42d8a97cd06df0a550604a54f2e0d826e2b4aab8cd2288df22810b38769acd35488dbef402d56579fbaf23075faeb8bfedcf661e63017b741afb6664ecb5a24ddb1b654984497b45a79d7bdfbcc8ccc8f3f6e901dff7478adc9c33cccd4b6b52ccc10ac1128406a5ee68dcc7ccc1ba97919d7628d40e9de48cccfbc1199aff9981ea4af59ff23d7bbb036fc2cc4fcccb320f3359fa367cccf3c90989ff92e0422f335b346792452cd4c7793debbb094c32e87eff0ac451ee200f4cc1987152db948001d0e2b266d259db2c661a2b88b29f633adc592b3e01e1e629db6c254f0a9bf1548af9923f364b33ad62db257ae5e992e0e3b93f881c98589794d1e20e694729dc48094655e6bb129d74088d14f6ead51fdc30c824f24ab9a082fa9971e929c9fba07fb7d3fd3d01b6d3462798a722d8ee44c2fb723d7cf0e3fc3fc5c7fa28d464b1bec46db886aabc6fc34043bd2b235729692de0b47d19f740925dcb851a3060d4d2994ed9420def8712bc7addc581e868579eec76d15137ac15e31a1176c66442b398e9d96efa99ae7f75ea0e243933ba9f8a0a4007752e9a107777b798aca3c554337babdb66da6fa4be1f34183ec781cb8fd08c1c7a7f4fe363eb60bf3afd5e6d362fb167f71b90edbbcc47c84464ac411932e2c0c0b312fc3c2ccd7849b9223a48779f157ab553806d9b9a4e7b6950aa487796fa63402eb1d417064fc4b0307b25b7afa5e09a511386fa9c4eef5aa5d5d58195708f55e06c9a67bbe5e29ac804c38fd643f26ac00cbb4a85f2194f3203b1766caed4dc9f6b3f9d81aa67e71b1632569397390cc1435996262262d61eed82f9b15643ee681c8840d24473b18767c0a6bb1575b6fe527d3b2efc2e5efc28d6848bd1b6d2b298d16d15a779b4c9d9a2de44a64cec49bc4d01890ae5caf99d3ce2b1d362bcc7ccc03997920312f13ae7a153323f3397aa699b4a8ea557f9fc04a7eb5e5ea193b75261b15f332323134aa6ce698487070d628666a9bf6876e836d47c05c0edd357346947e29747f6ff4a3af3f2d569f162ba902db28d568796a7bd516e947983bd6d6ed265b0463a25a8629f6375176d07527f8d48d7224e60ce68edbcba58801a7cac329c5b497721603bacb4f31a199139b3c4d7814b7494f6d4b72b8f52705b73fdc5633876cf1c76d556ff8a930734b93344993e4835fe0eef93db481c0ec429996fd4bfa71487d11949e4bdf7d3a4a21fda13e41b02325470a33b9ba3bbad0759299b79feab3adb6d8b1ca6a1452eee4a1325a13572e45a2ca6475c89b9d3a0bddb167ff26d32ad579c9585ce6a76d54af1acb445519a65836aa922dca8455e6ce84759ce89b40ab62de5d5b39423222b7dacc19c5c0a7fe8de6a7fe1ead5c704726586d45e05f4ec14542366aab324cd426736d386c5e6e3f6aeb32c52fc2349c80891aa84a507b60a28262e3831ee103a440356eb51192394735dca6a3d5fdc2f21d7b46573e2d92b5c54af887653c74fb698bae286b2b47e4f5229ba37be629ba649efa690e94071afd6166bafdd155096c550360b02f75adbc0bcb77a4af1e93e892c22101f83e306f1122dbeb75c7edb55d99a77e2ddb17adad8b6b2bd9bd7beab4a3744515600202bed27b269476ee9ff0a540bff4a477bd9e00c18e5b79b5d89897f9efb672248541762efdee05faa5277d3d28e8fd8feb3b362bc4bccc5720e665c20ad0f8e934c8ce2d3d83e3df2eacb33ae485a51173c2a7c3fb133e9b1566bee62b40f333de031fd0a207e6e02dece8ae08b4d83caaaccaea10cdcfbce72e8f32a3a6c69fcc00a7ca5d9eaab22adb8efc10c30a685102ddcde8e3f73a674d9e7953d925c4cbe3195309459cca2e16825f3837b016598889e229a6c83861259d9c3da99d57f313ab3bef819b2aaef50ae645534c9483d139cc9cd5cca9028cd6814fbd648a5335eb2106038f41a7b4484754d6a7a6334aadd82d2d1675b93299561e33e93dff793beeeb43a0d6f0057e2eb4193dd771a311e74ef29c06d12c2ce96d40c063f4def3982008818deb8523ff28b4a93fafb7fda8ce298e9e04d2298e7e7e29d00b4391bb8dc05a7a8ad22a8d0b69152ad4221696ca827860bb5abd57ac966a0dc7203494c6f8290c8acb3c522a6ebf409fa853940ace62cb7c85340af7d01675324ffd439dd4d299ab98392de3b85797aeabd568a5d4fd85c2e520985789f990100eb38c432a73998ef1cd7324b73ae6a94a4a60f4679cbff9980cb1ae0b2b11b562852a49b2ccc1f0229635ca672d7a51a3e8cbc198282a8467b1c243595021268a1631c5a6b01629cd4f453071fb29a5c9682c65e6b0139c44fd528075123be38e0cebe1d9d407c01f51e18036f56ffe88ca8b21d9f8ffedbf1fd54aafb063dbd4bff1137c9c6721fc1ba191fff07142235080fc876fc4c6833f559c8d07bf85fff0e7a742f7f581e0fccd6fe00a387f131681320a81dc3c00c222ff375fc4c6e37ccf1a65e3a3fee847e104f907fc8152df66f4ff475436a35008101bff611122acdb3f81a9629235f2cf4f55f823b36c8450ba9f2af0c759b3014ed5873d0bc116f2ef870d1b21e77125fe7a78ef5ea3334b492ff473380e385537e05479a3120e3855a34d0ffafcf4abca521e5821dbed24387513d6959ffaebeac3951437e1ca09da5a991c9c749efc6bac687e4aa4ccca58e47a432dd6588dc96aac0ba9ab45a06a85e5d92b89bdb9b47916cef8c53370f6783700a88f73f37e135a50049c08ecad610d3ba8e4d519c679d36b736de4f675ece6717eac65adae565eabb153e7c799b11b654ad0b3d7bdf7f336cdad455e586b2b58ef200a7a1e8a4e514b5bbb09cb1414699161a698e627b8fdfef5b0e9e1d5f7429b1ede7b21d38ed098e179dc937e8aa477b0870b77b4c0e59c0b9ddc903e273d2becc8340ad6dac467b5864e3a162c45948d62d815d6e3ee980c1a2c8d5b4300c46071fee6e7f7c307e76fc87933c949b2700010fafce050e1d8f8243baa7ff0c33009a7c261197c30c4155ec460498e06003855213855eca0e992b499a365ce99801fc2edb7518570fbbd15669686fee3d36215b6daf4a8ded73f728ba69716bd467da8b0a3cf68a33c7472f3ab9b15499d7ad40150bab56c9173b721099fda6f1ae5edc33afd9e7703b6ca6fb8cbcc61229820861ad7d8c6fbfe4a422dab7b4fff411a4dd81b15f8cb75af5df51b0e14801af7f09320658a1c5810c60d4b9450cd20d0a03cc1162e78420a9718ebd05c6f001587baa272a9d75ab43cd41a35696ebf7b6914cd3d1284106630830eb6b001891778c0894f0d6ce042fb420695d24aa98dcfd1d40637caff06c7cef4d4cd4da5d5f2066c953b39b3dc5a7e8d642fdb8f7ee4daaffc87bbb174997eed420ad6d5f49efa93be03e97b2029a42dfa7be0c8ddd136fa3a023ba8c5396fcf369f5ad62bb574d249275d89fb38b9fd6c4a1a454b67127f5d7512dbddb1ae5693a79358983bd65527b13577acdc7b36250bd62b5ad08095a8fa00ac59664eff0860dd82766b805cdc7e9b19707e865af424cc6b02e79d31af0c386f0c0c7c4b4fc29742df5258cb994373606b7ee6bf1dfc328ff34d8055378fe363e6f9397c81c6cffc84c2969eeec08e14e66a14a36078bee7274d9e6d44ea9e5fc6e4f19edfc64c1e4a734b6f430a5402a96bc8b65aa509c57535aa14be10f34d734d3f7bc68f35ae89e6c71bd7148e4182dc98e79f9f8e19e158e306c7c683210068c2f146006240be161c3905fb341f03f20d47bef64b30c8f8afdb9e47cf3de9bbf7be3ed3076ab169c0f1c88d293d6d79aa965d0a4b8eb63c454e61470a83358a4628847f0877850cb1b744a7704f4d588958a73fcb16b4aaa57251bba85bc0fa8399e3c5cc01c2f6536b2079af4c1d2c33a7dfc69bbe155c7513d6223f95525858518bbca36f15ec6a24668c0609d45505573179bc5114055ac20934012f1bd0160daa311b70aa52a141b455a9502aa702d41f7d36cb1b1c1b3f6e4aa8cc671f525adb08679fe8e3840ceb53ff686f6853b887c6f7b311930704334ff37cc4f7f4c74ec6d71f3989d27b3f7a776498fdee470e8279d28fbc44cc730c0381cc8f1856b7700f8d900e71a338a4b216296d74a790ed8e54c7e54fa66549773a8103977bab169307860d0bfd8fa8be0c1f785fcad25fb7983c30d0b88fd152d2fcccf3c0008223b726a4558415c9cc0129156025c15ac3ccf9a93458b026298175061960fdc02ac306d6510f6e3f97c5a55858b9fdde1577a4322b6ebfaf9c9c79e95648d98c0f30e3ae5765950a2fac2495d15a5b750915ccaa37541f62b8fd5e7b01aecc2da65f31ab97cda7a763e15a56e7dbb508dc0cb73714dcfe4d05379cd2432153c9828d602aaeaabef3270167d9f4a8ef1ff291cb341cbd05dec46b949c3474b2632dd441af1629cd4f4da3b45495512af84465ee5db628f5f97d98a9ba9ac115e2f66f31706a725d32cbad87bbe9b0ddb09960d622d79a49bd325337dfcc7cf270e4aefdc274fdc7dae58ecd04c9a53f5dbc202ff7d01aa64e3b11e80992a0a5fe76d46a9f0e0ec7564133993957a650d5c27f1386375c594c5a6c19ece8b3d565d8cc49aed56a5cfbb7fea486414e360a430e8395608052cd29b1a5341da57777f69751b28ff3374e7214d65fc68fb5645a25b25ce28436f471febfff96de3eea7b1b7ff34070fec30d8445a000b1f138611128a3139c6781bd18c2095265a4042189f3386109c03782f336be081420ff36c22238ff210e3ff517f99f4e9fb06c831d9d044328f56dfccd8f385660239c7eba9161d9a9fac7f971cea0b09546f4f6a90eacff56bd7413c1fca86e91b1bd8c9f1fe9fbfeade5299c3731b9f447c9dd5cb71da4d43d2f1ce99338fbe92085d37237b8ef6f7ca4cf8294e651489cffd1570ebb31022674233e1b1e3e183e0886e104ff71a896c9801fee0773013f22106c7c3fa54d146c8495e627b0d66eff28ac443afcb91c58fe2df4578b4e9d083782fa14d66927dd7fbc06279d74d249274937eed552e85b4bd6e9a7542ac93a5cf30398e021a054974c1e117037708f08ec9d3c9cbaf9ae4d50b5b4f1c12ff8f3cfede77dd6a7de5838b3d2faacad704f169c3aa2ea77b251ec3f9ee5dad9822e1c39184ceb50265d0d71fbd955c58e5cab798a55ff383efac53afd30f8183f6c3087a30db8c7439b1eef638c71bd6dc03a952806fbfdf001ffe649ac7af31c69b79f0b8661596928c0f9ffd149362bdc3cceb770f338610b38ffa1e8a7272cffc8b54e62bb6583cdd19e8c6f472d3b081b4800061f638c8ec23a6de3792a6de674c581e30007186b79ba23d7c03bd612bc23d76ac9b5cab5155a6523aca5139375eca7a3964d30ac6af9e2a77659d5b269378f8373c343d65715a22a41c67c48aeb97316870c0594a8901d2b135646a5a18ec01ce7bdc536d8daa4511d98b25bb9873b35bdea7df53a3065d7a64778e4ceeb797daf9c16dcc34e58e6f712c7d54b431a6b5361f400891b0c01c44594a9c513404004e1d3822148d38a67f5c6ff8cad741293a76a31735215cb3cf59b4c3377ac65ccf39a75a8d8b1962dd6e9c701e9f4d34867b79b708dbb70add5a891ca2e50a3464a5bdce3334fe17c3fd7706e9c003db15aeb149706ddae2bafd515cf9424d67b4a5ff566a55b59c28e5c8760022bbc1c1186155602e0050cba4051840d5438d17531180db2d40b19d6a20fd4a521cfdc0ee4680a5225acc725b64fc1baa5c5144a9a841d2b127664587d55d2034da2b8887b9de0c3c483939964ce4562fce4a246995a1463a27cf068b1299b1a85c266ba5dab7d4c54e7c30bd6f9c042a1514d048bfd0dc414fbbfb05bfe1e8e9c00eed828b066d5bdba779366353979daf3a80c2cb7f2d63ccd26cf0cbaa9ef1b083193140bc4f41f88bae5419de26af3d46ff2d2cec5b77055ec90156e8a99e2b82b2c96db5ddcdebad6c87de586b8ef7eaccf0db538e338d28fb5cab659a36ad89adef296c95bf3e43d37e38664f5b9124cfdaa2cec9f0e680993b63ae3865a6c598b5dabb3eece257ee083cbdd19f4440beee8ad92cac06e3f36f9eaa2eece6fc78ed9e228eca199777dd5a8fade9a3929b7d2a719b4b3e32d6f81de1ac15bdef2d9cb8e9cac66925999b7ec899dacc3cfd5809c5fa4d36eb5d87cc72627eb70d8555a6c97e22da0cb62b1582c160e1c5e9d88e6639998b8a7fe0ce2aacc8666b34f562ed7ea5edd6138d84be6a7799b1b6d3cde6b0afe83cbb05eddab4f2aab9193bdb62f8529e3649c8c93f1a0fc5bd1e53a6bb1d65a7fee1622d8cc91426b60b95aebc759eb9e75fa8978ca7fe080b8ed605f6e75d9a29516592c9692468df6ae1ac54c1ae5cfaf9ef16b674adb2a43d78aa760fefb7e0b038a5dcb8354515ee5e5a0290d6b584fe99403759094d9e33c4c1d1fba8857b3ac531a4099b911b6891db91a579b3cec40d69f3eb17c9fb8b8daedf7d60cecc8bd3859a378a851b35a6560e91d1bc6bd3cc545c159c1bdb82bdc8bd3c2bd38d9943ef5077155ec105bb9f5d5a2b7bce52d7f523f206f7d2d7e79caad35997ed65e2f06ba266ec28423e2b5eec99d311a00f9935ac3eee5758f2ed879a8a9d4b6405a6c8ff39ee2a0f4dea8e64eea3896775dc71161e647b5516df27419d5463cf3343f554638567d9a91634d60aa6a7e7e361cfea00981cc8450c61b849b18a275f96b424ee81b85513f00b367c465eaf4a76a7eb4343f6306d865f902fff7f547f1d62f8878f9b92946d8ef39588efec079fd63df98796c423cb8a78764787199c630dc1410a6653c0c076b18193b72b4f7bde71f7365d9571ca8512514780cdfef334cd408c5b90e3fba0a6eff1cdd878b55c7f23e1a263ae9e771e5e4b95296de915a3a52878d3f9099a7f9cfc6435358040a109aa7f1d3431bfea9a211161915e10411a48a26e4b889215aa17847fba358bee06f930233efe8517a0ebfc5cea607e9f977909e3be6df312f87a27dfb2450c810eefad7ef18643e4666c4b162c2919f70b11a9013f2381c4c9d2386b032c2160a633fb891773fec234eb6b96f31341c16ae6c122cc23ff45622b3d691dc147f0e166b94871c37678dc83cf57b186b710a07e362eddb178123d73b653b9f169dae2c17e360306e4aa3f83d057674e7124aece0d63b99a8f2ba485cddab83959d0caea4a10bacd3917eea92d084a424e1625c1353a79f08ee09f17a32dc05d3982b5d0aacde9183d54a84933253ddd16e9e1e62682d38d59974b037906e028e0b1b0422dc7eb6954735ca6a714d280eecd8a517320a8a53ad1ae1000720b4546393f5c6e471f132d8dc5c5b65973fc85e35abeb56bb56d79a3cdedd5ddbb34ac4465f4635ee8a6b611ad801752f3fd1991d5c432eda2233aa8dbed0b087b68e155d99391cf7c5d4e1b400e37e3bcaed8e5c49a7d8b16b8db8cc1ce677a1451eac237add60dc13ddeddd6a1c71b9b01197c9e3f5fb7f346aebdf2a0a4155623175a33f58e0c13d341c71611758e054063230e2e282968682e6091e54dc1fdce5e4e9c9339798298ee5d3a54c0762f63b9299e2ca2b338725a5d7c069b15f4c5377b9fddc433422ec570ec60979aa86e360a32ef3d4486e3ff7034512515ab7017726214416d7e3aa7b75e7ee38aad51a2584bb475e3ad55d8ea35a39849a772d35e5ccd33c0b353f83059a9f098b400132f335a6195f33139a9aab710e71e0d8d911c56e1ac44d69918b15c1c15a6c1f36ae874e6686ba45f2a9df047316c78d2a0dc27a0b57bc3173f81d0c225e9b5b419b4b36518b1c76d35a1cc2f68f4f47765dd7310f5dd775a4b22c2abb64b1843a5937ebca8e263383837130512439d80c7ba5b4634d651be252d355f4900b232edcc3e3c7e8e9bbb81c664eeb723f4c6e061c6be6f4833097e338224a841dbb56c79e9a51f36307e3588d12e22f640877b92b5387c332739a748a23ea53731ccdcf7823335ff346687ec68f4d96940299f1346fa4e667dec88ca7f9b1c99a9f7916663c4d1128406a7ec64f3fb140f333c222a322c400225535210e3ff90d5cc454530585eb7bcce10bdb57126476b0418e4cb9db8f41ba77f005fefaf5bd51adb4920661f982db27d3b29dabc5ee805aecc2ae25c58e68d782d9b1c93e010d13b591353437fa74d41f75d51dc61fe6a98e8779eaff010821295debc795307bf5278daad2dddd24e9b2e21c9befcd80ad128348d79fa95d7696cec2a9a6c234f68299498ef27ab27225feb3d5bad5ead3b42e6ff7fa21eb5a1dd962f1a99fc5b1581cacdb5a7a033b76ad5a8b05d4a89173356a9ce5ab51e3a8d63d79b6c1f6531b58ff912b278f94c953278f95c9b335317b3a927588600e8bd9d32d51a5535d943ef573300ed6b5b82e68e6741d0f60f722b9a703a2eba123b71f4735ce07d60e13c5bd60a23e168c634161f9c7bdc74d8e1d66c497936124c6448d3151dda8e64c4635afe1768d3b5a9fec5a1fe8515a7c3d9939ab16aded5a5dab6b3da1405dabe5b2a1c9b311f93799aced2da8b96cd9424474799cb5b632346bb3366bdfb703e68e6a33877f1cd5eef7a960e37e644996db6f29f03d72ebef20f5207d0dbf6b68d3a3fbfa3bbaafe18d9933fa23777eb5fe8e79eb281c838897d6e7fec8fd9ec7b85fe864e6416e0a07f35497ce71cdc1bc8495bad5dd1c176b949069085b0a5b00d2228d623bd2535cc9a7fe2d1c392e2c39a44158ae649140ae8b12cb446d3151dbf7577260d0d241de2acb53ad85f585ab0bab19a82c3be6ba5526bdd64c2c2e5021ecd8250c660f0fd621819a49f792d9d343acd35fbfbf63e014c7b3f1708d211cb82c7c326d5c3d9c29a6a5d80b17b8878e6a7e622f3835fa12722937b0db6add6a652632847b465c46354f712c1f7de114e70276b65e6f232e2e608db88cb8702e60161861dc7e1a841dddb17b887b7eb00e9785539d844f5cc9837b7c86d95c7a680077ec295486ee3373aefce09efe62ea24692d4a202cfdb123619c121cac7e3f57c44471dfcf1d31511d27e360958375cf4d67871975a4a71ac93cf5d7c02db9dd1dd964c9ae1681b8357338ce5a93a9cbb2dc3e1f5df6969926ead2534dce905d324906d1ef5a5dcb53b3bb6b75d7eaaed55dab13da8975ad98ac6b753c49db9198662834a8af28324a49db887b86796c0a1907ad56b49242bc487625b8c6550672f3aac83d3290f555859021e0ce2700a7a8ccab2cd6a93a74ed41b5b8e3335762a2ea14b32eb981759854569f5aed7d94ca629446bd88c128516354c864501f688b97d8ca2fafc6625e3e858c65b2283499937e6a752e036ee5adbae2c15932219adcee814f9ec3145f3258f9aac43034b8a746c6f7573026cfc765f26ca330260f47eabc4adf76a904ea98f15ecd4cea8692eee57a2dc67e89866725b0fa9063e9ed9320b3832d3dcd8fd696defe58c9d2bf60bffe34ca86cd71d696f3d46fc351e663de9301eb4f254bd6a75131e1b4f69b246d38fe2d855cd2806ca5079c021b73e7124914dded4e269cd0a236794a4f7f6e304ffd3825906f1562a668cb5544099cb7be3c4583e6a969d06b46f8e58e348888273b4ce983268f10194b4c1e211fa53279846c9489c92364f434df4f85268f10ee677c3f6d62f20821bde9fba913934748f7237c3f7d62f208f19e84efa755268f90fa36df4f73307984d0aff1fd9e17a73ba8940dd357450e324523000000000143140020280c0806440262a1589514bd3714000d7f9452745a1d89d324c7611043c620648c01020000220020826d0390a878fca82b7b6b0cd8f02ab0653d9000185a0f217b24e6a86306f688a612542e5ac2d836451b51f6a3584cc2e64fb4990b5507bde2072deeceb6099005b122b7bde3a59412300b6871694e16fd4a422f5721b8dd28e9c3567d5c2a1e7dfd713565ef600dd725a36e68cc0c578e5f701043c4d3ceef51a29945895f339502d82733a30401f3f4e4ca7e18aa89828017ccf79904640afa61f6424d1372ffb837275dae343b67a52571afe65e46f7cae47192c748a4370d195b8808f7619fcf84a265be2f9d9ec2a515e439f351b17adbc2bb9dd2367c79c134a060845c3cd32a0da405e788852c42f17db58f37bdc01604d8d808e3b6a45506bfa75c95cb6ca54bcaa7425485ce94da77117db2badf9ec2a20b47e4b640b2d73438926d28a3a312e6b1d05a7773d482c5512ce5b4e4c8c2198609d32f730d68225dfa20ee1129088aa0bd8881f70378322835fee7d900853d0e6fe384403035c5855ae62a0900687e0e542a266503cd5fc0a30cec4228043a65f3f5642a9bf9100785ab39e075e7e536b283a3748f08f6901b09f001c8e63d0d4424e909e0f93fc508a27502131bd4cbb9c2286920c336326e1d38bebd8e75e602b2db77129918f34dc9cfc45f9dcefc2ce6209534488f8c2875197681c926be762feaa94a18440de4e226c0d93e15656f1a423850363c0654dfd7cc5ed4e33ac56922c60435ed604995a073f4b9d9bae53a6e674e45a46c9d377b7c75ba5126cd803372dea4b642d9a399e834edbdd178ba75cfffa2282321df0eae93a033303f33325b614e772bc516651a7623686680b9d903c8bd6af2c8ecc52371c392bb5e8b69f82bda1a637ff79ca66070f7b7793115f6a16d39d68356f5d15daa1d0f5e5c1bd799e80277139f0cb562f12e3244bd451e7a7eef6a2d08c74409538bc17fdbf3bb2527cbe628b2348e2408f1b5934e0fac395cadbbfb10059a39a2d05e8104bbcb025a6d4039b74d65790cf1a5f46b87dbbfa0bae0c2bc4d64983a4c7888395eeb030654feeb59096144742f931c96b27c047f8f5587f20c8db745413d0b00c6d7d96e1e55854a6575dc2bab894cb39c918ae2af681a65a443e2e1db9f6e9d8da172a368df9bf17d70e1b518e5a5bc2c09d02e06ff0a5fd5820bf0ab819e1c192bc4903049d2e4a1b108499f12e417c8d74affe762dc4ad7b933219ce9cb47e44760f99a0f31056452762df96bc60f4f6890731b1e5305464a5838b14a6c06857f08ef6e6093c413fee7e9c1fb879a82704c9c18bfedfce8e12948018d274872ca24173e3e1f6876d4e23fc4a7398d88b79f1c74c806316254e5d4c16c2f7b456017215bc409930d4504135b46340ad25b7902ec49c7ebf378f7e00c313f9130c95b317af111a70d2212ac7f4dac906056bd1fb9fbccf275cf28dac4e565867dee4138a901a51e74d6515abc687d03dfc15849e6418f2703f02e5981ca7203165902204875128a0bb99d4aa726e99fea16b1fed807e091175fc514db51d48767fdab67ac46b5a5bbfdafdb054e95bfd7b6e20bb9cf7fc41d87e46c9b62075ddf8cec9e6b7f8b9dfce6c1c4703311c9af072a25057ac1090a0aa8540a0ec50d059c49826eab36da703699c99c468e576eb6aabb2b04432e1b9c8019a9fa1ee5a83fffaa48d9f766151f00d1c24f176f4efd737609a8fecd2e0113e4b35885169f60919345c296c8175cc69ae25d13a83c950fa8f9eb811d2c0c501b523446bba3fa6865b30b3bdb34ca78d09a5676a5bffc3fad7ae0a8cdcf70a86126308f45026c4e7e41117a05f90be00f65301af2fb6cb79a01df335580101b9d260c8c705d5623593203fe3e631e757c7b4b27d65b368e22965d7bbde0d7d2cf6aa232bf8166065b1c69f3718c75b8288bb1bb7c7d3792fe73e131c812af09051fd8ccfe65eaf3b51dde8d2b1fca063f929c1bc35c71069787173200954a22a862cbc59bfcf0145b9a4fdef7de92c1350d679c686e26e18a8130a7ea70533df4be7ea5c05aec1d48b0351860de6411802a63c8a7daa60e794b985159df7927911d4e0a804bdb9d0a09efd9feeda8c89f56ae69b933e2de9c584c01b17aa11deea54ec7fe392a984129b6bd53742b21a18603d3e1ab53b06f361ea8b18b5475e248b4b5b73576f6f31245c724c4dcc44e6bc97ff9bc1eaedb4a55d2f575c83ab880c2fadd2b81e177a6dd9950748d33c15b4cd7a61d93041c28a9daae76a526461cfe6b38014850f2cd4076855a2699a533f95ab4d45ad823366fc5e307b1c61b4f39e67c867a8407839740132439a207e22fcda7f1ef7fe39370e6e4811159bf5f449d4c091d5553456546bb1eb71299bf68b3d461a3b7d795ff105b57acd372f58e63b655e12bce3fc9aba76e4f640e4e54efedfe82a14172582000f84d960090653d8e870f210bbaa504e26a4da45a3325a96704a0838062d67163c43d457721f50c69049e9b9e57aa4bbe85fc05b2dc7b179a8336bdba187b690e6bd773bc699b277a889b446ca30885aecb1e7d77959241cf5ffbebc0410f18f7dcb2615f6476b35c135c8329bc14fd4346da46ec1db7863c34b36bc2b40a231f55e11938719a8b8958d8437b5382832fb82049df40c97a9711bf8af6f3bb13503ad9d212a32d015fb2770034e6512b3a7ba694bd69fcc3541a9ea97ab8f1f7af1ec37bc4277a556463a44af49e066ad990a6281d33a85cf9ca0109356b676bd2d6f27c21803478fbc225904f31588a7c6b3d832f43ef85e5c79500adaa3c990f891a5ba57cb09c22414ce3d0dd3de07b1fc59a4cf15d7aa0b317a64f6fd5251081eed9de73472c029cae4171d46c7d89427f6d68153608de66f469871e962d2dc04d0a5ea0126d96519752a30338b9ac5e2af8b1cfb4a0b1faa0c00db8533bd1511cd4600b36d2882ef7ce8f8b92df5e867c5c82184f68325d8aa205d8471ae70eb7b431c76a46ebda7f366037976bf6d35c41025ab9a1a5d89e36c08a1264b4bff6e43dcf0642665eac7d4fda535218e81fca5b98b93e42264ff9477d9af9f7083f42812eb0fa4cbb83d48053d838f79d68cead5959468365367658fc41fca39610b9e3521c10030a5be0f5e5ae113eb9f4215a7b209a7383a643dc29c256537cf15ae85b20b27f778410c5fe8140d815fb37b036b870da19d4949733fa62c7b189e90bbfe4d2433ec1185350ab07973bc73766c1d0cbc200c94222d0299837b1455649188d2b17ad5628fdebdaec7f44e9f2e19d55e8a73ae34a22ff54929966c23f47efb802c197defb6e12470d2156673c4d1b2eab3c346c91af4668c041a97aa76bbd626b339031fad532f90b5b75287193085cf35eb67acde05b701e4e86e6649dfeee71953cebb7c3b480530c15778c428f66b83266977e1e2f8834d44f039d1eccb23fc9f5e7795948ade354666568d690f5bdbea25a7972a41f6d907c47782a1b643a75bde5e938b02f42b85f8a81d0e9992f6ab87cd3258bd756a87e83842b04183b67cf18aa72f3391bf882ce6a2bfd707d46ae49c1a779cd8c97e67142f118f64d52b8a5cf78085f21debf536f1842d5757f474adedb1a0ec378e885dd731faeb4ca386d37f7658a83935fb9bb0d60bc4d93da660f4ab64d23270e918ec6ff0a8153d419ded3d975ed6e15cb158d8b87eef75965e715509b00e64f2762b8ee0309562c3426a589a1b8010279804b35b47941a364692f7629463da04b78bdf1f772751f0b83ca0e528d9be58680de708a495b3df08bc3c6cf4218ce32d3b0c940da8a13c81c9c91200b682c0b1624a3daf0a876cf4ea1f143f30ac107924cb9fb8133485e5a41501be6a464d53d293c6bb9109a2e05a9b444772f7b2e3dc03eaea2dce065cdcf410301e2fba9f92affeca3399fd30e8d97fff8ecdc862217083ed772cba7cdeef538a37158a2dc5068c8ca3f2d6540bcba35d728792fbd4d437870d9f773ab5db4ec62c945f5671e398621c65ffad2c649ccacf75b6878d4c1da30c63142da10df78f3d4aed4959dc0ffb72d875b6494a556a1a4a3af84653fb1d7e38271aaf7cc25edc912f0083cc1b96deab4ccfaa4d67a1aeb9f7d59a381b76dad88606059b372cdccf4083000e54babeb7cc3604a62532d1e007f78d7d0a9c1fc59637721f40dadc45f781c4f8cfd54be5a5b123624bd1ec92af5fd4bda28c4413a076b74a581163fb5e5efaea9a048339e78b4bba46d29e5d9e5285c7f00fbf4a7ff3bbeea16da2a56b8e3e4ec9a831e3f5845fae7865718cabaa575aaad9b956289e93e0949deb541425c2a4a5ba6eb9036c2a5cee0e58b91038152d0bfd846e3d158a81b12e087ddd1ebc2211ef0ae5709d8e3d74d03008346e7e65675411dedfce9e3edff6d791a12c5fb3b86058f0dd5417f14a0c535f898394d947a1ac739705c2cee8c8ffd370c6539751d47a735be9da772ff9daba0924a961215ea8df42e11e26c9f6e69bf63dfa5cd5b5eda25b2affaaee33dfe4120e3aa324d92b9c0967039e15f93775c1243faf62dfdb596589aec4da503f217a48702b8cb8a1de908f05d25201619693f9361feef7b11565bff83dbbd634849181e740d2366ac83944dea097915ec8b5bf6993a9ff102d8efb73bb1b7e63e803737bb5ef7f25d72cfd2a4b0c063d4e21c153b3e2fd22f7d0d9c397479ffd2436dd6b4ab6e87e66e51a7b16076dcf4b436747dcdd04279f6a9c7c30e6b350fffecead0ea55a9c6afe5cd0b32212d1c258416c9108dfc34ef7222a44189720a805850acebf245bff62c0f1a4ce166c6a80e6653796bf9eccd094d0e90520e47c8391a95278c1f49529e522031d72d1a4e51ef4efb0ae8fa36481cfe348af34861a3bd804bbf0f843ab8306fb5bfce12ee69d490692bfab13150f5d05d4f646847b562d9ca70cf8b213794cbe249f0fcc6b06530a4497a8196acfdf1aab0267268c4906746a8253cea74091f24b954b40ff1b318858a23b07e9e1cad5cd3046b25fb7c3ebda20f0069d06b431d22c2c8eb993b766768f3951dc9c64e4885f36236b801ba354eabac19568472826139bfb9d71745d7a9c915f3db6afefcb4b6c5834e336600afef810b91ab9384e1d1535d4a14c61395e5dc9f13912f61136858c50d2b50c07956a3f3a33fecce55c3639fc89ecd78c36acfec62a7cb6301895af10511c8a4ba169c92c5cbc9ca9f698d760855bd22a2b81557d566aa34b34c142bfb93040706afdf1b180312b047f85a620a31af11e3db1a3b0efd381802015fc53c23043d8839fa8bcaa7d8ccec727a405d7de5c9d6875c1b02672d39ce1155ef8948ffaf585a031e03d5604e9918d28d47fc3fd1b54c3beb44bc81e135a40f431eb1853dda46db02e8b915403856cf52d24393cd48b8503a684ad7e45b4b67882d0930bd835a2afff4b1072a9c245e9c3d6bdc71f8d05aa73a96bbd6b827e3267e834c220f1d6f9f8b7041f6ea0d11992d17fa3e4e9d0703853bd8781746e112b40ac5798a13e59fb169bef51adc60c9fa9f97daa2ffebf1c2eeabf8800412235351755c8850fc4182b8483b25a9b6575acb0c5f845bda36fff71422ff45559de789efa2af3350de3b5f4004faa40041b76454d032f5928fc899902516f9c2ab548f0c4cc50a32bd039d14f6378298af363507a54a779d22a512407232980686e3f1aa44c4dd252e9351a1336f682664990fdcf2489a2253f9245763af3c8adfa7acb4fa39e20fc17f134a2dd97b5bb7c7b32137b14dc6f1b705495a0aa33d2c85458fc633df4ed34284e09b4254962e4dd0c3cb25509ced0e848f4e718b69771ceec90652826ff72312543c7dd0e77a689d71cc331ef216aebc7d79c485474cfd577e8e51af657fd864489ecc7491212d7a797a27d63c21da34cff4bceb3ddf6255ad1cad9e554d57ba1363aeaddf74b6444c1d5d048eb13bc717cc28ef859673627a32a5c3699a92c167f73f4752cf25fba8e0b865bddb6127f1b6a3a9794ad3e507195009fe5d140a0f7e5f8b22786f63eb15c520da9d7f902e330c431ff9abae01f2f6edea6519d120898dab828c17f186c4a9a41c67f575f40bd4071834d1d3f8f76e4168bcc441cbcca1d719e8dbc5ac3c401db04854af0fc297beb4a103d001f89c181ab31970a66314fb281663c8d9d4052f47c0e52c40cd8003c42c715435fb054bc01696a4fd256cfcaa4c26b827f83c1f4245fb98a93fc962ce6d3aedbaa937913e4dd090bb3a1c56177faf3ad563b7b6f01289a45a1b4625b65997cd4139e4d7a00a8e2916c238c51e745aa25810fb05f381e1f9255c036d397df317551b519c03206eb0d39c0b1f9af095005c061c040b81efa3c31e133e0c766524ef7dfd048c7b717144d0f68a08ad3db595cc0ce55a7a4d9ac0931739022af3e95fedc21bbbae438d64e33b2ec7ce0f1aac2d0ef0ed2e3b30c1167a18dd46d35220271e92718858e76dd9e5211267f757302e41ed3f6963badfce790f4a623a728639a322114fa7206c44ba7e2f0360c06a0d60069af0a1cbe18461e1dd7ded7086a108d1e0120d12365c2ba0ed3fa84b03d87368edaa9cf78ab0d1d09c2081215d97804320c603cd414d88e94f60284373c18681be1242f2f9ec05509275d531547ec66a3cce91a51ff6f7509b4fa9c3a38cbdf6033e732d26afbd6384cc751576fe248cdb7060be8f015bbe668461a9a80f1f1f9fc34a120641fd57c4e791a7ba8b4c1cf45ab2bb29a6e8c71cbcdeaa0b37471ab744d295f98b6df455e95b5ea03b8229611e2f58c4ebccb4b3b03422a81a65cc054b63638356fb5a4ebd3a9132b2179c51bce5fe56250f6907342993a4451634f1b1f0c932d64048900be9d5ff3d9e622da90f363ba0d9ac78ae0c6cfb86c171c0bc4b18e08d766e998b8f9f32a0b319ac1b0d9099bb8056044b1d9f460f7b1d5600034784eae6ec59d72b1af07f55b72ade2d32c008502f9c1171c09d2940869819bed4d9d89b959425d18294ce36a589d1e4a3312d79a40d4cee04df1826ca365af3d37b6272237ed527823086c2c2219a65a7d9da649d048bf5998524305ef330251598aa9085e001905846f550e750ac8f3f01cb7b7536a807ed32a5d69fce7292e53c589d2aa9ceb6c3ab43176aae88707b7bbab095d3b125ccd0502e982d282cc149db147ad269aebb39cea587e9e1ee2b40e609993720d18e7be95c0edb421c247ae1257c3cd2f7586f08a504dd5fdc35e30d4b16a2758d7c9775ddc88907d51ef7db71175bcffbe39298c1ed5fe96049d602c426d6b281785a7ac9a0f4173ccbff82c43a43ece680667e34ca3ad6423a7bc0f553414fa6ba756a7d3e629975d8c62db2787497b97a753be0bf62c86741d2fe4d22613d59adcd9e78ef76aba175eee65e1447dcffb4688acc3c03effd1669c3295a9318cb0082477576b92dc0fcd895948a572dd6f15dff14a371074eeba2f1587ce61e26ae91df652647af6178758c0b335d59ac35aaf5ee4bd0b524a69048b8d71c3f24f568faa3bd82b2572ac078d32bf1d34acc058494fe58e05355ab3af1ae391f9980d812c11c63076c976ab746f1c0056266ebab88f7061218675b51dabbbf99dfa501a226ecb4a0e966071000187af12a21121ed9eddf61ebfd4230c9383be091a83e80d6df6b832cfc1e226c26a0f9204a929556b0846fe46edd0be4e43be1ff32b5a50a728e65b40e4af5111006b1e10b75cd34827efce8ec41866c1d36e74799d97e2bf14821b09135badb3637ce12057054fdee72871697b08d95cd53908df20f3c78884c08f1ccc6f9c8dce241658ace725d3c4c109b51f6b983acd43a71d076ed6da9e8cdd24054ab93a494231e20f72360cbfe5d0be03e2847022a072691962a01e3092bb0ceba9e6f92e0f7f839c59ba20c96f0fa1ce940ab3a2f09e128cb8be34c5b454374ea80e82c868cc2e0fbd3e7595abc34e14e0badb1d813b4764172bf15578b34bc47ff802e82f792c89c3c9ac43405286fc1b18bce704c8360957c63741c2ad887ea248a9c780bd91d962bfd54e0e55dc8b7e576edc30dd185eb50a159786aea939ff92ddbd7774dc0339e600393ecf934d55b7b543faf15c8d0c72c4963b5b0b1d1ffb0d8362726b279786b9b12947b38261b5a2630d7b691303bc4cc39bc329ddfcee7117e2895d7fba44c8e7885d4ca77f3d207d331494961860dab9495f3682d64715ca56fdf97e94cb0bfb4540df4b65dc8ac2119823d4bfaaf24aa68bdbfe0f34dc96b562600d17f8cac4064edf63d72cf7e0418a4e2c8f24b70d13a2c8b06ce47ec7c32f0a23e8c3d4685ab8e37bc7b364a4da81009561254ce6039621897dbe47dfa1245826409077e9d3698edabe7bb64f92504523dc5ab4e589584301e489e441d1344493a361f19f99edd2460c6613db744505041a2a6eed3153c5fee36f2fd6f69ff3f21408cffe537cda8f7a987ad6e83f7f2074c30a7223e1109dfe0d861abf7ce2da0ecd3b99c5a114c76d56af92ba063cda422a13cbce5e0bb7fef3f271bfa54c090dec3bb64fd8336fc81633500b2ba5b9003490a799af3b943d202bff6390b02dd9c78817287abc5c200bec5aa45b8c69b244210848ff8e44ce004313dca826b9982e066f8ec62743da0b4070a02183812ec1d913b09b5bcb26f39845781013008c28e6bd19890a61d9a59e00c11be3be0f904fbc40f4a47f7abd981cb7f7b06f954822820b906882066b6d422bc6fd82b2bf4fcbd583952a1b2184f277e29a0f7b3db617f6f4e21544b66f5ab5bdf52586469af5d6754debeca56e9ebc203755e0a66f16d5b72fa076d3052340c7f81dadf775d0aded17946bb1f351ab9faf4bdba7b2d2a578e469289514367342b47b4ca9cad87c1102da38ed143fb76216f687c5943fb8433342fc6d0ebe60bad14f0ac2dd429f9b8956274ce722bbace8d5def39d6bd2ea6a435e70114deaa767631ce043d07c5b3a6d7b18b216a4b27b4890b7880605ea1b0ae0274e2c49102ddddf8b0b17dfddbc7b94d01f2c750b6d182bc0cf7af885530cc8359d75c14d5f5a26f928f38c33d267e92f971993465a9e1295b4e8041f2de8502915c39c0ab0505aae7f29c1ace0c33fc7589f332b8af63739388b265effeb9fc9e923444f30fa7b61c3d6db19a52cc1c8e91adf89139df744007a87ffb7080668f5d68c644053db8da53e7290c5df6c55dab35b191d3d65095591a0c120acea90a59242155bfd25040ddf3573084a7dfd7ae0781e3184b4d86ff7e9e74405bcb49196464536d5a6105b14f66a9177523d8cca12aaf729f2a9ebae1a1a27698928a0d3228157edf5cd74256ad7080c272c44136c95c0fb47bed9bd30161aad04062e0690c89612f78d8d754a08b708f172d3da05ab4cfe8e6c2a991a636b140917dab58ce36b677576638012d22bfe196ac71fda4a00934665d18fc29a6effd13993147e5257dc242f0611d3d30517b91470a02a08293ffdb14676387aff2dfe3c224b7f2dc31717ff4ca26defc5bd428d2d8d66179b0d5304e6077c8c42900c56c1605e987f2e981613a960cc43c4652ecd74781d4e18e6aca36b8927f778ecae2fd94473551518b1f68d268e3aead2d7a9c2dda702050083db912d7428180bf5960b9d65972bcfaba093cde11354319722b8fc636bdddd79e145d08c264c44014c6339317387144187cef46d64d7dd75742cfc280e166b329dec2b5fbe1f3092ac5057bcf7654c08f6464521407ffdfe26d8f3384aaecfbd66056c5928bd9ff5139a576294905b34cb2eff4b4dfc64b5b2d4642c14e437cdfc7a32fcda52426474a9f1302a5638dedb153d5b92e2146c950410ed9775c2b7851fb5c4c374d9bc10c9c96e61c6be07cee0b0cbac194ad3f8cae03715a8c0a3ed11032c63839c02993611f05c252283e1e765f8e89b6f5a2d28ba4d26bd8f196662df4887868831be7a89d1491bccc6d9c5d0d8f94468f088a3da6c4dfb69d726bf3018ad56aa9aa02dae1839508764bcb415c061b70438436718dc5a1f732e3277e045b0cb7b6655560103f2b0056b948d64ccedbb896800c42c424dae98fa7764f412164ed351344d96acfeaac628053b31a6d17594d5689fb3c398caada6e036dc4f6d36ec8c38f6f3ba0d8369a11bb1f3924ab574b83b07d1446c6d9ef309c0b16e542066db6e38eb288465a169cf89a9735de5e26f2fe62fa78214104e2e3bd2d904aaac37e2aa1483bff0d31df7a59af6e5b89679df65d795abb0ee2ee4ad9559cbb921067f1ffced02e4ac629f056d301b2bd6ce3076ec3d9ff237077b7d595dbcbe13eb46515001358ccf1ee34368372f4301a86c2546b9adb1c2342349a725b76444502a19d3acc5873d75613ad0cde5ab4ebb04dd751e6d9e122e2852ee991d87fba03dcd0e80d6b16a31608e3d4ac9106b50617a8dd14fa65f2702443dd33f470c1987c5f87f53f771ec156455173bf7ada7620b114e79ed49e76d7faf2132199ed1275d960323470bbbfcbdc47f25510880fd7b2aebbf1fdbbe4a5660413f31c3c1b4066fec843d2e91819802822b0b5860b91782402ced7edf57ce52208efccde9c8cf058611995df19c65c39eb07e9527a731103073c959f43919ee4d8ecd4c46acee30e16b4c461e21f3a25775519e315fc487b40da4c2ae8064476aa4c003991dafa41021790882a3d0b4537c8c8c4bdacae02e9feb5183af373984b7dd69efc43731fd83853651eac27b22124b7619848980a094bd133e87f160f79becc0c635c7d6156c3b66833eeda31c65a8f5e851a5c7f829991ddf7865fbc882af0d62e026a6f0b3a16068d52fe6510529759370a4869e358f31431c5b7686d5656d9c1480d8e7e1f658334d39c0bc3c8a07da9a848a21abcdfc63360866e7600b09eb7d265237503aa751b449c0e236216568c692c51a2426a0826c5ba3a7bcae47b50a167cbf9e862ce9f97e9187d1e110ee7897975bd89d2cedee6b599e023e6a79c9632d5a8a8104aceda4da19012f59c1c46a10f2d1faaa1a2c641f551f50e619a389e264342d0d13694b37398e8a0b1fc0c0b8520c8c236422f353309f6d9eaa062f56443116a75f535a4c9fd3d392bbcb5382d611da0d439ff91121ee195b3dc15348eb424c5f66e7a7b5a9ed11341ab4268302ee99ab7bec930cff605137266c28e76c88f1f0aaaa3ac54e3d5b43bcf83f8bea5cc9573ecf1b08a671cc3c107ca3032b9828f0f1346511648f0baf1d09e3c705fce045aff0ba367d9f76a13ad651cb1a969c13e51c0b3606e4b62c9273df2c3b8427c21a58740d53224467d85c4964786b0ee221ed37f56263c5ae38c04e5a53ccab2c4acb9a7977af2e15c5e669ad857f49ef6710accfbc26b190bf0f54ceb349a040d46cb83e557cf30dceb99a2d5cc08a13139457288d0a1d911e1d80c7ec0e49f574e3e20549511d838e83b60cb8caaf7ca2e2507e4f7552de9c8eebee6bf0e3e2c5e562c11ac07f3fbb8e0b18798abb9f49dcd528c1620b2558182f049c0e823e12f772009388132c7d652d553c1cf880468f8586cbabead96a06011dab146a62b9ff5b4544ea8c2d4f20304be6a383e8255c3d55bedd8c563651d4ecaa4c5f7e1bbf4af8c067c46d4146e9f2b56dd19e8256895d443e6b231b1613f3c4158ca81e49edd327c248b18162ee177768914abc912dc10bfa06b6a5074aa1c83e31d0a4f5c950b5495dced31c2f97d5bf1c2f3f00725cdb596198d3f1375b0e3b00cd080038263db9c0b2435d356e0434d93feb56eaf5e0b1ea374f1e22817ca5a3cb2b7bf0480009b87510565794b41394101e1683d910d1b47f901f9607b1f2779ac7582a50bfaa21bf60e8838d08f6923fc2ae15ec2eb8f9d6518bd08e40996298736b238b0fd7cbbe92c8af04350f56f0e8716c34e91f0d3ee19b109e821e746447875c40a4d2fb2ec890e00c487a5a47c35b3c9481919c2993d38616590f13288e890248204024ae86564387bda820dbc7d0be2e1d5df29f05623b052a7d1e229584852b6e6b7fac420f027c5edf6774e28e157b2b743fde1a69a3795c3d023dac37d25923a6d18e061031ab30133158b0d3d2cdc7c6e7152cb52f450c1eef67608e39809ac4e39f7e991492c59226daf5d9a0636a09843c3b4f4fd9e31f65106679dab1f947196a0b75c693cc54e7fd504a27c993980e941291727e64556f6702f2c64bedb8b51e5574a6d518f455da24d6adbda0eaf65d6710eb710037c40e69931f7787b8ed257daaadaa0da279a7edcbf232969c20a85733a28a19e73ca2f89309f514c6a26464249bc173be3051094632766593c5eba89126ddcf88842f5003e9837b84116720910eb72c63fc0cc8d008d4eed34d37d8da8aa900eaa7b09bf9dfc19012880bdbe1d1951e8fb66aba81bcdc2e462c10355125af42ffafffcc5440a4f40b289894803886fdf49eea25b77f95631d67da93096ef0ae72e0987e3ed04941c4971b2bf2e470774ad8e18df4ff8262bdc662efc64a8dbc79747f8eb3ce0d4f985c957a341b776033540f90e902c1716c0ce84b3bdfe658c57695989a341c99d538953b93a03bdd2c2ae22e042cdf11800d4c4b11d1ac81b4e1090693e9fcd0dc44e83b39f90350d2549647d5714788b6f728c764773c3f0041214d01f335038f5219131b303d5642d38028e1ad9930daee4929c954da95f9a318ea87943c38b751c4c02d5e487a79bd07f19ca9586240bbc616d103bd64fbef9585da778f96a74a245d96b20780e7018bdd81fcdc8e4855d83d3f7b334c7ba88c52bd3db28b4e53e56e2615de440d7c34e8dfca153438371cb9e3512abb1def04e9644aeebc90d1b903590e8839f18e66fb2063c9ff7e7b8874421c9dcd22d12c2fd44e89ebf9bd2ff885c645f46156167ab1a6b9b1df0e3471706711e9e06d62bb091957f61d50f59fef35033f5befa09f74c87686e8b2210314cb74b06623d32fe34f935378e8bc4cb0d061263cef69e6e1b0adcb1ccf67d20ba4619a342dd1ae8e2f8426cd4ad23f53d27f4e128a7f6ea96074e82a823a54761ef9761079538cffdbb4598ef0ae380e1cad0a344ce05d44ef7063b1e33c54d912b3007c72431157fec3bf6684a9776d182c6c6279cdcc3f194704812309c60a6652e39acec1890ea7e5360b84fe13143dd1b1d8c0d46a37145b77b021ee6f4034fa10dcfcda937a418e4e40c6efc77a4fb41e02101f13aa3751f0f5a0bfaec91e193f85ee6ab5b04dd6964a8453cc9ee16c375947c0a8bc3ebc2f51c7e61d050af1973f748abcd5d9459b9f3835a0047265c245d232061b8ec7ccf35f3399c6b49b44b77f64b29f8ea26ddcdb70f615f0a457b7f8414997ba37ecd045976b811ce56fa647f1b1ace40f53187b4272c00c35b36fec0e180a4079d4a7e41ffa6ac190178936c8527e3a6142ec242ce829ed2fec8ce0e9acb958dabdd75ba9424b9b86e90e6363489d9f80776546ebbfef7d059a9c3c87acbe82c81ce9c9ed46a7e9142ce1f69edc5b0a2752602d5e9520463f8e0b434a41098c1e5ac463fafe52d3840e7ebede48a91d2a3bcdae71df9328619006d662c8b7b707f12da520cdc3b559d3c85ac400cb4b15fe9e346a9307dd160b2a47827d6f210fd12bdcca2d4aee821bc1a38b0189be7afb3ebcdd1717a895f28b9faa9260826e60d2afe876e7cdbddf067f589c27ff9ed34d17f7f23a351e9f8a6bef273657fd22988955d301a37e555a2df38c831c2bad254153437c4ce0517d447227ae44e3d1c74a87756acf6249d156ebbf3c2bd3dce821e1659b21cbe82018aa138ccbb8a86c9e333fe423408743d434eb58186669a6e1504175b51eb830eb7fef7dbc145aaff16e02065d3ffd86aa083d17f616420345d23535fb03e9fe3b120a6e85f090de1274812cd303d5cd6c6abd5bf062d64db45d922115063884a68f807391d793eb3f05261e557358d0581b0c0edd4b3fd66e727eb87c43f246e75243e184e899bc042a818a0fcffe04f9e49ec6ca015d56ed5a4ee69f1f39e4d1cb87bf93fd9984f0d251812f923aa4fd8149ca01b6ffc60019f526bf1bee1c5e85e289e006b4bb039296a17e6df892f5ed44c9a6df13bb43165670b2f9f7c382fc56561e7de759e9865d3a1f7e7b401d6abd953778b85092bd01a679405efc1efb3eccfcc44c846651dfa1aaf9855c7d2cdff1bc22565f06d420c41b2ed0c45c6ba0b7a5d668867860f2a5c2cf06600b23a6bfa720ab2217ddc68602a903511cb5906754a7d7628ba1a32bacc74da9ebda78547f12f8690f1da9c66a4663cc7c44df6a5c0a88e6ea8ab9d9cf2400713f6be0626c4d2836d059399183386c6c48142fbda4bd152f044a21f8fec017cb618c8f93c7ab937937841722cd63399cd2983dd2946fc5fe9ec197253b1f37504359429e18d228b5db0f96d52cef9d7ce2df17c690f9eadcfbc7e45d35a2dcee7e9761f8ce3a290b9474d36efa772bf530c73fc95aa8c17e3d0b352421c922ed224a2a6920e75d542c533ac2d6c1ee671a6e0dd0577130ea5e3e7dbbbc1db32f10146b8ee08d96e26fb6ef91c551da6ec965c55ffc24f66aada2a6cfc3d62988258bdf5e89cc1204149eb1f098214aa6c2e9a44361c59efed0eb7ae6845297464e48bc43483d454325b71a864fac21a21badd9eba5c02eaa479690c1056cc9c2bfabe7ee04d56339828b2c91ff8f10e891f38cc40dd5aa8d9ccb53bdd5afe5f4201742802da600f8d39c95ce0f7ce8ce4ff2f02e4145a99432797168357671e013314a890b82de60b3d112b9d1fa9c39b6da7bf2e701b15b256aca9f41493e7ef4145e7f894a460a1d612487fb6a03fd3c248d8280e335577509db089926dc349c6812953aa8ee4da17ba88782e02e4cc9a2f963a276d43c33e21ab9aa02f95032dc4fbe3f1469d1854f3ee15de5f1d2ebcb2f9c234a20cd809767b7200d02906f5cde78ff5215b18e18029a86cabf50a990dce76832be5fc539a46050b8eb428be66bf99756f215dbfca95f8a5de9717a7689819d8c0644fc47dda24c29e9fd565498d438cd9e5a7d857164563dc406739221acb77a2d9f07e7455d0a1b798db70df7f585688c742f6e97c9ec5d09d23fd9d722e726fbe7a2761ae7edfecdfd783f7399ae647ab98c1094bcff16d93809e1c91dd600d005739c8633c7bafbca469b13061156ad0771a09a3ff3ddc45205026532b10515351e0dbae52c83def031bdfce1a140b3da25e844e827fbfa48b1dfe3f4da5f2bc827e924227a9383341ddf3b7eda5b876a627465242602e760b4c20eac41727a920d5462b98e2a961cc318cad5aa51981a686b19eb7d5364cbd35e8194401a385c0266b5c0a216c32a6d5f902a73cfc3154306b71447e59cdef66115d2eb29aa5c85d6793dedeea401ed75660c501251b2364da40bd6e648b475f7a8100f745d056c1684879b965ec8e18c96bf7a0b2277dda53a9053c7401255d9a01dacf69a494a2adbcf775083680dda40d279ef3aafa34600f90758634d88366173532e1b7198e77b95ebaa2efb2f536805fca5615c69d05b0e558844b266ab8cb6d8c57f1904096655a4b33a8b6018063725bcb5e236b6b0588203b18a517c0c97a80c36550776d9faf1074cc838dce8485d1f656a062a362f23ed65eb25c0d31e1087d1781173e8d0b6c8888fc660b780ff106d6a498ea11e0c7ba2cd307dcaab2b44d0c60935bc4c50062379d815449eaf4488131c87264378ebb3e47646a89ee96b2ea2bbe592b6db74759205a76c2c68348a0707b83a6000d069876471ec003a5befb6b30c17db3349e2679c772c71cbe2f55f625bc8ef6dae852add7a792574a42018466626cebb33cfb3bb6caaef26fb48f0df9d0dcadca602b7c2994677c2d60609f2cd734d0f9bb9648324d09d8e25cd400f7de323862ddca15e6f7c45e983fbc3ab4e53aa1663de5400ca1f2cf25e8bbad01ea96f1adbdbd63444f1b121de7a8affa3a9b9b4311dc71378c798e463c61d12096b6a37fb7555be1d1946c48ce5bbe6dfc5612382b7bfad2ecf40d79966197764ebeae836800f8801609ec1ad12274a83eb67b4ffa982c81fcf23f8e4bb90d02ac2285367436912cdc219540093013dfe13b7cc7ef46587baf50e93f027b4e9d25e4374d523f14df64fdb53b3a09d66b957220924dc35c608d05f62a99cf89e700a22c24c76dcdd1ce5c3654a0aace27bcd4603e8846ef65a5338a68e10bda87de0c43fa9d30c436fd29c0bfc0e3fe6227b3b45034fdab38abee8775a5a1eedcb4fcedbff80b00d5f0a08280b498c9795bea3c068bf685ab857839f202da50cc97d3f641a51b06906b7da088682169d5f1812ad4b9ffcf2d2739d4d3a3b55a9d010859da4565ce9a5bd2386862263b6621d08905b460911965d09ddaf909385c87aa9b9bd34ad692352c6ca89edc4a13f43cfca9c520cb3a27b440aef04ea5241bf843c0c1ae952baf6037ac9a506d52788bff134b2ea2d6789929286a861d2c77c61344a3b84dbabc71d5dec8878710de8b1ac2af687110a013d03e26511cd4391390f6ab7f63e5f878884642c7bcfb2cc4f26d471044b238dd7f2cac980ac2b4c8b4176f6cc5c7ff910dc677ffd7459213e57a3c72f8ef2e9301eb8e37aed3af115cd16279bdfc9ae09ff8cf00091b456513cadc76e496adaa8577b167b5ab0d4f82d1b16a61c0108e90572afb1a95034391d96f96d3385e4626163ab63399de73703f26d9acae8ed54bd676a1c0279c4c57032134895db348405b9066a77d283ff0c2989e2db11b93102d38df39037de937c321cab407a72392137b3e04f9eef67f75fad531537bdfbdf5287dcb439ef5d917b16e5c94eb1b2e4196308d7aead8ad47dab231ae22240e11467cb47c6ea8df4be4f5fbfc70909178af74ea13ac6afccbd9e9481a1f8469a922b3c293beb39eb35ca7789f3c555b9cad872478a44945632fdabe18bb4149552143dba7a99fe4848b86ad6e1b0e891aeef6a9789f5fdee0f969027b80d0961555ee1955e2759e27e60dec71d4c48e9ed093a54a403caa529eabea543d59fef32b912687e7ecc88a78f22cec82cd85aaa99089b97adf350ad9baa5cf68577c4e5c68a36ebc40a0e5aef4b84dbf74138e3b376313046a06108f00622c1ba23f60099e0dac26150358ecfe19f7488a83e87ade027170bffcdaa24e72106c237c460e5f5d4127851a78696e36a660b79e879238a0ae416d6072297813b6e9f000370bf7a0cd35851028e8dbcc56f7da9ae80ee962387fc9bd18ecb7e3c883a55ecd7301c84bcd78799e3f4bcb0375f11be5b95c0b156159a1114302c46b1bffb00e45c0c6539c0e99cdf3cc3a5923b9a0df5db6e33fb912c6b20a0430d2ae7a53e8de4d037f8934c7385121eca6a93cf7bd23cc23b1f3465088029641faa6149560047ae64ba13971a796ea8ffd4002d1430ad4c1eec2f3cc9163f90877983fc0903bc221fe83d8cc38689f4eae760d3478576b7bcfb547f1ced853761e39f11bd11e9add0381a3bd6a3ea33053aa546d5f97ac0e7b2c32f478757555e6e624c0f70fce68e2dad77535bcae23fc3f762a90cf5700e56d1d635a89ad05de026f8c207b03c981fc63fda06e152085350e022cb8c42e868ca493204e020b8c724aef8ceb38bbcc96660cde181cf61861c5eaa2c143b0bcf7245f5568caad4d36a33674f19f06134d178f60cd3f09e5ac4bfb9056f88da9d5abc106552899c2763488fc1adb63ec8eb90359951d6c7912ed269b8113a1642e44904c01914eab8dc14cc04570822a84f29121418a26f5ab1306c9690706a8a75314f66ce9493022e770c11d21bf41b0f8e8b3902a2f71d8fc6438f9517af41316db982015c7d1e219a507d1e5011c17929b490239883d5c6e514a3ef1e58ed23a7fa2bdc3914568669307cfb47c3012e8019e16a6b4820bf8bd8b56a8eb8b500914540eb6054f68e2b52d1eaf1e71b7158d3c62810ad72b1183d202f8ec82e587ed981f9c2386d33a3a665bbac49f8962da749df751965add5bb28e25d5915fad5ff22402cd07d73bc5ee108bdbe05236721baa8337b7617cd4858f616490fa0db16b8c6ca1c9b9ebecb186b07b067478d521779e2d2f26491eaf9a33d9eb9e4f888ae3189c2cd3c11744b36ff91e613fe1ceff5dd10b421b8ccdf4bb079811ad26715bbaa0b7693194c6ca611c4c464ba3f58220ac9eaa8f8f2802a20cbcb415884b212d685dbdfba7d1745bc8263681752bf1319e4866b1dc6d9f59a3191eb89114dcbb81c7c7e789d6945dacb136e58d6cbc32eec9ce59dad6e78f2d3d4a160d165eae2bb3257c9d7646c0cc1cd30c50f2e1c4d41e20129e5dd93cfc3c536006e86ede04eaa6db2e24cb5bfc24634c8cd9b9dbd3a06f9d8ff9f08b2f428bd89b7b0d8080582de713103d110246c86e84ffa922b27ed9ead21b95087d45caea68f257fa982f10fe63c693772277ec09478803b9efe77a64865b448cd26e9427a5d4457b4537792ff2c6e07254fa4ae0b661db7f073b0097f4af43183c5964a1dfd7a76d26418484acab77da1377f56a53dd8c96a7ee82166070030721dc9eb7000ff47cdfda023c88051e196082c6314706a344314e59fa9ed5cf3661ba9f689c2ceb3738962b4d529e8d5e20ba148f97126055bdf6ce3f717db1d3d789f33588cabb349057833af6f91ccd85ae25a8f6c63430524a4c385a78124ec721d2474fe0097f1eb42821f3c9037b11115f3ca07c9f1f860e13e4ba5f0aac9a21cc0c6661580728eb44b2bc0357906ed5e3a1ad564831cf436be1283c8007182bf8b418abe743767a34fb782194be5de3ea4de736ad990f4fa5991e50efe181c480d08d7de955807d9025889888fd869e57f150bd9b5142ce518cdc410bb6c62acec3c35baf7472de195ca475be0873784326dc63fbbe7b8398230f9e107d189449b4aadefd3577010125ecc21b6ad78702ef84c2662d452c476fadccd6fb44dd399fa81ac844578376063aa366ed9497f000954c0deebe0641197709192a042ff698b243153af854b17a22fd500a82bb201488917e41b71bca16c9682af7607acce1a75a72a68c97caf40becd42fff2611a2778a95a3200c5fa39478fcf364d17334dca63d5ae760d81dcfa0f5c999f0e2484be1558b2703a32c629a386009e251a95af4cdc3a6eb02d35c2dd03668a85e8a5797025220c9bcf3c031efc2d7e4ee9ca03da7c1a5a6b3079243686c612245595f5ead531c3c3516aa8d6061c709c30aadbde023432de4ec2b76b313ba934b394781142e2bb915aeda9fc1c0dc1c8f3223446fb89817e60c0c267776e7301f4a0a0fa51e03ee391d50c54e2e43cd0efa82e17a960b19944d61b376c706fbe4b50b92358eee99cb6a82b0641567930810aa4842ef7a7e438f5e3ba294778f67198f42419fbe8c26151372f25ab00f85b670f080f5919d3b503f21484ca3363dc4bbcbee8b5ec7b3a9850c805f280f011e8f29dc1e68f4b002c24b3b3eb0bb38a3c8bff890465d240a4c001a015cd0412ac28fcb642f4784763056e4c8f5ba5bc8bda34e2c7fd9fa58cff62202d37e0ffcd71c5123227f13e27b6a03d7a74bb0ea96024fe042cdb8aeea33d7f540170bf44c7f50be10b01718da5a8a2b1389bfdea0d26bc51c08d8179488af16e1b36147340181581b63e9a50a267cca4a8b8fb8d0358fea1ba5bfc721deb51223c48c0312bb8b3f836eb7411d660296104d20b827a501a741c48a67ad8d50862f0e62958fa3757d2e79131b98f92e4ce123868a442e8d8c76f6ee0e6f127fa584d2e99630248b102257429e38272e463601a30602f62576405b97e9d8d9d99201435bba6a237b6baca52f1d26637100a5eb847db4f55b0c0767ebcdd727c0b1c9a2f5808a51dc92ce6b053a829f27482ce6c9f2ce969c8cb748a632628565d75ec6c15e816c5e8e27065ef3687342dd52bc8e9bd283ecbc738f7ffe96731b5b57d0c59fd364ef6dfcef89e85013821556d47cd0600f4ade602378d0dfdaa687a0ab3690f1884ef788c6d6f00cec61e5666674010dabb756f007fcf1f7abbc072766a17aad87e9b327da9db33deb40472c4ee41b8e89e557ba7e068b0e378e78a0154051adce22946220b927b9442be6e7ae93a398dce63c71c4f9543913bc53d2ed38d76d61da9c05fd7ad9c1bd828092afd68a0ddc1ce60994af18e543d3a1dfa8534a0ff54cb00fa9bccab58702e580173be834564e99f45d64b6690d15d76b6c184e3772415f21a5de32d970ae88de984d2107931688985348ca2000d51187ec6dac60407142f8db6a1b521a67b157602a16243acc20f1203099c88b0e2232580df70f7a1629fc385b353d76268c600ed326981e5b05c29e21084a9109f72c3c4120aa6821f7e395adf27c2fd829b62c50348fed84ddb62c757c275fd9a8f488957a5bdd47975f32f6626a5033b26fb74e8090faf216080ac18ed5e40b2c6c8a60d05c0d4b94693bc9c2c424014b274585dbde043bf2d2191ee640b7e206648213245dfdfa12b80f716cf8a78d148ccd4fe486677c7c58cd9b7ecd12b4987b614596d6e5a901685b8a5462db9983bf1108d536cffcb7212475e981459d38b61cd1734fed42b45e5e924392e3c8b6071b172271851e393421ab2916db94de067455c0382be39f02764d9e333ff8ef5074e0729dd2735f2ebb34e68aaf8b5d1d20319d08a4cef63f2ac51681d4f4a64902742a20c5c87b367ebe2ee6426a4b4ccc88d0d2ac8e701540b89c8ed97d5fefb4d97e0c5e93f69773a7c0152701146fcf7e64680496aa0210c24d58c2d1895f244a78b58239576e18f8036356af0cd2c36d153845d2f59a5f34e588b44502126fc437870f7436f72b15d2a199d6be336fef548bc528ca7d9a659094f3e4f3f8a2201b966b2af12e28cb4519fb733cb566b5b563d1a543b8c322ca0752567bc925272b9c829aa8f9bd206a5d15a6c3e18c807a38a2740812e06563fd7d2ebb5fefbf5a8f358fa2456301f93daeb52bdd3d59342cce5da9c1294173d23a1bf8cda80d96cd7f73d40e06e23b6f6dc97db28237635203747a31817910e940ea93e3d522d88052b14bb60e91ecd1921ad362e04165fbe4f716f49e46a7727456b45a8772f9724b728ceafc7d90c8daa49fe3ec9fc938eefcec9b8df7627eaebbbb95feb248f94a18cb6c8f1cef3744488b3fc1e15182f21ee0825bcf5f2ea3d15b180d75375811cde4f894f84b877f48ec83d87d8c884c8352f788e5ccf0003d96b3f07be5327687a9189efc5105c42f8912510c4c7d73feecc57ba7640bd9336b6294eff149c829fb44635c1e74e31d691032708c5c7d91b8be287022002ee86485dcc148c5eeb69f5fee6225f1a4c706df8719f02961031db4eea799ed96787a849a8fdc54320ae86c733d01f41179ccc15388cb3f08c8a407a0bae3a9919206b4b14a64644dfd2dd3dbec8a7fa0c3a0a62b02f6bdc9e5e5e9af68ee6451688846a15961d83de24d55c5a489f3e06c849fe88bf3991ea592bf491aa39584f4317ccffc5edfa415a2b3fd74d9e9a31ab220bf5528ca402519086a72098ec37c701f15b59e869d4f75fda7d89da761e853795d07aa513631bfdf7c44b021a4f1e78f0211fea64470d64e5e1e778249789bac9fb3fa951e19f3cc70a16571cd8092adbff17e562b5447e1767cfd22bede0ff8d3cd60c477559a3a7e0015408540591b268b6f36b9e3f3c76a51cb5be143f4b577829e229b05dac5ad71a2d2051ea8301fdbb4be2a9ee30bcfb7d0004949851e3a8afecb5d5cc01c70b8700c80ff183bb425fa523cae5c3a1aec8ceda0cdac4973f37d158da8435547f6d6d7bac2be30d6b479d1d4dbf807227865a3e45f02f9caeb051c42604addb6b40f877cc795f6b5b4ea2c3f49e9246d2b08d1c76c4dad7f4197a8a9a94d68aa01fb21aba901e52fdeea723fc8ee43b51b2c2358c5a7d9250044b578503f7bc1dcb0086946eb68a673159a39d6ea5654d74ed032932cd26156225cebba0966cc385bb594ac4271ba9003df73811ee2fde1af1725b2b542cffdcc31e3b4abff7fccd10698661c8c204147de04eacd3c3bcc8f3b8de5f612b98c92f0225a97e82d68bc964a54fc134285266c6daba38c2785ba92a0535a1231a6087bc69018872181f6ac92def6cc127e829aaefd99ea7d6ff175cf396184ce7f1d25c2793cbec4dbb55854924101b2ba2553ede9e6fd83ca134f96eaddda123971f559431bce4d2c794107a0ed675cde3768609e8eb72722bb6f81d4ad247d9fcf8a0474eb194951838a97522e25d92def61ef945d3247f3850699a216b5433c5d8920ff28cd6ebd40490629323d0b34bcf75a7acda8de9af8bd85559424fe8d476afe7757853708fb0786ff1c22c262773a599cf9e6ce352e58af51e32f35d1e111c05297e400467028b90736d3dc6f747bdf6359f02db71ae562ca4e7392c336b1e15382805989591d42cd7bbbcc35e286ee684fffa37b8a693747c39334ea3c0df5618f500012e90c5b82ddb732b03188d6a66befbaf788228bcc9bc6ea0380dd984c67314f7bff63420458cd7b3da463195ce6c2dec2e251fb9b796d0e89674ea20e0e63049c607961a65d0edb440aa68004fb804d0b70597b0e1c961793ed0c2cec865635aae534e2c197325cec05b8e71866ec4feb3b0ef4d7c36414997b80dc0db4e45f5ca29c940384a697bf534b235e7f8a4ecf14728d578c185eb294e7687ed667c16b0760439be350d9ee4f5ff9d0856a7e9bc478c1d3129426233c584566c14e38f0d8815018bbaf6d053dd45cbb779d4a73e570189c2dcdab92e69f76bcbea86dc6e92907c6f88001394f09045361bd5e509f5cefe021da32f0137ad42b6aa199bbf9742f47e261a5fa7020e29e470b12058f4331c7bf687e283827fb2a6e4ac115fbd5a95676692db9e4ae8e250c2ab9db1920f413e05c096b299bec7e81fafbff0fa6ab8b56209531545b66746d2792affb87cd42dc80c8a72ba90713af9d80c24b92d47552c71c6fa8262a2f44c0c02e0aad080231a514c6ace5f25e317dfb83aaeb7b654d799993a86d59be5701c945b5ddc78fbe45f6d1d0b57a9bcc4496fedfd38a63e8574f47afa6852f3ef66f7dcefb83c931aca5eac927ba65152089344f2408a1d1be006312031e16af83c90fcd35ab67a6fb8fc0ed1845138865d9941c531f9d7c4d56ec91a5d5760569ac168ccc8fecb292cf46c4a734fe828a1289cc40c5d2600ddac79bdaee83103836f149a5a1e44ec3a061dac42492fee1b661c1289f2afd4eddebb95ce57a4245f1175140489ca8fdab6380facf700d57654859b34f75cff573f37e03fad33685b5686bea4387e883b9df46950878dfc6e53e4254266a05606b792f1f7ea04aca021f2e9cf227da7555f698488a2157c23105ba9b2a25a6819db67a29b51f4c653e49d48f32d71ae29da6f6e4923e12688492c5480531035edd9629aa8051a5ba4c84264c6264add081b8a242a3e09e5183bf65094aa3228dfdffb1166611b574253ace9eae3a73cc66e79a2526d4c6eef833a67da48d7afeccc27e592976048cfe17f5eb3c01cdd89648b6be45094c3c262829128e7833cb2a03a544dee8f18f2538fde0ce20200304e9d0be6c4dff13a94e009f6dadf2fcc0aeb93a68b50e7468dfe5133cdfa9c5f9c279a1e4c2b580228e93858439e5157190d9726577757e9c8c1f7bd0952b91a49dec34deae6e783a407a32ac707406a2fd19b6ecddc3ca53948939e82bbaae1a3e12936a564724afd132a5064df4371d6e72badb85cd75c509740e2f224720f0491b70191c6f06f4830ced4475579a2f0a59fdcd9b6a5608cf1c5828ae89ef447b0791afd1b16368865f3c13b036a87d817691394044a572f7e20a807866be9070e7df82353906d621dcfb177601e639f98c8eee22fd3460e666c2079a68c46a3acc7fec0a6196d7ed972b98c01a8b7c3b9069ec5c0284a0ed17b8633a2268835e9344ef675149693596e0cd3c5fb041d92b7f595cacb4574b2195b33df05a6c897cb577d2ec08f91e527990489cae0e8438897dd98f4c0517556cdd8c16b09e8649e1d323b6d7b1b3761c65919ecded12d1fff38d4093b42ba7f78f2fc9a3e56620c7fb447636930d3cb6ca314c5ad386204d4d13b1d94e6689d610fbc37b6c1822943aa9e93f31e9821bb101487f2e4b29c45b893626b6fd8b5b00aee6819202eece26cfde95623740c815551ca8473032c4fc02995324831adaed0038ebec1ca6f0233ffac6e4e5650b19e984a497e8d7fa73225f1bf5510734f7856197494c57254c4a73ae77adb962878a68b4f8ce94db361c914ee1a72ee2a5beb2cb1d55b2f676db2902682d850198bab57c812763e3dbe9e8bf5f7ded2792531acbc845a113ff45046a985752a832d659a452763ef914c821fd70562443c5f78a0531ef7c415750bd7b7f356a23d7f16fa5e4f4aa614bd4436ca227c506e7965f3c1fb1137d3be60fa9aa8e3efcaecdbb0fcaaa8f8e0da50dd3709abb1c0f739bc4ce03859d248c4a98fe36ebd7a6b93ec28ddad644963ea25ce4e7742fec619c02a63c3f63176d312a3f72cb7e75d49e51fbe9dcc137e51e0c3d822c258f9912d9eac2b35eb58c992ca2a31f54ecbcac308dc16a4d2199299b207fbe729f00ac7a0cd936c03d945ef477ee67f26a69ac4d1227a6235cb50f74247a982d5921d7e3478a2e4f6413bf0ea2a0833caecba4ca14122cc214e8216bceb122ef388375f0176e7dc4316c69fb1ff65f2250884aafdfe8f85132a5dda05c5493b4ac785601faa977cc60c8e5e327207a42827ad033c39862ec3489644533715a2684d97e65636219c30b9c4ba264bb2346d611f903061ec1e2a2ef9067ab46f005883df3cece51e972da772fb56795b6cbec263f8b24987ecd3997a258fe9939e03185aa07e1a15a3e739d591b023818c87485aaf146c6bb885ff138c318df0ec3a720ec5651680723893f65c8b82d5c82e2df2dc1763b1e1376c31cbbadd7d488f0877119ea8312e316af55826476de1c8e80fc08a0d780e27e3b4b0a254408539551290e0edd066cecc880db1706871c7624392f26d4b675f483a5023432117185cc1080e379814a46196260b9d95b51ec96844ced708546a814b1322f7fc2d759409feb404674a891ae81ed5c94acba868d4e6af0a4e2e032c5b149d5b87e558e530889907e401477ffe6ba97110a9df5ecebd70413a86da7fa2dad3c87c270886f6112df50eb01faaa91074fb20a819f76f8705294130b5925cda5e31bc13b0ce12d16c0ebc1d2f92654bfc043e0748a5e141058decc53a2cd0bde618d98b861a84ff0b439e89e4c8e049ff658b2d143689021abd5f9942c404f4d8544c528bdd759c5d6e5b0ac3b9b00298a70e053a031f672086c07368f9244d343e11e640461c712c5e98819110c7ab0915381839c10e690a589a1b5974d94e873a32c43fcac82440d2bffe64b284db365655891cc21fc3ed71883495bed0e484211131acb66a6951024cba75a6baa8e706ed59bdabe9fd439166ad80608a164f57e6e76a2204561276105901e7f7822665922deb420577388ba1b0907378dfb601e58abaa3f3f5351e32a21821c8ef6d89215eabf025885b53799b0c9797b64ea1bf632986dd247c0157ca0149ad4a8c1cf54f1aef738f3ccd8666fcb77e2715af1650d2a8dbfa821f0bda1c699ccab11df848bc2725ffdad4afe904b563e24340b92d4b14c429cec963b11dcdc8ea5e12d8b0da4a514d1870255c1644a4e7c632e6cbe80ce067abc15e0d0f1c827f60bd95acbab6304a5e8f5218546292d490827da8d4417ca734e75d519268e4df092226893b8fdb3e948cd27cd449202fc750e89f5f52ec0f68ba23371866e12f163f4962591065e12fd148f792f333d5272b7a987625a2b32f722a813880a1c7d7bb374578b531130db5b49891276907774cac400cb2b3989984f71ca0d523762656b6ab832a2e827a930ba761506a1d9900701114c52154e1c1dbc6aed5848f721b8658e106c76b8fa83e5928411370480f60be97b4b780355c08c1808f0bd4db5479fd5db91229b2c197471c68e71357f3e30bb33cfb2c1a0de2bb0ae8991e376db13a88df042406e315d4a22020b27c4b0a17b8589a091060f9b066f1e74b6bbbcce0b3bfd50399e8a38d95694c9c93a56d753e861a7a78c61dcfcbc0c9ef731bb8a0bba35bc5fd662828e5b5a979b6e57f5ce5dcdb550099fcd0f03535d1860f08f722413068bbf22dc07c2bc7e0a877a97c551bd26962a858a12bb7ce31a89bbb109624e32e65894736da21ffcc2791be1cd0ee7909a9440c2e2a94f983c3bc9194155a32bcb476d40816b3d0d801013602abe83521940ddb16a59d5237c43ceb81cb22e0e87db10f71b78e048375d091cf623a7a34f0d2d07d0f8e792953ad78b31560aa3c9ce53d15adb07b232d92dc7920f8179280640596a9e0d33970b039d2df6e8a6f10a5f971523cc9da3c8c909e1da330717f63baf38fa2127e8fd457bbb17bcbfe50a1f91489f866dc1b9d5ffb4307a6168201206c822989142a8cb4d2230ac75ec76f94937106926bfed6fa327ffc70689e07b97b3cb38a02d721c113030c392e2661a4e9dfa83496e9f3eccf741dc5dfa6e34bedf8e5170bbb802e4211c0f32c9ff270554512c906154019d5e56d286ac70cbdcd0e8990bf5ab6630bd1aeb666efaac1d29d1e555213d682bcbe7526e485c593249153b2b16843413a0e386b7bc4961b87b04019c6cf76443535b202a93b0e1d403118c7432f7efe260f451f4f6bafb6e6d6cf7598dc7678f453f68573de9405e996ee053a19336249712557a0bad6abd46682a666bea0bbb897f13f87827e07e91c0fb8914f2d82a1dc82a6fc948d62372b13fb0e5d9192b213095f3b1e09d97a647d903a7ef7548fc899898c69b6e29d4e8251b4b95a0454681d15c5d09a572099e48bdb8ebed7bc0f7b7df5ac185d1b61e04a1468eac78b9ee8f7c1a0b74ebf0d3a879251d9acec16ab4e247c69478953668acaf2ddbb9d8bb761417254d2f79a4670c4b0d1c9d1309978bcabbc438011322ea9b4e857e8661e0a13314abad57bff52f9bb58a1584a80f46e45cafb4aa300d3001f96e3e92b716e82e7c71590cbed53b2fd0600d19984d76e9e5101d2acf540336efe4047d2befe8c3e5d08caab6aef025604d72107a53329430214d303b2501703a18dce17a910bacf750e6a6a6a24f34cd62b128edb148ff212463d2f8fe0e77556f048008bddd0b2e5281b492603ce5e78c4f092d807d4b01c092acdef9718ac9d39175f4ca80e822090902ef95ad8c981c24f6cfd12154dcb88b41a0489c263a13eaf9d0a906fa1d1da5166584c9bd5008b036d9715e31473afa86a7b8edcc1ce7d6d19cfbab258596d988170dbec28f5c599d3bff54c473c36f950b2b2477d6b9e6d5d7432816526e9d53ae7f7c9522c2fbf018aac446602e1ff2f8940e32f361cba746ea84f599d96d8d3ae35e1aa244c1e596454c78c326bcf7a2d7d83872a3f7709ecb8daee1499dd64d2e2c1c56b379a28fb844ee53e6250211d20a3a853a1ab41a6e09da5761e1d92269d6ba8411c7634dccad9f040c4184079ac22a6e44a78e59661569a36535289a70f56e1caf1260ad81418815dd06dcf43e5071a93cbed4599b6f9b0ab1cb20004e3baae89091cd41e46141e3f7b8eec7796d3fb752505c2bdf9bfde0537e36eb24b13224bd3b0ffa0944146bec20f5588ff8894c702bff5f1ec34be1c4fc04750e1c17ff9d81268084db67682f720e3e04bc8cb869c2201923520f71dd44b8acbce21ef4b899054a7df40b6823623c0b2a0bd5ea84c6d0ccd6fde2dcdb32e1550c97c83ccecd7b622df3fbbad02b57e36398663b62f90a71abf06cbe3f336993b61c2015fa77cc806b0577dc27ba8f7f5dfc7208b8dec49f7fcfcc3d6206007ba6c6b53190b5f5d6b3dc93011d07f39f97248d2d49f3c20f480a8e70ebaead861aadfd451c5624ec66ba0c47c58d3204dd6d0c8315169121517e85b09505da58202d37c0b747312598424f060ed24bd82d3f8555355b7789aa0387b33a498b058c362146cff3544866c4150f21daeba8b6444c6497b30576f5e2c4741ec4fb1177e496dec37c87ac5c089f649f810322e7c766aceac5d5171b07e6d83369f84f23ab60c5d9af90fc1a8c44928678f3781a6f3c1819f410c14a1ec15d8f796bd8437f6f5f1c305773a5fa50fd060ca28647dd4ce08fbc1c187449513e07e5110be92fe2ca48d5b29ec3d165c1d2b55c0a1d90fe83091a6f136dfa32f56d6b16839458ec1a1dc4e11bb81d86c72464ed5f7bd55eb17610cd82216018c5c0bdae7944cf3b9b7f39a4ef12a95374e549d1e3997976443e80cdcd125416d72002fdca307871246569febf7912c7832666b62c08c67249b1c00280f55fec403fa01b3261ce9b1cb1f1c5bbb36885209704823af89e1a2993ad36439edfeebe2ae2e113ecac4094f1ac55f75e5018e1035343262e9c1ae99764e8c2b7922befd283904bf542a334294dfeae0316decdd445381a99f759127c69cc101c15bec5bf636a2be2db723fc86ca6960834f85e41ac962855b81a03c9424d45a66e184f6c0e04bc81b3440a8d2e438cd34de595ec657a46cb01fe07be7621df82bb2bc002f94bdc2a73a5056ac1d9c82eb7cf3e7aebed0906e2edb881fa833ea504033cc8918db0800e99fd672bbfa2a647c0ae90206b172cda3cfda27aa9a49e15166d3febc7903e9614a753ce184cbca426673af847fc87b4e591223ee5bcc74d0cc3eb92a44290e8498291e8aff2c181d25f926b9bdd575200ef0478ec94176801948ecd0aee48e4438e2182717537c0d935974fcbcbc7090a29d30a44e777f035fead86720964f6012e74f54bb7cd3832dbab7ae34376926e4c7e943303b778236c0666efc4b36983134b45af3a01419af44c0aa33b690e5727a36f1a65400464466e6234178455de875b8ba44993005b5ab4bec8c0b83c630dff3871467bfd0355c6b68fea8b38c5a6a89684e345c902bdab00f8544d9ebba7e8e9c8eaa0dc78f06a0dfe9fed50188d1f368adbc2cec3601270a79430e1d50a20fee725a707bab01160272e70e47b4eb3fb24f0e6a8d74a722a3c778b0a53331dd97d7a3b718bb476bc2fcc130a1399a30d3e815d794f8da62c59d49f07eebe3c1b9ae0acf50738cee1bd3744fb5352e23e11317b3beca2f49e4f11d65f2a1a0fcc909217a8436956f0b7fdb48a021dda6919109d3083bfc4ed83a53412040808d962423ff830d50d0302023d5134b05e0763f69f3b8f1ef34013deb00ef44c7e6901ddaf377609dedce29c8ba130eae21875ac1cd035cfc6105a6e292dca098a2810274c2a4e62b01ded3783020c3e2b210ebeec1271f0a6f0167aae11b899622dde23de668d784e7bd73e461fe0dc27d66fe74454cfe0487078ec621d8a3c669b204a68717858afaf084070fb3f8a91910eb119a1e34fd94067626a0e04b9d029b709b19ba554a685a3401afed8599af124c7fcd07a4de50ad6491395c7ebb3d88fe25eaf1743de166e989fc48cb40116ea16a2224a0f3bc781d92d1e50b1257c17c51f8e0e94c48e55882b725448b5c065a0ac3a406ad65aaf21841c9849319e6947be96ba533bb48e0cf3243a1e3dfea8f59ca829205e068e8eebb0d3ab291ea8e3cf4866c6e0fc7d3a1490f538e22b94a71f3e84fc8d680d5c3f131546e9b04e03ebd4b12775b987d936fae51103e25dc643ccf1e2d51eb21c04136e2ea50a041ea0e4aed7bb037e438bcdee0d01b488c1a771470ea1d585206f9fc897a50321600650397dc863e04760bc2b81873a0a483f9db4f8af538539c744805428326eef1345543d7aa1f87e8c9eec0e2e88861a79824e5fddbbb735adffa323b84a77d4d89fc7e3fc6ddc44395507742984127a205c612bf64230f715a640daeb38c5e2c10b83e0b67ba48063d91aeea29e3a0b3e54cd3480bce32488c9c9e96f7388ef64fca07b10fbcc64bac263cb5b243b7ad1df2344d644e3b8834a90ed7b3afc0470a9e89ceeebf41fd943e07e6f84f5a728cef09fd81cc0dce8b87ad8ff4d563187675a890e4470a23f6f575a5646ff93fb4e126507900dea2b5551b0896c9537356a7fecb18b87180c6f7aebc40140f6e81e3fafbb29c0581abb38132aff792f791c7f0ae6a5835cdae36afa8bb6927f523dedf25c3be409c9c29ab64b6cd4677f60e12260f327c657488caca5c05adf5c0f34bc546b17917e81b4df5dd4efc600e764bdf481ab180ccb9be8672b83e58409e1edf1f97620e4129970928f621974f6fb4a22e9314fd566a627d1751f825e096bc4d0fc7d346d4338f285271850efd4501f94600ae28dff496649a1e2c881b6822d6df7bb92eeb94eff88d69f5a29da6907b1708dbeef2a756b5b24ded74e57051f24b616f5cca667e5e13edd0f81703bd9b6957282db27d474a39db3885f151e742f1800172ff8bff78c9d94aed3b4664e71d18e720e7cb16d638b8cd4ee2d7d8d21b01eee3ea5da3b098af304e8b4155932e9fb05f34f0273b3de7b050065f1eb2bed938b67d651416cf145c6e027641815f5f83e22f92aabae23bfd8b7f9eb5ef4eb75d518f4e5660425cf2b20a3d8922dcdb351b04145bf5074e2d9652545d22d1eb9f5f310ac40b6f6f8cf9e8b44034f0eea3378c6ae97db72d6769690f848914878c01041fd9de4ee4f9e44b40e643dc0667ae557c1f8ee5226f4645b50b946e1d3a764f5f3649ebf6144bfa185756f0d95814518d2b45f598b5d3b0716733181cb11121816b08c5ca457dbcabc22c73136fb5af4a59a8b1016c9ed7500d296b3ebc194f3eb09a2aaaa6acfc1de88de0d6b21e130072c10714b4dba78b0d47a157f73ba36d57c1eb124a4528c9b736da9ee6d2bf26f6e18763f55c46d51ce7879cbeaaae1ee1555bb911aee03530e4840f2428b9902df6460a48451bb27c044aee30453693473ce887165b3332aa6b081f5f2a6ea583590e54a0709d6bf51e03dfdbe112046877ba61b6ee2f3e64e6a4833da6de84924d78d6fae1dde28e094ea9146c5661a2e12872481225c9be7f0821f3bbbffcbb4e5da7e691c41aeee38b34cbb5a53c6869abe246b9a8c7eead149dfaf89eac588a265b7d942cfcdc596d132870c87831c61aca5a54424add061689c4101b31667956a890967590ebc845c7e4dd485b0d747792ecc655c43e7ef4c6d7c1df9557947614b9409fa4fdbc6f6e90f8c532ca44248ce096602d9b9178ca1fbe107cd99c64afb2b722bc92737779f4b611a974c34ef4b09859ed173ad6b9ef54528b3fbff208fa50785491b2f4c8f00d468b08e12051b22ccebedcfe8a589f491dd567580e2ed55c16c43b485e04297d1ca2a134a0b4b2d6f5903e53efcad9176487c174d000515800cc52e1ba21daf582413d46621682a1124d97ec422e57f9ab5b56b6a2989a748d28ec1e20cc3c1d2e0b90acf41622c8c056b00071d3d41f11bc46b1e195a2b6cdb3d03d65def58ece01adfba01900807326d10aa97cbe0d389e8ed7cb0e096d8780f38f8731adde9a3aa4094aed13786f5d3e680b0b1f6378af7b5343343dd40c433d7a17be6550544d489019bdf2b3deaeebe5deb03fbab73679f249f59dd86a5b549ed9d571002bd73ed5d595b5e2736adb8a9f0201d2f7811b5d2a50ec716009d23a2b6b2bfdfd469c440c18a03e4c4973dcf5cd9363e335d910cf6e6f9aec9c6619559d57efafb8a83b10c303b8f19007775d3d677574d1695bf6ba5a6075bd401abd596dca75a2698c6d51d31bd16178f992c67a3ce6ef77b22e3ffff37f8c136282dca20f831d0aef6ee7d11f428c52ef150e4133fa85087bc007a7dfbcf7f074465ab3ae09b8674ae2febc394a383c71abe861e9508c7a63a213a3e1380a836cab8d0a55ab39286c420a3179e3306bb51c36549434e64dc3d982220cd90d4fa54245cacfed3c4c2c2c68f540570a7f9ddd8574f8b1ab6cb008a9311aac7ecc180935d05ec75909499128fe275b6930686307ece252b968f525f8551cb4d137977934f883a48904771d8f31f440ab553c93012eac86534bb0014f34b2d2c025b51282d2bcae4ec314084b510fbec3b221cc1e3c2e86f202ac3af2fb7569fc4096b70151d1d14600f8337ba3332581f033e801b47a7a4f531202e2f6b08d2875b85f2209f6bcebcf7017993c48aa49585907e24509aef45f4307f97585093601e4e0f8a066ea025561383b592c7e10d628b002c2b12f7f8f659df63ce1d2386ea1fcef6cffbde3d229af70e72efa39ec36f670107c95c7cb2582301ebdc28d5c1d58b40fbf848f469a10531375ef8c10d563ce68812b02910d8e30869712c7aac47e578c5c3337c73e85be024ee29e10cd557ad399156b1d297d9c80076c2fbcb01f1019d975bbec8f2068c6038888547d67e2174636883252349c0a3bee33e14cae0fad9a90874ea2a75a457daf63415200611664b2cc87b7c48e95a6502e1c25a2b8d89403f3630f6eeed8063e5ab1e894f793e1eb8fd1b8d2650275d1c711595c894f76adc1d7ac6a45b6117be04465943112a0085e48abe919bf1df062b3bdd4968c3ebc0da4815cda8f731175b725ff56ce500b266643dcdc2b6a5bde2fce5882b1000e2d738b0e093ad7377d4bf6712a658abc831b32c99de653843abfafd313650656a66b76daff865d4f2f381a1178067e2040ac1ec39d119b7ae95310860f581d2d5db3fd03bd99569b298fe893213cc19cff571afa89fb9eb8d7c5378850de2499c0dd74cf591bfc79a822fbff243d9e713ec865abf1f9548f80f9119707d52746af87ed51d9862d1516fc3116127166693bd421f931baf6ead4399766963a775a83bcfce31de5bf769eb5d6f0860620d4d30b662362f4c1c2ab54510ed5b5136026413f0a5a737cddbfc1bf41c40505a79db25de36fb12b2fd584bca3e5b03eb7319415b1c3399a5afbe23472e287cfd3756feda624e0e601274648076ca1c392dd381a957ffc39c9a2363b91f0a228ac9393db86e86bc3878c37c855dfe6462c607346f96959b40ba2820a8c98fe1af51bda538b75ab3811e23797bb79d4ce0c630347376aa189c7023024861bb02fa20167995a47e7185d998f63fb0d453d15c75a11cde803287ab242cf557256f9907e752dec64029cee1bfefd4b0231b65bf9c1dea53ca53feee8582f6f1eef0eafa672af8f828f4c6e113f7b11397372a9ccea9f2562ac110f2ee31a09874fb49313b7c5aa45131ccdac02752a8f6fb2fe0f42c97aba40afd68b45f7c6ef0a29901278d8e781b24e9b4696bffe7f29ca205188118d42e5896a53a16bb0f5f868d370fe4981cdcf17af489bd98efbe4d8f2d072d4be0537af061604d03d49892a17f17f0436c86767138f5ac8c7f65b2a982ad5ceba0b88326cc9e22f27dc4794f75c9fc1dc40c81a6fc841b5a5759955952e7c6979c3aa291cb4fe258cb68cee98e754e868456aacd4790ac0db399367b7cdcf50d05b1b58d99393b458fee04ab02b6e2bae6196ef41ef7ca50fab9257d5d2226e8f862acc2ee41c437d28a10d792d7dd51d323dbfba1a9746f52af09b9679e7794093943bc10b5867fa178009c63d9c76228f9d39d1f33c13a3221c867553f3de94ea1e257039f7d9f79294180b01a0ca119b53488dd97e8db07c28b51245e36f8529af15985dda5cd4a1b6a45af243b2262f4ecdb4fac8084c75afdc9f12e5dacf3de7181f553eef3cd6e962406cd09e8586f784c38c87222b0deb0074c54b86c712f504b7ff1c264d93dbb00463b0e600b7e488d66e34356d284c9a0a5de2028650ac21e97b9b89cfaca51d4f74d1b5ed8ae2dd2d3ab99748a16612a6d5c5e39e741a9cc922f5519616f6541e9c968fe60a7dedeb03f820e0ff05a72d74e0b96042d2c8fcacdd70648189ce320924ece1f8a9a8217c34e7dd6ee695a091e043bc13dba19e2f9dac85b11af1f069cea1daedc8efa19c27c95ef20ca132f50498b52ef4c851502bdb8b453e90802bbfc77b215b02c21ba88d8fa7700c50241fcaa7ea48e50ca31b7b1ed56325d1db59a5fb44918d803d3c5f9fe607ba51bb6a3c4420977c0884bbf830aec47f205fa0cb3732795148fbe2e2712227c97f50693932c5c27cc839a5aa027d711b3060281847ce578cfa87ecd64af82f32be58bfc50ef0c904d74b08d239dab314327a3978e041bf1515e82bcb83c0192174ba57e46f4ad19e99f12b418f8f547cf54e24a09aa0b1f9466b2a908c374e7ae5dcbb4e63f174e6a9bb9fe5e7032a108a0d2a3d3b85126cd58eb00a7b6be18bb8b2453391e06e39f7b0c632ca946f8a4842f4fc18ff3dc2f2c7309d588e56c743524e57246d87d42ac2f7dbcc05f0ea326597c7eab1e48c55e384e4b469393a2d90ec1c9d23a9868811251ec449dc55ed1422dfe8798903ec55a42898cb2c2a8b2548e82c2b9faa8999976680d5a802203d83375bfb482d319818a4c6ebdaa74dbeee2df1eec60fa9a6469ad8355fea0d1e7b2e7d06aef9cdb8365aa076e4500cc82d64efdbe40fd53143605eec4448e0f571058c86ad20100f9b3ca3ea3eac441f6277b7aa44737603283ccf433e37c5d599f6773c3079970e630e2dd22ab019e476cffc54a95bda793d273424534a9440f003532ffd80b13f2cbd737b326dda4a9b54d08d95bee1d6b0f5e0f780e615b1b863d817cd266cca152d2a96aa164249e929692383d31372757e50e9d2856cc35eaba9bbe56b14511927e1b914aae972e60ca151fe9962cad9c2894bd438443c032770af6e050d6eb5173c5dd0d5bfcba3b563c7aaf5e07cb63d83dbfba6b94c26fd908cb93933b4d841c044e10658b1804596104453788328611901085d31008babf5a84e908390cc34fc231cc9d4369402d68820533b0704a810b9a34b1200b1f30218919b82006a00d0d3e87d270a8c116431da8011754d8745451451526784107a6c0248733e0cf943895c3d228f5b0a50b29801254b4822650010a4b58c20c424005143570e205cd3994160127c80009464f10d2e24aad93e0842e9c3c6551a50456d4fa17fbb6bf29a80c429a27d883ca209c97b693e08f1e29aa90bfb76e212b4b2e96689059b96f847beab26f55794f79b5755a8c215c7daa5ec11f35a78e03478b49b2ea54f583e614b62d8e47f228411d80a44052128527b690e28322d4525775c7d457af208fd45bee435346306fb94454d968e83518acd3168f4059f51d2d1fbd6cedabdc71b53ef66c757bfb29775c6edf72e7754b0f5e9d898430d52365a568edeaf42fd7e54e8963ffba2d71ec5db74a1c6badb5bd7a833f6c5ee19c16e98f6a063e954a5910c77ea86eafc22a6c0155cea157e5d478e4bb558a296b8d745a461f438bf4334bf86a917ec49129fd70d803d1ef4e2f63318e16a9d79fdd8d67700e8c1e470eb5a11b08bb5048ca3c93bf3ab5c4276dbeb067df94dd2b7aa5146563a37a9f961782ad2b1bcf8930a76731f46c9d56c5d05c2c21e9085948820e9ed4e66194865305174ba07882c20a65d4e6ec1ff4a0361c876366898dbafb34b6360c61bf2889332f2fcd525229294ad2e65128164bda2c6d4ed3276d4698a6dcffe69c734e1e9bb9f4c2a4cd1c5c5ac93b7a72df46769169c8520736b3bf1d72a79fd3f2f14696af8794f5af6868b98c09696939506db55aad3ed2c8b57a8d5ca75e84ab6b8990ec11954d21716eb68adcb724983274ebabaf7092d6816a9648eec8f02db7257eb216b6b490ab9829ad65f5d68dd2c2db03a6960e73454c45930706c906499c2390884062b5be9770bac2173b793afc99e3e5c3c2f4c9338370032f727f2ed940e2f4398ebb85dc841203a30218a4b92433b96e2907304893a762182222a2c903535404c354b35a5171b34173452767832c930edb9943b44c26ed051f12a7ff8254fab12371a03383c4e943b9cd963c0851a9540a95e718fdaab790fb5ceaeecc3293d26e06157aa0041545b0e1a0d6e701098c600327829024a444addfb7febc44e0bc5083d2e18248838d29c21b51763324b3beba349d1855d775ddb9fb340f42d427949086bd57ab573dcffb3ceff3bc96951652ebe816d6ebc89dfeee7c51e9b418e108f3c4a85313da43f1eea30d8241a233d36098e68f1c4138c228794f3d85ad8761926098aef8e00514014aa98a1620f6300f544ee11084a30dbad9a7a6ace01f4eb55789a0a8c0d447445353535313c6797ad3fbbcc9d4b37a054beb8b56532b8c9e757779086bd9749aa8c53954369bc4e3b09981bde3b88eeb3a8eeb38aed5a2a19ab76710d27f34543d463886f6033344ea5b4fd1581c350954504585128e62b629299a3cd60332477f28db25451dd4e2903c31114d84ab5729c2ce33c806d528c2791c3deb0c53032967305fdec07c10f373a86772e79b386c27f5496873db72250a59594a580339f3c2974b87478b5d304c5726c7711c27aae6b431c60dd504234cb9a09a2157a108479dd10615116518264a8351a24a4c3048120841158b1725b9e315218f158b7c453632737d221c6194ecc7b964933dac4292381d0482708429b281a9d2a20d9d2d962da26c17f5cd096aca0a8e79a0320a734772a78bacc0acfa964e93ce6cd269d2d111a94e8e8e7dd7d9ee66a353391b1d1d1d1d1d1d175a72877e34cca5251a74c2dc5994ed3a510c80d2cca124e660c9769ded3a4b25db9b25529a3c304c3a3438b5260cd3e49964d0608d309b88085b4ead0dc3160ce6fa43516cc192ca6eb7db9cb7287355745bdde493959ed52a3deb190d2f067557e151278f2d108f39796cd94671bca5638843b4798b5cad5cadad560b061d30e8504d3042950d923bab5c3f10b6f48c9321f75bd69f991225cf4ce9285d94411e4e84a30dca73de25b164b953cf05c027d75402a8e1c753f10081c05e2d1aadeaea4ab1c1cb9cfd689bb81244e11f3673aa55dfa638729f73a9e8c6bd8b5a3ce2b89ef373be8fac0d6d9094f5bba2be75f2a7c3329c2b0e4f261c2d5a691146a96d61ad61965a34214afeb2e4c20a0ff268955ce4ac4b502471fa56b99a2ba743c39475188669e6e8cf261a266d8a412985619a3c210c5318b6885a54b46c72a7c108bf3cb66c6084311e5e9e4765b065933bab892d07c2712eb59cb4405093a85c8d41b5aa94564a6dd09cf574d24aa73d6adaca0a60b55addaecd5ec82d1bad42434fc2b1656b6a6da07275cea65c1bc9d5bab246b90829c7f552f70ed5eb7251b2dc6aa1d1eaac6b875aee50585b611b3404abadeeba4c6c6d75bb0149c3aa09b983c43ccf943b1cade546ac4fd759600f17f2c446aeb3eeeab2ce24a7b6faeb75ad07a40cd66683a86ce85a222abb81008adcaf4d842d5fbd655b0acad38adcc12171ba90339c25ee76ae4c84948656a86d1316092532477f355a0fe4b61fc87dbb012983d8446c128eb36987ce12a1114ab3422deb3711daa096d1a6951621b443422d062505f56c0a0df54c56235c9e67814080f2c444542dd25f99c2948ff45b4e5ad66fd986c2d106ad2e115466836cd06bad2d5b5b69f98aae7ec2509c477012a7656b7940e2b4a69039e46c39d15589d09669c7e94c9e0e8b9ca8234613a5b5528ee366586bb55d67bbce16d9a1a029863879e61232476ba085dc6f2122034cc25bcb36976eb75bceedd637fbb1a37476d5b2ad6e2ddb949e8d7329f7ac3b8ad233ae673487ca6690b559227bab2f1eaa6a8be44e92dcc1194649e996a768a26930482debc32039c930452ea092821598404aeed19620f73f1e2a3a7910d65b4869c7711dc7b55a2d1eaac983b01611f55015a19e9a28050325e4389825982a6084b1f999633cbadcb995c71d372be1289f6094e48ef7e9e3fb7e7cdf00becf86ef03f27d377c1f01be0f87ef83498299d2621f46a967a8f761aac81d982b5ac8198c0f6060946098a6088d54a6296098729f8824b3e9161aa979ec1b13a57551cbfa3058644fba325adda76f94b6c2304853e44e1289b3023933428a7d0e061391043d0c949e590c43d4b30e27e981ca44b428148eed7d7e35d81f8f47d783f3517fd0cc0de0b341e58103f8bc331f354d88895893c25d488a3d937b3f30474d9362df8729ea3a2170e60925e4fef950f9f051a56f72a79b51907a0a2afa8adc6f2992876ba52410043f15087e5781201e813e90876cf167ca21ecec22141287c01e496ec448e771823d3280271812677522ac0d43d8932d1cfb3679649e7defefbbea3b0bfcf98e907a7f3a812179a4cc91c2466693dcb172c73b0a85c7b0a50952b66c12a75b4e5a442d282d796c8540e6b04136c806d9265656c806515adf56371bd42d5b2ba945a56795b66c4ab7a5a34c572b9ce4881a4c93aaa70ce6a429140a758a6938f11c9a93abde94355993b591060e6d15bf8ae7508ba107240e513b31c5db13b96b5148aba5ab22330b99528fe33cc97d3eedd3def496660f72bfd669148ef3ca6d125199076c5584e3c44265761fe7136809c2eea6d24a1e41c484127ea1a4f37de0cfbc5648164cf60ac9c2caa744850a95fc8142b250aa18357b207766cf2a0a754f65d356ab573dceab3d44e007da3b27869e7557125b67a9c58b7426752d95c1d0e911714410f388499b9e53ce164d79f24c25c81c5308120a390b16891384a21095c789050ba54d9b0d4b4b9e362a55aacc398564c19445952caab428b3902caa5461a2d30abd42b260aa5484748962215930a166e02441c8dd86a94599ab5099debc902ca8f46c52b152a569d3d6b256ea9664c7948515a52ca86441258ba469cb426962215950913b730e654a049bcd668332b1a0b04cdb1c32cea13c87e6afaab66c9e62a71a117cd266f45e9ecbe5f25c2ed7abd65a5fb76b495cafdcc7b9bca0aacbe582f90baaba5c2e17afebbcae0b29ed87a62c73badcaec1dc594319bdee7afdc575174ee2ba0b5ea9264542bafe4396d9f4b95ac9a576a7b490c2bae7b85aa967d6f3ace7b98c5c7fb9dcd80b2779dd05d303d55a5661d7a5dea5509de7e170e6a0216de6602e519948653998b417aaca75bbd66395bb8e48e2f40bf389ccd19f4da4e041a7aa5d57bbaee7d4a16bb27b7bb57ab5765dd7553abbead5ae1bd2f11167978f61def1fa088b79bd5e1f696479dce1593f5025c11ea9a698f79703d55c37561fde9959b95b402229eb83ab5527e455af1097cbe5250b2255cb7ff8c096b1835a0a233373e14ae5bab2f6fa9aaaacfd3e4e1573b9bc5abd5a29a54a61f78faac2aeabc89daa85a4757761b404511bcd1fa8ac6b7406a148444522715acf7a5eadb513296d918a1dacd6ea59afce5e3e18555d1d955dbc560bfc59fd43ddcedf8beae5be56f769973b6b3017e6ae2be4f217b083b9495cf641a618be257cad8294a1ef7259ad7f9f8c6a82e0e7edac0bcc4b07f3020373180ccc5f6e4c08ec2f87bdc0ccea3f14aaaba8d7a35cff813fb53beaaa9a41f0678e221197fa17a3eaa8777b676edd7166619c57c89dea25a0a7f250959bb3d6baf2260fad972eaf7731920657cfd06bae8f3459ba3ed278904e6866994def195d0ab19c39eacb953557e7ae76ddacb9ee90adb95c770651d990c46932c5e640ee8fafcc34ef5c22f6e272a0dae7725f37f612c45f3726e4e5afbfe01c2a6b172ca96ce21cbae6ba0b07218290ce8a2518c5249a3c1d947b62e91498603609fad6449ed775dd41f0a75bfd5057e0ed67387f90324b876b28d4dda44c8bc38961547892329905f014246532e7489e8ed64a2d3a72775733475340cafa6454e10722224a54bdda433d1b5799a79b514a8389394db9678ef98fa6464551f97565ed06e9a19f6bcd3d806ed9dacf0bdebbab87f9823fdc5daeeb5429b4e7012a2571adde577ae6bd065d4c88ebe5ae03d55e37e68293b8fc75a0da0abc2f772edd97c3e0b98463dd6796bbdc981098bb1c064f261cebfe82a71395c9621dcea16b2e77c1b389ca642db3d02cc2a69f9408c25166f9a10859f58f86cae51999b779eb5f57d6e8c4446a2bf552cbba6930c5ae5684632bf9e0049906e128445131ea51d875f65ee759ef0757964ea43458cbe6cfc995c7a4c309e4e95154bca3310460471d826403d37823c728b5a21c32a7e0be6591fb7585e507deae798165ca1a9db5a3375a458777cc1cddd51d58764c9e4965937663eec87dae8394481c39db03b2974c59575507c91d2ad48492308cc11e43c7e42c007248389d9ea6d3132b8600ec6831784c61149516abf44c7228a51671b4d897d9a2a8a0a8f4ccc3a8282d2af52c858d6894862222421d115927a22c7d7084254f6c000a4c388941ad8f1aa2341c49c4800a50ac18e94004b5be75b24f9e5038338ddfb8046f9899c69bc8ff0c637884b20b2b64c938b2ecc20a54b2159e32be8c15a2d830730d9a472180f2cb696c646ee3e26bcf6e2e0241dfba0daeb74eafeba336d473b22f173bbd2d2cc4ccb1cbdc3a07440c17f92189e4d679cc3c7699391c66f04824738fe1d6633c344ecfc8f437637451852fba980296faef9be08f99732e1c5aa742ccec7ae5ca62bdfe635deeae3b73fec1ba34f6238665d3cfdc31f61be7402032779d037dcc2c73fafafff338900056450930b30ceb2edc9222646122af5f8238c89c622064eec240dc9cdea76397c88b8589bcb2cd2b1e89bc2868038d1f37b8b668831f738a471b58b628beb6287237bcdcf0729abfdcf1884cc33dd3d07c82378cacd71e72eb16bc81669a09de307267d1fc82472332cd636ec11b3ad39cdec09d855b788cf9119a692e411e343ed61a7804ca34b8c66328f8a3738dd35b43e6158f5fccad9f61cceb6d4911c61c99991ea9995ee50985311b667ef9cc2fe7f0cd278efda071ee34648090394ee140e358ca1cf3d038fe276908651755b092f165eec2235076bd75c7576e9d75472299c55dd962e5689f99c1a378d6631c1e69deba0f6ddd1b675d7bf18e445ef9e53477dd21667e79833f3abffc7839c6a3cc5f5a9385836c71e421b74cdde5d32ff88e327ff9f772c7ce339f047bcce071e6998baf9775d76dfde5e56bf087ebadb3eed3dc59989bb932bfdccedc1d69ee5dbc40c8fc3ef617f087abbe5abcc136f9e6b1c7301032a77173471a4ce4956530fe8dfb50d50db1986f3c75479d7c23dff86a06e59f63191279e52166a6719f067fb8641a47dd946d4978ef38f33d775344f7f5c6bf1b37e50489708cd1a53c4e2b313a8526298d295b4ed9a8784ac291da3adf57be1728d7cf6ebcf38d1b974da3b696f56fdca0d306003cb18284cce1980d315b652966b1e4216a06c28641e3ca7ce3d6ec2d099d2809477b435275454751a6a83c9967ce7d2c95046de04ecfba407035b35aaf13e4d162e191fb1033b35e73d685d5ef93493296149b31164ce16249b1582cf6852aeef5aacbbdaa4ec11fce87b68093053387eaaaab52799e3773bbc7543095cb55b5085a9bb211718516286551842e94f08305e0a08a183c41f941d313bca0f08e610e227353d56521645d4e257a1e8b41cd4693a8127716a698b3f636ab10c67ed0980ddc6b8cbec628e65133cd36a416a748214c113969b19691b24df007cdc21999853aea5c10b9bec382bdd11bbdd12b84b245d6a90f655d7bea04457b6e927904273c0189f623a410cc5841538d86a5586be98dd2a4454ad95250687037e5a4452faed0228b104451c60a327002253499a04916a22bc440d23a29e502c973612077b0dc71495d497591d20247e66ce4cc8811d95b70e13acebdca19ceb95b39bb71ee2a39b371eea19cbd70ee2f39cb31cb39f7193983e1dc2f670098e138774a6ff4964a3a231c53492a4a4464072db2487d9bd4b7377bd4b3d763f8b8a3bee5a3ca8c10f69a1fc99dbfabd0201a837e72a2329efb915a414f909b46a11405e1686f35d748919985dcfad75eea40425746f0440972f0021520219b30032b5b3c61cb4151184aabef2e17b645f62625ec4bce7597a5b776425d59c1e076ea2714d31076883053dc65d8181e61a853a872425d4131c1cc601485254461415d4131a198929292929266e8ba30355e83c60f0d9f9e5c8dcf1a35eed3388e6440419779b81dd9027f66df0cbb8c165b86fb74d8f216f823c3531df813c363921c7b3fd97cd4816194d5c48831e71e368d76ee30b933033bf72a775ae7cec99d9b73ef260feb1c1e89ecc8f534eeba63cdaea72ea33a511ba5a56c3558e6e5e53678a4916f483073f4c56b8bec914dd1a091c7940caec16348833bcf603b45e2dcac109efb289bba8c8b7aaa42081b51aedb727a47bb82239d391aeff7130d2c43da51ee1df7efa562a132ea8ac469a79630357a566b65c2d294a556540b27037e0a47d411aa0cd94e768a3d6aa776429232a924c92a51ba2959629d05fea09c5e3766c38d73e73010dc6f5ce6186ecc061b362e33caa9e56a51aef5da72b95c2d897a42958172ea4631552963d725262c4dd2fb3fca81acbf62b855b270911eacdb40338b56b0e2c85c1629934e36e8290c9232998128199232994539abc791ebed76b24e948662b24ef606f38cafcca83ca2922073130a0b8a09c5c47a0b8779a43698fa7bf1a51287bbcbad36ee3346c7e199256b3f75192827541967f44ca867238a08f5940a4231a586a0a0986844444a9c943c2d095a32d4ea30ea274bc2596e71461300b8d72173e12db8806d60c8c9f1828d1bd74a911ee75629d2e3b8528a99e5c295b9852b330579d8c8787c06f60a55acccc24592e4faa644ddc4c27154e0905ae0f404269c904216a0122831050b2170c22d0b4aecadc5b647dd14c25b2aa9be351e915d77dddafa6658679ed97569ae4d5994d225484b9296282d59ea30a6b7c4ba2a25bc2521b04ecf6539033382903fd66c6d61c6195b985106ebde58adda6a3dd5baccf5b4750b0201caadfb740bc7e0242765eb190bdba29413da3b95d4342c5b763383a89f4097b6b002155ae7ac8a037bdcde6ae714d2283c1a0ae1489f2077b89025d372bdb38ceb564c89b8d605292ba39c6c4d44738b2d6909211ced8d8b6206454a68a9a4e6411eeb7c128ea92498eb6338535383a9a49264a6c1a39dc1a38de131c4b6a49e51e959e55a5aceb550a49eb584b745b115c1feba5fe7148e16a972282ca82b36149314c211c58485ab078100f1e86ca9489ce670ac7e662e7338f663ac99bb2a739888aaca162e78120220e4e008482451a20227243d81c45311a4112d95744b25b9c0b87c823f30df71650f5cf001a55a509633c8920b1b95fcc91ef7377fe714d6f827bb3242b945118e32534d5d411dc99d8a5357240ea65a489c3eeda29a504c3d9b791f75a56735efa3b0f48ce67dd417a8265418ad566b167b7dcded19ebf534b7b65831d3cc8d5dd41554ebe2d0ba2c3ccecca243284685d162b330aa09d39204d1640280fb9704b3280bf5451442d7c77662722aa3674f29a614d3f5384a398ec5a23423da7d282dc6baccf82d4a69abf5164e59613db59485a59c9325175920ca32e72e10b5c5975720648b2f3f42e5375531d6639fb923509e79833f33add3f7689d1e2873774c9239d6a5615da04c8367939923f6458edd87ce5cf1b11b73a45fe8b9cbdc1128cb5c823f312e57cbe5aae3119955736576d59ce36a28e5326b488b1c77d69599885cb91aa05c59b888976beed3b5e63e4d5d67d55c823faed75c0a25b5d4625fbc292b3258b6e8aa719f4e55e91910d4499516957a068411ed29a5165beed0b075a2b21b1f69d8f808b3b1a911dad0a041c3023af9af208f9bdf9b3beae49bdb1ba5b948d9cdfbd689d268bf790b8ff6e6376e6ee392d26ecebac996dd9cbb2f897373738aadd3cd2b76ca7d1f7a735d7ee38e34f2686fb71a3795347277f9efe823c34ec3e512e4d1b9834238a6926077b158ae8e8c907597bdc1dc972dae8045366d218426b293ae4442c98507ace49d2cb9f0802d73d1812fb8e8c015d6b5a8e2c9498b2a90b4a8e2284f284d93b576b2929798042d25f1648f7ac6ba4e663de6ae7f1fc803e62fef9c42ee3e94bba3cd23119d6c019dec7aebf49f4a35c11e307f197532f7981e2d3ceae4d6650ebb52e2c43ec6f0a27d74d1f948b3f3d146cdc790c6f3d172af786cdde53cb7c51d1b99bbcee54ebb1c4ee63e1343e61ea3c11c1e5b231de915b9656ecc1db9bbceba40c0fce516fc71c132e430119d0c8343abc8064e64eef6e8e5302c14f8e322a2935fb2045fb03d6ab12dabe6ee09291ba5a19ca8ac9f72e25e57e61d3af636a6926c510d3e4f51c943c0b2a48a325230042894dc8041962ba290820a9aac00e54469d4669d8c68d4465d98b630c535a49d8553495c8b639d7685a45016ebd4f6819065596f0181006516fdc1c2409cf8984908975a98f5d65d44973a615d7a534aa95136e5ce09e1686f497936a66c19e594671e5323aa8cdc4fd9b819b09411e5949d7ac601093a9232896493a44c661b9020252993200e34736f5007da756838a683ac05a1b27e0fa1062350620c32aca8bde05493355a2a89d274b00c1884da9a106a614494a516464334b2d4a2680699da3c20773823da1bb4c1cb94562911cd087562338522f72908648eee2c31b5b5d88d113e4b2eb2f09447d9447bc8da98108698da28b52d21fcbefa486d39858550823f6a0dc216fc438bf3e08da1c579d53d3206ca769368c6c0511ac6ec1642b905168a88e4165880e2044aa647948a11a664e899041fdc58210c7267ced0e18842d19a290a8542a1f068b1ea1d0ec34c61b04c3fc510c6ddc2dc2e1f41978f2df985ee38ff2e7f4a4be170e1f23e94d6c2e57d04a14328ede6f23dfc10041194a6bafc0c9a4394667359e3f29388d2f0e5e76d1e4da49994e3f27369324d2c3397b14b99cb984bd8e57be8e5127519d2e092239437684225cb1b0c65c9634beecba62c6fb08417b9e52f5c82b3c890f0ae0f417df51fa3169804872489993927e732b01c31afff70393ec1202f231af531580cf715576f9099960afcfdc5b701c361c046dc1bffa9363ec120378c6e6a18a135bfaafa96cde935326fa488911dc2b37ac86cf4ddc89024e25f1e7e4812d9618e9acfc9b9f716ae117a2166365264486c079ad7bc061b219ee6b286f321b11d6aaee33ab0113518fe1304e7130c0283d10b305c97e7dc9877170e54fb28cd6bfe4d7007f134a74364afb90487bc0c81790d8ed1a70e548bd1b30e54f36e101cff725c9abf6ecdacbd6256395fe5b8b11d5eb0bf70ece56a158d161aff725c1b38b6438edbb80d6cc49f03c77668e978eb756fe0d80eafe7780e6cc4fd0bc77650fdf597eae6ce9a047f8cc0dbb8397e7365edc67ddddca7bf1c17e79dcbf7c29db5972c95f314ce8dede0f217fe023642bc0b8eedc03242c759aa178c3e30c80b475dc74d220586e73cc911afe7380c39f88817962dc3d851f27c8ef0e191d1eb2f5c9c1b52d93c8eebc2d5915d1f54362fde9b3bc4c6fdc1e6ce1a77da26d1bdf3771ecd799a3b7367d39d59a86c5ee64e272a9b8fb9f389cae661b7616e0f51d9fccb6d176c6f8c73e189a5b61ebe8567508c3eb64378d6c3b3b04865f3e10cd282e712ea2b3c99828038081511544671900fc77640fdf32d0079dd42824fda4818adc33da5394ca57195dc484a5848597fb45972b691969ac9a99fe88d224d4a9928968a54b1d4244a93b226bba9b334d252bd55a26aab4335e8960a08aa7891852d787045ad6fd0410a9060d2c1192ca042addf48fd4e429238434042f298086b136d0e08df0c4f7d53c57d5fea16e62e3297f90e8b396cf5f05b5dfb960bce5bfb983142fb0abfbaaedb3bf6902df896fbb4b561181b00d078840b8500ca2c8c84465ee11e72cbc39175aee582afb7e0b1c8f3103299f5964f1087f02bbc3a78c767f02008e2980b0f0028b3f0ea2d5f5dfbd71d59977675f0746557e36a858f70d4c6dcbee58e2b7c8493391873f92306d71665f0eb2d1e3f5c5b84b5bc7e8237b4e0716698bb5c8237c0dc05e68e4764979683ffc0ebf28f53d9ebb23ac8b9dcb67c7510c6e5f59ccb6dcb57211eeb8fd0ecf2b1b698c2235076c1a9d7141e67b6a98316bc7d3d789405adedc2587de6d55bb0ea0dfe48bde5f32da9960b44eadecafbbce7dd3105ce7bde53e11d7bc82108e2914606dff2178d9a1a1a9a9999584c462626060683817979717179bd5cae568bc50ac39696d50a0455aaef4ba550a8173cda0cfe75976b738b97c1cb7ce4720b8c0c1ebb0c1ef6982b250e0c8f5d6eb94bcb250c1e6b6eb9cb5f6ecde05fdcec75b0f5f02d7f5d29c5163c7ef2e1e5de5afd3b6bb5fa046d985fddc33e0d4e700040ab151e675e85a72d6fb90f5dddce2d77fcde815fddce52f5f159056220529f1f3f7c84cb29ec5d8679fcd8439645bc2c64210b4df948fde19263e62b88d23967534a29a54d7b40ff165b9c728af3f38a36628b3de210e99c611fd6b7397d863c4c5e5a2524d47fb529f87a91d256af2d3772398e16ec62c11be35637c6e15802c0afbe83cb5bbec3ea21360274b9ac7dc491ebbfd59552667fb8acaeacd557eb72656dd543fd0ff541ea875410c7522e9f4c333fd007e186e40e4f76793de52a101fe7820ca1b49ad77112cda10f5623f3d5d75bae1fc55c5fc55c2df6d95183b4583f44488b4c45a20d77090659d9205476136d68eeea35e1656ecbcc33b1bbfc7599cf5c59dbb1176292535b7d28acd1faf253f20c01cb131b0931096bf4f3237db5ac3ea434a1a19c1a3d93b0b67abd3707bfc005eadf54f5d2789a1b7bcd753905ed67ac4b0edced815e1d98ecccf7991bc442113f6cc374c92485906b105411d47bc8cc3d89701a89a57090984b10212198bf2ef472997f54b57aae2de47a593fb5086dec331fe2729adb203577b946f4c1c7ae11b1bbbc869a4b333399088158eca33e76a5a0ee728da0d766e9f2d785b8fc45ef728b85bc2e8393f4ea2e17fcebba5ce6be72a05f5d08fdea282ca40f9ee66f66eeeaf05aad3cd55d5eebacfc8ab9aac3aeeb30acbbdcf0afdbd2b23a58875059fdaa257c0a4265556cb1bed649df7701d97e31a2f4f556d2ecad614b06a26f6d18d67b94a323919c9c1cb61944725c4ce08313e450e923adc8e6b0510d2de6743938b098638219cec3e6a5ad5ce883562ea83a85f52a1e7a4631106cc471785e944ebd03267b57792a11e627b9d393e97de48e9729b541a61ea553086308423f84de87dec7ab45eba38627844099b3a74a3895d9fa29515986f2ca679b29b5f8128706c99deddb7b39996b91be38a6a22ff60303656993ab6cacb2565ee7152621f4d1337920f212d6a2947ff691cf91d791bfbcc844494003a3b63d4d5b4dcda09aeafeb52a022dce1f5a363f41201168713e48a627326deec6b01329edcb69b941805775ef9893eb3fef12f90109a1d7230297b2fad49532084ae3f15c2408ca438bf395f372fad80239996219c6bc381fcec36ca8e6787084cb94d6fbe3414141b377a0827d0606fb6760b0993f6c5145c74b6e06d5e009272b64e4d8295b486125698ca42397294fe98412f6ac4a9e1ac6964ea8692e4859f3f05044f3e4aea16555c6161e26cf9436485a0e29ebcb2a994a22e41e35f4287e9c6a0b7994e4a961e6689b6b983c3e63e77a9fc953c3e481953c0af678652b71e618b9b94fb0c73c2277a6b4eff71001eb7928cf4b79dee7792acf033d6fe5792d9ef71944c1ee53c9bb192777e63d3c4ea1dc606e30a7af4ae234aa2945f4491b6ee61f9da73752dd287c6d31ec9b80f9fe0e611fc446ccf73c957dc3da85f5ca9a94b5ced1b93871ec7b4cc8fc95087528e5c92db20689dea3b38970b49943cab3462f52da3d8581c55c59a321739d54f454466760e32bd3b748c52954bbeb5a4657bbae4e1dbee1ef5d9de6ba4ee3b62e5413b3dfa1affa0ef3e07f65adc1fa8faae412be35bfb7e5134cfd1f0e52d3f2ee34ae1133074f738d902264e6e08d885df56f82a81445d1a756796e11cafa09fe1829528fc23d64f62e2f83d4d4b45c825d912042b0c33c663fa4affa9079f02d37564f53dff2f02d1712bee5f52dabd3e02433f3e0574f12b33887beea42a6eae1816adfcc1ec8c582842b5953c92cd3b1fe729f7691b9acc7dc97c3aecb61eeebaaeb3a785b3908855ffd5b852dd78bdee5854559414e65540aadaeba50cb41792aa332fa15a54c8494c200a1daa5834fda8c9ccc5355eb955446ab12a10ffaee22ed3a9edc1dd61462e93ad94926617f0cc3de407fca1d8ffbb81a5fc229eb3e76d9cbb5675689fcd179670abcac592ce47b128f82b12029d525689fa4febbc5425257e12460eac6bcc36adf8d79b86bd0bba112f9a32aefa694c85f55799ccabb367f9db7f26e2b913f7bbd7f134c80ea1f8ea112003e86c242bea7701229a8276949ad9ee26c9819751d642d0c12dedece764db9bb0df25d0759fb70fd97c246d0a7bc1c5e487d8885d04b2ae37287c2def5ba6f75bbb7dceee09554a9e54a5548651d97c44da9ff2e843e75ef9f673f6e8aac7148dd3bd52d771f77e36ed2a6c340701e50ed2f049f544048df920ba226f268739d7d467af464413845cea42f2411954fcf395fcf49f9399ba850d0a20aa18c93a516454d3ab2dce28c23647beb19ec7d7bf47d1fbd369f91e5952cb970e2084aaaa94918d6ec9c761a4e42fbce816a639875ce731e9c2416839ace816a232cf78d9d9ba4e73b68e01128d398e00f77c35322747911a810a2d2548333bca8618b1a5ca185119278e203f572339fb94f7baa098a7804cae22bf85359ac732c168b357365e62a9de1b85c6bcdb5ced43bc3e25817fc11dfd1c89c6bb1f0f8ec7a5bd769feb96e4ac9f53195e47aeb52e231ccad11965bad73e04f2b5567ae8fadd3e014959452cd2ddc617c4464d7290d75e2a271e11128674a5b2cd6b94bcfbad43673701df8437137512788a04ea8134a5b54e6d6e5ceba319999149594528be29394787a3aa94d16c58b7a728228cbb2e4c20363e44f7c0c8f3b72cc4663b1c75cc6fe12cbb1b3625e64625e645a2c168ed940cf7a0f7a56abc5a269d1d8dc756f6e582ccaa2a134766b6c286373b323c35e03fb0f0bdb32765c8fcd1128bbeacc515f670ed6632d3c1ec92d7a16115576a59c84ad4fd69c42187beb632a299522ea59ac2fab9d3c33f6d6bfd84d11a59cc462f7e91ccbe391fc7a47d558dffa0479d41411558ee114511821edeed416b64e349ce70dee30c377dea0109df3e0242e3aa8e9bc4121b4efe0243d5dd89c6ab41f568f9873d896a1e32d11d2cbd02ecf75eecec77369dfb93a6ff08697bb1eb3a102d1fa0c5db17a3aa57563d54691a410a6945254e83b8fa924eaa4c51d68b8ce25b8c30ca7e1247389075770aad12e41213bd7c1495a78426de71214c2f324530b255060aaf1dca725eba9a430266530b551272cae5622483995f4199a8a2909c231651bad53eed3f09d21339c47e7ee5c8209a09d0727a13b60e256a3ed5c9d53f087f56ff69474d5fa3873bf75592ceec6c77ac79a55b42b6b3a343ec3a53bb8c2832a41351aae640a0aaa7d13fc31a29d46c30da9ac3fc33d95a5925255326cb44ed6a96715a7a8d8327ac6a56cb694cd072e60c19522145c210756c0420928ca30d241154330420c87c7578ebdc34238525bbd79778530f6d86bc44e736332a7f9cc2e372673978bffb8eb1a0a3f1bee86da6c6efe4dd0e57af95dd7868d5495a59e397149f06706fcf924eb3d5a2ceeb6eecb25c8bdb85e5da8325a6c314525e6c228a7165be61af921e2d85dfe43731f1abb374e7365b6b9a3455d4131b548a7dca763ee48e485727aa2345415a69ec9fc1db5d8236a8a12e188aa82b282aa825ae21ec617614cc9598e724c965d64e18e6a11bd75a678668a8972fd77d6e958333efd18738a5b9771cdfce5e3cd6962e2bd94171f8f568c6199d3bbc4bbfe72658baef1e5f4a924eaba8da41a49aed859b799c147b83c43735b528437f848e7998f9fc83acd1bec01447dcd331808171e678e7de60827d30a418831cdc7187ca4b3eb3478ec30b81cc340b83ef3c38581a8e7f20ceb051fe92c730ae2c0e5eaa2d4899983dea75bb73bbdaad77dda4915ea2465abb4b6aaabd63ace5c5dae225475672e41dbe469bd5227ada36a8c21c5e3112ed38f1d468bc32d7aebbb89da2abd7504aab53ae9f0386766ae3ab5cdcca83ef30afecc6019d22a59f54f82387cd975c7995ddc972ba64e74ca466934aaf3d6ce0eae8147ab832595d5b80d95d99c06ffac7bf37b73161e6d328ae9f5f42d17be0f4d25d978833d6297f9bd33a3985ab8e298146f03d7c036f8ab2d639d7591f518d65f2e733d90c7cd59bf97b931548b9731a87b9f56fde27757bc3717bf9b7a26b3ead489c923b3ea923ac9bfc7249cf9c73f77e7b465eefe33b49fa1f8abae7a0cb51173991aaff1f2fb1b9bdfb0de3a8b759b31bee858d7757a471e32655116a52c1c9b790b8f311c6267b5cee131f390b9c7defda039378343eb2c1c62779d452b8ecde01f31173ef7cabaf434f8e5c5b2aeeb93f562635f5e6c6c6cf24b0d9b6c737c9b1a3117efcd8d1873994bf08698cb3c464646c6938991b9784f4694b90d196ce362db38bd36623e51145fff7d4c58c73562aec2b11f3ff7c7c45c85c3277843ccaf523d2676d71d6d78c8adca7d869ba1b98c0c9e99c1232cd79997179acbd0ccbc72a5a1b179eb33333777e1b76e779b3b12b1c9acdf3c7687f8d136fc07eb2a3cc69cf5160e9d1be4c1c2e3e4aeebf5ba3ad73bde3c86d6591cb669612062fe8f3798884d8ec1aae3fbd02f863bcaa58cdfdd91878cdf027f446bf3fff5b3ee6893594f11f5ac561a4939eafa98247378641dffc34984b5454f33335ad77d1aa5d433171e93645a730ba3a8fcd6538c52625d31af7e747ecd58f6cc2be3cb5665fcdab414beec19fdc15886d3969328ada2a8d4918714d32bb594590120a8a94dc2515a610222ad3025f9c11f237eb047fd44dabf1b4e40f924ba3b9a825ad633d46243c13bb05059233993d7769cd132f40e272a6b2478c7d3ec3d1fe011c2e68408caade80869c718fd1d58bee8d98e3076641112645a8194652e51824444c10d054528384201929426294b3a3a3a3a3a3a3a3a33cc30c3cea71548e2c530dc033426da151a13101f3a96966080012789b644b3421b9a39e9d0a143870e1d3a740000000088e13a96742ce95892e13849384a384b3856709870aee060c1f902a709270b0e0e721fc706325ce34b684d453ead2d421ba3082d4b5e729fbeb63c99b834a7a68dd12211c639a238519a8673d4331e49d4e0b304078e25356c38379c221c4d389670707070707070705e78e1851c176fe24dbce5bc86ad0611a5d5a851a3468d1a356ad4a022f76b4cd1420df007c93f1790fc43726ffecd1bf286122477a435e1b001fed0c268b16959a692fbf44743d5813c9bd0c2a065699910cda965688944084896881f6dbe117f531334b4c4d6a851032be123994c2693c964b2165a68c185d704d504d504b980c46d6c401dea7cf24fa6949c80d3e43e2db18400ab3890a714570a9287e036f9a2c67c8284d1d06bb7a2a32848539294a8c8fd9e2990dc1d585abcd2a21c9ac20aed803d355982e689e68c9e599a9b8d8d8d8d8d8d8d8d0d1b366e1cf6642dec090b0ea1db007fec6d803d6afe709eb2bd431cc9a71293e8eeb8d2b21d5fb4b8a309cc7309dec1b48369a41d61a710949edd7a8e7aa2f420f54cd1404f4fcf0972bfc78a1d67344d48ca10489e86b831e4b89c604eb024d8edffffffde8bef727239b99c8e7ca4353511c593a18b041317875824e61945cbc00a222ba05871b3e2e8088bdc01529ac9c9c933333333333333343434359f45479f0b4c647b6d6e9c0b262044408272e4c831313131313131323232b1f7606a7211fc994b34195330b480c42a795b3b95f8f454f2dd504da22b93c893896b34a38802d3c26882694d53843db69ecd257a369bf40c09115632033ec19e48300b1218b4b2b4c66839b59e8ee40ed0ebf57abd5eaf978b8bcbcbc12ce01398c55e06fecc25489060a3219ffe44a13c85aee511da26274b2c13d8048601dec021168bc562b158ac56abe5ba6dca0fc3278423ed03009470dcc124694d3ddb71a569130a1692a25ae2a290c873c9ed81d262cf8dcaec133d362a7be23842b887c8225915582c248f1048728708239ea4080d6480d2261413ec91ca7389b7a5473d3b62662791a7b45aad56abd56ad5d2d212ca40d28ec023c489e89911597a9684e6442b83f62481fec49763490b44443956c80590071da24374e88524c67eca19278a111089a049044b44881021428408112215a840056e9a5c54b6c02708b280000629f96b214a2735a9d25190a8ac7fd4e2909213e46f66022a6212134a493625fbc30f4fa290024a08443082dc07bad1c90404126732796232816232219a4c3c2071261327244e33f9c064e26432219a4c8826935b951ba5097c9c4a4c24dd6892c536d4012708400002108000042000810844200212f86442c9874f26374a9b44b69e1de1a467f648ee1011a5674620f52cc9949e1591d4330d50e95906942693a5c9e40456d0ac8872e3682a196232641ff00033c030c308661cc18c30cc4082196298910433b21431842288504411cc682a22084508a1082f8af8a288a6229accc832c50692033e4ea43c95d8042131c91da0a4052c60010b58c00216b000063080010df85432d4c38bc852049622be28a2a908a722ca28e2a98833920425114a3294c466461472bf0832748ea0d8104d8189a80826cb030f6458418609c838011951c89042060ac8b8820ca422252852451123328e8a4c51840445a8285254e4a8c811194845356e0af8386f432c61244f451015117480031ce0000738c0010e3064c810047c08a604bc0852915b91a2224745928a5029a254a44a91a522568a3015c142060c72bf880b6630b2b7c7498b3d472df644693189ca7a94a80c4a135148d1636bb1a5c03d4854b64411220943bf27a96748a8346d467104a5cd27412e8378413368c3326d4b3b9eb0f46ca220a96d5ec8d944010c6ef9c9b6949bf60429a3250105309033da11a48882a49ed19a5a7c02cd09b426d0c6a03181b6049a1268596849d8f144693b98284d0c1a126861d08e4033020d0c5a93dc994bbe63c753a695419b42eed39c3e6b7730ed709b77f868c520430c28881185dc372246196248418c29e4fe0ca242ee033d511f9a20717c7082c4f1e1096238e55e727d50820f4bf081093e8c61349413f4e41830828d86a612f643dc21c23c042c5b6c349f601f9cba6e35959ce80ed9da24fa3755473cb93e381189f134950849994e2e123c6d0620629330f40ff2a8c94004d114c4520e39e490430e39e490830e3ae8508013213a7221f7e189d27cc8e2c3183e384d2068024213189a40133d2be2fd09d87aa681f727e0a46719787f02449436a1787f02374a9b4f240189dc9f8012c92344cf92cfc09fd9040992b9e412fc41729fbe123c83241859669325486e076e924fdb2de24557488a0632f0b56a527127d12709ee7cf2398511179a2010e2f37685a4143922281ff10e5c231df84ce288fb70e4830d0810204080000102e4861b6eb80c01ee802cd6ce50943f1d54f010a480271e8690a0e1a4a3ba03821c20e4802107d8286d1201f9f0e1c3870f1f3e7cfcf8f1e303b8029e3e00a86693968114bb065c48595f4182dc2aa0413505d1dda189cafa76c90e58a8ac9f3cc13d4e5a48ca5c7226af49994b184d22bc438f8dd284a44c26f0913e6e8283984aae002c0af842014d0ac8a200270594d13323bc8842ee2b800c05102920e8e7e7e7e7e7e7e787070f1e9f4a6e8fcf25b74f20c5be42b60aa40cfd1db0e0f030c4e1a3bde2a60229eb5fcc33825bd18d8a2c7207a856abd56ab55a4d000210c0547251b986eb70f405408afcd5886430906247815b0652d66f81009e5c5153cd24ee270027f9e3a1b237039f4cdcc981cf28ee14c127d19d4f7c2ab91af85ce2ce26fe0128a0f86c728da47ec4e6b9814f2897c96b52ec27933b8443a081cf115ca119c5e7937f93e8f640217b46c0816b3404ab0931794d0a133f02cb48869ec4a54c259f1bb84d3e95e023b03c97984ba692f78c40ee08f17e8f087a42d00345ee1879bf470ab93399bcdf1385dc19e2fd9e2772672af17e0f91dc9942eff740217790bcdff384dce90181dc9943eff738913b3389f77b3e2077e612eff73821776693f77b3cd0632b9a441f7baac8fd9e5bd330897e6bb3896ba4d68490154a9820f7873841ee4f265172df8894dc3f820628a0c115b92f045227716b2518bab52a98b8352389d347726970945bc9ad4d21716a2468726b54dc5a914a887bc4351acaa94d298e816b34a4539b52dcc86482a5f81442f2a9041224d8684a816b4792062b90346841eed7b09032f4bb55ea5d9e44b77624050d9072a770ed16c595c24392e70cf2a8c93c9e244ebfc751cf8e78bf47941e4894369fbcdf2389d226d1fb3d94e40e11eff7a8d23323deefb1d4b324eff7b0d2b3222ec447c9450d72bfc70c248f10eff3c8c28349eecc202448902041820409922186f868f38e21be0303ef79ed76815b7b818fe1054e83db1243495cdc279062ffb3413589aeac09117d2aa1e435a43c93f8479542db4ce2f638f594d1b2b1c78681c33c75fb48e2f4a792db57c89e44b75d41b46131301a725a56a0ea7b21e5420b28ebc93af186ab346ca03d65cecac887aecc53c9957932b932cf105c599b4934c953e81acd279f485ca349f4b904cad112251f694c28784a81a3c041742ec1415349076520a63c7fc4952d5a274f88888c485284063200c5134b97080c0c81e448917717c2081e8378f72257e620aecc17b816004196dcaf00912888721f883b7eac58d89a6013b8a3e8c36462cb7d09dcf1118000134ab9ff803bc21c7047b10733b0e47e03ee78062c40c950eef370479802ee289271fb90034c810966803b8a528c2cd7218731886038dcb15b90fb04b823ec06206064c97d1bc0201a8f858f3b561bf0f8f90196dcafe1f2e028f70570c78a456d8ee096fbf91aa13e778405e08ed50a1a641741b9df73c763c173c76a033b838e1548b94fdbc194fbb33b8a32e0248d3000e8d0b194fb30e4d4b0c15ec0116fb98f6384b520ab09ca7db1e786d694fb37ee08b301833de9e4b1e7ba5c4eb9c71edb68eb9399597494fbb13bbe62516d9047c905d3d832c87d185750eebf802ff069ac56e4d1daa62779a447f4a8c796fbaa3bc2f228bd78a2c16d0ea140e905343fd0330633e09e70441c141c110785c4e9cbcbcfa7458ec3767ade9116f35c80a449171a9b1c4488dc110b9083949426b3c9e34c86c9e13893bdd0aa6c8b1ef8638466be5a5badf53cef67e2a091b4cfc81d6ea6c730cb6ea6e5ce120f9ab9b678f2d07950f20c60e6983c0498397a66dfcdd9b536c8f1983c03b8c116b969f55412675e0e60f280920093a7678ef99e2d79de6066c9e45d52ef56ee74f66ec11f0f485a256607644391fb5d734c70032d4d99eb543170617058284d14bd8f5c166e8c6c3d2fe57d9d67adb529d50ce9bbae9bdc39ee8b16b9a72c1746e6ee7160c81cdcbf8e4b3535f52c8ca609f166113c95bda8a7ae903b84bb01640eeeddf77136fbfcd873ff217980f8c80117997b0d72c79e0b5f216755b6a7056285fb0c926708db23797ce60e397e798c21733c99bb0e776f730e36138430352477b0c81def1cd7629338dcbb291c534d9449e27041ae9021930701320777ce8bcc7d9434c81c27f6ac3bf745cbb8731de6b0b4c89dc3d2d2d4f5ca0aa6ec7d86ddfd31811176b9f322941c1524169206977befa2744872e7bb2271baa4ec5dca1917852e4af65cf0e70329f3ee7d43c81ee794bd30b2778b472e0bd9fbfc985af4de0921ec3eca2cdd92fc028a4de866ef1d949ec95bd382b467a9ccbb87f2d1a2f75427d4b490764dc81da3a1732b088d5c6eb9a57024a293b9b77c94597e5adee00ddc2718a14b965fe1d1475e5d75479dacfa376f337fdff72e08e128b3d0fc3acd2f8ee807b9f3bad77ae8ea96248e4dfe70ea49e26009475965823faa96bbae91d9baac6b648677ac58e4d525a293270f3d03efbd879eb5dc7b047a36df75e00ff809651473cb5b7509fefb52aa4f25672aa5e3d96a8faa525a69abf7092594b7b332bb2bf9eb76207378ff3aee6362ead995a611699977efde2c027857ff2e91209e90bd5740e6f0deadf00f2d7a07af10baa52c462f4b94f6823d9b83f46cdebb01248f77040c913b2a4f02217b172277be7b36e760333055abe6a7faf25743cf52f7fe43f20c616f903c9cd304c241c19338c8de7d4c90072aa7fea56e4e0c39dc157104214c3dc99d25b983ba473d9985297b475d9a45e2783f5c222d7a47dd20248e5744e6f0ee3d0a50c81e472471bc7bdfd134977bd7e999bd7797db5969996771b7d4a2f7f9b15b0a9956ed7241ea26557684d525aa83ccc1907a621493c4e99ed59ed5874153369dbf6559e36b91b95195e2ce62a6ca7dabca55d2e80394689c95a294751714141474abd92cff4d5a9bfb3c6c4e25285a9cb1d4822721226ae68bd0f790797e5e1e3de7a511779f162716674bc2f99bcd0d9b396d6ce6b499b36d6ed8d0db48b1a178a4d406cfb40883d10331f16d60184c75e3dec6471b366ca0d9c6c6c6868d8d046df068f31564a0c0a0ffac97e9187393e9c7eb4919bd9cb5674f3bc159bb0e06b3b6bb475aa4e72e112dd20ea2454ac4112c84a328f69b9e11d22c83a0346b432122a5ff3a8ee33814376d94d6436a42c9b4071e86b4482916e87df49f7bb0921604953bf5948a31641a84b56108cb1e364a4ddb0f75de521da841962936283fbc8411ce3c2f3fc11b669e5eaa7ea8d48b14c7a920764ad588080200007314002028100c0884a201894cd12349fb14800c86aa5a70549aa8510ea71452c620628088000000080824690800a0172abc01d4f13fcd2e40017622956a06762131a3ace2fe18e493294cd23a047d84a6a9c788fd62a3165423bdedef2182ec1b29ee5aacdc15d93ddb12f9b860b489c1884c32e1ede0a140dc42e9a326d317653c555c0a1c16c1a99a5e611d433515e9efe5a184e92c8653e72ba2be26aa0ada6f998430933f39483e53d569823c4ce01a80a0c63bc9cef0ab43dc3e29e359111a3727a2bb47d5e55940af2aaa0535dc35c51daa2d19bd2df5759c2f661ca84b99cf4a77c25f1d72fb6999e76ad8cbb7b14cc0fab6e6e6de06c5bbedce05a870d25593fa14765bc2c2a1e614b4996dabfb9e1a9324af8cb739aaf09329787d99640010cf2c89cdf5ffa2128548023c43c39d40a658cb01dcfa8facf0ce6c9c3c6bbe35f0afff705c71944b72a69f19c1aeb98d4c5c327a1fdae26ae96805c9918321216d14f06d065f064414c0c5d12807e4f0b9732b4350e7cc4d57ac3c62c5a67ecac68510fe3324e6b8c1dfef134203094ad0f56811cbafd9d41e97443fba82bfacf537f05761db250459f0f2850869fa8632d09283e8dd066089c1a6c78516688bcacda1fa76beeb1e4610d9b1880a9d1365ad90ccd82fcf402177f3195c53d24392a8aab07dec33467da78da6eade77483194b523c7d445210b8b3b3725e2350ece590ae6ddb4e627a90676fa2dd4e2a7ac0a0a9be0e20200d3a10d58e13f00e68af70ccb525bac604a004d79f4060ddcb15faef2864648d056db064249d11a61a24b70dd482f90706b9411c28d87534cfecc7da3a7636d032a06bfd9fba2c1a58d6814761ed9678e51620c9fe9a8cc66f7ba14da35c591c3f26c05568841d1bde3c71fecff0bc8f675c6d85f3bcd4d0191c6f4b417e54827d10387a8e07f3baedbe0beab832ee6aa1e240257a9c3cddd9b7098e3d56a2f7fa7556ed200c1b31b06404308192e43cee30aa71a971cce4d57b77becc60ae4f829b259841ce4b9b3547e0878ea7478a59d11af1467249f89d2eec0ad40c72298b5b6a464171b04bf98cf382a41dc6832ff4e09fe4cdb267c6ea66b0dcbbad575290f7b9e010732b48403b93554e885297470131e3e425f0874354e781c777242a89ad3badb618f0bc1dd16f5fbb87c5b4851022276c7d179b451eb1aa1fe08e0e62e93331a93b37dacc3b2a1b8fc6f1c70000e509302774323e1a60abe2a1c2e225d18826c244dc344fe5f0deedd58a8e8f0bc9593a558aea28233c2afa68c5b2682bf2c7188fee75d256bda7005b1ab8b373fb040335aa83b24e120eb671d5382cab9e250700992ebeb4413cb176bcc2ec88d7e0108d64a72cf0deb04db00e63d7f00e3c27074982c04c47e1b6ef482a308ccafe0931936984371181e331ec2c69a68cb900e99d261d60719209d9a53a4f8e728e7c42f5a0b9997e278944f1de1b639e96fca785eac267762fdbdd3066e8e03fb029ad0302790c15068c1dbaa608dcd0373b5babb430202c3500e9fa040f92815453cc43a3226b40e53b0af0d17e186080ff2ba281086e7ca5f0d913a27575ed14a15434e5fefb8d24ecfbabd38715ff44322bd1fb89a7c3f3f02be6522fcddeb0483afc27da7308d8d7312c0ac114dac295f3704a5df5d051f238f692bf2a1d6df6c245bf2c82da520b363b0911796313523511a0e74820d9987194febe56ad54ce611decbaaba2f01c3a181c7146d19e9e7b85edf5849e42a7104ca3164df57e3eaf8159cdf795ebda33afa090e05e49b66e4bfa96273e7422d83608e2bbd45367e1325f52b7503b2aef9c08d2ad5819202dd20a3d47a3d6538a813274f71b2c3d0b45ac1c5bd62619941d2773fd94ccf6935dd575e5ba714dd564e7e5f2fea1098f131f0e97f023ca5e7a3615b6920e38233b21718b8c357dd4479f7f99fe1539e690aacff1b4a2949f4c26664d04a320a864ff35241bad13cff9d0abe272e8a15830b38449eb890b1316d7401a1ef61d5324d42cb2e27585cf73d95c09b82a6e23e0e48e911beab307d749e88bd84b5a79f9a8cd3f9ae176ec4241d77d59ea1e6eae97b284ab2c2b48980c28052b70d4a30bb1b00dd2a3a2830c29dc4c65dc4e6dd450ef5d5c3194860d7530d58e38b1e89516006cca24c20719edce4efebdfdf482d530b37296b9629cfe99d936717c9d917c004cd4c92e8a63f89c3e4c05d1d729d9313ba4a945a9ef64917a84b12eea46b189ef960913abecb6d643addb6092051b29512dcc9bdcd5457105a351463bd234e424c0d8263c4f473b101b5d20749942e8569fc008580526f2b54b068f78f5f9c27b21f22587d974b46690f59152f9873d8841703de22271b3770aea08407c0a46cc937586e8679eb0a51f47fec7916fa2e3c4a24301d725147ac72ee8c5059ea93577fd208ea3acd08b976ee5c9a72351f4ddc5b485868a8797f8bf486647d4f7839d44e3f241d492a8cf8510a018a9d56696ad0ea324c61bf0b3a407cdd1a9688542d72537ce8a700085f6c20324eb6373a8e4589679cbdeabf6a84fe059b1c2627dc8a10f6dc39e19529bf7d5a06eeb2a956dd05232451839f8d346c94a15d187491d4e707c51557b324bf9acbba175b7b4a56c503bc34e4a31d215e837dab95da2a7ae65adc1c1b62d24a53eade0dff595c02e4cb98f751a1cf96d48c57f19c78349d407e8939ae0b0d69c49864630222b36477eddd69c75333c5be9b9595c9af90dde6b88e1dc56d8c84c7d656e53015dd3bdb39c5dd36a79f896dad9f3b2ca042cdcdd8a66ce8dc7216cbaab659ebeb075f14686bcc468d310910f0bbb93e285587898e397cb4afc8f2675d687531c459b61650a42d89d72efc74b3778a6104351e7b93e4de049631aa0b868657ac6b3711b29a6790c0c58636910d6cc5e840d87adda11e561ab8ed54b3070de3689bb24542158a1d108a4509a549d7a67637b9acddc769469d105e4d0d17d2828e63eb9b7e34f5f10ff11523d7303bedad1ae998369660f490a6447b783c11520ca4e375d140469e510fcee0d5cefbbc2d91d76c0f7447bb0fa8536fd88880503129f69100a63ac00c74c9c279d85c9f72c0c79be4da98139e8c67520db8b28c64efd6960d45e9ffd4872b2a560795c230ed161cac6dbfddec327080a31ab196d9494fc5846d0c0724fcfa6122f500ae4c85618bb87ce3ed5ab2396a33b1302a1db91f4f48c12955102fc0d5851be6e2b986929074df8635f613eb783444b946c38b2001c381bf12127d6eae60beacfe6e9cb1113c4120d301fe541b8451b04601cf959d5fdfe7848b643e9985cf540784e8269f1b197cbe8b38145603cc6d07579e6e568097db20d509e62834b4ceb6db6130f90884aa291afe00efb68019037769cb4c42c72f70165c0158a69e735282a06172ee8d726109ecb7ae00feeef472e11644d39ae46944677402d9240f7c3a9fbe24db1ddaae570b30453f03ba3ba7a3c1cd820667ad903b3f25489ae6b978a8b61d880090876758ea78f40af476370d69063a30f434c299ec52ebc5b94c5103eb17db2db0c28f6396377d6f86a7e13359d1c2c7e499d218ffd5b0791bcde0de1f78d928667b27d426af8db939bb6acae8efdbdfa4662438772e78401e64cc695a5a8bf83dd6595ab71acf78f3d813b8229d4717cefb9e840199fce25d20d5c1f1b69490fa2a6e2f06df73a0319ab1acd4d98a5a0e7bc89c63f5c0172818178def69655e2ccc0055b62620ca85a29f65674848050c225579484a6692b38049433dba550709e2b22b73c03481f401828f61402a5e7b81a2c7fac0cabbd90424e966e819967c4fe4a578d76f02e15d19ea93c4243a7f3c04520f905d0a87dea3649f4d0dd2e142091e369ee14c26a0e07806954e9ad9577f28df70efff9eabf2b3c740d84fcefcd590693e67194f534128d49d2314c62ab8a91eaeaea496bee82f689013807e020c42b189a3a168bfaf0312f8b988185f2de44dcdbeb48413ed60cd086ace5170d9b86f3f63c24987cfaabb848730d81ab060791050b99021be5786107961ea8eadded695c1ace08d7583ea115a76cb1cce364182cb2b5b6404947ece9fe2918940ee3bbd6f1e6f6c5d008da3fee3e4547bf3824dffade5b02c1c3ded508f736468e15d761c9eb547337344f3f05e5fa59aecef68b66f2054ed6a8491b5923780b48c8b584ef106d4fca3c3f79a27a53a1958f176150a3cd39da3419e0889875d068746d90b99c781348b9d89590d2ec3b6434d3256e2aa253c6a5332de52adef232ea4772d03e9b61edfbefdb2ea2e120e5b9a996184dac804ecdeaf1b14fab0c051d256063a814b0ef6bce415c1745950a1e6c0eb2f0dd89fe3d802d202006f2cd4fdccde4078b81de5ddca403bc46101bcd151d05606da956b804748f86ce3568645607361a8592e8cb63268d4158a01809f182e5c0a9b2d8297f887e7caa05786fd64afca95c14510125cf065348dc818cc36eced93b4055e31a420439da1d9183257061716fc32249e2b838eb06041a8768e9ce3d1eeb8ab835f898bdd222f420c5d3031e5c1c4e0be2b43345ca4185c822d1ec1e97f9c4ef1dc518c5dc2c95fad91cf728ccf65120bab666a2f8e719f461ee91ab66a006d0edbc4aa350519b928fb4f2685fc04b80b7c54a09cc2bb8116d66b020e7948c90921de3791ec0d1445e39499e9d24cda43a44aa7f5f004671217870328710c943377a2a0cdc58edc99708716e43b1969155915562216869b4fc6d873af77adea67bd3e6edacfe895617b594098289a51a47cab5f834d3e8277febb15d8fdc69e5ec863c8d56c975abc2cbb0c6dec7be57f4258bb832d46a8dba0e156f783cf8d90bdb61b3aed868ff65d57d211d97026660bb3a952851c30748ae8d50c74828288f72d40987501418d60a9f255ad543bc016f5e8bae928505bed6cc270d2c5f7f41c807e459ff34feaa564bf37f763d7c3d16de8d57f3411949db5938264b6d9817ca14f8062379d91308e805c819e169fe221a9e8b0f217b968086eb1e7fa2d3db4b387c8731cedcc4da6a87ca3e2fc47435d36f5e947676a27fa81814429b6cbca607e27cfb25c4e223de91265f1444f61bb32341376cb6d8a5cc4f21c98550deaa90c00b9ca03f6a8c3216151db727138e483c4f7cb03ba46cec58014f72ce65d5cf3f466e36b188e2dd8186ee277e725e92299031282797034c5156a24ddf024409e552b7ac4be3bdc89ac74a2712a6e975201a24d566b496541c22c131e59849c0a9ce1b2efab7804ea7b043c4c44c03487c99967d20f115e7a6a7ad24e370550ec080b6e8caecd0b9141abaa6d43bf1ed5615ed7dbd09598a2046afaec8f32bacb07c13c712f098188f494409a7f0631e668e5c13d3f00c468e984c6d8933e4b4b66439305c10dee2a72163f30fa5465f8e45fc3bd046872bda18cd6675880a0049e0f037d33f506f45fdf1dd087a16fdc27e801bd5d83a4b031b6e5d1b07056345bf0911595f5bfe1d40232e8886468437ba2dae53163d71cfb9016c516f430fbd699d6424e9bf5e3a5c316ebaa649d3a9b36facbc9c1488bcec16b5bc6b4d1f63c1e575e57a9114a74c545a7c1557497d6e42b5ff38e32b589a00a3072244fa936f427c8bf094bcfc0045de42e641bed037050ca47ca06a5be66e8850d1dbee9c74b8126003b51b80c3511376d347ad81c676393f931243428a20fbee56a35183e09dce065a30033e4793d5cc62cdc815dcbb1d1c19c5326d4a558f7a90f616c84d807ff219873fcacece490d75fa7b5a6930f58a3d55ac182eb1fb219a40d4cb970f1481a07dbccbbfa66a8b04db937d925741f6e3e558fab641d1913e8771658b94ff64182cbc915e883cfef6c1aa792e2267520a0f73750d13af19dcee2df0dc2435d7d23f5002618af9115ce873f936c4d5b60d9605a2b4664ca42cbfa567e5c8d9c9123217a1c709d2fa4b9e5a6e85e1cb37831000837a6eb5a1db30c3412c9a78f4ffac5a216b5717d237cd0dcade4d0d88ac709dde8b9a61433748e1c65b587a3192a89e9c280e9230ab9a0fed944cbd7ea2f638de910a71f83bcda30dbfd8fcb24d0fd15ce8f8cb46d4e36e2ef00040495655c5fbb7b19c7ae1900e689b44e4c7afe1b3852460f0212f368632298977acb52f07509d8ceca6a03bcb18759dc61c4811b0b631bf305654de88c1d56263f5510362885e395949e5743187dc2673033cbca76d74698134f949781024c7c7305f3b8851c29f5fc7073e088a5eb2a07fe9cccd2ab3216bdee609f6a0a91d0a5b7686ae9a33a7edb6f831f10b0d3da199a053243ccd850b6cb5d127dc412bf35f92062041a6209826db917d0ae4dc66b0afe9662f13672fe000fe8fe60e43b633b9f60253fe744b18ddd89678627e93e05fdb0b9f0a0d9902a56f7e4a64662f6a32b5301cb5ab7c664476cf1ed23e4760d267f23f5c4812ae3e7e2dc61bbaa8e89db817159386182e9f70a2c6efe0de3f43137100118576f0069f3228e0974166769380d33d04881006549ec80ffd57b630aaf865e132b785f913f982197f6dc7504c654385f99e1e31c28575d410b5f3c45869eb06d1bee51548e11fed3bba15285cb458535be8094d18a4bcacb410c61698c09335a8e9ad8469b372be957ef2bb2a6163b3a023d92f1d526fc981b0efabc043ac4c339a4f2da0d59e484de9cb3d3bfe2c871e32393e989759afc109137fccc4abe9238235b5eadbf42d64e8ed8490f2cb20bb51244dda3c000f1eee95883c531ffebddd1ff40cac70cce18ac158c220700b1c164b21380c36e222983487acda18529720e79b4d5950bc3d644978409b6099b2f204e9d39bf7e401af50ba3477d4d84fbb949d6f134ac16508f71dc0a59db8338ac791ab88c1ce8a4ef1b3723129664e48fc2e7478d99ff4e0f96228e27a7d112d6e921250adaae2a2618d953a4b5dcafa32a5204b8d9deb64b12e88ff3e0683c62b0a5a08dc6f42f37ee10a885e5fd9a14cee51734e0eb69151ebeb84d818d9e4b92913c98c0e9f89eb5a933db0c5b53e9e49aead822022724e270db5e3e2b186e5c5de4323748655fcaa1c5981ff2d9ad987d4a49b245204971683ed3ab044d73e5658b9373eb5c9c08a7ba74329ec1741a6ba503bacfd6a5cf5aa6bd1569f34a7c89b5c7f2a3ed42fb725a016d34aa05817eb8d23947b508b548bd2d12ff5acb31bc1c5f992e5e6ef2dc546ecd8ac465225dd698fb3881704b10899f6c8d44f9dfe2a010c943867f295294d8c0727c4f689c73674a363abd6e48ba55aa2864d7737096027c21a9c8a6aa1ab161645841289dfd05bf751dccbbb58c27d224c92deb7a5c2f6b97ad9e80fb1a3e04c09471ced019e73f4b4d7190f6d8d3d5b74663f9363d12988594e23a394245a70b6357e3e5389908527d98ce5a3d86809b9022b894686e33e7cd71acea200916459879bc36cf58ae9446ebad11926a1e3a7a0282790cdc091e18a99a3295a0d1668e902d5d68806430eca0ad785ec0259da87f26ce13a702b9c01bc1de7dfc596682fcfed3428de6802eaccf49b75434a3dd0361b9f2d4607fe3f6c969c5fe9fc4160f93f6e2f57a838c7d8b64dfa341350d4f6ce6f52cbea6f8e8eb058b2b4b9a02620dd98226f5fa20fff8f9422193d6d01121687bd114a76aba3a9a8fa630adb1ee80805944742f1564ced865bc52c30234bcbb551db25399101a65499ca8c795ababf17e71c97a925a4d4a5a981ea8704a9780175cb0c1c2da186d08cb11790f5d6ddddcbd1ad95b10b48fa4e2329b180aafb6480f2b74f847f63779b6b2cee22c2ea239d57de0a828a36820ebe19c81077342bb126b218873ffdb96ed8e750fe14053104828003f77e3a6c3dfe011e0ff60ef2ea1acbd7c8eb6e15d257d9e1ab36e71a47c6065f2d20f4cbf74517034b0fdff376d96110fa6b78810e891ce575204e09722801a991682374e3142a2cd67ec2c71a1b38f119cdd67a4cbbd7df5107513530540c983eb63aad9a116987493fe12fca1434b357b32c8dd1e4a9b850f50526eb59b046e99b01b379ec09d92fb66bfd03846b21dac616b3761d6b44c1f0b294772280b6486b1529a269d8e009648d6aae2dbed1727209e9df12147c59a9e90a009ca68977ef3acd227512926e09e62227a1009a6621c8ca8056e41a02d369e5a55f4f64fe063926981f643c9fb91d28fbc15687dffeabc24faf03c3f9bf944f328691e1b9b10cb8cd0ea81e4df4ada67fc85281216c6d100e97c50df501778d1bb5c8450e81b26992ff360be4d21a7c140a06f161d8ba62c4d984c6d836f58ab413f5e59f7a4024e3b8fba6b03b41b95e53c261b8bec47e4002d410a59d28391a03550251bc4484f780a0d7656273d08da63d879a7955f3e10fdeca53f7838dc7acca9cfbcfa4cd7c59cfaccaacb7c7dcca9cdb45aa6d7c64ced4caa657a7dccd4ce546da6d7624add4cd5667e3de6d4ce5c6de6eb4aac5ca97bcc19abbc0701f50770c9eb16d54c09dc124fc30d4377fcf0994e89c00c2e9f0781c50c40e0a84840b5d1a5bf89ba79a70bd43098a8b4e3edf5d79bfdb10ac1641f74e1129ddb060926ea7037e7c0e72ea648fb8dde44cd3b48dc163524eae1c15f3b7487d1c1f1e4ecf27b0121d47faf58346d5d100449c5a2916b4f3a0f3f3b54a6409e01dac771d6317c2c67fc7b2e0d503cf3b022dc301f007edd884ed1381ca27692c221ad91d82123b4639a80c0c58a3f660c1e5f702e80ffbffc5828c270869da36f07499bb44b2fe1e18f10dcbdd3d72542eef34c8b8e8350ca69d1457a0cc814f1ff78d68954d5db542dc05d2d1fd6c9fd3700d52e600e16ad14dba30fe6ea97057c1c9094b976bab5d0b0f2af495a9e6c10ee2496d5ed63e63b728b41a1bae66078b350189ec8fdc5a7882a362f9e7c558e953f0f945f45834d78f1455c0f43424c44415899cfd60f3c8be5d92e54a3d05f381e25c861df5f9144c51d32216a99bb745febf68dea64cae60a41af005839d6a24c1978fc9a4c57c4d99d20f3726a429c6b325665401b21edb2edce3c4c55948633ee2f0ed5e119d8637f1374a1873db9ab10ec11a85b375064bf343b51beed2d4d66eb89851e2175951b451442c22508d5568c5292205fbc88e5e2df48e524b92f5fe58e65b4bf78446e46ddf2771c5e5d703f40d2cb63cb2c44850d4d80ecf25e502d49afc88c6a39cb8ac4ee7e6450bd4a49a62153f9836008bc1d1d928f059f0301099532c6932d44f34a095d5324770b2f01663491e28ce4b2f060b22ce67e95ed5328fa466288986cfd66af63d794a309c2c7aa63cf6b3e52cefd365d1fabeb04959ea25c13b6dff81f6d3eb5265200c78329e29ec827b4d1cd619f971853842db49ce03d090d4b2d9498fc9d610aa3694c884ffa614c3fa521be7e02e76ff8a271727bc4ad859237adb178b8678175e3ec0530ed133e1a17656aace16926475497a01139eba9e0c5ff22adc17a5cc83ea16863543090ebd13496aff468d5c5b1724115232c9cb0b206b702960b6a55a675207e5a1e8da15c20761d8cfb1a811282a767d59106b791d41a8d9c153f1ad036ea3eff15e83b45df3264c51897094684586a7d1d54cb3952650b4c929c23143a6e07fcc69f9d151796410d234694c115b991c87a55cf133073126f643272edf40c2af8b92491233247a6aed10529a85a83ff24a8ba853506b379d522b961889b3d4b535343b55873d63531a57d3521035151f80cd067ccac060539313635aa6bbc90d2a923cf172f303917f17d4bc06582aa986d4a29de90bfb17f9c665bce27c5125188768f53b3e5129bbe28f538322feb4a115b32b806f9648432a9679c13b4205e9de7d65185d6dcecff43cac7e1a8b009077dff6ff9ff291f20f2cadea32698350ae08163721ebb15586cf6f1f2fbf8a2726a9026cd916fa54ff4a990d8d1dfe965376749b3cf22ec1a796b22a00cc7bc39ae69e4e66274cfdfbb0111b02e0d676decbcc229ed0bc0e10fcf48f26e9b515a0442d010b207e823703b08e935055c2614cc2bc231f909865e8f34ac7899ddf2d1408528949f23f537deb1e0a29dbad8a1b65b3b0ebf1291555601b1b91905d2e80ab0e8700ca729c05886f409fba420d2d152b2e6207fb88ecc179fdc676e27c273f29db44988b50938d00683bfb2e886a18b12cc52c50b8daece4dbbcb1935e5377823fd3cc6c84a95a2a592d9bdd0285f8eef558e541cd4287b86c630e00c4bf3759cad3b6bcff112500aa5126180fa81227983a2e9fb42f6b1b2ebdb24c10d87e191b2f71b0d2ff65ae5ca4a59068f1c744c2283ab760c3275bc3bf06a14111143630a8eb1322c361f390d0da5f918c5572a6736e194de65a28f9c56c8990f1ca144fc02b012e913c01a4384499d220cd5ffb4897f470eb83f4b7563c648648a43cb9d3635eef446a08685831d79473aa87dc0c001ba0a0d9a6d60d733665cf8d536f8352833b835bb9d3f4fea62a3fe07b10dbe1125ebd61e239e3d2512ce9275f402dd320275945404f9064793426768f951b15594535444e70370c09f1ae2ee4b5673b568adf511ba604112afe175f323ffc823408d2881948314ea2186aa2652cba0f32c6abaf122a7e536485a5a4c01eea4040615023372163bc3fbc3fc97d48d4c5a8419c3a154b8d0a88bca55cd27292771e77b093b87295d0898f22ec549bf15cec8bd94fc1a9576e9753dad5e74800a2be3374cfc2cad20ba4e38e24acfafebc3a03158f83c6759d4618682e5ab9d132ab646d6420913f81f7ab1e603c80ad85f6c895470f3c5bdbb86d984f43099cb320d196eaa94568351a9c29102ac3b0545452bad63f264f107c7b40e318c576218daf26a385d00903eb345ddb33d9579590c6970120eb3f399c374e4c1532cab1cef33172d86d9cf52c1f1a748134fe52481e22d783e5a241610c20d349e9928a8f96742e627c2d3dc4232e7b7af44686f18e344a0388021167244303bb4bdf39a2551495c89507ff2d96248776431207db618293e8a3fed18b562636a399eb6e9a532fc40546077199a34a31c58c73499978830211d08ac806177198d23caa2817ec55252b17a06bb2744244ad067568f629a0920352315b5e1dc03c3734c756f89022ff44e8be08888454b7d57af2f4c6aebf8c0541415a5d44a38450701a7b2cf24d248a115476ce20a959a7ca14643397f8872a42827e6c9ecbee194e81f10c1d2a47a533f1b1854497d3ffd21eb68fb3ca57fc153186b2a4d11024a130f03ce853cd9179f30d77ec4fef007abcda8c7d0dbe1a8af5f595d17d4ef0106fe387cb04647ab57dc70a051118a14a82d2aa2b08f51f5483b32ea471d176e8035fc9a4f634c123f641ae4ef855a24994764a80ba4c18525b82940b6a3f2ee18e768c9cf0d4808d91ec82a59ac7bca0e6a47173de6090e5773ffaf95eae10781ec9e75da6186cca88bc9202b25a3ff0b498b2abe216f728f257ac98a3bc0350f9621d9ac3c952df9e4dc6cc24d8c09efb680df13613bbeb5e983ced30ebc2d64bcde023152e3456740a5d7f20f05bb960f393e453f502e20434ab10aa863023308151afe3ce8409ca050c81fadd09fed6ef7fad05bddd5b79cffdfcd603e695f427cc0a409ffffd2c27d461b5d1913ba5e4fae705072c9c997fc27f8243fbf92592ab1c8da694d9175d3995a24e96b7fe19f484870901938b296c15dc02ecf62ce71e48ba70874fccb9612c55694eb4127af3a04d4ef9fef9620c0e99122a2311a5ec00a29621a69a658b32f05fa4e972ae09b3de07b37ec29022746a70a2d921fb597537c74e41282265eee3ddb0edb62d644d352905823cea61f8f4d7498eeac9abe3e8c3832e9020d3fd0eb1075fc30200fe0e0e4ccdcf9a90d8452ae238ec529741df8f9f54ada6ab144a63c280acf2f26bfc019a53e9bd59f6059d378b09b14820895d2f504f09dff4cc50bba6d2692d902b03c426b4800a842629284ca9e5a55950fa690854e3e4445cc83f3f44e11c7baeff3f2bd627f6890f181b2afe229f5aa020b60c15785d57025c1934accac1592f81d4c7b5e34cae8541eb79690e3033e6231b97e076b4cc00422aea885e078f249f02e0306a61d2271e5c99a0f0d881408daa99ebe850e1fc97093a5d946adf5c8df8dd1b8cb6bc1716a6abe8cfd6ca6ddf89e92f6ea2572659a76149761a0c11d84c031a589dc338797bc5b31ee9a6bf88fe21dc59e09bf7eb450595fbf2d3ed61a72d90206395512c2ff29531e77e1bc98bbcfc08016c802cc301f5ffa2e85c08b1dcd96babfd368a5adedfcc400e78a28885e8b1423182121646040317c9e8cc414142df0a52738e8925a1044a775181fa9319d69ccc114b86bbcf2db920f491b9fa1c3af3a46e7091c4278bdfe41df74c6993c53e9da75e6e1904dd80888ea2979a2a7b84dcc2d35a47d1b0ad5b0357046b844910cfb0092b716fc2668ed4ab755cc2d2166bfbebd2d5abb1d7fe15ba109bc1278e852861821ea4a9d03cbb76da9461c248fb895c27323eed8a5af21e5b382c7b694adf2ab08b72d790d7ad77e8eccb0be08fa44add49bb38c7d5e16cfcd87df0484828d4a9704b0b86d632c7d401b0eeb569d1dd9e655d8e264cc31f30b5a3c4a228171c37c4ce127f9a24125f40595d6be88cddab0beff2db040af2f4077949c15a22092324278b64eba6a3cc47b7521eda09181e67270ca84f6fe0097f6311f973994933672334311f3a4f0549b42c94229b54e8cb3dad1685b2bd65cbc7ed7e427dc0c180fd74b8c841cbcfb3e3c1027275b1af548ab1bdf144d6e7896b8476b422af398990ecd740531deab3a9876be7082d6bb28f6861b516872a11af2d279155a32ac33f40f2a0bda0f4c32483dd7b81d0c54f577cd33abb57e11147a127f053f5682d2d64345d59f1bd1bdea41b46d16ac81b16740ba7de8d44db4b0494fb127d6a805eb494b106e7cc53580c50eba1a316229054b164051e1c54b072dd79822ffde378ee2c131ce8a18dd7eb69dadc6fbcb97e7ac5fa1a8a28bd85ee6e4a14072722f5eb43682ee921206442fd8e64bbe82631f8dd0b885afb00760cb715c58263361fa6ff9e6bb83c0cdfba0dde5a8a4d6d264860dc6bb02a20e4ecb60d112e621e97a34326ecfa93800ab3d76888e37f88e1dcab501caa579099eb559b8e4dfe9688bafa925b279059d2e203ee800d99edc0e5615ee823c3e79fd9a02c4ca81d2c917c6917e9dafc3a9851df7a55517f4e56d6a0bf44b6cd2df7c47f0e2fea2ffebf364140c9e11602de0ee977aac6854d54ecc3befcb153fbd516f1b523054af589982e50fe756f0f4303d7e0cd625516a443f764886c7800c465b251f7f80c25806bfb4d34ecffffd796a6185bc97439142ae82560647adccba20eb0781f4d835d0b37e99920b12f2b92d71d3b932987da4bdcded28cb26cc699f980c26fb3725b0c0574b5360df8ffdb728a89922a33327a88d7103b2ebd2a89761748c92e102de5658bad92bc5843613e9621227ced53cdac9cb4e92b50b28ff775e47ae1aeed736d05fa2a51e68ddacc5fe80675458d51d94e6964f3a4e10f662844fa86ced2139eed0555f123451b526f54612ab638f6a639979b53b4c2f01f23a412b87624c060f2dd6de92970d0f534c9432bbb2b03d4e4eaf7b78e8170940b498f236592088c6e7075f749f8693cb97cd0eec6742c8867015b00016ba3138fe379dcb9701c4401aef263659329bb93a35fddeb0a392e94ba35cdbe6e94e8a776ad4f50eb57cd87991580b3882fbfa6d21048b59fa68f607ed30647aac5788fc9127479746af424f551e4204c00fe6f433189117cfc070a8374c4e6f285b2de2cf24835f8f04f736adde2dc221344b8b093030b875b78e331e8d570d08e86cbd81463869499975887feeb539a01a85781c72bc9884581773197f815e2a2b37f2105cdf9efc514468d122f138cfac711590a62c331a276bcb71faa78d02622a7eb07d0a7ab92215a868b4d53298fcc50ed4cc6ae63b52481dfbdbe842c8698ef7c0610fd271c1edda77bf08e64356aa5b4ec57f88160a63bedc28801e3e5478ae44a3f25f80bb024ecfca2ed818369959c260768961a771567b71e0e2a867a3fbc0e50e242233a84bc7affffd0b3cc6f097056adc4b3d2af80e63b817301b366e558079932014bb0005a2474f74d638e527899927af8acd61eaab3c1f9450dc6e256c486d3e579822ae141c50149ed900b2b5139a12810d143f5cbaeef7700a93e12dba8683e041fb46b842d233f147520c905466d4035dd30cd277211703ed868f88d4ceda3486561416177bf6a26aa1152e62702ea6fb2e0e79705e4577aa7b3b84dd578ed44abee4885db3f5e9844051c42e38173ebc38187416ebb85edf32dae51aab866b41395b0cf650a2af7388eeed6005286e09e9fbac06e904ee9d7d114c423bdb54d936f542cdbc0f5ac7143cc03dbaa17161757a5370e24d90f19668da4347314ef96c363ecd62b1d560d67788f71a88e3fb78a059200ee5c0547b5eff8d54f107c478b6f102d1fcc3b479e1b8305d6e195c8ef0387f6ac64e81187827db41695747f26b0117a8f7d4b8023b1d5a374e0f48d0c91382b286da5f90af229b4da73e97842211c50d799ce7173b7495c489d1697a661113050544cea5a025652a0c585a267ce05bca6e385f1c7fac001811dda724f5eec3bf78f915f40f2c328bc7013ecd8ba144f4752008b623b86bca5cc9f64afba926b62845aaffc4a0215fa36563fcbc84531854463ba709c5ac529f61cc1a517cf6a92153f8b1f3bb279c272e320b9f7801afd1a2aee4e1a6f54e1ce54fe91252bcaa902089af0aaa281bb2051e55f4f9b1d87d081fe1e3de720bb62e39a51ccccd044db061e41e07ee483a38f51a3c548a7fa8b7df3f325988b44ff10a03ce8a8033f3c2de476c30017659a96d175fd02a7d845c406e361150ec317db30c98fa014d972cf9a40d61010af30be0c44276d0e04ed95c118a6dc5dc3bb9cbfb2bac063153f1d087fd43940f06d44a1ba106e258cf397172b5807e60d8b47a2bcd4e5ff3afc46733096bce4357a0e09cf553bc63eef65d1e0b626409d05cc0b0b4a1c858045320e5d830650a4a89926fa1041a55a52c6c1b66b3d67fa88c1214667afeb01075b82d74effd4fdde4b35c7af6bb41c83db4a7a082e52cade69838b7bc81ca5320e675810710df43e33f0f8b31d377575fb8839299250f61cdcd624fcaad8d5ca4151f5625127af2102f0875a206c4e0e411199ae1f3bc486107eda2fd37aa3fa39c963d6b6283d7c4fa8a6f48f791ec8458ce4a7a0c38f08f3c5b84f7023075ea9ca281df1126f811446b287303248a7ad8e24ce790623f7eaa7350d89a1dc95f6d7722959e2edca3b8d78c3a89f6ae184ec9e0939c01876342f6da5ebcaa0c07fa5fe704fb9247672e903caa34e4ec0eb2d6a9ae759da0c37626e2da48ec512a4ecf03b1876004179130fcfec3e05081d8b1f95f5c2538fb24bae175de500fb1178f90a1e58b8bce89de3a594a36a33f31a85fa1aaf0ff269a276e14d4153a4d2ca37e4517af5c77b2a3acc61db5a2c81a2b4af2f8b7025a13252d7592968bcd9b1c45970ecaff4953819ac65a05d5172732c105fa7b8099cb17c4c5294e331450fc4d98f02eab0337661f61201b6e0b265893bc698abee47a3e023a9866836fcef7be6c63a613f9c7e6c5d039140fecb43479c8a8118a6d237e9553a1cfa451a6b2b2bcb31c58f21bd23642f5f00951d157dec0ae06e63b9fbc6a831fdfe5ac18e41821cc4a4e69060ccb258a5e2ca601dc00b7aca1750fa989547a00401db9f1eba2db3ebae94c400429a0787ff83775ea8f5571a59ac001fadf2d5d93e046f1b0b4237f84c19410d84505107cdc630d288a9ab78ce9fd41866b0ab613fd02aaaac682ad145ca670fd3aa81916a1376132187727846180395ba36eae3a1f1857adaa4fbe5f7821f4616f66c21937c3fe460d29e9028f30eee197bc36c71a02cb473258f6bd8519f0a7663c8bb13b96cc8d6eb0b2611e53a4e2f0b1bc077e10b4c6b50b4b2e60e019df07c48de9dfdf048f974bd594da7d4d98df93c110d40c2f883d312496793b2aa8bfbec8142f9f9f95b1eba196b42b11df8088c830fe1affacd072061b9b17c7b0cad907390dcbe128254b351910aa464a47e832cacefc42a96a349928306edebe407542af7ceccfdbd7b5efd82538d55d1632cf2fc97c9ca2a78acc1bc018d14abe0d495f661c2d244e6e1a00d9fb6284342c0a92f7fe08377160d9a1c34fc2d96b1afd4c9371672412f7bf3636e7a2f89d12e30267169d4d761e980160ba4a617b405f69ae3db087914e9aea2ae272c31db90fddda8b43b2544a022d21c0caa4d2a1a85af6f186788bbac6138353d67472c1504037895062708df2941a359068351c6f520e952c1254379199c513c8503d58cda700cb308ec7a13d3796f045096bee2384b102c15e0bee2a540cbc8f3491a1705465c2293166d543d397a7490ace4e5cc89db74bc7d118515fb076a58eaa14f9355fd2ae6316f6a880e201c6d9bd12c72ff9b8a6055b23bfc6f387eb94b3abf0396050015503f345533c4e7c0294f61a8e205b505b0efbd0129ab687729c8e0bce27fbd14a81655286435194ec834f8d966a391789bdf793e99d9efd58b5ec1922a177bb274856743a38be759e63ffc2949ef80ef21548794669f5a4f32a9ae37079b5ecf204c7790d04169044568b94538f03ce187ada18c8f0a99b4dfd3ea6ff630c0a181cd099ae7d5543ad5cd08b3697fcff6275b1dd3c55f1105b0c204fc3d1417313e6f1079329c181435779fb7f4c7f73f75dca9607da546771cb45adbf703d868c6a8de616c7797921cf615355d38ddf8c1da0671b4d95bf60ed0cf04c1d9d39e1c73ed44cc03e21f444e5cb6a4fa50fdc2c01feff344bc084e2eb1356a98ab2229012eb036465db43a0ecdb50e645653c74e4e478bf2c93707e663814703fbbe691172ea6453d8e754684fb11a507645c0bcc587e656c1bd1421f8aaea5458fbe1407cc22fd141be4a01fa45d970c8d4f07c0e34c075de22a63dfcdc52575592f0b049df1358e765f9d61f88e64959d844a55a66d66d8fca872ca9d7abd64902a1a44a3d483b976dd77b358cd38c16f474765cccee4f67fa00440faab374d1ba1f594419f3d3838d9060ec73d71005d191419a4ba53cf9a4526b0a5061021da2101d92c62221375ae5a18fa1ae6a773018ae4ecbee351c3075cab429c2e00b80064ab6f2676ddd4d5264394c8aceea0f8b218d7a47a8c8ea4944165db6c352cd65dedfde67fb912797fb8d2b95dad0a12cd7db9f4c1e70178e20ea64b264a5740a7ecbd0ae2fd261e5ff8fa9b9dc326432ed3e105baa968c82e2acca1c32dd9cbcfec42e26f9483cef87768cacccf3391b2793e68f62351162beebad1712f401eda2ea1e907c95f524db5c0e1cc1e7d4281e06002b3934fa9a6e5cf02e8b4cd041a4d43a1b540b90c110d6b94261da36395a7994770300cb19bea17b269605f634f8ec80600b5f8668d907bbc8ce13e45a90f054bf682df4bc4bb9404914fc44629a65d1c5bedd5c26eeff983c215566e0e14d9a0ae719305fd23d39d8121652411d5d5b238cc0a888a42002f13fad2784640b2403d8935f7b3fc76886a33e5f62e0af51b7bf6f96e3e7aad1c406c46d463716c749a83d1d886de96b54d6a9b95f7bfbf2d6bce886454a04b26ef840e1e55085b076b1e1a739eb2d390d44887f7cf728dd2c48d71af8300eb235249ff32be24b8893ff43bc6554d6189d19764a0c35c2a1ed8aa9c75b9a105ec37208e0f2963001564590f1a89519a866c27b7ddaf3c263b9910b9b3afe73730c1be4938b9d680b4d93085edcee645461dccaa39a6488ef1fc134233171d5e51edcea667b2d8a340d84e08712711d4abaf0e2b0db5440c48fc1fe46add2fb5f35f056181b7e7e5bc214e5aaa378bbcaae17441e977eaf7cb217d868ad9b367a007931e489c480a4f34a3e1b7c2f4c722698a078c7605b1c5116b02e55056239f211833e76fd5647f12f2d281bb20883689d3310ac1cfc497b9b796037925b596dd798207b6053366ce2fbf54cb86660920f925d9faa5ec1869ff382bfddefc58e88bcbb8f883c03d43cf99d8fce2d17e8a9a39e1d98a29948b39ca6e82a297fdebf162557027a29043ced837efdfb09ba0ddf98a23a99ac5c444d8ec51a3f1de9e79cbc5f79bc9322313148ff450550dd60e1df9e90dd757acd1ca2ad1eee82f9a33b6228b0502d6502ae681ce576accd4d7811abeff5907543c4aaf64e684ac435e6a49842d75b9f2ca2e61c423bff10e84edbfbc45dab80385c74263aad09c84b5a68de26a9db7d1b9643009b53495748488b78ea1a5c629b56f4446fb8b56d19f746a14165ee82b4a9bc0db43e1b9b9e1d2e4dc11d490e85120b4142911e3e5e8f1a097026d8dfda0ab997b865ad86c14121b602e4f756230d0a4a0c4684faede77e40d13781c08ce7fa1f12557f45c422e93a549e95a63b09245d586ebd18f182d59a830461465727b5b399e97b1caeb8278eb388a6202f5a3e2f54a294c19ae61a4c9c99b81240a491904c7d96199b6bd69d3d96b9dd3e1c4d914316b6395d3224d66c474c279bf352d21ea694ccc40872d2a2340702db0a2dc4d2e88f563a17fd519edef01a257d90ecc2f4204098e37e022b311e440c374c851fab37424962a2a64b2dab009d5cfc2d6e5d3b39a6166aa6b8cf29cdfa5373453e6bca584453856302facf016e7ff3dc145c228c325451e3b145ec29cdf3e904e9d92782c9885ea25ec22522f112dcbccfa077c6fc829f93066582b93d3018f1515cac04c92b72011797ed4d1ce5c579c67eb48636eebd6d05610f2e5fd6bbb7800ec778ce69a43c01f63f703dc992ffca69652d1098cc2895caf32209fbaca20fdbe6b1c7a983fc711ace6397516461cefa9f196328414a27257fc26f0e9bbdf03453da006f3bb6944ff622d9f52d11bb85b262e5110652500da2d60a045f0e5518f6a573e3ab09db66399dcedd1990a2b411d2d9426f52c4e5e2020599a580796aee691c00edb96f7d16805e7f28e8a83680616234d06583c0854d55c6996ad48c80935802f4e29200bef3cbea57f775cb17d8854d936d4b9681b4323d501e55953b62c1426c44004ced9ec3e3a512575b23070d8aa0a29aa0e44151c46e94e5c9046ec325d20228693949b30e4f18311ba8a186ba085692f09d546ff225044d1710e0202a84eb3309e13688113575fef0d09e52619e02fffd4d4abf9d2c10c9dae08eaffc71d7c1e6e71dec3a2ca546b05144aa2c852769089522192bb4795a03e338285b742a14d07957d227f7029fb2d77f9f2aec98d1eaf8177b251889581203eaf24292af9909d289dfc7290dccb5093da209c34d5407ffa4b882fde154c35e72bdb2099e62f69ee2b6001ce576193f518654ec3729ae5c06d64e96fe2ac1760ff1fd7fe6e9eb106352dcc595628484d1c1930aeeba71394eed2eea7148f05afca7a801493271750ce971ce4503695e9dcb52b10a949059c266977b71f2bdd8add7f1a216f9a7d97780e2abc34f21c222e1b85c73b9cbbca18ef6f36e99394100f50a68bdeb7878e5a712ef46b7aab966af1e66c851fa77171c80380d5474c6e307587539ff594d6fbf16786831888b21502318efeb1807a0977f361f6f6854a523c7290367b7178783e1509b02d8bfb935b1149dfc89f9e1f50d02ec4330899264d764af7ba2cd08551f7cfbbcd33a5e4d9569f47ba65d5cd791e498ef84ee551d6157e4d8db9a129ffbe2b72b3427f5f0e87a9c385922ae149987b4153ca5d05c91e607fea7b0b0c8d2f5c83ee11fea6027996fa3b02fd2e05ddbd428815b6763d9cc14543fe4570e4b6a09fa3950a3fe4a94fe9ea7468384bb3552097a3b388f7afd117c4492511c0f083ad571596c5455c12d1d688b49af8c779828c96f15c3524a9317f5fdd3b9ca888dadd7e430ec0cb12f38f43bcf6b90da8266a41451d4c1d7eba255b0809656e21badfd11f890b556843dd828b6addf7bc1e6806c200fc41f07b2a494414531ce94420027c0449e1078bcbfe853e95986ec17e4266f066bb6a13d5733f68a4a1dc74e41d3503896081e4718532b6d027e9ca6255f1b9deeeaba93ed17ed59c1f46f9175db79246380149113bdc3ec3821cd1defaa916f2bd9dc967e878e732deb1bd62a752e01fed0102910ca62073284a088dae6e2eaa10fc9290fa8fa07d24e24cccf01884b53fc3bf5df72f85e4d5ae0fddc2ba3712a28e3e2f9eede0d69db00cdf745e7465c934f3b5cdf67222285d138021fc56e993072064294aad0f67f246467fa4b65e058144f515ca2c1cc65993d2d9533205b1f86911c4534a5762ea82b4a9efed98b6d9da162493560f1d13c2fd957740c4e337d485159217009d3ae2d5891f453519dc018b059905b1bb8e7fc66824d8713358498238a8bc6c9384f60b63c20865d9c2c8f7aa51cef667ed871840e61551c043c046e6018900e89cc82128a4817eb81c51e0dffd99f58a6f1d4321847b10e03360afd0ede1f992b028a5806dcd017ce7613e34485d6db84155219abe1e33e6f64b95ab8b99b3e00285481002046de4d6393fc90803e98d8fc6165576f4a4255de06ba20cb5cacd3eb643ee92b0adfb74f670034c4090d4f1cb4fc4d4d471449da4606b0a3e0189e6396c0d19c5243b03c4077562d27ed7d1c735f45dbf68cc758e42beae75b8f0580ee864b1cc496db930dc27d39af47bf06b6325829e7e58d5f51af620a775004f84372afee20f3afef8b6734665dd7386457e6ce4590b3c1e2308fd3743a88f1d7538827f9fc60e1d442c28ab60ccfa8c9cd3b784d7ef8d414ece50c49d1940c0f8372df7f3dabcba6a0f382d80f149945022b20d36247f563bb4416c0876a1f0f46c246bcef86b1fa62714ff216e4d81b5a906da1721027090bd8d7c52db7facab43a06fd5095a93ccafb9aca7faee48430fcfd59159c7dc0e10d3cab797b8a003c3a4025137958aeaa417c713aa1724aa4f3f7e0a7c8d8a0bac86c2285797b894aa48e940acd2a207a2ce5352a669a839db1783546f4f6dac1a271691594cd2ea0a606dd55037775bae3d82b59e6d10f0608823d8233feb8e1ad28872ac1d97d89b0a4e20c96cfc5fcf74d191315947faee0907ac439d970bbb25aa6411d3aca4ba3b0ac89313914d6aa317d4561fcdc49714339b41481194de487006b9ac02b2c16f522700325564c8a8f6c75373e9c46786b6564a698c64572dff7ff2f2f12cdbc3d4c1f223407221bf0193b86b17f5b6a13a61f927c465485464bdc2b4879c4a76ec94cf32b91ee441b9737ae04799cae69c071e34337a4b396ac18545389d1bb6069abfc5980f4b0c8317270dc1a68438723d9107fc5d6297b22d87ce6369f48462931dcab5d54da92054fd8f2689920c8df18088e78b8ce51d60de25ce7a9acc1439275599474cbc9001352316a334d7569b970678136cd3602d5318bad84ac78df31ef667185e485f65d74eb6af35947af175c71000166facb1746de0843efa670cdef78e6fcaeac07ff427471f26ee78cd92f07b277abb4f993070ca14b0aea0751dd6951c9f6d0068cdca347162383f51a2506b750c06602f2d5457cde338a8e03971e16877cff4affc370f22f228f64a410faf13d804b206060410221f1633dce439008b1667123959341a8af102e30b3f8e7aa2fd12d7d2961cd61a38958d4d96f5a306f427b5e7f64405bc5e12598367e23ec81f8ede0c72e1057e884c56a7c5a33ae2599f2d799807d6a9b66891012abd508a4fcadda557b8c49bef835fac04ab8e0a62197eb79f03d636607cc73964147ef316ec6bd64f8cf84a71f06262e30fd72a875cb800d68755d1f8a0b90686894150e3993b869a031909af44cbcd71cc43f3996fe980da6d5a13f5fb0f6b7f6a4b02e36368f9b0ad91ff54de641cdab2be4755a20f9bd943acf45be118fab0814c693464170f06e9c3fae2e6d4aa19cece0ea4b0873db5e3097c7aaa7b9687ee28c4c0d162112cbddf6101c73509e069d22960a9a510d9f201e7da004c7b6a2f45e5aa3002d72d8e1e6a83562ce7d5dd418f202826036058107abf8b60429b923224f5365655b86cae460dfc36619e51bce0e80f4892dd70a1d84919867ebaf749c27c6bab64010e537cd62d5ed17ee3e2d16bd40b8dc3868c124af2d8ad2ef1845a72d5d91255b356dcbea3908f4c4b6091e1176b43baab49d23fea8ea2e6386d18d773d55c9641d521749223b0e834f213510231cb040cbb74b3e62ba7930929cce0dadb3fecd87dd2c812eb22ffde1f47d657263021d0442e5fca2e620fa81bd06312eae90f903d2334aff436c846908022d583ebd39de49a50110a8a0722aae31a8dd8238cd3ae497d8649fa4239dee13746a6d2ee9d1dec10d5f72e8b82ad3a82b70fd615a42ba4b6fcf19e8c8c604cfda1f925c6ea009265f64d940f6f818efc8f39ba44f59a76718aa5e205e1dcbd256cdf0d2deeb522a2e29b4249fd90c775ac3911ab88b2cc44f80f668c836d674eff8ee3903ce96b99a2c32c448b2d86421fa8490b0b1430bb824ca01ca640b362f199658232b5173cfd051250b89659bb153126f4e1743d31b9113219970b1f8e2dfacda2f0207336c589f1789565e8386928f73f6b1720a9a59853405a4cea5a2d3b6bb78510cefdeecb05b4804bea1eca6b846b9f0913298546c4fecb20668d768214d1fabc9714301d72dbbd44c218a33adfe81cd9ba9ce5db24b3a95005dc24f2f70df47b9be7223058d3769b11256304c6a186051f064c608f131131320ac1dfa7506c83ed2e9e38cc5e7081646944145b56516b37e2b53acf86881615afd21c9cb3e6a040304fa2302f154f79c0a666c42a8dbb4715e1c3567a60d6a0f614e7880623203c710ad8b490b869834d331cc86ea308e90b8f26c30801d3c5e819c083a9b32d79b08ea7ce945c2048eb4ce44e3c148a87b05e971b691f2790d4bfe78413a162937aa0d941a72dc990e4f877ebf6fab5a98f083ffd551834ba8e1dc31f7cfd020356d11e14b960007e05a6ee00720ddcadc881c356a69dc92a0b9f08956e6dbe8e6e765c68b80f70bbd90200f7611a3ad3cff8a5d38cbbdede2716d784d873923ae65aa881803b62c88dbf4683a7a7a193b3877abfab5e1cfc9ee12f60d9528d39915f1b696014202e5578d0327043823276e011d5e1439fe5c8502134ae2eef8336f4bb1d3e34d5d34d1aa64975502fafce4002cb928bef1eaadaafe9cce1ab948557aa7e1cc20f41fb8cbbf39e0ce920aa0726a7d4362ca62509a075e8033b59c40a08a36dad9e7acf8ccac30b00f9a5e0b46ec81729340646577bf8a6853a1c733ab5de4c66d4c40d4a5216dca72cf2b32b45d54a98ab738e86b01022c6892684ea81865ba4fe93912a33c447188c232f6f40e4dd80f0d2a83c111bd813f410e1ab7308a0967ce1d2cf46cf67c2db437d22ece3b0a31e1c678dd48469d7b74b258a44d285d21eb46a7aa774e428724e21dd7842ce027a9b4595dd8f0d14a73243d32468e0dc4c1509cbe6515ad30f19bfb2ea419e7f4ae3f12d15e7f7709b521b8e7bcfc0a13ec4c54c4052e3e9a7055bb9d117409551e800207a408a8a20e146488935a4b883cf5a486826f4abc97f0335c307a77d001177f70cb4591b5683de3c1330b69db45d3d0ccc7b91fcf725a916b8e1e0dfec0a99582ba2d039925c4e288b141fe847a50e8cb1a780f2299ec2cd8b1ed12767b5f9f337d85869f23cef6950a98b5af85708d1cca1fe5e35b74979aaa7ef00d5f46148631e52c7068a5ae8f206b5527aaeb91c5246c657bb95afc741e185acba79620101f8db1df9b7e37f03d7e1216bd721d5d63878b2d6620e4cf8f126526f7408fc869e74239c5ce79fd9e680733e85391bb7830800d44ba9c8c6ab7837a11e7f4d7e1ff51cadfd04386f56c8655d7f1a2e0b0468ccbeb5887f7ba3c8ca7ac3d8bc0fbe652a7a3e42a03be353eb2e9e7ac6059a47270eaa3e49af4b9a42ffa615078ed8a650ce561863c37e68a44139f486ecb1dbe0ab41f957554f6e05d2536b6392108906f415a961b0770c6c6f2029a621a8d984d822b45296a6f58ba2a83f77bb287852b2973d7eca888e8efdaf5946b747090d2ae6db6f597e82adb6c4b17411d9b48a43ff52e50c2bc04a4bfd883a0b868c938cfd644cdf16c4a20775261831e84664ce8dde4a9f2ffc0d70d306c82d4e43fe278e32977c61fbfba1f285788997c968e900fc1159d877591a07b2c216445736b4ffaee8c3622d2d36a6bdc675b7a41168a2aeed9ce7af6f24c48947f2592988b5509ab85343f002a10fb3d379e941bfaf9507c62b6a34e152253d38f94934e1486dd9a16e3ec15b4c9fa21a821ac044ff95ccf15f9178011669d5568ef1fc8745a21748c2ef6fe96122e374a4043af06191d41f9ea2763d4c3a2c92580e7ae4ea72886409b15e2f8e4f36619164821028b4b2cc30eaf2e130bf8129b6ac2f3e2cd24ad44a32b891519ab08ae4d5dcc9a537438931c299153a57dc4023114c637ea7cb73c07d73f2169316ca43de793336bbcbc88122f2d31048f091dafaff17be0d15abf108871a2128908589c3e9ce2a03aa1d272869012f057f5842591d537ddb4bd4e64a3ca3a83cdadcb2b9ad19419a46e328415be0cc7884cf5d32f4cdb3538238c18e5339e140843e3d293d18f26ea8e2dfa9d87c182f441a0e6320fc739174e686765381d7e870addbc3350d5b31bd80df889850ceabd1f0c75dcdf91ec0e302cb9dc0a9f82c5d6b3698ae9d5a9a2eb41f9d7926ef610bf8ab1e8bd182ae8dbbdfd327f03ceed2c0dba8e2332a6d2cda7bfedb5604169e74f6a863741c55d93f04b4213294db0d0d9acc515d2e1c941cee3c4e5760234a18f4b78568140bcec3673c436dee2e6dd9b32f4618e434d66c4af930f8427fb8f3c04d977dfd39390b0b6bafab149cb7da79f4bed4515f2cdbd6cec321ca3da91a3ccb81c6b87e044f82c2e9eaa7d53c11355a851ca082fff00e7139aee82b86937c62f3472eded8f58235a368301d7c18e66a04a690782928e913ac663af97753267cae21fd183279c6ed7cd93e115d976c445c13888a8cc2a71c2ad58949fd69c2f31c6d9b3d3d987b15cc20bc10d17c8a735e400608eda9eb2600d96dc06f741a86dd8edd8a0b5619e61845309e2249089105a68787279936260e6fd0d9e6ff06c76cfcfcf99f02e9614e9c7885f776e48de83345f68fca9234adcf506082ca3a155ba9355fdba3de697b0309bcd50b09fbf58698ef6cfa61a8704669e26819dbe1f760d50c828a0afec7529a2c2c40972cb436d64bf0b5b4ff5a43a9c1c001d739e0b065a79eb3b049d795c11db078381a044b3294229c04880b0db2dcffa01b2c46033c780564f319f7b417bcdc6bba2008a5337d64b747e9d078f0fee1c74cf3c6629b5fe2be1400f141b97610406f4c330e70152e5c7c312f193f3747a2caace282461a20040f72bb34730e06bd54a2d6c3df8149e77d4b3e2dd03b2120d5a1306e80d46d2faf1cd1ac8dffa33f57b9d78dd6a5e4bee917804acbe84962f0801c95598491596a5829913b2a58dd3b94122f99dacb0e69da549793c38ac8f7d3b45c63cbe113db9f94cecf54022cbfa047e36ab09ae759799bdf7472b1f86c7c4d5bed54ff7dd90994d52cedd6014ac48be1847ac94780f3b2b968023c96f5de29d0d75426c898f364bb491462d72fde3ce3daa22fb2b18d00624af40f48def4b9d870ec022d0327a3cf64f74ec07b65a1ccf097cb77bb751cd454642fe5cd60bc04d0732f31a169d53881417bee789c21c38bfd6b16e70ea2e719c13036068c40cd1e82acb3add98cdaa697126df892fc55e2b168fcc6146b3c55ee42699ca28e7f7530fa6c7e24c391c71d095170d01439b7d18de9d1a56991739ba849617f13465e38fed734555ba0fe6805f587776011ce91544079ec722b1ed388086a68262a63fd23c5fe4358bd167558ba1297a7203d64bcd4bf46b21187fb3b2c2a5d9d1dbeb4be45106cb7bab74a2c92cbbe494a6c435d981c3eee11827a654ee2a758edf1f926a378cff7bb0352245ca5d2c0c0b588e53cbf23a9df4e27a83575333589dfb2a83339a0d2fc00ae74a37de796e885a3d556750f242cadcec86208b7205d3651fab98072eeafb603b31d667f66cb5bc986993d2a723c4873e19e023eb416b9baf2e2cfb04290583f05c899dc3a1b63542000227046f957be02b41eebcdbbc02b70e1da967560a23b2e5838a29200061f6c9a953ee4cbb6397fb2524a1c5084b100ae10d686204aa635a09c9c61d1fa25cdd8d133e68ac4502a8ae2c42cac90896ae081ecc2880246f25ef772cc9ebc2c5093094bf4596ec4b76b3f2b5cd40974acee7fe6dd38b9054c7e659b95678bf7a2c10adf852bfc965326063ffddc0c785d2ea0984d311f4c039cc6667325183963dcdf361f4df91e04bc30ff77946617de2701811155e8a9beace0dd9ad9d6213a60efe764342704a84c1c02f3a668612ce7cc91a8308f5858297aea7358c4a6ebdab366f274a56c155642a275eaea41b77af0039ceb9361d7b9372d35431a414aa2b76b09003ef55453d0e342a2de43292b973337a424619ec41d294ee5ba8b47edd66e7b7f7e3dba290d5e21658f869fdb03ec70fabb6ef676084cb2114ab106e721b065c0fd36a71b0a6c242b1835c7a13d26175e94f447544ed889068bd1039ab8a60eb2e7eb796dc695866e56ed9347d1e22530522439dad5e0516564d8c118934347742a0e5a5122d20a31ff227869a6656b526dbe2da227882e0a4c2da458345c89285b05001f6dc98fc33b539aa8b3b3b020d7df02496058040ae79053f1a11cba673b3406d049d96d033e1d8de7d2ae7ade23780095937d89136c91b681103eccc84b244de07de0bb839d4f0faad0f1f66b41db780c47da089d93dab7f97d00100460257e0f2e19a9580871fa718bf648f626a45ae93ea133d715893ea6e711b139e8eb148c0f65c349b96e58c54108573c8e172b010660ec2b67eddddf74d2823d33b708c4b3e39c7ec048e06c055d341dd07514ce3d10b0c342cd49c8c6345c6f78085ce188abcbeaa887ab3dee6875c456eea29f74db4fcc9452d0be2d3b7122ce6b9f46d41279b25a1a16654c7d6ff34c219633c3aa0105444216f4e3712e1d717b1b46105200247d5818f9687f12507e91982f5d33505712427f40863ee93e5fbcc4eac9238545af6cfa2533c8e2684dc1ce93af4a517e7b207f54fa963b127b35880f05c043cc56825ef3d0ca6fb248169150906288bceb452588950678dd8ec806fb0590442de4781a0a30a04bb377541ded2760008cf1e5159a1fc68a3446318b21a9162742e0d84c302e8b37b5357591776e28052139c0a7c96ba96c1812178000399dfbf5a670a32ea3159e087a01c7e5c8782929fd22ac2307410d145b02044ba6efd48b7ad0b0711790aa06bc4f859511d7f45cfade753b3544f6d940f0d5f02803eefd32243d23744c42d8a68a631a16ac098d1885daa2d782a10b00594394df5db78d198f08baede4412492f0347a0c205cede26808a582ecb85679aa02b6c24b454bffd5ba5ec5751b8dda1b6ea6e81ac6e80e0a76ae81557750917e7d62d5973aeca0483f253da19f4375d09500090ef37836e61b9abc4e8f4f97c419308f26864f1eb03e1aafad4ac73e66d7ee4912ce1923e9842edf2367531fe5c1af8f60860658a7e199c37949b17e1ae974b9eb1740bb9cf0fe2db6fac31ddd5e01777efe40e5b37d97888fa55140beb5c6268869773240f8bafe12cabbf5fa75af5ac9857dfdbd57f2235aa2aeb0246ab1cb0eaa6b2b7896c7aea26da7289b2841d315272d670b9836c676bcda4e09254dd2e76433d33df6447f8194ce06e27559825eafd63799728e4b4bda951653046073f69fd09f83a1b573486673b97336ed3967372b49b81c5a9cf2d4f823bae06621d54c91098e5472dd4e9a2d4b47e60d8ca8875bdc303c76571c1600b65071bb72ac177b964b9c1dec0b701cac3e26c4335d5ffc3318815338d4c96379bef8130d380e0a6c1f6a111cd684fadad2dcbdadb53ea5ba9c55f748fb579714083d0a849d205ee18ddd17eefc33a70720cca538852e70a6a1b203d17c2ad810733174907d52f5c420f76da02913e6a565645b46a325c73d0af7a3678e86bbb75a19bf03e8949e6d4d9934a38246123ed8f5ffb1f750c85a6d7d4e561c44acddc57f08b30406cd4f86efc37cc6dbffe3294959377b36f50da22f3ce52c4134a060f9d3d05fa56d2958874096c76c81373342cf14ee3060c326e77b6eff19be2cc1f0518bad58b8151097a98c10fd5b5bc0b42283c9b0a9022e859aa2e53682a10643e4598a724fa4678af2b55fbe8b915fe2f6268ed7b2ebc2ee3362fb6a40f2c1238d18ae6574d787adaa9a4b1485eb537c61348669aa6ac6f7b329ad108fc6d1c8b04c6d39288d5804e934469a24520bd3c6de52e43c41482d9384c0e2e94c95e19941064e90766dba2ae87be8ca017b72d2b38441dbeae1c9a18b8dba66a884b868176d425821875105a3a9dd71bc14f2fc87dcf096672a6a64039f8b76dd38fe4e5953874527fa980ee9ac28b81e411d715a477256ea55ddfa97111c528a017fea5e6c06b52a9112c75b8158a1b03c73af3700a7cb0a3f3179a1a23ba071216a86d2d36a8afa34a2b5457c70895bd802c89283ce92a9dcdd8963090b9f42026f05e40c88bb88647d7696a500470f32b0944b121ee88aff03c5c898f4be9f97534d239959b063128116bb66bb2673b380e20bbb91c100ad97497196dd44789671fe23e0c1bba99ba9539998a7f201a8b237aa6ceae9d97417357f780fca8114ee4bf251557c5cfc4181d7f5a1b5ea279a6ce336186e42fa30105b3948e29fd2da0c4638231c1876960c3adbc727e8fc7f54979934cff6dc594165aa0df31a6192128b9382a7af8c655dbc0af6836ec47d939dae2fb039c3c87f080a1ded040477025d7707c135e3250a8184e68bf7a051fa3e4b2bc88eff829a75373c707e828ed0e2078306983ed2ef315e7ffbaf81a2f8c59f53b8a930af9f6a42a74b61ce714ace5b612924ae7a8b616cebc1eaca31a8f41fc6de09d6a281b468b5165f433a20069c4d1eaaa5d784388438cd89f334d04b28ca574b0558a97c5d588c01567a3c632edec5f93aafb82de3b8049841256225f07e6c0e9aaaeb2c616c47b445faa5ed0a7a2d29e1432ca2330f5ec255c3fba3c49dcaa2b8d01d29351e823ea57b5d4e3b3a4826b73a9d4f1c514358463473511bfe62715dcf11abc63c082aeb8c14a029cfd277e4bd2d1f7b236e7797b6e09ed90c32e1dba4abaa9a7528f0c6c8ecdd9c7b708de5b27b45c07e2bd1a34144a45670013545a753b2e756b7bd6a667572d7b523ec240ba7808b046f208548206346e66fb8b9642dab6609b86cee2e7b4b59c914d7365f33b32af5335e1dae92f753bde20cc24910b0bcac2d533c288f8bc36d955f6091eb946d83e11ff78d8e90eb66f9f7b29573731393ba9241eea5a9dff0bd6e48f1dccaaf80e59b04ef5f0f6fb27b30757e9cfdec4a95d3c10e11b59db7acf7e3094745be8a78c77f0ab93861794c67c417468422e87a15f19e9f97786f8b30c7c3fb4bdd5e42fd28f8c19209bcef036470f4fb2c4cc12e08baa01e734ca8f85647e8f8016976490ea3d1346e17ad6c52efa107db61ececafafe405292f754c665a3bf37ecd814b0a217c370483c27176e94bb779eb37b9af2779d30dbfe887b978c5af4751373ff45b2b36c4d09bf68fe636009d7702a015e4e526d4f8ae61d995c96efdd8779d2207f69d94da6bc260543fc6e8f3419c182b194376f67527d8ef0c3b63f19426de5ccb211b24395aa4cb34399ef8a1cd423642fc4609fe7dc5afb9164d852227bdfecdac74dfbbe5a8e0c7717864b3e757723faa41431871f153388ed24169fb74e8f0ce59acb9338e7a40e019226890b2659e520427746cddc1f7007a7e57b0aa01ba337e509cc311f49838c66d8c1c7b7c476e022e95a1ce809cf8178e16b795a5a4386ebf241138f3b6cb7d4827f3a00765d3ef084b56968ba9436e13ee332c7a968f6ccae6e356ce996d64558c7d56b99968cbfb0988034e5b489c92d88e28cecc01b4356d7a82678c850805d193e0882fab10fc1e84c280d05f44897fa02682f4512b3983b8beca1e3f3c055c7ab20dd979658eb9c6f3e2a1dc68b84bf4fd850ec14fe3d73484f39dbf597e8c0d470a41b116051c4d1fe1eac90ded9008506e29f07bcad3e0dae6c8b5b6829f772bf6a371ecc1cb117b5cb61d2a55798863932423e498a3d728db62cfd1ed206fb374c7d31d3518962ea25af12d7fb167af19e20bda5b3bd67fa4022e63e0d19fc7041222f24e652536397f4d9de907140bc11993e644171a8eab0fb5367f113028e510282e8b57294e678baad8ccd008b99236ec0ef3cc825867580d14bf2518e9130b7d6775893374ddb80ec62dffc5562816e88eea5e676386787984c4f9f5fe0805268604c146d37f3f26d7d5996576049674cdef9834035686097af7a30342b4579b285b30e6220c2d1587f118e324b968894a2a7132806f3c4426188f69713201bc04be15b7bd1ce5489a7e61e57d09432202c4ba6f501f9f9d200bfdc4e184a29dfd22e02cf32c1d74afee51ad9d025ba03dc309ea79c5f9ce8e539612b0dc60959818a569e51561641a72b0f9f556e110b1d3991f7a449348c2a05b44f8abbfef924ce4b13af2481399822d53fe5b64ada66776b99f9ac0bd115052368d4bd9420bd54f99e31da2960125dddb89b2fb8b7b0643465acf4146bcd8966c6ac3b845805810a0909efd60eaa3136ed13db21cc65b5c73b28f3a8b4aeed2cac9c1716c0adeb829916e33bd1a6a3f0f8c166a096e089c03e3ae500ee78033d3322c81509f34c6e965c942b3624bbdd84054164f167b20d2c6213af614a4df81ce592f3da19a6207a385d9404600f8fc4c741c75dc79e4986f2973e28cca0b565646d4e8c58696cfae0979de8bc48d7d58a5bcc2e8ed5a7cc9c1d9eb15a504e4bc8c91ad8b775ace8f01aa62103609d93234775a5922acbc3c81c6a75377add716b64f0a06cc8ac038ffe610f4b36fd3f97968f9ca549f900c5e0f81e3660f150b957d96ea57c310a311b3eb48922e0df645dedc62d137ae071b9e89247848cda708a703cbef9ba67bf084641c285a8d3e90e2b7ab7daad80a737cde47be661370e2f107fe1fc6e814188053ed4e36039cbf89fe2f914374e4dfa6aa35d41ce80752549b35a31276274ce84ec75de1b446745ac87f843375f9e333604053960947fc1fb770c500a8e747c5f57f11c6153a41eccd6e641b907e6c95b01537ed8ebde49ed1d130c1150d32bef9b6a254d1f06b8957edc48ac400159e707024477db3c10606a68ad778e22435e6fcf6c7c946a3e0169b8b50b4f936c30d95ac796e2a095cbd1a18c8904ae47aa8c6177010fe1210a78f530f9b4c03bf1fab12c1c6ff3840a7798b532708951d9693f50e1e90846a92c5735c1e9e2606eaaadfdea3d29b267d1b4bc725b333ee7a14d4b572e7db26817603ee636f145b7fd5dfc6c940c1c447a597ddd8aabd55569538854a4bc5dca3f6a090fb88b563f62c6c7c13f4a5e124b03228926a12a28b46b5bbaf24072f57977c4c1093dbb99ca1e293ae69c812f8bb67368ad344dc79803f452372d6ae3791d1b9ee776f84787f86c27ec3185fff1c140ca1f443856aa5312058a53133b55f7ec5732904e17efbfdd2f4a10eb2ecf7d9696efcc5a1068443058a1c24579942cfcc34f347291cbd35ca5738d7260dfd97c65713c93f4f0382eb5257e6365cb1fa0b2d43e7fc1674206d34b0f4fd2fc289993ebb50d58b648a0373fc7a8504a2b352da5c9f39b79926de117e5a60d373ea43d5c15e367e441f9529d99634c45a5954b5f671915799703b54579937d46a5c65f702725b65e1c0d1b4ca32196468975546773c7b722e173bef2f72e7984988887cf93e9443a2a3df6262d8c144b8353040cadc6291eb9be548aa3bf5feee6ba5c1f7e998b3cc17eaca44d67e0b9aa9ca2805997ff68954d18859fb40a6a9b8f2d893557f33e78ad1838f961189364bcc3ed7eaa8638affb8e01d5a6e88e305112a2c1b2655641669063b2a154bf7e369165651a2ff6ca961a71ea0a8c47c083234881441bc6aab9091e275f0e4769596df00141ea528d151286752b4c79d7e398514f471ac9c18f8e70236863b8cb0763d6e06475d73fe8cf88d34bc231762669c086c8aca2f3582a2674580e675025e813e903e7f7669d3ba162e03b553a830131bd3d038b78dd85705d242296127225ca4b62fb064b79a1823ca33d4f9b2bbca26d4eca8212fc5fdb64d13138d3706e6649e3d3644f5bc9c7dfd73ccc41dbb5ed5bbdfcba040655aaa3c0fbc6e451cbb7a1183663e908dc1becf24f3d79833fbd462ff472ee30e1b9842eba3483767724b2ec8edfd6c4f98e85d306f62a80c0331c37a958886df6642a40adfcadcc57cb581920f9fe2e0386afb5ae098937be7eab015620e4102c2ac57cd0a0229e282b2b4c2fd91ca69fd481a65f9716cdac2bc49acc991d926035fc37d4b8c19ec22c09fdc03b6f8a659cddad85f9cd38e868e3f90b2b425aae47052693c748d68a39fb6f1fc94b9fd581cd445dd184565c79b6f7dd42cbad730934ab12401b0d50d9b80ea135e9e048feb8b123aeb0c431349996ddf834e029418f4112d0fe59a02d98a1346b723a8d9c11e7871a08cf2229a757a516bbbba683d71fd65ed3468551d76f89ea5db89017ce0872f1120cd52f3ab9848a3ac7cd8977a3b4186f3055871233d1b9a78005e9c1f5a77be38cd02000a3001d84685327ddc0b1574e40a90eb8997f73dc089c856ef6d90377c0c4c80111b19fc030f3f2df2df6fff354f263f6aaf777a7bc287a069ead70f49a9a8b59823e738e1d820fac7170f5592720d16c18ee512d73a4b715dcb3824fe9a373eb1a94ccda0c7a79178968b7726d2e137f34e88a0b3580c2cacd6f1de785853aada185a0fbb66f1bd0bbdcf8c10b00fd935d17f88bced1634f49b17038615c7a8c641d51029c6b14540ab29d39ee53a10a46bd3301b15c3e457b374340e29320ce2a1fd05faa600e89ca8c741fe22f311b14a8a09a8f993e29ece93606490c4102c70afb692023940eaf1b65a6eb482f14e9de4b8c1a69ee605d4edfc6d4c9e7f9b59bf0b77bf93737fcc3bd9d93c21756055637a2991c7bc3924c374a02c7ce76c85a4616595c98bfb07c3d35416d04304582cb51dc582c6f3a474d005e6c53d441f58f1f3c4c0ff2a26ad9fbdaeb5ba06441936a22d988f0e1da5fef7875210171ed694b723b1321c9dee3ad8a5c1ee7c92c472833581f37208770908d832888f9b7959a52d206845d7db98bded6c5dd99e77256a23864d281451fc08e1cf67d29c488f8df22546266819b302ed6f85235108e5566ed0109cc857386b84a06cd8ee1d4219cdf2468b726a94f2229c50f1e306f3e6a1d435b49b5b5e33b170510f76e7a6b8ad1473896219cb3e839f460b04260485785f8255a5bf7ef2925b8bea556cc697ec7a5b441c2c2b20edad81ab066caeee4e27082d195f86602e29a38c2fd37696b7b46427629585c39c8d1f022309553c53da1175e74fa70cd1aefa43a0d7aa3f1019efba1c1b4b987a5854748c27949906fd207f3bfb84717c2fdc7997309b020fbf474ce3ec217e4f423f108e1622e3642128847b34224e38e0b13c9db228d534485feb30b1293fa5f4e88b70ff49ab2b5cf09f52eee6cb64b189ee5a62f4ecab5bfa83ade568f0f706ff063fd792c34b93bd9763431533d254bd29d73e96115593b2e0c69326d3aaee9bdbc6f6b9aea80463cfc4cef5fc4380f827b677567bc467c393f6be429203ab7d5cbc71c0dba47bce9544d73863bbc2679db6a2a04bc55f78135cb18b0dd395c3be9c2ec6e2c92deb9515fb60bdfc49b35b6cee825320bf6b3dd4ed02259d50ef80e78769d21f9be1cd1cd25ff3fe406d060cc207f3c080b1ee6618fb1a8635ca82d81c05feea0eeeb60c6fbc59d89243d86eff9f4bb50edba255cc222e790a9cbf0c352cb08220eeabec5764cb0afffabf8167634fe07fb94edbc26aad22eb5fcb071fdd43ebcefe8740a8819340926f68f6544b45c67a8868919905f607572605416c518666c186b2d03de005f82c46100e822ca1f33aba354f8f416d598f75584fc06418ee47c76b48511d677dd97937882c189cb19ca6b8288ee974de45ed6b15e061c4944e343500598e8140f405378a3427db31ac9d2231070d637a31aca032edf0fbe3a81f65494034525309aeec67b5fe939bf11b14ec4481241307170b19bc4519162e0eb4a36a6863008b919dc1bfe5d1f73d306cd5b396e2ffac426e42b8a9603f9953d7caf8c5b83ff997737a0bf25e827ddb6568eda24f20ff70c6cc942495a8f97e39fb6f36d08549a4a11d0d48b2d3d04092f85fbee730fc9f69e95c28966d5a4b6d2360c0ecc8ad86b95bd9cddcf5a52d1a907d170dede06fe68a06fb105ea0b0de47dcc5c61187248150126ec39d70828db59a85e71155b9898aa74224424a0c91d28b0bbe94f00af51972fc028c9f076fde35237ae197422767abbbd7d84ae046ed7dd3a65884da11d3a44399ff1470379d1532585fe8f052d46301580389f5b95fb620d14de4cb09917d51515a6d228a8545c405f9a81eb134bea68e3d8c4b8fa20d27d23e669dbc1444421e51fb580f7f5707a00ddb52b5cf266658d7f9495ec20f983700bbbf31428f84f2bb188cf01694c7b042e7fc35a1280bf3f8ae8c362f15443424ac47934165117f9fcde1500338176a9af84cb2b9195bdd904ea45e3c7b469c839e769f0503dbd4b1d418e6e7e29632750bd2afad462cc9a39fcf6d98c41b3cefeaa29e10750e54bcae0a8ec8a4a185eda385baaefca00b9bc31117931e701e8891eba07bed2a9f47ab228891694f99d304f52ccf9062b5009d0b406c1e27ae550424afb58924c45fa432cc727ab249063a24cef6ddf7466f3c1dbf3b2db9490e9cd1e6e2109cf49a9140b8dda049a29cb93fc57c18b38e4a6ac7b8009801d8d864248454996ebac1543011c5947ca810de93794d7a38f080411cebecdfdaf8b8da98690cebd9c569c4ebbdf43a8e292496c5bf2fd2a424c23e6d263037612b648f727e74ae97b3667845d812d89bec8c754d29627a0f8390f8377f626c6e89a8e522e118ab82ff9d2cb6d5818d0fec1ce08be92a783b8a15f67d47d2573097372f1630eb2b2cc3840209c00e28f1c114e796bd886ed0c96ec50ae642361c6c0c54dc157d40ef8dd1a51c65c59fecf615ddc5bd4c1122b338b11644cc9631f95eb717043cda3203f72271ddc6529508e9bcfe37e5b6222adcd12e33e7425f835eba38b24c8126f8a71b9e4f1e8215b056e79d42202567332fdb05d2219837ad0734b63e944509842566380227156060dd8b3c05a9b5099460b752e2bd39e62f8902549638676463ee45b7982b0aa818ca37bc80faeb72c186bb88e1eb97405aab7bf74b53a6dad071fb53d1d46ad6aff1eea33943511b60bafb42090437d7ae4adcdcff1180e0207b075ba20d0efbaa48179dfd0a2e54c61efdfb056be1f707aaf9f61245f530a83b4bf6104333528ce228d1386492f1ddfe77c848ba1b320c9475d7793c506a5664153f0ca56bd719bad5a5b0d2ee0fb3fb48c02ad5acafa5b076dc763adc24977d8bc1212fd24fe99d4249a202518724a9c10a3370dc01099eec9f9bc0f2b957e1a424bd278ceab7cfbbeeb6054e105d3680105c4b6cd71bfdaada3228de27906d9116475d23d8c3f8079ee70f1c5991d1fa1136fb28a06e143d1058d763d41a3caa11c94e1edad3bbc253ee8a35ba0ce111bbbd08aff460431913371133a086e69b519a874ed0330b8eb95f7c38bccf5442c21f035c39c3e7c0fbeeaf2e42c0c408939b42b303657a2df34d6815cf9aa682de62b20907d65b680c9e1b7d5cb39ec6fc13153f69fc5c3d94e794386a133c390195634657abbb8ac478e53897c7643403b39cc593d5af7a5a8a0bfe4663598c975c044c2cfc490bfa3a69db0ce3a75f4dcbb2a4432f42fa7082e450d9c9a559a813d17f8a5f214a5ff30c1ee00d1070ce5f711e800507828c8ccc7616c548d4e8f91085100065286e8a87a727cdf87c17da324167a8bb86862539a9ebe0b95308f433a4851aee5c8307b2dc226c477e2bb44466a6184327973e60f83bf03f55297fdae04745a1f6e41250bbd0fbef2b858b8b6146eeffc09440f83d7b454a2711546d68da299399a054dc0c94725c15b0d8772941b32f19d7a2e83ea2aa668eb024b4bebb449ae3864417a14aff26e3f4f16627ec871806506ac05a83eaba83a6f3e7b1fd301b479ed626bed14d83c784181f2e519df54fc07dcfd262fd10a94a86126f82ab87b88f9894eadcb70199d52268cfccbaa180a0886b554e90cb04f41a254f6005f06912dab09b0f62696e0ff4ca9f6a3a170e0e78294ded342e7026e95d1eaeedb577ad7c511a0ac20de98c0576c8c3086487676b124729a7377ffdf19f42e2e5027168034d86188ade3c46aab9c4edf88842a665fc48ca4d20f96d68ef4347b2f546e430e17d31eb294de6e09508ebeab98674d011fe3b06ba936d8e8b93b6b130bf2f6db262852f3e2530bf06a86a2745c2793315cfb847bafc313e58ee670409fc25cba442a7a3224ef743b50ba13f4533dbf85c32addc2487e8099444a633edefa8032968e3ffd66737a513bb87daba23fa7a4a22a0bb98b9bbed01220edb47dab0cb4672c48e1d9766c3fbfb6814f744f111ee36b5ef6ed7c800317abf00fff77d6b879caeeb555ea23c086cfde0737e705249a83f9dc1afe8aaaf5655696478e3b5f9999476e17f66e843392075734ffd80b1ee5f827bfdfe544ada957979a1a02feadaaef7d3b626dd9856dc7243c3708755db6dc149724181d86eecc9ea0a371b6b3eaf36176df44eacf09445a42c90b36e9dfdd252b85c5152e4d9b5461930b089b677a9daf25bed594d2bbc7fd0672b3bdccbab5922621c8b26976f03c35b3218cb851c0730d905ccf9393b8b2391f58000adc2cf5d9e48edfd59d6baf2b99471ae35c0e7cb0cbbb6673fe9c36df068ba068c10ded0e5c26a654e9954261447f4bdf23b0a6e069d68d7c7d6fda4efe3abc1c20976b1aa0dc8571992861e995dd7f6ebcd2dfea47cd0a605cccfddd7c2f9d60c0290f0d79a9d4d64ea4b51dfc8278509b12a1469338a1ef44e306888518683db00ad658e51f52da0a8d5e72372d009007d02e11a438d87cda708cbf4e9801b494c13ad03621e41992e9dba127550a925841e6bba5ddf2bbac33b50a1c28f376ba023ed0d83942a3b5ae3281526f5d833de3e9445bcb8273ae9f611d7a5f26062b8b25ed223ea189dc641fc85b26920187a79d4b014d014679de8b52169386adee73178118bc53c6a36b223a3d248f76c2b9259bf651a7b5fcf04b7a356ff112588d9441005be7ac4fd0d55209a554d3a45e244ec355db1292c6f9e824c945c7ba28054bc2d450edf45e294b1e98c3e874f1a251803331c620408c0fb4d7199f750d0a981d2aff5c7641454a98de03e26a61a4b6feb5f6b09ed46a491bdb7dc32cf0daa0d9b0d110cfa8ef2ae872e7625418d7e5d64e39382c2631fe560bf727a25e3d8af23bd4a3976490566491ccc045f34f60b8b663d012f2afac4846e71b1eed2e2baa2bbac903f60c830b02096c1621938851d1b32c18d6bb8d871463601ddba6cf481298c74e11168277130c9838b61973c609a77b14b25cc3a8253d879803df109a2ed0353f10cb0876eb7fb11a2cb2730755dfec0140673600ecc9959cc01eddbbde50f11a577917469d31cf6ae447af02da239ec3f4a363e9a813e9c8bdd6431191663d21cf66beb9162bba739eca53aef1469a53aba3e18a6a439ec3cd4bda1261ef6b7c334a3633930851dc328cdc13e477c610e643d89c97710c96de2dd518539900583600a3bc6dd0943218d0e833019b6c3526c47ef08c542309ac3a88542cd61a40a839ac30eb1a01d0cbad8611004030af58a2f46fa833c54da8805ed7771b1ff3cb9d867954e9ac3ce23ecefe72f6ef61d8d697c630e687fb4b5cb93d9a572b4f04f4c53f98eea6b65156523128998c543e942860c9f65b950f41ccdbd43560ba7de2bf65459c52a85a9122612c23db12112e6e3c7fc4eb065638d406be4daa2096334c414d051c0f7d0508ad88535463bfabaefe9b20ef8ee7adb8af5f52057d2d8dd1abcb01b7b753d3e5ed236b1728bc808db303906c33a8daf47562c22a31cb839c839a0efdc05f9e75527c4867817b3d75544de1821c461d204083f40b022c5c550ce837f3fbd9cdff5dea15ce66e47b5ed327331b473f95374550c500c9c6e7cb34c8d6d61edda76f2fd2861ffbef85e12cc9a4ca77777f4d3c2e4967e3a324c34df363af76a64bb77e7cb6a3c418861574ad1bdaeeb8a44f26258bc5906efe86153d3b48c7455ecbaaa4874d50bbbaaccae1a4723edaa704eedaaad5d97a6c1fa2e56f96ee7ccf255df9ddb9691ae5fdfa2088bb023243d96794254d81026734cc7e677e4c8434ae68eddef41ee8611c2f79a7d70eea3399a536da3639085b2a12fd91b94975e3a02a67afb3bbc90edcfc6c43168d3fa5a30021de8702fd681e2400a34c869956a7c01115a910eb453ddfee1044516ef257b4219513a3db5466e5a252b061d695574676f44de9db05ba27ec80befb4710ef4a675d3828fbf6e10c8a2e7d6bc56e39dadbd8dc77c6fa46b1545b24d10e1e3f1cabbd9771c00f2eeb4cc4f07ed40072ec3dac16b7f55c8fbf65145fd1875a81faf93f7fde68e7e73e3f6e3d9cd761c00f26e6499f8a3c2ecbce550e5601a1b1f98c5004ef58b8acaed5497df703dca818afeba9b5bddcfe6684e64b1e61ead8cc114b414de6c9d7da004cf313647d822462963844760f25e6cd8cdfc38f640a18a20f004c136f169e253a240153647d8627637d76e22d1f9b6ec5e14450c6366f8306ed6e2b945d8b16b45300dbcf136479c9570e3e5b35f4701c9e4336b80e6a2361a599b678f43b4fb0f6d2ea28cd0be7db35064915db3aa19c84269160aed9b9d81a9f8ee261671591b3820001e05440a4101c1ee75ec5eb6023df747762f8b027209410111223fb206b878641689e6a24d0dd23ec4c7ada688375c5abc82be0d08bcb43b9a8b326218a5a7d3cfafdae1231611dd404d3486a14d51c524b30c26e5e1766d3cb21f61d36c8ec0e46647606273842d24943216d1a9286b17afc4588a9aa5c5bac4336ddcfe0d70022010810458fcdc8004ad3e637c9513e67c4866e0dc5e1420d7035375dd01318c7bd89beb3d1e984ca766691812ac67405947b288b06a388ce33d1318a09939d22359441b82b7b0f6a176432350f8f71db0fbe5c8a16de265dbc85fd608e58e95fbb5e411fa7ac561b8fdd7ef069fa5fec45ef3d607980c95dcec939fc020ca18e39cf33be09472bebe233e731732ae2aba222bf87a0f0c74b6883720bf1717a8051e0e388896677fd9fb826532252b21cc6557dcec4a40568b7d62e054f60c0da62b6dc770b8d9d96e8162979d05a6c100ed2bb00ed2b3c30ef02a632e1303e2300d3d55a1313dfbca339767da91205ade9938a6b99efd31bd9adbb6d96bb612a6d91a8b6b4ed19cd89cd99ca339e79cda9cdb9c4a5ae7ce3c9edbc3c5ced57e7d4e30d06bd39ab8e84ff6b95293a0e63578e71fdf9827cd4bbe314f30359fcd959a04f5969af356cb5d5a2cc354ce5b288bc1d44c916152596139c9d054b2fbac70a947ba1582b7b2986fa9dd22550c60d7f4474b7f5650963f2be87b72b33979eefce15436190cb40c275ec3390eb37fa6a0f39d05663da019e7b5239846c69dd81728194e6a381cc6606a3b28c5cd4830098944ba8d5ea19c7415d3ac9cc4031f89740cb25e4efa64010385cf0a6afaa3cf0afac0b8b2ecaf0caca379727086bb3dfbcb48cfae73367a85fdba8a69b45fc720cbe52d9cfd04b35f7fbc6a9ee6b25f77a9fd2408a6b2d601afda49f6e9a25d95746784af7687181a357878b53bc4d0a8c1c3abdd2186460d1ea08662fb8765506eb17afdf44fff98fa477599601aecd99518d2ab6a32994c2693c96432994c2693c9a4612c635bdb016a3151a321b51a97c683e8ba4a2f6da4d2cc156d241ec8ea1fa8d33005b6c3525eea0b8229c89823d926de108cd0cd5450e851b2af549d9bfdf49430d1abbf9c5e3d93c90ad35f17f4dd79d359361e26cbb475308cd2d3e9e7b83bbfb2f19896e98c0c03ed38a80777fb470e34a7a96856efc0141898d53c30959d32d3bb2c7b6bb8d98b434a7695da3f2c93fd65abc92eb53dd45cf6de81d99b87f4ec279b919e623b00acd8ee84623bcad036f1b29b6cf60b87d2a79cf409a33d2baca0720cdac12b4ccf0e793a7b66b2b0876e765907da71179dbd83200beac094135ec1244c055ec12bba7f9866e5d97ba85728cf60b2abd8aec5b82a5903ddec2c75421d78054c92dd95b3b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0bc6f467a4622912ee948f48ae5a4ab6c3c4896e9e361a9af0ef435e9d5bb59f69cdceccf09acc3017c237ba6859bbd7b50b8d95f4fafb467bf9e6dcf4ae77a85f2d26df4caf4d2554ca3f2d231c882f9cb1996bc602efb09b2fae78f570fa8b9eca5c35426602afb7c383005d4ab259e17bc1ac25cf6ec0c9fdc2c5bb14ab04c664d37a164375571b39b361e25cb74e62a911dc3283d9dde9d93613b8e643b55f62498a6f4ec48f42ae5d983f48a3efbb42912899e6235da5269875229a654a2512ad52895782895b85229552a695bbd646c8f33d74b2ffd59e99d8a643bee3f9d608672a92d95616a6e08b8ae598c457b60a02b97883a674642b15c73f3b4ce97a6ed86ccdcebda8680eb5873fd022a2f3a6f5a0fd40f784b87b7646d1781cda2343b123db342a012da3bd4503339a653f9b9d487fa347c570ed3bccf69390b39dcc99c29640ea43ea621a6799797efb2215cf96cced21a5c70eddde1ced64c71b8f25d690d571ed62e50390fef7cb55e226f0c58636ef50163cf8744e65c992d6119d9b0676b0f09b5824e8e90a55f40bb914e8ef6de501a6ab33fe0d50eafa6f59c2a502727e66a365b023fd2611aedf2a41ea69997d9453cd02af5310db18cfcf584469f7b64549b7859f569e289463a57feaa4366aecbfc6c09d3c45cf9a884696254b2376130dbf4bea04513f77bcd024d458306a4a1a2a19aa951e33c7cd6a83339543478787f86871aaa191ad67415d77c15a7a085f4c8c3c9a23b5dc87aef7ff19454e1728d270a6372ccd5ddcc17605666313b87fbe6a31cbbb939be57d939b331be5772bec3386302b2342b39053f378c535028b20cfca302b50216112396840da2f3901cc087019a837f57c0c71f72e4b0612326a67bb9ddd3b9d0be29d0200df4f37eaebec800cf34621a85184c62724c3705ed4e5aafe04dbd3a1d029399254f99253a63a278558c53b65f0426abe0dcc6eeb3a25718e96e57bb33ee8c1c5f471845a52bbafc5e71972fbda0dde8c97df274bc0e7bd89934e7d3736513f9446ad1a9972b6e8b640fd3e4905674aaa592e674648f64227d7af54e1742d8320d318d5018bd82222c9b224dc36e27650faa88ec9935f25ad86f5af34a5dbfa40e6499844c4226a19b846e4b0fdc30033274b1c50c3cd0ea1b1b70e1670b3f22e0820e3768f5658fec913e5632b9baa01d76e59730cd2fcba8e0cc3acc1ef0f21f8c10c6d7af6d87517a7a8f4094ff53070ceb558dca73f2369220a05a006e8c0c0115fd3a7c271d3b85acedd84fbd9ac7fed2abecd8dfab9111f2db7933229ef41d9d84f4514db23d23cd2886ee3caddb4b95744d7b6f36f49b35728229ecf4bdd9944eb246284c612fbd3705700b8329ecf208ed6c5cecd87740ad669f75c8cbb9a3918d5e09199dbfb8d847168b319815a2824b902d903b12043be871c28997f32e41e084134e38f1a478394e38e1846c811355c8f5cc76447e89fe722e9133c10417f8c8cdde93eec0cdce1d0bb5e01d8741337af7709a7821c8f983c18f78e01d760aa2404d3c29b27367b43b8de0ddcbcdb89ba9ba192bdefd7033196455649f8f0b4e9a0acc61d893d3919c9e9726b1fa4673be0ed428ce039ebf1c9e3f29ea7c22a8a33f1e2753dbc1c57c9ecf5501900a7854a0b3c4124b2cb1c4124b2cd1759d903f1da0d56ab5fa7441bdb8a0be2b68f027457d3bbfc18e3d92c5030192d7e0cf0a243530c175663083f35633856501b18044e08115665d6ce0634505a249cba002e1a48a0a4417cd01b10353bdd384137f5258204e00440a9cb040e88041023b1978c75d201978f70b2403ef4e174806ded10b2403efb00b240307f239638ab36c3c9e0744501f0a52f097e4cf03f59d400617bbc10d3e5f0a6a430105b59b90e4043748dd77e41db12d048689c1c56a9267031b7cbe0ed4d19f0dea912c860000062e3b3bb702d5812ae4e454212706e6652789201c051ca0172105e028e048027a12c0134410410411441041045180021460c711807300214a85ec0a6080808076c009b1b93705ed4edc0be4b288d62471342e6af07a9a6ca19ac3ec1db30fa1c59aab4df4803d542eb30cdff47b3bf0bae9a0bc1a86061adfc51ba9c46c474516cad6e2658bc82bc718630c0cc80b61169849956346a59a99c9a152cdcce450a972ccc8a89a79a1cdd5a0f10b637ac5d95061b0bb9f4a9523767f1107c34e277e681043c4610205185c8e812326f0bd77f84a4039e6c97e3f6088cd8862f6ec973d9d288dcfac89ebe934832f876fe642958ae3de89592716f6c7175bd48f26e295ffe1dec0364c29e593b2bbe57b0fcb5aa2c5fa3d36a8a18b3ce2bcde3ef88a5042f07d8c29486811793170b107667f76e52648b8bc1151bacfbeab90dcb711b1dd674b44dec5c0538243125dac26bbf1cdd1359272ca1963d4228490d439a16d70923a23b7c30049833d1f9344247e97b61eefd20d4523c5ade65d6a7adcdd295a69ab81576e358fe383a4cec88dfc68f933768ce24696c832b76d24c3e4431823acb10cf41d46d82a98f351e6e65e35110f7fc4db08688dc2130345d6016197208c11807177c4cf88e0e7c6ff1099c98d3d14c02dbe02b875449eff3605704b7eca6a240b9beb6c8d64814a003cdf0868735e0b9ef950187124040568c1e7bc561f0acca6ac40644f30159fb243e141f05acdc154bcac292b68f13beef24f3f2989ce3194f9ba7c3a626e9f8ef77e0c67a3597354affacec5d0ebd929777722228bef4686616f07dce962e77743dad8efbec7f760ec4262580c73d7af2356daf942e2125dd00a8987f2f518f0d42fa27794f5c7f8c95c7ca923024776c432f1ddbc4e5cd1dfe846cc7618b8a23f918d3c2e6882b71530ddf873a18d392e2e29a3f7ae463ffb56f671efe4f21ecd25e525e52b31d340291fb3cc932f5271ddf8139451475f57cebcd8aa29069150a2849f18e6c7c43c143ca6d731e63f7be2fac27c5dd7fb0bd7d3c5aee99a7a25df9799852a42645b6e767774cc02e58f60764b6498e86219961136cbf0bb251ecbf0976020fd7306d115e531ac66fc3280b10cb7fa82dc52f0392c527aea4e45cff5b5c649021b446998af619457bff48ae1d3313551363affd42b0d1b037def3015be2159ba25b61f7de3a7885f934c2a422efc7bdc80dc91a5cc49d3102d420c6a452e3ccb27e29b2f96208a618869002d684286212627f0ca71fb7347a77caeb5f103f42ada24d775ea7805fade69d70cf1933e2968915ea18048211d4d375ef2300d33e1e74ce0c4cf2ce99e126ee6aa13471f2326a443374884b4a7527cd8e1c6634773518b53a0d9b10b919fd73e3792889b64bb2143ae7c33c134444e6796d92ccb8a8ae6c4860152064a4f886ce9c4b2a262929182424bddd77e5521fdf9f9d955da77dd98601a22268c08d310919135c13444524617601a2228b308d310a19a134c43a4b461806988904819601a225be909a62122a21a8855fbc53222145a226d22a969d86714a3071260a0f14af4eab24586b4fc009d8a8f2d318b52a0f1dd7847808c5108b6f8b383b991483f5edd42f3c43366698053f133333870dc98bab1b6b458a1d86299e8033417fb03345e4616ba70547a1343d61835ad393e659ad78d58c3461725bb9d05ae4441b9946918c2c72cc3475dd48f4edea872a31d62ba8d854823d27817630decb1c6df678dd7f1c51a31368d2fd0fed35182506cc1931a7c5fbe1dd06b11bbde65ba710618eceef716d237bdf4aa61777777777777777777777777777777770dd385b0bb4df02f4d35acbbbbbbbbbbbbbbbbb9e8e23edaddddddddddddddddbd7a3a629ec8061aab017c2a02a6207dd88b6800b37a70aa4711bc006625d16dbfe0c2859fb9104278be1766e17fb0405647955e296d92cc46edcb41d6e964a2cdc1f84335f884bfee9ae30721ba9496966cbc8ee91ee42e1df21d7cc734f77ea0813ae23b1b5cc3f7ccbb01a5e59ab35163e27db95dcc7d97c80fb763381bbd7a79b9dc1cb3389862166c8b2ae2b204b8a9cb069363b09bd6757e0c532f0ba716ca08285036bf695de756ca8ec88ace2d2678d10631705ab2321752e404e1b478ab79635c226f0c94cd1520b2f10bcaad2c503f9a6beede74185c70e107a725ab8c01139ee8e0b43806767712ce862a3b9fe6e9189dffc3d331cf0fe2e98825193f7da63c56e61bda3f53ea6b952a0fb5fbc1a27723d548e91c70e1b5daf110c337faa36af906df608e31e66a5c787be38d9648142fa7d27374abd4373b3708c2129aa461095ae8f090146470069e2414210744d83abe20139d6f7a3a2ee698c41ce41bdaed3670e3398a1e8db26e2d26c7d07ecafb885958b30e9ac2636c01a48631aeb053c5095a4f06631012e2020911e8a086d63b6317bdb627450fd36817fe29e1e960f2744452939fe7440e310d33e1aa1caefceec8aa12a61aa140e53b166a423b167a3a34db2531591cd34d368a2ce255b2e8c137074f47d41e2d0ac89c96081c630ccda2e66fae76f8b783b7d32b9245fd90a42494680e8ba7231efec13ff172564442b156e0dd80c72aa9625553a9a6f6e1c5255021dae7e1df13f8d703ff7ca69022b07bd70b1a5b487cfcfc8cefced6b4e98510df38eddba239f8b784895e751da7e1c2c38e836e935e25810a21843e2d62c4b4c7ed31da6ebb66511115cf57d3668c6f8b25ef9e1617cef939e7531e6b05b42b643ee5747ba47c3ed6f9ada2b0c76b15783a4476db6cf7aee8f05abd00562fa01d7302003eb66fc7aa0fbedae314e8f3b18f09e9510a54f4d2d46aa71d8596366d764bc42f41ba5601d31d62ba5996c46463a7e2a1e50a3794f97aba21da8d16c53e2648a01550a257d476a5d3e65ee92b2c371d4e533dc114bc4a45454be10a8b3dd140c2031f9c56472f8c67b9e92b15156d1147582c2afea6a58229f895af5854b45c7330a5f297051593e5d68d2c2801a7d57197618a631442480983987d4cae5dc0c73c761f98ede2a74561e7bb1df5277af6ee61d9b74c647a0f6431d1290c92ac0f6b80e660ec0215fd4786d9eea1e2e745f351cd47fcb4a4cda73978927d4cae7dabafa739f87a2ebef074e11f13484f579b52a01df6d145df017f7837f8bc1191599a77838fd920de0d56357773b166ddb4aefa4a4063e57bfda0f449c9cae9a5bc77c417dd4bbdb3e13e96c37d2bf7b555e2dd783941394850710464f9f079e243f53ef37eaec1c0b8082c02612f810f070707a708bc023f07182e90c31040108238d0a0756384371c19e2a10309c8d0a4c5673ef68592fb381b8f39bd98b417a4b93fd1a9771c2c87eadcf7fabd480c03ed1ecf7def8fa757d126f1b0e8d593af8b68eea9bee3dd070c42c42206a312490c11fd2a02872811997c914444e2ea9eb82f48124a0ce9221003f00661bd73a7b884183b72cdddb703daf0ddc663b878624cd56d2845d1bb8fe6de0dd0a4bbbb9108725d419080eff8c911cd3dd10303edf807894ebd23900802e5102dc2db34f746b77f8a6896013af558aaa7fa3bf74edf4f710c137e051f3f8528319194121361115e5e6641fb8d49d90d91d1748770b4083aa46491942ce38bf1cfc658e57b5950791d377ee6ca337331e014b35a3c2be014dff81cbc123d5ec5abeb3aee8e1655662e6297984d92c92739095b20c3ed7e6509286fac8a59309392145c84e1bec73a8499bcc682bc36967669bbebba906bd3444caeec6ebe62b41dc4fa9217cd6cfcc5e0313b5bd41cf70abb22b458733d6a3902daa524f493d27718ca3b2a63e5dd8ce83daf524d95616abb8cca30457a4a45a9346326b108ac8703472592edce71aa992baa3b7098c9cd1657f470664e57aa5ec33d1de48ade3894993093b7b5688cf78304167af1c132f09a871b8feb3e9048c20679e42ee46cc838ecf1d1ab264810e01bf0454e37022c73806605b1699612a44bb248b00cccc226e5320e05ca4d8722e5324ef2c134a43bdfd663bb26e32987c274944321e3292725c074941b21e329dfd12837dd08949b64dc8894cb80da4924d2f6579a275521af46fb8102b209e1fb467fa4a98d6a562356b51986294eda98b884be772f42a4c640101f64ad7d8831421efada0a2f31177e7610396fcdf369d724f37346157f80f31da6bda3db1fb3556dc7bb7a08f4bd0a218ddb0fb8f2f0442f166f170120d715d9b34c5b1bcd4199a357fd43aff8d921dcedb745fd88b715e0aeb42a1bcd7a39c13ed6920b5c5c817f943c298224c134f2f0129e02ccf28186ab6219781f9085a3270b171280c214fc8e963d81f73cf07490de8d23419e8ec6797260039b8199196b8ef93a373e46a689c76e0ccbc4184552d20be50f9480832bba10230071c4376e44e9b28e87cb7fcca23015b577239effea0ccbc4cfd163a20f444f070dbef14e004ec5c71b9fdca0428cdf1e1cc25dd165bb23eef51424f471e6760ccb64bfea104e74a5e531ca2aea1d7b8c3f54d4b3331c10e8296a41df19e8d2c2860afa98d831c80a027481aad629880951ec4910c83af111d7e191e855e7e38a3a161ad5ee94e89eb8a27880e6e0e1219c690ee6886aa036ae8e5300ba58133c589ebbf6e0bb4d2ebd7b8ba15db4f198a34ce3faee63ae2a9d740ab302cb60ef76d021a9c037b0730fdd6119ec14b301a52fdd13f01a589601073368c1e99a823b1087930c8239ef6224601d38431783ef2e135cec310df4c516d0777fa7487b97ba0c74b15766492abc2d840315592359d8887efdb2464446504310705a22fb73c183d3e2d607e01863b4b2e87717696cc254aed7125594cd6504052ffaca2fbb43a5a26c548ca0e0576c7c02535804bad855ac0f98c27ed38249287d867d5e97485467aa0aa6b0c31b50fa4b8b6b49af64c020292ef6531928182ea6858bfdaa825e2cae906160520c7ae4a2e26287676066d8068673e0f8818b3da2816201d96d7a9688369b1e2cb0e8c1a26749677d9b1e2dbadaf42ce9b3931e2597b71e4b50d470af67d9b16be391615b266340af9d5e75d76d7a9634b7bab0b0e9b9a2e70a2d9a8545b3a44ea7ae1e9e4cbb215d8280922af07250ae7d8a3409026a237760eaba44d9c4bbdcc51a914860ea7afc8dd481a923f4e65e8fdac6c3a64749737cb3cea04dcf921e2d9aebb982516c7a9034c7994d0f4fcf15bdeaceac4dcf15d407450d4b7ad5ef680f4c5da73e616437bdd40359453a95fd12e366b3d49689eee58860e5ae56bbec510cddcc0e21897aa76b9e7bdd54bb784b2527f73aad1d87715d46ed1e16f77a4a6d22de0ee5e75eef6bc5ede42ab9d77be7e77a33e925455cadae7d60ebc0ce691ceebaaeeeb92ebed7e85d73d1f1170c06bdba1706185f740173ee7372af7397ddf7ae93d07117d7a589b0513cb5dd491ec5ba9c643bcca532a75035d727241285106d37de7aa0d41aedddf7b6c3ad88b7f5e041e9a3bf8b72d227d4a44eafaa78f7aaa1735bd49a8b8441dc7a943efa8c8d7289722949d7eda0b8a4c3adc77b0da3bc441a0a09a5d69969f3746ad3720c16c13075d2943a31c61c086b7a90ecd0dddee5e648e7ed07a9f9bdd742dab61ff2d2cb4bad90d24b177d96eae893daee5dfaf9aca02dc43442b6f7edf9eb5da54e95553cfeb9a4f708ac404947b9db516a8771f6eed6617daf1ba0bbfbfdb8f1e8faea407b4e92d469eebab482cef749258a9222c3a4d2ed032ceee8a5c70d01a3973e6be69defad86c69d76feba935e44b1db424c337fbd837ab5fd7a83d1abfef5d9a26f3544de18b7e78ae6b73f1add2d5f40b74fa93d241777d7d43be346fa8b026d309abb4e3abc5aee04dd4b8865aede6ab24bb21dd4dcf5ad7672e75e8f20a0dd08c9bdde7590cfbd4eeaebd205f452678689e64423f953cb9c53c42fdb78f4d6e3dd868f3552c781bbfdbadbaca3779d1fd579f5d53d34cb44736dbb212fe74edbddbca5326f3c687328d74d4afff064ced2a3d7c663e6078af1c9063779abc92e37a76da58d074b106036381b39542c839e4c9a899e4c9acac6c3f412a386f1cac6e34cbb0cdcd61ea53356c07782a6b61aeca1cc32f4a2de3b5398ad26bb33cdf15f0ce80c007ce3c1b1b9d309f5e3b6bd0013cdf16574805b8c7d74de6ce67c561f4321063a485ea6684d8b5200b7284c410eecb4b8c346358aa7c515702a0a07ad594b4960b2a435e5a3c209661852697169b346d15f84200e405130932fb4a6add067093dad1e9c2869cd4c8b34e0b4e6489bf5746e02185ef49ca6362ba77a411ace30b343a545ab59b0832b28f1518b30017d99a2f5a47085244b5a24309461496b6adaac1c44879ed6dcb459712cd1694d9236eb0068d0d39a295ae51e325c21d49a549b5565069cd63469f5a5810c530cb5668a362b8e181c01a8356568b346c154f802c8a4cd1a850e17e8b4b0f6e17daa68b3aa5e20d49a2bdaac4054e1a7355d5630862afcb4e6499bf5b121c94f6bbe68a3aad2a2356b5731052f785ad3459bd5072a845a13a5cd7a230a40adf9a2cd2a80317e5a13469b7500423fad79aeafbb5618e5257a58369ada467a258a42536498aaca0acb89d65a5b5c502f3000b88a247fd31ad59bd69cbc5dd767157d54b1c73a379bd131f8d1e766332fb24682c014fcfcdc14c0ad23600a5e1ea1fdb8035ed7a390ebdb8fcb62194ca190ba0d5c69e3af1bdf5ba2caadd8a239889ee8c915889ee84915889ee8c92adecd15e145c1642d46c7005805590760d6914469aa6e438d88249e8e8c6fb0584de6186e77254cdb58c73bf26ef4314c4aecc8d371802158a6ef35142fb30cb3cc3bf2ac409f7cefc8cba18269de7b65b8ef6fe3f19ee8958ca2d6b26d3bc026c4cdb3950911115ef5e5bbc8761c868a0d1564a9c0ccc498580663997e0685f95c604c335f525e52767747861d16ff7844eaa2b8d2c62688bc316e1f6399d7457128a45dde77e5fb8e8e92673ed3cba9dfe310ed77268d8641df9909d8b0c7e48e1c5fa41414be336995c281f6b13303282fe109fd6b095038726769524bb57e53b801e95fef0dc8063a791fcd654e4e59230b79ef1bf9da0673f4eccafe904016f3b353d837fb3bd2abee157cf647850e9781d7c071b819f623595c2323443ff28137462b0bf91060ad9417b95b92ba9b9b84a26a78b8f2dd922d862cd448fb8aac4ac027050d2201a691cf504650284a19ca881452c6cffeac903bd927f030335036dc4c0e373b0659291665437aca53ac9194937ed3ba6ccaa45589dab1d08d955f6bb646eb13ddc389dcf0881ba4b9ec578680728b5bcfee03b2549ebd089b23a62ac7b66dbf361edb9319a679379b611abed95517addde26d762bd6d17b9ba715b6644d22e3574d82f2514d429f5273b056ca2508e868c6ed8895f3660485a94bb336a4af58232af6084519599bd24dd6488a3d92f20f944a324e51b4a75494d32ae3a3dabd1c9b94a364541ea1a36bf22b21f2fcc5cdce1b112c862bed4c73598ee654cd659f5104a3674fa25906d8d15cf61e4d055931d9bb999b1db2a80dc24196123088fc4096dd00bd92cf5eaaa44747e72cc6645688cc6e6493a698f04dc4dbccef469aabc92e12cdb53d8265fa35f0884ef531ac4ffc64360b09d6ee112cd3011f9065c3864ab3c123e25058f9f28574609626a01d3d5dfba6c911d08eded3cae167cb554fc7f616de6cf7b68d8879356debe1f2eca65ea9a87cce39bba89d4ea7ed64bb9b7bfacb0bf6ed84b2425eaec19c3fe31ba38880b15d5fed28db758ebb75989df172eda777459a37209aede1ddd8fe828279cb5910a0fdd0ce2ddf98679ce55d8edb7297baf5389de769863d9d46334ecf4ed8c6a3e50506a6f27d61969acab976f4c236f2c4b6596679dc7ec0db728de5a7ab9e0eeda722cd1b8feedd162b84e346848aedfa6ed7ce7296d3e73b986799ed725c96bf08e16f3fbd83b12de78d88eddcbd53ed5e6c8bede2adf1be54e6c36c56bbeadd60f96bcb51957e07747161e9e1e9606dfbcb8bb6bde52c6729d2577339cc69e5e6602eb71eda85b8d897c78d08ed6afc9696c38d47cba9f2e52aafbb69e0f6f074b0fcf497f34f7f697882db0f19ef561f493ba1bc6815c6ee802c55e52d3563ada5a519a6a5e53b608b6963396f3f444177c59ef8bec9525fcfad97a310062bee44d16409600e7fda88e8e1dd60cdaade8d1ede0db64520cb08133dbc014c23f6d4f20bdc5c6d3bf7b05522f0aec0ab75515c212f3c34dbdd300968a772c272bea79697daf22c83394b55f90bbc30ef8dc81be34a2ae8eb4b96d359de52bb9bdbd2f21dbd6ddb7bd497f3c6a77a73b916e9fb627b78375858be03b654186baa2a2a3ee8bdb0fbe1c24f39025a448efbc59df371f72e6bd5ee802c5ae5e63496cd12819725e34df574a8bccb713bad8bb72bd23d3c1d2a56bb9bcab7cadfaedabe55ee6e2ecb7734334b75b195aa5c45e973f44a8507b54cf90b1596dabdcbc2c2b6877743f3d12b9595cbb58b800ad92eefe19150a257bcfd64bb1c36490ce99566b543dbc3bba155977355396f3c5cbea349a7ca9fbcd5b4fce5a7cab68b77426de5e5a70af3ad47cbcb57eabba7530f9895baf2775fb8c27ca5c2fcf41ddd72aea7afa89ceabc8bca7b783af8aa1ca67645ce39ee8eaed8e514f45d0c01912b46297693e92a33ae65873900ee82bacb76ed2ae77ad2b4a3c040c2a6571c85373cb9f0470061b9f6cec855e10dc8e9fc1d8d7ab9663b14112ddfceb7c56edaf91ab97c95ef802ab56b394a3dbd9c5b88d0be11c172956f2df6878a3d6d5dcb278b56bbed2adb4f2f6d954565ab2c2c36e50554b3fc928a15b272162b0475ed45fa6ae7da6db648ff273b0f372018cac6e66e4fafd90e007cfab7218061ce1b02b2c33ce38c6aa76f2a1afff42da31affa4623b8a69676dc68cd319d7ea0cdbbdaba99c6d3769e53f4acf7c191a6bef21434e4151402e7fb32b7f16f503fb76ec9bed46574588ca4d6c52b9e9a6daa95496d359586eb69f3696afbc371e44faf2b19b4c57e9c162bbbe2c477daba7da3d714f2f87816969b15d91bedd0520cbb3bb9c7bd5f2edf496cacd9d564ea6a31c5589d43cbe2e554891be99c5c0bbfc6ee572fbd140b09b6eb29dcaf995e56d44b065f9565b7eaa5dbca7b7d81df0f49473edcb725ef96663732b2c5688cab1afd4ae485f156bfae46ba237a5769d913befb2f1a025316e9177319b2346fc78b523f14efbfc9cf5881cca36cdc16ddb0ecf9b3540bc23ec3647f46af2e75cede0431f7c3320a2a08b59ad399be306e8d56593d4c30a5542373bf0001734c869021a526084160c82083929b8021590c08235b4e099807f82090fd0cb337a001e60ec0453103e5aec4291d6f0825af77b178450ca5ff2ddc85d30de2e123172e3bd2e84dd0b4401792820ef624fe0a106d7a928e56d3417dfebcbf3f04e4a29cfa97ac53d96ae0480f68ef4f26ec6f66e83790773e5bc1275e5e84a972bb32b5bae94a22b5964bcbb7678b77265cc3b952bcf42e39d8c2bdf4c83bde51dcae95dca95f28f69b2bb5cda8e3bfce4aa8abbe42417afea15db9b6ad453173303658c91eb95edb84795a35771269e46cc0eb61e0033605e502e2d2716f915b9858abc49867c8a94295579526596d9aafca866f5b18c3c26aa51f66442981ca3d18631c7ac3e3a155f10bddefd808373af187fb8913227fa0fa25537e4621a73a2bf8a6554839688918bcdc719e315b51f146827c1d363b852c538851debd57626f2c48df192ea636ef4583b0ec83bbaf3dd09e7b1fa361ef36a95c45d0552ee7bcf2c6676639957bb266e7f543bd27d5ad65d60c3a4763b465b2a45d61a5e41c5a7bf9c4effcbe9f4f2d3b1d076371772efbd39e1c603c34c54ab2fa7d3e8da68746d341acdd16864639aebb08f84608fd847d819fbc31eadea6296cba12ac2264279682bc0ddf883dc66b01821965d5cd0978d5ea9f4ae25a319e3d699151e73f22c2116452df77459e2ca55b9a22ae29494f0ef8a31c618638c5154b915638c31c6185d5c48d15e2c232fd2c0857f3ec83fb9810bff627c22d1bb8420eb309907ca3df734f39e0ebb0c218410420821841042082184104208218410f6dc1aef301aef68ccbb13fcad4123c676a70b217c48948004da03f9dc407920cb0689c78304f978b6b0dd1161d0165da144f2441e1ed1df15cd758fbe419a3bb2f5b01121618b961ddf9120bdeadbfc5e3784314a795d22edf5d008315213260cc424484bd1655f132641a0cd114800bd2630f7381b27c80ac2a4b9ec0fc2f79bfb2cea4711cd6d356da3a26afac2ab9abbeea82e81ad441006821d3bf57e65f5d4af0941208beb14935ea130a7b2dd9019965b50a8eaa7a4b9c7c35b8fec4669bba7e4f14c413b4d5b3ddb836d60aa985e4578be3f3f586e32c34cacd6dc0f4501841046080f451611c2f864074b780115bcf0d3ea77fecf0504ee4a1c3c9c43dbe5e828ca269bcf7ed37a289b6b9baf897859188f2ebacde8a26701ad0de99735729d7423a28f7ed3ea9e126d5e7b48200b65537af6cc1ad95efa4deb1dab463ad59de976efee72df1768179fe0a13c7459b87dbeff76fad8f300edb8e789c8f7d98e6e0828f26e5bd1dc6b0ee52810ca2434daf787d3dc53c20776114a7e746e912c4a5a5402481fdd0892e8a3438129b9ef464021fac8b2ed1ecf7da33f284a273d5e84c91bd0924591ec4382324274ec9885e2bae8dcd22cca66f4762cca08eca38f2c14d9b173aba3475c4664f6f970b7e7e7be2b898df96cf292ef7565307bef6197ccc1cbb97ea1264140dfb90f217765edba2779b8bc216074af1e2caeab478b1e2c2ebcac4d0f165740785d363d5af4f0f45c81dd1e9eac8bf9c9f55d52fc7c0da3bca22d42bcfe5ea1307439096b00c271390a4f904213f1469d4f4c541f73089b58b944a2c0b959c7df5cae87424c75a3fc42e6c4439154c525f0920f0706f95c28dbe7caf7f37e6e3c8cb291b44f238112768fe7ca167a43f1b0e65d8cb11f79d8037b6e3c7661d707491b0f29e3e788d4e77ad51c7bac60562200ab1df632d2654fcdbdc4f44ac6d3cb6328cbc45f36c9e8f1f1a3aa44860c1a7befb55d72b9e7f2a58e1aa80c283c61cdb50a6608f1e376ce01ef7c6a6811e3a56528065494e45df6f834d7120453fd4e36e9b0db12d4220459232c6b091afd401b98806e5c41bb918f895b2620084d40d00424b71a005c53500d6837f2b9ba8be26e3ca26cd16916f9d43bfa91a39fab84c404f42670b36a02fa999f5b7d7c030a78477f223b5b74b47082db4a80464d9aeb192dd0c2ed16aae47666996544f58e7c463ecd35d6a3262d413376463eb7dfb504596619e9d3abeedd26bd122579b29fe5ae300533b4a749415e22ac059d8d7a5a40c5183a5d161e3e301fb6f1b894ec74d845828476980665c89021a385948d01e89a01432345c54451627640d5e02dfc40898cb31a244ed0931f9f1e16e80ccd61cea8f6c9d38155f16e603bcd612fe861810e16d41c76861b1cf79f4e98900e0a0a4c4d79b27db1056d67d884483c20f19096908a20d2483d295d74ca935ed978367646f38ba76303da827aa512dacec02b551b4e67b1db17177e13822cd5108907ccc22104120f64e150425ad2ab219e908ac0ab21b8b022b422242424d462372152cf06d406a1d306045942cc805356b48039a01bdc354e62df403d477a5041854e94126b3244931f91ec19a2670826d815a7a01d4b410b2d96346b46a6d5c002080f102440ac00b2d31c902a80e800a102480e109c1d5e6eeb911d6abcd69811f31a40a680c2910ba40323b8f01db6820bbf64464c0dd10eb606e78b1fc89af104b26080302658d633ea993a5383a15167dc5698d7facf987a24a6dad3e802c80b19940489921f885082b0209670b5d68080072005e3e800fb003f918c626c0d4e174f874a08a857433cf1825743704102d1c5850722288824412809e2072220825080080222080322e802220888a00b77825872838400a30cccc1b741486a810a4e48424a67088fe6e7a7a7e70708b25e82200bf5f333a7a6511fbae003900f5ef8d0051f8256495648564a563f582df101c8072f7c085a255921592959fdc087201f827c08f221c887201f82564b6ae0d4a0e2c2d7c0a991d32b794ddb36938a8a8ae913a592a0ead4145412d49d9a85fa5381aa173b35c8349297a8ead414d49d9a85fa5381aa1775a7eed49dba5377ea4e0d1a499348250cb483015ac2a3446707c98c23171e666806ce3644a27112090506856525c346523404040890234070580608143e70e15994ac64d8880a28479aabc11912a35933c2b8f02e412e42245249c57456517103ab0ca9cc01aee0ac206165c98acf0a1458563acc65e567c7561c4c4cb509151c3d48680d4ecd915e5d2a43bd5209b5ca1c70204b35b4820466e110c2ca12c8c2a164c5a757433c598102af86e002cb0aceca0a0ecb0aceca0ace0a8e8b5dc159f951b541252474e3643b8ec576cf308a9353223d59226b4d07f806bca8d67c80658e442a74606aa7392b9a43c25343c5d6e0b00c7c4d32e3574d028037186867636787470912c87ae1812c94ce2ca528dd78a89c6e3de2257dcad06ceca884de8d4b3584430838940cf164082e64d8488a70f4a886700861082e0cddb89d6a08530d8d54435235a485a1211c3dac634387657e7a6ad49a254a608a07a6aea841526b766aaaa8d1a95151093d1d351da8f980500d0e1866f84016cccf4fcf7d590259289d1d243c4e2eace2e918e2c9bbb1f302ac8a8ba327c582948e6a483507918632af56a9428421c4901062c818e2897c72e14b55082429387a522c50cd4184a307470f0a8e1e1c3d178e9e215cf8c6d14395b00c7c03d12e252828284886cf926a9dd033841e6831b4069f32f420d102cfc9e6a0a458219430b9f0409440204b80f4f44a9a68546ec13013703ef0c6a8c1b12104593540b0262768e8c22f9840c575a2e3e449b366bcc756fb840b3a630c2969ee0cbcc2f103e6a0f6ee0607778484186219f821b820c67dd22b21e2c01c7c4f4a4a07b2844802a7c6587287204b881e70ea074fc00287925e098103e6a0d08d325c789494ce4ce9d0944e479fe08494ce853b9709383b171e8646adc9812925387a7a5806de56f6c1d103593087c7e1e3d38445e58a2b784e5aad396f595bb35283f305da6d3b3b9b15cd9a71f8d932512f00f884da56675c1a35e2e0b46276a8353aa85ab35393a38409385a286182cdd30cd82c3356546698b293addcaa303f0c0066cc807941019d5a0247b8b27065e1c2c28585eb0a5d7481842f9e5c5740c2174f7e7e7e809e38e902095f0039f9f969e2e4a7c4bdca3039554fc7b4dd9b6fce673b4d8bd7678c337e36d44ab2b1ecd9e8da9c733ed2dbb64c9b28dfd1246df449faf62ec7cd4ab623954828b61bbda3a49748b6dbb49989de1f6598c87697bd8f3e89853120618e2f725d63d0114390189edc1e2e47410c575c163ebb9ef5f97ad6f04229fa4504de4cce8edeaca1eda0edb27791bed7bbaeebf044e07d59966598edb26777d12edbbdd1b957d316e93bb2d975ec326917166410e306e07214c840869efb4a70390a6350726709638a5df57494ec157f8833d176db63f617e355bb99be321375f1a6bccb71b177396eeca1877783f452974adb4ba548af7a3adee9f6226d89c06bfa8e46b94efae93b1947b13625de922dd2d764bb0bdc74326c91beaf7494a7546a4b3d3c1da3c7936a0fefc666f98e6c8759d3afdac3bb616aee590de55d4980c2f0749a7421723c868944efc9f72eabeadd88d7c6e3c518af1cefba2e8a7d2d7691be700c538e80f2639a7b4f9a8032558d60c51833cdcb9ee50851f0b409b5de9e9529a01d0637be22a042b26bcf4473bb5637d145e7ed3ddeccee80d29a4e2fa6d34baf9aa3444194f204f4fabb2f22a00fc273364671f477bb1ede0dcd86818a1f1e8623173ec6460fefc653bd1b714484bc323e1dd276379db43dbc1bf117b8b9d7bb8e9b135d98ce94e798d833f0d7cfd1d3a3527432c94b1dca977d79e5310933593b793944bbd06ab14709eff5a5dc78bcb328478cb17b50710f39725c2f06210a62a8a2d4bdcbb1cb71bb7e91be0cc5e52bee002e47c10ba13b7946ade3eb3746a278224271f9be7b5521448cbcda710ff3bb678b749783c7b5f1b8aeeb5ac56aca0be86547b68b57f6e86e84407b65b6485f78ec3dbedfc3d321b242deafbf5fb68777435aad39bed176efd0f6f06eb43535c79f2ffacc61c915c0e528cc21e7ced29c57e477910891ac7922db1979e276fc227dbbbbb9fda0d0dd8c3d3e8a627c89b1e5298ade424497dfd19748243a8ba8d6dc93afc93039a64311ca32d1b985783418fc609386248e18378211c3b897d0bd0e74afcfa17b9d87e6fb02ed3786c9c715fcb9d77964971565440b14f22de756ac28234e8f3f7d8122c1a259d407e5a753d74f4c5ca48e0dfae45e672d507ee415f73a5df3d23491b6f5a07c5eeaf48ad2d3ebd9242eb20a1d978b624b3eb6c4a4391a50fae83cf58118d65148adaca239b9d33e5cef4e28f5e1e0dd0035dfb5185ff08e6596414d5b93ddeba4cf937ac53c48b609d1ed86f0cfe5e6506c87aac9ee767adfd01d3273b9b90ea58b7b1de547ce80f63b1427f7fa567ba8b926b8b9cd76508c7b1d0addeb1d0cba3c543efe49414bf77a162d14f12e97168a2ca09047fd97fe4016ea2ebf609ee4e5b4890f64c1d89213978acafef29b16aaa2328b4a80bccb6de45d9e65d626fec51a413dde88cbf4c9de5127973995b54df2f21d9d55daa4b98bfa4056c9c94bc949c949739744725df2489deb720755afbbc49d7b5dca80720f8fec13f59bd685b279797171d22cac85aa8d04a62e97dacd24cbb2b9a3371ed91f9d7f4f9efc40acf64f3b69ee5251d9786417d579acf6cacadf90bc8b7d43281b97a38eb246e25d6ce3c0d4d54d7ac54d985cefda4cdaa7b98be5d71f4fafe0e995d1cd92a10359251e98bade16d38ef2aca2bcd194955b2c757458b3c7caad124fca2f2ce53c9945f969ee3aacdcb5e9b96276b13bab1da8242cf5c5b19e750ccd8c400000009314002030100e074442b15834a02b9bea0314000e98ac4a645a9a87490cc31042ca188300000000000000820030000030f5ba3b6df8e2a98bbaa483c84a878344d4b604ffc14019da9479c7a96fc80fc692e36a5f9ca7b0045075062ccc4d8598e78068ec1d7394dfb2aed10356561fb0587c09cfaedd38f052e3d2e184aea53e1eebf7ec97b837f5ef25f77b45a1110d4d31927952191c89d0811658e1a3bd962c010e0c9fd3951df86a8258cf69750b521a0e9898dd2329eee3a1bbbfaaac7dc064b15c93c2b082c7ce29c0e927c30cc9bcfba7a856e8b136d7949c7018b220e2e0e8c7ea63d7a17ec53a9555a123b3e39e6b62fb0e53b8186b9f59157566ff1dce0a2387490a9b139880632b89b1f3e9bde1c54df9c466c8164567bec965828b1bd728e6b8ccaafc998bf0f592f2155c4566b1ebe79180c12d0834943894e6701f3705b71603592d1b188bd132b4080fe777ddb3149e901feb4cb2c53a4e5506eab5fe9f55d14d990842b1b8b9fd63baeafcaa71f390bc2de396b30eaed052f1be6598e31d1418303f8ecb1c2c78427ae8a3d95eed9fb728a0a2b5876a32e9fa5119400b1f501cec3a5275b4eea20ba9c5091447cc29b3682af356255c2dcaa095329427dab4d59e202723e869521ed670c0cda76a90fe59da341d79249f7836f8fd2f4db7e924237fe1c774911735491ca16261c1446bdb29e4ec1afae4b96b5f50c5649f29bc752b51c3466c4c82c78101c70ab92b7b394dcad4fff0428da5e40297227a4829f6432119d4e5b9b8fc8a04df19bee011441ace7e6e85f3cdbb7fc63a371d090eaec6709b04de9d3a6b320aa27df9f3fd949682de2069a96114f901b706c739213b9334bca03c2c85871aa136d203805004ecf46fc34144a81036ff0df49866b0a126ef2b169f09a2f2175d896e636ddaacb1cf1a0dd6ae6bad3a61ad4a9a2a6ef2312d7dae4bbbcf00c459c0b651198e1d6251c5a9fb01b716c95fae1bc1694909d12f3c18cdc1aa7017533acd4b8afb8ec49182427ae18e7d1a067a00e2f46040f1b5fd1fa6d296f2b44f092093f5159bc2f46476d617c9e8fccab072daa5455b9c55d9a8159155d3c3ec2f3360519af234f3545a58a84c1e0ceb0c8aca87dc9494c6b4a596f66e409930910269b8c9dfab7cd34ecd5ea60fe991842601bdc8c41e78a8450442da692d13eeaef5774bca3be4368930031a3b91e6ab4f37dc345377f432def9736211f8e1c9a1cd233e5ee8d9d820fc53f2cf1c63b2b038e610b6226c49053ad42b200472f2bf7b5c3e3b7ca2a188e5edaeb2e93aaec504df8ee601bb242fe9598369ce2b2b48745acbe2f62c867a629b886e5b627bb7f5cd91a552fd8afc7785b0024aa305e75be86464515b2b9a2f88ca114eae87648486f775a4624d91fbe8ce2b2d9f42f0a12b7c30905ae5ab2c459260d101c98539bf7b7748e51c7a739e496afab937b38d00beb6255b2faa8dd81af65ee19c38faee8213daf16552d29b3fea20526f070930695bab5327adbf54b09c7128e797d6fe520a6081a9e3304f2aeb8d49a348df7717c8a3b5d805c2f6a004f410918e0af4fd338f58002074100b2e818aa8704299e591a49fc245af5474c3c7e924626f1dfdd456bf4dab2cef2e1a003aa6945d29e80eda6e89fc44b16d08aaa63864e0fe1ead746ff2fc5cf3c84bcae60cb50fb52ed7bbcad9a0db9491a43387ccb60228e27e6cc05abbab2110180d07b6867cf44a6b6d66e3615f9f727e2b5a2599f2f87647d43dbcf05ccce06670621c90b79f7dda98f1bab7e1aa75b94e2a1468819eff1c231691d845ab10872486ade8e1c99e0ef44ea7e221c2a9309fb8f910a9753546dd1e41d7045cb7d7b57bc44ee493000b504ff8070cd63c5e7cba851a96835177438f52b07234102d16f1fc464a42ccd4c9d3104caa5fe98a433180ed97384845c72cf62cdfc716055f479a0b8701feb94b23828dbe54a45f8da02f29dfdf2e527765a00df4e59a84c0ba9c4c33abe55cb93032efa2af9d4e3b6ac7507f45c3312e82ca3b1dc2f23536e19d2fa13a9a86cc2127ad4fbcc3d17d484b934880b896800d6a8bbba405f75b58da4b4c2626728f625e00b9699daace5f0dce48e4f09bf50c61fc19d9d4d2032c820e0a699d9bf0beca1d8dbbdf63af31efd3dbab6e6ac0932b2f6658b0952cced7c02fe59c705650652faa6ab2f3e12fa3ffa6f5ff1e1e16f5d07c4ef3f6b3c22816519c3ba88f82e1be7461e14f13c2e7dc5bd6696d19a30509855c3e99751a77a41550d80583fe0aa5aae687840e8e3ef98b77ba78963bbc1d65dee4548380fc4fafb34201a5351097bbbf6b69982b53c054bf9f404681c9d296066095f9c577a6b2759674a446cc80ab4b1b1bc76566b413fbe37f8eeffe516ee7edc57479ba631470d788d8b7f9c01e2bc6e0fd971f4d65f71c4489f52dfcb7f13130177af26d6111f0624baf955ef51d6c15838adff79478d25dcc055127d23270a63fb912635e48d4848ab2435b4a072e9289dada1918657ac5d83ec430161ee6aaf00aa2c4e908c475b2d121470c251cdd8f6a96b35ba805a0f1a0d91133f61fda395e40b11eea86185708f90b3cfa029f099695407e4ef8cb97c4008a7190f5877d1c31fe412e78c09f46b2e1c0b492edfccebcf2d7213c35becb7109b56e43a367a3eecdca4046d77d5a60ad396365616a4e1a81ec7ef16efd769e193728bff38c372b29df07c45629ec3d37812d4e9141b461a56ce000d6bcb3bb2a3a214ce1846d66e10fd307c51f7fafd6131ca12ee79fd2dfd37db27522be7f626e04d5e90f1ce3776eb7bb4d95d43b5d078c35762400b68d9d6c5da5d106ab81dbc30f5cfef43df4e9828defc52984bba11367581c2224efbedc761a0d41ec3dfb08a9abf78a18b0bbaea8519768d47311dcab1dde8bc5222d917d4ac0039bb203c4140bffb82c80f2645b275947867f37e9bcacc0ee45871ec2978b03838d64fbb1911c9395ef6b66fa137f8d8a9292cca2aff128c79d5f171e1a889a9a44e6cb4a1596c7b893345c48ab401b960bae40085861c843504cdf95a779790660f73d90406a01f74991002688770a82d0cf426efa04fa63ec55dc6788cefa26c8e4fa678cdcc9816e4c8deb222725d004cdb824cd647f31e04336a73163796752db03f89be21b9b1aefba2fff174a14b2592f863cbfdc8084abe671282e67786701e3de91b605102023c83200893d5803670c4a299a15320c30034791ce8dcf79d4289a35050916f21a60c36ac917c5676ae78301630706aa591ad8e4ca3547612aa1dbf1c5f2ec9b0468340b930d852eb0ed137d1326243d94383fa228a3ef5d06fe582c68b4aa441b6dad283abc603c6fcc6b586f877dec7106ac876da41220be5174291a34da7c05cc7f82d10a25d1cc0d4b69d5904bc8efab6fdcc55a8134f7287d079bb050fc802998c9d32d3b75268d549cc047ca5a7121ddd0180e66510210fce145809147502b8d2f09946c81e3fdd0adac4658acc52abff36d6c14b4081ab78778cf8c60b8065f7c05c4b37d562ceee8a450d9d08a61ae6ddc33394eb7877a1eeddcde35adc2bb8afaf60fc13b7680ac0cf235a3f1e8e9e13c771dd698e03a76ddfbcb7d1f7ec5e883f0a2c3c97b3f9bbd8c5bb67704de7a22f6200ace0b9f072a4291f2074a891896fa74bdf5746fdd2d6871bbacd4a741e8bd1c2ff5c5501b2aca568b72ad716776a4d73a328f8d25c02f85aeac99da3fc62db58673833f92a48f5dbadb9fa1e1c846380b65b895688a00d850b9cd4315e65f6dcef35d9ca7d739694956b5f92099307b61769aa9807bf369c4f843a84f1045d933110e29be671c6d0b95b42e44d9ebe07f6b86316737b1ca64a973a3aebf292a7cd219d978f8f4c702e51f64e447941ec9c81730214f701052f22d42d252bfb7ab739bf14cdfc91a11b5d0c7b9d109677df358f6fe9b6c1dc2c67723b01c7248e4ea63cae43359ca85df4ca0fd794a82707f6b0a8261f9157c71a860e4c491601839b7ae97214bc08a73e30272685ed92723e17a9dc61ab33901489a5d044875736b7d2cc253782fa3838b5f4750eec39f636ebf4374b512932016dc2de2c2a0436616a608b22656510e7c7758a6b77f0da539e4700916b74b5c7bfbb9a3ef7b7013743f7bbefd04152754b1b970e05e17d92ac1d413c1dbdb8f037886020a923e2e90c5fd45ab4db8113887b6670d7441ad25ff994b1f051115f773d6a8098c43d392e665226caa357bad37ad72686b7dda939a613b3cd5d58977615b830126cf65001839447043f43e169dfb3b4c2780246be902b3495e413df65be42c1aa48514a67bd57199a94fc48964ce6a78439938367f8ebc5fa52a1cbb5c312a112f49668f20be5fb30f5958390ff335715eaf17d23d25d9397f912cd823e353aab11b747b0cf4eafee3579ba76b27ee226076c6b3026a946c04280f74dbdad5f3051bc8cbb0e3979dcc7406f41a7acf352f364377d513d9a9a3b2167262cd423fea873bb048f5fe7393c446f00955efdfd51b9a2821d644c9814d015adb0411a1f5c0a5d118f86769608820232a608a141f0f2c868588b361c7e7202cffa4216ada60e0afa64b0dd99ade0104a896ca85482cc2781d4c057b5008ff62e0cf3af91b7051478528c7213ff494c07b034139a047d01f2a5f3790a74d3e941f90bde0f83ee36e2c00f97e18ffdbe193700605e1d6f50a84187541e822519bb22b55f87375a33e0171405d6d6602dc1d6813fed2513aa1ebe769f183f13eae63190f71fae8f0f30350cc973324360c0de61f0f121bf71f0128aac6a9fd470d7fde4d2bdc41193a8dd370edf097141bef8bf15184d9387dc815306c61ab8e03ab421fe2ee3f42120dbcd5d04134585b43ce439036cf360b2b7aae89e928e282f2c101e4f13755bcd68086312941dbd8246b0206b10c46cc6a3eb01194d22286424c695a35063e116db2b35a8b5be20035c41c0edcd4f20edd4594b35e8f5e7436ac8526f60e9f2ffe924057acc91858ce7aa37016f6268db87469898297b0c1d0ef7add98b239117728a710bb5a701732a926af519dc9883a1e1efb64f81206254b53e8cb1831ae04415b6425c27b7b32bb2829ee91638135895cb94911d4ef4bfed3af7983ee5672a3a045071c24c7e9f55819ce59ac155b976447617051bd95492d16580357b4b783b0ba35dda963e43548360abb009e9d1a08a2cf1043c6b74e95032978cda0f927955f9e0f2f87d910189757045644463f7f04e4f0f838a6a595254cbc36daef2c10bd37ffc9ad35cdd5628b93e0e32ac5f87aaed00b8e10ac7b5c3f2841769e6c2cfaab9c394925744d91f3d0fc0f7c19ced00b866fd291e18e505e04b87c5a005ae74c6a6abe3a6f5d6b827d3cf8b5d06698780f2e413110c3ebabc9e7cf07029896d9afddc214fb37394343764ef2f933d5ebf6aee6caa8ebe87901775303852370f1e6ef200096eb24e87b2c514222555e8d13770eb2ccb591c810e7d265058b510ae64aace07bd07fe658571cfedabd4540588ff859b755685ed5be4627d0af67994fa93117d4bb295a27a6db9beaf54b71e37ccdf57995c7f538196c79c24a07819510456a20cf0a2a524f7296ef82b68fa297fe458fd6c2da785307b352d5262bb44d4bfd3cefc164d5fc21da60245a63cbe962a38aab89e2932606496251c4014192597ea14ab238b3636d61a95d83bf5b421173271fd35ffa7404e263be157f895350a138c3696c584209cc5322f0b8ec6753b3f5e8cd7d9fef07b2724226e8c79995d650559659899056a4547d01f6f52946e64316c3863a2e90bd04a410042f58a2823879015a7401c12f284f94d4026ef94d21af7201fa97224188db6ae8e18a56ff3cb321962d957345e2f585341119496aa1fbb152857833135a0a1f13c71d294e1af4b7f11a5c2d5a23a1d4bf83feccf87fd267b1a056ffc638d20db9ed7d056a064fb5fa8fead59fbc5c3ce196cc5e77adfe0458a67cf84bec6191e6fd79cc82bfa3d2704a32a87199926659a5028b8dce382b4b225f507a9e638d274493af01dd6794f5ef0f3cf8ef8603752d2a91503eb53df141e89bfc1bf33fbd0f569025c3023ee3acb153fd06458ab7ed4c29f7223955857c2ed78c6b15ecaf939a6efb37708d670590669205fbf3d3908f362e71fa0c248159199bd8374435be84464e56a1d97febc04f1f596b20f36be1176d383a5599dd314216154add8705c4fe3ff10b207cf5a0b111cdfe79230bb5e6e293e232abffe4efd32b356a494f15e2ac3f939adadf6ebc5e38abff6bb6179439d866c69907940fd1c1ca5dc69a3b1069c89d59ac3d4ee009b86263117bc195a38d1b301610bcdef957fd5bfe8c35b55e89f1445a5b14e1258e0bff29203015deb6b9e4baee266160dc125b6a98c43cf2139bd15016efd32fa5a47284e0fb05705ca1dffdfb72ea79a3132981d49b3c0ef3e500a32f4b1009f6376a90f257caaa6882fd4586332d8e7649929c98d8b1abe4fceb579bc702cb8b0379632d9e048774dc19ec53e1e4620b3b652fc55b2af84c93db385a82a7d852ec1f17e3befbb045dc03a8f8d78b08f6ef19f77be5ceebbf14ca9b78da123656cb332792e3beaf5924fa9760ffd139a5b736f7d287d67d436f3e80f57e953e5c67cb2c60ee59dea394ebb4d33648719396a67b5165004c8e50a59dc747e39f040dc814f194e4788e081cb571e9c68ce209831511c595961915101de5bdf98719a5e027a03745167ce40ce2916ce5e0b96efdd82d6ab07b003721d48281cc67383c905d61709530a032c11819dd058938c5165cb54c190ebeedbd884444401c05edbd2c15e083578c29356113d570329d3cb89a6fb04a36dc69306901e733526e1935b1dfe186133d2226fb31296a564c8dfc850327e431da7acd936a7f014b0449974477df494d45adcb5577d9ccef7f24d602749df63ca2815913cb240edfa1b8f95562b4a926153d99d7ffd66d0f505915f3197bf0d537d50bcdcf93c09293a6a2d5c2fe8c1720d9e43755ed490c1efe92ca25910bc49a0ddb1b77317b3df2270a6761187db82014f40167044226e2909b07ce3ca6c75cddb9bc98c28304ef2da53b9fd490db0a533db2bfc9838762b3b53f57f6b4a77a96ebae7cc909c6833922e1a7bb21118f8bc4001ac959f49ddf4447f27e2c2c2f656c437363866b881db4d9369f4eea83a7c71a26343c45fc900c084d0d47fd751191e6bc994823e37173235b137394deac96955b482e773ac485183704ba2f54a9f7581377640908fd760c3f9d723a944f0c0632e0dbdd552b5c1c06d04e028e43707179406183b87a53eb6c85b392808dd3e4fa816e45066cb92bb6fc5b8860cb00909a92a5af94cf2a6833a61fa2503b1706bd866bb983583baea2a73219409dd3b12263da9f21fa13addb8b0595179fcaac21c8e1183ba79644c62c99c6dc3512bc80608c8dd15f98be0cacd963dec3546677813d98a0810a3a7a1ff3bc3dd821fb55ac7dd1983af8ab9542af825835fd7797958c270be77ffaeb9df57bfae93335ae56592cc8b8f9f4a2b69d2558e2b441896105ff7220897469ef3916ea26d0a181727f82dc3edfec8d4888ccb8d96a09571c944ef86af1184bacc39d5d6fa59c2aa57dc63bd975d9792ac221ec8ce3cb13a6c7ef99136c649e900c1d09588f255ad83c61314554a9c4cb3e508d93d0ad0b846900fda09cf6b3e8875637a022a24cb040f1d81326638a5902ff4ba85b35bf8ce9b06e6ca142ca016d3ed45735764ddd611a083c63fcc151b9c78b162f80b857b18a459e90a15d464b3392708a48490539a10368e1552be5846cff8f86645bc2fbc1e4c9d178ee21d8f1cc416d71d700480c0aecfbca8edd4ebcb4f6d6203e635a12e728c9c554dcae800205f4bc0fd12c347f8d3644744f805f210a309c76d0466bed3b1ac49be20ee193026d1fe7d5dbf01cd8bfadd04e456b05f4c143e43a2256fe2b178bf636d71a6977b22b3bd9aa0eaf35f470683b4f30598f06ef5c47c43b94937cc8ba741a558087d95aa9eab4ee43c126924740fc580baf5b0aea427b641e671460347627cf118e8a181db8829bb2f989659d5e6a82a56a4d65da108eee2dd84fe675409e3515043e3156e0f2895c7b7424b75d2591b9d522e097d37025402426cfc1ddc506c1373299ac0b71419d1594407fa4421137dd673ded746ce8b595685097b081c056cc79dd396fe09005f09aaa7787bd0454f8d095ef76e0e85ac8f4d05edafb8906f5d532880340f48f0e83c647a66996ba441219453c9d94d937651d7e532818650a53d6328a3db8cf089acf8c2b4f9cd1defecab70f8270abbe51b9581d9aad44b4b9db702cca87e8cd13beb9edd236884c31bdb3081f4ca9a054f8edc691a6f45b200868004fee2df524baf6110d6642137eefbd236fdbcfc9b56c33cab6ee288012785e2c217a24873aa760d072321a492a441c3cf6f5442a45e3cbf7c368e3392f42a5aa0acc220e2ad840449a7def04ff17cec9da22a9d68ec44976417ba48842765e6ea40c752355ff48520d7051083fff7e669342dc7f898e14feff881cb226b230fe004a6a7d3250ed8e6268923d9799169dca728174dc460b18ee5814717a63997eebc2201efecfa72d5be0279961808065b265f7e42c47b462e03c0cc585bc7bc4685e5dc3f90175ea6589ccc08d25df019b9ec7a17809b9b726601e6e55c20c94fc3865cd0cf2c212d9de2ad7e1d116beb0cc4d137d99fe81534b791b2fa43a146b928312e55a0b3490fba777091c76216ab84e5a302c28c7017e8785fe37674cbd6ae78fb9b72d289ec395ff4a2407d21dd4b1403a205cc56bd8d376ca8621ba32e7fd894971758f23d1cf92d8036f2bf6e48097999780b93f1d829dfce64b9948682933c4faee1d298edd4cc6b0304095fd092b240840af44637b5b45ce8a3c2a3c0022a96776cb2ca32b31a127e290f16e8dfee851d1cfada247e678b6f7aa98ea90bed1b2bcc201ee4c9fd7799c1f4b7f5abb1ade5207b6fa64892a3e9cd9e602ac5f1c63f1c70fc28e62e5f2bdb958e0f84bf54b12c312d96eedc3c49a7dd76b7e47e2434ff83bf8442baf8d2aee947b27555038165d28b99e269ee7abf70759296b55f400e9f8824330c05ebaddcc97f507a412d05eaeed624037ca39e51792f28ebf3f0338acd78895b4df6d3c922e1dc6b28a64255e83f4d66ce4aa535214007f3a76937d1405f6ceaedbabbabef2d49fe6aa235e991860ee626385addbcdc476e50dbc78dd66d2b48c144a84f63ab8e3163c141c42acc4184264c4610284f60e780017b405a5cc8c11c513160422e776529ed4aec343ee329e1849c5b2c70378316c6cc2d956d0b754b56a87f926077d852979b03045a5d832c7a205626a6c78e947e1f832aaa8a85819980220683f9a02382474abdb551d2194faf483a3990ae2b5d3b4ed2ea255e3bc8f2765795eb63beeff7651d2a33757ba47083fc487cd6caccb95467275be2d63261afd8a7b75e4af06a506ffb673dd59819812871b541970e74dfbbdc2a17261a271e7dd7240e4384c2a606345b541d6a42a206ffc0457faf2f9fb3eca0d7e20077fd749c91ec77ce3e5a4ba90a6f9c8854361eadfb8fb7f9a803d1a28d2f7261ae293ee29a3f2d99fe27dafda36c0f12086a8828d2056b8a8d00aa9884f1d62d7d51f030fe56112ecde7b7dd19188b1154f7b0a73bf342ada7b4cbc15030698b58d0118b08d5c125131f59becadffd70c1882c931591180cf01581f19fead1ec023c70a61e9f1b14d5e679b850de07613f5f27ee578b9ba718895723e6fbbec3ef5d60c17ce7b00578ba04e0dcdfb37d3aa40b9770407b3d608b667032434ef4497001d8a364cfa31ea7385abbb50ee6eccaa5ae32065050186d65d5bead9d0df6ef86ae7aa90f9a6b86f731adeae494270bb0283c04c6b0872d79035142aaa598073b2eb280bef86cc7da71d57054796e69ffa701d7cdb1256a6c4cdb4af14f18c994830101552cfee777287057b8767b750146ae830b2a02119c3d1c967cd2a74f6ef9844cafc772fc3d91e245665aab80a9924cccdec14af8a40b252704e2813146638dfee09aacb2944a59747f7e71096684d6581765f2fee7cb163f616bb35b1bf048da57cadb8b88154d4376094373f6c407a65a9f06730fa2462e1725e804fffda0393176cd1864c460eeca3a286042749080c0d8da3246362f3284f8e6e7611399d630d9db1d390924e8c082e11a0bbe7608634a0488995475d57ccddf7f872058465e2162f3fd55a112701a44de6eb5330c67f3197134f06b87cc44d4457de77304c8fa4d4388aa0150701fb7116c21fe3e19fb7d27dfacccbae2b8abb92eb4ee4c72406ff445307c1a9dea7f4af0042969882718737650b587eb5a7e7a0a00de8926813cf261e0d463b0d6b7cc9d570c8ae91506613abb17c5905e5c4897807acb284e892758430997e7e55884b54b23ebd0a80802bd02ab12a3918534031fd038331574541068c4ed8c0a42009409b5165bdc232799a3655f59c4b27708a5c54133339879ad79265ce403506d5a31faa7b3cb5b3051ac054ec0ba9bc5d49b4749f55a676f9bd7579b9bbd4b36ab856b5ad1d2efa0dc14bd331f2445df38504681ce06455de16d3e1309bbe0e2b5dea84af94e88e662364d333110697f937b46567474ee575eeb33ece55e254689ca022cc6815cb2efb63be568b8040e87c098d5ca825e1964050b2eefb654eb58f9b0f9c3d9619a03db55eb1b7aefc84190664ae8ca3c75db0b8bc23bf00b1fa6eb071e35e06aa5b636a83e726a1a275388940761f9511d600f349e048b14dca051c14db6599c16222052d0cc93188e7377be5ce4f4674ea8eac026540eb0fe59c83bb15d84f03d8f1abcfc6a4904885fee8a104270d56e11b0983806db86b87ef49fcd1effff3cbf93b0df79c2d16f868caec0bf86a842346d33d31f62bf7b65c6a00bd07ece0b099d3c05df6bdf4fb8d69bdf0590c6f775fbe95c0a1f26ad82e3d6833099cc1f3c96816902a6a8efd9993a621e156389628506241305997daf4d221625612321419b26e41076878604dd9578c3eadf3a574420ca26f87077ff005d62a777c5865849d66a48a7bf731a3908410ae1cd5f4a625efce39b75890d9cdfcc843f6acb6e78b3cad2a03dfc83ad0e390679f7c059ddf52bcf06cb875d998a02b2acb381898879ece1ff7a626f18aef8d6d91931020e25a0fa1e0b218a24325a233135a342479a94026981e901aa0e7927170b9f9b1b1e14cc4e283234f2ed43f7124e1aaabfa95a4a7c78482c5a7695c114d773a26644557e61acbc8ab5e3749c984f7881f8448299cf0f563ae77784ea26387ba7313299fc2ddf46ef7607c49aec1d1f14d66d8c3da8af210747feb0d43bf4d13b84aa3d67b35e02a4f66e2331f8dc33904a6a614425715900860bedc901414c559287337063c0230b877e56e5bc13daca84121b7b5892d4676447f80b0a05da5c8c5dec7eff53e228ed3b8a0869f142f6e1ca64f8e2461ad00cc92947918723d3977fb94a73f9b4e7be8e775180bbe111d7e047337e4e290215ebeb0ded5f500fd21b2beca59d349a2ad7fb66210f1c5f6c36fa8d69250ccc15aaacb0bc507e178323e7ecad6fbfc4424602af4681130c32901f81290a3ee605821769ba61a719ab5f20e9d307f52726203eb0508019904df3c92c7401bb2af9520897582d186f69e71c8903765f0601eafbfbb04c25b919f295b7c45c0a699c0002a4fd4419f0fb8a8c109a1b6314b8b06b88685e86cdd0a1a3de81c08f0520fe2476698fdba8307bb1c3c6606ca4a1ef4f8c68ff4346803c9796664875463de711640ce408b925ac61198cdce67fc7b59eb7073162318972487f91dfe6aae5167ce1cf399dad41661eb2f19187b60986717e077e25b30200cf643160c0001071539b6c31489bc4aee4aa2248ced1a7eb62070e9569d7a547508900fb00f56a537cd4c10a76fc1ae1b7dfa005ac32c01b8a0d3096e42c4a512beb67b6ee803f2fa330a38b204c6206395b4cc2d07698762274724e60ff68a3e9a6819a6eef1e3826e8f2ce5063fee5404ecb01107ae2dabdad623a8cf2a8d4a1b692805c45213a87dde9a344a09209b33cddb2d21da009de71669454ba98dc9a3b40398d908f9e81e1460e8d0837b2c2c42593e252398017079e755c854690475e314cab116dcd239a15231744f2914e3dd1ae017c12816f552ff8936d89c69414ac6b08d1c010da94f8998ebe706b36cbb9a3b00c0dbdfafb287fe61d8456df971f8d0194268552fcdb34b2316913c572ea2e491bf78615dc003ad19f3d7eb7bef86bf040fa95b5959bce05d06abfd7be672e2923317ec799bd62314c5cdcbf4706aecfc9bdb10b6671b685ec8480899666e18bc37e89f5e7781b8e89bfde9a9c086dd1acee00df351c18776db6af97ae38cbcfdf2794f0243d75e5071b0a25db96dddb0c845bb42c031fae3d3806a5d9ab778eb846c251f5941fcfa3cf1b0a631282dd8c05b310be628b475d55ec7680187efcade648f7f458a6aff8739944dbfe4047ea597fa43f2747d6a9a6ac66d306a97a4fb063dc9e061b4a4006604112cc6806f6a10a12d1c997110e14a44f1ed649cdbb8d2f7bacd57ed48adb563bd95b37d6243746bcc6515ae7a7123a621bcedeff90e552b759ea194f9dffac95bf3e6bfed276f4dfbfc62abe6d364f81a85fd396920f15429bda3e9b8a1ee59e1987d2755fd09e2c665602f09ddbb00c5bb5af7eaaae923da39c2019fbad023d47d6b721de28d1fb8c4d26e4c086000b0b11260da6684890e5406d09dfef6b32301c52d05b9482c75b2a254c35206b83623a96fd3f2af9add27a6b3661c9a812641275056cf61ab22002692e86dc2f353f24443f784f2ed302289f23ad0f16af168a13773137aa48a22a66ec72ab4e10b792aaadd7bd07abc0a1f2d7ee3fa6f9c79e6b6be23c9e76f2bded23899759c5de11e15e80dc48127756cae95675058f2e12db4a06d5abf0976e5a33c320e884b9cf85abcb9f6712f3d696e70e5286152dfcaf4faf93e3a304f03d1d2fb58411e304deb5718a31be334166130891ecaa4a7458821ffd529e64af3b40244fa1139b1b2e1c1ce0399799b847794281f1fec28dd8a94e47a5d3826eafbfa2e74d5ba3e2764a45d8f37ea3c922788326a5fb5774050b1f4ef0b6f3461d98d5b93adea7c861a4e67c251a2ff5b705b0f54aeacd0262995c3545078a310e63f8a1d1b4aae9ee7888a7edebe6738fbfc230c89f277d96d11c73db10706450f1fd0a963459d633c266028767b6b5ce7a638e64e9448eef02edcfcd217963e682a5830a6400a4745bb184f94b6d727f3e0be8d7fecc1610c37e03ba01d33174e325f2c586cce47cfd963ba4475dc028af424475b6cfd160aba1d31cd1ab2bb1b6fa6f0dda6d93700f897810b30e24ab431fbc0eee07482f99054af8298541fb80527507f1bd31415937df880c421a048e1a36ef60a90176f607b507e4e909fb5ce6976f739a647fa27d36285bab9c07f1b03b2ef59f0c5f787a001ac42371303b7952cb90bf67b8e95b57f92fba09735357b0aab82207036f8c8ea713000555ed538b93511fc933ab9fd11675114f6240b8817fc14cb68104c1aeac68e150052d00417e829e9de9f8e16a30c0d181610d4039810dd0343b8d0458967c43d607288dff07df96562c7878342d3daede240c66d52a4485fbe161a8379712158f94379e10e5a2421bbc4f711070d9c87275a8eb2c67106b28f4f7bd93014d036e8bd8581c71c3548e29cb307f4558706df3d77c019040df6c825b712a037c1a738c50757bd468a744e24ccf692d02580a00f2908880f4bd30abd1de3f24f045c630ec57311f5cb8d4855bc63d9870a1d4ed30deccb0075b283c1bf1e0976437179c43c8f086fbcd43ef01bf609c889010dc4f2638aac05f644a4854bb4dab95dfd1cc2d756c77ededa8d7f7664cadff9598ef44af0ca0d0d10a9c3c2bddb0f6b75044d0282f655e88c0af694e71594cf086a76bc56e1777826fa9f10d60df3ad63d8d63afc87dfadfd40e697b27d0e82aeb035dccfbdbd15a2ac449c105ae9c66db296084a94ef2ce92a95215a07fe8a97aeb930191336f16e8a32e1ded619649b45f43abe6d9b475db36305df8b8f36357ed3ac72a443aa050dc8546e01469c9c0534ae4885b6ad831ddf17ab54e12a0c4db22569b5083e1286121724745c305ee01f53247b5a267a597b9daca10d6cf9ca633d56de5cc5abab1f13b6db42214ca2047d2d9fd5dce55de13182eb919875206346e96ba0d65fd85f4dbd3990a1943565fbfa1a7f3f6353645164dbb6133810c65d4dfe195d38bae926349c7eba673bc7870d0d4a3b4955481839273858214a3787776c850dd3386f004b7396439014f46c8d19cf3a02a78b845537f978d245841bd4c435ec3e89b7e4f6d5a486e4c01a3e607ecc9c0876ddad5254a2c3cdcdb84c299ab8442761c24c49ea7735115555f273d1f1310134986f410ef75b3ba175ba801051cbf645df873f7d4a15a03f9d6d521e74bdb3385516bac84192060f37b7aabeaff1c9701f14df9486eec1e0341424636b48501d49b4e41e6b96dbdf3b6947092b6262135e624ad1feca9e7a47fc0152e5f15f0fd801cc98fc1422f2a455cb8f49185bc4ba3d78dc0e5dbab8022fcafbf78624f881c3fb8443faf93f6d3b6f781f6c48ff0453727788a4bbb76e13f3a64490c2bbdd8f321dcea1162801687e1102f49f1b4747fb6bd7d55b7c98409815708fd4a88b74db043751b372f2e2072def05b460ce01871087c7a1e4c4f71b61d27969d840e18c200db902c13c7c850a0e4f2749e6666d2742e51da305e51b40fb5821924b729f3e3d1db71a15e7f741422267539e2c8b891440132c7ee5ac96ba10c8b69cc82c6a2e4b2f8f0b10e4eaa6f6d397398db612efe4b09393b1ba6e2c47c7b7a929d90f0f13abe57617bb5b152b140ccf2a13992e15e0508fc9d3466ac4f382223b26fbbfb91f7fc871b0b1ebbb3b33a94739fba7819a551398dca9817a18be4ff03a9ff91920dca561c0d9d50919cac6cce5f779ca5545df6c0738d010263036443c21624be0b16e221bee116d9757230083492008d0df65b07267cfcf71dba1a90b51d3637396c5de8172a2164419f2ee17fb339650dda68d59728f0d647acefac045b243d4c9ca05f483c3e3edbc3ed9812ca50f96c69756b496274942a46a247137732d8ef7eece7819f3bc3645ddf17ac762ed837d53073fdaeafe11e31e52ca7a2e15a5d5547f8990b985240a2dc9778e3028dd1f21d07922083d7c6c399b8362656c37a7f0bda7bdc3357c76805ea4acd5cda818803b287a54a698d4cbb7976d319afe29c2c41e7c72054b5aa654ebb5f7b5b6594156be563da4fc1b633ddc552c5009738058faaedd8ef3bdcac01fc57d67b54f46c5d7f66a7b93f6285a6f2c90a18fcd5fda61da62eb53126b92a39daa68dc528e67934bbfbd8a2436ceafcabea5d4ef0baa411a60c518b2b69e449fc454d1014fc138b787778a88d5c81b5f48dcac86162705cd71b7c44a924f4bd5ce531a1975c8980e69ff4b22b58aaa081b56ec7f2a2993da944238447b368068406ff14362a708040c98aaf4970abc52dca344b94f50554a7f74ffebb2a9f1dc47703e83aea7ef108ce4e9f3c1e4ca35534b511f9caad196b5c614d59545afc25d4e7002b91ed186739e8c62f1c786f2d95d67e64cd34e9c1845d933c524fa1d3af7e2c117c6d7ececa694a3922c6245334248166a7687062ad5404157e8640221f6175877754d9582dc8b52c839e885a21b3541b5988e7868b5267b36c927fdfc19861ce86c42002afba26328626b2a3f9703bba49f318d1de2bddcd41feab52946a9a588aad482946e791c2d606207321cafd10b09dd5996eeaf76fe4437726c0ed8faaced6eaafd5b4e395100089e5037f630ffc4550397bd818d9204f80e10e3c25f1eecf02a1d2881cdf329d85f14204655f7685873943b148a51905d275db92718b21f4e8be4100290bbc04f5a029285c77da1a0db7edcded0ff9a4d644f580e9f064cde273647b6adc52bf8ba8ac2ca477131e4366d96961e9b165eb07b7b4c1c6f0b0a0a2febd8364f019dc1f79fb35022cedf4422849a9d061e272389b2456d0574509c29dcfcbd4096eaf32ed3615be1c17fd9f343a783368525c3bf2bdb1fb5e0d0394f97decb62fa8fc0f23a72d5b9762f7f01ec30bf4e65133f22b47659c8957d29fd35612f3ef57837237b1392cf7cbff85c97a58681547cbe3a84f0430058b444f6a12c1242919e4cf6d95106877307457e2018da838e6100092f3b2d5fce9f47db390ddeb854cbadce683e533da9fb3b074a0439f0093cf259fa38d0ec9259b0fa88631330a296a3bb4f6a5e967ee779bf66c7c07c83026978779f2be6198019dd41af814b4ae9539a837d9ead3d1a3a24a077f7d908a4c0509a6c6ba08445de45911413b0d5661617ee4c64cdf147bb8cb53c7ff11ee190799f956f1e164c67900b753b715160ec0343f73ef9bccfc3bc8fa37a3eb61102d104f4ffa38139af3f8e3c2100522144ccf2d3713389a1405b18b419e7514b2101caa227a97006831f1ee6d6a8c692d419e3d19e08ccb6dd3b6571a145d6fafa093b2111500f89f87558c1368e9d25c79a08f1e55973346b8a3655007500442988f6e7e8bc899fcde07519345b99a257e219ef770a635e9e8f351891aceb3a778a224b2e8331f829bcc2e7fbde973e09b38c8432b67b038093344457b47345d85fd7c6d3ef0b7fc5404ef978fd01e564e233cb7fd7ca77c26bc8bbcf891a5c037293912c41dd6c84441c129e6978113bc5162b2a8204618c89e7a7d9687dc89ba2061edb7a683bc28bd01da61db755e5a67d7722daa7e343937e50f7e0e81c28a95a1307b4ff23ff0c38d7b828c31558479d7fdb4ee01939e898f831bdc747ccf4063ec91aa3f8026fe066495e8b1ac64cbb844e1ff2ef34994cc904884bffa1539829ffc79079c20a06d815490c0556dc9d97180b35a41676284ebf083b6458bd172ef33fbcd707d1309a5d358478564a4f643a776764d957639f3bbe0d50a40319ef27c328114b0509184106dfa7a5513b808e8373c3b5d544c26e982c695a433d9057ae15effc35c44a95477511cfc62d1048a771075a7c8557284a10bf5156574aa1707c9e93c89980925e05538d8c85a61be465a68c2ccd35ad35d76f95640ddfc085bf93eba49864c8ed2db27e370805bd639724772e3a68be38e381774b5ba3441e750f65cfd01b695b1453da099ac9869cf7dec4ce204d7105fde3183c4d243e61391ecc253ca32256bdabf107889c07a6c2da98bf8bf8102d5a8b879d7fef597b6a47869985cbe2e250128a9b705f9748131e9d82c8995164aaa1d472b5043d3316dd2dc3bd2d89c47884be47f1d30eb62e9d0d391f9b353b8b5219be8fea1b45c33751f41f97a48d51b13a365b9c85950343434246967ed76e1655419e0529064df9c13d0a15d279e9cf24ebe590cb48721f624ccc013d58d198ef7916504638cca2eda7d2d022415e04900fb6201b6d8f7e742867f2a5f3bbac2a1a738fb7aae76edac25a6b41a0cfa1d16ab61307aa6ade1bf241904074156ee81b64498d1caa51804db3d3b6fb9b84fd0a78991326e5f4771e1d67026c8b10948511f5233640ee29fd64124ddd36fae85c257f13bc518a7a0b203b85758cafb0b30d2cf8c7d96e8989b8f4594208af8351a09826d31a946e385f44043ba0d7d97f8e2322f191ecbc664887ac673f821cbdcbcd666342bdcb25c279cced0881fd7d7bdc1cc270708307c7174cdca91451829a622c825f6c83b7886d8dd17cdd738642cb6be28a6f63aebdb600e178af47da289a64778c089d6f9c9377e1dd1ed2bc517d9ce71fd831f6ae79a7b3c809b4a12452103a73bf506c1fed362abe339121fb395b1e4d01491c6c3572fcf672f9682da72394bb51a935946362f98bf810b3e9f27ed99368e193029e258f637583a9fe29578729663a080bc45bc2687fe036a98a853656b36e29d6d8f5c00a5ae1cf764b83d41475074b9042233e7c7bcee071e3f4bd65ae913d6cc217e261f79d205c94be4f3306ee41361b9cdf8fa1ffbfa6ca6a54a0a7113a00678a8e3f25d16d4259b7419467d70cc5d19cfdbf0b45266896503ad1b759473b57a787751586c7ee4d9545391f393455165355d1c882ab22f71dcbbf81e2b7beba40f119baede05e754cdccf195a8804bb2924e0db243a90543d6a8f2a1a702cea3c7d65d695b6e6c466e9abb5c26fbb4efbc1feb211803e77d948d079d87cd283948c291efd07f568458317c59676155f152a7a8f4ba29187e586110f757010f3599425fc77cd285eb67d37c965328d4b11d0248fd6290eaeef13a3a27beacd5ea581fe856552ce42ae828d9eb06d8eea7ff613ff6a2ff3a152ed51fd1fb6645837cbddb5c9f42c22f1b3e3d45d4171daa47eb5b57c32fb11c983863941989137873ca24cad49001ca126ad98bb7b559faedbd993b6b051e0e8e32f1f64ef6171877a5c640a06d8dbaa3b28e3238faaee20ea027935b4c070ab4e61c0e28e885c8cf286a06a58c5aeb9e519cb210b299fd1148c2a0ba74a7faebf553fb5441d174049001211f2556518c2e53c17100ec48795bbe91a1135adef350f1ca92c804c3687960f02c8619e4e0214987db195db11bf2153d540575ca24a1cea81e76b03c5446b92a2a2f2bba5a80c19a428dc8a24bfb3fb6c06a3b875cc38fd15a2ce8817d39949e691e4bbffc4da9f38dfa6ad2bc5e2314f55108c3556ad48e65ec5d71ae6d4f1535c964505c49f498adb9d3c42e6550b46dbc6797d45a0db215c3c23375124bbd71ecc629cf43b88d99d51cdadf839ed6f148d605915946bac8865d54727044465f20c80db7504bb863f62b43ac6a4d6d10e1757a7eaefed344d703e4b7cd26cfbaea5775832005c945e3d64791e3741200283b82c6bdeb5b29db3c9c1f1cf4f54cd84c56e54649f91390bb1c33e3a7f5baac1513ab76ec0053a3bc443045158dad58e599a658f10df9cb5bc1c7c84f9ca4157313548f96c1b3a5029069707b230824be5a8ae48e32f7ebb40142197a79007cec3d0aae12d1a144daab5c3d98b1c195828ceaf92fc6a17a9a5495f1f32e394937242f30d1200df92a0cc548a188d740a9e47bff40c75d485e4bb87466829bc926330c8814bdac03d89832a55d2f084cbeb795f315d449fd12883308a181c9617493426d5fd1a35f881f0dc4b1b397967683998e15d265302fac74aad7bc9979acc54306551860640d8bbb70a8c694af44e7c957a1b495a512c8e0beb43fd5b080bfb00e0b57679f141cb2028082572158b72d17735138a4ea8ad370147b744d497b41626c711f5d1033d59dd31ba60a04d75d456a6294f7752a5091840c89701d7b1507e8c7bc2e6323b54a4dca78f5d5b68703a6edfd8280891adbc051066257a94428558c9b797be30a54bd3d98c5409b8d63d31a8469979d010bcffcbbe53068137ad5a3f702a6a93c7cb88fe6b7885cff06e40c89ef68b8c78b578c78b007a57c1bfd64dbd81a150b38565f13a95a5cd18cc028a886056db67c7dafd9f217b353b9538ab05043b695b38a4ca394e1685a92dc7f2916334fd62643df0e3c004b0cc06582d9f692e19421185f1fda4974b7c2c638ee03f15d718e4056b58f430ff7cb6ff8bf85de8480974a58213847d5c743c48b4203abab9575b8a9ac7f36619541016c448569c2c04a47abc236623d0e2cc81b93dc36194aeb41eceb4aaa61040265514ab1e89896aa9432066bcdc63f02a11cda6cb6bcdcd9bd9524e2a39df2641554357f899a3a4cd4ff963783aa473e9a620f568fddf0497ea3cb9552d9e29ffe2b06ee2cb6b1bedc5ddc70e6d54364a12d4273f142fa52db382843d2fd2d0fe24c9047784362c3be05cd4ccf5ad1b3668d1d5ed8665457c5b988f6c5c64f95d035045aa0451ae0c50331970a2b3882f65b3da2a9371ae55922d4904cf4d1f2d72a379ee965092fea0adc222b9f507e741791beacca308aa0826fb1f23d05fc36eb03c361319b0d27cea4e01769eaa8dd2311a54694ef41a97c96c9ec3d77eb89fc3b8a999cd60f9512e4f5b0c8083011cc01708fc8508ce1b50c18a0134bca6941678caf82683d14c186df428a01a521aad1622d3434e4c20610e3d63545a18d164d01e5d1a9cd61599c266e5138ba0e059cbfde8356c67263ebd5f5e48862e1619b0e4cfbeb0a1aae8b92fc540e8025dae8f2802ef80c0d81446d03bccaaed9e241e856416d58671886fd2f6b944eae285c79d8322b295b2f20607c6c450d6b23f60b82e5148e8c5acdc8003eaaf2d5bc676fe2d6bbcb90eb9d912e451e48c96879f14a97707d9c8e228f265680e0409672546b39cfc93b0c83b04e54bdae074e8c1bee042ad444e03f664a2608d42ecf307a6eeb527cbe5cdec010fc1bf92521d1fade7a0b625dbd2a86d1ddf9d0b3e2fcb3d3a9712f37bf37a922e8fd9343aa61b75ff71910061fcbec76dfbdf70e4410193a099c0d4c9175412a0841d3c658311ea4cfe970d769a7721ab9bfb05d315023a548aaad1124e4182d8c63be87722fd723c9432e8ae89804c6b25dd0dcd5763599ce547edc7c490a1ac34eb59062bf4ff2326b0eaa9582512515ff38b2269d0be1676727d912492f3e95474cc6384b248adaa6e55348e3e12fac713ea83c3bf64661c602e498bcf658d2962bdbde3798a4a0216fa1031a83828525d1694e535197227642d9b5af917542457e670455559b3888cb2bf718781bfa42f01155bbee5d5f52aad8c0d5d1977b4c13d62a0f9842b6afa064a92e8e49738413e18a5a88019ddc5c3cf6dc434fd0866304b709ce27c2e8b98427e070cb2c815d9b520bc9e20e8c446dc855ad70edd008f95eaf70ee49f57eb0845c87355b64a58d4442f7fdfa8d8b1a9430050abd9778d92d4cce0913390a3e076ccbfddad8e60891cda8ce318374b9f7f85106d7c84ed0d8ef36594ea637353ac946c2ec0c87c31ec498e0a9985bf37283f582b15b9239114771ce40754bf6947d1af8ca804063dfed420a62008a48d997d841233cf89f4d42b9a059730bdaf11f6091519964e9b870d2b013b2ab6c536a43290369e10a086376b9aa22db5f2dd33e6d0fe879e8878723e2d9531b6581eca6fc079fae82f6bef00a5e794a1f8b7f6c61b80c937d791fc2ea1d77851459c5680c310bcb2d8059b33d1ffce70e87f4978757ea74e0bf85b3519ec7373da899a13ce808df483adcbb3c26bf2416b817f82e739cee3ad764de48e6cacc3d02fff461a8c345a2f73f4e523b18e3d33c85e59a6fd4f57e70d95a82b0135244a1395481812ad7576345610974221c1bb19f22872142c7eefe2b53564e0ae9354dc73e226dc2b091a89ba69556e800f15b5a1c16fb7314871033f823c84fb1cd3495be7722b8122692457e108ee00f565f4204ab66b7e68a6376b871cb6c9076b28ff835674b2524ec82f62b879d67d25125bea78e4b7864112518f898ee6a1d633df1348d3e785d5323def642a4df570b026f167ccf51838bc1ee27f198c2e2804c3b4513451934ada98e15a64d09aa499fd9e35edb42d5d9a4ed96d6062843e938aecdca7fbb07a2c3e99ea7d5f17ed3dbc0cb01bafb316591150a4eda37cc66859bf824d115bace090b23e85397410da615dd50a9237017dcc1b1c0c6aae2ea4a8209a8736d6b22ed2636c53544dccb48303a98618583a1508cf12ac658dfdf685275f709f8153dd555e541502d01d54f4f32ecb016da2e255e1bcbc6b1bf611cf89ac3e394b87f3d322d1aa8ccf080980383181c8b1a09f0532892f611a60fee3d09860446d7920bddb5c777120256bec1ea259f6385dca78811932fde8434a4543022308d117517ce198cf37804172c02230440c2b83e49ed9fbf38c10540123b821ea2415019913b0937dd960cad281c55207a7729a728e72c21b098ed4b148b6c0613de980b4cc2f3cdfc69cc8d1c7c66b0cd9d9a378f7c75bfb2aded6600cc3ed46d20fb95431ec294fc3a6bd2b09299d38aed603c2343e1f53f56f3dffa691beaed29eee1e330004f5c447e81fdfff9a07fff9b9576112a62841ba2163c89362ed880fb743e0b9737c1042533a7f0be103a81a24cfb9f067538549c2ac36e18fbbacec005c3fa4e5897d0ab0c6e1b237168dc3dcdeb80abc8670922591ce51e186f8a7ac99e29b2aa31669a9cb635bdb3b3dbd5126564897fd8ad128b45f7dd9dc842524238e06f0e0715cf0761277109ad57f47d270892cce4b768e7d3436c89700558377563737eadf1f8e80929538c486bb594571bb14bd8b48145e53ceced539888f60c6581fc11a4c81aa2d803f1059132dc7a03ce532a95d21a745cc8462742b55e70a702b9c531f4faf44c6d8c6dcd450160cdb40d43bbc9ae16c4bc647efc8368212bf61f801a668c106b8d22515210862078389be778ddb495ad096f21d131c17b741745d9d47e843eb0801c7c5258eeee5f02cb9c67a33d16fb6ff9e47946a4f213e48f3b151a6a06aff635db2e440ad412964c9dda5e0c3aae43444d0f5287681635cf5117b982a9e02cdd0fe933a1a5eaed1995be00a45010e232ec4682654214a80eba7b3cd72abd06a7e6daef1229c06dd98c1d2f66dd4d27868030642fee88d0c1d4c5330412418051fcdc9fab8275f13d242bdf5011917d2b31043a1546153ea4ea86ba016cd86df92c330e8306df4077890ab2c77c5f5b175ba807524f5c9cbc3126e3db28f5a7ed16b701e8308723390f701b5f19dbe1cf0ac8772c4277b265ad52b2309270460043a116bced18afca6901c3e81cd2d365bc1d78ba93e98e7ecb9d91e3a63e888403cb92aad09bb5d9eb0dd98d548b75e17cc7c544a8b6a82a232aeb90fde5bad26c9220e9377fa7355f98ddfe263e04c98a0afebf254db8957fa782fe57643af70db4c67e0b2a77bbf98773c5c51ea60d1c440ee1ad48701c8cd653e2b96c48e795118e4a3962dc49036f1260a708f8cf47f21d4cfcd4e034de9d4acb030e63d812026aa322be3eea19ef2395289743658a331e6db43f1385268c2201be4cf24b11ef99d36849816b5c2c12d0fc88c1fafb6270361f0f0bafd20b4dc98c31b60242e5e5348dc35a47b3f5816cc03011d62596246896c03e077ae9480f5f73da17ae38010c0246555ea28f03c4190f4a0639a0f1a308d924cb7ebf206e5bc018c5832b2c31f864c4c2151e1ad466a2600b1b7953a69b9206506150d1b9c9115656b7f4e60ca9008accff7285910a868885859d2e1c5a0a8138c588f655d971ace9320d7d06e0d65343cb0f38b3796cb1865b3c45858d007e5c8c8e3201a886e5e3a486029848f6c76feb4a95f11e83a7e57f3113ebccb24c8cac19419fd05fea690c74af854e514f04af9c9100b6001bd205686eddaffabad580678fa25961979c0f114493cdeb024cd605f7ee8ef33312c5a74367e7c2cb3946c61c1e8c60eb756a168670bcb56d0b23b0f2b04ca025310f3f40bbb976b5c8a914be7676276d6a5da52a47abab6e60d54a5e7f5cd27195a400977f6c3802edd1bc054ef95a610f5c4a0f9be87eb8e77902d5ecd78f147b1b2705c25dc4dcaebfc0560b202630273e3124ebd022d69ea93f5c40d0ed961f4f9e15f58e323a556f084842b0c83d4a12d012c4db46ae19bb6a5111dfde6934c5d297226e27f069a8943ea36807e419f5f98ba1b2206e4c573c550ada94e46ee01672d1f51aba54ef063402181b6496c9726eea185166ae6b68cf45842f9f9bb6b63b35ecd4f95194705fa262f67983d2dd89b479e0956b3203ea4b683095a7cafd36f67362677134aeed368253182ab81478f4a707619e2ace733a8cb806de5c7752af0972ed845756d4b84e721913d79526ab3ba46224778f2ce68e5988fade68fe04a47939144ac24a519112655c7f2ef36eecbe779a0406aab8343c0030da9313a6c10b250f52b6a7811c59d983d952071da91cea79668b8c2f9fd0b613105e56e40e59364eca50228c74c32e079e076003d6fef076c1b4a2a0b9ce842ca6401ad6d59a7206255f1ea464c86443ae40fa057a79a2387c583255cdfc4146ab7e1b748315d138bfb3c28a2adea7d745c6dd32a77af3676d4e5d548320013a0fbbc3114024643d7c7cc1c99a100ccafba444b68f70dad97e0afc497a4d32891952ac75934819e95ae10b73c25d94b7ed62e43c01b2dee10ab89949f79d5d7184b647baeeaac55e9274ab486e6073e69611559228bed4fac95ace2086914fee0d1710881b315077832b860294b1abe5772bd359ab428053c4b13f37b4d0cc97acbe36a21f9aa4d8e0d0db4b3f5266ff522f82c851320e73cb2e32231db9c5ab9654b2822168a915f8bd270ca2e5cf40b4bca0f275ab3691370ace183fc93b9f7e953b18cbb6bbbc4b49526eafed4ad9e02c577c7f38b4e891ac1334227694ef1c593789c69809c60f9601a557c7d4a95016046e88415968a9ae55ae4631ddf4fbf6299dc3389e908979025d2bae391e2463bc7196c5e7ac7943a298d4ed2f6831f8b9df7124d8865cbdb437d2829d2804acac7195a8f2a3f47274618281ceaac05db3e564a58ea017c6a03fc9cfe09683f0a6476ad8ce5a4b4a4cb03637e34ed228496ab64812bc4a3ad31fc6851678d16a5d733ff400a42125365d4bb0df72dd84bff5a5b01492cd0da908c1391f30ffdfa43ca7150e5898c781ce706d0443974bd93364f76ab1612162a69064629b9c2dd0a03344596a60f4f2ea2a8881d1ef236cf8dbccda6ee5a2b4bc58ac1eadb0800d3191a33a948a7fb3314534642744b36430e74309d1b087b8c3843b560636a871c3db89d33383a5a27f424377a813733a9dfa8349be04715e1f652a616464c15917bf05421f3aae52585f21974208d740deb646b70d896897c70f9ddddf6ecc2544e6533dc35f1e8e3d8df3fa43f1b6d124574725c18cedc30623a793c6ee577edd9925314ce9028f117ce00c3001d132d0db34c7e3c72880dcc04cc63ece0765c3636fab004705bc49c6bb0565caa3aed98c3504bcff2f4a0c9c4e6c87f8c91e680f14ad361975d05ab4576c47904a9e95a2bed6cb624d4cada0e918011b6a0ab34c0f6567838866e4e2eabde13487ddb116c155f984c52a7c3ecd1508eab163c5bd8e1915843565a24dcc740589118bef14a98b607060bf4aa250f932869606508170767708dfbac0a4d174d744e802b7ed398799848bb8734f32ebcf97be86e0e253bad285955e689a08c68af2abbf34f1023100e4185b5268d2b801327827e331fd5a3c0deb2cc02977fd8b1851b13ca1546b0c3f1eba4c8b00a0ac5f9571d91fe3ba437c1763bb3b3052c297cfa6061766798981442883a48a4d6bf5da4ef30e80e67c215f83768c4355b513492400b5c4b185e7da9e4760969420465ee7b295c113f091291115208022f620cd1e43d367962e41ef2451b5ded2783865c25a728354850f23c1ea99dbbdbf61eb8f273a449df914cbb54e687206e2dd9cd24b28090b78034a91053565d1e7d1cb0f6694955befe3fae0b5ec07a5a120ddbfc28fa6aee9374b0fdcf7805cd2a00643564efa95b1b49eea0f19f3186f9abe56a0b3fb46c52205a3ef57e597f0d1b2aae01a0c0a2103c82b82f8e6ea214490d1fc293cecad755c67be317981234429c0b98d50aec805a3a9fc960a9b21ab2b464a75f71ec184f80b11970980e704ce604d532b3159e69c9e936c361fb0bd2bcff04276957887ad087c28f0fb9b22372b9db56b3065d9adacb13a7b51576988a2f29d081e19340f0555c9dee90f9234ca69db000054608215430085e03743dd5a7ae3e62c39227db6aa58accc97925b2c780c86a17d0cb9a69871bb9c9c45924104f027b4be7f77f4eb39c6c5a4d7fa4caae87b24307a71e97a01c473d81c2926e4d1d684785417c7f3e926fb2cf54a7d00c94665cfa8838de7c29913874dbd58c38c9bd3671a62b41c88e58ce202faaa67131890eb3f664ab4edbb4deeb8ad3d350b668b2259670d6752acaad840729af439ed239086902ccdf0ba24e4bf138d36f2d8f80513133d30eeeef4d53c935384536ac9cfee3b62ba7757620f9e1541a67e9a6dfc6da27953c4cf5ab349206e28a0f09eb57d4112cb2af9410e0c403b393be343b39c99e33e73ddfa63f15a675cad477f93b932287fdf58bd467af8dd405d89ece4810b36e91f3fe5612c94f222c4f1f696df0db9c86b0ded449770da743ae89bb3762de3aa5be168d21b9251241a32605129b4dc6723ab298f649c5a176683c8302afe181f1e670b6bc6b7e9b3ebb38cf790f095d991070a31e3313cf9546ec6a41aa1e92d85b62ea70ca9c133ec4ea006028a44bc60477df2f35271f2fe2ea442283799e277beae0c02e22488edb5828b4ca122348b4a4c1e24919185cd58385598f4bdee258b3ed061a85298339d34d485b0dd1f4bd16757f46e9b138bdf004053e7cc30dd5a3d8134f111a914edb60b7491bdc7fee1d5fc1c7a7b5aa7bf6b7b877f7c2337e53c0eb70056235b440725704cf7ebce7ca395fc98a9c7bf4a01b6e91d0af61041556fa1c41c10b411f296cd0749b03252f75a22d86f387ab2b88e8a237315aa0136577f005e5bf899f120ca80fff490ffd80068f79afe91d79b86d5008349e833eb799d967de5005198fd8679a9236f46bfebb8a76f8e10251a8faa27aa0c097a3dc9cd37aa7148871be27a69fcecffce87d5f7ebf03827c216bc98373dff7394c7e2657f29e915a46c0eeaf9aa33a48f1175025fbcf48b28b6a86fb496987ea63486d126d7e66f1698b9a9f6d381c9abfe6d27d76d4d1322dff5001c04e79c75229efcf1c9e70156325722656e02604b0676d3ed299d490d8e93844ed72fef151d2a76a296b2564dee72ad17c7e7df1de6d4e73c1cd02037418392867ba4f0b202e4a0908a46b89c110c14b8062c384249a90c0726609b456c5a2fe52c7d957a083590ed6db7b039484bec89586ce63e25b49b3b45117bdcb42fa02113924636006030c1b3b3957720158fd17bb80777fbde34a0c183ee48557e6d006f6924ecc6cdd34a1ef41cbdcb0c63a4d491d8362121ea235562b33981af16872e24f5fde35b56772142c4b7bd7016fdded3f686e7e63778baea511f8d14ad63b8944d362224c12b01f2df4a736da4321ab0a5ca4e8c031580fdb9b6bc0bd3147317c8082cecdba0de0942798326153811cd20902c92d104bcefeda4de735d49ed878d4f2cf8309cfe02bec035589d49807588640466a49031cd1a0442434903720d3d651c4cdcbabd6fdf7b922791042c32b33f3e2a221ca5216a605a1db5568a43cc9573b82f74cebb5a40da6111b54256c16792c5aeeae0a7083b71f510dc419db64cb98a8a8812a9a7af6cd0d139ca790913ede337f216323a82cf5143ef552c552299db2460ac985bfae99c5b1e20c3a0d4bf006511c84c5ab28bbe9a63f4992f00638c5a9c04246298f0144170c1fcc476fa24f2f9f6066fc6026c42715981149c882832b09bf3a13b7e83306219c8ecb8c93ba051a98d18729c7c8b1d920543cfc5f15c7ca8a23254fc5aac99ce87b51308e3027accc9a4654127475ac2e6604819e55ca9b88606712d846eb5d245414ffdcb2bff80e4bd217d8151b0e1d6bf9fc53501590b3371a3e2b24368ceb127e6ebbc1d40186e034691035b987e158e42f7a78de75c07b3a845d27164540b2ac5214d9004efca366299dff5d076bbd1082b6f33b0046c6100023b571c3e9cbd7c02b1320ad6049296848a0714783707cd160e9186611923d94e163ddddff72d5d4865d5b2a9da198540e2c3926d0575f6580255519aa42a86b7fda7b8d40d40a211407a2795a0871dca6aebee0fc8293085a568a96c8e548fd2adfdf97e38d97bee5abb106c045e3eef76b6ddb224c775805f4860293165f6292ef816215e1ce4f450da24d6e670062959a134d6abe61b80d6f909f0bb54c2cdef5085e3069cd81769bc2de143ca6c0b4f89f514565e2b235fec0db2ecd19e960fa10322545c08f150cd823894b4b255bd0a3226e98b654b3cc1f0e8b480e8e83568474edae0885fb9e1dc4e0ae00caff2256196d2a270211b3d5d98a75d6bc0b057705f56087148fbd2eebae8bd246d5de795db6499bbe86a52cc30a09d2d038e44ae29173ad1dc84146dd40e572c603d67a9da937b538ef20c8d05b18439c8cbdd98040c9a5fde76229c44892e1e6759414c610139418b9eb2e0e08487d3d5dd9363abc9546a00cb42b1155d103027895fce8b1cce6b7d9369f81af0c3299fec8aa782eb1b7e4c0c446d491c26f6c8b882f22057bef09f295fc516cbad8b86ce38e54714609818552e3910837d9ce3b3e0c04178d07170724f8d024eac36d7d490a40fd58b01916e05d7457aaaa41346d79e67d3658e4f81f8682bf2e0f90b58182d9ec6b747dc9b698a2065919732f874660378a53cc06b8cd928244fcbc27695434bce805d22c22869b875f733818463551ea752eee479bf81c56c661c528e2ba6db6a6951c3440ac5f7f7582b89521da0633b00217089edd33443219e8fe432a5116507910b7db919cb5b50a92a5b34d2c67d860fe4b377825d05359b80a1f4a456c71a125a6b099a58ef2ce46ab033e1671e7a3d7fac9bf771f25156608274bf9b7b2b0918f7a880dd4fb050c1b0f63d78dd1a3ab6b452ff01339c2d3b801ceccdd462a5be6897b237e01fe732d58fe6f6acc445da3414c2c373caee3b67c98ef40ee4a26388c8ba40cf741100ba0db510d0dc5e5f94a2c5906f8b98004150ceeb54237ffa06861585347f625bcaa54f2757bb53a69156073f6dd6df06b2f92006194187d0c2e6cb619d042cdbc5631e75ddb3f9d42a6932f25b421bd93a82457c7e3fd56d54d372b7d39c892e2a9a7b085e174a0e8f3c830d641f8ec1bdeab33cacde8b2cd39fc9a466fad09db509640e0cb90302c4c10df3b01de755f1eef5dccb7f59f617e86a77b77993e340af0f1235f3d17b67f40254d794f340b4acfb7a6fde2d19a85de7206274c83cf8469760814fb32184da9e3a187bc5a811e17463a7445217ec931ab416a567748e3cb912ae749ef19bae390f7ee3d41c5a30b3abb82beedc67fbf61a6d730de1c0e29aefc927ed11703fc987548d9cdc186ff54c636e862e8b535e2944e5005b1744394092118b1ddd94286f01d29c559335806059f1fa676a08d7eddc04092287068f06e725b6540c87141d2cf8992aec0f2b2ac593c9adbd35cb30795d8a76b1b94bee7205488423179f91629bf9f7e93c7de21fe1502db7769c73bf893c3fe8a6ad6895cd1fc8f115bb332c0b8e3cc4e99041154fbead3b540837341b034992c61a05699732ad7edd8ae23f34c0d4219d4780e42b1c5dfaf6fa7d74635837ff6b4d6bca9158385080522bbab8083ef1c73ae5caf263c2ddfcd115af4647e0a510c84d4237874b6e3f9367354500e0fba8e728ba81a4c826450be874e0dddb50406779750dee05908191e9a1fea8e162c0f622a31b7907ea3a9937290f61a2adabc44deae8d19c45da70872e11a440aaaeea844abfac86d6a0f23a021cac48cb541438169b46b25ff9671768960fcd19fdbcca62182b0628fef5a9ea44d47323880d76d98f1cd08088ec93926786fe531ab98653bc0bac189aaf4b15105540b3444acd1e1b6d764964f386bcb394d5ff9e87969213f7f2cb17bb9d779626015777c6f7c58cbd6fb9f7c5638c4b878a9d01db903dc58d8cea97a4ca0bf94c51db6f352bb3ea34a607abc293380a11397e8b2b06011d5a20a6d970161c5a8b2cdc2f8e011184e39441ab7c90b904f13895b0dfb674d3edd1f320277a2875cb89b6f3b13f2b1b9e70e32d22fef970e3045b1553192db76db2016b4e45ae49a92505acfddb9c31a8759c616c5a5a6ecf6e2e48fc47f143de77ccc72ccd885377899acea9cd4348bdeb231c699e9a03e97b8aa001360bff0a8760fa6e1f1a6b0c96e623eca652b8e164fa62ff188375682750492a89ff332ba483f2f4cb1a48df2b2da140414bb9b078ac33d4231d9385ea2697bc258d0da70561353df285e376b15d09a400fb93393ee207da7fdc7493be7e82e85ab7c8cf5bbe1570f7fb2273f4a79b1ada10c3ea29b3ab04e05d4351ec8e3b2cf9c0a313dda1cdc456c8673fa8f0d50d0e5c789cc143afd327a1c4fbbeefd533ea1cea5ab5f3c0bcda8343a8ffba01b95ffda22c7bbf8551c325eee72ee52b670b2ae6a4e7e859dc957dc823791101d5bc1dc53ebe53161047b79101643c8517a04576585d6020ed98036b0172d197e9ef7ff06c36a859b9f42e6c55f100551adc7c51183b8e57fc2402ba2246aa3f5ce26d19bc63573e356ffec87b930ae2db838f80f924546b9bfce8f26eab5679b990a0bc4a24849aa2157d775ea85115e9f7e30332042c8960bb01561dbc70bb1148e48dfc7a7fe62996ab1e04fb52208e5a68df246b8b4ec46ef4fad44147985748c2af173350dafaafda53be692d3200c24cee724c0f8a8528381ba875a9c465fe8698f279c43d4939b1922bbe9aa6d33d7ca32e66befb4804d5a218e2d8efd7df0890b29103350f5efa5d64545a88fe6d0de7d9cd5faef97dac4b44dd32ea86df17270eca9df2c96a9c5a96c123c1538656ac9ea9ad4be3801aaa7bb09bc56979c11745f23181cef969a9a6fbc0c5017d40b2629e7b61bb104d4c330d501f764892b3a632f27ca97e979754d5415dc63adbc9a548ddb387dc27698c2005e9e1c0652d5cf897d9e8733459b1f10e3f39adda8a8c037c84bc25157cedb51d6fd13df18fbb0692c3f840ce705178f0717de81f020f36f2673230b8888e901afb884179dc21b57f0caa787378265d21358c6be7ac59917e4f1a9bc3b4be9962df93da2c1222471a5e40598a52d2975d79084469a8719498ba46bb267098b14a450c549b2888048cd57910e5ed99e8e31b56c49b1a4af2cdb47d775ce46814002610e4bee9d123885d8229e7be05db4eed468d9037bf6b0dcaf563a120cbefc8d4f5721949637d3019d81e16aeb3fcff10fbf10d6987629c6da88e830fcb7277f6c584a2fd95da0c51e345004ddd11f9c8ded8601ff493f5d128062507af620831b594feb4c470f845214fde086527adcd7580b1e88be64edf8febc05f4beb5092649646bc2c91bf5e1d952a5821d7839247e59719088c5a74cf05d57f5273a095a7ceccd7886e198eecd22f6eb9570d204d5a35492ceaa872704f5b05625ea64546730dc2d6da8850072d45bcea24cc3cfab7b11028abc4b1b0e42f912578b02c174401fe46d1537af883456f6d4faee3d14660dadc20223f0a642344946727fc3adac8cd9209577d1fb2555cce10adc6d9ebd0fab2c7cf9e4138da1029a9c1b621ccb6c9aa6550b3d4ec757f892abe1bd6c501d4022bbd12e02a586c08ceb3047639c21184b4de572e357bfa7f06af1d8aaf28c744a4cc1a13cc510190480f4a67d1a4a86682435ac727e2fd811dc23cbefcc2795efdbad39bdc364d1b46bd3fd39d4707fa03e369741b89d20ba02074bb7c0c6b814b3481eb092c41e017ed6dffe84ef992b8021303e488580269456b43b2ba8d1d89c62746a023ac6505f9978b261c59ea9fcb04e02f4015ba5c5b857161a8df12fe60504a4df013571224c167243859dfd2fe3f584f4fdc3b5f0a1f206e3241e55bca1099024e017cb9510b3aab82c63b8c3fd68d1094e6b0be70c3dd2e24c9683a320d83d3cbd2898166d86937cbf2f69e1523243546040fb5ca7387304067eb06e2145d4de0d617364f075fa1891ddb9d007315a9ccad130bf69ecdbdb90e1e6494fbe57e0e3c206f0c099f7d0fbbcb1d6c6b93ee83d1fe90df14891b741f7de86bb0f364f02e7b1d9544c27d6dd6d023bbe6fcad6287b220027f430736fef04e21a84f39d26874fb52ce8b22cac9a0c3abddba97d061df631a859e752d637729faa1c89dcd0e43bbc0893bdc3895039e988c33f83a291d478d3ec0e1f3e354177e50d03ffc81d2d51a1d0142a9352e9e486c27d1abb7f555458c5d51fef0a5d3ebd4569091207b1d6818b192c6a608d6583ae8295c2f8000531e67a25916bd6faf76d1f209d79692b39d5c201a695588e0535db7b9a810ece1d255797a500abce5c8287548dfc65c736e7d8ce20c492a9deb16b2731eca97f0188d18447c062b33a7f8537fab28226499d7f46b4540ac227ae99da88db9289cba1e5b684cfb2e2e2ed7e4308b5171e11039f647ecf275574a214c1a64cd8bb28d59c760a439ce56e91a740c04771ca60918f267114c6570bb18bd8ac580e5ed793e9caee14994912dd2e5d63e19190ae32e606854a651dadfb10bc50d4d31c0b3b0f6ce1b96151ec28226e973278bf964a076eb08ef1ff740aa5a168a47538a3d01078e2d681e3e5830496f57ed1b9dceede5c4479add33d8b2840eeb25883ad2bbb2867eec7b0c87ff8095b9b63bfddc08e32c38c2b67702c9f850a0e4121c40b03ba32513e9309fa0f98051cdc11bfc15454a1cc9c0b8fb1d2c9d4cd603fac00f0f0a40becab74c1032b4204e003a32623136278cf4dca60f17fd4fcaf41c9d4e67f3eb495d7a67421c76c08e55cb1901c285f36b9c0750b32eb5a818102066b8d307e72944c2c550a3cd65f8c7ceb5f173e3ae4d62cc27386cfc55da93832402b880c248c19efa30050cfe496e9018afbc96f4c2036ca1e7e1482b9b84e03c2d70511582424251d6a27ce5724b86a231a27dedf3246e0e48808819d3ad18e51e1d33435a98b0a1adaab2f25ca1bc2cc770aee7e2fa03e65ee62e3086d1d0aea39dfff2dd54d17a6039b74d2519877abd59a66f4d9f6698fa2c8adece5e94984ab346f9adf6646f319493f6ddd2eeaf4658f23d1161844d9bc372928dcb22cc804e58ed6d6113dcdc25677859b711b3ee808cb1f7514aec3dcaa6a12014e0f9f558cbf00f316cdd6d4fa3683794e2e86ee30e071876775b72bc36916e3a1face6a5d474f77db9f2b2ce1f800d2198a4cf69120ce2470a6144566b773274db49b97dcb01a97849a6c37638eb5013d5cf488a0cdf02cc80199ff98261b00cbd4fab6d203241b9afbd55f75b5a5d22a946bd84411c7ac604aea039bb0dacdde39a5015c27d82c6af3f2331d3efd9c75af95e17c5351631851e4823c88685ec13e17cf1bb8ebd68588c3b52b615ab617cf77586d4b833f1af915062bb783802e17e4d47ea391518e07a8931e39d7c48261a3648aecf3e40f6b75522848c8e343371d602a3e6368f8471ff490e00aacd31476102ff4eee093b2048dc9c198fde673fe1f75d559a887435ee643609e2737c23aa3848733cb3463596a3aad037864685281751b1b8ded8fdd5ed04684c42211981d8844b2ed2364c24cb0a64e3d8e1bc4624fbc8ef85a43ac8edec9ef126cc79b8b699aceea036e1cc0a58037aa9c1fef4b13a4b0614f633996a5a911182cb65f85699937dbb8080729f97d72c0fccf595a83e64ed5225af763d1a48b202952de239f0a30cb374e0c9a7411248552a26814c3b575efa17740584551d909d1ef37016cb2eeef606ecf17b6f0d68f9e6dbd55e16c3ce448cefd813a5519ee42717af5549a8a8358599d6d4f745a3377e587bf3049f431641eaa4820ddfaec34e2a2da641fd7f62403dffdcb085089eae40e3b96ee5e891b57841b0dd095c4d93deb2b1b07690c301889dc0c9f50752155d6218dafc3e1085907fda5587258ece263db6c62956808b3eaf806294a7eb8d276ae30e2f0b564815eb9176dfff0b9542c790579588d7cb5cc565e36437eb15758559a5823eff07130164fce1f5a150e18339ec98da2afff37232c86074b16b81f5425c02930c48b6ad9cab70b195466021d8bb00425620b0213c9e15c9db156de42f07b54b13247b964bc08ea18f8ae2ca79847ac7ffe44ad23d6ceee09e3259fb54fbe3f9318a773f15bc119da5648bec6bb0cd0c63cf1035402f641e11adafb24a1ead184f56005a5e13fab468a474e8e1b85a9a4130c865cbe57cadd4ab86985ee5a79017bb86985ee5ac91d2be4c6f95eee56c24d2b74d74ae2a60e7a4cf8a5338193ead63f700e804763749648292a3008c4309905770147030e6a6302e6c3161eaf00506beb1fafa48ace74d31d6ae9ae96417fdef0e097cad048bdc5c00d019d4a860ccb76be8a4e9e31415bce13773ee5c3dc17308b21ad441958ddf2e244e2e82444d987a6fdaa911f84f376c9a29c3d07bbb21bb8978d9c163635db533db162b39822868af928868304303cff0d386c5bb277b806702b6d626a3138c800b9cce46c19dd2358c02908c870720e2dc1344593ed70a1a9375c74e5c4b0a5d6c694694f7142b30aa8be25335c88099b33adda090443c4b45a54a931f032c67098500db89281841b0be2dac74e10e7f211d4a982805a5dcaac8c1f7c00d2380c5681f248f260e5ba82b36a3a161ec481a1c8f71725c0fe11b2c1b774026fa7f0384361bf22c031e55b16d28de490c3383332ffc2335cef86818c8ae4a041b4f4fd933d83be616b3db949e6391cd3c4bbd0332f8e7cea848d938ea9f78d062335008cb11b954d1410576a6c3068864e0c9edc488a186412bae10e739772f73e56367af12f42af77848270746a732068b0ca6f4cc665931d37b02411c8dc75f69115c19267eee7cf1a167b8c89577bcd79a0d8bfa1022c5d9aff1c8d2d3b7cd01a752281a0afaa0492541d521642714019093ea0a3cc16ea3a36b090f768c362ac23ce7131169caf1f5494ce8ce1fb3eebc34674c814b3daf16f200b8b7e1c3e8118c6ba7c2e79147ee7bd301b309d0d45a75f30026a286571241e8170820c1afdcd925c6c71a74994e49e1f26c5734887e17b51675c375266c5c9f9d590619b1e3e4d805100666bad654d8a1e0c8ac5b574750a6f35d017d854a3b1b652ff38bb9cabc2a4ebedf542ec32741e3c8af52c2a8b51d24636d4cca1d20d26648d775ae5d2c80122e80a6614ebb12c4d496001f49d187c282fbf2aa2bb9cb1b99751f674b4003388c7b069e7b7d4c6c1484b2582504abd857c14c296da3848ac147db22e8a479fee75f5df9526b7451021c0f56d8329c69ef7c20291f94325d08f0c738a2be4bf806703a75e0e3c655e81e2fe7f1c4df3e73e85b0abab1deb740105716ee106b0bc76dd3cabb51c998372a39b497474bec19bbac4c8dbe2241d7ef6e7644439901e6bb58186323332f691bc2e5f210e7e1dd18cb20d8fe6993f89f8ca575e4f7fdabef6dadfb818fc8fef82408a175a84d06f3e84a0931e1e8970a117da35318bb92238948cafef68c24d8931509144f7832543e4b52e29a13822128a33b1129471d29009d1bc947090bc1b1107addebc2a987d092c5d7e54caf821c083a1cf0e30e1935bff302882c8560c511476eafb143218d155fee461780396c64cc1420d1cb273da17887feb9be9ccbbe10105ed8792bebdbc71661bf123d4de9148039224d8fad87a6ef3126ab64b367ccd59e1da1074a99e70534ab75097a5c8097d4c4e249fc500980fc2190c363c1c6a8baf99d21356f4eb5851ea5b2d70bd0f14ed50eb6c8a07b8aa65b4ab2666f0c40f8749a061f1707ca15365ecc097d30191a2bf2bde3b1fe5b42187c36efc98f4c63d42531d63ba084e32b420b9975eb0de51e3044c7c9cbaf5ab86edae5085015f23fcdf905c3554440f5fc7951943969402e6bfc9016a646e81f8a77db5c993c703979cb1b6fe0d8f7a9a87ef9e242dcb6bcdb60f7a30760b60100c176482f0356de2937c6a238e23b4b51f02a514c8f4e18f5d3b7621b796e1c729a00b7cf9d64e10590d370aa9939f26fbe6217c15482d84581de6314100fd269534cb01bc54269ebda266fbdbd1383987a64d2f645b13b65277f47811db094bf805eff803da9461f2647e9de12467493d203909bd6ce2104af3427989fb1543bd4e62d232debe39c67b7d942b03ae0c59d0e897cd08e7345085317d8acaa80a5ba4485022f26201574abcc0ad08b0e1026a583cdff10437ba012293db9073c4b795525db2976f44e7c436450569d11f96d33f1df0085873319e4323f6d1f8befc1d8308ba2cbd08d0171fc070c417f2bdb727a02aab1e9a166d267e459d0195ef674f945e8d5416919fabadf2ac9c615819122e4e715171c1245945b7366ee41ab4f7534fa6dd86783e846e16de11261681f68dd89562abc69263c2dd60a558a38e2efea6c89de9c92100436fd6284d9a2998a453e1a4edf6f49b1a4a5eacd29b107d86913c106db2c349e846d67734cb2204e9c5c63634db44494a16e5dfbf35cfbfc618a8b4c5397f17c5aabe044df39961eeb65a5aa8e02c0331bad996e669e355dd02650d62c043fdf45572ea5fc37324bf218f7d129050b2fb2568598dee86946abfea65e7c2756e11e4ca5aee69e21805828209840c3f852accd5e810c1fed6b60ff02ea40efd964b95c570950c67c38eeac80d1b21fed5f1ba17e55922885088caab14e2373f55ce040a02718f78488a1a35e38351171ea8121c6abba85527659d651f089dc5fba15866e36ac60bf22c5e07f6a2598ee19bdc442da211bea341698df30fc006c9e95a0367e31bdeace8824fdb1a4f4ef9b6a690c85edada67370a0886dee580cefd6024b222144b97284a3557d2c08c391363df27eceb072ace176bbc961dc47ad65bdf798de72673a82d66f6a169cf3b2de60f006eeaea8b08997231c51721e7a1c6a724eed2bcc84bfb36f3d6e70a30f08e5730a45d466379a3cdbdda699f4056543c0d254471464f47e54537a460b9080015a4148041c3acce2b1d4eec812da5f93b3d6501071fd5b11a431682f468bacbbcc82b3c068a8a349afdf156018b9a5d74cca54aa82c6828b1a3b31349f481c46610bd9f0bda1492ac5761edc2b2fda13f081b2a304283b757456e045d9f2174f799aef7b5f9492ad0ba688f8c0ed0898d506b16515f88e4ce75951e6140a6209240d86390bbea6291ec5b925291e0a3988e65dbc183ef4b0adb9dd5f731f70eaeb248b1a4c51374361b064000d8036b850691cb75b5711bf42cc648b8ada427d30d33880f4a4e86f8e77053296bec3591080b2c6a0351ec0658ef01004d740b1e055dee7f9ac7bcca3b0e46c6171323d6e8f0c4d13c25cd30a7260c973006ddeb58012ad61c395deebb405d3ae760fcca7ff0d9ed1bd36ccf88bc8bfcb5fee79fdc2556d1e5cfc7308f9808c5cc9289ff5f808cddbe769ce099ea696f471b776005bf3bc40d6608513fa2fca7be8f9ad1fa2ca57d23f8d75f3924af24b1e810b09748b05b90adedd91b156247610ac0791c697877fe1413aeea201a85f88df054aa098548851d96dd0be752224852407e88a63080ca8585c38bfda80ecef1068fdd0c85f05a4ee9b74bc098a2af580c73d34fa65dce720b7b7eb5408c9eb9afb04e61ce32625bfebfb65e70ed279d05f5c1385733425502925cc6b5353792c8556438f1ca60aae655c5857466d9a9823759bd664f8fef02b7d2b27e513262d2c62e4fae0abf27bbe46f10011e9bca1aaaf7265ec8780a83f040993d832f015136d4d52b1a4609b6f44e126fff22f66dc177981ae019829f18b1476463606f60e48d8f6e15d45566f8cae420fad98ab2c01229b5d51f832e6fee8c34464987576b465b41b37416d7a8b5b3e207c6d911fba94518e8109d32d95d281f929f191dc4a9c6560571c89d3c853f0306f6dbd61f0c649b821e9d30b85a1d54e8208ca848d0be42ba55a2293e56b7487f0f40e4c6f3a2cb128d076c3a20c9e04006902e16df621c18187da0d9b312641af9e72ee2e3e880924dbfadd368a4c1ab6a4f01b03efbc5c2059ca4478bd845bd61e035699c00e7462e1ce5a7ed50f9121dbe9501025f96ded0c3fc6bfd90a1e26f8893b724f3d1dc94f261f52ece24aabfd702c738b4ade51b0488478eeead00ee442127f62240de269f6b976b831e71bde0746a8adeda9bb5f7b0e963ab072e4ee9097cc4c49fa10eef85f872da7a1487cb32f8d0b2af9c2ba46acd99be9f03f4df3aa9d2d597cb9d559e726b665c9576ccbdf12cb788cb806694ecec8a26b8556a8cac06467d00d5c432d51bde2c6d78bd84c23e91bf9cdd03aa91c3ee1fc58a4a3cbc56054e2c449d0c55305c15a5399981a229dd53793ab8721757c7eeb17b2a9bee5d6de52a6e8edd6397591e889ec1a5bbae822dd819c038e57c1958827689b5b710ed22054226dc80d1c906c0601ff60899454b9a6dad7513111112b203a50c9b0c4c0c138b2862f434ced80ad1a9c9e1a045b0d6a47704f35c5d85122a749478ae584488ec6e6557db40936b222c7ff1b1c8bbdbc9ef222c0447a4f42b7774d16569acc7ca47788a1ea2b3e029446f1c8743741d0e4aafc331ba0e47d774e9077da4f6ea2f6cbc15cf62e5182cbda3b642938328d9d1a18aecb430079b4c80ecb4b0b324832e8a63edeb7165f8782d10a853f22b62df7b57cb52898db8865264156cffc4888d6f1ad7da2624479792d2cf39088844ae0d19d295bb954b93409268743d0b878cb019f8e0a327432a628d48834de01c1c099ee52b17358e33b0353b251986e14ca3c311a65a4031a8186c3c8c1617c59161a0ee6aec2a2c154288d48aa374e53e2cda08f8b2b80f87d63cdb35ad556a13638ca76e51975601064bbfd19aaec9f56a395317de6a9d1853157e46328fd6627614870bbbb9244d7429de071051ae8f5a86af5ad04b71b48629292a1736535d0b80e28d913760b3bde72b50c031c6c8f6d9ad5f8f7f176567c4629fc7deef18b2353b21cab6fe5d20228a43b5f882bd22ecd6cb73df5aafb05c340019de723a9bf3c28a31c6537fb9468a6297a2225a6119b5c870f65d9326c99417ecfb176cf3e811638c9f80c3e28d7e7db016cb65f5fd215befea7b65ab2f7875add646095b3e493d5d45961f1b6c3f073878746b994717ecd6356da44bd0a64945baf4baa66bba8a26c1c7ae4962fb220a87d8482ed8510e6aa335f8adc1972dd82d6ac1c62adaa4c521ae06a55186e2e0582d57a48eb40c915f1138e9119905bb511c8a3645222bebc23c19c514a0c5164d8f5013d5a288ab297d79c91bad89d516f6bd8fcc215d7ab8886913f3b070259a02a715c195684d6b5042d34a4e129d8793db82a7298040bc0421c4101a0923c9f00f0bda9852bdb516385a746f515353535ffd46b7a8544551af6a156d72cd83e24d664886a2c75414a5349e7e2042a4881118e5a495aa7e70b9220f327ce441bc8957443969a52acb72b95e116b41486ba089058b7268b9be48164c323932ae0635afb871f38883e1d15a1c4074ec9b157191e12b51d7502d2e9c87e5d070b050d3261d90041f7dc4115d5844bf68520dcec497b8a2284ed71431c20e9258aca53594c915ec366f722cb48143201157e351b556b55ab55eb562b57a6acd6ab5b5be1b23f71281410b54c8cf00f9e1eb88fc80b85e9197ebd9bd04110fc51b233f77b582b844ad491cd82134120b00dcad1934aefec2b2bc1bd88e017836a7d3a90438dcbca922432b3c242c2c773844f8219171d145788ad103445ff90afec048f41519d835de1e4e7eafe53e246d04fce83a485ac9c9f05dd346c0af5c774749bc538e6d5af968c72957c1bef785445a835fb95052c1f6bb8676cdaf75cd13ec466b5c924f76b78cb85e115bba9c33b1dc3d2538130b5eb150c822fcac90e12dd3f5bab0a0ec4e716ab55624fa29ceebc2da9a23af0b2bb58826d12dd511dd3ed2da14accb1bbd14ec26ca4d7120091e5e46c16eaf0a89632386266bc9746b3205b82414585e235a48ea5880cb41d3c4e16ed5b8e413ecccceb518f9fd3569edd4568dcb86661d71bd22560ba7b10cf01bed6c5cae4b29d9dd3ae2924e88cfd1c49102740d34cd1b68bda0f761711f126ea0e925e191e061159064f89e90e1b779843a68b766d2471a8b36b11cbe6bda069a56a4ce14a48e732588738be5c6b67dd114a40e4e1fd6a821b3b0540d2f20cb45f196eb073b4219a7a4f3521c1c1bf1ab545b1e6ca66f59ef3d4ab5e812565ffd7defb11fc5c9a15b6033afe17bdf77df91ee1729c5740b9ad31a9cc154a7358829ce7b1137c581d8dd60be70148f7ab1b5914dcb5abc2d1ad3b8cc8512baa44b11d32a74ba347a98d6509bd6b42f280e8d0b23cb503132b4a70c1bd321998a0c2f9b6037fa8d3e99778af3228df401e9525bb0f176156913c56912a498071936136ce8ab02a74b6e0936d674c9a699349303500cc9a39a80104211ada15574c9c6000740c08d78651c09a01712981291d67489b21070398aa3655984ead28db6ac8c233e1bd4bb43f48baf4f2ea9049bddad0fe663e522dc0f109d05770dbc418dabd1376dea9b216dea217d829650deba86d6c4f8c172c0dc49b0f4db3b824422c1461f3c5c0dea69d124687a479a042fc64d1846be20e285cd920c214e4b9ba04bc245ae9870a53e81d35ca9ab70193643e19658d88de2f4cdbc621e7135eae12d1c09406226078d0e4c891d17c5141043580e2a3f8bf34e0ea6ce5cae4b43e4ea56f0b469127cc32619be5e2a534abd2356acc418ad10ddca71c57923c2b466dec0cf6039b41c9d680dda6002adc16e1aaf15a2575a13338c3d24c3d31a4b014c6a1ccc11baa64b558692499736fa6622bd680dfe6dc1c677dea44e86d4174e49d6f1825ac14471e8149c0f57a3ca9d240b19de83cdb43482ed77de1cbe5a63d2a522d88de2501c570325439b3ed8c631c6dede913ebdcb1188cc280795e35d7677665ae120adc1770492e045a223f5baee575bb8c7d2fdb6b82b2611bedee9ad1c39b09919a3744364eb5d3619d21a52a687828d96690d34890e4598077c4d4e72246b99622b44a76ef34892e1a108d31c4882a74a32bc8e5cffbab05bd7740da53514e7886d4aab3baa2e473c33c5e912a4a72e4571ea374a45548bd660d734091e8a6aba86067b2782158d1ece41658ad35a66f9ca2693fb14079a641c4e4e866759b99aa56308a3961d3fb05208b67fc0e25de22d055cf20abb754d697ba7fcba26c3cb20d8172c89cd476b103b2186d04800984103260031021800018a30a2945993cce7a400356c1c618017d001107023e3a828dd396082e55eb6d8857db7ae36b998ae2b14dac946b0bb75cd93199a7182263573e614799e5e7c030a99f08b6763877e2b22673472f6926557ce1edbf46cf00644268221b125e67cf6f8c59cd8cc9c339efcba2cb75d3a397cfce26212c1882787d208c466288e4c5aa357ce0f78ab55c66bc19be821bc5d43c1541daa0846dc79603c22e8afd626b6ad39275ac1708ca6fdd6b381a6d61ac9b311897e4d8b89b9b2ec9b966bcdb22c9bd7675eec6a24319af68b44d6b64552abb522d1af693131d9ad8c04bfcb49807fdfd88889dfe53d8e1d24f5c018e260580349efc13746233b5a88d144286bc4686076695cce3e311d2e6738e52ad9ad09fbb998d15c3b2e0c330c4f0e26c339a88cf58eb5d65a4cd43bbd83c568da6fe79c380e8137b07af5edd537adfa1683596badb5f6169665d9a9eca0ec317b28fb4976c92cace85b1c82b798184dfb43781389a0ce077f74e6bb88181adacbe7e7373bf1064426c7225bcd710895b14b6599855df9168740cfcadd5c8efbe213453c7d7428c1a3878f0934610127803c11448a29de89fe824cc078365c867127df687b5deea1d0c7e4f277e7725d93b2bbef6497788b529a65f44d816fc0795d7758769ddccf3c85a733cbf0c95d9bee096e26bc892d61e50c53fa2c3b0e85cdd0ecd26f4228a538577c19d4a5cf4fde489e0df7f9e7f3c6e9d2c93fbd332fe3607f6497d8ec509768865345bfb0990c9b992e04e7c4f006fcdc93ebf6b5c3ca145bf736156df34e7d6a2d7b46f149646dadaf1813d9b52ed7e1e89d2e510f6b40e3a890d48717e5f4dabbdc8723bb17fe4224b76b7583dde08da5b7bd53c19bd6688621132a3b8c62a853abb53756b8c02b906c229b65f0ba60e81bd4d9e952186d72f9df77b9f7780b1233c59009d469ada96c2f95fb04d6f30deab89c1ce4721b477577621c1757a67a278ad838fa3145c81c7183c621d12537aff77974c966effb98401398c665fa205d1ad1bb9cbddde3c9c99d6d9c7ca3af5a33ea5dd9057dde8f925afff9bc667babde1ff5f69e7f6ee35428680e4141b33d3663fff96c9d3d9f3b3f9ed7d02136333f0fdd7a4f15921fb603f46ac197af93ead7754aade35cd645274629bc317b765da634a334cb32680631f2c3ac89cd549fc76e46e960ad83268ce211132eff7bb8fc780a21d04f81618a7bb8fc3f9ec2050bc17172066bef5ac368aa83b1af0e06d21bd0669fafd9af5b9febf17842f7787e03ce19aad565cfe703ca3ecf3eefe7d9bcfd3bf2b9f3d9751974df9cd5cedb389b909cd5db8acd647834efae7b72b7ecd5b5e8adb2ec5595ddcd5e034272969dbc72f973879d602868fed8bf25ae678de41191ddbe23ad65ffd8eb72f6eb36131e119914996658761ba7b5ecf46e422ef6ec422868c6e01d865df14ecbe5aa566c664623325a4717aefea0c16e356b90044db0b7182b543f3a3692609e3a09e8eb3f2004f90fcc53ff007d7dcf53ef314fe11ef4153b486a1c924b6cfce99dd7c5861d61606d419c9555388855eba3b4e78452c6182584b33b5757c2c1be6cf58e5a2b76b3fe066c263c22dcfb6e2f0b19636b0d7760c1e8221e31d17f7fc0c4ce3eec20e92736b6bfbd9a131bfb5ee4d96032440d0ef867638310a821c317f16cbce3d8e97e5758c24e15e5d4c23ed9c347b45db21e1f125d8fd8a3e771f2f0f00828166fefe40ecb31439846935ae56a27d7b921c7a3382d43d0ddaefc36203259d61c2b95944eb9ca5f91216d123d3eaebc21364a6cde13ddb7a449f12af73181a4f894f8d1b1551434ae55ee54ee95725d935e489bf5049a521e7fe9e227643394d0536e6c12fcd80ce56e0fc9f670367b855e4a11c9456b31254a93ca33ad7c8bd6e257ee4bd2a498b3c46ecf467b3943daa46293f2887295d0534244e2b3b9c99149132b74fb2dd1f1e27d114697240e5df864140ba0df1a43cb59ae5a65b0a14794c73f1d57033efeef75f6b25b0f8b6207fd66af634779e890ca7d35a94f9df43ff610e5c6d06b255958ea6ef5e4da1c498ed9dda8bc3d259ebb5d8f9f401316e8923cc4340ec8135d92a24bf0bab1b5ead6ad0ea672d7b3b6ab94d4b5226ab556a484469bda29a17d5262e5f694c0d71b5fec183dd29af06af929b1b3b1a56d64f421bb981d8410426865fa418109995c828dad550458cecae47fc857c6ae27d36cfddd2c5bf5a2920ff62df226c3cb5fc62cfbf2cf04362671350890e5452d7fe9d275f998cd6d91c99c232ea955597b440e34bdc867789349b23c96932f2cd39a14b5b426af2c2f2f2b29bd85a63ebd089ae0e90f4df1f45a9762a68fe9120d2a1f2d0a4ff9f9e90185136e1143ea542c58520cfb1460f5adbe4c600d60a2e1636b180d8c30be1863742d9e8d03199ec67111c1885f442632323231da7b0f8c9d182f4a0f92952733c208238c30e2247e2a2c2346631dbb6559007481dcb546d55aebc927da67f7880cc3883b599e56265fec60b74626d82beec4989344d7ae64eb93ad53ceb22c0b6f40642218118c4784bc73a2fa3ceb3bbddb8c0c2d301e112f82f17997142c9745b6de05afe305dde643f4b552ef4c4abc595575f24ade52d6a5b4eeb9d52d6aade52e84625df0cae265e5f599d709c85df417fd0df8b92ed7fb3eafb54ee3c3c9d62936d34c386ccbea19cb83cd34ae4bb01896d1666a59d6e575bdba1ad42feb533e05624b58d992b73c28957b8f0f8b2c253623fbf0a42b1c2a6374aec6bbeeaf23d8f923a143892ebd78449e169aa0897a3422c628e34cb5e2902bf59c96e22d096482ebd7816aa5a4b44bb3479378b4c6e35276f77b33ef0e068aa08906bc6ad5e09d9607db976dd34b8cf1d13f4cfe61f1925af07aa9262a9a6813d04461ad7a36227e2b7844c06b3a3a2fc61763b4175e0ad30a9e0d9223021e3a2bc0b736c6cb11c3d8d812cb59d9ebc3f63617218eab71a37879b333103fd1c46eb5b60e183859cedcae6429a59476962d8d5b28b4b5c88e30f68b2e52cfd59a7c96e35629ea53b3a41c495607d305bb392d5c956cb0f1cf069a8a40424797e0e595e8d2bc3c8f2e6197efd1257af96c4ca07b9e9daaacbb3ec0c9af6397073481b08f26c94b89df49fb58782b42cbd2ed644a7ab06b52c55b8ba418091dadc9cfab446bf2468c4088a4357927df11235a1c81cf083492e5dd8bc43f1e0ed5b1e6ddcbf62c6fcd33587a778bde79b2d4ab59c4be316cb57048f6c1de801a109917f9b4b08ce4d733260beb80a4f80a53b80beb5ab6abdd2d34557ddf8c83894a28a2841b7af516998b248491671c4cb4c91676bd1b917030f16dc14b5e29a6b8ef741f154d8a46bcb7086cbc14ef54458ef14ee888f1d5ba3c98129802e60dc8c476fcfdf6312cccafe2adb31b438ece0b0e0b39c61b0e2652f79aeee13e59884493e229de42f9ca8d1bbbd15afc3b438c5a6b4f87abf1a28d6c4b0a96b3b2d311b68a1bd8cf4d9effdc40d3e7f39f23d0643fff41024df1f3283aae861079fe93f349f2e9c2b70fce4592e72f928b73a310c48eaba14dfae0b49e911b58eb949f092c3d3de56a5ca7ee5bcbcd10b9e5069adea6422488ac4224450792a68e8e0d529028a9ee01f2f6137b40fc07cf500249f3f6ced0b9815d837d3a364e3336c7c1cc4b2fec6689e469ed8d25628db81ad8e76d0e5c8deb9608923c2d1152154d9a43304f663f27a0d0bb81850740f664f673020aa1c8d82f53bc552067479a74a907904d36a749f349c2a0becd10c3d613500825c552b1acbe2f67cb7e4e40219414954b001f8a3aa128104585280a85a252284a85a24414e56a749e9fb164860e34358e194a6634a171ca2bb0cf045608262757e325cf77130bbf0991034575ea188d1de26af4e72d0c9c0d9b53854d972a19e4796843adcdaa49bd6acbaa6b13d9a49262e4f99ea719823982ea26cff69cbaed82b391a26373ba447dde6e6193b81a594a1abef017cf33518b88ca6cd880144680e79b8d8cf264293a29697899f238ec0d79fe82439eaff0269be4f9cd3ad5d7d0b309c9d48dd8c9f346ecd4b8713580c8f3463431428cd2a982d082f0821083d0036106a185f003e1c78b2e550f808d5393e6679da1a44f5dba3396ccd09981dd6ca8c16e3394cc50f26c7408e0fb798b09518a42690aa52a948a285da19485d211a5d0c6096c9c6c5061a3c6d5a8365290e70d6c9eb766d8c1d9b039332616f09067ece4b9cd0823cf5b28559552552a55255a6119b598608612687a9f9ff14597a83c1f63e36a90f2fc0c9d195ee4b9cd6002a10b8487f04288210402c217088380b72eec69c1d257ea3145f4b718b993a746a3b53943c97ccc7c8c125783fa8c45c8a73cbfcd5092e73b6b1ddbdfacd37da2b5f96ee2f290e7e71eb090a7dbd1e1863cdd2b6c867a34b215f64e3898791dd064f1cc79afe6749f8e3a9c13009a3c93e7797ec8906ad9b2aceb59588e97e7dffb7b3526cab81a2fc7c428f1609bde80313158123147d4dfe18cc1d908a5a49794d2fa96a2dcf256d7797937a7458e9fae663902f70a4daf94be37deea67534ad56aad8edc9791690242082185b549efdf9db4c69d1ed8ccf84429554aec1e11321e9a2a96398cd88a7a7a23707d381878196892c0ab588a37647829e3d290e19f4c8652ba243cde1367b0fd28e28d12bb9d27ba140f372746fd8d9637486b3c2a4e02934c22967bb981f0c67a4f36a171d6879d4d5fadbb9b5e2a8a983797c425e911a353c2e4ae99d058e92dea7a5dc0537547fa1487c8f0044dd2083472ca9094e31111964920ace0957051ddeae15458be7ef050f4e6c81594482412a991488bd02115ad2a55cd8a7afaf166d95e276d53299b24491776dad43baf68ad3538b3c810463c6f4eb6ad0cff03dae44897b678e48a78135f92c785922b8e401c9c8638d3e6bdd82f763f3c87d84c22adc1d82ff62c02a74d55554d2613f88b89176065024d9db393eba96fd11a912e3d13e5c26971c4114da3bb6b1ea64968cebca93e7ab4c6830b1627becf254d829f4b54442b2ca316193f3c240ee6c98869ce1decf6dc8d6e127c3fa9237f805d6b508621bdd0690d4a2638120fb6c2dbcb62496bb0566b45a2c318690db4a13536b04816d0c6c6e68a184633914c62a494d6446a7324b68cac456efa6da35eff7af8b86f08b5a9a1554dcb29d82c6884367deb4ac9ce93dde733419c285d0dda6f029b68f909627463f7888038d024759e7d905e47b1f5e07b13982d9bcc37a9d83d22ea6d5a83c1a53178d40719be627a830c8fd1b9844986efc96432a9d38b2e6d947a9d5e4c1dfacedb5c926175fbe60aec967449274992d89f492016ad69fdfaf57b930734adfc48bfe31fd9e29ad2ba5e110b6d2692790476e8c6b25e17d6bab4daa679d045ec2336f3798c168b26c167a1856c3dd8cd25a153a6c16e2e098f7e2f1ec1723c4da955a55651ad2bb5b2d43aaab5a55619b5ca79723062b40691504be97d481e16408ef4b469126ce7a6cd11d964da64c74e3cbfb0990b05a2c1524fd22a9747e5ba3c297874612b58ee320ab66225846521ac0996612b44203cc24ef0c4355b853694524adf9a6c72411938130bf6017100ade837581eb55a5b0240865c402e8ad80c21e26a50abd6ab56ac564fad59adb6d64fadf43aa9b5699c365da2bab02ef74c5b9665b5d5dd4d598fe7e3f19c783c208f27e4f1a0783c291e8f8ac743bd6247313613773cd529bd55dcec5d11c52a5af495d8a3abb0c95de392f4e8526c8ad5eaa935abd5d6faa9f5a45650ada15a31ac8af42d1b4b2bac3c36e58d22e6cf55636a1e4d825c64ebf89d78f8a0ffcc54af2ff7a9166d06bb72d1378a6362b14697e63409e26c5d73961ada550645fd40512e14758aba1485290a088a7aa128fcb2c874e58a9aa21e23164f511815efb05ad146d231a62c717da336455a832e97c16675c542523ccb5db9587d750b93e20644a66f740541758755faea7604a36f3cbdf18b4744bfe2c82482f188e85329e24edc7958c466a445712014345e4adfb752f45241e372bdbca38aa358c0f58de268af794b0436079a463d333c6542bfd871352c3c6262e5a2f71861168c45d8fa21cb5cb2ec5976b30c67191059f6926541645975b5086aad225c9368984b42066bd39af64e514a8720c10b0033e445635e3001b89aa23c17b6ae85cd54585a612fbc691a8ed8dd348a034db4a64990da8e0d3b7afad9ddae1c67ae78b79d72474c04f197f708023b487ac13d62c472c8e922ec27b17530f00e0694e38d9125e830e4b2b2324f574e57565080c86c200c44267b3e51ee728982636b1ebc8d64b4b48ca688e5a2b3884422118be823d1487459226c7d645d5eeb638d46a3c35b3b87ec2f679fb8fff068c7f5f9ebf33996dd619f63d731ec1f1048468785d292527fb050e64538e507199607a5056f3f0ee14d83fd794f0eba1b78394be2da911dc3dbe7d9dd7afb406c06aa80de98dcb1f320bcc9544fb93f3ea79eddce0e933bb655541a884cfe60ec2ebf01edc9dd746497476c660444266fe0613b50f2e57287cdfc0fbbfedb44161425437dce6f9f2eb75ce460af4b82b175a664327585e4342976774edbe4b48d8bc8c5a6e04d2452c12e2e2e2e6f6cc6053bfb743a070cbb75ce4e18395b24e142c9121d2f987cd12578952c1722ae7d74c90929a005ba34278eadbd390fb1a98722a1fba8a096754707dd95fb682d4208218412db11732814bac3243613fa3b621d5af8405c823e55be3d24ced960f9f69cb0019b5924e8d39a204b5ef877a491e0cc9d77a499007142d7056f2fbb7cded1e896351a591fbdb1991176b647d70abd106461f9e896e7826ebd6be5ca7b2e089b81f27206b605baf4f826ba5402cdcfbb7c5eeb139b71b9f5ac14adc5d3e706209ee251d15a8c31d65ab3e7d63929a5d97329a574ce993d77d65aa594d97325455131c6ecb9b1aa2a0861f65c6859567767cfedeb7a3856e5d785cda87ce5beec5139044da03579d01f46d3848389a2b78f2ec90bf194bb36bd1ce5ae4d2917e2c6eb5c935e2ec43eba4451198a6e7430f2405c7c1d11f22c1688e6089dd2cb1c5506ddbacb75f9aa32cadd6a4e79cbdd44390547117395e3a598a24bf451d1a510de82c86859967c83a5fe4e5560d6e773908c4b9796ff70eb07e82a077dde02c12452aef2bb3591650a4882a41c85ae82b7118dca27de40a0bbdc4406894022900824028940229008240a7d45e5220be4297ae820516805247a48c482432b786b22abbc3172e81975297f35e1237e02d17991e3bc50f419fabcc396503988e68d91530e7aada310cef1c6c829188a3746ad8fd29e134a19639410ce6e19fa4aca574237b6167aca65282547e8290fe1ea60404fc1d5c1cc3746be0141575e74b7d069cb535a2e0f25c6809765ca1dc60095bb819e824f6a60413888c42ef18f96a7e01fd7651009c2416476f9757a8825415dc6d65cf03d9778fb2106810f5b00ca02503e42b91b08f2687e24ef0874a832ba9c071da28cee198154f0e679109847df229431c232ee91717965e043bc058159c23feb3994f71cfe444229e51b50fe32ca27fe017a78b4839aa0797f80fe5982fa07f40ff5cfe7201578b726f25c09b5c0d18a0f166badcfab8282f2872541fdf3c11be8281be828b750eed6d072180d7ccae75579cff91b10cedba7dc1fa0d7d0516e672bf410fe013af56de2203283f0e7d466795dfe6cdf9af06014756b567f18f5ea7692d662e7e8d4c75a6dec1cbcc1d3254c2cf59c36d8cd29c979ae5748f6014d6d53a585a2a9c54c236dc2070dd506db597469735cb44d97e41022458cf0a06fba74c591c6a24797e69c129e7ee80c84c1925fd85a1da56fce9612c6182194dd33935fd89773bdbb90f7fa043b96669e788fbc73f221c1dbf3380ca3719f72be712e6c46ce997877abfae89cdbc2794e29b5b516d78febb17aaec76f419ae2ac71e82ba62879790affb81cc5cd04bcbd7c5152cabb9f468a72905e188dbdb3b0259c8cd45a47ab88e92929dd69bdea754977379b614f21e31679830fd29483a7f27483b1e2ad3375d938191ec24b77eaf11b902bc6ccc9e8dccb943cc568dc2b0c43f7f3774fde1774cfb55c8c91fa45c58847f5f49002b9f275d089e7736393307cd1ffa0f075882d71658a370d58524ae91cb6820489b0e21ff2f1cad4293d05e49291de087fa3afed6591e51f162d5f5f96977f11839e0ee1e075d5b72c0cc51be3a26a7d94f69c50ca18a3847076e7685d09870829485914760e0656950272658ab38097f5c127c8cbab41271b919d16d470639fbd5ff2977cafaaaaaaf07b184683f2f8e8de83d481b8a05728c777fe3fcb7591315a518915a55486aa5a250de11ff5f4d6c178364297f51510afb6cef440e0adabad888d86ebaaaa70a632128f420fdf68239f3be811e276886319e9270ba83edf65a6f7a4061605c368e4df75397f7212de6234bc694360234204f1f24e9dc268e47f58787b95acaaea5975acbaadee0122f391ef93a2a4917a670e5d97eb7b7f36c39e424626324816236f557dd4466d2f57fce3456c098ab7ce28f85bdcc9d4231854e22dee64262897d589146143a3469e5a9a3801c4e50382121fb6847c2854f58ad1a0fc37201017747cf3c9dd62eeafc70a00bcca09688a81a4fec55b75c19bfd818988056fc7a28e89c9a0c77cbec55c643f3219c39f3b6c01d63d1f3cc21e7af51bfd8ca8e02d46d38e82b78b4eb0910c6f167b5e3d744f6a6081c8647bf2ead74117a3b1ff718233fba7a486469f5e9ab4ece4fef4c7f3ead6f3ecba2c3933d6816cdd825711d9b22cabb22ccbaa7e58bf5ebdca9675e8a90e805baf88d37889eee5f7504726d37609ab5ea1a96ea1fc6a06c0b56d6977f7c43e5d58d86da3f589585bdcc999a70f6dc46862ac129ba9685cfe5c623a5cfee0132336e6ed93ede127ca4f4e82d041283f790f14ece0c97b84b083a0d32a3df5d4629f9ae387e6f899397e648e9f98e307e6f8c9f1f3f9cbf19b10ebc1f2e3a9d9e2adef3eef75ccf31bb081c8e40b47301e113787ccf4d5a56e8e97e92bb6f193411085642d5fcc0f5e124adb971036ec977998f221295e14469c940e241e123a5a8b7f5cb4169130491d1d9c2552496bf13ab0dbb9b0de83b0bb9b476b11421a4f217c144b2f5a8b4cda88a8f303fae7832875fa51c80c44091523a143eec1c653bcb92da6bcd1a4789c89e580f9861e6ca4f9c887e58d6db2f16f89857227fbe2883bb131a6d0633df966ed379114d0f479ac304ead216b4122d1c96f352d3ff7aa3b76cbeed94dbb6b37d55d755f957abdacab713dd66aad83a6ea56f68917485e21144c8994cbba2eca63e10a43528f8aa51596e20d5e3247aca692bc9b6a8524497c1b6a685f114f06e6bf4408618dd530c69b5d98d35eafc76bbdabe5b9d4b35bbdaff5eb52ebb24cb6e596455dcf73a93f8cc6b29ebd6e5dd775e7bb5aaf81ad75de97eda5e2f3121c876579f97a167b633b0490adf997b17aecd25b27466c7dac91baa147c4fce7a63801ccdbabe20430f155b119dc165fd8d3510b59ed18639d4aa691d3e9a4022ca421f74fa414ac108391d3e954c591dcffd41e489bd3e9c48297be5d833c2121f7b38b0a5728128d9c4ea72143f43d9516ea104fa7d3c9055be4e43e66e14ca10ab8733a9d5090f52f2a070559d0399d4e33e85b9404b94fa7930cd890fb558c821a9aec9c4ea714001187dca7680f744ea7d30a5efaf553a4939c4ea7197cfab44242e39c4ea7169c20f7e7091688ace1c8e974a2c1cb0b725fd62a3c23a7d3890541f420f7230686dcbf562084dc879415b6a08698d3e96403041372bf2184f377be4b59ee2a88a1090e8e389da690fb4f64fbd714e527ef601f16aaa0418678abb9ada0052fe4ce8da39e4e3cc87d27ca8fe5c6725656638c31c618638c31c6189feb86f175cb7791987130391ea9df61c8bd851e223f19a3c537d86037a7c40774f0222545c0e8a34bf0d0076c7984392bfc8d7e36b032ba7a75297ee2709faf07d15461bd7c703998ab4b11c2f86e1430f70860a4b2654d8f943e5a83d9ad87635ff68824de9adfb1bfa65f30d18948deaf379cd92111680399c028b3774ee3548f328ad16487ba9cf05d91b3bf9b26f5f3e1d89779b2fbe892e759760f36935df1be7cbd7ba8e8a34bf1797ebb1c36a3b3411b9c9d67a48e248ed5024da4c1becf96b8deceb54b127b1e3558efbd771f1378f7f5c10ae9a784e59c732e4608f160bd22f685a096372bdf2bb25db5d42fd0a4bdb818e304cbbd14d1648e08b5d030fd5908ab95c93026c36b9e6c8c3d5a832ec7478fd6641f1abe4a29e527f06efa6075ec60b991d3fa5ba4e12e1ae507490fb602341a5eb02c88631d8c73779ae59c2be2edc06e3177c52207690f58a1fcbab04fd4a6ea4d2f0487bc9da7ef31e3a7a89f22ea135b472776d6a785e1abfb449f80c450b84292ab31b3d599a7b649a21a3af18b0d7160b997adeb7bdda78dad67f33e591e3f6d9a144fc5e82cb746a1fb50f9ca7d881c347d40083d589ef20f8cf0c8ae5cb2e091c5a3106662e52aefb18255dee3a2a760f9bc682dfe2d794ae410a7e4d93c9b5a53eea9d54211ca370d2bf9a0c1827ea3458f28f61bcc190e25d355c2e44d184d5f1732d9d1d1319930799969e494e96cb65eb7b3765f929cfc2b27a7cac2adae5025a9b8505231698aab1c0773ca744e5b9686dc97290036235f008ca6f3b56288d36b85f64a3ba5c91c9871f16c482439e322f7b5fb863872a49a4b9af46c54577044545ee43ec55928409533026bd5a874d6a8e12ccf3c0c40021e7c48cc5c159a84f895dd85b8efc661563c239808722e92b147e4c6352fbc320723c0084221d7b5e634f90880cdd0cb91e40a18f25625c92de3e10980edb8168e4bde6a8b2a4995d344b02f01d8b3295d9eebb2b559cf6eef76657b59d352646c8a8ce1cdbe52314560ad6ff274a20efa0fea27bf40d853b07bf2024ba150b74199b01dd44f6ec9603ba2f440fefcd2b0cb603b64fe5c064b02464161589ca200d88e983fb7ba06b6a34f99c2d483d40c7a83207f9e83c15e039b39d94067aaba306cc2663ef686b2e7be9cdd1f3297e7faa94b316649c5cbb50f50ef621f4088d79fc464216eb5458d4b22f1dc97adc668ac29a85308b82e02b0779a46a0a9ca11699b8f4c5d9ede17a759b766ae8c250173f52a07b6c8557ce109646cc77325b1b442085c6dd1a43e12550e12d8ab9999cf39ae1d254c72bfd2c9b1aecaa97220a95f104af2263b1a910e2d94b311771e1116bc164d9c000de64349a503db71738eef56a7494d9e5eeb3479a905d72147da99efce5bdcc97d29b003db7173ac0a883d1480f148924412d8cca3d975094e91a93bcda278f22089a74412980e25ae67e795c06624126bca2c9690482c89434f3db649884b1c99c55b8344229108712515f274844c6b7d194bbeb6f624129985c4a1164500460046e25202bbd15a5f4e234dea9afb42dc4c0903322e5aeb6cc9257520a9ad4a94b325adf50c818ddf322e322e321d6892279ce9f0b8444b6033f1f3667d7a395d6671258e44424353024ba2665c644ab225f8cd1b581200000310c090633cc545b426ca312f008be9c880160600012e115a02b3b67ad3750972e039923c0f6c0795e3df9d3cb8938969e46202b31a5051b5011efae7e80c3613692ee76ac064301eec82b1602aaac2d0092361606060602284e94700cf3ccc765efa91c1c67acfedee8e2c498e2f7be66ff46b18e5dc6a86f856071391004404003000210c22cb8270d391a38dcf351010426821c9950e217d0f52b7074283a61b90d40e705a9778b4cb65dcdfbaa1ff70efeb05f970a2df2af587bf17f164628b8cbf17a3122cf61bd0a4411e5d9269cde52d27c12fe393fdd380f70347ea43e14834ef074eeb43e1b4f7f2088fde5d2e0447cb1d3d3c62a2e5f73d5a7eff7ef11442782e2d1782e315b11f21d895832e7a4d796f166cc5bde85af1c353feb8783f80dea1f7ca3be2f2933f1e74c9723550de0e9ab427a48026197f990d983f77ae24e363a56b7622e587c35b44b98e4611d7e5bac7285ededccefb416e1c6acaccf76dcc229a46cb68b9536b6dce335878286fb48b8ea5311af4c300217d90ce1042bc0999e20bf807f37cf4b96f71c74108a1f6ea2a290f9ddcded55f6fb9a3cb72452a17884c45c15b05e1cd9ee00c6fc79b76b92da6c21b101948c10846040387fe80e63deb5b5d29cd5ba5336f79ab53cabc559a0873de2a0decdc18cd870818cdcbaf725990a1d673d198f9c1dbcb9f4d47b6288aa2286a9e2e01fa880995a35c022ad84112ca2520e426634fb90bddd2c40a430c70427290b1cb0ec110ec2741212146327688851ea2f026c426633a328637ebeec683aec8c1c014948ca258364f2cde2cde4422bcfd56c55b4c0cca8ea52b199e343562ed8077d98809f9f81e1247f75cb77530eed6c1bc5b59f7eb13c8cc8dc6c9b7175008e5eeee0e05876a05dddcdc38d1a4be6501ed17899e705e94c1be1b68b280cdf40948ea530b54efe6dd74f5fe2bd2a677c5bb7902f6c42e0bdbab56f63efcaa0abff79bcbd335c2bff770140282fc5eebf681fc5e73bc3fa09862071430d7e76aadf5159a4e5ef1861dd253b7f4273553fa10aecfb2bb365992c5b86277f166fde4534f6a60311c24665a7d02b932ad6ecd533f2a4c83507fa75ef10f8a25c4a1d6b29e5a58d125698c0992c4662836b11cd445a9caba282c074d3f07234653610aa3d1b64f96d80cfd4665f98a55b7aceba281580eadaa301aebbaaa276f619785f1a0820424b03cd785e5700e46ce5454f5a9ac675996656599bd28ebaab0998a890ba3a1b9ba757261183dc11ae0791e8fc7e3715d3dd5319afaea16cb61e58aadcf75d54a5a9e0bc3662613194643f39c01610d709064319acffb7c3e9f8febeaf96034d5e73f580e2b57d83ab9322a4f8be5b03e957e3cf53455904c61f87ec555900d42f8475fc503abdeb21e3653df7bdd0daf0b466c47ad568c71a4c309c9d4b70fc47a3446436114891a90dd23016b292a62d62dd9524a299fab1eeb37da3a0c85ac5b315bf259ee529a93ec9e93e0739bdd73dbe323319acfa4d88ef7264663690d654a319aac5ef53620bbe714d6c32353693cd4552fcd75eb15b6e3a26e5118cd55311a944cb1252eec1c8c85d184f275d58b613a5cb6f016f3c6c817f6b981a54e6f6118cdcb966561fd30072b0ff663385b028a3746bef06847152453789bef8f765441f2fc289e06fe5dc828e21df00f045148d516105ebefb647aca99aaeb59c1aa3af5783c1e8fc7635d48d09c9cbac3769cd0807ea2237f7e829bb8913f78b377f6c667f7c1cb0b6f29579427a5df2ce548f3a13be7a94b27762a197e5a7661f5adae94ce29658c103e0987e7de8d2e473c3c1e230b81af5ff0d3e91444ea5cf6ba359eb658599f565cb77a34a93fef045a6b3358eb5511326dba74b409a3b7eaede1a349bdc4feba2f4d6a1a5dda6c2c620c1b4d32b3e545b05a55c5db11ad751152a7760c83e568f7732d6dbaf013167ec91b0d2760ad22d126ca22263a16be42936beb756137518e22893941fdfd0694378af830d7daa494e6c06e2e8949e48386ca407abbae8adbc833831d4d9c6fb4135d3ac94e74e9e344976c7e02c6fa6aad48742d5278ab9352e2a2a85f4e74c9e344973027ba746527ba6439d1a5ea72a24b548ef43353bc71e019a97ef05e2720ce1df4bbd9628c317e4689a38389f2e1e8ab3125846c557e432cc4169240d620565a632cc97813f700f360b7500b3da52d4fb1a845f6154fe44a55e46accdad2f43224aad493f8d2c1c81bbae2b574895ed45a0b3dc5a19bafb02d96a42e630f75a9be9ddc5eb6e41dedd85ecef4be21768bf951ac514a9f1f95724280c66a39f89e7b6e7ab61f595e3e8af8d21ac5a3ce146f17c8128fe885648a6f1cbd0c33c5a31d549eca18d8ade61703bb499bfc6ec576f718e1bd76ce5defbde75cbff78ee5ac4cebd2bc28d12d246914a594524a29a594524ae9cc24561f9d20c8ef3e78e1e383d67b0f76377cf0f5e8bdff708ece70761582e5acb6bad49a9c73d259e79c734e0a53404579621f36aeb404ff6a9d73ce790a278d8dcd348477d812f12e470961e3dc4d489e3142f837f372746e7a03103c656907254d8ad7b1793b00b5cd3382df92302cdc5e9179a5682d9e88b4893636231f53c01495cff776301bd4720a1f71ce39e79c73ce39e79c3327c7478352547027c9995970dad468b44988cf8b5482f87c8340f3314f3c9a1762cd3bda31679c31ce2c04e82f3788eb2069c29e36b089a8cc0731ff9285391f757294d3c52841ee9a346a48f4d2251863658ea071d97ab4eef2e7fa7c0be517b297e8be226fc8b5ac7b5de5868e85bc54ae8f4e095d2f32a8092f16ddb244a23b4c45243a4c49393c516915ab52a9501595c7363d239014afa2a2729882b797559648c12a2a2a532545d430c3d17afce2baac5f96e86e2f8ba048051e9a5e5e30de625e82b80bde2ec42fbc89f0533010f53fe0ad36e90721b06b120d02bb26fd05bb26c938513976556e754318a39473525aeb108ce6e594bb2eb9aa7a548e91e009488aef1b488a541daa0846dc8960649f37b3694d664efc86a41c623432a7fc37a50118702452bcc468604ea1c180d3e23b074e8b9f29b7688a130e263e05b71107136fc95a6bc66ecdee61f20b4b29cd6fce99bb4a29219623858a31e658410833766196f3b2ba3b63b7f3c472a43c65629fb76a0f692d3e45e5588e26e26062688897208430e16f07e29b96e51017888beff4d1258aca21bcc9ccdb7449c58302a27813651025036f5a06ad7c5e97778e7cf4a0b4dcc151b3c8778ecba3cb3d2e4771798bcb472e6771f98aca1b22935d7288ee925d973f55f674cee8b2dc2d266f9d03b2d93ebfdbc7a5e4f2f847a44b7f14e10d884c9c837df9bacb751d6847d731ec1fcbb372196f6981f04e1df0d7b49818d055f0a6236f2a072293413f407719ee08814020102802197e8b405601815e708f263208040a6195837c64080281361d197ed391554e96a05c97f0ced021dea0065e4e9132e5a0a7dc1db73411561a987237e09241df3e3401b19fa864ad15b5492c99a211000000005314402030140c874462c17848a809abec0114800d92b0527a4e1849410e634621460c2020020000000000002005de42e67a7c0b47e83e8158904ef708917d934feed679bfedf6735903b3963c8117774d2631510b17168b564d4df4ad60b0b58e2a03284438e274a9bfd0f733f845803db5686a613e254269a3a1bfa67152c11563356ef59f41e91be9d318ff1feeeb85ad5e9d9211ae789ac34c2893c8747e99a9852220e598b8574c05c15c6021d1c9171dd0b60595ac9b4b552945b80fb8a279d448193483355b66ce0d6200bbb55c058a93f95766e9533d58ead7347bfed320422e46628c3a8fd13575563ca010a003933db1b39b25088a1cb19a28873b62b05b9e226f138fbb9d9c74fe8e957b044ade90c0c86c7c4c9c8b167933bc93fc866dcf88efaa78acff585f57338121cf3bdc5fb21e74b302fec3e5b9abdde3be15f84f43b29d5a16ae2a0afc34327797ab6294d23614c9b02ee4a50c5968416bc54816730848e8adfe6931a8f188d9f8c4278efbc16009041c55510c49bed62e78b279d04109292f36c9a213ebec4e60dfecce0e2c02349250a592cc0812125ae1a52479de0583ebb393d4a9c87736f21ac4e97556fc4fe5653316c3dcf940ae18d09df8afb1e886fce07640d6dcfcc2f091b61f9b91a6b6b1453d742ff66658a76d2de5126a2ddd5353aa3620d29a436720ada54643a2f74c004654e2f253006eb38a64630dcaceea76dd4eeb52e58b529940662ad89fc5daf760c9f583b98959895a40fa1114a379ef86fe6e9071c814d8cbdde5767356e013476fa1c0034beb038f4c1564cfd4d045d8d060e6e72a248ca3199bbec08ace839daf49f7a8ae6986967eb79741a12bda939847ff48f56118125937bc259055a53369186aec40bad408dc0997295f8c7a3e41cafc39f126d9be972dfbc34eab7b3d8f43d80985c790bcd9edbd91e570ba1f0aff8fea6ec29774a97e8ae41c984e8d243746f8245506c5da9acf051be1fbc7956986ebeb0d8d41c87f205e2105935d7769e6266372edbc4370f54e3cc7e81c7ed580ae899092609470015ce255be911e533c5763c8daef6ec6a3420638390e6218e1fd3e9b7331032a452b7705f1048711f6c49498a4722c190d8a62523280d4daa16689cdc2350dc5a04cf244662161bbac08dcb09715ed871876517fdab7caf3fb56d08f525f51c7aa02571f6d7ef3e029462a943087e7773ac90f90ef29b1dd5aa70855abcd9770e2cc9b930a0d07c0c2c393387b8614ffde35f1507ec91c55ed32ae03ce4dfc783938283839adeaa661184cd6c7b9eb78a6117d943cca5742c6d321e1f69846ef1dd1701f88745080e913276803e4a642a24baf0125a9fcba394aa50d45e6c06702648e220f487e128da1513585401bc37266d488c378a78cc72722c4c92b78fc28b692299adb691961a4ed906d93157f4f43706043dd2be006b0974236659ddaab5503c6275be5fabd3057aea501ab22d08ddc4ed74dc63fe11208bcb9484a8eba181337c68cd664b0b44b224bd76012c7dc9deb79f8d71b4fb5cb5f2ae42b4a44d4f3a0d71c30a34432900480ce1f133c43e7651686121adfdc7eaed28d5147aef4064fda5e642c2b6b16ffb5aa02ee3fa7dfe780f7dde291bce5e0f8fd780b295b3c3fac5592b39b248167ee43a753881be63051b2b310827e53c7d85bec2bf5682bc7709c569be88887a67aff341d38e5144644bfc4c7f183f31f1eea9e93d3b894cfa91801feb9937d7165536b80632e2501abb5c79a4109b8de61d2b180bb4e06c370e501b5bd7b3dc596e4305abf2288ce0c07d13d0484f90b88655f3c4d6d233b79833489cf51c33e4e2ddd20486b47c5783ae1a04a2bc46dfca0c6c219d0101d4ca87f69b17f172d98617a0cf49c0f50e24ec312c0965efbdc79df3ae1ee40187b0a8b166bc5c6142a2d61f0f98ce3742e682aa6624e2f245d321a267dc7b8de8273a591cff540179884d17a8e44992aeaf8c8d72310b30b4c798b0fe147f7edebe20fb3f38ca76c7deefedd14907d8f75ba2678afc58148cf676002c053a735f9c53b1c845cc800dc180c0fb056cf1fa951732278ce93e8badb8701c74a5e1f8a16529238755fee92825bee560a1cbf2f4b7a9d3177f610aee4a31f507f7a841470b3c8fde62b9a7470ad5126fd313cf94c45a0a4bdca0416e19a2038ecf2f23c3ec23a95fde39951b57d6caf8222dae2829da7c7f282cbda26d297979d337eb7ffc2953dcbe82e2da0f4c800e622a46341f7129db2835cb5f128a4301cd0b0bec181b52993b1da4b2bb33629f80c763ff0a1e03f1182c6a7f901bd391ce2b02c64ed7fca01722983b30c25dfe31730c7638660916e8ac685f5309fcf042c2d3c3d4602310ba11cb12d14692cbc94d7713e0bb8b35eca655a5ef86e7571fb091d765bff45efac65eebb3833884b537ea3731de63c140977f0a61fe6cbdf1552aa5a73b6522e14dfa83ee5b8b2d21969b22051dd8441a2628b5d5cc4b6e4985aeb5541f3b8a5b8fa05e8db331d1499525278a22b30d25db2a7ea638f20cae80f1b290096b2b25177b330ccaed4e36f19ea5714ad3981dab83f5cf30ea6d9946a1d4d26c3a887a5c23878e61533099900e71c3c4f1bfffb5081e2c1b0738bdeb0ed5f826400cc551124f3990e3ed0884253b47188b8092654030819404db297edaca2d552d6e05d11b28f6dbfa79a28b270b6a76d235e821a416bb4b6b05d58b636e4f968be2425e1a38ce9caba88302899aac182a74a7862ff26909c3b71b8b3938c30edd315f9b79464e40eb80983776866c8a0336cbed440e2b34962be1c71e1269f508c7acbd259921920a40562b912f9da576ceef3b7ed4c1461b467be873795dd235d9c21af08def2f8c3b39fd77a1b65897e4140b28ee7f7dee53408bb46d5cb06aa030ac12c76e774d950c38754d7cfd4b26c4d69991890d555bb1c790148d6fa83f3aa429d1a1d03c34cad7fcd5f75add71da57853d10b4697492ccf5c6b6fa860e878ee96d3f1f00534cfe1002786fd8816c4386424da8fd651a70b352d2ec311116bfd4c2178215399e5a2e174e6965bee34d3c8b4859d26aa193b4a061509a2a02778bb6b852ae913c365abe8030ecf90689f6ea2bc7cf8874d1b5ca74b854b03b7e38896179aa5867e2da20c8b54a494d4490b5d908575ccce4257be3d2dd5b284c54225d653af56a882fa2d9cd04447f1c3deda2da54956942a6dc3faea7af25b035ce8d32057921b4704e5f87f9ab39f781ff25f7fe52b43825c7d0052913222413efe426c0d578126fc21161da388b8246d3394d2eeb502f6d1937c6eb4bbf8249e9e9631b7bef1bca825266dc46ef81eeede901cbd4dfabc20e0bba8aea274c248dd7a1f53840142d55c76ae1d0ccf9737e33c8406bfadf29d00da691740ddee948fb820d8251fce2b33f3469cf55945e3f757f535b351a6ea7fa8ca6184857d71ba73bfa96474b10ae3b2254d77e879b66cafee0dd075dd9d1e459bd47847109f2f83d5a51cc9dbc87ed1ea48502924ab5c7c41121f08ebb7ee25f769ea6b07b014f747510b823812cdea44715dd2a17491e13028527796dce608359bd4865892455ca1de24509bf532a26716ea97aa591ebae4996a4574a1aaa4c126fecdf0bb7b0b6db71527becdece14990e6fc6687c7e2f5b1ed24e459c60f0dcacc0fcafd13084d0eb32cc5e7939c60ad6cc5b9719c002cf43814f78ea60b2ca111d4f866f9b2fa5aab69841b78564ec5c55aa84587e95cb5b83068526171ed820e1b93b99a6357706d37c0e5c40f07f9d90ca4402a4ee887ccda4eaaf9c59987877c52e1638a5c9fff460afa8fb32ddfef5602340eff60ed0b7a3e96d2c0c39e6cd2f056e896baa8b5b33df92cef9c3da2d8725a73df6cda7e77ce26ec291a1b4acce49d23536bf1327db30fdd48b7e3dea71e8b7961aa6dc0ab2f034c356d0c44d972baeec159a00314afc258de84df03710c3701ffc4c5a709ecf9e35f7a6dc9f920392671133e4989992b49c8d7c0f4e4105be79f59cf9eccdb9713d625515d41181c8a65899610c19fecfd945264ca00576f7b0a7acef64fb0a1e8a9592c7e47d6fb85fe851d3b829fe0462461674ad22e8247cac982cbbf882c1cc071741a1e46e51d26c76191b5f5c18f217f2b8e110f161cae9e286ec25a0b031e0f8aaa5f19d75096ea4e7da518397ad5e483b3c32a3192baf161953092c479ffed577e42c7933924d562865251dc6a236cf2abdb75b8bb05653b4ee5aea2aa5d2fb79b28ff5b9ff634f33f7006de41655fbcd9a9e82c600056dc4f54e9e7cb65cec5bd88cab713dfb26dd13a569a28d187ce27cd3f656e01dd3681b16447978ee923ee5e981b53e7d2cd53b478954e0050814970101848435ff1a0600c6da20b634b3e72b89fcb233464382331b936a9baba463ffd4551da914423a8dbd138426b46bfda17dbdfc01c94973a1cc52da48bb335b8d706a6563a449d911c4ae1b51475f35ee6a00b4c1285ec7331158ae4698fd261937156a5ec587d49dbbc971bd0e756125a2241a7278c2a5066ac40429f751ef30e9da2421988af8254ed07d68c50ec421e62560cbcd9b03c6b3de41d715789d584a51c907f24211629b9fc88acc83b4c809c267444527f684483dd591503556485b8a4bcfe720ceb2e5d67cc628bc6c75cb13e22e968cee092f94ab464a9d57633327586f22e5c0ea38cd22d5cf421bc7e2e92b3fd0b566fe45d938998d4d5e8f0f5beddffb6c141b291eb74c82b4e381a1e18f70f1c9de130d3248d6aeacf05f02d595097b6880ace9c97209fb007e2ec93c0234a8791c24682e59c96aa49c46b0185544d9019fd0f5cb5654cf1bd529cec69c873c6a4823221928717ed37372a0378fd4fb2b71ed958e735577670940f9246e58588e8ca9460cba81d403c6204373c3449e399571a60e863eeb455b780dae6e94a6093e3bdf807470cafa175cbca2366d14b7c7328389bd8d2226b14aa3b0b4b95411da9dd535275436c2c1bad927995a1f269f5df5fc79c8ff717d4b2a8c1fe2dc8615a9e1b268332283f4d029cd9214211f7aefda3ee90e678d069d16b0c51f6f07e349a3ea9199bb7bbae153970086539fd9a0fb1ef3803fe21f940a1c2aff3b61d2a95d66ffd9a5bc20e252dfe917d0dddaa1de57ec86952bd713483f58e295f28cd6dc2df73b1676a08e34e19800b7b2334a067b0bf47e5520320104fe8454b203489656e920b83765697a49a5c6a9b76121c6d83275e2b8270a7871ab3507806a8f8de0761643ffd4ff40c46a8af2c0d51f85196d0ccd99a05a3615b9a5f0e4fe2e4286e9422f771ddb16161f60e51e29181cd524f6bbdcf1456092674a63c477dc0e2777e91fb0d16c1d5d0fd7e88c5c6b2fd7e2606838f0da176c3fb51eb5a7f21bf8e0bbf864b04bf23422530e9d6fde10e4abe03b67afe23def6153cfc84502444b07adf7f531a6c1198d94d2b5513996bceabac3ef6f1fa91b565ea6c70d2882d451d72034e9803f22045485cdddd65c34b0cabe550c1b40b8cc7195facb7611ae7721d68c9111fe719574ee7fe46b09496e1bdd819706757fb9633cfedb7971f02104613a0154f833ad0f97542f3da229ea28074260dab314ecd86c3dbf8f9d3e4ebe5c09a30a143de94a2fbb8834f32295507a2ceb6071e1b0cd3c5b6f260594dc1ad557b4914aad6a3b76bdf57b5307b5f911d444774b2b19a0c1781c9622ea50ba72e4a638944278238e213257197ccccfa11f63088657ecff097ace820c3a5703118e33cdf3516ee2c4d3034d8ae63eb8386b456076b22faa69ea8d687d602228d5539e9096299d180024beeb0c112bb35d3d3c37235fcf917dd49613c2f8d80a346a2236433d39448feea93c21cb630b931395ee43feecdc770d60924e56cbf65f484ae5e499c8f1b1902ace53ce997d02bf00c3195e58e88764de578deba36e20a4878587f4cadc9683187171e7de60ff7d76988716d57661c50f942a46be9439eb2867d134ca331c2d876a16a80bedc1d6c9d608bda9ed1974207d3cb10a12dab5a54726d8bf27f9dfc5a83e27f46095cd600da738c3d455316ba6d9b78558ec1f1f85ec9efdd0fd0ea8a2eda05d52bf1298bd5d40c290dd16ead41bd29c818057a242e7817b41940bf6ffc08e2a015b670916a7ad91110b1fc8307357dec6a435def3f40dbe068a2f2153ce856e9d124ced224eb73c76de1fb672a4fa4975b19c19386c2572836be38155ca6bab6ac663293d48d804a351c51a1916c1009159ab0f3dd7c4ab6b37665887a2ba404065441d83364b7ea5ee80459e1dce4f63ddd546457a2a88131cd753a4a06a1033f9bd8eeee8b5e137141a9bbaafac28e493a8ea94f7566eb69ec8ab60c530ee06ebaa2a0c81439613894401a7b693ab1b433fd86639641c40122f925f6eb97d441191bd8759c3c1c5c0df51d26c9b34e9bc009929d5c0df3cf40f4fac0758124a319c34a77baf49fc88b196ff370a5f41e3bfc2b7cdd1e3863c2da8bed7804fb1a15e8583794ef0274ee4973e23d3381422db588afc1dfb6443aa156ea4824ea64d84fe4f4211bcebe6564754933ab18c5b7638941ebe2b9ad61696432f3721aa9b86c78a652702cb6de8fd6b451d6df670ae1328370756b8dae16e7e529625519ffd6c35ef12b5dd22c2bc7b90fd8223c7ecfb47019409064a77f911a70de1d965fa26f8a5aac21fd1effc2ba0597f8df9211f9c2a0a02b03e8700870b1862d1a81a0480d958cad5709296df4c1591b9f6a3468a1eafeba6b7c54ca8952158f4435e7eedb87a7aa15c4dafd60da575fe8b125441d441bacaafbe4a0fbb6aafb6ca8c0a16c2f64e4709fd748adbdc4f17305a29b6eb09e9dc534a4e6129b13d96be7882e760500b17914d7f9d55c776590666121e4d63b13516438453a34b66fba6fe81ecceb17210eef50cbcd78da0b1960b385e007456b8c068adcbcac266eb03eb6534795d38cb34b818c731498005a18c28265416c24943da9d727dba17f3bf50e69262e3a33a1196bd450d563cfe9de26f0c4bf96afec2ef81012b7a007017656e99e0bcb90992abe5a92f0141a4a38f4815ad94b25254ab8a9b52f7d9b29d093e43d6ec0122cba88e6ddf24f2d359f44391ebde6273c6d1093aa777c64601a8a43f7bb611ea02a5a2972993ba6c66fb2660b44cb6842d4b35ac87b880fd9dfd9dfc4d101f735dd9a43664d9b5f97433cc302e48cec7d0a7cd70dfc4c5d7808b587913e706fcb0f81f38fa957a61a6294720975a731f9c95ad3a718d403299e2e946432abe2a3513c259988a132193fa2428ba87126581d5b5307b363ba2888f91cc9c67940e9ee13a819d6ec344a0b5ae49e661bb9a02201018616ff4cb1a7211c758555f117de1a9766d8299866106b364aa27836047d0e4f294c7b9671c30e422f0f9cc0e76140b91d444a82566ca278b289a66160f0f8492445d8a0e4ce43ff1db30abc17dbbf239fd556f02192ca3d0d7fd66cf7a4690e68b550f10efae46826507b27e1a4b8eb88dc61737aa6784f00acb2df3fd951c94f7fac2d788ff8083446f15b404f4cdc78a483d641a217ea9e0623809a6b8bfe4cf863cb1200a356b14039e9556fd299d983af0583581a5654162423ecc266617d541f1768190ed118019105707dfeed67a55f6fee88b35c7484308a1c4f62eb4d1fcb95751bdf8772fdfec54227451b03d53bc4b69af55e00b047dfdaee4af45bdc1396f6d85326bf3d4cc4ca451d5c0809ec7199cac9ce6f228d0592898a2cc06110c705b551aeaaf027c6bf7e02ce940389e4a32093037dad065919c671c22987ca77d419dd500868a7de57a59c2fbe9273aaf69d28a7f5ef508a679cdfe4e2464f3607ee851f50cf04da6612dfcd8f6d9bba2f64e8a8f8b4c9283bb9d6adc16ce6195d6efea6ddfd6168368069524894cda656241891fe136cbf9f11d8adef2f1332408377337abc0746038ed66bfe24e6b27a35cac9d136adeb8cd0b51d9a356efbf6a9caf9b6967f393fe6b4a9435026dbb5feb4618ace665c087efe240ddeff12cea9d0b04f20fe616b507fe27cfbc7c08b6ce4ac3cd5b8bc884f986e4e0b2386107f5124f98c4548203f1d050a3df3b93caf594249a7d1feb36001387ed3edc8219ea17e658eb317f6953bffbf79756485f1164e474f52d95337e6f8f267c36dd9f38718bdea12d2a9ac782a7ba2f0c620ba53a3516bea6de5d897079b0bc4c1e1e1070f3dfaab42589f6e807c87879fbb915ecc66e76489c0b06c188aad37569e460a300343d1ebbee8cd3fcff5fb893c64121b90c8eb70ed2c7dbee57bcd65a6395068ede769af20b908a2797f38ca0f13ebbeab3a82fda0b8f4657115bfa4abc3197ec0c1019e860685f139ab8cdc5ef6072c7c3b232a4f8778f815ad26fe573a455dad8e89c4220f0c8dbd2ed89d38e9d87565c60b793631761253b3bfc6ae95140723b0b7930a6313faa19322121c615c49bad6240fab0611bade61279f011bb3709576097713fa62a027c360980017da5d1d251d8b428138af49c27f217a03878601bbf32cee682a8e682ddf502c05e2d4502a0d4bf3691637328988250e73a960a86c74470d582dc5bb9e6f9525c84683723e2a446e1590b862fe7cd648b4cd6707b39ddd234cad5392baa9350912310bbfe88e918b95b81defb4830ed22d84b54ff8ec842f8ff8fe045ff7f874866f97f8f45d0396891b10af02c813e29911c1a87897074ce05042eb070011cefacaf2bdb24003d6bf9343e39cda99062c4a44d3ad871aa61f2784de80154aed69b8cd662e7922fb5a23bb90d7efe8786d64b15963fe0e3382f6ab77ef8f0f3df9cbd60bd8fd46ea45f376a878067626cb0b5855ad7aae46fa418fc89251efa3318998114bca682047d8983fcb7daecc2d67c8974aacfe0236e7eac838c43da257cfb9552174fbd68014bce41606c717a74a42fe56dbe276d528604457244fb862e652cbb0c531695fc062a611fe89d155929d03c9029c8abc99d4e402f606380175d38870f5d58549b575d814aae3292e3c978fbba8b074fb6dd216ac7205485d738e1cc8dc43ac367e8cd95a8f2467921a0b65a950e4806011b619b9d6f9b659ea8e649fd6740ed85da69997636ba878bc12099c2c352e93457997436616574bc3d88e990663025a112078a4aa91a540c0912c964046ae5f9b941ed7930f547443966643b755599ee79772c3d9dea6307e0fb7c843e0b614756f6ad6ea06d297724fb991ffa8ed708c62fb1251afa37cc4c565312e3702d288b984f62548ab5ace2fce0ff939b43ddfd0050232b7fde6c041c622add22128b11d70822907618c333c42d56a896c0c842dd48901991bb3f2086cd6856733b6d8a716856d39b4e5a1cfd8de0121968247f4e4dca6bdeceb13eb76be676ecb52ccf24b5fdb36d187122e100bf157b4ac236668261f0673407090d97274390bef40c77d0384ece80728cf277ead0d05690fb552d11ec8f5590b3fbbc21f8e60467fdcd11b84665838b22c472468875747786504eb23b668640b47ba7ec7e5280abf78384be3c2ae1fac52f9e752fe136bf20b6e3514be7c457b1034033677260aaf7f2684e03f2d65cc59e73e5d164c9523ab87979ed6a22d471cce468fe002ff507a7c024c479fca6c2deea0ca315030b8c6cafb1e284e06452a0ee79071aca7479ce3eac739a3d51af798264e6f02f2ff27961c12786af326da10710a08bed1334fb2a67a065cb450a320dcb5f5d7ff36f92557b2ea56f43f697c2de9b56d92251f0fb5bec502ade268fe9968a50055c7217509720e2fc54c34894ddb06833bce0994bbfb9e96b70e7875e1e299a7694b69611a8c63758b1dfa53aaab25ac6ea5d2bbc2e3c3bbaeee92a4e89eb39a71baeed0611038b9335975b9f21ac8ce1c719ce230f7e44f18f1225a1b29d28f0a24e8562f469ac519cbc003862a728c46fcf34316bc88b00eaa5b0859d60e510b72de0ebaac2e44f7933f11dde963843911a011bbf14f9d2b875d7b64f8edc311b7c7896c23afab85c6941674f52c980a20f12ff869fd976a8e2cfe5a4cd2a0493c20f1d6d4133cc58c05bdb938dff394203e530a153720574d3006847413af662e7f98075b49a1f3b79b33babc73fac7bd7279c3c41cfe2cda9c9f114731dcd164bfac121b5619f64231982f4c82af2b5a97ef5f6cbe644a9242d6e5ced730ad1d156c3fd0fed4a42c6862be86e7d2d598b832620dd76b7f3d4e7431efd3c20f6847213aa951e881c205865533186ed5cb0e4490db996876b622fd149f8f6cdc58e2558b3c77ef5973be5a112dd860de4c4be599933fe205090f0993fc3a2e842dacc66e15a78dd1132fec65c874102ff95bf1dbb9b119027923d0fb1de851878267ae6f4ef867129ba8a0f5c884f1da63202736b3950470510a9a4d8c01a041ab70a693d353600c82ef0af9c0b812e6b67635c6461c80139d6be0beb2b926a8aafec129ca9ef6efcfd61937ef9eb926a178e1649d250d41f9b174b2a9c921d030d3beac02681d68e6cacd797d2c0bdda28de12b973f37fe1466b621a6e1e2c4bddeaa2571bf0fd5b0460ee4f23e56debf645e9525a434f0eba4f15a6210ddd1f3f8ba8e29ac300877d3cd31134a57291332ef5ab9a4b7907a03c726d9a75c6ccb8ddd5fc5923123f36b48bf80d2562e5a4a94f34bbd8e6c431d82de5e82bb652db6febc641b8df83c9662a4a898298dc8ae71bb4d47f0cca78adce95fa4a0f32de5be40f8ab15c0a6dc4939dfdd6a011b8dc761c338dbaf38b16c4fbace37c55b7202eed932fac6f70a911899e3310f3bbeed832ccd58bfa9407393d01373045a16ff0a443c31cedfa8486e22704cef0870c97cc59d6a5ee26497e490cd4ef51edd53b1c9d1925b76f571c7179c3a7e6c0bea65b7ba48b7ac9d54c95cae7a57524d89e22df352a6c72519acda9b74b4b4dea30baa842d1ef22503d148906632fb043a9c3a62b3231d42ebf651b15b7fb3c1586f9923bd7a4174ae1e314489cea754b93d29f9a630369af412a674d0fc4ceb41ecfa7e32257c66b43bb03c6be27d257eb77fb55cd8b184854a7dc034dc4f5ca307f024d7fedbdf9b809c3578f389e809b3a36c710fe33c941cf9a73af18bdcec44348bed9d8e09d5d711bd81d769575c0cb9ba57a8b1649c2c84d332f21d5b329f04a88c09808625ea3cb7fd42a81d3fa1b575c1adbdc953b0c1d73d1112fb46669e60ee2ca1411c10e0ab2ccb120a978ad2e32568f013f98b99eff46586666ac72ac34c25ed26f7377bcfbdbe70cfa384cd94545a91858b750808acd54f66223269a6e7f5e4019c08e23e5b198f8a9a6e6f8ea86767e2d197c2ea2404b19c1a4bb2f7a5553ffe5d8005be8fdf7a563c93df2c5c2fa459e01c7f147b31f356a754f7a76d6c3dc579efc6c12876a6a27619ff411a85cc606621b9e5beaea1fcc5a326a2fff340f21dd0328d6f351dd068480855b5a74435abb9e170a018a766d58437863708cd3252d15db81a0a05cd185d39ad2ba8f4944cbf5bfba9233fbf210f502e0099db72e25c1e30ba6665c804acbb05f80fd957eb1c2dddaac2ea608431a6c954426028e9f95c5fdce2183516114595b40cc91d7beff665340d6867286067284de1cc17e74bf450f296ce836870762777533479e092e34d74587acb70f5c343b0c52af71c8f18f1e23cca3d8a43db53137904517dc9a9b906abb657b30cad8a156bab71edf1c80aadfeb93e120485e112ace2b0cffdfc1a1fda89a5e278f07fc9fc629f6e28acbcbcf9ce11edd437a96a040babd28565f58d0b4a4910dc0a5fa4d957df409ffdb49ae7028723a041c24519e3449f07d1878e6e37fab2eae3a1b71f1510a76e4fd55c74aba300691aece74eb5bd946cb60b79419bc7644da2bbdc0de4b1d13ff668dc3b62df2e7bf05163da9dc354019f395c180d26ec2828cab14d2fda07d671e0a9776b581b920bb2b74e76dabb6e684ca1480758571def4eb2b073d308d4d2cb6309d4f2caac5c32e2782a8009ce5f84d8b5e6b6bed2a43e979091488a17de411fef8c3c10e26bd32628a63428ad65aa1d77a810cf7a616112ee5bd8f7862648211177df321c5c9c97f23007e79a78ee09e93256c82758839d9c12f5b8ad837bf3255a04371b1cd2ac81b9f6270d4752ff0b9a43529d1a9a01179376b34c3b5ab143c64d853e1dab076950b1b6d077d10efb35272e48136193454a789d168e9b32b9ff6244e4c328e4a0d137aa13166caaf0219274664d202d39327ac7e559c1f1beafb9d9c14c51282515eae02f04fd3f4a5d73f8f1818f360ce84a1d7f7b273c817e0ae4119d5ebfdb91f43aa9b989517331ec2f9c6629714e1472fc1e7532df0110ab47c016924e29a792f47bf825491ab065c59c8459fbc6ca6c25a595fde7a7bd951d460fc23832e99dfe6b6182b81a584a2ea9f181015b3a0b5395e1a258b7a971ff31b94a529e2111156644192ab4dd25f912989dc9058a3d823debd4cf2a9a1ae427cdb34385379b81c08b2399f097ad6700a2d0ef86409673155df71bce3ff3df9f4425550a475b4cc469ca26189e7d7c34d11c470f1d5329cfb5aae7126b957b4c5362a253827252a81326074a44c75364ef3c1ca74a9e63d62b1cbd17ff2e41c7c6fe5bd7d260875832e340310b701806139b3f40af130eec79619816c916050f963eb15bd6ffe64ce019e54867ac4bdda23390bb580e4c16e669c7b2767f62466dcda23350c539961e47b1c38a77f28ca0186c83be148f0f6900916c1755b87081863c3a3b1790c08d41ca4fece18553bd59897c03a0d34db9251821fb6fee5bee2a0ee3d72979fa5a609d6f761a10b28e303d5760b275a13eec109dee3d1645df1fe88df484a8523e1666a4d10c7facb8d263e464968b233be5314139e09821d43ffa5d073ffc9fbc029a7ffd6f1e30fe0a9c42c273ba4c4e58c58a2f1b8e35c2e24ffb7580a02a3d8ae88d03779d2558bfb6fc0a3fcdeb8ae392d6f2867746eb38179f56b522e23115837d829a6ef133207b41a5840a1d66890c816c726bd520dce61dd5bc21620919050efaa1da03bb026e1aa78c91e76f123b1e7b93cff9c3d3cf395d42d147d07e81d67b9c67b251e0b35e84365f184cb5bcbcd308edbb566caf0ca46ad02070bafdd9e4ce507e7bd707a7935ccd91a066adc9277d4c8637f81886e6ca83d49f00e06d7144102f1bcdb81277d538fd12b6b49ef31156a5f46c0696658b5fcb56ca7e7652a4a1e86780d51d50118e869265bc939a2b78c953c87b2e9768ca2a34a0e67e089df86daac80b1ae05e5c3c692e812810262d5f2613c7a9b74756229b24e2f62c1aebd28ad63e2cc74ec997de76f9da8c4c59879a017d296c7bd395a9b528bcda66375d3fc0f781217fcd04b22ad90b7b2393b8bcf830999898c4524912e8c0081184d2331beef277ead69b88bb8e2927dcc372fc1891728ca3fc94acf1e3e9aa5b8e68540a17777703828d51ea11cdedc6866142225450a2de6316fa1b49ea0b303270466ae83bba491028b53c596c9f8e2d06baed8afc3e953f32274e5e68fba01c007b8a4fbffdd404d6a5995319d3e74c2ff98fe9853f107be177d53242c6df2ddd6c4df5eed255c019a0e16d6162d64cbc96048b59ed071295c5e25d033538025329081ec2e3c05e949f9325d8fcfa5550b09259996422b1a53f01e23e4a7c2d515104245459b759fcf28112222f1c0ba6d472d54208f22d2ea8f2e8b051b631fc44b8817a3b26031d1866cae2a04cb919cc235e0dbc5c26808a8462b583bce366d007ffdf8520495f16e9c42620e4b30e108aa4a8de7aebc2e84a84b9f1c89dc19002acb0708b1d4736b2b71421eeb72f8310a21a0d679b4b07fb385a4f8d1a7338f3d1d4e8dc0a0e0b8ef14e463ccb26dbd70542f78d1a059378717211ecfbf341eaaa8e421185c38912aac6df5c175ceea5c34b1421220d9426da0c094383bab999d25db2190593954b65043672c1bce83edce4e2ce90994b2610ddc101e17c6d8ac1ab00b68e578829c4c0f29cd66f393d004b1ddb1c04a9500370186cf16cbd738582701b87e54ea655ce8d93a8199709e6e28d804dc549a25525dbb2f557e6ee173c58deb73b3be9680fb440ab3a27e8e9b8b94b203494072b6b11de5475cf3299e516869804eb2d71f3082bcc790fbfdf3261b778a3e89830b4f8e7bef452f0fbdff303cba291fb929617c83f4bd895e45a637a1973e6777932b3f5184f42938d26635c57383ada8e95da42d90953a2aeb272d51c75bc01560498414a36e69a9dac3e6166d0758fe1a0167ed44a0a5d8862c4823351105d0ed16750fd79af9ea120b9aff60a187bc679d7976f196cb9c31c94795c8a104d72ab5644d43429ab6eae573a300e6864614dade20b1e0a0cb3ef7c62ae7480ed77936de8b8835b760531c5e10f93469cf350ff99d5df7d8224e17e46c533ebcc50008a19d5e2788f9350da92769f9df3972e86fe2513bf691e9f3c93a34c4ce133124b0816c74b3ed4d467a6cf6282f992e096c85f69415fd56ebc87c4afddff87f8a2b5ced6930eecf98332f559ec1a488609271f22bad2492eff66c76914c976900f6a98741a76c506ece28a8ad9d604cb69e5b9d6db3c215887e5642fa379da3a4b22a8aef3d0e024c61109bb8e26203352d597ca95aeae56b8c32a423185234f31ea78811b1c0293dfe4193278fc1816523a0ecc2ab1967cc7aedf4e4932ed73089f49ee008145679c94549f6014b98630ef3384a8acaf5ddf8b5524c4ff0b7868263078d74d6661224cc1cbe2fd934b274180be48cc3502e5a19c48fb478aa2bcc71d93e6a71d3cead8f62a988d24a4512a2283d46ec0d5821bc6851f4a76218055d64e9b709f96fa099d2ee6a542ef7b3635ee8664101b2db9e7646af72c20a4e950ed39590f835be838ef07e204409041a48b46f093d0f375681dc9199856d2cca49096ebfed51f01012ce1ab4c8c81d40a0269ec607016ffa7735b7faa0bd3d7c1e13af5383f81485e8ab60f1b77bf23534930ddd110183d31121f0ae35aecd7c8aa74decf3ac5c37942c4d1fdd3edfd44e34b6393b6eea151637641405543a0e3277fbe73a69230db7cf58c9e2ae8b7b260bc7982d851eec9e85bbc70b662ca51a5d3266461e64d341523868564d1ce540a6c562d4f68923b51a9f883c7fbc5a5db5bec869fedacbac904a6b5b6d00d86488c396c2d9a0d671afb240edbd018e2cf9c927022a2a128fb558fb1799025a0a63aa7364b3acd5703d830b466c1a9f38565216f7c08735e5140f4eb8aae59d2f8dc82815845889ee5b2426e3d6589caeba356539727ed93de37ce627b40b4fcdaf0fc3b443029a4d1d7ee515422473530cebf3aa8f13f1ce135d189b072654112b32cd847165c9823e6cb2d3f2d1b7a3d4daea4c8dc9f25c1368e6a5eea67940f1cf19c8d3d8c10b5460be153cb36934dcb3381f71cbef4db7e150c58fbfd82283a7bdd41cc2b01708b3aae2004fe105017edeed6608f44c158c1bc8d74f506108c1e8a3875600506516558173d76ecdb1a49a758c0dec6737ece212670252f1a9fa7af918a2cd13a56bedfd7e1fd09797000d7b18a05e809a4483c84d1b12d7948b289831c1cca199682cd31c2ab146623fb7260a3d0010fbe3b6a16cea51f6f944045cd623f88a2d31e5f456574ccdc10b1f93d3c06ed4be9bc5fdbace48057f4d52d2c5e29e2b4456a18555988c1835d4536cdadadcfe2b3759caa98ba3f21a5ea3c360a9f9ef5d14cde1b941405ed1c9a4744058bec22a54290ed8f4a0597a8ba1ee33c6d298b5ec0dbc97d6010d8b7abb8ef9fc5c840974924347dcf122146c6de92b89bd8972633098088f44ba09f8fa3766ddb3aad651850bda3bb43849580a3abcb1b3ad08231e3ddb0a326d26735027e9cee7e7a494805a3f0d910a51d6d4c0c4ac4abbbce700035c9108ececd7d50d5e68029e4d341452fbcc6fd5b508157d495a85995eeae4a9d855530f49fb240fd2a5c6a2d20ab0f392fa5045aa0a3ada59e102295456c2133a1e965a6f42ec1b6b6113187beb8141560685e32a4a14721521aa0bdbc41388f472133752a0fc3eed64efa45d0f826ced5051811222d8aba2cbe2ece1310803eec9c0113e8082e2b6745770f625f250bd32cf78f0dbb2e361792786cde3387975e2834c9ffe6858464c73e4863f720a4df662c64e942898b4b7d2dc5bd0c725bc1872d2909541ef068b5be72bfd31d1686db9e72579fc51d9c11136e433aefcfa8c171d68379473cb11273ef2c9a54ed91cdc9e18670e0674c65200a8fd23f1701d5255318bd35b986e5eb341e8f054688b0af3b995682acdec5c2d6e1aad440013f0522f0a536f35176cd4ce4380f8727f1d4e53c2ada5bcbcf19584221cdcac776fd37203f8ebf27e889fe4d00202c67790f0837f1b04e9e25dbfd759f3ac0fd6dd53f876e31bf98507168f2d80463bd8dcaf112468ee3e940def6914353654a508cf5c2ed726e13ad43a5c0ea758529bdc485f688179fb3ac3c7843d3a390e7f634f7387f70c66911356a1a139ef466bd3ad5ea0d671fa79c44929b67981b10fa8221c2fd6f3ddcf60bc150812816db89f216c0f90ddd19f514634e4363d99e367409077dc9113414eadeb25727a5ce54e15eaef1ab7dd7acceb5931f38c8880d13fc167ede486121f1f72c6f8a800906dc62b0f90687fb50de121b5ade2c565e7e7641062273ee8deba999d68ada7c6fca580419660fb8ff5351f8ca3663f44cc5c4012dbea565ce8bef3c01598eeba0ff80342a9d5f767bf827cb55de2f131ecd74d39a6ef8680125aa97d2aa554140bddfd03c4dacdccc32a7f5dd38c98b29b2200c79e59b9b2705ab56023f853a0c47a856c53311bb9606688e81edbadd0ab96db91201634d6335f796d4b3b794c9f9e7b48522e27dac02cb2b62f8119dd42410b8d075e879f9309927d9ac4d18e273047ae82175586b48607af41aadeab3391b6f41ddca2b05073a622c324be4d1755a8de68849dbec322e1643d5cf71092a974d312c18ffaefea150d31a12f23921bde12325998999cc8703a58147fb33d4dc58921277ddfc509a359feb770a431aa3406629a22cbf10bdc2ff049f06a505a73c884306cb0c793147e2be386060235c001b4cdd3e30355170802857643494be1ef061f2193fa9db8b02f58e414003aa724d5f37f469ad8f8e04ba63c6008e0605cd464309a00e920052ed9d6f496dc40223d30551a99350d29a43f3571bbdb817b73374fe78f3b7a4ced8bc2413ee42d5497125f4e5803e71c59e582a31628c11c2bdd0673364e2fa6f7d566a997a217a4dceaba9c8bbe3e6aa2ad6d5633534c0b0a404ebfe808a4a95bf861c121088483cd95fd08026bb8490b94463da05e517123f3bc094620e465ce25d60e6c7d2f1a537c5f8a618ea08aa687ba1ce7ba47334505019135922b5e264ce6d6a3fbdd91d6913bcdf4a18d3ab06d6e1f55e9379e2fa0c41c384b8a847fdec5a94ce0c58fca4a9c136c891ee1a642371c096ddfd882420fa0284fcc7b6b220f7c60ad6f4f5dee1b13c765a491419709f22aa0f7ab1a4421402979b4d82f4f6624c2c41f102434cce044220e368ac95a7712e1aadab0c2f170a61e6aca860fa144fc0a72e61f3f90ba703b5697e3d84f90d5801207b691427571427fa9928a7f211a889de3b5242f7146a5495f1ff4fe4f178eae75523299a466fac6b54f0715da99466d8fee950b5e19ffe819fe25131f2059f6d459ad9f4dfe3f478f7fe2c05a9504cdeb212de9793b45cb3d28dcb1e95269666029c86763ca5cc6f51ab9e35fb805f2a56d8f849662c2d027419a57cd79708d4c4a918934165f0bd07d450c39a24c95436640d589aa4f2c604036f4418ca104fb8b5b4d5a0d43217c6adf106e0ce8261dd3d663e3efde98abc93808f9fde7a8bbb1c257649cfa27bee6ae45b386ad45d44fdd5757ae29b600d2d42ddf3d269b747565fc7aadb5b7341e73d8a847af88f783849de7b5f0e846d15dd7a1b2d434abfd43c2a7b9d876f68a95238386d3eee077c4ff774094f0f2b6fed3613461615afe853a5cabe3f5432b0e07b9aac361e3ddae7c9a702e4d62cefe2a8418678aa2a2a86b0fa0adb8925b16b0686385538163cad22beef50dc562a2423a08a91f3805e12eb30ae42eb7900be85500aba0abd8834765e60778cf7d4750aa914d9094c647b8fb29790568a397233a45e77d7525b93b3053069ea29225e5caef88ef36506184646b4485bdcd2650167b5687d7e6600ec2154f5f3ef7c91e7a8f5352167fbef48e17c23947a884111ac9b9441553762341af6626632248c756370898e867020ab6b011cacb55ba6f4e06db9f015709dd42783eb748767dacd708f4ed0d8eec8473266b73ef2a38ecca2b43f922debd0f388237081009ac945cc4e1c2ec5dc5ce9f2679d4e5a4afdd0cb640fcf537b867db36dce1c1a7e40c0697a7da05c3fd2147c269a517e1efeb3b62216c2581875aafae7ec57652c251b5846507e1aff69c3ddcff58040cd62a09014d9ed0b9dc9831a2905f34b12fd19f1b4d890cf48672b21628f3537e0a4da8f9aff532c3a6dc76030dcb902070c361e0e17855028a5263c7a3edc749404213c888325e60e0199445649552416a74013c70beb6cf1c8d060bf84efbd0321fbdca1702980df7496923b49f8bb21866ee8a93462380ab11239c2e6ce5b0b46c2f0855fb5a8502f6f62b6b160814bc9ff8f749a933ce69d84ef1ea4411d3bee3ce26093853844dde374b260cc86bc6e5c7f2f5818a696c5bd167b012cfec26e7be76c425136eb67d59b28431537f04dc4e81da5dbb42618b8549ed06ec5479d49c03fdc0427657e3f7f6c54d1da5ee40bbaf7a463301ad8f8094d7c9a1bcb385b46f86ebc28455533dd75786a455fd6f09028bdb21df3fc102d2132b204a2b4211295ca3d7500870ccf05981ccbc9aaf31dd62bbb8f4e788b4aaf9c45794da568dc5a5d9779fbced6b05fd8756c6149a1267907b08346e138dc70c9320f96cf9c69a57e849f05ec6e92529f3a93daf7072ec95c9c961c493c07d7cf258650f7ed8750b44da3bb2893f79cd638755e1284ab25c17de4de55d75f868358793f6183016001d0b7a997926d2f3056a97fb003ec44977a1fe9cbeff3a58c2a1f409316a2e6f8f31ba9319454832608282d29aa16e5b95f920e93193f9a11fac5cdfd85bf2cde58e35c43dfb635bd14fa806906d31f784b0dcc78bd3c5845b859c079ee8fd2b26f0cd335af6b862f1da90443c2f688f7390bd1153fffdc9b1ac93eede0b93fd0130fcff725c124c7a1fa58a5eba9623d2794afed51ab85f1be7dacb608c75eb29467d929faafb118604c78579384878fb9b26b0b5c7d262cc1cb378406067c06fd96d7006b8fa41f3fe52ba8a2911d160ed0ecc42b11e4d72cbdd101798c266b6087f6765430f31286a46fd645efecf98443b23e963c78ca09b79ca6e8528cc80d1aaa4c424820fd3cb5270ff4a64bed59dfa2c005ce7f66d9a232c2b8881e4d2d62e50f5b9f6303412117cd8da98ac763d8ad5db96c357c3b501a611f1e19b0ce30faeef86f7bd80005c43fb82a65b522ce576fc38e534dcb1dd9f6211c300e982e015bdd8863c233125b51b950614532318694df49ef8c8ed85d73370b30497f9e4f5b4e9a7a89224e213c2e31f8eef047332ec6a60ead87fb4222c9312ee3b93a4d064d45b77376f770d26aa5f2145ddfad953a4cd8e185c287028824c79a9dbeff8f4b82c4e24ce52edb0c9395dab8a42fd385d7f78fd8a167c20cc1f856045147658707e7c0699b9452726770ba076a1b203b64056abf83fcfc572713bf2c190af23b661959ed2cc2ab6b8fcc9229e5a99b354a5f72053f1f98025983a3ed8a2d526f8c0afc3008291845b557964f0e0d358c7517471581cb0e7b2882691274ea38e19bd0a8f34d1d719b3719ed86ec3b6d04a285aec0ebd420813adca866b3e7514534d363c2238a95a3b90228e10a20453a8ff6efa0ad9f2a7d6b93b0ac0a351f751ac51d8eb6b5c5febb85d7cfe3ae0051ea69712e3c6523408cf88e4479a2a73e91e1f4ccacb0053c75217e4b69d3e8f164203880c5a1942caa600925465fdc0d764c04011b32283176c45044c5edafa74a0ab0f3c794459244dd7ddabc9fcae38b59870875b66c3bc2afcf6e6332380d35ab4c2048f83565b06c78dd4172cdfa0e592066f2c7a46f3f2d98e14ebf6d4361602b56d11d3c9190f8a213d03b357b9d5afa1811975a424041b85b6bd2d216de8659570408b9739d1968d8613b0095afa13b99061ee2a753f6e9c39a407accb29a6a37dc0af5210ff719da7d0b63af69c68669beb2f1c989c37cc3c9e3e274136504e2ccb10deab7f4151a349856aa32353906cb40a062b50a70596f6a0e1df05e554eb6d4ea5d4f2d7b029ac945364abde6d7899bb5bf6bb43e24abb643c8a6b57846dbf76571026518c7268863893e905513db713fb11e7e732ac4116aea193189924b6dd401d8e6e318f795415d6ae78828eff0dee937861d54cb747315c917eea8a623fea14d969dc8cb600826c350495eb945b346555cb71b671ac25b90f0dd840276c6ee3fe793883799414eeff36bbef04128b1af07582209f996ef6006f03fbcec32b15ed8f81a97ef5ef75d8d8528bae00414ffd8cfda3f632d63ec4ea76ccb4afdb4164d12301affb1b7b369f3adda11d7f951408210434885c4659f20fc50690dadf619424cb1274f5abc6b1f374c6b54e0d06492645aab59704b6ab97535bd282a320622ebbc3c1df2d9c185ed9e0814450a53bddb1101751b5e50e0620d6da3db3578fe63e35623df745f5c392cdf2cc51a75f26841632d8d3d663e48b0054fdd282503b2154728fa7ab29a2dd6072ca981a9bcd57643f64e89f78a61c08b1b798f18dce966ceb302b03ae05f00aa95256b68bfd8b6995e5758b85335c68a9dc4be945979c4c53a5c8ec86547b10a3bf632e2583b0fff165c139e2e84a028a2b4b6df6bd70ba7503c861cc616cacc784220008e51810691f4e869d77f083681a0165021b53c009743eef8266817caa4db06c070714030304073304176575b15f9ea6b3a093322217b35b4af28e8fd4082f884b94eb53273e17904db33a51f5def794023218962128ee226c0c4bc731caeb6218f7f65e032c755190641d0da6cce375aade6e663ca176a6ef20fd762d66b09468af0fa36a22127446f1922e21388d4367d861ea2be2e5055f37a34638571630202e1f2652a40f1b54cc9943a1a18fb2971cfbbe5a72013e916044bcb751abf4e9da71d31b3265a3506564c1bbbad44e856db1762543cb583c7096cd76b90d067888f143e1aa629f22b48044ea24ca9946b22b83d187e925f12d051a9b74a414e2ac39a4367227d500ef60ef064c0846b3a34e754c67b122000bcb91fabb9add6a8797e6873f9c2d724046c835a28daa8b49223e24639b392d6848599cc5d33fa08072059a3de75de31f3630d93c43060230a54aa295a5a1a0336e260155641d2b166505532bf9bc49ccee8c79686b73f25d38de8bbaaaceec5756eb846d5d3748b1ca2fafe434dcd4d145a304b432046f670fed853c8e8eab40232024da5ac034fa6f132c6d01be23313fba047fe55816ec46c63dce11caa24640e3b31044100de51c8c3021126f5bf2f3d0344fafb0039c6cf397a167a83d131feaaa8f17a2a1aa828f82e8161ee41da5e50ba7b90919679993eaa82279d91b0632ec36677a2a1ae206dd4fc8998477fecd4f01f28f33efabfc58a86201ea0586100f83855b7cadf43100ced27c34e43278d767476cf25d9be8d0a66b3fa472e7c205a99063b2e4effddcd2088748409259bcb385d27873605afc19e9dfcce3759eed132ff35f1b248518b69dc4f804bcf8c8bfd24ddd764900097c54f19893881e9938015193df37ef7eee35fd18b02db8355e9d6f051186168aa64e32deabebc22826a812027352ae04e81044f9acac51f9b98a7b111dfd3f6a6c4dcf93184918f03807de73c37a604f932f9a673253a3c6f109e6fe7949d5941bc9312f1cd03787aaf1ef8899ef7410a0169ea3c04e2d943428cf218f06e2fc3debbfe9d0979ed36460497296241246526b8afb3d9caf2a3636bf5330722a60c3574fbed903899f35e14b326747beb728e2f8eca4d397d418600e0e9b90cac4b187f78c66092603f2f29bf05846103da163b601b03afdf1888bf5c97e59749dbe14aaf20f58338688192171f951a8c0738f29f0f4557ec6c74650981673596e4fec38f982014ee08a9e1fdc75331e9b239f51600ea240cff82f8fde5ce48b83dae65be1fef39a96cbd14fed44f70ee5d169186bbb7254632463f14bb5d76609c27207a690d63b5880d6835718978a49ea7350fe3e3c80763e29701b6d5051b4d89da108ed45bf86549fe53623d2cf829f689d351c7e40beb911ecf06af09ffd1e17364c89fa05bfdc019797a64616c8df271f1d0a2bac8467af1b2cca06ebb911e46adccff2f56e795f53529050edb600859d7c10e3a34f6053f21725df61ca4845a4a971289e0cc599a6900ba311a0ff30cb202d0a355dfc87a6c3729d0c6aed9b07fac0a4209d9c0d7a94102e5a5b0f3c3d5f06a81877284aec030fbbf0560a9e11ecb74a4d95eebc899842b8da6ebaae7cc5d94e7f5e32f18a93044268682f03142de3b918430082a4bc2305d13ca387dcfd34f1a0eb74bc4cd380cd7db70c90e462c7add605e8b39643bbe288b65e0326afc82eafdda2fffe46339bcaab2bc4fc8b80971ac25809a600a72325fa9f2a61d4654a86150f6cb1475cc2275bf43ffa81b887f27f38022faff32bdc9298613e5e78fd3f25d128555ccbdfca7b6ad61047a66f6c93d94fdaeabb9df3453ebb35d8f0a7a99f3dcba970d4b96d683ceb7340c1be3fe7e4e150049cbad654883d9d4d22550462a35216e9b0d28dc000934b9f1ccd8eeb2e67e01759e4a5dd3f12be6d316aa8d7278d49fa19a984b9003f0b42bbe4a6471c630a461f55db964feed1908c89575510a95b7c8578a005812145c561c741e5d52f4dce4b5ac939911c35e755adf6fbc811c3c26ec8816c3aa7edfabb70c5282f74aaa5b4cbb2313ac8c9a9ba2eff000f1db7139af0d3bcd19495b405f656e9ab6a2eace62657fb132f767d8b33547ed41ac390011e9e5956c99017f10a7f3ff7932edb520ad95f5bbbc50285bb4fb740fb6cbe0487d7cd2a7f3b8925ffd56a1259845fe9db620257276f0c10ad9d29f49f7e67daa58909d0a09fc529affacd1c0e70f03c9b503a87c09b92d9c476dc05b322cb8738ad1e6e610e03094db78fba5395616591f511fae7e2d6844d771fca020d131242af708d7594e9e67c19bd5944629d2eb1363ee1ee87d4a3187e7d38d58d73a5ad11950162ddedeecbd5dc79f69e9084319e5a6231d81fdca09bc91a74a71a72252cea4c2e776f7f87cfb6deda43fb7b5671ee79f0e070750c16e7b405a61acc939047ee4794cfe3a0b2f3f9c607507610402cad8fd59b88a83a83d9ab6ee1889b15d09b240ceda5b04a700c955fc21406251d1fd01f8c804bb47b44b6eddd84028b8e0bfb746f20b55573fa7f0ec340a975e4ad378485fe727fe63126c11f6d756927b18d752a8852071b5f8bd7989e627262092e2c6e2935ed5eee77222fa8a5e64c5003103cafd6af12ec523173c08838a9984117d72830534db85d9fd5f2951e058910bc366e8cf9b08d4c6132cad7a004d5606f1da5042fbf6bbd791ed97f56ef81e9ed1403e99e6fc7f30761055a23aa6d341c2b37d7c52da7898f217f27267fbfcd3ea04d557663cf6dac724def660cb4a2fe79fbf1277959fb4f3cecd6ed3d76829e9ecdd23b54a7da82f755ee2e7f4f7677c3b02145cda0a835f7b98016b17700b98b5ac5a084066f115faebe6fc4b812ad10b707f2bd920cbc7595084264a28212978cc6f2e7b93640efd9cc6bf1bd971a7c238697fd1a1e062fdd08f970429e5853c41babb86afea130c363ca1d9802d96c057164b0da40559cabbf23e2e4dcb9258160bcb00d979ae6b7b2eb79e86bb255a607621c2e305b7c4d3a255013f49f278e5258765f31c38ca247bf52f3c0b25a4fa9a2e1034e8cf9ac4ec6604022c14e793f653bb83a0404242e41dd3d3b6475b07358f0512033bbc5dca0ac4df486d16630b2981c02f2526684d9de16696ff0f04a68d66b1c64418a028ca8a2d815034e7e53da6bd6a4d13afcd1f7e4f08b84e26fc1f488f2b3f3d9773225dd5317ddb0392b9b82fd8f890ad55de39f587bc594170cd3dc355c2a3d2629d8ef17ad481b88081da25358a9ee0427f34f2d1734561efb48131da8870613963c67aaf078e25b48dc8e6b43a72e21ab63e8b071d78d5fa90edc16b2967c943f74c256fb8e6acfa15350a48e14f2dc7598e03a781530ea993277fadf2552266b00eca91784e393cf33309e0d398709882a4b9126efc01f21cb14a597744822e0f762ed0838b2164114069ea4e08e680a430306dc8fc1c426f6a9f7838b3e6bd74284305c212f9094c665c1afee2baf481f4e94b42ebfd9be36d8f320b41bc4b7c81e69cefaeba9776d7c51b028ae87602caf4cf6d417cc085ccdc5c29c12563177242a4d1dae8cb2e24db05d3ad49279ab607ca5728410fbf258ae487d621d3940fc012cd3b9948f339e9e9193c8a34bbe7fd85d5a82bccfdccf53840b715618bca9abd097277f208802ad7819ec2553e2be938b9c0df9534c37d270815b85681e292b42faed5f1c0017efedcf47a0c59d12bc6d2ea6491e6a69dcb9c31f3d3e567f77cebc1b57761c60549727b20d8051b23d1ee48e9bea600dc4af9e84fd6d769c64232ea7e20274b9d120f5bf7f0b14d506eeb5aff2c3f4a46a53b2d065ceee746531c4db8e235690c9c65f814da6d54245af8a96d8be62153dfa11e77a750e0733d54e9a69835fb17b806a1cb08a9bdd8b779747eb58adbba087963c0b6a114f7b59525106e07d751eea4de2345cce8de38c26977d6318e93460c6c262d2784fe18e1847bc80d7d8a9f8c5b2e370c09da6aa8fd2c2233e0dd67963eb6770406e9effd71dcd2a5c5c18398754c58d67252f0b9f8418217138215d17d6ec23af174b9dac9facea4b06151996574b5f3253eb198a52f859b29d9570ca2fa12bf7e725c615059f88a3cd45d09d713afcf7fb273e6fe6af92c7c26e8f2a9d9f6847ac2dfd3bb8a012a2da59681b38463ca7e3f0e6a408b1f13a73425456530124e0fe038bbe62f668a341d6d826377ad499868c76a5a2f8bcfdd5d5e4cd9bec684a6d3036b02626d02a5c6aa70af4c4d76425e9eb5e3c01bcfb81342b7e2df02170b3f8251e8fe218005950158fc4604102319a6de43a617b0608100831dbf2c64f5d9cf2d67518023caba4b90f9662067295d295b8806d176d1b2ce7d52d9da8448c3a9aff70f6974e9b7650b0459355ab24da85cc2862127a0800da875f19733c71021f67868379d5ca572d2fc77511c569f1d0405b6430eaf23d849b9a9caa0514a7a5228e7dd174ba7b65fb6bdb53db132c513302b08f87cc39908b6909480e4dd3c6f6a5c72928d8552493319d2568d8fe239c41f49cd1ce0258651659cdcacef856af2f5df24a07cc754a0381e5ece39fcde5a447bf21024cc0462cc63e5c72ae74486bfe61bd4c40d0b1d2c34d3c21810a444416154c19dc2181dc1eb336734b9dbd770d4011e0652b2d2a112930e5e6614e7d33a9ca1bb983649cdad8fc0993fd09b3d7ad9feed3e3d63ef4eba63c76e4c01b18b9820451a323dbeeb4a17e34fffbb8dce58742ffdb160379a4ab0c7506d0162c9e9275d0c102e31989250ece21f9cdffa35b956f5178351fd5524b6516df8b55f07c7c391356c32080471f74d8110ab0604de7c5b00c44c813f785ffcf8302da0ccebb7053ccc37f0c9fdc59f0ed302940200ae732196d4a6ea10ac425b062d73ad6e7945cc23499ab7e11f16ead0709f8eb1ed0e5db1ae1b9268dbb1ecf22dec8025445fbe0f1f0330802148395d89e21981fe6c988893e39cc739fe72f917eb7106c720b496f2727a09db37d889600789f8a8a5517b8d1897cee077646e70248ca357403c7f4ef99bcee9865e1ceb0f695f3ac8e83ab87825dfc8d2b938e2848e3b910f9e8f65611dc01b082f11b071f5713c0e037ff184bad53ab4d388015e703807558dcb3f9347fd0fd6743c0b2f79e1ab8270ac20e37ed73ebcd016ba2ef48d03c997e48c94250af83df609044188d295f06c4e57a315cfba7f2f7183d1d7a93f7569eda0c6bb0cfc715dd382f5786e91798e26be80caa4ad4d5302994726b61d7bd8e3bf88e3d955f9a75f41a97eb83201d25e9a0927054b227d5061b37391db9a13c4bcf9a84c7549ed7508f33a2ab35a527b15c2b875aad38d58d7ea8a811acea1d597d625ef69937ed74d539f4931d005cb888b977e6e1825e96fedc1ffec92a85ddb6456685c0938895581b19efb9b8ac1ee7a0a06baf018325b80573fc110396529b99158edf88084996f8e3577d93d65bcaf84d27adf36519d2579f9ba03a7ae1ed7afed07054f8b9e37926d821f37be8f9c9467df8a008160b44906b50a690855a4898bd1ca0217c5e1262be50b6689450c755b286210cb7c11e3e4c08b1800cc77017793711e71d2644992284e76bf34fe023353e75801473c602078fb03809c5292129c8a5718c68bf8f84699cd7a161f6b106dcd0272a3c5d201229f7ef55afab50dd96dabadf6d3586980b7413a4346455c8f5d1eec02476c4bea1630c1401714e9bb1c64eadba48490d18676c82c8a335e6de072d0ff627b1032529479993613e4e6790cb3f178cf333638f9d6f2d3899345fed1906ab4ce1f8cac252dba0f14ebf7742c6238539c59712ff6e417232ea6c709aa0208f1cee2f1453a12f3ae05927c3d2e144620137c3c2a4e0a695514cd20dd4c8f188ff9e74743ae04e0df788b681b6a1aa9a182762a4ce04a89ab9bd81f782c1c36ee907238545a4eb906dd55e932e666de8e3c7e976244cd4b1bcefc4860f903aca783a6411b54e1df5907db08c17390afb020eef68a2c4561c16df4c87b02f5f4cba6036d4328f8c327e0d7abddcfb1205a48365632ee46f863d783214fba796bc4681061166b96904d23307596073fe01ea65a4fae12c4943685b89eec22099f048cef136737176182367c301279d2b1842062f9e21521a33048c1d76b177ccdbf8047d17421aa13d2194db20dfb0ce3a53dc6a2b9015c299a2f8da96b66c3bef9a2fc4dd25f174899ec1142d950c318a08e3502c3b2b6dc0df62ad1c423eb6de0928d95c84b13be13ad521fa8c6218d3e8871636cb5ab4d555af4858ce3648c044919555165edba69a7417288117b35c5b3d09289afc05b6e734a03d4147b5bd04c2422e629f27e033b38145c9de5131fc5f8d31286e78144194ba0542d3b06040e23a15d5708523783e7485a59b5295e809c0ec2cff9952a1a3407778d39306e28ffca029acc7b7b8cbb620e4b04ca3a9476c81370798347559697e69c171d3c9746e0e2ec88c2307977f856f83141127ee6fe387730c7d3807dcbb2ae4f32c29e81d08f0fda3860a00f2a566a6d2bf2ce6f587f1141aafe8377805853b0972463a9de19fe11269b0ac2754aa58055d4db0f4b215dffb1d7f7a4efa2569367a0b62218221c8c1e86c9322b69c426ca6bf481e1774510a7dddfa04dba791557fab8535da9bba33f1bbc370e613a57b5f87c63bc71045c7d471a94a3928e04b3b0b2c396b63fd0cc52faa9d7cf0d167d265d6a4e1955a0e68ae7b555aaae683eb6e3c89d555340cad34026d2e4b1f749e269fffa7f4338e41f15f626f2de3c298ef71bc0482a9fc40c2c45f6062114f48025d9f8bd48d2bc9904a95e6103cc06f8190210fd7fd0fd1f533c497aa93c0d118c72ec7f2e75fae257a4e53265f1a67fa80f97a920cb120a99f3c775d754c428063baf18ca55da5048eb00526253fda5b8ae69df24ffd399def19a398c842f043cfa48a180f58c8acb20619ec132d65a6275e1a0a32f36f866c0f74b81ba5bd70085e04fc8b16c1768ec5c391fc3f0cd1d67308d7d1d3470805696b9330a09d4be8d2e9c3c7309b93b0cbaf9a2b22631ec0aa19661eb98cd646fc10d3d0a932db1ee672290cece5f01357d1bc53eb22247ac6893e0ee28d49b22f5dd94af7711bffff505525cb8d093fda6bfaaef8edd2a4684d19968e6df1776b902fe1df1913404981eb94faa8d4dec1a0176a67b047a5e0f287381467d9180f138851bc027637b81082004e177b9cf87c42a7ca0ec01eb258a0249c0092a108b583e944b76f765604df80cb838ecf67f509dcfc608f3e05903e5cb57fa0406a0944b4241e4a4425bd912543715a2aaf587c07d5ac2e0d86a939340d0ce2dba802eeecbfa16159c24c83508c2b7de6b5e014f57a006a7273117acacbaf26396ad066d43e88c130671799f923104e8988c52c4574ecce38b9f15a5cfd727042b332a01546e26d62e651b41d8775741f52be3b87ed00816f325f121caabca393e174b0704da54bfa10f69971ab181cd34da7b54129cfe0f7a46c86cb04e5f37dd137c029eeab327ff376db14ace0a8c1b02c0b8e2232ff60f3dcc9649d59240ba4f7c0115f632dc87bdb8d61f59138228846fc758600c4765942414528b40771ec3b5590285153c0f325007544f499859291ee18d0b5996aaa984cb1adf2fda27d43342705b145a5e220bca47fecf987d1842375e98e42e6aa29b7040f369074e0f918689d30411ddd220be5689569088afa96f9238643b8ffb1f2a2b821d65344d063c1cc5498f7e996dfca0319df2e9b0a6c4aa21a4f275d951ac40799c8bfb647f448fada102bbd8bb1bfec4e3f1685224bbfd5eeb0309ef08a27bc91dcdc1c3a91929e8e2bcf238e9567311f0db3f34cc67be997fd639f5c4526b5665f80799a798509b37afcc3fbc1f99b9f921d446fc34840ec4e97256ddc5ea78cb339c3dc75eb05075d4112cb9860712186ecc5625a0a7d117eb6ed33396dd8d9e6df087b77bddcaef0971f9a07613e7deb4b54c0d24e7deef9c49fe9160920ab56211f61e251ca4f28f22ab3ef93d5ba829552ffde6b24fc3bba8e24273d636332663929397946e54fcb4eca41d511f708a25c1d7a67f9fa12efbb458c566f5d49176d38e4eb15e41241d5dee7e645de98ae19d001fecd6ad1e93490675c12452dabd3dc06e15939ac641bd4454e9c9dde4be38e4cc3efb29ddb670b9f20737636726ab67bf5ebc3452fd27d12dfc98eeeb2ddd8a3a51aacc8e1423f8314e521468ad006da256f430356ae6eadfedeb6c0c3f0e0b4dd6d1091ba1a38399b88474bb7de9d272bc42772f66fb7cfd0779bef789f1874756bde06253880a29c5afb0b359b40ff6c02ce7e8110ccb4dfa3cf44ac662ee26334d2a0781eee729b69db5c733434882eec9815d2c8ca252a103a36bb6caa1ceed78618bc6b45fca091067a80e068c628b2d4f615d420f12960d82902884aec9fa735e06176f1325b76a67496c04d2f47b2cc5502f14b689282aa0cf406cac309823ba17ccd9ff09ee223e143494d32b7c464a83ae8444fbfb92b31da20f0d246f593e81f831cad3a723743a51e17e9744cd442873a80d5335b4f7bbf3e0fe9f5423205b3938c19d0a08a343d255c239c01df59fba7f32a7f8596ac9664657d84fa2bd2744a19d2301dab6d8079bf5d9faec1e956aacf698af226fd1c2f018f2df22be10031cbd97bfa276a4977bf88f6295622b777cce64718c7ccc2e243680093e1a1fc23abfe412c7d9b0dfacae1c167fceda077ac5f2add68c3aaccca1c16761f719647ea730840bdf6aaef9ff1a3b611587ee1ae655fa3191f9194a415799670d69be3fbaa4ac0879145f94fb46a91bc7ee0e121b2bdf35e9fe04fa86a6ef8d7065bc327104a76d9d87187b8d4c985b6e2ea6a0b05ea1fde74376b13bae7dee2c9eb15d6f3ac5ea482ece2f6fa4385475720116b75ef2ebd60ac572b1554645bdcaa6ea3a11a97d1fca8011063b1136109d27aa3a3893c9701957f3bc85dcafcd694098ff2dd2218adbde2e11c8eb8ef850b6d98870de480739f9e60a59c1bbd53f8eb2f13d28436fd5b05fad05a0569ce6c80a03d9a332d626fd21095d24ce3900b89a8c318c9962e876291c0cf3ebf24d642fd3032fb0f28ae434d3512cae046569a90382aab6d78986bf26331d76db2e312ca2177558378fbb72dd6bd9e68cb9bcd30a46a738893f390ad8869500a6785d3d97f10ab478b0ae1521d058265f4110dc66e053e0f6365b8a161c9ba998f8c6c3e0e022795da79cc9a07182a3168b5c2c2242e5e3cee41bf2bcf1eeee2c43b53e1b415d29429158c9fc1d6e6321807208ada164fa28277494af7464234c6d75f079ce1c1add846f57904ccda5d782d971b4e47380771c2231ef8bfe81287c911ed60ef784476318e045260708f177ce1f8f5d114a4d060ee6841c5804cff0a0a412981468146aa49e28081bfc8c86f093a7fa2aa356fc843bcb97416412e10f787ab3715230d5991f0c592a81d9343a18f1697812a7be56daf9a5fe7e04cee01567b69c1d6ad8197cdd19069eb9f959c223c9fc948ad1fe073ac2ec96d5b3108b28d556e1effe812073d572a47121ada15159369f817bdaaa2f2a6be0ff866f28b1d61a162a65a1f32e2f32429470e72d2c213e477ec579e1bb1928ad148375983b9f934e0db359eb9642cb864f211442b4e24546d9e67496c2e32580a3af4503f10d421e841a4c00f1dda552dde00f8ef50486bb5094475b73df2efee6645cf8d88127121cf5669b17820fff65a6c132f52ed246d4b5554a72a3531dfe22a7b5894f3df402a3a6d018e5a08411b435467a5e8c065362e44cd985da587c9cc7404cd823e079cd6389a5f1458e6219c86a91f658e152da06d0ce2361b40c1c181d69d4e9db01531a0957210315ce4e157a746f24afb298b232835f7d36108278672a5741b305dd05201c86d4881ebaec1e98fca97d844f69109d004f97c03571c38b545a6587a1efc4095e80244ff9ea299759a33153f0a24b985d93dcc829d21e625cd4ad213e0023b3b52b9e374212d30c738374addba2d3b17a8e41d42107550cf9638e48709a4e9e70545c63342ec6e336646cfe7cb13512db7675a5aeb4b8b63d15724564926f20be06df3fc57594918d9dd2870b15a42cbd76aa03928e4a53d630f0ea2308023172c21c79aa684a2e163f224839fa05b210183c201856964ea6705c40331e27c6e33b647f06929b6de5c8eceb38b624310b471120189fb4ac8e6564846c2a0fd48a907c65b4538973027c529a8d19efe2f043ce7181e9b978a63af97ca5c0f42fab868876a862b29f4a14efcd29a2f0250a329ec3dd00c63d4916d3591895e816f18e56d861bb7536758c5564630873ade367421508950d01c79c971989c0f3ffdfe2f7b11963c867372c123541506fe2da525ce873af7ab624f65837815b56a798eac94c9568ad9509867a2253354a63b58b05c55849158bcc953d09a22ccebf9c7c74d43f672a03181ea862ba41dad460184654ac2ddcb7467e52696d50467bc5498769e2dbe7206861212a7148ed6910bf44ee06f615e4893a129d6925ecb021f7b5eee403322e802136447faf4875c609ea90fbede9b723f30d9b0cd4f51dd40b67105d67556cbfeb38bd859c01d8d9f3921d0bb8661bf2570cd1e283dd77012eca00e8c106701fe16a7ad047d2bdf8e4256807138ea34ad5d34531c3cd938a804300303f00dfbe4312bb52021e066d9f4329970a7f7099614974da2327e464d4157ff185c34ad349958e0b28e6c784581ca7cccfa9139e8c754aad53ce789510aa6f35cc582852aff4fcd3e4b512a7bfb5e93ff1c267524a3750fdfbbbd52c83d604348cada700ccd83b3fa4c3bf2eddb0e54739aa5bea2fceac4dd4c58243719e5d694484928a9d030ffb9bccf3a4f011730f8e26428ab806b83b8a67e6591521541410f2d6430aa904b5d1825a98e3ff69f14121a80519cd857ad762b0df0ae9d39f7702cedf416ea034fc2a352ad0661a3c85e1f73c9470c611f56b9441a899c57086ed9bfa295bb207865be084d96a24f6c383b9badfd627050d21f20062c752d8545d4aae67da3a6a68ff8bc25209fc38ce00f6b7401f221c0e827d219ea85e35c09189131a36aef4dd0f4f3af59a8fe1914dfbdc3a26c7c9fe7d3dd8ca8164cb612ce9ca9f37f0071388626b75e0437c1394d1816d5580d381b62912d49ac9552b38efb2ae325f67c5a38fd960046cbaf7e786d54c2e781b7410c35872fd801df31230b0ca736650d0a9a078d3e9241f799c5a0668a39f7246845602924491bfe621254fb6089f663caf99c1fc71e2c5da29a6d1fe0137610c83ddabcaae45789f4e38ade0f0768a8d079da0bc41907069883771d94e83f1e6233255a53557208c5b4b99de88c551baff55fc273937fb10dda1f96e0c5c1b99411bc9226d1e73eacb494a2b1845886c2c6ce67b8a82abe5b8fd0c803e5d6bea79086fd00b10a2a38b140d386e78c2949b7e9b517478b012f9497bb2e45e75b2025eb26432c5045f9a7227fcdf887377589f81024d6747c2d459222684273db920e0be935a1d6b1562c1c5813a3ab0d079f639b514659b0eecfd731c5c3513d1cfbbd57aa6a482acb191cad1868e90f5384b5137ce1515f9618a66baed6973dbf9587caaf4bd9981e29382ec5d5634e904608207102a6bd26af02706c2f02f8ce4e945af3b3bc5c8a972a940501372caad1b6563092c16b0086ff0f38a5d24a1795c3930aa2c8d81626c8b22629d0453e2c37f8eb612f88d3a2269f14bff3df627629032e5925b4b274d42442af0360b93d3486203152599ec11788b84f973976c139f2b361ae6ef7068e86f9484debdcf5b369a02e138b7bc2eacf408824594ecc3599e1b13e5e1f6632c5438ab74e881e499cf1ad60e7d9df14ace3b49d501b8fd6fc23329ce26bd388b85a0964088dbbf5180826bfd96c0bdcaedfe26abce19dc3e60892e274659a5680980014b39675ee715b40dc45722a3b2673be53b3a21141b291e55548e7696b5a8ea458f3d42276c03a766889b4c6924615cab5d81662d4b137ad4adb5951144aee51356b3ac9aa855ae72c01b88aa038d10128ca41a42842d05d0a8e57d9a00f05f7cc6335a374f0d30aa2387cf49fc01d60f35f786b8224b7938c00e37d14196a2c7446e343afa915ed1143381371b797ae134a4c74c636f52639ab3edb45be6620a2a9427ee4ca057be7650c9ab04131fe2f2da3668466a6e10bc4c43805d77bdde0d4c2397dc46e2264380c01b097f98e0defe5a74ad9cfdb3f4ce67a4c11e4ecf47a2f631d486891a59e741301a41a97ba929e2813a34c6614f85ec803022e2bbf10e3306f8ce551ababe5505ee65387c19aebf2e737d92bbd2d9426430badb7048a6329c099e846e68dbacc2ddc9be615798ca09191b02265182ebc2f2999fd42ce803a1fc7e6fb70641281785d70e4ef88d34ccdda5c29dab15784084bf92d2053b90cb001c351cf8969db219ba42528653623381b81a644924a62f13f0d8441008330e6d8da43679a3f1ec4b6085c334c5742831236fc9a0982cb2c11d08b1d391d82b8bb58cc664a877d15f49902e92d0f8eb216c9e94975049ef4aee336439a48c2eca7f67f8485bb06126ed37c48c92be3b4642fe17df94d244bc0d2bba9d6737f581d85094586d9ed192ab4ab412ec444c348e272fef8f75274370bf680d40bb2aa1a363db5e951469cfb71efd4ef13ee1588642c40dc1102846eb770edb4243b373188fe47af3214f004df5c072a970e5d47066e85996f0b58a3bc82772a28014359ed98cdc0a690734c1512e07c3931cf78c85a8dc42ff6557ef5fe66441beb6291ed6419fd73a4afa2c1c77cc890e5e3c68f3c32155beb4673f17902b05ef0df3f004eb90f7c96dc16bddbb442cf4fa8eea99a07545b95e63b7593e53fc22e7a1ebd80ee49823d57befa41c6031a6b868813976fbee217f3c0993c3e03b7679394166e43dbff4c393441de053bc0148dfeeeb78a33f1e97c77004b7fdcdec2942ec298c51b9e6e692d9142cb94b37013a2f1be2b180dff6c387bcc9ff37e172952531a4e4f91330a6434d662a2982a8900e70495ed68c74b8b85d5f93c666f8bd00174b956373904b147c0685feeaa5e0f56b28abdc23595e08149b0970277551dcd0949980a4de2d79ea201b18ca0dcb811ed735210b138eeb4bbacbfbed85741cad739d6e452796dd475f2cb9393de8bda6af1b7d59d671a3500ba14f91c7760be817cf8f993df970fd19c3fa16e975207102c4a422e4c985243698992c72666ab7e7c8673e640c612b4a5c6e9206d757afa0aa9b409466ff83d21dadf7dcddeb6cd4ac283f617523482225be93a8da2177f9070cb49e267dec08e910eec10989dbf53caaa3f508c42a13b52ed9c43cec9b3d43cc753b12686e8697e976592e2e2699bc2a672939be779092b4f74d192097c80bdf7436785338499dae45fc34e37b6891c0ac49ded3c87f61bf27d5bc393d523cf15be4c247a296662a3d38c80a53184db1dcc47e17c5f59860d2e0379804c9b372961cea8777c867a951a5df0f04a983215e2e3ed089a2417269fe93791c4fe905a4ef6e285dec3862cacc8553e05cfe9e7ade840958f5e8c9ee0e7989c6a4f8888914fecab827f14e4162031bccd5f052ece1ae80ad1d9060b1d772ad775b9f285da946ce8f4fdad74a41774e45df5d241df906ccfbf387e43bf0df54d6bee69e04e734dd65737ceab34e35ddcaa90b2cdb3f494605ed3f52ce2df15cbc9940ee88a9e587adba1c255a19cee56f5cda04958a17e8520405ecd44008b2db946ac4a56b0840f008855694c6bc0393c5c6f406bd63e726ba62f5e8bc937b28fb13fbc7c949d858dde754cb25734d40609dc8ad953f9d331443b9982fa2a6e6569941ecc044bca10f3ffca38c510536f2d423bfef295757c20131704afd09fde4ad17f472b6791167d56a9b2e7e9311466871daf9747d377f7614da42cca6c34be2aa3210b9de4426d21ec5015ab86f394aee4c30ec3110f05ed02fc61913a9decf67f773969b2ef8cdaa745604c2b4f46494e0ce7c0c1549604d8fd87243f758b969baa2fcfcea2c61522924bede926a1a7157d4fa8c2ab5c92d8232810adea9c5827e4a48e0d3d45c96a0a31b822439b68baba8b7aff27282f1f8aaf98ea5c2572e4977b6de4b22c0400e091f3ac825723e246913f7c0bfc38455fca663ae013afd3a89a1ebc6d2fed703d7be8348fb433c0fd4ad492cc15e7ed63a1c9247ad7982615b5abc294ce2e3fa89dfe5d21a60bc23b00c04560b200b22e6721000e6029313ddc893a82ff4a56b3d63128dbbd1f70ed97fe8aeb15e049793568624f899fb5fc3f19b90e43e3a63d77dbac4e2a679db9e4e62f676096c60fc74c4a0ba95ee587043ff58921b1513b48739d5a084b41c3fa511ba3315472ead26d4a598db5ec254c1c56f891041ed686be6db19505e1642123e1c543aa1ccb0a3072336279722373566ae8b102dd9b3b946a3510fa62f3b73c187c491cceb19119595d2aa0abf2ae8364cb102d19fa65580cdd84038edcb12127b6d1d0e373e8e25825da46c4c9cc4072a338b05ba0651823c6202dde7cc2a7f4f631bf716d2b08ee576188ee5a7cf0d3579308a8df7f95227cf430eec510ccfa7edc53ed73e39a360dd06f64905cf120b666927b2dfcef46f58fec98cd3bc31857e61d54862c4a356b95613a8fcd1f5f44dfc8d4118f966a52a67e88c9f64b09019949fa81b5ada2a8868f8a9daa804a9a5474a90014ea6a826cb1642dc2a8f14964b37aa463124950a482afe7a6471ceb9a58594f9929e241c99474bd4ccc70aee7392a842ed51f7f37323b255a4dad7d08cabe84c75a9e61514e33a3a538df92457c1276814fd93400d8f9995ab76841bcec0620d2dbad3cba94f127bbe2216397f8558eb06a3c419f316697df7e950942212fa730204294be3102d310a974f8abb0c1cd947d0809885af40c23d391bb5e282b8968f6e36195480ab9ecb3c07a2ec7f3a3d2f940c4f9d0dfa2092ecc3cdc57dada4a6c298ee1fbd7e3245c17a69c8a2302e921723b126d4f70f221cf2d8c1a86151cb05cc01583abeb3ed2cc0b395308ed182edeb497a1053a4cdac7014d94f21b0e770347319778abfc63fb753db5bb8b389a7e293bfe740bcbc7569afda83cc7b79bc64168166fa35cb467d613b6db5247704c82dfaf954f01180fbf4bc0bcdc05f26546b71834f53d07ad9f172e4013908b41651d9a6b5c4d3cd5e1bcec0c0e3bd20a6cf9e63eebde18038881a0370b8edf519c63e1ab21e5624b0b8e556572f1194ec20ee5e1c11b8d6e04cd0813d0bdb517bccd3b134519cd79f208959d7ec5309a5b5014c0afa8a0e5aa44814d49028823fa133822a543ada274bb86fba1083b5be33a3ad39f119fd749bb94b4e45420a09e0e5c6d035480362d08008ec6f34ea2bea8eb8292a1ee822e0ffb6350350a16b723d7cdb556ab642e54e2b1690570a0c8585c46a4a70a43696290cab22bbec8fd8cdf49ce880a0a93375eb4566918e8c6253baeda5e1e211c0c1eb69161374b3ee9fc6b5fe965bd405e1a5f863b889ba34bbd495d226236d54347495bb27c44c8e6a6fea6d06ff3088e6bb29a574f8124dd21645e3e1d7ed9c01daa439131edaf66328c4dacfb69cf63851983f4a53db211d53c19d46fa1797968b1c6d6cf6c376ef07b8d1f6211434f030a8943eaaa15dfb6ff6ba1493b116a5e8d07f1f38e28a74157c876a6a0c43da0d121fab647253791209eea5717f9666e4019b7a0c9cdfa31e36a057d05d32401b4d81ecaba6fbca116f97e71c084da716a0ce811abf06581828590842713ad76cf55c37a49441371844e26e888e83064cde96f51b097b49eccd678b96b03ad65106cc9240c3cd69039f71a883b2516cbe56c10a89d8e30d7090b22b5fa0a8fb1387e36ed8dbedbce91044dc99630745a77544a3ffd8600cd51da1d27c25587c31d23acca9fc66a998048d60b41fef82b0b040a9bd7101f9b81019d0d90632178e0f872ec26dcc71604c58c12ec6859b68e2009a9d380fb76950b7f1d03921531eaa99992867b2ead6044de1b57417fcd86703a7cfc807df2f307219a17b41bdee733dd8971eef9bdeed9bdeee433deffef8d50745a4ce28d1d21fd2a17951020392b7d529303ca7bb73333cbe3849e48b46ad7baef89b8e0dff6def2df97fc4bbb43d1827e529739e21022e6d43e2479bdbeae6a6d8af073775b76a429779e2f1b69b39e4cc6dbf5bfb89b6453f587917b289b0135b5f94d91821bff8877bec595dd049487a124a5aba082d4ab895760ad6d97ef16e2987d919997b087623a617a6d91fe8991531e691bf0a35c18edf81704c28ee854b4966bc74eb63f84b53ea9e12df6d27f04f3bbbc76eb313916329ab355f2f90e496bab81d8a132b65bde140d94eedee85ca48e6a87a54f75315b5d654455184dd61891b8de6acea09aa0e48f2ed2d154159f8f5c8402beb1990a992f2236d6c777c9bba8d37db1474af9f98f1562a2510680a7cffdfc608daf4214dff9dd80f49081f7b15390a0469d566991a2c1723194ad6a022e675d61483cdcb99318728ff915f3372e5df0e1581eec0a990539cccbc15bf4c90e8b99a1727e27a3887858bc03d7336ee892fef132459d4fceb78d6e03199589ad9a388892d6276958838259f66abb6924b0b3797db0b7ef8d1dead285021e4cc3a3c47b7bee3918657d441ba091a7b82fe3d5c4990e2fab0aa274738a63861cac5f546262ac3f4fe03d4415ccfe9714bb2ca6f178a4219a6a5476ebf8c7e1326a67636ad100dc40bf924e4ce721a7b89646d7dd268714eff1d584c58dda4f9b098b48f9e3ada04e741c126ea87dcf753a6cb12b7734514a78458dcbf2b56c0c52f501ffac4aa543fa838dbc22ede64d77b2c4d134369cbed8c0eefeeab98ea0abbc8948bf988066a4efc7c7d1c12352b2df90d1979cdf4bf554ab0d46e994e0bf6e0f29d246c0c95b6687ad146865422f4126a7b70581b8b1df6c269c48f47d4253ebdb6ff916d02603f2bb2c084a9ef7e41c538da4d29461a2b500815f918a09100ddc664cea1fe533c196bea9e25927079cd543af1bffae005b26f789974d94cc200da0bb3465c27f7a9122fdef61b876d7af874f2f43117493ba3bceb85a11d64e29edbfc0c989e5415469081c79ab827a621832775abea3d5b67c98adca450d543a75e1fc51cecc8ad5b2abc5ac646448e456fc8195111e66a08aa202c6b0eb535990817762406862652c412a10b27d23aa1b823c4f6893b1bdb374177a0f87df363fbae7b8aed23964263fb575cb3bf1b376a23da2a2a60ad2947aa6d1ff0ca6e5ed690eb633c886c635ba83e33d75511d9679c23a3430f747c39716d1cff8a6283af9ed12e7f887ee89f4c74664c866bfcd00f4a6dae80d36f3af76cf22f9436dc848cbe149346ba55046f910248226f58b91a4f15739255d14463e38890f8ae2a85010d21a5f4fa3d7b77c272be327fd397ab6930e33437e31f987518ac1abeaf839818c83d6da707d1daa9316bc19e60f8236f7f06ec6146ab6c25e463f7620ce2e1b33b8c4c0ea22131082ea542174a6916fd844892084171a62521d606616e8940240c9d46c1808a4fcad98167c4159afbbe805a3b7e73cbbd14e31d133f37ece9d2527e1627789208bf7b8dd265e1947d7722b7287279b247b3e49ef0f056b8e1d156afefb4898e46660bc2b47714b0ac311c561d703020225ba67e091add6f67c585cb739ef84330ed8ff341465ceb213154f4bbb74c2fdd108b5a61f0f14b28d8b7f7ab19d63abe9b1983687ffddf88d65fdad112f0da81e2a0805ae8c329d874e86c22a6e8a2e6bbcf68fa9bd7a1c3c2935a3ceab2fb91f5fd5c0396da3c69a79d5d828bc20344672bd155d491553b72c79befe5c60551ccce079a3244132092c5d77277b25527a8841da24ac98ebeec5fa2b9e1d4f10dbf1f158c2217e40eedfc8ee7d1e5a14b5a42f4ddb20f7f33a61109fc84815ad4922afe260b6d9d595f6ff77a04127598c871cc40327b2e1956c0547df1ded18050ec30850ee6f802aedb1555945c7db185524d8e9a5fd9f468b293455e822fcf32b012574121ced80aa350854625fe20d526c3624a3c5eef22905828d39a4d7bd3d7fa9afdaeee7d24c2e4bbe36308baf53be0a749a6b78dfc82c2d45c8b3140219b614e572ab09d6e2e6bfa14f567eece948827e3b1a779948900708a9e7a585432843e4dcfcffbc619bb29d7f717cf8669c7043b00afbf07f7d617ef38bc87c1cef7d658916c8d1ae0939cf73911690273a97c0dfc9526fa1a577fe39380fefbf4a239ca10ea76599e7265aa831a640372eda7258b0e1b446a17566e07a564cf8344270410731f12b7be22fa5782bbd8faa34070de05eeb53f80523b6f489caa93852b5726e10b7cff6fd057440219925450377faf6d84b6c416ad5c31401b3503ea6603d76a0ba754a38b85f437b690932a24f31140cabdfad6231a0399b5a6a2011a6f6c50d71a768a967671a734aee22391c3667433fe781bbdbb9ebad9e0dc07e7b6360894cb248801bb8ae0786f2ec1b8e7774346ad3b8461c7f241a051e9142dd40afc557c104174f6d65f82473f29a4e98cfc94819a072ff594ca3328c2e45d895a30ad3fbd936a0d6ab03e1471303f4e3080b2298769b5c838302f378a0c5f6560f0ec4010348a4c2a54df566b1761d17565c3ebf55d49945351a6ec343eb0481f1f79ce1b096d8b3e98f6bc8f8a3e34a2b442f37ed140b204f431a6c4fc455149114a326114df56e90b9f30d2f773905ce5789236a43b95f2235fa985cff9474898a04c493fa5da3adcee05d5b2ae8c55afa5996311557ce452a777d7c5543b619819788f7f1aa9e2fce0513f03b3e5f7dc47c11caab7cbca159c631c654bac08e965e9166611cc504714fcbbc38b894f09326b0619de044158dfc9fa33c776ecf2ee8ba5824518ea2398e13a1cbbf2b45e4bdb9fc604bce375127d5993567d9613c5c29a6ea9f9d0e50616cb39c165304c4e6e949a75abd2a09d113c33a427ae485ea972d65cf96e9359c17a9abf627b202828c835fbfc824809061788962b8f07ed810a7c7f4e7aa09075032bbbd7b46748a9dd901623d6685795c6a18bba1e9f96fd2fdb97dd6491db340cfdd525d4c9accea51ad61882eb5f3470bbad39efceb76e18ddbc872591265816e3f380bcf0e3998d9ff9fa7f74404c39db821de9ff986f0ad6863909c73bfdc8f829ad1ec4016bd430d09044f93a680e23fdd230e7da599993ea5ee6830ead6c47bf05edc83ba83cc163117a60b5845d85daeed0f1a2b4ae808e46a311baa5416b83d0dc884df29e5865f6b3afff83df2462ca75f5e58bbb642216239ea6ed352992931fcd65250479bcbbe002f793c26035515e4ba6b6ba00d1fce6be96872d71c5f279e40b451649498e30477bd7dfdce3a6d51b1ee65a25e40b5f2b86581c5db8b8cb4d15dce6f42acd0026d727674fb59020547a83666f8b75a082263e7f1f2e94899b6d7100691cf91d63ac29748b45d27533c5d4b5f1b0dbdeaab8765d35388be7de60751ec52b520ed0c1debaeef2e582aa8e1646e6bcf9d2ad8595d27654ba2f8c9a4c3b87e6f933f6721d29f3c20bf690eb95060b298cef9d5be1eda6496f1bca136b796332486e60e2dde906a2f1be1d352c2664779b2617bf0110219b2407c031bab83f2bad52982725a493bd97bda408345d153039b9a4df2f723408994274e1f1235a129725acf5db9d30b9a4e80071ff623d79cd3c9288425ee8e11ce59fcd1a09c5c00d218d799cdae38872d56082f40bc55c44031645509648561e3587d3a7ce2a58875b5065660dbf1d431260f8b3b4c2f9fa032fe8db5e41dee8c355f9d859fa10ce3223af5cf50ea4606b4f14196c3d5a8a805324541d301e96c420d724785635549706b77543b593654a69ca0a0b36d14fba7f0fdaeb1e5181e0cf58f56df4255024796920a5ae3b569f09884f5abf87c117af0c2996d92601a41f19518a3e12f9307125960015b9e9f4f40a6a588f5fe16f48220c54dd28fa08f4eec97dca7289d2a933ca327c8200cbd915ca30eb5baf34247f976c263a009ffc3ca1e72ad3671d614b8f72aa03b39e650643f00b768394611b0b22cbc61d50d46a23c1cfa0bbcbbecc21b24c43299013c045c446efe312e8f7d284b5be020d3b1a6b74ed427f6a669f72c8c9d01c3c0949d56c7c04a34f8743a4e06ed8c9f58918ab8ca458df5ad47db51ac6743bb5d425114d8f07dd070d165c453aef434bfc6f2a744d44df73c0603bf1fea082141017593f08ed978c8ce6529ccef9c5888b2a8945a7b326f6e523865daba62c8194d117dc58e19fde0d8da17930006e6b64f7d374321ab32603c8803a2db8b2757e9cae074e1317628e63175ffff298f846fb563cc7f6bf1c6e627a8086463ffa8ec63237915605f9bdf470c99b7aaa19eca078677839c5c7848f9e4797db86df89684b9d1a590d6cf0f128e5ca3a02f7112604dcd20d4b98855300c0c5c5cd77db9f8bffb7b89e99d2eff434de3cc10522b4a459fe185a639883fca069e34acb47a1de02c809c52c5d024859b053508fdd18e13037457b26fe080acd6f725bfee83c71a6d4cd19450f3062187ad18c72ba8c4f8665a2c6a2a0af94cb6c9ae1cb44a0847abae3ad8c8d461ba8245e9b46353881fdd825b2945391991aa7766208ada188051d967f4db909e235ff675392bbc90188a252e65ecaa23ce2dceee8fa74b3984fc2dfa26e880dfe5901d62d983d9f3fedffc88773ed999ea0e4a06da674aa6a790efff09e6682cc351a4ab3785f0a65fc06052a649476528d3e198f325feb3eefa7db1a48ed779eb0858ae95279c29b0ea494e7d0312e22b431d98b1f99d4172b112f9edf5af9936fa7886eda4657d21c5735888308f0e371a86c7dbd97103a79b20340d840780d3a44b288a549be4ac30072117a46f0f4aa42a18070a1d18ccb89813f6e09c97649b4458fb0540bc6de0b57703496a9c5b1c88570b87c9cbd5d6a454dcd050fc28d1940c7cce34255b54118eafca875220466309bcdbad2fbe2f2bf5165f5b812b8a3cefb87293d764870990fc470c3aeb352aaa27ff00115bc884a41f28cefc401d99e42e76ed22b98695eac06498f0ff38efc442db5278e52e5fc5bd828bab30da5c8242a79417ab3d6be9adea788ebebfbc67909dcd70d393d16c04d97553012e43b5ba942f33317098636ac255fe7751de53d1fa0d140cab2a2eee93b0d8ad6be771a483ca6dfa284ee434fb39949958d7e207e9a111752d2c57f80bd6ed54ef5c257a9cf3c95d32ddc6fa5c6a4c38b3d9ce70c2db38b7e0a286725a3a3bda4996111ec54fdb738437fd192a1f0fe848a3d19e95c23289f6b0fd1cc22cf5092331979f08b3cf4cc6d8cb66d296d69c697f65bce4495705b79781ab081a889ae4d8eab6eb3edb414cf8d6dfe7b385684f68fed7b08a1c272724a150e695d866ab5ff09eefd4515c0356956990bf00702f7ea0c57a8469e4dd687b21787d9d542bdf8ded9ca1d53ff9692ee50ff65094bcecc98d88bd24e63400e60f0591b5b979b1dfdc8a4973e12db8888f5bcb1ba49434c3cbf0a8c09553fd8716de5264f91db6110bef9830632c7679e55a02005ad692eb463cee93bd79e32ec8819b99387105d23f822dc4f1cd77781cf4e3566c28ee33b74b22d93c389e255dff94765f8d633d4013d9584a4597affb173d38ffb7e9c9920e3107a7878a8b96d719ae7a102304229332f8b1dcc5fc3d5a4225994aa54ed7ab657138cbeadda4c13067666d429d04fc46985ccfa3b256813d20ed1541d02481972217dc592fd1c3ef6deb1753afda3d5553e09348f93d0f92d53b2c879845b6ef9a0d458cdabec0bdcd24af62d3012b7fbb508c46a23fecadedfa72c86615559f8986955193002d8a2c12fc95113d8fbe879e3329b1e5275903b9eb99acdc733c95efdb825dab3bf8c0f011ba91eb67ee22b938ba44e8b4e6844c79ff0047600497cab91879cf0ba0241451f1a5a25f94e0112e5bfe99448e14c5e97f9cf1bba6844e568b14244f855e112c8f599d002ba4ba458adf4972bdcfa2e3619985d8cae04fa7d1265108b39fd30a6148924561b97b669d3112e002246965e060721fd1839b0c6a327adb2b5eb823413d698dac7fb6bcadc0e379204d2c8a1a8e303d53565b6a60b546d82ec615a931611b65236f8dc80c4ee11eb79b475e7ae02945204fa9283b6542020554d073820c327868610af10bcb17c04b0391a4dc24bf32c619571948e2569e58fe0243f0335ff7862c58d0878835ecad2476edbbaac25139befd5e8f87cbb330c74a8a814d48424d97befbdf796524a2965ea0a5c0bf10bd9c7ed4f9ad4a341df303069b07fdcfebca6e2376d2d2861dffb3567b65ccf67987bebae73378fdc6cb1e0c518638c31c618638c31ae434bc05ea7df919b768ee0127e1ddfbbe16d734c80f963b38d5467e147e79b2b34f7e59f5db1f55c6cfa422ae951f64aa4991dfaa7475d177a472959c9f00b1df49ceb5c7cec99ebb899098ea5e761883d3aa29a669d4a569a7130c94a4b94446d4e7d655a2571305ff9083327d3f211c2d03731f4effb21c8fec61e98a6833a010a4ed8d8a9e7853eb32b98161686996661a531eb58d7acbe72cf0ae62b0b6192d429a5630907dace766973beb4b40dfaa77f9ba3e9ca34ebea11c27cd949d274f2b6f3355fe18b7af7815ca651da1d6ddd74979ee36d8ef4ae35e684517d521a73ca94259bce9813a64ce14dd43fd29b8e73b6804e43c7433308c398486948cad125b9c39e4d41c7e1f9e6df633f9528dfb6504725421330d8d86b18a339ac24246c7518fee8e327ab0b83978a4197aa6d6956110358e9a7aa2f95a9e2659860bd9aaa9015c6aa2e8b43b5062ee84e895b6bbd74da4ae9156dad980a1fa74734094daf5b6badb5d65a70bc36c8a5150cf682652083f5edf3ba6f4f1f9a51b02a56d9130fdd21ebaab04b645d38b27f97c8c2708f7501dd210b1b11a99c6a7487ae35a23f2febe824cc96ea5faec18848ca4f8ea281a61be527948ac5727d519c736f8dfe2afe9c8b1ff79c831fa26aa81c99447e30f3a2f088ecaaa3e4a2735f72d2973e36891b4d4c3bb473a2836369621a6ff4382bc9893eb78f0d3aa924f9cabf0c821ffaf7813b44e776949ce49c1e4d4ce34d6924710e72cff9e8b4e2a51517555e2aad784d154b57b5b2e2a59187cadde2f8e3ee9550c54f28e75c857363398eb392efb7920f02018e25ddeede72ff7204bb057eab257a486a3907bae8a1b75c454b248da58a168a73906b8d28ae827b1450ab50e1a19f702177e25ca681c9e93639388e9c8e263728071de5e0587a5bf3d0ce32a19ca59d857216cbb58f0d967cd691441a4b6e8760e82c5f63c3f2c7dd2c5fb96832390d75a09cc51a4beda60ab2bed45ed62dfa67775893834ff2f04bbd43278965e8266e7a1eda4b4a6eba01475dc951a934f2d08ef2528f2c3f798d3d79bdfad2c73ef9288ca95011ed1f76a3bca6de946c947f3987b1948f888c8aa0bca6a67e345432aa953807fac9bfd38f8ccc40a37c3454c9ea2819ea6b6c4d055fef920fb2b1ccc2b0cf68686464541b4f9caceb343722525f737b51c8409718a8c449a038099306a44008011e9621ef2b8160d785fe7dfe758f67ba0b7b6040fcc8b1c67625a79dd7d48f2b8db7ebc61f57878d3bdce10e9d83e38f11c8dd77e3d007f6e18ce81c030c545f9c17e411a9af0c03fd39177a682a017784748272f08c326126739ddf0d749fb9532acdd5e0e020f16233443b8e092c12baf3a80caf881f7a93bed0c511184644541bf4214574fe43cfd825fd3cb3171b96faa95855d003595ec4e00a64f9fa5487dde60e7ea647eddb0a6f3018e2e9c225a62fd91ede681c82cfc31b9c029afef42aa0e94de30a68fad2de3eb0af9de4b522d8d7b73125bcb1fbfac7029a9e845556807a9334b0d275dbca0a099a7eb4c76e92780c2749626161096fae0b34bdf885e2c974e115e18daf086f340bd0f42199c99c3732674ab6004d0feebce3f2bc9820f675927b0f335bb0c73ecf3b302477b95c2e40d37f9bc5f7a14a1661ec2be101725bc762db586c1b65416966d1029adedbf649b305bbf7a5e9829dbe6aba60e77e355bb08fa7cda40225f0f31694e6aec5d622bcb9a6ef362997f0d01df8a18bec22e7cd45785377ced4850b083e6992d8bf2f9924f6f0554c12bbf82793c4dd4f17c6303ba60bf6edbb4962ef3e9c247692065ac2ed032d38042de1cd7d014dbf5911f010dec080a6590237729cbdd8b08c74ba30c92506343dde9987c5e9f3905e6271f0799e67a66d48dff4f3e020a16d587cf662439a86f09e345db0932c2fe14d2569e025bcd1d4f477c3509a615e80a6b79bf440f4ce8e738cc638312caba40ccfea0be36f34943dfc78867130e6fc1b47fb6ec0fb2fbce1587620bf375b7cb811c8fe7cf36f8b09635dc6b3ec26379d5fef4e77cb74e395096f5090e9e9e61e88de74f3d203d1bb730fcf497ae3ac2fc20bf4026dbdbc40bbaa30809a2ed8618437757bfebd26459525b305fb8b3096fd45f895f0d89744ba61c8817dbbce03fbe23c43405fc028814101717394181d0db98f0648800a1b0d555775315319259fce81a6227e705b77decb84b1f8259a2e350545d9c267866bcac03dd4a5ba8f75556f4484ba0011a1d448755507b922bb7ac518771be71cc63e6e678c7f03fae63649ea9b0b75d2db39324d92a626ee696d7a3d212216fcf2ce1d37cc71618eba6ddea67bb58fcf85a2923f3ff772f55ef0bd5a258d0ccd967c3bcf0c44d05084b3e2e35d5d6edd96a4235f7bad7b767bd6bf3047ad1b744a49d014ba98776c7bf30b72e2870fe60c825f681d343d100e480ff6e921e51cfd5ecdc86c01ead230f38eb706bc432ebbfeb96968802f16863364e438a423e1a88d0b459f1e89c55fd74d3efd06007ea82fedd385183dcf8a3b49eaa4e726499de5c1e9a28e9f35497a9a2e4a9d8eb79246887f27d9e123c26eb336678b6f18c3ceb3c23ff24d50235b31de1debba3a57e7d26e4fcf9cdc04a79ea4f5fca7a99aa475d2b326693ddb0c3edd194f7273eaf81bcb10ececd64b5bf60d34457171a73dc73f5af4ef5a22452ae909edea1e10f9d326bb2026b2bc07e40555b2057a56d223e1ec527768bfeeef6766810eb29b0c0fc803f280807ec8a9ca3bd3c53361a45727472cb32c5ee6246cd2cb4c845dc7695d322a4446319e2bc0d65615e812fbf880584665d05d7109280cfb500b63f18a9db0abe3255018cb3822e2af3b229247447216b3cfa0016a0bc319d2f9694f95ab742c7f65454537c7ba66959c9d63b74ec39bedeb72edb6bb7ddd66f7f6f56e9aebb534a8a535eaa550d0ddbdf7fac67db3ce0ff44f06f49e6705b782f48fe5a9cd8ab7424141b636344462f9694312bdd00341d0ab3c70e919ddeee6786b6def414b64893e2ad20103f1ecd2dbc2ae40958ca2b5b9512caa53a86229821b24fcc6b912c6b63cd39df59cb1c5750c73fcfd6e7e01593ef4a1d1807e7ef06579d006dbfaa25fe63eab6373ac2ba76767e7b713dc9cf1e6799d5328e8cf3f1990e53dfc3ca47fe4d7229e4a44646756663d74ee56920bdd726e1d0c2d67bfce3d6feb36ec395f7c3796ef368ee5390ea5a394e4a1e821c9bdf0066fd1bf6fbea8a2b3fc6633eb2b0c49a317c6c4f156321c27cb678bef38c39bbb2fcb111cddbe63ad0d415367f93961bc16f85541977987e5b18dc78d35c8baaa1d79587c863c15a80e5997101355087b405e14f50b6798c3a240832018d2802c7f1d4409c350a43b1b8582f6fc9301b2bcb5a17f8fe0c659bf9837662434f59aba79d7e56d148b5a612c8727a2288e66bd8e12e6b07be3c189a64d9aeb180c780412431cbfef28169d40c7ecc85a51cc6eafb55103ce4943da78636beba6966e704e1abd7b54da35cb63da79dea1150aa0fa53e996afdda33dbd54cdbc0491f80a6e611e06f280ac4aa5b585d9d1ed1ade90f658b91bd2bedbcd3bb33ca79aaecffdc34037bfefe36d37f998a481f086d47dc521e0c21bdc3ddde44f1b96cf4b747967a7ab74debd5d6b034e3a69ae2637c741c26d8674d4a7b782b6637dbcdcf6f4190bcb3bd6557df0943122f281df394ca5c1384cc8537bb88d9f87f45c755876786a4cce7504fbe96cc11e2303c684d865b62aabb3a2cdcae43d22f2855dfdc5c5d130c017217618787fcf8193dc46baf9d89bdfe8dd51183042ecafbf1bc884524bed9d01424552452abfaa1d4192c4446682e3f26291f2471851447164544685bc8474361bff47e8c305b8fdb6539e012a4f010854b28edf23c44025abbf0fdefa1be71e008ef2391c7f0c979f9b885f1da9ae4a84cbac6a2f646a78668490090120830387ccf8d65f3c0d87f1369c88ffe1afaf71d86f5f79ec336fe32c7fe2347fc3657c0f3ee36bf8cbc75ce5b3a73ccbb7c75be6797af470ae47ac87a23ab812ae53936292f5bd7429c9191b57b52574a932b4ab972a45548a4c9ad932d2c3a60e45bbc695701d296a3ffad81a51466e1c6dfca8f1abdaea08de4e58dbea88cb52ade230c2d8e89f09b8fddd33df1a9a2dd5df372c8c80465e7de55b3daf6fe5046917cc3c12c9c5852483f416a4973021e24d885497c9e5e557b515ccaf66fcaae8c5af924c98cc66557e7504c60b70c6932ee379709a6f71fc317ce65d38ec5bf8eb593811af0187f12e7ff12b7c7bbb659ec787ab3c4f0f1fe29d03ef45bcf75857f50dbcd378669c8d0fe77c784a0f8f19c26188f07f20dc7e197986701f798870940da8be54862a16e64b050d93dc822c4c65665d30612a534c5755a959575529aa6455a9c324ab0b49baab54415b505952b44b0f12dad53f1fdfe2e15b2ddf32d20a42c3507d556ff1add96ca9cee25bb299ca14350b9b53a50ea0575729025d5c48d25da5d27aaacc9ad8a1972545fb47036f0285e8a5ffaab63ab232b674585688788ec510afd25ac7c256b5554d6755d359d57476f5d78aa8c793afd09d07980bb83ddd780606c4ab2329bf228a318eabdaaad6e262a6858b5cc1b2a2923233aa6652a8929993696666f3ffb9fde76efd44f91396dbccb2265f9ae498ec98f4b4d83033d2da41ab0826329322ad179861451405095260832d044511446445b4aaad6a50fcfcace82065a53d90428675645506958cfd0dae079b1c1a356cd4ec9e174ce8c68719326862784536f330b3635db30903805fb7399326c6afd7a1f992f1eb63be5ef8f51f1396c36fc8c406c3c5af7313860316f3ebaaf97ae1388ec3f13843388f3d8c23c1d9dc702ea7a7871c9b9cdd53d363a3a7460f8d9e220bc333ebaa76c658b65432c652a569c652c7188b388e87b1d4e5f7ed949808d0ae9b4f9585b4a892453486ed9489b1f96ea28c26abaff234741a9ac944267a4ab167eba25d3d0bb55aa5aad4accf871b7bd3d98e26eba14d5a2df7fa54506aa79295450b162c5a7849b6f0d25bb4f052b7f09273712a3a11cdd3108ea7b41eebea99295a6ac857f48a5ed12b7a45af9068ddf5f1bc0f0c3beffbc050eca93c7567b55aad5624900f2e97eb64e403c1501c7924992ed2412c2c28140a855a31646414fb0986a138d2af3fc1de44848384b6b9e138bcee549fba5377fec7ba80acabb6b478cceb224da481c694714c494949511185c422de890d53a67aec4f307faacd96ea377e4e98f224c53e0dd54e43b52449f48a5ed12b7a45afe8d3108d761aea6ce74293c96838b24a6a920eaa648d79d28c24d3422b60b1bc9e9c9c9c9ca08835f18828ceac2ba792d5394e6b95ca7776cbcb5a23095957f59b27055957e53827d17cc2c6eed5b93c4d42e78ea2ce3ec9ac10f6ec14b960abb075b55aad56263321e1cbe3e0501aa5511aa5515a46d341b2ce76313a93f9d30cd3529e725a0ad3525eea9253e924013ac9c7ba7e2a29a30df5c040ed878f11e8c2b9dcf898c3f0dcf01c4f6aa2de7831926834929c39852f2f3aec8661613c0d633cf85792aa916830cf1373ee79706c3ea79dd9a2634d44255369e2d92ebd9e64258ee3532e9faa55529489b34aca52495249eaab4cd56157af9eaac34976a24d1a8b72ed28140a85f292dcda57a24c078932dba56aa9daae5e620239181700fca9c7ba708c224e75d598d65a6b6a6493fcc59772fef372f321d1483e9594194f325a17d3d164349a905d3d15e6606d71564998e7c1e12f2fca2a59fdc6cf381b1cbef9783e75f3d9d571c82c8c44a3c968329f58890aa5820a9a7a0ae49e27161b494db88c241a4dc51237bff1d3a6fbb97908632d5f62257675175f7a8bd3d06908d7a02409edea2b4419890495884a8a28ab7478120dbb60576f7d491a9a484e64a4144c232b12adac74d82589866497245a2db24b128d48c969a82464573791686575c32e492589568988a2ec9e764922d1ee2e45990f8da6da82d8d40174e19b2ab45a5be9ce20d8284df69fbb4e2b829aaf575aede975da3a3ac0e9a456a45eb1b5155f8ce98b7398439e1782f085a11dec6067470925401f7feccb5dbfd6b7ed5e93cf7978cef9e739c771e58f7d1d8f18e8017ab45ee1da7967c6396d1ae6acb3524a079f9a4f6d7f541445277c4a3e4e94944a3e4e9494f80c4be306acb5254d501927a75fc9cb999dbaa27f2f3b7572e2746ac2099fdaa9c48992e7c692a2504d388172ea8342d5504e94949438e1dc567a8aa3b840168afa537a62979c36317a497d7699f2ce4b282f7989bd3496d46753b77a2cb5934625d7f665976676e9e4a5120fffeeb2a486a19b48a4702c5f769912474ff4bb49238f91934ad358be6c8a1a7f543cfea85be34d9d3a41658c48de8d3c44c79bd49568d1a913d4a5c479e92d9747ae45afb11f90bb79888e7d863844c7fa474eb5c9691823b9fe51a964f29aaa6725450f1f7cb092a28beef1a8bca4f249eac8ce55cf5557e7e2971a3b494fcfbbbf4ef8ec9a8aaa2316e80fdcdb87b770c7ac241ef3f5ce62ecdedfeac23ec31d3e36f6fce3fab8ba02012cf9ac511a55d57a1cc771deab3409eec7e23c3439126e53f2f03e4b754f43422ffd10ce3fce491b69e436bce15c8fa32fc54087612c04b990bbe1461bce3ac5d849c5e2c6eb8531effbfce67d6b3ea2fb39496e9c7387aeb848087d8252aa027ac45812c70dd85d3af90c4b4e72f16ef1fb44f1a928522abaf8b40c4263b4f4df9f4e6e9dce4e27a727aff48953e94bba4b4ec3d857a29f53306ba761cce4f9a98f9ca7c4b5d7d4918f35959cf466e729f151899b9e7375f433deb949589d2a83313b9d511973d3910aa9a49091d36fa4634985e0d05ea2249283632d7b9470a0f5d803dcda4739787c7eb71e799874c94b6379f1ce4e55406590c691f3f81c6f3d1acb6f3452155017cfe9db9c73a679e692c719127a8db5eefddcdd8641aa0221da54c319d8c094021de5252a2f2139c7691578f29ce4dc7bfe7df9637fda479f0f4136e7240e04d9e2d881d6e6469390f3907371e4464e1ccb1f24277d3af41190d6f676909c1b45936ff421c8f64613ef73ef73911b71ceb90ebffc7c822e824efa924472edd6f3481ec88d3c4017471e2ae7bc07b847ad52a54ea89292d2c94ba792f64f9f4aa512c9f55722b93e954aa4afc471a6d2683299b4d65aeb6c0312c93fd2e8cb1f2a3cbc2afe25fa486bd0475ff60037f56d1b4b2fa4a10f4142f14b3efacf8a9f8b9f8ffc13bda435e9eb9e24e7a17de424ed2307c5b107f8a307b881d0541559801d888f6e9b3ab7e91c6dfbfa388360da81ebd3edad4cd07a816f64f124adcf10ec4a8e66b5b4896a71919e4e9dd620fbb4989bd6656b9d7d7797e1867868ce3aabc3e874dd1c3ad0d4ab4a6dc33757e839b4bfd19e5ea98cecab71d639b4adc576889a215bebf855db5b4a029a1e73685b9c73a02de72525c1aeeedc1741b3c51baea10ecf0b41f00247c41c9a62747daa94decf4d311870904e099baea81d3b9f13e8e9259e6dea375b6cafbd76f472365a87e424320ef20d68a6dd32cef8daed35b05f2b1502ad4fe8594fa71315eeacb556fbaaae02ce418ecb15cba6fe71c2ef19545f32946dadb5d6da0ba46da5db6dc23755b60be2cce2f49c1bbeb60d1a63d5377a5b57de58f6938ab56d75abd9b1e711048283a0af4ea53caec5d76e790329ada91cced9e71d7a802bd0d5379f143b75ae6e1b0778f4e841fd0e51a1bab3ad4a16b050db74d816284710dac6a87d7dd2a16e230522b797947372d25cb745d0dd0105f1d965f53cb1b39c9b3426379c873850fb3a47a3089a2d163b5763b3df61979c898eec9c73230fecd9e7def288471ecfe71eeb0ead43fb82e0b723413f3f5b8ef93e6f510ebbbacc25d2f409ea437d42eb2fbe9cc7395d398f34e36ce30beb30c21c77d77e72a61b110cebafef2deda1edbab3f3b20ee3f0cfcf48465d544f735233d0bf592745c786ee4847d421996959579b2d3f23d94f097675d84c18b33ef3f1a47c7b1e957b29a72aef547e6922122ae3fe5097ea594462840feb82035187bf23ea8e24b93f5446c7069c4e8a7c71601fc4e0b61c23c6fc44ec2d2f192606857a0c40e00d433132209d42a8b68539ad30a110e307a6e69a30fc03bb35ca000408ed5a53d53b9a609cd2806dc7d972bdab75b5293aa2cd86e9aa38ba5a4d13a092d585e88ecc168f05d355bb36784f4c8184da90211fa872a067e09d4065872e0eb52534f6bc7d3239335957eb6a5d8d5a7cefad8d5a706b2321d485fef7e207007830ba6d1fcf6e92d7f38793bcbe3d6992d76f1be66a5faf25d32584ca98d365f3cd85ec3a3ae015de3807bb51f3333313c630ed8e203b0c7431143378c64c38f339861d34f5123fbe350bc33f62918c108788a492554ce2b091ccbe98442c129188486416767faaab7aa34c5ba711c64424f6c5aa52c9ea4df8d068740d5a44221689495657c5b5aec2da4b13be5c192c19a14af576c66946ddf879508e725da711de703b6328806ad09a06bd46c8ad41dbf03ace06f61bf3428fb41882fad35ec7e92d6bacb5d6fa5a5da98c889de616cf3955da832cd0d9260533b881ceb6cd16f9402bf485382c111e7ee52e6fe22f9f1de6b1bb9e735ba4be2a1a264949305f76e84685d95a2322b337e7c8a461e1d67f54580cb7eea3be36d2cb2985156edd457d8dafd68affd599718b5271ebaafa4a71eb7bca20dd8e29ff526f8bf040a72c91d116a9e4e30c6199799c133771156be528f72c1a98d8f57581306dcdc22eedea58d825dd552aad69b55d75dee5857b977f15c4e172fc30fee57f719377f1d5f3e0b4fd5d22c0bcfa077b9c217609989becce0ecc744ad9f2eb2d8dc7f6d81efb630aad8ff539b14a1c585333845de3286f93b03a3a791bb24126f02453aef225934c79caab9864aa9bae149d648a34c9d4c924535e5325e1cd6f947f1f8ac5a5502947853115fea5c220c8202727a5128120643653a918f5581c2b7b1546d020cf91111359579d5969fd2a49caa3bcf52dbee255f8f82d5ce555ee9f729477e1acb7beb13ccfcb57fe22f95b345bb85b875dfdd221857facab7acbb872e1e22b123b562222ac635d2a1ee7549248f537c9635989d792bb44241f38697d5bb168a7139611dda2c745982ed5671eef5857a531d193c41176c7ba44e212a61ea0b440aa51bc355146ea6bf3282a0964838276755799b94810504e5a2c234343f548ad7d0e523dba87b115fea176308b7cc57889ea4eb529256632d7be454720b2f138367cc6440735fce47966c699dbd4b0e15f0d1596ca0a6b5301d2a091031a2a3366243163858583cdbac1ce282ab0b1e658577dcdf88a90a7ceea4ea585b5c7063364910b0911914b080eca904103192d1ea4a1f119d0b8c03f28e0c63d4d4297fc7b30061be5e73f5e796c64687c4c0407fdcc8c584885c452ecea980dd3a5f2bcfcd24824da36bd9ed220eb9aa12c964ae54e922f2f3ce8188126a1b57f2be0c6f23c33afa0d12daaaeeae35f24b270afc03f97c805cf5e62660c0c8cca0ba20002ca76b32f30a17f5466cac4c4ace440f1f30313f362be90910963db46b794ad24774a9e09b273cb78e3b694bf482a5954491c2ae315428c0c8c09e3c58b6f05b8a53c8ee26745c6b944330bc92bc82bc8b2241967d2704fc8bc78cd17fe8101238c61287014d88ef8e773812cd8f9f10f50145054b28949a3e55c6bb82f511166c65b34d47530421cdd4e19f14c932ba04cbc684f0aa80c6021cda13934099d2582309b8981128315e37381fe73c77894ccf3729a4bf4030d02788498791a2668421d76b3c82c324d18db64c8a049c480dcbbfc041b035d24d5553d65bc4438c9aefe2ab3905dbd4e0c056bd2e01b355886769f11c6b2aba8b8cf30a6e235f5830171b6a3fc0cd63833c39d7076b3fe17c98c4c03ff6ce4cfbde2795ecef23c305f799e1947790c452531112c04c3c797733fc30363c4402bd6887f7cc441462a0c46914ad619a72d98cd696d7db739d86bebb23cafffc13f9708ffd00871b8ec5b34e42524c9172f4af0a2868c8c6312c8d88889717c91c4f8cae416b1c64b74772b852a39995e2a37f9b955b057d655292f8ca1300e6ea2085cc347b010eb87b5cb4b4481e02a492d112b648b709ba5331d9b14cc40446778e3bc5b7489be4bf4e5519097fa80167c53a55c91edba4d4ab7b14651c901fcbb0fef7ef32d07c0739ee3513cc663af447a70a0d3810d14c1812196982f1daf01d09cf498f121c70d0062b076ca2034c59115b77e7f260dccedcb2d0909ceb66ec47cc170eb474c18116e4b7a704060544989c5f40033e345109128a2c86325d243c6715a9cc75ede7b70713f91e13fb88de2037816ffc16d5c857a7675924e7d6d4095c4c17c6d5898e48e856d41659830ce05d355b999751da92f2e09d214f3c52931c9eac358ba9039c692f49bb17400907662907682483bdc1224249f500f8e97bdf9f759f07f001483df067e18fc403a852e5d27e52fe02a8f017f790b78cc57c05d9e020ef313f0192f016ff170d8974ec487c0617c06fcc5478046074f0f1e222c40819a142e9b47998110ac6a17f8d5110bfc8aa802bf4242815f154d400211a0b365f350dc32115f7b78ea4edda96158694cd06464c0ed79c879b3200e088c2a29317f9a647698674d32fb8cf7d992f524b36a9239b36e7eb3fc0b350eccd261ecc43f910508e6916b87e1a65d88c82d8adc8b8617f11ef00d3c10ef400fb121fe032b50b00bd1c8d21811c556498cf000901dbb4161fc20fcc5d730a2075ff91f8af81faee359cef2d669fec4657c8e01f1ed5970cc5b28580c626834eac9d19e472269adb5d6a5201322261a3b566343ec61553bb1accf09bdfd0ad12754539fd027643f21fb09d96f55db3e05f6520266c68bd40ad531ae0a632ffe513dc3671883f14f057edb8f3be569125aa432e3458511524d5ec6552da7e6d424c2aaa3c3623d9296cbac6ba846d42aaa24cc8c172dda6c7982668d941552222213d07d8524c461bfb52a0a71b8f6cbb8223a829e953c01537e01aef20cf0975780c77c02dce511e0307f009ff106f0992780affc031cf60e70221e040ee31be02fbe000a40c003be4573c0b776500d78132110bc4991140316b0225a215915ad92c80af026384ec804783a5bb27b1843f1eff1eb51f6f62828631904b7c21877e2ac8d7ffe0a06c80f20e30f1f431efa635d3f5428a892b44687546c3c521f1e4a53f140d5ce9b0a0bdc1eb572026e5fb2594a8a4a0ff22015f0c5f7e0307edb38ec6ff8caffe0332f848e1780b3fc0ea7f900b88c0fc267d070976779cc89ab7c8da7bc0d1fe23de01c78237c7bd3092b881d352936f01f70204f6d3af0948756263ef0b487ee30b133691581f0188ef239fc7df0ff0138909f364018f19ee302d81180208478d9349b5d3b4284a46895446682b3aabdf898c3789b1b0efb1f7ce5adcf3c10aee37738cbf7e0341f84cbf8139ff1341ce66bb88b0d7f7996abfcf694aff1ed4b7ee2b8879a14de42c15c6d9bac6a2ba255916c16e2c0db715c16c4b792b48a8880f856ed876fedcc161dcf5b28f8b48d254542952c92da352c1b398989cc04e769e3b88234da979d924282e30720881d3ef34200f1c38d771c00217604010449baab545a6f9c625dbc45188bf116618ebb5ffc9b2dc091bbd4a4f88c83a2a0e0f984a6f9169216918e123a52d454662a339599ca0c06115c8b1796af84b1ec2b610e16e0f842f88bafe130dec689f80ff8eb8170d8c77ce583f099dfe1453c10dfc0fff00e7c0fd7f127cef22ca7f9ec32debaccf7e0dc0360c6db7098af7197e73ce6b7bf3c0d1fe28d700ebc077c7b71d3707f96eb14d5e1871befd883546642282d4711a24891318c61d2ccd6501040b8ce0fa3ebdc185de747d7f1118fdb68f3011a9be857487e5554c924b11ef0c66dab16caafd8305d8eb07e4574f22b2446fcaac8036f2203f226b31f6f92d3e34d7456ac96e12d618cf39630c7dd32e1f6961350665036abc2cb92a295142b36ac8ec8f815110d8b8e21de44663233c931d1e9c09becb4c88cab1a48f3ad243ade71be559b2d756c1159579531b68a80709b65745925552ad7992d9507da13be956fd15a3ba79212ef743a9d4e27545b0b1b2e4e504e4e50505050ba1a2c2c8d56abd56ab54a7452b5129dbcc48e4a85e8b3f231f1619166618b27fde4a050a9542a9552d178d1c7ba54a8f03ccff3bcd5fe524ecd976635939ac99c30139f2e3cb89e2651c9ea3a2a747215c016365c984ca7d3e9742a6151e3a9cc88158da739ab90ceb6ff5cfce9a792556b4df2120b91583c29c96ca9ceed947088f92900811e18a8fdf0e17a06dcf8810042b058a2c2708654e776b8ecadf0c63a972d4a18db4eac6d85377674419233adf0e54587dd2d2dad3046fae7aa9d1ace345ad870018620188661283a0d576e42c5049f536dd264afdec81b79236fe48d3c3b9266a24f56edf875d9c8343ccff3bc8f858bf1e4d3a2e4c7d1b278f189d9529ddbb1b01a5e1d0b95a311f7c05535657baa42b2cf4363241d21d572126a2c73736418c32b58565452c6f716ca09cb64a5429542959c4c25921e95e080542b43af5604ae1ecaa0ea24b17599a683ee04f5cc4cdb34e80941a3c94db9596b7118dbb6bcd9bc6dd6da2025c7711cceb876ad8c2a80367c53a5b47706fbe25b6f252da594528adb706b507dd97a6d0e0edda9e40a726691d784131506187ab69d8d081b2d43cedde8cf467f72cfddb937efdc9b77eee5f1f0cdf8be982f2f560db21e0f2b210c7bfa159a34d7679e913f9e8f07e4616192d5bf206f080bf3e5a161dbc2981038a07b5e41d0bd200bf36a5e51253d34cc9757879a174451305d2e9830d5bd9a57545f54e6d561bea80926599b54a6a432a034a830aabf58d857033aeb5cd07d4a749f6c7633ccc92e95814e5d3061a057a72800f346c1cfdb5e94b02b45d954466554866f7e54845d6bbde3286b1957bb29dc22a27c87cd966108ffec8a31ae1e900b66a2fa720c873b6e5cc8337313c4406dce59e573afb5f7de7befbd4fcc28ecad17df99207cd4c2bc3a149cb5f77e37dfbb85bd6d26583c7e325ade72eeb6e59c73bed7d6ba6d9df781a1c86ddbb68921f8791d37da9e25e8d232b1e16bb1bd9636b79c849f9f273cc1094ec839df9b2f38da4637bba71d09b719b9e771dc10cf473f24fb0d1d671741bfe14d2ec540679fdbf32f8c79de0d6ff27867c57e3b2e77b9bb77cbf8861527613ab7e74867cbbdf65eaa8137bc014fd2daeab5cee9b40e413443eec64729b5b43ab6d4a9754ac780297da1e34b0c4f9acdadf5eb7534dc8b0dd27c8abf49ab98e7bef525867fd21ac45f87f3966d187bb130d5d7e9823d7fa09e2dd85516469a2eec1473fee56d04b7d2f994d2a75b0d2c7697baa913a3d3db1f8d55f5e3b073396fde03bdd51766593bf6b03863217c53a5c42a55ceb8b6a8635ae9a5597ce76cc10e45adf5ab5bb8486aad352b61669f99933067ad60c84e6424e426ecdd18e3cbc3e26b71deac1d92dd3ab67eb175ebd8ded891aee13ab56ef1d437e89b2ab44da7ff50b93a22f9f419359c109c564d275fe80b89e43535ebe89242b1a914a02829f9e9c4cd1f8d72aa53275fad1c643977e29e8bde72947794cd39a7f4f1e98f4c9c23a88cceb20f1db8fb7c1b4b931da0739bd3b134f9c61b706e1f9b7ae72a4a377034f9c69b3cce4a724e1d775e123d8bbe7db96d8e1d95b3e89be7b18403bd8d3f2eca270fd1f3c8e39dfb71f736feb85bc4efa5d3fb89a75a2828d4536349f7091027ee7d275f8e60dfd0f7bccd71e751df3ce5756399f24e94e58d2c4fb19c7bd6977aec54a71ca71cbb0936713af200e968727372eaa70df2007db5e3e42b5fad560eba2e7d6c9ac7cec7e7e8f83516ff8fbb3d107a53f7e734d471f295cff0e6f3d55882fe957587cdf43beadd865d857fcf0374130d731e79807e723cfeb81b1c5726ab9f5b45c95525f7c2580a7553b24ffe6d5b182bf193d7d492a7464c5fd26da247eaabb4dbe49c976a272fa9116ae444b44d7a9b3ec8a644164683689091faaad557e9c838931c512a79475492937d1d48a18882ca8ea04b2a851d545f4484a400723ca3eb9193d9914b7124dc66f4cdc191e2501997f243361f7f08c6d843f7c6f97d29069b6f1dde301e4f1bb6f8888cf1c867181b8d26379d73de8d2c20775f4a44a331d0477065b779e71ff7476070ee0c52a2fa2a3a815ba638f565c4068fd820f8754f659b9733498e232a59c5d0a9839ff8dd701efad78537174f12f4ae0b75d82238100c39ce7f705bf43a0211f42f8c851c47c3b10cd2028e338c7de3dd4ef788faba7753597d755e9de2749ddb178e8658a5865ec935b8a864f5ee535925695039939433c93c839679f526464357e8065da07b84fb83ea42710333e7e94bebf0b7f90fbdb5771e5a0a4349e16792aa6df342934e513901eda3702e11f374dddc02ed9fb667da5e6973f77a23689f94730a58da2a56f12679398e6329a1a6eb3aca745d1e8a360b9197bad0c31ec69b8771f6c08fca0011335bae73dec5f8f77d2468ffdb20c7a532b0add3166e9217ac607873b72dcd96eb52a262ba5cffde64b65c1605b6e53c1187e18dc719917318de5c16a0fd0e55eae7a68b074e97ebe18b221631de448cb3187e09b59aae3b4ed77516fb6e6ebabc385dae83afb75178e35d97eba3f0a68e5c78ba05b43c2807c3ad7b1ed5387bb1418d75ba6e89c443a742a150a77dafab50a51211e18dcbe701c9d914dedc6ddfe213cc4784cd6079529ebb9a274b79a8f22d3522d9d5672f36aab1435197eaf70ba9921476162f6f2391854c56e24c7a2bc9240fec427184f2296424e4d26eed5e9a8884bae04ba9177e5713bb24b85e8c71b771c8ed1c76bfd5beed7a3f9a265a0f95717faebd10187d57d42109bf23c25b077a39ef922d894d47e72eb143a78bb5de0c47e681244062822e09974b8ff7b5db74b958771deec2d829bb577abbbd0c96be6e3a8bf8b139cab161ba48315bf2d795906ecfa5f5e06c043dc3c9a07782ae0805327c37e9e73eade8ae7f2c54dbed3e505b2e447998249ab29872cb85a83f4d9775ef55266959d36549e7eeedec95c1cdc9c1567baad46889accbd66cedcaac2d2aba93dc406dff34c9cdb9574d72f3f05993dc20303b0f981e6f212859a7a207113ba223de1572677796afe6ec8fd6fedd2ec9d7157535d54f9b5c048dfaaed611d1b810db6b7dbadc7c7fda1041774788ee1036d2d5d5ba5a579ba1f00faec284a954e3fd29311876f5126b61d7715ad7cf9787dc9ffbc3c4fd1182a6dd9f1b050abb346a61282776f56b040a438d22129988e42e41441204110976170b2e639445bd0d02021a12a2b62b8fd89b53b2cbdd86b79cbb2de74cebde32c66e59ac8054e3152e0a050de69c6b2af63ccfd3da3f17307c9e949852f987b23d3bd6b5637d6895a4855e53bff0d35a77313d4ead7b26e71c776b1cfee1fcc3dfdadf5b282a59edcf143fb4fb6cb0ab776ed8d5bb5a258f10e10c04cf83781d5ec93d1a1c37ec54a35ec4977e18c39fab450b88fad0ce64d625b33a36c7bf857ad08605fe69318b162d5f6d68a88888a8e537965d803c68ce73f0537d05faf911b2aea04a06814e690ba8c1cfebb88db3d9516e760151df6d2f20eab9ebf75e8eb2bedfdbbed64ef2ba4b7873f7c8bf971953c5cf6b2afecf51bfd9d8d1f8b9a03edb7cd87616e5d8a7fdfac49dc24e183bce30764f4018d05641a31edb84cf837271acdd87471e944e7d83deb66dc326d020185e16681286e2b6e530f46f0644bdb5f92c75911b63e19879685b974751a70b575677fec140d4579bef37300259772bac3bf28395b65dcde2188681e98a8bd942c2bbdabb37bcb5f0b0a13010feb94736c73f2a5595412da7db320f2e5b56cd147544b3d6d56adb771b63ec3141942ad76d37effc78765ded72fefb7ad9116deed66e7c778ef78755bfef8dbece4d1bd46328aaab7a877faa903ac37e77e7f2658b519c2a85834439e09f4b13917cdf77fe72efd3a297979087123db7edf3a81cd3211838680a93ad082a4c0c08135a8fd98002a821a8942b590ba3d62944230000004000b315000018100a860463d1701ec6c1207314001379a05e624e9989c32c865190630821630808000000080060208900e8b725a57873c4c4886bba342115882659c47e2b26a328d7d90b29f989ea108343f931cc501291af150cc0c84cab2d261f704554a2178a54fd7e6450140962b6de94822266484574c29de4b54480c6cbf0e73d33a791577467d362d920daf114c7ef3fa78da125a60ca46e1a4c57e43d4fda75c79fe1cfea9bea52d8c117e5d142c77aae7d026088bc4109c4a7ed98906156a9e2639f277f26c46cf7d1a19f2055c6c085b24567c944c082ce016ebfa44b8c5253343219db62ae0163f266c872a9c604e976438f2217dec424588e854591cfd1f44739a119ac64f431a2155477a0531272dbc545df989dbe411363f714506a0d7c82fa8a20379c560ba40488dd75d4be622095224eb3cdfedda39b5b3ed5d6afdaf4d7fddbfe48df74384a8575391e45dfbe2a03dcad81633d56268749e45097a624608238a38acbedd018c75af687007e98da47bf520528d1ab77859c7106b2cd60433657f7dffdfe8dc60dbd87bce63ef0e673ff0dc8eeeb9951dbefadd96a0aad0c1bb77da05a3f824cb56f9bc90f1889c032a94460e42a1d1a982ac5908b9f47c1e4c756db4fce4f3836a4ce87dcbff9d1b14d7892f5a74a9eb918caae06394fd349eed36faa10a8ed24d39aa393bf494442e59a977518c51f388cb9a24b651f97c1640a350d010aa9a6492387ea82b1323fa9f7c35dc078e626e446391cc683c9d7af195c572d1f9e5af696c4f1f1551e867e7a21fe65eb252601462fecee1b50e642949626c2a1d5660a1db01ac264a973449d82f05a3e6c8ce03abd5af8e526cefedd9ad7fdb8d9df673d472b25c69ebf29fed3ba3781cf7d8c40df072f250cb7fd60eddfdf332817ca15bc7729ac0a0f112466852da5ceda9f42a206a6a6920b34d84a603558e94ab777b1ed4561f24e3eee2ced7b344c5e6dcf67ac09c415dc4bbf9ff7d643ca392ca1eea1bfb4d73c09f0b69d8d8e31c327715806fe6d4761d9de8e88184486ac1d8288190eeb5f808655ec1b9a8c8891823601ee9dcba51a7bac525351ccfacded5d3ba044bc884dd63a07064a9042e08ffbe120db37571263f2ba370346779846648b6d146e4d5f1d0e57ea691012bdee728d341c93bd3181610096439fd0b37eff99f8fd375170f9f38bc93e50a43a8ed9f6a18e7d0c807d659140b5a92350ae4d4ac623d1bf455c21c00ff8d402bccb8b3398ed73a01d1d394995e20b3ef5309a26ab35dfc8a8cd4cb702374b517c2fb039bffbe8a2a4f405074c8d750ac7a3e2fa796b9fe9a68ac7625dd503be4aab37ad50e322a2b73cd7cbd58c1401c6fdcf5f7a6c5f726ca919be670036d1f66dec59a9434f8b1155b2705713cfad4a0cef9a2cb6c6472808604a160fcd94367acfe2d6f55e8f6b834e08af15f53a11d690065099573266538a59ac73c7d7807f5b0af3404a06794c9fafbf7aa088ca749e11a04b8d6853c8643afe54f32eebb0869440a026cc26de8f856009fd50b50236557be33031b59d8e49d18b3d580d3fc5116aa1c61ee32746c62adddafeaa23f177f82e0bb99c35149a977257481801974a83f98b3a1a036c9101144404c11a51b8e0ce0bfb80e043bae5eec5df57235aa3bc768cced4c9f3d7fe124f498f0d7b3985aed42208c6ba66827d35cc08f081c5beb8584d76ca8e8cb4264787798bfc3b53873da0183c624d4047d1594158c39a39f3996457f98c7b5a566b1faca1853d3e1f7ff66d69502687f50b9eb7869f3802e0058d7d1fe258dc2973192f9cca9e7ff3653917a3e6ca36daa96a29a12572ba24d5ab9cf1c61209d41cb3300d4ca81c64c2d4c2b401803adbd45ecec2672043c7f536291db4182cbc3fdb2067c08ce179541914213038ebdb484225d8b568e0a6cf5d48fc628ced01e93680a94fb664d1228af2a11a8b5271362fe7dbe5496bc76b143c014aa9098210866ab7923f594b7b5ed1f8b0871887940ffd9bb523d11425867ca610f0ddc1cbc04ed5ab713e941c16df325c07ec8833d5fec2e2b2a3c052946015551b5e728b39a8582b7c58ce4827b28ec0e74773f628a0882b441fba320cce17cb0863bed03f599c5fc628da6e19ea023347d4095d0991f8c39d7542b907a5af95047d33bb64cffb1394c361512ab3c7afcdbdb0045db74c34cf6c6d6c9f2d6eee6db8ef9e5927838dd33944bec08f473bbff8c15cf6ebc6779867907cf09c1952b5690c2cfa39e0bf6fd64b5b4084cd55096bf8e202d5e86ec0364cd451821906ac6b6e3bb2970e36f51a35109d57207d5ac26d30def55e51569d6366ed4cbcd12501af1c4d2e88d029114f8b3fa3ee0ec8486b549440a417a0679bbb4e9864f1a1164bf41a55759ed051c7f2d8c1d18f65531232b2e960b4d29ca12cee7431980fd898cd85ccc8dbb76e68000494c50395c416176f32e3db3eb8f964fb2f9ba26bfeb4c6de0beb7f82c025a0e855275bf00eea2f88b6f5d9b4c5ac4eac83513411c403841a78c79fb4837be2ea447e7b5f50245690bb9eda8d672392d46f387b0551fc1c3782283e073748aa6c51da5f6acb29bf04670e3010dba9a69dd27a2924db0d6836731f71fd9f9e420e8aa9cb29362ef3bd4b93d34bb9e6b2e344a28b58347c39c02ea846162f134f1ce3583c13e18797231e1f6d4eb5b09d198fcd322a503e1afc06ae0689309953b978f564c49c1d3929441e4a447900d7f929adde0912b189a1e14094d30337ec2344b1ad6762046d325733a7b8ec3aa217581c739c39b423e591b557780e0668ceeea29af392fea211cd354765227a14b5d87954e6437ad41caf3e5e7d90bc9ba8f9c5d7057df8887aa4fe5d3432166aab4da54745b21e0583e885c7d4a3f0077b54168349503422d261e8e02a10f366148d0ab447495ece9939c0e11861f01160e112d2915fa84044e57d7491290136bb6a3b82757377a05fdecc97ab468566cba26495dab83ced143d6a2940621a4904ee5489e6f78d4776722cb5a35be41e0c64297113b1910e07c8f2843ade8ac5a25fc6ad1a1d848a9bac8ba6bb33b9f9f1d1ce17904a6bc76161825f0f20b1d4ac513184db52922bf48f44310a6e48c53c0173cd908322a9ee28ce5406b361a42b1b9527059f918dc75594ce192217fae4a59a97ea806801b89dc34bb5f92391703d842c15e8a08bbc9747ffec9b50ab698fec8edee091f00191dc07ecd1a793a0de93f7ddac2a7a252166373cef456b62158e8550f6f046eae243a9820329652f5438c09b7f28b4960de964c0ff56129499a47d38c72d566ed860612f6ed2523907e9af4b78b30a9a401ef33692e2c11ec3cc553fe2ab5ed92bbe4755c63ca0db33acecffea3b814321896b466336ca7c007cfe32362ac2cb6c5f7c39f16d00d25184847cdee79d6c606935ce239609c36c6916bbaf4c1b5e33cafd8a026db801672f92a9541b252a4a771689b03ed7b1d1a2616c888aaa45134e844c9e68ce828472610ea55a24a504430ed4bf45aba44379bb1c668a747a6ab49ce847e12a2671337032e876ae0a659d42731121b19a04a7f54875a025e18d9ccb38e93f8581e3210096176969b945f40128e4917a5c7a116ea1e9e30f4fcd181a3b5f7404d252e595ec3c8c7d5549ef024900236f369dbfb04e1fdbb0a60184c1a8be70f96f073c7bbf3af643cb859ccffae897c3f1192297a7d52bc4c85b69a91a0b48eb00ec5656f1c4fd7eeb08f8264feb4538ce220640dcbe68b620d318b12875ba58ef6772bac05b7d22a5e4f600f605725ede62df00db6494a923bf0c923191fc9a89aa8e4c0a88522f4fe44bdf35512e4fd1a7261a1f447a29d8f3dd72f5f59f68c075489543601aad20a1c7b851797b368895784e2b7c532e0c4db7d4a8242359419dac3577d804aa5f698fa18c7c7b1fc7553a197a6fa838b689f426123d1b011fe8702093248cb2d498a44acf98648d8dfc432693c8280f5a6a0e2970ed7d330984b69e0ac621f1e9a821d2ec12b502d47befa8076be5e2a7664cb03f65fda0aaabe94c20fa72b349f0fd01d619de03044a9947b64d820b8bfbae482a48827763a0c3973646c44d5e7d207662247424f5272753a807eadd47ca81ecf3b0b7d24790a36218f4a46009fe2135cf592105f84d32ba1d9f8d27a94f3c7024aac1e91a8d450389f0085cf5fe49dcbcd66ae74113dcdf6515108b206714394e586ccc594e7ac6ae9d65e6c54aee6acf332204e99983f21265fa87b042b33675c0c04b4e776cfb56d7f2cec04b6d577eb764a8608e3f5510b9654d625c71c9440c222675c1080afd09f97a542bbca80f7b4a9f9b9cf1c86fa0410ed44b7d6f6fd9fb2ed35a9f25c3541a82f9396f7170e62d52ca5baa04fd40d558374e2296520093bb6654d396c394b778d623578ee7d5cd7fa85388fc1e862abdce7e2a5cd8043e0070b464521473f6d67ebc50420ae91acfd217642be1c63cd212251d1072995538f4bc0e033ee305b2875bba2ab0307576a7db44a4fce5b2720ed0292dd9e836e0a8ed172cc026328467c13374534d4d066710b8c912f9484b964e3d6dba0512843c8b6f827dc7de454e34426f169596ccf7325a2880a6828377758d8a1b89aa27b8ca85960cc94ee20bd837e11c0b7c6fa4367866d42572e1dc17b5b7c600c8237607df58f2f12664c10ec8b2b3aaa077d2222685bcdcf2654a61fe7a91a8fdc4cdd640040122a8a435f612c00583188e2002f7a5d5417c9a72bafbc49aa413b627a036c35f9e2508c69aae2b0c44c834d5a826a6e9f9500523142095a95bb4a1254da8bfdf85d308243b4cc88f80b78b84964ce5fbb40f4f9348c6ea75f484940d455ab2ad123288a4cb9b88dfda689bf8d23778454ba672c8084dcbf8a42de34e2645327b4cc06499d79241cd13d7012f5d2e73b06a475515ecaeb93839558dfe08f6679c32c1cf8e5b6e282f01935fb72e1b961e5b329794e51777bd6c05a1449d45cf265a618525d5347e87936c0bd897c6c325140363eecb8251895f249881e2a935e3b36c66fdc8c6ec203c3ea2969c7c04a183905edf01b0cc81d82860361065e9c2e9c20bf293b013f498843de9319651a4721973e0032ac7c10c4483648786190820e6c86f9df930b67f0850e8d85586ac407444b02fa1c035964133ff9655ffdbc85b33ccb1bb5178501a8153a559ab24b4bbc15ae59e010c072e36cf62f226b370055335678cb8ce320da2715a0e9e349cb200853547e94edc267b89a6d7df86ec20eee350c6590246f8e5854901b901dc46161eafe93498c5b3f88f11a784da105f7a1990b823fd467a3e1e79f9fadd7586c9e4ef3cd18eee4827daca13d16a0db82db72d3c1463240556b0a1ad29a36531ee790e05ce7ef67c969468705777437f67794b021584418d46b1862f45ab676df15507049d2489bef261608504431294702c6b0244b6a5219df4d5aad45b1ac2e00dbc5bd743818152c88cc0f0a251ec1ecc12dd76a28ab9acce590848fcb3763079b3682a104ced29da98f098eab39629894613217a2b83bce2b3d67d3f082f00c7304a7b7f661c404bb8146021495531e0e403373ba22204d0a4bcc837dd544884b7562f1441b25693a4c0483ff0c8dd26e6cac74e0ecd26f58207b99062c8b2492f0210dacd5f976be0c429baa08a9dcb4448f4e9e74becf57eda7e45654515b4851717b6fc847753c1d65d87294c05127bc4fd4dee5a3a5ca5901bc72c057cea6f50b109f5c5edd1dfb8995b418cf8b62f56940154249ee52e928565ed18e5805549f1284945c73c05fce2959daa823cf09b7cb6281d8025e89e9f63184a280561163e58e19a226876d54e8786218e364c5399f543d9de66e30ec6096c51844b64bd25ec2173c20f1c6148546193bd5c4b612e56832978a92b112d0d2698474c810d75066bbc22466f4e1b02c64d046d4018baf3c4b97e13a1b063e1b52fc6974e04601140dbf68084c304e70bdc5c34487761d0fe60c53dd164c97abdcb42978c1c4b118ffe0d87d52538d9b3660eb1b20d3ff439a207f42c6d6944017fa42513ed0aed2fcb2833b27ac36ff105acf38afb61bd2ee55bc86f6bd01a3db7bde50cfc95b1a7c5d869f65293431ea5a4ee400c374414547caa085a1a73ea1ed58fd425c29addc1b2d0851eab7eeff217d04418cc7f8b5f04bb5a0aa8bb83604e2918e2a20b78b103f50fd23838d084894d2872c812898a61553e3bbfcc305fe32db49d5b326525c231ce687e8fbd9352aee08c5869b63a7b64028cd71aea8c692a2a866224e3466f30863a51485322853c31c89a7f8f65360fd9a38510da9139f1c3a2c3aef2c1ab292a5d11a65e48755eb6061e049f04f2dd630fdb7d658936a576f1fce6502dc1ccb0a072b4077139cc3ebd8e99ec8b951587c65aa109c46bc8b62db878913308eeeac5f8899a886e5a37c904fe2e75110e88ec9b4cb88a2c429a86c8f5587c7d5a7f10ae92b1ed45c7a6f0ac85f492a44ee508593647b8c634cd2a01fbf314b330ab9315be92a858cf041e1db8938802836f9022290361404407a77b08096ae73837712515b36dbb756e2bb8b5f5fc45460e0f0cf0dd647d998ebf5e5535c19984fd76b32d2479eaebc102c471e98bc894b4e9260615a0481941fabecc6ab72601a943fd60855b995218c3c63622ad309c387f08e8e7aea9cf3861337242c534ee50a631fa675b8e7d97f6e21e8b31a3c51728234ca7ea715c2a2dd15199b4909f6503be11d8fef899740f6942c3383465c620c2f4e463cb256104957fd80837da23185e60216a492aef66fcb237659f006b1f5bc16c85d75e9ff4b457a0b7d8052f94b6d0d7bdd4894d67f03898b9116ee67060de33a253ef247ec41c18dec12cafd763146e961f35f070418e4e958068743cfe32e1a65b3ea73a40ff5f50e05cf71240067cf81c8e532d7f7f7c93e21297ce1171cf4a83d30415dbfcfab7709c42da6fa995c2cca900425a2534a1df31408129149785e581f54addecc34c7478bc5cdeadb8b18e15670a308ab05550fafdaa00efc4ec097b5052b1bf8109f6da3bc0f051b41991a06e372ce758aff33aba382fac0eac225aba9f51a43534652766c26f18f9c9fc0971395b884eff561d9300055a637a6226cebac2a1384398970c44c792a7e7bb789b935955237041ac79b1ff6206d1be026cd70088fed4d57edc9de316d72c21011e49d6685fc68c475848587fc15960f83c0a85d2c971db7d841d87e18778522eb54e223310e40e2fd957700e8451d33a72928a188899790ee1127f6351661cf44eed6c4d6c381aba1907ee9a351b3e1595dbacceac4e2a05a976c7a85658bf7bd514c668a66850d7c94eb2b612acf5fba4763192172daed2ed52c0c6127507f40ca9b4c6c49836c04fbc48c11b14f9ed75276d3d8f76d5c404cab925f55720a6781cba17f7ef6414169151b37fe0c35960b42d101daad27c2e0db599de84e08cc6cfc505f9ccc5144a460f53e476302447cd4e585ee6646af6eb5ac6895b8cf1baab6719a12f5bc10890dff2f54ccdc2e3c97016f50a80c84ccdf8b13efc20d5ec835fbdfbc1cedfc28df6b2dacc9a47975270d555a36396e01ec6a0302c03686b26f19f9120b4a9e80bdcbddd2724227e2d54cf2d4258bc84f21e38e9148a4139d6e3ee9cd83e961c225767b410524d9565d53529354c33ed56eeb8460450158c0f1493839d6714136d190130021f03ba3aa198a352bfb23563afbd085291162fdab1a11e08df1746c1642fb0d46a196af98e3a738cf87cd6f4131638daad1a7c0313698301c1d56405710655cd1dd7c03ce908d70e92cdf3c180f36606df3180131c1ec5dd24da022f232931be2c54b8f89a786efe31effcba28620c5350e84dca343240469ca0b1191c8466921c54cec04e249bd5c204f27b8490c10867116fe5d2c2429c32daac66db2c3fc1a53cc767d32994a0f2b9e65311ea9b3aecd36b6b72f2c5e59e28614e3c5cbdb0dc235d83baf7733d400d9dbfd147f7aecbc4fe24cba699e12bbb85be18826ee672d203b20c34eb80cc10ba129f50f9ca6a1d47ee2bc1e408981599f7074da29b3dcbe111e15801bf741a724524f7a39b4d7a455fef1d3c9244f9d0cd2e45b78dc35ff430ba99d5cb034c63de22d0bae3caf8675d582516850674338f332b172c6e4291335ebf0ae256b3e1de6c6ab724fcecb7c5760e0704ceabcb30f8481b4753de0b7ba1ed5eb74e3bb6bb44eeaec0ae1579b1a371684093b05e7691862005eac25486aadf6cf4e8738a3d9faa978bc884eb37832f6d49ff1d3c008713d9d32e966cb9d1fd823d4fb754fc8b2c4c20ed0bd2efc6e10ac0bc94c4f019064839477667d664ae68cb70adbffbbc37a541559bcd5ce7f4b68f9cb142ed368930586377b4e70ee345766751978533968deb94851e5be81ff3264340e6396f9fbf6e5bc75540936abdf914dc0ea020f5b3f0d657159bdd3926df657539d03489f02d512b0f5c8f60d7998d0cb745bd7f096d5ecca93714e347851f98eb1d7c76b683da190b6fc69b485a7d794523b08dcece36d812656d6a67f21d0bf917628430a815e9000008f9c78539cc3055f80d4960b34e446e7c5037d9d4b2d930b891dc3d7bee0610299eb6cb2452233fc2963cef233547b5b4a28514bd7091d6153526efb118eb4ee0a9f4daeb9c1f1bc6858582fb92ccc8118b1567044e48d0083b1cc75e8d24cbcf687aa3afd6cbda9d6e177c4a374353a455ef5638030469de2d1ff332674aa6cfe2e5dee6b575b13ed6eb5f4c054789be7385c604dfade01ce6e040e18b5fc4488fcadb362cbefc89ad37aeb24a13b9a850f5e3b802406ebb43e0c4ccf0369584e047ab38bedc9b2c1355c1f1990251f1dc9ed662cdca6bdaad361a2f48169e008affcf8a982c1e88550bae36a51f6b8464884a61090ee78b21c5495d9621380dd25415e114693149eca6c1e5d1d79123cfa365935f6211ec4966545757c9d150fbae64c0b85887119c783856df1445ab01b149db8a3f4c3b2be75bd0708dd7c6acdc3a14449e5549e40569db5280bb35ca1de35aa2388f47205a2c03c021e95249e8fb61bdcdfc1a87412ac1642dba4b2c86ea7cfd622cb84ed302980d9ee061a925a6c54bfa047ca4929b7654f12c665e4d4a4db7852ef7322b1c4b253c0d5cc6af8a0d5a1833d0540851f35dae762a5f6e610c155e4756ee4f59c6589075b905265cab56f94ede6fffba691eeca41fc8c792e1c35a94a7a8101bbae9341c66740b8cf8a6a84fd7031ae16840c8df5d3ea64b746a55a2ef9ac9761bb2e3fa855ae0428ccc27c66a40e20b9bb5781aac7e67d9b75ce4f4a2d9f95680f9b421c563f05a3cf39eb6a1e3bb26dfd30a94eb7636820b4ea1d4873a36d370de375fe65991f4afb517ef1967d37b1aa92523f92de1e9a1fae00e810a691eb55cac8d9e2fd33f0e85db53fe4fe3348f92c0831505d3e8c82092bb9f9cba5ab0498759449be6f1a77dbbf8f163c524f36455677fd7bb04643732ebc0dd934129c50320feb4ef53ee026deb15ecbde252c89c78c479264a1f07e97ad16989bb14cc3b8b0faf7df44890a04a79e1870f4ee111787787e51c5000b10b12dd6ff12d5438072a17b66d771812bdbaeb7b7c4011f24dd2992451f42c4cdd4bb20bc3f72d08ac528068b7a1a0eac9743cbef6519223064a5deaf2789acaac87d3887db22112c3fef9d2008d14285e01ab192934551998dc1ff6be36322a93bbf53c7cda54c01b60eff77194a921bc3d0682a6d215938243469f0508a3ba0f455c7f79f58756ca948702cb9ca5b7f2dc5814e679c3fe020599e7872fa20e58db2950811a6ea29e8d27a3dfcbe0c595a69dd9f39251b3d4d94b8393b4c51d138474579af28000a84fa935851da890023b389a9091a94b8da7c13e5867f8cc69ed781aeea6339f76c88feab8c7d35e82bff19d20110a3d30c6d3e6ae50369b734e399ee6d5da1f41c4f0e5b02f49a3616df18108da3f71722c5d1ab874d9c388f5c564d8865fe03a354f93020fd62908728dd4a5ff338f7fd316a489de0b447eb6d1be547a9a82284373113febdd7f4a94fb31678e58359b1b2daa86bca7ad899da22266cf3dfd52ffdf5869930962b7d7947a8c86d211346778d8c06743b5952bfdf9e403080995ef69be8b1c7d0437f9cfc3dab4936732a9453eadd2b84455e0d45db953355a867d8fc247c52d747ad13ce7fb219fb63dfc2bf104e530047c47e1f8eec9b6e3c3a68360d67146889f96c5dd5bcaf94460bb40425681d581cafbfe5ee87cf7828917e1c758870f632df3be9b8d5479e2b1c7f20b392286c0eabc0419363bfae6647718d2ffac0c4ffbd336b8bcd79ee8bd8c8692a2d98f11a048613e97c54e1ade3a5a26b04a574bf3da0e5c335c1c6a60e3c62b0e49ce88de4f6c995c1903ce1f648d691cb0798fba49ebe16a95f0854b7f940366a2764699b84d9e878d65f10d67282fad98152559a36956ad7802f0e093a3d454d90dfe0108b41d54bc8183c66a14e3d7d486d71155c1272f2c8781d2a5525292156f6093809794ab44fa49cc087ad0c8d4fb5ad857a1daf09d6f8a0ae35a7a6e6fd28307e84ffbdbb0d6dfd205b85efa5b60804d152ed09ad54aa7576fa7c89beef36e16094d1a5324c4632c34a7fd49413084501bebd73d829abe3270b0c85c03327261314abbca0e23b6f1ba96a37db5e80575731405f9473ff0d86da4be005dd7e7283600b4c8dd48b76c62672e0663a3d8ac7e26867b150d36f086c9438d3e3e6cf9b2aeb997616a5eb013e4856c7577800395d9821f13abd075c0624491b1b07a9da32e8c4ec73680eea6a3861cb2a2c31e013ec6ff245764eac7bd588c2c2115614d8c7c344454dff32b44342202ccfd1d8a9e9cc5c99aadc2edda91d36027165c16697e1918139eed1e92dec63b29c5fa9bff0785b5a0736b057e98b75e5050103a54a50bff03bb74cf79c6ec81a37189be82f4431f3f11021862fdc8543f1b6066bf54564915bcc2c811e8a43de8a82e9def5937c28892c66d46c990470f31eb86391ac40fe7e83b706095c83ed1257899a66e6d1908991725a32b6db123b559d719b7cc60dcc01d39b6c8755f57c63178e1fadacef0e22843d4bf1eb2364fdd9e7150d04bd5ed4b8e4f3a7d8515400f778d0d638c4f0c5e88668afb23b49bd723531f031d3cc3564665b70ca005a20dbab6c7bf179a6b18db95b7ca377705c3054417b085ccad37cdf29174aa3bd64f246db42554654051a3fdf6fa62b9105b284226d15862e4f2a273b96a40556f372599badcf1a9fb35a876eda84f1d9edb1818999dda03fe1863cd0796dd78db445e584dad7287971ef865bcfd8526bd36e8b4ac93174c8842e0cdebd8a77fd5947607d6c305f3a58019e81aace9326a58c5fea9eff5d35e89faf239f7dd334bbf5e29119e321017bac64c7c8cbefd26bb2a45e13d8f6fb8345408dc266a62b4225588bd2fc0e9e68faae163caf00fe2b8e478108bc262f4d4567300d8a3c35063af53af1826b7c187790dd5856fa702de9d40c0e073b0286ab10fa2bc7b7c5f826bae9a66403dfc67bda185d591c340a8a2ff5536a6d4aab9db075bf316013a73ffb824f9f2574f1094df292162059a7b16b8308e929ce0b307509a008eba572b106159e5c5edb61449cf4d88838e2a13b561fb46ac8d3145d92e0584cf1f02a26091c5de12cfaf989a96944e2c748b902727d80de3959c24c75e9b35258abc139ca45d3c574d7bb8db6df9b6290936d94a6f85fc15d39fb49977c4ba5edeb40b0d0dcd1f549cdee1488f516b05c8c33686f43d32e8571df83257450237cc532e5806d31b0423b5c440f0cb25a30099d96b59f02253825278619d4e0a5243f238af7347d9f936d3044e6aa1a02076b11d8f636198ab95aa09a68cc950e6b9bd511f2645b3de8e887bc32d8550b31e42e38c18ed52ea1c54ffc663fee564d668fffd9fe206f609e061488e20c3467a6fbd012f3385c6a2cd77d5c271e97d2b6b8aa7e85551d1b3aeb9de2e864b07c62e5362ba0bb4d6aea729aaeb3a897537005ab489ee2922ca6dddfc59b3b4fbb49b17542bdd64d74a6303fa99fe2f6c99163038ee1d94ee36c769ea45de5d759ef1f096c9fa8a4f745617bfa821260437121be264d26a65594dab5fe3c27a5f4d4644655f2ed89e8dc7ae2788ab9c13523587172451cfe2fae9ab1d040be18a251c043f7428e38286c2fa0ba2f36e54bf7b17aff9af64acd75e219cea46d1b59e5f8c3b70870873e69ccb70ed0699874da707139d8bedd1dbd700c04f85734483acb5c1f94110af9824698663bd1a880ea5f49b67949c91d80bd74c20f483c5f99b9d4a6d1a08337a6b833c9ca87b8909e4ea03a286e2d0fa53da0f1228ae98b2818e585f3e8570dcf67939ad57a94d04f5000e1a44cf3013633924df6e908f3b0c1166384c411eee50362c2e94fd691a8a9518be9afeea32b4d9d67fe1e33fd859d5937e82769cceae5613ca4f74d9f7763fa271e199b8fa736b68a687a41286fa54d0904f6157844f6666879271a1ad536eb6a8009f8c177b3252682c2e2b4ce9269f8ca7ae41573b2fc0448e6bd4520e144c48eec75ac28595835d24a768ffb1fcdbc491502df0cefe1091ca460ab40d5e891d3406685f8e39d1eebdf109cc88501015e9eff8066f6737a4c27f26c700273ba8610fcb6940db0169367b0f714656dadfef632172ea8c94b3ad7dab1ceb1364cc4e108ea8efdb5da343deffba442324386195cac755d82a7b1af71f8e9b6de1469da42aa5f161cacddba08c4bc5f675b5a48b1f01896875fc538d73f61d0cbc718942e462b4b04e2837e8b857db74db0846cf491ed16aac27a8c832ff5d060daaeaf1b60e2c4f4c887c66781634e9f840eadf2fe07b7248a39008fd13ebbb4f7ebbc4eb6771e75e51912fe31718807ce14bf0e1d5fc32d0b44afc1195fb003e3cae43cba5eb7082826ec708be1231952547bd9713e7fa4a141a360fd28164097d9475be19830f148439eea23cff0fb87af390884896d021e8bca12774859b612c34ef7715f0c8a0ab7295190587129842081c202c6dfbd707a15c2c622293123431d1e82b1899c487c70a23b4f5b82b51e29889d23cd9ca3cee6c57c32a39d0716844720dccbd5c709198bedae4e26659430087bc1a84e9a8d24d98a7b199644a145137f5a08913bb9632e637a29b450983ddf675f428566664664d8587f7cdf454fa17003694584430cae9d11fb8763b09a5353ec15420debd4fbdd865bbf32a9a8dfc5484514ad46d012904024a474baf5b953b46d98d716ad3251908d2af136bb73d8b7ce69398ad4cd46e6ec03d1c1f468e2f53e95233d4408b0446861690a27a5916f81033f110ec86e46129f836d22406a25d38841a685c445f0355f3b414b35fd24b968e059b25db076c3b42298989268cc48e3c434cd96f83253630d5eee09c5d1ff02f673b5339d00b6a1b1f775e5cd2862394f9d77d98c946933409db976d07e35374a4f84cfd9611c3ddf26c0c87b1cac136b2fc42982b67918868e3162289bfcec0b9103fc5a0b3d5e21bd017e4020b077a03541831e478c1a491788e54395d665086fdf99cd2980f07e66813161ff19b2db84fb3dd5434d4954ba6fd6a01d48497317bb1e5997a2f39b128a22dddae46fbb10087a996eb7a84d60c9deafa8539c3a5b889d661882125c8a7bbc8036adff147677e095577b963018f53d1e334d8ed2391d83684a0730f460efba2b37d9bf7a2e46b643e26eb9779a3a5929bccbc5903627cfc9a8d45436e3438871b90a2bbe205df96f65a5ef820852c3ef31de9cdabb7ed12b0a81ff2f2812e41aea340811d082e7ba086f87ee74e9cd34cb905b720b267486b6a1d33fe9300a9c566d2b1ab409e05ad014c7e64af3fbde8d614fbadded916fad91c93f649816fac91d0d8b0488c7d381986a570b476b17588fdd12f9c8ae50180416db19b6cd7407520c209e40e5209df4c6bcc51503366ab61592030fd77deaf3db847c580283e82c8e6fb6e287768361a8fe6c570a5a8d2ac0157dc827c6873cdbddc484c5823665781351070cb23520bd1f35b720244d2368ea0ef966d48d15eed7bcb301c4d2288056c348b11d52b8d7e2746d497409f4a10b18c1c68904ce23855746802d373e581e3999af80e5941f51ef3edff2ba1dbd24d632df0c4882e66d63793328ff672a70c1075eb617ccd4b4302d8c770d7d14fc3b242d3888f0369947689aa0bdd5ed7656c6211bc041c99935c8c2d0248bd6b7e9e55ae1a906011158d1101899c81f4073c2314311458905a68edd364d5a95dd44ecbf2a730a28dd309011b6e538a890690a0dce6af86cff445f4f25be4bde20e415f224961ddc705abd4c9751114bf2eb1734ec09a5573bccd15d175f90deb48b0118f2a4042b8ab382ad75cf3bc050ad7257d1b1a72b61d2909f77f56cf7e5d2101d7769ddf8ba559f4973110a4ba7b188a0cbc7d47ff2c9b16883de25105a846817ed5d104a6ba58fc4dfa615cacc12b174756cbc81dd1cf3a930064b300ea30ccebc75651d42194585336beea28b3b8a007405f75d6d8afb1d781187a939f75ee619e09ceeffe33b922be4657777000bf345fb40fd64ab033385b39dbe574cc1e2b11b411d587ad2cbed5b2ee20927957f4d0c5b72912612dfd7252bb18c6d9aec00f6e4b8058a1e7bdb6e78dbec1b0b56ef14bbd54b707614a57547564de5c487319a5c7d022df40bcc745c83ffbbef3b4d74f420d337cc135b6528027fdaa7f5396217acaf98d6521f26002c3d82ce0125fdd83b0fcaa7ca887be105d4220bddb9c6feef6fe95ddf47a6e621ca6c7f6e6dbdddebf52377de7f69cf9ee8b37e04ec555578d8105f74bdc2de3250326efd08cb0d3eb5bd939dd9c09f6bc56c9dba10f8206c1e838762b60bbefe14425a2d8d7963193155f7bbab862fb1b66c7d576d58ec311b9ed5c64fbd106a009f7c2c0e00dd4a4262ad068f070ece40154abdf79b6c33760dddf29de892e78f0c0cf89122fe5f8e5f330e6cc3f767572d88b818f1b37e1b09873cdcce7775703274f4532d465b731a3b050f891f89708126ebeed853b3f8e1245c317b13f3c44de3442a204de861b2743074d4bfce272007ea4006654f7a80ff7663fe545f4d049946ca862997808f6ec7a79baf325a9d454fe076553c7747a7311d7f57a1efe817bb556c664eeb1806a6db3b3fc0b77901e58e9ca4b32c4d697e3f8b1997221363a16f6b73c3635fa32676268444a407074d770cbf3bf245fbd18a8a97eb3b2e0f8b487563be6dadb482f0e42ed18159e87d26b6069185bb86f0e41f43fd14006d082c712d62fa30446afe5081718fd9423b2ac1a7d09264a07c4e6ae3f555e8920043f65fb9f747d0860a7169704efac6caaa73166e3bb3395c2ed2660aec8e5ffcae4911a3e2485f467f5c2f5abd8e14a0cd6edf84a9ed85c83a56a8e0e6acce832d08e487103417a8da326c6c894ed7cf6a7c7e8828228b9873d324e7105b29d6fcb58c6b6f55a2d5b0b5fd4610bd09dc4afc628ae487905b6f1399afd1312f77c7db5a7fe0d1f587b9350438618b89a570bc48081f23aa6479cebe1eb98c92a7bb7c26696076ead07f0bcb3ec3ec1faaa2e3ea1708c9a9515ababf102d8b05b6113aed60059116e3b6ab5ae33d044626c4e625ac0aa7fd9c96ff0a1dc50fb525965fa287538ff8e489f89eea0717fb28f09ac01070a03981bd56b341d2d696548da4c74506eef259d6161f0177a1543d9515b269e82258aee81cf88691445d439daef8a32b045d65ae6e9ac9bff92ff98b2dabf2b60e6c00d52fc2e1e44ce67099df26e3a88f1ed2a4de692187882a563083f3ad34506d2ffe403a4dac660b4c4fd0cf1e43bb69a7e013111bb0f935c209dbf2381c5b06628de24d84d294d02ddba96a6c3d523175dd7d1ff2ee9ca2cfd2c4db7e6e9ef6aa2517705f618fd26d19387ef95c45ecc0acbd9d890095627b14f6f5ea0fb893d7616eab7d7a72f47ce95567bf0a845d2406827be22943e35cdcd6c7efb8de9465ca59f529de24e4ebf82206d8f620c0b9ad814013067ba7ae1ba29b2c961905f868a8f880639308d675abed719af4310f1ea5912e32596fe99bdd21ed45a89aa4dd51484a9640d68e2d029c5d3d024d18ede06b404df46e986561511cc1cc033bccfcfff42be851c7a55fc9f2644afa63133d8b356ecf29cfafa3b7031f44a808568ddc4d2cbff8bdc33f161a0b7eab7262ca347da60db4c4d3f4fa59cdecacc81f74a37922f030e04d125bbb515088f6ece051eec915168dbc5d658caf86f73163024b35da1233fb742a8d1e99c883590f796a1e3db5dedc2f3538c2056d314db742547d7241531ec5ed2bc422c922420b69b49c68c0ca025cb022a202a1d07d74e7defe41ed07b3df12dfa27bbe50d6a64d343fd6c6151d8359fe451803bc909e0090fce265d56f91f1d8e56818d6bfa5f8b4039cdb017a338829c73a3585bb9f331204f65d9b256a852c22df95f045309faa0f9fd90ebb358f6f2a3a4442dd85c78b582c609ae23dd2509cf71b88741fce19350c1f24c76b5af81130e68bef271aa2d98063c154c4c77c6c76aec8c00e1d4e97373141c3ad17ec675624ed971510a17cecc2f9213b345170c3beb5e43d31e00019ff7cbbf068b2207dbdcaf0e39174429df8c61922592f543750b888cdbd5758228ccc5606b7829ac93a4272aff0f923db3e6a7463a6a8273a97a3e21c2512939816ed0fc7276845f00d2bcf55fd657f510ea240adf1353372a1b83e8602c5d2f12d021e7a68ce12e80e01b65d50841e4bf2473157c58f441db197a915927f79767aa95e4e7e8ae2c9aeee7a6dafc3d962fee5b05eac90e4905fea36a245f47525c4472ac46ab57b7f1aec75e43fd1903c964eee33aa069c23b51c326455b966d5c3104bcae5b13e6632d685b87551171e1400db7ab12fbc6d231999d6bd6ac5a67a20005699479fe744db024c4603d0f6183a1dfcad0968df0d407d3a0df2544761c2006709cd3123fe21a449380fe972a116862cfd72aa8e58ab9c811a95536a99a748200dbfdb584741d0029415130e69cbcc6d099b8c47b86898256d7532543d774c61a7dcac6eeb037458832b4eb248a30e66aeeab0038a4766fae4aab583148f2f94d3a91af9be44548e8564b80822d2260224fe9a6776690be08930763c9ee738b469fa57a3ec5e929fa3a84c4fac245f232827539aacb1ea5d04d1059d466612242dc583947019917a52c0d45eb0f0abcf393ca05e893db24d7a6558392ea4e89139c2761c88093f7c9c443f4501b49755a029ee00c396322ef0485fe66466856052ef3d822a42e4e728d5cc71a73194317d3072785c604d0b8fcfdae148dc4beff03b1c9c1a44198fb73506cab82a6df2d96cde72cb3dbcfe18b29b71c5c474d7e89b20cb8003ec7e92921a8236d8a70fd84a7f46a095858221718ae5452e435907e6108c093baf4608161e931eaa4e127aaffbd63943b8fbf7906dd5fee9fffa85f46fea3157fe226c4eeadf41592e961f73917b401cd7920fcaada7eb3bf1bfbc6b26617dcfad13fb563a690046577a2398b1d0d728ac8a71644c84942d244189cee18f92c002317ee207599f5a1d6a0aefba0dfe6b971e1b3600f7bd2c217df0c48c1dc8fdaea1609e7bc410b86870aaa3785c19f39989047a8ef673cdf84a2b6724cae03b38c95d222a8a1b1d1f9ed80a117b34abfe8c9a6947ef676a1f5b4a568a76c17835614c7b88b16e5234b6cc3a46e7a7ce4e63799315e460605865ea298bf977fa04967e424236876d510815da30225a26f5560c0588a5eeed92b0d49b8bc42c75c4a9f8eec989a1664f7f192e96438b97f978d8a11e4f690f2e30ea55d265a72c15e45af09b22f74690b27bc9ee5492eaad526cd4e510439bef149c30ced2d2fe75e3352a7c45c59970f8a6ab007445442cc43784282181a684a4412838b06e885fe656861c209aa3c7890fcacc94f66cebb1a6181bf5b64935e86eaa5e6c7edb0f6ff73f9cad063989ee7ddce338b5013a5a8c9c8e4d864c464c4448c67a00c3d3eb393a4fd8763ddf277e6b4782a98ea858ae6a9847d474c04e00aca8f7456f642730f0bf3165cf46a8e7e0d3ac768ac1031c888542e5ef352ff10169fedfa18d0c7d2d53ff157ac6bfb440527c6df4d022f96336319daec5cc7c94d75a41b4365e9494cb296a199076953bee0c6335618e290a901f403a36297315ae91d74d961ba70a30ccb1918ebfc41e0c65cdbaecf2c6d57d5ba5ad845ecf32ccbd00b02abcf3f3044aa98f74b5830b34bb8be944dd079188365126a3651201c5515e3890ea9dead38a570afbfe9ac38da1128b33655a1071ae7d7985a4af83e0fba8128431719d7074fff89ed4b83ba8f8ca93ac9e30bd7a4282121bd5c753941505c3fb83a2c77588d64bf38c27d2ee98f40d8e01f899f9e19b8c357938b08e11b1916407045aa378381c6da4cf0465e20969de150c2384c174d2bec1270fea7d7706e0c260ee13a2a8896ae1e27c13b9e8c1ffe4786ba4f053374296401e5ae7f35adc7df0547c41131d76503dea41d5507ea9e9ac68dc4734d064c6ead31c37cfc35ddacc483619f113581a2b542a68fd5b290ec4aa30639f0ddcc860844e8de0c8faf62025fee14335723d186313216c4777828336763577557b2fa564752dbc7f77f79f5d81781734f26f403bc448e5873455a4e8730552e9a1a1058ca966d28c7bc54efc54d948edaf6b8e116c6de8f028a5a075a3b13e5b0ad30c919fa638454ce180f422742ab95c13381c3ec7209258079e6c7aec7e5807326189448d9c3d04b9622769c9ae27e9fb8c9d94f7bda6f3531cb9a750ef503d2c4c2a4b4d2566a015d90610c0367e8a98d2ceb32025ba6e71c175cbf0e3d107e19aae64c3adc94ed193052bb9c7e4157e9d040ca43ea7b2fe01ad9f578a5a5f6fea56e496efc62055fbafe0308375199a5b179f37e50b1010cad25fa175d5b692b3643da0f59a96a9c9e33d9688f4ed142f903146211a973fa8414daab85c5066d4175d3285f3dd7937d303eef8cdf89305cf78372c244a42ef3e5a706c9740856a02c1ea8423239fe1a74c8c5c7b30a24b85636f4807c0afe4cb7ce6ee2d29408edaa2a8a5560a6bd0c3de706f6643a6cd3b07310a61c2a1c4902b33e39454749955266e32e6c130e8af9f5f427d0a090a08fdb049b122e2e09fadba0179634b01b44d0cad0e4d1b1f9585d753c98ff90d1271671bed9f7ca5705cd4db19262194ac7d561d2211679e77b19aa5b761ddd853a170f7245df758ced5ac521eca28dc049474e84e33c7da8f4d497c2118fa283aa9e3dc37a4a951b8e1df183442724179fb7836c0ac2b43cd08f1baca656cf4cb6ea46901d79780a9961f0c41819f43b6a5e141c8a6c129380146461535681e1a5326570b978a832f4d2627ad4e44369f26dccf44541053f73688a3df24ad27109132849e2e81056349184b675688080a41d3c26b869db3d188c5f2109d03dd2b89915f8b336ec84fdbfa3d63e32f4af8223b18cab73d8adfdc4ac2558b37f906b3a596344197adb3b286b53828312b76451e93bd1d43b952db7e479917d4c06e9bdcdb16e54fad3ad3e198aee8b2bb2202fb19cab8dffbbb311b372217ca8d9adc9be387e5b878d6bbae955865263487b718f5535a6e0eb9d1cb2c5ec851f6e197a10ea167b53da6719b77f7bc103c678a90e06a89e6166d88bcf84b5a07130c87729ecd778dd51c0daa8a0d1f204a2228d11435c7fec4f20c8090a546c76db556b1bebe2c003052a8452f95713331228d0e1890271b1fb01cb50f4280ac4b64781cef59e78427ab4776544ff5952226d2f09f4b6f8b70824e9a8432da1d39c22a4c25e344cafba270194149873335a42a02746b0af4689217db81a854246736ad49886a1a35752aee4085e69a115b9f9760ca51563503cf7068e71c207427cde2af7c8ddfa535426070e30cb9a0ffd4037d3108dac5ccebd069f927a4e2fd02643d94409f34c76daa7af332466ae0f4b680c4b70c42ab3f7f10ecc2e099b87b2f27a610d7433413407cd5847d4e958c9b3566ad3615be86b0751c643eb68c0a25808555b0fea2c6514a1e04c467ac074dca950b1fa9f1131131f24ed052645b6472811984a9c92961ce7293294413e52a30c3565416b97cf4243248a2d114d0b2d0ed4f43b2e1455000505bdeb356b9da9d8840e81ffa1fd6977bffc0b1e0118793909a99261093abd52630a0e61c8c781e653dde6d40b88f139dc18c4f89cbe31a97f229057a9180e780293eb99a73328d66db6681941fb3183027989814fa4a061df4851831b82530638de087eba505150945b6bd5d3927186925d765870ee5adef965c7e28db57f04839dffe11646ca1dd8878cc794de60b2146b2d9db029d79a83db2bb1112567f5969a704456e249c2864bf20c9e883fad74f6139bd8cfb84f4dfc0cbd0af46295945fb91801226a46255295a0a0ca40f3f21fd5de1d7d079730fdc899ea207b95bd4ad30609c9a2235fe490d4d1b685ff03163a9862e4f2e9ab051c65562fc64e983c1986374baa03b374cce8c7b020b0d19dcab6f684f026f851688be58982c84758ab088e4d9305fa3f50242419f158034471b1014f7caa3afa704ce800b2dc184029fd6698179a65f30cfb8393099463f8e43084d75626dd687b49f30c7638c06101a2566f8817d2fb5eb42a1fdd4323bd5d21ba38eb19f922468ff6b2ba1b4e3b5d48316f5c93766a9316727983f7199e7ce1c863d5a7afd9538c195163b7268d2ac755d7f18ac9c9e2eb0fd9f9dec40bdead6429067c21dae6fde1a2a4f325ed34e985d66195e800059b9afee5198999f24906d9c378799f54c00c936145cb62be233a0b1f9e14399f8a2aef88ea16ea0f158df130ddaef4f647941b934563da9df4134aa7fd47d8eea382f22e797eae5e6ae6a3018d9ee7929e0e33cf105e4156df1b015d08a8424a95cdadda4cfbb611a1fda532bc6d1def195a690f4f17955f9f419959103260d8d182b360c0b31e2de1cffccfe3cb04dc7191c4387d1cf19ec4a4005820a409bc8f08a7956c8e808cdb077f43b5145117163137597548e4b8f450f6979bcb6d886359fc82b7e85735bade61f140fa9881e52aef01c62d152d81ff684aa0af4a5afe761d9a6d25c2daad94f73cb1dde1322a1366d281d0416c367b794128c67d55b1e112ca0fe34812bdafd71843a6db8dac521b9cb102fc13c6543b45dff51f5f154f12fd0355096f08441227bec1efacc594e045f236a797e0884f7f22634ddcdf32d4830d4f8a92c9af40a4a0cdf53829aa2df97ec9cea608a71f38b179682dd6fb034d3e0f3e3f2538022b401d25be6f8771ecddf27da1d97b0bd39dc145f4e8b6f3f48e0014c2813d3831f8f2c1bf5428c5cea5690124cba76f42962020d6b8232f91d2bab7b3a79265a133e6f72627af51356acf8a6eb36dbb8492359a018320abbad77888336825285fab6ecde8d47f7f9e5267a7abd46449dfbdbfb68fb3e84e0b7f50b30f810051c285892dd01c2daff3ba1d833ad699d9c71c6b2f0527342cbed907db123386af704ab4b58321c96283d4ee863edf27807ff2e19188a948bcda3b1ec36ddc89f029ce29d7002200d316cae6face29606d8c4b38dd9c7a219346e413b812c165d4a550dde392b0f75a3d1771e7001d269d551834a766995a1c1dbf9c46b66433f39aa945b46328672184e671e66952539ca4d64f5c9e6367ab45771de3042da2f13cd7e5c5083b0b3851e6d013b3b3bc4aad8f56101b2ef2bf9c682aeb1d510159fb5b70fee7d16041084c06b3f19d38fae778d03ce44f7c570af02073c7e42a0b56885c8e1c1d723024da34f00741abf81013c5d3600abc73d689fb05f04b0864b6cb977e8f529e34ebd16cd96cabb520138730e866c68ba189e92448cbc0ae4f7b4cdf148e0fa44f068d7a51e64556bbcb13235a824a703bd4e1ecce69d7ceacb4e79c4787437029904720f7c632ea5484ec9e292cfa290b3f3e632eea541c4a51f4d70014f42be59dc4bcd600d3f1246a807f45c9ad9e995cbe233958f97b7cf6f4e9f50a3a063988de46d8e5d197f9aee740134e887c7195b0825c9a28c448d73f9e56b4ce686b029f6fc6f803fc0c59058bc2285b92461ce4e0a3422ee0ffc502b959b55e143c06fbea485fe1d2f5dc1e743e15da43e5b185d8031a92f9ce855482177489f2d12b47b1e85beabafd471b396071efd35cbeff43651a0b0cdee92b8051559294f5b027be4b82c94c76360ca1ce86a0889d21801f843462bc64741b68315229f6356d7faa8f2d29b556ddc1ea58659053b3389fa0afb3a2958ef3545951c82d52459254d845ed9cf1e7be40f97d3243315c22db4faf4fdd06d921112db27dfa6929b39acc1039683b61b44dd3b9b47d8b8ace9db96d0b6c52da3682dcc8b9684ab379d7a72345720b3fd263958c2a359f2dea13671cc4b70cf15fd46a7c1519f3b1d5a95fcbf344f58013714a4dc4c4757f028f6ad682c0c014cb7c9d284e5c62accd284c6a928ebdcece96a6001a31d4bce64b65c8ec21c97f7daea31260816b4462a69862339817042447944ac3f620e571c8ea86029af014cf2cdac425499e956134404280c488c35be96c679b695e54d0f4c1465f2a4350019dc73140a15a1b90e1f12821abb6bc159b6b49ef4c2f23332a139b0de2fc576669c781fb092abdfa931fbf4560a55413112f7a3548227a4e9b8c7011412d65dd973e6b30354b0328e8c59b3b7fe82c03c63ae402611ac4f668d2504b39a2897fcc4e0e3faff88965e98fba0f9118df872043925e31776fa583fb98376a50010e162944b735b88fe315cb8b11eb9189a04e986d9cfb10259aaf44c63daf26dbdfb4493df05815ea8a56b4af1338419baea99f93b67e1e1aae0a1a0766add720427d5676bbbcf4407447192da69f5a3147c16473efec972b2088fee0e4b0b4d85b871fff9a1aa71e3cab3a28227c614ca83f2c100fb2b23cc30360682daedd4731a37308404f7193770ff74f17ce41b67c562c82c5aeae08905ef1c7b7f434d0681f4bfc76e294e2068d10a521cc9f41fdaf9081f988298a3aa1224bf8dfc3dadef8604bbcf9138b0117181e4e00b1c6e562edd022a71f469084b363f86a95635f983b2c50f26fd353fc5ff8e24d7c10dcb98eee34a57749f2aabf5312f53c0b3cb52624b3f20184d1f432b4d4c531d7e6c49b9522cba946e0e2ded49d6387860bde881f1398949109b6d45a537ad29ee89e3ea447aaec006bf205a20da4de43a3e7ecf89bfdf94fd517c34769d8c970bb25f10193a1d6afebb9f22e0a4234f4dd0ea8966c6f89d3420d056e8bac0336cb2e413ba7d82964bc2ed7caab420a714ac56619bb8e1f3f591725cd1097b36fd8e05e65d5e9b444f7929dfc2e04d89a01358f085fb9a7adb1865a31dd1efea325ac8542a5029953dd84082c1bfaaf2ace63b39d7278004616e12a77f71e864094d29b795432584168f7cd96ae9197a84cc24aa1022b2183bee4a85874db0d61e6f081d5b8644686b6576852a96e327f2e084198729c727e455875db82e0ff7ba5e3622a6b5711d47b1210c7acbb02a79690020be4e542d51e8f16e8bc1abd60f5c3d04da8be31461855bf90d0578f8c4d3886bd2e73ae1bac59dd3b5345f01bea0a46c3e708842b09c494aba889991dda6db268a264210021336c7c59a8f2fc132b0ddf03f778c3224b897f389543c7caec880d2b4a099f86186293909ec4a1b11967ff11797ef0bb9dda79183c84865c94b1165292fc298fbaf642b4501812bc27e5f39e2c47505ccb854da8114cbcca3cdd3069bda82e04808379ab702bdd89f5a7347fd233ea3a0bd6745b4a781c9df2ed7c51761378569ff90e573074db2545f28c34897e8532ce1b4b5ea1209984b61b01c5984333a48fcd71ad18465cbf65ed1cdbe8d67cc7e6d0cf1306adc9eddb37792ae0c6a8b96fbd46cd369c743504c0e2bf57819ba26fb0ab885c00216dde0f93c7fee63d90f0974d4e58082c0603cdba6f7460cf5f8f9b1d8b7e96bcfad6562d07819543a0c52d9bdbf4bbcc6aed776528b7769cd30862213de4c9a3cc64d46b3edfd0d5a5bb69ce2e792dd6dcb7eecd2c4bbf2844dd62dc63a4b512f78d422979ae6cf058091d65b6214932805a7c61c16fc01d8348d015795ef5983522a1608f2c35ecc427a37194106c1911134ad53faadccc477e3b3cbf11bcb0c30ca3f31e0efbd795500a8f69ac646825753436ff0aa467f00c20d7f6b076b435013eabbe13471445766b091b47668c23050d829f643276d005b01d48ae36c0e132f67f9b9b920b7c6c5ea1fad5fb905eda7841062f069f06800e854ef45476b8fcd9ec63fdf1dc261f209fcdb3c0b5b1e0d5b19073d02697830fa4707f18c9aa373892da30cd09596442ce247f229d13d7fb542328f3fab934927a3a7127b03a9887f2d4511d1cd575e2683f01e0ebbb40cdcfdbb0a41eb5e4d59fdf49f8affb473b5e4fc81100a52c3cffc7ac3ac7454ca100997711918a745e50cd25b3af3138268b63a438dd5c7f9bbccbff0e7db841da56dc5bad09f91fcd331d3edcdf918fefb56fecfca2d31ff8eed0118b17aa1f23abb6b4b2de948959417b7a3aa78fc56835ca026aa0f74fa8e213c77c0c465d8ac6915af6f545fb5e2b6c10c33bd7904d1b487e9cea2edc152e94016b9283a6ab87cdcf0edfb131f9fbf96199d9231d6b47d447d6d68e2e603265a832ff97bd2688e74b92748ad4298595b1095751004c5ded890e1674b4e892013a44b6a3078e866fd0599132e848f28a067e62194aaa17369468503aa4f46755c535a0cdd09d45d29d022393f5481c9045b0668c1571d0026fbb570211bc61c40d0602a6123ab158237bd37ad0bd87b278e44a58d14e9687433cdfd3c9d317112f43ec896cb9decae07430cde177a18fc8508efbe529d264f1f21293a74b590cff576749f869450062b399b0f5b24cfaa151bc7e9b852f61a95422104b71fc6fde2f0657a51189c8d76703f77991da3d554918275bc3148ac7941d09fb2873a830e07ea86e5d642c9e54c329e1e914084ef106a71c46d04ef80b4289c201d0aaff03f6411be980775e7d892b33f84a18a37ec7cb29a59e9ed80bc01717a6b211f9de4f522a001457dd1f67164abcbc25b9cfb9b9f1798010cd3426a48bb5f0e3309769a51c06ad97f5d77a3c429a1ee3388e91b802c1488690e443a94c5ea0a8af448efbad871c0fd0e2367f53f2db134c627d4157d9a72e1e182d7c075d1823d0f470721d998e4d11a5575c5c366f0db4770b782c4574673377699a4f5bc079b2c993d247dce33e2d717fdf32787edb6aedff11130500f7e98b716c7721b98502913cbdbb23d7e86407b9abb1a1eb9d3f518fa977041400d22563972b56ff8c9337607ca3c090c40238674af00090327ab5c1a1e6d3ce5885ff9c354b4023f0e6622c5854b942115d4b1f65f353390c0530106c47d1313526e88a35b684263afcaed6bbb031295e45ac64671d7386ed2db71cdefa688d54c3637300cde12196454ccb232cd456410b131b627d06cf1d308e56d1c69a8547356b1f995947d8fc50590b359b9f4f9a50033f8bad6795ce0bb99409a63f422d6d8efe6cc45ed33829ef77a721d8756119207202ad3b3db0423ad0d4eb4f36123e97c1d231a11fa18f162935a6f05a0e5a2212b9886a15b91c0beb037d9eee5dc14652b6363dce27004a1a659a8617d3c5c124a4c2c7685b95aa14f7a525350e6b3a46e35e72503375ab200a2aec75fc01b562c6bcab1ed7e2f049e484169412d620a339f521142ae507e45e3ca57880a0f385f7be814ec4275275b9afbd145ae26ef43a52cbf985b992b5f09ed75e688072669aac02d3cb37ed03bca726cf33455e58797133febb84dcdeaf00b78e40b30b74a28089882ff27aa2e205f18ac9dd42bb008ea393a6f00f6297d6ce576378a0f13f5e87faa690cd454cb5d65b847268e62372a89d91d246b312d43e480ad6ffd924d888f6ec65c98fb8e32bb5bb130575af2005989be1e2073e76be402eb1844a1b137f205527017d1e6912084ecc31e905fac41fc77a3151d37032768be068107ad43dd07a2b89260291a37081a94149c63af5db1e9c2e9aa2e7a914580f46f445e0b0f106e0dd1a7204200ad63ebce75f1cd734ee936def6204f15195a12109689387b378263e99669e44852c535eb089c543b9140af21c0ab534053006d5957e7ab35487cb5986464730db784a8f64eb51698c92ff4b0a371c36a5fc60bb2f741c0e1ce9af0eabc0e3166218d1df7d90182b2cfeab5e5d5ae45cc2a702e9d9ee3c3298ea90b499cba0d34fccda7b0d4fc86076ecbb72a657d41a28d82ee8615f8e4f261fdaf3c3cb3576fd7e4e5b8651aacfd83199a307008c51f3881233e705187d9a5ffb280c65e734ab2011b7c02c5a064e266c0f2ec4c98920505a15022e39092109aa85d9b0f6f57cef2d476b5589e5929a2da97d50272560f811390b65543689dd180c999f5bb439b37e489d801459dfbcb81bd2365a0116a330e05b3849fa0d23d9e2ae063584d46b27a419cce71c7d3645be51aa26a24039485904e45229e0c86d2ce60f3b315d5af5601ce6018ca19c949d00f30f6479174756433aa539673945b265f9d2c3d0bdd98e071f4389af1c4a80374e9a1670a5a58b6a13e861551e342d686ca38c2df8c626676b82c555a77bb196186e7dcb1e0c727133066e848c161db31ce1f4a48a77e01a0dec76c3130b7a90b1d71ed44bbe8239bf45f51aaa535d5618fc150f4191c631bf5baa1fbd4219a7156e78239a15842580dc004629712a735da0682a13b29eef6a2e8e3500ebc4711da3709e3d743a66e392de68435951eaec1cd571d9ca847b71b2d9f17103fa0cf8b5055816f3d8816ba9a69352538a5048ed2f1ad642a9c9900d0b98524d368a25a7b4b308e45578edb8cd4848299b083551affbb31c5cb057a5e7fcd5cc4790abb108d4ba5dc93dad5fcd8417a36c5630a5d1b878cc41842ef3b35322f41eca2136bb2ef6e016bf27654248d4d1fbae46bb4873787d945b589d452f0b8d66c74d0497f9ce525a93ed04ff21da8d358adc98fffed6125a6337d6cc2f524089a7ef8d3543675d67329ba13a1b6152eab3190ab2414df97951e7500cf23720cae206e31c3ad24a9bc4398d56fec5c5fd059f5590634117b8c5dbbb25744e214cb2041f0b67ce30521ab6c9327ba97553c6969263cdd2ea99e56cccfc8b6354b9711d80fc9e59330ffa3742bde12ff55bbc3d5c131e832cf53f272bdc422c631736b9e316004e61776522877b9e8d756609918cef4538ae94255b844479222bfaa19ace955cbc1e64df352d3fdc85e0808e18c29fcf56f1de562d119a49ff6a92ffc61055d77136e8df79e33776afd884ae67b57f3ab31c053bb1ba93a619310de2a5664377f314b41f2a56e706ff2458a06ea22b4dfd96ff82c5da4c3d5d2dddde580f10ee2b4d69941f25ccfc3a2e6f2505e211b2e6bed988285a89d17ccf28745a0fd5a68a432d43d57ba37e28c984657096688d1085ace44b06ede653a253a29a6fc6911753f9df99da49e0942e1d0b0e4e5f3d2884fe8080f171e78feeb686c45040399c67e315017b8e209ec4eee2e579b88c296dc0ea335f02377e130c642639b72acca6bf7cc2b9d3661a0a33c91a950cc7badbdd928027a2bcb0e1b6d327c056870e379ade58834993a988cc30a45ee255fd289ed0ba9f2a3f2f0202ba26a6c3b434811e3cae9e814885edaddc52a102b721170c8cb9e4054b6f9567c920522b2c8f9290a702a3f2cfbc70e4ffb07cdb2dd7c52ea03e9d005bbf7ed6953856b83760f7810414b04cbc5a170d42a334b9fc5560f778b99aa57ef91f161d86a3719c72257de41d6e98ce255bbd73c963d357decd136aa78a184f104210cb46b2713a2b9c26d10be13e1d222afac5f9e20712228536713e7b43afc0fc9c61d4b57826a01d57503e89aaf867874d911512a5c6cf4eb83b0027871250d3ae82322212b71d152ccf6f481796afeb14bf88855904041001f0bc0c08252b1086d43fd4da006fe8207cab1d0e5e64ac4263756183fe13ad057415deb74a8a4fed7015c46146efd6c18d34dac448e51a1ffd205b64b60c2a382a14319189b8ea46e5db70673bb3dceedbf824b10df6ba45c638b458e04d5e9f267deafaf1f5cbc6618500cd54f92772a94a36bba72a2b0eb0e7662888c474af85d0b14fb4bc86ca9938f95ed21056692bd71de826b9d9742b1c8501973b1532789925ecb741fa2d17172c299794afc1ef74256b06ad3f34a6cfde00d9cd9a706541e04ee24af23d23e83ac7d01e9dcd8ad8a56d16ec4886e3a44264088d8fe50c362a48670333f6f2865dabab9d7f1b2d009a7251a75cf5cb14d88e4d12830f4371e5b632aa906207d0364c6066249ea73a07d0dbc6b307742442e9184a4cbb8f92e0bc09a9e8be8da72a18b1b899d47419050838cdbb9abbb21e91e6bdc8a49052ffcebd0e1016daf654af1d361dac6ded722ba6b4fef46df56a20be81b0300e5fa5371de066e2634bfe57c17e523466bbdb1772a0cc6ce3c516bfdd2a6a62de987f4b65f0dae1a6f7ff2d0268e9585ba4d08cde1d032b294005775f56f605c918b0bdf3937426d4e05a0d85253d7c433771faae5e2a19bd5f7dfc9878caf82cd017e2931508b4acdc94b637b4bfb0147202b4a0c35d9fa9c72c3e750be33df5a28fab12f8f8c0589e40fdd0d7230055a4358bd9e969609e35bd083dfb09c195a9a8bf11e2fd3e153bd4f4c0cce37184034dd85b7b99429367a5c1fc5d66314784655b37e04acb3e0b94cc92928f7a0e5f1fe090952bcc29023e5688c5a7825a6e4889f493346d65a0ed2eee81d42cfb90e664de8e76937291a3c0e3f1ef0d0a51e89b9763d4f9dc6841393ccbd17d2b7e50ead6af5c105889e7d32a4f083bab9e0d87db93bb0e1b92c9eb5409a7707286b409ea1238faed64d12076d095c04d383c2c8e881875aef624cbafe9f018d3426f28c674f48d5009aa3c1b1853ad5a06ad90ce0be880758d030646fa03816c59709485ce4e051e29bf9624cb87634c0da9b565b097c58accefa5bb5fc1738769b942abedd215deb504f526f6bb05e2ae30579b82b72106d800e83faa5bd74cf33760802a7c165f88e639baa9b1cae745006e252af32ff8563b4f12e6a7fe783783e9fdb813b8ea9c39e3a2979ea8881a33e9c63166a335541eb950c3b60709faa1528491d75922de15d2126d4d31102de51b087cba33bf0133d740bb600ac2643c3c5e92230d6d40bbe7d25479cfb2cc01b4eb0edd125bec276a6154385a5c78f2605a99b28656e6f2898c4a31d112c106097a20255406b35fe1ded428caf7083c08d4c1cb67937dec5a05dee428a17e85d6d92c22c24402c11e2f04c1493fbe773ebec9afac63eb773306d5222c02b2abe2e65cf37587c8592dfc5adb18629a647b867b5345ca0e20f6c69bba11136a3538003c46caa9c2dadf6e1a94f7484672a1cc9150b19a376a8fa7cfbf2121d4960448757b063b50d9e0dd3b1ca8d3d6c0badfd961cd0930b489128a96dd86917a8307a77eed3957b50c3b31bd40a583e3aed35894390defbdc60bdc211a8b0e6f175ad1f7faa86fbe9f9e40d297790c983311bd1d22554d214babd0d7e1212cb3cd86d8227f65feba1779dca2069c55fa2b8e6b180b8db1bef9222bf38868c5f236c527c54e2e8ac6f3ecafd044065fe0e00ded8873cb877373a5114fc426a96ab7230aa16982ecceb85b0efd92b33aa050c3ebd5eb85dab2cea3610dd40e5252b51dd98e480908cb89e41769fbe92f284e50e6924447dc3a920882d16aef24a42df494c94fb3801d9224807c53f25931030a2075c8b7371634accd8ae3007e71c2bdfffdfc9ad668f0a075c1fe98ef433e398c882b4ce9baa71adb0f69446d276ee2d3aa0b723729ace90a3a679197e9c60bb076ce2024ce2b3b73e73da686e3874f1b32bf7bd9864a18b1b28d20587c6802017e4536dd2db7c9d03fc5166a5c565f69de8876c53fdecce609c581a04cc68bca5ee004927971d714043f5b0ecfa0ecf77cc3b8550b9bbc46a3986b2a006109c89e09d3c63fa43bda32694e99e96efb68c98a50c75cedc43b4182d906ad5b06efb6ee592539d41e42847af2c949794f5017cdb457683d9b0a040355ff2676d12fe9a2a5bffc4282cfb9e8fc3128c41a6ec500b044dd660784e52cd33f813015f926d060909914ac747843b99f55ad6b37fed7d382f5c29d0cf8496cadef73dc0684353d1f84bfcff93e9375c2ca361d94124acce655b0c862bd50d95df140b0cd9118307db750984f6c2063ee288936d691871d31afe14160028e7f1b70ed002497ab07edc24211f2c6d9db10fb6cd63ac9bdd37ef32c0fe822dbd49589f456addcb3b296257e0d3018eaea025829bf6e7e7d3aec45a181354568a176ca1210374e5c316a536b508becd2d893a50684f79b0efa4211b9478360829e579de0cbb340c8a960602c91dc1064f5571f8c83b3c7e2c9464d6ca54b033a900c388a56b8f4faf85a0582d285d26bd318ca0b68e0699aa5b9199a1c4b74a113aee04f457a8e64258ad44b9e1b2de98c1197959ee4f195f9290fa47f19d3ee4920d48165974ba5cbdf62b9115624a29a2a44f694253425851f4cb8b40e6c56c5bbe7af369554a1cb8a71ef9d728856f0d1e1c290a36915fbfa5977652575e23162a405fd33e0e7a83ee104f9f26b924ecdc3c8ab969c78f3c400bcf2756298fbbfea68147aabffd0d8584cc0274f4a86e8fbde282d42ef1059bd5024ba4ca8a4c29f6ba35a923562eb5af97766f8dc5ee8c8ade5efdde4d7716bd6d66141a84db11c05903e250cf61e738bb32225e5c3f536d61b95c4afc004389614d599a768c9fcc51a837922453d382e14948422635bcdd02069b692e72b3108ccd1b1de6b8f7ebe7549eac512e58489e07c868eb70481eca1e4690e85fb1f98759126cdbbabf4cb3e425da7d4b203af5103366973c96ff3d794b856c784f2e83882923964f1a47d2c6820b8cdbaaa80830f0cf119a89474a54b24c114f44bc55c95f50f8b39c7eccbf42ab389b9ff0797c57a7913f816642e0409f4466e8cba85ce55e58d87278f5b1b6f2e329a007e5ebedea4745b165b84dbc0b50b03e203e7b6972cc5b6eec41154c5955c7cc46ddac755a1b7f8ca01eb4a2a658a97b7dced0c8bfb3bed58f9bab8cd5b0ca56d1df925932796a9ec05f0393948584c557b6bdadb4cf943b60c2f0b36a8d703691b7f9a1b570a141c3024ccda2c3c4aa5a9ce8b5831abfdd00acf8cc1277cdf58a8ac2f4977c2ce55a457d9af0819f475189b966e2103d8f1193d5f84d23e483bde96b21ae1a282765f6db023d805ffa272f4e0e111c07f29d538a16e5653abb242bb7c6efa0af422ad19f733e35ae4dc03375125e23de3ac3289378a02e40dca7adc5331f33b00753b2540843e288814535d375b4d33a4f9b44a48f28583bd22438e2115281acc2a79324517e4fc5a55d14cc99ec2999103de79456365bbfa7abe9ecb0f33107e4da79a4fcb3ad261f4816bf7c12b8bd3652d683b76fc1624a0ec69a6afd38d123ad29d8d67fab7eb88ac9636fe9eb597f05cfe7f2fdcbc669733b6f29fa2ad4d0c41a7875a969e309f54112b503280d9ff6592750d485cec730c65a895ff8525a279eec00c4e2fcc6ecb257eef949e786e7a44675c47f28bf451b2bee62bfc40739f1e2eb489d1ddd27b78b7635127d3d692f2a778145ff24b6c57222088f90ebca43bd16bdd9dc8ff2eceecf12368b34bb16760ad7eb296d9dff77608d563d9321ea73bb23b306519d560bf81518613c2a5dc3fb1b1141d62b24b62d3c4f21b0e185a9466a13b02ca0aa0d4bd3c49f7c33e303cba97d3376c930c6f03d857991d0244d8c7804993c2b31b1720892b1a8596f0b6125a8b440e2a58952b0a052506dc84ed3f98639684f558269a5c18eff5684ccb46c6a03bc25d16b569494d21e105f1eb00046ad8bc8d1b818decf434226785e8bad73c5ba29b8fe218b6d937ef01f961b4475cbeef820f03838b1eaf92cbcafadac8428b1beb6463d8d7303c05488402f348fb928c9fab3a48c1a0b80d6600f67d99980cf8d2c7d6ce3351d5accba18dd129d9ec4a445842cdf3e60b2c849160869b6c90521070f849902d3880e43ca36ad7214d965d66eb8f6d56c07ced3b1c3bc30db45bca042e87f5b8a92e963b1e6137668aad9eafa48d01350d0b1b0a80a6d41be398074ef751bd3629020b6439a46bf4308ad6c8a30d96e3fa3686221cf1c723713b984eafa1911e9ac8ee959202af9926377de9a9ef869204633065a928825a843ab2fef85d9c26ad1651de7f58c4f851b8877ecab9cd310dbabf13f51181d6c8243e25a444020145b967494f79130118c67798e9cd9c13e9445404a6b770777a849e7773caa0ddb31e22c0cc94640a2a5a903ed3e79f20689ee2bf68ab12bac820c65f212951c58b46dabbe1e86e28c84149f356dcb87f619e8768aa997a7a6997f840dbbe689e9bb68ca40a7182ea2007ab14d27a95472b2ff12aeb6bebb029d486daab3588b59e92f13dec8980db16019a91abf17689a71fccf75bdea05045b38d47836a92a65e90be08f6e867b37fc709e54f8f45e4d1fcfce1a3fd9450e59c5ec4a3c1b9dd3ad2abe76e4fba8d8e5c1fd8b6029c7e4fe87db386c888df39e8f355ffd1f6b273e70061d5476f5e8ddabb6937dc3b2f26cd3cb98093b40765577b327b0e442b3b3bf1d0d72bf8e975b518d47148c22336780f9396ba23e905cf52e6416a8a809292ed4eac59095e409eaa2c0da3a1667e83ddd023f13454759cc8c1f0959f57dda3c6e4b0c09e94200a97b2916b87227c430c5894e3d44c623a1187ae569aa7102a91de8c37bececd1ca6b3c01cf2d9a8a3004538ec413d549c9112fcf71c39b17ad4b20bbe6fd8900bd522524481261d286858b75b4f05333726182d797f8a2182c24bbab99680a8765de01e02f252d5b1866db68d88b6069b5bb426033bdb222e3b66f8dfd03e3d9ff884a1c2abdf7b4e95eb1a0dc07e73b5110791cb85df33554a20798eebc137468a95368545b836b9b8d07e317533323d1f6e1c93e8eede4399e62388c01b7098e477752320c3f340e18b397fe1ff068d6aa451e102a000030fd2ef82d70624b457bcff8e34ec3a732c3b0004f46bf8c5285e40dff0d837999d41e2cb6357c87a4042d13653b0a8a6012845edde3c64f8f355f1c1a482fb45f17023b76f9f6abdbe557270bc8d031af0c29856205c915163c9784ce6f0e02153251f018207e691c2290dacc444971ddbe8813aaad28065c86b42a9902c76e783cb8373a4f228ca124f3502da097056be94004f778748dc125a698d5bbab0b684ec5d42e4de5b4a2965bc092b0ae008ae7d8e9b2ea18728b157dee77d78532986b0600f31b6f6a9a914434e60da548a2121c0187fd98ab00dd9f3bc5ca2750c7b554ba69289b5ed6f18422c984013b8a91462a8c2994f4d08c3125db1cf23540a30f0600f31aa36fdb7a9146280a24469e84d859b4a21861fec15bd0ec581b78caed083a2c8a3b318567a2a5e2ad4a3b4a9146228b2e3093050adb5d65a3192c863f7bdf506091102b6a74a57ba8e0a7942f626e4099586ba275c0fc4785fcfdaaeabed9205afaedb07ee6eecf56c30d6dbe15aeb77fb6ee8e6be92b4f5a76907961c227f743cf0be0edfaf0aaf8aae0a5c9690baa27badfd015e6c6ff5d93777b8bbb7075554513a15b1ef6bd9d1157c1c161d06f67dc5f75d1190dac48f521bd9bdf8c3daf67bb1699bb48d354b33323694a6c39d57c2b582b782d7fb41c9764f785fce7afca8a75d4c19393ad8cccc0439c12da94ea2477eddbda6f3ef14b472c59ac1feaa8dbf3769ee2467922bf9fd0dc5c97e9f4371b1dfcba0b95b0e851e6dcfab53183d12adfab5aba68bc8918bc831a2490ed670e4a3472eb8aa960d234af94db199a6cd3c989272bb2a438abd9f37336df7cebc19cbaeca60bf9056ae58333dc25ead70c455ab4ad33d92b2f1bd177726141e41419d07de760001795f68de9febe37ddf13590c555affd32740821c2151f1c3080a6b5a916493bcebb1f4a522169395610673bd5ae48949091a461fa020a11e7808fbb837d3454291806128eaccfe2a59415a247d4d017385332a9090ec9050b442ac10511475560755337d912e1577c84df2e95a458a308a4646f9ee557991a0a825a1c49ddb9e9557c811b2a62c4da4f2ab725045ff3491b2f68767a22d7df19e525defa6543f80a5a4d846ec084b1399fcaa4aeb539358b548254284a5ba3d8815e11f5058d3063942ba37278c804421d375a3dc90acacc4e4e4c59ac1465c2d5275579e118a009351592c968a0208101914464631198dd266337ab3aecd342e72c29a94e695987557de0f68b42124271a13b1f809d8880b1bad701b70114ae3fd09b2ac3fbe6badb82f92114c07ebe96f79e2a25aad5ffd487e71af581a3b3133b226fe518b6ad1d7fa3c23b0f445b2a6903be4a56f91928835edb5a2b45be54df28a70916cacafca50d23d5679af4a131216c98ac427eb1aa9e94b5f2acc2bc476916810f9706f366e0d3187bb69af345b49092e4a81e94bc588ab45cebc1e386171add76dbe7d4be7dce41293b08eac9b883aab7b5957a58fd036b37266c6735d2a4c52589ac8fc4c13d97ea271d1bd95686c746f407014e661b6bf341169e298dc551295b44a229383e6c94f4e74a52ff72766c9c4c4a4c4e4e2a27b72b58b694d96eaaebc1fb4a8eabf7a31906d7f1243101fe9e087d874914c9d4f697d4041c9d0d1179aa44086298eac697774ec381af6adbbdfbcb8b4c8bc7670f64d8d6545469ba1a4dc62546ec660602de669ee944547d987ca07b4614cef600c73d0947230941d3485a8b08e37e6a0a832c069fa0037358da3e802fca607f0144d80c7e81f0e03c4595cfe1283ad565a56ac95914f2b40db2222ebc3b268b52795ab32a26259adb4ac465402a02d6db997d166287a95a2491935ef63f4e9ca1da9797510ac832b170cfbb95828ab15aa75db303516166b74a91ca6c6d26aa556645e42e89e37409ffff44910445c57c6f5f25432ede2af7b182d93a273bfe91747d13337551e83c9c05aa793910f94c9348e28140a8542a558cce478bcca1a502c081d83808ed9d0b12174cc87b803a2618cd1662829b798980983b9ad6dcd404243794dd449898139f8d0d429bf699872a7ccb4fdf1f1b13030303030a73be6a4a81353d211e63698181871064c696d900d4a4949494939dd285f893a28251d535ea6a0a4a494b68790905dc29a4376e8af85332dbbca5d5e5a6080d01524c864b2953843263bddb48f883ab4928eb293c868b28b336465b5e2624d4a7a6c8735a18869ba6b3065ac8735cd3206748471a679384df77053ef7014adc36f1a87a7e81c1ea3671ca645f3bca601709618ccb67235c0a32d5db9792593c86cb35c02db299a4801bf95265588354b602f077ce680b21a11d51ff7669e8460ad341dfb412149b1a9c82e0425ac798b76e1a263fc45e7782251b5558c282a369dde31bd63537362dc4a94a8f9d142d78aee83178dc004b4f3ed984f105634cd5974cd6bfabe45dbdc25c661b4f7182df3148dfb4db3388a7e7153bf4ed3339fa93c068399316031a01738163d4c204848b9dd566a6860b1eecb89e1c2a6860616ebbe9b0a0a0a4b28d33a5fd12e62bc45e7d8d4d0c0629d4e4e0c17363534e5e9f9a271ec5ed7dbe9761d53fe22eaa0fc45e4c1db3c485f42140ce6454023a0a66d31cd9f24c7b1151483d1dd8e26f37ebcb8d492942811dae9b659beae22ea78571179f0065d4299cef98ab6398b66f19a76f1161de30cd0437c013a883f402be0d7afbbe8fb17ed5d45cbc0e8fc98dc51748b9b31585189094a808494a8f9d962fe244721ada0594e0c588b9958508cc7eb7a2a2e8f8951390873981a0b8c499ba1a4dc62ba96cefb5c5e6254bc24c0a8dce5a5056606949a324090d0813bd780d0951f47990579062a954aa552ad7a00f9fcec08e221c462e565a6eb8fcf0e201e620d0a7ace00124931b319da4c0e2288a4e898c334ce3bbd9ff5cd13a01d00930005c4dc8bf9f71a73afa428e28c987f37e674df7e13756e251d636e13738b6921ce88295b10dd24a085e883355bc06881c3893af733a14cdfafe81667d134af69166fd135bf96b98bb681d1b8c7e8dc4dfde234ed7da61283c150527800639165f2ebc7bc3535aa969879184c6d05f51da1bea3d4cfec23c623e6f3a36340d6dc11a36341944585a6633f3534a1fe8b36b98b3e79024acea26d5fd1242ab49419ca2d66c2f48949898d24688b3f5b41319fd84fadacd5a3a478b420f4781389b2026e36dd1236a2694df3d3d6052efc74ddf9c517fb8901c188f9fc18ebcf988f4aca0b94172f5e24ebc56ae4c50bd87d7937044da592148ea6a815c780623e319f284a861060ab900b4823211e3dac9035edfde80ef124f260ecd9dc9a7b713777676e8b4b732fcb6fcbefbdf9ddbf2caecc8db930f776d7bc2ef7e55e18bf29bf2abff794ca567e6fbf2e7e3dcff35ce89f26ae675343d362268763211303f3e262766017b6cd43271f1b56898844558810eb53935e2e50473f8aaec904a20ca9a48cad144b88a5726264e47ee48e78e1a74760a8782e5aae56abd572b95c2ed205caebb56f80688a536f1d59d16aaf8a45934074e5c89ad65662b3ddfc49d28455c4f2716f9625f4c253c2f56aa69aa966aa996aa6daca68b512eb0f16abe5224bdfc76ab55ce48bc805496669191959ad56abd5aabcd9293054c8a14b0e6d568f5aadd672b9c8170c0543c573f1a35028144aa3b8a02e927cc16227171707e7c57772729696500c435114455176b37301361627e24493cdf8841a55a20eabf01371e840d319c42e750f7d4c16a609ba410aa26ad963ac62a786f1beded3ee94866e7a73a1bd75210dad26655b18f16db82fcd48ef359972e828dae799ad3da519c18b3befcb259377baa8746a1889e0335093b8d3a26166eb7662a269b69b33174979d26ab55a2532d84d5dc45d359869be60264cb7fc65ce4860b2da1d1a1a599554b891999155ac55451d72361293914c74ac0b93ddbf62b776ef7dadb05819fb3ef2a04bbc018fa0201779b2c10e2020f285f2717f4ab4c98ca484c95eb19a8d5686972b37d128d73ae5249a7c4db73ed32a8f95d87e0293b55e654069b9d030969cc064af58ad16bb8da64d6624256d16ab99b2daade12422456a654dffa28ec9c1560c68d26730d98ca484c95eb1da4bd30d9bc9622d4b5fee6d252f7da42c66ce4860b257ac863b993981cd5eb1db8d261493cd68544a6ea3699392e40426abcd541b8b9594243398ec15ab698d8b743e262526f2f2623b41144080c0c0940441616454bf5abf5a96e60c267bc56a5f59bf5abffa95242630596d16f39ef8f1c3ab5fad5ffd804451ab4ed4a222d98c04267bc56a65d901c166b132f0c8cd72b11c6c260439ac695bcc5ac45ad466af184c5603e976236b242435121308c6445eb3c76edf0199c5728d84a44652fb2cf6c9be1ac989a6dba4c4362329f561b257ac469ba996a64b394a49162e6431ef07b357ec3059ccfb810bf6d294ac77dd2a62100829482100fac741d73e43d3669fc941048e226ec85ad8f4e4028003cf0c1933361c0b990804a149ca17979a981e185acb596ab7a1995d5612001c7866c898993908def03a009fcdcc68b390e5e0491f04c394ccc1d3aad40f38891ee22dda017fd1429c4537e02e9a01afd10b38ed3c4e43e011d017b88cb6f1185da345cf7320ea7957e280d71a7042c0c60586788003846800031650a3956bb958b0ac0f223b6487ec8f96688b5cb4da13cc8561852d16b9162ba4cd82d01a93e85ceaf045af5c6ade42ba5aaf9defe54261b150e46db3d870add6f862b1e15cae140badf39c8e4184a6c073dcd048bc085d817ffa848508498618a24e2e71cc0728486828085af3f018fda202316ed33a3ca777380e6dc473d0b216dae634da7bcdcd59f65bb40b0abc469b91942edaac02ae183d362e710744c3c822295f5c6a62de5263a991fce55ad461a989a9952d9ae52e3ae6a5ae56fcf8785f4ccd4951a7c624a62626a6b43b808058585858584ef7cb57a2ce4b494796db585e58b43883a5b43cb468836c8fb2d461a9f53fad6fe4683d3d339a9222adb5fe77f5e926f988a84352d251bf4493e88b3374598b946225528315d9b9256d064bb2b5943022a53ec0493402dea20df0174de32cba0077d104788d1ec0735a00b769051ca71320a381788cfee10678ad000a4800101610328448912498153e3fe8d88f090b01989cb0289999d0ba13170a50a0ac40eecdde44a26a64548f82f4dcaa409af5a0a4dc30c76263f195972445ab0409d291942bba53414a18a36d2ea36fb64de7e4a001d042fb701abdc36b740c16ed95fac56fe8235e84aec00e3c10a191380574c5c9a162ab4042571f7588567bd281a7a671f875004e014d7174a8807ed001c0830f3b0829c2d1b5a1ad6b42a61b2360bc70a113c3e6db5e1062b4ce65344ece715a87dbf47dae44c7780bcdc369b4cd6bb48bbbe817678141a2f7cbdacc8636bb51040e227298363db499112612526e37161d72706a9f0f3df0b0830e3938b5ef8682d2126a0d001e7a784efbb0830e3938b503c0871e78d841871c9c9ad0516e1d590e23eabc1c46e4c1bbe5208509513596a4360811c3775ad0f4e46c381632116891bd845afbb059e81d8ee3e139ddc371680a9c086dc473e89ee7a06dbcd3e87b981a1867d199f61bba022f421f71da6b38b59394b3d93b9cda91a0dd64182f74728c3ceb6c2a7004058ce851a1b98c0cccc19892205daef33e9a16253e31202272741ba68409f19210b6c8d17a7a6634252c38162c8a90a0d2d58a868264a01e30884092902145ac88f9fce0589439929cced5f44cd942881a48376cd09ac6e1343d63a679dee91916a21e231e011923649e65eec93cdfc41932f7644c99bb9091992153cad0882e2e374433333ed0883268767664dac5658c380b7d739cdeb7699be734ce4bb4ec2d74ce69748cd7e89c447b2f7507a3897a7a9e3fabd1662c2f3ce8a9d166308c78e182dac8ba1392db883afae02a5763b1b19089008b106bc286c08a24c1aca03018d8109b1a7dd242abbcd33311d012b88c361fa34d6034d1044ea2897a7ea3081c44e8d326f03c81973d7f7121baf11a4b491481cf5626b0a29282723382e224c444c386dc6c654da8e486628b80cee60d4d8e2e7a5cb07881833143a2614360446e740913b2535060dc340c18ae160bc66a04060c5a278b820322680114a2082205288c2060eb0c86e0f3c5f8e4e8181fceddf7da5c17f7c585716fee65f18bfbbd327e67fcd65c9adbe2cedc9b6f77576eee5e9edf975f98df1bf3bbf37b2fc3a293cbf93df97ddfa7a37f9ab8df735c62e0ec1b182f5cd8d4d0b498c9ad745927270735f27c3a31725028140a35c6ec98725a605ec61466e978dc11ef4827268bc562b1a01932b28cbca2d5deaca34badcbb22c4962764a2d2c703794db0d050505052565860c9515928e0b89d2641bca86b2a16c281bca56b442f229ca392c56cb459658ad968b7cf948d221c9d7ebf57abd4e64cc78e18129296199a6b9a222fb8c49414c50725bc262b1582c13242a4e4029275c24f982c558e8d5d0089118d749a95229954aa5525dc60c1595bff0c0e852ebb22c4b92989d528b4e8e4b8c9b6d47d95036940d6543d950454599e545a780523ee3914e2c2693c964b259cc8ea893d38242a15028146d4690a25a51ada85654c3952b9f22162c453e3e453e86923aa0d7ebf57ac18076e8f8e41c2017209d56abd56ab96276409d9c169f22968f2586ceb94b8c18df89e972f7bd963f5a4ccc8d89892123b372f05713e9fcd3798c9c171e98942a9552a954aa91989dd57558725a6e46b1502c140bc542b150456390fca24b9473169e4f27460e0a8542a1c6981d534e0b4cb9f2297ad165e9a28974def2183aa5924e914f91cf8f1c12dbd54439ff72ca94132c65aac8c47b0c4d71be154f2505e5669e9894d8484afd1a6d268bc15ea4abc55a8da85223ea2486a0e9e4e37dd7fbbe2b851d34c8b6020082116a158c8400527aeb7804fb630c4d504a6ba5011d830b587082312431861f3ac40a4a69ad55ec2146d83ef3be43bc40299235994c60e882222a50137872a2d2aa12526db5292ad86b6f14f610e369df27dcac847cf1c562f80a83116810c2d0836f05e0bd37e3e09e86c2d0829b3795220c270803083e37ecd5d5a522dff7dd6e0a5c2a954a224fc651afb875064c800109f76a30148196f2d7b5e1de1ec623f0f64a1cf50a4c35a52bf4a506012f813e4731edee69208ce3bdd33f8c38f43e36c3b46f8903b589bc532a6c978dcb9396f7576c4fd37bd35080f7e61a6d268bc15ea4abc55a8da85223ea2486a0a9943fafc3d7528ceba6de152aad56d81780f5d5522c527ab10b82a0369562480e70873bb2893dc41827654febac1e5c7805b586a5a775d6532b3db856cad3eed6b1d03efd7496563eb9ca9e560e4f6fa55a3f9531d7c79317e8fab8b91b125a4d9f9ecbf3f4313fc5ba4a893187dd397572bc8a3eeb56f928f2b03ca358f459f7893ca5ce329e52270ffbb5c8737a4fea174fbf42e371eaf4c34616127d5a3bbdb41048cbe5d274b7724b679ed35bcffa1cf7b5194022955a828577263f1ef3a835a78f25b5e6897bec934cb1ca9edc3a39c94abd3cb1d0269fc3eefc70a78e53e353e59903a7c87cd65327537eda213b75746f7825459afccc283fc79dbafd24772af54c3e678d774be77c178b2c4fe7b1a2ff137d7215151c64cdd11edddc05923da53c33b63f4c50ca73bc95f637f602dddc15bab71f3777839395d82ccbcfec8f92c7ec8f8dcdcf6628b7194ad973baf97c9be570ba399b95b1d94f3efe0add9c15727d989ca43c33b69527597b599e630935daf9e3612425b79d942a25c61cdd2629f978d8b3c843f29e92f29fd843b8496e85941cbfe42625fe35b5664979daae0f4c529e25ec54973efe5a798ecf1f4f2b7d6c7c182c7b7b6601bc825a33e69c7339d68e37edb93c2dd21e5f2b7b4e87759bf651e8deb0ec997cce0f292ef57cda78bae149ba7e5a2a5ae269876cf1a3156f912cae75f17805411647b7285e7cb638d645f11e16da634db2263ea9ab152c6d7dec8f10eacc42a3161a4fea2aea90076f4c06dda9f3a4ae639fbef347d8a9c893cfca3a364be7e836acc42ba82de36feea8c593fa25fee8def071ce20ccf5ba8f8e8e9ac8add3c193abf5931c4f3b59c775d2758fa7d7a3d3f1e9d12997c49dd4c7d7f1b4727a4a53951263ebf9a7b125eab4cad3f3572bd66a75fa8d1d4734dd797ceaf4d4b33e3da52b506dc9e3edcd4ffd549e48ec531eb33ee99b8be3dba9546a3c81cfe1477d2f6a943e47fc93e6a1fb8a9a6e8aeb985f7f1ce75ce2f167a44c40c18ffd953f36dedee9c62915260be0e9f7758735893dd42450a89f4e4f9d15a8d67cdfc33c3e8b620fe0ce654d221f3ce8654ff651d4f1ac871aad89cf30d4a6f0eeb038fbc406412f0ca3a93c756491e25212a5b22651554a8cf6d95aaf6ebc6b12b5a52651aa3b50d5c302582bad2c88a20421a0369b06f09edae86d6c49846528ce477a1a0590044fec950ca4d6c5b3b53bbf73f87b6aa2b73cb38924f7ed1e6a4a71d0e17537dda58108c68bb3a33dd9c4edcacac4788ee38aac2b18eb1419e9ab17ff400a9283f615f2aa7783ae10fbcff37078712572efdd3a4424c9de7717a6ed2f2edaf519297c02a4b43c476c4d5ac40c185a4b7f6b1daab5de5aebbdc7bf7546fd2d4f7b94c20139f257eb74d30914c5b75037fda451170f7ee1290730e77124c9df344f972dc6c69b4ea75bc6e994b1f34f193276fe39becb1acc279ed3417dcee43c8e24797e83a2181bcb9de7943ec7d391a3462e1efc4589278d1af98d35e9f37454a952623c953766462e963d2347953dad8bd73766ce537963668f94d49aae832db12596e70b04411308fe6402499224c1140e40d0757a5923a9cb9ec1c75ee05dac11970d3e05134f96656b259a76143f0b0feaf3c6ccfede1dc5036ad42f78101477c29f333333326662165505486f2feebc2fd76b51a8eb4369ec692ac8d6db34dc92f12626366b9a2626b6c434cd6b9a27a74949e61517f6399a368b3b499553365e99f5190313190a2091dd1da4dd07c64cc3508354535ac2399732e8cee4a675572d8cb8f3b430562d8c2a9dfcaa8531567addb11d6f974a1db6ea34643c41249d108c5e114a034469cadddd9bc2761e15bbbb17e47a426e90ede91974a5d3c20e2b7c6077340a6ec0a1deba9f1e1a64744732e84a57838c2788e40979439406f47a80af3d469a4390d2d0dd5dc6bba34e08d2cd7950d85bf7eef484ba2136e709d9c88c3f556cb2ae0a3437837a423707c48eddfdf480d8a8cad33392f17ea88ce5e915edeea4403c1fbb3b9532e80adeb9a471824820987575c198511d124a77539ccaeee804912892c59dde1da4c2e2f2bb8342284d1a8ef2c95a4acd9d0fdac8366b76bf39977b9b21621d85558237ac211869d4e82ec3e2ccdddd87ee9dde5d1090255020821f23c400e7a442764769ec5cee1847beea7e7da0346068ca39e79c73ce39e79c730e95183398f5b781a45d7a4b8f9ca557cffaac403fb43e526680c6bd756fdd8a3fb0be2a33e0c3bd75675dc6bd75ddd1ee9ebd97567ba43beafe5d90c8c98e4c01a4a1cfceb7016d984c600e8c3ffc9954a7ff7caea0b77c5349a94971a635332e859ad9bcf8a6db77ba9a375793ecad0d79d70f50333fdf2b68aeeeb0b7fc635379a276c7c3748ceff1a9d883e93df87507d975bbeb8eb0356fd0a3ddc35479dc745d67739a1a4ce5aa90eb52a2b9cfe7def24776f74c694eef4ab1ac3c6ad014469b6b91909bab46e599c1d207a414559eb57dd23589aee4e7309b4aa5ce84347a94a685655d35b2b7dc1925994a1d08964aaa69cd112fa135326a4b7ebe8dd294ce13d34f929d7f3daeba9f63e74357f24d3ab466beadc2e8f9f0b2052dd2d8bdd475ef2ea3d69498406dbda503a134e0f36b7e85c2d3a7b9bd300cc3300cc3300cc3300cc3cfe481a178428d2915188a27d49852614a73373daea187347af6a7b3403bdffe801da529dd549e76c7cedff33f9fef27144551144fa28812c5511453a2a812c511510cbfd0641275f0b74d26d305b2f358c71ef960ced5e8e6ea1ae82d3fdb2576be585aa19d5f607992a952bee733d61e42d6cc2f8d1d2e73d1ee7edea04720a82b0f5d839c30da0dfeac3bc0a37e6381b20ddaa69f372ad0c6ba02d9fa938511e78bd867470d027fc41dd3b2613c3bfcf954213bbf7421dfcfe763cd7cbbcfcfc70713d9fbd0cebabe61b44bd89c8a0dcab7f935a95a61ed8fc5a180ec8e9a04ea9535bd877ab4a67794e7bd24dae4fcba23c8e278d42b764ea2b736d05c0e1a94c644434feb019deea702116132d5a40a647336ec2dbfeb0e1e775b18c163ac6fcc6cd33d2c8cf8e2477dee94f6e9e14119bbe433de5833dfc69af9ddc110ac3dbe2ffffbb1b96a85bde5e79a64cd7cda98f935ac696e312361cdfc3ac5682a89b0663e58dea04576ae493b67d5f3ad8fc585cfaf912f4436bdfbad6f18b1a6fba47fb03955be0c1d2cae7bcef93994267c7e362c2e040f3b3e1237f77a297fa6fb703a15756ad82885b8ef42309ee3fe81861ac6d3ebf163dd75ecae3ceb969535ee0dc766e0f3aa581cea670971df33be863571771bdd4e8d6795428cda461263b7c79f1469f78c658d6ed7b839f2f8e3253b2ace88cdb83a762c075cf6a04a22f2d8c767d35d83558ea5c548b6c6e9a4489e9035b12896d587e70d5953a835b2528d42d8b8d1a55cad91956ad4f4285d7fd2f42c5d57bbf319eb291137a7c3045374c0055f68810f6860061c7c246e4e4713474948a20a6340c20d7480835fe3e674d8a0045a08fa410bd620861f38180c2df0c11454d8118334640107d3bd3b7df7486ebcbbb2061ac6ca44597db03e2eb122cb55eadd71d2c84491b32e811bb90a973a0ed39b2377ee1ecfd242d81851a5563edc1c11f7865577fb707314078f650d728584c2271ee3999fffd2b11f5e6fe2fe751d38301df3813c5966a0e290d781236a21ac8d1b44dc1bfe4b2371ab8fad3f40948a3c787b658d5aa4ea82fdf0f95d3aada5dbd7ca2cb3eb3d9b5ddfd96c884ba5d24f5c3aaeb5565c05f05a4b2ded0eab87c15e894fbc7157666b86f8ee93628a2bc26edbd11a6b77b594d274a7620e30b63dbe56f85230d6dbe7fc3de39df1f7ddb3debdafac9e572d2ecf715b4a6ff4e3f78dd5f155fb868ee66c63b3bd9f2ffb74db27bd4f2f54089a7eaef6891c8f7f6ff7771c356a3fe793acaf5d6d524050c8c0e8a6a13b38cb259b9ed293ddfd94f94e572c9acbf7d6d5d453971a8d6ebb1cd5aecbe88198ae288dd5638871a52df8545ce54ee664a5c39d0effe9fc4aa37bce47473e37d7d9ae3c59dbebd9f5205ed1150f674aa9b91a435b6b59c36e4f1701045da159d8dd13405bba5bd2b066f7a127406a3b6990adb2f3c5e133dbcbb0d5e69bd3810341f44685e88dee217aa33ee88d6e1ac40bd8e62aa634f794c66e50676b625c3511f80b7ee10d415d71ec58ea485977b58c241a6d68cb7034bd1badd9ed9b7b63b1a893bfb238fbae94c36e7bc515575c51cab73cc2eeb1eb3e767fd196ae7bf72195da3acf7639c0b55a5c99182fb63bacb5c67049b7ddd50460c6d6a497c76e5acae80ab5c7cf785b6cedb5a5a663cd363f97f93bc1587574f512810553e09460c58e735c6d8adfd9ef2068437ca5a86009e5045413c69e0fbcc5954ca8aeead2814c34beb22671a2713a51dc4981bb32081585cce24abf4735c174f0844f38ee1557b480a5c90474a271c2678edb5d0c3db03c4d654d824e51aa0128a334f434f0c17c734464bb6952f7655db7f7ac4f0c6cefd5d361e38635eb0e1ebbbec72e41bd8d1b2653fd4cfdcd3a847770a9594b9b3dd5a08c2f683c7f73eb8d197bd29ee60ed05a4fa93d4875dd5135dd9e876958b3d61d53b0a3ed466dc3de6041694a2b2599457344ac284d486d7d873f138c96889bab463ec49f7205bb4ed411c25a1b44c6b316d9730328bb814021dd5b7d16ab913e83d0dbf48a9433bd251d40d4b066ad1ed25782f1a453ecfa9b6b2b15bb5a8cadbdb797c0ccae61cd5abf5f6fd68ff5a4f541d912106e784da129dffb9c7faf093485605832995e3279faacde3fea7927dce10e77387c872303dbfbd7c3dd27f84f8fd61c7dc6fa33eca1beea1ef1f542b59667cf7dae07cf1ed34bd55693f72a9aeee99ef0a0e962e95ed4f75567d29a750564dbb6ab5dd7fdc6e66ef4de956777d09be1f5741f778ff72a763df7a00f486d37d779a715c7d394666ada9c3d8fd2223da042044b00123a0111ce6d04465940c10e1b44f1069cca86345801093f8a6ce1099cfa8302149461073930c20f0eb6f50a90dace928fc591ae535414eabdf814bbbb2badd0965c59ef9e90c5423e2ec92a4f932c853e2cd4956d786267a44a58038f8dda540949427b8a7d9d308221fbbecb21a929353f86755cbd8a3a2367007e0328ee529375fc1aace31ae9daac5316bdb16e7a153daf8a5ef79dab3e3b38fb787c300c5dfa03f24141ab81a7901479eca61d1c432ceef4c8689f619afe8cce1a747e467b76fc636b2b139547151ac51dbb674e108137d6dd7963d775b43ca2ee71677c063fcc04104b636bb2ce3a10e32a86a36ed68fc0fb3b0ed4fe4a6bc51eeebff288ba59e539be7bcff87c95c8d3e33d47ddae77a56883b18bc2e268c7ef82d85ceda14b631c34d3f6da82acd0a5eb0e5d816238bc2beb0f1446d4ebf1c7ea9628c23f2ccec8e250f77162269cd8f8f4c44f78176d309e540a1b8f883c3de373943d382847dd7847abda8eb6bad3ec244d5b20360a7bf3b1c59f16a9f6a89fae3c804eb212a8dbb3b2fe1c8ddd59c74cd8dc4f13243e16b238d7f1710f8bfb8e8f87f01216f73a3ef66171b163208b6b1de34d6aa2da6b46fbfcba221b8f9b24c1ef098b73f17cd3ee9d787bd6559eb4329ce5ba8f202ffb8c36fe8ca238a282c86705108f21267e4011640a211657c4e26a9a248f95e086a2ed1db64377b23ccb0d7bec5c79b191d4713da6edbea28eaca4b4e5846d60c3bc1c3ad8a957ba608fc534b5620edf0f6be2f27bc28a43e3f939b1b10b96437758791e51774b4b810421234a80912ac10d43bbfb27ce18bfb3bed7d08aaf1274691eba5d2735dd60dd618ab63b91a7b6bd12476d7b77e9baed4975da58e441a1b677b2ee4fd79d1279c68da312d91e8e8ab4bd9307c14a53f6aaaea7bf93fafc449e7ac5f6bcb30e8a3bdebb8f88395cefc5fe441e18db2b71c0002dbdd5e293ab34c2ee23bceddd862ed66fecf784c5d5edc4f7e37bc2e2e8c6ab12f7b078284c929dab338ca5ee1dd35c8d7bc3f75c464a2c840a329e14098b3ddcdf7777c208a2e8543fa26ed56fae8a4681c5fab3f1432c449a74115f3e12128d1f80c8cdd81c1d9460458f20a740c82adb16a02b1509ba525f8ad99a16406a3b311219b0391df9369749d807079d5868e35f249b2f919cc791247fd3443d61c4816e517cbd5ed7b1b33e6ba886c6f154cce2535ac7ce3a47b747f137d73eebab733e9dc29fc2dfd8cdf21310920bfdd83689f11e04536115e93e6fe8dc8fe338ae76ec3355753efdeafcd4e9e67b7ffabde1d57587bdb9df0ec37cd2a10ef851d4b9bfc575d72dbe3efc9df5ea293df251d37d1a5dad5b5ccbd5c2819e556798c5c1c6fcd36fad2dcfb13ceb4b9f75bfaec22b107954fe3a0ea25bcc74e763a151d4c93ae24190fc8afe474dfe448fb7473797726b7d641c9b9907712a9fc562b14e27af78a74e6fb5708fd64faca263a824ebdce78ad4a91911001000040013170000200c088643224994e4609cabfa1480127286765046980984498ec32892a31842881842083000c68810cc9058011f9904d6919f720418a5292dacea0199710f21a4081ef30a0c3e8261555c1e8b71a67795b067b8b4c5d5aefe72986b450b3c99043b880287552cfd948a599ec4d078a2f5a530baf231ac8ea8d5ecbdc50af1df4445ab6c135c64947e7482497c4776614f739bd78922a700e8b83027dc998cd5f5634eb7e51d8566fe6413c8416ae6032a0b2875c29dd158df9dfbb3ab4602d68fc35bf65cfc41746962980c71c82f33f23efab5d7a89b4877bb0c57875ebd218e4b6dc4b96da2b952c57c4821e3e57055d40c2cfc61afbf0213228767241eaec0a1a31a76c53904e6d12dc60a2e163ddf7c0db127d000cb8534fd44f9816fd910f0bb9c86a16c93dca20e38f10a20bfc443ea6bb48d6241fc06fac856f0357c0fee98300b4b54e4bbc134ee288645c4b1945166be77657f206fd07ecae25a8d94b6db64cae8c719ef8bdbf42f31a7c939c5577cd0e5a9ba28adfa4d4d5de47e3812f9ec04ac5bc63a4d77d3e3e4ea6cfa011ab2a662345b2ea4557ded87ecc761587765edd6035d744e87c12b0ebb75d7d12840c51002ef8a6d03a029668cb66ca10d1d070da1f5764f4416c468716d37da8750fe30619d30df36ea9700f2ef596f072bfad74f9624647f490cf397f25a2d05a90df4bd002b066acec214d3ce30a6d7783ed84a5d48fd2d4a7aff8a5ad8e7db9b22df9cdf54170f6b6811e88969d32b313752c03ac25cf9e68e487569fdea01f7587042fa93c470ffab129f0eac6fddb69b62afe77900fea0ee15ec3410f9fb9afc55598cee67decff885bfc0926a92c2751fa720c8fc6f252293f9c440014f1d2e70f0d667e513308a125498a6ad99d6181b61a4c266331362160d5d8a6b1497c3d5445c59693f2717e825d5c09cd065b9792fbf6adf5b5c0ded870bca73a3acdc0b72a2b41f704a0e3eda9c4628a9a62a8a496e0f03ccb13636658784b5fa4059b8d12ec2e6d2d69b92a7852b4bc4e1154f1ef952082c67220deb9a88146e189fe2933380be3b964f982ea01785b4060214dd9a08b42e4ca6163b40f4e883dcdb6c5e9812c0c689bcf18644b2e9a70c0a58ea64abbc5c6a2706af552e6b6a68066468222258d7432c1f2e5a3c2a2f09380b22b69f9328328108c604853bdc6f28ce990277aa387084e6e98dcc8857692e0e8e58f36c97c24cd44bfe8978463373caeec22ce0ab3283c497912c4bcaae819aa5ab426a2b9bc9f20b36a6fc31a2936847553daaaa349f6a1495af89d86fb5b6a04674681b1f4f22ea51a4af63a41231b2c6b306210e8226965a3521cc86e29d35064371feaea6e9195c678ec8c20be1a60cd9e4fa64ad3a19b6de7158be511a6e1a0c43f7ec9723249ed4ab89326249b6a210ab9c229dc79bd0c5e236bbeff50c9173720e14bb733022b0a87976daf2cc35341ab5c802ff572767cd5844bf0e6986d4f3e8098428fddf704abd9bd50270c0b2a4dbe3192d9a60aa324dfb23190bac19b778226b8d4f79e8ef12debf38891802ffb06604e6219d5b2862e8a87239a2014261ad1581651c52270373b30617f18be1d3ce1d227f007686e52c31a3c4679bd75cfb1110c620dae648f43c0b9869623891a48558b5f01153ce8b120900899862ae4ca7a9ef890381a240d4de7c533f8ceb87c485f58783b9964b940351c7d55c5a394b604a2282daee8feef0f10421ac186b7501fe69eab2dd4732dc23718141795697af0e64e02c5003381f0ddf15d0a1f3b36e986ce7757652dd3a010c0824234cf2faeed7db1dd8c57bb2288e1f7f7898f7326a123dbc037e4690765b8c6cdc60a02d809658d62ccb20a47a41d6c1b4de6db348f1dd9f517ab0d6adbf7e21182b5ccb023ed191f8990057e6952525e9592ebb862e08d59e6a62b29c3f4335b95b2df1545ea8759ec4734b3777a2d35c2eeeac6e78197be7b0d8e912706246252781598b739b62d7c94d8b4a13b2e360758580a71e144e25ce83694525c3fdf24303246556e099d5465fc1f2a031208c795a1f6daff37421ab03408cfae474c803c1098e37be0e61e3ec0c5f05b61eee9410aa42067ebfb97696a03a58771704074b5f8cd139f8a381898c6b62d3bee0041495ccf9cb15448fab7040a4ac7c0192519f5186cf9ff5a6535bdfb5284fcce2cb450c8118c5903739d9934d3cb93845f6160b2408ef6641221d1ae2c24b84e88ae9ec6b281ec7857f0095c6f857392b1b001b9ad12a1df271279c1055847c46e34d7c0d7ca94a1541eaa6c48168281daa1516f817618498ec610b5d4804b50f7df451913075c3e7db95611c7ceaecc75611c5f94923f33f22a365d49c3c78c910c568cb4e566863210e1e03f9ba27be53a56525dd202618dfbc0406e766adf57b3819cb586c9c51ede0649c9c44b70e05f4f1918fa5d50e3ad41519e1577b535b4a4a2df1e638400fb727f53a8ddf51240eb6f62f18be8974082b31a4635fbcbd8eb3dac8e5c9a0b14cba448f4d11aecbab51cbaa62d878132cc583f1457ef4fbaa5340c964bb4f31e68b54b82d3e499717a9d1384e42070c194f6f1b368d829323d00714de5eabf2460d23db8e2850699ac181f0f52dc0e6f962143e50fafec42fd5dfe9b4dabd9e4c084225575c9bf3c9c4e061f69af44c03b78cca4f87678d2270c6bb413de2c942f39c286937082f6189d8871b71d4bba0869a69414b5f04aa63d1e059a4dc545593406109c9d9fb3b54be533d10bc81da692864b5e142ea5a4181f1cd45d3f8aec50b06140862f97998c172244a466a0907a96a05169c0e7042126cd37146be1a0bdcfc092c14a6f3531a3f2e487f3615d0bdb0d9f8ce7d2e8e02e197697fabbe0fab85b259d146c6ac44c1398b07675fd809b53a1151aa8548723bb89adde52c560d1a2616019376155877adb2546c801b9966b318dec5c3c723197907f5fe0008c101643e15f05520824bd403feda5d6efda7dcb2eec6345d21e40f968c697a2b9cd02041ffe882ed6e8788f3c87c66e563870bf13b676d3285a328a6499c7ba45093136a906ad78d79084713b493bc240d464960e888696658ea72d5ff7907c4d8304d5d31b798f5d37cb3551d161c9f62a4b6ddd181eabb87fb66d67a51afb05e63a5c95c62559a3ea44a136ba29f5f570271f6859568833a4f74e3aa3851ea7a1925b472eff182d5c58759492f3476bda7fa7136a7eb605bda528d15e77c608ed8a88216d49ff017db9619fa9eba5d6b9910d1daa2f136a59cff481f9fd9695695938097391dde55102aaa0c19293b93ca9382632fea22236688a226732336b8a8f7d3d0c850f740bc92487fac45a81ecfe90ec1920eef429ae5ee43ac21cd96cd0186a0d8040c71867869e08babfe3a007a0114b6da88db0dbf6a2095e94cd50393bc8f901b01f3f909f01c8d508ceab8396450fdd8a083b762a952ecc4043b49239772d1026dcdc6b0d6170585831dd5661f7c613c299c0b7f048e895070d5faccca7e8612466b63e2754fbe8ab2ad9628554835e5337727045560f299761cd4f9ff137c667445c0676ead42b4da0e61b84f5d46074f83db105bc1a791241c77a668e75c37a433caed0bc2fa642f1ab542055030cfccd55990c5fb3add7d59d66ee414a24f2071a87eb56b91d70ec4466baff7c8dc01812daafab1ada1f64213c39135670668455c769feef1a02c4cda5122c922210a1592314b4742ec2f44312879f8cae9dc9c143b57e9527fa15dcec4f41dff29350b6ae9abca810de2d94b6459ac158e18dffffe7bbe867d57399a483e86a20e51ee07d14f509ed16c4bf8095b4ebfcc16000b3927cda2a9f8e0c4fe9534b3593c09b027acb3bbad1b0c9efdf9f96f48aac585ae0775a7ace40bf4a1db3e79f21bfc9fe13998ea74005796b13690bba9b02c08cb2c6ada6ba1373b04392fa18a97380c39b802d3c98d5b456436bd4ffa4b8046a9c7e9a501bd2527f11f600cfb90d76ee02a805a297b1939cf0d85c2032c6b2cf4592c05518c56ea926a057af372678d7ef8b41cc57393f6cda378656541ca66a6447dedd8447c0f190c63794887dc56b3300d882acd1c9d742b1db00edd4ce450e14c047d327b39b1120490ee69e8e49dbc453438f911677ca1e94fe14a524a0e4fb033ec5cb1c1d6f0f54c489f7b61a7a8134e30c2bdd7809fff93087c08a0db4eeafda9e26adf545706cb0f852c687de206f8a3bdf43b3adb175ef666fe0026d5b4924b75080af9f5e14d37382207fc8ecaa17dfa6625a70f58c4f35a8300737ba7b7202b3bdaacb6e4b22303e6aee1134eaf7a757420df01a0325b89c784c7cbf0ac056728e1cee015ad808712e72572df2df07b9569dea31b86ae4345da758e9507f520832a536aab7d4083db534b14eba0c4631408e63720cf78633af7be966eefd18bd4f6d80a28f3d20742f5662652952bcb08a79ee32f60b5cf5e754ceb4266e596cd4e814c01a744f9ce964dff7d744eb52ea14ac3aada5668cb545587b4d832481203bc15a814aeba447ae8c711de62113b0eefa35c71fcb55883599b194c1d62c280633802e77a46c76d9a50fe68510f5d4c7f982ee9902c14e93f88fbfc1b8a59a206a152d462fb9b69c57c10a4fe4effc2b81dc1ea89e0b1c6feb1aa1776d1eb3a8ba77a4dc1abf412a500b9995c3003329449222821a99c119c32985ea46247fcab7a0401a9221893bc78cfdc1291c5039c3ed9a9aeaaaf2c8eb90222516c604b4dcbf6c34564177572ad839284bacfac637666ee23ff06bd0b0b148b548732bfdda9ed194200981d727128a0718f54a49f1d7aac94d9f0f22058a1b4e1f57349ef48ce1c59a4489b59e31e16ea823731e4edb8314d63dddd81edb8e4261d4859301d1d0edc4b8955e9530b4272ea7d5f4e5bf805fc47e53dab4db9672ebb79f1517b7c7666142494e002aba4b4d32f7b89e9f9d20545c7aee0bbf72a774855761760cf9532ee0fe4091101d8164763409ce906eca65101d2f4ade4ae4b074dd09c1b9e8ccf969652835b1fc6a09e229e010941a4f4f6d778d0c0c1bade16f92d2f3b4803e7426bcb4d87513bfb83b3be72f2429026df50f95d9c28760a1fceca1302deec809bba45f0b1d8b4ece463f9b5f20810f2b26110ce9a3a32aa59d14775a1261e83f4d3076e34f07868d692778a5f733aaeb3f95f5fd613328655343b83c24b3727750295363154144335383566f97cc569e3acf6b0199c360d9d43a212de86d57c1003e55f469c30b58c12d22110de9966da159f0a5192191a1e965cf84cae044829f537621d4bf3fea03331536ba9ce595b50c4876b089c36a49a771cc4e7626ca5e824149123aa6c8f660d477d15870cf91c945b4fc8873be270a9c05641a3b750cdd24cf47c16588b23fa53b5c64b629af9eb38a205fb9b38fdf43ae29fd15f0ac2f9d5f349c5e63c0e4f5fcf1d8b055e5ba5ffceeb895cbf1c2182ed808bcd06495472b7b9f711460e7998e1987b2a365827b146b351bc70f9aba63d8ec765e12738ac66379ca1d6977d5f3a44f31e5848a0327ed2690e119c96b3e0a44e985d3f7fc4a25df0f3622243a4dc5562a8e678d42fd5b40bdeab67e506219bf4a91a54900dab29f2cc1398cbf2ea5ed46b9ba1ae7702e890ac9fc230b61f2de2df379e80d4a7842ab10b9d96759df8b529f3e594b31435ba2ae04115418f3b7e6fe9725864962700eab577f00216b8e5208a88f27dd8cbcea14a41bb02771a7af0e4d0ba7245c1e624859ae330115b3a94f6b24aa3ce039ad52c018ed765d20fcc74bdecbbb7c639bdd11b6701993a9afd59c2f3dd742cbf659a4a3414d58720b7d3bdc9d5c1451f06c6d162a89d52ecf67d7194a3b24516f1f01553396be10eef0f5bf348b9cf98b7522d22f2971856f29aa6d738cbc54151519f16b8d4ec47397229761c32ad779ae020724430508b0b8eb2c12706d45b0a6e474ae795a4b0769248242f0de00eb0944155d8dea29df194ea03e7efd2a387cddb2136dd368ade74e8e611ada2d6a91cacf943d2ab03856973f3a88b15c5b6e7165078e957c0abe961797ace07b2ab59d2346962f50bc1b85f48452cff73a1ae70f4605ee619369d2d2c7bb9f893bde9bf1fbe7884bad2aa03b1558fda81470dd8aaaf5a3c02b8470a879a5846d040a1270d723b58d36785e1c78a620d621aa50ac71d573c77950ff70f68400f85d6623009f199804c018b554429904fa1873ac2cf649827098a95fd9aea551ace6c1a02c4e418658e443368ed5f045c3618315ffc79f1e9488307b59e969a9ac3e8a562218536147ecec19e38d86a1dab8c7ebc65dfa810d540abf4c10d5d5cd93da941de0d836ee899c80cc7d03627dde393743145a7ab635b6e064ec9be4d2c774d11ec4440b437954cbff86ec0054a3c4e7728f9d543dfd65e56e10ef015e491dc1171cdaa0a02344d8c12f58d49a0dbf8513a81026d1061a56008ed0f64ea72907fc890915bff4c7c6db46bd5a8a442f1e432900b264a73d858e7423167e4a6b31ee2b192829607201b8ecba30ee1d4050aa68ea79fcf518b22bf4a710341cf489070a380cd6281de37e8f46ac4d880e12ef65cbe1777ca2dee2944a64464b43c0be34b1f39cebf1ef429eb930f251eb9434319307d81a3a7c340e5d5a962a845cd9f5b652e49367f323db0d6934cb6b081b0e677f027ccb868291864885fc90279833ab750aba84058cb74b603a3caf55952c8640576ea3652ed60984df2da0116dcc730b502d026ee439b8ff1114994a7381e1e6d3ef0b4cc0a420758573869fd7791669b8b289392bad2c39cd236296e5b9252a6594f621c62fef8fd09971e02a15066fbed976d1578e6ba89814d0c6195e0c4cc944cba4d60527e1ce1c439b39d4b06399a97e1732db9ed62769cbe92e11ac9641cda74991652331e44edbd392a860836786d4fa6baa1478ac00380cf91f8af24bba1b7bfa11de250ab38dcfef98efaf02d95ca6a539612296d01cbec011a83591ef17a45e707cda15e2778bb5ac615222249107f102e83442497137c1b887ef2a3cc0b8f8f2ddb15c390a626948e39d0a57c021322ec03214853ccad3441e208e8682907144aa0540997518379f0c0310ef23921149812b585aee70947585fa4d1cba77d761e57106ce6d2d7574e5fdeb3b3710aa6752f6929a7d6386ae79f9ed2cd2260a365000ef8fb0edd0f7d54ea341023707231538350e3a121d6c1b88f7728c0d5d7f5dc1aaa89160bd7d4e59a415d45c736a2ee6091a09e2e31cc988fc5caba444d1ba04deeabb0367bd47593bf2c80e10509b94df31b1963bde3e6a19c811260e80037fcf22cccdc8c5a2b064efeb4b18ee4ad099fd277c8b405ae22de8bf4a8ba6d2062cb1fcbb3689b43f236783a64d641907ce99281f47a918ecbb3180372a0d385edd8a5c4c2a20a3e1a15c75d7a8a69d57b3f649511b72b19e8993c772042e9b20c04f6373f4512569780e2bca5b79c732a2726c9e82e63f7e04d01dcee22bf8252ab12df8582e94cb94556d5addadfc984fef57da751ece9e2e79a06172cc879892dbf4c7ebd1166fd5955154ee655ca604fb30e2cd8a8c6fe126944c3fb6ddc19f92e853fa30c05769915f953811c53db1fc130708dea31212c3fec3b2301ec60167ac867a4629ace9c9be2214ee66de0d5b419583be6d12d649b068119d1c43477a8ed3df2577a7f31ec9994a61c668c33172c11ee084f46b2b075ae03e52b9baf0ce2e2d742758118a6049bbb5de8ee0ce9a95ef967b6ac97ba2b4ef2d24b8b41cf69827c308330e3da9a5a264a2240e9c8dc4146a19b39cf4e0b49ea9534634236f46e0f2e6f16508bfdc40322726f6c9b14c12d0a9d7352ec6861c9f62cdb1fbbdd2dc66c04bae18406b35c9f63f64f0b3dcb305a886016f94ede4f25120de9cff65a8902a2deb126ee057ee1aeca05165ec3f18c731f4388897ca9248c481124d3708a20280f5b38d012813357e0883b7456bb0c70cb572887d24cce3443005fde1da451fb05c3c0068637baad14442ee14cbb7504b80b190741348a775049031133ac7f1a342e9a82ff3ed136847b6f4609016fe900dc18140a46b5c4ea0d1d776ec1df0724b2ac083b0422792d9520cf9d843227de168a05b9c5705e0d0b7cb340225739bda03d6d4cae5225183f03a0942af1fc0e0577a5d104a808332e1b01a4ae6d2196f09739506c302f735e023128d132ebd92970bcc2d65fdb762bb75338623cd183083b488a3f490d7847c63ac9a0cfc46b11168b4997e249a81654e638f3fb5a8abb2fbd34a264326a5cadf5f353d425d302f48ae5fb34c91c16c6a8c549d85d77414348042a5e824affbfe93db707ad35b21c137e0461add58b618f3e236f76108be427f1b88bff0418375a9cf04183a20c036d48df04b8e6371c55a893af76aeaed2807fefb430ba51e3af9855b7fbc6e4afa48707b0f35e9f44a3dea145806abacd25fda783d8ff9c2d67caab507048021cd83f128cc8fd1b52575bad13cd00714b486203b3ef484af0fa96f1e8f7cb38f5f2ba351896685d4e9520552438950fff15aeecf76c05dee3117c1a9e2890c9b78f3ad3915bb13107d2c45555f680437c0a964c8b4c4e3708ecd72085e07ec1c4c467379919f94e44f8b98110516f32e6ad70411592de9ec3b901e3c68ada09de8a551969cb05e8e34d9eb21f618e6e916c89a4eb6445798a7c5aa8a7d71cafaf465c78cc6fab18bdae71df7fd00da1f38837995c8853defeec18af6fa5be6d05e4bd28914def9e026da77ac1e0a5e78dce5cabb4371df91e233d906b52baaf866d1142ec04a20100a1fe8cbd99882c74e59a3a011063bce0d2c17da742e71baef6513e31a2837665967afd1cd0c3432a2d8ecae1b6a27b20375a048079b35f8fff9fd4e0ae5ad055672491f088e9ed52ac004792591d1d66eca1f1914378b3fd7b34409f0143fdaf9e38ef95b895441c26d8f5d9fc763ab84dd6cfd25095bda6c3f13b8de54666797b60d32c6460425f2a3483ab6d56ab2b9a81271ab002462be3b611fb6c3719fc6d3150a200d03c7bd563b2878d266f6b82748f30832c1fda3b7a334c3c2a8026f17fd377279823c7ec7503d8b09cd337e15db435a2590800ae41ab821fe63d40a64e1a32cb4a32bc4366adb00a15f0846f2123616a831360a37753841ba01ba975c9d813e19f266470416edae77f51aec27ea17fca524ccd7ff0634ade693deeba11e3295361709af7046e8bc921f85000c30695a5fed1e5380fcac19244116ccd488973571ca42f4b781f00e3d1154fb1181b6f65b0143a4719df95bb19a594a5f0d6d2c5cd0321a79ffa1b1439290687360bb88621b006eeb2e03e1112c9c7c9af5abc7f10ba066562f1cc51fd1466fa41cdcf1196b3681667396233772a73ddb05d484ca0d87095ffc4fe13cdf1d4212794f35a84f99566c694ac779c0fa5e5e50b6e00bc96b50364f4c0880d886a507b422cd69f1de99f0f9e6963f1946bccead7cf51f9b0bfd601349ca66777998e85596fecd797600a5a4e8561b0ae32c2d055c4bc5f9ad8fad2c15e4b9629c7c95e7d7580b808378ec68e47ffc7a9481ab4b51092b7848a9646dc2ca0f3ff593a9665e99c6f53f984466c32c2706e0bae963105468bdbb28812ff1ceb69e20d57845296482ce8ae4684c442b924230cfdd5acc32acc96d87d0aeb41970e5c832bf70b46187a5a2e92ac450f23ea90a60986ac89b3b28f285cbf386580716a45a9ea33a7a91824df8647036f55a303023e9e0b1acc4061b73a968fcfa74092d53b03ebdf0d40542a5995a9ec0ca604f3aef5a6e11ef166211d32fd5bf4e51a6d5d7e49474f51e89ca598793c2caf3c25c60f94f1632c044762aebc7d4417e1f1bb3f173fba06a3a9632041312a662bee7ee6fb42a50e06657047e69f83e17da145180dde225dccdbaf64c3086eda25326fac28b6fd98e1c64a7af7063700f7f5b2d980f65756cc0f84740ab357fb0c96c47b75bbc7de0ba1227fa86be000a9449b10c1ec7bc3bd37b2d4e49cf81ed2295066956dea49814b57d95430e24d9013ae349ac43dae505f70efc0a1f388669bcfbaed6617037367a58dfc7c9c756357be866db2bdd7b99227a48d866b83694dbaa9dd0caa471790c4da21e483117e1536bbc774613348f492c601be70886618d961c280315db220bb5eca86dc8e717e07953b6f0704a9e3bab9ab7e84ff030a8475808403b42531d78d6768078ac66b68a679ac6e08c81b6331ee4158940800a513e83ab8ceaf83e452a47a53b3638dbf0e7a233e80a55aada9872c686ab654b4034a942131a766776fba80008970c11d91fa923b6cb64797aa01d47c5796cf9764bd9935a0ed9d8f64dcd8842203d2c7b2640dc40b4e8e89f48d9cde7a5a8d35605c5ce1d533c90a5a67380e04d2de8ed4340c0bb528bf1ea8ed047fe9edfdd8a17fb9b15421a9d1e125a274b03cea67a4f89f67e4da51908dfcdd2874f82b77adc289cd5f06776e9363e13fbd55a6c86fec0897e1f1cf40c8705b7b6c0dc0b58e173f2d11ae073225f9ed69c3ef747ab746315041b147183defb5166b428c6e61ff267db2f70bc5a97c78556da89da2709ed002e9906b6f59deeffd1587d1334a523078c30039bd21a5e204b293bb968bf4f63624495729a2e6c781382f6f17ad7c71885104650ea4df3ca05d7269d24ed9b3d3d427d3cec949df6a5e62f8510626554c607f2acacc4cbc95c12573a08ea899d93c5ecb61a5b793332ff880ab4c12178532d2776478750b34cdeb68765288fbe9fa1d6ebb65beb8bd7bfbcab4d115c1c7ac53d66c5f08dd82be460fbe4e7a1b9d5e0ea317f7b121e2b7c50d0e55087165bacb7b40ecc7ce9c39b8334d8fc1b0a48b73fcb2a494ca990bc5eba90ca988cc21e4aa396b5253b9a59109adb1c821b26eb182abfbf8f984989c1c1a20ac3be7e02aae837fc4dc3d4c7c99cec06d8961fa37d1bc0960fa3715115128be7b4df9fda00c3b1a386cf7ad17622182e5a93d6eea03e04e4edf73bd8a1a89b37dec65f725e799e306292848a3f70fe231525f583ac80767e89384e6a3ad642c3beb0e2087cc62a5227bee0436bc81d34ede2bf057c923d33a92ad36707db8ef90ed0dec47cdb4e9b842eed15ca8f587df86615fcf49d96ae83bb7b5ac6810c055cc850b7aa66427bd876986392dd86e611d3f6e44a5dcc979236977f999b0c10f4358cf4e6edfd7bea0100039b108960715c73ac783db1b6991fb9fe1a5907a3b24571b1bd71d9f7bdc0c7628e1fbae4161963de7a74a5d1a63f0d00f02a8a5eb333f495e676a777c4c88f4e6729455d846f1b210420bf4c9850426f668d9212b77c3d7d9fed72433ddd630594e3ae2263e1d5a2b445b3ce0eeb6d609ac199a8b79e0da919d5b39934d03e75f44b738f5d2fd43c521ff0eba1cef879655ac5b1cbe7a420bedaa325bdaaf1902c360c28b99f603937a99365bdf830471162e9a147465a6d659e48fa03976c4858ae41e41011554b072c9a4cadc13ff3655eba7c7b0791717352ca450f9e85c23c5c1df66d736ff9b949734c0bccd035f77a8739ac16a07f339caea527d73d387ff2980231f7937e1d94c1a75d8037e3b578353f99bcf5af766645ddb36704213b54d51b52d7e5717f1b12b03b12a14becfe0702b20b80cb182bbf92a016641ea4a3ac7057a801a8a60669294c4a2fce56b8f8f48ac48eca0a201858d84af1fb58c2a5df01c0ef12e208c60e97c7bfbbc3f693b6784bbf0ff3036c2ecb53a510d817518f5293393da49f6202ab0f5a129c2db88c74baa1251591b8cee3e576527fe90a7a84e7fb06e9e357a0b1ca826a4fc32302216a6f847b97c9fa18671b46ac26aca8d8ed60529e85e385a462add37ece8be009443977ae7a028d87959284f285e360712b39b5485f7092e31b3ff13a0a4370a269ddf268b55daec6f73472f4523b87f5a22928adc39632c42b4461cb681597912ba77208cda606914cc69e0bb3fb476d6dc36ad50eb01fabc1a0b6114cacee653e400ed310ce2810373274caeb94d55a3cfcd738ce7d4da928595c6feb22e39f7234e9ebde920dcda3fbc4817fed71c14fae6e00685c5f58b07201faa6177b592a582a9137758a1b0aa4eea6842a3fa0dc94ae853d4f355c7695d97965f56ebca3aef956728fe0c73deccb7f3de0c03e7d9185fe71e5c98c340bac9108b283f49860657e626a36e61425d12e0e29af7f2d2fdf1bf015eb8d257e3f07c61ea56f632d901a08ffd2f052504e63d932b4c6c7746afef771ffd6cab95408db7e8f737c8ab90d57eca5e5c458e2929ca1271dcd6a579293f5495a8a6674b0633e70584330670da471ea99e8504a3fe00b679c9cc73e7939771f0fd805d0b1ddf906ce1f36c1b728e6fa239d484bfca86143dec718768fe48a8151c3197c44d448c8bbda3767849941c2d89723f5d1635474ba274ac4b4262cacb2fe388be5c18c0aaada2f16653e3eadbb0bf51ec20e846f16d537f427998f6bc8568e12e1c28d1d2566bcab999f6aae6e44fd1988e8b633586291e7115670a9a0cecad7a799f2206edb5c2db0875e9b02ea0c483ed5a2de15e07146d437816e3f56d40781c2154309d5cf5444d94cbff0d809692bf5b60fd3cb587b0f73b9ec51e45ac9b7ed42350998ff78e96a3bf21c71ab1a07375bfe31cd357db101ab55d0cb6a948a26606b7805444d54111f73bfc826a76e9d7dba4afd8afb48d20ab356582ca71a617e100591bace84ea52b9e90b02ce8a9c2da62411bdf047ba9a546d072d71533455c1f1f9553e64856e7c17e3423a8056b234654764baed26a484a9809819f6393fbc5e50f50531bb478ee01f5f94e6560746ee0a371b7076c24ac5b8a07c9dabb5393f50a534566aad223c2c09b05c878f3a447f4bc8cc9bdd9fb8f909f9e177bceb5778b664e6480865808a076e8f6fb354e5c5b3af473f7aa73da63238ac3e7f65f13cadd26926ef076c0123c9757427a42dccca7d7f3715b32c2a821efbda6a02b3352940b66058d0457d671b9f9242041cd5f267d59b76b18fe30f6973dad5b3be267db53c24e323c2a681948ba2e630e16591d20e4a7ef1a207591df5590b9d7364b9a2108964a7d4fc86e1c2aa5a658adc1e0a5ccd7594a8997a36884793757d6452ca302ba23b25c3f0a37a5e379ac33a67a90928c9c82fff695b3876d4a4dfec49bb3ea7514fee314599f2cb79fd9f70e9e4810424292a2109a716c103ffb6b3534b4ec8d0e5fb981729102ad54bf56b0a89dac85dfe7b22d7d850b1b997430139e30ba12625c749a30d1ca96ad924fda0bdc8344ba0bc201d59f507d8dd02b610aa07a809c3a1d960661f2d06d7c79c8772508d5825ac675c018d58f709709571847e6339e0b8a835ca018cd4d5351063a6584b21f56d0e1070a05b89884e2da167012c8e81801c02cad731752d20077213f04440b2c04e52e24a06186edb522c8432e64a20896d28fe4ea0d385c241e367a511f35c5fce0d4fa8285be9a13075e04b07f539df1d97ebeb9034c7ad227c747cbeb70e81ac845efc850f072b893571f523c3a8aef333ab81932a3358ad633744fcb2a17c13b10304d7a17d956c69dd6bc7f3eb0709562e2fcf6ac490f53c71eea5586e18286c95d95f10d4e1edfa1ed42c967bc0a601b3a633415ea41f8e55cf7a89859dd6bcf026cfb56af62cfbbf3ed80ccbcbf704eba0e66e0db7b5207ae47e5d092a81d5906cac2d4929813d1c0082664cbf427e4ed6c4de002c9b46d07b6ba067b01d4fb43415255e3cd05fa095f9b90b920ae4d9b6cf0b7661ea1bd1aeb9221d992309b136a72b88a3768b616e5bfdd7de1dc0a9d359838eb2ca60b9eb197178c9878ee93862b46ed0926d76ca46ac183d9a60b663e748e39b07b18c3037010e7e468118c5cb545adef750dfb7018f28b30f0650737b5a36ad33bde0517c0559bd718c775ae8240e1e505de4d599f1d68a4b16aa604fec6a213672d455d1c749617585f3b275e6151a451c4ba05f669c946aaed09191d2a6334eab87a90f4d9d8da0c5a86d2b80a566220950eda262ed7067ae7b49009a8c89f576b2f10857419c8c51728f3be17485fe717aca93446020b9dda356762f64d9d12b9be0345fe5e90c918e4670cb82702c07f56fc56167c9e3d83155fa06601fb0ce50bdce74707062845aca71cd53bc2bd1a1958be20a4d48bb8c99710acc2ab85e577820416213c8d32f815c3abf923b6ce5c48a971d755f9a05f907c464f7815c0407fc1bdf6c8ad3f2bda88ce5cfde7eb4cf19d64478b565875ef2e73b5d0fd0b9441083740ddcb013008b48fa91ebb3ec567b1b22ec8601d6010eac40ebaae8ca5da8081c61627567137c1fbc0e7896a72989efe4b7dde46ef2bbcf3f4a8acde232eeb063fd88ec89114a4919ef5986ccde786725721202df58f6236d4150c7cb863fa6468aa2c00c2e1391e0c88f8eea1e3e17530fd8203f357aa8323cecf54c1f0dde365c71fa977ddad090319dcc536652e0b2bc8bc3cf6ad9f721c296c292746e2df17260cf4bb473576f89c734ec583887f38c87a9733cda84b8a5c9b6bdb247f4a5adb3e8641b87aa5ba58aea252f00e5b4ab39c7a0c834d6208d3f2b6846a03cfe8461c08387570360c7680214c8bf712aa0d9e45b6c4508c3b3db69c4ef2d4c31b8aa8e90e833f8ba8686f2646515c33a3461a9579b086ef306855fac15041cf811830f26282bf3054a3a79873b6ee9c90e2ad0d2baada3cc392e73df71a22e51d7a1e88c1d7b57e82004a383f30c311f2cc904fe1af0dab0ad456c4e0fab74b2175850a16b47e2b523fd2a7b072065fad39e18091c87e2c84174a0cb21a965d6123ec175162a055dffe024a0dbfe50e3106d416014e3198d064d5301273c38a017471d1b4fb8a22dca7648b90bc5c0deb19e5f49f1dde1be21783a552c5180c5e7d03bb8c41b76b4b41637008345cc0852376cbc83377b805e9693d06faaeff2fcf90445067f93f6bc4a25f4774373e9b40558f01623d2ab69797c0405d8e40be91aaf7de00476c45ec1f03234bbdc9f8d4f20467159293703b0d46a842fdc414d3313682d69fb020644031f75bf77434b2a1c0daf2f10770460615334439d0fa1f19d48c7fd5597fb6a74fa22abcf881c5703cd6d906cba6c3e6dad2fff9d46293082656ec2b5e9201290c1d7887be0f28c9e08600970cf46a097b0d45a68b555c5666d04a9d4333d8e3f916991ed77f2b64ffe1835633c867c5ad814c2d3acd00aa6935866d1370369a3a01fe3cb1a386939666669d849f3c7a85202e4a2390308f90bfe30c0db8d98a14aea7780d281bc019646b10326aab7b82ccddd6f3f1c0bfc019dc0897fea9a54310bc4ca5658f7e43a8207e86a50cbe98abd385dcafaffffbc09c9d8a07a094704b0d1d94e9c1c5d04a192ce1a07c208b2a99686690a10356f9997cd1061cb27193c6bbf3d04afe99ca06525f30d552edb3b10c1c54ea1c8774ecbc700e257c193832e319fcff687688e602f61403ecb385c2edad26340345644fd29bf9730b57dab0b49216e849b55a2a493f612143618f412129daa280734e11449f10d0b6debc9c44507c6f68c4ecc666684957635f69a6f1838c2791a44a5a53006d27364393b8807dd1f803b0b187d9a305e60c08370080c11aeab0138ba027e70e0d46ee2d857e3d03df06c68307c508578778872460ce73a26f80797e9c24a087649cee9c3eab937c067aa5babf26135a130d9bcc11ca8e3648fca2bec243e4ac07a98bbf15d3bc6252257ba143448a1ea26fdc1da2180b881bac0190737f673507b05d0e6263acf65a0f5c70b7cecfa031b11241dfad57f86750d449118237bbdcc45112ad1340fd6c6600810603111e9e668cda4a5b7fb4c837edebe0de90cfef21fa3b1f10d57aa334574f228128bdf0eadf725424dd743db65ace2bdb1707926e08713d62ac009ddb438af2a0ddfb21a22efaca58536616c5f1219b84aeb4b9046bb4dcf97ae8153e5aa627e811434c19123efb365006c148efddd3bbe048071053b8b7488b037fa18443ff7ed3a13a8242e501794b587f59606cac2df10d3ffc8776166646ad7b2a201c6a2d9c25a20252238355aefca56faae146b1749c354ec7a0ad06458f3cb4474daa856a0ab0844f0a49133af7919da3efea370bc401be9fa16455fe520e0e9f7d957f90fa124110ad1a4a21c7cff050a03f060a8f8661349b098b64028e97d05290a5f3d99657de25d4e6a4d5939bdf4ad1dc14b4dd7f312f000cf8f7e4049fc47e63643ee3254afda6f3ff4507781573c4e6edc720ca539b22cdaed6f46aa0ef0b2990c1322adb7be9e9203a64b0880f5a40f2fba0154206840e4c6e405f6fae38c0ee0c1fd44157ecd652a27733f02ddd7c1d74450950b53fbac380a6f824233240a3e4646e11f141e92a15870919c8ca900c40534ae5b9307b4cc2c28b9141c0e6a6ac3c0cd97645b92dae25f09efdd20cea049294f3d12b845bb94c879b1afd9ef124ad27872d9f16d667390fa10a0495bbc31f40d21f180d4bc22421e840077cb3a0e504602144360c701e7fe029459055a6c45afe40754dff120481fc749ce7d0bc42847f30ce5e6f4d06ae62f05cd544406160db5cebc639bc0ac7333d962b3a7c28f03a57f6e4ed5660e5c9529301c1ef4f2b709363eb9d409feb6450364fb841c291f50a84115cf28d5a47d5887f6ab1e55b1842207b0602eea14f58c267906c37c67aa02f37e766d04f43c435a3f900eece8c58876cc47d6ad5f2ad3e81a4f2a7fabf9e008a06c2cdb7006e95e36901f6dd5f79e88cab20638bcf5f4493f2c0b2f435bdcefdcbde921c07d5ddaca85a6490df3ff4cc780ac9df9b48d4c772641990183276646760ccd877a206ad4481e420205e82801eb4858a39c9f3f6d477c6084bb341d1b648a0c148ac02065f7dcd44c83250c24eb555e8bf885519dc2b860cf4e0c83616ffce01b562f015d1a746ad2a4f5859061634f96484eb5b0f45a4eae98069ec6e135eae47f83b84f6498581bfea917f59dfe932e893876af5a591e0a0e063eed8f8c195568f7b4a98610f8e181bc2802cf7e57b4438e06f961afa5fba7ab47c884c0a33e012159055fc15209c64550c3d4478f11e2dd93ccd54ac7fdf2aa584e299e140964c0710969da706cf512a88b7cc189fb92cec2d9be6050920dc1cd0beff6658b32df0a2ab1e86c209c7f43ddc5d4e9303ea49d8a8f4ca0521bb5225b5907aa7b2ef15ba9adb80e0660634c9074527967c0101567c9c871119bc13888f936f2d0ac2116b9e5fe21402453380f5b10272ba0193b5ff7aaa863c788253c58c54093ab4ad1cb362ede86a01338707cec64a90953e3230df648d94df6f089f44b7008f01e9ed9d1b2eefe37b2a13dc0cb36bb182cef0974faf589e586d0b39ac905517de5f3daf71fa871a607efcc73b72ff2d5f8bac0c84014d73794a5b475c662f557f539f9908b23a1738a173c3c652979501a57c05831a3d65a51aeeb358a29d7b90c25d1428dc91dd1cbb109a32ed6de18836f81c06775064365f5a06b175d8fdb317f8c17dd89ed4a700886d3f59c4a2979b623f1193758f8681f5d5f8437e6861cebea22ef657fb4798dccc05669091133340bd6375062f03d258f259110cdf13777cf661b40c12a9c23998159e2468bfc3caeb6a232f83ff1022342841c851273240cc0084eb27a3021a791e70ed6a4a593a4299eeb24fa4f3c6b85202f47283825a9519047636c5577208f2aa1e0846f0ae000060b01e47623383491d7c9ac6ad412efd4fb7d186ead944bb0bd7dde35638f0c34e47cdc232ccc06db36efed21b076aeeb259fc325a2b4c984164842430a627d6ec8308ff0cee4791425c0181065f83ac4d25a312f0418a2cf96b3abdc631531ec89a7a20d6e21489b59b89c20d5e8eac43e60eeb61dc9d08a8bdd7b92aa9421fa7e603d08032f1c655990e31bb6bf65644ced5774dd86216b218a8640b70db4e02a1f83a8ad753702d7caa11e5eb29b886b2d711a0c1e7db04a03a460ea08150c6b535515a784029b7cf491404b112125f4f92151c2f197ece326464045b0ebe7102346878ea1d112ec17959230eea2019e476637beace82069f9fdb6c4c98bca2941de0d6b4eb58818206d229248944581850622004a39e0e5a41035b6310077d7f2712507fe2b2f802547280b6bc9aba9f82063abc25e2222801e4580de96060ad44300c4b1d1d5d7d1d5b04f42d476ea8b24d4e48969090b87cbb59d0207d814bcda1e5e1969abe101ad08a0936b18b7808f20e88d3caf217d854498977bbd41448b18a1f3f81345aaafe85aa9af66339b093d2a786fd671f62895c43039aa374f3d39f59ed1f65a7536969d2a48c0c1d13c307bd6d684035012103101d513fcc260c1cc86d018a826ca1da288a32f7a8b1470a93d98c47df93bae4e51e29c9369e7f3c8022d0dc433aba5762cddda3c34c3a8b0aa242960020772f57eb9d7d6ef98c0e71919368f053f9c581935b9f44c7867fe058f4f4f5e8ebebb022004ea54a086e207c508f8eae4e3b023996c3b52a2a2a4cfc070f40ef4dc948c2f621d1a0cb8e7719836f2a4b308b602342896ed06559fad5ba68405bce26d7b643058b8b79a22b8823e42eb51ac3211d3305fa1c433ace314c4f47e7565f34e07117788f55957b52c117cca74825110bb8e7303685441b80150c363e1092e326b35e17c6c524e486949918f3e57b7cf018627016c4981d28efcd9fc36c0a947a0ccccce4f4b8c89279cdd80d9eba069721430b94f04a75473e25254dfa0cc08e630e8e0644e194769c964d5ad3a2e2aa1c0d36ecb7ead5066f6b1628d76ddc1c0d36c1a634bc17a808630fae36561ab21368b74a3391f21fafcdde242630eda6794d08a93d19e3a7ad3d65cb74b68d0d8c1918813d17515a78bedb8428d3a019509531e7c41bd6ee1309268d276e670a41708c4d888f8893fb8d30c803954e396da5194228ce7a3583494801b5028ad8b5a0d122074899cc29fc791f9e7b803c37b319d50cf00a1d2b056f358972b834140d0b60d566b0ee33100a3616f04985fab5194c29836e06904db36cc24017db76d62c7d055b475291a65727aba1ad6e06d64673cda2d0f5ec01f5723696ba19c47cda373475fdd60cff990491cf4b17b81936f737216b4edd7cc02e88b09e510604513dab0ca8c41b7206f4df984a2297874c53cfb871cab16cb55a0be8d2dd7e9cd48e25c1a3c17136b2661a47a766e6ce18bb70e1f365f4a293da68a04ecfe0eed23b883e31f2cebd260eba022abd150854a4f73e0bba5f9965c4908a97def596398e9799fb276ef6103f97604cf8b0840821cbec1887eb135f20e8a3146c301741ff0bd721d5e896fcd305aad3a92d19988d9206c13b1483e372162bd8ba01352a57153c5528a38f927c8002e362a7e0f8fefe09063fda5c626874e1b4f28850ed7740c1b8042a9044b77355cf8c8875f42aff39e9ef1a77f462136dfc46aca3159d2a4bc6c504a83fbab9ea8afd2dbbd03e2f51f389360e25a9d2c3e82bd0388eb0157685ee89c626552f1b19e98ad53855a405695ed1403af9a08902ae4e9773ff257c1a964e9d7edecd4a2a801d79581afc192d1458738dda861f032b4d9c9ef848dc3814793ecf3867fec23f0176ad16dce55998487ebd891c3767017ab1e5d016df56fa659c5eb16ab8fb54aaa04522faa53aa8a62adfe58627b224deb508aad226265d5ab199a57ad5c32dd8fd802ebcf2ab05257ddbda381d25fb0c9ef05738857df4f3fe8fa0f2140f3a8bf75a03ff4127e7219d09e3e22e78cd43da5a20f37e79d53ce43bf55b5dfc8a3fcc43aeda6c44238b46794f3408a890fbb04437bd479d2a121d0878dda5192e7e18eb889ddab886f41c529be6b5c1a55492501c6a0fd3e2a214e7e83d8474dcd690aee46c0de9ed93ac0bb66bb977c994de1e2efde11cba3b49995679bae8c2f523f72cbeece59ac96f27a799f8ece69ec1cb9e5cb3f9ede4348b87fddc3378599b02db2973265807effd221a8fcf7170dfde93cfdd8e71faa1b716f06dbc0137225dd3c80f8715b04fa2cce2b980c3a5c386a65e5eedc5392d16dfd4d702f93f23bf05f8b0f6e3a66d672df28e1b06a5b120208511476b460c37451b16fb12e6cebdfafdda4054d7715490ea3f9eeed21bd8b0f426fd589e5b23ed28e6e405a3e6bc410d340e362cc3fe3b799754e8c7d62f8d7619ae71089adac2badf5c7f114cf8be6350e4e67f015ab90a832ba551e3ac9485262fc7218d5053f4953af72a6eb197c6a02455f9e66082a4a8e3a020a5d717d73fb13a9118a991867e45541147137a76d1fc722f48c452bea1112567e8588e0674e017fd6596eb12e4f6663ba3583fa029531acd7fca446d1f1c9ade2c40790277d66094bbb8e30ca306f1c00a61679c2d4c52f4bd15747d582080995c75ff355e94a3ad9d45684efd22da5decfabf7dccb452bd29aeb36066baadd720d94da640e4924d0864bb586e8cd359eec8771ce764d957c9155975a0a6047fc6727714f90fb8146b042890055840def4e5a0af729dc4d4a20ef7a3a6745c5552c836372c14de373f6c2d11947cd615378d8992bcd3ca8cc1c96ab055fb6ef48de883c9af4a561fc117d109d10353a51d155b03c34e47613248a96d10d585275e37567187770aadb75ae69d159616bf5c21d8e93685cf3559c6b26144ae5e88400696e18efcd3643edcd080ce480c2c37974b06e32bea3ae1e4298a5f2b9d8b4a61da7cd56f7a60aa36c53e697cb46fe09e0b85403db0a87fea22cb4b4f1ae409f5cc54af02214b98a9e33597b694abd5a571835dca177c0a2f13ea297c5177b3bd025cb2bd32f88f3df02aaa30a9a5603e9d5e04ab930b5754f3d803176b6d98987d5460c537287e7c0dd15798ef781e5acbca1a6f77c64978b2fe572963fa2a27bc45a91b89214b5991c7a7083fe96a299e5f593af689744c5eb3149ca5ccdf3aaa46ec205dc6a18ba91681942fa04286b621947b7a6ac5861ec83d4817dfa2e7c15d8cee6c0ea04b8e3884922e7643cd1a3e5168957a5ed838bfd36f1c38dfcb75b6522dd049e962ddeb664160b3e75409a30da7a32f8281928ea702cf62066ae8a678bf61d026cce808db32fb309f3a54d90f884d71d17252f4ef69f5dd8da18dde6455c3f1937b337a88ea1547f84d38361defe14f0b94998c0800d8a78cd5ec7c26a5e03a2e49dc8cd4c42abbfd37cd97c4db7e9884e295e8e554921b7151b214a1a4d2ea5b445be9d9c096c254c6d5af96c0841d40408ac20492849f777274ef0f8d9a4f55c651a11864a928ad7cc450222dff625711cfcab8486d17669c605850b29122ef832b43f99aad6c0d60428ec885f7331f1c75150b6f95fe05aecafc57f4f8f199e41788ed821203663229e8a24931fbeca879ad7b4fe6814f5a35920abeec8f74388534c391e8c5f45d8e19bd4f7944455383d3acc104f94893c92b33e61378b07a84caaf29947ba029ef7f27b5d0f87881c050668e24711dc89fa3558f8ecbbfcc093c0f71f3f80f4a8e821d8dcf0e1eee8c6da0ec3fa04945e4f3605a14de67fadc234a54d8d0ebad37170308e1cb3180a0183976908492fff42f154af6ca8d323293a23b8098ddf91e779f3254213132fb3ff66b121a0ffd4bb9f690a099371026d10bc6135b3fcddf006b684fc48f46c971155a0b42561121cddbfbf454b8f3bb09e580a223ddbe431464dd3044d63f20ab7f3a9291c10418c83dcb652c143e614434104bdd4a3ac8961d3c29a12fe8096920a7b48879e7645acb898c53dfb0a280d95533cda30d486823e3bc3d9292a3d1df5f30c23b64e16f1cd565a492da5fb176861032c02229f936b01cc79292576a4352ec9e3dc267463a2d7db62a26f1a60f183928b30d14db876b19fd9820d874a94c5776f170c59be62d56da0bb93dda4eca039b14474c9d820dc9966ab0c1d1c1036645d4be8dbd7d7f6013369898e646275375ee16b2925f06f311b15d1d002283b3d71c4dc0043fa22154380be3322ab2aa01c45deb72d41b6c7106b4ca3dda592b15ad3e71820110816dc9ddb75e462df9f5c698d5b121dccdda98e5c75c5cfb45bba5ee1eac18ceb951bcd0ccf13230c1d0721e7e893598f2eb590a5b8bfd568be383c0bec39ac8025fd28f0dcd4132e13047958f0c84b1381a1afd4ff0e60620eeeaf2ebb9c10b9fbbf82959f0f5d03e96934082686164e8e8d7bc2297620c16624470bc780731583f255f482efffbdc466b5001e8cd3b84c29980cbcaf33cc11f2a791c2363507ec2f78360cb003b048a4a16abb640a368c1d0be87f106490416748f80322c67d1be5f4f282a7f7ddda3920b48653fa799f8249564ed29510756a9f8158c69201c60977a34cfac10d79b3e9f187b331ef20a5810864483af7cfacb34f5a786965e4b01a9e3d2a408c9339071c89a4a0e147b62bf6f0003110a5b657eba90dcb3130367218645f81db6cbd7e41980fe53c9f792d26dcf08346903f337eec10b814afe4a580f187d8af327b83100206f5e468a806e5e471f2b49aa0ab14ff54fceac09c9ae7f72076a2943815a903affc2e1c154255b0767080d5b3f536edaf0ecce65fb910990d6e2bf3503427e29176b6816a492a0a5294955b2b773605ff3ef9097476e1881eab90f5d043904910161d63635a6218079a6bb1c456a3f4877765b2637f6c2085b379fbb7e2acb1c9b3fd0095d4f78e26e5ac1dd4979283061542ce26388031f54a8917cae4683bba7ccac18bf0710fd02c8b72bec861878064ef18cb60934f1261c85c32945081315717356c9b1e5ea101c74e03063b11ac0dd578c3fb58fb40af25437a08ab25709ceb93c2827289116ae0c5af0e0f44085db37879ec2f306340a18d0e8682b915c252f3ae68a465e255fbeb18c530576eb8acee815ce1af3a1c2abf874fed46e9d51d90f602425f24fd5c06bcc4b8a3db7dc1be7b4bc756379777bf822e53fae7782520b3a6f5f5f99e6a3edfb465b6e86826b63ed8f1cb216b8cdd0e909b273176a9367fa759a43debd3d10ad2ca3deb7e6b9a315bdc110c92c84913baee47856e4907259d271e9fa86301e01648718671aef63df04e2057e9debc1e97d56255f484457f283b77aced5fd3e20fb4d0251a8a99e5f519cc1b61ca0471dcb4d9c136331407c6be09008fedc90dd8e0f9391e311ed37ad25c3f9fddf52758465a1848d0f2241790514a18ad3f9aa75a582007b32d3467b8eba60fbe6dfbe3c765fb03e7579294426d02e862575eb76c8d9783744cb4ec2c4c28d7c7b16cb1b15f9bd1ae6452b5308e2f9694f8481b9db635fc904b5f05edacc9efe1bc72e16209cd16516b1dbda88867de5725a82d99aaa7d5c76ccaadf162813df80db771fe682b592948356983551615b3307e09250a0a29863961c0fc0b959b21ecb3495f6fcb139589afe8c08735b774b8bf031f79a8e697589b0230c713964a0a4520a98478d999aabe372c2dc724ea2347f77d7cbb4f0d9ff75189ae10c019d0063645de371d672d43a55ce0495de17a87f0427b79b1c66e37045d292cf858b830e4f662037cbdbf68cdc13032fe26adbca9747dfc0c84d748fdeb00fe383fa739a271637b6438224a2245d3a0ca1d3f3c727d8b1069b1cca533274341797ed101d20fd41210a989f701022429755453f8778c137cd328d0283da3cc4d1ea0bfb872c591fc6b8a1d48c75f0e51e49f9263431c96f53641c5c65c97403881456880e5a3cd573423f853fa80a5eafd98a73569cef1cc9e744494bf17f04791ece487e3d4634509571a797ce178a86958ae5979fc9c87a0ff98537b02e163f27b82c5050165133d3a63b52e7b17f620638a8120edfa93051222cb998816a378ce58c4dd04257b5afaca10233237932425d21d9e4e8bb4f311cf47842e8aef6b9d146470b7aeddcfc34ab36b12547e78c4dd083707fc3e3d4e584c54cdbb6e483a25ce2721cb884536ac71bca1d6dbc9e36f50a4b1a6ebad7165af8bd392586083f92495c22c719fcc40a00e67367a0d9e77a294884b76451cd00ff515a6de76553498c0308afd4956502159e919df0962c70fd057844d9a3f00c5b8d7a6ad4a8d5cf33e181a28958266d6a9c5141890a317b4b46ba9f34c5603b9551cea3ccc1b959be375df7a70cc4c770a1bea4d486cfaa5d508d7e4baeaae92f992858f5560e2f326ff060ac09daa56a6f3ecaa65fefdb057b866625d100fe3efb39e114bfdac7126b0be9ac0132f20036e551053eac3e0e74655a07fe3e2bf56f8b43e0d751996c932943b89ffa5c4fd966a7f8463b1ea0fd8a5303c53749d245305162c1c0ad68ddd8b8046c782c701c15ac2bd6126bd3c68e05f2aa558eb858f272e7742b7558ec9c90187477aac49ba691c33ae445010d7ed32c131052508090ee4d20a3bcffd317a491d45d8f151c0f004c56ad309d556413814c94dc298b1abd7b068c30f30f00cd62ccd41edafcb17b6c6de4e6dd95ac0d17a41eef86a84d5d701e58377ea2ae33df494e6b3cbbb7910d2ff0ad86c1e56aeb776e2026f6f9617594631262d89185ad25e080be740fbfebd93722841df34a768b5be2b443117b25bf6a404d4cbf8490c0a2eae778453eca0f3ba4979a1f09d9afbf4803c8531dd094561e30466cb0c90cec83ec86c41235f831bf51e1b861c16f94bb6af227df4a8989f3953cf7affc499cccfe1da55b236e1f4c0699bf0a1522af33c509f94aa63d2f66112dd97e265522f9951cb1959f85f67f25472e2246180f8567e5fea5fd96e3f6af64a76085f8a811e6b1e23394f208533318a551de352755f2eabe49a14e776f52e42250b941cc4a189af0010d7925f642a057e67708f5452728f61a93278ed95204ebd5111460215a8de8e8d1e983253bc8d20dc531cbd9677c77c119ccf21154c2d060be8f20092cbb8ca1292c99abc61524aecce6d30d7729f1ac72aeead4a46694c9a215de175d36f55903fc0b7de6aed53921b1642f1a57085cb3359bb2dc55eab5cab803f5c54ab7d62a21bb0452259345617ca3e22e061eed76436835a176320c4447b906c1545d77c4c9dfdee9ad53058d7e14ccc4353630c2b1bcd32e8d275b2f461a9bf1a9af45990bdcb538fdb05c4f6737aff3299b05367a2083f4b064e44505f9429f8ffbaf08c9098cf663c99b61e569bfba3d19150fcf622865de94da3e96fcf4fa9bc1d30f9eefda02c5f648a793abece4d6c91affc5105face3d8fc95252a361032fbb164611ba8e545b28ba6056ebd0d17c278081dfa8498fa1ed26b9694c9826b3609597bd082c8d4baa68d348f358bac6ba427bb1285c7baa7db3907857a3b6fdb2b4d044e68c4263f96acfebae7ea38feea349289c3238ff124f1442ba442164cc89bbd82820f6ff8556443563f4a1fee4243263eedac1c18f864c9f71e6e0f651976433ea8270fd3d3a24304d8b6fcfac8722c7100773f61be2cd90da32bdc032017e8ec32a9b35d60e55a9b073b2293241caf5c79bcaa1ae441e6b078414c6f7b488cd5c8c3ca58f62eb1285e65253c527901c21c12b8c3a6afa7a3abcb02f8cdb63a4b8e33344242f3bedcf7649bcb533a8d5ad81c7abb56bf5d98ad7fffd4ed6eb3015b93711121c21ad7396e08a8c941f66100698c7f2f781a61790396320be2a378858deec0640cba2bf282417d702dbff9afe8f462c63eb0d5a579820d546489a3eb62b28f3f25ed869c835d271a336639ab180b8d60c974bc6793f0431c16e0cae24ec060d35258b222f3b3cae7d909c4a3f4d3678703d7fc67df5f0c72bf9a39755772ca7b1fdc373bc2583a63c97d23c9850d37b75d2bb7973fe75f9d419d4ab07c3979c761c590181a6903c60d403a34548cdeca5f9b796f4ab487568f387c39c52cd9fbe776693584149b14c72f62860d13f907d2ed0c8833c8e82a5b3fc774b096253b7a3f7bd5f2008c7974bbc656fb3386f21faf8a52967cb7cc39780a5dec88017b3c4475b19b4f3449311966a50a6a87df4e6ca4b452f984a999fe25200bccfefec9de78b053846c1d6075b0a2c95312b225b2a1b3939f211d6652292e1f1afc66c962f3938fc130229f3e359f9834d739c216cc03f2cd98a60f71acca16c92d8ebe13088da336c524a3f642cf991fe6b17ef6ab693b549625d721b8790754df7ea388bd892f4baeb6f7e963f5f36ddbfbe074f6f908e35afac5055896505565b6e4fa532a4d65a3125ba8833f633c74bada91c238efe89c3cc86c0f05e03a669b05ad1a86851fc5c8db9e8af9853fd4a3508cdd31ab5c4e44b55d0752da699968c168d8bd2f8f107c3935fd462592bb86e41838535d50ab550d56623ab9badae781fda51e215582d593ac4d129854ebcd59133179818a0cde3814b1d1cb0d1193b5793425d02feb2eb899b7b49d0d13063c108ad753e03acad7c2478d29b90ee5eb28c245c4e442910c82891e25f186621733195aa51be0bd0e36bac09e28a318f355d1ccfcc671ce180198ddfb54d7414e66ad7a0cf4878488c954534e015f8a69499aa045b60f1b49eeb08ec926ca07b448fad03ee70a3578e1eee75bdb89e6abc8cd71661ab39c6300e997295610058d58519ec4e44808dad8da0683e0d34e7a9b8a4b2693a5f7bb6754ca671c21abb5f2a1a46e0cc018a80a0d0b39606c1d0c314457475f57878e3101be5b0c7c129323cbdb77a909e33176af1d91be09665e4395b095aacc24264b20991b2cefa83eab433d50436fccbe29d8370ea78f834dc7986c5d957bcb4293536284526354f71bf933d12a6197d9796e5e374c20037f3a33c174efeba5fcf0e2990622752beabd68f1bd3f4ce98488ea5625ae0c0caf4e13314ada0f064e4c4cce93906db6739f31831b9030f134b6041d010ae36bba86f66e6863d5e3f7ca042feb41f04523cdfef75c9948c3d35cf40c4838c67c2ecad408c48c7872b66e093151e9a2c9fb9d83cd3348474fe70c20c7001bc5e40360be4239aa453a140464300c542be5a44d5e5e87ffaf7346cb0db4c8490a9db59a549f9251931cd237d320522a46cedb78fdeb5b8970208e649743721dad0641633e64989e8e9d2bd08ac94568714c14e6dc390addfbb3d6407459fbf4df7f6d225a27ca90c19d2969c188965a1a28c4be727a2a45425a4252ea2500c2edb0176489044e4404010f521048a3743aae5f281834060b8213c20c4ad5cc4c339eda36104e2c160634460d030ac315a4440030ca288f9911890060240200064630378c087000219e71ab516da4fdfd50a6c96feb4d4bdade5b4a29a50c290e4c0f5b0f8ff66821071c01c099a58109a242db121312919dd112124986e041078c4094a5a39ad1f873442b600c84d700bed8bda17d76cf81f3f1d953d0b15180489d59731ae2b5b47701bc7eca7e5754519080b99a31d44592f10939e07c81b193800df4f7c892322c6ac050cba135017ab80dab6aa4c8321a03b43476c9311605b40d517e0531fc3504973152ba8cb9f970cbfaec395e707c761d2f769f7d044f871e4f1a3ebba9b5080468229715af5d6b2e64af1d855de69c73f6f1e5b3f0f33dc0dd5286f664c04ec889545c0c2c13037832fe0a0084e94de8298718dc0ebad566b7e5f8da45acfddd5b0a8d4d72d370b2c09d69d1cad28225ab8dc9673780871f75362178364c8d8dc98cadcce713589e6401f2d90bb04b123e5bace8006277940245d6598707920d6f8cd2956506290d879a4b329c73d1b6afa55829b689255a2e892b5e234097f0b59528afa1bcbe22f59aadf8da07302cd1b62f850da6a4b8176553ea9abe760d90afb53ee17593d46bed66deb170733a9c90f952a338a56a5da295641b1b75345a8d95f22b88cf596b433e3ff9eca6cf674fd53efb30abcadbe72c2b5e9ffd041db1325dbb7a92fc157bed228e5232f42426221d2381f9152799f02b8602533ca60063f774e4ace7c78513343832183bd45b877d9e242f9ada93f66b6ce8c9f5b295f0eb9d8b819d0f5696a3221e41ea7adb9e0c22c444d6238dce4a5d2f1c365e19bd92fe2a5da627fd3ab599bfde2710c2a72a73562d624079a2ae176a4912247249415cb40551d73b558ae10fd7d73b246644ba757bd25d407af2572bd78174bbdab95bbc965c71764a280c423bc9a5c2eb4901fc1b8fb92129614f6490d4d51a9f4c7287c28a11b7383058d4d51e9fe412f27a5f006c80c346591150d45b0a35c48b313a256926ece0b60fdec144f9c32502fb55e8f52b87cf2c8a3ee75cc522c9e716419f5b947d76137288307ea2123056c33bbb88d1e0fefcd3411049ad1697d15ff97ec58eeff55c00684f2f4dff3cc5c019d5ec0148c9d652edaf0f597d59fa87dcf31c7d85774aaf2119bf5d9360fabed47627a7582c9a30168bea852b163ffb08684f8ec23b184a08cbeb10af1d00688f3602954378a65f26bda6370e71c30abd1283eb0cbe89ab90b861051d74eda9cf3371c30a24be475c35f8d0497c5996c75eaf67ecdddc2fa75edfac1a6ed6ed183060c08001ca098356ca90c1877e66c89041230d87434d34bcb99f4103e50ff7d1b4185cdbda5f34b1e3df17d2788d9f343434c69a9a9aa99a9bfb3450f943f0e6fef9fbfde6fe040281487f696888fede0766a0fce1deffe5221038f770f9c3fdfd701b1008c46bf9c345cb1fd05eaf979dcef3cc4af9c3bddfdb7bf388ab9e2bcb122e7fb839ebb6bffac307d71f887a2d7fb8f7ab20295ddf4e627073c5bc838d452092e83a89a4443acd5d2f8ba5530974bd24da6850e4f1aad7f754deb1aa528904d7b686468a19ffba072cf66bd735891a56609cbd4975791da96bfae48720342988a2e09218c15064518942466e66b063c9dc0fae281e49f7e6384df91969a97137068c0d1436ac0bc1e8807110b3210a22dca08aa7cf679f854e7cf61052206236f77248fbec3afb0612a248b941462cc6922612b09ed2822dd09a5c742d3db903b2f7a200c20df229fbec1a32891e484698208122c30891baeaf47a9f2ff147a0d2f2d91990e6ab1c4d4a7e186139425273ce190060c99c1cc09afd3a62ec577b6524dd27ecc92d24144b8a7eac3ce93a3c349e7415528079d21f0074f5a463b06242bd359b2a9f2561121956eccae4cc98540d909ecbcf3903e0f3d2671f33058a8e8a91a8216af612ec5c83f6649fd6afc210bf72c0e9fa15840805bcdc934fba99263d5965e2ca93eea4e7c478b2ea8495273dc893c5489934322d8ca2ea70bea4c64848fdc0a2a2c1c20c101397f4d24791a6c4d488cf9e6a62d6934fbae98454552289c3670752997d914fbaa9f50f4ad567474d10d6e507d25091a2290f25508b8522c94b5c91129416b524a6a5d85f2f35d1f728ec9e5d5514ea9188a176248b4ba392e46477205a79a5248a44861cdf7e92b66ea84efb0ecb089fdd0c6223bd8361b5ed82e328ec0b0aa13030374e6e2701ace26408d159b1827677ec22521cf1b3937abfb024040565a9850f92ff209292205257a648891f5748cedc5ddc459fbbb93e7c76ad77b14609902b4631209f36754d7771884574f0b1f67bd2cdbc9342941861542dbab6ce54521fb5111fcb1c29463b93948f0f682295c5a484929914ea3a5c40131421428cac92185135407a084af080bc83d1f287eba46311223ce93c584408222c565594279d015844f9a4a779c79e05fd680197038809322a793cf2a1a5cc902c415b2a495c5bb06dbf89f878a594da5fb1f1fa3616d5a3495454fabb9df47d2a3b2b8fc267bfe663233ed614bf84cbc1ba4b9393ed2ddc5be20b22ceec1767bdc9d2e4f9b23d7da8b5a74fcb68e4f3dd7baf0f85416ab58c3ee7989c73467f18d6f6defb07ccf056abc916d0579665094c3dbc3da6984a7d3c1e8f97d2f49ad0f8cef33c69825a4d8e047d288aa2c19aa0921a1f100804d608bd7eca843e1a1a1a1aa18d8dafa6a6a6c606835613270c3e1b1b1b1b0c199a20693519d26a527ca1efecf1d01f061b434a86febc3e9fcf4754215fff01c91ba0ab807deec3bfdf6ad52ebe2c60113e167c3e9fcfe763018b08b27055041d5f25f87c20d047b4f1d4c6cf0cdebb414bdfeff7fb112dce61e1fe8f851a07faefe72bcf7fbbe7d985fe739b1b8b3ffc52ffa1ae1de8343734fef37b13a491f688eb0bd997896b0d4a5cadda75fd9af882deeadbc4a0af3c62d0e73b892fe8b9deaf892fe04f892b89ec230efdcfcd9bd27f3758e8e84dcf24aebef7f9bc7763a35d7863e3bd9b53e82ae4f3fa4c0cbe741dda3840fb5c7883c16d6e84448bc177d3f3d3bc597d6fbaf046e30fa6f7f28f97b1f36ef09b37d9cb167c2ce01f6812418cfe6c5d81179ef49dbdd41fb4db17e08c394aeb96b8628c7149e69d6fce58043e8158e7f6edbb26a4ae77dcbc8fc3c1ade38b9a90ae3a3cd62b45f1b187182174b11ee77513d235158ab0378f775cc5fe00095814f2eab36026e0ee86f75d1e24dadeb2bdeb9beb5a6bbcf6eb0b2a60d224319226b73e22f78d36d244fae89e707de700496b8cc91b9f793711a933e23799899ad854e632fff5e1757bddc42c4e4b2c87c2d4675e274bd3124dbbb630e2affb9c26694d9c834dbcb35eb35fd3e723cdbeea5f2f79af0fff7a89c47dc92c266f137b373dabf6eb0bb92c795a97e50f5e6b6b7d3b79637d93ae6f5692f44d92d9ed8d0a7906e5e76c5f677b4d222649d7e525ab7076039445e9f5229ed5f769dee940e4803f60c797c3e3324949e99a833d87e7258df43eefbebe29d06f9a0a3d67f0cc4104dfe02080b0799eb387900322844e0e881028eabd9bf585efdd1e71838d6be2baa1023fcf1b6c882bfcb2fd17fe7a6fed390d06bf36da730550ef79de60435c01750c376bcf4f111c15c133314803e867795111b4a3c4208d54135bf0b9452b208267e20b447094f882103c7b0b3e4d6cc1f7221077087ef242e0907a26ae1b4000211d6af0a186e1d087bae7e5d0b3d630f4d4cba167dd23aee9f0e60c4362064f33649b334d53df5e937349433bcfaff3fc5eed429ed0e6afff56dde1665f0c7e6fd6167cbd9b1b68a10b89ab8d6bd737bd0a68e27aefea7b1cf49e6b0c2bd838cf37b1055fa64981be9b1c10264f27079f7b90896bcf4f3fcf1b10a803b2d639405d05ac3fa3c45b816de2e7b90af841e86011bd33c7f702d69ad8b3dbb421e06092af18686fbf621c7fedf0d84d78fb1503e953e0b9b973ddfadca19b373cbf373f56d3b5f79cc723f66e822fd2d2edf3bceb8cd26737af6ad1154ccfa55f9457a22b94fe82d28725895640afa06950da13b4bf307c6b4b18e2125d21fffa832f4b37cbd25f309fe7432c22e7e7dde019e42fbdbcb9b6843b344bb7c620a6b7c6a0a8c72ec4223694c419dcd74e83fb4d77153efe8a01f41503e87da9f3eede41a6f7f28ad6cd5f75da675f51bb7601fb21fbbadf6ea2056c09d9b35a4f6e92f25ebb0b5ac3e98c4dcf79bbce6ac532fcaaf36257c9b5aff7e94bb740dec435c39b6e4bd0f8492736dde0d737974929ef5c22a55bccee020eb41cb910c37284a80e8ab4719e37fdf0c6b776e8deac3a7ffd2c8fcc374223b36e8f3e6f8b258cd43a897cf1cfb9374480f8824ddcb0ddbafd4bdcb0890dd0bfed63c77fde54dfdc1b1c31e9081e9c2317e2b393778eff85cd57d6b3d19fc07dfa998d30babe00bcfe431d60535edf782dbbc84658c4eeb9b63c6ddcd6d000796e6fd6f433ee815632eff65e0f04df660578eee222a067f21c03311bd5a440dddb3e014bbc20107b9bb881a7826fa8e15ebfdaf67a2078d63dbb896950b8ed0a02516bab35107dc47d5df79c3cf27937f6cd7b7b19f7201359257bb1ce48d7dedece466e9db866a3cfce73dbdb3debab4934cd34e3ebd9decd23f27226ba27ec9ee79beb196e4ec77083fabec9f6f19ab0864843c4bfbdf7fefdb6f5cdcbf65e228ff4dc731ef105bd08906e7fbe7f9eddddfafac27e9eef74f4c6c7431d60fd053ca29b68057c6f9db8beb0ed76df496e53074fea09dcf5054c92ab6f933716b36111f6fed66b1aee300daf65a3f55e7bb3d199e370f8b2dca587e04b279dc8e330f485a0059c10b480a385237cbdfa9ec7e39dde028fb71dd0ebb5a00516be475c4bb727eab9e4f934cf01a7a7cf23ae2dfc7693685b106618c23cc25ef1e01c9b2dde381863bc7d38e76abc7142e09cab71cece5bf3f0dc347d763b267926f18ef8ebd7a78345f0fc7a082cc2f4dede9b98a383c3d3c4a69368f10753e3f4dc49310e0892244b2f9df4aca342ce79d2e8b42048ad5691da2bc94a324e3ec0bb9085d4e6072c7dda2e25f1a50474f20e4fceda4760110cc03b5635c9fd2b0f1eddfbf306d349bc49f46111a8eb16a044d2c9f48674e0cd697383fae31cadd19ea661b6166081a8019c23769d9e700e19724d445ac48082040ef5a09f6810456d6aa03da5d07112da2324daf4c2017d9a3aa681f6a4a88720463f5a5f4a60c1a192805134da52b32154a745d54099855ebaefcb975ebe84fbb28402038bd0132466c658a9a51c16166757453bb3196a30bdc1479b1942c732d01e21fa66f4288abe1179d431128aa250c7764408450917463730d3aafd00a20506d891a32f31ee17b0ac232bb441e646d1d35816225daeba824818f901a466c38914313954218cfba585028c82c2b22c85716155e4d650d02519a96bfa5c8288912440d5b021e52503c718f5c5970f061dbb407b8236a589332e63949cbc080a6ef101c367c2cf179159d095245b6a59a68efa99a2692a749b52485ccd22ed05c6075d071d13a13dc1f40643f0a4cc14186a46b52655032c6011a9971e82b2ed4ba8a12fcb1c617e0499531222e38a5a7a098468192c1db7b8556e5d3e4d1db3407bd2122aef60280c3a07b3ce39eb9c669d89607dd6809572ced926173f67c839e79c7316fb9c8539e79c73cf05319f77de207482347d0e660cc49c7f3ebbce39e7bc862118e4f041b7313ee81a8b30c0078343bc3e4804c7071daf407b82410c2eb818d5a09b160fa13dc1b5602a4ca1a07cea3a4d85ecf854c89c90afa54162eaa6c52ad09ef40a7bfd0d72f736368e83d01e1b201dac0a72e48542c729d01e611afcd4f10fda939669f955a2953f8eaa7e60b9a802c2e54bc728ee9694924f5a42a1c247393ceaf6c8a3ae5137514fd1a7258f3a3ee1659a840b09365102edc950249a90d92981b31194a5e5a237d5d20425cfd47650f18104664a0d063592d47111ed497db07814f57b87f6a0656abf9891894b6a01e6890e9718cd52566ed518729685c812ac2f6970c946fd9eb9c72a1e62be745df6c8fad2af1d56ba27d3799ee7799eeec2da9f67799ee7793a0fd29fe8a980f33cdffe3c4fb7e779a6574e743c8a8047fdd6a13d289a1251bf66d01e74158695b9120bfbd26f9912b5722aaa65e997eec672f05f41800d995d8159a9f2611776e22a2c6cae2c97bc15299249c7a03d67aa1343ca4deec4969158873a1b664e514b76692716362c3c12bef88c95619161a3284637a5c99095202628c4c85d7d69f9b2f41b87f69470178ec8e7f3f99c830fec7d3e9fcf87d14aab39a61bc696f50003c753cc7b9f7b6f73933b6f7263995dfdf6fb64dc7be7eddb79bb0b647eef2bbf5ea0316b4d5b45c680e4beecba2437223e256e2cc9b1f7de20b687e0e1fa6deebdb7a67ebbde7b63b133ec3c71fe24f3f9f3248bf2a7a73efe3ccbcabce5980880f7e007964a109fa2fac18b5b0d0051e82519f605400138209c88e178e23526843566e58b56ba62e351df1efce0c0fd22c525000f80f7e0830b2000c41fdc1d619a8aaa0f7e402c7ef00f44ac3424ae58ecaf6720ae58e9d75dc4405c4b241be24ac209892bd91624aee45a4a5c493494b89262dbb7f63ed73e2c3123ef7322e46578baa13d19ed2ca14ab352e94bacaf372c302cacb0a42ea72e16b96c417b360c86be407919b3a548886669c6da9c8caf3914eaaaf3eec356aa7851b24328b9407182abeac8c40b1c549c0f1b9dd68cf36ceb693943ccb2f75a9393bdf7ce58d09e1cc686f69424e86012c70696032ee803483c4c5c6dcdb811b46fb946c52a876f0e0b53d65c9a18aa124f66ecc88ac67e2ca9a79efbeb5b29ef582cc2967eaf60792515c0cadabd627b1d5bba9164061d152c754d7f0a102ca7ea84cc0c2a5dd892bad47d96e5f655b1e18003e2c9d3932767c65e9459f3edbdf7de7b0381fbbdcb725f2a68cf1e009715017e0d411496e5b3a7313e1bc5aa7c66323a29f3d9ef94edbbe5ed8165e323ae784d0ada93af94a0d63b8345ae1835c58c9b141340124d25aa54599ac2e54d0c8d72a15c301f3c692894d1d455d59831aa0b8e22133246a07640b9e5d5c96a518628b121b19426171595457785f54c4f3c9a287dc15146c55728dae9f8ecebed4b331247b8a08c76c72ea520b7bc509c6a58301443a4d2e4b8b404a9f796a13df9eb4802d9cef944c093a2182dc8dc2892a1aee9a701496263256575e449d21519d85996be313561175c9ad7d66f4fbf743c19962bc819fdf8a20b72820b6f6cd19084c22d2f3e415eccb688a9e70dbe2a4b276200e07afbed7abbd9d5159696650a4f27d817367201f992ca0b07453f4e6b4636bb30be332f65494972cc9d75491ba266cfd97b6f8da20b6f8519c1b54f9fddc5fce176702273ec42336ee5d83a4fbdb5af435593de799ea7d6228e9ad442d372f11b84dfdba8f5f4db78cc3ad1b39f23d851db10b0d3fa5230b3628352515775f5252ecc4959a2c415af615d9fdf2bbb3ffff46be53bf70f27beec2bab8c59517e5395c6bb7bbdddebf5cc9e6dfb5e8fe8c4f77abd5e0fad87c601f71c844e082c627fcf79aa7c4f43afd7ebb98dfbdef77abded83855f72f812e7cb1565be2c4b164e5fb6287ed9a2ec4bbfc61cb1528c9c2a7ee9b709da538a956520428c08fa49cb0aa2a2224a48284be84ad61092152c9894687f8b9ffd2e417b7289cf9c88f815e7c7ea490a18bf53b8fd065af2dbaf929c5cb67df69b0409dad3339e3d041cd11c99427b7a3f2ebe34b2f72def8f2fbfbdf72e82a24a4c6aef11b68815d9813445c8f196b7ec05b02b8b0f0e323f37acecad4f983e765851be7b26a0ca4a4af4f5880c417bceb21c21172da2a5880bb12632e8644001b30309c7893067eaaae3986ccc0b9570073b4c9cad28ebe213f582a4aa2436184c414ad4bcf7ded90785809e8920d867c709407cfbf8d454e4f1d41686249f3cd16d7001068ad0d1d8c387effce133bb2a6e9d9550ca2a216782eb84d209b6271d11529ea0bc2832c60c94696e2077bf3708bc9a9851adb919d1a2eebd85d2ddc2feca218de6d711764b766c678c7733b0eea87cce2a4e7df6ebe3425d28139a9860e202ecf84446cc878f298323545a47a624b5e062efed714708128105d784c7de7befbd77e9c401cbcb1700bcf8f286f596950342a7c643d4d47cb1a8f13535353535615f7356545992506951f1d9ef0e97b2a666bf3a4c26b4a7a6b46a11c30bd3993913683987050172ee24b815614938b29ace1c260088f8188e720055685d34c884608135659d34d8820223b3426c87db121516a40d4a9728ef6023190b2159bc8c54b9ab53d7e12dafedd9af0f922564040b8a9d4f1b929a3da7e7f706dad353f2a58d6dcf6c292b5a6254d1c385baeafce96575647218fb026416860564a8d7ab21a250e32659798141020d0148113375f723cc93295d3da00477c0c32d2987d2d0538e7dced061611a987c763de587955b9d8cb23cc92c15b3f06831a4c68631178f1c5ac89c0919a3a28c5df57a489a878b91b02e3f31d26dc53eb87fb83983dca165792f0a47f783f1b7eb6dc585058c74dff206f1edbdb7110e115e6c1740cdc89261e4eac7d4960fb35e88133a7cac5d192b43e2c26acb890e4579e726a7b23c8952b1a52a26e068d1e2dc408a6832115fe11c7c2ccb93c5cef2fbb79b4b3ebffdae1896b7bc59e7cf0e4d34357708edc9a75fa1ab84f565e957c5de245a44b9b80224ee8d4ad7de7bef7dfccde3c7ef5d866c0aac8c8715321f757b09cab22c6bf61984f66ca1141c1b4fa0dc78caba6154aa0194d36386c267c790131456aed60f18553784bac8a08c6151963745960d16bfaf7ecaf48ae01483b465398605a5e4f76fbf284a5082a0f1105884cdd3d0d08ca510317c9aa7f90262a3a8aaace82c8a4ad3f5a3c8cbc40a2f59d4edb34fb204fc8a03c202530f36d66d00bf5a395be7b35ea3cbe405c3abcbe72caf315f5c6029b2c0a0f438b29515e656022b4b6c4c9613aea5ac27749ffdfaa03d39ef1326d01e9a1bb458c1c2461526533ab07894fd5008e92afb42c17502acd7736b51b0d706f942b37bb758425dadb546d343174a77d03d8d234c678d35d65a9fda5d70d320f46be759d2da39b8e8117cadb5d6a5f124f33dd73d2761f64ea2b1e73fd0a531974b3cbe745d96a5fb60581acbf2587a0f74b9b3f776fbe3f756e2f27b6fe7816f02fcf61de82d2634f3f02b881f9154a606970d251b739f3de706d867d7b901e6b3eb00edc93bab75312ae60007688f2ea17870b9d381844897194577dff26aabb476575a4928aa0cd51883afce1bd800edf7f617b43e6dd6318dadc5d69522a1bb6f69656503ff10231504cb4b0d1c5a9fbd1a944e839bb4e437fcf619e4ec03235e72398e439c2c51579dafb26261f2e4e04227356469ebc80519f8dc7e15d2704a693879ed3118d26416658c6f4f5882deb4a8ab4ece39e74cf5b9e8f3fecc002a488ebe1cf530baa2ee4d832626761261d0c256171959aff5950cb9d73396bcf617e80300d5d882d6a28b102b75d5190e5f6badb5d6cea3b5d656b4c814cf843075495235d11a4fe28ad72c8f8ea7d6b4ab35f6dc05684f8f68d32bfc8c03e2fefc1a6284bdf2c2fad592a97db619cdb62e84bcdea1cfeb35fa6cf365b2eb8d52621454750583c567e751e1011638a2f1d9592841d7676f810b659f3d0746568a6b404644313efb45523ab2738ae104eac95e218df9ec2d306e1e2852ad7bc415afb140ebb7ebed2bd0d68c19b11c654cd0526c5100101c280f92c05cf4006b91c5ca265a155cbd587aad3d052ad8bc638d9f802730cdf6d951508a01810e02f840b7550f7c20100824a28d3d41e3f0e381c79599baab3ab02bbb1d9ffd043a3b26c0a9d94dc0d3d37a88778f38e76aef1e09ca38d0f510b1765546eab58fa047c2865b965d508b21a017f7a6e0549541a8cd7061c3c7952d3ad49c7b447c249a5b04e6159d8910dc5ff6dfefe71c7e56fee73f1f621109f85f98a8b238135355be98a8bf174c8a96987d91b11aa36e9f3df4d76d1408d09eac3fe0019e520ce70cf439bb7945b7e5751922af9d85e193090d742fcc3a906a29516959b5813971c47844931a081dc65081f9da1aca32b35a732c5e6b37e7b0bc760ea418378db9d9c0083a93cc93d7ae81b42c411720518e64c415b5dd9b11f0d98791cf193e0375414539d2a872e5c4cd694ee17e98214942542caad9cd0ca4638c0778ed18b8d7e9870d1ac61710236701f30a0bcb588bb22a2d6ee48c020f181988a458754d35d538ab80982d0150808bd3f148d1118f2d72391fe08986dc9b0a2f4a9830b94245cd190de3098851fa20812047d008cce540c0096b0504fc2a942380dc92d7fe8061b9021b5a132542a0888018797c34a50bc0f262c78f14a62f636ace18cd682ccbec80b823af1be03dde1213962d635f734d5a7fce79e7f35397cf992d2a890e197647626acebd340f7f2571051273aefd1157f324ae69af6717f14eba8186618412f0dacd34ccf1b50fe3965e3b039cc41197a6a4256971328888f88183e6cfa0deaccad4b061660160a83e737d76331d7a8eaa43428ac848982073476b2acad2005730e8449958a2a4ea84d931c33346dc9f48637f622171f95346d59f9e8370dec6edcaf3365546575438a9717764a7da35e76d5ce76dbed0aabc8d4dd5dbb8dbe0800c1b50131a4e56f8a8369e81d01e1b20100804f1c0280f040281c023180f3c32f240cf2974705e48f52bcf0bdd0065664cd1c5d9e052445d735ee836ef34002b491693284f8688a9abce0b85421f366179a1d0f30fda234cd314e753b73e699ac200f2a96714684f6ac207d98c1e5144711e9ed4780f1e8cefc1cdbc430163902e544277268eaa07cf3e5ee3ab01e1ad8bafa971d3a8c9d7d4b8777d8de713393c2ca314cfe3f1789e4da03dbc123f9f734e761d1c82a7ea3386bc24e39c4d6461ce350ac81998b34dce39e71a315ece39e79cfd08e9793ccf45b3a6a6a6a6c6f19dc3407b1b1bc7678040c7765a3060bc50e8b80eed119ee7799ee7799ea7633368cf6914f5e99332a60fbc549049e27292ebc20564856e1263cb179718389a909ca09b437bf28b295f964cbe2c4bb5749dbca3d5d279dabea4299794b854c3ea6ad75ca0fbb22c9194b48c866aca5b6631b4373373868a9492dd132c29e6608451c1258612b5bcdb12c40a0a2d25547266746491d3b2455dad11e8da0492f11fae3f5d9f63b4d65a6badc5e49c17689988d68b2872714b4f243a0e83f610b3cc8cde344dd3344dd37433ab8c4d074cceb1f55904b8371e2a282dfee6c6f117b4e786685333edc4a3288aa270e8a3ce53f728aa0445d112288aa28e0211f518c204e3ac58877a097d8da1c26a82437de75761da8d11b0bc9c5469487f9ea71b10840d71b6028beaec89510e2ab4b0cf8ebbb892b18aecea4a131d175b189d840734b69cc879e92197c6650bda83fe7877c76d688f53b5d9780d1a7ca8c15d83e7e49d5483060d6e6ab06e580bdaa373ce393bce8285e7f8f31d5c7770cc666a85f9a1f087487e987f38242a168b27d4e1d0436011bc1fba99776cc264c0f50873e68b511dca41d90a12630637f49c963b58271fb25f557dce576a585852593f59699f5d87276beeb3aba0b575e5882f91ab174cec848c59d280567bb4625c5b501c797d657ced2a84516129aaeb09dc8d326eaa766c65ad0ada3324da942728e945702d82e335b44704a24d4d1740771ca3d62992fcfe6d237b1781404abf6b7691bdcfbd6bf6c60a5af11bb8a57ea37b0f714b31d776c2f8a44bdd51646ca0d81205c9c716a38e2a3da07ebedc414982822b06d30c2c2a6a0acefc5425751923c46bd3c15d25e948a1c30cd0d4a36554569ecfaee316638a93af715de3580ada5343b4a989c5c03d910144c5cbd3d69faea3fe84b216c6065c17195c4dd4d3b19a63a5587a20d07114537338da20e4b50fef5e3b86828290285b6598c418e2a6aee9cf0a2218ba544d998a41c4ac875a3a4e731c553e04d721383e437b4220dad45482f1bfdf90fffd7ebfdf12dbff6a7e427ebffdfbfd7eee82d8ff687e6e2fd1ffdcfeaed2ff7a604ebee29e4851c9507f562ccc0f144729259cb6d435fd5f9834a7222674b490faa95d090d297d69d9d1f673fbfbb9ce1299d75ae350321be61a1fb494b296527c765c566232b467df08f3a5872f1d8fa13de513b4e77763c773e0e0d809dac3814b0ead2ce17b3dcfb947503435bb565ead1b472954af77f67a6ef66e1871617c22a34b89a31e50b17bc2c5448e226359580ced39350084ed49cb0f921a449e5ebb0ef23a8a2bca158f2d4890c854ed384ccb8692862f1d83e59d168c908099d12209c90a1588c867d7403ecf600b0226899b0a246a76fce55a35ea7e6fc75eb86bcb4af145f1a13edf99cf7ac9b9bdcfb5cf4d3147dee7e9d0c4fbc650791f1924eff391d17adfdc8df7cd8d799f632eb4c72737e53364c890c133784edeb94ac562d1849a218387c0227a9f214386140744881127fc6abde0c27c760dc6f839cc8acf616a84018315e60e2bee0c4b2ec867c75b684f16c379cdf3daeabc76382cafb5e6d2d2f6da4dedf8a885f66420da9467cc6fd8e0380bedd940b4a929a4ea83c11f1f74cf3bb79893777482ae13028bc81f749eb30f8ef8e053d06dd0ae7d5007836ee61d176cbdd0123325636a4d0d5699fd5c8991438894baa61f2402a465664716d21529c19b2c3e655234d1920125e85842c25e6bc75842a8321c28bacf8eaf865616aeaa4873939de666e5791abf680f06efadf73506bf294904e1661741205a28675d7624154d49c54500c99d99991a46984869d1f8e831e54c8d31585fcc98a19100d21204eba8895c9622d5062b2832642cd86888991bf260c14c0e3353594c7654c62522c718473232a07e9401399dec18bab9b1b23052cc2c3571810a2e4acad78ab5165f7a4d4f2e3531528507959c99b728262e987848c5387bf12208da6fc70a27452c88b46cb9b2c447d152955695294aca70f8741045b066a49323c245884e25dd95b4f0fa3132f4d5e5a7ecc88f49026e626727e08aae4425c9e4ceda31f8a96f6e8a7f77f1075bc65e90516204e544253715d99427c91c1d9e947145488a21b6a9202ae98e916ce09993738fb88170ce750cc4edf396da8be37fc475f8e4d29fc455c70641714edc641481bda93de26a3ee9040494e5f523c8c9492d897755be4c7c7dbd6139513771f52761b059799114c595a46ae29af3245519d193a4e323d67cb460f06e0daeadc1b6a01c017e0dae41b1c741a55f83377e0ddaf835685c83c7c7412f0c9cb8b2e2c8c2c6d31635005dd49e00296631a3a4ae41a0a0189f322c2340dc6aa86b10e929b075876386152c2ce6d435a8e4634c927163aa079bba0683fc54650991b1ba22455d83d848437387425d69d61ed390ea4a4313805f69eaa068c41ed3a0d5f89526e9571a1abfd218698e8f69bc1e3b4d31ef582a5943b8003121c5879521a38d2d2b5864b14853579ab0ba2cb7a6292a49a0d49506894998a1145dba3c91a91b5c7819a9a47d659d51571a2835868b30476070f1e8a1ae3462697a97ae3d4ed30fbfa64aa9523ae3d754c6af29d2af699a7a3df6b49877480409ab0a2a33da2232a662402d288ad31521aa19ea9a021d31b23d412be195425d531ca422b4245b25669851d774042b369ccc8e45c850a86b3a77a445ecadace9c40c754d4b23107807647b0c04ba01e51e0331119008a816e357e0d1af4018bf028d2b3085ba02bd1e3bb098776ac8b0d4cdb88b232aa11af199fa814221c66c4d5d81408f79a4609105a30cd60b7505ea58f3cae2c2c89a5012750566d1a93989f9c41d7da82b102a0519653c5a240122c384ba02a7cab59fddafdd0da9bfb69f1cf1d71f2efe70f167f4ebefc5af3f17bffe8cebeff83fafc7fe2be61ddb36244a95324534843c5187b47865918244b5445d7f408f5920e1c264c6149f28eafab37a62c6eb8c92949016eafafba931c5a2ac89cb8c13eafa837a0714a9ab7342a598444985b22760a8bbc76e57940d45e5fc57b46e0d25fb8baa15fd8a12fd8a3aa1c6153d3e0915ea8a7a3d76b4987748489d4892e348652eed47c56c59724479b9c214a6ae285013a6ba2c4ecac0505734061328426f5f594c6ea82baaf4654ff8ba3bd5d5e7f3f9e63afcea13f389f95afcea63f1ab6fc5af3ee3ea3b3ef6793d765f31efd82aa4b72d4d62ac48518dd0aec6e4f84124860b75f501593429c71d57762bb87c51571f1209ce8a14c7a2bed8aea8ab4fa9a9471d1d11ba2364a6d4d51707c535b7228bad098cbafa96d81396dce99c6b8fcfacaee72927c2afa7f1349e43bf9e42bf9e2a7e3dbda4fc7a9e5e8ffd2ce61d12299c7cead8ace8dcda54b8aab7212fd098a690d4f5042a809d1818234d704057ea7a226928d2230b59b1051323ea7a1ea0eb8693bab5221219753db99a2489fb528644c90b753da77ed8137edcf57a3db8b9e1af3da8deeda11139f5b2fcdaebd5b027d4b8f351575e8daf3c1e4f2ec3af3c25deca432372e21957def131cfebaeb027dc1577a5ba9aa66962f8d5243289cca05f4da05fcd14bf9ac6d53c3e36bd7e40462d4d8917236535d4b41d603c8cfc1032c6495d4daa1f546d679e947022a5ae269257d2162a5ecab07e9ad4d55422808b2d2546aaa459995357336c0e8891112c5cea6afaa0b4bba351d7b22c4b9b5fcbba5b2c4b14bf963ebf965e73bf96c7c7a5d76312498c2419d3c5a26acecb0c8e78d98001747687455d4b1e4ec8cc7a4451c1c385ba964b4f90242de5882a81435dcb335225887abced809ba2aee5928f152341c7aa2a6eea5a4ec1c09ee0e5aea7ae2449c2cd3d5e491748128dc88934aee4f131e925027b82943b17eade6e5beefc75df75a39df8753bed17dbebcfb8c13111c38a4277a4ae1b0984955a8f1a545490a6d4752b4dc09e60bfeed4deb8ea35dda6e51eafda025a0ccdc4af9aa844f1576d5cf5f1b1f67a5bc6a98696b8a01a5098a8d8cb8dad34b9b5b51a403c2d5e5e7051011627455d35520b50ca188b594c1091a1ae5ae9b109a92e348c62772ed45543bd0898ccd88d09d93a7254573d95809c803b3554b56b869bfb5cf72ae40f62c67cf76b2672cac6351f1f67afc7b60e8b2e488657d6113b1968814a030394238b8cbae612700977412ac658eeb10ed639f32b267242f22b3e3efe157b9da0c8172ca7144c27c0d4a4224977735fb4661851570c848010ec09d7d76bf738843bbc5eb7c7ea7ae51edfbab7fbf512d5fd7acdfc7a8d5f56d7eb317e4b0b5303cec5d814752856d4648b09ae2668ea7a814804155f9818538106d6425d2fd2d316a4b223596ef0b8a2aeb7ed0ec810193f9864e850d70b5522eeaa055894ad2c32541f5804a0f684eb38cd21582b168b3fea0ea9627f01ef68157b0f2c0af67199c7748f5d052c420249656c53c21cc9a106a4621d5d5db850a9c052a453b10ff38e0d138475e5e9c8ab4d858aa3ac6015db9a2c29aaab5bbbb4baad2b28c4f860a1622c53494a647101d7a5ae3c8f4b235a0acbb22ccb6059fa75e2f2655a96655996c6d258966959ba0b4abe2ccbb2e402d2f125992fdd71b0081b2f3d07efa4c56211482d5d2704cfd097c0b29c91c4ca440d2d2b2fb504935372e5eb8595a2b214e37aa1bfd0f114da231462e8bdd0b111b44788d9c4d0f860113328dcf9a063292db71685f6a469508c889c8f4751c7436c1c0b31d19e720d156670ba3352d445ca570b754d7f4c0fa517cc8a51b09809c3fa5183dc8100224c4df861f513fe407bca38b0013cadd9dd318d7912671666c5508549d529b9342626688455f1d1234c5c141ea5c5b236b70594e3c8c2a8ae3adf41eecb2ab12f4b4f5b8072e643c793b2133df494d4bec54e617c1c9b4a2a35aca524b2629838ab2e3643b2292f724aaea08dedb85887962ba6d40423287a838f281a0ce6d038c0109d2dddf4fe90f500e2d6456e489b088eaaecba5a8cbd7d51579d0f03c64acd4c614a0d2e6e6a604f193801a423c8270d8c11a57d03eeca06ca831a67eacab4a2905d39010c8a901339e2c4c6dcf4c2bd4d952470d4c91dd390966401a281beb29fe05219d26710de1ac9dcda7434ef924e40c83937ee3dd73da2999708b15e733e3bceb9bac42b75016637334e4e9a7708b5d6aed422038e3b8ecd5bae1b6dbfba0e59848b4f512e96649469a2140404595d52e8c8e2a38825051c2b9848813b4a4ddda9504c601c4d9983c3216484d17972bef7faf0ba8e452f987bcf7b75ef9abc33bd341df274e0bdcd33558ca29cd19048c468196a6bc2c484baddee9024a9a214a66bbffd760ebeaddade7beb13e4d67b8fb509710e11cb6fe7709a449c1cd7b10bf2c148c59ae8c69a8258d1b1e6c488902e2bb425294842f0e8e878ae83aab1d2800363ea2b889818a30c7547e951c50b4eeb0b99249c1cf739e923ea6c2359d3efb81434dbcd10abebecdca28e359ea64e08ae1b767fbe358e49f955e77f40489b75a4317e47153f341ade1e55743df0ed31880c9a0909f8ebf6ba797d78e521a9889920268666fc9859ed38d285e2ccc86d2b4bda0cf2f8648c919cdc18aa32b94888471148d3b1079dd469e623b664caca0bd80d3507dc92ad20435e4cb123bcc5ba6af1c0b7585745231dee75f3fa3085bdf70ebefd6221f4f769cd4955912b5e6a7032520ffed7bab6737fc7d06a480d69f1b343edc00a2622213a1338ded4ebc3eb36d5b9561dd63c230d2d6cc811c90c99a434203da6bc886371438431296069912a1324c4ecc6097040d125b111c762089a182469367658f13012f3801c4d9a7cb05dd962a688ddd26e8a70f31a34d0fcbec9226fcef92b4ad967fc1987463abcc3c934acd17ccb852445861c18a3131c2d846821c1b268674bbab6c84d291143e1f4258ec895aa277130c8516685e48c9b58d85418b2c7991ad29799af1543547d226cc8451329634fb490495203cad0d8590f3035f0f28686648b50518a29b8e194931748b8dc38fa42802e62702ca5384b222201aa23b3155057aa24791b61234dad686736038c27f99e102912977a975f5e6fa991565ce882ae4a5cf9005399598ee3118ba421cee160d3b6a89959dba1246ccecb56143634a015715b3d7e08a9d9edf06bcbca56d2af4223e42def754bda5c2fb47a465d49bcb45829d1a30ca78b95295645b064714aad70904257a602ae8a96745965a5ad5400d78b1e43c8ab1f8a05f83aecbdf787b75d67ac1ebfed3a53c6496f12aed7e5d866e632265cee767831032a2e21291107054caacdcde6edd7718ceb78e6dbd9755e6fce64faa42689668f0536d14a0165f4761384b75f4261cf7bfb3534e4c1ba7dc10c2166755bc084e142024910181132556e536c4610a990832535c6e9969cac93e34c1122654ad6e24610b2b6c328264808c8ceaf3c6b8e0e0c21098031049b6fbf60f030ed170c1e7f731089c2fce6a97b6f00bc3db6b8f1346f8f44559e36d97625f4322116dc41921334a5a4af1c407840615b8c438ea8487a1a9e287e3678a1583ad988d688c32383978f91cd190c6e41af135450ad35bcf53a91e5cb3a02d4f23a28c5ebf4f53128c66ba2aa75076ed061dd484a521b53b5f16a0d495d9c992c672469665923e19862ca031399191734a284ccb0e1414c092b4e51b0a09881ad7c47a0301a6d80b7c714511ec3db23d08fed058b568f9e56144d0a7565bc70719a82b204624a13912c51277c8e6078fba565f4beb75f5a4044d84a986af20526881d9b91ed338c1f2668725350a684210b406abda40cbddf2b7fbdd4eafe3a079cbf8e55a4d8cd7bff9ada7d588845d8afd33d1e8f38d43ef49c6cb59b9ae81cbc6d4ee75ce23a7c6b9421b404b5e30d0eec5af9ecc2680dc7db982e202ada636e49c9b75f5b3dd21e22c8dedd4fc8721f5914fdded942d180b6b79b677eefbdabc49d5d6792984d4da88e9a74587d15a93b871a518d3931684437674ff33a11e433bc3daea02a832c49deacd94907214803e3179044f3eebdddeaad497293fb622ce536f11a901600693805cac37673afad709145e5c7437044cb8dbb1e71744dd49d663402b503051c1b1395ac295c7ec71f2aa89b1126485b4d34c2d4eda6240b151c51566460a97b935beb7c5c816616e0edf167e97f6fb3a6cc59d9ba312c48a8f8f09acb32c59a114a6261451455c5090ccc4de62caf39ac4d7b245223e5e8a48f4f25103228e0ac9c7073a242d546202b6c277cb88e49d6a7b5d6f94e6bad79c6985a6b0baa855ba7a950cbec7f6fbfb48ebfa63da8d26e32c63653f8bcf5e2b39797eca65038ecbdfdda0a3a96195353d1257fb1b1653f80c2c44519f97163cd7284622ceeca8ab2f32d970aaf22648ed24548eea649850c1d4c36b824a9ba84da992f2b424149cc549e35256db6c2d35aef736fd3b7a985d05ef75e731d5f93aad6da4d7d8bc2b75c2acedef76baaa59c9684749bbe1dc29640661ddfc4d5a7374eb39989660b32d2d57ccce17d2052d357bc4dbd4dd2247def4d1239e01c13e7acbebfbe0acb4dc4a9bef1996e7f354d2287215b4ae2efcecbc4a3933f58cff1e165ba9804be796c97be847e1da9a2b59bba24fa5273fb6a6edeb0e8b5363363a754b583b0a6d65b6b2d1c0edf5295a1fb55a879d7ccc61fd69e89da6abfc4a65ebaa3d528df355d6836f5dcf49e49ba70c793cec1896b0b384f7aa691dabf5ea664da93592549b72649240e71cefd9b0af75bae2118bfa6be874e5dfa3ac26ed242d15ae391d160c78e696b6f4ca68c7952b3d60e225aa4bc6c6dbda924d197ee1bdd64ba769328bc699f8f449f9d03d710dbe71a35a3808850919b950f2e3eaa07a44401997d854d51a166e2da024fcec537c29b21fe701dc35bae21b05f8524ce6560ea884059c17436042d431d588b1e39aabcaa40704144c6628797a1b57b0676a445cae94c0e266f291671cda4d2b49414e0034e1c4932e52ea88a18755bc1282a22819252dcf0f60be9c5936fbfa4c6a44eec1bef1b8d4ded9668122dceb122b4cef8f3dd1d02300deebf80ffdaeb0eb8f8e605fc17ceba6dc1ebe7edf55baf14401897f9de6b7a695af4caf9bd54784064e708aeb232f26e37b73cc35b2ea0259fbee502fab1a54eac6f99326d72af6bf69d735ec9bd3d7f586fd6bc77495c872449a664ce66fe606a93687591ad9e68e645400fc55bb7004fdeb146bb00bd7d588415a1f7defbf7ab808fbcb0986fbf8ce67ed529e6e11bf1f68879188045e0b77ac8a989429c93829d198bb7c42c87a9cdc6b21ebc2526a9490734f19ce41153fce1762893b6b74912b191d4a6b8cc8f0e65867c76d3ad107fb8ee7bcb3534a30c8e5fd3bf253665d8369e5bd310db66c2b9138ff318e1d0724cf735d3cde39ae96b4337dd74311ed3b470451e1e1e1e1e1e1e539bda5cbbd7bcd7bce6bda6bee635af79afa94d6d5ed3534f754eeae64d531da78b4dcd93335cbbd8d4e131af79f335f5f0e2f46233d57eaf69e6e438a5a6a92f36b5ce1dea1c3779cca136af79af9993ded4d4663ad4437d4d9da34da7cb939adaf59aa9ef1dea6b4ccd54eb983cd74dd3d43cc3344d53d31ceaa11eeaa176f7abc3a3c3a387d7bcc31cad738766aa7d62f7def49ada8a6953f3985adf6b9a9684d4fce2c3ede2c5f256cbdba1fd8a821a4335e46c8bbaf2bce53167e3448b201a56d455e76d5892b9371e4d82f850a7545942442a8ecb1575b5c7b25f2d1ad9afd698f3f60dc593b9a42b512b549b82ca14a92c4851c2a8d6daf4edd85beb25b06e470605585a17b6353b246e8bdc54912b46d65a9e8b1552b82801b3e5cd16d5c802232a06da9b15e22257a54b89981475bd725436a82879c1c44444bd6c2fc0e034d6d7ab16039e6f8107edc9af57cc89bd4a62d66d8d259d7493f4148bd8e0a40b874c2989a394f3a44e083aa55f7990d475c49357470ebe5a31b21b5f7eb5683a56edad857b522ec7d2af76ced6f95c20117cbd444173bfde9bf4a4af97c9a983af172aea98f6eb9d3a52d7abe4495fefd5f1c92b46d696f5eb452b52d7abf6e4653341ca41e1f1eb9d1352d75bf724f6c14044aa5f31d293469cf424931394d18d5ff1140c75c54aaec48ed07ec56832d415ab3d4942e1b627492c5783c9af786e85bae2ba27b3cf9319e849d2b311d3d4af1929273d99999c707ccd5051665cfc9aa752254fe6ab7c0480af598cec45dcaf194d67cd6a996d275d73db93192ecba59124d50d146e4c55b9617fba8fe0e769e3e7d9a4c69fbd33c9799270deb5d3b6fd5c78f1a7efbc60e799c354020aad145b57c26c80a967da12108f33b22244d435b5470d14017b6164266d0cd902985ecc9d298991b1cbc9c971dbf439ae7372b09a98f91ce3d8e778b681f6e4106dea241038fc75c403ed15700ce81668dda6dc1ee81a78e4ea815847b890c840d2e581aec373e281ae4292ae07fa036e3cd02da064ee81cec292ae077a09981e88c5a4ee819e6ba03dc0243e724367ce502c11a96bfa24b8c5224820e1eb49f85961a468c78b283dc8a824784e427b4820dad46dced8d894606333e26d6cdc12bd8d6b1b37a5b6bc8da75261dea608dcdb18c97a1b1b23716f33c5f5369e69a03d362360490dfd08238c3082e71968cf08449b7a9681f69c500f00d700f08c84f60080685313eb85d27bf0e0f51eee7bf0e0391e80ee610577268ee058789dd1a91ec2e882d4ccdaeaa8b05cd43d10e83906d5d28df3f47c84f69c3078caa83d0e8e6723b407876853b34cd6f3303cafeb79ee38bcd3792816b429b626a11e402acf8a992070766b5ac2ce00d04dfd799e7454fe2c93f4a7e71740201008f4eca28847287c218717ba700d31e28542277ba16ba19ba992f1853e547a21d652da0b855838945e98e3e78539a8bcd03311da233ccef834e5fa344d53a1a7a9f36c7d7aa65b690a4c539b347533ef6808d222ea0c8809ab899a325df9d27a1165034b25f2642c320624ab4b8a840e09da0d2c4f8ad4f586d4dbd8786e918147209068ed68cbdd97981c52d435e78165deae6029a9a212a4ae3a37763c1008fcf2caf140a06716680fd07863e88542cf2bd01ee16d32a309135b5c142a2b9a748c6427aed69fee2c84a0980342922446a49e9e87b210da930600e76b407c4d88af195133a2c692cd40c161c6d2d7f8d0bbbec67366d47d8deb2cf91ae7a161f735aec203747c0d565295aff1ac02eda931c2f25a67bd76c7d109c1d3f53ad5585a7bd0627abb60f65a83bed258235d25f23a8579adad34d636fa54b361b64099500245cb5913950ad7da8f24b136b724ea9abebef216c6280a52122532fa465397991730e6c27409cd3911612d255142312309521063939d9538a6187068c727aa14a6205fecb89808f2a413709e1cd640fc19e2cf11476f7fba3edd8c51e44f4f03a688a874aa19a93339c81465350400000073160030200c0a88c582d13c11c4527a061480106ab2525e4a1a4803e220c861148498318618030c30060c01ccd04c1b00f62a0284654235f05124d754493236ec89ba8a96e8e682896d2801b18a9ea34dc862248c5ff0af1f59fe5e00dbe67e07ea77fb276e08d54b83b6fa14b5ddc27b7368e8fc04850d6ab21e6016d90b62d6036d14018292ecdcd440b1c0a68c043eca77a68f1b503ee4b0f33ed80b6e1323c22bbe262565f660ebb707fd884f3e50ea0a49ae1bb395212da9badb1a66ab862b8311b1256f1bc4b0007a722d1d7ee2d2d39cd615d57848da806668055cca51cc07b0ae6bee79c3db45e5871d03f82c2fa627ef9d03f35372b319e37a9f889c9d0e3716b1cf7d17262a635c32686cb134d7f22248e891ae2f3810b7c661c219cbc0b7c64c8e863ef8c52b8520aaf2937de4cca05519088e3ae13215e01c6f5ceaed42b0f528a267aa11f25c6f86615e30ac7ec288a25f3d4ddd367623693fd738b9232b7e0db58597b36c0520935c5f5463f5a6999b940acee05420a9547688c181d3141b114b91244ce424ddae74506ef32c0ef992e26ae2375bddb347563ae90dbbee5a8062f944a56f328f104598e0beffe52dc456323614c23fbd2acb7b9f0e85bb8692e8eaa6506b0accfa2b0693e768d355f5ffc1231fc3f085f5abb103215ed40995b6885cb8d6f9aa63c3d724c054cb1eddcce17078d4b8fe28a89b39a9eb374c91b4a134e46e2ddf37c8ed0a53006a9a1818dc0379ca77d82cee8379502a02bb8c18db2c91720af52a606fcb0289ad538da5fd370800aa81a81cb7bd253a05862b93a4b4643915963f343efc5b5dbcdb525f8aba432e0fd074604ac5037f7255a99301d6ce11401eab7a684977e800396d3bd90e3b1182b60159d922e9679fc6669e688db35423fc2d09cee3df90afaaadf291a97774679ff0e4ce4152dd2ce489cf39c7cbf00f1e491b200592de2a7063d3204168b7a4892956a05a2521c8141b24c95f016b6dd25d08cd3768ae8fbb3a48840e99499e543e55d765777af118926071a1240d80c48746e04875980dc4f49215e886be5419c4f2ceedc53cbdd21ee001cfdf4cf98a638c28cf551a3a6f0130d5ceb524fa36ce60dd9fee2ddab9cf677c1a588724a2cf486e70b55bfbcb5ace9850cd3891b03a9273aeb58039c2c630a72c62503157afc3f7df96b0e8412e0bf484e812e975e15ef75ded7437f31c85ff2c1017a0275fb37d6f284b35be7198e9ae64b8a0bccdd6b64e6210cfd894d64df5672d24d6e95e7b90b6fe682dbd160bf08f61b04bccc30464f159bc516a9fca7f08770282c183eac91d3d7190ff86d80883ca9545f3d6982cf161b32a9b89243378d52afec98275b5602363aa966c18bd549d951628d1ba654aac11c6fe827a604c0c5e9ee3e623392e661b83ddc902d7361903720c82fa15a42e51bd8dc56091ec23982d3b18dc6ac83d4e2d2b8983dd7695387d5f8dad4334d2a1109230d1d7d0810c54a6e023eb559172f135c5d5c04e417d56df7c976776f53459ebad2a49469afd73cfab35e2b42955654927b4d3bd03d42ef92125e2d6eb51e054ba53ad26b88d0f8cf5d22ed191d39c5e644dd64a301d0394815898a5976ebaf6b16094f2cc4517b99e637d9a1620e57dc3bb5ab047274a30368c7ac7213cafa46eb7c3b477afb5c93f22f35e8ea8853558b87e8a5551882dbb60a55551bab8f974ffbc0c62c02e33a7cd72a705e185bd5d1e054bf487343609bed59e81b1596c40106677b5adac540fdbc89c2a249e7e4f7915e324157be08ade196b3d110df32a8f980727e4a39bc959215c3293e4a9b1d163f265f938301f855da3d1c28519c4704929dc0cfb4d590f7b769e977ca2e898bbab0fa66d600b3d92e5e797b08a38106a08e10746ad6b0074f056336b49ab368515e1727feb2110d9b88550864ec90ce1bd3fd4121a317b08fbde17b69a954ccc0f41b08c00d8c5c0e7563262e5c368ecf4e2c64a0f136957f01413308e62726cc70b323a8cb9b1bfae79a73ac0ce53e9354d783c969f605df9a5f6e02b6a60e084a1fea3a65bca20566b44b0837c96250e9bfc4cc0e63b1f847c117873aca8d31f8b3c03f195200af892cf9b38b0deb6baed49fdf36873293e424d35eabd69feead8cbc2472ca64b15498bf458b91205b73cf972302678415791f6408145330e43258bd158085ba630715d432554adf1e5256c0dd91e3c678b0b6831481141421831ce8efb6240092ccb9b61358430cf8ec61a14e3cb95181526c38b63985d65f83a25ba683b5763602a12d7010b3f9d13aeeb334df3c0f4b4ebe2f2a9532a453abd23417814f5a2e88cba936caa1e0585ef5375c023f2a66b3be608cdf7559204d9e34e3e3b11da5c5069217eea1c526b8fc440fbbf497b80c0a4f39713e5262c44ce072549dd74046b94cd0f3dc1c63ce7c78c25937a080f16e02f5e776ca7b6ef0007ceb951ee2086b7467239bc446a7982b614e1857818b8c4620f57e980e4814bd1d7eb920e118b8c54e8900bc772179e077050574a7b4d9ba37dc94680023000b2c98eb7d84214768291a0887882861b71bc172e80c47eff6a48f5d10b040a6cb15a47b5f8e1223473839a2b28568c400f64fcc6d7ed3ad3268bcf1ed54f36e3e0bb4615cc5d9065af6233d6a7f49acfb5bf9467cfb10ef75b98ea0c6cc2e6b79ce8ef89405746e4a80188a176d491be364aba52ca203fabbad8ee87f5ec8f802081309718e3596b09055dc690df9a0afb6a9b47403c79bc1013aa166adec8d9eb005345a5d66c7855b7cc5f1cf44bbe37ec55cd82c355dcc1f7590d7e13c96d306cb193ed4ecae10ecb71f0220e9e2553adaf2bd5839f4abe5ba9f59ca937f1344f159b862cfdf13b9815f0673dc515e5c9fabf199a51b0de1b17376e41541b0544174200319e211741e6b4194533f306b6362a773ec1e247f06c8c3576c4ac60334a0f9666c7401d26538113865ba88f3a32568b1e501a373ceb012a4995a19513ef5b2993ac2df42c226d8fcaf4f86820ffb66332f20ab74d8a4df29429f632e54436bc03dac03e04351a25ec10bef852c61585212043ae8dd4a0b0599bf49c01e1257155867c77028082514a997ad447209aff2768d902aeaccbc2dad42e20ede408f0c909e398f9af7f899d4e2b3c8a32c168054ad52f3c4706ee1a80fd629ced72b59c8d5dda06f1396766e6151943502a6ef41b2def18069330898f47c73fe4be0862e2c829cbbae25d395131cca27e02857aba980ac89610dc04c447ea6c6021dfb9cae346f9478ee5e86f9b23294fc4d65cb4fee775b33ae3ffdfa9270e3063d06f3d3dcdc0d584f2d7c34382099a1a35a5eb8c52bab7e213f8077687908713fa57f6b04215f4f38304da0f115deead0e4242583b28961f12cffcd9761bbf4c21319cc10077638b54973f3b1fcb6e222c682666b555dbcce48f7fb6c11ed11ce7d38e0e880f49d90b6d23d4d4ba218aba41a8d38a9edab016f5eaa5f3b7f99a0500c004e0e33656ce34c201225b3ced76f83fb95dadcfc142d15d183d3072e34cfa939a2817b32e985442c31ea4bac3814fd80541b45219e042d699aa699375188fe40714f3b7f5a6cf882b87e25ce466640891528a0b59d02096735448a0d08224405072a8706a944dceb79af02dea5e70f516acdec03648fb9a2a35314d5c303509e1dc3d76aab0a10509bc310ad2a89244217b571b063ab30c30c36cec58fd5d85af392153def463f79c760f5c6c34bdefae4a7132bb858aaaf6c072418797c862d21e0fcc8318fb44459d13c3f5f3003338ec26915465c4f059d7f34ec358525a535e1a77a9d829c379e30547b903ff65b3a9b5db793e00fe8615ef54190d1711b333e91dc0704f360fc0cc6269aa9a454ab667e5de6ecc2b03b6e0a4697a799fa8aaf169e52854d9e202bc57ea31fa48323ca84ad8f0d46c77d61b8c51e51b418526f03291561c90f652a33f5662694e19d5dc6634144e04a31ef2dc1e91da5bc8258ac0347e487b7b8812085d88ef34c0495dbbc5b4bc8895327e4ffcb83bb41477ce47b2a8f50cea98ee387f1936ee723b8a5c6d1b5eddaa1284b4386e1a2411e7a19859917b7c448bd32608592d281d7032f34f79a52bec6252a73bb5a7892f896b4de111399e102c2aeceeea5695cfadf70ced82a6768b42ae913eaf38b147b2a5cd1a0afb34c68fd8c272d322447ff05ab3e3cfde05603b25760dda616ff9d40c3ab0e91ab76107a4315f9333331c1887cc4b72ad0f99cd9d88b228354f46ffaf2a3f3043439d5cb20ad7a1a1dc3ead159e7691b4b87cf1d2062aa23ae1c6b00137d6dc1c8b8d7fd9bd5ee4318a5bc323f29e9d3a6da54c740f695afae957852192825b0a2d2c5b0cf10b2410d74fc144e181005932e23d191a8488c0c16ae68df8667c8047ebffef3472a40343364c4173aca467424ad11153d0f8da3012668029a0cbf6576842a4b8cd483581dbc34ae42a35aecdd0c80aafce7ae784e8ed7abb1f36241cdc707f49e58180594bd885fc84564561afa727b96f8434628b2a359f1aa837e6a604f7d0bb207255182a0ecc487f9bb5a5a6a893c3c0e029020c8dc2dc0780a3db025f6df4a96a12e3ba95a9ff1b75cb9e17638af62da335968ac557fb90a18674e06b5e61577d24b88f3ba3acafd568533937d03b847627929b08d555c4e026cfcbb5238e8f1ea54dccbdcba3538615bf3849158b848bfc9f1126646b12c3abc028c972e0c2615fb7eaf039a42f02a1d6860a19213b40a106f30a54702bcee2a9876365a4d555d6084cce7f0313bef8da21d5501839f4ee29edc11f2a4d1097fee8d042196f19c661a34d73b912d50028bcca8371651b176f3d971153638e36ba83d3a84f82666056cf8276fb233c92ba60234e95bc95bac18093d14607ddf632b521c3fe05d6ed67147517d612d3be6968dae5f6a1f7b9a1b707464fbf7c84d66d9da6e546077cd9cc4c8b45613fba0ef17e1cb52e4518cdd15884aa0facb81308a47886576ad5039de31b711aa6eb0813dc18cab0c6d061bbd3ce8492749778a6e9d2e869e715aa87f4935a6778f20b6f2d671a09f52c165664768374de16873882d22f839971a2ccb0d42a447837d7d2a8a903101d85b3c346055d73b1fefdd2097acbd94efbeead2cb1c4fadd0da336c2337003ddcbf57ce7879d84948fe3f352fb61998e14f32e880cdca9ed8689196384498d4ee4315c68f7d704c04458fa4ff7138739db74ba068e9da7b69a7594aad1a0d0c87a089669f987e15df7f5078a954078526b4e6059d1019c015709d7a8d945ed6e5c83a793d8cc67688ce1d4a96ee8f703f3ca833ae4cf4dce51bf2e664387699ef0a0f17409cd38a0e2abad90f91a6f82cb4ee951b1b0550db54c1f21f815233b9bb492107b750bd83d7537d349eb1ff49a845043c30f9a7dffeaa6669c8d7600573373b228607b0062242a7eb220fc7ac9326f5ac031c19352f3909d41b361814db19c3a8821919416355833cb5146d2ab8b72bdc00952bafd38ca81e888fc7c4ba326685db28e50d8395e703ce03c327c0c4719e85874352123945c4207780c5b4fc1adb312e420021da907df59c66eae083a3247390154fdf28459c4baaad0a2d351dbc3b8c06f0fa39a1fca58e89948bbaa04145415e882d7bae3421d010b680335d4baadde2c00e9185959b1931a8a1b626ca8c01772bc1bf2c42d59675223436be8f09c435db2435a1a6d6937ac1bd057a0f809da00a96b1aab69937604dafbf9de688cbe7824ea264a33656c4d0294b9f853949899aa8a1fbef8e10a558ca5afa070cc06339806f5fc54268613c1c9ef77b2686ce880ca57d4b4cd8e31f4f633b7d3873862e84fe97285ea70bb697b69986032719efc9cbf97d2bc23ace9264432811a7b611d5701ec4e064e1e87a25806bfd624c4f5ec9f30909d2a12d0f8e9aef15e82c5ff9b4b71babf4236d179d9e2666859d062124939ba10cf490495016eb2b64904828a355e11362002b72eab410799e6a34517815e528dd215f7a5411b6a288a24c692154e2f1cae9fac0bcfccc374ce79d3937809e03569bab05ebe04577eb505dc6914c546116184c247f799194df59b8b84f74691dc981f2162ee0fd2487316b730cfa1645cb65ebac481e0d432b2d230122ca532b47f048a3908883322a63edf83f989c0c1633722df693805d73b8b35c61f848c156bd8eb7041040bf5a924c5cb5344ed2e0e8ac6a438bef13289d79bd6b9e1c84330f19547e18f075f612faa25d1a1c849c604c04fa307869406ecfc193e0a7628d8b0bbe837e2bec0af4e542864d973bc936b6de3f4ccae293a4a305afc3e7390e18a0a414bbf5e087f459c0576a2658faed638a4d2c32797fe9b32d8c64f049748bc11e6cddf4ebea6cf1a00caaca83772b7b195e3156c398637a9e527dfccb97686c8de0734f633a10eda245664609dfa9bc42b046f9c743ae3f045b3baa2222ee39ade60f5e8c396d23ee4e3fe094fa2e126647d2d0a43bcd4e078df356ea0a1d1afd144386fc7df931735ee3c0635c88b463fab086fbddec733ca0377f9ba51651eed534bb7e37795fc0913077890020fa4a8eb37fb2d7879c8118931209f1780068ec15108a08b222003c319c939c3d110dcf7e7bbdf5f3c365d7fd3033ba4a5a3f972be21904c2b64cff829f5b070ab2421b9b12093af3a0cf0d6e0b1c062d199129dbbf32e6acc1d229f0852722b011cc1332a58806676d19907de02d8518fb468f0bece2aa75009ec9bac4d417aa26a173c4105aa2d01787e12cf6c7caf1b008d022c579849f30133d72a4f21d7a48361de8f585c75f2ee6058322f92777dcf4a099f4e0047b1e70b964cd883bbb6f81e3816a00c5e8e15c01d8c2d1932abe88ceb1ed83a974709fd9595d610e1f5df5bb88403d9a55b1647c739d57cc6f566318cb467cf63853f1ed20b2a48b27e2910286caeafa8a0b6086027aea52c46b63d41cab5c3ed7b1430f2bc90b5f1a2b92b8b6b4bb4f995660f3be2fd90cd8e4c624db51c0d9339ac7ac25d996f3911074359b2ce8ba8293ef025311f23b40a6e1165ceb8daed56cb5829aa19574c791c759cc1ade308111fdabcf5a6fd141875694eab79f3ac6993b7445ca4420410597696c127335195e893f34a98ef7bb33363b2ee802daa894c2d386e617a11a9e7277a92caad352702ca7b741328e4cf2510e0f6396190003c0f32fac9ec8a55d1192379ca7d0913edfb34a3cc645a6e2227c4cfcfef4c1d7bb9c947aada568a0ad74186b75b1ba3a4e472daba8a40551421faeda8c57792c34a63c3dcb7d435db0b3e2bb0b4c903598d3750282c12db10335cc711a644ffd2f8ade3c79b7243311253bbb10f42a85f018f0e30555abc068e480e0dbffd897bbbddc503f23852cff8966a55e1f76da65eae15331d81aee4dea0c8619f65130b1d661fd880bba4cb45813c85eeb019699693561a721d69ca67547197b714ecbfd152942ed86cb23560409ee13efa1d50a0c746d3725a3458ead8a61a120e605d666814fd3dfcb0d20e026b9e2e9b2f3316dc04a44bacf678367a89d18919ebad0288552e4483d104d6d832a5e55aaca6e0757b0471057cac14b0f62c9e5a0c6924f261456d9c463ab4b37940621563f34a05969fe207406ba29526d668709ca85662a18eaf9a183d83dcaa209bd020b666ad800f4e1d683d133ac8b6e979abe8eca9dd00f534a429a57f27ea18882d9bc557c6e586d703c4a637fe07f09784f59335bf99a89d9e9c65222f56a190c97ce9f5354751b08697345e0263de5b1faf38461216e101fb7ca1670f670b5df833c4dbb5aae5b22bd98ee30d4b5d693538bd91452d8e913b688d5caec78e4fa55a72191cba7b3cf74844cca3a1540fc742b863b57631d1f9defae03c291cb5433532ad5435b4b2e1a003da226f30c24adacf0677d0a4dec0ca2e5b65cf06b66a9cfd1c520f75f9ce9cbc6596b5f9205dcc4f11d1143d6ca53bb984987d2719da9eb49f18ddfbc25e2a94caf993e54ff9e1d2ffc396087de671931ab770229892da9f70ae0bd9337afb4ddf248b08037ad40c067f5f0bf90a672cae21f65f08f3e77a7d8a45c709d7efdc9abe4ceff9b6b0ae9aa99d743d1707ca305257ceb14853a19b2f534a6384f4a0bcd914522c2fbf3f3338722177370d776862f939538d8f21ee9d4b90bd8bd0c88e837a15c70c083240035eb9694c374514a895a136df02e3e5772acc3600894178bfc81e11098cc3e10c92f78353c68136ddeada03581c16ff88a509e55c98ca52a9e0e33d091a754a2aa99ca12f0ab620b15a56d4bdbaddfd8ef24551cdfdaf486e57209da34482d3b0fd6fe6dc349c3f843a1c76a3062defb21b9cee47105c4a6255d963e129bfef0a377e249dfd3bb465c34d23763ae400ee1529d7472d88fc967a954a806361402ab1844a75a407c495db536c283de0cc3860d7470114e197ff0f9211c883a780703fab8d202af80bd908d67bfcb90233b232babef44b68507bade7d0ffba219fbfe54404345c5083a5ef5d4f57ad4c1e0f74af7bcb2717b9f4f9ee4606bce3efcd20ca6e2225e5771d1f332913338dbade00d10b4f7a1188d7f69d85f330e4bcd2c8bbfe990e4a257eb6dd076670fc3181731e35b08c53c6e7ac3e7a0f1c52a54c634a7c980966ca334f28474dde7283a98d69e4a4ca4c26806a4b3990d2c339f181147b07443820c6d02a3196e7186126e29f764814d9ddfda438ea62ead184865a83091b237b961bf01060e8f1941ad84bedbc0cb3ec5d72896ded40d5060c2f88abcbf38bbfbb1eb41087f5216e07b57edc6f335350a3c924625192b7c0cd6133b26cf30dda06a5ae9dbbd98f5963e4a2e315cba72104f986189bc70fb7193ef7bfb45d0de59b63978bc1c441a4ac31ddd4f96e44d1cfe03b8bcd96c9ce0ccd703e40c36773b2fd0259150eb83d7253c39094de2c181d6a55de5941203f2c3d11fa7975a24406c513ba1c051d4f33a4cdb3eadb4d229a299f850b2fa227e918f81f4cfe50272b7fdf9a1d9a81fb2ccde3e4a98f64906f2d18964795391346c87c3825bf14c1270e6d12ad36eeac73807c3b24e766809905ad114b14e3f291e0e56aeafb4d7ecfe393d60084722374c3c2a1847d2ae1fd0b52aa68c9e038336b662d7b867678d4c704f801ae98cc1c0dba253974045eade9d836d2f5d246705cb5b566757be9502ad2bd87094868fa65864ebe61b693180c1f126c5e70e9c213d0a0c7137522221a6e7a2cf7163ec6c3c42d2af595a9cd15415ae93cde70f9f4b949c535e5f0cc8ede03fce697e1ab49066bd84ddc38b4ea196d8e1f74f9eb1b4b08888ae3d52160d012a473c5bae84e52e335cc239d5ba45629ac70b16bf851170a8284ed20730426eb6bac1a86262b73616097c57e05bcb43e21850c0df74ffc17427c138d466baaed77f9b1e8693c7fb7ed9b4216ebcce70987266cc5e9b841b74de5a00ea6b2c185c916de5eadc343640583509a6293d78ecbdf774e5b352ccb4fc6dae6c02354c43918f1d700016812ad9c5b4ba54318b821cc76468552b236fb9e3be0eb4bb8b69feecfb4cd22215425e5690b069db680e12247729d085ea513cd83b1a256e353a2e2fd5d8ffcf1cf0e7a761f9240c8e1a46061077545c3453aca4477ca4bcfecdb3de93343e6a7d69721f69f47a5a0e98c4c04df235eb205bffed5cad9ec22ac320a71bae1e01d3b89562e22410c4d90ffc54e586622513249948614156ee71cede842c80af6ac46d943d084a632b720f1ba543c9c680562d68f436afe4547522387985935ba03a32ce33c31d9bddc8118be29fdbe8477953032891ff53f77e5c1ddc2f5ceeec55cd539320b7056bbf9fae7c0f79582cfd141badbc92f47d80c850609888016aedd0c4b0e4b62a1b9d11834091c99b48507105cea1bfcede9cfc1c6ebbcdd85b2183b2f8dbbaf0b35aec58d8d0d84762707241b7ba8bdc04ff58079fabdef8df21201566ecd82ed353c8f5105411bbefb7c015ce1ab1b32a8a7eed8f4eb42ec35178dae40a16c8c2ec30e3f42b747dd1a377b0c925583f0c5bd172e86204c793bc314d22a60cc20b89bd9156f41eb97dd43c00d21281fb807a0ef3dc7f16638eaa198cfb2dcf6edb7f3d467d6cfc09728e4b8978bf76dea17b53c0eff1c841446600a4656b935b16b1bf61f76984c83be1fec31e1a0b02824f4bfa32093d3050a650d28d168d41358698af38f72422d85494bf0385b4478cdc86460c6299089281a89be2d1172e7ccc6c40b6662a648f7bd04e98b181f31a2614fe0bf6df0e0f51333fd1b553c30115567bc5bd7906a196d5b92e456dbb186fc91271ca9c52c2347db21c4ab46b9436c0bb6e427944abaf58f876397c325c38fee0523acbe466bef3442e6795fe9fae6606b49bd094d32a032c74c11fc30c111fa4cb84b5a437215d3d30a6af49f97a95b6edf09238d8fed52dcb533748aef42a7a9fbaab1b50b3ba8e12b6f4474ac851525e202d07fd8d8ddd54344e616025eefe2d3e5e62dd9d1738a08666e4f1728ad8d65e5b3d39e470d992b01dcd8300062e66ed74e01aa4bc7848930e4d56cee5dd6b0d0bafea0b787b15062857fc70aa1f43aa251f60b7fb6e2b5d3ce4642fa1a017a633606421987201bbd889f61f911562239a8f6f7a6f65edf954a2b7ec08db6122a48b0b7725688830be17e0a92e4da36de1206d36f7b43c9bb4a80960dd98524897c182d21a61850092010910c1215962e29a38a0744b23242722e24972646e7a6b768210b52a3da10ad70247a7f565eab5ce4a4e96c8150a2f2a35ad3b0f1d8d42aa194c804b72b422921d6c59e97aafaff67edd04075a09e298ad00922e1b4787e657c1f801a2d0a50a2b5e5a8230f6ec33b45c07327181afe917a75b5d7d8d6814e887ec03f4b3334a2cc9d0bcc5a677310e96a6cea4b12dbfa84adac9adc222fe51f762a4163af0b94fed0dbd8f26283f6ff733e8e402c52687679da8a2effdeaecbcaca2d7276dc1e914ede3105cb3709408cd3786b11b3044c8d18229354e28e297cbe649661664274295f01db6e8a7f55e7701ead1cbdccf3bf6376ebece7464aa4cd0b44e17ab8ae5bb1be790725b29c3471ad816d461c1c37c1bde38833eb106239b739591c931f28fb986d07ef757f377f7cac81a2576b3ae8230c4a6f06ae97e3100da9b13246c98ae0f979d428ca603311bc3cf18695df73d6e74d61bf08e2438b314d474df7cdebd606d24dd31fe811dc2883cf9e8d5a4910c10840c97d9debfbab0b08d18ce31ad41a8b75f42af4ce20644dc774204088c14227447f22c1bf109aa02f8cdd777fe3a0683455f02df859368e36311c2b76bca91c54ee2e7c19990f0e5d85aed81c155946c1bf644c3fe10dbf00744f082e35f1fb6963fde9c416d1d3e4c67e52e75f1622bd9231cb4ec8710b07b70c765a67e3795aca28211ac30f74f635204f5726ed70518eb945ac39bdb22ac22957d309f0fff805eb6c5a02e9c1cb97034563458eb9882c6b51cff38b5c179fa4926a1ffe1a2eb4216c2db8736fe1ba44334bd87fe5ea76d2caf27b7623d3bf8ab9910bd09bd1d03d7a8780868f45a924f050160cc03f53fa0358b950d1f80602a3dc5686e79c7e526e1f52b89947ef2aa74fd2b919a94fcb783e0b8b5b24992e4d197fdcc1941183d47f93b37dcf762e00152d1f1ccbc3e81c93cef4fa758a86552cd2093226bdb341506020ec42a23e4ffd18df28aea802e5380dfe697af1d7ce43697f91287a0c2d2a06f2048f549c90e1c94f284797084421ef2f9716da848085d0eafae3dce80a5088aaa708df5ccc10117f3beb5884603034a1cabca82613185d348288769994667845697425b8113401aa6afdabe00a827e175efd4e603bac8afee81bbd1b7d42756dc6646f332f58599155413b997d01b3e3263044f70187cc0f10f3b40a55cb9836392796bfca817a6bd1a3f2859ee7abac4896fc58cf188e50496c4fa305325ecde34b8629fb5fc689ed34e8b5327018f53bd12dcb2e43bcf3ee4222da54f2d6931d7c4340e98dfb6e21683caceaa5e4c1be5c6ca3d72ee39aba066e2193e24ef28443204a3738308573795231bfc4ab2c9d3ffc9515d6b78a3ef1f14497d7f557c070f66255ffc1aa6fbec75fbc30b87924f361c973b05ef57fde420e9250d2089a10515ccc1ef1e45c4f11d377c2d143797307cb8364998b75bf2a3e5228d10b72368bb9bba993ef043a653ca4e8ff16b33f7b08958e36617e4f6bc2eb41d3e82de369ff9eea17ae04cb7569cdec20c286078ac286b2627d967a4060c6869c7aa1bc12dbcd540a938cd1727ca4fd67d7dbcaa6f49a64ef3980595e4ae81addbb05d19ab283f325104e26d4adea1a174d01bf14a5d9fc726ce133ccb744313f5b25580f0bd06bf5ef25e6ff158a2d35a0c0edb2220eaf349db8c06900669704fbe29b988f4752d7a331427f775316b5d9c06e93a8ca35b26b5fe1b09aecae783517a1ed24ea472415412fc012b5d481f2e6dfe814dd426788a55d54a709723dd0002690a9ea42a123f4862547e9de1ce91eb38ba16dc19cac97227c4ed1d0acb0324037324408934f3ea33a6b760c7e29d0faa43e47b6b234616915745109520e2932309e5b844c281422b6e8302787a5ca160d13aca244da473a9ea0e2d65b49f11b02c206eeb1b610ea5d85a864be6a9e8280330b9eba1182d31097ca2684fa8bd83ff8600f1727877650480b7196949dff049260d8c1f66116a44bcb1615bd62a639c50b98bb6bed5fd2d3350af487fa44985f4ddcd2dfde6eb48700822b6f1c82b41832448912f6ac22be4e6f9b4d6600e5f12ee93050994463d040528792bb62c19ca0f641e8ebc6cb84b0d38ca7d5c314df7cc228dd8ad79c2535bc5b21ad7412f4b6d06a3803a5275a2a2597f1ed5011d1b2bf7adf2943e647a83183d5a5d5426ecb5dad2b61a6867128714a38d9e8dfda92466219c3c74ba78f8101d1b9a5b265e9095904cdf88e878e01e021f4408ee675490633301100231a12977249f5830ac09d7c651cba34211226a164783b59b63d6d34dbfe476916e4625a38a21304f67e1410a76ef0accd7429546597cde1d7944b76ef38a78e754a33e7b0c2509c68c7fb6072cf5516e8dd520a1cc37a6918add3c53e53481357dcad1ae3ff4f8a09ccd4554fb9aea424884b9b1bebb9d069bcb49362ef368cc340f8674ef3a0dd0671eb1e0b2030235c4b685fd307dfd710c0c496b7669b5a1f5b6fe7264637a0b1c1779bb85f92e7281737b766a6462547b823eda23028dd29979aae066c2e874a56e55217353e14bfe628ec0094483161faef6a7bbd81f7544ee47cac647969bc1b6f710f1508ac87443882e7ba2444cec7db249ecf1cb24301f1b45c3c4ba4d9f482b340e2d3a29c1a1839f5e9fae6b72386d81d4814f58c363e9291028084f41332364123619a1f054aaf0ec3f8d14c1dc8a907a4ef891403597be096624e0045a960bc1606720b0c8516345fd4596f9d3708090e1a01dce36643d5378f393ddcac6268a052c05ba4e3e29aa4a80144afecdd0f8bf988c34c73282e9ee077a0f20f8b50a9823ed7cc0ff46171256e410a87f0b088c869d9c12123a646308446041bca7e8b5c3f6625ec3b58005af690594c195ad46bb1aef5904ff12b3d80610fd23f84b29f75351f4bb27ac74077227026fe88ba7efd10445188a0f52d005450a56c09525a680355ed0adc47432a0fdf18324025fa660e63a8f535142be8d414b027d4ec8076f1453e8626d012add11aa632dbc6f04466742e433037d41267b476c4ade82c2cef33f0bfac07e080686e8920665932a660732f26919d0cd02d01cd05de1d8bc96e5259206540537836adbf15bd0b6ff1ce373b173ee7456536618d0793fed66d807ab4af21a23950bfe5cc73ff5914ba52983ac133eb286b09f18230ce470a569480a0ee1805d7ee46dae62698de5311c0491f6452cdcfd6cff89bf223c02914f0b8f1c6a8297b246a24b5c4e314913cc40a3dfc17813974ca038912d37448b9424cae1999fd7204558f9b144b960fbdec683264d38791c9c046ad4a7a7ed68f1e7f8ce9619f67b1b7c8770b07c0a692a2a59bda80a0c06f665a66a2534e5bbf544d7718863a9d726218feb55b196723191389e6ea19ccd5b063189873b9e90cfe1c9a33ad88a16d783c552756b49423f773ed5794b1139d038863c31cebe42a121353a8482a889f612b357cdcfd7e13124020a1834c50546369b6e7aebd98df2eab97e7286479934e5ef3319a926e0d50a7dc1e155c400c59a2a6716476046d8ee34d4a0d81900531ffcf3514927c68ff91956de35a91fdb12d1976a70d429b512fcc997030f715ca6dbd0bb4c50f859149590dc25ddb98a2eeed1a6234a28d8e7dfa9c2d354b9bc9291840a508741066d5f301fcfc3866fb8914bd81fd6a0e24f9f3704d4b8b9a68d3c34967c6d4c3bc75e1d552268bd0164225172cf33448fa5818d9b7d4918b37a71b6544ece326c82345e8d311029381392641c65291f53c5684c501477213fd9a4712e0f38180cd5aa7cc1a94b52ef28ad9cac31deec5b82f3b3d4d6a00953a99d88e10d11228ef1991d8df0b5020a0ee2f4d6d309fdc420c04943204ba595910cdb58c3cdfed85f958e9e2d0388814f6025268cd7a0edb1dd2bc2282aa0e0d3fb7aa035422768eab1f04abeb00b863c2423ca539e1ad783824d894faa744b7729e8eeac34d0f387c807dd951a0c41e785669b42b78d2fdb5f4f2521a326e25654472485dea4b805752cbc59f17e67e2ff3325aa0d7e4db6e2c130d18eea94cc2fe18f9e34045eeb7857c760cc6c4e5061855d281dd348db51f6e0fedef1630a1539088f99ce909a5ce8f823e882aee0c9b31ab7555af5f5d4917f1fa70cadbafce3ae01656c755332e28a7889f1b3a4617f1a1991ce2caaa6a9e802c3f0e97ae8ed401d60cf4f3bec681a51f5974b05c04c6700bd7d1a2e23f513df311b963d09d72b55d1501ae84180be1715700a22f34d026f1eabcb281f64209bfc7254d2c66144c89d842657a94a29727094dc265c07c7fc8a1967ff53260bcf0fb26fbcd816fc8ccf8385d8086d814a70022d1e671adf1b456b5915bbb0342fabad883c9360d77e27ca0a0baae072784a753a06f6d0dd5a6ccdd227e99257b4bbc638c63a4f611d0068d07a2727216a79a90b457bed6422eaca4ea98f77ba9f9f3e215fa8ae0f026f68f34be5f1b5311c2e61f4a17936840963d14b0d4aa3a6ee4cc8b8699ffc66d3a9ec85bf216c7f5018ddee11affeb2dffeedfdac52845f5776e55022318e772fe24900868ebe29895f71670500917d713908175565320bb653a7b0c282af680f1822182580cddf16aba89a49ea62232b9149c3992d9eb6735e0fcde59f365746e11ac2f9bdd63659042e8ce220d20a06e6ca0f0792e06034aadfa62a7202a9bb500b6ea1ab49a30639733edd7e72a1107e101816efad8339b1191b0b0cb43d20585737942850163ddb08a3364ca62de4dcaa4120dc413141bc0b0a759d287101471b7ab52492da97bec8aa083f04f18fa0bd2a0d43d2a4232c72ade8062664e3c402b3b76aec5c0c90d21b6acd1a2401f2157839232d1c5fe3baf7f5cbc94517816f3171766eca5c888bc5fde82210c0697967b0fe226937319675e3d7290741f6727c4cec8dcf11942991870085c93895959fffae11ae108a6796c753277d4987dfd50f027d7073eb4f91cad30d2a0aeb09ec3b30adc4ac715f5474b919287fa3db252fc4b79129147dc90caef2b0da8385cd331454a0d945d00121c97623a8d42107ce7d2fd4986429c61fff462f84fca849672fd8d4ef319426acf5603d9dd6aa0d60a951d045556607d4d656fe9849a249f4fb08c53bce970ca4aeb0f1063a408b3eec7fbc75a55042a5fea39a1060c769c85b0c26cd09ac3fe86b7e14e1b175f83fac7adb60a4c9219c4f0e6e5f9286c3c01a073f1931fab9b94022aecb9fba3746ba8a32f5f54516a33762772e6cffcc72e3e49e2044a7c08be3b26bf7ce9160b50d42898cbe97f3345af3f79e92842d89b1199cc835dba6bc9c48ea95f8edb753cb5064cce03e9bf2103bdaddd61f812a94f6cdcca68111973446db1e6b4fd9f75307c30bc80e5d430191d110b106d17b59d1e0e9003f073d86dd44dd75bbb32b18aa96457d820543f6c6c9b40a222a60ca8cb95f93167d48adc08815e71c914213a326a60ac98eb835468661cd7823398f4786c64628c77bc4015ebfa32a9ecba77bcee775f3635de529ca5198de0214033441f8d519162283fa910b67638dceba515a30d00b752798f43d9f9458f3d50a321d2992071f1860fc6c7abc48a0574941156d6324c664a75f2b503811b0a46e8a5526edc8e2d118e1b987d88fc1b448b2f5de4fa84c3bb40cdee8a9e163633f3d102f55584c4932adbe67c8900fccdd327169e39c5c47961c2e41d3381b1676a478651b8baa6f003bcf2a02343ebaa318849000866a5b566a9e82dc497cd238a8046aaecb29698b74697ad31e54360f65ac36a682c806ad97ca6b105f4a39de94740cfa48ff0673720d9241c5baa334ac12887806ef5067a036b5176631754c993282bb18db6ef7088bb40a2a761dfa10ed2815241708e3a76a6989d7c10f1bd2d8d26aa706af8ea3522778a3b57a02034c407f17733e88eb9107c53c6ae346f3c768cb77b022eb0d59a4a2ba55c2fb028bed46e2bdb82ddf112b37786b63b2eb96a5bfa2653864cfad50be6599c5041813c557b7c09407d35dc6a3853a2ecfc3223762409807a64535534c1b114f44cf9736869472181c1cad82f6ba458eca9323cfcb09827f34da8080e227dc440073b870b25a3d45ff50672434311733d3d295e5444b64f3dc1780fe21a2fd1ab5f1da9ee835499d107b562fe13cf88ec64e39456e365d643a9fda47e75bd0462a6bb5146f84e1d6d449c8ebfc51e4cb05d7ecfbb9f2add61dd24b9753bb5d2196f534595da1443ac25aa4ca69c1a59a733766856e082b84a0e9989809f767ed0d008608090e7a21d8a82c0fcf62c4c2d2cf92ec2554a3af5c826acd941f5f5a856dfdd2715e540d23d5b205e82a0265a14f1c2f34e23a41fcb9fde0fae981e32f5c1308efb8c0862ea7cfa405dabcc1695c43453520d2bbec0055176b00d3b800b0d9525682b270a3a8eb17d8d81726b3d9592c6aa224d0229343b1096c42fe27fbb9dde544d80b2c5dda682bd2bb1f4e757d101b542207f20eb79ff244b9be1f9a3c6e482dd8f51e357d3e2169ba040e7c187d816c1284117585930ea0141ea8ce47c9be11da82cab60fea16f897a8c064f02893fe5dfd8b85a7ba47cdf0b458e608d515109b547936a5627a11216f070ed52d929c24a55ded2fe67152962931ab1bc43b840ac7b20561248c8123f3891615605c8ec30e4063720ab8b511bdc318a404b83eb5ada1219217adb0344f4aefc352d7ebf6b65f815286b051dda8702ba52d04e45549de289ead646772a3d09d65422b91080a7411c87a6808373c3900d72262d4d93215126a0ba2ee5134f6d91b7197e3ad1f5008414a9dedb67bacd4e81659495ccb1417436bb099a07c7b8bce2493469082353d1d64939183bfc04141a08c4dc719fe6043c8f29e6ad9a6814560c0a9da638b9222d4cfebe55fe5df9b65da15819ef5f4b6ac2593e8c6bd1cd9f98982506aa99470e5ddd2779c5bc9e5c2218797db33b8b148016a172c9af7b35afe47e5888ba8140a74243c2b6a038b24c36b3bfb7de3fe66209aed2240dbccbf5d75b67e5ddd1dc427b9b21c78808c4c9209639960075a7b9cd0a2a31b3baa5ee4c0074df164c598fc0cb71ec975a11ae79446d4508efa90e4104a366b84dac388c8a4220099014e6460f949cb0f678439fc86d744d0a0d0f12402637186bc57675241ac4d62cf4c51c32b6d8c868f0b67eb99111099a041f40b823f5049e86656f5a6236c8d2ef1478854cb147de9a06973bf0d945943c5827c1bb5c2021a5dcd35857a1390875b10b52968bf4dc78bc66c90ae3d275f1244f94dfdb1f86b3c8d6552bb2d8deb0a098110e8b99e0c18d9f8f2242784cb2ed8006f8d06ff39b76e4455c4f674b006de7f1e76c5c514100f01bad8ef985034f8b08c049fbf329c49d19a394f8582ecebb520bb57ef908a472f4394f979c1df104a21f387a90d7a6da3d97f703206d35d04fa61d99be772985b6f5e3bf78db10067d28f6da7221f7c22914d7a4c3e938e070448e7e58f340125d6be8218871e04fd941ea3d451caa8fe18f2b0e35317a7959883cd1dad66534304f4e626ff85528c729cea3331de039b0a914449a434d4e3c9590ab44e9a102c6436be52393208f6afb70028e2b63bd302887b4e7feaf70e1f082329f3f3675ef771c7a94fe3bffee58b0ae68cb5a40deaef15fd3ce47ac55a8af489bf6001398e6bbefa6dd8a10b2e6582c216f2becd4c468b2ebf03807cfc0d1f856c485cd931d26598af29405edc3f94afc9ed66edf9639821e291d3470a231b8ce83c7a0360bc807b3e76dcbdc38d50e9e6ec8deeb9100afe26390712b43bbbbf0cf725d4e9bd905e4037e30fbc0b9e670c34973f3d459e6b4644c8d4ef32559113ed692f26630919d0557aa18a923236b8553978631b88dd52528d60e0dfb186d3ed9e298ebc07cef95f60bccf011e0b8017bc4269145ab2332e747f9631fea0e8bc1a517906d96a3ab826b5c00427cce0b95f4e06742e01dcf8b9db8e45d8a86ec5597e3eb7b0e0b54d5b30d38e91f55fec853bd999ff08179410c254cf9a187b7422fe843e84271465c8ffad2d7a295fc96cd69096a68f5c8dae5c6bc4b4a6b8e726969f736f297c424641c74058f553b23eb2962ff312d4cd14909f379d04ad7d9b007331f0df916d0e0955083166e041670fd14ffaa2c5d81e7ce84347078a9a47613c408dc1caac6dfbc3eef4fcfb149c0af58d5cccec90c0636c9764993c0b0c73dc16fbaa79b670ab19ad283dba1d75afb66333e7d417be20ed33a4748301f1cf8b83e09235a1426c4243c458682e3303ecf6939ea2e36048308512f107d27f2a0460921c953f8bc21f8e3a84cd36a2e03aaa7cec1bb14350325958e2a301ab7a293ce4b23714b716ac16ba603389a79573ab2d62554353dd5989e154d33b5197f2bfcd032d73733651eabf78dcc50d79bdaf5e6898596204b1e92d72b99faa6c53053c418d882a64c5f432e39cebdaf644a614e9d8c904c6c88f942220a8de523cc12509853b0345503a7d331a60c026bc96a7ab7567cc2934661166d6aa1c2bc892a28ba56a70500556818b87506a1b64a103b73ffab28d89ac46308468612dd421762b38954586056a25e291ed9c596c942bb81a1ecda61e56570c8305696817c545d135314c691be30ff89af07cb8f2531870b20bb142441538aee11d83f4f0321c00d2964ab9eabc65bfbf93a40435b80175eaa6c2e93a65bd07a726b3a6862eb8a82538c50d71ba24a1a3db4902b11db51978ef8599a369e970ce9ec89c946dbde88766fc414ee8724330c1b88ffc82eeb1a5ae2bc2ab5269d6332ead57d647c49ee17777a7a24078d449e23ba4012ba9d049958d71e5ce14eefca544eb2525d1c5e81b53851783d898fb968e7b78b08f7e41dd7ecd74c547e7e80ee9e9c2d0b6b971cea07dac18814437e4c11f93b6f8a5d05224a19f8087c49bcd444d768f9e87bc27678dd9f243ad1f5cf83ff864c4808762a06f98e6e3eacc3d53baa08ee30c88069347ec7242f68bd41a696fc418062bca407bd61fafe4819626f750b15a1d89155b4cc77e3460f82e55e366ea656dc275a3469285ef3074a611c7b170aa34a5a64b6af7608f79a37fcc4f7a058fff8bfb43d49c0cae476840cbf994cfe9715763a431a8606f000d4f792c0e05e763838ae976ff94420de2a10ad390712610114f3cf25e5c4fc88e3eef27c7716e5b145af1de384916b20129c0cf9640f35e082ee89f56921669debd00fb960e027f9cab1616521798ac13ede777476c4a4e1073d5f02195efbab20f7e8aaafd6dc22b91ad232a1097606eac9d97bf0327be0969bf51e52585a64bc2fd815dda6b1cadffd2fed086353a3a9a59b0f4cbc9e0c53f9e4c10bc0b1394b3f1a8448dc1558931d84fa38994bddebc6a034490a9179cb8c75bf2033de45330457bf64a8f1c209161502f3050d7ef411ed83351b37e791dc08a56223a00dbce2a814b63ee75fb196d2a8848df8115e626c4916def2e37be0f1fe3bb599bbed904102e1027236271402e53615f4e99f0cdb7c2a8de989fd932d1f7d64dcb457d3c9e75073b807d9889a5ee7c8f2e89f03e52f5a4638f69c3aa6a18b5cb442fe52bebcccc3c96d879a4f783fff7695d321cb4f43a3276b79e084fa880cfd81ff818a03c7ce8256fbd5ca8df4c80e401a4afeb0a66173b9a49925107b83c0925312cd99d1c5360116d5ad48556a0aab39abbb6d90eede4f4e3004e88cd0801ab2cba68164e01e667e7d024a2045e8f33c3b73e79d4612d667f5cf00f6e5cef2b41e68283ae3dc8aedbbab56def447b0c02d8c7da2f0dc3246ded85327f4f57746ecfacb9978d088b15a47c836479c86c9813fd8a6bd74bf9997d5efcda5c32b3a87a2664b9c6d6fa3300e66f2ae472f54440c1b265345ea806c91074f6da72e52016cce6539f4ee8ada988a1152a8c9806ce95dad119aa2331d185a0d16f7ba94998593c82391333d94238568a1be54d5d5babef9fecae8688acc16e83758c0403dd10641af6427fc09a42e38829e1ee9e264da2e27ea949c7dba13f77c93c070914e53a11ddd759935ae402cc6c62ef3241fe127d35d0ef12a7bcb37242c4a1a31937de8d7c8f895527a2d61e083fca2b9e5ca506960599a6a9a133e250ca884e6debcb4bac0f32c179a3ef27a3bd95da1100eada73b42a631991b1586d560b69dd05dc62ea26abcf3cb367ac01660bfdaeee5b14c490bfd21b87553056b44307de136ce1f445999125107f6ce8aa87e581f9a78009ad697e996d0d0c1f864af9a37d73041aec926729e0c02227448f4593d9b663843f18208d1729dc44096ba2c8af4081b16400988cb52aadf6e683d191bd301c0ba0bb73fa2faf9349bd29f0349eb93203c787acc56328894bc4efe44ea1a3a0ccbb0508d1f83674cad61a49af8e3fabecb12d416b65f0c9075ee93bca82db388dcd3379bb6929b1ae9c0d4348ba49c52c653c955f4f116e2079f12156df0f6939221f008b619913141f45b56b579eedf516f34afa5301b0de9a825c8c1be6b44bf32c580f302d74f908b459431d70806babacba233b45ac90324bae34343de4e8a8a6cd0c2e5bc6ec13c8a8c19a32b171f088e25b20479119010d3c2db7d122418aefc76e8cb0f3af012cc0cff2d841c5385b6321a2b0047e93eb37dff071163e0a248e23c511ce1b6618822571329bb54e48a6c9ca6db66e0c21cea710a24474e26c78b90da2ec2ab9cf6d8b3e171c1b764f007dede138ddfe41f0a1ab94f088de610a38110ce86ecfe1408f791f8eb9cc25081a5ff494e418ad81393dea97123e9d01e1c62922d2e44a297bd9d5ecbe575709cbfad622354b9dfe653ac6037622f6c35f123f0a40f3b9eb03082ec9e3a317fdffab46504ff46dc81e13e242ae2f194c673c2af7b44f7e4a7787973740530468d536833af265bf9873da65e5b9770b8be86d7e4e13fcb433d783e3cbbc8ba28ba50ef7e5639061f1eb76bf055d0951a157f970de123a17b72d389b33b4d4608c67fc0b217b32e526a7bccf1fd11d9605859a9dff431c85d3ffac3afa8c786a0fa0fd89e64cbb6c448d61988b82989392d63e60462d74e74b5d5d63f122bf877a7d0ef6a37e4e79e8058fc87cd423a2bff5ae33434026da653fb10c527818ad3ce7c2b8a855c78dd5b71105fbe8fd647b5b93a602ad0d4ac0d8fecd04fd8a04eb75aac75cc3e4ffe7603f9060a85386b8cf2a880976ebef84f7e18bc09449c7717e587f55101d78f5e4195ed1308579ceea42db60cdeb8156fd61589ce589e69d361f34f551b54d2c4710fa588ff76b71c0c70b963a9880790b3a1b97076208312373682991b5b1f956509d5ee8a74093b31329bbc2e854888bebc8a42b5b3f5def1251b7f8102db6377c350427aa1b83151592b2bc45cea8bc3a434f1996317ca6dee86c11c0282f1eb1156d9e972b5856487d00532d777869d099001c5ef8a171ff2ac447599d18145578ea0103e20a187169d244048df967ee13c3b94dc5e6ef7175262fb00ac33c68afcfb45d388eddb4fe167c85351f3dda85ec7ffe8a41ff707cbe50fda1f544d2ce0164b08549fdf1f21bbde199579086cfb4295498664e5ec9ace2d33b46ca977d597d0f168e2c25661a58bb889c9d7cd7a2485f87014f2f45c00ea560225d2f6234ce58782845145c10741eea1adb25da0574ad1a602aec7be5813b50a14bd35b832fe47f621820bb8cf3bc85200e1c36a39ec6998a2a4b2b00f5ec0131d6be454a52550ac2546852d3f624b23dcebfab92148190c6f825ac45aa2ce7b8149a59a7e6ef4733355a5c930bd41f26437380f3d27e377885d747b460902604e2b13380231bc8bb1990a3459c98fcec34943cd49ac44fb61e61bc2465259d5406c76a4beca62c12a855f33b04573c4f61827a82c911360cb91b55028aa11027ea2451bf153f35adc2cdec017587291a6feeeacc5d1215f3f691f4e959766431a5de891924a1641ad8fadb6d41dde1178bc07997004052a5d8234d4f910ceac7afc38249eca4676400553f9932b737666363e1eb289d5790d563432ab76298b800edfb6816c1fbaeaf700027aae0f81ca665852d1708a614f4495428ad7f3a54bf98ae45fa30ade673de5fd845817a95fab4878f2f962886b22094a5a6911cc1397cd8134d548c2897ff12bd624317376bad8fd7eb5585d45af02276b0050bb236a103eb96815a5a9acc08dce80150d93e17b1be72c65dc6a026428162390d712c4ec25d86a43cf228dcc808b21c2744b7a8653e143c86cad7008f84cbe2c938a59f4a22b3c10efaa1813d99e54598629a8cc65fc36cce693ab4e1cf232ec6926e4e5a57edc71c46c1cb83aa0da3c51c485f2bdb36e18eb51954eaae3b98cd336d03c02fabf080eae6530a6c8fdf4b48d3eced987a2992edd06edc5588dfc9276de7c37854b9228b5230ddc43b289d5d63f1a69712edf8747b417e0270471cb9f0a5a1952ed637f857b1ad39ec525a5ec25a620845929c7cc370413b5945238c3665e58358812b3d0f26d436da2083d3b8d55b687c131220ce43bd3434b089f78161cd2d684921f5e4f78429517e2a5033442d158c7711ad75513f3463588ee382dd4cb1f700194eb9315d356161753960a22547d22ed78b213dae4e6267c256b53082464ac721bc9c8035b03c12531c810c9dcb825eb0aef0136d16abea49c31329612aba5f4bf0298453386fcbc77b7778f50792cc1a91a886b200c9bafe829652015e40267f6e65ce6ea87230c9aaa6e6c275d6335c04c473647b67871139a16db997b9e79a8032061b2bcfc6323d0fd18696af83a65e7f2d3819111cef071764e60ad946c5d8c7c6d6ffd605e793db8005e7f53767b37a22301fce9c41a5f47858e4eb888174f1a8540a64a05560f5d057d9c87174e607f623bee451c334ba88826f50fa9448d626b7208e1411df5ef0b48d2c6c2900d2f63209b847681a173a51e6920c5abfab9957a20d1ce7ed61ef0f7abc3d5c730d22443e32ac30a4c3a6a87b6c5d26f74feee8048f9d77bde7bf77bde7d07fc0ee24bac5d366351da57d9fedf25eafd1e111c13431ec677293c66b5549b9834876adf441d484febc85eca5d04bc91f20dcc9891880c5a4e14ffd2225251ac02fedfeaa45efd1248a441885da2c4ac69eb73bc104b44895ba017e68c41551e05cc9aae30d71417b32d0189286396f4ba3962a44a89125952ade7c78d22026babd481ca774a43321ece3829b77568e193a00ad2c507f29a952f23d035718e526441bf9a0375245d3e54828cc5cd2bdb8777f4a3516f11f20dd1c8168842f7ebdf87b628c2b17102503f21724f6e7f5e99623a29985d1c6f16063e1f72c215b2c5e1dfe90ed5709fe72179d3ac836809e773b81d96a025300e063796443aa1988c1574187d83add737261d4976bdb73ba470b46b224524074aa7b220f6fef160e1c999881f4a2938ea86d8d0ff7e3e5087b70ee68a34298e6029059e9c0d28d2962da4172210a94c58f88ebd1ad9dde4ab3daf58356437dd8b7924b60310f314bef811c31a6616d32217531e9b7c8aeace26a3461469cbffe44c47a950ca1e604f92593b87c83882da5bcf389e92f21481f572d4242d019e41df2d161f93d4661a2686bb61d9cbef7c26bb2a3b57952bfea704b2ca0bd45f7ef15fc6786c4b23863e9f5b1dda5d9462818d422a9e33dd885c0006a7bdd1e37202c0949bda9c973daadbc1b8ca69dc09cf523b1f761c797c72a098525bb620d7f4fc4a82d5c12e8c9e5f56cbd2513bc37071fdf11d0da38c7222236a3fa2d5b0b5719e5545b1a30e348e985ea7d7a41fafe69704f1654d8da4872e3e55eba09359bb1bed43af174d5339ce8a5c389dfe6a7b92d27820ac616d808957b4be8da06f3a8101ae41a5bec5290c251d0f60307d030e35474b16b6976951b8717989a1ef712d9dba81770bf53db236236838b5747586a9741adde54c46c99ff4c6434fefc7ac5ec8b07c9b25496806f5bc4c8ad3e46c34aa4ccaf476b032d0c0cced98c87c66bb8eab11e47cc609faa2d02558cfb7e7b18b016e865e11afd3fd1a9b0d69ddfe7963b35b412add3c2e38d8fa1c3598a581ce2ecbe26754513a7eae9cc43dcfaaa109d6c3f588114e623d91083f9265e9c1a9516a65deb6910d6b1c8bb0bb2951ce3ee685f07e892228674cc3fd7acaf504079f98f656d4bd8846eca7b9ed8d33828889c0d1313886089f7865ce0aa069a736b7b4dac7904a83902245259169e8eb8e3a75f42e126c732fc1b19f1c0f07d16e160858b0701421339d73902b12ad44a9d9335ce348c84a5b3faa1fb1eac478100c102394a8f6f3cc54267f1b63d98de44dfcb221264bcccdbeecba3b4ea74c4269d0fdaa14f95a21443ea9c2e7800ed9ada093f4297847dd6fdaa8f3bf4e33d00324ba5768ff107ee03614aa1fa9b16c4015f337dc4e6d600edc75a39c1b5db6439bcd031bf2768a6ff2c0f1d14ef2702ec022ec12f11f9e75628a28be9d46fbe43cd0f0b82fd347e12ab6fbc50f6608069bcd3276ee1452fabe0eb4b4b4467da5c0e266526f4747327edd125f946ecc286da4602a84386e23dc921ed00303e6ffff7144c0505b02222f9507dd9598dc411e8f93dacf84c70b03b561be0ac403df84a8abfdd662cbaa210b5059125f6f2148c2e8b48159e0fff1f15fa504747f1c5a8d303208ac6590180da845d1816521ad7d8a2a7143e08b5993703741157b0e9f3a46bdf267b3b80cec8a950d064ba0867f1248ce7dac2ab75735707b90b507529b2d802f60facd837964f3e8a5de57de616e89af573b6605a73dd614be517e4f616c014a2540cdd216c2a2dea22dea7d34e9a6eeefaf52406268acb4813829bbb9dbda2a16b5d3a5c136b6debe7e9932503fa7c66be20187662cfdb692db5d3e789869dcb9f9cf34b76fe3f9b2a8a1ad95bf7ea494eb741a7b932d61d1c4c8bd7956df516f41c0572256cc824c30e29e63160e431f980abd524cc5e885a8ad3b1ed0f411ee60150d04a7ce256a9b17fd1ea7adc43e77d560e7b96767131d48fa74ad719a67c386765384b67bb8bdfcd876abaeaac10d76ff367a0aa0d3c493ac247fdb0b7d0d228537b191c0fce9b333c31184bcc084f9ff68bd3c6a68fe54fcd85c5c220b15afb694907ee6a258e236a4c95b4459e65ca3b64826c866eb7291915d9b7d9a4a617850ec730130fe261f5758b7c837ba2c0e1801d0cd7ae940c89b61a124e7ea5b090c63b308da18edf75612d98d8b1846735997c3c75efe408405e6dda4604084f70d272190dce490c886b00f93ec2361e89c536bf6d2f4ba9f29dbbf59b328cfab7a03b5728ac4007b571aa5d087b9d6be807196776089b5e79c901718fd7623b1893da64d487f83d85085d84906b94837ada33ddee3f6f6b3eeeb62de048f49111d870ccf70f2e87f278f2a89b68037da5b2b519f41740badb208ae35c7c4e98b0080c613d7b85a1a1437bb4694ddcaab09cae0e9c51811f233d2867d8527e804171e58904c1b452b355e19258ff6a92e27143fbe218d60680e9bf212db3412b42835e009b05eccd11e1d22ff496bdbb8734adeb84f17c04765447426708a3243cc7a45e30c64de82c460b64645e12327f8948e6b3144146badba15c6fbdd0de71583e69040ad694a190c4d92133027499c4b13583a18df7002db99abe43c8209881b0c78dff0ee4e922228aa254566c0e8e0267011bde8b4d296b0726d4b3e4cccf584738a32e57773adc63dd164c48948f1c6dd945463e9f9e41e21d636c54d902c37bccd177e9af7bd7376c9d950766167deb23415b7ba0d020534cfb16aab6451bfb75de00622702e64fc7ab4b5e4533e894850317da135b63f9c2474bbe4c810da9041cf32519461a13a23011c808cd439eecf8805b7973948234538620734171c8628407436cea14b8e803b7fb10c26e197591447979c25169042cb22712c1915411ab9a39d8502348861e4570760d188959096d89a11916bbae41460b8ec43314e6ae786bb781fc409d248fb761b5667e273aa14a72d896065e9c3869193ec3d656900650deca408e53c8754d00661762e8807f21123e81438f56aee1b02796a0d4cce753503080e53947b793b9985426c6e4380c49957fbac13b122e2a255cf52c0db8971b804cdfcfe7a436c7740ce51e6880f6679b030392498d038ecc2d86e997fe3edd6b5a3e3d80e5e320ec3df508e687ba5c74d2a42174cb9cd4282f86865bd30535ed7c1d9b723a1e4af251dedeb92e39a22df8a85a07e3b2ff4f305c7fe92e0da7c8e62e7bda0ed0262a15868c1c0e0fdabe31db6379818515a62ede8c2880a8d8d519558a49bb28b71836975557c8cef10b4efac4ed0d8e6b4a3dc433a6c73df4068a6073e57e624664c4993b708531a8a42820a7f77a5cc65783f9009121e2c2f7e319a240774920f0cb4f8b9d05ef3b104c3799808763615cf5932c17010e78bf6f6d938fccdbf2409f2a38010b0a7b4d74c495764c34e8a403b37df9e0dd5f198f92ba82cd496e351c1a23f66874a06ccfa0181e53351e446d76978579c70b9e5b5332e6ccddb07495b30b5e3ba3de2f055b714e5e1a931d2d00b7579946bddbaccd02b4b7475cd3df1cfc8ae955ec9ca0335d109371ecfb9fb72d01b708f3c4c205ab6d94480bf619c6d709c88b440a60ee8753878a6604ce2013fcf405d74b67633d454d9a380eb611f47b56bd7ef898b0b28404b82a5e11d2e2c056734e03a9ae39d27db0de2bb9bed6b3386a1ee526cdd3053aa31a6946591ef64f38014feb3a55f4144ec84e602472707d03c04685869e0ea380633015e873c120cf49743d278eaa21032e9f0ca1120cdd732143c491f01fcde60e196af3e1e06a08eed160cf0b51cf3b90d8efc46e423546bd900edc4411b6ee99f1bb2bb4e74fbb249196eb962df7079c6d48f94e085f179382557ad53afaee7797d14408b44b5f1aa173b39b695722bfaa1ac0f819b460e60f49fd54088e5b583a270d34a9ff078058569c532ada47ed84a522cada4b9609dca1df50a0c65450517919027ead70b0b0d934d91cef0f0429a3643fc40d0182aa74e395da5c6857af3e62aa722f037c6bf91b46b18b740f6417a5896484787d52e3cc454d5d72936c01948360620e9569816b264bee0930b57effc1170e788d1900b3426880680f4a7db7ad742a84d4517cafddf0479d439d820b38118d999cec1a2302bb5749191a5c6afd839b819a385650652da33cbf1323f411a2299cc42eafac05883912fccc29331232d8ef6770bc29e986238b6be73da6098bb51c671e0bd5c056030c01cb2fbfe0b2f550593ee6e507811e3c6a166e3cc2d536967d365e4df6d549d5e6470a3307bb13a0a856517d78adbff92da3a49622b94ae569ead59f77e62aba269e34d7832633c66421a1abb6d50b3564a23fb3fb4e2835ec3054ddd85d4019417ab35d8b04089182bf8402235434bc49ecb0b472b5dbb20e6a5d129c33c4bc586084314bd40e9b318b48ee3fb968a987a14856398615a9fce1682942f3de55f3f6c068e7a894a12e6c287f881442639f962f1fc9d00f19727dd5428cc4a9d8f37b0a6a542ca5ff75866e6add0468971cb453dd1060fb9f6a0120af68d5951c2e390979601b95c8940d4ee968b6f544e2820abb181d406bfa1e7cefdc1fe8a7565b24420e84d78de2b7366d0136c9f8fa544fa6d1ddf965283b8b137357306112e698ef5adbb26104e6d3e02483e7c680fa7a3f2ec015f4560fd38141e5c0c182bfbd6dcda1f0ed3f9db59d3bcadbef02b16a5a623a7d0efa7560b3a9a2a42530d5f8ee199f6a2d4727f742d8e49a81f0a6f49e28e159ca7ddf4298315e60293a4589071d3b823e6b294c3a1e653798e164c5957a10c9d9d0806a7857cafa357a4ea5cf43bf2586bacb82c63915893d3b721737371eb205342272c40279a71f94b86c21423c1bab6b3ad2c356e5ab48cb566b57c663b32ff38a3712e842ad615923fec59cacbe4c10a294334b36c2172c84bd6b3f239bee1278c9e9ba1cb49295098ee984434e6c18a7b48456bd091ea9737541be401ed39c9475fc0fe140df03c58c134c9bf2628318978b0d2d8b8c7877ff42751c714797cedfa7d99b629a280cd6eee15f6aa962151af646a4b714016152894c8d40f26f158f4f0c498a1601d5ec5bb2383ef95bb014665135b8bcd7ed782c8c9a405155c5ea1b660549ac97cd085d3358f3592d225cb9571f8d33d170856d547b39d85012fc9558098cf7dfc7eed09b01a17d9f849c7e3a735953120b8d765559175d22287b6c2b1ca362c81bc4e328045b6d94ec420590191f85cd68fcaa776ea2274329613d7ef9cb2d53b3bd272eae80507d8eb273798f5c4857f21ee125b47ae0ad9b108976379dc9495fb5b697462cefae6d8fa54e1ac1f5334b1df23c2b98d4dae515346dc94c27952e646dd95946ce599101288066311474244d1d4bcee85cf45adc3d78497507b0a2d3ddd92d176ed48f9e8d520068793f8ac76bddd44f71922d368490c50a07bdbd2f7ad102dee49d016d3a0a232fa1c705429c55c642a54adab7405c080b609bf7a83c80aabccccde1e7712170ac1e11f264414fd53dfd20bd2b108cf9b019f0a6a6d1fc453da021cb6b6f7808a4b8a8a10cdfc3e04b62c84c103823dae65e2d1d4c687eeef107f049cfaa5104a0c441ef779ff60dc6b18b00fb3d39dc2f705ab1405bd3e7023b5f9eb5d0a9c0f9e1891bc4b9b29f1465c037ceba949c57dc6c9c386727d7c2983e8dda57c5e4528f1860ad0b87cbaa17f43d0c8f5a567f688e220eb50c15b51232873664024ce85ba4ff3d1037973a03be4c4e79a2453922d97637bb6e95667b214452a1948d5beb38d18a5ef09c0bbe99405974028c955baa91217767d7aa858e12d091d59bf0c24cf9506381a49ec90eeb7b5494e8cdaf0f368b1271144447bee5243b9af58f82dd8ed369e55dbb879c187170dfdb8866f346e51560f025ef02060dfe22562948b55f7a5906e6fd69eab56c7451de580701b5f458348fcf85c0dc993daa092415b965e2497a1793dc3275a954d89dc8edc8ae4cead8d5f88a88cc33bee3f6ee7f24b07c71fdabe8606af678cb5bdb9b06477cbfdf7cd2a82ef02b26bc80de25a213cc28d66cf298d5e66fb5d0969c20419742956f040d02f634fbf2bb4c7e2c34c91e3a0b7bfe4c27948d0c4249a943c2ec9010bb25b923c737d49d1de553be7e36f4bd7b6a55db3121ccbee143e5c76cd2e7274421be68dacdeec88e8f609cbfb18c6c0e40622f299403e03400c5d683ef5c7525324b4b51f08c37b7eea1957f5de3dd1ad1f2acb21be82b6e613d2d347dd184cbc710d6df5e540cc8edfd75daa59a5488fc449928f7c1db4bf1dd3d94a2a67846c06bec6242287226134a81391926a100eaeaf23450f244849215f243a269b504d39c9f0a83e1c43730357b2a1e41b69e59f21590606f74382e62c3d79cabfef678caea223b4085b7c1b29e22c08d962f68b1ec062354c39737208bd5b7fc089e2b38f050a6d6420710214871f794f7ef709629da7f26689c09daf128bd1330d69f4fe4f637d90a4ada6366dd13b97cf7693a02556e7637015f1596e90b551c07ba7677526dbfb66ccb8d30caa1d37f072dd9968d20010ee167cd352a46e0500e9a5849676116e7f2c3c0cfba71e97007645f71857b1058bd70ccbcf3c85a5173f0f90d6f9bcd4582007f1fbebf431ca8c675bb4cb91384eea6bca1b9c9e34301ba0ee374b915304d8ebc77149ab620468bb9d4ba8516a1a59b947f5d228902cb0424a40da0c9f0f6e473f241ee6e0d7320aa7cdd578a04490d06937ed22a84bde4d9d88940fc60c940a8463ed39f63684db5787f469ea9942c366065e47ddcb858cadb433d4875f29aa03fc2702da9ad9585e60caa4a40e8a6203a45dc72979d6367bcfcffb068def823779d7a1d5a8fa7645c3341c46e89f5d6629bca097e02f12b005bf7dec2dcc47611c7fe3300f6bbeeadbc231ec12dc071f73d30a2828e2a3ecf90db1cbd8dade52ca94e4de7b07c205530577054e943e4c63ac797a3c4a3c3e9e20ae00eade6bc1ad56abc1287dd319038302e62f78abeaf619de030cb144f0ddb83722b5b75aed56a20743a2aa8407b11da62fa5253526867a0cadac7c44f168c264adaf879bf052dbaaba497491f8a2d137aa6f5b96476caab75aede613648545316c0290c8ca97da56d59df39df896705aefbdf73c9fb4a0424feec93d3800be17585f35e5de04c4941b2601b51b0378f44a9818bb6a00b371e4182c3f9a7a080fcb192828c5f75e34938fb333c16e2f5691cbb7020e29ebdd2ff7de2b73da42fa9befbd5831ab6aad02197f63ff1fe849d3b5bd6b2bb2ab7745eedece8c63bd97d6b3b7f302fdbe32e79c8182a78d5c7da327ae40a350db796bb057d9ce321e1632a8988a6364b123a388920f327783a12033866430f59a8c32b744efb699d75bef7ea995a88ae26923673236752b7cd6bb5f76d37aef257105c5ea46944fe64a69d215c24bc9459250e6568881316be5aef1826e310a303c3930d3850956355ae29c52e19f1e3a63e5f2707937c16b1585efb4912bd65f4ac981b9c5240ede537f2945839d6975f7facb262d7ebabbdb9c367c3b7700c0d4ea89e109e289a25567acf7eefd6fa2cbc497d626be5bcf9cbe86d6bb6b56a68d94497165dac855037c818c099bd346ae56aa57a2bea6afd5572deb8d58bd6a89071d5353c62f104b2b641c048928428e3fa282622b29b4d1d900b9304d0b732242cf60fac8129795fc1df9c1559644b660c01911a23b1122fb5b347ee72ac7ddf192300c52e4068e1c494511248fac184cc20e4b60e4769278794b222cfcad5b6b7f44460c953f53e72b3062094e0724761cab3ef014ec2951e38bd293c064833088b188089783b47584c9496744f04f11c21c3536c70647208a07c60f26462100e576488ae02082e4a4c75a6badb5d85a6badd6339d1240ee631d5913c7b1945608b03523888aa5163b608440cb458f264c528884a7bfdf3205182b288af507c23142231ce7799e3a5a1ef8df10ab3581ea54d91f189a683ef0b638d490b13034f4f48458e1240a8867e6558cd55a6bd5752661257f58362f8c3b9dcbeac57e44425061d223c9280a94260e5732de634224f5fb30a57384cca281ea22bb98b185bb7b56149ab391a13ba97f583d6eec9795234daf6c257f5852b124fb2f7906c9e493aa93750c9db3b203b45a6b6d01763aa03a44429d291f0288a519564aa4764d38200308e24372a2d483e3010474a28a2851f53889323f64709301c54f930c3b4b3a289d6a560c7b4d423a1900814207488f08b003c9046a968d3c60e48d118496272b15c8e102d762c6083d4460c900421792118f0f74587bd8e05275437477187c34e574f0c5b851410f9f974e948f9f0f8e2c0975807211ae58daa3d3df1121add39f112a278415b6923fa38c34aac35a063948d19201e4c747d68484838987202ec7c6024c0e6bc961e70738c5338542a6247144b4f9ed009d8e64caad3ed534d8a65996e5564b9cdb6ba3866463001e906469a7a8899026562692ec78a1f3254207e46a0aa678e48cedfbffbf308968b5f6626bdd6d562bf4caadd6270104411ebba61ed2548c9e22276a6c15f1b2f12163addbbb001248018975ac9de43065c087a9a3f5dcb8c4e195044e95809200d3ac9192b2525502c000d78a9a165b1a381891f117345e4a48423c719d5d96143a05b9f55093dafcc8ac942f5b2c7564f7b9b15dc927a95ec6a159c935611a636c690af0f0e44f0bcc9a05410fc67fd96aaa9e17a41568554a46d89a4aa3d16a410f393ccc5835a065d35594e50d0e90d80fab9fbea1470b51c0e09542438d0e863c153ca91141538477745385e4e79989c699852d3e3855762186359657f249ea88a5bd7c0d4e4a4a48f04089a2528ed10f125c325932322c0141da8043e6dd2681b0407cd67325ab3c30ae1a5893080d05b070f4bca64e7465b800122c2ce30e4a040f05e0aa86c43822c161c3e4802694c4840a8608277c312888394f6c92d79a6686167987114c0716256418d921e545140b28112ad21585c593103c21b1849b4046ec05017b67f45e20265677a621d3461e3101a9acee05a6ab0c259cb28e757eecee04c446423903024d1b49657575018875e6137f2cc77e78ad907a1b57124aa9cb784e30044353d34c2141a6d5f6cee952d4f1631fc2c141a78d446333d9fdfdddffde7befbdf7e6fb3f9441df21622695ccde6e4c621f2ecab47a81a878f1ffbdf70eb5a5e9dadeb5dd2f00c9659a9d3da23f6161d162d2746def9a0b9c8dd1ad94b3fde278da48a85e117d8fc94236f7de0b2f86a7f9a49573efbdf7bd56c10d8c71cb14ad5b045994a8ac28aefc98c958e4b450c7807c2a3022800171c978a9c51756e4a04ad400c0a835010fc74382cf8671386117a5724145f0a8456937bbc0822b077621c806ca8746ab5aab17520c7bb6265c10c2e912aae76ae502af67aa1456d2a9d8441dd2373f5fc78fc3f0ee8255906923d7172e2171c228ecd8be3128ab1e6ae34415ecd662fb6315f649b33058859574fa40446afe08bee32d26cdf9fa756a61617c15d114dd14e514f914f18a866272ce99e7d9dde70462824ca465da48a22e4cf4a55fd0a82f6e76aeb130c1218bc8d1520445901421b038b0d891f10e4cba74281141878dcfe79f5356b08b2b17582eb4541c8cefcdfe182b5973ce39e75c4b62f224a02751799295275d79125692d62da9cbb4912bbe522750e9e89effe2f31ca2e240540f64f540578fef3dff6615aca20366c9e34a02876e56df391f9788dc6ffefc39fffb5a4e9567957957998795795a99d795795f375f91cc54322a71dd2cedd6f6e77bafbe6bf6f94cac39e79c8fb44c1bd9e5168ebe686e722cc4f0b9c59458e2398a801c3e8c5545787a0491f1c0e767042122a207e6d0695765893966beb10088b4fe184cbd689a91fcffff82d2095d27ca430b6bc625a18a4943cb93cb1566719af1f815a0aee5accada1764d151af32dbaad6aa0ddc4a6ce6ffe68df32dbfac514346abed75d78caf6333efeeee3727e1d876c2a9748891615245198c7418137a54ab503b580ddecdc2a0d4070773e8e95e43e7de275c06d6e080e5b51a7514c5e4e3b5fa7ed9ee6e02c101e2e801cd101e193716510089800374f5f7efc3d4567b6f08eec47585354456ab368e7f96e512f404fa4e1b697f450c67f96516d6aa30f83031b7db3ea7409837a090cbfabbfb35cd2158ca265b90cae9f712d844d4166c284d8580019748b8fffdfbeeee4e811138834c97d3a65d4c8486167409e625cb3288691218a67144a18e542e8d5e2ea6df34c452137c86ee32c5ac8ca06fc1721e7d448ba9d59ec5c9e06281c9a64b6661461085d6eaf4e388650376d2479a98829574bac219a14b61e5455b5a7c357869050d336bb8d4ade4138d56a95b3185d9e58161bd1b68d67bef7d79c15a5557d2f7ab9aa5a60d0683fe9e71bea1d66a37a8118aebb5d93afed98abbbba6f9326d24cd4d8e0f6f28030d471926df9b92486a7937034c7ca33430c5deb31308295a480bd20a68851c9581b8de6df6ac3708a2834b03867438f2d068501abe4c618958f1fbcaa0249675f38bd134c6faff3062ea28855db680c221c2a240e0a838262f760f3eff41e75fa1b8feffffbfd6b2edb20afb9f8cbaf5ff7fe3f727f3fe8d3dd0fcffdb9c36d2ffcf9bb51f99e0ffbf9641073babcf47f370fdf7fdaede184f94c207e3fa511fa4b8d46835f3bf8ceaa0a4d27eef0fc45d7300cf70d35490688cd1ebb9192b2a88450e00c860836e89041970c86dd3f7f3fa0e411974e85920b332831aaed346ae5897c1960c6c7ca78dc46b0a1b272739988fe0deaac71ecd698ea2a62f666dabaaba597a7e2368d60b8bcddcfc308dd70c64cd7bcde89a73ce398be899365209fb74501d6e62ad68daae08634c1a9bb99f55ec2f5cc92f5b55778fb187abe7e88343f7d2cab5c9f8e2c701284dd7f6aee976a68dd405615d4feb94d47467657c7b1c9990b713091a34576531fe1ec20ab0cf0870f52c7482034c078df486d595cb408454d342c649232682512a8c49ba2b19bff7de33662def94f4ef5b7f77ff6fb1dddd3d68dac82126eaa26adc0c40c255c3b77cb1b53d6e28781e2cd346f268619e2ecdf3a5de8df3c5ee4e22709aaeed5dfb31fe70fd1c77b89d4d0d85cd8a130a1e167c71beff3c4058b134c7d7807b0d36af21f71a74af617773f4e28bafd962757c6245ccaffb678c854d4ef7ff73864c1b79c404a4b2ba5a73b0b28eacffbf7f9f051002f8c6ee14503035c19c69956b259d74984e2e8c595898544aeb9e5b49df166ff532570197cc87fb1964f44bee30b53b25a5618c491f0f256bae58fd9e8072f18d6b7b9b2a76392478034a60ac63b4d62a5655ad6aade297004d3dc804dd69232388cd389af1d150c226b12fa7660f62179ff1b4911804863feaa933123b1df30f2741ff97e51109092d5aadd29d36d205a7471b58a88ea898663bcd6e7494ad68158795e3b8721c582db1198f9a9d39446823222eda6a4c62281f54106a0845842a4219a1b858defd8511a84cd14cddace07bddcca611d24c8649dce4336d6453106b0d046484c71881d804480ba02941be36d0d0e4c18f07c2430824f71afd4c88cdc899e1a372f13fce6ed4c10586e4e3483c471a92a926cf4888adf2c0eb399064e2890811d68d0c0d9cc8ea021a414706d0e74fe8a0e9639792aa5aab347ca78d8ce1143ba3afba92a1421365c5ce91192e4210da7102466faa460f143f374b556363b17f99cb22ae18fa3bbefbe3eb63429ee5a52bd34662612ddda52e7d6d9ada2ae3e616f3bb484a63123f0d9f884f4514c59415205a021a5068b0521212fc4171f143211443c808e23c8b9258ae5699ba98be68d0e8acf25afe86ceb4913776186b1ae86601bbd7cf7c16e5680f5ee52056504b5f3549cbed6fe786ad7b63d6d2cd6c16dd605b63b8d620fad34061626eb7db866261de8dafffbf698e70de6be308c49d58af08bc8187e0570b5d861a2b111b1842d13dd5a8c8b0227ffe7c9e5b2ca6d598c44226d346025721950e22d651fc23b6d4ea1ae3d4422f3e85dc61cdddf8c6dc881fa43273b7def7611d3b9ee47c54159778c850a087c4071bc62127bb7f2718c5bcfe947e861fee50672681173d1f0ed2d30c29af9ae10b224529ca92985deb000fd61863ad25b0a1aa403611a84c709153a1762890c0a238e1e94b02179e84272f6f814174794a026359e19b55f1d05961816b7922b6e8144596272a980a906fe5e987ca846cf4d39084985051e5a96705d6a2277bea4096f28ab1ede65386f4d1ffff17c51746d811cd43bd34490caf30a24262d7c5300f65af4287a7dc8fd748b56b50d0099655c59007e33ea46bcf07e42035ae445c9a4256ad56aba9b78fc1d09cca9800d31863cdf365da481a7ca3d50b24d0cf402ef6056f55dd3bbd1da51ddf4e7067e8d8020c25a203f584a91a63ada3d1dde872743e3a9ea5e18430335ff056d5ddc3eb19ea39ea61ea01d6d4f3029a7962b9bc5acba1f21c2bcfb9a2912bad4693a5c8a9601c180e28f76eecf438364f52680010420745a6d59e35a22fe48a4f5f44d98510c62158c5f4665bfa30ec062d7371256d34b1597d9fd6b74483a238dbe8fa1206e9c0dd7da66aadddda7802bcbe316cd36e898de2ce32635338a208452b6858891da02b633378a603c672c05ed417accf73a6ce6cce15215ba5ae0f66c53080529c9003c230f03262f0c438c207136362f6aeed18d29847c0ffd8b7f305f97a3e259fcf17f40d53742beb51c78efd3afe7cbbd21b658ce28a3a0671419b602ea8cb19fb52ffa0e569bab6774d864f4650c6500611e3cf8f73682f2a16198bb88a8e186ffc3ef427987517ea843b6190b02754fad8cc257db6b761626eb7985f9069237b4a177ebe447278ccdd82b0342dda917f3bbe52e2cd62fcc35abd7144318a16bd68b9241eaee4af87551edafb42153bfc5acd3f2b9ad5dddddd1d5b77ad8b5438f993f2adbeeff541e49df7de1b15e3dd7d9cb88f59588a7a52abd59f6ff7eeeeeeeeee37b2f81dc8681a49c9b491bee090288354bcddeb2bc270a3a2316de44d8e0f6f4886ea088dc918e70ce3986dd0b8bbbb3bdeeeeeee1e4483ffbafe2df1eebd31882e348d196f69cb45d69657550a32c8ae08a885505211a3bd19617ca7603667a5f4d1ec849e5a1da23b6da410290467722f4dfe0d39e6ff7baf5236edbd38977350ecc6dc6e3e184e3c67e110217bafe9a68bb414d22523e4ab0021ee3dfa05dda0c422b0fb6387c8931fbf2fdf00b660400161ca87cd1386b3b6effd05d9c5648670dd7befbdb73601108a24bd417948fa3d1c04f31fb8cb235bae9f3a6580049d850d532688ceca5c118faecc8f630d6190a9846f465d52972b158c49e00739ab6f34cb6e4d54da045e6959fc2f000100318995561268846bf5d35472c7ffd748eb888ad6910655c36b27e484140e1947613482464e93ab0f885a45f78b1f9661bea6de2c03b570ab6fd3ddddddf7968fbbbb04371fcbb047d3dbe3ffff5ca9a336e87de2c19c69d577da4877778789b9dd68264ec6d8fd46d125b60025f7f7ffc461982d1719b885f4e238f9312e815d5ce993e1692357100142c1380cf4c2717f5723100163ac7fc462412a532a30264399524baa842bd642863639c27ed2cc354c7f487830e6c2a133f06592cb55372daed5263bece5722cc262614990d58ad1c68a052741472a16ba7409a4d27aeba8559f13d1ec6634668cfee3a42fc2d1b491389b9c6e97fe4d782f1a424d6a3928fd7bfeff4aa33806511c83afdbce8f1f7f512f2fb9dc8d6f0dfb3bc9e656d5ed81b7def758cc4809dbf766202e68bd270ca20eeccf47860aeec62f5b55651568d703ce59731a0bcb07fe02acd9610ab4decd0df026c47a2b90b977015384725c228a5744990b0523eb075290203a7edeb7cb939bc3d29b2f8a81609e92b80411c5f9c56a2dd147b66385c5b54b01a36a27632bf0f1e304c70a1d280e646c8dc43dd65aeb80124a7e29ec12e742121f62d65a5b334251b73953b5567d74a78dc4db5acb63b4c5d346ce60d284d93d13f210576b2bf4e87a76d6da99aa756cfb69adb518cb58e89bf153b0589b065031c6f72ddc182d0cf3f0588dcdf3c888afcd682c8dfd66b0dcfbf4a3b8fa464fe37bce7e617ec7dc68d8bfb82c7f45599dcd5ce93cfbdfbfbf63f1d94baa04df30c69e5bd0b406eaee982b65a94ae2c339a0b52ce369236f5650e38c5e17ebef9757b186a78d5431c214bb12d6dc7db7eccac7e18f31d88acda719c5bcac8be44e1bb9629ca40959fc47f3ae25c9316da40f6fe868260953be9d1bfe8d448cb7efbb7d3fce4472d6df2f8f62ed30d1fa5e5363fd2dc2aebfc5e4ea461386174a647e030f3747214d780099a464fe1663c4c7b491bca1192347f6ffe98a08e7552acc1873b7dfeaef97dfb4df16dc1ee65661262be834555a09335f9ad4add3272a0e2d7887dece2997c4207c9936926686c88d6a8da83f0468da482aab992157db8a65e603ae1b6f6cd233427a3132eec5cf04e96df3698a97167d5e0cea9729190e9dfdd1226de69c35cd4d6a47dc9c33f6379f8c762c97eac8ca34abbea862161c7dcdc4a03175111ce4108441b14edccdb4c9dd6e5cb9bf2a38a3b7f426148099aaf5a7276e259d703eab6f5476e232c6472c422cdbc52e27db9970f18dff1cba315b9940d7cfd4d6ef064ac5063386c60e287c4e1f76dc499cefff0f0c6631894b60993652ab6b2df145b39ab8894d49cd4b810231a7926a9574024105336d3026e2749a20a8d46bdf29a9062802431900000300184892344ce35a720014800727f068a4cc6c1c0e8c4391301446411403310c06311002000c053180e33c895575436464ab58f4dcb2c9dc7e6658f54a090f56dba56edba1b6e001b971b7ed01e6f89af44d80e1d1735491b11ac0667742ca1b3e11ab83348297a1451fb9faeeebb9fa9fe8ba6c9e9202ab39dc53d522816eeabc75562b38f6fea6aa17b48dc4137536c0fdd1b5374d00900daad7ee2afdeb066095f83e22f61d9e875f4563df19bb69171b0238dd2a8592954343c9d77f9cef50ba45c0d2ca44e8c4cd034861a4b711a5011751c73b165b1e4e13c7ab080a40507d9642b357701db6948bdd7688aa5aa26f89337022fe2264b946a01c5e5d3792c1cbd4992f7b7e03ee7b650016705a78080f03a516c4bc1a17472092e7caaa3b4680f3a0e94656503a67eb5c2abc1004108d378bf95e874881474e5e58f36747977191514f34011c2a40bb9c32db3888aa5e1a22164278c1021741b8b8a83e9812553cde21a5eb67ac64e9df79ea55a0462432e94aee2f40299f9da19418cb2f133ee2174b642185172c78bdce31c524d48b52599967c31e832e5de10c248b040b06d303e2a22c249b8eeddbce3644f11382315f4d78d3dcbd3fe3f2113f56f1f013ff620d7762b1cb6a9ec4e88cd2b6c7562a1f0cd2c0d7fab16edb7d3038d73b2932a9669e59f0f2e97e2ddaaa69721fb21529d1fb8d08e4d86d702016a0190c2912a198208008203a6db30953b4371f4178b4b9a896f3128a317147b7a7dbcd89cc896208686d2b70b5a8da1135d41564f2a82f1d6e522070dbac2acb04f45fbc9ebb94574d1e4f0ab2bfdcfc3cc907afc905b6ef1d144690a2ac10db85da1f3d806e4dbbc53a5990f9893644e76f7d95ca22932530619849e6942dd78ebd95205ff46f47d64b221f89ea505cfc79a10f506ed203966250ee3bb0235e504e931a8e5284e64185f491711436b73be01caf58353f7de7765fea97dee0ea775dc83b01f003618e4a1b97261008185f23375e26a7667559554e67b28d7596b0f2c1a79f50ec8bdaafe06194065d618cacc3ae0ff8610cca00b8fa0830ba1bafe92953b3b0021cb657bc989b00f2f3d4715c29f627d6ac00f2c55c629fe702e66c01ab64165072284f27b9c68114dd35d1552e41ebf08b3efa002946910489627f8cc7a32d25fd3f59ac73344ff4ea51a122a859808f1179db68a9483d8e4a4e0a3e774e20e5f401872d151f0ff27e7cea172dfc1be3866527e85ae134a1aa8b2d2d61d7aa5f42a92bc585ae07af278566d650542eafb9523075405f15bac49634746b1f44a460db5e5f296fb561040a12ee9a713b057a0fa889417a95ce9a43b0307e1122390a1df94e96c7681b4bfd2614ebcb6aff490ff9e59bf91891d76d69b94bd389aec96ac822f64537bcd86ee8d1d7522965ef708cf43185011317ea6edf8695c8a02e5724fea1cf04206412050e6544f583007ac11b0bc4a5248801c779929a951059e423e924e0cd011a38c6d3f3e0cbb4db2d95976a3a7284ef699159701420f6119e7d2ed93fe541df1d20fe788916e07d88ac14915cf2b51f4e2c5dfe53dc16d460092ccb242a72e975aa64ccb3deb1531e1746862c96a2d965f313b5643deb06cab9da6b99080ef1341f5c38a6dfe9130f2698b82cec01e9162d38e932ae23d141ef66bef442d80336aa485d721f08ccdb0dc2813089c5c4757aa0f7f43d3f1149568c369bb011904b4e918990fae1ef15b59a908bc4a8575cd291e4e7a1b846f6e867706322ee16b78d5bbfb6c9b1eb1cbd15501b2767d243de8901ff4cdd7a24658c8613df3fd35c426622c1342615718a5426b77a18fe765254258d9cc152e12b1ff74d3d0c1f202f9a4aaafcdd2b92575eaeec3593d8019e32c9d336a9ab3c2be80407a384ff33a9610d8c17e4f648b1fc538bd8c1670c433902154383c8657e76f454d913f503b06b0fc118e441d444167590b4f23a4238028878051012b9c5d024a25ee86b17da2693461c7456dc2e13a5287d5aeccb08d313d5495170f122624b2f05ef5320766b04d4274836addc885c8557b4be2c5c10e8c4448a1b547910233a528e29507595e389fa29e2274609dc5d31a0685650886d822239c919086aef06159d7514618a91c8212b9fd484a2961d574f8795f01ed2f5736e15f6c261d6cd2ecbec37aaa3db23ce80842286c1730775551eaca098d7a33fb461ecd19fd28d5e8103535314ac8f226441828b2a72f10417e0f8090746b3a780ea783becc4c11cfc22bda57270bd69f8caacc6d165f601d0c610df4d58685dc44c99b21a64ad888c05f745caf5abe38f9c31bc8a37eb0a002f55f32171bb1e8087adc152c47d67c45136886f7c83006d26097208410393c03c2eaa8a07b866494086f3b868a17a01e115c8c21f3b0c29e1f669b659c9579c38e09c4de25069c537878c0be927d3beeda7e7d032d4eb44a71f203b99b3321a1f8cbaa00ea103fc238cb256caa98454d701f2bd9937c5e56ba620fd553350d361bdbc6d5ab98ece381f66ad2ff6b259d5d387013607b81eb91a71cd5d81e27a95e1df9d7633cca6c6fabc1683160543fce077a87f52d2e6be902d395f3789ad0c018a0b2bc4b265ea9133b09c7638668ee4ef2c010cbd73bea08df79543737adbafde1dedc57e5dee69d60fbe6897da5ee6e707589553418f1c342406ff0b764e427a2e90235f8f5d71f2402958b6bf3b853471681f36f8a4860d9358e8fb54fe54e8759e0333620fb16d1ad477ed5a4e65a791c91043665489c32f4edbe28cd46e5ed2d28539319ecd3c87b22f0b6a941fe61a601083a9a1c503d0c2d14152285b2ba8a076fc08ba262ffb1168410aa8a632e1eda7732d0920ff97016d8d8fa5b3055e2d2da8dd20ed940097b829b0828a12ccce95720f78f96226a06f1d7fad303da19d415ee27ca0b3a432c6e05731b058bf7a8d753a8eb7fa5e733423872542da22d7cd7a0d3daa6d7ac655c8831014cb3012e038917f7729de4edb35f895ac38e1a74584514a4865b4ce02093f590be33f120b2c41e86be358ef83f6042f5c63b39136b0c5356106a31ab2224bcf693db0168c21a8c82548b4ac4f2175e89ebc5a4b9a152742e74faaea7672ae72c5da76eab5c87f346c70097f0977a3e9239ac0e26ceb1731bc23bee1d216fccf78d0d0ad441c3e981d382cd7dba60f42a7de8709a07510e515e54e5fff2b7ff804a128bfc0d5a3b36c1fd09f89285bed6465bdaf587f4bd58c1f1f34c3fc4ccda62b477950e2ca248fce3a16f09b316e37e13a6a5f6f9b062c5c7122bbd3deb4c1d7bc0ea21e0be163eaf625bbe5dd09ba6fdafa2b2d4cbfdb12407bf03107245b718a2b8bbb1f7e958f1c386aa9643deec4c1f6d83aa3dfc9c2277ba33f45f6f7d7670062b039b1d0556418d6e02884463cdbd3144b81547504517a2aefa4d62f7b0742464ec0902db1456fc8abc9026bb4663c28434ee7355bc8179fff38631b16105b961ef84f80cba9b21d364f521d41943dac90782aa0e26998dfa6e765051261b7fc6c9409760e704e691399b153a51175ec0a1d4c9446a9326cdc791d959f7c98427b3ff94840cd0b58903a8702ff8adcc8565bf6a96afc73b18ed70cd1ca2a921428c983558e2ca0ed3d8270a1885ac875e25fef748dd64b11639727b188a7ddc837396357a4268efe6d3cb797c3dbb309f50d91348c7711a5ca4e5e3a98bb8f03797a2328a26f8dbe633c04e9afb0eeb08cadb6133d434ca4896189d0eae3252d4adf1aa991c17d6d08a0972d0f848365428f86222901a7274f83fa63115e8cd00589583ce1cfc67297a3e071f66468f80c780957be3d09bbbd3b7c1ee433122aad094d7d776a257878f832bac02ea5dfba676e5c933f734b412380aa22480dbc2b0320a5ede15ef00da3dcdb36ca07582f8a71a464c729d8bf5950a97fc8e5282c5016a51e994494ca132a89adfd467ea04a7faa864f1e5e3a3259ffb9d7bdd33afb115f2881ca908c6e1e93afbba0f987433525ed0b31d3f63f770e16ff9e0a91aa348c4cc29fdc2fdea6d22561b7478426a7b2fc059e8f335d741351853be11d13761e39f50a1ddcc464585f62a1edf4fa1b02b3a26468e96bf345f56de9e8e6a93adfb717149ba61d9ccbc97270759c1448e000fddea56cd9caee467591affae074b98810cca5e37b5d67b58193f9a1a3ad84ffc4aa87f50134f57b42814116dd95fcef119126fda89c2a6a0412e1436054429caa521e630996a4486ab7a8c930c9a37cf3e277321252e5497791cbe7a991240564120a7693eedb9e2529b06042fe6de4250788cb4abe28d221adf5dfac086b88e882e48a0a4540ffd2d02628b2335d49f4162c890ab22bb127de32104168adfad02e9e0c47ea9793bdb2ef81b028c6b2362f51c15de586964344f70fd9b442491d2aded7c20c378d4fae3f4910e5660a57d6e0626681cf11792e5f3fc764078e6577c1afb89bc14607c66f9821cefc20d956580e0bfca92c94a0e872a49775bde3c86637a7830dec3da82ad457248169b0fa7ac3522e379f0139f5f9ba36615872dbbbffd583d0c062d429f1e4addc080041cc7b345399a0b440268e87f8cc2457d437684075b66e6515f8700b65c345494c3139dbf7f8c53cbd3db5556847a494b700e76794a183f3bac9e2b8c44bb9f6b742a6146e6de7d9933876387136d349ccff872914751af1615320a80ab2e8a7df0c52218bcec1bccbcd3edd06390c61e2ac65b894b16be71c6665ce19d18550c25bf6d48b4c6fc52c3a77ca1c0b849ede0bc1891134d0b2ccca058a237d9a3a9954fce6bfc45ecdb27446d77c2c663182fc938a2468b8140bfd24cb9a8b8e58e48b9f1915f29abe9395c900aed61bf18e6835ded2e295764634fc7fc272c2bd3d24df693d1d0be7ee78bb123f7096cc6e569b9b4fab3f4bb64cdd3feeb6a0b6c5306df06fe5249409b50725c5f4d252a1acdf742b6b7e98be8f2b3db7788e0963bb31f9907ef34e624d9adab0df9fa074e9ad2ea61984a71b46bd0547b961364221e4521084b978a667df5e8d9cf42ab72a35773a1d181a9ec3c1b1d268f77f71cb333d7bc0f7673375ea60b7f420579131b700cadec2779673edb4d67432acc730519c08b285aa05555728fddf074be3ed73c202def8d8f821f81490f29f57063694cc87455490d67019507b29de4ebf17bec2e3ae2cd49c4ab8bb78e624451757b1344b7cdd6e231da9a26663e1a88eb6849b4318bf46eacd49472f4d60ce1f985fe48f2ff60a665df495e02c348e8cd16ebe0a1f980e8056b9e3e378f8db39602581db1e08a393fa7380154e66a946f0950486e17429ca069700bc17a707e19a4c6a2d0f8ef3e1f17814bbed5a6dccaedab6299836688459ddc016eb53cefa442c8ef8628b5c08e105095e04e1f2e2b18f8c17c2e1639f8d1da7dd7b7ff5b583f16d502ff32b2c23da884dee4d998f38e6b76fe0e18864f5ddc55ddfd14a32fe714920febf268004bd49cd11b10e6e1151a1f792de9670dd9168ce20dc342f98a9b6519d78025fdd3043a7b6558d93614c476cb6ab760f4b254211c4a266a266d255fd49111756130b05ab0a62f27c917a0fe2ede0b527f9a075732c333476d0cd999dae2c4a1a5b761fa1cebcff06b803255ea845599acabb012cb765237a98b591082ca5ac27d8069195850e056fa49042daeefed376f3b334a6d8b663391a17dfa3dec228af96839f6361f903594f0cdd57767f5a1c9547d006623afda3f34b0ffc6e90de996db53702958d8af0eea5c3944b29e9e74cc28a12dfbfc40bf3b9b893bd3c59c81ab40f7ea427613487b58d8be0989cf9fa2620c75abd1d51c7d3088271d84e8632a0abb7249e7ad613848b585c53f7c1d925b39ba5ee500ff8debca1b67223417e89cdc1b5b92dd42c0024e4f8f24268cb8e8b419f2c5d7cc118fdd78aefe816c1b7b4e8ede44b35310bf2e6f795e3f7ad533711707197134d26183401482370a6468a2083a9107ead2b6fa987af6bf049b1689fab4de6e20562acf85a9f3b740fdaef7095358c11cc1779e8519ee9f3fd2e354f57b3b395a0c3a70f03f0f3dc10389255498c5f4dfe482be5db4604d5f2a0ae1d694e1358fc065aff8317c6048039ce44fb6719a8551521f6c91af668cec693da25fee4e78e0eda928ee0c41fd6c2a1caf71966208b3baef54e3ff89a0927feca51988371b9a5934a7c008e2dd738e9a9f434d591e5230facbe87275752a01fae54a83816aa6258e0d722731d84c1e9f220b027074c2f98e3f9749e1930c6fd7aec7d0de5cc834203d395df7ee6c637c4186dc618ec87f68312a98bc1cee2bff6b550449f66fe27f02874f5f4ccc0ac9e15b930068d791526d54307f6de43f8c330d098625d974102524736909bd6ad31e4d39cabdc5443959d9955d2012fc44016e08726406227da5029c6c76713a083d48a6a3176f24dbcd8f8e80ba7470c695115cbe0882d150be01a659b8d2f752c321d24973d91f8b389576e20b4c9648d8397ae1726e899263568bc04dab9c6b13393b9b751bc44aa2ddb72b1cea60800449ec4b360374f49c56d74faa1cebce0b3a730ae33f968dc3d3800ee478fd977a056250dd20a85cce795ebb9a95738accffb1b6866ee1bf1cdf1439ae05bb9fd4dea43b025da024f4d8127c8bd1b3e2dece7a48b97302c730dcf49e6861154daa860a4d82f90d2207b48890c5140a61a6fd2ccaec0a9753dc3227ca1518343f49b699fa970629490e2e4ecf07d670ddc702d5fbb0c7057255509076e38c0552efe56b2bd40f2f4b54f2225939f9bda3139dc0f2e38b58366125186eadc09c2c7be1509806207aefc6d46f266bc8123ce42b95b5125427c9f784ad6766cc815b3b9a3e96bd846a7ad77289627c11982d265154a87d74b118654f06a3847f2022528f043f6e89583de7654a94719b838dc3bc671e933cf37868346d1904d2ad7147370d824e7fa6532f80f460210c7f9ce1165788d915d84c38552f72593acb56c5e91d342cfdee6600540fe8a94c04bc70aeb19ee688660bc6279921d1c56618791a3720aecc7f42495d6e6516cd0e932a4c6377e85ede34d40e912e9809fb4837bb69939e3de1597c5b7821670e424b3c4c2027160369c49dd2e0f665d0138a6949418ba3c30426f492a5c7f21ecf7806196167de887fa961faca441a6ff0cf45a237665844bb4e090797417a46ed4f8cd4b50ad1fc7da14ff4d996150638f8cf3ee76c069770c0031465c0a7f798494676e209367670d47d2832b9ed5490c32d8253693d301e9648a59fb2859212460edefd062508b3aaf1d8342bb6708d128c5f49509a86802f42cfe3581f58bd1a510f775bceb29d1dbfc44dbc64105e9bf5ea43e41ba2962bf1e7f3f490f43d743eb5d651214425a3006619263bb1e47bfcfc25bf9a9dae2a1827cd712f50bd3a5e4bff00141a954422a72ebfd77f4f5e63d73098ad899ca0fee88145ffa16ea2fc15bb85231d205aecd41974b5b9e71ab579e2b85850a3906ce5da7951df71f5ce0f4600fd260a22c6e8233344804c900055f7a93e4e229a6a7d6c687f6b9af574746a6df2c2b5b7c774baaae711917529b70381542da3bde5edde4a2a6c9c8b7e922b74c0860a7d214c5cb3532498a8b00740192982bf2b1d5a52043c94c3f93dbf5d482bbb2dceed6164d963f7208d833123ac7be34a621a6efc19bb9dc4eadae91d8452d0b952fbd28a742adee8504930585fd1e589ee25a8577c9d0b3fe0411f6cfe6fb208ad6798bf90a5d905014224809a621e7d748bbd4ebac2b922e749925541901d8fc28af44fc5fef6f217464c1514159a82442fc66240f94a28ab87f1c15fa0fd65caf18bee86487b5bc598a97758083c3139a3d8200da6ca70ffe954e4362afd751bba642adef02de784d0591a9e9942ead2e49e8afcced52973d408f158d71994e3f953d46034110f7ff9f5c494516e9d5ef1b38bfaeeab024fe04e2e349bf125a592316a2d901f8db76e2319b7ec6a36c95310da980a7948b656611ee0252a159360226f02b556162e9454750de246ad2e107a367a4c2b3046105dd5600c89c55eea39d6f784118028768f46c31838da171e2dea8bf004a88b055cc001170d5d3bda1705f3aff4c8f0cf5d93121584c8e60ba7e8a8df75e08ca81be1f98dabca9012ec6055310836c149d02c52941a06d9b34ebe576866101a10441e7a1934b58d81f700e4d3fdc1d3d025b86298efd9fe1a16394a98828a089f2b6e1d96757f5808d04add095498bf8307ace5696e2f543877aeca7b0ccffa2794bd03632a133f592382f9405043cc0302797c15138dd7062325242c6c93e617fbf9ad8313bc586ce90101da8b4c4ea022fb60e90909d50101d6b121ec5ea620ce621682076d1ff88b0d241856e93a2a4294a1154732914411ad7fef4d35d682b2952f8a58d7dca21714334a966b317b50410f2f78438c402e7508a6d544c0d0f34f9aba8e364fca2d7f0c587c7b256a7e037db641324ea5d0255731e25cebe504b36dac2288caae239c17d638188f55332e6afc817b5342ce03f753d6eb4112c3dbbe1819105339d3fbfd349d876090beaded1c7097e1ef29bca4b3ff343d81c3bd0e2f1bf4ac43fccb6da9edfeaa3d71f3556ff972430a698ace493c9dfa51b72f31aa7029f80df353809341f3e081677f627c3c1ea885221fcfd488259b50cc14c5a89710cd83ac8bc5e0cff5a38343e2bfc20b66cbb536a95c8f4c758d860df1d3243baa5773d1606bd18633855e5759d05164cc8bf2d8165c03d5bebd63c513cc57e5d77946704f0a95aa114d280a3b9e31625ee6594e29ca11692fa442c8ef8628b5c08e105091e112fba926b6a4471f1a913a79db7297e8383efe367b905dcf0304f257e158130cb0d8fa045124f6e464d996180191d221e3d0e160120b7d7de0a818bbffa0a4967a8ab8ca76b437289345d1f5e5a02472898e35a813d98fb8dc7404a71627aa5d1b70f3f64e6bbf465fa7e49c1af5ac7d7b22b5bc2bb4d40bebf088b580fe962427e16a25223967a9c068f1653eb062fe3c4bd50667e4927054eb29eb8c282000ec1caa0894b5d7ebebe92b1c686bf11696e15e88b931ca0565e8d0c5ef0903d462731128ee366261840716171e5e66e032603bda4fdec79355aaf99a36fae561859bf19d39a16b540ba787c2d30d50978ce4c416e4a2343d6db2886a0d9d4c9e7dcd9cae85c3568335d3e137754a177330211d606e87a8bf7783f77f504a6fd5209cf0706034db0352d3d5196a638242d8302fb9184ef019b724a5570760261f61ca4c6a8ff3a25b963981fae70b38bcb469c686b799e90828ebdc6db31a3d16082403b90c2acb0055085fee74ba0feb1a39351e0a01be85e9dac7d3ec7ca975680c8b1899b74ebd549527c71280951141d32644bed336652f656b15a756c4827bdb1421cf9cc48357154b73075c78f41693990f3db59a89507554b1e2a88df95905e513a9e16d4918afec970960a63f570e62e034282d06e1559de22464d93a2a425e211091a24412eae71f6c7552ef42c0691c44c40d1adaa10db444576823311d4de0d283aeb2fa20541113b477973aea080138201055c5fd38740646c0e720049e5585eeb891ae6da37a238df8495826925a95d1a691f0b94cac009e395b449d90963c6de04d589058acf7c57403c4f0b215b0ff08bf195c44317f82dee28d361091aefcaba77b87b2056e47e2efe1fee80f8ce3f44b60c347808b2f502e2733bb0b37371f3325513f0ba5a6b7eae56c498950d5dad68fd8b2cd5bf6218a3d31c4507055ca7626fee04869a156c6428d6a96303047ad8fa765c0470381b23e626dacd4ebff60d2dd490cfb3a04dc8c4ad0f87fd84e54e02aa93ff691153697815e2b42e3fd1e1b38bd0fbacb757b6320b610f0ed790d5dc166c9dec47b4001c2f9da0fe8c9be189ebc45f08cdd5b598a845783dacc82048e9a5335cbd3e02943d875e857d8915ea2ffd3eccb20c39b9833bd6fc6f019419878486cfc31c6be926b9ddc362f5987871e441dffd204ed405026a8f972003f3712ec86c5d55cae152646639d4fe669723ffb10219ac9ba7794e64c4c38cdcb9355519b6655bef7a2906a5680b84048b2676382a84b7f9958ae4965ce9ccb7db2f3d2350f742ae9032873f1db72cf54b293b66499e3a663324b6520b4efaffd0d5047723c4e891bf5aeb5b7347cbfdd4c7d9bc23752daafeb3931a7cb7076a929d157bab6030ae425ee5e22b80fc214d5045d21de871a544253bbab28425bca2677f5027eff8f2bf9c647f281da0f7552972741c42683edc011e452c5dd4efebea9a36955d65069980f6f29f3f2255302125c88ea4cf26f477facac7337c3981518313a1ac9fc4f0d469909a1d5121d2940f9ce1b84eee1199919810759d988ac3fc163c3bdaee24c402d3cf122b3b7cc5175bb89a35973228de45f39fa7ec4b8249f616babfe09f25e7cd6e6495657de9f858fd1b1bbcbea9a06edfe8414682a965d4f9cefd7f54ce34a1bb1c0f2f61e7ee648325572d1b8e0a8a73f695d200498db42d57477edb1b9cfc5cb6c0d4b275150b003352a578f695af34374811d1101c020f1e9cc5154d2f3f6806b5b96e978853eb3ef86daa87823345f0e3fc20e138d74aeb1f493b7418c2a4fa6ec017a5f98f49771481a7d3ca6b1b47a8b2a9b83cfc526756093fbc2aa3e08ea07083f1d5115565c52a83a058d95fa72d10b906065aff8312a0857e257db9e82217f647eaedee4eec0c8ea230d4639f98b97d194e34bb695904131069fafebf9c849d5f5b6df27dd2d391837f394e9ad42fba069c33560f95061a7ce8f73fbaa67f7da1d1f75b994642337fdb3170b82c97f0d86cdc21b65315715e0c0e5baea029cf681d00f4f0b515f5fa9e84f7904210c2c3a83b20322ccd9f79ff91c61c0e8057e978753e8df5f7923feaa2e67c9eec3f511c1c4513987c68ec41ef8758261c9fc940e3d19d4258fdd9cfc95e07d1c60ce470d365433e831b30aa4702ae3d4d706647ed3c26dae174acd557920ed9c341ea328283a4e402e150b7a6abd55143de939a45911b66389654881664880ee3b461686b016e1e452a86ba630d5b00c061d824c9213dc7d0db832fe8cde0731740bfcd68b60d75bf872e3183cbc6118a79e9798c892b2ce65c6f9c86f2bf744b810803fae062dd4881e44d2e96237f2642e2bd98d41b0ffeeadbe94bddf935736abe8cc36ea7d653b4cb97b454316f173b27fd74c960ed06dbd5d57e3e987746615995b41ab26af409699e5a6d39bc1976a6dc91dd19651a19114e837b3104c90a8005e47aaf85a0cb63489eba3817a81b696f9e6cf67d65c1111158d7098ac416bbc9ac4e824086ca6e32a688eb6dcbe7682de5824e83b55b0be811209b0a1fd01b1368ff0849a010a44bc97f39f67d12deca4f6ac90d5d410449a55ca80859fb36478987da0fef629673151cce37f123b508565021f2c486758a762dd28b1f1eb39bcdcde14c5176711ed9bb737b227cec55a3a3cc5cb27c9dd2618929888390a47460a9a6e5a8c3c6ad271d0af85fbcc99700dc4d91b0fee78d2666aa972be288f2a3f6305d7815002f697b02f1baca9bf5242c57924c9124d650f9de894f5ead082cc4dac171f6aafa9f6ee8a7d102e36a0d426662207c9010294a023a88425bf46af0bfd98811b1f54337ce7a2b312d4e38f91a8950ccaedb049d9992007671db849da02c39f046a913ab93675ab82a531eaa018fa38b238f96ec6cf6fb3762f5f8db47c3e589b02308653d77e69bc728130861d512a672003d39a44b7287b51388a4ecd27a9500a7ef9f1c086d4382a7ccc9fa1aae9d082e98f062845890e8e2095f2411d64eb17aee226189154d99ffac32371ef8235fa853e6c51d287ab43f68a82a4db65b9932f5acbbc4c33bfed2a78fe3f84af7bbb22b5f1f3d948a900554d31a0942938cf17ca4111d65a88889130c81048be9eb71289443514371fe90177e07ce1e1388f353447418fc3be0af12e6c064eb79ae12110a453f5e5cf4be577d511a18fc6eddf45a700a1786fc3ee817ea5a980edeb766c59f29a68c6b271e984be466124b42d4eb0fbfe235c1826132e122eed115611484ab96c551752c4a0f036169068d18f080d05e8dd14cd025743c83d659e567d415c399593b534c635672ebc4f33bbd9bbd00facc53572295a0b330283081f85fe32c3de4c79bd3b2cd016426136128631064e6d077ae0d377a73d75ff255bb001ca821ebdb8c2bb00ecb19d7033c7ff6b452d3dcace8427e402b38d07d9fd6397ad2d2f2c9e775ac7b8974d1efbf9df95a15a74baf574050e0aaec26de0bb8ee040fd431ce9d2af1733915d4558a62f415d01213db0819f0e9b81b0ced361824a4ccddea411f0d692c3a0cf043ae08950625b90f9d9c50b65ec6f131a182dcf51c5b2d462806966386fee1f20eea83e3379ca968ce2919c49aafd1b95ea2b6d6f70aeaaf4cd18dda2f9295fe10065802de78effdaa2301b95f2d116f5ded22e3a5cfd0e01d5659d2d8be1a001ad4d2500004350008303f612a8e68cb1a0332cfcb0de41f824fb4268a844ee38bd25ae212b533542f7e0685e229c7a80f922a4c2591a5c76a85731f0ce88554e41103fcbf3ff8273d1e3399b2cd951f3bd24611f51f4d20ba86be13811469fde8718937eb5bf079428251c7a7848ef938c229dc764f416c89c37244ba8471de5b079e0f4527a3d4e169ea777e74c0837c1e35910b5bb24fb719d8b5f3417c1ee847b01ac2d386b9e8129921b14ed0bb9af87dd23a24c744d108ecd50645ce8891059a4b62d12cc3502fa0bc17a89d02d1aef815a104c93c2efd0f92fd34fc34a16c6129482d97e83077b1e481fa16515a684ded66fcf9a22d8935a337682b87a528ed19f3eb353fedac3b1ae73b65423ab04f315eed0e7c8f7ef198ffe3ba0e42256c81b057f14e6bfbb79aedb283804b358731384104be8f7fdb14af3648bbc52a782f2906291f53bd723fe9b6d9cdd4723db472fe36575479ff46f7f970bcf6edc7b14740700193de418016ea67927009207c0a12c7c18f7266a7b26a5eff000cde2c4154d21ce31372b7c97b16318449dfe92cfcf6fa29056c43034bd4325f1af9bb3b0cac94e50c9bd7ea3ee1315c3b813465f01754e7d769f4d24928dc1c5376be76e9c15455816115ea4fba0922947032a9e3cb4c17b7ffc3020851f5033a8bf65ec6384f19a04513c54f9cb4006d1ca01427d162dd8a0550b2228b83fd5ad5f12087fe5ac4282da3841c03ea4de45bb3efdceaf83804d84ae5af39d422d68fbc341e5c33b8da6daf926829928c47e9427266af59faa1b7259709813ee4ea34392e60cb48c93f5facde9f7be65630d03a5c6335bfdca7ba7ca52869376e633fb9b29e03f5798eaafe52e36823976e9173bc743796eed4ff6953bf2617480128cce5989ceb44f8b45110c364a822024c47ad64aa954b93cfe405632189d766b30555a0ece712805d65419dc33dd7bdc592197fc16c612421811a0571647aaf3ea94560d8b8eba4865be060ef0a0857543f098f796a08dcdf6ef750d0ca8c821ad935d09fe33437bc20cace549d2861fc2c57b53eb62e968836868334eff52ac14c50e218567175ca95255a57099c1dc33e679b64060d1371d38dad8c6c35e36a043d62e31cf667b4851806c7ec4cd3d02fcb66e2b9cab3943b11fc8729831cc0b72ed14bf9fd671d3b3c0139bb3e4c746c3bbe00661457c16ca5836bee53afa32069b3cdb2e634bd8e89dd1cd4c7d660b842274dabbf7acb1b164e33ec2ccea27a19bf768666e4740639a5199b0996f3528f846ebb070d6b09dafa425a2b3012e10149e5e40bf4b9f6cdbdcd368dd0e504e5689c4b65b66211888f5c4e557798f11c84074ec4d700d4f106ef7f5d593dcc92a86bc74af718b0510b09705be515015065e63b1c3db799005cc4ead26ddd5480427b8e159f9f99535e623b540e8f4132462aa7691a03a0b60c3222e35757bcfa6c0cf41a2809dbde6f0d96c95e077267113ddc1978f6f9213f242e468594bcd7632f27296dcb2b88a81cf0224125f0c0e6ec04ea4249ad598a475761f1dd9a4fcbfb0fa4a811addcf61258d5d901ea9eca256119ac0aeeec01d4bc985514a5e56e5e3a78f6d2b15f9dc33f6d89e04beae6dda5cbb00212b3c36ae7a0d8f52014ef058d05d4ae69126b7f548b5a34585ab12a4912f3c4b86819857701b360a4aa7cf6c1614d6d918ba4c01b098a81940bff339dc9973a37edbfce5370d1f54adacb94ef17fa60424da93c32a923794204c9e081061ffd3c9b3474b97badc54468ff78e316a6368693a4b4b813f48bcd195a2b359ac7cac34a1d19403ce57631b70bde237427555d893cafdda21d44d35b9c6365af69b7611a2972f05c5abd2677f3b09dac3b972ae865f0431a76881a527664ab8513ec5db187242327028e06916b03360fdd0e82b11ab4033290f0be70766b397ddf029e40da99814cccd246305ea97b682f8fa158841f070b234e42d58de069e0353637972622b694600d419d735aa55684303d428d3d34e2b5ef0042b1b9c0ce2fca6f7e575cbbf24c0e86da8b895689e0b37be15f0fd4f217563b0ba056233f7a928573171d0e3c0897b5e0ca17068a2a252fdc97947b40829748745b04d741f724ac17b19ec9ba3402e42079ddab21e182bc471fe7831cfb4907f0b5069d7a8fa3b563cc1333766b8ac01cdfb880053aa64a1642945c9a7ee41b3cfbd2ea0b7d4aa2c13a82fa035203c36ca52158ed566486aefea154dddd8ae4192e7dcf007113800e680b44e3eb64b7eb56e7085b74fc5230cfe7c74f5959b7ee9de66dea8d2e24032e2b3803b1aea2e6d0545964751e2e34740a5430773b893eae669953447415e06eb0dcfff468e90e13e04a9ec53a777b65846966b8ef52fe4d73182f36f31c77da07beed8c941678a0e8a6eaebdd693a685739a89769da04222506f6a0aa7cd1338d42f59cdfec0e8d128f52d4b9ff563391a813296351500a01b5813828318f5cc48ca0642ff04b2369d5802534488dd4d81a3a701349695a3f9328a78d8375cd4eefdeafc7434f44b2226899c9b3f85cd110e830f829a56551648b52629e8edeae1819bed1828f9b5004c1ff6aa5e025591c91a2fada8db6f906a259c96e7c27afa56bf62c372193b734c2805ee980e2d8c5f730935cd18bb8c408191529f345ae0ce5fb0f15d278db054e533ee824d61f3342bf4a6c9060b0e031ea40e0fb5a6ec65e7d7e43ac15354912c89047a45bcdbd701b97e5848881db2da72c6c39fa65d53160f3c85a7ccbe202734c66cbca34ab2f150543acc022c4c3cece3c6a4b39e74c342924e0d0d8945039fe80df2cf235c697eae67789760c9b8c2cfc1e8e2546464dca28e9f901688653d091ad91d64d56836fe556621a2b6751b036be6bb2b21936a58ac5958b51344f26704e054f27349291e28d8feaa0355a6ad7c959bbf520f4793b118b98b11630b7c8e803fad4a8f7f849889cf4137363c02db06a5344600f7d48782d607d43cbcdc7777d01f5146499b9b00514d8af60278b34d1f45d2f601b855bfa7b66db37fd4dd3faa813044db4d6a3ac6533b2d729f6882cb33332e80598b58095a12a2879f23c8166552c3aa2354c13a2e91a360d61b8432f6ae400bbe80b9b78d1567b15751b5ad424af1e0bb851b36438fe3a19e4cc9a48c063d8941b4c4267a04824fbe88b84fee4e82ab900e58282b295a29285153f7ca4ff31c02b1006cc95116f0912c09b42bf4c7df72cfc0c1fbf4b801c99aa8aabd1e10f56f89e89f27f5fc4288822b2da0c62348e5c98198bc19a4272477ac723a7b89299e5b7299fe080b76f886162e0289fc9eb96010206eb861f9e58b31053734cb58f1f86b8318454e56b97635968eadc0616bafc0c95f5ebfaa56f593fcfcb2e8b945a417339a6378f4b137fc0a65e15e8dd4f53d881d863fb651123e45660380dec6cb17566d0cedee9f461b3ee8c30c6b37529d3af1da9e690c1bba680b254b566e4dacd16956cdc92905896f35b9190e2c98d6dbbc9160822f1985cd4ab3fd3f5422d5069544b56bb200dc0352139ab11e2cfa8d4744e70cd0cf0cb6f15173e34031b51289d3de6fded679dd98ae02c3bf9f10080d88f30e9b58bec596677e9d27a1c9124c1dc85192066bbde645b18ac2bda8ea2b43f27a609d601a865307bb0e3b7b0b9865b285d241e84531fa52dc6e5139feabdbd736830ecaaf1af3de2bb13aaa1ac08f5601545113f7c2111ff01452fc7fafee03eb062b0fbb9eecad07c2ec593dbf712e7c9d6e0c1efc38ed99b9debfbf79ab2dc2f58405def6488b9e46e1e39ee6000df0fba88318b2b2e06194b3857d57baebf4bdf0e73da116056db3e9725c04fbd734c99b8ac5aaae401e29d553644de7a8887f969139582cd8c800c424b5cb9da17016aa92557be1753dc2f3966dff52a6d90d9fd4f2c135fcfc9bb2494288dd9884507913d119dfcb78fdafe00d94c45cd9fe19a04ab3c2c8682babad92800f4b0a4a31efa70a4ee010dda3d4c41560bf934dbc1d43db8f82f8d23506d8e9eaa1ace2a6922949478674591cf40032bb63ca474a8fe3dcba9f99d2cbabe770483c97ed6cf60959aa95e20a39d305935eac2cd3b51e1c29052b09930db8da592dc805b6ebcdd45127c2a60253e830d54953ccef815e637083036a807d91610951c3d78e31735d2772579ad6a8d2369e12cd63e7cac10c951785ac8c60444c17aebd796c920bc4d8bd9069b9215e1d0096612b4eb3039eef1861939b60ae915c22fc43d73d22f2a4ad01cccfc01ba7985554e2092d49b0336af8c18de0a55049106030632411495ac824315c1b32c7b810d18ef01e68000005455bbaaaaaaaaaaaaaaaab61ab28b4bbd782ef679b98eb2f192d43c252f42a5255ba694524a52ca4c053b053b05ef47eabdffdebbcc523bb24ac964bd325fb04cd9976953722c7bffe0fbc7587ce167d6f3eb59f66c7bd23df79e804f191b3036dced6ed7e59c0d4a136744db9115c9c96aca9c51351a37f73b870f8f2fdce469469b484da7a65573daac36d38a4f3e40deafaf7224f4fcae5a04b2e530fb20991d0a16946acf8af167be6eee7d938dab3d08bc7664ed2b0131d874d2404b70789ebdf7ee6e77bb2ef79b7318d7bf300a5d3bb2ee79c0174506acf24b526294cba9be7befdcefedeeaebe39df5f96a5766495cafa2a6129db5badd837df7cf7de7ddf7ef3edeeae38aecde1f7855dda5ce85cf65c005d6478cdf776a3f3bdf7de7b62dc1e9b1e126f0f10dc53f4bbb2078bc8b7555393a8f5f7ab978a70f202b8bd17fb06b7efce2418f7dc3d214ddc5dee6e77bbbdf3de7be7bbf7cee4b67fa7d98eac4e1a284fb46407497311b9bb77fd65ef05f04546098c0afc7befbef3adb515d39bdb6c4756278d5bb202fd2b5e8a4b87b2b8f480d3bfaff7f0eb617f22655a19e18227de60b835b5818b57b5064b84450b2fdc4403a71be9d02deec707442db0a006ad720285f0877684e334e70525798be619184dba546e7a33c72303a3c9d66b343170412461f5505630309af415cd8d15d317a4418d3b0dcf0546930d37d882b65d8adb806129a95e2295c582b70a5d01abc6a382b18d11bc15520a52f4a9130a5ccca22758b2f2a830956602a6f7b743d71da31bdb2b814d07089ae452f9bf128c870446933d1d1cc1d2890f10ac4111ac0d866089c7784ce104c1075c3b1a0f2cd5707c3c353b2067c501a34927ca3dc368361037a881a50eaf87f6ab4f31cd400a3314d237249a1e3bb226412b181de603f6f89a555e50511f36902c974b123828068c269da3215d000dcf027e6fc70b5f5580772705f42eb33289eb789f90260063430e5a0257c8c59865458e1776728a874aea5402ed7683a6f02a7111df0d26bc08184dbafeaa4280458b07052937be70498abe07184dfcce5e2a5e315e360e805b966ab5014a4b1cc52a2889b133c068d2dfb6b8050c7ffbbfb2ac59e654c09bb1ec8a2eccbbe806b70e9a00295b93b8e1932c9724256c5504184db6b186697700a3c9e6354c3ce85289e7487ce12803a8a515c02d8d004a351c432c9e13b87806d0a6eca90943ef2a7578dd23fcbe7055dc888a3ee51f7a97cfc32795ca273c570046933e0c730ac0cfe3bf4bad00e09254febffb4f1a4dba3b87a76185e7547d222d5a681b3d96bef726391b2cc168d2934be5ff4ab1e9379a6cb73a188236dcaba772cab0fbc7306d22bff40b5b0d5e68321bdc3863e93a462ad684caaece98bc094563282e4b092e2ea9fc7f979c5959309af4adaab10c8f842b625e7d09d314de49e5ff5fc9953682d1a48759b952aea80ddff049964b9230bc3cb26ece41b2788e502f0c85f7b18164b9dc60530fa349f771d33cb29aec97ddf049964b12b3be57b74539a45a51af35b8e1d38c7056451431e7ecea4bae90887e529f344fe77455200df772e7bab276646d2ba9a383c79a9e73eec2a57d49513e9c6a766956d525a9fc25599bc7f00d9f64b924f91acc23abef5b726f729cfc7bce4be86836e73c862fd79cd81c33fffad77b1fb2d681448a66a01a2f183531546d588822516c90b0faa1b80b7b3b1eb010928597b37b20566f1425612f6658a1280d1e3c82948096e019a1eee38857e1b7681b1fab278a23c203d1ebf278e1a0638a8f8e12a1c18f22e2ebe401e4394a92783a708c1b254048afccd05862828623b7587a2a6e91c33f563fd38d199d88543552a38a884314d5e28ba16b5425ee751f8d1bba71f4a65b35f292134e9ec596bb4b50443b945117414f188fa03dc521241fe41463fc19cc23ab0711529e20ae3978034d3e5c54384d2abe6a5858a4c488c23838c5001ce154565d72fa97aa538ca430342eb0271899c1ba1d3941270318355d88bdd5d13872fd4d099dddecbb6ea97d64550e28c4daa0d0979f2042ee740545f1f2d3a3a3f7f0bf31fb61387f3dc57c9d4a3d3de5dda0e4d531b9988d4ed445961c0a31c44bc8e3077a332c75423c6f2a4cee812c30ea168764d4b5d5f782c1a9b2f7f235e5a12a8183d4369315a8d432558cd72d3e1a2e1817158e89ac4a6204558fabedc912e71623e765020514524861fa33c52a12e4034113273402016f76d5ba2a0f0ed18f895677cd631473ae779b79df7bab2da763056b288b2aec459a4f0062708c0247a07869dbda8cd56a8be9f8b0f181aa089d68c63c9d4d1eb6087fc8da5eb4f42bdf6a2f527c7d56d1c5a1c74351184c891f21251d644db93449094960e5dde6368bad2ae62e90ba7022c3ebfa504d496a12449991b31382df78a5b21d2d3591dd4397fb13ad1eeaad57d7e7813872136d7ebd779352aa63de17d01a9ad409a11a47364230670baf352366e7dbac45fa162bee794447961382510f587e21a01c823ce855a95437625f577930c4a4928d57ea573426c62bf50b8a57233e492e3be1320fb5eb1110735704d92a7fab3c81e1ecbbe6e17beae98db44dc87131c4c28f886821d5827fcfd49545f8f51e67afba275514b1d183f3e3df4f87bf86451fdf183104e93f0ccfb068f6b9b9198af0eb7d4cde0717fc7bbf5e01e93f0cbbe005ed7580b02c77488125fc10e93f0cb32876d216278cba08bfded7a813fb8372f387e14c836ece05ff9e6f2de568952c9fc107c8bfe75baf7c457a91ceb7e654f438df1ace83894f92cbcfd75bdd6a7dbdecbdf75575b3e0184feeb2f44ab4c900a985d5789209ab3e51ec9d2459e6ef3fe255cb4b70b39dcd5a5bc5fac33bb1d6f22ac2d0f5216e87a7ed4be70553abb5148105a640c1d0eaa2110fe355ab0bd0480f7795fe3eb7c0f9506da3ab5b629ebc55719e3b530ad429ece0d4a081ea59c3a90688182b552a1410bab05b9146c35524c4d79deb62fd9149a7b8e4ab35d5492dd9c41777c42bd569aa527c616492ddae6e87dcd764770fa73c2f869879bbdb7be79b01ab55916da7c268c045a353134c5e513967726f856dcc93e551080f71fe3effb62b8433843366bfee435d27d15ac8f6f77d75c191670c8f5f745f9cbab7f6ee191af14caea8a92164576749318fd7abb3954225be979efc46a9a8bf7712a92054b43ec62bf5a6afed5dd79da5e2ad6fbc008007258332f82ca2d16a0015152867088e4a5475a3a4b5065eb5a6e5bcf68db15535a99d9c2bf52ae3556a47147bc4abd40e1a9f68340d3d5ea9373af146bc526f6892f4f74971961a334aa9301e8ff0d30ba9232f7dd7bff6b66db219ea6ca4e03ce79ccf56788a3398385f99e9c53b5eafccec028b39efd66c9b7394161a60574a60dc7b5fc1ec80b09844988511323b09514f33bc9c24a477cccedb12bcd65ae7228678ed4a298c3be2f5ca6c2ba374e8efdf8e387f5fe4f0e0d59b9b9991daa00acfd9ab419e7818af57652e58b685a212d5c8832a30a2b6f8a0bcaaab5fdc0729b9243f36a9ab41c0b416c620352efa9890136fc4eb95d9d3095bf11baf57656f7a65596d8078bd227c117bc4eb95194d6ed939cd3647f0974a25c9ff6e911341b61f02ad7344d71d76a1f56dd7ddee765bbe416c1c93aff2ff1d98a2535970d7142b1d1f221f7edfe570bb7e73ad5f7878245be85af65a005b641c87dcefbdef8a1d2f3c03345334b334233593f5d177ef9dadf8265fe5ff4a1512edc80a5454a2b2e4a15fbfb9d65d1d1cc7171e41d78eac7b8025236474f8cdab881b5f59586d47d6341ff7320bf1e045198459527f72424c2eb7123435d67626c386d6ced9f968590df18dc55cb5731a809262cc10b17011c5c22ac4015ff3cdb085f8216fbedf42a35c170bb3fd4265fc3e219ac262b0750011821eb22533bb9f102af80b1da7c1b22b7c8dcc1b169c53e05f04988cd6a62a2b5c74d82c9d2c9decb6c651f13a879f2a2ebdb0a73f1924789045c8728555c89276d3420423075d6badf5d118af5a285afe5ef4b4817e39806b5bba15354d2c48516a562d5c9c8b2053a289222da926ee086b88d7ae9696d8c72b965c5c7c72d4807cbbedadd65a6bad8f5a7fe4d75aebef7b35ce5fc359450b967dab41ea3fbd07d6f4549d08fcfafac9125cf183a6a00576dedb9a141b5935259c52d07b18af5dcfadcdb5f60076d4108049725bbdb5d6ad9f7a388a3fe2750ab393f613f6d282cf8ac5d9ba71204a73799971b696b487d7e73610dee30ab37b7fb18075a80f4cd6cf7dd082a107629113765d0990d7aa0b588839ecac70f12a72923f1038c4f967110bb44a0ef1048adef69fac594378db78fd722311134f7e16c927f9af1dd0222743b8408155c7415041e9d08cd755b9fe16031ce2753d81436b34c1c1faf31a67a98f572f1a5121bbbab6b5388d371a52ec028b9e6522c8f6983e606e36857c472c320b210749cbb29759e038bb3babb5d65aebdff9e69bb3bd916dbcad7073e4a27335343b23f2367ea63231045fa251786fadb5d65a6bbdb58f57ad379a2962fe9c732ec2ffdec575fd16b4fffc9f681cf022ffdc6f20d7a851a346ccf2b66dd93666599dd90adc855cfdeedb95ebb65d73c137fce56db170a25bb961a615fef89c50c19a9601b2cabc989bbdbfdf9b6ffdb22227ca657e9b917dd73a3c18f8f71f864700aa20fd48117ebd87d685f0ef99ba12e93f0cdf6c65e0df4b15458af0ebfd879f24ff7e8c1882f41f86655eb85870733314e1d7fb97b811febd5faf80f41f865bb032f0ef3b408af0ebbdca5f8811fe7dd3af30869fd7a0df91df8f05268e0037fbae770031206d133e0c934843f2effd48117ebd0ff114c2bf67ea4aa4ff300c020844aa2852845fef9f82cd24ff7e3afc48ff6198e64d847f3f460c29c2aff71eb22cf0efdddc0c48ff611866c408ffdeaf5728c2aff7ce401610fe7d0708d27f185e711be1df3f3d8845f8f53e45c984127e88fc309cd90e5b306c62cef17aef5719807506e0dfaf84805c48c0a90c61c43599ff090a6b2ec1b7236c8fd7adc19aa1b498c8516c17b00338c601eb56a7564e48511e96867506e1fd25f4c0e80195159ea543b733c564f6c6dc222b10203a11a337349745c4d4226bdc1a4ba0657fe213e5c96a75b2a69dac7d42f109eb8cae26b2482b72c23663f69fb0d098fdec7f59f67bf6c3ec5fb2df02ec7701fb83c07e9686fd6c94fdac15cba6c512688bd072c85030bb457e1886d596deb8900d4a66a4a746b4b499065105a96f59502a9d2dbede7b9fad9f66f4358d0a4513f39a231079641df6a8e698fc86049451918c9fbea7ba6ed5b647aedf687dfe841754347e6a4680b5313b5f8d3e943a9da09728b3f3203717e1d77b9de4653fb9457e18d61a7ae73baf6db367c50f7f627060516d53400098f180d37c5a42eb295ce1a47b020c177bdc0c6538eb155920198b2221dbc3aeb127d6d6fc995906b3e896a0115d528914990e28404a80722fcc669827cbcd573869adf5bb21c3030b5ed065571f65bab74887a074fe5e3899da46adca274caa89c4d7009a121f43b0039c1cd3181c0f6d8cd7294c0c2f43d6bf1ff3a1090cc123c22e068fac4d12acf25006f7fc19ebdf8b8d114104544a1cd21a0994a4a638206a07a39523bea826b81f0f8433622100926311535557f6550511011a0f2e025e18a4c8a80b4a164c90f0038f18e15961040cc88894638c8f171e7a1d732f1b07d98697515a8c222af961915bc2eb741c4eb35df409f052a914819291ca0fc3ca18bd3d61a9546add0276b6d8b66d2bb26e58b62d090a1bdab60db117b7edffed276945da0d7a67ac8942478ca629d5224a636608699ac6f5d65cd3415ffe7eed6359f6c337d07d23433c12facdb0897a0500151909cd1db9713137d78a8722353423a42e1b1a1ba709bea4bf0f11e264c93af3f79eccab2a079fef968e9d395f5f27cad647f87d0787f97de1231c44446cfdbaeb36b921f1dad532d652f5b7f4f9ecab4300f9e52300db75c5083b005cb13b8fa45e51d03a7365ce878623d586c8bb342ce1f8e1f7fdc59f7c95ffbf673b21c70fbfef1f6648becaffdfb3198ee1f8e1f7fd671d3690c957f9ff6b1648bc70fcf0fb9ac91d2db8ae59d80709ae99b408bbae19d3c608ae6b56e2ade0ba9d67b1390df2ee0868adf5f799a3158f5c1f4faf87898d8e9de23b35e41003e16e88352b18f58a6a1ec42e8e2113885b268464f4d5208eee72331a906da652d46e981a0979f31d7605bbee9df1873d69bdf599db5f2adf64a8a10c77dc46f894b9cc08f422804c54204e0d3ebcbbb4bd31c156233f0cc35d73de761773ce798cb6340e27b6152f1a96aa2fb8e7d90d0c9a16e0955bcb1672716068fbf001eb0ea9461d9353f588f840e41775a1d306c5c3b35dcf7bfec8acb54e12a2c56148e9ebeac00394633480aab3a60b94f0886bf3b49a387f64ce7f308d28001c82faa4a8a25aa015c58c8089c05bb17445458ae919e93f0c871c6dcce0688bf0ebbd20d988e30ac2a8e78ab30957c4cc3e414e2a9f200d2f66e69b0bf29ce1dc73ce3939f6422b933e3e492e8b6e7af3404f0d43ca5754a8b483cd99b38d995fd0d662a6058e10081accbc37cd39e7b5b9d8ca4ce7be7bce5defac838645f6e59c738e8461add439e9d99e9c53d764c43d3e492e7d0ca2a7ee2177ff0a8dd9e5fce51d22701639c27f781e47e25f5b9148fc2bf3d43f127f53eef2f91663bd3e7614b8cf482ad9d45de13340b22923a22be4cb5ca22f0fe65b88344be19e7fd2f9a7580a9bc3f8701a31a190a77a824cae30a60430b524a40f34bc3a001276d0bc5c7023b29b73eb7a4b910279990dd16c4d916d20eb98a103f1ed0166b238ae46d0df83c4eb74e685c592bb6c4e912416a37c86c4a810eed0e71e1563745fdff70ba83b8f268b0cbc40e9d91a11531b539e726ac498d86a983a430dbd5ef95f1318870d8f0e0d1263342ca632a84baaae60528919cb7b33ed7ee47e4d59c31da5c01a3bad20ba18bd2940b335a94b8b8c5de2e5224d2288fbc3effb5d3af6de5d6b6a530ad75aebdcf6c54c7bc4ecd3a170ca060af563eab50f2750c8ccd050cbbc9ae32a3f9360716fada950155a6f6d8c572a93964760cbc762e6599efa67a8c4b32c08b0ee6e2de38a01957192e187e7b5d65a7bcd75313e79f51b07749262a4c030cb116b5d8845c19145d95cb890e520033ba6e3593fb7be3e39efbaa146a500b31e34cf9c64678e78edc291115bfd0ae043f6de9b1a731363d48263c970428daa523e3c4dd07507e676331433b5c2f52dad189dd57006ee31a19c35282c8e70a85abd0bbcc85105a17af2866ab0047627a716f424924bebb1113c0a03ac6a5908608698f40d87691089657726bec410375eb3be6088f26f17f08190a7bf7701e01a89a666918aaabc385387a858a89c29f23ec84e002d0525e965e10da5a9504a61a2a6472585fdabbfe33018a2116342a96fa54f0a58e7330d6a72f1c5ae30363b59722d602aa25a3b12ac44dfe43c3c8bb26a84b0acb4a7c9db5c7cbdf775801c787af99b8a61820a87f9636248056187aabcadcd5a3abc9637a864ac9df90a0d4c6e50003319000003301c077224489228846d0014800a23e85484a460482218c8827140180ac318068128868128866120904228ca83ce491eb753ffbdedaf0dfdbeb44f68ef77a4fd227bdf959a4f680b9f97f40becfd9e645f6ceff3a57da2addf93f40bd8fbbe3449481bdafaa56efbeeb67f65d0ef49fa425b9faf52c91084b47139569b08dba7ffbf06a3fa1ed75e9c445b5e550f4c821c062fe0209fa7beb99fcf23da83eb379eb5486ef667b010bf3268d4cc1082c65701362824b8c06e1632a3f16f8339ccf9b28f1b9a058f16943626a07da7ae0ac127be325b2f15a12f974f4c9df6a2e63be6b2089642d8697f9864364abf00a3d6ffe191d9d822aec92b9a6ff2c4c2758bf72d780d585a9b81837c6c47c77d87924391c131031be19a6e4a0e5c09a0a6b72ba3f831ad12f38b666b41f406cb88f5ba85d2690c58d54133ce8e4a88aaac56f4e7b6860e7f27744b08999a03c7981fb7ef0e36aa27b80df298f0504d2c50240d63521f00a3e343bff3ea2bdffb148f1919926240ee94bda7a07d6f3c825235845a220a20ab1cd88807982006597d887a881ec7497dee857bd01d608512448cf97d64e8194c7030785b7717f4f4c84c63b4aff136cfa68d26b698ca3850b1cfe65808dde5342799c7e1db7d4ef5a0d046fb627dec34c657d941fd3b8631ae4b6ed9c1af5c24156a38fd81484ddc9cb9e758c57abd1c7cc2e9360761f9c036014091fcc7fbdcd3118b96609ebe84843b6d82ae8c94dd1ab58e67c9f6449de5c26103e0adef6a482a5298ca6186eaf79345e1ef93cea811a147fee101c0b6e855a743a32151b19bca504eeeb3972ec33c68a546ea10f8ea2e8eb0933eef99f8257cb1cb42e80732f0672f79e1d74b141c6c6378e3175f1068c48404adaca11c297eac92812bcce42dbaff48e64a255b7b57ee45e84e8b9dfe86c0ea5d0e86dfb0b6d9a007182cca333990065146950453d171c26a0156d8163d73c2c484f59c8287a1098fae6a8f8e8762e953aff87e4baa0331d640555b9824897b2f9a7b93ff5b79805aba3b60f7734dfb5c75cd7d8b7facbc83e0d758a9b5b1b02da4ce98db4e543ec2710fa931669bb12e376ccaf103bc3fb0e97c386e6168fa7ee5e24593c6256162b1842787a4735c0954c7e0de3b44969f55d4c5382bfcbd9d9768feff952ebeab17b8eefd984625cb38f17615ba74ff4c9db215d2acc3d1685a688577d6773451ed34911eb6494e47d7a9055529c57a1b8da68d56d864ddc072800cd7bb5168c3741640808f417a0cd3f16415f6eaf834f71a3dacd63869e5610143d2dd72a4c866082ad7b5542262c0814856cb05249e5824f5806c9abcbe8e67ded5dbcd07464b81c079637d642e1a17823ed2c1dfd7e8705d5f6ac79a20da087616ddfbe9ca9af774a7f6e937d2d48624ee73602f8b0d582101cbc286154207a5bb5b564bf2c12863421c9f5cb25ceeb6ac176521b9a58274860d8a4d28fcd3ac433f2d58a2928c4c85fa45817ccf3e1af3addb1b5c83e16b7655e75c73cfaa8da1864f19efc5e500bf96b8829d5d5e809b2dc838ca126ab8fb671ec1633e2a071642afe1b348bb373ac33098d48a060d01b3c5955fda375b04314e01d7d3dd2b00df1ba4390e96c1c8ba2d63a5fc9846c001f43f6021e3b9446c7f18c9d1e4eeb0f2f7aa1a11ba446e63b617f786ded0030161d06b8269d337103aee063443efd6737ccbbfd3b803e6171598c5b2d7ca73a0a26aa998b9cd354e58560bf2786941e9b9aeb5d2dc051ea87800aa22f05c4937b590f6a621a11cd2680ea1e9bb1aa13ff748cdf5421ebbb20bf0de35f8c213937232d902197d7ee4ad4e4bc5ddcc3cd6638d389f345b48ff447118f08de7bd9786cb394ae148c7a7f0d830c874d013d568b7ee69332998ef7d814722a2afeb46bf3ec331e074b29fd4eeb75b57ce0d52633b1ee3e2b2b0c44687a0143697f1563290e4d4dffb9a807223f7bea6c4e6328fc31bd4d56ce52a527c024ef45e280c4fe698668ac89a6a7099c5e4ec8f4665b06df2325f7b7a3b0a81c48a2b249e86ea9768689f1a64ebef247873a2f1b9393db96a7e0b4b251ae39b16e56bd42733db6a23605594313a7fb3cce386ca087acab7b4b59d01a34b2811261f6da1bf1b95468c9dc864d029ce3c50d545948e455a1b601a4d89057d9be18659659d1ded2086ba31b9c9fab60d48869ba57d34b9876a97fef29c7eea38a1a7aaf6ca69ec53d67d388fe927a327d95750a7241fea86f6c2b1ba3389b8c58ee1ad4d7fb979ad0149bba27781ad85811ca02228d29545f6edb4162bdc80a34c5b9f022d64d95567a9f7cecb058b68d208a015465ac179c854a90642b805640a27281516eeda1b523b6ce7e70201b4d407a868ec9446a877b564e3f2cd04577fd5f5125fb46c0210a5ab66d0130f15659e11adc8f4779c53f720e224899c1e49b8959b3a0271c21b11b95b4a7cad7c5e44bdbca002bcf8021a9ae14f493f529341a54fd74f9910690f851fbb33c245d3a9d6d9d21a42aec3ddc8d7f43b7d3a0991efb78200e99665e776ebf66c28f4fa3af7f1c6db7494db95a1286e62887e6b919d216fdab6bda82e653be3daf15c55ca2ad1753149b4e361357736873cb5f533d5942a934046b91dcc7c7666a1c0ad5edb17994cdbc7b624ccbc0d477f9eaf4be5ba32191c166888c626a243bdc1f190226874eefa25291b63ebe517274d8fe904f3b36ed07accf89b320ce7b0b2027e36515fcce3beb9057eb177f1a76f4e657794ace520e1b507c142b6bf100c7684cef073115548b474d03006e6affb6e61691c33f5c2c5377867a29530cfb07fd811b136af9d2ebaafa5be3e850f4c89615fcb830a7399bae26e0ba7bc004380b80f235623a343f8f0c221147ee8d4cf9f890ebabbe1459b09e28c1b57e5787ad98b08c4a681f88b765de6d334cdaef9ce6d4aa91a1db28a572ec84a1c71976592fefa03499fc24fa44bc7fb87f44d85fee08a49884f98b1f08d8363abc24141301d0a035e4f7918895cc5fbb5e942a92c85f9b7c9bb9432988c56b1454742d5569336653426b7b04c5a06134eff477c1a27662d3fb5c73cefcadc1f8a8d059978313b62280f5dbddbbf2f312852af895989a8b222d32f151cc9d6010ea24c43a1f960d4e46b1ee792e4af7cb183893988c6dee337e1bb8083e5131c304439ea7c2fe6772680be117fe28859244c8753bedae481f40a76be71241885f12b022154540f232559bcc0d811714635b0983b468269fc296f570b871b6ed5c1edaa7f9bd560e871918f612cdc9c866680b735f5c31ee6732821567fa233c44b172964ac9ae25742e1ab90d08276c4949b29a0e2db6d2c3f88a2684c2fd42407cf883cef91f2e0de921c5c1a46f33ae88260c389c4c4bdc0e33b2bf97150ca1b574548681a721d6af4a3dbc07cad61102b3a408432113d1b4eb864d2aa511062cc575ab462af4e1d89317441acd8fa02be790944a134a533c5808a20deef82d65d4ab75415cbeba541460b22135b1ce2e1485e952aca5f48b76122f28806f2222f1ec80a551d4777386d9940edc39547ad5c4141ac253bd85307069955334510cd8acbcc4770443da1d32f0b9afdd75a636cb4a8c373f82e171d7cefa3a37bc335d05c9a004408eaeca347f72a198c86bf7e1099beac64223a4efb68a2b0c17aa192f10f917cae095d553ee6c42d6ac11dda156c79afeba4232a822dd6dd61c17b7639ae946565278fa4c1be428705b7544711d4cc19e6ac76c8204f1ee696915d398f08576bcdaec257a81f8b75bc0bbd2c574721f7fcd8b70cf29a0941c1897f92921bce4d3b4e72451fd5ac1a84e2ad77cc494504419480df0a3fbc99f06ac9fc4a2f2fb1f947b5941f8b62a40c911ba435b79ae7391b962a13d1130c3f1718bf1efadc7edeb45d24f6d9b24c26ec176b07ae9c29ea2a959a16d6f4841b04f2f2f4ac71bf0e40c2ae307b13e20387b24ddc53a7eafa478b1556c0c0520abe8819f66c066484e688aab1be9baedc05476e83a7cec9dd2e1ff1aa32a6f327b5404838b1fc1fecbdd7a49481a184d45bcbea1fc01f19bb6fa329b8e8701ee63eac22a3bf53f7b9a7bc867fd528349350d0f540ccdf2277a99593250b199c352e7edf52677a6ab0085060e7fb8e9234e8af938cec00c2b684cff955e2ecfe049f180b64560ecb97fb15f4709607399371eaf61f7d149e519361e4237525472ae71cc510937ece9f0fb4ee1b2eb9f33e403a4ea3a940db48da307e4e8e6b189ffcc50add28689ea62f3697966d82402eed47bca26e71bf88779f6f28ba3f43b6e8ade2d7dcc3d0d2311c3b2b487e6f2748c1ee16cfdae4c80f3f28d34fdc09aee4bc277cfc7c8d3b59313a8959e8886a589c78f2706ebc77b77ed5c27be9d0b0150300c9a26372d6c401bbdd701048989af139844be5531fca9da2ed72021897395b9b7a45bbd1ee52af3e5f44d5947b115dd31b7dc5f858c726eb52a07f980e76b14290399cd3d12f87d22a14381db3e1f2eaa51b8a2d2f50b12958a84823658c88308bce71e09483756857b48b00d9e791ae491d7bac632236064e348b1bec516b0b5b4f5759293bd3704609c575793947b97f405d765601150e458084b152a12cdccc4af995a8069d5260830de1b56566d35803fee06df4d06d4617f2a6c244e8e82aa68bd0ad11ec4eccd55b18773c7be802d5b3302b7408396d70931be2fb59e3e84e8090c4554432ceca1e7744f40fcab06a1a796b495ec8f51602bda5bc19d5cdaebe9c8e40ef774b1f40f58fabc9fe639b33a149444125193b94916409e4c9c11b4c0d736bcf2e140a2a7df657fdea490888b934403cdf965cba074856fe85815eaf097f7d4a334f4d1a1ccfeccf4551c6c8d48dd15f28880dd754db78fe5a3f61a7792378a382079b3babfaa1cf70a3127e52c67645ddf201365568d6f120c864d91dd67b9c72895f3eef119fe5a4570cc5f107b8c878c17983ede3801f42331b87115a5f05da021ae5b1c964746e944579a9e81b3f8339f537a5f4d16846f652e8ce41469a76ec0e70a7a2cbd38230c924aafd8c827774ae778d8e44e358efebd9b2097b173dfd3c71cfb88e78652d1d8e1fe96607082d703e3de65ce31f3ed1fcb287d1891942aebde1597a3e5217e89dbab8ebb9eb5f6e81ef0ad1770a34ba57aa072d628b202cf267f9513f77101d3edfa69bab2aa42a3175cd012a8c76bb85eeb42269a139b8910bf3ff8a3ca4744435a4da8224d79b148ed343978389e21619964643d2bea4f361be9e927a81dff0882fd8878aee1eeb6cde8a75c9f04a3fc86a6dac16667741fd86fb091050f56c4cdce6139514fa724b89c9af3ea62d9f00bd0ffc2be3d598a5c1108eab8a021a78140faa5665acf1a9c600546864e0687b000f3b03b93a5ded06f2ea936079b5427085e1e7836171e806392ff0cf0eea089e17f89ed415f7ea3ef44c9c81ab35c5c35e8984c33c4d6f2dcdef1fb8641699e5360fa96379f17da6b0b62a3563c2135677becb814cbcd1e3a262c3d1a12d78c8dac277832b8509e724027e8bcbc9125d9ba35aaa74a677507749961300719943420b907f90f3920c68a8cec04b028513eb1fa24c3eaa0d7f6d3f8e89127e85aa1b3f103b61895a8672a336242b52e11c445be3a0abc4317e59509676a65d400e9724c06c8a0a6737283c63b036f7d5b121acab27f9890abf2c5b0ee58a1c0f8c548bd6c6af227a081dd1b5bf40c14e542fef1b35a20d87a2c97e47e8213f74224235c50bce70a8c5126aad823e35f82bff4050e3505ff48e447f9a6ffd8f0ae7820a9f01138a11e6169f819646e863aeb9dee7fc4869436635747e0382fcc9209486cf89445d13d99a09e20efcad4c9edf419483c4b8f904c3cd8cb0980a2c8c721de5c5b60380837fa274d8b4b08576645fe8af30b8088f6ae55b93eda5f25b1f03859571799832311e8fcc56591d66e0dcd6886f4b21b4b7b9755bef935f0fca76fccd5e74bcd1aaa41ae1db9c5645dbaf5abbdd5d8daf0e1ad676858175ba8c8452b2c38806581fa6fe3e34f58d0b92d3471db206b2a60f8568f565b865ab5fb548a7105ca8e02f8722b387602f9bf541f859bf40d78113097a788f2448a5c120b40b8bebf34cae1fc879a00a32e2b2f7c0394e554274f5fcfa48eaaf3f8279f00f1fcf9c75114512c2895018ce7d1d219efbd2bd0eb81c248989b79c2aa90e71fd5ebb4fe1edbe81ac20dd2845077e48826aad3a44bbbdc98fc29dfc03ba7595a323eb420d7648020a6cab116dc8b5fce8bfe54f5f963bc816d6fe8753aefd40c3a2cea34ceb1fd1d0d65f6656d40373d5cebafee5b46e4daa0bd528c6faccaa15bcc7168538e7e1550c1cd3e7f1e4bd3eaf768e03e90e5e064b3a062921609905f4233da0378375787fdd58325926e84d0491b986205e7ad0431884be98d7411318597f8f2448a5c120b477869e677a0dbdfcce8336e992fe1c41a0425215e2dadd44cff8277af3330f4de290f43f2201b5b42ea25dfb458fe730fac11d076ad048d7bd078e030609a10b66464f021a7d08d6c13fcc7106569b28b9d5fa506c03d263b120fdd8f7811030bf76dd85e3480b2142076656cf0db4fa10cd03b6d78fb5b358a1de4590d29608e2f45f3d8406d6b7342b430171acea696ec81abd55100dabd73333ca5eef5f9724d8bfa83d504b65206bf70ae2723aae663ad1960a49953de1eb65a20f5d5fbedeca51d4c53a461bacb24baba932a59d657f49f8f688d3b7dfee0575f98ab010da5dd34d807b195a54dae3b67787a73f654cb31785215992f71c6f63e733f450294e4333074bed599b9ea9bdd5e2855326ce4c4fe375432a11c82cfbf0c5ce20d6a2ddbf36bdb4ffc5e9658da7e4883e8b4753c5e3187cec231223eaf8787dcdb15e882262e5b195afae6539d508def12fdbc7574af91046db1c1d98731dda307e39c739be99a728df1b41366a3cd3fbf93e42babcf1c7a1e3263e7f8f45c1936135375bde79d057cf73f7741fd43c3d33320bb84ee91567651d47b5e89159e52b42067ab8dc992c3bface234113376fe49179d8c09cacd15a1ebf619a3b5fa8073f41d41ba511f56838d4f45233223d28ad875ed2c4cf0380249db7035fcd2307589817d5571ed6b1794aee0fb06ac4a4f4a6a0c5b5091422a1a3a0a2f95bae7a1fa44b10a8956bf3151811912ca0d8e049a458f957bce4135175cc0befd3d753f64c2dd2a424c6d0ebea817222a8627c1766afa5e9524851a53b0bfba83731c40abf07c1a727079393999e1a820ec8a8879b100086c66cd569f9f01b462e7908da42538fc448c6fd9ff615c86a1e720b92e06fd9d0a8023f506ce01c886204102cb38b6e4195ca51dfa940270cea3ef62a36b5985a20d950456baf319cc0d5b1b8fc5da2acbd662ffae3010ae51a786251cd4f1906b7b10058865922ebcd06f020132308d6415673fa479a2066f2571b5fc875dc37af76d1d36c9e02158646743e2046e07b0a45cdd950dedd98c3570915f75e01afac99637b3ac5f9bf3a3a378aed14a2bbf5e1a554f70c8c32b2ba4585c1261a3ca1885ed63484b8e8581ea863b2441598d72340d65e0d6e717aaf8eaa30b211aca4438c28fe186715655d7097f2394ba2b055a3387ac9093ef5e882c3e50b2bf60eacf7ed86ef67d9aa9a61ec183d55f01ae2a26c29b515c65a8f2805788f2c7c4c4b52db0f445b5d99e55187a73cb966523347aea3b40b4edb9a2db911042d4a3d99489b270dac4ac19090d457ccc4ad5a7236158b49d3332f354ad8bdbf62602e7a276b8edf529b5d6eb01f10e88dc6cda052ae37129085aab6408d9f02133799557fc4478a19fec23c2ea3e24150a793bfe717feb06ff2af9b5493c1042ef90ece614821490184fd74a6bd238a8d5d46c75d012da7e3088b2471663d96ae65563281f581c6d2d04d67e09df80e8740b115c66ee111aedbfc168e1da1779d62abf1c85a66695c8453a047284e96868456b0df340f00b5faa97ef56f3d2c2ae9cd3e9bb752bfe96e412f32d97e976132f657f82e86143ad4d3944720199ecd9b8dde2c4833c2fd97c230d3fba2ccde13242963ff6e3e95bfba52f7df1bb8e30ba7ba1199d177cd49febd8b6bf1462ff1e3b1b179c70a3bc26662531ce33879a82ba1544f640bd50e3e0f72a2828cff5974d75be7f2d818953d97c07ada9d44cac80763f873e9adbeb9c9b28029e7c90caf005324a3b975d64f67da6849c655f172b1784bef80e5ae1c44650323a56bfa32237f1ca58db6b14f6f40291116434601d81013f2ccb738e90d277f2e82bc3138f0d82c3b3b4fbb4d80f1f1bac663f042905b92c13013c65fcfb9fe04e2e7a606a15775c88b543950af428e13e3c9392356ae9caa97bf77fc15122773de0ef66f492e5ca15c50ed8c3d06cc6055018bc2193362d6fbdd595e5e77768a4e012f63d9797561687931130695ad4ad75215fef4c6076921641624591a6d742ad328da281ee49baef3f046962328a40c7d86c7fe65af2c49f9a9561906de66bb24247442a87d774c9147c77efe11ea9bf3d5b2512a4923026e766d438ec317d29b9d0c45222440214dcfe9c20225aaad50801aa8701877fd9072bb440b5f28f0e06473b27b6eb6a073a7dd6e00e881c22585a01c95908cae051428c44c4cc91dfac6696de9982d4c56757b4c419995953098e55f6034d585895c0c86bc583303629b66c6f4430c64d100629beac6bcd658de0b56fa372d47d26b5d7ffd829e3b0d44ce68f70daef4ba4160580ec5062894522e7a3b19cbce29cd702db65e906bb287072321348f088291253444e0a4b25f5c011bcf4a1b194d24b324033d94fe0836b24a944786b0f1c09eaec21af4268a1c33fb11188c420e92dd0eb491d81f52e3dbf620c959c79a2df0f6a074cc376392733610fe21c798b05e448967542f228b510027b9dcaf074de244dd19874065c44a494ceb0da3925bb30fe7981d8151b7fbca099b8e9898d8c4461947241395911e267a205811b8009f94816920b40127e9fc9804ebd3538512fd1b118d968b681f9cc3c333b32aa29063823702b35a906b591c66016f21c242828333e06bc3c3e858cab00cebbac1114a3a4132245e5a6e42504f77c101f0928990854c105672062ae70befe0dbd77b505c4613245a0d7e2e6971d0ddff62ed3cf293e3197e48c8fe2ccbb3ecc9bf1d906d92012825cedf5cb52c9bedab099a4a2eb9bb4926e9e6c619008ffb242de727f8d46c3198593ebdd1c03a69d94bc0907843d97fd6b5421f00b36cc3e51eb540d8df4288b9cd2ac991e3486fe61560fbe148d28f59ff1e71dc1d37fee069e8a453ca42e7bf0f5a55fd4c95887e0f3102c898c8357a3781f81aa143aeacfb1ec2386e6a036647c0594193ac326018951f8861361886f2d27044f22762898b8fd46a799190155e097bfd0cac81a288ffff94d949761033b30995068ee705849d5256f9bf0c00fe3c131e376a66863a64e383cf782c4330cc3af4bedfe0c9ec5f14d0eba1f66d64243840534befbac00b805f7fff1b3edd52e26c99b506949697c2827a02acd55eefe33be88e2e4485ea0b12bf84a0ae2e7c8983aecdc443cfecf62f4c0a4ac3dcf22b52a0525a28ee1bfd06033a14b2fd830a5f8858ab5961f16e0eb1c75b5b55d28fd9082ea2ed2a3311c3aa7ad51d042595c14bf006343f909c1dc9f92735ff92eb44090014d184c554473f33b17aacaa482c6152d80bf451586ab0fcf075223f505f796930dea8319d19e46fafee4c85d4964e5f7dbbc440b015243ab93d3f0e6274842446d2ab0095a4680a8e0a7881166b3f6e53c3183d34e94935c4d31254cb0c12cb022d5a44f9e7c881eed92184ff858a0e170c52dc9f877dcf8bf0c667ed87ea82413920d2993cd02a88b7520950e1d5d193328ab3b2fe6c560e579a3c3933338de880a566a290e43c0eb7352e071ee5df447a38f05fc1e025059916696b2c0ce5cc8287669776ce486cd74d5e333cc1692e7072a35a4a7ef8d92db80eec6c59b28e55a3ff9bb029f235789a58eab6e078764ad06d0a254e863f761120a7684c3e74a1d84796e0c0d68ab36f32dcc1580424a07a4156ab686c95eee2a02bd3d4c50c307cd2e489992661b4666329f6035b03241f93a942b7ecc626bf6e9623d56b76ae99061c80cf006c051e637c2b0736891a51d2ec279ec5e5b92b440deab189a17084c841744961994cb8855777e8364a622b1b5ffac8b555ddccb7643ca0961bc7709554b258522d2d346f826e61e8980af9f489f920c8e106b50918e04d51de0aaac0b0e99189b6d336336f408c4d99a9e96d3621c1981e21b54d0ba01a6b7ba14c6606cc20b4c59c1d9817c8d98a23145fc9583483f9e714b755858c91c86746973ca7f811c95d11e1569a18ac14dcfc5f07119bb2a939918fbbca92404ee98e65946ac593d30748cefaece480b7cf3c1331c1ac87d691d66a6d65946d6e1290ae8c0a604d26597bd45734b905d333ad58935b0626d3924493e18c6c7ae947510da9d2897d268ba6b607cfdbd1346464ef24b39de32b32b1cb3f76c69ed25fa1e2751f105e355be5a6a2a8193e0eca9e9f9af24b186f5d0e1a1424d32198f8b19caa986e800ac59d7e6200deaed146a22ce2ea171079a24e543c793678eba5fdab5fb15c7f65417c60ef05b59d1c38fea9719624980ea3d321438caa18f3572c70a9753142ace4eb4a665faa8c3fd9d7f516727954f1577094000e5040a10c008afe1ebe147a5172c7ed129aa1334e6caa3dd822c6c3a2b22949552c05b28bf72b6133e88a5d1d4b140aecd8ac652dc24b2b5beb757a69596b556ae58c02ce5a6586afbbd044d3858a9516af303b0f34185e83a5abefbfe5f46f19b27f2fc7c763e4e4c5779e9356ee5c01ca033d490c8ac4cd1a2a74728d57d26e0ac30c07bbd8dcd45f4510243361cd7c0074731eab40a6971eb62df6fac81806d1ccb20a44b4493d790bcd9a3096f204614156813e86eee0f14e6e7752de3c96ee7676aefe1dacd535cf26923f451c63ab6b54bc9149689a3b4650d7dedb95f30b87799336754ba243f3ed590eead02597618b8a1ce5649e3849f1f28726936ea9ddbc0f3dadea95698a0b161f9ebda069a69614569ca7840eb4bca0ab54d1cf8f2a3ff461e8f5f3b9d87237623d8317ea8e0136b45cc03125f405265180caaf2d51568688b7500d72bd85382986205b0110ea61d5a4060464c188988ee57871c8e1e340a27e1776baf2f38a304b42c7fad071663bb91b1b77339400f7c247d938b8c58b94a600ac9b0258b1f49b9c83e71831df93f9b8dc03172e4635ab3aef8269f73f370a2f9dbd41c8af81f48befcdb0b955e6f8024505fa076480692280ea2bc93822247d72d8db1062580e4571320fe083197d1c7f716fff070638e83489b36456be9f6f5069c243a680fb282386032b6e25e756a9377a5d1bc903e497bec8e5befad52ffaad3c959213b490bc3f63ad2e4f2d1368b7905ab40dbfe52906c19e28328103e6e81e3775ab4b56ce80a197a4a2905ff98c518577865262d42a2dd6323bce2c1df615dee0064c0d4eb9dc156fa64ea80e179374cb8e0281883076952bf63239d64638d90800ffb491ec95c2fb06f209d69664bbf10f0ab4bf04d4a6ce887bf19092ea06565b18b48e814ff13470957dd9617c50cf02997438596c52a15579c0916557e9257074cfeac8882ff41616b5b6e3d3ee810ab1903eaf53bbb3c059a7303a55e5e3dc2b6f75f8b5d572af63eed9dfee976cfce3a1586eff5b7cf6a58eddc210802d72899dac984a101789247eaa77df4483b473c0db707991771023a64df2a7d8cbed454a2d7eb0acfdac84d6696d0564b313984c69b4d569789a0fd7a74a34158440e6db33806150afe5e28171aec000e8c2d3feafa08ced04fdb96b29222cfde67833c85f6f4340a407fb4a12d4ccc8117b59622a21ae123571b43a3897533edd8f53ea3bd483177c2d4f216b076fa6d2a02197a52a53165ec1ad169858dd710261958e72a8b5a0116ac5237e88f8fc957ed2da1cdbf4d408de6938e84046fb79433b6c38eece5d20996fa9753a0a571d21aec22f2de2b5058c2b77585cac9110169f12175259681bb90755e2486fc343f839798e170b1f6e8405d87ee254b476e47a24701b3d1a2829823e646fd383122dbdace71b26776bca7040e6f3d3bea45dd427d004a0729cc98b1623c66d1e5841bc52411d7ac205ed29a2ff0d21b1e2fe3148a4d5f437c0348bb9f7497fb6e86f54cf8da789919d46a8e3fad4ac54f3c954c0097abff02f222404c2bc7dce5949a8dd44f287cc371606536a2c78b5215201c00bac18f0cff5adf8835287f39c6b8fd69937f18df13adb43d0d004d9f22bcd526df1b9680a9cf2e4dc10d1cad07e6b383d95becec2dc790a36f2281ad47a5df64827e67e96b1131628a2c9d74ec1f6abc7e5ee569eacbf49359f2e9697ee86fb4fd096403e84c9122f497196237e32e22399d3bbbc03887d47e7408cd2dec39bb1e48e5fb50aa0069ab11e1b52c1607192ca48ebcc06d9f1dc33f6c093389d5f2424fb9464061ae7351e6058dd9b7e3ad3512a94c25f4b8a61494817fc510e9be5d5942551cc56e5a38070ff14fa4ac27dece612dd1c293e0e447cffdaf18d47f0696434204f990e8144b653513b110be33c633bd676062d10d9512865313bb71d6f2c424698707f1ca2aea956b177774829fe909e8237d1c12c97889e48559f98295133a3c647f96a050dcca9100fb32e920efa603c310e7013c72810e51c9b8c34c865039226afa8ad6e10a2d518ea2e64dbdee70f1697345cc233cd68887f47ba1cc46547d408878a2eabd01a64b7419096d25cac652d33226446ed5daff738d8a0b63919d257310619afe81cbe148c9fdc4991b0c41c26691b800633f251ce8a6767efc3eaac9c8f115fc17cb83f9a99e2cc836cd864386cec4423252e5976f70762677d38b936f8a0840110f3b49eaa625f26ad725df6ffbd58bb2d67fdcbdb88fa0e2592fadc4964295cc82aad0654de8a38d41654ac51f6c6752842a77328aab54c926f14a9247d7f61ea0d99084888253f570912436321714664bf874c2a764200c0c9fb4303815bd2044a9512e604b8137420274e1a7d6501afeba0fe58d8048b1a1ea6c258124226278e457a60d266ef13a14bd0cfa142cf481612c78a3d9197b0c394efc9c4845b5c892e01072a73eaabb3c3c99895dd23af27d07104e2b54e5e6d48fb51d3f35580b0aa8bf12ffd3a639ff75989512048d747dcade05efaf24c7ca9b43c6e8e9d59cd0fa2db57a8f92d730a37ceca0ec253db1125475fa38930f9a2de718ec2e0f1a9b6db7fb0d307ee92215ed9b1fe7aee2e8a1af43e629e02a9bcd4cab427c66e432a0f10d599e9404b0f770fad11691b280a77e616621002ac8250f93e6cd80bf0e818e8b098aa3edbc5b1845360566082d52f12267c30e654f6edbd84a4a7fb83e939a3d6b7b5c0b23bb51535ced0a44f5314b17d926a5d2e750553050b6bf4481ff0781117ccc6036b508dedc5f52bbb0aa43d87b33e8648a9c83bd87bf4c51d59ee4b9a891da84629dcc6d9a42c43ac2ff01f55da9df990126a6a115a3f520d875f03abdf653958327ee111f2a657c02a292ff02b75be40b3d1c4660aba3a4f93aa626b207b079db769de72e783c148e2aa81d340de82839e53cc852bdd4485d9055449038f2e2a824cfa48d742b4e605206ddf82f6b74cd2f3029bc30112f21da2e89c36951a8daedad9d0dd0b0b64784ad0666c166a207b2f1ced6af598ac93ffc4c9aa54967468bdea157ceb069cdb546e714148c1d7b3d002f446cdbd5bb38ad833d3a196fe4e6c2b5366f7d0e3d81f1d409cf9b9fafae0ba86d670ea85c6a08afaf6b3190e22a3e0db590abc2dff02d84224f2704dc22e81ce900affef86ec842d101ab9e348ca434d0dab5d5567e71f11d21fa8e7160544bd7f9e32d53774eb6880fb5716247e1baec052909e487749d3e639c2f9c7311640ef6d2eaab4e3aadedcfdc4c0d3581fc1ecb5c2bf7934ba57e58c866c2ed31bc8727252b6371ac2f0024f5e69a25b4fac3ec9c3a4b6bacde6b6a77575ef4fcacb133a57856aefca5ed4a447039a593b59855871635f1e6d6e57acf6d8cdd12375ee4710cc0c6a1968a3633c449110125957d0dbee88054aba19b61cc727d36b3753a94fb63b978f16231843629c6d3d8daff2a723968cc2580745348ac45d9d1927e9692ac4c5d8e8efc86a7c56a5cc122a67a7b3ac5f8ef485a228d4cc46736dc9770ad7f68ce8dc3957394fab94b6cf294dacb0773ab34ec2b4befb91085b5268b6a89fe991d8dc975c5076c104a7ceec1f3e541e43690f868f28be19a4eb249ff2159c90ead4f3a7c3689a9f0c430388a63638009735007f3321b76a308ce378667794d6552e4f1464a7c2b3fbd8f0155a5c49f04aded81b407c57da002f9d74a9849cfc0fa7542c77a3c0b90cf694e5159965806a27d7f0d486f7f4cff7ae420b8558405dbd494a219cf077dadf337c559ec828fc47d02663be54c18368e04333b63c4383b01441492ce7c8081d6439b2138381a74bbae4f40c6353487af8879da9d15e02b053ba9193c33c31067790850362521f26fef936b4a1c25e6278b44db390761befec2769775b809dc54d598fdb59de117d02586f0423b0f3d45093d0b69052dbdd143bca4897a4c6d4af65936f95097532d9b1513fbda5a1fbc24719ea75c6bc4181d395dac5258b0851f47cf5eb93aa9a54183965488dc0c6a9d45bd8246f37a582fa252945a579542141875121891b7239b8c5e1c7f667d9605e6d6f007a86bd33d22dd818aa9d5e7579b9e7cf734dfd62d5e5af12f4096f8a384824f3f608ea1e7c0a2bc302cc488ae1b35e183994dfcd4b62147bebe5d7404fa0566d62084750a85da3a6a8f222155dfa09531457487054706e8b565194ab84d1b8aa87298a2bd26726442a510322bcd2ca0a013b98732faae656dea021639629a92e2e6824c8c09851a8900331c21cd70f82990785bb2c9ec219573298f510b895c15b05f4b681c2261b9ad94e90e37fd1a737e18ad22a92971e6cc93a1084cf2155914fcbdec0ec8a5a5986f5a70cc3dcf4ec4d621fb9c4f6cd71bea04798f0f3fc6b17bafdbecc4e1ec3b7c24618420f3409017ac7e02d505010b1ea1256a9f27c23cc1713d4859d2c95a6a18228b60ffa1875915125245422078f1a3188810300000e59882c3bd9410c201818001b80d92e6e4811fdc7d9843e33c3ffdd04edd62ada96494ad6ee0203c702b7024ebfad9bf29f31294a245b2bd2f04b894d2fbfde905ac652daa8b6f43287a0137f7e4b3f2950e90a2174d8f3c81917ab2a119723e858950e79a196a868482dfc624efed563c2e99270ca184ba7343a1b7df39e926c246dfb6061125427c630ac855d6b10a43e0d913b22a5ba3422a2ba31ad142829dabca624a5bfa3338d0e2eb8792d255c30962fd81c94d9b2170643779c5f6a92b389697eb7caae6609e677ab4c66068200473c705803658e0f202cff3b03391eee1c34043b5ee2e6c001870a6e0876f0ae6007b7ce413b1a64601184602c147f0065e22c000d37e010aca0770e38168a4930e104165c88a10c66de6a3039592333f09edf2c113ca190e382a00240d983293ece2f35ba9cf5fce13177fe787f7350847c3ceafe7b73e8d64f66eb2b8bf1d5c5e27bda43d24b91e7836773c7b483a2d4414360e8d171e75e70cfe4ac5b2d6d54761a370407f486e316f3e2a9d2f61461e35ba373f1d6224d4d2c8d8a3675b6645654f624d3c1ce8c05b15c8348c46284d559e3c05a7c8d797175557135558da8d12da7d6892c2013584025577e5677555aaab5293229afa82b28a7a7232721163d4d4da697a59f13a51f90695e921c52db91d90a30a32c29545112918aa11f15372960847c5250f82ca37bd0b9a75b101a50d8cf968f548f120f91336827474726a76705a767e4a66b03a30957a376e24a539da192618a91c240993b2f342e3c2d26784ab4f4b1d8ad64555ca46051ba4eac4c5894ac2881828467a446c4e9b2749a0043fe8020787f5b3fb6beb2185f5d2cbea73d24bd14793e7836774cbb1d94ba9d10187a74dcb917dc3339eb564b1b959dc60dc101bde1b8c5bc5069d31111b275d7ea5c645baca995a581a1699d49992d9549c9a2589eb1e69529969312962362ed82d57d65bdd6bacab8c0aa5a54a9ad252d6956148be7aa69c5acc249a1c21199ea4ad54565a16ed69eca3c00eb408b03a90d9634906610c580e782a605cc0a6e5228b811f1e84e5027413682b5641904600f683920d5c01203d205a20af07434136022609372808d08b24ba26e4496634d2e3300ac00391dde9f6531241a8f71ac63c6ba3ea4908dab81b9fa915b53f62bca90d254ec2f6e6fa2e210d9935d71dfbd677f861ef24e3e9c85d11026b910fe3ffa0b6620dfde50d9900df8851b7e0bd13949964812638f74df5c0d7e0d33f74dd7b421800f4f9990d10a924f9af4e5a5d9d6e4a2f744d90b8466ce850d659cf0dce9109d60c148e1c7c6cb8cebd2f6dc7ccbd8bbee9fa4ee7fa762efbdf7dd7bcfe6bf8b8a74327d13e54decbdf7be39e7ccde3b726f627f1b104164872c6f1e570200d028bc00ae88ecbd77993b7f24812a5d1e64d38248f6a66d692f6c373d59ac3aa8971f0c49634c3532cf2bd7e59ae7471d9979be04e10003456af982bae29928a145a56e2b0356e50216b79125cc6b6f19de9befbdbd366c3c86985f286bd2fc61dc435a6bad753145a8438933e0d396e1bdb5b5a5cbb066e932ac5b56302b4a4aa36273539bc1f935d524d386d4e501c9a39aaad9896996a1109ba9d79489f6a457e69c5130cb25d00af065a3c1cab37bb2911a5595107d027a2b31dbd306b58a0a4b51bf69d71494910c56e3860e0958e99fc3793cbf54375afc2844314415084cb9c9deec4160c35b5f3509c51dd50c0a7a23475db967d44ca3e0648576c714949e5331aa8b1d2d0b7aba5b46512a58bd7e8213d4e1288344d414c618cb528b90013b3f4e45324a2f725d9b94c55438024861c15935ff60a46e4a6ef647bd69c144e131c270eb4f75fe30bf54384f4fa54b76b4283b7e756d2a1358e159e55c3c99a02a0102388513a7b4b7e536a7cc8be3d22eb1285a9210a02346f7a56442c7454df96e2e756e2a7778336d313ef2f313b718f8bf8dff5c84f1eac4053f1a8d47213026acf9d79b7e75e02f897f7eb374f8923280bb73a0a1cc871d76f9bd9fc7b0f0680caeccffc6dfc2f98d5a1b993f62b98ef7cf182aeef76603b9615c11a268fdb19bf919941e018136c662c7d2051663a67175c6dd8959228bda5a04eeeb71101133190bd117a8a4164f4a8dc482450cbb1c961378c31a4e69d65a6b3ebf54b8a1302e96ad9d5815e10c58327935cd12698cf28fa27156512dac4f9ff2355709f8fffffff93e0ee70f6412b8f42fdf7befbdf7de7befbdf7de7bac2b28086fb8f31dafe8105776b9a2ca646be1c44e864a49ec79c49f0bd3759c3cba675347cd18147c45e673ac3bb583d5c705f91c2107cefcf0acb2b621511188d9ddb4700a2223d272f978d438644d0d1ae7089b8ab4aa2923a5bef253790103098331b6f50dd989c671c9c595d796e692a7d44ccca31f67cbb2476e2aa845c0f2f1a86db0791a5d33412972d7b213680e51a612dbe89dd19bde5090788c61b8d9a627b8a2e3f6a14c7547949ac78a9975c327d226d70cea1a2c9886062a35356279ce209b1c962d7326542fa86748ec7416ce1fc8e486091048024bf30f7c639b8bf30bf576dd6a9d26e48abfb03e63fe88f7dd735838e40102e331163a7de03ee7337c4067ae99e1403cc7841b301ee3786ffe9bcf990c1940c61db20c131139ffcded161780b71d147861ce7531ec888fdf3b172b4c60c72f7c03f3deb94504f0f48929b3fe8213845944476436a5ec2a28f698712b2fa24d1e0ed03449b0520ba4aa62cec7aaf4d6d138abdec4b478cab8d00da42ce4cf95319240267b72f3773fe7a210476c187e61350fbf375dca90efa4cb70aff07ffefb6fc861bcbaf4be9359a3dc79f2bff7de7b5733a0f7de7bb7120b78ac210146f918c7724f4211da3f8d0164ce8d0570dbe87b874076fdf06ecb38f62cb9bd877f6bcb3202886361d710845108effd5a280f00cc3909b54645e3cb1fd606113776f285e1de7b9fd970437c861aee75fa35356916ad967948d51e69989cb4a8618c8f317357bd6b55e20f2fbcff2e80d8adffbb9f67df8a1e36fcc223bdf7fe7b67e1adecaca9b89d0ddbe890c52216b5cc63638633543d4f27b36bdab5e7616db037644d673d7a6cefa44787e63cc82f482687c8d75cf3cd390f0639e71d5afe90f550cbf0731ee49c73be7be79c73ce797fce39f7e07232e9616d46c0a5b5a65a5f5463acacf4500856bf13b71c9e99124acde7567d0a698f56b8bdd65a6b9da662e6d5280f589ea2e50a59080c1907266a5f6a735d203b25a75a575491ac9e3fcc7bdf2a22f04c61261cf3e182c25449d1f69428aa9c5c9914286a84a42fd32daa90c896b213395d5567965821506201415843028cf2318e85227e77c88f620b6584981ad9614a3bab96297b090acd1bcdd8092668fc61c32fbcff2e80b8ef1db6d18158dc7ec3d751e9e3c55c2392b9a5d55349083080c4ae7835d41328707ba207547d6952a167ad623bcadae1e316871db2ccf573bb03c0338617141765446c84951e6bcb3364684aaa5b0dab31c5fe9c7775101780114ebe27ad6a9559a4ec4d13542cd2de98eada3a8860ef90e57d8c6361af22f52e17f4496e2150f3ad549cc1b74943e3566808ff6f6fe0dfffff7aeb036fde019cf9d7235cf816a5ef98ba1dd1c6adb5d6da18f0d623323234ef6a0f945fb8c330ea5877a07d41d48fbcbec6ef7cc75b66f1ce90c88350defdc4ffffe6da1e210ca415dad41ee61b1c5b5ab44984164f31402d6a6270863f549ce7eb32cdc459c550bed3848b8a1855654bf9bf5f6b9b1f0f87237887b525199f845f18de5dfbffcfb7eef2631c6f2df3adb7c80f829c23f901d40bfe6bcd77168df8bfafd9b8ff7fad0ec11dc32fbcfdffffffffffffff7f64872c0f7de6ef56940f3574cdb65d2824cdedb6dbb2f71563e9c7e2911d1222b1ffffcfe5a407566786e797ba953400d2f5ab4370c39df3e725573912522792902f39229cbb144a569a8ab854dcad5cb53af2aac6a47b3696a5c4c4f645cc48f911f7cc5a08ab0648850e4dc5ee2f7fcd336b38a459579d4311a2ee028bd4a8548bf86846004a77531a0c2010876120c791467c2d1400091cd24468a848242858c024108a0281502800060241a1202008832014072118c3642886911300c93dbe43781e1e053d0e85d1b25e4320e9ce459f94650dd4f841267ac7151c6b7e9785dd455fd8e572c62d03260f3a97a8789ee8a29a4e8d6276dde80b2a83090644eb711aa69a553c32dfbacee705e4529bf99af360a2910fe420f4bb0cc8b5293a685efefaded1e37131d566f69a9d815e8ee8c15247138d46a641527afe90143b636b80e2abfc0eaad649e3697514d306061991c133216489488b6cf3e306527bb1ec4eae59c0b7dedc2064bf5c4a0689fc4402553ae4c3c2265767ad8520f99f5e107096d49effd8d8e70d129ee3e6979636326d126ee3e68643a630e12e77dd7d6bd300579f426e4528364407c8b00a406cc5f3ff2c422acd45771d006bde5d1ad7464cb291ae7ae99bb0efd1a7ce03ed654a44e1cf45e0a066b036da4b7c8f5bc49f7f63608217ccd05506a02b5a27872d27c7bfc96cbabd1e23f30ba41384cb781d0c69a91b8e82db6407848ba0875270822ce3967aa0a445a7c8e3c4b5ceb0861ee2e26d358b1204b514b1b7a3da8e35b52b0b374fc91319f5340f5d42e0123362bd577afeae9ce5070a7ad3603a9b391b4cf9fd0de4cd457819c794fde36d55681b63e0cef12eac85b4c7185bed8d37e5ea22a88f70baf186ee721941f4d686123a86a51e7df0044bd2ca377a5283a9656a89ba784b424c8028fbdbeb54bc9b0c234b132a3a8b8ce3423a69cf3a7610c2dbdb9200772f99787bbe9ee4e858f3d00e05cf1a73bba3d3f94f9787f89f912348253abcdf185f7b209835aa76b69a47c937372abc8ba4d90acae2e5993d024af5e3420cc814ec0ae0d77a326b0ad10d88cce3e00ab917ac96d7385d06ef2312145a4674ef80e75e6aee37229d1cf02fa9470940f036ea8c490ff82ef0b703acc05baac221e4e28c4087bb363aae7a6ac0db71828350d0c0fa70488e5bfdce00de82b292843491a1df2d12a71a13f99014420f2ab36e199d90b59be39a352de680be9b52a83af0c0eae73353943e4b967fe40aa2ec71fd335250ae9fdc4b9323be71427db7811267aa0b1ffa657bad4e1849b845700d198fb2120479607f82941020c4fbf753a2be5b35be60363665f8b743db239725556a57ba6baf8daeb7a877534b1535126da195733dd1b3bac08251f36358cf11efb6929931049eab5b786ba38fd316d0627a3d766208bcfbfb6fb1fc6328e30765a7c74412026dd8ddf48aaf7fc0508282e4a576d1dd7069fca472c6c190f37cff85bc549e8382dc4d3af9471523ab207f6e7b514d3e51f41f868e197d5564bdd00424020945670eb94d215f03d49eb54067abc53330f5c768d49c8265ec9be4b60ba84d53202ea1a501fa6ea03ac0a057b5a8373b7e7efa58ef02aa0d99ed802867c8b643ab8470638ccbd9d3cfb076a99fa18cda75c5aa0d9266718e60efe9459d2e00527911175c14deac969108f5c8dfe1f3833cc3c413efd4571c1a890af80ab7a8e3e3eb6dadc731f1af18b9e97bfb6966877d71bf20d5ce6e5f2e209e1a2aebe179f3ef24778e086d1ab85d0d0f86123d02b3f4a6ea3308b7e1402c4a59523f33c878f29da77926a7b0ce60e7c63ecf4238039977b7a44cc9c7416ec219d8d6844e01ce8fa01ec250be3fcffe8a70e033dc28ef3642c6083e0da7a64948f6d513c1e516fa2cdc13638c0b582e11e0a52c02c2f4db8841a5390ee073678521097d0035a9660dc7a86762768bc3610fe03669e7ceda2fdf97de0223f5f80491634132c92e4b0c5424c301d8d812ace758c11b58d1dda9fc89a4856e60b10001e1989628b9c5499feeeccb2c1668ff5cc4077ccec82abf18cd21f14de662c291fd147f17acfa0453d1b878fe01ed8b65483ec5cb03e8953cdfc6744fb81e027e87189ab38cb1311f11c29adc206b40d55f8292b7618dfae2d82f2f412bf717b1196502f345066ca1cc7ed3643a477e20ff8437c629bb1ae82963d221855de47da5209ba27d07707af73d1b94991d39a088913e43522b8d91d5ab476d68ca8ff355d74e8ba399ba5ff9bade98f5e00194918bfda47740ce97cba785dc42c0513d540df89131740d2c231f969091c386b9c51f1b8cb6299f23e02dbf2037942e983e224d2aaa2ccf29dc546603a9fe39336f834fa384d291ac287830b36a0a4641c372151cb9f5f02db3aa03db0cec5d1fddffb93f93ffed193ce810170884461be134d44092791e0382fa2bc105f27816aabadf600266e77f7134006dc53d428a9835f291f0fce706d8571eeb7c5b8c8fe1378d47de1a17d59fffdec08565468c0870930da09ce0b73356dbfd679eb288f0b98aa823c123f44d5ce51716e28195b4e625b08a81491310ff82f99a6ea60753e1cf87733bba9b4162221f35d0e071f5cc5f8c4a258a332c53f8d8e7cbb8723e3cd309b09949e309878c10360a0e4631bc913b3c875338f5ae3fc1447baddd736f442226b82802f953911f7ff9751588dbe71eac5a8e333c02b9697e917cc76bec42ba7050a76a592637d615d537886c046c594c77f94cf313acb2a0a25f25b6e850f04a21de8b35285b2b1bc6f3b6ec61607b957a5d09970c9e3f57892720793a85bbfce84b036449e80044218deb007a828f460807a5ac29963cec9f300047bba1caca4c4fb854aef34de4e0e60cda9c1dde63f52b891bdc72cd08f4d21d234e8f84cbc3d7249784f8f5e8ffd0a2e9ca986d81da00473e5d528a2f6070cd502a91769a9423294d6ff2fdbc6d8e20a8dd997acb299dc7787d3016b4b0288dbae585d5a2c5c6987dc54a51813cefa188dae14134ff9426306d4782cb6c3ae9b6235a031d2f9ee377948184fac01a0f6c56cd6a738779d0ca675834c16075995d5c1367431527a931a226b8a5ab86deb844bb74b19974a34085c370dc5437e43b9c0f257b7048e0ba2b78a78b81be953befe49ce245f5b0d473d993c2707202af3b763b5e3334f050ed9c4f2f59f7cac726c4083110c2d89d08a83ecf35b69dc228e94e019656e5295baa4848e43df2e2fe889a602b91f2d2885c339e72b910f0bf1801550b7091260ea7579b19898fc09fd179ee493a4e202d35fe9ae4a1e6f11d2b5a9a8d53b026a0d654256fbec6d8c0784a7f4074ec853aad788711c2d0f64cb85d1d67487016fcdea605051462b88d33798e07eb4f87ef82ca30ee810954fe16e4fde9be2e1867b90deb9516e4f07befb0c0dabbfbd0ce453340c7dc2c18cff534680f98efe73fb8bb8fd3dce88076b5de6ec0dcd86e80fd899e0d1a5e0527b79110dace64b924b3654f52e361194b142fbc4f24f958316cc3aac13feb68a24a03f4a90a0dc01ad60f1ed7037b90ec87146480ce4db7e3e25f18cc35285eb2c1f8ac8e6182e552bd19cd4bde64806220ee188ae4f9d1380d023f0f83cccd179394c61281bd04339eccb343d712bef4e65b48504b92885748b38739145dadf50886f6da5ccf6b8818b48fc685025d49df31b027ad9a7b1e8b601620bb782a01eca1f2aa63ffc49cc2dc00c53f6222a00a711836271448c12afcd0cc331edab35c74c46e5a58658aebd231e8c573800eb83705feb3e3fd1877f0297f42cac96c650abe7f257d805db3267229705c4bb3bd45d43e6f1a5c222c4fa402bb3cd7e26c59271df129f903c1150cad9b419cf1a4e011e1e9982748f709411cf3dfb221b24f3e2131fbb84873d27fd9338e8a04479787332117891d45f5f0dc12a72c5e417d235af4f6a52671ba06a81dd145d725295804f919c06fcb515500b396c9b8313813dce945ec1b2d130153775dce6a3b4a88321e3d6101f12a4d1d54521b9454fe7e2e02c08f159bcdc77a20c67a8284b3c8c201ce4702d991d9957c4bcaec0237fdef0b97777d112bdb2e186bc1437b17d2e5b1101183641f1287f2aa517416aa08f8bc596fc3b4f61b93409c5da7e9a184b98290d0b6c247a5e2edb6ca4e402ce5353b46df270601d1110edfaa32e6a26e60725193550ae36a2404245abdfe3ccde5c69049a0307e272cc5a085fbdbc48642d8eec7826c8e29a39ed3d255f1f667d3aede7fa14d3d2665cd2d7fcf12bdf9c1c654baa59b72d584d2e72d29208ed43c92ed8aaa9b82fbc2d009e2de9a944c779022084abf17c084266b6f552933804088c82944ff93c3a8954352e4a3718ea17c642bdf6e76cc0e243469fef1de01a4bf6da0c8fcfa5c9a92aa52df882fa856c1dec1e5ebcb1878e92724923c01ff23514cecd41e5ad592cd344ab569e6cf65356e2a9dc7eee35485a0940ff688672202bf79cb3abca67ce1a56e2681920b8b414f0872adc25b967dd606140873447485860e52291c04ea7fe851e28997d2b6889c9a20d608fea304e2e265c3db36794d1eaad8384aa1a770c3401c205c0019ab9e14edb6cb3f2171f6fff0e8d080f2cd82b95a66606b982caa386dde09e37f8910c58cfc159cf795ac55de7106bb3445569c71201bb9ee85840569879dc87a67e04b17e809f8b467f811d9f624ade8aa929eaf27a5cf714d983d0a6c192008c32dbcb3a1217c1740842de3ef9622adcf1e24af8865713681a4277d6d24b37bddb217674dceb1a76579962511168a5a6a4d32308b2e5b8fe55991c7f3ece9344d98c484fef01b5052dafd7e67d9fdd8c08c02fcbe9320fc3128b517e7cc00ba52fd96c995ed3ecb9e82d225ae4311bdca6cbb93f7de932cbcf654dbf6c06473d6b26cc0be0b90696ad013eaf8250b707389ec7fb9222b13a0d8a15e0ee65c6ba9f2b463d0931832c2eaed36820c98841a402cb74258119bab38b690c4646567ecc34834850e0c369106d20ec16e6db0fa040ed44f9b34d555a42431983f2cee6c9a8254b9601902774dc37fa5a622f5dbdf0e57278a9487c884ee63fc8b8d292a92125b81f8c092ea46395f3ee56e7c94201bc8d426a4aca2a4c90a5cdd39748a627dbb8a453008c75583224fa51b7f2b0ca638611076ce0633646636b6d7cd058075331b64c2d675b7e2c298ff754c0417361b89f0e84ef83d7c3225a362f9afee0e2aa697853d53f89876b842fa6021446430e8d79046fcffd8321c4aa41a920db85e31104ef8143848f640d282838bb6f6f3e2268c18d7ec9e298c5ed54bd9d1735cb3b81e446775aa9ccaaf2bf1e680fc77b74429c224f23d6e4c22c325a52a4dd9591f44c7a77944df6e91f61dbdb9a2217c6e6d6ab1dc6cec96e809b1c5100a230e2a31f56939403a377ceaf3551c75ac6e515a79ba15f11fffe737691299e8ba6f76b97fc3d390b862aa4651a4c0592ec5a5a99515c400714b6c9169b8798c4cc5730859da55e91a99506d9d830a3d3101b999c329500f818aa41cf25c253d1f1d0e33b7cec3a9245eec106bc99a14ef7c72eeb1a441a0dbda2be47b768ec28e4fc8aff03ca7157235cd1181121542aba49bd4a7e25b7f1ab510e8284c91ace23164972889a1267021214c43e0251b8d3d9120486fb37d7e59e1cfacc88de7cb5d60ebbd9696bf80093c39755c6dce39cdfb201de0fa1b22999593bedfc4b4351a2f6d9ccc053f9b001325ee25b261225f1714aff534d10519758d905d009807a22301bb39f5b2a95a3e94474799705cce5b5463e4b2343762f6477993c847b3c5f196d1dd1b3aae09826d2cace847afe8cbb11f03ce78609ce10a1905f28db48cd539cd2139da932d03fde565ecbc4921c8e9fddfa6deedd94a20afcd437b82633f54cc802d43c4eff00728a202c99193913492e9e3cbb193d43a2407a56ae5cc6f362f0c578ffc6ef696012c307344edafdffee8516dce99a14973d26fff7d9808d7f35ea21ba13bbf3dcb0009b6589527f0b305feea82976d5d958b319ee00a8f00b7ae422480ed677c5e7ab5139fdb6ce83db1290a802b523b0f9f4f14d15bb592f56ed5339e8ca71f8bce2ba08ba125a11ee88c34855c7746b54acbcb27458d744ed0f49d42df8ee3e2855d6bd33e449cced0d19adf254edc7cf058526206f161de777881197be47e997d211412945750a6bbdf08fea6ebe5a65177d1bd77994790853e97686843147a29982583e66915c9072ee62077442271d71d8d098cffd7297c47ae8690cdd55cacfa99b4596a866469aa213cde0ba255ee23cfb1eccf617923549dc980d7461c206d1907a517d7a14d02bb711861df5e535ddd1de652de1681c0eb34009673e67916a84bc23ae9efbaf996c5b4ee45b167a9e1d00c38b90d48a1816fa683e327f7c280ac301c2ee38cc1cb7c876438c6aa98d17a27e20cc30f5d2e0e156c45d62ffcbc61b983736c20481b535cad94f5f101d34cba8beac52f8f9136755d501dfde6214580ae647d8e2aa48d1579e80b08fbb92951f8cf8c8f4713f040ddfa277435c4cc0fd8bd17f390dd8af0b600452b8100e01376c38b14dc6de3eb78462bf991150c4126488d86def9150e57c030346496256026bcac99630641582f5d0c13560d201ae545d7116c4e576e0e76105ffa47b823d8a01bdc399eda18215c50fda673ead7a0bd378225f1c24c397d08451ec39c81bbfcdf4b9c14565217c29b988b71a9c225f66dac7e81c18308a0e9d6fa38d14cfa27563eb8810781f1b8d28f0ad3530991ca247d5bc9bca3cbc7dfc7f2418ed6d7c716c00b6beab6bbf8bc635d1fb8bfbea335f671ae45995ece2e6119c82edd8059bf6dc3531787b50b5dcb49d6e5e3c367b3e035c5658b92c443ba842d34f84b1760bb07974eea03ab53cb323fb864c7775d55cd4f547080ed70923b1762d7235d3efe84e23f5b735e6a7a3e5824554888f90327313a03eabd904bcd80365f52a92845e6d4f8fcd654ee477377dc4891483a91c86e11b5ac141b2cd40643775bf4b3311fd7950206fcc16e83d2da2ec2a5bb5abb14f6812d8a03f7b06f5cad0e33b8bbb13d511dac360f6ebd5dcb57ea8d24c14bab71fc82d69f9a7922b52e58183fa95914c4dea9f92b31130c4728c6a0a3579cd819e9c7e4522661ea737de03bc410f8c86f24300d9536139b81842886494103d9efd611c31bdd2f6dc0c74b80306842b221b820c0cbf7f7ed27dcd755bf64ff6d1fe2febcfa5af7c7041f03f929ec9bd437db67a83fa47eaabed27d6bfb69e813d037d9e7db6ff2f811879f559feefe69fa14fb0cf459eaf7d3b7a81fb12f55bfdefd65fa24848f60f96deabbf50dea8bd49f565febfeb23e8efd14f44dee9bed33dc1f29f8a9c857ba6f4c3f8d7d02fa26f579fa4dee47dc4faa4f55ffb43e8b7d02fb2c8fdfeff906f703eacbea57bbbf6c9f843e02fd36fb6efb06f705ee4fbbaf35f9c3888fa19f83becb7d337d86fa63f6b3ee6bd5b7b69fc63e83be4b7d3ee73729fc88fa59f7a9eedfd667a1cf609fa57ebf7d83fb81fb72f7abdd5fe67c16c047b0df67df6ddfa0bec0fd69f795ee8fe9a3d8cf61dfa4be993ec3e28f34fce4d40786fad0f4a7dcd7babf7cdf9e7ec6fda6fb45f6fdf4e3dc4fd5577a7c63cecf439f80be497db6fd96fb11f793eed3d5bf6d9f629fc03ecbfd7e93567834e27c02b3ff521faebeccfbf4f7cfed23ea2bba5f45ff6d1fe6bed47dbdfac7f471381f83e3fbd46fdb67d417513faf7e5d7d6bfb28f629ecf7d467db67513f667fee3e5de75b367c1ec2e4883c9b270849a206df4037b159f2254b4973e28075d3808eecef50f5d9d35f6d7fe3fa44eb67db4f729f8afa22ee5fb63f1ef341447c40fad1d47f63df03fa0deaf7d76f6f5f65fa9def27bd9f6d1f89fa2aea17b97f5df345b67c88f483ea4752df15fa0fe8efb8dfdfd88afdfec4ea010a8865505a304cd24a0733f40c74ddd593650fccd63ab3b337cb2f2000e204346424ba93262b02c6f1739395b5dfc7517284332657c030101c1d6e5785fb4f4dbe731454f443b58df5e7988c71a9987bf3e83cfa9290bde5de7b6f29654a326505a204ea04596a3f3844929f0734738e43afcadbd65dd66f77b23ae6602bfd1bc046a82662118a89abdcdf357e2d3e107a0a44989005649a2488540113fa40e8d6382f905731e54abddb4bb783087db80d6180c11dba42374a183e61679717d3d97dfcbceb24f7b32afbd84843bae43cf03bfdabb2ef68fa9d46ee40df5d16105567d0c6ab5c3275f73b929d636fd317c85f9234bcef1d1cbefea7e77d70b8e5da4931bb78b44ef219356a405dcf4ba0ef9ed33e6e5b94366fcf83ed1b49abd6c79d8ff27bde3fed230e5faf1f1c5aeb83718c9a8d6a256944dc837770682d6e59e57ebd2cf7d9a8efdfd6bd79f3595ed82e54dc4a1df319fe1d8b3cb7e90c62f6aa2c85cdfeb7cdda304750e69ed6eee58d45b972b262aaeaa5a9a9a72a3252576882be06f81424a79c73ce9bbbab8347ceb6cf3f3fd9679fa42f6f8ea09cd9ef0e9a9f43fa3982b27f9c77e8ce8d7b1e3ca48030f4429887d00f611e431d0e4db04272fa0086911cba11e63766211d3cb2d721f3d08d30a10cd329a4690c18342b603993e4003564deb0206508141a58ff1075aa28b1a932051b1608c0a58632376031f3c60dac7fde0c38183dc731679ac86de74f2307a3905855f9628314501410858f1e439e3451c10f9d1bc90b1c2256aa18e9a124842522cd9a224ebad059d225b161c7f20c0624b9ca37ccb4992607630eb7cfbd24697c604a152a1b9444fd5801d6df4c9246047a706287ab237494b6c0fa3bd64a31073bce1d10bc30c9970db7304b7c880244098cac100636a74462630e3b26a7721480091429c8db091318cf178dd7ce2c21fdcb24f224b51ccd106192b4ede43866054d0c8862bafb5f6dfa63ffd6ffd2344df33c4df3bc269e17f4b296db26d7e379e0ff7c59cb45d1d6da4c11f39b5d8e61cc04f186db6846a7e5ac4091a205c70b1c2929a5947213001ccde8c43500521c008ca68680b20394f5f87977b77f6fb9a57c7233ddb3dbb6d19919318b1431413345ba64568e668a50c9e18ba026122a6a054a8c80c18a9438b07e33059226394cfd908187beead6b6984daa1e35da0e41685e8e627628c349d59fa097b5dc3675b02c92a270701204082a37725c3e518131424e1534fc60f2d1769b2e4d4a29a978a9451c2126c80d505f6e900293545091041a226400628aeca25959e1041a904cbd81c9353b0c31c5143d748822881c585448a0208a2e3d40612487144e40e3e6489928b22ccbb28c0b97258430c35402364fcc4cf951c6ca11262e4cb1022cb287219afcd76b6e1a6db9dd36b9254be9aa000d2660a3841a27264e60320e1d2c6ace006992260a29a5dcbe68f14018345637045124cacc07ac6c802ac114a5364aa2a266d7347b415423a85a1635b65ab35a9570c1d62a71a82facb0e40b9126599cc0b42544307981489a372ac852022e48f8485a63822c53609a10578458e2480c8a0a4e93c733edcedce236b32c9b940e90a5b4fed72a628ca66974f6b0e69c934e3aa3a6f7515153c045d334adde609134c920c40714aa24e1a049851eb4bc3901489a2cab5e8f9c74ce1ae49aa6cdafbec0e253020d74e048191264cd189816c48618ca34e1c5479536b5d65a6badb52ee18305a5934efa53eb1525c4744e8c8071c3062acd932e300d4e0b6b9c50938316261db45ac57c9a18add62834adca27a9a6695aa5d26a05ffe7cb5a4ed3b48c62c0c7171fad879681e2450a94116aa8ec00a18304941927374328a1820ae650252186ea882f564a507a12841346e4103135b5a06d4ec9b22c6365599665d4860c89cb9b17ced0a044136a58806552ce9c6044082a58d2a040ce962a754b0a4fbc308133c40b9d28b54492113f0831a3a507184d9e9122843cc19929d6922398f4a8820a26638e80654f58a84365882545a4c8b22ccbb2d7192772f8643629a5526e9a1694c1a1370438ace1020a413e755b39d83ebf6ddf069f3b0c45c8e738e8569286947218fd383a0c2965955b9209a554ee977229cb259f1b7a9d707b20faae4b3b296a2f71381f68bbf49bfb6da3ef52339523941aa97c418e506a9424c90ffb2aa94e2f7eee12e873ccedc89fe776de3027638ec6a59c8c3f7577c73e04836a6430a806d0cfab7194ea90997ea42f796ecc9a4dfaa0d458e5f8dde0c11deb62b071ea87952f73c7a28c3256fad7720a1bc6a910e4eb652d6e34afadc62b08e4b60de8b91b6e61c772c4a9f81d510c74a38351cafa523e91e4441da8279ae408f544111a394239112477ac577c47a70e9d39759bf7683e5125aa7528a82f98ef434495a8d63ae377a47d47f33bfbea6fdfd1f4ef3a84ed3b3c1ddc41f38ab9c2ca67acf8ee9fdf91afe076e882c41050386122888e092846baac0152c6cd6665bf94c2ae884764f9fa3a70e5151cb7f9e69b7c16ef3894af75dc5df1fe1d693173dd8ae7567c7f3756fc8fa464261899dd17902526a23bcfbd87f41d87449bf63e40dfbd7feb4607c356b8833b9fee67d6308e1dad07fbd0a759fe107ded391cddd3ace1a1be806be11d9e43a4cc752191d7f73b591fa9bcab0793e3b8797d3e7e9cdc88f2cb70870f75061bfe1844c4452aa25be3f4f199eff3f43bf2f1b9533e77b9a15a5f7bbfb4bb317bf746d23bbfe1a437809efe6703e8e977afdd2ebbb3bec61c87808872d7643bbb5ecf04d3126d49e0f559f61c4f7d1bfabcf73bbfc3fdbc9bab074e941368baeeb91bf2c8dcf69303a4ec2e458094353c820064c7f2257743ed5b7ccdbc7937a09f38d431f30816f4e7817cc7ae610e9032c5dc77db77d72ff74037d49ef5f48b80cf774f3f0d3afbbcbca13f873fe7dce73bfc7dfc3cf0790ee3f0f90ee3d0ee0ecf126f98f5f2ebc0f5f2fddba0074f072dfed64b1c7ad3c19d29819f9faf3f373421d7f9fed56faddbbb94797bffa9dfaa2fe76fad2a792ae6f916cfcbcb83e3c4616db57e5a302de89a1c7fe3161bb8dedff58ec32e7338b8cf3a787df659c8b9d721f96fde7d7dff8e74789e9f859ebbdf0949c81b100d4520bbf7f99f8ff135bf756bf13b3eef9f8dce3edfdd987f2e8e1d9e7df008fd74669fe190e300c9aff6db959a8b9fd773f7d3f174b072effa30b3e0daece2b660fdce77d4fa5caefc7add9facf71b6eeffaceafffd70db7fcfa79438fe5399fb638e5c5ac93eb294b17fe2c16efb28a2aaa98922c7ebb3ab4ec58c7eb22e5f81db176785ec122f3fa5bd18fa38533499a5853278d970cc449228a1b27351861c4d005258cf8425776d66ee72b20420879c2440569061de6a0b1a20414393d602c928833e48d8fa6285e6c52163368944e000411b0f9724aced7aa36df3656d5fc67d579a5b7f9eb54dea62f98bfc9779657c579bdcac1f952babcac4d6e4f6f1894a95c72b0adae7ace73df412cd0876dd559248d8841fdd066296377acc3924916f1be23df01a1cb9c4e7210880f84dec8852ed7dfe119fb61e9d3c7e0d21fba34eca770dbe6d7ba5da775e6959ce3569d372cb7772aec550e4aa0dfb60f81f086e9c6b3f56cad972efbf3316e8fc105faa11b230ca10b04f4da77ccc5836d0f0e6db883ee609aa5cf6befdccf2c310e1f1ceea0b93ecd0e8471d4ff36a81807f7345b7e6497508cda72c3961ab62cd902c39c73729d95ec5f8e515b826459963535c1a265dbb6a62258ae5827515890b03c2c2ab4bceffbbe966d4a8ac2e2c37af2ba763c79af3cb1b3b3c393640e538d1fabf65059fe459afab3f6c4865bf62f43ae88e1a1082184b002f3236756e0429c16e220b982f98be04f02ccdf48d2d8acad91b7fc2198c31a317ec43c620b10e6f737e6d13f3b2afe430859db41b3d386c1fd0591770d0d881cf45f80cfa81de7e1bfdb87444446e1e631868394a886cfd026de417367da78049a331ce4a0672c3865da6e6c1863fa077def0ec3df3fafaf64ee98be9893e2707e36e76ff8fdca9fe18e2cbb2f40079d66d9a30e506849d3e6c89724531c9314b2f0104515228cc0fae30603a57f8452f6dfa08e8865ef9cd8f9928a871ca1a8b8647f05e40845e5e3e3f705c318924edc9f07190b33e4961fe860c4fed6ffe51ffd379f53b2cc764d2c0f2121301e26b8688049916f42cf10b0d6f38874ac9e96603c4cc820aaca13acf5266429882201ac85a5b4e8406aed7d903b77ef3efb2e647d76c30ff2f7ddcd11c4ba2fa2b0dd7b479d3ff78e3570f0bf7f01d6eaff7dd79f0dfff94632bbdefbf4be591e8680bcb2b52d757158cab1d13d29c7f69304264b297f56d6c86ff8dfdd3084a38a3b1686c00e9a3570b0e36dd141e69fbd06bc7e6dcf3be6e06f5e15a125428e0ec838d6e849be671b7fcc5a0771b1840d5dd18d0dff45772c3e7d70817e230d58deed30e7d49ac7e4e1cd837fa40f3a38710c07713806a96cfc90088c11e46fe42e25f63a5b4903e904513ef810640c1418a08091f0020c47201142030e4eb0feb839129bf477d01514a9cbb5f4850737534a51e918981d62b8f2c4253a91692a3fd09e8fb1e8c5ef7c8c4503f8d6c7584480a202bccfc758047efdf9401f63d1018a62bc8cef9efb188b2e087a0fba000132621cc00030c0021060002f04a086e7fbfb8458e4ead13e62112b167d3f62110ab1e895422c5a118b5a7c7fab108be2f7f70ab1c882ef6f20b188c5b78bef6f16621100bebf5b884501f8fe16128bfe3e76a187f4fc0e0e9bc84e91d6ffe0b08de4fe791f1cf6119faf38ec1772ff04c261c3909be2b09124e9a6ee391c760cb93fe2b065c8ed386c25b937aed3289000aacf4f6ba7c76219dfcaf20300001751860537461937cb6f71b72ccbcfa40cf9ac2bdf73dd186558b5795222462b39ee4b3c5cb50ad19d8874cc899494b8a4c5134024f46da5946d95fbbf338879e889be7fe2041009e124d7814d9cdc763e06778b30e6c4de3f7cd8fefe8ab425cc10273a4b6c9418d11f99d858774cc66e89f550f0440ace0c4941d65880029b14c440f5a64e0f37666a00b2848a26ac86e8ef9458346037837575f69b8793cfb574e7a494dacb8d7292d229bb00503090a08c0c52e0a024ad5c6989e3a66acb126590705343ac4a0990334e57983001153fe8505501ebaff646f7daf67c95dfd1fc4e8995dff3f3caa5a51b1a71b763f3473255a00f5f9c2ce264fd43b9e41f22e59d8a430bf4598648b1bc23cbb6fb8ec9ee7770b859e5aefb1facc476ee61f219ed33e6ccb288cfe8f9f69e9e9e9e9e8f30baf7963ddf15cb705ed1c1dc8a3bb26cbfab92c1daeeb76077ac63355a3f3eedee719e77a3fefccdca1287a59483ddc34920240df9f4c445667972ab7eb76a61b7b2b773cf0d659adcefd59fdf545de533e0d8dbb9d5752f1994bbb08655f49895dc36fb8343ebb381396cab200f1b38d2c4264e1040be046103aa870f609a9c7c597ae2129dc80ca579e2248e1460a04002e204993628cc6026494953f901a44b6afa41ab364f4a80518eb70a0f80aa21093a4f7078220858af19c3c313535461642a4c24d231275252be8fd5b2b6c5fa6acb1620d4fffec33cbeaf8f04f36e0b10bc673d0bf360bdf748b02827892338d449f2420a563008a8206502272790382209587f65ddcf637dfeb15ad6b6585f6d59e95875decd20aaca53ee0c62aedfde7fcffabcec6b56e577b47d5bed6dd6bcca41a7ea577ab052cfbb115635ed8aa0f3118f93ddc9dbc7316474c8f1a3802ff910c1c8350624b9caf5b37f073b8c91bbefbe3a9aee63ce32ec4ae360ff77e4e2b5e1171a8652bfffc938199f72327ee5535e45c6ca1b83e6c8d9cb5bc129cda71c46bf86c31cae0cbe00c2fa87ffdd182b7f66cfe1ca3eb374bad47903d8701162453e65fbaa9af7c56c7ac7c98a51464842f60f73b8b2d328156be1aa66bfd9a419d36c524f21c9f13b0a0a12522787b249c81c19450c5304c30210b9898ce23422ec5629e7a434cb6ecc974e4ea37dd26cb34952322cb338d88fc2c324174f40bf36c486b2c98af462ccbeba74f2194d7c463635db3571f2196167b6dbb8387da3acacfbda79d995997adf0d99b39f73d6ef86e7653c4e36fbe8a0772346308261df68efd84d1ca30c4ff2a7281aa224492b3ec3712b49269f11f1cbc130168cedbed84e075b3b281bbfeec91a3995289d172bad388d4d765dac9228a35fc6102fe827eb5f35011038532ca12a67382ca1aa95655394d1dfe560c38ec9a6eefb59681390b06e1a492a95c312aa42c71443517a1887457018f159945095e787ce941dcc529d1c764c36e506b3344736f98c2cfb0874745688945be1083946191eaf72c7c5864831b6d8289f5c606a8445d84bfb71f00f8bb0f8f625ff05d838042ddff3a20c7f0d88976f481c8da82e5e64eb606c3b9164f79438678c33e6f0f28c1a55966919159ba96643d554316e485acf26aafc5ea3237cda0226c767e53886492a1f2d4d71bf5becc8f43486a986216a74679240b4e0833365d5bdfee86d1eb12c6f38a3dc91394611c921772c471cdb479e788a117295639490aa8a00970f91ca9e5d4cf627f21971f3aa7f1140f292b718237ed490aabce598e9c7efcfc696a9fc4c3469f45e514b68b2ff01723ce343294fa711df77de83b2f3b55eedbbfece9d0ec3aff63b574adc808df5be6291f711a9be1769c4a1d7ce5e28021372fcee3fef632cb2dfba31cab038ac51a3114747df52ee697d49a38628e5da8102b287c3f85a485fcbc0c6a8a5ab2c99fbda5f8743241a6fd839d2cf06addfb75adc53eeed57efe30645393ead1fd2d7b6cf067dae05f7f46bad3874efbdb07e0d69ad971531088a72fc8843107fc7966394a1bd76351a5b77b26ed8fd7c59bdaf61fc4ac4461cb3e7ddb0e2d7b08bf83187afec613742bfe4d778832e783d7bfc0d830e76ce6e0d079d4a251bdfb1c718290ec2313ec7683bb7dcdb12666e61e6c7cfb48fff92c6c67d7c0963b3afcf11cc3176378112250c0bbe8491dd1af46a00c548c2e87fba8084d1df1dc56748dc4dad34a744e827a13f840e50912ea9a021b00081956076d02c29cdf18689eff48391cb2f399cd1cc0f31640e58a9430eb71c89f0724c2205f20a1c5c8596225cea68517a2f6bb945c4314a0b14394605901ba824cdf594414c32e70c01000080004315000028140a0844028158300b72204cfd14000b74a63c62582691c622811408311005210c40310c03200c020c32c0200529a2dd00b5141f2dea4b26862c5d72b1f1b48ea30f815acf1a6ccc567002db0443d31b35b685ab8adaaa94aa5229c3345961a58f65e94a5c02019403f48b5dc32c5b9697e134ce1117515cb370790bd7d971edff108d19282fd573b4bcb25072d94e02bb8c12398223c5d2f5e75de0cad0bdc5ffca020c57d0731ab802d0661ff69a906fd9aa7156a1a5b7b50a7cc0f8aeb22c163a7c129ea9f824c5c58d6f71311e94b2df3f288c0817ad79e1b1f110f655554fee15dc38dd0f9c547ee2df8fe57a3bed1bec0b207875f17a84a1a44e7de4c136a917780c742960366526be435e9b100cfcc955448322301cf457ac71d5dc88667d861085095e2ffc5c29fe97b8aa1ac7c25660898e5255c8b6de97c843f2e51356accc18feaa980a7b05109eb6717d58c6c90c54b9d10996eb69b7b88dc1907d04d21d7b8e77278316ff942151e709196074241179825bb2e8f834a3c0897d7efc158489af3fa7620851e780173e2bab7c73e480275b44188064272a5f422e0e8976551d842e521a18a3ccb196fe77ef723b446d13b14e76214f626b7de9570004206332ffeb1f82ecfc8a55425b2414cef45b4e2efa92670944430d1578bed4d9ef0b165b5c450d4b06d2ec0dc0081223f40d32ff8ea51f7e12bf703858df286cdd93ee61a86bd5d90511b85e7abaefd2f299790bf1a11fca4c252688df64d01f6686846873836cb49f8970e28d9b072169975b16ca6d2d5e8a1ed0bc15e766bbd53c70502e0414b58f35dc3a79c164bc796faa1e59201ae76c705fed0e57b91399c44ae98f6b8acbd3804d238c8ce37510b2c4529901bb856587e2ebd1e9b6583c2527bde6e1380adaed2aff5e84c2a216bff93d9e54478d1b3783fa02f77cc919796b88e64ba354b3439a07b7934eef88f27b7f9aff9dd8b549b153ceba393f1489ee70b1db3fd844aaa19d802847b7c0710882ee9b5790509b269e3152c556718bc15ac9f64845ad0ef15618dd1c49445051798ce585444fbcd9da9925085800b5b2404f91a15578f93c59868d5b1d6b12aa3cdba228f7c4bc73134db156408a5bf96c84729a0aa9e938e2e4f823a9cea07539d4459cde4c09d5af96edadcbcb65664bf8d7456c307359802e97c7096c9616440a59fdf2b157667ae7b614276ea2d5d09e1b8811ef51f9117279693a112e8443b1dfe8d66495486edc03212b81a184ab15fe94ec353b0ca2511173263eb294efa15504a8420a775edbf3b10652289486b6c421bbb607b822fd3524412b07a315addd101502bd7661fb125066e13942054dfc707d4a51014f816cb9c904e7bc3ca1f5269b57b16f07418d6c669943abc9a05a41594dd9e66f2c3a7dc45277cd2c5a8b6b79506c81e1a35fe1079433ad1eeae6ed1d8b2719e84c73601485c77e1285a5e5becba775cd95459e900ee1204bb02417c4d5ca7a2d0b7d3810a77d64793c74e25abdd6f12914e291d8b29376ac95064bcd97a8b2b37bc42453ca123501640bbf6ccba996816ef8edf4ba7770c1f14a55575888161b3a3a944ddde55a036b56190ee3cfde9ad6c6166905e100ba00b4cc047fcba653f03d9e75b787f577a499b98e09bfd7d9db41b3bb71c390a000da38ffe054e608c8be7485c8ccbeeb51134422a1796ede01f8ddbb9791345324d3433c4f815d88cfbfac1c771a75d1b166f1eb0cf2600c9267eeb7c86b095709b22536cd78991ff5fc5257af7770283be99f414c0616e946ef1a64e3ac89580228760e1000c73513018c8c05f146030bc5ec1760ed15fc6d81d9a9928cf28e5a4c1ab7e0c805618ca81641074b8d9dc5d5910753b43a1bea6cedf75109edfa2900dd133c2bed05e7aeac38921f9d899152a61be443c2f34810d0942f7ed873d89642d0e9407ab8ec54d41fbd47e69f2ea92e462b23132af2813309f739f36e77006b35b0604d63e0a9393df05f1a15dc0857eeb591c6b969fbc3f901b9558698110cfc92a3d877373045104d665a488c85943233b4209a4162cdbfcfa4c721c4a00166d8e9026e65f00d7f4796fd69f998dd232fd5ad1b1cd7b27c6806d164e065ae3d37898f07e25364d6043f21b5f0a6043b3886b2a1d8141e30254393dae94cd6299daf5c6c4ccb97f3d1e242649fbaba33827c226652704d6dbf6a105880966432c003844b3299c29b5afe401694759d1d838b9785b927bd1029005bea8bb22f646a2451666c060a7399cdac1f9620bb33d4089f2cc127e28c7654cc66e6b0b968071bd527d751c4f7a1f4c69098a48d44eb86c50a9cf1a2c6ae2e3fce1ab8b8c65c275d40c0ef41729eae4167c6a7465038d834c6051c0e24b4977a4081f9a1cf362e86ef91149510870799347e76d3ffd0d5674c2ae7b3480da255c70b33e78671dc80549ef478c399f4fb0a0618040351e0087c7639dcb6b9760023147f088e70fe27e86d7d9b403777143912659774303a96a4cd0671d87fda3a126321d6b0c73f16f24b3a978c5508d2d6b6ee7620ad693082c8340752f16df52ebedb37ac26cdfde4c5306fcc039f6cafd6bf066dfb61543f8b1504d92f2ba980a260385a4091aed1e753c1e9b905dde98c99855e69b6b06285a9ad3f90ba3f3cd289b2eafc68bd8164fb7a7f9a8b0c16f8567590362b69b62eb02d5f4b28aaff7598de06bf2ea97f1d103b62fae6cce800ea2fa5b793ced560655482c325c5bc3388b2ce029321c4260b7246ec4bb34b58a77ed15ea64974fbd25e877bd33fda223eb4f7c368beb4152e26cfc895bd37a72f58191a8fda21aba68388a6f88d7c1b4c29f8a285a47feb8a51c8b584c68d587cfa47dbcdc50071312413964d0872b28bbedda55d652d9bd1e88b0e63a217de65403dd20297a2bad5ed81fa1495c6d58477465655307279d169c2731e7ac6b610778d1bb96246347bb9b9791403c41758b145d84c7b352baea8df7d9e346013472662392820fc32051f69849f217ed021c016f23f41dde4894e5bbe92a2fd4232e5a356d21f77a1a8c087f54fd4dd50c631184b5e0a0649acc568379ed8a3496876c367ed73cfba5f5670d0a68bce2d10faaec1dc2248cf7219992dd1185ded886526fdd020edb41727e3ed986bd27b1a4d25da6e6b6c341e6e924731e1bbeb5893fa6c12e6ed385a5bef31990119e11ceb2fcbf0f033a43ad5ef4e55818909c82c106a64709e0d778c2335a9d0e7e6b4e30202ea25f18353c45d919ff78a5bebf3be6e162eb3ac30a9fbda84320dd8b4b3d86384ce5877028d4dc8a3bd8cc6865df69413fbbd532f4e915678fab18545a0fe9b3ed26194a4fff7b507d7e1789735a3ac318d78326bf567d74d2fcab0930186ff61f16a840dc6657f290f85dcbb58c62359c92210456c1bd0d556a24c7c0632301e638c938264f778c03803d3648ab4c0e30b4cb9d832631bf3b38402926d9468f20f0cbd5a1aa345bed8db6e8ad0ad53161df7011c8d054781816f915360a69e44437ef6bed573c2b6979d5de2fdd8c54765aa36b84e76d9895882a7cf5d0957f0bf646499a0aefb32fb2853676cf4a9e5b36b74b89c323122e410b5160a4c296a711b1f7a77d11e29433d5e32ebb106bc29d16421903a63fed159a288d6905ec0b1477d0a9bb008475da2291a11f96bbfa81a6a5d548d012729423160eb9283c8ea06061af04e999d78b1456200051ebea41c46009db795341a250b1f76144870f65f252ec662f768bc085a23eba6178a7dde2d66eb764648e6647e84897b39b132b9171b98789ce6dd5c9386ceb33dd1918774f9392cfeeaeb3947d3fd8a084a2817f67f4df65a981d3fce81d4d1d650332e4bf7530d842a8589d2236f824d4445cc9c35f0445314e29b95a3ae52666f54209e9151fcd100a606c0fa8b24230708e7a6c645ac77a9abfaf564d2334b4183308c884a5d87aec913acfbf84a213bd2f144f04aa3e2797b1a57c55c4df9722e2a1d69463d1333abee8008654b2881155aa0090d1a25a9a9359684010a31253b421d22d430055e3b6f5d414db28f06557eb9bc5b48d7a8c0adae2249dd48aa0da4c33c74c4ccf579d1793399ec9035ec800ebcb7e6e9a6509d539ef4a47a7d54a9d1d0f217ff39a0ddacd767e8377da2272caa779a9ec76cf3e50329d82753efd9f81c65e39304a322cd7b64743e93064a6db0089d1550244117a731de52b4b23512360d9d53b1ca9658039ae7b9fe067b9a1c4c573d4cdf526614c16d44f0360907bbf4db38b129601d66f4c30932b5752b1b0d6cb78f1258cdca1551d14855da84eb587c88447ef9b496f03026dc9e5adae49e22322a0d9425d60dd11cad1a34c9f9828dcd6459a23a2064b159fc221cab589683f98aaec20288e5c7dcf38c480238ea7d11480e8f62d39000c41d60749598e7b96a71d6216cbb7e009ba61c62672162b3f4fec17a88631af3c4a283d7a0a54b71ae353c46c0ccba22838c4028d54b9e434c00a6ea631a6a273d36389d9d3335bea9c139dc931ecabab373e8e8d845b2b2cd14caa4801c72ddfcb985c4d82273f3254c7930bb80e81d6885465a2c0cdba13e06f2e99f7957655ea681843eb13353d3d39abbe2867a844ca9a76e563d50593dfc80d81fcc844f46996168e4e4e02d159342d9db6018aa83e8d36a79630c7fa647db8b335ef544be6cedc17095eeb9fc9431273c1136698c4ed77e131ac564be15ced703dcdb9b258311cc093091154425f323c778609b7dae9b849b4ac911e225bf06002b2991be18b7404640c544bf7981f9641c67df839c6c720153b7ab528ce2fab911238d63397819aca31aeb9f5fb2fe9f0654d23e6c335d00b39e34a49dd87b8ece8a1d6003fb0f04455bd09fc80f98e97484a0440e9f12c968afa9ba7eec1c174e9b69d01d0e4e0962e75ec6f1ac53aad914fa7fd2a70de8b5989fb0c01e4fc3e813c1dbe8f6e052c652921f15f2dc20a5c7e4187e112fe2ac414aea3b4024091ff4a56bcbdec22afff3544aa3c0c52ccca22ea1c0d422786a1b5022c51377eaac9b4f9366a1d111c401b6e71e9d451b9531a599c89362ee48ccf29e6967148e641f39e1c04a061036d51f88e60bd410bf228ed58ba7c55ad63d7e8a282d04aaea60a503cfca2b18cf5c8b28284355c34a8d267f0f64a76811123de8882a87dffef07d301380a9a43836e2d335bc04a8feaaa41bf72ed75610223f46fe3be19894fc85167209d55d67534ecac0c205a67233b2d3665e684be0458dcbe9a6ff1a17089a405f47b5dc3990436e5c86ebd00f6820206482e7f9015bdda91002e825cd42e4e7183108ec0bc950028adcc8b2a8c9bd1cbbe1bd466129d59a3ac619e27347508c371479118a01be50cb0b9c4fcb077e5f94b7ddf95c4c13300a6fc68d1dbc06a6c29a4c808cc094c941680f42b08b5ac2f2f37252659b8cf76c39a561c5007fbf5f8ea6096135224dddacda08587ac73c7487a3cc1d90bf3168c9962003930ef7b4584296ed6774405c1100bf6d0a1480cc738ff7e967cd3934701f0f11c45f09d81892d71c82ea12875639d7ecbc02286328b4192ee1a6bd8913b1f0ef86aa17ce1968731f9bace248ba8ff81b6dbddbb8afd7f4a4d0f261fbc1c146683f64f0888d8fe0c0f124ff87aa2c9f63fe17f242d7f6b97084e99bef56c6a10fdca72bfec0e5851580b8e7a493107f4d0319ce468d9ae590d958eca211408498dcdb646c5bfa884e03cfc8476b229328aef6abce82a213ae5f421633106094a6fe7c246ce095c307eea0311f8792e0ebcf90590846844ba0dc9711c3d3810f4591a898b7e53d05a266fa3fefedafb24ceeb2cb1d27efa513104e877511b984260102375eb348f2ae399e266f6cf421f751e779e89fe761120c7c2dc226ee079fca01d93ad62782a4d1b898d8711acf6e6a0da7bb9144f7b731d8fcf0aa40ed7e55348962c6245dd51e85fb222a631c37355c0a14f7ee77a16dfdf9ead05c5a64b1e1515cf4a3ed465234b9d4d675eaae904001f4ed4c387ce88353d429cd7976a37ea8a6e3dc0907b5e3d1a1ba3336d13c30812cd41a5a677a66e1ad722f7585ce8434566bc9140a5e785b6d116e140b2e686c3c2d4ad028d817c1802e59659556370e01a6f62773dbac67dbbec24d46513b5b8e3020e94952d78b404b196277445ab367ed49305a2b837d3cc8c1b912c8a4651f8760cdd1fe00b7e4e418be8a4dd94d848bf58a1ab6080349001ab2fd2c023803a9083668eee92949ac7f770d5ab0a1c6522b3b38f3e8899fd31712bb0e90853496a584502c0465c0ddb898d1c5055cc95c2af76f52c7c974dc135749251420d89acd89df5a26d8a8a590951ffafab0a9e16147ee72e0cc20ed49b649be2248113cbe27616f914549c035d549f4b21f249f76223ee6c7402bccbe2922d9fd785c28c736906d62e50f1f4d499325ba3a82761422f7ab002f5519cd8d93dc184f959d9d49c3244a90709a31700e1e95c7a5ba99fd51c76e6138dc14b37d697243b2f02e758ae9f22a0bedea596d7850f6773cce34c7ba109863c4b1c873b20d40f7da64999b89dbdf73d29bafb11acb590c48cc573ad49db4480eac1202df2acc03f92e61cb8c3eeeed5371097b548f126f6b384cf6c277e9ba46138883d9b18741de5084b811e1b79248cf0ff73c30b12dc22cfac511cc3bab24434ad42a2aa30c408081a7204380a12d904b83caf2966482f12618a94dea3b847198acb9877429596bcb33a449066139cb5d1d5ba8761f859dc943d6a72907f4890501fcbb398d9c03208eef9d90c06a1f64a271feebd41177184de371c8b35a860f8d2d24a90a75d96a84a017ccad5a6a23649d9ab3c3a324371918e03b808eff47306ff5623554c86d5db1cfd22fb6d0d6bfe4334ac9c4018d9c1c09dc42f89493bb8eddac69f8101753f98240179155783a78f6c8c2171f07c634f2d576e89e3b46591cfb6303fd0d8fd4a5e13446fb806ce78d98a564c992cb07bd1bf7034dac2793a5aac67375d7f73aab53ffe45ec997c21eca60ebf1b2cba31950cc761e0f55153a4a8cf039adb956db303301647ed849921902a8cf1b58e25575bb01d28b13af462fccbcccee3b0e511173b44583c2771e8b4cf390732cea8895ba77ed671f2ce6a0c7e80ef9728de0440caf1cddd0e5b3f3b40f07081599143f1eb59ac063709db8243704477b0ce25086c4fc45d08d67ecc042fb697feae34614efc211ce4a69a4d1257a4ccda7255c186dea5126db517d6b43ca74c6b7e0021c408f984fa48c24ba6d0521249dcae7a354457a8625edf03328a85abf489a1748e8588e72e819a5f78051691caefe8723b9a0d068d1fe2c6b4346e471b530b3d02a3966df881d0ad6dba266dd7d069aa47e475d14a8054a9926b7cd1cb4082e9026c94a70466824473c260bae799832b9aa289609c50339859658f023899a806bafa9b51c8d0e29dfcb3f857e76ba1f578a4dd2c4f19e870c54ecbf8abb5e4469f8d09b2d09349ed3b68324d7c1bd97c8f227b7ab4516ec5be0ba4d07cc76cdae16ea74b63deb91f5ca6c857e9fe2dfe2f6010f1843055ad10610388e8b6e4334fcd1aa6942755094fe9fdcaec0c2bfa56c4516a054415095037ea0adc8802e85c493e33325382654fadd817bd1e7e814988c129729ff619e7bd8bf1f146941aa2216af7972b665408f6160957ea8adbfe439f5eff78566f7794e7fdfa5b45aae103ec447f6f1c1973f8abe1adf06b54f84e000aeb7f61f86afde584882ec5513e388c78897a63278b3a9003702126e5c560d15299d923534028da668b9331c190d7fd148b857901faba289af701ed7152f3b9a03961ef778b080a1502261495aca6121ce7a54c5c232166cb6bbceb448bdf4ccf66d0be4690a825b424a76638934153b8fe00fb3200a42d41fdac1100b4b469e3b663f9ba81380111963dc2a78b3c4301dd4bef4f7d3faf9d4e7e5fbbf4f552eea9f6fb042e7f085b34f29fe09bb7f4b6e7c57e64495381bd87968b71c34f219d4274ea9c621f2fcb31a3ffb23b86a7333551404080b8505e40327562959c56e366bbac2275139b32d34619b7456e009374841845299a6400ab222d8b79a0328d4e09e5f5be19088e4846b7d3473bbd4230ddb70055c46d3c13dbc9aecca9eb8da1140b34a2eeedeee86ef916551446063d49f243bc5cb3cc8a1118bee0d0c9ae11a2ec0eabe470ca6901ffddb8e6d2ecdb7234d86040bcdb0e3485e4036b574a164ce8d0194cae96e72ce5a982ee2b24a5d7866d3d876463759cad58125d2bdd40588a91cc0599d7df391c84617bc7897037902f49af1f2aa28c36a09adba57b40d8ab3eadfc4adbd4974a78af19f3f0cfc50cec978982b48fc90b4f06cfc8471ba6f5186c3461f2f73912d9f208324707dd26c3add3e0c5dba40f2033b082af8ccdf321f2ec8321b8935b5100c08607182cfd2c62c49e6bb004a66b930739ffdaf4a523a1f529537b1033df340d2c9589151bb04755fd06d48616336654bbf28c7264d391a41c20f01bb6fb59a3782cd0d7882e456570042d32fd0391b64e1a0b608cf22f409d03d9ffbbfb664f5a1628de684da0449c0fb2aecd4f3f1e01c9c5ea0cff00fe27dbb73ca46709b536803d51e18c4531ed878b1e0b3d36bc650620ce54d37375093145158a52cd797e6c991fcaf57c954ea4d830b21ff735fcf0cff1206a8bc23d22fb8069c06c172b3dc047c76a761ecfaa644f899de24760f227f37390c3742292b06109b12e35d6a6fb8beb5ef402929187617e8843f08cfc8bf02c1258d0cd3b59f8a4626ae699d01732b527bb1b1defdc52ee0b14bea08b099d34bfb0dfd4aecc086068ad638668143a19bd4b08e6317f0c09c638175cb6cd59911b4176c64494c20b57ac8585e74299c0d417f36dbaf0cfc5ca2e428f59a49b074933c6fc9d4e2aeac3865ea286221d954e996fa165bca0030f01d4ae9949232977bc7bb9295a145049402474bc6fd9c880cc661efe8b96db6e58e77b94b62f81f7a8fcd0031007264a63b930f8c08c4a51f221d4a195f59df36d0e2bb5bd70ea52485ca419790d6c028ad6671f24c18a52813e94d04a9422200e8275c0264960ebbc5f06e55facac12dcaeb34ee339a06fbfb9dc20c59f2a69261ddbe1052e8efaf11f762fcfd4292b67992adb1f164f4a50f1666288bbd1940e112dc88a83980cadf5d9a1358a0bc6503436f52ac2442d5ce85c54fb09eb349d1e96ce3494c4532e1bbb51b25d2fc7e95a23a09d0fca1321dca5ed1a4ac6dc769d2f18af40ac9cbaf375c166534db56b6e92b90d7c720d552f3656e705cb1956427aacac5a386d73f8a7334e32175eff4284c35915ac3117fcd82b47f70825d0c04ab44ea091499ec94efef532130b718264652baece4c45890b15aef8b971fdecdee38f18dd79637f4dd11f6b9269a2a61f83d03944a2e3aa152d8156d8b8f685776b6bdc60d18c0a91e204f80d4958ddfe389952062150bd8c662ff2d15a5820b5881806ee8cc7c5df5f0cfe8054c10f562f4d83f2c7092afc696d3241a9000657dd49b7bdab05035a8208cdf411360530990f21cf5f4b74808d5ab623848783f3c392768e2e0b18ba45b8c46c7ed424e52e51458f4c77ab1c64f647e3911906d5a285e75731818183ecd2c8c84de408ca656d1a3eadc2d568e0b443325b8e0ce53d3d8f1ffe701f1d836b15cc41d98088fb0141c103d2aed0289db6632e8848b9ce1371af96e06ccc242d35bc28018430aac6d9a95f61892f00d143fbb1606014762a5a521e11a40ba8a98784c42c55c4cc4b5c344b269198cf58539c24dfb75c13837697cab2070478c5474887001b5b996383d76170d2fb340774c3f803195508b7d2625212dff8f2d47c35c122919b51e778291a9dc1237ae7a39be185dda57fbcc7f10ae56db1786c063c023f9431f879e778f1a4a91875d73d1a462b3cf74ec44d3290e074d93a19a60c10410fa572b48830a9e0aeabc711fea19db8283628560944424414e5f7d354d3fb19213b350c3005e6f6cb835c9ac6c014d85b355580f252170c077994a22a15fb587fa75fd550bbf810b1ecb875b6d3dab6305b42ab95832e396ecdc5604db305a5603cdc978d19fbaac1a66ab1b9485fd1e5b38900b2d7986dd74024cf44c831739e3ad5f74b8ffa8d80695920487a3430cec2918f3778b05f07c876d8056133b3ee0dd70922435968353fb2bf74860416056c8d08c563c227b23119324b3efe732fbb61cc06ad99c5f6aa5ee4cb9e42a6d1994f12127701be244b7593112f15e84a2a74d2b61e362b87b920d3700f2806123d2f5dd4a2d6bb5d81375b8a19ff47b84297caf77218aaf6173cc75f808799b8f113106f5b94968f229fea74088d9138c8231466e7add9e94a2488d5f66ae7df18b79697af911090a263370288218cdfa00404bc17d498a1246b83172a161790075e9eb2f29a7e2592fca2cadef1157a909bd20cf53d85dce7714084f8b967317a8f60393205d9548c01dddbe93a0a67d8aa79f6af8dd265b86f19f97da1e51d36ac7638d27841200be394e91722ae411afc74302af774365dea321f7cc58c0aaf00b70fe7c66f6af3db2394c733501c7d949c9b07f6b8f4ccef6d1c46815c45ce394dc072ba881db880e898bb16415e89d14763c9090576458697c658ef809c690b333ed1ef9cfaa52460b7cfa02c9e7e4e6ac30f016f86a3bbc6d7d58637dda04a83c1c8e494be13d2c2d3d2be3dac563a621c1a504013ac2e02548486caa5cd9c9627d1f1a87e4a840744bed5e45a40d85c296e2a9de972e5e388a3156304ef8743204ccf1e038a5359bbe42e903ccffdc1e7adf5fa3c7c406b48a159e94018745279a2e38374eb990aa411baa17081888666c0d1317969791a307d088f83af3b3ee51cc0a4dd678cf5fdef27f2091eb8db84c3ec23356bfa0984f3a808133cc223f55fe83dcad6ab57c5b3327ae457e1e31eaf0c75be6d226fa84d3c98b8b16a5ab565d44953bc88c5629e01c5e2a3852928e198e2fa28553ec6cc8dcf7eb1e67984938fd0926d3a7fa0f34e23aa03c32b3c13b6d8acb1da65224c0849a844c04305c6265d0bfab7b06dcc594a2cacc4331d393314c61589d260375e9684d203b1b9e52d5223f2610f4501e8c231aebaccf01f957debcf2168f3b75461e4270b3208e948df3333020f970163836ed83110ed1ccc77ec168b914dcb7710bba2be00c3708f33423ea171a0025fb147684db4f6b9aac4d8cf9c9b37ff5e2b62e8672aee098c3b5684a4c205de0882fabf299665a17d306bd3c32e6e387d5e9651faacc671c60d161487d7f11a6c00e942d63c99b50f37de4a1f1e375cab42b92466b002e094ca12c12c29585cb8a18a656dc50d954c1d8c08007f92c0e40514df5175b155ec4dab33f365bd2bb51ef239f5bfbc0f52dd283959dfa82fa7e137f9288c112a08dd94e09493a58a071b742ba498579b2f7b9a85ce30887c66e68644e80633bea583ff7768a388bcca66bae59b2571f11f18188a408476ddb4a84f13c594e6f6394ace46caf3a593a81d946a5dd0b536fc7da6c34020bb664808830ff43d43c5aacd6a93aa3f505185e355270fb78642e2c4f086b18709bc9c38e39fec8934aa6d007f68c4c45492b8dc88c4edfaaa057d885fb9f37d217410cc2bd413f32828e5c65508cd9bea2d93d70d82cdb0b8a2f3152652dc368465dc8c6a18cef66ecfe06b53d483c908ba3ee0975eeda0a504755a5327bc0cddebd423cb8ae2a35f2897280d8a383231e1a4279f4bc8a884dbaa9230836f83e3fc74d0b76538490a241daa2583303f4766b40161add0d45405cdedd8d9bf0f035f16dd6dafb33f11c670df9779966cdc5b7b4119e15c5a3ef6d06fccae0153f3f8d60b4daf6b36bca6d22cc72dd24bf9862bc6c1d2289c5fecf1f3d33ea21a8fecca67400bf72865fdd18855158edae46044d12ced4a27f46fe80da805c18f060c7785d86c5dd9ceb76bc5ce9c74a0b5a40d72da3ae90fbd63b706e4eb729154000718b49d775df3f7b0118206d81061d56cb080e02a1316dc9368db909092b0f13dc59791781d9718192ec5e6166d0266eb31175133f9e49df046f829cd149944583295f4492455217bbde8422860b9fe3b373df97bf003bd931a32e786b0ff97e5e0096d1aa19b8268d4124245f50b1eb2d4a7cf8c571b66acf7dc571b0829f36a78b6da2e89cbe020227a3388071805b8b26340a26cb96b5c51120b54a5816dfa01a303f8eb1734573ae4e7525ec0a607ee674a5ab162668d8355ed6029c7d3830280fc3c988a11d13deb5eabd183164b2abf9cb1048f9e6e45bf823871e785e2d064ec9aca8a342f8b4c25f9d5da8a0902f65d557fd8d0c332160105301f894fd76721518c8819c7c5608291f9f53deab02e5f3ff8660549dbb9d982eaaf1e1ef8cf2ca37dcc3f35cb844ccebe37c637feaade36c45641a89533761bb2b4feb2eeb403dd84396ef190b30599550eef8c44336e8d67b7ec42a1dc4bfec1413c725a6f47933c23f4b99817a1f210fbe18b18ddb8997f90f173972b60bccb49a29bf9868bcab55e8cbb946a27cc7760c89b30a76086bb95eef3db50963cc16ce8ef4c21ec507decb3bbe1c6ec1d55561af8302383ad875cd79d469d7befbeda24c031712cc1f743165a5270abdfd1565357d2d5d02a9f8df96690173190fbef66db72e3bb22140255f557c9587e6d8b096b843e84c08a95edf13422ae0a6d8893b6cccbd352ddabbbe2084b2660f34921ae2cf0d8e5c5d1d334495afaae764c8370092ec233ea0d276a80bb1ceef915dc50d23f3aa2407c8d176ab5863b8a7cb7daf115e95196952d41a19c9013c972411f7cb6de5740d1705cd2fce82a74dd7792ac0d2b11645e67401fd99a39735a847012d04b1eefbe821e59c187cedaac56e0ed225eb2da559dd89519593ee763ca1e6e7457af54ed978e306fe35dc90127653ea921d7be86b31ce674f484d777f372e504692c916c32293fae7bc78abf1abd9b52841950a76eaec7f88618bb9487e848355298172babb8b2d46e4a7c49db7feffc0ffd44a29451e6db124432e2e315dfd051107a0710cded87cbe7df3bc1dd379bb6bdce30bc0a02548f95ca5a320a9e40a62168c1cac1bdfec337ed977a37bc00aa76609fd365de9e0915e19414c035e1e834036cfb75fd33d7a010f5a428af7453a0c48314710b1c1e862df8cdc4316989a25f8bcbba4434f8ab3822805fc720c01dd86257e676648476fa95c11c4bb008d25ecbcb5a4c39d145b05914f79473278d3330bb16e8a6ae76ee0556e29a265cd33fc1982f57c28a67ed45c099f0839c10e1ddabfd2b17db4f225ad62540d58acdcbd5adbf5583d629116d65c272ec14dfa26ad9579f752d96a91d503204290377513c4ee4d5649506d41328edfcdce7885a54f4736c459b9e11ccce7818c46eb3293c63ed57842b2c5b75b1b6b92adc65c166be558b72438539febc9dc7b8a1fed53b60c19928a5c08e0568f637630161afcc789a42266a4bfd328ca01734f29b5684925a0029c81a2be5f06b9889a64b4da2734ea47d4744097c39b8ad0e8fe25a51c10aac6d1e8968e07a8c3782cff64e852134924fff571ee2c34b81b08707ed43520199546866dcaebad30edd80b389d017dde306fe9263f4dbc432100b122165949438a3a43c9dda056cee124f616add386098c66e38f1d0611a1c958f898887f8177fa15db3fafd0ee987199b0867d1ccb2beb8b9a8aa44f72a4ede4bb2875e94786ab202cdc046305394fbfc1880ea539880bffac7654c6fdb4f5b46d1f5aac6bfb02d5fe0a90fe64f03faae03af8d3f7431a51cbc86a9188ddae6b5e626b21dc469c98064d286ba14c9dcd8cc62dbab9c21fadec41114a025eb7f8b77f6724e2a58b06b79fb960c7ddb4bf9bcef1e8843b8d69597564b98ae16ad5531810e4bd164c48b56d78ae4f6c8420676254148f7fe62bb96471cf1474891fcc70ae5f943d8a184da8f3df9a19db84e2745df12284e2090717fbcf85468ff250071cf2841e0cb5a8d281037a59c4ccda1d463a87d2c01301ac5fa0118fc348f2e64d0dc795177ca6cb0d23a7ca2037e36b7f0439df55fd08ea1ce65714a99f89b7e61a8e39692c360c2aae4e6433d8f543739bd4b7459b76e2552bc9773912e8b97da04e8a802d9179193944dbe109efd4d5851674553608c43f42c4c69ef46f04bb3620a34bf26ed988fe137abb6f74a547ca974e67c367f2b17a02629e1e836ba7e304023e37649e898c913071da975e3af0eaabb15a9f79a2848f20f1afead8391398cd0cbb8d447cb32079ba37c498f2478d9c1bc0dc5fb7868c0b0802967103da317354671c102348eb0614554d960acff501684945c9e41adf6d772748bb62c4d3e77e56b2a5ca69cc0078a3015887f7e73ebf05b3df2351a40dd90c1eb82eaf359460b0401c7755f87624de0ec316af001c892cd124df742e163090e7057f4fddde019fdfdc7c4518b49446d66e6e2458fa325a3f2896ff40fd844bed76f91d52798d4415d84f0cf3c030db2055f88711b27cbc3c08f7a4e59bf2697985f2b303610aaa1e185dcdd4bf3cdae78c872edc59cfd4f5f44530a2c9f5f228b151fc865717da45d8a0e55154bf0e3eb06d70a7fda6194c12a5d15bebda32293f5452ae9ccf2fb0f810535b1ea9d5e8f7b24c7cdd7ac994c95231f54fb23c50ed592388e58125a67654ceb71970bc26c468bf00a0cce4405d66c57af7b1e0a610ef560bbcfa7cf280769bd3a6a3f4c311b1938fd7e6ea0644af79aec46077231685ee032533dd7443137a47f301bcc3058e5585c61057205c914d3ac9b0611b5fb6f3e4694d4632024212c09152eec2cff10c394c5c8506e0d55475135a83070e2c06821514200065e46fc5d981f0ce10e6f551e0ac28a3929b81f6924165de8c5a3bd41a216a8d10b2f7967b0742112f1047102e4ff1ee623ac245bf5ede306f1393975c22ea4b0e5e22c0abbad225627eb91281caf5da2d482f1152ca8c24b9be9c62a024f328c930ef66c995aa3b613010cdcb056a9de676f84a975bb3cb9d42bc3b7db0a5a1b9318d01bc1ffb5ddfba5348bbfaf2c351b7a0616bc462a0d65bde3e4f00ef59bf57e6df96cb431665d6b7ef66055bd994c1fa008624f113da20e63ab15a295759235ff6455fcadab546ac11ebd65a0b84e230033f68a7ff416640032d38cc1ab6dd94558ad5725627735c174dac552c80ac8f53767542100c8901196418901073bd2e01b4b229a38fa3b12e3f0450d1d32f16ee634016e59d12162dce21b93fb9008e9dac93f58bc3534827a45fda9475db6b87b4383df1eaf4089080341413efba3a334fc45cef5628343fca3485c6fb1649077b0590e63437a47f5dc65a37a4384440eb3b3c089abff011344ef31df0114572689ce647e8f01608c0d777787d071bb9773897c41dc92f4c77b8d688ca2cb30e58521a5d447b48afc3776221c544e4d0b80e5887064e808cad7e19a3f938939b062e422f63ad8f606e1dae8cd1d8c9363d9b90311a34b02d02eba93532d2228ad10c4a40c76c3502dba88db458af00ebc76e9de6396ac518c81ecdadd255dff2720e541e75329d9debaa3c1113afce9c95810c3a887de0452c04b48b2e6245ea6d91ac2959316d5439c5b4512fbf1b33fba05d7421a50c7bf97118a7b386815aad2334ece088046088411384b045ac6fad7dc1b43ed3467dcfc01c4c1a5828dad5afe2bbd1b9de64c574f5ad60b9306f606dba52a1a85fb69fe81795c95cf7e4859878e519b25082a158cf286cca4ef2d8b3af8b1aa98b2a13c0d1dafcc005f062eb2eccf38179033400b55a6fe18a248774e47085100338ca222fd75fbee86b3d9ac2148e18d0ba78f921a07511b71175e9688d0cd5a66b4c6c4d591be9775318c9c28811a32a72df1ae9d7c422f70d1114986000c72e3a1aa7ac8df0e8cd93b9720949a8014f4c7e434c998cab4016626042055cd022074a30a0750d09bc4c8c2bb58ee3388ed3ba895bb34646306e45ba5d846493ec11cd47fbd1863422ad4833d28e34242d493b4261723bb269413c3e455a4fdb22a421a15950ee9665d4bf9f98504ade512bbcb8d7735ee972f7367053c1149080448675511be5fe16542aedb3b45a0b9e089b4d6ef39c53bb262a13d35752fa6ec0cb6f5e75b512c8402bc14fee3af9dd68f5a5db3bce362ab921bdbdcc35a4b88b8c64130daccf086affe91758a20df901ed71589f598247109c59bbcfb6a846bf6acd7648bfb87ecd9927c77dd6da227d45b9f4a58bf2da2f14140e757a1180a3edd74ad60860ca9ad4bb289b4c9369327349d36ad49899794b74c59ce251fbac3123fe31d775c5dbbaf6bba1bd7472ee9adc966ed3d67e39505d74d14536b9324f93eea745534ae9d5c4c4528d72745215056909a5263f7977723b2231004d3e763fb94d4a4071e2f11cd6f02d0e0ff6ac5379cf54de55af3f1c25957b7a0ac7e92aefcf3ee563769153ef1937bb864fb1d6c94af0b8b29c15e26e8fc25928ac1085591e219ecea713c223938158a6c223283319ad14b91fbebefbe988f4eba45f73668e03c113eec49ed09379223be9d96c36a3585683c3e35317c71de590ca45a95c5411085a9e16db161581452a5bd4451303b58458a11e0e5b2042b9673d9bcda8ea8e3d4433e1e852ae2dbad688354ab92537ddaea70b72a303d262bf039257b83f41a0d6e96dbdda5b174891da599f5c6fcdf3ab250e0fd1f00f9fa43632a45fb48828a8c0041da4c18a27ac701e30a1441349f880800420c775518bad696d64ade59a446b236dd4a0ac083c78e590769257ed2899bb8eeb39e7e4e991f9d42223d4eb25e12cc9fc4eb37514066aa1bcdbf4973a89c715c0c3dd3efdb2b854c1bfcee45a648f3abd3e2d240ca0fdd8325917d11a356c51178907f1b85261a969da3528fa557adf0ae5121e21704ea8c56e212deb97f746599496bd97be1c2854888375b4cc610b851156c80af58b04db21168a7ea53050eb7766f0cad39df9bb337bb29ffe0c9a3eddf57163661c3203c9c00a57bcc0067098819008b880075b1c99410a28a84167ca8dc5115558c1c80c892d6881060b04a1054832981da10d5cf438f5e4791857c662ae8c752622e0cc13b1c986341015c5ba09d69e59ebd35124b073cf8cb50e448901c45aef9931d747eb23d3d989e914c911ef7aeb32e774cc8575746a20440b9e9878f9853a5a38ac6f5dc6441c56acc375f132e6bab6e85a23eaeab7ee2401d862cf108045d6c767825c57ba921e810b481900591ea10b3c946a9a566b1db9b17467b63eab15087691cf94b5d842e657a4699a01340c048222f5ad5b6b42aab847eb3385f42bb4b9e219a4c5f619d2ba52baea0d99eb47efc823f310e2ba673e143665d4fa589fd56aca7c2c9122ca712048ed10eb43613deb99f5e959bf8bfab5e190ca34143983148c925a90c40522ac60820b1aa440073038c1b54536092422c5134150b8c1139870c54e1129465064094b241121c1490d808480032daee0794217b0d053062bb4e831d28521ae20528321505841c408028e202951451bce1044e68026dca008478650e1c80c35ea6d68d5ced04dafa8439281b146b93faed822e9ea97fc9047fb2bc0366ab18d98011cfbc5ad44b29ea1d84e109688c31b9c48ea811096380242145318431247104211fac5ad3e42530cc5baa8b1c83866965286be3565ad2993d9238b648bac5137cbd2e503243b2f3d7d205bc9a45c75d40b616db45b6baf0f2dd63aeee46edc551dda6f098f3c7249876aafe118b6da2ab65823051d051a369b7a43342edd182d42408c71d3d18e4749a6d7512fc4110474d40b41613b4d1cc10a21e0c00a25184921566f53ff43c7518ec3150452a464035aaddbbaaec3a309ffe0438b75c559ebc30f518040902e99f31b76205d325b1b5315607d67f952f10e99d465a1d16dabb7f5da476beb6dfd0edb739cb65f1ac7713d358fd29ab977e6f0b8d98de28437ec7128b55c31976dbac6e172455d92db4872a238d2a2cc3b79e6d35fdaf93ac190b969c4853648a1096c58c36c89981ca283236b0881133b08c21790051648e8d18112238062a69bb260d25c39dab3a9adb427adbdd9be53b3b4ca1a49393b658df6b6dfde6976da4b69ded1a62592c204435a68c145902c878820451ea711f27c8c2c8ff0862cb46bbe481d123653832b015959ce48980e1ac393b02a5df35287c41b96454690e41841884cead1a2113f5e008e0fe80204b9b9f72d75db0c8571dc2c81320329d2f54c8ffbc3648de857e3f11dfe6144bf62235a9cefa103b071d276ee86fba603907b8f1f466c5f01766af7bea3f7ee33a8c7fd614415c0399b4d6c1f67d066a2a50e9a4fe4b95d7e1ac6a9d9d6e9e34d9f2023d0740538d66c02f0086f9822a7005941891c3861055708926690a2062e00021741d2b082d87c0f237828ecc40a232924110532e8a00b151f00e1054418b2041154109bef61c49077c5145308cad547beca7eb27c1522eb902cb5a22c6faa015865143691384e5669f02387aa1086206fd8421256e8c102b4804513a690042de4a006f29a263f9328acbedbc9a9d7de38c77ec33aa08ea4ae9d9d1cee1ad629d2d7e972744c2f7d27ec6ff5da83b0dff011dbed357c44919c0d4bea92b73f425257bd8c4d2dc20e1b8708e0ae3d08ee1af7204ad7aee1234cf263c0c673431df5610264ac3e0cc28928f020092d82a616a0e9dd7f7e78a68c9399a800ca5878748526b658c3cf9cfdc81889125970a10c473cdd9d43d425b5004be75ec2617f2726a96b16c5a6d1bc82fb8c7197b1234cda7118c4f650c7f604c8d88683d08eb0600c308001110f4fecd425afd3d3b1ee1fd8aee1b05fbae9e3740128632916803246a120c10f9ef0842c78786232d6e1233eb0611e1c36c619b2a12ef930d49143b11883109e0cc4610850979cd13e639a8e21130e73340e571fea92f2291f50c6c220666cfb8cf5a02e294bb8caa84b7e9449dbc7f6910f1b374fffc8d32d8035a8ceaa5035aa4796c7f65899f5b13f36c8ceac90d6a3c93421cde7a7220d59a3a14a247df258651acf9124247bd4b59415ccb363f6cadc18696e71a7162d4a6da85df2520eb5285f65597ed486b27cfda1b00df4e0064e0cf9a9410d881093af41f255265f7de44d5300b5226ea7768a083f796ed71ee6681c75cded86391bf89d98fc48c21bf4f46110dc76ae7484f6d2b9f14777bfef0e8a431c55eee3dce2223aefa0974b5081d155657ae5125410a4872acb976e188456ba7619e36e18c411dcb7cba13047e71b16a254838639dbb9735847a42eea9ada3ced91f9080d1d21254d990f5292cf114a4461f247a87f286cce9e5c8f8c6679aeec8f6d0d06f2a62a40f9697790c8c11744d08524d880441162f22285a582ba18c111194c503484983cb8eabeca92526c9cda9a94334440199331f909018e358410c39ca9b3a22ef98939ea9245d4b50570ac91a594524a29a594524a29a594524a294f7d7ea494524a79d30c9c2600c71a59fef2353aa98ff451235959a50205844ea0040d78d006232b6881133438c113c2b04419a2a8020a82e429a7f7511a218216b9a5a813fb9879fa40519435b0ca3fbe332701bca1dc53da00793623e4de6614072d6404da4e089db2a90a705ee66dd6aff9392906f26ed3d30340ee6f4e4898ed91ae7e3d0f8c82a2b03121f711720b21f7654abefae824b2c69efede45b12490b0b62a7809e5eeba65ef86f3bba1f6ef3bb1ce5e1c32afa44c38768f2cd7eec9e9ee619deedacdf1fe619d1fa86bded3842efd16c0719b6ddb4cda8ef05098fc099a51580ff10871434414268b8a38a3a059c9a85f12ea97867a8eb8a30d89c264ac88e8c747d693bbc4933bc908d82098628fadc477a333eda1b0eefd964d1bd3543465f45b051246a5205dfd991918305c5cc23c52a2308fdda3ca63f7e49636e6c1f6ea77633b9202588fba15e0587f260e11d0b10e531a0538d69f2a45bf68307f66206bec5743007b90fb72e620f7a6699ba6514a5f850f0c044df60885a1febd4f7de84f2e62bedf5d90b05a5790fb601a78c660c223c7e1115ce171953deb1dc96dbd3cb19559564b279d74d2ea699ebdd70304045d695a6bc7ed666e332d486ead277797794c53f6898e45647b44ca74ac933740e90417609153b274420b92f277e316c1651f5b1771e09977de53aa03599190325ed515102177e5c9d407262119db89f5b7a18d682ba29b91ac99390752a63f2f0d9a32fa1deaced8140188246b6ce4a641421476fa3693359c51c69bd0362b01d85966f0a78f346876a3030888c3799d93609d0dfc4e0cbce13c8951384ff29dd85138718880d3c1e79c0e7e1ec43a4526ce014f02629dfe090fe5ee368f863932cd1df54e57c6c02b63fddde8d866d4153345016c1e2923d3f7fe7d1e493ac5a622b016b5d8591c7d9bcd5b8d54a31693fa35ce6d8bedc8c645bfecebcf764461f5679b6db36da69d087b5ab168b18fe48d8bdc3c990392fb28a4a4dcaf3f14b6813568057e75542557bbbb7b9b5157a3ae8c4d1280350b5c8f5aec0904ac582040c64e979f8eee36ad324d00769a37af29534a6f0bcb0a2b544959a19c9894a8522420eaf4799da9c46d9a94913254ca48192933815030143e75f5e9da1975f53714846910a5415d94c7cf6d1604dc84b6274c5000e93b296aefe636dba0c8dd6d4fb4d8b6c7ce68c90a5c657af93e9a3628b63db3b9206b26b64b1c019c9f69089c1f3d8d01d847d4d5ef3eaec43cda1eb18fb8b18f2c8d75d8065197e909e0b8cd7a72b7cf2c77d7d9576693134abc6da7d4304840ab949c04e54afef3630cfb69717b2f98e91674f265b4324bb74b29a594cbd5540528b3890828a96bec5998d3ddbb87754eef3a88bae68f8e501eda4383e88c1651237a4491681285d12818b1420a7a84c26451e5e931aa4714262b524da242b21a446192caa80f85c998e539524434447ff2fce97e573601a402ecd7d3772626400fefc45a8b3e6aa43c6f620238f691cb09212534d18534f0a08a1e3c3bc8810da4e88115d8705a343b15610811520cb048818f4b14c6008621f044e102354c898532d8400838e0020a90b680035218a688821186f004f9c10cd8881f5700516eaf84370465d62996f9069c8d32293f71729b4f4e5ec72ac4c78653c6c3c3938b9879fa00c1c2ab2e80dd44bf5cf038b3cb65b7aacb53ef5c6e37713ba84579ca03badce5e6051be0e4ded0fe5ee6d50d2dbed1e99079c5e766a5b2742b57e63a5bef2afdb1827b802f2dcabf45d93221d46bd55e39eb26ef566eeb3417489195d6bb940ac0d6655e396ddda4b5d26ae1182dcae7b4286fc41559c4c23446fcb032b05970ce17c0cf00f41dbefc76983c97fbbbbcb4de6ab5d8fa3873eb2bf62777476579bdc5618e3ecbca9d99a57582c7fa22663e39cbde93d7953bf30bebce9f137c3929d3f2d52d499996d35ba78c96dfab4d192db7a12ea30773471e5e0ff96e4cbf4c5dca2c535ccd3ff7e5f8bbe9a56e3a2d9dbe7413ee9f2cc0b17db27c577bfeb4b4f45b3ef6cc7bc98206594852a208464bccb0084a83142818720530c87e07863a68681e06719ad3b834f7c404161481831344787862344ed3519a4b83d2d0a81888264673e5670e9657af8e2be7e1e51396133cd67c7296d33bce8ce3581b90e91099de874e8cbcf26e56d44f7cd01b2b972c1db5b22ebf1b14eb2d2d1ced732db7667a79783fd98102a990c90a20eaac1797a2de75a85b4f6fb39ca55b70b8721b8afa917978f98485c2a1acb7ace010c7f4ce2f725ab4b5da6e91b9b6dc9c175766890690e784e29c16e5af0e8d0b70944542e8b87c7788d3afaf8d439cc63c78c8f53b99070fb9bf93eb9d3e93488bf22c770a6971c8c99d3f1690421b9c4086239820073129ee40082160a2044928c117a68cc8884924937868e1712753faee20b4565abb57ac2dd55aab6d7b57deea5a70fa54b6b83ac563496ea13b280e739cbc4f6f9ce091070f99f5febdbd7775c79ddc6261396179b73db9e307b25db932b3dc95b3dc95dafdda5808dbbd626df7ca6dba576ed395e576e5f2bb61398b6c11cb16652b2553269b128f2b348024ddbd44773a27273e683e19672eb9eade7ebfbed653563dad5dd7fd57bde9714705d37bef55aa7b55bff75ed5c989102740345f752c77a5e5c2bc6badb5d2d9336dc8d6c719248fbf7d7d79fdd80a7263e693cb86d1f8c8720af395fa5a5b8ecf3acd0f9a5b6ebfbab245d62ac504c8827fd0cc5ab929264018fca333ebe3311e2516fde1d8415f330bef606135cb0b5ef9d8c23f3ab37c058f128bb9c4b4d18277b09c75cb8277d015fed1f9b29c7e402c31653466a927aa77254f45c5e45d7734ee0eef58efcb8247afde1d2ecd695c9ab75cd60e3b9ce6d258edc07ac92cefa8b7c3a57196bbf296cb3acda5f1f9e15839cc6d39cdd5c1a37165bb4630af74e8b7eecc2cb76fb460d66d5a87eedaa3b934ce729b6e5d9959b7e51dcb1dbdcc721ab7b68be52d57b6c8f2f9dd58394b4bf5d6edcc724daeb272471355906cd31b13269714e5135c850fcfa27fdfbffcc5e518e6d8767dbb0fd342f2fd84942cb7efcbf2933bfec827f2cb514f70c8bac5630844cbdbb2304e0b962d36b6f4e3c953eaca29ebd4be597ef26e09591887054b7c7293d6595a6f966669dda659708a09d0e2a334ded13a0bde01f33e0f8b7978b9556172a47060706df1057ff5c6a30b962de2d7163155ddabae8aaa54f6f544f5beaaaf54ef133cae547d15fe57fdf77d5356b75abdf657af57e9da2aef6c4ff1ca270e7152a74f9de2d194593b580f6dc87a18de9175128667d1bc05b39ce6ca76b1e0b1b2b0dc95d3f0293fb136bcfc70ec433cb24ea44d5b8b4f2fcbeba51f0e3dcbdbae9cae9ce01daca76ed32b7764e1b06556b9602eb92926afdfcd0ac51b79c894e6b03ff909de4169a7ded744529955293c899080770e913fdd49d4a2fc7767152d4a359840ee43a610c90394535c21cb7228cb29a85094bb1e928b2c3f9b48966f22fd6afce31d24df83c274f4907c13c9f7ac85e869a69fb7672dca57286cd34b69a64034b9650fd9a345397fe46790fc94c94f9f2ea2e9a9831e74610ebd610ec5218711303f30776637a023a279b29de5facefe54fb4361ddeb6d1085950ee41dc874fb43611e36c942799394efb04e118973ba9bb08ef7ee3f4d5c29e5c4405f4c5e4b44c6ec4f7dfd64252b6bb19aee114572be9f7e8477925b59ae07eb57f5b29eabe7e1f5331466e2c055ae62677fc09d1c0f87f3a577ef9e537af71cd3b99bce9debb87bc4e9dfbb7b44919cd3bf1f4172effd8508f04e72067c3f79277912df4f31eeca5847324500d6af28ecd546aee7a49424b59ea412e0cce17c7719f3de3d08ef1d3ea2480eeadf8f00ef3d88ef08d4bf03499d3b10d5497e64ea929c6c10b6443e8180f2a3fdd1c1a1c05b7fea4eb7bb477d273613ced373ba9f3e7f3a1d8575243d618ebaea753a2ca98c9d2475d52880a09499c72133112b2933bb9fbeebddee74e50d73be63aebb87bb74c71a595ebb1c9ea12e693b3448b9aaf11a9c3d3dc547d05bcc05a11d61af49393f72f61ea11d518f802f01da6d9863af7134cc99b65e3a9b1e75f265dc8a6c67727991c2549fe14ede3fe1b81f2159cfc673e4075994b5e6c9dcbb1944e9c9e4ae6ec955f55337d4be13a31c883a79d7ae38435d54ccdc9c578032a61ac5cc1d69913bc9b58f1448e6ded1abd126c140b4b9e82314a6038f9c8e16b9c7e8e56e6742dc6d1077d5b5a12eeef60660987324cc49bd9fc256465ddc39fb9339ee56688888c26612924da23029f3f909d2664214268bb4218dc887c2b86f3f1b11f72d88fb36b347b4a29f19e36eb91f141e37a1cc5dd24d96b90f8f5b4fe63c3c6e3c99d38e64cec495f0688f32b799fa5ba223e2c7cb688bb49c6d15125b22fa63a5c854467ffa34a84f65d46762131840c91d9d3b0aa2861092ba40f905d16298535a618ebadaa683f882d061ba4dcb8d7b69be9b537b09eb94ce618ebab4f797c37dc33adb39acdd515c713a66a8cb9af08abaec915a487634d60873b8c9b3132bdd0dd3db3475511795d11915a246f4a8f2d49e2aab3ef5a7ceaa90edb1322b647dec0f1285c9213a44617396bb8f24e5a64554c8a528a02998325af60570de7617872224b8a2dc9f72da30d121508920b9933b4039940417a5201ad4ba0ca2ae964dd73cc781e09c41cdc9caf3f94cb500d29bbcf084e6c9146b432d6a4215077306e0cca3bd8150e5b999da1047575383a2456d4813b24fb94d4bc9d1151eb93ca9bddad0d584b4a17e1119d2a0d086b421a1fa9305386a429a9026a441d1af216e0b4bd995c7f991dee436fda2750ebc3849e5e1a997b9f5998275bcc032e7c8a1580b379135b9f4e541607d0bc91a2021703d045903d403c65aefd32359b30559837a9f7241d69c640dcafb15095973f27e0581ac297900983812ebd72059b37abfe2a0e640d684ef571dc81a95bf78bf0a51582daa43acd71048da05599be8d7ec897ed1a7aa0aeec74a82918e21b77ca469c8bf41c761dad0949832c820611afed86ac82e1f1b0eb9df58c81a0d0bb2260b6f2dc89a526f41bebc20c3d030f8058b4a4c1b5b0ca68c1e8d879ec75c1fdb08b9df44900270e19e55ac75173c82b8270b8d1aa809dd20f796445dbd151551182794c2a3c9c526c7a309d8824790058fdc0aae452cbcba33734214c6c93899102713cadf6d77956b7a784b4fb9dcc6ad5657b92d65569f974a71757b3729ae4e6f27c5d5391985a1a46bf55e7df591f3c97ddc44fca8b97ef58ea6bc9432eac8299888cf3cc71d1c1860b661dc7141a678d4912926e2594a994945088090ed77b3da56279d4b924cf2b8252591e024144c4e6872439883a2c58a81c21c54175d74d145ccf59113ca3aae1f0182d65d380cc2758478172e322f63e2fbd3d17a373d978e172600c1cba1e09e38156421b9391c7881c810285090fb5b0ca68d66c194318f8414271ca4d806398f4c36489979eece354c35cc2da4cc14af519edf7e28ac9390ae5902ae57f0b3094da43c474d28f79b0909e3215d330252c67c0be48bbe0d798b1ae4ee429e97d12190c6a444421e2790274040caccd74b81fe0bdcba1de38a5e9a7582d93e99d5af9e5fcd1d13b34a56ac1e279d74628f36019ab2d06ebf83ce24f2bc77849e7328731ec541814899f91938d67920f915733ef95d473f2a6fdfc91b437ce918b7e97ec5b0337753ca494fd266b0bfea4baedf50748f34122f621d71868ccbbc8561bc85752a088af86028a6f3e21f28b27d27b6e3ba0bebb8665a8f790cd6c9e12d1ce6c4c478ccbb4a048e764651842bcc605868011c5ba6c51c026a7308f84d277091c536aaa2034267b28695eb7c028aae059d4c5621571574411d13a03de570f79305f0f280a6244abba08ec81070ecdc455d50581ba1d8a445ad4466008ab9dd00766791fbb036d2330be0683a92fb62d67207a45b1a4f6e1e59238ff48b0bd905c97d5bd4e5fa6abb90b02993aee6447082dcfd516b41ee9bb6306941835b5826419641083e4f98c205454043d27c225701cad9dd148b3108e99979c8a22018a0d806e138cdd2bc0424ccb2ccd2e33e20567ef138f3bd78c31cb1675500398a89df89b96e98e37aeb2dac03d38398eb3bb14ea56be97ec051c200ac9f5580e3948dbd0670ec64ed236b66bf64679f7e75ee5c5feb859836349ed82891729d4d00ed77538ba60d7acf72c91df5abde9e36c21c14093e284502cff6dd543cda571caf74a33280f640588c012f737847e9f43b2aee39dad1b301e89989b5de2f7b580bd776d5b70df3bca30a97667e4d1b3257af8e9e1db9a959db0599dca6c157dc0549eef6a66943d505b54884526eda18b9735386bd7d373f1c56bb1d77327d697257754d2507ef585f82532ffda65453a9aee4763d3fdd05a53a1319c0393f03cc9c0251524f79ca55d454823a8ae4ddbd1df4da9fe396ceddf147e65eaadcbc46774c1c12015e3b8e9c32a60c8d7ba76938f3aa8317c7bc4a95b5ca7d95eab4ae9b1f8eea158ff57466eed40b391c12513a771c8e9ebb38f3dc4b17c7c415d71671b873dca457dd91fb37e9375bd25ec22926400dff44f10e934fbca33bf534ccc3cb26d8e2f14b75281412cf432929b94d97dc59a2dd6e252547f956a27178442949555309361dc5747a4d55858272fb303491413b063f7188937a7dea158fa6acdaa17a8a967a4aea2929d76e29f59494ab60ad975ab782af77e4e171b78889f3e5483de5297854953e1c33cb0f876aaf77864494bc1ec7e45cbd098ec9eb4b2e0e13fb8a2d4efd7cc9c5513f67677bc77995b71612a1dd1e879b32c05b1c0e07771cfb7aede298a06a9c988797553885ca1c5e30abdcf1f9fbea8e3f504e5e2af5eebbdd3873ea3d6da4febd4bdd2e48d733bd009a3e76409eda611fe3c9f2cb418fd0450ed2af14c6809777a00ea4ebe9d777d4bf37c9bf1c5d26319de4df45a12a0e7168173e68174959bb0fca4d1b1ae6618bf27801eee305e6c70b943e5e40f50b801f2f50f2f102261f2f70f2f102de2f80724a4faec9e47625d703efa7baa7d24571776aa8d38b7a3d0a756bba18f03209e6519253160aa02cca3047717171ca4ff0386b6adae8a229a36b505e5f32c99aae06f57a4fd6985effc99ad4eb4fb286e4f52859f3bd1e9435a7d793c81a95573cbebc7bb9262eb400613e9a8e988ec04c1ba929a3a35ebd275b14c91a1f264779df4641d6f828b9f7beb542d6f800dfbd6fa5206b7ca88cc81a1fa54f41d6f8984fbd6fa9206b7c70f60a59e343bb91acf1617f7adf5641d6f8a057c12452a6be7fbadf4549997a927b9232f5a9fb49997ad3f5a44c3dea7652a6bebba65b9232f528979332f5e1c9ca869edcf8de7ee5b242959b821b2480ed311599cc008e9608f5d21159437315929824299ee4ce38cd0fcd33d3e051029906889aed65fcc81a9acf93dcd3bf59a6c12d1d057086ac5f210e98693e827986907e853968c61e9906efa0f321cf696ebaead29c84e403baa18949baa9e0bb09d25c7e37244fd1a6f2c3a16f1cf6d41938eca149d1bc1ebc639d914472431e9a191f6b0d7bfa455373f21195ebd882f2f194ebc892ebc72f572fd72ed7988f61ae26181f55581f4b39c6c7945ccfc91a92df2dd71125d7f124579beb689253c71f4bfe91e63aaa727dcb1ad5eb4892eb98cab2a604e6158f34b7ef686ed8130269916709f059422037b53437b60b793aa438e6c88c1bb3c50878fa35c218f5f46b3e0412068131c2f9fc6733327290890123c625be68c1bcb8e09b0303691e2590610a6f615961852a292b94139312558a8400d886dab4cc3d5c19f3e1ca18ca12e5f953c8539dc8634c52cda670862c4f9c1fee8c2c378ecb638ac9f450d7fc8dcb638ad12d80a14ff813068544615198141e61f1b07a5832960feb8715c43ab2c2b312b4d2b3220b8d5833161185499e70160acd9067c52709e9c8885594c3a13cef03d0cdb59bcbef467d4c528b33868b3cdf75407212b9a3df8d8f19f987fdccf4cb61b3adbfb97fa25df3b316e7ac46490d59fb344b8e4ab2a09f5dd3296d3d492903e4c363b668713e2689c2608c7cc0303149d9872b633dc018853c797e8431caf3a12cf40979c29e972cd61a28d234b05a0e02ed9ab5014920d2103cacc522b84a92424784c793e96f18c48f998500a94be2e8bef2284f50cac839e7e4290a9a090d51983ca2477a36df45443f3eb29ea47a449bd0c9977a679ed286c793651639b4326fb7693b4361df7e907e452fb99ea1e4e58b7763e60efc614ea2493489ae7c0f892b08a4ca24118e8489d455e516729551d82eafcc2285fdd0b8d60f082af3bc31b3fc0f14d6d225af7294caf2a6228c83337da74dd927ed61878d7dcc2c4fc4ccf247bf2406e2e87b4827b4a027ff90466ed0938de8c953396c02472e574a29a53d654fd9264527650c29233f8300cee9026983be739f881f3503f18441cc58fd8c55dce3c5eac1fecc210e2af75119a8031573b3f6e55aaea0932f4d982ac7cd39e9e424858da07c7771fc5ce7140efbd4bbf6b4ff9aeec538a8bd2997c21c25dfbec96cbaf6dda0aaad003a5ad4fe838e0248a2ce6bb1ce0f0727041cb9cdc424e59bc9894fa882b2627def58ae7d78b99bdc3064dd0985d013b32984e61f6a47b3ca95f98730654bf966a2d2039fdce4f50838652caf9fb3f9c41482a25f21d1a953b9db596e4ab842b97346f30f5d46a1b96339c126dc6d37ed651567cd517ac96bf4ab8443fb9dfc19e08638aa73577d27975e2638cc61b2934d2e73ddea14c286ae2b1c66eea69713fa98954e7aa2793bcd1b04fa15e26c57b90a1e59df7088a3b29377727d03fad58016ab8ded2d4aa0228bdcf23077d5b342ec607dc3428439b6870f714eae2b0ff114f2ed4ed99763c359790b1ec3afcc198095759b576cbef1b1727bd6955264b9fd32806366d657f00d0b5729c382c7f00568b166160bef08718803011dbdbddbeecc33471461fde29930887b7c8c757662178bddf6ddf8983477dc94b3397bb22aa759058f1fc82bcf610d1e6c7ce897caeb0a0487a0ae7ad4bb09b2d4cfd97c620ab558af7227142dd60f513924994b3c6fc333089e3d6f0029eb256f408bf536ab9c75c392571e1e3025054f21df5e8f80e3aa478b2517a7f2f0645635c153c8b75b116c97c7edc106b074d3b5d103793b0b4b29aa5c7e3966ae5246058f2a0f71015afc70547088f3ed2a58470e0a6008b478835861cee2808b24846cca2dddde99b99c1f286c9ede492214bc5a0358fa945d8cafcb31d6a94c0c21e6827fb18e00c2304b8a6155a944e506d0f4438b95d657ee3bc96af5bf688cc23e1c354f998e025cfb28895c8270f99c5fcecb5db08ea4a20ab19739d790841804d1d4a59964454425a2e67125b7a8d63e5b1e707b69fecca0299b3ee311d9fe5e7c59e94e9f21c7ac16ebeb16a0493bd630885f3e2f5f2ebf2040ea9ac7975f8ecb5fb04e5884980be672ee31d6914da0e28a59ec62495d50582bc3e19d6ced73a2b05e4e1452e492cc528a9c28a098d6d6296b57b5962b699b3665510cd9a1957e5185204d64fa91ab583b58b79ab5ab7d395148118514511469395114d500dca2206a51e66d1c40a6af16ccdbb77501eccfd38fcf61bd8e07a610c4084f6c5ec6fa861513916391288af5736a0ed2d0044f6c5ea7037198c5fa3246b75aebdb45a3188a82a856abd9967500b266ced3be9645275fc69a942b48a9890b6098436fdb766bf63c36a6618b79ec2dee1975d56f011c7be8a891286c26f5c8284cce846a0ff11045c18815521851982ca2471449a8be0e2155a2fa5a447d68d25027d5f7915a6bad3eb9ca72e5c9f53589071dd854d612adc792ccbdeb343c7259eb39dbdab7384d9dbd4913afd65c95b266f6ccddb79732dcff6aac55af45cebefe459c5debfc6a5e72dd4dcd0c355e62d4a85ea62300e933fd3833d6984d4105146c6b9676c0a12ebdd3b71180df4fef9a7a37050370e491c792ecddbbbda75b4d5a004779b479dc4f06a05dbc217f78a62b044c550087a0408bf5a62c80a77b2d7a1fe5519532d6f33ca09e7b17883e468bddb661ed875195b793481b079832eab7cbba71f7a1c51f8c80dc71703e66ee7e8069030152468d42aef7e413727db7bd7e37362d568e03a5bddb0f3e4c508816735aac3f5c21da551bb0bdca1aee1b1ebf77f636e00a2185919ce3d0cc9de6e8cce12a65b69f3e79b037de735a887e7dddb6e1d297e3bb35c4f16eef61af08dad51afd1a2d0ff655dc708d162be67c68577d6d9795db5eb70d8738da3150927968116cb1be468dba5ad52142b1bef25bb558bf2d81b48223520861084f7c095a300ac110ac108445ac1e02435018275d36a70e118ad1f795b16e7acd800e831598488af5e4f9dea069da535ce9158f3f4aff2a0e21fa254b25cad2216f1f4be4952d7247ddd328b1d8ea0cc299b03079f65575edaaae6cd73cfd80182516128b799bae7db0ed1b40f955172495f23fec2bb598c3725e1e5e6e8ebeeb5a69bf60ab303abe64fa0e085724c504b85d6c917e9b38468bf422877b6609dd103c5a9c736e9eb59ce5386bade5b68f5c0feace9eaf00b89341262761f3a7f471cb76b4d246e9d64e20f3676a585aad5ffafbbbf3b77ddcf6e158cce259ada890860129a24dfbd309eb5813b7e1585cf2d50ff4ee9432f69d894a29a3633d90351c9bb7226476bed3e9d7c87dfb8e92b51f0e87e7ab467b6a9a264b272965ec75faa5d3e2d43eb1f6dd50694b320d1754f185182579f2882dce4b2ef2d469188f21a610f336f33fcccfd4987d2be8ee5ecd2f474ba618a8be3ed1c9178ec2bacb4b2790808b3c4e1ffbe9438221d97e0eb144ae4e919cd2e924e9e91acef96ec23adcf7d2bdee26edaad351f77bdf221aeeded8f4f66e69fef49cf953e9f31ace41fdb3475d759d22397d15d62992737ac9fe84af532447f5c63aaa7be02a25925cc6ac8ca9ae8ccd2b63a891cbdb1db9d4d529a28304ebccd8e9881f9e6201584f4f38e573844e9104c818c547d0cbd8288d80cc03a94f62c668919cf9c63a454204f4bbe7b4d6d337619d21a8cbbef1eca12efb898f20f5532cb07fb1dd4e6d3b85a22ca7b8c24896535c2145c6594e71c54f66c941460ef7f44aad6d5993d695b9f5ceceaf65adb5d59a98bcd5bafc6aebd277ad3bc1d66dabd5aaad9649ab656262d26add5e931ceee9f26b59af7eda4f6f5f21545e97d0454fd621cb25c0a1080a7b28ea8364e90255efba136f7e2578dc91b95b7d37aad7daddb665a62a575d7595dba954aa57954af5aa52a9a8542a2a55a57abd2aaaefa6e426df8deaa28b0b28bf9893937f46f10866fa1692f663fd09ae2df4aa1f4521d36da11663663d7a2694fa6edaf51f2e8aa416a50f85359176c94dd641249de727d343f3a75f32979f4a98534c1b2d9b32e4e5a70d24ac8774c9a35ec0b88c71f94944d6c82c8b00fe60161941b08df8717ba8011c6592113d7e80f446e7ae42cac8779e21108dcf6c3d209acf1f1a580775c9d9cc395cbee3216b482e2fe3f20de8d7cce587e817ca5ba75a1248314eadbc53f1fad6cb9830af87f94e9671eb591a8738f7e597e4bb393961b9e3cebb596b3d8e53bd2cba93e9fdd19975f23eb90d65b92af7be88293cd6bcf25f7cc79d8c4ff2dda8dea1dc8e7567bc6bddfe6d87a94ee912d587a3749356abf57e0a8acef6575656ea0baed9d6df8bbfd795172060deb72f9f415656f01d7fd0bab2e3e5f62befa6b772f919e0e5c33f3abffc621cc27ce52c03e0d4f7eb57baefedefac151cf68d77a4eccaca8757c2708564e5e00a0a8a1718982bf34bf76fd7be239869eb18612df6b9e3647de52bb8c795b3ecc53bba7e40c0e0b1f37dfd3fbedc5ad6570e735b61f08efebdfdf88261decddbcb0fe7aee0ae5f6ee73e0caeac83f79f3775ee86ef6eca6d68a924448b3366cc58f98c8a979836589d4a0a06a0c53b4e7edfc730fd3ae53879cf78bde38f19385c793deb2c7a983fe5ca16611ea658477d38c679fa80f072adfdffdf77f3d6f20a07faf4cb71027372faf5bd4d7b2bb7d57a03fa757aabf525a68d995b47b969b156eeb89357dedfcd8ac5618ed3ed719c6eed090ceb277727f79d4b4c19acdb50d66d7de59a9ce85b5a5a5a6caf8264ba626161d158eaaa572b9b666961b92b7c65beba314e2f8cb7c85c7e37302ee3cefc74bfb35c9ae56780ef33f8c5fb3b99e57419a8ae754d2eca9d3e58d4cb2c3f21244e0e9781735acce18638dce9533c966b33c9e577c3740550e616a045f918f78716e5615c1f48ee3c0f2923af83e38a563a78084161327694e56f670d0d3177661f0ae032dde5ca1c7365de868052a0dce5f2ddc604985d5d07826006efb8ca282fa1bc7e3738b4d9d545d9f58eb33ec0ecba4d775de7fa93afa60e8ff6215d58d984425d4ebf1c1d98420ea6f0935d2df7eee8a34776dd74975b44cd2ebcc3f4968bd78764bd6bb97482b2889ac71e79c7bd318236cd523dda2d7764c13f6a6ed635b5cf1a40fa16f9299be821fdd3a25cf9fc6e5a40acbcf57b477cfc150c4c0beb8585f17db9cc302f2b5fc13b5a5ff9ea8e2d5ffddeb1e5f7355b8adf77bc63af76d4b364bfbcec35cb592ab52da717c686aeeed88279fcc8ad1d3e7432cc65c6d707cd3038cc9129e6412d0c30be210e7e1fbff161600eb37a3759b2722db6dcda22beb7a1303030abdf154e677c7fcff5ebe4f7a4a5efd83aeb2b3f39c123cbb86a1ddfd64fae6cf1debbba238f1f79e5f7acdb554a5fefc7293340eb2ba72b97f9be3f20ba1c528cd3faca5b5fe571e5addfdbc23b564edf5fb17807bde98dbb09da2f8a77b0dc5ebef2f89159c69959aed5965bcb7244a61e20424a99b1945b64a6b87f5c0c30b34bf8096217165dbd65729897c3b8bcf84cd9143287f4e8d1a3478fd28f8a726f787fd4f0de971ff547cd7f7d398acbcb57c7263030b8b57a6bd56ab55aabd6710bb75c5a3875dc37d5618c5fef791a0b52527088e3727a971497a7b83c2525c5e52929600faed2d71f35a7bce4f29414b0033bd0e547cd2c9c7294db50ef82b93b949750cefa6e70e8e2729b4699e28a2cf2c9513860de82bbb1b6546aa790ef66e5606be5f47b69799d36566fb9366ddcb79c9335f82d2fc91a995b421d341e86415cd2c034a771f9eee4f626ef685c1a4b83e60403d17c0a6991a667351763eca1c0fa537f562e3f2e1ad8b978a87bfa015fc053104ced977c6981a720c89911b81ee4fe8b5977f1bbe9a130ba5a8120ed4131d2ae7e17f3dd4031aa263cfeb09d76518c508c681f518a7217b5d8f5e7c323e7618afbdca59519a508c5088a51bf64092ee9b4574c81226cdef1558b93f541c0d485abd4f202e38197e2a90637445dfda1d34d1169e04d1149ead23078ad64925ac904d3b27164f4794a9de4a32cfaa941256da2fef47cd1a016c7139db5b6b554d3eab6594e2b8141f39e7ea44c104e33c6931178904f33903690329ac87d13d77525cf337d5f773a953c14ea03c1d2898404bc40c02b01c68028f198c94b6850bf28518bfdd5eaab75a6485227229346bfe49e7e7a871b4cd7f81d8d27206c4f750908d3d53fddd30de6a461f1788a224fd786c7d30e729f12f5ebf4d32722b48adc4f059540958aa4a4a494323129a9330afb88a88bd293d43dcd48565fcb4a4df4a4642a414131f14eaafbd51ff0a87bfaa14414769aad4e3f292625aa939386614e3f3465ba292a66ea09334585e9ea5416a62bf5859f1491514ec1c8d9a712f6b8210a4b3537f4a1d50b674a116929a21f868478f974b4be1baf55fb457bbaa44b3b559c22724911bd103d6e08009926e5314544448f3add74204a70b1d2950063aacb8b2e59c35dd6c068b2a454c44c58259a321a48a5a2a5567597ee3d0149992029034489c74e369034faa719c81dfa239a3228ec84034a94fb24c483dc2727686f95e49e82205d5fd30d8fa7a08abb02a96eba272348191e4817907459950a9f82205d7d4a346d9c7e682065fa23a522f7ed294cc68266f92494eb0522b9e902a56e495e4afd7443a0c3c31323b9eaf680b1d4354ecbd179c3a79fd415814e726bd0999913ea9e88b4ab0fde53137dca9d12e0fc78fac96d7374aedbe907bc1c90a42ed4f68149d84a7bc3a7d8e9e7f4236ba490ac914b38a13eaf439950256e4369165529aa278d538a48ca8c29a21491155648ca28eef9fd1ab7d76faf78ec6fe73aa900505291c450e6be5191c42c6bdf4024c09679657a49bf647da9a45f1a1eb79b7088a3bde4b548719448728c10a445b963bb769c4da660006e7887f6fa1940c3f2f257560ad4a162f4cb8a2dcacf17d8a0dc592f060c259b27006d9025f2d91fcd6ed9e211472e1949998992c2b33f282294142d4e8be5872abaa82a50446400ed479414794a812aa230d30cf4509f369403577934cdb6a3a4e81711aa8a7e494db35f8e96edf6dbd476c81635bcb298d505283f72b21b7209f9840402507e34cd72e759a5b3253d516c9a4999d92131cbf3f2a6990d02426c51a2923620485c3d9cca43394ed6549ce6c9f4146b44cc3c6ab93f359c5b44cb7af24173c5b643c2ca1a79834ebe0041aeae5679c6e8975cb56b72d9d485fd4cbf28ac797e560f71409e4c0fc628e141d6507c63668bc116419e4c714a0520789e0ccafe4a4a498728e10d5918a184376091fb3f9a8bdc425dc8a32793bc4fb09b808459226d9b1843ee4bef9cacf1b277af5f40e0bdf777e3d99f267ae6fd7be75ddbc4776d90f7d11221729bb67d9a7bb4d85e6e1bfadd9a89d826bc56c21bb6f0b80fc7b3433a20d4e57783ba4ddb34787be8b4ab8d90493d7eb4d8ef41619e97bb3d237e7030e88e8301d1649d36a866676dad1bd716edb9ec4919fd8a479d5cebabbe4b3065cfcc9c69a80c539b91a1b6587ad799ba528993693748aeb5564cbb4963d0cd3929a53caccf54420fd2607d8c3af9022c39cad6274f61e463359e3cabe90de0cabe748d87f5c9f6dab52f7dacb684c2789833674ecd8779151b1e6ec0011c25914d5b9ffc0385b1da3559ac59b3fd1ce55692ed8dd1e27c8b33c90407706469afcf356e3409934b204212590c618311ba7041cc7e2561262b3082177a60840a245011b397d29e93d6be01f4660f1ed6276bd8db30e70670669987e05167b2e6d9bef6edadb53e99a5695ef5b21d82c23afc039d1608da0fb8218678021c250ff9877e8d609635e307b28907d379b0e95769bbf5f67299fea803788b130d60d5789ed0996cbadbe9fe52cfeb458afd7122916727c9983c79361093939457c95b3e56d60a487825b898cc593eaef264e570204554503ecee439d680f9c88394224f3cfea6de72e73bd6ede8eaa6de55afd3bc960b3e2575d645bddb3c94fb5de59efe72490e73e7f14de570c5779e3777543c4aa35cf2586eea2b24ef78006307d9f38ae4eef35aee4a133130c7c560c4c0208a6c913cc4bcbf49f92279f7a7b4d1bd4f254ac262f494711de46ecb0187835290c90302bd1b7425decc6d1de67ec7f7f41caeeb291775930bde062a1748fccb057a81e2f2c2c4eb3ab0069f478395a77249ce72c1af5cd467105ea09818ae9877285eb7ba40316e22832e25062a300887b03091bb162fbcf305304217e46ec5077bdded5c58c06a793902f6c797918734ca249f6f0ec61392bb963773c5c35cd4f105ff7b7acbfdae82fc72815cac0bf4e2e1056addc5b57a71bacced5e78e1059f82ac7281623c06c6b56131deab141144a5a688022c8bf158eefc8aea2780217381142982cb21068ab912ab5891d4bb17af0b2f90ebab981817aeed82f118efe77081142179087ae4f013b10499b5d202a3e42f82e4f002c138cb058a598981f1935b848c47029911cc78bfa9f7c810018d8732df72497eafea2932874030ceba40312ee3d676c1787f35cfb50062deef6478dd6db9403167b940317e182f8171d60a8c77335ec7ba4030de42720c14e31d8df70bbee5a2ce724f5fb9df73b830de5dd605723dbc40e2552e50cc53627c7581504e6e115c36c140310e5ee6f67031f19d0e20d8018997d7dd22b89c7a2701e07d89acbaf3925cefc2b831e01551ae2bde6bf3e2b6ae0eeaaa1eee3e7bb2c68226d88027978e0169942dde5171f55e9a2585198ee3914bf2d4e8bd169bb22806b714807f992dbecc378f926cede7d56a7784a4a38215f70ae43aecb5d85c6eb00637046e3374829d098fdde5aa9c9235be78d2351f234f2fb70c71283d8f926cf14eaeb57253d45c2f5f7d9774bdbc64f955b07bc2a0eb26d894528a80aeb55a6a2da5b47259b61343d98e33d9ced0d9436514c669efdb9f19a10b5217140dc451d7764f5df6f68d06501bf391ace9db2b66b21d67b26d5c429232f6363d5aa16c1fa35f618e7e8fdc629b6653246456d66383f46bbbc55ca6f29d0562b4b2920a87c70e24657bfbedda202d5a4d03477994e76165dbec16bc78f1e245abe572b55aa278d73bd1e572892f5a202b77cde22c29f17abd6bb7bb1dcafd05dd5c85a44c5f6e24db0eeef42377ef1ed7628a09f07bbdf67d7e1a96e0779bfe3010caa3303b4371f73e5ab044ebb87b2fdde35a1c3913ab7a95daa1afe918682f21d3b7ce923532c5040ccc847969dd550f91c187d382a9ce64cda5f6d62295ae662b963c71a98847cacc12b00a200f9593d6999431fd00818777c5d699bcdbef7b9fe34aa757eda6d75bfbeea78ba31b226b78e42ee777672e8d3fb2566f70df8ec30d91ebb71ef66adacc5b9ba60c5b39eee22869dfce5d1cda372d6f58563cf2e0e179b3bea0e44404f29393698327085fe8e44b96278efb70d9f2ae4b691880f529dd29971f8efc424679d735f5705cc98617788127e4310138c21801dd1cc688c26ef0ac321ca2433046fd82c1a25f249c1ce2ecd015f63549d6a08c7596fb152535a69c8795659477a6348033a33c05a527f8a1909c9898befaa9e4279492300cc3300cc330a4a13949f70d8198f1a6298c33a38de84052aeacd4eb0c20484ef30e67601c122c5ba4c1d5a6984e637a637b159aa631d1e01413a04ae31da6d3e01d25eff3b0b291621e5666728b4b9e8252826b8b261ffe2a088214fc280df8d5f143a92727ff48beeff52b5ddb940692874f91a09c1e8584a4a2a09090d0a090ec641a7a9b3abd230f2bcb611133d7d730c423c96966b0d0d09cde19b26c67d0bcf6e4d4a9c927a768f00e92a3dcca32090e9fc2724754504e39eb8e1d48ca299f0a96200f2bcb45cc8c8282638eb47019c7b5e1841ec8961744c0a706589802154e9860074c007bd3b440aa9fb9562fe469119235353efbece5a8b31f036c53210a40e0094312522637334295924b0a9b395d366c868cbae64bdea9dcd5c39bf2d495917be6a85df33366cc58dd98941bb3451f95bbe9cdb83347e19dc9e2ce20c9e49b5b63304627f33364283366f8ccc03384182151d80d0c4c52bf6a86216b312629260b982318a37ea53e0f8345bfba130a54b954c19dc233334877268b2c629062b4b879e3bc73bcfb6545d1504cd214ce1093446137dfa668c151ac0717c41cb15c80e3cc1110013e73349345bf90648dfd2ea58d99eff2bbc15aad62c2540acfb8fd8c4ff0a6c63b0c4999f91930463058c01c4999f919d9b421a50c92cfce30421486836f403007c711004b0a239455475a4cd9629c59f514a414a414a47088ac9979de9404aa5437f7e1f6f07a47db93c790a7e6112c814172c7123843569d2869efe1de685d7f37dbb6c5bdc1330e2c880152ec668a400612becb08923528414e87d143614042d0c33c0c190c21fd32f93c0c9f7e9534894a51ca69eeea2597e42697e627b71ee5cac8b487d5353915e2d3c3ad31942b93618ce6558aa64a519e33405a9c33411acff4a81ce579131ac031266906c88cfe9c213b31b9333e33438e282cc7e75590288c009f5739a29244613d7c5ececc66642d4e1529628ec81a92cf4a4329cd69ea55a45021ea571593d21e4e739c12e094d2192133ddc3f56126296b01ce64d1e29c39aaddfd4e96ffe12865209ccfc8280c07c31851d7bcb961ce8d155310014fece63bb11ede03d6915c5011f3e13bb11959bf4af9e5314932e66524a53ee3b397232973048e3046a291949991753342fa45f2f9199f182d4eb1c52a80238c9191949934a647cacc6301ece1de87bae673dc13e05e465d3f2dda8f29482d33297306709c391a6766333f315c8c31f21893240307793e75c7ea849d71c7ea842909ac24ef09ceb038c76101153c38c74981ea34389f2547293229333f9a5e72faccf4d3474a55a653d377d0abb0aae423a5947e9f2a31210c568c1519161e5a02700198c0dc01601b977c725a9229cdb18faa4cdfb206e59424d354a67475ea3ac5e377f0dd07821f6832e10ba9f00c9f19424ef74f7c66a3f439a3b16c330001048007991830625ce28b5b29be5b2e9958a14aca952b94935b29ca887b498faca12823138d94aefe6e54349724e409792897556f999d47d6e8f0799abbc3eb2c3c2b45fda221feab15081ec1668e60e0276b68fefc5d1d5a9c6600c71920343427007c9c91e5c9835cf371864c2649caccd3b832e20f829c8c1f2933df65e8f668dc92a3eee9f4b2e49923efd3f3bcf1fdf23e8a4bc8353e7e1693f41d59412ec132436400c719202440fa35a6720f781a50cad471278338cc414f731a3cf6c8f42499e21d5675fa999b2e3dcd25a832a96854180887e2dcdc1e9ea234332c897dfd0c4b42ed67dc1413a04da5ec662d090d2539b994bc98c09cb4505eacc414d70c16959810062b86aa6545c674ff81d872243272b849c9c48011e3125fb4605e5cf07d0b4b132bac5025658572625272fa40936a068732caf33577a44800a0c61d4b6d0476c7521b79dd9122b1838c1c666cdc912bdd6813dcde6d9aec131c72fd4d47bd99230a0bfb23b85a1de5f930c8c750481e43599e415a4c026b7f376eba2d8dd7dd04eb8c6e7e3937ee83fc1880e33de030a78769831400c9623d7c2766d33edc30c787dffc06ebc8309820e6c37762f6279fefa6ea2ba416278aacc5a93aca477b1a4c72639254aaefb027c124b727f9eaa3b524b740907c873dcd6d3ae6c864c9a145c6672e0dac83cb0e2faf14170cac55e305005462c49a30068c1596cc2d1e4d5ef2cee4c61cb9315bc424d1d0949ce6a389498a394283c7e751856790e094a4142dee0c215d004753519e1f67c8724c520a529e8f49ead738431673a45fe38c2c668b182efac57d860c5bf087cfcfc86a005003f6da41071a33327290890123c695437cd182797109ae2ca8348c53f6b920768aa1a111040000e313003030140e88c462d17844a42a22e47b14000d95ba506c5618c8410e53c618630c0100000000020000401b0002f3fa33c23d49de8902398b7862d01a817206309ff6344aa98c8b98342372dfdd6fac262749009cd397b460af7347f7cab8cf4eefe5a340af7a79e783db28c6682d71ca4985f462312efec52ceb214b6d29efb5fbea9f8acb311e0be88d68b7281b141d74bee3ad7f87af9d8e1f70d28b748e161c761427d13d2769c1cd8d26844dacced4ada68fe3232c07ff39fd99a78aa3d47ab878d7ae93831a2e7a3717f75ec6e85d9a5d83c72e14fd6d22a62031f879805c20b2a22cd832c8ea22969301a6d84536f6201abd5d641200ba32b28aec082ac4ae3c6cca8ed0f8a1cca95874a22d4d4066db1a4d09c1635f90ee2c0e2c8d4073b00b6547cd42ec653a447f84665e0a4c27cd85392b428b91dbf06ddaa3cf21c205981fc1c494e56cb4ec873abf029bc88311aed13461e0c1460cec57763a3631e921097175b0ede5954da1411ecdc800445efe8130a0ecbda8402eb67192acc8a9aabde7b2d0c31e85b8c046db5e2f4034d515fef2dd58fe40e4c73405c9c232b0927ced98b48d6b61804a42002d5fbc4d414574f4316cae9d317c66ec3bc33c9e4c8b03901507458043cb39ff650c5b1fb52c29da78d55db441f8c919234c25d726e5071806ddf03a7313096955340c34bb43b881f22f84b1ead139542474aedb66123e4bff6801731228542a712835357dd38f7b8544f77d288f33af6b46a3d75f3277e5cadff086a5b77323be61f7f26fc237d8bdff4df8069b5ebda0e08f4c8e0600627237faff285d5e453ed443c7af5062ad8614d56996c140a2eeac8dc21b5bce6fa3e8deb185a1ab79a2b6de8f83f4d8bdfe4df846bbd7bf01df64f7f26fe29b6cf662e5009f62c10da3f77323b869dc0bad08e22c0eb9d1a017831827afa2ab1c4d08853e89654a4e3635194afef4661004f701417d66de38e04bc3b52d5476dae2e2405f66d9192c77ca5d071e002dce3d6a0eea06c928931e5637b0136d9b807163adaed66bf1dedd02ac625a239a3af9d006073ed32c3ff464c0d7481f9a7c7636de27fc00df60f7fa6fe21b6c7ad5b4c0cec5e31b766f9f8b02b37b430a6a0fe50fb2345b99489312f05fcf799ba2dfa33ae21778e0d38deefab65d30c039a4bc5b690c65519f99f20246ce536230e330923ef08df67bf54cf8d81c84b9375313a254233c7216b79beda4069f8508dc33cf7c1eb2f6c51a13bd2205d532c3959f38ac4a50e10fb07d1d0bfb8cc59b63444feb491f6f6ee85423071c822795eca7d5996b6ba587557994a29fab6caaa678ae640afcf91d5749b3b68485f8578b12e0e48e1239c396eb20d569aab5b4d49c890ce7879ecfb39f67bffa7b5b67c2666dedb162884f3381ffa61bdebcac4bc46ce0495a982fe7c2d4d9f7682d48a222344d71c8af5b06f013a612cc1efea8e56539d5cf3b710ab393369d87a76b53dd4dbe425147c06225511d351db85b68dbfd3669d9f6504e9b8af3ac1f0bb0e539fbc41f04488aafe54ca757db122c2addab0b1bc848ebe3a23ab55abc66ce44b3e45cae5ee80d044f902d24ab7cae0148a58f769bcde9a1f10fcf2c09d33cec7f03b408bdb4ef17cc99c199987bba6ae6911f71b29715a3c8cd78ebed8f550f7f64d9520c7409a4596fa8eb2a8691fcaa6084c66883f693217205f49f84aa3cba65163b117a5270e89c68a272edf758e91405877f94fea783a8823f027688c42860bdb83190bce9b1231c064802f45954ae8c110b096ced822cd892c2c346c7eb1593f941d3315822c4c0190fc7d3d3c0c9c2a491cb02a31bb6668888970b9bfa9c8ae81724096625aa3117c3890bb27c8a521b02d81614f3fa650972331d8cb3d6c4f5d6a64c621ed923698658f625efcfb09ce3fa5f3b95a3ca73df66ad6aef2a93fbe35e1186b2834a00f3cffaf45b30a4aaec778b2185c49b57ac9bd51d3bf64f4afe2b82a8c480e357b1b2b5750987ee5e61850e42f01346a8a0493ee3a63952525bc578b13012f16bf645048acbe2a0853b68b4879b8dd064eef4962d573a9ffd15c8c2bcb96ef60ec6d3edb4cf3aa445f823bd14dee4d55d92be76f3e89a82062709dbd96ad23165dd91791bb9dd57aee3abc75f8b0b46212964215c7ce4a3ab49327eefda85fa6cfbced0fd7afb02978f7c447508cf8c66727f86a433032d9011a82ff77da0ea94f024fd6c23415b4449bb00b9770f8c3190b2642015731d62033dd9f6efa3e561b7b9d5b3bd01c4063c7a542296dd0607156d207543ac34b671f8086b7bc421069da12fcd30f11fa8dff7168859dd8864d314bf40ec1039ba65b5def18868608e2f9465b1809f7638a4fbb66d57ffdd4a1e21808eff2819aaa6f3cabecfdad715ed82ccdc214df43facba0bff11375b59e57479109abf175c652b08a124fbcf21d15a1a66a43e881deb5a440785aec78e3f04e1fcae30fe621ce634f3ad91d9857aa69dab8c171445e8d2a291ab0a3f648f1978e2dc3f97201d3e38e05a6d1b95a2c208c0ff1b9b759c03135d7ceb675047c8630bd0bdf4fb89b0ca2be7d897a05730cc3a57640280850dc9da65df38965e576a19ce193107d8e4b9e4c2db58d1b9b69fcb16af75bc861c6ba6d293689eded062d6d280ed59acb6384dd1091e28dbe57775ba2f5625f44e010a21589b4d80cfc8ee46324e689723af1189bb986c6a4d3ebd5224f647ed8b015f4fba731c3c72dc558465327a88cd20d2d97aab94a52e3ae0289be4d5cc84570a5668058b886da612665f56a2b72bc7e486257916f9ae84ead31c7a7a18e3bbb4c054227078b7f9b17090121f02f274cf88cfb5ce2ae6c1a337559779e8ad99849d0221beedb508fc7118d844d93d7ded6039af9c8b464813baf6234c3bac0417f3fb674107d14324417c81c88991eb4d954d2f9b57fd0c7a43da340e48b3f051e4d0ffc54180a21dcc6423398d2650590062b20d09ae640ee4de02ecd92ad269b64552ed2fe9747827be22134c1e0fc0668caf092e23ca15b71dd4bd8098777d0e7f1af67c98c861a30347b37287492ba0ea79acbe9021fbc5eb5c2dcea7949bf567eb0d90e2de8e79491e6f5411d36cc916bafb29883f0a113f48214ccc2e0290b8fcc32bec5cdba286fae20cdd5910ede05994dfec96d6d1b5a788903e940bbb223448adef7140675d732ed25f9345964956886371630b56b2495fafc39a63f53f196e3e8cde4e001a05dfdcfc1dbf65a3cd0e992ffc6e961dd433b37320b52d4771086afca0f1d839dc939dd35dcf34b55d6cb50bec704befc0dbec70b074c2941d2e48ffa6aee355bbf16aae6309c304ee681d7cb8f2530903b1b04c00274c41e5688185a27388e81eaecda9516f2e25a32ae5a9b0c8e62a720db3b56c4ebdd7b52fecb6ca57e2aadfa6d9920ed4f2bea4ae0aec82836b623feaf5e4426587b975abafd7e27440b0672f25f0d262a297fcb29cda6910bf004c22c93e6919b3f398147c184312b49a9c412271fe837a1fe1799ef2c53af9bc4456a606690908a5a44f48a83921b7884f642755c487a48ed241543e31614f5d137be8bf3e2a15fe92b252acff320d513877bacda2d2b7897a033a603af5136f053ad781ac588e7dc095662abd6de6157b7b66db3c4b61caa322b512eaf6cc3223050ca51529b8692895c7ebb294f09816879fb51ba4343bd6060b883a32ebdb8f46096cd3e908a8060984feb3efa9fdab52afc6109ec1a832f670172f1317192e337abe4039181782ca8b95971960d32fde41700115b2f345ac0fb2aa53ba04e649ed353590a2d8a44e164a19c9e4c5c69da351e215214ff46dcd0532c80d11dfb20144998af29c2e09a9b8cc448c9f44045b0c806685fb151ecaecf2280b9b04bb5ddcfec03d7fab32b53b0170183e6f48ed082bbd98352b74d608d9fe4a2a998df5ff73e318cb2d8dbb8032e864a8340403dce5f87297c22baed218aff581b5711559e2f351b88c866439038a9f0e1b422de24f67c5a635179b8ddcca59d004d3abe4db5dd04598fcc5973a637e8ef61059ff262b25978c4733373fe6261d5384afbf599a1d75fd866aac9339c22964ee3387c8c09130b69b9d36e3f31c76e92785ee1db286f509944db8b7e41ee83f7320193fefe73930ce74f26286d2176a48362b7ef52d3f1a1a807abba836ed4350547777f191af399d9e5de23306899e7f97c6c9c145ae38780f9f9c7f50b74c4c3f9f5a6b0c5c9d049d68214a85410f74a60e990a2680acb0f90f1fd33452b6393a2e941824a94b2d42df2ab67f77da0c852a87e2896956cda621930c4e3ff37962f9e857d48d70549e63981f7bd5f4846f54dfbf98a90662da6b36651fb556aa54a02ecc440e9486339ce66539e3601623ad09985033006189afff1552c2257307537d34870640e75c4f95546f01dbcdaf034e80e282e301b0b0e365913b171294804db7d06224459dd8df6a708bef23c29058075d0639375c828cd4c14a960493dfed9b4bd3df0347c88c54c6a8cb01ac423d082e57497da0d76c159d81babae755fb1a454bb25007c2aa19d92401696552f713dc7ac56e83347fd2c36092704e94071eeb69e3a6f1d6bf1e05ee976a5e5784b0e65a34e1705478fa643f9c5630fa911b1a9a487c876d23030f6ba48242fa05decf4356059e51f76069b0dbae520f7c2f2ba66aa3ed9543c8eb272f1fcd4f0b7d43c6e964732e9f01f496daff3055321f844ef4eecc69eccfc03aa0b3e4ff98ce361480439f6cdb57b4509d55835d1a9ecd4b878cab22899963520409ec81be9cb6120a92c4a30d5ca0eb575d737805a73e7774b689d42ea2b4363c7a06a5792461771a45323ac2fb15a25e40c92c259341341d56f94a686cfe48454b9fac1ae5319a804c7a146b52b5630e2874c3c610a29c0252663c0a862248e9266012f08f320a80a0688b094d896ceb8aa60338831a1060c853f2b7aa4dd307d52485fabef9333e72b659d51263e65f479b1c497dcc050f17e5916905f9e28011e6c6308ee6019c1eb0b469a53f4f395aab47ed0a3f52205f51616e0506273f4de888124f9c20d48e6b6e88276ada21807a062592bf0aa9d4b5663861c4c586069b8208dbc6f3346995ade1c812219e5aa8c684f23f2b2df93f8714a236726b4e5d2abd1e3984775ef80aa57b77a441d53bc30ef54d7caae31b1b525ac5111823dbb42a616db6f870aed9d56eaf5fcb9f61dfa5b1c4a8b29919f4b981d82838a854d2c501db035719ddbee9e76896ffda5e8fef170fbc90c4246a288a386392d07335b028cde57efdcf1d91537eb34617f457b2121bd99b068877cdc32ecb9c32421a5055e45290d0dfa7e3d922efa082014f56080ad728eb672a4661657efc570238a5bcdc451ac6a4970103e724109c15c07c63b58506f3c1975b43805fcd93305f7023fba5e2fce7a2e89f4d3be58b3d780b5488902c3cf4fdea059f4cd1deaf1e1bb27f95f7950b40b0c14d73687a9544794cce50b583455b94e29f760910a03aac62ed7e1e602794fb6d8380d4aaa7f17878bbb27765d820444f2666307a8d0d36a61e0346e36cb29275c786a898e372018d94997c71899d07edc34dcedf8249bad002b50d094165947d8d4a347966ae13073d141a61d7620c790b55a48dbc5cbc6446e9f06f12017608af4c70710d6460d5b5230614d77a1c4705a4dd6b32fb0cf51e22445012203c92ef8d8e01ae64bb8795031473574908b05b74c526b86f268a8d4b647b26531d248612d088906163c44a68e55387359cedb3a11b412ff2a859a5a2d4bece5d0b671f95d08a192040d46dcee3bd397f8cb56fa40f57ac4258380291aa5401deebcf7623e993835048003b00ea9182bf5a58bde046f4cd12689ab052f4258c0e14d46e742ace1dcd34ca6ecc8bab13a2c8423c11f104feb298428001bdc19aead174d64a04001930cabdf7b5d878e49c6b2088488fbc311fcca12b43a749c34900a8c4d4ab799bd3f322a823d84f47f8be0bc4f221047d2224635db5a36eb40e42f8fc41e8bc16c4d768cf743319b6728a645b564cbcaf5128cdb44dfdf9e5876879b95fd45554b7d815d9e6e8c151da9f005fd2c729830aa038623e879da3e97c7be79e8d70d814c53ab747a2d2f41665f0e61b100a8de368fa2c213b72783d41ec200e93f592dd83b5e98b4c05fc3dd417513c2075825cc855146306eef5ebd3250d7ae7f33ec0c1a99f61757624cbc97a767d1afbd80cc900037833622ed397ac389473de61c0d1b3c9c10849b78403444e4d0f620c9b4751260d81a22399efde20b77782c9756ea0fc32c50311607fb8cb8a5ac95523f03d7518591a70c7246d268550e7c54bf640bc2988cbffd88c202afb09b64c77b2bea3ae67bc6087fd332ebe1493eeff43efcf1d3c568e176857bdcece8be8bd58702d84befa7afeb9ea7ac1d24b257153512a72ab26055b782b2a46eb500e177be2965d5c8d3afbf3c01aae3cd99e15b65e40b180ef73c51a30bf5ce6422d78eb815b50cef99c97e3d0fc0b0b958389a8d1fd4f881938d46e6480a1981ee55a8f6f1cc35acf4f503674442d871cde0307c449e5da8240a4a70543924b26cd77946b0043dae112551eb6ed160aadc6a9ba5e8bc66fd100b6ae9b3c331e07c648ea5d0d44ce79624c7a2e4b983f5bff0c0287783b1439439843d47be4f041741dc40a70d351ab02c670451fe6cd0b29d2d78071c6360e65818899115fd0a1b5ffb11e4e27ff9ace9f564ba07e40a1c70fc62d30f5a107ecb6cbe417fb084c3eee97b12f2857a06dfab7d3eea0585055dcfdcca23120128b8954c1bc5ed5ae5e6e0d7c950091603892e4d8d9f7e3b6da4300537db6b9ac8fa07e6a43d4c92c9c451a1e0e9e8cb0b1f30d3d58e1306b666289bea1b79585d74f6cbfd0760f21f1194dbe9017d3b7dd7f682be41144a2811073d79d060ddc4ed8728eb643840f221832bfd49b3286d72e2491a77b3346b65d8e0e781a79ef97feef2ab4834e0ae1942ee0ee579aaf156cc326b0220f56a30212226aad856904a34136137e70c150dc5569c063da5f6e7e740b08a72f8fb43b2a89d04e866e58d4c4f82846683d5632929cacd8e78c4606da1fb262e3b14d8a070662d6fd32b0b3805ca6c812223d9c4beb1480d43d9cc03c0b227d11647f822127ce06c1c2c0b9c44a82117969091d4d618470e255e0ba09b49f012813732c8b7f847b5e9e240ab778afeffb2fecb99a7e9f985b3ba7cae6d60d9ff8fa44f0b42b05a5fd800adfb2a0b9f91f09b6bf5d568085d9ed5a1c0153412c72688d48178d34d23671eb6a593c30bc8c9fd92bffa0c7fa801525a7fc5122c17cf28bdf75740bd042aa02bd5f330bfa6337f945d1ef29ab535861370677e3c84da7bcfebb4d030c94a87f22246b74d31e4536ac11c61b6edab86d7b548718b51fb19a7569ee1f308adbeb40ae1b52d0514879c46609480318900002c4db8230dd370d26b779b72dc865bb2067d388de1f8f0635ddbd6e14d570d9666db6ecaddb512ec70235b3bbc7371ac025b7a614a0927306b2335aead7517513987e51b929a3e750dabb747c447378c8728a0c427e808942a30f532e8c74116e9ca21ca623a82c91391f214698b288fdf43c467c4017c65c58edec3f35c5e0eff0392f064f5904b4b42083f937ebc098fd137164d78bd2429061793c60cdecae64311f7a002584128b4f6d8c11964540a7a502accfc66e0960e4c9d37a38b6b0df1648d2c10ab51895107fb3b529831e07fbca22e03d8e2763f3795aea244257d0e203ea3221162c015d7315153a9a5a3e8957aaec3be139015c89095d05e8dc0e26eff577f999e585865e221c692eeb9e7665e1b8fc3a607866e1634cd11040524aa4181de30a3c1336b0693e38db14ec5e323678ff3cbc7dcf14639f9690ef5fa718430a60b99f1a5225b97b4a3386a0d4cae4c3be83feb8c3ecfc55a2802ad7e78b825f26e59966c412b38b8aa869dd0c6cdcfaf09d6dc6bdb3ad5f15c90f8569d98dd1893bdb72f54bafdd1895f872b63ddd0d31e010e91763d043e0c8e6c2492ec6d69c108db0761968619752a5eac7a215b9882bf118ec169773516614b32c36e735b42222c5837fb035e4b0a05c769c2e39f698af9581a47202d78aca31539327274fba0f1671acd8b334118d20b7d44da872727c0c92543cb9dc09e9da29f09a66fa0e906b3be71499d7c10a34c1ab1b899c37eec1cf9b48ec80d84dd33d17a3c6ebf4dbd0c58e7044c5077305f1584df8e84e665673130046fabd20836d0bcca6f60805103dae644fce41a1735081cea1c6adbc8d6d7a8433619aed4b690813fbf267c045bf1e31bb6b0723502e5c829c8ba5091934955305acf80dfb614d28132de8af4ac9ea4da526587c9d74fbc9c7016da72a9a7821a12c0b7f6a8a8f7a7849996113a971e7aa40448c91600c9a6a403d220627d79df1dc5b27c4db26cfa4b95e0ab36c3bb95980fcdc3a98f8365812fe8ac97fc63315f31346dce9b223e4ae05a77453d61a57913ec23ec6d373efc3046363da199b57240fd8a808e4a12fcd9a4d681ea2aed4d1cf02a5df2c4531b10756f220e035c8e493ddf3e9cbbbe427a85d72c232cb6f16e92cc1f689954bd578fadd595dedb89c09a224c7455bb9e1a0598fff098bd2de97e08f43542e3471dd18e9408041e62bd31ee8f82db17c2e74e7677a573f87e15380e50b8767287922928114cb1f48e801b4860c827f3fc4867f1e8512196c362bb0479e91995beb97cd2018b49e9111978174282e8bb75cc11b7ea3a30129be1afc4b3b87e5858072c8bde1edd348f3d709f77f92900b53c7b4a403e657f827ac3c38c4b49a5b800140fe9a77009594587d7226f1efc74b60b382bd7e1195cf38e98f05b10355b6dec1040519e9ea1bee60aae9ee9780f5a17ad5b0cd21bdb51f606012b40ea8e4e7f801b0698ac332c18536060ad6883e7b93f29b2853c45ac8edd36c0ebc788bf620514b3f23e0127fabd6c9cc612892a56793020ed27a199e7e9ecf460c8f653d7eb853ff1090cc421d06195d02003cd6a90eb3c012bb83b716daf0510a5f1c1488aed4f34717d36742503b4d43c73ccc1005ccb6465ca9bf92071c9e20703e3ca1c80ece26c61da9b39b34906c0399f8b224c1ca59cf45130b345ac372a9ae67c23a0b514bf76a8cb6836ad42d1ff023d2951c5e6d9887e813b40354c13e6e4fbf15a10cf7ef2dad3786155392dafcb62a37fc40784c0501f19f6be0ad0fe2755b285e59bcb278a47809f1908954d90da583d20a1d90fffeb5acbe02a2fe33964f4a58fccb07d2260438d107a478f3255b1f43417e52c4f6336110708a094902111b82c35b29d8f2f7857058063343faa85517d650cc02b03aafd52cf5c992484921cf6d99b0d555e84d00bd26d56cb1cd5c52f6a637a968994c1deabb502ab991609797d8cabc350269ee6d772eefb25f9ac864605e62a797d410dd2aea08ff4fc195a89dfcd08ace06b9b2c6a2c1ff358c6e0b252aef923e4ad5af7c367f186dd70b8ca46a0152bd684065b9b40b5b522a1298555cd670bd36ef2100068540e6d292c8e6a0612586dd6b133cc3319374e47179400a2a7077baacc17d92dda731a45845349ba41d1bec1cc82230e2b51e8c47a3f7310aaa39fed6d35b584059702c7854465f93009b1286afae6a9d72cf81e9d704e4f067e5c13512e0ab8c6d9cf5f57edc39804dbd771f1ec86fd19700f559fe1da6dfe5ef733d9c18adc791cd300892bfde68378f6d1aa171cc5e78cdcf8617ec6cd071357bc9f5d2975141d43b79c0558c719d1cb24ffe2a503d2fe691039afccb1936e400ebc4fe2fb8c3276f34edb818c6a940188db178349a81cf811e4f65cf1a5a4ea2b19cb83f382e8d66b4298721521e8c4379647078ec9b93e7a0fc258f32963c4e475e828a0661e24fb94450444fbcf21c50b700392c4f3f01b3e0a71c60bb70b985892bdf5a8cda6b7889d10527511848f91739604d1bf08a968d928bc5376020a81d905124249e57050f9e2e5076adb84ea9bea8313e2089120eddfcaffb5494309451b14a9ba66c58dca494c69ade387fc31fd9a2d12ff69f840b5d3aed439fe37b22f26ae4d8bca9e0c699d8195e2c814b75cd33cac8ace0ae504d951077297827c708935b20f7af595b04301d0635e9930f8c3240d7f0dcf9f9b8bd803e5612013feadd3f363679472e2bc2b9a538821275e522192e5a9c0ecaf6b15dfaf20b93ce8ea4e19678bfa448191aa6bb9cffdfe7582f9908305629a0cf9ee6c788186acaed31b164414ad957e7b8e733d6240d7c3df00fbd5f2b2467bf5997ad2281fb69af60057dfd22c8fdd6817a2d0d775d855da8ec374bfb947e97552c21aaea486e8192c7b5906587787b4acc856f618314504a95fd66699fd2df24f52b5455912ce96072d12bec45055fa3c4973aba2871abd39bbeaeba8ceb5f5e252f2b4dd36a64775054d0a9b468e7abc94459964c918fa20ccc9c07e7a3e6e81501f89ce2d9cc5fabeaafb95a94fdbf4d448f7c4713ddc4f14956d7708d6f96be994306ea66a233c5315d327ce7f746db159b800551e8ea147e0a7c18e495c7e153cd8051b89857f2c96094ea9162135c4b92b25fb89aaca8bf8ba5f8b026d65100f0dee2e86ec3644a0d222e945b8ae5e3ee537806eff8d91d84972abc307c372051cc82a830872b94683a34a75fa2040f3ce7f4bb26daaaec80094791887a4c9f5c770b44530793a3cbfef0e1bbbc9ff7c3abeb786abc6f1ca7cfd477995bde7b098daa9cc8d30cf9c96920125a7d191d9a0ca3b21d5b60141dfd2849811c2642c5c0a9de9b3b22f98f322975dd241170aa8ee4a044bab0f059f32cdaf0ce1bde2a44ba599388be8f97bb83c7e7fa365c6eeb3e490e26f416fe84e95f215d5c2fe9444c8d5f41e21478265446e2e74702fede041b313089f43b590b085f9e2bf45347a9ad29b124d9938689692bf50a61ec83b6665885e36e242b28eb423e1530bb3c624cae0c53733e8aae78c913214d8fe0071077eef2500b753b6052443fc7dde4f9b5e4f25f904f7addaa8f7b05de354eeae06733319b7945c07a2b62311dca78e21fa8fc0aae7bb9c9185f3c8e06fd0e95e114fe33b3b89f37261e911a05182460e0eaea0fdc32a0cc71e9f910c8055a135e370162a33335ac54a4fbea622c18bf56b7e544e5b897f6758f27783200027489f2086b7b3b10ef09007c19ba2307de6383b85cf2753e559350a433aeb10ad2042b315749ba6c1abbd9a2db768b64cfd8e63fea3a4fd622bf1f625f63c5c0a0892df8dbfcdeab96649bcdd89951b4b4b9e61be8d6ed244b0298cde3c09366df126bb18cf12ec4b2972d1aff0cedb863e7af84b253cd765c8c62ee580a306a6687f357c2544e33a895bdcde3b9abefda68b6ca96f9ee4b998f791aa2502cf090a184256dad9e133fc409c87563aae4e5b0beb742857d1b8ab5f5517012cbff3b05a7c0b096e2203d4d7822ae1c24b40a7ac2af1de722d2bfbef82160dcf2c0769607efb1862614e52cfd0f539fe5cf797ebee7b85435f42a4e9e8a8d48c16f92f095ba52295de663243cd16077e25b8466e6953402def181da5aa6e2f596466d614447e2d18e0dbc218bd11f2e52889a431963a776adac567b018ccf31ca5262e62641449a7c8dbe91582fa511478cb7c2fd7b1add41466c3ef9f3b18e2d04cd6cfd3f4d3bd4b4b33d4b415e20262461d0607d0bac5032350019c8386b315b2bce4dd6ccde7fd1afbeb0649551fab8260dce49d616088cac38f24ecc01f0068c93879000368e96e849439ed90b08b4db5816e4e11c910286eaaba7d8ec4cc7afabe1010e011112b5f72adb9647a77b973fb259383cbe0cdcf2e38fc993a5a9a9318efc9657d5cafcb6e2e86030e284cceed7f3a95d4c89d71c3056300edc031a8cc038fe5470dbac422e24ba2646dcc105dfdae4a5459bffe8662fc1e1dbcb2f4a8e67f91c66aad2bfc3f8ca7f8e862453370e3725405daaea8cc36d8c2368ec2241a38604526491f581527a0f4520db08552a737025b27e82773443e238d58ba4188e6cf331c4189df824b3ed0d0b56d13cd18ca56f978c339f8fee0ba94a7b19ba43b3eecb73c489bb5228941521c70e98a142211c49b4550ced710803445c99d064905c15f059a14c65c0cce4c8b65028b21e09ba216f5df81b6c4bc0eb8213f35e1c0c64bbfe4b72acced61d4776b8cd8ee6430eb1d93ccaa27c59bbe7f80db2dc7d33f12ba6dc0cff464be9a40f00f49f7378ad046de40de95522e08ed69fd073a01688d473856cd737029a64628b055aaf043c8568b6e2f9d18f1c35ec67624c8ef04658e1cbc933198cb3a59003609c35e9677fc6cfd9d08ee80f3236dd476845776c491fb6ff38181148baa5aa70158e8c9f4b8ece3873cb0727f923e9396072c7f6d58f0adab00c77265aaabb46a8b1071586716a5c0494c5e576ac3646f0f4eb2d22f98f4118aec41112dacf8348118348f604111ecd058804692ee8fcaeac7f9ca8fac8e4dea591558ecf415f22374a6230496e9d9a749e14412d603da5df88f74a68e120ea91517d807c79bc70193431b6ae9ea308aab01ce1901c38ab6e0797f157c541cbdb83090ae3b35eacae8ee8d0c059e2876b9815ff8211650696adbdb020036737175c64a4074ba019aa65e8eaae8df9db3214c0fe14547ea89e96dfd96ab0e008ee0a9d16b64265bbcd5cdd6b69f715d7a90844ebc1629bc5f8c3ae50c157a73e62f0f9a5b853efff02eaabc1dfc3c2bba07f4e5069b15cf9ec03c52d74f71bdf6e33e891d1ee316bb25e9b86f558ee02a2ef255e682d6882ea74ee2138a5e74216f38dcb084657f94ccdb3dafe32635bbe5566a2bf5cb0cca34f2bf988f3f44a4320435a3d53e2d37bf1ccac93a5f989e2db0df9b6be000cfee60f41c46d779993082ee69cd165e4de3018df75dd39c519f7b7c8de68e45ebc666da1c41471897a5313885896fc80319a28074c42b3c55c237302acf336f3f5f0888bb49fa4c8c7953b03e92991caf0264d58408230292f584504164e7dac9316eae0c699197489178e5a4f70bf2ffbb782decb7bb190daaf66387f0c09eac2f53b5c0f8a7061362b66c8dc96cc25ad782e6a66c8c3bb704d373431b3f23a6bb4cc8d68c9b431972eabc4bf38787755800f258b3157c93c61c065903e5405bb48bc6be79692d231f802bc13fbf5918d6e57343859066ee4df6603e46ff616c7ccc56e5808095980bcfcfbf0c8ef1ec1693801a1674b881efca32dd5b2e8e76eb05fd9dc3071775a1b04fae103ec092256fef39820c1fbe935e76e9c27be0e94c60a293e45dc1252665c47f7bf2cc3c357d4ba0096bbc4cca003d36fa3f60b9b9d389cf54647b8a065735785c071896e3ac87cae6ef5061daf753e595f7f1d1fa8e21b1993d640e2ed37c560e52f1fd29320ea17fbe4273cfd7e048e9ef9709ecc3a84892c743a5f33157dfe7e6742712e831e9ae8a988c13b91a5c6d234f7dc23a7820e4e18ae7f370c71f3737bd429eebdd0a3eafe8dc512602f7cd4e7cfefe610634b23c681153cc8bfec1661b7d98d69b871268d610aae993e18c8bd2ec1b6fbb049308c3c3fa9ff7a527164faf45b10d1aaf7a8c9b232ac3ce625ca36c609bcb0f6d2f7fa8577d9d878aea4cd7431a33cb2c905cd5bd697c5e613550c83c003950516679552c1f90ebe039d4d488d12c0fa142cf189456237e2d874cf16cc80143bbdf903b47e1609d2b53b97f51c52fd65a950f6b64485912a862f1fe787cb6d9675b85c080387109c89e0570e47b079ba52a260f802587d62df3c75bf4d41b25e643c3ac876f58431f7174803a9c6dd2610f48c2cb03f8112cf18a5d9d27cb4f0709fb14f0f449008015d25cef5d3c3718e691a5f3c3c63d3df1369416c3b90bf08f044760db188f45a70dc672cd6df399813e76a0215a6bbbc44899c513cb744b1e6719c4e61023af2e4b2a38b83e0a891b51b036e0a24b3fa28deaecfc4d286099c5073bfd92f504ea89bfdf36beb0e3ef7e5121de09e42a702f7a5a7df2a355cedf5e038492868a02bf0d9402db1a491d869296412e7147d2036250927e381d128f407ba134a25388c7f9ca1d9c81c65e13ef86a123634bc32ae3e8dc8919ea6ad30e58c7d2b6390256644a5ed9027b9c9b8847cb664390dbb3dee3350e57032a00ce1a8d6b19fe053877d800bcd6d77c01d8ae22ee6b11fcedc51a7083c50535a654e531a5983a6b4d5cf94b6f0d672529557c0c36da4b0587f8664da8698d206237c2e2d6be7696ec60cb4e2e0151ab379469a953b2fadccbe561a370dc8b178f03ee3d91ffbee75a6ab8d58852f25284468f1e6f0a23abeea0480469917b40751cf4ec04f5ae526de73d380a0033c592f545da7eca6c668a549f842a272f7634b97cfa7a8c8684a7c7ade9494eeefda0d82b518e8c5310ddeb9a494285a475750a90d3797057aa2d3ffa95d5543524e746958e4b097c4f5b1b9fc467e55b378e22e0d53b0f76722c5a473994fe03acdc984af68bb4e109a3b743267c27a492b48465ab345bf397bbfdf9ba6b60fe3fdb3005dcdfd04a5528721c750b5ae0cd8483f12218c5c142cd66987c352064815e8946e62dfe51314652e98bd4f319f3cfd144fed1770cd9596069d3f58a25bd95ebd64d792ce2e6c543012860132f02292d21e983e1715906dc8fe2001fe9d0a8640e14e489c1944bdde7e1796886916999c7ac765e06d3e8633d5a5da7202a280a15e08e91971280980afa58ae676eee2ad5db6043cd8a3bf775ce4c54dcb35045f775ce88ffe800ea647a9619f749219a99632f5160bc4c8a16145be542501000f4c60934aef4374c291fd659bd5b342b94a701f717ade05b38bcaffa8f10a95dc824f697113f88b14e08569be2778f21c41569e00c3025ee3f87c988360744501ecd7e878306d10b53ec36163b8504b5fdfd12b5e96f99dd209a8730458d51ba0e38047c2c80727f977b4a5f7c415eb0c0fef1cdebe7a51de35bea932441f4f8ab2c97c19980e51e3ff63566451ca1f23a0f4a3c07636896a94444528c1ace28418d8c6704ed112a3115cf69f00dd8f6f461ba47856fdb4b472d7d573bc3dfaffc92afdcdd17339d832ac73adb1b7ae8a6405fe3d15dec4d2fe19aabe699011d935bf6a05503211e651df27048cc6c30a2b7bb7198cb030514dca44a8568a0be2cf88996332960ba0d247b695ac41aeb8eab321f434b5b4118af132aa3dd341e34cd703270c6ec1bdc1df76291c89f343706e04542e258a0ee473406d532b6898c71a0ba9407c7d251cce3a4006c05bf97a7e7f4f55b4ebe1a24e701e7fa60b940567e769c15953f6a7c05758c42071bd33bad043a2681d3462ead6b68aed7a2297f8dddec05046e4d95518c55ccc6253cb3352a53dc5ae3ccc803101aa34fc87b1344d18c1a0a383f04ab7434a0755ef4cf541438b28aedc31d2b14f6364e5e9ecbf42ad712f686c359fb3427f01065acadbe1fd83a7b20c3e90e42906af0c53de5c1153f95036a6a857a1d97d2fab1fcc1d8f82d1acf2e705c4deac3a6146e3bcdfcd0b1ae2a4606a265b6ec9abc4ec648d996b022bde2721d4d98af4332321e6a2a3d86d0df3dfe64327842959f683af8375b6c263ba594daf26a345ae8e1cf81db081bbc8648f76ffdd096cf06425ceabc4f9e465cb785b6be326c24c633c75bc71da0a93e24c876b9753dff1c6f61d7a3b77aa7107ad90c10eb41375e6878439a3a9b568b028a92b120565fea7eb107f6dfeaa0f856673bf818c4d78b39c1acc05797e8c03c4548b59021d0092ac7af07122bba42f9533f7f9fcb952ed74040540b48499ae8350a53c34cda621100d6062966a44b99d86b76ac607459d99a668ab359f596cbe6570cc03376c9bb1d638d3be9a5f396c16cc1f516eacb60e3216d641b4c2aebcec446c329878f0257a48b791afa128b2bf0e54fcc1c1bfca209e620966ba03bed4cd259bc5e7563cbf252d1d9243869d46bdba9b7719ed1a0fb7e6c9017f56a6221871e69c9e393582a2d1b57518c6e3e3eab32f32a576ca18882e91880880a4402f48d7222e14fe5c1f3fb87fd48bf76cb860e195a1e53b1d594afc96343a4b895620829ffc0e58d6607af887c15cad1047f132de4097d93e8482f30d179533393c2e43fc8b40aaccc30e482c3deb971ebf7e2c0531c3f98c5cd3ced5940ab880b0278e143b97367e2be5b912c9601b155ed495eb4d34a0bfe858b99ff7064fde287ca65f24a1eb4124dc15fce08038c569c167cea2335bece0d08b06fc539acd7004cfa06d7a90c697ebdc98e2d1ad04139a1f18f484274ab41f9caa06741af6d8e2358bd406df87858148c31dd3cbae2183aeabeb34749a7671efc2bc72c0230de70060da1cdbd31e28029c5075ccb58a531720a6820777681858d39cf9221928467cef12d9e708d1bee108d103a6aa98c9892e222f1bdf25cd75eff22098a87e0264b01ac1439c9726eb6b0d140bc315008d7c4350caed1f65210149061d5bfdc70dfd1fff00ea576c1da34a80b2bec26106852ff41e64e328d76abb3ce7ad6dd30b6aaca0caa8e0fc9971239a0daba5d9042effc05f1c05c4f343a95f9d282a9bf4ce2067ccc9ce33f863b29b44b67c0b63b3064400a7f12b23107c9cfb3b4c87c44c6152c659cb3351799dbf9ad95520f0c8f02f952d52fb0a1680763022b6801a31124d553a989e62056174a8abb433d8c46410c069b051cf3ae48528458f041418b01ce7f073e134fe1c8180f93934a688ed56988d8d6502e2e9a72ce4ac5c963195e3ca72f86b408a6fa7bdc3a2409e59fad5f011af4ec358d2151168619609736941072275ad3a82f95c9efff100fda748af7fde2366e8cbbba521cb6af4b72f81136af2f1475e741e1829face541be33dd8855822c9ddcc33291321957577d7077fe94394f7a3a82fc1e6d6b58ade04b00099517c4a1490e9416d60222d605b7e269199b8d6c1a0d602916324b9ac359ba973f4e2500b3075ec90a10666eb38a03638d15e798e27a52c62c7e6a9d807661137796b1e10276bcb4a45f8a8791282e5b35315cb67b5900fcf865f4852ade382a13c3b284daa321794936f63ca2f9e3c0a8812052b2148f0de6cae44f787efaec9424561414d4ee0fb0afa27eedcb24035c75ee78acc5dc809e321d89a6cd56603e83b5e86ba26ca38666a1b4ac22a88224480f4f6c306fd68678cfe4751a10e31e3e0b34b631a0496c64f4111c7e8136709590f65f6716ac9d541f47fc4e9b6bd7158f256756d875002b20ec31bccc2d1784218c21d6fd9e8b365655f0fe08f6193883c8b2bb4a9e2dd18c807e2231896078612dc8d35b543dc42865ab688ebc5577c20c8d044d5747d72d2e6e003a98a20fdc90394fdc9711eec050ee9c63f08be1e65c55f69f7fcd4fcf564d1eb67b402f4709f1882bfa3233c8ae6fc363e5013e7619da72cd5c00d325f302c063730aa13d0ed3456489997464ef33b95aeff54f6317b5fd7d370308100234ccf10c7d189decc3766d8e1293d242600d1059638ca05daa5dd37ac8d4c5c701795673cdc140845ba581e15d6ce1c51e897ce179dcf18d1a7fc7ba7377de1505b43cca9c4eee2aa97ce47a4fdcab09934efdca3ca8ffd1b9d99e247e55b879d527d5a85526bb12b6a80e7da5bf27a3b5789dd7e0ae0e388139e3bbd8d1cc8764a36f9cff07235804fccdbd1e6062ee618c4ea3e64e9659917cdfa778a2a251e09a68766560732167ad01338d539b80339afa40e2518f29e4ea1fea45eb5331c0ab8a2aba7810566818839757d749cd40e232ed6f3a12ae6f5591dd8d0ce15e3478e3acfaffc04e27eacbb36d2986ec8ab7a14d0331a847192e17b68bee463d6057c5a3fc4cb2a5e0046121ca782fb5c95ea7844c342052e72385f976b3ac331b3284bab1ab745abf61683d253c8dc71bbe0f208f04e20ec1cbf7eaffac5693861dec3f1b21699e7ae28d027388a009db81e6683df161e73f183b26d494200314e18837349d102f494604a564f4adade0809e0f01f11810e036f3f7652e17f3e1fe9794a6ea0cfa05bebf73f6f1f94fe4559295ca8b2454eeac1f201ae01d7ad263151c00a6be6b28b741459ff5144f7af09e9621fd375c277496842b1c5295d13fe61f0145bbef8623a6b5f6d67b38aace0d22c27679698d1614785beb3029cce84e82161fb3b4d5ce50aef6fe60773e0a9c80f53e704047e336181c74a5095150999953fff50db0ab4d929234eb559df585650721b7bbae4e74fb9ddd933dbb88b215ba67749d3ac5af127c7a2ef3a7fc35ffc437bb99941860cf5abe02f987098102f2b0e6efe4b7ebd2ece123663f01190785ec3857494ec1a02b1f835603282c2782818f627100f5fa7d07d6146bfae4f3bc7bb626aebbc9cc5e514e96715520ea051fa0c79f4fe2e647f6e33e33d003ec39db9772d011f46634d3b677165a2d93465b0737a97ae4a6cc40cf8d4aab6def2994c7558fb9d21e3b8358ff54c89f520bbfa68b9d2f9f6f544d15baab5ec747079f4262c7a0bc205b5aebbd84acd7dadd0bbb99e16a53a0bfe51064bf368d13be6944225fdaf83c2203ab2614b89ca92ab530db6122e840db436aebdd34ec9d29bd90b3e6f668892c5163266172ee544790a283144c0ab1936f4342a6bc6da3e48ebd4694da39b28d26748d1a51d93a2dfb17eaa24e0a6aa23682d3db7c5f339592e9ac16e3a9011a5f10987dc4b96cb40ab32f0de58c9479e150fcb8e7f966777d6bec09ab79b228cdacaaf55aec363d84e11545a9749aa96028f7fb904bd11c9c74683a7921173d788309cd3baa00cf22f2108ea35fe3f0a50a6895ca93b019d9ea73cd568f1d428cc77e2101ce0aacf515e79e691aa1f1d4f712eabbeb09a009622d5394b0d0847e0b95c87b8d479ba246cf9fb8757d6a5a3882ecf31759aff777480f8ec531923af2a3bff18f8cc3cb2ebbd29f352b54a64d2e1b6381881a877c1a37db0388baf122cb35c3551b809749e08587c3ccdb10311f6015b4439e24ae56a08e8c71d222daaeadfdcc6cae79efa01e86ee8588b3d7878a61fd52f22d082a62667baecc4057abd9ecaf0e76e974370684d598bd2b97b6e68e26844baf220aabfba67569c46fdce78456cf0d8900a82f2f9238f6dc38afdf1cb667c80be9a33aec385098b636e861faba027f18ca535e175c50b7e5a68462a0b9570efa6dae9f06575fdfbc7fbfbd28d2c5f31d7503d631261270daf52a33cad9011959a0e0cd56e16d69ae88195aa4a64e9c0b79dff20130fc08bef36aef49a6628748580c773540d454b862b0d7d45fd485b83abb224e4735ed409a8d5f5b3aa0bb847dde052a5f9d57432b3db0bec64912f30e899ba60000d08067e76e10b028e13cf7c5c1bd9537148c63b6e1678778cbeadac3c57881f2fccc1a6ee7428328bf0fd37eeb6e63516c08ec7685cf4a2156eabc778658df578b67d96bf9ee202630904243aaf259f49c8fcb1ab79ecd8c67db72603bd23c7cce292c532cfdf3f1d9ae3a3ee0f6218bbaeff56f6a74a6a568f93b4439d92284e109d51d22067e3f0294542f415bcd54a1401114c6f78440b646a4d0b7d1c9e0f0937ce7d12acddd1b085810e4b1a7d11f956e7e74722dcda6f22b3abc72426e43194f811373df21001ae929c15aa322404cb703354589888249358bdca6a59ccc602fb389949121722d194b523f0f1c285b4f78b17c2805e07e6e879d4e0d62bc8126ce5399e61de4dd76bbdeac93bc3e0111885cf42bc602be30bfe679103e5382878e0d6992f1bfb7d3db580f224a95569487690f82cdc026ee3901a527c067242e3891f08f5af8b3445e9ab8acbac4798d001ce2d6b10f6550f7c61e56b045602b6ba74889190a2c5e2059561db2f6cbff5c9a0a0fa156ff6a5cbbb7264784f2ae0bcd215e512983cd95a8899adf96ac99afc47f890b2f1bc752c91ea1b9e48498bef6c99fdf7d047925127b32389e20c9b0803c6a5a09dc93ba452129689a08b5e77180e1b1d79faee2dad8ff5bc1ead63cf7f06ba2579c977d9798af8d001d2bd6d9cb8e1c0641b07a8bc2855f41adf03017653379f53f925c086e50469bb46e269ffe5b6837aec0ff757b258a5187a136472d8a7562a11da1b72ff7b367de68657bcd25009dde4d24954ee7c6ce7be482963c7f20ed3b31df0dcb65c77e8646c4cccc494620d44472408570f8c8a890036651265800f4cdf6d2ba215392fe7731a92165a429611875201d3aaaf2b66eb84d4d9c3c4a3d3d055180a936bb4b5a4638739030cdba6788f9d17462b31e574ae43089ba3360986cd2c56ad28df63d6df372059dd7b8f2ef574fef6171f4a5ec3eee65e0050c90faa10e7743a96728d862e7e914402d7c9978a909d96280469d237905faee6f9913b5420ac70d6238c7234e1f9962adb18dfcc4a09a6ebf59ce25961f67a6e76d4ddf201229fdcc4f8006034c5ec06c70f82b0448bef3ee26cdca7be6260f119fb56883e82ed2a085e8e0b35bb385a66c9e8953053d8f5715573da2a397ae900f451cd86e96912bcf49e857a83725b24ade751c86883fbaff40b840575407cd661d0398088dc37153681f46e8f480206269fd43b9cda09fc37213c6feb56fcf792852bac721a1220a45102a7965abf7670482d7dc18fd60380a84ba5f0320b7f0f90cb942e057d037594ccbc09cc227d6afdaa541a9a762170cc3208c109a62c60f467cd071c2aad73e4c0fae91ed74adff11d3582ce896c21fe31e555551554ac061b53a30c2dd29f1ea9e2140da45bf231994a5e5417c60e6a4dc972ff0034707f31723817f24af9646579ccd01e7db945d6e2be3beca78d5fccb15e2cca9c3c7201c43992262c32c2a2d8de16441de23cd14816842af30e253ee969f6b168afc0502870567c3d854f97f1fe051b2ac53c47d01ce37083e12a22b4baaf710c9a2b69bc96c011061fd982abcd062c93ef8febdf001f68c361783dd6b9df7b81766f1f1e1ade053353c6725c8d77ff9eb03b2799c58b94683ebc3c2ee831d61df6066ef661e2b5aa7e340228bbb26f36f7a1b6fb116a448fbf716c84e2a9bc974a46cb9976165cde47f2546376f776220cde4903187717a3cac8f2d91965384737a70212bb57302fa1b61f0a82fddd6f50dc94721cfcc322baf8b88ef9bf669e0f2f98a0dfe8422515c83d6243b1da3576bf5e8e3784e60bee79d52637c03e3e412754ff33110dae56a214cf443600e5915f5887f184abc8550cdbd4a487bbe3b4ad9c5d8eb9fa33fb8d0a56c18d78670d0a8d840dc48126aef9e2faeedfe97fbfa34d7099df28b670fa87d33334e5539e12f175c0b643fae864465f5677520dd14193522e526892af81b9ae87f309ef531f46db9ee201d9e1d25f884df4c42ca4c5c19e2fc64f1d159c3fbe7c628fac0de56a361cd2d91fbec5a54cab4f6097648eb4489f7ee559d268130867ae28f74f746d23afd2cc5a84217bedf5c46514e70949270c94718b0439a5b60052ec0a4c3bb9fd10fa1e98a22bc41ad51d4e8a940bcd875df5914fb61b01a66f010a2929c7744b47cb37f3e59202bda8c49f4bdc3ecb131e9ab6d4b0278698d0db9e502128e6aa36e5ead587e6cf179c07044dfea80cdb1fe71acefa477d30208edf3dbbc8d8402a39d11c4d5aaebccd661a3e32789fa13f253b77b8579f1312ef675178ea950012e5c07de27401c87c7a9438dac7d02592c3d04a14b13cf0626dbca7bbf62a8ff7705c3861459978381b3db4a0bf8e92bb60022eeeadf8233673123db73b7a571d452b856f7455edace5afb5ee50e0b2fa8893e13a1e5b8e9cbc3e270d82ebb0f4bb79efe3fc6010190abb6b248ad9157fa90bcf3758f901ae6e169107904abf82ee0cd800d8166eb6e1037ab8fc9b4a4b697e33b158ca2f28ba6a1d0c7160d860feb34c04e07b9122f51ff13c183a32ef8d02c1a31562f163254911f96c465e925a280001d7c1e3b0156555754d3d4202ee3cb656a4c97c7e72918d72014aa428c6963edb28bc98305f7fffe9894c616c4c00d3627644d71e1af493eb8b3d910640c7bf7005bb7d5650742c76675ea3791865b4027b79dcf57ab87bd6252770e90dc7446f8b85b7612a359689c690ffabd1684aa27126d27efb158e8c4bdeafd216cce008974d9bd2609e7b364900636987aa3f1a3670853f32b3fb3de9f8a19d40efae4cacc439207771118e267ed1be1b2f329bf3f8b4a901638a7f57267475a0392c5ea6a3aadbcc697446d956eb15eb1da62c63d3c6260cac3faae972de21e50d6344138328908a803122fc8a110f9cd832ec061a8c0e7189ab34503762506121b65ca43763d96a56c472277cdd969018ffaf0931f502836bb770f74f61e692a2adcb3acfa7dbec2f01ab453d2d2f8030c930ee25200437d40a0d9c3a0216aba876750af0103d1d0ca5ea1f73925de858e45e7cf458ce7178d49b5f3ae71b0592d94242534d502edd0c8e38eb702a9330dd2f57acad81d37798776e3cbab33e8a67d75c7e868615d40b1680a80d14329e721c3859d6e28c91221349fb04a05bbbe6177ef5163357df23d3c59cd38980f1df76dc1bbaa1889cbfeca4659e8902ce9efa703106d878d756e9f7f94c96a1da7ab1fcacb51492b4d9936a3457a19bdd8f7a3dd1ef689a71d102c6beef36120585b0421f0db6e594394e13d3701515d481f0bfad89e0f521e735306c43ae35d8fb526ceaa2b3aeacd7ce7426e8c29e5e91765442329bf062d5422cef1f5d623fa84ae28e1b3a3de24e93b28b2760558ca2af7c35237570dd51386a53340543016cb42716cf9c5c293cfe9cc973df520314bb6877fb2ca3a9edf5a209fe299f0daefc1425b179d2ae8c3fd42754a6b8fa346cab8be1de7fe11286becd74fdce8d0050b07e067d517d2497b87fd9766e8d7f02045315a79de134638c84899e13b8ba06059f8d42fc0f2c73d27fda092838d1bad5857a2b801f8efdc2b56da7f978bf84e19fea5ad54646098224ece994651dc3d2472e9edf0d46db04fb6029ca536374f8ec6b5589913a71d91c704ef8cfe707f2a29a3f8eebc1a14ab83a52da51812d85b0167a12273b4ee964360029f66a6f840e8649ae042cb5f42f332ffb06f3ed64870a4329c50902356830c2acea0795ed0e5eb367d9b18c7154135ae42cd912672be65aa43162c133826c9ffe15f0a0e693014e6755a8ef26c0b996e6a40bb917958d16f618af96335906435e292ae5c6dca5b32a32f5a7b4786c952e14f5579b782c5b44cd2a67a8ebcb308ac7b414d446b25838ddb0ed27f9a2eba1fb4472d23e5c211a357b8fc439c052d90f12302e0830d808736eb437519897b51fc6cbabfa347227271c31876d456863936f8d2c63af902f57a7bfd28765eca65f2da9bcf57fdcc2198de97af8480c2ed977234798f9b800bfa8705643a843515210f437208a92a49c54753a867f3587d5f92b29a2318f1c0649fdd520f01fe92f72b91981360a04df6431356ea4130e938db96d634efeed064a914173b796e7e1a76a33d13b20c3d5869e9b104d7e8d2c79fd201585b6035494140a817add3e8d734651520ce1678b82023ad6e5afd4175cc68c2e0acc3e3029add4c82662b5c19e460fa51d6f29b5b914864fb4a019b2e9c0275b0ed6753b57c823d2142515840ff74eedf95529670c17d676eb1728ced59ed7cadfe7a69b4431c618a609446d433fcbe06b8be1fab14225e53ace89b10b1542b3d4166dad6ca3cd639f2726b91355b7b632eacdb505983b189419cc16e663eeae95c7a14655b15776063e8275b23fbd459e5beea9b30c9046af96a4d04050eb860173fd7afa8e789b119f8277c7255fc26bdea77ac74f2a4cfbf1b0ea749122bbb54ed4024487bf42c6da9f8b3c3cbef057f29372bc093d15f997d3eb0b248abd40d7bc78daa840be882ed0c539c7b696295208237293e82087bfea4d29268c93736d932e142844b7b75166cb4b5219530dc3ae91813e984c5c8445d013091625d1a2085eb88bd7d17816363edba8b57d2ec2fc0790f03545912a7450ebebb2a2c496ebd2508483fd43b4bdb9d972b1c5c44873c1e14d85d48aa48bd887c1c8672496279c9651b58b154c505baed3fa9e74a55076d95edf8de963de961041fda92297be8febd3e03cd354dbab5ffc11df7625939a46744d15f32d1cdf36798437d6b429f488f2acae236c41efc41f32ebaa06ca956acc325d0a46b32aa05c71c113ecde9b2a2d1ecc1d28b42c0555a929b9cf4e4cd5856720025a18caa38503d7cc841b548553259fd068b6559306ca4571f022611b0e78c257b896666ad03203704832d186b05a6298b776eb78c2a3088e70ef5ab6abfff7f5c166610ea05c3113ed9b4ef26dbaa6322f50728a5239a5d69f57be9864124f485060365963bc07a8dd073c8125a0563d92d0b76cfc1c85814e4317281346dd15d3268f430c992dc8daac3b716588e39e014fb8aefa69ed218a27b47ad7248b19acac708f6de131c9e3efafda6549cd39d27d559cedceac4079dfe97a4cd7543593824adceb828d168439f070fec92ccef2812987d9a7467e9abff47da820f94ef615c2895150ea47a6c0a8305261718444e6ce0a7362ab7aca4cf044b22255ae173c0c971e90ec0d59d8bdc87b54811421c49f2f38857ece1a2932b88b944088e7dbd3ba35b78885cfd73b6d8da70c0fb306d9e43912a65cea8a055d180bebd27c75d446ed516205ef0db7c27d2ba70651a823220f8f7344c4c96cd35f08615cfd293776325d9aa2cfb682a5bef172aa68a070d2b74ad98b0b55e02238237d6c4e1cb14b642bcae76286b7b12b981e2ea1f61441f42b1f9469fc462e5356c07b0bb799aef8063dca85417614427dc9e3d824a08a70082003389367772d1260d5a8100041aa054902e303c7cd3781af4a5a368bcfd663defbfae86fca64e8db1703a83cdf5b52d76df998be1dce8d307e99284f58c2cf337b4c1f105f71d0c8409c3e2e6ad6d6b11c46af369f80f60b115256eaf440e7420e537d037e29fd1e2f2b4776cd108564836841967efacccac3be57e59709d2886ff4e17d1b65ba3507786e98701ef5baf9d2b8be5e54eb6e99995407adc84f0d63d043d548e807fa3a273147feb7b9973119e84027f4ed1ee871298ecc2b4f3a7b473da594e5c4acb504eb0a1f039979f76cc38af74dbcfbe13dfb343c2d39b2ac6a22134c398a4d802150d0a2a814b4a8c2c54c5488f2765dc89c13f24a5826d5f435d98ab5f229fa2d575af18ba1e7f19bd711cae5aae670d1abe673eda11bf8778d5f00eeeb1bd6cc8cb8fbdd449f438b2e4653c3b00eb943dcb4371623fce20f8921bf2ffb7daeb128770fbb4f0b805d6e041ae8b734efd3243c8be6c7daad0eae365ae5eee749c5bf26c89891c5f43b2f8042c578e88bc58debd3207011283b3d2c684e5f31a796638140a7b85bc08eb697e28afcebb9b58b4459e3bd2bd8b61a64621a81e702a3311cbd1824d6fb32c7ea9b7e0f9c218794dc424b128467b36fde0e775de47f2b9825c4073aa4c198260645234d09c4e5a4abe097c1e07029f07a7cfa9a4e14ce93f71d002de732c9b52be709976a0a5d221c46d812e55a369cd903fbb46d039c38affe2936622f59ff5b9f44049b891289effc604f8aea6015f0105f43cd8ea01a66e8cd31fc38f661773483be7f1970d1a8c54e4e9c3722581327d9874d850aea44d20e5ae14efb38c0c44300db83445f68e428907cbc3a3ac97e1eea91cb4a635e5229f53b1c55d70289f79f9aeef48eb76bf9a9a9ce261aa4f07eee39146dd02b3cc2c5b153cb710e5836aead9f7744e0390056e4f6253d9c0012256bb07c0a6951fb32f66a092cd5600f6f80f9c5366b1faa360a37ff46416d8ecaef92de9ee66003dbc27c10f523cbaf681eff381a906f48102dd73556d6edc1cd4b92a3f3abe3eab0111cc9b9352316016490201b2e941705f2a224d2103242984ebd6c8ed2257aaa38625fac7a563f3ffeffe9c9f5af4406d122fd3582dd383c5ccd116b5fe6d182087c1f3457994c6533bd2e81a7af65d63f0b83458016186eab1156f7c7b09d3c524062332db0b7a627cff82246253d50ea8a7ba34f536ba12a2808b00da39a9ebcedb3f10ea88f94b5d4d5fb72e38ad32f4856f66f96e8609872c742bea16bb93a9c6f70b635f1b4d113602ab283e24655e49b587ddf1b821236d57d470e31a995c4fdb7a37ef5ef35914a8103244873e5f9c67d05b0757fb1287d8e4f5db41dcae6a2ad18841e581d3afeaae34d315fc789f4c47b0da54b2a2d44fef3d0c676875be2ad77bd5b5bb6e54472b37c1cc491fac8a8f4c7ec11c9160dc4ecad28848eb897ec09642557ec579a5f5881ebd9277144547572ac28fff42dce6a4731d3090b775852c20952b5e6ae1fff9c2a0d44e3e39e1e3418e7bb72d21965449696e0a17458409cbd1e319bca5cf04de2058947dc31e501124f0ca2938c21417395782d6ecaf21a2b08e6e1ffede8310d349c0215d505057ca8141fcf1901c228b81fe888603bed76425dfca60c70b1f76375666d051c246a0eca8af268aa127c7e71c597a354cf7cfd999e2723dbc2e84050244117c9da8e5951887438dfaec7112910d61af4eea760d3433ab093e05ba6e96b0faf4e7a7fbb4eb46517b9ef2cd4afbc81c7e3a6d911012301e892e9eb8f8a73fa039e55b531ce02302d9d0cb55adc55ac33a0e414e931ce6340e49dbc75b2265c82621604add9212fd22b2733b2dff65aabc12d6a9101f3c09ca29fec0effc20c07a4b102144b11b9deececa18f3b456741d48a515ea114e622d91a4f9eaa66468b99d8123658ce43686d7d46e4b284fb5cf694139c541f697603f46c5133bf094032e38248e2d373ca65131c3def099af6f6ebac40daaccba6faa2b5dfef2fbd364d8775907e67c770d032556ca5dccbe150684c32d85daca8ee3637106bd6696e5a2d51384f882aef5ed1ce05bde0fc7683fe82f5960727f5beb6258c63c6e0d121a9fb81166262db51adcb2ce74171d7ca31d3310d329359d6507b6c7619d523741aa43656b3af8d7d9008347a4a3f84096678900c69da7ccd448b5bc2a43b4c731a3c2e5813f07547dd82eb2b8b9fdcb8dada7139f2118100a5c83af913a4d8061217759b7032424c5927ad1bb8d3147a70df53715cf1bce2c45879ab23d7dd46c5b74689382ae8c0dedfaa6e78ef6efcf2fb525d74db68b27e80b4c2e525abdd20bb114d6685698f8132a39c88383f50f8f63400aa628fc4eb772f9a12f8d8f62b797f82104aaf3ab72ceb2137c6db4f246ecb3ca708d658eb2924c94e0f21c5199b96055726490a154d5327cf41e68bf93fe323f1aefabd10b2da65b151c47291e7d90567e98ae56a8167a3da1c324d88804b371e69476d10e12a2200acc466136f50dc5571d9494620ccb97bec825019c7d3986ffeb9d2b09aac71b25fa62ec488f1cd38af3895a1d920773e15cd4e068f537829f5a67d8e18500c0b30a38bb288101080a395ab8393c94abd0786431da424b48c499a38194e7e8a595984d40b85e872a9e3df3d42ab698db1d86995efbb1a017ba7bd517d27d8d8b36723d840553d09100259ed057655bc95d39684b98117fc2242b9a8b6b4632f6cb1f6a24eb1a8309fe6b4ec206ac69ad176d868ad994bb90ce59d43098ea2e9ac4f806a2105ae1573e67f76ea38f1b384c75fa5a62d94ec3044facc7bb0282669a2db23bf4aa672880c5ddd41b561d146ac4006990e4fe3e2ca38112a011d7178ed8102d08574196c61b3b4c2f61890f59b4e1f40046b93c022e5b4ea4003687f179b087a40795e96a242aeb55976b633d65aa16e9a7c750e46f1787bdf046629a060fbf3b9ffbcae82c916bea37ba8597f2fe12f11ab88b876c2353ff612321710589171c1546bf818cc80f4f548f27453249b66a162882f0624bb9a3cf7f4f5c8d6d0ab5202fee31c3442b5063c4da6398b2636f0c4a9cb3252af985982be0827fdc3572de9b34f571f70f903b52193f8156c7e949ae05e0018ef5493b6f3548d1695bdd794b73e18c1f3ab8f883a1ed9fdbd513e19ad22b01e09554b3e7ec2df0422b0e936af83f8b0e19708ab97bdfcb8f5d9ac74b60b2a40bd12fc08b46d94d2d42d2f2b9e3fe12c4e8717aafcda376e02b373415d9e5369dab2c90e15e0891fcd0f9c8787f2769f177fcdba16c3ac944276e87a3322b208dac73eddacd681d20b2d8134961fc4474403064eabb7c3f43323439053cf974905570ddb0ea170fc5f332096049c6f76db4cb336e1c0cb569d5b1d14101f6b89d66b28a23cd3048341bc0e6bc997fc4ca25d424ceb6211533b27ce4f6caa0c21d9e4c2df91056711f0e06bedac37d46add1f301c7e21a0363c2cf3fdb82454ec8b7924be17ef6dbdcd0dd5e4cf4befc44ee610c9c2cca5f954c63bb6de14b19241c742d5df6717949b678e27c9c8daa0b34702996ef5320849651e2ba5388ca9c1021f718d19fa90e6b4893496056fb30b8e0bea7672747775865bde6c7b454587d6988b664fd6cee6b9eeac9029b7ade54dab1f40e5c81944ba3b1df3345df0cee261cc943660264ad7b4ac62d05517ad7e0158d4d8a13a6df26b11bba0a1ccb68aed0d64ceb532f18be1759544f524de1df653071ce195d465225c5b434a03374af52e6b1c9412c7f28045fc3877be1d4e3c4f81f0b942df3592e27c54a918f14b4ba68eb55f77609a7a649e65fd10c9a2a0b396504cd45483e47edb44c4910b1e140234d640a84e42e9b9002a3685828b716911e31f06f22a9d5ddc98802cf1ce52ced05fa7317e17966b0f3e0fffee5ba76926451f929ad4f218f5f35a36880c5d055f8463804366d6e73f996ba1ea96e2632ae5d7769d9364145f9b58e3ace4d8cde42d63afc2d19bfa65e64950c8ba4b0cced51d371f794f48c79b04b5d1a292e34252dda0577e816d20c67d480b7c891781d0325dd9a0085ec5b1f80d748c3bc76905f5fb1b7b735a6b5181a174c92c56d095324e5888a028b914e03db6248ca7b127d2a1a98ba3f160bd91512568267d59ad42028c7995ab35dc76839ab8a8ca79ded5719d5c567db608450e340bae0a8643dec48c0e401eac9fc83d0889b70afcd0925c56bd41cfd07b19a3420799ed8947d5084431d8d80bee89e8d230d54decfa467bb35a0154f18ec8703fab9324598230745fa6e0eebbfeec6064f9ac17a97de2a376e4242b66d2fdc1171e2970ff470c0e74cd4dd8b0ebbaa351fc929f8dc8d253985ab60ae5a5d5babcdee9cd936798f0501a60a60bf8f4ddaf87694a2682df796b1b5c6d476173942212df66e4a427e4564d997dc723588c151c03783fa74c7b2e6ebfca43fadf1a882bab3d8aa56048d96e79747478ba976ea5f7408402024916a837094c2757b072529f655c584a8833cd27521851056484a24f02b60a8d88c0f9e626628b47d9c5331834d266b534a34b7b69421748c4188bfb3e101354714d9135e5f1f6a35cfa422330fc2494d646be1a36dfff46ad04da678473f1ed7a8973c438128e5bb980b4f446ea75869a2d059f75d2c42126b52f18589880b3a03986b2346db3a8c724dd31843efe9b4d46fc8f2c25c9261be09aaf070f02edc602c4190c4e6bfa9be41f2395fd8dff79950b5b6a6df04b2a9f836c28790485355d5cb2909d3590184d8ae14635530106ff675538a908d1efb6a202f9acf561b8135da817c4ef12b7ac11fc43237b435541c121b565592872330b8f1c52e17c7271194e45cd1e3583227145f13c0f3c7d1054b39624fabcd7ca34b6c48a8e6c00e708188aa998d593f9b2155683ca15e09e4cd95d011cae9b8695aea18b9c31ecae3bce9c822185167a1fcb365e61580b99f2e763e5eedc95c961c1bfa7522571a66d6c4235bb5e47dd96bca7e70c855273475f8b50ed3ad3734087d864ed0c65fa3ded23ba239a8090ec000c5298d0803b09195ca705365e91cd31dc3a642a24f02675596d4ca8792210a3f54228b34f35d34222d2a43ee424094c8d371c12011c80f99e0092ff50806c841f655b1e281828a37a2b1a6d2cb18a629cc030be884c062b1a895d1530dd5010ad68a068d07fb9d5d9ed340756db002c873efb79ffde552283408b862166ad68a46c9fead36b9c012e3738de4f817781be6459cd21f29b748c2b1aaf7c0dd3547fd298899d8fcaa735bb42310d576d2b229365fc60f8288cce54e8e7eb2e948ba5884c44ba774cc42ba6099c107f069a4469bcb8f128d0a2a6a449385c234bb146e59243847c5bb3eeef61e3388d4e1f52e2ed8bc844fbf74b83f50fc01120e44ee08c35cb705aa7f58e4a38d931f9688a96cc6225a0f18c1f03e6d7e263ead801f915da8d74f8bb439a96611a78e4bce76934f83e80fe6da351e2443991447c873a01be8d8b8933f9590722e19ba789ed58a8323e1648723473d78840620f9b714853b226c9aeba4e8e3cdee3119345e184ee74438314cff42a3fce8b203a5acd51557df78952541e52147004b65a8f919e1d234370512fbd79704f389cec83da67ad3d75f3e010b559486e274beb45e6f9aa94c2b205d456580dcc5d34967adde6aa96a8e5e04f7deff4f75230d89624ae69a212c19781a352fa029e8d32601ef71f13ea239e1a57a0146d364fa9d2749c02840d5c00258a44b1af720fed71adf8881647524824c383e327516349a6e55f5be817ebef200492c68578bbb746a9612e5e668ea98ef3850bf56e1489c04fc5fe328df4d55d49e9152811b26df676d0db57e8aed17711533f916b91837077551f2d56a840f2c01c669d721ad06d0607b0f2dcaa6a580958b34f4328146ef4b5b5d7ef055740f3878a9359a530e6d6eeb34c1ccce4a5250b825eee4bbf8c9487fa17cb2ccf5e8aea749f93b870a1859ec12479db13d2291d85b6c1272d757f5ff1a42f4b89415a874e6a3719c99fa7804615b8b4155d2045e0afacad2921f8df7ea670c6ee0eea9874b6a9a59bd4612448486a0a82d33f92cfc9e9d0053b841460201d803e62e93d5b6c5fda4f1e62a1eca226bc5f890082fb1110d42a87b60b1a63a13fc6727414a2054594ba992106d543c510fbf14053850b4a0bbcae16319eb2a74c0ca2da4271ef31fc65ff30205882848d32918ce2cc6005e34aff451964374a10f538d973b8c72d3e5d8f033f86e5c2537e094b2d0c23ed7832628b60e0ecbade701933096656384274a39b4a73506826c4610a1343963aa3d3c2f61a949a3058b8cce1a6cc726b6ff13a549a08115fbe0d5907d31ad4919083d62bd5f89ddf739b4a9081e42a21f69f22cb76ff429f33860c79fd8da25729d50627cdda082c4804855ed65a9d4370d1c7b16aed251024959b99c5d2fe89639f91be0f757f11ec6abcf160814e4b879d82236ce8eff8e9ab956c8322885db90d2e7052fb829236e224238f209c38f7c6f68a81392ca02f0f3bb701a8ce33287ba746c53bba894754c4bfcb3915f5d0e7b0c69f2413dc7a10928c6569d8ad8455cd0c4505facf563e012e43bd136d02174c8d76cf0fa18dbe80ce9b6f166119034fd56759c6913dcf651b08fc9cca48b7cd07220458158cffaf7da14e0d11439f950d0018edcd11e935aebbdf4370db514a00b67bff35a2dc58b790019df582a7a023a8a9477d5c8fae9feee89ed107ad58c5fbf4b5ae262b21ea83c31279cf30739f3e56e065380d741ad924937dfaad481e2a5d8d4835bcafe4d6da752ae34a947b66e0cce5474a9ba03ef828f57455d1ffaacfb212943431d4ee5aaf6725ab3cc3f4a79f04e84ce1a2c232d7c6cd8a6856b4151cc214a2bf543b6bfa2a4d23e0e5055eb1d062eb2a13423f907a7df31d7b293bd0d0d50a1352259c0742508e684a620b9b4d8cb17f95d992a04b7d7871351dc1e721a87cb0a1ccd9baf3b77af0ca214011b494624d8706c3686035d2492bf984a91b4c66d211d38ffe9a0f076cb77866941c3525986c98b6ba1442da66a9029a16989988100c69af8c80c5cca570952f24c7f871d57b93ad79c4891b075661b893e640659d1789657dbe19c6144ae00053788e50f00796063dcd9163bea555a68a8072a12031a3d315a9756d3c53b460d7387386afbee72ae91e4fa338a6a01f4af0b7d0ee070ee29f5891f97086fec1507b628a3194fd2aa4e7a4b7ada2e6c4087033a2bd0ba0676b3c38de973e7549fca0dc590081cc0cab24c5edc7470ea7b5807f780a0da4e3483137e03a8b4fcc23a59c9485c23e165857a971d9008c71050fadf1a492baecc38eff85ba7122243962917679ea80242c1d06bc788afc2e4c04bcf0e6bd8b9095efb26a7546d3ad9a59c89cb9e905a185d579d0b50a2c9d42b722cc748e00312bd64947562917a16aea5984aa3109fc766bbe8e1bfd1f3af43f36f40c0d6340590b501bfd235d25aab11dea681f39147eb7ce11260254672a2b50b631a4b1cfb1906d14bb6e5eb586cb05c26240c787984a8505f85565ec1ab243319f24f40292f5ef4192d91486317aec1d9a983becea53824c29c95fba286c292628871d77ad6709a6717f09ed5b8c12e626e346179c9e32ca87001b84f40d20e1f3798a6878392d481ddea9607293c8019c79b0fffd1af388e008b1a2d80f811c6ab590f865f7cf52245fb6c9d8ef8bc0b8ac8e127feea7edaf5e6acaea375c1580dafbe6fd9ca38f0e2f39d2c9c7e053ae3247848c626731ef6740f49201fc0a7ef028035bc9c732609cd83b1e3cfcb857695d6b56af5578bb42f7a745c95c3f7e3fd5d3fb7247e312757d83bacd54b3140ada22d084927089cccde4f1899a2bff291977a410c49f9b17189b1a7c8a872d90df3f400116b6f8016572d15952fdd1d3712965e6310f839b0b7939845b41fe00d95c010896b980083cd347efa94558531c44814f2e27381b8219222c79ef4f9b7cbf007886fdbd64cc11a5951cebbe17bed8dda8a5dd6f19d2c52c7411c584bd2f1804a7c115acebbd3d5709ebafca0582da784d280ce9b10908ce7c72adef1bd241d158dc6cc203207bef4d8c58b6cb9b890bd144abc2d554afc72d290a64ef2cb97c9ff8de3c661e3afa4a5585c8a3415e34edc32672ac011b1606d6d14dd60f4cd9cc6fa9923669d155e603f18dcb4d05325f503658291bc4359beb4a1aa4c9c1ff9ef58176ab79648e541cf5c292d418a88b4b358782b876881117117180242fc7183e49511f634922e2e6e49f838000b93e9e8f4b28cd468fe54985ea790535d512095cc33c543e60c186d486dd5059a04ded6ee1fa9b289e343d38eb8d6e2ceb1c34dc5a8a8aba83f9d03bf8ad827b400a988640d783df9751e7756fa4c0a8e17286d1f154bcd9cc46e88a51f76800e101cbb99e0e03cd4c77cbc7a243410c96bef125ae6485447eb74a6aeba89ef0ce8efa5e1567de448b6aefa2e108135dc222433ae01c7e6fb2ab86bc06891ca15f9b9fee8f8499099b44659e092f3138300501440f2a0d77f0fdd9b3ee7eba2ac8d3c84cd9451b260b740bac5b4eae7ec4cd1c2b7fadb3f4c15cd5a6d3e893c9290fd87a755e052068ff3d415875095eb12b77054db0ddc40ed58c397ac1a4f0cb820c404682c53f384b38b8a336614dd496b4cbd704adabc7f099865d3c5109001d54a013426b1673e964558cdd7fd04558321805381e0909f2fcfffc0d97f2a226f1c6f0df2946b3b7ad4ba206895da5468f7ff435ca3b697505bdab7ae06fbbb5c017e298c27ef4db93e54c00bc2b08562ab83b037b6b50e1c194f6f73488a0326275fb15d11cbf1a110a7100bb452d855cc4fe67a8694b84be0c9062ac135951ff8ef58255a44adc3d653afcd54bff7ccf3dcab64c3e1fe3c6dbac9be1c840952a8fe20ff37ce610efcb1bbac2c7cb7e5e12a022db313f77694d04a05aaa1a61e4a25cc2c665ccd25ea6d58bbd9429d5b7ee59f5481860433f919903db8868a845c36d86d09d9dcab381bdb4313cb113b3c7f7d7e3e32cb2da9b1f2cf5c7c86a8fe366d236584061965d10019d1b399fe34f87442e6565a074de4b568b548380f0a2b60a742f575fa2e531c2b50fa016963721bcd94ab78461cf82ccac9458c8192ebd5c099c3e0b8c3458c2bd2697d1c36ab4007f72e41348cf28c37ef75beb6b8cec458576cfa97659cd70fa5e9622abcede94f2ef43a8e7764875bc96229a65012321da13eb697a0903cfc24855861b08813e9f584cd8eead421c6c8b02fb5c977af42c0fe2b670dd337b6a4d419ab4938e8991f8c3224d0bc5002569a21bd91e4847376a485598a1c3619892aebb2a72d2c1ad3424a1f8054a47363f875f91f54c560ffa590d53a724fbb2eefa6bd5aaa5ffae88be22e41206f7657a2d9734b2321eb460a254af2767b0f00ce12c230a9735b95ea59d1f979ddb42977dcb3651335618176ac05627438d95c592eb645a0c82d1e92add1b5bdbfa987a0b09990ca7445019e62489f512b81750f22c9a38b98802752c9b1d880b7f708d47f6ec56eac0ba28991cbc572d2229570734cfa22a22332622712711ea1bef08366d1758f6c37b137688b4d341c520723612e2a5b5b02e8b98aa9d5517d0f8ce4452926c27a150e3c668a778c4a2b1de44252fcf21101e5200d0529283a8ff90170f7252327713b54a435565d989130d97c5f54e1a4a4a6fadda169378222d1b47f3f264a2955c2995045a9458c9549fb4645252cf288443e548fb463c07f5aefde48b597e82769e1115f1791c420628fd64b42cb46d9b79d868a91b3308aba92d24d557d528297445a2945896bcbce460bca4292c84d61d40fd90ebb53e8a5e1998e3998795a13435ee62e7303c6662bcfc7fc2892ba75cf639dfaeca32e37b9c0b25891f1476245bf6a031fee5d0011f54879f0176d6909de53b427cd9f87d1eff716289582a331f676221378b3fa4144939d12bc9ae900ec5ef5bd26cbdb02c1b0eeadddc937a85a33eb8f30001eb17494311eeadb25ec4d9c5c379c431171afca31a599ed4d11dd5406307502e797f4a5a341a3676544e19bff431d934b2166cc66ac159cb89597bbf2d56b869ddce6b319e1070295f337dbf67ba3aeff32caa838257a8e57c2fe402a194cc79a550c519a84179a052a0620cf9783be6187525264b78f60cc0e49b09493f6983dfff389ef5a247b3e47a66e181f50468bdceb2ae4f4087cb69f9a373656ee2a693bb23225ef5081e76e6155898a7e730c01ccc0598ebc33fab7d177326597533b9d8129861e70d374bd3b154f3c5e24403c120584365fcdda78cface4e48da878cade966c2a0c04b029b17061eee6cbda58004ea4ebca11bca1627dddd365a637842a1a07d61d9de3aa58c3f532e5afb795c310a334effaa928a5464e9055efaace9a9da6a565b9e005476fc98088fe35cc483b98ec1e18bbaa869332b69024c7254b8432b9cce855177600d505657403993774481a76b4abd11370157b5a2e6ea0db21bd1ae224d48e6cb8720f0c87748504e453ad8c7aa32cb5b8ec909f79d92a649e9d96dd0b8ec87575a99595d48cf295b1a9fb5068e783a92a79edc65de04a2c5290a861f4a297462ddd2da00a1ce39193117ae944e58ae3f9393a3f5d86e0c87afae5d8229a8f64cf8d4cc08c9334864e1838ed8f9e8c4b51032d2d3f5898ef7abf14324d7bab0e6dbe7dbd58ad4496680fd84735e1312ac26d3c457db5a34e6ec8aef2e6ee00576b2be9cdea834701fa9710de9dfda010d8dd48a8466063a1e507e329bfc957dca87023a63510628e30807dd885dff51a8329555d5dfd9d4ea5e032fa438658f09b3e29d3e18317ed7b390e98549d46873710856136248cc9a98ac93e107f20e6f08e41c0fc9953411b0ee8e3e852c4a1259e0c2d3db759eacac5113895249013b76bcf7e63e420e8905fc723eb56eff80ed4351498ed3c69844e2497561c6d594aae27af2df3e82523accbb0bacfe752fd1bed4459554a005218059d4a42e0015482c63e18fcd47c354f3149aec79663c8418b0f5ebfef816da0a387dd65b649809c7c4456385787c4f6d613114e8ac70ecbe34d83c4484acea8fc03c81737200cf7cc6f57e10f6d59396d21b2d4ab76cd3c1e6d1a99bd32b14253ebdfc9e99229b0bd333134ab89e46ae782f3059c1ce477f9d3a7ad6f3bb6ab982fd4cda8794050b28e3a816de953bd8c7764d5b5585e1a651e183026704418e92c2dcb5655ef77ec32b2efc7157bc16ff8c9b3981e6737f191b5870285cee7964d08ff574e6cea583558670cabbc823242b32f6019307532e391399c88ab71c611ade729a5e5732cd04ad954c63b7b5a57c4ac35157cd5b7fa2de27446bb080d9176bee26ed3bc93219f1eb90e8893934d64abef03941432b7893dab141808d1640dc422a72a6a908073f4cc7b76e746c295d4b40c7221a131114389364077e609ae5a0e64af6cb7d274dddabe80f950fd049e457a0cd9d60812e15a6d3bd54cdb83bcf4a2349ed5fef79c39e518a89f4950f98f93311963a2b31818d0a0b72d4f5eabbfff1aa90de600b45ba10a802a52b42fd1c4bdeb9e3b1b5fa8ad8f0c42b8814254b87c401fea9e32fb4fc3bf5d1411f8d28b7c2dd7c1b9282f342c89e628e89a75ad891b5849421fd3fd6bca3b257587211084c01696b01bbc5f4c9075001f6015115de3335a1735cc2e276032f13962748ef7893ae2ab354477dcae372aff732eab780971dd393aa7e401279d88e9d64ad83293f88d5418577a9a557d3171b9764af7187bf866e793400100a11a264a4680ad729858c2371192ca024847e163188b6f8ca45025c98a0a91c29980043090272a802d4052d39e55302662d9139d0026a8ce82acedcc18b2c15749fccd7f873e807f493a2cdd5eb34f00f75058f5e471ead0f049aa19923c298f3a5977fe8c64f70d7e712e79385c5b218da40a444c135383910a45637f224bb5321c23bea37a8ad6dc1232a45ba5c7605dc27e77b8a0cf4d11d31441f82e91713032805e20705e0b83d73da4d6c76a94d81adc2f604c50f2d0643e0fa8d83607b11b1a2c560e9aa744390b2f9bb8d3496f36b6a552715e837acc1532a8b33f1c7d3da371a9619f52202b1fa712c253b44d58970e21ee9afc12a7a94a1058cd53188f572a41699b1a53fa71006f8fd8708c25b2a9cc0828e4da42e90a3184170979ef256185d33fbdb97b3b8f45887b7c742d45bdc628f74e6b6c8119c0b8eed214b21a8c8fe269215beaf38de2bcea231bbc023ad27e2cd7d402379349833ba5c8726ce0c2a8ace7899d91a08236a8ea1152359bfc7bb7e58eecb75d0dad3b99986ca65285667e64f71f096d1a7a13d6bd928e5bc91b41a22ec84b5808099937d5e6cf27e19310ca1000509e284fd3001cb3a7d2c92bd49552f484b43af924a5f641182834c4e1447630b578765e4bad39bd56e58052864691bde73f629678fd1108887793109a9322e5288cea8cd4f36fc5185012c99602f3f091b84e9080cff936870bbf1b108edc45e002a86940a45f0286ded7c21db5fd16f4d2b515bc1024223d4255c7e8ea1e73da54adafe50bbcb422f9dbc4acf8c029741bde9f23b99451197835067c350401897704b503f19a5644a6ab021292280b67374244812c2acacaf10e06cfb9dbfff1ead237f82bcee22601ddc423f25e98e3d4fbcec207188970d55a50bcd4b5e9d6b165ac8e4827a41cf7d7d0f358bfefc49d3891470e28929f8c544b7c10a50b94a7875ae184d13299b55c1a3693197ec6c29028935896df61aeeea3d8a72c7ba63dc12b8d8cb0b6e0c7de116a94e9000d4daf92fd3b6e66c61490c77962203184b682d4494ff6e01db0e93a35837f974eccce89370fb4d11fd4dabc2ba477b14fba55db29bde1908e294b16ffd2b1e6156efe17288129c39258ad9f6172f820f0da87b494f68a091ce9f5cd4f61c1fd62883ff8129dc71b2463d0663773e6c6da3256503d664c9ee8749784c9a603c0add8d42370aee25a4b13b9b9c2611a51fc0a8423fb598cddce8a78959a87cb02947e6c53eeac6713bd685dcd0306ce5dd3c6951a7eb17a72bafc339ebaf211f4beb1e7d5dd1d05290c4b4dbd335c1c686925c1f94f8a64045ec31aada368f4eb208ebc9f8a169c7a4c02c4141d4c9ec27791a86facd4417925f3ac1d2268d3b7a76d9af5ed51ecf2bc70bde83dafbd22f447ee81116bbb4283a527922c6e8823213a06b5c1ebde53cb9a3b513b8c186da276892e3933433dab14e48fd3f1699c06d250d18822f3842c73307d555700ec6d8402ebc353f76c2316b54d52f06e4740344a5992460431f1dab0009b0aa0a01def8bae274df68199ec5a816f89a6cb1fbf3cb12aeda6b0e8e39d5a6a02fba5e22477e0b274d2364522619df09fc692eb89b1d0f11fe8105909280b264de7f195ffdcdd50ee1fe97d04b40f1e5bd5981819708760cdc392bc13c20d0996e783fe8c5cafaa6fe2d9339715bbfcd81c7707c0b26fa58b4c506a3d3cad753721f4cb4a47279599c1494aab4b7bd4cf3060bb2201c83b19b01b3ef237a83fac0a2ef1fe1ea84d324d160112b7125186fa224cf0c2ca245c1c2d571aa0059f303690aaf9a93f619e2ca3dc72f3362f90f0cfddbd5ada271cd3e044f8400f2aae3deb549067a4a85d37574a809b4bce4ded001072ccda44c9fa3efa7af0bacc09f99fabeb34f1a5602ea300ef38d5eceeb297abfb400e2378130c95eb5c611d031621776758d10eae66b0ecde05e71b20f5cd352bb5d1405c5f745b23099cbc70f273f795ff69ae5cb0fdb33c8fd5be93925f5320341301df37e3e561adf2f4c8f77ab125a4ea6578359dbcad822efac696495300bc7e19ee588f4e2a90dc44e791e568f4cf22576f9e4f518f2e1f3318dd0fe3edda7391db4ba41d5ca71cdead4bac2613b445d19c580631472327de3c0b659cc85108af3af480dbc9eb4a6c5341b6ace91a8ab42289616c713095d156e3c9878f089a343567799572db219b3a8ccb8ee0cb81aae1a19dc50ef772c084e43f9e4e7eb2a4e0fac8da0f2288a55357b654c6c9456e95a458bb5c46686678263f64cbd3788282cb3dc74d579352a9fdf237efce447444f3b9603d67e355841f23defe0c73221a76a4998ecd751ef5538d81b729331d7111e9688f51c9145fb3a6ec93e3f50ce8283fd5ac4d4c02e0cc1420ea2cf673accf7760e3c2150a241976b23ea60b2008b5be36abc99ccc0cb7cb2b7a229de02dc8fc06128017f101b8976ea05f606da9429328d9cc5d8a59dee9a5de6564eba827d834889cdb2763739c69647ba2f676e30770d96651f98a63dbbd6793b88468f24e0822b76184b957cb23366edb051b94590ef0b003b6606865b0e6f8597050fc78ea3a3264a1a8dadb0fde65e639318dd469b48dd2444f38d8d963f8bd7439353a880c20dd92a4117e5e29f82cedaeb7629061fa68180fcc3354e3de45e7b290fd90c594008c42fcc3909ad7ec9fbdd8a778bcb7b496bdd491756b0ea77ba82210b239e85c1ed7a4d56f9bc1579bf29d7faea714e1e28c3185b8ade721298dcb01a2b18aef3b55a2fc7da5de5e093cef20ff09d14fd954f0230586d6820dfdd3b2fddb54beea29d513b2046417f2b76039d0f8482179167581ae20864a81cd131c23a58867c847570c78990557160bfe68fd98ded8affad200a32b6f398a36dfa9f8d8609c81da9c6404a089aa8a8acdd67a6619d3071aa563f6247ad90018639eafed37818622004a94887d95b823054c2e894100c0fd5fe6eb3633b158792c7bc6462fd0461f2ea6e3cf69888d912770c084fbc8d3f2ea3424d26e3683111bf087871b561412398f265534192a1365d9da12b4b4d1a92e851dbe0e9a8d01c73723bd6f821c105e7c5e6e9a36f971bc25415a4e16a0b34eac7000e046d833591cd91c449a1843ab15f18ecf67a10d17749cfc08ed34629a907910c2b9f04688b242a7a1c96ad371817608567725aefec3ecd2490781ddaf7ad79351f39383030e27d7edb1dd0e65dc17d3cb2a1f5ca144374e11adc97afe2e01bda44c9abf1c52be66d08d8aae19f3ce698005132b2855d6a42729817f4030482d02e53a8bf8d4fcf026d1f66756b6e705fb9a7a38400a546cc1dc319072e318aab648359ffeefd33e0682d6da4cad4aba00c538a0f4b80bc59fe9cdcafc339ce8871303cde4c8ce82f274254e1ad9f65a729c5097261e46ca9ac36e7a8fe63db72b00ec71bbe953bffb07fa2c1742e29a069301194ea136e0bc071543cf79b388aca41197d48213bb65c66cdbf0997320533b18e871b419d0223cf43d9742263abc3e6b3e288bf80252740ea36ce2b5212402f85375ab14ec0bf23948194a0c64a34a4a23d7919cb36f06df0bef0d99d7f8cc53677518beb356c5d5b12080982b8ec0e2e20bc8369a2ad4ba5e80e03c64db1fb1fb6bc39a686988b6e3e3fd5510f49f803d0dfa81759e1d2e1dac6599168b1db7655fcaac7d17de8da95e0a7aa177f4989909db99280eafae448eae1c794a4cf9fa9844bdf6805ab53b550424c213db2f9c95e8d941eec28c16af0381f1d7ac251e95d9fb034de3676446db424069358010c82a52915a2d45d9a1b32ea24fe2432eb731f36d73ff3c3399a6962e30d88effc3649dcbb13c37a7514ad8d50bb0c753c344d7e0181810366c66979629a1cd1e0120b9bc84f43adf8f3dbc22ba7ad67ff3463111e1998d85effbeeb2008f1530a56839150b6b50d3caa6da8ce31d4327b9febfba590b913362137b54a99169f045a62a05b0512809c7a2a977dec07fb44e90a66db5ab5fc7d675152fae613d1ea10bee4907408dbe51a12354d70b823c0513d227c23b303a275b0beaa98606f244a6fd49484d630ab827c720e63478887ea4f0cdf5e02ef458de19af860b9ac7db54867c74ba2682003d230e0423d39803205162cbada603b81e6f17f0044e2740009813f46bfe709ba58a84a2eb5ebd12950d0428c771f6d5ef90a6440c11895187d831579f37c16406ce6ca025d159055ca5e7a478b405e4c1c2bbd6f3c30c229a2dd47553e7d6d330083479b0aae1821f3fd2d4700e881d090c4a2b9854e3160c08d374778490548c40f09d67fd29c5908f634748a84292b17924b37b00d1843ef6a402c428e22019b4c9cc143db73057efcb95bce9c330ad7024d10c66289614021ee50d20828fe6fa6f32c6c067b0d07a334ba035e621ecdab552a886135e79f292db77f58418b6b8b7a61826cc7eb3bf491fbe82e228ef05b9ae9ac5a8360f70a6447b21d630345bb46b3222f0247da41f5975f02e67ae620ddedef524cf684fa8f8c6b8ce8f8c66f807106c144c1123bd85802ace33f3ab53d3fdb3898b49844b46432586af8bdfe086b2c68388000e1f6fcc77f1fd677f9a7cb3eeeeff8bede7b3731417fbf1189ca61d7360ed043571b8b20aa18c822c3f8093d5d011bf8585926468477213cb30f6bb5bff32a00f3c9d251e546c8fbb0c2921b993cf1560409b33ecc5467cc5aad9d73890cd92e614c048a12d6f303b9b326c730da7d69071b6b2f2b11350f6980d470b6c29e6846d1a4c922dd6cc989117c3de8c8a8ccc99aff9003566dce8f331060b3636263eee5de233971e23e085ce794a5855a7d66702b1f3aeb400043bce439613bb5a84c820db3db9a0695a0019a5a0ef1a5a1c377dd288a4dbbccc47597ee22e124b977c7942561fec08012306549702cfe01efead7c19159370603793c5705fd88f893b2976537fd5ab3a743852f8b6e2441127ca86c747f30373a8d3cc07e849a1d802269257a65c052e3bb49546aa2cc760d4da38b84d34516714d73ff733c254c54239b9301770fb0b568289d8253b91fdba38e697b63056a49a5a58846dd5b35ffe8e5991688f78153a743433c352ffc3f69b83dbc67ddb686dc895725868e06b19b92c3b2ae25b4a740e038abd4f14f766a0b92a011725a602a9d0a883b9380e141a142691717c49f88d347544d22f2ad27827889ea56ea9e02da3e1bdcc6588244241811ea06d0aba452613426a1be8d5aba7dbc4dcd3a574d61c3a5e9691fb39eda8e9719b64f9a83549299d6f8297822911917f75d2a46407899c95bcfeed34929156330dda68201cac647e97200860c96fc0d43af11fcc56e0e6727e3e47a320ec4239b83b391225103a4eb96678cf7d2d47061e9495a3530be2264182d8b8ad1926015ed0e9be75e0d34d2c8135b9337a8ad02e725ebdc275b17a385150ca1fe50a8d0853effa4985ab4812b7823cb779c8ec04c98f60729c3005be7df8df6a83003c4c7037ac1028a5a409a15a703ca890ae10fe171e06269dbd14cb3ace3c3dfcc121963f4b9ee1cf16e9c231c2e0d70208e0ac5956b2837401de56bfa8484d02e6141637ce4b7247f1b108ecc2aa4b712c6abdfa0a72624c9de5bee2da59432252903ce088a089d08f6835f4c863d4f5ce307bf181c1d06bdc42edd410dc47535a08fa401320afd75b1ca0d337309712d5eba405e4cddb726b85e9ad12846896d64d07c101e79a9cb386e5450ef407d4b0e85803c4d324fc762b8067bfa7c671e083f1082200c416892458d0048640863402803429a3d845886e152bed87ef00c11fa4a7ccce7ed0c085520a401610d086580b083b004a10d086d641efcb275b134320c9ff2ca0c2c2d34d49043c70dd30c2c2d34d49043c78e956c074b0b0d35e4d0b1c3b4e1a723b7d050430e1d3b4c27961c2999861a72e8d8613ab98c46d7663394b735d870e928878e1da6938b0d336418a621878e1da6938b0d2fd9b583dc5fe4ad348e6c02cb54773452e53da1705115c32cd124bfe734cd799ad3654e1be67c9993c79c37ccf9ae5243a6cd901d67a6938b0d2f3c6e00c08e95ec0f043eb727171b5e78dc008000680568c91e485ce2a57e9761b82e36bc78c6236637c80c00330b000e5a0190c8b3d287611c392ef1d3eb1cd90d1bf985c70d0008000e30f9e4dae67f52341f570c8f1b0010001c6072cc8e0cc39d29c3b00c35f2859f8429493ac8021fc3343af80a40866195ec5832d1dd12974c75d7524877ad8222492fb97f4386e11939a63301e410b31e3ee40fa9837316267b19c35c9634ddb55ca2bbfe98a44d3205242a691d231a9a0d80732e94630620eb5b8139c330c6de733fdfc145d4204754ad727752aee6f33189b517b6913fa34f639834000792af37ea64c955c7c192b2882f207e72b919b17287698e78cac822962f85e4a7b85e9c45ec197259b63332487136828feadc2a0f848ad6c37f82fce31f2c1b8deeadf55bdcc67847fe250d90eefae549e84d243631c1a350067d3ca19b3b79cb9f21ec24d624ce24b61263125fa0b75b2631853a7809c20efe5b6528695ce69199edcd2496124789bd4ff08d8b4b0c650884534fd52244a6240d8fb804b2b4833ef2258d9f802c6987403a4710feb4a83e95bde76712062f354049636384723d9206bf1709644a1ace860c1f255b50438692c646868f83133d03f1137ca58782df0a7c0902d8651a3f717002ef345ac03bc5f7859c512177e80a0d78cf0a2f0b5946ef091fdd3a472e16792bf0b77c1ba660887d2aa893568ed7c4ee0beb716c7b04c01d75fef5062e43aa0d64c93affbefacf2871211da5b449fef5ef9d1555cf6d7c08b5215f6f2f6c43b69d2a725892c61922fe3344eaf6ef5d3ad909f4a398cdb79d5dfb623a2643d80249c7f782fdfb1c0379c07f9f830e7df27ad365d4b68d5abaf7fc0423a7811f8b40ee515e44ed47ca87656370e1db21b60606177e665f60a1a02929d9d6ecc37a2f2626f973c53b45d5eb7c0d70ea478bdce136287e8b62533de144cdac0bacaa0596052b68c2aaa093d914581458211fd6a7085a8f6db327b02628c128b34c5812bcc8ec08ac086c4a46cab691e67bef3d49258eaaee606c1384f00650d218bccd06b9b71de43eb971d55b91383ef1ba297277322aaa34967397eb2a2976c17b628a074503418a184557b9c9006a520802c4e101ac37c83ec4fbf14081f056fa35563dd1585205599c782b3a803fc8fd3798c2a34d741a4d63398dc6d26e3426e47e89cd2dc76d7229309e112a9e0e971bfad471401042f4a9da74e16e511f16ef7a9e2228abad94df8684930fa1f893218410daf8e9e4e6e4c626bb14efa4b1dcb59611ae105edd7a903b3148459b13e47ea75c5445d583bde58e714814ddf5471bef1869ece0a8f2d2741a2f55b7ead5a7922123a3b64d08efe434f189777216cd6684510fae14b96790ab6b1aed60ade525ed486b384ec3a1349cac69aceee2d358eeee1a4b635dd06fdfc13349c8e862e6fe8c125dcce7957089f1fcb6f2936fac8cda9010553087138f86fe0df45b7ce295faa59841ecc1db11a778518ad7350d95434520e48e5cc7599d1c63bca22a46558c30decb156a13f6a213f29db6a8822cfd9fbc552b5ea95a5157fe616d197a32863f38dddd5cf14afd5b9edc87a5c4cd9d6c6336f1078b9a777a2f8b07797cae782cfd1f2344277c6cf9e23e2c4c7a43f9e676e12d7faee7e8b970670c6faa0bbef68b3b3f31cde2fb156faa983b31dbece21703b1bfb683418e6b3c5f71cde7eff6b957763aa7a6932471998ed64b2c08c3988ec9401eb37554d009080328034803b8fd20aaeeb515cb1cb3f5ac83ef57ec1984fba6a6595e6275cb446b9cc6e96ca3459973ab9d1d6f2a138d8bf9934d1cb3ede01703b51ed2058fa53f5e78ab79dd0c5e5783579a22f76f2a934de591f12a41b82eb1a56629a74da5a4bbd1286e518fe4fe0f12cdc78d0c391c0df18dbca9bc835fcc855d723612a164173eb51151af56a29317173655161545e60bd28577e0806463434a91915d58471429437a480a8ccf2e9c038bcf9146921b6789860286aa553062d4009298ede01922bd04cda67a2b57aecdc4eb54a75e133184088921e3c234f48c8c96e99f32beae1ec765f42b12d516f5a63b2c2a0bb7b21c8a3556a6852b72e788a118962c812230e4fe58c38996842046ee22a33e5ae466990801814a4395c71766a9ab2ef5af3e80752167c2193e49f868f15656dddda9844bd28f7174ceb802712d0264b9e2add4d55f91fbb096a8b14dd7c490b45a33f08571d4950766c41e62884383833f5874a9ffb345eee7668decc23768d4b8b08d2d341f17bca951ca18aed93eabdbf694fbb02c08cf108146baeb3c9c1c5c7568e887fd606f7585affcfa6560c970e1aec3badbd9c82e2c43092bddd28decc23572c5359ecfb09aeda507047a0afab9b98ddbe0bd60df321b864252a01aa8f2920a168136ddc169a363034776611a8eddb8372eacd2f97e1c9a0f96fcb9e9c0c5513fac7ce11939e2cf0dabaebc54571f2c3eaccfcd112b46e0ba7a2bfd2b755557ef65864d95ebcf15d4905d98cb19aeb93f7165757739c745d48c3dc445dc8c71db90eee67f6ea2e8d3e7faebd3ca587477f36175c781db2694d3649a6aa44d91be9729c40b22c906c5b60db966d07c5c19e32840736768c92e8c7356733fe2cfe7c8a7d51f24f721aea1b931f7e9e53e3749504046e6c3f2d227098be6e346feb03670e1a33e2d27a2d186391c306e4616800f0b860c1951e5348f718f69ac8fd89481738dc45e2c8b31c69a6d0f267991dd0f94f0de7befbdf7dedba627e42a9e2a8e538a1477341a8d46a3d1e8351429292929cee5a003e411ff3dea457e1801e0e925e1464b0e148ffc7ec63bb5605785d8559bc21e6e8b9f7af09691ffcde47a68f85e24eca107afefa607c9ddf4f06e7ae8e1c6888d72d296f1dfa31eeba4f274e4f7b74fff537e747fc8d2df0d79d0fbffffffabf8444a4a4a4a6cc863caf76e70e1bfe7a558a1186c4a7e0f210ff9a216970d9e5ecbc4b73f3ed60259ba05f26869c9dd5eeaafa39617d3d272e35cc4c8ef6d6b5262e099b0e8d17cc4c8b9565a4ebff7de7b178c148410c2941b19ac55bbbbb156eeef884932d6c6dddddae47e7fa192a131a2a8b29b6993fba5cc6e72bf1c65154aa6b41c2d47cbc98d4f724b94654a5aecdaa4284b9992725b8154f6a9a02aace25a2c7bc7c0335d2f8e8e3c9256d25dc8d0c5a6885cb1e40dce0d4e2b494e2a954aa552b2e5a5ae3868d96ab55a545423371f81919391a93636ed312727272747ce542a95a2b2255bb2255b18ace232216568644a0a912a3904a7952467c95ca5a44d2a954aa56411b992ac1b89b35aad56ab552a954aa53212c49b88d34a92b344a552a954aa99b3f2d26ab55aad248d4c4921522587a8542a956ab55aad56da1c816a884d2cd245560e55cd9c88d34a92b3e4e6e6e6e6e646a552a954aa99337366cecc99393327f76b9b0872224d14426f6e542a954a1587449b5824ae228bdea8542a958ac22a2e8ade5471515586a65695756f4655c693d09b9caefb1f8d5237a9ea4baecc88e6535148a553be6a436fe8a43792dec44eac32abf79bec389e24f7773854bdf7e250a311e5503fab4c9751d52677d5a6da44183f79ca4ba897b2c1858ff2547bca539eaa191c8007ba1a34f2fbee7aa96dea0c2e3ffcef63b409467e6d4a6913a94d2f3af666af4da3fcde7ab2d7a693fcde823293fc5ecc6b53e8b50924fa9c784617a5f36223a564af4dd96b936d1326237b6dba2a7e6d9a2ad96b53acd132bcacd4755b7d2bf0e51129a5fcff22ee52c618638cf1f929082f09e1922595724e5b03897a58e44ea194b443949109f6a9a0445192fe65425a72c28b44de1694b92d99993ec1d4844b3021c4e7fba3ef3455538a89f2a87b22bd7b8789862921c025e0127605855cd694e299ee13deb469d3a52c3f99e47809a74d2299be4fe8540f33284f7aa8fd98197b1414110d69161199140185408faa5dbda34b942080a01807674621e11e74782c7fd3ae268e91690a7e750e7567919e9c49ca9f89288451370b2622c8fda0a7f5e878c75f4aecb11d425972472ca131babb3b144d7427a4bbceb0ecb5e90467bab3b828b884ff6942d13ee79036a13c8a91bb3391fd5ffb12d9412d863ecd229d7754975d244ae2752299ee9af4ee3639e239644281c58d8f9aaaac7af14ad418d2cf221eba1fcf5f0ef5371322a2f1131422d3269190249e49a40213110da62778b405425c489b68aa3b153c1325c1ebfa9b9e60fbfe57ea27fdc99be4f889c45dd63561e960b5b49032eda9aa77f4532176e5fd2db0dfb9bec9cfef7a5b3709bdd74bb5d2549b6eeb8a24d2d316bc13e9fbe90948a39a91a57413714e3309d3d4981728910617769236757ee55debbda38f5d7d969743752d59d2949056b752ad1bbabbab5aef1d8dfebb0eb3abdcb7453b1cc8e6b6de4adf56445d2b5018502850370bb91fbb9990dc54b85fc8ad9a50cc215146497320ede024191da6bb2eaa3b6cdd564ba43a691960b04fa56b9b6600d24ee47a9b56f26d181da4fc1b6a9394524a1d7258fd80c9ba833d6020cea1bbfe5a43f7a68c6aeec554fec2359dc7baf8a14b40a2b8f2650e9c105df6774e025d26ede02f5fca9f3fa5bbb6c30d2e2e12477e38ee3730307efaa14bfd489c03b2a31f46206d02f2561a88892574ead8387538204070ea0504c87b79391807ec0cec0c5634cfe3c36aa6bbb75a6245d3dd73598547f718dd638c1e3d7af4e8d13dc6e8d11d93e25fb966191a9b16179e7211f4aa839003b50055d0053d3cea6921b9676570e1b7cbd407dba39cf4ba36e71ec80a086d3c9c941b8269ff7e23fce41c10a147654b7203d130301f88eda2b5c41afd466ce81bcc5bbd97976a62cbde5b392fd8e97426addcb66db466f0ca90d334edbd3c7bbd9798bdf7b2e5ec65efbd74f6b6ecc5ceb6514a630988b8f521f68efe177d8093ab15080d91202e39025d4622663e9e99af0491202e9908a7a1c6488c8a1994fdadf40c3ee4aa7cffe7dd1de516b9223a3b91223abb73b5560f42ca0a2bcca4463797e575e5ee703ef60fa70eb13d11b533c46b43643fc47dcfb32e338b5fd62888e66392c0a18b9c19254631a057e2c62401519f1ae2ce10892dda67ef726db613eaec853fa2930fe8e1853d4b26aea901af6bd9840fdd41eeadc0c79e924999bec85946c4e7210bf45c2affceecc22821139a5d7874e1930b8b72e7c226d966a150d640275ab685e824b35a74b15b27ebc89b3f9dfcc92ebc6926d9b52656860c119663fcfb55f385690ecd1ced8becc2925471a83bd1475c73f29dde21129d7016656465dcce94cb5d4aef803332047daeeb5e49efc3f885238dcb75b1c611fc0e08c3b8fdac83e55f3526a1d07f424ff331266f2d4a884cff4108bdcea7414ba52903d788be836be72578634c422d34a31893bf38c81191a3f918113722bd401985b2960e3de3f7b7746b92e649a731668f3887ee7015197e34c2b2c17bc96fe5b570706ee05bc95204ef845f09be0d31a0c1050f053906b2c411c013074bb0210bfc171940e9446e1b29c8a1fabc76683479822cdfca12211a08169382a66891362539c4e347d278e993e17b4a32fc2e2cf9a16fe812fc891f12a982579f787206d9b18eeea07da84e0e02bb98f87529872e513983775279250fbc2740efd1807aad1d40b0785b94a28e0c71cb14251b55cc9d9d4305c932931d6880949187a4812c9f0cc41bf04e3204af244310b9e8c911c70cdf7d057e03dee93d20b2038ff4320ae63944a69c66fff3afd2a65b2f10c8d27466011ead07cc8c5cd453829381846002d22c4954c5453d25d006e1a29e122d08cca1b729360a97e6a3f3f6231b059b2d8ccea378f2b3a28a2c3cd9c610fd80b966c6bfd03eaafbc9cf0a2ea8c8d9ca90da0f98454fd23eaaabe56745152b2d5b1952ca39a79cf1d169323bf959c10591ec166719f6b733a6123ca397a159c18512b2d3995f11b0e083ec6f55b20cdbd53df9d7ace0e208346f34bf22546106d9dfe2eb6fb94ce29a35cd007646bd66c81974063663c66b9f013b1bc4e90e1e01c2453d25288843448cd86399bd628c32464fee6fcdc71b0397e7dbeb27fd796112bd50a49c988465965e9b0c59369f523aa7dc222a92327bc57944c6b00fe219cbb4e62b8867fa92c69fd7c33c2f4a9f4e1a0466fa42f3f1c690e75b1b99c432fa737f4f65eb4ef38c3a9fccc02fe68351d5d3b9580666fa12459a413ccf29e9c4418ec82898493b681fe3c3ce8c0f33c4695377b613bb4f4dd334ee7591c4953f91883f73847114f6a8ec51f651d7cf979884713eb04cca381f58f62759ce07964917e70343c53c831c91e3db2bc3b0fdc17d56fce026a3c290af77cdc77b429ba4e42106f99851325146860499086d87934c399405f2c5bdbf25300b418411322d831b3ea104e95b4c3c63272602c4a5941527fe305d9ee602bf837f4749dec54f9dec2efc11fc575b4f38e62d53dd6fad38080c07e142c06aeb67ed32d7bd3e8689c8b73fc007e2e27ea84fb51e75d60804d4de910c7f904040f78eda0e3874d1451745c40c44e74c25a24b3a2595d2e5fb4bb7d97148eac032c53774d7b37b1e65edbaae75bc95761da7fa59eefc54391dae438737ec4d870e1d1958b160ba1cdaa4838c2e3c208187f7f27aa6238eaed3d1d2d2ee9fa384f24db9e1808393a0654eab813cfaf7d74b155afcb28c7e63469fb3cc6297ddee5b812c80b01f3582953e8acb8f4ed95cc8d0fb4b88508e316e71630b765d302b988b8369f1138ce41a83f1e8a11892f1265a01617b9452ce4adf561c3385137aa6b8673b008896104124814070e456b9195b33a96dd76621131b4c552c7aa07620bf875040ad879b0b7b8f6198cbc5c5e5caa0eaad400cc35c86a08d8e96166bad12d9e5857f34c2d17559ccb41efe3194bd135441151c026d322ca2eaeefa88211451a8a0ea0333db06552ad58af6ed40cc8580cf5a7ffa575a27ad4398f06a0091901b4ae157371007b2fc42962a56a86a135c7517dbf472d7fab006ef546baa7370f55edecc95ce862bb86a81abd52a360542cbcd34e6ff6bcc631f2077bbdc3d4806b8be7e022e2e01ef5382081091243fc533f4af97fac3c40df296642262fed1005f8c8f62f6b7d3dbf4f3ff3b76b7d462e8ffbf97273b5ec1c2ee86a317f2177d0bc1fe6ec2c66e7f39f647ee4382dbff1c891c1d421cc8af81ebd3c0f7299ed493a2f201c9401acd38a941e3868dd20b94951928a54e393f22839bd4af11ba4fa3c6437ae7bca8682359f288e59da5c381a3c3f19605cf10712858de5dc5e2b14918661cd86d6a7c880ff195e645baf32224aeddabf5e019f2f426a21021f1621a3f71e4142e1e4bff073b159e155e161e175e185e176fe50aaffbc2ebfae52fb1f746a6ee14d6cd0613a954bd3aa52568682eec763ee332989df11e2c03eb06a785a4c8ca488b61492fb1353e28df1ffb517077217bc1750e4949087b8ec897c8d0683e2c0e3c98860c4d4a481338aae2909c259ab73c78c6d6e9683d48275c96225048743232e99090b45a4aba4b72afd6e3f356947930cea4d1c90d1bd5e486a648de4f1be995e8b30f2702c2307e84b937c1f84ff07f08cb78118ef11e2c233b7e19ff8df196c38e047b1257823d077b177c7499f481560c9170973f1e1c23cf96f796b72d7886485361e3431f1b2113100a8cd08b14130f7ec1c2c2758a86a6554270885232940cc23536dee5c992d1c883478f34f260118a079b641076242f6cde0b29834ddceb2dce3c1804228d4e6ed828c96a724353f402c33cc34aeb05d7b5d034713b6fb9cc833fb984e30dcb4b2bc781921c9b1ba2620a6fa5683eaebcc588e1c11e2c583062686fe1bf9721e31a59ad62c8c8f0ffabd1c9241c6d5238d29c9cb7643cf7388c956cf9068e393852317224dd258945baebb8fa4c1abbf05efca91071b0c8e3196f06c779b0f6019146b108c481094713f256db78cbc68796bd35850c9907671984bd853d49774a4eb07721ca78c9c510e27c890eaec42fdb0cc2300a38c483af2c534d081102858a0655aa9a3f182e016968e688a0404e0d38d39dcc9c5974d2554f5280ee74e864c08183f052bf0c1a10ddb576f09cc279abeb6c641e79925984c4792b2ac9fda82886dc62782f2f87700e271c0ced968017f425adc7c71d3443e6c1314b5c44bdc10554f260cfb206c70d1c6d702ce271e59115b13811cd1ae26a6cbcc5816788441b9a8f2b7fb84773037bebd1d06fc3fdc683bd5db9f46e4d2de11fd9f024de6ae9baeb5afa060d10074b3641d25b33dc28e5e872e4381199e4088172e4f070de6ad5ec0f873ea5d46b340f5f802d91482412bd1793fc502d5de9f108e5fae1d9436eeb3cea3121df473d24dc8d1b695c67b3116f050772d2ec7a9e29feb3e209c0a4889bfd5127f9659c115dea3742ce46749703ff0b3c93733774078f440e1e792b7d045445177e2f3e51f27b08f37060de4a5f9946034c642fcc5b8156945d1e145c6a81f1929f5e4cbd38d4cdae0c8f6aae97b42d3bc1211e1497b77aacb72323bcd45fef68f46f890c19058df0537ea5fe2b64b4a0690217b005363b0783030b63f395556c83792bfd0f86a040dab60df2a0c06c5d1fba6b2319959d7ce801c829e36666ec2701231393bd121f83fde450d75b8981f8d00391f918fe01e6e8ef863c1e863f4449b91f8efcf05e9e0f6d9ad3afca45096453be07591af278510b9429a9bf197d353af118020b33e4c1e34196f9a8cf9b1caae60861106a81f2fbfade8d9c2e0f863accfb897b397ae9306fd582c28d7fa274197dd792a1430923d7d2d2325d5a5aa2063c2f6ae0de8e8fba5ef2db0d39b0a564afd62a4496a1c7eb1f9df279a9df7b6f76d893b8d06293d67a796eac9452babd56b1a6512d34fcf23643247edee3a93f5f4c05816aee7bf0c7f3dc93fd5dab7ffebe0f9e0779be723e7cea7fb8770f77c49523afa07690c4a88e52b7b123f40d85003803a9c32c6bd308d35e7741e8ff7879082dcaacbe536cb3d0d1d252e14ca537b8b8c05a9520c92c56001d58263f2cb62ba9f9a82f2bf6246e0e3333da0f3ab307af0bc25ab1b4360af7467e5978008a4c3df808223e78fe7a38cf5fac7b901400fafb3e7cdef379c9f900facb1d41443e88a38097fa636b43f870ffc31d010477801713c40e57961caa87fba89783c5bc18cf6bd1432baa5108c8efad2cd19c85c2ad9c0dc2cd1a1c82129ca7f9c0accda0f6a3bae603c332d468e0127006ce6c19c5e84cad31766aad1d2dfb2cfb9096dd4caa320acec019382363066a5eb179d15a61adb5d6ae8e3b1c5d773f546284504208e5d78bca182116310dc362adb5d6fa53eb51ef3d62dfb15dc521a24fb7469c4092b3959a01a076801f35571c2a9d4bf92895fab25e1d595ffe85491a36eb7545fadbd3a757adbf552a257dfbe875c94abffecc1c5e99a45fa9a4549398a45d52522a29a5d4297d2969ac0fe3b94db45e99f61a362ffbf26df62169dd072dc717362fd881a310d8245cf8f15f955fe555abc568ad579b62f5f93ffe27a61896fe98fcf1f294500e410a9afc32a490625285d01d3e8c5a8c2fabb46994b5204364af695f31ccf46b6c48b1cd22be7e9537064a1fa552ab9455cacb625356595dda235c98df10ae6022fbc799327a63c8f49f5d5d9906e5f411bada8f78693f502a8d326e998661a616e75608dd553694057284691e2477439a4af7840b1fa542391b840b5feb31842b68de8ffaf243b0be6b3e6caeefd846dce1e8aeb3732af067a862da0f94f8306b3ba0e4e85f3f26716b8cb56ed75f169bb5cad75ebeacf4c9d8d45dd3b40f615a0f0d57ca8d5699d24fe2d6874f3e2449af1162947d144649169bb456fc3294557e108f52457ea8561adf3578c285d53b757fd97b5492aa9cd13d734adf73af723ef7cc7d9421a594f6a0f4dd22e1a2a0e35c4f86ff46d0fdbbdb669f5d55b6631f1f73eb3eed11463e3acb4741c13ed426ac0736391412196ace592d6e7e2fb54710d8858fde4be5466fe5fdf3814d4685e07c4288d2f7e8938fbe509b64f76763b0fd4fa5633be68e8a95cee8d7855dd70cbd47c50c51f11f29b6f4231e465d8f42cd7f1789ce7e59468f31b6c9717cebf1c5f85e0d5b47cf240c2cfca7826ab14eb8a8ab0224b973670fa10366b0b093d2ce360fe0bd17ee48b3788d99c4a6466b9b5ac7c5beb3d84014d9daac6258cca19c1c84e6223e26f4fd4fecfbdb0b7388bec5309c99ec80041521e822a390a042462657c06d647234828a43b064b27d22b01b5f2293516f25932d27822c90c5881732a5d8e4ad8cbaf3b7e20fd37708173e4a9461f812e19e64ff67692b1791896c0dbd9721e02a1731737c7f93f7320494c94170c83c5c196d005026c7aa0d00092a5232b9024800c146c666f6adb56f33fb94abf6a3c52cc53ec39e24b1275dd8932066edb4187e51db016b53287b11996c6d64b2e582f812991c390cb2f857c8e26fe4c223efcefa80ebf365a74c89e651939aa64d4da39aa6554cbb344dd3ac0f1b8a01358b192ab2cc62460cd97e7c1b32bdce3ad4a64e8f07a06a5f72ce19dfd6ee40190a667bb5c6837cfba1eb6b9b300e75a1b0cfb8886b04e2db8f0016639b300cc328fad8d74aabb55f312acaf998ac4fbaea93607dd2ac36732e674772f6b1c2875a161a882267dc5f6f310a7b0c15bf720fc6613ad61851d8f84fc5c60743f7aa7c0ef1c1fcbeceaf34d22350587d8a49587cd245821de99c53ce4961866913565daa7d9975740784fb9e3e4a4765c2edf71133cc12eecbef7a18e4d132966636629b84fbde2ae1f64398f782657fbbe1e8ba2a5c32bbb8707199928c0bdb49198daab07961db8216b1277133bb85d47c4c54fca924bfb7e257f35139d20e3ffff2420e7596ffbea3f130bf7e08662c62107b58638e3714122fc8f561671b8a01b972efad643c4cf96eec13de32b927bcb1072cd21d258202dd5d14c481ac36b5da8482ac8c459bfc8adc0f71daf4aa98020e4492dbdfdd29a52e33fa244bbae89322dd5c9404ec6dcc5c7bdd410c05b7370ce5499d94ef5769d38b1bda1443c6c5df5f8036fdf7f7d0260dc68cefeffc440308574972292004107e82343e4384b37e922587b2407e6f05c62936c24f504877f79021fe5a589861288f829d66708857e88f65eb9be8e78be6765d5524125d46b8b28d2874db50b66dc35a43d93694387fa3db86b26d1bc6c1d0aed836ba6d9063f9bd3efdfaf519353360124903cfc056efa0f12a7886e66368701049975eef404125b907115050624641c1301419c3478c9e37dcb26298352284cb610482f87569af6199bde2755dd73f28648b617b73df10a448e567c514c49061c6e2c719c433a531d2395ffba8cdcc5e536298866134f747fad6b3d89da8f5a0f3a164b54844603eaab3d4b488c5f93462d28c947e8c33caf954e239a3cb27259dd883429e19bc5e1fa6c1b4cc84200105339c792b3786a873900ef571ffc2d0e45b8a356b2da531daf9f6e935298539da2863949e8d38021747b25c8956220c351e227784bd4456eb119fbeec49e9c08bff693d60fcd37ad82cacccb8f931b0bf0c0c5bddc1227e822c088b4c25b89d59d899c5098d3f409905c11be36d28cbb0cd02d6cc7898f6d82c9ef6a366f1b42030c3368be7c1b0187db20c6398f6a3f386190104ca8a7022c230530ce3a9c6c1b8c224e6170428a8e0cecbbaa28bd2e96429b8a6c693303c52838339acfe705009c4b102259b81610c0d0c5bf86910a73b229c6427d5c3419c218c326c516a7e469c68c2f37ca55da8242df864450a158900000010007315400020100c0706e3f1681ce879deec0314801175984c6a501dcbd324895114c49042ce104200400006044064a64d00ea2bc09a2724a73057b2ea2914d79a31dd40a7d5ace371bf5cc0ec7e143766d196a571e9a6f9fa120431361026765f0f5feb6d95d49b0fce626d2520fccce42126174a7c165f3d34167a32b3e6ef9447cf161a708fd8c2e84b411232f43f7ed9399ea94c4750de7d68baa0f55411f6a26a6f895e7d75eec9ff56fbeedcd0d6d086ce1f1c90f0fb264a129e59b717a09b919700ce2f411b6c309464116230af4f1b0b693b3077d307949c015373a7287e7be08642a716e44f7720b153ff0b0070318a8ea71071b9120784033ddeb00785ae65801ed27a374e76ee29b2fd0d626ca8d76e8b983667c810cf509d480c8e4104866bd2cb9b9ca0440a79062d80a5ad9b27c826a57213b889f24b4e837362527b489f5c9e05717262d1e144017c7e3e6542b512e8104eaf74620e6338067a29a1ec5acdf8e91cc0a444020df92f473c42127e15b04cb3f20bb731823a1f4d5f393f5475d53f352f9f0513ce28f2351593bad2a12b14d93cc5acc5906119f7f393b08d7a09b734865cd45ddcf09400fde55c173ba6a757a0a213555f82450c7e68e43c86f0245801a9c464937153cbb64928ba99a61272343d64337ec093d2641fa96b763d87af706036d2a84df26752fc2fec50da043569683a2dabaeb1d2f365cef8836ecbd3ff00c774cb14a8fc0966dd733cca3f832894a188534023a18f35bd739506213af8cbaacca0af9de9a691f5caa70b67baa7b84c14bc62a9fc375a54075c51cdb46538ed3cb503b0522054893d08aaa5945dcdad4021e024dd092338d7eda8a48554b44da76890bcb0d16b51cf5b113f6037e746104e6e1fb4049d3d2780e4405f817c637855b1f0a97082bcc4049181484c9620554c58580722e54047a88c19d62a1174e9a92c319f1131670c0e0956e1b0422159587c7d5b401a071ce8e94915313f28630d2d9940ba30a566a2fa0a9124d72c84ed68f06f6df51b2b1092d276c0916fe906743dea82153f62e532e8bf96893d02ba2c6a1ffb84e1bf4424310221451e15e967df3a01e4866e677ababbaa00d0535be33e4500b3d540a8097e1bd8c12895abffe9f44fa37ffb0c6fbdbede5daa8e67ce908e21ce515a6a18ca9f5aad020e3b4504cc6d42f4cc3d48b2359c578e38b7f050979431b29f1df293f0f5ab1a88e621931e2b76e902c744fdfb1c8147ff151921638b982db3ac9857194dcdafba5e40191383462cf7465d97eae26483aac2f34476de17a5d8d6848c104941be9ad0d822c1992a07d452b348044a9e0e225de2f1fb249161c114b13bd20dd86b0d8431ffd5a258a8d724402a49d502d8b0bba725181060c2263cbc8b1c672d957e7d1810806e5e902b190464429c0aba642517e45f21b28eb46e4daeffecc7563159600f908a948af5bef66b4545df539c2da998fd802a5683017dfec0effa19efd64829b1900520397596dd40048d14a7c8bdeded8368e6953cbac6f05d4080bf69f23761b4a8eb1b2c5ca08a3c5bbc02e92a9074f2407d4605c34ddd4d0f1eb2b9e90176e1dac66760423435192e7236aa3e7217a8c4582600ac2a317ed69a5d3d3c75ef984404594d03baf4acc1815ff951a7bd3ff5f6d922ed16041042411f969805e8173fcf43f758a671a238c7d0de23f216b25e9ffc1605bc9bfc058c72ff608c08cc1c8b37cb42230ffbab7ea49d3b6d884225cde5569436f52b172a263f6c307d5ca990ac1900e3318250fd1e7ae86cd186f17e252fc1b9d322e1abfc759998e5272f535456bbc842a60afa49c83987bfa283804767777856609b88cfea3d5a0fd2e9584b827123fcbf06db004a7834475991b46571fe3edd621f3644e0e4cc1aa1b8b321a0f35db2a80bb962233a653e55e7210b61403911401e968b55c67cfdb8443e0c5de655b6388ee57e0a332ea3f798017663ec1a0a95be3ac83e7255de14de951eb9983762656bcaa0c2c609e51cc99805caf00fea0d41d98b59253bcb372009ad43a00ad252c08e7d3aaf27c0ccbee1421cb004776b1da766153e728447be7bf40fe2ccd10f22ed900c9400595405edd027167c368edd8ff59bb41249da82c12aabb75424f470ad57a5d6a230e3a708fb66c4559b3d2837e4fe06103d5d416f7a50397cb8cd3050bc310ccd1e5685caa77748a832f61435c96f5b32f19312e9ff3373cc9438f69c338babb2b0af74064afde96a844e59cfd17c2ce70765153e7a430e845179cd3d0bdedf6c5931dcca33165a725063efea276b7c835507c8837bcf5253a1b3a15fe51a3923f28764c5ce369e046d4b0f0b252c30c545884691c03e6b128915b279129884290fe188d7a883339633c9b552e9f35cbae467bbe555c2dde11821effe2d8ce07c897a94d8e34308ab65d031eb1b007d027b00a20c0124c8bafd9d67cfd01b7a0783bcd131764e71f6ad142e2a3b883f2d2034f92487a4e559bccab584700a93482b0e7dc1532c42dc1d05f8b31946a0d5ce26a9529e793b85bda9f32ee1094b4998da848b8ecb1b2495a0c2de4c07800196df7fce5199ae8b1d97aae2e377c4be27ee6244ef2fa70699824f8062754234b6a0799fd74f97006deab6bf909c7033077c84da13827b72af8e01e6373263d59e8731369bee19a9776005722f7a466f0a9d876b52559c6095e8ad01bef83a7fee1ead8ba77de7afd556d1d4c6418180c5c8c3d9a2349f23d7506336bf6990aa7cb2bfcccd03a436f7f754d75e0b318d960c13288d6d2661aa65b1614d445482d1b169d6a0dcfccf235f7f4fc218b8d04bbe241498305c546307c2b8aee1eed7363fe3bd9596b5c962c13ce143e61bfa78b96366d310c8b23b10428ca00e04c7be4ba2f45fe10434a574c35034177ad2b3a1a13ea7ffb62c2bfbf800ee3720749eb9d061bf659d4ee327dfcfeb99562e620cf593d513d4d3d68729073b805c81d2cc060442e43f054a4711413726689246ec030444921f4a4989258b205dcaa175ce7000db0fec815e2243a8d4257043a05e411953fe4d2da6ef58c61a410740d122ef0a692e60351efb22c29d14743a59419dfa5abeb3b1c53db3c2a7c0becbe87446207fc84a85b120cc408bae3f3f2719eb6f425b426dcd831ac678353f10494ca0e269e3c1a1a206e691fcd5348089106be0d164470e3af79366d802812a5e75618dd5b0e18a0a373167f6ffb4944a0a0164bb5a7b6c3585ee2ea85195025fdaa020cda535c7a484f2da6d2e6e99928672779967bf8aa4bf10b903db478066e8a5565f2bbb1cf3723b519e168fbee39caa2fa279e45f0288b49eea433defcf2390a8c4a2ea3ac2349eb0d416bade85651a7a1e5d67a5b004ad32acfe35a877f6edf0f4a92fe0e351e2198cceed4734ebc03e7bba12897a48615f529f2a4caea2e14614883ee384238b19d515d160d4741c3a0c9d2892d079e7d805305c32570a58780ffa09631e22136fb49b6433bb6a5294808f71dd0c142ba4ab43a4d0ce7909053e033e937ba7216873d9a406ffebc8d10b56df6e58cd6bf5af88d0f1f6c7ac010a21f0b657057500d4d7a2ea1f302303ba6f4e697e736e4676a16fab7c100497a4258d09b740a66c3812b2a75fb6a20c591ed07910f9143256fd0ca6d9c40dceb069816384fb3a8d0e453c0f92be1a1f8839c4e35f49b6001675143a6eae3ed73a042994b3d0cf838a563fadf7c854123e034bc413fa62afbf887f2717e88068755ab420993772286eee0a4b0c81661f43cf37e08c10038959382ce789e33cf5aca78fe9c959dc9377a48916da3e19645f908e8910208f690c0295bd1d72f98c5d398d6b5d5862286b2aa916d063a5ba2c71a24443933532393f3b612970b874f7a6d0c15036b847326a39b22ab7a656fd65dccc815bb31e5880dc7801559569235a2e5565ea38e5145da210c5f2f910a415e4a55811281724b1c0e750d34ac84cf735964409e63ed9763a4c006bf0ba64c68ebf457080417ce2947e0cbde87b0e23c8164b9194d8e6a0a22fda0f37a4195a731670436f2b04fa0bb81058c83c4e0ca9b9a286e51a330773d88d5549c1431c4928619a22b31c62159ba5db37381704be38c4212a0f89076355bb13581015485b87bd2133ade04eff1ed088e9384726d605590e37600fa0a1496994a0a7a4c1baa48a5a02e63f8e0c5707b69c634bfb9682d8478a337da41a6575d04651341edee26bd1c8d1fb5736fd1d13a31297923072adc068d481728d1c9c899bba6dc84d0d3f86f67caff338ed1f5ee0986ef97e370a21f2336f34d977af59a95102e53a8c974f1f4931e9f3a8ccdc5df783f0e153ffd57145d992fd9e27ca5d21103e94f881792d5382efa51989c987f33d9822cde619ab4eecdc7ce9683997e50d8c4a8505883a72ac049d7b3b986671abca977a0c54f8a4e5be0166c6f8650bfe00c1e89d50012c9bf80e8b5c7954f678b16b93fb0a8dbf37b870023f04386f4d9f223219075c17cac7780a2f71394941d1b71d30ef960a4fd3d02ffb9ae4f734867687a33218d3d55eae2eca41a16e7511cbfe4eb8e778d941dccf733b9fbd004b5f7b5afa17dba00ef239cf96141ca4185f8fe78be766b8c4d76c5e88c65fd2052e70a96cefb0de6fe8b4a0bf221500cd671132e11a29839c9bc31646937ae4a4249480d67801246fbbd1b8157f09171915a0f79164830125c441c7fc105064e1b38a6330a7231b5750d0088ef28e34faf45028c4c8a202a1370b64da72d50efa3251769a770a4722a36a4a82450e46e8e0c74cdd6740c882585b72307f060d98839884f66d8041d4935feeb21469ce08edc6715b4ae80b64f7d25d21d02a70a8dadcc3e58ca00e858e95ff4f8800f9f140f94f0bdc82b744c7103fc717c26afa27865e8f3f3f4e77f0d5b4c22577e94c5115c7f26d6bb32a0d89c9537058b29a327d8dae9b909d2bcd59437de9140dd068845ba88669242e9c8cc4b59cbbc75ed1c47652866eb73533eb940e03fc4691d3872c77d5e372f714944bb55cb40ec7f05184bbffbcc0452923af796fe121501f734cb7af799ac2a6db852d141392dcf2bcb0491902a04ddf975e6341d64f12623d2bc9c8918988795a68a5820885b543949a03807b8833231f6957b1db71b3b4293f573905309ca1a21976a433751467149641b543b2781f590aff0b680044c1dbe5e859e9bda52cc0e8cfe44de44da3976693c188c0500e10426baa73b8152b9ac6e162d3332fc3f424d2d98b783b115a557a52773a89946729a85f13d1798b764f27b6f11621815765c26175f47af0161e36b47bc6d0618910683bd13b393d49bef6df1d9aadb1dee8413b7fde8d9a4967f10ebff9f7f21969d49e97a0d516575c0fe4974c26d0c1cd31d09cfbf83bd25507f9032d10b838dad8b20e20d5151fce190677577a165b3c87a72c76a2ed83e1c49f87856c1c1e6e3609d9a3d270b4ee5c306fd7ec19c6355b6c9733768794136978a4445ef49ac01cc74d0ec753b3e5fccfecfe40c37fad0a9ca0c75bd003dd26ec63e8908c8a84dd44455d7326c6d223d0e5ded6f0ec7bc8b7e55534781e04b68c9768e76a234479edfe2420268143737b11ac1123ebb827f929a2974d44a24d36d743138bc7e62d55b6b58729bb31d5f29306868ebd6570e5d090304abe5bd1662ebdd15d4406ebee50cbc1535be820eae5d0e3c649058f5a7219f7d683ce0ace10f5cb700ab2ef36feab6a4f20616c031c330d9c7d3b7224e2edf4af48178a11ae1b2b22eae1d071f1a1d2514bd2be6594bec54aa5d2ae46c50a514f4767889d2bf6a2aedb76e0425b2e9ce5099adb4746b66ea897879956df5e2ae3a307418f89ffa72e735be18d207b77f04649debd1eda00d1cdf1b5f425eeddc7fdd88c9608cc4901f0ccd8c4d6917d33f8a709f62a1880dc683756f0a73a5603664322f4761a951ab4c6d978e696db47b457c4461b9b6c112429e052e0280024a6d7cf4f044ec75db9fb800296a339850c0c0b0437864743de3db8837a20c258b0afd0ff0b85dc8594e939b0511eeaba68730d318e31bd787e06b74f41d3962720eb39a33c990c1d1d383e449ce974084801f1216ccc708ac774828fef0655a44f6c907fa8aac247deea933f0f739cf2c9ab6311c06ae66109c60557be0cd7a6533c4100671016485d56f142173d12ac4905757e5cf62b3cd5e5121bcc11a121ce9db19380e58f112ac040b70366a49244bfbdb030181a313ed2e44f029506ac0f2e0422c351c34c5e426d97ad544f422432e4e0c2061b8745233e330f4cf94ea586b23184b35a83b0f5e8fd48206f6f96b8d55479cedacc5849c589bd792e42cbd582c5a24b60dbd7df0b3188536b938300236aead2d226c32e90e722969f099c2f77018c42a6bb7398bb3245c2ad0aeec1f4fe8f2d619622de0fcf9f536e5167d856c11d43c43dbf2378ee8d269cc69fac3c4245c12acde89b5b73e327766cb731358a876e5c994acb6e0614ba8cce1f782ff4e7294303ab25b2424369c30b45837f00b240fda1c2f2193d456d7bdf515c726390496e4f064513235ffd44f257a6b1029e5faa5340c26b2125a5450a430f7fc6efb0e487bd4729d26474e7a0b92a58834b0f14002644fcd70e9e7af32c10407105f4c1beb3f418f57460fcfa61116f7cc58fd100841806b1e2773be4eae72257f432a26130cd7386e8f01d4b5871a00289b917211b41017cf9826f50039dcdb4a2f57b0e4961bbab9e0feb59039cd04248ffea62c4826a71f550e7949025ac03101f5ef22448dae8f35ab5aa0f4141025a34c176b78b653f20544edc40f7f3286871c61ea7f91c39ab89c81ee55f52c196c2f6c3b40fc5572a805c804a43b5c32d364dac08847b0856b6db211ca0108c14ba7a8b63175ded54276427d8df74a63c8aca9b6ec0e0f3732cd3806945476c6e68596accbff95e8c6c4ab4cd6fa3b9bcb55729de3d69277956cf31b63838ae439e28dea52b1053a529942872c0105e3a8ce8d087d062af86eab4a423c79216b6cf0bdb72b56a8267c89c36a540afd4a46cc9218a74c9aa780bec5841925ef2f4ad09701a3d13e111c9ba8dda7a09969d1f82e014751a434a8e65be55a08330071cccacd6e61dc3d9698c14000f19a992af9242b2e6b70d471661461b3d731496bbfcba90a7227ff6dba5952867e73a44dd21d346b42ff38ec6b1d45ee3d86fa147fc531b83cd08ae2dfff344235aec83c2b6ebdd6b2aaa8575ca248370dbc37810411dbf3875d8c12e75db435bf9dffc379afe60d3d4915bea9e707bd010921c76fcfd828cfc1c3b5efa8cb4543536988d60fc5ca48f7cd37326c80ec6ab251d0ad56ce1710a776a01fd3105716deaf8f98541ca1ccaeace1d9888323e01b8d6d10ab88902a2c7acc3d19ec4289f726758fa1d6b517c0ab8f8a48383e50260691833bbfa0d169cfbbe037b5429c8e7cb1dab279cffb4e222c18c4290958ac2ef1753b53e77b02cecd1378ba0bbaf58a76cb325bbd80841147347f0f28f0fb231a8529a88703d40624b0444383f284e08d339cfd6ba616d2111f2d8320b1c4d8da6576225a53b21440cab0c4da7a0d39bf3dc16b2174a395bb8c661e45ce4f93d2bbd48413f9f28b7ad496e1b0d984d33754624e66dd8af73eb5d84a00291bc409d3956c1943e052d746a71b0180c07ca32267ddd237f1eef85adda354d233dd773b63223e0d499d1294691d8badc04edd7420045cb86a6f06b07a6b07ed97049a88a63a0a9571e1037f14a1799e38008380df2f8bf7788b8fdb4f0abacd253ae0aeea8dc85be6208f20e82b427382241974f8814e6b66d2a331c8a9a199d0212381b2737a1aaa03d5c4a4f85301d57d1aef2722e651f5fbc59b1e2858c44e6436c4391185f87f3391a8001a27143a4fb1c2f35c1490abb6c577814c4c7a78837ec684eb1399e146f24af525e8b3cc415abefa34c1b7a0bf7987dbfcd88d64f89a22e96b7e71e66bd770905b3b22f04884ad400126e2186b8a3991b3df80a7512c9b5634bf6ac6eb5e2d160c64f6ed2106b25c57cb32fa06fdbfa687711abca6a3ccd682d3c258dc9c9aee0153bbe2794077dd893ba17c43bfac77ea3f1b842e2ccdcbfcc131f47e84de39adfabdea34795649578ba1f8be584ece6663d63273f76e779e28aa76ea4ee4b504a24c4cde2201092864a20b188f9f8ae8bce20d3a594c48c2a7710cee9b6a40bc6f3a1550c6f25159f9d39a64abbaf813e3dfdec362331ff0e27560524d7544b5b4de2a940c92b2da7383427d30d8e341b8752d165d6d236a8530b20b8865a981ab0f8c8b4ce804e3b469f35ee18c7acb7cddcad3f22f2c96cb7e3e8549db2fc12009f45f4c8f5a6509a34d23b7ce7a65388dfa1540ecab7630e2d42da3f4ea7b4064b5a2ef153e8e595f6e329701a2c00f6f32a8127c9e74370234f88482f94e08a5ac92abfe1efcbf06591fcf653232805aab1c3fdd26009721b415aee39bfb8880efda21162cd198c5b4652bff7c0992aa82b5fdef8e254ce33c59d51322fc8f73148db3e2bec7bbc84ed7b80796c6195d9c27f884419b4a95b13bd01567578802dc684624c635bd95d4a70a835948c8bdf39a15d448a181227c38b600bd102b00dfeed61f28d6100733cc2bda1982cb3eebc77377a529c5254d767805521ba862874ca23cc4edebd23d7d3862a3a3c0c36c104646abb1148f54df9405dd13fd56ba18cd5d3a43ffceae389a6a2eca751811811ac5c6332d370ae27ff0ece70eb2c1ac3a9061d0b32719d9983e557aaa866d5434d003722d881d2f8b63137ecf3472c91013d76191244c0c511c13247410414fbf7c28224e4079af5f94b8ecb4e5bfb3a360fb177662a336637eeaa2912b55974819f73c7b7ecb58269208488a135162f3623edbf16281a41bfd7dc0dd3d884e85afdc0d75c0f4bd765ab8e170fb43c845577dd78d6bd8372ff883c10f9cdeca74ebb10474aa93d0b491c6451204909760645c47d111585b02084d7862520e1c5b78e61d1368778edf62738921762e4b4f2ad4db8be68ef83ca6909b20aefdd7032bab6be81c09f733a7829af5c838bbcec3233ba9ddfb48f59bf2ca088223859849f4d0e01a74aa49c960acc51729cdfecc964ce983ae6669f61a2f9e5d698ac07ffffeb94f9d5a7fecae30fe06c84958c53a108833d499d0655421cc1fc2522f7aa745998d7a5b0e0c46003c3e5b2b3d0c3ea8f6fe921517179c0b2ec824e9e95d7d66761bdc78756a780c13a37228f35939cff21128f6a3ace8b3cca6a6d79741e2ed62c3d420fda44e59846846457c9e54146545e0420eca05652e15531de0fcbfbd7087aebf859dbf5960efea72e5bb62a4afc07cc6aa87f69bafe41a020982866e749fd593d5d98df897c7b931c5df66fc16da977f4996a0a569ab4653056ac5c007314231422726e0967c7650ace98b1f664cbb2b28b45badaa2a7b77255c25b83bcaf3a0fad35ffaa6bb2962e6c83591f992a46c760c5a23bfcd2ef92f86f691513fb231666fe1afb8cda952931d41273b9b12f79d0f47119507ac635391868654edd6f15985e92780e2e68983966d192d3122c118757c4fd67ac95769145fbf51cab9dd77dd17686361268c1b17443564e4d22f382958251d8c4a81f50a8aa7b78036a22a5f669a8659adebef6c5f1927c04b1acfc729a8bd1352dfecef8b0f3f2d5985eb5c0a9529b53612fbff9b15611b9c697f46f8b01860ebd8c0c9133e24835484a581e91bead10772e3c646cb41d21c98d2b40ac1d0a04c3d877c3943aaf1b92788b049cbd6c60719529571cd22e6fa73a82f3e5197b76a064c2a92626afe4dc1ef818c159481d440df61275784c1818ac2716f5ddc244ee8a149eaf506d2a2f609ab4bf5c757fd7b15d8dd4c78dd7190ea99afaa2fd03d881c26d563bdceafd18e42dcd8f6d72f48f71b0d5a31a803c5b196a5abc0b5b9841ad7ff8aa180b246dbb6ea8ff36a60de97952a8233e8606534e5a491c0e4ff2a279420224ed834481e9c932979ffe7ab039f1419f11bd344e18d2f3a541352044f02c2d8088270ca85ec11cd7d40353bcccc909b558388cd45d9bcc19e6e92c5c1bc644538fab7d069b81f8ef26b9cfb359037b3e6328a02193cd781ac0a34be482146abf9350b212be6c1ee58b390eb4d94e6d0c30cd9816991af56334e3c005b41c3ba6328bcc5c37c89c6fbdde24c8db10107c462bdc027eef30261444fdc515774b115f782d20ebe53677f177e1c69822a4de93651261565b1433318e5800bad80e0d7a562e299a86c1b5f7a4d856939d6c887ea15668744d7c1a2c7c7a4532b5cfb55290574eddfaaca3672d1890f9fffbe50c58deae91f0186e540ff7d9115517db1db748d5f2c2953f8381881a99a21e1be98f241b2ec627f7db7f2de8711c706025f0c614d15b4149934d490bf8387a7df76c71b25fe7cf8772bc5a28d71e63c75e6742b950579fb6087a26f7c087280f57bcf72df35eeb360b92b79d5abc75b6a16feb0197c5e491772c9a7781024e2bf7706a3992b3845222a6bada2ce90d2eda36e0d585e3b266a910e2f916cb3abaa59ad4ae45c22f24cdca6975dc01abcb9aa0af9ec35e8f09e2b002a1c591815a06caf8e68e6e4c851a82f0be4ec947477e44c3b439d6a6b218b81086eb68d6f0330790d83e388d170fbeeb78030a2695c57824e81e2a0f436062317c2f301de70b97b61a312f4e5955d70420b15404440c2096e0049e699cb222e061a5416af8944c88bde5442dc0044e6c61de02e8c73d17775847fe8404bc2f37f735d63456273e7915affc02762513b6942f51169f766f316d818760bda415ba2f403ef51f80f46eb98bcea5b212e9c3c7f48d76c9053538671932ee5a1947dc5637d96bdde250b79eb1761f5117143181fef099991e8e5f3552ea19759bc533a8cd6c4cf074121facf46eb1f17ea7844afef889ac5cba762d7c14fb4189c699723e419ea82094ffac114dceafa86511fc80f6a5d6a035a51d152879f0b3469d9b737111fe91f6fd84ba4b3c7d7ed6dcf17234c0f96337d7d5032b8495d2bf27674734ba3a93d41369eac71ad608ad82fb0cb897b69c4b2dd9c9435f91a1cc02c022620bf995462506409208cc111f8bf0cf520af345eeda1db5103de44bd5d1e50cccc5845525ae77ca20bcbf79eb8283bf6220f9b9e5f49bd7a6d40cee214487888934f77b0c2c24cd1f59c9c32c0188e6c300b49eaaf89a1aa5c8621b5defa1540631f7ded0e20d43e24d36f4d6af14dca2930ac2d4e66e1cf44c1f6e4b330d0a17ad6589f0ed0deb7edeec71e4f833fb3e57fd6f426ace06a530ee1119ddc5517189adfb746be8fac4f20aec5f263f946d323570354d7938ba5e6b1d72cd2bfd466e9ab87c29bc48f516b68b3a6ac19b50d727d6c1184c73a62e2343e4f8e097933d390929610106a402d270d1ff88a88fe3b4b898575de21d8ed570490caf9a7689f665a412268b821f622fd01a4e1568cf4947b58f79dcb815ddccec6eafecc7055a4f7a28aac73de4a0b620fd832304d9ce9e86f7ac060793997abc82384c48bbee3cbb2dfa27cfd902ade7a5fa26ff0f22fd8a43e613e08fcb5a31f096e601bc6028d29b981a43ef2580594b8709e95e481c78bcc2df9ac80cfce7d64d13df91ccc78f5863b78edb8dd0af6bd8ae0667eac549d8acfbc27d5b03fcd93f49d1c3d9e0e060a8f8994997d081b036163223c950d4f52a26c1422d0250a25458ec1848b3ec4c01822f09f44c07f86e2dc58c009eb5ad06198dca0046a484028daccdab570f08054e4c507b913b7215aa7e74b515857159718de11fbddb0f8357b261187bd3daa27f2d4e664a0ed2949f17588226f122a64dc8d40b77eccb78381994a0789263b54ffbc1f5154feeaf00931c75e6c3ea208416b0be6b5ab2ba4f4d14dabe43291d8ff91e3a8d67cdd9ac085ef40316b779c710fd5d9392d2b11ba19a274c9dada2c4b53c08b5841f3702c6f80ddba4f6f669cfb297466895835b24b894ca76eb688e418bd63c94972a4fe077d5c3d195cd8488d3b9dbb160d19c4e880e65dc697a93eb7c61ce18c2ac881162d2de44156ab0f28b4549fbc7c456fb8ef0cf306e9dae46fa123f7feb2655ef47678c16217633552ffbb793f2815d64c66d04ed9bb4a2c7bf39940fc61aac116b4893e45d7d2b920cd36e3c1666224efb59974d9667b066d81f85ee8ea4c9015602fef53d5ff18c218e041600925b00ade20cf6b3e65220efae25b167d1212cf8bebf48a635d99d2850123980d6efc0ec19dce9ea7e1bec871a22db9cf312369e0ae7f25e02ad1b595a496a39cb4235871e6364bf621be17118432e28a1df401f9707d0cb06997dbcb2423af351e2412f793084a5f9964d867b8d8db7b85146d64d7c56a8cdbbce31594338f01e10702e6b1dd8ab8036124785a102139958d97ac4a07545b84ff0a264a85e5a6039d29ae24b9529e119e1408be059e041d49a2a0a5bb1c39bbd0aaff35ac10159f53c4c0d0a773b8741be9c90875d608f76e91b6005f8120afba88b22161140b67cf0b5bf713e628ad26d4ce7bbd78aff080847da2ad69a5c83d05ae233453b854eecd0a34b11611c45ac2f2cc73a713226bc7d416d574f64501d797fe777e558a3c1e4c0898a40a7d79e97edc7e041f3f16638d72ff9aaa37caa035ccbd4ff7b914d94526165f3620e46bc2bba8ce90b9cd32e8e950912fe519dd51ba88e505a45770d273594bae5ddcca6fc8f8a9973b09644454a578f08ea4ca7d34d1be81a518c56d82784f570720b90d647b0c211418a09a8de5aa0e0b45cd695c0e055b8acf396c943e4ff264a4fdbe1ee6eabfd9e7d05a9fc6c26c875897331ee7710bfa81c1e7297a126c6ab1da829e067c624f048e0d9857344ebb15a6c70d32a4201bd16858d9d121c90053761921f34c3556c0af16def823fb64b585598100075d20a0ace0ac2ccccbf9043dbc6b4a1c4ed9747dc6ef00d2d18f9d3f8f36a136be2b3891b96d4f058823b8809ab71fafeb0131b437f34235ad72d400ae0256c777b1e1e80e0d78ff2b2c4fea168f99caa9ca8cb5c439ccea0350df044cac987f52ba54a15d8b7c2de0f3cac601e6f9dfa9e89e7324b0355dc5df4a558220ad13b120cdd6987c677b82a1b3b65624a229b4e1a68902daee5ac5dc7c7df8ecc90766593a356dee3685c9175f183a6ae9beb09faa35edf98ada803d6fba3a02c5111060ee6e8d2d1c36951cb84aafed1900db4f3bfa6cd10d0b9d66596b11f149c1071f03ba30f1cdc130a87d22f2da457cc67a8b089f2daca1ec6fa64cd121bb8535eb4417a7583af943ad473315a433e14ddb7c4390708c0e1069a6fbd403eea24ceebde3830e9136454a7180e836cff0ffd7d34af318ac120e3d9fa463dfd3e61f92416765ca15cf83d74a46e285bd62cd146d1272cb508a576ff6f94a0c31d0e5b545dfa89a0c01de8494dc207324f966bdaf76a7cca7623423c330918ff178e38cd9ac8670cb60c75cd72bdfc59d24eb9e0246f3ba9ec06876fe798512d08f936b978e38699c76aab03399e4351632fb6070b955e8b0ece16c08d177540261cbd3baa3dc6d79215a878b1a922ab13dbcf7478a91245d72abd301edd28126890d7e5a85df6b58d1d3962742b7146422963e9422df299c57a79a4d36dd487a44f3b80681f7de40db5af85a723ebbf4c71264092ad8a582646535c3472ebe03e45bc7395c8bd6ad9785ed8295356a56b07240a9ecb02d1936704214a177719c5a9ab47bc866731056a63499186cef1289d3837668a2a6123580fccf905bc9866baf4204ce2a8efc3e8cc8806af650a749379f7d7e15b2010e724c6db3cf93101b5ad9a030532cd492c6663d54fe11b61c327241ab715a517d1ffcce79c70e523e5d971eb49fb2af0a974fad686f05a5183c52a3c84373a0f726922b75c816a1bc220e4e6ccf43610fea26b489098bf592381b976ff2d47323e5e45e58ea5b1d0ef308b51768e18e1f730207036284501e1c9c88cefa38c11da72186cf7f8079e9bbeae597b94ef07a0ab9a6c5427ab3a276723a1e92710c88d40da0c7f3a2c32f62c78580ee7a80b3b9c10470528a630b631d92655fabed365506ff3b07f41b16d37f4bd7630dd99b177b452b60143d18a59c4f5ec8deacd341d8b60b22f02a768dfc70dc11436d849617f9770cf2b8be98d385f5bbf759d28ac6409252010c712719c7f84a10fa815f6cf053a8e7689962ee9e14dcc4098082aa4b5a28642cc213beb42a0c512f215989f802ee52fdc73d01c9afaa89f54ea76566f7483f4a26f790e55af63474a90cd7342ff561ed16e80083b7ffb4495bd116ca0c830ac630ee299127ed788e9c19be87b59ed5822906fef4a0090e28e012ad52881d0f08432a4153ecd1092c82901dde51860aec6aa03700ca4c18c748983a1897b25f67dc546529a46306a62fc90dcbbd6fe64c88ba3d417102b4d029057a963acf14307d8999046ddb2e2e95cf2f970dbd3b261317c26aaa9dee045b27ea034f5e4451f58251cc0b647bcb84a6c6c86336ec19323afa4c4939b1a1eeba6210edc683c70474097334facd5d5b9dba185baacb1ac24ba4e4010a73d2035b7f0981dab672e0de472bffd4fbcbca16f608ddb11e5f48937eff590d932d7fb9269c1d74aa116aff5e5eb1b4467f7a201d7f4f8a306f220f09b715c4c2411d364f663e1bdfc891cbb450f072bcd0fa898d1c5e11c5a8318bb51c6ef5c0b4a8e12327a9099b25108c984e5b09abbe0cd40c7abf637976d03222b1d3d9de1ab956a745575c90c026ac693c9a153918ea31cbfe79967d7bab38f1adfc0470de14b4661a41c8ebd9fd8945089a2548f29b00cecc3a476c78a8ba9bda09a4798a06c716aba8b788e3f83dc2345c7c2c545db9a999b682fa3f6efe9ddad6cc10be38d9174c19428d0c82a8fd56c4542b14fc22b57867ff2017bc2395087c0cc96df72619d04a2282c6832dd42f190439f8d49447962c5086a4dd3d9eacf92bdac30ea4c84f2ef261330e0385ab0adc5c49b7198eb2111317ac98d17fadfb6bfedff932c89dfeec204ee97c6992c092660c5d6db147eaea46692121411c6b61b9ab90d5d2de9f09a718c8ebe9c3ecfe869241fb151846afb66abe7ad00c47e39cc6ca11fcc69cf48cacd46342e92662125c11c211e8f846b52ce3a47084c239072164bea4f7ccf72085b013335e6622a129b327c748953078b7ac89b5f124608277ff636e15a6eb0cddaa426fa5f2611786368bca9eb4633b97dbe7919963111cd799008275e8e2071bd97807f02c90213355c7da8cc022af8d01f2d211b8279ca757905c0de7fabf3fd563c9e613f7bb437b6e696059baf026b7c7fe0ca2acaa3806b0fe44bb47f3f833e79e8dbc24ecbffd0ed1d74d1cf7a524deef821a04a7ece22b9264bee0fd491b719c07d4f2ba032904008c8de329739e5d9b13643a1ec6cbd801f8c59013dabfea805942c1aba2101f315c9f162606199adf2763021f428214ef626ce9041e3abb997fb9f0d5fa988db6a64b03533561b5ff6c57f2d347c6548cba645eee57106d5e709a941572866dbeac0c03fa902a03efd4b7fc70b2367d6fe060250ac204931ac7bad42c2a9138d31e9f340be1d2b3f485af4494d4eea701453927404ebdfda7969c923e8c764390cea4e91d907ac04d05ccaac9ce871565971679698db61edf40c402cf7d1acced60e33f2c232cd407ee49883c24dee3b0246531eb51fa9bbaef54c89ff5a558b6c91d9e5ff39f8b0a7e5960d4b22f169b99d04dcd597b2785367965d5e2660bcd9cef55bf42c017f27efa569cf921aedc5bc5562ba7be19cad4ef07a2af2263eb367ae99959939735be189d39f0607a802759bee7a85dd7610c9a8acc012db106a1633e91c3c9ad9325fe631333fcdfcaf5485830abc00b2386997c00abb1e534d518965bd3d999db939f36332574c6c85a374277477a7ab6387968d427ccab5107c665fe64fcc5c9d388a9ae040fa7b3041398280a04c3892fda40c32bf9e49764fb4305c64ebc02184bdac5efd60e7ead1021538edabca3c32a4c96ec816c9c1246bdb20a71a52ac7f02e3aaef1455315a658dd422d5e8458f8b05ff9bb414fe6846bb104ab1fa09c43772c44b472a7903249b42623c24ceb313f76224bbc6675caf8d7cfe1524e9005925ceab1395f26dcbdaf9066ea2f6d4782346a28db5a29cbb3504fedc3baab1a15f0a930d6ad4817354f956fa900a45b43051d192cf81258b45819a4c496cd8d14fcbb721195881bb1ce51c1a1a603151fde6183ebcf48a01c69ceaf9a1c805777c0e8bc6f56d92d50cf2c501589962882f0baab0c353237d0bc1f2b035503db6348632ea7ac0ed374e2ccba9a09463ca054af99242e6204e2c3b68be7861b05af1b21ed38cb43ede50b310243757bc9aebda22b1f5e21ccca2ee233cc5258a34a800d120312f895b88bbf51b56a774cd1283c3a3f587c88bb6fcada2e3b7543a72d19cfa164d9118eac83b85baa821d986298aba359e0a425c91d589ffe25b86f00d38cc7a95d8b29ab8c39f9bb0faaf2c485ef5be4f6a99c7769b23dd2a38c0c17e76caf453bd927189ea2375926d5f4ee462f4a8bf5287764344e12d4c4ebc705107acb044cdff72127f3667aca5a67e9570f94e1788a844f00e978c73ad074bc3f661a5ace51242a31bb8db5f11791b4c8ad0ae59152b33822eacb4bb2eddc7648aa661122b69f106fd7e5ce6b1810c1f969cf07d40df3cd6cd55c55ae8802e90030954a27db3ee8f9ff91f9d78eecde0fab6c4ffce60d9c02ef49801171c33b5c458226c68d1a1294078199705b9f69910109438472332ddb6cf94d9e4400c9c192999126851998855d27096e94490127aa7f2975c04a4d7401fda031b58e0c967c4ce249833260591e4f1395e2d5ffb4c95a43e74403ff0c072e085b8efa3d7baf16da8ea902101e54bedbbdd76c1bba09407f8af26f718fa60647f690e4be1b16ac1e2118ea2e74dde52e21f1ba454aba01d0dd2c3d325f630d4dcb08417ba576474422093919bcdc49bf5f1d76c7e1bedf4d9326bd93027c18b0e51ea9e587198bf1cfaa01fc84025b03e023b34e6b1b9a932acd2ffee875a938d6f79dffb743e37ef7b8d7d24bf36b767329c3e891a6884e04de1a0117a2318d40cd21e1816c25356e8a68861e3570af7d5427669e92e2d41e1ec8ddae42c97ef726d2968f1dae3e78c674d63be2f7741a043335d7e516d6e30d68c843b62d324907ef8c5aff9f0da0035f4402fd0812e9039ee57e2135df5f3b7391f891d78f84d22c912b19219da8c1a02c03f404c8e3f17b07e3b55cc1f4298c7fb12b784d7823e5611c64dfaccc2cc19081eea011e290313825e6337d89287e80826f089ca028cc08415d9525448fc95636d1c062452b2e14819565570863074108c2c14145874ec31954b86286ed154533f1ca77fae93a7e528355b0ca01beec80ab2838c1949acec0456b156e1ea1d9c436423f1e0a0d8d829a435f505dffba74b3540e8ed908a3aad97f7caed14c99d352e5f3134c794494c935488a3852179d71e868191f35aff5d24f2b5b7b6a9ea9214cf544e6cd81b8433b5fa9565b20bb75f7dc3aaf7578aa2195eec22a94c589fd55526edc271070cb89e06b9a26250e872940d110ade8c1123658a422e14716edf6874e1b97a71f60486cdebd727af7fc865124d93c9da58407128a8c2199f614a09b1491daed76182e3e42cb299345b0540a7531df83ec8b35281b207adcd161b72504b56f2facc3aa5ccda024b29aa4745edb71559221e266e848de792fe9c69bf0abc364d0e6d3bc18e3c1ed228f121ae9527d1675224b136586bc3e047d9e8dc430c230c3aa507ab8377890bc8a5b3fe32b9a317269a5f5b96b601c4c8c688e3718ca71f6851e80097995832a7a47cc0c7825214e34a36df596de4b1876d150f6430560d9e7b327480c2deb2949e3b87e904e17adfba30f8ad3b47956ac6d246a8365748395c25d69a9793b416167abc152e9d7ff81ccc807bc4e79a6e361de4d47297d0634b50e90d2eaa12f800a33e172ae20774fda2bfa353a0d472f8a7304b3327afee79dc9ff8e333abf018b89454b5e0e0fd5dc94ece803bf3d61fa00d56e8c0e5a8b1d673166438403042d20cb80532694efbdb225cf524ceb1806506e04ee25d6c647724e5790a930165de090ca8f21b545bf9a2639704d7684f1042026c3492528af2834c2c2d389d667607f6572d57ead66f4b0f91823f61999b1570a55a5edc2cdf1c71a79e769ba3c6681ea99fa677150e04fd00cd4f0b148ab6931793becda24917be0d08ad945048bd2972f7179a49f9f3299110d87154d08b77d15020ce714910dd89ce42dbfc7f98e99c1ad3ec25888f47eaa14b8392e3b6f4aa4d4c08bbbe93bf275c9a55d200563308017ae3bbc427c12f62b1746f259140a1f2d7743a219ddec371c08e7c6e94b834fe650a04595b1f3803ab5f0529ed62b03b3f6b91572ce0ba69b18dcade0f7eb53ddb88ef78da2952eb25d3f2624a4e498db7ca0ec0a03b366cb55077d2e587d9ae5f93aac72814b63c0f1ffeec5688763f295390fc3f63f7c46f0610105c45cf401a72f6a351c41b7097c5f3dd561af61d21e427ee430b77844e6f9b51ec57d90176c2ba2c2c059078b6789aa2e9d6406a8ffc9e2b14a7b0b3778f73d5b68da0051cd2f02399538a6bdb7e763122658b6d9f98706a48402682016b722379fd6ce449c54018da5b80fab8b66cec2e79928e5fe88034ebcba24d077cd536f0843fcc3dd899e2a2f5007e879a30bf2a33a1e133c6f6f3bc9521ed36c5a49e6ee64134fea61149524622aadb2ca11c6c2435b2d7f208bf4020c0513a15d11e78d99d098edd522ebe34e08ddc9632afbfa570b2e1b36b8aeebc1a8f0f0be972c3e684c43d7689ad42e35160f2f4ec90f3653c80bdcba0d25c8e676b8fc0960da4757af8364405cb667fb7e50bffce233ec2ce42b313c288cd2cc29ed1a76bd3935fc782048e6e0bb427c54e3e75e63c305422f47c1ca61d5f01c85802e623257cae11d80268ea7b1c138478e58024e0533ae818e4da4709033f56cd1b33c5b1e28ef6cfca250ad25d26953dff80138e658495f414cc32d804ed365ae5926246f24572f508da25ef8eb77de5c3637e6f13fae9715fefe437b66c710b66c7e6d6e3406f2ce23e80b7806abe0ef87b85813774f41aa2761617590ecbfde8c7eaec1c2e197507e60fc966d2181d4035f6528aeb9699309761409cdc7d390d73a5c60170cabf5e7f010af78e3d7976dedac5c49e6c47e41aee78e6aa719285970e31c720f161cc2478ed2c47f51aef4cfda5aaea04110595406733e89701a69d9e8ed66d439a6428541c15746ef7e261c1e1c9b3ea55480541e52a402660eeff8341802bef6c3db37c7a8743050f819367b7809784b83df4c83c93c6c9822708f74144b2c71433a728f97a20c270c1e2e200e0934a6e9c67f3df11328178c64ef790fd06865e6df7ceb3581a15af6e31fb51292db34d68b28d71ef404b9f82a169b1c2de60be9f3e2631563b99316ec369da60c1ffa54e1912ac937f8064489979276a42b233c52235d0fe9b3b11f6bcb171d5118874d19f7728bbf877566d83a65a4112e288fe3a33595546df9fa5c60a049208a0a878ae39a1f1317e438d23b1e81f0e0de25078fcbb63c1ec38f14118091098c910d3f03111e28f108aa3f865141a7f6432dc784c7ec4b316f31ee239d438414ba2e088f1a3ebbef41f2ed84383eb30a083088ae5e93fa69e3fa14b22f9a4748fb74c55713e508593f8ee2d45f83d22166bc2ac16ecdac19cf959885809d65853b946b6d66175add272f9e886d674654eb0a26e628dd3f73712f77a8e456320a8b0e5b3691629e50b5c0fb21c40760c717b4297bb512fe6270a0da9ca0c0000d2191d8373a8fa9cbd7c356fb9aadce25caf47d02d106dbe08663a01431cd92586188f058cccc2f2ae151d2887695030fc576ad9fb0a382102657a9f470a171977c5f0e8565508ce5bbbee76d56303c8d8e02e763593d96ca872566455cad7b07f9d2106e2e498d1d2dfe449de36497c68d9b76a4bf4d167e6594d4f52173e4ff621ce686d12e2aaa51e6329c8b2ab76e066e63a1e51e1152c5d915008f0c6d1c0d10df077b809dc25fc0c13b5de70b15f5e8ac25f24e2c83831c48304414ea11748a817469c5465bbad8fc5b3ebe3f10fdb8124be4db7fa30d63b6efa4636e366fdc3a0e36d7f6c9cf63d115dade23f560d466ac06bc5b13da79c27ca76e61f9931bcc3b10e28b98e4d12cd4c646441bee0ddc54aad6c9f644af9ac4fe22c2c007aadd8b86649bb1c6bc90d0b3738bd8b7a9b4db9522e1669110b7728bd417ab7e689aa1c8b9f370b3738fdb57a95c9745353361ae35fb19b06de128361f81e593afdf0a8ef218ded9af46ef5e78e79e4c76b952a6d6a3b09c56033aa5acefbedf05272260f4ef6b62024d5c6c32a3658f12bb4eede631a1cccf1614c678f36aacfc7f5fdfe70dbe26a73d0cb02c4918aa710e4b650baf9d542f47ca0ef423282d30a29332f367be9454fb2daf88f97d1873f1245064b4878dc2b6c3cf40a98f63eb3c29bad508786137572e004c4e2d899a45a1e6df1e2a9dce031fcab192bbc91ac17a1a303f638a5700ccfe4072bbb2ed452b2eea7e925e0f12092abae8a0a6f082bb964062eb681c107cc0efc46d3b04081e83c97b0d7da16546c231a1f56c7fc1145c4c8a65c8d37f83163054119eae46eae129809a1ee3484ae8718ed684494427c4a272ce95c1b454e2b020a2c311e0df45c4e4d6b14f2271e479aa47e8494573f492ec289b628f57020ca346139a25bf3f80b9081e1d950d010b06e8702a0fd340e4c4f005df03e3a502748f16962ecddf825f0e845fe1e005b70aa2627228461f453afeb32a4473fa13df95ce709d6ea92f6f61f9805d28332c604d8efeb8dc00ce5b6ba2039a104cb76dc5c68ac4b8f34e686b675c668670cb4c0e37682f7799838535857d60e3cadeb445f0e65cf9d7498b6d9f63c6231b5bdf19c016cd162df749dc221f30b614625d855e8bb134469802be69fd055e8b31e291e3e20165abdc971490bf254de3f0e253d6f998d2e93e75262464931ae3f06bd57aa951cf718edddcbb6ee4c0298bd870472bea7c01117faccb6778e04f01c5ecef6b6ce0b83f520143ff95e64ddea55d8db4abd4d00df7b6fa59a0b1cf43ad5b9412da379d1cd7726645737fb076cfe21204f0731b8a19bf10bf9fd7cd90be609c1592cbc40b047bd0e341d6e12e4a6688fd7ee71357dd4746c797c34f2fc11b0286eadfcb7ce0b0a4d8e8b3e8a0b96b1cbb5a024313b498063341366066475a0a5545a1261fb9d766d037e802b0e371415c7e620e056ccd18d64e6842232051a65c4eb3d0b689daae7529a16c127d1608388a6f8d372f876b241389ff0d1adc0e2d779d7e17cda6a26a29429fb7e70c051b15efb14300d0ad1da58cdbd4b117d89848f8fc92d1da3c1cc16ee5bf0d5c12b6e7c1e373c7af4dab740ea259e17e144e4bc0e636e9fa7971e9ef9bd40a67e153c84d04e22a52cd596519fe2efbb8e46bfcc90aa67f66c8283989066b15fc4d494e16d64c525fc2247044c6d5e315e8867ab44388910fd4b7c6c38a4cb20480d80752932a30ba252260918131a352ca15c873a80b887285e95fd0f3ad73c0e35a4b2f8658564cc68366b5e70e744fca5c8eb32b8033737e708538ce8628d459faa307bf09dde924382c5618004dee9f5059d56decec096fed1691f43f19d943a24d052a1b17a7a816b5f403e6a353a71195662baf5bf120ce0bee11708c8e89e54cf86846c26e7a6d8c9489c48602bbb5d1614326a2664bd1eb57710ada4846b6828d7df5ba70259fe014501683da152c0bc6ddbf1854a7d402e81ee33d9ff4aec76c492b5953e7b7926ab2347c7479582095ddd7d4624facb0ec832628a283b42c3fd43c9e157a56b01812c81a1d140f0c5b4be99380e09d25143c768ab8a799fe89a83f0c7a1dcf8c8bf9e3fd4f5abfab5fe391f29d9eab87db767ba081095698bea40862760585da1eef0381c2dd0944fc0a5f6a0304e231aaf40e63f39de096eb56bf4d3a7b4344018d48f652c49c545f7069d7b7a263e6e89a9bcaa65950e78d51437c99431ab88fb7fc2ef501b86cdb575a9a900e868cfe7077404a1bca52a83717db642d64d83e497f57450fa170834429d86f5e39e594535c87270529d892d7ac99eb2e7809f005a2f85553345ca38d48dbf5c0412d844dfd3a922309e563227dcfdc4439177f1df6ceee4d635ab6c51245ee090f72aaca4960c222d409648a1e6c47e93e6d6b723325dd9b9f7e8178bf593f99e3b667ee471776d2555e343677883556a6652b5677e266b04e19912e0db6bebb400a985be8e5ad1fdc7ec7af7775c9370d0fcc8bc87766e1dc16b42e9d65427f32f8c329534e5f81c0d294f9b83fd68b23d7f024e445bdcb28bd676fbc4e77b98e20888fe43f2c4aa8d708fd49307c5df39d716b4c68c062d37232eb73c14743c2cae17062ba2b62c3b264469affba77e434c06b8c8ac11aed0a4f5ae2a1fb49a0ce3230ebcf73c3154e08af67d72caf2a5af1f1df4a0b9a074053d764f6c4f2f218a95711a7bb9776f3a0d516a5eb0f9d5348188d685f6fc790592c1875e20a620d387b898b57c8294a8caeca2eee7b5960c58211465165a80ee919cbc4eae91184e1b09635459a7da751853652de541656b454bc2ccc6f75b73ac954151427894f38aebbe349ae780011e371c5231eef09ff3c18fc21617e861c47acc1eaa6b5a214ed5f0a601b04d4404ac78ed2cfdfd3d16e52c2b79b50df102580b62431855ee48d40f4b5c8dca3b820d30afd2e4aa2c83a2f149cb27ab26742c2be5900a0d8921aad001ab13744c1406f4559cac983393932c1f41667baeb5b4501f81e1b674d942709c41e7b4c267d32ceb966aaa560d6d4a297810304f536f6878e730d7c4938d2c1a9d5d739bbec4e813bc1f9579e19d9e73142186ceec428c817a9c61ea7d3db23c80273ad710199f279895f68aff9852a63d2362bb99a099874d5f960e25f805e832e0c294a94d35ed9a630fb237b9a79dda7dee217555739008e8c95cc57484782ffb4e8d37e5bd3c8b6a94fbd8ab81b457f8fa030aed3ec5cb6ec48cfd5a36b247244a2cb9e01ba603842e7362db85143e12ea8793e6591b9f620f4af2da331c44f09b67c917b84f53161d98f2ded2d545a61af8f0fab063b795b2f69ac4dc410c6ce98d46f68deec78f110549114c3e500beb4d94e82644f3656abf0a2d9ca2b2085c672d88dd2b21f9ec0d13e5fd04f16d661d11d0695f34aee02b8fbea8faa17f1709485daa8aec21c2035dcbd21740c2b02986df9f50d65548e7787e0affc3552e86e58004aee3e6bb56632e95cf632bf43d45c03d17266aff3c2805057a5b56d812aa2d8edacc10c88224a743a662045ff2d22da3ab854b89baa16fb8d7dad5b12fd7e920f93fa5719c64fd526a9f07de22b37da19208499d03f24be0469ca1a604c457f8913fb5ffda6d69a5af63055d2eb1b9b5663c4ea5293e4bb5e5aac891364f2494bbcb92a8e92eebf8a431ec43a708af41170e769e0bedd0aa4fb03b78b36104093c9e181e6c5807ebc4bfca4a82c0e50f5bce503fd0e024bcc31c98c9f761c121f7838a7675116105771f7b0d0d27ec10d935f4cf92b4e5077fb8164bc226f3292328883f16b1e1b3f1ab67458a514403f7cc80e16ca2efa89b7876dc1accdf289c85d2ecd239bad146f51aaf5ebcf743d40c5fa71b689e0d42c6c84e796307003b3c37b514f65d7808b010f760b7344ec85e2042d4d8e3461943fe4ebe17aed76691f454e58cd0f97e29ea39233031f406348a81825d82c5c7dd8b2063bd2a92116c672f965dd5b5ac6e756c8fed44f812ca076c8b6afb1823ef11824261c4c3d2e5cd01a8df9d3fd8d2a6116c1e3eda6fd794dddfceb751171c01d1cb25e8a94f046a3445a56f84c33a997ced7fe775bf529b8a42ae5d28d07be9f8a89799dffef7ea25432bf70560fb424c7104a924824fe30f064a746978d590e1d7ce37eac938e8582920cb390e0629fe83fc6d85d07ffff4993eac04611dd9d3bf9d6fd593e137fb0ed63e08b5bea80d447df9ee37eab1a286a241801790c83a128780e2083cc06133dc89a71c454ab98882e2bdaed295f8c3f276ca778efd1711f6b5ffbd75b2f9e13ed218aedc864b7d997dedfb1e75e677078592b4ff48e9d9cdda7e37ca1dd0dcfea300a48ddcb6dfc2007ec9a5a91bcae495909ff94fa18a08b385853de2d83ecc96c4cca7209ad81f84811160e0021aa61c0794e8b8100196788d85a51e9e4aae680eab54a935ee9e79be027e4a5053df26d897f024b02fc82a2f34e257567c5d4381e9d4766bd381ae903a3f83c4cb29e59ef76bc9e4b3f7df1d2922b45b0c5ba6e7542bdc6cad58be4665f67a41df21bd39999e3af4ee9f4521b95d469d25e28bc8563b25640fffa49088ea5c6477beb34e367ffb6c76bf22f4d996622b8f1b837c49102d31fec4244f6d37a97f4b47ee77c0f5b86c344b31e6d324b0366bcb7f331e1ab9e57d3c04a0016480d40414230dca9285c22fa58152d45194f80e056e5f65e6133ba49fe29ba0ba4058b267b34d837b75d5418b1153956afc6b24bcb4a10b599dade39df2c1804c41cfa2c40038eac9d46fb777acdb44b6229f526bba1ba955027ad989dc76eb9df31bc4419dec7d77bdf3babc0dd12bcff1f98fc4b4ac00241fe62befe75998318488cab44ca2cc11f2518f5c1462002833e16aa0a9e8d3cad92d261bc1930c4101b29dd7bd25124000c73f30eb011fb10aba6b7481cf34390f00aeb8a930c6286d68aff60843f9f0851e0168f0f4f1fe3a7a1bb53bb0a359889a05ce2fcdc2ba651959dbd32c50f5950bb6bf4506f97a5ded5f036698e883e0cb37b81c198bbc46a24a6e195073c3a8d678900f8d36809c0a5d1fd9f531260142f56af29312c1c50841361d168c81e83d86cce47c6d09964016349135247e077041e59a6ecabbd25373de2ca8c8800d4ddd24d1a8b0d2d676a3dc4a8ccffba3048ce45d49832039e0916d87b807b98ad454ff0aa49d203165c59bd9847d10df13d1e8dd207ae3ab9a0800cf90cf8b19f56898df68a88017780ce8e82febf0c5b5a1577388304bc48c58eb0ba2367cbc138b426e385da4fa799321eaad9dee396c28f644ce1206299be8a7a7eb617b37f3f2b7e0a4120e289a66327391c8d5915d7011d080b56b08d0bc888ada5ec39afd3964e2f995bfe9760ae5305cdae50fa5a8d704cbfda8e3433e5d50ecfb8876255ecf0089033508c491cc09e6038111dbdd01e2589253f548c599faac1f51832c7f3b31525fec94b842ea180feca4960d0eac3ddde561e0be1f409139f88a20235810ccac10739c23b5217ba9425e6da6c383fc1e820ef18189c890d92a715a6307c5cdf1d4829d15854194e099bf6ea52ad4158d05341b04ed7040418cb1234d83cc3ceac91cef19af04eece9a79e9b5472633d1e0ff101a09c8dead26588c9c7e31eb8223b8c0a4a04fec1cb1b9dbcc8aaa4cbcd14f9c1cf828270372358fce1b414a4d0dccd6281bdd6e0cf1ea7e50805c087df1d810322de64d09d898ad98764da855c57e67f2f2dbb7862cb2167721a7b2f07870ea3b2f1c7bbce839f02cb419e8b7d23e39a5e753d66608a8537ed79c13bd39465b977a911fd447deb9f44a932a42c5d4c16c941779c980575165400354c457017f6f744d071a08691bdb1b502ea307131da0b4544b800b8e7bc711586443eda568d6b7e7304a1ddb853acfc410cc2237b0beb9540b29b03cdf5751d090ed6494af0724845322ce433301c3340155aa6b271372197b3198a48772f8e3af3463354e5b80c022b707f645c55239bef6fec617bc868b1a1a865a54b09c60fe64a729db49b55722b136fefc99b1f1e7e0a29b958d667a3d6f0b8b62ba890a13cad9c956393948ad255273eb9125784196de2ca742541c3fbd24c7a25024653ac2a788bd388e76b2ef5e7307f47895a5563fa87fb4f4d781ac6a696c1386d941573efea58e3dbfc6885df7261fe7a7c8f29aff918b3b003179ff303cc6d608f0ab8680ae6ef02bf55787f1a20b0420404edee2e593522dbfffb9db07d7fc061d00e1d6111c4b99ef995c0fee4472ba540ea199ee95f5b1be98e018357d0fd29130182ac206b6f4f1da02fdabe35c25c66237a606ca1db5744d42152c4a4ebacce115179c613efe8bcdc8471458747b4823943f8ca42dae1373718ea28c72e85411336b002f736446f31469b46151901d7dfb42736e0dff95cda8df40f3e653483651e3843030c645f25cd176f43af1c02161549e001b2f69ff39fa19e131b98ff7c710213aa663a14b9cd67e0636d63865466cbeb2f95adbaad84d5f2f83767e3e82213a60a521b46ad8165b785d924f79fd3999a2e4db3c5df6eec801832da539c8a22b0637a7edc5934b383a2e5a261c3f94be75214a5d4bdad5029d7bdd456f433cdae642516a99dcb82057685adc9c1f88080b37181b0d40b7cd80c452b5d1e9f93aef36c7eac5006cbccd7945667b103d2f087c0a051c0784a7324988c870444ddef5d3342eb195048d15c232a0d0a9e6f2379168755384ecffee75da45b11b30c3630a766a20c415b188c196ac8594cd75e5fb99f1e4e11a480398691cae19dcbc604d1254c0d0baea3c8c7bef3b81006560be3724729ca176cb551b0d31a7f692b3fc9306741d93d92b31fe1861f08cdd0e99ff75f26db5d4d6c86bba0f235089229e82c4c456421be6d3b2684037f6aa7cb8e625810a4e9de10aeb1a6868915316d1d599bd41aeda49dbedb1683a758cfb170ea3f86b9ef3abcd270c0611431d5af1be70fc77047e9668412b00cb0bb6a963920867cfffb2776d09585dcc0a61084dd20e101573eb3fd239646a93a75f4527f8ec2e8a4834624f82e56322f097c28c66e8ef801abaee254f3759f53a042cd4a9e9a9a4d4c4cde0fc47b3f505b4074b5ac7858b668d8d2f6e6de6a3a7de9e89d6dd30231fb5e5eba9d1c2e161d607f79f3e9942f22e9a9efa3db0b0a3cbe3f4f1943eea06f54ee246b84fd1b2487805ca4831e6e1182588769e6621fb4ecddd0a1e02284c1fe7c87318834f0f0be4f758680d085e44dc9235368b78633975a37e6b0c0584e4a7964880adc8bbe246b7d40fe903367c1f498a805ec3e4758d24759e0788533da737ffe8363299febb8da822029db96dddb16015e53a35bd3fcdf4c4307df01b14734906a5e1a9c825eba54f05cf1905c159010b9bf2d8c1096bf955912177f8e09d5c0be66415b952528c0831ad49c3d37f4eef215932b6b613211effd16b85b02890a1c3c551f884e457dbf0a85263b7a57da28aea883d9fdb675e1e3db97637cdeab319fe7791ca0db461af4602e190cf9add78b09a26ed9319866f60ce4a857f29478dbf7b6d88f0809f38441a85cdc7eda2c338b9b1d7c77a957677aa8ad54bdb48ddb83a245af3372fb48a05060c92a97c96a7ba3164963a06b9141314621c9c384323b6fe7321a53556373bd26d49469926d0508c6004b5d636c689514bd6a3096d354f3be22201ec0c2e0834e684bebc9624333fc81d61e1eaf3bf48958e264d085d4cf334b0f94723123f230ab62ddefeb44fb668ab10c0ad3b2ae4ddae71449d3ecc8f279569280f7f0466fac6c5751375bc17c45bbba2fccec161d8b98416547c366f4fda8173bc80ddc5ccc397572d25bd3652db00a21a069b3ef8ece5eea65c19ff64dcc061fdeb11708bfae981ef6befe08f206d114aca1eddff8d173ab7d999bd6e021f15d3daaed0a1633cfc0f9249350f8b13b0e2f18efe298bf32465d11b0c3a1c735896a45a384f7247e696d058cb35b5109559edf02c430ef03352564b38a57cb692a87a79517bc1bfb2779557360daa882026576d47f10cd382d5742133ae6b430f23a234a6eb1715b8cf1da9c142194af78ed8f8c67f8c2288c08dbce4d4968595fe8d6ae930d0dbe1a0fe6afd7df96b288e7ba30a5af0cf41bd7182a6ffd7de5db78567bb22131ff7972771e5ee099372403be81488534f4446859abc9bbb1439eda10f8b7a203f2b7e4e8e395884e2546165844075d72e7c5a7a5688b5a2331ec5fdd77d944eae5fb8931e6215337d13cd31e43500c72695be8b4f3e5b851051865630a6694648ec43be9338e926ead9f7077d53b793c2a93300a58aac1ae05daf8e1ef83f0babec99bfad0887e6368cc34d53b3da9020ed8c69d1cfc757704a44091c55d7863be472ee3e4d9c9d513444201d1a47fbd56d5d6d1a2def9569ac5a99c6bf34aa280ac4883a10112e61c70263339020ac548093c6324de4888bce150117d1a64aa79999b704be2c14c37eefd8a0e870f4f29f6930179047b0abe9b1d1024a21c4e5339176b45ceeede4a02043cc62595cc2100be091129c0b40239c7d72c2aceda711ff9c9e170bf8e5e7418080aba229cc1acc591b3b60e04c31023022eaf9a1f2bfcad52aa1603e3ac5a2c98bd16758d423c44180aa1fe1dbaa008776744696db375ed15bb9a9e148098f907a80aba0d003ae277ff8369c44ccc2886461d639b1f07550e54c1885e38a008d5c1cf9e69ee050cc2e477406468ed5bd57d4f1db3b7388f798eed388156e4454d1404a1cb29e3aac69c8b553fa4bd79e9e92ae95e4011b0a7280ba6bb1fa96f559700fe9bfe82282a8385d5438f4e138c0801a22c08f990f66925e17c1209dc1800369b82b68d18e75cc990c494cc5ede2ef6ba0af2b0aa5c76bd7ad5c117f60bbe452ec32e7a0bf200b47000021019442ab2f0133411b30f45ec1cf8930158f6d753d0b76f87ed16d4ecbaf625d503fcd545d07fd6bd0c36a52164ac08b223ab31c2fd38121625ff329f42f47dfacd1b1bff1c9322a7dd88b69044dfa98c4dd931d841294cc016f5f086913e34260ca5a00e3a9408d0b7708cf1cf44edcfea3b498143465c9cea1e61dd37f656a058ab9808773aa5e1395f486d589d50218f7f97ddd4383cd491b7a6983d2f222ac4d41b0bfbca41a89728813ddd4772d34835b5b0331f72a07834ba0c2c53e60f9ec88e6faf2e072bb3517d3b8e727ba592260a9341705ae37d98d986387e4465b3541d0875b5f69ff2045f15db99fc0ab6a0c0a67fa118717a2f99100310939d9fba7d2a8edf19802148f1d0ebf501c4b1dbe640b8984876d0a606c0aa9d29ba0711900a4e3cb8dfa784abf8aa97b53b9980180357768b853c55409f7c28af1f0780db26aaa2093acbe4f9b2a0fdbdc47e278e79129dc0553dc70bcb514288b6a08967bcac9886cff12daa51ab53b4ccec7665651dddd6447d76ce392e7ec9b3fa85726b47ccacb84527d05235df228932c4ae9bf97fe6ee90156f2bfa475e395242e012a44994354800be47ff97131566703b30d205a5b9385970256e918395c052c0a61ff5d01ca6892ab4aaf9d823e5aaa9ae0835678aaa649fcbf21d7caeac9a4aac1df25d7eb25cc4c5521cf08b8fe0260e500a3b1cf477aaab761bf3e405c32266bf279aef078faa9a790edfed4748840014be21e3380a1bcc3ad007538744d902b5c2883f85015e9d1999c1f99b12744b9abde3a3cb7dc951bc438d37a34b23e3e007f3ba49c30c9c700ff8f1e38ec22480d857a96ae3b0b8844f27a59fa7f717f6f42f881945e2ebdeb1659e5c1a720ed25cfc87ca382fd788b19bf1f2e6203156fbc853ec4b590b29ae7783ec383ee5d3b07e7d5a070575edccf99c29b68abe5ba600d5018fb44877a4a3a6c96baf6a159c22f19bab3c9cc4619eed8da910cd959d3191c38859bb49f69040efef7565e46859a32f9f38507824ada94bdb9ef459643fda3e751fe39e64986df349a628e1947e445c32eb1705edccf5f522a1857cbb2e01ba873843039281b232f068b3cb54cb3d6514217a3b014ff69bc1cbb8dcb62021292ad083a1ef8dd2f3cf293d9362be966ad4308bd37f744e2804e9b7e8678b72bd8456c6ec8116c5380ad85acd137cdca2cc966829b97570dd8b0b5d8eed8cfa386a5be9123dd5ab2784983466cf40ca436bbef7c7e0df455238665016485435cf825718e6056d95e6a5b2710b7cb681f96b11065c503a914fd79fa6e05881ac8ff1c2e34745894552d8a286e370b03179da8bb13f967020af68324927f86875241e73d8113c23f7038681e938affd38b33823cfd5d4af2d303e06e6c9a521ea9df864f2cb80a8513374d9d1afaa808adcbd13b9c876fa08def914d91bf184575de47375c0a0043ac5960e4063c7b11f34cbeea30653ad8ba0af319be03da2da2f17d19fa29ab9b1b08c9e1c16cc32aef63606d97f6d77b2243814e8136a7a2aadd64c4b100c30c30a0991a0e26f9b66ce21ad2f1edb7a05914b45d17d5212381d717237648ba8dd7b235a9a200596615fb6c2b2f042aa770ad8b89eaee52671665458fd9c481f51eb921329a4637a035a282ac442e919ccf430f32c4b0aed6f57bfde5b0805f1d5e0f19cf0469d5f2b61653bec2606db97d563d94ff4bd668f62e79c5b40f68bfe46618fd631fbbbb9aef5a9f90d455240b1acd050cdbb18d9d956f72beb7561f34a0ec8f140ec4675597e386d2f8835365e172673c2ef83a3c1a300eff723c99ea953cad894d53aed2e60b5d683b68c20d48c85c93d6b9bcd56c9aca0e51332b6a0eb7f4770da91e0d489e10ea7ba210628b2d9577cdf1a6dd3e3dc1c23a0164ad8df09a4511e59a3463a6f52486ec29322f11fbaa7a48ff5db43429f92c2bdee70d5eb69a80c4c2be8a17d49f16680f73f6574bfc5f78f6f88064d5053a6788bd3c3eddc274baf326649fd0dac4374f1002e6d392394c75bdfce05f9fa98aa086bf51d68950edd3a76b600108df570af5ddd9324227041dc6ff4202ab40c6004ee2e377c2b205f08a4bab576216fe87ed91ac7a78b775fea208bf0fed5948bc6ea14788e623bdf9700677914c9c2c4cff407d8787a636e2aedae9b3e032ad550d0ae05b7f38023ec54f45053e0d8fd7aeef7bb6b4fd497d86412a28825700fc2013d4b3b2d2fff581012c00050ae5e7bd55205c554973d998c4190d6c011796d3c089988d8141e0caf217f409ce3d1c8d61a49115c31aa8805cd1311200012a0500a8a068daf261e90b3ae01b6a7284dd2d6d848234618d6b5d2d7f6d9bb5dea41b351121213bc40bdc0b8c0ba87acda3ac896199dd1ec624be36d40d76ebd825c2dca0e5786af5b06f02ab81c7b6bc83b1393b7bc3bbac089e9aaa063768f3d86166833dbb7907aed7e2589fcf84e5f481aa18e1eb4ec0849589965bae69b06ea145830790efd3be7cef1076925aabdd4ef0059a800953544a015763af08ea5d0d4d57f9d430bb9e5adb1ddff12fbbf1038e563dc0090e00dead41abef1b5b0f1d12022e23c205923318e109246730c213d9101896f7e61d38da58b7bc035e17a5f45950c7bc75ad55d9cd35b26a20455396d96869d01c76354de975d149e7ece7f82c3b4a3aaf79796d43f52ba487f49dddf801d3cb4b2d1c31f458144b48f1766aad425db7ee708c8fa686fd5b7d60f82198f47af87ef889116c5f5a12041c831d923238c1b201f270663731dbd1704ab7cfa537bc7da552e9345dba3d4de76078de6a3887a09f375ba7370a93c351fc788de93681d54831ad9b77e4a1097cefe0cb5ae701cd21791204c3e3b0eca3994dbc385786e37ad90df89addd4935eb31b787bdd60178e1562c709315b38ac4b4dbb795ec2d2cd70dc72a903182783c093008510b850062648a1a786663714cf5f1b0e69f47ad997dd201d1ecedc2761f1389610f1f030cbf1f6e6f84a03eb230e7cbdf9c21247fe0338de5ccf5e4b5bf481afa374c45f8f37932e7f91a1091e5d0b82479faf6e029a4392c5107c7d6636cf361c9479e760b019b321aefdca6ec4dbdb0da583f478d23bb3b294c76d741cd2b35797dd700ee61a7d5e54ca5137a5935e3ae9a467a347f1c33920ea353d65bbb183690aa56374d24727cd64435c1767745f3060c7094d306067271362c709190e89ba893db008b0cb6eb45513d85d3b185eef0cd39949f05000b6d7999887859d83215911f068c1d75d6d0253ec5e97de2c3fb31c34d83919593ee760f2a887766187c489110c2ffdd18454576f680e89908f31d000d7ee20e03e8b9379356fec90085501cbcc04d681f4076d6653bc0212a120fd1c2c59d7766a5e0b3b244247b0bca6d7108ee275e93bc0e8fa269334bd79ca64c68b32759f4e9d328141bb89ae0db5ed7b33421805154170702eb5c618314a29a594bea226d1ce182311ce160e9e935661ede2d98dc17501431c4ec686e9f035ae06cae117e054d6152083e10c0c03d082618b93e564da86f61e0e0f9d4a1e5efae7e489469f5f13fc9a3c27bd82322d04572e6e3e692b2b7aba996a2d6ed64ea7a7dcee59adba67d543adb5566ef63d6cf7dab6bd85a00cfc812b28037f7e28d5b4d56ab58256d28889b95b8b6fdbe91242a12121a1088566667c78a6d9a986b313ce00702311e8c31d5d075f52e290cae1a554fbc92466674e36987436f0d886c361222222a22bec7041f0f9582959b5101e1e18042244a8f0b199b55b64d229b8bd269dba8930b6872710283383f2e96e97dfaa1c34182d4f27415a952713dc3e5a95ad2098a755d00ab86ffde8e9a46fad5ac5e4a9a21a5eaadf8f69706b7030fd6f91c94bf567d0e8a7a02079e39083e9c741b322e6c45ad1e7e904f7b1133947e48888ae7059dc2213249dea3fa0a782335b8453427145c931624889132a3922265c1194910023e8b221321c1147105e76a3abc88290254c705561c18f1ff00e38c6cbe33da9d8ca5be86d66b392e17060681594312c9c198e766db9585fd962cbb633331b2c46166fcd43ab526c0c0204bbc15ea3c9d4294ab7a7021e0faf1c07563c682c37b56ae5c8cfcf8c1187788b898592dd906428b53052a488194c7230c121e564e3904ef55f4f128d455ec678bc09ae6437ac8bd2615dc6b062dcdc2ad910f296d5c262190e78f9d9f34d38a5f5eaa825ad673dcb7acf072bde5e53a74659bcb50aadfe4497e1884c3a1571248a43f42ccf7188be9284c801d4251b930405619844b131089a21cb64591c8631443cc4a4b4365bb9c4ac2d4a20202989e0d30963f4c93438557c64b2c934b8a156a1bc271357c33a41c984c8c1b415447816b99c451e6791c35b240ec141cb336806b58abe3f939062c9daad6641a327a29886851225dd12b3362587b81a8ec9d01b82300ed964e08a622dcbf3e31007e3c26097742a4587a4c54223a51708928e0222fd05e92e809e1ade0c260e860d2ed58f446abdca2562ba299148b55b0d8a69884371280e495189429120e06ce1c0cea8d9a9d5a11736c6218b72383a4c8a4317ce71c805ce71a8c9731287aa7d9e76d6381487e68c4356cf6d1b1a402ae7e5869a115a4aa53c8cf313ce29257defe60fd45a6f92812bb4915aef58e31e61a43262d68b94d26a82109a5e7d9713529de9548d113e296384efc9f7e468a653cf1a76f6ae87144464b7d9a5346b8d747b2246cf46f6f690629e7453f0d98f6e8f93a59f37efb0d9632c2a6acd3b0fd67766b321a053562c8126658c52c2cb8ad91de9c3a8b26ee3fc2ecd45401a348723267ee659efc51a6396179d326258c5b0d13b128380d18720ac4741d57a9ab5c29905378459948f9bd6a99f4ed8b2e0e549dbc9c406ad61b0d0964934ce2cf85508591e76d1196d8c27ebe46a5810b2bc27a564e9da970ceafb19b42e02c2ce0a1ab000f765b0bb820e40b0cb6c2a905962da6187dd71cfa089761a42458102fe65f0ba4ef5a975266a63b4ac2725c52e3a2d4bbed8aa1881e098dd7081adbfcc653a5cc82849f034fada96768cef0ca65caeebbaacebba9ab29c4e56502124a355ada256c6f4d2a1698b81281bdddccd3931325266d0eab38bcb5d3785104288d9c057d236fa0e2843a9f6e4add2f67e349e13518c423b4d6bf7f9c09726c3142fd57f3cd90967d9e9e3811706b9a70407d3cfc78916c4d5782757031e291ac2f98d01f71fa552522967c5a494544a4a29a531d26ad2b4ebba324ae3ad59b1686516c39e8f35aa14675b7e4dc0fd28c33d1f4a63a47656cc8a36466a5d8ed2f72a26a394d467d4a72631da8ed6e4d050873434680ebf67ad8a2c500183e72ded59efa2d2b2e6b4e69c5aab64b4e6dfe0ea19b4db566d285068cedd3977238ce67a73384975b3643b15ef4c35c68777e8eb1fb59d3b7c84dd129ec203c4c38dc201b8f7783b0f3e2de4e81728046c1140114820a662a29315b0af76661070351a7c819f2fd6377d76e3614adfe5e8d6438af726b09afaeaaab52eb3512202f6f5f6a8b78f80aba9578ab7836d06011428a0c6de137c81b779070a1450535f8fc17aa3617a9aae994dad36081a2861c35196c028b3a18f593f6e42ece854bc56055a7640cf9901277104cc4408db5ddfd12a382fc4dc5e1a70e4e814fcbc178e1fa280e7ddbcef45fae2a4d3a2b604da9c77084b071d025f318965bd675d4f5ef1bdf9eab358a6c3fac4550911adca301cc2c21183afdb1268d785b7e68e563d1c9f43881d241fd5391a739756c12b304482071f1c85c0da1246291b75516bbe6ed83a60efd0d730a8ee07936b244e8070c32763d3aad09e8d798725d0a47cb1077c0f65bd1861940f46e89ceb547f61ce39a7a4d69c11c668fbbd47239ea639219451526bce394d6198a639e9a7a4d69c73f6a443a8fd3e6168b543f153050c9d0bfca142ad19e17561d7b582dfeb8b17b5668c11c608e194adc1e799863d900a385b18638c3e708cb17fde7b60a8011226046113a3365848c137316cce3963b43293a777f50ad87559d2706b8cc24eb16004c35337c2ae0a2cec00d3c36d84217c74b69d98f56aeb65d58935be367735a6d8c468137ae6352ff95aac9a50863254818625381eba2ad0d0050c1f71541c235da1208b2c22764fb0c118a04007222cb31b1187058519a8b006ec5c2a36c1049562f3b228cd4c572901299a4906a536b4c1426973350f67c73621b6da8d2bcc11a349d35c7e39e79d965a4138187a9653b638e680148b568c378ad25d3681ae29dd1d1b11fdd24f31e1ecc8a06d42ec6803f4ebcb82b8d80004d7c0f92cab5a5686cdcbb26a8e186766135d7d167da49466d8bc78f4c0d4a292526a552b6810bb2830f98957d82b7268879bfd8357b82c8a127699d9e410022b6daf46dba2283de5fe78cd25945db756a191b61c428c81e4b21b35eb0cc7c3d92b96d592104ab86af6daea4f2cbd66591cf56834aa23fb7280afc32dc332b389029320f87a25451289e4e4282b8161fc8e4edd1c42d01c96655d97854d7a5da4cb932e2f8d74e588f1ea548e6849694d3b2a597a5da5cb01e5a099b50940707640a61ca4fe196440724ae7542fca485531dec167a3e3fb5297c4c32e7ede48297c6f273e5845855bff8010c60837fae406e98ba675eab91c3999aca6f08a98ac99cdc83e2db3816d03ef8c66a38e7cefc5930b86105a27e541cb3138de8b8407cdb2b65f2084f03d61e78c3831ebcc3b5f113caf655d4aec0da453b2093c65036927de8c66c19b01fb473b313787a53c84706b2072523a1f1157072101ca6e6f3eb626fb8addec82b1cba294ce39e79c319ab0770ad3c1524a29a58c903ec3cc666a2c4eb4ec823ba55ddb122d58891d0c2f4a07bc3a0fcf63d98d3c9cd7e5c6104e49218410dac88610ea744755848d755a07840d2184536271ce39e7c4b09ce382e1b13eb659fb8e9c25e63d4103fb75c53b61431c5511367cf2a46dd077120fbb274f3094f29aac4e630863ec4b080773bdc2cd7441795daf177417941042784179bdaf9c73992eed65296d8c86e11374c64e659d88e5e183f219420853f3e6eb079be4bd03b4f55993ec14b476802fac67938d125e1a3873dc110c49751875066dac129b97654dad6a4d6e2668b2d95e9366b21147dccea92e6035537e38eb407c499c5dd48dd489d83ec78f3eba39e29ce382f0e8f095544937bbdd46f51a8d7e8dee96ddcf4db51eab17ed203a4529a431e2d8704a79032f939087ee089e91d2471ae3928818bea6c371cba79c9986514ecbba516602a372a000c393708e9180931fdc4f6659a49dcab2d1352745f8c1c106126e8665c12ed8d91e687d4a35ed8467cccd0c36992236f56824b9d91e2de5d921b1b44536bf32af326d5a6eda4e6fb1ad6c3985b3ab6c3906673789fc9c19fcb7cc53cb35177474f3c3a325339ad3b1993158deec342db35b1d6877f4785f2f9cf89b72f3ce0f9cf2b945d336832702f07cf1377472c1f391b6b8d974d451b627e460ba7ff44bbf22f8e20eb978f834e35e911c68f63faebf1f3cb6479b772172d990802ffd568eb435915764f52d0eb420411a7b543c9f2473be873b0d746a3e6e3ddcfcb020446266837247308cc34c47132e40c1138af0a8b4398cc211738e2bc230ce72215ae611d117681957734c133373c40cde6ece0c3ec9703562bcdff788198cd372edf92ef8fa0cd6aeb5e4cce0f996d782057ef761bb007c7944ae533136e7605c36075f606c47b8223cba38f132b361b94e8348b822962d5a21da3c0d346d4b5838efac30cee8adf07c7d2b3cbaf52c936fd5aa1757b938b91aa5f79fcfa3e2fd2001655e5cde7f3fa04cea00b8eea04c008866f00db49c3383536ebae9a6ab6c42546b032d53d43b099eb758607bf7b2bd48cdaf6cf32aa66d1ec5099e01d81c7c01c0e6c3bccb36af11e179f3e8d9e3883a24d92db9a885e72311dee26582dfe1a663e137d4a9d773e7768b202bb4e0439a772e6d80bead8186840e13efbd4b9f982bc00215d880fb9647cb8ec8c281961d5113d9a03ee7a69bd339e7a69b6d44a756fdfc922c49f294086da149abf27bf29ae0225312dc3ff50abbf7de732c9d6a6c09da0b1fcec70cacb6823faa7301aa10fe6817703522b5eeecdd1f107c41f029818fe8357972784250a67485e6f06468bc973e7d79a0710287c4892433c0ce75e1998087070965783c1870369e11948e8bd34f49120ffb143d25b89f9167e3257933fa3eb97d92d4c35ba110dc2fc9cbe8bbf17551177e78547f8d4a9b96d59e42bbb0edba1540b9769b404de0d5687f35dafd616b50fe23d6f8d07e025a533a697b352f2322d6a0dc13948054a3bd6b5c6d0263cf0151ff321b9256abc0d79fd0841bf784d73e706626262695faaff6b9dae7baab02d7c3bb1d2760ec10b3bf6c853dd606874021b304da03dabae66542f0704f30bd15371936f027ebac8aea5cf20bfa69a848a808c8fdb8196a62d9e1649888713310657b3d0d638cefbd0cc7133284661a6954b3cb3f57a3d4f384f8d4cdb5cbdf0d594ea7ede14724081d4d1af692461a6d37f21139e260fad9b3220a478ed01f68ae536d4fd3393a0723afdb227e990dbd4e9f106b88a45694718489094a8b6811bdfba1c1f2d78d1816a12406fe74ea18344243752e48e8b44c8552a85fe0e7dfb3a665cd5967ccc914cbf75e86e361b1e4aabf6ece699eb7a4534298116d3e3f2cf21b7ab04890209cdfd07b58b46ad2bb0b26712288da239a872ec14431189a40261ceaab712e5368efc78bf681fb56b3220b425e103968f0e688f3fb912dee1f16065a6e1fede347cbbc81f8c0c210ec47bc815a853c140980f67025f9d0dc314d6f374d84f500eb1407ce2791f6a4123bd85d01b87f8805dc5660c107eece3399cd7b56c999c133e5f27c3668f9772fefa2de1f0f26f0fb8943d4828270dfc422851593b80096a77ed635699deaa8234d9dead47b226af1f35d94c574a0652da59dd62000cd597105216cadb88212dcefef8500859d1559188924cb9252c648d3ddf2bdf8704768450c1f5bbaeef85aba27e5bc2d812663bca5e35d6b3275ea6df4c1e0d806804d31be68d9694ba0bdcb1be13c5294c4845d148a80851fb477876d09b45a1da6adca7df8badfb3a9ce999e2dee1fdec14bb7c636a369d0e01d8cd8662488b3d15badf07b6f25350a459eb0820a1284514a88825142e8a8355d6fb1a13c0dec6c88f83ecc74c4ec2f6bc0756da75ce376cf5d188698e384e2bb281df03a2d54cbca4c76a5397993bcdd87b971ecc6f103eebbee0b4d0e765f545ace4d2bbaa7e31a02be3bfe650d80d98d950d011ffb7ec2965730010ba29473ca39a373d3c9e85c7f4e17bbe5f62c7e94c637e3b9eef75ed3760f2563c78e31c66e391bc656cd487b4e89926e4a79c137b56074cecdd66edc1b7d6f3fc21bdfe5a4746aec9ee1cbe4e74b05117324478a860deb7d083c1bf412bba04c2a95aaf2653704802b1d344a04847f5b0ae6197833bcbcac4bebaf88eb5ac0ba49dca217bd2eb42895ef0a91a3534174aa8928c202312919294a29a59452d2503d525444b143128628c0c3274fde8c57802341d83dc1063ece95b0b3c2481016f5063ec9c34e1454602705a2038c01f76f3c350481431a709f810adc1f030ec47087332cc16111042f8801b71594e0aeb802922b382bf888c10e363c1cd06a045807fee19777a61003ee03a8404a6b946f728063861560b6805370501d400c0e89156e162f4c50b2020f488f48c315ae8ad508b04e9b70dfdc8124a5195426316694917002ee888db207823ce004f7e3124b60405d830684d41b7073015b65c07d59836c944140072b0be8036384304218238430c60861ec338c32964fe0fe7504b70ddcd7edc04759f0a30926d9aceee4071bbf2630253d23bdc78fae5b273ddb9c8321dd4c294ebc4b3c0c9fe11bc36390e2d1e7064f8f7586e3dd399879baa1746087237a923b82fda4c007c60e4ffabb39e2077b098aaf5f97de4c9f53035bd65d765d1e1043d296e12dec4a77644502ec320738fcae7332b2d13c5c3918f99aafbf1868d7cd3b0fc7174f9dd546cf4202840d6d6cf860a71e0cea7bced9c0060f3b2b6cd082878721f10a2748362b6cb0daaa700739cc392724c2ce0a215cc0a63b778515428e6053a79e7b33dc9f8dbeb36208931a9f8dc602c033c3c0796564c9e7d8950eda74710e06f6595a5460df6c3dba19f4cecdc8fd48fb26716cfd8079b82779c0f38d235f6c5dbec22478bc2738892526a6d7693caf43310f05607aadde227ef3c2eca631842e9d829f83e6f2ae78c10f2c8d509dcbc9450a4b0a5f6ca4de8c7e6edc2b495d923e134146b42abba21e17d040abde8ea7fac1bd1495917a3660dc8c46f264e0a659c60c1946c8c0dd1a80cf4e480684524a2865c89011e9b30c4a21a494c227c30a69ab86b3610f1ceb5115bb68ecf9624738449c114aa8845ad5f0e8b356d60150fd1a64cfee68abba1f51743e4abb2b76c539e97c718e32b043f4447675d0b65349b46c4738db76307a0607901d92254ab00ec453471b31b2831d3220898309d600d413448601e782c88e80e7c59957625e0fb4e0f83805bc73913d7a87761482c40bdd5ab712dcdd5d4516a8c041ad697003bd3791aa1ab468861f6eb079d9807977e47b5360d7e91bb4f91d6ed0ac1c595a16462df66959b5d65b9685d9f7ea76bd1edb5033d2cbaab45a35d3719d3ea294c8116f9d010ed75bd6c5a9d33e07c3f5d5ca7458ee0c4678028910ee0c4678a20ab7d73a0dc486c070bd1646afd3b76b3b87b84cf8391769b5a066139640c36e8f7a139bf376cb6ddd1edb503d1f98ecc14e84abb55a1134ab75aa2f1bf3a67d37cf9c7e9e1d507641d8cd4e8913b2cffed55fd77545967af3cbea6d8643fb8bb3b4cab970d80551ab5cbcbe6636356563f9dc68294565e50ecab478537bb386dd7c7abd393561f7b83027184a647269e0853a867271acdb19dbf06ca01c335dd675b23fdd4894c262e55e272429f7ba3dd775dd7c94f97c3de7d088c1d82f8ed5008bbd66d4d5696c1dbba86bf10e92ee602647cf5a95535b1f8c9b53a87bba2deecaada72b2af7ba58b00c07765dd747d765769d74ad44154a658f655916ec1e2e32894e70a6f691496c42517e45a2d8061a8964b8b09862cbbc3beb3198c6abd328c79edfd569202c7e92f820c1b0873d0663f514e515655e9dc6955a1385462629316edade3524e04b3fe7946309ba52a89b531fdda02bbb320cbb2e0af5f7f9d349a3d7270d8c3de7d0c0d961e8748e2c9bcc7060c7c96e7e5abd8c19979caacfc75d6f8671730c9e2c4f4e8c0201b66d7836a6e302ae775b88a934ea6fcea181ed67b5cf5eafd2619f7d3359fb6b8b1895bd9e5a55cf4203d78a005cadaad5ea6ac8fa18d3aad1eb25e06a9c5eef621b26f06c8cde8c7e7d47a2393b5e940e78ec38e0b1efbc1eb85ed95d564fd3a6bb83eba6d338bbb10d6fc674f1b7bdd02eb0998e5dcd737d88646bad774fd96c8f66e117d4415a507e41da0bfa99250783abc93e6d66cfbe5edb85619b367f6df42db6fcf01210a7dca67c3e25b3a18d535a983a356d8fe652b69922d4024ff0a55b6437b25b8bd95aab0c3c31ccfead6437deafb7a0afcfb6235c30cefb75738bd3d7b75517561ee182b15797e16831b3bb96d92e473d15e5baeca56dd97d9bc5957ea37f1bd5b4235c708e0b36754a3e223dda115e0f56d55715f6ea4cad6959ad371fe3eb5d164fdba3b504d5f75bb65a6bf66b239d6e594766f5a2d87889e8542bc9e15c49bba42de25a35231b7cad19f62cbfa191b517bbf95a3644c51729c3a15d5eab43ad8aaf1f6536b5d69b2366adbd48d7e7bc0e4bb1a44b5f16cf066629f686f0757ddadbebe2908eddde62d7eb7551f4f6d66bad37df5cafbf6eebb13b8f028566ba6549190eec758459d34db198b52919666bf39028a9d6faeaaa8cb07b308161b709ced663768355ebf64fe8d9b86e1f93cb035e96fee63784ad938e51d2c59ee3c5eae7b167233d1cc36cc4a4add6d3792fa137c33aca96bdb48deeb26def61bba7819a765f914e5957bd2e6a7fcd9bb37836ac67a4be40b18196edc5b97460b7f557bda879d2ad7a8b922e0a14d9efe620e9669d38b26e331cd771eca5afd910165fd7cd4aece0faec2f3b96d96472621058fa8addc2b079535b5e6f9f9156bd2c9e8d876bbd4e7b43b86566c3e3d98b423da0e5f713f8b7df6b827ffb0eae5bd670b5dbb639f852e937ebd8b683af4d27627a5f166f863537b9b5ac60741053785052ec878a67e4d93019e51d1e8c33b21fdd4ce539a6a094482f9e59121003159369bc9bebb1571728d45b7c4096c36bf0a48d6543bdb4c4bc88f113bc06c6e14f315c905c1bc0c5b6b5000a4aa2a45f8e1ba236d87bf42fe28b5edaa998173d9d54172f21841042d847cc601c991f35ef73a66bb6ee1c5dd8f349559f535986dd489b832fa3ed5178b375eb46bf6f1370a736144275396e084bebf4aefbefbd07f48e704318e71dde0c373784c3f5cd366d5dd7d66b9feadc3510638c313ee8fa29498224dac4089524c1ae8bbc927c48f10ec49d8b26814ef01a29b23bfc8bf91c24dc903b0ebc4818e186dc95483ad548bc2dc7082036cd881cf72cb10cb24f68b9993413a056f5fb0b249b042232572c3dbc3f854c16b44ac65dbcf8b4c313dc45120fb8a70f98e7f903779e41704f9e3904779658e07e009e2593d4b3247a79964d04f02c8b708b67e904f76d0fe4906e39a4e5909643e4901f5c9d730e4227dcc5da9677b0d3342ddbf253b9cb1c49a6002887f019c12baf085e89ed4485dbad1fd269ba7fb4ca09a8f5db54543e7ab3c08906d2aad155defd33d2b6f7c39da6f3ce9343620f14d23c0fc320d8b1c0659d86b0b31b8f24e1cd2a77a6a3dc7549023948ba3a10939ef2fa0a6ff5d44abaf51514283495ab13b1d35036142834d3cd2917653e62e7e24379d681af88c4cfdd3acebcc4ce2acd971b0886edc49b010fb7d12b85f0f46e6c479c308e7b0a4a7c1440bcf4ce70c4bb9b08b069fde2ee522e53ee4ed3a52d0a201e8198b75036dba9f9026c5abf9c523e37021c6533dddae4dd264797db667fe59c53ff6895c3a3b713cf86c3a337104cd396075a763794ad2b640924911891d384c8904482fb6a69b9ac772ba58fae72138efbbcdbb23b77150994a4074012496ff25917c5801deca6123b385e0fb46077512477d235e2f396750c92fe9668c1f2efeee61c888a28799c78eb325a276dd9ba2d3d96ee2efce580e71cf07009050a6dde5feee2941e2f8ecaddb79c135e396195dbc34c4776a37263caddcd23932905e51aca35144d739b360f2ded0ea2684fd1ee1af03e6f4eb90ebc913d4757b55b9f52ef3657533608dd530e1d74cef2e0dd95bf8bbac9fe9efddd8c618923df32b3b7646f794bcb96e546caded27219b77c32025b9a09febdbb2edd4c6f5d3b109beb17ed6695476bc35eb79c7322656f69b9599ec4801d477adcb43f683dbe5b7fb7aebb761bc32dabfc74d2276a1ee7a2f468efae3cae90eeca96556ece09cbdb72db826dd9086c8f693927bcc4b3b21b159cbd566b5f96dd6e138ba9a4536e9b4239f821819f0e133df02bbd96b689c510ed274f25b89574aa3f148f740a3a2863fd45eb3eab47069e5b964b70117ce9533a8b7a66519192563d2c844a25205e2a412036b9a45ffa755db1efe69cf0fb4aa643005bf8c116de77f0e3e954aaa5908b8b123ca30e742e2705d4a9bedd8126a455590e71ed438ccb09f7107f6036cc071f0e7397ddf0e130a76998fb706cf321e618869db62ae5d8b556cdf80fc78e9da555f4d8695ad3344dd36c0fefe1a6bfcdf4942d3f9c62b79c03dbd248a5fe9d5a1505106ff9fbaf77738e0b4e398caf58968dd6108872b78d64e928b7329b518ec5a5d116b135d4aa9556a1c826594328816894b694cbca761979e6f494cd61ab9dde83cb4f97990d0c1517ec72954c078bcf1bca805d5e9f85b1459ce27269cc663b857dc6a6750afb0f9ba953d8517463e914f6d3f361cbc731b2d573c12c21314e8cb73cc65b60b61897217fc82127d4bb00d8f2c300b8db9ce5a2d3368904c899524af074b70de0295b3e95a00402ca03b84e7b2f0670ba8a0036dba3bd6739c4f60cb13d1a0c000ce2417af2e409a641310e48bef7de7bd14598ad1bd6ff2ab7252c8c63fda59b7756b8f4b759bf5b7ef8de6dee488a439269e097bd09c4e33d79f2e4c97b4ee1f7e254994cf8ddecbe1d886d52d1f3081094994cfaa5df733201326d0faf00a008beb8f98309265d88a853b647b38a583d16112036a9645a3d5309864d2572489155d4aad7c333c5307a388cc993b2cd2073fab40aeaf4cbbbcb9d0f4874eadd7a0f005b9eab4cb1cbcd938a3c85e03e8c593483d099cd769df6b096e382b08beb3762ec5bd6b1de4af2b40a0601de9740a00c10ad02ba122843f4867ee2cfd08f8b3f5b299a4e03e71212e3986e98de627a565f3ab52f9da555a3976e5b4602c197ae281bfc7b47cc6089f2b884c438d65bc5437334b4ed31ef02d8fd695b76574762f794755de2169f72b9e51cd90de194a3d8944ed3285bca8d9d2add6ea74e953eda583a55b2fd52facd265cfaca71e99a4e0369da14a3658bd1586c460ca16ece0c865046e6fd4885abd1e22da1cccc55a7418017a7ab641894723f4e4934823bbf00cf33180818b484b5919e23cf6095bfcc8606aa6ca79b3383df4f40b84fb77fe0eef1f94182fb3332aa57e4e00b8dad009b832f406c38d8e6e0eb5d86374ed397405289249a3fe6115703c80c3279a28c0c106fd50df00258568f454302114002c1208805e941495aa5a455dafbc7eac97a200c6ad58aeb9b5d12bca2b2a5801c1292eb977769001a05006273d98d9be1aff823815c121d0bbf5fef52cbca6c5a4208df7b2f063b087b09eef711dcfd63a1129c248921dceebde9ce8c9e40fde7a455f236d22aead5bb8fa853fd8a5e51ab56fde3350900007c70e9e16e6f89018305f5c2c5e9b5785fd91c8c2905a5a4914699837130efd74637ea60de99287245f739e954afda00fd7ca2af08664aa35326cc847337bfc7635668f9bde85d427908af965d11133388242354161476294db91a3cfa381c4e3916ccddc5e5ba8b0bcb75fae6b13668d6e771e6edd48bd80689541f52c09422429cb34ece1744d6f7de23e2601adedac46d95c8dd1ff0e552a0c2926ae1569bd4221f68ef7d480f6e9d2258548b3ad53ddebb45b5492d7a25ea54ff55b7d5a2da249379354dd4aaa28a7aab378212094aab37a32ffc2eeae6ddfda26e72c49727c7e221b8b3782be6a3d55a89dee06a7469a569a7139056bd5722f812a465ac0fecb5b4aaa5552dadb05b897cec4a095a9e4d2a1194714b7cb46541ab80bcb4228d321b575af9c06dad2a760ee6513810bd19ced570efd337381beff00d1b84c39b319a440ec641194a74a4652e1f4d8964b8b8e04c8b10657aad3a557f7e80829408419958f31c76198442506888a868056562cd0e842520259e524f8988abf1301fad7db45c895c8d11381bae34821209de0c5b448b3f1128280a41d40eec3b3545f109a7a2455c6a155d8d478d2004f7ab7d0ff5fefa1ef6a41eda776a48d7aedd1e8e7435927cf87d4712107035396e0f9aa06741f6a288c03e3a76513b7ca41c3b8a88fabf9ad195e288777757839277878fd1b38f6e0f297664b7c7abc93efa4e4d763f2bcc6eab941d29174504ca538e72537850fe6a502ee5812fdb4e4ddd88281d7ba9b49ac0abc1fe6ab04bb3cce6dd11ad56b87f56ab677dec8f15b24396c81665abec470624e3c98632a2114f56345a59a09eccc7f6404ba42bd1e887909220a0cc1ecaa0dcb1d20f28837217f580d2b12b02ec25eca58ba0dedef52b911012160a2dbb7aec0f059a46c4d5b081312257834e9e9eebe08bbbbb59db6a51252239d27b5c4b64a786a66bddb08d07e57a30ec472d822f6daf832f3b353b35a5213d2520ce95784a41302c68f1d40737cf95832fb4872757a20aa402e181323b35b016a93eae86bc181ab44c79268659697506ed3d0a090d113569d58539f1517fb81a0f9b839677f0752db3b968c4d81cb4f93c57a3cc46d28b723649d0fa637f8eeca844f0a52b503dd2a9b9c28a603e50063501ec15bbabe91fa02025aec6db7ad88b8004d8ed454de08ac0f6c06eefa4d90eec4e22f0a56e523c27345b44cbd86a85fdc080603c580f4624284889d01051d1d573f55c457c7e806c112d5322dca714db766aaeebba78ac6985fb8f044f7397ce39e79c73ce39e79c73ce39e79c73ce39e79cc35627ecced53cae44455066a7e6e707b440a04cace95b9ef956cf06caca5d4ac4c1dc4083374f221e28137df209ced55ca54aabd2caa7b48a3e3eb754895e934e35512dca0fa382e6707442832b288351ea6e1ea500f72b5169d5aa9c32045cd4aa5c5a957c54a256392bbad0a45622abc426b141d89f111f28f363940227537fdce805b8474fe0fe2807b8ff3648548970ff854f25c280f25c5940f0a5673ed51f3757b8e710ee2553c8c1b405f46e05924bab150a506985fb0191f94d29825d0f4d603bb46d0c8d6ee4ddf938e79e914ef950fceef3814c60faaac40e76786eefd03dbe5b44a7dccb022661e3aec4c3f01551c122ef59f3e689732c8658124e261618ae46544293b69b0ba269a557c4bd08771b5704ca68fdd245dc2541d34e3176cafe4d6074d25ff62e11a36b276d3d7e20aa21bd487d25954ed36f2b02656011580416e954f7786a285243baf69476223560ce1d0a218431c26c3e6617fbdc64bd76b0ed8d3e6e2ecb01ef6e0601110ce19ce6c1ee4122b85d13f98b98dbc8c3021786303968daf381f32ba2c9402354bc9083f67a8ab491d7f386d82609dd745914cb271ba313dfac5dbecc9b73b02c22c774a2ea5cb27330605c16162c095a66c1ed52af251d0442085f16b0ba1ef76501374851dbe92e834b709694dedcf22c63ad3bf0453ca10761105a691ada40b99d4e47fd099d4ea89fde1d04a38ae8942441f92d8a7a5996c70d4aa1222ca550132ca5909442520ac917d12a19ef5bd229599fdf9298eb8d32055f5a2503e3f974d9e2ae656852b0c5cd6e09e966aa035958685858ee8bebe2e658ec62e52cb774ba3a10bb58f9751cfa885d5c9c1559aa2f41892149fea297585e2d2efa96648f1b8aa647529a7ad895cbed0813c6815f796df9d35a1cc6d6020f3308c078cb6bb418e662b32bc7565a6c51c488bf36bad97e31dd58797c7d2d31c6e6430a172554dceccc31158142fd2d9142c7d3feb4d2ca8bcb1627b19c65e5a8bb38dd453cfd16e34fee8a39c8a011377978c52b46aac40ece39183ee7607a8a22ebe1122d780e411fb14789c22e037630858f2bc7564e2f0a141ae600eca240a1d19b33c4cab18b737acc3165ea3ac5728aa7975cb828b538a9c5492d488f142dd2650bd24bb74897b0449287f205e9be78e9c5e5f6e2e687e5cae3cdb5547a2c3d5e4546a962a5d0503a303dbca73ff86c65e5266a5ab9e95b5e39cd564c38075f10c63b48bad9c5afd7c3687194bbd8728b4f4a4d37ddbc72fa48af43136df194c7538a4fcf267c8a1767e5a72db7b83926bc724db71a969bc32653cec1b6e4b41c5336a230084f9b6d198e2d26239199c0b407a6d46e3232d2fc45baee74cb6cb0c6acec4666373153e272297a9add441df02626219f840ec5979b41af73c2d4ea5cd94d5bb92d91ddf40acb24487714fb3597682c219617a61f901b753094fea2d673891fd94c06c6adbd0d9a38f2f598cc6ee4b19ba3bcbb54f0e9a0f1f62045156348829d14b0ab620c2bc02418479da62b8ceab2185f1cc626c57b75d9751931d3aa774aa3533331ee22f11e93738576bdf8db6668f4cb7b22bebbdc42b07bc492a0651ae3301ee3f6f881a826c661fc6677739a676e2ca736e1405d5350a73abf18ee46d192c4d5fcb45cd72f316872c4f467fa25e668ee678a213885dd8f12aaf0338511ec7ea6f00183dd8f126e80635c0d2713e3c323042ba03842169ad4f45fa6c3c2ef4228a5fc51c20c228c2c41389977cd7b118e08a75a51b5b0cf24fcf228c3cf05333f80c82ff80d3d17f8650cbf8a1f029ccaf4771aa73afdbde4aa536129282feea9532cce1480d3c9c5cd3bd8c5dfe67045bd3e7a63a7506742107e71fa7769a750375c765dd7461f371cfa1718f597ddd0bf78a51bcb91c0516379f1b85d2f2eeae61c8bafbfbb17cebd783e96b521e1cdd8dcafed1979335ebbf7ebd4e26161cb3adddeafcd7a8bbb95bbd8540e6562de87628686f2738c1b52d9e2ab89feb439fcdef567c2b96eaec75fa763fedd8479b85328682db667e4f9506182e9a36c1c7030dd06dc6ec0ee0d360e8f48bfb4079c902ec820a805cf04b88f07dc46e4f7f37ee812faf8aeeb3a0e87afef60979940e9d1aa184309b0e576f0db7420b66414304ed32618f705c1c7052349d0f2cb69624410b41c1343c3a1dac5144db6e0e451ca392dcbb22c1999e8d106e86374d072ec88fb39a1b9ec7dd552a8fd5ebbf7b0be20a5969b535a91c2abb15709a0c1eab08bd6d17dae2d3790625057eb032d37911d68b989146995abe1b0c3451c0943226fe7b6dc18557230fd871ba350a620c23a8d21bc8d3126684f8b47345313d90210dcef20b411dcaff047cb9a0e120ea6e39b48d6b47821910da2e57824531a832218926091297ef6da18ad5d3951f3fa89dc5c9c314aad0852562a27bd35e53bb3a19f52c64844299d5b84cfd1cf8dd28dd25a8f9dbed6691fcd6c281318fb9c731ec3b026f07c43d59a2f0bec69f418a5f4439da2563db6557b2dfcdca276db2ad2ca9c73cebb3b7a1d6d94081ae93b37b4165f798f56616f7115534a8ba3b478e9d9ebaa97d2538cbdd60da71e3be561e1ec1846696e6c27cd6cddc12ebbb94e8af8b15553357a18c7a46498ee6874b3a68d1e5b461bfd61d8ed19717d96d6c475635a112dc7e06c3f376a95d8c1f3b7b6566c27769abe2c0bdb1c9e578c449d9af559978785a30d5c792a4ba0963cd94b3ea3f8ba59a328ecd875facb3abd46e4ecc0d93de7047b4e279dc63702d8c20fb8703a1778786610a455cd038409b8459e4e358d36ae53f7520cd539e79c737de7ded3b2bbbb7b06e71c1867f4fade6e60337874177cb586db647adf7c9d9e4219d375f025a3b647b37f0f6206ca980e4f93438856a1a858d82f6926525ba72d672667e6c152c7251506aca5a8c40cb6e5452d999a11090080021314002020100c078462b168402c5574457c14000ea0a854704e1787598e29648831840800080000000044100409009663365d0df3fc26e86c2f4b93298a4c0b525111287476f7f0e09710190119e6dada482cdd5ca35d2432560d9fddc3a4e0906a835192122fc34a814dcade8aa881f181b68a4bc45080914c3c0be38b42ffd91429172ca9d6918d005ea107fe08c5bd1bb6dda02d67a2e31c5b5586105e6ef7d4b080b2556b8c6f3a7bee0a110fe7705bf1804736b14ca32905bb2fc4d3877af8aa227dcb8bdbc709e0dfbc70bcf0fe82c96a10994d1c682e370a7a8098096d468806508a8f984bb623fd84f90876c98814b602411f1573ec8d6281607768696d19ef53b0db6c0013f324686a0d3812b34f99d9c12610e24bb766742055d487eb521a21341eeafb1fe60d84ee60d6d8c61c2019b4b24cf117a89df91a635020faadcfddf57fcc959a82ede000eebdd5a1c58b7899a601fdd13f18368efbd32fca36c9f388c10973c3cd414f8dc8a4216daca190929f99eeaa38e3afa15ac98868df0d4878201d4d4350f0042878215cb9cfba9ba69b46c099cafed60c9daf4c6db8ab4282f58a864b17e49cd67ff5071234491dd49881aea896fd34676d0211a2912b39761ef7403f8dd06f9e687bc4258c6ebcaf6ab1d32c73d78de6f5e5565d76b4a6d9d2154cca1e3632dc5d32e2a0bc664324e9ed1ede5b0817a76caf14087c428c70a0857ac8026482f472a7a35ac777e51db6493718fa79138243addf9a75f10aa13e794c1c5584d2dd426a781bbd6807c541a62a203246b3dd486c39b78c9a0a412d76e818c2772268778db9604467fce6628cb308a524d2f640ca652987b51e90bd37d761dc2f3ca760ca81955f93b6ff3c1fa69d79f7d14054ec0869998687ef6ecbebdf709e258c1e5939a0694055f92a3e2bc698496b624097c1af6ad4929b233ddfa1c55c2f7ab7d2435c56814b0b04c26b00a4bd36cd09c59511aba5a0c8f8115134f1fc0630411fe69d60d0a40e3580f7aaa4e00f5fce1c4d3207aa9346dc522e09de1d58007200d2e840009aea1c477580c3667a16d51563a87102a7ff0bac4779d696488f87089cc9c959fd39d0c71b3253fd164505f98908620cb37a820f1d67b1830d3c6697ec33fa008a1b0301e8f26aa7ebd5795f6d09476de74fae2c6ec262fd1a6394b67180b5c694264a5f68bbb0548d3cd8dd7cb8f53ca01da149939eed14262b167aada46352a035724829de0307656985e958ab1f81b80d3d2881b7d7d497e872b442b98d10039a44320b9433c337000cf11b5e7e51d8917b48082227b6e59d241d40d1d24ee21c9e948f738eb0730bae7c5d28d3c2b1bd6bb452ff267a6f65a193f081f77cdae30e1b34ceeedc6cd9135613e2b70469700bf50286d8e538667ba4120c8589f8b24388072ea54871d8d41b2cc553c53161970e5ea462c5084d025dc4509b7a342ce86791d9df233caabba84d0be7d019274c1be9382cbf47b477cbb48112f26bd669131d5111e3845e7f8b098b7eb8c3df0897c63bcc19fa6cf84770714706267e946f319b53090a14c21c7db0a52f7b2dfdccee138b3bd66509d449464cd5096487b4a5d6c92d6d15a7f8bc1a2980e89cbe8fe8d0c450f60829fa6af7fbf914c6b2e648863f73dfe56acb2b62e1714a3e8f93c23786afb8f2a32bccb58d16d94a4a2664cd0ef2cfbfcb8b8599bd223b5c21381c1a3b34505c325a6036b9c88d2ba96c45de77a81097c21c9b16399189efbfa1b270b296a4300d977e758cd18d0b6c275ad40510dfb282f446f0cc71e4af9c5d015fecdffe40a82441f4b6470c4ab3230103719220fe7702fcd82c136b8f81da6cc00dac78da241ec49bedaa086a37dcb29b351da91970483316dd54bdf9dfe326f1b4797d2d43838e2b68b470c1c0c2005ed6b3897c91811f106baccb68a96b0579d1020e69d6dccb84c1a8198650a99ce62986e8c4abc4f2d1492aef204a0680615ed243ecbba4671178ad80a4d406803008485af70049dbd6678e31528504a1cc83ab4bf0c15f10fef0195cdc65b0796eda95f4467e613631f6dee8242f39c42936311c83e94456bd00c1cb3a40d0863517ca1c503b27af2ceb5817027e0643bd0eb3ce9ccde0026a2abcfa8883acad64ac2490e035305132899e74e8e0fd356cb973258ec6a9d20969beb71cb12bbf9a8b45e46336aa1dff05349f519cbb004abf6041071543dacdfb52a2bff221f791d2f7fac1ab4f6dc9e800eccb79e6ee870944e4770281d654f1d916bf8045bc022931c3fbea188388df68030a7a03600979dd122217479da23680a365955d2a5dcc319d5a6155e94d3a7081943e60f5657449c8858d9522d6563713ae5b53608ffafefe15cd800480d005d1729901651ba316fc648ae187353f3b1674c8d0a16cf9b3a9da150b19d3d4e132572f0248609b026657825a4723eff097dbdc25061315a6db496a69ee832d716361fb55d267e7d1388367599ca4c6094c941acf3259072ed99267bd4c453236a9e68923796cd8b500b96788e1ffb8022bdda9d4d9377b200d6e192ae20f2688fae41c3af9e60173d1e25ac918a4a9af39c00395fb5363514bc4cdee2b03346a50fde35addc046b924e447fb03a97bc685561a2ed2ceaae49a84a97bffe8b5fda8369406b85d0e1c571d144cfb9027622c0cf31180e3400686210ec013300e22514c1deff2d6164b1655d2dab6141bf45a918f8d70017c3b8b23ec00bb545b050212d509f191aaf38175a2c28cc0116f51329c1a9e088c05f38f13d6f116368dfdf0807b62df3feed77c724244c1e6c999db4b4ea321172fbbd1408a2243b6e2d8c1a858475cda2b3c406cddd460a2e54a357c2130ea821e30a5a3022623342fc831ec75928ce929c3751b06ce70f83790bde707eb7c563754afd56ed373276d68e6663dba01147e5e10cf683b28cd5569bddb4a3daa31ab65d713d927acef74a482d9ae19a59ce143c9a930b153e0c4e7dbc01444037cbedfa538e7dca60f5d8c87df4b32fbe45ef3a68daaa932fb3094740181dba5e0e4cd6ef4adb10d93914df91d1bf3e9b0e8b49e572483703300518454c8cd5dad9f806e801e08c7fcc10e8878844d245fd49c0e2550cb5b8378faf6961c7488e12bad123b82062f5d813690eb736af4b84507c2c80d5b67f9a77fe0664d2f954c1aba3e4072cf7c3ef13a6212c429763c627ff69aaae934218d970b3e6117f3495483eae37749a683299e2b4e5188c753d4bdcbd9963d6049e066e5e93ded8578fcbc7f2eaaf0f22ddc9a91bf156f28d5cc6f4eeac00475f6027399975289adc0b98aab67dcfb30ca701ea6a0ceb5058f350760cffec6bde40130993e76dd4913e78c291c8c30fc2ec58cd989623aba26bc9f244f3435e210ffbf27e1b92f8c115d9f20d3fb402d42118646663ddac2d2b9b3c0021ca81992110b849931cd21b465e3d70089cb6365be296c971f4f1164031155c83d7c2109d27905af911b8da4293e8e69bd423488c1c7596544ac083834f7e916a4006497bde534634b30d8bbd07e51f43e951f5e0519fcc2bf37aaa94b10afa1f720d954493847b4fa172e5a3f5f1865ec9eb6cdb06e97b05db15bae3598fcc32d0423e110f65addab6a4d0f395b08a99993fa190d17910c74ff9134d58c014c19132a9692d8531442f75014c9eb89a6a7a0ebd31442c45753cc07f6b6fe4a93d8f374e51a98200da6d872d90b8488f06aef8a830eb2095662ab72650309d3680bd5861772ba2d9e725b6b7fab249a0fa84eb266b06a359522560ac2ebb0628ee354222fa19f12caa6693c99b40d1a1fc05d8e2d0c77ca8c05e23f99f857dd188fbdc240dd781b2c8cd3d04507d2d7d248e33b9ac6d9babfc01d3f70b90ee80ee10242d4e630d5716fc6f07a8d50765d2f85856162b4bfcd1fc83a8a4b5a77b1e3586b6f24130707cc5ce3a7a87fdb4ba8acbeebf5dbe8deee4b923e61cf585f893ebc301270487b905ad10ea7bbbf5fd87d5b16ea15431e87a4e93c3a3b20af2037f95ce45f08e33df681def54b788c6bc15260d260785c77d5b69b3ad2807f9b99375542291605e89d474c1357e0be673f39d5570b9717f8d8a3b35306af6164831b477180066a12b0d2cb71670cd286ad90d36b9bfdfe158a15c06bd161bd6e0000e35116821c370b8b2ebb637a834a755fa17afd114d9a49cc03461a7bb7cb002505e73279fea9009762a3b8ae204e634da38c5d5dee4081503a6e0d3b49b6fddf4132d31d0c20ce5e3c1179504c978e63799a07a8906aa7a9a12c6fd6ee2a75978c3e72382ed4fecdd0819b90ae33553d57529e697185b64a6caef50c5683647750bf503b10ca03596739f70d907839ee08b9a15ad600e7262e0c504b6acbc39c88f58aa688f9f6769fc5e195c5dc5cdb87bb5448250dc60b2c62e85b455616e17c1843bf0906422cafecb07a619a94f9b5141d675302356c71eb269f4704df3a6331eb8f3f70c84800650b2fad6b4d5e60bc090894ec953ed8a218b332c5c7cb48322fb84c9a0139f58082cc20f6a48bfe131c9b00210631a6dba13920042bf9ec059729500107b57e870dd69b0d433489400225ff989809c8fd59cd9b7c86b5bf52f3b32eb09db75bb6033dad56dc4a23021163e93c7ccd9a35248297e30a1e18328b0dffe207504292bede9be61402620b19b0594b020c6b957e27d2c09955c088e680c0d098279183130f3ffdd73877875e11537af950ea9a26057ab68c5902b085fbe866a4e138fd324104657493684db582fdc1aba0ba3880c74ad068b298775b1744dccc6181fa8b79a655fa805b1816f6da7998d45cd90d9013115b379442b5f3735a226ac0aad869c2f939bcbd3170095299dfca48c0001ba7701c1ac425a2864c1e117bbaf875c67f7f219f73f11349cf13b378ae61709b0d692953df4c96662095d756377f40fcebf253d3fcae27cb1bbd6e1747b55edd1a6df258b0fc8ec253167c1e253b1405ade813c9ed1e00899636686f392fc846ec7099e06ac263ff85b470bbb6567342f97433e1cde75364f7c015d5615a784bf2a1ed07488f04142b175d0fa385b6598aa234222b937f9c34d3ebe3c4ee0161b68753cae160b826cd8c2f197bf351cce0cc4d4a6636a319c268b401faae9fcc4072616dedc5781a384e13ef0be9194f0e87547b03f442086019cac1ea0b0a8d5a54cb33190f89c2e55b52d888b63c9fdebbcb0e432a588283e5e9e608acec7d7f4163d0690a68e59984b4b754a34ff874d83538a58783bc207ca1a1604f485340becb6d74687ea42e257d527058639ca8aee0ba65f6615622bbbcfaf972e2eff43a8fa39903d0ea67b9154bf335efe794eca4018c4e3dee7bb5db42933ae25d09ac49452035f9bd54c4d353fd649be8fff9a93400f51804c575f5f25252741698ab395b188b6752af642c7a9f7e681671fc000d60f0069ebc4afc60ba29d4f3a24efd3470f57bfa86cbdc8b49e981711e2d22ecb43c8aa99fe193ea4755f942448ad454b5fa399694a37cf4f348aa7eae18db56a32f54af7fbc8874a6fb7f9e9154b1ad8ea7ca6b270c4af953096d2933d170a178897101ada94b1a756591285948bb3b8487024bdde633d6c187fd1dc406193a552d492d13f23f278d4b05aadf11221bd64209e893ab28b8e3af402ff269dd9512b4161be558332c184748e83a52268a95992f879ab022e6d333e461424166284c1a8b92fdabf481b58b4663366cdb65102f326d4beb7dd4bf38019682053a8a0f918d201b7b9289266346efc5e016a2a619004573a8d0ff5cb6064a950d07343c2d2736b54fa763f2f3ce6354f676a6dd17454a3035b38eacec878a707cbb0b14908670011018e187a53bb4d4bc026bf4890b98615759b7759224d292678af8535095815ffc12c283dd042871156d7b64577f92f02368c23d8a43d42f4b8b090bfe0cdc293342d2e115fb289c7ee2a0c30b4b8fbe2457000899acdc378a4b79da3576be4577621ea52df34bfaa204de2b665436078e9e2f915fd7cb256978aa92db6c2224c87b07422bf48828875569615e441efe04bc4de11eb896061109ce785a8ffccf68399ba75759defb9a9808f3cc8d40409076191ca2c651a5e65fa8cb79fa8a8279c26693c06107f879fc8af4b86bfc6345f6af51cc39cb1aa70b0d5b8fd49adbbc51cf7c910c46ca4cfe124e45edac74b2b8b9e63e89f2afdc1e0c191c0b7d5302a730dc980b83929088043e0b1e788ffd1d03ff5223085472f35349b4145b3c1bf17c6e804c93291d01ae264658b60f97f34eb9523927ef04dea89f84f7715575cbe9a1f265a06cfc3dad70b896f58e94abec7afda5650d300985d1c016455b5693ff14b712558062b809e0df8e138acb36a18b07617cc4038894a759a0ce8e6f5cbcb71335001c70f43153711587970a80aac9e49eab077d849851a83b183e972ac0c364813b9e7b24f638efbe3d23dd977194f765cdf42736bbfb08be74ca7ae4f1e34a9b38f48ecc4272146bc1fc6aa81c7120265ff833110005ba7ebebfe134cedcc60d2451b7e7d0271bbd2088a1d9b690c6026d1632413c850949d7281acfee900cf6e998fd8e39490706c9592cc0979af72077e3a1f4f600fde528cd1fd5ffbebe0ea140e412fd87a2677c814d470a6a1341730cc729f50738797c45dd3f8d767a303f6a3866da195254e06e4dd232ffad3b4f358e1cfdd55be45d25a58deeb07a6cce503a5cdc7dbb53370efdd2b2573a92f1965a675b695618636156f26531588c6e64e27c2acd069d4fcb93592634c2ddb191cf60c41dea703cd9b6402b2a53b91325f27e56f8ee20ea17d05982cd9056de50eea4a22d05b57ccbeb85cb4fbf4110db4753fff240165a5f358b4be85e745ecad1dbb427b4e8b844d3c418d13b44ddca06b1f199970aad9fdbf7ffdfa2d79b8c3a338ae406b1ef8e99320f7b1030a37339bb767bfb56b01e948f99261ceb42befacad6ec15513afeab79595442f3fe8ed56e7e30ccf288fa2dd9e653a3bc7617164a35f214870756b8eb2d3434a9fcb6abc8d0b85c5afd982169d1127a18d0df713ad2d99d955ec6cfee76757699b398bc25260431d8f3cb300c136e3ea43dfa594b8c6bf43641631e04399cb69a0a41bc01d18338ac4d1cdd73179b2b022c7d4d2471b558a6098490ab8653d96faa4a1e875e1f4f42beb4da2b6fe0e8c5da7f22a1c86095583642e3948641a6aa86cb24b846cad4ddbdd8135e309168b87b21e73509263265d972ed340d5886523ff8f39937a4d2ae31950f5bb4fe9667ab245195f482c01a8885f367edc8f78a8c6a08a4e62549ef01f3357812a0e762cf1a9b2f80104bd9e6e25c3ca6b0640db81eb2663be210b0b5e3718f490be03d92a1f19ebed7923aecf2c776dcc1685167e94089f9a228bb100fd94367a977be51c5f3d0062880005ecc90291343a6975f480c34717a1e2d1da9793904a04611b2f45c25bf2fbedbcc41d9c37c750d39c134121dbe7b77f6a4827489656d87722e98ddea20616104cf1f540bc19f410ea079e327acf66ec4a1accfde08337fd3a200e3d6bd29d275ac8a745d0a16e9aa5f3a1963c3051298684fd60295247f58a39feb8e714656ed05ed08428a95ddd3ea74af465864384fc4e3ac78e62c63a1b4162f177c9270efd73e17aa7a50cde1ea25f5372fca73e1f2c0dcf371363ece88c719f1382b1e70c6294e900580470f7ad82309ca6d811946e8b85d3b1d1c03cc8a8a40af0507be88085660731292c3f51dcc3dafbb1d51a97bb847dde2faca3e3c63da96123da99dbadb32a7620d9ee9fec3e46c4aa10c15a8806f56972d62cd2f91920fb2ace20ea27f51245436a370fb72f2635819611a7779d73dbf4baf5ed68869e55222bb47b744ac6c4d9e34002c2320a6a2b88852a8474c969b8112678b0edff073ca65828784295093e72e44ebeedfd2f082e9d2e4557c6ec938815ee960d725fc6352a45f53eec3c6d57f55a4c12eaf52af4e23d18e7ec5159e5a36a2acb6cf1a507e848ee69d55959641390ceaa80ceef697546f230ee535f9e1860ad93b45335dac3495ff3f9ca8934c8542876bbb5122486ce73d0da679d1ef3b68e72f4d71c3fd4ed0d1304507a684da1b1087a62884508066994b4c8fe2948c139d69487c26a466b984b4fe2574da7041b6ca79cd3a21b5c8c75253f5963fc70c0d9c395ad3f8096105387487788964a64b0663ba1c2c18b4e6972e4fe5edb27d0086bfe2d5e9b934cb1ff7b45112750bb54647ad53fdb3ecc7174f73f90200982e72a568c82c06ad80d881f6f249b9739e1bc8797af28200c4445d82052d01753f7767a2fe5373e410e6203ef14809c614f70861b05d65a98159052eb74153c825d2eb029c40c9bfc404dece1c34768e4f7c5c60ea22ca170fccfc3c8aacd0bff1344fd98bbeec3e65e2fb59dd4304cb446e6d448a9c9b77622e03b7de3375fe0cd519cc081e5277afb36e86884a2315b10b33cff648d9ec85b1fba6f4a23b0cea80ff3322ddb08d71c0b50676f80ec6eb0c923e3b30db30e439ea261ddcf824f54c5101c09af326d638154d701d00a60527efffdeb2756ad0529866141707c0833b1c791f24ee93f9c0e7242a88f920bd18a29ff1cf582c10d7639d37fd2de4563e40bbb39bfd1a4483eca52ddaea71cd45be33b6319d362c6d99daa62807da434b84d1a2847519edb899903c4a102ba31a01a980671b8059897e6e81b01c5b46252b678d8edba0d376d1bfb0fb5b6cf3c362673a2d563a26f251da757cd04f2f04664b5b2d61866390d12bdba0a5e596dd1a8974e7729c326f17008bead2ea1a1d5b4db0c8a294c36c0e2309749ede1c53b0cd9133ff0cca8a3b73a5f280706cb648064477d51b467eb7f9f467af5914680c60aadd5dd4cbeeb1db51c5831b63518e9a848f07de18758624e0c43197fd084c1c3ddaaae38aa98a3fd7c6ce60e8300b24761d2d8216c54e2580c2f0ce4044a7d171e22127f96237f695d0086ec2382972bbb616bb42577f5c41cb643ccaef74b00dd0cee38062f0b1957c92f7b2db8193a3d7b94c028e431ee827ef98a464128ea3f7d4bbcfae00de165b70ea1ebfa9a55c6840ca2da80e7e5b352735e0e40ee580d9a8cc985ef238fc217557f059154504abe78fc82c00d811035aecacc1d0ea9f92ffb9f2aeb997a19473d3105705f7bb87f6c9885aa5c1b22c0b9745c91c9f4911f50189061c7143a8c84e355eef3515f3df1e431bac05ee15e022e6d50e29c6f4ffdf425221250f9a0f7f6f963f376c40b00e13616df96872bacf5702784193eff17444d76bc8b4cc08ee7fe7e3fabc5fcad10d5f83c21d7d6bffe707b9e68ff0441f0ede3782b5d6810ad3ae349730f514e6f2cc18f10be2f9d06d2ffec9c4680c1f4c743cecc94651b510adacbd13bea816c0fca4f4c38daead362af2a363bb5932f6d4309cf71e12b3825a793baf57057b9bb771dc4e82a3509d6efce576ef71821f5ef6bf8797f7e201621ce62f9f5b49d935c24c2fc6bf09deb6198a945069aa7198e530c7f87f08496a3be6a83205e9f1107ff44fd343e44bf0b726e9c2c70f1dabc20acbdfe5f5644f575425af2b0b79cb22049db900f326ed256e6ff093a37c0bd8f8e7f7cff9d6a4ae0748d65a341c8426ffff8d019d02e762b9c4299c352bd25a3ad578c7a809c66d076fbb045cf8fae91a775268f298eff73d1d73e911954e8ec67418314eb1156c1213a5b0ae061e369d643bb19791952d74b13dcc7e4e2f2d2a0f1e636ea02151bb88490ac16982291a0fc007f084200d5b0b36b9af75c2e1b9c86877ae0c9fd0ce9614a0f3e3de343e42f935aebf0522e84533374eddd8c61ad888ac20ec26dfc4dccdc7e91cd2471a67a8f932eb1528a71c819e1eec3c588afcc0197d887b950f75bf08d16743d99e062b505d0f88d6ed2ad1fb9aee5374d4b9944a8d2cc453c04d71ac311c1b936f3c1b8c4213b9734bb5a23b8d2ec7ee7f9f752498188c3596d8a33b74ecd6b1933fb8094c8ae6323170695eea9b8490db1c080f7600828103415b8234fddcf22a85b160b9dee4b90978a314e095f799276cb7125ceee508afeda9d81a7d38c288effde3ff9e17f86d1c68f09cb88afd37eb122165d11eaa6c61d386d3b077c2f78eba48c0e3969944082b3f52991054b2f8af9c855e9e306c46658f7ac16e723e6bfe0fd7eb6954b386fc68170106ee41c49332012bb7615fde84938dcf0af4d3e98a51e01a3631a0a5076c685bf78b760379ad918c92fdf80a27a30d9eecc8091b8de62f113680df5b3a085402e51818bc7d9146c04d3e790d0a5bed42e36581be69276ef9e3c5e6b3e0b2376b031d1b6441f8c58ceb99e4a4cdd5bd387fd04a6f112cff9daad0a5a06e067f598f1cf0c9d105f64e87b3508c65ad2d2bdfaa18b28a375cc06dbb7d2e844dacd7264f738933ffcc4f8ed13613e0b957087f02a0ef1a656be427264602302917474d4f117f355d64c6a1b74570c58475acb3e98450af420474e6dc6da38607b974187945b6576a1d96712a0586b3284d4b31b338ad4ba1b9411b97d17c489e7a8161a1cde68e0b0bcc5cb94f2a79f74fdc92dc9c8e97d04699b80dd05a507114ea26954975e3a835efcf8539ea36058451959266f165f9db4754601055dbd21972ab616248e020644be60a09c71d2dc321f3c4abdc807ea86b544c3566ee639d16173c00e055495a6b2dc415c14dc5b255d8f41583c14a4e30748443782e54ba13cbcfc150e8cded42c5c82d668d180b9256e71e79db5aba5170e9d810054cec8dba55ab35cab631387257f996964d7cc356f411bad5dd37b0e8651db9133802815a18b5d9e14f23be35d8b7ad594991d8ecbe9f76fb4294bd582f340feff94b19c1d34f90b3abf92807d86aa80b32e8293340c4c69a611a196c7562de66cacae3b759725b3fcade8cfa40a88de0cc7636aa69de7a7584bc3e85c81b022668317b9d4d5055a8698caf43b3548725effb2504dd9b454b4fe80f91c5ebf4129c9949f6ea9242bdb4c303a77b22fd38ec66885f77285b8ba60bd09eb91a2571118f476228ee2a2dd9618ac0b00f96d2dd1024a0d259a8c4430c5968f193d705a7e50af490e7484e6db187c09b61bc8d8869f33ca6e9933babe4c720db90b7dadf27fec5095061c0705b5ae4b00c4b1751e8dbcdc1f01070ab7902ae818e5046c5bc8a1736210380904401bc0fba82b46f9845635ec726cdd5068f02f5449af023d95c73c57c82737758363490e042e89431bc4e6270865454582dbdd4d78968b87cedfaedf4d5d2bfcfac1026f98a976e8b447f499b51f7cd7319b30eb326c5c355c3925da23e6490c9bd642ba9bfb4b60d965edd75398d2de1c16cc5e6b7812cb615c208b1a2c440b83e128833074b7528d063a1207edb6f77e7a9312710e1c7d73dc7e5875878d940072b8c59ccdca88f04cb14bc7048250c4991d519a7f56223fca912e6bc678e9c34d60c9681adbb5ec65d469725c3842331ce1fe32e57678271f93da8c56648184e39b068d30fa0d391c0b980b92aaf00d249364493c7998381ca6936c25c2b00320422cc01e210caf9801414601a4f338bfec0a2101e78080ca64299bf3c41e9de314d1a7811136b21a87e4f56d9f0c48ab43bb391a1696dc6fc3295912fc792bb0c09b033f0dea524e1415a99171389a10dbe67d44097bb85f7533c2e068b5abf44aaf5797647982d027f8c2c5ab8f03b07843177bd5c6854b94845ba6bd3494ec7c98df1735a5ad52d1199b278eef4daffef8f0781bc562c784f5f380898b801c2fc1b5379319adaa4eb7d72ffd6ccf77ef817a27d00821f0fc96ed008c52a06f685aee090bb0f2259a9d4982ac08a0d44d11568fc8aadc642e222388be7704490f56bdf05ee305c9f606fa1cf8fb87407f6d7b69d9e8db52ba449923eed30836406f1c31b68921f88aa957c6801de9afd4fa4167b79669a816e9d80792905d2031ab6edf949227f6152fea4eb42b0d6b1babaf8854f58215e246e592fbc6318a981662bb58b8bde1fcaf2baed7f66fbc9b0a2b1bfd86d3e01d90e1fd95f211dfe4c210b335279e6007ab61b2b7309a69a5f3f744da9ad2252cf58dec697e89014dc25e48ea128700089c1470048ce087f801877bf831e3a1418c3e7d119cadf0c9f63bbe4ab789962ce55ad91f9bd5a409a8f7f2a952a64c77b3fae6bc0cc0f77530e92a433ea12a8162d668aba0044675c4c03e792867770482f8cdeab00a4d58bbb1541b1e52ecb42dc715aa5fb148115dd77c3de9056de4d66394f5f41e69fada73d3905b72a810d79081135532e3f932e9b811a643fe54d9cafb237c46b348733c19332b6ac08d9e1951f8ad916c1cef237b3491fd9947449abaa5d15d7a1c559f6f3695b276d929d107b37584887a30b84e095c4edc9086c36a591dec03fd186377bdcc6f29575d1f4bb27c0819fa20722f43d22eac0f6ea18d7b1fb60deee0e75325fffc2e0f4412d2b06ca7f6e3cd185c500eabf479707e3e5824b19d99374feaeeede0d5925123d3c08f6f1ddb4e37940b85316c9c81557e9187eff6ad4fc2fe555b2174ce9f496ac8b16c9bae94b6fc917232132d16decf7745c4e1bf6991d590dea1d3e93aca58a9f8c95b7beca69f60970d3d11857ae510d938b6808beab49ca32f4ce40dafd562b66eb3b0c6fd72adeb524a0713b2bae42ca68a219941e30bc13819e167987e1218779f7c5eedfc747922100584ec2a1d05675e1610d29c1d4b8ebc736b5140adcee869c8c98f84baa7db2042aa046df97b6349851ecd61b5abc9210b344c650aa1ee2eb3bb8bf478cff69da77c804181463df5879d3ef1272e6a3f3a003190abce938226f822ec7de7f63b633051c7aa8c99552f4625856864bc3e846638c43762ed9f84ce4be10c167995e20943ff379b15c9ce162fffd009025370e36b6c7c68568b40ccf45122370c5388393a1f0fdfded462d3e1c8cc414140b72a901794236490fba880e0c937a1c6e77f1fb632609baacc9a87b8900981ab98eca16a10e5e2f5d6d078281bbb3f5047f5bc564490421253584567720e54efeada06df030fdff822d9fc14a3d5d81ba04a3df9bd36b37e96d7798e8b2343cde3073633c9cd431078ac26e018a7ca797c75441f247ba18d497088705e6d4696276b50bad25438a3ced0f9a7a4910ab12d5be7c1b6abb9d2c39709cd5c41c542c26da50a1505ba994b8ba01ba21f1ee64e8bc41b54d4817e015d6ae5a76ce902ecffb98211cb63b3b1011a11039fbb82b2c03bfbaa51dd8725caa818bd9d4d9cb6b4d19198785c3aedaa98d7780efa8e404424e44297f549e72d96f7839832e1a4402dc90a00d6457354781edb3aaa0517bcd0e0310c53d510ddc5816c30fa9f581a3ac9ede0a1403e2e693f4a7e08d7ca899449311d87821227598276804f2736788c03631af5bb0629ac1a070e4006109199419cf329da2a40cba7a7483051719bf1237e2ecc6afc5e20e73b55a7328897209ede00cbc79027e15abadda2269b805990276959cdf453fc230606db00ee5c9451d21ba83b2671243b8d2788a9c1238e495a9f6873634618b3c36796b86f8dd052faed41c10a2d064280b76051b7fcebd896fa072b4966eb9a1e28306f027c1627c861b906f5caec3d7dd2c93f5a44836fa164ab0d1b75d026e039af332e36635e61e35c5e8edc061e5a9a93e7d13abcf3fa5eaf330e4d31695b77c8ad2e225578d282fc5e07411d09f014d81c50f521a81842040e02665190699aedcb37d29b0a21fa8707325e6100f65b56ab72cea59b59ed1539bbb00c3696c9d48639f58228ed50f94241b19f3967396810e5f6177b4ba1d5fc8f7d2599dfea3c6a8fc265521e16dda40b1db3c1a0c827ed2e21481139ed459fa3c989096824f083cacf31b83bbfb3aeebad1e7a24334a790c79066dc62cb4e1db3cc134d4dc6f46a768b28a283de61ee7b6d162211e3a64fbab8e4b600de123525320a66a0f2fc5ff100397134d5a5a02b256156721d7ab98c33ec3b9331611ed3379c37c10fc9eec428e541746088806dc9df1b03d751d5c75756b3e7f6289a76f2f3332ac57c1a8ea36090db58845635516e1daad2ea545e30800878522303dd880294379e5d3797d49a313371aa1615794e906f6b05219e3f3a07261450355e13d3f22c64af29ce12bd86ddc25b17068cf83a7956ea538a80e0e162c2e6b0593750fec4e9d22ef02f33c10e009240a5d2820fd09dd743773208592f9c475252e036bf7d0965864b0b111553270cb8d9f13e4d9a641d8d37219a3b8f3a9ce623a8a02b80a0985e26f76426d58b022ff22c32b305d59702f91f96efebe304af43a093d26202a5912c1f42d94c6d25dc7d8e856a4eef965024de64aab6267059dfe186194c442e88bbc1383d53de3211a2eaf6450278db920b91de588090356364d96b2143eab48bbf0c78348f22d164b252222a4f113e17110ebb5c58c688cf0942a8488fc31db04aa23d28a002351beb0e2bdb56c34af427e6bbd725182ef8acd52262efe0caf0951a3185495858a3b066313e33341778dc5fddde8ff4e2c3f7b4aa34f64fb1d396d45ca34f5b8f2116e6e8528e0ccdceda7cad9c04a2194f22cf0e6ed1c310a69b45a73001c0cbced440a9c84fa524bfa18f58a24562128bf1280e5348724396662268ce896d383c854df9cee982bf7598cd3efb77dba68b4bfb9a7a1f866d8907ed07c9315d82c3719699fdee81d45c4bd1710e5a7f0fdbde2380772a910f3db141d45088d83b4797deae9eda20354e21b6100af7844efb79a857333d82a21b0a1bed48a2007438cd23685d56e06a193c4a3144cb431769002f6c2b63a31f3ba7d090ebedd6d73a55f2f2c7ff66fe71ca29b83ff4cba94641334c482b5cc894f92d9e693183c214c62177ab34517f5663744d4a240df3f103387ec837fe8f1ef261094a828333e66c7a51ca546034b4d17925b14b5da856509788cc79cd8891a600a6cba624d0ea7908a481a14063cce6f11ebc17d32d40514154d8a2a29c08bf191eb92c352bae5a529220cfc7accabdbdeb27fa06477d16acaf1b91a268c69a2c0e6c5036da692f81378c97a69115dd3c4783f3183532e17d9aacb52abd428a9bb60113b194169086f79863b08d160eeeda111c2acb9f87e3d27543c381e5157aa559aeb4913d0c4339246baf78413c8a4872c39fab1c206c34aaa5e5580b02066f53929cc0238592f606ffb41a1202ab931758b66e01f6ce1aeed113cf4ef8550f6b89a43e63b20b9ac5737dc4130ad9ce151b6bfcd64e4a609321f6b957ecabe76473cbab4e55924960df114224d43c1f473ac5e44e575f7aff175ae406ba754f3c1a7ef96716c8aeabde4fd22ef6b96997c25ff55ee3761c2bd2591eceab373fc2528f45a9de811b3074eef3ed3f51846e7c31bd81e47e509565b997a4371f9531703ca7d322a48190be678553c234ca8360bccc595ad7199d1456e1ecc0bad4f2b9b490debb5ce55575d9c0632ed608f272ef4cef72f26de3b2ea19abfbdc9463df2afe939bdb8450de0b4a36bb8e8c88cd33acdca0dd1f3514298c48d5185b222623f13d04a2232194817efffa3ba0d9ea346c2b373cf8a6d8f78f2ce25f47daeec655bf783d7bece00b57d25bad6381a7112296e66bbcea485a18d1b0fd80efb4b3772796c449fb020e433cdea93d61aef3e97e85bf2134338380e6280ee8ed2a17eef154d8f8815d9265722f23064121143466a06784d18041a55836cbcb3ff2945d12c85098f557de54f751edb7c156bd882605c4f1d696920f684593071370c925492d95eb9e12be8c04aef57d33804b73f3295a12bb94e6494d4a9c6ac471db0b0d2361eebe1b00c52c73799a3cc094b731ec7c1604bf891a378f64fbba521b00f392005adec691765ea78f44cb2db10ac6ec67fa056ddb8d9c75960f06b3ea69405f61fe4a59ff0f9974621922b048d0f89a4d3b0f8a33bbbe82a9445968be6513680edf4a3eaf6c2e005fd5ed6f558c22abbfe038e5fb50edd2d0b601af926c925ba564b730c7c184319c0e30aa190e832dd74f720491d33cf6c3395fd4335208b56e4113db4e5e0575c14c9ea749ad7e19931da27f558f0ef108eed232e12fbdbe292ab0d83bde5e12c269c00acaacbade83afbf7a84704bfa9ad8d4ca51ea29e78f660de22a15d061100cdc8abaef8fe41e9c6d1c74b8b748d72200c724d3693c9d4e1d88394adc9d0a14e42c9c37d859f5efcab5c5ce8f0f5bdd733c470dce15f7bb226045c04a3d3bc9584ba3262595cdc603ba4ac3d952fade45bdd8c43c97238514cca28849da073373620d74f8a6fdbe8a22e944e08555c5421b6c789d094d41811eb84447ebd170d6b5388afefc18cdc6ba0bc54d28e17473e5a5fd583a04cb1b265f8984d50288e064ad69c0e1f05e8b7bc95949696b942e861d80b3ddc8e2b28b825a4d6fedf1d2cbdef27656a0189447ffb657fb82cc606290645aabb7d19764195cfc99b611e616c72f8b0172390e0772957c50f3939ddb9a523f630c501a435a2409e52616dd6b8fdae06d41bd433f3e3359b3240154f3a970d46040599ba8c5ba1ed4fef2347855a3eb570c8b8ee1acc047ebc179586213e04ea4c1895acee6c6402464d0d90b1dc9138608f4ce37d7bad73ad7ae94c49267e2c06bb05f596d683cb1ce91fbf976bcd1355270262ea5ca7debbbf20be235fd371035d49a2007889aede2b47e62af2ce44bb814e33f1992ea82325ff317aee521fa9c38ca3315c76f7bad4f46d5676f670dc25ee109151747191af6b4ed62a25daaae7c089d425066e4a917d73bdb03751367c57675b2df46cb3da11fbf68f311d16cbf87790c0859b1b946d8036c18b40806f5d3264f6e510b57b362bea0c12051c881dc5ce32eed73410c4afb8281d470c0be33de351cddaf3b9d8a85064c11d40fa60fdc63741b4cdec1c8cc11590e341a9e571efd4f889900baed207deceb9f50415c7bb6927dca46f450adbca0bfb5dd532288059dec1ba606efee9341b5ed0009d9a4c69fd68d33ce35f42a10a97c28485290b34444341dfbcb6c784643ebefb2748118245eeb45d6707cb467528008e83c9aa5e4db5beb8e3dcdc4ef780c3ff62b7e93dc2fd7b5dd74e98b527ceca58a99e4a45b41ea7f04346b23367d846d870b6495a4b0e92900497a598a83425d42c1c33e0e14be3aaf88312ef44e04040c59e8319464a357cab4f4c4cffd134c993bd50cbebac1de7f79325380ed86314002806afe8779ffd33f4d079a956e3c2ef5a1b2eaf6c9254b1732712d7c8f706738b3c3e8974f85d1f32f6295d7c137d5bef853f8866b8d91e457b4005e2340ef25b0b5ddd91f7745c1a5099f105746b69e44edebab5edf17151a59720be6c693e1a2e11def734798e8993602ba79c8ba221187bc27737bbf7e691ddd28192a4536a56e50f8c231e780f712f48917e3cc11b1b8e55ea8bc34292637a860b8d7810463212f58eeb6cfe443f3f3a508905403bd606898db3c3b070ab9bd040ce5a47421a5692646068c7880ed561a294c3f7b258e79054d9d49b3350b7995d90a9188853c4dfe04e81dafe66d40f5c8bc9f52dabb604ed7cbe0855d9ba0d539d9acd0bffbe195623e2bd416e2892ee875eab1f7853d133037f28661d77c883ba2611ded25fcf7e712e4bd8db651a37c87b8cd45059b12a4339c8d355dec71ef2bf742f7e4a13e658aeff3da3e1548063e13eba6b2294c44188bd6e7bcf79556f31b2b81b94083e271cf587965b8f51d3a48b6609e1da4a892d2826e4987c3c0300305f5223dcc1b5b1723669e9c82711060a8c5405ce6f7e3a89e78feeb1bc4ed18b79aaf2ca77fb9c203e9185ddd7e4c1fe127789e28704778f4c004e6e5ce514d6953ec041ce200acc7f1f17d489458566942d6b89102ee86a90365c82a1d811f84384425be5e0582da39a4ced0769ae373a4ac2f78d84b06f9f4e074eaa8bb94ad62f24008e78a0ca9962588c514082c448bcbd3d0cfd5b72c00fc47e31d1032636c41144b74d59b03db504c1aec308b66034b20d05512a4873e0478486ab32638327969b8c3d833ba50105f4ab11fb5dd2df626d6a6db40cb0b13f0aef5496918471e9ae689243a64162c394afb8832321b80ee87dee275cae845f2839b48c127d7acc0ba4787c528d0956b9bf51bf0cc445ee20fdb589b47c596380f9bfe46b1d9b09bd2f17c3f25ebb0fda6a1801a74d7dc2c70057d4bb2af7afe1e19521e9a296fd95cfd663d0cd06f5bd314d4a77d66259387ef1daac75f0aa7fcffc5c629638bb6ac1f814d113be66e88e4c18fd4005eee6f99c43a861b492799a7ff7ba6e0c800f334042e5db97b40afd1f2176291c7560a1368321961e32b01bd623a06d1af6ec2ddc45845abd6750d62e9fdb3d56390930760352eeb78d7b337781339026fe732aad8c40c9c6150b1e923e1c2afc3184cd76fe88fd1fdaa3b83d49dbe491948f8bfd99c8cbe0ff5103ed4cfc71feaa978adee5f688b9881b930da5ae55fd122efe49d6c675247ba97b9ded5ea3363cd5fd582203969decfafb5582def59bd5bbdb26bb759cbaa8d597fd95434881aedf42668c0e3d5303bfa5ad4c86c37763a40c804a85b6c06537376c2b89b0139593829fe0de6333d73829e44d136456c3e46101a4a7892deeb94e9d12fa4a11371081ae8639aa0ce73256e309c7ddc8510591bbe5c67e46b674d45c91bcefc7d6f487785a7bd1e9e5f91d34c189bd913b16c5c3367e8997082b2dc34079f09db7dca7f2e1a1e7c026eecfe1290afa5f76a6d724f7ec0dbcdddee021960ec92f0f1c28ec386a22bd40cb9f0f794f2fce3b2904bcf82a5085c0fd2dce8af68c4517dfff85e183f0a836282ac6d2226fd5d9f65e9a401c478b182d307e07361072463bf030e207e9d66ea40ab3791e94a028daa33a64c412c8a30b395d39dafd475816a36f6d678c181a2fa677682d4e2c4b7e108c119d914408b1b8182d25adecc5f58a3a95377bee2661fad490941694d97a1db37635ad5db4de2ff8cf146a541672b895ea9a55c3db24e05035300f0f1141844d095e0330e3a6daaa312d86efc6b43a73b2d79c4a082195052325f075081e4194e069fbf90c02423fb3f872256dcacc68e85293e1e2929f934d815afa56be060961c485c7805c737140e6a3b0ce7d5b7befa3d91674a237dc08879f508ef175b4691d0531a8e4b41bdaea9f7cc4233b333759ac2bf8f7b5d555e4091214e21cc92a0e48edff4271eb42683d656773f4c55eda7a4a15851865493a1ff0ec1c8b41c08615661ca31410ebcf7fdd006ac270bcbcf8540b6a0dc0755976efe0539dee42cf3618411c1925dcfa4e1bef459d41d312b20ae6acc1ca4241a2e87045e0e3f086aed35c1314267d6c1e917b1e63700f41e3257861a5e42ae479cff385b55fe777a99b12e38ad870976a5b3160e9ca908b15d0a27f4ae20517d3860b5d6693ac25bca5131375c005fdefac5fed26684181a36e26f582a56021b52bb78b02619ddc48bb337af8840496380b25655de64b20d811d04ef510128ebecb4aa6d83f6cfecb9d7fa7cc720cc41f516ea2388ecd79000e00bdccd015964b5df11c5cf7c23a07953a3e8f8673e62190c392342b0c86ee780e2ebb7fcc28d3876d9976207bf91de0f86c05315899597b98adb9fd49eb25d1df212bce5b9e6ae6ec82e948979eb039982bfa19231fa10b67ffa352eee4449eebc30da6f42aa11c883dd37768978d3956ee0d8d07e8c9df8977446d626fffc03de8a338e8af76a75807dd769c5d51328a3df6a853ef6419315cc8871534143332b84de8a660890a30323c65f1ff6d2503804d3eb7c01ee42d23e3cc13f50c0bc4f4d40e6220913c57075ab0389b743f60131a5682c592407cd915bd51bc2371352bf466b2518df26a783da2dbe3c27437b1d564482b3306b4464b868de0a3608b0bf401ac35536160743a185e08f4445317f817529696d95e131c2055cdaa7b6141b6bc77ebd2fcfdf74c2981e4c1cb22762ff7a5b6ff82472d9664e38cb011dc5ab9fe64b6da096396796f201a357311fec13f3831f8903ca21abefa8519910ab7d95bd7402811faf12f93650e849eb331e73d24098bbd26f6523f46a7a1dde41d72bf8d70dbd717ce6af0dd22b0b5d6d32b2e9c314684db62504a315cc02e2901693b44ffc62352939ae804e1721d84efa0ea4781713c82f7b17e7c095e79e8d40541ed8698d4af4271bbeb9e976294b74930d93603e1644ac158709a31fd9c57577d500c8931f8702e90016f55f03cb658a1e6165e4c6fd56f7701e487eb6db89aeabe32369119cd417d20f595f11eb519bb8787df5e17f9ac35d87f1971c7e5ba7978a3c44ab7fe6fc30a5d76c3f848906b7cebcb81628b60d61b0cd8daa7dd62e6e9d359a6d8110ff2c3f302a802c7b93448390192f948f7fb708c15e7f0d2afa6190438b2a40250e51169f9bd64c27faf2097325384192039e39977eb6d52f321273b4a0c04a2d5c0de20b295c5266c75767a76f9e16901319b9aca99fec6ebf7635e06f53f4d46d4eed6e9a2d783deb29c7bec98f8a7d9e77a08bc4fcd54c9f21fde92f3830d69a1c59a0159dc4b6a874341067f2f46b8423f26d23ca18fa209031435ffe5d64352c03f4b1acbc059da22eafd525ee5a1628f56da99a9c83a81aa22f84a865592961c9c38691fb9f112dbd9b354fbd478863010ee74c035db5de0b55800503a99f4d8ac8648f80c03196475537779c7314cf0cc806f40c61e877c6497f9f493b46ca7379ec55c99e89636a3e7265260b0b77395ee04ccdef5d8768b995d84bf492d84bf492d84bf492d848f492d848acb779a210f64dac53c83b956795eb2627c5f7b926e81b750a0aa59f687f424cf5317cd09c1c15dfc7bf6302acb7e7f9400736c78d75d0dc875c2d28b65deff7e1cf7e2e60b8716e719073e7ee6307bad9fe0235c9a58e4f45eff935a07463f98bfa15929ffa97c50c90867f9841307927e911e3941a5ef4af36b34ce06b3a429932202652cfadfef370832ca7b5d62255b25051032dc8c07523664c000a3a43cad7906a61e4dab3047018146a3fddd07f3ade063e94b1654518eb7fdf8f758435a5610cb29a4df61973077d3eb2801a19fc35042d1666565239f18c4e195d73680ff018974ba8ace4fa395d134c7f9cb747b7544773f60213b3f7e3d152c470986840a5eb6dec37e60a244d4014729984c2491abdaf4e509c0a590112d3a69bca963464f1a9efb5eb393fc237396c71f996b569f36b4e5a485a8047809d95a8d93355dcd9b43f7b4ccf6f342d1759d448c7a839566aafc9849f5c8b80abb99271511686e068713fdc213b424d4c5680bdc0089ebd3d298e4933b2d6b92ed7bf6663e3078291c2accf64700a7f3f1e3d2bdc4ab023601694158ef7eb5b63f785388b7b3f542edf819e8a50f9e0ef555c02fc0cab3d01ab4ed0e70eab052935a9b60be4040b0435595a6a9697b99b0057c2e5e0c11da07a856fbe234b2b6c11485f2395440b28a3690caa76309938c9c2eb033915d7bfeca99018705617a87986fd526d4da02157d6f54b140ed9332822206fc6832e5cfa4d0bb2548d311da595a2fb124b1e80ff13a037679d910cb3270a038205d4634f9ec8878601dd081c248a74aa2df7a33145ab280480040b653fa4f48814541487848985eed16aca7b1c61c2f708e0490b51db5f09604f444660d999fa6bf2c0845eeb017cde83eb3663bec8d40debfab26b52f5fb6ca73876b22b8dc5bdbe33bf6507c6d24d1c232150b65da69766666d5b74d38778e6db8ecf34e7b7a492512c0d4fb27af182a31d30ef65419c7108da66bd42b7ee0b000cb4e2b234e4ba9e66d1be861c72e80cd9719153652b6f5614c7186603b3d61a65b6929d94ac62b036d003824d0fed1274e4e474d8719a01859d574f4887c8f7600270564ca427d348ac5bfdbf1b937fa1a7216e6f16e1dd841db708c9c58f2d98ef77955ca41bf2eb09af6a7ae0a718730b9dfd9bc2d03937820d7b1f6ad20fe21f008e5ed9956246aca42d78383ee067cbdd8a6070284a7d59fb9b22add40f231b61fa9152dc194d6c2ba679034744b7abcce04da180a1caf806c049fa0c91dea5290e9b2ac0254bd321835f9b9c1db77302359df4d07274b9528f49527c56ec42e9d8474a7d20be53d0cae02c7b3287a159043e4554287201bdf5439ba0252ed0cdc7fe3ecc965a6d88825b452887529315cd1cbc9e246d752b655e8877d4b90e2a1f4450f8859d03852e10d8a5a34ac55bf4b365b155af279610488665df3f8486c9d79a74cefcd7dd45105cb045dcb7f5b06e3caeb06761610a548849da953c6ff47a52001234d6c04c170a1b5ff962b06713aeb68c26d0cf0c275e3d803d35e495d2b48c34d5b802cebc3859686480e824ef4398f490998843312f96ccd858078cae8e3e859acc013e3941172fe615761c4fb26b32a34dc78da5f13d2146f5a4e073e588f7732e21f0820aa05358816a82b100fb489182b3bb450e0b2390eb8c2fe9cccf8992b1fd89a5098ad5961f11f16b5298f81bac6e0bf2719dedac559f0ff9668b225b521a58f40a934c853912bff562671b9cb70d6d4fd0bf1077616662cea21760ede8168b2019ab77b1b6d123cdcb4217db9a0193b7a08e84a190c572423217976515e015eecc9fa2bc358d9e3954480aab0a750c9749c51374cd042d66a6c6360b9dd698204781a820293b80bd95306441669429c4c976333b581b7c8a00d836cf54d1299fe225c6cc4a5c349ef2d4196aac44f2a319f2cd0494b6b025596c53e28ba0de365dd7448a5efd290b7045d8007e4f865ace65edd791235f68372fe5f203988cba25671109b9d5fbcfcab853d420b80a692e176856d63ed69b596c2aa0ded7f60c60cc6fb5e2ed2f8a5ee8962f8014004640555a2710f7d2318c35f392590bea7972065e0674371ac81822a95e7d224caf90cf80712ccffcceb0b5b7206833cb452b2c118d533e5ee797cd8e1d1440c62b133e55df344c1e24daadce881d3735934f35c0a99a050aa5199c05b991cf2c5ac37511848eb804d085f4623ac256dbe3c977d5391404d61d99ad07f41c31e3fbbac1452e4da2e5904971e5bc590754af7e8797d2263749d4245c803660a9725bf201a657e184e0325e24d787af6d933ba16e917174bc1312b07df86d5acf037d3f4e918169696f958f6ca0abb49dad5c2b95a628e3fbcf99235b4b06470ed890fe8b9be5051214775580b0cee6a5757ed9169a9aa72ab51c6885355a267df8d682bec822a9cad1eca6405e313590469d4fb0efdcd710c2e2bd6e13906c7b4c60b019f9191175d6e0c41be7e509b45db0c325bcfa02b38405b8c6659df26e7ceeef533a6c20f56a0dd3035545c4a754b371072ba1124f3030dbd5e169748dd6e5e6afb846edd73c315108a3575d3b79235ccc0dc32fd4527a39278d240b653eca55e6e4a281a7bddec8fbb0a591b595b5300c097d8b73b9b8781ba602f79dd182eacded257f46f3c526c85c071ff82908d6b886b7fa33d5f5b558c8d46971753df8bd67204cf6069adee61045cd2dcb37a0518b2abfbc26e0c2e6d1c7fa7bd27d1a21c4e1bc0aa9d887d7cf5b0ad93b07da229baab0892b879b5ceacbec0f1509480a68193edf79e67410d675bd5321b0e2d50896ad342246ccf37946dabb08398dfa6ff3e0343295e02d11a57252fde13bd7de745a4bd042cbd8ecc1b9195b7ae69a1533b077ff168353289b8aafca1232d0a336791b6b5912aeff631f882bf12ada3d35847e710ca88282748a74b9bde6048381fdef95d6f44a2444c6bfd1f04bf3d8790b4982df8d21bd0d0c30939741d4ec9d65f30ef0d9260a3018b33e1076819ecadac4baed20cedc687337d1ad3538dd7bb23f9fa15d31f24f633c7ddd52787e200bb8a995395ff0f2cfa18e698b9573c79d15a0204fdc458098191827d9511f8f25cc3d708e6d0647dd56ea6b4925316999eb14f0d1e6eb8a3d6c4d307dd0b9a34b5fd80a76dad83f9ac1d9808554a7524da645f516653f6e1c366e281a3945db89e839ad3e70a2f21f6928674c54eae507dc3560296cd1782da0135f615320d5d3a411295df7f7bf95e2fe2d8f55ead3c30e0fd4b9b9e4c60e08c41eac92d11a9a08457d79bd9863b8bbdfd034139615da54908198d3e10f98260af71137aaaef18bfdefd516d92142d82310bc66c4214fd6adbc571814ab266e1b699d50f0d141d59554833b3f872e82bb43aabb62c628f38f8fdb114809eaa617b1b786952e11f172590539d65e0124000d7e7290d3c6188003c3bce0567f98038181d77cc0121639fc4a3fada0a526f0913f47880454819d288a803297120118148a6334981340291cc12d9400a5a0e2dec3ff3dd25cc2c58ec23394c665396a0bbbc215f36903618b2102cd8abd8a61d5cd4b9ee6c96dee3570602afe76d4540536d41394cb76f32e311c82cebdf2f6e95d5defacc1c48af11d3e8e8367733ca3c3c944ed5816194955422a5d039e17cb9a2e621f008041d19e977a96a2e945e98d34c06d96674b084a95a3b1697e19891145cc707a503ebb07b0604b8e53716e273e8526741b5312b62fd1f712d180b0b21328b281ec4a2b08b299ad6244f076a9d1e7a108d02b2b1948fdc0442a859f726c24da3dd460bb6c8d3277223391a0f86a6dfa4afa10630a557ebbb19cf6174c3e45c9a213d2167d067d22fd7b76f6218293235cdde9c3c1255cc1396dad77c70900e0f6dbaa90a327a8eef3503a32a2302b527b37d68fe614ed12f0d0ee681889bdcc1217169f45d8e5266371a701fc9e9f0fb0f84d0f93e5b8deb29122f265945ce3e4e801bfd51a4b1e3aa8cf19d24608f8d09ba87aab74fd59b85a275ee75ca9424c174a9ecd8b9fa3062edbca534a3c7dfb2508a7c39c0ab10cc5f2614fa5ca3805dff6b4c766db20a404a8e9405185d02011f9a501459745fec4c96151c6231f5652c352a0a337439506d0f0bace90610125484a2fcc1290997b9c147195696d75f97f23043cb6059f3b36c7b3e752ff1f1dea1a4d19e3e3d5da0f23679080d521e28fc1639958f5bec45570c1baaeedd680719eea38569428d650022c85e57c6c4b4786790e43bbbe97548d7b6c599c3a71f126b453cded3aa82134294f135a00c4a99de61fb64421df643af9051b2c334b5f28c0346473910edad57cd616c20009cb503402641757d6c3ff986d543627d28aebac39765be80f7e362112666d1467950fe39c9e63625625f89e1a041e64d14bc3e1200b301bb63195b824586479246eee5b59771cef697b6647eb7be67530d9c8aea2843d631e393c6e613b0b385fa47a2f2beaf42cc706d94c4a626ad2608727c502c613ab9605f78bb4dbdd89964d709d737c45283049ee05a32b16d3214fa4825796c10a337d82525195ee339e0d1de2441d0e487406825b1b68172eaf181a6ed5afb013dac04c94721151d6757c4b3e2695fdea8e0edd6d17111963659702429c8212bc9400195e4ab0a68184b3ee24702992dd23a8961f61330a76e74e507636386bcd7d1c64966d7eb14d87d696c0a51ed0b5171942acabea58a44c0ea3b77080c7149a935e85ded3603d3797c41c7337d924a0136525ee74e52806effdced88487d08ab833699e57f2e93d732f004bd2795837cb0aced3f83b7323f04a7911e597e3df9cfb8b5976782cd08a929d0aa5da7e904680d7a603a7ac81131082ab618346fc36899485edf1b2c56f220b1974f0f951d030c42dc7e4667f53c09adb87998b716ec11097a564c29c19213bce4dd6b52dbd13ade55c92e90cce1b82167b0cd457aa10e42b24e8c1d2f27eb8239853aab35f7dfc1afaf15eed69b8e6ecc8afacd2c269833448409e31c9675d8e853f1212a777049c0f604dfe123ea262e99f307093e2440359bd7bdb01eca668ef59a15936db434837dbfff486dc8898c64d42e9e433f5b4714d71dc3f12fd1bee4a383af7ebec36b1e1a9795dbcbacf4da51055a3a0cc56429f0702431757b53a3c7dd9f743221d3b40cc10db15b09c56bd091c0bf1dbc7892074577e677ca306e807d643311287a37add243dc55e72579f19a89068466c9cea14f4450b61a5de8c9cd534c43adba4c1f5ad461999269e7921b65b9245fdea9746e6e24eec7dfa61d0454850b5097bcacb607878fa29c90d137a788adf254a5ca8ce08e41e09efd339c36a96e6f2d29ddcc5f0af6003e27288370667b8946db1bca8e2875a88cfb52c32b6f132dc4499d42f90aa305b46f7f9844f3dfa9e938a904970076170e49f33c3aa53200dac6f5e33f1d0423e12a564e8b0361a70eaf1918b28286878209c1d460b16a03e12ada1a469b42bb28f3f9c8a98d3bcdbed60b0c92df40fa6689df77567368713bb59412dfd80355007a05607281c868119e132b15eb80c3420b4721d805aa7d055b17c19cee3191483f8b45492b0c9d84ed0da4bd332a6a651fefec40913bf7a027c69837943e9239c73ba60f2f320927651d1d7adc747b5f504031492fa6fb1b048c5f09b69254039a552b4a9200780421066a07131f744d31be84d49b61536efa39e8dc50555d22d45e374ecbc079694a25416246fb7c8847c8b472b1ca664f1e81e8064a4c4be1f9083d5175eab7080c3b6c0c47068a5b5bde56c867fe1950cfecfa0051c96ae432ec54e8493b3652575f6ee583381a2d61c99e923909ce1ab09654704d2857f6fba897082c04c73715b5cb963b111077da2426882c4382e1b938a34048ceb34ede7f186218405fa51614cbd51aca50766ca9c77a70b4c684b10bb4122a94c3dbbb2b8c2c07da889796185adcbed25d3d7aa1a562b78abaa1638396560cbdf0494a096954208a0d82d2f6ce7c0b3c8fbe03258e424ab8c7f7af882b4401118902654323b77696549feab12d5a7521d02318056c4005733f4d6fb654e80283e7f7cd5deaccd8170492cde9ae1591d24bc1df940bc84efedb1c9efe43343ed45ac7e82c7781fb1d4dd4d32fb744c2aa2400d240f77eb7c90adf48f53a8f0921ed129192dcffbc82300b6b89ecf281975b4ef728a1fe147eb2d61b88bddbe2b2dbcab5f2436282535507c512153ae7732c9819cdbde61932d6f4bdb2d999cb351beeb83ec99e3bef2c1670a478960a604011e9c805ef8890777741755a3c119e9427b1233ab1b3148caecb9e93bf4ac807739b46e6677f98ca82e986b2a8b742268cc8e3dac739c1f0e5dcc8c13b6d6c4ad1c53b9a9926a9069d9e5d4182c5206c96ca07fad86781daf7dad8a3eee02232d149dc32b6f179895748288f049917816571df3dade30295abd77fb57514859ccb051a4486853b0b498967875d9c02de950043b441f960a6c4d3b7a294afb19df2ba21745f04f68605fe63fa69705f753af0f4caf0b4c294420052887a3070b41a50df70b789ab8b1cbff182796deccbf1cd02fa758207a0ee9c8eb87f003821eff9321a34c7b69dec7412580194a2c3bcf32249bf4d6b20542934465707af7726bb12684a9ac8d703b1166aaa8c1e807be8eff872e423e164fbb5934eeb8d788fd831e1cd89bb512dcc7e983bbcac49e4353b0490f6417d4aa60f9037cfb4ec8e0c05100486fc6f5eb9ecc38e0cd9befb77761ede17a1866274fc9991823faf89895694b25387a186a5819dfffcd6932faa847d6639d215303cced0c70c0177024360492ade5cd76ddaa36a2e26be95e632a96f4d02b5d49b181b3282907c9b81b438e4d6f19d10e113943e93674741946fce781fb3ae8388ad8065e7d0f424479c10ba31c5f306e18c74187094006e9bf9bd78d33dc95a145aaa38717cfe1dc8fa70ff56316100f12fbae89a25569fbc58d5afa79a4f1b7360d27480fcee2af6a36814f4b3fc2d46fa562034993b48046776120ccff62727b7cfda92db4cc6d938131638d14ee6ba0cdd478df1bdae619aaf0c1522bc3aa8aebd9ec11000fbe4199a609eeb54de8a1f47f8cde409c67d0fb50f5bb1144bee7650835f1325614696fa9a5cb474407b50cac8376fa8303a75ea4d7be4e79b44b84a41cbb648ae013d8328ebe0365a5e8f139f2854e50b6cbccf6bbdabd85d12edc6fcf27a5cfb4082918fcfbca418a2e3b4026c52b59443b280491493f13dbab8976b90a946a4168f6a80a845f4a22f4f2f6d5c1dc678438aa9b713d086e873d9ddba1dd4c5c4624d9b32d9ae94a85c0e315b5c02667a6494267c23b6ca30ad4e45d5738fa3776f0ea20f3a6b73646ecb7f0e7fe99e6d413971dd452fac1f7201a1a0fb0663ed23bf9bdd522e50cdbb2b2a403a9d53a74f48edb74d9e5e15d6a90c6f23c423ae31181089dc50bb8aaa23c1023b6ca288457d7bad385419b8aef10788b082de539e6ee19824c0718afd402f3264d882581412daf8d8d97f202463b57ce740331955895c200b3d48c08aa4d218e7911487fb9d59a15d4582c0982fe2239e0ebd3bc847f1cdb9b0a1e79b48395d65073ed7721a23688fd95047799fc9f25cd35092a279f75a7f0aab6ab7a2ec14a080081f502ad769f09e39fd132da16c859d826b9a5a63593467ee11a8c31bc74de0c42241dd0b4920192b8ae77b4ef40e966764010d2e5b1a5517218275111b68a25bcb8ca41aa56f7556c6b1335e20b733532280af281f6b40d1ae108241622ebb1ab5c737ecc1c106651cc932497a63277419917a214b991428a7610e0d504238a925404808688218e7c573a9797084063575cb050135947c4411a24d80510ae25b50db530d611c903d95db03511d47fe5fdf08629cfc0cabb8ffe23e58f6a1d3e5e81523752dda6d72b7c5c7a512c316e7f2e9b107c12e3e8dc29f71ad296013a2bc727c6619f80b0fe56aea2f093cf402882baa329eb31f083fa58596191c51cbde4eb715258b4f6087bf31c24b1e4a1c8733ef6d18d85812fe8a994e819a0f2654eb896ec511c107a86ec45bfc27be13ed61485b3040d4eeeeeb7ce647e7366f40cf3a0f5648e3c9aa9a72cf66162dd736a5a3981686b340bfdb5b5587a3fa3b7eaa892bc6070c106eb6de638a88c92cedad0a73da0c5e2452699791c168b2eba0dd872c5625ae780c43f01a2ff856467d0be8d80cc2018c3be1d9501c6eaf0b6f48c584287c75d96cebcd0e1268c41c5eede4db9190f97ee9566258e79127bee5f31d00367fe37c17d86f701e46a79289cd9f4033b47b9a66599a523761421f38b537b9bcbe48d4fb3d789fa4cff092927b2b1aa3ac0257d10992c2622c2047362e9da7ce9068192cb3adb474e0ba33cf488ef4cdcee317aa5dfe35450c49fbad999b4a84ed93968240b1025040a2a6d0917889d48b52adb06efa01ad69fd05093b97812c7084abb40d4b8afa2c65d94c3d4bc5cc58bedd9d9e4a5e66643c918289ef40b5200fa37da9c860e39a9b97643e4c34486b620783707a165e6355b76c5a4fe047cbaa99ae6ef93d055cddc6072857bea723efc5f1de787f20286397976288eaae37eb5860ec76b34f573de1c2c956a9cc8a420c76abb149fc78e5c39aac83227b4214ebcbb12c2dfe022e3f0a526a5a4224a41e5a47b8288af6104aa0a4f58dd9de8607c34e651d544f7acfaf24f5054e63fc1b902424b2884960b2b9bd81ab5782b2324f658e306a807ad4a06f930cefe235ba5c9e1b8d1d7731c6194d1c608e0fa3e5cb87bd311421a2492498178fc52a55e644f1746c184a905f46c38d816522731a9f138a0128ae928ba76e5c2417826d7979903635cc03c0e82b6e9f58c782d6e08c4b95ac2ffe88f4eb60623cc18f44ceceb38ac4baae78a608c8ef3bfa9937f37dd51e53d3a8317c4415699316162b3c212fccf3839925d53189dfe989e4439981a3dba8fd632aa69f2f85212a8dfe68dc7394bda1a8f38104a6d344df6e686d6bc9014c32e28556f1b55ddace83f2710bc1354b39dcd39973197d662a64dce8f9b36967083b648b6a6a11dd68f253f1f59202cca7d825d68c6364699653628500966a961ef2ac372d3c350b6600d20c517e86aa6674be6f621a0f60d91daa6d056e29649a35bf7127fb159fe4919dbe7c0177f5d40672188e49840bd2e9c4921ea2c0b021c74d3faf8224708060c99a0402f871e47ab52650630abf92dd5f47d0bf0a958b29ba96d31383d5527d92a976ceaec04183ae100fde0e4ee41fcd612ba7120387f3f1a1d869d5f020fed8590eb7fd8b53dff1996539b212405062d703db6cebf85ebc1930125cd8be87bd56fce4651ba44fd474e4090d6e788bf77eeb9754486c91ee18883b1a9f16c29a1e421351ea36f3059d1793084babece78d9bf60e44c27081a9339b506eb5c7d7bb9a8c761aea4d6f2608fd41ba923f3ac53415afbcdce8cd3d7f6d740428c6ed19e914873de8df8ac6ae75849eb985f7e80ae140647685362a71360d28aa54b517ecb225df77cd0b1f4cb6b9e954dda67fbc8c3d5803caef9c176ed8208aa5570f0d7b8c008ac7a8575984ac744e1046773c382f4cfbf0cf5aa1ae94af33ee40c1ef8b8330edcc105207fda6dfa89bd596a9c03dc89da2c9307014c51dd8bcab1ded92ff32c7bd8c3b4abb76c325fb115c1eab050359925281e26ade9b4a3bf6b21a272ca70eeac4f364bf28154ffc78f7b94fe067557ba66c48c2cedb648982abb536cef536776c865e3da0056ce324503307b21fce119a76580b5f3bc8c88266b927d949f62252dfb1298994c20af0800f52ce390b6495cdd2f37ee15bc3adb0f8a3ac0813f6ef0576ce369a87c371123f98b44688524a8edfd4a9bc9c3a1c49430a0254457d8743f26d81ebd0180094911fe0993532d01e0a234cfdc1512be8441e8089f2b0dd16abcc0dc7831167b3441207d476974bdd65cfa19942e21211c7ca29abd8b2dc4ab286ae667b00d4f56aca78550938171e48365cef3a119b5f8ec9a287cd47c836da0eb6b35af910a0ffbfd2d63aff9d5bfaa86a53318586e2f7fe309ac6247d1e33e7ad435046acc59fceecbfe9cf2866937be0076d998015048b32c5d7419fe101a77f82579d26cc1fac2aaa1fb8c3d2ae3a89fdadf4a88b38f1715b2f0c62f32a16dc1bb1419e86b69939dff1fb57213e9e52befe1ff06d7d35df40b6bf78d147869079acf08997ea026aaec4105872df9463eacb03d9ab6f7b18fcca2546b4dcf9a0fc53d06e49628fb02eed5a4b8c89854b96e193c74b7f51609bfceba6e5ba9b831803fb09be9e0403dc63e2f13d1424e0b90a06db76bc721049bb448a285a7024c91a0de095184143b07f7519f64be3dd243e5a636a05332df286e60b9b69a205194e26f8ca2822d6969446592bda41afef14e8af04ef22476efb8409c57e74e75d56e8fcead8f6832b876025577742d8dfbb740f87213692c7cd6a99b40eaf4cdfabca2cf3653325a4bb55af714b35b3d68bf3d448e0ea2d19743145e308b0a45e981805c39034990c7fa26ee467dbc951dc4981f46d02d91984126d891841124b5dd0962490d5847d1c4200a6181e1b434af14b2f51d98fdab1439622dd676027c7cbeecb49249929d64a6c1c50577630cff319a847dcc35d55c610fa82831a7da06e09386f5c2c7161164672cd4a929ed6b1eb1a34f97d8a75804b46a1d517e135f569051c9f0a8ce3082c529be5dd041ec842b9a82d0c8ede48d0cd65b85500548545e08dda3f9a16343fa72bbc7bcb04d78bfc2edfce4ed5d204d0d2215f12f73db64ad3fb4cb26768d116804fdc2f7e17bdba472d028fb29b58606e6bf4c94df88d122c524129bb9668b9920377286ed9d70ee6fc08d997f6f4685bf436761b941e51cc35889541df3f78072a3e0602b8fc41368db531825da0573d143618ff25c3402dd4858c688043c91b019b63d3f8a086e64c45f68bad39d835814523eb2af888e8a685aad0149a05b7f751915bc59d55027850032418fc7cd31c2d0ad56d855c688dd4bb96a6f7591424881d5744b719b06f941d4be911d10141b58fe083846f19177acf22605075ee7eb1ca9fbb3615a1d09dc33a7dc7337da30e174a90b63e8f4cc9ba4ae5c80e2833b3d3c067f360ecefcf7d49e0fc20b9dec9925c362b5cc79e62249dbc440e3e78d1ed7aa3e8ad005ef106bb149566d925e048cba59575519cac986d6d06d363bd76ced55132859ad8d9fe9495ddca23e82d5413f661672c31ed6796193b064603b9b62dd0cec2fcd97cfecd2114e75466e39ea76923b4243fa0d2af52b4acbc2116e60c5e9a85ea751eb5c31e700249473bb518b0146a23f28915fd88818010b5efbe3971b48838da57f1f664a1173b0b0a16c564aeb34ba3f39a4d3a261206c0a947d31c595ddaf7f350cd7fec2823e2646261a0b87ba9157e1a42d5c6be6fe450a31eaab2cbeadeae8a06bb687624ab20e2f4a24950e4fc3877123154abcf02a6c6261467d6d950e67e1282c097ce163814911760702f3b80fd0432f376732eec649c7d2304f4460f6fd386201c95829e55b209e946dc39d5c38021f489c2022fbe4fa50f3cef6a0125eb7faaa5691134745afdfed270b9c071731e870c614b14b890f4ce99c2de5d7e8e6240cfb45f01720156236806f6118f03a4b7807dfd6b4e694f049f21e1d84b1029dd44090f81a5db49d05d75dd3a2b596fa51b20b4d0ca7b30c88e4871898dd36889f9510c7e2640cba248263d738f684bcab6d21b1964a9612d8170aa32f822b6685a8bda67f3d0809ef7413830b530c420820522ecc5288548c454043af28c106a600ab44e5a91cab842c8928f74b9e076a5df20ad35c965e740b5e8fd870d790556b5344db71087ceff63e12ba0c0496c699b4101af65a54abeacb9ba6c0eaae4be50137f5dec61599d460adc9b910fa9e882e7e3ffc9df74ad0e1edc353c4233dae0f421f170f0c586d93e073590a3d3c20c05609632fc120ba0d98ca1ba2b9165ef7e47af3cdec4cf29750ec145200284cbfbfc5985d69ff5ab18ace2fe65fe91a13fceba554a4fdfc645156f4fad1f180e5f80c1b365d960d0dba31dc07ad8d7d6e401a21e9fa5c9912918e375c9f30d08c0c251675b2d0d77408d422c9e302603e40f1370243fef2fc1f6959d1cc6a99100349d8fe5b0c799a3203f851ef6b2c90fb769ed3008e15ee59faa9d964e4629698c5b80a0106393641c145b1ea0f218544e243d6abd2cfbd82f0407107b48e4206452f034ae58ae2f73157016b4142202144235f1756155e848df3057080803672d945f3e05ec15f8aab9f73d647e9120dac1b0352109de7c18190a91d66c560c479f9928a2a9cffdc9712c4ac84b895b1a2797193e9179d28ea89d5fbb4fba5275c186e1a9d4185c6eaea3385548c6fa7242b4be4aa4b5421f36cf90ddd5762e7e7940626ecaa4aa008b83731a3820e959731e1bddf49a63e4b9e4148754e1b8f2a757eff4441c7dc51af76ac4a13a03d2abf1ce27bed48272c593d20128a512ca7322357f98b1cec9d963e6d2151f20048408845298c88b55c8663a6e4d376f46156d452a2827b13f677988d5cf593f00e330e65e141ed66f2516d5cd7ab63ad35a0c419b6d48debcf3451c2f90ab1202e39ce2f8f9b8ba0d49858f7c72b0bae38837cce58b99c327d99c62842421d66bd6cd942c3690e73dbae58525ca0c37819223e4739e187e03c00290fb9315da0463df0cecb50a61ef4b293910e861d814d3d889513a562a9c0e3662dfbedfcf6cf3021128fbe9e657ebd43b6e2048cd52baf761b514e58f5c9c3e6627b42709eac17901962a0596aa3f7ef8e63ef3bbc204afba00283d26fd7fd88e4e635186b11c1365dee91bfcb3ebe722e6dc8883a8064d31a423fa04348a30fac4ee4c87dd690ce88a7c744a7bdc253708fea111c1b21bd2c6e0a370136d4a69a07570d04592a33a526cd03c5d01915398479d84e47a8fb6b5ce8ac346996b3b9c8674e831e24ff61d2e13971638ce62423f716779fffc68669547d0ca8c3b12e72941cdfc4000f48d56027a11dc782fbd7e9e309a2cfcbadfb5333110f884546c61df9c26c48c48eb582778857e0730898861d76aab7247093e7a7e2f118417800b7b6e179e155e5fc462527c3790b09e1aa058b70151fd05c539e70670947746b0c286154ce127b20f82e904839b9d1e6397b67be85b414593cdf9b6ad79769e7bd453d1799c53903214fc0024293126925b3c77bb35e2199a949a842f783dbd24903d974d8c00bf02e1d1d1521cee6f0d65db2502ca7713d7af5c493d50d1c7e15fdff6c1f25c0eb0c97b3dedc8882044c13e192b306a1c0e89ae4b0075b8eaa302aa518bb7bc63ed40023403504989f7598900f601d0520d22b476faa4979f437ed42feb7da7dfb3132eb8a7080c80258fe6e2ee5ce4416225be911694f50e65da425f19be0bec7ac2bdb07239eed8d6c5f847a4687bf29c4e67ad39a9e1a30dce81b7dd8a52b3c304fd4b69a23e0950493d2ec56a28f368dec68c396e001401e8afc4851a8f9c43770e288fc76893ff2bf137f728fcc19e8f57103985f1d765482d6afdaa97c63bf89bff9a420474a416340785fca3c295b37cfe8b0dbba8476ea57a8bbd13950e36cf26449eef708d5f4cea2c5434a3c95841c80c06fa2eb155116993402e89063b461cb38ad33b034769d07330566e96f479f07313dfc45649a43775808fe4589555b7c1113fb3a52ee3ab183a3853f527fbfb25c5fe7241c0a5718ffd57b7faae23f34b68fbaa83a563c7b390bcf75526a5990d5f256740d1f240f67d869bbf4c49d3d32f6185bd78884fae8abf111d71ed58af80931e20024b631ff4c2d1bc3693e64ecd5a61040a4ce0e08b17861485de11ec9397f8987136c1b1c9a2053c770e0e89fb80e19a2805f755cea478a8f615e6d87b8bfafe4253ef1d97a98484675d7f91c486d552b043d9d18366bf4f6c1997e62fc5f16adc81442c4761b02e4b30c6b1a666bac95e9a7dbe5949ed1f7940db7c0106aa84aaf4d9aa468a66283c21d5ef27b8d7b820ff31fa9ecd8e695ef190d157ef300f33570d5d1e28b40daa01f0849000247e17740798eaf31919152bd3f803000ada6dd0143568922be58f80dbeee172849feab3df037cf5b488fff4fdbd933e8abe8da699f095994b181cb241fc7f7def26464e30fb108f1527b28724416d77c4f4810462d20d8ea0c29932587213fe11dfdb7cdaaf19da88c01d09ea0126596717a5efe957ef12a8845996e6b8a898d8307f0b8bce1f291288ece59cdf52008f3069e09165739ad038b1c3ed507eee9b6c928773e25c6a360b88afd920b8b5ea04c551affd028725f32e6a604850aa90329f2d822c5c099cdf123d5732187b418d6ce0601eaf52ebfcc684e892885ed62bd34b88011894276cd1cb207c33df81b3b8c63ae13447d76a4b74ccbbecabf12f6da73e2757f3e2600765f93c9b562c893a53030c6aae8e9d3bec1e62574827a57d60d04d44867db3852bc66ffc93f4078787c6bc0af3408240b80211018776677daae53a5f7192b4e792e82c6926b9e8b723496f0182e31d7ccf1e56045a137ea5aadfbee77f1c5e2d7b974411c6f1fc060c6d17cc39d8d296d5886cb977b9717ffdc993fe7c24f7e1c1e04b7651a545c1b4afc78b1123669154941ae24da6bc2dbd12a353244f70e9e2fa45af36d4ef97a10efad73843ecfcf40c1c892e945715d377fe7f5c1783100f8ef012cbef55f9168677efef8433130598e41c00c0c1f472091bd71a7570a7767e3b245c7e9bd1f52006642a7f058fbcf99e3c523db1be688ec3c2ebfa16e999b849d398cfd6ae250548a0fee954aae48101a04a1b823add2e5c5421f0e07c0baa97e4682621332ad1395ed72ddb8e5ba17bde88ba353678d784585811a1886a20629d49281ba72cf90a0d382db743ad24d6a06d283c169b0459b8269427c0b4366af36864640073bf2d59764e36dfd39f9b3ddb5f08561340e7a0fff5840c02b918f548204a98de6318d1f75e8fe8aec5de407e8f76b3e9282dce77e219c560e0582cba190471db4e0461f9afc5b583d5f5c44f5d31a374f344e9a506f3a3f5b2684758759860ec39643c21f9ad1e695909cba72b9b932cc0a3bf4f3c195b62745fc7fa3fb582121acf82476818306fb10e7605847c08239d9ab6d24d757c9f1c47cc42d66f57da04db576e44ba3aea60c2247511497c7a62af952109efd6d8d1b0a9d4be5b40bb1af4c05732fd57c8a59d5511a7b0f9f39a744f42f6c661d64412c71ef19935d551c3459d4d88443baa8cbc65c69afe304c8196e39dac86225bc3ce416ca9e4e6a83fd7c10e15d57ab23436cdb6de419e657805b926afcc1a576ffe2bcb1fa58b796151967a4122f5cd0e475f734b477638171f3a0fa4296f67bac4532ed78107f254a596091a9c1448d2a3e3073e20c8277aba458b0825f744008f012a72aa27fa04d2d1e42d7462399ea57804dfe9301da2e8a78199f258e8d2e4660421427b692258e722fac55f3b27f5699a9ec411d32a9b29555c5d842bcd72536fd6cbbadb08163559d0433a70cd18e14139340eb5423c7ba016ff226d02c1a4a320bbf6d034206cf77b7fb7b71240d1afe322ceaf914e083f188d86e0e2682c0b2200223a4c5a26a5f713b8d79f56eddd0574538020952011779441c4e1598e1e574444a4b29ed7dca550ce71e9944718c48f3186101f121374e0e06967bdc7717b2a86928dbff6b77bff241529ac16b544a43314669b15289097a1c7a0a30770a54b5c25adddc45450dc087d27a239646df5c0b29f71b02d4978c216d11f8001f09680e0281de9da50969bb0b3afa25e879308fc45533a33f9913b9d39ce0916214da0f3747c67ae153b2f415361559364f67fb9f0a36ab447205b251434327c46ac4fc5e53dd82094196b6546655206fc8f9581593a8dc8f355a5a5484d95c8201a84ad5d00380a76a6a8d02fefacce3516bffbeffb7ffad2f17f864ca3778ea9ecaa9986f2662438bd1f3b0c78bb1f19090404c21f3201a4d8710244bb3939c9231afc2f13c5a70fe82bc9fcf60a2c5a27df8348ab568e36c7075eca641d04712009ae9a86a5b93e6a13980ae409a21db5d5cfa9168b6d49daea6c2b00550bca8f98e9e5efca561d878ce327313928abdf94d0848b428c997f29c0f1ff20d4248e94adfdc20b7f10ba99e86f52e33230b1fae5d9152b66a98da780d28d4fed4cf6f9c070e71450d363da69f83a31323b80c1a0fa2b3b2d24f0b0f7ed85697b3d848c10d1506e7e373a378d2960543a13a0bf5bd0b90dc6b17dc819f7b8447322ee15b0a20dcef26f458b0d81f2a49f601679faac50e81f0c69a6967393a586be60c130fd8c89e1c286902e9202f438bbb71e6213efae3fc32a4395e69f0009f3744c8fe1b8786467a857a1b5f1727473a66f0ea07fdcf205b746bde724e449d1890ec4cea6fc2650cf80e043f971d72991755d717950c86340fe781a25dbce3ca0510f457abac7661fc74a21f94662c7c6809f67fbee9977ad5e97e86e41917c52cecc3e7b35e79b1d9654f45383ee5f655cb38379f8508cc14b2e9ba41b600d8960b83ec83f46890195fb2704e3a7c19b0ef1a52ad6922c7610a5cc5f54c5370291bdf30443759bcac0336a251abb99d33e391b6ed395e50f64031055e5665ff72d79dc4dbcf603718ca5e49e475f48289aa9963355d5242a00ca7abefc07baa7878f36c7a45c26ff7133e9d5b0aaa803d1452a759713883bcee064390395c5413930e316b43a3bf8b348a85e460b6d968d8120f64e48626a0ce657b828d66f7744050617b2d8f6d169ce8f64b0b54704516a0e9c830a8a301b89188a677674d4bf7d41d8ca9b8ea31fc9b8ace6822de09bb11932b5e09a90a211f2d774d32cfe586535eaf0015804219041c5977cc6ced024591015cb82fdc518999e453997d82508e94d585c3381b1ea9c768853faacaafc2f2ac44a158f60db7a7f9098f4da04736d25e98898524959dcdaf7b0a06a63134edf8d9eb3d9172c9c4d8038764c75abf3f54204291e6bf20fd6c2ef32f2265695853c02a509b100de3be7eb6effa11d17bc0efa0ece5378af5dacfe9b35bfccce6e2d66657143566be7f509ca354d5092840cffbaa5a4ca43fd50dcb8040fbfe4e9bf9ce9ef390c20e7c83f9adcd3874c364b800adfab2f29cb9c3e11c1bb8f377e6431d9f16c8f3db770e1315ccfb7a59fb9ced74dc1592e70135b6d62d43803abe4996aa6631cc49b189c53d48453c39166fad44e1aa71d12b13cddec2b28842580ca0440b3c687754c8295dbf4c805df9ac01663a1a258bad3bd2466faa15e97c6c844fd908882b4154912113613126b6947a884683178782256d162aa0547efe9d7c62ff2deca93bff13f3e640b49332e15297067c084a30056d24952c7b7c0f8b109b839acb4f9248a04685c25e0d880027eea4aab422788dcc1c1e252f4d6f91646c04913721a5b0204654a84b08cdda38cc1b575c7c5f083ce37f5803255f1af7824fda7e670fbd3673006120e99b8f0a7768c843676f78b80b7d9adb02a55ca0615f246931a8db5bc6be28cc5be9d81fb2341864157537fbd07114e3d4e775a0848867ad1050b80511173ff0e94b05171bb295d469b48f6aecb328d690e09eb58fc8128e1b8a242f76604ae1fe219ac08e84c4c1f8f8f5a37ad318834ba765b4f7d9b2c7b2d0e87a78b8233873a0a29e1056c11a930acf38e8842687009a38ca7d87b780fd62aa0d2f566591133e70f8e4742bb57ce56ad4baca9b62d990c25a766d671c7096fb18e9ce72885838aecef99ef82403e9a8cda29d5b78dd227e2a1dfaa53eb9757734dba0832b7bcb07acbd7d2836fb62ea0ef7c66510e0a92c879d8b3d1c4b70c5a167e3097298a79d62892ad816e71e952264e4168c7d02f290b12f45d556cb83d50364489e17a31749bcf974ceba0f4920080594d705d9784e1c0426dad359a660a0743f8ee9e9501c1bf0c2391c8981147bd7b19063293f51d66504624179b13c2ebd2180ec375178ce74814c005221fcb47737dc2f56b21b10107822a3c4cba5bb8993a2ee98dfb5b3b1c1b9a636bc65794532552747c9dfa498323c0e719662118d54997758c6bf1fb5a35ce20cd5c3db8d137942b89892545b8ea99c4a0538f09ad433452bc8c83ac781ff4cd943e956f26a7f51f15e88381e1b1563040047f512950559e251af7c11c689d37c8bbb2ce1008136853307543b68a1502905a08114072a0bbaf83c6eb0a6e7cbcb416a9f52d2bbbfe3936c3dc8538744858cd617c043b2b48a215bc0c13195e8207f6b197497ae6d54ee1482c648a452e0ef193917fd5d41ab6386fb946db75b0dad65a87a8edd1359d0097f3cf05116fe748bf7b1ec3079c43b0349d719a8fae5adf75dd98a1c19df3a58cad53a9f275c34e4fea902877ffcf0511e7e6389f6f92de36ffc452147344d677d2daf478ffb5776c6bb81fb4115604d64820654eb0f4810f84f03681e1ecbbfbbde1ecf0adfa89ba4a145ffe910c0632bdd681659d675c7758953fab3aa10c2c06dc70d85aa7c181726d6da199d6c70aadfa110c26ea52d43b6d109d25ebc85aa90444d5b56a0389e5f05031f2213d6b5803ecf8b8f42ac3cf4852e8e88112c86442f69253bbeb4a16f0fcbb97ceabca5c5bee7c0da9c7b07c14db46375bc19e8e9d5d1e9a51d211c341d39c600e7a55b9d5a39b7e92d604a95d31fcb3c58f6ada41fdcec7421b7eb46b9f1890592082402cf232cb8a28b47eeb28d84e0d24d3aa5ffc1f337accda14156c92923348db93cb39984a99bcbd99d048a2bb03f2736c30bdb26e00baa42c25c786341be3e6448b99ad802e2f3abba964645c2a83e9953cfb76e2e41513fc5d187c0f91ad12a02d9b812d2ae95372a166b5725eb0530c1c4920a3e0898c735c936d3f204c6f8d4ad1c0081ac4c2c06b5e4d3a774cfb46eee4f96325d55b1c085671b189f143f5bdf4a975c0783544b46729da88421efdf5219aec0a2a223c8e7666db09a2b048099b7e76660a74e325522e9b0addabb1bfac68b0bbe4e2ba4b30a32b4ef699ee46917090b8e1e6ae784ffbdd0cef9704ba018844026ac782f654b9464a1d5375b3f3f5b29d91beeedf670655169e586ab8247058b28c009ef960bee6428226af9962d0118050842d34b52bab42440f9e7a851afe3b97adf15ca65444549cdfb3e05f3cc4a44b50bfb2774e4cd6a472e87b26785e0211b3346f688a34d62a506318e34bdb6876cabf8fdc898bf514523e52c9c457d2e5408d5fad8f9e09c00515bfebeafc456fd531e9519a2cd75c2236bae5549eae6f424f25a832524b0b0d7d90ce54a59c29166f4bd2416456b95aa7274421e98cccd2a5a7c64857254e083643d2fae85be2853b4c8c0686c636bd62aa507ceb88200dd612d4b992f2bc754633343181787b6af6a5dad45f08d774bae2ee8a34406bc1d00cfa5d0d5ac20beb744b9e02953c4fd6a776135bb1e36cd4cf63080414f2837b7a11a3600f4f671f1b71142148dd93af3740e05836f98ae762ecbfcdc540f6c179e2bf36014f8eb97593153eb49e24c8b4252c9e119776ebd54a550eda59478b0fb32b0a8a564ee44d7a9018413054e0884af0c59305c554d07998456b5b2a53f4db32336d2498a52e23cabd94a1f42231d5b1136f5463286d086263f6e9e031a470b0bce01008080e60e63280ba027b2dfb3e771170c4e07f957b908ee56ead8ac35d94deedd6d6f29a54c5206ce0cee0cab0c6fc3d6c0094a50f23182d139ad35a9697123853a7eba1c9211c05328d62ae9d567d19c44524a29392939c96dcec96c13b9289390b2d6cce5573d931ee328d346354f2046e1a18ecfb6975b8c2a4b051c64810b1f6edb6fce6d91e3388ee338aec618738c31d618b31c0db667517828bfd65aeb68e4218d85fdb17a6cb04a23678855e6d0bf08f931d6208e08fbcc251566a86788dbb66d2e6daa6f6fb3ed8871025128f3b0e63089af54f86ce4f1cb7cf4d17cf45ac3247ee49c966d70c428723ecb138851e4e8f8510eebc728723efaf65aabb65a6badb2d61aa56613fd86b7d1682cca1801f34064c07c48bd50e33b92d0217df02823cbe41b0ebcccc8388ec98c0fde301f9e8426340e7023e33ec884305d38bab1d530e630898f41442a7ccd4062bc2e11764ff5d517e3f553008c29a048c3cccae317eaf86883230afdc8b398640a423e87fc519e4014fa2c03d14012318a9c9998ccf2550ee3c973b38bf9561e2f0362143933abac23c6f14cf9e0325f9cf1e163d11a8400064abc200833371c789959398ec94ccc77c3819ef1c1710230b372990f2700333ee878a266e53a0eb0721f5cc7133532ee834cd6f1448d0fbeca3a7cc8ad9587d115c5d0812200d9c21368200525f80e132409020b5800c52b0760988933312b9fd19a8cf9565ff685437c8efa59cd68acc12ea2444b70f590c66a448f59a642521fdad36053244e107d488b5ad523a4553426e91255340d8102155387af2ea38c08ebf99aa58d0c132fce1086d169831ec85d24f3a1f449348b649e938919fb36c34b9fb1564996aa0273155b52081232c9cc9143a4916f568fdc89a9688c12554124ed37e7acdd95d3e58d4e44b62122661c73d67b636608e0a877084b4494998856c58ca387ae09815685918f5109961f62e48731be5b7e88336b31627ef820e09045dee9b14f4e273df3e9e4e4145d2e7f8a9c7c4a3cd3b79fcd88dc7e5a258dc4f9f5d70f0a9e774211256c46e8d95af1250d3bd87c10656c43248cde8600e17bebc1b76f42a28c74b9b54831afd5a397dc866c445c51467a74af3c5e795a157a49f8f688a48a1e5be59195a75946af2823a768f1b42a4f6cebe9d984782e6d8845c4ba894210f6e8258ff5762412be1bc7759987d171d43cda444d7ad641a523c132b93479c9a5c9a5c96da4cbac83158b2a0b092026a5528c31462959d175b062d12759a52f077d12a954922cec79885d478392853d8c45384b96b7156948b44a4699b57f93cb277d29e3e89ed33cd307e4c4312e954aa592e765dc60770dc6942c91450de2f44d832cae5973c51a034662080e6311123a8080c358f43fc09c0f70287df08d626625565895d40aa3340f7d15da80b6d7f6da801a6ce9aa43b617a59b2bca2093ca5c63bfb93697cb18e070736d2ffa02da5c2bfc9abeb95a25299597004d9d56afb204f8ce5c2387af3e0d2ae91516d2a996aeaa43738571a690b012611c1f9cea83717c706c836d411bd0e6a25f11c544db121cc3b13967f6b3fa6c2ebab9e60ab7706b73e1d6e6c2adcd855b9b0bb762980817551f0d2b196ad0f549b011dc1ac53e80c3ca93439491d4b95a2ba59356dcc22d2ce4db298f1d333b6682308e2a524c558069f6629e9206a337e4015cab8f37e4b3da805cb4095c3ddc5cde50adde900c6a159542ac4294e10d094599e965e10ad1438f0adfeec182e013dfd13a9fd15094893e5166ba7c5c3ebee3de909491ca210b3c4136233c3eeee34a43cb05e413859d2146e8077c7c867c585aad922e1f23bdc246702b89cb1565c6ad10e3e056cc1e0bc785d3aaf0c4e3c45262a9986072f2879c22721e5b42adc70c58d6573889be7d0e49a951e9f372c6a69206690fed5c4cabfc1fa6c11953757e56e0e31372d0e93208963e5de659f404fc82c1404c07c3e4a904063bb223020e61785e720e23a5c718302b8c8039c3517b0bb0632e31c23e8ef8ea5ce2a8391f1d08425af1a59d9b3d9367a63829eff5397b5e1e60f2704da36c4a02c2f98c9e0ad899af6f9f44bd6a1fdd3e967c77a8fed9999256c5e6cedc993b3020cc4e0b35c8fa25334eaf433778fad011b2ce75b78d347bba04b6b2e6340f4f8c27c6137307a5bbc78ca3e6bc447285256c1ac82571076910c967aff8527dbcd449019e3e3b29023c637c99b1fb9849d9c71cdaa04be09939161af046061cb68fefb07ba8532dd4301f42ad0abb8aafa27db42ae6266a50253310ae53ddb1ac5f7c8ad8e0033ca4c085a228869f2ea0c00920546801113a1665e22482c3b9338db4ca05711593b0337df0edad89039839034a2ba595d21823de34eb588b3f58ba14bc30c4c40e1a52a0822fd81c206108ae9c1e2030d13e79224c4cb5b30861a2cd2ba4873073c7e7e74eecdbe78f1964f2cc9d28d3819d6f2fc4547b93616e6036f1edd4a779e28bd6b14eb56b1ac6279e993bc6024cb59e51bb8e6c0971ceb7731e508cae18bd979c010e6b4ff5a9426a8f8f2a4a23ec4b0702cf077dd7f05c7395e56dfbb1fd7547d6078a32f2df735d1bf3b79f32f4f45721bdf26233d5b121db0b557dfa96c48bcd1587d3a9edd5aa9f2843b99cd8f704f5aa1ae95411e2aae22086f5871f62c478c1527b6864ae2dccc22c5b63f45e1e902b0938f45cacb9f2843ae56a958c32d1853c264415662282edc2372c565d6d493ad5db8f75cc9ad613f2b010651ca16d21cac02c4f4994a94a74e1dbd3c2b77b4351467afd31fab44e27bed49e116ceb8932b5f6d800c3e14927be34c89232be08a35b7c885934d79d9f1f2db721df3b7faa3d211681cf4f92564d29867c7b155287c8b0f6c88f30597b4e7c86f4ca03f25c46e4f6d3dbcf94337b2ff05cdf4596091c62d6cfb76356ab428c6f54d2714e690a2dadff117f8694d11bf8aed5658dd1ba57263eca34101d5d49143dad383599d7ace30036eb00c2fb2620cedce010e61b87c4f93803d32a9be851e85be863061d8802c43408e3021c3d8471010e636bd5d2a9dec1714aff561dab00a2050a374ac0a1cb3ce30538848189315bc399760040740fed5d0b03d13940b44afee8655c59f7192d6746452f7dff8c963eb0cdda634b4983e0168b2f40cca09e8e8782efa15685168a701b523223c9b70f20fe300388b9caa2cb9a850d58289cf02c9ec6b6010e6b508749c84b638587829a85cd0b506c439b922d165f58bccc9e0e117018333d46e6981ad4aa30e6db6aa1d2d9d17a6bccac81df524ab192f3374f44b72e7d6016273c38e03327f307f804677aac8f433bd9f9ee04e7434fe844eb4e82787cfb098f1e2fd42bebf264e74d50956c23a826d886947c3be781601b812734f4ed271f7820f8f1e1490f219c131e9d6aa7279ff8d2de42385aa801cb82c5db8f762aba8c94aee454245cad32e6053904fb094318660f38cd634b38773a9fb69e45193963c74c288bb40f06157de43b666234af5ea3d5ea58cb9a26b364c90d641989996ab7b90273a6b562ba1112d6ad3642050f22aaf830c6242c066bd5945902b56a116e3a7766571fb07c288030460ccbebdb1dd4648422ac2d880d60e8093b4a88be59d3a5e3a79ff64da73e630b5593fbd5432c9c9c1e9ff99ab039142bc29181841cb466688c16c599d8433a3b3dd4ddcdf3438340c00e82c398981f762a07348fd1a90eff8161eaa797e22a5c19fd7419575a9c91a8034828be3493902da5a0ad2a68eb8df00c0511f2031c6acf93c30327beb8a4a03fad19f167c6785a3b1a8f8bc286e0b5c455fbd4f05f1aef6dda299ea9d849d9de7de7f125ca1c963e6c9fdd93d2fc2da718b4d810f1657ae6337a663eedcf9c39c39929daaa3fea8ec599990ab12f6d47c84bc6e6095cd4e5841ea02056e783db676bfa7c0be9c96a74227cc74c787afbbd503094cc280458a75e63a96759474c6c7b00984d0a1c332d22437c698f3371a6661a9b29a734e6518616519d99eaa1996a9f2cc061bbbe7f1a8491453dc021289b4e41a93b81f5ed2d2f624beea00ee0c2a3c7a7efe2f3e8d25de44d8b3718dd65ba745749baade0501dcbad816483c7027b45297da66cd2c2a69cb464279591b6e23287ee2de07450e23498e33a3e5ae55a4cc53cf10d95b2a545fe9c850d35b0a056ac9c545250624c08549c98984ad823dd8edb465a66aba6f94e4b6f3e0238bd92488efb4e3ad52ebf9b27aa731467ce7d15a8cec51a7df33cf2930fe353d421c32e077d2a5180437cbac1f8e4d4d2de18336ae61a46d4cf41258ece5929f860054172724c833d9dc095ce0ad3343c591a16124fea36d2e5749a3b5309b0f40264dacaacc04d6badb59964bd3dfa8c7685b5b656cf1aa454a35a379f10622290bc7adc3c4167cc102022c2321143b47c3b045a159d46745a6db59536a055d2e54d94a72ccb43c454fb89c608cb9d0e60777e409ea81e7dda44a7339600cf8cee8d9869ee42ed63660d7dd194628a1339135bc2cec9b43929a59466d99454764f99d1cceb6985c44c49392497c8a2cc6551ab32ef5b83872c482f6df06ae85eb27028d30a130f472db428a3b9cc5eaabcb42f535ed697282f9dae4815798394a537bdf4186538978ea30c8bcb1c665e59011bac537d53f2520ee97bbec312e961bf1a2239446e88b06cb83544584158d260fc1a22339a45e61a229785436be4db6dac55611723b245524664e1e4e85c9e797b4838ad1af21365e28c79423c1f8f9443f2f124d89384bebd86884eab66163e3e00be1a223aad21a85bd31a62a455130b1f1fe6ab2962a4c78a5b03458f9f56cda18f0fe3ab29f2a3b3726ba0d0e969d5bcc2c77ff96a8af4b04eb7060a964faba6153e3ef8d514f1810247e5d64081f3a355b30a1ffffb6a8afc204ab9352d229e564da18f9fbf9a223cad22945bd32a6ab56a52e1e3dbf0d51469419173726ba0c8d969d59cc2c767f1d514d969c54c6e4d2b36a455530a1fff7e354586f08832120a1e425a35611fbffb6a8a0881e2a6746ba0b809d2aa59c5c7277d3545822cc1b7a6b584c89256cd287c7ceeab21b22489776b5a498ae4b46a42e1e36f5f4d911c5894912d988f56cda08fbfe2ab29e243c9bd352d2545705a35a9f8f82b5f4d119c57776b5a2f22b156cd277cfcd3574324d68a32b245a4a855d3091fdff4d51029fad96e4deba7488f56cdd7c757f96a8af4101add9a961011a256cd293efee8ab21426444bb352d23ac56cd267cfc94afa608cb1565644dcb75d3aac9848f8ff2d514b9018a32b205a4d3aa09f4f14dbe9a223a43f5d6b486e24bfc9a223c5a3597f0f1f157d30a7a7a6b5a413f280f0dd2aa7ad3ab0d2624455cf510f5417b7c531e2ae154e2841f034f9256f5121c4419f346c2e8e93387b40a4f23f3a755536565afe2cc64e960fad860a5955c2a99b2bbfb28bba7b4aabf7ad688fdb1494e9e6b2dff848565e2f492792365682f09a3bd8796bc77132b651209331153ed20780df7c0ac06fbc61bf29478b10689bc226fc94bcaf0aa1061f415bedd7b79304f28beb4df25a20ccfdb2f13df6e7d48195eb63b124667eb8385dbb0c1adc7ebb5f019ddc2397a6958230d36c9e49c2927ca5cb9ad5831bd6e4b9b724c2388aa7a8ae121d6c1436d07efbc8bcdd50ed9ba74c89f8bc793f5802af54aeae4175974169f4eee5e50c9e5021d6cb0416b53b49f92abe422bdf80b8c87305e3e17305e6e70172f0ee305e6e505c6512f30300e83060c8c1ca25e5e5cdce02e5e5e5e5ebc4be3859e5050a8d55c29594b5272719bf6b3dd20aa531fdd1b9466140da55e9017e4bd00e0a10704002f08009f07646df0ef85a6506bad4d714b5368a4509a425f68cadb3f17171717eb35cb9c83e3e09cec52da4f4afb399d5c6a3f36db60c75e4d3a8955dc445697dc67aa356c702e5e6972958fbe07d4abd8f282bccfbabc3458b8e963f1e233b5e9b3c1f4598fa6de72a8bd0eaf95fcd2e18b3115e38b3135bd1639e09053a70f05fc427ac31782a174f1859a351265a2bc40c8a71388e87da1bf378447bdf4edf82c5327248cd8b7c7c243bbd35d014b29a5f47cbe97c32c0d6948c392dc1135d8a552a9e4793b6a83a5ac35586af1c92f612fa9a8788a8a4a8aef78cd53547cc79f5cc597b07c3cf27afd11272831a5e1db4d3e1e791139e1c7875dec88137c1c0972fdcbc723413bcfc5ce0a38ec62271e4e9c0d14550126a413c261e7f14709a26fef888aba25d3ebf4dae315f003078e518040e8f3c72840d09241eba5d7d8fa964e62cf5b2e0d132a67b44dd2aa149c5b38a77d36498bcffecc2d1831d2c55270ce5c549ebabc37543e73ce452a3629acc1cf733103382209f2f3d8bb5883f244760dae78dd92cb6a150a0acae95158769c34882d912dea62d8cb26d9c6222d798e695734713495943caf0d7fec9ced4c3e8cddc43dc7b7003b1e63f7eecd77711acc3c97d2fbba33c4975e125fba185157e479f9b2a880ab875d8c86f69a02965efaa1c192cf989a16f4ed285d4c0a58e523128650f45b0c4cc94ba592cbd87adc1575aa63b21cc2c08033873e71268e97c399f3ed5f0c8659adead88f251f7237df6e8df40a27c121b45e572557e965837c97604270b825e724567111bd94a184d1f030ec46ea4b382417373f529206793458fae29b721a0c32f403e6830b93e0f1d4bd8f935865cae99429a7af1032938048afae0a6cd3e590df7555601be9a715c7ce9dbecef10a0a9bf8e94361ece09f7c059f48278fb8fd4472d4c964c54d482b39449d4a3cbaa225d8c4a57318c3b0501470886128893f9474f0b19b84289969c0c7b908192bf168d5e728ec217613af1f86d130c9210a671af04b384f3fc4b09e95544d5e9fe2dd069ba9ce5e1f2691f38261c759f39a040f22640ea9ab38373b2f085b9e6c7f34987383905efdde1bd5a5f45abde6120f286059bd14571b2ca6da4ba52d6eb092774198046bb03d18e7e17b238a10dcfcf43a338a269770841aec39738947834d0aaa61835bb7af156049f46117537959202a70761bb97b02f67c36115f7ae23801875d2c7fd62589decb4a9ffcd80e7e8d7d36b0f45726be3aed559c81a19d755250af62f789f4ead0c6621d51ab5692b4ca45023a399e725697d5290ef02912df2dd0158b767e5ae71bc5e957445604122f2b8ac415e5a3cf45293bc64a32017acd431bdb841aec9a2386f92ef679b3e62aced01c6a6029cbfc2679838513c7b4f98a9d6f67a6dabf9fb98beda478d33c05aed9063b76e96117e3e464718ffed6c5c2930f274e48bf0d96d2c580a87f21ccb3f0602ccee1d0a97cf44b38bd8a33abd88ade50afe2ccc9871ecc2beaf660edc1fa8910c61bd590c3933f71ee9a76f0897b79f26810480cdf809831328ef47892c3d6d1c050027a06e6b9fc4e7cc63c29b9f7dd6b274e17b379f298399afb482531d2c4e1d14981a7cec499ab0db6c1700a107f3658cc33bd4c2f6c6bf5bc52a9542a799e2db18c264e47d429540cf76278d704fb436a59e6792409eb10bcc4308961d2a518e40ac364eac73557315ceee0d265ac2551945171e9320c5186871e64c9655c82a35725d74cb526fd01518607e4106822868832262ef3cbf39173de6779ec0fcfdb603606fbf6926bae4c39da8fa9e45a715c729d5cf3804a3e2f0dbbe379a5d2677f347882a2834b930d6672148d741b136cc8463af6f81b2cca68b1f8c284d85c21a1fd4819d665ca89391f6a1d129db75bd7f5be16c527ede64571937e15158d87af07964b737215af41cba6a16c829d8052be18304a8089e13bece0726687183bf0e03ac4d8c17b26eac0c26f8d1d5d43c5b51d7c872f461dc2143fb95f1acd55fccb2d2ecd0e2242f81428a48b8bee622a2a5d4ca58ba97431952ea6d2c554ba984a0e55fce4a1f6e0a5d13cc5539766479157f1942f8c507c4aeb6d544a6e1a2a9db229e8868a6b0e5e1a2a39949f924d43d90443f964eca4be49964b904a08a0c3d733a6214dba29a8c106db5d2e0df692bbb8344ad93484b309160353d219213fdc60dfda4852a939d55037063081d6791bd390a953020e4daf6ec9375157d44981435317fb76d3d002e6aa25a6648c972f5e6f7abdde8405a3650fb4c065e9341ee10c3cffe2db497f842543be5d237dd851ea95da506fa7a5d860acad267ac4196310b3ef0d1a414cbbca987d6f507b6f744b19190fa61fb2c874263bd7a04cd428437a8c5e8f80861d245248c3b7bbf8880426f4f4a564d58ab91c3b62d486d8b63366e95381c7524a1d92e6a0ad1ae02a5b2e8734d88a3936b88d281dc5a29e2e87b4629cb2256dabc12132b3590e69499f2c5b1f0e9f21adb2de9a755b334af2a8611c8ab9020dd2dcb970488756440031532bfaf351fe6850f27c2fd8504c892402626ad3e7c7e747126124a853ed43423e34d20161cb479bead2a59090e746a5c900b589596619a4c1a121223ad59e041c5f355b1583703f9e7e464821f38bad267ab04a435828b660831ad534cd7ad8752feaf42c832f4e5e34885b7e3ef8edf1c14f020a7e47c8f2f2e3cd8cec1e167492b7a516995d37270b4fd6cf689312f832e1c3866d47f8b05b5cebc3de21e5e0c3666d3c1f4a58f7310a960ffb310a96131fca9d12d08f51b044f06184651fa360e17c187db278b4c7956cc594f49822981838747a6157c4f8740241983066b6e6c728584c7c285b4b740efd4d4ae0fa310a16eb43c96a9610b89b27a273c06756ab0f0920e090c6e20542091f21324883fdc5d827842908a98e04c98f8f429042cfc3f8280429b0664b099c398d3548748325abde13c82e09ee8e802d121e66c021058a459ac515ddc1c389a3439c3a3c783877627838797a5045ef565cd11c3cec9f8ffdfaf8c2c3867d1cfa08c3c36e565ccd160f1ba785ebb878d83b61f384ddf36074d98aabd913ca9f8f31463924631f65515c754a94391fa5cec71857449f1157ed797ce118874c11747a04898a1ee9811e89418ff0408fec408fe8408fc0507ae4080c7a0400f4c80b3df2821ec9811ec1811e49e558922337606cc90d31221731252e31a09658508b98508ed920028f988a46be1cc60cf11cc20861914330880d39f41e3115bf864c041f2cb387083f50b327968408372b624b566244a798129518504a2c0825261453271b4678c454346292c39821a61cc20829e5100c8273e83dbc1c6a3e622a3e29f7fc88a9f837f7d8184292988a466eba1cc62cd97208431453a0122e870ea4e5500b8aa9f8231b43108aa9f8590e4f3f5b01dcec6eeb43968f5fd87d5b7fedd2800dcedc5ded0809f313e607206a86c081c44d8e0f1e21ad24adea9ffddd3cb1b5bf68d5bc34d63b87f9a977b27378b2cd8bb5af3fc208a9378d069efa8b9c20fa690677bee5bd813f2b42becdfc74693cab76de20c006a76b39a42d3feb11f2cfd0ac7a6fe017a2dd16c18dba1c168bc5c44ccc3cfb6c96cd2c17c1e2e9edb44f7ef6bd68703a4b8373fa6d010e5ba884bd8db4b369adf59e320bb56ba346e6ed01782dab355ba05fb48032767978dd9c27a7bdd23a6739812d1a3db1f89cf364021d869941e0624be8f54c02122acda6d55c30168e6b52d84c75758ec2e6aaeaccaa033b9d30a653088755671b8d70e501c2c3e298b27093dce29f7b0b778e73f9751ce72d92005d277d61059ee45c46d39132aae437872821b073a852be81736c90bbd24921c9577432cbeb9c775d57ca37bc4ceab88f73d31792fca4c5bd16e772e727e732790d209ff33c5e03c86ff1197dbff0ba974f1eaf102dce659b16f7b24d0be77284b7257bd7826b91b91c7eee2b2cdc84859bb03061b172bd23b9c6b15871ed067173b8e239e69b849233c936f80af7d9d0755cd7755cc771d2243dc5a52cc92facc04b1792bbb8b8ecdcc5e4f2964aa552e9725388c9b5fc48de75a41c3b4779a9647269f2bcb0e35cdeabe3805c9e2bc5eea4a0a07c3bdeeef8d0579dc82e9f9c64784e9e5645795900e4db2b9028136b0e00a45382cb68e5e29ad6591e9706c805f436ea91e6ad396acb10c847d0b7c15fef10b0b9aa3e42d8960087db4fd7795f1260adbb3792c5ea9678ee76f5f31cda1b91033fbd521a2109115c424cb57d820acf240f89a3499d99ca91399e1265b8acd2e96235179506322a0fc77da3a71f102ba5ed1d9ed6d19e7e4072e374566b465dcb624543435aa5be01719171a5ce659d51ae52ef461df7cd17cce5cabaee52bf55ebec8ee7c2d573f1b8f864eb061f9f8e1b695b966136f494f0ed97746950275d1bfdd5394eb31f1017d567662e6e00c2d29591aae7459918a377388607ac46b03bb57e75f474563a29ceaa7dfa6d47884988a97617db14f547cad87e240c2354237cbbf5eae2cbbed6e4886eb6d2998da6cf951598baa6ac3f93b690ee99b4ca496bb356a0ba18654af529dd7e286d1927ada49c178e2b1601217a4c9c5babb2914fe4509366db5c41d54029a59e69239fd15209b873ae45c77d406eb837b870cee59333377cf3a7d59a2f57832e972fce38311ad59f6c87c577df14925c9eb01f12197ea4e0b415d0c8ae8f7b82ead6fa4acda4a2e9f2912ab5928665b9346abe27c0d2b91a58b87c976767c7a7a747e594e2f2753336541b587c1c0e6ba658532727274565d2a0d6b92c7d602bb36dd37c9be15cf8e6e2e6b8c4ba91e6db966999a58e32698bcee51bb5742e9f36a3514d9ab4882e9aa4697973f9b29916f736b16d2e9f9db19f8f9e9835e8aae0f51d7568df4e5c3c97cb5767b80f888bdfdcad9a81b878bc40daa77dda3553391325052928d8546e8dab83c3ca13654e27939a14d991733236e7120acc39f7a273f9e6ccfde83d41e6a391cdae094c9786cda173f97a469b7e9dc0d26734ed99a44c2a32418a44aace52830d539ee6ca2573e1d2e59bb1a199725164a56c4aa994b2e7ccdb8f0d2cba132e6d3f714b425cb9f07617b9feb878b855e1c2c36d0a179ab6d3a367adf196a0ced924c0218dfd4819d50872456332e5e2540c5f902b97ecb9cae0b9ee083c97cc267ee342ab76eb6ec6792e9354c2a6d257dfe4037283cb37b7a0ce6eb3d24927901b5c73f12d3183c5ba21d39c99a2383385b33353ad737374bebdba8284a2bbde2469296f3f9292e81cd1cc670bdff91528a8c1ed3573457079fc6cae1b02af665a2d7dfd5a9cb93c925c104ccfba16978bc35e662a69d46e9d0b0ca6a3537966e591d2e5dbbaae3cb058fd5aeba85ab7d746ff8ef6966e9e5d1ad6330e1f214e11c1bc252182eda56d0911dcaa88a9768faf0dc8d2d8cc54b36fca82645e7978a810da13b34d08165f92b8a4004485206de2d1a5b123397dbb369af4cddfa673d7467fe69cd6799f11397014227b2eca23d4ed0a5fc87266fa8ed03ef3d277842665d09884d155e7772e0f2cb97c3f802dcd341a2b7df15b4619bb33398a65f5ecc83b0f4f2fb8945af18762adedf07792d90e7f269ad6e1cf34da46f82b6d1f7e8ee3bccfb9eb3adae18ff4f58b3f495c0d02096d41b75efcdd6c449a244ac25ff7dbcbdb5e9be7d10e7fdc3b9678a4cd0c638c3bfc6d2fbfede7db8a106124e1dba4882fed4788607b37b2a59a956669f4391b99b669a2a65192cdb50135d8dabb6604198504b7cd6582bfec4ff067bf0271e1f403e2e2c2858b8b8b8c0333e392b79f930e7ff5b30f888bd30f880bdfba91f6cd0fc807e4860378c6c57160665c78caf6a5e0cdf5f8a39fb71fdae16fbef71d8125a644ad7d4070f00cf701c1819971718f12a168915679b2ada84122a058e5992bcfa5e5cfbeea436dae3ef1454619d7c8696f1f569fea5329a772696c39629ab77ab27269a811daa22dbcfd1c819f3af71d817f7af71d813f1b423d80a587d4a76ea86689b24975c5a5799b47d9a4db8a7b9bd836140aeac40402a4ead257741277bee2d2b8be7235bf9fdde13427f9f685dd6f9ac66d5609ac692ef16d028ffc665309f048dedb84bc5c8e78e4df2dc08e1fdd1b23b7c1a3ef88bed152ca887d85a02c96bdb7896de33e790465b11a9cefb91c79cf51de7ee24b4bf9db77f2de0fb7a2e3be38b23f5ad56901e83a002edecd684e4375d5a76543c341c4e623dfbe1c7e2b10db7e1a3ccd2edf6a77deb79fd1f6b3fd64f9e707888b6f3fad8a2edb8f8eed0709ce458aca295252759a1a3b5adc20eb5481ce14a20c0a93305a7e1c580020b6d4e8b3cfde20d620824022682b1274106152867dc114be1d07b73d3f73a003c8e1cee05ebcb8346af6f4b33bd6ee642fea0f2f6e8c7d69c24efdfa0171f1e96277ecce4f0d02e3d6a83c3dadaa1b759d6a4f0d52bdf234d834d634a6830e97463dbd943548831df33aa4b6aa0f48352de74b83031368c0042dc6044e6f0300182c30ee0906a6777edcdb04d63eb4f687e5d9c1eeecc0c336d278a834d3c5ad0176da48dbb84ebb1ac9c35ac9a4999ca0682d7920658e5b956de6c15ab44482135c6c09fd09e9b1690f198833f2ab915c8e317581d15397f786c67d5f8d64b1728cf106414301fa85251c7fc76fdde87ae70ab81de7521b7911320d7fc339bee9b6ead6d61ad54fcfc367ce7159d765d56d8f7aeb6eee92b47c447f56efbd313bbb3548b7467539c36559963113428dd306e52937b75187124f71a5796bb9a5532d73b768f2b452ba3493c601dfd3599ff3ba1865b6516c0660c7735146ef782eebb2cf52afb37d529fd333ea3728cb08eb46c0909ee394475df6dd909ba5d1f174bb37dabd6f103bb85b837a7644bfb533baf30e2be7149e17001a80e99b4669adb5564dd3b46d661e663ffbe7fc49a38ccce71c8d628b37cb69d6794284f87224be20b9b7094c3f9446de48e5b28b23379fd1f4b7ea7466ac51cde58f5a29a5aed92051343d9bd9bde1bf002dbeb40cdb2f46adb39580258d039e52af0741404b4c80c110f42d3e4201861e3c51ce7f1fa1008392f788823edc60a109e8559228c9d4c287dde3b082723e1e096221e1e391270cf9ed0815b18f47a88031e1e3112a9af8cd84f5ed4848960e0ee0d01a610287b4f5f1dee09ad6901e3a2c1c2200388cc3f01707fdf39c188f2549e267b7c159f8f5ce49cef9e62bfcd58a1f3f7efcf8f157fce42657f1af2982e2268e3d7eb803474a5923cce3959a47a7d43394cc35a69f78749818a157534e4bab4aae064b409d8aeecd2154600c9b2bed65336b03ef797983713fc0a69cb9d25e34d20740c0f20738dc5caf0e8739ea7b2eb3bda1acd0f40ac273fb6ab06e30d3abe64d681bc226a056791988124f488fe12dafa099825a85ba51653ef97083d99d5645fbc3bb343c19e2781b53ced4348c4d39259729a7e432e584a61c3cd42a1bebd54b25cf732f873870bc75d9fa7083411106a1696da8799e87a0e7218c97a94b2c64e379b59e57dad1d01a2cb9626260604030740f4f21ce365e0a513c64ad6baeb034e5bc0087db06d37ee66af433727d3b7e6db04d681b6ad0c63c180ca664488912424a3ca0180cf67abd866041b4a3b693b7864850bfb25b4324e855298e4b560e4e7c42908f440082f32c3e1e79028f17ea546f4abedd731e44507243042d2c79194f60070a01167b180c79eea5a3f501e0e5175e90912577091c7631160b0727a7470f2238af1a222f95c45ef572b843d2d891790087da6b532265c86fc7c101a6051c6a2fe91b6c7a360bf8c43d0f37180d2f9fc05a15e3091a700d11184cc99012258494c4622f1d84c11a8cff72f17a0dc18284940c05bd5c6e0d911711a0a016af06a30aa747abbe86484e8335447adc0d608f87976b88f4904782602f3dc75b4304a7c11a22f139165e4384d5aaf8354472707a155996699a9689c069ad5ce98431d53a5a042eca86b1b8d3349693fc5e7449beeba6e1a753874fea0728a52794525a6bad95525b6b96d96a29a5543a95814798b731465a6a40839afbc989bb34b216f085f518a39432d2c8b22c8bf5a45356cbb2381a699966a5e6d6718c2ddd5e41d33c6a3ea3b32e9356669bccdbb3ea599fe00635f969da48d3368edb469ba669da6834d2685b2148ac3558718355caace4d5b6d464cbaedd1577aa66d6eed0b4cc66147feda6b66d7b2dbad9791c88889610fa171f7f96f0f9ecd239b598c40295512a7929259d734e4aa5943136edd951c66c83a91431cb222d519a65d45a5b279d4b7897886870f3303b39b18c46a35137f56e4ae99c5a6b54b3b48a61646d585b2b8ba914db5a3bd2346d34b2d666a34ccb6cad2fe8087bd9735a3beb06ec6c6b6de6d6adb5f2ebd795762d62a7f5f65a67694eebb5d66aed9cb39b6619adb467d357466d4ba9699c66b32fbea6f98c6e3541f49de63de3a4d4da2ca394ce69eba4d3470d11d88b72b2144e2d736ebb34b293134bab6474cdb99194a34ff32cd3b45a2bcd2cad96f5b38124dff2f187a5f3db277f8549051875837ab6d93cf33003e97c7acc759463abb66d8bb49479db2cf3e7a2bc231ffab9e5cc6b88bca24639ad868892211a366636dbe08a048e8b57c0d1b96e1c296d12eac677b6800e6b89922141413f4a2cf9364312ebd3fa8cf446196de4d169bdd1590568c0af289b5135c3c468f046ea61ae8d7e99bd79bc0087dda3757ab409aa0f4a2bfd018898d829230dca9e545252b8e363a6c7bc68100818559da26a9ebe93f9808b2d615f2d37a76524d2d7cf75d1a3fc4269839e8f48f88824c86b74bffefb04cfe31ff9c8efc82fc92fc94723d770467e351f917cf48262e96ab081857fd9094cefcd2cb7468d2c728b161717e1ecaac0a1fc111d5dcf9c741d7ccd4734a3aee68d50d43327e52e4451964b435e1a37c7e4906fe3d2b5b8742e6e005338e490830d35b0b060bc6265e5dea00d6aa90ebc37bc1f3997ea70b834a41f3997838c4dc23e9f6b19d32a9c471e35cfdc575c1a38a334cdb59287d8350d6b1f4ad31c7c9363cd94833ea769ae951c3ba77dd57109676e3af1d2493629693ea363763c76e9a5929b429486ba34505aa601df7aed469a5fa7f17ef45c0e1d0e39742f5eba0b001817a6bb3ae04f9bcfbd7497527fd14247a3114eb9346ed8467ece0e092323ad1a65f9d3516e10d747a38c22b59156a1463f9d24cadc1bd7491935ca34e08f7c341ad2aae9dd6ad5bc3e25c9479a8fae36d24179ea9dcb53e79c83e960c0743aecc0438c1e54258fe4239fdedde939491b8d48238d7449238f7477b837bcf79ce3a18b716948ef39d703a76ad9246fd5dd7e2ea61b7d24ce07ed9b4fba3450a3d157fd7ede17a3803347913ccb480efe752fa3483246835267767d8b907f5f80337cd22a1bec9a4fef6e94198dbce478e4a64f3ee90aa1f948f391738d6934133e423ece369a8fbcf4859a7bde5d1a928f9cbb37b4ebd7b95803472436d8f968858f489ef0794ea68bad4275f1457afcf0bebc315f6b5066d77cbe7cda7595d4daa84938871a782d8f3e3a6da5dcc4ed5d27ddac759fcecfa1ffc24e6b708749b64cc1c596d0c2be3a976530eb5633612fd99c39768e56dbc928b312008bc3a534d17aea2a2b1d6d950294043dfd4092a76e35f73cbf2a7e5554fca4b9947e72039c8f483e22b141eb5b74ceb9689173b8c29d050b9696951515475d1a2a27575139a154541c7c163fa9b0e4a0bf12836241b17cf257748c7f5a5959f9627c09577c3aea0a417d251f8143276594e15edcc88242a5789edb954b23adf57bc353f1ee95cd03e5d6e857c9f1a4e2d6636254aedfeb9d9ffce4d23865d4cd34e05fbf39367857f8c9b9fb8dfcf4ade8a2803b3f79e7b1c1eee4e0a37c458e0dde8c3a651af051a32f077d9598f8225532ea08fa2a5e84f72a7eafab7c31be842a425057c947c847f11b6e0d1437712ed5d99667adcf48999b64995f19e090027d963914e4676e02445fd4ada7a4e430c557384dd2aaf0baab5536d73dcf9cfe48cd3dcd3db7d73df77866c6c1903187f2643c45c8f7fcbe0077e1c957dce6e42a5106e599f70ab87b7dc54fa84f3ebe42a8f855f1eb1c0f9dccbeeb5c0fdd5f8f716ba0780ed9c9286303c54d36d489c9fde29fbeebf4d2a8f875d417bfde22e49ffc7e47c83fa1e47045ccae0d9b93e790afe22bf29d010e3be7333fe5951c9e7ab44a25db9c5cc5333731dd1b27955cc306c5ef0cd27079b2ccfb47169e38e799cd894bcfdc746934975eba374eb8d99d8cb392ac6b366b9786b5de4519cfad4b0d6f51defa8d2b099ba99b71c05c2098f3b822d3b4eb1a4a4899f8cc4dbe1cf229f58c47abe267948998ca1c049fb929879a093e5bc1678e33bd892f5926e550fbdee172fba8eee3c1486115f635e665e69b8fb24c037e8cc79f6599a665ad661b7b92df92d85bd7fc79615bdf1eb64cefe2caf26833c69cf4e79b4aa7326679e64a0e75aa5d8b7da861d68907f6a1b6810fb597b9795c19e0688410b89ac7b7d321ad8ad47f08d5b12e2a042e46992264ec51ed1ef7a255917a485134d3800f3e0501d15fea33a33ad3804f3d26f1d2b3cc26731a90fab4092d80a2b1b9086923bdc11b84f4ce2f766872f2e0628d204c28f9d2c72898882612e0f6e8ed474820dc4193a5d4e16200a89374dedf7a104ba7a6cb302287e61d921ee07c9639750d3c89e45c7f47685fc44403ebab2fc0882f870cedd7a1f5cc7a9865994d36bd00f50af1bdcd20d64ed85f3b9d30b69aa6f99491bafc0afee55a469ea1dab3160fb03c122037dff211890c602f035754c010ea36739606a71023b7c9324b08fec86791bd35eaa5716380437a7fe050037fd53ee72469ded2aacc2baa7d737faf2dd3bbec9685c442ca2d30c0a81a35e46b19d5aeb9fc7efaf2ed15d2a6e39328d3514a354a297549a097be51243c189a21cb4f9f487800fb39b5b9c2f4b3a99e434e7f417d3a4c8c28a3f9f41ea28cf522bccc479f2604754bdd526a394c7fb695b192ba2f9c78759de73cea9ca6c5e85c6cefb25a7ba6baa91336b0eca1d3aaea6d3bce4b9fc9b38f73932f73c99aab92ed3ec075d9cee1c9de6be98f36699a33eb35c936d32f7542ca38f13afdba451142432965ce67572ddbcc0ee266ea84e5bc65ab55248f73b4ddc8da6dbe2615602ebbd7c689777742f2534a46c95c78e2d99abe6ba3ba8dcda1dcaa372b9bb4e6d0023ba813d909297b393ce5511efdf4ecdacdd68184b53f3eac3773da83faf83087bd33d7ccb930470ea9ce739ea3bf9d5ab7d6723976669bf6ebd6c356f296d5426f6d0e73681ac63937aeb7cfe81c35bbdf53e372f51e1246667293cfc4339f2bd9a30d3153d4a3a95943cc956cdd7c0a4f35778eb06dc324efcd71b6a9ee797b0e658ba6bab76d19457213cf64cee98431ac3d0b4b26d9a4029c79e7d6c35eaf10dd6f2e733ca71e75d3171bf4727b49c2e886bbd32987392a75da39bd34ba4a227df16b7542cac8720efa9e87393a732fdbd43047fded07c7d58c99a231aaee9643f959ada496da502bf976bcc19c9032e437a53aa3cfbf9606a9df0ffc5eac60e8740d94a798921e5d9b5daba82631fd5a1bf63587994faf3b38e7260a88f8d66dc4b7d9b483ebf785feed5937fb8b7fbb2cebb2cce76acbf4f4daacf189b631bff6eadcec1c14e9e2075512fdf4ee495170820fbc8c2d1f18f2d6671420e879998f51f0207a8e76b4c6582bad95de17e02893797ba55e84f742589f517c20c85b9fd38b90f3c50b23a6c7f8123d44459b5131d3801f3d66b0c118da2e0a78baf4f8a1a4c7e933d3805f33f8f473bc882f323a97c9d89d5592a582177b7cfca1ee5e45197248c268cfdd924352868c93cea638ed02fc336d9e722872dd5130934eb54e19a104f2e333a7746a8e73a8699a111e5b97c3e6b2ae03fd271df99c99383f9dd3bac965d98a2fd3af0bb0754ed6d8a4708711ad2984a3ab5fe83dcd7248c6e9498d0a4d73a9b9746e4e23adca7e2e8d0ce286ac5a57fbad75695d663c56baa887584ab7d2a7de1b7293526e595e9aa965d67ab55e7570644ccf7e0290b9e65c9431a3e800cf57b72553a9e42d2c26b7866c7d96c3eeb3cc7d374f84d5db065f1a69addf1b75e4d56dad39cc5cf6cf98dda905e607206a86c081c44d8e0f9e1394be1d4e37d252bad82a1babb2d13c0b2f8dec808fbc414ccfb42b47dd0d9b299d327625dd2c70b1259448ce80e40c3d01ad7ea8f46c35b64d2d1d9a11240020005314000028140c878482e1783ca2c98a750f14000e8baa5478521ac84110c3103208214304040000000000329a2409ea4945a1d20af66fb753dd87c868d9582d74e995b8201d98e32089015d2822a1704985e0cad3819098fb251646c7521db3aaea959c252564232bd6fff703d9f9a9d87eae7db4c781af93e8bb04f272c570e08feb1c0b386726f611fceaa641a6f12dc245fe566910d5a508cb04b6a3410a209f208ee4cc4a894fc8aaee752a2e25054d56e6deca9029e8abc7608a993b74f69e9f4d3b832bbecc802d6abbcf4344b3eb19b06d24f48ce47a790a62fb7c1ab7123539687163538d57c68157abad89bf1b450af57574192adb4f16eaceb09a20081a6ec2719e101b35ffffb49fcab985dda1ef17a6ae996fea730cdcfea9e54e84654d04c9c4c191642a5d6b145df14dd50655358cc37531d467d9d28a064f5b110c662bddcb4c0d961e6088ec420a2a98b65afe932db1b4be73abc9d73f5e35743b536fa4d9280edbc7fac0d71dbf6950d6a2d114ebed720a066d1153673d68b240476fa3854276095f521df21f5271d47ddf1e5c04d9c0f1ff7ac582772edd67b3305eedaffac492868b2ca424524069cd6a63b88d4a6521dfead1040b67d946d0bb32f87b8b9cd9708be896c228af0c2bdc97e8da326cf7361f185a868f2c2ad362df743d77dd966c36f336b7804c43d4f183960c6b8f605bb33b842bf183e821549b0734bb888dcb4474fb6e7d99681d015468a26f01b9e73a20040256c430819f32064a6389c844a4008f4b93daa833c5ba22042152934f03557001b4eb610e7f0709a8dbbad4f43431679de29d8881334604908847bb814a93ea32f6fdbb3ad458d19d16b8de8ccfaf8f4b6d7cf02e04bd437276bd99dc61d3dbff534dce00a724b850554f4bca0f5525cd00718e807bb493d57dd6d28e19def6ed4dcfd3d639bc2131d4767bf1e9a69602aa07209d976e38e7cd09bdd06218c7a82295d2530eb56481de063e7f39c39273de5d40895ee5b4b25560e12afd1b3390a09d55217d8b4f4e2bcc55babdfdcc66666e58543fc6270e6ec32f59e7629b2978690e4331014d512486ca7bcbcd6e252b202e76bb7a74094419e58ce83b13af6204330840a485228bd20305f192110924f67c5d2d9132b4a6c484e1eb94dce20b4b270af854b9c83e32dd21e867a0dbfc89031070d96f0112de0574990a7c24c92da89960e12a5560ef45e02f1b063e532a686b41fd802dedca43dee607abb2818382d31d13e37a9a9c8346101cc86aff76dfa33b89cf6fdf4bec049de5c8932c554369188cdc42ac4decc4b506ca8134003483673096b84c40b11864a88416b016e169d66da4babc915c7f5a5dc6f60c00367729381a119c317c45df837b9a720226ab82a7c4f837a0878dceb3ed94ad4f562598bd0c67d084f0c9b0469638d647650472e8f6e9e0561bb24bbd5723ce2d714b17842fa52f839c2220c07a3cca2789867fb45cb3113bf3e27aecf0623e1ad17245a765e4dbc2cb2be98d76fd8b6a4aa9c9cd40d640529f1013133b62abd8f02a36d09a74bc03e1701f886d1f423798fcb982bda2aaffc03309720cacbf142d368b2f083d7afcca0777b91d577a1a18ce61d5175c180a1591a68535a55b844f0e1344ea5a1e9c5cdefec891bc60ddbd48a4d40820c1f98501fe3daa5122d74c42e0321a01dd214d35238b8560a9470278b52d041ec32172491e43ab01a777e814f9062d5e2f17ca7748b05622e39fbd06887bef50efaf2eb2f1a117e56f6d22931e7091bc875b4a18f5a2ba0fa381dd733e06dc19f0add09fb2f33c392527d04df4d19868305a7c260d1949a654759ccfeffb98418ea8b731c93779f0633764a0a9ccc568e6665cb923e07a25fe2429f1cdf29c66506a3223913b32e4f9ce20fda88e2dd5acb5d0b5f35117298404c31e2802a2e8a40c1ab7caca18fc825c2f9994e2baf848b12aa5b23278e3594c31a1f1991e860c132bd1c31e56d3027f9561e7d4dbac443b4f5a52ffe7e98525c20291c3e3857d0bb973240b8f530421b0149b144a847c9068a1849796be62f74483b731192d8df7f8ede7407f68c53b8398f1178528201207b3604c871d77f562269d7569356ddf5bd20866b2237f972611b0a3d00f21469684fdfa39b34986f26ecf58d2379a9dadb4d5cbd02ee6cdd129bc87148dda4c89c6d500694a95178e99d1b7f63cc1ff0858b63b5d75a765c3c185488e289a67a9c79d511d85071c82ab7fd2ba3fb968655f9fedb386d34f7e58fe250ad3e5d5b22149f1a94458b653ead46afd70b307a099817fa4e68bb15a8b7d0606b8a66d1c579d3f6514dac4eef0b5ebbdf11de9532b978e922d0bfd987b3648a08bb6e84d2c2a9af9d9a2eb8c634c1ad41f791d2da9e0500f77cb775a77ae7afe49fdb739876fcb40ad232019d73677511533c236756550d209ecc10888e215e7f8c3a88ef26d856d574fffcb515803b1b4118b354c07a066f8e208a65cf226cac827d623efabc497689424fc45a2cb771856bc22c151d944b7e5958ca157fde0c788fdab32a94b1c579e57a89928eef9e46de536511edf95415a1cda122503b39c3d42614cde5a1ce47fc85ad365c4ee4bfa47291bfcf9dd99e6ed81935faea1376b45da63b0cce998dc25aa74590616ee9496f3778f9dc96f6a3e73d24c5e690faa0031f1fe267036e2b3524c6427fc4e8f25392bde43bf4c384e03c43354fa890dd53f0c68cb782dcbb30b55bbcb8f374d3cb17da22df486d97db554725cac12a5b99aca312784484ce0d2f0210808459e874c5667ff454e45f078ffb4acd4333097c958ffa6874becbea38807184652c6af360fd0c8833c502c6c3238b776dc874897d4cd1a04321d3c489ce2199037a0f5b62606b412f457b2be33299ae47e3bc76674360c55d092e304360746468f072d4ef30d5565339d7eee4109a70fec57877099223c1559a3ddaf657445aba420fe2c79d58911ac871cc404b0a7d1d23b0d7cd5df824baf903daf4828bd9c8fae4458c2f90f405ed9ece015e673d1c999d8a8195cd40793f781510e664185f4c1a8672b816e4dcf87542d462a6b5ceb3576082a894eeac064f6124d943da603adf94976a5a173c5d3375da6df8cf4744d7d74c47e7454610b0a8c5b45e7bf6f4c2f3fa40e3fe84a95390cfaffc1092d0ec1000a50e16f9012fbac3bd979138e604cab826aa5c23abcf3cd3b887900018228d3440759b465e606e8c5872651c31e87ec611c0e477a62f9510d7aad3f88f427f2678be76ef2d08451e03b8a7cd4a99a10135d789d4bb1f1574c5e01d6f1ad10058e7ce45f877fda81fdce01971ad08350d240b7d715d4e4dd46733e2eb3f7616559c09c907a2aee9796281ee0ca81ec2992a533e1e8a7b496266682ccb8710637a0990f647a7df49864d9ab288ed63c024409f34264f9e6c4b7ac1e174cd7d85588ce16597c474edd000b13e20722fe0d339643b6134cd46f6903eac63fa8b8d672ee21786b240d2b5b8cea0d79400d0aaaec934a147fbd039c75ed766e34c2259d4cca91c96ad2becf9c0f463fa95e2fb5a7b51b719fc63cae799e86cd70cbf6016ecc271f2ead29eef6e69813c61acccceae70188ae74db2ce23a19e4138090959fe5bae9d4be671eed5d8df76effa285d1c7f642cbc2774d815c8b3ab7123605e42397aa754e846ef2444606c0c9d34161b0a8366dde5cc48a6e75327cd2336d21e00151b38b9211f7cee57302ac310b23bcac2b35c5b6040d90124211f2cea78d40608cff48c9b32726507817661a6079421cfd89efa699906395135d33f85d19659a3197211c220d2bbf87ba80f6ca683dd47b0124efa7dc0f86fd76968a1d4498c9121f5e7ebe053bfc94ee0dfd050df60ac1315372e38234bee398b4097a1b57438e9e65a67000456930762b0c539a72ecfb43454255724048e17de46b1461dbb46537e0b361c9a7d34777051c730634bc054d06508af1a054d52c3d45e560062a4c300df0022257a82b9c61c266a631740b458b2959c3c4571798e338a46cf03f5d5185fe7e1f66b20f1ab12caeed231b02c83911410ee659043e78b1804c5f7c176b0a72abb81377d443201717f7090f12131bbe568e49b663f2bb9c962cacba00990c66dad60858a4335bb663b1c54dfae66eeede0ffdbbdb9f9327e9242beef1dee9b8f7b99cb476afa6223847b502db45cb5416b377675ea907badaedc032d0790f049c05bbabd116e4e434545e119ceb212389a0794a5be6a46c3d2eefcf9e2d5148b9f98dab77f329fa645afb232c9214450838c96dce24402bbd64f5bfe267e74db38cc88e26bc0b13c97b87f79b270930001a7fe3af4854654110dd4aa3dbe00bf1315a865c5e3fab85ce94a038bd125000e7de461509c8aa6f4c4f3a3f7a5f132b4a1641dc70f936d4675ee08510399d071931008954592fad892aca1651bd6ad8db16a64e54dbc24bc882a5bb5d4bf1261cc70d3165af4164cb6421c329c0b5cbd2633b8d33a6a88efc7d4fe1e69ecbd4974387c490bcd389a17a6d302b882f07af99c95cf78972465abe3d91957c5fe9e394b8a80b4e84a23bb27adbc20eb0737ef7bb2ae05618d75260d7c130f0b5b0d4a5e8811dcc5c61b2320f75b91f802bd2ef5c66f726f0f9d97c3e902bcff993ba23f663e07c2371d7f16986b65ddc7a72f5c09e04e04fb571406265f106fc59f59ecb26459bdbdec918e57809b137b10a3920280c94b0c4da433b738410812c444e432226e93de543526ef2911e800ed7e487bfc26fe5235ac707c2f9515ce082ad5622fc118ceb8e2227d920ec4666122f10a6e89beed4c2fc88cf6d68a1437e1799ee454a5d6922bb5045a803b7d2abf6ec0142c9579e783913504f05d1936daa05e2862b9eb03e56667f3cff24185d42ee43acf614b7c18aa896a442f86428a88b1940436c87f4867746dc782d1b958ea214b4925bf35810ec561a6db061a4e8630332187d88643220310621da70c6906838e2dd94a20904c352afc42b86f9f3b0b7e2e2fb5a6f52830f0547f81bc1d2b5bc03e66d670320805ed769de4e10eca311551137b773c5508822c711f237b5a30eeed66ed70e2005568d9ee1338743af30dbce5a281142434f983d7e49e9f8832dccc85bc0feab0dfd2b255a2a340819af25a2b34e192e6be87d2dbdd616b575c5beb12244c7851a5b24178b60c7d2926bc875ae6ae081fd9f134582771db5c67d1a81542b8ac4dc9225ced4f5e7c1025dfe0b7c27e3e5e59129ad4b80ea4e9e2139b75f1d8d1fb74ef7454b1eec1f3b41e7a630ac14866838a5b3745136a8f4904661967edf017114ef0f20c4d7d7c201ee6bed9452e480447ee89ed65a09e9d771ffb432f45d0dfb6e214e14f05ce4215cf4d83bb2de71d014a9a9bd4e2a8001fd026edcb7b3eea3c118f25e0f80d83a1308a21d5f044531f1e2f383179ba4221c36eab049f71351e882d65adbcee1032d835b3cc2d23137d209bfe0e537e7e11f387dfc3d6b21511e17d1812195c85504b1547cce4c6be8393f96bf8594c3c9dcdf1ba800d25d9dccf32101a2cacc0525f54cc9e7d8bf708b49dff25dd028d64defa782ace35e82822f88b769c43d34f172d1e8e0167c5917628de25ccc46f8984e5d64aaa54539ad2dd2b9f3f225dcb2b2f5296ebaeab286e3ccf882d8d7493cb2d59991beb145ed0290cec33aefd09154b863d4b4a9fc23060da21bf63423c8890bc2658f33dcc57fa6c13fd10d7b7d8701cbf8d333664af01c8a082bd6261e7163f10bc2a46c28a04eaaaa0a89b7a126522133b65b43947a20f2c0656ac19d05c22aecdd4820a5ce44c2bcab6af77258bd952b23b0bef805d9720aa3aff14ae5b4430579a14c922417e72c6f4481327b67adeafd550abc22554963bb8f1a5758cc091c4a410cc019faa075b9640656c5e4be81e01a60bbaed50bcd4ca37cc6f964201fc997b236520fa14c6500e8ccbbdd88906f6357060ee3d7a41e57c9e1dcee77c9a4139cddebc4ff4b704d8c616147c0f37518d8ee6689451853b18c9ad46013136bdd22a7d956acf74531cc0389f60888b5649d20a8f91acdfb42ef6d11f1e03bcb9b83a0d401161834418b0d899b012f7b71a4f9585926517d6780a68a30ecc8d1026e3c5a1e1801be61cabe17b0756c140306b848788e4be6a63a5dabdab2be78b8ed8289ccdf33559c599ceff57a5d6b3d30bccf48ef92406c2a31bdc0482f6c7987e48c18f95334ceec954fe84a33961b1749dc9eb668aa34866ef5581f51a6965632e71f56766c5ee6ad87a997f9a2ce71808ac0379de373d4c2cd731ec7bc89a173d3e23cef662a5c16c062543bf7f7c24c3829f272672d758ccfedec42bb86e8de55b81de55a8e14fcd40c6c34b80dbd7eff27291a7aa468446d811e37d9bcb3326b6dcc8c1e3fd3f6f87d92f2452e1631c77f989734c3fb24649cae464d6fcd5c392538097dbb681ae1657f181c577462a57b1caf5f2261fafc83ab685dc0a622d0f589e062df819b68e2aa74d0139b15ba0b53ca5d9bfb3156dc0808169dcc759714a00e25b5412320f30070570f4c1a343185f319360b938e084964e46cd38017291ec91d40e98cde77bf9352a2670bbb228ae04841d56a4ba9cadaa61207882ce86d1c3d539b5914fe1b69f81270e22b8c5b3317dc9627b459c540019ba0cc122a287d185eb8d923c1ba31f0af33e5e2fe1fa6020cf4ff51d54b14d831bc773ae71545588bc66e923a321a2fbd674cf8cfe6737a8256ea5859e3f348e74465f2e703c678a49b0a42d6ecf11e6bf28f6835d799f6a58745ba848dcf3c266818b56019eab62490395205890d85c02917a7e06ad4a7654517d3431bc01549a48e35c2b9795a1cbdb68e5450d47a5bff086c521bcc3150b0afb09eaf617e7ebb6a73608ab6a34b0df54ff24fbf00f2ed6b4723750740ab95278d0c8fdef82302a830efe03e631111e8bf7ad244d4a46c2f1b3d5888ebd0c44ecaa4789b8ad39977719831614d3d0f9bc8fd0e9ba774e92d6cc5aeccf561eb03022dcdb88508f531a760887ea12ee63b5dddafcf1cf19e220060cdf5e964c07507ddc580dc40664177c904fb8a1544421a7c67353a27c32ac4a6430b0e81dee521432f4682a4ba653fd1c2de5bd0473e4e0a0b9dd64eea84960d5058c301d99af6a10b87590c1d38b28b1bf40665798049823596af8303b1e0f45835c6d286313b55fff2c5cafba21ff7def4984e9be45ba397f8440de61a03453346712107afcf74b9902b354e7cf68f88e2201600dce42d949d0bfae92ca205853fbd6da93bda2b3716a9fcca7c4021e8ddf0e468d8d564e3154ef42760030819ec993547e9f425cb1431e969f818808a2182d239e50a06274900c14b10ed77754102645959d0f27c062a204a3527930a6d6630664c7469208031caa10ffce54b4f8c2f76c00ae79405a0943a1666b64c5e127443a314995e92177a58e3de540014d26459ae9f6136c0569f931ce1499652d11e1600a9c78ecf17eeba05dd9cba90d73640970fd24017275d35fc13bea25db976ce859c4289bf0150c207734e34b0a3df01f1697cd05bd21a12b774cf3ce725a07344a18b4943027092242a45dfb4f353252b980e343341173bc291f154dd48f3115a00e6b7bf8210f6fa6413d9182d8b42a3fcc10a392231e011caba282bcad1e1fb03eaa2404f500721c5f453872823b721358673b9d724209efe5d12603f394d01da4b9a1090498531cbe8640a8bc4bd16f79e14e9ca4cb33e83b07d6bba9caf2d34dd9b095a551c637a0a0ad4d8295b228bf3a60e084caa8267b23710af41d143a8e538d9b1882cc793cf73794316d8075ebab7be860009a63c272cc80e2d86d0c50574741a1953cd92db504e3b284b9e0171df000aab84c96185e46c8353d05b285e249753a8fa05c7f7584e0874de1bc93785e12ecca4aee381aa9c0e213959f4422f63a486d89bc60044a2e3528b31352354f7c1166413e459363655d7a2f3dc9338b458946dd62617a4be58c44bc24c70a871cf72b3d2a364ac9ad191c7f54af56fcd9d2c7cba7669a451b016e25228862aab5207d5e32818d0fd3e1bcc06d2bda05375373939420cff52a396138a00725cc2d2658b444250ccd8942147e10ba8c09f945c4239adcd00a19b2bebc9690690b76b0786d6235e5f9b01170810e6af00e020a85564d5c5ef27218d9f96cf81363e98965e003f9b82f5f3b857667d810b563df8098a875f8059a07a4bdb527c5061395eecf5855a49820210401f8e6ed938709b461322905691e79a4850e66a05770e385a6c417d03e7be81d2b0fc2cfbd2016a73229498cb299a0efb8294111bd948ec7f31407b4a769a0fbf521e3941a0354c488664078f1e696522e1adb621ceb11b01f87cc0272795e577cd9f103659fe57ee731c493b1fec47c4adc0caf51ff85eabce5c6c59ab592c5e0d1ac4dad69585f1872c1b2795c5ca0bdbd63da03814ac12d04ea5f5b78ca0e6a623f9f73e35c8fba7413a810dbabb66c53c973e24792b0663aa78122f3e43a8cbfb1f618afff84ab49c391a04a24055129059111cd148e8a27ac2627e04daef9b67c7fc3fcc78fe80536352c7c81e76047a5020436414e9fdf8ea7a9e7131f2a434ffaa1dd14e6310fda87615ff15db99ffad76db149758e7e618184fe6f2123981fabc3efcb354e095bfd43a74437e983f0a44f6e4795b302edc8d92992b09ccc958a2fc3f71407bd26aef46a258f6582c22bc0506e9f2318374a56783746132991ae379d7121b85319537da4d4603d74d9e79ba1c95a2c55726f3489a7c4f6cfc343d7c220cc00ac1feca41409e8ccc10ceb83e4e73ce696badf4965b9702410902b8be39321958d67855ece73da0b8e55afc6dda6d60d880bf13dd165d6155b13bd557f1487fc2fe9e762d2cb1e944b6f9c2f4e9382a6b5d0f1cf928c5fa076641092c1644a775ceae49ade4895d04a50adee4202ac3e7faa5910b7ace1c78a2f76000e68ab1b43cf50108ac8451ae12ca6cd01bae2f75bd92973cc98fe0db212e2544324470c0374d45e0f7a95598e8492d317da0427ade50f18192f6aac50378bcfe2c74bca3be39f217f3740d231f176e9dba10faab8a8300a637c4afb5edf5e3ff80e01f0b03b9cf8f97ae50266a4e419520a8057f0ccce20bce06730e3b9f396e737a263192c9bce66aea6b82412638e1ecdbff46d1f35be321116fad3c62b6be94e3bd5f4f3cd923a05e95ceb3ca9fd454f6cf867b335388636e2f608a7c74fb436dde94d2429447f43d2cbe4c9f55292e2219f2efef47901b1e3329b59397eec620dd2f07cf16a6f64a4225a13e7e39aa51e8c3a039e542d906094ca9aa536bc9123f48d8ddde6dd2450038b14baef9dba2b647451497430431874bf0300cd6c2b4a99a07e328e051bb8144ea2992b835907e45a5075bb26b5537f19a7db02addb4ae4cce175a5731f9ad676dbe5951dba6f5e7b9c59add65f0d276d2dd8750f6a86adfd1fe7e0dc8276acbc8980a9c9d3bea856e3daf6734a007f1032d1d0d123a7ad039995fa12c8232e189c42b3629ec240dd0b94b3294a196b7dae07d88bbe3896dcd28168eb9437bbfdbd154d712ca7c0b306fd1171204d488191b00b429072bdb9b35080c0668d974874f991374115a6576527ea66468a05b3d7b56fab1d86be9060eac9b982a721627461705ef141fcd743881d84820d2e9ed9526b6c69b80a5d8298c0b750ad7558908fd950274092e0c2dd4b71eddad239cafc17cc1d3c0ce7a79498758763366ec5cf0bcf2c4623422141f8511dd804773dfd53cc9cd192b56ff0d8290d1bfa95ef3aeea4a42b8a407672d66a534d8a64ff1c234f29e1ac0ad623c494abdbb1083f21f801c8a6c0a60687de2c934aee505cf5fff9ef96d10e2ea2796399aff486c843cc75bfa00dcbb864f2fe1053ce8f207e79fdfabb4461c375d1a5ac0eb2c444266600e9e8e1cc25d71ea97ab01ed7bb12c52e3b23acea384a69c29499b8841e48a5dd1874409f52a16934c641d54743fd473b42ff96f1b80a9a0cd8c45321480cb7ce8d26c186dd0ad4ea326de9a3ccda1d8d2a2caba141281c29ddd498d9374e1402d812a78cec23b83bc929208ea8e789f4f52f64136cf741670768fb9a7ab3de3d7b61d7d1a8510eab95cc2afcdc63c9a15c62bb39ad5cccb34a093efc98e58a273578a81161076f6ab1654032beaf30a8bb95ac3935366ba339b0519b00297d6c4cfd6c6b73b7b8b0688a124493d194b02e1ecd04b1f11f740b828752edf7447cb047ff981b2528bbc95ce66cc6cc478ae19f3572c49752caa6eeba79cae2f6a959a8565d09ab7ba95231a715cfa81aecaf05d5934cb786fa2b27396dcfcd138faf5efaa4c323823c9eff628c78bc059e7f02fabb64f2b2bb435f4a3962dd47cc8f3c39c93fb77429431cc47505db804be774e50e90ecc220f25f057342477c1a3ee5a51b945a7bf8e22936b741858886332ed00c55a0effbc86204441d5cd2c4a95e246ebd50811cd415b6046b225af7918b55d0cd852e6811a6c037d5352e50a6add8f353c787a2f8724d05a02a70c1337daf5cd1c1eb669745f9af356d9b992033946eac46342c287f31d0ba011a2b9be4aaa55257da91444c568bd7bca1a3a5278129c6d349843847c6cd8ad3992a0d08b336ba0b0dc1fce99cd8538729c74c3602d56d31d532b977d3c094baf1f542347e739f8ee8a11218fd6a017fa872fd1d5393341c3289ca7088e9159ae95f916e6f03b2f328b8574a049bc88b8c58264c4bf86668d7d5fd79f7e22d260953dc1893a4e02febfbe5c9f1c47921b5446add7999108adc9bc439f21b54220c9dacfb6f3802d20727d785012fb3e462e2f3cb1af9d999f35d3129783aef7a0c238d3cdc00729ebd83a5670637862efd8456c7310f6dead8270981ee08b6bc1480e641fb41e39603e0987f70426aa3f8e0c04b6ea3566ca49c454e964747e301dbb2b30ee708268b2fec938fcd1006eb0cc1cadcc66745c8e5d6bb9bd899c370840814dd8fa1b92aeefe7ed4151e2afc32ec8bca81d91a0468067a142bdf2d08f6722eb44818bc82b8a49ffd357c6343352442f1f6f9d518f65f47dc04fb6aec42462a53a33ed057a82537ad509ac7610e27ac70e527fd1f09127c2ead3bbfd28cbd0789291ccec45a9865f700ee1669a6882da973ebdba414a13d42c511c895214e776d53f327b51b892a01a09dfe6b36af8d401fd7b7781f3f1d75debc968419cc478410b0a0fd996bd62959d19a6a2f229d5ed1c7aba01dc94954bf0df612b6dad87d98ba2225fdb28a950b0be7aed89b15650b544e7bdfdad728f2a31d619946ad686477ca508a5ad09b3691e297bb1d98beaf3e76b8701a338b24a8791cb63958b12c15dc5a0635c59a504574db16916b51d0b199f293cc6918512015869774529e720298ad4771bce2f33e78467e8f5fa1fb43ca28efdcaada3543e98f02e7a289c2274c956f58f3f7b512d46684a1638512dc23c96282c414b2641e44168fc364b1a0825d16f5f0ec99151a7a13d2b461d4fe3d955f51548ccec453d647d96ce290289bc65e8a6033d8d1ab07d2371ad005c5dcad82b303b07423c06a1913b1eb948b085ad707b7f4ca768e88075ee22a1e336f21c25333b145cd579fba4e168387b51c248ec505220f86f6505ccce8a4eaba6608a5ac16628c589064b2e500721a33c4223c8711f0c58cdc1d88b895adb158c4f6b73d92c2158acc4fbb413f57cacbfa9e0bb76a2e62bcc4023cb17622f2a6a610cc8086906153b286e0783a018cf1e270c2761068ae806cd9aaf0732f2c5884f09ea6c341ad63ba454097fd74d103705f6de0d3ec567a4754e2069ea8b8a809775c32c713b3298b02d4afe81830145ff59fccc08b9f73b8aa710889ae7590542a035975a67074a6ef3b8596c32e52c8617d21e4a519970e85cd34ee2ae7d05e661b1448bb264dc6bd3697648ee2ef0523302ab3ea2b32812b615c0f3c0e960024f63eccfb7f863981ac094f3bc75dd7f0a483abc7b0ea3b577e4a49154f0fde136a44f6e2c9538cb1ff12f0af79319f8fe72067d303577b35a679dc8eed27cedf6960462fed323cbe47d353a043a511cc0bdd1d1e9c514dc3c58b8b12242896cae37c10bae3fa7607035d187ae4d0472671b70adabda42995fccc5f47e1fa04029c229de351628791b61fd00ea38d29d9ae92f8f163a51881268034397ebbc381223cc3370eca9ae39876650f3cb0ad8ba14495bae58ad1f6d55ab3c00b8fe61c355644cb3664901870824f7a04661c9e6408372c40d4ec18b474bc11009bbb8d1a07a20001015a515546e00e373ea74426d508bddda1e04962509398d2bdfca8bc069ecee865fecf10a577e99b6a2cdaa18700f2326c4c9791cbcb6f0be8f9de7f2cd7c365e09c7c546bce361333f68faa6c11f6bd66c7cadafdbe2e7fa150f59267190f66a5b53ce651c9df74bc1d36bf8d54ae9ac0b28e31a84861ada4bc3d77f82bc95605eb7d6a7d393819d6532b556215e1aa7be88f405973e015372f6daf67679f92a78d0d2052c31872f0afb8c7cd7ad556a7e75e3c176a0fe0c4961f61262e8fc46d541b30ca0c89e73b6566a4dc728ecfd3f88871f3f36212d616140035b388780200c0d593cd3773bebce072ec65b156e8ef91f5d3555805cf527de8c847241950482c9365a21d6eff14db05f655dc4adc7bad55bd792ff3a37d7aa9e64c8252588a61e3bfa03db338c6f369e39e5d92ccb3399c47d823ea131cea12d5104f27a31cc77061412f592172be4c32a7f4b00b5c52f416528a08fbdc30f89a081fc35e65edd35fa37e7fb4ab0b024eb3dc69b9f8968c771f9e61d8542812a04d11d13b7ffa05641a18fb4253fe66b2af2c2c6cba86285b9e84f6ac7354c15e5be160e346a721a0faf48b50de2e19a62aa469da50ff38d8f215cb0de45b22f82c3c89ac008765a8bfbee97f78fb30148678482c5a0d9d68158b8cc8d881ce1c7d1e4dc91753e0752caf10a6733867967f9d4220b011d7c21510c9933f5a83c1d3af60d6c0f9ac2d066f63200d5e912d6adf9353c34f28d26a0ade17c6545861fad7a4868f7e92518c158271a506d7bc195cfb206902a002e324e293055cbfc4dc0c8e6fe0bfea9664bdef759857c47112bc7b7366c064519e4eaf843f6982a4fee84ef52876c01cd4619fd8d453f73555b384059f926202742c76539f5494035fee7ff502e3b058f04f56fd5fa60a4fca6da50156fa887f081033c0d1bcd033c110f3ce198660b8372aacab2e3f6a94f4c06e630a85e1435c5f759d0c217c41aedabc5fdce6c9401f8f91f7ddd905582e945343c969915bf30b59133304f3efde3d1b64213678c53b70946f947815d76e6013fe6cd0cbc738accff8934761047e9651ab5d212128d6d49ee8ec641585f1997a5600e43fa33530cf13950f0985c11640876a5d32b4ce9b4914f117ec8c8f37824a425a7283d1f50517bc5c37b2f683b5f1ca4929d6ab86f485ec167086a1e362a087ceb0d7a2a429de34811358be21c82e790806a5fb8a9426b8342249167e86877d1f106ec60ca4200f613bced48b4f40b3d495ca77d3a06f66891e081831fe83ab0327272d6a59e4762d26143605bcd6b0d5221f248201797874279f948804a82d7991b4f8ca6e8e5fd5ba6d886a29b8966c21a1c072820daf279c87b43b82ec983ce0904f5a1faed26c3245fcf1d4beeaee8777fed75252e35d901a7bc719a87b6b2d1a9f774c3587d061673a406ede4bfa6f84d5d3bc375f698b6ebb5575cb3d3dccc65dd26beca694ca1c37b6f7ba73941c87d632886100ecdcf69dc7b785ce049b084cdeab21b8dd646336ade57bbc1ee83950b4ab903f97c22ab9a90ef606ba33ad078ed78dc75983f19c85d428931c44e7208c8ec81b46f6b5766db5fb2a498300469a403aa14606dc870d5393a018ed27ed33293c876963caa03cd9a87c41862d27b6238f96cb795f3be1f985032ee2e4f4ff46a5faff81c006c6d6ee03956e7bcb03bdb21f13e80319132d5d5ba57c90210ed8b8b6ff343d3e23079ce8af02154a5a855f694f1c9348cd80ca1d4d9742c4868d6a2d4d12a40a257a99d8af2b57cecc21c91f9dfc4d49786961649b580fea6ddb10cf150c70d4ef89db50c8f14765d0f58e608f82a40134de4d66df89a13164a042c3e63bed7daf23ff322c9e273035f4f65cf758f853c646efecdd0a0267a79cacac78fe1ff415e863c3f4d9225755340f23c7227af162af33c9dc0fa16cdc10f444cff0efc00e5b62806a58dfab3b33dab982485e6eda8da39af2f8038363372c8e3fc87c52834850839714d1a563dc03bd39b2fbef173a414f0974c73e26ae13d54201d2d440ea5530e33520620e1930d28d68d7d3b845a8b2d49649d576fb1f118eefa321547855d500302106638e709c6f446f4b411adcb6661da27c29d0ece05341ebd8d0dec048dd76fda457657ebabd1f2d056d0306a10c0827ff91b2c00bf2e79a746ed7132cd5e3290d0e38f00ac1d8ae00bf073caf50e6b8792c43f39f6bc0b54770f9566cc69dc4946e1664d5c9406241888fd803f784ba846a6b4e37f5ba86b51e082edd3be94a1f9755108c2ddc909a1b0d9c5cb84cbca0d6ef106dc56c46da8e38da21fdcbb8d3762e50acf8b623f2aecfd06972f206997e4b3bf9fbcff90a3d8fc42401f80d788dee45860d17ab0b35068a99666bbd162f83f1c84423cf000e0994cedbf5db9da1bceee529ac462ce5cd6a15ad239dbc191910b71fb6ec5e793ee8806a658f107a4fe53f83ffb176439f2f9c7f925d17edb2736652eb58e145deda05b0897a6616017ed47de34870531f5949fe465569fa4bcce097720e3c2173a04d1b8c23ece51ce8b3774b9c7dbe1e0d00ce2d2eee2c725cfa6ea54c9152ae5f07033551ac161e478b64f101d2d5a8d9b5171e181712a30f95c562c2c03c444cd471b085803f0f6abe32d5cf21651865b11a65c671a835f18a6c842e98b5b8bedae140278a6a93a224c7eb8918b9cc4ab1639b981202554972a49db3598a1a4abd48c71627cf69109e8a9ae3e823ab1824fe1830e452966b6240ec7c7895f7aeb44b16f0dfa0a9b5d84d075a1eb6ffe42874743138b2a16193fd14147f08bcf27e8ab48cca444f2706f109214a741c0b885de97ca4c6c1f09ef3e4612dd1164fa7c2344e0e00830a47bf49394302d0bda03ce337f25956ef741f080d63e10eecd0726ca109847edc45cb8b1a8c54f4172a0066a4982b0a96147a3cb145814617772bb6a40893500f41c3c12457e2468eada0dfd1674a6675273e7aa8e3998874a37cac33f5c86ada9bd61c9c6fc51aaa3e80d4f48bcd673148b09984ac850d7097c56f09897764780feb5330ef91797f0e432d1899464f08dbc7cea608009b22ecb349b3a7dfe4744c34f760789f6b439533b8ac0f4558ab2b1446495b1cb413680b333a3c223dd86c878ac93a24e04b58dd5d3e99e1f8ae3f8e4a539e4ff347b5e5db241c64f57c4c4f656e71495666f9e9b9f68f899763da9490d6cdb357ee953cc2ba1570a8d2d74a75592f2335b5227b07b52122d72d680bd68219b5ea83fd97175be8db888db89e0946357add3f91009696448ab2a5c75258eb7468388502914c0e0b480039ae13a3fdd67c1a32bbedcf9097d770e098ee83a93a94a8a27fc76ec9d27a458cbbaeaa12b31ff4f859f422f1807d7d0749bb4b61bb7fa897de2f9e94bfa20a241835a27cb71a9ef33d081ce7c08d2915511859db2427e776ab3f2c50cf20a10143d05c486513bbf9098bf09be6063aaea509d4fb70a5cb7dcb4b2b7bd597399f666dd344aa5a7ba9f380c816e6e1d0c9d954d7be962056eaaeb83a0a709d367a450210fe249432e28ac38950d46a340e2e80d600744602f22830c66748ca87953f5de819fcdbf51b5c5518fd4f1ba3abb2529f10325f07af9ec16e811d3eff9f3446c5120a1ccd646ad6099b037094e76a4fa2e3e1884efd05da60edb4b4131a531e1ccb2734070540450d86227231f3165457a3bf488c2303e7dd205ca638038ae5a0383325ae5e9835dbeeef0a37ab9d1e65377f18c95ce6207ba35df14c4d09a0110d12963d2503c2ef2f6e9037f20e869fd31a5b9111063d788b2998a5d705f79dbf57468a20883b7541de979362a5dbf1b1f582c3419b592758f80d2e6b44f0ea2c86ff1266edcbba8bdee3adfc3be109f26017e9c879bb6088339b7de0e2aa0b07e67da540a28cb0faf3cef865c24fce4015ffdfe1233b9ce80b5609c1d6e45a7e1b161787f0033df3b6558198b3c2c68d3a24c8ab21f23c17d1457fa1cb7f0b8a247f581e4c7c230ec4ea73cc5097fa91f9d190f64ad8a7a454bbb7223f0812d2e8dc8b79d3c14fb4c01d66121132ac82e386e4ae1d1b081b2d6e64b95b2085f479b76ad6384bcc7892b166caefe1a7d5323b3c1d39879a53642cb871bafe1ec5b6eb6d4a67b25c17a14bf945df68fd9d084b4f80a19c21da96e9c1e8fa717d366bacc2c20d6a238d3b554ee16c71e750dff88dcb6640f56cc60c95ffdba74f971c5d52133c7d9616a918edbc95f60db85dd8994cc9efd19683f47fecc546f1814142a33a5a858aa3f774dc2bc89d46a69d0daaed281cc6b51b12849716903a23efe04fec71d9e177253c9bb0b24a7eff95e8892690391d298f7f4e77098bfc5f56e3a6a3bd94813a25bd2152e8d8be7cd8b8be6818455d6565e007618ad13c76a3cffc636a73d786e09b15547b3d23ca72751f864b7590cbb3ff568c756802cf4a2c40512a988cc322e9e083e3afdeea31a19370685c644680cdb31c2f9e4346e825a8f895bdfec021434d78510fac3bf8b09cefd5b842252043210ecd26e77700999f254617f4f045876f8d53e3d804e86bd804050ae7ff4b95d0bbda830219086c1fe6e31ef638874e0d4470047722ec9fb7fc2608cdcad8c51d6747ce2b722a11b7574db638f8a88d08dfafb9e620f036c18436d111a4a7b2bc4e242442166b3ca2a957781ea604d7f4b2f1bb6c63a18aaeaa57422ca57c678ddf6036cebf83515095950e7736a55e2b0b87b3bd53dd3dc3979663d7b95280801ca2e838bdb170cbe46fc75e5b9ea50c8bcdc39a3d72907a4c626c5d3b4def8c07c9fafc6a9d4b6d5a877f5f284a3d510815d3b31ca1b152b5f3e44bfbc8349c44c8a7f09fe361a171d1aab14ce8199324f2b7a215aeaf8f87d44ce60a22f035d01d0528ae6c2dcc29d104856cde578d6b405415f224478757e3574eb1cf532ea62bf30f11a09dc84fc6ec12df378394acc800b715f88e2402ce70f06da19cdc381d801f729a64c4fb26df03a695273b5f7c5aab8e46fb1eae317478a2060556f6e71fbfe5bda5c2ac82f848efa82dc82c2a81124fb5e5463f659fa31e14792a15505829bbb50b4b6fdecd96b7dbdefbfb256c27a6fd4c567b87ab913f18cea289ef1ad34a78ba3c9dcbe70e0c53a3c2dc06fdab3702d1291d6c0ec7b9966475d015192cc19c27dad98fc97bedf92c51847f4092f30d99908da3bb0a7babd185704eb761de954c94764ef7500a77bdfb3998b760b7a5a34f69a4408febff50ab3587af60709f97a138e17702a10325670bd02689ce5d5496cb70b15106f0e1698d5b8e8de7d1e7467cc929b21063140ef64d2d290d8948cc9f128380d26466b44c1b177aa9d0c08b39ca3dd9e3459d9d38389109e0e65a201872f6bcd8ea21462c236b88732511df6e8e1335db19bf834b44e9d6729009383cfd9c04e66c68a248f4c1325daa2beb9245e2c8384ccdb97cd7041ac1dabc915e1ae3296d1031ad744f7b625b8d9167d2efcde44894c4254fe4b50fd73d32e483dfc457b8341169aded0d2e22cbc10df76940f9f266cc355c10f7c567b045286ab082125a4168fb7de1f430124779d66038aebae7ef14b9b3e843afaea27ecf1782cc50f739a4e77f1498b55cd156a570d9195da37560cd15aa089cdee3a17f73e4d5bc9ae078958586b38f00cad6cb3d335a0b7f83ae4374882a05cefcae1edc53b3742bd079c8c0c14c6ad3e3d98602012799abebea2f292ec450d1579cc467bae105e4b9280fcf423c1d8caf1f46b0084a4aaad4fb92ac66e5a358b761f0176a8b85a623df8fbdfe7cb00dee78ca61514173dc26e6d687b1398f5f3902a00fad8653be735ea9b8f93867f7ed811173c5b999d411e41041de550e58843c6ac3ce754112d59b99cf27bbf516085903f0f4179c48731c5f2e0a9507f2e613504fa80caa017cd3cca51eab9c4ef7801171ae46114773cabb4cccefc1f1f367280c8dc83a64934c9750d7f3f80c2ff3b6ccca8084fae643efa0d26000ad2698f5dc87e53c6a13398fbde3b6b60e64111e8b6798b4e4960a9e6facf51fad7ec52e6bcca4c0a3813aa6a3480024a48be74d9a81faf240d7788940c28b6f54e520fa5e31ca0a8407ad670b3d19db676080d40719f4b7a1175abf40451a4599da0d15b7f5371312b42691114618ed6f19dff3add042a7364462548bf864066219c738787b31246dcb217d549b0b57165e993cba242e20814e8136107727a9f230f61b50325afc366d6508fa8c677c1253a4486a29a267d8569d001a8ee687bf55fbc6995a48bd9a4500c70d3fdde2d06c142b1071e5d40b7627cc66bb68474c8a147bc26dacbdcb4d4d22cfc1682e8c18e335b1ea3e90d8799138ca842484b452ee94c7e97cf24cbcf8156244e4c79db40a08486cfaeecedb4c676c804ccf99bb528e9f96985807f53b30758441e1bec012de54e85f4e1321e0074d4e61b3d4d973f8a84f04615fab04d3bf75705724a217e8dec056794131b239c2aaf9572480dac15fa8b2790abf53faebeb9ee22f73c5b77b12c12c29a9a8526fd4fea034c327ad67fc488f3164dc0fe7d649be9ec15e38facf07e5a2fadab135abca706dcd2878d11bf8434b0bfdd97b62aa9f81b91a5370d530160ff38b4e47d9ff626e6efe952f966f617aa0debfec1cb97216cffd631f2707511dbbf6b2e6f0f07bbfcdba3d8d14dac260eb7375db1a401068025a9680d42ee6f94539672e7fe8fe520218e81fa7d3a631ea829548886e7cc2f8500059c898c49de5597dfff4e4d4ebbf1f7208b8c4549ecbd840d7331d6df3526f9fb110efe55951fe6f75804f24f1245575f34b92bc7ec3fd3b8d56f7b3aac75f9067dfea44bc3cc2333a8f0586afcd251a2eb2ac5290ba8c1cd5f4fa4f21e4e46c2079759448d7412c1979b11530fa1048edba592764777adfb6ac7d5c5b33d18f888c8dabcc43983928b413cdf984c41f59f0527d31ae6593c0bbeddded3c5956386573967ecaa1c71182298e6a1f91ec208e656baf4bfc5ab53aaa582845eae7ec375c85b4ce435ff07504406087765fb7427599fe59c2a56b066e67e9aa7c6aa757e61bf316c70a4df85bd0f90950c937cd4112fa4187b44b701427de06caaa0ed6bcb03bef235d88ac4cd2e35bff73328428493f4c8a605f230a4f25d8b5ea56b3e634003ee832a2d7aa185f6d16acfbf4c77185a04a6331ddfb532de410c3fb8d769d72daca5d3de42e890d540ce0f5fce1707ace1e8cf78fa8c8291895f3764e28bb2807c39166d364ef6cc2189260a6ae99d3170df30c636113f12ba02e4eeed109fbd9ba5299f2355d16615d3fc6b6a52a4b5700a3b12a16dd8bdcd0a00177d6d69d4402e272e0f293c371ca5f303d669c3ecd240ecc8266d330137ffb99b1cbf8578e493feb187abc3f87e983c77d01c4b934e4f6b583512710510958b30c95e3a05fe927e99826d83237812be3060f3a0e19470ba49b51813259f9d8871cd09cc197640e249de07d945294c3a7eadaf85e426848ad172631fcb99e275916e0a67dbcce187f33c8057b6b61987fa9b259243f2b56d81ef3a74b6d185e75e4402d2b039d0865e86af4de52ec3a05cc44a80d308ccb5c95b99d3e39dc98eed523810a0321acf6a4e6d8592bd913a8dca85c18c7d9d09fbb3180a548dd4c7eafb7505cc5212a4a50603fa9d25c193e2cb160c5446cbdaf720f7e539ded5c02a8aae5d9e18e60402e63cdf2d11798522ecc6984d4d7a48752dd5f751d463ef2531da29d77dbce6fabe43281c604fcd253fa7e8680fbcd875a86a0240d651684bca8da9ee858ec55ca6b2ac6adfede56ee57e8149c0b7e98fabe2755ca306c0b792c56deda3f262995e07ff63238b8aba7b1629eb8608b2ffaeb6739574a8320da8883fe998d33d2260a2513bb218eda8af5353c983712dcc825ece72c3e0256a39c1ca6a8386b550cc11ca55cce7cae3bb6e0cc08c21a71d830213d23232e0838fbe455b84b331d6956f9ff652c4a13c6d6ff341100f18571a54362e1cd6301d55224753adf4a8e7d385bac2eda1fb5381eab19fa610412ccf1472f912057501008d0281c57207778f3313566897f4bb5138484425fb078113a790d1258546b2612b0f8cf1b61a31bbf2a79202def7031e98b8b94a4f2118038592c711812328cd135839a1d1240fed6ddf861343028fc2ce5383950a4ec8010052f3bcdcd617ffbd753137aa5a5b427bd1c905c490add82e9f1669803755e51c45c7ffde6c369c8f5ea0e7eeb5ada7d32ba338334c54b19e7a9c3c160de23956fe9f1e2614c7b8d0699091d467374b5defaaf493212c1f885c766af2b0ddb97f3e32f4bd8ca93edc01d2dd2f8a6039aeb7a4527412bdf22245f078d72b6fb5f09633cb5b9407c50289ef389c11ea77db2dcd3eb24d2331e263f9ca105b90d0c0279c214b995d1fcedaa7200493ff019076d8be6c10d48b955a8d47c6b7c78d351c7fd0bc495752c530f80c29f0253b0390cac08c55438af82ae5978b845f7acad83247bc493656052d2a0eb3b59bef18cef53b3bc8871aeb0d8c311c5f7d8f4e0951c16e71a42570af892362473431e9786205abe8593584f4b5c7c4a9ab381f9dfa385426a76e8652dbbc1636fc6af75aaae90b913cdd37228d88aa4eabb76c9f9a9fe9f388a8a6d95dc305daaffb4ab28926d101ce8941f590916c5a73086fdbbfb503c61b582b9bfe74798878f364c860e8d1ac4051ec5762d86e02e897469839916323d2323e144ec81e8f24c49a898e7b382a30dba2f6f922c592e90b3c7a8cc79100505943888dfe06fd6d07490e59c0c5573e166d4751259040bc85a6a1aa19a88326712c42221dda5859e509029d9cefe1ceee50b0f2cdc1fc9afaad1c6bb3445e59f5199549abcbf3103d29229fbe34a6dc52e2bcf2023441e746b38631dd70f9a4a0c0a0368f87b398e146b6e40bf6618b239be0cf07c516f309d1acd3bacd484285d8c14a80baad0f992e8d629d296c086cd8e641c82cd1158123d23e1f18f2f994b0b214838ecebafe7edbc974ff1cc48ed218df3e4df2dc7bc3c18bbc7fb86ba0860a7e27842ce12ea152b62dc31ee4dd214f4ef37addf23c96ebaefc686472b9bb795e28ca75f45870ca630a670cd768e85a5eb52ce1a4bd407ccec636c13ecd07e03e68983a601b1e69cdcb39adf879a5ad3637695d57028deef39836b492d368fa1269948ed41a9b6a148c0e80ae12582b158d42e59716a777acd277b9419e804e2f85c729adf42f5835e9971f5aacb39327f1ca2a569fb2d2ee03564235f2c272b26c1ea21b75344bd612ae879ca2edcd8d0fbbfa3c3017f7586e5f492e8226e567d8ecdfda43df5fb5b89c874bd3f7c8bdc5e6e279e1f04443f0e4a3506f12b50732bc8e0d09d561930469bf301a598957d58a8f9d80e898c260b9a0ca8c8d2a63504ba6100bbef18140cca81f769998a4ae977c939a89c89716a5a3d513d3de5d8f6214271946238192ca4db175302d3a322b7bd6caf0b20064f54a8c07a5f8d16c35ec755410c5acf8c470a7485125aeabbc7126734b47b05a9046d1fa098730e1072b52f77d4ba5b2c8a0af5439303666b0425071bf2acfd8bf5a1bb3fe500bf003d3bdceb72623c3a6775a9dc326e206495c21ee8aaca5a9e92e9850003405a46bf52b3bd6939e5f50fa0acc0940f785b81fca053461156c116e81bada3d84bb5419e77af2f2dfa92efa471c140d24a8281002b1765dd161db760486a44922e50e3ead991541d8f7724283a7692fad609457ea3afe53fad26b9327cc9d4c11bfc084af55ca072cb66e870a1be0753e946297cb95226bcf1d5e6a969e2f1a8d292ea29c92693d17d84cf440090a0b885ae169435f911faad98b12f9a4ab34cbb21d2e7a364624b16803096f7d409b7cdc42fff4c83bdedc8a3cc3afba17da26615ff1f351dfbb19b6de3994638cc3cb5fb28d59e972ac0aae61df6c9a95f79300ec16ddb306f475c32d80f8ed514ab7e074105614b6ae48c7b03deba98ad4ea529f5a2004c62a28d233f03493907264e34305125228891047ce3c8a65989e2b888412029f1e98010306fc58a91c5cb6ff4eba3efab4032ebc6854ef6909665e988bb23cebebe2cd5d7a11bebea5cf387c26f2bba48a91a0b1048441fc7ec7069d7fd2968ea9c8a1fbfc85399b8224c775c2972793e72fa4f221e002c9d77df3d8567f73bb1741e68229397dc438bb1947fb66a022bb4bb6339b12678614d4e4524cece1b5c8bf5fd1f4e926350d381a2f27ab609217be18a2773be51da95b5a9ebabca356151262afc93379c7f3fdc176d6da97c93f6ac0c2702b1793f9ce9fb3455df050b62e2f4ab2d9be75cde28c2b5da072dbfe8070674e4a5f703c36f2821f847dad03e2a4fe9d6da1b54180a628464bdf601d452c6417034540e12e27a1ea25ac5298844ed116f7d96abda4f0794dc9e19e5165e1ff00e70b8fa8ef6bc33068eff2a1577d824d52d44ce3b2ce0c23adf86ab0bd00dc35b3431702321c87d5406599fb346787db759162a059b93a2cec2831ae6d6fca14a5f13e8827772833ee7e0609580722617863dc4e98e862992de6f3a6b793fbec229cf3995357f229398774c4a5f5546e59c5bce06f9e9fbadf2c5c80ad8b12a66826c39ad79b8b651569f87fa983b61a51c542a22a5cf7dff650656f37c85132ec8b25dc68fb4c05645cd438f44dae70437b6b4d6df12f361470f177fc955d9a6f8ce932b3709e69634dec95a58053b8b94f44e412ea12aceac04cb0f498b7b1f9de341361c3c4afacc294037428ced3e970f26f0a14060e3e2961f4aaeebbaa1e2a9a07f10f7fbcb31660c9caf73b98377b6af841b37dbfcb9de37b48dd21b8406504fa333f6bcc7c88553054ff7c1308ea1e11c07d54914f399852385f2d0ade64e998e0edd6321d4165ca09c2c059d60193c97a2f26586500cbfde14735288759b8194189a8553635e1385c688963918ff3cc91a377858ada8ddee4ee55d0bd386e35675e0154dc814ce50534be7e00ca58b242a27172bdc202dfc6e90b7a5400393ad30225690b07390e50d4288feb024bf993e1642ebc5bb218a6528f3591adbeae0a764d820e0bd5d6fa6f17d06a028da53abe53e9f2d91678ec667341891bfbacb22cc785c2de1c421ae41c29682a7fd58cd7af3a8abbf1f13769197703a429f7167783ced9e880c69e4ea818d29a9d5d177453101b20431e7501ec0da6309c21b25a08bf771c17ae059d3b3d448110e0b52e81e50a9d22d097e4e698601164b89b0f744ec37dd06f95aef2dfad3cfd48a88b861ebf0d57ebc301086aaa39afa1927352e00429d0088228a5565d24a3165bbb884feae25b64d28fac2435b3ca2dcc13cf1076ffd842585e751cc24b9c3a58c82fa1e96083694d940466b1f6b52e4d6c78c2fa3f89e04d3a497fd26374097404b592ef5fbd982be7be5f92f964befb7b358d019069425fba0d48e229b99eaa0b19d4269a5f12623965c7c3ba3a38707e9979dcba3148a925866053a5ae2cba6995b88bf5dc86e1c6b7db1d9cac3792f5a92bdb9fe25e49cb97a97fdba11879c9571f004eaa131ea63c24ca9bdd9040ab38660476691a9827ba93c684ab1c79fa872fa0b1429313602e18d8432c4195283cc481d8fd26728df11bd649aa68fe0d7249cc958ff243ac85c513712ced89e4e964b606cbdc37809811811c6c6b347e7a43a37cd9f11f903072d001d8238d264216d7bb4faf661744ea5f60319bebbd0f75aa10d930e270f97f9a6344278ce2b7448a07246cc9438a39b8e8c34baa011667eced7ac83a0c4d85c99969630ab31a79170825faedb4c41a9407710ff3bb4d9c26f7d050d445bbf17935088b91339f8792a7040873357c5668f7680ff4868672f41bc9f2c8da25a918f612958df3dda06022f8a42a01b10da15e331ccc640c71319cf275828909ae8a0055c2344296fc38ddfb1487dd6b1a06db7bd80b6c00498800e353eb94efb92fec1fac384213b43b4b078f0d11956755882bb0cc1da1ee6a24300d6ca355e9eaf9a93efedebaaa506e00e9063c640c0115b5ebf0af36650c9d4e6ce1256f40129821139e099de5893efa3b6c390bb3d4c7e2008604508ef40e40c5d612b680d1e7cd979032adad9fb425651c3483d531f80cdc7f98df54bdd053581fbeb3455b7129446c0ff20bfdc9e6d588101bdf4c2a785e872b992ca1f369857e2517e531d8792b9ea77fe194301c6577028bdfa2d2c60623e7ae78a02447a1c89b03d6a783d86d09aa27f48d47e4a7be8cd9a1fc48e4c872e93c083e915e6856dfe85c88aa1966484f4333db96a8f3d02e9c8b2b7bc296bfe113cbd96b241fc901995628443be22af34dc4974579345e4e6c5670da30f8bf04b58a2a6ba3af57da2ee8383752939ad3eb8a34f773c98c931f20886384774005209baf685a05ff66a7efb63c3b8c2ae401046682b4036d69225f9e01ad9f12018583d0ef6171427ef2bc7ff21cef7bec8ee7bd2099b75d3e0e48600c8afd99fcdf09047c51875916729793eade1866b26d907dfc271dfc0c3531a712274950deab3eb9b8372e4f9e946846e615bd9c563a561fd4050267c6e72bb97f65c1fda338dd37eadae7fd6a30f1744e0b84d5c22a415930792ed2a336e939d0222c803c3ca0d2187144a95cbee8cf26c127c400f3316b72b1f74cdfc2ec90e9c84200b51e83adedffc171c4b9419c927f43a1cd17643d69c22159a532a4359a56ff11e92a4f49aeba5f49200001c2bc429b3b81551c4221b4aed8cf1073bb39bf70a4b598a6a3f76bc6ad6902e37b20cc1da789b1035ce10350bddc3d091251436972212b7d43549c31a5f39db1a1d7e6dd805afd07b0fb942d03f52ca4ac0003b22bcfd45af3a929ca9c36fb93706c964a603963e28d9c0fa18934ac1d5341042ec331e2d90a720da3efa0ad67ba62b79e16b401dfeedd8ab53e4b742674c4d2902048e6aba56a4cea2ccc22b0130da3fcc894f33e15cf9079087a87c5d428c6d37536afdb92419466c15e4591ecbfe7c85be9dd2413d100ca693b01f0b7cfffd5f11c5e426979e73e985e4db701096ea348501fdc54aee7b9cf87b693d6f33d7cd4f59381e8c27d233e9c00e71388f32374be07596b8ad2a70cd56821966a715686334efa435fac0322760c0707e1b76680efa0df19e79c5309753c34b8c2a45651228042304b961bdb9c2a927d51ca359b6ad8ba7a37cdfbd6532b03d252579dcc4f9a705920fd0fc4067782ac334cfa333a7da9663806e9d139a6e51e044a8acc79d13893c2aa17b4b51ba12589e6652261e53e3d8874059b448f8cd2bd62176c403b78a98832e5ff6846c051a19b9832d62a482aedef978ef9ffd527bc4ad41e6bb0e9bb404616d9b424c558411ebcea2a1f1c3e48207afd43e99ca154b23a17a592863a7079f9e93b909cc336d2c367caa0957ab4d11326fa59dee54d7b373cd614389903a0161001db2434f697da4804eb69691623a981821f9b483cf4951007f8057cbae047a93460bd33d611f9afcf3fcec3f929a0288d578f282ec5a6cb8f211dc1962c33e4d7a87ea6baf27caa637c9e0158e2c326ef9e41ee9ecdc6d8f385a0d873d04098e37b379b47106ddceace910cfcfa720209c6b9a9152a503e9f0aecbade59dc9af1dd42227cf092749f9774ae8c3abdd5b332fdd05ee9e69adcb7494ab04d7472d2da321004a0eb796ac4f13d1e6aa17899e8594633c1de866d88cc535a3d453fc08fd252b245aade4dc29689b6273e526c1c9f3c5d5775b36712ec28c9b5b0f2cf1c71cbc1de1238a183320edd57bbe105340c87c8315fef9a0c96431f6f1020fa84e7db4f140e6f98c4b9ea7c6a8547d492175168fc4832a5fe934495d00d3d9d462bc82e250d5360345473b036e3a08751718d70decc97f68bfca63a436d56496a8d4729aec61140562732472e5f446c852af8bcceed849e7a0887fe2542d9e2c7767a34bd00857c00f1da4d733a6987022218d2d7e3d414302b34d2e07c07703553bd5a3760c03aad26345b89959c42b504ac14f4a5fc7f9f01e4190dbe0b7b60242a3c9e7677cd4d66923ec61fa12b49db9b9cda16d14d0bc9241a7d3da2347626920dd8745c4548dbf874f68c9171899da4ad6f3a6b306882029403d1619898889c74a9077b3e477f854e1fa0c3cf47a94dfe864c49672e17ecab818795c70ebfd2a77362912cbb4d278210495f567fa8958610b4fa9a1a36a049ee1a01c13cbf9769307afe26ef611dd0b108e4fe3ccf7c8ad557b53d15a01a850b99f65ef1e1275c0285ae02f73f67fd1c9c226fd70b234e29aefcc1575be8f03955eb69477cc3d949890052e2420d718658c4287bc2dd69822b5f391f63937dfa525f820838049a1055c9379012429a3e68894823051d16a2089586f85d94cc97f4506c5ae3df848197a4fc843100c160e206a65adcd22436d976a7543d9392c590fcde22a21af98c0dd6ca67c296cedb5ea440406f5e5fd66795007c99495294746000814c20ac4d95dd06f49c51a4370a9c1bf127093e3b8d0364352fc91cbe06f708e21985ca1956feddc09a393424dfb34a529da9ec0c8242024938978611501ee78b2d22c346a2e6759f6bf61be89dabccf31818bc43b1411180f933e89045dadb6c17d94a67ab7100a2ec88045c7912d569ef7a1de0231be91aeec71187c315f7c9541f4780dc88316257680208ebf3fc05ab5201026cacee0a1bd7587aafdeb126b0aa80982af2b1bba40d15a52a195714ea738f7c081ec0d762e78441fce0ea89b32c9de3b10a8fec5d2ed8555fffce5eaed3461bb257df31e785e59e1128354803d53ab2b2705a96a7aee10037504fb3b6e91e13c56a011173f1e5fe354f7f24f74c642c5cafc519c461d7ffdffcfbc32224e8c7b5c2f6f37b9f4a7e08a70217979fecc7841e6ce817b823dac291c13914dc00ccc2456d2f3d36dc175581b68924b7f060819f5b91adde85bec665eb9363309927ecd3a072e6a4ebf9dff7c9008b5a36a7d7fd15d4f0818b440526ddf2cf30446e1ff3a1bc80a07c0019dc2dfee84fcf1c112e472c39060196af954d8d177d15b94a444b2b09c1cfa36e08529093514e5b2c9ce52edbb05243b9f85a30706a547949944d612e36e535c991af8a30e8e4d240d964e637d5ba43f89f27232a62249703afe528ddf4941e440801fc48462a79e884f2215d87684821b4e3d08ee1c0df40ae7fcb85e6b01a5ae9a98b479eb1d0d3b6e6517039fe270606336399b664403d1879210f549011f0807e22c95202a08145e01e64bbb0351ed006e39d047750eaf1da7d45329b7a40e60799bfe9e5edf01c45d348ec14de2972bf7a98da49d2435b2e3439b668b669d543ea435c0f6c18e9af4040ae6878ff852389a2da3386615eb8ccdfc668adc941f3409d49a31a8749fb58cb274247e5c2e3cb4b2a471704a6928cb50713d88f52895013b28c7c9c97ba395eafe2dab6e8a3c75a029427746efdc10cc183f17f29fb87d1f08201b852f6d4067488cd44a35e12886dfed0cc5e01377e5416e98099210be1706eaa114db9f61017495ba2724452427820e8f37993571ca73d281d4ee2885c4fb0824a43c1d0e7e02cfd102e4d4f1db3057e67381b73322339842e596a4d2b4e296fd268836047b27ca1ea0169f17c7a61acf14bbe00f97aac8cb28780facd9fd0eb8f955ba240781651750e449dbd31ddc50fc274cb5b14a0e4ebd9048543ba99ca25046cb5371164f6a8775887614a834eaf53ccf2eac281ab9bac2ea880751d3cf5675f074e867e6ba902cf8a6ba460490d6aa381c4fd0264495dad8ed703029b99052a77991d40e7c6ead5b67bdb27d863d1025f6fd346f7c4c8edc692fe66285cdcd28d7a44c36033c6760f0a2607fada0f89ad49dde1f6412ab2d07528f78abec2117c9d2c4ab67abc0141982b6db4f3b33dbc0c5feb09865668e77d62b7a2f29733c5256d304295d40e6603f08c917bf907ecbfe5b646db9c87ca00f797810eaa72c8e9bab88865bd6509bd3069c91461af3ad0792432176e8111d4eb8dafb6bb8cc5093cd8b061c78021025f06e741607b4c75c714968fa5ef8d3fadd1351ccb6a314f3f5ebe627e05aa86e70c0f56e9a5977202cd447e756a41cf9ea9b8bc7610683f9156c84daa49d73c1e90ca42969350f307840a80454e9881fb448bcd4c086673d3d783f7c6abe423fa97384610f62aceff204cc41a23c43863a1c10d290d17d8ae57f01cda4fe26b49251498b7348be4cc43c452b2ada835de987dc054a5d1ee71e17ebf83ec3f4a31ec31b762241e39db20bea90828443376a21eb670a504a31a2edadabb0665987045cd89781c061a0f5e66770cca3d08acfaf11db394d3b3892cf4293bd9018c47f04d110f503e70dc14ed4bbf06f887caa804cc4cb5dce9e8765148045dce9d98edf5226ec740ca34acac86b857816c1c5e484cc37f9a8dcb9c230b8c9ff46aaca9c050f5ab0ef8a4fd8ce1de4cd49e8fe4e1aae5fbf0306faf38a7cb7e3a27e2239740a284541645571413a603bacecae41457d47086a85559b3a2863507279796c625286567ce9358f89a58233623ca87f5c5deb972fc286ca3434cb0c094a279935d53e02602c96fddf3b553f5bf2f9807e87def19d8c00391bb9cef6e52e943e89cbf50b9ddee545182714229a9170da8fd5e53d5cbfda30f7569aa6bca034d99ea2f65f15b61f76ae514212c0711cba63ba49d8233a0be4ec18a81455379f62514eea5adfe46e3a7033dd803bd55484fefa49adaa151580f243f90c37aaef472984748d636a8f874ee6c295f03a13c17f87d6c955f0ae432c7e188879865957300f8ac624c0b0f42ce3d55a3647f98184a213bca0ff12d232a0efa53a235c06412e90ee4e662cd42ec7ec5be2e113018f42b46f67eeae1e26ee3578b9b51cb778de8204f4635e9d0b2e955b96c7b17d31efada48b07ca3934fb9903b1b3d12dc0edbdbd95e0f3c504e5a388573bfc5371b55cd66bd0c6fc193d8b6fc1bd51474a821b4d104a77f4c725bb53bc2071c192e4c0d4e874742647b476f6fadebd2db3722fc0fcc090b8fa0fdbeaebfeb403b8c58765d9eee984a6bf42758703939862091e2daec3a4b694097bf387ee6ea3370b3472f1b0b041bc0739452e15167e535c7fe01904c090afa2f05b40233a40c287d76c2680897bde238afcfc8bd8c1d2169dcfa2ec191cd6d75af758b968e683e05858e5f233cb30ef759f25ee92f0db641fc1f1817705eec668560dfe452872d622eb1a25208950708affdb0a41c822c938ce3a739b989365dd3e44810e3d2b567fde7f0eb0ac41f0257702df19af13099d6383b7874d2c4051bad4de44da53d10a29145ca29ca77cb9ec933c4213662438113d32c2d28819ab484f498fd1325f6be1a35f6340e4d2402355066d89d49ea7dcec8a24e16a192510349f5b2cccc655bd3b0a5f80e3d5553b182a6c120cb277df22b17b61a2a811998b55c2c27a7d897a48b284c8a5edaff58dbe504905e2e11499520523012e9d3acb3f78f6d614b7a495b1e7d1bafb2d477a2e578494d31f9a688ebce3700a66c871c703003ba003562af4fceca70568250e1135cb29522cef7acd23933d7743c4243ee994a70bdc6791291884b2c58f4400943c8de385eeeaab0a34fd3220f6132f3c1d9c9ee28b0fba4005652aabd2da7a682c0fd9a506506bc6a96cb38be47f1e78c3e1c570da8001943dae61bbb0e8e82b6cab71caffb4cd683b7b0e74188a8d84622234b947a6949046529fb5e0bb4ef281475ee11f6f13a0fa66bbc7260fede45132ec5d353431a174ce0227d6eca5437dc30d8e14f025eba8090538ffd69e09afd28a364b16b1076b55e0332282c7ecbf2d3aed3cd9d660bbe64a973d104ec1096b391aa5b0545aaf97a0c27da69ea72a846b06d37ff1a1f1e14f107c85522900088a86be5bae770cb1c4aa8227286c448f708471a141f0710f9208a6ff956af7f180fad6e70c12b1d7a5f96a5db9feedbf154e788593d4d28186667b6a936d1d84ac481be7d7f8fe1ecdf312c2a2974819f88690f15a7bc8c20430569a3ae21b09233fa33c6e1fb712f1f9c45a3131b1ff0d6f70000320366fda1435e48cbde7dadb50188c5c03d02d58b4975f6c98ff25d770445228fe14d8960dd1bedb21dec7012c8f71be627c04045fcea7be56229a05eea12a8e867e8a45562600628081da48cf6eeb999116d4fd777988d831a70778e7301edb23bb3adb97d6d8fc96a1105ee99345292dd1a3356edba89e1a622dbe39d0ebb6089fe2ed8aa10d313703364b1e983e9779316e244cf6630420aeaee85522a90c3bc319d26ad31537d920610c19b96c7efb74216d50fb88a43ea02b18b99e91906bcff593a12520b0fa78cd7651e50abe69755a16fbf811256c27e153f764f1c02a7f5d49ea252672f0bf42865c9dec09e12146c7ac5c80567a9fbe91b5ae335fae54b71f778fea92693d3eb55e8aab5b4ce218695acc63a5ba8bf585df521d00600d2c21b891b2c7e9643c79419052ea356cd932a01b4621a2f5fe1bb8ff373f88880bf1259dd226cb4121af3368c5c47299d37545910b8de3684128784746499cd3153233c3a809a2d34ded50f6daeff0284393fb44be8bb940168b3f9ce4f002ed3c7f66a96c4f6ef8e5d12053c06523dbb9ad09087d89683cf99524fa2d0b976ce66762f1a8d608db0a2f2a7ae34cb6a52aa43806681a89e73f478d16d2116ecaf2f24e1700ec7082f6dd7a5441dafcd58644c9527da9228aed81234457c7669c1f5a31513dc55b238f4ff46e83368b5d315b128ab65392aaa9c159c0c58d4b1f2a259e91d03e27d541dbcf48a8d4cde0915b327abd08048e68fc689c04a194c94f8c9099c264f201f905d10b94d531692073e0d9904d4109a568507945c610c84e3b146368f1c9dde153f4e3b4facdede0e0fee11c724b5cd432209aacb6ad2bf93700533f91da8afa052986255949d21d35cdba0b90d746452724aae83350a0e4a709752f11b358084445252a27ac1c5026c07bd2ee30c6823b593edf733c2680c43cefe2aa3555bd2ffd0d9bcc890c395380d06cd48c68469a8491a3eab02a63a2d26fc304644f14785921a0be623d87f25f5a690fe5e52bf4c7d3df1d4c88a2eef77dcf2c94215d527f5c024b614784c2d1d82aa22fb709073b4db4a191e243ed59355a5cc372da7d51892611e152b7fe3fb96d3af3b5ceffb054891a176eea9eeeab94fd95d2242bbdbca5d8a121ad2e9871a966688fad393cd334ae60223c324ef2d9e182dac0b7eb8b0f79856409abb944c6fe6721a0078eaa574996d4899d04a825a8123464ff71dde06a8e616f31ba527fe919c2f19de1f9c2ee49d84e612293d83ffd4ef3392075dc2ddb88b63b6e01ae733422a8990ed6d28c7b25d82df556af71f9b46498fa58b6a2cebdc112f2c2b8e7f3ef04ae25966a0c2bc6dbb0a7759a0d15b13cd8bd35b3610bc705ba57f9881342f34bb26fc3da1ae7d483b4ff2d46728764f2ac62a1380b3ac2cc2c75f5420b0248298041bc47c94ceb6d504bc3eec66549799ebbc46f88f974f4f6d83419ad5274b696101db86b9ac414e3749a15538d5fee5a981fcebf2aed04100ca17294f4efefca2ada8117f51dcc93bafb882d60b9b4bfc53a080fb4bf0321c212eee528480bfa04c20c4ca15860d40ff036f311815711878ca689e81af392234aaefbbda6b8ea2ca5b4cb0a5aaf409a45cb91853070b89613477ff03463410f7feb4a09c450c16850d64cfb6cfa55398915c2eab77bceb366414d6c36b48e8784afc85784e36ed6ba95f863a9c400be986f09c34774e7c63062c804099130a9aa71771ee0b529b8f382fedbd58ec4e92f929983e4f2abc11f189bb9f67202726092eef4b0cf4324f613859e72eac25de4034b8e2588bfd1261b1aeebfd227755869bd42093c572aea7a62452b0a54a8d97ce911a24f427cb9d57a88857f16445e8a3dfb3a5035810c6c9cbae301a34b7a3dace657b7d5bbdbe444cb8117f56e0a7ad36bd1ee05c43a4b7faa02addd4a5374cc53886376445c9f753a79c6344591a0f78d4a625f83169a1057a200e1337e7a05e490863e090d196a1e2acb5ed8cd2323fd8514d3d0c13bcb446ac827e8126c11bc86f2dc980ae3fc73c2d9ecbe58e149f57a5f7143ad2b5459eef0d82cad016ac8b4f3281f62ee4f1564286a45c55c8bcc4165d351453a9de02496c4ed40cd678aed24a1e906afff1d56bb917120c7fa9c0e6410d62b153ed3ca29f3f761ce0c8b6125cee270409cd88c67f83a8bfb5963b4639a4ce7298c87f6b441829ab30473cdc854c93ab5a87431c031d748eefb4dff3d6da3349254fab6f5a42855b0347ab2c67cc996ccb8daee17fa7f1d442b76029168b9184d84161ab5c29f2e5db2a9a61366e7611a7912b0abe72615a04313fb71bbf542819b0b4b78ab24ae793905b637409b7c3f442f955a7899dfbd7f417af8ef2dc79b2e6a7d1134041fa7e5e3d122b5803cde6ceeda72519663842c544f86aabe17323c1287d6b94af1c19d24f29bfa83b576ddeedc0446f3f3d48f94b9b333c2e99655e771a65df9cd019df98c77f749d46a226bcd884b4fd82240efd79fb4277ab0b38d8ab95cf5e2a649733498aa610acc4861cb38149a038090aa530a89adc718c17ab0f1d97bc3066dcac55a37760a9f3f41bfc9ebeba5f90219712dd18ba839a794611a3f9764bac2ee83a07b893029827439f0125b2656f04245a034bcd33257e13bb78b85d1928598631c693d7c3142bc5a292c2a6d11628e1453b5d319e0be99826db31f4f96b04e40954a30e67c4c9c03ae1617b8793a2e170c68d2d041325dfc829bd1f2afa3e5643bf7d819b20102ea7f3b238e4af5e83b5473cfc1dfe9715ed14e63ff4bda3b56b885d251ae2a4270b70aceceee95e00eab11d0fb04bcf0342e4af935ac645a378eef89d6db6c585d9a46ae17bbe000a4e89ddc7cb52f962dc176d549af8ab7de1ef912d1b6b865beb06cf3712924f598bd41ebb2dca050321d94e58308bfd3c007a8900d21cf148239a75270126155111e71afda5f1fc4a62a9a7006c59e57c9815097ee086322be199dbfe9ded67da0e0c0dda57a7bf5a19ada312bcfd6f0e69e7f7743c2f002a477a94ccff151e20aa6004fbb717b20893bb4e5d2c7f9b80eea07a48b4eeaa2b515f4b771c7ed065a1ce8b61027b1d39644950450074329a02767900175030bbd6f2ac6de8c06e55c0392aa0bed58e7c933ff7a91c1c4a6a596d80bfc75c5f829517cbd23c5dce2105e67f05e30ae4bb32299e8203c86d7a81a5dbd5f1aa49814c15c8a174dc43846a842a664cdfeeff5a2b6737b832b72a0c36f6e4ae6bf23ebc839306c0fa1b21bab1c73876f94cdf105202ed55f59c47ec832f43db69e263c063ed0e559ad2818f8017448c366ad7349e3bd540a2cbe0322c8b6d264fbaa62d71450ee6888e9f9a1de6e83057ae106b79d604dcd02db7cddfc6a41dc82d4bbd2fe7a25e48c6ee05abf2354455a0ccc17a9e06bea101c254525c2539cae2b40455ac7a822beee61eb10f53894a8f2f69e0114555126964d131193337fc831b9eee7aa0d5938b282bf6635e1c6d5afa43ff2316ce278d9e42a88edfc5f3a7a82b1d729a051473105833efa6bf004c7c4173e2cc5f127fd27295e592fc857beb4a40d3b4bdd32c8c6329528ea18649c8cb9f244808bbb6cf778155541066155865f182648ced1be7e939c55293f8694d38c2f827d57155e5852f7fe888a35896f6b25f4e7aeb8115c8c47f77845bac36dc38efbef3d00612bc08a0fa0048f39fc1517316c2b6935c9e7f00613ebb57011656be8a93b6b282da71112fcea018279a8e661098df2dba2680cb85cd439fb96a4e440bc1e5f4494a75e850adbb902b278d5f57bf451c5a865a0964b4b8876539ac9c2af962dd1b14f949feca0e1457b4e7a8cec15b3e94d6f4f9a79511a9314eec626ca43c9bb725f3f94a8112daa4a69b13938de7b95d472ac0c34572d64bd235495c78dc07e90ec4f72122b7f216da9cb445bd3e5173a4e4d2726c009f7fe66cc7d0de35300078ef4d32bcfdea778feaf8bf13d1b848962860f7e4f2fb6f1cd5f30f3638fbc6eaf8919bc9a38f7f487140213e2747ce838f352c966ed8b4df1d4f3fdb05c461b4ebb6c1fbab78277d8bebc293156c9e0bb6c9110f635478a696d046d1a457ca41df80b5ebd90f86963b4351576a95610c459c53287b285923e6c80aa9edcb9df943316b6b950bd42f0b848b0a5f7100a26c2c9892159192a474d54337d5aaf73e769fd78f444520e6b64cca12d6cca6d5944cdd6002b39f43081c3e4629edf69527ae908d8f205e8390fe30024b80e87e72ce194b0d346bd2f30b304335f171a4072b187d128e6b78ebe7652a0dd916ec8a50e7c94df9e5ac4e63757fb61d0e6e29497e82526dc9d46ea8a4d9799fbbffdbc678cce537055b0b2ddc7ffb6e7df6dc0c4ec312a1861b98ea18f5b1fbcf2ffa141b05ed0d7108b7c51d42d83fa0dd0c721ab2c2d580968dd3b5e98edaac3ff43d2990b0325b78e2e52b5db7b9bd6504bad398b5715dd0a3c87e660047dba7dd98395fe8af087eb6c110f5b309e8b36bae3e1aba9bc186a3c451d8ce610082e68c6dc04d99fdbe326c5a7ba9d10a9028295b25840909ffae8866c329effea53ec89111400d04a30071148ec59f3d47e6525690cb109814fd1f616e674353de39e902ca114527b2756bc6a70e840a7fd8082264202c6f499679bcb46a461607512c60dbd56f0f50e2fcf88798deaafadacb34b09ecf53208b952963206bc1aa582e7ea1f2a102c03ba1eded1581e5e9107177c928fed0962786015fa1b932e151f40824b16dc9122c38cbd7323981a2630df5fe372e70c4b21aeab460dcd3ffd43125d7b655e746b043a32fb5744410277abb67d3ae21248f12b0838eb44b81de527371f8d798ac97a8814723a43a58bb20f3eb2a8823243039a7f86a56d889818c1e6818fdd575e757548179cdfae270cc45a774575e9906f1a8bb49aa4adf14446ad008c6ab3c57849f8041cc4156b39440fe43732b0e9b846e9cc148d1eb2d82494a111a088c7d90b50ac3d5337b102dd98c9cc4dec34a799ee9cc56032ca4f458d4a13de73f5d614716b7d940d3823dd78a4f9d97a5c445d1506b67fdf5a284523885049290c1989fdbe3faa98407cc7e7d5a4ad1e830c5d2258c1b7c7f307c384b8623cea2723f450b8bf86114f952ac293e4edf0c6eb2b0fac118887cfcba7875af9b14063ee8ba6e28a85bbb87a49e06366beed9b3e1254c19b13536bccc2ad44559ca81c04210e8adfd59edfe2735c98f41f3c35cb72207a2188caf9391893dc367f5765923b0430fbf72f022da2c73ab0f59a73814c2202e8cad0b80f3b96093050b391d0cf47e07302044171530ae7a14c28671011250f02de05ac459bede9ed2839785a42bc7f724d8ccb14394be2eafcbb684917f26d02f272b5f2f3e4e7cb71b8c3fc1c7628c7a9147978e1a2e3ca05f9ea9c89c525b929bdebeaeb5e02b6a2f36eff1e81cc9ce14c5741f9011c676358e7ea596c1f3e674b4216d3e393065ac6c909af9903b627f682b3f51bc0c804fb2f13a88eb46d1e2a9eed89c6491b538a46a1a585849d1f7ebb1bccb641683ac73bae51604305af71205096d9367f6b624cc540e39d026163b7f2a2e4cc4df76bc7a6217c497dedb071b0affc451e430e7a7ed02d94d114e18d23cc666c9e27de99f22449c5fe9fd9e1362a392903b59da4e09c6817cc8d2405ad5bed5f848acf177b6b9f8bb93a6a0c9d3e9b4403a1120400fe517bac154405d27f16890a8bdbe4793525cdb3beb78eb04b5da50014c8ac2ceb1bf21ce1c65e26125c03f1a72362effd832bd57100eeedb2fa09c8ac61040c0c1ecbe9a345e0089c2802a733da80bac7dd451c82145fafd8e66a50d2138054520d5ba031f91026e1c1046c1253496c4182a78c127ca0fddd9d93d5e4a8c2a7b01378d511d92e0bb2694736e7fee406bb3945388e8179702c2886122034132895c1435dd84e98a460a06d1922b6b0882e3fa02e43309d3b058598cad3da8253d470174391840093e1b73e53b28999f9712ddb814ebf242c75d377a050f2c921b76c0e63d07bfebf93eb28d0bf251e03af5ae1b79939fb52697dc44c16e1dc94cde8e3893bd26441f64c4f05067b52455bf38434cbe42d7189589d6e4844036f22817d1a5952379651ae5973c269502589c79b1b12df4ee155594b5c994c5648a4fab4aa0a116a19dd69d9eeb09b49b6b946d7740938636e4b194374c166cabcd40f01d2649e75b9bea1f892040479cd81a638caeb5bda423e52d98919a343131e397a9d76e2d115526d1e9d0c7584520a3dac293ac760d272c0cd644df120674bac1fdaf8e3f461381178b3a241c6587d2c1a1c90a280627a789c0ef53d26234752182eecd499839466b6ce241a0be09016fc27248bc4fc1459922d4160b752a97a217c4b25070032599f6fa76b47bbf59a98f44e78f46289654decf65c094e554cc28ebe8aa28f2a97a5316c871823712b6af57c33af74e84e7bee7642c10b3de00546262fa13845a12fb022f393968ee8d78fa76b7c2c5a290f5bac62d2e1ef3b7f2e9d36e0efc53bebab7d0189190df91299af7e314a4b423df5cc3e7038d0e430ed05285c5040b93fae4ddcf821c92d15b5f4c4689f04a16d91dec4e3207c94a5b004ae9941976c457ebb43ac7a3e151762600f81195beba60969b974f9a37051a838ca55bccb54db202b5c9bf7f7c9c2174f4ae63b87696ae8eec327cc42f7f39b7aed9661b934fb5ecd795248ae18bef95d04eb2893e8a32864b3d4b436e66aa2caa95fbaf37e3cc212b48d211d466ff79143f80e042e8bcd1d12821f16abd4398d70f72da5719b3f9ed364d365846469858e9abe7a328a8adb546ee5df69f4995d65125072d337b04a89ba2c758b508467baae1c8e908fef7edb0ea04901ae3a75d0d9458f6a6a2c8f882b14c257f2a2cbc5f4a3dd9c0cab737b608f98e5aab44af0245571065127c8b7d87ff2091a6588869f45924ec6eac1e7b7c214b8958dccec5b1ad23c4113dbb7a086cee6d37bd418ef211e768c70dd0a2ddc054bd00c6b4251a4675f459a53bbe2407b23af4594c04d09d55f80c1277b1ff595d0ff6c7883713b4822c48bdac676df8b2363fab71ca592e69da76038f0d686159edc674f7e3c19a7ea672835b683e29f0cdbee7abb995c74229fffa2aaffe43cc41a26bc1bbdb7498028cdf51e394d9c0b204203a71250e1b0618831649b0ef20e0c74909f0530afffb38ed7e4dffe75f626598635c3e3b340c420696615a592760bdd8686b1a1b9316ad71c53fbbe2cd87eceaa40610b063f476e37569b169e2ca439d1f9af9e8d23863b913fc6863d69abf938418790fe3794e3c6dbc4cbece03b5dbd5830be46843b1b8f23b4b623f9294888b1cae37e2ebb85d8d381562c3e11753fcea36e5d0670733c01d1754dc02538c7ac675688cdbd4b5cb832179e9512867a2dfa39581517ace6655b8a9c0a8a98474ec0465eff52ce06f711d324171540e212455d2f297a130e73cc8ab82696746bed2621bb9fb17c0b8e431c0047cb061798722b9f6f58644ac6c735e6686ace4ccbc750ff978f208db885e3b11c765023e8d554724b44bb5ea87edc1e7fa59b3e5a341e12aac979f1e9ce9b793e8bf671426aa250ec03316d2c0f6f77fe67fc60dc7760fbf4696e79a33b992300584fcba9a502fe1905757f15534b347c7b643db3926eb0f86a7fa0ce25f3e2fb880893f9d4bf9a510c2cf05218ce216ae38738f032a86fbefa94ffaa6056bb72948725815fbae3262133be0d4932a70f3d006e2bfd9d450251d25bb3c777553bd59b5f4b73f851af6c05a5db7f02a6274b82bc4a7e9368f9f1ce621bccde0b07f3f19828ec7d96bc8f69891ede53a807bd58e25cf2da372181a45b99b9915535eebb505aac94f4625b002541cc9a7941323b1bd3672337406eee40a16f169b23aee122255369982ea24605245c626b613b968ef4514a747dbc9180ab04c9a8aa0f35ad89f8a53eb892b7b9367440dbcae889661e56043978d24e8884d23f772b2789287049f308d266cb02a4635afcfa584e6c3d27eee09043cda7681ecccaa9e40aae3bc9a3d0cf18a8eb9b5ec1fe460dd495732334c98f35707aa4364b870e43d3386c8a168e4ec0aaa4183c9b8da4d6a3a0afb2f4aff4a6b3a94c518811ca7a291dae6c070c646df3b82095901b755ae0c42428d2361e09fb0168a8564380f20d582a584472ac1ff5b029d05e8c94c0961ab8a6e25814887e0ae9e060866e21a081dcdccc0726903df0ed29092f6253ba087cd176d9c1f429ce3dc77e22031f880949af1ee8fa6965dd25247f815437783731b6cefa6b51d95fd20d4e7a8aaa6abbe7192fb6ebad6a35c8876afb480a06b439b6404612be9b246e7ca2876868434fc244edf09991806a26d48d83e32349cb29eafd93bcc8d177288a7d4826df46ced05eaec1b569a0d1e148501615a79cc77e14b366f3c458f211374e4d4c7962c2834bee162ec637a5a740e0d76432fb9798ac2529337b51495de4f87c652e81182b64e1e4c3019b423bed0ce180f6b544c0ee1b56dfcb306cd0d7481d20f109a33438e80954e63a8725e2270f3331078766f44b0e7ef9dcc86563b896d86ea732cf2e0c8a522413d58bc6941ea3ffcaf643d62ea115e7aa66077a745e2b8ca9886ae8170995a5ead51e94481d685960e2fc4c681e0f0c95801a5ae219a3a60699133158a2e11f52f366cd75481321a4489952f5e092facecd34023adbd40226814230fd32fa02327bbdbded81f017fe8ff784f10b8b20e9dbf45d15fea577f4193b421d69a5bc3566acc88c368cd91a13e509b65de000a6354edbbd58fa8499958096b50d2f07f3924b4fac6300174b2e2ecb1e22936cc62161e7c8d30ea47bf20fee52b06cf65b68aabfcf34e993f8f8c313aeb37af400506d8b5021900317a374f0c7e602180cb1b57f831a2540a95cb51956b5c37eb46a25cb337dad25ab903b2513750379af5f3c0def5235530b06540612da868c1fb83370392da35e812b90eb5d4129ee60f80549e4b2e560a00e6011a740623a3722269444723adea361b792d7c46b3fa6b3411a9073e1ee2bdc59f98ab8820810501d21475dd5cad9261f47d8756148f7e996b990f50ab8c019eb710930b53acdcbbd21b13e33a06c355a938937dd62bf662f4d935c4c389c7f4c3cb49ef534e09af72b6fd03beaa98992cf81d47a2b85cf60c6af9a672524a73f75b3855fb8a852ab9bf196128f04bd9e2f66e8eeee2c3fc254818c16e00e7df69f10259237a10831c3293d4e0e662aa5ac85ae38b4c78b421d58c9da69b05bfb388f943699c5dbdf9ff8a5e0d39910850ab47fc0b5d0c3db8cf14ce6a42be38bebf1c3e3515d9b785a7ebeb4017265e3e62de90c8f59e79a559d6175402a8a1c1a10f4a5dd4ab6cb220eff898425e7356b2125c0477803f05b21e251120087c6c9f0d6c17f6c97d0671a662457ad01940bda068c1029ee999302b96a0e373420479a91985f59c356433d67fe91a00e5f63adf4be4cabe3e58272445e9c31a2c015b2ae9210adcacee2f05c665cc7fdbf8812c92c6c029174a22e1813924c4e90bbd2ff800d9996a39735971c85564185e9b2ee701909225c1384df268d8ff45c96823662843f3e9c096465e072b6bd6307073b85bcbe4c4492e46f93251007bd0e3aec3b9271ee856ca04e833089e3807b48a1b61b6c3f3136095ae45bbe65e912eeca5e8ca5c4aa0f10db888856f30296c7d400ac6f539b352023f2f5cd96923c13d92c4b66d4b0277316669575f985714a601b45605eaec37bc58405c15251d995e9d11ac14e395bb95c541da5711d5c5eb65568f3138b1cc1a2418b262c28118f0fff3d7ef73bdd824e1c6c541d03f927ea1fb557cc7f1dcdda93bfbf66de630d0ff0db5465a6b9b344208217befbdb7dc3be10b700ba60b3e5bb02ace85b105016f45fe0859ca50c28d6f197145deda2ba18c2ca19411a339f9a227f2d8a18486080a7858d200cdc528124407816171eda977af48962fc2882390d0c9f21568169897fbf2ddcb22cbee25b94256c1a326c66558aabb16d02c3740b3d4cb873b3b93ad8d517f3407ff727798971bff8a2bdfc95b2fb6c0b7d2f188b7028fc426c9708bfc6034a4c1c24e911d2c9250040b2a7cf25b921f16455092adecb14c99e3bac5370704e2b2efc1f822e8d4d9e2ae092b5c8abb227277a2322f2cb631b3bd95813d72ceea302f57f8643da67abc854536b7c2f1fd99dce1c8d2665ae34cb69bcc952bd680c01e463756066f982064487e56040127c7c8cf8a20ec6488d1b888dcee872cdf13b2bcfc0f2e52de045b76c429cd4999841bdfcfc80fe8b378cbd64a5dbafeaa6f08be9b6c4e7bc80457fb8974edf3743b913e3a257de6fa4b7a3f5966ed16099f28b631737dc59289e6b4bf9facddaa794623c55d1dc2c260a8503f117a7d087ba9434447d9a08b8df4a71cf43e39551c3bc7bdf747b57434ea1ea31b333aadfa0938c3ba40a97087bbcea37b2fb6f4b33ae9a2b863d157dcd5a0afafa47a6f15914e6d220c66be8626e9267a2fc260e8632e263dc386b8327ddc998fd6c492d6934420ec259ba35a475bad5b7773ec1c4cccfc2377a24bd149ef1d70063da97be44e342fa6cd238b4817358f2c3a8ece75c68b63ea654c16bc669cf3cf44da6aadafac08537b9788b2c1bbd844a7e446411ff127d89e624be390ba3b4993841b27b6c49d147c6a1cd176ba7d76483ad1b8138be4d84f64d929ec25eb27e00c6bc58c465082a87e02ce80595a18485ad65a224ac291bd687bd0fe6edd0d3dbbb613fdcb0fe3c8dd6972242c7365fa32333ddd40dba56da2672ede235f48f2cdb6d22dd03de8424243933ebba4bf7e5d5afc42d22cd7e941d80bb5ac9ad0b3cdfeb4ddb7246ddded1c229148093d5d24ea6426cd6b1a9e22eda221b24b0b3823e5b3c3d1383abb18227381bbcedd8524cfcfa758d9353a9fe1186dce6b24ed139fb2dfdbaec6a5ed124594747b330cc6c5298e01b9b826b208ca897571b1fbcb859545ae4539b1b01e5aa6517a7a3b07894452923b7b29b2bfbf7ae08cf9db5d3eb9b324aacd0b89bdb7da3b12ee2e24a46b2775240dc7d08b4e9aa677bdc3beee6a813e7a259e443ab5bf2299b58dd26716cf5f3db0872cf4d32642d93acd64ebb4ec2e6d7d944825d29ca5123edd8b7844e823aec4c7eb23c7efe4489f1d450405e99a088ba0b832a63c9f1df48ac1ccc79070072936c49567efc8597c68833e488fbfb4a01781fe4891843b9938b117d068e6bbbd4cbb0ee4d1ad7865b7de923c29c59dcc5b12337ae836460f3d1b8d4e37996fe8a14bdbbadef14e59ae4b7f690167c00b49e8126dd5b3cd1289b097eaf0ca46d80be8d608924817ddad337517c8d3226d302f93de5810557512bedc25910ef332099f448f21bd5e84eb437fd826ba4bcc3e9ac9739331e510beb4803d64bf9b4b3c68c3acea545561286b85399e200b19ba5adc8bf860ecf72eec08b753516996ebd63c678c320e79dccbf2efb1bca020098f7bb9cb2a335a01ced07bf85139642aa092e58bfc1eb52ba5cc8b069d9ac8517b5dd07234201acec8460332b2d172b41c244e64a2b844fc9080e32283cc7561810221594b49e2269116bc103e4208cc10c0c27c70e1bba208ce8d0e9a9e2c84ecf8e8b185122357e4e0d4e840d23344c80f1f3f5b1c3112e3c5832193446be48a1c1c59237520e9192224fe883e7eb638624427a76b7c901019027f2cf9810ff6e0363ed683fbf083c14d1906c8ef12420334f7e8f5b66d5e8262d017bb4ed0a906cdfd262e18249240bbca60d5cc5a1fb73925c5dd4c9631bdc818ada5284bd9c963da59e3d63ba465a59cb7b3d66dd2f842c19903cbb2208426ec0542cc4473ef472e24971657cfa545d75c482e24540e0584c2b13614106b43e5503956dc22927b5f2e21b793812322c036c293b2ff64bf8e514af827432995c0111290690eca54389d689fe61e95fd85c3edc146d2d35f689f190a65159c48426fcd79256adcbc81be3c0e98a3b4def8595957317cb5b6ce3ad588af8f38c6ea1ad6638ddeba7923cb1b90d810f52d97b895599847bd4abc04ccb3e22ebe8aaf38466219d3346ec02cb1bd01734b17f4c91ea65e7ea6611e7d0f9f969019fe4636932536c4fcc34bc0dc8778099863f552710cc501734c05e19218242053d0410c151e79c26993e7bb141df18aaf3746a69bb40f86d4018fcf6bb9decafc9c4f25cff722cf2c600f4462599a6e796f4549b7ccccbf36491ed2c7bc6d085fec8fc4c8b127aeccd6d123cf53f1a75766e3ce4e7a7b768dbd5edf17695412f1c95ebe69dca226cec34c2ccf5f55b8f5f1d86b894aaee783fc943be04ed2e4f9ce459eb8236d5a73b306aecc9b4cf7bed835f3d42543578c9a1871c6ed5d0367a4e0b5803edf27782cd4e7bbee3293da35f171f5a0adbe955a8f6df557561bab7ff495a296d2486b8c466a5f60888197170621ec7e5242188525ad68656f56fec93fd88669ed166f73f293dee2db586b4e360c2bca2c6f7583209ae00cf804e9436779883b999780594a9b14e8c831025b64fa89248b9c437e4e188190dce180399e526a3bc17a0aab7c4adcc8f212325fc721b3bd3537eaf5d5295ae983d1593e28b184cc5803e6e99b3fd9e072779a31b0833fd580d5eb0ba54dffe897b0400d780a7fb2e720a6a79893d5464d7a08e71be24b0bf79d28f7209d98c2f7e083015f3477ad0d5e47c9379f7cbed77b3e3484349ea34a471dc80d0f9123475bdbd65ae303711e8b2a6a1a83998f32be0153c93c8cb1d60e421bf035ddb2c437b20c672a8439b0665429e54d69ae13f01270e194b75c9625a948732567ed768961363c102bbed85692a2284dc6396f2b9573e267658c29c48aa65b1b5075a8de6b1d5b2b1d2aa55942fc8319bec793b11680b67c9bc5a52b1e5d839a49b323757c620f8f223f4a70a00d8f148d46b0870ba149a35591dce9e182bc5287148a2a90594fe942256700451e265917517206194d204803229e0ff2527282419801c182362831c29432c42f03c2c55ee28902451c230643654d05d90fb21f6441b220990f321f50616488385061840a2354f450c143c5112ab2a00209153dcd5161848a2b9a7b4550714422e15d1b57e01bf6a0a7681b5b344dd3b9711b41d687b7210f7a0757cca4b85d4abe72777a3e48f91e0c197bca48c907adad95ce94520ec9a9d4bae03c84104208a10ee6b55db1af29270f2ec01869b060e54c86f0c77d504697173a1feded4e72ec77bf71a55d64b3545567eceaed92d6453e97070352f8e885d998f1466e0302d2800c800e882d43bc2d705598b1e5016179e0831134a90d79fb0aa331939b06bd9c72ceb781ece5cbc4175224c8647e6f38630baf5fcfec0166899f173e850b95809a29e5f554530032059b81d79363ee141655843c800728fcdeca8b91ba2c976780a00e6bd8df8071903aa801500f08bb613646994a25a89434561354f1129de9af8a6134e4a59859c078e468c3031d45e1fb91be9eb0a7a8b751d3b49447b53c464d7bd75fcc46bd7dc56c4ca06aa69418e35c62f2b8a6d099c46cc427311b0f5ad1cda2c4657c4b1b6dc303397ec6447c210401cde6ad8b420fe98c8417c864b7e8a852da889797a7db3c10d60bc0948f8155d801bc2173ca83f11e8c960fda214440425160938da08492560b01a683db5df9d9be661a422158ef75bf207e4882656124b8dddd2d25758ab2da0808638c31aa7456e69aa378e6459e87944e4b12a9554a225146890439c408890449244a2231c64b9f2c21067157ec25269155764c423515c5107da218600ff0f33109159348b97d6ed4a994ad7b9a93524a297b70bb46923b99f9c38f1f7efc00831f7c74cf0f30f8e1c70f3fee555b70672c9821618aebd257c4d69a466ff91dd3b93bf27b3f9ddbb9b18e8cf1a0938931eea06996fc34f7e0cdb98d3b99b637f8457350458a37fe91fbef58ceede04d06e283c407098f1d385a368e96271b8d8b30c28ef760162ca883f8dedb29a2041e9cdcd88bc580dc4ee629b5b8d2222822821db90823d448214f4373d5f0e85153434343c3a3a663f77b53b05e5bafe7a494d2392ba5d6565ae79c93523ad920a59492464a245236b4b0e79c2de79c6ba8b6d6aaaab6d6bf9423f4f3b55a6b6dad94b5554559aaf204b686a01505249a3bc2084893848cf560923e407dd7d71a63adf0303ef002c38db7666735b856c63721a517177ed88161b8f1dfa1a78f1bd4698e1e3a7167f2833af47047a7598288a21033f9876691916b8c5cb95cff5aa746a813573a4629a10fc4aa450f9334128efb4d4868c4104973f43db748a6a71da5fdc74347a6f4ef47924c2fd32cdd8583890bd224d12c1484548cb656996679b1b728ae1b115b2e7a4aa911f41d8410f44414115b2cc7590e7a810c360d6fc8f4162341d236b7089ba6fdddb287b722a669d9bda15b084f59f6ec5e7b485d8ffaac5615ba46a3afb5dd30c3a77b7fdbda5fd775dd2cc606410829e86d2fbb8d685c9917397b2814023d93b920cc0ee1d63591e3bde205817e6d7dd0756134de7597285f7d3582b2ec5d61356cbeb7b22d26fbcd70e846cdf5f7622fd7ea7a646d963db4dd97af84c144a797f652d4346b2189442299dc64a36e516af2d72cb7efcecffdbcf766ef9c658799656599c9e106b3c4b0605f4fdf69568656b8109a3e213cb44ef0b0fa7df510655d0fdbb4d0cd2c6b74fbf770ebdf2ceb772fbcdbe8702bfd9220659dfa9d25780d92ee6128f46eed333994e11b35879ac8d9083e1bddf7067ffbd9c8a6b9063ddbe2e17681fe8255d88b3ce81083c1da255e42989a09b4a560dbb9e6264fa7e5ebba22f682fdde7b98972fb6f617dbd7cfe42db47512349321e87a5f4fc3c295b6b9eeb418285360d4d42c9df5fecb2e71762b6234e62d86490c94615373afb3837ebdb72e03bd418f69dcd98744ef401f892c9941d7aaaac21de8a08fee1241377264ec0fabe1d2a2ed46cc188e911f6d58255f615104238dbd80703703b3e8d84d98c4685497f7a02de63ea6efb12d347fbdcb70371fd24ccd3dfb108eb9af1e637f9bbbaf7aca2a69c82dc6186fe7bbc1ce4f6ef0c1a0b35e37d1ceb677bd2f2c631993b8bb0e3a86bbeb6d1d04bdeb5ff4b4be4d9a13b7fefd36f7b69879fb6a33d94ecadcc90c731f6648df9245c68e9dfb5ddb4e36004605d0ee383bf7cbfd97d2dcbb0d0d6267b0aebfcbeb6a16cc20f9328669d875611bfc253384580d0bcb5355adb9f6d5a76c6e0b95e076dae7539a45d2197d4060e9086ed737b77f34277d34873367d3f8ae56b8c35e1dd46173bbf6a15d5e5a2c8f8de07657965be4ae7fb48f19dc0eeac8f23670060f1f3fb2bc455bae4b07518411ddd23e7a45bec747c9fbb1c1d1c972a70a277464d18d908720783e84e08c7bdb737d4c4a7e8210a25bb4579712fbf5ee0db90c538c8e6bd1f622b2c93ec241724bd13bd8d1b6d72bd583611be2d0c01c9ce6e0e1cc6deac6a216242f7b2b826ec13ecc11741a395ae146ac1bc38e61eafa6bd02fe8e5ecb2b9ec322ff229621b533ed1df0cc11d1c1d2806291a309f3a5bd8c2ac702d4a25f6f94ed2374c5b2bdc6e9917d97e76bfad205ea6f8d48fc1229b8b8dda7a014db6e0d5db751f4a72c4b618ec16c5ecad972dd263167389d84c86588deb16ccee953dde8f36255e44d89e06a6f3e2e4f8514e8eb893814c640c82aee5743319b3b04b83b6ae896cc1f8f7a6e1c01ee0c82642780a7b51a23ac4603098eab0b98bf1e027ab706327f32fbc57b0a0f491d81226cccb8f978fb153d3438eef61d083a104508e877959361783266250b8b7639c51aee009b7d3bae12594500a6b3e93c1b5a7978fd8063ab6854eafba615ab85d4a9e5d7f8ee45a6bac5998b7284603f4429fb728c55e1a143aa8b197ec55d5a25f9fc975eb2e6aeb70dc3f8c9ac9d405bd82ec7541db6559d1aa2a09639e6fce080d828541e1c24c06579e6e33996e90c7275b51668bbd24e146ac791e8cf71c529c6830f1975f5c9191df63d0180f7fbef7768165c19b614fb8598e5862412405f96135b26c296069e42d1bd3adbfa6363ab105d270f7b6c2d4e6deed8642a15b1dafaabaf54046aef5ac973d71adeb92cd324138f57a32749ba36410c9934596b7301fdcfbcab22c18eb2159adbbc4ea2e51fee0b544590459051659bebb419ce624cce915794824cb9fe0ce44d337b1264b7883827bbdbedbe5f9f0327c2b277fd49050919377d24868eb6cae769aa5b3b24810792ffbd6c8e5691edec99e2c83544c891a5bbe986beee42ab7de16ca300deba187f083d91262265bef68f1b07590c6ccc9ad785db0af93579b101964c7a56e217682a9c7ab6c2fc7d06dee7a7cab6c30439a48afa8479ae502d121d4268b1c6fc55bd1d2b275652b87334143433382166ac359d7ba15baf5eb9006ce50b9ac2e0f45f05878b8bc99f4f77cc8ac93cec3161f675d65cb36eb2bd639eb9505439b088a10c442f8ddcaaaaaec2aaf6e61a02c002b01e0818787ae823b98b3c7c3123257bf91e50a1f005de12560ce7017baf598d0b1ca0eb7ea91ca63b2c3a6b2499ddea27f7a45564ca86c306f17e284e00dbc81379287b770979743e415f288cc42129145a411c993250f97416410b9238564a71b3087be84ccd66f64d9c20078476d86d86ee187d1081dbf945d9eea348b1584dac41689133bcb84ca43313bf0701589b3c3267578d8648e955d32880c929de0ba889759d53b43689166717119244b791aa16339b89dc4c131a1e3c7489de6644e73529ede488a93a5ca7db64ed22bd2f46a8342e00e0c8223bf03eeac54c1f0a639f98be756b764906651b93cc94e4e96e5a182a94d7394c7bdbcf257157e006c4934278f371c306f184773f2396cddf58eda501bf9cb53a9a5a49872cadf4bf926779a93af3629a43919c326b6407b9f0e5806694ebe83349d0c92036c8878ebd2a6596e288eb504cc3987ed65175bcad65da99d04c9b2833759deb47570487795b6ce244fda94a856c39d952248f3a25fa6ead56265fc7019f62f0c60fd66d87a854156c526d79d4a7e7d7345dd64739646a539115841f20f17f247929f9b8cc114ecd107c364bcecbe73082bcb3e86c1884e6f7a59f6cbb29388b1fbe8dd63322955d64a8ba39bea535189b428510c7086754b2b1b936479ca6a69dd9a286d80956f894fd56d127125deec22719aa5a898c45e7461302ede96b44fa2b3f9e4af5b4eae430e38c5d28a52d4854d39e12bbb56feb02aab9252d29fdc498ad2471f3843de4625b48b49ec672563923c8fa373d3575747714c9f3a959d0434ad7d91925685e5a30fec611e65c3ee1245dda78b35e1ce5e13dc5ddc994af8c71d17a242949c330912dcc95c12c7d4ee36ea6528844fd7b3963f3e89d8727c01f0ee7f67dade5d0c000c6db0b5dbc5a04cbec360e463288b0d71657968933dfe8a01ce9098ccd548f2c5ef05abd7b5bd5cadcad653af9fb55ed42b4b6b72ec1a49eebf7e677a510c3d56ce9672eb9e2512d9869aaf3866a6701403ec21498649f2dc92885c7c7c7c777c4ab063a18a14fce48ea1fce2add81284bc1d848cc26230cf8da3a83910f2563724723b19412ca059ba670628bfc508c38d6f25110741f8696b06d1dc027c8c686ec2dbdddd31c31cb4733437214d73f34c3437e523bc6996ee2599357047b39cec5fee1e11c863faa03e65926816ba75ef489e2fe288eaf348348bf5f90a5cc08866b93ea957eaa2b32a6201cdcde7496401cdf259e108deca9cf3d48c419eb7873a1e8cf926dc96b263c3ae696eeec813ea5053d05b9488e690688e1ed11c8d8f39524a296c41a61c782b14c7834129ed2cbcc1813950871e06a13b995a718322b9833e287d5964fa239aa502cdd25d179049028966c14e25162f6c1d616b4509d11ce53215a259386aedb9d8026ff056e8a5c8f60799c22264fa8ae92d86370f06d6841bdf37991e1a9182ad2c9d9505bd9a2069adb5d53b57d656d6c2aa7a652d865dc7dedd31c6183f9fbc2e2be68a62b79894a1f0a2b5d6ebba2e7cc21e733d1ebb1e7f5d98ddba2b5b6cbba83893ab4de6ca14a680c01eec4da67789f507f4417bb05364ce9e73ce0965c4d9b367f7fc9c73ce29e3c198c79670e5718ce6e667912b1fdf4f65368c3490b7b81f6414d19cfcb342965c08836c79c023e2c19037c0c1440e48532f0f7bc01fb026cb2d200fe863eb64e44a55970f4208cb5aabd68aa264d85ab98ab9ce668eb3d7746843810421376533d9645ea8f4914db3bc1289a40111c9f41fb6a2d1b5265df0a659fa8e6c4637ad018133b49c3cdab2dfcd1a5df0823ec25ee8bd0fd55a7f2291b0c8e6564c0f7a22ed7eb4cde427ba77892e1d92efbeacc768c9599b7db5bdc7bddb889927bf581991efa6911c29dc3c0f86bc0af7a26e138eaace49734cb062a62b0340407edf2836c07b2a2931bf144c2303d73c4c05009c70d3c4153983fe7d7b33288647600f74c6e3e4630063f0038a6e7a354d6c51003c0267c8803dc8cb2a6429adf0015221cb5b3da15661989dc2f2c8f381a75928dc3a4030b8251def05f77ab433ec216e1a1f97fabc6deebadd948052be697eb2bc751c12e4829e0f5e018d5c9025ba28924e4ffe4c47b9c95144505c8a9dd2a3348d7ceb90bd234b2a895c6f551bb19e1830f3b981996c310774c8149f2afa8ade629a44eef979bb7ae3eec6cd4b9c3245eb69ac98013354c7faeb131342bbfdc48280593b7d3c88a274a3b439f141a73846bbc53128a7ade188520305cbe64e70866573268dadd2ad92d516ddac1963865803bab64efb33b39a844918dd4834469a3dc68f68a4a353900be6b126c2a71ad8fb98688a44a277d44b007593c86d4fa7d3f67a4593754e910877d467b559ef6b6f677da8fa9cfda959ac611416fdba99dead4b225f20ec2e5d8394310c8d6cf08ae6e44133b8f0485440cad8f286bc0e8e204b88822c0f5b90258c419642b2fcfbb1c91dccc9523e868cd892c34fef6c4a0ed80536a5e0137eef05dd609e8a8e490fa08784d7de1835f9eebaf2ef3d8b8f680e893e00fc7bdd8c68c1cd524a4a25863f7a14017fc88d0811dc8aa10e1a8a85680e42165ca8652362cb6532fd1c7745218828c26616237a057e4ed9f86423471c43b10c03cc4d668c84113d9000b1e076170f3c0422e519a05b0eff43b73c20e017d02c2fcb2c02d99f8f346fe5e5061029c15b79b9cb1a90849fb7f2b2c41701ae49c640ee53b999d4608747493492e52bce7dbf52899767ffa04ffb984c11f2882dd0c78707843c200f087d20843e10fa40e803b7282e86575c30b78fc974efc39e70bb8853d3b2411d133434b048efd410e91d21cd023fc400b1a659b03edc948070eb0c90e507f05a62cdbbcf879766a1c2270617382b1c0aa6252020cbc713bcd08b4104ce07d781c906178a2c6d64419627596e59ae886c6e902c2f5bda34277b27aec85b1f8877a61862243692eef6b1d747deea2cbaa791b44f6c8953642984f68947c8f2edd33ccdd32c3d21ec35d7b86d608e4e07e99bac27088431cc3667d32c6ff2e8018b6016fec0253adada078b64194d9065ac7930baa704d6643e705a07ee341cb2c1ac81e7438419e4236f32dd7bad7bc570bb1b8118877b0b5e1b6b24cd8de2fef5dd608f5e91b74857c360446e077db66896ee29c9d2075e5e1d5288a0b87d7bd00b0804318b290a3b05028140f8943d0674fb0c04cae0d65d19e2909dc51a93b9f28529b875f6c6dae08fe62845318bb5e664126e632be9c370653472f549fed3dec2a6a051f1bce669235d336fedbd26d3297cb5cd6db6e4e81579cbdd1826191fd2dd48acc1f91f7b64556398e0ee19e134dcbd222f755d137b64c4e08e5c91258e44e2105b61d933858f1094bc5cdf5d48de09627b6a4f4f4f6c89d6dedb53098935b1a573f056e4a7a891afb88f005ac1eda44ebe4e10b9235f7371482c728591782412a9aa1ecd597b88104434cb02aec2bd8871bd7c61a7eb2f5b55dc22fe481a5923796459bdbe543ecf074ac4aa17ac3693cf4d48b35ccdc24435ab6d8224082ee81d0c0253716e177bba26b6c02513a482fbe0922c0f878c9ec3bb182ede7129ef8ef2ce7462bb26460eb88bc13d05772f1d0577a67bdf931f9db6f6c9b969ee84e58fd8226d856dd7e8e8e8bc9c05f6a2135b648f44c1f24873f2279be4692e8be664cf096bda2bdc3563b89d3492e5a794469a25e309bd626fca4b1ff384d32cdd95f3a3594e2ee1cd0996f3843b0b6d7cfc903aba58b3a359ba0683ecd12c3d487c924425718b66f9894b248d8c43641c92e5adb991bae6c1905813ee6bce84bb97c5e3c9f3fd1d8f3c6aa954925787974c3f6d302f574739d94e557e98490cb7c1f07c88cf622ff3d646e55853b5959a50938abeda281cd8830d05a49a1595436b55cdadda08eaa0b6759d832c3fda3a00647951d764099219068142e85b201012de73b97b4b5a071c23776f49de1ebcd99ea5369c0c73323c7c3f1942083f694e1d802cac8ad3c35b89b7f6f68081e1f625755dd4df2f8aa2ec7f6defd13ab6854b5da6ebd44dd74537b9b6759ae99d4db86b229be077afcb2447b38cae526934c2a7ebfa552a456962323d9af0f550c8c4e45936cab29b989834914d27dbcbd949663a29957e6dd94b26d31b7bc94a77e997b3ecc464cab66ee646cd2777e9ece4e5eca6ed7a693bc964966532afc7badbe8a2cd243ba6854b3d898bca28eabab2995d5945dd8a1f3d9353d9881a35f6a2994c26133e9d3cc6f4ec27a66737e193873e932f9313d366f565529ac925d2e8d748ab9a25748a129daa7c88a0b8b76096ddccda2076511745559455555545adc1d2ac53f8ea577f7b2979613d770bd73ef44e1bddde7eb495ae8dde7984bb262e45598a844f14752acb2426f30877a39b3c7a7f843b99eb6edd4cbe9a76108804025dd39ac81a6824cab2531be819753cb2d1b21108748a128d46a7a883402391e8813edaa8679b0824aa74b699c75199c2127ba96eab97abea6dc12bc6cb402757bfdeb4b0115ccb9a50b87e512a6557d8768a9fc911db4ed667b285b127dc1d69ab0ee6e4ead8568f55180c4e73d52746c3c6e6564854873bb17289d853a96457cf6670bbbaac6ea57d655dc72ccbc2f1158e699d9a8621351684b0a3b8b0938d2343dc9d208c651d5e3fc5f463e82b0b86516c084f7e43f2c362888f6c75632fb36737f602f30c4e7d412d6dfaaeed5adb6d8ede9469672af3e26aade50dc9b3e535b59bbd70a8a7faf7ae9f99dedaa839e6190a561e5c08b3be656530cbcf076a11bdb3133f036130d9df73827a37c7cef16af5f164a51de451258ea187f1ef7ee2e80aaa15d3c37732978df937f1a946bfcff71ef6b0dbf75ed3aa84d0f85eec1c7076d8eb9c0ddfd8ac38e6bd524821dc91b1531cd3cdf90ea9cc747befb13e8c1db45d176da1cbad1f8410d2834090bed3f7b1772c7b27439b94b92a06031f03c2177cbfba2bdd5ea6993a01676031f5a03fdc65358bf3d64227e00c0877c837d661bfb6eefe893ea63f4ffb33190728c39dccd82b7402f68051bf360bdbdb7aa2f835d133598bac103d2a0b2a27d264b72c79ab8b7104257e99b5c96996f77810f612e5269ba316f5ba61bf1bece26649195f6bc571e57b55bd8b632a0a089c11fa13bd8a3095935fa89379ef557d8fd83e7cb287a7de23ee6abcc777186b8d540e0883113d6222785df1542743892e0ce63d46be4b1e84450f771ba0aa2c72356915638d9d830999777247bda270e08c77d8513ab9a364557147e5640a9e92c71d9593a9ff55f9e4e5d6c9c418a95338b087780a83c11ee8da36fadda86318b63628d7f507cade7176795965193e5140a84d04c5ede2ad0e7b676f3285af4df60a751056e10b539635b3a5d95240e08c0ef664ea9dcceba928aab2371490774943f336f8186f6fbae53505c4da442a27cbedba31d4a42a348b1027e2f940c483f1ae664ab90af722868c1f8a3c24b702d7857550315cebd55da2f552d1960bd45b4cc9edec49722d3fb18d2d5007d4f16c46a20246c496208a987789725edea279d2ed34f3cc627097b0403743611b233ed9987966dbd24251c5133fdecaadd50baebe568c0bf2e53ed673ad53c7b6007ae92957d144d79e6d5df61b306f6086f4ce24dc3591495aac6016e56816d211b93b912e9b2b5de6451689f089443aa954d25e9148c73011869d4422754de492c9f63266f2aa64a261d75e6dd8b5eaa56d622f181ed9bceada5dda2a55954955dda8d9c444db5ec65edaaa6b9b497357c6b0ed867e37d2374c0bb73e89aa62b556179b5885d97a2b620f9df49a85480f5db435f6222a954a8779b9844f2637291d7b097326cf3e93b70e47d66eb2952ad236fac334d23693b551e855e82ed1a545367bbdaf21bc59f002c9994c55b5aad556cadeda7046f781dc3166b9c53c25b6da5b96ac91fdf770571f71746ed8dd97f146ec2aadb5d6d7d30d85bea9a364d17adb6e7c59d6ad6b61d62fcbb27e5dd82f2b74eb2fb68c4499955ddbfaa3edf58a68cb7007c232a6d0f67aa5316c5f856566bade7169a15d59533bd96db39ce5a22eaa22dcc50c5f9574925c67c59dfcacea84970fada877d79cc955cada3944225185f7d7ad5724ba20917c772f6bd73b327508a7083ef46c0b617c27c4a2fb18b23e0fdab66babb056b5e620c517a4a95b60e1851ef542425d3dd4a5c4be4ee60ee2171f0a76908fb8526fadd802696e7deb74e3aed94357741b7aafd8cddad315eac2165b1096794bde921d711341712d2c63cab53a85a938a6c270877c849f59468c7555028e56813d2a6eabe2275350adc9e382507063eca735290be279abbeda90d9e24b0b5831c48139cde9c4c31c9d66e9276b0a64bdb4803d54ec93e1414f5c7a08754028b8f0532748f528abcbda2e0ac9f161a1454e0c7269017b807f98c5570fec414e397b5c89537137b324db77b1a64a4b5f2bb66f88927ea277348ffcac8841cf1022d4c0aa6214567fd4037960f3409e8ed04810cdf51530f00a1e125c53e6a2c947bea259faf048ed183b7684102302f4f1a35b6c4b38a4b9ce16ffe8956eb1700f0cd2a0105cd8b255d6c69082834aea1a2cabaf960a5722971bc6ce94abf74db1c5c614ed27b654f8519890bb725189233ec12b217367a25b4a34994638f9264b7c13119ac712951d432c6e9b2b3f8c07d726b6c420f682109ee2759a8338cd4178141ed78487bde3630717ca1d4ff4e477040735553cc1f322924b5fe4a5acc50fcbe6a0769add2fc822a7e17ba42b84bc908e101b29d5705f9e32deda60ae2cebd65a95555dd5856155c55e2c56597b5595b5d57555c7acc7cb82f10755d12a56902467f959f1e32377fd01c14905aa1fb3da95698b7c2436c67d473c8a3a967329dcc95098bd284a0a8aeabeae0b77f5fa4cbeba4b402db9a8254bba56aa5254373ed990a7fe4cee1fd952dd52dc0e2e29c1ede092a6d151b3a3591ac71eed23ebebba407311091c2428d02dd075734fd46732157d408804096ed73faf079a72104b75901f10056a10a863c3c723cd41aa93b92024c2ed601012dc0e06b1acad9bea7e3dbde160104288bbee9b115c1a1b908edbbd9ea99291882d90a757e2adbd97a707f2d834cb4de3340bcc11ff543f15fea9f04ffff44a7c75a8925376ced0859fe6647e10ffece0baf44f7351c7ed20cf0f8f0f7cec2ce093c0c70812c1dd116b9a8b22b8367434d73fbd648b34cdc5c39fd8344da48bfca8a0105c789393a1922d3a78935d624bf35893e95e6bef35996cb655a060493e407e55a0c08a6c41d8a357e2618ee9f5c01f36b125be79624bcce995782226213706c9f171b60d8d1f305c98fb27c73f08dfc9cda53918317872434f15f95921041f99477e560c81060db72f0425b0fb5d6407ce11f2abe20448f2098ee457851357e40eea805d24f729fa00897830227ed4dfa3e6abf33256d8cb8b35462ae74df95eb70975e07b30b0296ef7e22a29a61468a5d46e8cf142a8036bc3958f14ac8c106584524ab933b5dcef237de4c8157342088358f23e126226f5e4754ef9f90be44ec694b3885fb77027e7b6d8832377322610f662d24c6eed2dedbd43d3a40e97fd44d64f60303bdcc5a58b83e2535e4ef9e95dc3c3f4006c3a9cb499cec356ffce30ca65a9b4a33449a5d2c97bc749f798a51394c943e9a4148097500280bb2e954aa51226c94f94d79b1e710763cf2887181feb2c954a37edb07530ef701006331fb178d3ab2cdd74ed3a946ae73092f1d5540d394141d95e3e8931c668ea1cd3d43f4e6e5935f2d5344b589a4c559a6e2201e09da632690240fa4d972728241396ef1db007d25d6200361dcec366fa0edbdb81741a15dc591600601d0e71624b6fc7386678d6594b379d74976e9dcee11beeeeb13ce926141d50b0e934f6e480eb491fe17ec2a4bdb54fec452b9d9c904e3efa49034e4e642e812e41ef1ad143d7fa8988c194623ccae71461a413094f8230994ca613d308f71329d73617583607fa693b99fc6510ad17c6830b27057172f7401cd0bba654c21792e640a351f3a0aa2da447ee26cd9288274d6ce15e274daebd625d3d5d2325965b34b7e43af5115ba22d511fb97f24f25c5ac423daa5c529e5a3483ac1ed9a075debe426459f6639d178f07c80293f9d82a699a774318f5eb1d3bd9e09e5a5d2f64e4c348782d2f98472d91cca2166824f12a39c9ca48444ba65b2954a72b34c36d31fe68093ec27d96bf65b6bad8ff6a2cf6494ede4a49f6c33d964428a1928bb62f4893d20276e273b53d72ded753553ca55aa0e0f2d001ccbeac97d0b36a6d58fec8e5b2f1f1ff3284952be538dd2492fe128524ec25de9a71aa49b3cc6f41a26273d8674933f69914ca6934c276d30c76b622f992563ac51abc0f6a2b98e9732c61aab3c156be49a7bb4dac7eb68cdc846cb69eec4148707e37a476ba40e499324779626463c69624bca9b5212577a94336bfd69aea5c4758bbaa4a2c9b44649ee2fc91a105880889fe81b98c932fe46cca59865d7448e19ddf437134370bb1887dcbf9a280e251313d3ef7662c2b2b967d55bff6a8da9e1cee4a71ada4b8f39f9cb27f854a374ed31da4bf5f596a69d5cdb608e22e52e3d4f2ce843c50f1286643885fcb018e2932d7b51ecbe985cb4590b7613b6ba4a27d5c94b5be7ea044b982beca59452b5975e2ff3a2622f27f8a45dc3cfcaac8bbd942edaee9f887488dd5ba1cbe4143add64eb1c3a6199432429b9f8b01a9d49f82471bc4bcba7dc6ee91a29e55136d3269b135d9eb4d9928bb70b9275afd7b75b684d09e5a592754ba55b2add77be255a135b6493684de928d836572a7dfea2bc622f28f854bac9c936da54489bc96669e2f514d3768964fd49cedc4d622f15c36a74d66eb25d77bba24d238d36158c86cc1ab6a7f912ee649e2169c75e4220b8b46647b384dea73c9a45e2d3d45eaef67b91484492f2a1b991a23667f28c9b4b1485248e12521ecd35ad09d1dcfe85599adcbf36aa62eaeeeeeec62fdbe6f0299ebece64a9e5d700219a7b3fd920e2c178bfac1e94ce41093b8a64f18d616ab83cb287bd3c5bd9ca9eb2a7286beb9cd6d66dde80f6d4f6624f6f1fcc9b12fec88da5e1be8ce513ac3e0aa6058804facc1fb8c4c6891e28d0c9af8a1d3b59467e55ece0c9981a7e2e99a33998733b950c6116cd4d9ee6aaaaa2d88b057a4cfd3c088b6c2ef5991cb70e479432565585617ca792214e4e968f3937e2686f32863b1abb81525ce803e67863ca29fee5f97c34cbf3d1dcc3d27061868185a1e156d7755d57160328ac33b48e0cdf3a72efc8b021a556de4c1f4fbdbf183f238cb16b42bed7f3ddafa947e54c3adf1b2ab9fded343fb3c45027c39d0c61900c77662848b560c9b69c30829afcac00028fdcd90ced10ef2efdb628645ee448821ff94b86a0b93fb13bbb527a88d5a0b9e228ec1fd6c40b20a490180d9ae5e72bb621253eddf804eb35cb06608673cac3889f32c6dcc7f0d5b0019768d83162d85ba0dff1a193a38de2525ae1688abb53ffd967ab8824d22e2269966551d2368fd069e4c8e421912609b4912e4191748dd093f0adb0b9780a34aa1689443d25c5d42cd4744d1cbd45daba2660be2ecbd2a8d61cc534a539537397b56a04d5506c1841f520d049d4e19d469a8bf4f66aa66d64cb70bb67165d8af0e82e3d8d80ac6df2dc6bf2348b853bebf5f15dbde491db3c62bdbe9b46acc754d2cb306364b8dd34d22c348a94d794cf23dd9282bbc73cd22d1088289b07911b974425710b3b8d90f0a9621b33d711c6b6703b95ac9d9e45ce095dbdc19ccd74ab545ffa6b96d2db84f46e849349b886b0212c18ed158e6c6efa19f6d235f4bb857eb291dea2ce010281b49d37bad7701ee8be8a0e04ce40f93b0d213ae1aef3bd96931fcad689debd07028970cc158140156b22dc8d44273df4ee37a98240352793ae6518cce90d3a914227854e18e957e8440a59595cd1bdf7b173687527772150e8a46b244d2777a13e08f4a785480fdd8a3b2d27872a7e31dd85505c80dec10cbaa12b0ae1774dee624bf9c956af6df72e1d23474cdb5ed680984826d27b267c22bdfec6fe7d85b0a7a4bd1bdde4d26bc5a1d34e26b1ada8b46db5b5450c198d04002000d313000028100c888462b1603c281986393b14000da1b24e6c4c9986490e44c818630c011010000001000010040018d4f3d8b44e15c51b36eb3474b49d030e513955cddc970e0217fc91498341fe38757064ab78827d7ec7751ca8d6843fd83e132d52decadebb85b0d5e8877b363d0fc0e6cabb5efa74a00f2444ae6b8336b0ab4f6744347a24fd1652fb82e1831171e58c792ce8c2ef36afa16302f8aa553c679565d297fb504bc22ed7e65643dda3791f71f29868435f7d79c060b2d281903a6e0062cf35bd5d43a5db27add816e0e8897b736259b506fa9d65d73a78b2557f58171c262099a1a3359b886e3a66f41c4e30f091b72728685d76822d164da5d49091ce08a1e6207ee0ff80f10398ca30fb31365eabbbf15d7da355bd355f3055fd47486cb6a013eda35663a0f7c1b3fa2bd5e933f0c3b2cc66219361c7321044cf43523c3980ad0bdcbfa823e438b0f2b161ff3004087c54e57804b7e8545f90fb93f119c8b3b5455f4b193aede098d061557fb6e02e0a0a51f03a41497887b19c5727e8d7fd0af838615343c7836864aad0240211e8b40742c0b4d4a9cc331269dbc92a91b87b1fa7d5a8679182e736f4880bfa923ad5c704e45d9dfb21b8fce90d644934cc673c0c796e98489b1611ce1b22754a9826ee74a1385097e1557d8de15e5f56a714e81c30a1c021cb252a2194a98da15f3a45acfc4d2f52e8408d11cc4ab6aca0a0e3c103ec6f51f2562777588320dde1b54ef0efb4c104cd6772baacae2ccb77c8dcc702e62a0c9e400a27f421824cc052362805982345cede15e9b3e2fc4bb75c4c3f314a2fcbb701750e177072ccd228fdd5c8888a82554dafe9fbd14cfe8cd940d929ede5a46752e403add92465b7a55637e0a245ac0a0b28d6939e35400ee2b1df118beddde104af32414f4f1489b1e2f7b4bb6caf059e6e69e6f1cdf98eda469b925b1d32c17a5b31572748ceb32d4ea0c8b100a83cb085153e8a88dddf51d90e81a0cfb15fee5ccf4ee073135808463a0267fdd085b282df928fe283f7180582b473896b574a2d259722da497c4b41f404c9c7078113110f9646ecef57b177751960b849a12ae8bb7887d20016c51e8294a43268f269e9f7fe243e1898ae0375acf02665f23c7eff19c27926f8433a35fbb7ab8e9a021ac9d505a05bd7593b98ff8b7dc8582a20f1956f81d8e3606d95318352b9dc927f999503fd96d2e81528df1e66c30b8c95994586715e35279792362f0c482aa08ed7708b97836336434f32d7e19eebd00dbb1c0a4ce9c1887c9a08ea14b8dabc0e3f69e551fc7da1bed1b454e6a410863da5c82bc46b270d9456696d5cbd13e5ec0966fc33bf640e240e66d3773becbacf6b5dba82bcfa2ba6368d12c5cad8fcc97d3065b574b0334fd8e8b545a21f8adb7c3be5d881f1cd4b216e9c94797383ec3a586d4bc82ee325662d2714207d81f31a98d5a546cce8adb90c592be968afc84a90189df285c3ecfb5106ef4008c2e995d530bc87999686c6b3be0f29d04710a86cb5a69cc93cc35c1014a723281c1c438d1a41211fbf2c817ca391346f18e862899f508425acdce14afe999d5ec178851c8845ce652aaf3c47d74703bcaff01078daadca9547557831438f10135f60675c8190639a843047caae8d91c1476056bf442d0359a643cbeaab3b1fd7b79a10c6509acd760f6a000d5a2b45938cfec461e5e1f85d2976b59c80b96b7dd91c101a3bcdb60971a3bbfa5c2dbef136e551c057fe185aa4dedeb0e8d173bcb49865fd115fb9c9b1f667baa5fd0467af9d3341b91ff42cfdd4ff8c7d04c3f56be8dba23600404afffc63a03467641e10c9612897034e20c01db0bba3fbe37ddf09cd6656e4be177cef296ce83c79c1a3c2b118f1e1017adb2c11b68016ee0377630e3a588e7a038e4708d3b5f2432d93aef208f58a9611fb935039e7c85c9a372185306e72385ecf1578a36143da3730a329667d33c234813d8b0ddcb0365a9023a30bb00c3f4e63b0a6ec4ff5ad035a2f5adefec00ec11ac5f784d1fba4bfc534887390f3ac94c9c5332da1a82211f2a6fd2e01c4ac092d900afbdb8ac19e8f1d56df257a8149a5415d6981a2727604abd10f88df5b9c4e0269f540bad8b8f9eaba22cf34734e92f4271e68bd74e839f934674edf2757af695d90742956d4e6c0e3d48c0cd5e41929ec7e842de0685ec9c2d6dfafaad3d73dee61b28bce7f1ca57630079d806aa71424c06594b59adc9a2eab13418cc9d007f61621f8b05dcf00e7fcc66908733c597cc20fee048319dfec710c40a0055f20e3047dff753ce2c479e6306253f037bb3b3dee6aaf1e33592e6b040066d2bc3d511222c9baa2800efd892804c5e86e6963ada4eb44710d5b4d58328c8ca275a189f97e96ec9fa9e5608dc5a94c45d5beb41a875886ddb09b750848fa0a7431a9e8c57e2eb8d3c6b69a600469e379dd0ae347a424e890b6d66dbbbf14ba6417a97f80b00738ad0bfa6180c4e27652667ed7c36064a41faa101b7b3a814e775b2df61246e8920cefd7b23dcb4644d52236248521a9b8bc5948d147d9a8312fa90d5e38632e0214cbe24e8486f593767d8185ac0fab4c5060cb5418b9978492ac24a538b3a997c8bc12936aa4345a951a6c020890d83031c2962a61b9b01d0fbe211411d62d8ecf2afba9bf0eba8092dedd20858190f532a66add448456c0780c4a603c49a1e1aed2a953b959227ff043b172a9dda00e4916c03e5615aac650ce8496f269386bcbf968e95400591ca595c59e48dd400c351c1147506c7afa8be11c7c1d287217a999298644419915df8043a3dce916d5bb9c982dff32c6e352b94eb83f0c7f9f1458dea70b35b7c0670aa834c0202506b28526b46d8e7f44248395c7d8a512f05a0b7be2d9363748aceddac8deb4cd893dd40adda3df56c44fbcf390d8aeda2646da7a8e1f909909abb49708c51dfcba66add79f2791fa61c72f858d435a48daa3898b3f9f88a9106f2c835912854a6754a162c71b444c5063299c6d4d3525c7b8eb0a83bf1e124266f51cff439396f370b60b866fbc8f296eac4efabcbd78bd1395782df932c2c78fff3c2f798323b05e6c25df991fbfec5f420886386abb031e1663006cf87b8a07c085e42a2293d8982f53014118acc5547815bb3390e39358755038ed22ba678a078593d845537c578870fb64af5a5298d1b94899af625ec8e9ad0de613f7102799d7210a757d4b9e01f35aef2ec43bd4bcc087ec5d47aad5607cc6667052820fa9d4af6fdef44013d8a573c86f0d3fbdc01b2eafaa73be4d3c436dfb1cc730e24827c1e8abc7d07acacef24751d49a41248ce84013e7a9fed244e397bf7ce7d59844d593ae0d8565e05aadb63b331bbb922954419bd9a8d2509c841599a84ec1498b8fa8c0b216594918dd94630f34e3d1774ecec029b92e3a850c065f16818d21018b68e3e88f4a2d0b70fa2f25ac870b820e74a8792c0455dcb482b46223ba66ce7307adf653f497089c966933a6dc8007861f5fada900eeb1bb9d515fa265ea66d72157f1f196e9cc649cffe9b66651ce21c6feb21dfa748ebd75c115013973b0e91938365878305898a5f6f96fb333a7a9d23a8fdbbc0ace23c66a9f33cd2cf992910df44f550a109028fa31cb77d9c929cb2e3dd4475132a2e1a37d7c3a300a21bb8599f2fde6c1127127b7ae0f10f1a475056d969d7a37220a4921361bb646ef04f358ab22c254cf62b0b3a444e093abfa8ee41d2f1075ee45543dad6c9a1fc4c961dc5e58ac182a426fc692335b45b261fb2fb437401db8ea1c1abbce24bca604e9188c219422ac41d01aa1d0464d96c5c5a10bac7a6bec649033da0a3a1c9bcf738e5eec206f809f013d17f849a22b5dc432f4f0d27827ea0724d4f4b59503f7a00775a9fe5797f79eb745a80ec1d7d36c9c92d9056367d2fbf471d3a83f9639af81e73e2f2e5a2760957f774fa40ade2c57af471b7268912621bd4259e0791689b6ff7180adf13751f6d555c56073be47f170f7711a00bb30f58035b11886c74e7ed988310d429987912e0b813d8b41065bbaf387fdfcbbc48c9eee3afd0a4d64a4c63a50667423038cd642844e459a36379ec701e719ce2cca9bdb9fde13ab1317233c367d951500154cf97999d94a0c3e03905f10a4b0805329dcee9de63152f6d4368f4f63139a772a4f7cda26bb9e742927bfede05244a6ff4e6347cc14dbbb03902095c134460f7ac4755319941b0a454db79400528c247947aa85d7116e0863ff11d8d2f553edee5997aed4d61b2ab663a631f56d21d13e8f7f468119852990410c53f161099a54c0fde0deb1b4637cb41f1b3d85aded0742381743cc0a003514fe12c8f88ae1e610968262bcbb4923b6215dd1b01cbf61d26a52ec7582c4ff78deceb9ed84c8d6c0f1255a642a5c1e12df9ba42b4a6d9e61fe188f629784e9db9cb01686fb6acb46c3ccbea48635eacc597af153e9fcf028f19633e565e7c5e19043572e330e55775d2285ba2073fb44732b501b1de5adea1a8d555a7237a292ce7b2c0e7e025a14526e2b6b7cee4a9058d984838d24d5250fb397a0449e920bded150d8096af831d1d15ecf02977fd5076a29adf04e988adc68d88d1c9c10de38242495055639f2744a33ef44f2c62171a201cd3442a2ec6aec823cb241bf324c8fe112a1acb07612a2e91751d1fc2edb5d6a4317a3d5a96dbe5840352388a50314044a86ef63b31d3729ecafe4dad240738da386f412c4515b91b8afdddd8d4ad6d0fb580e967cf59bd847d6d2797b9f3bf35176308e807476f2b80bf03c26331b5a3292b74373ad469ab843c06d3f2135a1632442fbe6e41055cdb7d7aa7653a061811098df7047f3fd8f10594c5635acf95d7f2f84909557d660382bcbf1871961562928a8a9bc42de260053439398452369e0480fd6fd42e4ab29da70c1c5a2d99b1493546f7318b5175655cb4485b9947543eeb17b2b4d6c91df17da9806862339df9331a2e52d81bea5ab909aa0e4bae7ad22f43247b79541a1b27f4c7f1258b99ce7442fc25b6fd1bb300d9d18df5a56023ad669990dfe7553420905e7c2e5f2d133cf9c4446e29207f14fab57af7edae062e249bb409d1e189d1824c0d681b6d1fc204215b3eb5ff80fa25b4f05a2fec4b62f80d9e1fd3d81aa3087b44227626b41914049e8fd53a7088f6cba505b006ec4024bfad47b9869b07baee2a8b8386ba7ae58eff0078af3453f86d1295ce302d90a46f2029e2396f5be08e4d8e5c028e37f207607d416534c00575ee8a43eae7eb1df90e990a8c69d98096b983462c0dc55d0f021cc6435b4ea570df79272f7b2d220d19698c8e8472b5c9fcfdec290458acee3c5934d39a95998c38545748963b30540c0f224e694bb90101385567d78131439d0e031a1b49c3272644c6ab21013b1f0ab31a7502bb116f9ba1afd95e93d7f8fc91b6f013556ce34af85185a975bbbeb773fc5de83f3cd94ff24cbf9e4f36f0014cd690e7da73f4d62927f04b42c6471364935c16349af4e47d4c9573f87bf0d1834b142d1cb134f7be1e49d729c10b9bf73e29180e9df8e5414a1beb7812194461047bdb258c8c3273b4fef944546715ed075382d4511860fa724e6ca022151145530ef90c8c54d6bd0a51a3f63955e32c94baba4925a45d1c93ba51312f95d85a5ea2b305a602eeb59da8ba5303ee66ec0b6ba15fd8fbdb7534c0648dc198a5bc852e4eb2f85f935b1ea1ecd531e8f3e945eaf750337e3faa118891d823f1001098f33dfa6a8c6f845598013209ff449d4a7c1ec1c43325feab58a907eef64481ff63c3441541a50676c4b4a5c0048055b9368449c3d9d46b6f0aac162006abac96209e66a2a3bb5706ebf48a592a31863821c065c37459a697b761a05f9e184a8b8bebb62d431a357e4cdbb83cd83f9a738db91153b1744bb82605ed296a6ad482e694514793c87eac79420d81a61c545b2278049b18ea204c3490a07172ae7b6421848237d0a95be46051f097c59e8ed29587cc1cb3a054cedabcf035de31102c2eef62594dd6afadebb90e1a825ef4edd7593be6be867217cadb93352296b0af893ce40cac4759dfa33acf977803aa23414706f2211ac53d8282e68a736d9b2da93535a1e07ef407aaf26eec75fd8e6f50562bd60f85514a607db7bdf688b19aa17da951dcefa13f1805f9c5b451904097847842e41684a1914198a3c1e85f5cc320c751b2696e936eb0c0219500929d0250d093035881a37f4787786b1c521df43e270e9eef53ede0c505986a7666766b9aef8e5cfa249a77aa36d6fafa05b284ac787a64aa30e1359469dc6333cc3b53e0b83f094406ca47e665bc983aa23b70822e796d232cfe1a77e60cc1e73a88a4b242befef5f8f9e4953c552156176dbfa6cb14926d48244986c320f12cb9496a58eb70b73809412f51d465c7713d7c90ca818af49e24129f81f59a7402134c8cda87f1f40067e57f3320b438e6086afacb256986743c3a962d8496b839907034e3f0319c0c38f20cab802ebe14ca4c23045f1fb6ddb937320b15fe294b4f0095dac63169ca77045d15bc750d0ab724ab188f303c8b48bfd115416ea30154a2db07e3baa60e794112c3cf31a3ce758f874ef42c7c2e1d5704148c6035486be410dbae426050380aaff6ce9fb783a614d5101eaca23011a006dbdb07c2a143c0e039b4276cff66745f5538273a3c8ac123c7310be5507820dce2247bedf53ec5e08a2db4edb083c98d623d687005664addadb48452e20e83af39cbe54c8d39fe88d1af8d0ebf4b3d5572c8bcc9949ae85a9a01963b2578d7870b129eccafca9558453e3ac44f3cad841ff4f7e30805e987efae60fd2fed051cd7a2a601c75e5824ca3b4e3d01aa4fad13f1b88cd1b78e250c57acf57012c8879c1ef03aa6d6daf1ef647a60a9d8bd9f767d48ae6e302071dddc64ac049966e2dc5590586b681e0b6accd57e2b58c27d1a8bd5959366b09a99ab6fd1683fba1f25ef42adac80932fbe0863cc152dfc377434c35faa0021f5ddf15908f0e7236191742ed5a3ecaaf0120707eadd1889a9809cb021593db39421a283c3655fce0bac2c2b0160c8ab703c70802ef25d0e37e42517d3c0c2dd82d4ead3ca94cabf0a63839ada04f30b8a65cd556677972cd71d470f99c23e464c6c32cc8bae147a1b0bb171c5b1796a88774585e7e5b155230e417c0df938dfc896b6f4b0b5a9a2f61077d3b54e47fce85b71b7641364105a28297c184e00f7b6ff92f067f95ad9b3712e0951d2d903a0fdc5c77e3230fa7d82bfb58c03dd6a811289c077db6916d467897bd1d33d98bac8bb518c9b0371b29bf85920f8791503dbd790aef479937ad0e4fab34e8d7df475b562b7f8ef0b296c83a261011c8c8c56effb2fdcb476ec0040dce1f0ada437f07d57f721827462c78ffb62642cb892555631d4544f5451a377605b06e903cc7ec8f9ec342a9db0c746a9f631d06e52e7c9e95e5842de7bf4c76a87e8a5648501365a538c95d366a0ff3869ead2804bafdb26cf60174257cd56791df74c298527911d7a33d80dbe703b40524d7705a6c049ff4cda1ccdcb3745326a0c0af48f16d7e67552c6091386fb09b65282697c76ebf1f74675609050a663735544dc42214f436c2239c1e4ec0c67270b47ceb81dabb070c40d656238affea8bb7be6f2aa6c57e43d0f9f080434397e7f95ebcf737eafdaba7d38f4b9279a922384739490d1f7d88f88e45ee6afd5cff7badf844a38c86f3ef0ecdfb52b9df144b0eb3c39905e10e5cf77648b1bd9623a75ea4cf564dc7e4ba276d8326edd38cecc9d9d67f67eb1834fe294a96522414a576ed3df2a9476485128c82292f973172cb131b07c0a602f928244a0a023bab824551bc196795267c4d3ceca32ac365d3a61d22fe6b2e5272842c47dd79ee2511c8a27076ea13fbe358877737b82003bf065f4f17d1800c2bec1faa292639fcedea63231a4f12118692730b71ade94286bb1a7b9f5ff1e2c6cc4ac0df7d815977480f127c9e3072cd022c8d11ababfabe65018865051e35c9ea731089909ac06f0fac50c9f1be070b12ead3280dfa299534f2f8292e62d98d30a0cb090f11acd52bcf95e2bbe9012db75e001df4d57bc839c94775f89ec6232285e4839a81594ab21e2707d5a645fcaa13921fcf19385404dc929002bfc52fd47d583013d01953697001985ffe1a65639c2655ae926243450ede4a81a9e8ee38c2f97250daf69734c4f2298caa098c34c4c41ba64dee0ba8884270e4ce623bb5edf3c0fca3613044e7527e5c08ad867b2e7c5f8fb96417c68a17c23288d27d89861a8732e37360007fc11b8320c6325ce157cf0e3008ca1176f7a1ede953ef94ad3b1da00e02971981df701de6bf6a90079579b4490d1d97245518b07699040c542505a824386e06311a8718a78a315cdd5b1274ae450e63573835b532b6342f1c230150a265e54dc998c39084855d0222ee9a8cb9c9c2727993ec9dbf2feb0e8f86a20d082e0fa1d6f3aa793938f6dda93f01e85a76a5f98730f6336045c71c8156e967c2c7e28a0fbe1956bada5e8eced1c52a43b3edada8f7bfc8d5ba9ad9905494456e2a27e7c0c31f4cd8d681498c239324c0ed26d073688e65a14737ec67b4222863b65df1cbf365e829ee76023e4a6cc00551729dfa510be76c3f28d17f5445753d1583a165c9df699f617864bab665e5ce4d0011aa13e41e95b043fe86f2bf8c17b5ed0c607f9a859c47dd51a4c751e2884ad041e4358219fc4f135f26fb681636f702f29898177cbae4961b2b015f01dfa1331101b6a42832f4ad0cf0fc138522a5ad63171212d8176ad2953a3995cf73338ea8c5df905ee93983fb001e95decb0ba9d4619490482dd9eccd0000ed84d63efacaa8689bbe5553ae114a2f423d99f1eb7606384c756e00df9d7083af4251db259f51ab65ec1a569ce7d649fd5e29809070442ea560d2dbf5945dab89a1172ef8eea4cfd45aedf22029a9a7e63d8a9c5ec60b0926f9aeda6fc039a3bba731bd74fae83af298d04ef386b2227db162d383544594efa415f424deb31f23a55ec8b1cdd544f07ee7478860f4082d54875d5fab4dbd7c97f8e2ea4a348cb751df501d0105b3ec1e942241028c6c323a7e6cd83c89cc306031816b43395250bf34dfb63b747ccb824fb800f1daffa1141e546ccdd78214b1a4d3e34cc70e7f027b9fd3abc03872bff08b4487fb35ef15947c9da7d26676497e9943e9956d65570731937e3cd60908e50b0582f5136618e38e07f731f071da635b7383408bae3158e015425b4657eae04bc7e87abed73161bce3f9342ab740813842fe56be7b9be6716887b41d095b73ab0a2b4b298b77b7254eabf087d9825ad5844ba66c8000ccc5705bbc2de541e39155ec62307bab4e361ae8deca529cc2e7f0b2ef2e77b8d1d310049beac49c4ed74fdba863534137d60b5096b02809d51fc4d355cb9ea2f37ed793acb9ec2d3c2d128c2d903bc11bbc7512b2229fbc91f8e4bfb72e364e1813110cfb88ac1e9e447c5ebf50b6083f606c02464e422edf93c27d8d4bcdd748ac9d067182d5ca8d416d6bd680152ad30f204a11a0309c923d968e2ccd1b10fb305f4007a7deb6e0092108a779437a2fc6782a7d8404c563e8be4981450f9efff7a25f75a80c16277df8b2f6a5a47a6028bb5901cce29e57d0940c92ca54d37a52cd73dd87bcf9ce9ca598519fd82b7d89d6d2c183fa592afba07a02735c2277223ea5475f0ab219f12cb4cc523d356868ec26b2832aa53ecb9615f2e192ed157617804d0c33c9ee556543664497e2a41bd7ecc56f28ea3c855af6115eea54e665f50a9e0f0da9d3489427ae36a79ea596a4544fbd4032802c26853599bfd3095297ba22161770d8552e0d3481267477cf392357b66b887c9473bf813161b490dcb2de9a40046f8ee9304ab4e452826c215ed95e249732175fec2fae3f09443e574168de8f2ee3f482054c3d31b776e05da9dee60ab3d96eb17861ffd5f0c9a5c55498636ff2ae46645ed0d9c5de880f88019e6f74e3606d44ff967d971f8545dd681d7fd6aa22a99727b650e1736babec29bb8b907c071f387892c3e962d07ef97297af991c88941ce582cadc1cabfa97055c4df17494fa7810b5f55124b458018d32a88dd6a2c0440de8a2dd0dd5d7a2ed99c8f3c2924eaf0e82c2cc7d1f450f8dc44c539f9206d8b167b11f96be7a6ffbfdc9afede64cf9a3964b53467047a641ba611e0eb899d19a176b631915d194410b02b2e3a0eef27af1e7e10b103d0abc329e6515369dcdb1c38ea110542ee42d7cd5013b53f6c11742285bb43edaf98dfd7fbb63e16df341e7c93d05d68156c16c490d25d57b8753c4271670391b3658b0b6dba4a7f7816995796b48e82cdacf3ae7100cb02f4a0d724ff2c22fbd95d343cb551776e6b6329e55eb8fed880498e004099df4a3ae4305d967803fe16b3ef72a8d14a0a641a8e74a708229584afc89533a636e6567cfee7e3b9ef6fd9486ff78869b6fda446eecbe800c32ac7e0bdfddad29bdbe8e0fd81098ed96c57f47fc23d744f2e892f90426ef62c15aeb1580fa72d5f95e0e172fc125bf6cab7509779b03f43ccc1cdebbf468aed6fe86932a3d4e8bc663e36d262b18666090d46b33d4301af094d5a24158e65d543fb1ddb680bdf66722fb31b81cbb7179f3569bcce53046c423ec4c20bdf826e41b0e6e96cac9b0bccb2a5a516077cbe8dd31fe87682cc9bf5ac109ef5bcaeb7a0efb9e68486a888646a616944850111af7c1781446c3f486ebd01bb963bc30b51a30cf2fa832d7eaf8c81d9bbb52a2a6a71fa52aa59fa1cb27ab14cda5e23c1c18ec08a44b51e5123be5c5d20eb73c59f2f827e940bf197792c6128062933d336bcf063c7cf96ad5fcc4e8f9b09f6260acd7af767485ef16eeae9a07a520131ba75fd613a5b4a1ed8e318aeaa10db46a2e15b68f69d93920138162f67404498a43cf046d8cfd68e313ce513862741f3d1eaa54187309164fa5d0765db5c220108dd77361e1e223ba8df6a189232007bac45c75d28da23ae7abd382dc62070c508ca248999c62070bd86114cde24c452666664c45904c2ce5005207e06a5e77e33d8abaabd35234760733343aefc5fd7adbf6c67809129bcaef4ae04ceb8d1014bbe8839cdbb0800845925adc17cb8d130f6e6b5a72fc4cc774ea11ee475159186fdbaf47b61bb4197d5d600b058019178fc397b32c1a6833f7ef15c81f381a45350441d9d9c67bd5962b625c247219731f4838092f962ff42224b100e10aa6d539cd0eb3405b953d823b277599554a416c797711ac0089390bf15c0dddb6ff24214f982ec9e88df9d9707d996464353abc67ff5bfa0a4fd539c166cf4c941c4e2eeb0f7371ba25f28cdc1001e00447e7c895651d8cc0c90d7fe0fba6f31dbbdbda36be0d657d7762287a51b70bd925f547b538ae1be245da25d74076c4bba49e5aaea10cb23670b5d1037cbcd6bf7deab5bd4ada001f1c9f71080eb7081a5d1a230ff2eb090ed6ae9781b273b8d0e4f465f07df0c8b09cb5b80881fb077d436df1213614942e16b2516a23848cea14407e5d41fafd7c5cb590d6c6609ac29fe86058fcd3cbc7a40d7383f3b116b631d6972fc7bafd6492e6a7a7e50a5564c477fba868f8297490c6c48c191503e0ba34d4780d577459878465bc70cf8636e12d318f9fabfcda0ad682b4ec7ec44f8a661602d2a90e550cbf222912afcf0f7222485413d7f9ab195ea55c7810c27c410880f79c38fbc505a8ca4f2ef4fbf2d21c7c186b9f8276fb61708a600a786f33c6f8ab36eb1d723c08f246aa9416446b30d64f1f7a4b5e6eeea68bc3dff0bbdb0567bdd20db6bc194cb751418a569f6d8ea8086895dc58b2683f3037b83ddea43eb460112c93b203ec13cdba5ff46d5e35a99fd911e8b54a42a15aae6260f3de19b54151591869054454c2822fd328eb6ddc62e49d82fb740de58788804ca6b073b530b21296c8a19c0871221d936c0c95eaad450116b4db40b10218ea8465f618e83e54ba708730a431db07de226de53369f932607488dff1ba62abd9869513f18c682b2f0390613709982d42812f9dd6affe103f8a01429ad2e933dad03d85ee537d8dc0dfb79627f70be60f8e7da4a5a6f0c462b8102bc8dcbaaff8e12cda165ba29f3352602a97a865e0304bac8a0541046337151c249f6ae50e3a1eec4850f43d7608caa41d3a226886360d6ad660b22f6e5540ab19acb3fb3e544d013243a4efa1ab892913eb43f3c1814a3524cedb913d461073aef032a748199030127cc3a705c7c9816eb6df87a60c5ad93ea6d0316c151e40b642a82814fd483e1ac51002200575c5c3c28083007c02adec50c308d0bf4eb47d3ff7a9b8699aeb92cc9ecd4cd37939223035153fb6f83ca5e385deb95f71e4a258cdfe56615875ffe3002c3b4b7c35b5f3251859267eea7ab7392152ed4536a7a8076f2f1648fb54d74b8ec580c3f5f6bae14bc18198522488f9d9529ee8633224b6e58608456b1f88f28409508bf044e21617b14776b0f5f858d8a1d38c1703bb413f1790d294a251162896adfa83b7e6799f71c2f679b290580138be9dfe7f8b33510fcc2fc97fedcc6196d8ac51dee0c7b85860dd299b1cecb79b4f2c7ff79ada3abc4563fa83274053988e5780107fc595cbd36f40df106dabc94505a0d1394ff0682a591e606929e0bab2d52edf1b68d730458b71e0f7772882843c208ce5f27c5f1a68345f5540cc3d79a65abb0d9bf3cc595d6f6f136c87a38d05095b81f9b3015eaf6974b2009eb51a793361e23a6ffcb41f311e6df36401a837c6048515cc41ad447269ad7aa55b6364602a330dd986e4673d270ba0653854290d424003f02bdf1bdc6869724557973421f9915cf3ec93053c7cb0c6f0f84e302e609c6f83028664e624ba63f70663d6062ac77d261c04062e0ef44c0d2bbdcd6d1aa9b917e77f809c1081f9e101598099d900a381bc4d8ce1da023ad65f8f954f8a9389bcb652916f156a000a70c1bbc1e3da02f435612411b0dd18084dd825392d7b6d8154a768094e271075435b93ac8e9e5ff342cdf1fb4b87497eca1fb8c1b46da2401e96d3de9bd816775f630d6123ac58601c71120fe24bcb83fb30bc29be0bc26ba2904e1a149e63a934bd69de81d20d89e49975077c819bc73b6180fb7fd00609f50c7e3ce3771fd1f4dd4840d98cc9215389dbe717b489fbd941f02897692e526060d395b52e0a7b5ce27845ff99a21065c1a2e1f38883bc0ddeb98937f4b2788862e18327178ec7525b52b05ea9e39cd8fa44467a028d3a01f70967e9984ad7d1ff92d17219bf82e0dc771b191108147c86c7c681acb8a36771b903474eda4a7bfc9b6ab33cb5b49eabca65338e6d508e77eec5ec1ec703ab24a2ec900dd9bfb4cc0abc860691fdeda2504d94290dc40383ab035f6f4e665eace094d68b066713800569aaf357fa29c5e67b05fe270b4e59cf06f6e70a593e22aa7e482372fc394c563d4b990c53afb8da0c662da82d85f976fcca7088c64558e80a63ac20bf497c7b3766062463ad52e00836eb8060aa0cf16363ba6352848d8d992fa965156febbc092843d8489fb4f9e5bcd127d92a4505355a0ed2760dacba42bba7fb7b446251a98a94d006525015a6b6273e19c636b62e015d10cc14e49d329f8c32adcefe5fab349783d69ba0ccb96d8ac33e6918c21a8e6c330c94c4eb8b249b67c46836d264f8ad0e3d0427a2427834c3fec1f0c8cdeb2cc0b59ff04a0563613e015fafb64505a632006e96aa150a56e14a2d0377c4c4db724a292e1d04c7aec289c187922eb16531686b3ed055ff0252a557438b6e0be68794d1edcbeaf5be52550c64ca4ba7786664c2fbdbf0037a0a5a885f91ace6696698abd1d4c71231c66793e1ea6fa94f6c70fabcedd5ac0c9474e63be3ae7666fb776ddc29911e4287cb84202c3d1da254ac8398efc9f5ccccb62c20829eb0bec16e816daab14f903f9a056ab31e6685db716dfeb43473186a9a3eeb068943bb1fc01d68ac6422bdb728ede9ab932fefd874bf9018c701acec29e142911667b4b22b6fe03f9fdadb59f69f2530875d2af4162f4f66184562fa641ea76a80ca4bd1a9d9fec85f5c29d209ff3af68c5fcf215b2ab2d798b589c1b8acbb1ed8fafe9c7894598aa20813bdfa497c79884f03a29e9c3f57684d41a67828c605012b39f360e4395fafa09ecc695394a0a647c4e520b6f6fda10992455a85b5b41511ac3f2c0f9adba525bdfdf7fa7afb928da4d6c3d9240a4e0e35de25aa9d87b13a70e0fb87b21d580c28c403f26329ec1ddfe239af9b2515e86613b8c8bfe930111a5b066a8584eb11a18da6b869504340a6c95b356d00697ff12d366e02bcbb6f1ddb5350c8447c018435d6289e7a9d7bcb088c1fb8cc3449aa5e0e4d4c3720374e6c1eb76d81c13f0bd514be11c07c2528aeadb5cfb3bdbdda9d1c78acc375afa0d8576372ba512bac2778f96be345dcb6657e553de651fbf68e7b5df8d6d121be4e280a1865ac20a647a73e6170970c8b69bba9d80ab9e2828057a73efa0f3349abbc6c5ac561af98542d7de42a8fdfd58125fc28ca7b730715a3322f0d1f209f34cd850ebbbf1cd0a73cd0f065af4d990bbbb5b102f0eda384ea552d2c507eeb2637dc22ac5a205fc0c8400ea5387fc9a4b32eac65ee897c7a95cdc368d87f4878368117d501f68f8a0ffe5cbce11685b711582373fcb5b542d370e68b9d7a5d756ba13fe94d2430bb671d83935ad363710a43152734cae8cb30b96aed7984506845cdfbde1d442e3b60c7dcf051ff1024bc823174ee0cf3491ac03a47f8cfdb03472bb086ae03f742836ab63150373166f09df7f28f0321802cd55c63cf9f7a43e9dce44f79cadfb57ee5a910d164a43502763e1ca635449928afdb4352952490f65867eb805ac1696387876822857e2afa3fdc142004c66480c3c7b8e28b2dd668d9c63080b568c83482a2db6c6d49495a78cc03f1701448e3863cad27a79b204a72c29aa6ef4a8c9cfe816e4a1c6e2aeccd758fd66919c516619904b3402e8553e25d169779810dda0409ac5893465d809d1a56c5e8a4595f3306001eaf001419c047819686b68daf6405ab2e8a908a5bba06182f89c3fe1b85bba954923a5f9103a5a07aa8dc68a8d505dd0ff6663911b5734de86815c43f9798e8bc43dca2cb0db35b35eb7a259d135b4d1a4e0b72ba93eade6df6c561c015dd0b8a18b4a339ea94da6b1bb345388193df012590811c9c558182ada0ba995f08ebb66c311edb020b12225c82039495a10cb916d9e7cf0206712dda3abb97f63445a7f0612ac4db82a316c37ed9f0244b89b695f23a90a02075aec45d9556445c6003d42674a641f9402b6b13990965cef6479ef9352b723005efce8113204fa6a98777421bbb11fce54cbddf3949173eba987fa8de4a57c22c3aab95b9318ab2502e076217f1e115f295e04a5b5ddc41d7ac74e1aa1a4b8e2a97590c95e6949c0a55ecadbdc850fca97967b1ffa6e61ee7d8b5376ecf1c241125c3de180497fac0361350c0dd0bd87652085b136bf552a487cb73a93f50283a1a3f514c4c503670839fc5fbbffdfef4051811f4e10d12318926d623c023c73107c651e2f79c82c3f71038c2dbc3dd1248112ef292f25040e44b1cefcd478f9d5f865c0a8c307b16fe1d4a681f199b9f21b300d058a4f7a0aa902c72cd3908f636733bec81d98d73c0d5f47fbdd84e31b3fd860e54852c2d16539fb7db7b92cc70daf25c8d8f74025496610ada1d55233d74df1826ef415916f51d48237238208eacaf9540587580db15e5e267f7a606cca89996bb9381788679687ae179c7c4c82b08b7cc269fbb231b4a612f5367fce328303d8c7d3af92949b049bfc103e347ab442e124934ac1da53f1f03194efe3575054336926b141b3b19362a462311ddf0fd14832ce09e3f3cb28409c5b30b5f8260ddf94a51348ce53df432a47e441a366c049aa5f7829de50f97d7bb3d78e54ea8a8f4a73148fa2e8c21866550efcf3cc9d066bd93076d172daa723da47b60540384980eb599480d8ba4ed3b44951a082dbaf4ba92428962e0efeb75c54cd84639bf2b49dd58738798d424c80a4a1a8052b278e0f8483559395c584989dae02f5234190f809e76918f01de1ca38c9e6789b6a0318b8c5e6586599b2a88dd622491d10a539ecd3d64a4aa5a83159970ae52842b93f7528ed76d33ce3c380422cb96530e54f9d54699805610ae5f21e74542f1d21a400ce8a1a283b603752faa10d4777808bc52f9847fc6e412258c3fcffb938e237785381c87e358079dc9edc6f7fb4df276ff72dc2222182168a69ccbdcda2f29286f8c264983c9486fa3ac19d0f4f10e2b143204682a0ce795ad4135abc5e77c2a4906785ec16431d27df5d9b5e3c1ee3e99ebe14e6114d7c92df508a7dccdc3b2466bed60e5a4fb6a71121525e27d093f5a69800a2aac42add42bd4545669ad327c380df69bc80ee4f133fd6b3457e66370628ecff23aabc85c39d510407b208dcc8a0242e3b3a383a144871fa80e56f01c687b747bdac997ce968ce73ab97e050aea8d24439c1aaac67c8963baccdcd3b5673179def6f084bfd5c4e04448ffac4246f1ef9c344a3e9a946dd4a6dbdd46c40d9b62ffd92da41edbc72242af970230bbbdf11a461b83a237abdc087664fc5950342f9add882b3e464a36889fe63182531a8fc1a6170bd7e8c26e8bec704b52aca61f3af4ced469f7410b34e0296c6b5802d2fcb4b238f7282ee9c8aa71f1fbc318befcf589c03333aecf42219e434c873ccdd0bfb39011bd37313a7fd06f7e73558aafbbdc1acabaae5d7305add71615248da94c6ff747402444ea8cc548d1f7c257a7ff1e6a2828b1284d1ad355e47df96d7d0bd3343003f61041ca04b071b42ba49d6a811ec54c37355be3cafca5246c52e4d4d2fdc92443dede4413e4201fe1270bff8649d95b7ee09d100e688697f179077458718f597625192408efb79c2e03107a017372be5c5461d38ba1f99647fecf9f9257befcf2dcffe254c33149f23275e83e338530b07a07f0e1ed28cae2704fc741d37b82fb812c47795fbcb1735f4d46e1e146bc1063446c5197666a47e707023fc70f91744129f88ca0ae741936bb0c92e9e9b69190237e9ea8b80cd0f6f91bd7395f0e85e55593eee0fcda6f44e58e5b84ced3a745875ef89a9376678cf744fe64b9f3440038360dd47fd5588f4ac5fb788f372368ad8fb00ac040a249870c0463c38c8b9ce54948092c131d7c425eed507835bb9d8ff237d96ac3dbaf83513009f00b6d9c21790c28e30abd494bef729bdb4dc8fe0728b1d714ea5361e9af98529a1a519ca11f03fcae3c3209186563e88076e93204bf74bff7bfde5181a221e61efbfa9ad842efbe215ad4359b63c2e6103157ea348d4403559b386d910eb836a2260f4ddd29fb56a8fcb39624f9be577e9ecef75992e796d8645443d7bb8fdf178255331fa8b209b44adae2b6f134c0260bfa09810fb30693d1334cc03098b2c3d0ffcc6f7a8d2fb0cb9de40a0673d9ed52b7e5a7c24e547976263f0c2b26f0e7d793692d6a75d469291c578b1f13a83fb2eb84ebaec52f5482a0200a351f385bafea96b013e80e052cb2a8bace11319ed39cd37aef6d486f0480c208ac92152f08c1804196ec73dac6d77c1e45ebd617c36aa0f6a695fe8694a9f15773624b7b61a3bd90151ab0ab24f40d78866a3a37b2c43a4042dcce899dd277c92ed9d1f136907069ec84eb58d05ad1ece272fb3b13be67c27b73ab26f1dbb19351a4ff83d807e0ab17aab2e6ed83940166e5cecbc4741bec3ab10878274aa5a8e76930bc4373594501dc489c27baeb38ffa2481206cf4a8f2c24be0a3170d94085b0e1f26218d8286cf296bef27b39bceaa575d81b32ca8542b4d57f311bfe7d99cff5aafe5704610ba58630b923d475b3036a5095a8a527edacf9c13786d5ccb007619d052606b73d2d8eefd71e6484727826ef894fee14701b3939fa8e22297554e1f5a30fbf2e148282b6f43845225b4fd7d9bff12fd10723611ae5df18dd229840a1a204ae56d0474e55a29b2c831f4a4c3d8d1762e3d0630746fcdea3eb0d826e5edf3b44713ed4ed571494ca4cb8133350a5f12b8e0a24def2eea92271f169b387ea3d8d3f5971676b8900de493db60d57772a131cb52c35c078379d9cf4f6b8c065a1de8b37a5f1446c0b7d691c57ffbb2fa980b37e55a2be7c18957cf7f35d0f0ac3885c40266d252a017e07108628ea3da9c30e91270f5b5022d83c626ae4a803b5df60094c5d3e0022018d062bd17322a2f57b93fdb618f8aed5b3dd5ce5b4ba4aa8a0ed88ee00b1f96dfb93d4b0172023815b72885bd0e685cc07d7b4d89b59af83c4b87385f683b46e896932b0e5397ece78ecfe6c4bae708c6731897f9f6bb7c29615220cd0b34d512cd831bc38bd978c377b9caf0a4aad682360b3c1256ef3099399fe2d9c9f0ae0db64af060d9991188787aee8e55a8d6cdd285545ffd06047c1e03274ed23e1ab3b215cbec8074ae5141a6aa00cea240c6a9d99f3f3b5c6bea82201603cd852d1340b1ba88c1535b07acc67774d097eec89accf3439ea81fe62aa80aae8c25ad6fe7f91e75ee33f2e34dc8827134eebe17f1c14a1a3dd1f13e5b22fdce2d78c84b5e20efd013dc62820a11ec85454bd4ee21d0048de08b2d22525e6a8109ce3990cc39ba026b0cb852c15088a8c043a2dc0d3dcf3bf8146d075b5eeae405c40e9c30019265915e78a95e205761b3f43e802f45e8e593cb2030fc06c21649b8185ea3f44379dcbc7c685ee82d9068a7f36a743f39901a6fa6c0baa4179a78018addf15b2f27595fd290032f5633b2beece63c8757cadf34080575bf2010ca055215d3f8765c04955b9a718bedffb03fb17d28454d484b5e14ac0f6b7c82d5ba12f81eb1c97f10c9190cabc4107cf995ad8aa559885df172ab953d1a865f1f4f58cc4bb1cdeb8d6e04e5594515b7e86a8da6d42c94429e18e37dc28d7966f41fc87adf00988361aabc5714361b7036c3d23adcb23fd84c5ebedb159214aed2c5b65744ff04169ed8232ce5aeb763f8722b691f0b02ea81024ac3d52d180a29ae4866fab11ea091e2a1916ed895ff446ee9f9304c45d5148a265c8523889442d14cbbeff1eb4e94bd2513d6048ed4688f185e30d02d204861e40cd56b7ee2aa3528b1725bbc176f4e92f9b602f58d09d90cae6e21cbb3b07f598d14ff62e5f9e9c15e436df95991e4c55148209d44f9c83aca34fecc096ac184b7ee0c7a10834c2ae318d068b0bb5d2008472652f2863970dbbf7d303734bf158501ae07c7e37b65f1657300920a7888142531f0cb2e07b22732cde5786fb857fd38cbf44ee4886077fe1616e258a50905f986e6939d45a07fdf388de8b621891c052a1b7c39394310cd498146064f9ddfa44c88337ab77b7cd1fb2e653d150a94aa5271d069a5530cc99ef3b7fc08f8d008f722d79e9b5d58d6d7979b0b344e514845b2528c55a7481cd83b6aa664b2e6df82447ae2c94c4ca11e3f17c48a269f0c35c3dc277f6f43054766dc388fcc0fc5af202dc84f5ed5f7227c5836e903db8443cb4d2890db99a0ae2e588a124a225b37f5219cb935c61b0ec6bf137164a2660a270aa406f5b362447393e7f474f3186b2dfee6a343b0b29aeced09203c001cbce31e16718ddb55be14f05e4ee2873bd0dfc9894883364c401ff5ec6e9ee41197ac6e861709f14f4428f660cba52f3033f3b4914b898778a260cafc69240e72facfb6da2eab0cc8fe42a8300d0631fb73f6f510d4845ab9034bce1d3603f329eecedcde097424f996e86ad6fddd16862566150345090b18fa199e0d99175cf2d36b5b339921461be99296d1b111c2570cf5ab8f365c156d424a42738c8c603c2ce5c1e09497ff2c1e5ee7af9a43a3786376a767acd1a82af878118d510ea84950633b63fd3187108f845baa9b570d824d84030085c049265e6c1a0320c0ed3b2b1949a582d25b6780a0aaaa1a5c56b320ff3522c2a52c56f935b51ad46fc4cb82c04d4736a28065949e29af50f3a33baa0e0821343aba07836bdae1209437a0d07ae8be02bb18e12c9b79c3bc0e89fd6857a92fd0907680b45b93660467e100e85384388f51ce28838effa6762f4bc228c66ac1a4fe7ee43df9413c1c0162785ef8ea8e5da2a1882bdb7c95aedee4c6caed945aee0444ef839f5a146a6a43ffcff8ae66612938c71b8aa39e3580352c256c063bd969cdd1251d9dbe03d1473edbf401142b81c2d8bc3ab71b522931bd7d62b4de5dc92e8196109fb940f10b71dfe9789152514fe89d87e4eb6980ff384c386278310f03b75da7b8456e55c111888d7424b2304a5d0de8ca5f8bd9f576044ac96387e6a2cf4cbda61d717c20a47264761048f0d071298bc0500f750466e76a01d1d8a31916cde0223b9ebc036e068c54e72528d82039f7f3a9cb733118b873df8fb4a86647fff7400d644041cb11ae352d97d0525ee19f372184f9dc8525d4f09008ffc0a6e00b69be56e0add5d9e2f003c3b909320556352c0432fd1be36fbde0070e45c8371c3c9a6d50306287c7c06c0326e39432f06653767804df3bc0943de457a69af0ea0638c3d972cd3a773d7497ab2eb1a119cbac8e3962afddacfb0904a11e6793ad1234e234d0c9fbf1098708a55ca851aa9853f3394b148162c57878704949231bd90ee11ec43dd877b7ce1623b77de38a55a9262560d3a4428c7e618eee0825dc2812e5458d035ce0c1f9e590d205f21dbb0ac0531ffc0f723ca9d6fabe755630c8ad98466979879724b96039949f3fc8a0c7d87a3148d8c31e480caf2b335112510386d31ae379c95440a5e99030fac85739425465293faf4f87b3595cc07849c7b699bb5b029ffe366cfe7f68f0d59d4c03564d394ad2554005adf9d08d7747d1544ab819b55ecdc0786aaa15a347c4bff84af4bc34ad41f5799d7a0c798eaf831ebf924b288382c75de2a61ee312a50e4dce3e1a470ceaf3308d610ac752f5770ca1190a77941233fb6595f8024566dfd6259073e4652b7ee86988a6d85f958afab12c79aa182a4abb66d4fbaa56b642084f697d0ab1c768636a9f83e92e52c62f1cb27497bf79aff1400b43544baf588038a3f48c7d867cf34f8620f2b2be44f4c7a12293fb605d866fedb84d1c8ce5486286c7b96838a2b64c04918a37585adf8c358177856be13a4588cc198c2f2255e64d12a98536e973f18534b2c0b4de7606b9ff8e4a1f111e3993f77b260b1b38908d9ffff2ea48d8f86d6a3a54fd2e45324802318250d46eaff519388f7ec046876e8c8ad056d86160dcc4ea85b7fe580b993a548ebbef730293a8ce0dc73d152539b69ba15c92928412e61a1ae36c03a264d26c03a32230e8c071954d45ae32267e076514f9e086755ef50dc6f497c59991f038e80bcedddc372b8963c82c2caebc2132e6971f103850d0e0afda86c18121d04ecf2c7b0c3aef07b4eb64c5b16c0064f789564d65ec80a918655717a9bfc403b178c0040d2951d1463927c17b9cdc115d78b19d5681f88020a5438f055ddc8accca41624e9e47ba6e5ebf493e0d24189f65c0562bf0bdf3b681d1a911ded75394c60cbc9b6d1510c5bcdacd07da56d389d9623dd2ec92c3b010a422a7972b7b0c22518bb48fb4492d9b2c4ffd3b0e81fa451bac7923d17f41b7b1a7b027cff10d9d78114509c4a2670c80bf57f49da6f8bc2d0e70f3fc2a37e1348a17ed8bf05049eb20db2e6e2443e09d7a256e70b592776063acd79ccfaa8ed93d51360b5397acbcaef3e151cd95af701fe3f23b9ba1783271bd625946db063f500df76f83d0c09fea6fcf53e002b68c7a29463e86dc98cbe4de99ccb7cdcf3361a189f1fe53c2682d4e9cf346627c440cceb3464c558ad7c4e8ccf1403cf2f5cca31b32b67101a2180bf9a861426da99edd05029c992e3de84558bdac6128cff7b3dbea951e0d83ad336f584208e28bcc8cfc8bd3bd9b142cc33d8d8d8138eba454eed1108ba8eb66ee5a8e755b2f94235c5c463852e039a4a8a45c5dc1b0d571dd289e7f0f6a27dd88a61ffb50d216bc20efbebcb569762bc9e582423e2a3b039935d8599268c83a7ef948c2d44e8c47fa6d7da96ea9e145fdfd5e8072adcf45300c812a8514bf69c2d8598fa1ea189b44cfa0418200c90e7ae8d019240c058671d9e47378a87048b290f12cd612c2050b5a11f15f2ac2f1ddf2da1a65a57675518f133f46b4c8edccd27c5a073191f71aa433bc57dabf69d0685d7ca62a93cdf9ad3755bdb0f3a211142b124a54d4420c22ed1cd412b6dd2b60c7736150442f0a1ef8f7c257c80c2ebc5df0ac9789936dac4a6eeabeb1cecc121514650acb82e6e14abd167f08e15906b6285a3fa12b0483046373d5d306cf3eff924cddac20226ba6cbbd2295a69b60c1c1e7bea26e5a70b10ab37b16bdb033398aa43b730ee1d4d065b9a73843a57334b954c68d884c803556085f78c83e44ed52006b19351413f26cd963df255f4ef41ef3fd3a4777fde0befc64e9c0399b23b9d047c0a3760dee376fb43cf6492018fe3429502384a2f9818e895080665e8c7f8a2a2e57be52462284438ea684ca57a26440c3c83139a8e30ebbf572ceb4813193ed2558885b05dfdd2e501412b295717a1f786abab79fcc482cc9742bb63806957fd8b047fdd2db583d30830e98e9e489f44cf2d980633c7ad1511e29d1ee67812ebb9daa4ed27ac94edc435a452a49274b1874fe70953416b4f4aa3c47bb538a63a9562b36cdb5fea899129653702560fd5f467c4c5cc3fe713ea77b8081bc42515b683257608d774849450ae3baca742167773f9f3b44c62f85250b2d5abd6a46ce7eb5b0e5e330c49033a001894fa26a5c1b370eb2faabc283bd92f53b3469058e8fa4af3c694a665a4df1b59482c88602f5bdd98710e3b288928d1fab089be58586dd4ec192b786a133b8ec6348a2207f77292663886094134f5d518db2b9a7831689bf4d3660c0de3b20635b1c6014043cc5965e093bf5ec941adcb2ef69536fa9db6ea8d88d9574abcdbb6612d45d9539d88a9a183dab812407a638d78580a0b36a809dc584a111b3e09162accdee9915f865c61741059546f8b0d877a1e73f58f0ba36dfa307c102fc330b2d092087a6e8270c45e77ab16958934783ed100e8294a58cdfe6d8b12856c228175f1bc2cccc27225953654bcf2964559d44e6d147f6e481bea5e01f03e0013a38dc1eddef91c79821977661a20d8aa893112ead6a72a4724bbd93d2961af9ac19eaec341d879f2a70e9c0a237f838c93126e655c36304ea7439a5b213fdcd959d70521cc67ce6518fe2ab8e3e505abbd74c2ae2767bbf0a4348d240a4749456a5825ca5b8dc24df8ac675be6f098734aded5e208fd64e3b601abd50009508f046c046520edef41b6147366e46c673be5cf1e88a2b8ec82f28578eb83ca0ecd068331871c371e302b47a9445cc20dba32909977276d9ee4d5deec90b9fcbb6b15b5e31d2a0c44e70e72f76cd8a930681478417f42871e8ae06ea3dc9b46d79c1cd874ef3c0972186aef1cb733a723c969bd77f86431c019f1f2a4e9de55b5630066067508d67b09bae0b03f10a73e2bd53926058e55124bebfe278a556929ade2e394737ed9ef275798b8bbe58dba1b3b9d36b7bbae4b12adeb820b78fe7e0bac2bd1a042a8e908ea5c52b33410aba0a254d14ce8b5f811fa30a9e319f49298b552bcf11fb3db3704c6f81e6e0bafdcf8cef2a070819e96d74b3fc08e10f671655473f0d3c722d62d7f9a72042be570cb03c49b1b9004e13687955cd26e3de0ec89fa3bddcf91c7d40c5f5b9cd82b464a31f7bd06885d7d6b9d173059627c98ee136768680112b5f509c93173ba0975e695bf42ba3839a0f10872576b3c5a907f8b2970243443d8b42a07a0d264c0a0c9f88c6cbdc52c200005f557cdac3a51829efd5fee670238378b989b5a78baf60376a486d915a727f50f62a0724d29191ed1ff5324333c2721fa71e58bc2a99948b119d8b2f84c970a0bcb8de4074fc7b50fc8a2681938c681653373b24d3aeb52e3ae290202f46b30f95e4a332b4f4ba8c4ebde405aac82bfdae328ddd8c7534d1866e8292e44c7a43f70ae7fcd9282174a1f7f74eaa7449ff64ab34057ebb2793b6a82c8e1c6c68750ed654224ad6c04ebc55e4383abb2d060f1ec5f1c8918c9c5af3cdaca2877391374d7b8a4ceff0109a9eaafe1acb5515fe68e67c9237c29f0933f276778472268639b0d57cf265ec6790d56f5e466de5958f544f8f6c6328292b784d6a88385a273303a690f094af7ab2e7950de16da12134d3f812dd26611843d5ab5da405984caf480e88106c240b5a7d505e1077c0886765d57fb6bc3fc94abffdf8a04058dda83fb3525a66adde05bd1c6baef4e48d192623174b000d7e4404665e242d4cf98ca9ccbe896c3a19d0b41394d80288957fd09a53fcd7369822e65ca20dfc52a1fc33e86a1ce0a222f9e09bf05c2b3792d4cd7d6ef1dcdca60085895c406aeee57d6f386b0cf58c133633cf9c5e94349619fd035ea4cc35eaf1b37562f169c3313ead7489ef7e22a93d3eecd04e24edf0c59314dc52dc9070896923e0ae663cc0da33c0df682954051c6950128a822c41a124e32eaf1701c19d34cfab0dcafd06c57d17b98615c138fdf44c7c238b00e14827f89452f247811fde440aa9d8995f6b7577e611ee3f111d92d83336df21adc3a578f2d02a163f18c8e412b1b90f222f05c040d1aaa8c16b8ba4a8794eb9ffe48a34bb2050f1a4c05206d039b54856688d506be78eb7f26147bf3309c8efd69ec5f5978e1951677410c4e2c6f837f3767a1165e2a145daecc19ee4b1991a1e576ca970684f6cbc192457229d49e6c63a39dd2d013a92fd5bde09e51bd51fc03607f1cb4cc326d79beaecb2080ff0e28ce12b08e014778a50f53b2a539a18c98846bce48a134172e3e2b11a109dcee0f1287aaf8082a131a9b3edb070731052e34bb6cb256bf587b6429c847d9564af95e93c63f5d6e46f9bf3c479bba53c5bb6bdf3bf24b2bd993be2bbdb488ec466e85d10bb43886f7395d6de0f795d926f4c48e9d4064a23df8a6a10670f9af607a43ef42e11c017eb2a6400a2d0d2418087201f0692a2b50070ca495d4a4be4e929ee4e8f20f5df20ab5b94d1118b1a1f04bc510159374038389196f2ac7fa4da05288f2a2d0cde5009fa62eb7057832bb1d7770dd913ce7744bd134f2c7355e51e0f5064a5a5565645862fb1c6559f083640c4f6d31aba0360d3ffd03e63d01d4de347853d65104d0c00d5ee3cf776e8a7004465ee62943354cc4c320653ff618a6c6a40fc496f2f7326c874602728bb88566b0397109882b0b57def8727225f9e6b8118c89564e244d2af562e88fc3b3437b16d2bedb184f378e9256876c394e07122dc7df26bfad3679d04be1093cb6c4e4f3d9f05562e2f4f2487de9b3fd7de0c0f2b83de9a2642e53e08286e0d0716f6e19c567cb84f8044a7d74d391c1cd7574ce347288d465bb3de3f3da669a2e30d71a80caed9b4d7e17cd3b5f432e75d62a0ca41fc7178299be225b957a4d54630e67646fd88842c7a8515a5ba74b103f62d3744a9d30b6651a69ebe66a5fa30dbbe510d625e418346d75e7f9c4d872367282d52de473ab40db151055c3a671bb0dbd469db2175223b840f978914864bc1c0bae4bc5b18602ea8332c8f98e349b0a2e6362233a4dda82c5d763efb9a1c71ed1b14d65ad35f7de058a118b6361a02137d8e82407fe176734c1c171e5eb3d8bff12b94d3fdf6727b63a88210608e475507fd8618aa32e3a7e3262616e2cb68c5d98512c3b7f7688b3a8957eec37b397fa9f524a1e2909e4c7f4c1db86cf47de578fe9d5798c3e1ee33b710c8705ee763796cc00fb47552c76e0e4e653e119b1413f9c263cc42d4ed353c2369843e05f87ee1847b83fb45be0f3501b131f0fcf61db6198efcefdd49829ea3e2417f068ee967ad7e169a48b3129b8b0a0c258513f1498a053b0f5aa5120e7b5693f051f61cbf2f09e68540662afd2c38aa61efa6b261de7d802c783a3ffcfa61eb1641b4ec580127dc3bcb1dcc043ac89523165abca582c10cc8b723a749db90fdebeadfc179f674864adc9e3f5e4790291dc784e46f0b70e9987012dd214aef1b33204b4bcc0195a96b420784e88d2c62e8780c28ce4744bf2dcfb33d68b7ff22f6cbe2a7188a10cae0af69e9af6329c3d448414ddbc9fca55a496f780b22b4380101a80ab5ea987d9e75f974341cbcfbe31a6024c684af46d6e0b626e64b5d0c69ec4aba364e39c2200d222011f5edefa74f10cebd38f4c01436e5653dec01985c10394fc3962075655f376c9ac6a54e3aa7ed531025513dbed6e600e1b4106a77a82465318517a768cbbf405e25fb6931cc98fd06035bf798508ba9bf5299fe18ce51615ba1b1e70220f677de5e1ade6c0314938999d3b3cd07e887536a71e5daaaca8dfc380c8ac5d8e14ee134ac8db92ad7f12f98ed50e4feefad7f331a216047fb67b60ac35b5ca96c80dca80025b493360f388b297cc3b26631c1b96960f354b3a248df8b5648f60fdc577755bd66d5164e81fc45c5c4d73db426c74046965ade636b55e8bd54f485990874875dde408228ecc17db935eaf8fd39c9600cafcda3560fa69b9dab780a30dce070369090d99243446302e17853af940ed4ac650b34dc293c4465a419a3605ecd3485968d059ab8f5d9e38f3556eef3d9bf16370ad28344911e01999e54c8268adb4f208e7a6bfe86932abef9a4137520690d831fd2cf093115c056b0efcc6c956dec1cb57b49d3b47cd1cd7dd02ab0a0f9a53df61fb0cbf05c2420baeea7f8b4d1296c64efe6905c3c2ad5dec089eb801c87a66a5957ad2e5921854d29551ab7af00a2ad94fb443eb3ea309fa350a75a8700c8b5c8c9ea17a00cdd24646efc07fbfce3129b1164af75730ef4d254723600eaa0592eb1609572d76c572d11b989dc1f517ceeabb0fd8167b7315d3d9a596e51d458fda6c9e59b1c18531de420f616ec296e55b89a3acfe86fe49d145ea75eefb80ff0a8b067a7efd57053018da74dda40073436cdbf20952ae0ebd307fd49f4b45774594214a0d0996cf80329a6a990384ce5274bca846859a34de2e8705dfb0a76f24828f8f8a1f4c7b455e4d545d9dc1141ab469863cc959df3f63c21c3cd540fa3caba1f7de785c4a773f9c4cb71bb310afab4217355704ad481022671b35e884a8dffae6ada5968d123623df7c6e28142ae1151c0e1707522aab18211e6adb0a25658ec4cea7d5be043c7bb982a9f74d65db1c3fd05ee31faeb1af5597c6951f6aa9b2f1031c374f652182e66a74925c88a79ecdf49f940bf119ab886e210a22987d79d9c75375bf96b39263b39762318b23144793961db03f43c6a3152209bf205b4de389faaa36bc993bcbc8439ce3b60c7c2e0a6b3ada15981f39df9d735a7bbf70292cf022f0197f8be2d99851718da0c90c1981590914428655c10ac8aeb044dcc50f9b2b5160d45781123f5a1e62107537aa023667d5670022f0cff72a44dfe59c6375dcbafd21d88c79c6b94fdce94d496ba0f401755993f1bdd909d9f9c16db0371248d5e6a82ebc8c511a98a04d20153e91af26c0ca41aa84d7fccbcb5618dc6ce54ef3d2592b8333e7bc2cfd32fb86f4566a01f413c5defe56b89e51050da9ef6ca3a9ee75b3e1460bf5d8215c79279dc75ff43dde8bc2bc3082092a4e271368e72fc70decb2a12668d2ffe3c6baef50cf7c8103194f6cf3b1b0bb3c11d99dc3c1fe4a4104dbda5b09c1e315ec9553ee4adfa70a3b55c9113804094d43f6640c01eed5a6222ac6d844842133421336051ce059225d96c94d50660aeba8e3a2299d21169011c5488dcf00b20524471044b2ade59ceec0c496bc19ec4a31624fd1fb208b2b5eafd2806a40837b0451ca359cc5d916c4727b118746a3c1e16bbd05e33debb99d2efd74d1769ea9df006e46cc81994cdf46bfa7aee54e803f08b1efb0607c5179329709409e0917576906bdfcff1898ac86ad43e5c62d9acba8e1a5985b70d181964249ab1683927552752586866c498e3f0e2e858a97a038f53a7d35b3827d1bdd8f235433d0dfdf596ce7fb7305636d1e600ca85c2efca02d1694323bfb2f2404c2fcdab205c1871433c6d4cd19fd8b7ad1ce2d8aab0411472e0ac8eae8b830729ae5d648beaab616fee909d005b1041a52cd894a1b0ae635f31c3a496ac7464af859ccf83314b877c687da4f89ae87e715cf5ca6362838ad97db03538b3e10d6473dd4fe798b26c98201887662a2a3c4f0c068a13948b7285710344f923c09bad0a30cfafaef7c7939e52c49af4ec491ddfa30a41d525c03e4eaba07c1ddf56fe4fe20f7a83523276f0c7de70928c68818fa836118e64000094876da39e58bd3567684e230172a9891f0ef672de2de46d8c5086d26733e4915fe25cc029a3ca743f6a65388ec1514a6ee8b6852889d6bb479dcb25fc85e911383a0d09cfb4c2807b991843e20aefca38b35675490284ff76f2407324b0df9de47109284339426070108177c78311dce41d47f834dbd2704e89807c0dc8ce72f288fe123772682441aeed5f5ac8a0eeba93dc6c91d4a6715c9f2e166b7df163104e976ebb6c2ce3c11d878f4b041969f15c65d5042be2f471b50f6f14272ce382aa0c7535484583edb94e56e64aa98432b2b5a3a246b5d5d29f0c4203690a00ec0b1d88a55d4bf57358e4ae950746f1c0ce1e7e0f1c847551e4e0bb0dbb29ca06edbd324ecf4c904384783d0383edc6276490d614097d243f9a65c5dd169dffe48866d007964405e0a48fa081eeb366410fa8965899513e6794e0ad5bc0b53632d954db32b6ca531f6b0bccf25cba9cd3350d009e4f70169738e966609ef1de9e1746e340ed1770cb3ff5b445e6c4d95b7e5e5965f74bffa040fc20572cbd26011448db92828e4d5cb1f52f61361eb9d05ad26a820dd602ef7a61a4be64d61b404e50998d386b6b85b929aceb282ab8579a18f91361e58e5b646a4ea3127c41e4944e019d34eb6f2d2ed254cfd55b2dfe343a8ab6081aa940e5992dc9ac1f60c69b9168063e93ee575801bcb8866843092ed977d201c62748b7a588f77150bd9c9bec191fe3a0a0cb0a430e6c8d49700b70aa68a6890764e3d345d2f3055002929f241594ddcd64e2ef1e963bbc4d4ea9e1810dd79f46f497d2e5945a76e32a22769221fb6a81d1bafcef1f4ce290e85ef744e29b30f9905613a16a4159a7625f68b03c656d6fe3656d50c30dcaccb3294ffa37337ea84137b0679fa2c38bac7bffc4c56e8539dc6757814d848e248b004ebd4784f53a7c2bcad5b7e0c123a41ad6329df4ed1e673eed785d633c7677e4a0083332ee77c81fe05b711b0dd5ef2aa4839c6f6232d0ec96d922f001169c94595dca2202d223429a485e4094ca31649c6be425a030f97149303e1b24b9e280e48f47d40cbcdce15e6f003211cab55e71282adaf8b0f898945f55cbe3c6db93010fa86d0ac6a04f3e30d24a824823f603ea3a547e519c23cb88250f1d601bb3899a56ea0eb4818426cd18761f77edcd5b8cece809e6e3fed525678decde502a6868552697caf58d1f4dee6dce77ef84c0699e40e44b4e75edd60da9212e2afd2d3517c8f60407f6ddf19ac197bbca3145ed88d62cb373b92d572ca94b74da53407d67fb3ce27e7394b8aed9f4b934a50c2235dc6c2f4ea3ca95b0b75d314e5625beac4ecce966d35667ba357753cfdf6b61469bad069843569b4ec7cfb307b473d28554ceca3e1b9d350c9149fcb35eb3fe1aa74c541805bc77c2dc5a1e9f8ee41684d1746de3a53e2704e12f9c5a332261b30a53aab3e52801324157dbfea7b782ab4ed7d3f3181b35e012ea7bae0ab0bcdc748e4e3c3b41ad5d7ff83a1abe48a74a39bf207c0d785ad98414bd8bffbba8877643ceda5545031e37403d5da9bfd6ca99884e63d18b1fa4d5d61abdf379628218f1ebb273fca6caea3719e8e1d63521466c2e21a8dbe3262e7b3d96f61c544dc42d0fd1b887c05b43a63fb142b77641e87c15da55985a4e5686c7f63fe18ee0cc3068c3d7112d19e0f75f065af382ba2620116662ac8647ff32490e4445419f74196716c08a511c3affc323787d8a33049670a894211ca1fa1633c2612b301c3c332e19cb9509c22dfb84cb41174ec2ff01a432c0bb6dd97f03ce1b697c7e244ff078a1ccf96cbae19aaacc6667370a52d9748df88262b5310ec0a5d88616515b92b6875a9a9884b4145fdfd0be2a5d5e4e830a8273cc4ae5282b8976189a94a48f67af7dde2c7a6d488fbfdc063956fe6129b1c9b8fb6adace8994d3f2901c64bdacc2e170c93a28d79c88b3b590ae6da97ffc6e10ab929c1b732f43f1758bc9a61be968cec89d9cabf10f33766c851d27eee2ed7c18bd8ad5e39146d035dc0f8c0b3c2951f7744dc678d81feeca46dd6973c02f994d2a12f353b1a30d8b4dfd87b5da02f3f08a413b3561fc7ad4d0cde0723aff83aa158c02c503764f9c2e32618252b060bf5d422c9699d6f016178e36eb56a3b5e06539c520339ba156f8042ebc7b5436d8a2ec91427182e1744df65cdd0e50194fa2ca071208b205d5584f19a429025ba133ec52f88af37d5ca80ef94b6234c6c23c1b39348ee685bd5b5e755b0561f423cc1e333d7fd4e19be89a70d238bf0c39320a2e0b21ef56202dcd44aac5a0dd7bcaa90908aae3a4f264f1c42e428a52a3ec556b6661fd7a563671de4a290298ad3a601e05aea72ec5f314535f559ffd5b342c44f83dab1e20bf8415a55353fc7be52b0a2b31943819930407b2282e8bf28144a647e9d7c57f94d28e6aec7c5969533db2767fca072e5301c8b6461faf8c05011792ad4a9216017b2a0944c483a0f966f746c8576a17d606acb61a8f00d0303ee7224a1dda1685f71f5faf9222b95079585be7c59c93f53c5724a56e37bd14db73c1104b4fd34a9d82ac43782a19edaa54c5295e1c6464372c8f25c9fefeadb998486a11e2ec30081fd7843aed1e3b7cb2332b853d9245c6c4c5621033f94c0d5261b89376c61bf5468a8755b66c7e213b6d80781cfc1da1f0967c8349a2001aa6b9e2466f40d258ca4af89a5ec153a0da07a22204aecb8c70de3713495fb1f5a8dfcccaf6cb2b488ba8c9dc42c79458b4d37779360cc7aae64cec049ecf9539f4b6e38e4e77998d897fc4085bce170b0de3436b7a10010f169383112fd72f97256cb7b3f87400c4e2e59afd02d942d669602e1c5860fbe65b405c8643ec1df27cf2f2c8ea9233eff2e737f45b4b647427cc5e95cdbc5a867b00aca446cda29e46117b8cee87b58d2d26baf90d62a5eed190deb68ca837c0877f27d6516f92e8ce7f1718ebd642c060b7d3ece04cf9a2ac6f72ed8227b89e8844e3fac27618e3dd02b03c7942b96d07c4376175a559ccb23ce7c11192c90e8fc465c4c66d4558232c2b6328121e063c1065718afed382de57eb41c3fb0088451ca2610a0a93d725641693a968c84a58500a9024898bda1d7caee2ea048a47af5f588b48a9771c4fbaaa716dfe2a0fa543130670bfac4cea66afa95599ed9ec65720e40a5ce7d22294afa8f8a01d23c8788db1b0fce7e53259838e0184c1f813f5bd30784bc9e20e6ab80e2114a5ad0c85a49a68727f12900f3df7701c2d3425bc150c419ad78f41f4bba614808969c269c36d4a8b75ec1d38247692d9cb434d016186a4a2bfab4e70f8a18e0f8a4cf369942688247428e5c0b5e66b9977fc9296dea33402b29b2d3d1cef505761021e9a301b0c3f3ed5cf4c4188146f0629b20e5a841c0a0f5f668a91b6846e0ca61a339734cdc29cfda4a1fc0c17031888754e10f2d4831157df9c38699510315adce6530c5cc692a44c55f87843bb63a98582b38f072406e3bee3b026de9a88a00768dc0c49b89d44a86cd386dddab212460208dc205069cbd60852106015983b61e4b1190d38ca16be58037c61b24960f469ae531bf834100696ff700a39996ec48db2664fa0c324f1652f2601cb24d09675e7895be145c784c66d694879073b23e481fa0df2265ebfa8db47fdb0132a64999cfee1238c342b37d6752d1998e4609eaf0da52d10a096cf34632925a3631d204546ee92233414f9389042e291974e4e48725c0d994f050a01b635baeadb297fa3601a1194932e379ec15bd6dad1296aad4dc89082bc0629a6a2a96fecae6e31ca4e630338aa227cba6cfa0950ea138507ee17c58b905c907525ec1b803042e432abccb1afee47627b743a5092c4147fb626851b66c2f47bfe50705497c69126ed17c59d2a9ad0c681624adea03d3c1cdb8d131655bd16d6e9696ca46cdc4badc4359052d6351d25471b28b7ab7b91b0c49aac3030e09fdab5d9a58687495cce19afde9612415fa09d865735cd395d80381c92ac9352a850cb841f451996b1d96fb90f06c774ac22c1fb7804a69249f8b901dcc51dcb323d40fe9e3f1ee4f176125da685c6222eb514730281e75a20609353d4365495f2a56b0a0585466b7f4230261dcf243cde303ce366b8086a43705b787c69503e1199f34d1b100f908858a0955490ac06bb336281df6025a26704f89b2b0f9859d1cc79f80b3d4033e4ec2294cd8f5181ee6beaa651abdb0a5331764749641f918e480c05239e885992f53d43c55097fa985a851cd01cd61865556ab701fac3736458383752c4d115ceb684595e586f0c5a0724529e7e7cf0a626e3e070ba211a4d5ce6f52fc9bb47ec4211e871fe8fcb255d8d405051cfa6d484081e2558e3828072620808cab2758a4252b83b9dbbf1cd911f84abfe2a9a0af4054672960f2c3a6b0e20d6c8d6aa93b427c9080575abf5758b9de9e63e4e27b6d0ef3835719e2bcb131efdf06a7ad5448477381ccc8360fcf206a19df0365e87834c272ebdf8695b7574203b2701193e9dc1dd80ff920e5b0c51e060e46f2d7799bb50ebc8eb9b078b0c902c0419ffbec875c0875cd4baed9c503a690d314d237a5eacf5d00cb5231e0c7cfecba9e72a25ec4b7aa9748c65901ad55187d0899efd86d00113fc9b7cf0d48d52d1a6dc8470a279f50f4b130ef9365f4aa5349d6541644d613546ab045034a43f4e91f9e4d7cc528d50145ed516b75ae1d2d76bcb0e853671d0197bfa4c24c247f986328decdac261652a1025d70c692429164c942cffea01618358669d6bb82e3f6f37117c1625607055dc2ac0312a6aa394126c9278b29e7c251ee4bb81af11d5ce5f6c95c0faab7365e54e8bb1dc682e81fc28ca77701e78959c346ef5acfad3ee9c71720a3a2c836fdd74801be1e6746e3a9ecec6512ef4697de728b10350466cb31e7f16a1cfbbee39487930528a63cd9e27ad1431128607a6513a711cb16a21399b17b2a3991e0b8d6e20593a3cb2ff6d352398db497c38705eece44483a04442e13b091e21fa73961da2ffd53c9184c17ec279d6ae2a2803e8ffee038bb40e9346ef6ee367da391f971abdb3be699f57d80bac15620883a32f5190bcea0988d0a072cc4eae65a9aefde7f25b3917fa9f41681af8350100e110cdae6002d06847ef7f0961c7008ecbbb79d6d05211cea2aa000f0c36ea971b0a5660730f8dca4677cfa01489267c71c3e8816d0c53c621cb611aa56b676b9679e3e253b970166cb2ea9d4752480632651d40b41db10a0681512d85b072e499607643282170a6ff2e7ab9adfef8b258343f8b25122c8c51907d1fecb9e5255203e0a4fc0a77de559ae7321af4e415c071a9546086a78769990ae2e858e80460e3b1cba0edaae4e5862ac93cfcfda431c971d103a22ef6e60f6660c1aafb8ad1cd52d8d8049d83866050609cf36699fbbdeb424ae5d627f914e74f80980487813d37f7eb17d21bcf47ca019a16328a92e0e871da69b4dffa7247cd308149ae5017b08da7c5bdf0ce0d308daa296eb482019718db89627e4c9233d4707eaca2074be4c07166e7346839579c7de1dedc5c76642077e31631f9f2d07ef6da068fe3718c33fad5428b8ccaf4be84db2203dd9f2545de6abc84b9275a6be575ba26e305330ca821a2d87b2ea5be933898c3ed138014b73128cc2a7fbd030302ce0a63e94ac90d102aa6cf8705f0cde1fcae7c62aa3aafee5789a58a7a136945044d58108ff20a8d2a90c0a0fba6e358a94a618d7f28689717a959cc3f250f0ffad658939587bf8d0226cc2ea470f6c0d25045166597b9129e563d9bcecd138f6f3fd158f7c9b07a87dc33058b2b4f029431c97fe0d2d97922fb9bf57a66f3e5e4002e99744bef4201b9a5c2699b86add4419dec32713d65adc65cbd17b30c903146c075cf44cc1e7486e7d66519c186103606289afcbcbc67c0c6be0b0654a53ee54b339bb8a87c103a96ab147a886d4969e06c3a73a1d9f8a7098d319a0c9d8d17edcfebc8ddde53322594d709886f6ee276832eef5243dc790667239b2727d9677f9639783219be8d4d99c4d32953c65b08bfe81328ac3a7208f696a8b0325b7abdcdf6525ec5262b7203402748bc1b8b7ea16a84039a477584c51df900d68112dad1750bdb2b493e2122bcf9b5029875349c86d972db20f7d7e26fd721a6c56027a3b26611f01b16991d5220a13198ddefcbfae0cc70afd02c7147864a13e14e9c745db473694f68e3b41c000e3392b333b74b0ff27116a89bf62b06ca21e6dc1075ea35a7d125b193008b6d3d3c0be363e204ec96ccba6fbc93130fb8d5dcce95d1bd72178478bd522e848f78be2969a7b8eccc2cb3911e39a2a11050bf2488bc51435c7fafd51bef0ad99e277e2e0dcf72ea503940e0e82d0168c733f5c6c906034a01f175836c546e8997b29433960f49d4e363ceccce42103fbc81f9fa6fd166e0d0ecc5134a085fb1e06dae70d308f8f39eaeafe01d12e1351f9a4217b0ec3e283794737d78589168879b75522af059cc2798b08b66455cb0d5ee4cd6da0843aa0e524f119cf5589aba6e2a7bead2a1e023ca6a1678cd5c517908972c795e925f0f506f31e52db21cb18ff8c487f0f6ec2fe4e77eafe444e798fab733f67ec5af79715505850e950c10b80fc06cfd989fe6c1fd166a01899d35edf7682f3d08a8b578a0876cd5662cf417348bf3b84944d81f477ba7f688b45dd912f2e8ab8cbf0601ae8b7dc8162230354480baf090c1026e8acea17d73f5a8f13bed706a650e12c38e7ad812b6a9b4c5ead46867e4f5018695cbcd531cca58f53f08393d21f3e42ab200354076a4d83dd15407ad070a3aac2616a6a87554a72614f0bb04b8981e359f95d9d0b210f864c1a481506067a89488e3e0674b97813554b36d931e863ca7f970a9ea336c9e786253fa8f2a033ba457bff45a1751e2893a3d75b50b7ffa35131843884ce7ac106d8340700e7fb3d38709c6cfbc34181a97d86191b728cac662f513c3aa22b199c04a3cfb374b37b61a1074aacac16199ffbbbd4c9766c7d539ee81f17bc33831af560fb15d563cba94dca77d867ec3c0dafa665027203eaada17ee3b96d792d2d300b13c82201ae95d050cc32907c051c0af877bc7a740c530e6f86d1aea09212de7b4e634b9cf8493f37fa53afe934a114c1ae341094a33e168ec4003424d0c45dd12b5eac9acf2bb7929c62aa33da318e856ac0db6a215b9289185199da54519ab01a21e86ad86f7e6e017a3198d76958fb54afa805d27f63e0497f8a1b684faa3971d6895c01b2b1869a95f23872bdbc7c5dfa19982bf4abfa6a94b331880c3a917836918c2bcca5d6c41e63ea30069e70d692490a329dbd19ed93d39f67cc99d8a8cb2cc981c9c2b9782c29dc17cae4013f7f06947c47e13ae2f533ae5e94bf21fcafeb3872da8d40906abdd10b562439f4153dfdc954f287bbc279905be8245d1222bd2ef9d0b517ad145547571ba17bef2143b5b460414cd2de6eb480c0b0680819fc08e22bd27e50219443e59db74999dd48dc4870deeb0fed561c47444930f85b9de9b70c633a8cc2b61990846d4a9b5bbef6e796c3fe394b51b74acff9e066f538aed6619eb89502722066d1fdf93f14c717e4cf5861f950326b4b9d5c853133de34773cedd918f9adfdb0725d2febe3d3441d76aad01b37723c7cde492fc7f89f0f0968e2c53e82db6b37bb9bc98c4f8f26b6911abf372e1a415137a2310afe15b782c1720255a9611d4048ebd14bbda5ab82f70a586971ae0d9ad0b3edbded8c1e62c27a23acc614269a410d6e4696a34220df77f26ac10732a9a6368574d6c353d54a95c0d9f98be0d984aec10fe625a450d9a6dc2c928f5b3ca2765151fb97c6012c67640c06c68fe2978cc22522436832d95a69429349ad4b3bb44c6e555aa1cb64aba50d5d26b72e8dd032b95569863613ad57f2a569d5f23aa6a2e3e444b24bf6c04a13c8f915dc8ce7a3c32684df9a6f58e9872b10841d29afbe4cd89a5527ebd23eb1eab25569852e93555ea0439bc9564a23f44c5b0163254c392ba6153a265b07b212a68435765ae5298d31632b3d722aa0ad2688e8481962cd1b3b0ea0492e9e4c32ff66083092362655c486324b124e27b76687ab7df790ac5bc24f0684481e4244067380694fb49d88e10dc5c25267f4e8640a9a560ddae122813b7dab8a4ca534f0165d2c1619a4c3941500308e855d42b9b087fe3c3619e21c9e254655435428d9a99a501638ab25d155512767661465810c7d1ff5ce361535f55152ea50696707d0812114b00e79d9822ef516760f8718db85d93d9f18118620f74bb29ff616b37880689b4db6e49276594ec88c0fcd3505f73f36d34636e8e9f06f932c84728240b6fd9a49287c5be1cfa23212655248efe02ab6660e3d77deff5c6536e8b509f27e869f4cf8c622cf466b5a49fa5a48ba3ec127dbf38e22da3848418826b5c20895b04e176697e6a59ac8314b79a2194a4cefcaa1f5193c03c259bfa7209a66b3ab543c13e72b9b7922a9afb170c53f9d2977a22045a46fe049b2774897f04f56177a734381c7cf95f5c28e4fddbb8439ae34f1603fc1ede59bddcd64fe4f6f13fb18e7fb55bdbb81e0f1f3c97ab5e3b78e25d88956fb096e2fdce48e3af37c7a5aece34959fc385665979775e2a6821688e86260d25499d6e506213c3ca94e7babf936d504b95c8614bf2f49b743562df8981b464f9257f553ec9a97ab931a57ba1419b93395190ac199b7dc1c52137b5ef3a21dc73ad14bf8a6ee24e2b8ee8057966f22a86f6635ae56633292d8b63836d7aced9f756b5c2657d61b254c838888222b8088f645f313bd4cfdfbd8847f58411ff0dfe34b263fc1fa41d1fc242216ef1b2ca768d367bf111728cf5da9b4b770e1bdf0fd29efcfb9a28ee8beaf56752c5472751b966c4816116ce4800e493313b32c32443b1686bc5d3f2ddefab7e206cfe4ea6bf88bf6fea4e881feaa631f2243b4908939ac8927961390739cabe00caa8170ba28caf0c1290cd738a2b756fd91176126b1045d266bde61e3749d084ac944a710a9bac1136d318c48be31aef6cd6a498dfcea692e189cf2cac88679a1b0873529061ca41a69bcb2cb8c239196f54ad9643108ff367d70ba4b89da5f21fa858a345a5c8514e7cb9d30da136bec010aff8156661dbddfc9c80b1c078079d39d57146a1d496f6472aa6c0cc30b897628e79c60544221b80ae641dcf5ca1ec5e1cce4fe3dbe5f5e005487ca66168fe2986acc77eaa6381e34d352958aab8e702c03af0dbbb19a16dfa9564e154e55b4db0eac1f79bc5544c19c4b80462fff1bdc463955314bd2a528d894e79997b6fbf867f24994ecc2716c5564bb68e79fbe31e98def73eea1c1575e6504aa2eb8f5edc40483c24d521568d45ad276e9bfe7e50f7f0e4c0f779b1583a7e45d9e1a69128f1d7c6bcdf6f779ed8d3d8410d2f53007690b5e9c6d4537f93811503d94f76ea02f7a88eaf39d588bd52c14c679a0aa7e7d3c2289be5c591b8eb1a4fda8c2c1c5cba6b6a50bad00adfb8797bb8a949503dd58da0c93ab53da17ed06bab546fc06ba5733ac73788d66a818eea0191295040e56b022217f86343d34ca4043d0d64ca215850617ae2963e75f45dabf67d148279c0a44605020676655ec323c0f97a50d82c7258b84b46f841041928089e679ca4a9e2468aecad9a6d0081cfd0b75ff4bfac336a790437f10d518742b67249d69273a21c1c66bcfb76a82beaefd89f3da96b496d1366d6a9ce70447da434b41f4872bdd1db933b4f82f31883abf6ce98d667aa41a038baaf6642471927e30ee70b9ce0bdc6f9c5393a99b3728c1409c58b77aec0f7aac1c93a682ef8ad4fbf84cee07b4492e54e12789ca5c352745406f07a8e69bb58a4d04b8df556680486643f182550d9f6cea372881f5d39269dd7c0027d52c8867f1566f165728a462b5b7586f8dde113a932825789fe824bd0be271759f24aa25c0a09486f6bfa07238e58df28e229ae208112d80f66e38ad24880216039117f71452cfe05f3f66a28276a7d5dedac743db7537522a9eb2da35ceadfcf63fdaeb8243cb0ad501d9302cc311a54c881f1b7e9b4e2cf23442317d85ba006c6f4ab8b9989f1a64bf25e5987d2b6580484c5f31d71258ddb06b2b0d4ae3b0c06193f196759b000f858099462c966118737225f2aeca1feec902e63b66313b9b93ae331c5e9da36dce732dd99ebe92899e90724210168df1f6a632539e2aee69e7a340f39ce5efddc680114a65fcbd7cfa68bc705002acb5212c4b899a601111d6e6789a456a1241a0aedd80e523da8bf511216c7d8caf9752a9cc59c5d8a22530effa28fe76d00e740729360b3059d8a3459717b08c79cf55cc652cfe4ccf711a2a7be0f85b835654ab5bb6d366e2f933283eed531a3f2c4cd50c9d4c449c2184a00be1d7e57e30b5582bceaed586119861cf018ff957c151d54d3000edef62b3446311912da18cdcfc2aa297e96cd3a891f02c4840865de22859d355845cd82aa749fb368c42a89350f70b430d0eb7b688c302f084078b7c60a92bc520854eacbeba0bedf153cc30b9dfa8b4e092798356d916c12125c6c1e704a97501e133691b21669780ace1794786e1152ce8fe8d293d4005e56198fa112b224a8bc9d21f0eab5ca32ff18ae3dcfa0bb089cfcd5763dbc4c279ded709390043f7926c06c1e3406a31e149d70b72e16fd6820b93b8a77d4256a8331f727c51670223659780384bc87be5c851135c5f606782b4fa19218da243068e33556c0eaac0aa53f0444194e80eb8b9c4e89a72c141a026e794173fd3e01e5117a7bcdea439db1d22df1b5fd57ee8eaa7ef5dfe354399341177c8a5c65c84001304f2dfc732e4e26ac77c18d7bc25ccc763dd5244afa356e3ad499c8d01669f49036bb18dea3a6e09f37ee4bee23eaff72289f3ac11c882d09116f45c4a96b4a897c7d26c69b798da7dbf675f9e97458667b13d5d149f77e68c459f0b0bd161390ab33b07dc3e2b3abce009365e723bbcc488d4a73105f73276206641b11bb86dc6ab029c2364ce0b7e019124cd018be6332890c0637d022f0d337ff36680a07ef24fbc23795bae126b1dfe1fe8a0efc19ee3ac00e7b41c73b7354e0fed4bc191c68ce730c7bfae62387935d7f588b539f68f4558c9a5858b7e34d0e42c4a6a5b99bdfe4107937c65037f0187945a177560aee6992f2798f998e80971abe544c406e029d8e9336ae9b4b14cb1f00c9807aca5230ecfd46dcee8afa5f752007635426e39a6cdd2d5e27754285b3fc79456ca26a9b468aed9d837939ead983b1a012a01963bd22dfbf3028edb6434a2511be8d38af8fd25a4e19a7eb6b0bd9292e95f41c9baa13eaf01884ba29c6733f36836792f2c33718fe11ddb750c30e33f9af00c69fa2c1ecad9e079442b96c5978e4fa2c1ca8d64423b92e230795aac7a23fc03905ff129ed2518b785db9efedd82454a6159b3b5962ecd681b559c86de349b640bf33f5930ae49b4ae6154ba29e7c064d26f16ac7b1da866cb701e5a6030cb94ab01a9de1e816c285b69261a501900b76152c79cbb6bc3e7c3ecb098ad6fe3ae9927db4e670485d985e2763e9c33689bf69ff84fc12a14e467d873f4cc27c60d555679c8c2a48407c0ef114577fa30d2ec20036a42cee22ff67278243f952f57b7e37dc7d7504fe5d004c5ba98c5989d331db9965463a8b6be2720321a545c1ec20f68217d846781cf07635fbaaae552300f76fc54a1c9a0323ec152ea3d973bccda6f6712b94ee094816621916fdbb4b77162ae5a03fe9af721ce90c4d08d7ffcfc4e54afde55d5e87f0caf6da6fa854bd53311951eaaa23b7c9f3048345651d7848d0951ca8ec5b55c3c95db34f51bbab3138d481794b3ada68bed6bba63560dc583248fa14258b205ca4289078f387d9fb09e87c29abed1503e8de4a22bd5f15e22f2a5dfacab2511dfa8d60402010fdd019c08e6b61734130468a6a454ea95cb38f2de105813c17f2136871656a448beea7ef039bfdf980ae4c4d2bf3e8bc64f1bf7ea632f96b61cee9171388632227a7c1f76d1085bf6af82ec104224eb93a46bd77f7dafa199397c60cb7f2b827525045d7d08ccbc83d71fd1c467e316fdc8cfd83624134b12a0ab65ce12735ab199fe8084f6ff77dd190384e07be853e4ab0af181254f6f5a59bfa36cd5bbd68ccc5e3e78b70480d6b8e5935870f770663576f07acd7993199409eb99dac21414daa21bf453845627b13bf2c5a9035eef97d9fac3a59aaa9b8e2572e2f66286f681533eb394195b444207f75d3b61d0ca895a20f6be758341ea7d2dc353281dd53c8c7dcdbe2540add78e9a43dd917989051f0bf429ac267d0c876046bf0ebdb1e8d3278fc74295e3114c71cf8deeff43ecb7c13d7c80fd36947b5aa5683fcffd18a1ee72871be9d8f7c610461e1df616091ba6dc4de16b845de9b435a1f1262c7580379e62c873ffae96ccadf8cae33c8bee1bdc3612d861efbd21f4fac0737752acc168950abc821e0e53b9e681f42d1ee16dc460e1d6ab88875bce9372f6ba4892984bcc49622b59029d8ee203bdab2dd8bffe1de97201fc84d22333313a5ec6a7a434e20753fbd4c502bbabf7f700fe199a6ccf9af8cbd795f9428da16af6c8b6f9c90276e8cacd308be5e23d4858aaa34202b983cd4e09612fdd748dcbb68612a0562b26f526e0b82feb0c9dfd093afd31ade094323884d7eb4ccbbb74029ce76ddc0b0b97c189be5af666c2650e790678e32b918531df6d40a16a726cebb0363cb644862ac22b61c3d71d01e9c60302afeae6d49774bac6ddf0b5060336581ffaa08ffa583e64b1ad360213a680afe491a986af09a62332b322b50b28444f4639801fe5be277b689f1a15238fc4c634b8812f47f2d9539c1c55f381f3f6e2aa00779ef471c4a418d14209ee6fb245aa860ab33613efe16ce4bf38274517c1176957bd8ddc9975858499f20c3aaea69378179ad1d24962958f57b3e9dbe2373aca2bd432e4c42a1bc2acbce3bf94039a10b11e3c6b1050826a8124bb1f8f247938017bb570d8b800a70767fcd1674930a9158891efb492e20f144ecb88457658ff3680947db98220aa83b586dfe1707860200f5cffebb67304e510a404bd6fdff8b54d166bb50b8f236d511befd0dc66dd9f014c8988f470831474c0b7d046435641e02288e89c830a74c139e56e2e8c918adf80bdd54444779a60e60dd1b6531a117cb6ad90e28f38d3b67ad72c2322b3948baf0bc43c55e174060bc3b009d8e176405bba2cc785fb93df90ab137d1ac0d32f0b51ef08ab1634278913cf0768925ce3f19d798d83a1d0fd7cebdf8c682b07521fe3b9737d53d28f148ebc0eee0f51ad027eb472a0bc0ef623e0b1a101a5e8d01199cf567aedebc7400bf5a7c42550036f46eb8b1b467456fa3fbb874c75eb37c8004ca665da582441032b9ab778a35300d38ce7d7abb989cd70a45eb05abc61159d9fe0ff50a52674d9bdb796e27111cd2386714a90a76c0e1b8b8a190c6d966adecfac25aae431a17f292987d187d78551bb8388f04af99af35f77ba18a89448b03ae7b51ab721c7c5328a9c4f0771712ace2f6f6114b8c051492b3818b3130f4405522d323cacd0a55170cf5bb3ecc20e8e1ef18c5ef7d9e83961aae70e8edcc9880fc0881c871cf59200db3e0b9328364664c5637e2eb9cbb8f27da69357a0650d1bdb08ee85bf9064c6791d4a18deacc9c63413f82c4782f66c2a3348cde5d3299c397a0d0cbdf50697094053892ae7655d698e6c2afc7643f6c45f2d8435aad56451c049ad1b82b83c0344b50db96ff1e54659a414d9da026dc2bf256d8e9bed45ebd9f9f2d04962396b54681559d7106e964c4e6e5e0bc5550269f6d1bcf4c2be090c7fa89ca6798b972c4a46199981a38fc8e96015f5bfd345ff0b90458529ed5e2f932e7951029f6b784eaa04dad52103cbc5eb8ce5eac8d2662c27a917e3bf6a330e8b01d96e50f8e7203445587548528aae61106a0044f4ea8b698caa5f5e8a31280047d23e32c75672b4ce420776174ebc4ef8f27089020e4fd517a00a6c85df913bc5cda89758010f700f27dcb57d43e8ce2ad26007d9d94b072d0a7c3e12a093cb504f763690597e49592b868147c65e554dd1eba8374ce5bee1962b024fe2081345af6c1cf68fecec4ae667398e69248a6ee13173d706e55c0b1e9f6c4c2601de7ef31021ac96a7d0ef0fca62966cfebf79711365ea59002815aeb9948a8a9415bdf0418ec3a745ce7517924cb2554cf833fe510fd010f7b5351b3620f6ec12a513ffe4cad4911d82c5d94d428bc751e4c3357018cced91c84ce3d885d4e01cbe975797335ef57004dc0cb12c0c6b0b16999bd21ecc969bb3bcd020dd05d311bb15b8e9a4023d19c13070652e3f92db24e16d0fc4cd754155d8ea544c2991380fee8495ac4c41934da74bd3dcf105dd3ced9a26d57b2d284c0b64ad76022978410acbc929fbbd6e2ec9c2e21456d57b8d409e711a5e2564e16c998dd3f865bf7f771f40f5b5e4c0bc845932aa620a1b70aca257c0a3a50c0b7130f1ea7157a83f41259b1b36d112732025765a96b1bef436282f099275fdcd81b90531967498e5de6555461f208c2033d3a53827b3f8e336d56d9248cda3b3a4d166143523c6f27a85fc3f2d02398a591c8a711402c8a7a42107ca0e43d2f71943972a3e515dd4230bd1e2f6704b47917aacde06f60cb5228fa2e87f84466b3616fe3c4b47987c4225b663157397fb6363795e988da5af6d02f5084307102b69a07bdfac26111fdfcad68e0ef748fe70ec103a76be49048e2f59e5f7dd4e1dec9d67a875a7276b9175ba394dcb0ca0e9e3b5b2f2341dec15a4c10562c3665f56ac8433240c22024f61fad9e7c5f72e79ed2be2a395fbe98d086535b7f8c287b79c6f1b135f09cfc6320811beb31a142868ad1db706eacb758cbf9aed032374cdaf0cfb340b45fab050ad22439bcb838aacb2329c4ff2ace4609e46ad0ce7081e32346ba66495e5caf3147066393ac43afa7cfa185147398f179f37c846377fb8bb0d93f001c1e82ad379fc1adacee6b39d43bd297c9122c132da36dae679a68eb0e3ab77a2a12864038e6da043b5e99513306172b32633f333a2541d4a3c65a3fcf8f1925fc4e435e6084b076a301f5bd1f3a437ab6f7952557801bdfcf4766c997ea158d8d19581ea956bf43b4982bbdc2fa6709638fd331a576f842c23433f0e2c054befd0e1418fed42ef498bbc586302aa01e18d7a84cd69edfca4b310d18168ee36405a2267682542a677cf765a46f44fd959404434b544683209277c1d1f98221162630a02781b1e5ed5bb34dd6b6db0353ee7407a9160fd8df78b181c70562d1a3f6da9f90bb762d59286a55ec2365a18661c8d9ec20178a4d4da7f52ec046f67ca18c27037a18d49c19c7aae7a7f4818e2f54647ba40c7b133bef4384399220be77d3836050e80dcda8b2b902b0d6f65803b004bedc06564d08be902d625a64fa07fad153d583af492cf6f1e3ee2f3d799f4026ff0feac8e310f771e25cb21541fc7806e7a5b38aecf613400d0e2a37fc12d051cebd34db631bc7b072851ee2095f964b68b4eae5f6c3a42a7cc1d1844cf5b9047b19604e4f78754c4f76070a18f9f8ae920e7605b297af837b4f46e3828b04c06eec5eceea13188276de869acaa5728018ec7e3889b51807571ac45407cdca5ab04feb20ac06fe1b5a3da0eaf17dc87f7e598cea064ba147669088a57e2e42de8594583e27c6116b3ec3f8114a7920cf4251ab916c1bad9adc57260119369116b30ef8bbc3fa312ae8369a87df2800a81273381c3304a5b23d04b3f28ad12b13c3f256a2f360c666f698e6332174f9ebc6edd4ff9a3e3e16bb718584979bbe0f5c1c753c912c04345467c47b7b7537c3db678e6f180f0928a9606d62b6122279c3b9490fa3f300c304e1ef2cfee74dc61f7ff6a1069a4f90e4fdc4dc5f50748845fe0396c07396085e08ba45887e74a5a03e9d53f69b2dc97043ad233bf55205c914d3a5881339e5ce3c9359efc9019739d4d8746d8a2c9507138c6c3d23a1cac6cde51e48ab045a28e0291a209235e9af1246f60be4b7b6ef440dc05046f694636b48731bbab9935620921441a217bef2df70e510ba20b890ca7a7a1f57e3c514f3900bbaffae35cf5bdc95bbc4f82b6467e470d257b5868fdd534109477881b375aacb45a6aefb7aa3494b7efc4140e7bd27d091262d621414dd3344dcb5593adc9cc94cae286277712ad72e54cd79d0d58b8d2a703f665a967bf7a405656550506ee943be54e9f9d4b43f79194b917b91303783fff0d81f47dd23550529999ecab285d3367972739bb49ab50cd7a48d0736f15791351ba64cece899a16da48a245ed15572d94f4e331c96a15373a79b491ad3c0a41abc82c6e70b23d095aa5ca2ca6e8c9f6291647b6da7c9e763cc1c8737e4ad79c4ad86a6551962cfb0f08a0bdb42926bfd12a36a4abb37d120b902e99eda4337407924ad20cb9cf7324d9dd972bd2395228f6b672a266d2839480d493422766aee1cabd1d327315bbc08db4bb862b2bfdf915da52807fc2ce29837b74e7708d6ed19dc32dba47f7280c25ad32a44a583d89fb131e897a3a68c5da43b092dd06c932294896ad46bb4b4fca72d01e5dd77536b396748ed6eae920cdcc5a9276ad566bbdb7d9bdaff7de693f67c55d37b916225313e964aec4cd9bced119327166ced739376d45eb5449bd7f781ea4a637e9defbceb91da3f3a673e68b5e93572359315fa5cbef5e12d83a59862579edf597746f5b4192e18a9492cd7b755a27cf7bd7741aae5099e50443fa6d1c32e7d659b8919a482369b76379dcb4ad619b765ba7add86eebe4ed433a53f9ad84bae05642dd4df3b69c8942af793cbc7747e1d33ffccd1b90b6a4945a76eddab665a46f5eb66da4b0ade826ba5576da4af987b993176a29f4ddb5ad98afad0bdb8a79536dce72368a20d7b662bee4b89daed4df6bd73e36d1d51bb61513857675ea643a71da8a79d33a6093b84801041a1a20d008618a3e570a3ba773623f18d8f169950e996851eac0785aa567891290d21a70b543cb52b2ba4ed81c6a71c2482c06903b88dcb731b272bbc02398083427fb0d29cd096b662ab13236a6c5fe11303802063f2dca9c448bedc349501b69112daa3079be67774889248bb6aa85790919c279ef770932f7c6f382788809b6ff08829482a75fa138e0e7350f08cee0ed0c3d4d3a3ef57146a62499964c97ad4a4f8526ca3c0dc78af34ba7ac5f1d92ac4ad4e27c15fa9e0a4715ecbb49c8c2d4210b235d740a16a65556e04936a655442ad4e2769a69b6da4b789c91b750c8cca39d11323357ef7d5e8a918f1ebed7a719a561fd82008e9d4365baa5fa7ce748173d898b8f601ee93003616d91c40d332ee89047c22df23c0e4caeef51bfe2dd0b7124694aef570a1735a7569d776175815d5ec4c8b9c65507270d20f7b1e2ccc65c58755a9c3b66a6efcf579a1599b7cf572aa4cb3e480948bdedce5adb2dd3229116a7a5e9933933340490e64831f21c4d81e848c883e61baeec49610d5776a6553a24a26cb09f713952a2308794474a542b4d9e9f328b24d04c9b3cffd980f332db9d295d12366ae2b45acec57e83aad640af9b20d5f17a9c642ad4e26c2ca4e649d3a2ddc9f36d77fab333923569c0f9d1d2a25659b137a247d2957d9ed6e1de76db86b5b853634300c79ae77c8509a95467a755faf3b2c65a85e6dceed8989da1ad190779323feda0416167da053d833ced0ca8a239dcd7599856b132daa4b5a76ca116838a68ab97204fe6499a091c67e439d42d59c4f70370a439799c2fadb2a2a20e2c68a8eb94d57eab1e35d720730b0db4982359939b1e0f2d6bb96e91c799bb9baeac7a58b155c4121f80f735ec3ec9d364d262f6bb5ad5294857109f31e9aa49b4789f5d3b7343baea350d045562ce9174e67c66be909028fd7985ee586e588bb33b27fc21593d19fc7a008ef3e541e4596162e80ccdac9936adb2eab9c412b627d53fbce09e9bb75324959d64dd2a5bf77209c9ba57c208e0d8e52b8366cbbc9f2f17903ef9b6701c031590af054c94fb7b26a42bfb0dba37571c0bb8f7ca2d540dd6829325ac25068a9d2cad0005ce6d4f0b2598d54c0217182173275d14e6a68093269ca681a0ea46ae373a45660d7c4b2cf21c4010795eca9606e849bd0de99a796a80d21bd22cec2a401c560979677f33bc2159b5250698280238dec8550e79a08995fa0dc897c944a9bfafaa3a44c311cc37a48be67ad16464e5f93ae7fcc843ae29170d598bdb460f5c70e370f54065a276ac0ecd79adabda0c583fde59d2ae751df8ee971bae9aa669f79dafb6699bd6554f0777af6ddbe7dc362edbb2a91dbcf75aaeeb2a0988962ff574d8d96277eebaaefb96dbdb41ff994ba5d23b596b9e5b6cb1457db6ea118e1d50e595fa44eefe449d73ceee9dbb2ecbb87b1f97855bd75dd3baae93599b975e76e7fc86533553d3bee1ab75aeb30b47d5bc76b57b0d6b977aa44eb6d52e829f11b76d9d5518c41224fd7a3a4ebfa773f2350f12c9e04d3bc69abf73260c9e9ba0e6bdf491e3bc73de5738ef5e178e9ee7ddf3bacc2b79e79ebd1f49d0001c9bf80fe9c3ebe11d0c47d3bdaf542a954a2ad555e1185adc999baf9a0a8f4eccfc3dc323232fe1ce5b07e2fef47490bc846926c132d3cc81e03fbc52fa47827580af1e0fca6303024c965966ae4ed95f295cf5e8fcbdf3a7694f5dbb76255a45d3813ae7f1e8ee5dca17f852d8f93b15c243666d760dd25455d992fbcc44134936b614ee4687c31be2cb3c64ced162fd9052e621b3015afca495f40b32b7b8f77d5d6c5969a514c404dfee02af7af4bf0b299d3b786e044bc9da9e9f413c236b1a87c12c65ea0a1b9d97dcddb31d4ac3677982f552a10435d2559974295b4ad0939ac2a4a3f0cc273c6119c4b34f0411a450824a702530c4dd376ab936914b1f1e53d9b31e900ffc56befb4ce6eaf9989f29dcd1ddbb465bb288aa5d4cc141611b1efbdb3b0b581152ab8ca47f26d23f8d72df90cea483600bc071d2196466ef4ecccc9d6b6ebbffbe538f47a973fdb0fdf4766c42a6647d1f523387471364efe321f3f7598f87cc9d4b786e91271e4d70022da4f092278f99579e0eefa4ea81cfba79aeca2ae907bedbf09c9f8783982083975848e9de39c9fa30016464f03264c03287e516b984573d88c8e089c8e0374c44969e8f67ed39c8cce03fe9994e3d1d2612febeef3369f7c2510504672d7c6d91ca6eef1f177a78d5c3fb770f3c57ba94acf1fbf61cf4eb01be3b58e26e3f0f7721d781541e9bc8376c2295e7edfcc85c0d49204e360094595cc193672665710550d6a8a578859e0ed1e2ec414399e7b78b0449bc2fb58b01e7cbc032e79c33cbb26cce9e3db367fe7410664f7738699a93e21604516b2239e826cd1eda2ad1cc97d6c31c9a91ebe7cf16845cafa53ea7c5a613789003633460387dc45c351f7903f0f4eeee8bea7bd4ec016f3fce9e53456121f3622173c64832b57e360067265d3ba9add4f02442c27366fb04b973df77b053a6cfcfae9f3fb367fa4c20f0f68dc15f3c7a20dfd9b7fb13f5890a41302377b83af54f7d14eadda8d9f7bea3e0e7ea86478007c37b0d65ea0decc6a009ec70c57454b80263884923bdb9f73c3753a9d44c354edd67a9b78bd4db86e1c87d08cda9b1762a1c39d73d418ea32f759b3ec3550fd2e74920f88ff48ff40ffcf7e1113c91fe7d07ef9df3740a51a8394d9fdfbbdfef0b47f0744a7de28b3aea17f5d4bd779ad3840a4d3d9af41b0ea9190cbf6b606e4f7ba7711b8914ce9949a406e07c085aa5de48b1b100e99a5945e27889894121a8268fb2888c8f520bb94a30e42acd90ab6443766d68238505c5e6db0198a36f44ff30116da4b4cabd7799516f1ddc5b85d2d70e3ce2895cc3ceeb5a278f5e87c2e04d26d379c86c32dd9a6e6f0a2d085610972ebd0ae22772c54d74b914b61513c53bf5bc7aab7556f64c1c234223725015805d77777777eace000d45b20f596a81869e6e7be98d47d0a5148eb344549a4f505a3bbb24da2428957afb4aa5ed9eb77dde39aed45e6fd9b55da5a5eeebfeba9277aebfee5a3b3db7855a38e6cc076798e1de7d4b90fb643822434f3e034c16b3d4c20c43f92707204b2dcc403376383e410213e47e76033e844527224cee211c55200fe108d60847cd24ac1268be6811a54540c732873d618f4f2eaa5a54a22a5481e06062c213f4131414f483b1cc346c309e9986cdcd143158ce10c2b006e3cec79db92c27f3c972329f122cb38c123cb38cea525f6a0a2a4d255263ea0afe3093c97032994c2693c9706260996708cd3c4368680c95e5a8a80c326404c5c09d4b8e8e8e8eb218159619064c459b00e4c3439f505242757e8c7e8c5e6099572ff0cc2b4c67e80d680ebda13534073060849db99be3939393e393c232bb383a2a22071a435f680b1d542aa33c6570aecc95c1c93493f88ce099497c7eb05034149405172ec29e3c3ba78e6eccd18d01b1cca753df344e1381a7775aa78d904ab5cd8fd1cfcf0f0a851ba65950d3332dd32e389d422959608e4f4e4e8ecfd0374464866e29628406100ca70c8e95b1323899beb453da895d11f4d31385ef0ba56475ee8e6cccd1d1918d99333453073a383693075d17fe18fdfcfc1865fa2245264b1da6cc84992e76d8b6b03357737c7272727c327d267fa6168c88843419dad25868c5992fa99219bbdea8370090e7690f8c4ba602c8b23045b266e74d6552a2b174378351d9f3058145bab44cffe180fd964c9b65b479de244f0a93699e1f33327c6600658b191932168d4563d15834962cc8e6d9d258fae4250920c502c893694f472fd32ae4694fcf7ddd94f633034ba6f695c492258d272c30e70cde506f3a78af439d8eb2269376d30908575b45fe9a6436c93b877bb4793aec498729941cc57789f9ea264adfebce76a089527aea6e4da7cf19e6a0a613edc2d2ed7c753f8df4e4514a3bd33cddc7295c950ecea79ac586a3e9e04ff6274bed3dcae0e6f138dd924ee0774d28cde361fa0a0dc7997940ba6cfa2c92ba26f0deac6696a6358563b52693e994b598e6efc15fa3f9321d1c6f91bc523d20f4a63b877bfaa8d9ee285f24e46b8989d23ffd8774917e0aa77d77c1104877fb1c6daa79626b5fbaa1e9d768a2d063f09b29bc454bccd7b4f9424f02f5b499af5964a2f46de68d690ed6644fbf0f4d3fd970750fbec87c3131368b3de5003c9df200bfe201e93278264eefd34749861f92753a85a07d09656fbea308b2e91cdd726b1c277bf28ae99fe933994cb7a44feae930d1a3ccd5ce648f84291ca516e01ce66b66fb1fd265ba0d8be43dca393afc2159935a6f0777c23c4ef7de5e8f9316dd4f28f0dd57a8af9c7e8f3a85abd4515fa5421f624685cfa0f44ea7f390f9149e66c067301cff4436e1efa5e768db84ecc95f78e730512829aca3d4225fbcb28d9a3098904aa552a348bf85d9c78bedeb4d659a5ad56bb762e67e434ecc35dbd1e1d89ff7db589fe156b5484f5662aee1102dd26da3dbc7546ba99c12b3c543b48aac4ce0a4c97871744ba5925990c95892e5451bad72a365043dc9bccb6ba46dbe4a56be64572b95d6fba8b99048a5d2bba3304347d15174141d85cc1da3e91c476503d2e4ec4d64ecce7db4473dba70ebb1bd147ecfd1737b6fb7dbed767b8ed47536731f9ea3858d16365a988589429ab7a333150deb22dab2b0266a95bed647204c157b4fc332120c4682c1babbbbbbbbbbbbdbc2b68f7dae47df0bda5101a5d4b4987d65c3ee94c62bdd4f0b6b95edd66ede4bf5e787fb76ae3b6fb87641ba8a8c35c81e8148f621cb2ca828ca5ca9f4e109529a164f7225bd496fd2b36f09e048676e0d9da269d399265958fd912c987471e1153b4276e8ebfb8f72dfb86fdc37eea5ef3be7bd61b9053a35ba7a4e520bb3f494fe7a4636ecf045ea42cdeb412a7dbe7ff280f43db5b0163391fb780d546d16366e9f61879d3455fa20a54c7f45228f51bd80b72567594b1b591eeb93b37befbdf7de7befbdf75edc895e8f936c5b5afcac00fb586b930e5bc9ea97f09d282df634a26394d26df3be93d7e3f3aefd3e5bbe8ff4ddc7e9d2838663093c670f627b0ed77f4b00470bbb42868059bbe91bee62dbe9473b859cf28070dfac0feedbc3516b91d21e60fa03c9ca70a4f08c25d0eb510a9d98193c77eec35f0ed87446babcb007d225696ae80e8d71d786aa24f529e146b513672261db26ce3671b689b37d2465a7dbe68d9b06a41476a113337be1b81df47a7cdf56ba15f043b60ba91568dbbed91630940265e3270507d703d7528639baf6d079f5a776a17aa102d5a07a5484a5c5cc08a39c55a29c9d23ddee48977519e5cc4e81276796c8168d6d8f7a74587de864abdc40838dd750c50047b2f4b2bc952d0bb3519099b8869741f505300ba3ad422691de955640b6a63c213d3b13d2f5fd2f5e984c92f49194919ca8f97b9052febe691e90ef5c88f2760c99f90bbbb1fe54cb9232d2555c8148baa006faa9427d92fda7fe8cf5475577be2480a46bb9ebcfa445be67a7471ebeb9ceb48a89aae4a8b6d8c87ec391f4edde39175dc5d6c816b548d462f689ed908d4956f60edb294856f612b65498283cb6a7c5cc0b8fda08dab23e7d929d4573016172a6ba327746c67206fba8a83fd295e58ce677cbc2ea94affaf30ec7264cf2ca899ac1072965f0a473da170410265d5ace6e776891900a0ca016b090b38f568b9c61419e641f2d16393bf591462a225068a44045397bc685238cd61f151886a3fdc9d9ca76cec4882660707e6691999d1e7ab9f121225d9d2b2c83188877d20b6fc776eedc8b8ecb1fd6414fc27667c3361664e68da74fb2e3c84229403e1ee9247647b2b2576c6146f83e3f5a58ceaeb5c863653b77d2fcf1ba7045ba975d8ad3b32d94025525ab1b158a740607ac67d5c1f07674b8f26df75ab870457a4767c42fa4332d66b4d3526089ea59c3c098aae73f6276eea4fbac876dee86ccece3d97ec32a9a9de73e2250ceac50ce54d912c156b22c746266cf48af99a485d9e5da070ab8a0ee39d42d5bc0d9225ff3041245ba261492555f6f38593e243021abd4666a3a2dc301274b76e9c972022bfb763aa93e824d6e8c01ac81166b4f16496dc8448b35d5e29368713e94d7a46a51b6a8013bb3365041c58d14a4701364052d6c4cc60a93b373dce5a74bce84947cf5ecf365669f315386e4d9e74cabb878f649937a867a767af6893373a64eab949e7dc2e6ce8c4d1efb4c7b0634b3eed927517698692493677296919c2339a7bd354d9b5568dde1ed8d63bcd67bef611217c4042c41e61654d3c076818165906015d7ea1a7a926dcf1a1634f68f96294cceb27f4700b9afb2772478e612eeab933c2024e7ae793e48ce919c2321e93a1998e2e4e8c4c0b5c5a54fb24f0e03f244ba34996532cb56241da9d3328591fd45765576124c61d947b2a7b2a3b29f30f5a13f1488067d980a613a4489b2dbac48656931fb0c5c5bfa247b87eb0be63133a5e117b44369e80cadb191b3cb1cbd691e127d6dbbf6ed52d336d24ba84d8bd94d8b59efe4cc8627d33eb616f9d703a2bd7b27e6436b2d53e52c0b572a8caa4b5a509daa8880eee9170450087dc9ed3ba6ed9b48aba86e496e5ddc7ee436758bba7de3e480b7a59d5689354ff7b44fffb44a76abddbe83ba35e3f63dd444dda214c6a848a6332dd99e6bee5e4a8a917598bb07a2f06904a7ee028f9c04bbb80a93bc9a8025df9760ea42358d5aab592ce330f0ea2f308cabf08bda42841857c18b98f1af0a70bebe744ba32796c6569f6cab16b2fd770490bec49e3423ab70100fe4927b1e10d5e93bcf87ead4f3a122912e03539b1b9c189816a92c2ed27585cc5ca2e2e86c4a3ffa12acdd15a6362ddac3c0f486e2b468afc234a7457b124c755ab47781298ceeb4689fc2344679684f531ffad3a27d0953202a44873025a245d4881eb5683f03d3227d624fc2b525a4346700e9a4111a02ca23cdf9fe640a265aec3ee95b59e427d9fe72240f094a83698d18c0b1bab8641a185ba3c8f6f5c5deb05d5a45c284f53a31f30da78bb5b6ed7db72672178b253e00b34b8f87d6b8d622187da2829b5d254b7e8229a509ca4f1faa6529fbab9225311e4d4c5a949740b57eab1e33ec49b3c049137b32bd7aae92b62a5f6558c35abf53fc9d931c7d0db909d279aab54ebf97524ad3a5042f65c9fb09a7348771ad250f8f3348df3e4c0a552dde5f233e2c80638a04adf2a3c5fb4b5f57b42b6995fb31c638d2dfeb3dd94a829edc570f47a6a12a06e0f7278e79d4d31a9a8b4ee99bbe913426cbf614d62aa95b2260aa248f14c644674407bd6ae45c259139e8bbaee35e741d9e2338d38064cd98cc5152ed6f3441a6616d963e816cb9b8a5b7972723b255b8ec2f5e8c7c348d34cbc8c8c88394f2c8c86538635a2cd983265b947dc4ebd12ab57126d82d6dc38d74282223db38410dd43f9dd3a2d56162be9a0a8962ed613c554832642d8f847d930528a5eb4a97cc34a75bcd424fec35181853f5fc275b91521817364d632b8da1304500e78c8de053a7d0be59baa55d6eced12faa929b8cdc74e9ed381d0c290c95e9f03c51985639d9647b2135774b8b76c4d42c2f311a0b0b6a82ed62eb473e360b3290d42b4bab8cdcba4897e723f55abb8a1315f2059aa4abd403aab49aea46b0cd3940ab02414d03c1f123c714a6c57b6f0ad07e9c31d2575227fad3795a250b57d9bb4be1e2b68b69b1a75552a11424b747610d48963dc56b4843b637d900459270c6b808896834a08d0ae73adc08ed2947ecf785df6bfebc100392653f77a46b0b7790c221d33ebb212d22420732958274e667faae9eeda66d4a8f0423d46490a35d27595000658b3485aa54a586d52a23d79289523b6b525fff62225f58a2a480c60af20ccf3239da49396d53295e5932eb2de57b4bf2add63e9b543b046b4b99b6674309565b3bc70d79acd20a50b4216700fc72965680420d5008b5a10d56687141f6a44b5aa1058a2cad00451cb207f6096c15a94a764ae72947b5d5eb65361b679fde0164b60790b977f4b35bbcb29ff662ae371469af6148a6b1b0b00cc93e277c4de066cb29024e9a8c932557b0e7ac6234a1dc570558ff2a612a1c1f13c07a3b25ab279d03273357d2214d7804995be42959932be928e938cd80fd1643ea7175ced9f320f5fdb13ad13dec33204ebe6c0b78b2f66bdf2929292929292b1f62b691b53ca69ca20083cc1b4166cd36f298721f150fa5b5e6fa5bc3956b3f367a4c622594a6744acd4ab44a9f7200b69861d807a9ed75b8727f5f6d8f203367d9fcca9c3ea5d9b4da9b69a48debbcaf049a4ea8d4880b12d50b18ab4e8e00943026e0e4ec5c8cae5bf4e63919dded441b2930a0fba8248f8c8c8ca9c6ec068dd1133a748ec6684bd3868486ec877094a852a0647da4d4335f2689629f024a967d36940d6544dd42c1f5e3e1ebe113bf937f5f8dcfe41f37e43254613efcaf73f968fce362b158ec0bff714242dfc7d5d4d4d47c31fe713b3bdf8c7f9ccbf77d9f8c7f1c0dcdf76d43434343df8b7f5ccbf7adfe6db1984f0ce87bc73621a1efdb6a6abeef1bf9b7edec7c24ff36979798effd6d3434df471aa22776a8e8fbb696ef43fd23c562b18f14fb4eff484213c50a7d1fa9a6e623d57ca49a8ff49d8fb4f3915cbeeffb3e12cd97fdbb079a90ae522c16fb9e8415fade43be34a19a9a9a4fabf9ba7ff4dfcef71af2a5edb8c876f93497ef9bf2a5d17cf5dff79d88e1a8ea81871a261f16600973439dcbd0d050e792ed65d0f8c298500cc76242d93ec6bd185ccd4e0d57c3d5ec64fb92199d0cce85a3e15c62702e9c0b4793ed5725dc8b21ae656868886bc9f630561b8c9850ec452c2694ed5fa848235bcd4ecd56b3d5ec647b1589e66273d968369791cd6573d968b23d492a330d6d2d43270d6d2dd9de05ea9e62b4d5c9908454a690148b0965fb11d0926a483b5f3876372a1548aa21ed64fb548605c98544437221b9905c4834d9cef97de1f8c5d0182d26148bc584b27d8962fa6e86353b3535353bd93e45b34c63b405d20c0429a8711fee723a1c0c66433634991ab2fdb7038edad09046d42d20fe4ad3ad6cc8871f6a7836ee692d279e78ef95a55b190d131ebc1eee653fa107d4ad4c4646c8b39e97e178bf779ad3ad7b7444614734e679598ce79dc674ebfefc5022d6b39e778dbc92a26edd1ceb59cfbb3e9ef7e6e9d695f164803cefe278ef1de952ddb347473747399e77633cefddd22dfbf3d32f3f9e678dbc5450b76c4ece504e91e7591f9f2ffc489749a75b5646664786c74382b41e78ef53a65bf5e868ce1cd5789f9e8d19d2f65a11ef1c90af6ad4ddf3de8474cd2130c87b12ddaa39f4c47aef215fd5674766881bd9bb8d6e55991fad42efdd08e9aaf72eb60a37f690bdd790af8ae3353d6ad1237a629f3d13e9faee795e586f00d65c61d94636a4b5d418fa0f6136e4c3d049a8b5647b29e62f0a60a9872cfbe121ac6112663934c230b447e14f46966532b22c3bdd9b71b32be3decc14a38371ef8571ef054bb8d5bd17c6bdb7f4627371affda722911cdd98231747f6de8876fa31fa39fdfcd877a90c65737c4e39f69ce96a56c6e2d86fa0cd8e6c8c2a1c55a0171e75b5547faad10d7fecb52880348f1950cdf1c9c9c9f139d526fd5caa4cc5a9381faee78ab27aaf088d6e8234bc1e27f923d2c5b4b8e19b3dec1d79469d4c1753a44f2c91f68aa8cc1723f311c9b9399a1251225a448d7874f68ab868349a8be6a2b96834d9beaa6a89a654d32d20bc22d53b6a956ca2e029d4279647d3963644bb97a9521dd121dbbd64fbce157b45ba9821daea64fa65beba28248abded6e542ab087ba194896fdd8c120db6f1d0c14c0aed4034a5082d22bea137b0bd42aa3579409b58acd825a057b459e51b758b7f78a7c2c5f4bab64dd866da632b4253b187a22345fe044b1a71d4c8c763031214d034195ea5226db7bac7397ca4c8a9c3ce94e071995fb632793ede6f178ceb8ef0a30fb8e004ac1baf6198e9e51b6e7b49e546af6a3af9984271078fef489b5d75858d527f615dfdaf9b1d022da4a89b3c3514543f0678ce91695a11d4cabd40e46aa83c9f65486d29667d427f616cc36d7d02b6ad1bee3825794edbb9782566438c99568772a93542b0ba22738a03599663213853e0ba22d29335f594e8ecce470498a336765ab94d20a9b93335f59d044b1b82451529c24d5e40599d679ef0d4b1e359756c9c208adc242afb550ed25639aab57ff99011c2b11062e6001930ad0608202130825b0440420f007cc50c2010d90c180052820012508582501e4003090f8e1e308550f122378ec70a1c3000528229551390840846900a7215e2e5088128e968a174400047003005fc7a5a000c1f2e1071ba44d3b117be0a1c6cd3070010b5480090a4c40024b4400020f50c2010d60c002149000042401e40048fcf071440f2378ecd0618002149173108088010cf1720981a3a512c40d01040000292840b06cfce0c389d8030f356860994d784c787aa63014f453851a3562614d586303841d1d1c294c4c6868ccc032bf65e6b7b89c604606060a1a34586404c9081202032d624424861f68c60acb5ca2b3c23397e8c096f0d31363c28c1939306460c810a1018e0d8d0d4a4a62562aa3995546476f80716189c36a55e4a2c7458f8f164442405750a978485058e694cdcc299b9b2962b09c219090d464938bc9e5250534446256904ab59c706794cca0102834340696a3a232a05041383232323830d84e1326900fcf133a9764ee887444666e90735393835249e68874248bc821e6a5850e5d67b4e1ce9ce6a3f9fc60a16828280b1cd793725350341b198d6ca55ce063b5b1c0c78a5381d7191dc8d70f263e561ee4be6c2541818fd565021f2b8c04fab448abd0789fd641be9a58a2f1fb1448b63c10818f5408021f29d1033e52a32c430bf2355f94f848b9e0235d2539b235611cf091c21af091c618f091f6e419730131dea731b2356f14f0911249c0474a83803e85a12f90afc993c4471a83dca72fd2a52a92add903e4631f1de0236541a257af49f4e363af6148ba5ef0c8d62cf2f1b17d8ef8d8403d3eb650ac555c60215ffd62c4c7ce6247ba5235b2d5303c3ef6cd8e8f9da3e334dd03f96a1b037cec1fe47ecf48d7886cf54d013ef64b111f3b26f7e90ef2d53c393ece2d8a481718245bdd43808f7388888fb36800477541be9a68888ff30b3ab2d5afc923c4c7e98304f9a22f1385e2f83895205dddfb5346b6284cab674d10bff171ce20f76714f2456d86c816bd11400a07e48bf2c04897f7be079a902e0da56510eb49c816eda127d4460ff9a2441385fea487c87d23f76dfc3042ba48cf2e7eec21f7f0f1b9c16cf291d25c43be2a8c8974d91a3351fad905426a8170047305c251957fcc5706c44412b4950551a067023d126862beb29f25887296434fe823008107842ff395f928f102435b998c03c2516b000c03c25195339c05d8dcd0d63d52c04d026e1070c3335f594c123c3db4757f80f41ca00789907e12cdd735fa118e9d6f8e8f5974c42cea41af8f112f30b4756578c0ec80d10163335f17c7003699daa302dc1471936f78e6ebc6e4e0c9f4dd435bf6879e10a087889e0184a32a37d17cd9219a2853fa325f96c2d096a536f3655fae2e12a28b7c323d8e97168c4a184478c326d37a444f78e6cbc64c941edaaa3ff48468beaa006e027003809b141e94705481408423c8eab11112659a03335fd5a7ca549c8942ff4351168f7366cd96688ca7c51e18b8faf4494fed19e23a484a01e3399ab650171861500775d04a7f88a53fadb222330d1a43a524da514abb4f63ad72c3d5fd17ce70756f0f25427520ed675cf52214323325f2fad32a23f5c9f50303582fb3070470a4451f1048d40dbdd01650035bc8eb719285d469526b8f64d515fa2133cf4a89b4cab8723f69eae914d2d5afd70332e77c3fd322daf4e80be0486372ada74563cd63078955a41d74d42a6dd42a479d037952ff036d0860152a26e416ea20fa12546725ca15365fe7bcaff9d218993a611d9e3a33270a79523fe3856ac25097ada8beb61cd197167bf2487f7ba40b0b2bf4733edf39e73ca5a1a41f7b14733d7d69155268634543f12dd67a0dd4b166b0e73dfda5f4da6b298b8bf661059cfc7a542d66374cd19405b40a49fb28bd2a408dc77c225feef2b8b7b7ce7aef01203579495e00c7929cfd25ad22a777c41359c31ca9d693acbda18314dea03d33998d26c8a430a302288fe298b291425b9aa64aa9609048dadb238512d448da65d009744af35366dd59d657cb56ec87f800bc95aefb9559db039265f7da2ba50267adf691de37bdabee8b997419ae5a1bfbf5e2515b699e2c5d74b2cc32732d5d428294b294acdae2b45fd55bbcaa148ff2096d761860e69ce138249332d370a457753c268d07805e3c5d9a61ed396f386932665f0df84466912c7b6e669983008e76a645bb2f31d9fe9e40be2c1122178a6c7f59ec1da4dd22dbdb22b60ed2da21dbdb2339484b876c6f8dec1ba48d43b6b745960dd2ba21db5b229b0669d790eded903583b468c8f656c88e41dadb200b0669c590ed2d90ed82b4b73f560bd27221db5b1f2c487bdb63b590afeb2351acbd42b6b73c760af2757f248abdad82c542be2e9044b1b759647bbb63af90af1b2451ec6d14b2eda109f27585849e90edad8e74f1707bbb04f9ba4312c5de3221db1ab7b74890af4b2451ecad12b2bdc5912e93db5b2ae4eb1649147b5b45b6b737d245e3f69608f2758da435427edd238962235de1ad1d42b6b74090af5b44a258ef568a6c6f7f302451aea504c15c5e642fe84bb4840f6270c64d334c321e43468cd55dab8f9d5d97b2e4af928f9d5f977288212ee5000670298920e2521280009732478e4b99f3a52ca2884b59800218e0521a40c7a5d4b1e352eeb8943c7818d1e3081f3f2ea51197b2c7a53ce252fab8943fce09f10fdf9ff0f7117c7a2a751526790f3dbc06e6e126b8c66960938798c63d1cbeb1f7e3fe0f3cd2a12247464544434241403f3e3d3cb11d984e0ece8d4dcda521325520a811c916a4449d053833fd68676e85d91d193b94ed57051046875a5459dd0fdd1aa385b00aabb00a93919191911912454ab51a036ae91a64abd619b84055a100e36067706cddcc8aa4c1c2510bbb90cea02cb4332ed05a36fce00cb90716c6d0837aa84707c4d1ac4de9a6d7a2ac2853a940302bd2b470a4373fb00f7c04ee818dc03cf00eac031b008f1728db1700178133ce81098089c003c043e01776e1f1e28cf7e6dadc9af1d28c9688965fdcc3b4055317fa2259f62698c2601a2359f63cd8f7802911c9b217b1907982479a826cef83fd0f78a42fc8f636f048a318290db23d1018058f540723ed41b607001e2910b27d00f048a7c8f602c02325c248a9c8f641e0912221dbabe0912e21dbb7f0489b90ed71e0915e31522c463a85916a91ed67e0916261a45aa05da060c816bf66dc7566463573ac652a345f153651ec2918e4ebd2d0880148ba505d90af5b53f3856c4f7fa4cbc5edb5b1b11c16e4ebdedc64a147ba485ac8d7c5c1b9028f746d5390af9b9353859874552ce4ebeae864b1235d425c215f17068b024cbaba26c8d7ddd979828e74694b90af1b8b3121dbd31ce942827c5d9e8962cfa3846c4f716ecf44b13df64404f9ba3e53c8d7fd01827c5da01ec8d70d9a2856ba466aa42b4533235daafb1801480a7baa03f9ba423790af3b34512c0de4eb1245215fb768a25822d2b52ab98ccfb810e501910d8a66205d50d8bfeed144b1d9ed690ae4eb16992856baf0ede909e48b0ed923ea02ba826ccfc9c0313e03cb380ac3b80b8c3a875dfc78c64998fb8649af78bb100f431a344c4c6ad4e081871e7a10c593131f7cf8e1071b36582c2080404149490140000470238820627c854baec2ab9390347ef1131ef9874fbff83bbeefb07621f0ed4c769bfd26db9c30ac301a1a34686a4c4c6a6c6ad4b0b9e181871b9c1e7ac0c911c51c9d93131d980f3ec0767ef8612766c3468c87c5e2e90102881e1f1494df9f94a77cec0b0480a000dcfe0a0960e80651100700500082b200846e0c054194ed6f918a51eb0887102a452d231c1f3b0bf11742e0d1e6ec38700b8f5eceae8283c0e348ce7e030b008f3172f600e011e7ec00c0638d9c3d05a3e09195b303814700e4ec2c3c0691b3dbc0a31039fb0f781c40ceee031ee51539fb091e251639bb884739859cbd87ec3ce05162416a216737c1a3ec42ce4e038f120c397b884739869c5d4a966465c75893acecc79d64659f8141c9ca2e03a7242b7b0cac92acec25b844b2b2aff0252bbb0a9b485676122c4a56f614b62159d947708a64653fe11b9295fdc338242bfbc5434856760de730801192957dc33f242b3b09272159d939bc00c9caee022b2159d9517809c9ca0e03332159b26bd7afe6dcf6d29b88b354bdd0b49dd99351b2cce2084099ab36abd99c950be2b1ea0568ca6e767a9cf40ac463d50b49ca3348da986590ad59853cb1a74163b542a1f238b93ccea01665e9137bc942592a8c569848540570bc47f948babedbcfa090bed8539b56397dc4d298cc425bb486a306822a55165514c99672d66f7c2267a72c1546612c20bd51e1a8301612ab050976595c582c4f8bb6a74f6c0fe489fd9158f49999d1ce4ca151012e417545b637349265dfe1a11b20647b5bc4e844aa21cbc3052cde041512404b049b857646b22c15c0ec23c8c917505015b02a88e4ee06e810f51178b254a94e9fe0967d9e8e0aab3badd2425da48b05d265833903a9d2cdd72d328d0033a5983cc8b688cc59d61d09ea82ba70b13a09afea4956f7a4d5950209245a3a373b39164672d23912c98a44fa7d255dcc2f4e427a21e423bd5e4aba5f7df6ec25cf47adf519cdc695910f39fd74d41ba6480603936545eae5c9d48da450972a1f4e7272883e8d7cb894e787bf0f7b1fee3ecc7d78fb30e9c3da87b30fdf1ffbe13a61686ee2c3fde1995d84365aec146e20928b6e829bb44f91ae2b4e961fa98a0660c2428b2c650691edb99abd66dcb7118f074937c1ed53824f105c68bc1859d6c89264e547549dec9ee1baa39a70190633874b791291aceddfd19739ecf97899c3dd4d9739ccd1172e73781bda3287493ba4cc61ad67b4cce1acc8fde1b0c5c175c248d686696ec208c9da9e753691ac2d4637c12914e3a5c5c6e9569e0e4a5beccc69c0dbdb29a40b0db60c52a59bafb6d922db9ea1831b6c0ccf47f7accbb2ac6bd7cc54c28da30165fb9c6ccf5d3c360e65a127b60668c667a6c5588b4c18294bdfe421d1bfa0d7a37f6b0d7760f50ae9eadb580e52d266febafb3d835a6ccbc323c489ca7a228fabd6421ba3692160e6243eb60f908fcd7300242c02423b134a31891f884a758050f6090b12a1ec13966cefed4c8b344e00fbab9f90fa201ec8f76302987dfb68676adf503bb3d23e8a3b569a66632d5a3b53334f905994b55f4f4785656b5f6175a755b6ecdd924504f1c0769407e434fb998f7ed6cfb295903a855ab4e3079eb01fe2e9c87ec39598692d616c5a658b90add827dd41305550b6dc8eede22a5936f7b9ecca99bde6ac9fd9278c6812488193269cc5ad01976c4fe574a9dd35e4bacafebc1d34cbb07ea727f61a2c064a117c8f5c4e99c01cf4c4a22e9918395d9ee3f0ccdcccd67e5300e9b96b613872ac4da552a89f503fa17e4abda65e53afe74cdd0453ffac006f3d75586aa8d3ce497dec25e4532a95ea9b542a15a29ac69af634fd691ad474c8d3d19d4e2a16108b1aae92452b461d75eeeb3c8f476cc64eb0eeee2f0616a5b891ae48a7554c1446c59f5a0d468b813daa9f078943a873249d9594d2143d13f335250a2503089eb48c76335634a750fa531f418d14a1660c3563a88f2654ac847a095542a15097a814eaa9af5c7a3c50e14a09f5540915ae504fa14ea1094f9816659f9c4ecd723a9d4e1f456f1b674c87258763364bb31c86ca9c8efa486f90ed5140503fc1c45019e992a81075c24ecc8c0a03aa0ea8f4cb36b6491032440300000000000315000030100c068462d1602c909551660714800e8ea0505e529d48b4204691103286208300000c0000000000800100bed418b07f358df66c33a4ad9c81b2c03720895d4dbcb5fe4e9164a4ab296484c07957c2d8320b44e39fdc522a1b4a3177e5234aa3434fcec69c8d767a7cd61362d530b2d83aedeaa67a5354f412a27871c315b4dad6fc92cfc5f716b30e80188c1f8a6749a98ba5a50a96b5c7e7ef97812c19ce5ede2714b01976197396af328f05438d210bddd940649f9cc4772c5da6ecf39208d2ec155ecdf263506584b6dc4925897c47cbb2491a209a5fffb2ecdb1ccff6d09c6564e574368bf1cbb2f2ea080bfe2a7933f884d925e7dff794c7b71180f2b04e38fd9ed30050c8bdc583ad411aad07685a1888622461702e68fec751cf8bf82476aaee26dbd298d5b4061ac7b2dbd729352f920c89f3b6ebb281a826b080be092e9589ec625f371abd75bbb6240802d2962ecc978b589cd4dfd68ee28357ba400bcfd6c3af8c763ecf62a330d2dca19e096aa547d961a46da7d337d0d54eef909e5c6acdce0e8a5a20910cd8fa7d305d762927b7b3ad6c57c659ad6898ce4a1869816158661cb865b55d601df1b25c9f3640c257a3beb9d0b87cf77c64d10ad4326e862cf637d5315533fd79629dd856f1bc7692676b6e8a863a49df07cd24d7aaa8cb6bc749f1f59f822866da4ff0b6f5b2e61f70e9c127bb14e52278af1d1286fb8292667c5fdd36a82dcabd98b9abf6ba323b7171c10f1022b5298d6c8472363792b0a8c7985aca3eae3d511682cca96f16750320e2001de3e944e00f14c6414fb0f597b3d50739ecb735a99fed8a1f07193ba4b4818b5e30c161df95ac082c3dab7ecb81bdd5692287a9ae73ecbf8713b9bb3b2b2d5f79d18c0600cd05c9b80c00e069aa18355769841daab2d9d4ad43ed6adf5ab2d6164ac7bd74bf15e920e162ecbead60a7209bc3c8a9b06533fdc97f049e8947ad3dee894d28e2f21810eeced30f7ab669e63b6a7b5d72f59b3d0ea6b3cc4f9b2e1516854b981f7327c43a385e79bbf642e9674ea7257706640e92633c4fcda59f9e440b5fe42b7a44a0a46a6e4faf6d06d77cab6abac055aa514a07fa5941fa522498ca5f217aa5c623db0dbcb0b253a350668f354f37e798380f19888e7b15d4d6f752a8da2ebfae85a7b403bd9231bb44b0685d1746cd3feed192b1601c42f069f96589a04c8b729d357744b29d25cdc954ec77495e49f53ab89db9d14f5ce33460ead4123d5a96426bb8b780ed581f9f9e69d85002b0cb9cd9bfafcd9fb26699f2d20fd264e45469d43169eb983ff140414499c388e0492ccc228f4c7b86013b459377e00b0438e1c19229024218cb8d1619d9aa251098119469c8be08d518b9254ba393e3aaf7050f83cce83899bf383159a32144a1ec7c4b782da672dd6ec068993bff97409f2e074cc368ed4e1c9368570ae48b768549a261d3983eeba0ad879c4d4ab1b21c1f35778a763943370a148bcaaf38262b7643371af598108e2f16e9289146d2456852c42bd2f47b941f173b450bb5f2bc9f235efccb98b60375a7e8c15a7239ed6aa8c93460b47fd02e7bebf2f0773cb4f23acf81a816b2680dc4a8977c56f1349a9edf571b565c2debe9db2d8a98ef886f3c81e1834bcfe56105d7700586b0ad692b5e57a68263787a1794597693c93144c4378ab87deebef90ade9029b517e8e49960deb84db46a663a72d6189fe18ecff64913cff26fde4616af0e5f8eb55039908c8b5598b1d9cbbfbe69478ad5227bc3e576f2b3e0c4ebee94593793c254d2db2162e106a987ea80daa7ec42ff8a97457bac2e317f026e6a4c59b0cdcd51e7163e619bd099e5735068a95af53daddb57c47142d75d302403520734c8f5660097405759290afeacea28043d9006d8aaa5f92cb0bb7959d5655600c717a794a70733a42d1e4a488d61f88ad1319eefb1999b8d9c6d984be840625784a4602689d8e06dc5b1ca08340729d267c59bca32427126bd237154d9cbbbb9cc696362b0dae4c9682de35ea7fd1309390df205bca2ff78f20c283d098a4109d8fc43ff1cd2a3731f5b84eb0561e132253720401af158544166b978733c7d9a948b600b52bc822768bb49aa8cfcd77201b448845e2d97eefc44486ab9ecce2f42af964b777e2224b55c76074f5e69b190f128e5b230388513964b776ce5950b943180592ed63cc4e79566c6fa7b2456f30ada123106147ac1e218c010b9a70502cb2e7b97d84e4d56d4aa872dbd8f4809e94e2cdcecc2bb15acfd84fdf6b20b0eb14c340dc23fb640df7dc4b2fb58628ecb2e0a2c21b994b5546b28dc39271612465dc0978fc192b422afcab8223355595dcee2cd9d74dab794cbdb70db75c9e443e2212b4f1090e539483a4be3dff506db38894027b550277741477a414f5613285d1f251db885ab3d22e7f98381bcddf0e23b73ed6600975741dcd435c85cdb6742f1380e05a6c10d039bdd393b0343b5814e56af094639e1c33a0b2cb88e799184092c3221d90a8abca3dc7fb4133a42f4d0a0825c404443b14ba588e3b78b696c8a0a41128ab50f6d9286f0413fa7d82fe50073f1461072f55580166eeb0ad111b7cfed79bc997d5af65f32ff149e9d426a4eec4cded14aaca696c25b5977ccce3f0fbfa67a36b55d3bf171dda4e74e174807f27052c9350b4ec7c75c21a422e611e7aa53f225c5a745d2224ab68103783b422ca7737aa24ab3cc6e96a67b44b6486edfa0098fbde65b7d863e4118640ed1365a41fa5689bbc49c1ae13796723a21d56c32317e84a09e604306c7d87c1d25daef4bc1fae54c41529454c27ab409b0889c80d7d904e8fcd0f84d6c93970f9e47901657adfe6f73171e3cf7142cb4c7cf2018f707942c7532201f8a2895f6901ce65d22b6437afd33a31958f4b02e85616996b1cb8509b9248d9c2cdca9bd3702d6cea04ae8873e97c3645fb5befc35876441edbd19a8906aff60a29040174cd038fe035c837d13c7fcd4b29b398816db16af51aea3e799dee9894241c762a7fb04e968239024f8a7dbe7cd68607ff4e52d333633aa68153140f1282f4a659809206a847b5994212ce561243adabea58738004fb23c24dd86ac1858bafb611150019ebb2db0648eb9924af1b7d82ca58bac780d2d1c1097cae2a261019fd5da3d16b5e70df8603b19c6bfd36892b5127f70ac80bb73f6808dd5a39f7f811f6020790b2e1a092045cbd4c08ac54ab565397996eef39b558553e52514946ae6b87ab548ee46b59d0428b48d88e1823a557e3067ed6f92c5a01a27ce0c94c2d015a80813ee91b7952e31965f597cb9e8241a8ea7c7fc81385376ff06610e7dc2114a71794b1f2ac0c83584b77ba68dc56e3f1c4a92c3091598f4c4d394849d4556d0810fae8b6b5f2da7b5b39b1d9c78ca420a5651e100c29aa497b6bd4997891e5c353b7fc12037b8066ded73b9c9ef38fb07ab4ddcb4b43ff93651caecb3af24a18c17fcaeffc09506b542967d17838b4477e9a2e82036df2be6f616522d01c4d34464b0186dc3e4f5cce45abf2013aeef7cd89dcd6b37d8c463ceace01679f22fe8d31866fb15ff7679e7e8724686dea360f34942f8c1a6eb471ddaa3766e685cda864222a045102b4e2a869eb2ec8c7705530ecc14ccd57512fa694e1a3585b386246f0800c97fef8be9d1d92e389e679df9965cf7aac651b8aabf1e25de0b7d94165bc3743d5bd197752dac60f0a3a4989d97c4fb4b2f871fd1591476bf3f47ec07a19ed1d564b587d61231419a806c1e9fd0d057e0ecbea80a7edf204951233e6afb1f5cb13cb26f535e253e3dd2769654cc0b8a55f435fd7bbaefd49f12bfa7fa4eff29f973a2cfd4dfd2bf27fb4cff2df57337bfe573b4825d7530d14a75ec27cf37fdf1051f218be10b568f85a7e53da7315a6b7728f6da9236b3f03552afd002e7a9735a2a7c8185ac3127644424d7ca50e7cbfb21fd3cdb2d2c4f949535fc66c5e32dfa37c2d85afe07c3f2d76aff7dea4cac23ad6cdab6df3e7126d5d1561e6dcdbf1fd205876fcb9ad3be371ee2da63cb848d22546f09b4465893af69f21ff2a6a59fd9ce5c186ef07618dffe0ca109564ce1b2bd01e18def2741d63719003c482a4c0b0c28d5810a1fe69340105d101a639f68dea2a8462f15a9fb8cdb52cb99c0046ef533505d500d7d694080a6a67a34b9ff5a58b307407b9347f93790e6fe23d6d60c90922cfabc7d72241fee1350c457ebef21fb822ea2caa326bef6da6f5d433bd7e34d7b66b2f8c14f7b2ea2604fc24392f0b5c48ab69e8c67b7158b6f820d5923c3c5d94cdf62cf9feea733803db69df59673a0bf57b60d0fdc7a858f355a02115a212e4f343d9fc21863f06ffbee102d96b871c7848fa1cef057005232ee5409145c96196fa846138b120564ed4f8cbdb22bc3c329d9fde6d1236976672f938defd58ab81581a4b4669625e76448dc6f6514b66dddf555f43409820c474f97072a3c41e348ec2d1b42c7c391a1c08a5d01114395aaa723f6940b0dd4554ec1729d3b0be4be1e49e64f41996e3d1ba4e01b49329c4a027a130288ac4297a31aac7f28f1f0e024872cc93756dba29d544e9ccf9534750dcd9ca2c28f602e9fa32482d1309c7cf8881325551905bda3f3530e7b204b4c9a5b5897260c52ac705b3c33844412ef566c6e0c0cb4ac665b1fa10085637f8a30a5fc0d1980ee52ece005fb6280764bee74574299f983647b7bc14807227f1bc7d4df3c31fbbda8f5933d73c4ed8819c741658487ae453d0edddd9d249d5dee1dd7102ab5ad8275f7e5a0b5270e4315110963322e05dd7f8251d83fcd373c34c43af0ed2a61401b4b930dd2e9857b47721906c090ba3ab22abb532147be7a0cd711a7bdc56c52085979a1155f2112bb93af35fc4c0d9aa36a0c9b71a575a7557066ca362f1244806ede18acf74e5d25175134643432a3b5d77769b6d5a70f871466fc6ed5df4d57deeb92c56e77f33caa3d4d422cb9e8d6f6efacbb7113f78d13dd49c16288e33b4d5c8e2d20f194172b2d0da47fb37592fe368e682c4080fbf0a01b23107744b9d3abafc9d3bae40b8d42bc01442ed2ffe21b91f5641b221c1c11af5dbfb186f4edff015122273d32574c521e156e809423ac001afda372998fff8f02f99a4698ce0083a593161bf818a3af5601e03ff6b6f0d17f9669b21581ef8775a648e09885dbe3b3dd2d8dec27495d05ba5e32d965a98a478aa56c1074c944c093c75845eecce61609274ec7d78d0c811842523ff85567fa46963816e3bc4d985da9198a95c1f63bc62779c2b43c9d7aab9e74a36b310f2b304dd0b12710f4febca7a652330364e77dff2855a08c785003cf23545ac8ad0036b2c64befd28c4aa9d8b0bc8cfa72fc4a780805e28b15079516c2f1722ac6728dc0db3f7200b34e8bf307d7e3241ab4d690bd2bdf136de75276162fe5c2178ad3ec4c3296cd7ce0a5d47bd3f780fb49804d8ab37d596b7e6cfb40fef5a351dffac1d15f6dbae8a56eb1a89ebe324a4bbb307aa3ed138dd02fc8b72e7e31ca75269a3dd72a481931dcc33623970a5fa89789bb29bf3234e3c6a383101fcf8e70c26a0cb4d4f0ba00a1f87908122cc591e448f7b9a08e83e6127997350803d11354ee01aff09276eb49af724de6252d638c9ac9f9be10f624bdafcd90797eb2ccc79e490fd48c8cfa2a3c1dd3a09de2c84d5e0ab5c4ad4db095b49c90e6b6dfe77a54e4d5b43f868729f508e5daf71cae7ac11a2afc35d237be733200575dfe0309f3474bb35944ddd579e2f91ed58d62fb99d159950124bcb12ed6878a6ed66d432a7a63b33e68888b2188132165864937f55f388cde0f7ad376eac701c42608a293613b76e1cb886cc30eac0212124b9bcd722503c40dd386c42a0ddfa565a6ac6d281c0c9a9d41da26efe220d3bb86b94e9c577b219b2f82b1ed2870fba4fb88fa8b63613225f5debea36467011e48997209622d7a2708d0a10eeb620bdad3acd80524f93cbc8e8c5186308fe62bb4686590fa043f13b14e595d2b8df46d0d0df8e82e66556e43cb2394ab24253ba5ed86888d78670024bcbfc280709165d8e8165ebbdac68bfbfa2b1474ac8b7b33282e0882982951ff70d12d2d2abe2be2d4d4a3de1344640fd580a0c127aa26475cad6fcf530dda734632fd8b773048d6fd2a3103244b2ebc2726dd5ccea21e5d2d185cc322930bb2c294c366c95f4b9e2e2a06611f5185cdac8c29e07e0d0f53340043d1f65edcaa890ebfbf8912163d0d5c0e1c8ec3f0ba8674b1bde970c84bd5c9670a68b976f9e8f5929594afeeff07cc212945048eb1ab969b2174a50b8eac2e461203d64d9336f846061d339e2d105f82934922b144a91db115f627845d253e9b6de9d130cb65b5f07ece911c809ef70334fb695bbcc24416ffaf310dd0435046252e070a8e615accacb39d2121109432295ab608aa8df1b31020a015c9de2e8386353375d8005b6c88bd4aa66eb5c2e9ebb26ad1e50d68587014386d4a0f21febce4e8cd30222e9845ddd369432d8b6d966783a4beabd32593e55a898b3496633f7ae470fa2365db19251f790458b839164afdb2fc7ebee1f35965097fc645f9fd453d11363d7140de974a281e5516ecabc2875ec6fcd3a9bb46c7fa467a6fa012841d515a242508e37494103d5020f361b88366aefcb88149c464fc88679db08cce16c1127028118f5953089ab451be3016d8cf60c87786f8d7081ef61fd47161543bafe7e2b24f8c5bbfb645bd48baa56480b6deacf9e4b9f0c432ce938cadaba32cf7799b555093bf65788c2bbb774b04f8e7c67a26fa3fa77f0cd5bcb8b4dedae244ac99003fe36ac3310ceed8e756334144e6445222f52cc596761346c728454bf14c0848bcd5609fff82647830c6904c2483a920fe4e0e92fb56af181417eeeb3b8b817c4edfccbd4fedebac185843068477c8a099c84a2499644a5cded1f7b58c8ebd811a46bf53d6e7cd3af84c057b15b72c07e2d9bfdda2c64611644cda9ad9534309ede8146e56fdfce1993731440fa23bc382b9ac39cbf565eebcda93e272b39892829b9156a596caa45e5bc1e917950abc16a32b060627cdbbb6301bfc484f981ab0d119c78b03a56b1688f0a18bd6143cc2929705f6a284ab7f56c88b7cf06abcd1b013ea0fbfae5f101f3f3870eb86f733df0846d206fea24c9f028f9be1bdfc46c3bd6675e8d1b17fb0f620fe07144439fb906f86b8d753d8b429e777100500540011c0ccd26d0071e9e01d99254cac2266c02c067494e296a312ef584464793de54c6fa1d21d480bc3a00a785dd8dbdb64f43d37591837cf2397604789c88ff0b7e5a8387c3c69c3f20af99bd46600cc0a9c3b9e8e4380fd3ac96452319d6effcfd2290146bb75669871e56e4e9ad1ccc6579e17ebfe1279dcf654701606056f8da7c14826902304af64569623160c3240d8cb45c62a460bd69da576a66d03a688e0e453daa0e65fc20b719e9f19a5a669c41637e34db7ffe658954209eb00645b163abf6ceaa65677eed1aa3d4090ddafa969442222a8b299c0410a7fd59ccd5ae1721b69fcc6a9d19aa0f9b9eacf24ddbf80d3f49a5fbb3ccb263a466cd237a2d40ca5514d09fd9c435a779ac9d06580b4e754181eec6e4e50e5ec5731549946faa233efcfe495de2be9b73d8ae583e1d8abb3b16f5bfafd108fef466a939868a5d928f2dd2464bc203085f96a3f627ff0f4804fe49e9023979b5722fa72ec949f60301d4af016768e2a18db7d55ae90f60359dc7542074c7c01bda84cdb15359db40216d88811432c205401dc8d571243ae2975b5ed2bc3963f36f0bc4fa15d5cc191acea6b1bbce7b1037dd313bc94c288a5d70aae31ef9b121aef803706b7f3df2c15ee359d667533b240163843bed1bf797f23aae99defc52e57e3e886e11a0523b6c6066fce8812e81231534b33cd353b8df26de3909bcdea5230e28c9996cacbf653c7d98765707c53b0cc78a0f38d9750ee608b4f0bd04da37b3d42aade982f62497290844f1479f4770b3341202097f514ad5592b722e079855e1b9dab9de0550aa1c63b3cb2d1ac68af3fc6823f15824efad860e855b189a427be115d57f6f28cbf24691a8b457fdee1dc773d78735bd0a525d1f1cd1ad872a62f3a7171cc26cd02f54692925d267998a80d30d647f580909f48f2eb920a89788f1ff443ca83d63681e168c1ca629844d020d1558aed816272ee96b10cace4795d3a8c5b82f1478aea0dfe89085d41e971cc76847f1aa32cc35ad8349d0a150c44d381f84c3ecf28609b05c99b0c60220245a7041fa902d1fd6c71f23b5e794158ca331fde2642934d6ffd2efc86b1ec4b7e2f1bc579abeebb28d56f5868eb545a0e20486d1e78d42f9b041eff1110b385298798047076be1f93e1cd8e5073015ee7b6bc781ee110ed870047cbff808736c290c27bb1357809432aa40d40b24a55832f1f51254af309d22d7fdab4b28f5dcff79df52f95ad8a336f38c8850533360ec01188ccd42d2071fa1ba2eab59bef9fe835e7cf72e58ac598ed7e5f3c086d6210146ee1e7a45f4bd31bd7c71dc95d6ec3908eef954f293835340171fe01fe141b80d33993b0727819f32d6405a534a78b099aee86bccaedfa6df5c20c32991a0dabb1c57ea77a0152dea83f740f8654eba2c76a87f3fc198147620d340b6b4347ad7b7f5f4dd6d695d023839f399ae78e9f8c80724e675a148c8f8d4bb84665ed494e479def63c774488ac5c8f187e023a1343daae3efd7c3de3700791f09e590c70c832a941448f438c42be3b6d42f74b298f77ef2e159ec5b6090d5ce423df71c06bb9aa20b363a1c4fddc5bd7325a2139f336a521f695a35e7bf060e3c205a5a223415a19a9680a76c1f96f84abcd61f69a4d4949f484bbee082724bcbaf50c6e0ed27b5531ee4ba2a6fc983b0fae7f74e268e81fb521275fa5ae7c5dab610cb2c0d98e5c857b37dd3f43506b02c1cb31f4ee930e8c42a8fed4cce9f32e2970714289641ae65b7b2b36be51383a63fcd4c69273d622f048095e99c087274fd636b3da14d51b537093b91e6f3273472c6658ffdd844af9c096cf34e900336ad08cd3f6c17635f466b4fd1a25bb1237b4bf832035c2fea36e3f335485c116dc4221b4e4d641d6a26e8c930ef9280bd0773110f83b2b5c69c787d2d2a1e20c5b825bf73d630bcbc3f8ab0074a1b6973860c56915def1651d70bcd1d0004ee9d1018fb88352766d86a3d86eb7bc7c12b6863519c6ce8428e0a54c80213dc3c4cea00a5209b72fcd79aabc9b0c9b85422970d9284a62bf26e7ba38e9f4aa64bc03252bb358b7c174fafcd88ae2f84132ea12dc5a5766726d8c0e14324b50093a594ea4220fae54459aa27c9fd89b4b046f957acd332d8f1100adc76e3d29dbe4759f69f9b66b7c4011f23dc1ada38fe861690901c448de43158d45fa09c4ce9120b030d7e8ec5b0617e0cbbd5440538193466aa49b9cccd8ff3d030241a850c4cd14f26a03bed662167aa24a100e989e634ff389b8febafd53c515c58744d5aa6c72e2d82e9f344c6f840cb662a8eff5fd92d1d7488241079c767c5e83544d3caacc52e30160cb8cbd5b621dc916824f14e811a00a793f9d97ee292f3d404c57911ad338603a9bd7df9e2540012523eebb0e5687f3620fe75acac518b75b99c427c0360f286c565bbad2272af3c0d5bb28d74954fc05071f3a85b474e6fe3076f4650aacfe0803fb9d5c52d61b1d82ca826189663168717dcb6d0c5c1d1c50b52884f73237515e6d4ceb058db90301f0029269f095ccf443f6e94d81f22b937d1a62184470e4c8394380a5a92df5996b2564b6e7ea0c533013aab059fa9ff599d09413c0cff3b893bce29b9680aa5b51fbd61714f23401578ba4d5ecddff9fc04ecb711cbce0a1fa7725becb06e13f5b4816a9789f1d0ae1622df5265006fd251ba67ba16f0c21bb056eb40dbac3f5685d27d3e3a4d30067cad94a2419cd84ac85b9480aad3991acd56e2f4541ae7c8b0d65fd14f98675efe4ab23a87dd3c8022cc0b704561fd79ef3bd74d1fafbe8156233cfbded177215cb12a580c53d5a8b4bf6af144fd1f8eb439bdca9964d98be081f97305365186c3b91119fc9614de7c1913ebe3797bc6d610602d5cde0e09097e4697bd668e51f049a422358709c0ec079bfff735d8e89db40e3cd02d887b2062299f1c7eb672397fe0280119e74d5291f314123d8ab924c61238b8e728fb9b157a5aa46482c24b19ca328bf78482627cdff79ec8f7737af32990b6bc52319703d3253bac404a7604ab07ffac050dba28ef928d681e84cb5eb9b70eafa393e06f48fb24047be5bd123d7aec193ae8507a6cba0eab083cbcc12fee2d5bc9cc4c422e0a42a4cf0534999bfc0dbc744daf3af90395fab09cde5f8b20a8cb7621ae9acf35df5512c6506779838bd7c125aa0548f7a613f4d9d8fdc35a6dfe8fc1e38c02fe2d0866c69ab211bd260de3e1e6aba6503886ea1fd62f8a761cf256110ec399613509f001c6147fe8de893e88dab2e018294f89bba12af0fb9e6241c12d8c2a935f35795ddb4064f4e353503e7b81bfb902932effbdd5d66de136bcb1b4022c2d2e6bf357b7e960e20732af3812c3ab3b20468fa302e80e995e8a40daad0ec9053d945ebb18043af0d1c669eab2889f9fbc3b382bbdb45eeacbf39f0be38ae9b3d788d396edd37915da563dcd46b4052caf0bd6b22cc0e4cda6a169d3cd915da6c498184e43bebb339d1c4ca06b0e5231028328fded950734811ac2e71cf0e72af76ddf78d89207571fba3f4e541128014b13016dcb40ab5ebd95827439963142ca9b07cc5758e08b059947416d96b572c5923715ea36615c80da85dbfa381cd3c8647d32cf0874c32c9e4f3b15eade7376e564b7a58c5c13998d1614e6d6d2a05670d51f9058cf8516b23da098c69c407c834ab17a6fc512d463fbf5c268e3080648daef3ff53a59343073791939a52bafd76159593d2be66f6503e562ef5f048cd9f5a973acec5c329ae0ec862ec4dffab4311c4ddbe56440b06d230503cd2d66bdfe749d1b52bb56e8110de207265a4bb98eab6fc89ef577110139fe6232b7d7f30076108c85e2d8d2ba15f2d237bd792163c8f3799136d93a3df183726ba9a552aad294a6f44a29955295a634a5575aa994ae14a528add24aa774a52a45e94de9b995884e6e00ac9353adc99125a4895c71776a0a6349eae48d296d6f5b22f2cd88609402a0e58ef5b47b40b5839aff70a6eb50b3323f7a218ce27c868459ccd6d0081c8cb74fcd38707f713742c53bfc99e82271cbbcc04de4913333e63a683d8549bcd8e1ff7e0819bff158d17a7165f0de241930a899487d286c1c6c96bd996ae4df31376aafd2667fe9ca2d6d9c9d39c859c2d79a605482b76605b1c91276db6aeaf7403be29d44c4936016109bbcd65a88d95a42a952267e79fea3b644366ac66b2b5a0bb4a44d201c5b2196f358c5fa0d60fb8d66f6b0f300c55a8daac191b79e0d4ae3ae3978af1ee960f3f9f5b5bffe3eb08bd27c1ba7fdc5c677c9e93b7e749128c8f3838ebfa5540c22f5f06b73fc3749edff3f99134481f96f51490fa29dfab70ee6ef12f97ffe193c8882daafc8c4b8bff1c6f0bdcc69c0f5a016e04b4784200a36bfd62143106ddadee063f72ad5ec7ba24e0c9bf505cd4d4282a8f44917d9fcd75841972e28cc8474ec20aacd7f20f1c120dab3d7aa378b17b323e0d01b3d288123544310a9e55fe6a52c88d4cd0925da8653fdfd45e1b7ef29cd491f4582c893f82beacf06d19299576ba198ef3e88c03ea2dd5e81c364045132d5a7c93da84e040ca25dffd38ef5573487341e661005f559882050106d859df3c4c150894c101d4fb7d87fcdb89685362419f8050ee2a57216a18ea4396ad744dd19449859b24add8df65e6aad67f6594f0f222f87fb28b400e04d10c105bf3b88bc497a8d8c46f5ee470447992e2742f31473065190adb3a0a8866ac6a122778843c8ebccf32431d4db50881616026b101d8f5d443584a8c00daa1e22eb778ddbf764aee5eca11325fbaf9b2a47df8636fa12e943a10b21f11ee96d392b9e72a63ae090ddf896f7346df9f21fb745af3ba9f42254f529a9f8d3903b79d31576b957d27dcee21c1e1d75c5d7bbfb079b46bef4edaeb7bca769cb97ffb82d7add49a517a1aa4f49c59f86dcc99baeb0cbbd92ee7316e7f0e8a82bbededd3fc086a80e6278da14e45d500369ef384a61a2ad32d48e4667dbeeb68fe30b093207326c2524cd8826bbfa2694fdd5f05a0c6f3ec25d5d8564c7132435f4668f95bfccec21f306b33c153095bb58e6dd8dee3c18fe230837567d2db487e0062765cdd374d324bfb7b47c886cc109cba32fa69f14b33c37af477b4ae5a2aa7cc01446b1d00f1a2329c7dbb830312f63b4a8b4126aa85e35aa845bdf6255c01c6bd5e9552136cef4a2d2a19574ced87141a3d36cfb5b0e6fa4da59ff5c0ef75926c08ed12114bcc52d6a43f63b6f91ed60a64f6c43579bbb3258d9cc61056f10aa0222600ec649896e7999db1b921925137af762c09651ce5445189018df19ef663c52c4249c3b53aa0606544e355cfd5f4047adb25e4202fbeee9df70c84c91059038985a220948727ff9f2abd921047007c8080ccdbd1b7523c7924e0b40453f220b90823a13402ab95b3f3a2a0e2306e0401a0721d68e0012f12f8a819ca90048e8707ed4725009209bf7f063c6a191ff33c0e320c932eaff2af89162a054a2dd7fac8b3b4912bbb49cffcdad031186fe1a3388a257b3ff57fcf5f8a09790fe22d50e7b0fd8cd54feeb7490751feffddffc175d21cb69b2fd6b30df677bec884053feb5b350454f42ff97d97722037ad3fcb4a222ef8346fcfdc1b070892cfccd84f9e2e9737939f081305108328f3fba3fa47ada8fd182d63bc933fa99635244af88c47e9c16389950b6110d212f0dca871a2cd1adf415294ba35fec368e68e35b5ac681afc70638df5967716f0c63fe57060db741e3a9fcacff4b2adf7c637d0811ad494e066c228b2c1f12096ed517d0241ed48cc3cfe0df39425fdb9e61a4c1480a3c4f0cf5da7b37f8ab953a50f933cb90d92f5d9f169160ba1afeb21d9f89d2286aeb2f3b4f00c344dfb603106b53c26d71e8de9a0e3c21e88cd2ad8c74ec2731558f6e73fd04d07a8883f11c4f735d174495d84ab5d75ad88dde57961d8aa041e6b6446652fb8ce13d3b2b4a69a83822c40b27934dd53b7b7ad9f510289ed1ee0a4ed81341f5f282378d99c403887c45549e5ec681b4b8822ffa89d63cbcd0a7c56cf100c29e08aa177df943f1e1c5248356e5051d6cf4a2c465d30b0208d1ab43b0c9a7d91f5dd7e331e48ac77d2ce480ad21826a5948b37040fc25d9ec91eafd607e6ddc10d2c10210a9dc874c9eb688c6368b119232488b97e1ce93669347072eed96066f0e13d225b8060d303ae182918bda55ad55e9795a23bb693461f3d5b812fceb7b8679efa961695fd4face87f6862685697d3e8f7d83eee93bd6eb93fbe5b5d4982f7ef70922f84d5c9998c579dece02db6840f8f298c8ad747572e8435b7f5b2626308ab640a6944a820d8026e19847a7f6a19672a611103dfd219c9a5630c36218b85f2a84464da1a66c69df13b65b0a44420f45c832f0756b490388d83a96b40e3b5abc8fc5ff03a637a065a73d94c8c86c715e3afcaaee1fa265f52a2fa11d21bf621a7359e3cdfce88128afd57aa8c8c8e850574a10ddb4ff41135234f4b8170074e44081df69131278fe2ab3cfbcf8c4e0f0a45e22bf3da5705de7ac3031810dde011c77415522524cc8684a1b8527220d1cef917b639f326edf49f4adef6af425d76860d115b0dd2274ed1b323c53a5603bc74d123fa733192a8cae791dd01fac0feaa627a76d52b7b8735023b63f616af0b3fbbe04b562e20f60cca28a7c85896aa0c5f86181ec6e09fa082ac4c2f9487a5164a8b59a97dba99221309380131698be45c2f9707657ca954f698ae0c233027ae2f677512710bcaa146bcad17f592f274b5e3344b9c052e488c3d7b54b1d2966a16d3178a70c90cba80a7a9e5f9542eb9c19d0beb771e101e7d7df0b333d00ca00b19065c703152d06ae318b8b68689b669f27f0925d70000dc5ae1d4fc7d137eb2b80d3403646b0d52b8fb5cccb7413284e46a7a235f646561e903d5a0b388a59badf1d1218d53bc5171aefbb1a6158411fdbc90e2e022f0f1368bf7b9cfe46918788860b4e53a78310c2339af78111fa27b228b24d9f4a59f8f2f3014dc0290a43c259aa6f5c7c7c04ab0df65583f150095ee5c6f75e829869024d31be7d47e2a20484ff29a7b0249179eaf84ea59d845d04afd013d031b6a1820bc4d3e2cfc9e5dc15e92a98a72ebece95fa440dd804b5b4b5e8b3f76011cc39f17fa17e4f35dcd85dfc50df16fa6190b92483fee39d5a18d660e90bf28c03212b8d6402f01fd462d287f4a0668e93a8a6641aacf9caf20ccfc8acc00bf1e8b234b48d43576df7c8e31936559fbe7a2c39104cfe80d89265b72a79b0cf836d9dabdf7de33f329e481eddde7aa80733becae19107460bd78272f1c5af59500551a3bdcaa1b0f2ed507686f1bd8c804c85d1ed8e909e5ec2ff352421a15c420e6d7354b7f02b8c3a006ba0a6e69c4f9260dee9be0c8c0eac0027bf49779fc4e9d301639f64f01cc0358faf265d89d04119f3ec7e8ffef183f764df4692d3c08d20234ca94dc21dfac48af85bb59e9b83d6a5d56f836c937e00b2a1a21a6bb8475a6cf91e127fb540a9159430fb146b24fa426c28966d6aec4e29649f95f208b5a7185b535939a5900d2b9513ca96a26ca6c8768652b6ac205f880d45b24d8ddd3995ecb24c81dd1995ecb34c89d50985ac24bb27dca60ac835842c756429adb22a1c2a06d767c8d090d62798c0ba700bbd41033ddcbffbb9b1d2ddd77db8b772ec87bdb95b09ec937ddc59b9ecc75edc5a39f6c3bedcac1cf6cb3eeeac54f6610f6ead0cfb606f6e560afbad77b8b3526e56c4ad95dc60bccb8d95b86f25f7accc4de61d6e5ac91d2b736f056e8ad68b676b1c1b564d03fc51d5d8b1e372aba55def6fadbaeeaa235bb7b612d18a06e86aaf5e6abfdaf0479709b1852d369e57e56ad34b378a3e772ac43732cacc476041e9aa17b744066e9222a75e8d029a0b6cd3ab9b423f373548d5ab53855942015086a31fdefe1dd7d3e3c46879e15bb263cffdeaae6e7b7563ece5aa2aa9da758b70672840d7bdfa9987ddc98787abc19426a584c623bb52a7f50a3286a2236a7941babc30251c377ee8c5f97622235fbcc7cb5b9db20de40c208924ebd657e37a484261cc51e6ef435caa11fa8642a2366a98d2a8f44fdc9696c2d24080fc5304df47803acb6fd6cde1f1deaf625edc42dfb09279b3562150e68ddc9dc4e3758fddab5c87b2518529e66c1114e7fc8c9ee822f43830483436ceccc7a067bb03d4722cbba5db674b0a2f173ab86af90b05bcb670bd284a9e961c8b692848b5da17ce7ef241f2c2ea707d43beb1eaa491dc8b86d17dc4955ac4608ca8f9c2bdf7c1d4120b41feac7237be44d1afe940eab1f08c377e56afd464e7f641cf5f8fabb74a903daa04a41a4c4f841fb99a95607bb1c33be2df973739d6b009ac24fd62ce9ee010b6bb71c28f3909659d809cf5ccc17cd9a1a258c83d06ef6caa1b954d62f455d80fd4c2ea7f01a00f814e2e8c17c56bb0713931dd5a89cbfc9137641916e4c5c2635d574352584a3fdd6374cc580466c171b08cb29268e2e42134079c6317ccb8c2bc35b4bf1c46ed75ad03172c424c3584c96593be93888ae6459962bf430c0ca184c4373d4ec4547e9944338cef3831491b57ca0bc03bf8cefc599e9ca1864306e046d39d4d601921cabedde83649730cf1ec6fc60b729db31403d08b01fa05600d744988eb6649c0fcc1127f550a8c968075d47a6e5dbefe4007662c93e85934fb1e31497b40069fc267f13d810dba0198cef82ccacea131cdfdf5448eb44bfcfdc630a11172dddfe8c0d0a4a937b19f320feb2a9b4c54a73543acec86e4fecc7567f402cc2c8f0141163064416c470c06f48c290480e04a2b6e79abf0c93c17aa9d29d7e877da539d9886e20b28c856b4700079b1003d4c71f271e168c9c79509e4a444863ac2e300daf0072e80c7e7930c25d51074480c96351694c442572e99b515b8b43046a9158f0a5333f30604599a93451ad05ac031f3acf88e3db879c39da49c6ec68a22a864c8ec672415b10f0e8e2c426d5b2b49ca92725f1f88eac07968e0f490ca69509b4e003bf333883a91672a1c2029c5ac9321df5b2227704d2a01a6cdcf29e294b5a93a0c94d293da3bdb246787cad32d02f2b91e34dd69aa7e60702f2b32798f7240cf146f3be300886e739d5f724a921303c22d9306ad4d13fae5ad3a33ebc69b6ada9c5bfa17343881364e2c805e6a0f2830c9507ec46cc0b67d1952a6cc1d3e7888cafecce37680b1f7a583c4ee2f0722eb1f1bc0bc3ae6936b054de0d5091e79a2fdb986cdb56de2f8cd7287c87a6fefcd815716740d07f4bc66edc92584b9ea53ec5a8cc0a3cc09bff815d535e654e66aafc78e095e911995e43ffa804977e44f181a5499a29c7ace3d252a1fc47c8f58a9d1a034446c1b0f4d1c9ca2f2b15f47e20b75b58b2b602e0e28fd67e4b74cd60d6bbea728128dc2eb3be050a9377f8f2a3f1fe2527355a5bf2c76c96348d96465fb2e8ba3677b4ef115c6f66a28339dfc3f99f5726324e6c11413ba4d17b514195a1f5713049d12c8fe2a73cf9cfefaf3fb391528b2f0e1ea726dcabc3d0adae3de1c2d9b77d608c1bf9f7133b00208f71a162c97fb37c824f5627bfe847138b26444d345297f637b2a7ec3bcadaa181f0b69cccdded093d9bf446ac872c8e1bada757bc0bec1fbf1121d0b5e0265cbca501bfcf8999bda5395e64b981b043aad87f75bb33485bbf4ac291161da3cdbea5f868da2f16b66e9e13cebca39ca0a4597bd0b975b9e389d6f880f92ff04d627c3297e61b055bd18f5d7df3cdbc709880bb56465d5b7d2bad82d7bd8af5a9f40f2ef7372df6c6782c40e4a099193c21cfb7ae4221667167f27f9304f3a2bbf9bbb561b687b7ee9d918200168b9fd37615e06bf1fe342936212854ed0e739d940c9f428d760c102b2a8e63590a4ea557ad1a31828daaa8f34b3fbccedf9b3170c67091fe2b48b32933335468d1aaccf9ed0cdad9fc886db1baacf95df1f73b160a4272ff2f19645f7bedf1d9872828dd858816aa79a712290d07903f90ef0e3c7e0fa9e47f267e5b49e9751797d35a8f7a09ef850408835a7d5a03a849a3e2f1ec5f73d0e05d83c93dae3efa7e7aa1a71a5b3c09d06c55a9bc6d4492ba5fe3cd1193921b9e2b2dd132a01d6b4cf63c4a115829f0bf398253ba57ac85f2010442e6563f114868fa661d7921b063773e511213ce062bcdb8960702179a5296479cc155da0dc1684c4c71d2a23cc4daec7f25054daa78c175ac75c0a0a3da66fbdb244f1d175e85dc42ad7ef376865582f04e4f25c3b0b319d2e3ec5c47313b8824cebc8351b19aeb5268dc9bb3c277bd2e61a09981f3cbe46de4a1d4e1148b3711912c480015ed6a77f5da7b5a614833ff70258521610209fe8fa06203449909e00965fa6b11be497ac33bf238e4c4433e4e70b67d8e265129094a058843381505f7e20f766ff2bded63252a42edc633af74788ac10045dafc8c28ce0379ffde30f1326d36e5fd751e6bdb537a50375385e876c43f7e9b30e2983f0132d1d5230cb4fe71c5266c75fa939a49355247ce750e1f99f45bcb7a09065a9468f45b7a542c9e5487b8596218f997c1b56f326331bbf7d24880bb478c1f328a54f8b04da217e7b8a5bdd9f8eca856bf39b0b9bdc34c4ea161bf3ba4a3416482173fd96493d9a98c7228b1e4261a62172c3cce0cdc6564d1e484537db92edebb47e0fdb20ef1ccfa777be405d416dcde9c40a4a31b2933680ab4e9a9b2d1be3a899cd0ffea25b92127032a1e9d50cef46493cbfe2440562451b901037f109099e6d88b4261b96a4b3ad73d4cab2892cd111b6ae4777e3e660862ebea5663b24511876ebe80a298a5ccba853f493933bd3bb59a46fb773513b8b97f182bcd4e00e81bbbe2e12af97cec5224756523d42c85b4d9f746d06f02cd6c7fee79c9f7435d32d41a5c222ef43351cb24488c0b7dec0d149e9767162a990df68e289efcfd75e6b680224b8f453bc19c2535516a80bff4a661010a355dcd094320b868d40aa722c7f5ad3d19efbcffe129eb6b507757e0c1fa83aad407ac2c33d5e82670788f4eb0a8df96deea54dac7a9fef8389f0af103de3ed3cdbb4c3d38a6430b534bc5272afe4ff8f79a2faa0e14763883dbce65ad2fdad6a8b12d759ea7b2a009a485e59500b0e120b0ab1b6a9e980d175cdc33e30188595b21cb01aa6c78859e102d98006b7433c1fe95a75d5e03af58f6f87912dfc9f4bae59bff36736481fabedae077f2f43705fe801040037b823caf537db8bc628b1512f46583282c92b6dccd8bc8c2849c0e96fbb80a616e8abc5c397dee0794c29f3178155d26eb61c5925fb4ebee46a8acb4a0bd410e9a91b50f2c2706ad72cf9351906194716e9567bc81541423aa829e3b225cca3ee8b71292a42612d601dc5a7dc17ba349081bff1e6df820ce12c1c0eedbefd79c05a67a5e6aa990d8ef4c70adf1933939cb622c12cf34a4773cf783a8616fdb8f90e19c190d3a6f2b0f3d2d79862905b4e4d1369f624fb1fb38f60dc387c1a56049b93dcadf2244d784fe63ec1051f0e45ed571b7812ddac0aac50fb65f501ee5663aff452cec4f01dbf9f9d2e2932aefe73d49cd4f754836e4a7e91f60a00f20405ff0b10eb8b6524e689d6bedbd5aff0bac21e02b1e848c8ff96430ace9f76ac6604bf0a56fa0cf8638e6288d3727e6e13c58cae0fbc1ab1ce330941042c0aa87860b9d00a3f405f9e52634477e207b37d11410d4d18ebe301b735abea59fdbd7ae04fc3b8bd2aa94f72dc71a0656e03a417503f0853284752049b32143d8d8fef789b0a24cfe106f0e40ea818d4815ad0a51b104a16e599dd9124f81d570470075fa79c19486cdd640a5a30cfba60b8b2ccffdc41e5860d0474006dbb9ba35f48f05db0dda5a9ed4290e294c16c1897f4962f11a69e9c80e169c7c7fe5e192a01a180a3b416527c130011b0b2c7859ebceaa2d4bc8e6181ccbc25370b63085f52703eb0502c6061568d300ff8b4c70e46fed9fa1c54c80c677105ccd83c8ac565fd1e74af3ee965cb9e53a4016f9a4e8fd4c7a54353dcda63f713af149e256e3dfaaad469c63a0a58795f44ee54b234a00abc96948d1246ac7a2f697e473951cd830408b280a507ba8fabc0fc40b6b946905307d0e3018712e2129e28611d971a74357e0fb0490a084629bf4268b488df9edbd2b352ea2c07cb52e253c62d55a9650caa6bbf9b8b6b4b653468616092839b8f5e086be06b1c8b6dd0846d44166e5e55e9e0180da7db9d94c855272ad238c4597d7389e990c03275e610362477466c3ecf401b047336f61e7b02d11207f4e920c9a55e7f616e8a474a51389bf9f8d781ae03f5d3811d67c733e538b0afa982a03745cb685fd6fb2cdf4a9f48ee9878858701e0bb2ee3edf66038e854d44abc1d44992e900ac6dbc67a239b2904342644248e760d3c6cbcf7954e8f0d25d6f869deb2a611d7b8b3843fa630dadb1c184862f0881b0d0b7b3d469551f4127c233de961ff17e0608c3209980879e5a09883f06e35811c747ebf00b67e0c32dec7b65df8171bce5e52f619cc1d373bbd3774e4013fcda377fe15607515f8ac9544f81f7a52ad25eda0c726855298e626efa6bf42aed25c2a0c7668bdc082de1c2a325a6423a0ebf5ce693754581c1e58ed48ba116d0b68c63a6410b39eadd0b1f907c5cd461edca5f41812214f3100c0bb6527c149b7f03b147008b02569409e3c3c184efbbf8c3b1d0c5c14c5e250fcac72b3ba33ca48f957e5ce45fdc2a92b4864e1b3dccdd0d57c762e83992ea5ef88275b1b4c46882d0e3226a640da132cd51da004a0667607638774a64654829cc64ea2f1c8ebac6f7de0ad1dd9402cdd83883ca69d65d596f9710344dcbf3f7d964723c05ca37512884e98bd16fba0e7c20881b09b341894f9077603cd7393d387c851fa56aa0e42e49e3c7acad967f270c7d613eda55cdf6d6bfbe24e510fab2318540c1f157f38ecf22833b13ab9bb1278136e080639caa7ac5ee7d3d503cf23bf4ebd3b2be17b1f696540619b23df8026fc2a315806b178c5d1bebec2e162dba4a8c9f9125dc0269d1b5b6abcc3e902f82d6c91fca498f8bfc82392eed16f54c6ee1560079a27f9a179138e8b857a1dd8d4f875a43980a45a58983023c9d8abb807b168742472e54e03039903f96546f1bb710ab6e4c24955212ecd5ded05522eef1ad8fe84972f8a738a878598808ab6760218fa3772c0c69e20288971ede9e562050de3b09026d59b6cf77fd64ce687bdc396124b63836bc9dcb3c542fc5934b80c90b954a71c47dea7e55decb096f0db658e67d51f559ae7bb1b48540485b8161ceb28dfe403e85bf5888b4636f60138aceabd6a5ee77acd3f8462675d87c3bdf9ce23405cbec618e113a79dc4d678241452c35d52ef239ccfa6767bffdb12739ce1f90ae366fbb0fe201ed6c36cb610c69cda8edeb739f4f6d6a67b406016c93bb0830df922c242d46ffdd5a253677f608829781e5745756770aecfee3388f3e8a9c2843f5e9618a1f31c0cbdb1f4b2539dd0ac53d8277052fadf24b0f41a9cb9b1341639c779dd00e6a33472bc011ca134d97b7f1d406ff80a2733474f0313776b2de779ea78ee280a5b522586485004d6f9d659ab1e0e2c68f9153ed2cad76d276d46a6bed149e49553db8b7f628ac09b8fcc2c92eb580aad8ca00904e260218cc4095ed28e4ca56934d69d6ba0851938e723b36cada03b0b45432e0519e53195fd7a0a7a0ba7481e172b5efd3e9a60cce4050699d55b44fa3d6eb608c64cd1ad8cdaf493c12ecac98b21e446c56784b74b97128c62f8eb80192f8f6d52f8a2481521e63a9c2c298778ff5702dc41775b40237cb86bf444271e68bc60dbb1ead2cb2a5fb00253b8de5dd94b6a22ce89866c1a1c857a79abe9d0a281422d70587afd65bda63e08f7575d16036ea27179679013d462abadd6beb848cd9d6a288d01a38d759234500dae295df1f026c10156b99c90053ef08bc557a440d5d513e5271489b1376259284b40659e40318ee0ff0394dfdad931c5f6e91f9a1b7abb698fe23f1233d40eb911f238451adecc2575c547b097d5a7232d7380bf2cf52d10dfda80dd9b46a6e4982422f14612eced42c1fe686020e62c9ca1e80b1c38cd190b78c29aca0a66476ef110f13f4b6e463e762640b3e78f431d0d4aa27798281e115a93c8455468f6cc6a096bbaa22b337c67a1749360feaae045ce0b2cbb73c3963048a0c6270431aa3c72c74dff9db5658b8637abe7792c7d13c4d87be70ad26305b4701f0b32d87ad2972b1d69b8fa92599499f0e5a96825bb4da13f1c07008edb44c0d5b1569025eb6d9f59cfb590c197468727b3c105c09bfdb5f1dde6931ed75d140919a2b6fe7da23d4a57cfa3cc421d501d3a3ff64fda043e4662217f55da35fc427db60c3bb03b53938e251268cdbdb6882dfaa828c078c80762673dd216516941543b0dd4f1eca90b3856bf59d563cde9d32a00d1876fb88bbfe13b362774ebb263482f5633a272653f37d8672aa8f17e6b277780adeab2ceb4ff2fa8d0f5b4e7dc15e82f0c090df320de3ca6e8f200943765078846638027271437dcc5195704e87ae611943dd1b50e0edb4bca4ac071ab6b714631c289a06314f5a09d6ec8cc4e0a9706a2004a545e941367e6b8ed22dc9d856f0ac8230c98d8efeb18371f5dbd1aad849fa0b6e147d6f0b4ccb2420ee0d5906fd86639c2c8d222b3a3fec758d50d4ff2b8b331b04b74ce58c9de6c2bfa33d2da94dd573fd7ac03ecde02f69a3dad15281541e5f5dc4eadf998091c13cb0a2502b189b921d7c26adeb3239f3b634754fd5bb15116a6973d6ce6ef26f68000b7c3ad2183ddcbaf5c38493e1168376834efa2743619e14042771746f4ac3dc002cb74dcb1b111227793de00c30fb49b0a551395fb2dba3a7923efb9c71894e6920f5bef8644dc4cce2d7b1c114bade4eb50f842097b9d156933a5fc66790a4f0139e907010748e251dabc7b7d4a9e49eb5eaeeb660bad27bd74da1b4709e1cec5988d9d1fc3a044fe0a3476118e9c223df7a380046b1756321de87f0b7faa4e0e60c7adb6fe101bf96ac431663cc85d2947f0961e6d342f1a262478aa46f2100449c7a1989e0a1d1ca26ae7fb24e46ca738d5dd3e6ae053871a5c46d4ce1e479db55d2cc8f598bbbc97676656620d3a88baa9c4510f7bff2a457b28b0d4bc1ee15100ca39c1622ba51a4cd0d3b33872a013f8d6489418202fb442db528b4220d80dae64759deb39794c9d9567f1da9291230a7a3e23701b0df40b9120f3c3ce54f14c0c4b77c688d2c7628507afd9923590e1058d6e84e0219ade155238c826885146151be243826e808dee776e6a793984000e763697a4c5fdfff0705598d7ed933c970856720c4a9f790316c7eba011d01349c1cb26ac4f8bbcf8f1ab52b4bc1007f156cdb51d1db5b0917ff7818e09d60c92225290e702d97f25b0923778dac8e008e88252d888ece76927b1e9bb94e23828879b6e2d43e7a29a215aee68e5605e19ba18ac3e636b8b9ab81d3432944979955923e440a32d4ce42dc54427f00350d6546639481618ece98cc8bab02593d9411b76a0509efd1d26da011db98500e3d1f3c7b71c8d8378ce60eb2d3114cf5e00df437dae6aa16465dbdb1e71d6491a9f3fb57559e72f806da93ba715498a96fe385782031cb8684276ce528ffe5a34fbed7af93bd1c4a3711e7394532645b2162694700c764a1e526885618b34f3903d499c0393d486bcdbea11424db71f1c17d2eb0f7347f8190c44f260108ab33d62b80e510b0bfe1bc8f3aaf9dcd2a063b6a7263098e9d7528e3a3913685efdfcf2d1220315804fa63bef2d3f8fec3e48820124959248bb8edf8e8a245e13bb269d249774d4679f93a2d0579704ec47e6c58e8022e38cf81aa4f2b095a0168a26150ed1baa733c82e64086bc71fec74aa8ae122565f0e7b0a62bf43d59792fd30cf7ec67dcd5e714f7d0dcdbefff1e5dfef16d607d06bb73a2fb852fd826c8e3cd9b24df2c7d895247d38cd7917715c07e1b3f4be00b6645710af3220c875d1c8879498cf9dcaca69732b869e99090a226fc47fbbdf96a57d39bd922a6ebe209d354ecd13fb5b5dc2da16e7e4a8ae17a0cac236cbccd871bac5cb88e747be1b5af6abcc64eae63c735393b8ecc4edc73939ed4283f18fe25d4df36d9ce953efca89ee84e64f9f240a15a8dd4201bc423ebaf45182d72a131d23c7264e85d49aeeb5978ca568060bcbb0106c7d034629d6c1b7e4e4aa200a0510a43a1bd512d9ee3a9da25ad35c448ae63ca6e73e8a31b2f3806c92193e495c0c9118e748e0704c9985fa66dc8910aac5526c659b7ae97b61f83436390379841903e46880a155eb99f0f2eaf883d868aafd69f267c78497e1f88b78fd57930e02568e8280d33c3985a2c08fe7642cf2f15b5860d25606e8aea47ac7e193975736a4d1a738bc1d19172b5071f341a50b989dfc7a52dcf1b65f415c479471c80d9cc1dc02c6c839e48169753a9f200fc7c2150ea5c184275d978c4d37029aeb55482ba427853646ad427668eefcfb34ad2d0c6664f20a1017a2d747664ff2b96742944eee655ed3e6f62ca03db0959db14934ba6cf1a2b459dcc28aba00663cf11617999f00ec13dcdc14d784fc2d745f919e721f11a0d8e2e37a5f4a7f6a845c3115c514df815bb8f804b059007261d24abb41b0f9a775a7e8953631ccf02b0b111e98039dff592647f1255b9d9948ee1864a94001a4e4ca146bc21450b99b9a491959e3a370606976406ac3940080205744440d3ae7339294fcdcda966b9deeeac1ac2588967842662f663975213d019780cb69d51903013de9eb02f55ea901786c648cc86e46fbeab2b0d5edaa64ab2c654ee4e70159e7d2ff1275103ea3ad3bf284eed14cfa73be5b8496bf75a1ab6198d0b63dd981d17c4d616f4d4789d9aa083bd5c9d61cdc0f143307cca787e73224dde069005d3d120ee7cded38ec3069d9cea01e60914c9bc81831631bd1fe59841d13a6e6f273d7f56681e48fa48576f56cee314766e2cec1523cae8a2a6317a36835df7b82c304c46720a49c5288ecf87e4d94939b2dafe3916b59e28831b8852dfaf9eb9b8deef17bace1ed823eb6037cae7319a4d7ce99918de70890f4fefcfc2774046dfe9008637b5620150086368c4329bc20ed2836be30f2b1acc43cd5b19d0b4a36ab0113b312897f87e09a3d18bda557f43883e8b3c555859757853e2be69b2c9b4ee316e70dd8cbb2b115559aac95039f58ab390cc6689bc8019abceeff2b05a4d388a635f5f60fd9b82636a18059a9cec9eb01419f0c7c19054b8df1904cf009462583d3c38c253b5a329a9293297c57ef0e0803b1d3d67d5065a8ee3c0a91d620763a328641918b52eb1483b6d1f5f70dccefdb821f9806eb946b607391b97efdf66377ffbee9c80b76cf2fced498c9f35b798aacfd18fff3a2a8b09842dbf35a5a16e01bf30a937b9be3e78279fc65b29997ef4aec2d87b31b24f6add28db69fd1145f997434231df521291a8bbb7e90dab2252f92612abd1bc3ac88eadcd7a5d3d3b185d0167f34821401637f843af9d765e262e25560e392007cc41ec0618a0edb1b70110be047697a906741d3be5f3ff76c456d48cfb63780a0dd709d57381f5a39c3a351c1c4e24428708071a64a3b38a6ce3dff6d4e2c2980171d12a376115cb623f45edd5cb5833b7d03c3b1e1669341cc497d4c0f8f30cfb328df587d94a30ee19900ff707244e43920473485302244f8810c66a0b8a4cee8cf5337306df3a1f4962be8cb0f3524736897751d17679e12d3780f73d806b41a8661951f8ab561dc3402aecc28f279cfe6232239abe20c4894a21909d8e4d01811aa25031b28e55ce8bf30a0d9cb81a3451328d6d63858f4beb6b0fcda0ae0e05786ef95855b244134ad87f33bb07ec0f3b3c8278fd8fcb6c0da469ea8782fb9b79ce928f0c0a4fa025752289299f0004c0072d0a8c74056e479e6ecc379a18d5b3b6f3d59488ab26a8e77781faa0c868829b3d710b88cf2d4bbdd0b37950a811c69e12e686b9b26e05330362f8c496306f0727cb71108e06a87c416a5f2c6f30c3ce80b1032a95391de69b748e2083889f38cfb5eda1ae499393323e60e04d7fb19cc75629629ce4dd2add8142ba16f7ed1721c251122e9275102393552b4235659a1f69733bc1048c9a63a819d0aeec14a8c6b2bba0aaf39a138a90efcbce2248288c08502f4e875ba97c91ec148e8e5339064673b27a055175f7c6cc0169a271559d97642b22dd31f9c1c36fbc070ea3251814980245782117aa37189b239d3f9207a16e674ef20736db283fe737db087531035026d5f8b838cf5584a0fd0661430f8016258177c86606248df2e76a8dc81f5b51faba1a4e91fbc125004c6592033e1472c4301f659bd6de84048e9cf615e47e8cd42dac8cfa732ba4e3ae64941907014bd78948b6abff77535bbe6873c2c5a5b538ee136ca4aba09d2544a7ff7def6dd407fcd1072fdbe86a00ac0584d22b6b8a6f056aa60f33684711b7b99db78b8516ca8f25f1d36e0fdd8063a4b8aab8a0a0d4dbc64904daa39ba54bc79abf0053bd4b5776122f4bd44c53fd5b65489d24e1fa387450e669b5a0be05fa76d097683f61c03e1f3b6a0f384a958c9f49f50b3d76d8314776890e05c53085a6d331baf41488def63288896e83113d89f301dfd029d5f9d0e955d070557e69e0e5eb6aec7964dc983c300330b61b1654952207fa041c5360dafeff89f1c1d1182734a1a41d00d4a049c6f153c7886ffa417f1f43b30e7bfebe773def3a2b172479bb1d916d0401e103880a6cf0a26cc38595ca16a9b037bdc995137bc5895f3903dc5e9c31dab64aecf721dd195f5aace2ea8a8624384895a0a06781f674341a6ca6ff0f36703e67aa243504d14c074321e23e7dce90270c0ebf337657071c9334a7f3c0e2d713ee46ca5e59c61917ffe1bb898565a6487088e89302ebd3199520d0096bff7ab23a508252ceaeaf20ef1b4bbadea69eb72b8161aa86b0d3c86c146463cee3a5b0c79f720fc35cccd90130b12d49bda83a3bad8758c4b01514db8108f9322c66cd74e14e0e2fdb7c08af65a6956fa6e40e949114aa35c7ac768e250626dd1717314f0e14a682218f87b97a1220c8b5212b9ad0559ba8773c1989f66b7933ab9f55086d61ce96ec0ce8422e18de764a0902e06a0a7f59f11fb613bd4535fd4460fae71f5651bdd637e84359d0663f3025dfd7f74753cc04946937a11848fe5f057d04a23c12b50b5d99ac0984f5e2399b3f9c9c10907e1795ee64899a8d4337f721cc61957a7d5c48796019026735ea2e1d760a498e20b09d775f90a9c41051f482d0fbdee50c63f4209f14452cd8e1b59ac6f0c8b1aeae1f8ed2001994f2073eb7c126c7419677447a924f38a2375fce4cff1b8f823be0d78e94f37c6c57c5cda87e0f71e9bb991760d0ee4fb23fe1172a3ac3760952da83b448e2dbdcc857fea6d785032da3e1a50634bded279803a2229cd2c8af4ef33c3e5739994298b2e99e4e5066b4349f9d8ff757ab328acd842a4dc9529cd896df54c2d22e97fc67a9e5fb1d880725173e8be4048cb8f5cf593d761ef5ed8fb9c742bd9a0ff0de84942643212f933dcd979df97df55ae4ff9cf1b3bcf75c9363097632900219749d80546c35e1ebf5c00b7ccd000a1e1647af94ef05c185d896b916e2dfc1b3dfd0e8049410cea9f8ba145b9aea37ec1cc45b36fb88713c75301a5df2c5c53df0a1cf1a09b8bb8fe5557e90f86d98390bec6598d46ac5e3a19ced0c8ae3fa11252d9cb90fadbad4fc50e792eccb9c1896b9eb40e9f3c1c5485fea475ca6696503802cf43a15e1a629877faf6c7e97feca563364c8ebf830fea6bb6a7904247492231e965d8582f1bd3127540cb3d0548de6026a85a282bcc9de5802991d78a1b3b026a74432640d2bf08820546239dddf4689c6fb9b576f4c17eef015c4b9faa1de7becaade87389e102f4c1b38fedfbf81d56cb73ca51cea15ac37835b17755cf43096b25fc04cca3a1bb56019e84112dfdd5afd45163351012f54b94f139400666b5b02e517636576cfe34124bcb6922b5809ad582e6fba8e1bdc85e8c8e1eb946f3387370118c1f253bf7437a4a9262f2f7c830fcdd6549b82d78f1f96c1108d7882cfb872ea19c0d5969d898df1e3b4bc3d9990e28d522e5107ff001766bb221e0f634ab5a1b02a410835df1645e6375e0c87a69a846b88884e28c21dec3f1c7088719b6f5bea0ab5db126c5f00ab0701a4e642bf2452f465d6cf926ba34294c28f3ea29aa3006a5685c6ae531b602d7305b8b0325bb12b25a2748e080cdc78a71713a314badeeef6021f4b6f0875fb91a54cb3d054504c2314e5dc425a4249c19ce6000afb840046d885bb28f5a1af80c661647509bd3aaa3c5effc09b1f6fbf7ffce16dc1a52867d90497a84749c3f9d608fc676f309487f3eea7e5a332d7b631a1544f2c1fcb436850f380b127822ee72a7c40fd199ea682a654253f869317d97636f111f35f17c3517cec6874b1952dc168db5764e8b59032860a4b22b74d264d3192099549b70d8c5984aa695dfac6bc77ccb6e5a0e47d5dc6971be592b918ad254f60292693d379527892bd9dc5c85ba797c2f03503524d82e83799b016b6320f81689cf4e34103299e4d7dc1612ed3f885857b14b4eb5c9a33eb1bcffe5038ae245c115480d343e9b602cff2daafb6a2a1bab580d281daa9006a1ca59ea02e87434456b0f1f5588ca4e4f64dfbe1f12aa884f831601ee0d236d9ffb17694a27a43840e4e3ca97b22e34b414719a48ac08798ce763a900961d31c30f6d8694d47a0393f81ef0065f7e591455da8815b4c0835bf56d9214750f718e3aa92b7fa0a59b6a0e2afdfa168fb55a1893537bcc6089b66d0f5d9981ae73b1a775108a8edb40ecd9b9d54c3f8a7a3b1a3cfc2a9ab4765a771bf0955648fa66b926f050e5f80600d1728644147b418216cc3e9fe687911969e63f2b85e7ab44527118fb62507d0652bf754f82eb5bd47a9e572f035ebd1f01cefafd812d704de7206dfece6d44eae2a3aeddbe7b5950521e409a42e7ef1f96ea910515c8ba1cc88976ac816c191722c03b53964318c2bcb3a61129a720b16a10907a94811840aedcb513eb8d6a233cf99293e5d5eabad7aa1226f10e661ec997aca55e2eadddab4da61b7b12d1da513415fa2dfb4e603da1024d7dece08b13527a1bcbd79679a945035dd942d68d2ea019f54de43a073bac043a3b8662c0209c285f6575f684435e30c38a44fc5b2e0bb4ed32a3127d33808053e63379772c4ff0e4ead9d3b404da6ef4dac257aebd471968453d8186fa4139e3c57d1ea83dfe3388d23c41515b76f7a2636d5bf8799df0e98abd14d6b32eb3766df734aa127ca66cf77f75bd7122ac6cce3856d0c63f59122e53a056cb72466e296b5649b036969f460821b624cfddca0a6085ebe093ae71368b0eec6e06b6d405ab18c45297708f052ff5b22d7f713a0ee5cffe684e1e40004729d6567fa362bb41c75f7211a877c5ec091920cb62417a61990b16a811d2067a72f113d7b930db5fcf766f05e3c1f91a73bdf1b8da9cc16b640cd13ed2c11a742ae58c903a8c95ac3ec65235866c41ad5247d9fc97c7d200486eeef58c014160c06c5d6df4bf676e284b54f420afb1c2f6584ec8bdfaedd22358f2e0d7e8331974de6ab4e79e79105de81ecae3e261ef8c70293b4497cd478a9ccdff711633c2fd336d6943e967e7761565cad7b0a28b3f42c564a758d0dccc4620673edc633ba731434bd760015efc41defed8c00830929cdd6fce7fe24c29a80976641f60bab8fc9f7df4e201f6c5244a227ba234e31f452590b9bf017b670c5c17d889073c688ccf7ad265e57a118f22a0d8720888638e14fb57308fcbb64fe232ce1aa0d4e15ba18e1c1fa1f78f491dfb440f2875da3dc5b8b637584b2444eeadb26f508950c46995f0bda377e929393930897f046593bb559a535825652aa97d030aaa20d187d7e43403856e3013847a5cec0912bc02edf04a38ac7d0d4ef70a1d1630e55fc2415129fade4c47e10941001bbf962ac21b1e39eb9a68c2e75a396e267b15ca042b37bd9634c8292d0020b17e8470e6f67a134694d8859c97963f1b2508f8d015a15bd1d870a903382ed8c6730ab4c020e25c3c284754ce08d770067b824ce19c827085bf821d25152272074c226981b2a8813e751cd013829b9c9224bd11b113e3e82506946765e02798b99a352c2d9803cee05df40b4f012f400624952075849dad402ee6235a039c10a86f72e173bc83306656d8265230c85b3e5002c126ed3691d64ae680b9b1ac763dd46cb7fbed39bb83f5995526ceec53735a39936e4104687326f485f96286109215d7bcd71c9d6f30bfc7e6a609fb059d87ea32b8c0a166608c46bea7101f95e10a9647ec18414410979fb3296741ed994b131d0596ca54573f21c774449f425cc72a938f8d8c9460491b55e9ac892cc47c07b8e23f50181e77377774c441fb5e85359a107cebb372ce23d10b1f46316f3697958370b3c2faff2b9f1bb10ca115648bbde778fd992994077961e1e66e8a5497b1044a9579de34cc90c1bade9a03e5a9bfc0779aca5a8028a0d53ce5cf4f5e253b6c3ade4c3f4ecb0bd2b5660fab3b115eea0a3e06b564ddb6d37cb503f00f7259182222f6cfd10de8c38054571d232d863789cfa60f29348c3c9cab2121f43c22b810db877560df0b6c751ae800ed1990d327196dc7435286ff7d3f8d2bdf75c259e8a75dd4a27137ae0aaed7eb9ab74fdf9c58386a4935ab85476b5c6d22da326559c0ab621d0d18abc4c3c4eaa9ce011ef223db6f9ffbbfe8a1ed2b12dbae92f53802a4cbaf1c72144ddaefde6af8c22d93f0ea3609fda6da5de04d2660b49cb698f57efa83ff2992a79de76d6298d555bb7957fefd13257fa18b0677e7153df1d444ec57b8bd8b3d1f4d40938615275306ede222b5520e41a819cd4ae323662c1649a5ffca0aa0e1374404a14b66977d962ed315f805959bedc39b61a697514281345624d4c8333c1571fb39f73caa045a58f2378d5c754cca03b9ed5c189132ca0b4d33abb3a9d70b6db38c2febb51d60dee8881222d040c6a957944da8195b12076e2c20c47f68bdb1901734f116ea07306c87f5f5ac0f99b9e895af67a9054033a79f043903a523ef8f45297c498ca8f952d087ecf92cf7d61bf921c5da16334b6a0b6844760453cf7db18aeff98259c4688dd31b6e56cee99398a33dc4c32616771088cea63da383129a5fe9eb72683f4d40c887128ff64e01c07c58475527aa018a2dc90fdf2fb5ad91047f4b38a79936cd54f991438e7c142e24777c017f8f151a5888d5762d9d3218acbf3df206d310ff37dea37a077395f1b7692b3c250e97ae1c43d462c40f03f98e8beb1e910c717cdce032ac3eeb4f529afcd68f44044deb9a32c1f7c5ba2e52e2c974dd268742a89cdc28e47060f5bbfbb0262df3420ec1324815ab18d82373d669e5ab697a6e5e72a4cdc052134deaca25a5bc4cb69ede3a5912354f0b411b461e105f229d72600c6183c506e6b4345f5c0534a996ea76bad10928c6de65a837230c669766e6bbbcf1ac50ba62e7cd2a548f23a37e4ba3a8a76fde009c6c5cd95b2db8969a6d16b00314c9ee6c20aa9b41021b3b56c8c90b4416bd69c2665f4c8cd96ad971a2df29f9eccf943933b0e8d3303cc3c9204d8c9a74986e7097ba0b6d8e9cbdc5614090c4cbfe08407fd8358bca723b8607f835d8fdcfff0eb5426e838e1f4b52971d56f07d9d9ae9798e433956def8b20248927377743f00d5d22d89b1c5581da43f1b5239b5145e0009afecfe5157fe03384f9e72f14b3a23efed4a63e167ea33780263c044d896c4bd22af94bb32259879290e6ceb1803357c3b90a05c2f2f5dbbeafe1f384e0f296d9336b172e48ab8c0708a262c27ed7394549d45599d93c1fd3b28d1be0770800d2beda2ece65cfa23343287568f9f4f70ddf7a70a67b253ea5c0d7a6b49bb7fca049b4bdfc2931171d02c5306f69be225c263530e5480594f0c5ecede13b5549641a3795541a522718bd2da12087e732e08ca3fd433e2a1cc02d49613951552b432ef6e718988ff1c90e8a5ec817d24e98105a229c69d7ce6394c276a341973dc961a5140d48ee335f58c663939fe179eb5d791403345a2ae56608618a32ebdafeba462a4dea0523d090acff8b7a8e9eec299245e2ebaf5b0d242e5ccbc02ebe6b22a34ce2cd4509f7eda46761fe7776f725394784b132efbd587aad9ec13868c2bfcc1d9450c25cdfc822c086c1a09355bc4ac565e01c0b2df4a822951fcb2d55cef43363a98dcd200153c2a16460d04f78b91a7d29f38cf9dae2ff369b80cd5517e425939df4ea3bf42f738d1600b7aa033d00125be557d8c6fd76dec5dbe0e5bbda597222087799fbb5df0e0f0b9e27c059dd27180f9c4104d68b4d90a8e862116fbfa45fd2cdfddc2ae09da86f51a041cbb6d6b42265976065f8c23402472fd923762d18190215d6b670d21317af635a6451239f19d24926874fbe2cc41d7b6c323d99af45a961f63a2438bbf5df05d21909f92459bec35fcf791e22f0460309d835597e2ba48bd5305020fb93fe5368164a8aeebe3099d83d9d03be6388a216df0cab8b222340ec513bf7cc1a27b868524c08f680e0e450665799d6c7684046d7bd5b8902e5f98ae321464a4a697401cc22a29f303d6e97b31974215a02dcc8c643e3313c90090e856d2961c25eb64bfd8f1f0006f1b3d693cb899a162520c60f8abbdd63bf2b21a834939cbbf027a75afd860e8de1c2592a5f453fc3a5cac3573c672532249cabc257da507f0a80cc2b24594d249873cb6a6cd9eabd76384e5b1c82105c1286e0992b0bec8336439ca02dc1b6d051c4de526c8e48f918d2efb9d56c9d9cb4ce7d4dd0d1b7cdee8c068118fbec889be8055a9057720c36520af453ca49a318eb08cb150817fa5a1d4298944f31d974471da6e7ca13bb37abbb3a08dc8994385306f781f1cb01b10ca5dc5cea2b343232cf970a4ee99aaa3fcb5643736bc8a3b34290872f31dc473a9c9eac31c87af20d6e71b2142ca577366ecbfc39fea6d450d971cd25998857cba9e59ae034d49b2f4213259976ddbb89b69a3164524fec3ff3f58905048cffc8f3f1527518d2add127c74f82d6c6e1907231bbec662ff8436ff50278472e164cd7d48251a6be05db95fdcda9a1d7321f46cd8db549e22d830ba7e24f3a4de74791597f68b38d8d4980a482c9827d009dbed5c95c67f0e7107e30a213739c5108a9e5cdf3c3089937bd418f4c3d67c482a0712c8d2332724d44a964b081012d3486e669354a0556992c3b842aed9c90113b0201ee1021ec6216cc08038800d581843c383766260166e800bbb19e295e5558c43d461491aa121f8c2c9667af3f51d5399b6efae32ae0556d9e4160cd6459f92c2ac60a3657332ebe082aefead63014bd95757c3d724a81bc00f66fe6fe51f9cebb59f3b6338a3aa091106be54e74af27d59944478e54898556725187a80e05a292d30c82447b9bebea127290c3c3777e168c9b20b95ed79f3451ea7024dff5723c3ba33ed20e29042ced342452a659b006e7a808931cf034be30981874bb615b5df28e1dc812a093a5337953a5d0886a5d27c6abb86d70498b0b42c1c187a371d32ae646481a2cf0ad4f3d358828b4e96d14457c9196f31d6c02a3535ce87d75565494c68a0517741269328c1b27ec402d475a6d15d9d80d4ceb84367c25b5492def889f733647c3ec92ee6fb6d68b1ca752f1bfa17b353b4be383bb43687a775d08a70d6af9a79e95b5a404466a3b88dca60fd9af1b04e2796ab68517f186748a01745c66c23db4ac9aef592e23507995d09644a12a53613278d081e10d71d181e3285f8143dc366a00a77c8cd2a3155593e16be0e745d9074a5c59ed7308e81f02b048806d2c210c350f7406f4dea75e11586e8ff19e2a47795d73c6c3bca60f7b9ae4c3db6a792bf1a2544bf734488d3bc444723459570d4d3b9dd5422fbdcefc7a2c421eecf28734f3196f41b89095ddf73a75c448aa392493c35af64c5d20228dbb45ce35bca17781c7c8620873e6a2cb212405e2f756905691c20018c44169b037cb6d1cc1ebe191cb528a3543874e096d7f2f5d6c7aea05cea0a405d3c687119008219baa6534a227f45af7ec4e90245b1b535290be0026ed5f3039b167ef3bdf9e3e554996e9d764db27c741fe65a88bc2e4488c123473ada883c733d962c3b04e66d7a9ddde021103016373ab032e3c0277068305709ba3c74472a6ac938ee63d37d73eceb76b9d75ec863db2d3e48c536721324b14fde8b93ff671c17872372bfb25bdf140da2e4aa29c1d3d8be01124218068b336339676a4516ac0a1469486649aa3821473c45ec1dbde4a990094ea2110c99ab1461373da5e2468a160ca4ad3a152144a04237861a2e772138ac9c0c999fd12bfc5feea02150815a004f7b6c5074ac672d985dfea69bd873ec20566ce45cf8ef86e31a33c1a7df84ae4d533aeb0a0b62c485b2446276f60e04c4797af7a696b54dabc51e9fc4938eaf98f0e9bfa6031f8ec893ba48218398d86b631e0474e25388fb8b8ee21528668428589f7da6852a2d7775093d71812ead9f8822909f1d1c71bff3f10b342a7b74f1d70303912a83f626b677fb2db907b6acc9dce78c8128de8866716f3b100bd3d18e749e3edb9e33032d440adcd70f46eabca259bfe992d725b6a71bf582458f85df33d0b2d306c56dd7936552dd85d603a16298482ae1200ea32a04c10269b39439a48108f24137808a6690fe7e516673e33ad28c4940b801cad174728a63020cfe48e5f6a1a4974e8570252882d422aa0da30622bf0e584104a1f4f4294f474af5a7ab3f9b3cc045ac888a1f14907ded21574383c8aad2d52cb04c6f33428398ce5b3f324338d6bf3a6d0d7bc9cd147273fceab9142f540534880e245f1f0ddf42e4f186062127ad1c0323f37d3c1268505075e33dade2a80043830ea59f111c63883abcd9de74a78c1ae9a3d27808491e4b7833eabccd83412372188b7c85ee3d37dcd0e4e4f2e54a98194eee1013fd2acd1c0e0db2866cfd90fbc8a1415df4555c0efa55047ff60960cc9dc1fd3f9a4c709df257a76c0819e7de2ba141d8782cc7214bc6a7c70cc9e4d8d5d8a8677ea1c01479ee8074f113bcf9dc19d510299f8877b636f11d4db75b33eeec846468d0ec513da1225c44173e26a59b24fd2a200514bf2b763a795efb5e1e32840619e5878dc063cf621aeae4c22410c84717e4cbdc3d1b2ff5b4c9e1a815880d28340855d0454b9e082820839506775e6810ad1c2dd2e317c1de3c5e8896a9689c15688c3c17cb4d83e08120f25893ca28867e0868104e0dd66aa04165a814ab186f8873360ef834c831a83f09de03c8726f3f32646f3316699ee4aed49ba28690ff759ad0a5a376083d7283c4d019e2f782702965cea3e6d0fb388a8c1851b46b5e0905044a855a4271388a53be84ce7351c460139a7f26ce60cd9cad78997896a0d0045fb09f10f5ed8509f02a154c7a887d96d012e676f25937ead5315bdf85141bc0221aef0375f0e1e26a7f1f9c8f468d66de0ee6dbd894451f0e1f4f26725e04d2a7ce655dd11dfd7792620c9f68dc50d5673c0bab1ad6677396c48991a409eb8aa2a2d9246ad5841318e0872bd47899f3a0313283a2cd095501d2436f1a8b35824095829c099e1b4655c400dbd50e05350cb03235d9d553bc473f44b7bbc6429e60fc0ca99af9ab1f0b5774bf828ba9098e8e12cdc6c1c9bcaa268bc14a62c2433b78a627e8252b54c0855cf2ab846b61224320375879be251eb63573ef5ada986d311fe5b57db3cfe51b44bbf152255f383484a8738097c22ddd0d78bc131293c6dd4941cd41d972703c0f49158d372fc0fa2f2891b94ac743594113f22121651102f0e818d4616132bbe4eaa1bba70afa318e32ebe323d81ef056fe6ba08c9550e504b51f540a3b6ae032da89afacf57dba28444ede50f8bea97cde7c5389f8635ead6b280b297ef380d47d4dcb9a9e371bad7daa04d18298b8795a778aed2c12914645cba1418888a40090bda5bd4d1d29538701e73b9807a3849d022b27cf56ffbb6deab32602456eb43511901d0571d1c4602a3566b267581c43754c2511322dd90d4c06719588673e632745c4e45564651fb9a251120be7817d458840fc68639115e8cce2d2a92f4a4a0c80079de3b00a3d8ea0bc4af39a619a17f2d3b6f4c16b3d170c1d1a1747549009207cf292f686765eeac6d43a7c4fea6800e83325a05a3010dc08032a09ca615a605cd5a403e8df0a884db5e1b6a261b60e740008a0be5991a84401124512917809a0352751b280be3c7bcea3508717ee9cb5724f7f5b6698b605a4ac75b2f2aade2194754a342bd7f0e2070319b184c8bdb7947b4b29a54c29c90406d505ec0551405285245398c2149248a14715a840852a506148134e68c2094d34d1c4114d347144134750ea61e15ccc96ef2e9b5041d29d7591b92b26bb321eee7b7e1731dc18775f7a4e720dc610ee82dce55c80dcbb731930c1c4136e6e6e6e6e6e6e6e6e6e6e6e9860828923478e1c3972e4c89123478e1c39c204134c30c144432a7952146c9e94144d54d25a6525a594927ae933aad69f52b5d3537ab1374561f3a4a4484a29a5a452a46e68fff6a6a8ec862d4d3fd1365129a57b8e774a524a2929c7a092a42fa594d2744ae9cbeabbbe6449fa0aa9949224a524eb4f0a4eaa922c6b454d586badb5d65a6badb5d65a29873ca98a9aa6ec29a19456544a8a56d79357bb9392727a29a7977392d3aaa47c4a528e41634029ad28a5945694529c4e8723c92b5e9e54432a65f69448549224499224296320a99452522929a53fdf849a21ada34b184ed124e59ca669a295c2e6494991aca497d5444dd334d13a4d524a29a594524a29a59495be94a4a7e0a5974b43c9bf3aed184c537aeaa78be14b9f8d344bb520f99423d91e9d8f6f551d0e957e92f2294952495fbbb20826a7be41094f689e96122fb726a3d93106e8337d863f89505b6390a2efdb106af61782f8b9992908298410ba6e2cddc3894195fb39f0d3eef9fd8d1f426a4173fe9c3cdb0ece757f45a47e0a4cc26ccd026a17ce39e79c73eeeece9dbb73ce39e79c733a2637c5416d2c986d36eab34d8b9fb8edca2a40c40d2dd3ef999f05397b437b3b44104fdc068439b9b6e676381d4e2c315204c80fef4012244384f0e81d2de3c412468200693c33b261430a75834ae6f6ebb8cd3751c645478eeb0e0935a339ee123773391a3a7f2e3cf2503b403f8b5a6239da690e16d11cb79f1ab93fda98d9bd5b2d3615fff6dcdc4b179d0bf14db388ab1fb489fa4ddda0360acc96923dd1a74825e24d08f5a4b8215ec30bac1f8da4341e724386d0b8216dc91257e3422aa9ce091c483ae046396e7b97a4436e48bb254b1e8d4b695dc54103977d207c257a88ae3f9af868de8fe7a388112915316251271af2a897a72858510889f857466a266f4fd9919748632bd98b4fcd1098228436437f1643cea655da05a1d1d05e29a166b57241f562752f421ae31afa68a4b404d3d03f3f7397ba41f54cd2bc2538c62bc234b4d34c7689dbff82708c67e4c3d00d69333822ee199193cd3e6e5b1aa99450e1cbe877f595e14e0886d2c50e313448b008870f223dca11a42f0c1e0d465fd8307f37c4438e456b7abd5fa25efed1a0a0600a0add35552ea899bbfeaa277ac1a63d9a9bb96b8320b725719b123f94dc5925a1b2f52248a8dc44cd2835e2354ef9c69f1bf122b75f8a34d6cfd6c9516b61b6942235a3149bb3bfc8850f5fc807804cf7374931eed249c58f71d7b9fb4fee195f7efad90d1e0de1dcb720f84e3c0483de4b207ef88f2576783deba231cacf0826936965849a359bea7790d29bcdf419765b7b7f125a7127dbc9bfd6aef8d6f5d23eb68f1f69dc98e1281a376eb3cd7381dafb3f93363159f1662b4fa61d5b6ef5f172caa586c6aa7665f4b5f6c7af3a42ad5c925b3d76ab9fceb16bed2a70a395d18d35d6cdddfd5dd2b7ab3907b528b5c76efcd7ac2b660819ad8b087afe95534f1f5eef41f12128daf642f46d5688be415440e652213846def8b3d92ce5b668e13f1b29ef02e1502ffcea5e464b97bcb21e6ebc3217b7b16b6eceb51437e19982d964a88d0816105d221081e4b646040b8c6e7bd73e8729739b6b6e5f7edfdd5a2da1f2f76d35d7b5f66e6059d6fbf3d7c9759a0e46cba4fb2a1ad49aa6e29eb29994f39df4211eb98a6b1e15f1f9ead609698c723f1b49146e0efe96a85940b0f95b16524fca166a914834820ac3ff97ad1bd2a6eff01dee358d39d7e1284ee73bae3ed79f4d35d5545b2128e6cfe0fbbbc3b8f4cec653d87c3a1d159f14289c7bb78ea6cde09c8e510e93772a3e9f0285ede79bb91a4703990b0d46574e88875578f84f1aec8bfec995c1703d5608be2634f24effcebb4ee7f2249dce77ac27b9f11b67d3bc82dfe15c8ea43d49b3b0751ceb486ea250abdfbc8ce6ab5a4fd2583312fc2cb525d735207a4a940baaa35c50fbf2bb9f6de2aeb21bb7c78af715cf178c534b881a0ceb09d4071e5af1a97585cd7deff1f48de77198eff1d09c04b9ef578c3c54655ce5fd8a91cc8ad18ad17d7dd3dedc960d4e95b1fe357fb52d46b8cc7dfe6e455b8ce018cc6c6d3c1dd7b2f174cc7fdf42d2551e8bd458646b2cf4f9e39ccf97bb9df5cd9df0dd9c8de47b7e8b111c4334e5cfa9b6e8b83e2c5834f69cfd702ad6b261fdf4a2adce8f3a28bd71f9e324d916232268e69a51d2be29b9426ef3e06a28ffeeeeee4e3bebcd3c344b4d9bd3af98f85738adfd0ad0b7c6c2e29bd36cf6b9315c577953a0d61a83c271388da2fa24384616d32fe850d9179c90db2c2cc8aeb0b61f45f51c6f18ced76f5ffb396d41d5f34f12fce61186b7bafbd9bfc9f0892beaa5bd53940e6c3d0c1600f605cbc282ac8378ea3ae356c306d9ac2de1929826259c8ac3f1a640d69acdcda6e6340fae8663b41bd23829a67749d8cc09b9d363970a8e5ce96f30fe28bebd12ba70db67c1b517d7b56faed9cc868b77deaee6542826eb6a565c9d57e1f914170aebca62b8667858f12c869bad74be35510cdf4422d7388dc3dc507cf53ec4f0fff9b4aff8339367ea4f3cd577389d197f9783ebee709b99d88c93e850cfc3a35ca86a6513b835098e51b9b8edb3b64411cdc2d4b7deadaf5fd56a75a835c7834b8263b00c035aa8b51e1a8ce884dcf6cddf6dc68dbe58e63a5f38aef7d596b82e79cbc27577b7990d17b77e5555ceccffd22e5b10e7617eaa95537db5aa97e115b5ae31af7df1cde67dceed0d829f90f04a792c18a509d37fbab3dc5b7387ed8af10bad4b826970ce229993a556c7ae7a758d3133b7955ec1bce182dfa020f882e20d8dbd7727448cfcd66618227e3f2808be41c42b838897ea00728b0356db0cfcf05d305b9bc1dd49fd52f7b394daf38faf6d6527741cebf06f49eeb478e88163f04fb3b26a700c6e14f542df7d0fff9e871a3628e5d2784e7677e75e923cfe4b9eb58c76f7318befce3d3e3b5b836970df62dcb96fefbe3d0f3db024b5247c3bdf3ab606d3e0fc1d77ecde619bb1e49c532e930ed8bc292001cefaa91ba6733cf4c031dc7bd60c25cbc962b2189bb524b79fa5679b35969285694f9f9f7e33fdf6ceb7f1a53d502ff4a5efab3de79abe5ef3a9cb7a7955f46ab7d5e0188dfaccbd37778abecb1adfd367d2b7c9c2481007f7d4d6a8df5f8363b48c3e556d07053526c6a7af2eeb728d55ed299b35d18b3f0cb5d3bf06c7709b41c0d690323a95836731fe4eddf0dc9559755b8369e8b7fcdd871a2dc9f5e670a7c76c29520f9bbbe236257a00b9d369eb10023a86fc4cc261be7b962421e4bff7ec61cccf60b8ef7d6cf17a16c219eedfdea1860b29f8144e08dfc34020bebf458f0582a215101e92f3ab35d9ca328da374f8fb7ada4c465929a9ad31176833f764348d9ff31130e7b434102044fa9c2e1b1e8d6671cefd646d688c0602a2502504bca5d198fbe7a25f7fe1c5773a285df4e77d99f297f17aa5593297e4f2f7d7d052651b01d11fe3c49210101278cddd3f660bd55d8cf703d158ef506da1b6eb2defabe1c56d76d06a8b09ef39cdacbe6faa0a897b0d05e9294a87293da55eac6f6f249372913c269c9ff346926e2408dfb78e7337fc60c7c2cc7f0ffba49174bd0de174f3a1201f7ea49592a497a0f44f82947a792f3df82736fb5413f878a25edec3307ce9b96aa97d503acd949294d59b9bf794dc2cba1b8ee11eda265d5927b9597c6c1d929bc5c08f8ce4c68fe92bb185919ef34fca2639e9f9a575df374c43fc8e658932c99975d66941d4cff70fc75aef55ffa6b5de513ad06eb3a7f4110ad25bd5b7c891400a3a9564a38de5bd24bd6b2cf4df8581318fca01c24b51e96a0bd5a6c22f497c25e9254992e27bef41e91fcff8100a4cc3c49424afd65ac3f8df451be6dc361451982d45b23b7792c6182915638dfedcdd638c14151fbbff74afb250dbcd1cfd34182db32efa4cd1e7fa1e45c97f6957ca7795e155af76554edfba6e5c78c5f8ad6c0da641464f944a1efc8f217d5c21849036c64254774d345e997be79e9dad945458a899bcdca46952233a709b122798b9190c4f510e9f73d39d77779230a98cc9ddb6652028a82c729e9303155fda295a508c263ba8f7f8a0389c5953bc4c41e9cce677b2149f99f088334e4a3d6553c43a27caa53349f9d1664e52547c6a4629677439292945cfac3f296a3ef591f3114548c553f2af784953ca9fa69593c9abb83e7f7255931d5933b9d6d5ae87e3e15094c763419caf3fbd1db28382cc068b3ad45b9d87d40bf530d566fc28f9b95cabd437b11635ada7c3a9aa897a2961aaa72f9da41587b66691928c52caf8f23db2bada4f97d4a15ce2d75a6bfd583f7e8d2f51d4736a4559d357d78d4bd1093b728c51c6a453646136cbf42ea9354bff6ceaef2549a7cbd5f751fa4849708a4f3cf184134cdd109f78e2892ef428e20f207da3f1ba9f229d5c7a14f10798ffae1ed356801e8006fd8f9ad12fb5749b5993831a74958ec625dbf5c257bbcccd1d0616733367299767301d2371ce512eee25f95ecd7bf9f22e237121433af47648d285bc1f6f87871e907e3e6eb33fff7095241d7a4024fb7e3891c6faa3f5218df5d71f6eb32aad0b792e2448103cca9e0eaefbd12c401a0ed2bbab35461be32bce1c615a24a8520b51298158451a3aacac04e91ef7cce322a8d97f4a873eeec5e39146cc18beecb3cd00d1d6a2a4b3d921f89fdb190c6aadb5d83de8c0cd9d9ece807f6324f5f12588b23860d4b19e311f44515710540eac83fbe81607f84d8647908cd005b430cf7591252d25e33699ce4f6b349a257b1be6cf5f400ff3e79c4a6e3b42e6b624b729e123c79d4c49eb62acc1b95f7bf2dd956d7ee47894f021f3ea9d2cf31160c3e77e7c7e585c9e38e8cab6359626bd0df3694c8e3fdfd352269402fcc90e080fa1a0df3c74f213c57572792eafdebbcef7d5b779348bbfdfe88b3f5e2ffddc8e2fd744c0b681105cd827b8b0550fadb80a9411f64f7fcdf23d45b09849b90eff49f7b1b918c2ddce0761dd8eadefd5776cd60f3321744978463ed7421a094a64755ac69a405b6df691a92eda302fc265b78d94dbb5ea87ff43cb999a61f0573cc435ad02ff3f9f0aa1e581baf259cbf0b8f0330e12f23c84dd011dd94af36896aeef23a43612f0b31a6ed63234ae02217ccfb583abc0ef170df32ff28346c80e22adc88d5c5d2f1af3294916086ae64432e0719590818e0b9f9180df10b27706e443e8b6077ecebb71c72dd95ac87a5e698c6d0f4c49caf9a6840c805cc7419640a25920cc38c7850f81b0b2eae9e189570cdf8a6780f087eef07df090c7c2efa159fce10e1e82d2c6c66f540d801f485d98b992841fb9c9c8cf3c190dfde02a12aefc205f669fe9124bce29b601444cb378e8853b24524a293fe31c3e34269f2f07f4d09894ff5eb894527af1f257628a431b921f705cf936e4c7d863bea7e53fb6d22c71dad62a2c65ca952eae7cdee1847766c9d1629b394786524af9376e8cf23d7cd695c08f80ccf0b987efde83d26d3aa37cdf80fba094b65518e1755f0e15d410109e0f8b4fc15cd0c658baf8dfcb8b31ce0925694ead77c0329cd6c69c36e6409056113573d72585cfb9cd7c5fa960c55330174d25a0dd8fb4b9389d72911ec2a7969a149d3cd9dec125c3255aa3b581da6f65abb1c940f5161d12da6baf3d2b03354bb98f5d38e8eeb30f6cf0b94a0377718edd4ab33f619a168e2a29db28fdf473c59449b6a5bc22f2a3b45edc25addce24b56922fdb3f315bb3408b03b5a7e42da32505f075f0dd4187f04949511445bd44491fffc67d5745bdf98d72bf6cd03b815cf9327ca28d456b0335fb4c764500c2922bbd7cc94d1611357392fefbefb9a233822a7d4b2f491b998fd0be99cc9ed6dfb8f0cafe421fe073ff6b31c29d7970425b88f4b7e800cd9f2deaf76f7e6abb9b29bf45bdb4d0b4a85dfe161d5d512e1c29959e73753ef65ba23843de8e258a56c496e83ee74d019ebe85869a4c137d29b3961d93fca9c5088e71f234726c8b8e4bff64ba974c2553fa2c9f5a90a32a4ae9377f9c74484dbd9c3c5327fdb1d90745fc93b61d1454e9853e4cb419d378b2621421f05e594bd9898874cc2cbd2910a38f9b491f3351dadf42c331e877cb8e9b49316bd171b397246dd171a56ff223fd284d1f5f92b2d61839e6fbf9dd2459fa2d34959ed07868858d3ca1b972854d269d9a9a9a9a1acecccccccc4c75918b5c34801722e0194953777c7cf8305ac232353535353535333533333333333cc4c6880889e5aa9a9a9a9a1a6a6666666666e6f653021420043e34242ce346a3d16806fb9a0fd3f00ef6c13f3808ada9a9a9a9995ec09859912f6a86d8ec70231f30ecfff391486a1b7d6cea14dde8b991bb917323189493a8314070fbdf8e95ae2fba9b8d8dac36fb5c9bfd7d3617bb9235a4f28c4182960f346f6c48e56f1b03d0b621813b9d50260140980968b735e62e842dcaf85ae5db283ec27c406d3e6842c99d964a77c7185d62b42ced0d5176848e07ee4fb2ee9e491b5d0fa20d0c7364c9fa464fc63ff5e56499e5f359b7f80cc6cf2694cf2ad0671d9689432a9fad8031bfcdf9838704f04ee553c8f02b04305f86f92a327a3afab9527eba54fc7c8e88c6f2b129b6858d1665b2208b83062a3e037f009489360825756a06dfe925221a4b8af52d3e7318889fb90da07ce63c00facc8540c5678e04d79de0e326be376a9da69f2ceba50c774cbd408ac60dc6e162fdb3f8782a952952bac6ac9f103617110505e541afc3e751a6b7acf930d3d7f77cc4777af779eb678c1405e99b29f19372518c4e6b4e69413f9f291d3e3fcdcb4793cda648290628e532a9197c639a734e13c7345d2b8d4df6456bf341576b18cad51a162f21176b71b586cdcff5a261f309307fb2fe73bd686c7e0d8d4d39df7d1371389ceb009dd39c2f512ed3b4de5dcb6615b82957c637c5422162fed0e25b6bd1e2ad0bc5ae3466d9178db9e6e837258e9871998b226da459b227baeedd0f2d56c8889a25e59da731e95b5c323d54be5e317c3f9646cad5ee0f1e9229dcafb0fe51a162a7cfc50db3bec5e51a363f5e92366c3ee8aacdd3b0f92ad7a7a9cc9f939bb35c2c1a1dcd2245facd52cd20e16d9ad694f38539ea66645a303c532e00781b3806cabb4f408331bd7b1c1a4b0b158f0c1ee9f17c0b1429838a65bd4789e1a700fce84e3fad8a6118f66288e1b100b468f1d6a3705a0b394d930eff93b5acbf50527e461ecdd2e2dd471f1d5279f7d295a05cbee4477710246a9e8572f1fd9f19307117f8c169c0adc0044ec659c0c9a0bc94b5a27cf6b90108c0a3e07819191c4548cb7ef6463afc4f3b04cfb0fe7af727ff9c68162983e38d3ca51dca5bef7e76502c75446d71b912da6408a908e03389e561a1614e00f66da1a9b87716043432400dcca8d827ae7323a6a15da1cde03e73a3f9eeff4e18a0ee041cd27aea889abdb030d65f0fe34b1a732526b43d254b50be67d0588acf7a880c0524304a99f12e8afd01e59db4e255fc9ca8e8f3441f14fb464f0402bd7ca23782e1edf5e27adbf2c20b6ff496340b0ceffe39212f8bca0286cbe128a231f74ebd911c0d19f24600b04ee68dda1099c78525ee8d9e92b70407fff9f585ac82aeccadb8328f0ae764dcc5414faeece3de7309115f78c885ec70ec0c628b6e41427be75417a548455252d984eaedea1557f16f33786cca91ea98a8fddc2f98fc18f6ff7136a81e95bff9f5e03b296bbbcdc6caed7fecf2ba4889b2a738bed1ed88fce8eeeee607610014d366e08f4083d111e0d6ce3e16d0d80e3c94580734e6a26baab3a35af6d118cf80060f6a86d5829ab525cca3886699be35cbc441d3cf39ae83acc38766a136684cb354efdeebca9da2d48707f2dfa1dd1da695f7ce1feb900d4bdc248900ff902e305b4ae63f9cb68e890087ac95dbb025687c01967beaabe9ae1d748ab29ec6bacdd02fd0b8cd64ad9f7f2c6b352b0e2184f046d4389cb86e99478d7910ffe93d2ac3df5730ecfff3a93693143bee1aea06954bb9406bb1a0ba7f1285f03b0890c626db588905a8f1dd3315ab950bbfa270388901126270a185711f5bc6f0ca60a6a3b451314e245e1a8918ee208d79a3acd066f0a64fa8ee9f731312fed006bea0f83092bdc1bd12ca853ea1f2c307d2403a48b348db4a1a43a243bde4c5ca0a86fd03a9d5ff8d44b57f5ced2e105b7abb08f8d23a6351e7701dde3caebf6f3f98d131e3c5a38cb2139964e771d949cd23d7c3b26c8f2822d55fd42c6cf36ca443aeb988045c4a776f4b7ae4a3e9de1e7a4793dcd0e8508f3a8663746b79f7cfb53da28450658faefb0f18424089aa7b970f01be1c222a7f164351548a48c5e6f9d9a1be23a549fd549bc9682d931d1e1f52462ace3fb96ad6f2a2d24e4fc9e770389c20379e58e92ef5263b24db1aa332cf0f8ef4140a0ef529ac6706377e9d23a8e4edf6944109d50c0000144314000028100c07c4628148301a0807de3714000d90a6526c589ba84990c2904186180388010200000000006044a09220008333aea2f94acbad547f4ff44499a8e529fed56a0decfcebd4d08ee32ba130f7114556f7c90187d7fff8bfce2776aa0da5776c8ae4207ba29901b475cf72c003e223734a38768b89179cd95318b709d9a2b8ab48959e6109c21c3cda873e9afd574afe5513efdf477ce837cd43679948dcaf7f2fb8e96f28c82109e966c4477cec64c5e1f1498aa61366ad805b65c39de71a75bd05bc25cd0aebf7c49f988992139e79184b239b447e16e600a91c2655bcf96c0b117f4fd230aeb995778668ba59dc9fc0d6004acd381930d0f3d5e9aadea371f356e7ce638552f40a604167013c58ebe5abc512b0a06dcaf63768eefd8709c3bd3aba25e52fb51a8c778c09cd3fd29ce1dcb2fd40f25dafcd994d9a3ddad40dcc7cfd33b1133b51d89b7def6d9582d4dcb1cd46c7c9c62d64f4d538306d99fdf649259cf4e4c02f81fc4efd71c768716de75a13c71f660a3872dbc0e3b139465a5b3811a1999cb58c70333a0e460cc591b99c758321f4496ae8f35ff0cc7852882ddc990d5e5aa8b03f5239626ea33444c0175295d574c535a492fed009f8662e533eab30093767d93ece17cc44e9b9d62c9fdaca7122f6d94922263f6ad330da76d7c5b3189b364716cfdfb8ee452464748587cf858a61d84c1df372dc4e9a9cec6e4a5a55c2c9383e500e8fbd8fcf1dcee641e046916f7660c85feb51768e313a4c9d334560574f66f29db57bc5dbd93ef6ce4e2c43b76d42684fcb7874aec75891958827ba04d9f15d99957b0086473706485f392757699b1682c8b3e2b335752925fe49d49ce508272dfac60b44201cfffeb708d559fcdc8bd791cac53df876021690dda7945095f79c2daa06c5342fd91bce127d2f9cbc83e7d156b78bae157237832ea046df55306ed9dc2525fc91f724cbcaf3a219df19a46480f1c8f9c04f042c8b1892b3aacf74acce6fcefae7f721065b5cb38bdeb3d693964f1e8130d40b0cf5bc1b68da1eec3e5628502d1d480d4c4a40f8af8e792d7096c86d1826870d95931f398488481ec0d98965658fdf727fc3599c862fa253d271f63a8560933641a3a5d78b53ce0aced643d21f00909118d6411552f51397e36205ea688007a9f956f761d1bbbcbdb3807370700a033a9c65af41d4d93cec444dc6c079f4b0a0c12f12c84c0ec019726657398af543b525dab04a21a2abe735d99b1223209ed2b8f63fd57e282e974479bff2cb67abdb6a299eb9dd390faf08eea9be68812786aa3523edd1a26b7b7a5524739dfe73839dd698a8bee80877b9ed0787be0f3fda6a0984cf80c858be780a3419861551a8498942c0a194a069c8d63d75b84e43a8d14a98d93a46161f144367c0fe82f3fa5475a8804263f7443cc50e9b319399979b9eab71d4ff637f3a74365bd8b23adf0575a196ce0fea3d59f6385ae46a8bac70368a43da1d211dc2fe441cc4cda0304923fc6e4c9bf18986716481ccaf964393b76e0796aa8d9c4bac406c0ec574dd1a576724186b79c09015ccc9d2ca26fc470ff87f85f8acc50c948496fff54369a48e59a68948af58220c0122a949d44c245ee162d452d1955accff33ef3bba3021b3fb149f9305cca064c071764a4e610f31171ab353fc429d9e09bcc8403b33433511929a97782e45fd42fdfdc46674f275a81c5261ec74ee1c0a09a2916690dfc40d7879f4a0c7d8b46edfb322d21b66c3529634383e100119d9b0ec484fc3ec588470d107a277f65d7517065a904460e1317743044d157694b91c8f5f06ee9242ea89c3575ab0f1f3e013fbd9b08211c4439a723806f5ff14dfc2722110c8c42c6afc89a29828eba3d347a22d509884b29d070cdf64004758d2c6ea58880965840d620b89cf508471819e58b8111e0c4b7b1af1f916bda5a1d26134e7c65bc1d778d3a16a10bef8b060e5df9a708f88ff2def22be22e97bd66258f4fcb7063e6677fe5bc592f7744f73d5961ffb2901ed713ff5a6ab777df0f8b70e8f411ee803dfdc5bf39d66b8140a97ce6164704f5bba5200194b348e69017fd91adb3da77487d0754742b125ab69b3bd35510871768c087b022374301f0c23532758e33ae7b9a1bab8fb073814ef1a2d0843bfd08bd5250ed3d90f1e815a7291668867501e47d1a134e5bf13cb5281105454a309d9871eda1e846eec61b39f594f182d89aac7e17acc73341d5698848f8aba00cc8d56cabf61f55232247f3d057d5b37f160610d56db5c47621f52e84970d058a60fb5150ecadd2d88da39f6a02118380755003c7510591a3fd96c250b38fcaa2ee955ece958242e199413ce41f4e21d60119665f1c8c685a0cf4c7294bc22db377a8f12d48e9d74c267e8a17a7b926be822c039a8c8c8fdb7350c2a24d27a0e12eb4e7264273e3b8715df244c9f0d70e81a0075810e62bf5729cdb9b21af8c68d5ddcd46e97b51229ce095af77607123f5b6ad742f58f44129a42125ee4e450f56650a491e2de5e02b49352b550851df15d973983fa1b71340bd9fb8c91902c63fa59d5d2d00b8482390a397e9252f3446d41831816eac11d5d8580c40cbafaf2976a06090500ebebf81c05831b0fb3d67a5bbffcde00d91af3e07693f08513fa00643e5c8fd85e990bdaa727dc09acbd36a754a95c3210ae4fa9b3473845539786bb8f08a230fc88658b445851b809f7b416d2b8565484f51489ee287d4bf749c2389ddc4e70be05911dc1d481e2494589016fb17170a5431420c0efec4ba11828224d06cd1a4a80ae9ca42d158631a8048ce85ba99bcd449e06144c0cc5499814b8336b812cac9f2cfc10a0890793277695fce859b87773f8d9b06a849d4e2773a36998910136f1bae2c2faa082e5333e121ee427f912bec4f28301f517ace6ba8d706fd6b6c227e546a56322e557325a78151cf48be8764d836a51e1e5b078a9b28b1536e13b03e414ab8cb6088270e362bb1c2a144405875d43e06f339d51b1e33e97a180c8032b9c0156b30c7cbfd77c28286edf4784070fcabcf45050d75ce4d15437426f589d953ae497aaf2eb4b5089ed932808119eb35b0327b8919cd0aba8446cb040b8c8d04576e9d701fa1840255b0ce2ffbb21624ada601316430a56211049a220d6d80270e7c03de695cde02d7d7c93e01267a2a0e8e1e803a8950701db9b5f4f3d92551d18286247daabab38e3cc691923ca6f1ae9fabed2894f29f208910a26e3cbb2b2a1461ab799fc008a82e414fc4d275d3fc9136aa347e1c7741eef4afc5dcf1af5740f2e4f3114853034d94f6e67d201cd851e91f39282945e515ebd7f2a292874ddfe69454e9c6621181719f1deed4ae019e39472ec7446a72deb127c70e1cbbf88476ace1aff4593cf366cd17626d625372360411571e6ce1116645f9142c84da3b539b7d209079e4f04198c7d756cb4aba60889cc3f6f8ae3abc3f7e0503ad1ab770ed7327c8bf9f2b86d9a821d6c7c12ce95ad734830ee2a4e30d3a0bb8a0e2cfc2a9cea519246e896909ff2fe34fb219950fd8ae804de66d53ec1a29f77828171ee8c21f92c921686cc3dbf64334d4e70080a23eba66fd95a7fcdfd8194b248467c4fe1ddab8fe3ee320bbb9dcfb393d436ff4235477c0aa2288b7ad9364dc3bb17c49282c244a8efbbed788856866ebccc9badf5ec4c7c8107adb5bdf8826fdc1eb13acb0e49306231f71cd78eb9d480278f759a73e2c429749cf3637fbf788e8adaaef3533ac9a93e577d23f8eeb70d229170c3f056f05bc213d663fd1731be5d7e0a377dd1343c668a52e38ab7d178895c6207690e12a125608c1b40001dfff44a84773829006c33e4483b770c1eb87d8ed2928088c10024fc2a54423ace9da27a7b665a38d93d5ccefce6484379ed11d0fae8c4ebe870d98f5f26a6c12f953e9334b56ed5d5419dc815e1337c93b7ca92136174a056b45bbc6a3558b771e605b9e5f135eafa23f580c40033f2c123a192153a54cf74df39f882ab163e82060321bd304f204b75d3cb1dd353b9576b8735358db5590b31e0681c92f8176d7259ed40059055188ebfc6602505143264b9a615ec45c8283f7b055f82108b8b660f721d66ad8f03b760b02f30753de677f2d097bbc61cee64da0d7a0ec375e27c04e8df0ee288c6e45bc03703af940c2c2cfde45aee45a9b8a4be060aedbc097f293c6df35e92574eb2b0831320be476c6937141791fc79f709b8d3e0b6121b044e617fc5c84f1149db810fe0fa7e7cd3a80ce79441fc3e2008817532cdf61b46da524212dafc95c1ba86b9340f5e50e0cb16e3cb3c8c987b46a2780382a8968c3c061f9d40082622cec3aa8171f85be8c1fdc4303ea3fab41e8e593a02bc77e685f86b00452cee656933479839df34120b5aa485c9c1f6db9925367c5ce8ac6e80fe248ed494e046b0636199cf3e2793353fd7d6a246023f2fd70b12c39bf24304232b36bea1b26b38ebf7b9b34d20e38fb95cfad931908e16c5560a0a6f2a2300b8113cf4fa59d2cd35dac9a4d8d9ed82cae97a2a5f9ed2386576bf47436e2c10a6e5a1237e345962e78833ffbc46ee5278fa3cbc545cd07bcbb195c487dcd98b6d437c83125c4b588d6da3d61cafe77fd0476e89414ca952ba776ab3eccfb293b29b2227a281a19ad839243e2f1f161c882a56c8ead0cc02448070a21f71124dd51ccfff20007b37436d2d49215ffd2c63321e913ce22dd40f3a1b229409d35f60dad7b4ef0c71624ab7409de16716fafd8d00398442c01cc578b275c47c5d741555ba51cf73819a1ca22bec14b740fca7eaba5d19a98da3fc8a6ef7e02ab7aca94120ce46e276648a2b57eb620bcacb7cdc35107c14f9443d082455db9e53e1be6c15bfdf14a8576de1365548a30a44d76c9b0847d459686e9313c5c961da0b63ad4cd471bb55b265c7fe7f2cadec019c0bfc1201e35f6f7ed6ba94f0363d9490f33b9804a65d1d8e356837af725ff84212bfb793eb45aa3c6bca868e2fdf7b1f5734d55cd0c7ad63943ed1b9d908f394f66bb81bb9c1897b50463b1f2fdcad7dd2ebd6e71c3249dba905aa25d58220237edc3a111b2da593acb325a301276e4253d6c73d4ff86ea819e3f715414ce9f7360308635a3ba44ca1310df51ffc6bf56c0aa0ad36cb31eaf1788a4c935101f596b10f431c1fe9f0f8ce8043ba12b250923bbfecb39735ace0b8aec12513ff8caa2fa82c1e5209fbea3839b56123a21300129d403097200c720f2dcf2ee62c4a415c8e121950d9d445dd0d36a8a239d3f02ee654686ca93bb5fb8076905badf8612662a8c9075f219439ea0db6866dde4a9390fa5824a7f95676061f5a303eab01bee75bb91d5f0d988559238bd976caacf827b4815741ef04a5ff2c6b1397e4f448b7a8b5c8eefe083ec0f800d9646066037fc0f3246e7b71de2bb1d9c7db7219035a50db83e6f76a5e325da2cc5c206868a08a9a9632de0c75981d1468dc370f8fe5473abea38bb71ed3e581699fd0c2313358f9dea7bbffa187989363a21fa2cf03be630be41bbdb81f044206c91488375aa530847815ad956e4299b298ce03b7fb7bed9b4217b25f0e4a5da9b0d2c2158348e5a9b4611a4047009c461e392d82981f9abd0fa0ab83671e9e117f3af7f8f2f5f9588ecd2e7c4a30ecdf1db5ae1f602bf2ae594f5d14ad3ac437c4cbfe7a1785e2c832da9da2ca4422693c5fd0bdb98e81d55abce672e0ec7d031d57cf59b36750e54b13f04af5b0c716375097fb764eba298b9d365737a291b36ec210b270fbabbb24c12b82919075f484c9f78c84657b967ceb972e11a60225df015d119ebb5638ef9e31e03108c4786159241f47299f1abe2263d7cd8dc2208c0a8d6f5c0c6b0e2ad217b89cae7069a8a3b6a369d5e0eb48b23c26db67ea92825fe0c704d181fb16fb32f4e0a6de359f409888d8087036d99d0c7f4804b6e35a62073332266613f0ea14ed2a341ed6fdb7f715e127b8596b26e7b15ef6822a60b9feba9e7c03498ba92f3c8cc8f699ee270a1b3f41d7c43fc9c13a6d2124d30771394bb7f89f6dbb8b029c6704b5f10f89f8acb56fcfbb25f45302e0188e153259fd42b4417522476332485cfc0bcb06888f0f7a2dae1fd91c4a231d20383ece020402a82d69a5c25a93f66c0da1e23e01d454b34e3f8117d70443e6685309bc14a634f93bc2959d7ce2974c49e696fa7e3a4b2a1985c8f15dd5d39451307e7c5158359f7c188d6e8237cd15e9e05af38eaad5366862e71e78c8a042e06795a8f2eb75933658d53734131cda3c2a03d61567081db858fcebe7fb405050b02d4b1937118ce927003e9721e00ef4887bc87e529f2efcb93f8079ad5218f377a40fb4371df859999d87ee47e078acc9cb78df83321f45990e2b7e03e0791426f8c0180996b68f615c773ac3c545c334ea3060520a5be11d0686544086ec366fe5bb7ec88d5a1f76d171d09b4fb658d26b11caf41384dea44da68c6af142ea9d7300d062b4bae11649b80f3dd1439bf419e91f361eda1cfdd58c0c68e580e4dd507d1170794f3fc1bd5ee0f86501cd20c4dae49d5a32fb29905259996f6857ae0672df5c3d593a46c522faf89f02794bb72a6854d17a36717af0922da81d231ba8e82c83e84b959eb166a7108c40d1ca5b98dc36a31d8a94833fe32ccc212e1780e8d927b4fb13546603231ac98d456a3a5c78333aa8bb8412f4f1cff89c7459af1d1222099ededf7793c2129de7a43452461772e9acd8a810bac90861c51d08c82a648659f71382bbd5f8e141225687a93466daa4cddea301e82c38ea97d8e3f9a36121b5a169530be1e019d3fd0416d5861c5e5ecdfa7f084377c1cc5feef0c57e92835b55c092f06906b94d2092e2833b38e99aa8c6e2a2598210a2ad31ddbfec22b6b96276ff4ba2bfa7fee117953b0dcdf913d87348348545ac35018c7bc685497a33f95bfd0ab8a457ca292eaf4531afb01c059f06c2d58b5856c76a2d2ce6c7142d9b5d3376fd30cd98c3784d6f6b5d3386bfabcc6f02b4177735bf4a6a9859609aafde6117bb5c70b2fdab0b0324e5acd0e7aaa4f5528686014b6ca6e6eb62227f22133502d261087ee017e69a04c11ab536f0aebf5b9508a34d384d6ad08e94e322f0a60e16f4e3a6044dac26dc1ad05c1221904ab40cb21240c467213e8f7f6fb9658e543d9f790137f600197d9a4fb279df5985a2bd42dc21492c8ea9bdf61e01f246ba2413040ee2112ccef879af48dc2cdaee23dac4b3841cee3a14e28a940f67e6ee83bd9dee9e8f3522b2de17d1f807813a321ea6530b8cb4c54461970e8beb8c8d9b38a92dfd582a523a479864cf43cabd6fa6ec8f440c286175cebb93f42cbaeca2857639b71cd8df1c78e32292340045512328bf148db619d754c300488c067a54299493583be16e161a87154a4fdc47a42d1f7e216714444e50f0afd8be398efe21b1c29f12d99372eac04e35ae653d7e560f41e6f2cd51b8d650f78f1c34864fe3ef7fb60fc12ac4143648c0441c078bd703d0c371c877f256f7b7c5b1f94c3687fa5a3a1736a12e13d6e4d558fe213a791a12da86feca102b43d33047b02814a5d18d018b4eef192ae5b56371608e475086af08cd27a53b36b8a06b18e5189172328967faea839b3ab10ad5ef150a978d2154af5c8fecfd4283f85a4d9acb8db7c21fab6fd1e8fb87dc117d3aefe3e8b29099d1f79cd070235fbe2ed2b771c94e0943fb5644d5f6dce96aea79662e11013cbb5d50c2d36f6fa2a84c6a1304f3164b9f099e57b6e583474cae40c465f561ae2830ac1708bea0b4eb12bb57375cf4f605d8533bfff7c23e10327185a603b31550ce49a90c032c01755e01e69de002f8dbaca4c881651e6b130d8ee4be4ea74348d32b2e884a2b1d6e0b0f91c3c443c7fe5e2856335a1ac0915dbf5a8b88e53c02316603a06362929b1c22d917428d6d91ca49c14c050b4141c8b531790185c4dd5758e5638b98a3365553bb422fe13695e37aaeb6e5befb2438562f6e79c7569b80c5f670d8f2f108e129718cb94c7e32f1f6e58568dc44a7f1c1b08f19753f4fc6f1fdca0e21431eeef26ded408019cb2d67884b0e9c01d1e1d7af1e8c6e713ebb54e085fb801227462e53d2d68e2448850893a6b7437cbdce687bb4544eeaaadd63ff175fd6ac280f12b25f6b12878fcda87cdbd4a2503dc4616c02b8548bb629439e7452bd590a177809e7a9d4fb4425b1eae7c655dff456df28a9bc89d4485438d8141f1ad7b9c4015b1bcbf6e461a8bdfae55289a601d9e8878c802bc464bd72d960d172d199dcac3438d4517fe163c01c11670517664ced1922301ae429742e5ff3eb6ee854c0e17e45b7d469d0ca9134bbe5ac9a60ad000546f8c4c0edf3953c15c4564d6103fef41533052b6ba4a192c32b2a0b41068d05790f0e27247bfaa83d39ebde71ac4b34a23cca500d08ad3d9c5d8c07792ac03ba6f3562e4ffe469e0853e4ea28faed4127359f7faa9cd4d06446a23d10b2749ef80d27c38b0dde0f6e36a0a2a4542f5cc29535ae2e24759788d2abb27a80975fad80679edfaf563dddcc20a8306314738d24b3299fa1338a6d6ad7a94c71757d7511d9954387c5bd880a34019311af782204d5130b2423710bc712339178de0f5f801183cb4c95a428e5378e265ccc1243d7a60874f9b85eed7caba761cfed13625d035f718cbdd9bf5d743fb3d87b3aba82771638ac825b34c4706b9d114700d8de090bf5f2cb8615b355217f48501a9ec96aad68f4c6e7a9aeaede0311e973c33682638102436816f34ed021d10d99e199b3b8f857005f8730cb4a1bae7c5fd5926c76bbd32f9e7650a706f006afd6f04d6a4d8fd0cc90806b2ffbdc23a8e695854b2cc7624d3ba20d6ee1132d5444f13f48b0bb35b5809267fe16e6c75f13da72e40bb0f17d53b8d0b2cfca53b07939c0b07e36ad1560d93800873a40807a64a50b6df3996657f03a3857fe5650528b71938383f7372ae6b4c2f29f8c5242401ab18515b95306f6975e50071ebd21e2a3c207d4afea62eecac2a2086cb6fe9fdb880e47a168118cb103d59950fe1459033862716a114a7a372166c91d077c97e220522082013f9194c34c663729bee629b285367d6e98b85e0ca0c26a40ec88178769ab1f0670d68612d923d6a8ecc747c500bd75b304953b8ab20a1a9c73711e4e0625280cce579b9614e5cabbf3bcdefdc1b4c8d784cb63b1eefd81ee7766fffed751845e7cbef3cb09bccc59a01f0da25274f0abe3f33ee881e0f5610d9acfe085d4f772dfc73699a2ca5f0285b07c8775c9d576e459cc8663d19d598f6f8dfeea4f2ea3a2f9fcb8b95959a59ed29ebded56af758d348c2303f566a1348c42733f113ac0f8949edc25a5d50b7acc7b5cb6a373fbcc6c419b825c12c9dfa637f2d12b61547ca83ef82d898f4c0f5faa02697a175d6c9850db273246fa6afaa01186b84339e49b0ee58457a5167f0df84325614f3dccb78492fded8cbc5462cafa84db2f86791b2a5eec6898f391226b203d9ffd06989efcf9327de4f9a8d94a8c626477c777219c94a1df55dd5ba3bea8601088ffb4f89b503c7b40866595d4cf201e950a046f47574e1b7d11c287ffa9e6a8009688309ec110bf4ae95a9e5d93962e5ad7d08878a3718bf3b0d7775f5718ac0abebb17033805f57a2f31bca8115a9097dffe510b0502142fd3e6825ef669737908ba8e2528aafaa607f51a4014a71be4ae6c2d5eaedaff2ff39bfc21a5e06ace6b4547bcefa83df1f2b098c6e6defd4207eddd1de3469165f46ba5bc47f9e5b0fd98c87507c90a751ad9805bcc8f7abb078c81c758545488b62f0d5b00d86f4d819391af48cba1bd1b11e168e3bcf5bb41e1ed9997be9eebbc940d894f18b4b295c282ac2fccea65f045f817d834bcbe2b674aa827744945b14483459c8477a8c27e96acef827dd0fbb7f98caf3f6667ef366bc0a3f3fee916d744a1b2f49c37519ca5a3cef8690f18453f31912a6df75acb90c0a4b43d2edce5687e61c9590857b12c1b42029e0351b8c7baad8ba4e20e3e06524c9cb069e9dd0ae5b99f83fd5386b0909ded53ef44a2aef64afa8e27e2b73e4f87c0a89657932252a6069c7d17c1026490952628a67276015175a75a01311ec3c866a25e0b7dafccda38cbd6bc2fa09ecdd8d6f1e13277719971b65620186ec586dd064600dffeea7edef10e3dc017c96e8507e11cc47080063a6099005a960719acfa34cd73c10dc32257b76b0dd46bd76e46b2fb7d31d4930e0221e4ee63ba21366502f64a607d27dfdc556397ecd8acbaca96a82568d04d38fba0322c6d79e4a7d300d579ea8f816f7e1886b6d99e7c51453bbfdf27f334bb6ac3fc3aab8237bf3ddbd9c49f252a88e905abda70cd4ec0378c8cb48c0b74589423e7671a88d956d198ec3571312a7b372217af74cbded46ce0446a8407ea66792305b73eb2aa87ab6dd5d2e217b76d1be808ff1e31ef6fa226868c52f1e1459bd106cba4d8b02948faab8cf7d9d58faca65cbc657e5123ac235958b24717f6573d61c723e9e65b8e5c686c70f227511aa42876a570183af588b7e5135505307c55990e36bd5ee8f049a07b544ee483d1c1d682be80466dd1d71b65e70f241ea4e95f0dea3613f2619b099362f4e3772e44b7be2231e29acb961d0d7bbd604fe7cbf5be06a72e7ec19a25a5b47ac060a7c0ddceef421b2227cff13a0a1b3fd2df88a0c005e116127c2ce6e2294e7568078fae3a38469a0e9a44783cc72ca8f89b3118840f34f88c60206810ea7464b5bf33b30e4f385bfc29795371cd53d0da598a2192f09bc9dec88e8a552dbdc3daa92c148e6053192e4ea6012a5ef123537db3b369848f473ad33ea81dd88733f120c4ab5019f9e3b04ee79059c05bdc390df67bd312d01b55f95aa40303551c171e365662f05dc7b9e63e92b5ac72fd44cbd325881b6c930ad2735e912302b199b1c67b5d789f107bc58c2d98e225fe13f27f1403570e847fd2a98f94f95f8521a60dff09fcaf022303ad8895e06866f0e19b2f12a4fd599534b93fd959ed383d73123d213c29e2455f4a3ae42064a8261c121d38f00f6ae6b58ee984903c9654db5bd72484a70a38b06dcb7bdbb084986bc41d416c1e96cfe44719f25c2db3f2ced7fefcff45744060b7c66d7ced31ecbdebe31839d51a4178d8ceda6a3702192031a24cb3b7b4007ded0edd440d0c2658cd7e4203c2c35f78fef68dbeb0172cd19167868d83b7d6e8481b0790967d9a312a9fb333cfe5fab1b5aeedfe06479cffada79adb5f02e23232e26f033de5f2db7aefecb7fd45731fb222e995a3dd1a2de22df0078f80c50bf4b0dff44d237fb774fd082cf044817e4d989a2a4e587c154f38d419c585b2acae3756be6846dd51413a680608adeb827f044bc399a5dcae5047da21c4daf1bb5d9030cbd599a60f6cea557f909f082061c4357ae1f7fcb42d7ef0c88b931d06484a74d8c655e183882e6d79d9a4c86561e0adeebb721ce4b6c37a79cab021e293e50b8ea3042e4420303f9241fa63cd7987cdab28ffa233c834cd32369c70bf60ad01004329862e621090daf40dfaad21948487e86be43f35f5d49a000de4cf16a7b6c7dba329f4b9f2cc6b725b6c9b391ffd3c1da29e5b412148c7eec6fc74e282303c1aaf7307740a7a8cb68965b4a1ff19029582560d6d6cf7e2657d8a79a922ad763316ebfb7eaf4bbedf10bd18d1a4ddbca6871682f8e39ddc37e8d30f11fb14e4dbaa1584698a19c62bb4128232b283b83251e0b4daa6848a127d578e5fcda00546ed9ac08520f7b51284b4142789b4f29b8082a038beeab4b908a2346df0a9e21fdc5cf12db33a81365942d5fa61238b41bae7fd52173e816cdd3b004af3c906ae48afee222f180fc0d815a5363fab28423b76d4971d08cf08b0f243785e063d3d5cc3b0b410aa208f14b9f392d1237b52b86bd61b10a20bf5f81207bc17637a880e25f6137fbb7541948354b5f03ec127347026478b57f7057d078d39f9743860cb3fdd92233325caa7d639b5bacc3da08cf90d288deb817df9cabfa5a6aba4fa6111eeea48eea3ae1b14087d400ec764323fdb7f4baf66f8d5339a9f15d6d009677a160116db8ef2856896d775170bad5952f31fb620608f76c375ad4f271062e67d4737512bb93d6a360f939cf16d6d876a855a3f9fb67d7464b2ac5255375e50f56c120370dae06c24b66b6d3b75d64a8128e0e377f7b0335f0228b73a003f4d7214299880654283f74bf7721e245f5fc0154f30ed1ed96096523ef37417c30542cc6d84fb60d8e7ef44da5ec10b9781788ae24e20e9edc73a444d9cc9acd1952fde4275cc3d08f25243a2b29188e618ddd84d9b0f47b899538cc608f4547e40803e1e5933fa5a78602acba840298e9f2abd216c928c9575f106b5bf9042bf7c6e6975508e900f584df383958321f7048269f8de70db7ec0473c8af8a662a1f144393ebce27468db8df66e4b4c178232bb83e090579cb8ae84326c5663237c892205a1f784836d9a273a1aa62c64458c2222b403f4fe6dc8fe30c811ec06c3d69dff9a6f6949e56ba06412dfa664402e633669563e20ba3dea362ccc032fb2cd5e6f1bddfecb7b8f885cfc136b8c85f95126843e4ac5b0ed00ba1ed10e5060676879093f3ee57c21bb0064e0d2aec3553c29b11800053dbba2b2e1466e05d09ad1907a9d588557497635df944a4192ac3479f562ef44a10ec00b345f3a7a1b4bacef885dbc37294038e5ec50ebfbadcbaecd7841ad93d4d4e0fe5f0a684a240e169f78049228d975c79eb201a5f9ccea94a1f21fb8989e50e45549518cb1b0d239e7672553227f6ba8ae9efe60d02eba0708f203b75612c3a19220b9856b3b050b500ee1a67c9e52487d021bb5037c00918227359e94e1de64296b7d686079b5d02ae4168a98644676602b1387d042d9aaeaf9d154cbefb844a28ded0d6ec87ea6fc97bb26255768a627beea34b87637b2cf520863b572fe666e65d386c5901800dd272b6d0cf973e25b5c5810689ac139b69c02bd5ab7251672bd001589dc8e0b9452f894121024cdfdd8714f13928713ebed2daf6fdd63f7c74113e2cf691db9614f9a192ca7ee7a93f7c704032ddaf8b5646cc376a33d1570505e58a69c6f3448581105ba07671795f0c0ba88ccaf92d73b46d40de0398456f417aabf8a059125ffe43647e777d10b575161aaf115570812065abb097984e8575d2fc9bc88da0ab29d295f6f00a8c5c96957e5f0e537b9814b6ca9ec80ae32d7a6d33b8f5421ee7d427e578977bc7b5c29881ec4812d6239c4eaaa4b31ef1879fffceeeed8de3e22cef7a83ac44f2fe9d1c2613a73e913e6f712b90364927b50edd0c43118733b2a58a6410e9bb9246a9f40904f6e49834eeed20741ee5e767a127449a074f53c1494655888150ed1777e0a32c7f4153820dde82daccea473434a02a690f0696ec45fcc0e098028dc707d32b30ba451060582b8c2eb1203d27172096ef7247f1c33bb1ed4c22cb7c373be236ae689effffb1309f8270da6df34661e7589f3ae96a8f0506d7a9686296deccaf34f1cea8be34550b53b74ddce0cd4b889b80313a288fa07cceccaa06e40f3988f5f2015163e75f7e67ec52b8eb608f94abf7a833eb2210ee3be02b5973224128ecfcad242fc4e51dc8938cfd2452b8b520f9ea6b508c5c0da7508a13a925c49f52495b9234a601a9ab0e06859e9e96706b7d758879547cfdc34393b8248b2e6eadaa77840f26470cc8edcf04ea3cc70b1dd4067d8fd7bb8b5cf466de41bcfa51a5c97ebad6cac3bcef04c1bd304933494d0841be61739a4476534878d29a2a1aa926dbba8bf782dcebf733d956fbcdf7242da1274ea9b7e6fa91fb88285c35e0517b854776d368902972a0cce6ffeaecfa3e97e7b8c7ced054856838bcaeae9cc766f831a0fe26ff4641f1a67e026ca72ea105f0d444dbe0d2779ade275214259d4a39c697862e308fe01306a87d12754a97e25e2b91e53c6b71c02a0c5b4cc6a2068a790a18257721c57565985402041f93fced48bb3d4fd6adc2688aa1646249407eb40c2b554b3a33b73059013cd48056108645f81f8a04e8fc6bf347e5d9de1b8483a8503db140c7798d4fb3240becef75083bf03f822d457862492ec0875acb1faa4805ca47e5dc7057a66ace656688a1ade4cf66e044938f72b24a8990892045de82883f916c3fea91a314d1355ea40df85cc8c9144f3986699df62d62d8e049a01471b896b23f822d399a825c047248e7d64e32a80583f2e0b201c4417fcf55ca63009b33c53b9ba143cce9cc1a8b4bf4ec65493554d02bf64917003ef094906f06b3b8a1af1106fed03e38a16fd99ee99baaefc6bd1c451ac2930bbe99bf9cd18c4317eb1d3e20838f388287fde4d9a807dac6d1bd2e480209337e0096733bc9d09cceb390c9e240efd0bc51ed52e4262dface06832b626000d3041b91af93634f2f3088e429ba9ee15f2459b300965abe42419944d354ff5f51089caa5c5c26e439283a9a9a8186030fd9b2e15fd81feea32ae3da9e6b934f8dea80798c073ceaab5fe31e8b5e0e4b469cbb7527aa8d613d0bb943875231bc19b41ec771e3d8ceeb3abfabb83b166547a007ff400d982381f63e6c83bb2ad88ce3bdfc39d5b17b31e21b2c72b1e227e381b85cab8929895209853f3ddb28d9b2a6ebf2c858aca5308a9eb1f289e5ea09d0865ad9881ac204f42eae996d05dda6e89919136a935de6a83416f4d232ea39536cc0dc0794ad58090e6d14e21cb9ecba335956df9c8882434982679742d3a1cdea3a12998231094c763591c3562ccd8d38fed70de5c9fd9ec93c0fa3ac1ab3d260308f0c2c84884d660c48d2e600c2966b208f2ad9479b794791813f901a9e3c616be8ad803ea209dd994c619186c202a638de5c2397676d19214b70610a28001bb275358928000101055eadd62744858d1307ebcf821684fe728897e88dc76f61195f703613df60a2ffc45fb304fe06a32daa5a5feea048ba04e6b58281b214792cd9c7902113556f22c9526e6e3ec608affbf18185660d572328ec3c7462bd75c2a895994a95ed1ca9063e956dcfdb8512886a318054662a72e3dcd1fb468dfa19bf89a050abf6063573ed7fe4b1812e59a647b84456d09a9cb6c9e40ff3bf7fe097d9143ccf74637aee346733667c043c93af629f4ec859554688999f3f7c4628bc12761a12fd7bb6dacd062ae560f4bcccc9523f2a6943ec0cae60762e7bb8092975fb9a309017c5b26ee67c6c7768b68d2609cf37e83290a8382e1403a807198244d622e5062fbf32f8c218d9c163f233b56622aa147a20f31bc8bf5b7bded8ae26bb9680d55ec7e3d19a280d2183b130604a68aca8b9e62cddb9db3371efa1a5e848a11f74607cbe9f6bb5a9c8b141a7bacdb627ba1f81fa3cc8108c4c697f71565c738819baea5dedbd338dc5aade56838b1247ee26344c602e3bdf23eac7fd49649fd838e38e8258da39a443b6149b1024845f4153766bed1adc571950ac65928ed297fdd59c3807587d43406509e0ef3b8852bddd38fc8ea59220e6a11dcbc18cc93bdde5640ab3e7ddd32ccc33327ea85a19c57efdd8e1075e1b54847a69ae386d94350f71f2cf2c2451d6cc92d46448f89d3787f918196e675013afa8e7e556158928185901ea0a98ee499ada1749ae87e3afe45b174810175cad184fbd781b68d4efaac73610b9e27d7be25a23b2d6e1ec69aee963625d6ba6d4e106d25be4af5aa05c3b07a20bcb5ceaa4d9271b4c6bddfbf9752a040193a8d550064a998e974f509279694d3fe21fde91101d29810f4c82cbca55cc5748eee7301051a8f0aed67eae60f0d2d40e9366b3ce64659dc69f2cc65b0f5bff2ad820c9571742f52b484630532623eac135cd57dc29108333f9d036a79810c8f59488190eb1b63af671b41222fd8bd929c8be5800bff51dbf202df1bdc6d66aaba86a759b52ca0284301acd3ac7b88b5b9c94748579403619d2ba93c9c4ad42247b6a05f51b926f56db528786cf21b6ab778d8e08fc8aea3c3426e1694a812f598a76589e8e2711e5f9929ba459a5aa03e88e38dccfef898def651853c3ee284f9b41f1e524ccdb0aed98488ecfb0149670ebda1b8039059811f32bad5e5d88488d53a36217aeec0e04ea5358ffc3f4203c524397a0ee70a6d7418ed97fa32c4bd5c4f8bcb1065f2b28340b54e661197248591a328f8ad542e1a6b702d6746e29d1f78f3fa669022ab649538980a29c26178fb828eeec06490a3bd03d1a5cd79e97a5d1b5571808a8eac3defe110d4eeefad4c429ba13b110488de7b8d0959036028217e5975c89b184e195e7fac319c455e61ebc81971bd8783ed0f871366f890a8157fbfea46634e5e4d709acafe5a7ec60ac7e80315497f9b7dd806cc29719668cc252816192e71c491db86f48784e37c4a879b45f62834dcc5524a26efc81f4715ffdf800e1b77a37e1bee2c26682296aedb627826630256aa056b5d6f266f3ba86058ae45441f81287486db413fba83ec60bcca68bd783ffd69bb842d9c195ba312ad09c6c7c482da9bef7ede2dc76542a489c95c77e80877ab695781097c2508238808ff3330c23870aa69c6153a6e09837bdd801f39ed5a7d4a9666d67533bdc47b5547a09fb0232ae3b0862a45432943cc51ac32c5c660e264f4f1d6b3a74319b5e55867816288eb4c240f9ca41d700f0a65442e4a00d718343177145dfddb0f96d8e151f1c0d3ae99d2252c3dbd1af6e2ef1d456505f7ba5f716d53ce34934d7d02c456555f651504eddd1870a237134580b2aed0755a9255b73490115527739f0e2e535fb73a0c6ba2bbaf03f798b6937ad79a9bfa4dd5e8718f94c0430657b3fc73baf1403f615ff185edfe585cf39c29514d896c976aee982afb342913621f71ff95ab809ca9eda0abda80df6642eb89fef8c8b2ab435fe708a650fd0c38d906b1456e73646ca69be64d033cb589364431e21506c7cc6f2d34d3ab183109ed79c13dc5b06dbd79dfb5ef9cfdc2077f14da6262fe44cb33680a3983d46d5c7cf92013379c77a3b8fb37244e2e07da6b6512186cd881c1d4ce80d1454670e990f979545d60462ac9b273fed8d95a5686c94c886bb20df217de25b982f6ae2f0c2046a061b1a6dd7a161cf4fe5ab9a9c66909a5a2bb5f9d0f16c541cb5be04997f3da01291cf965a22f6adc4f3be1e175c322b456234f3affe393ad608cebea25cdfc983067e35d8f7038c101997c756c87d22954405c964c5ac2d3159a44ad191d710c1dd623bfb07eb27027de11fe71ad83262db0a3ad9824c5c53effe4bc153a46b5120e2a018da8d9a4bb8adb3907027152903fc10f9b1189501444a095de187e49e6a129bd0c407bf31a5654ecdaf5b1be52a72dff7c921ebf07ed9ebada48ba1ac7ced5bed395afab4bc0e48ecb69a152e231d22f17f8e29b79f2138cf94a62d7dbb562fffba833d5c6de153add8bc04e1e37ed1f6da2e082318f11aa88caeb159ac0449aa945d10628045bdc2f5945f47a873fc02a2b8e7082c3a93f23fd6c53f5493100185bfa149b51c55163fbfd428bd65baa8145b45f041d055781bcbe7f930ef768c558dd3659a3112a3be8655c2d15cfce50f14ac4369fab91df89993e3b9b83e398554832b030760ee8b4f0385fba261fceaea6e061e8b1cb4af290507743dbeea93ad5e7317f96b142c417f12ace44882c1f1026e0bcba274bad684e363ab510c74dccf7c56c96c91a47a5d47b7bdf62ef931ec8733f7c0b383c6416db4d916d8f22f57facd8d428152bd1c56a14e928ac1b9bdb6b6ba8c442377597eba6281ef97d31aac37d30dd1aac7cf1ae4bfa1ca263ebe30dd525c96de2e36fdfa38dda2c09510356d33ad73eec954a73b742de8684304b8afb7528f8a6a47a7cc16a279e316814ef483a6ca71499f0c138009fa231b67161b7d00cfa2f28aeb9eade3aaf7975e0a724e8b15b3c7ce1051f85918b99ac9c537313ae5912d1d7df49b25114b4491ba21dee073e0572a5a47416f785e7b21c34e248fd2aec6212debeaad00e392574c38271c75a196cf6cac05e8e02403173e2a9d00c93d67932c9d3965592c390134d890e81dbf931d2e683e979924612af2cf68106c3d583583e7258a4209e407f6e6d5e4e82e76024da5a55fb458812fd5d598a11dcd000d7ca3e975709afd8023f4c7525d65355626e1d93eb89a5c925dd75fe37b165007c4f66989db2e3a21c22521353259d6a4b1b4d26ce0f2664f7e61947fcb6bdf04880b5d5f5336f89bd8be90ba1a10b89f3b4aafc50f516e7be1d8d183101115526f8ba0816f893bbda43764f1900919e05f88fe55a6a7e6f64fc10f3e8a430b778843defd05b961bf42c9891e653fd530e0806bc67ac2e94eb1d5d228e9c5dbbb48d99e8832ece8b4a6b37081738252f961a8f0e237d44d4efc503ba3dc20c19ee776dc1664502a075c809c1973fe50b0d308cfd9f9bbfc27b8f4c6784528d5bbebe37963e4ccce56611ebed8392baf7318d84a68cae6e6c440368aec05db98b2e3f44b85e6bf4841f3bcfdf88e6066443c44347b21fd83d0d92a30ee0fdb9043b4051228d1972acd851831eed5e32f8f90e650cffdf34b0f23bd7c4365c22b4813e26ad4ad46793bf73314c79171b01468cfccbbbdc93b9527a8658b5055e27852f905338a233fc841f3252cbbbf054e294f9d02e5d2ad9a466c50cab5d7733ae3d230bcfe55344f39573f6986ae0c7ef52b3d59941cf94447164de77440c520256e24eaf68226b13f1141cc4e1ca2149a213b31db19f999cc201696281e5cd20dc093de36f2e77cce30a983f0e17838c24c508c180d1b9594ed12632f03a46433353411e32b80338512c209c0cc4a7c55367194659eac8ab6565d47ed6edd0a7fe10cf8831969e152680c0d4dd01ec1b453889f6cbb9771ed37b0e01711364ada1613e940eeeab14c9306a0340ed793f031fb5fdbc2bd9cab2dcc6a9968f28c79b40a5938fa5f238a8ca14db55ad90dc8d74e9bdc3edb8a93265b0f73e58310a8bbb2e4bdd66e9c97105a3a94b968e221efd33715c00ce27e272e5333779bb2a01255f2468a64399f10a8672c6a272078cbde8266d04f081d7274e6f5b2b52f725f060bcb9f249f723d05bc84d8f49a3f8c888db691a457144ab4cf80bd33ab2058d0353164ce200ea01d8c1f77af6f75f01ec98e8f794b78dc00ea1c4edd8b488214eea50f8c05023283bb12277612157ee8bdd53eb76afbe5a36dfb2f320876288a455b8c76205876aa861eb1b2d26fa7612b91f2311380bc30701b9d081e7394a3d59ed9c8fc063ceba7a116d0a5797acbc883b16881f216bf80aa5ea080d987d4a05bca301d5ad4453485dd442e82dfc307c0a08a0c3a02eb86a01bc422b659aa78db1f8369dd27ac1aa107f96013a91c3f6a06032e5f3a401cdbd214cf77e9355303d45af3c03ae1b640f4b1b33f8edc0ec9bc59741a72128ecefd8f3bd0bba5434d754d8d5249e867d38304cd9b8a4e7b0afed5654fdd69ad66d00f2d5418fd1e805c2c341fde95211d717907004441d90611a1b730a2f8e2dc9b7c90833cf3299fcf24f8d5e30937918d56082840a37b5dbc1c744638ca5ea670af9b61798e735bac9082b4ea41471fc2a0ddc569f0c8aacf4ee0d9b075a7afd6cfd089ffdb8c8b0ca200b0c181695e0590968e0488145d13c815e8a50e15b04225eac488786f3afa79513793a4d9cd6f52520142546b0a5a34d551e767b5b7d93b39dbf904fa522d965a98e92cbf868cf3e825d60956f7101a7877c1c6e1a58e26a95845c66addd40c104e70f9ecf542124eadddf5814206a9a14d44ecf1a8557434a230fa2f1f4f0306c01f2ab1a709f331b76f8e9c0ea4851f60d50cc436af994e9c09aa96bd8189b54c221cee4724f5c95ebec787644f824b5d11c5bf494d0c046ace143de538195ce425436b797749b10254c2383cc4ce471b87aeaecc37faaae3da7c9b18f5021ab9e8f98b624b02f1f8d297a5dea3af1fb66cfd76b46e99d18d05f39297a09badeefc5e7c26fa55e76b3d71f7bf1a2eab58277bf28f6a9055f08c23f8e5fd2bd5e43aff11afe8fcf80f4ba94df9310b9bf51e15b7c2f9cfb7bcbe965067b61b85729edb583bdf05c6f63f722887a4f4869102c67b00f16e57fa3f96c21f840b1d9d470424bc28d311b14d2299916dfc631b9ef9630ac0b306061115fb6cea116f5de04aba98941d8fea356e89a1e6985f9a0f30fd136279499ba6e4163e1cd5ee06f420ccb61d3a1810c563ecca1207cd3e2f1c0f72ce6006d1fc43cef0b091b08a5ad87bba649a9840414772a5820c47f900e0e5cebcfd48c854afd345c7d912053f5e0d51fa994b12a6bea7a279a65fd462ed6dd97f959334c1dc5a2a88367b94529464a42d400927b58e4f8afe5ef945e6ae646c628a4427abebb64f3d10cddbcce08bcc1e8c65ceafde959a05ea2dc3b428cc8310563478e2d1c33424cc15891630bc78e103b31763af566542f97ea2599df658e2d103b626ce15891630bc4881853182b624cc198916327c78e80de10d58b74bd39ae7703f4c28c248ae14b46ae89e85fb599f6fcf2e59198f8d68ab1b96fbb21343b598a82f488dff30fdf9e53dcc5b59aa7ffe5b6ad48fcf88630f19d6422115a4ded81527c51395711902609b759b96d9b71479f49a473b2d715eb78d60b8ea166a763a7737289299e5be4951b7137d437a4c565bd7bc4a51ceb8ce3369c43ab760edbd987f920638d79b08643aff3f796135385eb362912ee6df04a3c03bd6e73bbef6d737169baf429cce6c33f083c53e4ba4d83831be0b9ad75bf6d81c691fa42b641c0c1cdaafb5b792abb95aeb80d8169f156fb1c29b8b1f3cf99c5a0d470930ec0ed2140a669cd2e356ffbed76eece81e9b5593abeb1a2727574ab1f7b45646cd335d221a2e3c74c753c71f44c69b8e9cebaefb434c6c5308cc95017221147ccf1166e651d251beb5c0b81622ccb586664d2f504f7dacce39a0dd1ed9f527230463c00c42d8a6ee43642967e5f103aaa779a536f22719beb90b16a62e53f0fd816c2d06ba8ffff072fcbbfb2f3578d9b8270c8f88ecf1a9db1e3d0ec82d842c98f713b67991c1012f1a484d8fe22d98b808c93a618377cff07b921f6afa25e871361fe49e82c5cc1568afc502ee3a428e76ee7ce7397db0571507d18e46662c99a992d10db476e98d1a595b1890d7eebd039d1147479b58609816d74d36185f7c69d25e516662f327931505d5de136763066a0941bbac9487d343d78c6691b67da45b799d7511b5b8cdd3bc9f8a81d18dac1f851db655f1402a4f6ca3755f004c509f4a8777c8358eadc0b94e637f11eb85b4f2a53e576e0f75579771b742741d4c27ceedb6ec0fd46eb2a372b85abc7ea1565cab736e2a368c3e0980fbbafab21d57b43951b5eb764ddc42ef1c02af4556e8ec0d0024df346a1daf58f901c976183c9df2a4bd85439e6a319bf3ee4e3b29102e7dbd0a27fe446635b420ae42fe7abdc78c6b30b88f769c7aa2ab772aca560b6c5aeb9859b864252b577b7188eda75344c75be8d1c12af1b200ebb65955b72af06cc3b8b58083dbccacd4a5727217c11e55e4ff9ea6229c49a9483a93b73161c96ba49a814e3e0cf6c7513d70df589b9b991aa6def5b44ef454d5274b433eaba3cf0881cafa00dbe491323286960f5000b4e73aec8572a7c7880825186ad39257989b4571dcb8450f23c8e808fbf43adfbb93806680d1575cc8c11a342d75cd0ed7a84909c2c16b852b9bd0c8184af7b8afa285a12051fb001da35e31b9829faa4e7ebbe0017d4932d4d7dae9226d07da60148adb19e13b5ab3916beec6bec33453dfe3ed50099a2aa2ef2be900c005e2b4eb3ef1ce38e6bdf284bbdc318384ecfe7634e2f1f45bfb1c5363d61f7e2e95d1fb4361320200073633ec38990e637178db275cdeccc5247658d2577ac4a990174e380993d7d8598484b74ec70084c94798125407f8c38f642e755737d712dd135eaeff30c12824de61275c8b58c18a855d9bb95df2a76cb23beccc18deec112e2a162b24552ff23d47d7743797e77009f47d0f9cc33a3569dedca84a5a2d40bf57e43dcd9e37d5b0d15cd8e54237c759252dd3255324e44686eb87b592c5912105f45d0a1fb4aa07b9a05c1a8127147dfcfc202ed89aad27bc4553f5d0a67a1b7516cbb621b2a1e7b40e808916daae8c68ae9f242aa1e2d7c7323e8d4e64a247a17df1e045220dcd030bd87806b2f326533d36281162b2a909d82a3eb3ddb9fcbf44886ab2f4e1e22e584e4bf5c2787ef7c84f180156bbb284c53811d075df6da2b3091347b6803843bac8846f0463b618ae67732457ef221c1bc8a78282ac3ab326fa0d4f54808116ee715f5bb1a9e310887074c3912f3b552c2058ac19013d2cffeff298565aac0ad4250cd9ec650c556b39744ac4d46633ce853a1075aa8a0ae0fe86e213cc652f88d1b0b5e64636564772f8369591f2efccaf283feb7386a3be542b944eacc557436a507530794471a0a213763b2334a842c2625c6c5a3639869b1c0a49bf83b7750b1202b36a114b8ffecc16ae632a832e4571777b479c88e6b6cbdd1a5792701e37d3f50a91ab10da7256ea695b27ee74766889a556e3b4754ed8df883091361b5788c76d6da2a51e3bb2d71e447c8d03a8e8a1cd73ee70e2f75652f314af0ae98c5abcb05fb57ade3b17259e65bca107805045814262c510da82538b336fdf01d1668891012de9566584ecc00c8183fab4e84583d795ceb7edfa01215c39c7e45cd9937e475725d172e22b31ecc76f2ae655cb6bdfd2426da81d1a947b39652dd6c883564813511a8fe2f4fd51afa9130053657b57eda9eb2b612994862a1385ee5fc287940f49c1d1f0d5b5d1acbf4a1ed7bb9ba33a48c239e8b9afa6f9e2c4623949cf9ddac169fc384b109604b2b64d25dc8a90319cb1369c7d72a87c61e7cc97c13901c4028025cb623e3d72580b26ca78de40982d25bf210ed1949e0f65af17992a757ac1c85f7a346b843d954715199c4546ce6050aa5d98820124fb5b847a88cef69617b9db1de2cd27cf106e2a6a5fc462b6eef2ebb7b3538f373e0a0fcf9ff4080bb6f028233a61e0970609355113070d008c09f20faa3a7f497460ab72030cf39c1113e2012e8ea48e68947b92e551f8592dfa05b47c4becb84f0ab8a43efac1d98b4e985a85594876a5cee620a3e919767fe05b51624a39752654941c1c29889d5931791c0b0c7080d1d8bd38bfa5578cd31285898707c1dc46889e139607c946fa8bb8f68cb98938923b08318de5dc506d34efc95f708a92ca387ea3552f024d6ef5bf466721dfbfc64feef61104902b74d9636f0efc29e885ce0874bee67d1467915c73475fca789c4824b1a5f615da81935e557e192e9971cd0e6fbf2c4985f636e9a3aa93eb4306b544666c93e41475d376fcaddbc9127e5f250ffd85e18d7dfaa82e3973ca42b0f1cc8d924db3ab2886dae2e56751af5a8256d08b702a4e288d9079eeba1308e3289ca48e1174c6027e119d7a4fc6d691bbe1c238f59d00cae209cd94a293302afb164aaddf5ee17429054ac29143fb0e2c545380e2ecde1c126293cc176da38ae50a9da4e84d9e72ecc09f82c6b9745afe949da072667e4f77e026ae83c88e9891b77554d5c28476b2e1ab34e523ae1a1d221a66607db951cb73b97f614ef8519c81d1bcaed3fd60a8f26d9f01b2c81aed25906219ca2e9fe0337083aa94e2947df097361a2d54a1a9c0f85e2ea9fb174d8223eb281e4dfaa0a1d76d63d3066ceb827f092547cb564a1a542913c97762056659ee98b457f23bc66fe1686da927c9858444bec9279e7e0e1fdad92f31739eeb90dc0a278a5399625aa4f2693680566d1699ae9db2bf8e4028c527cd61bac84de1f7cf86a5dfd807c2ee7b0ab8507b6454a1ce1dd75ea64a6d1296e5cc50da53258442afa8fd60c576890856d040d24b8bc791f8681b86303508111c8c3b68ee1e654df638bc12b6530d0f40619ced8b7928c531e5a7fdc388188a55f629d9c35d565c6fe8b22ad0178c1e5f913bfaa8f148bef31bc131e6fa07a797a91267cb8b2da287620179f576cc7ce8a35aa55d8558c347f0371b06c8cab2c02cac8f6163858fcd8b609e8873225d0182ef0c8e3c90059dfc8b1510086af699f8ff1d1b5a2873447f20bbb2b7c976a331ca685a9fee63f479cc1434224fead5a24797e467061e2ac786d8387233e2198dd4526c38c2adc080a20d607bf4b0b8a61a51f8e716b4f41d00f7b7f75b6214d77cff46867cd58e7933deb89d5ddc7eccc2a8eb26b3e0cc8cff5398d06000e079a5dcc3f43376d260aa2784d3e487c11e36715a1251e89df3b62295ac394e081f98fa509ce666cdafef4ea66766d4597b108c2930ee2b923a9b8b30c3efd9e3c0b0783ef0a09464a1a09e9da0dcdf828088bcf941f565dec2e92116b8464a347ef385f2554262f403deb0185540e1eb356453408dc21f3b6234151578daca2ddab3d061e9558397d44fb032132c383a3cc1d5d45b92c86fbdaa79222a8950f672d90f1660b1621823526cb15879b0b2b7307f89dd117885d66a6c6a48ef3dd1057ee2044f4230bc89dd14598f718821bc687cf01405f3aa368b01fb76393e29bc23927f1b8f695f29ccb2269ee59f976ff202f31afe6498415394643d70569c7b5d135fd87013d0b17823a56cc46c47117e9b8fffc6a3d072069a68e1091167b30a7554f8e3408089b40f6694578a4b25df236ade565134d6e14bc69d1d1e7ee50ccc656114318f698c9622e3f965fa3652e89d52795e6827731b1a196c0363d489617eec9bd244290b1696c1d07f3898a75fe6746473b22e530bc9e00bfd03a35916995658a67dccbeef4d8e87eff43fda983e6debb60fd7660b811d1ed9cd13a73635c0ce8a5b5c1e87bf08e9372910302a384b3cbf6274c48ac04ffe617c5c541822c311a49642872992e87608868570e7263b590d334142e7dffa94c24bf75b804ef851631294fe65b9eb3b2691442db4229cec2bf546278f044ae470eb400ed18fe2352abc0601f190fc5b47c8f63f8ecf9a646ae27beda4d6b157a655d8456bbe7f9c051dd05ff8e2bd2bae493aaedbe208887749ebedb66ab6d04c8d9d3f6e249489c9d25338b6936789dd189298893c4daa62befd511aef7564b6e24744458495402f58bb833853e82e2b9ea7425f8ae58353de91832c735b2cf2c58e4532d46383d9d3aad6ca0040b5bf3e00c4a7f8c1090d9d5bc6cbbbd1f7ffe3849f3c2510954cc2195a1c944eec7e8893b50f6857bf2b6503b27acefe8b3c1412abb3cec5fbebcc5376a2579e7e057030f94ce65470fd23b7052db29014e840b11cec2296893282cd70988becfaefc6466464e07275b6a984735a2724f50a4b1f07f8c6d40000fdad4e359882f604c1e04972eff183443941b5a055ee843dc4904c738b0566fcd724e2c22c3f0462dd23c27affce65bb3cf2b65e5f4e4d6ac1f65dd6bd2c00120e81d4c1d8f60c634d85bec8f356e16a38c0998aa0f7f1b036614e33f3af120848e6e14dcaf2d6a5dad306fbb0ac5c7507b274bd8a276da9a3da290848f541daf330c491a546ecd9ac062300b071c54606cd0be359b44bf116ef7727bc716b5b38c84efa0dc182f0ef88ef674c529cbf70e2e5be22b57f3175875e3a8551848ee0b26662e66363084c2163ef032bd9261fa96a2be14f5be41ae8f03d914eea5ffad597e33ccbce81b0f81d53bc98b871053ecb8d8eb293f3b27fad743da04d4e27cac35836c356ef3aa9bbf641e4e6f4dd3e6890b0962615b516c165d7d53db60dcd626dab91ab6689ab0d9b1355664d6def50c5df31b590dde7a1fa137827933b3b539f0ad3b3f0f79b2cfd66bf22fedf7000add9e1f50c3d00d5b68b8dde43e24d2fe26ed6590450347775e3c28b0e6ce2dcb2a7c6710bc17f7a56a141339a3ac8336ae4996cb8b5225b933f550de36c67343f27e0af3b4af15838ab010017e404c5a5e785154a64c46aa01afe618810d49f7b7d09574b20618c05b1021d5021e4d32eed685a541a2af199c2f0abc772a7151a03ad59ad16cb7d096cc10b3013c03035a83d2875720988d750e5160a5643bbc1c21c5e585632fc74e0033c7f3738044d3104854e18765447bb35ad8f05544f909e0605345159074bde0a14e76827d22e64f971b9e1dd16fd950fd4d2a2e9745db768d2424222111112272cb88082f0862087bd4b1181483b8cd6a5a5efd60549a5a178b70d0b26d9a961f46755d16960eb0c4dcd29595e7c04ac7a52a7b880aa87c6ae36e8a57a8ac5eb56fcccee26291cc8a8bc11988c19cfeb2085de31d75deb1064098f63b02fb68c538f4ba48e32fa8a7f8c11482aa0e77353015bfdd6ff75a203c431735017ebc1faffcf54802fc7664d7fcf1761d3d551bdf09f0eb651cce3f5ec689c14ccb5aef7e3a62f0b7a37ba0bf5d10b9e2b0e5050067429996b3d851f6387f28f02194dd9c7b6437a33add7b00b0578b97cbe5224b69b96d635996db46922ebe21b043add67d7825b0811e2200011e767880031a20cbc9663194023bfb649ecc9381b2cf375b5959a962adb4dc28b79c2a2553696229ecb5f996ed12bbfa631bc5ae7e950d825dfd29bbc5aefe970dc3277ac5ae566157f31a39ec4efe4ca5f1dd07595ad247c68d53a89119c9de5b84d639e723b5a0db63b1989bdef6cce7768c096c0dfc0576105fee91d7580be2525e58643331643a4d6b77bc9e8c36431505f142333f663142662a0dfa44b9674174c875d1218d0ee9139526d56f50ee184aad568bedf047a88645455927bbba17969cb293556a2ab6ac83977979879a7b2b2b2a44c020ac685ddf079ff4525e58603e7ce283952b5a41159546f360c35a2d2a0daddb782bb803964501bb154cc06e5d8180dd2a3a80010a8023c06e0173b7fdeae57e751de337145c2d7763f32dd49ef0a769f96d763824140243a2ece67a425fe87371a6a55029540aadfa88888b951796172a0a5c04f135b68d17d921efb26d7817dbf52f7be653f68baf6dfd2a1bc6db36f9b21df3b10df313d83720a476fd18825a606be083d8a10c0676d813aa3c36e47981c34c6a01f1498b0f62639991e7fd4ed3425c1b5614dc306016b2a21ab60c19d9ee59f03d59153260ade6baffab558f812161e817333146549ab2b7802f3998cf072e5ab480511acdb20514b6eee20293f22d001b377c6e07c00600d420638f6f0a200037d8b0010035c8d83f9a214164e0c6e607179934646b2fa3cea8bc8c4dc61f9549c7dde2e5e2bf06ac62934fc3c3ae4dd41ae3975f62ae4ec8bcbcbcf494ef00d860e373fb06d88b7fd8fe51167b995fb25f037f5df665f0f7d9df9cfde7e3f75e4803b21d6c268659bec8902123c66cc37cf804a66fb952cb58a188612b8b5006ad3e3f6ec3784aa1d3e737519fdf6401d6fdfcfce68e199f0fd8972b7eb4ba5687e6d6631b2788a2504717eac21d35dc85bbd166865a8118b1cd0004c868701a336868e12d204b76f3d340811dd393d3b4dc0d34a83368a0a109799b5ac3f5e5d7685069f4bb1ea5a19911e25ad93d3f3cec871f7e7fed5f1bf6aaa9ac32f861c35e3036305ee010170662979615ad60ad861a40fe45877afeda5649d9ad2bb29bff65b78a5876eb07c6add86a660d359868014b5a2d2076c126b3fdea1440516b905ffe893a5392904c6093a8ac69b2ecf77a7e00a834b5de0afe7ed8aea6e50780fad9fd99b4dcd9069ad4c68c74dc58b65b5664377f6cb7829cb7804e04e0c4c44609cd1d1199c96236b80d550a65e30462c3c6c61d86fb7e17e9e2660f211fbfece6ffcd581c6f0e935802c5b277a5ebd93c31bf2c1f4747b18b93d764bbf98cdeefd863759977e41e0b64333262c08089e932371c0d355ebcb8703941c9b5a0a1b2c232a3a5564363abd93a3fe6f83429333262c8f41818182f5e5cb8b4c8a19cf030d81302350d98756a581416852191da130e69da90c62b2aee088ddad39aa6a6a675b56ddbba5c2e57c80cb586a6060d346c2ca3692ec661d66630a8866586ed8623f9d72c3915695a50d3f289e84454b306a194adb255b6ca56d92afb8d888c466a0814029d279aaaa3119113455395e453947b569f572c168bc51a09aaa1b24bba222123ca3efbd9e71f7dda75dd1315b31a1a1a352c336a6c34b5d597aa2a69656fb80d129cf91a5389e7ffa769419a964d4c5e65b3456c3068b73ff375c5bbce39e731d210698ad1290b78253fcd3ea5ec13109fe49fd918a7bca72a3af0c70f994c2693c94e442adf89482b2132e3e15149a4952da52abbb42be9d8a11ad7af562ffb9a212420c90af5493b4de3019926cbae56ffbaf95f35766948d3f2d3b04db3e483957cb0c71857823dc6f193ee56db3319eef5932e08aa0f4f510dcb0cdbaed9a12e085cb46a9a1dc6f8aad26893a6a626954aa552aa19680dcd38b369667ec6386332d382724283a3eb2ff79b7bf9278fa25440df58f333342a3456562c884e27d372c957b35556645afeda5601b34bd29176baecfeb0afea47cfff238b2c4ad364d975157a4b256785483a2d3253674aad4d155005ecf951e6eea9f994dd43f3b54da2b14f3e359ca4936999e6479f5e3faf3ef6dfd1878997ddfc33b64947a6e5f7d1cfa7d925df2e01adf0936e89f055f4cbd41ae6971f53674afe9adcac79db26e9b29b7f66ef4c999a2f8146a3cf5fb35953d378ec0a049a9166f5adb08b44feccc632e3c63d44e1a25ae3849f7033bbe159f20121f697a49b117b2375a634495f8d9047c8a7933aefb29b7fb7d2c5c8069862e5c166dc431cc551ccf956f907ac786a0209bdeceb0ff4e8ebe39b9c02a3ef06281ff1d756d45f1bd73e42604392e43f685fd74dd480045dbf29720a685ff721933be8410fa288620843d023146798b53892a5393ad15425ad6cc9047242a5542b56ab7dc13e25e2d1bd425c6d8bf53b44f3784621a2952a853a816ceeca3f1ecd03319578ac0d79647025a931598b57fe8269299bb1c2909fbc99c8aa9b44dd4794ea23dfc8a7eaa98ef1c90d46521dfbb0cbebd4a16680ea944cd754e7d3443c28d82c92e6d9aa6b0904b5572dd74b64c766242ec949cd96aea4b0165de6c93ed907140c121a22d23e5d16d2e9743a5d1e2202068b5e21aeb6e5f3f97c3e966e2572d3112cd2ed32ef17243444f4fbfd7ebf1f8fc7e3f1789ac8e7f3f97cbeec937d1928ff72d02a180c0683aadfeff7fba5783c1e8f873af97c3e9f0fc40457825f18140a11017f3f1e8fc7e3f1345190a828ebf22ef33e356aa833218fb6b60d2b72d1be5df952092421d2e7ff0dfba16c98cfd07a025e122c0fbb0ead43ebd03a944bff9a3ead0e5dc96e754c76bb6b79b5135b0d5623647582869465c77e65f357d9239fb25ddb16f9da9e3dca969dc04c5e25242ede83c3b75c37c4cc88d9ae87840e1b168415c17e6cd86c08dd8847b661bdf3f3cf8c98ed5024d25e7a9e0f049eff4020afabffa6783d7f8c973c13ba56d7ea3e87cde2b07fb5f2695cab6b75be56e76b75be9ebf0695a6d6dbddef460de5ce0098316da8495b9d7667a3d5b5ba1b4e4c6cb081dba04aa16c3881d860437b636319b3c562bdad0fd0ef39d0f2c070001b42dbf3016c0c3b14b4c0892cf8189a420422fa1b7fa7d019a469f93c9f80dd3348e34e227d06b3fb047c3bc180ddfcb93c8934ee2cd2b460bea1bb130cf8869e278a368153509ea6a12808f00d45cf118aa2a84f0d6e02c3f48c7e908fc6e56cb69cc661191ed14479f2cd66b3a1e8383245726c8d3f5105e8afa4826fd42b541cf5691c47335467f0a8dce9e963ea91c7c4a70f0dac8f847288519124f251e7113a76b19f26eef4c1e7121867bec95799966fe1bf270dfa8a67e5445a8a7af575c117248ea5496af171ca103a0e752ca94753e8f9df949ebff58ebeacf988e8f45dc189d72efddee3bf4996b0d7fe90992c36e2922449be4abf3f64ffa3d905499ab5bea2bd4e89fcc869349a9a438467946eee104576ffc34aa39a432dd51c264b52a2995c90b4b45f5fce64b1d12c8de64c167ba29cc962236e6934cb596934792f8de62a2d67b2d12cad541acd8372c33ac8d644c122f3070dadb75c037750ee5737495e933c4a22fb9349764281b42127970b55ee16cf3c9eca3e1f5607d93db2d72555ba82a5e55ef555bb2a77ca0c49cbd2da843993c54aa3e98ea839561eb2b4dca61e93cd46b3f47a95603076ff839840dc75746922d873ccf79e954673642ccd4aa3990392924909253577c89722bc347211354769346da572eb5e12e13f93c544784cf6a6ecc798ec5191d94ccd418bd17c3e120de4242ab964253401d99a8a7c8252426b714566b218dfdf026b51a5502d279096965299b52e455f480e7514093938418a874e4d74e6118ecf369a40b1ec7d511c45918b98d439d4a41fa285a31f623dcd73631954dc235d64267b943cc958e71d255371effe1d355371c3faaba3672aee90eeea689a8abbeda89a8abbd551522a6e5647d754dcab8eb268291577aaa3fae8e4ae79eae82915374837f5524755a9b8d98eae5271af1d65a5e22675b4958a5bed689b8a3beda82b1537dacf8ebe52718f3a0a4bc56d76f45311e5a9b8c78ec650592a6eddd1592a82928ccc921c692e96196d2c333e4953866ed63a67722433d90514bb10c7552c47a32fc51f99a3d21c69ade6c07d67ca8c3e6c02e3469f3fecc1a34daa3da98f52e4189fa06a8df1c53ff58f3fe26a0f1647517c91c1826d5a8fd98c82dab116cb91598eca721c455d7ea9aa39f446bbb84fa6cab2e10ef66539fba80d433547598e4c722c47a7788aeb0cce52ad316e41e836ea588b5a7cc9eea86b9ecbbd3d40b1ecc566bed54833df5062b2e6016be6db49c73b645ad6a1877c13c51e7610ffc5443a88e7a9cee8208ae20e6adac33e7bf6ac3262c6b7f5919b943aecd043e98a6ef7a1546be05fd7fc65946f25299eda5cc5d0fa8c1da0a90e1ab7f2989f996fb47cab95e4c80caa79240514cbb21645169bed259713472dfb3771c7bc4f2c8b92651a6273d4da2c7fdac768a2a3f31ca1666a6a9cf926c62ea3ce2614c4fd8d31cd54a2d1286b64a08f5fe2957422a9b9067a948ae27a42ad4fa0522a2d8a2b90164531a5e6b44a5573ac4e2028558ab10b08ab340a51a79297af4b1ae5eb92d57a8c5d5261c720a6d625ead104c2ae2557881e4556d358b64452d79097a84735871ea7d03306862c40bbc863709849646753b506aaaa342f18ec2449350d89ceaceac1f8b5ad4afd6c26228bbdda1d92d2aa3d4c369bcd669ca5fa94d5f835574a354bcd46556af629d5aefd48ce5aaf62a55c28cd8343a5607bd44f28fd43a91a28758af9d6d63b50bad743853f3d654235eac69dba445fad78abf58ab5c640078fc76ab130d8d9ed5a6dc947eb689dae7599f82bd67a582effc845452e14b647bedd271fdb24ffda25ffdb7dd7a67d6b9bfc8aef10998a95a28d680989bbc51f7bd4fd50e8132f906d206c522ed72a64b7af58eb612f16f521dbfaadceac1e0d59970b3a15f9567e8f201fd915c2798a3cd462ed15154444d98a0cccc0907d3d5767628fae5a80f9168b384fa6b15a0f53b1c655ca255369685d2c6aa55a2c910c243232eab3367df142052f445ce9cbcbef781959b1cc3d6b3d8e679ea6e55bee696a4fde69da2ef3f4b29b7bd9977d60290a723ceb7ac2224d2b2a29f9de15c16049084fb54e62a9160b65a5a6e06db1d6c69d87ecf61583bd4cc54ab97a42214dcb85442b2e0657ab7fd7b5d96cbd1d2cfbe8485a6e0edbe39079135ad7d716af507b2cf80bfe82bf149566d457564446d02348abacb4e0161696115e143fbdc272c3b79616d8c3cc3d6bed318a9c1015d8a5fcb2843d4b0b0ee36eb7302cc39206fb988a9572fd2075b08be601a45b6e399cfbe1d499302c7b64b7242df7f80bea1145766b807d39df541ab58b411dec8c3a392e16e988449566d4617cdce580250141c8442ef45191f031c911ea68a186bc9017eee8ad541bef5c50d20fd86437bb68b958ed5027d495a4ae8d7b8b2d5e71ebb9fd8b187cb9bdf4a0c38b5a437711fef2e245b8837dc79fb9675fee3148bc22d3604db0eff8a3e77fc91d72a7f579f579cb88c12f481869c8ba1e863a433e7f71f47fbddf1ceb76d74a5aee546bbfe015cfe544d7c38069916ddc637cb71ef60a51b1c655ca95cb7dd8e6b618c429f9c32c06dba892040404cab717d543f57e40ea0c898a9e89b24bc2d90549a952e30eef704a46c6c5a37e5252b3cd66ffb2b37f4d11940fe5a369d91c19f91820101010b8ea3dec849db01376c24e1810d50302c290e479a2a95aea65598e889c289aaa249818912fbb1904e494b94ed3769a9679c8150f70c5d3513b503d5293689aaaa415c8b7fb5fd7755d7714252b324de35455492b3bc2c8901153b3c9c430e9273125304040d89fb01376c24ed8093b513d2010d5232149201010900710105069576ed564977e25a0122f9552e515a9073ec90fb349409ac6629de7799e67ebdf6ce2c96cd30ed8025b600b6c6dfc0404ac91902410080858eed4a49f94c400c190e4c9080353620202026d561212a152c9c64a645c299780401814149a4bba2b1ee0f8a27a3d9becd350df27a1937df249d5345555f55f36ff480fb357247bc593dd0cb4e2b1e2916fef4a072b1d6017a013f05ccff55ccff55c4f1210b0b42301cd50247d8439cf5cb24b57e093fc260f4f3fe12720a0490c4502d2b812d04ca9a2a87175d22fbbba649378e093fc268fc6c5fc6808c7a88000a35a01cb1e18185eb2a20404964f735fbf9addb1bf24a02010f8221bc088d144d9b4549a114de4688aba24b7d8cdd11ccd31ec23298aa2288aa2dee18eb0d76bb5d05047eb3c4d20a7136a94cbe552a988df544aa552f926ea910c7d27adf589c5865a49ac4aa55267c42742976fd25a9b4c5c17444d49fa572b75466489ba2447721445566bcd8aba54772c5b42cf54a561b592608620454d2c40b12c17bdcce4c89cde15e55b8e249f2092e410890579069c42a449f209f84692580801ff00e34a1d9927bfd6a14b9d92889ebfd491452491c669269ce1083d8b5a480f15699c0e1a591d4406356992c17cd3a5d6247906120b732472722c459df58f5c89f0ebf9052896bd239e7cdb61171f19c74ea1c3cf21d77c24caa48edc4ed6c959f37e9aa7356f24227b644feffa4bf68044d0d8cc3a9f80ec91bd2c946f239e3124918091af72749a216bd555630ad5cdcd962c4b96e6e8445595b4b2a6d4dc58c6047242a554ab76d56a9144cee293fc614bfe505573e456576bdcc2d2d54bcee2d4ccb7b66371cc24153c433e422e4c3194636cd7cbd8edcfecf169b6f93cec1b9f53a025b09bff1d77bafe3107be957cb29b83300e023f8c6b0010c639c087710ff0c1b81d703ca8a4e0606bc5903143c3f275019845d1bf7ef1875d6aaf515e9b7430020881bd6e2526242c2d394391739e028793d7e1e1673f11a6cc8dbfd1dec6ecae6f59791bb3b73905eaf94b3ef9560ae525f0ad5402767d1a570e95ba8071e6094a408d3379a5a27c33794a59e09b9944cd757f35c3df154bc35f569743259fe963d2a139d5a96bc7c8e988b258256ba76117d8f75f3b010fdb0a78da46c097ec033cc92ec09b6c033ccb26c0afec01fcc880afed05a4a83c020630c48005b4ba56a7ddb53b3c1d04d86d6f00bbdd816293f1584ccd40321c66d2c9c94ac5778a1263c2a64af114460021b05dbe365ab2414cb68a84656db16431111873e3144a4446f2ff335adf7b8b0c994e00c203e149c234641ae29ca3ecd6db36ab01bb8787c00edb877fc07ebfdc2339046bb1162b16c46127071f5e09b4be16a8d585ec17cffadf2ede96b2c957d9fa5776eb59f6ed4d36ee49368c2fd9b9a79d6c57db82bd64ae964c46027b959890b0b868ed8ad6262a4daadf2076f2215bf228ea0cedd1906579acce903c8a928e7be6c6e6e1a5dbd96512deea72ca8eecf67a59891435f3f0a8a8a83321fb7b3a9ea605a97cbba379a0026b5778bb83d669bcddede0b56d78d8b6f1b40d802fd9353cc9a6e14d768d67d9347e65cfb0ed9aff1d80afed1bdebc313b00660460c3826ed830201bbb6d7576bbdbedce6e69d8ad8eb6d7eeb8a1d4dc70283ac65b4ed27287dc5cddc499c0485e252e5a2e0c864020cee4e15fe14fd33290a6b99ce9d07a025e122c0fbb0ead43ebd03a846b27a44bb9532e50fd2524c5cbb7f7810f74495176ee6bbbc5ff7671c096807e96cd7a93ddf224bbf525fbf6b44d3e6ce3feb561fc0e3b02e50621f50e040dd8ef4b60873210d8214f4fd80b7d3e38cca4567763f3f0e6a6f971cf7cbb65bc6bc790c0c63223eff33c9af63a5e874205e54e3abb1d9e8e5e7677fc0065bb7c6dbbf8dffa6dfb4565c7fcca269f65b7de64df9e64b77cc986f1b4cd7ad8cefd6be3bedca67eb27b70f8bd7b72c0e1cd368716c0bed2ed783d1e1c1439ec8fd9af23bbbcecee5ef6eb5c6c1890cb86f9ce162693c9049a80ba1d5ecb6e75b4bd1db8201fb8c8e55e945cb8b8dab1ec312f5e5cb8b8dab1ccb56811b2651e65bf8879dbee2f2e5c5ced28d3635ebcb87071b5be31644dbeab3325dfd51ab1d31ec53dbdb179f872af2b35d7fd5fad58d605030bd9f9ddfb40b033c912131296b1d378ab8382f52ed419f25da835221a9386ecfe28fbe56bbbe53f666fd6a7907fb25b2bdb7c960de34d76ee4936ee4b768ba7b95ad7d0abcb7ee4db2bcba2e777c1b0a2172fef73c1df5a7fdfe7c2dfe7e2efb77ce4e6adc56e77b8ddeeb4bceceac86e6e69b176cf8d57fd0d1d09f410811c70d8ad4fa5197bab832264533e863a637e0cb546ec278fcaecddc3030fbd11c596fa37c56b876839d0eab4bb76a7dd61b70fd8ad0376eba369f91bb05b08ec36864a33f613deea644e760f0fbf770f0e9fb29ff73a5ed763f2c071e0dfd33414ea6504c54847b49bb02018900904240993c96432994e3b76ad4e6787a7a3378312f3a281d1843a421e2f44e63503362344c64acf0d9d5d76330e344c78aba3d1137383867a437669c0c0b4583458215b3fca6ef1b5edf2bf5bdeb65dfcdead4fd92fafb25ffccabe3dcbc63d6dc378d826ffb5597f636399728ffd64f7dcf8f1c69b306e3d24fe89f7ed4080ddfcb97f6bae16c3e0adee95fde83f5e6cd80d1748f45c5afc13ef03c12ec75dbce523c7dd704b0bb73aecc2aae92de1ef5a3299b3b9e5cc3133a983ead47dfd2619c62e442644bf6c35bdfe2f29bd7e57eb71584fc44986f4fa572d9545bd10a9fd39ad8fbdfe93ca9ad4c7c9d91f7b21704278ceec69af82fdeb6757aca9f442ac1c2767e4679fe33eecf7e310719259f90b81f239edcb5e7fdab35ab1ec6a653295488fc3e23839264f7b9c9c939f3d4e8ec8bb9f43f223b1fd383932fedfbe10b627e224c39a56a6528984521f2765f2238f9343f2229f73f2eee3e4b0bef539a96f61ff42d43e47f6bc642a9148eafa382a2e044ecec9937c8ec98b3c4ece2af5accf51bd9ebf10209f13f23252894422a9ea9aa59061dfa592d615c5be8d955a7d8e49663da11e07f5383932ecd754a5cf21fdea717242fef538285c889c13fe93be09ff19dbc7c9297deb7172549ffa9cd5b35e88f573b21432a817a284e3e490f09ffc34fe133e4e8ecb7f463fc27fc4cf11e13fe6cff8cff9383932fef3969ff92ac67f5ef443fe9cffbce49b9bffbce69ffc9fffbce78fb88bffbca317b9abfd17ff79459c9cd687f09f77fc540817c7c951bfe56c6e091f2787f42d8e93637a16ff41717256fce7e426ff1971b3f429fe63f2f424833a719c5d880ccefa3932ece380709c1cd29bf84f99a37e89ff905c147b38910419960f11e6842440c20f2464569e43e23f23c7fc47e45886e3cce811502c7b4322971b3363971b56afbae6e9d8f5dfe8ae5d6e5012bbdc8094d805889bf686ecfa86746217206e525df393cb4d9862979b51d7372512ab6bbe5af54d5ac22e372793ab6bee0a41b0cb4d79c22e376bd78f6f545df34f61979bacc22e3767c72e3726167601e2a6d53597e91676b9197b8b5d6e541776b94175cddd10eca21fff0bbbe087696eb256c1be210f741cdaa9818fd0140a7598e82106e1e80f95c86e8e026757f7987e3637219dfc70470f08080f7998f859be399680d7dfb057018d0bb399721eeb16581cc4fb11f2b061fb88895427bdcdd94b4ab8bafa3662d81b7bfa366ddf71933bf920bdc477503bcb7bc86e66f59533a0ec24ae437633ac939c002a4740767b376a1ff11fb29b77d03e7a1b54a853eae5dbac38aa3ebecdc826a493be02245ec3aaa7fc86ec3ea99f5c86a98f4edde42f692f45206e5a9de42c641f790effbae6af0884cd4ab340e837599bd01011b0a743e8e79bcee2b83a7f649a5f66298c4006207461471547883d9c48427f6f4274c8df100b4ce8d9020d313addf99fdd73f42e7364feaa3479f92752081a90cf8e247f73784e784007e3a722af0a3ab420be9945fe6e80064690417f3100ebf9c59ecf50093a1e855a0ba8ca62710c514861c50944239c4c2a78fd0c21832e80c1054350c20f8c85148eb042165608821145ececf4a0e7033200c9600959c4e4a0871048b0848f0a2a28d259ac4122104289ae9ec085ba1674ddf5afcc54c74122a0427f4fe2126418d9411142c8c1042596b083d10e100b784cb153869d3144800c425674a0035e3022099211987085154afc7e782ed031055108c690043304a10945aa25f0d0420c7aaca08a20c8e0c73f903a2e8219ace8afc86618acc45f3d0e478e048bfb2a872714610a43183a83ee87c515473021031d50218927c4408e3e828a181101054664b5e3a022783092dac7f4a5a424824290051645f8f8682e8e7b05e74813e10136979fc01a0b528ff9e3c764cc8a3d3c50451745511445f1c4b22755c73d8668a28374dcc30343fd65cd0f88a1bf6effa1448e2254c1e3033a701449e895000a2a080ac11570a0e087124ef498820c51e011061c4448f1430218b620039d1364f0e309ec58400adaf1d658c7411f00fa427fdd1e86bf02820e9228a282074800a44326eb2b3afe1b722f52c8220965500214b258c20713f6e4cae9b03f3828fb60f34d83a193bf7a57db7ae08418e8f039438f0910c8906f6a1c890f0a1e2888b44084840cc957223fe1ce865f80b182d0117e30c41267e0000e1d261cf1829d202420018bfcd8ecf986a530010c7aa884d843949171a1cec70baee8a58e7dbc2088081f28c9d3cd8ebbc77c8d33f929f720c20452f46842d75a466bbdd27110112de8a58e8388e0915923410750b6b16ca8bd10aa3328eccb66dc9b3d7f0d6ebebd6bcf423dff49966fa10e762c8557878ea7e8a13a13453aaa334c2851a6e44bc661991de4188e23cea38e91b00b0afbdaf8e9867f45ec7afe979e35a98383c25088a5015d85d623b0f871b926a1679a4f927b14ba7a884dd32c4d93b4b1e462325bb2e56a94b92ff43e8b4bb37c5bf9245647e38ed5cc44267f6db4d6da1cc7d1dcef775307f3b3b9c52f4955d452983d33f7723e4287c83b42ece55ecef9847198e1c8c3180d51fe86281aa268c8dff4b34dee2219a2e2a3e93a9aa31fa1288aa61fa3d3d19350344d47afaa6fc843b9053429fdf32cb14f1a3fb7d0d193deb4472bb621e512caa24f52b94dee293779588458f2971c7b4e8883cda40daec083b138922449923870540408d1c957c99eb7a8d2d0785b40d3e0d09a7cac317fd5cf36b993a1aa3e4992afb505740f5f7dfc581d555535a9807d6df4887235fdf1dfac7e8d0fe4bb3ef92c693e49e22ab7d11de52f8ebea730b38b9f3ca525cfabbfcd98351f7d524892c85ed6c1e3effae2280c45b27c722d5fb19bd222c21aba92482412f9241202c25dc8eb2fb99248ebab205fe26fb8d3c9d7a85105a412adc44993f92553899fb84deea4f5d57f4138b7c97d25cf2f22ac911c8bfde4ef28a4a19f0c8b18c5104729971f58c59dfe66340ca998a28f742c051535a04289bed2b1145508861c074e4e0fbfdc951aef37ec891f22b1337ac947dffcf24b1b675ac9dfb4fcf349cf6e9c69a34be2363993dc46ebaecd6d428245f96b93357f47dcc62c227451721fc851e46ff89a874584b5cc4fa43cd2e008922585c41fc5512c8f10b568c48f2449922449d2254937dc028c17b9162e2e5e6a369918b85b0b0b2d4565a59b9cb825282430305be7c71c61bc7871e1d22287bbb5b0aca8a4d05c18181871ec23cc89893b32a6c89dcaa884eb9b69729429532200002000000318000020100a8591284a92200d6a4d1f1480125d8e62504a3892c863a12087911845510c43c610430800c620406686684e006ad2e9c549d8ec5b05c6af15089ef6b67337a444b84864de073085ed3fbedf39d03378375dae78aabad0de1a7a2989d3e194bd6dd8aa2a664f992277e345d22f544e1b28bca86b61e4bdacad812de0d450269700b70821ea6597d649812d0dd7e0e34244619f9c3d2e301313dcfdd5bdd70333e5bbe026624d0ee33b099c1b2a9cbcce7604526663642d01684dd6dae18d921c6330ab7d4875c831429e6e8f7d95a0b469dbb0d1dd0835da7b8d0723fe06abe7df623b49ac0edcd2a1d9edd1a27ec548e2d6e49ea65ec4243a3f803745b712852832595a699240b1475f839bbceaed7da89fd3801aa3c8d1d8aefeafddf1c342d2c65cb26928ee642c2e6793baf10c29ba63d3d4a20193de1a64e7285f1847390b21adf9cb411808f74ae875bf08c6cf196a35156a31fe0d5c60eea32ecb90f595243bde1b06a7cf8fa27d1da9eaabf71d6ec39cd688d0c7bfeeccb30560027bcefa1e5c959d8c00bd91eb5e0fb1f05a626bb612f7a8f78369b8d98471d28879a441d9e6e56885342919027383b10039110188012b21df478f4ce13972200f89e4a08955cadf39486fd06025eafcbc5cb74c0d61a3f0f3cbbf0d73a3d1c6c5617626e57d0b3657ca7ad7a30348aae6d914d8a2481083559b783ca86325c13cd1ace24c060d28a5d0e9298ef8556f29b75d83726d7c5b1aa4f08be120a94e608760d890a28f809009a7704aa0889d625de3ff46aa79d6e03673ba8208d58c2718b515daa0645dc8c704592da5224bca3256830aebed0cc42c52f0a30e4b3207bdd6215383b6b62273f0a14a142296aef4fbdba4b397c6d0969100ab57cdb0adc713f62b8d0a7d6d26fde08adad742227707703b8ecde9497838da5c81d1beaeff793ec2deaf5f89655e9cc7b8b47fcf0eeedf455433979ca32016b663a1b1cad54f89aca236f88cbfca133482db67e7f622dc88e164d5d5e85c0b4c097860feba48acff1f2c0c9f002b5768b7511b0009bfed949baefe29ac52142a1a599e1d62ca9af655a114b97e702e253d391b9d11fab32a1e637e41bc722f1f5974d3ab508104808d6edbea76e4190ff574c5e8d781cb189aabf7d05388f42b32a5ba2305cc386393ede138d990fafd840f177a6fa56e562061c56439b87417ed14dc8f2ef1258f6c3c94a776576117471b66ba01a310a94081b3e311a297e20b5f55c776843817ccd541af21c52e8151ca991ff37c4cc9060e8fb964854a39806a3bfa214908ac9d22ebe1d31270ddd5876b550b926ffd9e5198d3f434b6fbce749aab0f77d21e710394fbfd25506b1a8cd29d3ee6a390c7513832c72ed0c1de00ed46c4b6bb0e206ac70eb82166d511326e85d7fb0c76a574bb6d6540038d35ec8b1b0bba30dfe1437c74078cf4e8e5ee54f48cefe2d5cc846fd0c8a0574f6c63c1cbff05b5c539b162048c82df61f3a746dd5c342d92efd2c0a9152bc910255f12b1023616bcc90887eca6d9c8aea42871a28bb1b7e1e142ef098926ce344bc9f9dac71b6d3266684d0d024eb06a379bd2a0a63d0e855f68ff1a424af861654dfb1c034c798abd1311fb1d81b37b205d56665803b86ec03897abc1a0b76182ec782523e96e6f8b4dd8160bb106513207261d8da13bed19a99047068f7ad10092818fa538337b7e3cd49dd312488550b85327a21646d76f5475ee0a40581d6c5e5874886d40773702c35cd22b0b67a43b0114d630c031e07f693dc015299c03f5c34b03ebb7ad57743a1082f441dbef66d81fca0048fa1a8770bb9ab33f17e87c34d58d13156d6fd2bb134e55b0f7edbe87e277527301240f38516af88fb51f480310b5f3bfec56544658137e3880bde01c2127ac3f7756ab67608b2c3643d6aede8110f69bd006a46368b384beca9925427eb68da35a4a0d7629144b5c10a03c4799c1977468bfdb96692cc6734796fdbf5b0cbc4ff78c70739a2b4bee8c3ca096fab90d4d27daff4af86a38d0780f237b47a7507b24b69908a7643f8970529b79d640c29995f519c2c4041daddd0fc923630212234a1990bb21739a916cd0b560d6e31fdede7075b2e297625b91af7b5c7de68824be4dbdb95f6dacad78c5a57f7d11f3e66ad6635e57453d4a046e00c58800ec739eb3be057890f3a6c9d95df8b4c8aec654627dd9119d1b0804aa07217138a0abd80d1efb783054c56fe33c1ce1ca251127f017978307606427a67652465917ca555bbd87873f2cdecd93a8ac722c3fe2beba9f6be6121141645cb3553fb34b82192f5eb2640f8407490ff99ebd0b67ce06532bf3057a4fd4f74dfd6c0f954c180396525f2a230a0862e04455047e5f416c1978f810ccf8b24e0dce4da13eba53543f968c3ee25869056ea60b689fa125ef733685ca313236167541118b6928cc3e5c57776031800132ad33f37dce9cdb2f57200a5a6ff4054f00047276742c01d13609b47e4b86c2dab59020c56b711f0b9b9c474105476200584590a2afd37ecafaf31260cfbaefcaa500c3b6269fd08c12284fa989ac91b4e2000b1b3d87836c345c6b322df58553643d9abe106442de1f8d16e46879e300edb7f412b031d05f900f4c8462df729a3042ff81c97a0c0e7b338a76d182cb37337ba32e29327c1830a388ee20fe972a19c5743181450c2ec764389d966b57f4ec216f04206fffeac711a3efe0576c9c4f3ddfee07597263c253959638db9d72ac9f113348764ccd301923bbfafaf93956ee4c10fa5a22a79f839e0d708c3ac182e56d23ca6e728b850763676e82ee7fe8baf6a42a99f77f98b809231cfe691f23f052b90c50e767d9d554dcae4d2ea394a4205c48eab1f13d5c31f1adc435be0b4506c56a5a5ad40d9d265c4d6611d656c07ff88927dae418f4439cf74eab10328b1bfd2d625ab1ffeecb80a705957b1e55064726821a592a7019a763962b1205d62aa11b868cbe553531e6130aaa4a88f8e32caec884d574e0103bceb584c0a70c83fd67f54f5885c98f096582077578187145ddb78b070d0762bec9e4b2eda7de0151c88753744de448fbdef6ff9f481dea1d65a71f459abdedd222c30e8bf1867ae51083a85b9a6436e3111325941e628673d19d647ee3ba9ceb333212a2ae7b378d098f835d948c2e0f5280d6a69f688570d588af31cf544c705055506409e1f6e025c15b0435cda0bee666474290218228560100a8af418ff3822d39e16121bf30d0fa7ee400bba6159acd2148fbf6bb7a281e191242306f931a6611c17b66021fabd96c213acd5ec21517a743034d0f11e9cc5970fe043ba39063f456f13f851599da595e03e5a6ad7ec7af8f72c9d0a57848d62341207f15458f222c8faada68460588705209a614290f2e04ce224195c52ac41819210fe66246caa90f3b363c7e902722da68d11cc6b7c9fc9ba41c33795cf673691d474dd48f55f5939512e4b5bc1824775c225c66dc9bad415b3e40ea2390eb1b2c297102bf824c4c850187f9b0742071a15d1e0d05d09661b20dd2ddf06465208d2361bbdba769b86d22270eda2a887ae806e00ec801d3e63e78d4ac2e1124e884649dda5b268f952a0488ab822caff6e66d0fec25d02a46601af30c30570812038966a2844bef38565fce134696c3ed628d49da239af7f216921e48437bd346c5993334f9508be70256f8e7791a129ab179fae8ef385987d616f783cd9f1eeeb2f0372ca444e97b5cc55453e9f5c534e2c0c468a9ec4098eb48d0c148837801cda2540432507e702c6d519774a13ae51ed03749c3d24823afaa4102631728f610881cfe11d113ff385065e9e654e3691da51e4eb18a4da0d4b0b86282cc8ac84130bbf3f1414a762538e18eb413298e687304ac31461041f620c9d9bfc410459fe52823008f6218d7b22f29f0c094951ceef2de2c441f2ed5f894c8ec4b784e9932c97d0cf4d7ba9140d81db12baaf21b19c2bf3fe7ba4a30bd3baa0963d30da19d9e28a8a03b965c4f6666446494cb82569b5163895cd5aeed8c138b1a4514c6882572415b47c66ee11b4711c453165af731056b75da2470e254ee2be54482a9b33872047c8174e23a88ccac399d8f8d0e05938d64fb9bffbc1cfd52084b5496577ffa0eb0b20e5c408ef85b912d091142693195f498122fb771ab9b94a19c9bd8292c8148fc62a338a222c835fddc26ade47df811fd9e8f20154c6b8e1cd69d7ebe93ac23724fcac81d392e14fb51080e9dd254810485f1a3a6959269895444b4301e8c898923e04c4f43313312e656bdd12a41d395ad7bd4578f3ce1017f8bf791e3a94bc029dcaa6528b1124cc28c047520776cb09306e4fc31dd474eb9fec8d59d25250d10145c09e8934b17c0265148ab8465b892818f2feab6aec1137df3e48ee7e6cd681b85b3b34bcc41fdf99a62198b6826a77f7e846a74bc4f4e59314a5011bc90c024eae69b86c7116e1d88b320b36ebf27487c6328cefc26aa4a467dadafde27c7a20206e23eb9ba1ca0b37a66319c4684d1bb10e38556784d91f37ec1da201117b6fd9744c717eaf8c246ff5593d34d9e1f52553de56a5d44dac489ac5d53f64e8aadedfcacc24a221dc821c2ee1f404152b6e8dcc8cbad0e6ea07ab0b98bde3ecadb039b5dede598c1635fae593cf672cc8da0772d2178186fe049c13728424f22cd0401214bc3c4797818f15017584a94bb6b69a27b9763361e3bb96642263966f0d8c96106df3ac05e225175712b1ff6b030dc84b91e5f0e20b6c870f99efeba8bd9a47b2d37bb0e252d33739de10852d39175d4b20cc7c4166c4a57de4c67d06966921c50f3101c5c7e58ab2177e59d4738ad3eeb4a04c68741e9679b5bd599e37c14706e00d903b61663b4fa3d35b41679674837976959cd8e7188662c4e41f2c3b236712b1a90155cbc5ba072fe4192630a4844070b55c09328a024a6806208cebd5dfe0488d57eb2f706b442b103c41ec92388230f476e0dbde31efa0826dde51fd5f2a72411dd4f11330a9b7ecea314503735aa9103390fee650920291046911b23f5e125debefdb7e1e3aed4fbe31114620d901ee1efb21296c9377c4674a860b662a4d7f1e0fd1f61a427b90474c9eafc2e8600312342c35a8cf80d50f6d6a9a4bb10e456a63590087384913a2c547cc41c03538803a2b6acfc1f801725fefac01e0313960292aae86929d142ea62e4756ae2643e8be93aacec8e9c298a36fac00c523ba6ca9332994aba8973664e229d96461a74ee64c79020846927e932786eacaf8df9b284adb8bab9d84d4b4baf5769af962899cbf70f3593f4c702a5c0620e12d86014e5eb342b6ee1e030358ba6862613a244c06227e9b63607164a28a1fa9c0615a4799a57f3748f2c4545b1502eef8d510aba62859a81c7c36176db8be960baf90c08ccfa2d8735ed406be4ca67a2d44548deb5621d2e547ef5a2ffe07d8034e55e44441c8a6c3aac39c524eced620085602c215a36a4f6a170ba3588c4745886c05804087f3a501801f6a532fd905685a40bc5ec7abd6f432271d15d32320f83b9efb08b565016375a929747ba1d94c578b1d0513ca384332cb20f6b16a9abf50a42e75a11edcb0ac7bdedc239c8874915b57ce1f48a9fe7580188afcffe3f1cab8a8f0aaeadec5da3409064aface66110a80576278a3d1a842fd9175e6c19c69801258b1510b16e810c573db622bcdf4ea9e9702083105789fd98209e31e682783d842a82b3d6931f36f38be09e5cca62d91cf93f68db1e75a6e53b3e29277745a6c8f58e946f5d728a003c3b1f2bb77210156956d2eda6168c6a2809e272d73802c42832ac41ba9bbf780bba7538ffd07f3d0ae2ea8491337dcd7195b086c3332a1122106b888194d69bcfe541523bd3fc76ef5bf420dd9452c2876c16c8e09dfe31ef2bd59fa7eeed8cc3904f4414a98b4bef00458b9a53e5ce3cf8b39c821f363b608292ae68af43d9c3a6880c9b3e5a4149d795eacdb2ef007c580a7d659f3748c3ca3351afd8c39a35c6344016dccd14013e2c334d70b1a63638ea6f079274572914effe7b9557bc452c4bc9fd35ef0fdc1531d2a5c2498885f4ba376c452cd1dfcbc876858c85460d9f21a49a39e202656a452d0665105d48283ba6900b05f7321a4d64b4a9b03e8894f1256aa2938ee994c121d434e64a2c44d69f16ba105202937590cbfef9d3db61043ff2b2416c1741a55036e84ab4ef7e0de8957130320dec729399dfe98c3cfcf6da981fca87dee389f2a16cd7076c659c52983c2ca48473760a1c2355441a4410afffcfaf18304a0306bb4ba9f795dc93f4345059dd0bd4d22ccda44cd470e5544c8f58c9f9be71fbc1045f7b4d18fab10c227f5f2ed93ffe4289d43bcae0442259aa801978a33d4ba55c52a772ceae8efd9bbb5e09ec273cb05de988d825a482b2a4fe19db64fe6d4949aefaf22116c025306541433e4d87581b8f631ab7b4f509b09952c44b499f84041485482f886dffcf891905cd94c7815a9a63815fb084b852e10599250849a4aa7e0c3b4e660ba2b1b48c7d672a3d91d4988b39b939cf49ed6842812a7c7cb2f381ce4d4e1079074f7b13d4ae9965d5d88d7461732fe30ace855efb56c2a27b62992d8fcf3054eb46b14b50200ace3fae5eff8d4c36e77c59b316be3997c0385d9671fd7aef0b485c94a6b3d11c81a43185a92dab6785b29a7d9b9a8d0c03ddbc7adcd38a21b03a8e79bd0050f69fc34fa6e1f24b0c9108ff50964f5c17030c1d98115f5ef6277464a60e8655dc4c781c8ba46572a435f6732d3b9acbce195cba6a2337ec89c6e41cc74d8249d018c92dc7f4d9754254311dc8ebfe542d2388b8f2d680538ac35850f0cb8497469e13c4bc1b83d5e4fd3301c8f6b63f3eabbf3c614d749317d1eca791bf3ef07011c0f567696652a9660e79f90098ae4a1e0979e1569dd7a4474ef8ee1bd6fcac0c79a92e6cd3a26812f580922f740a6ae8e152d72427ac8a07a457ff44d4ea4a10b8893a34ec00d67b7227421b725a0fd4ee19701831b15b0508edb9286a17564c1c55a9cf95a056e9de8811b7907d3f0d916a2a0a3283c8fc26b605bcd6e677c95825284b2b7d3a3b36504d0248780947e1d9bd7bea5f6c44cd4f76c0536636220525534fd775ec06b2cbc4ea4b6035e6930bb0ace9d0cd55de82ec67a135e073d604c98938bcd0c7821c8dd623b7525810ace7b0ac79c186fac2201254bcb46d88c5c97098b777bca2f73d63241d1f5e0615063932c92e6268485830854ee0c83346b806d534b0d393128218a9e31d73a61ed81a73d8884397c02bfd51ac104018a9ddd8d95fbeb3c2fe463f54b4dcc302b1e658687fbb2073000bae173caab8a54b9e3c2f88374a7380385ea832f9858467a412c3a5f7f75abc7cbe0f67a4692c038bf8669082623df39eb476a393c35d9061300f08be494376aa9294b782cc05f2eabb87765d92b37334233090b21577a93774f02631f226046bcee7104321b510937fb336834238c72474a14b9d62bff48f20643f26bde24513adbcbc1156d14b28780cc78cd68d0d4f04fb53814dd02aadf2e974e5543927cf0ca126209125700e8e0ad02ad454ec002e6e760e78915d0b2b5c13fab8a19a8314610b8bba9e8aa1cb38460ffa325cfe1576012b00236c3557ee4fef0787b9c56cd52d3af6de8c75bd38fc5b29deee65157426a1ea2df810760def9a6de99154d11c0ca10b3c6a1789f6b45cb41f1c2293c81587513e1af5932c0c0a7ad5f1d40122715287f119b1111ea97f19ce34bf51730627f4136cf4adec2e2e0d61bc9e7581004fa592bfd2da979547ed88453e8b12d0f586392d34a6a694e2fd6062d0c8c386a32689bcc61a9bae3f453f4a3b5d5987f3aff94bc2207bba94b613326708930e828b9c6364021e8ac381f00d1f1aeb74c82fb4e2b4328fafed9b9f2af1d76a8760fc1ca9119b549650cebae0f04cc23fe8c165040559fc9eae23108594fc9c97fc14a606a904ec81be65ce90e2d98830f0aa475e73003d1822fd32f7f363d2e540ad86c22ae78d74514be42634e1de3b248a4bffce3083d8091c6eda452df99b41b1589f856819d77165707023708ddc0445a3349243afbba8578ac2dee2d3038ac461ef3e16cb9488374c0fbe0b6946ade312eaf0892ca61fc84d06c2b088d07a892a98be9399b6a4a6904a0b843e009f4371fca4810268fd47a8e7d26350a988b7a49607005072b47b60e254501978bd5bf203e4eff661b54a61d3b17f2eeb0418260ac3ab89c6b2a72f4d7bc5f0b917c5473b87379a7dbd83d97f882b2848e3a5f04add67be0c01d2f43cbdc5b64b016baaa0f683eddc34e3bb4db30bc9faec9c86cc83d67022a1772b82206fda394dd7754508fd7d276c05669eef473b93f741a318004908325228a61bb4519e39829e540c921a826476f39323056d27c6731ed0a8e305c1bf6ccc226374036c5c7bfd9bee1ac2a0314d6bb9bfa9b288f2bc34232ba850290adec55918075c39c1e2e0d59816bf4ed53b1a9897c2fa5108826fee35281fd37776ab458aee8b94c19787b49d3ad818a45e4a795431b013e384aaf3962c71327f2838b89706418552a536c8f1e77be8f49eb41e65a154c9d2e5a479a836048024784cecccd8d68b9e028b34a5ba0a5d6e265b2e71aa86b2e3b6b60de59ae0227b6fb3a9e30156fa5a119a6becad34715ab92f1bf308fc9ab5ecb965a2c8bd8050bc266500ed0a3147865ccb393d90cc29b169705d203e28a9c5856a016ae636b0d8c1a14c723870c6243d9650c70fb9802dbcf39ea653490328b3e278ecde268e48c5e9122cf74f03178fb700b48a001a1c5466d8fa817a81ed437f43d38fa64a3e3993490ef95d721f132391652a03faa2e1c660555657ca449209ce32505d5dcade773b717ffbd34ad3c942b479451f33459ecc9b501f2a699a2e98800517d6ba13a72f0e5d852abb9a20e677304fd60ee2cb1f23f517d5d30e2d574a535d6caf58f1f13bfaf8203f4ee78f030134bccf2d3d25910f95e2425321f7268e8b524e4551936f63f0b4c83f2ca12cd457d4b3664a06187aacde3179a01cbd58b6760dad9136e8fb014a40335580af3997182cdf2167110adafec55e5a37c6eb990460c490b4fdcbb3889e28ecd1629123d360b90e5ac9a272aa1635acc59249b809aa2acb66e7ce836a2a9e4437efc43b13c26bd683d849e5c758502e3c782346d38c4535842a9af2d71a72f8cc1aabec0348c7263d32628c4d887d83534d9fb198ee54c5010955882897904cb8ca6a53f2bd860c8ed9c63afb02d2d984478cd458d62eb7896a35839eae3a3d16c5f494abcac9c37052d20a32e45ec730fa8295398fd26ab4ddb361002060c7b2d1175761fb584d2d946ca901494556951335a2bfc63a134ec7237b425560184d3f555014ea2c53d269b15ffdeb0f013f758cf6e003d1a686e42bc5a09d9974c660a01a5ce74190a706dcd0c27e464eefc7fdce0fb41a46406a8427435ba0572f6d4b6937ed5187137f8ded8fcd10032f57b70c7e25f2d7d8e831676c629a3e55145901a547216905080c6b0151c68862b8df02a67860f13eb99811a975269bf300a8d8051dbdb5507e03d0ba5d908070cb184a4b0660fbd4e12080e76cd522f2b3fed64ac738bb628b36b6787459fbc6caf07dcd9d27b2c30522ebc3503619bb284d48bca2d00bdf45f289b17e2c95302dac51b870ceb5f27b4d0fee6e81880377c6b54d3488df39bcc1c3d92292cbf6ca37450ccde1b4fc8482b5987ab5defb4c30e01f6b87b255b5406167c2ef13c47bbc853728d87dfc2e72364838327ccfe7bd60a3c3006dc0ca99ccf7348df8d5e118ebee7e01a5f37770f8c7ab39fccbed618de6b96d92d173f8c134f95c35eb03472332750dfce49864c8f0f213904bcb31e9e0b1d9e3f3f750412b310ed38167a4fcf9844299520d4a50a0a3a1a0a0ea4bbc4f1e19308799b01f2e4f2615a268eee8913eebf54884813ab2ec325e57dd92c85815342c8c8f5dcd3e8534fdfca3bf64257ee0d5180be13b6e4f55e11fa2777c1488f9c18e0ea80ca0cfaeaa8c8e76b08d8de67a04189ed0439d9c778255be130ca7803f829e69841eeb7fb69d6f8438d19a71a0df2071926f633dc337ca385ed08872dc447234d1f104b9f46f5dbe8e4c4d70f705a0a5e9eba3bbec274905cd222a604605531c28c239a2386077114f544c86495e9b7bcadcc3ea490096261e939436e33e6ce8a0ad313450e3288dbe6dd0e8aa2dabda048787b1223a03daaa0101e93392c1ea61e846284e602d0e897fff07ab60c6f26503cfe58592a90d01262b9b3774b334c0f85352dce2bae363a8bbd9f121867525e59389ddc6463420a5e429761cf2993232a86446a50850e472168af381baaefdde840118e72493dad8de50cd464a3b141559e130d8c94458cdd7b23bfea47c2b40e91680227965b9e1550805b700fa4b51abbd79658d124e58314648d9e0e87d8d3ac4a8b6142846f3f7de1a6f529e6334b86bac1b7ac66175c5ef36c9360021b3b191e5536dfaea1db655953487b15617a7427e51a432523fa011d5569f72a945bc4515563de3b8dcb84e49224bdab556cd34ade02775bc6e548536aa20aecef690e6555bc591e19f961a17b2c4f9033257f8abfaa49eb20239dbaa0d62dbdabfb71476cfdc163f7f1baca61b190cc64a9eb8982e9a346ff5f33cad4710cf474ac0ea5c6c6cf407319627a0fabdcdc8997e60646eb19181da02c4a32ec26bf8f5d8c210f12b888bc39bb966ded81b238a47fd2870f06122107213d2df13a5f52964f07ea74a9c7fbcde3f51db60bed144099c514d86114c20e7819c4538bcb65f6373d597d1a097d659493181c58de7d6181c0a3a513d60eac4484546a4a8aceaab221cb249f6f9ed5bf00043cd201ccb8f73303b63f1d73eceaf1cd3c7e17e54b9b2cc3621523397866252a463f51519e7fcf39cbdb299f68030086b9255ca023a53c178625c28c488dc4bf0d503b64510dfdcfcfb025be6e8e5bc87f33334ae5f360a08b648bd1cfeb5c0d450e3965b4e974abfbc6d8f47e16ed87da3b0c96e0da4451fd7af513f86e53203bd86fbdd8d16b386729e31103a9f698001e52df2ab5bd3574e6e3c379a4c5f0225ffbd39b4b7b2690c84d188e74f30c547a4a6629a5f998f3100aa1f183893abc33aa47e1b952df9c10f50447e76162ba50bfcba31c3d895c589058457059d6d76744840168c9a9d31e05ac2e1132315641fc5e67c0dfa9bb615748d4c014688915b726e68645d5984598330b5ca7343bb84810d679f6b5a4ffcc584e89ac52dc01a19a3bee56df7a4fbae1d4b8dc45b9191eb86c017d3a72f251a6144c26800882836aa4273410102f12c0325b30b6ff910e927137c32b0295edd700533b12b1b64c96744446f82d37d3cb1f72ce07374938a33d5957e8ad9aa684b61d357ad68e8f9406a7c5c339db60b6b16cd8eede559d8f9542e9f758743b33afb41a13bb8802149584eaa13fe2ff0a4bcd1b43f7413b67c25c567ef4dc9877da2e0735901ee59db25e42321075048d7998ceae35a97d9cb0b650e635110fd6ba982c41e1db67cd3552f748ef5e29e9915151e9346800c08b0aae2f3bedc5b3ee3abdecb16a4e2704a8925ab73806c9cd44a5952a57f9ba089256e600785eac50584398289dbd883a2f2e200419e40e236f220a8beb40b07f03ec5e4a421b1cf247bbf23e7575ab7452f9ef4c81bead2af6b6033a7eecf6ceaefe5108e75ac11bf3c6afe190ee8e33687baadd9dc276a83f1779b850f6ab855257c486fb36c81b7b511370023226e703468a4365d5d85339766d3210c2d71c0e2dbcc646678d41c6cf98a98aedd592ca32ff7377de733042cfdd048370eb2b3a6fc7d965af2d9722ff82a9a0d8d5717c5d9b9874de87f22fb1bfdc0a139132c4357e81580d2cd335dd87966397a2dee3bc49e56906a133deb6fadbc1fd4fe34e57c29e7e02e3376d75111d160a3350ec7a43ce8545554c6582202b0dd728c01c5dc474085a0ce15a858ef9863c4f83d8ec36bd2c65a42a3538e50b93621d4640fda74cd3803c1b1cc5018250c246cff61aa335dacf004c9920731270233407d8e1e2c1301bc93e9156fce53db7db5323c0904f359466681cc729e43862b6b06d16f7ef15b082d82f92cab584da54eea1bba672558a4f7c85333ec2c8d60be76279af0908465fed27760cf707ad2d32d32ea2558bdd9f350ad9ea5771639a5d703787db4dcfdbed7b21fdab3daad20bd673b56b071506a34d9eb799e665638069f40af47b747d3c0bce8470780988e49476ea2ee4526ca84a147c45b1a3e4c407d311da5d94f599e4f334d622e05a80fc17ccc87a10c01a2a4bdab8a92a9f101cb32fe8dd1d4baa51b26cc27c7ef19df5ffd20e7375eb5a5bb8a98719feee9f3435568472190a957c010a00c8fd7d8f47c2c6e6b4d27e8318a744169e52d797878491fde65ef9fc6d8ec7eace147efa1859e34536edbbbb14a33363819f1e2548c20746f808307ce9bcdf6235e3cfaf10b8360bed907395e71a20639af34d6d69dc3a4a9fe6b427eeae2a19d21e40acc7880b4f2bb57c99277dc873199b75b52aee5078606fd561caa2795d729bbf1798a5c3e08031bd29a08f5d8740deef195517f4ec6fcf6f667626c35248124fa6554c510ad4d77a0d5a609ab41de40208a0faf08b9bb4cc624a0e337174d2dfa675b653543b052a06fd0f9ba74ae9181176774901e2af2e618e8c9826bef694a2b5ef24b5bb8f01c0e8aa6ee59eaeffb49a583463eed20a05aabef59410fd2c6628bd5f3e04e22600d11a4cd7c23a68e33f55678974d00458c18721d0a5f4a3337311a0c15856b9e6acc761501ab08f49c8b0695372c4a00dddfa77110603b1f8952be07e8288da95e04f04d849fb40e74bac9774c1b13040f1ae39881647e83bd461daa21833b55003473d87b01655aa3fd580ed28198e6049bb1a1d802833d6d82e8c46327b866bc1149669741886fbbc3cbe79a909e99c2629c3e2bbcd7b7374a71b6aa1686f3b86e74f901e1536b29f3edeee95544cf994edc7327c371cd4128f07e43c28e3d085ed8a3848abf88c988e7cd0ad945f8b61704fd423100a995cc50fa7aaaa98faea63691ac5ec16bfd5732c005f66700d5a962a26fae79dc5e26aa7f2e02b55e86daba4727c984644b94aec02a19a5d0c2ecbcd4511a7c07c36c45d60f3b7490dc66dfe78f018959e6fa67839c82e348f55bf1079ea1a6c658e8289b0c2e7988cb2f96d5ef9e62fceaaaf88eab08d1df28024e9bfa60d7288a7216b40edee222f49d637919a5dc5f56b907d94b4059ade17f6c2451e0619bafe1f9e521f843b374466b533b69c71ceb587a6a2d307085fcad9ab7c28e7b8af8723ec69722fbaa758f55e33449c42c2b7370c5e6fa1c7e20b20b008141bf4e5b7977107c4a56e690256a9e2c9a4ab746e7cdb24a78383f589448c3ff9e230dc55cf3ea1559a5220a2b85e8e34b0fc51c025a9c3b31f314d119a0b9ad9dc07d707335579e451425a02265ae3048664ea6f649505e2b990ce9ff5fafc0ad637542fd83d8524ad34450aec21b26b2d1665f11567bf338f27447e0405de3efcd64ba1482e813ad88f8cc6aae468dec1056c75ebb5f46a885434150d9b7a4f89693af9973cc59379611296763aefead29ca8b33a2e54338ef5bccd5bfd0660ed17e07e71ff457dc5774c402647f3f4894f3628f41264c8bd0bd6676d8375607cb3a61997c2958862ad9d9a939a46b88336672accc62510fe48b8169e5e2b3fd56396ac1c2679efa87a8f6cd82e23a7a722c8443ff4e00d010d9a6f8c469dae80e4ff9420a62b68af27f0c8441f5de8a11091dfebf501a9e1334b926d7094a7668df0c4e685ab6d1eedf7b8532ef8017e05d370a39f71be27e56c6462134a31b33ba4465f35be7931eb570e56ccdeddd2d4a0e7853f23d69c8ec915253a353043af8109bcfd45f411ad5e6d368854340d7969729b87ce525beece6da9ee053ffb17a410cd3f2e3a2bf755b2f19b055b2bc0aae4cd85683059adda6942793408c362864e1554ded2bd2b6b10920b19b7ec620d0df4d9c5cc46f2ae95bc2f7ed6026a1bd17c1458582a458459ff36456bcbeadce36bb674370af7a959cd5cdd4f348c9b88056dd358581b9f399b90dd4870a7c530529acb14240207ad768c596950cea56faee6363592bd21cf1dc6bdab04fac639235ca2433b54c231fd774154db27ea38894a403fa9c58f9d3155f4ad38c16f3339fbf413d2b3e1d74510001aff6a6c61d21ecf72c7b1f0c02469d86e41bb6b61c76ba2657fa430554b545cb2e57d5cb0eb9dc7c638ce9949e37138830c1ff3d08083018993cfecb61edf8e4f23005a2f263ebfb557084a48c2dcd7819bd0145c890bb08d1ae7ace431c88dda4643c5acf79790f0552525a93d567dd2a0203a26a7f6207c4d07c77987bed9d637101fe2d46584c9e4038267909c5fe192c708dcb26f67b1b5070c42d9f9dd632e719e97478f2fb365bc8903cb06403d1273f7c33d076e3b8aaa93bd410a1e2b9e376519555cee3f2e5dd26733edf395f83993756488a9c07b3a421aabc604ef2f44344764d404c4bf808130f804a71abbdab711e6aca256a9a2109cceee5d6e163ea90c7780259b354442e1a0cf2a3fa165adccf66a6bc0c42585f7c2d5284c1198970f9b5c4792dbe9d7d1e248b5500c4ae4ed7572b9147c562979aec6fdcf51af354315f2136bcee07cc8b5243e6309744552341892012b1fd9b96300410640ecee87a0e5cdf7a50f4148309e97bae01a149d406ae13c4259891a76ee217e39f084248c163cd8c39112921944cefccc198b50b6c26e3d270657cab8763115a2f92076e67426be99884c36e09388f400e9a09214939c8ce089e25f0918b130f024f49676e1c8c1937d3336e1af022de786d8b575657574b2e3c4d4901d5ca3fc8c38db758a087dea8441a56bd7a4f4c48788321e254c2618170acbd77a91c1452f3aae4bc000082db262aad55e21831bdc02474f93d7920dc493584a4c83ef23ecb835f1c5d623ccc41851a80688e64402d1f62e2b224d49d8410dc5bc01a72fd96110a6d2ae36b397108a813c6df1040821cf3fc74e44f7f70d9188f49370b83eaa32de614bcb8ad5ba24a21e58f04750bbe430a86aaee9bd0d142d3d49e712cc2d0288ec80e2f156b46639701de130237220c53398af0ad91688e13513f9abdb4a23a339b7f127680221ff5482518770c6adc54a448770cebc21ae282e62c0d920c7cc183aa82a40b15b533b09b7d9cc807fb71b0969795d5ca953fd9699f0208236f45812fb9b1c8cb7cc461315ff403f592634ec5b5dc153b71b18ba915e2f6dc8e49780ba1953c2d443e130b13ac3cc5261526b48b5a03cd781535462713005ca111dcc5c93a84b327f2fe81c3d08de0ae92242f3fdca0845d23bf0a4423a9f6f583023d1a823cfb14658c138a0a958d86ee27669d0d90a3e4928a4a2849d234a398ef0997d24e82bb3e5f80df80a2f4874018bb8ea71c04112094f349ffb858b286a9b3f001601d73110446d63617b6333e14bc5c9a287584062a9bba4e3989f21872dd6d90a58c2426d248cb116193b96fa60a106698c54c2a176d727280604a9b802f5c8391998060e6d0905d464d7e4fe2cf98e358e500d5fd18047921fcd66e43e05dc1c53bd45734a1b4060961f36df140109e9414fb48aa27c4933944461a147290324e906ff66cfcaec9db3b43d954a4d91f2628c07a2dff58e2bd1cc2f9c1cecc302a9cf862a2e9f1d985b57a52805a4ce610a98b45ca0392b69c681ec3cdb8c442a922fa91662d19e7708d88f16b4adcc838f1375b6e928285f24bf4d1cc5a62f6080a529e0f3c730b3d2b5804ef0f911d63392933bbece3830270f0460629a7757e841ed550c1ae3ee93cd11a69e5ac2db3bad48b9d9db3cb498f8b9a5b572310743876b75a8e81e94a5b5fe00767174f823120c870da03ae0c5670b7867726cd1ac918b521a5f5c96a93aa48982a295d264514638017c2c6c66abb46aa001b335efa156ba5aae5d283f4e391e54f6dad323f9993dfcc0940c32ffa8b28392d405f4ce1c84d6e24e6eb1d0def09e607ab2e826bacfc5cf6ac5ecee4f2ad53c22e78468914c148611f388d821e4b4110d20d764b2b76e95a52f8394c2484a589a65a8f1472686913e962c9860f2491e000ed85a59f36d699c29e86b625feb5118260f7cbf252fa48afd5afb4d4461d53b4689530f0a756d6c831a097237d44c69a2efdbff38a3e7dcb52d68b59097f3ae9d089a4bd7859e45a26a7eccbb8b2c4acd665a764c54cbb7969b5596e06778aa102f110996010f94a63c50685cbc8b3cad9ce0a3abccea521a38322d74bdfea7d1b0f9470f22c45633e56b5f5121bba410b0f6581bf4b3fc038d4cedd4ca6a026191b72bcc85cec1652645b384ddb3691e63f6672f4ee317d077daeffc6f5a319c79542f0ccca9e981d3a0ee17e225f452b400740b72712f9dc33c7d5e17b10f312a506a86985f2b2758612596924cc8a1cf8db18dc45efb7d71521cb69964fb427ba9d1d430592485c7f8ee8addad1598ed52ed75a860047677567dd4d1749f7de6bbb3061299df88e3cc293188525594b3e6f758f01524c698f3daf6b2912ab90cb534139310dd9104a2f2a7619c22893a425c4345af8d2ca221c93e41c1667b7d0f5f78dfec688e269079e53785aab5a162e8b93f6ec0f5d6164b8fafb567a66cc20e116a314a5d9fb4ac8c476807b0bdb406f44f336801397f08bf439ff201b2d8df73c67fcace739e05644008adeeab74e6ef2d91e295f1ba139bead3fbf09390079ec4f0019dae3e77bc57da7e070783cd5e01eb75d8e463a950dee0513eadb344bd3ab9c23d1d79251f7de77b276caf8cf915f75f3da054970773e1e8ad74ce05f65313a63c331da0a110ac16dd4a4fe5e816efc80bd96e456e93f28530507ecd2cc6c3184ac9eb34ec7e7b1456cd4f3aec7038862be1fc2ebd0acfc53684f0a3ec218d9a74c0f816c1caeff473b9cbcaa60de0872e25b1c2315f885fb035fc29326111320afce80f7fe161b19740992a26f4a101345459eb95ae25651c1ac56e4af7473fba99581a92de5029f2ed16d37d3f8f2e8d189a6eb0657f3d14083fb6facb29f193f62b6c1b4cba82d12ab60858ec71e63071f36ae2db8cdba7f48ec18245d328d1efe07476609cde3359c50824bef4e8f79dc606f7651b56ad88b5ecc198b8173a7412663b0f030a84b1717e79052b29cefe2b395647eaddd4b500c70f4a697cae760e92179c154b5750de4438c91f66719b9a26c234a41dfe7476c2bdc64f7d2e3a4f3b1750573ed4ac833d5ba5c01f71f41b9ffc2c762ddd3d1466d5aa73cca47ef5a52539ed2daaf9c5744cdfa008400407a5abf741a55a65eca1bc922c210deb288d9755357b9046f26af74625b1531bb6ee82a97c8cd66e1b8e9c24f2a7a8c96afaac3f91dcc2e0bb6dd957795a394a501fe46155c374b4429dca8f45bcbd8eab56ab55ad9116d7aad05c86c0fdb0afae92580a4e126b92eef87bfe5e182911b9f2d0b1f7e28bb2d47a25f3bb7a7be7bad612e2cb874b3c592b10a5f1b9ba8898093ca74176b05e8eda097fac5cf1f4cdd2497dd5864b0f25877cb6cef4663a425ca247f0fcedd2011782adaa8d77ae04b9629d7488ab55ef62ef0b14accf20b419abd5b856772edcc1e0d286d7d6262bae138ca5970758d2443535b30986212e184207e8e97ad3cbb07a8240a82e55870ccd741d0d7911257839f03e391b3e2ca601bd7500eb34b18175c20716ac1faa27f3a20dbd69f5a0e688900b6490bcdd6ed4dc3d6210430e8fe33eaa251b45c196520b25a8c876377995d70353e23b1ed3f288d9fddcffb860e5e209159f3435b73003279f0b672927942e405176fd66dda446d8dd0d33f93d610216fe48a238cbc8c3ddf75ab14120ffec10ba6def88d052059c252fa82abbdd22ee34349b5c071eb5716c95a0f2c3af8c59f0cfc1fc52d9b2b7bf2aa010d0c6e34ae43070cd5f38d80d9e970177965986aba87bee83413046879ef4797b104ed37bb97be9feda79c8e4971135b4bc12099864d1298766aa840994ad643cb85b20506578f49a121b71158ad1d54dafb2d84f78a01260182a86b3f8bac09d9057f24db82c1a529785627200f79aa9f170dbc372df5afbd3d5016ca441aa94c63c7eaf6cc0cb7069802328cd68f2868e624b364cd1ca9c33c33662f390cd9f9de39060bb872bc55000126beaeefae78224098eefbf514d016e8f3eeba2d0546a7c804b8408d90dc27eecbb5a7f831b8aee97760cc8641a95a97f7760269a59021b15cd916df92bce9ce06ba1e2741298a8d34b805e799928fd3041b191c3f671eb6786e441380d3d8a447468c48c3a45db67dbd076731e744621360024e47b1ad725bd44fbbb6f7d9921806404fbb7c50f27e02ee72ddcdb4fc08a3abb0043a0589a328d6512888dc4e4735c8c8db038fff979384650f24f4a302209681560a1a5ca2fd29497a93eca1777d95f100eb353b5a6f6943d92ec8e4f26f4a2d650256483612a905a0c7eebcc01319a0dd5404470144db4a6591da4d9923c86d822eec491e0e36c89a5483ab9dab0af5cdb1aedb639944f601c73ec67b4439980d5d1b99658200ee9ca4dc5929d5cf06b7f5d63a5ce0b713342390ec8f4549db25810cae7ad4fe2ebc22c65db40dbfd9d6faf1d97056a6673edec588dae02ebbfa9f7a4276b7d9c1bc64697bcf9530d811227d3dfc76efdce54caffdb527fd03f6ff7155628ef375dd8dc45f5facbfc6d52a19705768634fa1004938c4db24cb101c5c0341a37cc1a12a47dae16bc2a014740ef3a8d651d42d2f55a3e2359b7aa27bf5caeaa06ff050d30cd690830b3b32db459f4affe05ff97f9cd02df0605f42dc688ce776d9a7ee752fc368f3c52c19a22d9fb61f2315438aca243b79ab085b19a383eb1af7ef18ed7b4b09201d25f0cb2a6d8b0d8a3a138d91d337646e2932747e3c2ba1fe132e9ae087739f83db99b0fe0f70f033815deb0b38e219878fd14bf07230f5bd69b8c3058854155286e9daf52343ae3132be2882e908f13aa4839bc1a149d605508484e605b3397e2a3fa944c2b3e150913c1a9336113f1f12d21aad596257ebf5a7b0ac4e17aa2f514b7f1fddc96b7ff9e710aba2db2e2f60d10f7a000f90e5526c9b6196b241e5cd1521b65344222305d34bffec8e955382eff8a7f6a14c5b7b17a4fe3d28d62e0ff9c9d7ffbdccfa0cdc381ddcce4a2ce3516696416c95481fcb52d488a265ebac175538af7e3d8bd68313284f8604d6858a1b2b905cb3e8dc93c6becb8d8b6246bf8db3b4bb52ad8688f6b83731258d4dd8bffcf6991336ae403d53bd51193870b1bbd83e9bc97a3c35324b93e4265793d2c82c09ddae0ecf4ded78e495239a24b0ee787bfe3ee78cbc7673cec68cb9cee4b79f7be6e723605d52629e4e883dfeff01c00768b92f74693bd03d1f2b01b29c1defba3b78b966639904e67009c388f19713603ba5cd0fdba880d8892d43263de43da6680cb975bcd81207166595329012865ac3432b5cdc5c5cdcb9b9da51d8d295a1c13d2f666627b8066fbe631b89d6b11107607b96809ae05e3071712032a341079a2a79aa66247a316caad1ca179b0bb4bae4200e933cc7a6fe0e1589096e618cda723d6f57c9052ba437af02e0aa374eb182429db0c752deebb5baa4db04f76f695c16e1dd1d1a81e383254cdcc0304807ff0915167fd78322c7a82f6bf332802d44543f5d3e5c952fd9c6bd9a1728aad07e87e60eafb74d445fdf1f5f24c187c39893fc0bf6451a9a06bae384cc16fe4bbc80ec3538ace260eb362812f890d6ab66625cf37ee3fe142c2f98ffcd53821b017fc2d8003a06c9de2c0823b0b1da9fa5033f3680a82ed7444857afc91fae79df8da82e9737dc2fe4ca1d1c53ac19fa7da14ae49c2f4961151ff0c742927493a637517b867bc12adccb8df8278c3b241cb7315282c1765010967aecaa841ee473821b9c712c4f6e5bfc32fef9e91b0346a4ad3751da43d0c88df01af462e06f42d92b92deb4196c51dda339325d17510671c1bd52d118e971a4a09ca16d54ff2c1ff181b1032e57eceb4603534c0f91d88d3950e3d4e50157152609ff7ddf7874bce60761751443fc6e1080e53d3c0f892f40fbdb96eeefd897825eea98240a25c42100bfe026a611817cc5e41a87efb00a05a2a8b741aeb6507fa7d10e8c535680aecb8788a648168059593ea83e5e0e16ae7484a0b4fcd89933e23fb8480d67156ada66081409ee80ebfc558a0eea2b3bf85b817ee2eb42dbc02e55023cb598a52ea98e8adb25db383a1dd167426db5ecd36cac74bdd6eeb1ad9280ec6f40e8e9fbc3582a59173131317ee052210377c674778fdd4f3ef17922ebfc24dcdda41234e713e24832b2e28e32726242215c835839bd0c0d64523982dbfaaddc2e0bd821da774eb3d7572da4aefd1e2b8793cdcc1f6af8b230f77fd5a5c1d93148b7481f4824a35742022b98b211a5a9652f3bbaa1d53f3641a86e7082ce45a6536621169892cccb8ae96b79713a7bc55e8a01d0b0ba33781753883a74e05c8c2957a6312552f1fe219a3fe21bb89bf77b6e54b036186384292eba274a2f38c5fc1a567d25fdb1fd6834b741c19dc1add0818d958e420703f155628cb0aac4c724e37bcb409375221bc445ecc581f2a8880853a927e48a3e900e95de27ae7dddda11159e463e139c7857aa1931206ce5b21ca48b524a9e27cb79a650131b1265f2580fc1a5e1f834f7414a204d70346aa129ba3459746c5e813daebbdd6d876af9a5d88179cbe2be3e9f709a51c43e0124a1bd8693bae8dbfb004e2d447075e8f49891b74318f6ef4b341f31ada4e2ddd5811081f80215cce9fb5a80241852170d4a3893ea1af4baa9cb85a184117468cf9a3db29e1cee3800776ff2b9a62a87bc382022875327130aacbb0596d4103b31222297ada055092fc6e0b756d3ba444c5de23c2782a9511f1e2bd6dd27b9ecba63e2127bf796b8857504c950da49a7db1fda1e46336017021c59476378887947460a3abc877e7bf92e0ce83094aea9e2a3c835dc6b80dd9f2075695835b12ceb07cd03aad89d4a1a582e56fb21bfb5a1a238f12683b5aec577581f2be042cc97365403d9da50a11f94831d7aa154c772b2301ba17cacca8ef78d2806b31b391a8d4f982b366a855a85f72b9f9030a3b46e1304998e85ee6219d787855c2060280c4ec6ee61df0237388f74ff03ae16fddc93b954ea44ab247e0c0ba607869243caf17834c74b9c0d1d5d248c5d1683663cb9210a326570e58e389ca396042ad4f71cf480c0c7e92608fc1c71530b3b7bb279b572d6be8bd441c33dc0acfbbbe58affd764f8f4b2e2df2fafd8bf248601d77e37996222f01e60b2b60f8e8674dcc039476f47bda4aff7982a52fd60129533e592dc7732ae5fc6bb3e76999eb10e03ebca7e136fe005fdca7356cc0f0cd7ea92d1accf5966cdfc4d040e8183e3e57bee1174390a89c7f1bde0bb604d1d5992050cfadb18caf95d795272d3b0e60aa1c7a6bbd3d51503b8fbbcc84cb28efb88bc7653d05baafd0e2408d57c797ee7e8ddb115c9f114b45f407a26e68a2d65c8ad56cefeb65cdde1a8db61aa9d05454c9981a7998854fbaa7df9095a4426aac0aaa8e7825de264f31fc6b443d85518b41c1342a930a3039c4c4064e055b7a40829768bd6b116069f5149b9bed919b415c538c928cb4a7bcfd11b662f1552b8d5d829b9f74903e8a8f888b98ecf30b59c1d78a483d60c0dd43513260c637a008cf81992d63b7dfbdf0eb9fd8de10af8fe32336c60047c3f39337670225e3f99391b582054e98adb0c4fc8ea5d8df744ec90c8ddd9848a1fe12100508ae40269cd1bec98380485e4e6a04d5b623d2dd3a3e7351341940f68b8ef5b25cc791072f8c00ef969a98576b7fe2b48b854f2f5f48e060516916f339d3a5f8320d4f8e813b546dd2ec02791fb637d157f3a9ef3e2007399d6d656d615f063902469565ee848dc5e593ed8b61e3eaec15f8c14d79ac3c5d63371c57e85776d0edf88c181aef75b8a5c0c598d71195fd4f2181fc9a593946eb805da334b6981e380af4edc89810c44031ab203dc001ad03830972b78e1263dd62aa8a7bc93d6690a49baccb1c5d907eeaeea4a926b5743bc638a0dc6936a46e95f976b0a1cc85c3392dfe42c1875ffe555169e09d12e791328c81cb3f12dd40d8c96c1e0cadd74537c8944fdb576badbba24559182ce31838fd088e65e0bba37505b4ebf61667542da4652a8cd9d21c001974cbfbfeef98debe830fe3e0ac1e4148d75c9d63d6f40cc0164304a11ca38661503d4f6eae119a33f780434fde0f09e0345b09e2c63d7f5ecc69f9634c9043e7904810e5b20542ad38c01aa240f07342ad28555ef241ef6aef15d176fa9225e9a8ca35ddbd237112958a5a16d78cc6e7d27696fc89f0ec0008c010f182ddb6aa97ca76477b9180f4bafaf995bc8c588284281506bdd849a880809d9524a2965420ed00d750f37f3e028017b33ff8df4c8decc7b235d626fe6bb911b77d89bf93c568016b1374ce3571867b03774a44df6667e880ac1a959c9890e4d4e7278128fc4a971b6086206c648e2892352bce009a322d46842ca08ca08425254154e34c9a214dcc52169df7befbd320415268c6a28620a12e0c0434aa31182156444c182080bb620efb3931b66b0c33d9de050b44bb19e6a57a77ec171e2b4475a789ac65de39cc84006582cd9989218638c357c45bc841495c90ee9417b0c9493d9d316edf3926dad9ddb55755a5567f628ebafbea00fa77aa10a223536777da91d3f1ffffee0967da2c66e8ccbde3ac5394de3348d8b71cde76b9aa6691ac5fa13c2b9c8a3b38ac0f3a8487deaf52ed7759ea7793b2c17abb18b8fa3de3b71eeef3dc29b55874e3aa758efc1543bb630445d20c2362dd77bf49ed669da3dee9dbef3ea689ac6d51334ad565ad24e6b9ac6e50d6b9aa669ae1a837d1a91cde27c35bd3ad7d613b879effcad31eede7c6b4c3b6c6bf75e3f8af7d5767bf8bb757bda877bdcb9a5b29e634c8d69738e65ccd6a6eb630913479be59c738e386a4ccbd97af6f6945e4de9f599797a31f0a62e79bc4ab96975de388ee3842a776dea82f8d3bcadcb1c97bbcdd33e0cde940dbf5c756aae3a34579d19a6e6c4c994520d7f38766c83edeee36034b1c62cddb6ba8557c4b295e96e559d6b1f8466070d6daa5ff9540bd1bd7dea923ba5dff4b671dcb671dcc6715a29643d8e7bbd3ad772dbc6715cf78e3b377ee2740fa3c4eeb7c63abc6ddb36374ab106f2a0a7db174689f5b3c6bc59edc5da46674ec126cefc0c7bf3384af14b4a29c518538a5f524a4f31c6c714d34d5ff131c618638c31c618638c31c618638c31c618638c31c67847d5b8bba9cedc37fa7975eee6cee93c693d81e332f7cb715cd61b1e4bd8b394810a21d2df4803566a4d4974cb2119dd47ed91b63d24432c715218041108620f4d6c19b6a629b369dfab4bf000967e87c5e30ffd6cda76042ae914ef56febd9c4fdf3d3a85d374ca4332442b17c97cdab4d6b43dc24210cb6b8f76cea2e872393ddd88ab887844b4b50ba5951789366110a7530f44fbdb9e823cf4bdfd0efb626136ed5bc6f0749ae57c1ae7d32e2d757a9202b5c183f52b88942211c37236a54a1ed0696f9a878e65bd5ad57aa4b0a92e3310b385f40f10adb2b1be3869e2545ad20d146edc13e4e2249c6477268964095393d393943be4d5b0c89b302eb89092d24c2c130e2e6aac9e9e06e12020f041f7578b1c39b468123ea573931acb8193a1d458bd3aeba0548aeacc546335a57313d48d1b23f0e07f23c70d1d3746d800f0ed34546e60fc991b239c5e26e7dec768d9d24f903d50cafef513a469bf2101d441dff71500361dd47567e9208e7b0bc64a0ec5c9f92c7ff98328d541db761b777de927881e28c5a4977e28d64118bfe5eaa07b0fb33ac8dadb9cea20cf7b0daa8334edf42edf98549da0544a6f4c9a0897a4be35517582c2506f4d28c948c26f4aaa4e9028ea4dc91149df8ed0db1179885963aa6723aa6f430ce18391aab319295263e3f6b469b135d55893cd6983326e52362ec60d6a356e61c088fc473131462e57266ab5ae88a295ef3323e72a35568328d577a342b72923d30fc09719aaca2eb5a4f1e53685bedc8cd81d2d67d188de8ca4b4912aa0d69c660ca7cca578e3a50b8cb983a3b7293b38f4ac37a997b907bbea596fc497b98c5dcb8cc6aeb3ded478c915ed7a98b00c11887e4d104b0e96a096961170825aad9c209812ec7f0ce7350c9f52a9725a3ac21c2c4b3f2dd7f9ca46869a38368e630387cd08ac5bd8a9ea35b62944aa4e4c07c5623a13b1a1836cd8a8f12ca5862e9f8daa8e8d0eb2b1d1d9488b2b5507a6836030bd5d8132a5eab4e8a09616bd4d61a252755874100b8bdea83031a3eab47450aba537336a2c56cfd2412c96ce4f35a6d241aa03810f523995a20e0a0f04ea1f201a1514eadca4a7846588406a0e3e2443048d3019994e3b38ed1aa6ad89ca942a1c51dd29428f6119620a28f5b00cb1c79c38255866a6d448c31f88f9076211a82275db9d0c556fea6bce4c3567a69a33532e32c3d8e5d6b44d2161975a95cd8856454bd29c5abbc44f569eba5d62228c241c43c4bbbc4bae947b748f2e91abe41ab9435c1fee11b7c84db25099698ab545987c68c226d92396d8219458234832539d52a7542a9648b552afd8a36a8635b244b5a94ad374da216997d54815eac49499983841b152d2a4a42368130e89bda9b409201a2ec9de5425550728cc56ec4dc819415275806832d4942a963271441c19e2a83314d3ae870a0347088bace78c6ebe1fac529fcda829dce08868525472e0cfb07e0443e6787dbe32824c3825c77d4c0bc7fec5b2f4e31d46672b5507886684175d5af1472fe40d2d5bfad9eed22555fd47bb8bce4c55a76cd13f6a8c662655a764d155a76ce92655a76469a7aa53ae3494aa53aa747eaa3aa5a8b31655a70c75965275ca94ce5c549d12d49fe6f2a6e16b6bad95b3514fe841a5b141731a1afa239821b60d016c6c5e52223438e625356263613534d9a6c64c816624e75b322fa279216f5e63e3bfce0100091eb0b9a6a961034000ee1ed0f1344802fce8858495f0219434e1d74328a9f32194dc798c1e42499e0fa1a400be9b791879f38d0bcdeb4ab2a2f008861c6148b2e7f3df4ef8d10b790a14a2f0cfbb6e0940800f40860004780a4730e48c5e2a2d016e68c8efefb80adf6d62b89b97132a851086bc397a2165ac96917939b9a0f6d40c4d86c586e6e5ae7b80e6364034387331319f9691da03b0d778e9528966e64a367a3c8c2e5f68687ed7cdd4658bcc59744b97ac98aff4cb1254ba146d1eea942e9560301b9b1899199acf5ce63157aaa173e8d0a1c79bc76ee335405d7edac379399b38fdacb5f158db8fba066673d86bae3ffea75a96e338c7f1117e8300e38f9c3df2ec5021853106095460869e9186ecbdfeb3afa9e357f1dbebeaf9f530eeb5f5eeb5724d28f094300a608c8167fcb133f2e88c39269430ae20017b33030df309679480bd99c1d290c333d61857b03735f6230609d89b7a3d56609cc1ded47fa461cce1d91156890dc1541621bc09a361967023003746c83102ce08de7fd808b1df8c30c2d10b69c28dee343f7a2149b838df9a356ec3047c981fc1902690c07de625f561cf7facf918d86de6a709f72f25d4bb02307e92902f0380ed31d7fe02a251e508713e977e0dcbe7a885e81e4fefd24274bbb47879f97d39a5c0c01cbf9c5cbc5ed75e4ea898986f2f67183232cf2fe7949999732f27151a2d4437cdbb6b21ba7f6f3ef67d7ea65ee2c8617df5b20496b75ef2b8bce5250a35d72f6793cd612f67131baff1f246c7ec6dd418a9cd2854e91075861ab3d7233522438dd9b78cd4870ad02213182911098cf40802d4688c81128d140a75a24d68d34899d4987d1374498d2919c78f333263cc0833beb8c6900c312443accfb971fb1246b871e34258e40b3858fefd08e647d501a2c1615bf77ef4b2e3f605c88103e7472f2de860bdfb110ca9e3f628e008affd0886c471fb1574accee5501d478b3c386ceaf8472fe4085ab654d21ff0f74730e40dbd54feb4dce5f61f787bd1be15de6e1775cafcd56d77d6adf756f99de52e3aa6e759c6d6f87135bac6d6283aa1a0e1f18edf908d2a4ee1cdaa13342735a34a954d85ca94296184b1a1a0b8e0428a14fde3478dcd4381e2e4d4a449130a28f0f09450420e8e3d1f8bc56030d8ff98981897cbd56ab54451fcbe2fe77c1f6475903d50d53f407307d9cd062f9c38f4214b688658efa4ba3d4d5afd088654a92e84456ac1a2ad97d38c14644521cb8f60c2a06989b72f555a3f7a816ac92d2f271516c77a39b968e958bc965efaf96ecb398505debe902b2d5bfa499d46454555d94730a44a2ffd84b751514578dae59492c3339b9cc2f1c7d4e21bbd30464b858ef634d89d98bdb1b712962102d15db3e6b4e127ed4ac116ead629965699564233c4b00cb1477d10dda22e33e0dae2abce00cd16b5904b75fb1f53cab6130ad4e59cf269dde97236b1cee99267dbaccb9c6d57d80149bd997b5b618725f5666ebbc20e4cf5c6b5ed0a3b34d59b5749d5fc026fba3e7f01e0ca717d1ee672b94c088b8a95c3464723f37a116b3edfc25133c28f5ec89acfdf05473f06a6b2a872b0be1a12f46762461b356c2ea4e6379f8fc1c1d19f8919c1bb6cdcd8cc67120090a365427274c46a5c39c70d97578e1b2f171b969c50c76bc074a46235638e7b18574b6bf589a365472f240e2d3b822147d03221b19a91e6c6615c2dadd585b0e8cb84b8b0a86ef4d2c68a79b7a197becb84d4bc865ee26cf412be109ac3f492bd4c484dd5d71ff5ac26d45fbb68f452a8b316ab09327a29a5c5189d5fa08e81f95c7abac058f452d697a59734ddd24b7ae96ab16608ac39082f27e6614b5c5d88b7432666465c5dc86b82572dc9c0dadb85b89c15ea257b212e517471b5ce025ec8771891ae529f8fcd749ff7d785805f7d9e4788ea319709f90ed3ba4cc8eb2f9f5fc1eec8847c97d14bf93221e063f492769990173ecc8b5edaeee22ec4e5adcfe7d5591792baea32212e7a4988ca84b4e8a5fbef42c4b3e82519582ebb231b42499990965ea2dac5ea74cc4a2f715a54650d13b7502fc9c0da9a7efef492d052d59f90d61057ef929767ceb5ccdbe62f6ff7f638ae96d1606fec53c0f7472f2407443383bdb13f7a21b570057b6343ed1510b9bce91c7b63cf636fec77d81b7b2dfb616fec63b037f612b061154a442b668117d3daf4421a0d5058858848a6eb5840e10ec2b2bb0bdd4de9b70202b4ed202e9b76a00a0810dd415cdbbb106db1505d8a0ff2a2f23ebff28000a9b083b07677216d534f972198a2ab1410209a1d8465d30be1ceeb74093e08cc064a5dc86e140cf2b23b20bb83b836bd50dd5d577a0f02b329a59f657719589bb5ad3495060ab178435b53b5821a28fcaa09347f59cb727e90975d7a5a495614ca6efe110cc93d08cc2e59bbd340349c9615d14445459159cf6a02bd101679f4426e5a06d3b4ec58cb6260c8ab65ae6a02fdd10b69b5ac55032f17291e7d2ab15c9636323262d1473c248bc562e12f6bd7462bd0132f556923154be712c29914b59128c3e5cfdf2f64b1b48df5213c9f0782600a831fc2d3ea52a9548b4d7d080f99ba1006a274f42259ae7414235bdac86848265974abf5f0f3337667ad74944386baf5213c64eb42782b15d1a86d63695a69058220f8f91083572ba952a9540a4810bbad562aa25164ea4aa26eb55aadcf3f0cc3300cc30fe121c38ba2288aa228be8ca9542a954aa5fa101e52b563646474c443ae7e142357373a7291ab17855632b9ba51688588c845166d578888c855914d83885c7d080fb9a2993d40f206da7610bb955a7a9e35ae46d5288ee138ed8df6d4088e221422dde594f2c519bb3e064bc3eca144bb7e937942ed79803298eccd6cb237d3c98a4fd62545d3e5a16c6c8acd39401955eccddc567b35e58557bbbc51ca8363df5f8067ff50ebfda620aa5a257ef770fc92c4ef3955c77b7dbee2b4e088a3c6eeefe9588d65d11b3d2d843d101515e5b4f1ef057836d63f575b7d95eeb679dbed6336dda92b9581376d88e1bd175acc856018be6ced50277ca84b7cfb908e1e0e437d41fdb56a6ca3600ffc5b6915c22cd05490562f3c8f8a734eacbfad6af8f44e8f563ae79cb3e680677504163df0b826ce18367bc0dbec19b3e129a554a3e1a759cf03c70d1cb591def3be6dfc0e03f2e8c0ef20c802fdee516d9cdbda6eacfb1b539f3796b0edd997ae186bf5b43b2c5a5c1d695d1b4190474ba585ec9eacf11347fb8a09318bae1ad32e8eda53de387707f2e8f4145361ea7bf8dd0bbfbb27f869babdf0135b35c68438e93d16ad87f68e7b15bbdb2c44852c0b332a2a2aea560e098fd249bba042b527942e96a07441442db2d4523b034b7fd012ff07ff62ad0b5063da1d0b00f258c1c7eca177fca17747f6e13ddf5b8df7b0aa7355bfe3dcdcaff7170bf7de59f7bce3b1a4bbbcff099f595cf05ede67d5ef983af87cfadd822e78c7baccbfc7ba1c4ac5b41e62d659b8b3ce855f3dfc62aa4e6eb96df90135f74febb2e3f2a5d5a6ae12517b79f77d0e0e6d558d07afa66878abddf35222db6336a9addbdb9a81c317d2360784bb90b65b9f200b1168dd731848cf8903df310c63aace8b4eb085dbf08ef5302df6f66ac6be7fb1507f5987528330f67d7dd8b970cf43753b7eaf23f898aaf39d722e6cf7605567eea12d7e47ad6fd531f5d6f8527df5b9ed5bdf51596f8d2f16b6b3be9da55faabf58583df5d5534f5d753b7a3155c73b65b1c7f8ab51bc6aec31b4454dcf32667b437f521a1c7f2cbed563b995f8da29e842d69a8ec98038a1d8c068830618aaa2fededf6df5b759353b79428636b7e9e985ec6aed4f59d031032ba2b60cef8a65185aa2cab6fa0297edaa95364fc8a61cd8f4da52b6e905661858cf30b328b2afbec0cca2c8b65a49362f247c42420511b969221d33500111395f7549c3041d20da27af868d2fd1bcf37306575b3b718038d2825274c4aab127940fe060aff684f281277becdd29561d8beff10fd6e2d577f64c4bab0d9e03c4bba71332986c7a2f748088f77452c5d3acb11a5cde347c6dbd8068a3b8d933adeaab31ba67530e53ec5d7d0066349408c1b3a723942b56ae0533108dba62b43242c7276804a1d65ab1b602e3de7bb5cddbf3091a52344ddbf213349cbe3d9fa0c164e22df29cf33b5ba63dfa18b77d756df09ee7b445a27da7ec71e30384fbea9206a1bc3fcbdadeb8ed476f2c3d0478607b40be07f12ec4b2f3bd2983389f1041ca16f77c4204a7cde57354d352794b95427483a7af1c5407fd77ccc67123265603e6d29f69c5c0b8c496d6eadb22d5419fa23ae84775ec8eeaa09f600fed02d9a8a87da98e5da98eb9738eed27681cedf9840856eaecb1dbf873f56b85a95f0698dced487705796cfa65ff83bfdde26dbbb66921bb395dde07a17b1389f61589b6366a1744a27d27d541b9276f561d4f071ccb9f0eecd11d5f66f6d0bd3d3bdefa3c561ca2bd0151a0ba9d8c8068fb4c28a2f94a95e5ce3a48f6418940a04b4454c416caa77b822cb8ecac4b0db8beffd47f75fc9a00019a558888b6d06a83b757e8dbe07395bd01a9b0ebc4c91648be90b6c12ff60644b3b7e71148854d274e7dcd806b0bb9f6a6e7c4d1f6f4dfd8e39e1b270e7d1e65268e1d873e7ab5f02647812891d52ec657b35bcd41b8b2dbf8a510dd40d60a512983b73b2bfb4fce98b2ebd17eb1508fb6d76483d1e6d9f8c91952f6378764bb76f70bfa70edee68d7a3b1a4652d2dfef0586a1bdfdb3e3cbe58a8477bf6d8a020405b1d8386367e0aec518982d88d0f96f8ae6e4561764a7d83ee8876bef4b811c8be4e51526354965469c20c262b4cea9526a226d6a8ea000112c4b5f183e48d0f4448c8b5b1d3b6f8c8ee18191915d154f1c8ef452a40bdc8ef464533aa898868c808e4f7212790df8b78888888c8234c7eb7ef11f15d10c00fe5d93d22cf2eef13951f7c9e3d41167836d6402aec0ba547a47b360d19629796ca24efd37dba4ff7e942a926d830768fc8dd3ad99d212998e8c1d3164f4a507440dadb29f6c8ee4cb2044a455022011852e4000864699f8e7ca0063b5c7114c511516469a54c1b546182043b5c0101134990a585caa2ebb11c7bcf035d183777e9ddaa86b58b359cef76459bed2b57cbd954761ed1acf7650559a8363c218291fd7db74dd330bed7da5a6dd825dd1387ea12d7a38dafc7fa66dd59ea2ec802fec1f76580597feff9a85753d9f7f94eac4cd9570bd91d846e2a126d3a8a4496ca79705ac8c95aa86d4523c46db354b6bda552ad19d68abd7289ae51d539ba448ef61099efdaa53844963c3f32d8ad3d689714b880cd4688e56cda7468bf50bfa3002bb400017a02c545b8caf2811a1b4457cd539d31883ff794a8ee1925aa894df73cdd993bea0e8f69c197f669c47d1b8f32b97d8ea5106e1cc2436e41eec67ff9a049f6157c69fac7f6b95f10c952fbcb47b7350d14ee39839db3cba16d4f8928d1cee3b437230644fa49896e124c4e4e4850705284914dbf22a4ec5c0405cf3b9239ca44aca75288f9dbeeb525bd9a18027cadd562f16c186f9aa66d541442d4156b9aa67d7a5aad746adfb4d77baf76a90c43987e39f03a2e6f1abe7bce29da97b5d65c6badb5d65a6bad5e4a081da275bb410e1162e972c51cf6fac17dee6e54f2b4d1101e92bba78f32d965ae1bb7736356da6ec7728697bd6c36911bd8be81fc006c9d7b6dfd6bea1ff9562b609239b8de27a208c4228e2a1199ef4df02893f95529bf9cd7eecdfbb9d1b02fd626fd11aafbea20762b6d603b6bebdc6bab8d8a3a61523aa3a2c8ed4adb2708830ae4a66d199e47c539566daf1def9d2306817c74bbea206f6a57d36ca55aaea76478396f9ba6617cafb5b58a4388f4147fdefca14bf10b3cf148e628132a85485f8a799bb3d671d4e69c964e9c795b2d160fadd5d22c0a21d2e789335ff2ec59e6ec291e11e9a9b7690844a3f6cb47b78168547de2522b8438e79cf3a342503ae7bc3536399aeb66b58bf1b5958e80d211887497dfae3d93eb522f1f5da674ce39ebefe7ede9d49a18027cbf3b71f4a5ad164bb4541442a442ac2ed79ca73a5b4a85486fadb5560891cef272a9970f6edbd36d6bca08464f689911a0fa70b166c50f2be896a46cede10536586badb5d7da56cbe5c319fbdbd3c90f50ecb265b7e89e3675c24f73e2d457f10651dbf45ebd78a354a3df2cc8026d01bdf7de7befbdf7de7befbd9f4e7ad08bc416038c1f8cf1039c264f9a604c91c01a8846617aeab4e7c4c1f41376c521a0343b278e0bd469dbd268d29ab41e88ec328b382787a7ead49d93f82b549dbbf15bf87165e37f55a76e9c8431deee64cfe3c3701ad6da5bf7d4aa8605a574cf536d579b3a9938ab8def0dedaa6973e2d0cf89a35dd3a5f6794defb07356c9353c893988ad4dbfede9a4872176d5f469e7e4008010fe831d50018218d648ad43a8439838f53d415608215823b3c71a9951b6b64626ce0de26a97d4083d2104554412eb35ba63801d789893ea18608710ccd8dc656a57fac49ebb5c6d03ec4064c6e80906d8a1c8d43193be1178f301a27d2df3d6599234451cc4e9840726db090f4cbbdc76e561c9269decd0b4a9d3b6f742277baa4489f6dd2e50a77d35108de20104dbf4461b884651277a828824ce53a5d913448d36559a38f33d414820b1ada64eb327e87eb68062317ba8d3c419291613679e3a993ddbecb11a286ffa6ad1f0a6dd7979ccb59f339fdde77754c0eed87cc27c9e32d99dd7c3d4fff97dd67cb23e1f83dd597dd6f83c45627744d7f5e769b034c9ee8c600e5de69de32ea3d6b3116e1ce72ce3a8677a3cecaab1868dd778ece0783dc3c171967b638d9ec1fe9ae7d146cf70b07c846f238c9ed5b0f9cdb5f1a56baeffe33146cf60625ec7193db379d16ce8659cbd3e9bf6a69c4e8a24ed1c336fe12065661ef3709ccd68a411c819f899c3bc83d1482992e62f3d7b79f8188dc442ceb6c3dc35cebad75b678db357eb314fc53cf59646b2e4cce5e1b97116a39170c899ea31a977bfe32ca5910640cebccf741a29869c7587f94b23b5c8d9ebf7ab7176034723bd90b37c98e3d048999cbd6645b32172048d44c959eb31bfa191347296facc5934d28a9cb13c7ccb38bbd1482f72f63a8e69241839733dbc8d7fe3cc8646eac8d9ea3135345248cebecfdc4623f19033ed3017c7d908d34836c8d9ebf6d74837e4ace521f79f8eb31a8d54c999f89817cd8648ad91522067e167f48c6b9df5d555178f44c9998f1a69879c7187d133982351f2f8f7a719672f3d43a2e4eb33dd39edf432e38cf5183d7bbddc7597b79ce5489484d1b3d96c163e75f0dfbdefb03946214dfb65748d317b33ef32feb037f32d230df6669e659c678d39f6667e35c6606fe6552325b237d3decc87a3686fe653238f0da9d6f8f23ea3f060c5c3a24aa5d22feff38abd7d4b4d6b7f3eaf356573a7fb7b771fa4ecef19c50728b6a771a3f72dd43925d4d8eadda89da7ea889e278e3c2594dc3bb0c7778e5b61c7a6f8e3c6594fc5ecb53e591f37d2bd7a275ea54b106f13517c99935363d613bf6f5c1d1cedce9c0bc823bc87bf10e4740b436085f1340bd67778cbddf77d5fa74b3ab465b09efb3e9047fd6afcc15fdd6379add54a6be958812008ae5abaaca5108ff555b01ee4913a057be8d873e27475779f5910e1607b14f4a9fb7b141f8e00bffac1afd557678daf9547c183c75f753b5fc3e0f77d1fa8b97f87d5a5ddddb5d203df3bbbbbcf283e34b127e8c3eeef29950186760defcf96536d0b43558cb4c7466bb915d1e330bb1caa62823eba5dfe381e4bcee3b2c6b71967ed425ac659cb7a4e1c5ac5f4b8aca7b3caaac2fcc09bb7d6da496d91a32bb6926096824d0131b567911358cbed19a508124017bc463608625340f48a3ced32cf9e222bd8ad1d782d6f7e04126714225776941c86d8f3ad3da3a491b4e93f027894524aa9bd4994d28ba35c1962adb5588b8246151b850895286838d9288e8852841e766b8c5284a31b9e4165e2798cb52d4a0e44b452567ac032f13c2a4e4b7503a2aaecbbf175b6f9cf73c5c45c6cb55cb3a7fb3771b22ebf4d6fa6f41574016ffcac85eec6f7fe36f9b010ddd86a41e4492a8a0ba2c85188a88003f78c42c4891dee19e5892cec6bbd3dbd77ce596ab7afe38b9bafeda5cd5a6bad5e688bc4b969cdc188c9beb7ef993546efb13db69ab518d38b8164d75a1a78f6db4bfccd8e2fbcc36e9addae1ddaf78b321b62e3577a42692f7477e909e5cd3d6adbdddd7a5eced7eed1fc09fae077eff4cfde513dfb69776b1bf55e96ddedb7f1e5e5abfdd569766f2e5c20bbf18e6a338dda9c8e6203939d0f608ff5ad1a0bbc20d1556374baa04055d9a52b9ca73587585fbf3da15cb9b2eb6fd1aecfb13b3b762c597ebbba70885688b39c4d2d404086d9634bd7de31566181e71a22664f285788583e487d019302c79e50d00041093668b520853da1100109660c161759a49abe269048193963c602c297839728304cbcf68462c5886b4f285688761114d74b6a6a37783944fa09054a8a5793903031352515e1ca11a7b44e4beda4336f594f20d5c35f109a8da701380a1a6082b1e7bd1f7b9cbddddb3e3be297f7b314b25f06d8f839bbac7bfbb4af7bce1326174bf6a6cb9b4b271188b68a4988e5e4269412bbb4303908b06212e2a6cbf27e5a7085793590ba95b88be15356accb217005d5b62f1838923bdd150cbb2708c3a6833bb30001de138441cba1086d4f1086011855b15d1c28c97b8230e898811530582e7ad043b72708834dd2095ae05533566003177c7b8230c8e450021f8a00f70461a824302ac3491530b478b144d194704f10060ac60978808410515124f7398a7b8230a86ee005126914c996ec39d5c663a90161e16e7cfb570fbc8168d4eb471125b9e37d375002ba73071234b4b72b60925e8f9f9c7aaa1b3f900395beefb0e08f52f775dc53e0edf81d8f403c708f1fa5d4e79621c856ea74f8b9bf771d993aa7893a123c05629f80f0dc3d3bb270836c25eede0461d02051477e1a8c01d4441d19bed3441dd97d47b5230b00d8a5d277198686d84adcf7efdd84214cbdd344330c12dcd5a9b45be9480592fb9c3d2dd400061367ee166af03475cc3d75792be843fbe4b8d910297a60c905edf3e00b4d905df7c3fb8eea82f6180220041492d3425ac801134240c90113424421b90fed09fafc28719f5b860e6c25224c722d5b3b384a609c39e0bfcb764c7bc3cdf9247e92df4b3125ea25fb0f609741585b86e90409176ced3ff3da654b2fd81b2d9b414fa84ff23352a52b27141b8a6cfcc382ddf341565b863bc50aa25d817e78b707470f78077f14cd86c8214bf84324770bb29002ae626f8a74079f64f4a9836ae29ea068124da24b8ac86643e492fdea07716aa019b54b14f64f10d69681c6091a2c215b7ae17bea44b24aa48b7c92a0955d56a24f1b5592fb243b3dedcdcfd4e53cd63f3e437b3e486bcbb00023667b7e4259a2ca2e6b91a95ff31a80b24b0d3cd9b38892ddb97148253b6d94bbdb11888fbae71530c9ee1e55c02481c2a83d5f9d660fceaef76c1a44f66bdaf185f58fee130a9416fb3535038648ee130ad4d39e50a0a2ec054c92fb553a2a81e43ec10414cd282bdf51bbb1688b8a8ae274c6da17481b7825873ee0be1b74b70bcfd6e0cb3000534d46285e308d50ba88b25b148c255465c9f0c248d5b935b6fa00ab862b79cc2196d5a9955475ca5a9376ad47549d4bb4eb84d245ad5aecfada347be8d4f09db6d255ca7e529c2a3db0ad9e13a7e6a1adce74e1394064f168441dc42be6d0edd053218501a070428f007876744c28210024002047470e1c1c23dcb889d9a86103abd1e39e3fcd8c4ccc0be6c5e5d2c2d262ad546298023fafe3f2a6e1d9736fd37ccea2ebb192a7be690862499b422b37897ee1cded393c54cbecc1df5176affa36cab6a78e4719bef83ccaf25bae8db2d665dabd73a38c3bebdd48c588214b34818108960401d61c0683b52e63b18e04235997756f6939eb0b316c100426b6b04110a8a8542af02a2d53fdbbece5363636ac9696969649832a9c30e102307eb89204044150cbc0b35cd672180c0663b158a9540a0a0e821004151a9c317b227596cb6a6e131313e379de0a74a081152ca09a4200c5bbcc652f87bd5e2f192d43c10527b062044a20510426a2cc652e181818954a45821849c66862c81058f4a06209c390c5e572812018f3411769c0c0c80e681881abeffb58585852a9d48b490539788111327438925aad569ee7a98ac801d1932184714409ef3397d58461288a62b7c4174c3500c2882590103f73d98b8c8cccf77d2a954ab3224410948a74f1450a5a5a5a5ab44cf599cb5a6868686c6c6c66b42c0354c4608c34ca90c2082be0c7cb662ef31f0683a552a9d20745a480ca18455b1091fa7899cc696a6a6a3ccf4bc00a943002041d8a8c6c68696969d132efe36534ffcbcbcba86506e8c10534f8c10b8458c1103d98bc20428923582091848c8b8bcb101557a6a48106104200e1079a56ab35740492232298c28c1bd0d8c10c8bc52af2451551461c21c204894c4c4c0c11309aaca8210645caa042f37abd8cc220e2034e40a0822d803003030333adc0408a0fcc30c2851750d38c16407521c618548871654e09e2481a5338e1840c124c1b6481022c862005085850c6cc824a122c9408c1901f9ed07cdf27001d8a8060a244099a0063c6c6c6a604292700c20b223ed801090c06b37184087610e58a143310a2a6a666e6880d6a98dd30648b18bcc06089113d60c1931138894e20d1a1e8873148c02464430e4b64204593a6243040b1a2c91549000183223109c02205452280628a238cbc6262627c9ef0a189252880c195252a98d7eb459600073fc8c1061c9c6007d0050303934aa590e420041652e0e008aa86148bcbe5f23c6fc8882f88e0830f3a6832240c6fc5c2c2228ae2100f51e050e405471cf1400a315cad562a956aa8861ba0a0046154f1441739507d611882202804273e300326c0f0420c24a0cdf71d4905f24ba55262cc86e081531753b4c08b54cc65301b1b9b1983218a8c8882ca163af8c27b5d560383c16614208e5471c5164564e00311e6b2979a9a23a940d6a854aa1c393829cd6e7084072454aecb5a5e5e8ea402f90282a00d1ba8e0498b279cbeb802b25ce6d2d2d2d2f2c189922a4f517051e597cdbc15131373d9eab2968b8b8be7799a1846784004910e466378ff653267bd5eafcbc2cb58add69154205ba228322006612039c348922c4af0cb681e03030373d9779966b158d7b21e553e9006133e30a20815d0bc684633f397cbe5bacce6b2516b1da365435528f9c20a1a4360228230665e349b39cd655e97c91c868585e532d8651fc7f1a565434b6ac0e20ca4165051411534343497cd645e3493f9cc69602e8bb96bb55a5d567319cd7f182d1b4262848c2830f0c15318456666662e9bc5bc68167399cfb82e7b9d250cc3cb5e2e9ba1a1a17169d99091227c48a2441947aa484246e64824903297bd1e731996cb60befabeefb296cb6466666658b46c0ae10a0e8e20317285524c4ccc65339817cd60fe7accea32d7431b1b9bcb5c2e8b9191915969d9e4424a12299ef0c0862168f17a1d8904f275d9ccf5a2994b063ebc8ce51f0c06bbac75d92b26e6482a9031a1964d272918c10f4804e108164530303097cd585e3463b9eb30df65abdbd4d4d45cc6ba0ce6f57a7d5a8663c6931c82808512a320b85caecb66ab17cd5667b94bcbbcdb5c161ef6f2f27299becc050373241548181b2d830d4112450ba6400193182c2c2c97cdc217cdc2afcea265e261977daf696969b96cbc8cc5e53a920aa40ba66521940e98a670c144124eac56abcb66df8b66dfc3afb44cf59acb6cfee2e2e272d92f5bb1b01c490592a546cb30f0c50e55c0500193276084e1914820c3cb6cfe3d84bda5d56a5d467359b85a1d490572358128356012620857fc0083ef3b1209e477d90cf6a219ec36ffb42cf596cb6aeea265b3238d647d866449d6917048d66533977d9f1d6d64f819120f191e490532f43c6f47b9a20414348e88e2838d8dcd65b39a17cd6a0ebb8dcb652f6fb55aad56abd56a691a5cb46ce8c80f6ad002084a0c7184133018ecb2d9cb8b662faf394ccbc496b36650a954446328a9020c2935585aa2a6e64824903597cd5a5e346bf9cb6bb4cce5ba02f3864e207c1184122ee8e1073c8cf1f2f2d2f2172d0347168bc562b1582c2d01190c2982698a13a4b1031cb4b4b4b46859ea31c08cdc008a3086c08318443c9a1f2b2bb680f221092bbea0429c5961de50954a1543110f6270831122462a50c9ec98371404c1247408a2065dc4e0890f18015d1ec323def39e4aa552433c1401a585132b621471c4e545339754ebaf1cd5c517cd5417ef799e376960a50915479604912444eb45b3d65dced232ef2f97b10ed3d2d2d2d2d2d2f2213c648b8ecd1b0a5ef5a21978d545513c128c14b5ec45cb0490c492275584c0081e30b9b8b85c3663bd68c67aeb2e5ad6bde532978b8b8b8b8b8b8b8bbe983af8a259eae0552ad59160a44acb5ab4cc023510821952882841c1a4d56a5d36135f3413cf7a4bcbb8b72e6351a9542a954aa5d22ecd7bea4533efa98320086a594bcb869c80a2e28c3470d084104ec062b12e9b69e2595a96afba6c058220088220a845ec794fa552478291292d5369d924e3c80b78e0a188299e442145f1482490e26533fca299966d072f0b53a9544ae779438bba732f9addf38e04233d2d03b56caae00a1ccac8210a23b83082947ddaf33cef9e77ef4378484fcb66f745da6533241752fb0c2907a91d890452bbbd6c86f442769f21cd90dd916064f75911f7fca2ee33ee59743d96c3530a6d426a68038678f45696a52caea3ab0b61ba52d1958aa54a7dfe054624c597c89e3d68b2cbbb6d0fa2d89e673f4a6d0f96883f4c3132a5dc0368bb1ca2dcd69ac47a8f8a4c9be68d1ad9f51a9d5231b5727fe9bd4ddad48a664b5b65d353245ea6dd94f25518fcf2cb297a7a9b8890f1113eda2e930635650ab6466e5375a23590f513b4c2c37bf998c7f799f3de7be7bdd3dbacc5f770ad35671f3e57db7a45d027cf79b11e270e067db40d44a37cf03667e6baaef338aecba00f0f8fbde13aecb95cde0bf8e338dc591ff5d8c3f75e5c2fd61ce853e7f43ab0de8ede463f51fc40056cd73ef005baafcf5c616eacedbd97ce9cba3e17ece179413edebedec6dade876e1f3abdefcb600f6e03d1a80c622db4278e8883f774a5cc1edaf249833daf27c50c1e538dd56fdbb631d89b5a752a50a5983a3f33562f65db26d8f595c863aa40d5f19c7ea68ef764c6ea3d2629a35645cba841316feabd2753476362c63ca7aaa32da942a362f678afd7a6983d4ca4983d29d0a2d098664f7ebd06c5ecb9aff798ec13b3c789d9c36a62f6b498983d28983d4bcc9e25b347553d263a80a33741e128876479a9b1a0a6c072134a5a43a5399fb1eb3722ec7a0d8d5dcf7545d8f55f1a3b6ad7839468b7c60c4c9c7ad61864e2d4af460d4c9c89a31a81264ebd38029938f5e1182434712aced7726f543ae2215bde712dcff7db18440ce2da572bb5e8198092cea80ddb847a0fe3b78c348c1b6b6d77373001d51dd4c4a961ece0a833d85a42cea2682dcf166becf39e3c2a7809155654b1e9922dbc7bef8e0a1045ed5e4aeb6ffdab9d3edeb6f7f17cbc5d2fa40ed95a87989b02f2b757ca595badb5d6d29953f6334f9c89336dddb5de5daa54b58715b5387166cbc7d5e3387156f9db67dd2b01f9db5fc85ba75597d20bfa88b5fa840a005fc89a67d33c9a4feadb40342a9c7b037bb054ae6a15119dd55e477357bbd405a2513e342de40ee1ba89e1596b95b0a9241e0861a3f06007cb83215c116c941d98b16ddb4639db7d963a41b2032e78701cd77951a22889b2832b7660054623010aa0f6dbbcf7de5b694ed9d317c9e3ecc99f27d2138cbe0fc9a4d112102042e206a251f9427977074fc5cc9ddcdee1b14e9c5c49701c72722948def9ae76377e1c67cd8cd5a7461bf3a61e1c77e64d556157189cf3cbeffb71e751dcdd78274ec6df3772a4a77ddf98c98df4f2f78d1ae971df3762d2ebbe6fbca4e77ddf6849efdbbe2ec54d6d6cedd448553b35667b23d64db437f4b6807c6ec7d4f652a3253dfaa5c64ad69b7a6ddac7f548709c64f5b6760fc8e7a61513c47504040edb8e3eeedec6cf9bf8dbaeb6b99a57e0f9b0c71fda94d6fa7d3e2ab695f6b8d3567ab10f6e7db44e5a53e550d7bde87fe6ede9b415f4d15e09d8aefd05eef9dbd0b6a00f9e383ef77e5fce17833ef6f5c276ed0ad874b637f6065b0df4a9db5aab8156bfac1d83d06cfbfaaaf6d55a1fa38f3dde5e3e53dfbb3368c11eddecb07ef9e06ed5f30eddea25e17954ccdea454ac13acb6eaabbf1aa34aeaa93893444ac56b67b53c5649a2ce2a20c432b6a70f923d6f89260e0db2f283b5bac766a5da7a2dbe1763ac699aa6e241c5430679a878a852a5a989878a870c1e60dbf71e37f3cbc7be9889773f27a535e75aadd5d3d27a8457ef85aa1ff0f7078636c5b8729d16bb49e4fe679e4e7ac3248d66dcf367de2b01dcf35fe0f40b5e5791ecc49938f608bc5fe1de7b6d5000f702a7b3bdb1371a781180a7cfd0f636f0feb57dcb18dbd1c787be3516b537d0473b055dd0f4cbc7dd38d087eebcb9cc4dcaa5f069d49ea00b9be6c6983467d0a7476ace3d54291dc2abf77a7c9e057df2bc3e5727e0b65ad6e5aa626b7b18ccf9da7b6f8f3b71e8efc499f7c21f46b39b59c803f4f942550fe2057d38d0a71cda17f4f1b8c9f9687ae22c2ecddf2622d26ab1ce7584d9b5c3e16ed4527a91eeecb9cfdf166df7e59bed4ef568ab55c694b0afded04a3fcf7eb5febb2f1ff7de7b650f61da39e1a97610cbfab47d286b52952a3cec408b14014199a3da41cca18c5d9f6a8cde8a07048846799783d51df0f3f96eaf76a3d152bdcdf7eea81591def67963f6b86e1c72b2bb57e7047b789b06a231a79a40ef95f035396d6ebcfb7ae3a4dcd23d123daa36d821b5ce9e20229e27500d4448dcbfdbeb29cba6b7dfad3b464bf455f54daae236d0ea29661e59bf7c7ce77f67ea1a27ceedc63ce69172209773972a856caaf3c4a1cfdec8636fbc9cca79d3ba318fddc8137ef86ae236b9bd691c72cd2df066ddb9e464d1ec32060132880022892c6a2841181707227a300383092747827006a5371041062c3862b6c412241dc852c462c9bdc10b1ed8a003922343b0200bbb6794165c615b708585a2b46736b9428c18804006370041116f424413226ae04d98cb355d2e1a6aacc9afb5619da57dfe0579701cc7e957f71feef81d777c8eebbe7d68d3b1fca8d0be65def4437b2b5947ec12ff607d3fe0bd9584ead8b3e6cb69dbf6db8516637ced43dbe66dbc9f201ddadfbe76ccd4de00aa524d9728014110b4b5b504dc34ae7be71dacb585a4d6f02d24e192da1d467bf875af9b86bfd4b521782f95aa5f92569256925692594b89d6626a219976da69ab6d2dd9b47a2b0251cbddb59732d8efdb412f6541cfbbe71df43cef20a84b1952deea9ef85a2f56b15ef5954a0c53a02e3fbd799d6e256925116bfe01d4ddeec6549bd81b5ea2441445115fb1a5a4a5a495a49544a494de72bbe237fa959e561ccbd692cbe1903e1ca9eeb8534caffa54d1dfaf95a495a495a495a495046a062d259795d442725b4c2d252d25f6c9de6ccfdfb927bbddd3f6e9db55f52d7cce0f594a76be7855a8bd6da4507bebae7d5a866f6fd7ced1df9275442b492b4958b52b1e154aa97854cf3ba3de4675fe86dccf82535524fee4e38dfbee616a45c9d642427550bc515d89aad1d17d7754a76a76315eb2a9ca48d44eeb91aa48a45061d829968aad725b495a4a4a0cc542d9302c95569216928d9584a9ecd242416dfb56127a02d6e510f7925e5b060db19658a8cc52f2d929db1e8ff889b341c8a5be794abfbb5556731fe8438fe6fe4e8978208fcfe3be775d67e4f3f1a552b6a37a470d6fb30b37ebb2daaed3a99732d8d4eb1efcf67dffc0eff6fbbe0dfcf44fc8d987a12eaf0ff71fcb715c66722faddfbde9e12fc5dd5a6b378ee3b8cdeea8b73b250296569794c8de0eb31281b63baadb7fa9bb53e3f7fd76233da23abe5390c7a6b7e751bb6a144f7b745d97a2cf39f51d556fa737a4bc977783d7c679eb8df6f9a4fe93b5544a979aa637e04db5eefefb7ebae77fddbdef1befa679ee4fbc55e7067a02fd6808e9a6e27df53c4ac45afbdb7529702cf3fef227c879babc7b7b370e6d6e94e1db79abd7469c573e5022f4067a446fa0442811fa092b737288384a5705e62bd2ae4d449a76dd2920704499020a070e1c38be69d64a31db60293803d66ab952a083bb4dac41d920881434d9b686b4d6f68006db7a7b4671828a0cac6812cab91de674b2b5d65aaecc1bb65d6badb5360a130858519c18c23761756736c16031288ab04b580e57311287c20caec3f8062c4ec39aa66932f832d630c6f85e285ca06df7defb2bde2850acd4fb7cad0605152a4d73502ca9b058827c390e8a246c390e8a1068b5878de3a000012c3f31c65eed19e5892ebe1460aa599109927db77d6147c08c83b825f13426330d9f71a70fae98c51b7c755fdd2ab3a64921834f8a2bc428cad85d936e0903493850d1441a504d50398a15e18402226630050848301426b5db74f29237ac049e9c1c9b63773afd6cb72bf084e5c48e73342b5a71f1afa6a26bb3b6046c99b88bf1662dc65889d9a36d6c8f60bc650dd3c6d8cbef4d2b75d73a9d536fe8e98d80a1d2b4d53925d41b7a8e89f8da338a911e76b767142348bbccd93457b0073a1747a49f74a852ba84370f4eab8afd309a79c08bd95391590bbc08839ced17a0a0072853ce188215e4ac2aaa670e11d3571d8aec0bba62387266530e546c0c853dad4ad35f8d61dda483d1bef3035e0d71c80656a345a3a5abebad578fa2f5c9cfdaf8d558be8803f1e2761868b61cc41951c6eb41b7cc6bbb38df318b5c8831e24bd3ae1adb9ef5edcdf698bdd9b6ed3e782f18715eef45b4777929d4cfba23d2aa5d221d80e742bf6d5b923761b9c6b40f07628b88df82b7e520b2b0e6b72d48bfa37ad3eec0706c7b1788e5b7ed9d38af6bef02a25a49bbfd1743aba65ba2ad15caeb41374be5adc4798390b26794209c7649b3eb73ec192508239baabe1ac3746e166325fa7ad1f589756792758968775e7edbd2a973ef9dfa55872ca5364c5149c32217a24a7c5dedbabdc18fd91b7ca3252ada402c45f1ad1c7a83278a296f569d192588a33a7a1e1545a325aa8d96e6873c47ecbb6e917ed2677ad7150d804111370822690b1120b936b400c61835e84114688c41c41d52c40c88262db27852021d215c2145071fa6289145cd2e79b6fd2cc56dcbd8b6393f2c518318c221064f9e4cb9028228946ed3ae9508110c71240442cc9e396705e2071f7ae06187223ae44004871b908e6c18329b3d73f6cc1a26d14e9a37f53c3cb326cd9a346bd2ac49b326cd24984b74892ad4252a6b92f884583475ec8cd93077b67943444f9853077da5d9f49a2e695c28116eca61a3aa6b604b255691b5c3f229fed325dddfcb76bd546deddcdc79b976ed74eeb45cd3a50ca368775e748e4b4f7be3a2bd9651b437f8a2a87996c70e609293cc9f3c303a034ad40f43e0010969cf23058924594841daefb03b2840c1e40727302306559220ed57288115337c4006f9021b7c700111c608c1ec05a47d0c2aa0c119528a20ed25607768ac10821355d46008117a40da57e08815159c41daac796acce67c2110cb6f1a77acb530b46979ad6d19654bf9423ab2c5012e6f71d1d3de0c6d0e54c024b3bdb13bebf20739c9965b72823e549b132d5e69dcddfed3699ff9d2c6570f1d7bee926e4e03bfc37eb16d2dc8a36ae316af812cd01455a1628b5564198d9652d758ac8dc56205a8b8a8642b98692335ea944333030c000000a315002030181289c482c12808f33051ec0314001099a646604a17684910c430c818830c410610026444a4044848d200f446d6476df737a1052b1164afef77a6f9565b4d014e2a0223e2acbf80d5f4f00fdc9b516cdbe55f912ceffc2e6ff6d5b1aac02f7a8c19ff59737ad3fcd837f59c1bb4e2582112daa9ae75e74d1190d9b0f6f2500a627e5801d07048019b7f01f3001d7cbbb72e498c1eb4fa97407353f8a4b4b19d788155ca8f950e73bec02223f0ca2e703d10682124ecb13abe6ce45b20072ba53ca084966c9128c06d60ad5780321d320cbd647ecca36a02d5d3d3f7c34aa381d136a1907cd5f379665b13f7d60de5e32698c22659d38d0e3dcadf8c58967b46cbaa5c2d952a6f5b17842cf4d0325d0fc0f41987d9a2defc871d511df3e26ef2d072678161d900bc1d22a404b44a648c8274f18d5320041ebef76315986b361e92f77e4f5e521d8ee30e6d9adca9e3deef1147b6b176dde2fe44f8303242d94b0306cd8352b0846c51093232c661328aae354f8b86e3b25c2eb02a70730951960f14fb60291cbd49d78eaa3d9a8a707336e555863588aeacc7ceac877506412e35591c5b1d0b6d36b090b42cf0104829abde60d499bc585a834a596f0672ddfbd16e030d932533be92609e0f50d0e2b65b2687dfcd8183f7b0811a2c3efea3c13d5d1ecf3296bb71eeb01edf652061be5ac80ad498f4a1710e2dd727754d7ec48b1e3d83dfe099d076b370f6b1f91fdb0f4b689c4058a918ef0f995d82f543f999d0e361c711b597bb26e375bbb962c4e38cd33f200bcaa306ff031831415316b7ad9495f3514f084e4d468f479c013b87b457a05a2fc3a6a668964795a640c58144a77375b0a6875d8d92af19bc1ec5b2122a23193a0fd601bb01d477cd07620d98e1a99daf42d8013615e16e697272fb25c36c8a006b3b8a2f2d06f02912625d0b8b15d1c0c5f33bbdfa15182d992371039a9d967686ff212ae677d8252f1e7cd3f8863a7d8fcf4fa7781bbd5d51c2684335d997c03bb3c88dab53cc664ef1c30753f846e7b51ee7bb1d6248deacd48ac544735e7a11450f1c5d2201f9077ad686f2cb9ce0aaab05fcff8c73ec61b777b0f90e35ebaf7d73c544ae63bbc98dc505e69158184987129f47c0e7137b862d7727cf085e0eb1bc008c9cc13e52bebb569688d6d2478a199506d7bed6a8177e91f1d521fc7f4f39c1adebc2c6905eddc18f6304081af6f7aae44754c4495497a8ca9c330eab4cdc9555260ce3573c257332f74d03f16821bf466ac0812ff422a501d2ddb6ba5ddfa1b318d735285e6048409ac6fabd37fd80749675e3ae652fe84eb5ff004b1c5b80b2f67fa9f8f6de7d20195de413da3d8d44419df7ee5778cca46d19edb2ead0979ac4fde5fc471b251c4096fadd47f49219814bce3f806f697b20998af87da1d745c96d79e27552cc890f040ca7d86fe29a78de18ca5d6cdc8fa0d79eb2d0a519831c37cde3f12883f28c2eb9dd731496b31d8409ef00625342df609c2b650719640369b85fdb2b836eac75e78ffe16dbfb7f62be0e2c20379561fe9e550c75e64fae80a28bf758b090bc58ce4e8753c4e4381579807f3bafb85a7b418c456c73a75786183b685ed910d221bf96a74df49b12c9db190b9aaf8c29d1a59032be8c08237ef89fc7f48205c838b1786fbce7ea42cbfb9b92696ab117317db3709abb6ea0af47251817f3e05830ffe6013538e9ff397254d67a298fcfcf0d919290bd816074e44ce3074f8ea6134c7a4ba9cf5319a025c241a0eb4c89bc4c8dc30ed0e312fa8cfcb45e7593dd1a00636349d41b793f2552273227cb4adf1ce87c5ba2040a9cc63a92a80406988fa397d4b4115018bf55da848a18cf3837c013ca5dbc95fc29f0c5909844af5b0d49e4c538f55117dacb78297dd785a4d2e57cffbe9b6ce4e7241e5118159f5e9f65bfbb80557d1895e688a5504dcd08ba93701abc54595f82b4ceeab79815fa9baf120a421359b6b70c4df8248fb54c365476cf3d553918d07dad3e8c2d85a6fd6cc74101059809b3764654a7a2f392d2d3b4f491d2fef4c919231536688b9b9120e9cc49b46810f80185199dd1303a56eca1b9ab5b88d4dfb072dfa18925e81cb4a0293c07c67e06c1820833eabd10813da11820f9cbfeedfae8f946fd752ee6aff8d0e8757da59c1368e6528ced348de57d9cbbc057b2c7d22bd79cc8d0e116a76cac0febd63b246af91a470d3e96ddff3488b8a2cfb32b803e1815edd8bc3f12ca207a0d306424948be9c48935cd6b4ae67471acf3f3c49ca2ae5bb1976e1d33e7da42101d45bebc31cc8f10f4ad4f5815ed1b706d2f984c53567078cc8d544a6791e7b49cec3720792e1fe56faf5a2066655155a27d9f3eff76995118cc6a369548eab4c04f47ea48e505b096c221012aa13d33c5be540df53f8f5e794799dc164c395ee3d3dcffafc486285353f3165150bb85816b9a4558ca4e12e9a82c4b6d9e1736814ffb85f1563d9a5ba14bb502e37a7eb2f18a734a41f4b1093e49826b91072f04ba64ace511ea8748c2ea6e0d9a6e0dea0aa5a6ae10ef7173b8e4823118fc5ac74bb1462b509ec2858ccb825bb01b70465e76a151076bb7d1067b9c18be7bdc1ba9990ebca1d92ca06ec03214a7552731d4c61c75b7b6751089b5219dcd5b6f97b6a65fd370a45db3d8a318deb61389561381797837f061ba0c963aca4b2c09e382c6f7f390d112bc98b60022953b0b97ce4f04de6ce3a674de960dfb3ac09a9573338a157337e99d179776d7ed8b92a8be241c58bbf93bc843d5e4dc8fbde2ce011ce0a277e14d520cd224ff8656411be94a304efa9cf724f355b6a155a1055652968e15315c007e00aec7a91f8ba94dac9b25c573a6681dba39213af4e91240d3d6e029e7478181251ae1c12c5b9e6d23aa76b8203daad045c7d3bd1076742858f92cd3ce620d9da920f5565560e17f7b54904b36fec5bf1208b384c98469401332acdfbc716ce0d5254a6a8e0075cd4fecca520f1aff9c0a1955c60d4495116e8c70f67abac08c551c2722c54f75e0489c233c1490d24d03403b1c82370a48fa9f742400c713cee3e531ad1bd41c39005210727f6216daca6a40e2152aa6a6e7e63d1ffbd050b6c16612a1d1061023f0505248db6efde795387cc7a095c8060542ff80fa68399f1d61886a9b88666f3f8fcd9ecc04814bde76c737f397d7e31961409ce474a3e4289e0102d0262f9213a9d67b7fb92f50d4b21c0335c4224643608cbd2a44ba304c6667d2658298c3832c8e65cc39a316e6bc609ac6470413b1194a446b6dc95d1ee13fc7ab99028a9e06ec530d1974ee5241dc2cb02b0cfb845749e5a02d2357c083308c488733110b57c382648202194bf2f6ec2c6355a31b708970347efc4368c473674fd3b75a4f0db2d7f38e8a700078f3806f95b452f1c7f78692110f1ed2a6a46120f1d86f931a239c638b008e826b8ec0078dadb93accbb57403eb901f469538a535e181b5815e9564ba5b530a05485917320c20818f8c189435da0420f1967716b414a767671dc9328ff179a11c2b961efa2db120362e7adfc2db399ead960bdac186ca1ae636ed587a1b2b32e2b7d89a4e8acd906161874bfcc384cc8117455b48543e60c25672d297b46b8797cfdcab1defff7f23bf88cc4b90062d16402b03837330a33e488c407608c89a9141756a7afde729fe676d88ef5212b875a899e46d64d3116cec1ee9fa332c49dc2aff86a03fb871542eb1b00545d74d5e08656eb6832456bacf3a6df68b85eab4b2ab33d637eabd94e41079dcb80f1c59654e53723fd133b23aa7077b09de0151d5bfbe99da88d2c528720a9fe989fb1d0098c6c479637a93021937036e4f3d3547f9b2680d5c63e9007c2c7206d6cf21ef596c62b92f7a0f94c2bef5b0120c90e5ab597ff58d4b186f99cd9a96a684e629add043fea0fc748fca8d2bc21bad4458c8d651c405544bac2c75c9606b88d7a4b081fd60ea474c4f6f4f3bdf999f58244ae78edc987fb9991f3b6b4ab69cee534e811cf95ab4fb00240fc491aa4af03c197195224fa102ce4bc0307d2521e418e3ca4ae2c19faa096825c2cd6d2c6e4ed57c81243d6e7731fe718b3481760b6aaff58e12d110f0425880c78b97c9e288429d2166012475078305ef8109a19186d742dad22c2b786bea5e86b770bcc69a19116987e08991cac97af7dc04fe2c9f2b8d344083c17ed5e28177052dc0321e18665ae4216747911efa6a128bf8bb408530daad3854eb003b8b2e8fcaf9312723da27d0c5503849efa441213bacfb998fedd14dcc6d8e0c1194d0db65228e44ff7a48371a8f17d635474605a00781495007243ac942db25803920d89acfe15067d01c18e8112cf2f7d18cb8024a99fb60ec0164c8fc3b70bf84a1192262b57dda3bf011cc7c416bafea1dc015c6553048164bfe2200e3d5f8d62741a38ee126544e3960b914c818ee538471ad816ca382c44fb5aeaae0655c02f6b702f7416b323d54aafdc0b5a6d82fefa1f9d8e2de1093e66932b82a4b64c87843a4134e4c8e6c7e968704bdcdbd2722da68454ab0b2aeb8b43e66bbea83c55677e6a5886de6036008898e3e014fe01ea4e523cd89088c1510a094fdaba1458d7362f6cf00bab3156885b1dd467cbf4280b57b9f06e1f30a3e0830d69f827e0d1b8fa370a06228e44923fca7d4453a0a9a942d43dee1c56eb5e828691795614040cb3e67e618359953e2e8e6eb9d0d46004a7cf353a1cc48ca7c62c7a8e278205498034204969e3d45f7b49fdaf137b9060ae626b5e52e89c0bf572c3f81f848be25ea206d77cf85cabb524fb506aa65300a5130b42286e1bde7a6837e66f0de9d6c509dbf6ea2e9a2c01c65fd88cd2aa1953fded9858a352370d8bcd88d5faa30a59fdfd86de911edb40c0c157d287c9514e858d28fd80a337d324f29aaa5dac23a076ecaa70d2cf5cb7fcfda2f6fa0c96c90aee3c8b13eea53bf409b0f338fcf83b84c6ca9b61088ee24a906a071716894b041cd25059a58b95e28c987a1a002be2a57e6f8ddf423d89053e0eadc5d103436f9e0b85b26800d0af843f5e15014883be0f9ea83df1c032cfaa539b25f84ae94b2a1875cc7d62b931f7fb78785a095722ce63589e29950ecca91b122cc3ee0f770bd92c7eb6ccd03b31ee548b85d660bd8fcbdec2dab271f66aaa8b5d0f756baca32e1619d6c73a12ef5699fb43a806435e0d8f371f4184fb89184e0303e77b14dcd7de7fe3cc88bb35b5ab3f73bba838d61b0c40a949a30f7780e1674a3f35830c95ca1ef4d8040e17d8f7cf14f6c51142dcb573d15007d09615b56fff8c8c471457ae85c6ed27eeb77d10ccbb158d6c87c9a7c9fe10207253db506b5913596aa093ccb816ca8585eaec8d96effdb4bf03eec3a9ab90eb2cd2e77d104ada1538189c77178f6d42540622139b0c11a305431b4af142672ac5ed701fa85581c956467033b0aad5b7e04c94ff45fe95370427cdccd2222e3a34347d380f2fda213565f73356eba905f57fdf51f5b00d88e605fff4c5c769e92bd027aad53dab4f9ca3f234049542b1898554294fe0a24dcf82dc8fee33ef34b5a21fe7d102e301ff2daa13e9420701a300fa68c39b541ad67cb1b06661222f47d066289e987dd017f2913990f976b4ba7735ceeb8652b90d24f3517599238e1bf987f8a286298429c6a588bd53ad25e23ba8c5fceba2d28044181236a4e497a41e7b08c6f7ead8e79d4bf05f75d41fa86b60d9632f7cecc95cb7ed97e9b655359edf5dad721d30233a076f1287cb7232445c099b77fbe8fee0d68220baac1a0c009e04f4eca7eeea7996e1cc84a51ff700c723e8936d817e4907227fe840730f783813b03032d9a2c7ba07227007e21e72c6617369f0efc26b2dcf9878db2df5e972721f1d42a1c91468a471016142e57685171c62ba7f6f4a27f9dd07b6605de876eb45c8ce04c7b1340e924430d788a26b16eb53968b2b3b8997c144afc5df3481b7409b8b6dfbe275790622e8705d2ea76d7f4dc05a5532c981048f40f1416d2d9eef5209761847bc153f6d297131a2be0ff90c8e47d1bea261c8ef6513d0eb7c9dd35f01f407908837901980018e7d5fd1a40502f1c1fff97f08790569e6b5483e977d19fab98589620507227a4245ba4c00eb870721dcd173c9e7a86838aabac46042d299ecdc890705002d0f6c7d08d9235bc91d90479b6cd300af1ca114e9488ba066e74225c407540217b3524655373b716a51ad289da1179ee02d01f043b9ff780f052c02b74b28969236e60bf18190c4753f76f8938ee54db7df2f8983c1a8ea2a8b5893aafdc593fb9ffe1100b2ffe77a42555b208a552523b761c400b4f96973843811987336e38352e44a95ed9631abfe77265819d8008b82cc4cdef8c0657f1f38d12361bbb230252a1322c121a534c8422885fc4e23e0eb8468ee9d2764815507bd683cf6ca766de8fc0507c1f4d7c3ad25b790e7d58b37d78d45a4b3e0d1744599b5f434542273e8c4c0aa7b1557966cb2aff3ab529abf54410639cb1159b411c46688ccd2ce87d498f798e105d973cae5bf72f1986135443026a510bbdff1bce41d9f579b1ab00d33a880eebf639095c06814a7878182047283d1da7d6da628ac4ede253aa3b02f2ee41c141f06dc81ff7c0ee222768094a7f819d4b07903ec531578d4bc363a40c62f2ec5b01782a8b07ac82b56e2090622a17bc2f87b17f60020c20dc13c91b6f0c45fd8f0ac0d156848d6d7063cedcf923f45bf20004d048ac2ea5520fa541d8d2620b98cbe2eac4c53f4e7f79f073a38202823ac1d4723f9316d06909acf84567de18719f70fa05225ee43ad4c454df7edb4fa6bf369a5b663f5a401631d7908464483ef581addac70a5e2cff096a8a6c5f883e426005c725afdda85557007bbdb59686125f4ee3720a6958ee670c9c9ea46e21cec2f52481c7c1287a1980dd60e1502b09d93db66f46b5f2a564d0e696954c6cfe247be125dfdfa3d200791f6809fd5f64bbfacfa699b420f2178f6862cbbb5f8159e1699cb8d16754888b6b371bdfa9709d2f090073991bf4364f2787ca9f71e1a8f5bfde015c9d3b80b4f57c67130ecb8d503db9a6f5dd21e5ce74cf1482bc02e632d52285c2394bfc7ad1e08201d278f22906f86797c181d52bf8293ae89e214e530434bf3d5b753623d9efbd3e045280d3820041143049e3df1e830829d9cef8fa29a2730b513dc898735296d21cfb604f1dbd6777799b3565be0bb47ac4b750ebc94de88db4fc81c48bba712ebbdd521b488bc51cc0c68a81b234aac8b28dc47719912d4523020ab21eabeee0add41395250c6cbcd956cc2eb3280cb2a926037ec3ac416cfb37bbc0383d1544e7aad30bcf79eb215611571b71c1acfa6c9ae2aa85c140e0057627dccf67b196ca1a943fca2770501ac60f89380663f28b13ed67ed9755a00604b5d5b6a593a0b0d792ab15e05f71cbc18ecf8037f3b020a5a7fc99679dcb7ee77d1417627f3c6de7d9fdcf7e9ddf92fa5716a8a80b69e97817ca1e0e7623d0d9cfb7a2d07a29a0ab3003fb1adb3a84cea065b2895b266f2fc8ef27682d8f49c186d6a2140c6d6848ad82227e722a787bc137223ada6501c0f43715d457e29af9df81d5bcdee46d690145e152550293c979fef00018a93ab1b0a86389becc511681e7381daa13eacabe2394fdbd2ecec66ae337a652da684a565dd278a8325bc73b0ac4fc9be39d5df928464e1498178d032b2c384d98120f65a08d8195349c6aac37e3189fa2c0382d54bb304a6670c250cd08b65cf95d740cbd962f9dacf91af78c80c61d29257dc5661f386980fdec0c5c2345b8f9f653e95a414f00dfcb000b74a6a156a50bff69e7e29bc411a547ea172b7837db25c1c29c4e15d11ed9c7c7cc84becc46fa7cf819e3bc8577a39e9d883d2f241c446379005e703f9224a0f09d78e073a92dbad54b277ba82fa62e54c5b61116332e7619baef010fdbe31adae092813603293860e484e579052ea14ad37248b160a5a3594a74d6ba886a1f8c99e20fac6b750fce211751d3a4b662cd8305fd483acc837dbd50e271ec604189b4399a44fdb1d0863f23015f9de93a8cafcf3c036aca07de621efea195d72999cbe35581b6fab88eec1cbb869f9619b8bb24c2ea0bfc2602fb53df3e0b986b846e514f22196c7fabe238fbc2d6aa18478d3c41dfa99afb063d49c63d1c6fb6ec36c835078526885787a50ecc7f45d5854763a1636d9c6a0c1e2ea06c27fcf838bf44cf757492bff4296ec484a3b3ee3fb9f2a7ccec384359ed02b2cdc9c0d325f56617bfc516ed62d23b8104a7615feb81da5a43bd3f988af67281e408bbaa23b6b53c37855dbb0b67a69997b42dfa150847fa2d97fa7c392a6dedcd92a27ec3558409f6b11a18289c30e487d5aa4d5b1c09934f758a0350ba6a38cbc759e18bd093cecc0eb35f40ff74e7df7971bb63c59d70dad106e95bba980d314d5952436ddb11e831b9cd808b4d649ada437f47ad9f0a7afdbc89084cb6da97238852498efaae27efb6a0ac9746ee000d019a7d88e5a74388a522cb70d7cb91dc0116f2cf767f733d83fa51b242459e1d929f35964ec9039e4ef0f1c89953f0fe0a9ba0f7ce17a48df20bba3a0acf05a56fd3be095222fefb0802dbf56f7662b51d5fcf79b67d5c0af81065b358bddc5335bb578732dd65288828a0a01b6bc4c22728d8cfc603e80c72c0b11f74d5875de0b2da82b3c87b3464fc0cd0570e450c4dd81b4e9c47db19d68c274b36932c4dafe830b6169d2abcef19de35da980be906c5b06d0339f9570806ae7bc3eaab8136120c881c558532a4189a2b8e6bf65511a0ea0bc9cc54d147de01655946b21d5203e0ba475d692fb12f3ba664a57349a855dcf4b8a801f315c4c9ed831890e183fb7b2906c6dbd4b6e9846e809493973a9969e526314d5cd37a16b1b75902e8f16652f0d510827e62c3210159e1f3962277af54976c57dce633392b339be7b3a81c14f5f9aec48eb3e81dc9d5919b9ac3632b2d36f6646dd5179ebdfd5a82a79f5e5b5dec9d11181dcc6e806c1f06e1d288c7302e6600eae9e2843cc1c5502034d61d41d011ef6813d472cea93f1c7d22ca213bfe22c6ccec776452385a374b87541264760b1d901b8cd041b7ba633142c047a17ed151121c08d145ffa0022e15d2d08d2a94a49cba71a80692386464920b9d6fcc22de8c5a63fd5b4a3f9741cd250979e08baf56beb93e9d92601c966bac33ec8af239ec36cdf5dee00f9cef83e92c4b21d5d077f8b91c463bd623663240f38d9af6690a80921ea8ada7b4f3d98976d35688171ae5f9281fbc5c2159bc97b5b72d2ad61a0147b408cd82779f801cd586f52f10ba2b19a32982ba0027f3ba6e6e403b9d46f6075f3013cedeb6a5e159260eaf458a35321800021212b7703e75a25dd4530ae4a5173cc28cc6853fdd645d9f039d8092dd02a10dbf8ccea4da91ed19b0284a696daf1ee7d0402e73a027f150a4e50f22df50fe789d25743a03ba38c088b59fb9ed06d68c3a789165040a0fc5b7a3f5cf005dceb08005b330657910ca4d795a0b19e2ed6012364ad9290dd9b347b2118a7cb1001a697fe87ac5397b9efa15956834c87d3aa3cfa1f73c03578075ea55d232d74c1a77e5a996ce50dc0bca4fa6b174b196a2a85f064e367b4efc2366837047c731de9c73d0de657e32e0625b54c009d60c8f4876c3d23f17803c6f083f8b7aae37b3a4376d454be9cd018672bc7daf1fdd6a0c43b2bbedfcb6d3ccff56ab394d22b79a68e46e9674d46dbf1be260697c085d6cfd1f11240ba6eafd7fc9b96e494c2560d7133f6436ab378282f829f6f59cdce7e863f1fb149d72b8c8e46ba3166d9178a4ce69ab596d6109c159a40569cb27364e5bfa65ae74a85b39ac1109bb2442fd0c782a5f3b5d8fd36e006981fd8da13ac4d4270331718aa98f8574e723c04c4172917863394e2da52f833f113385f6692f08cd18eaf428ed2191d2f806cc562cf86db53b25bc2edb5f7033f8ec24ceabcadaa5ed4203786fe2d177a4387dfbbcbcb4637eadaf5c3b4d9592a16c62b419e4316c89279fb3965e530a17fc1c6e0104017ce6cb20aed9194a8c0bca781dbc6217ee28551ea3f22dd06aa473670aadf34e4b0131a13b69e33b4b959a57c23784dadfaaf7756aac0ccaa362eaed21a4bfe9788a742a2f41925045bdbce36c6d9ecd45da87e52ba77d9c31b68c674d850f758421d9a5000308ff9992b37df891926045b4bd154f06887062cb60dae2bbfb9069f34a41aee75c1008fb49c5a23b7a639713c57b6e645a6be0c27bd6fd0d2533325bcf9bbc640439c02fa1f7e42545cccdc73eb3b648404bc775965bdc00b81883485ee341270b50dcacc6c98b600a7a3ead55d5bd368ced6365140fff9600eebebec3df0b8c1efbd3281cb91c925e948f7cff0e16b18f3322fa01a19a5d00619a0be43ff413b6a20cfed95fff6b63ab95f3955643718cbff41d1de5835a1bca8e581666aeb4aff216a81a4d509931104e9693b7a07fdfcf923edfdb7ed93ca53c8fa0165c4581155f1738d492f718f59e46c73bf47b87c7917102d13e3a3d07ffedcc68ef4eb25fa3091904e697bac949f2dc6eb2a1d367a264c242607a140ffc1dcfcc476f604cbd837d5b0a8d5d684dfe6e562651ac1000abe0defd10300078ed4e48ea7ad8a4102fbd27c4a2e002f19fb8b9bd919b08df8f0413eadc00e75b7f5771b834cfe06131355fc77794aaad51f56d266c52b0d96334d19748b1969a8297a6dcc0a01af1257fd34d93c8c1a8061ac9e97b4019a91b57ec902e83b9cb2b35fdd606472fdd51ce5cf3b0107adc18dbd37262215a616ad36b28a04b71f2141454a9ba656cddccb345d35934b6bb2049263ea770783a906952b1ecfd05a7cbd0f997dd33662b176fe7ca861bbf1a7b3bca2ffbf820cc55bdd95a9a0ed700746787673bd6b4342dddcf164e5a23e960c42589d7a531ebc3a3a07b6d7b649a8d99343fa2b77255a8b56fbc2f65f5bb183962c60a68cf4ecbcf67f0a7acbeee730809c59f87c98f5d20587c469e2d3b8328f8ff134c39c523c5db7e43119bf2524928a0c4ac02c4e416cd548b35fde426701980fe27d3f3ef95baf041daa93859e1b108e1dd936bd3bd59ee9dd12b0a60ef84b8b8adb2bf37cf02ce4b33fe8cf229d312c848d318f378c29fad68eb872614c857b5ef9876fe4d38d1df65c22cc50672b3a9bdb6a704eddc4d0e21fad1d10627fc01c118cf12c3e0dcf0be63aa79ec8cf25af06bde68655e142bdd87f362fb83ae7e54eb39ada410fc80b9a5e78b9ba97ad4b9dabdd293170627eaa45f9730f491c90869956563b3e42c1dcb00ef8a19895cc63890b4e9c6ce1c5bfb2ba1a232694a7bd617933d62e2c97e55ba4649ef7b5c4afc75bd933045b964acdb0a6a8672a7cb4121d8f5ed4ca3f655b7c28897e020293759ab9bab6cef4f1205944d3a325e9f3ef0054e87b1aad6dd918a4cdaebd1d49773a0798237a1b0347f93f89b76adf30713815cfd0e92ebe149e6f8a0901046e7d249fe126294d72c2d6c59e84a0639cfc5085f7efe80abb7bcad48ac288aec809437c73909c92be1447b9608b45be64de2c76946b84edddf6afece00a4b1f71c0bbb6484826ef1376839c851518e4a5258fcf5248b93c8816154e31aef7d248b6066daaf625711e6f753489ca844292acd4c526369f58c465a95a4201214be45de83cbf47d9b63e62b7b8373b040bbd858873b779f73e0653227a09a8b7937faf70a5795a388fce05324be4f9447801cdeff9356198cfe883de8ddaae27924efba02cd88a4546322cc32fbdb1e917d794a8993660142e79190f7de13140af57757776dc72345ef91bf204900967a189bf75e632edf4cd0463b215cdc478efc5c7644458b068e000f3bb7fcadac3bce3ac808bdd63f44874b179fea69da2c4a11cd6bc13e201120f3dec32c7089bf143db7a68ecf7a396c805f2f14a42be46c7721bada5782091905b20cfd3e24147a58cc0ac85b63073c847a70310c1209c9e47a306e124c5fcf01bf193a754b44f4a3fe7f7690dcdc002515cd730283907115f711e764d4fa0da80ee1ac53477eed6fce5e57890c01745b4a6b8fad9bfcc6ffb75c2a6196317158059eb1ed6aa31adbe5bf4e4e761f5e0110f86b76e5a4ebf2a59329053590921fdc42530f293757a307fe01cccc1f8c33d45c72fbc22258ef17192a52520b48709dc0983e578945b2cbf70f691705b4c64f6d9c1e93b61a8c4061106bd0f241a2c51347f3e0dd25007c252cbce3295a4f74c7f8dabfd6f5829840d74d81a213c1292f3cb1854895a5c266988561a17619dbae6c8f705e121da5a0c05154d6df2d5dd7cf4e62599a8cf7c1fa10cb243fb2c7b797b5bb88549cab23228321b8a189da5ef0c292549939fff6daeb20561a9c37aa0047849423a3b492a87eb7a2162dc06cf721cece0588c8629c30bbf08822f092095c33141bf29c4992622c62df13196030aca5366a1fdf1905e1f1b63e23ae10f9b86aaaa746d4d6cc9d651b2048dfa47f635744b5ef280c3fee73ffe36ddacbf052d34b5647760dd959661577e3bd512678827e9f9fbb5f8892b0f169736fd548a8bad46e50bc02ed95ab0dbef8e4cc414c85f15ea29f01bbddb5a8a7d6b8b043e6e62ff006911400a5e82383eb91782c8aaa47db268db2120f4166cdee6f20b6cdc7fb6dbfbb759bcb1e1958bc6e7e54ec87fd4542e025cc1c09afec81855ceb585ad784f361b9e795f6eac9c9ded9ceb4f3e4e6c52a32a430b8b16cc366a8a305d67ccc1f4e40e5c5152ea74bf02d9d4d1a800d819c74985a73b588b78bac078ddbc22172fa32ff3126b29c13c035779aac24591903955d89150be03248143fc43c39952b98337dcb050eddf0d83c2df4125dbf3e081c1d895eba63ab77914a352ace3c64d0b609b39b96c295d16954c552cd9cb4b87fba338b3d520f607a6c6355b80806e5b394a14bd7bb9682461eb1cdaf28a53087969a41eadf362bb754a3def26099299266191d4f163d7b8faaf389163d848c1ad7019a2311cbd9ff4718f25d61aaea11722d1ca6323a58cd8567be490112a67f2f76224ec487704fb3f46d0bb21625531c73f8ce8623254677c88127110fba6a1f03bba3543ce8c4b00d553cd6b9baf2f65ddaea7d89ae14038807f69221c9cbe238c4b4a0826297727cfd46c9a0e4be5149fcf6fb3200e2e3843f7a70120931d3174825966ed11af96b6e204f9e882cc4802195d3f80c4119030bc55291b7de751e266af64cfd05a23a7e404135723ed5e369e96cf6db5a601055f01362947f62dd9e94af62f1ea462549f82cff43625e793ffa04abe84b1f0a023ae87ef3ccabda1b190dd43d1927de4811b19726f5ac4efe197b4e71d0faad338ae492b2fd838b46562a8319aab8048116bdd159477bdc7ea77219d9d8dddad7bd3ab694917a2fe0f15e72a2f0944d63ec25ff0ac30b8aafad2c3485a2fb584f924129be0381e3ae2745ce4247bbd1a8cce8841ad5995f4be12d8ad5caf31d97126a9bb37810128ebeb8b224f84f878b51d6b2ade2f39726b1b9f792dbf421523b838a4c3992421aeed09b693f85d0f0355da9542f43014cf9f750e4d7aadc9cdbca505c5404a41ee350e563cc1875d98cc19f794e21a32694855cb203108bf7e8ca05246365c45ede7e1d5292019d4d36e8f05ddfa7fee95a32451e86ce3ce85115945b40fe0a36c06c721a8588a4e8bd673441c7265ce9ccd07405f95650a4a338977896ea37db10b17e39af6da767c6313ac231946f1359f744feffc4d8aaff9d37acad7243d7be7df7fa91e5ef3ffbfb4672b53a2c7d3fc493d5f377bda63036033c2396279dd2ff61e5f0b738393ed839156e4abf137d25c5df9e1b40f1185be988b53672cbe7b8f787e82baf5ce06dd73ce6574ca4fc01fef2cf1559e58395d99ce361074fd5cd1f37b54346a4a15a795ec2bb9bcb171b866772ed3964640a01f74cbf741e861cb19d60d1a8e014e6aeba6713d997ec5f1d9677d47f496e0d6aa970e76ccae380d839ed8a04bf59426a0488f042d8a4253780dd9faa1f9eff1b5415855584031ab05a332f053f0b975ac28ae6bbffbcfc51f3a6770ab4c881e713bf7addde8bff20ff0deeb22ca4d46be397bea1aef450eb6719d64dd64f58807b72e019a7544181e958e8c4e0e91bfa24b4499a8992c836fefbd2f5595abc191ea6509ca96c322984e5ee68d545fc5c96e1394c2b3a3fc4ffab3b492cf082e211480f65272b5e18d001407e7ed895e7133ccc767c8b14068042377cc6529c56c2c2d22d048ae57746e30c56f7513c6767a159600d7cab35a58bb439cd6aad8a380d51738982a2cecbc0a283152503a02c1168369345ca1296246dedad6a5864dd378b048994559e9586f39633be2ce55c3e5bb551138a387e253d3ee660bc01bc234029417614ffb0df9679436ddb994d6b4e0b4f69f27c8dc436278d2494c346d19d1983ddcee7f730243f1bcc2916f75fd29d0806fcbd99dde88f4d6dc48c2ed8b7a4473a9c3446677653e7ff5e37ff785f70c9cef0ade332d06d37bbdfdfa886388d59df8b3f416b4426f12e7233a7a1bfae6277cae9d765c90eb26f99e484e8b16a6775458db1ad51f18ba9c059d01f7aa3a76e34c12525d1bb0b1304320e451412975fab529e8ad3e950800e2ad7ff8d4793274c215f5a92ed840d9f3b33c3d7dd6ed4024dae3a8b397441a93df8a8a2746d732dba8e6887e3a7958cdb56c6859e63124ba7e61dc18af4cb099130e48ff0ec9bc179af9c8696fd41bceedae111fd0b28e262452a0ca7f2c62d27c764bf5624dbd2aa41d62be05a578fa18a3e5852529489c597667644c1375811d0ff7c99420bbd14a87c7a832564b7473ca7e9b4690db16f134a45a6db65fc00470885f54377591996efd61f50083cc06545c8e53ba520b2d48274408cedc33b201ec0696803b2813a6281258a7770dc410e3250d8341a89f456884ac5063dea8ff11e4b2bcaa6cab43109aad6e56faa3595e522b32c3fdb0e6b8531d6eb6a02081095aef21f87f9db2a79f9b92e10e49aa97a78ee3e4c5b881d84bb3856b0970c2868cd73a0dfe73fd821333ecb380b9b0dfb80acad822c35b14d8e98cba79ef0f3b9b365eee701ea01cbbadfc40e49c716686866612f781484a5ef7f204a69cda0045cc8ca2010dcc0cb50d0e0c19750b4e425dc3292a8581011df6631b3fa8096f26d1960ad08a3de505b55cd219f4d4a6d9b303b34635c4f8d81e570e2a7ca80762664ae5384fd3c32ca8fea505010d099f269fe18654dc952899366a9c536c211ba2519ef06a579fdc17a997f889aafbf5bb0122d2a54c0d523fd1989cbd3925cd69063f4c6cd6a453013415ea5104f6662fad9061176d3b45a846c7ce1eb665b614cc2faae07eb8463dab9fe1bcfe8c682bde64d3bfef3cd318c3f1c44687d7afad26a31f98cd5fc17d8f5259cf84193bffc716c187b35d11f78b41c61340ec619bc8a07d58fda5c0efbfa4aed17f72408fb879b2cc4cbff1d1fdaca53e02b99f0e2c03c660727eb18c9deca72ebc621201054ce055235fd995cee916a1fcfdc26012c00c6d75e62a0a855efd1800627faa1980021ffef915ffc14fdaf05caa050196c0e27f95592bf1ced55b1f0418b6d95c8d0820f2a497fbc7e58d3079f781471e8195b74cac16fb8cebbfff7cefde53cebced81db6833cc61f7efaa9e1b745c3f924c091ce1f46db44ebb6564f77f495da3eb0823aae0821b6920e9801bb0e0fabf4683089976f4602bc83551a3ef2dbdeaeaafce889e5b839e95f646fceaf4274fbc9f0102ad95f586b0eafb2b579ccf207ebe15e89de46afab32eaecf387ec60af396846af9b73eaecf387edc0a7947ae1afed91bd33366d0d65921eec58669a0980a934f081f8cd6b142ee056a24de89af16fff2c2fd94e4b356ca7b62d5e5bf2c819e857cb6d2aceabf39313d637a6fa559d97f19223d9ff6de2aabc07568fc468a119c7842f8385a8f35b90834dc90b4b3071a7ec3fdc965fe1fc1375645052558fe31429f5411d444ab8301b7ff7a9bff3f88544c803ed41c4470fdefd6aa3f80aac5c2456bcd2082dbff746dfdfba73a36045ad60e2238fd6f6bd4dfa0fef0c5d7ea32f8e1f63f5d5bff04d5c30ef1239b70fba77c79704d9b80484c021cf88053b0c011ff5e90d5d900108d0f811becf68fe340c9903f43870d2870aa3f8bb182945589841162524d0a47fa7b8e062cf2ed9d008938755ac002dffa5b4de64c3d0d0e60de00ae61eb769fb4379d985728c889dc409af17b6620005cdee7dc50a424b0cd08ee0df43492b88692bb08fac0411b14ceed20258fade8449e7407a5037a108716273d0e6a00347186c4198d213d4804135bba836e4399dbed75774d8ba52d4e41defa1e1088f3a222a2aa7b901307c325d0f7bf9073dda975e3478e2a2720f7befb93fc2b167960bfbe60815f222db7cb526676f9d4ddc261648bd3cfe351883d3e3e7ae6829c44d98af529c45e1f5f7d73019c44d9cdf214629e1d9faab9e04ca2acf3b237c1a1641fbab643115c744e802007573d71106c018e90aabdb4affa6440ce7ba8aebeed552495680f235539585b53106774952c64e786edbecef730383e4a40069c6bed9dfb15b27323a3b6f3388ac81c9ca9e4d92cf3fc958191e251c5391b550d861bfec6f8da324570f0af0137f66cc92ce483f18b452cefd8e28e7c7ab0cd63c5370604beb3dd1af208ca32d3035c4532de916c6e4cf6796571322222b6831453359cd82f6fe655a6901f3ad8717177502dd0c33d9aac042193d84300c1010e2e1d2a0a0fa221d09d091a803106101ce0e0d2a1a2f0201a02dd1998643065903918222e0fa67ea24a2881c2c9996433603463b90d9efccc3475e58fe3e085464845844ec6aa5478a6f7a98fe693c51b5b03c5d07f79e302e0a5f70ff4b525f789843f210fe2c5aafff43f417dd7fdd808f5c5a1f9f630b3b3b555be337ecf7c265e31e2f6d650dc06ffca797268df934a9e6b4d7911cb35622a2388fa8c649729f81167accdb09d797cbb8280cd21a72b53d56b7a9799b37328191290d53240fcc61154c388d0413fba259ea640bdf36bda793f40a3bfc2bed59ea1b75e444f398c77173dd9d52b1d2ec13a9bbfb835a0404813964906c1301c32c375c8146e86739485203bee1c207cbfb89c96494bb9af6bded9947229cc442a4a692d658d095614cb30beba81fc11febb175e1cce29c0aa800ef4bf14483911c6e6cf6bebe6d42756904a115012b82c91c18b3745b26d380183b2060963fb8881e273d8bcad8a972d5c293dd37830b4fecce55eb7b100053a438b832bc61bad85a1a351488a5ef22e0d47d64214a4699b071a53e3c0d6e869cd08b4b3949f9ea7abe536a56b0d1a25474a6956e6ca0a7f4580047e8bfb7ccf5dd19653762f1e7593bffed11bd3c9365bed7e694ec0a9a5e7862f5dc83dcfbd7419ddf5e7f6a2526940a84cf119daa3ba64578c7156319ecbb73f0f23e795a154ef78824213f0a02710e9a46c37ff2dd84a40df616d265b974fa0ee089ecee4042efbeb612d7a9fdcef409d4aaed4d9733f17090b45193544a59bd60a8667b701a6b8ccd0d7c2b1293827dfa3ba725e8596d8d916b15767950035be6b5be8cdd0ab27638e76db52850df4d79ccd3d02c978c95257fb9b390c8e966e0a603a76bf3215200ff60531dffef92f40c3a8aaebe498d65a73d67996c354f4d7d25ed3438884179606fbaaa9746b455d80e1050316ff4dddd0434c29dd7a68492bb0aa965d7b262c93cd568f35fd87f2cc19e02d3178b334271003b305cdb6ecc4a0eb10dcaaecd0b28e2daa290d15b119e4ce35167f38723d290f28a973395130f7ce75c1719d409b8c7a43c623cf8adcc98e046d21fcffaca163724af94b68d83b195d15200a44a6aa26df3bb8434e9a5b0f293d0bf7cbe71e3a6ac50241f774210b6d1b5a44edaab42de121d8dbb454103653022182130f4049b26fbbadae5d7ceee2c36c98a08936123e5582c012089184cb4be726b1490984dc5830f6a893d7bd290fcf64adac4513f4ab23dafe2981b0f0fbbc5ca5744d06bd2e6d92723de18c199aaca0d9619d8efd2a363794cde142a2aa720596a5fdf781d2c20f251a4f06bfa009341ee30f7e83c053c3da819c4d7e76cc77b55be741ccc248e3a532b9ddf77c6a9d9ed0e7e6b701e8cb4d3aaef4b11340fd51ddfc4e478d0e1305fa479c955a3b3182bcc9f5c906c22dbb939dc378d295ffa92fafd73c40aebbaa454bb0fcefaebe1c71c9ddb65862e067ae8bde8a1b498c114050da1dbe007e14e5c591e81b17ab08ce03f09e9e87a94c3420b3c94e4dbe491386290f99bc6fcce855e45fb0ae05f5af022ae6ea552e688b91d95f6fd5c19f4eaf6e0e279517caf106d949ae759e289ffb3a71379761e2d2b50ed1008f034e4f0234be8dc0f1b9252148757e10e04736eb4c10dd1a69fdf7bf2bc75819a24ad1ccb4217058f4b2de13f29621d0fb2958b576a01d9cbae9fc36bcc3e4545d5714c8b8d17dafe868affd25b40d6b361e4d1c1f866b5053916b2a2fcd513a4e39f43302fbb3a417b386dae60fedff5ba28515c3810367347f81d9ab706bedce609472ace878cd0fd037e1c9296a3e182eecf063a64d1f17a1234ab5c9fd5634982d46ff7aaa0f30506f4ffbc7a4fc4939260251dee51f64dd3b89c8c48610e1ea70d9e27c3192474dacb7ca7cf4c6d03ba814e9855005c4614f6929692b2ee2101ac470ad5a6cfc56046d637b85acd1463dd542cb4cb511f1d2d0efd6f6a4aabe87dcfe2c88add73a7a9eb0818cd355c114e5b1c9456ca9ffb4e4fb4f3de2dbb44f19b9033c04856f56e8b77736f331a757b77fdcc7d51f7f28cf21698d193d5605b1d72125a6693ed546902422f3433c6ae49521d203e4bd9a6c89807a77812d659d6b30b895440c05df26f47f45a999190044ecff8c5660e04a02b8014ec4afa2bf6be71a03afaf4f111f81a07d2353e67362d8df54e3001efa798b263ac44a1dce3d00a60448a0b4b4a9a98b03c2b669dc41fbf95a316310381928c96f98ae2763fd36c5691343fd9b461b89befae60ed8a4f403d9b760ad5bd8ceb20326d4a899288044df883f3fb062c7653791ebc78e8b43886688755240f6abd24bb3e075b6401409cd8dcc031aa14ab31cfae32a9244a0c130bf85225e888a74c67d1ad11061ad08e92557e05d81540035ae9411e315589732b26b5f660a8bcac2b739c9456ea8216df980f5ac5541ecd610e1f3fcbbb2c9b3ce3a2adbd8fe336eee38d8258ea086b82201623061e5f4e505e6c21818a0f48e7af5f6ef3dce3a68401fa8ae1ff52a8e7e55b8376d7b6ab9ecaa6a086004e1704fd051b39ec76f397ac5bf2588f4fee9a8430243c7933f0bd6e206fb535b956c07fd41dab7173ab8074f55cea221d56db404acf75ce888564c7837c534413c16c9456b86d4b8f58f1ed8ce4c9d7b77dbd3f56a34a95c4254fca555e5487208e6d49281944b4a1228facde5e8bc311589ec4cfe237af8ef010d0b371b3b17ce16fc38de503a4a82e9014d73263978d6c4c3c861295871dd1950c76c32f750949219a86f8ac82b82dc67488c0c1b6a22b06cdeea444cf5e1e6e3635113929ee8a1d13929d3d178e4d518722baf5800f1823ff747c34ecb14de2453ebe0419b98a066e9117578aa4ac2f6a615277e12de517193a500398f91ed0d635acc9feb2708e7f8e1826eb0d753466589b9a7148c908fc75dd917cf801a74681513d5f494bfa471e890642e5998f27c0421268a079c834b9c960b0c080bfb3035771b945f3d28fd241adc87edd6de1e7d359fa14195b2b4ea8305e89c7f97a1c470887787867bbb3dfdaa297cc3e37b92fa0e484dee4f682f90702afa1e0b86f834210e2b847f0380a4a4b50c0a1335d2d34ec515941b2a4b4dd1cbc8b0949fd46f1d4fed100c4a8b64429352d270cfb440a07faf72a457b181c4929d406a753c26056095989c863a08dfcaa7c9700a68a5c04ca81c5ff05a0d7f786b0b79b897df1ccd138788e8a9db955d7761975dd935f7ab8911f795b6fa0a84e3be3f19c84728952b31e6450069a2a1dde0fa20f8a08bbd1de325ee0834b796c9a95f9403243e925780521bfbb9a2aa2871f22280bb30a50fd4e8f89936e6b7a90eff23dcbf17b35086dc83918207dc633aa5e76ba0ba7d1b4fbe332da3cc796c2cb14d9505b64748d1cc4745833b9252c779a7712193afaab87836f28ac35ab8798a951d0107551e235b8fb3fd35002c9aa99638437c95a01d1f9423e21ad98570bb7e47b9d90f4ba3e55c9069a8e40a2be1028b5d7b9cf9284bfc07f7c0a04aa5bb752e97492cf82d11012a38e9d15701102ae67ab1cd042782025d8361d93acaafedaa97e7ca3c3dd17a2ce4c3dc76858d2aacbd89619af14ebf9f8dbf1da5b890d9456730851c755dc2b92376df033daf5b5baac06433530266a6dbaef1fcb978fbfa8b39b4b3c152044444ba838cee6bc64063d64271e95873fb2afc8735a404d40e207b28b2c9cb581e629e1149260bc27dc03b417d43b3154c4031148959cca171752a87952e890c4a65c8a70649002f5e3d578b03b5854ea64e18314d4a54d7454e0c0d2c90472bf233e5b3e876e67d51734568bc32bb4c85fb37a08283b6c4baa479bc416f1cf2d4a7108d86dea64fb0e667e3db03a1e6d8facf776651b9d5efde0d3d0e1a29835ef305fa13313358bff79ec9c22a1ded10100b43e9453ea15e3e357071bcd9826a09f3025ef13b708b2869b2ac38829ac96e548aeae3c629d6f907197fe2076e23f51c5279bc16345effb885169d37b0b9efa3527fd663eacd046d8c98bce534dab101c0b66672b40fa15f0dcfec567c32103a571cece81a9c8609e67450eed5b3ffcd49718d134cc0dd8e6284660e83daa468cb3cd900402e597bcea701f58c9d249e57fe8293d24a768559635db49a57daefced0a1f3b4093434fdef7483e9a8ac66c214a12e9f4479a9e306682165c919443667ae260d9224bdc94cb61d6ec3a5098eecbf9c9a5a89a9f857e70e42dc0ff26b1254feed9e46428bb7d6293126873f95b97607aa32ef27e819abb0e0f9dd2d12bd7f77d7e2014d6bc4212c361cb1b3b1b1736827df4871ee71900c4f2a4dd2196382dff8a2549e4dd5f1a5b0bd28a0ef7705332d601908829566c23c05af10f8a960b01477df8c51d88994de43ff0067c7efbfaca50f2c8a77cca0979c66add06874679d00bca8e130c8bcdee79111ff6279ebf122b73a816793050dee505059885035003abaddf011b4c9d04a864682042712689c991893c4c92a74fa299514b5421a56ac43b9ffd84319f7712986fe7f311ad7a04511538894b785f460db84352a170cb5d633ebb61b01c05c7fbfd71cf444f98cade0b9af5a80c666b2cb46f6f4d612bc07078f4eb3ed692048bb48fa26946f18d1ce543411b1444442c9bfa7a6f58defc94dfb663efead6dbce996a71f77e099ff2c839e420a7a0a19e091640dd2871103221ad5006f6ffcda43b903fcfbfbd1df24516aa248ec1c820287217e05384e8f83ba3e189200c0e31960833a6502d89f644be49adfeef146c95d0f5e2a6a12b858cac24d43e7847b10109fb717d18858c4594912a14b89079b0f9ba03b6109f736855b6bd126b0d882211d710068126e4d97cbb7b57488330d99554cba0d7253b3b020b44b51820d1b955120bb1be96d3673c38f6842fc9e3d3b58339d37b9796eb0f0a8df67a192431e5c9113fb6fdf701fbeb942334f31b324d84d7151c3aefe10c0351738bd2de29734ceefb0ded8ee41f16de411a1264d0129e8d70765572cd8642ccdf231b2ad288be93b05ed0b0c1732bdc4d9a24ab9971f3d55499ef3c1a510f14633209a076e1b7be2b6002a0f63f68fe8bc7d9077e66980e89fdbd6db3fcd0c2a5df05b1400e57b1a8a1cba2d7417e9cb28affa31be30abeaf74300b7d1b77e8c0b46edcd171a1e0ffa4c32b80b5635e0d14c4bb2b1cda13c4be8906e4757edbcedb4c4717837a42b4ca9bd67fa4743ca4521d7c3f20767611b961a48a6c89260d6b317fb7f12802c315bf3de25d401921ffece4b629dfc3d3ae5bc6eafdf4c3185147c20510159fd33b275931c38e4c59e69ae0a705910481e73b48b08d1783db2a24a59f1c61c90caf368e7fc6700d174a750c3e8938d47de448af3009fb3d3b679a355b0a266d27d2ffa5fc76f71617274c0401750fb750a080e983df408619794d5629f783a9ce671e6160b59f0034013dabcb15d13a61cc16bf96ffc9672e48eaee85400f2795cb7eedd22d05f3c3ebb1dd9922ecb3f1d90bccf14ba382a9eed49b37e0385d5a40a45e1920a2203f88b8121458453096cba7b07134b22bacc10352e728ddf8cb594512c184267887815d422a62cf1a8c8c35f899d258792fe75f9e5ede69e45addb744c0514f087235de03657d279195564056e4053d752013a591506ef12d9c48a0539dac33103e591d6d8abea1b1d334228f92d3b5a49b60362861c6f889388bc88b5645e1be09c4460c81dd144b28271011107e549495e434cd6c1971340662f4d086bec5be7baa2fe77e520815dcad99b570e29495c447de20227346e0caeace70763ff688641cc11e90792f8cc10f7ab67085d0b7e1a0d65c24a4b6360d22a703e9d725765f461ffb38e75921443e0faaf5add41bf8396b4ae36f3bbcdcc0d1f87ccb15fac4c293bb0393dbe736441a3be4334694308e5e9753559706f9e9a7482473e8dba3d8edfdefd05fe54105d17bc8b5738e58572c543c1759a6d641d3411dfd13d7dc8156315394ba595a0a985ea1665a00ddd068c3bb02ffb73e097ef2fda4be85ab1f0fb5aafb526c17bd5240129eb789e23eeb19609977d1430fbfb1c6758601f5e246581c597bf288ff6a46d962706d017b91c3c7d481567ac72315568be6e38c49b58eb38c9645190e3b42df68d3635761441de9c31aa00eb1b1907f08ade10d046611f865eac93c734b611f357e4a72840efb8f8a040b54c500a8f964541bc41caa04364a9e84ae72fb4cff70858dae236558b6b9b5fc45d33de30467c2889fb91205ca10320bc33fa76d16f0d00f7edd20f771e10bfb07e14baef00f20bab8f281d2764bbbf29b26ebc0d374f7e1ea914402085bd705f404e8fd786862852b7ce5b8780b547eba39dcdae965c499f5aa5e804ba0cb894ffa0bc271b7faade5db46f00d99cb404dbeca48fe5bb985b85eb5a9b6e9f203929e435e7a2b15a5c9070f310478ba9550041dccb09119349fcd88f4296f89462d0138169599a7aa261854fb23495b2f07fecdd98da8175e57ee904e7c11c9456a00c1e259557f895472b056215feca2228c00130eacf379dd4ff13cb42115778015984c5ff78872bfd0d97cbb0ab3aa651cb3c903ba670ba1280c85239ad48a7f0f66aafcf4286ea0a168b2b35720a1d7f71e48825074bbaa31f83bf113a70d5430b6e462d0d1611df83d27fd68d544fed1d0678294046302d3db1b6a6d46d5f76820e1f4d798ea28dfff898d339f51fed6ad5e4d5806ae78af71b6dfca8e828939370f594fcd79967c843534f6139268f06bf49130f1b6081704880629680587d02dac1adf2f4053e63f07d49dd0566870e944f0d9bd642a20cf49bff4c0ffb2ee0f0c8367a5c132eee91aa42f56c04a832183e10ac000066f41a0c06462a088104c978f105950b105cb9e2ef21a261158d0da1a4e1433f2228e2577b66639e8b9771b8570baf61d109e8b2a70949f0c2382a043892a0a08dd2cc873924d6aad5ce73ac1f403468077259cd2136c4334d420e2165aa29f00f9bf4378cfc7e48ea7ac8313ca2cc287fc50486bdcada4011da0f131bd76b14573e3898e25fc01782efdb710c6356cfd73e54d797b0e3eb3a947552c4a17312b0af78b944b8a08699157ea19d68c6d81ac49ac93e6b1e26ef8a34bdac029002c2c9b83e0c23f89f711b51472831101ebe3a8f976c42e9319cf5c86672ce63d8eb746902849f3045fee09d1706a9aa4d9e29d1bc25ff8646df85e5a109cd7e2884c3f68c6934d5fe067d166566e2083e8d78bdcc6c29905031fe397506426f20525cd1d72f8f4d230b77261ed4b270eeb0548a5c9a0e8d9267123c3fa24fa00fa1954cd478c293f1c9582d5e7b6d6083d6fa33b695a9cdcd2737ca820ca724a3f6cc2ae182c120bf9f1e30f91f4896c9aa355622fc7d398d0c021a9364b5ddc562bd234bf33e6079e112b86a9614add5b3ec88bb4a479a5c934dda9b3c14fb8b25ae65f0b257b1d229f8991d337e1abb6fd3fa555b5e8793b6555d532f238ef0ec22fd8b2a9efcddf372cce05058c012b69721e921d523492f09e5e989387a25bd657ae4d3cd6999c2482459aa8588e6407259c5408d48e1a5f2f69035fe87e29f29559215eb4f38043643c6964eb809a088881a7a80e6272064ded66105a5c823ed09ba2d5eac31fc72b7ab28b223db64f99fcd5886daf6c5007a43a9aa173065932f82599ccd4a67c86d82db18cee4b533059c33a2928337394525fa0a23e2bb30cbbb3cd227f00165228b8deed0d0e6dd7f8a5fb9b37bbaa7ab32ab3910900343b7a97a8bced7ffb65193ef9ccf70eda841f6863c66085418a4f7c4a7c2ac2de610263675f0eb010bc2122799e42b1ee858437a0eacd34b85629f1ba82e2679bfa8c472173d64f259130bba13913f64ba4dceddd514510ce8f83704b93659b7da18d837a6f45f59d395d04fcc79e7465917826332423e82a79b71cf6ec4050474952df6cbd7347bb8e1268258374fa9947bddc240dc6e404c6f2baf1327c4445f9a56299de61b54ab9134e61f6f193f68f7d1da0297128173fab36e1c9dae19a07a67bff6aae9bede19502f5a2f5d2fbd574d2ffd7a0492dfa6034483a044cfe712f3eab38a01cda74359008ccadbaaade4553ea0d9a3c123cf9d4b2ea692dfcc6a7fa8db33426f57cdd2ab13ccedc64eeaef1fb58f3a882b7851ff34f0aea1065df785b6d7c53d338b429c52738898c24babc0ebcbf173441ed4eb3db39b8417602b5268bb19704489d015922581a78c1bf38cce634cb1d26f7621a47f9680239c01f7c273d09d06950f253b36d7ffebe1e3de12e4c38e18edf3c320b864ea2080e1fec2ae24de81fdb9d95ade976b85f66a47c6c43cc4344072808195b6ee418b15063addd97d75c3953ab1894fa5cb6a7017d7dbdd96ef58dd3df0eaa57cb5085af7586249b8f351fdf636eba9fdc4744146bde75dab1d0775c7b3ee0da8808afde7a7650b4be856397a5ea8874213106746fa2713df8a4ff52caf9d08b7d12e67fd32309eff3f8b7dc7dd94ecc4e4fe09a303779f9bbfb9d10b2d6c9538788020c6fb9077146e96876bd086457cb7f455d70ba85f0deafd9be23e64fa0180fe70d03fe1067e2033ecf7d483ac21ead3d5049b203ddbc13fdaa3b04da340df6c308b9dfd632ebd7def3604ed5f4c3e6086ceb227848223d832517e774ca850dcce9e434d417ce2cd56cc11395ad9af86c0055b07b12b896aa261fa96397465a5561d0be2cd510b1fd2813c0bcd16b54b38c1e8baadf85260fc4f6bfa74edb25ffed17de80aa85df2483367db994eb696b9b21e6244f1f404fc659248a9195bc2005377806ba7b55d06b8c552bcce9d470019c400370c7ea72937311484d39a04cfe703d3cc96e9b3b58efaabd2715a4e404ad8d3990b6cc4a6b21bf4be87057d585d73b91b05025dca44140389d586820804d25d161a9397c97c0769ba2f51b8c3fd047f6a5d824fee74ae57d69edfc3b29a6b57b0847a7d4bc8f162336900f5f0fc93cf78b618ca0c86a2882bbb6f83dae67a1383d30ffd0031d83ed82206855242d295916971e9fd4bf9465a683ccb629e9e700c7270e05c4fc33791bc7cbc77c5e321f788f8310906e2e1bdd891ef173fafaf3e9c998caf7836df66f2280e776597d97350a488eff107645599df609cb4c2771d3493424a44d6cf4341a0d3b5f4626114ed03da146adc7de1230a4e1103436d6b49ca4e77dfc9350504a4802621efea602d9a7eb45e07d3a84c66da661f7aa6dc9b5035b6a6d4b97a361c359a97a07726920fc59519b2943a2cf76c977c0c3cc6c38a85d776c2fef9b0bb7324f178ef9519438ac47ffa40c3e0746293cb58a6cc87bc269f7634ea58e0ea42a470e52a852ca13f51b3d30d11217696e9a381a249f03a869db856fe618640c673974a7ab8a972d81f00c5cb8e4aa1269529bd4076f9dfbdfd5ce4995a5aa7a5f7d4a9c917a9d468eb965d0337a3d360b2ee54583f0d51c102ed78e4a1a8b3099b3c2d0b6929801d48621344bbb7a83b9aac328a46596651c54eca13829b6b6845db1c1e74a1ef5d89a05da120357db66ed7fa340beec8718936e83a61d775e2eb56a757458d529cb26bdcc638e7a34e58cfbbe81c1d8a29d3f9a30aa6067f1d6d9d28ba345c6e38ec74fb586a6c127bc080fc6ca625ced651950cba141505554916329615a8b5a95a84f2f76adae0933baa1b32407d8ff4f8da693feba68ccf6bb39fc832681dbf3faa397e1aaad6c2fa2d54fbb3a85c1626d2794efaefa2a4f3904181c84c261a722d70146a777b718247a427aad474638255e6ebfea2ae598d5d9ee80dfea15e542900a123e162ce9a31ae2ffa5df4f1ab2f36941fe961a5ca1ee75bd6274123e40d32b85051c3beeef644377ddb555905438ef26f8e176a999f757f8ea516605f4cab2d506a4e0bb8fb8a3e798cb51ca9202905753fe0e1901aee81318fa16c258896c4974bed848bb68e4938d7dd2ff6d87cf5a60fb3756d713f134931454f64156421cc9810d4ec91d0ee1d7e9ebf9b3b3a9c0621796392026c00f51234b325083dbac576dff0815818a2e51f654ad144530fcb9c0e6d2978e2d7dc69f62eaa5842da707f27a4624994742d5ad012ed585ce0a2f9e9d241a81ed6bd5b5d01cc3fb82868770cdd8234ddf49cbb411c11689f76c7bd3e43cd2fba3075f8e67b3c5b72f0c0c2e6fb5b1f13257b18d2904d1eaab431fac4a310dd8f216baa6a2786d8c3f19927a7d42371ae72a95667c9a3b72eca2e53aa0f9a2bb8163d0d5543ec631285163b86f8474bea733dc27895535732a56e4bc957bde7b11efa4700b8d3513fa2adc1bb98026fa4ae2e7b9cb3d1746f907cd1a637eb2e1073a988571313b9c86e734981726f058b362accbefea7b32daa6549c90db7778e21cb416bf0d634c069a26458678274d02b70cb4d279d351a9b91a66b931336e3b73e1418d3c3018a7f451de6376a965ac24aa377c2616d7a7aa2fe303e9a9bad14b4ef2e20e74a156d25f987017645704f852920b672521393ec2e7e426a838fa05ef6b8d2d0dba4987e0ca618cc9123aa8ab2b5b6f9274588a0265e11ef296ac494983d0610cc5c6cad77fa5694aac38eea58df13d1d88aee8dc4df40dc0de2de20ce0de26e24fe26e26e24fe26f16e50f16db601e9b5901fe81f4c4c020c508e81f5d02510074c41b8547b7432875694492836f7af52d40af112f5c598af1f2f50f3cd95253a70da547afc753150faffa7b3744fe4e401182077729969ee54d6d51365856954f3188749a28c545df3c59e0d23e2b64648dbd5183dc84a7511cd95753e16356445f5438244c72ea8158eb2a75e6c5fc9f5366a75d50aba2a13701672012c9c72a68d15cfc92ae9c506bc89dd137261c78dc03462ffd89506e6eafd89301be8b0df5a5c3cf6e231e6143ae50617877a6bb8d863b779c7c6548dd64220d490886ffe198105fa444fc5f756a43446cf6763e59f70109d883d56891b11f9bb83fa32ec81df961315852c2b7ebaf01b6d3f03ee97012ec6497eb832b9b1d7ccf2949f7ea8d2ba0faf2400f852d1e9ab5f7ad34825ba7b32a7a95a659765e597681c08318f283e93af39008da8ba3127f2605cc5acb6bfe836953c6779c63e88ea8ff1601e1b5d84330e1cc56bd915f85025cb38c42600a8cd6929d4d0cefe70cbe5532fe581ec766898c1e3e223e319aff9ef8f7e068561f32a250b5866eaa377cd01c445fba7be92b4b1939e4e1ba8c5f13307a0133d5ca184e419da66dc47ea1caf24010d428d76e339d1a5ef2dd98b174b9890d0f20e7906b830b51328e14ba91aba3541fc080740683833fa43b1c2179923005d465d1770da9327b08afb57017709848ee8bfb591d93e57b3aea7e9e9bcc03b2e8764ecb205be5f59b9cdb2e8c1491fd9d2c6330649ea1195acd36e1666158c6ef307aaa7434f59e177a9a111d9de1d4d958c90bee1a40907d862580af3680d5ac6db548b581307757e55809322ffa5308399d2d2a306403b3712d71fcbcfb58ff3c9dcd27a7872be5f0e1a975316ab7368242c4c626aa6eade31d2d42901d3846b96836faa55b2caa2249c1148a9be8c9dde01ea52c44530cb2e5e573d61fb0390881943a6d211ac27b90989005ec245c1945bea85f600592c66273c08362eac5d02530d4986c4b69d9d78023008e5fef565292c71773d6d6abf1d779f608b5859852643f41019d565c82eb99c0042eea5c47308ba00f281932cc3a66ef0f029ab9a35bb03db2c3615e1d02829e5cb9d37bb30e627002173b27975fe010316ffc1b880818d022d9e2d7c25912707ff9c271b2ee8f1ba8f419494446ecb15176515d2b9fffe79ba287f049de6c8c5801aa887970c33a4f75942e4f0eb56f0777d281235c3a7740ab98358fe1ebabd3543b75ac3f93315ce927c4568552306ab53afe61d8fef964930781345f5fef056da13c8974ab6fdbdbbdf36b187d3d4d5ea5f734025af0a42b3b4697fd10396a7140e24860f6ada572d382da80b3506d130b516fc973770eb25901c57aaaec8fe7d45bda3c07eed0996419a5a4ba69021b0ea1ab4422a0253fb83601bcdf7ccd2ad64b4d939f2ad6acdff1159ca8d4e02a9f0e3e99c0db61dc416ba5196f520e6c08db21208b1a750924523c43639f31f76014ae106112b0e3139d7ec3c24c54471ef1e740ff73636ea5df45a7c9142b6ed04c3d31f27749759d80eb05452b46ef638676827e1a8beb11056b6a6813e8b2d88260bfe80b3c06e0ba3fd152376299cb12e74bac5188131083e63309c0ffd01f890dd3901324f7abd643eb8f08b68e167fa05039c858df364aaa36a3a18cd3eaa6f21305b09e66344caa425cc4420e5c8b7667739aa7a821c5cf1aff470f9c08696c43ba38302d640f7b23b8fd286d26a00670649137abdc43477e8ca7f7edb313f117cf641b5d35b4d47e4a1caa746fb40419e234995d06f35d8f9e04dc2297899a0f77cd4318e32c9e7d4cd2cb7a6e415d3b745bc15815d98ff4e717b6441194f3e99ee8a7690783851119d1d7f80e271d32d08b9b28b67ee880e480366c74c1291d0f376ddddb6771107a9c484781aa01a834d12f3d772f94dd8e470f05c1c016c58e04a4d3a33a312eaae293d4b78c3f3e4def4a694d3568d4de2c5d24308b0781b70ff37029a252d18a746d9a290d76be6277f851e3da79656b04282f9461d86c77524389732ca69ae42248d8e64a042d91c75da8507ec00a07dbe22f08a54015f1ba4ae5ea06b027abefdd137cd85d9104ab9eb9a2098cdc7b59ea78a316d1d146a8e075f8b5e80506dfd1328446fb6391f4e699e2a38cad487156bca6afb56ec36ea96f2278a38203d431816bc55cd62a28324b22078542800c25921a5429c2509f169f44189140c93ec12f4a8512d1434d8c0a5a3ee32064bdba8700c3b71798aa209c7eb74502a7d3fe7b240a7648683986a0d184418b6b0c64637a10281a87c529f883fbef14fc10da315b47bcb91d4ca30d97ac9c44a99c3456139c1177220c43a287941afc544fd59b4922c402bdd58782346492b135062dabffb3e1010cf0dcc1978c62f114dc049b2ac7c1444a321eb4564e4163938218f27a7a02f1f2aa79c129e17c090c3c2dcb2cd14a5889662d1adf13b427ac4427fcd84fec8c9a559e62e4fb5802ad6c42d84146854984cc4506e705a58c80e2d10275eb89a6da58a89c6cf0ddb6a54ca882d3e5fcdfaeb5256c69b58f2880442db4782c524a049266b9b97f6a71b8d99ef91d6d70f6d032e08fd4d542b58f888847ce4418ff599d1cbefe643c8fbe58171ab24dd4b0717109ee1913e3f802df8147673432f88ce61ce0aa880cbfbbf29d60d355552c9140af4dcf74c87834b28114d4e6d9a5bc4fc0027e2d037a01ba46087614dbe512eaf1c07a923ba59a1a2422b4e29aaf0a1b2684129af155e220f6b7a8dc82440400db87275233cd8ef9a05c5a0a618acb3f0f1521f86ae182967b88c00a241fb26086ed98ec00a3bad58a8ccbd5d280441813bab0896a805dfa16a89e7a5c821b4390208106827687fdb4d4eccface43952a27aa86b2b4123afc0b1cb9779f706bd44287c00751c1d218fcf001043f0d5a894c6a7814009da82a18d2f36578e8d58b7de502a1027f566e5b21394300615180923439071decbba2c3335d969a36fe8762bb3237780b71d94acef87354065360a5ed3991b748de3d25da5c0e49bc697da726c9edf975070379c9dbb4eef8d740499b9cc3f461964c3b3908111672b835c9b2ea30c04671dacdcac77205b6cc5ff85eca2d18ebb82663c46291dce925cb868f92aeab2b8981860729eae0387d966004d6684b4ccd87b04e50b324519fd3f0b47151744ac7734ac9630dbfa4995848cbd8cac15983b9caa97583c12ba70be10211d3970bd6f08c020ef0a7c8b2a0a5c5cf9a5afce31eceac1e3794d80895a96ff6820063f5325e8c063bda0897b7753e8cc6543d63dda1c40194646eb6eef660e0439233b18ba7d2677dd049d304aeecdc76539751b21b65763b387dd3b97f5d72e7bf929c14f264888a9296e17d822b2e7e23b250cd549985ced248df24852ebcf7456acb15cad278a0597dba5a9013b50291d7ffe5ad2c9a32798b307fea71c9a88a27a17b581f321b216e393b2b4807b27b8e052694ee8a33c32ab4dd6e90222368503645e25377ae1a8347f82b4f86a0863d6a314433fa43a189b0a7fc3127e1b35e04db976391e1d55385d11d11b5ddac2cd34423eaf2dcac5b35d8dd4e10adc23a15cef57999862c7378d8d04c885c32f18dffa5272f9935df4a626f3c065f6a7e1e559a9fa7155b399dc0d85280236d53c0053d8a7b9cd82adc57a8a99daef49aef697bc5d974c013930f1612cc389dee2bf888d635c9e25d763a8f6b353907cb9d54a8409e07463ebc6288b5e010d5b1bb11143fa548143e6fae505b1d84372477de42595cd16315e1bd6711cb8e2312472c44de0a5d7ea0d6ce088b1ecedd994676ce82972931fd51d3a42521c6d9ae5f55adb83cabb98e79de8f706c1d6a1f1e8f5a8020b5987f218efff88add23e282fe460681f6616bd7590cc21fac45a96391afa1c966f2c48b2c39758193751bc1136a4f9b78b4829af85ed29fa6be5c09f1b465e96b5547e26e59dbaa12020b1832954e16212f78ad43e4ed0e305b359560b29cd1749b18cd8443017c6ea2cadc021181712e5a5838a829d1af63bad343853f58839587bd1e0ddda38745f0daeca8af876f470f904156eaec58aea59767d0f9929cbe4348da8c11a9dcb354ec93f707419043e43cdee5e36bc592e0c4ed4fbc4494a93c4191b55eb132f87a2a44d60452bd431cc155c643958125b876c243f340cca88a51b09d23197092211b32763f25598682f7ac45ab00d4c6ae546184d51b1106e0b63e6c3674362857c2042cdfaecac157bc92f995562b6c25fea3082f3065354f42342711617041671b544d9b9213549e3da4e3d5863200741666bbe92f82c4206bb3c73a360b6b2c2dfa021d7db958160baad3a9772df673556eff0d42701a086a2b788c256727ee9eab4d0dd3ee2e0e7707d12c02b6c98b808fe071f560ba5b65c5ef540bb56fc2d93da0920b8b4577d14f94bcd1c8c0600332c2812c77e63b2f197559ec86fd1793dca99f75aaed95e7924999ecece46230fc94f1dc66e8bd48e7bbed13c98be5c6734539fbace0190fb9efd9fc0af4d270f96791afe008328dd7607682c0c7e8db067ecf1ac3e0f9b54cc2266f7a52963dfbd38934f58c5666a5be371c82593c8272d8d9163db636ec4f0f5c28a4d52f0b28e6d9c09567cdb4695d8134921d3d4891c72c677ed9ac620110a2cd469aeb7ae3cf91fc1b3180ec0867cf203a3ef326e41b1618540bf7133daf681f32904d7c353e7253707664999a71a435b4262ff33cf3ba9ca4a5590df5226e7ebda7cc1e97fdb5db50be765f2bac2ec1208666c91286eff70de559badb4a33318a3cc297acf98646298a6a3054a45aaf8fe365b78210ace8e8c59ba151be14dc43b808e99f5995fb4898325a25ce8a85dbfd2ead9255627f6ac08a999d3d50c44881d9426899bc5dd3c6e05e0f645da40d94fdfae97116bdcff440907e80333b17beaecce10510c668d96403358d2c84b3e12b16d4b91f6d4d22bd4be07fcc9e825fb5319050bd3b2c160a4625a9e519e4b96b1ccef22213b5168aadff504749f690c4cbf976dc5876e6ce533870dab48614def054966c46aff9119000d3e6026f084badcb93be4d6afa0d1b0d3c367f4fc2a5e3d2b8802c38c321315b8b8a4b64b373a4cd19c3564436e5009768dd904966812a42fe54bad677a2583c45000ab23f25d1c77c0254d4636a7a0304a882e0b98846606a10763ba03cc0a0ae314bbb5481cd764e615476091668b46302a606151cf56a09aaa00f8cef39c2de24df360e7727c048ac920a9674182e6b625c7362321cf276c8eb0e71d85b3810057412bbfd21fba4a8dcab5279ffa5e8ab9e257fba576068df298baa9b7d6b1c4daf14616a5d91a5d5e02118b18e983b39027a3659c0f7c973f1bf443866d341f7879309b1f0408db9fa7f65217c49623acb3e23c5881e4905dbec04a4e26899a42a367644c3ac9935b6073b1fd1f514641a36dd262efa0435f7ac0bb29566073fa76987a0bde22d8e2f13017082d739f9480020430ee481efec20c2827f590b29c68ba6a52f284b5fc16f5cde0e990493994b0f6bd76332cc0e3ecb609617152b825be56fe4dbcb150f66f6f80618ddf885a8912a930a255bfdf9a0176e3a25314a9afc4b954b62e7f659cc6d27311db37eff3263ce3acce86e97ad79b344c53dedf670e16bafaa4c9d6e0d6709b722639e8742a866e9f0eee09e52b3f2b7be1f403b5610f95e781a470e9ca5d96d61d538209e06abfe1f5f49b3751653a69d894c694ec5921ff09b37920a63d3ca7ba812f4d9a9272a61ab0c0141f2ba7ab85e45b9fc87f43daed896d182530f44222f84824825f16ddb46403863fa9afe18cd88876960371bae47b62c8b998051b4c728b96d1a4cb02de8d290b0b62a1232a61249088da4e0ed4f96d96cd7517ce923c8479061150500a0208b1bc4b947af369765a68282052fae35267181384de3b79e100830a5f309187a096050e52ac26c3e4ed48f051e6675d435042cf7b72e917e2a3f38cc3b87fa63154080007798135964799df4e46546b4f132f53e82459304202a2035c1b2c8a6b146739d25ae1e0b1a9fc9fd2e8d48d6b1fa4128c428b4aa32e8e6cc5df71d28c557a8eecf69ca790411fc0bdb6c86947d504c20f03e88f3ec7cbe5d1f2e65b2eb9ce49f1fee64cbe1c9f8edf2e897a0482bc60dd30ee844219196d02d5697005e8eabb87cde8ab34f93315bea66bd75554dbd14e0e5daed5fc8a764df5fa491f89030dfcc1604edbcdbd70c956639e465bffdd0c389650b0e0cc18f8e6917a798ac97ef1f0356d41add9960d4dfb1721b7a94980930cc2d1da4f6943c08c180f9e77f77baecbab543c6bd821de4364e1bde4bc4a5313c15796055d04cafaf3530355049c8830408356734025de156d90572908b6a13c0aecf901968c5aa1031d80c1f0111d3f0c00135e506320e076d538cb9a663cb714406111bb1c5505b640909bdd57247d0f3148fde511febe9c7c70824c6c4a786b7850d730ceb35756ec2f3fdbc2e889924c87783c777128e09b48b8b9958e892dcdac7c48b500723fd182770f03e9e80c916f3f570440f1f05b0982d0a9918308c389ddf8977b6549dee4898d4db760755574c0666cc8bdb18135f3bf51fba65f291c3b147504ef51e3596c0aeea5c50af73c0f764f93b4983fede52488482bd8cc67a92934ede6529abfd032422042e6a84280f5510280b6d73c95a7126ca6d3c86cccdd3cbfa3ed38f3df0cff71cd6b880449123cbc7a637b4220adc5a9e5699f67df48a39e0410961201df84e849579b63d29e71131a407608bb9d8ea08a3b78d96b697369152ca14fe0e3b0f950e20eb6d66b3d92ca59a928d7e7ef6538418fda45bf0f798bd0feae3e39352f5789f9f5264d423ad1a329aa53c509f74ca683483c068f6329a4dc14633104c578c1562ad59f13a45b5f1afe0eb24b3f7ec2396d9df35c23898e0c77bfdc060361b83c14362afd7db1ffef0d726533dfda712525b9448f0b3dff178964a6d015327e10e5f82ff3e7cab4c74b5b0562692201351f0df6735994882ffce172aea61ab097ecd5a76fc9ad7dcccb0e2abef65bfe6333b5f2ea3b5bf2f63edeff15626ba56383ef2c36bf6977b9f78cad6733d7711052858957dbe9f0075ade749d7229d7415c249d759ec9ae97af6a4ae5ef6f9c05cab4cf481499289c49cae42b31fd35546a6eb89e35aedaf4896ae45423be92a34cb49d7d9bfecf58101ab32d135ca22d3550433a6ebf981b9e9fa1f18f003a33f30385d1dcc5e3f30d8c93895b0cadadf8b595960c068699529b3b575e68c9afdade29afdb9aaf6f7bd9df16587b61e923ffcb7b77dafdff97ddff781ff81e00782af4b3c04a69f05b87c11468d321860c60ca31fa7b87daffa08d4fe34a831d1598af9dcabd3c6efba998a0073d0068e3e8373f31a9c8ca3d3007170705ea3c1d16c7070f499120707a72cc77c73c25e250ebec1317c62187e6111cf741a9d46a7c90ab70079405083afd180200f086a346cd2004110d467341a9d0608823cbf6a352008f21415ed3cf839d4c10963212c34c39c3ffc1c1cdff3e7abd481f27c0e94e77b509ec781f2fc0d54867af6c9156d1d8c93ae622c5dcf5086c3c7b31dceb0902bd569741a9d6607bbacecfceba5cfecb0c16bbe345eafd7ebdb7969355a8d4ef32fd887f7de9dd76876d8ecf515dbd979fdf91acda9d3d8ebeb5bbc7762e1c3603bff2dc6ab56b35fb9a25c91b88a39ab6cffbee04ebac27e2dda3af72696aeb32be259ba0a6d9d0686ea3437e8a5d3e8342216d8bd825dd885c1320c7f0161b0118b7b553ec62af11712567e39ea5cbe9889625fc2cc58599a3fe22eb80b98ee908afb872118866198ae64f824f9182b7c322431162149a2617ed7e1fb977425c9900cef5588bf902489b370564892241992ff0ac3173311ce87e99af3a6f93a7136cdd73161e1f9e1f592838624f83837e898b6ba0bee82bbe02e271693b8b9c102cc97f33ccf0f7f397116cec25d709713636171af608fb160f80bec5758bae2acedfa60b09b9b83737e78b95c2eb80bee82bbe02eb8cb09c321183b662f978eb1b9a5187ee05c853e334e26aefff62ab44b213c248e26071d94e58b2fbe9be51d4331bd5778765d29ee12ee20d1d90ff9e36ccebb57a12fc45df0173676fc7c669cf78e25f91f89bbdca0321d47c74228c805b80bc67291f78ac45df41ed3f5860f435f28ee72b3ce1c7ef6529eae4562d70b5a74cdb6af421714651f9858c6da8431334ccf9c9bdeb9fa89c6c904f65fec61e679f3b11bbb31dfd4684e7d0696ea34374c95e059fe175a82094a4a30c1db7ca14e136be304fffa18133e34ce8b74c343e6c33e7f0e3bb55078e8f53acd0d3a5318ccd920dd1c8d4e034b359a1bf499af2fcd156216edf57b766a83bf16c984c8749ded55b673b8ca4459d1775e571ba47bce8174cce5de1b0603b74d95223270c5016050e9a1871e3220c68983c63a93ab60306bae162fa379d86bb9f115d8dddd3d144351082df7de2a34e49cb36b3c83ea8cdef77ddf48aa41138621599a29e372b95ca509e68b599224499a2f2e573b47bf4ad334cd172ccd953439c0ca8ba6b1c15f57b2d84bce9dbd8adbd18041938504ec6596e4e81243f0d3195f3348bff8cbfacb80551aab7bef07a6e9856b72ce190ccd385381effbbe50cc001661cc30138661283a7a7376958e9a1101d0050579ffe28bcbb842c3bd17e732a8d6f03c46067a5dd068c05ef59253efb0d7d9f6ab33d0d082461534c67dad9c4ab08bb131d516b1d0cbf419adc63192a97bab642225d8073fa6129aa5f1f8c3749589b19e64920b7ee822332c35673bdfd4959fcc686e50a8cfe0d94592deaa6b55251389a7ec7f362b759a0b244ba5a14e73836e7873cc03e7ea596821f19a0fc9178471debf60e31b3c4e41fa8e9b71cea7fe7b85b3f00c0fad536e1201e2b48cc9249908f6af37f1c3d2b5d524ead7cb1ec97f71d963ba6224f72ac5583708a74878963ff433269a24fb64577aa645b8cb05823f7f10a954ec7283f0e38cb3626b9c2b90aca10b80a0f93373e2ff0c965173cf9bbf496128893fdf7c6ad388d622911bd488ef9bffcc0e7cdfc45edfec3cceaba0f3390f9a3d22ec3cce2bd94995e8a49e7d725e74bdf8f8bc7952146f186210ccdfa7b5fe720631dedfcdcddffd810f3e368fc41e7c378de01b582c3d51f35fb0cfb9a25be4dbe29368915ce49e4ecb1ffab7c676fe287a0a863f0f58d1a18431cc9421831a1592d84012207640830656078438c2bdb802830c196b2650811cac8c5106135bb050e38a1ca850e25e81a18c0a64b161851ba654986265460621c6a8a1f585951ca65880e2882934b0058d2a358c74ef035678b8e2080800a15ddbc348808a59050a1d50420c9623b8b02187c3196496d86289aa1c8cfc9dc90d245011c2033390f1020682b861e717b71043f0d319b36854e9818a335d40c0015fe42af704f377e5fbbeef2b4551081cb060a38c153263e040c41946e0980d9859c20244f03006025ec2944153a5296b9330106709750ed637586106bcc1e045cd192b68b10219189ea8a2871664102325874ffde0030666c0801a6238d146152bbeb842092458d8001961a47184517ef72cd00a26f69a83f55fe860f6a148894c860732568a4e1948bc029917349920fea80c0e48e18022c28419c348874185cb0b64c66001092e8c3499145e10ca63e812c778a15d2eeaf0c1f00bbff0cc3ef76f4ef860fec6688d38479fe0f769adb5fe72d6c07775b601e6430268b4404507d490d980105fa068630628d458409b1cd9799e8fbf689d821149740085182a80812c3bcecfff3bbe7c41881b5fa878f012c604c47c018226151b86502387225ab84cd4606a71031a0cb880060d6334907ac1e18b28a20882011800c31c2f936931fc3e30d4e58f41a20c835cefee3972f5953fce56db3ffbebcfffa26b0c8a3306c5e93d47c47d5f5cb7be729ae723f210464250d1c319350c21040e79082ff3802c80a0818a23c0f0c01d3736bf8d37be3e9bfc72cef8de7baf7fe40bdd246cc5319cabde0eee2f7ffb74da45f7a73feafbd8fef4a7bf2fe7de7b8bd09b4b725f70df7d752a661e9bcc18e38b31c6d833f9c29f6217be2e865832304518010d68069011010d6081d1800fa471dfc5211498b040152cb4c0058ba6214acf071c1e2005d615109a86a9242e50c40d4e606106165b0fbabedc02ce8d0c7ee0077a209489391ce386470c3f50a603ce4e3a8e5a5840ebe40cb24643c5075888814ad50c5a902973acc059e2bc09e2156b40793631c2b4a8c1f5d2a2b76396a1534ae086bc023622a1e31a93e5ca147d80855a3ab840ad14707c1b886909dcc85940b1b56c6b0d7e20088263ecc8e28735cff6305bf4f6d763431e4597d66234a05d39e719b656228bd10236d5458d99187ab872c4161946ba85363c88210504ca9002849196c96499884c7768adb5d65a67bd434c9a3c135fdbc388d92245315a642cd1df9bcaa081d40bc8328fbcf0a275c6102dbca065caca14689298428a0a3a8841c61a20088220d883165da198174431ebac5d19cc202846850d822098434c05088220f86959978f89930de345837ac797f307a6b10abf58ce39af09b596410dd1add042034f0cd1c4144c44016a612503665060872972a840ce21be4c66c319593403c4a5ec14c51ce64cce39c42ddbb1c6cebf231b6d61a5016d8218a2cc163f333723022e336baf3b5e6932a84532cedcc8f28b2199582e65a7289e59e42f7fdfa77315e2165fd18fd08c9c6522320d92452ecaa9e7ef6322bc3f32a1d99e0589e2fbbeef0bc1d9f79191c4f7cd8204290a8365af415e510869f11b22ef98fd5f7989378421193288201953c8effcc0f73967200d57de317b331f76d173ce39e759fe72feb24ef3994130e79c73cee09de121cf00147a47fe1de05e5f488decd2601833a8f28359e7bf9f653c331a3639b22ce33bb8459acf3f7d86e1f77ddff77d2118668b32f6f77ddf99e3daebf9a00be4e80ab1803978263bf5a7add06cd161b0a44f4061850e583730c165062b6af0400d49a470258c0187d901fc51758133bce0c0150f00a32be345ca9a2628c0451a10449303a8c51c06cd0a1b04415083200886270862d1c606df0804c3e0409a0648200343f4b48c40158c306e9882430d4f943102f5a7331be597038220088117d6a28bb78c0d822008821a04417009f29e329d0124f09733990a6918be84665c645038a3cd17618821230c2fb098b9a10a0b16e8e200233048061f83af451004779c2f7425008220087efa6f6c0f8345d616b787c1026baf429e259b815cefd67b25efeaae7b8ee86c1eb9bddef6eca978537dc3bd42d9d73709db4c467023f0a53ccb28eafb28f063bad7d3ef5b83ee3a3b7fce7f631fc9eff7fb5231fbf8b9f386ad77f704007f4f91477b8eac5f4e5709b6a7229e89f87ae87add1d054f692cba40864f920e8e632ae2efdeaf0cbd4834e21df80ed39b2b674ed12647d2487824fcd13475f97a85e28f0f338f88e28f47cc310c61621e43334c7bc8f155c2643298691ab9a3f8ab6b7c12866130180c765d7c8dfb651a3145d175c4fcf143d48829fe488ee387a34886a1d34ad388b89bdc36e1b949f3348f98e2a3a669043ccb101dc18da85488f58800fbd72b51123b5fa6912fa65d39e3a8a34396b72ccbb2c4c931cb779da6914c9a44c6274d9df37c8d4fbe7664b29df3849946ce7b9ee7798e39a611d78fa38e59be699ae6e84a9bdc36655a84dc634ac64c233856c262e588ee984ac29bf2c99b721c9f670cd1db66f39823c0fe650058ead948cecdc9c9c9c9712cbecad7318d8c5f963ba6f931732c5de58763dae49a691172977f33923a65881a193f1c8271cc1c31cc31d33275a791ae147cfc3dfa8de4bf608f4e7fc4373a649d60f65f3bd89f289ea74cf6bfcec05b74f3197c11fcb104cf743dcf57bacaf6f766fafb67fb4bc3347f60ba76b0bf29abbdfae78af663d71fb83867fd69adbfeffb401004c122f946e014cf9cd9b94aaeb266cdd5e2656e04ce22f9af3f7effef03e4f7e487fe778a79eb7b5f879fc6d7ec5132ba9488e113618d180135298a370c3108e6efd35a7f39831887e5877e659c775fd737033f7f45c0dde4b601370882398c648945151a32990b967ea14a151961ca00a3881c4997d3f08b391b9721811d6b9cd93fdbc3ace165afb166934c4e0fb38610db83bb6fe0b8d1e1d4791c8f83933fe6e8ebfbcc66e7cf41736f1835caec7b6fec337abe8992a107aff79e9d8fa56b0f929bcfef1b6aedd9498fdca4eeb40cb563ef1b6afb9beffad7ce7b7a8324f619c9f966cf4d7ae44cdd69f9cd57fe1d74353f90fdf99fd9c1ddb2cfe9ebc110eecee7bb19c2ddb2d89fe94d0e672c4522fb9c3291fd9932c9f936c7d2366f9d7fe578f01dc949359ee9a46b9bd31547ea7886f31acf701c04d8f33c0fba46d93cd73c92370fcfeb63e68b3c9ffd5f1f83f17cf822cf67ff9799aee1b779f3ac7e235da7364f7ae3c3cfe611bc6f7c466fc462e91a8bc5beccb15c7ebe89c15326e64d7b8e7cefffbda7ebb84d26668c7c728da1a7c64337fff23f517f4dfd0dec71ec4917f265707a180f60b1c937dfc8a9f32f7475da259edda4abde37ef5edb791e9ef4e6775077da4dcadef3713ee765b27467b693ae7abf5eb0d71a7bf1757070fe447de7a04cdabc71522777c71ef6df77c4fcd8794d24b1587a1eb9794f6f503c9e1f731aec3d159d06fb21f84c9998fffdfa4ac9d7e7fe9cb6f9bbbded4dc2366ddaacd92d3ea2b3bf94097ecfa9df209fc2715f69905cf6f717cbfe1eafa5be1a63adcb5fb5d6bfeaad5b4d8e9fcd23e3af49f698f27ebbd075ea874d8e6beca91b3649a6bcdf63fa9948be2cf56eb246d945ae9aabed7bc5fbba89046ffc59cf20beaeec2c5e89a217b16a67576fe735a21a515f5c85a97055952a9b4714b14471a452452cad9458ca2ae5152a2f38916865c500f18a0ea296078058aa5439df24e2f96cde27f36845bc12adc42bd14abcb212afae402a4c44ae59a3abacd155d6ecfc55707ec55450918bc913963154ef7c2f4a8a5cf04cbc5ad3c689482c36d6d2869dd7328672859dcb2a58585858170b63b9b0ca2a632aaeb94244b1ac229655c4b28a58561171d25576938ae2d51a6295f88963f04cbcc279f32fece65f65c4325788177748e7f38f605c22b22afbe4bc8864bf8e6a6c229e5fc73423067650d1881b3423ab32110f4e8af34ad7bf71d3aac7294eea376815b76638d2bf91be0c9ba968a2be5f1062afa27895bf1462e7bfcac2f3a05526ca6b7a62952af18a95a8850a88a58a6c1cc7b1ac229656ca2a25969d9f079b6595b20a89456291582e1e9728f2a422095231b357511445114b144551144551144551144551144551144551e4e1e191f1f0f0c84451e4e1e111cd2c2f2496288aa2288aa2288aa2288aa2288aa2288aa2288a5859677986a528ba5cae711c499214c771748de337ba5ce338ba46d7388e233992e4389224398e6458966489b2791f489224499224cb922ccbf2659aafcf2ccbd22ccd0f964d190f8ff8899f298a3c2fe3e191a5a2288a595fc4ab2b56c42a62152a22152b51145f57727001ba8469b3b53d4c9b24367895894833a4183b3f8966e797f2657b98365a3bc776313d343b2cd12c3a0fa259766e5838d79bc6cebf8356bd91ce0d0be78a7b1b05b7b9e5575fc93ef9c12bf02a13816ab2cf5526a2da1203b1402f60161e02bf4a5f097bfbdc6bf4952fe19a34be7bd95c367896ef1a92f4d7ebc2cc0fa6ee4a3eec5e589310a3b0276f89abf0909329a6c23d3cf3722e719231348b4e8e78957df29b2888057a41c5ab9baa73c55665cce02131f0d09a4337f865c82d6ce535199c68ccca3e39eb06716bf1b0f358e6879d5fccd157b0682d5a084c8e599928b3c13ef9a9c050d1cabf8e65b095be82ad4678f29e77dc12b988426021cd90627c265966dccae2d66bdcda8aa15974de44c1ac9d1f04bfa42017ecd306cb46377edcd39b04cb312b138154c6ac555fa15ac7ac551cb333952d5ac14424d6f5c92fa6715e36d76795651ce793b93ccff3c9af3ccf27c192873f9df30b6f9c621af00c5bb90f9a44b0159ee53fb73857128b7cc289c832d9277f8ead2419328b9dc92af2f96b91507ef2dc31908b887585804578507e504d519190d06cf62fbb2726bb80574ecb7f23e5ecd93d371ddfc7f8405aa51ba7e018ab4c045e619ffcd86ae73f1d30aa7189b0551eb7ee58813b84f3f9470c5ca29dcf3fa6b9443a9f4918c829631b3bbf5f2137f51b743e7ef29ee41b8172c13ee0154e5759be412bb8b5f39f18e7878157378887d37c9224ef87e900984d825b78b6c219fbf2e017f0ea0a3191984faa2171bade8baea2d486bd930f4bd7fbb07fa1ee34927cd86314cc52636bbf9e7ca530f4fc6b22793df97aa12bb8a53713fc37ed3139c065c3fe9ac143690cd578b6b62f14cc42dbb0da7ac3ce87a5660a9a41412c223805b756df42035f768bf7cd9413e7bbf3f8f1182c6af6cf1863b06ce99f317ec6702d52c0b2dbbc85bd5a5598d12186d14eea2df62cccd0b05bbcf10a802c4e3936fe9b29e79a5260eb72682c36f937534e5edadb64aad3586c9c6a5581c5c6216663ad2abc6c12c9d5793265821f8798eda60738c46c9c36c96ddae864d149c57c21c46e331356e70b465bd88b6f0a8ae1b46ca2e41669862c836760169e652f7896c12d3c84d39e22fe050bfc72a3c2b98257bbc7887fc1fa826741f98dc03e6bd893249979248c5ccb8063f02cbf06c780654033a0185ed3c2437e85788ebd8257e0979dc93298e824b7f090d661afad157a46f9b2b1111b96b5041159ae44b9214a0c5156882265e39cbd424903a58c1828554069020a1728426c0ca5ca950dd342ca4b0f1bff2a85c38ebd4a55edb0610af0e204ad13b49c7005cc8a6a826ac3d66c20898daf36b64a63c37a69885a4fb0886a38796263ad1deb62c37c70b283931a5c6b583058176ecaec9b1c0e932c382476cc3025b1b4c48d2bd4246e587498d9309b0b435944c610d1bad92b912f448a9060af1c5c60632b7be5c08bbd1a6dedecd5a8776682bdeead8d9581d6be59b379a860afbb37e48a8da118d24503ad1d1b0204ce5e873860080c435a18d2dbd8ccc64f84c94a62c39e5862ea092a534ff4cee86d18666354e31b636be326ba68428ba926c278d9b12698d052b371145b5b52e02085980dfb2204135a4c3131c3c6696cd897351b36c51a1b576d98103b36c5d68e75a961e316f63aa5c49520a89461b3615dec75aa87dec6198c9a17d468c00a5b6c2ea0b5a58ba91db250c0cc864dedc0c2c660ec754a872c5e7b9db29266ca4a6fb6d7a91cb680f63a9503117e815e56d65ea770c8c261ac40b98261e32cd6e02eccec18192c7b85a2a5b7f1ef550a869e0b657cf165af522e7441c65ea55c68a167060b1430f72ac54217522c8051238b8526d0ec558a852e1b97b157a9aa2d1bff2aa5c2d5d05ea5a8d248515949a5a066639dc5a8c4981de361632b6cc8d8b014ac365e61af5229b420a50d1b306cd8a8a60d1ca488b1b1949427366e438c0d939282036daf525262d861c3a47a5b4eec26dea68d1a4348f57cd8784baa978354cf0605a869c363af0a50e30105a811d3c3101b26012414d0c5141b07d165c326d0c3c62b949929b8d82b54995e157b852203c40f3b6cd8175d9029f70ad5c5165d48e150ec15aa0b263c20a241468ebd427151012ea6e0228b8b24c6ec158a8b21ca38b105962da8c8b8428b2b2dac2250e3c65ea1b4ba58a1b4bcfcd82b94961119ec15ea09adde8ef5b081c318c970d9b17c04111bbf4339a001376cfc500ea0c14c1a3b9636f115ca012b38a0c7811ec2d878af503d7cb1f1af503d70b1f1af503bf42250f35a3ad4b0f1af50567a3f7b85ca418d6baf5039648562686d58dac4dbb4696363a82aab8dc5ab2a28641b96ae5154b6117205b3c98d94ddc2c80d4bd72632b535b88b0c6cdce47b2a5810450b528a8416b02a12122185288a622886a17880d70ae5003321113f6c2258d8f8cf18220b22aa8640620806b0110e2126dcf245b8058a8d1f082ac21f98d8f8b3c21f7a30024bffe0c40f5dc22d6b84444441a489189a1ec4362c5d150006065c2e97cbe5ca66bc56292a2afd4313590d275ce66b9562c102449ae4f454d0a607371b96ae522ea8d9f8d5b082c5a81143cb35e2de6b9dbad2c35d9cc96cb061c42780864fa0011bbf1767706166023b8ca1620519534b90e1e28b8d5da2cb25ba4451145d47af758a09361b3f155aa40833844bc1c2a8c16b9d6aa20d97a2ea4b0a0e85968ddf35448ad1e51ac7d135bac628af75ea8933409348139dddc27616921c47721c473283d77a640d0dbc442145348da06c8abc0fa36b748de393d76a6bc2080454741c91e3881e2f6e64c9c0e4308287861d3039606c2338616c5c9afab5320993330159151044b1b50902ce86a52b2fcb88b8c4f75a9f6cd9b82449b2244bf4b542ad404ed9589b20e0d8b0748db215aec1016348851d469b8d1ff66e82004bd39e22f89d881bf6be612e66072dbbc5ab9818d2d8ed8d12e260b48585a5b9dc820a46f8b0f1e7a23430013460300f48b3088e7d8efd79bf0579e7b72012a418fef3beffdc271fb69a4f5ef3c9afd4a608bad74b5370d2f98b66d1491dfb846611908b095e519d6b944d3edee47b98365ccc344b169d1f514c95061e5a837b99682705c1a45a3beba02017ec935f44412f60169e7dc133f0d4e2d45af00c0b9ee5d7a8a69dabbe828587566c45037885875c4c4f8c9d1fe472d315f4b2b3b975834bf800e9454e1fa3456bd3b68fd1c2c30677ac2e7757ec065ae4e3c382edef44e78b61087e3ae39d866813a88d499c86e0a7bde6e011517b06cbdece11b3c42c6c75c2de5fef66f93e62abd9f721d6f7615608e6fb50ebfbb0ccf7e1d6f7e199ef43355f900a2aa82008cecda32900b0d5e7e377529dd44a4cc174fd145bf940c132d9e70343437fd01ea8679f9ee781faa09e7d2088207c514b26faf1401e0700e92aa6e97aa2e92adbae4fd7dfae0fd79cb057497e60c02ab04ca8251349f06204e92a9e10a4eb29d391aeb2ef49d79fad33a11be92a248be5282a12129acdfe65b2f31479d2553c4fd9cfeeb5ca41efc64157f16aa560bb3e86aee0567805440209249849f03f509f1d3b76fcec77540d1949f089e229fb5999668d59526cd0a588220a2836e8506c9df5ad274687ecaf4accca3e9f15ae025e11b5dcab112b2b0db166b3d9ec7f4a91d1ecbf17b1bce6593e7cf860a37b463cd229e3959090d0fb3c8f74ca682494560d19f9f855d4e2e3e3e3e3e3e3e3f36b98c583070f1e3c78f0e0f16b08a6478f1e3d7af4e8d1e3d750ebe7e7e7e7e7e7e7e7d7b00c8d46a3d16834daafe116101010101010d04f293202fa353c13141414f441413fa5c828e8d750cd951b64604194b28dd6d0036bb8c6475a667f0f6aad11d564edefc77415cf606d5d95d1b23fadfd8157f627947af609424120f45b937dbea7a1df0ffa9dc93edff740bfadcf07fdb4d00f4cf6f9d4ec2a6be881fd3d296a99fd2a5e8959ae2b27f2f9d9af2e2c57b3fd03e3016cb3ae66e3194ad5e379bc4f249134013ef446b10308925ce87df9fc2e2802387e42401e1918914f2e0ac40ec031bc6172e0daa14370f1e4e49800c70e0fb18707234c2065148142202610a22349c2528738be5a1e72959a821f12bac251077d1ee8a221f7ebc9e8b723e41295b2054484c8c471c74524658310c820e24cefd03b40207a3c5e9a83afc707816b87ce01f39175a0d0030aba7929d374fe149026600627763a2286d0caba2202082c2d4c418162992ca94a480930c100250c40002424f920001dd48a80cc26900000afa998a2cd1968c6d0200309521c37c22b61b0c8e283084434a8e9d02949f08b972e5bb464c1e2001eaee820801905414039e0a08484366cd24832c019699e38dac51610036e29032163a845062b229704cafca0a566c1104f0e398a618e1e25923041bd21092100478a10a905f1e173137b997a07185858e166ab82268818028829020c80684896a3b5d0426300196030e40ac122a67431a2871a667041010dd861871890849081100acacb465e03afd16a3e0d3ea3c7c014f8b6ae17980ceec2c54539066b81b3c05e70119908cc44af77c78d40d4f1e5306f601eac73736238df0d8edd53bf30f98dd8258a380c3fac6fbe1774f7d187fc043f4b2bee3a1ccf2948bded9470baa71ff75b9639782d4ba261710ffa4936e1eea29f2412ee3e819f640c2749e548bfb47b9f9ffdab37dcb7b81712c5b3f16c4c4a6fc37d1b95b48624e1a68d0adcfde52749c4917e890ea7323d799f190617bc0eb7444d42001010d00198968016ccfc2be2eeade308f55c67ecb7879fae2dae2a3a5ccbaab767526a6d4ddfee74cfaabbdbfbcc5425ded38e759de0baf94da7b6b6675d1cdc74eae9ba71f933b54b746aee9776af2ae172ecf3764b3c5bcbbeba4467e3b980dc55c107e69e61818fcfe079bc27251e5f73c7b9bb939fa20f4f126279404d4f3a048c3fe36c06e5a18c3fa302fe15f0ffffee3803778c813bbe4048a8e66b5fb8f8d7ce5086f004773ffd0c57f7af8d5f6b97d4dcff88d4322dc1f1fedb253587c4da30c020e4e00c77b83f8b6b9f92fe599ccad47e8dbde99e7649bfb4fbf669f7eeb836d6beb5fd4d65a284d3d99c402feeea53cee6e49154dd2e04a4b7bd6ef7483e33271bef89eea956d3ed70ad1312a4bfa9b99c4de9003577c7e12758c57349b6f6a90984e25fbba9491f75b3a9bc9cad7d0281b7e3f1883cd9f1783b23b0047720a0d04fb0480747f4bfe082f7317b960774db3505b54d4b2a6fa7e4722fc1cf0f019e84cbf9001a02f24163d536aae5ed926c1fb8439930c45dc88420ee6ec2190ce0c438bfd3b19f9f764f93dcb105eeb8c81d13b9e321773fe2ae2dd03d6edaf8005710c41d0371c73fdcb10f772ce48e83dc31903ba6b9e31f77dce33a39e97ea9dcdd007e6a997adb29a9b70a8084684515b0ee35b8fbcdcf8c85e501a9b9245bcbdb39fd001202f241bb35e1d8a3a41f2a135bce557700b8bbea67d63154c10f1b132b0404c40790108d5599581bd3910eb7536a7149414b3e84842af0614b4afaf1e346e4636988b6c301b16a6be3290145f15a16b744e505ed96f06c4a3d774792ba6bd1dd13e038277cc158788bcb39b18fd4da9076fcc41cb8fb8d9ff88a7bcee664d7a4f270328072771e3fb1cedd73fcc40670770ca0d49b0ec753591dee59dcec756aee2f7835e96fb9a71d13fb3eeefec3fd3eb9bbce717a6adc3dc8fdd2dc3de7312caeb8631eeeef8e6feedee4e7a5a16d5af271f7eb78e6bc1d8fa7becef63755c77b6a555eab539bd49c5313ee5b9c8dd7fe121dae6d6d4dbcddd2dbfcf6e0ee3b3fdd8abb9b7ede77771d3f2fe9ee373587b32d3dabb65149ff4bbbd7ed70adeda378bb26b589e501f9e78e6beedec44f97b93bcb0352529d1c3db129ed72395b5014cfc64bc2e58294786c50122e9784cb053de996d0a09e74b81c4df764a763a27ba205193a1a2a82a20901111101f9086275381b93526eb76b839c9e5af68917c4536f39dc535290dab4630a72c714b8e309dcb104eeaeddbd74c73b729a60437a56afb73de740910449de34203f995126df6b9ca6443c20bd49fe7222150a522e7eacef6b9df3bd48903756eebd2413f09dc8d55aeb073f74e9f05de717c5bf79cdf7bece194badf7412de504bfd8e6175fcca25428a6d8ec20fccc0474a54c40fd53ebd45ef15f2660dae4bbefff5d91373864fc59fcbcc32749f723f9bf94d7ea079de0d76813d91ed326524d641b4cdbdcc1dd62da446a8769d66993bc99f8fb7e37919c1be32864e7fb8b37369cfa7f879889ccf712c54f6214f035cabd5c96b8c45e82694f91f04126619a250a3f986689caafc187821b892895fe5efefb1897495caf512a28e45f5739d5eb91e8140d8cf28f2855d535ca3f450323fdb94421ff7d13a532bfea8dc81751aa5efe9b52a1907ffc296f44a6bdfc634a55f54665eee5c75fa2289822e4cf8f93e027bd1cd1aa5b758d5c4fa2545334301abfea1a914f62b47c5d962914924a24c18dca14ca1625e4df87323e7ea3ef47d405fe35baa1e16ce26d369832c912853f4b947e9d04ff357b44d08f5f497e23f29a49f4bb9924ff670ca6408a99484a2a0afefc51eeeb97daa224fcf1a5a8aadee85302fef7515c5253dee84ba5a2b8d2aa374aa3802fa6556f943f4ca380f7bf3405581bff28e0d5195d14add2545553c44c848d303a650a4a55b5a589069b497edff7a7e8744b130d767ecf220079b383182a2b01989acdca1063fbdf31dbffc3b2fdc32f6262e0b261a47bcd49cf47a4e74b51f7473db8fb86260826085fba4ef9fbdf5b8271e21084f01dfdc97a8326081704d07b3c98edfb37457bee635da4e7de9fedffb3c507eff70249fe38a23d46240a8395ff4aa1bcbe3cdf8da0906ffe00c63f5328b01fdf4ca16c5102fbf1a1c49e7c377223f296234afeebefbf5e3f6524553e2cedb9698f08e4c35ec9c3c6375329d88f2f157b52c769e2f7dcff123d4599f9672a2575669f3c65044ba5b6ac59603f809b06892b7a4650a2a43dd8c3d2285086fcf9b15428fbe42f3fafe7999eb802f15f0ffb55a886579a24fbdc5439dd289b2983869e91396554a25346a493f8a24eae07257a7be59ba9949453c91bc18d98b24ffe2623b8d1eb477023f3f64a5763bedf2bd7ea4a952b47f0eb4b14e67a8dded4c9c55b3f0cbdd8e42981fd2b95927afd2bbd57d9273f2c1dc18da82e56f6c9ff8265d8bbd1ebd77bb5337e8ddec76f6454a2d7c8cd9be6e4643bccbe8dc64f23893f3826a2127fca1bb9a030a87105fa4574cbf76e2271a781e90ae5b40cd5e60fdf316cbcb4c1858d2d3666dcafe39cb3d6503ba34dc29dff83a98dc99c73ce396bcc06e93bd657cf6bf91f4bf1da04ef8f51f09a04ef8f53f0da8e7700bca7ef8fa7780d7d7fbc82d7fefd7195d722787fcc82d720787fdc82d774bc3f76c16b39de1ffbe317bc86e3fd310c5ebbf1fe3806afc9de79de1fcbe0b59df7c70bf09acefbe319bc96f3fe9806afe1bc3f6600aec16bb1f7c73678ed7c87bdbfde1fe38073c056b00e3be006784d7c7f7cc56b616faf622f7cf15d3f3ef9e59bff7ad89f1ffb9bc7f99cd7f99de779d9df781cdff3395ec743f011fca32900760cc93e1a0c02fa81673cb2ae7c07ceb5d4f2528b48e491aea24fba8ab3743d4f19907495a53e52cf024a677bf5ac34157b409f51a03fbd9c6b167fce1e321e3e3e730a9cf6a4ce82220a29be4c41451560acb80202588411938596165b44600c175d902923012fbe3033010d860ee35ce13c63383d6baf23047c8804efaf378b5df5c2c169fa41f455e506e9277b78e89583cff4eb2c48aaadff8ce1fcbd3e0673855cb186d3f467345c7383f48fbd4c24f6b08ffea22221a1d9ec0a96c9ceb3f72f24740661684e264ecf2281d82b78e5f9ba50d09f5d4eb177a5cbb9ea3069d480756ad929ce664242e92a1494ae455a2b78a5b744f13ccb10f5e0453400ef428ffc8876f0246ae44bb4c89b28917fa13e1e8672f027bac1c750a3bf41f7e3a0433e07d5e075d00c7e07fdf13c28062f432ff81ba890c781d6be07b5e073a045af03c847800efda3153c8a06f914157a00a041bf03bd2f010afe04687e65d1f20310af2c5e0b5fff4b8bd7c4d7fffac16baed7ff0282fcf2cd7f3deccf8fbdfe97ceef3ccfcbfec6e3f89ecff13a1e828fe01ffdf401f03b5e826f72db78cd83b43c23006999c6693a0aaf1d494b33a4f05a076989e68bd78ca465195378ad485a924185d788a46506aaf09a8fd49de6038cd73848cb31acf0da066989812bbc669496178080d7765a8a8185d786a4a505c2784d83b4ac80d3b418af65909614c8c26b3f5277da8fd718a465184ed317a425185b784d485a4e20025eaba5a599315eb3202dbfe0c26b4569e945175e234a4b0990f11a90d49d06a48cd786d2924c0569d985175e0b92965c7ce135a1b41c63c66b416919810978eda6e51660780d4c4b2d74185ecb69a97526716a1f3f803c980da6ebb7c19c41f0aa82206920516a0129b57e945a3ed255a6ff84e17c188e70a30ad2550c92aea76b187ed812faf1417fbe707e0d7b157bfa85d25514faa0743d6f7abe9006152aa7874163cddeca44b907245dc51fe97af2f0f9f567bfceb6b67c6409a5412950baa23b7f91dccb4423bca6a56b1192ff495731c9f748d75384e791aeb20fde275d3f849fa5eb0c84a7205d85f69a7b7b845484d45dbb8f76ede907e404e8ed4980965a3b50f00a00a84e51b20a45c7dea3792b02344380ea2b4ed3af03cd594ed39f03257b4ed3df83be9e709a7e1ce8cb09a7e9bf81be9a709a7e997e1ef4c584d3f4efa0af2e4ed3af83be96709afe1cf485e534fd38e84b09a7e9bf415f49384d7f0c7d21e134fd27fae2e234fd30f47584d3f4bfd097114ed36fa2af225e57e88b08a7e91fd1d7104ed3ef425f5b9ca65f445f42384d7f88be8270da2b0821b60c41c45511461cc105892494d82f2faf265e4ebc9e2073d695dccb5be3de7bbb6730a7eb6d02d2d6338973bdbdadff15c40b11c1160886d041448eab9e22701871e30819171e247692d05122070b67899b2e3126ce9717d8ab89d7cb09f3f54449f6c89c35ea2baedc13f35638f676d596d7aef4975abdfcfa7b65758081be90beb117f9ddb5d65a67d75a17f11be41863ec464e30fe6b997372be9cf9d7d2484e73f620ab70ba1371e77c3f5fa14fcd4d0ce7dd2608777f613ad0cb9afc40494f1dfcb3b857f28f84e433dbb58f54aba94e514a909ef635de6e0949758a6a796a2e67db80b7635595559da2da16a784cb3941a93f5445f373e80043b9022f1cf85901943b90ed752a135bcbd4e29efce89e9e985a56559778f000bad9d496d5e11e09e95556005fbba9ad4d49e539a9b76771af7b5a7a16c7a484070f2077e7e167053982847177223f830499e2ee23f81924883b90cac3b1ea8de5ed96a272bbf6919e06a4c335ddf64725fd4dc52de1945427f65f67036183123e4a67fb253adc8d675ba2f29e7dfaa8259cba44b7cbfd4ea7f43695877b6aa28ee0ee22f8f9038d1f687edc70fe58f223e6a30c1f35f890e2c3e714da72f700f8295483100c4245415beeaec4cf202a18f81984a403400d7077d44fa028ee3e003f8166ee2e003f691170f71e3f6958aabb93e027ede6fc9102023f7f1ee0ee04f0f3270420103628e1e769aabaf44d6a8bdbb53a1c0d88f589ca25e15876e7f4379d6df6aabaf451eaed29a7a4c3b13835a906f403c8ed08d2eb6c3c55a72ef9a5ddefafd180a26c3995f7bcddff3821c007086866e3d992fcffb43a95674b7200a45793704e51ede77238023c1053db42a9ad6ea7f4351ad04d675bda39d99440f81a12d2d38098b038deb73635e9a36c4dad4e657338db92eab4d3d96eaaaa7b16a7f2764dbfb47ba4a31629cae6f43ba7a7ff416a525bdc91aa2e212ded9eb76b955427eacdd6f42cee9ba26c4eafaa455ef7b3497896824dc2bfea64d7f4f37fd3d9580a9ed87837a616f7e47fd7ea784f49513c1b4e09b7a4ead424a4ff9bcada92682d8edd39a9b756876bfa5dfb7fe3d99ef0764b7fd3d9fed9dfb5ff5f7bda0321b5ac7a43fa5dfb6a5294ada9c9c6222101f1763f3cdc92a71d8fa9fd9c4d69976bdaf1969a76ecf3d425a6f6e8a6b31da94e51edd1121d8e7d3a3abaa92dae0997bb1d352941b147ed4da7b2eebe819f3cc600626d4c4a385687e3b5506a6b736271b7e7a94edfea6cb66775385babdb6d90c1fff814fdf0f1f43fb30b94d401dcd49bee6967c42af158281b083af57684a7363db1badd061f8cd03eedd4265cab3ac1b54ab6231697c10078473cf5a6db39b12aafb565e053f4f43f454fb30ba28ed4a4285b53d4cda68ec053714bb87617c2121deea65393b04fadad25218aa73e8900c4e29858565552b27d54126b63526ad5a5d7d9947e840752792ad3df54deae655bd696539f78edef9e2501e9008f43005293520923d46a6cad76d4a4048574805799da253a9c9aa4e6724bb86f7536276a4ee5a94a3a9eeaf43c5bee6989ca7bf5b6dbb1ffc3aaac4de955f669f7b99c8dcdd9969e8db2b5ecb7b8bfa92ccec9cdf62c052d8e3d9264ffeb70adcea6363d8b7b16d7846b3f97c33df9261b6fc98ee7a4db7d544e87e4816eea8db753527937d5094e55527951b9dc4d656a7749b36741d8a0845fa2c335ed947438deee792a53ab3211e081783ba6b6b5b5ac4e75629fd8cfd992763923afb6bb269577539928ed72aff26cac9a4bc22dd13d1579a0289ded9770ffa32eb1b5ecb314f096e09a784f4a27e05a1c6f87e339bded59dbdf54964909c7f4e47f6e6aebd4a4b6adeda653d9b77d6be3a98ff403c813d2eb6cff73535b9b122ee7f4c4c103edda5799e0724f5e7df2404bbb6f5299dabfa94dbcdd920ef7ea936775aa92cafb96dd35d93e97539f3c6bfb1f565da2b33129f19e76bf6b9f7d95676bd5253c5bdbb4e32de16eeaab4e6c4cb9dc7ea0679f7ddae1783627ff64a763f2ea936f6d4cedb31fdc70ac6ea7f42acff6ec8ee9c9b33a95a9fd9fa5230ff42c6e69f7206c50c2efda6f734fb625958307f2c9e56c2dee9770efe35bf669fda85ccef6c43ecdfea63ae95435e9591bd3b338a6f67f69f73c35a9e949a73ee56c0378201ecee6f43e482cd2df5427ffb39bfdd2ee99581bd30f55f0e359dc47a91e3c10eb64e3b5dfaa2c6b6371502aabe296e870bb25ba1d50144f7d6a92c3d99cd8be65d5d6967b9549c9abad9a736ada29e98ee8763822399bd2ee03f6a6b6bc9d93d3133b8200545600ba2337ddd3ae48bb0b8189d2ee03dd129cca539dec486877216c9689d2ee03a327bb0f5adece49cda94ada27244c9454a60d6e6a128ea7c4263d91b00be1839bcd48b7c3b13c7500379b910eb704c74372c3e56c4e7447d85665d9cddb3129e96cea081b44b54e4d44d45c12aee5a94e7447da5d081c80a0e6926c3a01e4704554de530e672b72d3a92408e0a6367921ea0938b6e9a90907656bdab59fb33d35515f4dfa5dfb37f5041cabf29ec53dd61e813b5875eae0c0bd4909ea888dd2d940d8ed942cc119ed764a72aa4e6763da6017422ef754447d529f44605a82539ff05427bb23b57d5252a1549e0f9a9a53591a6fd7da72b99dd2918ef794a42ae96c4f2c8b3bcad9da5d7bd4b24febcd76d4aa2cab643bcae56caa135cce76e4a4aa4c8e8e5425de6e89a9b5a9b7a327bb5cce76c45397589d8dd7b6b81cae7d626bb5a356a7b2499b83a5dd8e9724a72ae96c4a47aa931dcfc9c9e6e3e896db31b12a8fa93d3a82b9fb07dc5dc94f0898705f8263716deea9c9022034f5497d6a425397d858566db2f19e6c2f4dba639f1cee36c749a18ceb76b856c9c6ea6c3c253ad509c92e041fb42625a80928b8c0f11077bf8e35b818dcb8f29b7ac339d9f19cd8a7a69b7adb29e9d48fcab54a2a8fb753fa76a77b5b6bbb7dab53792a930ef74a849c6c2ddb846bd525bc2727364a6572d4aaac6e876359952502426355259d2d671b4177643bd99eb0514bb876a76b754f3ba52395b7533a6a59f5a989cacbd99ea83a9517c5dbb52c8ea97d4ac2f15add4e49b73b72daf16e2deea6f2948e54d6c6a4c47b72529f74aa139577d484b3e594744b702c6b53956c39dd0ed7e25a9ecd89557336f648656d6aeea85559dd93ea84a7b24b704bba9d920f20211a4f65b2e32535b1b627453f68aa926d89a636e15add138fe6c4560084e6d4646b59b509d76e3f6fdcdc5de5ed744b8edc5a257555794abaa79d4e6753794f4ebc27a723b5b5a93c2556c5a947b79b4d280a6ac773a2b56a2e6773ba1d45e59c9c6ceacdc65be2f474a49e80e3ed98da275bab539da84750b82595e794cbe198a84b6cbc5dcb32515299948edaa71d538b7b72a4de764a47adcab2ea129bd391934d653a6a559609cfd6a4f284808680d09ad4968d62696a938db764c44f1e20ee4037957d7a35e9db9d4e6753fa26b53dd2b46b7536a62447475f536f3ba55773493626259bcad33dfd4de5a9ad4efd5acea6e3a9ad0ee76a7a481e3685ae5d63703dbc726f5fec860ebbdfce7d5df18726f24c838620c4a2f8e97caff36020c77e45d01a5c0f857c0e03afdf7bbf2f0826b1df7b33eee0def0e27b337802bef8867867847bc11b3abe2650c620381bff6a8cb5d5d5f7e2f172005f977f57e3acdebbe27bb12800dc832f0635be65e07b417c45b83cf7662c4af1e5f07577eebd175b8075c47c75b8f882f85e9c8f2ed6a32b082e6f06e2fd76640c6e88b1f691478caf0f6ce82a40fb208be424d8b5e3075c9d67fac337fbc7805b81ebd8cff3f4eb575f7cd35c11f3b8177f18e77b81dca02bde12638cc10d2e05186b7c85321079439ce09a3738b00df7c337aebef93a4e827fbcda310ef447ba2f6447a5b83e840a9c2f787578cd9bab602cd6f22dca1763fdb874cdee776f28a47d442074f1088a38bcb77631fe2283d78575767253fc746fa65d1789af185e3c04438021c03ab267bfb00b627c4d7d668d6f608c2f78f5d275edb8e487ef775f443df84848baf04d12cb105f11ae786fc657df0eae0e6c01ce81491ce2efe68b2fbeb5ab039338d4377ff95ea29befecba6e79ef157221c0630eafa82fbeb7762fb88373aec6f7d3d7024cde8c21b83963acb1be16607c71e0f1baaea8f1bdb77675e031cc578bfade4bf457c643bc20f7f86ebeaeab65d7e5aa9107e881e002405f8c411caaf7d411223bb8175f7cefa579e84e6e80a9aba60069fc0bc0c319ad02a062a02180ad02430880025bae04f5c249e0410b95045b163e020f5e741801dd21118187554d125b90211ff000011a1dd8720859c0832cc802db2b08220a983b88d0f10e51e07e6008a9cd0e43df860321b101010d490bfed9f261f7f3423c7a5cf9392302a42f23789e1bbf82830047fa64f0d729b8675fc251e2ae802713581e90ea6453625577133c89bb43f1f3868badb5dd8e4c58eec94ef4f40b3dfd01c8e36fc80129a70fbdef2bc309bc90a279f0a1794a2c41802df4f407ae9d31872c859eab00da001902b2054bb18858048e59886cfc20d013b17a3926487111651d365086d1fbdaf4be124717bdb24d9de8b9642f1c0af9823e1aaa74c81b36a0a0a9f460280ccdb45890288bb541e1eb211685176458be40c4d2cb20f808024750885e26411cfa87f491af2ef5cf58e4eb111600c4018ee05ae694392e996b272c40fe000a208e7c85c207a627c1aa9bfe48021dba56c2c098be999637d0494a1e108704087bc2103e9dd705c9fce932e78c7398c5ec1a73e81c0a20bc812519632118de1cea203a485ff146ee91e28ae00ba2f712424a0cd43d220728e83050488fdedbb4318604ca68a1650598a72524c86045c448030c8876ba33d2045170c2c4f000064012421b3163b6882006a12a360cc1210c325954f18412446409029aa086a7360696c7010da831c3c5982990988a9200130c500292108c148900029e1d2f4c4c1131441428473a72ec7411bcc200a34953af4d1b1d50c38403f0ecc4c8544105144f2891441131c0c0c251020a400024211cc9420c15619aa8d2c1175e6451c5144f38e1031617544841036ac870f184135e8ca0eaa9b7234462a69a0b881186155330d185cb0f32bca0de8e1260c20108708488909a4fcccc428c153ae42003957a4b40008e142122c42f20461662aea082892e5c8af86101305021200047301052230ae2c3e726a6bdcd05c400e30a2ba89882892e45fcb00019607881aa0247083041832020366c7ce001ec35811c56545c288100423dbce04214d416579bdc06fec0c7065e430c4203817fc059ee0fec230b5d2092967be4df8900e7b83d218e7ce3ca34cfdd71e1dcdce453c3cad769e2286f9039c6982b14c11083e0f7e5eb20d52801047aa12b74e9973814bab28e528994105271068e62912e615797e0917e92cd1cd36552c0a107be70e8d23fa68ea2217ae300ca9bfe7949c1417a3e01e80b5e10450f830f3888a580f5a83ff0e9400f0328f0d09272bf5a2c822152b0c691694e17cde0ebc1450f04234842a5033352211b91b242ef868b00654e997342111d27911dd5e85dd0ba8c202de00c5dd9fc986816a84811f50bd4716140a48cd1838b471754e21a1b5e98fc86c4420bb407ea01ae50c0f96663917102d004cd23b4008525783082021031ec9c4254a6d2072d7ce9914f4b39a460fe80dd01e4c842c21b4352c6d00270145f99e88891ac632ca2466f0c8f9824881df4102932ba3a2849b85db0448f47ff0c8d600dc704c79f4ca8140bd60d63354b228668464404100000e31540304020108ac66259900661a0b7f814000d77be5a625096c8b328876110840c3284184208000600830088940c1105002bac06311f38aec58d633e266464ea74d90402e575d21899e916cbc940a901e98135c62a9392539dd60fe947713934a3d9566cd1eea365342af974b583e9d99dc0955e3319084cd4e9191409e480cf72456ee6bf56bdfcf7d0f1030f18cb52a2bdc5c04a97aa38aea42f191e9875e5a4c45067c6f87911ef950d7a6e511be10158bad61cb7061bf22e24d0ce84e513337cc6d4cefb3a06da4bbb84245001623d141de3eeaeeb2fc3da8d60a97a09a5ca901e555944ccb261a8aa77248489d7a154fd0cff5d291c0cc1fdc58b8a96a6259dd26021d93f987b686af73b7dec754922cb4abf6750c1597df7741733010195c7bd2c0813d9c37dfb446b5ec9ad2ff8cd06585bbaad78287eaa274d960c3bd9e6b2dc19b493e4922a69f1bb717787ed76149d45e30e6a9c41880fb5d833eed977a5c717fcfde334433bb3b6366d8aba36a5be5bbef8d3d3127cd07c8d71e480818d3a0986a23e24900429dac0b9e0de6075acf67459c058fc603a807a6d980686a92626b5e989682f2eafb941df499ec496cfc206ad921d7690015a755ad6fee33db77ef36110d68ca81f1050bca92c6c97f214bd7b8f8ba46b0a17de4a00c9865fa8a6483b6f4961732b8d83f5e3365a691ba17403e787901d2bfd4e07048230d7dbcad773c100f5bfe3978175796e13f69c7119e8d7f2c6431fa56c4da0c243687ca6dc4b6615c768d45dd60ffa16068b483541ea12231b2600d339194586d2f8265ceb8bdf5243a24be4e401911681c8eb50c02e418d1fac8afe4358d76be4f59c61a5aef9ce8e1748b5ac7413fc9b8c3b6ace6bd928d8afd4b8ddf29d52557a91e1cf4ab4fff7bb3f2f93a2370baf604f241fec01f782e14cdddf3ac358bf07110a0a1a3264de9b2a3117eada75e2cde803647e216ea2be2362aae06104faa3640816ec5471a3766e7e2033a98828a41f35d5fd424d93abc900326f037be7885489a26b3bf44079fc12fbc75ab9c8be63669c13f1ae6d84c4f31ed332e7af5e60f46b602101b31869a51a44ea09bef77f5003de00784d797263a67c70058b30e057aceb0d6ca7810d73cf3cf281e50dbfc1ec060176d57facc55299e1b1dacff5807ad462210a6e0456fe4c7052c6eac0edb8b1e1ddf32b1496cbd8199f8d95430747c03b974bcc9f4230565140548ad17fcd737db1b6560e8180abac222f359ed296db221d85ddbc9ba9ed054fc3431061c1491e6b8642f1ac8c9964a8c1bd58cd75cca559e2458d4e8c1dbc1bb84bd0410975c84d45e27b065f7ff3704405cfc6d377cbea9c7d08b146079ab922e4833838d311b50303d768236444a75dcd69d1fbfd1ffff16e031057154bfe51dad8dc75873a970ab77e332be81604b1c8ac30a1a3d7acbe274533362d55bedbf1dae1b5e3503d52fd63e5de14c644005e7f425debb85c55ba32eb44355cc61704f4a9d73860010d8edb442a6581c11a5af8eeab96ea19c639223236e3d8b1f5e09913bb98b28e4c863078705a4271a85f334306d11f0ee9bb40240bff022e7bd05b0dbc14daa991bda9940d0b28dc5d200273e16a6ca418cf2612414594213a38caeb1e8a4722e1565f9ac81f61acc42a6190e80c18794f76bc8d0c6e84354c3894a3b7cf3d2b50d3f292d950e9b798b814885d38aa3f58e2f5a68d04efe2a0c5690a964228c1693bd8f7106c1ee95bb3a0707e9ba1088a8ac542e8eae82888be0c19634810c0bafd2f277bef5db7597a3d074217f8f193513ef2c238f1908426cfe12b2ed05662b1bb6270ab7b2b71d2aaa9a487eaf49e2b16e5c8cd30e5d34fe151791f4ba37f7a5d742130f0a3f48e13dd86e1e6a09d819f5622b5bd607a90833827b0dbe78a0e8cae171f80e73b630dd34ac14e91dee5c8c7f6a8bb8ceb50420d39269252990ec3bf30cf7dbd28ac3250d22e0738f09e48afb63f5354f44ea11558719a52b4fa1a42b0d46bf59239fd818f971fedba497a76430e76b947e891bdf456e2c1781e67060539f07652241c4898c2773c3fafef1538c2281f9577e2ea2b9772686926ff233d482a86ea8a7815935b537b3986a4bb15a24df23d087ed3f3744a74e27e5b117d324e70b037bb75b0d431889c910645182a6ce3729dbc03aca027c49907121e204aa922b9e045307e34e69719ae39c2e490ec3b8ae3ad7bd065bb8664769ad955093f9e1344a25a0825681304a4703d61026d32aaeb458c1b8ad7e62642179b75dfbf8c2896199f83d60466f8929fe03af50f2b307fad86fd09aa5eeb06287e1883fe8e90ff9ee9ec059372fd129cc3591462728c907512949cccce0d74f6af3d6e7d372c7952feb1e98ffb77e585ecd4d93206a21baa7d22926ac55cbb76af097ae58761b80f3e497028c0815b412b99e80a4e9de6d7e6ffd2b4bfa11375152d0f0787e29845c434e7f874041cd0b55577d28c7820bb5896cfc2cd2d32b9c41164610e65d2f78c9d19a72326b8974e9dc73cb660708720fb766da1bd9ebd53487d0ec876b6a1da90f77167b75b2510ca1cfc97aef5f6b3ec8f171c69f63e28c60de29e777e72007cf89a5fbf6907e6c32b7fb2c9a5b85c9b8b037c1d95d90ba214ef995f2f97b8fd80f52b78ef07db6511bb6cadbca4f2893c3f2d4b9e5acc6ae90c9938cc42a7a760d3142f9b66e37a4ae26bcdbac1d39f82efed9ae0603c4bb925ce544b1f67e1fe85f705cb18cf163fb3f3c6626fb7118448e2250b48d287efd87e9d70f832b5fe1cc3ff286a6b0111e6a551ad36269566d945d649f020f850c66206cb5c480efefd827170ff0f1f5f8a68edc2260f6c3b008a844c4ae1b176d76fc22012135231df30a36f4a6e372297274f7c15d107679c091dba636bb5f846ea5e496bfd933ddd131b397fc6abcbc57f30687f1ab3beb045fed7abe610d34bcdc5efe26e733579090e919d850a4cb9745b4adf82ed9b1c31dca369ef2d2a113ef4d3b6ea7131b15797536aac8ec9802d9594adc38038611117ed92f5f64e77b056de6e323c00e58440986164b9302339ae60d1a145311ccdff6094b80e44f3522e39fa005da48489da750a30c8fdf51c2d540490addfdef2f99b7b59757ce6da84590b0ae794014265f9e45bbc61b30dd4e1220d7ee643e9c2d5d1619695be8457cd02b2d1907d703a758701fe9d2704a7df7a755600e5d49c5003751f26f337f876eb019602349e3254a0ee74d540c0bbdc90ca5d7984ce456e4be30d749fa18c56702fe84ba0bb67f06155b8b82a3acb23abdbe6417c4bb01766c9ed8d2c617ce2f3b3bb988c0946fd427382473c97b23b0bd46521405964c5c431e9f8a97329428e74134d256cde925870710a1b12fb8078cdd345b8184298fcbd657acbbed0a486049756efad183ca62cfb3ee939a65c1702750d3c5ba9c96990d55ee6afbec6bff0ad36c202d9b33d633b747498797ea3e1f40781cc7d0000eb06458ebaa61570f894b327b63a1961b5f80a88fe018d23dee4cd333b1ce6ebb5c29528011f7fa6ca33c0016138e8eda920fb11b0012a3414a52427da80bc5f13a7b8012c99a15c58d3a3bec67133616dee2618763be6aaf046b0960ac25809a1a66d22bf9889ced540aa8a31f3cea91825fc37448d2fee40f43e1147fe1d59ec8414cbb731d6b7b9f1b9402fdcce9036f6e17c47206d326937d43b820b6f11a39821cc1731374ff51e073d15df8c86d4084e34161eb68ea885f29911fa387b38cf5c953daac76327e32d4ae0f70442350c18ba1baa66d047bb191b785f729b64201366e3940e57b2ec61bdcba91653ad1404a3df66630deee561f789d528a94f7c0907db0e9b7cb4d7afd8fa251765d22535fa3224d0ed8a9b496003f481a2302b0716658382e3687384fb2d1c1eb6e0245906d98b215b3750508a6f5a4cd30e63373614e64bc00dbc24e8183fc40974ea29ccd623062b898e5d58781629136e965bad2e7bebe7819c4599f1cb65d656532d945297db1d862bd83355c9311d4af564da8c67937ef4409c1162ad021c1dd954d7e6d41d02fe58f48f94aa2eb8a0fe1ff2f46577c20692e9aab52099085c6a52f336b2a98085eb68f3f133c58f8c2b122725cd64597ebe9cc956885e7fef42381cb7f2d174d5c6c0b697595d79925926ff59cfc5df66f86e3d06e024eb01505f506bf84d3f33add699affb99d208451499937d77f71e5ae9ccf6c595af487e33178855fe62f02d37b5f83eadc072ad94544cd7c0d529888638674c0c31385cc99ca7e5178516b05c1b7b7c7ea3522ee19c15cf928aa86fb85c313946cbd515008c3ae3723b9f83fd9cf8a0dc0fe390968255b8b2ecc6d6062d8ae96f1d9a01fc689d9a98afb1c045c7598530a3559fbea4a6612ea0c260d02e01cd10aa9b6898bf48514b95f556d20131bd8cf004445eadbd3d076cc458b2c5839e6192e570d73818c6952db27aa0cb8608a6e664e8d84ab440809e7eb0b34e09b519b91ba4ac0b7ded11a41739b0fde06e9e1374b2830c165adf47429855da5785d6c7848930eabc78c5e0648949d018a2640724fc43f8b7101482c2b09514cbcb9561e69865ba80fe12d86cbace504a1d634eb53c903dff68c32ad4aafff9986c30ec36a207b1f4ff5c848ba159f3000af0052876dc612863f1dbb927dfb9be82421fce1a94091d73a280790e7e380f57f46e200a2883ef9afc8b625ad0cbb812de355445891074205968bf3727ceacc7be994f7751a07adee8abf5ae1a8761bd4aa79e89394e6adb66a9a1b23f80f7a53c10d492ad3c28038752dc359e20345d3c9cec3ab8ddf246edf1a8ed507bc0ad0bf5834019aab7751fe783be88e86d8dfccb115909cd21a8848454ba6b481f801cd41257e5ae51035b1aa689090975ff510c9d74e812eaa16807a0a18f54b50bf8c8587fc56b28f5b2c2d5cb1f054074d1c848f68c8851e175291fe74dd2fe5bef856641f87cb2d05941695d730a90e44ee3decd426eea59dc27f39a8c324ec0bed5f904515e5a01bd85bcfc651a43cdb186dcf1e5a3057dc2d533f6e39d2c1d843038c447be29729d8ed1b16b9d45254d2c9bec8176a0530ea8c86edab07a3a274474dc72b1ae2f50113abda289706c8df5d856f8b024ece46954778d238bea82d107bff792ecb7666ee183c57411eb23992f6b637725768c0e5e1095cae454f3a4a87cea8de0d2a846214274b721e26d7e23ea4edff4f281be23b1961d11ecece6dbcabf56be721f7ffbd1b9b2bdc654b0a70fe047eb69a63880e866900b61a160cefab91d3a1d845f7016fae90d339c8473f297fb37af0701e945e9fc09a8fe7c49e44eba3f4519590764a1b3803d0d5aac1397db557306cfd0af4f13d08512053bfd677706a08324f2b0cd426b8d8322dd000feb6ed9a1deee8200be216549e52c5791aa871a460e6921fd429b828069eb0a7896bf3926d68a2df2b97cf3c443d71e9eca3848c943e5c66f08d3066a5f2cb70208f530cd112dfe3f32c86aa523046d6947eac66aadab9d552dca97ebdcac904a5cf11e52bb6eb1c5b91c2e7627bd8cd6d12276ccb3f8d2a4f24ca2d52f6e4a98eebf65136abfe151d8a4c10d8b148845ab7e4624e2d578d7c9419edaa0de912b770f2115cd7d909c0bb5276de9f91367049909348200bb9c389f8ca1b933fa7b6f80229fe1669aa3bf6a384f046236aab04fba9445c1369d45c6c13209fc956773f866bc03abd18cf37464893bde974e31a68678ee6eefcacfaef4f59ad448ad7559c3d516088977beef05efdefbe3ac8ebac39c7808c74681e98d66e631b7394c8ca6ec1549bd65bb88eec713fef18707e306c8b5aee10a6cef56f2a36c8888b70858fb449823f7a1b1c35868045ff96e75cb6726da83a01b7efa259b2f53169ba022967f7e3b9b2c6644b99d2cf14b56b887242f45b21ebf096e38107b5e46aa078f4ac739fafee4abc8b787dfe8b7179272219390af1f3481ea6c77aa8052048fe1b78ccddcfb0770bde985d2c40081eae27a20af18102ea0e11784094f03e1c8e358fcdda076d40b422c733be885288fc3d163e35004023181315a02c701a0135ac91f78f0474b8f394332918635fd4c080c3fe1b765cc8954296125fab57bc0b621ace4723f5826df086b71619d442e4bc8eac5b0e72596844ff855bd80e6e81db873392ce4da621b5153406ed562d659be651ee1d5a5e51f85e244a5d6f261dd223836ba529253b0c9d5d8091affa62c316a803109b689e902b3918a983b86a2465ad70ae977c4c2fa2d1b00cee79cc4dca074a178910089dadffa3b58624d346bbef521d8d7c1171c624e9d0ba0d1c3a6adee7d6f6893cb0f033a24f8c1107c0fd324da34e07750583295e4381cc7379c158fe451fc959983c4f5ca6bc2a70da637aa162c22a1decf94f7c93ed4d4a3897ce6d353bc98dae0e8979d1168db554f25189eef2fec9fc790b2aa03e38a1b8c757e6ff6b388a34531f8874b36961fb228cde6014ec863c42c737b1fbad177a41d2cf3829839e17fd7e0cbfff6834ed171278b5c08280ad57be317b45731733138b012a76c8919ad4ba76d9a690e73de9f561387dc889e253ca14b4a7b5c21431c74ae60d65ac5a81fb4983de030027062cea6b04d2b99e1aa7c3027ca511c9f0c5df36e3d73efbe476036b140f7cfc67953e2ecc312aa3c348717f9d94ce8d813926c1629695f907215e4189c215f1aff2cfa5530df4c9688bc7b50565dda698d1ce8708570a0de8ec0c82ba1b7cc4e2a7c6ea971876448f0243913c8c4cb0f48a71b9217151221f412883eb27d0c3518da3c8d2562f45854f65686741f65c19c4c841c77a1131d025c3cacb20b13f009bb06b42d0ad3ef2fff44fbbdb3029a6ac3c0ae5f3a6a68b13af81704c8b04b7568632135c4bffc3d5978fb70bcf2c85429d30d75cd14079974a3338f84a89d6371c96b4a15f3451512706718783e53d4225cb003fd21aa24f939c6943aca644b8231ce4b18eaa45252bd270c63595d7e3e77938eea18133769d3c68f2cefc7f2df83e80f67afa535a83a9424739f9b6843a4b7d09e884de523dd31c48cd98cb6a65129bce286a00c406aac6778dc016f7ba5aa178e10fd7f41d69085f1d22cc05b310def0f455c171728622f64a0095f98c4f408cf32c39134acd61d96e81c4ccea654768db0081b6cb62841c281b69f06770c2d4caa7ce284524632d40f91f93be4ef944d636aa556c18105148112149bb46ea93f8aa2f5998ac27c2352068cf902db251b5829a2ae4d5c83c505706471dadb8a1d2fbc3bcbb1a8880727899057b692d2f74db2b55bf39b7387525b984d116816c77caeb7245e20fb6d588f1a29610b645374fda00b3a1c13d85caf7f4461198d6666b1b93e117aee382addebdb53020377117e3c4cfded0a263fd3c6fe420a8890c57317d258a3052b9425cded3d3e99eab00e09c10ac0b2d8f00885afa6b6ba84fc4a0b8b31a3459a0ac3ba09063515d43b87aa07e4a46286eda75c598e9dc5f4438b80dfa8eb573c1bfa166d672f95cf55d7c664c265b232bb20d978132c526834de30bdd5990f628db60f816d9ef57fe105baa6873962c2719220f65d3530d8001944955b67bba0bdd506f4decaad6603b0a97108e680ff5647a88fdff07ef396cf1fa22694634c8eb95b8b52eb313027463cfd60631195a92a561a1822b7b1a0a7150f67f566fc78f2598734113c9e540f51ce9b5e30de15077beb1ccb1851c4c28dc466462ce6ccf98cd36aefc70e8460ddb02755af1d062384429ac50bef7064be1008797336e92113a198294b4917641556610aef770da223351c3c560d4adf62fea795172ab31e643908e225042712828e29d8f8005c22c51fbe4896db0fa6b5343a4dbc7750b35a491f41c25a7512a3a68e86c9538b4eed0ca9bb41e7c95b6d92beb961682c47520ec5c4588e468067e60406c53f0bb9ccb244013032bdd4c45ade115cc1fe17672c6e823e04d03076befac32fd1a8a7f1aa6d8e0ed738704a46ac175d19f36a3acbddd61e94d4a6e44db6357ed71ac402843257bce95c662236ed02ac7c2984f1c8f9e9fc5d6b6b99d6c4abcc56730589270e7839161acf55085fb11a59a51442e35959db9311bc8dfd60be56b72828bc6409a66b6af0e01905ba652f039a5f25457242a3769f6c023f05a820ab2e1ad89c95a50d5b91764ae560f4f056810f71b7e8ac3840e6fa1deefb40e809cd37bd7c9645168fe3ca6498ee4412728cf05e964d6e158fc74aadff9f64a3fbb178e805e16defdde2d9e8aa561b3847f4f9c06714ef3613c4740b8a7fdfd79a35cc908f1d88b73094feac7cc55b62694888870cface81010574c2d81bde3c0934bd730c96d769417aa2f1fc3c28c5a377cb0a2b1e8e5d121c0bb1c9c7ae541e32b8f0a3cd63a4845761ba1de26a345377c6654c7a69f140fbd0e82691d0c75b66a32db66585d361e4755e630f38a0e04925f26a0e0940958d391d85e98c7ca9aa9f611f9d3933f25bdaa5010895d5d9a79500c593b00281422c50e09d5334a32c0de115a7f37ff0203a57cd0434150cd0e4b3e05bc66493234a5f82811bcc3ca21959218421c6a6d927cdbbcc6eb63771344e03a9df9037ad20143174f6ae5e007e7b2415ac96026d34df7ff5886534e3d069f94224eabc2c681a02a9e852e0800a0f1d571c165a0c0dc5c8aebbb945e0aa7a69992d92789712eb5da8ff001563fe59662b625e673803f8ea947ea2d4e96bc2e7eb6a05f4312221d6b2d88adbd3fefe33a495d53618808c25f2d609d3460bc73b13494b71f681a5d42b2d6b022d4a82ce935b77335295b5841149950f90a19b9f64505cc71ad31527daf99ad0232407d5906404cdbb11dac61d1e6120b0b252243618bde155a725a087ce293a7f7af12165df75e2a700758ce70aa35163ceb05c0dd8755230d6ff6e232dffcea296207a9a9a6c8fa76eb0ecb3f13ae2c8d0d17798e5fa7eb65d705d7bb5c59deb18bfa978f28b7588dde571a76eeb9893d0c6326fb73c39c39eb589ce348aaec93cbe9389a3bad34db163fcc9cdf4b74025407bef90260670621d131ab72d1bc35aeedcdd3017035eb0388072a42c0d54b290d4316e959871c5c5d1fd5a75f2c5544f8f8f8fa9ac63d63f7836f32396efd4a568c64ff7e337daca2de1782165f9ac63206d9ceaef9a05675577f2d6316eac61c0ef17670798e4d3181bd8684b5523e0f333c0fabcefc251d7324964f89d81fa8cc4e8114870778866c45a9f0ef65224d158d8858741661d83cd4c01b26085816e0a5d741d2b9b94fc8e669001778cb917ec246218a1177fa59814b21f3dba3ec7785f1d83401fe9db3258fe123c5644489ac33e0832bfa06a8893d4ffc76833583b216b40247ef896dd3c70312185a072dd7dd980ce573d1309b2450936468d016c39d690984ad4b20578688402f6b03bbcf2eec6e1136ea95bae1fff09b0df890d37c3a4051d2821d299885fc07771437c0c2e4ba6486a855a878ce0fb1c3190ecbc6264be13db2ff2ed15b8ec415825be4733f916564a9e72f3ba6a34acd8d8e6b7102a64d8f08cc28261af662c8453a04a99e7075ba0dc45bc52cb28c9de4e96df0cff2946dc320aff01c87dc2c4829f31fbeea2ba011ff59eb177f3c6cb239f41c013a5b3a88af442670fae59a2348943710ba142e34ec9a4340115099a7f2596cb87ec4661ba158d280689c8183532d1047d15399636cd1681b0631a104c4084f98e2755fec128056c476da53c1d9108321b6b80739f879a43551216fcec171a2c29325305649e18c1ad31d6b7c9579879505a0f9dc7fea0a772ea31cc5ee76489d450247558099107f3c4878d70263327a4ef4505a4bd298608fbcedb536be4c8da20bedc91ae0b6927b79b5188377b50c4d59b8b23119e71a7c5eb38b9c27243113e39e04720b4adaa2cdf51d645288cb013d0661e2fee236cad1725950cdd5f91105e6ecbe623f4183813474b0ab349762d5214437b80a41258d102925643a4486020a6e0da06a94463b4a549e343d8f7657404762830e74315d9b357d73ac56debc536003c5c70e455936b4175cb58ab40a48d09ffdb924120eac301cadd2a61b6fd202280a0e4379dfa94cfcb412a2e0934b34e2657ef268b7baa0a0e31e4863d464b4030a7e84c411fb8ea666edd87e570be5040fd2c80b0d039a5159766ff13bdbd431cb2c3d2865835b5b68c8ef410dadf97f002bb45ce608aa737fbe288108e357af5452c04fca5a72035ebebd750e338454cf5e0600da7b4566cba2b6241ace172f172de44cd21ad15809a26e4ffabbd11c266c4314e4b5785933c336ab81775c7e7e69d363729108a96988878297e11a9681aa9e3804762f81c832d2d47e6065f64a2d6ad4781d35df9bba797412904147f27b6bc2d26228d3d8c0471f84ed6eb4c469d12e928a64476be46e60b027bac3cdf94dc410b0854a92ea1645c5c322c003469be87967eb1f6790b20b1f56b06d5c6d059da9c623b6ede2ab0617d1c6c2182943f2f0c1f2e4e3e1fd1388d566c5028c4bac0c7ac96981dbb0654347b671a71c0b964d78ef99fff580d149eae758b8465f83bd1b1b57d1f9a664fdc1b57e3820cb556704f47d16a05e01117f14c7c7c95d4de0e7c4c1846f8553a2668687427751130237a73341862b8a4cc2c4318cb617b8f1632620b9927ccbda3dfcb263bd7532a0add78cf293b0b4c31a651f048b2ec5113b90cda4d896005d0b573063497a7141d922c8b195c3b2c7764fd65a066912de629bca532b3a6b7666b05cb33f82dcc06f8ed6217b58d43d49dba08524e4d871315ac8cd19e99f21179a3c9374ad1bf7a82a19dbcaa95e8ec830265baae6e7e2ecfff539b06b25b1941d79c6f4a71a9c053aad471cd52c816d85b5b078c762476ee20ac54c60b63128b91b519442e7d6af2cbabc8c88e5a6b9fb831f83eb46e23cbab824c0ee97a6233dc80ec25774e08d2973afbb4559ce7bb5bf019a84426f3f6bc2770926937764093cce7c7c08d9e60983103849aea5df564a4d80a61ccc7499f3d2acc2c1259679047e3f8f4313835cfb735003c0da33adec1180aaa675d56e91e05f6ac71eea2057aa87cf5a808278ff121ee708aae6e10af2483c0688f62566cb1fca2928fe65968e719a969e052a9fa5f97d9a9dc2171e26f6726d8c9677c9157fcc5acdce1b176e3ed7dc31f0871fd4fc963c2b0dcb99f88e556fa2691348368ffe79387cbc754c1e8c20df5b44dc3687c890a81a90003a4757050651ba9240ee0890192b8477cf346194e657d7e96148ab30da76923266cc397f3cca22052fcb712f3c05c5faa8904e1d527cf568c7af6bf250964f0234221a9ee48f4eb742181c27121605033c9d1ec1421cd169613c6c2ebcfb384b750360fe7b6ff16ccb213225de9dac0a338c241a3360ae4eebfda45ce366f7f311c8b8417ddc57968b7c1ab25e54c3919756428d30816eadced4b55ca2b692e47193cb4b2707aa4999d95b14258fc8b8f13752ca10e5afa33c0caf02b7509ec5ea413ce34bf3c3c1a457c287421b43913538a57185c289c10c0e0a1e88a18083d9f3ef8682b6a1a6269ed2573a4b60c6e81f34a2175b37013d485c9fc559125a48c1461a5818dfdb15917ecd4cd285902f0171cee89399ea74aba28a8f60bef19b722793d1554d2750d3b755183be24d86f94645a3ca39e1aa08272a2f87e61bf4ff4cb631fa39968c66622d00abe11b39f07e5a4a26d9d0b02f779af9175e1bdce5e4ca3caee6897560bce9eed24b438a4b1e48166f783342dccb793551e5c72f248822663dddeec751bf6ec37018ac7630de31a193c7680250e28d912b87698e2b539c40f66ada6e4e76b205a21676bf297167324f3f9f847e557d5add7872b586c992ca50510787074476756a3499184450ad3f25c5ae2c18864720edf09446b70ec48e50ea9e51371420c80250100b806945bace3a25418542ff764f60c50acdd9b92eb3b23eba14b04138750da3b21cec9ec856593fc87f76d9dfb26ea8c43dc439cd613c607f1986aaeafcdaf2ebbac8a5337ac27d85bce0c713507034472cbb3715bf4afb09720fcc5edc96a491b6d6aa67dbb8e3bc7f9b8d75840a0c88b4aeeb6c8c1d946cdddfa6cbb53f32851d8c3a6841a590d4566de678ccc5510358c6c6289d6aa621dedb20e39c592356ce9d0ae0e00b6238885984f56002f6180e036cf67e399e68472dcb0370b61d9e1d119a2c12c9fe28e5398d55c923bbd6b90bda16efddd5f74b383fe5a41de84940a5ea33aab603f4ada77d211a6caee505afe59a39640f4981ad97e4fdc209a3c753594c14881c7c099c62ee3ebf0c27d716703ba6937b3c45afd9d95c42b0fa9faa27a7106a86c24d339cb9f23fc399bec7ca5e8002101db5b879e4f4997dcd3ab1a930a9f91411f08028e991e21a310a9405a972e8385d6c5744c891e6b30b80fbf0da81d7931d1900dfc3bbb3c59e714b8f615675c60718cbe2635f94aa601021035f67facdb2edabb6dec289e949d75a3ac77f6a6486e68f886c0cafd0a8d3b218f5ff985af4865b1ceaabb2ad7a93666d8c9030112ac80a82160b31d039849defbe00e00a0151a9986eae59ea2690ca95e8dcaceb5035ff8ee8cffbcee826a51d1ae169c73669a8b2443bb1e8bf9f8536ad98fde0ecd6c6a8bec989add078cd87bc42c832887a4b5cc47420ddcb27854ee318e63ec1f94496d2f4e371d17ed4e7301b9e7b8a86121d7b5a07e1ccdaa524e8a29075a66dcea1f329c7e49ed1e490bf4f4c229555d6dd3834499d1f6c242186f2b50b5bea640b5a646db33195d96e561aca512dff7f6e337d0dba016abe47197371a4492feb9dac0a1768c2433b8f379ee234144c9f7372f7a66f01623f6cf3131d30b2caea803cfe738aada0dae9012c362aa38a7bf160d0263abad0c01e59442259da29f9703a3619b8f16bb20f32ec2f001184c40abc6bfa311d758ce78bef664061c1cf2e9ef61010978725cef9aad4efe0c04ee9162b462b53ccb1d615897a1dc94e0fb6d2665c25ba4d9703094d0a943b879f984991d6540fd7912a95239a260fb44f0ee87c174a0b990c3f7057e7326ffe8d198400a9517676814bd82683da582f17716e1a69bc03aa9823103685935965680df9ab5e34dcdd143f628dbc77c434f33489dd086b62d965a0e0466eb72c42350c40406341f23284619cd4a2ed2ffc35f0b45a5c1b873f105096c6380f548eb20f31fec5d4483ab8924ca74ec12d505b11b0fffa05fa45c68e2326e796ecb171a7d128634e423bb2cc30c7062fb1ae19fe80caccff7d3efc9429bfc1ff529fc3e109bd4a9ff2521ef0b6c2187370a8fa4c1467bd1945d3b6ba99361f4542313952d0215b956d3d3e2a5049e74b5658cbb6d803f844043ead9b64d88f781580986a39442d04677725050d2a2d0815ed2d02e218128402f131d955bdc4540153cc323c422418c5c5a3da1bbab90510ea13dd31c31c20bdef1d8ce025b8a3983338d383d80d21b8ac936279948319bcb2e40a408dc87650a33028af4d48c19c879352224a2357d03287c5014520334428d6a710161165eaa0bda62a7a0d5dc4e2cb85849f43d5da8b0bdce38008b7643833da42483217da900ef5f725c4ec36974b8b17248429d07f839aca8f07e13f4457117aec65f6f98f4f86c02110d21a0cd011c4f5e6d0ef2789ac179837c0a9bc0a6b3040cdde9c96041ce6621005ca1d044295e920eebea95f763a125b0a8b739cc8c486f8aa5f37d08276afb70b6f4f8e9c1e8e6aff0eb7462583cb73dc7e12b81384eb64ad1167e530679d80c5ae4cc3c000ddb72b06e8f8bf7d444351f424a1e2c8e55bb7581f1531ee8490e00ecc2fc8c21d73aec5cc2d8dc36d7541d77afb1331a011bb067e05c2dc6f4c5911b5096d78e89824d5e900ded089d7bab98836d17ae9868c97ec26bd1a1e0168446f0707ec3a971f295a4785b9813380b26031578b0c4526230a528cc2a00ab88c12ae2308bb86157d804f0f2343ddc568d86db619fe995c98f7e2b56d566d06471db314b322ffc2c1250b674275029bdf3d6a0559bc44d9f7b520bf4265e60f926ff5ee443465e9bfb7c9adb85280878058866f0db2211601421c7dc618f8ac850c03186b3053132ffcbf4b3a4c56af55a749841ad2781ebe923b10047303ebb6f7f6624a5bc7b2decec5a694a2d506b363e64be7f5f37a12175031128d5af3c50d19b4fc8a5419b396f7652757837c40732f49a0cdd4240beecf35988c930b81e2fa6579a9fbb4de7ebeec5975927a9599fe1e4272f0d830adab971fa0dcec6acd6609ac62be4f95b273af52e8b0e527b7e7e43940c84ed62be4326b1586eee2cedb9ad0b76c8377e8191500931d32b03825c77eda9af8b4e00fcb686095a609ce6822573b8571aea2fc8fa5e8757687acc399cd17dbdeeb77eaf3b579af1fce55a40b1ac680278d0a3f4bdd2ca21ad57482d971d7f13a07a091a937f5e64eacee9e17767dd49c9eb71d1784ee0abd4d88fd6409e5cbe14af4fb7a74de0f7029021e15f569464bf7fab9880741a87cb70be5971a46c6f41ed13032f8962736a76ce6035e6dcf5545a42c39dadcf7024f090faabc44b1895b3f4087986798ef23ee0eb4de089d2cf7dffd5247474130b597645c2363eb6a102177bcad65d6222f81084c8b9745f33122f388717694d0aa6c976d1eb296b72837b64315b192f0e2b503ec738302e6e945a935d67eb5cd82b9dacdc736410a15c058901566b4366e2b1cc5e6df51da5b210c3028259375127716163ccc2b6baeca0643216932fd473c1371d1518ec34beb0b374a7f82d7e00339e2abe7000f7aa651d8d9e3304b87c82bce2d64730b242ae0efb816a61a7cf7de0fd38d51e2714de543f034161ebb353e9c1b2d64d3378688ceb49c9475be861ce3c0413a5f77a88b62bf6634c9aaf0fb6ab3a850d3050741ac07cf369d05660dbba4fa30b4dda321d0897bd1df0a252e0cc6b71a1c5e68e880d411e0ccbd5c9dab6873618471d0caf7dc94811a41830f404f1a0cd70221de8350881402e769087a7cc262ae82144a021cb11dfc4cf97e4b8d04107ee50934165cc871aa0533115ef301e289ae5829e30b658bacdf8444fe3ce905cb7b11a895f2062145177b059a15d344ec7e226f7bf442d3fb8e00df091477d8193023cb618ed1b926d3a2a3b5ec361528cd4b890a1ce85c8793ce460fb6227574587a2bd764fcd0be7ba0670a8428b5b2c6a7c54402393cdc97a54a7a41f7445f76e4b6303783dc5e6e4a96eef88898a8e3a6b8187033c9b56dd764444c8bda58a6c05ebe6655de634d540ea1e6f3562b2be8037c67c110c2fae1254989681a8056f1dea894d3e5d67205801864ae84f93adf79cbd663c036f3653bb269571a192fb9edbaf0209b63b98b7a63a00749de02204baf65ff84d59eb846b89d9e5ac4ddec7fdffe7505b3191cdd5b78169c416de7f4fa8ad836e27a6515bbf25376bfc2ba5ba1f92676d2420df0936b80401e98b2ee3bc202fa29f1876427b49d6e8c93c8bc68431ad6262712a6a3c7108e4f754711859103a8100071670090f69f3a3d05a216964db1f772dcba9f879f618a19e1e01526b7cf3868a8f91eb666b2bc4f729bebd3b1511b734f5858698653e05c80ecd9e11f23b2ff434d8b5c7c7315a26bf4a8c112a3aa2ad57178493143da74cd95af2f1150661ca330ed0e8166390760ccb415df9290f5623f74f76d90a84da1623527e723813f9c3195174436d4b7ccacf8bab74128d328a877af480a1c171a67971f5858097f983da71acacba030c6f8396a6d8a52b63df139f26e014d109563b9362077251db49ee549185fb43cd90a48f60e5cfa166bc08c07f07073fb375e492a578b8aabec79a282a38b1a791bc7a26a1c6fd04d0d525294250eeabc112f98d7c0579c832fc8a6a9a0397d239bc45e68a29cf80a3face8f6b4baed22507ed6aad68322ebe3c163ee2ae32ace84909b6c8c94319e92af574bc3be9d84371c543bd5e306429c0a1cef03d91daba8007204ab7032339672d10c8fd412609ea86f419cf1386b752933bcd1ba0745f497bc91922ca56fc6bce88b4af41ea54f40ba1983c4bddc8c6457f2a16e1c43bea86f36c5f9a371bc585d786dee488a5f986fba236ce066dd6980a3a691574f43b51d00476028a87724aed051c710f3a5bb7c8d8fe8dff51c7e225a924f324a12b18d4aae5d5c9974cc47e6fadc184b439a0cf754ad2d01427c04b4d66ebcda636b6d2602c16d5ae266839621efe0ac0d0e377d109b4f75f88e5428ec46d58739d04dc1cec1b82dcf8f18df90473ae93fa67563e7ce9f71d100ae7a8168fd44a4cb9212493e9af9354772cf828a175fdd143fc358d3fe6a6af0b8eb42f91c06654cfa21ac2b896ed1fb03a5efcd1d9115722ebf4590df3497ae85fe066a01e202a91ddce018c639ddc77798b2e7e0cab6303060c705b8e824033af98e70064929a2b39a7d554caea3ab8d9990dc345810f24c1c2a9353e8de10f3f5465f60c7e98e8b77cb88f8eb32f8c782c757e4d0eab89d09f9971a72d383954327c83bb3e09b6db670c31e3c7bc063368ed9e75dd957f3c8d0dd12fdc30c1193ecebe95758af43ab1a17e149dc48fd669b001f4d63a95754878ebb54ea867a1c26f607249155720e50b68d8afb432b020dcde4bc00a39f441feabeed21552d31d80977431a89977f62eaf07d68052cef71adb0153d0ee4e3c7b066b14f51d7f9ebb932e6791be36307bd99a6aee847e8a678b8eee6443b003437594f0403cdf995ccc6f07561b957a7f9d5fd9e5a17a405edd69cf43b4d8c067a68d94c9ef4811c8ee0c42a49c3c42758509fb37c278da8a30376224ac3b19e028eac9401615977a101630a57af3c3ab3b39152b3e1f4266806ee85454a0b5d93e8efd3a893937281d47d257e5b9f41bfbcad5ee72645ac48b8f3c45afdd38771c3a075a2f7f820f774cc322ef3bffb6f6b8132c93a4701bc0514822e644cfac0880121d4be8cf9def88400c7fa9a2eeb149e0c43a14496a417af03749aa04c68ac2fc621a5f51249b0b4aa2a4da164b4aaaf013b74a85354aebe1f1c41b38cc55b6733bd0f5d6a4f1068e8aed21b47a8ec14c8de92ff07170c89efcef0dae479ccc58534f85050d542b671237327722a615aeb021f74ca879444f5c1115d144a59ae5940b2720fa78adcb7c03cc36800b632b8c34568d20bb267e80ac2644e2e895cabe309bf38d14d885aefb9a642398bec6e14310f76d5842375405853509ddb9e141ea76be3f41e9935a397746714941b42a5594cf340251ec18d6d450f7634114578ab64b81eec2755d915c57976e85eb0f9b5d81b66a7b13672ea4dc0a7ffab7c2273fb3181579f19c8fc97b86e00a2771e2388962f6faf489693ca308707571c599395653851c8bb149b53eaec1d3816f85a3bef2eaea1ad3e64a29d19d4da4eff7ebe4959c08390d72070abf39f64424baf3c18c2cab857ddc97d5976f2723d6cc47e76c1a4851b95b08b39fa761ca8eaa500477da423d83d32ec0f1139f8f02503e91e2c28cf5a402aeb24dab7f81d9bb14e6d4fbaf2932b1708c5a74a9cca096e6ea8382ae148006ca6dca2e1bcd1a4392402263b9ec368deac5a800e3ce4188560ce8c319316c5c620b8af92a48d309e76b37c586da4d512397cbcad6efcb4f60784d3b892e04ae6b0df341322b08240546a5666fb945bfe27e715a1262161503fa58e2c90d1065595402178095aa8f633352dfab604827d962792e4ab93f71dfc58dc138790d1840d7a237b7c69aabe9477043c6d6b78e9c00b6e96eaf248e75de27a0b740925f5c751fc4ca157a07522f02a1610bdd1abacb0969f5dfe6b852403e88b73752bd5255ef65bd560f3d523d9f6f3dd311c47a71a1e249677b1f60b0b390af6609c5c3e38b87e812b5050528c568b391c8ac0b35cef574a1eb2c3f516958344da74e3273b2c5565ce42cf3cfd4a2fa21ff8b6fd3053b93ab8103c37e10959fc5ecb9a226cedfcfffeff2a672f011085093a6584406f137d2a56a7afb82f58ebb9a80326009ce4fc7cd290c1dce9c65d1472482561141e3a6edb79729852f86fba50fb098016852d662c832941ffb426bcf01c95714726d94f828d216c5dfca135e085e80f6db71f30f693e4bf12d2d478c76bfdc91c9495c10aadd0ea7b97349030da502e8ee0d32696c2078536c2e5a5adecfafeece7249dac9d5e93c6822f9b98d99ed223e157693d810350e531e3587298cd20194a2ce11e5a36afe9c88b787abba1e30e7d9904ac6f083ef91ff881d5129c2aa0f1717ccd6f17b7f1b0e56c10cb28bdc7514ee9cd268cfc9ff2293ad799f73196e2fa7d315a5f065a005df07dc503c9369a7ab25a13d8cce431ffdf633751ee96cde57ba2ddc7d6955f01311d46e39c971c1d2d349485ff90dbf691094506eab0b7e7251d0063994a8726f14dd013d6856b8cc5a3df1f27dfeef56e04eb31a9ff0021a0f19ed808cffac7c46638cb2e07238fc329b83a0835ddda3d76421d8911ff055082a52669dadf00ff4c140e8f1cc31f5dd567a61f4c6bfbcd6248387e3bcdc8eb8f63238be3bed2673bc2605ef9074bc9f4e608cb7a30c666bd70a32e5b595e6176dd5a1d5e42bb2a58169b5bd537d600f923e3406928f7074081a5870a45285a3fc678536db9f6809580fea48f71e7552fce6f3a1299efbe91e5d3347670c1f36a88c50d5a7aa62a918cbf3b5c8103e3d0e737f83cc8d85ce7c1a36ae7713bed62dbfe852c20d74a620ae09248f189ad5ea6487e15d842992babe5c8196a88448cd7250ef2450ba1341b566580e44a50315a75427de60578adcce6a73eb15d8da1bd0122bd9f39fe4cd4f0ab2efac94a38118c12ec758d6f3e4ed998c63b32cabc346185a64925b44d63b446632b977c19d6a8ab561fbc122cd5ce309d6f4aeabff132d69474312ff4f502de0f034e5034e3e156553fa9531399cc74f6c1c2467fc20c1c4a7a9f8725a9681d3f4dfc851b0194b45d5561542c168091ea0643167fdb88a0f391bbd9654ff27171750fb914caa7fbd020ba8be7df640a691f8470884cf41939012d43b8f2371c7129fdd65de40fd554164f646b564cdac9318ab8603fa6ea73c45377fe2555e1fdb0502410d87ce511113194c159dd9329a82424d4a41ac3fc01efb5d2d8013c4ae706251e60f4bdf57c4035cd61b8f3c0509c4250ea7f47007beb8efa2e8a8a2b57e83fcb59a880042b538df4d42c58005d263a14c80ea5e1a1e0f2181ec10710f3853f9d7c998731ede05188bdc9d23979c86905204230078547930fa01d2511ecffd16e8098c33a4297247dc0bc21d18b32ad6fef2ea042a98dd33eb6cdc9950901eb08f048a9734cbbbdee6eb8db22514de24195f5ade531cb69b5a0e8d003386910d06e07bb280353a392f185345b32b359fafcadfc5847a9a9ca4827137812f44f7cdc41cc7743578c22917dbfa11217df0a8986fcd44d9a1962630dcee10e2fa1012fd0e80715869e91cb35be814be2a8452f60e9908334b11cf096e9ba3373d9944f9063091f64b39a72a418998ab4318d823c9390bfa2f6f7c89eedd710885c2537eb7a76ee37a76435c9ba21447aa5aa56cbd030104f49f952e11242ad8a1fdbc4093dc0e418d26bc520433c6fd33da3888c9479763930efe028707ad342e66db5c4e06cccf4db8d232a65edd6cd66a658b024de4a90f5114e72a5868462c6169b2339854e7018c5b746d660cc03eb8836edda2d2e033c9d3bcfd0e63697fbbd6f1d10d66dab557abf4bae92a4994ddc25569aead3b850bdbf3cf0f40f1330fb95d9c6fe9a5122748583137a0ad96e2bd07f1e5d063f6722f1f8dce184e49e96f0b636aaa1141d0245c3c46bcb008082e2e596085f9633253ecbcc58219ba5c48062ae9a17bae4ca7fefd71efa07e0d6d97ebbc55701a10afee21739bf45f2d8cbe8dc8cf4ad0bf253442ae7b6bacd2086fcdebb5bbf8c0aeb46f5d4a6dbdc06d6dd17f47b9e0bcc2e148d095815482c74b3f45802d7310f14a46412c4296b993fff54c8f1ec7437b25860415ce654deff8383709e253daf61481eb16f984ad04bbc35784dde19521e686db8efcb17c2c31604f014aba30ff1547c0a28cb1d9a9cbfd17b36ad2ca071bc4aeb6afd831708bb0223159441759354c42224bdbf4102eb7991ed3bc1c0102c00a1a0ace92240557cf82f320418b65cfbe47307fe338bd8a2dbafb149ab93ba95732f577565bacf15ccbb17a482cbadf9b5b8c9edcde71c232f531f00d6e14b13fa6739cbe52433969c790d65e48950f783240a61b7a6bdfe25a89093e889f99d00d86eeff554fa046a220a2642033841d573bf4e4a8542fa8c2f8cb9d4845a0fc1767beafd19f7eef684996d82a683a37dc3f9dc4768e1f606cb34e7e8ce46f8c100d8e8c0c11900064de651e3290f054326d4af5c1fd04fc2c1ae2330b135c91a2abaad95ad8671a38447880220a4892608195970b060897d8a00321ea2df894f20da0ab587623269239b43db32104569836af0024b5068453d18b866fb33fa862263331ce472d190022d4cd55af0b957d4e84d1d74c503541fb4e680dc3666d7eadb7c5ce3405c9c97716b15a509f4766ff1a2681955c0f95076e8915c138050ddaecccf3ae39e70ec9349580470369ea2abb0834861f67edcfadb68d40e05645c9815eb483c349094cbb2dec663ada820f0a204a504b036de6dd66a8fe325084d87759d185c2fc355a4c6f7d4e148093a11668edb01b34733faac3be3f8938928076e9daa2e996039b0679e989018afa0a73f14c9635e4c57d6de821e73f5d7d9f39b1077badec7f2e13e5eccc8fbf8d933467aabe87aa0515e1b049a7935a10b9dd44ba82ac7f4bf8b02fea7f8eeb0f3ae928c3a98bd2d17b3a9acb7f129894d643e177a6b9b0811b90904b02e118fedc775a49bd433639705ded929ef3c6f062943d3dcbbd8085df5ca977ff76e3a85d770712b9ceb151d973c7f64a66f597a396f778a85e92b39152b9fd4388dda10c9837649c59243b90b367569e16c669027983cc8663ae3cd1f4aec3ef96a1b0071d740ac49b5080656e7f7025fc29ffc04c989d722969dcf17571173c7f2bf5f61b763c1e422277bcae3a7752f6a202297c9550f0c1a610aefa1ecb79b687fd13c4fa1139e7133ef2277c45a71b07e1a9870de21fc41e0c8bcad4fbc3037c0450b81bbc46d5164f1a945ccaeefe8a3f2aa7baa6984628a5e92839f471db753e5bcb2d9db33fa08a4bd08768c8af2073c1baf44356f8a5888dd5bf37b9ed60c1a433acf3d05f353fd19b1ccb5ba6e2c4357664ad298b426e257dc0891bb9233dc410f7808b607716a1d67b44c3d985dc72f881409d8bd40f8bb2c2a8dc431f7a14b42bb78bf507474c24a8af079012217f3b10877431b2d6650504695d8f379185d415e7441d1e8ef8f3a988040aaa7dfc918e893e7b8e7e26a0c375257a1f33c637b790ffc97b42cfc97bff8b150660ea03963cf96bc52959618882070f62b3ce78ea2102fc666905c330327a74220587faf070e30ca6db2000676be276a591772cfcff04ed0303d93c11b902aed254a4ccfd4aa9de2f804b53707b458593c7f0fae2951c1210f7a1406fcb2b575cc7df9168c725ee51e225092df283808c94916aaf8608fc567f7629c073bf952da13a55e5b3ea3fa4bbda4db250e570c5dca1fd565df52f8845a3d9c09ee9af92831046c06efe4cbea47848c20b662b4837ba14eb4c622bce19ecc4b468762972bd0dc11db017a2d0c5b0916d0e67845dc845573832bd770c20585ffdc8c0e232ea21305ff5d085a8a3e075e326b078c86905dd6ba7c7711ece99de3cd31159c40108f88cc1f954433871db39cbef0c4438ac198251a6628c07b9847a97130c8522fb33f685bf3cab31951206c7a7fafc34c3b9b8a4b9922aa012138d1d2ba67b1572b8a45ed0bf523211b2e6a16723ac6785f66a5cd1891278560d2df4ac379ebaa50c54cf088f38f7ec8438be47049280a27d70d627e8b1652a6c4baa9b98bc17c6253758e0c270e617f30862075d0de2f80e7a5671a2911268c47a6ecf0b45e852029392e9486d7b5c3b67ee59d46f32769ca6d3573b15082d0c8b00a654d3f17b00ede2f09c5c2cf8954b5a33810d178f06a5297a80d4b9b1c08ea2474c049fc54a65330231c38490a64a45a272305181faed90bc34c996969b26284d7d988757c7c84df9818fc9b7dbf7899f7b17700a666b872cdc5742242998042fbfc41192720a712046226dd9c9d1f8faeff6888a318a739476be103083bcdcaa834209275c91cfab8e2e9be923decb9f855f6e4b7c737357b3e0708495d5878232baf49ff0b152b6221a0c692c0ba4cc83d0134a1eeab13d45ef1f4b47a844bad34358270eada079c8cac86f5907209a813a563976a966624c1793599607d59a5df1c2e5564733b8fa9cbb6d85ed64d40cb5be96267a13b3cf89c07937a36d5581ed383153fd4279152bceafdfb622bf9870eb2293ae1cf2b78c0f6370925588bcb9eceedf723f4def20338440507f6021d6660e76929b92a3a41ab35d77fb1d71e7c02a4ad0742cdba6e97221a549f45e2ae0137095b6aac3e7c682965ab43823eab46be25b966c80f7eac5f19f1d798aab552915d0ee3279811349c4291c20d812b2a9ade4de0cda81be4cae3a14a06e1ae42e026599c890c69533f25fd1b9ea3ace255527a8520e530833c1b3c3626f546a12960e725580f6c218337b05682aa3e5c10a91eb1826559cae0a2cf034833ba65fe15902574d605284086d33b0b228ad667718eb9f18f7ae419d756034cb271fdf532ba7864974c5c67e895d9cc20efe65244050e75dc8ca56f2ca6c23a4ea5d297e1e5240d25bc8a78c0b0a5fbea97f6a52c157dc2dfcb3475bc895f7176f09724813cfa9025b96ccc26b8708b848df956862f82d5c1201d005afe14a86fc7ec2d433183abe78c0661d6f09ce610315e6185e3e93fe325d2a3456a4e033c227304ba53875c5aba4e80c33749d7c9084fd57b8722a7962e8e1398027621bf78da48b9aeed2fa909351514a69ba27e54058a772a13d11564a75c155a7dafbe59c5c744e018842ecc14c915f2ccca37bfcc44d0c860e222af4d02baf25920b9d5f68fb7b8885b1308906499b74303173ecb06873ef85d3ea9927c83ab2bd2b74390833d3d962d5eef029c173856786bb86695c6fe76486a6e043ab152f1063d5d1d2044f82c799338b3a2317f0d6340d33a93eb4758968344968888098d3100c874e3a256d79f1c32697ba8c8e891538b3b93f27195db08e2cba1daa723a15f40e300632862d9addaa990432f9ae19ddf4a098c87bc8e6f88cf28202ede0a6aa48f509059ad300100de2061afda4409936302961d889c5116e61790a9a5270c52d34e36928d6a0e557e5d9b7444e89ef0d5a11616a3d14351383edc749120eedd4bd3d56dd1ee17a119cdaac4470d2a858106ac7b31b791fb3c6a336826c41ec9d31269631b44253add6238608eddec4f289f462ec37cb7e4efc08d87498f7a9f547d9d24d49d3a8b463458230ee7a33d372bd8443db5d00d91120b276a44d482b92ece453e45385cdbe32ffd9959c1f58209cae39140edacf4efe9078d06611f285d4569241a6ba21f07c27cc29b6824a61287685902d81cd477b944f0e49f30cca08262fa74f1baf4d49375cdd0b8b3ada042c43f7bd0fd5ec1146d73e5b9cd78ff07a639c38bbff8a5c0ff37ce9ea1c4616a52f3008d2f50e6cfcc2e7309359a475d5fa88eb7ade20bb7467bbfe7344b494be58ec95396f1b5fd752e0a69d1657a83bd5a83f9dfe3b588dd8d4e6d9f8d237c9f0689eb3c5e5d0d48865e46c2a18e118218ab03ea6c2d313c9c75c67e8c49e8af8b4f25afb12d7bd2b3a1fa646623cee44372cdcbd0ace5f061db6b8099abb3c055afcd903720b362bbb0c96bced173ad7e13305315b44ee0b53d61c9512067c725cc58ba7a6ae3cf1b0b5969963f0859d5d5d3b6fd0a7f97e9a2c33da6b7cdf3da32fe6f8fcb6b221339c97c07cf4e421cede48a0224634175dc3a11ce449cbab1217f6b7ad690d4984fae28ce1130f167e2ebdf9f69c0416195b224fc810ab94a29fac3399fe0067c47c7329b1316ab92258e71c9c078ebdc8b41ca02518d79793d0394d85a5a6cc231312466c1a15aa17a0a4c1f7de0b2708e752d6401a555f55ea4c1298147d5c753f7fe56d3fd1a86476d182fbaa51aad114ce6c7f4b0e2df8d8484e9ad042cda153960bcf910c1ee50f74f3c0d5dc0b20bbf382ef50e1c9c2d3e48acbbbe6d5808d108f92f31e79b66d0d08248c6952810b4ad1007d51270a919270a801d3f73ce6f0786190b6255a5f34d0110948bdbc6fe5cc6ba72fe1343d26de315c9604459af5d0e7a51f00b7c151a8a6eff22397ba569229e6894bc9fc5a1ae644c7ad4ddafb77a3cf8bbb63de667e96b7a7d270c043216b76c28a560e949c7059b2b41964def3274581e1513dae82258eb37374373bcc5414e473704c54a7273775f005195f4d63436c1b70d189bdf622105eccc5418ff3222ce4dc70fb5ede7db4d2eec4a2cc743de6a7b6f090e8368c21803ee5bf749f8531380e3e6877c6a938861ac6eb4446f5894c4e0013d25276c26850a129f043499af14bdf1e48d278f120e8d061c1233055e6c883988ac12fa3615b9e056ffcf23ce19898ac71c76455149f383f561ac12efff253140531bf11a5835486f303278fc19344e1f8e1ab6d249faa04376d515ba5f770510fefa504674771695065e7ce96f39835c9b3001528fd9ce42fb355f2d9aef0900b387cae5ef2435e286009700d5c2e660fd962c8e11b3946b27bf1e9f4eff08e85369663b4a1fa2ee1fe92d2c07145dbb8109cb02d698ec910a7f6e928ab96b1bd2a8c58ee1e3dac7d47ed59774dc67098770e6f17f463c23711b88a1f7bf5876c6e8c471f7ec3321de5e68d79e5a188704d76ca92d0e18f2d8acea666a2c7ce94253a14a2c95ce8e96a34a30e95d3c8b750145abf438cc6a14a5188341615068e82701a13211135c7e434c67c83625c97e1a56ba0335c4330c8120b665a81dc05240a386a74db2d391ca01380318ab70f86b131519335ab160fd8f22d6386164fc833c60f1c8f0d1ad734035dea0fbf9abb26255566a614acc0bf2319f9f3ea32ebf86a40682a6ede8d98f8c01a61e47eb5a1504fba73223e6f84ee67b1dadf516dd25e6060b310a0339168f09af875b6556516418869650fb49838f0a72e0c9c6e454db16cbd865ce7a29a6a14a0c48a55090d9cf8365e964f5183afb71a9dfa20420ee7fed997063fc49a250dcf920a3a098db1a327725a78cea57e678bf62c560c9f2aa667f1b7f349e975e3843ee4041a7df2499276a30628af90ad5e1270bf9d96169d1e605301f4d30d93f52a50bc5248706f3833bfb81baf9ef0140acddce9a874546c495202c90630c86a1cb02bb89fdd29926ddd2878d282d4700d022fc2f9f2dd610db1f2917f24f2c80fc1031bc9ded7182ce5e38fa0445c8b828bc907c9088dd53691f686634e50a00f00bb9b9e459cbd1028c536f8bdd9148534c6c6d1d372b9df60ab7a969b0ae5b82ad967a4d22d29a568b4ed407c6a4e3add36dd2da774bccbe43e20c452612f898e813bca91f51b22730fc581a3c4ad99f829fce2c8ba7691f5926f6a14733d10d9bc809e9a0c14324e9c4693b85de9aa726fc50108b3581731d013881b5499068ee906a1183b1020b6a60323e301742240394f24f4c076109e6c225147a28fdfb63d4d76c71f7d22db9a3c5ddcb3d99e87844b73e2a2cdad6199fd16c67edb52a670169116711aea70e3f5dc1eb7dd70df993db9ed3a8ade7df48ca64596e7bed3616ae42b1f6e95dd68363b77ebc99d83bb25770e1465eb01e46e38035cdd9aaac2540e55d322da94ffc7f25e15d47d70a76cbbc26ec85531cdb6796a724124ba571e14a0a2c00f054528d060b662d52a4eab216fb6ca6f3e2a0e59bd3b2b0258c1bdc9ea1f6ff77455a2556a7e958d9e22d7b45df9b0cd335b55beb9598e6606363606238017c4b7deb21acea84a4dd7aa8ae6aa8d7c5515a6aabb6fbc5497525d4965232e95867f93f584862acebf89c75754475426fee5da53ac4c55f3f97f7eaac913f9a9b5531cdedcc63605fbea787b3595e7d7b4ced4d1d49a29afff2f45a8540b66aa9c6df5fa66969a2bd5c024f588549c374935e1445274a4f2ff04accc0914fd3faa0651954f206602b809be463d4237918f6af2ffe628ba515b28ead29ba928336f8a6a459d08e5e9df044baac723d7624475f7dd75a83f7166a19a84b2f11faac1b6d3a03869bc20aa72504d4c50638faa5c0258ffa6047c246822019d045fffff09d67f4af4a909aa3f7dfdbf2756ff789b0fd05313d6538c08489911a8f9efba18411e30021b66274fbdf361272a9d74fc739ac5290e8ebc8b6dcae9680e819cd6fe337013abff38550fd34d7cfe3751f93757645ddd9a0e37d9784db0d6d46854b5a6479ab680b5ac3eaefc0ba809eebfd52830132bde02333d32d17567de536026336fa29bdd2c47eb68dacad33a3434d570c6ddb2c5adc8ba7db6fb56b59c1abad58dea3654e51c0edd281bbae1d0cda2972ef5f4529eff37f97a89eeff5fa857249af2bb4b63739658fdbfc9f24c96596e49cdbfe965892eaddb96c686793bf734674b0dccbc8b739504fd7f9b2b9dffbb1da66ccb2be59eae404a829ead5b53232531bf724a474a3526917ab07627bf36cbd1e626f1f99f545cb7ce6bca8f394f8a51b7a67c9d9494c4e75f5293779364a338d49b9514294e3adc2d31d2954831de1ca6755cd5b9ef48dfee646ef90ae9d19bc916d20290ceadeadee6edf56bee51dba39f23508ef8fc9b68aa8feb0accbf3d4c5947261a496ad4a4d157a35e52b5e35ccdbcddc2dca258395e4eea9eae6513e5914de36e5334080a80002ec90816a3358cee189158e468511cae0e397f3fa2bae5ce2067ef99b7fd776af6a8723617dbb3453e16e1075c3dd0e6011f0ff47227f29c6cd38c6e231f1e91765d1b73924daa2a2fe229621579487428119b4846a20b8818fd9bc654abb9efb0deb7aaeabb146964e7a4aac78279da9822da8188c3a15066de45bc43560ec138e4c0102243584c30bcdcf262ee28386f7f67521f3b32c3191a61a8f79f54db75afdac8ee338b990ee071608d030238d0fb67f9902db33c6579deaa962bc4a690903737aa8d762c5f0b3120e488909a3783787b3db398d939de5e09ed2054f66716431b4469d097ff9d55cee1066d2024680141a77a241279cbef52deaaecbee31c4f4e50d9c0010d0869a046031fe89209b65996af38a6ab3682115375e7bc857af8d5d3acd9f2ef4cb6695dda751ba84ca01b811800d203e8f86fee3add9148f4cc62783c178769d61a0e50095b7f2e9968baa67639b9ea2367d3fe40f913e6c7023f86fc6cf123a38facffcf2bd7a9caea9df1f89ac5cccdf2a15dd7ed99d5b45d916752ddad31ed29ba6a3613dd3ae7e936b3a3a179bacd64f7319b288743a27bb37cc872e266f35633cb73ddba893cab9cc3b56bd747bc76d769aedab11ccf98b61ccdc5a1de79c5cb762cc70343d7dd57e417da998969cec8365dd31cb655dd79db85c8bd6a55ddc39e1a91ad6e7b72a8ebb68aa68d765db75fb9b71cd5762a879be36e6c7acc53e36e68aaea1eaa9ab672edba8dc0ced3f81cbaf200b6dc6d1bd3b9ba95b33e5ae41baa723994dd776f7dab5a8ebbad5a3ddab1dc477b44b22c1a9af21e796a4995d56abbd53a389f6bf95d0ac7ee15efade56e2b4febae1d2f0e4a3e0e5db571a7ad6fc1e11eaefa0ed51b45b2fcc8d963d04e450acd36cbd182472352184c6a75c70555bdd11455790f22a0094dd115aaaab51adcaaeee8ba5b2457d5dd1110f22aefbb381764f5d47a13ec2baf69712ea8eab1f3ffbaaf704379b06f960ff59c794d51bd75e496a833cbd1b29d8a3ccb449e87297b0ca2ebe6c4956dab5ace0c4de3569ec67138b316c993fab85b7d97b2c7bea6720ea7dbbeb2ed9dd4682de771783aee170cbabdb1c9c5a9f508aae100c6bdcdc905833f20caf6ff15deeb80b4cf3f215785d9ed4d4e8077e1954750674d761fd55d0c06c5f09bdb9be836924d3b96e365dee62299b7aa4ed9dd1ff9047c171f2d37ffb8ed1febf8c739feb100ff98ed1faffd631c0d3eb859e471f3221ecbf1087a138f1a3c50fef1bce1d1f066b14d0a81772c3d104551208aa26d160987ee3be79d18ac1d582ae76d98aada79d4a4a3d8ea9a02ed8cb13ca37bce4e83645e26aabb6714d5b98e02755b4def52f6987b9bea61df1aadd8f59aaa6ab43c7e663657467c3b22ed38d761f6fbcdd13944e74867ee59649bdc731ccd49d2bfda751b93eb11b5f79213480e52ce8a38a9e2c88973c6710027d1a9eacdf2b5ebb3f3cc44ae8da93e8f69b1ab9b4d87bc779db3307774b3c81649cc5b4c1522e1e0dc80e3e08da037c53765ff6fa23b27c1cef3abb369abc1d0af36d300040c2862808d37b72ad4ebde6eaab8296bb3aa8d016d8ab4f1c0a6111b396ce4d8dc586381d71a465d17378b3c9e70dc2dcdc1366f9f59ac6bbc62f1cc6270d9e4ad3ef236b36716d36b9a5c8179b3c86346f78aa78fbdc7ad515b73d5e431577eb2bbb7a9aaeae1302ecda83482d2a85cef95a62e8d85343d3476d0fc4033e30ca9335fce24cffccca0fa1549cc6bdac37658eee9baf779c3e4ec3e821e7352ab6367de1d89d7766411244fe673b328903cb9f2c826d8591cb65af8fb9d611a59970a8dbaa7e899c5ccbcad12799bf7be4b7b4f8dec3eb69d1b55bd8b6d163bcface3cc3313799be6ddae9ad5c8ba62df2c31ebbce2e9a39c19a3990b65229541e455c64f99e2ff9b6226baea2c977fe799c54c22cf445517b730af3c6b55ff3a9c799efd54553d3cc97822b3c58bcc103263ff295270608a14d9dcaa704d5b628ac78b39ecdc2cf278e6a49007e582665f795c30dbc8e5720fd6a545369b678c65b33c03ddc58e3ce6b623058801e32c76bd76e6b0d3048341f695cfac7351af7927b5ba51b83cdd66aa756bda891ceccbcc2a328b1667b6d327cbdba1be11d691c5b96c8a6df698f5796622578f99450b14d599ddc7aecfcce4b63bc1be887c1f49fb997b9a358a6a961393c3e4b6fbca467517c336ab733feab63cce1e89ea96e36ee8ca63ab42bdf268b95b090d5efe0aff7f7daf2f27589863621dddc1607045f2a8a2dcb88fc976b7ba6eab1bddc7e4dcca893b2d99c759b862d745e0461a495724fafbcd792902bdc4f8fff7a2e13c59fdffaf6f5d1e1d351eb04b9e0776b1024437bae3b6aaa639f0b61bba5b8dca7569c0251477e3b2c5a8b9acbd39145bf99abb2e6e341da648b92da4d89e8a9dbdd7962b5be0fedf64793e37cbd154550fd5b67869e1c31e39bb8f88ad735aa0fca3bb6d53a310a9e5d4e265eebd72024efdcba99925b79d5972e7281bee1ec99d830022077b2f02e8dad4b83fbc170163ff6f6e782f021a64b993e58b9964f7dd4633579eb79167299205c38df7c2f2e85f44dd9a8af1b56bee669e9da3781b0b112c5e8cfedfdcad6691c3e1c6cbec4657a410d99199b799cddb474e9122450ab31b77abaa698e2b765750588164258c15b52aacde5455a089447771d8336f598eb7533427b5f1dc72ebdb993b8a3413d5c515b9ee30bbe1de604956afa9f02bef3a6d4c377b84aba2a58a1c955a54de50514365edbfe53c2ef7cda6aaaa87e7eec8ac6a23cb5774dd46231f6eb6e56ed9ece99a87fbd88f469db793ed26eade22f9b6d3fd87c38dcd2d0ee8c36477ab5574a7aaf03c75e6ed11b3f79a32eb77317714edba8d2b67d33ba171f70e146e1f7270315ec8c9b1bbb5d3c68db23cafa95077bde3b2996cd97de4ec318fb811e345ef23369b63bc9093cbe8dea858bb7164619ab9edf8dd9ae6550f75ab512237c1dacea6c48cee15c91e73db37aaf2af7cdcdbce98dbb2d9b530fffa899ccd731bb9dc99cdbcf2b4786e36b77ccdc434837dddc8e6c97b4691ecb98d7a3dcfcdf2562e9b6de76a5d5dcab63c6faf7c78ae1c2f13d3132ccc6cae8ce537bece5dec9bc889dcd8d3551787db38d46cbb53b6cd7dd7ad759add775b4dd5a1585bac4bd5dc8769db53550596f5add7dd377bdcec57ce3aaf7be3b55b98ebd6f478d46dd96c7baae6d36caecc88eacdae7c4d895cac45f2ccebf2f85936f791b48bad69de75ac56b3eec1e1886bca964dbd594e5c8dbb4dd5e6dedcb299597d0c4bcb66d76bd93cdb2d97cd21678f601dc56afcca3d9bbaad8eb7b9451ec1f29aa6eaf1a85555f7acea96cf65338d4d5591c4beebf4f1a877f1b7f24037775bdfbaaa6a34ce6e202b77db468eb6b643cdb6796a7caeebcd0e57363ed7d1bdddb651bb0df751aeec71be570628c5ae8bdc6da37cf84b1e39dbae3ba8d9764d7fc5aed77ebfb962d7451e1be5687d981e79bbbb2e1edb75dfa9f576dde930251291bdb3c41da75b9dc689ec66f791e0cad7e13ef6bcd6f8fbcdede1cad7ce9a9ddd29cb6ae12d7ce33e12b48ed6d936ab6165435e471ebd972362fa568fb9ce11f5ff55bdfbc739f23b92f32fffaf79111bfeedde6b1dfb179155bd7bd67148604e898f7bc9afff37d7ddf55673abf316268b2da6d0a1813c56ff664ffb9ae67facf6ff0d705ab04d8bb09be545b4aacdf89a1a83c13535a26b6a671cd2a1a93eae3cba4e55e0303df2617ae473ed96db286feb7bdf68b7dc56857ab7dc8d87dd90eb6859aeeaceeebb74e501c7e66963dbb931d8ea60cfd3c6cef294ddedcab6f2c84bd1751f8fc076cbb15b4557bdb6e53a523db24839744512775cdd9aa22a5fcb538b43d73dec3b8dd55b45ab5bd3ce553474b7c73d1c028f46766dddc737bced7634b26b3bcd87195bd970f768c1e2ceaccc38a4fbfd5cdc19877441546dab42244f4b8f401f6f667ad499dd762cc70b1289dccc765db7598c48e4b95bfaef3b35dbbef2e19093e3cdf194dd7046a4315dd3b63348bab3306d7547598d6737d4c2ccf21beb8adc6a5ac46b379188ae7cb87baaaaa9316c45b29a450233120daefcfc4c5eac1011e83e92fe268cf6ffbdc733fa4e5b609e6efbfde6f216ee9e932d9b66913a780930c2c0d972550eedcc2d573b67f791dcd3bb14cd3ab31b5d53bd5bad2287aa1e66dee6ff12ff577fb0e0bf1dea75a3acc63b2283e8ba7b90a3c81e6c77170b06836247e330ef681ce605835f96f9fffe14f0d81759d3dc931a4fd53d80162dc8d29eecbf5f6ff3b6d9ee9e799bc34e76d7e955b79d392954b9db1df4ffc2f7f230e21f9f59e8759a45ea366f8b75a48a342287c1ba35ad537b70b71a3d225154b7eb6ed734b8eff456bb0ea22b170693c356a329baea6150156a76af2af26e4d83edeebf604fee1c667ad472d9dcc7649b93db2eabc8789a4dd56070b7da1ca6aa107954d30144935b77ab872b1fc665b36e4dd9b6e73306b1459e194dd52d44f7ee6d9ab7757ad716db146ff78ee4c96d97778b23b77dd7a568cb391b6c91c762d76bedbad935b7a259d970f7e86aec46f55eb31b7255f8fb0d5376afbbce6ec8d5b3649baaba65795bb1eb35dd6a54b7bb2d6fce474ffb5e370e76a3eb96e3ec0602b7eb585d44dbc395bbd90df7701fe538714d836de7474e5cd93871656b3b872bb6a98f31162c5ae0e9b8bc8daefaf70b1e7bef9b455160daaac8b656082b6415421422142244c80821ff6fe3bf818816ff0dccae07ff1f7caf54c777d66477077e6f0b99e21f176464e6984926b6f25e24b85176f7629bffdf44ddfbdec460304f1bcd548d6c875a55f5d038a47bfbfd7e3fe3306f1bf9b045f2ba354dea63b1eb62b1eb35e3900e4d83754ceabe9ee88aa84613d31e5df736b5bffcbfd981669baebc8887ecbab8e7f0f6eab543a00fa0ed9b2d9267741bd396e5390ccd3a6dd31cc6eebbbd26b596f15e681e3e30cc5391bddd752892adcb3d25f5ffec4e85080889081bfc9b2b3f2233badb216fc37218abb525dde44d55d543be06b79d6ecf5c6c533bdda25adb781da71b68bcb3d4a9e6cdde91fdc8db9e7d9c4762069e1ac0d62d77ee96c8bffade37829e826f827066525591c4ae8b41104412ed62cb79ee1a4f67541781ff6fbe17112cffab9623e23604d610376f9e60390c653b378b6cf59d2e22d119a7aa6ab433eb2d5c91fb8e1b57bd63887088857fd3987566f9306db591b748bd6aa131f794c877714ec824214b84a808a2290895202ede1472f6b8ee3b76b7ab5ed97dc7ebb2aa91ab6ecb26ba8f47ceee62db919cdd75ab46c1789b51bdd935cd5f1969a29bdd4634a976244fef367bece950ab47b5ff8ff15e403e0111f3ff269830ef95e5c2afdca67c050241768d074477b1a76bda530dd7f7beb1f288d3addc0e35d537dae6e4d0e6fabaedf4dcee71e856537d23ed2d892651bdfbca8fc37dccdb2b8f76dd72403a28ffa6dd90ab5955d316dd7b3844f6159977718ece06ab7f93dd44225238d4c79e893cdb0db59a75ee475d64379cb9a619ccdc66fa9537b2f774b31adecb47221f792658dfec316fb7a95967eeafec23e8a3c1ffd7ad698be46c26f29cd478b9a76d58d778e866d31e97de2492bd570f31df23469fe341ca4477bbd9a32a3ce7786ce1623c62982b2ff6144c55f5575ef1f81c296431b769dec335ed7354bea37363dbc8f256a76d8aa6fa88b27372acde44777a9e794e2ed1bfc972a25c93ffba35dd7643ae02e5e8cc647b34eebc59a15cfe7fb3a3988b4bf45babc38d66de8a6d16edffc7de2b6e8b6967cc9cb77bc5e339aef8e6ffaf78afb8b137d115c9897bb8eeb2f7da412acd613bb6b09cb8ceed101a91ebce27cb5956edccbb385796c7cfcccccc5455a3fd7e6668b9eb3c57666606f655661cd295e5f133e390aeed1b35eb66285b1e3f7b0bf356e4cdc2fff714cdbccd756b7a663113ecb88743ad5b5dfc22ea2de7c6c5cdcecd425ba9b62fff66dec522de0abc5d6ccdcd6ebca1cedb2b4fae401689def196b8d58ed4c32decc654ab683a08707b2f1d36ccdea699b7195db55d07e62895a3ceff9bdb88ec9b3d7318926dcffc3bd18d9e59ac2eefe28acc2ccfed961340150002db1fb6edc51684adc1daa43737aa8d7cd5ed4672a3ee7dabb9a7e919ccd3c693bb994955d549754daa75dd78e2e5ba155d816618bad7bab4e730adf3c691074790ffcff15e38bc6e84bab1e5ff5fbcd78d20377a6a76d4c6a8a1a59dfa7fdf7ba5659a92e6c22bad015a1eb4241ad8ffb7bdd7d92617ef7516e7df04fb22a303fb62419773ce62d9ecfc684c734f8d69d8ee291ecb91ea306f7fe50cd66e36efe1ba8b5fd9ec672dbc80b5bc80aa8066deec67163337da864697891c5d9146231f6655e56d9e9aa11abcc607334a6652ccd868c8d2f15e34eed000e24563c6ffd778af325a5e6575cae650bc5799d88c4d33a0cc30ff7fedbd7ea37e5c7eeff5f3f1ebfa7f13ef25e3930c2c325c748a4125868bff9ff15e01c40aa04d00550270f1bdef3535b2bbdd68e65dd5c7ddf6be37717dcb3f31f36c43a3e3c35d87a6ac30ebdc3b67873a838199660e0333cdaf8eecebee2b47fbca612cf2af1fbf4c76175b1649ccebbedbf9ecc3b4e579bb6e4d8bed36f23e0c3bc1862809030303fb5ab76a7ea1bb5d911c4d55815fa89afac83f246941440cf7dd97714877e6fceb3af7dc75368fbbed59d56b4a5c7946b26d1fb2bbdd46cdea6370e546de76e4f0cc7be5684e0e57ceeee351175b5dc4cb4974ef75987771ce3c83e716e6550ffb66f37a4cb699484cd1a4369a44def654cdebbe4bebd0cd227bde76bacd3cd134d8f72606cf34a39be549a490b767127976e6b07ee4c59c64758a6e634eaefa6d45fefd0218c9e34eecea12fcd1459612d3acae5d6066ddca59bcdcae1b4f2e9b5d88ec99af79d5ec59579c0a65889e2bb0af604fcde4b60b8ac07efe719f060c7c24578df27fccc03fe6b3c03fdee3e692578fdb80253ee68dabffdfb02dcf4223921d669d3b9608babab23aef3b2e64db28773b4bdb293b97d155ff7e4223924553a4a69a78b64863b0ed5a3df71d8a8d378512a9ce9a2c6f35bbdb3492290bf851a1f74dbaf4c955eb24cb8ddb98798b6aae227b6a6ae1aa8793dcfce3042c24d16d64a8db56f7df0fdd2bdedb46b9dbd0c73f46e01febb96d6c8d4d71abf024ec7fa37ccd7b4dd535bdfbd28dd8ec312785970d96e08bb4e9807f9c07cf3fbef38fedfce33aff98ce3f9ef38fe5fce3a8208cf38fe3fc6338ffdf7bf3f745052669d7ebfa6cfddff24162f4e84ed956060b734c4c888aed946d7f68409b799e596d75303d4db9f4a8f369eebb6c62376dd85c07be02ca72bcde355c5e4adc2c1c5e7323c68b2e87eab3182f76d767a83efbc76ad2a03963068247ff15cce6e481e04b86c04ec8fff71382b23febd60666b828a84024c8604c67cd610ab8ff7f01e52bac78e85675ab6ffce3325db73aedff376032633688b11026022e000ccc3ffef28fbd74f97f1d668b3caee9b9f78d13796c917b13c3f2dec4e0dec424abb679482e5bb01603c0beec78b0a72658cf49c08239ac7f9d48f295dc76c1a430183483bd6fb66e4d7ba168d0c82c72d8abd241b3fac8852287b528d6aef1b8622042f5ff7ce5928068cdffb77c352b76bd6644ae4123461451e6ed214fa6ef509c43c77cc8cbd02161bb6eb9b41b3e431b1c4864ae4836f336c5eba990ab42d401eee6c05a2158ffc04262d44267a19c7237428a902ca1b741af7c83d49861c5ae8b72d934ea55abc47c0e82214895a03e82c4085a13f4f5e636f2e17177b403cf73351b28d4806a668db269569bc536c54b63c30d02917afc6586854515b7018af3398cbbddc8bcce3c75abd1dfefcc44de816979173bdf78a62ee2c1b5f138f2303bcbea61ee1ad55c453b2f1a8bfda8d7ae33efaa6ecf6dd6993b871dc3e6549dcd76f7629b168729bb8dbb78dc756b9a1ab31e729e41d4be026bacdc473677cab628da21a76e751aca6eb83348de5ba8aedce443bcbd0e514b7b43b30b065575e3fd7ebfdfb1071912242c8bf1babeefd2ba95f39e3bb0b76baa5916efb8b7dd90d38ef3b5649b0ef5510fbb9890dfd5ad28cbf1d0ddae1a5db78e8cb6dc0dd87237ddeab4e419badb549816390bd7df1af5ff1fe07db77aff66db6ea8d9b9628ba678e8aa85417477a4d95ab1eb6250b3fa6886ea5d04721cbf5f5045f52eea20af0b0e57e03f26e01f67f9c758fef1957f6ce51f57f9c754fef1947f2ce51f47f9c750fef1937f3cc03f76f28f9bfc6326ff78c93f56f28f93fc6324fff8c83f4e62bc7f7cf78f91ffb8fdc7fd1fb3ffd8c83f3efe63fe8fd77f6cfcc7ea3fb6fbc745705abcf83cff23d511ff2be1ad0338e7f606842dee6dad5df99194e5c5b38d875b500d07504e4ead2d981607f401c72348076c3bf31f62fa9fa44e026f12b9b23c852fab33e5bfd835aa373f1af92eb88d72e35f1e672e2a743310911e817bb89abb38679e449edfe6f0f95173dab71b725578e5a3ccf9c9cd6120e7807f33290cdb9b988bc334eccc7b138168aae1f6be6176def663da1e8da97a34eaf33c1a91c29c6c775d1897cbe6316d4fded5e20c301579464e9155e4af4c231fd336d86e7506d8316dbf86aa1e0669e464bbd5152b7258db91ec799ed93ca6ad3087811dd336f3f52b8b255556aba97145b262edcad953d546b6af3c5d577e4cdbac75de9b184cfb7976ce471cd3964def46e4dd228fc653d56f27706f6270ab5d0bf7bec1b689c1b4bd6ffc3f8a7f7ceba8c03fba72a11b5b6ef8b841bac96bda7672166d579ed3daac6993a34d053685d8a82bce53ecc8db9e666df258e36acd99356bffa6c60bab43776e35309b9b45d6a5c5bab4b8c556beaa59a5268e1aba7fdee6134cf805a6bfd2ac4a43264d5a1a086816408386a52d1f26856766b70f8d893391ce2c3973fea3abb6d3be332ecc6cfa6f3bd2689a71f3959955064e99b7583e3276c8f420f363188d69f2e619b6a6c9363d4f60364fdef6547722cfc176f7e0b1eb1c4caac1dccff6b86788ad7c0de32b47fb574ec784f9c48812f32569f6b39f28901357b660105db9104d8362bebefbc4fcfbc25cfa30793ade760b534c0a7d61d6de44f79af222394ce66705702a80ca9bedee3db9ed523427fb16ae059c0f2c800610ddc7636a2787b7ddf0b61b8aa240bced06060e6f13d754c7175847e470c8bf246a77328d2da739def7c5c617afff7f2fa4bc88f102b77261c6db6e5ebedecc6b17586f764924c0fbba1ceb589d7689f1dfa5c13f974b6fa271a9f31ac2f0ff1fa7fd9b76432dccc933f715dd79e98d6cf6216736935debc86652d5a8ce6b9aeff2768b34f6339b3d838525db74451a8d7cf815569c1b763674e56746cede687baa83cfb1b5dc8de56a78fb06bf287c59e2b29468917c05b26369000b132c61a7d1a88dbdf55d497465ce15baff1355796bc5022b96ac286005fdd3d4ad4edb6c1a975c75c6db6dca5aa902c93cb7aa72352cb8f23458ecba5825c49b7d05b6eb96a3c2eacdba5498396f7d54d4acbd4ddb2d47a5a8a9c4a022e14d344fb7994876dff19eeece72bcdc83c389a1ac2e265555b7c06cc2b5c5ada93a4fb799690f0ea7553ee42d678f59e57dd7addc980e39397165437751efa4aaf3749bb9553decb9d543ce33485ed34c2472b18dce486a3b3e363646f6c58b68d94c6a63525591c6b4278599b79a08d79ac3d4a8d724da856daaf15ace8579af75a9985e67ec9567f3458b172f60f035e371b62e7723d24736cf73d548239cc88d5d8cdd771c5d75cb5761ee31c79e5b7335a98f9aa37ab378e751b7b57cedec2eb6bcab7b856b43a3cb291aa7cf463cee42b791197af865ac72964f49a25ef92517af23d73f27ae6c68c1e0a9d1727ad42c129816ebb8aa730f6b595eecc462d88811994db7669140363860d2c872221b1c30b8eaa14954776fd3ace6aeed869c3d5b9d69d0387358cfc8aebb50ed61c2a358d749d588ec5de730d4cca63e7b703855ef8eaa1c8fa7783d6fbcb64dd9cdea3417875a2ef7beeb345c6777daefd4dec27747f76fbc3345dc5978145df9d9ff47f84fdf8b8305a403ff2f620e096c2d68d9b44df48eb6144975abbca7f0d19e2d8921d298f1f81aba3b32d859fdff3fea797cbdc99f305eb00876b663c76c1e568cd9b7b06bb64e6caf695b3637d2883ef29c6cdbcd1e873cefff4d96eed9af37a2e8df043b597ea2ac1ef614cd71bb4ec3a9c11969718425d6a643ee3bc6f93737724df97aec7b4d81be238cff8f7b1f47559eb67ce57cb8d0c76324d976b37ddfa9bb1bb7cac3d096afc52152ae5d59997c5df9f474a502b7ee3892cafd7e73bb4e1f8d89dedcaa91849182fa473da2aab0eb64a7c8eece6747678265155f6ff9d7ed586d2c0ed77d66d6e9e35dcab23ab8f261ee1a6df366bbd647ce1e9366e791cd73ab689a0e39f374db5651b676f7b3efdfaf9f4975a7755b4dd175e7af8c6e644eeeb0357dcbe6aa87c82158cf449edb3ee424bead5b479e6e3b83e07135275555ab9a98ee2369df48ceeb32309bedba7baa1e8de9aed3c314d54763daf1c0c456be7ea16b4fd3f65dda59e470c7a1bb23359c2a545356b3fc68dc732890bbed3a0dc7dd765ccbdde6a0fc75f237c8ff17df0b84dcdf6df698b7d1956dd7693833b332b7ce22b9b05897ee359844f566dbae5533b37d2495cb61652c5af0e0edca96c362208f7a17f79154eea8f7da3e92caed3a0de743a93cca8666b2bb25a2bbae4ecf9d6652a8cfb6afa9aed37965f71d8bec2babb7ca39ca8b6dce6bcde6cadadd837bb3adf0f70ba27bcbedcdce9df576dd461fc99d83e537ec383febc99da3cddb6ebdb3f5634777d73afa1cdb0e35bbdbde53cdd74c64cb43cedf8fdd671036d8eeba7c9e794dd75ddcacde603062b408604864bf32baebd86dccbbd8733e92b66bcaa65a2cb9ed32d89a93ea57ca1e8d1ceceb348b812c1bee1e6746772f0e913d13d3368cada7e79a8ab53bc8d71cd65175a77a85cb26bad5541359ce967b8b54d58daab501e36e64bd93eb997d4084986d687440d08058f82142f28f0a7e101a222487a1690e22c4fcc7c21f7b67b29ef6fedfc80b49029f1e819a45024dcd2275b0e56a37d1dd5b1d9654594eccff58b740d99daac77da3cddb6e5b3da6ec1c9f438b5dafd9b1dac8ee56fb381ad9b575ebe8aa0a5cd958b4e0c1e7d024bbeff8b0a7691d4ddb2847db2847c3db6eec06b2b59daf1d8d433a23c6b4b66b1d289b6e755a8b7c3b1ad9b5347473b476cba169dade37d23aaaf7dad0489bd6d13b57e5d49e866e54ce38a46bbbd691c7852b1baaf75a0fb4add556ae6e4dd9ba3a60db531d3db973a07b6593db5d17e1d4563c9e0687c7dd78b01baea329cbeebbb7a3714887eabdb687e91dbbe5da751bebb61cbaf233b40f009f387c7236febfe56a47f7abc959280e5b6deca9f1ff1797e53b1b44f56689e911681a91ebce4382e4ddf634d9759bb62a32b7bdcd2bab76e655f76d34793a62b37b6d44988a62c488bca67984719837c238cccb615fb9abc23a74d5624916350ef356241b4cb268924dcbc6615eb05df79d5a709b810d778f1cf6651ce605d11dec6a2b322ec9a6198774e911681cd29de911a8aafacc6143cedfaf67332c450e4b917f756bbaa6ba1572930d0e080ce6bc3b322d9bbccdbf1439b3baf73ddc6b0e6b57146b4adce8b09fc354dde8dec4206f83289b8f13ef44d936d138cc3b8d43badf79e614d96c43a3cbc160d0ec9122776026a1d32370ae23896c70c06cf2b6a365adc48e98f7ffc5f7ad39d059b3cddbc17f4ce4ff7b8f87fc6321ff38c83f06f28f7fd0fd631fffb88717e6f18fe7e2fc63b9ffef807c1f8e263f5c77ef3b88aedb6ea8858fc5dcc01166f6235f53cda6bdfaa7f5ff49be42507dfc163c0b29aaa409c75d52bf59544d8bc39beaffefdea726e43f88eea40b734c6caf6971a88d6262c71de83692671c77dbedd2dd373a776ff868a130737ad4f93c0ba2e56e26597d6766b3e56b07e6751b79dbef3777e6e2ac04d011f00950089460a38f8d2a3e1bdc46881aa66a80f1d530cf76f76031673bddfe7e689a7666221f6e940fbf32d24896c5c0da2db7be9d99c8d3afdcf39a6eb62375316f0fd36072d56dc1aed5610eee95bb05879c6790a4306b5dcc5d178f6cec3ea25d3562dc06668efebf9b95b1c3353d1a756bf6bc86a9c2b4efce8bc3cc22f98f6cf68db2fa78d419e5ec31a748a1f174de67d9ec769c17f3b98f0457bed1a45045128f48dedeede1ba914676cffa1fc3b1c8fb48da8fc836ebffba7f21ff0ff65fe57d33ca74d6dcc5a11ed6ad69dd9ace589ba1e17f97feb79177e0af0ede76f3fd623cde26fa7e32f2cc90d1e4cd0eb6596efccac955cb00fa625cfa17e616c5ea8b212606dd9b311a70b700f27c0079be00341ebb51be866560006ffa60446279666166f6828117575ee47041cb459c37d1807cbd99c79415d36c2d78b48860e17d2c62f9581062616491c1470689cc8a8fac4856668a99eb56c5f2800079539181641559eeebed3ccfb094e5690f7bcbe64976e6a41a67eab0936d2ccf37e6634cc60a09561cb0428829b6f21ce6334b8841f28919129b2216e71323111629ec49185c180e9f0a593e1588547451619682540a08522849f1e54bd1018c11981330b42f55ff39c526a66aee6d6adc6dff89ed968c2cffde56b081c9651559ae8eab5f6fe7576ed94de427b2aa93c2a1994fb9338785f5ae8f62a6d8ca796431f3049353d554d52bba7ee5b4a76c790b7f67db964d5ec4cb605fb98ba52cefe9d9cfb0f43cf3cf3c832759163b339113539df3749bd9dbdca62bd204cb61615f44ae22bb38b3d9f1b80ecee77ce4e9361edc6d656337cabe11df5ae4db4e598eb76f703ee7c6ddd03d07c84cb3dcacac5d537edcc674aeab1a98a7dbf66689bc0de2edd5c859a20938d3c4d897206582b13d359610c3ee56ab25ea7c2534fcbfd93b57738be4612d52d8359e8f8403ff4f0209897d4cb62db28ed5374c58c64b663b22ce9b422ae6ba8f7096e81bb1362229cc2d70844f8420130cddad082affa64fc49830c352552431e7e1ed1d377e6554ce97a9f832dc87a8f56fa2c28d860d597e03dd78ba38876e74a36b3aec3b8e0ddd7167e86ed7b40dddc5ae5539b6d5c71dd76eb9b6731d6d47a6a11b8fa3ab9a2fc4d7992f840f049f7ff3344355be3657467ceb01a2098818ff0fe27d20bcfeecc3a357f507356fa6c5cc79ebfb70de65a0efc3d8bf799e1f56f83cf03153941bf316ea56dde8ef37b7374b0ce2ed75e5a959d970f7f07998eb40ebffcdb0dc759e9aafc31b5f871e1dae8f03271f07413e0e6e4cb09545ee627ba7e6ede32b8f91ed7d976a3ccec3c7e1c40659be0d7b7c1bd20d2ede64397be3d4a0e7ffe7dea781884f83075f06495ffecd20ba874874b32b8b149e614975b3db185c59a4309875188bc4e3ea16e62312c5ca22cf7c19b42fc3081f060bfecd53b7ea9d4e6abc5cb7b6ba238ba0400c787c18a0bc79b69cb367eee905092e60b920c302280b7e7c16aef82c20f15948514192af02920a267c144221d9f62befbb54d599b7f908b6bbaa895f7a98c3ba2e66553df556391733777a4c87a6396c770eebbb4e278f9b3d86d965cd0a7318d899d78eee5617dbe056853a9beddae17d14f25080f2e6dcdb5b5c4e0a735298d9dd9159f3f051b8e0f369d2f03e5f219fcff8ff26ca8bed3692508d6dd134f30fc9932664c830533b3de43c836839369fefc7fff73cdd6626575523d1f42e45d7744ddbbe91616816b1576ec7d3f26fafa99a8dbc6df95936799b7b9a6616c9d33b5ddcc276d725b5b1efe1ba913cc9964d399e96b3ce47645ef791ff56bc6447f76691c3ddd7f4dcc4550fc338bb8fa429d81422dee2d4806437e0da5c8e539b03aac5e1c86a67794e8e475b36d77de4d944555edc46ed96cf15642f64b0205ba1aac8e38add6ab6ed42645f511cee36d9a6ac3eae30f2a1294416dbb46ec58a5f3fb66df1cc7bcb659388e4779a98d73413b9dd6689195dc38472aad9cfb3233babcf1ed68944be51cd6ee3d989e43ff2799e5949ce66bad569398ccd616665c6b42877d46dbb4ed3c8396724396f353d1af990afe779aa6512d9247234d7b5bd357b9bae48ce6e20ba55771ada0ef54e63ebfbc8deec0d54e56b7aa7c9d5ad69db851a5df7314f2d4d8d2d2ed9a6688a3492d6f538b2e3ec865c4767ed865cc7de2cb1d76995a800cef335b0f1ff3a63ee6b00a12c43f13e068cd2d27c0cb698c2943df33180932b5df8ba36fdbe4bc57c5d6afe4db4ff2ff967f24dfe33bcafcbedffcd7ebfae87bbc7dafbb88270e53789c454a8aa9cdd2a2fe21977b135f256f7b6af3796f69587afcce22b7fa27c780c4ef3612fdfa5f4ff3cde779bf82e0bdf6bf23d1edf6f314f34abeadea836869dc561abcf4e24bbea1c3697cdb61b9143361d6655d5766f67460343fb7acb6226d8b9bb3efbfd4e7d4c0a73df684f8b735fd9447256b79cb39960c6fc95cf1fcf2d5ff37672d5b74edd62742bef56b6e5c8961a5b396c59304f21b207d1ad4f166429e0ead27e9e2b98d8bad976d578489e1c6a7477246f339227cd6da65f44b6bca2752b57756ed5f486694cae1c45ee7ecce8cedb6846d72d572b53ad38645f6fb570d4da40ab11ad3366b0e53c2ed84d5d6c533cadaa3ab8efd28d06bb0e9a1ddd686f26c41f2d44762f022298f5c82472ce1e6789e16eb38a9fc696dd66a15b16ab7fb3efbb54cd2d5f770e598b4c59b23cc422156b4dace29bbd4dcdb327b7dd9683f50956175851609db020bc52e0d5f96aec025b6fa23b2f259e605f1d4d83c96df7fbf5e4cef1fbcd9d190566b383917dbd9d592cd9a67999040913acd875dbbf54bdea6dfcca3ab7696c39ddc2dca258fbe628bbfb9799dc762af289b2ed1c6772db65adcf5d64f50e5c283a9d9535d40cea655f119b4778d9664acb28734fca068670d7968ebb58b8fe5c380b6a384d038f1f920942e985499b4ff381d28d206fd56d05098921180bf4647a10c1a74815fa220b9c25a52c653753b90abb4283e05e2f87ee982fba07258057496452852b248f9bde5c9742cfa481578f2a93a81245a60b7a6655f48541875489c4520b8ce6e5761d4bc8bd9951103e0b9b4a9f0492959b424cceade5075229378470e99888ca1f7acefed08930180a193817801568b8d20708d71432c69f9994dce2213ccc67ced5437143e133f8f972b75ce9704ff432e04a6f60bdb50d0fca35305e5d17a08de10799349430f8dcfb8892182eb916fa8ae8da509e8c9adc0a02387bb4296afe7c65e3baf5b8f31e206428d180e7cd95ae943a862cde800b3860240114efa614e1924282bc3b0241ba193a45b8e55d18de70409b3f41c74c294104432e223255b0ddd7bd665d8dcb0801164c8695865242998c3d8cd19520baaa604873537a0a24ef94198c2429096df9725dd9aa00dbca0cfec69d8bbbc8003cf7876e282d8469f03e30a5dda01787471d7cbda51010fc025590df67a8769388992a8b732c782d42f460396553be8f8350f791d1d1a78a93e21c87bc2c4eb195050ce76011145e6109ec54702d4805567e4a6078f11c25e829e923e1c23021a577a7ad712dc060f0a5ba665d1b4756fd0620679e78a960628a083e8810062e6127ce15a476044b2104e119fda9742dc09a753321cb1e9104a3fe8e04396e9c4e767749201af8cd29bcd885a63b6499e0555d214a374bf8941d3c84e121330ac0663048ea8a61cac63ddbd062427042dd0a02f8c196e21edc3b266a17562726df6580347c632d797d44f6dff199f2b05699c25f1ed8f2694adc9477e0eefe8aa827f890ac3e5f2a89a4ac4002c35bc0f3058f49cddc07a89cc2b0c4d878326a6fb892ad1cb8142721d621e5014c25142cece7b7e78b3f2038918d35586d0234372c0e211c659d543e2a0bddb30672a5012da07fc1e4c85d5355e96692ebf2582ea0aba40957f9b7d26ea5146fae221d58feed5190af8443f89be6c0c16ee856dc1225b4945ae0fcbd90628097a0ce83cfc2460b46036b51c975c8cb8df103cbed81c549a94748a10ba882235da172fc6e2b0352dcafaf1a18ce2b225e6b8df92ba3fee96c68f46e369efc243461de83ad27d7850d085e0107e6674822ea2558d2029379e1f4427208296f50a9721b58f8f05910b1dd1f48e4e00be038dd1d423ce1fec5d56de3baa09c40023365180d4fbad8424430d8a5bc1e140130fc9b56b6bab82c404129e1d697267e2c70a439b7b003248d7e02455eca4917fe0e378dfa1e16316f6656056b3851e1ae619254961883eaef885cae020ad47a2686227853183add2301482a9b78357aba5043f089afba0ba296a38f23a7f85b168dc04728b2f0874228f0006e1bca1a6316ba9878fadd39176a7131a9e1f5b6c8807701384bf098903d65da123e5fcac125cca2ce86d734e7d5e5a423d0bd93e9dc3e82f6dc178e1e3c1f55112e01a58e4ff3e9caaf9870f61b0420bb0a0873dc376f1cbcaa15661ecc9bb8776b787cd20ecb5f5f9b3f9326d1bdf382515e70e8826f75f703df0e6b6e059896743588e0e456606115035f0bb8d286191e8c47d6e7a7b012e0b3c80017c3fd282da91d793ac03365291376bec11d15d8d511b147d52212be0137f66a408df8212041f70b098bdbc0417bd7f37f8e2fce0513e996c641493ec570c14f91b507cf12f4a5d4a307821bc294a99e19b731f7347189eb018a001e342a50ef48cbe8763a0e5fc7024fb702200d4a3947b65eed64e89af0fa7143f98eefe128e9368a73010e9390e99f18cddc3c3d71df240b58998706828b6602a84f53c09b6f3441c9079b00ba3e861029ada03a71d750928323d409e2524a12e0ea0000aceb684a5baf0792705b4c28731b18740613b9a256f6803b551ae1742aa318a2f4775c28aef440d2d5a0c9d27312222ea43f4ab01a2a75df4101f3f270e2e046e2f2b74d835a17001774f82741c6036972ebc69900cd7da065d235b601de05f28cdc501dd8fe436a0086f0000bfe214509d6e4630d5eb37301179b5247aea2490bf43208028181b332707dd13104775923eb81b1b0e4668855a8848b43fb086736fc86449afe0605284abb58f829316077d9704df90793325dcd16e376c043a574206ad5253501052ea005a99f50e6cfa39015e65e39cd4a281d5a5cb8bb4fa55b952c78ce4a9c3243962d4f050f2b2e589be04a35766e30de124db8d7294df9e600f523e51dc262274c5c285b2e954056577e440d2f980f21132f844b74816a1edd08da09ee982db56fe4f505e7f02abe033f5a613e3322b80e941dc16d84440fc4e4011f3585f80a24ccc00cd86273cb405a52be353984ed4c48b9b75032efe878067bf244e5367955888bafa882d16cfcae9c038a708e46702e9235f38c8ac22b628c91eb9629c2fd9445cbb379824059498ff16a69f4e67eea30e1dee92ff7b702ce6399400766401c75a7a4a995a6d618f80f444e94544c4979de96a3340f69781d2568fd8f1f7aee26e3e330101db000410b7a9e9200cb38b528e13152e06ed7aa065c4456e07bb4d5aa572139c18ba2c0d44b2971fedac7cd654097e14db889f34243266e7ee0e93f82399f2613a12fcfecb840347af01e469c3e102d18f7161c047ed487f52d999df9251d28941672607844434d1f81060db84992455c3242f5c01138ac612f3630e0092734955abc12c05c77687a4d2cf44a2f4460b70047f7269da0c23baca03d051a309556f29f777441f1d1800c5c595d6ddfe4d3da5dabb3402908918def7266813765e5d42b11f4df458f939760155e9946908d47b96cbab1c284dd13c3da3b90a40afe936356a9c3109ddb674e9c8b774502fe308a03de2087c85780670357188e2498c9017f7e025632aed18991c7c18ac5eddd35c00e586af31ec87c57102709ee1d5100940974a5ba502285c23b287cba6c6b448c4306d7b3ea332c6da532f1381060722bf8d37b0348d8c29d5eb5b98b2001fa4cb61c6137b08ebd510eb0b988e48a3d0a2d36e05aa64c2e11c02ed8b784abeb47190ee55b724c979c0d2fee9b1d6c4a4d98ec2e72148b07e1a7cb5df22ad60f42d5bb52f284e5841522eea10f444a39374a9eae0d53ca199a7a236aee7c143042eedc0f07ca09b74e5d31019c17c3ac523fc3c924eca891dbe7993009f72094e791cc68b974b83272313148833b4d32f377161cf4ba9be1b7b920a8978756761f050086296991f01cd07a37cf0c082e251cc7af9067ca1fd0e0013c6450d82bd9d00a3f200cf43a4a797a063100b879544b1f24001457100be3d6b2b3e3aad870e7c75654f0096c015e8f0e42778d40bd24ba985c2e2f6d4a10937adc369684e5061627ee05556bc9c0d802658944695c1324535c3ee4c28f3d292f036862dd364a1ebca0178dca0c65487c9241246e2b06c07e519b2edd0cc5bdd78404eea307eaae21176f8f8a45fa0c40a9f9072eb0ba3bc59292021b8bcbe9961b1663c4a46464a25c138e74b88feae49e78b0a25c6401904b3785e319957e5c241240503a90e0d33585aac30f203cf26924689f4e92a79b650cc2d7b900d25504a7f60c30845bc4dcf12e90213e03bae7d25158833735f0e636ea42770538c57c92081e4a2325f2460145022b2152b827a08cc0411c4dc21ca490e97d4969b10ad6c59583e4ebfa189ec26030385c6218b0476a049d4bd7860136e3a3c345614955e9a68045d7d204784a1e1560b90fe69428a35471bb6d1a287021fc6e3c94076ef8549755ffaa899f4f12e7d54dae6ebfc1d3dbb3f240e56e516aef2a98e672b961e216c2913f8132b2ee08238d5e5df978879a7b0dca9c380d57aa924b983097120461ef89241858dd4464a04181211735a6b9656ea1ba1922a8282d3c09fb392ab47c8e0646fd8914492906048b07fbf0f5508adcbd1e0da81e0059aefe889e31374f935a1fb78788a7901abb660c6d287bdce9f1782c41b925ce5260ae022ae1b5558af0963037f8041302a34961414f0a9b4c78ad6ec41d9587049673b2a77450c480dbabd0fe8a52877e55dd8897b3b6e59e298bc36352e2fed35dbb5e30bc78320c40bd1719c4bfb588d43d4549d33d72e5cb77ba9076b586b9cb8148e1be4a205f1e5f936e094068ae0b5628309a1a77f02453a570002d62f5a2ec41a03ce360e10a12e142b909c718ae09b404b88b2220e25048201fd7a2d24bd281e66e9140039335a8f07e9cf8c06dac483fc94a9b3bc194599f001709ccaa92a777e31a82c192149e0f0e2fbfe88ea2ff34e501fc746a0faa015d49094d9f0793448195545ae0ba0ac10187cda282bb2c8460b04242abcba5a22dc37420851779f8d4cb446a0946b3c3530f0452c3cf3223e829280e792c4eea7ca556102e25346517823b7c6ea44ea65e47d7f946625cf9a74a95fbdbd4e629d0d27403ad9a72d520c0dd19a7d92349d8bd1a3b722e1ae7c387d8f1e1d16e04c2293ce0f58e87e4dc427e8270a152385c01648de2ea32a2bda4e6c4f0980985b0240cc127722973bb548928173801e9cf96a07aba245abe0b938c32068d52f713090b250c2718de4889c47380c5ea96e892536a28dbf166e71a962096f64c1e45fa2914f4b9be2c767815a32ab70758976b0b44daed710a7589b6e85c116d627a650d1b1882081dbd3a0d645c37680e95837004fa04e01c7b25dcd4bec68cdeb302813f45d88bef0179f5b7ec88652f0b8e9be55589d20b89530fc8890afce60ed78d64d45416308bc247906503cb18bb75bf0ce9db6894833b84932995dc317bb35626302d506d17902cb75e4eaaffca37a5e7e6e9773d5c21c4255646c7e5304010ae114842e1081ccce1e220babc00966061593d02ee1e4a404a52b41e3d170aa23cde91104fc90d03e50306597e6dd1c63434b9785b4dc0ca092a0c70cff4c1f285d282f7138346d86c78e63d2d9155ea7800c59d3500217c26ee0bfe216e5c6992502ac55421d2f39d68f2750610a06c2341dcc592a7acfc5169c4dd90e843b98208a477b0d6cbba372fae001098ba769bda9e0d19b8df80995c40953efcaa4116dc4e65791718c4ca2f910506173a40cb6df1a55e5860005c5633ee60461e7edc240bbcc13d51affe0d13b8876407d3c553c9065777c0e072f172a80740175ae9f5e72cffacc1e1df03007e53a70e9b601de895d85b7e13a7338f3cb4e37a92d26222c049379013301f8907015f9762c21b4285f9b0535f309e4e9cbe813a0f57d42bba37fb206ce641f351485db907408a71a3c4217102b7487da74f264a4e6008e10cac54f5d45e542ab92554984e1d117f786b528e0972771fe0228169a16597d0a2485d465019f07100741ca786a16f8b02ebc60a42e3ea0a202e1aebc89f70b3f1004c40e6428a42e6467935e91b0de16f00aa42ef874401f802060d5c269134610a6404793b699ddeca8843b7148a097e500317584e5598d245f287d5daee359263941c54d1dd03b6a45d1f62f4f460b5214ab8354630901580ee0f053e611774ebab7dc15082b860d45328baba80b4a3bbd92cc25a1049f0b00468f174c4de8711c3e24095f81d2442d0f350247e4c6dcb8f419add220476e5241d5dbe9583086ea060272cc1d68a5dc135794eaab0e054d287eb4bb5e9c671a5e27680847fedd3976b254e2ee91051f0681c845c0aa4d07b878180eb28cec56dab71a24cf506e47b5fecca546254ae8f2bd1ed0a85e80b0d5100b3a241f60b8cadc1132cb073cf203980d784a1f0b088b8781c43e8fc254a14ee9c1d44ee026d16f4c8bcaa3b418a20a5260524e1e1111f5c38ce3061041258eb1a6100a61b009a987285990f4f06d8ea1242e5c08d5447c50e204cf93d29586009b218ba0e10d92f8b16ac5772c75e365c38bc291b5d7085ece9636c28a59a4a017c19895998ce55a66710614e19a26cee5a4292a4ece202132ee1e30ceeead0e80db8c00457a3162b1e53a1115c7a1841281bb08086b9aebc282bfd70f29ccc925c534b50dd436a62bd05537238730a7b3c3b15604611947c0c3057ef85c8d86b62fff24180cd23fd206f2451644fab02a03b0385a2df10f6bb7a9a44f9319c207dfbaaed2e3a3107b31071c0d5c0e5e02e4f12e1b7462fb8c08015f09cb9c60549d0a44bc94caa1e8736210ee3a244cfad4d037f06cacd95c3aad297154982779880f23306a5e158859a3c870811ca734c810b618c206c2a8791970013d9730895e17a85d16ff62daf26c7c01dc2adbc08332e3f01588bbf76d0944ab0b8b938c0a4625024acd0cd90e7419726172afe01e745976aa6c7af75a9dd560c8077461f4ee505236457c29c58b80004fcbca41e4f2e0251b25c4070c4de4c8cfc665154e11a61c2fc05b4ce9b628028cf032c56697680021f28491dce2340c8a36aa694732ff7567ec8b8305651f0679e528fa3521f6c4006160c2cac213027246cb85c4909c30da04ac32f80233088dfabab66eeecf1f86ecf003ff9da6a599417bc90bb86ecfc5c5549a8bc8ab42fb74f9ea8579169d49b39cede962c237f77cbc1a3d151eb11a501792f744adec8a827af06aebf225926ae150418943c5834709d9c39b9450d0d5c353fb41e0b10741f2a965ad70d34b52e005df63d13a6c36db38a540f0e97849fb40e312d07696e510d19dc4a45991793c97c96cda1a740938e2b84c372bd3edd29759c81b96e1c15ba8f2e55f939a17a3c9207a0ab03eec4c7cae275735402f4abdadeee2a3342f93687d1e39005f6b422ed4bea478ccb401c0925083123b8e2dcb77bebc87a0e8a78dd29692cae111ea1ae9a82424f5598b12bc8ae5259c114dc5d8bdcf2d119d7a55184ec3571e17953a82add550d98fc9cb052b7cc91e0bd53a907269ae9f273fe54287d0a5cba6b007370d99dde0b3bd7450349ee533a2f9c00a538171dd350ca9a12e91a5a3457b6b160752b31c0580987bb47e01113bc470f5a29e35689b2cc88a5fb472d15aec2ead02bf000ed0612a5eaa2fdc0f265ead45c10bbc77ba194fc3427ba3c32a7782b5810e8826971f23a2ce0f38438b8782d561c94168c4af2a615aeb25267f31280c8d20617331cc2ac2ddbd0c87175b8f1c4e5460719a67146a834d3b10707b0e9bc854c5c509668f5870bcb0cf6b97a46101ada4078508588466fc5a9241b584b4e2cd408c0c7852c4c6880b0d021c383e0190a62ff5ff7141c68f8ce9ae826335d88d96d55a36232c85ebc60b1efd8fb494f891722ebd6fd7276e9d24874ebef251bb8fd43f77d223dc03e24c9f81a45d4fc101ba6fe0e842edfa3f5e17eda296ea203cd9d6509ce038270fe8b94c96bd170e64a5114094b509367c2ad5bb742d4da2b862459dd84240eb070d0bdf4b5c54af5c5aed7cccc8266bfdf4ed93678ecbad5685d37fe7ec37df7fba16d0f1e7bab83edbafb1d3f06f3b4d16d2d1834db284743d9fabe63b50a830c19ec69db0c0cf85536dc3d824323c6a011232ab78fa43d88166796c350b6a36eab5b535ed72279f068648bc1a31159d78dc1a3117986eece23f8fb051f0e05dce6ff45f495b77ce5c6b8330867b9dbd9eeac0fc553b83a2250b85e711028fca6ff2f0e5b6d64b1c26c77574b6540854d946ab029254a511c4c65412e743169a000003e051c71c97e8ee0b5823d1ea280e2636242141d63446c89c002cc99041210a34043011a1a519293b624d29c151a9dba56a1e7ee28926cbbee3141b1763d1ad9229a47c2de5027fd634949fe712406652ae0fdf9c7901e6de02282c47ff96a95486ebb374fc72433c9c454dda7b3e6baefda75dfdd25f3387b4453dee3f70b0601f8fd58394e5cd9ccc2ca58be55a156558df6fb01f0fbfd7ec1e0ba51342d06d3a30e1e7b6ff5f6ddc78ad22722ac1a79ad6528e8a1f3a98dd59f4f3658d9f9ffaea7b007d0ebde0fdf2a5aab187dfead32937fabd0555f9f7f3e55b0f2cf38cc53e580aaeaa12a2cf9a76a4e9585fffc4bf528ff527df9fc4b75e65faaaffc63957f7b1351f1f9cf3f54543eff50cdfde71f2a0fa73cfde73af977ea78aa2cff4ef5f24fbfcf94987f5368fe9582d54b09cabf20ef2b25a45489ffcf3f52acfef3cf470a0b29bacfbf0958612ea22e4d80fc7fb3af3f549f0d7f3d6f07358bd448e20ad42c12d8e6a96916093c1a8774c6219d7148c7c3d13f6e8421f8c78cfef1a207feb1a24488fef121432c1bc76e3bce9ea171b7096db0feff869a0b75d6a4d22a1c9618c03334ebffaf994a31e000819b95e6ffb130a5c15b81f262eaff6f97535fc303121dc0e5ff2f2043a3e84899aef8ff973f8e71742859b855c1fff7e2b0910357c14fa200feffd6e812e46d4b95337ffeff5e3915028ce52aa3f3ff58875a0d5157505c79f5ffe5052d8f548511f327d2ff77910103eb4efad9b2f1ff38942b2e4968850115c0ff739539198c292e2a12c1ffdf1de10196cd254096feff4e12b23024248b114e2ff6fb990d8f47209ffbfd4ae4aecb823e508d3ec976b65d913c7e01ed5edbbedba0aa875c6dd76d3c7275df6df4c78d225a0685da6446801b8c8a2469e94eb684b4a2604c160e3c34d11ddb242931f4846210221525de20709ce109d104a840b1dd50332a448a2117940871a00312b12759c15ff87150e3605402654e4c68bbee20280ac5f08e0e48a85205a64a0d350224a0baf0b0e47864421c5906183096e86c519115bb27e33cd103411c91ba28add883126a00d031c646c3d80aae18396a30204a4b19ad14a69a54299517610b51059e98f4529506b294e8ea42c405426d839c48f5179c129314a4d1429ada4e2afa4c1052a00a0ca24bd94229117dcc447958d56912dc87063634fc59e009a751769eda70b5a85b936267ea092ba44b13a207354e83ad4b122c973888b27486541e97893c355376460567fd4055a6972212933b2a7688ac582517ea8c075890a6548243e97420ce9b510bb651d4f160cea6186f4b3020bbb0ba50c7c1d2937d05422481429b8b493df2230486a4d0810df022cec0435149847a96a702a444a28e4820fc41621880959c9fb083ab472c18104a3d62356c40803292f4f059c3b321a2acc8185b0d366f8ce688800312830bb49045e480a67886a90c12852172feb0aa7327079042ab70ac71d243a8a9eb921128c44c1250ed490508b10614ad2eb20c566aa951e21476e44f95072614fac4060f173eaf6cf5a8e0e86a4f13119fd2ffce068d433a394e5cd96ecf13aaefac7914dbc6b4ed622b7ecdaf119e3739e32fd8ff0f799f270f313867f55ed3ac86fbbfa8d48e46762d6fa36c4723bba66a54efb87fec40926d573554efb8b696f3b87f5c080b22246890a00602fd1dac898fe3ccddb93acc79ed9173d58703007abee10000d3c887c4acea1e40e28a70c8f0dfeaa600fe8d757b9afe13f9d64e35d56aff18d0e58250895305e1094d43b73f7299d0b8b823335d909d17969a0f875260b0467d2eaba4ac7290a21f5c004041713bc8a175d99c88dd0e34c8be6762f5324885b9466c4cb917383040e9a80b9d370323d52533ebee7d6801b0060d47ee940afee0adc5d0657106e8226ad575992091705be9c97b3220717098872eff874f58a9874d89bbe64d83de90176298c19e39aeb91b5aee9e376365161eecdb729386eb7745d4a522e596b05c61b9a8f02295bdca8497f268c713d082c67f61650136a0819327f1a5ee97a8a0711158e2761f7c7af47a30192adf2e00e05774522b39242bd7151d908fe04dc895f48b542af1b5b74f0538ca080750c154e620749597083d022bccb8c2bab4282d956a89fc8af57ee45e70f5f861c07540284f8f460a7c3465f2931125e907d0e0051f61dbf303a05529e9906df8b14275bf06c397e7c13ef090b250f08a9cf878577aee6e5e0f2e9cc1c8d8d330d5020f800478553d808411f843e7114911be9fa41f0c80241fb804588d32acc90e4c653575dfc010bbe4623970c79e48979621187e1366ea81a9b0e34a5034e52aba93c07d40c6e1521824e13a7891a4749281ce1dc000f43e4173e67ee852a39cd428c4b75dd6e04b01007f586150090098840b8407fb8d2eb4793a4845659c2e437f27afd67dd1e2149610c7012e069f44bd292d5db808253a75d7bc05e9699073e7faf179784b233476a16905d79919692e900bfee0189a6c5c30583afd1949155c4564454a203b5a7da71d81708e60d7fd800243c9068c9a3b810a5c396b10a72b4814963b8aacd295c26847598648bd17fcd0ab408f31778aab006e1f2e666e154ce74fe1616fdb008dca1c951c6127b1c67a1ce6fce05daa8e6b8a9994bff2834b2f960d06be440560c9072f79175532f2243a21af0d0ae77d222bc50719a2ba723a70fc1d2b0f0f01a4026e2552a9ca30b21cf89f55088b1df35c3fb5a06039450eee9318672fc744ab37b402ef91cd177c856ec42523a4bb5b262180ef44aaf22704a04a2616526c24cd778d121101572091ecad8204f6b26aa8291fb160f5275c59f0b6ee48708127d0301002aac79084ff1464d76d23888047134c7409e8e4a3446487c5d3694340f944bd72e3c46a802910937265254181935bec9a3252f7a6039d3008297337ce13980b09c80a9cc1499da7152ad815e6069252ca25d183e0881eac6182b28b531e2eb7d3222d2597a452f7c52c09be8cf0c3071153032f29d2f6acb64c70836622ae893a119411f8315f87fe53829001f60c64c88013f072e58751346119696a5d20238694051431f500446a545a60db8173bca9d193128a169e22a7d8a3e586081e7bf5a68bcc8d0a4eb2a50c9b203bf13b4c3d5006727376d57c79b76d13a52722460d135105e3da9df8cbb5aad12d5ba4a964591470ab24935c1e8310b80be4c9805dd44973cf2e3cbf86c2d7e563ea0ccfca02e12bf05af16e4e35d78f8c0d2f8bdfba67da60ae9e81cffd31c50b03192162dd42ab7074d9715a738d9736744d9064a044606e458fd2a31e0fe228e4014199f146ca22375559d7fb28d42a2b98d0e9c19e84ba59b4016fc2c19727928af05fe424c1a4405cbaaa36b8282f3868f10e301cb99b15a9674327c69b67cedc387e2c5d36473e5d13a7861ea9321ef79e69ea81c113c1079962a2d71ad1fc2b06887f0005ff9006b1e89df942f43d260c299f0c5a74590d8a2b01f030e4ee9060155ef416e172702079115dca7011edb33f9393e33f04dd8701f4fb05b0b8294b74d073e9408c613439245e820b5a65103015bc861619ff7892e5dec910de07bcf095e4e6002e0d312cb873da20c025b70450e9e8c1a81e8b4aae6e1451747a9a5855f01aa65c79252d7a770294fc702ae8f33a3c81952b4a0ff7139055b8919889fb07cec48f10c5e18f165c28918f543d041468b89a9ed10f00aa808f3545c2753068d0b73872f82fa5f0fca23602e04f93c6ca3d460af7813d5db0026f0f2e22075a7a4b505dc1a4c0886230015302b8c323065c76826efc71d200f88529f4de0d9a5376b990ea8618d400feda50e75a9a70f772c75b6f6b8215df8013850f41c448492a109d17b1c78835ec09e0cff894958958f3390d10a33c21bdb94012b12a258de9294144608bcb04a71ad8ca0f463d46c13df8010843f79c758693a9fcfc2459b56e2855834a3c616c7c29ea5e109e6c7c1c9ede22a34abd005450612f768a7e6dcd9bbbc09d077ed05d9352d32b51b748dbe709f5dfa76910c096e4ee5dd509634336e2fc0f0e5f77538948778d8489d2498337cc848159bdb7d5f553186cc1152cfaf28fd2deb84cc9798159cc4ad1ebf4b570ad2c6d99e2cec25dc4e5813b560186db00915397d328041e530e18f7c86dfd9aaf2765026243ae2a38107c9c142a77c78b12b80b2d298f82929be78252ebfe32e879b3b8b9ebc4969f7fd225eb7eb17508c3212b00abb94cb0fac4c61d60d6977760cf892baa4fa82e186711601818b8f40441f981e9d4cad10b63d79fc91f2f659c67f55a08e30e2954e533647050b662fcdccb03ce758483c8f55132b9ac861470c36694791186b4bc9808ca3c20f4820b05098d12ce24dfbf9ae5a4ec79c53fb400975b0382991b05c7e5925581c37da01498de9f4c63302a3868ba54e2aacb4acea4ae2e1458504a1812a637aa68ea2dcc00bb277684ba884218ba8450d17923615cdd431408ff920a16980e00b2bbfe908563fd0cdd0972662e05086a5c35bfc0254247cebf6ad1e90b4529f4161e482b17e823e673891158c30a47b8c957b204358005655957a1fce0e5c2add245a894f007474903ec4c39e3419c8bc77786dd58527587207183dda869e09a6ad4e372323ade4bc498bb51b0b7b047cae50327e78661a080120312542f812c82b2b896e1599c8183f30a88725fa04db097a82d77432a01ca1e1ed897f0e50e8f45b000239184eafec0c1858d4752e14a64a46e83b9b6976200b15ba88103ca1444f23092f30b533a63f120b8a99b674a971fe0ae15e6d3f374df1220e241a6a03ba555efb63925e5f1ba54f0292a387449f4319652bca87903eea294097ca68b45d2181ed207828f83e3c4dd4001a5f762d57655857000635942e4fee16470113d1ab8d004f001af2a4576331915bd1d4aa1b85071817a0a01c4c039ee20f09764112f274c486e1b1017600efcf122f418f6c2b5af7a26ed2287387a3b0c90ba5f798cdc208e380f658023770515bc8f75e473b5a8cd784d6761de501a19e589a1ad1fb5465f4f47e3e57308f7c4ecc171f55010c5e58747262cd6f5a577a80e808b80a0240c00c882e4fac113a607a5cc710778ebff070cee32d202e1b1aef286384db9954484ba629818cb4848c63cac4e596e5ada93cb65a8e441a0f8dd4a3fc1e799eaf084da5e7d1e03f05c204814c078077cfd95081628f91c695d5414f0f0035d2ab02d38922e57250a5788044cf7479c19170957965e0b32a6301de29e5bc1a02b8f4ac172edee00fa77f4170b8a72ed54c2f46f4e31d7c1830617469ba2fbaa89dabd2088a8a765e629b948aaf04d7cb4f882556c2f04af16c6e263c84d82ba7b55609b6e4fcfa88f106bcc3d03740a5f122016f62241c675638cdc4d54c44e6901a822b88211665d3854135ca9c5b187e7a6ccfd0a11e5459102f3b1b0a8c16374a0ba70abaa32ac0edbb729a0ecbb18d5b99c641929316d7d8b68d973310121f142205170333989746920b05e3b2ba47e48911b8f818bd9050a0978152d2ac0ab2d453d3731afae9c4c3f4a1e6379ee026a46701d3920d19309a572dd49a300a708a4f616e0a1eaa18c8af10f6078f14cea7cba0f1c02f280ce50958e2058b814d44af10c0c882e8e36b90bb61eba4f4acdc205d4cabba4e8ca3e0df0c5357ea972d12952efe44f960f14c8c39351a1e1c29901c01da48342a9258f838f63b3c615e6c7d3278274ab8424c70c3f1acbeb9db1487311c07387abcd928a3b04561c761188d48751a3863df4665d46a7225db208067c9d4e9eca38bacab33a026c80989b0be9800330a44b256e04a5427d2c514f6e47d747b4c9c3656527447963805af7518c429f45c600d884295825964488aea70630dc628a04f0981b427a660d44506a8802a20b491e1a7803253a5c1d4849b83c12609f2c85a50f404e100c070abd7637a0e0304bb3de0d160d3809092d17882a49e5111f78374d9c9e2f8456eaef6e0a8ca5549b0b81844ca5580af671f0ac1f87bf5d12635294b788aaa480c0f758001dc067b28af428bc0954ded832a34bceb0cd7de3a604830ef7ebc66d6a834520275c5a6702bf2691e0cab9cd288f8e68dd37636695741022dc4a6a426ed8af807b0292147c0192403f298fedfee921e60e5242a33c40d4884b83c78f321540c9a3994c49764195ab4646809bc9d11c0c288bab920d84113778e37323d02a855b35c95c96fe8072468a4fb80ebf812f44c982cbb4f579b501d6be800b6bffe0048abf6237e9e6892457aa5ad1765f2930e716313a7857776cca567bd4ae04022a5c459e82dc3d2832952ba85cf0237474782d2f6edc0ba2da9e93da73dba4e97205a5c8801f58882bf5b0b9c3b060c8e97d41eb7323bc8080c199480dd681a6829e871375572c6d124ec0450417139122463380d8634eb270306fce53e2a6b0114e18ee282ab88c72b6e25eb0e8061e42c6ccd5208a979bec60fa43454add015e20f05a22752a599c427b209858949c7c4feea34b08c341ab8445b14dba2b1302aea48fd21502d58772485a872d75d054e2e0e0840199daa3442145511790077a2f0a615e0d9e3e1756bb067f2823e0ff04ddbc00a9ac7c0f0e901e0d870f978bcd4559c00d1ab7558f15d70347af04592aae13194aae9e485a70223279f7824d66ffe0c7768d58d0a10cd1c351a673d41200b2b6bb250fd12de5a0c81562684eefc51ee04dc52ad4753384cfcd711c2ea094c58fc531f27f327d5d0660a0957986e03c900a2856037c70d546a4dd3c31879e8805899e858e50f704e4c348b137bf64824e0fc3568c6b86c7c3f5e201ebae88a3ef2a4c62ae58ab54780d71040b91e07509c043bca7a0902a2dc99a81296c407b852e8dc15e4e90e1065847f7c2ef462fce0c9f1bb60342297c94fc416aa03c06213b9e4c9f302ce7cfd70d53c57e240de8f1283151ea2031e819d884e9e26020eb2fa844e1deea47ee9bb5aed29404115c3c03e67ec6083c8fe5875719800b07f84284283d35176e61018615b87ea538bd041fecbaa8bc40bf4f933b3d330572e0267ce4f09058ebeff130eb4e80c778e54e755d41b6ecfc1d94247748fbea9a184002ec82c9aadf3196e14b85b1e02de94871cbb4fdf8b13b194a190f3cf0acdc08ba33d0387027a80b96432e7b4f802871f59fe10f1054759521e0e522d944a29c0181ca35953c54e6654975ed2a50520a7ae4e3ead801898bc28457bfa6a151c986c3d17de00c0e0c2804acfbc6c8a2afe064ee03c19175b159ebbef9c953ae3274e41b688487a3ac053f021566eea02444fe44a1382509139ade14a6b88a66e00b41285a986848081e51ca00ac0019a58ba48bf7d69ec0ba6217fa25e10710c693232cc9a234f0954c8961428ac0dc21128d29e4a17ab3557c30006e52fd020f707da249ecbd8324a0ecf160fd30fad065314680b7a3520166e074f47d38b0795053f8bd3c34957254310f645156e609c0d41730c54aa9281120dc21cada35374853c9e097777b9f406164115918d19a6fd9224ef80884aebb0025445c92dc7c5c486d03a51c418ebe6c0293520a5da7277b91076f38a4e96a2a97caa3178a37c7e0f8202a70dc3375c4fc952c628f0e693fcd1328af06e775a3f4d05faa8aac9b25ced64d33b43f824865ca062b1ae16402246e964277259aa5df4de1094d979a8c36984eccaa9e222862984821b4520ed9e4157840e5363035e93d81a9baa3defe3c9a3bb43e4426b23f6320c54bcef2dc4058e8cae290d07d2f84b00267ec7e824a14ee5103a71bc44801ee9046cca5f3d5a664a0cd836bc01559f8003989ee1850ae309706153c2c1c79e52c211c7c24cb533611950a67789556ae2a04a1f4e1a542cf1685027e058b54658a1452beced8a71b400f52ff658757e902cf9fc7a283d06590b76f5b16277f210388aba2811ae5021cca7fa024f234b8665d48442c614c94285c3a528e659e1f2a3f06d559ba95f071699c49c2354662cc9d65ba2a4191e592c21d59b7cd15dbc551034f29ebd6a5bbaa34c1808b47791542c25c3d6816bd0f1c68f7c8154aafc4cd85cf44c1996ba34b966b000b4997810bbc4246ad79280f2e28d9e889f00fdc124f43029f7ba41503d72d58e4df54e0c16d8a8c78500780ba17e4b175c18800f57dc230ba35ee6094673a19ff4f97a81b77420d972989eb8190e1068f49722a21b9baf06d1ace709105323d2aae219700302d7e4595e1c3d648f0a0024871159815eb7d6d6edc1349f87c026190603d3d0ef809d29ebca54ee513bac2e90f0881e50b4d6952ee58b4e47d0820e3aa3854045f48d1a524b38b71fdb009d1cbab4302df64bf8838bdc2712cbd3dad4972d753d98f1e849f930baa58e335831aafe4b8eace4a375d379d505c297c10b83b2651c16cd209778f5cd75d318accafc19a51da79c1af51602ae1caae3c02050470b36888731510c1e5afb805b99be82cba653ed0f81f3374f40e7072624f78d34541b6e39eb92abbe4a424cb22b4a694967ea4c0460e18d29bb2c7ce034180c8351285ecde49f41802204997cc202f4fc893950b80a20a8fe7c58c67134707168288e06bf091f5463e51f9ebb384d7acf1f38efe447a0a22c13da1b14c170cc38b9fa1c60877aa2b845db474ca34b61228d940fac2ab1841ba7d3ad4e15af30005ac0145a41e0554cc700900a00b4b08dd774185e5a61813f75c5ae4bd2656606e0c2e24ca5e93375f36880ce65280d597f1ba82618cb0e00a8a40018f4130e6ded984e2b2da30e97661c238a84ac57330335312e023e04dc870556e4a9502233275010b4b74c0700eb0e2b23201d3954440081c01a058a59e3aa9ba3499f952625125c0db4120e272858a7211bd707349d5a8509a521f7d284de6a5934bdd18680e7ca60965b7d62a067e0d02f4f9981d8061c858fb2e7a465d4fb110b89eca0829f93020eb0a00830526ab53e7b70514254725013ff0094ae9a488dc35f3a7496fd0b1eb463131e47af4c50feee10781de8ab8df359166fd544bfe167a70f770ec60f84db15c3d9986225fc6d6a3240449c6ad00509bb7a026ee7e029a70021be43c8c160c7eed0f86cbcacbad87652b824ff96c794a802a3d945764d80e0c3a97d4042b185203b93f934512574fb2a314e0015f29d688c15d832570e1a516e00b1e88954818f0b90e7499285bd559e066a1c4ef2f0cff01f817ae42418c27200a24acdf20b9708a7fbeecc28eef43c11126a426c89f51702c2930a275796845f8015d913bf6e50a0fbab37603bd91c16d807657c82594b5aeb4ba858624ea6529b3712a40af70562104b399077055f86000ce6400092e306b0fb73aa6f93b46df7d62c10fa6c00f99373385121e32cacdbf6da92b4f75b8f16d234b180b28b42bc2d4a0d26d01022e08143b9e2bcaf037e2ceaf2bf5e1c25120764fc47af531ec08b8724a2dfa353958f74b011cb09d0adf838187a9bce1a709d72d4a5b6e318f0b068504799fa0adc242444d789da3075792035c5d2651acfc5a231157569f553a62b55c2c799bae10327497031d86720c1afb7791d09b800a04ae28bbfc901a402f152250fed3a03017548c350c00b2c5c56f5a3c728da3f7b24ac707d5f8b9833014e15a20932b7cea8cb0eb4fa83fef0151282e474c4edc37202270a18261bc663a04ea257101e58dd070548615f1713f0511737b2037f745a5228fc7aeba653229f0a54ef340446c4c6b0bdd3db3409092911d2897c8a817252828e983c8d008aff100e67f183174bf44c0f46dc6847903cc202a87b9130335a4e0dc173202e14d38c660211e9daecd60821be2c8839e0d4268ee141f467a3ac234b9248a14703903252e8fa0995fdfe43ba19450a672f4e4b63d82fbed067d2a151ae10b43e0536112f7dd5183b76333856f7588f45376c095b5547d7a5d01cf937861e232424d943d74c4b907a87d75b5482bf14a7e5e7ab4d8e45c4e807c7491a125f779fc4479342e0495c60bc2b0151c90ded02145784eab54b70b10cf755362c8c59144cd4d64a7784fc1627f80bb3ecfca025d86b102ebc6f1d071063e5db789667325f5062f02040d3cc00ce177c949507639207231119001db11b380dd4278f5424c2a711b941e5cb7c088e02e4724e1415a8efc052450f5ae5440e7cdd8802bc78ea8df404a84eb1528cb0da30657a28afb74fdd059f9324ce6a3ba35e83a0901760340552cb90041ba9638b9b9029055794e4040612a65105d237506fd1620a82e2207d2e00a76d66e9e95126ec0e3d4b73550e45a1046e40a2958e8810112701d0db9d2e5866c004ff91240d98a1325bc66c78843913874e5041a754fb19a74c55278fd91411e6e090a77f8caa5e43f3a64e50d3d91f57ade2294a4a6f0476fdde1394b70dcb42048ca1860665d551022b80758aa745958b9e5004f40dc592d585d25211461096cc9f500a012ebba8a70a9d424fc955cee0071dd51a372694469d4d5667fba013031d1d3b261c8257bf1a774b1e4c2bd1834dd235081dbe702286c8b6eec52b8e0ee49944979b243141e968626df40ed0136a3c2c3ef1844eae2b135e9befa61abdc704e70792801e0cb183170cb8c6a74e5f67cc097d1921291162a259a97230ee2c1f48a0281b938d690fa58980e7149f061edb530f09533e00add4381c8dc32be0bff677d7319581974433119f158cee4ae0b58c192cd9fb84390fc286f026317161f190fa700a32b224386ffb440a6abc76c82bf2324cc1b29c35c3f98085d40915add320b64384bac0b4a4f5c6a975de280cb6b4a90ab26538912898e096f00199e9e2c49b34a2b8f24953724907ab448a76c512cb91c78d02a33a48a707d78a2832d0811e68b201a71510028fd8b59b2ee201879fe851450659e1e3a0f4bcca5b21f9af0458434506668eb741958c440a904887e025c4529f560895272d599bb748e29feb1d117003c9f5e0238b04a04d84a95249474e2eab26bdcaf84b930a5a5ba638268950c6efd3d4335e841dcd273f3605db83f2d30ded78dd789234d0f818b33dc87cb8c5bc74d90e74ac3f2315aa5ba5d0e6df8140584c07b648cf95a3bd3138df8790bf88c95112060c235de7c2807d0d1e909785b817f08e0e0ba8280ace787805397d8a51103b1149c2e0663d99be18980bfc204c65d640bcd4b0203069f0dd8dcb64e6c1792051cbe85059bfe80268cae1db552e58e0366dcbba4106c27ca9e6bb636e30d01d12eabc52c5db145fa01e478dc4e6a8267126204f604c2f712e4d95c4b36059fd5991f3d496f43f00fad7b1d8054ba280858d31332aa011ee18ad285f340d0ff6173545e2800c723e151e2cf090c9ed7395e0d448cb70bd38c9b34027c166e29f0200851aea60707fcb14d883fa724703f39e2726975f1801f4302af299301bf838183ef6c50940f3e65c085147d292148f36021b52c05ac0ba834f3a6c6a19a640cd10c00000010006310000030402c1c8f4805e3019d9f0314000067c260a65ea00ac42ce79432c68011000100000100000800a700f8f44f749763af405bdd0fc5ba92eeeddb0514c1e8fc3df9b244eca122279d212954d994468cbc52aba95e133c64e7ed85f4323181d2b280e7c56d500abea0ccb090bd187d4e6d477c4a91554f5811233081909e6049417446045e2f8e198b8070d1e19999c78cef186dc84af3b9e97ddb5c1f76dfdf4d83f7aad04935b2e48bc525bef35bb0a9504333ece602fd66f0eb0582a43eb9d48ed9d000b9d76a9842c4ece1519f06ec1b5c6499927fcb10b92b381ee27430651d505a1956ccbcb404b15576b8d06a4cde37c670785ff59d1043908d55877a6b5da82b53c9d67d63b0ca585108df5dc0e97b707bfd3c38691715396dd5736b03eddc10c82df34e5c8fc9195cb248cfdd78cc40c9d8ab076880dad5b6e93ad904588e52f99f29e4813c48ea7cd2f1257214bd3424c854b080b20276013d4f83204e147ad60f965a8f4c049ef50b77ca8d41b0cbe8570792c35828f6cf6a2ecc03b6fba965460972648109d451c8c8fbee8d5fb2a0a5fe1add0b1d66b4dc95540506bbff4de448494c7523f6a152d7762f5e6756b0211a065fdd13de07d897e8b7b26db2f4f93d5e4e162bb777acd13be27df9211f4fa7f7e92d78bd9b52afd805ac8a8a4ac73ac31717d24ad92096e67b8c7a3eeaf4f36b58854f529303cee02f1393a9ff2245a1ccf981358db7f4470ff9939a8d383a773877ba6bc71152fb033b117fbf59a51beca5a08c2529a875832e9d8a83d02dc5784f9c56e68d36549bfb45168636969e6f6ffca9eeab880cde1809baa07b667e7e5c8f6513a2345227370bfbbe259fb8cfbb1b05ba6d717881b7701c6603e79a8c85d1dfac5abe23c501ac2e522779b50ab724e96bba46601343098bf72105c07ae913327eb0206cfe8a272cd43b877415799d734bb52d1f2139d39ba827fe34e8fd637381ce32bc05ec5b262ede020bf6c9e386e988c301acbf84e04fdea8a9d218cf6cb6fdeec069404568dbd99b087819e0fcdee6c1f5f23a0428b9418648a405cefb7bee6e7cb6718c129429757d791fcf05ec6e124feaef69331d08508228a038cdcad8944e9eb6f185d6f677aa0db0abb2cde3af6e44fde603b98342862d6efad88f00ad82f5ad5d4bd9c132b5fe12398e31a0417d4df922c65800e1a089c4dec6e8f25e59763e0c8e5e393b51b2e2a0a8710ab4c122380341baf6cca66f706f42934bf3b4eef8b435df904887dd4c3b4ff58ebad3475922455bbe0a1e8780cd1a401a48bc6079f0411174d800d00a85bcace1df02318b65b84149c4e193f6a6c01ba7a3170345ee6c9655a5045cc4cf18b8a29eacaca68898dc844053c51d36c5f92e4137bb570eb0a03b4673f07b07af6022a435efc69e4ee377d0ab49dc37bf567f6935b6e2ce7f930859a5751427ef938cb86b00e4df96f218a0fc7dfb668d76f27bfc55c7a94763ca8f946bc2801a152bf9cfe3be95747ba3ab487dc5cdb46669fa9ddd99d22cc7bfa1e1a52eabafc30755e047a75d1f5b989eac6320186c279a4e618b97685f7d09bd0032f07ffae836855c92449f4d4b622f25e30393b133eae186cc4d665a8d033b1d3915070bbe57736ed1d7c9b7e9b8e2e4564ee228f368b273c7967e75f1f002b16e64db13d5c3176e823e50afce306eec1516373417d8553461e4e42ee0819faf93592bb2c073e659e8bd82e2d30dafd755d1616a0f59ffe06c2a72b3683d8d1aa3cddbfc96f54e7135411df08f46205350d270b2e6387ddc5ebfd99426d691b5c009696dc209ced1e6cfa2795de6564e5bdcdfe6074b785304edcd7ba197a3a2e82fb903fba8e943b8eb23e2991bc769e637f52f7fc5c03b63e715176b660e5bb2a9d7bb4f94b23adf167c2c73cae51bffa8e340b9399e77cb18ee2ab2fa5a145cee3c5e7b7850f6f99c4a7e8a339629a87e0d30996ed11ed7ac5c7d81be8555ab14b1cd7b414789761436f49b27e1498d31b3127a004433da30742003f8986f9b0c54d7a1d54ecd8ec0449a8a685569893b14d7c5830c20478e6b3171b1b675722f09ea4cc420234daea67d36a3bec6a34be6f9b92bd6901eda3b0afad977df666bcf0250cf1873aca6b7ff697307adebda7f27df1b722af821ee9bc8deffec6a8e0ef2c25a5b58340fc59dbe01345ec54f56da5cd2c433812077e9bc438a71c18f48abbca3dd9c7c4a8f547be9981b8177fac38d87e7357e4b95d4d1e4dacac812020e47c454f61a5a6700aca670c6aba64e3b489b6abd3bcce08dbd1e918d4aafab7d0a1cc8d460ec44182f2305805772b586e35ed9864b304f348b38c15745238c1501aa88c2d16be3dad4863a83a6939706bff6ec6a734f9802899dbd0a982a3175f07b878f38bfbb406c3bd6e69ef0081b8ea1b61a0f08ecdd2fefa4b620b2c8a25dced290a612a8cdd0c5a171073272e2bd6ee98cb12d7e8fe9148cb465e09eb14bd8701b74d90cee6399ee562479fc5e6664f8aa613070b4e1a7555ddd4c46785b85c069e6960cb2c202f3e495e4057d49b5ea8a9295da4841d79ee765442302718126e417824ff32c06b82c91d29a75a95868023b6125d09a56cd6cd7838295f3ac76b6b10c5ab930088f9694fff220f4f0a4361b92c560add9b16b7e438054d71b74cde4d5b0de37c4bc6557430daeece45dafe09cd3c7f0b7a1c37583cd39c39f210806b78a9c29b7112eecd8e1b59d414e4ffd9cf0a3e85e788c7b5ff2256d3ebda0dfb21d8af80f62fa566de3e39e00c8f0b7b1c60499457710a05881cfdd61ea0422fd6b80d20bafbd925eba7f323e18986a5405e1d7048ba9a86411ef75ed5e74d773f9c2f15a88c0597db25b1730f566be49f6919de82eda4f89e3fb7994f6ac94fe0c8efd9cf99d85c3288dc16f3675410cd08e9512d6a1ee1ee9731256bbde9b4566aa5149d647df6eef5e1eef2679fafb90692ac6215ef629f2fbaee2481ba00b3e8552265f380965f92ddef9fef4ef2d3b77a8ffb73cc0b9675c3d77a9652f1e8e7bddd755b01532b9dab14c9fc2ff49c37e07d25a9bf3adee26fcb6f2c68bb51561e630ab8b37837f637a3e2689870b8e977eda59a93d8ad5749cf1469fc7c7d20bcf735fede7b8b759d9f48915907ec31406a690878c63c27700c9b8f50d049f5d9fce4f6bd4eea8299ef665c65538c4fe3aeb93293e1e8ce26f452d2c6d30631fe1b28bbb1846b95de42946141d44734c8235fc6c17868b350ef343f05243a5f700e56068b85ed2cfcb07d83d46ee00ee25febfc613fe9fdc6e42d65b350d6b018e4128cd7b9163fd33df2259db38d066491b04cc7cac7dc3b77414327eab17a24b1ea2ae6b1cc3fa511a2a6800a6ce694f6d521e4ae13b5d2f850f4cb9017c8fc73796c72710aed409fbdf9cd2dbd8a0312531ef40b9899a10ac1e950d19839e6a566ac7e69d639e9229a131782c1bdf7dbbcead0e3d1b799765ede6658a6a8c88a82a7014f0e9bc5e535bdb07caafdbab4dc3f18866cfe80e0589874a39fb0f62793946b60857fadab34b201327b6e4faf88d7e84f27a5bc4c6c63f70b4f6683e15f5c1a2dd9fee465a606d833ce7577da91970ac811b97b0bdb92b15c68d7425e0857e84e344c27f0bb9ec3b031b3ddab9d1e58665d2402085866ac39e6674df73bf21c18de0da3f8700f230e1cb0df2bb6fb6504fd2ed981d3225d372d75dcc54110a00da6cd66db86fafd326d4d743c7b9ddacd4b516d6a0f21e5b3302ba80fb83366bc7e7154e10db1705c211a5958411755af089b1be189d0ed9e94e70b200e3ded256f924c609471d2166819025882568c718c58f9bba18f82288e2de2e96f5ea1e2755c6ed4821278173816b3426909273a02e9d5f9df285124fcf99799472c78c8ef5493c918de5ebd00758ef107ffbce34c94c8f084cf879685d9f0919ab0131f00e38f8fbbd19d54b6c9f45c1a80fcab86c0c401f3bcf8f5a57e0167dc3f5e575cf543130d5f526957d1f7424d60fcd3d871ce4f6f7f5b5bd58c669d698db8dba4a9d5dda3be5a12cba8f6f2858950fbc91b84479149d2f20331047eecc3ce07a347efb75e53b8bccf495e588d1fd4304d419ddc384d1344d31f71986aba9aeb019457bb59d99fde26cafb7e72779292da9303a33d8833447530cfbe1e96fb76ad3e55687a0911d62d9b8435c74869857138f920952238c4e0718e4a93208ffebbd90dac46a4f6d7b795dd11ba9c4c9b2ef2ccd803107b49efc5f701cabcdf0b2b7db631311a780d3b38b151c4a4d079c160c99b03a30a9afe97f3613d976eb419055979129a7f19afada077676aa3e8f0c7765c15781e0fb608eeebfecf41c32aae93d538a100cfcc6057d42c3fb23ef63d2a6b71c3328f51a1a103bc07198e9cc4ece678de4e8001f192422cbcad68b459aadaa9c7bf778f7bbfdf56c96cd2aa038e9c6c4bac2b1ce1d3e5f87f36072ed0f40fdd3d8697967c3bbeb6788b15ed638e020308b40df04cfbac05d24f6d03f78c0bad91c99f1f47039fd3f11dc76f2d9951a40c9c0926a7b9f311082be1de42e2df1c91235a4698a6e42e4c668ca4caffa9a1a3b1b9f63d634c823541d1dff14c289e7503df70ec75e4e3efd109a6aff2f78c78d8b185864b96d2538f1e6f7e8f40c4dbb97bc3941fabf48abe15eadce671aa44696b88710f55f41dbd69c0583db875bce0b385f53ff768dc01d6fe1a048f86116285776b1cb05620dd8acac31ad93fce7e55417862fc4e6497e7bae9e52f75cb9afe5f52a6bf7e7810e0dca5f7e36ad56fe953a06aa6ec024f01ec919b767fda7e332ed7d45dbc7d6d8e84efe827ebb0119176c0a686e17093435114eb6e0ebbc112db2202127ae830f5101589cd4d323781b75fb75014cd870d9e7e14a6da975af085b3ff9f4a471c1b2f842a21daca19175cc98e761c9ccd41e5d12b4abe0f8fc98343125b1fd2d6e106800add5cfbf05cffbca6f8bff30c330912dc568e8473acf4489f9e687abb8146f69dcfae331770a50055ccd334e77ae197d3b3936dadb8fa6c0647c428f9d075ef8b829b5a3dfb8490c3b4f4c429efe4180b3817283a439a9704368f1879823d9855030cd225bf23b5b2664a807442259cb492b0d0b3928b774c7369a6bea92687f9b133b6daadbd04425835eb5fdbb77dc2ae9103ea797a8974d634f40e766638d5acfa1013c491ef84202375b0a494115582c00ee8c9f560e01722e8d3b9d2f1a665e636ea0f4113e50ff8ba64b54554e557e23c01c211d321af93816c06693bed1f09ec72358c9cced90aa0cdf8e344fa519db916d85feb0eb2e8b0f6fffc33fd78ee3d60a56dc1fc1f8289fa4941ce4d3f65016cf8539994dafcd31a042c74e6e473d62f024be09987d2798379ed16ebbd2522c8a8e7bade5b9875663285f9dcdd9df590a48800777be2df8de1a0d4457deaf6839c2adc24e887aa829c73b59790baf57516b1e98f5bfed69e569a91530e7fda0e41c307d3a19ac18f26b5c93277b3419900aca76eef6c5162e52e6435c66c7b32c1d067a41c8b86ff8daab34b5d7982a46db43b5b4a68fdde760b26635b6cc2f156b322a155d104208ee22e076e7763ea02c2ca190b6ea0282c0cf9381cb2c8bb28ac7fb5c611c267dd52e17a6962366baee02a8660c3658a24463290f8bbf4c2839e9592dafc4ba849ce17cd8ad2c0d742303d9a2056350d3322d0f00d5e0ffc2d36acba7b5461d16b0b9d3234b4b226cb7dbec9bd700b87c93b7290dce40ea37e91b466d9637aedb0ef6d7585b31416c2329b636cc249c11b3566149efe3385148b96cdd40686caaec702e4f975e9e6ae1f542aef86c1200e415ec234956661e1b6460027a4a0ccf7cac3f808f49a0f1284115dba82e3009fcd1b2725c4ab00ef787be47ca8484b068d181a9f1d24ffb884c963191d3c866c7b8a178f3c6ffa07b8291aafdebc50060a3a35d6f793294721d0a84e0de3b09b191c0431ceb9b6760086f8f6a9a6862a184d13352e8585a018daa5d5f6c10777d66d80fd5cce982fbc9275b724ef3918363b4ed8ad8912f5c1accf8b2bfe4b7d2f9985dda70706317fd27988d493e126f4575a69418645684a9a117f04fdf5ad6581dfd15dfb534388948e75e307d80324f10f9188c488c0a930f83166c615d5329359990e0bb9df991175ff6845379cce92a369168d02d279102ae0fc6e10a6b01cea2d9964105302742a090c21741f0bc073e023ac1299ae6ebb80feb9b6e1bc106f0ff13b6fd20e24f048cdfba1a83aa8fdd4d3f87718807bc9eacb604a74464213c6b32d86bd964b23d1e1db25c0dba01f2880f08adc0e8efa286225ddb7b8e30875bb4c78e8557fc5784f44e284cefd15df06b22e8aeaae671b56a31d6c6ebcdbe3903e015611eb3fae1d6980863f9e301a0fc0a8cd12f4817437b26a674dd5f70ea9979676bdbb4676bd84cc4210b9d1e9a5385f961fcf679bedf0fceb14e86fc59f98c8fb878ea1c3b319a09c30abbd511c23a31e39478e82944a46c032aab83502ae3fa19ac96d78b5820a4f9a54c519fdd5751ea0a93609f9f1a99cbaedb7e897ff5d4021557ec2b858b4ef24f7f02742439822068eaaa2ab233b93d5de9ea80b7f73999cb4602d097acea3447a4923e9c54e0838a80d04fbb7c023f504b30e6bd21e8a40cdfc472900235c8349cfcfbdcd86dbaf144c3336fcda7999f714d422f1c6d8e12df2d9cb76d07e5e068c4d59b37ea7879270c0408ec28d7a469ad52b785887798126fb018d6789b3cdd7018216a539201ef6a59791db84e229bdc2d8d4f4aa43586263c51b6d76fe141d845378e854c6c6adc94ebe0dd90383de4b4debfbf90ca98701f41b1ccdcc24944383c3724054adf664c30b5aeb5a831e5c9c867919113e518274270dbeb0be694ea0e867cec69ceae2fb7749f1e6f6d5faf6aa089fd4d295910f4f2fd005492769571536d4355133a81a778e890d3e026a01d164d9cb962e37c97e938bcacc2b8fc32ed4eff98a3f32a2ec9e0381859b1d9eef75435efa6aa7375c04db51549ddc17776e86f7cb789d30dd2dfde642eab63e7a11bdcb459d2d7d3a9cee37be23519a1fe307883f77b1ec20ef000ebea6891349e536c4f2c68779c9cf6ef8e7f0e86af2cfd439aaef8975f952158229102a353341b620ea1592552519c4b541631c9b7f2ef34c83b2ac239daa275f0a57f8af77179c07c0143f4f442b8b9596ab5c281a4667756f78ed4c964f5d7efc497a894d1307f3a739fab39d6f07ca33dc712f103c57a3825be1ae699dbf1406e291b3bcc5f52db5ada52927c03881f2682c1f1a5b687e9cfcde48453290a5958c3ab9de9e2247afc1e9d0aa5763133916e33f6935034473fc7c8696273298c25b80b42c3ae8a9ec812f86ba924f66dbeebe65ae0d348043700d01381ef4279eadb5dfc932d65470ba6c85cbaf65b8f04595eed9dced4250f82addf32675fb28d3ffb09462007cb59a8b4e34776c8a36c130fc09008bb9069543298ddb30c6ad0ba4403fb2b0cd6804f3ef6b1d01337de0774b48094212ae036a0471a240a1f4b508d0661b95181f262a17af975f6e8685981eaf7e2399332f5bb67c37d5ec09157f2ba146e68109bf933b4372280292be0dcf2c6aad6f16b996c6baae6ebd5fe70774658ab369d08005e0f4baa50ff5bb9b86adc3a5185abe973ee0e2d979796892834200b863bcde77be266f434c402d289a644005627cfed06b2a1b30336147eaec15e458f89c4fd9dd008d4c3bd729f9f2bc06c164db85075e3c1a65d218a88cde50a7508a07638e73f5351d250b1c416a615a862e4fa56d7e4d1257fdc377d65cabf7d9fbedfb4ddeec5af3ecfbcf1da743640f648f5fd916a6e605d2fceeb43908d3616ac107473e43b442b70f4a5da0a8a821fd2402a5ae5187f01a16e3cbec14a82c52f348698b56ec1ef9f261a2ccfbd7ed75b9128ad72181093a160aa0df510eccec7c483b1d9908790f29f15406f9d6ba34da3d67a7e0de2b278c12d89ffffafe41ba7c7b3207d65ada3c00341868558e72d39395a145d5a7c364096a173ef2aa8672088c62474bc396892290cdba9665167bebcdd971e6a05564af8a84ad77d0a51b9928798ebc7fb3914356abe8aa2b49acef8f06443ad9d5d503c0266d9ebb02e18c289aa3e991ff10e8c53c6c1b7e797f9b5e383dac898af001a1188209082c4c30486d44415cca29b8fb0384c7a8928f71dca9cc585d9317f546b537ab626b5758ca5eae67eee46d189131197bcdd82a5f98d50197ea3402c0e48983d903538839f36c49ea7651e5bac31a623948b9b831a5d27db18c884ab7366a92efb23a15ea626b233735067b81d0cd0e73ec1601ee46523a27066519a70a38d6a59a4198680c83b176fd38696b30ceb8b0d2e4667d4440f0a960570aadfaacd1c58650f0a4e743e716ba2a0f3c2e58171a1059ed5e3f18bcfc1547e3c86fd5eb71fb241b14fb97b8bd7102323f8d57ec52edef74bb2328cff10ec67c83e01c633fcf24b54c1f07ab7cbe6e31013ddf51a0316f53b131a935ee005e2d3f37e72ef45cd11c8c50cc94a118584b6d3b0246480b3cf8438a9bfd98f169b572fcc8116217e5c4b48d5713eb4288738d516b1bc137231dad232ad5159eaa01290586b5f53588cc58bda8ae6748e96f7dba5ed591bf5bcd7ab32a8b72da2b209888be1f66626198e48d93d987f4590e525133fec22ca36d116802c44bb4caa3deb203543ea134825c881438b0099517aa67fd108d00d661feb018a02ca66d94639b999220d8ee5e085a66dc161fccc9e2cecea472ec324768cdcd4a38a47ad4141a1ea3ac6ea031af42ac84eb915eb9af1fcc5f15a19b1638d9390989669ea69b336d5aa01d88492453b0d681cdeac08b722ea8cc17d4135cb6ecb13a2dbb34f584290ad5ccb2bf7349bd6c8c723c26348a3085ffd0a6abce6f9b20d39c05c1ca45201feb636127a62337bdda540ed5bf90d1543a70ae39b8cd4f2225443fd020f4f44c2dac0e0c90d1ff27bef90118ab21c19df9ce6b904cdb9c9b187d084849bc5d09489416a2d709ac83ca9f590a762089e198d48ce9b304c0f9973cfcd4ca571e02856903ac93d160ad04ebcfd96a3ee28f00042743c18939a531dddef4b5527e4a07c56cc6bf6cb3e39ac189724d817afc820a519d3450099623d3d66acd81a7d7d9d056ae18cc8a6095f0977bdf8d289235440321a1e81abc6e5e8b4534413a40addf060d5ccde470db94271a76a16f3e788614e0c05f947bac408119bd47e2f4ec6d42df44b71a00be50985315b17c34e4f049f3eceb808770a1354ac12e636996caf1ade8c94bb8bdfded7fd1db2c3cef9f77a5698900049f9b871593f148fdbbb71aa958317b211ce829ac9006bbd3e4186ddd04d9d962f17958976effda58e0318af7bab56119f97e16640e6a9a93166e72b001396bd6f0c97f3a9f6c5ef5043f72f44cf5165bf0cc93338f39ffce69bb7537a83b5892a3091b41e6ef091f1d3b936926146d9eea79c6b23bc85696f7491701c9341e57b137602b6355927dd73b22a2ed1f7bcebeaf88ffb15e51cda3552a1f85fb02deeb55573cb3280004e53a00a72de4ec7ad3eaf69a8156523d925483ca856300d8d86d8a758a04215b07e9fbf01788f08dde7251427cac1e084c05245294110ba79a35d35367fc74278f60603acf165d7963a642c96e0ba1f180afbbda5b556bb12b4cac23cbd0e5a222b7a2e32879c5378f558a001a23e2771e8448a86b661227aceb67aaf7c8c52a32e7543404514d7e12fc439cfc1d78574a129a9290ff53bde8c9521ac1bf2ba321efa6da882374797db5c9287628a90b70f3644292ea41a06e01d1dbf909afa7cb406a79ece2aedb3c20406bd0b3c613099395f29083209ae4b26842f6a0de2c98b091d0636e74f32a25c8fcacbfb796df5fdb18263c915ca208c43ce37670bdb8e23cf2b12756b57faa2504e9d5d2088cef971c9f9216f6f3232ab7642b01cfee358ba64246fff00706dabb2b04b45be1e6e5fdb75d2752f593a3a6fd975d26774c657389a81c06204b2c4ad3c13028bc9baa5bf85c8a720827e4fe66caf8e0c29ba0898f22313571fffea5c6297e0b2704c15e82a597e2395077ce2ec4fbfd129fcadf06c5bd423e9efbbaf73f2708fc46961f7c0a948ee24e2926af4151b41ae2cb418f8a3200efa21dd8e28b0c86063bcf162daff6ee4b12c556de56878b2d6a7e455c50a85587511e4b93d3e999255927f9c1443121258399ff822def75b99050fbe71d0f3b1aa54e47bb64eb5f9216fee66ad082dae42abdb97cf1dd1486ef49729fd897f067e633c4eca5554b2046b6c8bd08779daa77e913e4aa6327647c8ab8b7218847825e91b4605dc99f6d2ee0c9f93b29889038ccd0236d3de8cbfb41520cdd85abbd7d6f1361430e0e1b4b06b3ecef3501401754f18b04067d858bf9d6d36430ee61505cf5bc369fb9e4031b306891540f558e934385531a7d6038df5b026c2d8c2988ea8a3f1ed770aa0408efa0f5845b6fe68bde5f13fedd86e20aed9f76fa59ccb7b89d2bbc5322c1e009fdad4651fae4aed53f344caf8304a8b1f1760872b9cf340a22669ef7dae359d04a844e7026996c808101578a3e8d57d0dcfaedc384d418957a7e8bbb83e0f5f179be4b373b908a6a5f9113e418e1f443687fd057a318d9498d381337aaf3f1d1e859a2188892b69309a20070ede216254315a7d4938224b3a822fea4dcd4c0e1314df43f27fc1459e18a600e475cb52e214022e30fe90627a327c90ff903f697eeeb0e5753c2a63d13816d83ce57e8e118fa803337d2120ee4f1072975efaa493f94d72275ca7caea24930a6c4dbe951d3f89d9c8052141a71a83b5213d460829b3c8d1730420b51cea3d4f7d477f6f37ed50cc33cffabb70f2692a7688a27474a18373b5a8d750c8e529953725fd8fd8d40a578ed99a2691cab9f6c389a0f337b423f1ccde067705db3aa636e11807b601afc5430a2a599a58574fe9594410503b54cb73dcc2e30f5e7154d3669f99d633e1c941bafa10f7fc4776f1c9cdacb31caf1611e6ee2657452f8d3e142e5fef41d19297757f540af741c0e4016481fc2ac740d983617cab1a1dfe858e5e387ca2be60478b12a21ef0c91f67e6e3b151313caca2ba1457062b9f9f22c4a7da6b911eec273da00d8ba2d443b110b446b9ecadeee087d595ac65baa3b5bed644536ea347c451490ca71f77c8a2ff6e0a5d1635c8cbe17fa3eb844a9ea270242c580251e33b98680bcb8a0f1fbe3f3f2d6dd028fa50d9f882721634d7c9d35d06c018d40f6ea403101ce935609ccd9ba53e12bba09a323cd1bbaff0b35f07608c8cbc8aaadd7375157d31765545884b2679ea0b44e33cde486043f6557369ae3e6d0f343a9a42188497ca787facf176fdbb361b36b3905ac6d8a339598036cd4a458c2ecef4f8d2424f52b8745093b1dec5c8dc68a0f2bbcb66516735567f4aee515f2243846e46e545b6d5186c71f544d1ab8ec9d47f2b87f6a57d72ddb9309a272ed05fdb7fb43e929fdf29ced441cd7d595b2d33f11df07b88f2bf2d17cae83bce025829647ec1b0aa91862b7f41eaf1bed2c8649a91a3039ea2f4a5a4815eb946905547998695ad9a6f38a349330859a59ae79147025b102ade04dc07dce47f518e2e49caac4159decf9a1952a9a51db4107a701138b60c610a620790b20657e030060bd9679effc5df6b20735f057eb6f64b72137679ccc18cfa166a31a5e39849547b1a2a7aad876bbf99c82cd19ac0c254f1046a942519998fa836344140d5833fcdff15a99b6602143d05a35ce444755c847f183d991ca8ba3fc63d48c92c3459593e8b26a13065b83ce685b53c4352e4107f1e487dabf548249434c00e71b5a33b0a81c1e41d0f09f09f1a2624bde2863c7a3f7cc70c917f3b96da07a01d3fcbfcda7f656b80b59abdc3ca0111b58714c755253b3b43fa2b320cbb681999245f42b86f1762830f1a7f830bf3ee5a07a23dabc663aec968462bbca93d36d123d18d5ae8e79a5955a931eeafd9678cf2040e054dc0519a5ca56b16623b2895e01f2c45ec2e000e254031d193c5cff84a2461f2afcebad71635fdcaa13e42951b4b66d42e12f75aa24382be5826e589d8b47e111c762850495612efe49b47d4d62fec5ba04bb80ff55286a5018a7805e80f69cbd97450b51c1ae8acf6122f0524a8bfaf40e62aa5ee671280518b36092f9f230c1311067eb1e69a9c0f2461fdfad3c2e65796f95c4b60b4e4001180ebdbc4abcde958a055f777097c12af029b031f0c1e722d6becb4a0d025f4c4afd5ccb98ee20c9c0d5f0f2613e4fd1244289a037bb5fdab53958199b8f24c1db064c503b2ce193b7ae5e37d83538bc21c01c10708db133d677f2b62a5d0b152df13e5ab8bb64d10052efb5fc2c59eb844f50aad45d732d67ce8a0451d798670f31d7f8c63639e5e878cb066cdfeffc43dadb3c1ecb437b044cd69509edfdd855a822fcfe517bba6fc15e8790a419ede33873062e24154de84fd7db63fd521f394a5e7b706b16970281c45c2f505ea62e5635ef6c7436c3670d28e814ff4ed36772dfb52622f931b5771160828f752afbfff475b9b7049ef1262183c448dc027c5332b186e31ee4736499842b56187df18e8986f49f0a104b2179842cfcff6fb9aed74066686c2ac0f224a9ef8b30f41c5effc9177a4199771965531e15adbef7f076a3179a7cfa41e06c36579f1267fd924b410b6850373377496ea9e0d7bcb1cb3113096183be2933e7ab20b3d7fb2ab7fb679e33d413af992735489703c6946a47300acdc22687e460ef8601593d8851b972dc279142604493c649fd184b7ff24c056bd7bb0b72ec937610e892511db69f781eeb7651309bb5c380fca05852c4effc0302250c596bfac80f19805242388f0fd4c80379ae3f01e63d23c5066db108472b547fa734c3d2ecca5fb600ca760d3c0d02fdcc670d2b0b719e8c9b087fc56058ae7aa091fa3366ac666aa11dda6e10a992d07fc88deeafaca928e2078939c852c37e1a148bc3852b1f232f5d80439fa10b90a5fee52a3fea1e2e9b41180db8a6400f9ec32389d2f73f77e8640d99d6cfc5806d0f6a26bad7483528e6612ccbc6447b7829f91cd19d18e01b2cdf9bed303b95e5c11241fdc678e70b884f84d46de4f72ee1d8ff35e67f60024da7cbe13224fd9fcb9827d3a0c8b79f92335b677517cfaf7375a8a8705ba8d01495de830273387be248eb93005431a8c42308d9dc31ced755c5df150b8c570d9fa33f357088306c925734e740399b526c3b692e20288f4775892e56d25959cc58f623c4885c9dd275b557fa769c6065f426411a6a456726cd9d24090c0b617b27c601ae32a57c9ae0e6eba863b1f386692331bbe232b46d0557d49b117049dac12b044726d225263a10d72811aef3aa6bcf86333321d65467f498cffc059104499a35f6d8135f0eb2caac984576f2ce1669fed41f02d542f5aea48cc144e6f711bd1d12fe6e2334059696e4ff6c502e0b667789cf1be72e73aaa4af5cd9fa0430f1d3c321007c5304cbfe64130ff26a7feb75ef84410ebe90ee7d04c728ec8188b505e72658744149bfe4d9d2c2169301953ff06e608d73f1f93969562231b0b743d89e5c12cdbfe0389b442e3c5414dbc4f510033b82207937df805c2573a1cf0b3feed36926bf98fe37c3049f25db8781242af61715f03d7970a1530b3516b1d95236906fc82fd742ea161e3563a04996f056473e5870e87247f6011a337c8291726ec7a568531bf76e8f614e012b2675e0a0feaeffef3cbd040fe32f29117b21a9337f5ec495e2ec82d49842b2113c1ac4dc1e47c5f13f5e4de7615216333b990b231cabfcc2240733206a8199b04fac1543ed8d9b58527da435b93ce45cdea1f6fe763bb3dc0705ea8e70e788b3f7d7bde892bf8e93252a2b3f54700cc31d25e0763d509997fe89f1f5023da580ce58d86acaf58ea8632743b88c76f82e687b9244040b776284d499f209c29726614635dd37ba61add8fd264d0eaa8ee0b7d4ff1bb46826918e191c6bdab1545a56800b2355ebb3dda3219f1f642184018befb4f082330bf221c10696068087c10a8c5472aa1db1f1f1ce14d2912cc31a9987b02c116a411ea37047af78cfcebd49d2187e4d07c0f421e649abdd5d682892674924482f177bb5b5023162228ebd8a53a222d816ee5cc4a1f961569e5c06ea02d685cd01a7fc90e0d60a8d26a4d98044875b78b39189e7cedf28b560928a268cebdf440aeca841c1edbd23b34f81c4c7d6878fb78041183aacd3a6bb97283af513e5cec19f71f947b2c61f064e46fb660851946db1996320e69b0a5a9c7267dc19889e3d19ebb61265ac5f930c36e57fa0ae57ca1efaf1704b238fffa8ed6508c6b571796d1a4cd22ab01b277420e1c43bee40a7b7fa04e6c3dd10bb2b455621d6ee50c19fa6d2e7be65a17ef8cdf4fcf07f6343c354441e4466961dbdb1595a56d02b22b93a1e2b9e4cc9f44c1c7720f260f3c5979e49fca1bb6dbbc541589609081085bf5a30b9e76d5807d2b55fad48feabc4c693251109c868c4be251aab5f1ba727b6e6b2819d8161e7236096046300e3c1146bcb153733d3be0401daaaa1ec01973d6811db748b8ea36e95714b413295fb147b658873a5b71356e5ac9b152adee127fad4f989f8411631cfad92425c9a0ee49c7dae23fdf8bc2d55be9df6d2cecd3c8d2722a0cb392ac504b8ebe4531a60ac7f6f3730a6488267399db172f5a8c8179c425d0a0819fa01aef2607620787535fc9a91bcd1e0c8b1668432b918d580f9dc906f5dd5974a0b8603a811a49de3fad8d0353be5c3abaf64477ba2f02e08bae5621483e6746625a81798c60f466c852d9a17cb2b1b44ed58760782f02c180bc77502ec480f9358a95291f0e63a6a239055cac2a762ba0db06152d2238e197d7cd5b468da4f950d8f530438d22f8e052bebcaf8421b654fff2634449593edced35faa7c44def3f99d20a35f0eacbd479e4bcdf256b02c694ab5816b1088f85fb554b9f1d85b74e9416c9535ba8e28d166412c77a55838bccfd9650e46d73807a813645d75242763dfdfabd8d9fb543a1d5905812e1d2a9a75d2a3ad8743c773baab009777e1afaaa970b0b101a9c36f6c8aede02f6219d98caec7788076c438f00a87e7f809d39449f96f66475d1c21282b5c983f6a8763e4b8356ae0eec27c551d71d15d6774768d07d0c1179b74e0bdccf4feb3bae2d19fcce886c4306c2c7d3bd0fd1ef2e1b48e2453d6591e55121704b6ca220172163148fc7ffed5193df6103dc12e3932b2254f4fd28d66937c5561dd2829f7dd182be743527c6d8489a6caabe24d4cda21e93ea4afdeb3a4de1176d1437b12d870adeeee01fa67426b991d6bdf22d028359555c07fa9f449fb5ab37c5f028cc82286f140aca7858327d545c7d6111c35b218e8c53be5a922edc97b0dc023654733dfeeef8cdf57cd6c1220a5c633e58d6b28430912f9f98f41632d926987b2146580bd647141e4533c5e8cfb05cfb0c06f92ef8f2634524ffbd18da8c87a5db6eaff322e3937060b22d182e5204cd5026193d949a725e167dbd4e1836d1fc685f775e7ee13118649de45e6cecdef147e9877d9f40f1e7271646c33dbb7929b00b90125e54a05c74d96d0bffe5d1d7100f760966102b0c8b71fde1521c7f58e8c5476c334f20489afb8f66f0ea06813acf1bbbe3d43ec636eef46d64774be1148558a08a7eb5c526a2c1c872529a38ea6dba38c4a0dcc259ee566c8c45691650d72b0c19fd8e625f8d40839111fa605add53d56300b4a1facdb092593cfce6aa54ee43b4ced388ff88652e1a558c0c62b3d9eebfa20c3a67ea5db7b49dd860a7f891d2f3c32988cd537641ba7e021f48967684301e60be7751d49f8233d9d5dae543d0c50953c6876be9e1b5e7887cf4e9d8fba914cd6d5ffc3712724c4e2332e808c9c5d6c24d4d322657c284fec0ade482c934304c7a32bed65637f76bae0b940cdd8c02389f319a9048331b5d9a7cad1c91f67daae88b0f149a21905a301f6f334d2efb2719518c3baa138f4ba0e813714c39826cfc8cf8946398b6a1f771c1a75f659a121d330b861de5b1a843ac91ee7c511d4567808f7dca1efa5b9cfc4b6cef57bf0805111ab18ef89229c450ad5f9c3e82cacbc217fed18d64c51f211c64f3ceb534180155bc612accfe49999f3b9674133ca0688808f3814eb94bd227ca8d1e2bd2c8905e641a8f9a99faefe1c237018bcb8146fd414c0b7c77d3b3d2343419c58f7136fa9404a73f419042222e6806e97d17906ae80b5d54113bdc9cfabc2b0c33df58f393c06ee869f0cec4fa021fede753f09cde3ee2cb60c97d53f03944caa1efad2eab73f88394de4227445aa90b81d8a9d109c69444cc655c9371ac8f529d6cc2ea6e723c5991207c879e14b04cf5fc391211be1499e8adb7e05ee89ad43d2874b73194bca875a0b58392cca2225e90dc9e0a8244f9ae690d631d2cdaf4648ab0417869bf43675d5aa03bf1b63a81392978fd6c343bf604335ba6d854831ce84db9474cc70bc7baa770f2e6a591b8c7246b07340af04f8a7bcaf8eb0c1138102a446c563519814a8b15098f54bf0ad43867dc55ac9a5e0f61f5dd12b00cdf38b2429e59c8695927cc09f2409c701c843d4958465a04b52fb0d526d6853aaaa84ac7653a1a6300cc267c74854b881039cb7e132517777f8cfd5f19bdcc627f9521f6ef5593edfe429179aeb2ca5da375568643c77fea504fc07e471fc2c132d9809ff9c6c7a0d3331527739e72eee73046d767a4e2d9bc9a711c096abd769a58efa770d63176fee95fa45dc0c3fa88a649a573d68d4c06c986db44cf1ed6bf8bc87bc4f4eee6d343adefe0ef29295f72e60ae171a4c80c2d60c0a6daee5d85b0f32703452faed9326e62879e68cd331bba87092e28882e3c49baabc2a1826cb543e91bdffc2bcbe70d0c1566995ca865807c3c099342fecfcee3613bc84e22b9bb5ea88475d01b151989a26d1f451dbd70ca4fb774c3c20b2e6b91455716664a170149948bbd46d2477102d7235fe5b0e467221e9af3748088a53ec23e09f7556658efc8c5298989ec8b933e9682de24202446b879f687c2195af290e6b8967ad5cacacab3dd58bb5a5110bd591fd84d372752e2609444afb1db33ef3293845f7ba44782cfd4673416c6dcfa257c4d0810724fe0607b32f2061ab9b2c8bfffc4e986de31cd7623bc55740d40f84b82f421a89dd8f2ab9eb86e12bf46e882ecda12e62bb671edd1075e9658a35a8fb735e703790ac6090fcb21fc3eddd4ebd1dc563bfaeeb00f2df0b18a20accce13be378b3eab7a5b16ed570fd91e58c8f936886fa5975c9e1ebfe13e5678037d99eca18ccc69108e35276749677493d5a98788b1ddbcc4b77b2faa136fa7c6b81a85b77a4f32b4929cf632b50eda61099e26d791b226ff126c77ee7c832829509f0c7903148ec8cd51034d2141a87629e73d0f8b0e5c95d1d9771ac8213771660d5227a37f8475503beb47ca4c8cf8fd87315f7579d5e16e773166c2a7fb91af7219fddda9536a8b538a8b4adf06b3edbe23d6e01a7ce92460100e32d62d9491acf11b59258b9c1335a943147463bbae2c0b7244b17398b9ae8cab6b0c2c5fb84fca2572ad1cd9c004ccbfbc2543d8e0e42913126feff5c3bcba1765ce6dc400ad601284d5a0fb36d6309dd385188449954248c67e82570242af2959a8796e31f1e34566c9114012fdf9e0a12e429eaa2c5d085b683deee43af3458b85fe8b5f0a0697c84338c2d21646a5d41bc24147e1fa319845297e9a41e0860d7d61c20d5d240f5582f53b1fea723c0aa620b05900cf92fd3f26d5d20b41c8636359ca8e34164fea4d5cc1b647bf18569d73e12cb61764d3b042c31126546ea67243749b8f19a87042cb4a8b2ca78d2a13833067f6ce1e00e241eb16c366f36f97db0dbb0f5c33306d1fce7f91e2e0d3a2e232cda65f8186668bf32aa3dbc4987883fd0f0e7a45d06436ed559929ea8ca56041e9946f2282d2f3462fb59138c735a166a6f9b5e43fc1457d9a704dc9921d0debba2dc9e108d186340c03b4916b44078d8c8de3d718cb4add8f3f1306b69c72e770a8092d40b303232d9c51ebd27262c72a2feb0d41278ad4537777c9564f4c8d318b4a67732c23f056602ca11c5d6fa6af5325d229f651d65c4dd4b380957dc64ad71d22ebb96a4d5cca1084b34e15f5793f5517bebcd86d606eef0f03a6859da79554b9c504457412c8ae1c5b1cf1c28622221123feba0b75a7df81e8f1305b0c0f81342fd333059627174c21ab1bfeca65a6a8e7c9dd9e0af4bcd72f7a20a1f81eedf5f2ba8343e18dd50e8158664a3663a1ad9d7cb184316058e5d429fc03fd72ecb1d0407e2ffc1df3d2bbc00222ff7f288ee6998bd637dad43aff173479f5c670cbc12d5ef224c2d9e9ad6a9c0aba2a9602999c1dbf1208c878b464387db2c710b0ae51173340d8e86bbbe4bf8becef5bb89566ea316bf2a9a494edb4f7178ee3b1d95ff67e94e25ff5467b9612bdc5572d59e7d9a34be7ff5a6ae9508a02f62dbff681a7790d96fa1e3ba9afc9fbe5c616374b6279f1b1345aa51d6038b8a37f6cb56421f11981e152810600524ef3bf5e2ac6a0324f05809fac0174472309abda0aaa8171203ef9d0f90a971e0b98d23165e19d6f170519ebdb082fb129082c2fec6e0c27f4753a38097a13060e7748c5a5053444994b0870697b073e12e33e195503cd9933fc5c2785b49aba1178d6b1448ba1a9a2d9ea9c8c75e5d1bed171e5f809a1ff800e64fe4b2aa5de205b71597aea0508c6f3f527f543562cbe09e56276cfec2b22a6c5c90a73e1afd808140fcce9e5df7fcbded756c74a5b9039be4c53ecaed5f9d9118db00c97c90b3d848f3085547c55ad15561e056b8c51fdf70731f3725e32ca9b5d97ce6e69ac7424d749a78064f7bb154f83a01353f27c8e788dd6ccddf42fef5dd765a505942fd9a14cfdfc4ce81067450f0e076fdbbaa8b32c2ffa1ded323bb15e702f714abaf2e00bb3d2752a867153bbb0c2df8a21e6a29e4e8943b2e604674ea432b0593415a1935643108271e47f5d846832b57c647bd5560836c48eeac29c876295914941f67889441c7a6372247c49d4fd6671f7b66b25b300ceb21207d45359e672cf161aa3a4995724d0fa080d8a482e0c5735905e19c19b010da6b8df07ec11b0f2df2ab60debaf8bc8b6cb02bda1ac8aab154486f34f8b532c0041b2a97a60ef8e11112d0771525cb5c406afe48757a522eac89ec01bdc3122991fb1e5b22bf77f6f7938844f6c080b38d5475a9d97214ad9e267e1571acf0fc535ca8b6d5b9eb4ad5fb1a652129c957be7efc982c458dce5122dd75d846c52e2e454a11692621f9dbca76b4e6c715ae5d24db355477dee9e16a6d218afa96a002646d337c8187e9bcabb4de45b5fe26acadc925e00a3491f93c2cb5a52848e9114941edb7cf51fbbec6dd8174f12248bf38f0dcbe2964b6e0b8c7afaa06dd0bf7641202292deee043540ed573a9386e232bb6793e5268cfa127c0f1610c94614afd8d7b885776bcb1f8666b070e6b8a6b8cd8502521f8aae6adcb34c0cdb1cea86fe0dddc71610a4263063423e42d88b2388b88bd896479eb7ab267e2ef51df51229caa0a45b9cee64d5c632e1d6c078d52b756c54fa55504dac88e460671e68d541f295d7d162c4430b18ed24228b9373eb930251659269a805bf2824b50f655951ecfd84c30015634b048e8e1c57fef7333db9c2c2e82ee0dba9e23b0e9425836387b1ebba20adcd529185bbf9b81537d82bd0b073597944d5967b4e5cd6f0134775289964dc613493b038c044dbf49528722620647922a4bb3e49f3ae7a9cc23c5c37e271c91ecfdb94cbcb5ff22a242649ef39883d64b3cd8021d1606a5d08a3e1525a06595022882be0d1714e7dcc6e7035c8a98aa4b068a10f24463716d6281b7dd9fc5ffe158aa576f418ac6ae397d0663a1a5d7cfcb43d456089507d6ead177ab87d025370beb6f2944dfb01d98842e550db095eca97284e869fad34258011d3650d8f016b3e721b078f9d66ac4fb5b6b3bf765c13a58ff0ae9dbcf9dcd7b3e07ea3f9eea719c3e6efede95773687a33e1b4570735e6019117bf9793581a7855bfd13621fd900563539249bec806c8800b7491e2d2ada6061eb7f16bc6dd3f3492f84f33ca9b034a7623b738b64e673f6a13b26447f6b20b0fbe7b187083e6892b5251ed6f045d9cc0d74f09268fe7cc3e60016369000ad0952b27ac2068ae6a5d68046fbd9c61a9e22d5201fc51244837dd860b3a7433080d231d1c03653f23c33ef3e11eeb3fa2a86a5921a50f153ec296cb1991a1c33c487dcb82cbe50f1994d8ccbb031e85fa4929ad32c983ab43c8b808aa5dd8748e71530676b43f2f462edcf53e4e12e65a8de6467c59ef079fdc48d0cb26cbf8fc66c31c44b1dad04cd8d606ac435aae91de1ac53bc30201367c2fc048ebc02b147ca543c264eb0b675731c086b45a502ba310c996720e2709556f8b4192473447cddb62bf05bbe52f929016f5587aa073da6bc94b4aedcb0145483fbdff4fdf746b0fafa5a276deb2ba62c98fbee57b3ba15039e9f9a396c63c51f8401811246dbc7f3a4893f3e247526b3d154c1f2ce5fa13fa932b26f11f17b4740ff3de5fdc83ef44d42c153867cac049e153e82bed837c2c42da00dd0a16628878c5f0269656f1837607576c5d4f7d7f869aebf00258c5e13e41c0120ac3fc39ee0513380938ae60b2f0a1caacd788734d32bc4a55bbeb0603152b2603b491643596a277099815188b044021b1d26373e4e3d07ee06577c33b5752e988111f25c8101383c8ed70d3e0f7261ffb5587fda971779e643718ea55e3a0802556a3955a58fe8f065ec9540d0beab7997f3380dc440b6d95878a85b992101f47eca1b7a0b9e40c2e9b5fbd25345d663ff0dd6c1c1f99b96c995720dc7c121bf35d385f92accb033f9646d68dfb56c16b32fd53965a800e20c4cd52b0173fb2470de266228db2be0b2b30cfc41f68201201df442e0e732b8c0826e5ef5fcf43cde1c9adcc2e98915d968743f0cfc8a4f858769ea5bcefddf82a42306af5ea4ab5beaface6a845164566dd8051eb16ba75aa1fc5232cd6f1356c7b2bc94be4f6c66d7b9aa8aa19d991160b07f4d38284253375927884214f9fc4d2c99fddf5e7f08992c3a9119b88b095ffc9d5b19dc3409be83857b5e896ff273eb1bcc72d4bec03a9c27c2326f5698110c4d23977175eb6a8e81331627623276e2481affe5d9078e4c6dda5b6c115352ba235ef69816db9f074c18329baf19e48a7848f696d3aaf6d16d65cd90e28e75ccf0342e8b9cf1c9b0f502726cdec37b1ca8747ca3bb986a1b3547f7665a54a70d7c863bfe2294a7574f991f52e2c1a72ab86e557c683e7a9c2090d20d34f383bf2fbef8118d262a471898aed25c5f1006e7a780e0573e32184781d4e65285a020db68d849e5e693411dab810ac3629800466d117602c22d812aecda9195201cbf622eb14ef6d561b0d1d72305567a3c91bf5ec0da22b047d0abc97f255e45ae4d5650280a33dc9dc10bc37536b399f7de57c0fd316dd0e8a6e65b5bf151159fbf77adce8e89982d129af041f493afe6d0c114d5341b60f8134fc91a09f41a0781180f26b0d6a1c890f51919b0787fb677d6f325c8182b3f618bf9148c9fda19e0a3424a519beeab13b56d5d45a502abff177ae44d44f0a591e85fd2d6d1476ee8954b52d5d76b4c79d364fd0e148ac4aa10ebef90f738e0f17b1b92ee42ca00f1ef746291b69a31f8097679c183722be3725a6e2f5adc0e4e790380300c5122e6cfaadba289103a1a3044ce256156b4f12f80ebc31629c16b4cd6f6b232ee69b6e5d5f8c06fe912a17417d7166cf4bb7d802e2154ac86d20c40c29418c67813b4239d42897f0e03a70b402c7091d045fe9b90dd81204615c55fc65943f5d98594a8e688b537cf35049bb3fd3384e10ad37bcd9c0cac9321c7bd40dd0577a13c3ac86b3d74e5449f04af3c30fb961e60a2180889df60d44044e0f589304de994643c6e060990624e7e4001a27193bfb3a2e387791a541db29d3b608619d559650ebe81fb06c3511b6efc6d6ed7423686cb06037fc6cbd31bace6df742cc75c400cd69aa3c356d9e275ae733f763cfe58e1f48ed2eb3e6f6cba1b834234436e0fa804010be77916d84a1efde19bb8a368f97b056c360263098ef84905179e5b181eb47d43167f9d82848cf9e87ff9c2dba8bb3b6437eaa1f9314e8600b90328f41c8bda49d993121b784f12c3ca6198f1b0e8db59911e3ca474da10304e27de62b580c2160e7eaa002837816761e0f185e21e930484e7c6a2bb77152765884cd8f5b1b2e20732053101cba11f4a38c1c69e177951018be289c477e66898612783f873e27efb90658cb1ec1b21aa095075d3015fcafc10beac1492e23c1a532519ce786cf1fa04f7ec31c4b3e74166cb0517ff4d6049278c9900fd7afb367d78643eb02f57e0e3b8d3184ab13f1aa3664d508dc8f531620c737c1480fd5e88f3b68fbb7c0944583f59ce1dff8b016b93a0b6927330f78dde54846f154cc1c0c75f277fc4d6d050ab5db19f5465cc0ad8b94db138e456459111b404641d1e21968dec144e27ff78a3d46169dc908ee6dfd6ca5312d0b7d566c08418778e9ff107fb002e7d14d69e08da923f0924a1e22c23f7450471d09875ecff34dd8b0dd505c9ece73bedf101cd7f78dfc7f1313c02173fa266667051d54a87c57de3406fc9830bc0709062785baa8438bc494e7ee3da4e274798690319b3b11d3467f44757d9398a5315fe6d060bcf1c2318d6ffa95cbbc2fb725af2ba8bb3c6bcfc2e1c707a83139ecc7b33cf8979d43bb73139999570b413cfeedc99301f1bc7c2c64ccd18a376d2085f369cb04a189361312d1a93d40d3d8064bf56e2574e4c4553c831f8dc4c87dbcb647612a4c31d0bf7904c10494afa58cf9d94b3727510995b5de34f6c352f1cef9b7327cc5c77e19c51dba8692d53072809663180248d04011b7f516e10c6c389a871a37806565af079026c2c37996ead013df93fded96804b52f3e482dd9344247ab855d3c5f749af0454aff800813d70e115c1aea85ea8cb8547c1f7e65f8772b8de3169e96d2b210eb184e41ae3a41ec8129f6b01a58373e825045ff7e402d472a29f306aafe50eb18406ed1d8a45af9bb2bdf5985fe27ccedf5d08b260632f582ab8570d97fb94ce182819a7a7c515411f9017cd9eb69b7ab4da0149e9d2218bf19f8b1425f472384f6e4e14fa530fb9fa1f33da19a38e2d43eab245b05b83d6c1ae725fd4e3ec364081b152b67fdb77494908e8a9b4c5296b48c6598a2ad70fb13d64446b7710170f4ef0396a53251ea3b4025fc5edc9395af00ee903390019fb35138eaeaea9c0a1a8487d42018f7702d0fc285de0e6a8b35bae98e6f22bffb5d3603a1afad51cc5dd2f0cd82a1b2c80520901d620af1896f4d0e105ea4f6e32e842f01a5310cc6a89d91fb6cc9775dc3d403da101d02201ce43c6cf658ea9480c1995d6a56e13f339c83372e2c3b260bace76812888afb2c55f1f9d286447ab769215ee3a208edd11addc16ae56361673f81f5231d447591e65537e56b8d3c0135219435db439e9db2bad2d83d9da7fce431b478cb40c860c7e098417d7a38c3ff5a9087aeeb4c873013730b7463f4ceb15a1fab9896f10fbb7fc8ac1bed851a8f8cdea4d6f779c18d88605b925945dfb63887af8597262994828b23082e49f8578c07abf175d4f8ce4cab6c18defb1af91cac11eed41fee13efe2664fd561feda1dd26839167e91fa3b7e20be5c7ae07a27b35f86010814bdd95e42c40e1f0a56ea4896d6444d497c85e621cb79927d1a6e943245856eb0923706c1649b640006655d4c947f728ed8748b8ce903df8cff4b7a19dfd29d124785811e77715b10262112c52f2b000d51bdc62fefb12b390b4b2ad48f7a43306fb40f1a8e46b54268e255a1d7635837432c5639f895ea004f78207c5a5f24186530705fd4431d5134465d0482b070589aa1547a9809cff8ccaf2e2662c4bdf9558547cbb81d1bd01a27942b4a495505aae14f1d751c320dd79265185997824a436d3f17818050b6042c5671074db91463ded90536d661f4582163383aeeea66e3408806c39d98e61b68190f3eb3fb757abf515d860dfa14034e692fd4897ede16cf695b069fef462b0d311ca4a5e2f985a9c4a69d5dd556317c09ab051963d9d3351aea408afbd6d66d9b48ae621b131b4635ddd6cb692105f207f4cd88cff110797486fec1de7b11baca04b90984ebd47c13f8190c61de1c249571189828cb907fede328f62cebf2e5a12cbc56be81a405d3672135f3f36abf1582cdd72a4fad252bbc097d71e3d487b66163570529cb211b5885b457634445a67b8f49af9643d62f2ce81c1c452b2f88c44e716d80242f872e659d025dce89bead3a2a65930418a5672f5530f60fe291833522a6879932507e76fea139d272d54b9747c19f7daae92f489ad7ca4365c0681fe02d4bd2d59d96c1fe22297e11f3482bf5f2ea6849f4b65fdad1158469a43096633474f515d36b62146701f0317e53c1052cdeb9401dc469cb8f80d1f8fc47107b25e65b5208c9833d1000bd0bbae87bd06915f086bfb31e387df5c212946550d2c1b6873fa5cce6941c15ce452bfa24a837c14e4444d9f057bd418ba6a49f26fb3824583779e018aa80345baa95e26015ee089d2b250ac3f439596a3c2258447a632bdc6f5f16d9cd3bb9886400c5ce3f0c277f0e1489ed8d92776a3b0e96b79388ac145b52b82eca9daebe2d84bf5a4a91ce7beccebde18dc229c468c69499495c018b32c7dd5c9363d9e7cabfaa0145318399e0597b3b48cd4a2740630e1535d58e94861589830528be681570457a4047922228ab427b9dd4c1b33511c61edb65cbe0c27480c102e6145f965b5f720d3200012e691a86678aecbdc7eab39768937e4c7305cd378800736a96e134a4b2711e3c5ade640521c83b598317cbc1d58914d4da80b8b6a12506f43d2fb914fc096af5a8db60c5f7a229f9977bee3c332bbbd9973a73628d7bf3772248f8a252e66226eb39b513872cf6cd6259c2bab22e2bed17223c0c1fb920a710b58d9bdc52294d7f5895604320cc49d7c5caa8df979b2befb9faec1493f2b023f6c74d82d8ed95f80c66ae6dd3748effaf197a46033d1236ff82c3c0425134bfabe62d157fa1b3164c5be6afd18e67f9dfa153fb40cb2553c76a64bce76d906ea40e0953dd46c30d7bca3a89387fe17c3b3b7fc2563e0a1228896472bd3a5d86cfc5361d2cb0e1b61170fbe4ccd2c88c387fc1f7002383cc3ac9d37dfb7296670965211139b5fccd3dcb2e9394806fd5a931cf64a3a6007579d890dd8bacd498b0e4fe29ad484baa0aaf373b132b2c20764a89c976296a4aa0624b624fccb971b07887750a77507831ce0260c20830d8195a4d155b8551c5d6aa03276d4945ab552dc47733a3b5fc96cf2cfbffb824d3b73bfb842ce0c990c88efdb22eb52c8ecc4fbc0fe8f607316440ac5ce72d8117ac246745e7406c12fd4826578d6f7b43b067af4d69441dddfa05b3c92e61fcfa2e89501811fb081be1ebf27d0e983ce9f45982b39f4e93cec2e7820c778f38810422bcaa976a0c5f896f627765db84b1d5fe83a30484fbaffd8337194d65b166020fd5f807a65f26c979c2dcb07aa30ee9250f16b65fb404e6889be3523d5a209ac98a4f3e7379fa30da10c4582a2959d4010b5f02daae213197d7b034f2e8bc1a99913717e3581700367a0a95472cd1f3baedef4fece20eb3e4a75739a6423dbc0715c8383f09d34e16881d38251908b9abb63ed1674476f431c2883564251f4d5fe02c0f1a24beb81710113944a14975ecdcb4ba53ccfc8baf9061c1516f876ee991f911f37b0532d7835ae780ff1499984ebb96fd533ae210019181e40c75570f1b43851a894206622b2b26f84bf06d7112242f234e396942c60eaa79295032077940eeda896cc66cbb9ce054441a5ee2c4da122e21edafbee0c9d35dfb6f92a61a45a2fa196c57978dc6644b62fd0b5f5722f6b777a586644c8c8e253830c314272705a498e138bdd090ee3d4bb328d71c08ef72b5fe341d029cff3a2257717163d9ffd37d4643ba22e9192cc2cf9986bf26c8037f175b11511daacdf913fbd9150b1e7b9cd2ed3d6680a9a2bdee2bf91f080f201f5e984b68056c5804d7261663bb8030c2883e7ff3b90b88159f61690883a0605fc41b724db8779c4cf657b8d7bcb784a35dcb0d551ab12fa9fbebe7e32f65cd0885a4f42c477e7b308951d0c11af81aec91cd5ab08bbb8c4d0175ca82efeb0b09d686d8af03ff7a34207cdaf7cfb1b3779fab2fd3e4c81c879ff50a2452228b850a29c6f8e7fd899cd680f16239d38621844320347bf4bde73e8e3c77430e198ad5cf6b0886294cff0c8ea7e977c5cc5052428a207301ed31c83c6227179be293e15b2454cf32531965729b4b5d4277b73e6f7a7978905f4993ecaf0bf680d0b21fe38bb6c8c3f560fae4d1bc992c29da8afc88f1bff16d07723ef044a7b0870f967c9f02208ab01f6de6c168e6b43610c21dc1b511c99611873559bd74a4fb4be4d78c9f02d1a941586cf210b601c56aefe52c1843deb82d85e23930b773a8ee944c00d9229bff074801aa5fa996daa8cfef1895228c7c1513f91852cbd608130ac3c2543e1759f654b49edca8e8de05b38de4a670c5c5a66876509f9af79eb9db43b75099e92de0c1358f73ebfedc65b8273377cf816d328d15e61771a281b5c75e1c22a5c1bd253d14cdf648049e17ffea5f58e3811ca610da19d22065fdfe011ff8cee945b97110a025fbb8b5103c450648e8ca9350e619ff9b5c4eb0e582594dea6cfa6861379842ae98d113fdba5be12b21ac8272c5e4bbbbd4bc304b3d2fec1540a5112aa39650dd7b61e3e1b0aa322f48af9c03ba4720ac208eb3f3fb688a2a564b00cced782178f9d5a1b05bf9ef664741cd89c74ccad8902c2225fecba185ad58ce1391900be415a823047b74594385493c2d9cd81fe117c2fbff7a8cbeaa4e86d2c2e5936f6f931bacf794c150f7034e7332ce6ea6d661c4cf4147c35e465578cfc88906dc487e0fb3506ed5e32e11855a8e6cc0aaeb85f8fb466c584e0e37a7e364b79e25261a73097a16c128a2fd3407095b1d8c5ab1109137f387048d8aed1da3a4e9c0c140524d517fce4e00c7d60cca0d268228c991eb5632210d8c0c1d6cda17b99e48e3c35eaa67d70bb70643bbbbc301d93f2bc0ad4a210c301f000a8cf811e7dd05e649d95e9bc05fbf316794dddfcf57e0d7414b4c29b371b746d57dc963eafa670c3c63b3236db1970a44fe4f382ca74a71bc1e239ab77d1ab23af88522e3900fe7e213dfc6f4b64bfb3a0bdef3bd4d343ca78ceb960ec9201bba6527382ed6c0b6b9f9505aaf07a3e3aca2a8dc24063a5569f16942f06c043c76c6b3648195100e3988cbeb2118d2ac2bb59e4138ffd0551716d52bdde88470722f4a754c7a278fabf788a9a7bf9669a9af5bd88e9806875a79e25b0802556fde314041f608d62ec839b8ebaeb912b45f44705b6184aff6589a96e19ef61483af2dcd04872747f87db2f91f804bd592340e13b3366f8a774db9de13917e45504af37628baa0040445435bcd40286ad35dd90e313984254828791e9df2619f60abc1fb6a4ede2ff004c27f8a024de2dec8460c513a18ab074846c56d828eb649cea80b448fea3c21e726a4e2b72d055875c5de23fd21bd7b21ecd0bcb0ae46b1d147bb105c07055148617f9aa778ea777ac17d1d6ffe6c33c3af407bccc10df89cd5c0cfede7bff6c1b0002e816ac2148b0147f49d12702eb531405198fe20c516ac3b733bdcee186863ee8e19d445398da8c1a9d0902b83c5832800a40f38ea96555c7cbea5b10eaf1cdf72838e422476712f392864e6251b1e085c0e37db29e997bcf1f31a61efbd30eba20a18cc80235fc5e2add935b3ef4cf9c1af3d2966357c032e5082e0077a908147338f058fe1b2b63a027c113eb2e9f5f21542f65c50132df614e73a02356950c216d7c9efb2726d4c077acba1576c1bbfb1222404a5eaaa722a57d864f40ad791e229c20c192455cdd13f0d49cbe3bbccf705176c62cb4df2b1a59bdeb987453075cbeab1fa769ae43787a6b704358b926f7ba15cef2bd73e6e6165ff6e249e78aee102b06742c6a636554b929d7331d696250ed78af1be428db542d78524549a34c95a4137c06a42d5ecca3f86e49a0e4915d82c21de718217a5b6c0169d7a32b485fa4f94ac5b737be0e4af6501beafa47f94b9905d66e44bf85dac638e430f05431569a96960c44736ffadfcd39f46a1dc9115786985d7f5a10d961492e4e36e601f52e5a5473c0b69a7d25b5e428e4cefe57aa181705ef30a5bc2279647cc9fa9b73cbcc7f979b3c6846f4f2b45ca0f4da305c5415ba87716ea25ea88c30b7cb16b5701b07c9c529b322ae258690cb8fe49d22a50d42368848858fe52697cc0d84597b5aa43941c94645e9333813b47818e0dd2b860d319e2502d6611ec5f30a24d175774058f710a8638cc0ab32d2ed75871270448ac6944b4c80247520c37854f447c62138efc4011b8147d4ce3cc81402cb00f6fc7edcf988dd19c2d6c5ff89eab21217e55fa685b501d5029cfc3f507d7ed9b1c04542a654899f0ca42210a7d0bc91673bf07f4a8d6b2e5a69fa7e43bb2503b60ef3ca3bb5062186935329adab26dab340812c8c0406af3e95573b43d72b6ab5cc0fae8081b2501080dec033e80beeffd068bce5c869de07974fe8ce4bf8154d48cb46281e7baccbd0a9bcad4e6549e2903d155060a70fea2bb73347c043cf14ff409fd31f541ef1eac95307184d5f8d39e020d5c58b216998b81ac950ebfdf177bc94b0885621f48283de3433400754101106d60c7ebcdab3b8af492bdd65d7183bbfe0e5f8fb965edb9b4b19ddfc99476b7bbbe1cecf52422cd749b5301417cac3e790089a1271e8c31fc434b92c505959900738651fa784bd9f9966f1f3dd9828c805c366021c54b3aace7142d3ce4e4fb6e73c0eb27d5cc4664c3f11b59675e9ed176afd906b4fd8d446a414cacd52cd20ee9c0a1d101ca9cd8dbd98060cf1d334ab447222e0187119da45a60ee6bfe2bb075635b2072b757f912a2ce98a84487e54723f8b7b9166257623648b0ce61949af4c9f95a9059a25d9e6775e68194e1c0f80f1a4bc0c99700eaebbf9e0be34d087cc2cdef2b6ca79b95bbe14e6ac4872a6d157d2c336c86e1fc3eca016a8d9d88fcabdb65679deab64a10d3a9443830a773e505b07463b21134d5ba99f6da930818fb0d2ba53972c494835f2074f6fd4766c1fd25c90221bad0af44d52bb52e2de2879130cb80451407578296f25db287b706a90913e87c0548b4f621c71359057c6dd4b9394009145e1c065886a80619783b5f609e903e0c53d358917a08d909c48320ec5edfa28601e7a9ef33d70627214fb30b4585bfbdb7b18c644d4c3928a39248048cf62088e70ed3703594871fc1449539867ee4f1bb84fd8c8ecf6dd4c771c9604a50be81aceb511262f8b824223791a91ec5bea83fcf0acfacc425853236f950a1b18f3544cd18579dc03e931d5de4cce2608e0816533087157c9e24253fab5aae80717596467c50c864785a6a8682b95304796f59f0e4051f9b4826dad9ee3df5df42c8d4b50c3ce68aebb4b3f0f5e748f8bf89c2a6f04227e8d73980e726ce6884e62e90fa1eb17b56bc3bb63e441cae769b4d9395433b7669453b187cb3fb26d04c52689d3b3f930c6fd2cb1d3f0cd8dc20d5540d6017cb9735692551a0531c704222da4ee79c062798bb222c98497bfe101512b19472017a9dd11851818591069ae8492dca315bed15f4356b6dbf396d7f05e97fab43051e7483d309a17c9692bfda5df2b0c8c88caea9559590c762b5711069869cef8a0666c004fb137d3394ecd0db216a9cc5f00477b71dfd20410f3c548bfb63fa8c2dd3c60775803b1d484a1cb775972e928c445796ffe4cd00128841f337200ca1ce214a24281dbbc757cc90ff09d5163a80d48dcb044c39df768c88e9fe5e1e2d8da32e4dcd76cb857a1ab483aaf4a866a54bb6563be8259bdede0b9bf9a152177430e6a5950c602aad7a895022f423b0e3002b3fa8aca8334a5221cd549a343bab4071b9b20933f6e385a7a206a377d39106be58cf98525ce4bf52a1a95914dd6b1e55268051794f98ceebb4399ad7d7e8df5ac78839efe40758afd245d4becd4f827c1488cfa44102424aa6511b1fff842447e873cb2eb7077708512d33a3e2c54df3f71b9d9a2441472dff2c8f07bee5f5042d4b6e88aa74c972f103592101cb7694289176dff5b69d467cc191c97892da8ba594038098368e73ea5a3b836eb867092001a9994452e71b93f9bfbad7fd4a523cf84f3d7f5d2ec7bf1558320cbda8bba270ce49941970e36283055c3c26d50aa8bfc1c622132d7238fdef3aaa0535e2aa2102a50f66cc8f1c15237ffb5876d0009f1135c24402672b553eb958e204a6e29d4f734e98fa85509ad3e036191524f5caff15bbd5af48b8a10cb18e2567e5ebdff7c52996b824acf25365e9534c01e83fc703e80260ded40ef150f4cdbefda4bffc145c73202e0c61437bf87dd2049beb8ae329bedb1833924ace4fcecf1d4bd3b24cc693cd3e5f11b4a75bc19f25c80d6fbcd5b974c5572a973ea0595f46a81970d8d53953836890d239f041461d3dd921fca5287c8ed6926043bfadecfd486f0f4253af1020cdffe660a8c326ef745c3e3a37ed1701392f8c9713f0e025ab122b4f365e31e0b006f8d560cf438fd42148a7057dcdafeda29e0e9ca5e4905c18e7c603280b08b9f74227f67dfe220231956b367a7e22d3cf966d185381e5dea340ad0d42f4634a8d2e2eb7cd9edadd8ba7b9d25712cc9e4bd4479d5fe332c0df17a4b0656df1ce016f0f57a94a8a1881586d05b1f1784fd0bb07eb21022c9a27c7394f16b81b48308df47a80ba8e0900f83904c2a2f37fb67cccc6711dcdaf1a983cfa6ea088863309167b083148f030350b7882e70e99cc417af7c738c7692e44d8166f963ff72b02be31e6caed2a592bdbe7b62de0b9519d083a479a9456ed5b1793da8e5527fb93eafb28fa77cceaabdab30f1f8aeddaf86b7ea70f69339d5b275426c9e5e61f260b6323feddac66054e61b895f8abbc8cbedf3b7aa77938d26200ccf81b4312a4cf52ef518ca47c387f25cbd6864260cb9deb9ac75d082a0ca8b7e88f6a05e610ec5bdc9b82c21a84f9cce23371c4aa0c0fe4fa13a3f786159971b4baf7234d86f06503ef57a2ba89152722f24f9d597ed339b5f33c0dd14e32afe348653554a90b3c7a6903e027273f1f7018a15bbf664c44d0ffe979a5e3b777b02287db0b2956d3a701f5cdee3c43cf8a696605a106c2d08fa79fc23d9ba70cca3547b8ceeca1dbb07c813308a9eac54ddf3a727bb38f6ed90086c18de8a3b21bcec2735003b14a749a5c80726930321b83cd37a674fced8a228f0f021ece8867df04978ec2bcf3ba04431eaf3949fa3eee445c01e3a5d7f313e9adf35071a572587873ba1bba20997804d7a71ac3505cf126652fc7b3ffb79dae0a1710fdc3278f227984b07d48bc8da0b7d12923049d1978bb0132d1d0f718f74f158f6a6911d3669ad88fa9b529b12c3c05b87dca33ed305bbc53d50b69d5fb0f838e193c056a3bd0b6975263945f46f53275a2eb2eb15a236b9151f3ea56b474a6bc563f1657ed6622e7afc0a893fe334d947a2ac050544722610558e8e86591ae57f262bdf99d986a2db8199226b4d9350c5010a0e5c94145e6fa14254112b95424363e07226ee35aa42517f7145cc18620c186d601de92b251f28caa8f03ac04e6b6ba75046a0f82b132619d948af5c3fe4196d38fe35bb6e97b9baba95fe20f3df5326e2ac39d86fb149c3830fbc18b9daa568955f0f8e54b9685b3eb42982cb7709dd4e4977492ac2d0d94ca0d88bc7810a3b9d93671c552e0b842f88a6f30f634709c3e88020c6c7c4cb5e9c0c79ad01af2592ba6b07f76e0970c2e1318316ad7bed3a674d762339a4cfd9f04746ff2d3f8d13ad2f31df4ecb0550ab206a92b09dfe04674074311beda15de4fe2cf918df8bad91732254c7aa25b38154d70a646e58f2280dc80ef1c1676c8793a5f4bf30935f19bdfe609a06be8ed71702c70dbb1eaad7af310908b889da0095f24be79b88d37bb63267ebbfdc9f982f704f8300a4d961669d692d5067e6061a84f8f26c809dfcc896d1e48b56a4425b4f125186de8ee094f8721cc00d8f9fdfe8015df79256bedf12619b9d3909c0e7f6608596226857cf4f4250d01c7c65c22db663f85ace22f12fbd75f9f94bf13a3f5f428538c634032a5222a5fa470ab8937ddfe9e624d59cfa57e801390db19a7682d756fa9476a45356e8d09612c9cba6fd830f7b9b335c69e0ea0f4ce5584468f5d9488aa28d845228786730c5952cbfbf8833579a1a12a291ea885293722809358ef2bb7b72f481254c8db58b2064fb59d4c90caf45d8e1c0dde3a9a18f195692540c34c31eae275fb844223da2786bc722f624423a5cd551ea22f02d87f0d4c677086569d1df27d8a04d1252db36d60392258a46f166b78f984b8fbf9e2e9db92e6339f734116997f53213917aab17fc175a768b19a814938ff8304b2c0732eb6f3250941c457fcde8bdba1cca2d177af63ebd401a7df3ccb935077fecb0970252e56abb15a557bf165e8b848d4ae1c420e1ec942bcec92190fc8395adeb56063a63a475ca6dd775d5c2cc1264b501f826e55f168637941965252c6ebed86cddd865597b133359cf1733c1e8c19fdcb6637ed1a1c330c0e1493859036ee9aabca664167423875889744503e4dd1dce8ea3b95ba6ac780d4054d893e310b7551f3165466ea02bc5add9a2501c96c8d4716a1983ea42720ee28380eec3ecec57f727a01b035a5669c29be20bb878a3fac6536667361d566fde3dd3da805932768f1cd2afd89f644dbfd34f547d145a7efa898fea931a44e432b04d849f4cd26017f2e062f4f7a9dc8c0379b8fa70072db99500a63dc1782a96cfc106de38563421cd188dee16467d046136351c2cfc9e24ec91f74214bc77f196070a0168f43a565a880d3df82b339fb64ca61870810742aa00e497a0f09db847bb03436e193d560445af6d5e525f43e4aa4ab122cfc943eedf0ede0490445cff9410d3b8076b4ad55ca7000d27f8104c4859d203e3dcd652c81404d8c100b7e4ef026b9fc84e279deba4e42ddec6c4e4ddbad1b2427643c8b0a56614b6cf62be2e1c35ee233807b1ccf70928f65b8cbec1ca50e4a0193f48e1486c79c46d30b9e48c9e393cbd63daa454e6af88bfc55a2ff11be937310b127f4de6df7220da02997a07057052c61f1b0be3599e5ae636d1a3b0b1b9d441c59bc1f31b517c554315f3ef69e93f0903098a4cf449c29d79ba7769e1b50933b980f1b33f1da44a74c46807f7c538cecb85acfa1a69626110d67edab05c739093cca92f92cf92e898c91f45b54e17e3a921eecdf6dd5a263f0e0733955511552bfeb5c7b587d03f57849646a019b0f33c6ffe5b147fe0f9b3772b57efae95f27ff0d39696d9474f022e207473fefaf2a2010d39e501530b8014544dc49142d70842fd016dafed1de70350149e093d077358674dcf90d1948c9ef69d0677d5fdf881a58a6ec9c337d949741e5a0de3a7779c267c8ee82159ca07ea7b071b2c98b72b004ccaacadb21ccb5f2f615cb2bdd6141c3d79befd9f2fd63e1bceef3430c5cfd41d7babceb92a060f6e0d566b9eab964bda2777dbd8d0717611cf43a029b3a3aa000368eb1a5321b56ea1acb6a00ae423f4231aa4ac7b1d9cbf13924bb0fea9a25b824f15c72f4311530657fa45622b3fdaa1e467ae834b8ecd04dd145ef7d617ce26991ed6a9d4bc6cad4a9e61040dc9c5ffb4c160a7f56bb3591ddb8776ad5a3963df185198f88119e4e8fa7831db2838bdeadeb66d2038f386c0bf35a047ca43eef5392f77a700b26d1bf6c7d4df53339ac1bcd069014bf879c653d2060acbc55e509c23fe9ed84b79c39c419a4cf52cc8db94e78ac48cb6b568749fe0a45d79788fa285e090c46bc7309a293c1b55d2ef82ccbde95c88d20f3f0284b5c9972bdca6870c8de755888a1118963d1b82814ffaaea1fa1b7dd02f352325dcbc89220091bac7942be0029b46a8c4cc6149b94a58d1e3de450b8f07f30f701d01c58f8cef22bdb34d3004ca42262598160e15cc1d7f63a75af85e8e88378a2bb1363cb5fbfb3f1e28b7b1882e20503659fe57a5b5dcdcb85873d29a3f0f16c3e0d0b23c5e6858a0191027b5ac33901da450aa6974a283202249a710d6a850d1d47eb6ddff25be568beca8438bf107e571dcd89c68d93ed9a839163cc1ea9eb6e5d4e41d8a5761474b12f5979251dfac11ffd9d189e30eb2a9b723aa30187fa138194057a422439dbf475c018c2e4bcb9b146a3ce86c55b207e9b72858d3e832f872c2b053f3af892b0b92d0f244edf4f70725679feeb990e176e535abe17729b5eb24be3e758fe7099fcfb6c42ffac3432317d38aa4322a7dc748f50c599933cbd20176f4879fc4f72480c35887f67c2a94189989f86f5b275dbe5ecc1aa292b9982c002c062a780a820084c73b1b00516909ff7da2f37b01754e38e9f3e1269a1a827ac1c0395287f7f3b4fe57beaafa78cb07d0674587b6bfd3a5a7371368dc2d12810d8796ef16f7c35b5398b4a02196605cda8547deef48bbb8ad14fe52db7f73a750dc0ce0853862cf44618e60f1b83b2aa63f6db6905e5a3691b86b1fd6d5e8c5d80ed27b70879cacc6f505b6bc1e9e96a383febfa351d7f2ce676cba62dbecf00a4c3c10cbc222b6e7bafaf3d400efbf030f1dd98f8e71bd1ecc08c1505325506d20868b37c5c711794e91c04f80f5c091f244944159e6f8b0d087263b5d4f8893263d1283e04689f9c476c45f1f16f0fca7055775ce24857c03b6eed64f1784c89dab8261eaf9165ea6761e3e8de3725a705b2c6637ca40ed03fce12f466eb6f65a4d093679a4c39d45cca5fe7d81cb26bfa7e02e717347e87b1bec8072eb4efcc6f3e9e444821fb5f379242d5a7c5c70af52c76104fa6317fe3f3aaf35dd0796495f348ad89df31865ed4e165b84328d522cfc449cfad46f56755b826d5cd18550d21671d1cd9dcfbe1a8dcdd711fefe6e454175d8458091867bf15d3ddd72e166e84353e414ebdd21f40d7ab1eaea4565af67d7bb08ec4eb6eb3b6aea9d3d60f08d3cd62eff57bea17651d101617ab3a9c46bf88aca7f83af3c9884d6d598508a3a2c921aea4d780f915b9ebb4c60c464cd550b6d65c79f0d326381ab5f4b4bc2f6e09de4ca53f69c7fbd948564acbcba10a0fda579fe1d532a2854d46299423bd6bbd4d7fb6464c4e0c5087fe6b888a3c6ad5826ea417c750466a04c93c8cf2a3456a8696c5dcd7feccd0a779a47722d49db21bfbd1f5f2476027b54ad1de696435a9f33a75d351ee4b646f3e6df6351b580ae3018fe8bf5429b347029a2af77e230a0f75314b7112b88cd85ee5708a0dfd0da15291aff12dc525a86fe51030b6915c0791276b5b617a6e8e8742829c6cf12ba1a749cf4af0cc275a0877dd3f20ef77edb076987e43f11a960add539fc8fa6b03782dd8f96e99e1f6d8cb06951402aa9279085b6ff55b62de6af59000152d571f5006d8e3e200824b9bbad2f4e0ea71d86fdfb34e803df8ce14bc475cb06721afc33538d204f435aaa65675f5030dc72687d5d0a71b1f865dd462b44abd167ff319463e5e0d1fc2a9a721b299c686237aec29191f4bf9b87c0ea73b657104251d35bbb732312edf2a7dd042a67372dea754fefbecbb436fd92184b4551bfc6beadec1c3b54b969d23e617eb93906c9bed3d8478da35973c018c2d812b7740c8307ab29088bbd01755a10c20b0fb0248e7fbf4e267293efef7f5048ef0deac0d8b45c8d11d45707eee7acd3c41c165c6a1109af2356626e7178b00e93b051bdc9871edfdcd3f0ceae38eb31a4ffdf23ae07db9351fb497f25b70c948f31a5fe7625a633a62f8110b5e29fbb42482041b60cf1ae1ea3e3feb5d44670446f5123ee9c1cd74f41db7a7bf0fdcdaef4e30cd39b6b965a84b66ac331b033c590384c66434e8e803906acf9bd856126c01cb8c186c270861948327ac001243903fb4e8fa832fce5d33853196632b6ba6bfb0b3fa55ef5494c38451a946c8e7768de33bd4da9939e546343dcc00d2a75c298c452ced1fa681a7a1e011c4157e5735b3d93c50c85c1698d2cecf107756c9560cd0a33fadbb9c7dc113805889d793943fae3d63b2d2ce54663f34bfce7596e7460565f6a72f4e5b268cd5450ef3a41ee6c0dc027526e2e0973a5e0f8b868fe1e693de20ea40e78b8dca6c2654938d961edf111e8370a27c0d1548b954eb59ddc1c255a34c814846bf72299108ad442d3ca8889f4a1cf792202b432a62c295f5f492f21f7a1bfdae98a7f250bb042f7a83e23c32f1d5275284c495d5d6d50a04e5dbbd9b941ffd73aaac9655878d7f5865c25448abe3865e8e0f00d3e8c70ffb0b58caad6f577dbcf7b9bf52d52a2dfc5ae54d3683796108397b3db26244a44df4ebaf03a49f09dccc4e2bad001634bae9dae366a1b8c76c2293b8115e8837774f2a2ba7ef6b5d90413662ca1d1e8dab2456482702d20f245a72bbd014cff42202894ba24c441f097ecf8e10c8889ee886af4247a02597847b57a5006a1ce6e9ecea12dacbcdb1bcf30f0ab216a4be83103792343b8c2c4979d761957a88b1e36e54d7db9122feb0f37458856f35a0eb13e46b7fad6e96e11fd170f47a71d9174bded6a11606c95beac033fbe7b4ec8bef87ccb4062b279f71b3fbb6b9507b871c7338d21ecc5d0cc0822a4c968b33a29337222f4e0306130391271e6b01ca0ba9fc4764478aae5071ee5e14e9ea2fa123c73e836cd43d79947ca362dad22956b690d54d04de5e8aafbc91de517ba8266ec8143843f6c50d7716749bbbcc00ccdc5c3335f5c7b61431f1c0febfbb74d9e15e4287db889c2392778af63b92742391a7931bec3102182acd98aec498212e2130c5b010557861ea08f829b7c57eddfa6fffe8efcc06b32a2a19512f8cbb43b00ef9f1e06fcfe57e68cf06164aa6cd0b58ab997aa24b26c665f21f241787d70d853fb94bad18b8d13e8470165de7ec657eed60178db249d1da49897a1476bb2809a1709c4491a591979d2e9941ce7fb084e7cda424aba07e10af5e7e638c9394ac9877c2831eebc13a46feb3faffef9c169ee7072668688fc223cf4c9f9ade0ddba70fedbfbb233d3465cd76d34ebe45a3d39a9fedd2c58ae0b11fb2a3dfecdb77f473ffd38b9433c8dde9a1d6de2d02273a215734d794b39a28feab396c65dda93ede9b22003b81c43beefb4a8057f6611ae6d8df9efa100ca4c135cf0ebaca15704e814b477d225f5d6fe37ee1091eeddd991a4f0c1294d8424ba598bf6387d47bbfa1eff9e4661befc3f151e3a8037ef0eefab0494543702a6b430f48c1eff38594d1065030ad318cf0ed0e0bb42c249715526c061eeca3541535f87e2b758fa5856537c781df83f10909ccfd37a847b853383c3965076bd1f7b9565d6c1d1d7df41c0bd545e165825665c6f2996566cf7f21e55c492c03a73789465af702971b91f1d09df25340f7361bd39fcdc787848890d5bf15a1d413a83fb5a925a80e1c562b543027aca4bd1d799d2d9f0b203f8a6244e3f00222c9b4784f574010806567532665831b5ad21f9efbef6213d1e3c44199c709d34b919ec0bde8db5e5b3424df1ddef3ce2975eac3f46f6b4291c16820adfd41ba35bbeb73e18fb50e372c2f1e1615ab6f63717e97c60570e7a0388f9b7111610d0c29a601a22896f8b43d39089c26bd3ab6ce18bc2e7c6406c7be20d0884f303d3af9edcd5ba2b79422148efa592a870dfb8c4fb45adabf558588015c3d3848589ee7132382cedfaceefc752fce7484d6bee1f4fc90f11a58cd97d65c3b91e47b6f492dde766638fb65bec17105843544725ebc0f82b6ae33e55f248ae701d423f958b9a759e6a328ba974f6bf7a94422c112667e58826ab6126cd0694ba3bc067f926314ebf0c1d05927357cfa7e759800ff8f244da2ad277fb9cceb1bbe2eda62dd2b841e012b8cd08f8a05e6fe8d8191c51b6bb8b0f9e294191d42d08842880a6377fd4628f3f1f506c5ce4a5f5a45c98cd3c492659d92e6111fef98f7515a7a355ca6a1bff4b5ad172ccc0b15f289fcfe4781ba431109c8e8198f911090786685ebd2e6c703375fdccb49197bc1b28ebecc53e9f48fc26d945bb7a3c5bb4c5b6596c672392ad52ccc7f0143acc3d523daa652fd2c239de35d0a50491abc2e53d1be7650cd099e71554cd02fa13de0e4bef7023318c08ef274c04fdab7308ad86dddbbdfde9d3d06157f0330e0ebc1b79b01028f15acfc4ae926236b25293ddf4e42a10433b713d7702cf8ed8c0e1bb6289cedbd8ded1206707b68de90e70c0bc57c4278c1f6d6c93231c7ae9e419b4dd057fc290ab15f06db315e0a8b4dbf74f86c78ae2324099400c2bcec8f3ac9615a199abaa83b3a323b20cd13e82eef32cb0cee8ad653a2485702b3cfe386893dc70d46174b645712912334a8fe7ae04dd8e8e25ea8b2abdab9fec2ae5bbad9d5aa54a6c64121d80c6a52854173e7bf0ee3ce28db5b0692b99387dba0872c143ca4f8a67c5d0771d6b1641bbfb57124563b1e7d61f95389f2e0562b0a3c11420a70e428e3ccb2c9a3a3e5ba4df8d170306c572c6ef92eb5c1922cdb45d44ebcea2430aa0ded472ed2bbd4882fbecec23014377e7982e303da3c2497db0a88b6320e586ad9a7255c87f583eb5f538926866ad6fb8859b68ca273186a00ef2cb562cad12862db6bf1816dbecab61705b47bdf2ef93b6ea52aeb3672a754fcaea06e2c589aa0717fd626da070f88322c3904bd60fff34813f920ff2b6a60435683282e832dc6dafdefd9459e5e60fc377f35301f8d0259b5ef22d621d0c6a31208c1b58f2c85bdc2d1c3248808f166e7b62cf4d6585e6f7f3066230c233b725346b95584bb78efaa21f02ce20789afd15d4a99f577d2e4f021333af43bb3fa0dd1e3475f8abddae60377341623fed0985d14670787148ee6b36cfa938b838b30027162780e1ee8f51ebd6f45b3de1a8e2b2e7b676c5ecc2e597ab2939bcd9282a9505f13a301c1f6bf377ac211e0c1b6808a940da991456273920fcef460db9a2cd03d7616afb50109f57d5047c7a3744477516d4dec8b6da60af40a30310cf0df1ae2588f49ba18ea2ddd5a7e7eb1baa669b880cd05996f86d1d105b856457121dc4021431c5dd1a82e5079f64acaaeac5d0c5c571da53eccc1558d7f5e7ace8cc626c106328a793248ff5b20db759559eaba7939bdccc1bdd4c4debfb2bdb573cd7b1809bd53b28bc420df5cb8420f878eb3142e407c5d63f3ef195baf82ac7dc9be03d20e0a92ea73160939a59b0f51fd020a237703fb7f79a9d6e587ab83332ff2a0404493f1f6706b9188435fd2795f462902f11c71f86a22d57536d20ca91852e5c6a1d3ad8f8c6beab071339ae0890dad14ad5a56480877c73cf9955218117117e2c0a1f6b5c37904b618ea182df28caf3a86f33986bc7299c6750cf66aa145b55183d339cc4d363b242c9574e99d8159cb61f9bfc7f66a3d53952f97b646b0fe074b2d7959ed86051927558b6ced7b5c6bfc4e9ec2925ec3f512f02e9b29d35ac3494b2c919bea99c9e7b63a5b958e5a836b3d8bcef72bfa86761ef6353473aad7b3a5713e5837a546ff62c6ad56b97be99e9b4abba9b6d1936862a1261763c60bd92d87bb5e63ccebec493ac98bb5f12d058ff3e10d86e6152273e96321f94748de62c26296b2f082ae3fd7d95dafd7258992f0b9113a5be6e227c9414200652a66c45051f1f64e09b7b24801910618851f676aa1f99671b42b3217ac7182e8ce4a4c0a086b0d0ea7c468a995f37bceef867ef0e8833f9d563592985f5943a89e4fdd325d50b70fb68ff6ccccf28ccaf818a57892f36360b647bc7716560a64c3a1851cf753c4427073c51a5dd33dba2d1ebff9903caea294a967b4789b5ca798a609d3f96ffd0443260a2a232dfc216191683df0904af6211a2b33ecae2203526aa08d8c2c560ec01d1ddd6fb7d4e48ea08d2fbde3932f1e19a94fd9d5f2db544121396ca0518f442064d40b221ce4eca4399d0716bb5cce388b10e91942a8a9215102fe7d53be71adc64a99f72179dab3f3e6005f9a4d08e2f0c68d6a79e1a16c880c33443881f1d44efdb1fb09118b25fcf2ccea177f9a8f7a623f2bca61aafd3b50608ebcc3cd8e2b8cf2a0094dcca609be79d1693d3010b045e980dc31e786200882200882a88d4025f98cf578ff95b53900006ea66d5b47de8d7a3d0c5baff62dfe37b2650ab7412d42d33e63ba8c9d3e9913a00d19412cbd6cc949f59df8547b41534be6a10655ce83966d8bca05168106643738a52447a0d2e40f8c606a3275ad0e07825346a547ca03106ac212f35b874820d6a5dab25cf8c644cff82af50ea33eb04c3a3fbac1fb9caa0645cf3d60c34ab9f2eaa240456059bdc0f4117f5c84712f009d0c252150441439b925650754234bf24d03ecbed8e9929ca0ba2b57c2dbd531a81c8eeb969efe51a554bed344461fd171a9e130353822a023b6c69f1a7fd1ce9c57853e161c20de814daeef78e0c63e67a4ddb9e6e645ea783c4b1db19e4506c417d8529481b7f43ace2a22d02f8b1636aeaaa505c05ad0044e29f8026ba088ad10240fa80b86d0a176e1c8b20ca8b91624bd328a156fce40b9e0912c54df658e9bef41067fe09086ce8cb4340a3b15b9c99c9c9bdac3ea6d9e24e94529c4e43c19f21c428ece5f9ecadcd2a7b79c6a6e472b20cb9017d9cad074504c831a7051b31d1f21b0148c47dd074a561e13e76a69884b4158aa5035164261d9475f799054491ea756b19b77c44b5af4a45ffc45791106c2ae5652d055ccfe5e72a21da848ac678082e4b4e834ba265667b29aaba31e92842fcf82cb757801901ca7cd68226d4bf2150cbdd89f0583742af9c90dc06eb1621e241f2a8f1c8b6ac1908e030013300f24b65c345406686507864b330c69334a1e4f124a53b7ce126df7176c98cf9afe0b94a35b69c8d268496ab67057e1189ca07a1c04346fb284c599a4d9f12a2a09594f97ba1ef321546b7a84ab19695af34b76612de744ca5a4f3cc9000cb499c90b4e73010406f88a0d94a624c28fadf466435790ab63ed1818d52ca06d5342d1e96461ce583b44352fc397e921ac5c9b5629122c2c2425facb8ff4677e861ab9064cbe231f6d5500a537b9e1ea1a6e203ded9280ff98e1aafdc8ec78b5d0a04eb2f1c8551ec5403d2a8b7ad023456ca716d05c2010db7bf0f47252870356410047d94505b11ce9c0b1d91cf860ff94916a3e5fac64595f7ef4294b90de8456f1d53e142ea8c2940e42e7a375d9d9f146a0a8ec9892cc29d199d0d15d765a8e43ad1c9b69b9a53f5cae8748d80bf60e7c4d415c4f91220cd6d8a525a3309496afe4fdc8714b48c10955686528661484b2fea0c888e4caf4a308267e0010943d62aa4f03fa4ac3eec11a7554cfb5b7384ef95f5bf0ad78f4315563e445601c7c8809e16355696b3480a4e428131234213c66daedefc67151915e45181fed881380cc37a84e16a242b2496b5f6e7fe005a7949c99d78a3996008331f9c11658f876c8c0a6d19811e4316b50bfa9f4d77fe2de3c10082dac151166dee8119dbe01234fabc84371b1250c3a09125a6d25d2e42e90a8c87e5a54ea444ec0b068444e5dac34ed142a2274dc9ba881662a1c8f14860e924955562be20a48090b9c9e331c04ec73ea4f9f4b5e1edb2122a311bf04bdb88ed8175bf8b29555761ad8244686a0e4aff3b83861e56c31f01b46a84da01688db001a1f47dae68e5e2460e5ecdce9208b375d80cdd0a7f4ed68134f743cd3729a252529d2420a0fd84713ccb4da0c09f92f68a821c949d15316ece844566c01d998e1943910ef08551031cb0514edb14b0218c937ec503b0b2040c75302a52f1449f5a7011cf21631629a4a6045cef242d8993abdc85fc8588d40adda67794afccf0f5e0fc2ca4cb7722632f25183179904ca72a5a027912a47b692044bbfc85558426e701aeed0abe0548a94cdc08605dba5ac8ed57bf2c9754c21c9d1078b803e4e99623b503908f7ccba1e4117bbee958c741c26c4fe2f5f6d3485a7bd4c98f3036dc234194ecfbbe94486c57bd5e3740a55332142c5f7b104a3991c78b618361899911ead3e73ea56339b6438d95829b62ea636ae371b9a842205d940aebb6c01d15d5f2a2b0bb69140d5bd72b80882f842d7bace6cca53d6c8bb508a6b2ab3941c569c1eeca83cd026138a416e25a4c563b58a95e1049ad549a8a9327448933f6a3bd2720bdaaee59590ad9a5cfc0d99195f93323b86328985720bd906ac74f89526affacb020bd4820ad3f5bca3580730d0f21b283d729f5187ce2b03f56b3a20429e9080573bea003f5622bfb6e394d561f6d0691d6a42352317b9d853687a9cce0cbb9bb2126c41a3808d16a7f8a3090e5828a83cfc0a095999881305dd6893dce110f075824495d85b748fda2d2d5297d0f5cc7ad85a7993845b8da989287616815ed948eac0d72311455a891128c05b6d50f6c1963579ccd7a5c3953265a614255d66eeda3d0eb5751bb251ee70a1c817a48091853841f3e0036b06d042c6737812c336ddf0b50638b91cafa2d44f120460d5a46c97317094f3081872283d869fa081018b0252976614402c47996101b8a2d4801ca6abfa65c6654c4ec0162318c14ca3be83e80a6413733619b035c7bbf1e55ce214fbc11c6a37b1d3a58144396b3f2140e5a89d33fd76e89aad3048f15c6c9c1c881cbe5e854145fe086ae765c2f11c62697a88eba0fb228c695b7ea0ed9444215bcfc011fea9d17449270a0081c89162e56441611f0920d09a02ac050b94ed3dcb980de10b1f740de5450356aecc8b0e94e55457623ff51b1a1f76d2973a2fb18405db5e42758f14429a46124b6f56525f79c1a13558b19417701ad34f3cd5b89009b89a98a0cbd3646ad1032ce9c88c6cfdc84858e46a34630f3e89d22aa08b4f52da0b942f405811ea7429b038c82908856e936154f0939f2eef9b75872da3834acb6034ead60c7bcec2365854647cdd02449bcbba72f6365c3cf4df0d541d17a941f32ae4e984ec5c39195274ba0188b3de82c0542392b5f7314b061a149e356c8643a45a940240405496203408378b821204506a145bb200299d80901391ea2005217f5d62920616ea6c7329811e7d2a47a79e4274c44639daf5118c690d6d6a9e620f24b6d60607d73467519f1ad4e82af0f6586980133f934620e76875a7975f19ba4ab0ce8deef37a4410b5d9904eac8022ba5823943ab04b2258ea253ae0840cae901ee84a1260012d3afe835583a0a04b0a7a579e146c273bc5060384422eab13702b6dac6caf47354e0c31ab9940f873106a40d851492e759f8428ec14d0b0dfd0b2c3762923ed2720c29c099260dbd9328a6521657a0f26c9c6b265c1ad3a767528007e58183eacc102cb3a5dc65411a090bdd45d9a4f804682c2bcc50a16743e68e6bc0b96821256f53dc08768df82f5e37dc806b166a28a9e084eb2696a1d1b8a940e19439f1afde2c39edc69c7a2a63386c1c5ead83bb8531e86ab3807f1068de5a0a4ec5f0de63a4189b1c69445cb15c1a9c8a9280162615958d82fa0a7af2b681d7e02411c90c753460f52f40008a746abc6f2874730529c349f82edba1c873a6dcb92957ce34d828e5589cd730d629bcf02f44ef270fa05323d6cd2cca06f8174e16788b0fea7c030bb08d3d19388dce8208f1c1f62f7e1345eace85c649ada38c14fbf49cb21d4c0ca436fd8c1890dd468ef4e0059832f98322c7b6acf57163c5ed8137228351478d48d0526b02df2446926483075a7bb0c7da9ca29fbf060eb624d52b1617e1bfec44e33df39f5e223e24061df232a5a4ed355470f60e8b348c75620cac3afa800c3164132a783687ac01e99b3cc31d892f31a3eca2f195e99d1334d57f2ab95d7e4e070507f025825ab90b0c24614da459946ed2ac18d7fb9c27b0bbcbce301d1fd6100946d82004e5f6944202b51a9fa1f4a3bd8a796023d408c9ac36295a94d6099f1e23b7658a6ccdc6f82897ec242c20652c1d736ccf068205d6c3525404fd8e7823710bb3cad97f797c1b2a000de3d51661153c200850837b4aa028c58258f42ddd12c36d954b3c7a144be7a06a5074da212ab36a083d7810820f14dee96a798d028c7056d5d6ec9a7ac044fadf6d341070bab069b9e65d684e5751cd14f02e561f9a43ad49162292c956a99afb2b2049896eb9919041574202a19b2ad18a73e610a8c9c235205a09f511afa1188304216091a1d86fb868d2343ec190ea860b381e3c52068c1c63bf6b4d54cad4c560343632a11216fa93a6a4102dc7a4e9e097d21edd2695d1fb5941e365ad6df591b997cc80020b46a535ea62c16bf0bac9aba24bb6765432b1f8d102209d2d7795c7161617548e615ef5f10c6091f7d07eed9911f901e12c24deb7a41e346d81c79a72c0d3a8ca04bac213e457a162757ac8197cc85286be42eb0489cc8025bf9549116cd614296e359d07eba23094b7563702fa31065366d75deab25c48e85315b15205d99899a3387e9d42a47da50a8b5349900b43222541ed56808dbe666e9166b48d84979656e879495cc442d470bffc0b14ddc9879164089b29a0fad3a801a232dd4c2f63e104dda472d281d09c5df8998887427896464e1291bad82172e3655291b4731bd638fd16927c774b013227962810c103b1328aada100e30414fa2d232a865982f3b51c864254252196ccfed2170208216943cafe24c7f8d9ae61f2541d3693804693c8b966d3cabebbc32626c19b5365ff231f2af0f2a9a45725226752aad55a988c49e7986fa5e1b4af94ef4c3ffeca47a8f58d25e5b91a60594dde53658f8d8496244d800073405a57494b071308e08cd863c7b573410b054a4af4c9d114148a5d0ab03c29bc52eca1371b3224fb60a981a97f1c641637a84d6593e55ff238f8126a1a1cb835b1c3c412f46f9541211efe2004f5759b13d970af1b416217a898b5e0da7e7a78d7b8d0ec24d84c6758357eb806f640505d4801d247d7807b654395710326792878cd0112a25599096385f561c4569212034642c51fa1c50093e6d3725d5bfa438700a2204bda5a426dbc214d773e014b1602da95f90adc955ea34349e10ac0e0189aae3123cea2776678dc468890d1213baaa4960722caa984bec49031c20264ac781e0715068693eea9848b80112a96c6d604ad8be8ae6407848806f5edc6911101e3d91ae4fcd760a2dab4230a8efa8a2e61137921d8729819d104847b35994a943c87ad4290a41fb932c2a9deca1844dc4b7a28dac5ebec557e27570fcda442926af45e3114b6a04ad4e03f3083e82dbe39c127e954df97418591480ad2ab5e93e62d67a75d20e35204e88aad4ac5be954e41b27da5ec5b2ed494c8e67aa212b8ba9a2765c9b5efe02a748c3d9b95ff202460ffa7bbf4a56a55665ab0e1b0054a2d665c3535b95aaee038897f9dcb2d5d21e66a785a14aab5805cd3404d962ef2641ca777092b2a33a4380365c793aa9936195c553f901af1d6c5752d4aef4cc68567b0ffac1991bb9cedba3f6334440be8251f41c651434949080bb05b963ab58f1d2757997320f4b044e6604905dcd5d3bcc4c049b280aa81e0468ac8f00ba9e8415b1a652a0735b2756413b7f40b2923515c1311492b4173843fe1427f82e7d6ab151404d6828708226a340c38110e1b0bd67d9a9a8c461512d63b492095caea2c2d919da9ae53426d37b7418c0967db1d37d98a2b089d4dc68eb3403eba30f8307adb0bd8a66e3940435c967d0a6fccc5d6b1a5be05a122d3bc128aac4e40b7246056b8901c26222953c9f4372fe6a8986202006692c84c705435d71f3204a36f4a6f6549729b3aaa904d9d2b306c9baa01730fe3689d735fc096b4b65fa640191c67ce9454927da80fcda5f93dc8705dc634b9cfe2480a42ee507d0e74830d231a828c979d74c4fe541482e8b408a9da20650702d57a5f7398a6071f4ba70064d54042ff96936991679ac06bce8b9b4089253f0c2d05628ec6111e5c8742e2aba5c40d88f4634467d21a188667b555b4f39e9082e81385f17284d0d50e5a26215ff2803b41730f5fc560b556c24bab61e00a8654f59c9950925ef00310ca8fb21016580552c20ca62ad19b6d525b47c02c3f24b8455476730b4851526c39a0fdfa12bc812a69f6424bc12263887f5161f1083121700e342b3a1a5aa030df1faedf5bb02306f990f95614b7b1dc85cfc90f5978325ec5d24b69e62034ebe0b016d151f3e7c4d544006d0f69747cc49c93c687900de21f2214baa024b7866829ab6a54940508b9b9c35b11a02694581d536320216098aad530479931fc19c5ea4cc9ceea2a7a5ed7c88930744a8f53c0cec5e480090d78225ed65a8340fb2ca0ffb810387bedeadc9a31051388d448d2e690f5cfb9521af85d92803f19c003be4a2cb59c874004d2d3992abe880129ce661d2758b6a0873bcd073453b405d521b24b744ebd345bc20d2ad7ec465219286fcae8b9ba9a4e896e3a4eb3036bc1ccf842b4d6095a247b052e947825cea12b894d911113d77c0345e8794b5ef22a526a7f1d2f44e88a2ff729426ab72defa6a2067d9f187376088006e5a92926a4b2184280f9f7f4106324465211f7a048f47aef4933ccd466365d6a1bc0d73900aa2be2a050f36158ab356f1e814cb690a9c26218a4e53b56c7829291b2bad01e96b6a56e44b659a9ccd053c8f6b6068135f14b213336b2705264623285ac9862895095d3922d44f401582523aa5faceadb72f2425ace44e76f08bc6b0f754d5085a5f47b77e45ea534d54740e1098fa06a2ba5b41f461910cc88de747af5bbd127b8d2086de81cb8be6a005513f1153e90d5c11c97066b39a4f8f222c892800da4388108781e81dd38ab4fcb6a0508e8ef900d4f1a6112be40227e320ceb11fee88c2218d9c7422209b3a7782cb777966b29869db56eb2b160c271ced8948a43b29526c004524b1652ee0b58c4cb49a8e9d1a8ff322571ed2c247f7a121a48ff470755e704a35970d0f3a432b960d602bce4d0cb2d1029ed126432184f5a400af9f51e6e4504398ede3c9cb76827ac985d810d93e6367b22b0a44722f2c7672a30919ae6b1aaa957078c232fa33a6c934c0c42e0a61e5179ef0e52c766e75893412b9d7031e2d049ed41f76446952358e5d6290894375ac385bcaef7e58ce0e40caa66fb47cb9b563a3595ed39c039189f621a6150bc5c85a1674614d50d671408fa94040c8b66a55ffd99481fd9021ce58523161b3f8313baeb798cb0a04dbcd101bff1a318de54a2456959a8ebe42e64fd17bda098a2419eeadd3f9304d75972cd01610694a2f9b373aef048f56b00453a7d27b95ff2e00ea1c2fb6f419040c9de443ade0570c65d332be100ec9442abb9121111432d7e310247d01afd4d9d08dc0dcb0791ac4eda44e23b6cd1e9b1331cb939d550a2724c6d23d218272b95d128e0188a273b2153d84160fbac51db76cca7ad66d62291b4b05265732c7820d5bf63a2d3b6107e5244313723086d5d10b9829e841153426f8f03db521acd5a591c9c40cbb3aa493b720a9412c6ca464a594b7ac776ac2b70438d06478069ac073c0a76868d232e2fce5eb8dee590b5064265dad8655ab434e0125513b7dc8f910bab6b651c9481380c3d307da12b59b93551da0caf7466d6efd56c7416882907749b290d1607ab20d8471c014515c6520914541e64bcc58568502c2790835152671ec233a9d5a801b5c5f4321ed2d03ae6c00517afaaccb19168c2bb0b624eb47c6c1f6e53384d59faa11e7628bf2ba16186a935206e9e696331d069e5e2e87a2a6e3c88e950b04a5fd34d9c5e2e0b4895dba7f99048e59dd7efa04447e4193a525707de971032757a8652908a760515e46d091b72828f45b989e645e664cb4154f2cfa8689139d8bd63463589a7a98b731760096538da10eaa8c04296ca7991b1dc433e1a49080fd862d4c0fc157e332708d7a083f212c2ebf5aada905a5ac05d18786348c9033f502eb0c024609cb46b10da14a86a0261e255a92f4c5175c003deca42c00847a0068359cb05a2f4069d73ba0ead45626943a24114a0e3721ebb60d740f338571166e3ad7da03e14126e1faa12f715ac7a8b3832d9a74076b8f2e4a87a2fe5305152beb47ab3e913ce6397df81eab21000fc92993f14c40fa12e3e319059b1d994f57822b5a50254b1129ea1b464d19032700efa27490e7c876dc5211635e4393a0739ded7a7f91fb7b2cc00ea7dd959c60627b8d7af43cac98dc44063dc7f1a547fedda4df51d2e8abcc10781637abf2e318cde8105d874880253b80d44b284409e64afebeb02fcc3475aa36958414ee6cca729788f948c94b4e904c146cfb88b433135cae70bc7b0b6989cc29155fc3e202804d4424d5a814542f2946a8b60124500e13436a4562b26eabcf85cf9ac588bdaa237dc6477f15115633f10c68b31682fa0c1e98c3520127fb417526b461c648fe05224038e7595e4ba108b88b095c67a9938015a0c748039a0023f74095a5d16a0d6941502af5f114dc73ed02f4539d24bc851b89fee36453068487d56125f1c3b2c0a2e6768d26b04cb406fd45c9592eae41f211637b4e8a828ff395faeb31846e9c0c8b0eef82eacff704a5654b1064e45a88e2808258396a0a70553206476e58162f5ae0dc8952fdf767d06b31805b14852fb915140c5da9171c9b814890b65e09d3065edd359818a6dce242f34029425a4f9d2e5d5d61c636cd241f4da184b514b6e936a050be401299132f8cb5a85b927a441e153912a0541d08828f7e9ae16395804ad24657756c051c6fe39262244fc588c98b58b2172a94426802adc1eb26595f6bccf2c4114f580b85e47c850511ddc5c0b02f5ddac05ef534fa0759307a2cc2890e7588c30ff948d132ac7068029ffe8e868cfba753609e4a2e0d0b6107abf76a4acdc380902eb4e8ac6fe88963e96c8961c3648ac28601b4aba334982d41d735cb90442747e2e0841ddac9d0d5459c5a512051cdc0538b4eb331aa5d9d485ec92943ef83c4260f09bcfa9d1e62d7d164aba5167065138a5efccd8b682ea205da2592bcb106e260eae50a1d2c872624bac8147e92156876d1a819acab60200b6b8d61eb3644685c6818d8207c586529b8440899c499d35462948cab878376f26249ebb986b8ac52731a2ec5a0ade868c342da64f755994ce4062ec2bc4c34caa2f1f0ea85f2de32754c843f4230e5b9be54e811d0e39338bf5a4e0c4777801bd430a428d811c0094db6e711f0c48bb9d673bf0461498973950a50768ef1158b1677164c526490d9041861a971d46e1768105b05d0e213e686f419556e4d26baa7499432f452431259d71d4f2f844046f6ab1abb95838a4d43bbeb55ae2c34a830215e440f8c6e0fade915422af94c98ba4652e8c94358ef58b3be3ca0b453355e221242b4e6b08bcc01d48a4eb0650b479a59070654b9c4872d422e7526f51a255e7e69578ea6a0c94d3f7f10f882bab1fe3288fa279088ec8cafb09642c84fa71915774e693875f403a5270923aa4dac6af13f6782b01aec449dcd9a681e40a5d5074dfb4e06c35887416195db7010c8a3acec68221f00e5b6566f424d6110f217dd00e0d14aa56e2297ea693cf0696710036c2abab89d3aaad94dacd7ebd0d0713d3a809acbf0096ba907914ef422168ba7935e0f00b1832573a9ef019c5d6e6b8d84875ae32833a9f2a391c870d518d4607d1804f018d4347dab4829b6a9c9cae2897505afa14ab4274d89720e22d31ec3e91030c925483d65c003784c1bd45f4e916151c1f168047a7bac59bba871241ac5be4012d6af5ad0c92edaaa7cae0a59160137a8cb68c8c24a49bef724c74f7e02e1d1739049e9269eee7c09a01559ee11a4a31080a3ab463235ae0c626ca40d393280239580ae9880ca8bbad0ca9a501d62c10a14c82f6c9cf582124be085d75407601394cfe432b59a487e2c04150e0e26aa45d7aa7a681c4c17ec5b2dbc2e7313824d852bd3cd8c9af50077757da591df256c62f5eb153d19f94a793349e95be8f6fa2ecb942c4c9ee520cb08c13d3469da0f2309c1b6429eac6a4f0abb2488a0f3a1b2fad27017f71cdf9d608aa0f4365a551f2b43f60e5a82796e8c8b1362f4b25af692b4a9ba4cfd56979a8d9ca9dc82128dd692e345db3163a785137afd080cea5750ba72b18d4df7aa152baf7d4183cdc995719592c5221f5cca96c020730e2f507280241d320805a732d915b76ce0c42bd693045df9c5ad0b415144a2afa28ac0ce1820e5acdaa8605138890dea8dcb82dc7cb8863ca9320550276e421301b6ecf9e3bb8245f21302477ee9902676890a4c2d038094fcea31d1a91acc655022069c56266aaf2d1a94cbc0a20434d166c88518159b16af016da40914e0aab857bda7ae0d9beb4b5b2e90ea2a4c22a949739a11e658005c9bad258ba550c94b67e0d0abbb28c95a8e92d0e5d47abb16514fd84b4c92270426c6de19f3d4682908b16ad8c0e827752b3a0b933f7735a5094b6a53927ed19cc5aed9f3aadb261316881223d9cf9a105f46dc22f9801442d6950b51ef21c1862de5667ca116a882994ac9f5a3b303ec5c9c25cd0a17ae96b37e7a9c3be49bc33fd10d2bede60f8cdbea91a3232c09723d32885de6ba9a8625b947535568475e8ce4346d14da0671118be38edce5c25cbfc9079f5cf772ca89e0f4692784e2af16ca6946ba6900bc100799ffbee0006bdc31f51445f2321ca53dcf5584d3531a3c792d1b5d1a45a16827ed2ef45a9cf10b7a895d9015090743a74a433862e81c16a8ac0a25a1fb2841e6a0622e17865090373069f22b0e47d723026d2c207af50002717258824c5997899cd7def8103a09f4b256acd4094a6013a831c891c5120a16d9170998c1499d2cf48d240a72a511a65ac392bfb840eda4ba3d2122f1835e39c9660a6234a73257d85bae76dc8e102119128ee07f287e514cad3e338b4e7f72e4a03d91d1d1c3bd0bbd600f505e20e45637c042882dc3f279880717fad9c8d684a110500d5d340f789b03bc43604d66ce29616925d9f01950845d4667a97d34399ca921ee2cec1556518824f733566543dc22d48cf8acb51b2b8fc683048bbd31c1ed2fbfe111dcf1d4ac227cc80330cdba8d55a5d8185380f45b02c26fc5f1d0083ad861d1fcf8943fe891054bbc39d0c6eb877cc3428accaad98a6df5a23d678c1bd0da2751b71a43d4573217bda4c4f60360629fc246d35bbcb9d440c25a640735067d0b25032dc5075ac770ab9cce2a2a4da74749763447caaf828c6401d4b65bd1a1e77732013907205dc6e325a68f3fe8b0b75c5c39409b675664654b36854354b0112ba0430910046c3322d771449bac142c553fe901e80bfaa03a1cb4b0dcac84e37daa7cc8a4aab8b88d4a74f2f5135da31133f50c54de6e839d94bb2880f6955b30721067b583a8421cc2a8294d844bae6c6d33a4abf0a0d3a690014e0b2c06d0d19434f9c20b21ac8d2935df421305168083a137b511591a3cd0349c9c1bf080a45497c4ea45ae43d7e4c7509995e354e8a8205061cfc8b16b45af14e5493af2895c62c5024220e1acc8e83a40aab9eb9a70a3117d297b14143c9aca46391c9dd37d44e4ea5404c2d844cf634bc13b90db1aacc8c04272c0a8a047b98a078715ee5a944915c2c2c2e9d0a89574aa918b6a6efc40e84bbc09ea3f3a14fc61ba59038e7ea651907e36e094a708e8d0671ea9c89388f45d2e081d2b298aab0ec2a7fab7959a0e71a1419efbd2e9b3047516ea617b9a2a62ae55f6e6781507f653ab1a1d4d8380151025d3ad9c32b2104fa49ad2de9ea025b1986590778385cba0b4ae096c0dc60245f75991c132c061d7a9b6e060e7b2d06a242d2234d495f15d56aa5cea08acb9ec71d09b7285b82a0e16dac92b30578562045b6bd35e93294564e7f65469340074fe04891916090919c1ba38913a139bb0e00e0d1a7a821b26ec2143cf51c24eb120045d6a417a6c054d48adaf40ab097b0c25fc2539b4ae3126eba5a2a63a011ae2cf3c51915d1c4d1cce10079609d5560f33e1617508f0d00f2a99c9650e28f8280895d8f80a9f768333cb6092061c8aa4b4bee104cb00724985ada01b2d83035db0975551b715f194875b3665351808001b81e1e92a579cec8fbf25ed2a975b834903f64ec727ec8f1f8c9eadb4b16ee738ad2072d9f8cad9ca1c87ae63c69b73726be51c68069d411e532c136880c62587cd87ab2034fc27c32ba9292f61472856068844df25c78610c7195559811d96f512e7caaee810176465604893b8ebc58aba0483a5db1321c8a240976f001489dd25cac38d6c78715c7da66f362a0ea76df82a74d657a181a3c39018c2ce08137c9458476ea726434785d8caa4980d0ec30a66770783d6c4e800eb9ca4e06bc46664e901b03c26e9c49be855e8eaa90becf2f99751a101024c4b4b63135540037cb0262c0732d3d68a3c2d3b4e82b4ae53ecd11954159f064b402f379dfa24011cba140f42ec1f286abc1269dac608097fd44b2d2b3a03e068d60cca6646346a1696e8b04854c43a09226858247fbc5c930c352c5b424b9378650a98265225d6855bc69a8d29c95afe54121ee845a40111ba9131fd35ca3754d06163238c3ea24988e5512cf32c98bef205267c3311987c8d895d97eaf3b2b6f4107c8418b70cc5469e8ef3b4a4938828d480dcb87595d2b061c8d163a1937edc2d1092274293a74d85dac55e1914ca677b003a0f2832dde15900e8165bca90d2b879a01eb33a49090eaba47a8a4d622705b04095c1d738b8c29ac1fad229daa8c97009b2be3076e0739eb7be84c982ada4024f9b25cacb08485479a225abae62ad6b465490fc9126079d8b5322b61d71a11fa188b2445a9de84ab0ce58226e12b26bec032c614682e52336164c2089afcf5c718513e458656ba8bbaef1aa2e8f859d08b6e0c2aa31fcc14d2348ab7df0b19da50e8da603cae51d79258e26b9a36df55f431852b814beb1b66612d5696e98e90d6ed696fad5b519d54bce0184d4430419b2a410204f678b5553c23480751da901b2a0517c212056b225024cb2821271f224396f2e698309e09e0c7b1a919cba2cc108aba37891864d5a00704c365eb5dd120cbfe53a7b45ad0c1d42c55f3f4051a98b9cf863db5975de64974dc707ad1e9497e95447685e06a6a36f2168d368c6747ad8989fef6a7385fd6046426322b3833dd5a703fb664a2c4c4be0cc0aa69860691111c0ba783247b8e091817c474501d0462e230d61cb9255b2c9cdf5b4616d012ed28d2450d2440e007f8bec8fa5c31b7521ac0cb9ea49ca9180e295e9faf49c81524faf4243a5d7043ac232b9537453313337396bf0a29c47ad420819562a8590691930c05a50b503a806d02616001719c23728a6643b76c43a115a25d6c55e320b2945a90350a2d365ada34e2123166b458d48cb6882805523f5d1ad021579d183268765eb0adb290af31eb4a460f564356a465836b1a06eb46ffe2561f138297428c737d6cf84fc584d393fd30043b6c00348b3eaf0cc47a3a1dbd96121f7b8850a58964457a350b02ad8c2d5d3045cf1b92859cb0fca63a2d95c5439944e3fc680177dcbbdd01b2ef9695435c0b280b5bebb1ab1e58838518fc9c2287652905aedaaac7931a2d0748a378e3215087b2f9385455ec4cbd0efc49ce42dd5326d41c7942f300180f4ac37228072c1426cdd0835403d3752f652e6652b79b294cdc87a2064c1273e8958312e288c4c6b0255830d3204d8af7815684a3ef81e092d4ae76a1bd5acac136c340198e6f041c3c554ac6838ead7053915f45104b059c0a49a8820c255bdb3ee81d65ae624875786a0c249cb4172d54afac8c96b204eb5dfaa5bc14aa6a264641f33568e488d1c0a920c56c0a2b1f3fa8af23db8c00e804d7eae5b479acaa40cb722ab51a74174f705ee5827711fb17988c9437822896db6d8fb0e2ca27ea78988ee7067afa938e2d13dac43583d2c8a8dc986851f395db98d57693d0843a5cc609158500c8be675290ac12aeac2a7c71020913bfd58fb0a108a329f82030d87eae981cee4359e180e9712a555236f717a9226934b81403a090cb5fa0099bd3e05d6a515d425c912cc7af49544a846b007794405c4b06440507dc8c4c54e79c4dfc01a590e8910e5621c1a4000a92cf5728919a11b0c083ac9972ca4e34b9081eca120ad3e53996a978ae5f4c14d03dae164e11e34ba19400f7e89929316b045d33d3c75b4831e4af23b86d7e7fe083d9583bbcf81f5c69a45d5b4252eabf280d671587a4e0edc72e66dbb201c47271ded68479d2be9636c596968b17a02e2dc679a23d3019392c1dccd01e7b2bc781d0a26c206158834d88b251ff5e1ed059cb5fe6694914389f280651a38d4677088c8852c756a219b4b0f8126d36dad89c1027180760775602c063e144d5724461ee3a5474f0114c70239193a9a45bb9a80185ecb4569b278ca5275953483806f839e19d49716f6519b40edca8615c81626419666244102905cf4972e34a02d257d7a9775c85e0d81351a4e297ea00b8db71f129de351df5fc1cae7d559e8446f3bfaab14a7ced537a499331e5d815fdf43e8da6bb62a1d3641866737c15124ef9853a7b970491e0827431fcb20aa37b5ad6817064c7d3db39446000403109327b4dc68d61e5bc7498a5cd432fccaa06540e312f36371146af31f155ee52397289cd42b4a6c241459ee64a0a497f02af538628532dba8fe1f6829d68d995d9bf5b9e5566ee21ec2a34946f5c7497fba2b72b92589fa9425339f11a7af73d428b6d18e984c16484d98a5949963faa48055618a543f3fbcc99ac83eb51c5e8e803626b0b89f4b398ea44f91362ed0943dc56f0bf0f286955105c3519522c472e880a24998cad1672064bcd60a593dc6604853b872695a31881e23a59047e160f5641b900b307e69267851d8047bca644f1fe034a841ccbe922a05acd2014a16ceed0143c009c88c28f010f2cab1270f98e12728a97ae2452b73ba0a32ed165a5c6c3640ec0f16d2f2d70c3a9d0b2c4e43996f5a50d89e4c542a5b0b9b4bacacdebb803a551fa362fd915e4eda0f8fa896736be4bc0dc4067b52d7d7110a329d2431f98e72b51b979a7b109797b44705100b2f474d6a04302806f626dfa05403d84590933e31f7e012e6f0b58b3a06990b9442df932af39b30b10ee03aa5a5cc907ed510afd3a6808ee051a93e2279752c5888f41d1bb7fd388960a5c8287565ac3cecb40cd94f153cd855706a3aae1329d6281dd0cf5820842cfe44617df838c3de594287f5a161ac89514099cccc9d775a92e904502fdd0a4c52bb92a1a4558149d5425038731f11553a50955e2ca01c28fa099b4decab3409fde542ca1b8c815e9554c5814228fc899c0c59d3d8986ed36a43467ad8f5041884b49090b05b2cc908a70968e515016c00e1deb75cc5ef036ba28f46e641674ff092926ba78221a4691991dc4a5d0236d8a1d19fc009eea7cc99969576d703089d785b02664f7271348b227fba51a5dc3314f9e84ea964bd6a873d9212b1c3f08038735684be25c4087b6288fcf10d3b8ee499b62b230958178a411e5101446e24474ef710438a2d340b8c85c225e8365a4f3202386af2a31674580de432931b685a102148f96f489de602d7aa6514f8f0e69cb4c6a2a9ca85520899cf18097f306245ce83b834185884fc4483a226d165efef1be67b49926de78bf12e42fcc9647176d8012fd880730566b4050854322d2b75f98f03845c04c6a23611a780add2c2c22a50c405b84704861bf2802b573a55f6304868f9cf80081d415921c73003e3714684752050ba9a0a00198d6188f1857a08db221ae02714e96a39c51547318cf210758dbe65978d96b128ed105ed86003bc085a972a35c1359be8d8641b0538c14c89ec41d002e0ab356d99c8052670492a5399d5a634421bac8b135022d716d0565d79e153b6a268d94c3b51ada4a1a3f5c82c620728d8715691a03c030ed57a0860b158cc78faac12ed8928f674a65c6cd830a4583d025d828e9273bc133162a1cd28df808517eceba2d6a7bcf8f8526b349f514628ec378cdee55307164aa87904cc2fec0b3cbb1a829cb7bf0802a6dfbca0c84748f0e837490bb7b6c96a36344e74125b607d8581c6726a44a42dc978d442dee08ebf3cf3045db9ba3bd5603d41c17ad10a20cff224cd6915e558be50432e7db4299325e9b0cc324d5829b6d69a442c242c0e5e31321f1e230fc4074d43f5dc0471e5b0d58a66c8e94beea886f2a2456342d1e275144cd91863543c979a1c36d41e14eda74d07eb8c9b7b2552640ec414e953ea18f9014003ae46d28e96c02041bb58e4260340d4e2615ee462711deb749c2d5e8243ec7ee45c4d387c1150f661ebe2bc405e6f903d26870f36c3a468fed2a74836e0827a1a0971b9092c05cd8b071916c02e582d7747d59b7665fa0d9445ddea849ce721b3a3a7fca871556e981ccc901d7d1707a2f1c408dd2d8cd94f2195fa442ccdcbaed20e2cb57558981859af9de4307a65b90d174deca1247c58233844b1b4fc7235921439722e4484b21b2a65ec8b34af1e48d9d70a9054e93e0774fc0c222eed5413bcaa0b758de350b4bfe409754648a62f8a59f0169496643b53a87f6a19d098088879a91362da459a8b3f2a15839d02204687d990702f545efda4c2b187e42cf58c3dcd3605c1566624950484e367aea3fce9f932f06745a791a26199c022eb3857b6583bc03d87454db2b6c8fc3ad718a30c6b6c4ad74d59d64aac4bc7900aed7c7ba15e74f3f6d6455903b0f5a0174459f4a839318ba0919b8e54ead4a144a175b00c0cf2264f7f58333bb880687440c864b0ec014a11c5c88a686401d249c26f25a512d4fba420fbc8e403d8e191de876f24b29a19b4ce0948aacc67c383b6c20ac3cb0080d38d789df819695ce339b27adb94e6a3406f6435b2e01acf21b586d71cf59d1bdb5159587526af896e13e1a8810c927d4664d142128508c6b892c94130bd41186c0d1a542d5bc02b4022652ac56bd0b8a0da8f8e0d805bf0e81c9a61046b36d7e57984919b3de0d177b4b0349f2c100f52c174293a0634186bcc52a0a1e22b8a28692d4d0f27924b4397c005e07b8f12e5b94af0475178c162f1e3bb85385358568fb26413cb434007438e99ada0cc6a0075e762442a88ec32a911248091af8c96c7310995f0d9a651b77005cbc9939983b9ed399c34065d2301b343b0207a0c81a63ca1c572477330b21258749ac303302c530bdd19c869d51edab6342c044ffac51e5d6b71f1e4d236766e042ec71f8081ca5e30fd0953f18d61edbc5861bb2091d45526b1019e89a1d75ebe9c60fdd82992356478220442f9790d28d1788ba46f3637d8356ed44e74480e5be8c35e4b87629e444dafef1855241f9ade398933316f25674b57baebc58a4a71e1434cb978951cb6ba41805e2db7aac2534438d0822608f91410858010e25860c91c8fb48f347472860b7b80274249c8299669808d2c20610f50cac02488c05a43a36a066ae2fe29eef13909cc0ea1062d360f24101f4309c7b3248af13712758de25291bb82512353b8c3a32d59d863f7ae19fa0aa9cd4a2eec681d127a75acea800bb0239751acd99511f5358148986ed745b7a95324e1928d5abe0017ad20d3309a985c0dc38b756044664c448a3cc0a339998ea3009fc576468301d61d343535212dae9a0da1286c11466b0eeb4d932c96e4d44294963218324bcde845ab2cc300adbba2d4d6372e8d39acfe63ffda127c978605d98ad4d2683a4a008be811ca06ea16b1b4aa0af2ab691cab63d0335700a208482baa2beb621480adb3a9d86fda74c8b2d2e4c6e0a77a526cce7ed58548b30549f45f2b09ecd442a4cf6168cb687238eab93b28f7f047ef094ae462bfa8da7316791572a7af1f3f6467402e00e2c2e3fc988d85af40e37282a65b36b7329f4e591a0faab3aea5a60d70d2daa19c3462629164d893432181138c346c7bc319713d3bbd5a48438e8563c2ef29fe82b98d19dc3746dd65315278ba4ba9273d024cf3a80ed784e8b6b41dbd60c6a48944e3a1248ab5200841a36282839da065c5fdbc71d45f48d4e85217b204eb143c69465392643b2e7af4a2505484b4d8e0583c22468016e6f4f4ab59436004102b2ee0089a7c24c9a31bf4f1c19a4a42e40dac0cef2811f44f1b68598c08ec2f1eb0f2914f851fc7a462ad3d34353209a1d5e6fce83b5c0eb05978857a170967b7c14a41a7a1a0e54aa664ea45687065202c9ee40f8eacb0449294dd99420570131aaa3f4ac08715425dd4444055e1123f0b9e55456a52712afccfa65eec2c09ec732928d36a08bebe440799ab1dead2458e663296609b160204c1670828d055bb509dca059fd613e392e37c71713e552f9f95e7cb434d3263bfd258c93faad001c220e322e741ca0056c8b1a5278039c4ce0830cc2d7a3809be3263a7a1af7e002d38c8d38b9060c81712ddf8255337da5316e4d3fc005babd79547ea33258325e07537899ad59061c78b8c2ad5327c50ff36e844df9d6a7243b0ce6e424ea93b38c08535a5c8cd595472d9010dbee43b13223a4c2c4b2c9e0312583c91ea722f1678be38ccf2d3794f526cab3869f28a374b0611cbc63b9082b38e0e4cae678a0e8b0206826e7063433f08d6399a235dd830951e5c901c037615901f3dd6822c938061dd566c889dcbe2e550805b1ac80a1e5f524850bb5aa2a5df4c711f27c58b4c2984dbb3aea4e8496dad0ee9cbb5f30460c26e39fbc4ca10758525427688a51301652de451d01702ddf958de94a75d08d162c672358d22589acd019ace923a6c974766ed8617b35f72ab8e2096aa27dac3d456256cd84a44a8ad0ac5a1eb11c2a0d16089f02901b0b427b900ec97d64b06b2e6da2a164c79a6430bb29a5ed1ac494917a112965bc36092019af9805f578645700f009a83f0242b930a65fd1f30717207516f3e648911b66ed8e1a89e6d5f55ddd34b1f6432914c8fda1429572c29052d0ec583b3c91099d2ba84473ad6a3fe533badf654725425d4f22d06cf951e3dfa3aea6995738052c052d020a0e952bc62d188c995d57c080a116d91d14cb800014692e2a98361ace43c44563e828b960b50227735b9b4dc4fd34b9f7a03a1954c15757092aefce789d9977c28cb766851681f6953be85cd5bc3f02088ed2304d139422d6a32a1f68e07012f56061b9ccc098f58539164a9bd2cba02e40b052537354df96200e04def714185c5f506a8d3d892d1740279ba5d1466e97c8075352807b2f11ae707ac8460c9d845683f64672d8488922eb4c2ca0ea931f73d7025d85c7d1b1a48840b6d24ecef7fd07c61fb7acb63596d1db687fa08192abc7dbaea450ede078930ba510264ee4405464ea1039370ac411a1b878617fbc38a9963c873f74084ca7ad08f2cec9c46adfe16eb4713180bf3b8066258134336bd4b8d372d01efc34fa543275ab3a4716c52f3124238742250c4c34112ea4da348af000bf4ab1f5af91220036d6755a94695a1d96e4c7912724072a701081505534170b2463b3e1951dc952ef4a623c880c98ecc6582a7200048b75ad96807cbab3aabb18c9de5440542348d1961d9149a9f06f449caf6625bf45b190af9cd81466da782acdceb8e897e03c7d953de810be192bc242f3cde225f7d55130a872403cdd1428461f5b810592b5c88bca3c615605cb24ef7d883003cf2c112db242d552321c239cf1b20a0f2cb4f8f99e1cb9a0a7d7a251f1cd858bd74753551f1b1a26f5a578d102c99b7ec41b92eb9ef0baf9f285393792481bc0ddb809eb5a54cc7301736d49a513f4375750146540733a30f8b2190880c87c502e10c56169a0a42c946503392c5107502a6f914d61bcedcb59893af139ab00a08278a94cee3a62fc771e1d37dce38c8225051fa16317b7ee202b5fde800d065a6796d4692a22e2341d13f815993cf70e274eb98ab6c48d1a8ae55e04046f58afa5c032acfd186c597932ab55c260f9dcb0001966e46a46672a74f5861c92516cf95be206b46176b61d90308f75cd47080a8b1a49064ea19430edd11a028fd055690c3592b3b5fdcd787aee0b46bc9164b47aec71b5c0091b14c71f02a4b35eca345d58e34a54d1391bb7b1e4a4a6e1402a8997674b0b8b0f0388cbeb63cd737ab93a4fac0a66dd87153ec19218bb3ea6f452b0831f8657aa15e74be304cd193d3cc9d052bb885382bbd03f9c68f4c7f52d4c55a51f835166a9ba35f372e96e3c3636829d06ce6fe322bbc742c145858157bca2ee69633d76589be90a9251f8be3d16e5a533ec0e64d334fc469308ba0f7b160cc57821986fa2d56937c0b07800c6bae5690cca14359d2972b40b612b4ce470508201dea9d9e1462cb5ff89d39d3565b86b394e8515cf9603fad79d0578815d84aa89c8f5b9423f315399ec828323f64e4c2332571c3ee55897111ac8aec1658774764e5d881c46a3c0f1816b97a6840d3e9d2f64b294e64389fc97c16317bd4043b412b46bdbcc797c68e99ea915f446a13ac901975015169728c0bc7d3dc2a9399d638cd2493cb1aa062d6d94607f68c9444efe1e87250ab263d938a5ec6d2d916c2b46a1d5010b4a14479aca80088fad589240ba75183363bd5d7ad548c3882bf2139129411ed46571ab60dd5404e4b25aa9dd8216b2460cabee8d67eb496176fc01578737a0d4081f64387fa3d4672be74c554d3a1c4e917f01469546408651766541e80879015f2847b8628903550a4d5931c5034a924401e448584cd72abec925cb53c202ed55ce2d46ec54fadbea474c346093e683a9044b181eec0741c0d6d6c9e0d60d9559838d8414ec7f5e860123e990e38a6e8a1ec66818083c2f2e977998a5c5126199dc808a44f3af3d5bd887bee4454920d71c3afffca447643bbd4b798e8ca00fa8c3d8f902f960d8e0b1782e33d074c9c9a2d4680f652a399cbee1644a176cd5004545854bbdc5b0381ca4538bc7b0992c30adfb46a597263807a1c7e0b4012b08b6ce8f88bbebf96d1ca38bc0bed6fe278f819a0914c65428fee5067aac7c818ea2851152c6b60d1e774c8d5b7b058b80a320f583504656f4db38e0a386d344cf2bf142574ae2a3ada7d43270333a46011f162b6fb080ceb57c80beb1673dbf11b6b500824b17c9598349c1c240bca90db4f9998bb8c24bb3ecb4a97bed0cb4b0fa0d329bbd94de93b4f38ef1295e8220454c96f6e506ab027245809f18fe613268e0d726071a204043d046477259fdcd84ab8a619c315454058eda5eb10cd802a587979231e4d205e2358aca9426341599ef6349dade0fd9410f6156b91537971e4acde8a641f650cdee4b9f75ca736f505e9dbdb2f544d84cd9fd6042ada4858a060afb8692e6b98a7fd32d079a23a0219c78663afa585c8676fc474045650dec72752d6229645882399cc958e82f21a8c49ed858a2b16cb334253b9f084fd528142e7c0808505f0e6eca4aa93ce884da4db31c2c25a1093d347d27ee4b33c280d4535960d8c50d15f902ceee50d8796442b6e133c06fd42270f0d6415e5ab2ed4ba17368c7e47cb9b7671a954d3cab227275070e4848c76c2186758daaa4aadc7a0f0cb792ad2b0546820ca4164e80026ad05bec5c61c2018e3db182654789ff54f379160ed3336909dedccea487538ba962837d993dca71329e59fe995e9212ebd1dd2a7b726a209ca7c1d865cd418d97171fad1666a886279f0bad289ae85a57387a51fcc38043c90014027f2312777a8d3213309332babd8416c234f88405e1fb4e45667767c517860a21da8ba905b2654ba46a92c2cd0c8a5e5ca54391a173dfa0e54028bc68da49682d0d380f0603a9d5345ce4548af35fc49b28e8cbc5ec10aa1ef8e28af468c120b8993a05ef440149bfc2b91cb68b860e1d4f4b0654ee87cd5296bb17cce0ce44d28a0a76441fa49637664374b445e4bcccf0d0c2d34265da15ea04c279657944adb684a39832e3b4d2480a3cc0441e0c1462b0eead9e6b8dab464346e6e4d03d000b6c9195ce3519064359d02d473ac738e4249a84311e3e879cea8790a0f204135510232a4b0095fd40086f21946732c022faffac38f22390d81826e03a303bb2781886331d4aa7f30a07243add464e400450dbdf1d69912c03826560e3a115a6e00924e9cd59c6abf66de5a5a45cd1d34f092251828f24ab340bd0e70ef51435596af44866b3851e3b25c3133910b6a84617378b081f2f002f68268669b25833d23874b5e85679727cd3d60f1b4d4120a91b5e21c24d8ca4436906815ca11ec091c72fa996f643d6170f49bab9b7609f1fa9f407a1d63d488aba11022f70d9bbc1272eec155a75e8ca496955ffd3e060274071f2abac88806dbc4642513fa4a63e7a4a8d4d3251f219e38527200b942ec9837b91a569f3e2c9f4e9cba960f4deca7414cfa4124072dd6c2518712d184ad8368f925b8627d5417bd6ec3dbd217fccc7507378fd8381793ce614d5817aa91e59a42b9f88734ec01b138329821437a82180b2c52cd5b1761832c134f60b21a175060a3e2b1a17346582bb197cc47a6c7428ad7742734b75ce0429f4ce90fc8e6c1d2d64226b5ec0206045e0bc2a46ed124edd60760d9898357a71a238125c4823a2939435685db5d8b9210770d65cefccaac48799840d5d30a2c6916102e3c0614bc66b520d18ff40dd946a28c8d8349a8831285968178789545cc29ea122d3404357ca1cb1d144c60ef2085e526050f8d88ccd403f41a94e19a8c9d871b8e4cdc90a28d6460d2a672496a336c9b58ebde9e13d0e3205f15a83a933759b94a06d3935aacdc29ebd3916c8175b81fb26ee2ba807d824ad1023634cabd78a1b11d9c42201c0d156c8e46728451785d9bc614123b6b048d1322f36415e5bd69354d76b06a96903c111c5d57b0ebd2613d2e741e3a27cde51d725271a2236ba17999cb6a478ff45e21048357a0b2ec0368b8ee428af43264cef481a3933c0b889b238892c716a153abd7781dd92419909c4a5519f096dd84cc27d08f46144b52a3d2f2a36dc5a9c9526480017f0c68d1d7210decb348c9f76050b90805bb8ee75196abb5555a8f852c5f74c9ef728640691f11c01a85284f39d4a8b1f6220aaeed943e3ea894861380d33b1e3e79d8582a84cfa08109dbaa81886b619125db19c5a73be032c0f645b1d1c03f2cc19843df4fb970591f72c8d8e49e4a3d9ce1a53374d2d24e260db90a32b05cfd32a34d5801d09a20b0b59c1e8b0fc292a33f5918954bb550d25d2e09381846adba8b134b06216572bb2f232ee0129323ba539325c4067ac791338f7312f60f40b42e84614676da7895d340109317eccde9283cccb065afd8d81babac19d685489d2411180b872f54db7aa2a1655ce8c12631ad789215902c45a3a707343534832a185e2531a56d90edfadb21355908414517d9042b0b5ad1e4a704e968a716ebfbbcb9d14bdc2e3dcf4a74b618523e41049383a1a4e58ac6b4020650fbca757654203441a59c07aa4570cd138e3d51472e48050f4cc7f1042bf8a8c6a4af203286f5f4c25477b94164f1d46035030b393e4b0bac372abe3aaeb2372d89d721764b73d990d474c95548d89d02ad40194d1cdb5748f7f4da8203b77638921fcd3afecd1eba4ee3fbf32c8cd0b0801604612f40e9056ce447af938cb106d7f050331d530c58bc1f6b9905181d105123579d2689322f65453a29421b585a9b62b5910d6e2d6da5e77878b9b82a0f487a8cc41ecb0626e36746c13aa514783a158018b77475fb54a3be57f0d1fcf00e91aca379a249f860e643a7ae9943163779c5a647d7b39c026c037b3cc8701258b2933a0d1940769554652395c73925d5a18515a128024189945493bcacdaf483e5db64ddf001694a1d08c1e88b0e3848feb23d78f004a301ec0402fe6b50602d19ce49d082d1981f2d038d0a639ea8f27469c8cdde44fd593519f8d1e61763806ac21a1911b7253f1a271ea6781d69541b6e06a7961e38568ecf2fe6e441840679ca953f8dcf439513983b6cff595b5634aac4ad21178b2549880253959f409aa94ca460adf8cfe4a8f1e179b2e163334ce9a082e1274008ca4cb1e80f202703c9a631ff98a12a0551435e20cfd602b93fc09f43c8293f99db97531bae9676a5cc2f60845eaa9f6ccc1ddbd520b9bf004d47fe32b2493ff2c8900fd8f1972df9d7361ccdecffffffff4fe626c01343cf37828833ae26e48e6c21230046df845a2234bd72248742984613a8911a04171664d180b42a889720922261127e9059300bea6d62ab2385add494070920000230e224bc14a5412838550556a0f0d2c7a2c00f152398d0b113a09719e5b2cd96dc314874a0c4080b7b75970889fc43e6d05a000e6ab1dc54b1a40a971e3469f21acd312040c97d66da5b628a8a468a98f04f211e63c9504b61114f14464aaa3b80735725677eb460f882929ce543958c43483ceca522f000c89184d48f9cb45270f0a4b9028394d85f140670ac5414d24827a82c298027ce5985373a5c74908d81d4a1f0ac42500a2d4d4910b55e7b049078071966966f3c8512bb12a792204b00a08c71a09708d98a9867c6a793925751a5b761dca5bd346a8c89d052b17060824f2240253630c2326545a43d626f707c24bd284097a20964570f382271661884343d3840e0815406f36393200343d04e84eae082d6d3ac93910f7d005ea90ab536460059aa5822d2c6120428236b734646d921007994b2449096c803c511ab3669f40cc0432644944bcf131ccbb70c562c2b9648523196ecf540f3c68030441963770648190abdb3126fd4b86b6e85a826489026d200364b5dc0c8a0a4a12c6e930068dba422480743221fe0208ab2e991d446543f9421e3846645a3565eaa223ea4120a138dac02a60038b34b4d21195b0691118a0a03488c5a4c9602c3581d574162311ab125115448d67422b54208bbf4c60002e9ee073081801c07c51a1e4b8c9c4450dba0c746b0ad80211aa2986646f871852bc194536f89f8c6fe0644d890088c1af7d1eb244543016300be301456e09a5289922a332a71004a0128100011220573d4af244a1a788454f242692c8a052f14383813d8e13560ec2d45467926ab5191e09821a8a85d61ce1cf531f943208ae140921872246860087ac960e90d84b104d6392bb644c1d194080191af0f26bc9c45d70af9d19ac109859e372d89b31c44d218a9b1a3c76d421819055aaa5e6ae43920166838a9451035e7213d41def4003a98cc5c390132d5ce1c9a3b954346e7005522ad812b44434e81d9f290034f2b4279b07c12a371c58b544a033e2508bcd9b992a9b5317baf854ed49985ea0b195e6cb862a0394373e207172a941c32461a0161331721458db557b73468d1e4858929406a6545f6da5865b668a00a64254427e1165c84b72660e806cc9ad3c619c3c3481f3b81f46070f5c1c8da841b3dd2464031c546471c17ac89e54c19102e8f564067c451d5f7ecd5a0c5a164008e6b582e89d3e98c8b25196655efa442c61b546068d3890a8ae68e1472061c3850365cf396a4c9a22e93da0e3cdadeb318021a55c290aaad07a123552b607c8d3ab95103940452b28e138f535a704dcab48b4a0cb22cf1061c4a25a82604f9239524478f4c022e8cad88ff3845e5cac1c70b835b684ed48c6767a8b03a42c38eaed9b268897945b6c055124f71707a0e25bb29d479b01560ce9a54547af572f1f420c20189f0c5ac02372c1dc823a49786039c0c50b18a582561ac0f6bab4e582f25544577724d68350b478006476821adf472baa850a642ae54126a11a8936682b5ae978735c3e2a21ea4ece88ca950f3095629314d480485804e405aca39334305535e9f92a7a710239e630ea81381a35e894496d88c2013d049c9a2bb6221868ad1ab3f1f484032a64875e5d3afb83833f067471e8c1b1b521c28d3c76c031f66da0e0848840fecac68dd98687259818a9058111b71083acd21c3600c337057690a27b332b27ab5a27423c023149554e951341786e6288e9054413b0584b422ce28e0935b88ada10893c54a9125e9cba3445aac9089cd18b0b970f561faca83915e7e18f8985042734bd54c85658aaa4bcb5eb74e647a03620dc8012307fad84a402288065aa28e326294c599a362eb0e273a38af50f93dbff26419c0a5d0ade981b023347690b9a58478c6027250dc9db05556dc175189b8c123b01265756c2b98ccfab2e67a4ab1848b90252906081b2cdfbc1e18686871e081a0503b92c8af3a403439299315b6a00d9e57d3873fb24392a2a4c9d34a8f0ddf033aaed54901017a2cbc62a9e68a8b4c733804e9682ba5e6e2480a534028559b8e0ae1995057e106d90b383a29229561354a080d3a188c20e8144095061c658a9848c329949bda9352ad2615302365ce7800d494293174258855201570cc5a81c8025b8ed26ad0e1d012806c8c0d70a76894d40e0651b10cd5d2e5290b160f0470f1e1f44814188d08b5665d20fb617765acc7a5066cc7a18c3f68025c2750ce8039e3c404ae415811ea660d4786573cc00e1150c12a481d3248c433547251da80b1901b1ba335618289410ae0cc19c2e9c1881684ce62bc7fb9907326a0152013167762f2487b63bcf2b1deb00ba564e4a2c558a31073a3e487d984eb194761705c2a2b3166925926a70d340b7e60bc90d82231408d0430edc8d209d5e4d6581006b0971c09bc801013514405843c9c1abddaa4864c5aa65147331a4952b7ce4cc1d0260a2526ed132e29d05e3f5eeea0b883e20c0e092b3eb004955973d4a60899d6808e1a4218e0adc993d3a42c54092a67faeef4d549e11be3c0038a3c0334a9d10128235516c24e8c4571570c24583b9a3242654ba72d037444e8b1a1ea005ad60450c9aed712316117083c6a9ae0636a4007b2248c04ed4864c9784050911c6b70205b6869f06302083e259058bdc95b2d62325a61aa28c038c97b21ca8e02309c6831113027890032c057211e0c08052bb8429aa7f6450d1826211c68ba2346c0aa44679e24212392aa10d551a705934a4567fd59a0e9928003495a651926cd4152a0849c3c37288b0aacca25671380237d6994386c80d045c78e8cec130a54c432222a5e69348c805e210aa0e50a191d8e643c6a778d819502ce0ebd0218aa8cf6f06a13d4030811c2811988cac6d23c916561fab4bc89a2a08fad3d1f1102887d29d892c40a202d74e438a88389062e025786af78ada97bb32b4c5aadb52673a863179060b97380e0892c326993953c71489c3949f39787d653c402044800ec3943c353daab297c967344cc80f506af051e24690b314c695350af2268c1e24810ad211bf0e2ce8aad5826367a00f9c82027968e154206a59db8c238be50f0a613001badf89662e688490960627047cb93e188ebd451865291cc9e1c68c4830ca0b76883c2a44000be144293030108806284468f66050fb9aae2619618980f090d12d9e0354880072f663e76ec998971bad6c1358b9754cd8c08a72e20ced0cec4f8d6f0c00a744c40a3cc8a67aab156e345160666f2e0486993164db55156d996f8d3a644084e547fe009230d51b337204895b314b8deac69f124644911364a2f9061e8ba94c1a38501904a773bcab009b2293b408a0d0d9d207c71ccf82883868d99260258755923490d54804e276a385161767caa5989b8c8a7607c99128a8784039cc29490cd11b3344a120c229d9ca4f98349111b3c026e9c0d3b7978408a8584294f63852b07d4e2d24c8859b2d5e5540f392500beae0fc834c48aae3a521d22e9a9e352f350ae3e0124b56a8246819651ac882ab1c82d3b36058ca0829322ba8bd3073419264ad961e462ac92f4118b600e358da46492125d81e3520011c75e6e883c2c00c53d8a23618a4a82c0a6491a326c515a230c11b4a1008e2a5ec69845182859cbf07a9ab4b764ac8f0f32678492749aa800182b1dc2b2238083342604defce030c446298a226a9f435eecb410c47a9da571a955e47a81cd953ea35614f07396a153bb8187193d4e2c5d5571398360555a9429d729518e68a28bfc96078b604a8c4b9a97bf198a50b918bc641832bc106626a8ede0f7ea3a2a03940c80ad68a20c0d56052b7a1eeca111c5ad039535c74f9ac4e68ce86ad1c30e053f500ebc10874535661d4ce562a2e908e23abbd38e4a80ad407311c66e43a83d5fb127033943812967d6d620594449401a628b31551d2099b903a98c910b3045e2284264c9c41ba34149587c809f35474ad5a8ea19a1c6eb829b9a531b90abaaa429f03640419a02208e2e500235a5ac85173594c2c811e026232a46c842481bc0a0039544c21a7dbaa025422832626b14f2ad8c8e821259572c2cf9b2a9baa445830cd49b2675e7962e3473c92f13a1060c10904546b69194f313a9481f26c84ca0d4d47cb42a34cb8ed0aa42089c10f09e604143069d5e352df9c0f18961c00f9b804f4a040c27f9a1c0804a08d34d1b07a9d42ea92ae02848a7034a7bc721cb953b490525108cf12ac541d78c1b9e96f02a100b908c14310204f942e6231a93e5613813a1151c03ac0a203d08482b312640080656c760d30ebcb12aaa5e49a325e2281735f0300055872167b8ceec3832f94443571f3817a10c94b111a0423922e5cd8b393e52054a9549958c54630ef8604e8eeebc42c1638f45121699649d4d33499992a18c035190302940653d01276dd2a3b83845893b34bac4db860ab549ac9090310de6bc9aa3674c24246020b04265466b6d09dca707374e31c90c807ad651691350edd07025ae8564d5610ea22b63b888e1885586f987d1002b2e88717cfc30a5c38cfa74d46e72e5d8c3e0515ada0d353eb42a8a76150af04787f726886d0cad0499d6705577c17dd963a8572009a9184d78652cfb7b934103195a3d8464fac40208a05a8a065c65a090d4444a63edd115349fda785cd728c031e0017a7c9982f8487ac11769afacc823b9460918201aa3e992812b8e881407288570d005e74d0f118c91832baf1605f2c71d998f4d411238626121e603721d5306e6270f0a3345a65e64881a384af1072880d283105242079e04d2a407f33a90175443146f3acaca9bf00aca8b30406e8289c8bc38bf860148edb235e005934c4d4a7d11d0c1c3884605bc00827338df9c68fb62448dec529a2e3385de44ba0514705781354306e1d0944f561a6f9a46a1285e8c940911200f1e3c6777b104f49c38b80ecb269b0a2c95076ae86955a050010dbc2aed8213652c10205b7c756851b9b250d3cb03a827d50012a070a65073f4f6d28cf532cb34410b813e43494fb47cb97226254b904e463f3fc65e8020a20714a13e28d540612344c09070c6260629059960177336b55949a3f1a04aa0ec4d17392700a40203a00e972858540162ad4c88822385098b6483525d5a616133e18c418e4d9b68e5a1e963a70011357eca7aa4f1a09312e616428a83bb5265c6d86ca22196a4109a334804b4aaa757204c1419d499ad81c518faa4676d530b5599c03ca22344ab2445c41d4c095045629e390142c327116208b83ca114a42036ea89e4b811b1ea84590421b182218e6042dbe067230b9aa9506814c4b4126e5950bca34207fb189343c01a1225a88619263cc1453d1296b6840aa6cc4e1ccb5df0694f1a1b9889140b892203c6b48810448a6581011792203ceae3a51472119e9e30c73e2f9b35856e0952d5c15319860d708514d542d28858ed4441162346038e53344cabb2d45c70b26905a257172c20c3eea85831233a668c136989cbe9a80419a34974aa50f8d0480d8a0dbdd2caac0110f0e3c3a75b88ce76b160a3926154893495d46cc4388bf56cfc40d3c413850b981549c8689c416a32bab6a16a7954d9728b170160d9d85048d75eb5ad004953335b551570032746cb0f16197c967040d1811d63666c55af125b60608861c9568349243a7cc00be00a52cbb0e3c99b25b3a6401b55300d21d04b82a928c1099adc4c084304ef3509352604488a4d8630581bed727a6236c9f3e82cd48d32516a81e900f2e7500b0ed0a5100232e21cc1d111db0306822d3c4a8b0085190b302447af386da6490b551d1ed4f48c9cdd60d313d40586985d23197b5c98ba9420cd4e832bef90552f48fc7095a6098a18414ccef506a239556238afcc967413447fcc3ce1b283ab809e314e4e2e6ddad51e8434325b636a95329549c5a19b15695eb2256682d3112e00dea0ac4e438e9488204933cb21e994a016454551166c62c151561d687a46424d5800a54ae254d3ecabc69ddfdaa50499fe62b969fa92a3101ad10dd7ad32535a843732219310f25341059a405dfe067cfaa3a896314d03f8c19719291238ec593b83709505404a9d2877983c81af951694412dfca0638326898b1b265c8afa10cc1830a2898d0f2e74781002c448e563298204648d37b3ce9a752fee6ea470d14004ae0a647e6f04a06811c8f9e13287d635c2df11017934a9b1f179f6aa216a6eb8f82a28503bf3c4541395a2ecb2250032174344942cc9260084a6f4b542e40244e200a3151a010da290f1b055560dd505885072c38c5460161d2d00e019336210529609118003213201717839bff628d0d58102910749155a00305d02b124600459456799121152de1500d1d02304da84f8b0c7d3093e1e7f288cb9613305532991b78a1693304722ceca043853a526650e8cf0d49c3c178106783212f0a25cd2628123c41448d2008e983148631c906b02469182a3e46189d3d3481edb191537cda74e3666fc49314292a2332052a5d912248665c52c09ac5a4f2c1f283292629cb4ecc0d1420b0e176a0d48b9f08b11e62c6cd7875a6a30c8a931354d4b75eb0922cd85ae2c6f948e44287d9232ca8cdc570cb118c8a75007d45042f0a0ea4af82359cca880811183150b4479b60634450c41e3072d0fb0cd9b340be812cdca5184860e490fc4c60aad72834a13a90b327c8cedf511f16116200e4d8c51903a3982d2c084c912194e6804064579d385038b2023e6983031a2898ab5e49c3a32065142f3a9535f0e64da9b526560e2bc7a9b8c7cb559c3a84fa5496f000c4092667c11c50c232c2d7439507244d318328d8e280eea9cf0f3a7c64f9c2abc63a63206ba66740a7b6dfd5883e93c422d120a9095eb15b3626296274bc50d5164f4f9527bd5a3c4a53d485855143d9a44c7d51a2664788ed143b4ca60f8f9232abf724c620848aa68a237611384076f06b0c676e346cdae14b4cc4fa4395b32902ca44201b0907d889420020c1da3f8c4800be9e09202192053c3a1b0834f1a833761b09f2032680a382932000908a60e3a5aca54e481d504c098a637152e4ce8f812e5f51cab04230f89002776996980ac33d424d0578010ac107822200a8371968244b5a0d0259e36a1695569ecb980c19e8c2f330e2da94c98cc3bec99a2097460b41989da02528515210e648004ea728169c367aa449d3e5c69e85421821863c17468e2244a1c398dd21649c805c2d1d9872356da24c0356cfc21d3c3ae8f800c6958d0e8f1eb0120d62c378c36316a82011303a3a44aae13246268719383019051c906668754edf559b3f1064396393a3868f4a983760b01a6356ae0b49cc86548edce1c0777621532b94c9a42c24c51a3316bca2b344f66234cf06255484c12b90473de3907635aa0d5c8c12b8d1d114c426d7d4e723c64aecdb91568850e340e74aa2ee0181a2b0e298bd4856ed685304600585d3ac165559a29030a6d3814c751999f166918dd0d7257c821674db2d509c8a6360c56f8d03327c8190e65320a71591345cd8e195550b488a462019b016d763690d561f1e1551e516a88908ae50259814d4c408e53591e2cb7504ada78d3242b75a708c08b0a209d82842af2a96a8290802f648e553a20c0c102a945794553183a6a4618a9c853e98d1c1a3c0c177a8025c14106e3a054c9839b31a8eeac201e8d98fe0900602b44884b599818a0104a93861a53ae052ad5d1b289c91f084e249a2085bdcd512063e5844115e3cc8b015a6944390842c84380235e929081e0a55749a76c8903c5c34a0105859a24f48814728f77026dc804e637a6850b91b65563684218c4ba950ac9223f67bb848caa2eb1dc8192e54aae8c1abb55047e84e2a409501f3d99e234893862413c3326c1986a41a62b75ac6dcd628d2ccdd759350a29b727154289d9c3010d9e26154bd234cdeaf247ce08194ad2b40030080a821d6289708dc1e30a0add1d45b448d4cda03b60e6876749a966ac23ed35168124510f6ed2e848b12ae021029a1e7ccf034de2a52c6249149564b1c985eae9c4031622c204a0cc7a8c1211e70c8d4b17b6a69b831b5126e4ce7f17c36f92c38a0ccd693b85eebdcbe7fb2aeff85ae89d140a3761577a07a546eff85aa8bb7ca3eef3ae0ac75357196def96ee1d5f0b65469dca6875dadad951d0b3b39b42f3946d0765b43ae5b0031370155cac4636202ca539841f1fb32c9d61d0e128d3a71e5e30a0b2b561d09530a72e4479031753090283a8cdf0102c21288e9d6005a295a1c5744a1f0678cb135c4ab64111a48c8c8098f3900a4e123486206b048d0f5f88a683823c22d099630b8d821a868ed405519a2f3234449b14e97542479e1fc9595382ca35757fcab8a0b931066c4786b5bb2e46e8ae842ead696a4dc9a0f46745410400523331b724a7fa24b142d86c19d2fb00ea140615bda26c72e06882820b04ae90e9c161c1a34f2d58371200b9197940328e21fb8d9cacd7914f610977b01b3befa02f8c77a774a5d3094a57afacc89625093b3b0f70c878edc9167899fd67c370818dcd4e0733ea8c3adb78da4ad9fedc094af55095be1d96f02b036d09bf32389d98525f2ad3998472f8cfe1cf1af2a663569149289dd117ea46a15946a19ed4922a64bab4e2ffddc97435e1da2ac4499d49e59d8d182c4efc21f1c783060b744b2d6f7f1e28305040c01f3200c53fc23f59172e5aad529902d5e952a446890afde183870e9c3567c070b932c5499222407ae8bd3b943768b43831a2839f0b7e2accb9f981c0004181017ec6fc80f9f9f2c3f6ca756b56ab54a43c69aa04699121407beec85953c6cb95294e8e00d1933a9577335aa420d1e102dd843e0ffa2ce8b39666d667ecd847d8a775dd8aa5cad4274d65502b9724394a44e8cf9e3a6ed088d962054a92203d62289e8e1a3158940091a18e8f5b043e0a0cf041f241e373c647acc807c8ebafd6ab55a63e71ca44e911a2417ff4cc6993a68c972c549e283112a447fce62973cc607142c4870d16e62438d8a3608fda9e00637b8c7b847b585e7fb45ca91ae529d3243d8b1005e25307ce9a3260ba64a9f2648911215518da4ceac1a127460b14243e64b09b7b8bd020015b81007ac4f48011f504f55cd72d59ae50950ae50913a5488b0c01da43c74d9a315eb45481b2c488901ed3a77b27238f8a121e34d4c1b5313890670d2dcf591e007988ecaeebac56d6509d2c455224888f1d3868c678c942a50992213ef4a4cfa632079e1a30569808b1c102dd0407780ce04933c33366c413c4735db866b1b28ef2a4a9d2234584fee8a9e3260d992e58a6384142e4075ffce63175dcb171c7458a3b223a64b0a3737bb0e080da1d34b3b03bc43bc05e7fb662b54a450ad4264b9114150ad407cf9c376ace84e142645516294c8e0cf1418d3695773460ac3021c2c3053b15ecc0b5d96170c04edad9d8d1ced00ebbeb5a0b962a529f385d82b4a810a03d75ce84c942c5c991213d2404d283772871c8a8e302451d11753e68a81027c181813a6864c73ac23afd674b562b55a74071aae4481121407aecc45963468c972b519c241902a44a470f7e32933866b44851e2c3063a15e2da1a20584ba3731666a413a4d3bbfc68bd52756ad4a7399ae65c8ab4a8d01f3c72d694f972e54992207c3cf2963966b44841c203060a73263898a360ceda9c0173cae680cd11cef95fad57a84675ba144911a13e78e4b84943260c172b529c2421e2430f8636973a6cc468914204073917e4d4c9919333410e03363432394639413999d775562b53a13a618ac408511c427deec05943a64b9c2a509208e183f3963866b03051760348080d7671e6243430906616072cce57afbf5aaeaca2fa2e3d4214a84f9e3a6fd69809d325cb94274a88f8d883f35c1d3662ac380182c30538757070263c8083008e1a9c0170c4e0148370be0b97ac55a6406da21449d1a03f79e8b44943a6cb15284cd22019d2434fbac3cd41e3850a13203860a01027a1c19b036fd4dea4057843f606c09baf37adcb562c55a53c619ae46691a13f7ae8b84113860b162a4e921811e2237e9f269ccb1c3462b4301182839d5cdb023637696e029489b931c29d20730374d3ba6ec162654a94274c9216190ac4070f1d386bc894510fb509d3058b942544aa541e50667b23c68ab23c282644b4d96027e7d606020235016dc28c6d826d5a971f2d5656519d2a39525428109f3a6fd088f992858a93236c84b0f941e591e7e6984186058a111cd860603337818d83046cd4d0ccc28a6c826cfaafd6ab55a64275aa14499121407ceabc4953a60b16296b9cac51b24648750a6d2671c85861e243060b736f795fda1cac51b0b6266d8d803562c535c05e7fb55ca52a158a13a6488d120df2a3a78e1b3566c070b122850912223ff8e2378fa983468b14243c60a0530357a63726c1c101350504a8315323a686a806d82b972d59ad4e8d02d5c95224468704f1a103870d1a315db05489c2e4c8901f7a705e738983868b1527caa8ab4070c09066eead8d411a036a6906a4294b239686184cd3bcaeb560a542630acd284f98263d5234a84f1e396cd0984123460b95264680ecf1d8e1e24033a3c589101aeae0d04440a3604d009a312295139ace552b962a527d9926312a04288f9c3769ca74c952450a932241aad3d799c421a3458a33264274c050e1cc5b840507906967cec6ce18cf00cf5cd72d59abaca54279d2440952a34483fce03103678d19305cac4871b284c80f3e18ea4cde98f142c5093324cc78c850416ec2830506cca4051833033634c3eac235cb55aa52a13c6192c4a810203e78e2b4495306cc162b51941401c2074777e0ddd170a1a204880c14de222c28b346a04c803262658e65866582bcfc66b13a450a94264a9014110294874e59ac07ce9a3260b65891c2c408992064f478ec60266fc45051828c070d15e2243c584086adc08033313247324432c05ed75ab0565945f565aa0469d121427df4d881b3e6cc982e57a63c51420448751a6526ef6ac04031a2438631766328b835303006cd6c0cd898af31b9975f2d57a94e85e28469d223458502e9b103474c1a3166c26ca1e2e448103ef8d954e690b16204070b7212c42c10c326064d8c99180062886282bb70c55a550ad4264b65502d8f141512d4074f983861d290f192654a932341f8a64f3c1d345ca410b1210c86ba307061da16b0a19585390ac35c172e58a844710243e99122427ff8d879b3e60c982c55a2343922c4871e8fa7abe3860c1760509000018603980c76746f6d0d1020d1ccc08881218201f2bada82c50a15a9be4c93187d41f4a5509f3b72d694f972050a92203da679ca3b1a5f5898f88081ce2dc282035fd4027c21fb62fc12ece537abd529509d2e454a34a80f9e386bca84d142c50992205eaad3d799cc11238517111c2ac4b53140e085ad8017332f62452fc05eb96ccd72a5aa549fa6498c0a75e9a367ce1b345dca80d132a5099220d56974c7f2ae4617172a4a7cd0603737e14117055d0c140830d6c5d845d8e57fb55ca522054a9325498d120dfab3670e1b325db854717204889e346fa983868b14223c68a83027c10197045c905c04907101c085c805d8ebef962c57a8487dd254e991a24281fad891d3060d992e579e28290244ef752a6fc8686122c4860b746f11b63440a0b625c096b12dc62d2cafebac56a74271b2f4689116425afe68c9a3658e963566be70b102458911213ef4a479cc36878c155a4878c05007d7c640cb012d6b04b49c8d8111b5047bfdd97ab5ea54284f9626394224888f1d386cd08ce16225ca122341f6e0275e961c345ea420e121435d9c040709b2ac6519709685ec98459825ebba158b152a52a03a65aa1489d1a1417ff2c86983668c972c529a2019d283ca63075e12cbdd8c16264068b0203701c2022c6b6865580060196201f2c225cb552a527d9a2c414a3408901e3a6ed48ce172250b95274786fca04a9dae0e1b31548ce890a14e4ec2150707ae10b8520676e5eb0aabeb56ac55a7406dc21469d120407beabc4123c64b162a51981c19d2c38a1e8f1deedd0c17565690e86061ce8a042b0dacb011b0722666c56845d8eb3aab957554274b90aa2caa7208d01e3b70d69819e3258b9426488654f5a651e7b2bd116345090f18e8de222c58ab8256254095b12ac62ac05ed7ffecc9a8dc8aa56ad4a74c931811f293670e19953565fe0b4f46e58b16322a55a844514265c8ffbe3d7ab470d2edd18ca96f9519a5be55ea5bdd7b9f4fb70ab76e7509b7d578ea84f7dc673c75e1bd3ca50bef495b78af19c3ef5e1586dfbde5137ef7f2e0776f09bf7bcff7dd5bbeefbb176da1ef1edef3dddb6b4e9d7beed4b9077d9753e79e0b3bf7f6f6f2a2ce3d66d4b9e7469d7b7bef32eadc8b3af79e4fe7def2e9dc73f19c7bcd78e9dc7397ce3dd8954e9dcd3da9b3b917759b7b4fd76deec56d73cf7db6cdbdd8dd8ba7ee9e0b7d954f776f093bddbd65d4cd73dd3d772fe9eeb97b4f77daba7b70ebee455f69ebeeed55db3d57afdd73e369bb279db67bcd69bb07bf4e186ef7a02d1edcee51a3cf76eff96cf7f29eed5eec6cf7a2ef9ecb6cabaf1e94fa7cf5de68ab7cbe7a4be7abe72a9dafdeb355be7a4ba79e53efd9c64ebd674b9d3af562e7d4a9d74e9d7a532aecd48b3a9faf53cf65b671d4a9e7eaedb94ebd2afcc64aa7d2a917475b38e9d4d38bb6b01b4f5dbd2aecea45df6a1276f55caa5eecea3d9d4d572f7e525bbd78daeac1afb4d56b4e9dd1562fdaeab97acf564fcfa5325b3d2895aa6cf5e268ab6cf5a653f7e94ea954774a75993035da26616aec4ea554d8954aa9d1574a5d3edfa694fa74ba7a51eab3a54ea9512ad58d526367940a855f3c67941aa52e9f2f5e940a3b5bbc28f55d46a954f7a98c52a3d4f6f974e124945a7d32a9aeb41abf7b713c75eec551e75eec2a9d7b71358eba7bb1abf774f762f719c3d4aa9b0753e3a71b8d52e3364a8da9b19ba4c655386ec654388ea754388e5d29940ac7d527158e5d2a1ce729a970ec3e93d4178eab4de90bc752271c439d709ca774c2b19b74c2f1b375c2f132eac2d5168e9fae5e0bc7cd690bc7d2168e992d1c2b9d78782d1c57df38baf7c6b0bbf7c64bb8dd7be378ea84a96ffc6ce3379e4edfd89d3adf187ee377d946e137769f52e91b4bdfb819bf6ffc7cdff88d5d2a33fac66ef48da16ffc46ddbc378edda7f38ddd3786dde772f9c6d576f9c6af52d926df389eb66fec3e63671c2f5dd8194b9d7135ea8c5da83386dd24d419c74f670cbb4c67ec2e9d71dc8c93506a33de7be166ecea39e166ecba70338e9b4ceadb8ca7ce66ec366317769b71157e5da8db8ce3b619e745db661cf3b9713c756328ecc6d1a81bc7d1367e3edd18daba7153d9bab193af8ddf378edbd88da76d9c376d6357dac679d136ce7bb6711c759f6dfc74b631b38ddd679eb28da554b83a85beb1145a9d3edf24b43a6d2a63e7de941975ee4da1cebd698ce7dc9bc6aebb37855b776f0a85dbbda9b4dd9b4aa1eddede943a8d9555570fa64e612a4c9dba4c983aa54e5d983a75a12e2ca54eabb02ba54ea7d568943a8d52a7b00b8552a7b1933a855b26750abbee72499d3695d469bb97a44ea953f7598da7f1140f8f1a4fe3a8bba4c653f7c96446f39c703c8d5d178ea755a6abf7c6d3e7fbc65337fac6d3a6b285bef1344ff9c6d33ca5339ebe52379e42dd789ad7baf1b4dac653d8d9c65397d9c6533c3ce7b28da7d3a70bc34e2a8fa9dbc375a93ca62edc52794cabd22933ea84a5d269b585a5d3f8954e63f8954ea3ef2b9dc2efd3f94aa7b1533a75f39cd229ec2e9dd2a9ab7436a5d3e7d3954e97ae2b9de6b5ae741add6ba5d367eb8c5be9d4855be9b41953dfa994fa4e9751ea3b7d52df690cbfd32a0cbfd3e8fb4e99d177ea465fbde73b7dbed3a5f3f94e61d7b97cbe53b87dbed318ef9db6cb779aa77ca7cfd6a97ca7b0ab54be5369fb4ef7dee8140fcf1975f3dae8344fd946a7cdf87da15337ef854edda7133a8de1163a6d4ea9cfe9defb8cb6ccf739853a9fd3a9bb743ea7cfa9d4759f5368fb9c26dbe7f4f9a4e64d63d899378d3af3a6cfa7336feacc9b4eddb8cd9bf239a76edc5263e7147661e79419754ea74fe7b4fa7c3aa7794fe7348eba4fe734ca744e5da6eb9cba4be7344fe99c569b53f78987476d4e9954b83995429d7073eaeac5f0db9c4adfe6347edfe6d47d9bd33ce5db9cc2ae9eb339953a9b5337ea6c4e974fd7d99ce2e13961b7397d3edde674e936a72e1ce3b5cde9debb6c9b53293576a7ee338edda9ab9c46dd29fc3aa3ee146ea34ea83b7d3edd699eeb4e97ae3badc6ce377661a53b9dc6ad3b6ddd69920a2ba751d7859553690b2ba731f5554ea3af530abfcae9147ea753a7d2a99c3edfb7a99cba50b7a99cba515739554e5db8554ea3ad725a6da7ae5e3b7599ed94da4e5d25b59d3a9bd3376ea755bca9336ea7cb683b9dc6d4673b8d9fed34fa429fed74d93edbe9d3d94e5dbc763a9dbad1653b9d2edbe9b385a970b5dd8b52e12815769f54984985dd251586dd64920a3fdbea324a7de12693fac2ae3b7d61e8fbc2ae33ef7d61bcf7855d65b485be70ece6295f389e52932f1cbfed0b2fdb17865d3d27fc6ca9b113ce9b3a61f729953ae1f875c2cca8135e3a994e386e329db0fbc473c22e73e984dda5136e2a9db0ab74c2d1379974c249270c6dc6d526bce73af5f4a254178e5b1776c62e1c4f9d5317769f492855397561386e5da90bc35157faba701c75e165d485975127d4855d18ae3e5d18cf753e5dd885f9daa70bc72ecc7461774ac5736168ac749f782e0c2f5dd8859f6ed285a3efd485e1b7470befb570d4d56b61d86db6b00bb7f0d2296d6129b485abcf670b479d2dfc74b6f0eb5cb6709eb2855d650b47df57a96ce1d8994cb6b01bbf541e3d9c541eb193ca234fe9a4f288bece78ea5279c06e0cb7541e506a1c6da93ca83c964e680b57a5eeb3470faa34a64a9b53aad49dc254a93b7da530555a8d9d30555a954aa9d2a7534a95369551aa34eacc9342a952e9932a7d3ea952aa74498d5f580abbd2e90b4bab31defb425f581a2bdd1d2f2c8d9d782f2c75a1ee33f9c252b787139646dfa9139656e116ea84a5eed2094ba5b08be7c2d258e95cbab0d49d3a5b58ea2a9db1b285a5b0bbdc7ba5d51876f55ea9f48ddbf895c6d357ea3e93ce2955fa4a9fef2bad465fe932fa4a5da5f3f94adde72b85dbe72b8ddd570a755fa9cb8c529f5226f529cd53529f5297b9749f5269b57d4addb87d4a9fd2d88db64f69dba38753da54c64ee9f38da74ea92b754a61d78dbe4e695ed4298ddfa753fa7c3aa5d1d7653aa54ca7d455ba4ea90b5363a553aa7446954ee91b6d9dd267ab744eab4da93b6de1a6f48ddfa6d48dbe4d69ec4aa3ef1476a571ac74f160570abb52a92b759fd2d7953e9dcaa82badc6cf36ea4aa3ae34da2a9d4f571a47db69eb4ae1d695c6d468eb4a5d65eb4a5dbd56ea4ea9ad342a7dbe70ec8c5b69336ea531dc4ae317865b691edc4ae3a8dbc2ad1476a5ad14769b71b4953edd682b6d97d1560a7db65257d93e5b29ec94bacfe5b295c6ca56ea46df1eef1b759955be1776a37b6f74ef85f5de67abf7ba4be734a6beb01b535ff87d9731f56dbed1b62985df38ea3ae137da32e17709bfcb377626e1f775a7af54ea94be5157fa569fd1f78dbecee8eb465f57197d6327f4553aa5d0eaf375f59ccf77f97c9fced7553af1f05ed8c5c37bf1f05ef85dbeb09b7c63e51b6d5de50b5395ca37f9ba3055394dbe2ed3f94cbeb1d2dd917cab6ef2cd6bdf981a75a73055498deebdd1a7abf746a36efc46dfa83b7da3cd187ea3ee73f9be51d775a7ce37ea3e936fd4553aa3319f1b9deeb951d8d573a3cf168ea96e34bae736a56e341a2bdd27d38dba7aceb865bad1a5eb46f394d168359eb6d168d499276da3ae9eb38d36e32ab40abbf1b40ac57bbad32a349e52a14ae7940a85be2fdc9c52a150aa3ba542dda7724a85569fd227151a75e2e151a14d2515ea3af55ee894fa42a92f14fac64e2a8fe90b65469d51f885baf00b7db6f00b8dbe2fb41947dfe80b85c26fec8cbe5028f485569feef285ba4f67f285ba3035e67342972e9f13cae784ba796d3c7542a75327b40abb5327147e61d809759fca167642dd981a7542a154a813aa74429dd0e89bf77442e326d3195d3aa1ee73b97442976f1bbbd0e6d4855661d885c64ed8855695b00ba5465d28141a3f5d6875f93e5de8b35dba5065dcba5017a64e5b171a6d5de8debb6c5da8dba385c62d94cf09c72db419b7d067eb84ddb8853695f1b4854ea72d346fea84e1161a479d700b8d3a9949b885ba4f690b8dbece69b485becc680b75a1d116fa6ca1d016eae6b5d0a8b3853e9d2d74e96ca1b11b65b650a593d942972dd4854e954eb8faacc2543eeab3a98c529f701ba53e9f2eb36532a9cf6a9e92fa7cb6d5f7e9eabd4f9719a5becf25f57d5661378edfa7f47d9fcce8fbac3edde8fbcc53be4fd88da7c9f7196ddfe7b27d9f4bb8ede17c3ee3d8f98ca7ce67f4753ef3a2ce6712ea7cba79ce678ce77cba78cea73b8dba4ae7b31ac36ed2f9845be7f3e9eab94fd88d63f7197de156fabacf69f4197da153a7fb5c32dd678ce73e5d98aad7ba4fbcd67dc2eeb2759fd51eed1376abed337652a77bed33bad73ef7da67abd73eabf0324a6d9f4d26b57d469d71fb94beb1b47dbacc96ca8cb64f29b47dba79edb3ba6c9fb0bb5cb64ff84db6cfa79b6c9fc9f6b9f746f3f2946f34cfc57346f35c379ae7dc73e645dd3876e6b9b1332fea3695b1332f76e64da7ce3ce8bb64469d79cba833afea4697cebca5332f4fe9cc93529bcad8cd93ba6e5ed475f3de176e99d1362f9e5277e445a93be0d719a5ee709fcc287587144adde12a9dd41d2e7349dd517d7754dd284c7d77b879ef8ea8f3dd917c773cdd3d7747f5f974774ca3adbb634a7d9fadbba3478f7607dcee805b2ab3dd11bb79ca7647157ef59c503776ba71fb7ca7ce65b47d4e9dd11776469d6eecd48b3adf1876e368d4f97cb6f134ea7461a7741a75469d6eb49d469d55d849e51175c654a9f28d469d6edc42a3ce2a4cdd1175c64a77473476bacfb61975c64ae7132fea8ca32d5ed45985e329751975c2efbb8c3a5de8ab8c3a9d4d65d4e94e9f5429d40975ba512a14ea74a751170a75bad3a91b7d3e9dcf96e93e9fcee7d3e93e97adbb74465fa5d3553a974e38596d2ea36d724a6dc630b55985616ad37d2e616a338e529b559819a536972ebc8c529bf00ba5369bd1164a6dba4c6a33496dc2d4b7f974e3b7194fdfe6f46dba53f86dc22f0cbfcd28fc365de9db5cbe6fb3ea46dfa60b7d9bcd6abb743edfa6fb7c9bcbe7dbacba79cab7594d26dfa60b3b9b5267338e3a9bcfa7b3d9643a9b2fec36a36e53fa749bb10b7dbacdf7f9749b4de6db74994bb759d56b36e367eb3697addb5cc26d8fb699b7d7365dbdb6e9eac16db33985dbe6126e9bf09b84db66552a6d9bcb68db84dd780a6d9bb00b85b64dbc67db849d6d337626db26b4ca8c5299701b3ba9ccf8e9a432dda593ca9c4e5d2a7309b754e6de0b33a5d41766566157f9c2ccd80933f15c27cc5c3a6166d47561663576eab530733a6d61a62b6d61661c6d61a6ab6c6166b28599d1bd9729754ea72ff3e94aa72fb37d3e9df0cb74a7efcb5cbe2f73f97c99d3a9bb5cbeccb87d992ef5c9dc7b9f4c57ef7d32abf0fb6442dff7c97493ef93e94ea550e793e92e9d4fe674da3e992edc3e99cc65fb64ba7a4ee61376325d26d37d32994e668ce764c6d1d6c98ca76f73ea32dda8931a7599ee338eba4c178ebacc29d51975994fb747cb7499d496c974e396299db6cc69cb8ca32e146e994ae7136e99517799845ba6cb6ce196296d992eb4655661f7f96c9955bef6d932a3ce9619bbcc65cbacc2543c57d946a354bca74bc58b9d54182fbaf7c278f1f485f1982f8ce732a34e186f19759d305e73eac2787114efe964b6301edf8b07bbf1f4c57b3aa7d3170f4a855f3c374a8de1172f0f7ef1629709bf78f1d4855fbcf87df196ef8bb7f73e9f2fdef2f9e23d9d2f1ef3c59b52952f1eb47df1aa4fbce694fac45b3aa94f3cd8dd7b9f78f0fb3ef1f294ef132f6edf279ed4f9c4c373dd271efceab54fbcb87de235a7ed13cf85b64f3c66fbc4e373e239f162bc67ab9c3af1a0b013cf859d78b0cb8c3af1dca8136f1975e2419f4e3cf7e9c473e2c16ed289b7e7e2c1ae9e8bf76cf59cf1d4c573955117cf7db65017efe9ba784bd7c5735dbc670bbb4b17af0ab75438e9e2b9b1137ef55a3c2ad319b778b0db8c5bbc671bb778718bd7e241e116af3a6de3688b5755465bbc688b37a5bed016affa74425b3c17dae23d9f2d5e3376b67871d4d9e2b9cb16af1a3fa9ca16cf55b6784a279c6cf1f65e38e9565db7eab670ccc7e74e5f299f1b75b64f299fbb8cb6523e3776f2b94f279fcbe7ba53a71276f95c774a55f2b9eed28d9d4a3ed79d4e5d259febba7acf57cf75f35e3df7e9d4735d65d45d3a9bb1ebbaaeb2da4ea7ee0bbbeef2855d77dac26e0bbb52279587fb6ca93c5c77f94e9d52d78dba51b7a974c25137ea56df1d51d75546db66d475a34e66d475992d33ea5699b01b75ab5037eaba53f85d46dda8bb8cbab0bbf74aa16ef57d4aa16ef475c62fd4755d650b27a16e75f926a16e1edc26a1ae3b7dba6eec7cbaf01bb77a4da9fb74e3a8d209c3eef2e9eebdc9a7d36532dd187ef1f05c376e95d4a51b3b97aecb5cba55a5fb36956e75dabaf1b475ab4fe7b4759b31dcba51b875ab4fb875dd27b3756197d9ba7870bbb7acc6d46553195397f194ba74a3d465124a5de629a9cb2abc8452e1a5f485975227bccc8b3ae1e5f3e98497319e135e425b175eeeb5f052e98ca72dbc6ca12dbc8cbecc165ec6782dbc74f5dea53b7d97f0fb2ee137fa2eab6e5ef47ddf65d4d9943edfe5f3f92e99ef52f92ee13756becb6a8f1e4e3de7d28d6157cfb9749dcb6afb944e9dcba973399d3aa153e7b239754e9dcbe5d4b98c61e712a6b6d337ea5cc26e34ea5cb650a8fb742eabb133ca742e9f6dec643a97b1eb5c3edda9eb5cba4ae7b20ab7cee532fa425be7f2d93a97d01666b6cea51bbf7aeed2553af5dc65ac746377597de178ea2e61672b9dbacbbca9bb8c6177eabad5982a7597cd58ea2e63b895bacb6ad45dc6d367eb8cba4b77ea84bacba5ebc24c7759c573dd69d4c57397b0eb2ee157e93a95ee1276935057e92edd65ab749753279c74976edc26dde5b37597d57619dd6b97b0bb6c4edb2533ea84dbe5d25546dba514da2e5d660b6d97cb76e9c65465f47536a754a5ab0753a94ae594fa3a61aa524a554aa94a17a6c64faad24d5295cf369e566165155636a75458d95446a9b0d27dba532715563e5d2aac7cb64e2515562ef75e18564ea72fac94beb052e98c9db0523a75c24a17ea8495b19ba774c2ca3d1756e6b92eac54425b1756567bb4b0f2b9d7c24ab8396d61a51b6d6125b48595315e0b2bdde7b2859579ca1656baf15b7d9551e794fa2add294c7d95ee534a7d9555b8a9a4becae81bc7af329ebe4af855baf0ab7cb6f0abac4a5f25ec4aa5aff2f9becabcf755bacaa8532ffa2add68f455465f25148e95d465f455c6b0ab8cbeca6ab47da1d057a974425f650cbf78d057e9425fa51b7526a1af320aa53e5f25fc3e5f65d4f92a9fce57e9ba78786f4c8dbeca57194fdb57d954c6d4a71276e329f5a99442a94f6592fa5446f7dea772497d9fca66fc3e95ccf7a9cc53be4fa5d4f9542a9d51e75399843a9f4a3c3ce75399a7743e95ca3cd87d2aa3adfb5456dba772af7d2aab784eb87d2aa5ed53f974ea3995d5d8a98cba3d9cb153e93e95b053197da16d34ea54c22dd3a98cc2d4a6322f4a6d2add679e92da542a9dd1176e2adde9fb3695aed2f9369555370a75369578aeb3a98cba794a6753194fdda6b20ac36e5389e73695eed4759b4a69db54bad3b6a974996e2c6d9bcae9db3695af530a6d9bcabc67db54c2ceb609bbca67ebc2aeb20a53e3a8ab545661f7e92a9951e7d3e92a5dbd96da2ae32693da2a9555f865ba71ab6c2ae356c97c9f6ddc2ae356f96ca9d356e93ee369ab7ca3ce69ab6c4e5ba53b6d9531dc2aab30dc2a63570ab7ca25dc2aa36f126e9570ab8c3adb58da2a9f6dec94b6cae85b8db6ca69ab176d95ee1b6d95d1ea32da2a9f6db455465ba514da2a5bd885b64ae8b355e629a7d458d92add67b255469dc956e932db64b255f6e8414dc26e954a4d56a7d4e474ea469d536a724a4dc653264c4d46dd254c4dc26e5e949a749fcb283519bbcf273599f7a426934f6af27db67878d46475b9a426dd6732494d36a7543819dd7be1249c84be2f9c747b445f3819753e5fa5f285937953279c4ce2b94e3899a774c2c9e4b275e1a4abd7c2c9e9b48593cb680b27a3ce164ec6c9ea9be47b93c9e474fa26995127fc269379ef9b9c52a36fd28dbec924f44d3e9d6fb2ba7c9371fb269770fb269b53ea3309539f4997fa4cba53eafb4c42dfe9f47d2697effb4c2ea3ce6732af759fc978da3e93b19b176d9f4917da3e93eeb27d26f394edd3996cc6b033b9849d496772197526dd3c6772e94cba4f6555e94c2ea36fd54d56e3a99b8c93f1d34dba7aaef3e9265d3cd74dbad598dabac968eb269bcad64dbacf386e93b19b376d934ae7b44dbad336f97461b84d469d2d136e93d5a70bb749b84dc26e34da26db681b6d93ef9b84b6c9e7b34d56a3aff2d926996dd2652edb64f455b649f87dba4d659bac26dbe4d4c9d7eeb54f2ade5eeb42dfa9bbd756dbbdd6cd6bf7da77d92a5fbdb68d42a931b57d636a4b6de32995496d63e792da52e3d65d5263671cb7cba81bc76d9eb28d5b37769fcdb86da1cd78dac653e774dac64f6a3b9db6b1d2954edbbc699b07bf7bce186e63658b07b77b2f0cb7ae9e1386e1d665465b186e9751ea0bb75528dcc22f146e972e146ea170eb529970db465db86d5db8553a6325dc369570fb74c2d2d6759f52690bb7ae54da5699eff395b631dc4adb6ab4adc6ae932fdaba541ece38dab6d1a8bb378db6cf961a8db6aefbcc8bb6cf16ea8cb65598196ddd2733dac22e33dab6f0dbac3edb68bb74a754681b47a92fb465469d3d5a680b53ddb885b6b01b3fdb77fa6cdba6f4d9bad1f7d956dde7b37d3edba8eb3edbe7db7c95cf164a4d3e5b28dc3e5bf73975c2ce1676b65067ebba30b38da32eb37599edd2d9c278ed127ef1f05ad8d9e2e1b54a67f285ddd6553af5966dfca42edbd8095db6b1d2b95cb6cb651b4bdb653b9dba70ac6ce13756b6b1b255b64a673ca5beca76e954b6ae9eeb6c2a95ad52d9ba536ab25dc2d469b28d956d127ea7c9d6d57b93adfb4cb6d177196d936de79cd96794c3d475e1bacc367661d624c7ff1d278b228a4c4a8917767b3ca7b133c986e76c4ea7b00425dc9b043a09716d4af7d92aa76d645106fd12966e4b16454a1685cd7db2b51cc8a0a4fa2f614a4d924159b3248392e43f8c9341799bb66c1148b04ddd0e530e4b17eac624a06e4c62da8c9d32c89ec8f95fc020f25480889fd4a95319e5f016c36df1a448e6e48fcb6452a711a66d73cf4db1e7a620f19278beef0a6787e7fb9258017563122baaf19244deb47d91376d5f3cdf7785fb5c92b873a1ce1887db1b9b853aaa8dbc690bb5b3cb9bb6285cf8f5d0ebfff0218ebad029b37d86504e9d285c3784d49db641dfe51232262e9313677b633636e9bba4be344eb624d6cf6c9f786c2fd85cea4be307dcbccb41b6c4ed8793e026e14d0f4407152d5eb8d0d1ef353d8525b8c9178ea7716d51e71376a16043863d64089121438a439ed9216732c48993bf78e2ff26434e1c3284c890214e86fc4386341952448d2cc9a6ff7112dc24b8b541df25932cc9140306a653370a7d97d116766167a77497aff2c58b9208e14edbe68a0c77b02be56ba1cf367ef95aa83b6d93d369fbcc001747bdc0d742a77d87ec08dff19c1674dcc12f2c611a3ba11aa0cf76da3e3dc0ee8a258916b113ea3c91a76c6317cba7eba4e1017e611884cb6ca75317c574ea2a5f7845dc42e137c4b2edb074f56077eab6705d388472ea84dad94da36ede1bdbd94d63670bc7767631fc4aa5d4e99d0b6d61bc29356e6317ae32da3edb0e7193e974f7ee9e2d3556b62f5e94445319b7d2a9f3433c7d57b82ededdb4da4aa7d3f6a98c9b4ca7bbf7e245493495712b9d3a3f54e1376e97d116c5b38dbeceb8855da98a670b85df14d369fbf4d054c6ad74eafc30adb62bec9eae9efbbc8bbece58d94ea32d1cdbfd7ff0b791ff3c4e5604c37fbabfe1fef33859110cffedfe7efbcfe3644530fcc7f03780ff3c4e5604c3ffb3bf83ff799cac08867f0a4b80ddd879076d5d389e4e70992dfcc6d3094a783ac14d829b04bab8b6187ea552eab4cd85b630de04bc3737b7b9b7369984835b5278c3a36b7b9d12a66edcc24a097cee32ea9ca084a713aa703c75325d78c2cb845be504d85d3e9dd4e40417fa3627bc29a62e8dffc4931559f0a8fb64cbc0b6744297ee33d946412cdd67b29d3a3f445fe734eac67cee5d73da36efdab85db6b10bbd73a12d8ce72e5f14787378722d05bc38b8b937b79593c373e79214e8e05cb816ae0ecfadab8bc38bab53ba72ed5c52d9becdc5cde1c925e5e8dce8e45cb9389742dcd2cde573bb86401f1a4dcdaf21981ad39352c1f5192d7cd8386475f7e1d7284be9a3de949c585ed401ef2134fde8261f1e7d0d905a1d2204af2f4ae180ede547c7a168a1c0d66065740237951a919c84bb90820485e411ca667d2ad8527aacedaacd88fc263dd57ff03c8179025ee557a4a66436545dffb2844a932902d517bc18ca0ea2b87d1422086d28c5f141b4315dea4c9f263b8661b160f2f0365b7a4f63c8ac8d680d7202554ffa8ec5cb7bc4fe3498036f7e2155a1136ae528bbca10d76575b2e40731a0be2001150bc4cfa56c9769ad4b1582d24af8d858180a4e6437abb208c5e6f0694383d464494722579a32d5573d3fee688e1d3b424eb0dfa6253ad4aef65a9403d85d0f1a75a1205358578e1c7c8e81ac16f521504fb932236798f18350a081e5f254f0d78fc3db28b5bc8e23016d0bc459837806ca24780062e5a6b4840bfe38ca12d89ae45663c1d7f9ebd599c194767118691b2ba4bc0eaae39f7e9e1a5506042f54614f2b00d43c1125011acec31f565321b1dba9412b6ba0e3e9ada8706d6042acb613b183b56141549bc1d5eb6d0a0b0dc02fc3ad7e0279c80ffcf49c9f3fb0d03370c18fbc7bce497e20a93751edbf5e781b633cfb2d7813d1fe6bdd9be8e4bfb679069ef891ef335be847c63d5f47134bfc57e7fb087cf6bbf4fc104da4f45f633db3837e24dc59a1f35f83f1363a9ffd2abc8bd4ffafcc335beb479a781f153d5fb5bc8b09fe3f156759e17f7474e097897fedcc7347fa73d8815f2efeb534ef22dafff7e1ecd7a67fadd4db18f7ecc73e779b0c7cf023db375886e73f00cf1ff4f784b711cbb39ffb366679f6c37b1bf93cfb31792e2afa73c9bd87b0fe2b803771c77f65f21efafd5701cf6c971fc976b6cbfcfdf73eaa79beee3d0fd1fc6e71dec709cf7ebdde442aff75cef3d0c7ef56e3b928e9cf55e19925fe6025ce06fdfc6b60cfc3f7774bf13e2e7abe6e390bd4f423e9bc8bc8ff8fc4fbf8e6997dbe5a7a1b5d3cfb21781b5f3dfb057a83a13d5f553d7f122becf2afe53d0f95ff0156efe39de7eb91f791d7f335d2fb48e4f9cae2b98bfc6d7dfe8e6cecb7999fb711c6b39f826716f987c978ee4d7f367b0676f8913b9ed9e78f3c3eb7dddf3e9e9fe2ffab67a3f18d56f79c63fcc00a6f6280ff3af72e32f9fff23c0f3dfc07aaef2392e72b8ce7e0dfbfd6e07918f71f803eb36e7f1898e7fce507c23a5068e95f3bf23ec678be2e78ceb57ee395e7afeabf36e7f939fe5f9f87467eb7e4bb68e5ff1bf4fcb4ff91dec5bbffefc9fbb8e5f9da7c17cffebf0defa390e7ab8a3771d37fc5f53ee279be22791795fc7f779e857afeb5bde74ef467e3f383fc5d7c1bfd9efd16bd8d3a9efddcdec636cf7e3ddec521ff1f9c371882e72bad3791edbf6a781f333d5fd3bc8dcd67bfbab3c154ffda817711c1ff97e26d84f2ec87e31918e14726cf7ee5f8d7d8bc8995feabacb3c148ff9ad933fbe747babd89c9ff4ae4393bf8d9366f6283ff2ae24da4fed72bcf1ff3b7dafbd87cbed63db3f08f0c7b17a9fc7f81dec72bcfd7e53330c08f9cf1fc35e75f8bf42e4ef8ff6a3cb33d7e64d9731ff91bd5f317a47f0dd4fb28e0d90fd5bb98e4ffb3f33c44f01f48f0dc6bfed6f53ece78be36781fc93c5f793c0fabbfdb8c77f1c4ff577d1e7afaddaecf79d56f1cf136e23dfbd13dffd1df15de60fd7ca5f4cc7ef809007866ff1f153d3f4aee037fbf6fe297ffeae75decf2ff297a175ffc7f449ef38e1f48e86d14f2eca7e20dd6e1f98fecb94ffc1de9b9effc39bf89a6fe3ff639b8a58d199efd00bcc1063c5f533db3177e02c27791eeff6b0f1486fad7943c0bc5fe35b7b771d6b35fa167a0de8f2cf22e42f9fffa9c0de2f9d78cef61f15fdbf536fe79f67bf2265affbfe01b2c3f5f2b1df835f7af8539db7f7f8ef0361279f6637116b8e847be79ee1579a8e23fc0e47948e5778bcf0a11fd6b439ed9b01facd373f0c08f8cf4063bf07c9df536b279f6abbe8fb79eaf899ed90e3f81e3db08e7d90fc833a2e7a2ac3f578a3751c37fcd71b6a3fcddea6c2bffdef426a6f9af889e738f1fd8e979f8e977fb3bcb267fe4f04d94fe5729ef6394e76b8ee70ff80fe93957fa8977ef2387e7ebd8dbf8e5d9ef79f6cbef5fabf5fc65fdd754bd8f78cf57ba7731feffc8bc8964fff5edf92bd0bf96e93998fc91a6dec458ff1fd91b2ceef98f7d1e2af80f2c78cef10fb4f42ebafd7f36dec520ff9f9be72f53ff5aaaf7b1cff3b5c9732ef413e59e73fef384b341173f32d4d9af22ffda9d3791cb7fddf3268af9af81de4703cf7eb2de474fcf573767857bff1a8eb3414fff1a81f7f1d5f335d0f390cbefd6e37dc4f47c45f33e7279be3a9fdfe7ef086fa295ff5ae77908fddd4e3cb305feb016cfc3bbff40a9e7fff89bf82e96f9ff24bd8f7acfd7106fe29bffeae8997df523473c0713fc4849cf5f75fe3549cf39f90371bc8d299efd90cfecaa1f19e27d94f0ecc7eb1918e54746797eadbf633c7f85fad7ac6fa2f3bf2e791fd33c5ff5de47f8f9dae15d7cfe7f5c0efcaaf0af897976f43ef23d5f473c37dcdf7bef6296ffcfd0f397a77fcdd41bccf87cf574f60bc8bf56e76c70cdbf267c13f1fe2b923711c77ffdf1061b7bbe8e7a062ef9914e9edfe9ef0fefe280ffcfc3bbe8e4ffdbf30c2cf22397bc8da79efdf0bcc14e3cff15781b553dfbf179ee3a7feee760a27f6dec3da4f55fc9ce361ae097f35f7bf326aafaff866f62dc7f6df1dc0bfee6f12662f9af77de4659cf7e84dec753cf573cef63f1d9afd3f3a0b35f36feb535cfc55cefb109cf2ca91fd9e16dccf4ec97e67d643e5f29bc898ffe2babf731c5f315f92e4ef9ff00bd894dfe2b9be7def07790f710c06fe0c159e1a27f8dc8dbd8e5d96fc7dba8ebd9efd19b98e1bfe2787e9bbf0fbc8f759eaf459e87407eb71b6f639f67bf266f62dd7f95f15c74f4e7a27b1345fc57bcb791efd96fc473eef4133fbd8bcbff8fcadb68e1d9cff8fc0dff513d67507f31ee3ddcf55f0bbc8fd7e72ba3b771c8b3df8ab341e98f5cf5cc86f99107de450effdff35d34f1fff1bd89c6fffae02c90d28f94f3260efaafa1dec701cf7ea9de4749cf5731cfc1e58f3cf5fcb5ea5f63f52c3cf1af8d7866d7fc4806cfbff1ffd6bbe8fcffb2bc87bcfeabdadb48e5d9af7d1f453c5f053c0f5dfc07e03ce71a3f90c5734ef3036bbd8990fe6bab37f1ff75ed6d8cf3ec17e44d8cf05f4dbc8d959efdcabc899dfeebf57d0c3efb617a06befa917cde4625cf7e32dec354fff5eb4d6cffeb9077b1c3ff077d1f753d5f1f3d0f2bfc07a4cf9da0c1143c5f6dbd8993fe2bac7746fb5925678b78fe5c119e3fe76f05cfc1283fd2d6f3d79d7f6dd2731ef303659d05b63fb25ae8396ff981aede443aff75d2fb38e9f93ae61918e64766790f9d3f0207cfc1013f92d1fb68e1f96a7c83b53d5f779d0d96f8917def2298ffafd1d960861fb9e94db4f35f2bbd8b70ff1f8e37b1ca7fa5f336c2cf7e1d9e59533fd2c37303ffcef12e02ffbf0967856affdadc5960a41f19e76d1cf3ec273dcb4afa9115de44e47fc5f03eb678be1e78ce877ee28ce71ef0f78ee75ce207b2ef22f3ffbb72d668f6a6d4bec180cfd74bcf6dfd3381e746fe0d3d9b817f767b135bfc571eefa2ddffe7bec184cfd74c6f238b673f03ef23a9e76b9d67e0961f69e540a1a67f0dc99bd8ff95edf977fe76f0dc4dfe5ef50c7cf323cb3c0fd5fe03c06736c34f60f82ecafd7f77ef6391e76b8b37f1c27fb5f10c7cf123a7efa3aae72b9fe7a19bdfedcebb28e5fffbf336e27af65374f64bcbbf56e87d64f47ce572e097877fadcc738ef203ad6fa29bffdae86c70c18f9c749615f223cf9ed9047fd8f47d047bf6fbf4268afdd709ef228dff2fc9fb58e5f99a7c2e96fa7389786613fdc8b9e716fe7df70663f07cc5f526fefd7fc87731eeffcbf12e96fd7f199e73829f95f23e4678f6d3f5362a9ffde29e8539fe35166781827e249b3711c67f8ddfc73dcfd7256fe38867bf01ef22dbff67e2f975fe6ef036f27af68bf42efaf8ffd69c1582f9d79e6781cb1fd9e359d8e05fabf02e5af8fff09e3bc4df729e7b56ee207f937ace477e60a8b35fc07f8dcabb18e1ff93f12632ff6b92e73fffeeb771c7b39fdd33f0d68f04f42686f8afee335be947dabd898cfe6baaf7d0fa5f83cf4ff337db5961f15f93f03c64f3bbd5791bb93cfb399f73971ff82a3fe7138341213028ec7f5dec39c80283c2669b15760e362b160403068544e2810f0e8941e0573098d916f6017c0959a150d8dd4021b0d800c488c5619ffd3b0b00d0c46c362c3e7f65600fc34e6ca0901d16e8ccfefdaf668dcfb9f389c7dcff502864df6342f6eb281c12870fb2ef2c20ec67c18c0f2b3e77be3077e7043f9065915f038c39c0cf7e3dec6770e07f3c10ec423036837dec78763c10ecf94076783156a816005804703200016ee0cd7660dfecfd063e78a3070144b1af07099cbd82e1f0c60bc5320be0c703eff6fe800303443811c0cf7efcd8801b7f04f90ad43e9cf0a0b18314423cc3db6d6c79e207a438588d8f1de80305bc17b48193ddecc10760a0e47ffe1f60d07f80f777bc0b9cbd5aa40bbf88ff7ffe3f3cf3c2fffdffffc11acfdfc1e7b7f9ff1bb8aa035f3c882379fe6fa9511cac9d9cc77ff66c17e6ee1317fe79c81b74aa3f6b00d6f8ff0338c6695525be2e7c617d5a0febc38a584f8444fc7097b52901e93b1b2aebd3f2f4fd4baeaf4539b076190feb83714c35a957d6b3b5eafbf094f52c82bea709637dd85cdfbf3458afd6a8af4505b09e75d1f7367bac2d4a68fd972b6b535a623dfbd677b736501d56c4faaf0f7d5f73cafa3675ac57bb64edb0157d9d4767fd1a55d60f07584f6016f15fb4ac0f86b13ec8c5daa21258ff55c27a56697d2e64dadbaed6a70de87bda9ebeab6db21ec088bcbb4910f50214be7a47ac3e6bb47e0d2aeb8599ac575b657d504ddfd788b2b6a8a2f5ec82beb33bac0f1eb25e0c4adf859aac07b0a8c759147d2f60ed07d958afe6c8da949af4fd6b56dfd9b97ef08af56c5255b37bd6abd5b27e0d2c6b531ad2d7695c881f8eb27ed8c9fa34217d17d6b09e8d9daf0b4359ff3596e00048e4b52803d6aee4c17a5e09ac67b3768b3ab31e40a31e27f0ec7b9a23eb059c114fe003f1ec84be0f2358af26a9afd9aaf5bc24582f34b3be2d95f54142037aacad1f7ae93b015ac40b4bf59d1db3fe8b42df0b9cea36e52ad5859dac1f0ab01e00a31eff1ad177d6693d9185f5ac6bbd1b97e1d54e591f9463fd90525f534262bddaa4466f43c8fa3023d607cff435cb67fdd080f5ac98b503e8f9faf080f5ec80beb351b2361a06e20ba4ea1625c07a355bd6b3767d6783d60b5b1cf8f1c2d7bf40581f46a1ef054cf58529900fa2e97b1112b1450db076a50fd61e60f7d5a2a4589f16c9fa343fac67ebfa6a94ac1f7eb2b6981062b33dac9d37673d9ba2efc34bd61655666d00bcfa5ec055dfd54859cf8bcd7ab72ec3a3d959bb0c05f1c347d613805acfbed60faf7d5f93cafa6197beab59b29ed701eb8536ac6725f4fd6b57df0198c86bb255c47fb5b29eadd1773543d60e33d177f640a38335223e0d4f5fa7a2d4d794de585fc093f5ec0d551d86a4af0b68207e58aaafcf067d5dadcfda7fc2f4835bac6737581fdc43d6a3e2ac1f16b01e78c47ab545d63e13446c5141ebbf32f45dad94f5ac0d6bef90d5675ff475a50ed62605cbdaa65aa53a9babbeb345ebc306f4759e9cf5434ed6b369ebbb3095f504a4d6b7b1637d814c7d0faeb19e055a5b9498f52c8dbe3605cbda6517beaec6ca7a220ae20138ead1a20058df66cbfa212feb0b5cea17d8d4d7627dbe0e4462fd5787beb31fac57cb643ddbb4b62804d61605b49e8d5a9b6c8e78310a5f4f33d4f7a19ff56cbbea6988ac4d096fd3852eac5dacd00f0a12f0b65bd60b0358df468ff5ec59aab305fa9a542b6b8b62607d508bf55fb1acff82653d0bc0daa930f5f558b65e4d96f54138a0ae26ca7aa1296b538263fd1a21f1413d631ff6593f8c45e0434dd6bb41307516cc7ab64e7db7079dbec695f5ec83be2e6a203e0d9ff5697cfa9e06a8efc21b7d671b65bd1046dfd520adbab0ccfa6118eb5916d60f4d59af66b53e0d92f54201d67fc9b25ec027ebbf48589f4696b5c9e8bece8ae8fbb0cd7a36567d5683f56abcac3d0ace7a007bf4de86cb7ab708a99e46c8fa34417d6775ac7ada23ebdbdc223625e9a65615c2fa35a5ac67d9faae76c8faa127ebd9117d4f23c6da949858af86c8fa618dbe13e061fd108cf500ea9857d3646d52aeac1f6eb17ed8ca7ae10ab60f7559cf76aa5bd4d1faa1186b174f591f6cd377353f534fab633d81d7fab21cd62e86593f74643d5b2c6b879db05e48ca7ab544d6a7e959cf1ead4f135bcf0ead1f62b23e88c5fae018ebd9068d4e74617d5aa3bea644a4ef413b6067cb647d9b9ff569f4ac0f7601f5e09fb317e8647d9b10e28f305e5ce8c97a362e882d4acddaa286d60f09581b2c81f5bc18f49d1784beb309faae06cbdaa288d60f59591f24633d1bd7f7343eac6733887896697ddb2eeb875fac37a2205e0d95f561687d3da002b18b607dad8a84f5693a884d89d94d4948dfd57af59d2db3769891be0f91d617e0d4d76516be3e5c60fd179cb529fde87bf1c257f7aebe0f03583f9cd4f720a000576364bd1112f16deef49dc8cbda600aac67f1ac174a119cb5d077d684f56973acbda3569fcdb1ea0528595f00553f2d91b5cbf0ac1faaeabbdab5ef6a9cac9d0767fd1095f5693fac4fb367fdf056dfd916d6a614ddf4343d7d578b94a9458159cf22fbfe6567edb50ec4b7cdb2feeb95f5ecad67ef543d4c89b5c38e589fa66a7ddb2aeb09c87d5db8c9da6125ac57ab646d4a4aac6fb35acf06abef611536355a06e2bf3658df46ca7a026e8867c3ac4de9ddf4b65ed666f5ace785c07a9644df59057d075022af45ad592f64656d006eac5dc6b43e4d80f56c07eb8567d6ab15ea3b8bc1da63b77ed8cbfa34aff5c201c8b330fa1acdc3d785a2ac4d2989b5557db09e6deb0b90ea0bd3d83ee4d2f7af107dfff2607d014c7d1faa59bb5867fd179df5431a7dff12613df1c2d787b3d4ce3ae8fb1092b5f3e2ac6fe365fd1094b54599592fbcebfb979bf52cd1da00de58cf42e8bb5086f56da3ac1f36b2be0d96f5c12ad6b36d7d3f4222361803eb0154603e6dcffa321cd61e8b23beed94b5cb9ed60f6063eaac99b5cb60ebdb6a59cfaaf55d2d96b545b1d6b355eab304369d95eb0f19585b545b1ff4d277b64bd6870d297296ae7b6c10b1c7a65f6703a1ef6dacac4f5b647df08db5cb62ebbf2ef475aa4b7d1fd6b29e855a5f0054dfc37c14795b296b8b22b3fe18c3c6d55c597bd49cb54521ad6753656d4aeea6ab7db2fe8b95f5c3bfbe0f1d58cf9259fff5d67702d6af0f2df55dac02f1ec5adfc3801439bbc27ab63e6b832db0b65988af1e93233e8dcfda6122fa1e44d4f7e09c628bbaf50460eb8736fa3a55a5bea7ddb13ead4f5fab75f87af08bf54232eb838ac87ac7acfef055dfdb5a591fec53f635b1ac0fa6e93b6ba0d185a8ac575364fdf1cfd7794db09ec5b1ea5f18ac6d96c3fab657d636eb40bc50ccfab01e455e7667fdb052df0b7cea7b81507d677bd5f7e1036bbfb28457cb65eda2b5ef4130d61b2f7c752a4b7d4ff363bd0033e287aefa5a5498f56016886723f47dcd2a6b8791b03e022c6b5382377d4d046287a9e86b510dac0f66e9fb1056df8366fa5ea05477000dc42e6b5a5b1401ebdd26887a9a58d6b3acb5cd0a115b1508ebc12e102fa012f142146a6f7365bdda2bebd9187d17baea6b00bdfa4ea00df16b0e115bed03f1412a7d5723643d3089b5d5b410dfa6cb7a355ca6ae96cadaa2c6ac0fe6116b5523ac67e3d4673d585bd402eb879bac2710b57e28cafa6126eb0b5cad17e6b09ecdb31e001fbd4e1341bcb0cf7ab547d60e0bd1f73440ac57a365fd1081f56c22f4b59894f8027d7d6f1365fd5785beb7d1b2b60008c4a6e4a4ef413e656f23c8fab4437d67b3f543497d6f4365bd7094f5c219d60b4f14f83094b547d1591f96a8af4565ebd314591fc413d6a4e2582f6c656d4a6eac5fd3ca7ab55ba9ce72b0f62839eb87d6be13c8b3b6580862878db05e6d90f52c83460f4b626d4a3efa9e56c8fa30b8489739ade7f5a0ef6c96fa5f757d67d352bd2d97f5bc0c581fac73fc3097f56b4c59bb6c87f5613f8abcf8e7eb1164594f606a7dd08df5421ad6a359e87b9b2ceb5910b14e6cd1773553d60b63f49d45eb3bebd677210b0367bfac2f50c9fa201de3d9a7f54023d6b302face2ead0f3b427c013feb7939e8fb579cb5df58c24613453c2bc37ab40aa01e1463ed516ed636f5aaaf29b5b13e4d0febd3fe585b8c0ff1698cac074341fcd096f542156b67d3646d4a45face06e8bbda28ebddb8229e2d55dfd542595b5401eb876bd64e932336a5207d0d6057dfbfe6ac9df7663d9b27eb87abac2f20ca7a5e11fa3ad5a4be4e95a9ef6c086b536af6c37810399bc17ab655fdb4417d4da6eaabcba6d6b314fa6db1ac674f589b92b39b1294d48377005ccd93f502e4881f42b076599ef56a9dac5753653df1cf57efa0d59de766fd10cd7a364cd6b317fabee695f5052659bb4c6a7d1a1deb814aac6767a4fa9785be8bd9117bd49bb58b767d2fa0a9ef1162597bacd157af7120becd94f5acd0fa612aeb876cd6b70964bd70ccfaa1026b87a1e87b9b39d6b36deaf36ad0d7a28cd6af2165fd1097f5435ad6a7d9b1be4d95f5c417d603b0235ead95b503e4215ec8c97aa109022dea81f500fa109f46b5b62a11d6f35260bddaaebeaf91656d516cd60f6515b81087f569556b9b19faba106ded6bacd687c5479ee6c3fa6124ebd530591ff463f635a3ac570365bdda2ceb79b5f535251e9bfec5c1fa230ae259b8beaf6165edb0147d4f43b55eb8aaefc14268ad0682785e0bac0f96e97b815ad6cea2fa1eb4623ddb24eb8b288857d3a5ea6c85beabfd757adb9ff56c096b66f3cf02fbec87c0e7ce39f820dbcfc0ce40209bd96083bd1f04e6b3c57ff5f0f94121900d3e78620e0e9f81ef6e621f85390b3be7e35bc87e092fbc987078a110f81e760e33beffee9f1864075cf8b3377eecf9c13ef11c8467fff500671f1c3bf1ecdf5dfc8083b16242a0f09905303c9a3dbf59e18dc0136f7cb11ff62cf6b0bff87f00fbe08117deecc7979dc081bf0219f1f9c4fff9c0078373ecd9fbc160f57f70ecc37cf6f9f97ff7f39bfd81fffad71b78011fbb8802079e3d82e7db3d00fbffcaff4cf7560771b29f81bd1fe2c52ff9817fff035b4b4ef0fea0444410215f2226ccff45c988231911c34e141dfe96cd021c9b82a8fb9c2b43a20bc3ad5a702ee7ede732454a8cafd0507664128923379ec9a4333a2c312c712ab45f5df8db552740fd670a03b9646093b6cabb3d371a49088bcf5d4639fc6f512442dcdb13864128dfe7934394e97cb66e0fe7f4c49caf647ea0a3d827215a9d960db904bb4a98c3ff6285970d5972e634563ae3369e0e494e980042affd907c3b4c98e03a97b01bc2d503e1eab51f5ce7136e9b1e926f0757e97c7240c34659002cd8d275a77c6e33d8170fccffbb970591f3ebb9295dbd6ad4193763d73da2c578af8b66dcae58c2ed88e9b4658d2ba224bc2c58c0e6c686c1403043b06dc102360c19d896511758e8c03bc028c0126a3f900470c40f60fab21f333e8525c4f03b9de02a9dcf62dc1496507d523fb0b52806c428f3f1e1d39c2567819340d726e5fffbb21e1e5ea5bb8493f026c1adaded55c2afb2ad2dca744e3f98f830e28de31630fc469b4a17364441422b0b62a0ba6684939b5c1c00e57909369f40c8f05c6301a0851038d62294d0a8b06577a74627eb429416cceb8a1f043fcc38488e3452636107d1caa4f587d1f0678bee0b6df174a5d517b08b777737e57fdecbf8c6bcc4ff4376f8bb67bbf6378525b05f75420a413ae01c2b97e31a6ec6cffe6f335cd81d0117d78beeedcf5eeae4aa2d0c7358ba51279ebb8cc2883a3bb8f0eba1c3d27907a58290f12a5fe5db621975e3a92ba385b653aa09d84de6c16f886ab5c334865b294c7dae583e9d4d0fd56754451bb7cbaa6be25975f3dce0aaae1c1d9fbb8c46e1e232af147fe6126d9b2f5cf845b1229eb6ee899803f48dba4be81b8dbe21a6285ca5f38d51855f445fa7f3c3b3752a9d4b6a89e7d4c9744f3495ee0b570f0d480276f39cd11745ec8cc25892a0e22d9d7fde55a6cb8dbe29cabc650134da6d837180142344c09001039b03bea5b3418ce79eb0b38b9b4c670b58458ce79e606363632bfa60e35b3aef5ce6d2bd633b5140484078fc8421039efb0cf661b8c0c606812dea3eefee96cf978d050b28e75f13e2e9920d0306253c4dbab165084228931efaef2edfa81d396f6c6d1830b04970994b376b297b4d4d6109eef2a5f18284070e2b387860bbc0c6b774b6b4ec8df009d216cae0bf2230e0e3c42dd3a9d74627b82e1c27274ce3a6d1d719cbc5e9d9d9c1c9c5d9d9c1e9c1c590b3b38bd35b92908b111763e94ea976767238ea28d0cdc9c5c165c0f1c666c1c60525cce182d28d616727b77cf1a22432bc785112d30c51f784bb7c93d51645940abf709121ea9e70a12dfc469d5017da465fbc2809f7996cdf144b370a234ff99e885d14f19b62eaba219eadfbe14dc10762f9a4be325a17dabad3671b02c4f3490d11a737cd10b724b1742edda51b85616797c14104b8386a83e9f3494d518d72802a67c0ee940abb52aa0b1729a24e132aa6b1b385e30e2dfc42ca07e27d5f4c5d370433ea4ce12e5fa5fb017ea51fdc1e4e175310cbe73bc27d26db37c5fb62d976783edd784a85e3280c15cba75386fb0176e3a733049e8ae793c3f3c961f974cac8e04ea7d3240737766165f4f58083eead0e875cfc3e3bfc194d0cb72baacbb7c3924475f976c890012eee025c1c8c781a7d3dd4c1bd51eba838dce0e4e8a838e0e29624dc147071d41d7676707a767625f010e00d802af9eefe9705297385fc39978b142a48bcf090024689bb191c5038e326d3f907a674f5eef25a772f830ba5abf722af75652c5b17c67361383d3b3ba51b63ea9472983aa52d33ea7c4aa14ee974efbd3075976ff46edabbca94058e620a4b80b62e1c4fef5c271c7f84863b77f9469d706c67d754da0d21e2e347bbe26fe369a8188e40241289c568cbd6a11ac3ce65cbf6b271780359ba3cd82c40df5619418783bb062ef475a1436faac3acc38a535882de0b8da7c462f47da7d2681b7d55b04539fcf9cf9081d2d5ab3ea32adce58be2f9a6583edf1121e2d6853decbd4fb743f5195501c3c3d27db6d5f6c49b0207881a245cdc7d00f14185871420ee5aa868d102c41d8813303ea840713783030a360b75541bed74a974edecdc76ba548270b104f1bec9137a2e33fa3e3330db1717946e8c15d5d809bf4e584ac2453576c680f1a680db0ecbb6c3740a224ff93e3b3463d8d98103defbc22b966d07f7d9c62e5c981a5343c44e0e5137ef7d317d53a0c87041e9c69832dfa794eab6607bb6510e54b6288729fca660739fd4e50b656b3b48a979efd4d942a36fec4ea751b7c70be3c5d4e4d44db6ceb61947a96c2edc869846a96cd196e99c2eddb8b5e094c0166d9b31ec4cb2b145930ea6ae8b5725c116bf51b6e6b41dd1c26e0b83989b9b9b9b9b9b939393939393939393938b8b8b8b8b8b8b8b8b8b838383838383838383837b7b7b7b7b7b7b7b7b7b7383738373837383738373837383738373837383ab50a142850a152a54a850a1aeaeaeaeaeaeaeaeae8e02050a142850a0408102053a3a3a3a3a3a3a3a3abab9b9b9b9b9b9b9b9b939393939393939393939b9b8b8b8b8b8b8b8b8b838383838383838383838b8b7b7b7b7b7b7b737373737373737373737b7b70a152a54a850a142850a15eaeaeaeaeaeaeaeaeaea2850a0408102050a142850a0a3a3a3a3a3a3a3a3a39b9b9b9b9b9b9b9b9b9b939393939393939393938b8b8b8b8b8b8b8b8b8b838383838383838383837b7b7b7b7b7b7b7b7b737bab5047816e4e2e0eee0d0594c469fcc77bd989187627d4c59170a34e6614048c67ebba70e115503726f11fc2f36526d0feec60f92a5be8b4dd637b47907af26e3a6da5d3bb6a9bf74e3364a8a35e904e6398583adf182ade585a8595bf1c38cdb8954e9830e150480cfa1496e084a97772716d2efc2adba453091224e43df1d8d85c650bb3c56edeb44db2b1459d6d9cd73ed9aa6e125eb23dbb20618204090712244868c006a2c58aba39172e7a54f9f6f4a8f114e6217da3d0bc1dce26b3068d193262c078e1a2058b1529509c305162848810203e78e8c0618284b608bd203c70d080c1020509101c30c0b686542b40200d6d808000bdcecccac8c67a891173581965e63ff4854344dde7dd1bdf49a9777578318ce7b385ba78df171d30e42c7cfa11a59e5426e2c2126e9b6d1f4c7c185175f3daa81fe2f7e9621abfcf69fc3e5ddc49a5ad9d1d3cb5b36b616a7b279d6658ba533be8b4ddbbf06751a1fecc66509f1cbcb05ba3dac1f9611985f17c3a93b0bb62ca8c3a9bf11dec4aebe0de602c5d3e67883e4335651ffefcb7b3bb934e972e9f13c48f978198f1efbd4f3cd8d57bcb4028f81dd4c9564d3aa7b0843b3ab836a53376a1cdd809b76dd23000604763913864d774de901bb4a6372548bdc84c1987be292c61d9ba30198726fc2a27bcce7ca66cc3a5ffbff1033f15c6a346e32415cf5d2a936d853a0a74737271706f6e392c1b73ee5cb83488fdf9a446cb32a4faaf43071b33ea2ccbb0e8005e96e1cb7f69352ecb10c5cba0e3bf0336bb086c766ed4f9648bd0a02c03860c726c6c6ed4197de169cb8c3af9dc26938d197d9f0ef0a2ceb60910d8e0972d459b822d7e990dd8dcd81975e2b14dd9a24e37e9e655dd3c360721dedcdca837dadcdcdcdca8371ab0e938000447041d763a5ceab3d5638bc2ad34840a1042def858bbf0268e13a2b7e8542304531c08e960c7225a84531f21600f0898024a991244d38b520526c19d829469a3a2c4061ba482403f9968732b6c100aa62e2c39f54b10b6c0ae0a5c70cd0112e9caa21b0e9e9c00b2654f38c7008622106595bc41695a2c0099b0e20dde14597e3fae6031f64c6b29fa71a8e82691a107753fa60c99e4497af1f783869a0e210628b9f523019248617a08ef7cc4ca33d2c95577c2479f0fa18c408012c20712d69a9960a8e46385245673765a3cf948b38230808b468e1ea7900009441021a4071d0a743f103cdd1e3e9c34d15107e7ed11826861489b8c273dc6c6e8c26bf2465aed935354dceb81a29a668a180b551661a8c2602726ac19f356bd40aa4c481c57a4fa45a0c3a31bb79aafd28f3969891c4c3e307ccc3d7c70ae1619102b74dde34562831caa3037f616d97131d42ac89c3d2b49b32f80e016ecddb12fda721991ee3590a4e764c2971a7ab4384128f304c8999e2042a176f468fde831619e7ab528c504bd172e9033c66478a2c7d621089c13bc325157b1bb4899359245bd2389578abde120ea9034aeb10a94492d61e652a815728cd433159f844c055d88471de9c015eaa58cdd8820b28ad2963031b5522418718f0131072a8f4fb71699c5465805b2c84893649a69462937d516c0291951790e288a274d9f5d0001e11744a674a4dc26d9d08334cd29a04c7fdc1961486e602d51464caed4620227057d91f170eb12dcc60bf62246960b1eb878150a8006a58f87213839503d3495e211254f9f5d5468e4f1985165c21b07b3183c10ac5140e89fc6a4b0a6af17b92baaa47c1c2c3833d4e685f4081bab0f5f967890ae90a219fa3364d10d21afa92f592041033c7ae760787b2487788446aebc2008d83dc8fba2f746887a021a00f2d7868aa2f9824a4b2e2242a23ca216da20e3da602951a1013a859a143a422949a15f5e04f053a594158ac7c60da30e2a5841e10cc4b0f33245f0dc95114cf1db43e1a928d1b3ca943e5dea14517ae27832301484ce88612e8f567694e35d3ec80bb403d42e21c236794b60087983cbf393e7626f4bad0631dcf2d614104a9226d6891da958751d1228c51d7660c9b5513833dc2164ba83c411344b3df2a4ec708a7ae1a439e64326671bb6506090ec643963540334694ad6706ed823eacd9b14729c4542cc1e704ad069626222c90508538d2699b530495e1f4634f3dc461476d98135e7580d2334baa2a9d94b2cc918ee95311f0140ca52938015330b8f3a355aa93161b6b5a2c84150e21233421f20a7821f92e0ddcaa565d50e3075788592a15ef99973c583b2a397a93b2252f064e01db094c94f8a1183fb6a2d508d207cadbb07cd3d7bbba6728d883822564b512b37c5264b295e4ccddc0170a89b3c48f1b02c05089728ba23dd524e161a787f44c55856f9961f28788869154ab4148b3087cb41538c9293a818333a6ce0a53c63872f8417269c52aab413d202c4a9329294c1e4a4a49703c85ea77e29e926dfda5c8b2ce1b223776c13b554da1b5326121ce5aad52e287449c1abcb908e593a00e950a2a3850e354c324038d2e3ea0ed5a75079c43b597776049c82656787c15d90276606e06005df8db0715706654ec28a2c7272841a0123002a194272b011b6e1e343f628471c84d1a6c353a61c1b801f12a0f8e12607710c5448aa25c371898a630cde9b361c710ee1d88141d4082ca6a038e478a110825a2103c71d492b9998566f340a95b68aac858d1b587edc68e1c6608944c2ed06842372074aad4161e3960d425f4ab83864d562e3499b073e168a4f6cc4b0716008c4c30c5d456ab4ea940cda680b53434f8d227b23ae6e6a7035503851630b6d918a1a3448a502e46c83f688461c0e13c2f4a4c0a1c147c303211a00728df18de0303763d3a24e89c6c83d9861c612a9ba210efccc78f9386bbd03a21915f2660051dc99c6e1802563520607b60ad1792283cbae305860528992b16c345d20c0d510196e31febefca1b1c70e430c4425dc4424bac22b0695e1023195c41cc5b0b101c3232329c8622880214bea6809a14c030c3f3092b480d5a7634019182c3cd10a6027442a182fac2fea9080a3e08a21202f80bc10f182ac0f11872229d2c5a75bd4e4263b4a176afc70a4827343858b699b005732801c5d6488f324ceac168e8ba11333821aa448d0c25219552e9f4d6a2dc4b470b6902310259004598a5a9c05a31e2cae68418b21f760110b1d7ca3c60cc180b278e06385adb32e7ec00fc915835634b95b01438b024f0c2608596100841e5248047151c14a451e028fd48c7109a082888a132a52904af1e6cff9044b85638a3d097d327d5284214507278bdc9812b34c018642138a3228a228ea54b0aa345c6da16061a712bc96ca09496a5434d22f044e6c39a13c31c1c4d5c4a1321353d898a8c1c1448248256295e853024909165d4a9038352541e706891f2442903831a2af3a224d3b02463502039a115f222a890823a2594a445c085e211685b02220c45d0807ab40d402310804930ce2c51c08362a1f567dc0f361c807131f3c8cf2e0c6839e070e1e8e1d327528d301da8142873ce68e0d1224578ba6234ab2491c241c19e2b7c3d012291b686c48700db1fe5f4a30fe2f7d998f4d0ea2eef36ecf8d36b883dba6f26eea9480f774a7152ad455a05081aec25c05b90a7115e02abc5570ab50a1aeae8e421d5ddd5c9d5c5d5c1d5cdd5b9d5b5d050a75142850a0a33047418e421c05380a6f14dc2854a0aba3a34047473747274717470747f746e7465761ae6e8ec21cdddcdc9cdc5cdc1cdcdcdb9cdb5c05b93a390a72747273727272717270726f726e7215e2eae228c4d1c5cdc5c9c5c5c5c1c5bdc5b9c55580ab83a30047073707270717070707f706e70657e1adee8dc21bdddbdc9bdc5bdc1bdcdbdb9bdb5b05b73a370a6e746e736e726e716e706e6f6e6e6e59084008600a4b88c26e1cb7d209703c75d097a24d811775b6e1459d6c11cadc12e8189efa8fe36513d0b84b0a15de24b849786b7397b03bd563a3465d690b6573a5d578cf8d4e6870b609c758d9c26d5319ebbf0e36d865ba71d4592641938e6a0bc3ed94ad758102013ca54cc28dc335da3635e3563aa11abfbd49806b7bf1a2ce364f53b84592ad19b752b6e793839d1dd082813fe8e67ffc32b721ff0dfc413dffe397b90df96ff607f5fc8f5fe636e46e12dc06dc29a668e5e1470bbe516f511d678c889519b200c7f8a2a4b60da93503c58a66a7b530888c0052145c3222928b413eec74ba85668212dddb1308fd32eac56571e0c3cfec829a1c5062b14d9e440837f80c4cf8137343722a038d2fd13f970eccd191f664111aaa0b6476dd6803f2e70a88026fcaa80d667b76a5589200c42b2983ee4c0b302217b3b26bd30a3b5e2e013e3f23b1a62e78694992b4ec50d13284506b50a5174f1e6038ab53e1e046cc6729060e268036443f4bb1eb2657a5a6e8603366aa056c804c320f01073602d4a16a004684ab56cc4902ca38eb23e7c35f0b660649757ea63934d0bd194b2a98b488432b380d3ab0d832d52b472c02932e10d9e0acaaea7558b02e3972941660831b13af8fa2576e171a4fda5c28e363ec112d24ac168991b56ad4280c2f76a56054c0c7da8537715c01376ce7f223c1541c60d1a94608a63428f52733756111a4f680cc8e45b408a73e2a187949a26cd3abc412b507044c01a54c11b2c64f531094fb014cc08b520526c19c7af5d1f1064867d5174d646d5494d860631497d61a8b25b4044855ed938936b792a5b04634315fc0b0441160eac29253bda0f9321c75e287a6369bca0aecaac005971c3d73bed2cc6821835586bcb2e88683272768a09dc1f54cc06ac0da803de11c031888a246ad40144b6d8928b4b22a7983d2b4584843d18902ad1296ac3dd656bcc19b22cbef410007b490a0d6343d40038bb1675a2bd192313f0d4e051112ea8559d14d22430fea9e9d74b1e9d98277c283d890499ea417d75872dcd222545949e9d0d474083140c92d14a7d00cf5b8e1c60ac80c49a4303d8439cee81121094b0058ac1a89e519e9e4aa3391e72ad4d0864f102c4c691f421981000584ac2852f713945ed60367ac3533c140298a110ab284a65eac528849623567a7a5d32622063a98aa5c9818d3ac200ce0a2916301754211580d6cad213b43022410414410240f9e3405b9c0c567cd1805ba1f089e2e051818d8b8845d5b17049c34d15107271ae8d522b9066852f25a00a285216d329c389a55c1900b1168bc9c181ba30bafc99b37938dd619f63cf20343013945c5bd1e279a4090044088d9579b840053c458a8b2088385181a323c120b020a44067662c29a316eba3ef472a5474acb2d0548950989e3885821b3a5cc89512abe6a0820d0e1d18d5bdd01159c146650c1cf11643fe6a42572309b7c64c005f834883146cdca123b6ddcd0c4360415f823d429419c0036760e5ed0d23385843b679117335586c85c2d322056e8bac14ecfa0313fc4fc6424890d72a8c2d8e082eb0993190115153003ecb8186a15444e9c3b33485a21681507294b9a7d0104b740019a8a30318c2098b25c635fb4e53222b560a34e9658942a0d213340929e93095f68300ad0806f901a4f5dd2ca384128f30488d9185049143d098911676b8442ede8d1f6e9b2eb0c8f2e52ea860368cc53af16a590406a6924cad982437129cc5c20678cc9e024d50a6786bd1674527888750802e704af4c2ea64adc081c10698892c6ee2265d62816122468a270e886ee1c3349bc52ec0d07eda0c442818c1c50e402b134aeb10a14cf4f27352cc8e8c432c52acdcca5502be414133d4093e2880a5497de9ca9f824642ac802253f7a6076baf629c6d8910e5ca15e4a001310d59224e5041d32022288aca2b4250c10b40b7d4ed5314b61e4ac522418718f014b33372c47a2e8a1a11ba3f2f8746b5199110f35c6e836e558458500ac025964a44112a692033c09a02cdb140930a3949b6a0ba010004a0ea9615875208f89ca7340513cc94553c13987d78b545da00b2020fc62481932b6a8a876bd48e30c40ca6d920d3d482950e1a29264e961cf0bb21450a63fee8a6892dca90993e78b153db5123e58fdbdb52923e5727c4bd0b6079080282326576a2d21420b8e991a466424e24526e88b8c875b96bc38908187547e23e64d8d17ec458cac16543c0962e204238a571e01bc0a054083e2490da95e640c9848737394c1c981eaa189542b3c5c50dcb970a6760a99a7cf2e2a34f2cc60143a7315e155160b03aa4c78e36006830d283950326428f8a0ab6c8d0242ff34f6828ea153646fd426315a9bbe5ee4aea45252c4d2504dd4843b7a680e169c196ae3428c973e619013b36e1d326363f5e1cb920ed60024c2389216ba63c5d2604c0252411292cfeed40ba579824533f467c8a21b41b42c3854e6c4d9f40d25b32f59204103387ab3c6e221b629144b8d1810103c12905d6052c789830c8ce6a02469c9211ea1912b61463c31ca0738c815cf08d83dc8fba2074b2af525974ace01193152575efd010241ca118f181c49a6184841006800c85f1bca848825bc741587cc9138fb824a4b2e2242de27740ba3327f4066ac448b50ba985c14c49201274a200e060a026d90716d701433690a489140847c552a80013a859a1432e2897304cfd7a4534e528ddd89326721d27bc809181c623ab1b8d0a7c08b007eaa94b27e815884e5d114227f8602b071c3a8830a56158063f632756a2c4e320331ecbc4c0f5c61ed58211bd11f5ea8650453fcf6507051618d451e4e5ec6241120a76a43a22ba2beb63a6a10f52065ad4436a54f973a45947ec8b2c167c7223c48a86a7770188a722cd21689600314182c0baf04180a4267c43097168949a90146058c9c94654739dee5031f9ba22a42bc2ca244e40e50bb8408dbdc0d9a1344d3802224d60c8021e40d2ecf8f1048347a91f5e84b49caf6b6d46a106302171e668f002c6abd4a6b0a08254913eb44833bafca4a70f2226bc500565d87040ab1cf831961afd90f426065b0e4da289cf95a6440d471c627b72ed2b5536c236808614e921e898a22e1ce83146847d02cf5c893629606c3101e816e2dc960e68cd361518ca3d8115eafd10bc21838b1174e9a633e649a82d9f2118f0e58a3a4b185028364176b8fae05789d4451d054c20cd5004d9a9235dab220593b1b12e18d05b13da2debc4911a709a849a7da3c8ac584511a21660f3825e6807a4b71e1838f343d00674c24b90061aa61a2c6995d2c963887368dad8549f2fa30e2c20823bbbeec09624511701b51d86507d6b6c1d2041d82b608e3ce580d2334baa24906338c461a9c28e0adb12596640cf7c8deb480e1c4918206864a010048596a12ac82b342cf8f1241a4248b04e051a7462bb5254dd25cdd2c6c81f1cc8dd58a220741094b65d6da064d80d3600aae027d809c0a7e4032e98d1424b433b03b8202e4d2b26a07180a9c0815c100a70d0f1c2e5932d42b3f73ae3e5a8e57822535e820d576f4327547440a84390359c6747a70679780258ff2d489743c3005951b3ba3fc18da456629939f14e38554d3564c6edcc942b744ae05aa1184af9db682b3e6ca0b044dec06a0b9676f575452623571e541afc8a55c65228e88d552d46aba0053932f39248931426eb294e2c5b48c150f186dac3432856acd0038d44d1ea4783840680c8687a19eb53e65807089a23bcee1617218cbd0bb1357d6b2d0c0fb230a062ca397143b466ce9a1040d84590b373b7bb35e393c5e8da9e6126346c1434cab50221b4f9ed850804242d22a16610e978366183966ccfc50d3344305124d548c191d36ec3a55494c045d4e0605d16266872f8417e6db91354264b8bd90e0c8c4a458c9938384109d2bb8370b0469b2d1214d480b10a7ca440a348245190fb85910c09cc1ada1b02a151a57a8a6c3205b51989410b3e5e20e16db911595d69a5d7218c90c091c40f63a754b778cb8f10337322f1bceee9ce272e46c70ccad32f4825687334863388ef4987425400ef991b4e7a0dd14092cb284cb8e9c5117f46a4296a739507b01ec3c4490722393d2495b261b6787e85cc716cd01d200844f45192763a4f62645d15160ca4482a35cb4ea8071a36292a03b023a40a14b0a5e5d856c95803505c373f0a6c9e6f48ed0d09271607a72a3b8c7400ca6da0119760d648149c20a716d33684e8651408a37129430a0436096180907e27084ba4086268613312d6a05b051c7490a29414eb8a9619201c2919e56b1aae8015142885b1595804fa1f28877b10651ef7690e94523d75a998053b0ecec30388e53af50f5f231e104f28999013858f1e832219389a3233f137006488b544dfda9314a10a83252336d44196550e624acc82227add7a914838a3481865a1b0123002a1941a870899a6252f040aa179ab00d1f1f32476ae0cc5ad1a2ca173c5bcc8230da7478cab416c8c694da21002e3862c00f0950fc7073620b09070fbc80a8220b6d0c5448aa25335be0892ae6f7b220623644461d9eb4b88f15a94360569e709013c37bd386238ea152b0527dd1c406c371a5611035028ba9a718eb86bf596b5a2f09cc78a110825a11c3ca02129628aed24819117324ad6462cab787038f0fb08c1178e8d242a5ad226b516350138fdd0a276a96c4381332c20f074f3e20b14dc9352dd30a4a360637064b24121334a1d8c0c8810a044da8048ec81d28b5e68493389100ac0922c6c3ab00ec8d5479d8305c70b2c9c887d72949b2c6be947071c8aa4569a6ecc21547ac8e840ab479e063a1e8a45218246d7d4281ea212940932f5726583003e01405198bec0c486a201b02f13043571178c5b54c680b0e01b740a764d0461b18237708ed311e8853e582803302147e24089271b58e612a276bdcc8f6465cddd4debcf841b2429364625ba0e6448d2db4452aee6afd30438a470c2e9a04946975c86c8c0621b71a15c0c380cf4719592a40ce36688ff0ee860170b548b4a80fc96142989e1438d22d47594ef49c89ad0c905380c60f96b54054b146a60846a650cb6eac62d5d660102b6b54ce18203a3008c85c637c2338c8bd3163ca840a2c08467c18b0a853a231720f10e4597141439b2263289459225537c4811f15888eba7af9f162e76e8d8fb3d63b203a11f521c1f5bb2279a1b506a67c6e8719275802e9f9d3716a8b198a3bd3381caf545dd87394a845852c13cbe0c056213a4e5c31babe9450b51a1086b62b0c169854a148f5153a61e4f886d609b346d305025c094935c78bb4992956213362646ced294b80e762d00f1aaef80679c993f6e50f8d3d76185a40b262e82ccaaf08ce4ab88948746597274d6c9aa08c717f45c6860bc454127314208401363a65a4e4f2426003864746528c01c2d0905401d1aa54397bc40bc3dc26006ebbbc18d92699513b8c491d2d21946580a245ce85b40d6238221140e5c6121fb2d10f05a722dc7a64d50524400b587d3a0690d1c54a0d50150c48b2341af3442b809d10a8762d31a565cd1b0537980a584136d9c3633a810354d094c8ac374b02f40d885e6bdd500049967baba3c482929180a3e08aa11fac8c0c8e1c8a64a4d544ad439c324ac448f8000a0d19bb52215aec09683ac153e18402f6140b148bf050f25485ac0f118722a9da173d71063b0800487450bb454d6eb293bc3283cf2e07a080746005f8e14805e7468a4f658a76f919b0949354d626c0950c2046536196de925555863821e33c8933ab7d33068d452a3052fa9e5206383123a8410a047644c47d04a421110b2e2ba3cae5b3a98094278ef60d922f5a51d6f2c2880e682832210a8bd36c78dc630aed000ced13a70271c89e120f15cc2852332310259004598aec204578ce29ca53674a2c80d1d10c42cf094526b1200821e8c883f627941b427355539fd80cf990c90da458665ad062c83d50b4aac4ab532043606420c6376acc108ca79f37c1233f4f2a2eaca5d9e83c41183d10052123a25695013ae0cecebaf8013f24296c2122c4c1010e1a2131506756e8c010b883231714c00414472e4d172c16b172e5e8e52349d409a70940d8ceb428f0c4608210384675335e51b31a0d1903a1871412415b6c4113c1598042ca108f4019419330f5b27180048651994805996a0a40e0919a312e6778be9677dca4721d54c7e4646a05c06c0c87182386fef059a5e44a81134eca48f0c193dc52a99222299fd0f40960a60cf5d2152a04e050a9cfa9003d8bc80a10c1f5c9831a1232a83c00d42054a20a05fe9c4fb05430ae7942600f0b00b84c850448e893e993a20b4932fdb86bc3a31088269993456e4c89518a19db850683412430aed4dec421ecb68859aaba620bc61108231f020039a0b4a8079a9a9236383e99d1722949b6cb0f800ab94494a8f48a4e9002553d3cc8e4a15252fce0311640523152d40010ac012a58551aaeb53aa9d1e22a5ae76a29a80c762ac16ba7c469556d12c88a2c35774d8d8a46fa258d4e8f1b636eadeee4ca34c0540e355a73ce6a2c22a1a6460c5c134095a93265aa10ad0f23c6d8b51a01a2ca933a6b7d64a2c03d500ecf11a2d370558f3c684050c802a34306332e8818334baf1655315b66a8610a05d91e5bbc4eb5f1a000ca416cc51ba91518d658c1d50b6940128b04726968aa76a0e9dad04a10af2c5f82a4aae0ca6c949225668c20358983230be0a855ae0462779ecf4fd10cc306b53c8178632d5a95d647841916206e60005e5419da49f32476d656d2fbb46b5091c7270e63a48c90b3618c00004441965cc8d4a2d3283440699c408e20c34676529c4a887889e38854839f9d7a1b436611dca752a4000ade546c1f3bc2c0ce9d313616ad3903ea088d24435e4088a6d58bb844609dc82c85b6cefc01f2f4c4f270230c0f1f775604a9acf8c76025a22109880928baa66c00c61bfe027532dd1ab088af549b1d2e63fad8e23b246a8c0e3c811c88b0b308c71f8534342b2e472f2adc18a37420cbd08d3382dcf0b1d5165152eb4b0935bc03b91edc8964e9410032749045924ba62005042ffec0607f01c33ad86c1f186c60b3c5afeedc442210ac830d240e8743002c7b232b14f6d711280c361a7be18d01802d66341e7833360bcf1a85c2a0b1f88be562f1172b828d090b741fbb8bc22fb6c0c5be9e8b6f60b108c602c3fef7df647f50f82e065f3c7e35f06d46540306ff23f1cd1a872d04128d02586058916dec0b40d1d82d847b7efe02e61e13b6d9000000129c4082239bd3de071eb8580bf38144761826644f207f957d154fec6ea191058e09cf1ebcd989ecf0617dbcd06c6876a0583eb1ac1364225b10f89b890d3030f60381c3e200b41fc50ee0073efc01fc8b282470630f087b9891ede1d7337048f73e2ef8f14dcc01cece0ac916048f67fb0a4ef89784076fbcdabfdee059f8316101b02fb34738f00e30247f769608e0756b615f43fb31ac859d85664204062e06f6160b3ec004e18bdd1fb22ff02f33a3d8179051389178fcf3311cd8c7e72281bf29388be1088e7c18db11bc94903dfe78ef17afc0eceb598617f0afb6488231073bf0130ef7e7277ffcebc3171fe3061e7628c7d2e3935838b8f15380680ffe6bc0b9bcd79cc94f1c3925ecc1dffdff8af01f07f020abe2bfd93df58707effc8b3ad0fbc2fcaf0f3a813e9de385232ebc809f68b8bf38da8560673301e34f6923dcc7742dfad9ffb9a8ffc6fe27205b0bc9af2503611d403fdf727466084efc622cfc6202fc62c27e31c13f0caf3fccf54711e30fe3e7b90c95e732009ec904ff137ecf6322fd6098ff0957ff8948ff975dff970dd98bdb6f22d2cf85d7cfa5d0cf45cdcfc5c16f22eedf42ea194b9e7f8b837f8b315fc9f297a8f37ca5f86b11f597d0fb4b449faba43d5301f16b41f0e3a8f36731f493b03e43d9fbb1e8f94960f9b1387976f2f75f39fbad5cff2a3ffe2a9bfe2a9afe2a753f1502cf4a24fc54c6fe29b2fe29579e91b87a465229caa5e721a81f4aac1fca9f1f8aa3e721f059c8841fcade0f85c0ff84d0ffc4cdf38f35ff1318bf932663fe108afe10819eab78cf7c717e393fff92bf3fc4dcbf04d4bf44d3b31ef35fa2fc97e8f8415cff25fd2b19f583d0f42b49f22bc9fb95344842ea5702e04fb2e44fc2e64fe2fc933057fc20f29ea5959e5f3a3f88f60781e3f98df023593e4f1bfd4802fc4768fd4764fd20203c3f313d43f39e9f74bf91bedfc8a3df48a3df880b23a87e23807e23087e23707e23cadf885acebbf017b1fe4500fd45ecfc45e8fc2decfc45c0fc459cfc45a8fc1ff27e2961fe22c0b82fcf71569e99789e996afe1a787e2219fe0fc69f08fb0fa9f37bc0f41c77f70f913ebb6bfe213a9e5d04cfcb4e7fbf102ccfca0cbf901ecf494ebf071acf4911cfc906bf07b93f08883f48fe8128fa3df40f44f97c97e407f2ff47a9ff47aabfc398ff47a5e71b43fe0e0c7e1f8c7e1f899e6db8f93be4bfc7ab1a6a9e69fcf87ba8f87b94e030e1afb2ca31103dc7e8f257633cc758f06f28f5f33de24bf1fc42eddf90e5df10e2df73b25762eddf433eb3887b6681f6bc62d6f30a5a1b86bf065dcf2b3e3cabd8f3ac82ccaf27f66c404c3e51e5a766783e41f75313fc1a08fc71a33f4612dff8631119f6fc53347f8637ffd4c93fedf13cc2ec59c4dc0f63f9e121cf21863fbc026ef0ecc1cdcfe3cb7307e5cf03c47350c12f85f34bf77e29905f5ae2c790e597129056f8df44cf1aa23c6bc8f1bfd11f7a7dce40e98f2ac210f747a37f74c20f957bc680fca1487e28df0f75fe500ed00c3f34c0ff64fe4f48ff53d0f3853fff33c5b3dddfb39af1d90eca9fe747cc9f07ff1752fc792f9eebd4fc7906fe0b03fe1d9e9ee9ccfc3bd6fcce55bfd3ccefec70a7d9df5cfb9b519ee5a0cd163f13c9cffcfb2d90788e33f4335dfccc1c3fd380074eff10383fde97b3c0f2b3a8f2db99fa2d0c2da0fd78247e3cbfdf2df5ec56fcdda7ddf35feefd4b30ff32c8bf74fe76127e259b5f89e85f1e788620eb579afa95467e65f34feafa95189e211c7fe58a3f79e94fd2f99338fe24813f29f6b7b740fdad9cbf3df3b7757afced89f6c4df8ef875287a5e70a94281bf82ddaf83c87f77fdef34fd7790febb2e7f5da9ff2eefbf4b3eb79d9ee1f6fc758aee0efc453a2378fb73f07a365325479e3f879d3fc79cbfeec7b301237f5df2cfe1fc7360f87334f871ecfaeb26fc3848fd3846fd387efc38f27e1cd16735eb8fc3c3b39aa9ff0694ffc6201d3f0522ff8d03ff9d8bff86f0b7d1eb99c080df062d1b9b7e1b869ed11665f86d0c7f3a5d3fddabbf06de4f63d35f83c15f83c04fa3d5738055cf01d6fc34923f8d033f8db49f86f09f81eb9f31ebd9ccd43fe3cd3fe3ed9f01f7cb70f2cf00fb65d4fa6544fa67bc8a11ff3158fc3204c808f0c328f4c3b0f3c370f3c3e072e487a1fc61b8f86188fd2f6efd2fcafc2f9aff8b11ff8bbaff4598ff85f07721eb77c1ead9a8fc5d84fa5d34faa5d2e7620421bf0b20bf8be9efa2860b122e84bf8be0dfe26feeec6fb1f7b780ff1621fe16167eb9507f0bf66761eb994a28166ffe148f7e16677e165a9e83267e16507e16cc5f8e0f8bbd9fc5f267f1e26781e25968f7cb85f957485ac1e55fd1e35f917f157e54e848c1e14f51f7a7c0f0a6f4bed1289f3e7cde94601ed2373ae34dc97d5392f146737ba3cdf1799fc9799fed799b019a63d6e76dc6e75d26a32cc3bb4c04dc7b8cc17bec0d8d97b7589fb718973f284890203e7f10d32a55a950594d951a250a549fa74e9c3665c274c952254a7ff0cf9e3f3869d29f3f8508fd41557f50cf1f9cf507effc414ebf9828bf180fcf412c3ddf98f4dc82c4bfa1c2bf61c06f01cc731ca6e7061f9e1b94f042b6c5a8c5d3af2546961f7f15bd9f0a977f0afc4ba973d2a489abbf09af268e9a084af233e1f02ba9fe4660fd465a640062e3ffe183cecff7e8dfdbf0ef95f8f56afd7a9ef4d67e3db59f6ae1a70aff98072ce787e7fe3d3552a4a33feae98772c8abfecc183f93c0cf14e0c6f8972dfe65815f79e84fcae918fe6d8a5fc7a6ff0ece7fe7fc7370fa7354fa6d34f86b247f1a2f7e1a1ffe197648fd30b8fc3060b4f8fb5b28fa590cf95980f8550cf959347f1678fe140bfe22039e3bbcfa7550ff2d167e2dbdfe2ca5a4e4f9a10cff27967e27157e27fd33c9f23311fb8fc82852fd89b8fa87047f21f01f84c31f84e863d0df83c8df63c35f8df257a1fc551c7f35c65f5df15747fc55127f35c3cf47e58f0ffc30849f47f47f0ffcd1b41fbaf73791fc78547e97d4efaaf8db597f1be56f9bbf8e2bff8de87f63f9cf58f3cfd8f0c768fe31843f0c30bf0b167f0b537f0b463f0b14ff0a54bf8a387f163dff14503f983b3f9706ff165dff1658ff945dff94babf89df9f84ec1702e8ff11e8d712e3af4af9abee5fcdf1572ffc7a8dfee9839f05a81f2ffe67d4f8610cfa596cf87358fa9938f9b3a0f8979cf8a558f8f1eefc50e46f03c9ff23d39fb4f4e748f3b7f8fa5bd8fd46e8fe14837e27337e29971f1ef4ffa8f2fb60fb7b38fa89a4faa18e7ea6963f8c98ff8b8c3f8b991fc9df1f6ff9794cfa5fa8fdd13ebf0b0d7f16523f9547ff9251ff1249bf90ea4f25f5c7c2ff79ea6faef999297ebcb2ff86fbbf08fb5b38f8b324690af8db0fff9d935fca831fbaeac781f6af80f067e1fb93127e16d07f4b8e1f88d8cf97f75369fc31f18f7ef9a11c7e26ad9fe9e36fc1e4cf22e1c75bf28b81f24ff9f11fd1f5eb75f8794472b9fc3734fc365efd2b3afd2992fc3a46fd59f6fc54eefcd538bf0a27ff9601bf96117f965b7f15b97f48885f48973f76fed33abf8e023f8e3e31ae7f0a53ff94faffc8f0e7c5f9953efe3b5b7f0e464b0afdd245ff0b407f0b337f0b01bf9512ff1404ff9157bf9405ff90f70752ebaf36fa63263f0f12ff8be05f76793be5cf11ff52927fdede8f97e86fe1e50f13e90fa3e5efb2e3c702e7af3ef85f5ebf8be8cfd1eaa731fd5f74f85bd8faa948fa9b54fa8bbcff0f547f93c8cf82d1cfc2f9a788f353dd5f39e62f72ea4ff2fa9f4b7e2973febc3e7f9336ff1112ff5eff3372fc2e0cfd400efc2edfff7cf4a700fbefd8fc2a04fd7cb97e17027eaaf49f2af97590fd3650fd292afc4d782525fd4e86fc59a8bf11593f90407f8f023f8b473f8bbeb7a8f46731f107a1f00399f0bf613fb4d3bfa3ecbf91fc676cfab3e0fa9f14faf91afd70f21f12e4ffa1e3bf03fe3342fd4d32fd6184fc5680bf11463f90317f55c8cff7e407f3f77b797f2d703f14587f921b7f12e13fa47f3d543f2cf6efb0f42f0ffd2d40fd2cf4fc2a92fc5322fdb0ae1fbae3670af87334fa97acfd4436fd49463f93e58f04d2ffb2fa71acf8c320ff246d3f4ce0cf03fe2ea87f8a223f17593f951dff110cff14d42fe5f44309fc3bf23f45cabfc4ef57d2e74fa2e11782e4d773feedad9fc6881f86929f0aa59f060b315f7e17a7fe14707f94d2ff64d11fa5d18f57eb7f3262d72c59b160a5f1b409d3efd6a5d2efd645d2a24487080902e4878f1e3c76e8c881e3064c081f7cd4dfad0bfcbb75799b78cbf60e870d1a3260b860a102c5efc6e57733f1e0d3ef46fcdd8678eed8a953850a901f6ed8ac29a3248991223e7aece94d61f7c032c32fa038d01ec308101e2e2840601c1e602b5d9a74a5cacfd6fd06a6b0b13f5bfe7f870d1b3662c4300201e23ad6ac2183060d1a342c2242840e14aef15ae3b5c68b0b172e5c862c1f3e7cd604ad095a13a4458b162c58f4e8f91a10070a3b341d3a6cd8b061c48891162d5af4e8d103c2cc0c0408468c10211224e83f1d366cd83062c4e8673bf4cd3a7440840811224488c4881123468c1841820409e2c2850b173e7cf8f0d1a2454b870e7af4e8d1a3470f162c58b060c182070f1e3c78f050a142850a152a1d3a74bfcc8c4e9546954695c61120605922f12740804844800001cb12893f01022cf155f1aa785538493849b02e08d7655922110102a15028140a851c84421601070e6cce2d8796430bf9d962317e7b43802067f68b6f06dfcf7eb108107c7d0df764ecc9d08ba1178305b26c5b9b9b5b82046d6d6f6f08e217531753b6117c7dbdbd018108107c7d5dfab3cdf690ed6e7b8ba688a680a280a280fe6cb36d6d6f6f40e089e7893c137926f24cb8b94990301c2240f0f50504e2856019b8b9b92058e0dbfe7f587e587e587e587e60f086e07f87640705ff3974d090e182dd189891f8f51398fb09047f3109bf9882296ed290f95285879d3f6cc81f56e70f8be13f8cc71f86e70fdb6023068b137f989e3facc30f164a52a31f8cd30f2643c40f96e1070bf11f3115ca94e83f62fa8f82fe638cff18e2376a52f41b03fdc644bf51d36fac72e0375ef88d067ea38c0cc618bf510484020202d4fdc50b7f114e4e999ff8e72792f9899a02fd444513201c3050404080b338b79f78e12736a8440853895f0863c42f7c2174f10b1998802082810720020f083c2040d1a62a550664dd803ae0000a02e80270da74e626e6264617800a8c3dd4d9c588fbd9e15c1d700010c1803421b00c78f6b34a8c100942c407111f3d78e8a0e1c2870d1a315cb460f9af87cacff62db0cd96d178bfbe581543060c5a0e0b162c58f0df0515061506dc026ef1aa785538493849b8205c106361ff39f86db226628b678af88e5ca5f5345091678229c29ae8eb8b1dfec763371008e3783c3a8f04081020d0a3468f1a3d6ad0a8d2d8fbd9cc366800830a830a830a830a237e11bf98ba98ba98ba98baf8d9e391018366fbacd128140281c7230306ddc7e3f3c4f3449e891d2548384938493849b0cd114c114c114c114c112e0817840bc205e18258b2c7e3d757cedd0d1a08854060b54aa552a9effbbe6ff46787b9cf0e73ff2c83b3c5219bfb679b1de63e3b64739f65d961eeb3c3dc6719b0c521fb9f03070e1cdec43dff55d37b88eabf0acf0a95fc6bcbe7e1d86fa0cbd920f047167a1f573d5ffbbc8d6e9efd7c3c0fd17e0391de475bcf57446fe2da7fcdf0ccbef9910e9ed9017f9887b340033f12c7fb08e8f90ae5f949fe06f09cb3fcc056ef63ace7eba077d1f8ffd1bd8f1d9eaf64cf5f71fe35486f228dffcaf7fcbebf413c7fc8dfc6f710ec37b0e0394b7f20a5e737fff77a1e3af80f7c781ecaf9ddf63c671d3ff0c6bb08e4ff6bf336227af6c3f2dc83fe3c7c13a1fff5c91b2cecf91aea7d34f37c9dbe8978feeba53771f95f8d9c657ffc48b3b342e5bfe6e26cfefaf3db9b08f75f593cffc37f556f639267bf18cfc0143f52fadc7d7f0ef09cf97ea0a667b6c68f04be8b6affdf88e72f49ff5aa8e7a181ffc0f1394ffa8939dec74fcf5738cf6c899f0086b7f1efd9afd1d9a0851fa9e94d24f35f073d0f39fc07f89e83cd1f89ea6c70ee47627a1763fc7f46dec70fcf57b367219b7f4dfa06fb7abe6a7a0e5aff35036f2286ff7ae3ac90ee5fcbf036da7af643f4fc3f7fb7bd8d359efd1e9c05e6f8917ccf6cf34716cf0addfeb50bcf2cd80f76e21958e347ea3dffcbdf04de464ccf7e689e9bedefe89b48f75f61bcc190cfd7576f63fbecf7f6dcadfebce0f9706cb0d6bfb6e02cdbeb47aa787ef27faee7229d3fd78337d89faf939e3bc6df96ce0669fcc8516fa299ff5ae87d543e5fe3dec417ff75fa2e36ff3f2ccfe7fbfbeb4d5cf45f51bd8b33fe3f24ef628fff4fcd73def0b391de47e7f3b5c2333beb479678ee087fc7cf431bff81516fe2f1bf42781f233d5fc33ce70b3ffbe839c7f985079e8b9cfe5c1bde4424fff5cc732ef203419d05067f248bf7f1cbf3f5f9dc6ffee6f5dc4bfe56f5ecf736aa79f6db7bee3c99adf32323bc8992feebab3711d7ff47e05d1cfe7f71cf5f6dfe3547ef229bff2fd333b0cb8fbcf22e0af9ffde9c15eaf8d75abcc11a3c5ffddec6e7b3df8537b1d17f55f53c74f2bb49dfc71bcfd708efa282ff6fc5b3f1c09bd29f375884e7abaeb7b1ccb31f7c96d5f523533c0f45fc07883c03c57e248cf731ccf335fa269afdd7b8f731c7f355c2f390d1ef96e97948e6770bf33e1e78f69bf59c49fd451acf4243ff1a90b3c10f3fb2d3f347fc67f59cf7fcc241ef6291ff4fcedbe8f6ecf7e747ffcecfb9f903f79e8397feb501efa386e76bd833dbe8475278ee2e7fd73a1b5cf4af913d67bd1f98e95dbcf0ff31dfc7e9f3d5c33370d68ff47336e8e65ffb7ace6d3ffbe65dacfbff946fa38c673f066fa3a1673f2bcfdff4b7873718f1f9cae95d0cf1ff4d9f73819f65f2fcb5e65f6bf43e127abe52797e9ebf1f3c3fd3df19de4743cf572bcf37f5f789b7b1d7b39fa4f791c9f395c6dbc8e4d98fc61b2cc4f35f80b3c1b21fa9e85998e15fe3f03e3278f6c3f53e1a79beba7817c1febfbab34150ff5a810385aafeb52667bf0efc6b5cde60c7e76bdffbe8e7f9eae41958e6476e791fd39efd56bdc1de9efffa6d4cf5ecb7e7d9f8f53eeb73f6ebcbbf76e84d6cfbaf279e8718fe03f1f375fd5de35d24f3ff457a136dfd7f68efa1adff6af62646ff2b94f7d1fa4cf77fd45921f05f8bf03ee278beb63db34d7e24dafb68f6ec67ea6d64f5ece7e7ac91c19b52a07711c2ff17e3fd75e55f0bf45cdcf52e33f126dafd571a6fe39a673fbe37d8daf315d6bb08fdffba3cffc5ff59cf5ff3b781f7b1edd96fd7730ef30363bd8f8e9eaf5e9e1fe0ffa367a0d98f9471f66bd4bf86ea2c50c38f743e7798bffddec402ffd5c2db28e5d9efee6da4f0ecf7f5fcf5e95f3bf50cfcf023f39e9fff133af0abfdd7dabc8b4bfe3f3c6fa38767bfb2b7317ef6fbf0261efaafa5de4445ffd5fa26aaf8afd1f751d0f355ca59e18a7fadc4dbb8f7ec27e239fffdc6476f22a6ff5aeb9995fbc3d43cffccdf6b6fa3ab673f40cf5f5dfe3543cfc1263f92d673e6f51f07bd8f2a9eaf6bcfc3bcff41df3b97fd6cfcfc15e55febf35ca4f4e7b27b17dfffefcb73a7fa33f279a8e7771bf4266afaafb7de44e17f55f03e5a79be2a9f7bf8b78e03bfa8ff9a9cb3414affdad99be8e5bff67906c6f99166de474dcf5735ef2398e72bf45988e75fd37b17bffe3fb8b3c12fff5a7ece337ee08a7711c9ff57e70d86e1f90fec3ddcf12378f03e6678be0278068ef891d037d1fdaf47ce0a5dfc6b26dec646cf7e5d9e73aabf98e34d14f05fe99eb3f52fda781fabcf57126fa28dffdae3f9abfe56f15cb4f516fbf2263afaafabde606acf57576f63a8673f39ef6285ff6ff906037bbe7e7a1b4b3cfba53d177bbdcb4ebc8d749efd88bc8f969eaf669e83537ee4ade77ce2077ebd8f0e9efdaeef63fc7cfdf0dc697fe7bd8f4b9eaf339e83c81ff9e8acd0faaf3179cea2fe22dd1bccc0f355d673d1d29fcbc2bbd8e4ffd3735668e65f8b3e0301fcc8176f6291ff4ae6f92bd6bff6ea7968e6777bf336329ffd28bc8f329eaf0cde460ccf7e60ef61adff5af6ccd2fd616fde4414fff5f96c0cbecd023d0307fc481a6fa39c673f216fb004cfd75aefe386e7abd873c7f9bbd79bb8eaff23be8927fe6bdefb88eaf9aae7f9abcabff6e75968e55f6bbe893cfeeb94e7a19adf6dcefb78e2f95ae06c70cfbf763c1bacfe48576fa29cff1ae9990df083813a1b64f5af2178130dfd7a7f315fc27f4f077eb5fd6b5fde4714cf57b537d8f0f9bae93d94f55fc5ce7eadfd6b5bde4444ffd5d433f0ca8fa4f2dc97fe4cf6cc9ef8096c781b433cfb05781749fc7f7a6f62de7f6df2265af8af359e87827e3746cf4344bf9ba5e74ef277aae7218fdf6dc59b68e4bf967913affc573bcfc3b7ff40f240a1ab7fcdc99b18e8bf7e7a6e527f467b1341fcd7e5fb38ebf95ae84dbcfe7f6a6fa282fffae15d5cf1ff0179ee140d76e1f9eff83ca4fe6e2fde4406ff35c4f3b7fc8df626b6f9af8c9ecfeb6f1befe3a5e7eb99e7c77f07cf021dfd48386fe298ff2ae8b94bfc0de939e3fd40bd3771cd7f55f45c1cf5e70af1260af9af619efbc3df64dec74dcfd735ef6393e76b8db771d3b3df9ab7f1faecc7e87d84f57c15f4fc16ff653d4b7ace4b7e60a9e71ef277a9e7af21ff9a9d37b1cb7fe5f30c3cf22399bc8dd667bf3ccf5f8efeb54f6fa389673f02ef2388e7ebd9f317a57f4dd473d1ce9f0bc259a0db8f5cbec1083c5f59bd89a0feebae6736c44f80ec19d8e047ea781f213cfbe57a13a7fc5739efe1f5bf0e38f04bc0bf96e5f90d58f6fa2351bc8fecb39fa5e7bed24728cf571c67851bfeb50ecf2cf03f363a1bdcf123539d6d1d7f6b7a1339fc571d6fb012cf7f69ef6399e72b7c1668fc912e9e8584feb51f678524fe35106fe38d67bf08cf5f8afeb54e6fe38a673fb6f7f1eef93ae15948f6afbdbd8d579efd966fb000cf57eb5920a21fe9e6b9ddfed67b1f5d3d5f013d77a73f9f3de759bf11c773f1fa1e93f00c2cf123a3cf79ce2f44f02c04f2afe978831578beb67a06f2fd48236fa3a867bf396fa3a3673f2fcf39d04f74f0261ef9af66dec7e5f355ee4d3cf05f399c15c6f8d74e3ce7b89f95f33e9e3dfb9d7a13a5fcd738cf6c961f897c1f8f3c5f5fbc8f6c9eafd5b3c2fed7203cf7ab3f33781b1f3dfb7d791eb6ff8155efa291ff6fce9b78f65fe5dec5e3ff47e11978e347eebd8951fe2b9c6721967fcdf93c84f3bbe5791e86fadd78bd8f6ecfd7bf8973fff5c53370cc8fd4f236d67af63bf41c3cf4af893d3fd2df76cf0ff37781e762a83fd787b34dfd3bd4815f32fe3535678365fe35e0fb48e3f9eae07d0cf17c0df0dc2d32f0cc8fe4f2fc566d0cf3ec177d1365fc57bdb7f17df6d3f0cc8efd607dcf423bff1af51958e5474e79ce197e16d2db287df6dbf02e62f8ff9aef238ce7ab82e7bee7def367e0f3d0fd0fb47a137dfcd72ecf4348bf1ba7b3c00a3f927956d8e35fbb3b2b14f0afc5bd8f629eafefbb08e3ff2bf23e4e79beea781b213dfb817917b9fc7f89dec359ff75ec9dcd7e36c8db68e6d96ffa2676f8afedf3f1feef7a1f113cfbd13a2b64fbd7e8dec60dcf7e62cf59d77f1cf13e0279bea238db7c7f8b3a2bd4f2afed781311fcd70e6f239a673fea33b0d58fdcf3cccef991109ebf6efd6bb4ce061dfc484acf6c8e1f293c2b7cff3519cff9d56f3cf1dc63febebe87acfe6bf12cd0ef47067a132bfcd719cf3ff237d8bbb8e5ff43f49cd37e76c9fb287cf6cbf436c23dfbe5e75ff86fea7d1cf17c1df03c04f11f18f22e82f8ffe067219f7f8defb9bffc6deb79e8e577fbf126f6faff1ebc8960feeb9ff771d4f395cedbe8e7d9cfc9fb48e0d98fd5f317a27f8dd3db38e3d9afc19b08e5bfbe396b1c7b53d2f126c2ff95caf30ffd2df73cccffdaf54de4f5ff2d78fe7af2aff1791b4f3cfb1578668d3f988977b1c0ff27e259e8e65fe3f13cb4f01fe0713648e85f0b7b66effcc8b6e72ff88fe90d46f7fc277c1e86fd0620bc89b2febfb37791c8ff17e70db6e0f97aeb4d1cf5fffd5978e15fdbf0fc19ff6b3dffef6f1a6fe3dcb35ff0994dfbc350bc89ef7f8df2262ef9af6ade4434fff5d07337fa33d8db88e7d90fc9331be54712781e62f9ddf69efbd09f8bcf5f62feb544cf9ff5378c6776c54fc0c37367f91bd6fb28e7f92ae47d5cf37ce57bbedc7f51cfec813fcc7936c8eb5f7bf02e12ff3fb93771c07fa5705698e65f7bdfc747cfd72fefa394e7ebddbbd8ff5f846776d38fc4f0dc19fe06f206ab7bfe1b9e159afd6b70cf433cbf5ba0e71cfd81939ef3819f8df236529ffd40bc8d779efd8ebc8b6dfe3f4d678362fe35f63918e75f1b3eb3697ee4823751d47fedf52612f8af76cf39c50f3cbe8f3b9eaf76efe39ffd263d07bbfc6bfd1c64fb91909e73951fb8ea6d04f3ec077d1377fd7f0ace0245fdc83befe3f1d9afefb908e8cf35e16c90c38fe4745608f6af4d78173ffc7f3cdec43bffd5d2fb48e2f98af63e967abeda7917a5ff1f98e79ce7172e781705fc7f1dde4652cf7e75ce06e17ee4a567219c7f0d7e1ff53c5f959c0daef891a0dec415fff57d1383ff35c1b331ec4de9ee5dc4f2ff157a1b733dfb393a0b64fe481fef63afe7aba4e7f7c86c9c1ff9e05d6cffbf286f229fffbae97908e33f10e77dacf07c253eb30ffe30bee721a5dfadef392ffa8935de460ecf7e63efa38fe7ab89e7a29c3fd7dadbb8ebd90fd21b0cc2f335d7fbd8e5f9bae36d6cf5ecf767d1fb08eaf91ae70da6e1f92fec6d54f4eca7e55dfcf2ff317a17d1fc7f959e9bec6ff76c70d4bfa6f69c5bfd4613efe399e76bfc2612ff6b836776c68f64dfc45bff5fda336bf78b2d781733fc7fcee72194df8dc759e383372541efa28dff6fc9815f0afeb52e6fa3a4673f31ef61acff1a7636cffdec9cf731c1b35fade722ac3f178af7d0d57f3d9e055ef891cdf711d7f355d1736ff93bd6dbe8e4d9cfc6739ef203519ded671b93cf7e706fe39c67bf21cf4349bf5ba7b36c9e1f29e17978f61b88f3dce86d24f1ec8776d6d8f6a634e8f92b9a48eaffebe7a2a03f97dbd9209a7f2df8366a7af653f3360279f643f13ee67abe3a7a130bfdd751efa389e72b8167608b1f09bf8f4e9eaf369e857efeb5ea735ef103c1dec7b9e76bf03d34fe6c7f13cbfc5742cfbde8cfc7b7d1d4b3df9d7751efff33f32686faafbcdec500ff1f873731ff57036fe3dbb35f3f7fe5fad76e3d0f59fc07de3ce7443f91c6f370ef778bf13e529faf209e59097f989537d1edbfaa781fd79efd60bd8d759efd8abc8b29fe3f1fcf5f8cfe354fef638de7eb83f7b17dbebebdc1d89eafb19e7bc6df979e876dff0112ef63abe7eb9fe77ce7172a381bacfb9199de60129eafbcdec405ff15c4f3affc2de04d3cf35f0dbd8937feab8fb3c140ff1a80b3edfcbbd39ba8e6bf267a830178be827a1737fc7f796781c81f79e36c70d3bf96f63cc4f4bbd57a833d78befe3d7fe5f9d7283d77a13f139f81697ea49703858efeb522efa28affefc7f310c9efe63eb7a83f0f781f8dcf7e9edec702cf7eaddec5b1ffefc273aa37f1c17f25f1cc4a7f2480f7d1eff9bae80d56e1f98f78a0f0faaf45790f49fd61fe3f47cf4314ff812567817c7ea49ab3c6b43725e5f3fd9ac8e9bffabd8f5e9eaf79cf3fe62ef0f7f3c02f07ff9a97e7219ddfadcf73f1d39fcbc35960dc8f749f874c7e37a7a5e72ff93bec6dcc7bf6b3f0266ef8af776fa388673f01efa1aaff3a7c0f4bfdd7fc2e8ef8ffa8efe3d8b3dfa8b346b537a5e5fb58e8f95ae539dff8812e9e5fe5ef006f238f673f0ecfec971f69e01958eb47fe7913b5fcd73ccf0ff4b784f711d1f315cb737ef303afcf454f7f2e0e6f23ac673f41cfbff5b78ce760801fb9e87da4f47c25f33efe79be3e791b7b3cfb9538cbf2f99113dec637cf7e3f9e73991f38eb7908e13f20e24d2cfe570767854dfe35f7997df223d39e59eb8ffcf026cef9af929e813d7ee491e761d96fc0cb73fef1033d3db39d7e6486e796f037f5991df32311bc8d5e9efdf29e81317e64fccc5efa91169ebbae8b62febf47efa28bff6fc8bb18fdffbc3cb34b7ee480b35f1bfe3532cfc1253f72d6f341fd1de2b948e8cff576b6717431caffe7e70d26e0f98aea7d4cf57cddf3260ef9af62ce3695bf5dbd89bafebf03cf5f67feb545cfd9d45facf13e963dfb953adbb5fefce06ddcf2ecd73c50e8e95f4b72d698e04d09d0fb989ffd2a3d77ac3f377813d3fe6b85b791d2b31f99e7dcf713439d0d82fd4844efe299ff8fd2dbf8e1d9cfec5d64ff3f096fe3ddb3df84e760961f793d2ba4f1afa1781b4b3dfbd9791b233dfb8579132ffd575acfaffb4fea19b8e247f278ce997ee2a3e722ab3f9789e706f0b7f24d64f25fd79c15a6fd6b72cf79ec673fbc8f549eafedf317967f8dd0bbd8f6ffcd780626f9914ddec744cfd72c671bef6f4eef22d9ff87e1c02ff75f73f33e0679bea678176bfc7f4a9ed9087f189103bfbefeb52acfc21bffda8a3751f95f8bbc8979fe2ba667e0941f29e54d4cf05f3dbc8f959eaf65de4700cf7ea0ce06bf7ea4a13771f85f193cb3877ea4dc73867f60a577b1f8ffcdbd8b3ffe3f366f629fffcae9994df52341bc8f6ccf7eb1dec430ff15d0f390c17f80c3731ef103fb5d34f3ff4d7aeee2dfedfbd8f77c7df3dc72996df3231b3c1ff99fd2d960841f59e97d4c3e5fe19e874a7e37e673f1d49f6bc45921827f8dc2814259ffda933791fdaf07dec357ff15ec4dacf15fab6f62f5bf6e791bed9efd8a6f62f3bf2a791ff93c5f99bcc1463cff0d781fd13c5fa9ef23abe7ab9fe721a1df6dd2db48f7ec277c1f393d5fd9bc8b6bff5f89f770d57f25be8fc867bf57cf2ff2f7f119f8e447427913f7fe6b96e722a63fd785e7bff91bc1db98e6d94fef6d5cf5ecd7e77d0cf0ec677d137bfc572e6759f74712df4500ff5f85e7e1f05fd3f5fc577fb3781ff39eaf16dec65bcf7e899e81097e648eb7d1c7b39f893731d37fb5f53cf4f3bb217a17ddfc7f9bde60169eff8c6fe3f2d94fee39dffa8d8dde4753cfd73bcfdde1ef3167837a3fb2d5f397ff753de74d3fb1ef4d4cf25fd1bc8d419efd52bc8f709eaf40de47e9f375c3815f61ffda95b3eca31f59f73e129ffd38bd89a7fe3fe0fbb8e2f9caf6fc267f933d0325fc48e5d9a0a37fadecb947fc3de7d9d0dbc8e8d98fcb59a0f547e6791f87cf7e9b9e81217ee4f34d24f15f9befe38267bf5bcf6cfe8f8bdec706cf7e7e6f63dfb3df9b3758daf375d59b98e8bf9e3a1b9cfe4856efe1a8fffae70ef0b7f319b8e6478e791e92f80f1c791795ffdf943711c27f2d7116987fe48af750d77f25f0ccc6fa9124dec707cf7e7fefe291ff8fce9bf8eaff037bce397ea08c77b1caff27e84d8cf45f5dbd8dd0673f0c6fa2a0ff0aea7d94f57c25745638e55f633e03bffc482c6783c51f79e8f911fe777a1fa1cf570cef2283ffafc5db38e9d96fcc59e1f35f8bf1dc667f379ffbd19f013c7fcfdf10dec743cfd72b6781a57e249eb771d1b3df967751c7ff07e55998e25f23f1fc12ff5b9dfdc2f4af917a13effe6b90e7a1a2dfedd2f390cfef56e84db4f45f679ded5d7f6e7b1b133dfb65791381ff15c159a38037a5e4f3ad7fa3781bdd67bfb9f711eef99adf47bbe76bf16d14f3ecf73e7fa5f9d718bd8d4f9efd6e3c67e4cf3679fe4af5afad7a1e12f9dd74bc8963ffd5ed1918ff48226f30b8e7bffc3e2a78f6b3f5365e78f63bbe894afe6b9a77b1c1ffe7e27d0cf47c8df236d63dfb0d9ffbc9dfacceb2567ea4da7b78ebbf9ebd8b28febf1e6fa3a7673f37cf7ff09fd3f3d0d1efa6e9acb0c2bfa6e179a8e13f407d1b3b3cfb91bd8d649efd783cb30bfe30eadbd8e2d9efc0f370ee3f107d17e1ff4fcc33bbe547ae3d7783bfe1e7dce1672d3d0377fcc81f6f628aff0a7dce217ee0dfc537ff1fa76736d38fbcf0263af8af239ed9143f010e6f629dff4ae93947fa8938dec5e4ff27e55dbcf2ff113a2b7cf0afd9bd8b7bffdf9903bf78fc6b71dec5eaff97e6acb0d4bfb6e43d3cfe6cfd366a78f60b3b2b84f2afe13d0f27fc0774bc8f2c9eaf069e8738fe03a4de435cff35c0f350caef367d6637fc048acf5ff437dd9be8e2bfc2ef639ce76b903791c57f95be8984feaba8b731cfb35f92f7f17dbe6a781e02ffb5bfe70ef4e7afe767f97bc059b6ec07fb741668e747a2792e1afa73c13dffd2df18de6062cf57516f3013cf7f049e8542feb5f6f95dfe4e7b666ffcc8e0fb58e2f99af69c973f30c7f3d0d2eff6e96db4f2eca77c17a7ffdf98f7b0d77f451ef805fdd7e09c151ef9d794cffde2ef4acf40f8470e791fb33c5ff1dec736cfd71e6f62aaffefeb6dfcf4ec07e72cb0d08f6cf33e923dfb917a834d78bef67ace7f7ea1a56776d18fa47b83159faf9d9e834f7e64ad7771c1ffc7e24d44f5ff099f81643f32c69bf8f55f17bc8970feeba3b35f83fe354d6fa39d673f23ef23a4e72b98e75ce71726380b1cfec816efe3a0e7eb9437b1d4ff97cf0685fc485867bf94fc6b7a9e1febef176f30b7e7bf9f6d1f7f8f7a83913d5f49bd89b3febf00cff9ec6791bc8d9d9efdda9c05aafa917a9e1bd49f05bc8940feeb9737b1efbfe67a1b413dfbc579ce6f3f1be77948e33f20eaf9d233f0c78f4472f6abffb529efa39de7ab9137d8d9f3f5d4db48e8d98fca1becc3f39fd9f310ccef06e4f919fe9f7a1602fad77a3c0f09fc06243d0b05fd6b3e9effe4efb2e77ce607d27a838178fe3b7b835178fefb7a13fdfcd74eef2cf6b31e9e8726fe03489ed9be1fa9e1b988eb2de6e60d36f7fc173c1b14fb9189de470acfb9fe3fb6e77ce507b27a139ffc5737efa3dcf315f82e8afd7f16de452dffdfa13771c6afe977c37516f8e747ae390bccf323d3bc8f4f9eaf379ed9323f32c173e7bf71bc897afe6ba63758d9f3b5d4bb28e3ff3bf23efe78be9e781b053dfb49391bbcf12349bd8961ff55c2d9c6f567086f22a0ffdaf79ced7ed6d1d92f32ff9aa2e7fed3c42dff55cfbbf8f6ffdd781b733cfb497817d7fc7f98dec5b4ff0fc433d1c6bb68e0ff3b71a070d7bf26e5f965fe469e65a7fcc802cf6deacf696f63ac67bf416fa3dcb31ff0f931fed37aee497f167b1e72faddfc9e5fe3bfad7711efffb3f25c44f4e78a7b66f97e24d99b08f65f233cf785bf7f3cf79c3ffff9d2bfd9b3c1093fd2d233fbe247f6fbb8ebf90ae99d01fcec863751c27f45f1267ef8afcab3415cff1a83e7dce607fa3db3707f5899e7a195df4deff989fe9e7b7ea1bfdd9ef3a09ff8f60613f1fc27e06dd4f3eca7e47decf17c2df12eb6f8ff843c7fb5fad75a3d0f65fc07e43ce7e39fe3dec617cf7e09dec51dff9f96e7b3fdaff4dcc7bf93cf5f53fe353f6783d01fa9ea5948e75f8bcf022ffdc8396fa2dfff57e039a8eb5f73f00c94fe48216fe3a167bf2b6f63f5d98fc473f0ca8ff43b0ba4fb91786f639567bfe4fb78e1f97a7c6645fd480eef63a7e76b9bf731c9f335c69bc8f75fb53cb3f18f143bf08bc0bfa6e540a1ad7f0dca9b68e0bf6e7813fffc574f6f6290ff0ae66d44f5eca7e76ddcf3ecb7e44dacf5ff0d78173dfc7fd237188ae73fb56721fcafd1781745fc7ff1815fc67fcdcabb78e0ff43f19c63fdc61befe390e7eb8ae7dce717163a2b8cff351b6fe39267bf19cff9d24f74f42e06ff3fb7b7f1c7b3df89e7ecf71b1d3d7f35f9d7f6bc8da39efde8bc8dd3673f0fcfdde7cfc1b341113fd2d3d960ff4842cfec991fa9e06d3cf2ecf7e24d8cf35f21bd8d459efd5abc8d679efde277f1c6ffc7e43958e547e27a1301fcd7b66760901f99e4ec17ad7f6dd6bb98e6ffb3f4268ef8afccf711c3f315ec0d167cbe627ace4d7ea0a97731ecffb37b83c93dff01df464bcf7e66de4614cf7e6a6fa38d673f086fa2a7fffaf70c1cf223953c0f85fc6e399e87767eb73fcfc14cff1adafb18f6ec17ea4d9cf05f533c67083febe66cbf7ff7bd87a7fe2bf02cb0d38facf326cafd57176fe3a067bf29cfc0583fb2cf7bf8f75fd19ed9ba3f8ccffbe8e1f95af6263effab93379887e7bfb2b7b1c9b35f8df771ccf355fa3e367abe7679ee077f4fdfc4b7ffbae23998f6231bbd8db49efd0cbd8b14febfe473aefbd946efe2dcffa7e3393ffa8937ce7eedfad770bd8f6fcfd77e17f3febf2def23ddf355f8fc13ff5dbd8d809efda0bc89f17fb5f23e6a79be320ffc12f1af997917f9fe3f34cff9c90f3c7556e8e15ff3f03c64fe075c3db3a07ee486f7f1ebd94fd3db18e5d92fc77310ef475adfc4b2ff0af73e8a7abece792e6afa7365780f5bfd57e3d9e29e3f57db73d37551c3ffb7e32c5be44706382bc4fbd75ebc8f749eaf44de47b5673f57ef63f4f99ae16cf0ee47963a5028e95f33723658e75f2bbe8f799eaf49de4457ffdff1d9487c9ff979ce6c3ffbe4acf0eb5f6b7b1f6b3d5f0fbd8fcfe7eb8567b6057beb479e382b1cf3af41df461ccf7e6defe3def355c473b0c08f74f4fc65e95f1bf526eaf8af42de6066cf5753cf6c8c1f99cf36fc37a837f1d37fd5f52e3af8ff5e3c030bfc481bcf4331bfdb95b731faec97e199ddf1238defa38ee7abdb5961887fedc3f349fd3de27938fddd5a9c0dc6f891a2ce068bfcc8586fa287ff9a7c1f793c5f393c1bc1de94729cfddaf3af557a66f57ee4d8fbd8cf7e949ebf7cfc6b749e591d3ff2eb6dacf0ec477cce1f7ef6d27b68eabfb2cf6ca01ff9f62612f9af63de4436ff75d1db78e9d9efccbbe8fe7f559e7bd59fd7ce02e7fcc833efaf59ff1aace7af57ff9aabf731eef9ca9e0d22f991b2de44587f901fd8f7cc467f24d83b87fd2c87e722adb75897e74367856dff9a85e7a2ab3fd7897711c7ffd7e45d34fbff34bc8d469efd5cbc8f6e9eaf3ede4535ffdfa5f7f1c5f335c1739ef0b370ce0651fcc84fefa392e7ab8c67a19c7f6dfa2efeff83f0269af8af3bdec418ff95fa06dbf0fc27f69cd7e4c37f03df452fffdfa267e0f34702791bf59efd42bc8b4ffe3f3e6f628eff0ae4b908e7cfa5f6366a79f6633e03b3fcc82acf5f86feb54def228bff2fc8fb28f6ec27ea996df523453c0f0dfd6e949e3fe5efb3b791d3b31f9be7aef4e7b13798ddf35ff15d24f0ff857806cef891d4e7a7fa3bc5bbc8e3ff0bf3362279f683f15c84f4e7aa7b1e6af9ddaaef628effcfc973a9e71b67bbc6df98ce067ffcc857cff9c02f15ff1a9a3791d5ff577c13b3fc573ccf45467faeb96760da8fac7116f8e947da797e25f60bc3bf36e6f9ebcdbff6e84da4f05f633cb30dfe30bde7e1da7f80f82e96f8fff6dec750cf57396783b2fe3505077ebdfd6b609e3bd39fcbde475acf5743cf17f5b7886746cf43e1bf96eb6da4f1ece7e07dc4f27c759f83a6fe35b667e1827fadee2c30d78f14f47c3d5648e45f4bbec11c3c5fafefe283ff0fc6fbf8f77c6df4368278f63b7b0ecef9d788efa2f0ff7b7b2efaf97349781b033dfb457917f3ffd7f63ece79be0e79135bfd7fc6b32c921f29e04da4f5ff097817c7fc7f90ce065ffd6b099eb3809f4d725618f7af61781f6d3c5f213cb7d8dfcbe72f24ff5a9eb35f7efe354bcfc0e88f0cf29c5bfc4000cf46b637253f6f63a167bf2acf45547f2e12ef61aeff9af66c64df667f9e59b63fecc6f310d0efa6e819d8e64792791feb9eafc3e72185ffc0fb26fef8af5edec4e97fadf206e3f0fc37f60c6cf2239fbcc1483cffa13dbfd1df149e8baafe5c25de4509ff1f8d03bfcafe352c6fa38a67bfb5e7a180df00a4f7d17dbece3d3fcedf09ce0279fdc8416fe394673f1dcfec889f8085f711edd94fd5737ef103d1de4717cf570467f3829f9df21c9e06a894e8dd6a4296c39442c82003061999a199090001d31340e09854220d07b3244e6154b4091400065d9c64f1ac064284903106000000000400004000000001ad10f607323d1ff3e06cd495ab1c7493d74b82073fae0c073e3a2a48619b457377b01d5ed0a5f9eef2704eb48863ca81cfe1d5251fbe8371797dfb5f22b399623324310b11eda36616c0d7c1205deab1722899cf10281c09978c1f52c5a5b2b807bc31efb2d2dbf412cf59fd6a8764b92a43b143db447033df223522b0e1cd50ebd3f222dbc3da38f2ae4e663878fccd5dc4824364c13bf1d022943b23aa43b1e07ac6f394628595e0f65e0dfeffb11dc7a99b64c5bdbb8bd4eda0ae2dd79de58d88d5d1542757dc77f49ea82fc1d3ea5d32697afacf530fcc4c6e59a278e23255c800f690b1b09d3b0517c6c7ca1b3d34b8196b0b47d35a4f4619e82cc94cd6f7e399f0f2d00b6b1054f532c2a8fcb2bd5b15c337a7ece2c36558b9c4ff6a50d87e298a13b208ee529d58dc4ac3a42606fc4ac4961b49e9f068f0c3453aae4f948f15fd9e4d91bc37ad48dd6941412ad32d57593a0da9da092dccdddfece587a5089e59e09afe589702247c729438170181bafec66536339ce39e7d199d6fa61ceea4e8debdf7bbf49044b72088f6d0420bb93a19bf22911ec76ea30b7c89bd6882a082b2fb57715144e593526e93c506f0a2509f498bf609164e1762dec085139f45e799a8c421ed41840cc6fe37b17b3386baf8be04f265c8a228f327a80427c08744d005ff57c4bb5ca169bcf0fa2027bf44a3f1c340d25ae0a01d7e188813bcba9f47c5492bf9e8e8e54cb86d089862da5a735ac1c203270463b1613b183e2ca4470eb277145e73f467e18b8681cf33567dbcff309111017c45cc0da5e23332e3508c3b105d2bb7aea832db1471fd47d60d321d8264be5efdf13c31d648b2efb8c77fba2b9ddbc1ecd4c002f6327c8364555ce106dedf45aee10b720d2a3ff47e7370944cba54529a868f7022961ecbd45e0cb63190967d3b81d9b707b206a30a301fa067c14da122a6bb9cac0a7c06e030bb402fb330e53328bdc38feaa0bd39a7509e20f0be6c51e18792a0b42476fe62fccbabb6784faed9e5349a86994233e03831cd37be4f18720992d073234d2f23fe83dcd4b5241c021ccf86e4c8817642dcabc1d6b5a05c4653bc806e320969f620e7f1d3ab617d20359ac4636d8e25fa8bb75c58cec8dc3513954397e020c17772682c698ba4d3069f50ca78b98790f1bb3f2c1b9a3224b0635183b9067136bfcbaf777d2bf3a44448d8a1edbc193ee0a8574025ed8098904d5e9e0f34a8dfe0161cdf8beaafd7fb984fb8de96be6d2d22ce48db8f82d4e9a8740ff93ffc18ccae489b42e328f67c97848fc842d797c2efebee9ce57ba104e6c20359ca83fa6f726a8000238906111ac54fc4fc19a0b413285e6145e641f19c51df1c00e7c7236da11b1508f9e1813d15881acf8f5d4352d683eda39a08fa51fb1701177c8b279cc92dc0ecfacb5ecd914f3acf6d4e7c2c3d49f94620601c72e0bf31dccb01ca832374ab0af901627834d0f23ca6afdd8758e2bdd5cc449bf51304f64de11980f84b5542887c6d7510f02dcf4945e7341f95ffdcede140d81afc1e0b2db01c9dfa5c2ec94bf8bf28ac982b1b16ff2458241f8a5905bf043e73e059072c77eaaff9cdf0e1133fe6c896455799dbbd4e5ade0ad4135aa32b226f06f0eafb483d061d71034aeae58243f8bebe1bb91b9fad000e3c106f0769928cc80e1f73e8774d070d634f8076c9770a38e96c86dcc676ed94aa16db3c57372b80fba80fce9f3e745b89417541684907c433d633757551aaebdf631277fb3e1d39baead97ef898b71a767b288fc22ea763ff65cd427409518c02ede254c27da870bb646e2c78df1443cc5ffb9731f9f996adf4510c1d88fa0bb5fa2cae29ea5dd5b5317e61006d554453fa477c28120573526afed3c5c4a5f14dde1d5f2be230bd807e4138bbdfb1d2fbf6cf37c243b211dc99a0c12d85a615deddf424b2d2e8c74f4f543c202fd5400fcbfc9bcc058963694c4ea95b9e58ade7f90184ffc18ce883b3d007ede04c5a086d39685596a29a1c151e204c81703fd518f8c9d3e1e79db0a5436a6699ce507c2fa0c4f67d189ba29bfb7fecbeffe8fbafe8a07204cd2b4271c17d520a5bd4660240df0ab834532bb0084daf382fb92956cf4791741e43281e398ebae27843ef9627381e1abb38e5b7ebaef0507a96fba52a43fd0e0a286179df4b24e66ef0c10f2436be063f88703fd5177a0ecb32314600a8ec4e9b86c704c4f701edb9c381e414d43971f7186e5951fa56b2a5bfdad306083b2c4d2ddc70bd6361190f2c4f340c48d12962fb2eb4fca0969c08b4b5888ef52ddf4a74118fa511263ff3ac9b4ff1ea746f5ff6699bdeed71d855875332a1c7af42e46753ae2bff1aca7b5417c278ab477f2a509c1e6ae4a0ef0d16c4afdc26bdde5cb41e9a31c48279c9552f5ccab1b01925171cefb3cbc0ac23f7eeddb90d0bd2550f03c22a7986daf7198ccba1bb365cd57e79ecefe165bd376ef4b1f4950757261cf27186bb6d8459f695e0fbbc31fd123cf29f7f1ef223fb09433ca7c267fdb08c6c5bd3207f82c2022296e07fd9e18c3ecd8c9502fad34c9c3d311a1f2612abaa86a2447d185222bf6f5b478b06349415bdad89bb720f895fcfd6c3c536bfe1d1eb31dc89e6e67cbddec435f1e7f2567cbc3936bdc40ff4a6e006f343e68f7e263cf6fdd2f85f9c00edf5b8cc2f9991999d10324d76f3e0986e6e4df8d1cf5e317de15f897931b19723fff77cafdc47715c270decff3e6798d0163ff5160ceb7fe4c6fb7971e560101b00799a71e95affa62ff13e53c8a7514ed7fb13af6b38121791fe36459ec2cd7f21d79d4866cde041f7037cdc9e647e56d3783b0c1ea189d1e9a5618176bb748de6a27eda95bd9627d717658d760841a6bff2459d7533c31338af9cb24653b943e54c551c238d99e31de3d85d0876abe37273f0b8fc51d4eeb4a2c01aca8d51f14847fe5c75d22f16f24a04da06fb70205a971aed11e33006fede74e1441976e4b41a24966d4043efdf9b1f4c4dd4bd96e0afae53f49c47a59e2f47ee5feea3a7644372ef23930f26278b2cf777d8e35f6acfef0d1a481e8cd406191a91ebb81849343422c8130b95a3307e27e824cfb61ab6aea4db35525f389096bcc35ab172a68e4a616cc7a87fee5a4a429806923b56ea58294f07ca6671d1ab8a962d4bf64ec53a9edbedb8ccce4dbceb9175b06d2c3b8792cefbf765ee74bdb3ebc55089a4c3280f396aaff913f8986fb69e8c71b4d8adb8da1fdffbc603ce796a01d69f80db80ddf45bd62712846b5c145bc56b8503f86ccd7e3b9df24206dddc35f65ea98af6aeeacca573937c9bcd697cc8ebd4c9e98d479fbd71306e2f40be980bcab0dd002a5b1b4fa9c70803ca1353818cdb0da0a255a3147b8c20a07c31159441bb0154b63492520f1105c81f630119b51b40654b6329f41041c0f98b695f80c93f0beb95298e4f3378097c6751e377e9f6b68f37a578cb2b639c22fac8594e649cd54e88966941e063407a9f6bef0cd94081091bd1f592b562c8881c0d3c982a9e3d9cb0115d6f17d9834360fe96d53fc2e6d5c47f7232a9419a40916da52d916a8494112c228a86cf256bc7940d5ada9259b15423a64cf0f25675dff414117792b762e48297b56456db9cf8bd03b948db3f4e66350c52e89957b6cd59a3512a26195e2f293ab6658ddbea3883f165643beaa7f7f4442e62ebd613b707188567e059100cdb00dd6cdcaac8fa2a28985c1bd108cbac50b99c61f03a260cd786e849c55ac73c334f7a17d5162fed704df7e20eb6caa49bd1741c86137d55adaddb63e30d67f61a2d758b74c87e999f3635d9456905e23fce4e887061246cc6eb07e3e6e63269fa31ebabb22f1dcaddb65d2866d9c323b39e23413248c23e11bda4fa58741fe31fe4361c6487a067c519e40b22ded578252ecb936d36c8a7bbe5a4c4b8cea73ab7ca1bb373413dccb99d6861460a6846fe976a65a7d6f6deb1099b76aba6c06af8e56a9be1743fa07602f092bebfc99aba713c9e75792a34fe7833d68bb1599089bcc29a39a682a5e43a7cec12e887e401487d3dad9b65cdee286f2a535a55515c2412b326deede35e96c4074e6d1efe3f02a6c13d42736968693345dbfc60924ea4109a39bcdd57ba6379cd8d092f554eda541ecbe1cdfb4c77ce8aacbd342c61a9b29600ff03bc36f0741e2067cd8c4c95005919b88cafaf0b9221d2f0e6b3a1d7cc1f9899b7d7930e8f7e37fe53b1e5aaf4796a2e4fbc140cf7ae9b515b3f08a70c5f3b87be7318bd5d4b5b4dc9759064ea3076ff09cf0c5974b67a5919025aec5a9b1cc8c8705a28cafa5abfd327ec282ffdf6b8753417a73e9036367c85d71099207474316fcddc7aa66ca53bcee837ccb63999f81879e6fca1b77ee613efb20d5cb00fadd208f8eddae5ad73d1ed2db7616f1cd45cb981c73d6b5a8e1f3300e754bee56f380617f4d1c4c1e5cf51fbfcadc66ae9ecc08e90b2c784d8f52ff6f06a370fa6befbe977d831eccbd565e63b2cdaac5e93427371b016b6912bc0fbe2274a620e96504b36d9526cce62e691f95ad26129e551a2bace2c731c8b01e58c2565ea10395712ad8d78146dc02cb9108785b9b3f25fd26d440e599a0bf545d3843f4e33792e7f358071f5de1a57daa534cbddf64992f7ae0a2bd478c23bab9d8c0072616797394cf5e76f1bf9580ab206affdd038ddd5b938b05fb4f6c699e1faf19125c6c399f53d03cd52b1500d8c73beee3742bd6d6c98c5544b0cb6c72ddf672c1c0d5df59915b16676b6d472326d5dbd12d62d8d8fa098567d69db7d9536c65b01b2f019a74e69847bdd4037b08b8eb199db6b9ead3869ab6afba662f5a6de7255a06094ed2db97d0c68953a6d79ef5cfad759a3d8bbccac5ce0f62cb32b77d536fb1b4bd6ef59fd2c49c25463af55d2a6713667b7261f2427550399b92ae0371fa0356309dd9898349f6b6c5c94a5ccb9ebb4af3aac8ea1e703e2dc0f7d2dccd7a592f0211c073f444484b3d8797f86759a865c5b6d788276f1da74d433f3b55d6bdcc6006c842504fae72f20447b1ceab8beef75b3c6fd871898269f4d8d61e7f65ebf7aef7bc5beca34bd4a9f59b5f7b14091d20d275da8ffe4b24da2fb70a31bc5cc5c3efefb4e93abde7635157b731e69a9dbf4fc344af081ddf7ff31ffb492318196ae078850fa92e9b5b22ca5befd87716577bd33de19adfa27d840e4de7fba2722c9ff764f557b67e562e925960af5e634c9b61b8766fe830171792f3274f4d9ffd523b7c26ca75ed171f3e77d1930a71a0bba71de748be9c3ddd0d59b8af53ebd01bf7e5cfaaf0febc17e641e76a3788161f5b2ea479f09edacd893b43ad73f1d5f98f54ea078ba373a7ab76f6c28614effd63966d81bccd09e1b1570f4ed3f46835d6fb52589f63f8c8918eb08257c1d5cb138e96bf254e01debeab22d1b07437a097b79092afbe9360b3ef61d546b04358fac103cf23236d87a7b20b1c3f9e21f7f5d12caa0be5471ca75331bd90d5e7c68f4ad0d3786cccf6a07f154dbfaa7bd3f55e39c5b41b72e047dd54d6f66d57c480032eb1310d08dfc21b7145adf39cba5e083b9ff88f55bfc6ee4f3777ab5086b537584b245b5d659f51890789010734399de7749731383583d15641503200346675f3bafade5f458682de7101bc28844a35b188ebbf2f5173439f2ac323c1bbcdc5ef8dc7e9de64d7e70392e43e0cb615791b8d58b64b54e5e94e6c0eeb92a31780c31893d764f9055efef1ed50425be30e7f2eea7121a5a8457c09fac4ac5e0c7f0265d9168a70fb029ecec45dd0db47c9f1eb00f2fbe7582dd549c58f6dcf0eec874e6b87dae5d890aef5af389b7309f9963e15c0023d19a273a3722de67d420aaef13eb29ec05040a5c2a2b92e241eab7e79b9a7b36e54676c6178a27ffd9c1c12477711aba2f63373a488c1ace992e0e9bb3de3a93a43787d898083744e573de45e2078a0caa0e1cbad7e75fefabab33379b015b6c53879a76e0eff1692b2f5550ef702d6cec11a05f8b4bb6eaddc5e388ff6ccb18ce91cb1519c4ba2df7f11f16e44fa9b3325da023fd323fe5d2acf1da11461d22d6628c5249b7cdf5f5bcf51b2ba9fdc23ced73d82135bec1638b7be9dbdd7c2cf8f8e625570fba8bb46c6de003c96c1c317c30bfb4d76295f70447a0ea8daef198557819077908e8e7136fc31ae39f7d956a7796432ce74560516f7baa01af16ed50fd72fc714f2620ed4718bd896ccf0a4c4b2bcc6c09ffce84c45c3413e2e92d4e2407b8e0125d0e5f8ed8edea222d37cf9dab3bac5f1a65f1a9fde18ea2970370fd9b4710d93765701515f3e1ead431c329f8f44a58405615406d4984bdb1748fe3ea630eac566c9a20c3cf255bba7d27a59d537fda576dfd4f68a96a28cd792b3a0dac41625c513925461fd785583ce61849ba4dc3f651e57ed3f6a0be9707e3dcb7a1a3815ab396947cd6d468252911ff42a3e121e0aab922ad92356f55bcb8f3957adb12d37d1774dad7202e9c5bfc49818accd686fa1839310d691b4f77a0d6e2c24784f50b59625fa8523ead03176306c64c1f46b449f58f5cf80d970ed6f792acbb6ef6367565ed9a639388fcf5d5dfa51116da0aecaeb2c13957635e86d949801eec2bbee93386e7bfe3880e1b85159375ef980fda075ab0d2074aba8521fc5ef330e0905746ca4b12009304f89e34f38beed86248c95b1934d9d112038d4f5dc19993f6b2b70343a1a5c3e0de8e8c5f1f6a1bdd80399db9ba330b3542386e1afb904e71cb996b0b358bd8deea2e1ddc26281d1c055972a3f27de5704274b60d560110bf5e09cfc6fdd2ef0484e7ebf821da883058e5dc75605b25073d9c47779c54e8b028d7e2fdd7dd9203c19b1fa63e02d97afa429d7ba9952b65ff3c2963dc8a60bd0d746e92baedae897a02dc6db5ce4b3e6ce387304de16f8fed5be6fef4762a20b7aeeac5d7e0f5f3c36370a262fe05585078b51a6b7039d40c10b402800f60abd1e55f636b547f55af08c7aaab587e6c987f9ff778725d287d906c6adb6f52041b078c6525bb9c672fde7cae6a390b1cfcaaebf08a1d17aef461deb3edd48995efea107264dd20117b9dfcb6959ca5e3126e4e89265eda74dc5793515e7135d86d895ecb3f042aadabbb5fdd34f8c74d7f3786ae7f60b8d6fe377b031f5bc8a0cfc5e73612c3ffdffe2713bd23fd0b4c6db218c8923c91d6e612c5dee4d7a55dccda3b5e6e32431e1b304aa44070bcb0fd8098ae7c5c1591df994c5c4c9e754ce6b59cbbd97a2b056e956162cc7020003a2f579cbc5cff2c728d10a9b3595b717498b7211da83d942ddcbe6035123193ced7a7df86510e435e88780ee16158e5cd2345c3d44afacf1b0551f510098f3c3a0b921dd1569bc13cd54e8f7853d3bcae78f62ba428bb7aaf153328926ee77fac5b8a3672136fab27d03e51e485f5230a0362cfa23c31f9be89b6b73d2a15504f00cae99bcc1b122670d1839133ed478d1dc26955b8c0513e72697996eb8be351aa59d8c92cd983b87733cebeb53decc61013b822db066e71bb7f97f800be25fc527ab159dd2af7a0b35d0f4968728ea0d538636b2be9c416e7b5e3b8e03a146afa0586f2a8670ff8caec6336c04550eeec3885b738d400dfc1d9824a0f67a6ce47c13f19b8cf6cb0918e3117cb35729e40e26cb2e373b3cbdb6363006fa47000b36702fbb98cfe9f459e20becd8bba93a1a9f4fdef96a7c88c4fb9e423e1f1abdd03bb0ce3f971bbf341e55501b9a6bfa7bd0b76c8b3f8c9c931b82025c4befe55494fcb775b4bb41ef0bf6a94c35d30953d6e7e4d007cec5c35acf54997226ec6c086f96d956225ed0c129a802f98cebf36a0dbc3c71c1d62657d9d7a51f3cfaeb7fea1c4cec7861011d35fb2a7badb4e2393680fe2f1532e3a59b526235ddd2a6ce5da2cb3e30cce7ae7b4de643356efd0eb23ec6ef07ff426f610af88e4e85f6a0bfc20fffb8c5be35a3d864e59d7ceaaf235ee800fb20082d7f83f6b51d84107b9c74a5a9d78e83c27864ea1b5faaac83686c2ff84f03ff5afd736f5b56207be6b37a29b41f6c7e167cbad938a867d21fcc706f1210ebfc41ff16ed5757b20ed5f81a77c4e99fb0183eafe0c367e0c075569d500e224ea113f10e44a65ebb8fb84187b8a90f74a29afc0e8c99af5a27d2b007c205af4a28ee8afa63cd7cbdf821d71b5ee944266c19bc85ebae4d137752373832ef083f94e4ce133b5d609772c0b4d56a9a059cd70bb6961b03345d377f2e166c281b06f39cfe241342854ebb0878e541efa13d963befe34d0ea1fc2d9bbd254ea2010b26d924049fe58c63ff6c7c5cb8dca78f8b0b2ff06b3d71d3b3b16a303fbe01998d8499d2dfe0f08c09dc1680097ae48c8d64b9b2dc70f2aafe29cf417c0b2e6afb60c70398cfcab66d605dc5f575e6fe41997242360a86bb906dcb8f638572decb3030ea6a19f0403586dfd07ff376d34888cf20641d4f1a2d79e2f6c309bfc9e9fd27ff0baded303b68c7f063aae34cf7429abf37095627faa985d3aa66f48c6cb29344137deaca5a7466e2f384b1e985e7fe69573fd5082b3b42957fb20a473515ae55b15caa0cae23e2d407d0d948ad748e01f1f10be65eb484f4d637ef9417cad8b6131c91970d47cf6a2c2ff0cc995b4a1ac59c1db753d92538d9be9afe786f1013f81edcdd6a52158d30a5d55e8b4752984b2c6dd2785c82e9b2166c36e9fdb0aa6fc53b365d5972ff1b6d44f379e8438fe698c5e528bbd13db5ef39d750e4c8d29d466db7d44adf359e2b70e480e6a1f055c17206aa1171c98054cbb5067dbd5e6e84077c8f91c9aee15913c1a9e9f116cb6f0480664ae9becebdd9933e64950e2ba304fd0e87b087253e0b7bb1624c4cd3ed42e4f72727d262f9bcebd5b07de8c1e13f59ac4a3f3a25c99dd50ac0ca5d510ac86663534bb43af1356f227d19e81e74c557a6f29013fff10302e1403c18f74d4dce6e886ae5fc45c6e90042a2199265840f5ae6783b1d0c11f68f857bc1100344602e746f3e228732e54bb4f27741619c2633ec1bb9bc909c79506647abde091ed7231ab1c79ee2ad667e57cbf490bc6d8f3a682a5dae08b731134b0dbd2b109109905c524f31ab39bf0178127d78fd1cd369ce2e9d41cb9a47ae3b78fc5cff04b4c23fe463c27f75a7887e9a2ffc3857bc575dbf5356d87b7c45d53c627e43613c66ddc7fdacde7d6694b5bdf9f32273641bbea53e5e0202ec878d6c188d95b1a73b13acdb077b3f4630b690ac18eab4aee9df1d87cd066f93b8f1bd37d14e190b2edef06651bffe61ac1f7233dfd79b83c5b2908e7007b8aa21dbb231fc3307ce20fa9a639241921f17d1753d822084bfc0f7536eee4a1a3d3d6df1cff1ebbbfbe45f15c25f851154335c2370ac267d83822e017f279cf91833e6cd99d838cb8f95cfec2aa4d5501f854e908e7c63cc22787987cb18a5ec3b3996d838ba7293a145a802d5fb844ffb6e9d6559ed267fc2a0eda3923b11005c7225c45672698f1a768db1e2f10f027fa100ded30818714ab6c0350fad27bfd4808e84524f10f081ac43ca6fdf79ace3b74ee07e1d3128fd36d40b1e81604df5a9889c596d6431bc3e5fd4e998188ced888e3ec33829656caf4a047fad1875ee95d09b195d8f26c88ac1ce91edad12594f58a4fccbd447f75b60becd9cae487c0907b2eab3b8a45ae21f9230f95ad3f7b4418969eb8c63062cd1ea8d90d51814de91abb516e01adee780a4b8edb2f0ef02388385ce281cec1cbc7b2e882ab3830634d3d639ece9741aee9c291a6a63565e3c6ae3ac816268c065d913ad14e3d8108673743b29239fcb3101ced61b498e9016b8567d23c2f23373be218be4534eea9bae8722d353c805ca9c01e2a3f590fecec279aa568af6df50d7a1a2bdc6d1727a069daad564cca7e079261654ffa69f6ce3a8b3b62a8203b69242e9c459e4a91a33406d74a536796025a8b0e17874284b286a081bc45300904cebcb88cf649d3ade69ab0d698591d1eb8d40cc883a58799735dd439bb72723703042a2070041374a1e18f89b1f820bcf2c88e23c4a759b43b1710770788c1031c1a760a00ed0a2906b3a43bbc13488be48861a2696536634bdd1064e63be1dfcaab8b2e3067133290370483b2dbe878315c159a31946bf113e286ab8e3dfad0cabb417a74a927de7f35ed800a02c3c62c59954a799b2aa38cfa71a507e4520354a012755733db4b27c8603313ddd8fba6554dc85a420a614929ebc22b505ea6dee20bf769116e007dd9967716b39d24c63352ca0cc37011f24117b7b4a0b4892b4b26896e5db3b101574e26c6f53d2e3962a1dddd0cd22055287cc9152dff745928bdfe6f27ff46e7066c87a44cecdd4426b9af3e2b4c5559393ee2d133d9d053458bfc8003fb5580379a0264a052d5d598d4faff648581a0f9046737fd944155e13ea7b8366449b6d8bdc64d8f2523fe088c67d68e5022de83d329704a2a3215283f0f3fb2016691d62dfbe75bf703cee3c12aa6891c1b4378e67c987da3d6f331bb45779e5b062cccda0d87f348aec14c6e1ed0ebdc86ef4dfc4136f4a510d1259d3cab8132f9cb6343c6da184150b425424f7a5167ffe7733d7b0b20acd01abe22393f12bd1be76aeb9d31b3817d6a6820df44476f2e144e4c6738f4a5114958889fa6f895857864fdcfe17cfd0fc10b062c442a15c1b46319e1f5a3393cd6790e8db84d71acdb845b7d71a9110b8610cbfb357019875a18c66b8f5e3bb11da43915368555021be2266d4d836fab4c1941994e592fea433c800f7a9b9fbfe12ba6a6068e1c79f6ef18c8a6379468b23d0caba6abc1a59dd02037401a93ef23e597eb40a8b57358eddc7d6a56206f2737c44e25d83fa44b825ab13d86fc90be874985ce6a9b33570f3b853093a07c7b23a6c3539461d7ab35d1eec3c2916d4e2cdea457d278fe90cdd2d1aa06182e87cb918835427e131437e554c25be8a7e94ecc6fa6bd40d592ef9ae03a743160a70c941172b518549a9c60f37bab480bef8a0cf8d96c80cbc250444e68cff81d9daaca8c20b3b5f2b61866c4ee8260f477d821ca3474d825e25750fcc30ddd4cb826211f38eb42d979f563ac1b3927b4015f5e4f0392538cde0c230dd31d4517e0c587d7089b1de11d12986101f40d4285c8402e284a871236b82a1b1075d2b4e27817502b953cab7132f7457c5195ac60d0027c4c294f4ee4ea93a831882a311e8ba535b19a13454450daa574c5cc4b955a99bad2e3ae7d18dbd4d0ccd30e2e39edce49da0c4a7cbf51d02e115311290e3573c36b3e1bffec621a93e15560fccf5d94e0b192d78f3cbb44aa276cce19aeda1846e96969d65c3968480511272a8a27180af7a61170d6357f3a70880e0518012b26704ae485e49436724369f1127d84b6143da0116f61cf919895109c5d90e9a08afcc5654b3a35d8e40c818c6a293980927fcba55b598dfd734a85fe41244dcfd3510c3c563f64a5316ec0ea75ee593595da94c0e6434efe7d6b4f76b8970a764dc0cdd95a8595a8e8da0ecf9721121d12c542f091b63d21ca35bb168ee309c0f5a508712a98724bfe5e2bbef2d04e3a0c35913087cbd50e8de391b50398367e1e5c390e7947e43883a078727a601a6c23e5107ab054e3c380ace4e04a2503abd5079bc154dc3301926976283ad2ddcb9bec07749b3ca95594dfadbbca97c0cd24ece9cd8753da9e1832a5164c0a24c8c952afd2c9cc8948c38b812443aff69f73a775dd24b9b1c694fa05ea94c4c4e148288eb9e711739a07a56b148ef964f652dae14ab84f93e79d1e7a872dec572ecfd441c7e918951e56cdbb2063675c9188d4bb5b8bd8d2caa171ee2874f03e8ce52d5de766a23184c6dbe819562e7487580671b4b23ccb463905da0741bdaeeb4d91864110aeebbad694691084c3baae6a2dabeea2a6d6295576290f4241505755bd29d36018865555d79b221d866150d575ad29a7611804755dd5da651a06415857557d5ba64110865555afb76512846150d5eb7a5b24611804f5baae3715bbd5bb1cd2d29e5bec6d5dda52cd468cedeab5b5ac79541b19359beec92cc8904da47ae46859a3a952296ab49a3b74ca5c31e55c397a872cb2478dd43db26859a257ed346bb6ca1daa695d5aa335b43f0b6769d6cc7ad968585874de7e2715eb3a5d76415bceaf94a3b3e674c1c2942ebb7829c432d8e91d9a4d6b762884789884948b6326763ffe2c426279cd29b088e0ad84abf5f0591c0244641d3beb9c73dab498c640a342b695f1abc54c5d012fa5dbc82b7f0fe2d1b8167eeb94269cdf1bf505ffa6b31684986dbf70c180d9b5794e58c9a0ee5b9216c03d83a1bdcfc0084284c9ab9257650c10bc91a1c19e4ec84e6df0f1c49caf6783a95302e479a9eb164fec015cb4a3faea4a79c1e259e783f45db0cd00b6d09d7f53ab0c2800ed3fb4f407176e383ed43a95ab60e796153650987c7383e044dd4c22b77703e7806621c2c476118b1ad7da558a57f86b1400ca0d70b27cffc152c31a9a63b23f84985b9c3dd82d0f3cf9d30e80c757db6a13bf43821150e31fa3844273b430246d99ea030535856330c1dec534ab54488e86e2abf7bd5f7458d937317dd735326fbf789bf74f865ea9d507a97ea66454bfa16376c31938f72288d58a3d3944f93c45488af9a970a5c9387c97a05cd9232b4691ec3650f2e01662b6073499c0bb5d9f8512e238e840e2b8c60f2dd5e81f73d7290d88a88b9360966a29ddad29f6bb6cd602b46f65b871c97ceb76917ca3fd23a747200c4a923088946ee3734a0acfe1806b13a15dfb8268097065109903fa7cab49865df264d07015bd6ea0c70f8fe233ccca27ebdccfff3fc527708e237f65c1464ad5097ade5f2f553b419f393688361c5634197410ff210bed7394f354afcca855cd554e9dfeb8cc53d8297a2c9ac4c6fbd94e11eb9fb7a3f3090640629725cb4296f6860e95224fcc27a0dfe0f65e89bc760b8caad18e9dde3e9e97cafa5a907d68b1eed5d91e6083601af98f3dae118c77e405b4cb32359d18a70de0f1b8b2e66e20e4f6dfb7fdcf7b10f60bbe249722978db85e382d0f7abc0f67aa9658be2a2286ff3b35e00ec4d7dc58f244ac96b6626a1d34b66beeb9bece1773dc490a1023d0572709f314a3d0027b8001a02f00448088eba0ddc68bc3af77c0ca99294cf1d1fa534c7790b6151d274c51232ae746500e59b2abd8105c8c35223551bcfd7c5d5e5d73e5d79ac31f0646128e79236008b69870cb9ef6a8a39181c54e5999647e7a267103cc911a65278ef31dc7b3f75975c4c55075ee8dff655cb8d8541e8e42c494d2b6b3c1dab5fd778b88ef6ce79771ef4207114ce877a0b32cf13f24deae0db0c1a938b47a37ddd0bad110804846da4a9544f3404c20e2f4a44117151d13415640377de91a150aa3df2b680e709bf874c51448b31a04318a50a332a4c3a843c02a51cb488af4ae46a093a3567aa4cf284102968e2af5f413271d7789028954aaa144a8740f6a15f491ab2e29967634c982894db71a258997065dc1405d35ac59c6f4cd740c5625eb31aa94e942d2204f4d6b9eaae9ce650daaa46cadb54da3a7b8c10ffad6a8c2699138708deb532b727a2974b053ba4e52a7f3a2d60153efba133c0d291ee425af099aa7cba20756d5eb1ed9d3a7ee01247c4d573e3da40f24edeb8ef8e92af583277f0dfaa75904103e0ad8ce12a8931a086011ec4a05b55e0661d3c1ae0ba16628217452d8b516ea673184530d1b2b87faa187c004b1dd15511324112c35b14551d49b2a42228bbd7551af30824f199b92463d6b231cc4b12775d4bc3c82a38fcd1648cd5b21f165d59e5e5690849b67db457c8400bb10ad6ceff27a85b7e085141c004d6ead4ce443167a3f7ce8d09b54d74f8a91f83e1f31af4bde7957e5b249fe87afd72ad34d4865b105b32ca3d7a19cc0d3b729b648727b3e92fd6d1886fb9ef5ffa7ea8cfa032333b314662e737d12c8a634889508beafd618f04155b2eba69cb23a6742f0a808a007b6e5c120808f3ca8ab212eb04460405827696caaa6c296bd20c5ecb3ff8329ab66e01b5a9ee122f7fa032054306e75fdf7464c3901c9cac292c1735a07586e43145b46b168deb8b808a3c7341a18338d0cb0a9148fc71759b7cb177c7e536963788f40c652d9f3ae14a7f5f3b5b83b80072ea513007ab089cb6f8eb4928fe11d972235fa3369e2b433d9710fb4240d9b381ac30126195624d60d6b81bae98ee5ba749b06ebd2410e72f4222fc6622ca2f6622e9ebb4f153221ac0df55a05a25b6cdc8ea6dce20aabf6dc5110d15f4f3943d7d1634c2043e3d9bc88a2cac1d2e3e182e01a9645094a413527982ad8afe9567fe9a907b93fa235c057c245fd0fbc810d321e99f23f7dfcc77ffc61ca6efc54a89897f89e632a2be9dc1425fa33d45ab7a623112ad64fa3d2c203e9752da4468f0d5291c2dca2f093006140fe50825653366bede4ac98e19dfdfa52b6771a19f9b21aab92be0e7a0b453b650998bc0c21e02a33ead0dc67c4e8a3281106b338fed95919e6e6036bdde8b99b0fc3ddc8c05ff969bce10138fe3afaef3242e40bffcc742fd4e2b0739997fe0e517dbf5be341feedfd0538f0d8ecbc8be2023f6aa2fa6811f6b7d3bb2e8e30fe97bd57be12c27efbc5f95517025c8ef3c903efebcf9fe4f1eddeec65803fcfcab63c9364a15f3b0d6260d0579c113c217b5fb3a10e276503cb1a961733cb23fccf480ac10137e2803775ecbd7ce3b798a4cebc853d4d09929d6da34883676abcdd7cf1b165834d8c2bdaa19d6873a68555dbf60acd748c82803b3a789222406b3128abfc1d68b10d1cf6c93a3c336366c16ebec02f2bf404f798994e7e171c3fe78659162ce43bd7991be797bdcca4fc8b616733e2710e32feb4631577f39cda6e053477370da64bab9c39d21d0f38c50335818dbb7a42935acf871cf0591cb4fb5ac5ac334957fc7a1cb222c068b8679e3be2c21e6df16f9ec6d7aa13ea98f1d63ca79efb3944976ebfb6d7ee297a4b6df2f671844d5ae7b5b79ac1be297f92a151e3ebd7b1793e1ac34cfcd15f0d59f541a11badc0c03046fa86b8fb693ff3b86d677055f8485ae7646f69f03a0d9cf74dc0410ceb601777ac96c9db25c29e350b94e28514d6dbee14b9a26b27dad8c6adee8cc6e1d5ef502635da1d0c7ae35a9b83cb474db2e09ad6026c81b191b1ae0f99ad4fe3bf32d8bf379cdd166fa769209bdd372cc96ceaa85fd4b66eb2f7463fe91b0239e53c3069a4957375028b32d16b74e935427347e5860dd6faaffc5ba791f622368c6eb8f0c4f8724a3e307ea4c7fe99e31a7ffbae9846d1399709e18341b64d7b00b7c85eed63ede5adcfe9676a5c687d64ac3c28937c6360fb152d892d3f8b59f7e86b80f098165b0c18ac07eb1612b23388db00031ca61660fa1dc418f74fc990ad7454ec72fc43efc9be028ded78d2b6dc780f750d51f6979b7280a72cdfb31eece4da8a4c46ce2397d6c58626dd6da8bb3b78deb2365d1c2b6fed4a0f217955a37bcd9cf68b8282baf9dac1321031d94f0f153be701dd562d669c1d6d7667e9c961ee88bc3d4db4b27bf6b79fe6cce9c85fb7c69b838f0c37214df326a3b97c3b9806f89fe063e26c46748e69b3e9e84c3381f6db7c02536dcfe9652def966cb2bf8030b458e0e99ccf16c603069c94b1971d077dc6fd62802dab155f99a31dfdc64f97bcd9d9668058da86f69af5b4397e8f65dfd9de6f56b59c4fdbdf95ffaa66cc7aafd3df85b7912ff7f47ed86f5f4ffad06b8ecd64dde2c406ae7536c1d6781b0ed2900b9fc4813a37f27d6bb2f02b3fe39585dc464b74f2580b6cdf4dc75878b2603a9d3ebc768e7a7c13e6e4d8387cb501f334a171dbe19961d78b9145ce54c7b44784d8d36495a1e85501c3a8d5c175eded5be63fd42867b1990cacc1cfd87a47076ac37fce598259f67b6bbef32fe20521fe3c6f998179072f7ccb154d35e23162ebda788ddbb73d61a1b68f084c5a10ba37b27ae5c97266e752ae533f98744de4c5b6c999b567fe68e56c77ff29104f8a0307cbdc8a73047d882d27fc0001fb4e773462821136c71aaef395878ddb9ff9bb35a2957d5f3b62edadae70c9a664d51161588bc74f1892055dfbd61599323b5b465ab83b54c7b9b141d6eb6b30afb1ef75d4e397e9335e369a2e95162ef604b04e6548578f593f387086c06c34c1b96eb02589cb38c9b5fcb9ef410fdb344c7e1df69a35fad3f4ea5eaf6a32c0ad7782167decf81b4fc212a399c5e8ad68951d9b8e7a4c67f5d8b16b6cb50eb2e96e4fc7bb2073eda5a7dd0703ba80971abfa2bfb961728dcfb8964757861986fbc046f52497c4d593c6aeb7d1800eac87c8cc82ebbe3c52bfdd87638e1e9eb333abf50eb0a58e33034386071b8781e6dc569814bb6ead1eeccb846df0d4f5b7e8c2310374a9c13ff66468ce6b527444b2fead30c0ecb3c15a19128e8b0607969edaa38fc7ccc79ea0b5d1bad3b43360abc9cd744f3f1387b9b9bdcd4fbcc1b3bd5b35a1491cae594b5d2bcdd85f16fed7ea08b88edf94ad9bfba4790c915964d3a6bbb3693576844c091fd0d9f5b05c64038d3daf680a8634fe14cd1e0f5fb788a36e65c073dbf6719d7c6999cdb67e9dcd6fa42b3ec0b40fcc2c7bc6dcf635aaadba78f156f78cc3a0d634afdee75bc233df395fa02e845e9a6e25e747f4bc5fef728f6589c7ae84f6e0d53d5e3b37199f33dad32a3b6a1cec1d9c68b7b5a339fd08de6710073db1f6e6b0326cedb0fb15da867bdef5022ebdd58c5873eb5d6992f9defffeb19459dfc9361f4bc735feed1855ec3663ac7393ac7c2bf39fc1c6d3f14356cb3d66ead8dd9041133a3352eb0ce25ca366c06fb486336393eb66e9b3345b9795f18209bb3ed486e5996d5bb3d1d51737a8efadd277b85a5ed39cc15836039be658767deb9140db7678fa3496ef99963d99937b598d05ad353bd3b5fc73cdb2da9c6b0adbaa7635c6096cbcceb7f5af763678cb697cf3ddaa2d1d36883cec03b88766da9ead9d56fbc63c56c814cebb4337f6124b6ceed47b074d1be1314e49af609c13bce77d994c33f76db367847da666f428e5ea2472c56910e283ea281ff467dc8e70dad57bb4627ed59a0570dc836a8b690ff0cc674be8f1d71ec38f6fb8a08b00db8f384956e6f8c25f7f10a71ac1fc3a2a3465d9500ecf706b2a3387d9719fd9c7cfcc871199155adcf89d0e6e77db1266e484efb7c26866d4e6739fadf9cbf1ff2aebb3f9c77bc2420e5eccbadc0fe6bc516dc416d3f5703a28faeecf6b5b2ee8dbae8a6d3e013a8859c4bd1916ddc34c2fb8494347bc09eb6d64cdd8aedb6851971a786397ce5157ffd4036ad0cc7a714d8e99665cfe36f0d3acb7b7e6fb7574463395e66a4cbcb770ebd675dc0598e7dbebf81d4db2dad59d8f9e58874fcd1ecdf80704d69d53df60b3d5f6ed30da7a8d5e431b45ddbd67b33e71ce12c184cb8138f79e7794eb3d5856e9b3dfc92866f3e91bfde40d78d837c7da4e180c9dc966564fbcb17918a029cbcf7b98d92abaf940dd8cff27a7257ca1316f93317705eb0db21a129b39d24ef7db92bfeccd5db3512b27cdf691804de233613618d028414398f135cb109c26a39a653ee8bcfabc919d61ab9e5bddcc92de39eeb8700316d39c5958de786615264d5423a0d3ddd6dd379f93a7d3e061c4738f7238d9b7cbc199f257cfe7dd77cdfa8d6bc6cdaded3a78dd626a6e956d271fc8b6e3637aef1eb5cd38d536130707010dda90ad1dd75aae5a5513dd61e2435868572efa67c93a7bdbd7e7da286837cc2906c91cf0149a564f8dea740cdca4afaac5a6896fb4469894c76590711aac9ea83ad5a456d9db3f0466de7bad6aa2b7ae980ca80bc74674ca36cfd60dfbe541be84b1d5c9e91ab0fd36233659fb1bf7264c37fde831e5c277cdd5a375cc46db90c5ee9ced30105677db2bdddc7a4f18fac29b30ced1c8c0c86079ae58844369da19e124e565a08de488763e81718eecaad76bf59bbac538a56418703b6667c72acdcfda12039d71ba0f64d0c1acffe485c531bab61a13a7d96e61b203969f9c49f708c0d62b3cd7ba080c67d230e7c5cdb65fe336ce362c76c340c8be81736829db4737a1e5cbfad5f4290734a7e46f4ae3d64d587fa918ecce7ba0bec17cef2ae6e2b21a27f403750479dcca8f992f77da472e56306e0119d7d6332473a365b613535d8025b32b774d93ad76e4e1de0831654e6b3b119b568cf16bb5e300ffdcaaea6eee9e5b5b3bd31327cedbb61bbd61ec83b62a074e96d95dc711a38f30ae03ecfbfab11a7d3f4616f7d8ada7f9ee45d3eebb8bb9f405ed75fcba66d19019b0f95b6d046fb1ab3779cfedfa364c97d99170e9f18d3b4bbde33f74e85db15f3da61f4aeb4453ffba5bc5bca50e4d6da663299271d6196453da828186b79e5df2946e95f766e8ce7ed33b062d1fef716b30f38d0164e34d5b6a41d6f069fd0679a430505c68c3722c1d145bba6b16c6d473256cecaf8cd1dc5f7618bf702bba93c1e92b3404f58634d95cdef6b27bc47fa8d156e7fe275ac678fa3ce244c65caaffcc4bafd01db5fe113e6f87744d5776f4d6b34187426bde1998b85624185cf676b17a8875d94cf85a2a709981ba7468c5623a27a101ba663d836ce1627a86d3d541276fa3b62ce553619416a2e8cd023969285094b8091938b8e498824372b7621b2628dcf4f5d38466e0c2db2e188d0f292b9d8497ec87f0223768c25389f7f2b7d0462dbcef1d2a5d7f76b44b20595780690c6b7ed8e569c035f90f91f9ed052130dc243c751e4824075ae261847e4fb225a81cfe251abc964cfa028e937f27a948a57928f8b0d44e83ce89f718dd2ca2d307d14011db5ae2f55fb34d439d3aba8b49ec65950f44b5c188cea2d55b7e0622eda77952f5c0ecaa3d382678b5e7c5f81da3280db6ea55c8a0d386be4c0ce3c0b4d87b58fbe8112ebdf80298b379bdc5a50f96806e949aeee6f2602ab1185201f2c6daaf4a45e39b965d3b2e66c6531325a2278edfce9ae4028208c24cc43192a59e010cdc1cb164589dd0ca5d1e8c930def3974f5db1ebb7a1b4ec0b9b60bcf6b35044bc10a6e952cedecaeb2b42c60d023cd3fccae994d58bc3b543650cb7a7ea08182407cc95d905ee744ca6e1f443f81be7f3a1ab4e4483f05acffb99d4917bb8bb86bdaf885305d5514b1466c5739012e9dfd7e055ab0ac82860140f858a905ddd412ee022ac7c2fd75457c0d1dd421ebf396f854dbd45443346ae693fb44c90b75384290ec39a3429b45da031b2541ed3442732f95ad489ae1a39b7f577dc4716313e537c80a03adb1e03fcd255a00125cefa0cbb556175dadb8e98fe5e06253f45d5600dc47f799167f6674a20a13ab48403d1dce353de1400377dec02ecd4a258aee08ac8ed5788f20697170a3fd7e021542315ba3bf93188bd00cb5c2d9d2c5311d7cdabce3040e82177f7169b43c7918d8e24315399edee46235fb23879d673023756e0283b159a5df0c431c2187358e1a4332f9db45a3871b92dd90ed7d9c8447c52ec374ba83582b119dd4c5d59fef99975043985ef352ce07470ce14f532cd0904e7f422db2eb26ff079bb6ed3c95bb82e17f1405c35afdb78c0d315be187187e0524b607e947ee86f91f90f0d194c17276eda06e80cd05a2b71af0d6e2db83c00b445595057a0691c0aa0eeb84234602adeb0339aeba9070140cd6fbdcbef331e8a64350bce6f3e74e3a76071c3ff97f34a9bf89908e1498f4b5bd348f253c3667f02fc98b33976f54f405fc329c54e386c506889f8b64aa0b1116bf78550d087f011c0fb7e64d1cb32cf3bf3d7f91f4374241e9a413b5f003458da79863bafcb8bd20bfbc4f11044eded39ab2b19593ef749afab269963f0aca8c743d3d8c08220b1b7cd0b41e343745629f2f8c93c8d3e634ea62db0e4443d090055842707c470c03c856fe10d531e6ea040b0d9b967434e3146e2517471fb26a50726c56c69fca13b5de5e627d2e2fcd1b55d4e88e1a516813ad093484803852d93fefa6ca997e58ffe461507ea38e1c244dbfd3c95797e6882ac143bf85ccd94192de522ca47ea9473542cca01e59f31dcf11ca7b99910795e05358a10cf421e618e091f05fa73f9df81c900ac9701b239a2da4f126de0bd45e30f2f3e15e832b1874df600dad60cfa784e876eb776c72b469741c69dc9593b37477669df96b2306448698e8cf330945ccea5ab808bf69e0482d96687d9fa08079d5753346b86eb66bae007a18c83d34813cf7c4a650c220ee03f2dc5e305811c1c590c5f0375d5fa61f3be73e2cb5162dc3cbdcac9c49011f085a81e0069f9c4944f778bc42f28b0654a4bbddd7b5b452309475d45f7729450e8544febff5c97c2512c910d5448ba0fb11511a97874461192adc476c47d8c7c37d4384d1304e20bd78a2eb16d31dbc28448e6dfd021f1e64500a56674a1e2430dba93186e8d71932637d6ce4a28590454ace37675bedebb9632c75864fdad6456a25d68dd92ee079cbd196340611518c09b6aa1490881f8a31ed2ce27c1e5506c26c4243203f2e2a30e158ef4472bf124e6daca3f72d8f34110e19f5b4c517e42b8a35620798529509730068e63a81922baf11e00a81a18d696d60360cb52d1f5c672020e38ba6d5a1e9213fb42c45ed3980fefc4dffb56231e7f5626fb808597f7427822988857921b96b7dce6ff193ac2bcdc7fada93c46a4e74c2305f15f39fe2f894a42ee692b91d19ae6f8bfb4ad8b1a900f809cb1c4a68b7cbe1d67a896a21e29e7325a12171620ff14a1b601ec80b5bb514b110b8510926ff86f1994b9d184ea61397a93ede1485f4f21bf35db8e7173b50c5756a1138008d5bf53ad6d7d8fd8034ad60733bbc1dd72d6e5260e9662998e74836059510545b832e90c758382b0918a81f2fe868108618eb5a8268e99b09899195a8999b089b774c886ea5dadda5259ca3146d52e2534bb111f03d71b1dec8d4b42fc53f50f51e376a2f34d2262c5298cb709a85eaf6ae7c61f8d8f41e710667f073c3f15da4f7078a8e8bd5a05698c949e41b8cfd1517f8f260971e1438f11d063e1c017dc27fcb2dc70a93c0dbd465f3875f0125b95e4f2d810b1d4458b1b5d236e71a643e4884c871fc1e667127b9431dadc6511b7e379638794b2d21d0ab26e22f936d30f9593c5bfa6d5fd18ec5de342653d939425d8532815e9a49c8ccfd707c3702d8d1e805184b3f98fb69d36b7a4fac995e066ad43975d7bd86f17c1cbb138bd8a2f9689eb35ffb6c18ab52c29e53dcac38fb1007bb4a97d520332038498c320c42630ecbb65538305891109fa3682fdc7b8f268d731bfeb1df8a050c20862635f06c1ea73e1792fe61541a09aea1957f63402a28dd708b2473011d0fc65b1f36b83c6106bb2fae21160133aa47f2b1f33a7716719d77fc9dcaf8a29f87d16df5913856b949376f8815691767eca3b63d8cd1e517d65cf9898fae284586790ce9580d372f36a02006000b17049b3c03e9459b7e23eb1e9c1e0e8527cb715884ddcfc92697bcdea9053158803429ca92f24c2490a5030ffb5aedc71efc1e35f4bb08fafb53c95035138d98cf3b8aa5d868a7731599f3acb7bda61b070976e918aacf04cbf4ae18c6a295ce1199b69d143fc8a116d3c2638b65956de991cf3e5da693f1597c68426560542c993860b825cb1ac0a52d3132af4f94f599c49901d48ed80123e038f7031fe26ec3ae24299407f6b591c2a0ba90f2e57b1b8ce1c209e067e82aa33a04c2f3b242c663b8794752fde042492d73084ccc2b51a044891eb7405a80ac0841d80ced1c3c0d5fb1b12cc78cefe3a7e52dbeb9044e433221db8f491dc801f04c8fbaa5a567577cb0803f4d43bba8b7b0087312dbd94295e10ee47316a334a640a6b5402074a9f917ed38c93b36113cc1aafea5bc8317d66495102f7d2e55108510a955778d35770ee8abd33601d5376cd2f6a170813fd101028f83ffa66910f5cfe0b499a6ba00cace688aff3dcaa340f629ef3b2d9de6029fa96a3b24e072d000cd52060979cfcae320c3b96a9267f989fe8620e20f1142b201bdb4285f284ac88e1431a81ca4ae0d2e7a79f9f38e9ae239a6780f7d017ba8cd2b1182453a2b969c26e214a6aac2355ce0717a420f8c1f81695a7674741a246ad96aef4ac101d94642c88f2140b613dfd5190ad1e36c9cb7b66004f07c9765388aeb8ef425b7141c8bafa50ffb4131caf9227350fb675607397979148591171ba6b966ce0ff72b113bb4b767226d5fcd6837b5f6e7a00c8540f13feb19cfb65859a4c1ab531459420eadee76a69b0da2f15f462e16a6f2dbdac932ca4b2b090589218b7a23f059e0d2124946a5a88b541933d848f2692ca6c648c2ddc9b429e855ae7f27404c8b9c26b060cc0cd06e18b8443403d3c0d9ab8ce604b79845fda0561083f42aebf1a247269e86e4a21771f984da0fa1b22e817496ee2d45049f4a754e01f15e246cc17fe46c7fcfa60b5981ae04b495cf98e405681ae4b420e450664d9888be289942cd030882d2b203ecbe1b5b279ce0635bb01252fe5d7292483188255b791c4546791367bf48fe2cec05de93cba0224c103094a88531083d3ebb72ef95b4631ee60b5a6bd14fd33eeffdffffbfffffffb7bf670cbe06d353d82c2d65a2100d8884260502b7b4b4b4b44429aa8406ec1ab5d6daffc11ef88f4d884c017b206120b023ef717ccf0cef0cf81e355e54152fcd12ef4a83f715c4bb02e27d2db2469380f76450cae2dd41e199d238bb29e363ac351c291f53df1d023c9324efce21df64c13b23df83c67b5ae33932ce6cd078a5997777f82755bcaba2f795c85a16c7ff6c7196d3e46387bca820bee9f5a65c785b51ac3581fdd217ef8c0ddf3df2a600795dd95acd17efa97186a3c4c79078537ebcae5f15015e57eb3d39f9a041d6563b4979ae849705c20b4be23d05e0831a79797ade242aef2ae98595670b82f7197a59322f6c87d70601af84c3d90d131fa351b2e2d5f1c033a52fab8817e63a9b71f29d1eaf6a8cd7f581332739af182c5e96d29b34010d196fea88b7a588920cef8e06be0985b39a1ede93e2e501e14dc2f2a61c795d169ce5ecf14bac351c413e36c6d9cecd3315f149a7885f02c17bf2e2b929d69af4fcd20daf2a7d5d80bcaa365e975206839cad08ff247c79427893b2bca811bc2df00c47ccc7f8785594bcaf11d676c878a611ac692f3c08486d907196837eac03af4d055e09e9dd30dec7837795801776c1bb52df9720673716f8d8f7a638785be98bd2be498737c5c5dbaac0ab72bd2f105e95d2fb92e15551795d6abc3a077826f0dd79e199ea78b512fe279297b5f3c2d677d8f7d0f1ee34e09b3a78d7e37baef818bda819be098e77a6e63b37de9df099c038cb09fa58eb2c2be37fac586b52f34b32acd95479cf032fcb8c173682b31aa5f716b0a673faa5365e56246f98a1351b18deebc0bbfae07d1df1aa54af0bcb9b42e26d29608de78b570ccfcb13803789871755f34d3e9ce5f07c4c917725c5fb92e44d05f2bab4772701dfd4f3a2d06f32c0bb63c937a9f03ad9de3121bcac306f982cef2a87f775c7ab4ae17579f1a250f82630d632a5ffa9e33d41f19c11af8c06be7be24c868c5d36de875cb349e1bd0dbc3c54dea42c94bcbc2cef8549f1ca40f15df9ee60f14c63dee1f81e195e161a2fac04673b6c3c93d2bb53816f02df15eb7d65795141dff4c4ab4df03f819c31f1f284e01523e5dd117a2604bca790cd74df21e03dd57c901daf06e57f2a795316785d21bc291bde1617af6a8dd74582339a46dea3e1d5e6f8a02a673c42bc6234a5a1176581b765c16b73c5cbc1c3abf1fccf1fef7d7c0f0f6737697cccc9bb43826f9a61ada682f78856e95cf14b257857dafbc2e1dde1e1990ef06a707c900cef4ae985d1f0da60e09588789da0af52085e9939bef3e1530d94f708f0ae9c785f15784f6a3c37c68b8ac0dbe2795117785b19acf118e015e373b619fc9309ce789c78c5dcbc27309eabe25d81795f0e7857e7fb02e4eca6c92badf1eed0f04c7bbcab07bcb00fde1d107c130c6b4dfaf825295e5607de249bf7b4c37333bc37fb4a60bcab2cefab904f351f782f91b39b4c3e76c2ab5df9a05dd359fd921c2f0bf5c2b0bc2cf08551f16a7a7cd095b38ce67d8ede94d2eb8ae14d29f2ba566738657ccc8a3775c8ebda596b32c92f8df1f2acf02639f1a2de7869cc7879cc37498eb31c2c7e295b6b42c22f99af86c90789f1b216f086a9f2b29678611458e341e415f3b396ddf13f5dbc3b609e0992339ea557cc0b67371af818f96a1ef8202f5e9b27be8d02bcacef854df1ae2af0c2be37d5c7db6a7a591478c3a89f4e957cb77aefe27b465893f1bef3e03dd97cd01d6738187cccca9beaf2b6fa78592bbcb031ded5eb8589b02663f49d09efa9cb73eabb93816f3ae1e5c9e04d9a4129cc7b22c073482fcb026f182c6b3738bc12085e9ea137298f578b7d901aefce11cf14e6d58e3ea88297077d93e8785548bc2ed7cb93be4975bc33357ce780b59ad47b5aded7d75cef4ef927437437bca805bc2d9ab526ad5ff2624d07e897f6f8a4b1f020e4bc32517c17e5d549e4994a78b3ed7fd2b5264f7e0987b31c998f1de05579f1ba2e59c301e463628451e145f1f04d7cacd984f05e246b59eb7fd07827e37b54585bf50ff2ae84de571f2f2b8f370c09ef36bd0fd1a7cce87f9078537cbc2da6d7468f57e2e0e599e04d22e13db1f15c01de5396e77a781fe47bd2b326ffd2082fab831776c4ab81ff138117c580b775f36a667c5094331ca08fedb03693c77b386b3c0c78c574b0961de07fc47851aeb7a57a5562de5794772688efc69ce1fc7cec86331941be2b7a5731bcaf35de9de09f9cd63200bc0f116b363bbc37e6dd41e49b2e7851167cd3d19b2adfd6122f2b91374c0c2f4f0a6fd212ef2a88f7e5c88bd2c0db0ac0cbf2e28579604de686efbed7c905ef1800bca80abec9e85585f1ba925ed413df74c9d91f5816fac202795322785d2ebc2926de16035e4d920f82e2d5863e68e7ddb1e2993ef0b20e79c3bc70a6538267327a678af84e042f8b016f181b5e169517c6c6bb67bccff7f2ccbc493f6f6a82b765e55535f1ba26f0aa48785d589cd50cf19e17af0acbeb12e4d5c6ff81e4d580fee791f754f45cfaa270f8a63b3e6543fc8f126735aff7027953476f0b9097757a613a9cedfc4c41bc3b8c7cd3064fa4bca7093e889097258137ccf9f2647993f47835047cd0d0cb1ae38565f2a6c0785b92bcaa9cd7659ee594f14b362f8f086fd20faf6a01ef2b837727886792c0bb82f2bec07807e47b7c784f493cf7e55525f2be2c78f7e87db257d5e4759d6bd906fee78d57fbc0077df1f2f0f026b5f1a6c4785b93bc1a1a1fc4c2bbc2e27d65e0dd29e2992cf0a68ade161f6b4dc2fc9218ef6acc0b9bf26a1bfc4f22af1eef0d97578abd4e7a7895c4ac654cff63c73bc3e53b0dbc2825be8992f744c6735cbc2bf37dfda1a4c459ce101f13c1bbb3e5991c795389bc2ed59a0c06dff9bca94c5ed70aef4c0fdf49e0654df286d9f29e2ef8a0435e950caf8b8d339c1f3e86f46a577c50785683c47b61bca83e5e1a3ade1497b7a5c75a16e67fd85893b1e0bb27af4d22afc4c3cb9ae185bdf1ae8a785f107877a63c931c8bc2ab72c0fb0ac0d9cd043ed62949f2eaecf14c13bc282edfb48017d5c54b43c59baae36d89e0dde1c037adb06643f4de08de1425afcb7bb50efe67016733df77867c3a59f21debac6601efeda134c77b04bea78eb36ccaff1cadcd98f1deccbba3f44d55ce70d6f858166fea8db725e68ca702af18a057bbc00745a1b4be2bc7fb0c60cd490cef98f2f53a415e99a4efaa389359c0775fde930ecfc9f0a2b47c53222feb891716e63d49f11c015e1b4a5ea988331c117cec8ff7d7f7cc719683f331435ed521ef0b0067380df8d81aefea901756c1ab95e083d0784f3b1fd4c73234e77be19b1af3ba54785364bc2d4ace70501f83e14d59f1b660ef6e7c0f0ccbcc5cf15ef66a6b7c900baf13a0770c082fcb8d37ccf6ae247961e3190e171f8b62991a3fdeabe355a5f1ba44b066d3c27b1c5032df9d38be297bb3a0ff415f561a2f4c698dc690f762785928bcb02fded4015e97cd7b1a7a8e87b58c8effe162ad0907bf74e51d03df13888ef7aa22795fdf5a93207ec9cbab1de083d657cbe483c67852c2bb03c43341e04521e0a501e45d59e085816fc6fd8ffae994f41dcf9a8c0fdf896f0a92d7f5c1198e071fcbe1d5e2f8a0195e94015e1a3dde1d4abec984777df8275abccbf43e5c5e141d2fcd1a673c48bc6268943610867c57e0fb92e265ad5ed80f67370bf81808673981fcd204af4ae875edf1ae76785f7a9cd980ef4d72f698cfa09077d57ff2c5cbba7961e6998d1caf34c1cb4ae2854de05581e07db5703607329ea6570c0cefa986e75a38abf1e1bd29de191dbe7bbd2927de56035e994cbedbe25d4df2c2467887c0f7c0e135f19e521ff4c71acf14af98d47bfaf29c964f337cbc977386e3818fedb1a6a3c12fddf1fec4a362effafc939ff7d4f34188bca909bc2e0fde54ea6d51795171bc3468bc28f09baa786fba57a2e4654d796167bca72d9e83e22c07fc18ec6591f1c240f0ae2a785f452f2b002fac885785c6eb0ac1cb23c92ba67b751c79a6155ed6062f6c881725e66d01bd280abe098877047ccfd099cc03be1be25575795d09785988bc6160785525bcae2c5e151fefebe63d4d796e006b3557bc77c68b6af24deacbf2f2c21c79590778c3b0b056b3c17b40bc2c0c5e989797c5c20b3363ad89ce2fd1f0aa30f0bec837c5c8eb02c0ab25f2415c5e55d3fbb2f2a61a795d14bc9a94ffb1e4bdf95e29036faa88b79580676824f09e0dad2e2f6b026f18f445edf1d2c8a1b4f4aac4785d1e50dae2ecddb5e37da2bcabd5fb1a3ac3e9f2b1205e27e13ba63bd301e499b67755c80b9be055f9bcae2f6f6a85b7a5c4abc2e47db1f0ae4c785f5abc3c1fbc49e9d96ee07dd03715c2dbfae1acc9e9974a5072e34dedf1b696d63602efb3c3d9cecc330db19673f4b14cde9d2c9e0993b31ca18f5df2ae3cf0c2a2bc2c0fbc4938afd6fa20225e9596d755c89baae26dbd5e1522ef8b82f745bea78c77e7789f13ded396e7ccb52613f825305e1e15de2426de1d2ccfa4801795c43761e05535f2be7cd6de59d62fec863795c2db22c0ebc4e71dd3f3a686de561d3e1abca80fbe29895765f4ba147957147861deab52e47d5df0b29cbc302eef0e20df943abba9e363179ce5ec7c0c91b31a28de2bc09a8dfa1e08d66e6a78a54cde95232f2c00ef6a022f8c7bb5a20f72f2a2f47869e238ab49e4bd3cde9311cf19bdac235e18ec4d51f0b66e7887e47bf0503ae35525bd2f28af13f355cae49d11e23b4cce70a8f8581367d909ff43f4ca3cf1dd0aaf867ed0cd9bd2c0eb0a5f14182fcd15ef567c8f77f6f82b66adc906bf94c3ab2df24145af4e26cff4c3cb8ae2855de0d548f81f0bbca89b6f3ae3785535bcae38de14d3ebaaf2aa06795faa352728bc63507851347c531c6b3442ef816f2a01af2bf5b21879c35859a3217a8f5ce321e415a3c19ab6ff73c7bb22c10b93e15da17f92c5abea5ed713afa6c1ff24e0ddb1c037856b38ddc77a78554fbc2e0abca70c3e28913735c7db02c11a4decbdf40c47f5312a2f6b5f180eef8e23dfc4c1abcae37dd1bc2847de16cebb238067aa626d0b791f2bafcc06be83e25de1f0beec78551c785f299cd548f15e19efeae87d2de0dd397a26d78ba2c0dba2808fd72693579ae23dfdf09cd0ab92e47d856f0ae86d6d7951e637017286a3c5c7a07865a4f84ecabb3ffc13325e94976f6abd27349e0be35551e07d71af0e22cf34c2da0c19efc9bc282d5e9a285e96005e98126b323edf69f0663cef03e675b27ac7a0ce6a44f0de226b1923ff53c6d90cd0770778530c785d159cd558f2de212f8b036f52cdcb33e54da2e245a9df34c8cb82e285497296f3faa500acd5a4f19e1bef89fb6d7c7938f08a31e15d31f1be2039cb71e4977cde19f5bb30afca00ef0bf5a6fe785dbb3458bc2b04bc30009cd58479ef006b2fedaacbfb52641a199def7ade9d149e498d3725c4db2ae46521f1c224f0ce78f9ee0367333fdf05f2ee407926365ed606de2499b39dd53325f16a867c5096f7c4e5b9f33d5df11c136f0a84b735f4cee87c47c78b6a7a5b25bc3c37bc49629cd9f8f14a31bc2c3bde30e3bb28fc13a1778b781f9a17d57a5ba93725f4b6ca7857e37ba6bcab35de97d2cb2ae38589608de685f7b85785c2ebeae24da96f2b8e302bbc2b2eef0b9117e5c54b53c58b3abf29907745e57da971b6e3c633c5ce6c64de6bc03b63f3dd1b9ed0abb2c0fbf25e14ec6db1d66ab2f7d6573be4837e785398bc2e286f8a86b7858512162fea8e97c68d9705c30b5be355f5f0baf47835107c10192f6a8a972689b31c273eb6f4aacad725c6cbeae30d73c29bd2e36dc5d6d6f53e3abc2b05bcb027efaa8e1726f3fec8f7b8717653c9c7c697e78737698f77a9fc1302bcaa1f5ed7015e1e2b6fd21767384f3e56c3bb62e17d15e0d582f8200cde5517ef8b03efce10cf4481b50c90ff01e35d89f0be947859ad370c0f2febcb0b6bc0bb13e599de38cb513f967436337e87c8ab92e37dfdea14f24ce1bba2e07d11adddf4f04a2238bb49fa5809efca8df7c5f43ec5f76c67377f7ccce78c8683f73af071b2d664875fdaf26a4d1fd4c6bb93c837617076d3c8c704f0b2707861769c399979c5fcf09ebc3cf7c3cb427a618cbc3a753c53ea5d1de0853959e351e41513801725c64b93c5cb7ae30dc3bd2a2d5e5706ce683279cf7c773cf04d52de9500de17126738487c8c00ef0e06bea984d7268f570ac09a4e1fcf44c1194e063e76c7cbc3bd49456f6a01af6b82359a0ddee3e05d1dfe09156b4d52bf54e55d55f2c24c7859402fac8957c5bd2e27decc82f729e26555e00db3be3c1978c58cefaae67df1b0d644865f1a7a593f2f8c88331943be337a53dedb02622d1bc1ffd0719613e69740787512f04c249ccd54f01d1f6734b0f76a78378df709df1312cf79511ae25d49e0856d9f64b2ef2a78b7827f42f3ae94785f127867b2efd038b3e9e29576cdc994770c94570701cf24be1bc33f41e2b591e49584389309e43ba2359cf1633ebc3b10f82601bc3b23f826195aead9cdce2bb1f1a62af0ba047086c3fa580c6b3c6dbc622a78350c7cd0141a84f09e54784e5c93f9f96e837779f82756bc3343df4df2ae78785f7bbc36625e098a97e7ca9b94c65a93167e697d4f453c07c4d94d201fd3e0e5e17993c49795c20b03e36c47f03e3fbcac06bc617078552cbcae02284de06511bdb004bc3a7c3c1300de94096f8b883050d69a84f04b3bbc3b463c53242f0ae79bd017f5c54b63c59a8e0ebf748837c48bdae2a591e27d8fefd161adc922bfa4c5abda5e57136b3643ef85e05549f1ba2279751879a614de9d259e899277c687ef20796708f05d09de5318cf59b176094eaf34c68beae19bfa58db4adee77cb50ffea79167684e780fe8bda97925335e2724bc63c477077da604bca999b705e5d5a6f8a0ee4d25f1b616f06a5f3ea8e7656d2fec8965645edf15f1aa30785d4767374c1f5be12c6704bf149ed5a4ef55f1b2c4bc494d5e14226f6b5f9b3a5ec9e7d5943e288db31c9f8f31604dc7845f02e42ca78e5f4a75486739503e668197b5c50be3c07b2ae3392f5e54ea9bb29ce588f14b346b3a54fc12093e9d4af01d00ce662ef8ae8f97d5e58529f2aeaa785f18f854c3c67b6f9ce56cf031475e5498b7d5f38ec2b2e478c37cafb6c707e9f0a6a0bcad24de151d2fec747663c12bddf19ec6f7b0b0a683e59714513a7a535ebcad485e4d021f84c4594e097e495cd368fe278f3785e56dcdf1aa6a5e170fef4ef94c6ebc1a241fa4c4990df91e25af6af5ba86de191ebe8bc0bb33c93791f05ec9f708f26a23f820335ed504de57d0ab9a795d3abc2a3cded7cc9a0d10ef91e0d542f0410538c339e263479ce15cf2b13c5e1604de303bbc63f13de0bb63bc8f082f4f0f6f921b6737887cac83571be3835478b5087c1001ce7018f03135ce6e7a5e098fb3dd5131f1ba24f06e2e6a00dfe4c5bbd3c43365e0ccc68d57e2795508785f4ede951aefab0467332e7cd7c8aba51f84f3a28cbea901efea82f705c48b52e19bc478771af9a69f3735c4db32e45591f1bac4e854606d4685ef14f0aefe78613befa989e7867851a86f1a7a57ae1716c2bb0ac0fb1ae2453df926215e9407de56082f8b8d17c6f46a947c1015af6a7d5d0638cb89e16393bcaa155e571867383a1f7be1078a97358017d6c5d933ec6a8f178673561381f70cf09efe203794ae7c9a01e4bd26ef0ed03361b1e6a486778c94270178557fbcaf26af1310de311cbc2c235ed8eb4d05f1b60ef0ae9a785f1478b789f741ade9a0f04b81bc2ba0f7b584c7c6cbf381574c0a6feacadb02e34579f04d48bc2b1bde171d2fca8a978689b39aa0f7bebca7271fa4888e1e6739477c8c044f5850bac05a8d97f7b8785302785b59ce7034f8980def4e08cf644557e55dc5f1c2f60ce7918fb1f1a68cded61f2f8b8217d6e5cd2e781f235e1e296f52146b4ef61543e5dd2bff648ab31c0b3eb68077878867aac0190ed1c7bebcda0aff9381f737be2786359aa6f7d4339938be137a5542bc2e06bc3cab3709fc3463c97b007867b07c7781351ba1f730395b2dffe48df734f34174bc3b2c3c531cef8e03bec9835713ff6702679bc5fb3c59b391f2de25afaa02efabf3aebc2816bee98c359e335e310078793279c5949f4eafef765ed596d7858017e57dd3146b3a3ffcd207ded3d17343671918ff33c5da0c17ef692fcb861746c73b637e4781d78909ef18f23de57c901eef4a8f1776b38633808f9d675907af41d08b3ae29b2ef0a672ded694331c313e46c5598d13ef91b1a673c12fd5f1aa5eef4b002f4b8a1736c97b1bdff3c2590e15bff42b93c777ebab427a5d0a785596bcaf13ce763678a628ce1603ef639ed520f21e1e6739377c2c0367371cf81809ef8a8cf785c9d98d231f0be1652df28699e15d35e08571f0ee687926069ce130f1b124de5512ef2b02efca8bf7d581331bf13d0cbcab0bbc307213f02e81efb1e34c87e999bebcc878750879a6ef5d85f1be3ef0fec5f798f0aef67dd93013c4bb7ae27d59e07542be63c017e580b7d5e43d59796e8a1206ce9ef29904d668c678af5cb3e179eff5caf4f1dd0f6b3b663c1309d69a68f92520de140b6fcb8997e7e64d12c0ab1ac0ebdae25545f1ba2cf0ee2c7d530d2febc90b0be24549f14d49afb6fd0f045e9ea03789cb7b02e2b9f5452df14d95bc1a08ffc38077a6c97773bc272ccfedf0a63cf0ba06f0ae65574fde979777a5c5fbdac09b8abd2e195e1d053cd3096b273cbed3ce7232f85823efa987e7aabc3a8a3c93092f4f076f92f96a0bf82020d6dee1a403c52f8de05dc9bcaf2baf4cd377659c0d805d8bef11d778ac78c5a8d66478f82e5cb3c179ef01ef82f13e3f6f6a04afeb85b31a0abc37c83b25df638077077ca62fde930fcfd5f0b200f0c28a94b6bc2a48ded7f6da68f1726479558fbc2f0e5e6df53f7dbc2a2baf0b8e77d77f028692166b3a02f8253dd63217fe07e94dedbcad17947e78752ef04c37bca8ec9baebc2b27ef4bcb59ce1abf94f3aa8e785d107879be37c9e8ddd1e299327935ef7f5e2f8ffa26d9f1ce68f9ae92b39c427ea9825713c10795f1cedcf0dd03de9318cf69f1aaa6785d615e99117cf7c559ce7e6c90b52613fc520d2f6b8f378c09afea8ad7858197078337298637d5c2db82e25d95f0beb2785191bcad0b5e9d0e3cd3798673808f91f1ee48f24de4194ed3c704e98878b78ef729cf7216f9250cce6e0cf918072f8a8a97468937e580d785c1bb52e48561f06a491fd4c51acd94f7b67765f4be14f0a634785b3ebc3bdf3379717643c8c77e5e9e0ebc6206f0ae26785f5bde95f24f8478c5bc29ed6da1f0a21ef0b676d69c4079c7a4f0ee94e09b6858db44dec786351df197fc787792be298a52182fca846feae2d5b47c90ea4501f14d8ebcaa9ed7657486e3e463329ce1e0f0312d2f0b016f9816de55d30bb3e1ace687f7b0785112785b4ed6323dfec78b1765f34de6bbeae38535599b81e13b069ce5e8f0b10dbca9d3db4ae175d2f38ea1e04501e09bbaac6586fccf18ef693fe88d4f3353bcb72f8b90378c9477c5c5fbbae45585f0ba9258cbe9f2314c5e55ea75adafb6c307696b32427c77c2333349ef51f0f2fc265df0ea6ce0997a78751cf04c2cbca72a9e53e24d75f1b62c709613fba5f1657df0c29058bbd1e1954270b6737a2630af6a8ff765f3b29ade240bce6ccc7825997727906f52bda902bcad4a5ed6f8c2ae7857e9fb32c05acd93f7baac35b9e2978c78575ade9721af0c20df7139d381c033b5b02673c47729bc2a365e57095e56ce0b43df54cddb2adfa5e09fccbc2b18de571a2fcf25af98125e96d10b53c0271a20de1be17d85cffa7859a917367486d3c3c788949038cb09c0c71af0a6e2785b98bc4fe07bee784f2b3c479ee524fd12f7a6d2b705c77b529fbbf29e34f820052809bd3b333c931e6b37585ea9046faa82b785c3cb03be49486b3c70bc622c78b39ef739e213cd12ef0de0dd8bef29e15d9dde570e6bab80f7b9614da684ef04f09e84788ecbab31f241466b3a35fc12025e12ac9d12f9eee6d50cf041e7d9cd1c1fb3e02c87848f4de00c67928fd5f1a26af8263aded514efeb02efcc96ef32b06683c17b127855595e17216fea87b775c7cbcae28559f2aec1ea64e09976785545af0b9157a604df85f1a260f826365e5413dfb4813715c5db7ac0194e1d1ff3e26561f226edbc291dde56182fea002f8d1fafea83d775c4ab43c733a15ed498b715f4a696785b8d9cd99cf09e06d676c2782611ac35e97ea9875775e575d9f1ae46785f57bc207853afd7f5f3a23ef0b644785724bc2f2cd6749afc121cef4e986f1a5f1510af2b917785e57d11f26aeb07357965c47c87c559cd09ef19b186d3c7c7c27877d6675ae4d56af8108c5823e49599e43b255e5409de96f8b24a78615b9c39b979c56c79517fbc3476bc364cafd4c58b52e3a51163ad0920bf34c5590ed32f912f4b8f374c094a57bcaa11bc2f18de15ec8501ad3519f34b677478bc9a93ff01e4454df04d45efa984e7b8359c143e869ee544e097387877f4f8261c25205e940edfa4c7cb53be494f7489bca7d50705f25e4356f380f7fe78b5323ea83cd309c1337539c3a9f9d894b31cf3631c7867ae7ce77a5581bcaf9dd7c9cf3be6c93ba37d97c6abcac0fb2ae14df5f0b6c878b50bfee7006e64f2a20c7969027935a10f9a39cbe13ee67af789f751bd0be59f20bdaad3ebcae15db5f1be96ded494b7f5c4590e141f637a5376bcad11bc7bfe132e5e0d00ff6380331c057c0c8d57abc00731712673c67757ce76b26712e25dd9f1c2665e1d033c13f7ca8cf92e8b577580f7c55ad3497f2991351917bedb5eed8c0f92727663c5c772d66ae4782f8ef784c37330bcacf5850df2b246786159ace1dcf1b12f5e1518afab032f4b91378c0cefc2f04f8e78531ebcadf50cc7868ffdf0ce1c7d97f4ea4cf24c38bcda201f949edd60e063e2abd25e170e2fcb016f981cd66828786f834fd911ffb3c48b0ac03719f1a22ef826a497d5c20b43e35d09f2c2566738371f6be1d526f04149bc2a155ed717ef05f81e282faa91b765f3cefcf01d25af66c407fdbc3c34bc495dbcac262f2cf59438cb41e4972e78b37d9f2e67376b7c6c82331b00bc073bcbf1e29764de15fabe0239cba4fc8fd19bdade16d1d90d191f5bbd33447c178277e78967dac0bbcaded70d2fab8d17d6b426137ef7c19a4c07dffdbcac08bc61cc7747be678d97c5c30bdbe345b1be69cbbb05789fed5d0df1be1e795510785f1ebc3c406fd2963725c3dbb2e2ddc1e19902797fc0f7bcf1ae28796125bca933ded606dec5e37d5878d7ca3f69e24dd5f0b6b6f8a4c3c42f890003315e94956f9ae36535f286a9e1cc26e8bd30afca8cd795c96ba3815722c0d9cc93effe7877be3c53045e1e17de242bce7290f858093e653bef13c48b82c0db42addd98f04a1c784f633cb7c59b6ae36d79e03ddd7c101e2f8bf5c2b4bc3b767c13cd5a93317e29899705e58589f189267c2f84b3cc84ffe1f2ae1cf0c23a50aa63191a2fef9190c75a13a25f327a75c23c530d2f4bf5c2b29ce128f2b1335e14266f6b7b5558bc2e4a7e69726676359a3ded69e6ec6c465be6949d9d3abd349bd1c89c69356bff0c0dcdcd2972bcab0ede57116b3a507ec900af8acbeb3264ad8920bf44c59b02c0dbb2e1558df0baae38cb39e16314785195bcad0d5e54966f42e44d95e0755179798078930cf0a22af0b62a7877a43c131c6f0a83b7b5c3190e161f7be213cd10ef95f0f26ce01533c26bd3c82ba167a7117e6b3abbb9e3633d6f4a85b785c41a8f1aaf180a5ed6d29b44c18b92f24d66acd578ef09f1b226786144efce0dcf04c819ce051fabf2cea4df457296d3faa59f339948be3be2eca68f8f3d795735bcaf39de5de37dc6b3817e1779572abcaf2fde1313cf817959e50b23e39d59e23ba6d70907ef180d5e2d8d0f9ab22d2eefa9fb8d3ca3e1c07b3cbc2af17551f1b20a79c34c79653ef0dd152faa002f0d17af3680ff91e45571f1ba36f0aee67861dabb23c333e5a174c3598d23eff5f1ee3cf24d1fbc2cd81bc6873305bca9df9609ef0e0ccf64c7bb33fc1325d676e63388e44d35bd2e2b6739357cac92b39c2f1f03c1994d07ef5560ed66ca2b7de04d6df1b628f0de14bd12d38b0ac1dbf25ed40ddf64c7bb0faf3df2b22079c3a46737633e3680331c047cac006b4d6cf8a51f3ecd20e0bd9d7765c80ba3e0b5f1c02b39f1a60a795d37afca8dd7153be3517ac5b8b0962df23f057853376f4bca9accf65d076b4d12f04b57bc6bc13fa9795546bcae079ce558f14bfbae72de97f9a9a692f70c795732bc2f363ed104f21e0c2fcff926cdf1f28c6f52106b362bbc67c9ab02c0ebe2f2aef27861362f8ae96d91f0a2c26fb2e24595f04d5cac3519c12fa5f1a660af2b006f8a7c5b41bc3b63bea985b395e47d845e56951716c7ab9ae37dedab12e17529f16a757c500def6acafb2ae33d691f14c7bb2efc9322de94eb756df0ee9ccf84c89bd9bc0fd28ba2f926a1b5268ffc52172feb821776f4a61e795d19bca8f29b0af0ae027961a957a5c7fbaa596b32f44b5dde1515ef6b92778702dff4ade1c0f0312cef898ae792785324785d30ace9c4f04b07784f323c57be33407cc7819765beb03fdea1f89e10d678a078c5a0ded50bef0b8d5753e2833e38c321e36355bc2c11bc49ab17c581b7f5c159ce1dbfa45acb78f89f21d6648abe2be15541795d603c19c09b32df561a6739361f43c05a132a7ea988b39d9c6732e25595e07dc5f029b3e27f9e785330bcad29d69ab8f14b4daced78f14c2178515cbc3453bc3a629e69fd9429f13f4cacd5b0dedbf26a0cf820a4339937beebe1999947de5bbdac215e18045e4d880fcae0e5a9e14d02e30cc7898f29a1b55ead900fc2f2f2ecf026b1f1a230f0b67cd67690f7a9728673c8c7ca785306785da75795c4eb7abd2cd71ba687f743bee787b52648bf84f4f2f8f026c17176fa7e1be3d5b87c10ebd588f8200dd64e817c37f39eb20f82e36591f0c2b4785391bc2e115e56172f2c694d3bfd0f1e67393d1f63e46c183e83e44dadde960cef89ca7350de1923be1bc19b6abd2e0dce6e04f9d8066f4a92d715f4eefcf04c8d9ce568f14bda8b92f9261edec7f89e14de55eb8509608da700af9809d668b2784f85f784c273e07b14df23c23b83f49d07de9d0e7c53f9ea4ce099a87ccabefc4f12afca8ff795f3ea50f24c5796a119e13d11ce72521f4bc09b92c0ebea40298db31910be1be4dd01dfd3c6d929fc8d8c57c603df59f1f280e01513e52c278e5fda795595bc2f129420f06a05f8a015ce6ec0f858eae591c02b4600cfcc44f29e9317e5c237a9f19e581f648057a3e07f045993b9f21df8ea60f24c59de999defea78513f7c5302de1d249ee902ef0ae97d31f2ee64f24d2f9cd548790f89b5265dfc1201ceb29bf7f1b2b60f789f2befa9830f72e4ece68357aac07b22e2b92eaf6ae775a5ef50341926be83f2de74f04a90bc3b987c930b6faae76de97086937e0c88f7c4c57351bc2ad6ebcaa294c4ab59f141e0ab45f2414e9ce5681f23e46529f1c2207957227861545e56015e5808de151e2face65d19f1be5aaf0e069e298797679257ccf7ae7c785f7e9ce5f4f14b3c6ba741bea37917877f12c58b12e4a5d9e3d51cf04141bca8ef9ba87877bc3c13ec5d0df2c258efa6ffc48bb52671fc921367381df8981eaf4a01ef0b83b39c093eb6c8ab4ac0fbaae04d6d795b79bc3217f82e8957dbc00761f1aa60785d69acd5dcf01e146f4a8eb795c98bc88b6ae19bd2586be2c42f0df14907895f0a81d2f92ec8f7a02fab8e378cb896cdf03f5fce72cef8a59b5735c3eb6ae33dd9f09c0b2f6acb3729f2f224bd624e7847e47b84785723786131bc3c1cbc4942673b1d3cd314ef56f13e152c43f380f7acbcac39de30e0bba3c233adf16ec36793bcfbf13d3dbcab485e58a864c799ce089e0988371580b785be2c2b2f4c8e77cd781fef55e1f0bae8787736f04d29bccbf13d349cddb43e16f4ee48f14c1c589b89df01f3ae0cff248917a5c8db3abd1a131f2480f78c97478337e986351b23de5b529ae165c9f0c2dc58a311e13d10d69ae4f04b5a9691192f9f6c2a782f029f74e0f8a5d8cb03803749857795c80beb59bb115fc912a5a6b5fdf23e326b4d2af8251b5ecd890f12e145217d13045e941f2f4d1d6b5906ef13c5598e003ef680f724c207b53ed170f11e94ce00ef0c98ef3279662693f72a586bf2c12fe9f0f2e4bc4922bc3c25bc4945bc3334dfb5f1a62a795ddf8be2e09b8e58ab99e03d2eef09cc7344af9301bc63467855e7ebf2e39511c1775ebc2c0e5e98112f4ae89bfc508ae4d52af89f415e9b03bc920d6bd923ff73c6ab01f2413ebc17f23d58ce6c7cde9bc09bfaf2b60839cb49e1631578573bef2b7d51317c931bef8d935792e36585f1c2c6bc07f23de6dacd101fd3ce788c5e319fad11ef63739683815f0ae165f5bc30a4b51a33de6be3fd84cff0785521785f2eac9d1af05d9397c5bd3028de95252f2c8577e702df34c2aba9f1412dbc5a161f34be2a0b5e5797f70600af44c7ab02e47de9bc3b7f7c13eacc868d5762bdab0dde9710ef4c97ef2e7979586f52f8a22e795b1ebca930af0be82c6702bfd4c1cba3f32605bdaa3bde97ccab8df03f15586b72fe12d1598e968f8979554f5e9797d78905ef9809ce7216f04b19acf1bc5e3120bcdbc23f21e25599f0bab4785157be298ff7e4fd36829207af8a01ef4b8397a5c20b0b634d0684ef02f0a288f8260a28bdb12643c47728ec02de54166f6b022f4fd19b04c8ab6ac0fbfa795320785d51ded4d2eba2e19dc9f21d06ce76847f32e53d7df11c15ef06f89ef34d35795b2dbc5be59f30f1aec4bc30165e96ce0b53cf6cb678a5d76a32794f9157b5afcb86339c047ccc8c970703af18f05d79795f8dbc3caa37e97b57ebfb1a644d67ca2f0df2a6c0bc2d04bc2811bcad6fada68ef7e478b3dfa7e8d52ef9202dce6ec27c0c5ca389e4bd1b5e194abe6342297d664602eff1bc2810bcadee5591e07d5179554e5e9796b32c7b1f20de1d139ec98cf7057ccf196b3c0e78c578709663815ffa606d8685ef1879531d785d25bcac335e1809ce70bcf8981467351c780f919765f3c27c784fa80ff2634de7855f22e4e5b1e14d0ae3dda5f7d9728673c6c7ae389b617d97c7d94cf8dd21efaa7c5f622815e095897d37c6bb73c533897951ab6fd2f2aaaabcae375e94246f0b83b59aa2f7b4f834c380f754efce14cfd401af87f7a4c47341bc3ca737c9672dfbe035d8de15045e18086ba73abecbd64e877c67b39671e07fe058b391e1bda457e5bd2e285e9e09bc624238c399e3635dacf1d8f18ae951faf2ae68ded70e9f684eef61f0bec5f78c2fca8c97c68b77e6efcc785760bc2f0f9ced7cf04c54acc99cf05d082f0acb3719f29e9a7cd01e6b3a1efc521e2f4ff62661f0b29a786116586b32805f3adf53081f04813755c6dbcac0594e968f7de0d5a2fccf06de93ea830079796cde2410ded424af8b7b514c7c9306d668f6bd9e57e5c8fbdae06555f226ed6bd3c72b7df0b2e078c3746b3520bc87f4a610795da8370be17f7c785356de96162f0a8e97e68cb39aa5f718795593bcaff13d95cf8db06643c62b9d5e14256f4b83f7943e97c35a139c5f9ae12c47898f29bdac1f5e1802de1514ef2b92359929be93e14581f04d4abc9aeb838a38bbc1e2634d5e271bbc633278553aaf0b7d5942bcb0475e1d063c13947767e89916f0ae38f0c2a0bc3a783c13eb5dfdf0be10b02693c4772abc360e78252cef4e1ddf34f3ae32f0c206f09e00f041077857b11756658de6c97b01789d50f08ee17955b1f735c3da8d111f3b9ddd50f1319c17e5c337fd7136b37d57c8a7d305be53bd3b8a7c5306aff6c307a5ded310cf15bd2c9e17b6e5e599e14de2626d678b6702c1bb19df539ec994f15d0eef8e1fdfb4f3aa94785db077f5c6fb6a7a5501785d43bc7bc7fb4879575bded721ef55321cd8c7de58a371f29e066b3538ef65595b2e3a7a3c9393573b3fc8e6ddc9f24c8cbca83c5e1a38de950eef2b8ff714b42c175e581aef0eec9b825e1e0dbc62c87775c5fbaae4ec66918f7d709639799f21ce7260f8d8055e1406dff4e54d9df0b68c7855eaeb0a64cde683f72c709643f3b142ce6cb8f724393bfc6d646d41f827df9a0d12ef31bd1a013e888377c7876732648d2604ef9def6a86f7f5c68bdae19bf6785994bc49bfacd89b0480775580f795c97bda7e0b5f14cf3771795955bcb04ade5db11e79c35c59dba07f22be4e4678c7842fca896fb2e4d554f81f4a5e9e9d37697b5538afcb877791781f9c351a30de5be1e541e14d5262199a9cf79eac6513f81f35d66a74defbe1ec06898fc9bcaa2e5e9725af86f44116ac6dd2fbacef8a012fece7d5bcf82013de5395e75858db2ddec7e7dd61fa261b5ed506af4b8877b3fc9331ce7232f9a5efe5a179933a7817e37b5078598ebc616e389329e43b205ed509af8b8b77d5c2fb3243a9cb9be2795b34bc9908ff63be2928ded6236fea01afebc96b93f44a4dbc2a175ed719afd6fd8febd57cf8209a97e5c40b8be4999934dea3795145dfd4c8bbfaf2be18f0b2c81786c5ab1ae27535e06c0683effc38c391e46374bc4e4e78c790b0b67dbccf0c6f8a87b735c6ab12c0eb42c20d12bc2ced855d39cba9f2314a5e9515af6b9257cbf241a8f794c5734ebcac2f5ed807deccfb1f2c6738217c4c87b59a2def65b1a673f34b6fbcaca11776807785c4fb82bd2c9f1726849204deede19f60f1ae81ef21e4dd199f498c7766e63b36de151bef2bf6da3ce095b29ccdc8f09d236f2a8cb77581b39a22defb62edb4c777a757278f67e239c301c0c766584cce6a2ef05e21efe97cee8635992cdf8db0d684e997d678b5d70719f1b2327993502f4b016f181a5e541b2f4d01d632f47f8a785799bc3017de1925be5b7a776c78a63fce72b07ccc03cbd01cf19e09673714f898f72e0dff6489b3457a1fed6515bdb044de95cdfbeae14dc1f1b6c69ced58f04c4dbc2c2a5e1825af8d14ef06266f0a8db765c99bbae16d75718633f4b1a35745c8fb5aade970f92531ef4eeb9b42784f341f54c7ab59f9108a7835473ec8cb3b23f3dd1a6b4daafc5296331c4a3e66c7a79a2bef45f1cae0f19dfab28e5ed8025e5414dfd481b38b781d0aaccd94df2de06569f1c22e39db413d13015e8d8a0ff25e14202fcd1d6fcac9dbaaf26a441fc4f3ca60e0bb25de8de37d4cf84453be17b47613c4c7b2b39ad67b80bca8325e9a2e5e993dbe1b7a5167bc345fbcd3f13d565ed60b2f4c8d351d1a7ea99077d5781f716dbbbccfbe2a0dbc2f13d6b691f7c1e15d9df0beb8786f3c78250a9cf190e015d3c2bb24dfe3c7a705e47d68785704785fafb59b1f5e49e9dde1f24c0d7877b867dae25d81f0be08f0eee4f04c067879f64dea79b5493e488a77878e6f92595b0bbc4f0fefc9e783167977a078264bde93ce07f1719671f13f517c9a19e43d9d57a68eefce7707926ff25e2d8f0fca614d6686efba77c6e8bb0ebc5a073e888b35adc9ffecf1a204f04d4bbc7bc9fba46739dec75eef26f13e39efe9f44172bc2c3ede3003786752dfdd719603c62fcd9ce55ce09704705673be47c53b23f4dd04ce96f25904de1924be537a59197893b257a79267d2e10c07e963600259cb3cf03f71bca817be698d17a5f4b6c63519f4bbf1cd30781f02bc2908bc2e9ff7e4c67366ac35f1c02f99f1a694785b8c9ce17cf9d810af6a03ef6b00afea8bd7c501250dbc255e9d469e4985339935bedbe15515e0758d795536bc2e39de9d45bee9c919ce0e1fe3a2d43adbd467c0a4d4c6bbeae17df1f1ae86ded7015e1d0d3c130faf4d162f87d08bdac0dbe24089866568f878ef856768b6f704a0c4e55dd1f0bee0787742f04d54d66a6ade1b7a59af378cd0bb50bccf4a6992f744c373529422f0ee5079a63bd67056f858faaa7c785d7cbca8d8db225f95cdebeae195e1e3bb2cef0ed13339e04d9d6f8b8d9745f3c27a78bfe1330c9c39d179c7bc3643c3770d381be2d52cf0414d9ce140e0636d9cd568f11e1aefca83f765c4bbd3c3331572e604f58ed977c9789fa0572bff4703ef585e7badd588f1de1aaf36e683c278578cbc300d5ed51baf6be9ac4688f7ba7851237c93166faa01afeb82b39b443ee6c1279999ef2c389369e4bb20de5519ef0b04af0e079ec95cbb19e1952e39c3c1e4637dd8f19e909ecbf2f208bd496fbc37f23d697c5a31ef83e565a9f1c262efea7b5f519cd990f05e25efea8cf725825727e999d0b31914be5be4ec0b7e4f78770ef04d13bca919ded615cfd0ccf15e0b6737627c4c759633e697bcf73480e7bcf766835782bd2a1d5ed71d2f8f00dea4a1772702dfb4ad6509f81f325ed4eb6dad9ea189e1bdeed542f89f06bc3b0af8269feee84581f9a609fcf1b2e278c378af8a86d7e5c65a93a05fe2e14d11f2ba6aded41a6fab03afca8ef7757a4f157c1002de95cffbfa7256d3f45e236b3465bc17e5d5faf8201e5e9e9a37e9837785c80bb360ed4c9c60f08ea9e0e579e14dbae29559fa8e8c57f3e3837a78554bbcae08bcab3b5e18cd8bfa9b70383b8dbf99f19e5c780e85b31cf2631278531b785de2dac98fef64de9d2ecff4805795c9fb9af2a688785b87bc2823be49927785c1fb3a7a53e1db427acfc0f70c72564382f714f0ca287d27c6bb633ed321af8d21af94c35956fe0f10af9310de311ebca918de56154a689cf140f28a114189e8078b57abe283be339c373eb6c58be2e3a599e35d45795f63bc33eb7792bc2c302fec012f2b7d610638cba1c02f79f0ce9cdf55e0d56e782033d6b23efee78b57d5c2eb32e37522be63bc57dbf241abb32c85ff297a5328bcad23ded5efab86356d8607e1cbab49f1419c520767376f7c8c82f784c10725e06569e04dd2de1dd73789f06a5b7cd008673c45bc6264de9425af6b7c7710f04d14ac9ddec87242f04be0cbbae185d5f19ea23c47c2bbea795f462f8f056f920bef6c7c8f0b2fca866faae3e541bd49dc7b127aceca5a93287e8988f7d4c27327bc29f06d1dbd4ec677cc777673818f85ef03f8ec8e1735c84bc3c7cbdaf2c20ef944f3c37be3cbb3c19b94c39a0c95efb8b505f33e33ef597c4ff8ae32785f482f6aca37a1f1ee30f14c95286df0a21af0b672de1d179e890e8f9037f581d785c2da0d94574a9a11e2dd897d93959787cb9be4c759ce1bbfa4f3aa26785d5bde53019eebe2e511f38a51612d87cbc7c6bca92c6fcb8ef704f441ae57857a5dea7b946511f1c25a4a547cd241fa254c5e96206f98f2550dbdae41de1da4677abdb7be278eb53de47d6a58e3c9e215b37a5733ef4b87b319007cb7c75906fe4f96339b7d8f01efcc10df81e05d85e085c1f0ee08f24dac17a5f34debabb3c8330de0cdbeff193acbf9e0638fbc5a131f14c2198f12af989a77c5bd2f275ed409dff4c5998c23df09b1d6c4915fe262ed068557eac0590e077e697b65f4f80ecbcb937a93ba1725c437c15e1508af8b00673418782f873755e56d65f1a2be7c93eb5da1f0beba7877ac3c531faf2dde1d067c53005e5406df14c4abc13ee808a538de55ea7dadef0c0edf41e04de9bc2d17de1d1d9e6990576701cf84c29916c383e0e55d2cff248c3795f4ba4c78b7e79fdcbcaa0b5e17106fea8bb715e6453df2b674de55e27d9aacf140e015f3c19bc2e16d797186b37ecc68191a34de93f26a407c10005e14d03739f1b23c786104f874b2c077a97735beaf2ade15085ed80b3e5a3e653ffccf11efaa9117b6c1cb03c39b84c5fb01be677d775678a6365eed8f0f127a516ebc3465bc27f23d647847bcaaa5f745c35a8dcc7b589699a1e4bd095e1e2c6f121eefce1cdf743abb79c0c7805e16132fac022f6ae79bb0bca804bcadec2ca7915f7a7226b3c8775ede531acf89718623c4c78858dbb39d099e69894f3a5d7e69cc9a0ef74b7cbc292f6f6b901725c23735e1edf0b2ac78611958cbc6fc8f1cafcc25df49f13af1e155c264adc91abfc4c4dacd0baf2466cd2688f794ded422af8bf55e81efd1e375b2c33b66869705c60b13f32ef49a03d66a7ade2b5a6ba2c52f1df1a6d4785b1c78750c79a6f1dd31c037adde130fcfd1f0ce7cf94ecc9ba2795b2b9ce140f1b1255e56d00b73e2acc690f7ee7879287893a4bca7279e2be255c1f1ba98ce64daf88e873735c8eba25986268af75078f7867f02c59b22c0db5ae465f5f0c2f87857e1fb9ae2dd59c03769f07ec7f7dcf0aabcbcae05bc1a0f1f745abb315f6904efe6f13e53d6b20afccf1a2f8b046f12cfabe2e07511b1766ae4bb9c3775c5db8ac0990deabdd65a36c9ffb4b1a613e59704795763bcaf31ef96ffe4cbcbdae185e921f3c49a9328ef18155e54212fcd1f6b1995fff1f2a622f0ba3858cbacfc4f10af8ae775fdf06a623e088c770a7c4f1e6f8a8ab7e57a792279c56c674e9cbc63562f2bcb0b2be45545e07d89f0a2c86fcae25d2de085f97c3a4de03bd43b17df43be2c0cbc61b8bcaa185ed71aef0e1edf64b3d604865fc2f2a6a4785b1038c389e3635cbc4e04f08ee9e0dd17fe8911af66c707d940b3c56ba3c82bf5f0b268786170bc5a063ec80a252fde25c0fbdcbc373eafe47a53e8db6ae3ac4689f7c478778a9ee99177477ca630de95015e98ea3dadcfe9f0ae7ede1798b39b087c8c3bbb897d0cca2b4382efc0785124785be18bcae19bf0783fe37ba2bca80dbe8988d74900de313e6f6a8ab7d57a53dfdb327a676ebe83634d86fc0e0425315e2d870fdaf3b2d60404bf84c6cbb3be49779ce1a4f1312cce6c68de73c0bb0af3c2c4339a31eff9f06a3fffa3c8194ecec75c589329bf0352da418e1d5ed607dea49c9767cb9bd4c7ebe483774c005e9e01bc4948ac3541e297847879727893d0785741ef8b894e91b31c327ea966cd46cb7b22786f3478a5d7190e093e06c85926fecf0fef7c7ccf0eaf0c07be9be245e1f1d2bcf1a6e8785b2150aae4d510f9202defceeb9b805e56f8c2aa38d3713d930bafce1dcfb43ac3717dcc8d331c1f3e567466a3c62bad5ed4216febd74905ef1827ef0ae77df9f0a632785b3cbc2b22ded7035e96256fd2ccbba3c4336140898c57479267b2e1d508f920f58ce78857ccccd98d161fd3517ae20ca7888f19f19e52782e7c55dfeb8ae245d9f1d2b4f19e36f8a005bc5a181f84c23234a9f77c5e273abc6364f8740ac177139ce518f24b16bc9a181f94c2ab72e27541f23a097ac708e0d5bc7cd0056b3a3dfc1222ef8e08cf74c5194e1b1fd3a29be12ce78f5f72f26ae1ff48e065fdf18649e10c07041ff3e313cd05effdbca810be89899f2bba04bc1a07ffa38057d3c0075df1f28c79c5407935127cd0192f8bcb0b43e455d1bcae1dce70a4f81813efb25075bc346cbc27189e53e1cc068e5772f26a3d7c90cc33323cdf61f06a461f44c1bb93c4334df2a69ebcad1e3e6544ff438077c5789f105ed603de303abc5ad0ff3ce00c67cbc7bc9cd978ef5d40c9e8dda17f22c68bbae2a569e2dda1e29992d6321ffe878817d581b705c27bc2e2b9265e4dfda09c5755c8fbe279d7fc275bbc2b395e58f6aebaf7f5c4ab02f3ba1c797789f7d1393b86e579f226d1b09609f23f617c3a317d47c1bbe83fe9624de7fba53eaed141e39794de95f8bea8785547af6b9157e68fefb69cc910f25d97b32633bf64c2cb83c92b66857731f827a99775c20bf3e25da9de1796b39c223e368277f5811726652dbbe17f8478797ede241dd66c90de2bc1d9cdeb63dbfb1fdf23f4aaca785d98bcaaf0754db1d644fda522cf8957e7906722df9d129ea98c77e78e6faa7979c2bc62b8d78603afb4c45a0d15ef99f1b240f026a5ce7228f898025ed50baf0b8db59cf26391bc4e78de31aa577bc00781795184bc347dbc2bf23d057859585e18216e8ce0dd71e29934f0eeecf04c84bcbbc23ff1f2ee44f24de2bb23e69ba6bca845de96ccebc48377cccfcb92e40df3c3590d13ef8df1a272be297db78cf7e1ce7462cf84b4d6e400bf54c5bb29fc932eef2988e7b6bca82adf24c7bb33816feaded3cf0731f2dab45e49cb9b42c0eb6af2aec8f765c5abc9f14134bc9acfff20f2aa3cf0be567877f8f8a626af8a7c5d56bc2933de96065e56082f6c8957f5e57531f2b272786177bcaa0e5e5711afd6f33f85784cace998bf9480576be3836038db85cf26f0a6b8b755f4aa72785d75bc3ce49b04e6dd69faa61b5e14956f6a632dcb799f2f2feae79b8a7879747893d4786da27837c6bcacee85457146a381f774785317bcad2baf0a7d5d7fbc2c43de302ebc2aa6f755e54c07f64c2fbc3bdb3369f1ae56785f61bca910bcae16ce72daf8a5262f4b8c1786c9bba37a2624decde19f48719693c62fe1bc3650bc1b5d5e9e18de242dd66a8cdedbe25dddbc2fa1f73cbe278737e5c6dbfac07be2e08318f0a6b2b775c27beae23929d69ad0f14b4fac2d24efc3c39b22e16d81596b62c42f05f1ae4af0c26638cb56ef23c45a13347e69895705be2e29ce6c6cde7be47d8eefa9f2f25cf026c1f0ae34f0c24e58fb83df44ded30dcfbdf09e9c788e88339b2f5e295bbb89e195c6bc27f3391b3ed12cf2de0caf2ae87531f1a2a07cd318af8c1ddfa1af4e24cf64e58ce7cb2b265bbb89f24a1e7807e37b06f0ca48f21d12ef3fbc36e65dddf0beea7835373e88cacb8ae185b5f1aa8a785d8fbc2920de961faf93ee1d03f46a28fccf24673601788f02efaacafb8ae35555f0ba8ade91f89d9c978784378988351cf0634267391ff8a5ee4d5de0756daf0cd37705785351de1613efce08cf44c67b7ae1b914dec37c4f1f6f4a84b7a5e5dda9f24c7cbcab28de57989785f3c2ceb39d9a6722e24dedf0b6c4586bb2c22fa5afeae675099ddd9cf1319e571be2837cd664ac7ce7bd3a2078262dafca83d765c4ab33c83379efca82f7d5e50c67fb180f2f6b8a178681f7a1e5f1de2420d66e80582d900f32cf9a64bf44c2ab638167a2e17592c13bc682339e215e31a7f7047ccf189f681c79afcaeb4483770c066f0a03afab5be341c02b6683b526e32ff9f06a517cd0f66a02f81f47d66cc27825ed75f2bd63b65715c4eb6ae4d5ba7cd004af4c06be73e25d85cff6789d9caf1208de99d3776abc1a121fd4c1ab75f14125acd190e03df40cc7e86342bc32747c670625b7aee42aa6e6469a2769aedb90c875517228415515c70f244ff503bd758b6984454522ca22949a5d3ace48452291b8acde8843097e64879e271aa229f8759c3a24725fe8450889cb2ade509a20488a27ea799d788e1ce90d899c16541d42854e1bca9443c1511dbb543cc1133dbd70851aca740dc98e33bfad0bd3f414cd21914bb308a95dc02081214a0108080c916925f4a85c112aad081165c1a29ea92a25ba9a9b187e694aaa1b386ee090c8a9285191d0962d264aaa28510c4451c2f1a84b914743c985e0b8ad26f78de6d8a5a33743a99ee996926ad771ab9786a1178232946b787edb08aedc67aa28ba995e1743b985aba87ae6b89adc06aa9ed9711c95121451d223c3113c3b72fc488e1c612853f23ccd55fd5031fd42d04c8b4678a13c49d22349731c456e04b9f14b8b5c28bfd524bd2e25bb101db9cefc386e6ba13cc50ff440543d37f14cd3ee0cc129e5867e2aaaa21f4a7edbb692e090c8791d0be59686263aa29b0a7a1d98a660c77152ca5505c593f4b66febba71dbc22191034388529aa7098a1d7a9e2249a626971aa565a9aa6af78da9697e1e888aa6372472aa1720b21079113acab2912b9469377aa6e89d1f9a762027a64322b7a50b972c42a96a640e1d8d9c08a5443d7224b933f4c0d154b76e2d42ea3a125428cd755bc32e55c5711bc771352a3acd0d5228c3b31b37b4fb5491e4ce8e0b878e442e44a1fc386e4d3ff34c410f0557721c123995a8680b2a44a47e5185b8141975e13a90ca15a1114e28cd6d55d52ffc4455445195533b14065086aa487a5d878e21e86d691a0e895c97a2a22d421ff77147485eb07c1d47e58a500b2694223aa6e2c67d2848a2de28a24322379a369c2a7c5c48e58a90584299a2deb66e6bb88a9bca9dde39247244ea96944815fa3a5045b36c39025520a11455cf03d7755dcf14edc0d41c1239242f5d88b2803f56a40c1d992c00018560670e1d01011da9273752b922d465843244bb313dc74e3dcd900cbd6f5d8b8490b26ce97244be4096e86672e17aa2e3b7a5e6a79e53c6f20c43f14b430e44c9d323d7cde3c29043d52fde14b1544d6ff3b8aeeb4252243772050222432a5784ceb01457350dc794044fd2ebb8300491b8ac1e5882e2b9a9e7477a1c776ee4c70d89dcd091972e4246456bc8bdf09526788ee329a6a1687ea7e77d432267640ea11b27e49524b971dcf9999b7a865fe86d432297129942424529d7a95f8cd423d548fcb122e527851f283f567eacbcf083aa360461d240e6d095e027821eba912918a6dbf6a943226784742444aa48598c6ea8020404348254ae08f1c0959bf779a1da8123988a1d496e58bc9cea916964547a20952b42346c65da6d62f891a94a8a26679ee090c8ad425d4ca32088bc785cd805959d07a6eab871aa1882dfb7894322a72265310a02e400a8e4b8ae03b70f35bd114d43551c1239a18e4332b91815ad211297d50b45283f8e1b3b3414d30ddd3ef53353a22c4110792922121ab9114228d5500c3755dcc271dcc20e4cbd1f2b527e3acf8b51d10a0484c46505fad93a2f3f5bba70c9f263e5851fa10eecc2258bc7c50b9187c465f54e0194a8baa627b76ddd778626789e432287c46515c24294450b9a85c8ec42aa4645e847e58ad00642d98d2a796e1c48926ab7aa9d382472422287aa5f8482308d4490ca15a1f1032e4545425b522321211b0f8c848c8a8c8c54a1232f4642421574c009156dc152b485020e9e04e0c713da9245cbb641071a78e0e3c1931032e80003107ab60b8490b678315735fdc0820e2a38a280820a00a00535cf2d5b8a8c4098c0548d2a70a26a1142124225c2808753b150c03a423aca22847ac18acbc2854b9107aa2ecbaa1a75d12065018a2352bb74312fd8e102a0a30e91e548c86bd2191de57060d62c46ea17a10d7052f5e848483512328f525415e2b48460d705558f848a90ba803142c59b0ea9a8c84828558dd4d4a84828043b358b1112083642a84317d4ac485e846838f4280b170d66beb0472604bbd3136dec3821218a824012c2429465e8c81cc220bb603921212e42464548265ab4658b298424848ac12a34544b48b22a1793e8a462e28b1e706e1522480a6723f84c049f85e033107c96c967987c36e633319f7de0330f7c96f459073ee3c067977c66c9671bf84c039f65e0b34a3ea3e46c92cf5eaeac109c5b83c4523885d50d4aaf6e08e4d50d60a264f01390ab1bce57375cf0ca06495ed960c82b1bc0786583d12b1baabcb2a1845736f0bcaa8102af6a10a4a6070f5ef560c1ab1e70e65981f0aa0799573c90e0150f1d78c58324af7870bde221014d7256515c78850590575154a8c9e0cba80cba8cca408b0c2b7587cd293b3c90b2039253762c6205d3292b924e59318153562ce09415789cb2628d53563c71ca8a2da7acb0615426329cb242ca292bbe53563c396505eb9415a7535574e0541514f851a826164cc042a550990c312a13a4519960411df1e5d411eba9237048ad36a754a6536a25a7d4d629d591532a21a7543e4ea9769c52d798b14971c0c8290efe38c5411ca7383063141f14a438a0e21407419ce2403dc58195531c4039c5c1778a839f7f07c58525a3b888e495160f4671f11ac50523a3b8386414170618c5c51e3f14a8231a19758401461d71c6a823b818754413a38e301a75440da38e2061d41121fc39165480031432a83eae8cea0386517d9c30aa0f6e541f198ceac3c9a83e7246f13182517c50328a0fd8283e16308a0f3f46f131c7283ed618c5c717a3f8a862141f4c8ce2c388573ccc318a8fa3517c6c19c5070fa3f89061141f5246f131c2283e4418c587cf283e2818c547ce9fd2b16135b9a1d9b1c9690280099cf0ac54a9511b40416de0649406b1511a8860940697bcd2c2334a83088cd2a091511a18324a8339466930c6280daa18a58112a334106294065a4669d0c3280d6418a5810ba334f04669e0334a030a4669a0334a036d47667593d20100ce9526af7208c1ab1c2cf0a356399caf72105fe5b0af7098c02b1c0a7985c319af7078e2150e32bcc221e8150e15fc3e610514f8eccca07c8c78f54239ca2788513e44a37c5419145edb4ed98071caa6895336419cb2d1326a83ef948d0fa76ca69cb229e1940d08a76c263865a383d384677ceff8d77bb7f885f26352453b699996d1e0f8703e1c0dcff02e0378568abc3a4496232f4f8ecc2738a400c30823a8436439caf2c484129ea84364391a813811d421b21419a943141911d5901279298a9212d5a06e394d284845548e5475ad2155b76431a340196184a32c5d4c212ea810e7c1a3cae23f32024ab764f1721e994f908a889e0c219932fca30a553cf0425fa837d050812fb0b34a17407488828a8d8525842c60f81afaf0e23d961a2224de4acd0f31c48349e2cf2a280d1511b068e1a9d8a035fcd9c517b1de0af9387ce0a980c308159e869e57ef10a2e26980e1d5301e089f5f9f3c9535a298e473a8e0a95051a591d7e1863f5dd06323e26f818615a054a9c2c20d346c3c1beb2b1ee070830d3558a942c30c32c4400586175c68610a0b52a2942b4051811cc510fcbc8edb36340259219452f4336810fdcc082110082a905156602184131edfc60c7f92e34f427faa218b16523835e04f769c70f8930d6d44f1272a2717fec4c229ca9fca3fad7052e14f29fc09853f9d702ae14f249cc653f827f04fdfa9fb13f727ad02af51402b24913f34c81641e4b5430a21e4b5413403bc16c81f7deca101cd6b70686ebcd6c61aafa9818619af95f15a015e23e3b5315e13030c2f5eebe2352eb4c8c45f0e4a0ca50aab0b5252d848307823b9f935e41701bf857c06c667697c86c667577c08407c06851c583e6b03898da4e6b321b2203efbb291cc7c66c51b89cc6744ef86156f24a7cfb6309191918df1990f9f9d9fa59fc1f1590f3d59646bc8b17ea6461646f6480018f9009cf13e5bf8641180ec9fc0f1b3f1b7a1c69fc62606265b2c0393fc06071b6828fdb61f38f11f34f11ff14f840f3de880c2004a000a81830d7c5668610a0b52a2942b4051218511c8510cc1cfebb82d084884100400c2071e74d0420b2db030e3f33334d030c30c32c410031518fe272eb880c23fff0e252c8037f019018887b79ddf747e6bf25bce86f3dbcd6fa9df50bff1fcc69a08a17fb2fa27db04bf392161cb7edb3f8446a4fc24849ffce427a027856421e8674a0f3a58a103155668214a0a21a850b6d0420b535a9832654a39254a59b610c20a2ba890420be594164411c429a508650825500825082efc4c07a2148ee3b8effbbe30044120a01042104184eff3bc11462049519c4161068519147e464ab9c2f7799e00cad28a942e5280429022454a092442082d4c8912254a942851ca29e50a53a2941d17a5ecb82865c745e9b8196488810a0c33fccc0b335dbacc74f999ed675a6801a88516a4489122254a942851a24499d2c294124884105a9852aef03350a04081024505155450e1675a985202a590c2082390e428863f53823f5302793f538a1042598ad0c294520020fc4c0b25d0cf78e081073fd3c2945284101a99e28045125184055707531ca0800430b248228ad0f100425c0608040f3dec80230b30a0b0828a2a9e70620926da58030c018640e20822668078190a0840032f5301482020738197e172c4cb685165bebc0c1252962caf72d02087f86e74f05be59783286e14fde9853fb5808523473104c9510cc1cf5329214731043faf9bd380e7fcb2910c5d6428ca720a8165cb16241888c0a4455834e0495115b89870fc5a60d032174d10a22e30d860830d361c698274465260d0d269c0e3791e97aee382ce85cb962d9a2056a4c0a085052d588e12658b14185cd032174d10a22e3154f0423b5b0cf0ab4e0e1dac22f470f4d7e07536189da7600e7d1e398a21f8795d00e902481740ba00d205902e807401a40b205d00f9374cc2c42eb9248c4b2491c4124c22c900269734c0026b74c002314c20592416014422c0c82011b063036e1ca246181bd0639134381006220d706401978401c8227ec4f8b0830f3d2e01048f981d6b5ce2814b24a163031d885d420725bfd1c1081d7260128625721c22c71a61e2c024160bc38e37e040c01a98ac114b03930d8ddf5c69c4b60658a1e2a960408c077eebc06f1cf8ed92df2cf96d03bf69e0b74a7ec3c06f17f84d92dfc2fc16c96f16f80d92df22f09bab01bf39f21b037e6be437467e5bc06f8b207280df0601840f3c7eb3e3373ae2f8ed8ddfdaf86d8ddfd2f857b04165014b0d961a2c35586ab0d460a9c15283a5064bcd468e62087edeb7917b5e0e1750a1c8974974f8e2ab90f05530791e2ad182fe0c618021f35b34f055bafc0c203c1659bc880f26024fc31e54a061a509161b95922c1ed9f261a9a1c203158d0a174438a92c293f6c6432f0f33ccfebbaaeebbaae23e28a1e8af81a62c024094b624881e152c50a158ac4b05f26d161b55204954968d8030c0f54a06104c64a133003c0623304824ac90d1964f108160fb67c5db460a9a99202151e66d042459b810b152e6c80c4860a2aabe4c8c1c951a5503b3a3938363433325a764a954aa550a99d944e2a278593b249d1a46652327b70c3f6397cf054f6a950e0a57b2a384f4584a772f33640f2546c9e0a1529343e55c6a7b8f894169fcae253507caa894f31f1a91c3e85c3a76ef8d4984f89f9d40b9f92f229143e157eaafb54d0a7803e25c2a742f894003ef5c1a73af8d4069fd2e0534f3e85c1a77a3e15c9a72af0a90b3e25814fc13e05814f39f2a9463eb5c8a714f914cfa7589ff2e1535e3e85f4a9a34f197d0a884f75f954d1a7883ec5e5535b3ea5e5533f7c2acba7863e85e553eba7d44fa59f423f757ecafc94ea53a94fa13eb5f3299d4f35f954cea7703e75f3299b4ff97caae653349f9af954059fe2e3537b7c4a8f4fe5f1293c3e75c7a7643e75fa94f6293a3e35c7a7b24fc5f1a97d5b448adfa0f84d8c2d8c2ae5575961539971c69b41861934bc192d3c7933566f86ce97b154c6235f0603be8c432e838d32bc3c1994fc18577e8c127e8ceec708fa3102f06244f26244e0c578e3c398e3c308e3c3f0e2c188e4c180e4c178e3c1d8ff0293ffa203ff0523ff4596ffe2fc2f7af82f66782f34f05e00f25ef4f15e5cf05d20f15d04f1593c9245229fc594c7228bbf828f2bc6b0428eaf428fafa2cb57913e1505782a84a022ca5321be147f140f88e28887028502857742cb3b01c32b21c42b61f44a10bd1219bc1216bc12399f44ec93c0e493b0e49398e49188e29120c023e13d12aa4722e791580248f10498e109107e1123f8228e7e0812fc108cfc10480f869007f3c78319e183c0e483b8c00701c97f49fa2f07f82f75fc1723fecb97f7a2c57b99e2bd6cefc583f792c17b01c02355f24814f8a328fe8889379ae38d7478a31cde48ca1b9df04624bc51f846207c172dbfe5fb2dacdfb2f35a20792dadd7c2c86bd143cbf95a9e3c160f1e4bcdaf1f78959257c3bc0ac8ab6bbcfac5ab4fbcfabd1af4a70b7f867fd6bcd0212f74f442e60bc9f042ab17c2b9874cbe07027c0f437c0f46cf03d3f320e679a0e47980e47700e27720fa1dc61d765e8711bc0e48bc0e32e4d0c1e7c0f339dc7c0ed9e370c9df90c1db00fb2a937c9545be4a1f5f4589af92e5abecf05552f82ae357a9e0abf03c0d2400c1cf10e66790e367f0e26750e267d0f233a83fc3094f2590a772c653a1e2a934f15472782a273c95f0a978608619af85012f82f9c308432cc45f8e80b8682cabe7151c6ca8b2420a43801122882f5e908e8c80e85244c4658b961fb20c6159d5143d3d204731043faf030202020202020202ea388ee3b88e1cc510fc3ef080dbc8510cc1396e0e4803016ce9162184f892e54b96155e9882c39429367022387221f7795cf764058e143548bd76c66b5b1c4506028f5c144555e18a952a34146d99b21dfc432c60b9c34b117ac7d12652172e5ab21c8acc3922135e03d5f88bdf93137c3499ffc93ee093ee7fe23d41b16a582aec2aacfe271921bf99699161f10fd173c1ca21441733bea789cfb87c5680ef21e2b31fb2a1cfd4cfccd7cf76f83ff0590d190d7f3201017b51648fd7f4e809c0ffa5a767a49e09bec7c96756d685b5fc587238edc93e9be133197eb38669d0808a0b2cac15bfc289a0280004ceeba011c6ebc8f13a79bc0e035ea77b1d1814f919242419255e467d4d0d305e33e43504bc16c86b85bc96c86b356cfcf15a1eafad56665d7c94a1afe1684f9e80c99200f30f432b1051a1b2e58517d25798e83341b6fcc2599ef2e4c90a456b1d6882fca47bf2e4559df1ba40f0a2b86f8ae24de5f0b6be78b5463ee8e8bd11c02b59e04c868befac9ce16ce06378bc2a99d775e5acc601eff9f1ae74de177a5633f4de156f8a8db795f4da5ce095c09ccd68f01d20af4c07bea362cd2687f7c49cddb4f13100bc3a1f7826f5558d795f52deedf81e1bce70663ec6c26b53c92b19f11ec9f7f0f1aec4785f625e8de983d838c3b1e2634ebca7259e13e25d61e08591f02e1aef03bea8d337edf09eb478ee8957c3e283c4b39c397e097556b3c87b7a9cd5acef59f1490692ef8c585b04a912ded610af0e24cf14c3bb8ac00b0b7a7792f7f161cd090def9828ef6ae985597953446f6b8f57c5c8fb7a729641f99f2eef4e0dcfe4074d1e6b35e17b605e96f8c2ac78652af9ae895715e5758df1b212f086a1b2d6048c5f42e25d27ff447bb514fe0703cfd408f29e1def0cce7771bc33477c478297c5c50bebc0ebc47bc704bd3c94bc62c237a5c5db82e45d71f0be88586bc2c82f6df1f2b4f02655f1ea50e0996478518cbcad9ab59939deb3795561de17f8aa88785d0e58e3e1e215c3fa9439f13f4dbc2728cf8def547c0ff7ea08f24cdd9b92795b2a9cd598f05e11af4a90f7957a79ba37a9cbabfac0fb2ad76ab8782f8d7775c90b53e16589f0c2987835d6fff8f1ae42785f499c1dc2af22ef4ed03365f1f2686f5206af6a8bd7a581b31c427e8982339c0a7c4c8e7795c2fbf2622d73e37fb47859217893542f2a8d97268cb31a38de83e3dd39e199d0787744f04d31bca90fde1696373580b755c47bbaf25c0cefce03be0984776700cf74c6cb53c92b465c73f2c23b66855735e57595f1f2886fd2975795c1eb427a67d0ef2cf0a2a27c5319af76c2ff5ce0e5c1e14d1ae34d51e07581f0eeecf14d3967361bbc07c98b1afaa643d67446f8a53fce6a48788f88b31b4b3e36c2eb44e8551af33a79f28eb9e05d75e085adf0ee0cf24d3c2f4be885f5f1aa34785d41bc2b17ded719af06e6839ebc29d6db9ae13db5f15c19ef3af13ea9b31b283e66f36640ff73be289f6f02f3ee08f14c1378513ddfe4e50c07848f5d39bb51e263333469bc9a201f842a71f1aa6e785d73bc2b2bde17256732587c47c3eb848757e9034a55acd92cf15ed3cbd2e185e57176e3c4c76a5e193fbed3b296adf13f59bc1af73fad359c2a1fcbb2c6c3c72b268357d3e183322535de999cefe478353e3e68873785c7db2ac1ab29e083babcaa3ede17ce1acf1faf9827ef4d7e405e56102fcc016fea85b725c5cbe3e44d225f1505af8be82c67f5b144d67450bf14c79bc2e26d4960adc91dbf04c5eb847bc788f0cee4f05deb8ce689f74e7859237893582f4bca0b2be35565f1ba2a399349e33b1dd678c478c538517af2a256f826325eed8b0f1ac0a7d398ef9cac6595fc8f1b6b3456bc97c29acefe121b6738437cac881735c43741b2a643f34b6e7c9a29c17b16bca8355e9a31de0df99e2cafce98671a7abfc0f7fcf11ec6f79c709623c4c742f0ca60f29d16ef8e1cdfa49ded04e099a4784f393c47e5d58af8a00dce721cf04b1a9ce148e06370bca97d5b0378b7c0f7ecf1b2d41726c8bbdac00b43e1dd81e39b76ad09eb97acbc27017cd0033ed110f21e95d74907ef980dce6e0af958005e9e13dea4245e9b31af14c5cb2382570c0baf4a02ef0be83d59f1dc126b4e7078c7b0f0a68c785b899ce5e4f14babd72602af54f4f278e01583c2ab69f141e45a0682ff99e3555df2be50785189bc2ded0c026b392c7c2cccbb42bd2ff55326c5ff38f1f258f28a21e1acc683f78e5e15d1eb3ae4d528f0414baccd30bd77c1bb58bc4fcfab61f9209d351d27bf34c7aba2e27549f2aa0c795f137cda12fec90d2f4ff8267979b5301ff4c4abbdf14131bc3bdd3371f1ce24f15d6ced54c877352f8f0c6fd216af8d23afa4be361d782526ce5004f8a649de13fa1c0e6738607c6c8af784f34179bcab23de976b6d6d3e830efc487176e3808f89f0eea8cfa4c8ab63c733a9ce9c9c5e3131bc279e0f12e4d52cf81f4268b438e3417ac5ec9b6ae26d39f2b22e799368d66c54efb95ed522efabe74529e06dcdbc5a023e68cbbb63f44cadf774c673602c33f3c57ba757d581f7a5c2ab7dff037b978af7a1e0e5a9e04d9ab27683f4b17d55525e1719af66c38b50b486d3c2c7d6351c3d3e06c6194e241f9be35d11f2c278de8de27d78d69a70e097ca7851e93709f2a60c795d3aaf96c1ff18729691ffa3e545a1f1d280f16a967c5016efcc0edfc1d69ae8f14b517c9a51c07ba99747cb9bc4c78b5abf899097a7ca9be4c59a8c0adf89f02e1def83c2ab82e27555e0e5c1799342f051dfaff89eef4d65e07581ef0a8df73582b31c293ed6f4ae1e79611ebca93cde96d2bb53c5337960cd6688f7626f0ae96d19e05d15fe09102f4f93370948c98757c5c3ebcae35d2bdec782331c463e96c6bb63c83755b0d604885f3a7a556abcae11bcac2b2f0c8fb39910be23e4d51af0415fce7278f89825ef4e0ccf84c7cbc3c29b34c59a0e05bf44c78b22fa2646ded4136fcb016bdacdffe8f1a6a8bc2d2ade9396e77cf08278f7827f6273b61efc13ef0c67e96306785522785f2fbc3be93325f2aebe785f49ef6a8bf765c9fb24df03c8cba2e30d13bea7189e5b618d6701af180e9ea1c9e1bdefdd89e2992e79550f785f1dbcaaf17555b1b60d789f1cce7234f04b402f2a856f0ae34d69795b78acd9d8f0de075e96052fcce8e59179933438dba1e09998786d0879a51a5e16015e58045e8dfc1f0abc2b82f7c9f2a604795d326738a78f4979773ef04d2c9ce1fcb1f2658d799374d666ec78efe665f9f18641e1d3e901dfe9bccbc4fbecbc3b243c5301ce789878c5d8acad1eef23c3bb43c83739596b52c62f29b17692e3bb7d530a785d4ede93071fd480f764c6735f285539ab497a2f01ef09840f7ae4e581f22635f16a747c909577a7906f02c0bbf2de17146fca87b765c6598e091f83e4d5eef8a01bdee5d913d173e8abb1f1412fac69a8ffe1e3bd8eefa961991927b4264bfc129857c692efa27851327cd31bafca7c5d7dbc270a3ea8901795c54b03c5d98d141fbb39bb09c1c750785759bc2f0d9cedf43c93132faacb3731e06ca39ff9725653c37b4fbca8ee9ba438bbe1e2633b9f686a78cf7b6542f05d172fcf085e3153d66af0786f8ef734c373515e1e0fdea4f3b541e4957438cbc9e1631a785700785f5cde94cfdb125282e3134d1befb1f0b298dea40ad69a80bf24f4b2d678614b6b38247ccc7c9d80ef18ee55fdbc2e306fd6fdcffaa254dff4c3594e25bf24c2cbb3bd4944af76c40705e07d8def69e19d417d67c76b83c72bfdbcda131f047426e3c57735bcda231f24c4da0d0daf84c9eb44f58ec9de93cc07cd718673e5635bce70ce8f75797988dea43f5ecd84ff09f36a18fc0f025e569417568017b57d13142feb8a17a68177e1789f12d66ccef732794f167c90216b4d2af925325e96961766c87b32e1b9ee5d59795f729ce93cf24c53de14075e1709af8e049e098637f5f3b6ced789fa2a8de04565e06dfdac658efc8f196b4d847e89cbbb35fc13275e8d031fb4c5ab63c93309bd1a0e0f84c959ce037e698317b5f4b64638c381e46371bcdbc13f097a35453e88e82ca7838f39e0ace688f7c0784f2c3c67c2cb4a7a936e5e5411df14e62c87898fc5e4e8e1d544f81f07bc97f13d2bac3551fa2535de9d3cbee9e64d8df0b684785575bc2fed0c87838fe1f0cadcf15dfaaa2ef0bec457a701cf24e5655de00da3e5e519e14d1ae26c8689ef9ad678e678c55cf0b26a786173ac3591f24bea5a930afc52183f55acd160794f543ae2dde9e39b745e9e2e6f5220afe6c1ff30f26e947f12c45a930dfc5201ce6ef2f81806ef847c8ffaae007961a8b31c4b7e29e8dd219f698c5715c7eb6a7a353c3e088777af789f0bce6c4c782f036753d6f6e79f70f06a4ffee7909735c81b26caeb448477cc07ef4e0bcf34c78bc2e2a579e24d89795d297c9a79e3bd9af774c273dfbb627a61359cddc4f1b10ace6ebcf818ea454de06d4df0aefc78613aefaac9fb3adf151f2f2ce7134dcd7b19bc3bde3375f1aa76785d78bca7289e3be25d5d795f78bc3b579e499077d7f7c8b1ab8677a6e83b4bded4066fcb5cdb49e3994aa014c499939a578c96d709eb1d937a2f3ff363ad668ff7e8785915bc3020d69aa4f04be83bb3df9df1f25ce015e3bda80ebe89002f0a92b70580f72abea75bd3c1e1970c39bb669dacaf12095e15d0eb5ae23d1df1dcd18b12bfe98a7759f82760ce6660efb15e1409dfb4c59a8c08df71f0aa60ef2b841705c53771e05d2df1be26b0a693c12fd9f16a5c7c1009af9312de31e31a4f1eaf180cde05c03f91599359bf235f270078c7b05e5515afeb02de943785f3b65858db9c93cccd77179ce154f0311ade14ea6dc1f0ce107db7819727ca9b04c5bb227a5f0938dbe17926255e0d8c0f3ae1eca6041f53e11d8def91f2b2665e180fefdaf04f9e7857dbfb6a624d66cb7724acdda4af4482f7f4c10739e06c2783677ae22c47905f02c0d9cd073e66c28b9ae46d3d79772ef926282f0b8817b6c8d98ecf3341f1b24c78615cace904e097f058cb7e5e0311ded4186f0b034a56de15242fac3bcb71e16392acd180f0de076b38327c6ce8ddca6a4b7c1008673417780f871775f44d0f7859e70b03e4aca691f7f8785766bcaf10bc2b21de57035ed47e530e2f8fcf9b64e555b5ded7072f4a836f1aa2b3e16595e04d72f2ae80ef31e36565f0c2bebc3b957cd3003e65ebff187176b3c7c73238cb49e4977a5e8d8c0f82f2a6ee785b24785397bc2ef26ccccbaa7961422f6ae69b7af092785978bc61467835f3836a5e94256fab83f734c57348bc6fe07b0ef0ea54e099667853e2dbf2f2a292de9600de551aef8b04af06810f1ae2ac0603ef21e04d8d6febcb9b92f2b69a78b500fccf226bd995ff017356c3c17b46af06c50705bd3698bc92142fcb8717e6c7da49fc4e106736da7b8ebc2b9ef7f5c3a79904bc877a53366f2bca598e081f83c0598ef8b108bcdad207adb17652c077386b4d0cf9252b7a7078752e79261f5e151def2b3ba3f1e03d0fd69a0cf14b5f5e16162f6c03671909ffb3654dc6cb770338cbe1e2974eef8e04be897b794c78938e789da4af92085ead920faae245cdf1d2a8f14947885fcae4cc46e73d08bc37e07bd8f8a1e2bdf995be7897e27b80ce70943e16c8cbca5e580e6b19ec7fd2786fc057d2c0ab25f1411ebcab455e58066f2a8db775c92b0382efb8389371c07760ce6e46f0b114d668f278cf85339cec63515e96062f0cccdab6f13e24bc290bde560e2f2a93b7c5bd2b385ed82f6afc262c5e94936f227a6f685ea98cf764f41c967785c90b6be14da9de560c673b3acf74c459cd04de13644d8685ef82ce7266f818065e55f6ba6e7853ebdb0a859c5ea5f9a1dec671aa478edcd79da0ab0cc371ecd25534531154d3b36b9529a782a1178a68ea8164ca8d1028c9ed4c3bd253b75315cd501d420ce2f48052edc035f5448f14b71f2b527078a4dc5474edb83555512eedb88d7440499ae0379e28b78a1bf8a56303ca4d5dc37125432e15d713ed3e474a4f35d76d25570f05d353dd440694abd7995c1882e2f885694a828d9428b87961e76da3e88168778a4322a76e318f368f88132325b8925df7ad23a98aa2b9a9e4024a711bc72ee440ee5cb7cff34e05949b798ee167a6dbf7a52488868b949f897aa4a7aa5fc879dd866e318f84380e3cd2826641da38454a311dcdb453550e3d49534cd3444af4e340af1357d3233f9053c50494e06976a7ba81604aae26ea8d8894aa4aaee3e799a1876e2a7a1e52ae20fa7de0f87969ea81608a1a526edeb8815fb876def789a0b922a0fc56113dc3ce23bf6d153d2f2d045d41d50c378eecc414cb01cad54bd52ee444f43b4d2e44b91c4e8494297776e3e88d626a7e9faaaa83941ed9715e28a2aaa78622187e4322a71a79e9d2719d2025097ae2a986e1e87d21b8a1ab014aee5bd57504d1ee4c53533dd340caeddc4e2edc3a153d3912153b404a4ee4cef54cbbef34431344c13fcaf4fbba50244f2f054d9354cd931f25f875e32a7e1bb989e0b816090d1d992c7c7d94a9f8ade1297eeab6a2dee681249cf8284591fcce4e454550dd42d33cf72853f35b3755ed4cf153532e558bd211cb498f921bbfcfe356efdbb6955347f39447098ea6f77d29b88a9bbaaa5f3724721bf7c3098f1224c56d1dd14e34c57335d1b573e107ca0f47b271baa314d7cefc3c6f25d7d3fcb61014b79cec28bdf4e4c2d0db423424bfb44b8744cec84815ea6272114f7594dc689aa4b7a5a6ca89a0d8c5e452fe40f9b1429ee828430e0449955b450e4445b343436e8ed254bf0d1dc16f43c1aef3bcef0341394af0ecb8d5e4d6531d55d04bd70e8f531c65789a5c4a825f3876e67786e357431112d1142a57846438c15182e7c69126387aaaba79e9ca9dde28d18efc3cd5144532e44413698b17a42d5ea0fc0001010101010101adea0a404046eaaaa69bf8692438b951821e678a5eb872231772e906aa716aa35cc5b45bbf74edb66e0d4d8e3cb151a29d897a9b677e68ca81a60a760638ad519aabdaa9a0c8a966ea99e6b99dd4283f7205d7331cd3152451b3eb845091bc70111ab92e8d32e4428f44d7ad1bbf734c49f0088d525cd1d304d76e4b5772544f67946717721f0aaea7677ee1767243228766d97204047432a31cbf941cbd0fecbacecbe3544639aadbb88ea0b99a274a6ea37a2a406976a36a86dfb89a670a8a2b2a8e604e6494dc9676a3b98adfb68d9db7a6a7314ad1dcd03434d1ee0cc790dcd621910ba1c000e5e7869318e5b99123a97aa10772e0770aa31c378e03d38e1c43ee43cd95ebe20446d9ad9fb78adcb7aaa6b882e2f645999adde98d1b697e66aa7e1d3a24729ea8e5e445a99add0aaa63e871e82a7aa8ba7e5e17e5479e28887660b7ae27d979dc911b272e4a511d37b34b470e3441120dd1d31625b77ea0297aeb686e5e689aa778d2a2143fd553377514552e1cb72d5481ca15a1214e5994a979ae9c4a7aa0979addd78ddfd091c9029289121541f942218a82b002043474640e8d5894ab088a26e871a448aeabb9911f3780d315a59a9e2837a69f4886ab9886db90c811097546272b4a114dd3f15c377415b9ed14c12a4a343d53d0343791e4c26f04498e0b8a83bac570a2a2544d7034476e44d7150cc335edc8234e53941eb98e5dcaa1a9fa9926d99dde7792a24cbb511c5311dd38d2fbc094ecbc38455176aa7a72e0969a2917ae1e59e50445c99123d799a6797ea3f7a51df9e5f4444986200772e0378622b86d4245e9487472a21c4d70fc524fe556520dcfcd3c35516ee677862967a2de89893244cf5434c74d14c32f243befb444d98521caad29888ee0e6719e12a59986296aa21cba92ebd7a9e42989f25b3db01339734d3930dcc4318b1312a5aaae2b777ae23aa6e4079a6253e98de7a892df2aaaa0ca7961c85492e7787edcf799ea478eea111855cb071a694ba51872a169a25e68822b4872e2172b4d8e43d54d14bf74e3462eec8644a18d43322a3afa34a5b2e34e534dd7ad0bc36ffb42b004e52a92279aaa1bba9da3c9a920094a743bbb30ecbc2e05475086ebbaaddc49765b088264068626825244396fed40125d39d0333b510b41e9a5e488762927aedfe79d9baa81a00ccf94034174ebb8d0434175cda40c5514454f725c3d55ec546ec4a40c372ff446af0bcfefdb36551d537e2bd77d1b67925b88a6a887d4f9a0892945cff3cecf0bcf0fedce500c8744ee28cb1675fc4049a29d8982e167ae5cc8ad23e98152354911e546f02343130cbd534b2a4d9433c18fdcc0d5fcc6aeeb3a50a2dc177ea8989e29f76d27c7691c28b9d55b3d32454fb15bd54f1cbd04689794e4c8a11ca7822229a2a6096e432257547655344bca2f1cc5efdb40923cb98ef44242a101e88b917ac475605022d5c8c80b2a86b601d44bc17125b7503c87446ed440b98567888eabc7a127099ea9aa65a03cd791fbd20e15c1504c4faf23aaa4e440f324cd3315b754dd3ab5a3a45c373435c70f55bfd10b8981121cd3d0f344f0e4c2eedcbad044325321920397d02629c77133c3cee452eff4d4ad2b4ab7ee02251782a07a72a24886a23782e890c87ddc11c91d2165e192654b38832649e9a9a46a92aaf879e40a8660b674e9620a15a5e1105a98525d43f03c55913cd3550c577348e4364e2cca22d4e5088ca43455ef1c47504439d2343f8ffb340b94e189aa6287a22627a2a9b892e38f1529404069111424b54a17ad02a5799e63f8ad6aa792283a7a219189761c054a0e4dc7745b41ce133bf2234323d38b1423158cf902121a24e538aaaae7a11f187edee871a736815225519204b753edcc6df5507048e4908a8a8c38aed324509ee9896e69d8855f1872a3786e836811283b13ed527215d5cee3ce51110d568ea8e96de6c991e0da716b4822797995e2988edbd9a1aa989e6a2a7a9f219aab54d714ed4c4e25cfaffbbc900323449151975639ae27ba9e1f4886297a86e1d97185681028bb0ff5d48d14bf3525d573151f50aa1bb77a5f78ae9fba89dfca79dc23a5da795d27aaea089220eaa1e8d735a239a044c3540cc951e4425504d3f368e41a507ee718aaa1b885a0f78da248728e94e206a2293986e0c87d26077a9ba731a024bf55e53a7024c930e4547224029342f94943af91f21bb90fed3813dc4c944bbb949172fc44b1fbcc105cbbf314bf8edb03680b28c1ef13c96e4b4f5345c5f50383d014506ee2198226c9919dbaadabba0d89dc88a42d52a25fe781eb179e21287aa0c881a129526e9c6a76a2f9a1aab98529c8454ba4ec4494ec468f1c515535c98d4b40b9a9a03a72e2b97d5e279ae0f96dd1102949af0bcd30ddd2cf135774f586444e8822158080525588a2331489b4434a0e0cd7754d45530453941b3913c95c61ca6884d4e54833a4e4c0cddcc2534cd1740bd7f13c85ba2e55896a00024a1150aa1f48ae2018821c1a6ee7868246485d78d00a2941141d517323bfd0dbc06dfd48aed30e5076e128a69dd9a99f3824aa5b4ed3088d9052e54eb02343f043bf313c49f0fb0629c75505bbf1f4c0f55c3dd44335414a53e450513d3ff04453ee044336340394dc087621979a61e86d9c287a8194663aaee1f675aa7772e4468a46eaca09711fb70cd00029cf8e1bbd0e15d594db4e944ccdd0fe28478edb44f223c7503c4dd2fbfc28c150fdd6935c373444b98f43fb284f914bd1750b41545dc56ff5d6d0f828b76e3b557245cf7005b71414f728bb6e14d18de3c091ebbc6e25534d8f72f34c53f5b8355dd77014bb8ecca35c3f5355c171edd0eff33ed1fba2e1518aea788260aa9edc8682277a0aa1a6441e27c475dc1da5276e29b88e24a886ebd7ad3f507e42cf8e725b456f25c18e4ccdee1447914452ab6875946ba78e5eb88ee2f951f981f2c3c28f95177e8080c42f4040e2978e3480464799a21c1a7a2b398adfb8a5a43747b9a99bf889dff975a7d799abf786264799aae7ea7deb9972dd776e1caac5519ae6f891dcb7ade4869add6776709467b76eaa478e5d0a76e397866e686f94e73892e7fa75dc2a8a9b789a432227d6a1b9518621e9ad20686e69d771de760e895c1733bc810ead8df204c37423c7502541933cbf543542c120ba3934364a6f0b394e0dbdf0fc52921b3d6d8d92e4d68d54b751454f4f35c14f53a334d1703545731bcd7448e44844b4344a4efd46134db9710453cffcd0219143808646297aa1f77da8b86ede897adc3924725c97887646d9ad27198ee0b87d5fa786a43824722951d129040645528f46eec78a94a320c8ef10cd8c92e338154ccfee2351b3fb3c540849c5227248aa942bb432ca133c5554f44872e34212ecbe2191fbb80294aa9a86aa8a9e20288adee6a94322d7316964945e179a29b99ee4ba8a1f7a8e519a676a76de6776282782607a8ae3179a18658a92a0c7a9e0c98d2b87aa269a65cbe945062020202020208e134d232fa66887164629a61d97729ea882a448a2aa51102a51c80d2199327c434866970f0c52a7820646f971a8c7a56a1a6e62178e2aa9760163050848dd62a2474661685f9462e8ad9ec7a55e3876a7ba6e9a17e5baae6037ae244aa2684a829c205a17a5297ea7d87de9266e9fba9a2417a5b99e5be88d6ada8928796ed962a21f51948ed3b6283bce1c4dd20441f2ecc28ddbb88c485e60208a026a5a9421c891aac789dd3872dc379a5cb20c1d01a95b4e13e9cbf6695994e1d685e2679ea667a2ea8a8a4322b70a21a947aa51c765318dac64c192c528060d8b9233c593dcbc351cc7b33bc18edbb42b4a0f0dd75144b72e254d744c4d2b4af403d7d03b57141c49ee3cb52aca4d0cc9ed0b530e0d4d72ec3c2a4a4e2451ef3c455535c9f4fbd41eb4294a50554990eb3c103cd714355720a0113c3a412a57846ad0a42843f10cc735f456f1ebbcb0f386448e53a1eb46f0e8d4a228bdd14b450f0ccff0334d1425cda1113c3a1a833428ca543cbdf53bd7d30bcd701bbb274a74154574f348715d57f5f34ecd89d2ebb6b04bb76e3bc90e1c4d301d3923f5c823416ba2dcce91dc5473eb4c5125516e1b12395234528f3c8d89d2fb462e25c14dec366f34536e48e484309188c01c8520186a4b94674a9ae27a72df877e21f89d4322077e31684a94e42a7a239a9ae48776ea77aa36684994e197a2e9969e1fd8a9a4b76d1a12e548921fca792b9782e1a692699722a3158080ba1419a5aa6a84740201914d65ea819f88869b499a6adaa1dd18ae195379aa6838929bba9129f8a16b3a247263c779114a8dd421b254010232528f80808080964a35dc54ef04b96f04513425bb113c3a122a42023b544d8ba08ce051153214a95c1172218b956b0776dbf8819f9a8ee6d8ad4322d7754a25eaa15b9a7a6b3a766068865e911091897a25283d522439eee33cf223bf55043791ca1521352341697e1f2a82aaa97a21288a1e1a8ea0f4be0dfcc6cdfb3ad3fc506e14a95c11ca9289a014c14de45470e5507214cf8dcb42507aaabaa55e687a27189ee62982a0ecd67315c535dc4c4e3c5590cba43c550f254571e5561005396fc5a4043b91dc42cf4b438e34cff31b53aa9ca8ae2909aa22c87969aa7a9e985244d5955b378e34bf0d4dd3f30365fa8160878262caa55b6782e0f779a044d70d44b7ee04c1140d41d4f4bca4f23bcf0f15d5f3143b506e2718921b2786a9996e1b297235641c28c571f4528e53d34ef5d62e54bd4bcaeedbc42e44d56d544dd3f4c62191cb2c2957b2db42d4e3364ee4c62f4c3750861f7872a047a66afa69a044418ff454ee3bd36e235190cc40897aa9c875a6388a9bf9992a2a829594640a761cd77de467a65bb78a9f474939a2211882eb46926a0a9ae80804f461a0ec5075db36103d43555dbd494a0edc46f0f3440e1ccd8d3bd7cebb40d9715f3872a2ba79eab789660a4586177e404232494ad3344f33444d5245414ff5ce30e5a97ea7b98da0398a5d24e5e79de43792e697a2dcd99164e759a0f4cc93544d4f1dc1b50bb72ead40998a9e2a76e306929b19ae2305caeee350545dd3ae13b710fdbc0d8a0c92b223439354b7d044cf75033fb09b4099825cb886e63a8664789267da49a05441750db76e13456f5d4f6f4bd114a0283f507ea600017531b900011d19a94040462a529628b20894ea1a6e9b8982e0e6a5e2d69119ac1cbd513c49703d53740d5152fc5e65c7a5e128862b088a26d979de7747e62ac313f5cc50ddbe2e3cb753f4ba56499e9cb89de84792dc11044a8f53c1d13c556e3d4df304c123ef0165fa991db78e63a7aa2188ae5b15d92325da89a7e9a51d487a26a78648472a92f9829844e680f2f3ba74fcc873fb44d034d1b5eb1a509a69378ae24a76eac6a51d37769d2325879222b8816b086e21c96d6ac78052fd3cd53453b31bbf46cad1fb3e941bb915e438cefb56464a343c538e33c5ef0bd10d0cc9ae5b40896eaae78923da7d64ba719dda750a2857cefc3ecf4bc38d1453f41ce5c81629c91105d1b113575504c9140dbb4e9132dc567455cfae1bbbce23bdb54ba4e4c470fcb6af0b4db453cf10dc1250aa262a92e4a89eded6995f28723d64889424ca9964a8aa66087ae908a687941b47aae7468ea2078a27997e8694db38aa5b2a7edc48a226baa19e9721a03c4db40b51ce145192f3c86d9c232ba44cd5f15bbf35dd3cd444bb6ff4bc0394e9769a27a77ae2a87a1e2165c7899fe9ad2b777ee7a99ea7e70d52769de879e21972db487a5cca9154ae081d9109529ee2f671dce7815e178620e919a034cd6e24cd505ccff11455aeebb627b2404ad53c3bcf14c513f4d674553b40ca70f3d6f0143972f3c43034d53455918c8aba9086ec8f5244456e0b5574e45675ddc2cd8f72fdbe0f35d13155bb94e4b6f48cac8f3255b771dd3c343cbb5555498e8f52e540af5b531154b9b3e3ce318b6c8f325d3d9233cd8f244d34053fee28d3a32453530541525439ae4b532ef5bac8f228d56fec3c9053d313f55653f4c6c8f0283973ddbe90e3b8314d4593cbee28c77513d7900ccdee33372efd323bca8fdbc28d33bd341dd5b553bb34b23a4a75ed542f154d7545d56ef5d229323acaef5bd56fed54b02353f0ebc039ca35e5d2b323cf2e4dbd30f5be6f94a31cc1ce0b49135537b2ebd06d75228ba3dc44d1333d5135b7f54b4f12fce02849310d53523c3f74f5cc94f4de28cdf5e4c2f43cc74e45c7eee3dc284355345393ecce2e05d19f54f4f2a31a79392ada82fe9ca2971fa1b11bdb28c1f053c1cd4c552e24436e5bd9283933e4d6f42455724b41d14cd728576ee33cd2534dd2133b2e0487440e8cea02a97a6a9426a88e62e871e3fa9166777e64646994e1a8aa24397ea1e98522ea89de8746c99da2987eab19a6a99a921fda9d51a2a689aa6a078ade178620b97e1ee8456646099eded975a4f97962d7a1e006c60869f4c01859e9be0001ad9195516e6a089a5cf881e0c875a01816a0fcd213453bf45b55eee4b6f57c2123a3f442d53341904ccf30ed423315c728c7adf3b64f4dcdd11b55aee3c428576fe4b6ae03bfcffbd06f5bb3304a4fed402fdc5074053930e4d64f8d0c8c12dd4053143f2e3d53cef4d6f1fbbe28c3f534bd500c43d353d1d14c91bac400043452b922f425f3a2f4d2d004c570ec38afeb42b0eba2e4bab0233b9413557445d7f50302fabe9042dcf745c645399aa3b79aeaba921bba7d5bb64569a26b38aa5b378ea229aa211b9916e516aae21786200a9e62d78164964589925bd8912719a29f9aa6613a24729161519adeea9d9eb8a29dfa91deb6665794689a9a21a79ea818761b3a8e276456949ea972ab07aaa92a8e63078e6a9a55518aa96a86e40a8e5eba7621a7aa671623f4485d41089424a3a214c78f5cd1d023bf5325418e3b2259c8a650539d4c8a32353f721b4195ec467334b1106501936e5c1112d114b0eb6272f1408ed3218ba2e456510c4d144539355c47cffc81425494058b4a0310101050c70971e01f1914a5d971a687766a1aae2407a65d141a7e98c89e285530fdc8cef3ba6e033bd55cb7cea32373c2fc3671edc0affbc0534ad644e971e7a9aae2887ade0692a497315192aa478ae7ba9d63f8752718664b9464277adf397a2728aa5d1aaa4322a772f172747a391241ee28dc3a2a578460c89428c1cf5c4392dbc0f3eb3c303487448ec8c8cb49c210da902551a6e4f68d1f2a865e076e2ab77a65644894667a9a22a7825cd889dc1992432217723f565ef8410202fabc6e1bc36c53198a9be989241986619892a2c95486dd399e1be8a9e0488a23d92d95dd399ee1b88aabb7ade1099a9e172bc17103b7145dbbf504370ee43c4fa934d52dfd481424d1ce5b535024edd81294deba72ab2a8eea3a76e8977e5df7a52341797ea1e9ada2caada42aa61c3882f24bd7edf444702547cedc36741441099e1cd9a9ab1a86e04872e318827253bb533d5530fd4690e4c60e0425baae2b8a86e90982298772a2e7655272eb669ae9fa859fb7aaeb360a711d26a579aa1d388ae78672202786df98120cbd555539d25337d223476f48e44231e54a7a6a78a6e4a8866a7a9ae707ca0d54bb0eec3ab0fbc8b53b4fcf03a5c8a99b4a8e9e18a25b678eab97549ae04a72e2baa6a70776a177761d284d544551320cc1901b4f6e8b172e425f152020208e89e540d991e3ca8d5f7882aa87a6dd7949b9811c287a660a92df697622372472a91016a22c475e3c4eca5a52aa2aba89e1d8a9216a9e9eb96da0ec3ecfdb4c143c3774e4d2311d123922750baa7e1122b928ab8132e5c25424b99414576f3cbf6d48e442750527360325a99a6087a65cf771a9687ae6d875316108b92e2617a18d43da4aca6fe4b84e25bd4ff556f2f4404a4a6f13d593144dee1331508e9c7a86e9988ae6289262d14a94450849c51216ad4453b6a84444e6101424550a233b49798eaa08aaa899aee836929cc845453a0273c4791728b7ed43d54fec509424c313e5dc58494af124c32d0d5512543baf03d55568e31eb061ca70eb3ef5134f54453f8ee3ba219168cad1511846527e66a77e6a08821c67862b780e89dcc70171507eb6f24786177e2c50aedfb882e6a8a21b1aae61ba0e895c2a74940508888b90aaae2ca86a941f283f475fb29837fc5879e1e7088948252aeac2a5c848c562129930a86a142e280e40405888b2a8eada890ed80a94e646aaa349925d087ee7b96d2051d1162840402a51d11631a440798ea0c871a6ca999ea7ae9d0a49998a9c9a72ea0aae1dfa79ddb87142dc04ca930351733ccfef0c53130d372ea810421b146e8695407986e8666edbb6ada029761dd7c534ba2102a5089e27aa8e1fb7aa230a8aab109853e8f390b29c63c7091d7d9cc7c14a8ffb3c3554d7d423437115d75749aaeb4672a1aa9a6a8a7261b7aef24b4f72dd4e553dd1b3fb3c232c425cb7ad12fd407053d7f4e35455ddce50a47245686821508228b8a1287a82237aa62b19724171784089a6a81a7aa6077ea10aaae223a5b9a2eaf6799f8a8e9cd981df90c81da9ea2ac47158d601e5a9a6630a729d6792eb09a2de90c88d462a11d1942c5d8aacd4308494e506202020204e8b6d40f96d9d998e20697a1d1a9a9fe9481986e286721bb9799da79ee637247240a8409440405db88ccb80721cb92e04377305c34ffd8ec68d6ba43c3f7043532f3d43f4133d5365a41c3df5134f521c537035cf714a0a1d1dbb80b203bd4d25d1901c491214d34d01250886e0998edec8811f388adc19bb48b972e6d96d204792201aa226aa48d999e9fa6d643a76a219825c2804c60869e3c2d8444a931b411524494f245173e35264b47eddf2b1092851904bd71335d1955341724587442e35f27244a4821cc985352c2265178a5be775aa899a21787ee496330bea25558dc4ad8b3da4e4427244c5f30cd5735b512fedc22b6b48f9ad9f3a9ee7d68923d7795f382472e46784d4c55b0494dcb6aadd279ee8c9851db76d43221744d19623d22885904389c01c7d03d8424af53357d213c1ee43cd7135c9ad8d3d40997aa6daa5620aa6deba75dcd791425c77c51252722ac7a964ca7d2777ae28970e5282a7f7a124ba8ee24776ebc92119993280498b54f03c41ca50553bce54c973f4d2f51357d18c3540496ea9a872a4279ae7789a62d875819427da815c387a6998aaaa88729e074839a6e446aedcf68123c88da729c4795c57c7fe51865e78aee6487e648a86646a825b15eb47a9aae989a229078aaaa776e2e7797d94a0d7adeab785dd0992e066aa1bd7c1b17c949e17aae2b975a0da7ddec7895a8c8a824052a9ec519e9bf8a1a9a87aa8f9a9a037020179a410e7e9519a20986e28da759c987aa7099279942bf88163aa86a637aaa4fa711e29c48dde970e8dc5a3e4c6ee0bbd5115c36f0b436fef284f73fcbc1444bd730ca95c114ad78e521dcf10f43c92dbb8d3344fae0a10101050c70971a8fa85e348046c1d25f7791d6a8a22a876e2b87ade4647397a20b79ae96982e2d9792b3a4739a664caa521b992eab8aaa72747d985e866725b38a6e83676eb070484a41e1d99601ce5ea91eb796ee4f98128d9812b29c4c1517ede9876de0a8a9e29a69b78be518a5f67a6a2ba71a8798ee7086ed9624211e2ca58374a4fddbe7433d1334439d0dc46928d6da3e4c26d45bf1304b76e4341d463a3f43ad2ebd0703dc995fbb8cd5ba33cc92de4c25045d7144453f153a34cbdb13b49931b539114cd8e4ba3ecd6f1ec4050fcb64e0d3d9544f2d205c94b0c54ae08112d1aa5b7ad22b8919b79aaab9a926017fab067945b7a8edb7672e096a66a87a643220704d479a319e5aaaa63687e6beaadaaba859f0c5b46d9ade61a9a1db9795c9aa6a039247232d0f0f323031816a0e4d475dd4e313d37d0ec48743b0202028d90ba905186619776a49aaaaae9ad9b778e519e274a72ebba85600aa6a3391aa95a8a8c4e4e8c5224d35524cd314451500c576e5569800244c586517e9d8772a6c7811b18aedb8a0a913f56a470421cd8bdb16094e8e6a5e8989a609a72a9f9a140401c27c48d80ec1725f87d21f79da3ba9a1eb9ae1d16eb45999aab1aa2e038762308a6dbe77d9e18db45c989dd4a8e21b879e1b77aa267c572517a2a9776a62992a6479eebaa72294291bcc4f07d01020a4921eefbd27164ec16a57a9222fa711e79725f7a9a27101010d01129c4914760ac16a5378e1cd8752b89a29d8aaae428c46d526c16e5e771e429aade3882617a92e890c8211165192a5a81808080b88d13e24635168b92433774144f8f24c58de47eac482152bf94e338c45e517eea896ee0c78d5e67726467aa5eb69836a85eb6985fc02cd68ad2533bee235714edb6ad53d3cde3b64e684b172e593c0ee4a85c11cab8d82acacd0b439224d1943bd78d0cd5b408252a431055d3225448080c521623b3cbc851b92274c252517ee1988aa93882e419a69ca762f152222f23093b45b99adea99260989aa399a2e24a51a2a3277e9b29769bba9e26d80d891cf96345cacf1423a328a8daa50a10101010aa7e21a95c11da26368a12ec506ffc3a6e53bb535c557448e47eac4881f2d379508cd421a4188c6250b998558080d0a32c5c54d4dcd24588288b509722a3b4fb4823a42e1ecd230b45c97de61a9e21e99de490c8a5aa9a7220e8659f28b971fd387135416fe34653f586444e28e4364e1cc3105d274ad0db44131dbbf324d734fdc21f2b527ea4d8f003e5c7851f2b2ffc0001010189cbc536518a67179aa4a8a25b88862b990e891c18558b5017930bd76d5c17938b6754448a1e47e58a90d03251a65c687a9ea9a25ca8ae66fa0d891c16a22c4842a6d0e9e548a80889288bd8a5538cd825ca3424b730e5b8711bc9ce14c1219113222ae2ba1f2b527e904e7505a42ca96a04a54b91d10a4431a800e5274522f25284a2298021c292a50a10d08f15293f36000121a16a9723a22940403200010101fd5879618aba65b5f2c24f0d443100117911222a0202e2920508e88848d552844483ca250b9291171580808080448ea37245c8a69155a244d374f34e151cbdd503d333ccb24994e01a82ddfaaddf18aae6a77a2a2c1265a8aee8c69da0489eebe77de258854b9151142020202023a4a3908b17a22c042837ee1b4995f442af23c72e25855059305283287aa1ebe188b203b773333b74f4b8504dcfee0b4f234a325d415134d7d413c7edf4d221910b4225f28cd421d4c854ab182155e13822231509c9ec221a211d15516edf976e22ca715eeaa9297772112252b7889c10982e4528f893825e7eacfc9ca0971fb25389284772544f312453541cb90e553d1686283b30fd3e3545bd93fb3a8f0ccda128604a72db4412f4ce0d34cd6f535721d2293f565ef851b11099340001a958884c2320a0a32e459c48e58a502a44298ee2a7aee6169ea2e9a9ea2844724648476010e5376eebaa9aa779a6ab79a229488a5f4af43c5194dccc753445f32457ce08e9c8ebbc94eb36a2a6298ea6f86deada09a10a85dc8f15293f46e6507794160d21a95c44237308fdaa2095eb26ae67ca71aa6772646a8a484747a56aa2e4ba9de2ca81a4ba72df96a2a2f3a372458805a3721dbf0d54c3d124d35414577148e4843a21754b172f484258bc9c6a0a762510a528929d979ea7688a1dc98de290c81521116511fa422f42ea9191d9e5e3be2e2549aaa2488a67a79aa3f791e2d8715cbc10794245a5c98d2a08925b2a82a908221d657981242a41744c3d54ddb63025c931dcd42d5dbc58d948e0527e9d48aa9ea86e1b8882640822a16a1721d42da5f78527d9912adaa960f7719e96522449905bc7f41b3b70e440ef871214538e23bf2f14cf73fcbc354b9672153ff25cd1d34b3b8e53475145ea62a629a4a60c40406348e58a1096a17215b951354593fb4e6f43c17148e4c02a1c7764a48e485cd612b094a1b9792989a69fd875a7b9824322c7a5c868258f904623a423cf5b4b7423d56d33bbf353371335cd219113dabc14d492fbb6d11341f45443b1f3d66f48e484c0a45db7658b8a7e645a7a64f771a94a86ebd6ad247822798121a472456807b4443b74e54eaf23c971db40530502dab24545b790ca15a11cce120c5530543d7555c30e44cf6fdbc1f43aa0524c371235bb2dec3af2ec56d2f4a11c5571f55675e3528f13cd30fcb122e5e7c7ca0b3f4546ea15a2222a40404546ea1044454440405cbc108922952b423f089521498a20f98129b76eebd89120952b4238f4508e9c487a1d7a865eca85dbd77d1f0fa56aa6dd99a6e8489e63a76e5c141a7ea4ec50a2220a7a1c97821d8aaea6fa9124e8506ee6c891278aa2a9189aa2f80d895c6a76f180ae04940ca8f4edef94402009410cc60000035074ce981999b301c31340502020140f88a43289a4473b3e148009327ea28626362389c210419003310c82200681200618438c31c628a418546600d0351d347048af7265740980022dbe7b53505a6db898b2c90867ac693de346640f80ce160c16bdf46cce72f4ab026223a5694ffb5587c29bd926eb1975632e2eac9c29b00020799cd5a3daca41604b6330011fca0150cc003ce58707a2a6b88a6eedf238039323fc8856c310d8a2397c22a53681fbc5527861289217c094a7afb223485748bc1781fe8569475bae391a43fa1deaa0c6c82adc5ae8f442dac8b11b4c0516c8217be50a5c1b483b224fc91cdde77bd0092a591ecdcf704bb26a77a594ea404f421c87bed74f1e1c54a12a46ac5da733b2a74a2c8204639b5f49c9d57bd181e6f0147f540ac442b5e07a9403f495d551c251313c05d90de741f853af41671f3be868d94ad9d015b5213226efc6f95e2c1269531674c0a5b5bac0616d7a670bf610c3a771be5587de7e1e4870b932edf53fc35c54c06e6abeeecefe57fe41dc118c9d12759cdc92c605812405f7c8495c5cdd8ce56080f2928975055e30d0857c0d279c50c2adc29850f11b70b256467b3ddee394720cc7682f4f0fe4644714aacc680fc8d354d00785e17df1bc8bc8f9d2bda088e9ef3a3940a243c28b02480858324756c61eb243176a269cb676af206575e2e4a3290ceefde8fe77930ff81f347e27721dbeb4e62b9260ecd9c941cc327ac0107833f8137f039c085741729edc00d8189d8f57360cc00000fc6d805ff17c1c1487f0dd02532018ea0d5195f02cb141dff614f6b1d111a0084a2b2bb4660dc4c0aa8f54331f24976f98722bab5856711b48e8612c5c254e121b8616f5fd1bb4ae6869a29c685dd6ffb804e02e6ae4c39a90472990bb573b23ac564b340bf5970459249d9513deb4e4e21a2231bc1b696045c7cdf2ce842060d23574a275b0d0456707f41515679021f7c74e9db38b148f16107ee73c19aad19d57430461fa676229bb2eae645dac0fd99674daf8eb6d8f85b5984eb718e0eb0e8967b7f104b54b8b1adebaf49596d4e01050228570449ceeeb21d4d76933c48943bf3b9c06426e356074a575d2920ee0e382a22c221d5e93cee57819099e12520717815e30577068f8533a1769c859e0b3fa0cba8e8292fad1eae7972577e8f74275992f820e2b37f14b0cfbc0a35e62f36b43d037a60d9249c9d114e182b052574aed9dce905278335593b32b3c7101a84dde773d66b870333fc18cc22303f975063ff228dc3bf76bdd9e08d0440419cfca73962bcb52b509ee5c1acdce1ea31dde2ec7b47346716cd14b9928038c849031f47e609cc5bb4234daefc55afd603d9227a456c4523096968425e808a6f8ac50b6279823a2fd5b3e70a5e102f9c8cb573ec3e203bde5de33ac5b0784afb01eefdb02f71c7d8a96b17d1bda61d99caf1bbd2e68c62ef333ca15995b6ea9b29c576ea58c651bf22f86e0551c68fca43b16c6cd8e215e34c3c3eba9856a0e07bf8d290012ed78c36f1a10a6f1c65cc00be31008e3b6aad145071397d4a017f3475b312c647131dc1b39090ee756fec06a903991b945930a9d69c3ed228597d0ef6d6acf981cdcfb33fbaae321a6d06fc3e2d53632f4c4156a026876a6ff10d849318cdc90edac3d5c906b01e994dd6190fa8ac257a2d69d13e33b40ec698cf6bc98322e3fc0b9ed4225eb701ceed684a5a2adca01370bca5649c40ec98de0fe1db6548a3c3632e7f103a96200301b0b05f80e37d524bdae5b88978d2827fe29469a01262eca2401ffa0443607383e30f04e2739d0bfd0ee574cee8f6ac9df3b13431153fd176459069cb4565fd6f2f339aa52ed68b2c1a08378abba594a486bace575b006de299c209547d690ca4200ed68da626b1c071a1d1bb9f0341f3dc24edadbfb04befc0d1fca1aaeca951a25caa205ed7cde8209907d74a8e4354a52de50c3bac15c519d4e4eface24a9661d44ec1931da103eab47ea5423c4471286aa050bf13bcce49b41b2a616f4c5f5b10582249c2ad0a51e50e0e18c150969faaf8f1c59e61b7d3e96a1839efd3e73bf00494f2bba304b28a12420bbdca3ee222b747d99f0d5bbc95f275b5d63895bd2d7b8777045c2c80075b994d35aea3f6d92292df5ceb6ba055381017e298c10f384105e595ee8a93a1e4c374b05e9e8a247efd2b45a3ee3c5aebcb4524715c851c5af83c7bc32a696e758484a030d315c1fdc775fb797bb26dd0e8c21231597c0cb7e8098943cd8e2ec231b4c74404acbe43abb3fa5b6ee94703195e7d994247ef9403ec96f088a510523a27a002547bfbdd8e5b8f21194699c322476c8ff250d4ceda120413f2cdaccb14237d386a493e9f4faa933b609e08e968cac8a36932cf0c55951beb5c8b80345e9c49c39a07d48b24791e17ec5f5c776e6a66d3d90c91029af158fae1694b7217286439abc0dc375971ff80cc1df399635403f73ce82233a74e472354093ee13f387872207116eac1b4662d67220a67016a219805092524be8251fac0dde99f5d637f5501da2ed2ba59571a007a7b3e3b9c0c6490a92c4a40cdaf97b226f60952e0988d641d0dde5e9f2d42ee06328173394eadf6f7afa845875fddc8f495373acc3e57f9a5c46f1ac549b70f031721882d4b846a03a0a519e0dddceb3f5f16f507c1ea5a75a7f3fbaa944c7ff19660d346e1dffb2a7d0524e02ab7dceeb8f25168ebb54a5800564a0b0ab82be2cf9f0c65110d04c61d30c628d6b421f809d5bcbcd1e9424b5cc21ab30e489dd885b07119f2fa0f40defe155eb2b002068b48ced2c40b5b7793eba6596c84990c756511e283784597325e332cd1cd91a48495c67805ea01baddff6a240ad4966e62e79c5d8eb166c00351962898a73c325c9c69e9fbe8080a670429fcba250a67c9c085a770194f024bcd92154092db295772c6b59988b37268bfd49624793002e442c47cc04509933d49985a382183e3e8ea098eb407a647b3d8a2a2792aae192b11c29c57032ce0a8d4a28041b007decc0e08db19989851b06fc0b8b804946042955a9088ef85be5c523ccb20eb8da9c76b0d7c93b0cd5f927e3cdc2cb1d1e4c5d7e100770a466303dc9e743940bd3fee46b8ac02b518e269ad55754b91d0d8781e45fd6a5b6cafc68d412858621b34e03d28f7e5ad7fd92fb72d53a45bfbb3ade309c6c442131e1825783d6a4100437a12308ea9724b2c4ec6c78f34175ddd438487da3db2b514d9910952e0b7d29c484b2e536eaf7583afc4e676b2a26ca85cdef6e7dc188a7fdd0661fa77110d2463799f2af0b9bce3961bf1187e3ec68336dd340e37f039d7f8acd4c67d7c49ece6045e979dc9e42214e2841b8a0efa4327d1d9e37c7033fcce2e472f52a793a1f87f842207d2148b0a67574f39e1c932e663386aa93ea56ef9f1a64affb6f4b0bf8c295c34cf3d3a5b5d555ef6dd0438319652c71ffda573304dfa5fefc8cc0ee1acb0c0e8ac5d55c061f4020b5f814d4f659217b20613629bf8bca79cb200e78228d3b5906647e92b36b6c36648811230858df148449a6c9693a4aaef18945980cea75e7148fd7fddcef1855616752a35ed56ad64b14d9c67063a7c94077fbc304bddfb2020439190266b698e29f4b24f281c7fba950aa730a079dc89f08dc9e5b80f690479b5872e6fdd11d3d832f18d11ef6c3030ca533dd92b1559da2a15b48a64900656be3572b0d96f087b45fc73ba3a3695d66609b28ea00b7d1b48f567841cb63090520c371ff000c5a4678fd27a9b083f7e0e1b39ce20a9fc7f2ac0a723e495484085d98d5f42e06033d41887738652bc8d846927c28cbf890051943e060fd8f357b23f9b7fbe484030e0a18ea53dba96a5ab83f0c4761b70fbb5147e1254bf61c804c7bc15fcfbe7c0c7abac274950c9217ded8d1f09e6c40e0910fd5d41ec8ccfb367effde77e45bd2b28b6918d4371840114c06bf33b302c8049123e953ea461537ed750eb9457ac14126a9d6814fa13c4427f2ff457273f38f72161fe3c860276ab84e58ea09ebb4b81451228660282dcc0cf97c3715cefa55e34160d35eda1651e2c5dee41df5e28312cdd1940f28bfc12bf1ea2d40b1479005a4c90f2630eec877391124e706f73d937ed855f355bd7fc3b1005564fa1cc3ad31bd13244a727d1b8d7e789e869dabbe9cba37f96f3b8bb01c86f7fd0a28d2df6cae65fee841c42cb0e3a63ffe6df8cddff84891b0af76c7e855c2f2a2320132a7340b6ec2580835c08b24cbc96f47ab44b10fffc020b811e82cd4b98d1f4583508f1162f68280d668188fad9399f44554a284b895b446d34046700fd7acc564932a4a2db2492af26a4b16037b6f12280f54811c94109c799564ccdb17a5d477a7528d22794bd31a10c21f45ca407ba00de8acb1b7b0a420c5a9da1c4b7f26bd4594dc421a4314fde56bf7a5d45f3d8719371a47f1b3f21a483650c567df12c2b78a90bcc263e3660ca58198fcc65326fb6a98d4f9f7f9974ddf89425d82db88f26d8427fc1fb86464b6b1fcd0f6246420cb152f774bcac9a9eae42ed12aa95e3bf68174048c743e35daf0895906f585cfa351df5924d6cd29282bf6f3fd5569b3a4b8a9d3e630888171f6ebbdc46e6d8590fc8e7e2b05024871ca24cbb335c20a4beda11a39628ef3965558c94d723597d22a0dd8e77d5278bb24f8a66f56ae8a834e8135bb8d31e4cb64a9594689fa6122be3aff6a56e83fb3bdca2e6c532b0c6963b129b336f1ed9d0c43f867f7c682409c970b33b3b1f9e8a160ecdb796b319eb32329c86f18827d7b4e3142d3c2504a4bc7e22e4512fb33a8613d39cd75d70326f155340957c059b3ee323d96e78901f02c874c6ff70b1ed9f92e439780e930c6323241de4cb092fc95d64b8d82484b53603dcc1d8a4e04a64d93c144ab7683341845024dcc83538996ef2af076d7c7fb15c661697d436694d7cfb4c40392a9622ba0efcf49afaa682f018f5afdc6818eed63b870ade3d3801587f319f1a7bc778aac4f08855de6e2eb4216b64b1338080d541c4e6b9493c121a40c3977b91f968d197501c3d4b897eb85ec998962ab02c009a6fa613154a8a3b9350673918c0fea1364e59767b20607d9e716e4f74fda84914a7e023481aa8f8cebfec2328f2cad198ddb8461262ce724a3d9851b61524d2d77a015facc1e66c5884af21480ba83828d3359692155165f9b1816d5aafb0ea5dd2e4923433a89eb39f07a9ff18e96ce36238453011709eac688791814e0a80938dc3af443ff8e5c8ab5cb73dbdc200781d7a069089235cd589fdedf839d6134e85268e523f718b8b842f387825ff5955457f0f8ff5aa7c50e88892dbe2e1ddef11bb79eea89d5af3d534dbd5242ac6877aa5d7b7e689b9a2226ae86c78792b4ed362de7a1e0674767734080f09f66edab87bb4a284a54ed7184acdd72875d0513df2ec5d607e751e4f7b4d6d0f951dc6beacd1ff28328ca33f38f5ca2fc07c0a77344a36c4a5ae9cece73f7f0c5d0912d40f27345c6dafb2c0f4ad062932a85422927db64b1c1af8604f95e42c1b8daad6a1dc66242aa195f978ef0e6e110caea9d107dbad89e4e75a76f9082d2bdd497f2d148d5898e6ac9dc7fb41cdd7df1ed1351dd3c8e05db4a3517b2d5ccd924db31a3317012493db9fa40866b29206a5e49d9ad99027a499bb1e58c287835c606e58e0922d59a7f8887e0a629286f391dc492968917a437cc45ce055f5dabd1e9a5bd9bf3bc01d08106b3195fb6a2827d292a114911b67390d375bb01bb8c9e9f8e0cc172777f3739f9fc28b0fe7054a02162a6bb00ce5992d79ea2c372e2d615a8061a37b5b3972390b071bd277dcd35f9756cc52847f72340fcc2c20be717d256e4f263607b5e471fce7233d99316f5ca5f21ed0f3a51517be4dd348b8fae5d22da8280d26a89dda9dd2fc44e1b16eb49a4e9dd0833a9d29c3f32368f856e7c2572b3760eb69b27481e74a01392804bef98821273ade2cdf370105268b82b68bb279889eb83367abb62edf7b7b2cb896970bef7b6131159c6a5b89b4a4e39d7f64113a9b71a84cf36010f0c5c46351acf7325015ac807098aa7f78086060f292cbb3ea31932b94238f23da00862847619f7533d42d53451d53cfa1d7a7c216bf0525b9423dce082235aa84eccd33df0b34b0f6a1326e0e4af1b5f69fd72d26b93b296d62adbcda39a103a63375b666ef20a5804247f1b0c0929c9bbe47f6da6e4fa3804125270e391a7f013c35d4e0ae964463c22585708c759ff7025953fdfa5252c855c4f627ac9c247894dba0e0b7c74ac1e15502d28ee5662c24bc3d4dd012a991be1a67ea471b805b44c8675a241628e8cc57880dc9ac30821f06458b873b526623fb5bfa965d6ecb6ae16192ff64495d577222aeeedb0a38c3290028c4f4f9cf91b49f1cbe140bb6d42a82e16f762daf0fa4becb7a00098e7a0de3d9673fadcca2bbf0eb2c009fd4334b97894abc63df91de9e3453e0f7f2ac69dd428e235e022d6dbf340e3533e94a40f507540e6e310edf01c91caad88098752eb15267ed468655dd6d34b6e26f30e56728938331f2a5ff2174e36cbcf4d449668dcbe4fd9d54fd2776f98df2b13fec9e11e255cb3866b223ed0e9e2be11d1f9cd5cd13c9d5f2680043e96e11801f0783838cb462374c88e2255815bccf9946d0028cdc5b4e3c52c17286ea230bbe894d089f1022bf7774926d22a208d110cf5adba993eb9afbe82170b25747db09acf738a963510e88c8b00f46af48f353838c66a362835d3457fa496c823060b4f6fe64f8d6c803c87f1e270be475c06d88e02af94491f6667d450a102f3aa4e1b047ab0893f2f52caaa711aaa8c91a98e82a9b531a1868cda627e9e0fca1724c73bc645efc23668fb2653036a151aa9f0371230a119fe0d9bbc6f61c9ccd0a3acc08d288e3eb1106a499b678dc3f4be7d60d286b37da86bf6d2af3f75fc2f2fd4fb3cd20154aba1300886144848a3ec3fec0f51d02fa1ff3e31750c59f07491125e1642bf318844f201ac22879a19b2ed538884fefca3f86491e16df958d3ef3f0fd00ed35fb0b7f75e22207bc7ed20bd0bb72a88b2424a2f8c5eb1dd2230ad2a5cef5b6a69a44c280b4c347b8f92811d20fe0a42ccc2e5a92ee00b0b5f10bbc49b0ba9f280dc5bdadd863c72e7ff85d887e0dab346f2dc4035f0b1b971289bcca5833cca5506680226216a6d63019cc4dd14c33cf8bf37b02115a6e620469dddfda2c119ee44329cb06641efbc14482cebdf22e5043391465b933b6118680a1a9784dd25e5033fce98fffa42129320eb5eceb75d62b483152736009b46902f1cb2533e69c260447900052b66dd102c1c397ca70402c7263c0e1c4597eeec864af4ad614c1f41b37436d83986e026a748ccf122e88c7353e76ec805061ca8624b781ee97fe7a0c40f1454c84ff893bb2bf363d0baf6d083bfcb30a007a65f19aad06a9b30751af8243173cd53dc6f9c2cc058ed29c33906e0cfa468496dba9be87dbfa56619ae24f48abaa3088a399d7d60a9bfcea6f7862c8f5a9d6d02c03f58a4b52f5355e34bb35a83c57657d9ca504a501ec036f393df41d68d9a33ad7acf2f40df285cd0094abf907e7ec6ae2b23cfaca5cb44322cfdff77d49c74fe75056fc164dcf01c1cb0b8dd97e0565f03e209c8639120dea542225ad43aba4b18dd9f929038af91c02a78b89b1000826987e837ec1ba6256619deade8b5fbb1da2baa78eb8fdcb43414e03f6e6e191f00b6172fce9bb64815f3c65115b5faec49dd49e07e960fdce6b9448fd7b294bd4e7eb1cdb841c82e493e8a81f57fc3e592b30b2fa8b0df3030f9cc7348f594c2de094764f52972a4ad672ba8e9ffef398ebf6917591cb020a62971e368c04490c894b78e7f24ec71fd43f4042386bf1f34266d8bac678923948937d947ad111f10bd5f009fe6055d7c16ebf50bfed207e8837c9d114eb0c50e09699cd4779d24f5564e92d2fe254db625191266b052affde1ab9404eef817d345e25277ec830753c720425fb54ff45eb56ddb3bcbb6635d0c128d4b3c8690c917f41dc1ddc6f21a862bcf186b7ccf543ab5a92d2978506d8c40909a6a2cccf2ac65508df4f86e3a3340007fa1217193e26f7b84b3cb14dce83c13b53c707df793560176242069cbbe01743dcbcf9001c4a67bd6b50e2f14a703b910857159e1689ed0d4dedb73efcc7c47aa01f710a1e5c4772239ff9bd255c5fd1c1a15d05bc8c935f2f0facad29acc00c3ef961aebc9e06a2a657b4fdd436bfffb26b0783bf5c1948f678de06df0bab717e9361e562b092ef2d5431f6e88f983c89b0e0e836fe1a3ba1ed8b8b497632bd49b5cbe26b4a3b9a9d429d379cc8a31add1d24d901fecbc0b4e77afcdd0d344aeaeff0384356af7e84c91f0f0d70b43d38d8059de88f3e5feac81f854b0f25d469c11a7df71e26071b464771494114c6ac2f1d82054a45b3386847fc0da9bb8d81235b22d3ec1203efac68d76326b91fc45bdf589fa4bf4eb88e828060ef9dd40883bbf7e5b6e634854db2a7498a55bd81dd381a1669a95b6b96ffa2977396e7aa12624cc142927e1001a7b98478528071b5cf362aac608cd6ce7155cd0d5ab48775c1eb7bcbd9d7749332edb3c72214d2cce20ab4225bd2c9f72b383fa91d3f2af394b5e7f10b89ce327f66e005ba3d1d0576e288122a14f0eb59b524afaf39738afaec936b93fedd863c338fc3d0a5aa31bf0933c87972b701111383ab16f95b9550a38bdd998952b0b00a64cc0518d6030b7a94c572b50e22085f9d4c998e3270f2d4d31d1474186272cef3167e8dde81e34f70423f6dc0d1d1e5d9b81af972f01e1fc4d42a3791b297409975e05351a9a897c61bfbcc26654176df2785bfd8ab79f58c64e4ee1c4978f82acc228ec4c14252994b35035dfd93eee97480aaf1ef9f8e66772a6f4eed5af2a92232b6da04b040a93e90ba8d1486d76ff43500b3fa2a6f67cdae7fb0228b978f84c3d1d6380cf7d840cb8cde0e7af9b417780efa63d00496fe837f4920a30355e62f52434520636034a4ff081ee6aa538081f2c1860a611d43d0c06349cf08aaedf2d81a43c3945ecbf003468343a91b40bd4a6c44fca95a66ea253c5e0ae2bcf187c2ac5f5d650f9a8c64bbd0c77c2e915b4f1dc4711afb9c69bc63757bd1e3958196099cc355887178d10fbda9ec7f02be66c5434f01e5f6bbd1cd786767ceb5053d83c6861bcae6274f3ca1d68a4c2af466193d97a5d5f3c85ebcc12125ff041b699a856c715adb512fff7e06b79433282a623aafa9325c9093490f8d5287882311df180a50194e30b6f2031f7153eb3065346e1db19cb70345021e415cb60a48bf44cc68d00d6afd765987395d83571ae4bbb88f701bce2380515ca181c5f8b166145067a6a30957a3c6fe063928f13ef6e2b2c485bd910fad1bb915bea8be7227d69d28d57298618d98680c5225d6fcb5360f8ec376f67688e79eb9ebb2fe1d413ee7270a3408fde6b472f04302d68703c26f7e15f42693e2684733d3af957e94f71cf91eeac90a9ed44f7dde2eb16249b5e0f6fe0087c9aadbbf627e835f5b87d4aeafa72e68851749a7feca03bc1d6dbfe1e7eec1b1b13deaceb1f643348cca099326e7d919625fa4892a01ce270599247b1398c7cdf2669ea3516fe8cefe9545f1a33ae833cc3f4ec256db50c45a45f50660d9725d195529e21a55a6f061f49a9eb2e35740099a1df75757a312100fd69bffe3a0082af1fa271e157ae822dad3a51983632369d63ffd7472d754edd74f5c2f4c5062e8c992183450334baf131cd928f3a247e70c6399eeb823a3813d424faf67523af29a764f60a59ae1bc522a34447ca71d1392522a6cf36ffbdb90f56a3b4051cf1d5c7f3992cbdd2bdbea7a8661954e72a8ffb6648d482a18b5824dbdb359decb58df5c579e5a0d03f73e4166365c7821d721d12b27f6f80929140d8c3fabccb0fd77de5d9d6b4cfffc000df19e76b168c184765abb48847464076dc8c4d52a19063830a0b27e27cf2d630c0ee194e7c17e6c0f0d555aa9cbe49096be8f141e239b706debd0033a265e9d8710e456538948d09956e6dc1a472bedb8dca15ab61e66335118250cec5796ad93ea5c7b32ab3ca403d67d25f49d366469ed328879296e9fe1a411207b2d160ef47218ff81ad554dcf03ca900e049ebd297c1479264484461931c0c8fef1e2cb9674bcbd2593a6b5c646a84f43f897286e250139550d839b4367d31ef1e7332dc1813070290d7544f5341852e0a6a87141746fe8730859f373d64143993a1d33a79ecdfaa7c1a94610fa5a968cde73758298154697333eec86a1cec9e626fcc14ebfcfe8a2457737d623ce4b89389a21d6dde26537e3285791fba518ab54ab45d5376500b32d6cb7f089846ae23719c59f89b7f92c747671ddf2d57215c9055de4cb4eef0811290be08a439e17c51b4059fda18d626256c39cce2e2d65677fb3fe33cfc229b44a39617d2e992c3098e65074f24458c2cc73f4ca4a45609033dafdea263f84cd323b6fc988b0418ab3ccefa4cc9d7f2c7bc117935e4585d34365c45afd247084372c28598f0a3df8437bab18a88dba94a7c5198791a9f040b2fdd2dd5558ee31a45c2373033683a0e2a27b53dcef8958f089a1c40794b423bff96b0d7a68001ba412d2d0681a744509e0bd851f7777a0fc59aedb6890b84ec02f2e3db040cbcb108ee7dfb74b0fbbf6831c436a8385b051b5e5bb6f0b27fbc85a0b56b610f8f23a23331236126f280080e3c9fcd5979708d31c5b47d0e0e9efd1abc2681a718c0fadd765252485b4773748078251014dcc2565cfbd70e1dd8261b9b70eb51b1a0d283b0d6153243573b974044c97d7172f4cd7b3f982ac560795e5a77262e39d937132e7241fc7e12ff4dc9f789cf746d6ff22dd0808cb6bfddadd63f78f0f667b9006129cd185d0cb7682cc6277ce51c29d3f8775eb0d77e36d5f002edd352ef0a031772ea4d12d8c6a1b6afe29fd177f4dea51c72fb2636effe37625cf2e5283cebfc0320efef9ff038735bc2beb5cf9a6a684ba557c3b7e23bd07735f32a6a25082fb4dc81cc1b13987e904ec397bdfd86e625c1824ac655c8f4ed6b83f58c26ad006e99bc48e92754fef5f682e40d107774ecd36e2ded20f307e4a7e7731608c0c0ee0f2ac412b673af6512a19bdbace86545f297ac37e813847ce64ddb5207b5517cf0714bda73f9ccdf6089935c811b779e29547786e6d7a0c0f036f90d9c6add9b77ea2fd72df72dbb9aeeb0731c1feed348f0e17122e8e69b3d7e0b9bc9f2aeda3b4684f4c49f5a5eefd60a98d3ee0976fa669ba27e711c3b1aaa08331f8bcded1d9fb6c51b3b3ccfe5b666dbf1d70f5ee94ded4e227e2ab3ad333e63e557f757dabd589e8b0c6d25de2e11bb669a992a47066303fb2ed5ddf8c7162458087633fb20dde4ee9702770398e95e6f080a1b485794c83cdabb2e84f873e4adb69a6eab334c318c46a6fd3352f4d416c569aada566907c73a8b847ab50a45d2117ce28c82b923c429105585ab22961c6dea61dbc22af5c40fb1f0d64b159d79c95b7ea477b2e07bb65636d3efb1cf4b3771df7be3b8521273650663dd602760d400c87ed3cbfbde5f5f76f2f908103790b8fd14207d4701250dca78dfab091a74623735b70b95e3f696f5d9c7563b015c6de19c29df80744a8fb3d00aa80e5b039fb4daca60b75e446fe78381876231cb720af3b5d07c5379dc5deb790b1899bb3a98b5cee51e1a98ba38ca58eaf814b85742d8bdce0b6c72cb9aa5c7d6fabf30641b8b201ca7433f0758cfd170cf826edb4c616b96efdaf9cc9725a4732e020f3cba07b5b42ecf02333f9c5fe9ff50b612cf17b69985fb25056f8536bfa227f2a2b49df355b2661b874e954f32c669275fd74c98dee866c73f29c87b5f3c2aa2b7794b9c9b3ff3e93f30dae707d95d7f4089ee26b8a3e589bcd1d3848f70130c4cf0ca7e2672c2fc84e5bb35c1d9bc3e91393deb6385f78297edf3faf7cded8f397fc2dfe91b4ffeb19cc8bcbfe74b8c36adf6b3c2a85ad256fb7e3f30eab74ab2ade91d81b3c22df08149fc5e5cd96983e63c7e687102907ad4601aaf7982a7e7a8f5d738bf4c5da71b7c12e31f0e575d6cfcea10bb87a19d8018da61a7830541b7f616b4e7bef2e1c81b26a6fc0b7a1054eb1abd2bfd0672457190ff740ff9ea4406fd6738fe259a3cecb4cd2fdc818167d2ebf196d2c0347a7dd8b2cdd0ac7335b35e0cda4859c0424a7ac687992ed387df14f9d4c0ba9f281db5d3b422b6c613645e76f97b974d2fb9a284d4be6c94fa63d0c8dde717d5041964bb7c0f268b17403a4ef206027bf6f2c7d009c76be27c7a0fb7eda3c05d8bc4eb42567a31c17f40586bedc90b8b71d0bcec7d0af90a3b1e19355bb42da50ce9d0a9cb25bee8d36cbae95f4ecce5810cf35177631e33f3d99335f739e8ddb30c272bf01e4e3de0e93ed0287b0976e6c49913cf9c3761fac4a973a7ce9dba55a67622aa57ac59b7703c1df119229eb69ff13dff179f48d3d013df82fa88ff981f44f27aa2d38d8e272547c6c8c853be48cf2573fb78d7e3d0c9fdb5c2fd9fbccccf985bf3ca447d116fc44cd99dfc7231cfb6cddafe6ce0773696cd212477ff0cd9abd494c7739574bb9db15a1e45ffe8c9f6335e8befc7f60607f812e109c4fe722f2f05d2446c7f50e9f53b32bdc79f05fd671fd6fbea3a9b733fd56451f8673f3826cf6b7687458bdee3276e8f8c557d6e8f983db5ceb161c5775b54f95b2ff1bf3ca1b35d0df7f7905f5e60ee624a7d17f5aa6da4defd56ff2dd9b5729a269678ce88993555b382f6401c76f46c3bb2fe36e073f29615291c9b3490e8ab18e7255c6c60e66a48407018193f81f18f8bbd49789a1e7b1eedcdf8f54f0a56bf2bc7fc4e0fb65eeced8bf2b0b29c5fe2549b415a1feb342950a847cffec9dd70a28007065f0f9f22ba189174c5d712b4c3cfa35760f81296453e70cb12ab75af7daddbbee0f82ce130f6b290ff9561aace7fedc013f854ae55bd3b92ff2ab44d993c54f5945833130bd39fde2af9364da7e5483f77f4449ae05f705ce3bd8397fa0614f78e777865d4cc065e071431d30cedc7e4450a0a5f0e6fb62c1e1c15e16b6ad789e7e34cbeea0972657cd23b1b117d17eb5e09a823d7021ea3d0df335b1f557e517dbcb083a712d5d91a231faa42ea287d194f451565fe322bb880d738fe2a35c18439ca1ccff5b2a5c2df7cf5006aec8685553326dd035c15bc3188dd519aff783e8fc88c50c42f79be4f91c22f219594e01a4bdb33d9f59ab5cb1c3edce8dca388fb67a4f541d67ab688acf7324cd01ed7dfb883db5890f26ce4796ae246ec8f9b32e0d03926fa9871b5b4ee1e5f9a1669b3b551732324a323726106750c8f5b6f137ccaf654afe906f246d3733989e7f76f3f38bb5db8e0ada73edbdcd2102fab8c6af3fd662ae08940df371d1e41db039cdd0dfab7f178bf7c813b7785f7c25fad353808756eb25ba89dd2f22aff74d62d2e76b6363303988f098dd99bc1e2c164262c5671b4a5e9a2ce0644fab1612f49dae6b7ffe5b43cae7e703d8cb667452cd379551c6d69081d3ac5c07f3cf361c2e6df9bd63775da2fbdc2449f6b27d7b535d3e4635cbb22cde263cebb0ea3b56fd146f96adecb3ef0da241ca735e4086fd0203c909eee011d3993ed9af56af49f6eb24b4a6cd970cb462dda376cdab069dbb4fee1b740298e17fb4e8cd457c66879030cd159398669cd8f83b895d21cfb9ce1d95f9b1fd5073085d10e6106da7f29fad93dc92874e3e7eebac4ac8595ae4a38b8b62cddfcf3250f7b22f4adb6a6ae6ce625f0fdbfabf970054e8370d7c4213bf1fdbd77cfd4015d49f3d08bfaed3bcbedcfe335c59e45b75fc7cd507fd0cb4ffe0db10ada45b7feecb3239cb9b2bdb927cf5cd06ae4e3a898f4efa7f458e949f3f242b887ec1a92cbc45b2dc6b677f23d6cdbe929dc350c8ee33ef4536139b8e1c1f228fc5bebb6db819d1e2f0e1120fa87eb7601ed4fef715e7a86b65ec60b09ec593cfbcc363ff73791fa8b5fc569e21eb9487d63313b8579f27a23e20e4a42f7c33e4f3c0c50770f47b2dad13916f03a5f1be51cc0ed8d185d1462ac759fd6d28679678487fa172ce58d8ef28d794473ee246ff0d04e5d999ca52d04770a8f3f8fb33f80e64cf9547d9c04b4779a6038a607d9cb10e978a269c652c160ed356d0b86711e36375669f3ea82b468fbeedf9db7c38c7b5f296edd947343c73fa138fef4ef48e227f0d6e55909bf3b1d16d9a00f679de161e8a16fe4cdd47433bfcd7ea31326776e2cf09f31bbd8017a66dcc271b729e55657f7f08f3e491ba8738157f6bd864f0577c60684bbe6cd3f1dfc2bfb543ae8e308f2c992e3189d1be275516a3746f646f47f7ccac3cb673707530fed1991e0688b4bcbb806cf1357babe8e131ff6812ce439f699a87909be67156b3065609248f644415b98fd2ab07532a7c02ec23fec9a57fa297e88b8b310d439188f9c7f82f5953cc7c1ee874196e80eab5c4b3da3fe1b1268e1d6b87c64cbdd7544d7eb7682fd3ba4b3e6c2930610fcc28fa59ee9ddf51e709c8a0d0e376da4f3d74f864bead734cd9093de3343838e622bc3b95a1c589eb1ef2c3b8c6f2863c731059e2fe56999c8509e73c0c2968df5110566e29ff08d1dba8be9037137c8769e0d7fb685da8e12ab8f314b41ee0da682155df356703bc682716f41f7bb20a174129dff3188efbd6c77dd21123fa3a4ef7068cfc9ee9e7724cf922061c6983907874e970d60fa42871bd7c78b51f78ee2829f0ec484234fcd75ab65c9295f40f20654f20704d66745f78054ed07755f3cfec690ff1c5d1eed349ebfbf249c7d0ce4dc354de8f5c1dd92fb282a7d9c2d0e7564187997d04de89f6f47f19e06ba0aff15ee2cfc5bd0bb90fe021c067d0c7919f633280fd6e6b0972793395bf903af4ec31269f968c885d5717a5cbf3ac141ecb655eef377f2348fbbfb40f8ea0b520dd223b4e38cb87594621eadcda8a63b74af2888354a8bd08e33e2b6a394f2603da31aefd839f635e46029778707e061655aa95dae9c4bb514345088f001860c1b3460d0b035389617e87526d679444cba4b318b466657d315ea942037799c5ab7a8ef46f6ac17a17de690c86a284f3de91d3760a339dc900e06fb359ad7338d5cacf84f4c6df061ca1ffdd466421f9c2df6540b180cdc7ad635539ccdca0ca0f22a9bd1b20d5994b6565f25f47b4f05d02b2a9bc518994d6765a12c348f2477132a79ae9f79ab1efa0096960d807d89122fae382c62687f8b0ea9c9826ebdd1ef9f569870a0a30f361a559ee0faf9ec112fe58d869ad19a5bce9b2f9291b59e28c2ad16634b9b80d8c8dccdd99c751ef7c8d8ccc549c6afaece59fd5edf56b2519f7cee41b14393568649ccfb53726f92e6aac1ea782de58563f77f46aefab062b3aa8b564f50791042ba88c47672f3ef2069d4166a89db7aa3a9a12938d556bea60132fb0f64fc0d9a7b1b8f770bc94902e3ad7efd713e57be24d9c7ffd7ec3ae94768a9efd8633c301fee14327aea10877d8f437de36625dada0db4c369cca3c7f4f772149f9eefd1d149ab1d23cca3ece25b4ed2880f02eb5b21069f320e3dff32ff0dc335e2fd6ad7ddbee0c41fe07da436632277c794f0c0f0d4d914bd6ed40d74e774ff080bfb73b8631f67081d9c53299bd3cdf475e0a6e738e6bda684d1a2f67c1787b1a3327233e3491e9d1ad513da067834cb6d4d01f96dc4601fa9f792cd0b37e7b9e60da4ba67fcbd798307407ece950e5ac262c734f60671b898a749bd068edefa26e8a984bfd4b770e82aad1c16bc3a125f3d86948c9ea236e832be5dbdaa70f4d3f914fef773b13fb2ff5d184795d591dd9e1c4e207af7a8add6544341fad4300a5f0d11e962c38fff61c36fe7b2e1dfd1e5dc9f750364f3e6486de178977313564e4f78e1eb45030d091dbb99b81fbd89de11c0f31ef02fe6067d9653566f7fe1ad97f16b7e17a72121f4532b8bcd5e9eedbb4fc6f31e34aee558c5b16fdd343f980bebda0096d20530fe36927ecd39d77436e8253a8d4199905b32876f2b5a929b9ba0d7732b74d2c791271eb47e8bded1d5f83617fe61f95ff8a0ee36176462614c6776c20f2fa4f2d8749c5d4586b076fc2680d6e4c1af3d19253349e36ce356685217eab41a16de49cd0152e305a45d696d77f1cc61a368da0de2728dd156ad6d6ad9f1a7705b9b4287c749a241c9c44cbe775694f3ccd2ae3a29ff75ed0dd67c966d94b96d28a3dba356f47c03e9a8973eb1996f64643858e96c5ac2bd363baccd480602487ab5c9a57bef8c9cd9cc1d79d2954726685237ed9175df532c22e37be86d3dd2d3dee14f6799fd4a7227b236079a33f1652293b88df19cd9eb9690bef170378ce69ae97232d46e3bb2744b0c2c522f5825b7a0eb3f560a19adf7f1a7d33655ca9a3b7a20962bccf9a245e6442fb7d74c7a75c6e5b06cdb4af2b1f7618c99e8576d86eeb3af8cd36cd1129a1d887aa0235bcab2a3c67067794e405a87925065b8172cf5a56c99a9b98f4ef4b487b22807cd8b423e9b0adcba3971b51206abc927ae490ddc2ceded86f3ff4bcab34f143096d02d2a024fb72fdefcb76811c7afd45d58fe89f3223737a5732f023fdc9dde5a2a75706465465813da78736dca7a68ed17d3d00ece005d92ce0139c28c42e7ce0e053dba4821ee6d93e3d8be2adbe71c99c5ab7d9955473d3ba8d9818557c66caaf51db1fef99a75993d73a054596bc414ee762a19bbc69aa64aefc309d6bab9a33326ec24c9d21d9d84991ff0b89524579a8c5eba4589bb5e5f6a9c6afc93d277527642192acdbc888942d3254e6929039350ac2f318d1f5aab8d0dc524317823b3c8c68bc848ba6f7a96893bd91a3e779496887b5c40f2defa7031e5169874597bb91cfa8df21f046443fecc2b43ae6d60288a19cbb868a9cc19aad6aa8536c57d8bab54f73f94a5d90145b1063b3f97fec19d65a969465cf6aa5d14c73a9f16ab672916e1cb8b98a2d4a61fe14cbbedc740ff5ddd182e799f448bcdab964e447ba7c04d52dcba368d2232c2d2225c56f5ade410333cf2511bcf95c6f39c98f6709752df7831df5c0518ee336257fa638cc94a7261916da3463734cda09491462a7ad7f69d312d370ae8ff072e876875105c296606855bc6261f7a430680ac7739409ae75d937f457f40bc09d9b053133aa3b7474f6d2645e8e5c546fc83feb91faa8fefef920b0c820f5df018ea6d92d25271a563bcdd81d000ee9b024459f64d853536c09906e7fc76a3e5ad4c4fe9ecad20fb7461643ae95a03c284662dd53544ca9abd9b7aaf9f58348d8994e23186c94d6c4433694b2511a2512a57d2168b2b5d8b067f77fa4c14f1ab83757dc523a198cc99f0c4fd816b2d1ef78762fc92882dcd1bc76f253fcfa07a61a612c9d07b9da12c3f159e99ccc2a1a7d7db24091d4dd829390140fac86ed9345314e6ec789a64df91de8bae3b92e0eb094ceb69bd6cb1f3ba3b06b27922838d62fc4b2c4cc9a155eb27c417511b05c9aaaf91919f91d8893162b3373e4c62c122f14261af6d4a325d86fae1c9fe05e53c32d1f9cecec798a37e28988a53175b831a81d41761b60cbc96deda0e509d45777c3ff3070083cf9f667739b8a2763abaa59120f8487f4ee54e2e397e3a057801d7ce87489bcbbee3c64f8fe6999e56b665629dcdfa4fb211fb4ecc745e6b454b5173fbdae5e86e652f1edeac05ea3c92537f568624f1d0feae19ccc60200e04b20d9a80ccd9a9d4c4f30d52fe0dc43ee500cf3b09c765d4b78de4fcb4f0c47f9d2f740e449e0d558e75c46b4593cee428835c0651ce4518df24193d4f4e3d485e8079a5a5b95421fb0fdc2ea9cb689cccb7674978ddccd83135dba9c71e610355d2b701e5392b2ee67929fbe90e71787258bbaea596f2e32d23933b756fc101e4aecd7137af1d7e6243d406ebd5324462d40129a9b80becac4d9c375f130aa665d8e4808be7a5f6e8b55a3ee8cfad26b7696b6685d1a64d82d9f44a500ff4b8b2326badd96e104c8b0fc4de6b6f6a72b94310e1dbc5d77f98fa44784ec2250253e17bf5b5d559b0ca9a06dc31f50969764ae97825880d595677858bfcffd7387bf62eef8ef843e3ccfdbfb8f0d93f19085873805b481f3751ccc755c19d14a29f793977562a1fef4f3fb6434926c2390038cb62b30ba6a2324122366519297bbe07b75ec0f99ba2473dc8e7b1cc83f4d2de58154f84fa5bbbb102671e631f214b605e4f3020ea2841c0c3c60b46439330f0f0f0f0f0f0f0f8b036e24596413d22ad94d2629c970b335dcb65369c4cd24534a29a5247607efc2eee01dbc8377f08a209becbdefdf3f0c010cb60be711a9b5e517cc276a8557ece46b2af582c94b25a17290bf0b26155f2da71551a74c870b86f124f673be249e62be05d397db87935366976d2d18b353ee967f993a979805e3df2bad7527cba2f6c28259bade8688ac6d71cb154c5ba6da673f0aa52e6405a33ce5eafce4cc6e3c5530b8db79fd0a7d2ec3a48261a4860cf95abf821a794cc13052a687efa465a689a5600a42d75b5cae3826f62898eef5ddf694502533858229a9ced676e923f27a8229d72b573baf35373f24d709070f279873d4499a8e5814192f748247134cb6b2d24b9cc9d1156582f9821491a69349957fd2259852963a05f76e5309c6ef509dcc95a9602ef48147128ca22d6d65f6f9040f249872abf152622c2821a48e60d2f2df565dfda5eda487118c755a54d645a55bbaf62882f9eccc638ae7a0a7c41e44307bf42ca4922144baa80cc1a473d433a48a3aebd196f4c88896427808c1bc6e41568a7d10ccf69ea2b9f6179add7900c1d85a43b9ce9f4c9abb3c7e60707d957715ea936c95870fccd2e3a2493bad1ff7cd2069a4e1d103b3ecbd0aada3b00b5aeec10363b87c9bb455ff5099c70eccbde5a273a7ef26521d982c9b86659da32d3bca7ee09103f3ad7cdc92cafb7b4f0f1c986b47aea7289f1b984c69a83d39ad83ce52363086d6ce0731dfd2c3af81290a5de16d4777060f1a982b990e25c5f4eb67cf0ccc6c2957e8fd2a038349a54e4356aa60f93682470cccd9d392fcba510b6a1190e8ddb871705cc0051e30300a0ff15e734267d9b2c70b8cf1ab525d07153b6b210f1798b55b141e46b9e58f751b3c5a60564aa8399523f36081495b4646a494f244655678acc01c3652e4c34e54334e8a023c5460d6c29490a127f79d5ba930aed4496d954e273ac90c5418572b5151bed6a62c770af39bd653f3d11095f31da630fab7281b3b3331657794c2a42aaaa82a29f59c528e490e1b0fb8d1410aa3c8b938327a334e748cc2a0dce5e870d2a59fced0091da230bac9a6ae450b32f2224304c78c93c59f9ce4f89313244547284cfa4ea950556bde31280c42691342a8a936f1c925747c42157755181b4f7bc2f41adfe1f9b459ae64278cf28354faae79b1834a72e3eea48313c6f9915df53f6fc26ce1c7a2de11b929571d9a3028f3cba7464de851c14c9893f2f8bc26674ecd0913e6189dcf7d74f6b88a5fc2a895847aa79dbc00c1af0244b6b02201d96109e36db7d8d5eae91ae238376a98a4fe3483060512a095302511963f29113a77669430875a95bbaecd8267a592be1b3552e2c0822761f63c26f7a5676562250983a5cfe1225554f2cf48464678d01109f3c9ae15fa3aeafc9acb043a2061924a3fef7fd63fc2785e59dc9b7ca94d2839c21ce54917d3d9a216b5f9a0a31166d3726496ade843e860847163565b16d7734a7e42e3497098f45ec7228c264c46c7e71ea9d456d287c384a46f0b8ecf3143657428c2ac832c792df5b2bf1a25a218df4823c2e4bd2ac44b57897d9fc3c649c702056f9c1a7908a316a9f315d745e52a49eed8c081c5dff8620b1198e0c061a20006c01f3a0c61baecfaad72cfbf78a18e4218bf452953ad6f51c52684316ca4ef892d0d25bc931a690483306ca7a8defff00e211484499dd69ff1f23a9be94bfa484c72d8161d8130a85ce679d9363fa80c011d80306f99ab7e7edd4bb3fa83f1d5cc09adecdca316ea03bc28a14003d80f667bb114b4ea85116d25c064d978c0c9c971d4c951eeeeeeeebc34e7151a2011c0133afa6056ae2a6b28bbf041cbea021d7c309d8a5f3321db3d68a93d98d2a9c8987d4efa8457d27b397098dc18c15bd1a107d30aad742e579deff5dc9107834e42fade9f18cfa6462634b820490874e0c1f062b24bbcf8ec204a9206dca0e30ee6bdecb2294abe5bf0edaed00089093aec60b4a483ecfef78debc9840676914cace822999c9c2b344022828e3a986db5ec78a76f5abea783e994e5952b4c2cab94e21c8c5abaaf95b93861af2f699683b9557bfa96afe48e854746ec74d0110763be4aebdd1efa1d5ab8703005d7a77ee282d29655de6058addec2f6c2f977b2041d6e30ebcb5c2547deff5e8ac6c1d106a3f9e894f561e4cd8d3ad860d4f2514635557d3ee91acc3116f684ca42865a4e49a7a0430dc6f8cae29ecafb3ddd92bec542471a8c2955d4aea1ab957794e344afd08106c39d4b1d74dfdbc9703bce608ab7162b6f9810a2c20e3318dffe94cdeb747172ec59a0a30c26214fff84caf25955470683ca1f5dc839e9adf753d2e7c50949768cc12c6d45c79099154dec2c3ac4609413a65cc58c23c78d8e30982bbeac57d915a46fc5111d60300b8ba2e3ad48cfb24dbbe8f882d995e7d7494a0bea73f010f534d0e105a3adcb8aba4a27253afb27dad105f3bcc751e9937cade22824e8e08251e924e3c2e8b0132e43945e58a1630b263fa13b89d616796154d297a7a9430be6babca7bfea727736b01819b16142858e2c98c467c92d3d3ba3eac182d9e5a8242f7dd2422b47848e2bfcffa71694593aac605a17aef55392de328d53e3e060c095a1a30ae6d75b97a488f3a49c417272f2890a4619ddd51ba232d49d5a818e2918f566bcb2ae731d6d96f4dd69d1210593cebf341d73c9fea54047144cda83b61c75aca8df5fff6b64646484e4040aa6242efabeccc495e9559f60d61815d54a27e9abb5994e30d9aca99696f2d2e86047134c51448dfa14cc2c7f8e09e6e4aef5ecbefa25b1e61a3a9660d2d17a5b285579bd6549e3e5f9073a94601639f55245f582c60d1c5e9c90281b5eacc7a187818e2418d34ee46a21df2c6bdf8b363a90605233e579a23fbdcbb4a42f470d1c58d8781c270b921a69042c878e23183f78a715a52bec5436be140d0132a0c308069b137add2b9636d1318e1c373a8a600ef3fc38beca6cee238239fe270f1d2a423cc5390493dc76153d28132ade47219855c79cb29c933a8260542a677f6e3be5df4240307efeef574aa9e41efa8e1f98e3c8553e42def8bc4e870f0cff42c8d0c2c7b2574a491f89892a1ce8e881f1f5e5fd53572bc5b73a78604c9d841ef1a6337d2ed4736163c6e20e0c17b4cfeaa45fefc3a84307c64fb18465a166eacdcc81f147997af8aa16db5f070ecc292a3b15efd3a23abba42f045d90acf33448d4021158e7ad902192c30b098c8ce0f82e709c1aaf4cae1819796562030370878e1b18c4c9d54137742a2d8f0d2e669cbca0c30626e51d3e58d0a59e4d1c19b91f74d4c0d81d35fffe835ef5621ae7739cec896cd10013195cd898e1f8cac4867e070d8ca92dba8a0be3eaccb166949c90d83099b1d8310353961d2be6ebdc5298b4430626574fe929aae5d022150373bbae53d2a2d659346d134374c0c028365cb4d5475d2e53257dbb828e17185f48372d3fdc2913a792be1c336acca08123c7898d198999261d2e305f586d32948ab72afa46e868815985fef55013cba1f5383e87175a88c810b1e204c78760c602161638be24c70c563174b0c0f8e53bbf6a313b95540e111922225b582172c549023095aa44c70a0c7bda4e8b1a1dc5aa53870a4ca67d173b4ad395334a853956ee0edad5b66b6f5161caa12f5cd651a99c423f85b94ca71e8f59a7c46e728324c749394c6c1c8a6cd1801be71d202243e449308302278bc65385290c32f4c5128fd11b6f6415a530ad694a0ff33522457232c34ffc115590c25cca2c5afcacb592da3061f55cd838255850c0640b131c38ce152323364c6ad430492427558cc2fc36db79447b96228bc2a89397a9cbd794e25aa130ad4eb6b1ad464b295450184ea80b4284cadf513d9f30ad6a099de2a97e3eea09a38ed3d2c45ece4a7fb0130629434c77e4a28a25e68441dd2bcf22f46751dd69d038242529c74123238b882a36615057adba29b7f28585015568c29cbfe4cb9ad4f19c5a15993059965a895613b19863c2ecf16a51e5be945ef5258c2a5c5eddde9676334eec401596308cdeee278fa55045250cd2f35dccf7153aa7b2a48f29612e694adde794c47727d915aa9884410a55391129a45a9957210983107316a5eaa49256ea8c8ce865000e5145248c1f376a94ea5c22643a038da00a48984ceb84e5a4c509b5aa47986545876ad5b0a42f4fb95c04aa7084599e88accfa95f95fed89871723c0e0c54d108d3cab4972e9f3d33b42a1861562adea212f922ef4b3aa86211a6d515ad4eca9129d58585c8165688e43031d182ab5084f1cc72f672215ba2748930aba8173d4733f5d3458459bc4ceda9cf93adfd210c2e773bc84e51c5c7cc10060f2fc654f4b4f37faa2884517baa453152a5dfb6364c48ec8a9b2a08617629d2bb4c8eb66fe920ccfa65ff8bfd8230767239df279e5dda2510e638a95e0abd1555b7632309d9a24d5c0208128c97f3aa5acf954f8714821cc1205bfbe3d3a5e58e006204d305e1b99229b33c17562b82e9c755846fafa9930b110cfab12f4ae17ef3b9dd00640866114a0965da3d6b6d219834ee4babce7ecac91204c32af962f6a7ae6d424030c90fb92585769ef9b4a80f407e6050dbb1a9ffab773bb301880f0c5a48bdfbdab29bec9c1f80f4c0302b5369cfba5ce854391540786054f7b1f2c688d888d20e8ca6dce58d7f166762b702880ecc1d5f6f34b6c402480e8cd23f5816cab3bf833e89008203b34ada2cdb7f52c13be70626a5ecf2e90c7d424f2d02880dcc2fc2f76d4bdf493162442780d4c020e7857e76ad742eca6fd438394ebec68c1302080d8cab4e866efa7e874e6e184066603e55ed526ebd568c2e03b3d0e231ab4ce81d211303480c4cf1546ae1af4d69955fd601080c8cf7972b9afe3b31957f81d1e26d78abd1a182bb031017985f74d393129e73579ee45000d202734575714e25a53f68e1165688a8018405060f72ff4e5bd83addda14405660d67697da4548e9f15d0e405460ce7fe1cd538ea142fb51f84885f1b427fd9539131b5a5498d3fe64ea4a42ab522aa730870f5acc6a791435a9620ad398bc655d27c5c505abf0510a53ac20669530e525949814664b5be31e4a2bc52d0b9bc2c7284ce2e7f5996b2b230b1fa2308e4e69a5785928cc4a077f25fed427f320509894c90dd5d174c647a54f98c7435caf5e4eab6247307c78c2e029ea0f235a76c228b255ca9f7a5db81c4e98ec5f978e8fd838d1da84e9d5a8b113f23aac14e262c609c995e143136633d1d2d6c2ca5eb965c2b842ad788eeae5abef31618c17426b88370f17fa91914b18352c278dd3df59d29368098392972a972c6172ff8a6c6185c8c8c847250cb633aa2c9c76e17d213995c107254cd9b5d84ea6bf43786912066f537bba535239179284297b6b559e75d87ea913912182e367e4b5e12312c66db1551ef2734ba5b938392860c364860f3e2061aed75a1d649b8591e9238c3fa693d7df99504d86880c768449591297cf65e6a78a8d3087cae9adaa839d698f11a6d723c3b28d6d29911de16311e6539ab11ddd83cc17528451a97eb1f2737b6aa824c23c7e2695d0d0f89223224cde991ff651a5ac750ec9f51b3e0e61b27cab4b5c12d3163d8630c95cd0f64994be284334283032b226344e8a0b3e0a61d0f9fa44c4a71c634c84309ee9aefd55ab024464882440240b2b44d88b8f4118c34e29aff53c32845210e617723da6c77931e705c29c1d2a8abd6535ad5c4018e33feb2ba9a62fe9fc1fcc5b42bd4aabdf4c29ad1f0cdae6e5315bab145cd507e378d65f91f18be1ca0f7cf0c130a273a450fb56775a275a8c8ce4b0f135be3837481885f0b107c3760b2d173deb984ad683d9b3f8b2adbb245cb43c18e577941ec5d3af765ccc0b1f7828fdf76aa91e5e2323232324c71f7730cae9e7eced0f774a680b2b98f06107b3d21d3379ba7f3ef53a98d743659db6ecd257490793744b2fb58abdbd2edaa1163ee660d4902b7264d8ebf8580d3ee460d09f3aa5d54f4abac9e2600aab3d69279d72b3da427243f88083514fc8fcdcda7469e939f97883299e56fbfde2d9ad633798a50e2df7171d2d556983b9e79508e11b3ae5206a13c3071bccd95c2b1d4346885be51a8c5a3fa9b111cbed42c8858d19a806a3e64a37f16fa7b3b34c4c70649177e3a47bf09106c3eaeaa496579bf2180d0615d256a7de5b2197543ece60105a84eabb089d524a3a2c7c98c1583953eb8c8f7557e93298544af39ef5aa71532a32186ed545c898b07c523606b369e1492f2bcba245c52706e30b153d69c9abb82b2609835146a5eb5367ea659a9ae44e52f0010673a96826d685d6aaa54771f0f105d3d6c512d3975fb6de0573f0e105b390b1cf2a7d94ea32ee824946db5c97947d379b123eb860986df7fca4eb53f5fb838f2d98b7e2afb29f719ddcfb935392457ff1a10593947bbe666b1ef54a838f2c98858ad253bad2a53b4ab1606e15ed5b3945215b9eae605c7d21435a5a0f622392e3c601840f2b18f4d89790aa171b4f8324473a74c047154cc964fc4ba524e5dea682416deb20d5d86ccd8b171d3032d22477b2370583b0a8bfeea2540a26cf32be3cf5e5aadb3ea260f04ba3df95942beb23281847cdf5a3eb14af35a4616282f6090615f5a9ff1cbd57697ba1dbc587134caf665dcd2dabac433dc04713cc725b9e3ce92ad4954b722df8608279df73485d1b61e6dd271b265714e16309c659ad822cd793cf2b2518b5541461ea3283e4ae9360d62e94f417efa8a3ce21c1a8f696d3a4fa50f07104f3ab27e92d75f4c30826bf74faee430b731116c128574ba9f7729a970811c1a4a4d0290b95a4e8c7ec63086691afdb5a79a6a310af5ea10112087c08c1e84aabe5a0bbfd08023726abb4dfe21f4030896727a9e3c892f2b99293e3001922bc6822822d14b0802f7098d478098c8c2045c247878f1f183b6cb8f4d341c707edc307c6cc5897ea6941ed453f7a60d47a5fc91261a3f46debb538792e66a8919134636444051f3c30abd737dd74d579fab7437cecc0e8655a29214d968df498244017f1a10353f0d1d7325fcbf3515bf1910353ced1c5c377fdc58692101f3830aeb2202ec2b3cfed5cd2473263ad1b351ef085024e4e4e162348f8b881d93f8a7019bd1cbf943e6c60ee15fafbf5a7f9f0aec6127cd4c03c5f41ece6ddb3ad94b3e0830606dfdbd529a5fd9455b632b0109121626ae030f998813947e68954f2fe908129b69273a56a84e8942ae9d7c3470c8c2a4735bd4ab7e2770e068693a3cb82109e17185329aff75851cc48f9870bccf257bb70293d2e97ca470b8c3afdbc9f162b3df98b64c6c8887b7bb0e18305a67c5acba898253fc7b102390e0d068c8cd8f81c390e8d1d7cacc020647da796ce426d941f2a30ff8e25a1b6b3948f5cd267e359e0910a935211dff69febc40aa1c21cf425532e75927aaf750ab3c7502a87a6d232e71a1921394a7898c2a8b5da78ef97972fa74adaa314c611d57efdabcab556521845bbacc925757e73de62e1310a63ddda25d3979d063c44613859166564abf55f7128cc6fba5afe8828754f1fc0031426d5b9214d9e0e91d57e17e9e0d882027a24572e121e9f30a9a0b3abec31fc5f7a3c3c612c0fb22fc5aba04eea3c3a6178199d54482ff5b41c4e9853258fb66a7e1677b50993ebafbee0db31b4d7257d232324ca861788f0d084f992cb3b3127f75d2a65c2a0f92b5669a595fe620f4c182eae16f25a659955a24b18bbf3767ccd197d5797b4031c20224344013f03c7162323232324374ed0c3120655fe76d95c9f47ad37342cf1a88449ea381bfaf4a7d8e77b50c264e2d674daccb7acf54998a57d52ba656344ebffb9f09084e1540a9d852a5f21b416071e9130f6de5b7e991647cd08ef7ae00109737493de292be6694b7984d1e3abcfe79fede97384719452714bacd2a31106576aab837b8b9552278706498e19346e9c9807234c5f72e567517b51289592be2c5ec81011c9428b2cac10c9c20af4588459f7e3be54e95f85be4bfae49f012323fd858722ccc1dd92aad0a743b94a224cc2a4dab1db4ccbed418451f3a33275358f52bccae310e6942f225bc507f90f7918c2f0299a5c71ba97f4d90d8f4298a54bbbe0adde2d9837bec851238d209110a61fd93a27a4b8961a478e1b09028f4198e45edaeed43d8bc261b248f24e70fc4a18e85b1e82306ec58bf6e172d495f21a0883d0babe9576a975769580308a16d3dfafdd6486897f30e7f3dbd2ea65f68cce0fc67f65aa63399dfc677d30aaca5572da423e60de8851df7b7a954287e86ead073cf660d2b93f846cef90f1427a306d9897ec5341cedf9807e388be5cdf2bda73943cf06094e24bf6e7adf8207bdd80c71dcc4157b09896e58793d30e46213b5d5b98bf9d7a3dea60f0ac0f52cea3c5fccc830ee6ac6d5cd5761e35cae5310793a5d5624ecfaba724f49083516967f175f75a6e8d10e360ee8f6d1d5d76555c25b782071c8c95ff44d484d4d1dace7c835169fdf1be3e280fadda81871b0c2774f62ef9524ad8db06b3ccc7bf2773d5e7a2071b0c3f6a9536d5dd1acc1b27ed3fbf6bd3545583415f165ddac4cacaea330d06d392c2830c1d2ee720a2c1f4af72cd5cca239ec194c543bd565e4bfa4f33983ea70c5b7996cc3218b4baa0636aa15daad749287890c11cafe39fb23c42ceca3cc660123aca0a35e7c2550e4a31185e2eadabec327514157a84c174a6765d7e4e3afb3c3018e795526b7f0f04b3a7b99cb3c5b99cf2873808f981f9e3c717a7553ad7a286f8c0f897d54a9553a82c3fbf4908e98151cbf90a9e82369db287f0c0a0f58be5d7e97d85663b30aad6a7f45e0cdfae5507a67071a4d459e3b63f290706255bac749bd55fb775108203a3d2e9166577d4ab7e1c197142c80dcc314d8b6765522d688f0d4ce97b5c43fc43aa14cc42480d8c6a2efedeef6ca7b66960deb5b9fd9c55ce123a928b4208fb233a4a05219581795f56d0b1b5ce93150b8981f983d2d5ce7a4b40b9101898578a49bd2a8dbafdfe05667d79b2b30e2fc405e62cef3bc999fd18ff3f03720c212d309ab05c7aa72b8bc53b8405867b5f5d5be797cf43ab82901518e4e8f7d22dff54ad8e21401784a8c07ca73a3bef05fbff12622a8cd973fa39f6a70e1e23a2c258c9e5854ab942bb3e84710a831c7df6a6434634854108715fd3a73653b9104b61d29442a9a82d4597f2472485b995a9adf4ec4cf55288a330e76fad9a13fb21ef228ac2205c5be564f2e93c55324361922d2b4b37e34d970a0ae3f927252e9e2af313a613ebef2e5c56506a677ac22452a9ba2c6d2952290d46274cf9dde6e49eeb2d29c54b80c10963ca11e293c678be2894b909f388baebaa88ec97a90993e9fccb5dd99309a37add5acb351313a67cc1d3aaeebc07b9332f6132efb4f7d7490919b719018625ccabb7b3ceb27e0acaac84f1e3c9aab49f7fc5a59430e8603ac4985e17df0e8c4918dbf6be820c4f12463d42f7ca95a274bc5f482e6300231246d941b83c9bcd0b1f42c2686feeae83d4d2c95c188f309d54faf757afd6c25f3b80e108a39c1cef7c426bf92ba4018c461874bb106a5df4ae593808301861f64b7acfef5f949a6d0a3016613e5991b352c592685714617aa9e5e715fa55894b521dc04884416a9d54e547bde65a8908c3fbe9acc22e7608a378e5902a2e27af1c1ac2a0a221ebb37811132f8c42986407178f1fd9a36d3f31c962083008619026ef54562fdfddc741987c5cc7bffdaee897250883cab22a6e6a199ffb0b8461e75356aab796980c0883ce799f9e53e54e1efc8351c7be9a52e2b1b458fc605e59dd9d3f7f4b47b70fc6cba2c2ecabcd078334fbdf96f3a0d43e2c7b30c891afbc724e798f3ab92b020c3d18bb449c54e74908755501461e0ca63bfc2b71eed2ddc3835929ed9e5a47f9cbf512d9c20a919191be8361947855ed29b594b7aadac1b45eaed56bdd69448f7530a7eb8eb25de185ee9f0ea6a8559e0bb99694f69c19261620b91a30e6607cb1dd49e87b78adf4723066fe6ccb8b511c0cb2e655e925b51360c0c1245a7df4549f5d37a59393ffa5fc06b3c717964ecfb4fca66e30ae4e1685d6fd12d776ca00461bcc9e26abc26c7a865eb1c1982a9b96eb165b5c34d7e0e928746d4b3d3a393464b81a0cb32aa7ee94f5bf52370d66d73ae72f0feae453478349b4b57a871cf57ef12fc03883c9b52a9da2458751752b0c3398e2ddae5629e7c7fdac91913218a5ce0e52996c0b9d3e0787191939387e060c32187c476eb375e954d78fc1e0269e4b6b695ab25262309ea7beea581febb90a83694d25fdac2bcc77b06dcc60000c30184f56d5e9cba58b9323812f98f5be7608792a28254a2f985f55eb182677950bad2e986694875ea5dff2cd30b8603c9d7d1d4febb76014d53a532fa75b27d482d956b8d6593ca67e27b360363de1b9b2ea28bb2a160ceb6a4dbfd62623a3362bc0b88249e774f8a720758eebf20630ac60ec3265fe2a3aa78eb90d6054c1f8ba2afb45dd496fe8a860d4db7549a720afb2ce4dc19cc2afc8932fbd4cbc5600430ae694cf50da72a85739c28882c9cca4fc9eaf7200030a26a99459cad1c5b98efe04738c0771f12443c8879c60ce6642869637a69df335665891216817c06882e1657e14f75e519b1033c1a89d53ceed17ca63664b30e9d54af16f85cea24a2598c5c98baaee65b6cf97048358a1562eea57cb42878104f3a538ba8248cf15601cc1ac22e4b854a2b2c5ba8900c3082695e3af8f16b1537917c1ec61e9c3eb58ad469e3088607c9dffef598588db118c2198b2e957e6e6d25bb7c92780210473e76c2a5e25e923564130a59cea45be36d1d22b4030eb2864caaf6c7a36ff81f1454dd58893a9c557bc07307c606cd7f1f4a07e295a12460fccae55c5b73479e27306830706f9325e0bd7f19e6f547800630766f768e63f1f8490c2d381c1a59b669bfa4afa74726076e9d147b6694a171f83810373f44a6f7add1b18f354ee18a32cb8c86a03937d6a399e524b79188100a3060695b44c9aac37d38b5dd12880410353f28fd195f3c79ace6660da6f7fd5909d465c5c06e6b4523ea91effd0f363600c5dff1ec48de89f0b03f3aab5ac6a332a086d798139769454a55caf52cf61b8c09465b7c98a2aec6d5a60b4c058b759ee3682c1027396ed7b196fd970b905305660ccdd55b1b35dc548a517c0508129cb9f692584bbd24f2a8cbaa56a687aca7edda1c2ac3b7876b0a0aebe544f0039853969ac6ef7b1afa8575398c2a59caad38589709506298559b7ad0c53e976552c496196a69d5df9c54527f928cc1aabc25fd4332e36cb201185512993bb22ea518b564361dad650cb1784129643a0308e9faabca8f76e4dfc84f1855d0e2b75678b174c27336a289b01c413465953b9d2e788c56d75c2f8daa4f6fdcab94fce6000e1842945ade5cfb57e13c655d17527f9c1b50e441326132e367664f9092dcc84c175645dae17312da39111c584598a91f2773b35ffd427209730a8926fe73f1f966e75be2401260d304b98544e97f47818a41226a1b5efe6a952fff62b40095394277b85c8f10f3a57d237e36446b9131a33727861009049184e8e89d0a3b142255b12e61caadea59c7ea1a456244cf63aeba4b744e9a8363d8040c2a45b5a8757f37ea9553f803cc29c7f5ba8a87f940ea742b2208e305db6a042b7b61f0d0da411a6b09f5ee75c76ea9fc208c3c8ce650ff92c4e4b8b30e91db542ee53c6a84b11c6ce42c8f9a7b6b93c11c612d5a9c27938d14c3da001223244182022630122321061cefac5784ad333214e12003984b9bd4d5ed0e5f57bfe18400c61104fda5ae5f953736521cca7626448317ec9728b10a6d36622af55b4f0d4066196a93f859252aab03a250893bea84c9584091dfc0b84f1b3aae55c52a5ede90061f6ffac85560a96e4bc3f98d53dec6a997d722de607e3e99c42b547f59684b40fa6bc9f222f7d98acacf1c1a45d0857a63f8ec7f7604e26bfa55679e356957a305ffa512f375689d3511ecc5a7f4daa79794aa5762d00c183d1a4799a9e8c94d52e0b40ee6014b79bd5a25cbc5451103b18b41ea15ac7558c6d790820753009bdb735a3b4b58bd7710e2074306aa14a9db8e7e660ce62b792c9552a272a39183df5f96e6ca75a90c5c11c5bf4d7c85afff0351c4ca7fae9c3ee9998ee241c5e9850c086c90cc337184eabcbb9ae4bc8f4789901881b0c272bbc7f4365b7ae510d2fae10d9c28a9191126e83c95b7918b7642f95b8b0c1a8d32d8be52cf399a90c40d660164a8adc5739aa4a8e2323a8066329bdd71f9e3c223264546064e46d78d105903498b4eb741eddb29c555204206830eb931d5b9aee0ce6109784d29a9faf98c300c40c66af13294d7798015ad400298341aa75cf5aabbb5fdfea3c5a3218b5bb5a19a1c3920c7d016330777df65ef9293cee4705206230d6e9d0b39fa6a5ce522527c701242527a7c4710b206130ea97acead322b7e5f50210309883899eeea05c57f63b32c205902f18cc645db858adad375e00cf00e20553ca275674f46cb2716400e98259cb8c6f7fce3152c912f822c78c850308170c2b44a4eeab72a9e91ab923c92d18fb447e2ed339aa6a492e07cb01440b266dd7162f5de8fcce96c3034816ccfe297cb4c57ce99a8e8c8c8c608e11bc1d2040b0600ea354fa3eade4c8996e805cc1b0a9d753745f67874ff300c40ae6205e666a294dc8716d154cf2b27f5015945411a6d203102a98fbc49f9b149d53af3205534c91f7e9750755539282797dcfc395f8abb03b0ac6cf1432332dc907b50001040a061d5b32e3745510293ec1e0795de7ef2046944e2d08204e30e764e9dc54bbae985b138cabca558eb987972b3e49d77fda47cb7509e691e1db2fd5c90fbea9124094609affacdac4c66b11a92498774d8c6903a6ef91adf3898a290c675aa7cb95b37deeac1466194a4ab916f6a4de9b1466219f628aae68ea2e3e0ab396a1725041ec8577164314e6ae57eef5d93332427272f238b87c8183a4ecc949c60885593baf12db0fa7ea6d415c400c509865a6eb2844aad295fa8459084f530c4f18b58f4b51ddafa5aaac923e04c4e88429b6f6959582fcea396196625aa6d0eb2bd6d26881189b30bad23d672b65e99c865881189a306b28e129aad9eab88fe3dc505e9930b70a42a60b25575b0e3191e7f52c43bb72cc389961812c46464646f61246d54baf5b89bf9c3c9af7312c61acbda8b7b2547fa54e2e6c98d0a884e172f257a6f5f44ec5c6db30b931825709c4a084f1b3a2ab28a47b8d5763467a3509754e6e41ee7d3b99118225400c49183cdfb93a0f6d254a2b6244c2fc398970e9e1e4c9f89434c977716ad841c230fa75b4fd9b58bc0d2cb688f108a3d459ef97146b731e3bc2b04aa7d6dfb62fe676238c3ad52acbe9e1b4728d11c6bea0e3ebc6a7d21f0f044f012f3116614eaacdc7b5872f912f4598728aabee723717549f08832751975551c5e7558830cad2427374e80b0d621cc2dcae4677ec8a14751f4318dcd2ac56754dd5d94bfa30bd20d9ab21c2002d440a611ca95f9ee3630ec42084b1bea3691b51a782d0c51884e9f27d49cff22cd35479366208c23c2a459d525ed1098e93059e026204c2b0264ce57e6c907c61e330163100618e23c4a64b1dd45bc35331fe60cec136f62cb79079a75212c30f06a9e7c48486e79c1bc7e883d9c249ef4ce152bc8a49463063e11920061fccba3db68f16dddb2977b207f3beebbfc96cf9528a9563e8c1ac5a2b7ec9cd867069492b1bdf26461e0c9f941457c2531463ae0d1198d8e8c2861778308bf3a4bed2e7d82afa9319357263dcc11c7ba4be8eebe1839876409ba997d7c1ac93aaf421d65be67e3a18c4b52e2dd47f756e770e8695d7bbe5af75eea096832925954fc98f7437558983e995a893254a9569d5c1c11cc464afe9da7ebcd11b8c7af5827491aa7ec56e3077cc4551f14c5dba701b4cba2973eaf1b45cd53d0546465e8d8cd430c961e394642182186c30eaeaefbc2993aaa3bea4cf86090d93449223fd07904999408c35984cd8fe9cae4c1d5d4ab2b7aff0158eef186a306813722a09fdaefe212dce6b11230d069d717fee417dd536669074f17fa34f8b051cbec22c62a0c11c4bf57c6489331d544aface02389e467a454272e3c4066083186730a9edb9be0d97198cad4628552d62b49062198ca393f878d2f5b9f28c0c46bd23bc93163d331b8dc1ac9ff2ef8f7b5b90153198ef557c7fd912f623f2186130dd69dc2a79630c3098455d2bf1202a2a71717ec1a43e4ad379a35eea98c5f08259c7ca5adee2f3e8aa5958215284185d30fb6c9716619fc5bcd3410c2e182ceaad894fafbcfc82b805e3b9694fd9a42a86160c9f3d748ae87dabcbc6c8826153f9b6f8e70ea9322c1845ba8e23e4eac751638c2b18f4a557d97eef54523931ac6054fe1d5c7f9815ff2f46158cbdca54eb67cbd3af23210615cc222ad72a2d55ce4b360583489551520791da394ac1f4f1e24b78ca146af32818b5b691974c09db783d148c16b45b94bbe88ea12798dd2ebfd6d0dbabe939c1a83fc996a946f683184d30293dfafa9307e5e1d54c309a6e9552ae7d4f615e4b30eb16e6e23eccec694809265f75af5fa726c1a0b208a1a5c2994aab4782593fe91cbba4795d501ec1f44aba54a12f7cea798c60ca2a478dba56276f4a45309ac7cae1292d99782911ccc9bccea279967c960fc1e8263ee508b50bc1bca9c5e5a0948260f4d3af4a674556a610104c9762e914199d6abefe8139deee05315a5aac6cf18149a7e8175cadc89642db0393892ad9bb4a29b16df1c024b588cc16aab22c69d9815943e98856e562f95b33c4d08171c57e102e2b64cb28330746dda9b5ad367d9e298c8103a30a2a2b8ba346be974e1062dcc06ce7794cb63fe9be7c0c1b986d3c3f7a9b0a39425d0363c9c98a1f549eda3bc5a081417676f1a0d57495dc316660d61ed9aa964cd5183230fd0b2174cb5019428c1818b5eedaa7fb199dc620060c0c62fea553bc2fc60b4c4a3e5c709553af6e15c305062d65cd78d0e1b512718c16982ca71cadb6d2d87b198305a6eda85d6becfcbfd4791c2ab24503727871c3c60362acc0acfa1f6adcb538fe699ca484182a300a296b59aa5bb8b0da905418f363de69db892dcf4bfa2850e33c8e1c2730084185d94b86142f4eff684fe1290c96f6b5d66676318549f58dd0ec8b2a7fc410520af3df5c927a59a4307650325596b9c09b42c828cc1dd492dd472d947ece03ae509fe3e46d905c0f42446134f7381ea5e9a130fde9c5baa872a030cbd05aeb4ba5d38a7395b4046478d1783872dcc81026847cc2a8abbdfda59dab7515e209e3aa5d34af755f8f5a9d306e05cf346d1546ab16274cf25475e45912b7a80e81498dd7c206162232b208d984b15e87beac73be8f3fc78cbba7811c0c219a30ddb7d4df2fed0a0d90e008c98479851625daa1840973b9d41d37dc4fa9472f61d459bbcaa6936b09d3adcb89527aefa2d055c234ff4abdca15cb598bb1c710420973695579849f9330c910f16059376ef39584c1c67b4367dd4ae7c48891307b5442b7cac13fc8974afa4a727061e3699018244cca3cefd2b9cab93597f424421e611615bfb63c6fc70e2aa685880c119b80880c11cb4244868861212243c4ae1091216212109121625688c810b10888c8103108886461051f00d810e20883ab893d1db58434c29cb22e7795dd97a29a6684800c218c308c9a7b94adf128b72f6708598429b8fcf4d86fe2553cdd851045985d0ad51f5e2a8aff9d0883d6c9575c68931f2d8620c2acd5652d8492b6aa6ef5001b58e0151a2009001b420e61d8eea83584106af4d3104318d4aa88d314cb494a6121cccaa3d0caf93cae894a08210cabf2a37379d8a9bfb40021833077a7b4e2946957216e411853ed3c4b4b580aaf12085374f1dcaab2722faa94f48560860a418e1938cec8c809204cae83e9d6a3ae3a0993c8160d1039e9c2c4c40101b043c81f0c2a6829bf531017343f242439d2c19163047fc880103fa064e48ff872bdfb60b8ff913afb699dee89c98d344708e183399deaae94a3ba0c89e0e020493508d98361545512a66d2e5ce6257dbf67b842f460344bc1b43d9d8c5a561ecc9f6bebe26e970a3ae886175d989858d17508c183613b4f0a3959f9b55e4bfa38e40ee6b06e3185bdcdad4ced605e95a5c5d6f9d2b81092d830c907d81842ea60ce292915b466eddc761f08a18349bed0beee61e4c7d3903918a5d0977467a8f78b1f1b1f8227c9f1278f23440e66f16aa4e8eca1ed2d1d07637c5cda3a2594f8150a818349aaa9d44a6ca89cd3172e42de60d052cb4244abb87d4f021b587c21c40d06171b22fe46ebe7d329e9ebc2c4a484e469a81924364c7009216d3069d5df42fc7aa98aea0842d8605a79cba3ddd999f1cf682884acc11c5ef7aa54b04f255f6a30084d65c1e4aadb9c5cd2f7c5a1a16898a4130e44481a8c5a05f13ef2dee67f6486103498828aa1c3987e957bcf601e35e29229312a754e33189550612f69cb2d5d25f909216530bb12512fb4b6edf4a092beb481858c921c332e704283460244648888c810912162d4ee433023840c06d52ac991b32937db2de9fb1c2743c66052f39e2f7c580d9542257d8d23c78d1031185b95e9e0512b058b10120684885e2954564a216030abd96d8b9732c43d5fd2a71008f982b94fa8e67c655befd40b26bd164b4a796a53aad41787c63b6064e48b43e3c6c90c35822f09e98241caf6e82fdba1e3bb42b860d26f17722b887525a442b660181df5f2767d0e959e164cefae5268f5a0b4cc3a0b86afb4fade3b7736b162c1a063bb05afb41dbb735730eea93bf55539a75db782395e72e9a1a192da13f11707078e5323a40a267dd2555ca998ba2e8b0aa6cfd2ff54964cb14a680a06d7aa739f4e2905f30bad614998ce4fb58444c16cc9bc944bedf9ce567c8506483610020573f0dc7379fe4bcf74257d24666676225b582122e30e214f3029954fbc47bfb09e3c1ce204c3aaaa47755aab09267d419f85d349374b0f618251b43069675b6157052dc1782673e92feab6f59560f6b01f47cbe8778ae28c1c244014d9a2017b214930b9d2ddbf42dfcbd3291908418261b4a4b66e952b8745f036ee44b668c0851cc1fcda766fc6822146309fa97cd27d84214530efc5df12abb7f7511e4204a3eed52928312ae7772de9533466788156648b068c8c9c74616252e283902198d4658bdb172e7752a6100cdaf326737e413bb49020982c6abb6cf2d3c58ffda874b285b248200c05a21886610080e3e71100631200000010168e8503129950b0afdb0714800443362e463432262e221a168f48238150180c85430141201408c241100561188d7434466b001708dd705e364364e817cf1b98360d18d6d8c42d0c1f897e559809560eabf1b27fc43b8d85e27e90d44a21157ddbe961f0d245ebb7e344860a99a9484b4e094d13290449689f8ea8129adc251e0215ea148ab7c0504691152a37188e984a940ace33d5ec356ec460c3bb5e6354e02a2d02101ec63541eafd7f3b20ac62be7c58c3266a32fb93ccbfc63e57b4a5b435b99ec27bf21b63a0b94242677465dcf7dd82c00e0d04041d9fc0cc402726b98de0ef8e27b49f37370f31d4b36e3831612060e4138f11cbe07aeea821dd52c5ae978ed07a8ee595494b001272874ca5339ddce801ba569a2a4bce59ba4154bebe193cc89950d7572883833a2d55262d78aa37134250970ab216a431ec47b9dd7bf2484dc9c82b2152d748941fc2ada9a7c6a251056430e78a5fd154a53f362ab8d29b36e35172c187c0852b0ae8367881547c943e602b6b6d5dd71ef4f377c77e7d49a80515101a88ad9805b6b30696a5247c0de170d86dded7ffe2de6038af671fc7dda7b878704b9fa042508c78873d5bd305755fc3e8d87c029463d3f83c5c4436bb442e92e034052a96e02f64ac6e5ea1f2e3296eb86bd8aaff016a7092eed23d2b8734fa8a6b37e1d09b08ac6b4452b35a26a004fbb1a477ca79f11e20b4a963b1bb18bac546e3607ba91eb4f07a0513a9b934512d3eced3c57722604b56988dcae73c0cb4fbb8561d3c05be8f8303f6e7e6169eab555ca1e72cb034517fff5dd5534b58ae90a82057c1a784a91054b9ad8b7b264194d263a13e0ea6fc3e1c3b5add3f5b716a4d2aec14243351344fdc6496b28c189fda22ae9de4730a3cbb5c9ee1874b97f54255af08e544cb95e6a3cea3a94bd555d7d2bb0df7f6933343384827bea24e55fbcc0468c773014a5003b26108907158d725c7ae29d9894a250758d86a44c39b52b81e40aecf0bbc1d9793d0a2cbf04ebca5538458038f2815235289a86c206478a347ece271101611bf35efda3a4e0d67e50fd54899da50aa279322ffe08df84647c29d8a77c206003a00d600a4320018de33d489317e2bc6505f838e006aa79625faa7624f8e31820e56ab686ef16b7fa69e7afc2b747cf9110c4186b1ad3e8ae4c5c1f8660988d9f0e97b8a2a3007d035003a2472c9d78de8913959f19c6e8161433c394fa9ff9375b3d53bf959c68e8d7446fd1abf018b6173ae708fdd5d5b8d35df630c922e4fda4885fdfb206bb3830584be4220732d448e245221774517d5a6d361eb185c46d1a98b9b2937ff9f9dce934fa76ceff3eaea88945f3a422684a252f3d946bd1d5887f838181b2e8c2cf63a14031072e0fe395be6d014a06645dfb0836b057d6fcd6af07544df6b241fc2bf27cf10dbc1f4a8b255685a1157ab21a3eb15d7635989b2e216ff7002fbf135cb3c05eb987c4116db09c1d7ec87f4a1b715625a212d57438195e90c40d2aaf1ad40b3158e56416bc575565fd2ac86b87386f76235942a96eadb0896bdac7667659d56e965d59dd5d663356c4f4e315219ae419c2c06e5a30b83b5c6c403a19bffa11f40ef7f27738d80583645176f4632523b737af06d1c516da2cff2d7315301a61780506042154882140550a5b638cc46bd27e1ed0da7410a7f84050ec54b7f8864dda0fd8a0b4e8a986a100eb9e26321eb65d485b6c3f2fc0a697fb199513ce57389da81981301862a46d4e984252619f2f117291fc0abc265b01e9cb95bb388116516044caee5ffe9b4728151c575de087dc106cac201f772d0350cae16ee1de053d8b7c8abbac924765025136d3644e7e18127ec40440169f075e21f46b5cd22dd195309a9139de37805fe9aa3028fd17cb0fafba4a82212819a9f9d37e0c293c24e3958eea42eff4a808a257a732e5a71a5ede01b292f14548da85fc7000ed5b4c42678223e468f2226122a1615da40d8c8a91116f5e8a646497c692a502554df4ef21aa2304291f0ad7cce9d175b43d85b35dbccecda2e789486d3c675ba87822841c03cd16a86012397e43ed638a38376c90618931a2cf3ce3ec3246cf6481f30c5206a5fe243310bc44d80964b37aa0be2128a363da505fe56af7fb92e70404f2929f3549dd64539c7cf298a8c7f0c334e66e4a0b80e544570f4ae9e574c358a39e3b63b2ce0b522b74518afed81ecb471e8448c3a9645612d749b8b1b514bc19791eb062bd7f6e5ac6d2a7fbe73c898ebb5ffb521d2616ef6d23201622d55cea92bb878e786122c7863aead1e879df3940c6d0587c536dc3ba7250c6135ff09ea540546f25d62aa2fd84cb4f0a005f645c3f364d8279147d18ee7a9a031049d3fc400b646818fd653aa63010beba1a2db30a5daf7849c246538fed01a0d79a15057aba6e6829530ce45841f9387391243564ecb142a8c1b88886ad73bb38d122852cc9951688063f646c1a310c2f3fcca5970cf11fcbf2946722b1938c955461379516f29eb61f073d8d6d2e53b7839c326e268a28c0ee962dba7652da518cda1c25f807977243a19525bef860684b50b5b56ae29e4851c4a058fbb57d8e1161b9be1642cd7850a6240bb9a60f0ed34fea17f8ddbd0716578ad80ba7782c73e9119f22f718c7dd47a9d6ccbe848016ffcbcb774e56162f9f6cd02711474965a3b61003a28fd5b3fe3f2fedb52abf85f2aff799c1efea5fe21f92361000e7b06538fcce6da9bcb589216fae989fb230f4def43d11c9e14eaa46fb8928ad695b5bac3854f1088fc67b2220a10e8249368e4dc24453939cab50077198397fa1715c5b8b049ccab92966bbc8b3ee7a60790114e3f6efc6342f4fb88350db1a46e914f71869020ffc65d602e3b8272aacd286a9195f3539da92c962d483a87d830b80132441991305bdbdb4c68c05620628cc06ab22900c662a4bbc1826e96d7089a4ede615474662f8778b4d31cf9863bf9879b4e50203a2530b5cc4b6d35ddcb17b7eb73bd76ed81dd928980bf194ce56e8b378e9b38365a985367d85f88f5f91e79e835f173be1bbbe89a548cdafc117d504019f7e2df9c3b4a8453f9b1f90fd6dc52f9f0498d3432c2fd4626f26c941c721ce20c17c893faf9032623d92d60dd6f6bd070838e3bf55d5817cea118e6de0b1c17f43f57291187517bbd504c92b824bf388528e31b55cf66828f50e45118430b88d1d1bbdd4f9314b437b66912d8d4320bbbe945b43e38619733fa73724a10517645c8295799ff9ed55c69690269d141fcb86e5a92dad3e49f47448c3f4f747c2b252669081ccc037789fdb6a1698fbeebcecdacdd79ac30f458d8eab1581ac6da766a1b09ecb65c79aa5c033b266f2de7ecb2c49320513efd055997a1a3c62a40c5fc4863da29d161a87169348ffac3b02d7ca802ed945d0e3b6b511e76dcbea93576db6642272809f926332cc283e67069b904affbde0d6583aa55f0db03c0c0b5b53d7b6494c436faa2bfae9fbccbec6b251c7e56f2162c0f59dcbdc07f4049f0a9510eb1cdea2de377501d6528577519e629792d4520eed5a31e9893064c229a3222c32321db098dc64bf2db848c19e15f5e1f4c09fed951d401df9dd5e7605365804fdcb57390ccc661f11cf505bafa54949451c32d83db16f15e98fa620a29014001e032a5496b1cdffc53ebc83db92ab0dc6bff2570fec3bd04312c2c1e5ad65c2b37c51bbae059a7b55c4dab412771137cf50c22a16d09a7a6649a31d0f9143fbb5a1956cb2adc4a160080470232dfafeca1aa951b6d109129584ae672a9214e63c9ba2e773bfb40395b5604c948574b63344cdb1db6ff4732318dc34403a4de54301aefc3501dc850a387790045fd64f02a44130ccea03c5483c5282201b4333b50224d7f75e5af7df9d99cfe081bedcc7a895d39831e305ecdc85075d8707fae215e89298a51486b7992aa3b6af37bc02c766df2930ae9818b63a18309e393963197f676bbbdeb7724bc3a3f6f96eb5820464a806247f727061454df3164d83e0dae9bc28df47dd0b10493e21d39341b85c8e493a0858a1907c0ea68651ab2de2d005c97426b5ead014b88e49ccfe0b808d939c2abeed4fb6ae4bd0c628ed2d645c560e8f9d838de692ec90b2d9bcd6b8b9842dafba6fc9374b60078b45217f72c2d52981e719059a8b362146d1da96da12714b76794217590cf664291ed33502f91e6807a58d03ba4a3e9acfbad25302784dd045fac07df2e8a80386b8e8cc1aa529c5ed210be58013426198f058ccfa333efc629af2d40c96d292f5017f2ee2664fed26d7ce4eb76d7a595f897c5fcac51130e3271deac743a155fde611cb875b769fc49ca93bb37a303eacc6421573eb8851927540bc76e935174890faad62b773d48337aa61f0b5146b00bae790a4a0792b7f63035e0edee3879cbf68e262d432a147af2600ffa031e14ce752f1a1c69dbc902ff80f208c71f746953a3b46002f33750ae05207b566691c162a106d5c04019376d24293a73c3ff7592961c6e73a41b4710b2e8c4ea25c5ff8b984f1efb180e0011486026993923a782c558f2bf8a02a82e4860342f8d173fa40446436fb0a3c4def1899e442d8492ccc9f5489d4a76418e6b1434722202526644c9b99f6458483c29e0f7d0f326ea0df5d648826b8f377b5410728eebb2ed59041b505ddb541fc1311d41f4f0574835386475080ab950b41dc9962e9c7ee18daa82dbb0f8205f7f6c898c7cf1c3c0be5ce0c118a450d290836eb303f4a549846076c9a7fe47cf6358400218c37eee8faabeaf2a2bd812f64c8d9550076d5a703d21d2bb00777ed23ce00efcdb2ebb8d70e8b5935e67bd26931ad3d8a7a17383ebd6f2e73706d0e155666378d556d190d9e56b32f3f2cbbc5787f1056699bba11b82fdb6f9387fccf84c699bb05f6aaa47ee006b407f4508a4e5c9dc954d8fa95202143afb184ebd607805ecb4f8c18adb5e86a921809470df84a85e4e09afc11c4903590546bd5846763b4f57b082695c5e074cf40005896fa3873cbdba22e00ac7dcbf317a1d56a139211d205100060180519d8d7e4da02aedc6026316beace70b8d07869d50158ef617f2701bd30c438141adbbdb99d05d15bea3f032e0b7784c48bcdf618b996cc9dd3bd80c8f9a7bcac355974aef0c7dc2912a0595d83a2046f86811a2c740a4d46f1be315919339ac89e15994295265d48c703cc5cafb239c0112d9f10ebff244427061184914ea754c8520f482c474b98e8cd4a4e00b20ded42b1afa38a25a9d4ec75613a0e064e402843e7f1024e35b0479388dd6c19fbbcb102fa42e659a6c2385ac60f605c88720386effbe7d31bef5235da12df9c04856a5d3affab80c1eeb0419c918f27484c64f35b7337938c68b9554a6e83998757364b6da65851cb2085033e948706cc0f4eb8fe50d7ebf1070593f0030954e86aa9393656c6899045d94b3cc9fc6ac4c2899e6eab52b9bf24287262dae1fd33ece6a80d02e9231f3d9364e32b49055401fd8ea253bbdc663acf392ed6ab5fb32f495f487d3e1e5d70778ab0795afe1363454c893cc3e4a430d89422982e88dae8ef5341ba7125fe13d02b81bef17c0b66a9584e9b60dc793e9044dcccd293065720181b7e85a3ca49967fe4a81f2470a4c54c65143446653dee20a589839e575b493c4ce4c445cd004497259066cc13c79e8c220ebeb8387bba02c071031441f3aebd336d0e74ca827dfe9d061fb681471aa5cd5bec0710234dd2d36eff703f7c7ce5a0975fb4571622840022a15d13514b64802298a4444d82eae2ecdf8bbb0234d0f5f483d84ca219de88fa2885bf244dbf4ffa7d458a1588f5a17616cacadf770b222a76250e47dcc620e4b676e2d2a580855cc76b26720efc82d7a730d750e7c262c10298e81968054ddb4b90a2f827728d3fe45843e7ad188882d263977975414aae3312166d43b025381cc6467f03220f1def61cf2efd2fc4ca13995e5601706312056e04b881d25865e1cb58f6aa4a83a69055c1fd9ae47109426089d2d779ba1e5792f822b922626a398202ad05a3493448eec6999a390a69672a04345f16d39f459eb925ca8db3a9d9dc8de9a85e0452ff470089caea0441965d44bf8fafe9006d35500dfeddc2a0efb842905145cceb8139303c8c83fce1cf48518e417e43cd8560041f1c9bf4f2ed7911cf52587ff9801dc74c451cddce9f9187888c70f06945047e4715aed13724c2920609a3bc8ce2f3a80b8a60ec4e13cca90cea919968791b68760f60d29467b75ad124543de9c6bd9ac50794e52885b841d59a2ba8a52a1fb40e87389492e236348bb28dec8bafa3c71bfea4089d64281879e7612de501866c128202e004091d5409c7d20faa0dda3443322760be81179f076b8e18584719be745da96899f03eb8e0d5f2d7e24c8cc4a587ed9d9027475793592613d902b7cf041aa72b1e585ea2425236ee4ea6848c2835ccde8751746de9814200e6dc58306c7512cd994497b2138ef89902df96bf91cb3759ab8a294bd008bf56d983103b519bdb557e9af9d504c7e9ca260e542a4bd00524fba984b3c4ec66ae4a412398f38ad48f23ef49131db76c6acea54ce022c596047c0a851e25c9bd8a5518c2134ea75241f8d7941a0418128984bc92ae9a37db7433b3ca4c3335ea0a46a88e5e619118530e439e134d8bca7864b70b6285fbaa08ff387ca86f69930baebbd5aac0d3109254b0aa617ceed3daa26032cc5f17ae5e0cef826a0994ae5648f7bb1f4119f12be98a28c7e6e7d4a5a96263746c1b10c53b120299e24361fb52f5e732c26c4dcd8432fa65f5a80ee85180891a72932a185fa580529a3e3dc4c4bb3c7ef1352e2dca47d4073c45f24359c213a45bb175b11768442afb57a08780b4741e144ee008d1271d7f41deefeb4ddb28785a3b52fd771d27a4b27287715aa618efce77730e51a058e33df2cc4170fd9ab5cf28de71da517331a444905efded3370367d801c6be150a0532eb72840b719ec36d5a85f8ced0181a906168a8188a071eff3d1cb47656b674c70aff9bec67ae7291cdcc769258e1d4b99bceb469e458fa89fa862576ab136639ad41d1ae012960504978701a40c8e8e6d1be9b1c3e0e554091568e35caf083387b6a19f7c75b489af15054a9820905dcabaf59b049811060dcf6bc06ae76515e81f060a3ac08eda4e83287c50e77f37e8070ef883069a5fd1c57da35dba119a70a59868d43ab0986c80e4eab43215a2f166f13f9279686bf6cfccc4d46b50286160ccd8c1414bac7e73a2e8affdafac79f28588a6241282bc94acabfc636cd727e406d7ad6404529315e961e39706f20592f087272b1ab81ddd4d4e3a51de72300790d1d3eda9c5a3cebd358ab4514654f5095f5b73576991c36a49fe647195b479b2b7a58a8efb5dc7ee24aa6cdebbc23fa4229092316dc1177d556f3b1d2748c23b1143946838138b66b57d63c00879b0fc9666cec650690c7b6a740d2924a6d8278f3f1f0fe272ded871afe17afbcc6faafdc96f4f9b1a6d22cf40e44a96bd9117cf83c10fa1d04452992e69bf7f601c26c1b99ca6c6c1645629c1ad944907852921e3495b9040b6d51e333608d19ec4e5d6e4531fbce66b7ace6e90244c75e064d20cacf73ccfd815129d272e64a3c3329363580eb1abaf1eede839e198b4a4818a5b712713ec0deb2d476e0a440da3c5a84f4879a824796785a7ce68edabc62432d0948844f9ee5f1400547a230f5e2f53cebe3cd830c18aec21845ed9f5de358be809cfdb32b5abb217b34969c57c75950f9f5dfb3b9bb979a1104f279a919407b56ce2e07aa300eb128a628d1863d255a9461ce7e0263b3e1193d6200b4faa02921e587d253261125b5884c8737a83428cf4255a7b47ffc05b2a757d91323f7a1e8d747ed65d960a89f9b8b9b51ca7b762a049c02bac18f418ca6f8c04b96e204f74852829973bf7b10fd912bc61e7344df6fca6aaecb97c68cd9500ab102b269cfadd5c2f3b845f9444532590da2158490e0d443f9d32d673d25c829043d9183705b15c247b2c45ded1a8375ed0fe1d88249920a8aad4c13bf5d21996e22441e19c89a59e04d209f2876460dcc8ad48a434bce781b3cd7ce2b68b73c656a8b8a8bb1fd57fc342f1576f553f122169638b0201a7a56a3550ad2d91ea0980dc2ec8f3624d189eae3273de62ded9303ff52628c302c48265f6114b6112c4103b0caf3f498efbb8febcf0400783619e451f6abe4256768352e538f8258881734903c03c47d4fca8c42bb448c8fb30044e5a440d4f6dc318ec2858ac11eb340a4f8575416f9b0e9b3c79690a86041867d48058fda26c9f8f8db13e0bedeba7e7c95c8d7c87f939a52b317246f5887d30c7e57e1079c09c3bd7f9c037ac6e1ab04a92c71c2106c315cd1b414e9148e8e01940cf814d5044ab6000d5ff88b3db2641d75dfa71ea6a9eb13f8db8f3986b1e9b533a4f7362c21e62de376d20d80f84c89902cace39f8dfdf27e40ef76c12c671f40037d302e096c667a6bab339187ffd8fb5420acedb156090d755957418af750c764a3d3b7eda50dccacd8849c1e8217735dbef4e8663a23fa67c833b0a4da5e5540da2a86e107973347fe6caece97e1422f304688c841435056bbb7f7e679908f443bd6edfb6f22834f043aaed9cc2712eabdb3c06ce830f274b52e264ce17ea97031c4e4a2443d239261cbf043ffc296cd1254bc1020a1203e2efb4f10d3a818de24c98619a8969a2cece9419096f8b1387490dac576b90b51a01e6004058b4fc0e09b2cd67e0e281172d2000d0898832505a61a5cebdc9a20c69b64ebbe0a58f50f604b5bf769e7b263d4cd200797ac90fff5e0b14e8285b39ae123e05eca18d38432356212f3fad7982ea23b90621b453474d523c23299b1685f0fb944a095eed65344ad84da8a71f7dac192b271b0f9399a2d0e2eb40935fc63127e11e373e46c5448ba82928f056db87d89bbdcbd34577e5855e1c695df5e55620ce27cacb0ffbcccb22b497aeeda3338051665058c854f4f7f5f52fade323e2bc13fd9d4b0bbc7a6aa9ab3abb277d1cb435f04ff3e651da617cf16b06752602a7ada0a1512ad596854bfd8955a411eb76014115f619415bb1fa8972286fbc59494be58ac156200825aa84eb07d31d8c8d8e7cde843d6166ecc308fdecdb1ed6118782f7dc90809c81734dc2ca78251007faadfa563747da68e06f5418db4377b43c579ee5a36761ca0ea95057ffbaa57cfe04e3c39ac7e86cff5367b0014bf1209053f2111361b007760819a7d01a581e86402696485f0788a50124a0ee6a3156526c6fa62d59f5e1528a5402c7bd7d5a48e19258763e927d80d4f16d9a2f3b61efdc53a2aaef65ec81bba39adf59f6eda1e754137ca328e78f4a2ebadc385a070b552fd1d05e401855e6bb9a376a958376d550e43e87a2273d9ee1b910ddfb21384f8788f4916a6f86b8e20e2fb9dce2dc5142f0dbc48902f361295192a382f43a4b65a7ad4cada67a821a291b2e8262f19c206bc58ba4cc328dd2cde76860aa8e4888f19fa4e1703685b3f890cdb5dfeb398a3d018f28f3b832de9e6a78d5d6349ca6b41e0ac965a23235bb3924a234a589acb4677bb5689d7c70a0bec12c0b775c7b45c13b2eac9cf3b2cc75bd25319612f23bbbd82614060085b93515751c414d824a20314220912bb59a1f803e6c05bd617a3c4360a6a37793ba6dcc13e2492836fa4f0a48f19ce35690a28e85d0038a806d3023a079952a8963bb25592d1421660e43132293498c19cd94fdd90b562584abc6c83164dc18d6ae00348fe8bd6b6a34eea9c9f0a23d12b3aa90e820000ebbb1893937288b977dcc5fdb60a02eb0154644a3fae27836ddde1f81222d137d01ea5027bf426e32c31e89d423d57c78280489da1232d44c0d571138299cfaf1ff086c378be100cc697044d1b7d5524da1ebaea4b202c544152fd0c1f46b125ee63be605d5bf8598f006fca8c0fdded79e2e82e31a922a89afbd3b0daab8ba9b8fbd979ddfd901cd5d73abbb7ae0dc0e32159cf077cf3055aa6e9810de4ca0c7414cfb4e22201e3b7383546394ce24ce72e6baf8e39a93e94ca400dea757f012327d012a95d640554a8b3903acf4728774bf94c20a8b90706a78adf2d7ef0a77a58d0342baf0cea8567739eabb0d0900194dcc9f809849e69030a5030d79c044dbc30f321d3ff6714612f506cb59383da4b818d4a5e67a144a5c2b27928230e49f8ef9bb81e195c8f548cae54b5aa1552f7cd02df00a8a0c3e1cca05b0690c710d329f34f16da68309db9900327852506412d81436cc698c25fef9b225646e1e5a48a9340da50316b9adb63d7194266a7a127fd5fcc13602d200e416a2633347fd169322dc1e3e183f5e06ba4074f9387241b4c2d6cd124dcc787bfbe50f6a8302257077aa5857d25f1fb245e14d7ed3d727c946affba13e46fdf05821347a2c4d69d2963946251c93f3493d7e7d991573305d88e1dee9009ea18eaca43a51a770d100ac3095193b33749e30bc4b828af8a14ade32ed02f34ec65e95029491389d89452d31c90e3f5cb053ab166336696c464a6cadaaff29b9485adb39521a0349c2a4be70ad9690bc640046534abccb653eca4496809bc3f70450f491f980610a500150eb01a4bb01add9713b15bd8531d533eec4ba66a76a06d6c24cb0cb010b29bacfed6c09b5dc18eb970e76c1c9261616a544758fa2b6abb7833d618741859bdd089fe1fcd76fbdea616e2338a686dd460216580379097640844613f71753963b9d7051f4f4208e84310a4db7e397ab1f501da2a9af7f784eaefbe1298754d2412326cbbce5c7af1d344ff796af2d1363f657882fa2721f6a23c93d56f9d47930d1a5665d85e6f5607167404205648ddf964087d95989da38571278d268a8c8864bc04134901a838b48121e22a74084f1327fd55da837b82fd3870e2be86f5fe03089885e359284dd08bc545b8a04d514e84adb7ac00d09d625a92b3f486c703b3c2c47466efa4c7a778098ea80f0bbdec5c6e99ceee9df2bd98a8d08cead5aa1cdf3e0ca47b363a6b61066ce3d037f7e9043023ad223540605f63d8706251418d415b68661e35f6b69d7f1ffc09440ddcad13aedfe158d502371e9227da9462802953569efc0e889f3d608fda3c40747b578388a3326fc8adc25cbb14a45034a10de348aef853391b36cb0178ec4263d253bbe51b014db24368a3ccc7e07294cd767680515f1e58a0264e60c18c0f07de58396a85ffaa15463094c687f85fb176c110f017d176528b31bc4ffb5eccc40378c25d66688b3d0ce89b2278b8b4f0802d00030f2eb6475c843ca4f54e01e88cc4250ba094a18098382e8484d4ff58d566f454b411f2c297d39cc774504e76cad97a3ed657671642edc9830c19c70b9f67d6803e697e45d567bf1d3cca5695abe26ca789603e9ecdc35c245e62d562aa32fcec3b9140a12345fdbefc70a9220be0e2cbefaf5c9e7dc9d038cfa7009def7973558ef8f8e8cb5bcda43415222a50c80111f0629d4e8158c8782707beffb593d21815dfd679aaf552813a95b406735d192d67f89a4010b7053a01c1a465ce2e39374e77c29a27406580903a4f5af34f0d5068155cd5baba9862a8a350fa81fe2e8689de9222a2de4c2ff484a817fa4a085aa949838b2cc26b961ef7d14fd038225868b8a42de498531fa4eb07bee0ef6439ea37a7a9064e275437447e3e45d5e7af7649ca104a9f9342dbc6c37b41ce68b28119c672e315e0a36b0471d2efc19848356a5ba6156a6f837ae7386273e4f12b285c001127c29b40c63d6108f24ca93ada9220c00d8f216f794512aa57e653bd594fd57e7de85d8c00a8ff7d3e1a155237b42b926ee07dd61078617fdccff9ce6b8dcc442676a10b55f520ecaf0bceaaff338bef3b4c05e9eb62b259dfc396bc648e000e307efbe8a5861d98ea04356782195d1219b858542a2c04cb8b60540682551c12e6e22221e206b2c7fd9308e78ebafc0b1598726d2a8d99e1dc034e9c069df0fc019ed8732494184a7ddee070648ec7d360de8045fa77458076036a9b274a6244acb2ed9d4b9e88815106d9f4d5f59c4c992d9bb543b38e3a3a856ba2d7f5d9db001fa9cf92b7c28ae6e5f1065590f511b736b58769e30bbe11cc48a9c721f84ad87527c89a3b0c31ba7ed8dbddb72ac017c21de01398606d529837ca7f71dcd879e9d5c5cc1a7d1c749c93093b44be532cc3ff4b33ace0c54986cceb9d69e04b36625a6a460e6448a6c10300303edada4a8ee76ff05364780d36588bcb6ece501090bf6e82c3c10a29d3841c0ef2853d7ca99d28c495f3d66d707620403e018574626813fd0f86f3c22ab546cfdbe8f9149e7b353edd54670fe8195fbb14239296288100a6856e796f73eff26bcb37e40e1b9017a2c4084a11f469d85103815873e8b3d3e264d68a6265519b87ed6009a10f102ce30584430883798511816fc9010b22b0de1f0bf7714934ee1876fa588da1cca650d39bfb222eec2f6bcc00e315c61f705f68049f3023a5a3334e603273eef03f8aa7ed522ff182c1d4d61f339110aa1899291052884d1248c30e72d4616d08191c467064079b2d91e7e99eb2146a92864238c2b421696f41009a31a2449261de4088989130ab9e2242a1dab22449aa45d08ab68bb2dc3fa000cb024ae7672db6b59f24179092e48271dc16b97f4068f039c8716edea5d9c24a160cc1b3543c340a6368db1cdb6c1634113be6e07663e55bdbc6252472a4359e1d258100d7a3a9e21c663f806206972936889064c9aec64490281c60dfb02db48aab46f23b421245380ee2e320321c05dcfc498558d6cbb18879ea586fff804ef2db12894fc96f1ad66cb6eae7d593c8580e7ac8ac68410b5a572772ad00adcd130ce64a99855d9f8e323404c30a5212c7b4b08cfa2b6de94e61cfa92bb8d9cde6a87f73d609703f73b5f1bba5b00e9cbb176760123ed2201592464614ade90182713440ef68765f3c5b1fc7f944e3cec50b1b41c1b27805a823b08826889e2871deea55e80593daf0d9b372e4da74682fdced606a8f3d94d3ceb38571cc7fea6a17b2998902bdc7b7c4e0bc9e278ab7daafe7dde6c7b4c73c8de01be8c8355d033ff1b37fdea07df5fc9ff1ef5eb9fa01ba8e7d5068729652bc86ef28dd9be7b893f614868c092ef32a727ba073bf9807e29ca58aaffa58883098adf98b9a08e7ae1493af1200b2903c43cbe251af85a1b0189408cc910012300778317d64f5a12d68dde58ab084afd6897f5892e4903a483f5c2d2117336528aec277649ecfd52afb3581512bf3ec11d2626c9cba5311b8a3064e2cd756326bb91324308c4baff979d47384bb24e50545ad6598fe44c62135f5a6297e64c5ca0bedfdba8e22f80af97d8861ca700a0541f602e3938cb530832f382800bab23b46b2c9d7995ffdc4f47bda097a735e14a20bc1d03bd0189e65fe17b1656f191b5f4272bf1fefc73c1656bf9d6321f9743fb1b7afa68d9593f8a1cb4ea05792cad0f7ef951a6f01358202a99a4ce6ab5a7c920ed7bd41579d2e1478ed75fcad3bdf952f0803beae06799c3e08ec5e40dbfdbdf5620e7d91810055884f7f58926814ac9d836293d6a1cca86003e389f36429d21c2ea90d956cae21cc1e8760a79b0cb23a5cc896c344e763866f9a6996037585567939811dc19fb317c28498c695312ae5677fd24d7014b58d2d9b6505bed7b679cba0559419e9ca5c68d52c7df75fd5808b697afae5672888f64e672d1b712c7e9c808824c93c632a91c0a1d4270b3af3f266037b33336995021895736896dc0c9fa5a3e90611fd58ef4b877313e0fdb521a7b41d633cd8b585984c5fed95aae84d390512cbd8f95be489388010c34822001f266ac0f2d385e7de823c3636ff57a08c558b6ebae4d402359c21bf7b2fa2d0a902813ea25ee966c0ea865b55e963c84cc882f1f47fe8244d181d9f09956325c8126927092a4aa7dcfb1f1170e5cd627206169786effe08fc2ebe6586327a1db26bf1760aab0fc80d4c4ce5fb52405c829df98bc7ebef4208f8eedefa064309c5b738b7597677193c4e96df63e2aecf3de2e6e32aeff2aa84b770fa3168c6901cb39b0da5c2ac4b8c018528534c78f5d26b468275866922356ac86c14286784cab5f13d1e4ce7afe76453be18bca97b3d2fde20c3692e606e4d64acc140eeb931fd32c7848b9b89c2924d8e883dc7c2b37e421b2b00aa4c8bb82125bde88356c89b36998edec167c290d094cc476495203dbd1fa6e08e0a11a074c822f5d4877aeb7916307175dcd815d7860a9f3db28c6e41879b7071ccb8a1992ac601d033d3bdb200514b84b6bd3ce247a5902118fd914e971ad7397823e35803ade9ca892647e331c0fe3a0be96d9e3bde23fd35518caa8ff078f829b35ea40e24357c3a15f488e595f67f6b1886248ec3e63d6f3f572f3f9bac4e69d6a00738baeefbc462de113a850c2dc744478d5f67e7e1ef22be0594a9fa961c4994a5ce83248276cb6ff6d27570543c53df17bda6187f16abd5a783d7898d08877f421111304476752cff8f08060532409df17a3ec103826d489861dfaa9666a6d585c009ef85eec08975b22ee6367e5bbb8c17164089fb932fc3ff43de8a82033150c60fcd1cccbb9c07cf0384071f815b0403d7147ab9eddb45456a626999195ae27c17eb2576ed31154abfd8d697ff2264fe06f42bc725ddecd371ab17f47ae481ef774083c6c63411b24f9b2854bb849eb32393721a041330d778fa91325ada96aee6ab5e874b7927fe087500477c58b9d2c45134963267c981284aa64809ebb2770f1c23c03cd66b5331da7d64a3d3dd3cdb181e2b25bc1e9ad50c5161a0cf16e1ca823a9af5566998b729fd55554d51e64b083829c37db1aa0e97c489cb69aba5d7d90d2d45399fefb12bca0825dcc64c921d66129a6f6812dcb011f769462b9f97b7958d8c1a89b6fa67bd3389e80d215e4e87ad747d391e01654f904da1a00bbad1100474442fd817db0a4e81bcbfcaf0b14b0081f6429fcb7d13742db44e299703f7a09673891585a63f43958cfbffacf02d8a8af7384937b3b53ad32d3f6d4509088bf86c5116e1349658d99013de41415704f78e19485a0b261f00fc5292b0f4a0abc0c1ccc4abab0f2cc2a074bd8c90f26727c2708e6d139a961a05d11c1b3411084501ef9c1a8f6d2176dcb1ea2124a25bf222f4ee91b01e3b242e5357097e233d98da6fd9f683f4a10ee652e24486806f1d0189af76ee34cd9d0073c4115802c81740e859463be596162d5273d4473559a1cd2e41750c0f20363b3db8e35a7022cd6327b7aadb1c33ba7d1428a90f1ada973e605b4ee0a0c242bae7271716a8ed375039c6922fe4ae2ea2fc7493911d0b178284f7bc45a4da283dd8c34d6fb62e0a00608c2bd244e5ce1ecb3d81150cbd32c331c750e78f5c50b3ae322b4c3c0adab6ecc3040b219110c0779c10f4211585d5cb4db7053bb8ba0234f2bce1b77c8697ac46816ccdc4b06d9de1437cce8a50af7dc2e997b7d83ae22dfb0ae0e8a24a8d18a574c8baf2a94a667cf9f4164fd28332b0874307fea846136f75dde0388bf2ec9f0cb513e41d98bd426e650b35c88f9b5ebe52371d808f07ad0b56ead6917d59eb311c2297e54110e41691cd874ac9432d10ee0d15c20d2f5571b3728d2bb90cd59abfb2781b4e833281c88a212f87e05f29da95dd132c65a37d95763d47aab2604c7fd3bf370ea5a2452b719da96a25b622d9a6f099ea4dfa20e81e88db4196bb666d4d129a6960c93988065c13f558a095e3853df7e2901ebce1f276d8cac4ab9e2e37e7f6104a2416048d40ca87d5e86634264df8257b0f291c351dc5a6e7abf140321240d709f46462454b9739da35e30678a76661c9dab336094fee25f1d06491414af1d8a4669509b600ee2270b02e393b38945aa33590ee8cd8b2f64ceccf43a1d6a856ff72b54133a70723e9a64692e7c6ad400591500d50b9b820f8700e2801815c08d2c85eb331fc38a287cb77b6e14520c9f93ed1469985b8586aab016293cd42db48fb11404cc7d21a3a5feb5a0f534cc7d06b55f1fe9000245eee94034222bfc63769e11f5b2e2e9a84b9abe67f914e63264fb62b73b037c105348b94458fa52c3940a801ffd8b00a2dfc0450e19ae382ab114fed956244a38332a102a579f65aca379d82fb93f8e88163b09b5d81e1c05f72b7e3cfa5d18dcc8624c4dfbab5bc3b64f0a23fc5835599ddd1ce0f2d946cdfc872e93498d2d7b56010e500a11274c9d17baaedec77d557e7e4c0cccb815097efb2b0694816cc9d02b1c2737b2089f4360e1127d01b6c9ec6245c0a063f6d95b1a8eb89dfabe2dd19056604775f4693af0efceab3a8334864497cbe391932c4419028d8ab2f42bdd5e51d3a59764dfb7db5cb7ea693ddd487a3a449bdbd76ef43aedeb1c7f49f64031449b060aa0c76c60f8bcd0f3a77781af7a8c2703b769aa53f523aa5f9dde1614043e041356b023acb4ba33730ee34c3013cc3333cc3333cc3a39f35fd68948491b6a76e68a72425b5ee2042782cfebfa04899644a296552f830f8c70363d444a4d90c670af509250a09195deae8b78eb95bee1f8d48fe8978fa0c5a2ad7b3dce5a50f4624ef36e81bb1a32ab5b8e5d3f8939533707c2c22d9ab73bcbed8a3cba2292f616973263845a446cad8a721babad165d7f291887431dbbc8cedf832f60fc2072252faffb662558dbe7fd8f07188c4277bed71dee5c310e920a38edaa3720fedab7346f828445a85569ae5df3b6245844876761d17b29bb5bde201e1631069f5e89ecfc588f0f031e1f3942e4194861f8248e7286c47cb2ff6894a3e0291cc2e8c902d84383f5d99071f804899f9bebabfce6d2f223e737f482a5f0de7c53af58ca367b18490f0e18764cc39afb5eac1bb68bff721351ad4eb728b2b97d9251f52afb634ba2877a8125c516931e34b72b08ca025078984a425076f858f3da4737c763bd79f0b3a3d8b870f3da4bfb4e331bfa77eac3b0f49d1aa5e3ca4cbe56a5c8b6e2db43eee902e7c39f6e665f47d59b3433a5e9ab96ad830fa551364d2f8a843528e54d97bdb2b85cb7c4b7b0e17d8071dd251888bb697d934cad1c71cd252eaacb27e273a7ffe0d1f7248ff6bf6dd56975f2d0ec1471cd2e55aa9214f8467213f296cb000e5030e6915b3599d4ec3174765c4c71b9279b370d9e7baaafd32613254f0451b3edc907ead736c1522eb348a484832cdf0d186848aebb2c9668edf2265435aa7155ae8f17231c8bc3ed6902e765973701d4a737d1b06b3243ed4901022f5766aaf15ff5226ec5b0609c95a39988674cadc2e17b597644c33d040e917e41a3ed090d0c9efe4e54e63fe2d573ece90f8c2f81784ab7df6c6b0000a1f6648db6f8b32f3cdca65aa0cc91c5d8ee905b51e83504a56544ad8e8953d147c9021e9254ffdd3f8c584cfee543ec690b4bd4f5b5d19575c837af021867416d2ebbe98eb57cb921595963e76828f3024be2cc49dcb67dd7a4f140c0911bb5a55adf2da91052658f9cb97e1282726619064e1e30b69d99a5ab37393eb1ce385b4d4b229c3b5e85c5ecedda18f2e24fc3ea4d0cf258d72f70717d2653f59b53e5e7ef1390c1f5b48eab2de24a72237a5a98594ae06d1992d6417eeffc84232f9ea9c936f9acdfac3426a43bdb4ad66cc55f457488ff0317b6126baadfbb04272d5777f8c0daa32721512dae9cb31a78c15b5171552da5ad5a8f5e419b3d0123ea690d621428967dfeef2d852488a95eb31b8f072b98e4521e1e59139632e6b792fcb0f28245dc57941ca67d6d7e113d2390b259ae1457e9688081f4e488bcfd9542ad7f4fe054de1a30929d92cd5bbf8b7da5d9609c98d26373322aaa6dfc712923a6eac780bd5234323840f25a475b8fa3c176abba4f6471292a3eaa2551774b8923f9090b06da9ba2037986f673b3e8e90def7f4f4e5c2767851e7c308c9d1a52f8fb4d9fc5ada0e3e8a90f47c1b26f205edd8d13a7c1021395eec4f23e3e5626a8976858f2124446818a9c163264cf226abc320217993d52b2d01c4f02184b417de4cc54b9d66f4ca8485052424791f41487c177c34a667ed3c0d0889d13269d857cdc528633e7e90982fbca767faca1cb309dfee404961c1ebe0c48ccc6ce3a38db48b4ba54285b6cbcc32e1eb45427b47291ec6e745facb1db3b6cf9b715c8938f0d84532f6baaacedf5317097fd1b1496fe367b07391d6df19b5ce49ed460617e972fced0c1aedcb3983b748ee76bc3dcd71b31e94133550fec0c316e9a065e8cc2cec3dc88d3af0a8455a672ee766c8ffcb74596891f41aedb859bee4d19d454297bb9b7751288b64cc6776f8f8a75ab209dfedf088454265b356f76ad4db8d4cf872071eb048bd5a1311fa0b3b5abe22a14abb3fcb8e9af01daa78b822a9a516fd85771fad37d38a8418cd85f7ce31ba5f2eb278b022e571fb2373cbb0f99955a4c7b5f4a232d11d140f55a0ef99eef9a742383c5291d423a3c8973d74d6bca7818ab4b78ef2dfabf383dee61409339379254abcbd34b3a898b01a1ea64886dff45954de08d598097f71860afe64a5e5c4a314092feb976c46113ab64d8aa4ba6b7e47a9338ae4eafcd8967ab251b71ea24869525de5b2be1dafc66289472892e541ed37a4e8d2a7c7840fc7b79c94b0d12b79667880223922d3557fffa9ce3f8b9ec0e31376177597563db654c04697310212fcc9ca19068f2712afc3e81ca3b92cb3beb034cafd0bc62021d1f56ba04751ea24c5dcc0a31369991d63438516196d9bf0957c8aca211828288dc30c3e1478702299a93674daccf3a3719594db44ba45694ba1553497556d8230be1023055f84f18509d6f0d0443a779459bfd8c16647c72313e92ca42eb8dabc136dbd4a4b0926921b1a1a5c7674f99d9af0a15b316847038f4ba473876dfb1cb3521a858c7795310e8f8146497a5822f19bbc33e4767f41d7267c298d9243b909de55c62069c3a312698d652722e651177438c5831209cf519fc67531df8e1283c72412ef055d1fd733ca7df590443a43577a517fcead0b72203c2291fa2fcad81c36aeca9723820724d25247ddb7215cc62e968f48e8face60eb72af636ec27a7a1e8e48ff68ecb2d3cd05295f133e944e59f9164696151d613cc1a311201e8c60791c9d5212018f45a4367deeec6ab3dfcfd26260e0a188b488d741c897b9b96761c9b1c71e89788007224a20e0718892931c60a89c81010f4370c0a31038560e18e04188b4074d5fce1521f6b72983c7204a1ae0210896ff4bc9053c0241010f40fc5f4a32e0f187f40b1f9151b5acf8a229e90a1e7ee880471fcc830f2a97941314940e630f7ad880471e1242cb155eb28d61930ae121031e7748c6d0fe9cdafb41f7ab24e5528283a5d928f9965e6961c9b443dae3cbf2d587d0aafbacc30e0b78d061021e73a880871c92f26ba5f4911bc4bd748ebc34fa0c334abe65c708c2202161f9961daaa42445e524141e7160d9f16a5cc0030e17f078435297b763fadc233586f4534e140e958567dc90461a7d06073cdac08674a87fa185a84dab6ab386b4accb1632a3c20ba622c1430d16f04843043cd0905c399b53b50be7b24b40789ca144021e668080471992217331a8d5fb9863220949143cc8902e7aafffd7c71e6348f7ca54ed2f6bd15fda3cc490962e9bf57e86cfcc5d3cc290d0450d593e1e939735ed0186a4fb06b939fbdde56290093cbe90d6b2cf7c33857ee9bdbc1d2b87041e5e486a217755cbd8baf75e4cf872241947f0e8424ae37fb8d1b26ff35f0d1e5c48ae3c97e5fd9e77f74507e1b185b4a99c7799353e67565a727868a125e091856446f9a59f17195db4c7030ba915a1b5b6f1e2a6aaf9ea718564ec7241aee61832fea3de0bf4d6202139c14989de1ab972529283453dac30e25185b4dc6aadd098f5476a4df850ba84b1e504c7094a89494b8ef71c785081011e5348eaa031b3e872d1c5ecc1430a094d113a6574d6d4dbd0c1230a490d1ab450d5b71d3ca070c3e3091e1e4e484a4fcf29ef3f695adba3092519f060c2023c96507292038c5ed10106033c94f09f6bddd5d47e12d22fa46b0d19d367f5e2945e2c1e48488af996f9ff357cd0f01192b5ba2fd4abcc08e9723173f98b5aba3c8ac07924cb8308268fa43d8690bcdde41dbaacfc3dac2b2d3954e02104cd23496ccd6695c2566af68f1aa31e4148ec8c10bdd26e20a48b5964e3da98c6d61e8f1f244b4fa44b5d2e2651ee8de1d146625ec5baeebc52ece714d08bb4dc93dbf19cf20b3a2f526fb7c2de6c5c68195e514949e3c4d450c02e029828d55ca972a78e1028243ceaf9763957ea7dc19027a4343de6e26df038afb18438212d5a978554cd6d32e2e0110d214d48e617451763bd85862e6765a59cb01afd30600f6142ea379dabeb4f5fd4e179aba09815842c21994767f11a4f934347891a2a2a28a7055f84812e4409c9f0e263ee15ab0bab83429290ceb221527717d3e7592121e95e546523b39f5f9c51821d9f821c214748ae8fc75721f44648cd77615537486d2fcb22a4f5458a5a9551a98c22212142ba658c511fd35baf78703cb3113284c40bd5d632964acf7934438810529af368cd9e7572a93c214148d7e7ee5ff1b91c8400215dde34ef961bca3765945e791c6f922391906c5ec80fd29963eacfeee66f1a9690369222737e8d6a73685a9d1e905e24cf73e1cfcd44b41095099ff21296b66301630424f05f9dc38c1d9f821e80f022251e5af75b9727f3281306d9454a363d261b4d57542201a28bb49757e3288fef9f63169d2440729174ffe2bc8bd610951dc335b848173db47e979f3fe7f0dc22ad579cca38dd6e19ae09df4a1f455ba40b9a5d2abcbc4bc506a9453a7f31e868ab356669ce195301428b74b963ab79912fd1dd9a453acd973dc8e4eb22527964916e1973a7cdd423bda88f455a56e47a86ce79d5e8608109fe64e58c4980c02271df597ec8117f5e5e9178dd7621753975b88c72455a17766372ffb91dbd1569fbf7283d7b78c72ec88a7469a4bb8ac48bf792cdd947fd7953457aa3f61eb1d9db73414e45ead55fc6f5242374494345f2562a352fca185d5ecf299265b2195e6ece6d9a31455a5c7ee9be3eb8ff079522dd6aa397938d67f93d7b5fcc59bcb347661a06192af8428c32be3848808c22a94cbd5e6bd4a248eb2f672134eb3c14495d9bb5cb79c3cbc5121449ff7266316db539be984fa48ba923eba39427d2e24b22a56be77422599ad2bda0398a13094fd5d62c5bc7e0a93d01d944eaeda59049b3b68dfd494848485872a86822f951ec878c314af5aace4452b9508f32c7161df2020413e92dd7c1c70bfa9578614412805c2229bdfd8ba145688eba5c4cf8cc8d01c41209b9bd1ed353e7c000a944b2c3df9c467ded42eb12c69fac9c61890238020825929a8b494667eaa2bf90555af2f4804c2299bc47d5bf3b3f879624d229a3d6907a7572cd191a209148ab902f235e7a741f2d4824659cf528dee2f58f8e3d22b5a24197bba57cacd025850d9532401c918e9a21d3632ad1cdaf1d208d4887980d52a46726f50da6008411e92f67d617f3df219045a4e45f888989ac789da0b094a034a622d251e698cb31b9f8a266cc9d014944ba18e5a6d90f52991755267c3b9c1191b04df1a1836654afcb99f0d913400e91ceba858c9757a6fc3fd504c4106953f5a2b85eed1bc3cbc1c9a510e9926a1764d43f6eb39010c9d278bebbefbb397c8348c87751031144baa0e1e55e4aa12dfa719040a4b53c17765ea7a770b7e4534e50524e140410498f3777e2255921ef1f1d28207f48e8d7d99e63d681f8216177bb427dbfc6d773258501d287649637cd79dd81f021a12a6e8458a9cb391bfb00c81ed2e5513bcfcd79efcbaa00440fe911ddb19f4147f64be621d9b265ee52fc36d637615b03081ed2eb51befbbe18fd6d84a252c277486ed435c28be1a94b6f8b0e1c6980d821f9a373b54819fb12e100a9436a73355daa2ebb765968c257e2bfa2d24287a4963bde2db5175bd68e6280cc212dbe98396ae3aa7a1153d850d994435ac839aff172c1dbd5207148e6ff0c2b64bcf66584a35756c0202111a38c2f4848c000028784bfb7a62ebc4c7d57544e4a8e05206f48a8dc9e2f17c417438f2e1b06881b52de653942decab421fda1d7cb217a237331c586b4a676175d66b457a9ae2179b251081dd253435ab98d7419524d433a368950ea2af647656848a84d75a37551b72e7ee80c09315f0c21a51cf97214198819d2aea3f36dcb9851d5d9819421f5ba3aaa1ad12985a9eb2a6318261032a4349dbd47818c21f5427ace2cbfe0e582aa023d54021031a43e6ccc0ebada74850a240c292fea0d2e758ffa18bc280e9e04eb5f70f83a70f05eb27e0d4406081892e145cd5efca03c5564be9090ba20a4ee97b3bcc0abb3b70bc9ed7e9dcb9b428d1017840b4953a5bf2fc2c6c45bdb42526cc3beebfabc49935a488f4e1b625ed65c8c51b3902ea7eca2de8e25e2b6cb1440b0903e171ac3ebe8288376b94242675d521d590f55cdfa9395335a74ac00c40ac9d7f7fafb43cbac0bb22a24936ab9e63a95a6f201a1425a85102a3eaf692e6b272b2dd60190292464165f7acf2ea5503e4a216d779b75504ffa65bd45219d3526ffd779224d44298040212da5ccc5f2f845d551b50a8b4134061a252800794242eb28c3cca366962303e284b44eb3f3d2ec8dee5a419a90ece84591c16f0761423a79d45c5ed60f640949b55f325a69f8975e5e09c94c35edbdd956a91e4812d232c377e8a8ff43e612040909d9ef627ed8155ece721b801c211d346d85eb583defc584006284948b76fb38bab5f6d245487e0c5ece30ba1cbfacc54448d87679a41754de8710418690565d8e52a4fd98cb1f0d014408e982fccf396f87792d070942ea3bab501fda9af0edad800021f1a75ef6458db9ecb7a4741a8b4d00f94172533eecdf0a17dfdfda00692329467a280d1a33b588a517494f9e5d0b2147fecb2c2728df7262c28b74b144f5c85ceff2bea8925da4fda3f45c162fd5a1a28b74868d2fbfdc3ddb32978bc4d67fd97483fe393bd358f1435ca4d55b8c90d1753179613e61436f91d2dc25d14595c9b57a69363ee52f6d91103ac4c8f3919f8bafae453a8f4efa625e128d5999f019a44532c71c4397a5a7cbcba282b2d8101fb348ea502ff3e6d1ab367e8c133e64912eaa175ab37ee7c99d86b148fe6a3dad8fd2a58b2eb0486f7ce1652ea67a3df67a455aab6cc67c31724542e7626f487b7735d7c5846fb1091fad48bf561993bc0adb98ae0f56246d447ff96354afeca70746ae22699e52fe0b8f33db5e5491f2f41fd765d6b119ea1615959583858f54a48bb69db9ac2936cb175d34061a25f8818a94ca5c3a95724543954bca09c2f83845c263ce72b2da645f7b3145da57c78cb553add378ff518a74d14ebdf05e50f3f3ba902219e3ecea5ffb7241378a74bcf6cf17225b275f14097f179e212f64bcd55024352653715f72d1ab3550246c3ca716f5aed7518be65a72f089c6c72712eb9e66fe83ebae2f060f173e3c919ab5ff8cb9758d5009de191f9d4877eed477ae7f3fbadc072752f75af966e86c4ea5b0d139586e13c934b2b9689f4bfea2a09ca8a189849ad958f667b29937387c6422a13366d54328d36c1b444c2444abf32f7aae6b501913be96c661887789a4961e67e49f89ed082f5d9277ec04f16189a49ef762561532eb9c3b6af8a844f2a396f1da45d7a8596ec2b7e3d5309448fb7959e7165dd4249259d8dec8caa87551755412a9d77f997378c7a8b5432bf8884432bf2c642ee77afb0d66422229b38ad8d1ed72f218f30d3e1e91f6f2ea77dd348d1d37a7e0c31101f9c60c9145a43cb8b9af58d34ffd2822d92f1ba3d457edfa2c11470f493a173634c82e690e11e9cf1aeac5789d5fccba09df1e2221b2a30e9b44aa6bd672f49b94a8b420ee483939c3dcfa3576a49cbc40c4102971add3c6130f8c535288f4975dcf9cd6a74aa55a121142243744d7a88d26db51fa252b2a2732888498c7525d98dfd579edc5f2253978931511419c9a23496b10cdb2c57f4ca3771a880422a951bce87ad447e8ba80488988ce5d561dd37c528521f28784dea02aef959cfdeb45fc90980d3ae35e182d83585d90a2c28202913e243ecbe6361736113e24cfd3566b6f9c88d6b3ee21a95f7bfef098753ff7480fe92cd5863e0d238508ad2088e421195c7997c53bd7e39b69a49cac941394153c24b57fd62d47ebe8c7fd84848465c7ab4142c27748967a1c2ddf76bc1ac80e6921a5ccfcea97851052133ebc6561f9951c78db262c06db8445c740a3c444ea90eca84b5e7be1bf28e5299d23076f767c0a5a7e65bd192729272b48457935584c840e69fde58e22328a51109943ca5ea68856d3a8af5139247588522927fe3ab42f1287c46f58d1592b028784149bef57e897b9a328f286942bf92f978b35372bef12714352c6d85ece1ea396a3a1494b93414262d2d24242d2226d4806adbc5cf49c5b3e57cd86f4a990325367ed89c81a123247a9215478ec8c9d22a286a4e6dc17579dd385ae59584e5a521ac7d9d1d2f22b398c8e1d2b99868494b1ddf1bf30761a113424de7398f5cfbaac538a24242424bc46e241e40c691d467adab82d4df5ce30435abf94a9a9cbe5cb9074ff20bfa42a3d5dc8c9908e327cb9a4413f654ced189241bc7d14bf311131247454cb149dde95952ed9914365a5c58840240c69ef2feb6c2ea40aade3d53958bee5c404062d272839cc58696111014362a5ad8caad37e3e6d95a49cdc0a0e8a7c219d3b7e08d5ba3a973724e285640a1d3436bdcc9d8ba54817d2b99cfe994196db173c5c487baf4b3dff5cd4a9e35b486ee662f66b86f2d7e5a8a4886821a5e62adf695df5b44d912c24a4be66fa2f684a95970816525ffcb2dcd1b712b942323eedeaf8beafae61112b243f7f84178597937f525521191ff5bc487351fdb9645221a136a45c4f198a4c211d85ae797c350f196e1129a4456711db9ca5abbfe844240a89f3f6a83faafeb2969a3644a090d6713d6ebafd2de42ff28474c96572d95efc449c905ce9abebb6bc77d41dafc6af28a6915206a221d28474c154ebbdf8b22ee6dca791f228286db2b604224c48ae88ed88ba5b2f882a86c812d29e3546dbea91d7d6b9961c272beb3c20a2848412d3cf3c22912424b5a89997761fd587f21c3c33d02b95951616937282b2f238cc1868941c112424f36f75da302e639499b9cbaad16bbd1a660c344abe103942f2f5fd4ff4b5e7b296891821d926e2ba8b42434139b9d88591464a1924249ed22b65ac939426838444a408c97f2fa9d96afb1bad24426a3d3d754b3d0f14448670e9fb5d6aadbf8b8810d2a1735d3feb9769ef8b894810d2d9a6e549a3ca7c41de4b1001423a6f482dbd2cfb5ecc4de3449578ff4a5e0c447e90109a1e84f8b2a88b47c940a48d7497b310cf902eeabc642fd23217663f0adb9ced258e15153170aca85c105e00c410c28b74ac8d51dfcb23f3fb4bc82e929e32175bec26ed1b5d882ed29f5dae97d3349f852717c9d94d5ffc20de105c24d366b7ce5f7cbdb07bc82dd2a3e365d6fe5597e6242139e3597a0424240b89105ba46bf3bfa03947f5af5d6f05a920a416a91321b585cb58cf32bfc649cbfa1ba8ac90b13508a1454af63ca64dbbf18296777e71460912893b187801b845c82c52a37d23d5f676bd8e267c25ebc45354c220213951218305e54fc6f89493cb050c1212961259a4e53f83ab528d695d63c297031555a2c66a14851ea545e9603163a051a2819058a4eee37d3153d67631d8267ce60c43038b948667fcce51aa7770a1e8580109090909a60e12922fc428e30b4a84bc2299c3eb6bd4bc691d3860c15321bdaf96beeec5d5403654726c2b9231ba166a9f2e9e568aa5cfa2c1e4287f228661453ad9fbbff8ca2fae2777ac3c0e95345a525470e8d1206415c991b9eed5b6d6980be3091b2525ae82a3c49411a28a8446bd17b9217388950e964468c65969945e2c0653471a2e21232415297df9be6fa931e1632931782d2c2a2625252ca84508414552455f872e7b9659329f222de47f598cfefd0e5aa770083145d2e64447a9bd5d6ff44a915ef1a729857aae0e27299219a39651480f93b37314a95f5d2cfff3551449fdb73aa2ec5eca8d4391de243a6a7e512a8c3d848022a11ae3175eb81c9b1d8710f289c4ceea4fa9737646d72ddd628627923af996dcc62e280fe66a21a413c98f5ddccebe2527125e2ee7dcf925dff4f10bd944329497ce46bdcf96290949882692f1c6bbb45f7e9bee15928974ebfcdf7ee9adfdd6104c2456c8967175ebdcd63817422e916e196f3b5f109a193d2196486706e1abf7e556339e4a2474d8f672c7f0aad91542896450fea3ad5a7c41563689b46ed032b6345357e69144d2cb1f447b31566aadad0993900ce016219148e6e7da8c2f87171b732190488b6cd17a44c295666f905e0c5e7035c41189f5949717f7d5bc5d421a915a2dee6bb5fdbad04f0823d22722eabdb1ad31be218b48c748d5aba961b4978542149110bd69c42aef820cdb0a494452875c2fc820b3104310910c323d7739b5f010c9a8bab4efb5dc511b443444da75ec7ed9f562e4e7100b91fc6db1a34b6a239ab510ad11291f421c44625e6cdaf788d1c52e280591d0baa875d4ad19c317f7244348209241a98c994e948868901a42009196dde275306f1f8de2cc3fe4aee3bec67c34d30f682eae6fb972bf0f09edbaa94b7ebbbad47f42081f12ae32dd3e9ee66cf443f6908e9a2f745e77e51442f4902e1773946daa06a14727240fe998ba0b1bbe98cb6a552178488a8d7a856a0d2621e40e8917badc3b625e8f3acf0e29cfafbdb52175486c8afa2c65bcb8104287b406a9ba2c5f4c1a57ca750ee9f83ae6a507a194437a4606252bf7d3bb4ea21442e290b8152d7da4e77f2d35040ec9105f76e1b93cbacf3e216f48a917b3bbdcd5fa4799103724c58bedc5609aa395d88684da1c84b87fcda8b5101b92daf2bce0ab74559626640d4917eabcb5967b713d9a19a28684665d3e2f898c42d2906ea952cc8f2ed10e42d090982f08d3f9a2173b44e60c89b37bd9efa1f52d8de3a485e5757062c6454565850cd50b31435267d18c59f59817b5aa0ce9b28e1f3554ebf7a2afc890bef18ce65aba798f38640cc9d4f8059526f7c5b6590ca9794d4de227ee850f8621e99a22e5f686c6f0620e18d2df5a3bf48da99eac4c0a42be909e4f9e8b219ef9bef0c1102fa4858b67078da9bdd8cac141481752ee1f5dd7a58a0bc95c14772334a5561ee2902d24cc36ea188de92084682121f75517b5ce385fab9d21240b497b0d97ab352ca4d3e8a8fc337acc1a5f340e2157489c6673b1efa51b4fe6bc102b24ecbe6caa3f72b3507d4815525f969fb3ed6473fa62ee10428594a6d414ff70324e21f1a20b3a66539952dc2e8584260feabdba5223240a4939031be0eb405a07140d2d809d7ceedf1ab080913093dc04560b8b8e9502046087ea80470058567ee97095951c090001cb498ef608c0220010000074800421620080854591104000ddd24e528000744bbbca0ac901003000072460e54bd458ddc2525212028000dc38400e1c5e48bb4e5ffe1c5da22fbd2ea45b37b83c195555de73e10037b6902c7d995d64f0a8cd5c381e079b1b5ad89163652135775e7cddac5fc63b267c3b722c1c8fc3e0781c7b030b79d2e22a38ae90272d6b9cb88e929204dcb042ea9599b78a321fe19d091f3c1d78387ea5648d132ff1d7c109ba969493644939694139b931d02869c18d2a644909026e50214f5a564c58504a4a1270630a79d28262c2d2252509b821859667c1f1380c70230a295dd71a5c5746ede5dc8042b285101a450ad1395e18b1e45029b10fdc784232668f591daffda9bd091f4aaff17a82432565078a0a19ff621c6411e3861312baf01be2fb4519e489379a90149ef653d6db75baf20613d26557aebd9cebd273883796909cfbd474217478d4e586124ccd9ddc484242751745fb679161e47b030989134fa3fee3c3a8180d1292d7c189cacaeb608f90d62e4d85762f8f16fb1a272befc606378ca06a8ec46f14212133eeb9bc1579199a5625262c3a72a019dc2042d2cbb3aacd65a93bec299fa3a465458505594890f82c2a39709ca4e8b821a4f3bfbc5a97b74f4f3eccc19ba0bb2184f4eace972ff37b4117342d9fc68d20a465ebd605f582d452688e09df49491a8a253780902eebe720377dca848f6f6ffc20217ca4d6de05fd9f5e75a38de478d611b2b79a7b847a91bad7f6e22e3d5ea473597e8a0c62dcc3c7ec22e1a15ef66598b6df175d24458c947a5b8e6afb6c2e92e6b177e631ea9c75595ca47f3edf4517e75ba4cb2a55af8bfce671d716495d2ee9bc7f6294f1c5da2961a4162917f62dbd3d3fa50bd1221923fe445606cd2299aecb625575d57c7ab248c817bdd15506152144b148bba8d995d9bfa35d18162977df2f07ffe2af4898978cbff4f9607ebac2d0b42299d57b369bfdc28a846d9622f37db9ac22a942c6943ad6a88ab497a62eab2f69a9486697299a61350acf172a52db296643d49775a8f3146999f5f6666ee5ce698a745986fc18bb52b7e7bd1449fdb2665d969fedf66d52f0992349d7a77657192a472b7914e92f687ddb0e2251a4cb3c881023b32614c9d59abc752e9fc7389109dfabd16780221d743185bfd2d8d0a34f24eb8b71bfa85aabae1fcf13c9175dd40597596812239d48cab96bd0397eabf81127d2f5bae51edb85fda27a13c9245ff6fbe05f4eed42554d2447c6367bb14bbeebba8e6422253be26c376d3091ceccad3e6bf660afcc4b24b48b9af6346a8994b7ca2b9142ddbdc72b917c155d1be5d39bfc4989c48ecbf55c72fbccba9a444a366a8f0e9d4b22f1dab3d6050d2f1ddd4622a18b9ef37a39ea0289a446e905bf790f7ba327794452caee76a8e6173555e888a44e2bd3977e45eb34ae298c3422b5f1737bc6b05297a3cc0823d21e55674b6bb47fbfa230b288f4e772d17c356dabaa5c1189cd1874798ad3a04bee482292ed27ea11442474337aab50de9b79cb3c445a3ba667cbd1ababb30c91fcdacf6ce75a662152f69bd1c31774c18b5e2e998448b62e677deda5979b32287310c97dd14565ffaa1f4ecf1444da3bf768591b7ff3db2381488fda7b69fe2eae943120d27b9f0b769bc5976f75997f48c917c5338adcb12d35d30f697df7a34ed40b1446fa90d0a0566ea310fd71657c48beac5c2ddd34ea51e6c81ed2326a7ca99a64ce3e5fc2881ed2514b376a6e4eaeb385ba309287f4dbafcaf6ed205de677040f09d52f436a6f1d2e5dd9c6c81d92597ff2d2174584ba50238ed8213532eaf60ff5de59785618a94352dc68be33d39ceef7113a2446870bfd596f640ee92ebc4a5fa9c5237248bfcc85cdf590fa60240e692923f734eae208841138a48ba1bbd5caf4b4d25d78a430f286840c23e63e796183c879c40de95ca92d5ff2d01db65d307aa40d29adcf3faf19852ea7ce081b9873640d099dd94b1f7517a31733460de972996e99ce2a57bb8da42131f29acbaaa3949b2f5a328206e43c921b8c9c21b923b45dbc8ea6bc098b8e1c3cc6881992d9bbf05e2e8698594d4f1992befbeddd05d749bcc5644877ceea9d0baf3463487ec98b59cacc45570cc9a80be24499775851ae8621a1b6f93acf7e6976996048baae97acf8557e2139ca735ca1cb256d6def8817d2f98579a19bf754ea74a40ba9955f2e66a86c2ebcfa5c487ab9b4de397ef8a21e31b7a0984792235a486c77fee6eaebe7e792b390ce526bbedb8ca19b0bc2c4423a68e8b27b695eb367e40ae99dd7f159d363db218c58211d3e978bfa27cabc2896933d2363a40ac9a0b9a0d573d466993c292354489c867818d3d9cfb08d4c21e9e6c530df1de4d9e846a4902e7f505e982f67610d46a290fed845d9e5783f8e402169ba3a65d59e234f486fca74ad95bc469c90f820e3c4eecfd595965a1869425a173f3c0a9d5228bdc4a8008c11b0400525303bc2848497bbbcc2cbe56cdfd11b5942323e97cb52974b7f9f5b3ba284d4e7cdb9e0ba58b3eb45d950098384840d959595208c2421dd2a5e504f5d16e23f348284a4f2fcb934e6922347486b3122e3cbc58c374ace91438711d29e56367e3a11e5e2929567430505478a90f6ce723575dc4688904c59eb256af3c810d2416d0be9517bd176be1121a4f463bb5495b6229e1b09426a4f93eafe8c468090f86287f28dab8b524a7be407492fcbcd6a44cd888e37d246e263da7b596755b789bd48b95cfff89c7c115ea4633cba1ee15f522fc7a0b4c82e923a3533eb3ce28596bb2e925f924f259ffa8bb5ca453a7a327b35e6598468ed40041769d1ef2f46ce97bda37b8bb4ed8a17bcac79923688d8229dedb58f0e792a7366535e0d95334a4e0722b5488b7da9fe69ff3146a6456236c68e41b9ac1fadcb2c125ae8f2db9a4861ef6a13d680882cd259f686a6a9169dc31f8bb42e8677697a864dd350418145529736b393b7d095d2cb0a445e9196eff219e517cf658cebb9221dc4fb5cf4ab15c9122984d87bdd2ed5b2b022a17e2b5abe77c76c6a1509d5418e70a52b3d774a15c9ef726cfdec92ae5a5d2a52e6bac37ed6741f2b2a52b25206d7ca8550a144a748979febf49a2542eaa81a889822e5f14df46ebaac7aedb014a9d3e8c5ecd275d3ebe53b438414692f76aaf8cef15f16916514c96c2da5a24817748ed0bf6f9e316a30100945ba85909d3bacd4ebf9074532bdbad4ca750eba5ffc13e994327afecceb0944bdf8bbc9e74b26914e24367e647edf3861bcfc7256651a3db789a48e394347f5a258f34f13091d56b5aa0873b16215c9446acc0ba3346c2c10c14432e468abefd776b32f7b0956446289946c70ddc5cc5a5e37c6042295489fef8e4e7122f24415a14432c3efcb858777d82f229348a8176d5f545e6c2fb6940b229248a62e66975fcca5f3820e4522251ae74774419eabfc9fe506229048eb147aa4d6e834f2b5931517f023125ff40fcfb0a523ccf2f062c9f6d7083d87641991545efe64aee3dd2b8c5ea8c4302613691c1206845110c4300008cea32000c311082020301a0ec703029960aeab761400035b4c2c4c422e282c208984c2a148241608038140300462180863208a81400c2881d875635647b87ccdbe230f18701ff75e04a8ac4ea45dda0b950564eb7d84cc3f5a0ff2fd64201c5940d937664e1fe2102e0a24c1b8996d8880027a6a33ff9ba473f87fb4888679caee2d399e1ac9b3a3bcdd6e904a6e790bdbefcd298b2fa5dc169d150815c0d50a9a20f2cfed3bc8dfa766116314043773fc366f63c7437e49c3a446133a9976886dfdf6223831855fd0f003efea50866771fbc70c4ea82b73fc74a6ef5d29d23ef1496066efe3fc1c74079951c1e697818e08252041a58cc4e009975d33bff9cda9e2e5ef810f94950497bb3240054e066bdfa042373fe590971e5938f0ca2368f3592432c91b53aafb0d23306aa4e316c5464a70fa1978301d257d1b635224b21a790f7c26a036774ba7daf2931aa7abdf858358fbacbb2525127cfa653f569a87aadf0f785834e031d2f987edba9e8e6040c80ee698d6fa49f8d07785b609b287eaf907eb6694ae884c0bc08f2be8e919d5ada9cd2e176abc236dd6e0d5d8ea4b68148f9ca59f9b4c2062ddaebba436bcad6b7919debafa23edb0b6b23685acf651ec29da3010b5367dc6dc02785e0fc7311cae8d9aa357e922ebbf6be9e93368ff7d8658ad950f666cc66773994e551bc944d8421a7995eafc4b4a61e28858913e65ae30dd672e597adcc02c3eeb0f6c4b1e3e71af8502df63ca717e094b421077abf650cf6330af1f8cd4edb0e90b11790cd64be9a787bd4aae93538f0f24bcfac315b9f71cdf79d38f92e2425945c0ce8155005530c286600c9f6d5b30c90f224209cbaeaa8388ffd2bd07344307ae8804be702b2b9fb8d62d44b3602e34208588209f31b1cbf2a6811b77b128dd1cdf5fdec27059d1218a130e4dee4c03805489132f6de6c015911f944e8d15700d14989726be13f572b872373fed2fa8446e6fb2b02ad9a28fe2dc0ef9a350d55f6008986bdf39bec818c43ff1aa07d3617cc4835515cdc83fdcfbaafd72fa2c680f15112146ec23ce4b99911f82871b067d1641724b44af116d63476a44b7c98c76fd7cc2737ed103c58f63e28bb6022a01d756cdb4903a808518833d0086ca88c15675da0d1628f3c98c1069c10aec9e20320fad47881e4bcc94dba511969a63f664793f73cc4f56841722c296a6cd4fa05737bcefc91d01da6cff0c2a38fa83715bcaf411e75cd71e856759845d5b26758bce73116c56b2e1ddfded07fa5cd1fa3a78729f83ff0afae2946478a08af8d5629bb7c4fd001b0354963657e62be908c0d1021cb51be8803af215c13bf035158a4c117d0157e1a36c40a2e719d89e6aad433585518bf4a06c24c1ede01e807ac5452f28f184305132e187108098bedf2bd1dda989812a6a1bee2027db1c278b834a7787327525af28e66d1675cd1b6cd9b914d0bed84a601a265234dd3014611050f39f635320156fbc501f745321ebf6d3cbb0ed1fc5b29558f7a5898879ddac0a707c65bc30839f21539176c8bc3096241e0c696da6a07af0708559682e63c340fdf6a6ee1548822ee22279c67bfe536160bbf0994e80ab9bcde2b336d4092fc650b79369530bfe6f00c0a53e83d780980791240444dcac1b0a07ebaca7abf25fecd066f5625a6fbceb1918512e6a3477024a7c0e0c31e06cd5f36993c66d59c21b68e72de1e43f65678c3f45602a264845612ea9255fd27d82a1b08bc940cdfca3bcaa1a4e1b9c9e28af4505c0fa495be20df71bb7e90690ec8686b9906a2ffeb69932177482a10f31719bae8163d961d49e3dd83bad6ec121d4dc1e6df3ad20b4596ff4e459b11c328943dd18be8575cec50dea4056b7e3d7370d0bc80f939ed86ebb61333fb58ce2e73719526e26c8cad2e743b42caf27d241682a09a96a9828fb6446c82845c58c12658673ff89d5163b1ab01a65981a03a7410e726ffb8a32581469b0ca342713406d0de2468d54cddc3b431933e070007088d37fcb9f1d96892f6dae5ea7f93093038721e22bd982c4744d058c5379a7db688038b3f14c5a1fc75a9d290d9319b102e292df3fc6813e652cc2f48e29a0a3049917b423df93fef9698b2c469a090ffae68e8c6a7e9daecc1d62766acba3bbc2a38c12337cfc04bb52da8a57db046ddf49a9297096775bb6be05e1fbe78f023763e6c02bb8a13643351508283a95ac2bfbefa7eebb709104cc9baeba66e411e1cf51b76d9814b626bcc4fee007417e4e0022d7053ec6aa630446ec028a091509b64074f00d883138023281385b5cd81cc46f87c2b73880f62e886348b70e815a5cd8e9b9e2487641695be0aa92e6237f0b6569e962fb0e346799a13f2a9c785db815731c351818551bf1c056927002b7dc3b16992d606491b462d9bb03ad55335df11839d0d14c49c6d04cb72c0338005bab7be98dfbadda4d756666f7dc5d54d18d1137bab2ef04e48cf9a7c5acd2829b80b757f9afda71eb086ab8309aa63bb3bca675b609ef133f13210ab11b0d54f3317b49d3885414ad2a4a48ae50c3c491d45acb10ba60f30017ce16419a01d5cecaa922202ce75172a3f5cc6a1d59fc1dc1f0105d8ee72b2af027c77de94f676d5cfcce0b41d61dc28e97fc22920b0cfdfbd6ce2c958de5b2730587d800747cfcae0c311c960e3a6f29cc7383de497be0aa975dbafa84d698611bca406151e9c62f7c1ac857e9eaffbb301d5625d6a6050a0a0f00f59d7d06591115c2f54ca6f400d308dfe7156326d1bf2321af805b112c70b98378024c93bc2cd005fa77e8067967bc4dd5f6036a71a954e299bb1196023b5404c437c7333a1fc07bf276d1f5e823aa87aa22f06a3bfdeaea8411092e395d92c2520a72251b4a281bbedbc6428590cb04ed9218266551f5c6b7df09113938b440bd60f57c03527387ee8c024cb58d7d0326ac6509ec710bea7780d732091a5c465228c629185c6be7769b6b1be64f3482f269b6d4592f001012b49d6cd9383272c47a01f561a5ec7784e0c936a35604a2f794f60943fe3f32ddd66b1077879910f5153a8502aa665219953b7bbb3c38d43778b2ec7e04244f56d068e18594c423d215969d778d33ca9215d01c28678a4744984fd1127d4fa1b5580c35077d0055600229cc4d4d74150ad47447ca2178ccd07b428593caf2a3eb432b43223c41b3260e9eaff5d60d000aedc91ba944f9560c96f232c60e98a2888f39177a7db09013006a2ad016418c30c91cebfb502c7cf474c4a89d311371500b5e28c7608c8a4e9ea24c37ca7f12e8e8d1a0d54c83a49df514d781532767945238a0766a4a13c69ebadac6ffcd9c50420d904d4d2982d0159bf214b4ecf75989be8348a9d98153d10a113170c45f39e74ec6c64c6945556640b06630883db229e1f246d664eee97414999b446fedd17e5649511cc0cd99b510a2004e93f809934fbcf44fcc8ef2b405a5f02400fbe6ffcecfafd607744cc42bb3d3601c2768070551d74354e530f1d2c951d06db5718c8e74a9997f10133fad21a0a3962786f5db88af0d39181847f6d3973160744416baaf23b8a8840c84a612183a165dc5923d4493943610bfced0e0af5aa72fdd00ee435aee27312bc23165832b62eb6515838822a6d9012e850568a7938df0810cc8e8d74443476bdaaac38db0132ddcdff1d6f2c3895d3a34478d3a3a128024fe7a5b019093a7857f5e0c265ef7bda4065af1fd764c605a492039b262157fa160ddd4419ce819b7d70474c25e56aa97a679ca0d0a7d786d25cf3dab7fb76954f01aeb9cfcfcb31c849b120324e5f47a939b337c10bf4fb253d4762dcae01461ab8df66661022977924916c7bc9b6a55a4782fdd3e51eaf2ec835b1e91db1fbab52e9d54990658cfa0c5a66ab8587878157a39585bce70af906d6b3cca382975d3fc5bc6dae39e301edc59c62561501101df094a4ff853dce575d473f6d0ca7eedf721627509d1319faf9c32c49f6b28d5bb3f25f3061b09f7e340497fe17fdb2b748c2629176db3506b831876c6622128ee9616b6beb2552cbf8801947ad629b7cec7498052fcfbac9112246c5d43225d6cc907e17b07e827a28c7efa8c0821d118a39b93de134344141eec6b0942a0e4ca8373d14d4de5a06a5011ec56aca91dc33a4653948860b0e7bd455376affa517d2c9e83e60d548329505f2d8cf33f0d626bb01320ab31dd7ec00778efd756174303ece6706a9c86c937bee7a18bc9bba753c7736d9c47defed902ae71090cf0cedc4be255ee253a1f8149047a1a6bcf7f70e83c94941c32dc23e4048bba96388b5612ae32eb674096da615b18a57e021ecf0be630bce0b675a78ea759172cd11efe72e8017daad6912855f3874863fa8341e43a2d6d99a6e2ef712a40ce9de1c8a77141731a7bc31495fad18beaf2dfff1cb07f0434e804ca08eeb68534590b5022c6046e9108261a9a07416108e8c18851f317339ee91655b985b7816a72cf0a3973e4a9a3d1e2d8b92b526e09107767d7f6cd121f63b29c890444e11bbe32b32b1fe259fa7f1c2b2c98bb4e50aa08dfce23c01c3b719a26129cde71e5606ee9652403f5fe0c1e407fc3db0a5170aafc1641e6dba42838f8c6fcb63044ff59230238a6cad1642233e8de1674cf533505d520e636c713b492acbe4960b231e713183493322f5f83b9008332e087ac8b40bc726e55ff649ef645d3c045e895567c75099d36075b65c63c34ef4807ed0e23a57a8405110ab3e683176afb22bac7ea4382d80e35ff1e031b94caa7f4da11fb165ceacc01b7db53409ea17ae3e0341ff580a443bfa4b8e21ce3f079385286cb925b559944ccf2aca1e8dcd643fc4418939b9c954733c617c7a9ba5d89a4005c98d4d52a5491ad2b61470323c65778d920ed4dd7c7782f4e4732893d929a8ec75ffd6d0fc0d18eff447204c80c141856e04b2d02db4c49ddad31da43a8eb25d3ecb73861e2129734a2c4ee3ba3acd52525395c491d8bd0b3fe0c5abff44dab1574809e10d1e46a581009d586051aa1df97fefc247c0bc16b4464f8d5db09ad064901f7456eb39b0d5de69216df06e535cedff77559b52424bda36a509e8bcab5b34b42ae4614dc7a9f5cea8fd99c79de7f1253c6a631a1d98a6c516eea23173884113b819044c435f618237be93bb0c82e6995e814d2782ebdf5f5c0a138002b0afff91ade2277e828dcdcbc9c383919a3a9ceefb82f57ba8913e6bc2550eb6b1e4693d7310814074eb6208496986cd277396a884955494d9419acf1c77542e99972dc4b8e46a9095185b315f83a0f5e3b11924702c6914f2770166cce8c97830d2d3372208d4b8b57da3208ac8cd3c2ad56d3abb78aba02de82ed58d579e8825301663babdd7a66d0de1b3a427b6e911063957690aeadd47193ce03739d717300f0918492989b7074f1835663551a6c7331849452027d1dd8a2499f8e20c18581813e67f4093afcc34d6a4fd0c4c2123941e3e2c06a925fdabb8a7033d0934bf57d60725ed9dc40b97902ffe301d9fcf9c3448d88432749871f5cfe6fc549d1b75b4a76c6b69401ae21a71a5e791440a922053fe832e04bb7cd59eb08f29d8347593f28838ea5aedadf3bfb42865a7d5a6e01e68b1fa12b7a3bdbcef4fe8cf199d8225caf1987815bfb9c2ae19d0c3af7524018d95e20737961cef3f08ab7275ff9b7a61e0c99e21845ba43c5554ba39840a547027014532444fd46258bd8ab74053f6f3819ca8c2bf58ba28cbfff5088457e867900f77eb17b09652323595ddd976e31d28fe8c6ae6cb94648ba16f235d05a536ba82a4a7f6c29efc0aca00fc4c74198f26e0d37521f28f7161cba255b63b4b97458c44adb9fdbc51bae7e80267851d19b512d3d140a1b7be6001435975c75f293865f66db5e3b984d483d9300db2fadcc23b41fc19b97a4e513907c3f3d8c838bf015e5a3f384e17d4c88d53761cfec5323cd2ff5fd2eed6cbdf36488d12883466b6e232dafc88a4e6bd0ad6caf72cc1fd406138f36f461efce4f3bd9e6d23cb3d47fc4035202fa6e08189cc4daa82cc5efe856324dd069c5491be71714974312a5ab564d4b32216555633c749d5aca1f45a70a561a347777a81b026bc9d5166c1e75b6f3b34081df7dad44e25ac4632cd21303ac74ad4c6e6af94a1029a0bec6188a98b1db61d1a8526e56853dfa40055fd86e4e1d185285c1c56baaf8d03972d473ca8878756d849c6857b17cbd3e3276bf4e2e1c1ceecc5c8fc6e5e0a47745c3fd51f07a3a9c8878a781a3555ec16a0b503cbb0bb7ab73d057212f771783a6c8585ac2c5620c8a54b382c9c6d92b4515662ab5f64368a7dd696f77c4887f26508ea4c82f750caa47041291c2c1e08258af9b4e383c1f84f278d994dfc375e5ed91a8b3b03849312433e9c46c59b00acc63a23b4f049d7eb2cdde918d5a0008358952d47c4f29ae469d7eca9ba64485eed639238deee16a7d709a254a905613e9a5c4b5f4411bd0c795db11977cf8d82d8c8e4cce6920f32f93133fc9b75f20677ae9e052f90dd60ac761cae70eeb113d226eaf176311c7e8731571f8859b78cd86039b0d659d38b03ccee3968af48a8d87f3f6b5b611cd6073e41a069bce5d74a10cf909bd8e45676430e49f6ca16973dfc8d02ee60893028229045bfd8d41b1bd122096ff410bd826c2e408d9269b6960820b244822195ff74c0e2374f7c73145383ba9e4a2a66118c5943232047007e649afd67513214881996af349b81be70c0ea6d4c326b00fe05192340c2e848a43146b10cbe25c416a38d80b11edf3afd71c182694715aa89ab202756f60a2a174cea98fa6daa073ad216a26e6c40d1a1aba3ffa535ca8158ca0424b9f189056151703ecf1acbec8f068133f0a7e5259c64e3701ebbeb04c9cc4a9b0f010ae73a452ceba74c539cbd86f62562d6a3398ca06e61bb31d9bcb548a89da2d3c3cf7f7adea9926a3f1870f2da4e606a7c6564e579f83ec43fb983f0a82815027a2f4974841bca206ff32154556b5547381775595c38271aa5b8a8a0f341cde584015289ea569f515c37bd8a8cc5c5f70c2a84590e14e07974b2bd18d69d3d0b772b48416d456052f98df9c96c9324345aa4a03c55ffe4929820407e8d69eb248dedfc4753b867f7764b383ffc78d48377c7c49bcb8b67f41d55375290a0ab18a440df77d465e8cbda4d33c653a534a91064424090a7e5342819961bfe7dff5d0db3ddeaec85b1c3ace0925702ce88238be3854369f68a28513a986e0e4169b94cb852066385cb3e3e8508726e39b0285d17648f5f7ae68e61052fa2f1354ef85f832c64595d4791033cd76297799f6fc5c150be8d14154a98d5f0e558e0c70f69ef63364b9fdee2bd160356485f596abb96b1302a61a5c9398821fe3932c5aa6a91355ec0ba96960131e5a6d8acb2b3ea8c654d5c7271b06367d9193500d162957b2f1bb3eacfb048e817b985f9c8a3aed9ddadbf2cda1718658f4a25bd69c05218617b325787fd153b170a8874da3031a74330dfdf5beae7e0b09670ec48a2e0237734db4a313fec3c75b93df4f39787a09cf96e4eba2081044bbe7834da18681ba45d8f302304904c561b4f6b65851f1d6d6d318431c95a2e600844ad3ee24cfa0eba94ae93c408da23aff9090a51eb91ab91e12083b18377aa1665eaf30eb91ee8398ebc1c74e0506115d0e76b064e6b7ef186d87f388bdcbae8f365a7d2ae327f3f90c7c39d613b3445be4315e184906035ac1c22a634f8cf9ce8aea7cf8d6b1d3dba83fa018976742ff6f4372d26f3a6c023e744074ef78aeba84e38291202d254551e4726c3c5185a33292341e4222b56e629de813203c839b4e012445849b22edd3135942f4d6e473f7e2dfe752787cacd14a5bc9de32b8d83aa12eac91d39965c8843a6390ff96601bfeb9da58ab831da867693e716269a1d66c381145501196a8b13beddeb5e030a3b595f89b3c87b6b26cb310f0d36f7f0c302ab087704f5c4694e09203c993bd0ebbba399f14f5ce603f41e112466b7ebabb84d724438f8cb97f9ff1f37492a2bfa751b27c4bb5155667264b24b6bb018baf0742f1c3a74f7e5131f54f24b8ef2837fba23844c53fc52841eacf091cfc9a9ca8c93f9675ac515c717386745c681aa40a08315bc9ad8c79706948d8f21b324dea6fbf739ca120edd41be39980fe3d54fdc754ec9aff7978fbd59d63958a69e6918a7885fc3e7eb240c54afe7a0b1abef12c89122738eee1cda555730fe1188a9be0ac10a2fc88aea20ae681d619f9650edbd961d2a85cef414491fc24a9806d087901a26247fae1b572410db416f5e9268b2431b4962668a6b7143e2f59e516d02cdc29daf2ffc74a071c98bb69c445c8844a48d5c9d3bfc4fe3f2f500a937032c25d5049fb0d1742419dca3884289a7c0dd91c55a9bb23d7f7f698e236515eb52002d38399a8298eca195c22228a1d5e5f96f7121e4371f06367f1e8abfbb7aedb08d6e82cacd126dc1fd8ff7767a153a1605e880e55bd742724f99c4ebca80356403c04f6b1bba995d2d665d4562ec1299c04bd94da3a12e4bff4c02531d685ce5bb7ae88be012d79fc83779409f1aa2d71039710191f4f410d2db218c3c1ad8fb53f48bc37ae2adf8f73a7bd57b7005b4f65019d8cad44eb56e11ce9a345ee8c43d3d89d3f8ab7f68c26121bf0b5ebe68d161c10847a8cd0aa67a839def2091ae4f3f4bec7ac62967119bfa915a2a350964ce93a8e42a9780e2044a7a3d14d8cddfafeaabb74cd4f9cf8a8c89c327e74aa8606f97f49751e47687b6e1b38c8713f3868733a038287d4b0817ba56f8fc0a75c8793e9c8f13a2f4b88bfc3fa1bab0d1768c2b99313844a1bb793f5f408d745d7ed5370c48df4f1c7a18d1189516b7967645a67bed2ba23c0509aba4e73c4be9d22858f415157317b444506f4b26da3f58865ca245308229bec930a0b964058c2e78a51afc4920075479314e0b5da1dcbafdfa284add0e6dab0289b3452d8f339d806b17b7d0bc4ba8520c070c7e497b70bcc8b8997e04cd10cda89e3d72369155b1fa1f32372203947303c2b9f9ccdb0608450d7621aed73e22be22c618ebdcfafddce27728581b99f80a0563c55fa9b6a2b2ae756bd90676f2a60779d9ec773370cc14a5b1132108dced1c34b0848d922f1dda44fda6fac31a35d8a854c2d3e5eab0fdc6509ae842a2c2a4b9cfd9e41e0e226090791693bd253389d80ecbc7482867d5bd5e1e5bd6d0a96bc3762c9da38fbb0a37552f261243cd815388ec8ef00cc40c6092f574d3ca64f24de4496f6eccb0a2fd7d099b49b646225bc98d5fa305bd51994d124e677619085672893bd52d8e7b6905b155c65e5fc5aeca02d8629e19953447c8143a80359111b36fa9c4ce73eb6ac982e18f22e0ebe5ead6db1789e9b29552e0f78efb9f9ce634b478154ca8cca2a92425a48dc59a88e9499355244ac1ddb4dc0f65abaf9fbf5e00baa809766a5921f86f22f1fbd35749d34f5374ec77f268f9b3082b1be312886a85b980567165bf420fc4a12464c1b96ad37f6900101a69a00e8e3d141be16b016babaa8d7f3353a1f80c16aa5d0f955fb02c3e4fcd80d653afc8a32bdb74cce935024b42f2ad89134e5cbe6375e1907a2aab0627d56581130832a68de4225f21a95b094013e947958623b1fae7581034d3986ef6c9b9cf14c8b5d5fa4e1599da83ae79f53cab1e712f13f53a7cb7c0db3f9818dea93a936d8cfde62d6ff94ec61580b27a59757fe2eabc3947eef1b7631ba3fa07d95bdf03685604da227b03027cc94215b96cf6c7bd0ca5a84d6183e33b58360dbaf54fdf37fe16002cf0eef09eee375c385127efdb1a21d7d802319b405d3bd4b0acdcf708c4990857159c60b753c409da32886854211e6ea384bc67e0d0187f06aa703b63524ef604a63a5ae1b558a1ba892f40da8a7e869e52296586b55f8c4b0db87af1f62f53ea41d381107a7a2308e639809fdc03fdaa465643fdf95b5da99db0fa03333440cd8d918946f50f35a13b8f03f560e3d22b8cb52952146c4762da860c0f204b4afa7ec1bb4a2e15e57ef056cf546322df80b8ce696489e62c05ceb7e1b7954b9544141e90683807c751645784b2f2f363e7eb74e6e1c007e52e03b0e0fef980bca2e7033ea30d6ea26d154d52ca07c423f4caab424681751ba0db42b8e2bf5b2abc5e6c375d8e4ff5d9dd5c00f4f2f8ac2ece79acfd668ac797821748044b1de4799cc3fabf7b8ef12a83fb912235d5b0274945a175f0738a951198ea5ba13fb72ca3b87c7482484eb7aa7739430501427519498a791566e4a7178800e7b93707e00d1f2a19b01816f20f8734dc8b3ec61f48a7299fd712f2ff2eeef324a528238bb94fcc98c3d2e6a288bd641e12992200688f1d363c3766b4366c0bf1c26a857e584bd04fa3cc36a15447dfdd8c7884f14e2f0a40c0fa806854f932625cd6018b2b458526174174d36a086472a896c0ceadb38dd41f800f8666c92dc36e5761a95276f7df96d21dfa012d44ac8e9effe8cb2ec54d482f893602e5e9da95d049aa242b8b251ba87e3f8115c2b35f0a292b3dac22ab1c222f2ee950cb43be1060f72e64ea741fbd126f4329ead878904393d7599f5f7461fae09b13100103c458da4f649857e4d698a16d03d74ec23eea47fab337ca92cf7ae37f19e4c8b3517cb6b95d9ebb78b36954fe6f381232cb005e13f6a68b511682b94bd377501aefe2f165a2a0e5a1b16dec7b8ff10e4cddccd069dff3a91a55a60bd3a697e0ab17f80653c7f14c9fd98dd1bfc906a4f99703d5d36162ab3d522ef0e851a15f057b0f9ad1dbcb4f83115bb3ae333ed8cfbcd4d16f56124ff603b6d1bf249aad9475e9d95a42645627f45636d0a0d2830e90fa8087aaa9768d4dd0ce9c465e61745a215cf046d0ff72b28e3defb4617d7db17c37bf0363cb88da5b03a06dd3370697e3d8a09ba2f761f8af1a30e3b5a1cfebd4974cf20182cff940d8756841ab7007b372bae7d28bcd1c3e65cf8abaa11f05b5acd561501bdf5077a07ee458d0fa244f596eb99088309f6c93ef1ef8ad712efe75b8b5d2e8108b67c8ed1e263f1ff95c58cf7f50473d4d4824bf8ee8092583f01119e6913348919eaeb9bf626c66194ce06dec23f4ec494a461ee1a46c53f47f2be96e030715b0b9862995c95c578d2a47508d82d4fe072cd1e2152233114764f8846d0c2a933c7ace68437e650c113c084e39de628d253e72c1e5ad1ba48479ce37a5c8ca971ac5b133db5f0ed72ab26f2cb2093db10f22c2775cf747509c1225e2e63789e6582ea49090a14810e392042472a3bcfbaa072810db2887d32869951a0f041bedf0292f534a6ce3fb0ccf727d30e5a951eec112f42bfb79fe477ca4d3691c153a161d14756326053d73b4abb667532dc6609f8340ff030fbb0b274b4fd9c47fd14fc20753c4133695bfd62d3f9d5674e072b1d400705a4f73ba2a700111cc63253898f4ea270d10c9b28a4d3b53b62c4b577b9d68ec6800f1746c124a5b26f46922c2cbfc799f51f95f8cd67579199278627ace6b7d2e8b25310820ff7d553aa4a1bea47b33060583da8fdc4e048887e5fe4a9bdc39a3636301256f5c44e3b61588da6633d9526df8d21eecc0d622366b8ce095dfa85f1c1a9ec054c211c50ce0e605647629cc22df1b9424ae06371876e898e5f02e5303fc162073e5285ab1bb52393c7aa1a415722d45381c80908cb833bc3d5fbb5529dab1db8865138f3d983d2a46fb0a92afb15a1b6085adb02e00bf8cdeb3df416c71c103852f5cc0ebe8b48f1bade303169ae00fac07b7f6b731a3a94721366f3bbcd87a4a1479bf9acf12e246a5f354c5da5a136cada71389be14d77a7233a092fdbc5866787f11e676748da41572be0a35ad65f84a7cdeae24334251213fdf64d75742bfa6bd3a1c91eb8b81aa307c3bf752273dc75db2846f36d2088ddd1616ac6927cc2037cd23fd73f7a75b7d0840fff17ab6987342c14a3be9e32ee75ef4aa90d3270d5c1ac8f88d97b065ee004b69d59fe9d42eef2f60200df93015f641731e75be9d41a0e7ae1e06fadbcb8e70f6013894aa7a15505fe8713a636ead0d2939b81e9253e7c01929915040a6ca747ffb6fd4100224473b8dcd7d72ab1e9f8176be3a9a002401962545302406e6947fe63d6f36e2485afa5b116445c690a70c48f29e3efb81d117f609a7198a47a72bf1e7f04b97fd4b585d74dc18b888124cf15b701f38492e42a8cf4b4bbab9ed25d38d8ddc22fae004bf98da86bcc70d3656c12cbb91b483d06509272192251f7f89bfcdef570b21535c6f53a010d43459ce49d00668e9407446792fd0b5b5f89f358ae286d1180b1c7f8b7ff6ac14e396a628a6dac99c30ea70b029c5a8a7638a017ccb05820251212cdc9254cb391ada6907bc52505cfb54096deeca0708c4bda291817eae0e46688a2a5ce560e669f57d68a509199a0153007d5ff00a6b090a2bda6b51d4dbd29e9fc9b9f1db27c8b0bd24f7dbde59e42f065d7e916b2fbd5091c821c0a841d314a635406bda84634b183171b2e78dedcfb2aec50b2eca64676ceaefa2f58b246e69f4330380a24bb4843db0d1fa020230f0de090822bc3518d84382e148aa6691f7503ef0b8ee71c67be15fa4355cfc10090b260033ac6845ce4d04f7bee281d6fdd4b670cf2e10bcb7a81e956862c81d99baf896b3d5f48de20ae8f8a5829d5ae3e699942610a692a295ddbcecf09b03b778d19d7ba08a29271c341eb34b83197a2783d95c9847beea1ef717d7cf5fecd7250473d4195808ffddf7b870f52b8aefc42b3e89ab9baac3dd13197c1c5ad34e4884cabb1147aea4803d0019aa21f80cf73278e2906185d743f759122e9f3194b8328b8ea58a181eb3869dd187701628dbef97adb404130795b5d795541347f3b1c25eed7edfa8902228941196a9a0f2cfa345aa99bee485832ec0410a2361e44cc951f1917d06d4cbdc957f947b43f7132f5323581c2e3733830e111aea31664f19df8ea6841cb79786abb52500c01103beb827281cd5626a06f2c009c08b157128b68389160e28c09d6c819719c2083cc57f5241443173e8d2657148d07949aca1017af85937e16fe8c14666336d81b8c9b7b85db672a", + "0x3a65787472696e7369635f696e646578": "0x00000000", + "0x3c311d57d4daf52904616cf69648081e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x3c311d57d4daf52904616cf69648081e5e0621c4869aa60c02be9adcc98a0d1d": "0x1ce063247ca37058db551a8d99f2f15cfede61fc796acc464a9cdce4c18f6a46597283ea6b8648673305a3e06be6dd83b7bc1840081d50d4deef1ce53eba21e914248dbf89d86998772b66900d78e98980ea2afc3c8fe5b93f4b38052f3018a2301c346cb44aa03f8995eeee230970772d6268cd7606740f269bb4e609a01a3a15dcaa0b4c6840028f6d4fa8c460d5a7d687d1f81c9de453ef2f5ead88767fd22af0d0e90c36f95605510f00a9f0821675bc0c7b70e5c8d113b0426c21d627773b4a69b6ec0eda668471d806db625681a147efc35a4baeacf0bca95d12d13cd942", + "0x3f1467a096bcd71a5b6a0c8155e20810308ce9615de0775a82f8a94dc3d285a1": "0x01", + "0x3f1467a096bcd71a5b6a0c8155e208103f2edf3bdf381debe331ab7446addfdc": "0x000064a7b3b6e00d0000000000000000", + "0x3f1467a096bcd71a5b6a0c8155e208104e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x45323df7cc47150b3930e2666b0aa3134e7b9012096b41c4eb3aaf947f6ea429": "0x0200", + "0x4dcb50595177a3177648411a42aca0f54e7b9012096b41c4eb3aaf947f6ea429": "0x0300", + "0x57f8dc2f5ab09467896f47300f0424384e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x57f8dc2f5ab09467896f47300f0424385e0621c4869aa60c02be9adcc98a0d1d": "0x1ce063247ca37058db551a8d99f2f15cfede61fc796acc464a9cdce4c18f6a46597283ea6b8648673305a3e06be6dd83b7bc1840081d50d4deef1ce53eba21e914248dbf89d86998772b66900d78e98980ea2afc3c8fe5b93f4b38052f3018a2301c346cb44aa03f8995eeee230970772d6268cd7606740f269bb4e609a01a3a15dcaa0b4c6840028f6d4fa8c460d5a7d687d1f81c9de453ef2f5ead88767fd22af0d0e90c36f95605510f00a9f0821675bc0c7b70e5c8d113b0426c21d627773b4a69b6ec0eda668471d806db625681a147efc35a4baeacf0bca95d12d13cd942", + "0x7474449cca95dc5d0c00e71735a6d17d4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0x79e2fe5d327165001f8232643023ed8b4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x7b3237373ffdfeb1cab4222e3b520d6b4e7b9012096b41c4eb3aaf947f6ea429": "0x0500", + "0xb8753e9383841da95f7b8871e5de32694e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x00000000000000000000000000000000", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb31a487e6cc5c348d84c0aa0240b2d7485675e52cdb283a87973652f6acb42c830a5a5faa80f7a707e": "0x1c346cb44aa03f8995eeee230970772d6268cd7606740f269bb4e609a01a3a15", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb32d8a863b519f21b700f379b621bd73c45c7d155d2a1fe6a04649e3ece7c7e03b70b3a6242bc7c127": "0xe063247ca37058db551a8d99f2f15cfede61fc796acc464a9cdce4c18f6a4659", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3313cc789e5100ca680b6f570f356fef7b891afa2e1c30fca89bc7a2cddd545fd8a173106fce3a11f": "0x4a69b6ec0eda668471d806db625681a147efc35a4baeacf0bca95d12d13cd942", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3624ad9e747f9464220d8c795eef2620fba2bde74dbc36461c07998ebf600ed265b746c1e05c70606": "0x248dbf89d86998772b66900d78e98980ea2afc3c8fe5b93f4b38052f3018a230", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb368a58d3eb991155a689e1a66fa33b75f66415021aacc4fa23f49306a3c21407748b8b2d39b4abf63": "0xf0d0e90c36f95605510f00a9f0821675bc0c7b70e5c8d113b0426c21d627773b", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb39f053c2746e722456610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38": "0xdcaa0b4c6840028f6d4fa8c460d5a7d687d1f81c9de453ef2f5ead88767fd22a", + "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3d21fbce2a623d5a4049bec59fb5fe6adea4578250578e89dd7e51ad88c7c92493d6f451c6680925c": "0x7283ea6b8648673305a3e06be6dd83b7bc1840081d50d4deef1ce53eba21e914", + "0xcec5070d609dd3497f72bde07fc96ba04e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19507a74cdfcf05a85226175726180f0d0e90c36f95605510f00a9f0821675bc0c7b70e5c8d113b0426c21d627773b": "0x689e1a66fa33b75f66415021aacc4fa23f49306a3c21407748b8b2d39b4abf63", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19507ae4ba128e21c1c36175726180dcaa0b4c6840028f6d4fa8c460d5a7d687d1f81c9de453ef2f5ead88767fd22a": "0x6610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19507c0de6df75d99ec461757261801c346cb44aa03f8995eeee230970772d6268cd7606740f269bb4e609a01a3a15": "0x4c0aa0240b2d7485675e52cdb283a87973652f6acb42c830a5a5faa80f7a707e", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19508f578a71d93450886175726180248dbf89d86998772b66900d78e98980ea2afc3c8fe5b93f4b38052f3018a230": "0x20d8c795eef2620fba2bde74dbc36461c07998ebf600ed265b746c1e05c70606", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950a074c92c894f26b161757261807283ea6b8648673305a3e06be6dd83b7bc1840081d50d4deef1ce53eba21e914": "0x049bec59fb5fe6adea4578250578e89dd7e51ad88c7c92493d6f451c6680925c", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950a273e8876df6fc8e6175726180e063247ca37058db551a8d99f2f15cfede61fc796acc464a9cdce4c18f6a4659": "0x00f379b621bd73c45c7d155d2a1fe6a04649e3ece7c7e03b70b3a6242bc7c127", + "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950d017874cd5fa32f261757261804a69b6ec0eda668471d806db625681a147efc35a4baeacf0bca95d12d13cd942": "0x80b6f570f356fef7b891afa2e1c30fca89bc7a2cddd545fd8a173106fce3a11f", + "0xcec5070d609dd3497f72bde07fc96ba088dcde934c658227ee1dfafcd6e16903": "0x1c00f379b621bd73c45c7d155d2a1fe6a04649e3ece7c7e03b70b3a6242bc7c127049bec59fb5fe6adea4578250578e89dd7e51ad88c7c92493d6f451c6680925c20d8c795eef2620fba2bde74dbc36461c07998ebf600ed265b746c1e05c706064c0aa0240b2d7485675e52cdb283a87973652f6acb42c830a5a5faa80f7a707e6610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38689e1a66fa33b75f66415021aacc4fa23f49306a3c21407748b8b2d39b4abf6380b6f570f356fef7b891afa2e1c30fca89bc7a2cddd545fd8a173106fce3a11f", + "0xcec5070d609dd3497f72bde07fc96ba0e0cdd062e6eaf24295ad4ccfc41d4609": "0x1c00f379b621bd73c45c7d155d2a1fe6a04649e3ece7c7e03b70b3a6242bc7c127e063247ca37058db551a8d99f2f15cfede61fc796acc464a9cdce4c18f6a4659049bec59fb5fe6adea4578250578e89dd7e51ad88c7c92493d6f451c6680925c7283ea6b8648673305a3e06be6dd83b7bc1840081d50d4deef1ce53eba21e91420d8c795eef2620fba2bde74dbc36461c07998ebf600ed265b746c1e05c70606248dbf89d86998772b66900d78e98980ea2afc3c8fe5b93f4b38052f3018a2304c0aa0240b2d7485675e52cdb283a87973652f6acb42c830a5a5faa80f7a707e1c346cb44aa03f8995eeee230970772d6268cd7606740f269bb4e609a01a3a156610a5024c2a5db3d02056d4344d120ec7be283100d71a6715f09275167e4f38dcaa0b4c6840028f6d4fa8c460d5a7d687d1f81c9de453ef2f5ead88767fd22a689e1a66fa33b75f66415021aacc4fa23f49306a3c21407748b8b2d39b4abf63f0d0e90c36f95605510f00a9f0821675bc0c7b70e5c8d113b0426c21d627773b80b6f570f356fef7b891afa2e1c30fca89bc7a2cddd545fd8a173106fce3a11f4a69b6ec0eda668471d806db625681a147efc35a4baeacf0bca95d12d13cd942", + "0xd57bce545fb382c34570e5dfbf338f5e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xd5e1a2fa16732ce6906189438c0a82c64e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0xe38f185207498abb5c213d0fb059b3d84e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xe38f185207498abb5c213d0fb059b3d86323ae84c43568be0d1394d5d0d522c4": "0x04000000", + "0xf0c365c3cf59d671eb72da0e7a4113c44e7b9012096b41c4eb3aaf947f6ea429": "0x0000" + }, + "childrenDefault": {} + } + } +} diff --git a/cumulus/parachains/chain-specs/people-polkadot.json b/cumulus/parachains/chain-specs/people-polkadot.json new file mode 100644 index 000000000000..083c0fbf44a4 --- /dev/null +++ b/cumulus/parachains/chain-specs/people-polkadot.json @@ -0,0 +1,2963 @@ +{ + "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", + "/dns/people-polkadot-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWKMYu1L28TkDf1ooMW8D8PHcztLnjV3bausH9eiVTRUYN", + "/dns/people-polkadot-boot-ng.dwellir.com/tcp/30346/p2p/12D3KooWKMYu1L28TkDf1ooMW8D8PHcztLnjV3bausH9eiVTRUYN" + ], + "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/shell-head-data b/cumulus/parachains/chain-specs/shell-head-data deleted file mode 100644 index 032a8c73e939..000000000000 --- a/cumulus/parachains/chain-specs/shell-head-data +++ /dev/null @@ -1 +0,0 @@ -0x000000000000000000000000000000000000000000000000000000000000000000c1ef26b567de07159e4ecd415fbbb0340c56a09c4d72c82516d0f3bc2b782c8003170a2e7597b7b7e3d84c05391d139a62b157e78786d8c082f29dcf4c11131400 \ No newline at end of file diff --git a/cumulus/parachains/chain-specs/shell.json b/cumulus/parachains/chain-specs/shell.json deleted file mode 100644 index a02734316d32..000000000000 --- a/cumulus/parachains/chain-specs/shell.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "Shell", - "id": "shell", - "chainType": "Live", - "bootNodes": [ - "/ip4/34.65.116.156/tcp/30334/p2p/12D3KooWMdwvej593sntpXcxpUaFcsjc1EpCr5CL1JMoKmEhgj1N", - "/ip4/34.65.105.127/tcp/30334/p2p/12D3KooWRywSWa2sQpcRuLhSeNSEs6bepLGgcdxFg8P7jtXRuiYf", - "/ip4/34.65.142.204/tcp/30334/p2p/12D3KooWDGnPd5PzgvcbSwXsCBN3kb1dWbu58sy6R7h4fJGnZtq5", - "/ip4/34.65.32.100/tcp/30334/p2p/12D3KooWSzHX7A3t6BwUQrq8R9ZVWLrfyYgkYLfpKMcRs14oFSgc" - ], - "telemetryEndpoints": null, - "protocolId": null, - "properties": null, - "relay_chain": "polkadot", - "para_id": 1000, - "consensusEngine": null, - "codeSubstitutes": {}, - "genesis": { - "raw": { - "top": { - "0x0d715f2646c8f85767b5d2764bb278264e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x0d715f2646c8f85767b5d2764bb2782604a74d81251e398fd8a0a4d55023bb3f": "0xe8030000", - "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", - "0x45323df7cc47150b3930e2666b0aa3134e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", - "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746b4def25cfda6ef3a00000000": "0x4545454545454545454545454545454545454545454545454545454545454545", - "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x08147368656c6c", - "0x79e2fe5d327165001f8232643023ed8b4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x3a636f6465": "0x52bc537646db8e0528b52ffd0058449e04ae95c504114c108066940e98db59ddf6af6efb57b7dde0b64469d187d03f0c9208338b0a9eb6f31f3d0dab728101fedf5603adc13d96d400acfcf610cbaa56a582dd86ca95fddffd6def4db6dc52ca94520a3b115310ff106bf4ed568cbaeacc358aede3df1a119009a9ebcf35e2d7a3228081c842f12de71abdbaa558cb26ed8b1e4708e99b4ff5c2375fd2f34d0ec57cfbd42f3fd5d97f5aa37e47cd7ed70809d6d09020c290c54f265f38c2ab0be9118597d725020bb23c10d6c13fb7f4884c8fa6e0f2cf298c88f5f3032ea882fcf98122e8e0495e70f043fae5cb1e607e1299610c252b7e1255b1c232c34fa21498e115066390603046942db480072de0c1b39330226be59f572cd8f2e5cb6b10269b007d9542fc7cf21222f843fae59b5318103d628114fe79931f283d51e9f9a75d5c15bce0350e599606d1a329c8f0cd3736e7f89cb121edeb96bb140b32b45fa273c6829cfff4c6a947537879760a23c23bf8e70f13c2fe56aaf2ec747295679dbdc5c9bfde04beba1e4db182576c487ff9f2ea456f9f1762e0c5dff89df20e8b6fb74194bf31b4cf6e71746e291684a5f3c586ac37395579a61ec5008cc780708bfa2ecea26fde116788c342c80199fb2c9bcc686ffec3968b43fae5cb97f5c688dcf8f56db1c98c2f80d87876587c47227e1bcf6ef1a5584721f676c680b09344d62b9ba61e51a1e589f85b4ef626fbed7de33bde788efa1b89ac572f72cb62581ca47e14d3de2e8daa8777b15d2e3e89a209e751c43c5174b9f82453acf90f6b9cea384248af7228e69b0ce53c117f93549cb7ab17bee72d97077f9746adc3bbf8a4270a232df8f2e5cb1720e7967bbadceec10ced97a702c5819cb3bae506f37c352a18ff62f39fb65ae4576fb1df0a5a40a6fec34f54cb154ca86fc2df8125fb46640ac6ab7754309ebfaf8efa86b7dc2587b79a9bb6b6ef06cc04418bfc1d950eaf1810ffc31cf78bd6c91675372bd6be15c380acbd415920f692b6d8715d310664eb21b082648d4d99a54264cd8378e5e2082578d7311959c20b07443d31deede0d3a4bc72e7a62ae2086946ed3be3875ec57d1d3e4128974076a2f7eb166cff61783dfb7ad9b7bb95eb12a2f7eccf15233274837de3642095cf7daee4bc74f8e45cb10428cb49b9bea85f5191e14501234268408dc378e709e0d3341d41013ecdd20f9fa66631824ffcce7ba878e744b04f03e9174db37ccdcf9ec7a1bc9ddba558107406c25e79c380ecb353d16a18037eb8abc818907576c682d8dde2d8bc00f6f5f5c586f4108c9243d639874f943bb7a8a85fe293f3acc67d894f7a7402162874e796553915a1577152fe288771163d152957cc882227505464a37f51685d5f31210cc52f9fb8bdbcfe50e41666b184406fb7ba1d6c87edf6a98eb323e51052de9473a7ffc3941482eeacc52cab2f224e5e6e294651de0dd961905b1b71dad7db39e2b4b3536e2d96809f57dd31295f5f8c083be50d849d72c5822877d0895ee5d65eaef225edcf61f4f29e5771ee3f77feded07e79e85647a2f7ed2f4e76de73bfa154ddd1fec38a0171de4fcea27f4ec5d92e049d72ab31204b2e5f42f4def22543eac5c8e88966be72a2eb496e5d975fd77579f94a95a7fd8a73bfafe8dc524cc872f9ca2d521c32c0aff240ef38f9a13b270571de3eb45fbe72c51450f49554ddc11810e750b6ff34f55cb4dad917c87e7bcb480bad686f1378d1dc6ab1a41863ba32d97a49bb302ada858025a472e894abf3450a42f2ca7f9814f515aa52b1c5b88709a99c1449bece0ee3dc87be1810e815ccc961d3c6c626dd1fde5db762f62dc58274653236e5b0491b164492b3e849fed316293aafaad8647fee3b27c526fbce2dd665caa92a3aab97bb6186fa7180f4438772bf8a2b8528af9c14f59dab8ffd175d79d41b9f7a5ad0107ce74328afe415a36c9a39afdebcbdc426e8ea2420fb904d0a23ce73edc2c8e883788b8a9372e896a5582567d1574e8a739fe430ce206bf4437bf4aa3c2487fed3a4b85e45f61f86d70e352acee64f0eed3b59f4f645611555898296216c59c31e62500620c52ce5129bd63336ad13914ddfebd7b7c7afaf17c127f7ebce27c5d245caafebb0cf022d11beae3a2b85f4a8d93b2220136a07e2e7af5bee52f5317bde1529a07a67b9e6b3e574f2edb33242cff04e5269ee1a9bbb280121bc80e50b907ac7f9c4f77c9ea4a88aa77c3a79e7aa3f5485987a2445099e689f924a348c1fea2f5ffe492a4fa83b29c2c20b509346f3897772b6cfead97fba23106fedd5a2ba6216d02b44015220be9d6c11376bc1b2f42aea1ad813285ef43376656f47cf0eaf8c08eb275b571680ba5a961220d3a328bc703eb1b39bf8c4cc5164f1dc40cccc4c58eb1b3d094b5f7566f6ecd6aecfeb797723ffd13779185f904f731faafa589f3dd97e076909db635ebec94c8cd5d7c67eacc9bbb87c930b467d2c59a31f32c0afb32b46a4192d262433faf58b4ffa6cf4ab9abdfe50d4cb70b0f4954f939d7d7d36b75aecc9d89bab2b46845da84965534bf9c345bc10b0940059f31e3e4dd8834f3333f169f6bc73e744f0a9bdf3129f144b1c8ede790efb309073e553ff2ce21dbbf31a3eb53b777ef169ddb9ea3829a4474e2c2540e67c9acdc4a7e9dfdeaec327fe3e7a62e5db2ff661a01dcf3f73be5d779358ce5567f67cbbe5e2beb5978bfad6628d4dce357feed8029a53fec396c5eaeae284ef5ce374578bd01563398b9e7565544ee7cd7f9a237417f5b7c50c3a773596d59762413a6c6a5ff7b891a38bd3dfb9d5578b952b06e52c7ae83fdc98aecc84269693a85fd9e49ce4253e356fcf69bb72ae937cafec9d677cda8dca266593e58b05d96f6cb2e4b49ce41bf5ad48d4cf6e2deb368c8bfa5c7ae7b07da67020e59dd9deb92acfcc79e7ed3f0d63e5a498c509ff3963aa32179bd61b9b9eab2f1654499c21944387d7b3532f2a16e42464137b566a51df61fb342323232323a07693fa689d6fef79fda1a85ae785a53e991e4141c6eb11145d78bc1e4191c55bba23d353a64750a8e0f5f5d91b1340760445153fdbb3c37508b57d947766f6eb33fb095f9dbdf1c9b9ab433ee9ab5b8d0535394446b98b945b7b51fec38c1951f4945b8b09794ec9f9fcb9c558d090987ffec32deebba8cf5850736b2f2a3e574cd9346b7e2dc59c9c4ebc732a4ef894bf389f2b9b28ffe917f5a938db8bfa8a3949d4cfa675d5e1b7ccc5a26193a9ebb3944fed13beba6ed46f7c6257b73aea73dcb7b8e37ee3d3babac557c7758b47d65ee38d91356f675f2c88afc5580e91ad5b0d0b5a5facc9c62676cb5d8bad2bd652d9c4fec3d65e1bf71563807e47fd22defd81a500c8ac18d599fecea7c6a676754b77648b05ad2b16645fd9d4fec31b954d137e7b0032f6762be393b249bdbd864febedcaa7fd097f66df6eed95f149bf5db1f51ffe618e3843e0b3c367893384bd397b9344fb2b954db3bdba6242d6594ef6f51fe6dd24584a808cbd5df9344bdfde5ee2937a7b0e9fd6db1bfb2c507bc627e5c2065cbe5df9a43f6bbe5d755a0af9eb0f45bb412c1522d323232e2ff3ca05942baf3296ea8b2293af58d410c553af58d250c6efab8da5a64c9db5ae7c9aea2b954deaea45bb332c3d329af24a59ca93a9b3742753f7b400e40553484f0e2f0e0f0caf0c4f0a2f0c4f0c8f0c8f0bef8bc7c5cbc2d3c20be361e169795b7867785f7860bc313c2abc2a3c2f1e973785f78497e5e9e04d7956bc123c285e94d782c782b782a7829782878207e59de0b9e0e1e0dde055f16cf06af068f0a4bc193c19bc183c2a1e0cde0b1c196e0e4e0e2e0eae8b0ba36de0d4e0b83838bca3ae82c570657066e829382f4d856687ae8223833b432ba3e9a1e5c119c1a5c0cdc0c9c061e170e09ce09ae098e08ee092e096e0b47057381ab81c3818b81fb42f4e076e05ae8a1b82abc201c149712570460e8ab60747859be25ce0b0b820b83b70154f8b77e525c19dc041816fd070683d683c7839705f7062682374111a8bb6d244e821b410d6047c85f6c25f3412d80aec054b81a7c050e02a70172be5c161cbb057582fb60a4b857542103adc97a5410420c001258a68200318b840050e70c4c7007a00bd2d1e1326400197078787d784352a7242822746208210380182261f2062b264a8092694782089d044f2a83c1f382dab048706c7056705e785ab4283d25cb059dc145c96b68246458bb25e78667026682960373430da96e685b78366a5a1a0c160a5d05ed088d058e0be7065383db83d74165a0c0d466fa1a1d05a68366c150d0637468761dde0a27052b827ac065e037771547058705758315c1d96097bb45dec11d60adb83a6413b01a381c3d81b6c171606cb86b685a6a55da159a179c158ec969dc24661b95828ec1316cb6ab149d8256c1b56080b84dd01a761b56c95cdc152591f2c0ff68ad5c16a61bfb0536c0956066b83adc1a260a378c010053c23210e28c2009cc5dad76d68a8b88f30416203459a40e2c812458a58db4a283952a40849f748920d2041a4e4031c284294c4912548945082a448911b07d332502638a0044991248a30c10125429430818408892449983800511247922461e20041740c8890587244c9910ec4a6429984e088501126458e28c14412479428c224044786286102091326471e70a35fa02040d2c42f3922b48489091089ad023d42848412489220d1a4c8910f1cf9400320a0c4910e7400090804d129502642491c592289964299102939b2e4c8124a90781b2941c2011cce832681848912244b889c38522404499a680289224b8e289104c907808492602209500edf413d5004092224944082e8c80264d80e2240920409244448942099c17250a1249848b2812247883e90c411278ecc301c74091307b8645a0c8a8b2b5bbc16597a6464f45bd4378fa7c053d826966aaaaa3a76765cb75de675ccddda39d78dd9355e755ba3b9c66b6d6b40d7dac2d71cc2ca44ea6632c176bb37cc6d9d73cbed9cd3e61cb3e55ceb1acc4d5114e51ac31aae063b08bbc1aa2184eb1aa9c11a4e9d53e8b4e1ba57c335e6edd61a1031ba95bb6e3b07371cadadd3f961d9ad5bc7bc8dd7ed2e4376ce396eae313be79a73ee6a55b5cbcddd5c63d7ad21ec6ecdb5065d7bf2b9768dd755ce6d7330ec5c734ea606e59c73d0ed6e3bc7aebb39e75a43ede61a352ad78ed9f1cdcd8dbb71cdb9beb9b971cceea6dbb91bbee11b66e76e9ccc0db36ce8fa4976ea5e2bb783ad9dd3d6ae356ce7dc3676ce717371bb3599d69c6539c78e1d376edc1c376e8d5d73ccce3576ceb9d6989949ce39b7aead6bcd39e77897dd4d63c76e97ddf23a6eccdc1caf73cd35e798991db773bcccbb8e1b6407e1766b8eb9b5b6636eae612355b09fc31a356ab4d620bb6dfddaed6ebba1baabbb3674b7edeebed696a276176aab6c5ccc3eac73eb761536754cb5d66ad4a84151356a3c2dbc2f8088b9c9a9219404121b489284091d383568d8a07183d5204a0209264a90584254840889073cc084a946c2e03039d20125482c91845472a4892690c8f1001222251f5822613840f4011f8e2c5184480992254d14498209120fe4501eb0c1478e2ce14091254c10219104134992209143c4c907acc7100128e204132020b2d1012548966082c4125e83680912444c80186209931f6e7488234c981c59d284079848a2c892234d9848e2c892224830512289234502207412c0104d247184898fcc12491021b181224b3041a20409074a1c40b2e44893220308800004308412478a3041d444089624f1038f2448847a6c80a0314309248e2c3185e088501122278e28d951d301206834004c88982071e2888e191dc209241c38b2a4899e98231d40620913444c8a289104c9124914214af20124387044891d9924479a1c4952c409243c7023eb0013498a744009920e748089243731479838cc12248e2449a2881347945082a4881224482c91040738c0441122278ec8264a8e34a60128a28409244c961c695284880926961451e2c892234a2c61a2c84900431419e2881012493650e40892254445889c38a2a38992232da31c82254c78e088075e1325477a0793c2eac489132745ce4911171539235ae4c44951512b6a468ad6c916151515751134a24545da46548d3871e2c4899366c449d13a71c2469cac13274eda48d1aa1175e2a4a88da813276c449dac91a275b2469c6cd11a71b24e8ab8883252b445ce48d116ad112d7a46b4a8888da81615151535235ab46ca4688b8a8ada48104cc5aaea7a8009121a2e45e634339ec9f88c9ca20424858c1457907cc6657cc6336fee3d7c82debc08f6d929ba3375bef9d53e0aa493882a5d58f1e29b2bef952fbef9ae20db572c5628e3e74ef9e633517ba75d2666517b27266aefc044ed1d2c7aefb493a25232199b2e277947a5642e925436919c47d6d625a36cbaa4b289e44057acf00987e4ed243de281976f6f5ff846464ff2c582487288acbd622d81ae586193be0e9175f7c238a18aaab6e942599bab363961cb99bd02b19c259aecc915eb2670a02bd88b78972c91edef12b8ed0ab2f61acedb97f0b3e9c7f34951ec3fbc649f88d7c7fa6c0ff5d43e9bb76fce42cd1b9bb8c9d9228c2ac8f67581843423a3c684ac91d1b733260452de24cc1a0cd715043090b187261481065528e37a40141518210e586c610578b0bcb0f8d5b57d8a7090072b6ab0050da290c31740a49fd9b6c0d22332c502041e3cf4cb9f966f57f551a90fe80ae37e17cf4e61014216df764ac6ed98cf9e87f149448ccf1e5cc4537ef934bde573c7b74f366a30dede660ed658e972dcf6e8671f7d674f92d743b71c143e350fe23fe3d0954f323edbc326e78cbc641e06f79b0cc53cc9b32c368771ba2851aaa892c591175bc2f0e2ca8042c514215c795d5858dc7750f814e3ed0f1be29eb0a93d46ce1a36b5c34807854ded30ee3b2c6353fb5a914d67f4ed333b220a36027afec358d427a910f3f2750a23e2e42f38841dcac97f79c3a03b287cbabcbd61500e61bfe42461436228df8611b1e4d03ec97fd8e2b7ca0de6c973e74f8a54a038d073cb455ebe5c5ca0179fb01190091ce80ae816d52e8a9a0f4212e9a22297e061ec2f5f3e8aa7e47402c543b7ae0b4621e85fbe2afa4939143e5144d867d153ff54e4775810033c94430678e81616448fbe32fa6a8fbe92437bf4d01d047250f8b4df4ec57d20c5b8819c917be2a03c2daf3f145d4eb888dbf2c10e7616efb6206bce25e7cdfb8e7b78d79939333232820248d95b182c054016447f9d075b5673238a18b07fa9dc1664edeaebbd3a4bded4f737eef76046147d8f572f4283560e91ed2bf6ee90f92f63a1bd7c734bf9f49e663c32cad5f43c328ab9c1a8f2501e44253ea73c73cb6141991c227b71bf31238afe492a501c28bac557e6835b3f6cf910f7ad6eddba45f5f1fa297f3b05e5696ef1e543d4b76c6cbce4945b950d6563e3038e5b7d598d01b9e1cf2dcb5d5cc31b46a41b23527373035e54d47f35eec309b27c3b8e5b7aaa22458164ca0514284f73956e56298a4746e38a05cd70561fcd5b4f9437d7fdd1595688e6357c9666f6975faeead3557aa7f9e53458107f1ade55da67b37496fdd15eac10cd1be635e42cddc89939afa9223b4bfbb4969b1a8ee398b796f6f9c19bb717fbe3798de3b496e835e4cc7eb69698b7f19bd6f2cd7f8894eed838155b4d361ea3eaceb4791baf89aa3cf3c6dbb8f2dbb417aa42d8f866d91fea433f0bac483a6ad2130da77c879e6828e53834dc2687460dcc88a2a7e18a01f1a7e17bd5d0701b0f2af90f6771daf0cc67e29cd9b711f7df73abc6860d973ed8b081831951f4365cd288356e131b9b6afcd988739f86cfc080d4d4c0d4c849c333b7f11fb6665c8a01a10183d1701bb7a1c165f029c79bb7119f70bc793f81f1cde28596175b0a9b9acbd855b0a9b98dd8534a578c4fa29bc081a2bc02c73dc729b76ce0e0386644d1e3780c1694e35676311684bf24935c8f33b49f7993f6cf8762fe49d9643f73c580646ef90f635ea3864f37de7cbfe053c99bef163ed978f305834f34bcd9f0192c888d1b6eddf0c582e00cedbb37693e780dc719dacff126ed87d6cbe3f850cce348559e89e3ec1846a4c67d904df65dcee7377e6144da716493fd1c399f673724ce101b8ee338522873cb6d48a11b27daaff11fd6b76af0ea4c0d07f3de87a89f133b0a9b9ae3c4a6824dadcac7bcb85eb0a9798db85ad8d4bc26ee176c6a7e13770b9b9a97e282c1a6e63671b9b0a9398db861c8c4b92fe3331890fdcda23ccd174a666253731a9f1175d8d4dca2713d9f37994f191fed9d1a9fd553aeea2388be8c53beeab3597aa739e535b0a0cdd2bc464e98c999cdcd42237d4f90355f9f9e05f531b45e9648fbcbc227f6e6eb059fb4a80f1dd2fe669aeccff84fcf447d99a89f45fd98381d26ce0b8bb3f4575c427d732b12edf773929c30fbe7959cd937dd91d6cdb5182587c87a5eb13541f6e4542ebfbebe59dae76708517847ff670852d8a4efe4843f37cb376f2f3e341a4bb05ef440e985da597d299f3849e927f4e73c9394fe4518350d1974e781d23bf6e7a3404df65736e981d23b29d4bc65c62db0f607490aee6e5e2696ee50f5f181f642eceda7e7dac5abef936c7d12f1eada9c04cac1166cd25f37f1e949202bba00cd1dafdd0e4b1d67d6bc01da855111d890072ee82086190035a9bdc3fc904fd5b367ed5354042098a08a315821c615b000554364fe3f9cb1152c981a9f30f399c5f82c659ef934bd9315f421a664939ba732e3d33974c83ea9190e877e7a0625a94461e333b2448a91b3f4995b7ed5c8093f6bd2bf84737d1a6e398f4c888a931ea02b287f5890f3e70ff249a8f98dafcfeb5fa41c260e399f45ef241320927291469c4e8e9e862f4644c69f62ce3952b1f1928b4c68b84c9c94d3f017677b1ab28af388876ed9c42b9e53f126d6786464347cbf3c948d05514c434a2a2467cc490fd015cead261d9845af847aa27ee745cf5810e743eb7084b4770ebfbdbb89fa36518160d4a321548133e4b9f3a742648ac54a95cf79c56245056f597ab93877975079d0c31ebefcf321f8a404503c93a26f4259ed827c1252179dab3cc65d9cfb316e597ac150eeec43e3ecce3e4e139d774c33333e342ee3ca3e364e79f6bc042939339bec394d54de7972967c262aef587c4dd374199fa599653ea18ff20ebb1372aeaf6c82693fdf979f31febe3c0dff61551f33e08ce734e27497aa8f49f9d07ce2631cbaaa0f279bdc7c8dcf9821fd43d09908cdf018179ae1ae49ff124e0e419fcf9bf42f41e3c921e8cf29777136e76f86bbd85e311a52d534673835430ed5482a53d0b814334e334323a728014941f219390504920273292e9722d31d76928cb4d82f9742752793133ecb79c4cf243d2b14e36b14239dc3384cc4e215b3de61b722293e41b2220747a0410c9c508529404e744b153d48f145185cd8c31540da3b45275593f3f96a3c3b64cf9dcff6ee9f53fedc0971fee4ec7744a8a1fdd7ee0d69b2ff248e10f8cf9350dfa49f7a429a3b39d70917b5132e6a4e5a1145cdd4c052b6948be8eeee6e539bd844013665a66faa995a6bdddddd5a6b3a408aa2288a821445398c8d2493003665ee280a42485110420829a7288a82d0298a720821a4ece05a6bad396fada9baa8950c11179b76db16f639e79cdb1fea412c8879d9313be7f8cdc1b5d65a6b6d9d7bad35fde65ec362e75c6bcef16e6b8dd739e75cb342fdbdf7de736d9923d8047d964c3b66cf37e79cfbf39ca63a5eebd452befeb005ec530bb1a0ddd57d8fa27c5755576a53942ff5de5b2aa32245edab1e5161801042081bb47864d53e5f5f29b4cefe7caec41142712577b009565e55105655554158555555418710c2ca21845e555505a5901e315362f4781763f1c8201674b1c9f90f13f16e07ef38f6c59ebf0765729abb258d59dd733def4cbde3dedb5d666ea6f6294dc8904fcf9d5f7c627ff18d9131b311454fe5400759bc8ed7231d404942c6ef783dca81174a613fac94cc12cf352d41afaaaa32b38c12cccb41bc5275b7bb7bd779d5555579950ddddddd3adf39bcd3aebeae657a2c69df5a6bae8fbabbdb7fb835190cb0a972483de7ddcde1d5aa0823851951f4b839bbc316b0df606bddad3933b7ee6eb1a9a5a0f0a15c7b2a1a79ef39f7babb1f15f89c73ce0ded33297ae8ea8da21646551ee72f3e1904346f4751d4a3de93cebd072184ef3de7ce39e764b0bbbbeb8a0595d8b4cc4e0602eccbbcdecdcccccdccbccbdc5a63e65edfdde57d3070ddddfd7cc21277c3f51f6ed72053e1999939a69d5b5395e95957bfd8d45aebf6b0a0d69a6badb564ee76ceb9eef6d6ecccccaddb3a397477773f570a0ba2562ad6dce291ad2b1694c3a65e7f6e5558d0934364ee614614bdf36f6c65a97573d75e74aeb5e65a6badbbb5f75e6badbdbbbbc9b9fdd4e0dab4b5d69a3f574cce22271573ee5c9b8c116c823e6129874fedcdc53746d6ceeeda150beafdf6acc61bc3396fcd2d8805393944b6eb199b9e53f1614614fd3e77cff9f3862d60dfbde7100b7aef518fffb96bcd397f8fa27eda397fae796badb926857a281384414a18a090d1e58bec150b1ca6f058c090e5f548075dfc34fdf3d22b1630e0a0e754b97a738b47065db1202aa41a6f8c0c6748f3ca2b295439e5cd6725718438a7dc3925a940712092845e4199c3a6b7165f3c32ca17830e1dcad9a042cab5653236656ca22e3651bea4413e153de50d836ca21c480b2e5002991ee5608bd7793dca81942f3a41d7b754171bb20fe5a49ef849c42f81b41003480b2e0d2590165cd8a44fb9bed5fc940369b18592405a6cf1e7c23ea5de79ae0fa405186ff1c880b4e8c2267dcb7a62b6a7dce29155aed86c5fb1f26916bdb2a9a288f8a15311488b30d8a40fa4851841405a6ce153d1eb33566a1fd83bcf5fef4c38e1cf920c90165fb0e9016901069bf4f52939f781b4d8c226fd1f7e4eb6a8319502ab5dd9312b06beaab78b47d65c63412d87c83aae2fe6a4e5ae2613a02f053e35e167665f229b5956c32722fee65c7a6e11c8fa507ff9f2e54bfbf5f62b71866c6b3977bf608002c0bd7261c5150664d61415b4155b7cceeb911538782be65931aa3ee67b72160da9bee37b3e295f399dbcb28985b4535878f996ef8967d72b44b1dae77cd68bef3bce7eaf95e815a27c2b21c093a36f7944952608e1052e9cf816c20b5cc07cc72a809c93461ac6a5578842a252020d03c888004f8ea0105ee0e25131c2318508591a15231f56d0032aa6f0cff526348c37a231062ca25883911190ca27d49d28c1410ebe0045194646404d1acdf695b38987804c19c6e0833d3c31320252ff612368bed909176d534fbaf9b27b94f376caf973ceedeb911555386fcd294f6b662eb4b706d547731ce7fbfc38cef5c88a19b46edfabf4ed4b7943efe7edf039f5dafb79777b7bcf0a295f62d3f3e69e8b8d4db0357f91041eac0a648ce1a00c2359052ef5c13b074b8fde7973eae3458843793f3f0e25f508075bc240049b1c0ec8f81e36395f4cd7fb154b1cb4fc621580a5f6516f9ff621b9f31eeac39507badb815e45c83bd0333e4d1bd83e25de81ee8e70c0e52711efdc467dec3b0b460c7abf1ee1400c5f6213f4a1fdf254d0507b551e48458735e551ffe117f79d7051e3de828c67c741958f6129d4de9c6bfbee73f64d40a64737e8f2edfa8c29c049c516d0ceedec3ffc6263d373c8fe1423d242fd82ec7b72b63fb728df37db295f6f5188a2b021cda90540a7e462434e3c29011446bfe43993a27f726882200f7af8f24c544b152a50f0953329fa4a3e392977fed33f0ce374e21b3604cae9c437a7dca2bce10c69fefc7973c5829e14723ef4c4cf0ef26473c680905e95673e778d0535576c08f5cddbd779bfbd1edda00caf6c52e569c5828aa87551ccb090646fdac1a7f6ed597b0dfb2cd0c3eb023034b05e8f6ec0822fe558aa71557595b074652e36b51acf02366ffe9aff6b4e80cc790f982dc1a7e745f0a9fd730a50f1cf31c03e0de8f5967fdac5bf1edffc87ab88f2cf73f8c4ffde7bcf55e74921f5c262505105142d4a24d32328471f9800b25972ae71bf5404309e3dc7b4e3d95d2cf5eea164e54a0e163678964550810e1664b0c1e2c90c2b70a08184192cac80315b09c2f3cdeb51118680b1c0722fc0b8dcaae2147a5e393bb7f89cddead6bcf2f6966e8528af8050ee60b5556b18665d72c220528cfa9890cab7f295b372c68248be9148e524392ba1e71c2b6fcd15a384dab5cdab284479d5a817a53698155dfbc0b0d87964ea1c557754cec89e5ca1eb4e767db0b89039027ef8d4ed10d0f2eded3dda67bfc856cef59e687271c73ab9a3874f2b658f49dfd43d507d8ab698220d5970010d46356003507ba63e5a06165b68c128082cd07205a8bda43e0640820eb410010f5860d102a8ddd587004673d88210aea8c1152f00b52b972960180cac766acdfca3adaeeeaaebca6555f51d9c80e6680c4380af475dc0c310b43c7b73f629d47c9e4037810341794513d29c65737df66efbde62931837825553bbd6045bc073aa3df1bc2a44fb8bed8b09e96fcc72497322f8cfd9c98bab3c6db5d5d630cf9f1cea6fcad3cdc9163d6e340c81cb6b6b150d82b0071504e10441a042082f00828b128c6106170c360b2860d8320413f4e00939a0d802042880812bf010c6d11562c0706bad41387fb882cbf55e8f9f1e45f4681fd3eb21a762e1cdeb5f768516601a34998a60d346f1de7befc99f1e6cda71bd62394215debd1e75218b1896eacc4cab0a8785e33d28701ca9421dc2404109a2d803171c62f8a97200051bae84e10628ac808b34e8cce08a296f6a96ea8a2990e480450a585460e906818b6a39a27d7eb6cc4c0fceec3f09683ef508016c5aa720c0a61b5052401ec12647c92198a3fee85121eef0fccc4db6cb1c9ff0464ffb5c3d50b51c018177e5d711c0a7f7627005964a08563016a0600858b0000428d0000c5cf8e10a1424014608650801ca5b4265056a6a168aeab1bab002e747b0699d73cfd7df83c20b25700db64fcf3273114515387bc50203287ef6b87665e818d0200b1da6008615f2600617482148e148085440404f8f9ad7a320d0e1ad572c52b04212a05073bbf31572fedc79db38df66915555054655f56c504ea8bb1fb16cf1623122cf574ea176f6f75cb11672de74e562ed8ac122b8ad858ba3d25a12625e8f80808246835e7af4f3c40545b8d2e50a25ccc04a1662152c7e4086e756a06d88a20b3dc8a18a28d4000baf22841f9ce19900075214010c528401873c74e1061743308ae2e57a3d42c3916b81c9d43e3d660f10a0a8b8c74f8f22d8b43e86a558f0f2b033343658ed597c4abcb3aecf67fbd51ae413cb8b4d0b79675b93bd5a7ab7dbdb77db2d5cc9668fdf1eed636a3e7f1003bbab8f7d37f5389fa6dfc1a6f51ebdb3ee28b5c2afcf1ffef9f52fea8f05a810ebef0760f8f7cf618d9c49741e09997e8f22ae963d3d8af841001618b8e00764d8d6b28f3384081674cd39e728caa773ce51ce398a72ce39aa41e79c7bce3de79e73cfbdd6f36a3ab57eddddedffde7bafbb5d7753cbdd989919a6b17639eb91a80ac28a223dcb5d0d6b188ed9ec523e75b70c0c7659a40ac6c0dc288ffa4f666687de4ead79f94737af6b4ebb9d7cfed34cc4dfaebb1dfb730a0b72ddcdce75777773ce756bedc4efb52fd5efbdf74edcaebb9b4fddddd4a57cea6e78299f5ebbeee69ecc170956555555d5d47992e7b08954c32692bbf2901cb2c939e79c73ce39e79c73ce39e7a073ceb9e69c738ec4a4162dab9ddc7b569c24276141fdde73ce39e7d8bdf71eeb2c75ad956c3d8715c29494c7c9536b7eafdf6386eff57befbdf7169e5ab3bf06dbe9f10f2a4ea2f6edee313333e4062f3629e5cc0dfa74ceb9766aed5a7bcd39e7dc73ceeddbaabbf9458a9d7bcebd76ee39f7d8b9e7dc6b90b44678c1523eb173563bb5e6e5f6e95c73ae39d79c6baeb7ef60299f7e9447bd881efdbadf7bfd5ebff7babbbb75de7bafdf7bfddeebd7ef3d2fd55cddafbbfb7577bfeeeed70dd94475bfee7eddefbd7eafdfebd7ef75f7d3d12162079bd4df7befb5a9bbfb7577eb58edd49a977f74bfeed6cddddddded6c5a66cea1dc724c62be2ebe2ebeae6e6d45a2fee7453ce5a7d6555531735744b089f21d6ca27c8b90ad9bd844b9b389726bb97372de7befbde7a512c9adb78e5b7763b78f99e173148cf355e579937ff092c5829c0f6692e38a99d939276bdeb6536b66fec1566bffdebbd844bdf71e33cb0bbeeea13c94bbe7449e0bb17337b7c7ddeccbed7193667bfdc3cdbedcdea31cd5989979c93e8c334911df41edeccccc8f99297d563bb5e6e51fce9dbb7e7beadef6c712b2e9f9be6efeb675fbf75cf7b5f75a77abb540acb01a9248241289e4ed44fd1042087777174228736ad8a49ead7abbd8a4edd49a7ff9072f376f3e77775b846cd2ddddd6e25cafd1eb44d6673bb5860b9db7652f35a165b5536b7e22e61fbc2fb46427917b2cc8676bae35d7d65dabf3e68238d984ac11dc1963145144114a7492e87cf74622d601ba62bdf9b60e37af143a608723306829030cda00061b3847a8f2ebd96afbf5a32348f1e11a05c4a00439b822062d9e1065073e58313c32a6e46241975bd6fe906a1ef19687e12d57cb31229a87b75c31215a86b7dc927b45211a06cdc3be10c5f2eb17112dc3af2b197ee5d07eb9e2be458aaa3cd0190baa547758569cebd0ab5d2cc87228c4f2950e89587225ce7a23495513f4954210b63ff659202eb2b6e1608390ad3fea417fada749a1c00333d8c1080d4798011072bc7d1a1033a41ef37a17cf5e536a1f2579d0e20e5a56a0451aa20031cef30ba0f0cceca28eff20ab5967c5f2822d7e7b5c2b839f482a00f2832a55d80296268c9105a8c637cfccc085511768bc726174f4d72b174630b0c1b71b28b02e74810a1a282a2f40b1a000010575b002961fd4200f35b8e9021cba80075e2abe7df392638912836fbe834fdb93063885e6072150c219ae2c01095788918312952750e9820d6aa81ce10c57a8410f5820031b2a50a8d0402606574a7087279801087140821168f8c00c7388998119b210421954d8028a2c9630834a16585a90061caf473ee0c1cf783d72039426342aba10842e1061e6f588ca171b90a1044be0010f64b085156a5ae0ae63dae1dd022dc30e34788309a8c0820dd440e3032d5ba05a0a5aaba6b0b3f495152ddfbc864fd637d752e9f5e80b3b5471810b82116568030fb650210b6080c30c0bbc7837b78bcd4239fb8b42943b0a5eae810186bb944fab65bf78bd9ae7137aee9cb121429e94d6bee7f0b53b2fdef973fe84d04e6df194432e52208477fedc92b96466646472689c9cd7bbf6cf55cee7559c101ba2efc56042a0bfc626ca5f9438247faeaf184902e1573659fc3fedae924e4f1109808091244e3c89524595cd824ffccdad9a8b54526f17364451b0c5f702da9d850979ee324861422035e3523e09c18b7d66b3663e6757afe29016820d6977de3021cf59ad79b539984b0b5fb2f8f6a237e2c13be7137314627a42dd771321cdc88885584984046d9d97504e048114bdb79cfccd511f52500ef553be00271bb50dc5d21d6dfa573cb276fb16eeca5939d562f31b3b7e1d12f1ebcfe9403e55555579f3169b3f742e399f59d55ec9092525fdf5f9c9099d9cd977ce6f739f06c4aeede1361a32f51baf473d88c1cbbc1ef5a07514625eb1c0800e5a7e7e7e10d0d323e707010930c2c6eb1111eaf0fc8ae50427d0f2034b75b6c8bca77da00ab688810fa280431d9a00862b3261384323c1a02a4214d994f7de7bed3d3047566ed01e0520c0a63da27d9cfb387904470134739eb17c61e5990b28c8f0cc7e049b588f544b0dfbfc24804debb326e7f7c9fad4a35f3f020214c0009fd8e6154b0bf4f034af474590c24ff85c5a572eb01e1b1c1a62c8b0cadb6c522456105d5f5d1a53585eb6290237378d2aba7523bda0b9e69e0adc738f7900e55d7bbd1eeda08c2f51d7c6b5c197d804b5065f6293ba4ae5610a1b5a786d5457aca1f2b0d71063e33eec6824d3a31d80f1f37a6e95fad80116bec4a655eab9d6bc104695479d17638105958643d52acb6a4a390d0a194f88c31eae70832b7c90830ccb196e20a1ccd894d5c0a6595653cac96a625e8f8a10c6b7d7232364f13373aa4fa0a4e79768497a1e5271ce91a83f480e69cfdeb60b4628e3f5c808620cf17a6404257c4ffb2c15bc5cde6d15ef7c960adf283fc87adac79b9c44ed5a34b9963aeeeddc5d15f7099b9c37783184f2c457d51a8d215ba36fd7b7c80f634d1025332ed9dc28efb4385fa37de2bc3d6ff03be6b0c995b864b3e7ddbe73237c6a3d32c295774ec4a7e6ce9dd81ffbce15feece9a959b4f8d42f1c68aa185c5c150bc88aac7776dd73e79ba4f4943b1ff6b9e3d54d5c4431e5655eb9888205afd80c2cd79834402bcb74a05ff8829730aad8c216cc4087981e64d1832e2ccbb22ce87a8382222d52e0458b0aa020450caa00d3833af8800595e556154d6caa7cfaebb069bd7d48beae59fb90a4ffac7101d0ccf9a6f30198d28323c0e1054448421d809a433e61df8e7c20e59bcb2108dfe44cd263da8dc1741f055aa762a9864deb2e664f5c874fcdb7a3b3699da30eefac2f1599005e8f765083a7f17ab483273ffd29275bb48e7282a5eae3c6f9f461961a8d29d323e6f99cf949fa1f7085609f90f269fdb856087618e5619f7d826d7fa80ad1827876929cfc3df687ae107346e7d92b39f9678f6787d1464dec1d7fe89aa68d67d3c4f10cd7a2a13cececd7fea85921d8d97fece8c127555393f3e6d987675f39d93fe3d393ecbc5f93eb1416d45ce325ed67f62c85f4a8c330e59d5bdaa31480b9f3ea33bede340567f65af3546c11b2a97915493103c2cfb2467966e84e73226ef094707cf399bd0fdff6c7b64bfbf2092d9fd9df9837de5179fec3a6f6a140ef3887979c30b34cbfe59d37394b1605da2704bae31c0a2e53bc73eb8277ce57799c73dcdf176453b5bcf3a964c0d4288ffe117c9a3320c0a729f44d4deb55bcd4b40e2354d33a159b9ad654935d40e0b76739f4c4b76f526aefcc357a824dce9dd8294eb668fbd9c0521d664bf747bb74f707437129e563adef3216443d48c549f13aa76207b20ed2ae26b662e31de78a5527ca1dc99d239124113f49e20ca9bcbd6513fef5ca2d8ed38de0dbb992aba6e78b0969bfbed890fecaad6d4f2c600951f6ff7c5588e78c09e95fb778a8bf94f195739cfccf37364c081b7d2597544e045f9587bdb1a02a36e1afdc525e6d18d2dc7e921cea378b1e4a29b2e6dc60e1905c7ffa93dc22c979c4535eb5cf06fdc5381fc9daa08a096c72f3cf553e49658ae65238d79a3b75eb4d96a47032eb1d752964a97794a57a916b5058aa33f7e89b6f955728304a2645bb402f4a8672f9d6b3581011385e0346cb9b7812d193240946cb497109e816c9ad38042184de91249d1c11710ea18b1347cefdcbadbd7060531fba2dc8a64c993b2588bafe15f1cd6bc40b7a8d77846ef1c87eb8fda76bdcd2abb1a092c358f292370c488d9766cce4b8b558d08dd7f069f3307be8aab309a27fe2d7a8779a433923f0d1e711df3e21f0ddae7fc91dfb3bdacfcb872c9f4fdcf0d97eb9894f42d04d7db90dbfdc86bbbb0d97433e481d28b2e6347cee94a17de83f8c139707cad3dc822d2fbf66e340bf2c877e794718673b8eff74431bfec36b64e3cd6bc869f3738d6c6cdcc9095b4f279ee4caa71cbf71cb2dc823533639a22779130ad027b975c493e4d06cd2bf04c99d5bae7fb9c721929324c999143d49326927872cbfbc864377de4344fb6ded458aee8a05b90d771127462a32eeed4c8abe25931a32c90dd9e4e67d701b52d53471e4900f92ca1498c3600e037ba7498149189702f3cca5889159ef349771293219e3d6e53ba57d64a491de691e23715cdb07465aaeed83c91b572ca78d348e9cb0869cd0923323c99939394b50b9cc9d7213f4ee90dd780f9b9a43572cc88df7e8374676e333bcdde29bbee19b19d978077a2936e555d4b7894b1c8d38fdafeb29ca6be24c72bdf39962c6a5909991c160fb4c11e352c0c4c0c064ed3345e652c46431313ee3cd4bed33054daeeca3bcb30dca37e6008a4b031628c87e795dc8a037b7164b80bee5442cf9ee90e10ca1bca24205df3cc87e796a4a4bf9e6aaaaaaea00b85db87cf3dddd5d0750fcac7c6bcecccc0e784d86976fdedded000744f2a32bad39a03907e59b3be7807e5a648539808148be259b4d8a031688e4d675591891ca29b72e388b9e9254482dca37a7248e90ca290f52c92dca53f43f1ce4798f808c6f0ee59b4cd2a03c03e5600bddb68a60a9cebca63c5f6ce2dedde71d1b0b6a5833fad6647c9bdda5d45cbe796f691fe74dce240d8ad562d6846c2f3671a97d9a94de61af9c54b2e42c5da576c4ce580318c849cb4befb03729ed43b925a753959c196c529eb7fc6cd9fa4fb7e6f2134a79bef8a4a441f98cb941e90665c7c8ae298f0d96eacc1c5e9ed2f26df190597ced95dea1dcd5220684fd391ff189ab406df1cda924e889b35047ead3c39b5359d46700de9cbaa23e4ede669b1284cf66a43eae4b1ed4d43e1b8c6fde5fd09323834d51d487086fdea4a88f00bc7973519f1e6fde5dd42700debcbda88f8f376f32d4878737ef2dea43086fb3870ed71ef5519faa79a63e9595de691d6fbeeac387376f7acae1cda19e4cdefcd21310dee44c426979caf90a9bf8e80e195ff9de42f2119bb2f0a93ae22ae8a97a429545cbb7bb2eed7371e91d32f874796193cb839eae39a82908e9bacc67f4edd594f6c9a4f48e95f6c9744c791c95956f6fbe978f48798e18849b220e0722e2f0f73653f83484d481c39beb70abafea884fd995ea097aca96a0a6f6ec28cbb75f5cda87664bef78e1134d976b0e7aa269839afae2322f32be3d93d23e3651b22aed639349c9aac49ab75a6bef5190a2288a8215849044b22ecbb2ae0bbb1666b5616c74c1306ce990c15c4b876ce244a14396b90573e9449cb7666af094de6997c252d8ca0c8c0a57a9f2ed5676e9c41bc934302a0c85a1d4d4d4cc94281d4d7a99b974a2cd5b3468dcf0133662a3196f8a520ce9a506169443ca2e65b0a97dc920e3db651741320b26e4c923e569b7c18e90577a0773c56c70b16e2e22e20ecdf388528bcc226564e44e5c2001c4f58251d92e5dbe77a202e950ad41b1c11ac040398ec8a82a9256241269a6479447f28a0f3ed8b821e546141b64d8f062a38b0d2e36b6d8c4687303c78ae344f101c4d5b2597a470e9ba5b2b1457de0709c28edb37395b89472302abb65b7d490b1bab0b03d3abaae9bec7bc41c56aae4e454507e30da02b3050cb657aec4c4d4e091e1604136bc688ece348c8d2e6ccab978643958504e17363565230c31d8d4578ed85c27c6bc4f944757ac54519eae5103e78651d699cd17365bd864a305270a0e15ea05c70798b789d2353659fce0ca3e3659f04efb0f3e8098a347cc718a39b225645766f8cc8e8c24193e0188d24a9529cad34eb385060db7b14146ef74a9e4ca3e36b8788b385268b0204ae2445921380db655aae0b0d172e335385170a2e0d011378b9a1a6cad58c9c180f0db01e7ca1171b84fdcf153d4e13a11fb00447924af482bca23233373038a8d30d8d46e8a36b8d06034d8c48972f4ed345bdac7464bef34cd966f0110c1c3468b966fa7a103475c1eb0a99d060d6ca774f10103c22fbbd8e1c6f5a64885c7858839ac284ff3c4c47843d813b784515923231c3678e24ae99d761b581025312a1ba5ddf2e1d289969487f9214aefb4036113a57dac097f905d62f540c4244b74216ac2cb134eb45b372e9d083f4754c248bbf5c3453d10d18804b49b22048ec81131c0a6f61c18052c9d6b88b8847fc889d10fe1168f6c8737c7e13a18111cde3c88f8c6c870b8b24987eff020fc87ad20220ed7dfe13ab0a01d72880c875b7bedc0a10333a2e871b862427048226463930ed9d3f3a38351e9d1a39f4dbcda0d4607e58d721d38ae46e1b872441dee03107358c951a577da858839a6288f4f8fb7d3b4a19fe4ed345d48de964f1a2f928cde69ef8936c2e09d0e6ad2061738643b6e60a631b2f51c56d4c78e89134576699f1d6f3f7accdd06171b5c5c474747103a31e775e8b074ae1c5187bb080037c5201c8848b9107187ebc4f6345ebe71a2e8d854691f9e56bd8ea4b233e52b0740fc014aefb4f344e9a577da71a234d9800a6847ca2e75c0b103874e10140e2c48070e1e59109e030b4ad2a0bc0ecf8105e9c0e1b341790aca377f4e1ca1bd337b4b15df5c75e890e9cc27a47cf3f9c4946fb3bb7c108e23ce240dca531e440e2c884927f69b22951d0762c76da2b48f0d2e6d33c586077c0ac2db6daaf04987b7db08814f948e4d946f7731eb9d76c5a8c0de9143b6414429069bda7544e945d2814ded36b874ebc81c1890f673d8d18151593964ebb384e3d2891c4410392e9db83b760071e9447d53c4a1824ded40441c296cca2171a2c421e3e236c2601f2906f360414dca2e6c6a5f2fd93a006e4a363466d4d000312393c598726070b84e24bdce741c519547a7c91f6ca67cbb8c536ef9f618674f21bb11a7c9469c37a67cbb0f71ca247c7b4e9c8d05274e538d387b0a373851bebd1467fb6993c5b7dbc4e934e26c2c33e2f49a386d8e666926ce1e99382516df9ed9e0327b0a3f6597d983c5097fdae0f2d08ab3942307df5ec569fa29bb643f6597676fd810ca790b3ef1153e7af0156b549c2b466901baa2492594966f6cd21c5e5e7fe875c21803c4e0c2ca936f3a7c7b0e174428e3db5b3bbb2bee9578e58b8276b5582158751a0b0d9a003eb7440b28df9e917174842e3fe333de6ec5d4382ba6c65ae8d4c2d0f8c388b477e6104ee8336e913022ce639cc280143d8cf1197d9a3829b77c264eca17e88a3551a8aadc79e53171167de5ec307156de228e906eb784780d9f28af714b7fc6691cc61a9f89599c459f79bbc5d7e5397cc27c557966c633a1b74c4e8c88738811810ee33f0d331865e28cf1e659148a719c21ce63dc798cc41902e395c3c81c2a50a23000906a00485814ba64c6a628547915219ba6734ad6909c6c51b7934356b9624778a128b9ce7276762b6aefb4e6c0903d578a924df8294751158c19253fc0ef7ca8bf7cf9407b27a9c651f080ce0b7573cb5db4dcd4c9e43ce233b72c57d6f92c4acbf7e9bce5304e9d871042084f98b367723a1a2a9227804f938822f814e399b32340c63367272293892698a8ca83456593a9e62dcb92ae9d14276cca71b64e0a2ab0e72dabb59e1e397bbe61707d609c2f3fa21d3b4c7c71c3c86096917c9abec55943e49a5b1b86cc397faebafb7c679d72ef5c0d203dd0f342ad5c5e6b65587037b625d2539eddb2009045797fe522075decc0e87b5eb9d001169e8b2358e141187f5dce050f54f0a6572e7610c6efe08bb7de0aa2959c456ff9f3cb2d1a7f951331e9c9c0640b2f1a2bf6803272421839b33d2ab9b4dc91e4029c53168dcb49dec4d81fce49b379a9e1b33d97b79aad85a2654a162947519e7df6780b4aefb0571811ebafca2b2c880ebfbcc427f59c4adb1b9a972b96b0204be640997066b3347d9aa03cfb1ef98e9b1c08cfe1385c479b188d0e3f79fc6a6fd86101804810009093bdfc453967c1cb7bccd0c8c06441f8e49194573e8750975b8ead00c06d08e1377adc03e07108973cfc076d624c1e7f3e9b9727b98e38f775788505b920a987f390b36708394d301e00395dc67be42cd1b8107266330e8029048f04008505b95cc8e2f18711b9fef21ead3d43e32a63398ce5992585900b009ed76e0af564b5473b3ec3e43480709c1c7e83c36d74bce42e363176449207116bb80e1deea87d968c1d39a149ce0c08394b39e4741c7ba4b347cfbe64b40f5bf941ce9e929c3d524e9329cae9ee72966ec8996536e49261cdc809218d9c59562a6510be9265e3d4e27846c36166b8cc8cd340bf7c562539e4b2fcc959916c6e7068cc98612bed4323674f8f8c9c26138c9cee999ca5d24a2b94b4f27c2521e22d9f4988983d4f5ae74a52be3d2a8730cb4aa54ace2444fce599acb1dede703989e4ed0dfb439f042f08af2bbab7665ced0d106659a95455b3a7874c424412229210f130323dcf5d7a877d96dc347bda726a616424110a86bb64dce57117ee7271171277e9f9e6854756c36d70dce291cdb8459344e7699cb1201ab72a27c5ca2d1e590d9b48a5cae291412ce8826c22491229cef875e333ae58d00d4663c969c4bf7ae2abd2cfb81589dcdf346e6dd5c1585e72c5822c1e99cd0cff611b0c08f4f1c14998bb981acf5cd927c7615cf934777ce53ec41ebdc39e136ba2f6ce53c7a2f60ee55654e59191b3e62bc78995d788ca26183975bef29b5899323973bef299ca69c4525436cd883672b68fc299a99ca527a7ffecf1a69f3d7a2eef2ace4684904bb642d9deb042382fe5687b43f3524283e99d5823aba43e9efa703f00e5619f37ad0b51eb6632d854521f9cf36ed5a053521f69c8980c3e4db642073ecd243dcdc5e002343e5595b3b3158bba4aea837ae630b2997d4507cb9994e5cc9aefa13cec4590e2acc948ce979c4bfce5a458c5997d55795579e556b45e18da9c9dbd58995724777ec524a5af2aafb9c0c82c974ddab3922cff6117db67318997672759243a3cfba2219bdc85bbb48f11edf2ec93bd3cec71c5154366f9bcde923571b6b79e932ce7973fe7964fe89625dd252d399df409a56539cfdc9272ee15277fe6d69b44add810e759e6165f4a919c82a9a8607e79e31315280e84f9252749ce85c188586fc56041649c44aaf4adaaf28dc227cb2b6f2ca822c50c0bb2646393564e13493e1361fcc54a52804d587c52e32670a018b72ce8975b15153f6351b03fa05f42ce2d223372f25b4e434e7eb751feba1c460b3abc3087ce2d877eb962432eafe45ca2c681fe9c647925a710cb2b2296574e013e91fcf285b23f2abf6455cd20390d16e4cabc0623723de9cd908f5443f218d27b3e83e43448cfedd15b5574cef9bbf65088f5d97317170a4d842e13f567228c5b7dcdca5d7549214bca3c49013639c7e293183781036155e5167fe69388a79c0ac6575ee3d92123eacfa410c92fb77c566eade58a2de0aafc49925712e7b97358b99b0ac643f9c6c82651ffe5ce05001d8b8d0500e5246a9808c64fe7375810cb852e09bd0646e47acb929349d1570e298ad27fff6608de724b9719668ee02df7965744dc5bee2dbeb47d9a57be9810ca2daf2c273de5517e12f15b5ef496cdd5245d86f961eb923812688eb9039a63b2e8ab38617b925b579c953ba7a0ff702c7a52d42d5f11f5537251b042506051b03ff4dd4679d73beb1d6b7a0a0d27dc9c2c74b2456c01e5412d9285599765d5bc057d96deb262e21b23836e798c6f9cfe3172882c26b6878958bce26591620539874dae897bc6825afb8dea9e870cf00516c12c87b145ca97bc44e373c73f9f3daf3e337ceadcf8cc7975cdaa29ddc84c6aefd0c4374646e3303030b1d1449352aedbf364d407e522f697f5a4ea2d775111bef52e2a526f511715dfbbb7aa7ecbbaa8c86f5d177551aa3cf3e6d961dee22b531fed3be7619cc66bf844e3fd68e410d9a389ed611a0b42f95053dd5fc3a71c36f1e7f0a9c6dbb319398b7ec661e2d479187fafe61f8dcfd2bf9c7ffeefc1b88d63f18d91d1f873cca988c921321a8cc65d79287f11d2c838c482c8c8c89c3364ed242c68c6170302e334fca76762c96184e83c0dffe11a3ed9784b253a4fc36d6c3c475299e10f9b512375d894a90ffdf63d4356c3de9ea90f8a1dc65f9cd9bff634f0697c5e4fe334723eb79c8a337bca2d99b83ff31c73c582c44498388b1ec61703f29ce43f0d132fd9a43d09632cc892436424d6b74892a87d55c326f67fb149d84eb668a691aa7074042831f85695512abe4b398bb9d89447a505323dca828c7f3dca220effe48a751c99d7a32cb800654646464640ecbb07cb6a6f27eff8c3a649397421ea63312094439e45c00f9bb8c1e5236c71be864c1f3ae5950329fa1edc2ecbdaab41c711d2daf76be530f22b26a4728bba5cb4aab8a4b2aa0bba4572cb2debb965412771f94a0eddb0e2e4b7e29bfb503677a90f26fb9437365dad8528cfbab5ef044a7ab4243d7eb9c716babb9b77db17dddf60f7362fb4d6f44b16d7dc77bb5f6f0668dd2d4bfbcf92146b28e695676760e9bebecae6263e95d8739c8ae71c366dc6a667bfda39a425a874aa96e973450c3ac790a1119a49002883150030301c128a8603124d54541f14000f93a65c56210a644994a3380a520a19c3082084000018112198216d00c95b065e65fd3cc27551dc8222c2552c37d1aac814fe97141a819b4296c99a44d0c5570b689f0544a4bd23e18e8d1de0f2f00bdff97c3598eb29760dc5af787fd2b9959a729a1acd1aa6e45a94c3c7897b6f483a0f1010f2d64052fc3a4ada9e639b0da1e617bb9b42bf2eb277d1acd271d20b9556c18b948106eda9a18de22bcb0a15b194f06e10a61de741ad0f151da3b048c1c4b43df4099d71e353bb50854bb6cf3c9dcf7e3dd9dbba2e8e9e73fd634e960f2d54b9d128afcfa2206ae5474fe07b6aaa7dc04ede8eadd8a4fb2dfc22bcc7b6218ab771148e8007c92b763917a6835dde339e1a1609dfc4fefedf14b48fcae013c9bb39db61c14a2fceb3ee6cc2edb17482c4934700f2c4866012a29df3dc655ac9d9b371d56678f6fc5cda5524777c83b7f612634608a35ca2a35908e8fc83ca2d01143801a4d3707e66d119998ef43a1312ee7eaf2fba9167aec609dba9dd5b69ade8d889b1a839e9fc82ee392bf60daa51b89da1e95f00ca90a99f8f4508c8ce0e3af75b18eb669a12f06f03f340ca157ad6b61c9d5f6e5723f2377c8ca82b82698eb0bc647d64524177f027205d4762662f046bde317b77e2c8de792c9c6a469dc80f3c5d50139cc255d437e030ecddcbed9035a3addc125b3650ab2e3127aee0be17362517e2322e430d31cea3ec7fb2cab225bfd434b3746227fe9a3e9b94bb6ca7fdfc697e48d7387074b893b61d2aff82fe7c222705bc7ab362635b97278c83fb29043f44a20edae8718372c329b64f74c8712c1ffba292ddc8debc6a72bd8a1d698905bdd374fc6109efa95dcc98428ada3c5b048cc4803df212ae7fb7e2a93c2e12c65092f4a2d0113a06942f67f231246d795d697878791937e83ddaaceb8ed7c5a764eec98b6fa08a81eaa2aa744fb1865f170681fc61ebb6170689cf6f6f80a529d33d0aeaf7e85ae3f07582c975ec1f2796b593b32579ddc1a57e0cf17cb8b2ba56c660b380f9e7e40decbe7aa63df7b02ce0ddcdf998ee8a076a0bd8db5ddf8fb4cdae74573cac0d542da0509eab91e79a852d465c5276c92f23d3460189e68a863753bd0a73d377d53c552f4059583f133b429434d918a0a0ac5a71c269f1d43bbad42ed93ed7e2a4b3397227c9eb937a2110a748771a822cb5d68d3430e271100e8760a0163db5e10783e00d16663a580ef36761447b7b8bd40611fe14a60fefba6b509d07f98b45cf40b246e5f967b3fd3e61d94cdc46c54d22eef565e27eb21108d8cccda5bc934a2419020efc5ffb40d463a89f09d03b9060ecd01b890d3503c279f1e0ec57dd45d8d3727c45a1475e9492a04678c1a5c7fba5f3c3c79bdb2be78e775ac81bb5299db2f8aad78770bf84080e0d4aded3f782dff3558977ffee8778f6be59e4294b1c6432aff8ddfe8538d7972502f7faf038f20423fe92fbd57f254184595bcd88267cfbf783295a5eb73efd4f2071f87ee7a778299c8a5e030295f31a7b446c182d44b43ba612551e4409543513253198f101176dc37213d22e54f5b7088b84924c0e4364f1fc2c4a1426fe562f31d12f9c7eb48f2eed985b879d096163cc379a3776f723f23470bb1ea7a6b7e7c0c897d1f1eaa1806239a600e00f716493fba261013804acfb6bf72eae4d19f63a8b9d7db623e93af8f9505208207081e2bda73650eedfa9208f9595dd773cf09a5114e44ff43e785eebaf893f1195500c4bb8b2071213617f0f1939ff25d742fcb45e0ea2c246821a9039513c854bb410ae2c2e743cdc2bc4e30f21bb287d6b7722bbe98cbf2ac0a344b0cbd4e955321e0875b00e752c4b6004988b6af3b9e5638161b9965e2d939410ef8e4c6da6326deb54dd8a4882de02961ddbf50d020cc0a0d2dabd2155e43cb6d29033751f1c9ac910250413f763be3221926e8c201d13451e81c79de799e9ede865bb874f062cbbcb3ae51221105a7ed6b379ba2cd2962cdfb7e1bb0c622d8e8cc88ada46fa45db7d59165720ca69f97b99c791e92ab4508c1ce288290fa1e20367841ff2ed32b8e73c94531fe7eef51dd680000716e1d5d8e881c742e112f10b24bba22972bc0005a0ac761714af9f24629c5a6e3feca756901ddbad75f8a42eae95dae7fa4c61e6eae4e89209e75cc028abcb396d6c14b75d1069d1c70443fc2065093e1679e0422fa20f88b8641992a139f4c956587c48ac870cdfd9699b6606ebe52762757d222a2b0b526101fa775e9ff5ffc7673a13837ae31461a5e4ae140460a6c4c7235097ba548b8f43e77d49c1c5641cf8b9f888adecb8bfb01ea0a033a7d43d3ce4b67754c5bc90094cacf3af48cd2fdbfbaff6c77313502ff851819791bfa70c2776341098c06d3ebd61649ef8d0bf317734afaf83a21163073428ba0c2dc3e6e888e81201972d544e0288dc4ef4ae3d2e78b00604f60b6c014a38628c3b958647318ba032976c4ad903af44a2ddf153fad3967005d58e846a4091ec827d20527e1e36dd76f57ee4c8dcdde9cf8bbdebc8e78e870124da16d1819f6ac93c01a58e456dfde329c5311a1af599a1abbbef95024f36a3e3aa600df54f67364b7c7f457c143450ba0e448af44558f3059e0df615a595d11f115be2b240670fe442a47251fc81ef497e3d478518a30ca0be474fc1ec000e6044205a2312b69c8c011875f496a8e316cd95c513dd9a11db7619904c666dd14f8ac6430fc82c896d95169f408364e923758985fb4692e6a50865371d35deb7798acd8a4110c96979ca6a1fc0cef3f1429345fad6c8fee0a30eac32c72b7968b8ffdc8ea684b5120020e05cbb77e8e28c3c4fa8582d11594d7f60ba1fe7fa2606334069c82843c748909e34e6a5dcd36f5219053ef6227d229ef220809aa18ff7cdd05d7f442cd688e8f46c0dd5404639b7a2b5dcefa5a5c044f68a48d35a4688e51b7681125b3055f971aefe47c648f5669c2925f6397ce1d51ab2645e2e0dbb87717947535e30dcc852264e1bf4cffc90a1a88740685b008b7d0268b577aa56e8ece9ac84962a11c4621e0310f14420da3bdfbe2e2ded15bfdb33c4f69f382b4ef740dcab7c03531a83518c56cac97d60cdc519870c729234911528c866e2929b33af148a66e38ec44943dee2609b72655b35315f2cb43625aa59eb9c70eb7c8cf617c9684e51c933622f87c2312c695881800c2211b9ffb4888b2ce340c401df4c087b47aa738a33092ddd0f4f1f4080c634bed35295050684a98dafc419048af85c6ee267ef94cf640aa02a54a641555ec9b7d245ed862ce6931000e8c7750a2520403887711d6a798b42be5e5e86181de50520a24c1e14c8233d1d4676b1fbd5de487d756e615dc7797253ac84d5a621958600a7166902ec23c657053d3dd189fddb7bf59181392c5c9b02f685e1784c8e5dc120027bddd10d3684462706aae145e52798b45f7e7bce1afd65c3ccbe9cd16a14d78611a3a60617e570819186b17c87308c63bb6df3f38cf3f0fb5bf1740c1a8c23b3ca5a3fda3dad681c8459d00310f58276fe0cf3e8501c32b87bc8af436d8c56005daf7897a5a868853dd41c06fe59b76082af400681235a6179a516607fa3aa6ab15074af0c444bdc846de40e746fe7673115a3e49441aed21ace0eee69aa4536aab617054c3f41af2468db3f4eedfdb972fe40222f65c0511d84e4983e7f793c6effeaa93ea06bd613232671ac02f409ef430e9192962a5b9359531609b4b384aa846eec0f662574624df5968013ae8835aab275586f64ac1de2f12e0457a1e76f851de4b015bdfe559d787501785218b923550d87a09f191e2b4f0ad588d80150510b9f6de8bf57cc108ba1588bd5cb9e81a803a1ad1e0b7fd34773b40978fc6e90653a0ea039ea01a2b53710334d1febde6d5765490b36000a5f4731e55a74d03cf3a967469260fc08ed094e51fdb1d9b667be2fb28108b3f04498e27e4f5f672a6ee52c0e8d11420e372aa6907418c18d55b984dec68ea6aeaba7bd73328ab26e9168b6a31e93d7216a01d209fc9d5fcfc051086eac9dbcd8879bc876b724a39be2b08f27ad117f7d2053267a919fc3acdc70002c15590ffb60a2487b0e5a3bd0c12efd5d66a2bc450c03ce000aaf97d2da5f9c0a2ab897a1e029b40ad09ef8290f7c4c1f594d3481a8f04133c49bea27d9aff27261cc3bee8c73217e55d22af784772b28d180ed6bc50d76779be2460b21e8fb10c215f2207ec98e94d07683a5f07396de7962cb9cc3bd40ad8949e9c2d24f1bb9bdd47eac0c4430963300413fa5cb1c18ba4d74b69e5d745de62c0afa8052cb2e50053e0173bcf1397d289c4e7627891144ab5226d35c1f2c02bc2583d77bbb368d11acbb6c2607f8396be26c9bdaa1ff8e0fca481ca0c956f2b97c224f66c9d93a7438a63a80c9e9c694310eb134c3f12eb6197080dda9e6b6ad46b6d06bed7c515fc6107eaf98b59f5a2e80518c2e04cf1248a48b1ae2d16a090562b54e2d8792cb217a3994608e68f9a78b08dc32b0f7d8ae284460667f965a5ff929cfdc9c5e0b3bccdcde0a1fe53c200c5e36099523e4e469c6580e751dd83cb1b2562cf8e609fc22a377d8c293c1bb4ad68efdd634c12254343f635131eafcfc2910e1df08181697b2e9cb2ce11ff651f68a67a89d5afb941516da95854959d2aa08890b91bbfed95c73f5f15b5d2fa2be4d1fcbd9f0193420d196f75141673c311ff6a28d599693b5618e73f6906046f2d04192eb46a045e8410b45494fd992b5397acf5df0f5f3db052a86762845184f604412402924e32ecaa18aaa80e0939d70be740c51672381539c9d33825759df62df1af3a25ac66dd4fafd9aa3ecdfa786a72cd0e47e662969d16b0aa1565d08b81834b7868fa037514cc3d6d4e637922e36cea616e632dd964c622cdf913a7e38cbd823146e5649caa83f96818ddd0097dfb1627125ff0aeb618462c218e2d5e53a912e0c00b157a69d97e01136431f96e2f9b9802a809404ea9e63c73a76acbef12f9ffbde0b3be1085427b4e6456a3ad3feba1c7173bc841f5c40dc0ac0f109160de47726a5b82a7ef9b0f21e6244e08404c450a6d6a88924852574889d41ee98d84b17150d222abf629c99b95e83e72482f09a3ee4a1856e9b9a3b439e0175d4e1dc9dfdb843ee0932e4a1607ecb5ea63380731946e1019d98485f0686e9c194a87972e5fa6f63392dff881624b96969e886c65c5758dbe4dd9a9d854b88d0d31c9a482b322f0bbde7655ed1dccfc59e1dc09f79880951a1ddc463bc0c0e07f2a2f78621c1e83b2a0c8d7ec916927267f652b82cc97d4a097910c89f020ca1ad881cc4c1601d52d63874b36efce62d87a55c238a61ebdffb6d25adac0329ef29688ecd6272283834db18e51fe93f054cd28d298db18e577da81524da2141d0cc9b9e28b250e6b7f2a1be7f410cc28f71f41e64d31782ddebeb2d4a3f695474aa1be179d9c4971574702b334aa00f1d4541d79a87e3fe9e7b3f358f0de1f347264226f9405ba8fe9af2c090c7479aa736cb74621bdf65618fb656774c38b047eb8c783d6fa9d359d74da4fd82383e6b6c7d7316469bd79786341b0db05a863a7af0cf299c600940cf010bc39c201e778b73ec8634f28c478470d9512d9c6d47e0a2e3f9ec306cc3d402397bb3d3479ffafd720adc480529777b07933396cc5d7ab10065efedafd71932603990fc284112916a92dc7d32745a477c17faa0e7de3db592d92c8439ab364e5cd4309fcd34d00d88b8b89d9d0293092a057addb393014f73e529724e5039485b370ca8baad5cb02629974c0adbd11e06b0258f84816bc6d4d9739aaf13d42365da7264cf14d407c2fe01da8f598cdbf5cacddc99110814174f514b70c9e3fdcf92e841d97c95b8d9a01da7bcf61c4a83fd91969177b099488847579ed9315056cd824fe5ba453437f5afcf6a967bfff076c3a4bb2ca150b5401b9c15eabe193ce7156842280a28e13378ce048a0971f55e7139b93a0acc0918dd28dfa4a84c06a2a51a0005ad9eb0cde939c37987c1050c9e0956de52403d37a4e92143abe92950f6d44e4ea3355b386230a549dd59d23f86daf9d6839d78c30aac71ce5e62524c81cedf922e9c76c5e2fe91546189694da853ec5440cbc870204203ebf520834b1841b574d878c48052217c6c90cf2c380a82cb03bb8f81b65c626e0b0b06028bdee617b22e1138401cb4d0e47d918276180eff010b0ff1959c813db1710b5328f5c419eb61f176d54b4ec01f6777cb8dbddf96f7c598e3704fb368b0ebb202c8438f0a9750060df0285a261e348da01d2f1d6f6c9c59af9bcabc1aa4338efe7a06ab64d5543dc20ba1fcff0e4e38663401e49bd4953dd61f9fa8851cf7e30a15a0223caf425312306165c06eb5efac732425de3ee9c51d567565ddf87b2b711d2f97c5eb542f86ed2b450ab189fb8b988749db7f89a2c2603bee732b80c338ceb36cd7fae73a61e1d407a04150cd62bd19d03f30371b91a6fd16ce71340890196b10abd3763bd1901b7743f8f59bfded775b1c7b499e7b1ee3a49e0c6dd495b58e868ac7f3b004be129d8920ad9c701a4a1144d78ff83816b0780ae73324c2ef8a7b3ec9cce297407bed7d268664e14240cc68f4d2af290066440b8abc62148f390175d54401987a48b24c1f30565ea180bcb8bf581de92ecf280c321eb32eb7beba3b5afb827b9df4415682b2fe31146f790b0bd02609c44ab8954bb8e38e8b6cc3a55630c6242ecee2bbc193e3b0d1f7c42707f769c37c060daeb71510c666a09f8b06eda9cac030d862b4c818b262df0cca22dc4a63542c7ed937106a09b54259c88d49a55c6a39c3d34a2296f71014a7c07b571b35c1f4f9bbe428f2ab8fbea54379fcaa6625677ba5dd5db57421b5c14a9e3992b35b8110c44a442caab50d0a2bceb7220af96eafe1e5a4137cdc51271ca34605e10d29ddf134f8088dac5cf58bd852a2d4bb896f8f012231b298602d3125a4f999f13a7519a2fc013e9a53031c0f30f570e0b3377a4bf5f043e232f3de763652e6d173f0a4720c917a617c63a785ca3617a23fd13ee19190d61152f6d584c19900333098b9b6a4e56ba0e4248fd97555dd7292565f2aa10ae56275a2c3eaaebc2e463e639fec58471c2a7786046f5ad9f6eb4f30d41ebc58f04c6c51c35fe4aaf4467d5a9f8759db3d949614e4f358ac0ba591a0184ab5ea7afebbeb72cd8ea872d392b0fe93a8086994b964a8082c50b7396c38425739eaf46940cb3fdce7a20b97f79a8966c9e29dca688c7c9b1f3ae1fdba70b29ba40e7069f2f742fc4929ae3723f607f4ad464182d0b8b43955e1976f11c9a0f9cf8a7e2eaa88cb17c51c2a80e82ca594e89074ca6a62b156db132738ab2b010f728c07fbbf3dac830670b7ec3dba647032fae1d3940e9eef7ea48086e33e02d6b6ad9824d47ffcf70ff09d332b9294aaa260f4102dcff9c3c6944edf937788abfd71cb69f619966bf191db8b80961755007a685d995f1469564934dc7f50657548834d00705bd0210a1ea937bd3524443b7cf00b791c6b8371911ca86205a51bc0117ebb4cb0089845ca0976337aa85e6e84df82ad3d2ccb44d290446fea2a3b619be4067a24ed5198642955080472e7049bea65a1f5ea6b725e319afeec4caf683f65dcf0781433b68cfdb7964e541f9c39f41a3b04cbe3671fa037c0f3d30c485dd45b056306e155b82324e189f3ccd85a2c741e1425dc5e8918b0e70ac6063db82ac7e202e84636166ee5b750d5f3ec43c496a7098b94032e4d9cdc127dc9252328f20617b3ba095de6a0359153b835e63fe830af1cbb8b520e1e55253cf70ca9f465980718e4aeeb094f1ff06bbf62119ef80feb24b66ec735cd3d5bc16f6c0c453805af24f9b6a53903fc9da9b34f5ec1d51ca03482b7f07b23aff95a99ab46619b50f30e6d06f7590f119e32d7bc6e6b6e4570c391f43adab8189ff73b3ca291a251c2a66b297a64ab577462243ea5bfefb60d5b45f98bb9ca476504b3676157e40edb8174c9153426714dfdef2777795c8fcaa0d9dffde27910993b7307a5fe1d626a28a519dd70ef2f36d21d940a0780e272dd5387606ebca7cdcc4e8ef73ea60dd99fdf72ba0b87eac0dd4c3d1a508898855be3f6a1a4beec30a068dc492eb3cd1b844c6dc4e14509a99e980b18b686f318567097c22ecac9907dd88695864545e852c7f83065fa276107c4a82902b98e0e163bb23062a094c4573e8b756c097ba22e94aadfabab907b908cd81699c07ab628d25a4b9dab8cc5da4ba41d10c10552f0f0897cbdeddeacd1fcdd74d24134199c45e6f51e21adac07c5046501c9bc0b582c31c6760013a72c65c2087fd7da7c40d3ec5741fa1b493fa8b47993d0525816b1192f28cd7023bc9496182bce43f639856a326f359b704ba992dc2906febb9849f8d5490454db87f1ca8cd83ab7ce0d3953349a7ef2d1bc46ad970d5644166e6dd075394b370ccfb8734c7c351e55f14cec14ee5d32fb7811aec50ab32ded47b5b4a75c2689ce8e9311b444466d2b6e0d12539d922035afd61b585035390daa4ec55ffa5321e243dd6f2d8d5494ca2d2dc0d77040203ac867967e2a44788ab7232119890d07103b2ab6c1194d5e7c3b503bd8ed91491fc803b01b5d05861eea051f96514b449a8630f1dd7ed1b07539e5cbd1cea27319a6f0cea5348c3d94e3a10ae69f42e84f16bf922fdd2e88fa0e3642dc039af193b0dfe5089cda711dad2cc4c543fa07aa7f2de933bff9d3f42f8c8f7ffa24ea4b335f5eb52045a46ae36237d097d13ad68acb7259f796551ac7c2518396210765bce2e563d73eb338ae053c33620d78629f61e9de6f85dc0ede045bb7b23c2e9ec8fc46cd37ebd4aa1c853f33389764d6aa47dc6a4dd6fdfb1691b2ada1dc19c655fb1e71cddd16007727eef77de19610908e0fe3246088b497a1029f469160318a45236358f769f65164fc9f3ae08b84d790f70364095618eb57fab490904c2aa01dd6ff81f5837680c6cf730a55861e284f5f518ad6e85712c95042489ef787cb1bf34d2923d3af601f2e09ee579bba0cdd929333b5bf8665a76b6cc39570eba6a74f92243b36558d38eed95bee1c14de21d43aa9fdbfbd32bc0a4fb80bba4b07e04835eea4e08156e315a20ebca38ba5b6f949b514848d019e3cbf54aec2a9bdb9843d5e10d4a93046c5d1a6dcd6000e14c44bc6089ab2d606c6c30169778bec65ad2c44eadc30e8193f76546ac966dfb7f5af83812b5cc53d5e5e97eb7eac16654ceb069bfbb56a1c15f3b2f5cee784c554a2024e23aa93bead1c59d6df34405d5489aad2b1477b38bec8f8ca9b43ca9087ba033166c30a6944fa667e83f72ca3c55f40193a5c63ba4b055fcc3b09573e951d42a73be8406e80d80efd97c37121308997201c156b31611e6952518e9c4d9ebb3f4d774a70f06ac31a2fc25404150f55ec895bffffd387d92866d8bd21af67b2b509efadf4963905dea68a27b37e508b6c365e6946330aa27b9192ddfeceaa21118bae8b474c5142b447b469bce34085e56ae2187d3ec67844c72bbd130e27b4821492dc84bc58f921d0c3bf65e5194f1aa7a559c6e8283b0bcd897f9861e5274f628b3d2cf6efcaba27ac44c487f969baf5d8674a0c921d532028a1e4d7abe8e2c54131335de02580646bfa72fd33ee3808d3c88cc8ff74ae744096815cded3856e4c4f183098e9b9d6b86d34cdeba517d37a2abcee5a961216126eb2b7e20b11c0508b9bb98531576bc6a3e1d19ef2a5d476ffca7568759b0c2dd313456b42da93ee8ff3f3b4d3ea4eeaf27b7eb25bf6e09d2a676e1a42f860ab63ec2e4179418987261e6006bf8a6847243d3d7c2271aabb0f4ab2e6695ee9e5b1799d6dca4c1d071437a784b842179c637004e2aaf80428aa4a6246aea02e0b6c8aa2a9e68bc9b311ba2331a9d6bb0442f257a2386f3aee7dd6e2e46f952142c9db8d82d50390c2b1e50e4ed32a1ca48b643ba21c71242943452829158403ae1615a679985a74fc5ce68be220f47499cfa58c109a1421c2acf9984e85909df51e847b05979f39f0b93043205469278df41a4ac75bb55cc0da143f94d590d62170d9295eba13b54379931cb6cda2a6297c76e246f40eb9be01eecc145d4465dbc720d75d2a2b3b62e2919afa76c41a9629467a08e324f53a5b2a7981dddc362a52d0e73a125812e66711652834ade530da041462dc9443f9b5c341e2dda10d54420c942bdb88863b0d12258e9a8042bfcc7a41155e84c792bb6116477497a3eaba966d492ff704e80f609768bd5835bec28f2fab00b013805ca6166a9eac6a2b6d770ae1f21fba62cf2c548aaa4cf9f11d4c0797364c4e50e0c3983866a2a89bb8a711662020f6ea0b5960dd1c42df07255046d2bab3f2965cba940ac2c3ec5ff323ffd292251542e3ca9270028740a293125a67c584bac8613272fc895edc8e7511d3a1eef141680184aea00fcb3f4ca86fce79ba57060c234a9cf2c21da3bc6f98cbc469c542e18bb3b543ea7388ec1108c207f6c4902f360702057d6055f059c505c88890ca63fa04ef46919698a2f4514ae537472ae108231143b98995c9084848ab8c6b4314fedee23605383496b64b57add89f18e2ed4f59d524b05abdf7c2d96068175c91d120a29a0e7eafd71a60e18a2df3c783a314a68b58fb53197354e1bf68cae8831003c1bc32c24d8f872ddf01064adc490c3d6102850a0eb15a7a0147cc37ae856ec2a36b3853595b668d0c4caf6f88af85c02cf230e8ced70a90aea08ed2d992db6105a8be15b083e6676a99ff8dc0a83fbdc002e69933e4b49fc09f9a3fb83f312e61dcd127e47a266dbf506a9879b24089efc5a6236d64fbf56229186e812700c0ec4d10d48b9bb3d814a363211090909c73ff8427131a67ef226269883cab2cdac8726926255bed597cd4f17ad1b8ace0e870b4f4dd19f3167f9d324c3dc4d6e7d3f9a84236688edd07044cf06583661969e81c9bb7050f9e5a702a087c118b5d4e573df4f4e804f0e9ec1705e88274397f8e41eb9d065b1a0e5dc3c783e15fbedae7620bd3d0cf3ca3503c0e54a73dff838f5811b8c0a4b633410ae4530a41be3598c2ddf7343357d3e22fd5f8016ec71cac219730a32e41107d1fbfc2738fbd52e5c2d203e7784b623ac5f5669dc6b65e6359abb1add5d8d66a6c6b35b6b51adb5a8d6dadc6b656635babb1add5d8d65ae38ab8551a44a5d6d3017dd0d2c2ff004c4f7306bc7e716a8f969700283228cc228ab3d647cd7abce536dcc458b0554c90bc7b744c48119cc1244f07ef39913f8c29d4c6f0b627cd617f402b12b2d768ced8a5e2ccf43aba650ff831ad0ce4e9f1d6f69f6c91301083e16b9dbe81c7d41920d0f48f244dace56112fb67ef8c17e8a8ffca16ff47ec89afdbe7dbbc0611849270ca0c065de20005e16b0f461d8b2dc65d98c32ad78dfe982ec607dbe7042a290a6f42a70abef7eb0c244d080b84c864571fea23a5afcd7b70381e731d34190144fa05cd179b10289f950850ce900732b616adb10aab63525cdb5acb9ee281a3e8b1a7d6b9749ccabc059f77201f352a19b7598ec747096ac20bf73ce5a1527256d0c6f8826d8508580f98348976756437d414911e4df3689ca63f555deb130f77433f66e9f778e13bc7ceab0429d6d26db87411b1e6f30de307d1ddcded3ad15d68df205668f06b734e7efdc0cd710f787212c6b4ab7ecf7ae8f18f0dcbf3a051152a9900bdccb39209e9f4f6b0f2e9d8e4222433b085009f3f449d81a360fbd35dced8f5e26bb1ec286de953f6811e13a46147943b490a22d1a906cd624ef85c09def565cfd86f08f3e0b7fbe0c743e64bee3b5f555ba62173faa90d3981e92bd6627cfd4ef65f4cd676ffa21dff84a2e4b451b8f1fd6b05ebcef5b95724cdfac9ee9a841724af94f4119b0055fa71e27d03cadb6e6496cca3ea1c9b08e06e2e3b38ef0dbd7b5abb4a69c8f98ee271777b7bac2ea9454aed8517cf39bfd37839218466069f3eccf2934d150d33aa4aa6e3ccd624dd40e778d3216a0ec7510a3c08448426424e6ed7a6e95b3b76dcf89dcb2612a82263697666574925c2e68f2d6240d8de5217f9228ae77dff6502d9efe8f1a4b1a5a13405f4a058eca097e3fc480e123f6e4639708c88974b75c33ff99661cd86f234b6c8585385f688d8a7d2b1436e0053622ce715069cdfcbfaaf22f23344c91e20d0d5c90163d325532901a48ca10e2ae2cf76c98362f519f8e502185ca36019ed4bb8b1193fffc1d398c51a3b9123cf1b1124aca1ed38a51734809141e7c7b6c4fbbc41fa41867107dc04a4a7b3fe4cd0c27d8870ac0b862d813d77287fea071e82721bb235f49855076c73aed4ebcac06927621bd866bcecf81c14622d00128bf44001e70d25b442bd4680def4136df25c7bb498cf46e723abdd4aa06c5e5f3618dd95b4733b0a96cc0388f28f2e645c3a23a4277cdac8b01f253a080177760c23ee2a7b8d337c9462cd8457b637c6ea7c683ddd47487bef47018e81165faf472d3a393887b3de67ed0103dec253fc24e5daf8f3343dab3a96684612a9e3c3cdb620ced7d8595ddf28d565fb27cfe71086835e70b8b98dbcd9ff022de443f345ea2dc9d358ae6ddc2772b7fd4d9e2f0b24df170538d0fb89bb45e09c92b8e5abffeff0bf22fe147f7e1d67adfdd7f356f1bcd2f88206f60b80173099fd3ef9ca3aa535f4d8c8051cd622e355aaa59b148683e64e4d1f56c57bce7689cbbf7565cb275c67271527074f27b1b4e52d6cd48d773a71021e5d877ad322d261e0f37c2f1328beaf0bd4dff7b6b44f4da8e3f3097f88848279a5d64b6e4dcf22fa1a91d0b347a7db7d8574503d3ddd17cba3a633c1cc857b902eb2baa1aab26efd6b9098b9caf6007a5f71b6a5d4b0f1075f65d2ec1da4644cad4937723127a0cd4bfb356a7f83e0f5ed1664e3a75f62cbe8e5f78f339c0f551a56b0f8bb1885970052f8411d3fc35daa23c15cab16ea7e893a3648e76e225796fc2003aa14354940fb94711cefe1379ae383e2392242bf288710be4fce2571a5f4138d88a5145b7248e7fe9b357bcf0baf739cd0b9fed4b9a5f6be387aa03a633ad3310e8ef957c45e1213df8874f26b5b64a9fa57700b2c95802b0cdf64bc3df6f1d1db74c26c51ed1ab8125ef0b17f6ce3aa42709b2b75b102b1589913df2204cf230aba77393b18b68cc421132ac29c44412bff8247db5c91a3e73303bbd62aa1469098931726437a7c34df4d6b74d31ad46ccd365e334dbd465a9b934cf1e22da9aa69f424d7ae9e4d7dbc6863f4265decfa1368109479de0881dd0bc024cbb5fea7113eb071b38af3a3e199be7aa0101b5f3a93cc08980dd99e34829df2204823cf42535854637ba67ab976aeebaa7fa1dbd3a906e6f4f7978ee56def1b0786a2b66fffae818a63a501e193ddf3bb11b8fcacfa26b832f972054c3552ddd618d8981a2fdccd9a5d2281b88abbebb3d1844f860883052838778d02729ba3fcc3756c4d6fdc58a33bd5e6611e293483333950a63614442b7faefc989aa5da3efa8f83c9e20a28070d2fe20f7cffb4c834437c0751b9f72f3e58fac8da379dc8b80546e9fbea5e53dcbb172aa4d11e1871408191587b76b01752a68406ebc783402fba05060cd363cf2c03490c8b7766191beca700669bd981b3cf3f220afa9f4a8e2477536de347e14acffa0ca7fd8147d8a9ebc48dc16b6176ab5cf819dac48f20eed3825fbc49fe0e33675c39ba7774e65beb945da4e89d7079482a422c436dead65030103748bfe8a151ff289293d209310a5e8b9fd1cf458bb9621a46b4fe4924e39207bb73e5b37e7a84b34a883447274e92b24df7d5072a4bed8449f0ef1cb565e3c3f1d25c299588859730a66277278929a999ab070f55c6fda4be8ab97b168b3ef0cc2b9610111f85d2cbe7db22935983f60d9dcf2a1be2eaf565f6ab8ef9a58b092a0568239c36b0773e070d5ebefce22da569f66ba73164a342c75c43ebc6b3c81f200ed014387d57285e53d7ba143be9c1071daa5068523c9c6338e96f43cbc2a2391e514759d1e0ed9070abd4d128a5d0ca4c2865f69490005d85fb0c07274c79c165f3e6be1d2607c2ecdb332cc463dc264c4c457872d3aa23e67571fbe4f6bbae9fc5b3e87a66674b22a273f6e824ba5003fc73d860ba1a5685cc0a90802bf72335a1f665dc5c6caa3841b8686f71f07b318a63e62ce44dad9931315b199c1d9b4036b18e09a585bfbb893f37749ba3757556404b6dd9592c4c610d8504548ea4c62f4aec5314e18500e1328b1bf44ff8b080f11867daf6783d01113d05d0051e1a00c3ee106abc3de5dafe6b7be8874e3230ec33652189615200ad969b74d622544093b4397e9818560af21f2af3771bb9b54a514d777815982ac8febcfe542288ac17674241c7412e29038fe5fbfa3a44a9ee05dc1a67ad5af6b7b919a99446adf0f399dc49972b1dac3ad5cbc7641d8c1684e9ff80d1dc023e693a1772327de496d43580e28c76ca01da6752cf82c461410071ba19ab8849f7bbf96ff064431f881e28fd7674eea742896fb3e058fbb0c8eec882ed6950fc640760e103e66c93b301051c7cb39a2a24770be34332d5d7a777e6b309409fc7de7a95f992d840fda36e88e663fb981dee270c329f4ccd6e48d4be5106e587f3dcf252881b7eca0840542aace17efd4123358ae32e10f19328865248cdb29216b4d48a241deb697fc5d662c0cc770444af16f551c9f9fdb9f51c986a5c652aecf58f1b99b1b4f04dbf1b49ff5ca66b5c746442e9a7ec09c79b56bf674030b8861e0289b0398976ae7788b9fd27249e3f32250fd381cb2bea9284849bed6a444bcebf82da66b91649cb1aa5124b49401882f09d8f4d594a0bdcb5933f261fde9ef109947be8c3c90e11b5e3b08961df377a11b5cca56913884de2846e709b79a79420a01f081d1d3eaa7af0d52aacd8c62b1487eca7d817e213f02b1b508dcf9d7a9b6c058f4891f9bdfa17afae3fac3449f51c4fac3ec352e1d01593aee61080a6c34cbf80bd00423faa90f18b8b4900065eb016ca78066dddc38aa000567cabe8368846ae763aeba90c440f9aa339eb5d7e339e5043c84f4ba923d92439afdda28528f8694203cdef868a298a0235be4fac4d455b5ee5ffa6182a133523cb5e873072a84fd67646a10def4ff420740753387cd20c5399a0b407e18b8512986be4cbe2bd538d4d16fe8e156e1c28a2123c62b1f56ed57927e724946535cb425203dd1ec5a948dc0d74cd660f2e9453175974812dc1595c32e1832eb110415898b5dc17da183e62a7befe549e14d1ba7a0c54980e1c9fe6243e5ce0d8e5b4c885eb7b4a9be6f41a3efe27a21397ca8ed6cb8bfc07ddbd23f2d99ffe00757a47e1c486f132f30a140ff5bffd14eaeec74a26274185a89ff2f34a6d1c0bfe2076f0ef7fdc87385f9cddb606bbf8a33988e3d7e7e6449142c9e104f125d2b4fa62c2e567693f13c38e635eaa44e7cf841d86b3c877b76a3ee53bf542bd5d15b6c3b2b68cd58febf1eb92c8514308179e9a5ce872a05564fcf4ab0ec46650164bdeb90c8cc3c1bee82c4eeef82e04ef94d1582b1bb3156ed1863aaeb17dc65533ee90974bcf29b354dde408fedf06856de401a421db5d62efdac88a4a47bc97bd80570e96b4e99065d4e04a776464b85a175c58734486102f1cc5e73c709a1b94062bc3b7f3eba2ebfff30a096e7838c985f90904589f83e32fb2a810a92d43d4daea3e87d6fd8f8ffc6c331f4de087274111feb5490ace1f97f9e2ed6f77f70f2ffa7f8b0fdf0fb79cab72361bb5a37c3aee7f83747485a11e0db7e5eaab44f77403a439e3b600cac894124cb7b411a133b8b26cc5e9824b66e1aa7a694136a99c9738c317a514090bfca9343cc96c02c54d2ac6cdd813ae73d1722a5dd497e6b870b7a7bb4b53ba9723d9631f7a8c4d14a6a39bfa808beb5bdddcd5a618013ec3caf2052ff706b4ce17611e649b315c6da9edeae7c6cb65a8fe2f2b2e564010d3e8d2bb700cc26bc7e98ee0435fc113d62b859e9a3f09de1b8abb3ad3483c6e6c8adcb210f4825e4a1012df401a4cb8c48dc156fb5f0504534b309f40bf498384f5e876017c85d95a8f882d874e2808ddb180650a4e19f231ee79b8981c9511300fbeddebef5c4cf59ca48d8fb206a01d74d5edde221c815c10452de7a8057b2d2853eae9daa8394c0298a264945524d62221ec6aa8fdce526ff7099410f36f945651d6cfc9df932d71b8c86dd239cfc6a39e770913b76c857aa23a08e6f706161e88816dfc5c096cf43bef94cab155400d6ce587b3a51bf8ef8c4103267d6e8d9cddca95d260550e955d9a6c342dd0b8704b84edce4d8b40bf93d20769df94656b45d011b730129f6f1b9cc8eef55e4e48427a1536515a04592a5c0303960f4577d898ab324c0a9f1d351cfeab0f4c4439008831d02ba4246735fe2e0aa739e0d2a572604261f4aa159137d8a3308d9683fea759ea11eb1b70921e69250ff45fa3e96af3df2b878beff7c970b0f095cc5f952480170e27650631b1022a4f4392ffbeaa94ef01a1134a8f4e789a22c35fffa6fabc7f9dea3baf6bed127507ab9d28978bf70e5d513be3f47cbfce1b269f5f45ee3eff945e1b703fa0bfe4d1c6ffb57763f6d452dfcf05ee9784a97fa1c632d5f27e60cfedc48202f421582bf38a8607c821b82ef38c8606e821b82ef38c8606e821b82ef38c1ef412200fc17ad976f67936f09758249ef41e336354f3b5433d89b682f27f2af694073d7dfea9c860630053aa584e7ea0cfc8548081efbf58238c4a6599a0676998f7a6830c8ca04c73877457ee4d30be7d6794350c517eaa25d11908d6148f3a93df7f3268c998cc337c879e14b9add235252d0c0eed8c03d326822792007a895ef60a5943dfe70602572cf070deb5a262e84c55720c7c47735bb2ff671259cdb974cc3d012c08edf400c4330cc30f26653ae1d7411cfce82b3fc1cf617e2460c792c6fae29a1defe33cae4e9865f0cce2ea6fc897250d9869855645ec50c79d814451a24ccba5752221c16ff5315e0a3670f9e5d19608065dc59f81544d77b6108a9ab9fcf391142c8a6595c452d91fd978c355d2c229fffc1ed19c34cf817e86eec6aee7edf9de30fbb822cb0def7a2b0d18f5e025b177f2afb72473347a954c5140f9c2d38fa8caca1d55f8d81999dd2f792a51b6ed20f7a4301daf2f95d8499212b93757364d6e354ac317b26f54b612b48d9243d91cfe25995a21203db99910d3a87678e79ded2182e57093d1c71cbac035acde264ef78467417412160e11e89c9f0f64baf372c4e1989be64cec9b9f7a292fde2193943e456502238a4877fa273b468265956acc5d4a941711b438bb77942aac9885e2b3fea066e1586fb62439b7e2c8b62b3357479728915f47c94063a26b441a90b41a26e5141baba5949c7c2c59517aee95a8a275f262dc808552bf079e98f0f085da752e25ede478d9d4d7e82e047c8400490f354f6de122147ce18339467834d34a453b8d109964b51a2a625bfc79cd29fc462a0d269f5afe556a9f75e33c4b09dcf1f51a1f44cd8716eb95086ad1b1263533fcd130422e7c5b70882497bb782778dc6d99f7d533ff4309cb9473a03b303a733b6c9909bd929325da0346cbe38bb475fd4a93b888ab65673943fda2ff81cbd0a9f76c60ba6fec6809886466fcbb737a2e9762bfba19a86fe690c67ecc1634d583a26722920059a9fa30fb99705984b65e19b76fc3590d98b0ccd22a7c0e60db92cd8221bd243eb998777ddc63e6be1ec0033d56e3fc1fe102c9b0804509dd6506c5c2900632ee379dfe538d6abfabe11e44b89093402811b0c2a93fc1293d9ca691e8359daa560417a7cb3da7d37855b4f1c56368f190dbd195a31019be75d87384428b1b3dd73c39e02b39918e059affa544bf030a19fcc159b9aec36f0bc5a21395fadb54f1852b61fa933f8311f4ac872e1bacc6a3a886ec21c493f6788c13ba801083222d85e3aecaa2a092c22c365994b83ea1a2d701027fedc93626a506f56f3ab87301dfd4c2dc64a54d7fb6133507db69895ee0dff8925e644ff10cf38e8781d2a0a91f12b994b5f41994a2db0787728b3d0256556f9d008133609f03c7235905184e85a5b3c4f257a3afca41ec9e1a748bb2911429ee3ca714a79ea174b50c98fc167ef0d7c2416bf1c1390b47d753a9327df6ac8a95ea8306f968b5dc5d5edeff0e95e24b64b89314173b8ddf8628554aa1ab9f8198eb5659475db6d59031fab8b6c8902a4fc9343c4d8411cfa0d71c7927eac46217053f322f9e9a5dd75b96023d518bb5e673b7942f503ed94258f8c6b6ce9ca7c2440ac3777663d949580302203326792e5ad3fe6fc8c7ab612f1feced835f084d31bcd517c4a655dcdac3e0084b1fcf651fc5a64f5254179079216ceb14d64cbc82edb5ba14716fb551c0bddde2311ebad461164737237a303578648e3caff54b13c7b9fffc21de5082132bcdb55e78c108ca3b3b384771797425c8391d1abeec24a0c04e77c398a31f478e37cae4e31b243acaa179a3fea6db9ef3c7080307efd9fdc04d781c14610257327b74ba223233237be2e9ff2fe4d24e47924e18f3215bedbe5e6099d0f8255886369f92f359acc0e8c185b22854dc423d9b9685ee643c30dc61bd6d681086e97a09e0e02607e95cdde5fc2a39d6e6d2fc4add9b0c81925663bf11122b1d640b2d71bd5ae1e2857a18e93aa4fcc66aeb63b2ebfe50bd9bb5bb1316d1920b4ff4a3f583d891cd704520e8caf22916757f45ffbe3b2eeb755d18092a69528b38a024428dd9060e20dee0d6ab4e3119234c93061494e8a9e8b7110967d74b0bbd4cb208d6f430e589df8782190836a2771c823439d56e09650d4bbe7504b41c227c0332021b5ff445fa8bdba12f8372a5340569624b9a5b62064a1f268f06651547cc32490c48023dc36dff703ac8854d9ccb4a80a8aaf302e70097e267fbcaf8c8c62e099669c4741f7a8d56bd6c90f33f284454ad7a87aeaf055c765abf9a97d52f5cf66963c11ba1e40a18a6e5e29e2b54f1803d0a4161ca43a93cd5be7bf7d1290af54f1440a2b43c11f0eab5e85ea80fb969e5f89db0faf01f74db8d286a5ca3dae65d1901ac0a36450975dc639b49d7c89224fc187bfc22a485edc512d346dde5bd53599b79afa632f5f0bd90bf987684021e8eba99dc8de4e51fa1d82a5e474794e66bf32fd0d1f07a4f8a3012eaa53a03eabed51081fb41a8323e2971588ffc382535b93f5bcf3f827dfee5b785743afe32f6bd5448072aa2579a79680efd34aeadeedacc90865f382ecd393caf50d8c13f0af58737fcbaa6fc941280b280fc397a68c69f27be67dbc8c63f6c111307c63b6181250d89ecaecc1744437b4741aecd3d2d4a231cff71417a92dccf9d084351683cb5d3a1edcb49fa0bf66bdc998e1f0c4bfd01f8749b631b720040d8831e03650fa28f81b1d6d5785d2368b37bee619e52030c6ef0394fca86201e7b50422df196e85f0217096753aae8f5372c14da7ccf447892dd2b1382050b462bb344fa014a67e2f4cac275cbc475bde0024f8830be0b45713488cc4b79d463ba1735f3540e7d63fec5f78dfca7d8aa72d93a47bf83a3b0980aad19a187963e390ec4e05098d6058a73cd3bdb284ea66b671103155321441652575d5af8627a95cb9b6685748632843bf6ec9053bff60865abd5d0f400bddfe3b91f046cd6f385d717c08b89f8028338078f783755da5e610feef1554486f9b2dc972e3e03f85bd0eecbef52c7cd9fdedbddf6fb27762eea552f1ecac088958fbf2593e4da5d12cc11962067839987405ee2cd651045a7ff08b020b0e5953dcec10627b38160b1c490c8e80919ae7eeb925cbdd22926596f007359104de868c4dab8cf8cea13134c0a0c43908c386fc790ec3f95f3773d64f7b501070e7b726f5f742692da2b3c4aee51a60bb8ca6d5779cb7af11f7f7e06c82955d88c5bc5fdb08219f0322e92b50bc4661a953933063ed611265258222e15c75524b23397d8f87b5ae443244ef3c94b7bea9e8e6dbb25d61f0f74a75edcda65aee5eb6c9049bc581c28523c0139f9c998b0c8f825234e4dc3849025809452dc7214fe03006450218d84c7bcba6ea2035d53c46b24e09cc592cc9c189248aee46af958a52441696ef0d142f2f3829f4666612bd95d99cfbe60d67f919eb0a7582ba9679019cbf6f2c20a9d7bf1cc29ec92efaa1e05cc23c86e503792325aa11d9bd54fa66b204901905ce521ca9f65c405653788648619d83f11dcae42d91cc3ac1f501fdd80b6eded079316a26b8aa099e2b3639102371478087aa50a222901a25b67346a6c6951c1967c2c81652b6f1ffa5af80c761233ddb66d747fb0c5ce0d6b1a20e55a525867358f2f4a01de5b5b49de5a9199d8d264cf6321c726520d09d5a732153d01b28c5e3230c045d86c29643807463fc74c55afafd3dd5ab92d9bd12ef059a39b4073a7a8ecd573d9145b63d063bf17835894da6eecb753189fb1ebed5d2b302bdecfab84b3b3a99a0536ca04e76a82140fc7eefe1f97d17046350735d75db8bbedac8d5e69a230198232a57a4c62d04eaa7dcd1d4fa47e480ea17e10ff502aff4df0d8814e62755143a6816a75fe5347a14a5df8620e65a1a444685a8f3d705e21957eb623b4b13b42547dd495e00b3beeaae51bd2e7bf80d476cbba8fc929e5fb104c1745a2ab9181e21378e737129062dac5abdda63992b2e7cf4d842c1353fb39729b9d2c273a5a41884b66fad18ec49f78464a7a62bd503dbfd34af07e42160c6fc034bdf1a75eb5e49ca7e9902b21cd23612cf8b3d590ffc4db3b07210e962e267a6adce230aded3c977119efce5bd356c0231b8d3831b24f1f7175b4d0cd24b92c9723ed47b46360d573442d035b8be82eb1f471efb5b9a406602b17d0b029a30fce50b2ba25bd05d0cd750ace9ae2a572020d8f501a7104d887721eb703ae99f155c95f63399c1d3b0220484723cf76010ef707d6392b06ca529017715f96bd01447db7b2bb4a97ca1e5c7aee0004c2863c00c48e0a23163ec5e393d9d38153ff38b735bf875d9d904222c47da20982d6fcd858e2e18b4edd82bb85e0fdd003d7836486dd3af8ade1fd55ed6e900fb5c4d303110a84f03a3d42b5ca0a8e7b98319d59e5b15778b07909fbe1500eb2873a9a74558051a5bb8df25f230cc9bd240083a9a2955c05c71ac0b4b2a04cd45b8cbc0545c094def6d80108152282a9ee4c3f5344093447bc6677902e7805281b5c6f031c3bc032dd27a5190de4d253b6302fbdb222a377671deaf997277bc6c9470ed7e037efb7920d517b40390195add7259c32a446db9c2e0cf322a9f5790bfa96b80ee282ee34a42db7772420ff29f8806bef1a1f5c77e62c561a6373f8fed949dbc3e1d81da3ac5d9c981ef8f5b57f342e1325f9faefa8c608f03629ffb22783b8a30c99a47cd7e6fb357c51eb4904fcc7ba9cd4c3bd9ca535f7770637e06192031b350fb0b493f9acf4ff65049a930e7117282bc89ecce8c59c7ef2010e3e964adcae55a9d3be8de83b6fbc2c6997845d77b48cfb97fc0355b53a0392e0b298f7ad354c1f900ba76d1e7757eeb929e1e701bdaa436d1aabd7f53d68ab2516c067f955f83a605e33dac3ebc8d82c56bc26c02ad0a70e4513414007174c7867a727079a4da5827010308f2e3cb2d90b1d732e178003f9008ec529d32dad8e38b068e5f2cb65e49451eb997bbbca2c7b956dbd6bd785adc2c531d666e11a326d053833098210950477ec079b2ba037bc42b97625369ee54c5bbe289beb9c17dc0cb824824331c61cbcb310f786abb8b84ce3bea14f7f590fb40f0ea069f1fcddf6a86721c5b169e0da9570bb60c8def577d7d0534ef33ac23f93c679f0d1d05b8c20deb3e0fe97d2aa2cbbb7ace0f8c53e5ac520a2c80f6868b433862298536e59af61d2d4833ccd2f98655efc55e5d1338c8422b9f765629d3147b7f02fcf5095cb4716dfa5365280ebebd8a3fd80f0917b959a612c9d0d95ca811a7b75c9826765e80515d263827b857e7b5ddaa4c780abe59f027426793e6682ef8195af528935b464e0dfb8bfdeb7323aeaa84ed5ad689d61d31855960d34b2929dc8c5363eb5b01aeca89809b19390d5724a6c9c537fd8115ed82cde14c01f37a182dcbb328dc5145219a037c1a6244b517b8188bc12ddc0a6392bb9d6822a6356dd069ff1e960a205455bc9c73dd6bf57997807410456c6fdaacd1e872b384e25b6628ebbdf01a4fba287ee08afb134de7e00f9c06abe3595fa398df17a0a178d4a1ad3ca5d1bb6f84c10734bdcff08f8f7f6aef79e8c8d10e99d74caebe2ddc6939e6c60e8a958723c14e9a32f99de88276ac6e87a8df35dcfcc6c6ce3524bab8602fc714733c093f1a8f0dbc53dd6cc5e73b7c45e049d71e362f947c0f4cb176a72b821f8f19ef910f277665f954270cc10f72a3bd6ae7b37fe9e5cb009cc49d683b9abb4cbea6fc0f62f64a2e3dc90b252ddcdfc9c29d32bbc83e75560f463aaac7538fc1191e0a8067dc90b9343960e5378fb95deae0e63c5901181f06845b8f7169a021671d36b45d25d3b86407ede780af34bbba4de722ed666b39db04bc6067c10f2ca1fe41d4213d6bce1605286b22f05681ad522d11de54dbaf2399dca346a80682651cdcb4cc12c7ecc69ea21b4654368082b5ced2885881819e8fbc00843e89701161d0798dcae303deb6bf66efc9d95e35c27a7e978e2b1b418efb9cd142cbdca6d883c16a41aef3115f30cf87d5ad4c3420f9ec7e119eea0bd24b186b280969ea5e0990cb77baf2a68331a17ae01d7240c0d2fd546bd60448bbb1fd5d430107f87e42d4cf6e622c5044886e5ed6d11de9cc3e9732e9a6efe31ac00e9470830b4eb4d29b3abcba5e07b46a4659cf0d239e58de4ccae4b8f1ca27a5301325be43b4dbe006808dcb0c06f34348e46e5e215548e9e2ddc472c0947c72439418563463ea894682474dc66a4d80bea3291e3b528b70d60563d2c182fabbaca0a0c96aa5804523bb739a9ebf116c203cbeffce0667f9d987ee5fcf5226d75dfdd3da207f5024fbdd26e5e14e4d2cd92f3036bfeb5c593f446d3383463f4fce5c945be5fbdf726dbcd34d228a0784ed5c80740ebd0d3f71743426148269553f8a4fee349602c4ed8cf029ea9f0f6bc5f43d995861ceac159d3ac80fa6e6d40380e9ba730bc2ce9e4df929db5da00cbe8b4ca517d1366376828742f7f1aaa9956a4ca025096a629e004147ed4b1ec6c5a0496558ccb8c107d166c9eaea7ed093aff19baef24d6261d603df13d4e18d5e1deb5df99f0e7edb2ac58563b852bc2039982fa8af99211600d519385617edab89b4e8c6df1eeae030cb0d6463ffef23a7e4810c37e91b57a67cbaa1b8c9a54d1650b02b66cb3af159a2be67a833058d9d2309ee546dd2df7038cbc86582ed2e42c0cb31324a51959b6930103e7f8e795d8ceeccadf08b46087d6db56dd2a8cce632010d182bd05e2a4533b97e7cce9a48844a687d043a7d5df4eb901232ed481c9870765393e12f7e3ef92fad5feb282ddf9cbe9e977adbd788f0980e02fc3f5cf6f54f5aa5dec6d4c7cafdc6da7210ecde5cb6858655d77ef0dde0a09c20346a61e713632b193acc3d8edac4247b875eaf0563aad96d855788722d0be13cabd7cde927bfc9ed2992da658abc3a1537bc4b991ddb7710a7f36a385ac69cfaac701d188f5e418390c99980ac1f29a372d7bb0a41fccb65cbacfcc8b3fa27baee451541019e0abc281b85deed9b03ad372ab4fe361b166490ac2b06b0e148468273dc9675ff8d4f8206ac6ce6521ff637d3c30d478ac3d6528da7214ebfb662b7fcc6b13637942147f7cd414f9f52145d771c31ab24138aa5ef521472e5da3f184a45867cdd6e200dd0f10608a0fe47991fed2ba9800acbf7514e411b67280562ee8b9a0d1cadbf65912f3f41ee0094ccf8a38edf75fd6bf5d4133c150b044fde160835c97f233440e3053a80d74986239dba19a3ad727265553e73d0daa191495c29de6015ec6ab8ccc7cb86574214762c80b5be9f0a3e6c48eb1113997d1b4d0dafafef00a5137a7bfa50803057727ec37b35e65cdcab581919b0bed77d09673bb0bb2b5bb24c978678eddade4eb844d50474c772e773a4684e0812519437339b55d320fe7b4c280addb94cb03fe8f60db9a191a9b911df7378f5d26b9fc01ad478e211aa3b06bc2811f36a082b491c04d732cada6ea1ef9b8e226fe96c3283dc335352e0e909b92350c021858bb3023c266cdff9a0a1b6a7f0359780dea2359b5098e150370090b59acf6fc80cbf6d8c273a509c369e2cca9587ef0f34308ee9bd1310150e55c5770d8ffdf5ec17305257ddebe396ef4f22dd1399bd3d28e6ef9eb96d91fffb15f330bd860095b030f361d0863768248116622872e186e7dcc98727e11d04f289e5aac2ec0023f11a812659877bd25441ca9de8fc8315f0d8419488be480b776916b21f1c17d20aaa31245dad0bd86104de080f9ffec8ac5c3c52ab224348f56da163eda4aa8b3b5a0a16b0190a788978fea424c9908f26068d07b8ec257affc0333cb3b41d3ae4bb87db5f3a9d226aa3f4cc163181cb13f90da5bc14fa18c5aef9bb74aa38bcc266f9ab75ec02d35bc36b49efa9b3a34335848b265b293c7fd0a483f1a2063d9cf5dbb900c9f8afd933f43bcea1452c51195c34262e07aeb790451e63c2f718a02847a968a40a18bbb9b73506c2b098d7b79737185afb5c9528ba8dc50e40e1961a5db340078f09352db5b9d9b752c9bdbb5073bda7ab9437ce9205f2290ef489cee3034622311959fb4feef9bc9279f12f1f6fcaa99d43e55f438eedf298968af6e5bdea9dd9312bdc8ac028e01883e762867e6d1ed0d1adc4f6570408e4e4cac8824b817f2f4d57623d0d87830e336203aa3820ad95194039d635cc8cde6eaa0f8f2a399355b055a926f7300f718c641af6a6274a579424379226dcc8462086f204d2803b30f22a5755b272fad395c10cd282f5ec0ed3cd7ec5cd58b615accf297756098bc134b89555cb71075235b49a3a1dc8fec72cbde65512d571f5e518e028903c9968492fc32393cc9a5ac7858665f6a8a292849189cd99677a39ee34c753dddd46262810465b727f904de44dcd8739f06499793c0f03c529ccf64333471493d2b0919491929209dd8db4b1e195dd83c14bf9b62aabedd4e128874bce750652978078557ff4933c0e0dabd3e846a132d33a0bed2e490c80024910085233eb2bf39e11c25b24e9e8a1f71381c88079eee65f278aafa72c4ce5aa71722fcc60d94540bc434c1ae9b6b3ae329cd2cf34c1996679e1dfa2cf447b5000fa22ae205262d428975101d366fb12c183aef869b160294a716d31d64dfa123f3605557f4cf018db77cacdb416f0a35c0d90d50a9ee207644d9cfd3122aa5bbcdcc5496021f2db2ddaab213fabfcd81b890f77a384e406eea2495f96f7c7f2b668ad0da5510d55c370b13c22fb68748718e6426b68e930528e1e1780c2f7e90baaa326ef504989317e1a1ff6093bfb204c876c944b9eaa68b217c32e4d9e2b275fca96315165f2cfdbaae42a8d8decb9410bcfebdc3b2ac54bcdfc888d21d85f49fb713d978ac813b389e466e60defece9130dc55647bf7498e6bf5e7305424f96aeffc4a2407d6fd0197b8be1cc602ed26d7897808a5a54cbcfe18e49142c331b70cf3db00ea5976383f8206aa110a3d0435a141e22540bbd32ec614b72165d8fe6e99e5908abc6f51414e4180fa377001153a60db8db31c94a77f3dc52872c09bddb730c0097bd4555d7b6bb43af464c7c1fc654a7ad2294ca0f7b3a6ae94576d88bac0f26c18b822f96ba0018002abc60c299561ecd83044c0b008e8d0f1de6cf1b661c4d0d73bc22a4d47233a77ecb935ff99ad64122d09636bc226ae0c87db9238308cbb83d599be7f989e63ff88fdb190521e546fcb9f934579a79f61e18e199af0c4cd0c7bb81922940735431d447981c5712327c716a09d6ccde76d6525f12c7208fc0776b9a4abbae25c671d39a0a42406962aaed383bf1f433462b9a0642c02d1a1cc74aa805a5f7e3912ce3caaa7c0195393864986af451fbce9cc70e6d0df21570f848f09fc06800fbec686fdd7c559fcefa896bb9cbbc2a04591f4cd5bde17ccf7319867f42aba9ac27f3a5e7fc20ea046ddf00d22538712851d7008d72d81316ad0b739974c3d963ca8e8299b48610bbd65dfe0f5f391d0ad003bd005209c80a0aff97017d2d42a209beab8caafe6f89728755d6b9b86d89e817988eb3de6c7e8eb9edd9b5c8bf8a7ef785816c7fac944d02e609a4ab0a907f4616f34681456f5b9c80e7c1d9b1c49b6f49904147a0f4981af89b9b1fc535f6b7ca165428896e9e82fc7deca99b8897cd793791b6b4f8db363d8c938520748f7a83f2a9d697e9588c27180a02cd1c43e2fe2c3ab565cc3e870eebf754ff6800b15d3abbbda36cff9ea910df27c778241dfb7e811a42626815225fa6d1068ae21cb2e7d0dcd2e29b96bcc46e371a852c75b1c2ffcfd30a000716028822357ecaa66d4a9160f53a564976a335561c6b7ff54291e5b3d2aa43c1b2976c358c4840a0a2816d2cdc3e24a793be592325ddb26471de0ac3a3fb582c95f5254cb372f0910cecc487e75f663350f9143498c166f19dab59ddb23ea61a134b9377153cd76a9a7bd39b2d6a58fbef16786eb191e5238e7d6d4f3d7ccd6c414114213ba363f59150906d509fc3d179b9cde2236d65782fc4b7d95fae3741a32369008271c7c835ea0e6b6d427ef1ca2cc6ade97e9c03447d4af29253d6a59c7c01c27495ce11cce358b150a7c43688ea0d37b490f1e72368b5569f79dbf09dfa002a7b7731270455b69e06e8861c06d743fc6091ce6dfa2fc0e975528984cc6e462d1d705fedd390b07d1c88449751f00e5fa9d3efae8cd0e78a87bf11aa2327010101e27b3e668e49ebfbbdc25dbc0eb25e9432c330b3d4859f65cfbd35cf859261c93d3b0a0b1bdd409e94873b6b72071e31a9e940e20e03eaab1187015fb1f01778dbd0722c0f7fdec67202625d771d97cf7df55b66ee5aa20b009530b40b8e777196e2b4ff6062d8e02f5fe1f8906dd00bbe41c99b737ab50eb28e81b3bd469098d4634ad68b5b17030d156f7226ab027a6686115cad97046e77e7514fac4442c9046108822a01b97e0813b8f50522e8f31bf10ee2d5265810e1df5d429432a0c0fd061ace752c70deabc28cd28131b0892901b03edaf5cbba4d28d38d2df110b02e8bf9aa16eef6580186c8f59db72366f387d01ba8da46b7a05fad4017db6c45910cd83e2477fc046a644e4aadec170e6e2c0a3603de5a8a82f24014d89edb1b56da418d97f97b39acb0c6993f1368a01125b1afc6520dc273dc7de5cb66b45f992c99fc6dc8f09855ef42f22ea8fdcb1ce15ea9f47135654b14cb6e9eab9a733163761516184f06ce6f03e24b2083c36cd1efd8334f14ac27efc542265b6e01216e5338bb5cb7f2e1b1fc05056985fce8d5a2b31a55671019c282c49990de758be38de7180b3948f0a5d089adcdd06e3321999a3130d9d64274dc2dce4f5181cb4a2ad0e3e92a4ea19ef82bd512c0d89a84a41a8353443540c75cb9faecd2133cf03edf5bfee36644257713a033b8ba8bf3176cb89ac2472367eb9f3ac4b2603594416bc15ac4ffb283a0a93c87370fe9eb639f708ec8d670cdf521aab75513bdadf321e4a6d0789bb301ee84df465ca206c7d3f1463d95f780cc7a61c620f7eac52aa8424a890145a62cc90110adb91ad8f3ac6d4107f79d946f430f40040609b5ff12ab35bf7e4b068abd0aab09ab52b0d6cc0a17c8e3c246f8ffa2fbec99f4ac8d1e9905c11609d6609cd0d65d44bd63fff3182d7df073704e9b427528b96fea64978ff4926e825817b7f66006f2b70e34a4aad5ca2f07e3deac062cc7b9aedf8575d6e0c5b4e74011aff618ebad67437e616b5624b48808917aecf71f4cd9f6816afcb4cc79a83b262534729433c055abaf6aa7fcc92ce49249b1c247b1ada53e87b04349c4bc11ccc271a617b6cdafbb917abdc215652601dd157133e26489d8872f73a8b1f3a6688fd4c593645e7f897632219b71aa20db141a6626cebadf72eb46c40009a1f07b01b79de9f31f7f2f9b6b3c46c7ceb786cae4d02275671609c1a0cc0526d3d62117e34b6f50f182a972fdc026e1a7e209e65209d1c2df484e4130e26ad84b533376c80ab141d10c2532028f6da76beecd8c6553e3907648a2f720ffc3f9868a50f08f4990d5c0cb6d66cb68dec1f511039f24417ea8b76dce9bd3790b290939291108db295a6198595622d7301d72bbc856e74f619268e25d64c0c4b6c1a2d4c5c00c67141406ab099cb2b069775cccfc2bf7190453b11181010e7cb23f0510c7f36bef7d20504ae67cda30c6a1fc50f412cbe002435403063d0aa0fc07465d25c35880ac53e9f401e415089784a89479c9cd899fa93cdc9f67bd0b7d7f7990bb783fcee782530c283da29cc0f8addcc14bd5fdaccc461c459ed399f822eb47059b3b4373faca5f499f5653702f422038a0b179c55201e555107b96918e506631dda351d8a1d4313f549c619d6e66db8e2803095881966df83ac54d2121ccc4314c34c52b4b927ded58821bdae757f12d38ce7facff5f97a4b68602a5f9f6c5d4bf66eb2f7de52a624659e09a009f7095f4f3e4940341210c988092605792420d28f46990d1fcae48f461939c25f2e4f2372e4d15b7cd63990f675dcdaf0a16c6d09be8fc2f64f987c1326fd08d7fc237f7f7e424e406ddef2f4e32f399c8a9c8048e5e927c9c9f479dded4afd1b914f1a512a432a47a348023a4fb8ec2f2201653f4f3f2d1a76a363699676e293e98a938ea837fa2be111d65abbfb48ae4235ba4ca9cc3b50a6f4e94806f27424f7deaeebbea15cdff32e19c893fcbe4fb43c29d08572fd4b0651f8e52ad691fe38ca6859e140daf2298a444aa156a47146cd214992a552c934ca6c984619a594526a69d759dad1d7716affd2b7a578329d4ae4e9743a9d50469e4fae65d7efb2dee86ae9090b783e9e0f1642ca727a40b93f5cb5f9fda9367f3cd63bf4c763e0d777208f7d5f6be9939b7a3f3c5e8fbf9a7e08e2baf36117f29e196973e4f67ab2975d080abaf3610ff7a0feea771c59bffbba506717ba47c8faa70be57ecf6fdcf62542ca7286b3dc1f52279289b0198716d7ec46daeca0363b09f2f420a06bad87cb9d3d5c9bfdf7887716fbd59f033950c38c74ccfbe1e13c5ca53dea3e9c591384b4da5a5b03ddf6bba6a96fb17bb5b56fbf4ed77c6bc7210c472018a64e4a23d00405e5ae5a759d8a451257dd7822ad5d71c178a586e6e5826752c4dcab62c5f7a980b958567c2d30a6c994f382058b1c1a33f20b16326aece0793cf8f0cf030060b4f0e15dc4d07979e93ceffb40101489c23014ad5d71c1786586e6e5826b52c4dcab62c5f7a980b958567c2d30a6c9240a43511cc7713422914824e924d99592d6aeb860bc3243f372c1352962ee1d4723128924c952c964329d4e7e3a75a5a75abbddddda7b6f672d89244b2593c9743aa150a892122f29e94a4bdc45e28834a14c4652e994422a9d5aa5537962697111c30fcd51367af325da90e0bf4659687252fa1046f471f430618c6843a63e6694a17c0cea4319199791e94a65dc5142d5285bbdaafb945fad54441f57af32ce60b158ad96b75a5d69cbda950f554699cbabb0441b123f6b94ad7cd8126dc8996f8d329a6fbd3e7cd147977ffc21166dc89ac7a32cc5e3980fcbd2cbb22b2deffd108fb2158f4bd186fcbe5c116d48d8afacb0883eae7896efc396961617177771e94a5d4ca616d186ccf9d06594bd7817976843b278d728cbf9d0146d48196f8eb2196f8e336ace1fbe441f5ffc8bc5872fa20d49e35f46598d7fd9e14318188781e94a6160441b32f661cc28bbf91819995116fb7046b4210bf033a3ec003f33cea899001fd2883ede3ccdce8735a20d9980af19650af81a213e4c91c253a4e84a53b45aafd3df4e91d89f0d74f3671b11c09f1d44803f5ba8007f369203fcd94342fcd94912f0a7f328e04fc7c1803f1d0b40fcd950e4f70100fd4343c61852a99a19148a245326a218c49f4e0bc09f5e1bc09f6e33c09f7e43c09f8e5bc09f9ef3d90e0316a080042040880318a000041880000270130b02886f3d007c68c9a0c15299a959a598a444950ad1ddad1d653c7c78451bd287bf9787d6879ee77d2f2f2b44ea316fa779f0f067db7a891efeec1bce873ffb472e488f901fba067d83cc22e745963163071a355efeecda1856ab540a8522c906ea20a121e7f11cfdd3fa01c77817aff330de876ff13dfc3f0f2cfdc24276532346636707173362c8809175705abcf89c568a0a25459e745de779a3acf5e127da902efe1b65305ab4fe65e745a32c86ce87a1e7e920528f753b475a7f56a1ffb322c1f9b30eb5f8b3795cfcd93860fcd93974fe6c2576feec598c3f5b87eccfa68d21f6672d43fe56c0feac41ffab540a85baf9b36d2cfeec5bce9f8d7bf167e7f29fddb3c39fedd3b517d90e3176b20e8c172e5ae4e0b0f8d64dec7a1f6cc58949090a0582a048b421557c188a36e48a0f4315de87e3388e463e1a75a523930926528fdd1d1f2afeacb81f367fd65ccf8a3fab101f223f4574a83fa841c878c5e53543135393c2f4ab552a2534d43c9da3674dab419e0e18e65bb0f9ae5ff12c6f833fac82e53361994fd1aa798969a1819971bdcc92c5e55bf150a7944914c5711c65de8723d1866cf9d12873fd689c51338bf7995e9e1c65304f9a1f964a5e2a75a5a57b633b34090f8ef2cf9a83e5cf3a6bf9b3ea70fd5969e69f75477ea93c64feacb6d69f340e993e07febb150b67455768fd89f9b302d59b492606e6e565ba5c5a58564afc79df2ac3dbb156a6d58a442291e428537d58126dc8d5974a26d328ebde34ce389d4e2894a3505d29cada1b917acc77589290e967da4385a4fc497d68110a448dd0207a44050c47259313540ae579c81ca9d9d3cc5ab50d5d157cc2232631e9572f7e0aeeb00ab38c2cf89527fdc9fd289812c96d2acdb13ca990dc7f82694f6e5279d220b9bf44736279deacc8fde1fdbfb9b961c10247b421c7c71965a4c71967e48836e4fd9c51d67d4e0bd186347d8b5176fa161fba70e12e5c74a52ebe110d9a33b0ca45ac5888d463bd43a2449425533353f2cf1b90e6b0549af6a71415d3667f09a6fe429567cd29c684699ba592c4a4119f26689a2c35e74569fa61a88c4bee2f8d32c0ec258b104724c954eadf346b4e93fe474d2ad3afd3b708593fc411a9871f088eba074547d41bdfca02508494eaa84ef325da6f997ebbcd69ee3b327d771d38ffe13e7c0664a448112024434240468a24f9a9b5480321f1a14cdf8580ac914cdf16714fd279d775a5ddcf8f1caebb7978db7ed85ca66f716dbbbd44a67f9b474f10cf3daf2bf5ba2684e4c8112121244782dc8f1cb1428de3768e4cff368f508724d3ef8ef4cc6b1d99bed74a7cfe7d5de9174469f58113e2d3e3fec3878f8b13527d7a703faa8f9faf48a6ff11011d04bb52b0de8c30c2086b87ee1d67d46c048f8e4ae3a93832fdcf885aab3cea0e918b445da96888d2daed3bd8aedbc1ebc90b00caf43ffa936980427668930247327d5104420fc3ae34fc469952b14d4a76bb8bd65e7a3d4f2459c07146cda251261a67d42cda9035a38c7e38cea839a64d17c5ae54fc46df37a22b7ac26a8d3069ecfbf3f313e5b563949cca27d645c726b924d386b9bf6c495139ec44c7a71c7aa263530e3fd1712987a0e898cca148744ccaa138caa1283a1e73388a8ec51c8e44c7610e49a263510e4ba207e6b0243afe7268121d7b393c898ebb1ca244776c7368223af6dc3944111dd71ca6a854a3ee65ee9d2adb98f7e7575f2489ea184bbffadbeccf5da61fda91bfcb5cafb9ddcd21a41e63c2631d7698090d74be42e460020337790833dfd8e93ea4638def3150a3c85e761847f7493081819b2cba96a6f0eead3ef6706a4c80cac3c3c3f36d80d6f8726d4c00dbbdcd57879b6b48ef082c35d04cd8f17aff7920fb57cfd6c323109e9d897bbf882fdb977559a9fba8bbc480e7dbb6b4d66e210c6d48ef3acfeb3c120d37efe0968c5b5ce0161f2a13cbef7f7a42f8fea79ef05d7c814b1858c7662b69fef2f14d6ce39bd8c637b18d6f621b3366e9e8d76cd602447152bcbf4a952b691e9379d68c357b1a6fc6c5a4797394d1982fd33467fe35e322bee099bff8e66330cdc360ef75308b878171fe05cef91a0c7b1738c59bd8e69335b3794c953be1694173ec75f8b366c59fa6cd9f7fa6485b6e51f690f9c9e0e7e0720807972cf00a8e36fd6f7089abb5c923e77fc2e3311dcab346f42bcad3b429cf57519ea9577992a237cbf393294bdacb7cfb295e268d37e3a27973e6cd5136f32fd33469fe4563be8835d87beb3906f790791813208fb166264226481a46f3fe26430d9b314d806870b9630697351e33b334471936af4106bf9bb85b5a4cd1c4d5c585467b8926a63906ab82c060558f6b94bd94aadc4c959be9e858b9c345a399af97d79b5894cd97695df82c73647f177c7a135a54b9d35c51e5583e780cd9ff4b1a8b35f326ac5439d68c3594fd51587fc29ad594b066b80ba4895693cf9276d2a17c96ac59492b875aa690fd45342a94cf92766bd67544bdd12509f020b4214b40da6603896b65c17f5efa68edbd6437ca2aaa7390b5768a56efb6b66dbf97dee779e148732192d64a2b4d9cad5cc082eb93f38fbffa76de078623592a9528c5194f14a7e4a3ffe10df8eb02fe52831069ec51794213b193381129c511d99f8c86548fb65441ba50f651c69889a8e26c04ee292b115c80103f117800900d0ab4d91fb45211ed4780207c5458967ea5e3cdcd0ea85127e7439bfda791469bfd210bfcf0c50ec7fee77f5224abfbdd0541d0a47bac69b3df3bbfd69a749faf6994d94e825c8df6070932c6feb4194471c2ef9ac7bc6fd1fed81f7087adb5dc6faa34fb638b74ece361fa6a5fedffafbd5df8a7ff78b3af96e28c0d22ff50045a4ab1285618e4ef2b8dd2f4d3ebd77ed816e997570fbfbfdafaa9cbb27c1449964a2b2b2ba5d87d3ab1b08c321b2ca3acfb303c6badb57aa5d42badf7adff0d59467186839c15c140f996f6e7abfde4feaff6f1e898a8a35ffdfd25a3cc4b7126542249e3a87b9227d395ebad17d8a046cc5ca8042e842428ec14926eebfe5524a4a55ebfbbbb6b5b5bdbb6079d362a6dfac9ba5940f6eb38499190970cf4bb170009d999500984b2a5df6712220159b37d8b06d38806a11108095921fa0909017981053a28cb690a656fd166d8891bb8e5da392ab6e1f978af03eb8186cb6c794b6d2a7fda19cb81fce5f8eddb1a8d95f7df9ea8bc7a89adc058babf6953a72b756834ccfbe981c23c283c20d1c72acf4f0528fb874a7892ecef792bfce5b09320bf9f868d823c28286c54066afa8f3ca0ec2f12f29889472424123a43259a3a6d1fb9bb60fb2becf9b62cd1af165bc95049928e611eb8d6eef65a6bdda248d2ededeebd2eb8fb15bed9855982804a25534fcd5a5b92a45f5e32b4f24fa9b4d84e5f326455682bf8f52bdc65212d3c43285409d0cfe39b898909ed18ae3d7d208aa3f2feaad4abd04657e585cd51067e1219e6e97ea81b8378a15a27a1427bc1ddbb6095c7b8f5257e79f9e21fe231f1a0a0bc890785a4611efd5229714d049dca77abd7aab5eaba3100bdc33234643b1731ed60096201c22c3f54c67f94f2fe23f1cf91500e77f10bfd90bf702db4e3afe0161b6eb97da0080441151e2ab6363b09f2fbb08695fa48a5a6b243a5eb56ab6ea5a2b24385870aad4d4f823c712db7d81a89161b4b10c5618d1ed73cd622fd89f293fd698badc546c14f74c12adfd2fa55910cfe69da91fd59b04aad4dff15ac42f3d7593212cafe261e8fb5d8fce524c9c433cba23f4b8630c6f8316eb12db6ecad12d758d60873d589700dd7ecedbcaf52f01ba9fc6a655f65d5a5e0d3b3aa3c59b08073a8d05c483e4d3b700eb3bca16408fb9c2c5d20c2925a6cb866f35932847b700dffa8f050a1994299aef811f7068a679280d2ef1704cd813cc95a6b14e499ea7677d2869329fab743f0b64691a3ce81a4afe3165bcfd22ccd56cf88a5b5a5e5fadded58087db27b90d3fa0541d9ba7b3779d61cf4a980743f55d943317c20fb7bd80ba232fe4d23eb576f77f7200f0a7d3c0c37ffbe0fa742efbc5028f750ee8f27e8cbe142413e5e907f2228d62848d18b74684f8f1b7fe15a240ac1eec52ff526f509c25f5e0e020a9ff0eb56d484a138cafc7b90628f40f8df0ef4624c531cbd91da9a1794bbbd207fb51734226f088adf17966238bc4fe277bc9209f7b73f1a6bf8d7d2b6e97faff5a7b97bd13b17f9b52551047ee2a87bf1362a83cf32fdd03a415227ac135f0b854e24fb4fa6f4a3209bccf4ab5190e7976df77d5f58cb3002c1d0e4a4340253282857adee55b1c86e754f24f15b71c1786586e6e5826b52c458152b4c261530d35b618271b17cadddee6eedbdf7e545a775efb5a2ab56f7aa5864b7ba2792f8adb860bc3243f372c13529626cadddee6eedbdd792ae5addab6291ddea9e48e2576bb7bb5b7befb527afb5dbddadbdf7765f8995b997ec582c56cb962693e9b5b4b4b858989d980b173b31173645cbbbd889bdb4745ac480d12283c68d0b062c40010940801007304001623ba2dcf202001f86c47668b8880143864e8bd64bcb10cf941a4f241352ecae150d796969d1f9cbc34b8cf7bc9b6f7969e9b48801e3c6e4992c30aef16f478a2792fd44435a620f23460b1d1f5adfc3cb4b8b28df0c89edb8880143a745eba5e5a5d5d2f2f2d26ab1e1f82d2f2d9367b2c0b8c66f91ed106327ebc078e1a2f522caa309b66288671a4f2452ecae150d318da3f9a10ad338dad1ff68f24c1618d7df8e144f24fb89868cad77c1b0982b3c6c63328da2fc435a2f2d302e93c5338d433cd37822916277ad6888c91b4793c91b6d091c4ddeed48f144b25fbd8d3231302f2fd3e5d2e29944d95ed66a88671a4f2452ecae150db9d692dd7dd3e974427d6f6f478a27d2271a62bd279d4472d5e1147caf15e56f88671a4f2452ecae150db12e40d1101a443444344474573642c083f2bcee3d922453a9f77c28452281b47f92a8d3ea10b387247f7f5a1d5f0e9e1cdf97c3023e44a67cc88744da3c6e4770e27363691d02f2bcb96931be8ecefdd3854efef4a194d5dbb739680c25f5f6579886bf9cf42798fa8bfc8ba9bf4cce551ea94c2754c9db4f5158c9d2b2f7dd87fe1dbe0101e9b9d3f098fd4ccaf323c9f2244925edf11f478bf3d8f77d246971d93fb4f5a2b0c99f30d959c827048c823c4940619d037992805498f428f87e0a9fbc09935efe6cdf47927ea6f2f9d9b2bf58824940fe2a3f40d69070cde4934827a4b7a3b72f52f9e5911d6a9ece844923dc05c9221210aabd3100e0cec9f497bf37f6787ff977b7b74aa5dadd411449ba48241292cf4f4891ec1f7a2ec1a71f7f759ee78d32f265265190a748cbfe61389280e24002058e1b1aa26968c1124da0c066e40c32a03d4b4c8127090fa4c083c48efff5d1a67fc59ec395a8c235f728bb2dfcd852b39f8eb7244286cd183022dfeff198e616a63954115517776ff706de5849a8c10d2f108a4112206cb8b102153ce10362e0f1a9dd088002361c99810db8700338bc40c115d6607b01146b00b2e3cfc27e93b449f398db7b73dcbd619a5368769cc7e84e3e5d0a34f764f75c769cc7465bff7932da3c56faced2ec249fa30d833fa032fe2a180442a5f15f61d00795f14fc1a010a80cd8447d8150e8b1845a76d008b4ec3f845aa6b9277ab20e99e69e08cae08de274f6077f4071fabb0455b7766b3cfa05e80309d2f2945eab409ee06dc847c3c0200dfb91fd2cdd465b2efb68b3f9749ce31a56ffc6ec0c28e8810e8204e10c5fd8f12fd13c269a81086e40c30bdec0630d3b3764e005320051a24711e600851dff92cd631298c10daac084190fa670841dff8afdd6a6a3e0a766fd145e51b3fe094e51b3be094651b37e09ea642a757759527f75833ec4fe4c73363092cfeed27f1c65d40cde4e4076f3384fbe79ac16e997ff2a9fb5e7de8ee42a92ec7fde9ece01d9c3fbc6017982b70ce2c01f0dab44bcb74fe4727f9829901d3e007df40bbc350ff0f6dddb924c81ec10baa51d2778bad276d9a24dff1b12b9d3848f71b4e589eaf25ce52692eade40daaf3de38cead3a6bfe8c70f70fca1e6aeb936e94e133f1ad6b5dc69a2e787b7d3c40f1f9e8f86f90071d97f342e17a4cd5a6b2da2779ac8ed34d183f3d18de0cd63f7e62fbfdd5b76dc08d71bae3f702e48f6b7d5078fc72a8f7ef9d79eef23c954ea7ebfcc7cd69ed40cfaf2c734a6e32f3f7f00d4f447a1b020daf49f41bb903d0103a0b0234134ac02f406e4597f641f17c8fdf5fc72111677b3652f42ccb5da1097b84011ddb9276ed926d31c4e0eb94719ada51d27686dd2fca34c81c82006e38cce18a851d45aebd766a53254a659daa43f394c89b4b4e3444f9b345bf0d6b0ced64ab5af28de87698ee803b8e62cf6fc612668ae0848e43acaa899da80fc9ac76e8d96661eb3387a7ea55997b534cbbeca14480c78e4f3d6b21351bf773c4c776cc82bb3f65299c6f5b2d03b3a6fe412d5117ec33ca26fd85bc510e4db742090a60e2405a203473e6991ec3537399064ff160ba859d1b057ce7238e2df4e615e7863dd9f285f69fc4b2ae37fbac91018f4755222d9ff522864ffa64bc8fe25c5794165fcfdbfe6b4a834fefe37a4b3a484ec37b90545abc5ca028ba582051595d5cf6a95728594149515542a942aa0a0a488a45227434e4e4ca860625232859212940f0a7592c2e9648a82c9548242a9440a2149d21348a4911346a3b109e328f68862c88430142d4124029500825f90eff392e0791d12baee02b9373b95a91606c571f7ecff82e274bba038f5a605c569d4584b92dad28e13b52aca426843d6fe50f44598aa278b69664a6bfcc6ce4966233bb51d7f4a9e27248a63ff7efd4b71baafdf511cefeb7b14f6c1688b19c410704003a84c7f871980174065fa2d56009599007da16a8e10140d09a03299f69912c26395c7a33f2620eda75068ecc671299fa92c7a0450997e4a653a01350d540a64c85d5f27f542eeffba467e9d794c085a79fa3dfa93ba95a794291018ecc84d03929429902ed8209fb566abdbd17944f692de325db921aa1e0c42ba436dd83200c13f7510fdc9e2540163c5cc0c8c8ccbc59222f79f2eff2a2fb9ff6ca1aca4504c327dda245349ee3f455f18fe6949d4ec17e103d0573f8807f099e47e57c9fdde5591fb2d8bdc7f001a2488f2d4219fdff7654b85b0b6db4b639e8751fd320294533205624409998e407cb987f73a4d7acc2b3bccfdb57af544b6f3dced519caebf6b8ad314a7fba6b7ef105ed051587b6fd70d8116aa4e2655989212ae4ea655c80a5b412e60010b5820caa10515d6d593440209245ce00217b460051d453fedae21206bf9d5ddda7bf18cecce31071fc29fe7894694ca74421ee441ede2cc5e8b047b6dcee63e9bcd5ea76ec8c067cbe5c22ef4c22f1485611886a552e914a2e850ae240cca3eca083311359f9fedb3a5a0a65042d5c9a40a5352c2d5c9b40a59614b059694741948d56873350e399bebe917d99c1c6c10db637336c762b15af7b3f9ab6d2df15ba25f6dbdd4ffcf4291240963fc62a92cef97a3ec7eb5ef1e7eb6137cb625be5bee3fd9927cb610fcba0fc5592d214318865eabd75e0159abbb7bad5e6badee5eabbb7bad5e6badeeb5babbd7eab5d6eaeeb57aadb5ba7bad5e6badeeb5babbd7eab5d6eaee5eabd75aabbb532f29f5b2b082147433f2fbeec6fbbeeffb3c4f241289a2288e2808c11169348aa108e441586b6ddbfd99a029a59492f6deaefb3c59addf2792e2388eb25a5638905da24895564a92a59235555a294ac90d2eb5fed166684dd0b91a3dcc80c964e41d1a3bb8787b010a7bf1f68ba031186fdf080ad3791a4481e80ff549414f9a9b69f3754363df6c4561353533c64b0ccc2d08381fa02fc0c4a0efc763a4dccc63a41af353648af22469ca9f3c33cbaf9a1dede730bb1c837bdc87c16f22d4b0ce6ebef74f61601c303e89df815132616f0d236941a0303206359c8fc74e38a0869d7abe4061a727e07cb2ffc92728fb93721e33b10d79cc04a8a6c634ff532992b4e53269289b18954350247378cc24477ef161d7759e088a429148248ae38836ea1847dacb34cd978e1db3d188245624248da48344a2bd4cd37ce9d831a391aadce9435234714a0e51a24a88244332318a0c69626282ca69f13538e6030b980e2b6c54bc7c6891c32206d361858d2a97ca2a5e5ec9289b2931f1490e5326a7c6712ac931b8dc517b294b5a2b81c248647808050ba18c41e0201d34d2d391354b116558e69477c0250f1e72a1502e195c7764bc64cc9789d2222412894c353016c2411897ac1e568e6563d55834d68c9523c5c5256525a596c223650915904a084b8b2ac7c2c2c2c2c2d2d203c8ca41715eafca794c8666becc1b95495d892fa59c28a6d4c02d403f54e65f84bbe15aad56ab4566f365ae6834951d2aa38c5563d1583a582cdacb34cd978e1db3176cdfc4a44c0363a120a01f2ae32a2a2c96100b092b09ebc6dad13ab166ad56abd56a9d4e709ce46853884795cba98274acdc4153698d720f3566f050e248e2776a7c143b3cbc3f19039296fa93acdd6c34763006faf1c1a1a0bc2ae808ab0666cd5a079b0e5b0a102925252525258564b1aa27882af73ae159fd79c2a3caa972af991b8b467bc1afa781657ec698773016c2411888ca380a55c262b570b489e3c1d2118359339313928989898989c9094995abe13c76c2539281cb9c0c97b81d7059e3e1a19933e68b55d2b09863708f9b77815b80a88cdf984cefe5509904070fd1272412894422d1975f33f365defccac4a14f2657785670ac28b1449b3bda2c098d4aa552a9f42759faf31bd156c00cc38a61bdb0b068e22fbff8b7dccb301ff32fcf3202615ff5e27fac61dffcd0c42ffe6594bd7881c71ad6f4f0c53162c468797d0c4ccd97895de20b9e09afa2e6d090e62eafc035bfba6fee5eb8bf6d5e21aaa839ae4f5198f8f55714d6f2f54b688ec5551aff935cbf44612a5f5f4461abafef1496f2f547d5ab60d7f2f6cd35e5afc8aeaba3d2f85fdadd01da2a8dffebbb52559ad5db3fbeaaa62c8118bf755c5acdb13e7747cdb1446c35c7febc74749766cb1dd96b39becb75b8be069f3772cdd35156f33a0d13ff8c69f9b306e6d65e2a7fb6acfe64a5fc79529a95b9b280b74ae37fa6bcfe44e59a052a53cbd3beeb5fd8fe541a2ba4d278cdb13e95a6e6582295c6bf2b59fe966797dfe5d95d0ff7bb9f71bffb1bf9733debbbc6d7dfc816d3fcc245741e4b1595c6f52aace33538e65d18e643985751736886f9184cf36894c1942a48d791e908f33a6d858cde9f8ebe545a21d93f65854123545309141482c12c983ee0fb5b22adf7b73fe683cfe293bdf5654924fb9f3772d3baf7faae3feb9bafd7f17a7620d7b734d7ab749596d666cdaca73b5898e633cc277803916012e1e5b3342bcda084830c83697ec134575caeda4c15813c2d4d6646a61c6d97661ff2240d7b2733050283388caaa7630d54567dc5174065150d62e66bd31cd227d787f17703795e2017e1790898af6fcb93f5c3ccdb9877f92eefad1ce202e510ddbbbefb767d370261fe6dfbf744657ba280a06d8e33babfa53dbb17fdfd0ebfd47285dd727d980f6910f6657299e6ed873dbcbceb2bbef769f77a177efdc51dbee60b9f36b28b8e40982e1bdd831f7a1d7ef9b08e00a899c64bd9b581bca50dd4f8a1d78d3cc4bcf9e12776d83e1d015073cc79df96fde3d3b146ccdb72889837cb2164deda409db7b481ca31a595e98146a6a4acb208cf33ef52da9ab208cf30df305f7f9829cf9a61fe3c22d78bbbb187b37b1b81ecfa6efcc17f388bf00c539e1ec8e30ffd43995de5d95f847fe31a564b2fc27fdc7c5cdcccc71a2319343f53e3c9333faa21caf7ed08c40d6fac517fe675bce28bedd8039847a78d6c69cb3c6d188cf9f2b45f32e5f9654bbe9016fcd1df7288d1cf7c8f3dd0fcccd7b1c6e8671edf6f7cda18e1ceb47f87b83ff3615847205cfff2757cbdc5dd3786294f1b2f3ca37bfb263e6bee2e9e317fe675fa05bb3a373e6da0f2ccb75c4fdb345db72bcf23f2cc8bccf2b481a2f9469e2947ef34dfc2e70e36b2e8efadaadeaaac066aa6f97e9aaff8b491eb3711c82ecfaff814229fa2b781ca345fc71f6aa6793af680ca34afd31f7444c8c8053b776083e08d06d3fc38c8c81121236d7a5f22d93f6c7c6d68c0e6141e6a9729347297293cdcc8f56f0c61cb5b5e9f219044d81b0d3e6ba6f9c64df37da599f7687b824ca9613f053472442805047f8ab479dec834a84c833bd75156a2e1c813bcf5d4d202a85c5ff4358ba8e8bd2b7b78df8da81d26ca941af553ae91234229d72703360ff193fd16c9fe37f28d4c4719886b1c797d1a4669be3fb25f21d945233e6fe4f1eb281bbf45a28a691611e127532299e6888023e78680245b9aebbd875abfb1fd1f3a1b2db22dcffa1aa8d93ef9b7f1ca5bbcf295b6b95271bfc5b8e2ce1bd99efd4574be40dcafb8ffe2eaa33651696a79cb14b0a761aed2e6dd3eb529c1db57965fcf408a7ef4d1304ad21093d8731e7e0c4a2086b4a6c046a4789bfede6ff4e54ff32739f3672ad7b45ab9c6c55ddcc5e5431b5ca2d14aa98f4a331b4c77da0952c5b3de59df7a3acaba0992754dd0c73541dc689a7fefb709c8fb3a6e9adfc3e6e968dabc10c896e7f641b6ccb77fde9b6dd3e2c05bc3ccf79507711eb3b9dfd9069774f4cbcbd2ec4d5c834660620a94bbb7c1a5d9697133f36de70d13532ad3a0cd062ed1b01f1ddb2142deefb7b497f2559ea95c67d0b9d71290321f6369e58b346d8a3f41a0afb73cbfcf7a79a6b28f444ce687f93adef69857fa85197d0a4c7764301196756b274824fbb7307892e0ed3a718240b23f0c3e8bb02a708a79031de02007cf4e8dbffc3b08e4599aa1640a04062108df53847f6b18e9a3612e26680e68d301857539a8391667830abb34a039b716030ab35f73eeadd2c080e2f8203bce6d0d766ad9dfdaec2dfb9b1f8636e4bd40202fee06de720d0383340cf6bae1a5a1f73b4178178ef9f44b8a433efd158a739f9afe5df7c44f2b53205bc0e57bf31808fec0dd480a040aa0fc7382371f10c9750f480a040a1b981bc205fd00c9024eacb866d0567328a5790268cb4e50d33ffb5fd0084a1092fd2dae8248a8559008190814076c82cadc6a0ee8a3d2f807018b90cf5b6b0d69b5585460b154a6a0a2b2f259ad52a49092a28a824a8502051494949054eae4092727264e30312969424909aa07853a31e174322dc1642a29a15422839024290924d20809a3d108641cc59c288647084391114422b00820f8fdf83e8f089ed70da1ebee13f9e6fae0adad7582e2b87b1314a747a38c6e21509c7a47cfa1c5a5ecc234f70349267197616010400fd31d4a712a18845e41f69f51976b24baf0f571834065fc497c81503613e409deba27df8569ae086cc824f632fd4c40927fff2ccd280eccfbdf1fd0fbc405925f1e66b4790c04427d39d884f10848c8feaf21647fb3ec1a09ba2c0eb374a428e6b0a49fa0e0ede69a40c12964ff5e823cc1db1361bf6badb5d65a6bad96beea83b852ae28b9fe794d4872bc4f6da9be509b34370fc873b479c9965d066580910fbbef7affb0249ac61f689b2718a477409ee0adeb488c5d6267129de2bc695ca24d1ff2242d2cae55c55e0e6dc85bbb3cccf2439648c78abbea639796667734ec77b860e8fb48f2f6e0cda2a44e4c4a5027d39ff5415ce9cfdb0e2e04e901716d7a8bf166d301798e361f6d8eb7d136dec0db78b3efb5fe686b73bcd93f479b2d47077dfc35dac69b0c9000bf7b7bb3e6267bdffd798364ffb691aed2c97b33dddedb4d7dfffb9d7f3baefb9f6a4bf3cfcff527992d88036ffdfd5d09fab0d5559e64aeb6164101710dbb2578c3200ebc95448040faf4b4d9309a55aff2a76321fbe950f8bb908e81b7d389647fcf35ecd6dafcd1b06fbd0fc52e8f0e627d80c4dacc90fd291872b534d742f61616cb63794ccbe3433ee4495c2eeb7299ac9667adacbc4e7b92b63cdd3dbc5f8d2b1fda90e563233279ded4c09c4fbf2ce3aaa1f9fa5dcdb15fcbd3468b5cdf055f1bbeb51e64fdf3d6f2e5d1a683b7174c79a63ca63c3fe63bf056436331d844a5f19fc1a00c067fb419539e264c79fe4bd95d9a75832920cdeffeec59108ad3a36d08c97a57597ee3223a5f1ef65d7e94b9b8609b57de872db1e29b55f8862cb18eb21e47b4d861a26b0bcb4adbaf6f6b12902881853694c1e70a6978a0129c4009212620811076c6254a8c316db3ef8c3cc1dbd9b3db78bc8db636471b3dc1db509e5ea8b4a95c8b82a064a866460000008317002028100c07846192648920f914001472be5e5e4e180874184541104629640c2186000008010020232334630200e2be49081a17149bf9b977d42c95346061a08395c868b7440a6acfdb077563f534a416d5e6e3dcfc5ef89780f9c847d177a6059e8b5ccf2c71060e63b1c126e55572426b893563aca535238e53666e03047f93e23b42e3eaad378327da4c87f73d769f54aa7042671e122422dc9e6c8ffe8ae82a9857a0909edfbab23ef8a9b66f29464be1231780e7f459819e3d3a0be2ef2c7928753cf1f7938f0c4e527875511feebdb86a6d69433e058636dfd35f905b91af79bf44adb6d44dc154193bb6ba74a476b701fe8241c0ec8bb9d59945b500062f1488f6b00d1ee2a4c9a3346c8a488ec589e7b5e5fa53e3d4b94c84802393214ea9937eae22620c322eb6c8658ba8bd9f4318fb23ffe25a67279896da2776b6bb02d73e13770adfbbecc1c887a64ce462fde5e2c6cd7c4a48ca05a28e414b37c67e56d3a31ece39bda6f7440c4ec787cf3b44a6eef184f4ffc772e971dd7ee45839544ee623ddc7624711bd2114a3b871895f9f28d9caec7940586d87af3858990a8e4fd64dba61c75781112205b666dd2758669101050481183cf6db1b53afaa70094ecab594c2041fade5a7487b540a9014ce33ca2679d1c84f00379388aa7b77bda2b2c2d9d4dcbaa1e7d0dba10c13039002b984dcfed0d5ef4dd3f2156b798b7dc50860e408f2be260af78cc48063a909015273cf1757f7c82ccc36288e4d476b1d7761740922bf4c662f8aaf8e66e7cfda00843c7980ddfa20c24c292c5bfb44a879b2a7e2210998655ecdd2c826031b7510fcc885718948454d51c40d75cfde34f06b2b9e1625ba56e1abe47e1c31a82cb348319dff0da691eb14a2e6c1f9418c33e14cdf7b1928e556e4f1293957955d443dd5015f2cc25e792e4a5a9de1cc1490208ad23bd956702af8e676656ef55c69e12a8b2616390bad83cf09a1a8b92f4e61d1586fd09ebfd2e5d94220f7ffbe03705cdd8d83c4070fb01e65371abbebc22ebeb22f4e82f1164f2e1c70e3d1ac2bb4b1580e39e3719bb6da0487e3d2bceb147a89227388b434a90eddb3772407311ea508c16cb592e47e61a55a1e540c79a32d52bd0a40127b2898eab5243185d35e46c03d7bc8161327c7763377631cbee06b812dc4cd946c09768554622ec2d9918d256daf6dd260171c390a431c00a08d5486eb5edaac8e096f813d1bcd9c21f3b3ed347254ad2d07c8fe3d8cc9135e76655ece18590c0299b9833f8b378e7b41629c22c221606f8784058fcaf993ff82c8e13e289710acc0fa8a9cfd156201b29085b115e414198160ea6e2c0ed2748177edf774827436364f252e41583486c0409bc65350ae87be201fb614729127a9b9d2e7373b964a8e159c10549cb915590da2a570b1d76bc5eb7049ac3e989d4d917a61c9000cd9429529c9b948885e413506974758a7973082e2725c39ca3499e4a30879d2848040cbd79694fd7121b1fbfa8d7f8d72363fb90817f948dac04b5ac39e522fbec7aa748a9421deee95cdc3907743be6d8b5882a48f886109f8b6a9ce4910d3be87e3a43506b31044c0fa7c15371d15c2e4420c10cca274c102cf447949102b14534096397fa2f7f713770c00e2eee911c482dc4ba2abcdb3b6b2a5e2a65a603fc1c2e76bd41bc7b24830cc61c916dfb678e253a69a47377a26cf4a798456c530c55c9708e0058e195d54443f34e95d73e542b173036efa52264f7b2a21303d1e92d338008d71643f8b286d428def02f20c15fd02f196c6f14f8bd689b17a851fbe06d9074549b34c9badfd32697b3911ff10ba74b2d67c006dff5de3039707c65182391498caa0bcaf32a75ad4e80668bfeaa1881dfbb51fb986b403839adf832cc7339362fc632aed5b19ba0eade76fdc1e03bd9198a770ecaf0a47184e9d51c4119185a93094736e31c14cb5205e2b87f4392809c45d0ed7a29484a5341716dada8379116ded46ca52dee31a005357c9a9bbec387913a04e3549517abd8037257fb46f808dc4bb08e4db2f479c2e401926cbd9d577feb0a00f77e925d84ab917e8244c4863ae579c8c0cf4801b22227dd6a9193793d2fd15487843e8686481e41b946e94ea918eaa36ee003efda94a139aa0a606396e4888c148c04c4810b5f2c8769dbfb6f70e9f89b26861d2d482b8c8882ca9be8aa118c93b983afba4a3bd9d20b8d851ffc0adade76f991b8242d666094329e7ee727f7cb1c21909afd9932c1dadb02176a92396dc30661c6f3c8923b8cb38ef6e5233a7d07bdd1562391e53108c7fc78f4c4d25c1bf480cac4131ab4058da74425721943c2e3084b48403f6b6da0bcf55282520eb3c0d4e810c0a3024c2cfb54769a5ec0cb5814291840d12a2cc095b1f2696026a41d0fcc8ff783ec31a5f24783307dea8baa0a1df0bf217e6f1080371cd20cf8dd8734692c0736d9bfdbb7873e6fd8c6633eb777b2cdde0c10f6a9e53af6e42df59881c592543fde89eb12f78bcab78c3d8139e3bc7eecdb1607760500d7c8aa91369a7c9f66ab8a11c012ba15d51f54a035d97089e85dbe447a063b42efd60aec43d4ad0f8ea6d9dcb52491721dbdc6a3fbe4e2f1e1f3c0bfa3a60c1a4cdbc32d2edc431d63e2e4b495aa53876f86170c0fb4b0dd35f0083f5eecbf0bf4571f402e644738f5648a804e5ea01fe18743f81d89fcd48d1272e0a3f68d9a22aaf2e61bc53edba86b008374f72b611a3b0ce6ea514602dbafdbfcfc61191cc340be65ef02914ee61cb9ff6e7b398481a455de3f3ec89dacb1c43c255fc19a184177b76e0796ad01583ae1684a2c072c9057b0f194d569d7892b478299613eb4ce33679752361452e0ecc3408c924923a7470b8d0375ad67c06496fa52a8b5e130d8bf7c6323d56afe1b69c99908c40bb09647ffafc98be5ce572f3815c2022f81ee92550c999829d85760ecb23309d0ee9ec2d2893a3e368ba80115d4d94deb397b49a39913c5baf298b1d59bf917d9765e0150454b1402a6aa87d8a6c9b4fe16c2aa335403fe43255cc408ad38bec8e5c04f43609b5802370f40a3baea19908a7debec67d6b022c71bef38a313ef20954c54f869e05e57b01f51356534f5a5d3681bd528abad2bb1966560f6e777f5a5ba5d12db28f2a05ffe5ff5505bff7b96648b1800c407d544a4ae3577ba0e802fd9dbda122ee4774701190a7035030600e8b485d4ee3e2b17c4e81ce731bcf9031b7e79b01e333cc4e1c02f31e0ea20f13e864d0cfb67e0e69c54451bc81b8a4579c014b177f456bc8d9d84e7919b1f5d5bf2dc9c3f31b96116e2f00bc92b6fb3285247ffd604e5db99ef92b6f6d1bf0d2f19a38d4e6b373a084218b16174489b366ae5e0b6a25dfe980ed9546f128c5fac5b4397a060f8bd84dab765a166d6fe47e1f3a5f48fb2d26fd2796d4bd84b35045d926e6b41fb5fda7067e12975e1dc1e3f564df9c6539ba1aa6193b5acbd949e4e3c7b9a0ebe2c748dacea6e2199edb057e6d5762529fa70eab42ae930d39115fcbc63455cbcaf9b3058f637e5a1dee02786736e4a076691b72aa3d0af7d7163c87c19544a5494522222e6d954b9aea00d8ba669cdad3db2ca5ac2655b17d88db2e5e4bbc64ad34f3b945b8b519172be698b99a2adcb34000f46a2d948cc2644e137d004c84bb3f0a8d5121249ee72ccd809f9298a187f8fc3bdd36872ec4c359a6c9eafb0ffde1c70fa1f75e9683ece70eb53a18601ba6d32a936ece38a9530c9a3634f7a449df5e8335880996f7b762d4e5858339029ad26cb7235e3eb7c6ed97270188c4c6abcda10a301f3f1244af05c6f41fbaff9c1e6cc2f1b415edf0b6ecef703b5cd28b945f7d02d7f2c6e9b9eca596e35098b7392d6f36ce3b03819c2002b36ecbc8660ecdf69e8be7e8204c71c575dacf26446716a3f6451d37c2a42dbdb92888d10e7c49a676274769968d32b2e18842888895f4a65ea5d5db06f48ead5bfe56f1aad94ab6e9cd6b075c272578a250d69d4b00a4440329f620d64dab6d31a4407744198970c08ec0224bac204ea8efc8d55f91ca6df5a88b47869b827279ba71f76cce10dcb02600d81bd9c35969e18d70bbe9eaa96c06944fea8b5a8d71b684166dcffde5d95faceba683958dcf520e0f89c06ada0c3b07ab8279d03a453b21ba9b87174312dc4c8ae2edb0917cbfcc7d3ebcf093be5f62d541cacd917b48e404b30e01de613a99c10a8ab5b13524f42b2c44d8ac10a06e6e47d88da355cc6a74e89474ee9a167b430e05a84cd854c2c118fea367f6772124ef4aee8f67fb7d8d16aad29ea93e73769084162c59ed09c561d3d3c9c5cf32361b92df24a81c61e08251971c3d349470fc8cdc3173fc08dca165e240c0076ab3376523bc58b83324180f91a1959659866c8467a09da36677790a2b217c5f0ee06f1589ad96776d058b49e22af13a8114ddec9d59a67730e604284127c8ce7a6122c7f86a1030cb4aef0244395961427c533bece3556435fc89275e18ab93108d63cc975b97b583aae0cda1a930fd34808c1ccdf2a344991b9338144d626045adf174a0191d7da065316476053577bfc8322ed2cbb568cea93e8b696934adf7ae59df4cffaed4cc524b2a05579a3009e320858ab9ba4a981b62a8f5254215605f83226851da8a2e45e64852dd41105d6ffff3ed31db3617c660033b8f84e8ba28196dbae7bc689f17d8fe857b2970d49870da54e8e401d254ce4d3bb0884fb7f9d976eb19d694c24f0a1ca314e6683eb15a53fd08aed397814ff896244ac0d0c2cfc9bac889f0d50147e2c957cc9bc37bee50426a1b6a1786b8958895f978a557ee66d3708b2ecbf9a3b8903ec25536bfdc2d9f64a82f477b86cf54bd23556fbce4bde900658012a63d184009cb9cdfd07cf1a770ef0980fb6263950842f3e92bf9cc08220923489ca9510151cd36b4b8c4d6d93a1a5b6c17a0da3b4a553cc88f1440eee21310027eb7a47c0e5336471d9f295680d25ea0e0f663f540a1eaf99cfb19bbf62a3b556e75e050cb1e777b413f48da4a8f7b578c50beb0a898d0c3cb0103299ce01c238b11411a7d06e8c1f25d56ce6f3bebd3f5e2fd4204e93587acbf7ba251cbefade6534794b5c627ac9182069b9ba57f7fb7f3797b8973ba429c155e72301ba3361245cf6f1f9f33b131a3ff1c5c2c31b611fc483a7612bf995ef1d0f17d96319c849e7ee95ad9a4613b4486037dd7a0c4e506dd0ec9162d30f7d013d0cb6b14134788ed32204a68cb4000af6ad6caf81adacac68a3fc00c9ef874332a2ddc669a2ee5b2ed35d82ed74b0013d223c875a5dd6544e9b4e0150cd8c2df23ec36a1e9563fa415e0c88698801f0deb6e20e756dc8b43c929f14fb45ed5e8d4a7cd307e151e2c4969927e80a153607b8937b39d3f147b0123886b2f52360288893bba91ef50e4e9dac770c3f927d700248dbf92d2eff4aa5585085b6ee6a55d2186f8d77675de92aab92b9e29df4f88d1fd9964506829eeb8090ac0d02eeab520be43941c65466a9c553e5d76e1b08d4db446d671154387c5dcd6e53647dfc0e6fe0df337920dcadfb0eb66245ab9a8a8bff32398029a718fa856af5414cc7d8434fab2318caa6ba709c25a9b6b11fb4dfa8edd864e9832a11561f0cbc60a6caa386f0844313ef4aeb31557fb62bbae093a929fc2d25cfc5623614fc465e80a7b9bcd3f1ddfb56aa4a7855588930a36b860f0825aa93b35215e50ce86d749674972393629b1e1463927a09f36907fc24bdac0baff43ebb5d200d44ac46c1c92085b26cdfb7e5da5212bcb81a5343e8003b8b8c234932bcc1f385a5c747410f7f30ad17d748bf96554ad97afc129df5f1564751cb96586f296a218dcad6a38b1886e7905d4134b4ef2a787b8daf5867660ff0fae41dbdd245320eba0e014805efa09b925d0a6ab579ed9294fa7e7d575282e154b9b81e6d93a8a6429fb540655393a4db8a881d33e8abdb65019778703071fbba9e627d1081fcbcb1a1a32969f09257b5ed9dac589da4c8cb5f7fef93e50bf77043092e4799ac172a0749c26b1354f0c31ea3ef5f690eb256deb1b6a537b17f7d2c14b23432ece0d6b9ff96f16a44005a9b3a1a20c44daa33690f8979f5e32aafedd98ad69c5425f3ab4a761ef52beab386470ccbbe66013812136fb09ff20700f26c1c131de8a385343f5137b18c27323d109ec3c8deacc163684b247bd1662caad3000f6a88efa0361e95c57a0f03b6f60a7916b0a0a0603985f71706fb49a4e8dd355927661ea4096a5337fa365e94e0d4f4a35eb2e49a6a4cd0964c359fcf9ee6b646f454ef417ecf390c81f588ce1f522197cfc8b63660feaff30ca842a0ff5a1b492e85173a7e2e7e661977f15b8d6107f060cd1add887b65cf75c69ef7b8fad10140179bfd35ce9e198f025665b0ab8ea9514289b45a2b12d7f4988e04ae263107d676eba5294603bec57b0543d616cab6ce74d2978a48b6dad13ef2d54ccc82ff179ffcd5c2352f5e9430e4927450f416eb0d8363a5eb2a9462bf01c1ba697e4b0edcc9a91c4b06d4a0af68794374c4d85c9e99bf9e6fa34e0622fd70463649952db89ec69a4769a31aee8b3c3be3b9029e8756dad4a49524158fa1862df5e10cff544108bcbd7f138ed4f45e037c61605716bb6f0364a0471d3ed3088532141b3d71dbbc69d22ea1815496998d9ac9c154d4595a489eb86914d8fc5ffd6c2be03cf4a6c6b9ecb78db9b4745d181b5f10ef35b7040ba9c275635e7912e2793fbe63ccf512bdbb305334a73c2dd4ccf7ddb5492a563956b39779ab1a86d2e815a6433ac8b5087f9a4fed8fd34f5535ebd5c817791747af8c778ae7d3b7c62535b236ae666c07e8248bc4d631b8d957d60a74e5e4ea5fc55b35aabfc6a82f45a45b767fbacc572e12f99a59282c9f66a794e7b100376becdf71ab206c82817c9250688af8dd2651a6156f4e5194111669366ac0d8add23c4223316c7318055b0d18f5e89de6d2eceb712aba0b8580bd34f8a42b41ae4e6de7e75565eec95cffef465fc399e868cb5db1447d435d826970783f08d7823ba8e3c9992d99acaf200122132187bd00a154e0466e4ba05cf4f780233d17016147cfef24258a1139f5b041223b35cfc0bb14394919f3f1c34bd10aea658eacc84e295d15e97292a05ea1f9e254399fdd45a0525b859e723f62546e8d81f3fd86adcbaa796ae819bfe8b39ac4e703a4e38f1867975eeba042841a8bc85564924494d2911e7d1b9f9341216dc1950a86c12090e88e2e859a8fff2fef49f28615b5473e12574c845c973b3acb9dda8f6619a5ad0d354327176686949eb11eee1f75e60e223eccec9b488fc1662f5bacea3b42fa2ddf55253b7bfa0efea77129dbf82ac6ef7313c9bc53c7a7f22fa3bd7747cbf467ab2d711f4b7b636265b9975edc7b43c779bbde587244f41d3b1c3f4e2ccad95f8783c8dd58363ad5bd0c091c2ef673201fec71f88101714adb6a418b7063e13918c84d8b0b87d12ad24682b3d5e820fa25c5a36a4dc1cb9e62d1ebdd2cd3bf3d34529b57cb4ca5ba2e94d5aef319c8975c099fc55773364d62ca51e5fa38330f1e8d3c110046cf4fd30f9418ed0fd03531d0e8cc6681dccaa9702a3907c82497482bd6c2dae3646da78088f379828042b02082b0b16bc3405f9395ddda995dd55fe6662eac66c0dbcec86ad8a3ad41cdaf9a63ab7965b65814645bd73fce6e73647138b70469771a4b739419d4c0cf4466e2bdc6855ff159a928a8ebeae6e2261b6154010c773b7472f1390cbda018fea425213941c2cc38088ffc2add409791cb25788a59d594fa14828509b97beb5fe6b09e1e596aa6abbe5904b5bcd7d3ac584f2aea7c929db96339f6892aacbe2d2e104ff4f7d404e7fb57444e464d95f47f31f0944f87c374d7b1ed817154e7fd2169c3af1448f3eaaad074fb60f59f45eb307c2bf8406dec41b50586e7c5b190c639aed21c423d2d1c9d2f72311aadbc7b14efd7640ad61749b52ae6300555eb8ed66aae199acc87dc78c9f08985a2b1b873cfb94c6190a561bdf61c756fb59b6096755fe8b20dd06742c66bbb49b6cf4c7e667644f63937b2855bc4dae91edbadcbab1cf07836cb75a6ca370208f8d3c975fa20b1101e85bece5ccb0907bdbad7d269bb171bf82344f5a5aebee838d7cdf363e075f3b33f33382e03aabfc7118d6f15ead3a816209d3ea0276085173c32dbb3cd3ce1025c800166cbb75dfc386fcdac17350fc4c3de7681ab4854b24f7704537dfced30227da9a46929c79df33870115a75756b3aa384708cfe5d08b2848cb120ec537df24186cb4b9fc1d6203354e4e4034993cd26056ca242066ef9759965c40599bd0034a1d5811a658e146622be991795f7c05ae88858b218fb2e7f70387920e7669ec2d0d3e14a5082e52e526ebbbf8b37f7e45324bbb2f3e7ee1ab4758a96e347128766183494bf79af8dca7944014a9d9d3332b10002597843df86fe8e5c6f7ec0b6dbda14fef20027bbfa782ddd495b3e0c8aa46848735d0d1eefff9cf7d3d7bedd9ebca5e3a3195f1be405713bb3f56951867eab8a9cd7c33b095a139d2c46f681bf7379b2a4c9c76dc237b3dd39be1b5ef4ff8915c155c66fdc01854ce91655390dee14eb5763f8544af6bfcc813b0793c036efed7d4caccfc8dbb7b072ce1487bccb176e87927edd3d62073d06038b4e451c9aeca2d383aea58780b9e3f0164ac85960e16307d764c42c569fb721eea9ec76c1425ccb62f3fa4643a4911cd88c6962f08e6f17ad3efec79d8f78945ed0e74eee0f37292d50261756ee861e05374078b2b7c1e76ce8de785570332c3c07dbba8ad25fa0f9199b00bd7f75e4cc0ea331edf378b0bba51d3ea63b517cac1ea7b957f0f3a45f4afd339927f0537e9a87ec4fa2afffd37bdd04cd3ea5b1f85336238f4e32bae04a62fc10d5277cfd5a4058a5e7f2864d960fa2adaff986bf1b9c5ec019733169c3ed20faea60cfb9c6418b14733bf61075922103ebc83eb3d21186fba397e5bc52bacbbdfdfafa9c81245b5ec122011b7af3aa0c14ce30cbc06cf33af03e0b0148c7f97dece0eb02cb12ae13a3563c6d1c21a07f3488633e60a1ea2c40787a5ec01a0e810f54102060cbd2b2692e5a3b6b8e86a8296f15a2ac7222752acf05cff260f0a7fa79edaf0d5698a3c93660307fdebf6a2da2f94b39059bfb57e96632f53d229fa2ed3a432d6124b404c28f95e5489c17d1cb69d92162c677b03f33ca17d0273ced5b6cca3448d1fd6dd63d36eeaaa6d684ee60bfb1ae3f666a6d3aea7dea7e4bea4cecc36ccf8998324fe9142eb4b4f9207dc3c0bbba6fc2ef672d2e92bea1dc145d59a6aa882b092a1a49daf04c6dbf53b367d35b8953b4c6daef04fedd96050ed95cc136e552da1ceaa06caa06b40dd0af792290a2de49ee90da173a09714f41e4d6af7b294c63905e1734caa66a1990dcf2ba21a15986752fb038268aed1d29b124e04255ed4fee85f8c115188f7d7da4b894c4f53cae4ebbd26cbf3377dafa25d86c6e2bdd8d9adfe8065f0a9442c8145b83532224b522cf5d3c31107bc925184c68fb159daa06d531d0e83e4bb77eb23c0579cb565bf7db03d913c63cb5590bab849209e7405a716d40d8358e99e91bf845896874cbb70bff190f32bd1caaed03a230b8dcba8dcec7f39614c0ab5b11e1ff1d70e2cff8b3e2989f98d8608e3c08acb98f27fb3590b60b930b1af49a53c62b65ed13be8509e52c8fca11252518dbe8a1c4ec4a3b4e33b53c5dcd85dcf3c4d0a4adbdce7d558f755cccca9b3b74d11c8a338c39a0c16599ae443a02661fb6a128fe89aba3d109f95561796d191f1e820afff658a000b1900c914c926a5aa9326d57c8d7df94cb72ef5b1cd19a05f49da4ae898522edc6d0ba6740ab526fc1e8ee298dddd48114d918d52c1b06a24eedd8ca5174fa598d21de647dfeb3573af4e2a86c9a206d74935ea836255ef6e4cbd6647c1986d1594b0ea00b2a7f1f3b7bd9b3ab92e6e9791dfbd234c4b31a4dd51bdb74d564cea2da7739019416cf25a677ed3c005701db800a6b5d6cdff9b5ed12689674aa1c1a73194deb2d85fc05cd50fd5205bb171f0a85c0b4c43b436283061fe4d6051dd27b3ed139c6615c02ae28275e69aa0e1b5cc2da8c744f12b34f817071a537d31ae872cd3b77aafe5ccdf00b51995c80b2c28a22e393ae84bf57cae478de7fe78aafd95a022caf795ec90b33dd1ab224a717ca6d24d0cc2c9fc8aa87dfc0a8f7b5026ee3a5ed8607278e3868d9b6eda07dec3f6a8ca773daff7fabf29770d610d3d22507aeefad63323ee0078e7c170951aae3de94d5058afe7423359c89f5836ddd0683745bd8d8e5cb7b046ade014f913c4e9ebfe1c7bce4674f0fb257fe2daeab7ba6098247eb015a0b22c92384328d2a1f50778feb88f1fa3fed60f21cf586bcf25bffb870a5292a8b286f8829e46ac793c56a8a898a64ac19fbb5752d2f5df8ed330e8d54aaad46b034d335ac4d111dd32dc3bfdb1d86ff38ce69ecdf32bd7b3e5711772f03ecb783ad9c7a5c32da9f2236daa30e47d8a364f5d2274ef9c15851fe1e9c4b7690469316e4c348c45d2abf22d44f0ee37e9b3bfc694932a5def450e00796df2bd101547e22c7f8f70192b94eb1e13055222e66c72dfd65848753df32551390bcfaf39732687ad00780f3c798e02023afceba776fd6255d5e7e2050f5584476e0124f05609771d4491ce9472a9dfcbbedcd3c9a212aca66fd34726ef451621819d7cb527dabf81c52417259ec9ff478e99c98e65801a84bd79e15b6564a0798593770675a595d77bb54cf5bec1746027b2bb0dfb029eb4eea4c1c1e4b9ad9f6210e35b1df3b5c5c79d75522a2d1b226cdc4cdddd314d4a3e287851e561dd8e75ead054100cda02ab716340b40b21469bb9c09bc1f723378c2f91ceb23f89a317b7f9eeec593bf9eb461ac8c0fbf3621193b2382545234aac3e09527a4f91ba84e41ceb4950c47c84f154a97188109b47a6bef945311d9dc5ffd71c33f8f3d6276d74a633d1259f30c1213a32e552b283fdc4902f0afb62c25ed04d5d105d329ba9fa66e50aebef68bdd953983bb54aed0278ba8c81cea2c2cd0580c7a8a83b5860d2bbf96d21d74cde3f73e205a65ed888e968e4e1d52039b7389cad095eb8573e04fe572add6f525dfd5859f4afaeeb34daf9238fafa374a52ac5ffb142f503de3cbf98eb200f0c62567b2743146439c2208b8ad16521939c5345b8944c39230f45f0cea13b1b97d2c216318310561daa76839137b6b37f272ea54cd0c4c7729dc9bc9ea7d2e74fbf974f41f9402b768ba9345284534e29408248a7f499017c50ae89ff39554d56d41b140fc11dc7e505ccee89d500bd36ce090cc89ae03d8864114dd9ad295b51f55d2c38375864a7109b1294981a908b2280a2acfd15e6a12a0fc7eb4789e977dce23cc636661314eacbe1e0a26a3812836025c23adaed11693f3dc9def0adcf235baa6d39e788fb2d0b72d60a4b452c446c405ca66a08585e7f75cb62fa4a4f62648fc8d9498a7a194aceb0d3837f0150b004b5d8d8b8fc8c0da428f56c52f4bc4a6e9126113c4b4a905284d95d8d4e960947c3bd681aca8a9b590acd0c8a3119b79337b5ef1d635ab0ffac9e691ce665be3b95b2a17872401bd474f45dc04c83d4f918849565cc75174264fafa37c6877dafb263802661ac447fd44b182a615c677ef144afbacfea7d30439f3391d62052a265043503a486f0a93063375e8a937cc08b6485eefc813b177e52c63d69e1bc2b85f613b9a4cb91d121a0012793374dc4ab3e179b9cd92fe553c33df00bc98b24c7299bade13c29af8af93082823ffbe1ff06b9725defaa51bfb6c2b0e67931b492bd7b441a8cd0a42412cb561f26c9e8724452c4c92cd9037997a9cac245a45436a43c47a48ffce21ca807674157336ae38834b8488415c9b02a3db290f4e04a15e94902cc28ca8fe5915e3aaf8d893191263fd253387c53003e3322250a8e48d9122b7a4b9e1f8c485132dfdd14f2247ef22eba0ccc54f932652dbb4d3965b8910ffc2c6b616a33136ce958dbe672180d973a3105e64015e3458c3effe124442f39e8b013c1c19a3675d26e3517d4a2fda4db200a6182da5864173209e5819720b213924450713363e3820e09001d82e597d6d179b22b5006f1008e9765c4cd2b9823a4216929ca8969847e140a50e78e32e49d60eecc006292fe156a3982709413ef3c38e916f521b14ba50715e059325a71122b66fda4a6c54b44431759b34004bcd104760f3747be6aa1e776a3e126a18199c46150e00d44d0717cfeddcccb345ad9b39697577ff11227089db9f517ce9f3c99918681b370603474870dc0b18dc90b1fcd8fc970a727015acc75cbc06f70b05cdcd71762c4e54d02e540ca99fb12137c6e8155e3bd54993ea221ef16f5a3f026b1290b11de7bf7fb243c1282836e5f002671276015292522d9f94df38a87d0d23df81da13f8a05ea79c0fb5effcd8c57e9d8d8f784b8b20d63adf0292c6a8827672cc8bfe0ab50d5edeababa45dc5a34de6a0250663c0ec4bcfb4387ba6591a431ea67222c84bdab148a3b5698f1caeeaa16bb81ba0ece9e786ead99439450ef00b7e9131eeb524183c0043e30c17363fafa822ae4c5447849371083774f311825a4cacfcf3c0ade5b6fd0847a4d31356b43b201e6d5cf442394730ce8ef7babc448a89ac345ada3639030ef881e5373ba0a5c3f3a2b5e8026d93e27c28f8f6a1df81726432104c3a71a5fc9c47691e867e6b48a94047b8573742f9a1a50b589d955f88cb4435c5c7607a7acea67a225aa12b329851b4140eeabc04642a0a2357e247c14a533a602e0698600de401dc63f80a9f768b01cd592192e0e930566d4eb67d889a1241d6353d304198a3ae12f31c8098bc80f8d385000dd1eea205998a5c7f637e3cdef5aa423f3ac57e3522230281d2948af566519f6ca7a50a39959335150c9216fb4a4286cf3014440ac1281f8761e299c4eb8c63d7ea08406857ee8c394cfa894640f093811c0be7d5c7ea12b042eaff1bc9a82531253eb09d00265e21034bf1cee3c64c6b2db98a80d78dd5021e96d138bcea0bdf7d15c47069f614247ba84641808ca4a2444dd49011244630797a6459128298e82e0c064be9326915e44cae319b380216dfe6d2dacc6e9e47367b74740a3798454682518faf64050b1ab63e1491b715bbc9963b4c795116d1348d9c0008aa59a1947cdc9a072b678fade3ff663e093ac707f2120a26932f2accaa1ec2764dbb1636dc87bc59c919f01a2bae4a221ac1ef6d6a0bdd009d392f383495aaa5d48620d2cb38248ca0c2cc422df635af3908224fb9f1878b0854c34e4b2b2786d24874e3953c7d2df1cd45f8111eb746871285b432b4aef3bd3984487bc110d7c8528ea84f7b124284c202ad17ba5ca8317dbeb821c55b0f8aa0d673b0db42b022a24ba5fb346fc5de49ad66e0e43d4b4b33bffb2a50d7e4f6254dd99f221ea9548658916dc5214b203f5a51d29e59759b34e24a5557548945942ee0e90371d3d7941be8715ad7de1c85648d2f70435573e6008e3a1ee05d2711b9229150200a3fd374b9ea3e2948f13e57c24ccea1b81ec4abc650aad1c92118923edddae77a327ba687f91fe03fd072de85e6b0d1c89cd3f794dce0f60d77adee284bd5719565d69500afc75a7938455e3121e1a60f1c6bdaca315e13cebd15aa6dad8868f56bee008b4be96a4d6b72659ad3d4ede242c3b1ab16efd8dd87a9aebd682bdc2de6e1d3e1297aa6e3c9e560961400c32fc8832fa1ebdcd5a17fa9f5cbf1b81d06143052f7f580aa6ce19ce38c23e78cb2058f80c9435935e834c8fafdb0a2cc847e18c0a298e715fbe4d15d2f0e301f9dc7add2dd8b9dab2ad1f2126bedd5da72301d9c7735bd9a87315655df2e83c592ee38e9b7c4c9447df32e39e0fcd417c93773caf01b771bdcf527c6834903360e71f60a7b53c8b660b8e71f6e724837950620ba1aaa9d5e5a05c72255c0fe32ef04a37abbd5dc43cb440fff253d62cc8765c065307a72078abcad8648be2432eeea3b82ee3f5a16a9910e6a4a7596dc9915b1318b50042bd5fae4527e9fecf19e837f9a3f0053eae611be02f04b843af99572c974685168d155f15b0e3ae55eb9fe9158b95ab714e0ea915bd2f3643189b510bb455cb72c816b9104b2839e4eebfd22967d9e192e424bf57446d219fd1057e9c3e8509aa6e438ce20d1ccc2b0a7a000ab147238767ca2fa20cee3c893987228ae6a76f4a082c471cd82c05552fc5af655ee9c4ee4b418ae8de2048a8a4e963defdcb1bca78bcc84163b1d0a702dd9634adf44d564df6153aff172f5b103c8e0035145c71be007ab61858ead72be458be238220563e672eb57fe7e5865958f56b8f7360a745807e551aa96511c319a71ce2ec559afba56f6eeae03a90b2625f6912614db9a234de0b01758181ed045dd2e2edc9c615c549e1eeafe4ba1b58dc41d6d85f88ad53a8041cd920a51426d1819b3ff6f7b179325a83cb089b03f3fef58c7a5d0dfb8d905475cf7caae640c9cf811dc704d1a357c3710375705f191dd652dd84cf01d1852576af21d8766e66fbdaf548d1612d18b84b23f738bdb6d2e775194a7d1cab13f81c4ffcee7bbaaaba5297caa7738a4f47ead369666c4e1ae3a71344e73cb72bc1238d28def03f4c1787247f5a0b62cfadf49f5ebc805ad25526ec46ee39b14c20f20fd43fc35613355a95227acf6522573657101c6123893c034df5ca09e7f5706abf2a8d07c3c9a07f4d52c00815e94f0b86839a04fb973bf63e27f891dbba28fa85940a118448dfb83a2328b448deb65e80c8c23e9159f352e528457bc311a48d8679958a22ed76e57add54a13311f6e6640e3628b8e655ad5f773e7990d100e62655ced290949cd5c8b9df2ca91fc024b43989a612677197aa109e0eb2e11c86b7e10d88206742c39ce5ad5b1f4687e493eef280b2fa6c790306407608db23843d89ecb67803d5f3f2f5ec7fb0c91ba8449b790309d6ec8c73295560d44cdc3bfa365e2eaa71be768ff997c34cbb967c55e26b158d8b85f28a19c7935e40bedb2de7e075e507d0c2d6436316c5b5721adb03a1c68bf218141c94453940c3bf167e22bdb47a0671595049806072b2daffc646301202fb6141fbc694d8c665214b4b564b05de72b929265fab2f51d7f434f08209ab920dba5faf51bd2a2c2b117c28a0aa40516ad6696db65bb5d46a4c5660885ed276ee79b54a067fa8b8d5981d1547144a79dc0ec29375a17563e9a6da8f3a98ab56aaf422c6fbf4757ba2c43ae5521270fb43d1d0e4c010e7ce0de6f1c15880ec527acc8b6b502bae83ffb8a9c6ad361e36606e1eabf8ef8a42e76a304d8c0305e9c6e83e51881f1a4c0135bee5b111a6e00007bc5e561c5fe8eb79d28e1478e9d48ea68c10d569e361e1242d6ab8878169a4636ea13b9ed40819c3628174eda31468dbd471c74552cdb66a2235bf5adbf44ff3e46b1b7c5b8d35ebb3426212519d8fe3564771b972fb1aec77b07765c6bd7d8e07da24293fa456a4e91c01907b72523572eea1c6eab7cf30c6a0b4b83e88073d99306ae05b32b747345c36532c7f5baa878a65ebb20aedbb8666007144263601cefceb17252ec9af8a3f8097cddfccd374c8c1d3c30da0ceaec22e9842d3a8fa3c3da28e8cc23cad28c3523b6f224b6dd1b020af213f8b9eef149ff90faa6d8662a79991bf1ccc88df2446fb35357ec83768fdca50263382b42f46ef612e64558c32a576256b9b1b4a356288ec4bf89ecc87b8c1c3dd26790fd6e92cce696c8010f589e650b91447518a59b95324569d2d0f55d096151d091b57d8bc11d5b7507e7032d93e59b88ce5547be379dd26769977deff0895c92fca2f7b2bf8b410032482ea90aed3c7f45059e7623e02f08a3282abe6b6779fd832d7d1d88ba6ad449a54cf162a538e66f456717ffd48bd6b466e5077f0a5ec1e496a5b24bb83e2c14a9204d250b4bb4363623f992a29ba15c7fb145c25f978c300d196e228c22431df80166923b8984fbe4d8a4e97f13e05b5493e42534ed2521c659e24fdac40606d2ca8139e384e800a251f0c677337331c3e667c2594c4322be10e5a29fbd847fa06d0fbcf203dc4327fb1874809bdbe3bd556cc610c3e8a07aa0ad67e332da610bf880ffe41bca914efd31bc2d8748f8d7241037562df237983813ab1f4fabe9b7a693d3d2184d1f92d941774239addfbc949094727c5750eef086793c2ffaa49e92d79208c0ea52bc70e9d93f447e50688f180fb28fb43f17933b9e3a07b28fca1545f75f592b0fc9430887a32958c91c4b8c741aab5bbc29758b073bfa5d6bc3ca240bc58ef91bc51604eacef49de5860a26ec33d92bfb23af629edc16736a55de97403383a5016cb2cc21d1f7ad156f98a715895d0fb5e415fe70f01ceb87ea83a5cbb47b598427c119ff7256e2c705fac35009fd414e6f3d3d9cc7c2e8bd495e8458d9f5669e028e1618dcecd8ec1b8eae7d75bab0473001f5223d0287ad44866135089353ef080fb28fb43a95e71f5e218cf9530c22a1e58da2f6a4dc69420d47a5de16b0cecbcdf52695e8f48205e6c6fc538a929cee7d3d9ccfc5c16292bf14bfbdaaea7bc5246ae24478468b7e60040492ae9c321e724fca7b4ea8a5c2c8d6e02bf3beb54dc21c010194c95a1da62a0c504e297f1898ff845b53c3d9fcd4ca73369a4ee890a1c1ff1a46329c5c4d2fb6063b1d3263dc7d2a688d7fc6e1a13a2478fca6c02801817126b9469e94e49bfd196343e8889828966a0863b422de36107bfbdaa7939821b5157e9696958e0e7b7766180a650ca6f69a951c455aaebca0b97cccd1e655b05a186bfa8bd3c5ab203f8719e2aac267ef1563945610a83302b4a4b4bf2711f282813900fc61647bfad1ac043e52c17acd2f2632163a34170dabed607383ceb022b788ad022ba645535ba689ca6ea11995b446944af896093ff2f37112797a192e6613c4074dde509d1a392888e7018bf9d53086d44bfa824fae158897ee80f647766389970aeead6db64900498d4c93ed674ca8dbf429acd7d9ab2e83462ab6f76447de1a2eafbf9c73a82471723500464ca9f9c7d10288f1403cda757228660a06b41e6a160b3a94904dd3cc31e06d609b1ce417b91f9048bcfc39b6b8a9b16ab2e268459630032f38b958498fb4e348d150ae15825b02dc677a4c5710e5ef1c6c92bca899748f889de6d957734897af16ee33f986d1e8fb8907b22ea635ca7fbaae171055a8d478aa1bfc6fb73a73a41f2256021a432850758c5729c02049ad73e28ad6565c893f35583911116a8c0d4d55c84188cbc913aaa67654d88cdc2451f47e08bc130c21cc0074822d75280baf7307a4adc161838b27f9b496820edb6f661629c1c01b1aa2ecb209b56df5469a2a656d5cb3ac858f176cae6652c818e57aa3bce95d43df4c0b14d6f29b9ae69e8bb94ea48935bc6ec63995a245342ea7ed7d5d7b2e2619db03d622f638c0ba960d6e0640620477931d8997e4d848f2484771dc89478b849e7c8d7b7eb0f47f08a07a6addb5079a15a6f0ab851f73e3d66d74590a34ad4960ff1250a0c5dc653142f6edb8d8354c095c3c9caa9192baeec9582b7dcccd84dfdca42520f528f8f4c3c469f4734e6595dd95580131ed82346b94ae1b6456da9bd2f8a130051bfdb6232c847c0016f0b0edd626b5589658ace0a10b023e514479d256c7307b73ee0750f23c8f24a5d45e31dee9242b15e211c693ed3e5deffc8219ab007dc062dc9fa2fcf193b326b884991e476f25ac292d02b1c936a5d0f029e283192d2feec251cdf427eae5495c0017ba1c6b53ecd730b7a48a74e3c1a8e5629ecff18fd79f355018530a8016a01c2fe95b0c1a2378a994b948a0ad2af31a169fa8f3d07105f17e009651f2e2efc0712dc1011fab5a756439836c55b5c3e752dad6375a45b7c89e5c15c748491a117dc54f2e38e474c1bf5fab93d5baac3607bc698e9253ece78d6062580437b56fdd6fc6cbf19e75ecf6651a7011a29544aa283257743f4f3aa10c0acb7155455a370439be3f4480d0521d152636c910e2beb9512266f67611266f408755b91cb1c2292fdd30937eebb6849fd20adb5ab19a56b64d123db0c204429059a898d7e607c18302e842093163524d1b86677ba256fa89feb0a6f5f6bee15d6389611d512337debf26460b7669372e2b7eaabb1d4220eb5f3e12c402836f36ed52f51737048c59a005717ba16caba573620d0732c5c68e437972ee2ed3e2fd142b171d81a2528c06c4cfc180990a0de30e15b4a903abc2353591d85c47e9a1db7d09593865e44d9b72dde8b1f4fd5922e0847cac3dd9d70f77ea1f3e4da8e69ad7f04140b4b6c84a85ac716a7e50959e04917f5fba6590e3dad8366cb40565193a0f2a545e02c2dc27eb51abb9e6212feb9cae31389e78009988d995a7dce6a440e5f314d84c41ced9463324463ffbe4d400a93984b7582a68f115b1cafb00324bbfc1cc4ae509c90ff1e6da10c4ec72b25cc2d9531f70936fdd7f641b8a7a667ca0b0129deab856d177edd3b478e907062c71c8497ae8897266d868c07e1a51102ddc4c18cf8b0dd55b72afab5ce1b27ba3b6667faba3cd392b2e337217fabef61386d6916fe89f93f647f0e05fd676822fa2b100dd4e1d7c29a3ca3a62bd784cd7591ec03c8cd9f7c71cf9349ca97cf2ea329891374c8f591ae26692564f403a50f20363cc17cccfce9e3d89196b4cd5fdc7b149da6c3977da8ca79cf01a67f8fa2e576792f1a2a6f67ed1c0ff7c5f8fe296c9bbe58d5d410b786d070bee67bbc562a4d0f089e54fb558af24f7837674028feef51f9e56b7780a104a37909a1710dc0f958dd820fddf50bc1d1a10c60ea3cdc95102b6c6f9b03cb0f90caaeb90ed27ec5ae1fc18db5bf6544432ccf581b8df35ff7508e262148bc3904b676a580989f56327f801f2d26d8acb5420d859df4e2d751f54f38aa8afe5b2c406430026962572fc37e7ffb0b43668b78fd581c1804d3f0d21080a2ee6fff88ab2f3a789f83f17d8255aac4deb56191ba9af475ebb37e8eaac675272a4a1e831d4c3e524fd41481b43087087e887d442655e5b13aba8c31b1800ff8b0f620db41bc37fa0fcd14989d985b768f5d280efeafa0adb9d3184790f98dacfa8e137b7f21f25494c825e05794eaeec4eb2fda0a43d6f15a6a51d4dd89d65fb05586a8c36da9a2acb313adbf5a9d25be4c463fe24005c2c3ab9aa9a4505b1562940ca740f485a4e54228781f69f659a6426c2924467fcb34b37d70598893c8e08b42f83adf5bdbcd5329e7c3b0662096b789ad12d67e68a60cfd418116b8476650a1d459c4f95de13e327b37adf067ea549bdff1dc8856d73315867764b04d223dccfb3c6c2349a77aad176b287f5c7de8b4a903fa60e3eedb64eb4b8cf1e7f61d30dbd0e7e4e1ee53ac00c27109fac9afd36b2901ac61c61a9870dd20d3bdc1a5de0670d86d3a4d0994f934fecba7d9c184444242c8997ebfb5bf3728525f4797b656bdfa42c3b4f64da95b2925b78fd29564e6e6d98bc142bcda6e9acdb42d87afc22eb2e625c30aada1163487ee3b698aec2986d1cc74c7aba6e3b9f5ffc05c1520be40f8855d77e1d889828b871861e360d2d7f5b11524830b85e99502c758195f19f42d74ed5ae6a5cc2585af3031a8bf35c9e6b8d136be42c5a036ac678a41e9bf35727b0a32a4858fa549c80bbb42c3e08030e9d239a29dc8b27a6019db32c64318eb6d50d319d9667f8a5bab3e679a9b9fcbe013c3ec867ae35d8c122663e4e87927127b189bb8a94cf5150fdac54d9fbac01f305ed7cc43bfa610fc6fed78d0c67f820a2e5ec4261607933e40896a2dd32868925503aa25c45af1c6507a66396de23460e78819a5c5a68acca196853205fba5c1e8d24ce832b851606fc510526e4c6ab109c6eddc1073ddf599427cd8b5b9459c996ff806de3fc6d6172460ee01b2c91856c5e076b7b00daa45db1b902587cf9330a4d3209171ad9c7727d8ef99694af61483916438c3b5261d0059ee9e44a0239d44d7809f126a9831fa3acabcc25dbd65987d4952c6c936eb1e453ea65b17fbc6785834ca459a502672877b7f90fa17ab9e151aab4e46a73b6d43937223accf32f5b586c18d666f19838aa4da0e9bb4df7d135866668f05228efa45605e0ce44efc39862c0bf958b1633687f75089b5508941bd10310db7c43bdf657968522eb9eca6e5f6fe0ee206c36e8f1c925e322ba5cb9bac74861391ab91d5e4df0f37b6213ae19d2a14af9f46b6fd3d24cd3e14535db35799bee0297d1259a9ddfc54f5e4799d64b4bc88079f4a594aadf74ad507374b32380dff106c8adeffa3e935ffe19ba567403ea3256662be2077071a13c77dd486a58ea11af6777e567cc1df2a2e60de05012e9a19f44cd0b76d06f3cf79fecd0d6b3207e2deb6c623e2adf154371f13fdc561590b08558832c95753ad9e59b9bc2711d8cc24f85cdf467656a8e82af3fbef323c4f959c67670f867d6eddd60190a5f7e5bb12314a2497fc5acecac8b7257eb7ecbeedfb67618385cda6a09fadfa8eb33dcf88bc724aa311cd79fbacafedc90a48186262f05504db556cfa726cde5c4ec5c02b8bf3068236e3266513d15a947678292fe715d74ee56c401b166d5536f5d7693221fd77b3bc7675c4437f187481fa8f07e782169d5881fef7da70b20a7790bcd9a09427623977625638a8de65f28676aa617b3c387f7a88238e41e17f379857f2c775aaf7b78523a5f75785be04d6a60fddf36e907f7934fe5fbcf23f7226a063ed144da1d18882b041fc052ec014ce650f2c2fad57f741a8d3d0082522bc8e7b7ef0c2a4112fa69308db53fe223c4325a32199dd3f563a59014c8fa23a6622aadba61485e8a3c58dba39d319a5e00e16be5efe1b1968252ba57f27ba219496fb6cda7966da88c31e0e645079f6c6029d74c51ed9a8c4c9dd6ec8ce39b77ab45b7f4439811d57ee4504788778cf1ebc38eec1ae9cd90669d15f5ff59d2b3fa9a9c4ad70421f950d2a5388095723737733146ec0c1afdc139ab36f8f3c9d09ca55bb95146524622bc2c840ce8d10037e093cd20e65dd6041a88eed4d49c7a505ff23d1596edfb50072f120d507e33f7a3632e45f2a6bdd1dac9a8ad43cdbf0c995c665a0e148dc8506327088a6ae7943862c337893e939296bac38c43836842277b11e8c11885c41c3035d4e8628c8d1d91b651af2865b29e4aabd0366064d2a86792a16b49a284d2a26823c86c30b3613c8391ae07d15d8f56f7eafcd430dd280b1c0a53eae51102d2b216c41c6191cce1229905e38c62fff714d841675fb1c1ad185b8696b5754c486cf1ee61b2b439593145e1ece03d10b6ae6d9229f66345eb6deb88b655a60dd1da8c69d3bf5a170c8813331614832649e65dc57b28f9d4a4cea3f1a2e09e468816b6abba66b842b2f69ca73d9b7e5d9986af12a5b5562f34f15f98ef5e2d706fbfbbe947eff53f87c1aa88f550b5ba94837ac487cc3229749535facf3a6e0529a2f2f7dcabdd0f7d7d68fd86c07993ffc5638fd8bbb396c61ee6f01cf5da24dc8975b70aced81da6e02305c6201b2c570c54a1206553c7fdb2c209b56c87ded65f53929e38ad4a1b8a8a46e0c2afcf7e9932c6300f453b82f58c53d50d87d9c5c7dddcb98251282f0dc08b27880d886e6dfbd26d60295a05e623c06057247d9c7c2050eff60416db8cd599e65fd2ed1312904a2fb22d493350ac68b4bd8fb3432276b58499217be25f99c50f5fdf0014d87236caa4b2f10794960dfbe4f7875b49b96dbd47b3d8eeddd603a9012c6dc325c2b32497346383d46fbab0db3be79084664ec8c5fd9a96d90d4a3b544f8c239415e737380796e561ede23ebd0b3ecbe4f83d23025e9255ad80ed905d3bdc0748e57e6228ae822c9afa7d280b6688474c36f4d00be98f7bdb6104c8e60309d9863ebe521a6469a4f4d305d938ad71b9995d55c4344ab047ae827c156209c59a5034d38b21d9e4879183f4703cb71aaced55f0ea86852c569589a983e76de5c05ae071411fc581b8151810020ea80cb4f9c2f30ddfb9269998391fb8f9029b06c2bdc803615dfdf24217b6f42f69652ca9452ec0b890b4c0c56ba4b2155e9d6eea4905255e27594424a25f560199963585bc14fe4d4920dd90df4259b9ed1c8ccb29b274a2dc678038d3c79218aad24bd11f4a352ce39b108b3ccb8ab60543033345e171667dc55302a9819ca1c7d68bace677c8697969b17a234d660da88fe028dae45ae1f656e23628c6d448c31d296e8b2f1bc9012060c09e3459cd327f7c1c03873df75e4437f524bb0458386d0128da804a1873092883e09f483417d604b4648bb0b77c109e1c29ba33d3bd07713d2ee8213220726443bed59576c45403f1a441046d6ccdb82fa32f0718706517b3da9a51687918484ff388987cedcc21798174f2db51713fda341a34a7b1f8ca4870e6910b5277f8b824af05a120d25e834966860814e638b6eb948a23145e9a1d33882adb8037dca0823a93d2bedd928b5b75d596a0f4b7b353c741859606cd15e0d3af0a5c22c156e0123890651aa49522a2825f430fa0c09a5aca490dacbb81d164c910a82addda972e2be541413f7a5801e3a562312e8478348a9535252477f80dd894feaee6cd2da0c893f1cd65e8c5f1701fd2e25a5f632c95246b902201391d1cc7f97522492c1d20aa2d8f9aec8348ce20f527b5f049af98f0691ece20f6c01c12cd0e18a7627337d896a30f4d16526c743fff44be9bad2de16b1e0e7a1634f5ef840bfb0b4b7452a107a488388c9c36b09fb79c84b54aca007ff61400f4f3e34d822163cf90f83022fa59da1a1ba13c594ba13c55177fb3488681cd190d25ecd43a76184e33f1a531efe4783cac39d2128e052e7b07503681b827be26c85215b9aaf868f14e8f59ec1dfb5b97ca1b3842e6bdc8de7450a19267ac59ec123fa6547cf47d12746ee88be0cf1c8fc74c7bec382291a89243320f732b4361c59ca4021238484e8b33bfad95f82da23625b2f4370c5fec2c44b9417277eb02bf60f7bf94126c3c3c3870ea3b1600b4616aef0d981ce575dc80bfba4dd404f534a79f229fdc45836ae7772e8d87a2687aead27bd75396402b1f48a1d2ec12954668af684a09019a2d93c992a84578c1ad42636e1e570e92f5e1b1a434d5885b3ca30d15d2a4acc07ab4c50772c13f43ce7758492118a3e7c297d900c13b14e30d0ebe8bfe873da361e663efaf480b2cb3c69ef7b9142e6e74507db824bf045a6c9b30cd0f391ebe8937102c3b02b667f9142420ac3103d0097602bfaecaa03db8abd8a20d8dd21f3d0b3ebe833de86725e11339d36146f28c8eddaf0d27714f465e8886f8f3e3e5b7c198a3e6bd31e87e82723f4dd3242b1c64b1239f8f9f95982620bb4b3d05930921cbbbbbb7178e8a851edf08eacbbab87ec7bc48d822cc6a2b2e84b7035ae4d03e8161d09fda7adb6929399428790ad0128f40fdba21858f918638cd1972642c0e83fcc8901e8164141e83fec8b3260f2d0b16e8c2540f41d9390016b1013f90830d9756d3c2fa042b4873991ee80a8827ebb84c49f08dc2524ed61ee268facddc18f325d11e6b7480923f4125f92fa4c8eb9d72f7aa8af7f497739997fa7d3d2e599a39cb53b2eee5a723992eefaba5cc992f6ae2597a33cbbea1254458204b67827fafc40d21ecadb952c696f1fc5e5a0d7a5f9a98528f5c3e5323d608e72146744663ffa7e63573b916d347f50d2831f49cb205eacee5a47778dd35d7b0c0eb49d7ddafbf60849bb926626dfbe80f67a8984b4b7fa76960e255b7c23692aa80f1faec811e9aedb757668cf1f7b24be3dc0e2bff88be574077e7da9c316925db5b320b74bdfac47319522bb816ec718b6bbbb2d97837a051cfb2074083dc69ce99fdc5fe8132a59b8bc32c2e616835a644c613ed50ccdc7adaa66aa2f33333333b30fde493a8957b2f5807d735f1198eda09b2add6ebb8ddbc1c89099bdd99999378e44cd7d3cbedd442184ce70b77b45551f23c7b831cab5f954df3054c3e2c6085732332f33f3aef73233af942c659432420eeb0e639392c94dcee3b1e81f005efc5bc1f857df857f319e39a6509be6e2170c86bd50ce79fcf4cca5f27b731fe627df7a4cd7695a5315436d5a85e9aee7338f1b4f264d7eaa5f8ce7f1d2759a023cb0dd08b9863da821b8a7637cc283070f19f6b5f2d19726a359f7ee96caef1a0d595fc00a69cf875de78d3cba5b9cee7659edadafeb68cf7f9dc296ef6a7d5500b457dce03fdfd642b6341f1f3d7bb6b1253a6cf113e8514aa11f3fa9827efc2463eea0f6bee8fc84a170100775c7de0b51973f811cd4defe74b90411bc753831b94acfbe321f5b40a5f7e9b708ca0b8ab4c7cf4ea4bd8b93e1013ee698f773c6cb8e55f8d90dd489ee9885baeb983ef39467266287e1295188dafb78484a7bab67e7284ef46750c378bbab392e44edda5c3c278ea174c7bfdbc5f193ee9887da63e729daf39f51380aff3ce49e2841036e01f51fd8e2284b608b9fec8a9d370b940efcc7519ebd5740e76fd11550fee3279cf1c908e99c7535ac3582383e7cd8a1bdafc3e1d1d5746b77bcbd4ffafadc7e488f1c8dfbd27407a5841e69fc6968e051e65cd7bbf656b8487ebdb72a899867d8a5237adcddd91febbf23daf41a65d679e859e9753a5b2e8a0837b6b713422bd9d2ecba5475075da5a3d3d1d5a866bab53bbb1df4a306b292e3976807426f126a2f08f620946031ae847ec4627c1b5c6046ddc1294d24e586d33997faac45a267d3694d12638c5c92c935c7f8dd80e2a17ffc3dc543a129f0e889a49c601e7b8e3737aed3ed83dd7e8b5200069f953b2e2d15cf0ea53c7bc492f3393c7363a0ed37ea9cdd5fcf6ca7de75cab443270fa53cf558597c335dfec8c137d3f7757a4e9e1b4e9d3929d41d1b15d14f0ac92196526e77ed4c9d52cfba727733bbac2cbe89cd39f8a62995e1b8cf35740a27bffa25e281d243273d1f3bdf2de6e09b9e1eeb0def2a69fda217fbb9bd65e79d6750a3f58b2f87baeba49472480e5529d41decbace85da6b28dae3a12c6e3ef4fc119aef7c86db0845e9ce891aa7dcc7e3a9778c5d51afd8eaa903e0556b438554aaaef3d56ad5e1c0d175ae0357d506ef680d35b84d0d3fa0d46da8a1a686531cd08d4bb1381b2ee6b748892b32a8edd603e535ded51aac86c92aa09f4968b5720601fdb0efdce4385a80600d1cc7c92ac3721bbc06cf3e25f2e51443b589e86712dac170541c6e53bf9eb771de786c3c83da456fa0c11163f49ef7286fc8daf3ac44e2701cae036d2a0dc7516df8ac3c365a8066784dfd60be73564dc2cf6e4395e921f31a3cf31abc7f403b8fdd75ae03bb7aa2513fd3c97be3b9f1cd092841362a8e1a87ce36be9cdd405b805a9cb43c69016a0182595a9cb40f36aec15183f7a83ec3331cb55b7af474f06fa7e4e0df1e6d1178ac94a522c73f1d3e871c1cfc6b3d7f1e73f16beac75fe3d706247bc6b61e315e83c359dd0e9db487c3db4f1b4fb38b1ae32f6a7418150757d51c8f5179b80f5507ffa1e610abc4a468c5f4c48e006ccb9d43fdc175a83e388f1ac373aaca71a8303cd6171e535db8e71d9fac7c3720379cbdc7d7b17fc67bd5ddcdc999996e8e4a34492c9ef176ee87e9332bd3c6c3dc8dbaba2263c9a315cda3521cc3da5c59e21cf913c7d0577ee969f02cbbe12cce991c079ffcf7c3a5b3eb740eceb9e19225036486fbba7f42272f5b80288bc5dd902c7696ef36d312a5bd1d1c7a8b13edf138f41616aca7c3a1b728c15e8b436f21c17a322d23f0e150864b1597afffc5775f7c77c7d70f63856fa0c3fce06ef80ddf6d86eb41fa9461f9caa34b26515e47003fda99c539ec928b2cbf1e7ce51f74f2f1c7b8e48c489fc9c137d1a59301ece0485fdd7002f4c029e9bfe13fe40d1c3c6e40b46f5f02709f8e5f79eb07f7c55f49c7c1a3c7e82e369ec8e59055eecf6755fe39a7ac73b27e643fc3e5e09b15c731896fa212df40e7b0b036d07df8b0f8e686eb409dee51a3f3503de7a939f80e5507d75179784bcd71998a83c7c4d4d5e958857322161a5c06f7754ce29c98856fa05be19cb88566050bbb4372606d943847fa60e11cc9e49d062c0f3d6ec139b209dfc42c9c237f04b0c543971cd81d72046be3c33912886fa0eb386779d83b02b0b556ab981e80efd8f100e0f82683b581de5af95c750cd7c3e472f04dfbca75ba39191d7ec3a34b279c13a70c40063b389209b36cc2392d4023802e8178873f9300b8cecf6f2e80260f3d07e74cbf21bf71fcd3f1b175a8aa1c78d496edd873ea693b761c2adc8edd088bc36188735cece0be4605e0da1bf667dfb8af9fa7e3702daf6e77319e83737a3a0ed137ec4597acc9ebba1c73e9d9bcae1963ac49909c1c6e3f9c4e3fa29f78a04b4511462f81440f423e12c915d98d9d74d7279f279f6e04154618bdd4f6070d5fa4bbc63c3332fde45aec0ecddb33edda7e4c3ff9c749529f99b61fa69f4cd9a995ae98aa745277b005f4eb25252ced2d71cefe8fe8adc5ee4892fac632dd08731ff79269fb21fa0c720203fccc3113cd7123eaebf9205aa4bde9ddb94749a4bb1957c908fa6491452e66a13d04f7707797d06bd88cd7fcf63a0c4cec5667e9553b46a90a96e0db3f1a1ebacde620d99beec2b77f370f7da5f64bdf5b742b739a99afb39c3a4bc6359593c9cab7cf5e7d7de5dbafc6f2ad115be92cf247fa481fc98408f4bb808ca4cfb75f417d057dfb0524bdbfdd076c5ddca79ad80e8ccfebf425f45b6388d8337b3e21db9ae9597b3f81f69123ddcde93b5dab524ad98325731cc50a2a69ba6b24ca0e91b043ae484572a4bb8944baac48ba9b7ed5223dbfd949eb5396695a912348dadbdf3826f140d27154634433a77f304bf41d6c1581abe918f5eec3f9afe328ec4477d38b401c9c13f7b1585de74e957e7a3b817eaa9faa19a7694fe38d775b2847618f32af29af753789a6489aa72bb0a58f7261643d36c68e1d320d5e3d5b1b280d315e9963780dd1716c57fd53d17f3982abe82fbe5b0f780479896fa2c378e53e1575eea3321c106c492198e8bcc439311e39ee53552934c3fd9ae13cc3e70c9799318397766f66f80514e36ba159cf9dbdabe16d5d407015d95f361eaf130c5486cf8091214386c3c858da1dfbd13988caf01929193ec3bf0b88860d97aeaa9fcad9b39818671b598b0d1b36fcc60b1b364e366eb8c4c4d018ee9be1b286b7c8909142c9f430c36b788d199894f6388f8e19b5573d3a36c5058d19329ca8bbe8372a94d25d741b151a75176d547e1975468d2eb556e760d4ea43cf57df8d87631a2c1d03f1d993a49e3954ca751ac63de682d21e0d8f7e05b537c3a35f4cb427c3a3672e367cb71e366a7856c3db5134d06c95abc1c9f460c3ab571bdc8b86d56032270dafe1996ae3a95143db7ce8f919329c999341532b0dde5cf524a9afd5dd511b10e834d048df3620315e390cf073dcc72ee33a9079647c8d1e323823d2536e44c695f0c7b84ed7a8fb198cb6ec5c8543154ed15d7c51194be52cbc45fbd0a8cda47f64d46ec24154c663b4547997e830eac70fc337293cf50f1e5d406b133da65e49ac4d7478062ac341a4eea2c7a0d25df4cc45a31b5f401093e13eac0352c5e0e0d1c216adbb9367fec1a30b05ec4fe206043a035d4eae27bb637b80aec200bfca75a0aaeec3f817f57317f5d360eaa77aa9415c2ef5eb961a447c5a83e8ff2ea08f9eaa4ad8e4d351dc876ddc47b56e6beccec4612ad5ca89cd1822f6348451946d573682424cc5391a0de847658d7169a00978e959724d779c9a471e83d13ee558dd8d0709ca3f1c338982b20f93dda6779dd8c4362ddb6a938871dc598c312e9c291e4aba63ccbb6258479f28d7e986289467b389dca6a32684ce4cdad3aec8db278e7da8877a08ae4e9ef22c5591e88066aeb991ccfbe4df2e29e98efd34f4f1d033a4e2e2fce2ec9cc45658e90a43c13886d25d507b5af7c6b3411490cc99090eea8fa178de6feca5a2dc65bbbce572acfbfaf98bfb8e3876b53631c9db8f8be39fee7c9874473995cabdeb582c25ed510006497b29675fb2dde223b8624ff96e3ca9ab09ea1795f9d18e39061d7a73323ffa53fe0df1d1f77b5e6e3c7c9403faf15ef16126edb17393f632d79c81d8c97f0ce5850c692f955d3df0c6836558e657c56493c77cc35a0261327212eb06fa26fa4ceac0d921e09b20ed49ed080e8ff6bab53bd2e4ec4030d273956737355003bd5f550762df91c58a008d977bbbaa3b9ec1407ccc9de3ff7a624d7c55cf609d65ab61dd7d31623e1b68ce0fbb26e69777c5fcaadd846f1ac3b80e01df3417659889177d98b24328e887edced26f8d14a4e1888c999959b294bd35cca6642921171b5298a18f1b7bec58ddf0070c9dd923735d044c09bbdaff52bf4515bbdabfb80f9b3ba0307ebf25f0103e8c6ec201748bca80e52ff79726c9dcddddddeef3da1dba93be03136874e84184b4b7444cc0f2d287c0160d647bcb377753a1df26119135e849a1d432530fffcb296ced8ec67d58c67d34760b73291bf3df5c7e54db4c5262f425852be9df4ba01f355d30dd4917a2043a840bd249a02d2f236450db76c822d85dbab20914b2942c36126823d11ed1142f3df6a7cb65c9cc2b99a3cca09432c628f9591c5c01ffd1dc68ba2e533c395cc5ed4efa894342807d9d3e6d1e6374194d3146e7c83531b923a617715d73fa5504e645cccb8b98ae791198c98bd038155c71a73561d764f5c02294171532ffe830b286c8308ceeaeef73cd47e949380cc478ccbf75c96b9a2e7d9a4c26d334714930bf38ef4e5241a34fff58917be6964b72f9c726973c97b34b13c75c128c6b02fae5aef56abd3b18eca3b16244318b6c69be6d231a44c802daeb791953be017808808734948685383cf4e53efaf178184f29475df3d3e74928a5d42dd0f394b3c0c97df3ad5ffcd63588f2263047ed7216d8b6fb342ec9724d48ee08e945cc29a5cfcb8b90d38b909e79111747e12a3ae645649ccac461dc856193935ce4a2cbd8d3720a45cf16bb8840bf751f3abe437bd021c6c5e8ed52b029cffed1168f5db1efcc64e59962a0d059ce103af43d8223c83a08343acde0357f5e57162f87575f575f17b770f29452cebf2a4b72ee71071f7419f7e27677777777b70ad063dc6cc6685a6d0ec61f8edf9a4dc6efe59de698ef7a29ff60fcbe7841c37a598e36633d94afcb6c0ee528c45f9c11cd2f00fc0ddf4e311adbb5a36c7c7b66a343abe16bbcd81d33d666866fda615e6a0fa9e6b0f6685cfb073dd3b6fa1adc78807ed2c0ab98db0e73b8fde08c44139c1242e9d8c623e5e4201769523c99c8b6864eb971e1eece5d4e721ff6a97e9d8b90653c99cae3f04b0513501e734d8b928b3e3720d3650ece397974250d399a18e3c9cc28094d3386644efe70392a6a2ccec11cf2f8eb939f8ecb772f2edb80643fb91c5b0f93cfe99b033ab92acfe4a8cfa69d3ccb5cd6e8316aca5705c35f60cbe29c0bca199f315c623e51a8188c9a1b4a439d50280ee5a84d3bcd702c65b81e58621e89ccb88b2f7c71f1c30f7609647250ca78845b8f8972d3068488cfe03e958c249fe13eec73c8f04f0737e35b0f7623d365fcda8068cf73d32627833b796a26b20c8410c3aeeb42cdadc77493bbca690b8c5f95c537d26365d7813115c6a829095baee23eacc561701ffd7ec17d2a1d0e665d38caa17cfaeea665dc75692d73a397a3fc53d2580f284e93d15cb571449cc44e4e2186f22ff6c0dcc889db9c3720da63ce3ef044b9140adbe0665ae5bf2094ff50ab2b77db330e3a63ec13fb823e3113d783a469190c030bd9d6409887f174e2647e9c5c7a8f13d7f358fde2c78f39d4e99ec794f443d7813c70bd8d7ac6d9bccd9a39a093269ad79cf28a17fbe408f91be2796de2152f6e7d72230142c82c70e219ebd6c2c87d47601ec3b893cbbaadc9d6b8efc84b8f1b0f98679ef50624fa6e3f26ccb87559bfeed74f0b5b266f8871d742c9450a53c05d2f6cb7f62ed6bbcb7337c9fae6d667b60b355eeec8cb49f6dd80ec10dc7335dc010c0c0c0da6b560bad5d8c57d1885d978aeab5eaea3bd7d4c076d6fb7130f1dddf1c293b377acf6a64b29fdbaaeabcacb3923996b2ee3835f3abfe46408d0f397f7fc6544e33aef8e9b50124d7e399fb0bf2a0f7d3d17ac1feb4fdc77447b2c064f4e7e55291df34b5e13ab0c05df5c7e9297639cd6dd0c37e3974be9d952e89315d7b5d6c1c4adc7ee2e8e39aeeb8e610deb825817b2a5f96eec5a51b272e58238485159aef9494d491d3d4119832d17eebb0355402eaa4c7417be3b596402fd6850a134886010292ab122e07217dc06da2fe7faa5525184904140bbca55dc065c78fbeeb818e2824b4581591a66f1694fc50eb3b4f7e2e2d03da5e4225348a92add25fdb4c74e83284583a85b34887a053d955aa25ce94f10f5490505c1968c101742b8e05241b0674709b63675e5a5a6020fd89c206b855f6fc07a2f7c9d019b23846fda15b01e0c5f4fc02259f1bb4b5800dff432606d9aae107e9d67737474d89c1df8a6bdb5393ef8a63d0005c8e103ebd77fbd165fdfb19e8bef0d5dcd77e363bcf0a0ed9f4b0eabae97e5e8584ff375189b83135381e8551389319cf322ed55eee32ff2cdbc74986d2181ab760cd0c7fc832fa5f3e6602e3dae57c3a563bbad1897b516e9ae590a5afddba41ed5751a09cdc7cf79967535fe35a34b1bd323176dc4e9fb36bc65da98a9e9d7f663c2559d6ec3864b1b97bc84e8ae1ff14d1b1b55c375da460d3eebcaaf1aff46ddaf816d978cf2aa107b6931c1d0cd643299dc466de2076727c661b61f2618979376dab0d4e9743ac54bfa69fb113dbad878e67cd97ce8f911b919a952fd88df440cc74442d81d97070102a15fcaeeb8bc9d89ae996d3c9189606b77ba32a141ecbc460d22099fe16db812ec6f00c115d0b767b5091abca3c1676de247b513e3372a06b0b7c141b004dbe2172c0bc1176c8b73b042b0c54a3007db622dac126c75935e69e1eb26366aaf60bb761a6a37d1a4bda1b487797b07752bc69b86cfd0f00ffe8c6f7c19dd6486ef077f86c754c62a4b29837cf776cee22e73a1369e8962d911a216354d281a9f5f83a606dc782eaeee57a28fa3f0ed33ead751be5d46fd66ead723f87699181810ed518086489118b737e9a7183f6d313128401383a361300451c178e142c810062c800ad249e7c5a585a676f051001fa84831aa355d77ed2c2b1e0adfce42d0f808cc846f3f55d1f1b11270b8083aec0e0e82f3e01c96c237ed548cf0ed385246871532510bfdd650c91a51645f862b8dc3fed27c100cf46ba1f62e8750c02129edad771bf594264ae29ff63e5f6aef639fa7f2edcca4bd24b682859b6ceb47d8e84d5b87187ae8f563a3b7d2a37fd786c9337739ac47d8e8b375acbbde24e7249f9662f4ed0bc8965983d1613d42c3351196af8fbe89daa85b4a7ba155332df7d975ec4ab6ed7537f769df9ec420f6f07a23307ed2fb88b6717723dce852eec29d2bc3037f8d0eb8ddf6ee569aeee4f6765cef0e6641d7b9af206401c56f51164cbc8edf222b4b9fb5c6557e7cf8fdd99ca84897662b903131c277a24bf7d138b4c71aa471686f2d286cfd148ee06a9168924ac997ba296461f9c0d527fdc0d5fe51d07fd823b5fbf8f9761fda8bdf4740df8df33b4350706b1042395149f80cdf4b547e96f5949d288edadb22259fdfdf191a6a4f06fad050378c22cb6ea01896a5da05740ab39278c4632b8fac212f8c6bc3ad7d3b54a269b4c8b34a93d7941162cdd86226d4d7f3dca85d2bbf2e95325316f4970a25984085124880bf5428310536475411596b81b2af769918a90a159389c2682c1d35271310bb36d2a4e34ab635598c7ecd0823fc758cbb62fcfadcd5baf4862da5e4608c305e41f47337cf397dc619218c10eebc164e6e5d5e975c08a7dc7558674378c9d074d7edb09579c38c73d8a62dd0e841ba5bd6472fc2e6ce8912c208619c52ce29a544a2b0e717a317e1d53997c7eb82179c10c229328b1e84107e47b48f1ee79cf39a978c1e43e90e23cb295931ca18655ca29925969288c0162b8816625c9185c3d281d3852974ba2025898d4811204a004407812d1347c4081a44ba63161124304135a18e0fa21d7c3ce1ca13b0c80ec820916893a4b47490214742862c216df1a8892061063126ebf820dac187164270b5314e2c8810218104aa8819bdcfd15581e88e8b10012288109d2844458020d21de4928aaec0c27f7bb48435f5c117ae2d90a6c0d2329f405484267d88929011830c39123244670b9f1ac44022862491d10c32841b421406a35e6d0c025b3a473050fa683d9323b8da9712b682e460e9940109c220425433344d187d4bb49581c57a12e30e57f4c08b0c6694d825d432a18ecbe4814d0a2c80c212260bb6744cd84c91ea6ac59d8610c2092f245eb24841162db8585de39b817c7c7c8eb0e20583cec26129584ba48535fa198950419325a4d0c2480b2b5a4d9881167ea0129eaf204443575a1ce3f649af36088b42855443bdd2b90251aff6bfae0ae9aea5044a4b5720e267dc0166cefc0b210b5cedac4384b08830ccdb1bbf4447b8f2f1b7e80a2efcb744291ebca884bae0630513c430052a3bde7f34044a9012855191157a708422e090038b455aa445aab9a205a95fc77a194acb7604ac03318ca0d4041a2184f00a1dbf91c6142a38c1083bb08172608918d4221cc18a294df0a04b64c145cc8e2270600a76042ac609385418258231c1910992d0811644b002021d3b6ab052a5000c1b634430a25311b5ec8bd1176c86d0822190214b01086218e530da418e4a093250205d188a0116249f273ce10621dda251085128c1a19c00c5432e18019524e0c00b52c01c104208e10d14fa90cc317a8adc977143ba630fd21d6326eea318b713040e09c24f0e41008215425081ca937c7c7c8c803285960583101328f0200c467881040000820fbe3d621aedf69976a7e970b0babb7bc9c7c7c703b1bb7708b24ed041135ca044132e5cf140b3babbbb83c4f676e0313cb4e2a1634b7897874e61aac8e221141e1249217ae834ed75354020c1e3c0c1a0d8203379910a1b1401e3f14a180106a7bde8588f07b2e042134135c8220c2eb889310c384ba400b52e8aaad081b17c7c7c3a0065c905bff40ce8e7cffe03304821dac11381a8888900688df41903ac17633b76b846413e9887bf4390ab7aaf98e17ff4b9efc85241e3e89020422011df1eb12abef341169e8a1fd0e07b088fc19e0871ca107977bbaf296377ec8edd32767b9b9b646c4cc69e8f7d4df6281365227314a9a5e929d0e93ea0d191b5f2db9d7c018d1eb3ce414c7cf46c6e3ccbe5a0d8624cd02efac7fa701e932ea0df1af9681f82606ec25ca731e938bf2c8cf38ddedde2f0610f570a74592806215b9a4f0225e9d11ff4c9b02a454095fcb779f469ef72e991497b2d2e3dfeb43856fb33de30d7e91ab78a711af491d8e6b465337193d3811bc699362028c75adc949ad395f4d69ff2594da914c5360cc3b0944f0efb817acae4d9a6b54c6fc13e2c3efdb09f1cb699b61e97cfcdb50dc35c6bd2dec6834d6ce3d92276aa2617cf1ce5d8e6da0fe7d08dd380a663aed3da073807e5f3744a6d546bf213a5e44ab94e9feab6f7c2511ebbe5c251a8cd3f94a7b81e18757293b7b8b86c8e71df8fcd31c79c3720db74ed876bf14f6bf22d7e99b61ed331ce08e629c7361717d3a6daaeadc706c3e7a632b9b8565fea346d304c70e369e172506d8acfb02a4f959f52ff53cac4611ffbbc8bd3aafdbca89abba82f0e535bfcba745ab6cf4b4739b6f974f1e913634a29b7396a73978ceb0185b90bf7f16f322e7ef281a7eb29caaf16ed29ca53fec56ff1de7a503782e2a8cf7f4aaec7fce2b4971a7b854a51eeb340cf639eb5b4b4eccf77a9fc1ba5f2a963d4457ea6699a928b3ae69f92eb5b1cc34e59fe833e3e2f27c61dd1de08758d7acabf23dab76c1c10cda9eb744bfdf86993ff4e593582f293cf16dfeaa7e43747d5afc7e7514eb1fa69ef63dfc55b5a6a8f961f2d2e2d3e7d7a0b877587d1cd759aa638545df25b3da2bdc6691fc856fb4056f7596bf2270e9bbcd207255f34493a4a3a4200dd222c4c7eb7f82df2c2cf67a9ad3dbfb025c4f4e5240e92a3ed2dc5b63b3ea27a1e897dc4648f1c41169ffe591b761c448e916a5bc718638cb1bb61470ca354a5d2ba8b44147a8f1fd8c1ec0661777707f923ac6f181ff00455aa0bc68fdd41e660e2e6bb71310bcd228f8f351f3f9a192dc6184d31c6e833c62c0ad3b3d581622ee3f683865775377db539e79c2847b567f2e91426bb816addcd6972ac9e5c4a082184ac87ce30dd4d0ab02618e87784f5987f41fe927e5d521a61c7341853d56885e90ec21a533e5317b73f24e6d96e3f9c20c3cf8877275d09bf115577d267ba8bcbb0a344c17427dde498ebc06bfaa92a4971310b16bd5b3ee06a7e2b85878e9f3534188afb607ebae326dd4df7318d3e1c1c56d7b9ab54d8bc3823763f32b5f644c6447326999f7c693ed6eaee6475774eb57d765841417e9d63d48eb03e9a6aa8163e4b4bbf455ca8f2df2249ed547747abbc9355a1871ca5bb1883dae30df408ebd763ac4d9c3ceb248ac5c40cdb7862c4e21468dc456a290ce1a4f6302bacc46a6f17b684e09d85ab6b6ede5d6ca627c7ba8b11a6bb250257d0672db280ee361efa2337c40aca50baa582ab2747d03f9ea2928233050b0a66e2a1671c050a5b43bc6399540f9da10f81ad85dc878383711f8b75715fd77915da1eb5ee966598fbe83031c675087d79e96a9a946537d0ee76b3200f594758cfde6c8422945e7a11487ff2e83e31ee8e934b8fecb14bc7580bbebb63d7e6dbfe63a417fd4cc47a26f0d91d50890d9600ca6fdb8f25daa22ee27fa1f29e8273ba4ad6538573506580abf22558025b2aef7e92fdb75976a569b0a76824bebd4530451b21e50c4659a66871c43958f8f61fa22642ca188cbc30e5af1c4dc109d011df0ed31cf8f617327c3b56db5d5aaac03954f827ec0e964223710e57e19b2c9aca0f013c64a4f6bef81ff48f91802cd1438e91ba83eed24297e819a9c5751a426fa1d9a96e8ef5e69b4787cb3793b9203339392d5cc90216aea064852a6461850a585cf153904214a69cb0caee90de534e08e5e6bd01d97cf3f5b8fdd836dfd7fcb4691bb6b9dc7e6c9c2637fe2f3c6fc10adf3ec920062c5dd0c2b767e1db4fb00adf6e25080ca83e725ca5bb7625d8430e89cb7ce399f084049be54ad4e5ffd75c1f7afe02aa57a2fae93d21350dd13d2e60cd15d9d6b052129ca8aec02850a87168cff60c55c8c2ca3a14ea2e8a5b591ba1f696fbf8a1509b817e900a58ac4d3b5f21b4d00921869c0c0ffccb71d2f37719e807a3c028df5fa09fea7bc9da3494ef28ab8235899b52987875205b9a2a80200944d0c2ceb600e09f3f2bc70d8d0f0307aed8af0a6d5c5ca74df5eb79939665d0e79c734e2927849a63365cb39149e91042083597366c481b6a70b84e673515870e1e46bf990d2a48bb1d779ab39ebca69e2e79418735f5633df40cbaac9867529315fbdd605c7a19f4279f9784326e816f2edf7771f1abc625b8f1d86058a7cb2a671dd29de61906793b7d004208f44cf49963957ff806fa694877fc01be818ef5bc062b03b16eeabe1337dcc77fe3ec524a29e5119cbf719667acca51a640f9e7c609c79ea9ac0d3b637153f965ed4142690e8e02382f5937dd2c168be5bdf1b024ce0e0d647e489f3e8bfc6e3c60cfce58501d3870380ecf669558c472c266957eaaf10adf4cc7b02df00d0e3f71587738707032d37908c4b2aa551b75a6faa99ae212d7b805be7171592f7fb9352eb563355ba13e7647dc7c87218f39ac1fc5b213125cc59333ccc30b7aacdbc57d9a9278a4fbd40e3caad0940711ffc349f1684f6220fe8ccf30e5bcf548a55cab6c85ee0e24606bb178e24a0f8060042da8d060877d093bfb28218267fe699f3e74774178b94e5f2c1fbabbfc729dee2e974716e9729cee2e4ea59ac0263de48ca8bcc533556d7118357eb65b8f165739ac2a7ff1c2857f5bc5bff0df9c207bc3fee285d7f40b7fe13cdac3fc85ebec0e1afec267daa3c15fb8b757e32f9ca63d1bfc8577edddf88b0fe65fb8d62d00f80b7fe1b1bd197fe12f1c0900b8208f5519ce325cc6318715ae8dbbb384dac3fc844924b015717026c7819ab376b98b8b67dcc2d5053bccfd546d5c5697310eab3bc651846a4063fce32831ec04cd43974236f508eb63228490668706319ed950f96fb819ce36d4cd68a8fc3595ad501aafe19cd9a8373cc88bf34b0dbe42face717844ece49341ee5b241e2f6d749285f39295b90d36cef4c62fb7c17d588de3e03e9c2ce8b7416cf887791ff6330a5ce5a8fb59bcf11c959fb5473795add00f07002c67c769ef268703a02e5cb132d769cc86ba6bc34fa2401b38326ee17784c79f3c930eeb6a898f0da8f415a23dc85180c79f3c73e92bcfe229d650b7bbd5767b8a92831c4e7790861a5ca5d57da843d606fa8c2aa342192a3138558551f75f54eab0b6bba8479f5b79f6971a44bceaa772a9df6ef1ec1a0f7daa96fac106fa549d40f728cec8e6d06166b809455881154da860a28a13769808cfdd6fbedb0e210159189145e8055798c2187636c736252a0425458108289880c9ce66f4db1546bfa17edbba09d013ef20d87a29c20559c080084b2cf164a7bda3b4b742c0d1e40826b2e00112507061a7bd87dadb20c0560f122520a20b2be882154e6065a7bd8dda5b201c51416aef2aed9dbebd93ac746b77bcabb3ec0ef8ddde8d04ae386897da79687708f11659b0b4b77d3b2f29213941a90fed4376c70299f2032954014516a519ecb4141a466520a2045f78820992a8e21b094f041511851e7cc109293bedfcc340ed75ea79202188095c98c1123d88c24ed1bfa0c11542f085282c2185043b3d424a4f8a8092823338418a1d015c01657e3b8e01d693507e3a8864cd4b9a3ff58afdc35e524fbaf41da4079159102b8f6141dabb1a0b9a292dc1d656a1083f36288114aa90e2043bd0394b7b3a3cf4f6d9c2436f26ed9d1e7aff7413e8eda4bd27ddda231f1f4682dc69a887090b9288020faa982245163bd0d9a8bd1c84debb1e3a4731711fc642dee5d08710815ea43dd3434782f4d095b4877ae84b5a08e8cce447034250f0820b9e30918520ecc0a02a3c7466a23dec7dc0168e773d98410665d042951c3401cb4ece43d73142f6d055b0a5000e80810959b8e20a3bb8c2ce0eed2110ae78291dd328085e1e210856bcf41959248417bc749af666badfcda9e1352e07ede721d842b2434020facc637bf5b3acb5609964a474b484f4ccacf41c04b6d80c7f3a9dfcc44327ac484a0c1e63c263d8aec763c841e3e3c0160f0de19ce1af1afeba98a8bd26f2f1f94f569e423ac6f114444b3e3eff498e89b8a145b2545445117e4e5fa524a42323a2a167178ad241fda481faa77d9e3dcb92529223f1c7d200462d244ba44b57d21d33115c2d41d21d2f92eda09742e85ed2ba676608ee8126215dc036094cbe3d52181a4d768c2a557739987fd7453195aa3be6a80a862955c166ac178766a5d47437e74af9b9009a0cce7c4d77d3997637b34c42c87dec7c84c7438f55353908c3338d3323ab94996418618cdf111adf78920840127976583f7f0855bfdd7155221f762f1b425e8992f2080eb3d6de10420877f019233347e60821d4b0f63a46d831c61865c718e31563bc628cf18a31c618638c13cb628ccccc713233333373ebf85d9b0c42f60f4218047f33841042082184ac1be8c02c7a117633d7ef08646666ae818c03da1ebd08679c587bd3b1083f9c871cbb0eccb2e871c723381b8ff4f6628c9143f1d6ae7d4a1e72dd0e7b0cf4a3365478764fef7a84e6255322e8fe3eb4029511a2f9e61b2784e63d3b9b84b9acbf454bc420d502de2c29208272c406862bcebe26d19684bfbdb1cb532d804850fecd8288382e111de18a0c82c212ebc4542f75d2134f5c444f18dd608b474f386118d4040be051134cd88b2c1f78a7679f2ad01b28e6d90d5add3cd639bda5b65ba65a3a8289c9649a31a949d1114d6c684b473c0123e9670bd36493c78728ffdaa7cf125315a24d9c10ecd35e735f73ecb34b7c9aeb2ce378e8cfdce4eca43d262d2484d1bfc0d6ee303925114581025d228a429499e6ce10145f90bf9220f9cbd4a6ba9faa1bb7dbae990810458864396af10e27f949884f22c49b4c3a5897c7b879139afb5f1a2744af7aab9aeb40ad9eea92eed837b6ec481125768c1846378beafa2dfac9827f6c6cd378688c8356d06fb3b0a6eab728055462bb4ce478e88fd397b4079f5d88f6b6e809280c45b75e82b60807505e303f79ee2998080747ffb113cf71369122489c73da03f0df6239da9be917b7417c0457e07cf620220efbd79cef0eec798797b52bf67ef66dde690bf04fcfa6fccbb72809e837ce6cd67e664e42420408de81a523eb20ed7d46dab9203eab9076f8a3856c3da0ebd8b759368bb396b05c7e8b94e0c17f2c557b3df34b2effe06f0ea6d1765577ed1f8559025b44dae457cdb2b53155acbe8447681e2683353be896fccab7d3d4f4d1d3b05277cdcccccccccc6ca5bbfe38c9a79dbdd5fee3a4779d5e9a9593bab3c24a7ce5dbfb522204509ee6b708892c3fe33334ddb1131a7ed2ddddddddddaed3d0fb63a0232494befb2d4282e8b1a058d027947cf0bbf140ee63711f4ba77f7ee6b7080458f8205537e1a22642bdf4404f988967ef25d8a270658506a1847e43c10a5ad424e967fc163521fa6c21156893a567ef2adc4a7d656a340f9110fa1bbf4548fc7cc61b0f4f6f3d9adbb591d1bf468258c02ba8f47ec2043778ee2a9f7b3427bf79e8d123c66ff8104218639c729b62a0edd8d6a39b5b0f467dd0d79b8333959d6c3cd397da9b1c3bec004da23a0d3940d72111949ddfbf911aa997189584ff1aa997c3b428bdbf40bb9b070e42081ba90cf46b24a3effee8b0cae85b5547d86869c9ac3b051aa377c3daa3934cdf1e0df7e1113642d2dd6e57e94e055b9cc4aed851e02c78e618f0ee7007d14e6aa4eea013e8d7f3dc59e8421f1741c8b214d323c4a52b3ac71863e4d8d9888de0111f5b6996c25660942d601418858dd8888d36c258942d4d9499498b1088ee3a4697524a29a59452ca2334f506baad1877e1df2ac178a9a0a8d42c76a5494c992212001000005314002028140c0805a3b16040ac6aea1e14000d92ac5672521b88398e52c820630c01000000000010001098218100208371ff2fc93ac7f3f252315e71ac01cca79290e62a604498accf2dfbc80d742185055b94cfacc7ce1912aeb01ce0638b540ddc368d8739004ffe9ff0d7a44965093e8a9654ead7512d79cae817950721717a39d74e16cbbbc08e3b2583ebad0ef1daf19f853be30a24759d125b692ced0d0dffbf1f2ce565e3829caee38324e3e6c6c8cdfb26e968bcb41df399a82a37876a5252c0e005e9b4b3fae368c80620886bb8eeb100266bfab90fdb519e662c2a2856466f6e30a7b6886cdc4840ebf0abeb307fe2110401cb57b72fff849f137bdef823518e582543f7833bee29eceed08c1db37073fb995e4aa578b7a763cffc045bc1295a97c1144108a42366f560344d8d9c4405c1fa12a52082e437240059a5800bd6da1d3e50ce9c9b243ae3ffdd1ddd75b740d9c9b35e8b75a26a4f4fda238c0ba3705e93b47d59f85d7f607e1fdcfc07f683ffc07ef41f9a0ff6b1ffe03e721fbafeb83bf99098d3860ac8c60e9d5c3af186d823a507e6393ca8b85ba0eee6edcda894ffc062286a64afc4ff869ccf83d91a082a768c3500950799e6efd7e060320d6bce1a646f579b3de1d62dbb84f3da1235087f993b8150269983ac9c6fd9461158b2dbc4aeec490ca4ac248fa184be9864155c38f3c494253e45dcde8d033a5feae7e9ef0982d1b2e7f404fba55c5fb6a36d473d171e22761a069928470998074df3c4f4feccdc6c95ce951a9471afee219b32b92ababb9b93792f113ec8b6922e41a0cbe8e3dddcb6889344b6a648f3d308f5ac8e193f45f0730007dbf4225200c7c75cf801b013e5a43fa706dc1cfa5be9523b61fbaf2b9c1810e16f6d6b7b554388b0170611086cea34944d646fde50c6a4efbbb4b660930151ce61613a6530ce52079a2c0df913c654f0e663c9d91bb6dac56e417f4b821e4ec8055c16a379b889b77467137b60accc46ec5faed1fdf6141a38d601754faec01daf80a7bcf3df2718ceab20475217d7b60267dfadc4fa438749750ca672fdd586d3ca510a60d905cb3c5388cec77a5b388ace77c9daf892f15f6d76d62007029ee2112b246ea82bec213c4a007a9089bfaacc16077bdaee682823fda97477135575841051a435618dc67b224a37f70546ae25b9c21b21df10f796568892f050eac1a906fa6b61209cb9e9b9d29843ec69d1faa63f65d242f19a16befe62974c07bd22dc60f6fde6d001cf2fd4d245304d0fb53eb243fb4f18cedb62a2c3c2511186cc96f2027806651bfc0041470ea95735870eaf15e1f0c621860ea536263b6ba7485070051b6f065ecbeb2c17d472220428c79cd5a2350f95343277a078d87494ca88b6a8fe98153a50cb728f6b8b67e531e251793b3f9e6fb3d504164989726b840fb4c0139e0c68b01682011241b8b86913e548defeae5f3af5253c26ba5c0579205e89e66d129feb101c1acfc6e0ce0155ecfec1c00f228da819d51c0e14fd77c1984110464afd6e4d86febbb837b13c42b78e3f7143b72bafaa2ee6d05b3dca948426c999a5b2ffc15e17df1fc293a3389b9c9a99f1bc0e305faaef12a4058e78c66543944b3b811bd86ca1c7bf843f83fe78ad5d08d69723f75276da2fb771a0af1cde7d3fa3249fc210ebb66720fabc17a3948a96270cfab22601bb9872499b2c8751cc518af520b98206449461a17309f47e10174b6acc0473baa703730763c4d4109eeaa2ed926c760817bdb4f87a911c81d81b11cf51a355e01bfb3899e24fc83df97cba57de979f0c7a3a72251bdefab0868172330c1b776a3180604f33c2c1b7b1e88a62ba46be8df952779884548b991141c01267f1e05a38734824fdd8c7cb6291d62a333d037c1e33d7a6935886865453d697390309317aba68fe2d0a5c35d07481d636ad9f0071dbee5e79dde3143c944beba2ee0d623cb165f83a5d526969f84b9e6b6624e9d702c242eb668a103dea0c72f36aebbb7c92ed4ccdae5e7dab9010fcdee22717312ef68634a1036dc508b3e73d4e0850b35647c67c38059d99330620d68b3595c2ef0fb0fc4c057cedc631602a4cb8d6cf0e316bb3e664af2b60382383660bae0afb910b0806a2db243c567d78dc83a773d8881180268d5ed547744d9dbfff12637da1a895d00181687ca86ca29bb004f454f8811082d75eaa5db2e95593c832299ca895bdc975f3be995a242974c01e315f1b3aa199554e168dac697b6e47213a5de549ac743741b3f1559594b917b0611df478127e48c39f0d202f82e87b0836fbaa403e44d77d10d25a9fb668e5ec978e1bae16e63649d2b512ec06c5f4a9aa0903489f68c283f68370a613147913f56ff8caf5e21c8a3880381f4b4e3efdea9540eb5f9ee3911c644955ca3aff420ec694805b411387258454ae0edc9461a9ec90caf17020308ed3f67477e297ab687e2aba46e87ce3bd3ed4aa67163c8e580c44618211f401ea63e9468558deb4d127ad8bcb5d062f437eeb8b5b14e5f8d59ecc94c090ca9f792d031e4f54f021424450c7f922f145de02d52c5e65f309ecb2687dfe7aaa551191cc95f81247d339732428747f5cb35d0750745258283648ebc76190b51511d03f080bf0a1042be73f56b9a87e043cb8a0127937b677ddc72710421840b8c80766a09e6f2ad059b30c78e5504d67d692ab204045397ed6b8cfc8ebe05b0a045b639573ad19e5aa5005ec206656b348b72a86dcf6b23ec14408ed74bf3a366ee50b82f8724698571140a9b4669286d000f08e6e844e0453950d176039592ddd1850710a372ef04aaa92a3cff407feb8e5e9a8f9b576dc0e8552e01c0c5781d227039685c777a0989d1b58ad5f3d693dd8f37f353d0c9b679a4b11715904b30254765c02d836fb7bf3806cecd432c58be3c17be7b1ea9c3906da2163dc480476429ef0394009a0557fb2d03680a4bcba0bd67a921cd681d5de6c35e40103c312ae20d0deaba44dcf4cda28fb2ec4cc254119bf12a66fe38e93b4c7e58882a4920ed63e24347c5905a25367f419512845e6a368c2372f61a798b58ea4d0030b5f19c1d5474b0874525c53bdb5989c684d3e87a300303a4d61a9d7027020c78289b91b5120b895c67964fd1b6c91207cffc64c276097bea458f8f6b78e02af1a9499367d7c6c34d3c22df09af560914abdabc72cc70f3ab4857c88cb0fae356a05bdffc93e7106c628c45e0ed8f995594f7c2ad02402961a4d6b1be37c19ab31b80aa08880ebfd7edea9a2f3d912705bcc4c5e650712d32b0745ce8376f819df356750f161b6a5d4ac5dbd88a7bc24ab7d2fdad60da6aef19a7aec0492a9d64838229be3ee77dd5dd68ddbc7d8e9d294955847456a3a61239b0ec15218797c1377d9184aeefca31b43b525ca0d388a69990501a429e97c534092891b6646445613e84e2b153d82890fabe4e429739b7c82c347bb49a4b6d24fae3666e843d6a6a2c31585ef5ca20694d7e444233f450ffafe71e4ea15ea0d79f0fad9f6cf6b2e4fe8600904cad223225e62588289b3722895994e76d57f58f0673d961570229c99d1794adee7eb35c111c7ba5de778e7f6869206cf08b3a4b56913526c0ca48eaa23e3cfa5581468dc29184965a85bde7df49592ea06c5042bcc2ae484e90f925302e965d0ff3e340f72d4041cb3a7f115edee3797bc33fcaa43b0f1948ad4397f5ca99bc85feede58f515024c62833509d6d9ac0948688449b73953c7316a678b5a8cbdfb927e2160a01e3cd4cbb2c06493c96b73c8258583dc7724afd90809f9304731a91973ac987866eb51ac9936e23b346bd9858387230f3c26336ea335cfe276a99486d8d5a0846f423ae149a43e04f1b3e1f6bbabe32f1d57e3874ca046c10b71f6da33e224761e440b85d831c65ef60c09677b4705fd2dbec273e350c5f18c274d00ca9ce8142ac7839f507c18efe1ba415d99ff888492691b870ea8f06b735d287d3d007539d825ed8fcfee6a990dd308a5cb3e95a50b8d9257242334ef5dad3880bc58f76d34cf8e0b5d3634cc6f5c016a4bbbdd3d3ed92ded10e045f5fb1306199ac4976fab3d6e253bb5bebf43235e283733d86dbc9acc6d3a0988287154781dd2932e2ee1270d1a28c9340dd5415ac132dc600ed237ff4521555fee34d337815e718bc93737846ff64d6662b03023f9aafec3659262dea610abd5f28047f76f20a254430de20872a9e7d4ac44b93f63d30062d101f2e50a62a17da01f67ed3ff5200856fb064d148a3027ff915a5cfbfd408abf495c050fd8becfd49faa86ddeb08483b2eeb80e08f72b4087c651d09fbaa7c03a8f70fddc867e4c8e7769b4a9edf3b129c560b493095facc28ae9b87220e429965497dc6bbb37f9861761fdc438d3df896ba62f0b7bbcd5871741fd4deaa25a5951774535a71c13dfc85d415111189e432c3cdc05e5aec41bb62c56a963730615776380f6455563ecca96dc60317892612aac68a3a4dd3f010a853dff920605e26f2883d95860588db52229f14236453323e050ca6f73dd2e7bdabd9aeb09f8796f52f8d6bfc15e04f8c2615e1e00427253e3e1d220c4427751c6a3ca333a8ebccb13cd8b32c33b73a683a28230d2ba83577fe95daf6f484273a8ca613bf60b090c4cd0f4fd144fb1c327164bce200b91780070aa3664848917142bcb1f193928eee96224fb0cd123015f49b25c50cc5cbb3165622e1ffc4b04a4d0f994f44c522c74b8c52305a99df21d2c4f24544a89d69a9d66e6d58b5d1ed94566abe11c6f0e38e9e6e7022c253ade8ebb8a64f6b4cf0508c91e9421e70253d204c168122e37abc8b25c44474117d7dd6cd81f63d307809bd56673cfd3fe49d90b527ed85c352862fa91648687185dd1712c5f4829240bd16ce3ed72febf0fa17c08b4cd926d2f135d90012033d4a7502f5e59c16e3889556f0db2bf894d1ad8ea0ea62169c2d23219e46a6e2ce167789d8c4718166bea6d78ee08bd878a603965514441f0098a862f2ecd910d680fa3d233c385fbf6e9eddf8057b70e9bfcc3e50744060821498830c32d56cf540b3e3febfe2e7790ba3b8fdef31c600efe32f9293889b26ce3b0537074d89f956c501f14c6df2e2a3a3063d1037ac33bddf34fe6464c0256561fee02a6814355f2818b6eebd1f59780641816a157a112ab880318ed4509171df33e70db8bfc1a5531e1e492e691247503ab4051178456599186e60dd7e05e61c92b64d8b917358756ddfc6c77638651118ea24f2f77457015290eb8a751fad7f971116c6d9e80daae2a3337be303ccaf87f2150e8945648d0a5360ed572031998097b66fbb02f29ce8112490c9a111b7e8d342a99adbe46f81e9e6a84b84e0a53b4d18487b68321cae18b23747cfa4813d8487a89b057ca623e95e39cbd0692ad440e6f8b3fda31539732494511f3a2e69d23661f5bdbab46feaf199a7a890bb2ed06ba37ef640552eb179ac0bad08536fd01845ec2184e1537d02df40632b642d485fda7d6395a0dde6e214064f5099ef1a4bbc737ab8c099eb978101d729699578065e3e9577015603a485584787603dd8357b36447233abeee6e7c8446671521ac2d6bcfb6f93aaf5c3e1f60da4cb021f0dc0d4be53d8c3a020f8b2537aed1d734a7099bed9c4e4133143c04794d5cec514815915b928ffe66b4c3122121607d1d8c22561bd604b54511b88b24ae501ab6009cc4761767e1bcd7d1aea9a84d50c2009888f363a4bbe92b109c12e53719a0ac0201fa93164ab57383469567d9cc0460ad5d5a0922c158e1784d0c8681371fa24591f45ee11bf6ac34f139e2e93fc8fe36c263699c7535b8b4ea52649a195c3b4c70e0598f4ed5ba82e7ce080889252955c3fdeb44c7f6e75ba5810e130d22c35013ab54450a412f4c81209eb0fdcbc87810d0401ebe97abce7839155c74839b95db9d7727723c9f53c4f0009f34f3cf0cdd48cba5524a6bece72b3000549b5196f0e79f293d25438fe899aae6077e4c9977ff1475390f23ceeaff6e71f38651fb796ea3f324a860d1c51f097291112c4b0ca39006b54e1fd7c131f298f3fdb2c583e42844521bfbf10068da56fdf7187f70d1310fb0eba68d1f3f732f340e6a2492c6de93500425a2e8b4d3f218f987c020fe8314ad3cf0f56a0c762e7947cfc0370413d231ab42ca9e25125bd2e53119d08e7ff190d59ea8176b50a1b88d4d23381023f42ff8cedb83f24f094a2ba6d429b2d13b56e0e9f35e100080189a24e3911aa71247038236e8fd2fd7d4a823bc0ca9c749589a4e73070573943c9c964cee691bf4e650ba4a0e9435adcb164e702de00fc1f9b2da19e18f8b684b600faaf3c00b6636840f223e9ba0929186ab1f2e5df02c8f9fef6c58a910be0b260e0a4b8123f6e964527000c2fc7a7f849b37e5b0d3cdc9dd2dc39c6a132004da5b5004a32aefa49576f88be1214c454fb6145594e12ef546b5f9f332399fdd786d253be7dd1560598001e5b0d59bc14de524d3a70a824d9a61bd77ef7a74bf00f6ce48f735a09c21683dbbe1f6320638f31c1a7ee88b39cd21c766e0d260001b9293bf7527f9c8a7dd18b24b103a1f82f13cdc1bac749b79bd86c800bd5ad5406332529fa23b04fce613e131da3bf5b244f4610c948b40f42d87860a941dd4120c89f32394a76fed97add37049928f8663c2ab8a4499c23cfc2a38739a67398317ac67fe4e4d31dca9fb8b33a34b829a7ffd1dad9d14b26b38248cdfc8ca1cf6d6f9a6f84b3ae90014dc5014351ae69472a05fab684cb3d97d1537cfdc46f508a73185957ad1e7498a44a4183a59939536880b3ad5562099669e790bcbbef4483d8cafca900db6fde0373105fc869e3bf6945392538c547883a1d163e01ba4fa111efcfcdd3cdbc58bdf264d7804d8422466356a883942ac18f529d62110f0dd96795ee10423d8b1fe03e8820714cb9a348b5d87600b85aa9ee578faf94fca3e497c9db58d1c6d6a797d196c840cd2ed67a869ce49052a07f6ee236b2290723ad2314929d2f2890fc5ad0b1dcfc934b358cdf93fdf4216a39a02ad83322a2416cbb2a700ce45d71ec842b3407434a636b7e3c180f5dbc311f5bae996cd2af8d43995d2d42f586ba202a52a7ddfebee520a1b0bf2cc7ebd164a599eb6385083e0dcc40ee16276cc3e3e85d5c7291b5d6b41ffb09ef632efb8a958700c6531da06f5eaa77ef86b013caa3a8c4a790f52508d688231c07d2c54ad947b8195f2945fbce0ec7d84c13d754ac909854d5684ab4c4a67f03acaa46d4ed44d66e020b613721e23eb6e091260d77ffb2a2f09256626b27e86066429b764d8b0d5de72ef40b08269b3cbf93cd9ecd84dfb187fdf5e60f7847e47c77e99a369facbeef368f1e0ffe25f8b9ebd15d57174fb48fde55f5e24c9df5112301a0279de61a5a0a6adb9ebb2a031276ee36d73387e1b782502ac358455239182c1bd199a08f3a6e63d256a0c5e85b6501adee961af1408530584d25e4588b9e0bb320b9b99429bc39d944cd71f853cb34a25b0b0d2a0d0d36f0200c11a25d762571c89a41ab69983af23d17dd0e3c2769d9251842c52098bb4e27e39ca29e1e32f9629c2b5345da0d3f2658bf6881efe30d6c372d532247195119679462407e71a012e345d5d344cf33bfded5f96c83f4e6fb443793a762547c9547e5670aa13c30bbf2c285fcb31c972123e0dea503fb63d11cfd95db8d4759bfdc5e13bde05f0a359e72df53bbe07589484cb0a76e5e88af9121d96821d9c2d0b9f48456d9395f5509e9dce8477dd98fa23c3a97c4ccce057ca8d3257e6bd1ca2253496a512f740cebd6b79d0f43dfc8c20c04b3fdbb54a82a2b574abf0e1728698bf9765893c2e57580a635c7ac738b74ed4ab9741b1aee89835953b963fb5bcdca1ea397400d4c9561e9ef1709b552bd2bcc61e61c90a8afbb000905535932e2f1c431a88fb47596b28f2b77e2e5002599894e9ebfcc57ffd90cd66fd0046c89c54cdb4d5cba9455af5f75af6b4bd9fd40b2e611570b20e016fc696e79794257eca8490544cf69691fe7a91cd0c5766b58e41b09c7aac2efa6e04d4d8d507c345977a41f85139109db972cbc019c7884124dd8fac30dde3d4b04f20aa5f7dfe96d8bf1a689ca3038a268853efef2aa42a16c7144ea5bf52515d417ae7c25306ef4fb5331f2c0e6786a20235f502928c52cd137f3942705938149d778b9fe1ef332bac476bc79c30eaeb4798cd4c6cbeaed99412203aa680a3c32cb1aedaf21a80fc7576aefeb6364574851432b96f5c781dbcc075480827ff236b59b5d112b0e0aab609d5a3f56f33e5f37f44551020c098f46059a1f12600b62ac0969f0ceee551a1fa422fd024bbd73842b44df498103b3d3f6bd413f05db6a707843f3d529782515d35a89bb6371b14009222aa28955180287ca638378df71b40292c7c7975e47e863b607019b7bef6d8f8201fa340864a551783707c326a42b08013a6623738fe81b0df7154725ac842226a8a702b4c5b473b0f3b581653d3140f84a2e905085013943ec910704fa73dc50b856b84c7b7da5bf363aaa67c5a53ea99519696a064ce4868e62927d222606a982162a6db051ea2a0dda2006a98a36cca178225fddd61ac8a386b0cd27281b5e8ab53753ede6ba1fd7c226035bc4486438ab70c7e2f7db34f68155a0e9f72f5ee998a11a1e212280829b2a875b1ac695f5891184d66528ebe23c1f1bf7ca2331d5a6d7e852d394f59d30453821cd2779e19b27adb3913afe4d3eb49ac39a150322860e1302cd48188dab687824337b179d408ca5c62ec109a1164a67dafd702cf74c0fdc5b5a4d45951a7ea7e04712a721eef5a807240394117d85258c296019a1ab601395ef2dd4158c6dcab0272b0a75755fd548962c395656c0a0c768be20ec7b06d3ff04e8196355a46ce5b9876d78d0e1903629ae905e017f5750ef3329c4c91a676469850df96d0067a8b52186e6926384507b6431e31743357dbcbd2de476f00fc8e0280a8faba245c22708b12585643b3bfc4d831f14fc67d2ffe8d5f531471019b2594d79b86b51f720e1e3249fc628234f8784c3f27271cb23faa5b3de11ba8e4de4269d28c22b429c99761cdcf12c5af5b212e0bf07765128082545c84484d485f18df1a884f8667ff17088d171e8d146611ec288bf6935a48a68071ccb702f97f8c14c2b479b6cb966a8188f74101d106e5c46a4a58b90400519d5eccfee18a2724464ff0fe1cf64a46a4a6f036d4207aef125877ee0b5f77283454737cfb374bdf3778f2d6ec075ee5eaa30d3a6b532379fd9c87f1b15a354e8e747b4f32097abca7c804123c116efb877432a9142271a7321486986933f4ae98a4ca4182422d028dd950e6960f1d83545963b056a55c0ec94ed8f7ef9c3450133b87e4d62076ae85afecaa7eaf0466633fbe4300eba9d457eb2cc6a248caeb21d70267f0428646c4df35f6dcdec2dd57188f3dd2ab5828d9748689cab26cbd25ba5b68a8ccd2f9992714bc43c5e74cdae9a5876dc6896f5b2e3bf05a9c50e46039ff6ff74b7da68e8c8b1cf74cd30b2d086c1cf2a12277f78b951969b7b2d44c4cb90c95677941ad416a45a34eda491b9d1bcc3db7a7eda3f241161e6fe54e1c1182ba83e8b5d3ffbfa7300a8178e35e6ecec1a836115371eba3849a4159283812bcc19bc83983925a711bc0c74c24b9fcfdcc56ecea62ac767388edc0096db85603ff8dfd0e0f8eaa43bc07606ad438d571026e21412558b60f4c3cb8b39d35860c9897f302aeae8e845e74e0431b2de4a8396e02f61bb9686269cc18bbc2379de944abfab7a50ad2afa3711950a04d3a58fd253da6e29e02defc1595e2b4e56c31dd0738e64f7079e78a6f07a62f4c3ae8259568d06859d12e826ba13dd0cfa9f6bcdc269d61db438156a585ad373809d3d0ef207ac2e72a8fd28e711f83060b2ad177583e2878dbdcb00f4ade57bac4ac288268a5690173a4dda46f4fe1521dc9c70f6f6becd5ba191d4553b6f6d1b3cf32cb13be7908dcd21a99d833690c01d723791ae77ff9d5ea3fc9b3510b5bc8333a5fd854c7a6cf0b2ec5c3c9b18263ba59ee4e59d31b90548e67692efb8c75086259b30572fe1e736e2fce05c10213f9871a0ea9de9e6664df3b5e3329502dc416e08958c58f87bd150088ed60db305153cd0863f662b9c4e1f1bdeceec780fd6781b13205b2f54337c760861558ed1ba58486d643cf77b51b5dd1369482a245e22cee8c52152996b3da9fea36d898d494a6a75f58dc1b655c3e84c0493c565f4824ee666121796a1e5b7e48e0d6ffe57160cbb53d9059f3c7f9e7df29bf898588e0bc2035c4f044ce99230674f139c3f974e72c86db78811082d657724828228d5d4364b6c4ccbdd28d7d7f218b61a15063d00e41c3694df61c6a5493ebd99648cc30b871c1b6ef7af763be22b3464a3b2915c5f1590cb93ef82ba33e7df3d0c1f6d6caad4db069abc4ba2d8e75767b6b6b389dd9e9acc7bee2ce8f8252076c122125472355480e466c6478046b907e48396d52ff409bc2ecf23b0810da212fe0603d890416804e745cc9ac727d8082c3fe22f9a16a74132b4dbcd20f3cf64d7ac058dd1cdb205a71363370c7777beab14c67a76c72bf1f9c4a94ef2525120b951e09585c12b7aa617642475a4a0a125f02347e44196abedee1b796d6e25133fb387bc211331c3341f1b215b2cfd17f17aa840801eec7a81dabf5a24a5202b7ef11e5321a0470ae8160af25a2f839179ce58042b9bda0872b8f1120d4e2c525cc19c3e101542a23b55c5171ec27b11de4201a8b147c5caff5435e0e26e7c91aba3e467bf52fb84a40da31644b83464640200a87a8b56e7e7c66d2529bb091048c4156c47968028fe845d4a1f9ed85faf352a0708c557e478f3d25624f26ccf33a03122611b95733416ca80431e39a3c31686c14a9be92177d83d479fee0274c89158afebd197abf7b227bd9ae1344041a0986bae79a5c4794821a0a3fd24e396a6df105c474a8d80c5a380c215a602a0b581aa4ab563e8df2560a6cab580c917a651214ba661a3119835c6327b9a841a6226b14da0a1f46d0fe27992d4814fd3ec6d9abfa7585b130084876c6befc177fcdcac5837ee12faa080e02be856dcf0809ca5c4e8d4fe48e3d4f0009931e1f9f419215552e2e3738c51315282b2bcb26f0e44ed0cad2ab671022f39e3c3ac3490fb578a85d3eba7c3b8b5b29047bdcc95f7f3f5709714e9abb739fc23e987c16712d884e487d4b86055f79e34939bcb25cfd71ae8741ca29ac4b341251af4e95dc059d6d5719c019c92a5f69351ddda19d55e819971be757891d7ed5c51ea8e99d8f1d42064d535f68f35222e50de90a5d87cecb60ae584319c9562c0af4f8ecd10e3a70b4a5e4f117ea4ac27b9a0e8c66aebecf507850a4512d435a89eb84aea0f7f1c6341a3c2a01a11f285ab96894d806b50b1c9b0d054f257da2d5fe063c6636c496001ca07a6f962042d452a180e7e30a97402bade149994e162d66ddd89b92aa8436445585f7f0237de7d320662a65c55516330093f450b85013df5200a211ebbf2f317f094790bb394eba2cae64d0029a702242a6a6f4757384978647548416d10d720298dabea33af40d0c608416b358c054b86ea56b447a4f914ff987b2a631c037fb188320d8232b3c82a11856a85b9e0d0afb02e5b4293de50c6b4b48492be1d1867090d1552019368fb07d0ac29a1bab3e5d28c969450a74ffbe328a1a84292db50773f055d1b93d0deb696844e8fbced29092daca1adaeee7e056565241477e15e3eb32812ba0a198d446b250a7a60604c245456c841ba74db5350b20509ed8d0a48e8e88d7be74768c4723b911b55b86859e8b9e5bd2d5dbb13977bd4d75c743deb11ba5e1c1ea10b4d2f37233ed38125b4b93dd211ca9e63afe5b0952374b73b3842df4f12d539dd085db1f6aa052a5e6d6d50deaaffd8e9b9321621a7757b761ccfc5cf5b798174c751f287534ddedfc120e9ce34ae1724d214872cbbdca072454a6bdc877797e41ea04cb3b99cb42b7dbf874274edba3354c85439a95ef28677c93f53b1522ff6ac76d96b5ebe6b67ae5ee7b61bc8ca623e954d6c37c36bbd97236140156a139420c994de88636dcabd57bb2f57e4e0a01ff1f96039a4a3bddf33a774af7fbbfb4328bcdb69b724fb3e4f1031c8f63f3b8fdf15dc5f3ec1e275ac5149f928b84733cbb5fd2d6069fc78f11d1a26cdee3420351f5a55897768924236945d990d497b1642e80fb56a123ac3e0fad002847eb81ab2f0d88d7bc64cab8c411c01734aacc51acffc7e414604ab40be7dbc09778683234f2269896a9268a74b364608b4cac65e1e2103aa26695e822c2fb7ce91e056ea7e77635c34ef87636c361544a72fbc402e6e35372faf6601a29483fd143e31121d105f3b7514d69e58201a0ea0c7daeb6a759205c5116b7efed5031ffd2f5a6c2e7248b7286bde509c93fbfac50a6a12724e9ab265f661cde0639c916f8cad718cf54619e27046c0e50b636dc70818055e541a3959be128b11c858f32cf81e7506aaa46c18ba0c23209fe88ac476ed5266909c5c01887a4cdb7848d245f5cd999c2a71e6023d919faa3c2302b4477edaf172c73e605dbc56dd6137743c3e7449d9f6f37c4b94791b5580008d94ab168f5ba03cd4ab1809c42ac1c431c7fa8726f62caa2eef6ab518d910a113edbff55645c79b3a290c97d3a33518c9575a6ee9ffd4fcb0e4461b640c7c9af0ccdee03198ee9404f58bd8feacbb433af489059c833768b760d8da7c510b64e43c43b9c05a83965e1876d6f06cca0d428721f91ba5c05d0e25727c53e45a1efae588580d6a62808eec7a09c42e39e0d1720c621792e6e791496e4b698cfc12fa6d1ec05555a91705d0c70edafed69161c5b18bd423b4204be7efbcc660313d2f2923deac76b0270d54e1d5c639159f4b0dce7f65049f751ca48199e7facdef8eaa12d97dd5e37776d7b61c45555644e86a363daab0a3b242c2d42d555afcd0b708c2c450e2c6eb5b73c953b13cd4dcb6d6c625083bdff58c0b3816ddefe023bb13e2471ef8d592a4547ef161428a98fd4f9b8e0421175262f63a891e4515f5b2c30ed426ec511b628b9f67b613cfd18fbc07fe489eb1bd984fcbee3e827f9ead1324e981e47c78aaef5b12d1521bfc82a72bd053b2b3817102bc6b352e3811c857cfef8d699d0abce53f4d942e00b92fbe2607a8179f3c5e96ca9a95bff45461641187054b33486f99b1a2bd028c2382e9f6bcaa73514fac563cec8d76f9dbcd55f1b3d9cfdd40211bd393808653714748d7ea0cf62544540ef810c3356fe337968bcc691861cc87b6ae78edc74bc05fbb5da37dd70cdf5e47d7192b7fbd7784d752fe85d32c6c035ac28943959dd942ffad0d949aff8c0846f38d45642012f81f8152e4b7111b9f95b3035a1f7ec91c3f20e457d4787105c2079cd583d083b97e7cb7d1a1034322c70ebafa61d05d9d9c7273b8d2a1c0dc0432893c1987b0d37698ae4434073267b887b34cdaf8f94e43ecdc62ffcfa0c96023a1920f74d1e12defce9c8ce8dfe17d61ff1cfe535df28df0c76c33491aed7dd21d3bc893376667c38e91a91b975995dfffa37eae69dc1439c9db2d8f6924c8c0b12b9fdb55d2fd6ebd93cfd93cc04bef9174643d799b2f2a983892b9331e1ab47da28768004aa50f3475f8c34f282d6c1630e15b85c33229a37b512ce24c8a3a8e062caac3d1a948f20caeba89a6d9b63aa7dfa78061af8d6ecaed9729e7c9c849c19818c5af6b57649f5fa6682b13c0412486823703259b47d1aabef558507293f6bea334172221cb6d3e2bdd4c121c16b58ea107bcc672b0ad0db7959ad5ac03d8c4e5dcc5f5c9958d8efb40e87fa4c2980415233a5570afed5be23ac1398271643e0cf4fcfbb2d858ce728dc9e8ee535a8dbe9660543692ed7e9c44048485833a84d507cbb24dc21b135276d8b288d21678dfcc22222f0507a28e5539e3e374d226bcb87a659bf559ec6a1cf7ee98497b41a0d5154e86c840cd54579027accb0bb68d70887fdc38ab4710288de6c8d1038235101daa0c6d2037d62ef8a6bd79594e5ba16df796597c89736b2772822a37b8370da61d5d6eda9e520087ccec9eb7f2564a759387795efb6eadf606fc14ea3879d962756e664a11c0c83bed60f2c90dd3f9b4a17b517debed14d8fab6aaaafa417fddac7738ed09ba51c7159e00096822e6d518de3b4342319a8b1704479a4893bb2298f2e659dce0764ceaa84c88578998f2ad3365823d2b6daa9bcd1fb09d465b2956876b60931da9581e3919799a0cfc0daa0535fa7e50accb2972d60273d5e49c257a5d2a20c5370c99213b5a051719cedd194bb945d9e1df41c5562b08cc076a02e7317038ac1a195376df483bd56c2d846ef69c54fa051577bf8a937b1348d938bc959a9066ca2eec663d23108e54839d080c6f1f44d8fd79c9df92e218512b15500c621b0337bad62d661e379e07ea42ffc3886976ad3691b16c516caaec2b35d6dd2e4d0aa8ceacb796cb0f7a784b244e074fb3e638ad110ad39ef9aad73ab065fc26acc9e7b6f08556f75ccab843a47ae007806005c9462cb1a39d1b302f2655e8494d7e6de77b9d2968c2b42aa4da1ed6a20cf999a3b31274e671fd3322bbb3360239495c62fea4d3591c286641c17546345100b360ee5b630b3df11ce552fa777a33272ab8635bdee5f3720aaee5832ce0021656cdfc295c0dd8ffdbdca877147ccf3e7b1bcdac2c2c0b94665b3815b3aec9d8a93622f3e8858bdcac3793a864eaf05f8fc92521f823524c0872f7e963eb053b4597bc9bcb714e2b6830f91caaf7b2049f8cc51b24b96749c226a6a9e0fc734043db674aad4c83225ee57691ac97ec69c24c59d838d2479ec136c0bb6120771a59e0a04af5c2efdbe8c071466416ae2a1929ef18e6d0558a288b1294ea90183d3498dc56e0140ff91543439fc868e6e1248e46decb63c4f39b586fab4b218158c8d868013b67b0142242d0d74147fb10748b1c95ce001d58338433b7907435fe2578d2a0320a1482eedab7d62bf594e231bb2058e44055d06bee78b8c97e2e6a775a00dd25eae193c3f48e3b7049ead8727dc23ecb1d0ce12b657b56424b6ad71d246c01236aaa7694636e765379b261d918aa89a9b6b8ccf44fa29b889e2c2d7238df51a1675df84334242acba0b5a49de1a74ef81518c37a0e05e22979a08c465305b6e850701fdda840206e5c161af9fdd451291114213c4227ad4c7409b22f862571424ad67f5b6fd2e76e7dbb190883e1917e132a1119a99b5c60285382c34d7ca6ed1d7eed9f96704180110c199240b04293dd6ecf6306ed5c6e785e9befe0ef80be17f4ffcd8e1a9450777fd694cd1a7e70f14c54e96da2b6cf5c19cf11a84c1f789444fb8c23ab96b58709ed908e00f0c1c71ac91ffe5fb2bf5af5502a6b48fafb62314314b0ff4b76668d54d4ba356ebc93d6c33ee7e37aa5bf0c2e2805ee4cc53586d059c32fd66cc7e6ad62009657e85ee34f515a3098888d50952fe66f9cca949405eea3ddbd74d1880ed979d2deff11e6f7e1e0c89e3fd4ccbdd7d7033ea881d08375c8428c68418fe721e5c709a8e0ca7d2ee833c5bce236771b03dfe292d3018fa71e44049e43127ab0423eb4cdd6e2e02e5b98ebec56344b18c1401d6d503f671b8fe35394d0cf2970594e1a0e51ac5210ea11b87d178e77958d92462c7abbac0365964ed84a1e259e11211200520a80a410077c9a82fc0d053410557304212bef298d9d26a6c26c959ec60709ca09e0b97aa9ff82177a248176653c0d3614a8920624a9b93e68244f1e5007275b68c240e0b9a81f5deaa4a3343d39ed7a5c873502a5bcb2616b8f2dc593f5c96aa567ce079b81cc0e94a888e680c94d1640c8f4622ba0bd23da6a63b0e0779c10fb292eebd965fd7c7b3909435111d95a89b56cfe3bc364e7247b09c13b64d59a7edf8d6037bed26449427ebb70618524b8018f1ab5c92cc8c3bc1ba673506ecf2b6da122f5d56c5b9db80ec7481a128ccda0b3a489c1a08967128493c7f7b80eeb9ecb556be79e91a581862b38820968896f1830e73751233130c54493e150312efd40b5e5ec49dbad661d75045725709e8eaa91f114a310d324fe215dd8bb90e118cf6c6fcef970cb0902526d62f43524037c580f0bdeff2364286593c737c1193190645e514a39bbcdaef6e1a4b5d7508a42ee6c650382a3d75d5198fa57ca6438eac7cb9774c62cfd97029a84f0109bda17834eba62521e78c0e81141235478e7f9c8f4d7260b520b41c771f8185ad74e61c6777e506cb13aaf119d09f6cf1aa7308975791d320edb0990e9e9471b81703e57a8df4f4da1a88bfd530a03824b539f0a6debb4a5ca10781076dd73badc1aff31297bb04848bfcde4c015d04359d06dbdf1053042b7c3c0e8970e2c0eff86ea8dcb2bb67b8cc5531dfceda526d6e1b50842a0698e4c43acd8ab794df658d9550eb5438f64a1f4d89ac747167bb88d09f50e58a44c7ecf9a028522781b9b77fc666375da1f214513de7aca12284c752f4cb3b83b2d7a9827fb76ef76bac041b7f465997da424c813fa806df4de7803089be0f70f245a29e30a7a053457cff9bafb96511376794fdba0f90e9444a9a69ef34a70d3f4686e190001edf29a8a3616332e0f751e727e808986d38ae090ab5d4a1d89aa501ca5345b6d1dbfd28c13e8de57d3d2867b3e7a3a122fa916a142dcf2ca6d7fae033a66012b93abba2b14558e3a6af80af11d0af34c226bdfceae3bb90249edbea84fa4c21a7acd0c636963d26148df51e780bcaeae93ba42a631c7e21ccc2400aa545560ad474ebb26b8d0be7d44821a7c60cd5b3fdc8ccfe853842becf251e62bdbceb4f387de35225bf9ea574ef15fe675da958636e05d39381f7a720ca9ad405111fb337f135e64ce20cadf302463489802d927b954012b9e2f9a41457d4c4e60327daacd1f7233147b7bd2d245a3da81a8fdacec4548a4fea61c31f11ba030f199b6b82dc01bccb521079778cc63d5d1884288c064fec84f7596bd3296e9284a428ad7afe54724c516ca29d6e5e563e5b46fe99f57b2ea68840454f6be28ef43031098228d4517c568360ebf8e2be24bf12a2267f38dae377ac7ebd9b25391af46ed58d21398610f1e8360eb61fcc9c6368118c5ec6d82da7c32bd26fd2a296985933ddd08c15494ad2389aab51572dc91b5edb0d4544c83c253fc604cbaaf6223174e8c54abea6ad72d883c4907ee11136b41760f157620eaa9548600802821adf88c4c8632e207d293a0a418231d5a493e4098af707634ff82ee06ee5b44e0a6824492eef940b721f9a2bbbae517ec592f3696e80013dfdc35402e044ec6f95e0c2d196cda8cf1ccf4fa1ddc5c9fbbb8ce67c3d2859181cc6e81e4c64af9e0fdeb85c1c1779713a09151e6430dc1d29ba9f4b26e800b1edb8b3a18fe46a4ebed6d7f36d2fc4472872ea5de128dbdf8f77732ec603ac40b1843bce4d4de7843465e9a07d44bfd293930dd43558171a1ffb2673880c757572888f8ea2ec23c951b44805e5c3b3b0f8e3288a68c9787421d17e446b9e61f187a8be8ecfc7aa23d0cdadcc230e15ca9a26a70f14ef4b1469c60b7a13023c92f01452911a3a97c17e61b4df5ef4c0980d5abd8b8398eea5cb08238bce7b72be43a673fc5b2617e8b5327f05f1dae85a7ea1f7d0ec6826655ddc56230f550da93a018b163ee31d8ce8534a99478bc98348a66cb833d9b6eb5ec37115c585dfa86c8db801f48b1a46790dc01dde3f37f1e4ba062d58f72127c50ae229427e295a6fd8614ad4f7ccb526c403b73541eb9c4b201c72bab23ad9aa3134a132916491647ac3f1087764d2af00ceac4239667ca62a8483d1b7d1072707378370e1ff46a17aa71b740362c03024868c9e554b9f9d9f695d4a0a65dc1733baeec6b2f5d42305d6b1dddd296bfcb5a5ae7a1479626196f1b2b7948dced62e40a3664136e1d2b6b7cf0bc5e3c31f5ca0fd28ddba703a2109a1752ebae92c3d9ed6214e40782fc125cbf80aa4a158c9551508d4c99569d668c8d7b583c91c2e80e9b8523b71caf234719fe8ced941ae932750a140bee88d35e0d76a2d822952d370c7b503d95999071355c8ea238e1c87b71680a4c728666825b8a7829229af00d431b11cee8c4e67d532d74b8b4a647a09e25fc87dc53acdfec98f959e67bad77cddd35b9e2c02f68c80b9e1dce0224483ed5aaf863b8e0a1e6afc1585e5ec2109ebd86c2e0aa7e2a9785f09a97ab7991bb63c7d5d9c5dcc6966b0326946bbef3793e8175040bc4dcdfd08e7d287c184b8a091316558784ff126fe118fa12978105dbadd24a98c7f46a6c29caf5b0992e184f971a386773ba188dc77ccb2ec0bd99c8503a176d8535b6934b65fae3c1da73c5f6f087b76532beae45970de61532aefac91868783d5eac28e4e37822bf1e7dfb718db5144fba4a7f7340c35be09f9a466f735d545562fc2f58cd3bd8c7984eb31a0eea9af6f8f3b8d3918cbe30d0dd1ed046c11e1e6f05153b86ab6cab39d2de3f3a11bd7950ed2c55d87545eacd43a9cc787b5315f7eb7c7dbc2e38a2c7a9007a025ffb0c9e1a4511296e7431028ae8f5fa6d7d56093a295c33d2797fab2c3ce7b79a52b081597ac1f376c5af084f1125608eddddb06de53f2c5943f107f60b96101b776fd9cf7951dff8dc4e0ae482eb6aaa7e995d36c262916e2106710e84425fd44ba3e6dc40c3d695675086dddc02bf6015b817b91ef5f3ce9085cf57bcfec6ccabf04f6875e0978bb87b89c8740bf31284c1678d41ed985a27ed8bd056a6369e90b74dbcd331a0f9b485e5699d63aeb051beace7f99cb716f973462c4678f1c4827ecafe890b5084799386a44760ad037b041a863c52982be70bb4efb3a4d045b40e13b5f8d7d38c1b4237b7c8096e44549d79ceeeb259ca93d6ba4984219c0594dba8edcf8e0cc9177f2d638c1e5cece4a85a5b05af4091d982975937e201dd7119a59d03893107213c646ee662ef19baaeb645a7918da950b72ec968ed9063c84a6285c75bd6dd741c437fa8d83a633ee690b3249b0e08365d72c5ef5cde257368c991f7a0e7a62a5ad74c835bab17f1987f53589675d07ad771b2681970b4e82202143821e64fb42fc473dea581dc00f3907a065e871b63b36893429bd261ba1ecd946a5c6fd526cb309285c5519b928798b92c1f073a795799be1031bb0ae3b6ac7c26a61d1c2ab2c7a816a1200f6cae1cfa3601db92732421c28fa0b59da4168a06d3925308885707af2e405a0d5101e98b1451d26cdcfce8d8ae6c7cc47f84426af864282a4b9d34f140b6f6841f9cfc8b96eebf073a64d63019cc2a95f25a29c10597eacd0db3b5124697bb0fdc17e32db65be5a0686ac5c53b3f128db50f6773091094d7d2c46cbc812efc977908f94f4f592e3b612552b5f17a3c48363239a4b5481df1c19852816099d6614a3bc566c35303c040e44abf83a53dce99b18a006a9d85711b240de8a8867e371ccba8ee2fb7cc4232f0046ab09a825791328a28b28479f6e249fba1300afaef3c1896e0b55012da5cd955d50ecbfc691893932c6c1cb11c17500839d6f2de8d440de41f05baddf2b23332e97c8a5bb8e401030e4cbb46160347a7987fa399743f09ea1e6ed009174e6ce4e230f9d84fe9e37669a8ab7cc2c51533eaad960b74a05ed1d7f7d015eac711a0085af0859872c524775db8b5ab01a9b0b98ce89d732be0c151a71d0b4cd0c8237160507e316f3ac92db457267a05c84b6103953a595ead162a50cefc1a87321c18777e0e1dd16fd9091df01ff58e7d724fb89311c3176902ccf0ec7f3592abdb2183692523c494e483cc9921a4addc1afbd8cfe459af415f7cd5fd6136985c04732bbe81c41d9488dfba1fa3e8b93976bf397d975732a5d4ce846ddb29f423a39abbce4a8fad1c0009dda2a45b60855d9df0f95650670cf2d69b2d8a61f983de7588d6e0589d29eafed6ff59e25746084589dd3fa5102c2130a0440499dfbd844bb6920909742c038a0d303665756c98a4e01739d45103e30b0189299e1e48bc2c33053a1aeb2d86848e13f2a541821c097ef91373c827966f870658d4034c67fe532249801f3d65217d7475d3572984f31cee826989228eef5b22c5845491849b6660f7c92e2ed4ebe0c9c9fd7b95bd0bda38eb0ba8250d6a79b9b2ca0b37b1bb53a9e9d404155e1b8303e74ed547d6a02e1c48d6ce8dfebca0a8270c418864e081187e10ec25d0b97ef9976b8c8a4f53bc3a4b846d853b5938d109bd8a4cfb215941cdb9b31595362788d5edbc366af009cd4df28662ba1cba000b3a43d841b40356a8ac581c7e197dd436811f99206112ec7409465a7b5861a594b38193f3d24305368ee0652d263aa33902f28ed7e6ff48b70bcec2d602ea9028c28eb05a34f420a130744ab4bcbc89c6b8cca5bc0b64f8f05d08c80854d64810c9d9cee36cc9bc2b10f0604cb022c15d063686e8722450fdf8735833e706a96845b6d5b48e0b0c684f70d5e39b97cf1fd0c81e08ffddc46f595aac8ac4b8ee1d010be7a4791234a422f9f2e3df424ec4c46891ce9c0f2f116883f4ca1ab02a63cd68e3d7adc22457ecfca918fe5eb25ca3a38548e83b638524c08d0f22c91086b542012a9ff50dcd107cb8190c5e515968764a849529f84f3e550dab7a8365d7e63955af5671941e99e29a01f2b6a66eff0b157724779b27c7bd05252e9452000e3fc6dfe14cf44f4caa6408001a6f3920a8d90c411a4f6a081432f852a7b35f54cac322f991d2411a46ca98daf415b10612f45880a7747a8900721c43c9172162ba6f04b711bf589bb1ebd13a792f42244718c5349740e9efd2021122f1b9ef2389e9c0971e2299fafb3afe3f52be8f9a85561c3671de78cbb03b3248d9e8c56e03dfe4b8e430d6d2f99f95e50fda1dc69f08c6e820914101ae48cf3a05440803f98725d74c56492f88ecd90e07e409aa94cf67229bbcf9803737b7410fb61b0f6c91a94ec1bc6e1998431056ef4f40185170d30f810692ecc156a1451dd9ef252a8b6426aa195c18fe9e237a5eef663aad210e1656afe1ea25f19b0350b1e7e488583659344f2f38756d48773818dea120998a5f3d0fa15954061a500f278ef43c84e5b28771f145f4120b882bb1124128a2bc3de6557898ee670d47a2803995021f33d984195f8ed40e4e2471030674eaafc3453713af5cfeeb1d475b85b00c5d8d7763aa5908272f19f3626a54380cabc25b943d999a18b6f0585d3b0769f64a0f8dbfea14b49a0c25b43d74b0c4d8652f690e2a91039bec5798ac8a54e22d6c2bafa03fed4a7cf649adb6c9697ea00ed19f9df0d2e4161aea097a3f9663a2a43e445cd12665d26e4576b0348935e99fe3e9ccb15a4ab083ea86f8a90cba53bd66b229b8ae93d6bbcd2d2ccf086af932498a33a4a281af1b725d9874d6d70fe38e315c5ec59545913e4f83cc6c2c21869b6803bc2f8e9503ce97d167bf8fb9e7a1f0f4f08b232191d8dc0542370bb953d838f0b3230f63c32eccfc82b995bde6a343b46c731d7479232c986c1c60d834c34d7e87c1ff860d6e994f4ce1ddeb0fec497c1d017740280c542093e6d27d0d673a8eb1a40ddb0d64e0fead811a3777a8f75e087d881f94bd28a278617decc4c410e275e81a7f06fd8272ff955d9ade9d281c24fa82062c0fa09863e5bfdcdceb16fae0768142e6fef3976ead0f0cd6c0beca1fbb41dfaef4aae14eb86a25a0fb9d2f1d70c09bf167fd069215c36efe345c3f60299d726dee5cd90df37f42657c69a2c6db2cb639bbc027be6bef959f5d708574ba312710614ad6ee47f6aa2b89791e8ff134607f016deb88ad3b100c49a065f6062e6ef9cacfc28097c3feac7cfe0592b642815de705bb178c88f54567aaa3cb76b6c106a3a1ff04b4cca2a9bafc3f8181172dcc72fed7f822760c920290d1a06e15282edd559f0af037d4aae632db830bd45a0cc130aa13d5a4af7ccef69a880e5ed6febfc5ce314b900eb074aa9770df3355ec9c9519f1810ed445d686a1387bf355a53ab8ef27b10ec13e45b82334af3e41aefdb0181218920227e95e7034f833b083195bd78636a9575b23998e80444fb526a0568a57bb20afcf4d584c02028cbc1d760851def0167fbcbae31e718052b1df96d6c7a01b927d10dc217c398a738b43595e8317d1b295cd507299800b3f73236f1c6540820fea994acfa1e142466197f632a8ed7a166bb1a288a13d52b8c097460a35dd8d3543a1162fe38c224dfe04a4732553a72a7cb31d4cdda6c24e5a9c09373c97fa4294b87edd8424969e1299e3ddd2be3eb10739dd5c9f1c7646131a62096a7f2cfbcc45d32ccd8aa435966590abcea105985331de19cf260875123e48e036c0d558e5170aed318f13b70a28ca55655e1fdb85c777957b2b6e75f10d442525dafe839a46ae12299c0cfc4694c4883199322bae0d752d8f20cdcbad6cb8b00053c333964c71a69dd5f4989ed422c6b512b6ee2be78a0936b507c1f2b05806adf76481b6e4856396c9994b1f307ecf631d5e2d4c7b3fa4adcd4810efd789eef1e70b562472abdc5fc77690eee9e8d1ea4e0766f4e56e007640da223fa6f295e04087c16f4fb9cf89e0b2d446bbcd7d2485812ed5c1db21e3dfec3f0f747c09d6f163f41fce474172fa2359fe23de4d5c72af14d57f826d5e16a2b23439d6f983336f2b076b07251cdd082953dbd97032a440167c4ffc539606fab913904098a19ffa024b560982ee9f8a3c93f743f857692207a4f733909fc07277e64a11c000cc029d6e4185beec04964c202920f7099bdc2ad82b76daea8d1029c90ea46a9c61fc096b202747f1576f1dcb0fccc1aa9b1a33d7112807c26b26dcaf57eb47786ca0b0064cd9f9a0e833125ff97fafe6a5c23a2c565276580f0910430dc2e21123d74dbde11545ceba84594af207f92d2a1810785cc3880ad3be08be90cc1821aa3177cc1d0e0733d078cbf3a5cfbce975f1fc899688535fb132401c264e81ad0c38349234f4c89b81cbca97f2faceb6149576fc662b70253ab4da8a6319a50faf74123b1a8dd2faca311355ea75e5d5006bd0182fbb7724ca94b8b8c9e8d0a05442862c8f7566cef706af56613e4f22195783f41aa329683448f6ef72f0b66c3d44408bb319c5e4db8e85683ae99b1a217e8e0140fc353b3da378410cf7af89a052763bd84d70863fe49335ff7021cb823f02fa4fed52c2022e37d42721ef60fa78a10411fc5d0a7bff3e6d8ef432380a2570f0bfcc3befad8c9ffc8655f18e08bcc0bf6d371de3084c287b4213e8b9cc81f3e6436f8fc039018a654057a68e3e34efc1aeef476e4454d6b53af27f1c0c7bd0914ae62eb68c4f487e148842a62d91d728ddb8f6b140b28555d67dc73a05d370215d293dfe47523d00e81d06957e52ad79f10b0200012145b47f506fea40f3d8c5f33c80e81931f2a7c269ef8ce03677a3e17e17f4f03e879d421e47aa64f0004433ae9e8efcb4ae29f8448f77f30c98a3261ca838b92ab01a36ba3765fcb1b964a7bb8b1cc62e85cbe0d61d64c5a27053d30f3378173e933244aa570f1cd9197480ff0fb2ac3a083cbfb6d55b853750f64e82adfa3db7a2c00277b6b59c782571bf26ea655f2a12c602f7bbee9d43726d7b30d00d4ef717873b2a93a8dc66d2a0f86226c99eada8ab6600fdc21b03fdfb2af0ea5d330a023e19803a0c934e273184ef7668cf980f294faf24af6555abe7d9029cb17493968617e7e981eb4e8aa9192c7902f0c478fef9f31a59a38777fe93037c5146186210b12abf6b8a7c13b8ef567b63bcf47221dbf1cf3855dda4be09f2ef18ef43634d002b5e1468194cabd9a4b6e0ebefe5d8923eebcf9c0ee17504382b2ff125e9dacce5a5feee9c9449a01cf9eaf9c561f91b760a61265a0061ffda06fea7f8713e3f2e62fabe212fd0262cab3f57deeedddfa9e1f6fb6e3444f8dd1ccb4c20c2d9d0ff53434371213b7e2e803cc96b20cb15207feaa7c60d97766fd93d49f000525b2f8e97826e2132e9a75f259229f7a37c34438bf12af7084dcbdd65461eec374a56b3ebc7e3203904f2386c01bf365f3f5b6f80ce8ca51450e399f91fbdc68705e28dae31363c8a81e29857a268a1f967e0baf5d3a18f417b0c5a265d2d2b44c7ae327bc6212c119cb85376a51099d3e77252115b807b9bff3c7ea4568400f71a0bb367cbf6aec3758c7bb4987a0d9264042ce08b0970bf92b622b1e264c09c0ee6a0fa30a377871a025c78392bf5f223432c5d1a67d32ebea96e66b7dbceace4802ca6dddc639f48904ffcd243ff07f001145555174a7fa6321fefeea1d20d53313d1fed47b475420cd49215959b7d82d1c3abe1ce20addf1290ab28571d49b4d29ee1f4083be76459486f7ad6b8ee2a77c128e7864c5a471413f50d066f6e7887070ea48c5eb08d099c1db4a3b46f008ae5a4f90d817d961984ef9f21e4fb0fb30d534ca11e57ec16dfca1fa3af94be9f705862442217200e26569296a6c4c9eb0d71776024cdba6ffdc5cfe039e15584a3b8fbada53782a31e926fd9c72aeeaee0ee575ff51f80148a5421f81ef6ef85e884d6ac93757bd348079d05d9744e1739324366ef9fbb53e2d19f5ebf26bbdad2e1687ce33958f46d87ff441467453b0b2a6b76856a85eea90a848e470f29cd26cda35f128eeabdf1108f6e3fd243a698b5ccc20e21e1369421ea1ecf4b9da392f0440c9cfb5bebe9938bd3b7ac4609710bd1b9c2a68722fcc09d95e58085420b84afcefc51048b4f1d509db83789df5b0239eaa427492d501b7fe1d267b9d13c2a1e114441b6909629cbdf9de2cfd8307610c52a7897c6f40593105db0306f8a62141454c0c23e3663c39127ab9f9ef5441c871096d853a31416b226ea5f72b034c86e9004fd14898286e14df57f46ee8b4dd25276aa9f8ac3b97f0f0d771be6352057b289dfc3a35b31d9dc89b7059af3b1b4db1d915206d7bc120dd313f07aa2fad46b0d652f4f4d276350e9bdc6a7b1668c4aeacd50a3f74132eb511665d3cf2dc53efa7f9b584f977df84eb57ede4a676bf79c323b35b5f9312a8d530fa932137d4dad5b6102b87462c656c3a6abb402f0d624d39d47f54a9f2ca43e364a757f270bd8979e9b8bef5aa999073488d113ba466918b8f980f117f48aef8edfadb2fbbb1095f5d1829fd486e200562d1f1aa0d5cfb120ad6952251ffab3f14c7ede4c0703adc85bf48129a8cef4835124688af1f6cce730c38a0418b16f30efa7fff581125dc188b89c2c9c4f7a15062548b90b8510aae7361c320c2aae17e33d22f544bcfd4139f06c182963ec421f5c34f282f9cd32601a0610af2eba62825f2df77d1b2d8ef779c14d494920ebc1e2e43b6d179fddcfd52acf0e7f613cb1b0ec620f6a18ec2afef53b6dc78d1dcd835bb22c50b9d8a1b7cb8b87484e5bcad3692011cb7096003daefd6288529614fee0c72af470cbada7b99979f50c6b38832a132c205e3fc6e671bfd6234c71234cd4a178d7c3ced167683722dc2cb734b5b68d01959ec35fd6c086527321189d887e7660444a1a957ad35bf7a29a83cda16b2150f1adf979c7b2f62a9263bc8912c899e5fcef41f6e02bc16a5f8fe507de1a3b5e1baf2fd9234ed9d49891341f6c3b0b01a01f5f453d994c4629572f89f8da8300be01e7964c322e1d43e86e7838cc3b08fa088786b98e278fd36d68a932e002c454a459884bcf9538e39e2a645a1e2ef8fa1325bb460015c5c830914ade9ad1a4af3222f9e4dd0aa2a0ed10281b246392cd2408ee7b066b221f9ad6b1ff67d1206b0d5db70b2dd39c87d61d962a3a170a591c59bae753c24e87c147faeacfa5dd5c5d9c6ec52f8976dc71c55cfd7e9f5c093fb92db0ddf44304cfd56bf3258e6a329225d19c1d91d0814768063a97eac770fe37d60a80859765962e73cc0551807cc947157fc52867d494b167e80ae6ea84ffe320c9c617ef4583791f1f746d6b0413fe8961ea7aa19746434ffb52eea8a27cc2f49f57e7d044beb83f8fbf7c0c6d8d70db5ec16d9fcf9716ad5317dab2e60f1855450c9f601871abe81b330e40ddb2606a456792d91bb3ee850eb36e1e3cd102bc1caeafdab95be1c466c5f52b64d252067eb7230b61959d29c6c9ca8416458fef1e95eec9357ab936f4acc073f02edeb05b0e2ecac65d1e3ee68ecbfd6b6bb0dc95c3eb53b3469f4292bb594de36eb062079eeef1cfc5c669b24bd5ebf1f71be6f1ab4c5e2ebb299117c460ad3199b2eceadf024e2b8eb4688c696fccd8d8bde0eefe6d0572ea6d0dd856bd655491ffc1a5e1dd5fc21b88af9c911f973d1f6e327caf2338953972838d5debb62c0d84dbea1acbbd57b1961388feab2c8581d0f4e711dd59aa0ab0b2bdaaec4a48fb37d34b44dd9d23c6d5aaab0d10ca3698d397ce18b053122e0e2549ac6fc6048ff0f7c57dd773b965313d2d8415a039cabb401f22da46bf80086a1aaac3dbef99f500bf40c296e4602f4b4ca2bbb9fb8b6bdc934c7a5e763949e19ee8e0e606f1ba66267182f6813920d7b2efc6160e68ff95b71133a2417bcaf7d26ec3a1313aa5566d7512038a7202046160c042732706c834a8027c97f31840e26b096fb329390fe30defebc9d688b7b56d12bf1392370e41abe274bda4e3dd6b8d596fd5cf9ab804ba429d184d6a2df4e20978a59634e6622c23efb1262635046ddeca1146cf0046fee29fb531800a8703ee505cecb0a8b7300492c2f1645125b7dd437dc841e584a84a306ec8b0648f777565731888269f30be29f3f6f40f0306283e8c38fcd0b0df3521374bc8f1ae714f915bb3a264c27ca531ccb27c4f9974e97c7153a75cc76b5c533f248119f0c936f7cdfc5bb716f25465689e33753bb41a724672630a3f34221770bd0e43d91bf2984e8b6592e196e985cda261530306d25808975b095fc761434e064e43a24c07ac3bafcce9800637d79068102ef869ab2a5c6385039746df0cc254f865c281fc2b18e9ce282c502d82c24bd27af47e8e6a8ba06fbd32c8451c72bc9f18e4d25ee5fdce3bcd362fe2e20eef677498cd78a87cb8cf20b43af3a322590dbff5770d41fc3eb33e917443a639c999b9dc8f7c21a72be8c29d642f7ad8654b19aa1b9af90d217c83246106aea75669cebf3bc32e0b56e0d6f9f53f2f2004ef19f53a42e13ae0d2b214e68fefde72fff8d1992766f4591f12c9829dadebc12e53c8a7dfa9fb151c17a7d704dcdc50b7453bfff4b7b1ba75d781b3f8ed14889f2e455ad3fbf0e5a318ac132d19735be1ef4d7232ef0aef0c540a967f02a8160ab01965f88d439d851cdfed1b2185d10c515ede81a5bd539910069cdf012db4170e7684568d25618923b70ee4db38a00562bf3373889674ed91a812d0729745547db4a953848022bbe7fbaabb0ed75a6e38d605081ed0aa60cf21ad8bf50ead25eb3a5ad470c68545253d2ce7894cd4ed8c2204f2d67ebea9d6e3c5f2bae72c4516c4a3259dca9579e685920ef64a3aa342e0ff00aa5523d3286ea31f50f6ed169947890a3e2b00c0d4ea5658513e2f4a972faa9dcdfa9e53a34dff194cd40c53fbd35efd4afcbba7898ffefdf1809009b32f95f8ee71ff6d3c3b1ac141a32a7e2d44b4e135028a127c4508721b7b72430f6df6c3f782651a12e8959fc493dc282a6deb2bc1588fa5a5ee451270323442af3ea7a7a69bb37f7e97fcfcbf61a9ba7b8887193af22f0a5763d4a454c12c21a516dcb11c0ebe24c07860f04194005778b3a57f610f73f2e1e809b79d16e5e9cd0b381f4973c8fe4b091766cdc50d88fd69deb6f8e06d7d2a9e0da43c2076ed295bbf395348946f45f186f5a9c1152d58b49d836e4646a2da920e5f761c64c4e332926203ad608e0a6338d0e41d1cf28b36128e2c12b260044169b2184d51718f4e9759858114ae00e0b74eb4547a68c09e5efcae8f92f100f44ef337a288084b1e1d870d3a50f51a832fca15dfa0c3671067bc6c1c5b833c12df1e016c810823b567becec469f0b4686b13bcd350b87432b056a7e03354c7bf21905a670caa4b6e7cb5bdeb30a3315208642df66d2e35ad33a1ed8b2da5b55855d359138c90df2a04bc2b5a4f5ed770faf381571b5d3cfe2cb3249ec4902cad3c6afdee3c1dc42254e27ae8197542c522572968f10b0de9425262627d3db01314ed712d00269a88401134254ad879bfe46a67a40b7e22efd38e2d45ab2032c2a39ebf1b69f7d137304a6e0f1a8faf9c19f5e4cf6f01f83ca5ba828c5f9303a16346859e07030a60972ba9fbab42512b7b9d985a13777839302b3861c91ecec4482c7bd20c74f3450c45635a20f1ad21c590ea378501333ce504164bf7a1a5a23bdd15655f39efa147e62ab05cbfac89a4733f6971bf4f4614b0bac41903eec4c09811191102810f045c286ebc42af132da406bf343ea07f3dd2e7ac0ee732ceeb53cb4542fd8d30096b1daff2f804ecf35a8b4243650ab3b289c7bf3f44951cbf89e88cccba5c300de287100af90ef48b875cfc7787ae73bd312a147b23354d2171d0b5617fad8091ab2e03fe18db81fcf115ad55f181bb15afec19e9375eee39638129c7e8d99e68ea0d29be920a5167fb0ba1e55f89468088565bb9e472179a680440d653dab8a802504daf53e1640fc072c0eab7a80ca7ab9c803b29c087cc253f0d4db110cda794e4d23cab100e52a90ad48907fc09fcc1efcee8b36b1148ee13044da4bb8606efab0ff141d3e9e98cf8a5217d15014a0cb648098ba18b7415ac8f478212815903c0ee221370cb0a610dba88bf8a27b230efc657494b4120781a08d4fe79166e316ddc3777a0f0563430eb78b8f706797302d26c0fc5c44887542812043bbf0cf3ebd6454d62d79b3f96cd0c4c93ce550c1eebc980075a2df669129677f58a2237f17db574934372c76106667dbd430e91a85e4eb3a772ecc210a9fc05d0b6672d8cd85382a28ff437a8811f22dba975a7d5862c474fe52f40456923dbadca57412698bd1d1ab93ec3bec4241fbd5c904cb310515893ae00edbfca1b06692bbc68fab07d9c5327ef66ee174fda49450e87e2a744b9d3bd56d1fe969789f80fe98ba29615d251fb29193847a65a95aa8f8f3f4045a5ca37de0c68ba57e81dea95a2c882a04be73f904fc50104090c0481248a110721a06a06387ddc37a157fb3b750347db60ffc775985dd9474a0f3cc8eb2e4f2291faca7ccc32784561a7ac5fad3b6b37cd38fa27655fb9e6cd557d14e46b658dc86bd97f08676d445e5026f836d36eda9c1174e3f4a32da511b75125bb8ae5c91e257f83f89aa8001d180ac0069c4edaa4dcdff8c165c314f2f68b3069e3fc21301ce74d3edfb01f0eb75fe27f6e0e3bb3f40adfd7c75e67c5e3a1c327e1a321933991801d142d3fe8a0d9d7691337210c421fdf3e85f893406a83d0c623ffe81cc7928ee543e7544f16bd0fef95b4668994817614458d059e94ae23f8d3376ec7ad0b8e8a8ed7bbb46911a941d7d43fd2ad06149798576b431a95e4dccd2c717f407343a57e93881cca40455a37a4cae093e7a800de1acc1f1b37020ead0def95f17132d15d60e6157541aa4c1a5d508943a1a673d4feb7360a2062e56744e875f258e1dda0450819f0ed25c145b60924cba90f7a5e3a4b28cee58e8bcac936618aae5ebee4527879fe95b2b0b22eff59dbae97aae1223878037fb5d825aab5e7705550a9f647a3e41416f986aa7197ccc2f837ed7e60953d3f602019ddabc1d196facc9c580571cdd2c0205e9cbe6c1e7c4299554aa20b3797a3614b4aa12d19657b7847de99bbeedf5405fcacdf1aed9290978450cc04f8ff30cdfd111c217495f7082aabc41ef4c2a1f170da820e8a2f2ee013413fe98c81f912b35ab5f84a1e3e901efc746d42e6a8b204dd09027f7bcbec1800f4117984e98bd4707b519606e01c7681538387ffb2666c4eae4658845f021712bb79969274a0f97d1c982353807231e1bdd4c9c7e8ab7387a5412cf1c5c8423cdb28e890af78802cd178522c798d2bde8698ffb6ef426c79174013ad269487a06fee2dc0ba92fa83121a97248b1b216a80133cd5679f779fd1b68f0315c63f8222cfdecac176c24f829d2f287ce93f9db4a464bf66f73fe021e82594eb3e401d28fb1b16334382434f7187b7b74c280219ddd1fee2b889b4381716440755da169088b3a44ec62198504b0608dacabe31fbe8192eb1bda4f20cdf164c965c34269eabbce991c099ce1096a32cf90f7db050c726f68688d2a7f7f14615ad842079dd48601843545e2281c986b1a79e056865c7e15b2635f0fbf20c882aa5972c25c08d1b4fb9aef39767771d34a408842592e02f2b368d3b7888c7d11988ee8c51dafc04f9443a81167e7a01d686f19d841fe1ae52809b8391c426f960ce947a897214389d93e93a3777510355a7f8559c96a7b1a7cc26f9e76d67ada3c1db8f90f9dcb15727e4341812b74a32e5fd6b78a9fb294a9ab29d2af034c96d303fd34255771945bb0fc7eeb238dd4ede69d2d0f50ae73a6885d0b41318394350ce9ba33afd660ff76df0fe06bd3fe2a6f7bb65f9f67b8ed259cfcd03c337e03e0aee1d085139a33c436a402caa23a685db81f743ee932178f2c45fe2877238468f639d1885e9fd3c93dd66c2d7214cd72c3dc7f66f56a29a471ae4ec35b1940a5f827af286adeae98d0ceb0429722faf94534418eb2e44d6356fdb592d29b1a6a86ed1de06713701d129ade08c238996ff75f9c569014283927a479fda624f2379aea1bc4bcd9683dbf9e42e2560cfb8fd22102ba030beeb8bc1948fd54a2b74752c9bc770502b6ed4db8f6e0fbc6543eed5bc6f3de4c035773ed860db1053106be551f2852dc514a3d1670f5a0ddf2e1eee7d3590ce6b62ebebf5888293253a95d0636f2eb28c354224a00a85599187d4ee06bb314ae573b0c3a12639abbe04c2404e8e566919e213bd18a26e15c9bc966960bfc8da7a32e374f2e1dd35f78650d570e678c9bb65d818f34e4f1dbdf2b816dd08a51535324e611a8554d2250258e4b750c75e11d530e6443fec00526984a9759c56b2a9f3089fb3ce8f2612bb5d388731b404930b0fc64a9db1f8f65c07057634c71f4eb70bdb1250c4fde6fee0ebf083e2590041128bcf98caa480311f73fe9ec3e20a7220ae1d2d5d2aa921cdb5d33806eeb10f18b837a71247310c2ea7f9bee8fb1bcc3dcb90e5758292482a45f87f6c572386c6e3701fb824b840260178dcf12376040c086687a8c9af0a39f8f4b1ccdf3a74d279436020ee031e483e0d9674e517f53d382776044fa98140a04435c65660a92d7d3b58c2553f90e84b9ea609a6093f60e0a9a891f014ab704cc581c85099a248e6677ca638af0d60e5f2d9da5cfe6dfc918c055e64760d78d85ff102ae4f54bd2fa3b67dcfa499931c7946455758d9a29006a88b139e915dc51bc7e16060a37b7b0347f4a89526933cc28d944cf826deba6c0ab24cf87a74b501b7cf6dd4e780036b2b6c548c0f5098e52e9a036a7928b2631b240caa58dd34b89d8688ef091a6b0585b388cd1326464f09809434c216d1f628e2f21c2e0e10f78b8403bf890acfde8f0a1b38755ac5e926e708dfef160ba87983f010a654ed667d11ef6463e1ec921a2ae204df4a792da6752073b6716eb215d40f5a1b19e68353fc00e4db74c3ad9ac8a38f158690305a196b75ecc2339f27b074ca64a7328d68010bbc75d9c385a474ff36b8dd9ac325fe6d387515fb2dbcd76d576165e1db47a3ef75cc4cd3398f20da57a0132edf9be9a22a74451d4649959dec7be671d219099b0566501f997aec122eb3d22c34581c141cc818b53a696db650394a2785afdc725ec73d379111ebab0c1a292265d3599e5d4c87fd2d571a0cb563b5760882f20b048f6e684059a379d13b31e6b65890113748327897d3c1fa07348e0c3841f99b44d64462f496bd6eb4bd9159b3ae7a318df2a06d96f80dc9302cebc0678d141020e3c5a0caccf61a9bb2af58a4def44f01b89f0d619d0a43ee455f4bb9636ba2e1f6fa2b6dcb4953fa5222fc0ea08dd36ea9a5ccff18dcd48e7ee2a0a8577afd9d012ad1cba1a5c0c26b1b546d411af7b22befd517523b06e4a173eaa0a4675d1675a884f9ab87d4402f7abf22218ee42e5ce040b5599ab7bf52ee1d74cdf439280026e80e3ec1240eef68d527ce6ccf6c97ceb8e796ef745e092996702bd74a27830c3aa0d2ca1e9df0d97e0be68f1f9b42397a56bb75551c1eda75c6c03e40c55b4aa3f30115bb1ced70b5403110dfa02ef1d1c579b1c11db2aeb2bc94af949a824b6215ad260bf48eb0c9fae460c8e85ca0b4bbe927e8e84b879c6d91943201834d405786e6818d00030dd30267b014ba3a4d592d3c0ea842c32a6484612aea1ad2ab6bf8ed226583a65164edea9f7950c596637bd5850ccee4becbad08d627740787d48233b06c6df21772225900192f21d7f525deb4a3c43b13a19a41e70682632e4d6db6396febc25c8dad39ae2c165889b7d60beea3c038f7fa974390d970a36771132f1bece686dcb47537f047d6c39d4d513ed0815103f4449df05f0d26798ba336077fb1179dc91e0d93c02f4762c319f8838be321fe8472ae6a1f5c9ef619dba1825f72cc6008c808d60b37c7b13e80ae5e74dfd190fe0a68db24dcc7a3e1fdb553c9e5b0af587cc67f608b34a508617f753ff339af40dfc819834099584fb0029cb35b6228dd52b2313f2d83acbb12335b583cfb16dc85a7ca0d07e4aa47f4c8217f5a3bd41e5c41d163f2439579406c9c7c1b3fcd41b4d9198c515c09392210b782ea26d01f4dafdf8c016162057e6154a6467f2eb3fe90075bbe98399fb7d0fb56b593dbc947dda443a30f02171522cf7d921e50207a95a146452b0f4c5c13911e9e8bc496bd60f47589d7af8cf2ee196ebf128eaf16b05a9525d2d8edbeb33ac0d352d18b94835a9a62d727153f8ae1ca733fb8e40f6016aeea7488212f39054a3b284d5ea0b3cb900af1718068da06d4da01612f53c5125d6f7b386a1c5b48c778f7656b3556645ee3e959775ed656bbffaeeafb39d59baec1501118a0670ce6d819948d02fd3275a1093e613754c6ce71ffa03e98e8e49c0d0c667678b52bca684425f0e1ba66244a1bf730fc3fdab78a6d4e179992609a7458c5a19961d3a264ba35d01cc04e7a52c29b59527eb458d3a446b69e07505657c1f13facf7c34a933e50e18279cf7d7a7837492dab88e4bcb7d28389b6582cae7b5e0e041cb929c0ec7f0685706af98dc4a0cbf33a7983555f06712ccc37e4be7dcfb4a9ad240b522eafc38852c303456a02b40a2f91856976ee5845f81b38d7e2cbc1cfa512016fea9daaffdacf6896fcda6cbebe5e173494df7c77576118ea0b0ab65460c1f2378195fb56911e65c37cd8bf59b857bd488262fb4b5a893c993cf4de64ee96e9eb6a0be70fb4eccb545a0b244bf1a699f48b54b9c82b004aa48612bf2eac713f6400ccda45a6ba43bcc7a6e9556962f15671862548d26d5cb385f82eb7433be076c06fc80025dc040f12853494941735613d314d165228f61a34014717cff7aec125a3f255f2bb08301da5274102e4a7a569384e8031f0324dc3927e329e0440c48a1056033c0f4cbc77fd481c0eb57ef215aa85a376cf34e9121c84d80f15a449fe26b8f13d2acaa5cd11e5d42e3495188f72c39de16009f476f0042527f9996eaff2136a3146b1c9472be40d4c3790efdb8eeded3a810377c70507ccd3451db0ff6c5675728c8751e1e621d76372e5c259c7310eef41cf6423d89a93ef5327bcbf8660e7d762a55e7dbc2467cf2629098fc5f723bb3004eb8e034bdef45448ed694fe58b9ff933047b20059982615741a5eaa4a991f8ec0128bfcde32d6a7c37d28365991f815fb4c45c918ca1518cbea30dac226bd272baa75f36a1d2238163ba5c8e6b18ae82e42b8d520bcda77f8e27a0bf06e683973beac56cf7317c31ac305095491d2252084eb89549fb015cf4ea33b15ff247ccb8cf0a8fc54640290f94fba867e66e2eb3367f070b99cc432ade3fe18e00351a2b2527377acdc9424d897812d3387d3180f1276bb9856cbb1e2c14df875a862cc3e7eb5f84ac1aa40559f7a21292f90d5f3df01b737a8789b97963b4b2475faf124d8edbac2f465863ae1f59f7d57da65a9b2d8ad397343a1f05c3e7d78e193e920e8688d57341f5b16d97b71d200a95c87e5e2017799e64e492d53321c3381ab01738c4f3fd067cbfc406206d2e07c59ea18e1e22f0ca1fb8d7cf8391eebde8551150fd3ca58d6f768a2ca08047ff3c87b57b03aac1dfeeabcc36559928fa58bb8b2e9fae422f53a028640bca6af4ea8e27adbb23fd52813d86da478652e7e704cc141e66c37522ec64707a4fe82cf1d94ae712c42d6aa6291907fa02cd26a287359d0352fc7d6193bb3c04ff483ff8ad89755f205938d52ca43f55bb3e6f8959b91789149afceaa116a774b4ccb013c6d7e31f951ed705d6ea87324f2ca991ba1bc9cd889e6736dd725f7ba60b191ca0d15c2c95bb1b97a0bfb614b7b7d4de369aae742f65b34436490a7cb24330c585d0d7096e3e192a7a242ea1182bf99aba952bb7c1b99715961d550586310fdb1929d709a167aedb3fe69fc2c285298bff0e642c2b5546fd6186aa34df5e4b48154050b1e4a7ddbfff762a7421f6739dde08a4cba8574606077eb7e00e311a2094fbb9f2abf63b018864092a6594b595075ff4eee357eea837e38a8d72a3fabac7182a2eef2a48a86a0580db935605c44b57232aa2aa80892ad7a4097467b33c2ed31cd404dd03867f63ef6491990322196c0b2d0badc990f236de84071ed8e75c60ec78bb016a572f1645853a82a6e403dbab4ab0e3a6acd6c2e1186de1dc4aba0086c7a9291e0c9cc52d37216a3feabd26e6192600aa74b2ef783c25cbfa619bf741b9e768f0a546afe7c9554b73a574308fc69d6e58305746fea774d7e85a86be24e48d428353f8d7b725d6ad576ce3c800cf11ab6c5da4ee2852f5510bdfd3bdc7024a6ec7b239c9487a76f4b677fc6b143ef2c24a39a7aff87375a050449b2955bd3f28f1ead218580c63d559510986012f2402a23ac99cfbb82dfcea84ad0a8bcaf76e56718e345a4bb8317d258bf88d53c3dc682440e40dd57d6c05ccc3ee3763ca581c7e3279f5946bb9c59a0acd94f7f5ee8887aa218915704f5ba4c6c30cf2c4ba76adeb4cdb81adfe1d2948d988f8c99aafaaf0d2b3609d349af759239636be83753e3b560a518b54f70d29133de5eaeedf6c55e0c041176de8b803e633401fb9210bc530cb1d0c48f68ba874141bbb6c3ec5eda20effbbae614615ca2df7b7fd089394fd21990feb414b9fca47891b1e6bac36f94412d08e226ac8102b907b2dc9f06590fa16650272dd19bf8462763c55445e1a3f4b568f911609f5b204da77da36c3fb0f6b74eedeecf6c9e1560d01b1109e72b0b15421ce266cb4b494a88b7923c2882fc6e86bae55402fae2281326c2edab9ec192f6db9020211bd4e497b9b940331a8c84afb70bdf0396a496e6bad75e22bc07f7ad3f51944986c04f1941569dfd03f001e34b09c8224ff4d4b46e9c1cc7d93e9181394ca519d67b925ddfe8845d54fa298c0bf45a84d6a6d0cf3b74650420360a939693ba1d9afab123a812156058e4fd0d215752d6b73b9766ce650422e2feacce56c488eb88e637f93a9d60d0b8bf10d08474d0d6c287e09acffb9f2e1c27fcdeab72d979c1f84440251818daa09e9f43ae16077128dfba5e6aa14cd55e4b25fb41ef40208e523ea43d6f024a7adb0986ea9f17cb35f58c291bc9752d41b5d1f2a2dd16e4f77c49a3aa2bc8a8be126856b1dd4c27e2c3248dd8706a220e0b060a4099d2d9a4c3c8b1422f10ca7a49cb289602d30a0ab55c4552925bc9e3c920fe4b55109b25a4f7850b964a97c662b4001ac00bec815e08211c9b9887bf1779a653f950fb36b857b610d0030e809eab35c91889c7ede961d6cc76564a02ed8021700eb47940d4097361ef412c5a2e562e563e351993ed9fcf941e38fcd3aa7184318fe293c3cca26a83b0bb1c286dd1fdcce124bd587897081ba762afd91312265fc3b174f45974c58940c58fa68a46656e27ead1d90e708b20fce15d027f173fab9ffdff117bd473041cd90958aec82326e997efaf1b96112986d7f9e61c70c2256efe3b22cab419caf841a69357589d69c601599348354bf4675cf0a85ff7f43d9997312e29e45a0659bb37fb299e479fcdec3fd1a8520043dd94e8223197a03960baeeb6635472417c914315e039802e185a1de02441c05be8fc4c10e56105086b63918d6c7c60eeb6363877547db62a3bc4d3cddc06f798cd1277b3ab8db727723befffe3a7af11d025ce47ac3629c399bc8b2ae54efaa67792934a7cf97975a45e156f05242aebad99aedaeedeede52a62403400ee50dfa0eb623487c70c004ce661fc9e94467b3a7a521f961a2019ca5d5240ca10752b6f1b36f2dede7055080b2b5b8e2a88a0d095865ab2e2385c97d2489eb081503741248f0029ccd7e8d016cf6ed8924885a0c94584114487076cb119870b6fb5dab76083252b2776d2f12c6aa935e778219e248206a5d42aeb508b5cacafa87e19582c2518b04f39b08ef94328269d55753535252566dbb565c726aa16ebfa00695e65230a8b39e41eda8ae7597ec525dbc2ca1a4b25b79be5db255149cf0b2cb35084cc85e6d8b47ed692694547b9bbe842f5b09909e4992f742d0bdd049d3c3210e4cd4a79829d00bf9ec73154320d065e071f48aff1f4ecd30147a1af1fcfe3b871cbd0ff403d35f04a293bff799f7e99d5dcf3f8ed6c47751bcf9c7d1cbf3f3133e8851472f1a7edf87f2841ee879df1982de091ea8ca2e7ac3d0f3c865ac3c26a8f359ea8139307795634a0294f27dd54959b9ec6fc5ca94ecd67aaef6a45dfbebaf27eae80f4ff7f9e34d76c94cd1fc6351479dc7fefca03f55308ba83d3d3dfe3f9e437de6b4b675ae4e30d3f0aa88a51ad4be547d8aa83dfea3eb6c8d01c237df3c3d29213054186af6ac6a8f7b5d7c96a66e25e39ef2f8a9c7c551ef62b9641c08d62fdf26a75e944735e5681747fd5dd8abca99f56b76995e94a555294b33b2f97b53565bb2a75e14e99e7328eff11c06ccaba55a7320b287578e7aeeda931a74b34f5927661a5ebdc59e97634a3253d41261d6fece39a61b5e894896e6b92ab3342fca0bafbc290be6d0d03a810ad95d88ecee6e65998490c14fd11c545a3865657edfed0fb2db2264b74bc8855396165eb9cc3ffcc2aba9f02abb877382998239d00b78055ad51e0f99f214aa18448b4baa98735af8fe602e2abb37038f0b0fb27b37c8fe22113f1095783a88a27a3508a550833c1984575df3b4b48f7f109c6c41caeed920fba72210fd5e94cffab4ef7db5d6ec79298aa6e1edeab6e59985eb4f5938168e7554bfe65b6bad157bd9b272b9aef83e19253254fe25eddc76083395712b97e17f75e57ee528ea6d873059df99757aae663b8429da38ead65a6badb5d6e644d173ee61e7aa78f1daf47dff0782f65a2539f762656bb55fbfd3adbc50b9955ff917f7d204b732612ed5141eaf9e617be39d5ddb6d470f57cfd6dc5c8dd05d4cff7a866958b1648bc562c9f6eb2effb09eb5b61b08e8e70745ade779e72e5f1bf9c7bd9ee779a1cf52986c6152dcb6d6faf09993d65a4b86b5dafa83dc1e8f23cff7ec289b47e557083aaaa3dcfbc20f64b158e5df07c151243560ee706fd1ddc1511f4bd2b57ce148d280acac86d5ac32f52bfaea2c4132ebef65e1a29b6f47f52eca843d0dc82d6f297e4c817768b5583031d6a7f8919582c52ac73216fbf2c732f6acf2168b855e79de5ac2945e8a1bb252e0fbb1ee591343ab759261c882b1ee0b9b564c4fc127e21d82f82cc81d4911b7c0243fad5564df56ebbfd6dff2d66a3968037a0ac6f1ac5df30e3e13df1f88cfc6f70f5274f378d6c4c0e2e1e6fb290847ffce1d58600271d4adeb50f45f46c68176f0962aad9904deb0d65ab97855e94df2b86467ba48de4daa954b05c6bf5fc3fab1da214c2773f8acf5fe361081ad91f597c53ad3f14df25938bd99f5faf1b4ac4b03ccdf9ff9d7f8459e4d183cbec693848df89ae585fd785ef361a3dff11ba96be48f974566d61973c933ed568a928631c34a18547c0b4c6a2eaff27673a4f871acaf37f1ebadccbf84f97bc9677db3ba2aa76452d7609e84d5d04073a69e3a8c4c43d809037b180ca7373fcda7187f987fcd87f914e692cf3ac9b306e65f3ffe8fa5fd78cf1407eb2f0dacbff7c9f3ded7082b61a8f97bfeb80ffb57cdebc686ac21c99b33bdf9f5296cceb495f2abe695c299f278b19761602e0cec759aa6f9437626e655905f8a37ef3d491679599fe2ef99c2c633edd1922a70cd5eded3b434f1cbf3c7d2c47328f63267579fd15c4f9e30f26160cef4e60b033b7f90cf7a983385b9e4c37c2d6760dd7fc1dcb3e6f5e68f1fbb6fb2605e050d0be661e39b250cacff0173a6ed2a692033eb73388c8a33c5195364f37d18eb7e6c1cbfc78f95b771ac39bf706792c5f2f2c55e663d2bbf7065e148f1ac146fbe706af4434e3e4ec93cdaf246de3753c018c1a468a56cfe906dbd89c177e123d749e57e7535979c83353eeb5f258efb25f9e38f23ebba2e7971dc9165455c43bdd1394705727f481a0463a2188fa878ef9d451103a96788a454ffc54f6d7dfb6957a9a723d9d1cb5bf5af4121aeb536a4b36d2847fd53fb0d55a5ad4079dfb58add4121e5ca825c7725d8e5d14b01542d397c3bc4d9440b91edf3705a23b9cc3f74db4df6c9b6ba267e4a664b25dbf76aada9549f7ba6e109a4a3b27786675d62d6b4abd0200ff972ea48559490905ee0623d00380d3399cf2f0a6698f67b5f772580ca60f86d94eb90fdf07df7bf6757b1ed50aeab52e5892c561cc9955cca9521ccb487aaf8771524abc4547ac1964c360966fd29aaaa1c9f07b4f37ec63bbbd6baadf556f7bc7aad3675aff551d38618a8b2c42e572c4b34f1e48a85045e72356b1daa4e348ca08a656ccdc82fc2a94af5428d5cbff6a7b45cffa7d664689f4ae3616540e98a6c1fd75a6fa933f5a6ce5e6f65603e7d65cbca293ea66b6d05d6ae1a42b54fbffd01fae1b9112307ec6367ea399833750f10b54fd770e84f71a69ea36bb0f36582a20d4409c0a142b1a2bc71efbdf7de7befbdf7de7befbdf7de7befbdf71e3552bd2fdb1257df388bad3d53f0ec5d4389ee32475db35d6b2b00e85ae7daa76bfdd43edd357b3e91dbb3076a4fd720f76fc9fd2edc2ba8687f0b97cd82dc4fc62037142fc84d78a006b50a6a4f77adafb44fbf96ec442e6707b91f24bb84212707470738383739b8b9b199b2b1a9c1414d0dcd0d6868666c30332303858c8c8a1aa8501143839898d813b1188c140c4c8a19a4480193010cf68ac1eb656a314d170c5caed60b5aadd20565494691e4d8827164b180c5129d10c5304b18824d80e0c7c4f77958b2777b97ef5d410db2d6aaa0063954a7e046670b22f9cb56829da37dc5d1de9d0de5684d0cac472244667dfdc202331c712afef82979bff7c00fafbd81697f7cef26dcba9c297e15dfbe1432db6fffb106fc9a3fbfb93a855f43f1acf1d6133f3eb3b4f07f2aee0809d7501d7545cb4f0cdc910ccadac04cfb29b7cebbba4ad515ea04a369696d822aebc712ba20f73fd1a609557bda6c322dd0e50252505566698dbb27685b4c196b0d13f6f66f98150b0670d905738bf957fbb2dfd93f8bb68a54b803af22206486596b613058ad7e85d5b7150613dffe285a11068359d1dab6229daef88eedbf88d317fe9e608a5f21401e29791b15fb495ce54d14ada5023b7fd887518100e9e4ddeb97b42571ddf7b395305f2fe2f465f6ecbaa335d63bcb74346c3fc78a4d47c5eff2268a40c86c675e2634557c8c9731583c3a76bd88fd2d4e710ce2fb59c6e0ef3a7fd411a79d79f09c1ec9459e9dbeaf58141dd7c440925fb3ad89a1fce174bffc9a819019763a7d678d7fb5912eeb1a7f5b06aa7466da566d556764ce34cca6795aa98839ad62478861f2e8be92b7795f82a75c77b9ee9620421e9db4f2726515fa94dcde14923ec5ca9b7c967ace93b06a2fad14ef250ce9689ff60866eaba9691de6c45d1753e4bc5777dcb78fd10bfbe23591a10b5a5d0b326d499aba2fdfdb6df6f642e04ae020d14526426d4a016d93efd2b868882e8ba3e537fd7a7feb0af46d987dcd4f535387272fd9c5cdf75f5ac6697aeb33de7b3b43f57996971bb07ccc6595ad8542db655387a476a6eb09ef53506b83f787fbfdaea7b6f64f3701d5f2cccba72a6378bb58441c435372a16a72c597c2c4ebbdc968553a3cc12d2b96271ba922fae3140f883ad9644e0dfb3c6867ba446fc6af3ce1ada76bfdabe37b219d9c273c8ed10cc3434b19d32d3de49595a5865fd4d5565fd69ef9aaa2f4095d3f085c433b216c74afdcffe17c7f03e81eaf9837f8080f04ffdf407c867f5043a7f6238ea9dff07a80254dc16d1bacfe5a63099303a52bedbfdd65a6badb5d65a8ff4f0a77319fef6c84ccd244198ff7d498030edf7e7d4ace9afd97ee71ad767377d2f18477777777777f7cfbbd6bab5d6dddddd1d7477ef7eadb55aefb6351cab8ca3b7d7570c3fadf56d3dc1cfbbd67b14433bb692f9171b798b2d18ab4efa59d599f54145a7bc5c3da9ec6f7de03d51a1ec0080b0533ebb67cd06cc296ba96a90e5627f506b0d557dfcbf494667de5cf61f1b84f1533395f128f4a632d9a372d4dffb9a6bb75cc9fe1789c9699d25e76fb9f8ac6221c114bfdfbbab94fdb39e47f9acc6cc308e7a8d41762d8e84f93d599a9dfa7496e651764ac6f3a87c9686cefab186b67955accc9f704d0d6d13bfc600e2b39e758aa7d764651e1797f9933036323a3c39f5a8bcaf38edd359993fcaf33a3236264c986d11ccf48bb25566fae9b27ffa4565ffefe79e5fe7fa1e95a535d40f8afecbc898a6134c7fc1e92ea83dfea3b51ef81787f7867f311032b75785cec5bb7c5e3cca31604ef994a350b527c465ebc44c7fb2bbd75b1acaa12c959dba8159f37df57c763f1b475d06a97f5ac9a360507b5c507dfc1b7b5413b33fb553afe3a84dfaac5e5270aa2968c9154b125c320bb93221821364223508f62e92304cf2c5f2c67ab184c1338bacdf4bd49a8c0c54086acdc64604df3eee81984fdb04b9760a72fd76a20699ad447f20571d0d1c516b3aa8940ad41aca0325d7ef226a8da77dfcbbc94f2bf505728d926b3b69a41e22d76f216a2d46fbf87712206a0da86b135a0ab5fb41183fad564cc8b542a14621d74f6b1572fdea968c7baa0766cb744dc8a66b43dfb51774ba0680b7c9791cb46b32b44fd772b48fdbd03e31806e501b9e9a991b36db17ea1a8fa1aef9689faeedd03e40dac71f0bfd2ee74c1de794a16b417274ada87d88b4cf54fbf8df68b191aa8182e69cda32e4c6e2d135bfe2a36bbedba16b9e0548d73caaaf507996aa28ff205d732d455d73a9f6f1af39145df3a9f699ea9a9ba0faf86bb1723741d6c11813b8dc39a61ddd8e149fd1e09eacccea2a776aab526b3592586769a22ef7c398d50c5be38ff6c7a7d6393ed92fcff129f799da44d51efb2cdcb5c7be88435cfb234b18c26c86d97fa8ac88a48dc0f00789b1eaa42c72f5bd233ac64aea8252a014b8059c82e1267b3338c2f3ce18ab18ab8cb303a56a8f8353de8db102b7e47e0f9c02a51cc5d9ddf7ee89b3c3d981542c7249c6b1dd8158873165dababb5f6b43bf37f43c128ab7fa43981163d501a39e6afdf41b2f6e5b8853e42f392547242b6b6a75695965ffdbaacad1a2ca39ea9e57ab55eeaf1888b5ca5fe8c1f2775585cb9e1552f63ccf7bd2627ade077edff7ca61f88121088252366a973387dc11c95199e75d8fb457a699478f0cb12b731975d9471dabab6dc13047a5f226e6b287b57a5ef5c27a8e4a8efac8947d4472d4736d6511b3acacec7b82699f720a466507df62990b3ed1c027f029bb8f4839b553585f5c863febca5177e5aeb2bf4b8acfc2cff98cc9753eebf06944cafe212e338864af72385d0e53b02987e76dda92533b25bb7775aea6fe5234611c5d892b49cd5c6bedae5dabe7f5bd2018dafccbc0c8c0d8985d6bedaa83a26ff3363a32b5d65abbcdd39574aded4a5c49bf109cdce7cdd55875521955b2d7b6019f683bda2b26ceae0685ae29ae27476ff2f53e65b1846d72be670f55ed418119669c5ded71d793cf5250ca7a3d545372ff536e57932b0339f72b032c8b25f08994c552f6b4076797bd21dd4375effdd4d574032783382730db9ec04c5d4d6d6393bdd3d5547bfcc6d5943d5f57151955ac8c55878afd5a5343f9ac272a4fd61355fb35e147adca4636239b8bf74cfb087c163e62fde7c51452af72b5955fe25a5d84a7a3df596d602a93bd8c0146fede8666fdf5d9f72c6cde90882cb4e0077ed6ba6d6b6d2d5be3c983b58da07fe18b57c4b5fa781fe28cc3e67b5e2adf175d6ba9f050ad3d85d8fc799f57bdefbbc0585b307f2c8d75374d776bed597f4e30d61bfd2007bc64f0cbbf6389c791f5ac1f9f7502c0d121fc82a3b70593cbafaeaf8ca11f7cafc431fef8d765dffc71f4c6d11b0243cdb5af8796bca607f3c98036e18b3a2c74e4217fca18ad0c43cd408ede2f7265186a16ba5230d32ac5c3f5f7738c3a6a50cd8d311d42400d62fdbd48b2f823eb6f79135f9e287e8d2c72804b6e3d090507b2e4f249337b67da1f900cc2f0250dad73c88e3f46ef4cc7b3ff7b16f6ca770c04a6a63c6f944ffebdf7de3b8af8873ff92edc250ef24b277fc8c3ef49d6dfa83d60bb7ec4a9f7adeff286f7ac16c6acf24beffcca5a9e178b583860257b4f852db9e61abef7e1fff0eeec5a6fb7a33dc1d0b3a31d4f1b86ad4fc9af4a660d8ed7d7afa75126dffef8c2a6896fb57e2d6fd8ecc243baf68c5f347ec5e90ff0bd2f5dbe6cc9153c6b70b857debcd1bdbe2cf9ba515f2f5c83a3feeb5f675ae37dcd691be5b17ee98dcef5eb8dceafd739be896f636b2ccb1f9d7461f259cec29e2babf4ec8aa1a3f0ec9f90ce9f90f6568a24830fa6a11024d9fb11a7ac07bfc43fc81be4f835b2f7e378fe08fa7b21f63faf0d1dbd61bf55ccd25873787f53249072e7ce588eb83aa22a7f34787fcfd34397f9ebd825f89beefed77a97f67d7d19cfd90f1f0982c3e17036afbc796fed7f58c9dba8f4bb131b6869c193f1bec04c7f7e4cf0de5de760ac3aee2ca89ee7e0e749c06180eb42762d6c1ffb5f48f39dfede8fee7fcf5bc45875b298f6ac325d23a9989ee95d26a018258e9d6c86f776770ca0f000978ce6ca840798727d7da3ab5f03a6fdfac3fb2224ccebb3b4060971dd0eeb0cdf835edf8ec27d7b4bb206d59cdab77fbdefb4e50cf62f0f6de47543b51266bde0f7fd1f5dbdd04b32ebd75df6bc33fdbea845af6b4fdb7ccf113c41e5d167c8150b0932837f9f46fe3ca4d10fefc9ecffc3c553bd4f9e2ae38d91af9873f456efd7d78ced3bd3ae62cf6a7b9775392698e4930cde6738434eeeb375fe6dbffb610d7e83dff6c57426bfaa8c2473a57595f97712665bb517a7e5a890ee4dc2d1dbe46456dbb5cbb264959fba2e27c5674e811af4fdfdfedafbde2a67e8cf3f6f91adabddb7764d29c9912c827de74ed8b7877797bf33c443c2a2ce20e8ead3afec5c1f86a6e9fa54e6b2de7596c63adbcacaee87a169cac8b455edb9bf04d3fcb4ada4d420fbb7d614f5d54de5a1fd21ef299fddefcb1fb2430e56189c02bfce21dee7c2433aa7aeebe2b3dbe47f3b177ad93a9fe96030d8d9ba10d7dc2f93657ada3926476feb1cbd2126bf96ee6ad7e5fb7edfa5987fbf99746368ad7562fd0ffb45edf8c787a31f14e2cae1b3ca19fa41219dad6d11e40b759d5a4f6b9dd5654f32df9ba90cd9495c187c49bfb2be50e42b9e66edb16dfbcb80197ed6eb4bfacc3a954753c5c411520eca9589245a720d1ad25f6b8f91fbf5bc7b3d9d7ced5b9edae33b21ae967cc938b932b1644bd6e57e0f29e5b919fcb16b8f4ef6f0839f38b3c94532b9f545379750d97edab99f40f79e303b7f0bd7dad3faf24710ebe4108fffe11ae29074146ca5fdf7c9af89813584879b6bedb95f4f7b7a390378ced09ff7e10cde8367dfff7ef47bff7dfae1cf3b3d2690bc274cfbcde368fda2ce4db6064c21aedcb5a73ba4c1e82bc81230c265ff7bbfefbbdff7a537fce1d5dcf0dedf28a743d96b4fadc151237b8dece7f5ea5eabcfbeefda75ec28f2c5291220f2f57ca3c8e5ed5aef9a1b7ed6e0a891ebd7c85164f7bc5cc9f6ef8fae4ba373d67286fbf60c53a35cd3eac5bcfde51ea101a6cc42ae5890a8ca9ffff9c3cb9b7defeda7457efeb8ef3378270c45edb3dbb66fd8b7a1a3357c7ba6feee7e1e61034f7945ae583670944757ff58a56c54becb6371884978c9250ddf8b6775d4f14ffd528d8e46fb0133d5c9fe0133bd1948fdf2e368f7155aebd3ba0417cda7f507b93e510d6a1a7ce4886da8d386f005e3e8fdbe37bef70f1c657f99f78097fcf913c5ef3d3725dff7803956db01d36ec0748f32bfdfb538cdf5dd54a8473914b9dfb17d32fd6b7632492f9d5c3fe49603a6f9a9d54149f159cd14a841f77f8867daa96d6a9533f8dfdb227de7b3761709c3ec2cae2b666d4851f80e55d28024cbbcffe827898b3a93e387c91feff7664903cedf69af385aedcb6ff5566ae4d4b23a4b6b9d61689aba1b367bd406ccb4f30f982feacc4ac24c6b55fd527c9a93af8ce956d66ac01c913053abcbfdb6c9673fc467d52015df6f295083b259e2109f058a1f7b15b833ac9c417cd6d7f2c6436798b3a16278264bd4e95135c83f2b7fd8ebab2d533c0f611662ab80cbb60659f361d8ca2acd49c5189cde5d367f6c25ccd47f74dff9cc65644e5c73bfcab01cdb8dceef1d2a75281fb2ed954798a943595dd71c88dc6fa538945ff1dd78a636f380c3461145fe9c5cff83fca2bef887fff7fee387e50cfe1fc94367f2c71147b5bebff23254617badfb43be031016ee9d8da3a5d559b917bfea5a73699f171eb338daac1c32385a557cda22fd3c8eb171647df9fd360d75badcbf83a5ed542d2d725aab9c781ad9df6cff58fbc344595aedd03c53a32ad9ff154512d5a03ab34d66da5057cc6e2ffd25f7d72cad4f4d13d49a0f14a4d54bed92562edd5369457d8bd364705937972ee2a739d95f45a50d595905eb8c74555aeb63efac4f3dfb6983a3f563b8561fd69936eb434bc3a1cafc0190e24c4dd86b4459b8d61eff9b5ea02a54d12a5465fe16bf6056595869323ebad6d5c7ff47067dfb2597279719fc3f9b0173fc1f427e08d59d5194dfa83a290ff81587601a05f811e59d1c99247f87ef47f2472ce4fbc4f7efc92f6dc87ea640aa54fe51b391bf1016ebfb4ef24cef0fbb4f7c2f59effdd86978a65dc1cff57aa78edde5bac28dcacbc2152db4370592c51fbfaf8e4fdeece58f977cf28867f13b6b0d3fd957cb0018e5afc471bfcfa1103a2a031e260dc6d145422106416281620624962186f014b9eea0e0e2d6dddd1d0032bc100a01e0060016b887d6cdf75df85f6efc5a6128610e0179a92272a4bf680720404247beeffb3e0ff4f011978138daf869f8b1fe03df718eb6c0043fad57471c6d1e3c7c8447e349e57bb1c4f1b1f0f704f3c3f1f9103fd657e2f84ed2070f1fdfc9c347f6fffe45d1fd4e1e6ef601633ada95ca06990c009fa532a8a511e9ef9f5c8180720ebaa05ae5a8cafe36d42de3dfdcfaaa430639828bca22b2897238da720a67399c5c3f5a6b6320bd2dfcd1c3dfdb1f229fb5ad9888c85133dfeebe16fc91e8ceae6d2227b2e19637f159f8263e91cffa5b6ca26b0391e7202272d4df06475d14c5d3c6d12a95233cc3f7208e7acd7896678d28be9f452edb2561be5566e10ba3334d234c900ccd1c9616c4b4d50ae77ada99322ec3df3f60a6285a81a26cff0892f7a4d2df65ade78ffe8aa3811c2d71f40b7de5cdda6beb2964bd556b8f053a532021182f77f4fdb9bd1f149d92fd796274bf3d7f78258ebe8f7e7fd73ec9d444511e98db81f06d124cffd0bd2f4cc5bf677534fc9cf02714ad98be288ae00f58cfeaa8d4a3c290064cd99f8cd2b205c6e6b4484171c5770ee5a8dba3d0caaa6aadf5b157397a7adda1cac6ff7e1cb145b238478f1c758be391eddb7c3bd73ed3cff6742b15985539f52b2fd95dc9bd7494a3956671321930c55cb130b140e851b60833eda8a86b6371563644484791cb2f0a73ebd39b4332b75923bf929fdadc7d8e2676fd88bdfc3dc1747dae1f9b2c5dae9afbde3cba0d3f3b62cfaef1c91f451739822e5c5f6f3e89871499997cd78fac6ae612570f475cb3896b45abc94398cbb356d2faa442540b93fb4cede32f37ebed159fb14e08e86428f1b613f80dded7526bf5428ff29e8ad222d504d3e22cceed91cfdae690b49167634bc6b18ea3f5eabddec5a9ad46b7ad134892a471b4b3755baffd2e295b752bd505e723049dcd9e546a7074b6b02134059e7324c779268c86d5d5955515d52e4a6a6a4a2a6ad7f454050aaaca5353e31aa973ad6b5de71aa971343c134655e5995f84afacaaa862343c332646c3f3ce20b8c70dad0bebf1b1f7743c4a84e6fea9f1931b4808904c910c8d333583e06a651df33dba86228b3461649ef452e7623411448a18f1e1fd0120430ea21e382082f408da4a93a0972801d4bb09defb04ef286825fa4aa74005bd6b2ccd4437f19ea59d786741b7a0a356d02e787f010c3a062d839e414bf5134d83f71a341436682d37681cf454eba077d05b9a07dd83f64153f50fde81d03978ef203497f7170211aa8a6084237469242441093d04ab253413bc38e109ef0f85ab2848610a5f9a40852a44c1023cf463db00b707bea1c00d821f3b073813d1c4c9d2932298a044516292d4363f8299daa820b83b70d4f446b82bf048705be06fc0b7ff010bfd11dc48ef036e23de08ee23be086e249e08ee255f84ddd683892857b93211a52aa7f608b932c1f4258722ab6bade43d09d0d3fec6ecfd757c26e3fd514bbb7d0c18ef0f3454837cde3fd7a016dedfd6b59ef77fc1673cef0f009fb1f02b64d97b10efcf43881ee21510d4c3fb17a94132ef6fa46b30ef7fc467e27b03f1deb8f76fa37724efdfba1fde8fbc1351837c78ff16410d32f2fead44d78a1079fff6ef2b435ffb59d0fbb7d48cf717fe5d55835cbc7f17a106fdbc7f1ba16be87b0b16bff3fe7de5389fe9bcb707dedf57bc9fefef3a4bf3d15483f0fbfb1135e8dfdf91e85acefb7b123ec3f99bf7f7293eb3f91d5ff3fe7ec56734afe3eb8ca511d520cf410d6a275df32d4da5464311f2fe4a489656d44aba0f33bd20346237c420097d1b815401a7172c20f4d788a6a3f7ca01b4cd855e62496c9fa83d34681f206c69d8dec076866d95ed6263600b035b1bbe3ef822d51eff16f05d527bfc7bf04d6a1f7f1e7c59c077057c33be327c2780af027ac05706460402df281cbe5a0e80af11be48f02500be3fe07b84081f8c14c1570aede34f04df2f2fece16ad80bca616fc68b225c60af0aea41b9a703f674b09703f6569c3ef063af083837363b6a68f0a7037f4833444d9c2c3d61aa01258a1025fc4531c19f1647a592f09783dae31f047f3d30d8c29f0eb23f6c4bf637a9b2bfc725fbd3b0fabc64ff1bbe2b107794fd08b8a97c4751052a7c998214a27005852738c10b11f0d75485bf238a803f248c80bf24bae06f0a12f0572509f8835202feae0c017fbb25e04f0b13f02715dada0a3bd9be9bc084255829210948e872042314a18a083ac05ed50eb057842dd833020fb0d7a507d8b3f201f6bc5061efea07f8c301017f4741c05f8e0bfe9884803f1d68eb2108814b1080f0032a1ff480075b76a0831860af8a0cb0278219604f0929ec5979027b5034c0de951a606fa7057b5237c0de140eb0b7650a7b549fad73c0227b0a0737b0011435a0c113523390410c76f85e61c1370a4ce02b8526f0fd92057b3827b077d402ece5a2b0c7b402ece95c80bda617602f091860efc9b3b51692ec2bb843f00d8317b820aa052c70224b134c60d9f508f0dd59c1170b09f06562097cb39400df28287cb598005fa913e03b85027cb728812f550af0ed82afd5b5f50a5480bb03df29c07df47d0577d3370a7057e0fb04b82df06d027cfb86c242df25c08df4bd046e23be4980fb886f2bb891f81e01ee254308f13df004de0877108f047795bf012be07fc03de58fe016c1fb80fb036f0477922f825bc913c1f783e00b656dadc40bafe46d2efcc80a5b4e36fe08b38e9c88003b09f9ae829d6a7c0b819d88be91b0535fe01b0a76daf1fd043bf9f80e017622c03708b0930edf54b0d301be9bf41421df41d4f81e82e8852ef01d45c737d38eef251fdf1fc8e1db033a7c77001fb1905c867f9220dd816f269df4ade4be0b1849c6e6c2b712e6c1cc9d743ae9f84e827930f33d9d72f81b3e4ae2c280947f011f25e9286c543a895712da5c38935410c9d278b0a1c35ea4fb74a32c8d86f7bf551e92a50dbdbff76469395e87f71adeff43b2b4fcfedfd3176569b6f7ffaaaaf835458b3efd4981847c5aa314f06995aaf1699d4a6b555aadd27a953652dab9b475fd947695b4a13a2a6da9b4a7d2ae6ac0a76db5c3a77de5804f1d29fdd4733f3e759d0d9ffa138f4fbd0a54013ef528037cea52387cea5308f8d4ab12f0a95b2de053bf62c0a71609029fda5c043eb5ba219fda27097c6aab58281bb607c09eb1d780bdc973e0a6c24d00dc34e0c64d20073ce463870e1eb0dd0d89000418b0800420008701f0b0e147ea801d1a0023e6f1398bc9b8c17181a88602843411459deb2270b5bd0483b92f70bf8d6823928c48fa2f9f4bb097bb02b89d92c04efd747363c0cc48a1ad9fbea5e021f78520c1e596f2635b00fb133e2a7a256f2b3aa974d2277d33f9766aa7a4a41ff276c29ddb02b87333f9924e0bc8386a81bb010e6ce0c73662031c680e6c60031c0037709a46f4126cf3e8916d01ec54f49d047e298d81ef0a9c321ac047543ae9938051441185ad35f02c9ccfbaa933e0b3cec0fb3712b86bcffdbe000eadec7e6300572b3b02d7f6499760ef246ce270b8241ce270b89c81a61f59e5ad9bce176667a033f0689881f3c7d19b541d4dc232381c2e8f1fd94b96603137063095d67d5f001f51690abceec79682ad14ec52704bc135c3e09bdb02b82b808dc09e11f81a81ad11d8735300878eeabe93be29f0a3abbc3505ce1766eb743fe44d01dcb98dc09d3b09873218e5d69da6a3d7085cb3a346e02f8f5d857e090e97e09ac7916495f7fc9c30697c7f10dc447c0381bbc9370eb793ef813bf746b8971e09ee277f03ee22fe07dc4c7f043794f701779437825be98be066f2447027bd104e3bd358d248df3d2c692542bc1de2c74bdab2917af84e12c47b473fde6f6c09e928987cd651dedfea7cd650de9be9fd6d93a57511ffa4972cad73efede4fded159f7593f7b73b4b6b22dedf3ee95a2bbdbf5daa41cde4fd6dae0675d2fbbb5359da8f77171026eed3301b7d6a6693458baf96268047df719696f6aea92c4dc80f9f9a3906494c4c48153bf26998633b3a2bbe5a1ad1ff7cb5341defe25f9cf89f88a5f5b0f1433ebc7056e6463e3573112a2b732242395f2ded85c7b9b1a9a1f96a693e7ec6574bcbe183be5a9a0e5f7b3f82e9df4bb08d42c256cb10d84e29c1768b10d8521d61cb2509b6554160dbc551ff70e7df40ec32d8647146670a4259997f88e44cc31fced404a58e9c2948e5c39986a09595f99b46ced42c72a62191333585ce74b481bf1b6ef82180193e1c6578d106f68204618561c862d9c0f70007f0f43d8600fc88c306b60a50000f215296e680bff1230c2f02c006f61e3d5e68dd7678175e1ca3c2f1478fb481db76b15351d1db28d034411b258a55749ac004de46594b6bc00f7d8ae61fbf5a9acd06066d173b11e07b20c083394b0b9baccc3fdc41599a03797f6b65690f787f1b6569367c4eca04a16ab0513968f8f14129ff10c91fa4b234b1c9caac2c4ddc85612b447aa29232a340ab506c39d560e5b0c9d220f0fee193a50de0fdc32a964680f70fa12ccd86f70f77961681f70fa32cad00ef1f4a599a01fe86f70fa92c2dc8fb87559646f4fea195a5e9d8f1fe22ced2841ce01d87f71775968680f7179b2c6dc8fb8b4f9696807705bcf3787f71676912787f31cad216f0fea294a531e0fdc5294bebf1fe2295a515bdbf5865693ede5fb4b2b41cde5fbcb2341d2cadc6fbb3902c6d02efcfca591a0fefcfd2591a0f7802b8084b00f318825b086eaa20d89b22801d02d8e21e80ed0e08b64d3fb053a5d81d8077c08db332ff06e88073c0d5ca82de07ee8119b0001eb85ad9ec158013801180ab95c5781c70b532187f00bc03ebc044b85ad9cfdf800d800b806dc0d5ca7a9e0078005f03ce8169c002c033601970b532161f030e00c681ab95ad78006018fe06ae56f67fc32fe06a6538ef02b6e18c87b00d5c6d3570b532bf2a626230297efcc8506ccd7c2d854e1a58e887ac10ee5cc34138ad52698d4aabd50ccbc031300cfc02a70e957a151f9cba540f4ead2e5ba4d43ea5b60a8a5be0d4ad52bfcafe3b5807a79e4b5d8771da52694f21754e87a63f3338b5b9d4a762ba4a5aaf70da4dd977d97143caa6ec4fb2422a113724cca94835c4cc290bd73935ca4278e41faca6b3ae40d2fef945e246620c92194642e877a582b1eaa433566dc99085ed16500a940262bd22986e7e0d9b1ac706ad05a168a547b2f8a08841a9ef03cb1b370b21f3180542e1a8b3a66c06bbeb90bb725135883616cc95834d617107a59eba5a07c10f6ca546593c419b3fcf76ea7e6aa7f297d3fb3320d35875d214bbecb5fb034201d37bef882b230b938e7adeed8d278b75a640ac551e5f4c323bb39ef59d59b8b377dff03e3da2cb1fe935a298d6641f6168e50e3f05a3004621a9cc7d8e55b5670933754d8d55aea9d18e55d96f7c279962d721105419f6749f72bdb98b34465959d76aa966349f5a2e339fda2a9acca7d6aa8666aeafc7ba31cad2605351611ea370786b8bd6de2fe6297baef9abcbe67b12339db11a806853f1636d2b1e2e1df32ffb3438f1664f2751fcab834d591ab8bb53760adc02ee2c0db6b3b2fe7037c23098613438940ae5825a59197a5583db664eb4caca5a8693e5723f2cddc9c56431531e2aace342ca4a972b314df32a836f963710a9ab105ebd78a87257c14c3158c67e144918fe720c76b2d1c243857532df99c23b4c8e4a45c9743b13ea46ea46ea068a9b291e2a4bb3a1c1f150d520da6c6cb02ecb90eb331609c31e599665d982e19b6968aa3ce5fe1432fdd5c2683e854df150c9a4b8acdf2c6fb11f5fafd7bfcadb4bd6248b61994ec54b850a0c53a142a686323232310fc3b68a95dc3f2363698e5cd6270dced126cc7427e77d4c18133396640c77861d5181c59ee689a689664a956a652a687056d66f9a3c545b727facbcc17e8c89897d4c798bc5c4bcb5ef504cd8c76020a0d48f0f6058a69349913531f1e30397e9f27e7c5083ea8d544c59836813dfe29a9d9c28d3c53cc974352a6a6a66ac66ae7ce6fd1d674818e64c79b3a2a9a46dc1306b9ea6bc01a1a9cafd8a796badb53136168bb131fb43d6d6fcab86878ba330dc39863bd740e57e9a9f2bb97f06ef78bae4fe1436c543856f74b91fb6b3b498a7348cc176b9657ec8776ea472bf0cdec95959bf0abca3b3b29d1d54ee8f79daa992fb63313b4ffd164b544ac343857524d6ede476260d8ee68806c967df954cca74b95fa69335f9ccfb8e3d787bc5c4bcc5a91b61dad8c7589e2a479b87cb8d06577bfa6398876a0566ba93cbfd290f55eedf69f2594a134b37365fff851a1a1383f9cb3d4cd3849922699af7bd997c0e0e76bae1c771bcf61302c66814c5680869314663acac91d5327f88a041adc79ec4942b3bcfa2e5c606db2795498f196bc5d6c076676539a83d3a689f2d5f968460a7b23217ae9345cd9960425e9190108d1a356cd818ca34683499f136ca1b7e1b43e54de887d033c75ca2597ac1c286a6c50e8ef7433e03058a8b15333f3a37345058eb821e4589c938bab531211913438e24ab6576f91939a7e7494cb9e23bcfe25a7caaf66c71d4a9b87871f48bc54579d23e96c98abd62774d309ab36951b32206b33adb9469d0807d8df2d64c5ebc8df286f33686ca5b33fd502e6f2b3edbc4eef7f2d672713a8162eee09998a4efa49bb751fea242d7bdbc5d1b1a3aef95b79cf79a94372265ad3d313f7ae00541eb0d8262abc3c63607c3dda5bd388af3232526137b128efa14bfe2bb2caec5a77c4b52142ffec5e22c0d6cad143bc5516b25075b1c162d273b4b37b79fd8e8e46255b5f4cfc9a1f92f6f373c8fcb5b67791c74f36779dbf973c50a1daba3e35d7574c496ff8f98ec13b5e40a1df2c67082080bf22bdbc9c330618845a2e8b8f8d719a205462e9e49ab856bc58a1649a2645c2b5a42f4c028c160cf82c50bd20532232c600fc36c25325688c5fee7e715fb16626f832d690364c95bdef05f5a0f3f8c30dc4db6488f6c164946a1d1427913fa167cca5b3b69f13fe50dc9ffb8286f42ef8289c5bf286fff2f2e0c0b0386778501a385f216fb5abbddddda7bcbdbcedf56faf216e5c50b18e5ad25f431cadbfd18505a2fa3bc7512932634b115f33060c4286ffde45f4679bb2f6336a3d1802c1090770502125bfecd44e9dba3bc8fd696b7d68cd25ffc5e79bb792fc9dabfe347822ede2b6fadf7beefc98fe1c3307f1e2c6f3a0f36938fb920818072727e4650508e9050cccb5841e805c4cfcfab84d24203f133fa8047806a139fe2ebdb27b5167e7dcb546738ffe4535b65f6c3a7d6ca8cf6a9859af5f0a9bd92ebceea72f8d4365911d811e4146161c287d9129a9b9d209e1a0b484e94488c2230c4d6955d47b59696eaa34f7b6ac70a974c27f9d48f1cc99584e8616104caaff82e8b12193ee55b9cca53afb2722f7ee55f2cce1e11e0538bf4b1769d822b8d82af2768a82fc11224b0f22350d104ee3cb6c8b2f4bee57299a6399ae4eb35c260b0f1befdf7ae0f6384050b7286cc080b25325668a209fce51c9a68a2096c730e393c69a2091ce61c72c821c9063714283fa62061a5f7291a0626168b758c8c8969152a54acb02b5678d715dd72ad5861cbdb8c8c6b450bf15e79eb8101411004892002c49e9b8826e2c79004979ac035cf70c18f32a48ad27b99d8cc0c0d0d0d0d5953debcafc9b1216d6c7c88ddecd0d0dcf004edd0b080a476a2670c22280cb148ebb8f8d719a289918b3fc2b566e076c133cd44fd7843da94dedfc070707272726039e43f0c632cb332997795c17668686e788276685840523bd1330611148658640677d4b713274e949cb4e0c793c4a5f7e70a72850ea9a3d3d22177765a2c58b4782c0f8f77e569ddecd0d0dcf004edb080a4d6021f3e7cf8683171e2bd6721cbf9162b34138f9637f3512cdf5164e5cd7b5947e1215bb35f61858ee2637d7cbcab4fcb091d3a74e8b8597e64816c756e2759b030b1c33905d8f6820c38601e3e8010e92bb848a3001b39d1184560887d02dc228072e1a3b54081b4a3044bac70c91cb9121309acb03042ba6005194b2350f1837d8b537989dd8b7fb1473687ed52ede90fb17d522d9395629bacac1f08db29d68a3d00b63b560e26798258d041c4091da316f451540b2173a816a010c022e57e1babeba741cd6666cc08aad584847068d0701dd9d9a12d39b2336ba107a1574f7da51ac4d7771dd45a0fb1a5ce6e983ef5ab2f3c9f5a1c1048543b3ef5aa284c21850a9e9f999c153f3230173045aeea175c1f21e5a204c97e20baaf831a81b1e4838fe8e46c6124e3533f42120369e7c511af0275a587590b5dc41150f8b1c07224957c4dd242283935113fe69038a5f739ff18e31193e739ae58b1a284a15bb02db4e05d5b3082be8fe8c36d513bcf16329a189d319090385152c25fde81ab4d494909dbbc63079312f6bc6387120ef38e1d3b9294686c7e1462c2e4471d7245e9bd4eefecb06051decc67918205d9a2bc79df02072551d4d55166b0a8910535fa0f63c908fa3ea20f37278acee19cd013274d96f85146a2a5f7b2d80a2bb0c0020b3116481e9e584f4f4f0c1b2386778d11fb59310353c4450cb3a8a9c15166b0a8f921c88913274e9ae05ee2db891327509cdc2512fcd802d9537adf820fe9f343c23055fc4f7933ff27c50fe9a2bc79ef02e705f9e2058c666934ef4a8b32339323f3330353c44593e0efbd4a51acfcf88284517aff4206cec398a948f1777661982cfcacbc35ee6737c8060579d7a09a6f14dc5674e8d0a1a35b77043fd2ee089c6e78154182040912244851519020e137835f90018711601e3e80b0406ce488a3b83e0a92fda0548e8fc2f04184422a398d642071266faa3d7e84103b47684c7ac09ec5512d3e1504f61c0c815d07d5a7ff06fb16a7722e8e7af12f16678f8eb0c86a9227e70746c70c2b443a4648e0d342875e22c613f62533a9dc2f8cc4429016e5cde66b424236356ae8d47456b8476ab2253e2cbd90f9d4a13e9b506de1eb3b12b5d6f3f53d893aabf928333ef52c1e65e453d792ba943f117dea55b03411a4837021166972f33b46301648829a266705104c7e1a47a48573b68842fab4b5bc7af86109ebd47438b202922b796e49fdd4753c2c1c013d6d2623c657183e5f7f1472ea227eec21794aef7b5a68c1c7a7bc99efe343fefc8c2e5cb818ef0c3b6386779d41e4a7cf16383827d213570b9c1e7e78b58484f09789848484b0cd44442029843d13e13124857098898888949cccfcd84b2f4817a5f72f1a068c183162740c52868c9ecd66425648c8bb0a3592a058ce8a6ff7f29603041374050d8ec84f2f2d2d2d2d619b75d061097bd6418725a6255cb3d013253fd2c859e93d2d06043463c68cd80c32282856abd56236ac0d1bded5468dddfc8d116ce79b200962d16ab55a4f702bf956ab95e44721b2567a2f4483460d1286d941c06043e5adc80fc170e75827f9ee308fb116e2471b24ac730b01d688f9f710d8e986ef208a8a8a8a8a8a8204297a6f14c5239c81b0adbe20030e42b008a2cd68725630b514223262e0b4407afdc004c3a7cb91157c60f2a616b01fd1831d094fc2a7f815df7916d7e2683f0f0b362e8adcec20d9817692d3d54a7ad0d1e1ca6cb8ae9fa84a6e98fe2e424a2c7a51ab3511a241a3468d26366c0cd9a121ef3a6464068b7b83bf6b6e7e7081ff1e71bd68263a45ea43f9b4ab7205e2ebb7116aad715deaac9dcc567cea4a443ef59c33b9ceaae8d3bef225cea44910d90ae70b9db1c9a97d508b2fb8b491723e7cda4c492c8cccd0917695b6d25069ef5a4bda544648be917af8ba44e6614428b87347c14e3afc0844d24aef8166cc080a2a6fe6070591b5f2e67d4d48a8bca12f54c2706bd81a35bc6b8d582dc76629a8c5e30809f990b483236464068b0b050afe7211142850b0cd454550b0e7a2222838cc4545450f05d7ccf4e4c7662244c668d41a35c818ae79b441c66cacf0e39039241b2263998c35c964ecf5a38d8ca13632d6f9da2c2dd5726c96825a3c1326f8cbe3259b09f69830c136e7900313ec39871c98e03043799e1f4bb255debc6fb95ce58d86f9660c77e9fdebf5b0f2863e2c76b3b79b77bdc5787ec78e1d3ba230618105d90a4444444444444182906423e1dc03b6d51764a8611c58c03c7c007194c81219211a1c1f581899010546acc16d25871f5eb85c4655ede922d49e3642f5e92e8e7af122d88f5cc9d1fe1fec4c584482594da23339413b767874dcb8801de9ab7e22fd3abc8882d084849668d4a861c306bae2669bb377cd2cde263643d3a4c97b799b9901c3344d5eec9c17c7c5a71d65ab5fd3ae92ebebebb712b5e6fafa6da5cefac9d759cea70dc5cfa73da5f3696f51fab4a9a072eddd1335583af2c30dba2205cabb9aa546d5b4681b167f3543a303cf809d2f76faa916e483912f42e46be756c24e3e7e64d1f871ac24399634ca1f7e6c99477ec8c716e9fde8ea251826fa26d9e38df976c2c4e4a445d730b1789bd88349f8cb413a097b49f826619b8304e924ec39081ec31c24489067f251a06418ecc7b22c5b240cb397be55de68fc0fef2a6fe6bb4a183a1fa1f16679f3de5c42ff55de56fcab611606f3aeb0b015f39daf976fb659074e921305a843c78f2179719895bee64ec23523f9b17db41723f9580c1c45f1c80f3d76ecd8b163c78e1d3b76bc37ba5cac56587b3a866bf6016723d8c624d40289cd2b1521828d549f2333b871337033bdc0bd833b892ab5a7ff855b04b54789ead3561ced2b8ebac0ad25073714bdc5076e2a2bebaf056156fb902b9cd4a861a103c388fa29574771a27ea6d01d33ca1b0d1a4c356cd8181acad9666d36ef6a7bb20405ca936fb2f417ca8f9e57de6cde83cd9c9fb6ad5e05b1f8fa466a6de7eb1fa9b38ef2356d5d4bc19f7653ae9d443f35ae919a026d01a61f174e706ad29aa52e4935f92b946323244667c5a32dbefe18d3f1638d1a356c9030cc661a2261982e7e7ecc24d38f36128689f3b6f256e324e6633d62d88bb5622c56ab936ec047549a89d28f637f356ad4a831921564b5fc7f5cc41011c5c4e0cfbb644c0c11d147c6101111bd37c2c010168b415b605bf57941068c83f3b0c14088d49e7e16b848ede9dfc146aacf11267d74e2666a291877d30dee2474566056fb908ed6f49328a91c9731d3391dfd8443542454de626758a386d2db286f34707ea884a1f30d8dcfe5cdfbace4e46de5ad9fbc2dca8fd705eb820bded585b015fb232a0de595bc8d8ad0a775aa52317d5ab934e9a56aa544e3e6d3c741531e27fd2405aa55aafea00621d7209baf6fabb59aafff429d35938fd1ccc07ac0603d7a9030ecb9071ec1c64e357e0c49180e738f1e3d7e64892c562be66fc047545a497f8333c670070112d2516433c6f3138346cb3c26a97563c81806f3079231ec85640cdf3c8a640cdb9c2858640c7b51d18f2319c361a6819d84bc37cad49194f1af19866bb6a9c1b6eaf382a332380ecd847d2c6120334a988c8279fa09be01bf95f56828b83ada4d6ae07682ab0b298ab164cc25633e320624631cf310e6d88f2019239231ac3ab25a4361ee249c6b4f7f0bdbf00b3cdc0706e2a8679556a96ca36a0c1eaa3dfd9f3efae3f5b8e15399984f59c8b506d55a33f9fa649d75d2d7e7a931aaacd662624fe3eb8fa363307ff9065c6da3bd79f46ec04972a2f86ec037fc088e20e922ab25c495633ecc8d452698958449fc56d6dfc23c3546457b3ca01b686059f5e98fe1fe2e63ceb0f6b48ead5fc32398eeefed9a9eaa404155796ab2388b64735667753667912c8eaacaeaeacaaa8aca84ddd60ee65f84a7a4a2764d4f55a0a0aa3c799367c2ae7fcc914cd71561d705acf7a8d48a986b733dc91822110000000400c314002030180c88c4a2d180385265c90714000d95be6064248fa320c721840c4184100018000000000000040620d0026dfc17e3ba7e998cfc5bb0d9206f2d1ba68892286bf7cc1e0f614896aa12fab3d175ec582dcc987aa0750e3f671defc7a92b7340428402c25885844c40c90597db4fa43e2030021bc5e7c63ab4556b81a001f222936bab07729ae185997b723d55614a1a76b84076e9c9b0aaf5672361ec58597606512e2dae8cf5c99bed5a730ae3613ce4b54adbf64382e158722d6dbdf01d9fdcc9fa5d580ab102ff839a04a55c87215d1ccf6a6582fc756b8cabdec363840e0d03d142ef6109d3f565f650b0b410226b9073d31379ae4ce4ee3ff148d6280d36d2555c57bb2e0589f469bcdae362818337058c5a38e942df8d071a0141ebf545e5ed3a94efa877418a952655b3c4cecba71a51c27850d0718d2f87b3ef6817175728a3c99065e00a77c02a10e6687c5ba66ba241bc9ddcf43930b1538a54b4622e7aa6c1141daf4bdc5005e21256b6fb3fba25dace6890b55b3ffb564e59ecb257d1d61327f5d7ac13635d6eda2cf476559b359f501f71d2c4fc7d34917d2eccfafd01adb67ebf6aa06d73c5c058c4d76759653eac00d5b2e75f47fa14e68a67693a4704bdf1491f238dbc0e8131368b1c9e46c737515c24919d5373ef04434373590b63f018e3f2d67fb042689ab0e20f89b7514ca97a6eca852c86001f677200c163a98c2ca6db272f7b354666d70760a1dde29da401496ee6f6dd9479c23e84083e2a31f7c833b3f108802b0350602ae7486ae8cb902b17e0ea0509de43c2504e33f2ab1dc923075ff83792dc4412df10ac557fec578517dacab7de705671303db21b000b2a391ca313f1b8aea0a97053e885d8229241a1a12df298114200a615f4834cd0d8b78e1b29dcc9e8787bfd52250efa6a387d1814ed1a68b64070531158ac484c1f89bc6d3f84b96cecf666c4878604147f8de23de33114dfc6c5247201a0df453f7771b3f25de8d18a17e9b1dd92668aeca6614199c029ad0373d48d5225f6eddf1fbd3e51ec4f5b4913815af1c5ca3eaca559a1184cbf79b4433cf7cce57ff7b570f434f94f7e3fe37fb59e44ec4715cfaed9ad925de2c500e137682fc06a4241588629a48f4aefb4e8660f67487a1d1e423737487be8e77a76230acb8ddc869556948e54a99326538981d0a7fa6add4b237c7fbd465244750b4b5c72ca8151eafa3b6cdd2fcf69c7330814e48b4834aa9ed4d2b978ea9299e1ca93bec0247d92fc123a84a12b78888f1779e8f1e1d08856879649874f0c952de8c5b7c8b4fa8d58455b89d9f733ca4dafd614ea87e95a59c2be22e1f5828c455818e606f0855a5d57e6a2af2e8e6182c3f959ce3725e698621d78375a38dfaa06f72c9b748acb4b27272619dc02d395463139f8b0f94e04293e3d4cee0533aaa78552cda212fc56db37dcd8034b58b969ec9f724e6346f7fa9dbef6fbdca34dbeb3aed38aa597295c04d88f5bb4b47be3b0812b9c511b61f76a9311770037f83e7bd36387386d9516c5eeb72899868575e52bccfe8d75715fe8ac726162d97c1d7f92ce70a7e1eb6558bdec8d1fae24540546e4c7f6e067d43085fe4b75855455757a117639c04bc88f4227bfa1e70db766d494af01226440a2abd6882cf69fdeba386d593be5236080168f957fe9033838577b413c2c47438e357714817d67da468b797e2b53060ea04c0df7ee1965fdbc8aedc458606f48f62085c963e4783e5f7c448079086891373e7e9ab1afa9ac9553bc3b98520596a02b81213b5a153810a7a6b214663afe24f093009c19bba67a87bba3756de98e5e560fc8365d9f153dfa3f47a162ea704874846e7492b814a6985dfefd20a668553d3f0e0ede4b1711987896d6196f1018535e7dab46d0f22709300724db564f8b764b4d4598d0d6f8bc9f588aaa0a36a68fb3a038c498a0408d475f50878467b8bfc34f0533a7eb82e00ba3d9d58987beae7f11a745d23dbc37258965dfa5e4a5e84ebaf088d36dc6e13c13d23d1f6ae24d3d95ac61635a706479db20ac927c9a5a8c839be7690faadf52764e8a49df9ec8cf063a6c1626a99401b329c8ce7c10ac35d01ba374097e62cd4e2931c58a9970b073e0cea728fe0c908595238850afcbca9761bb3b01354ea8065ebd35ded8aedbbe6a9cf14a7b5c0bc493b651874d36c437e046a07d040de109f9b58cfd6d2307ef651b02a3a766bf8a2a2f6c6b19c79a41fee1f7a8946fa85e1e51d95746818e3d8d6d4ead40cf6ceccf07ea0099f762f6183cc134d0b3fa939193aaf0c2926cce2efd67a09dbde147ca35e92b63d0dabca85654e3f96c641dc465decc2a1335a49006b5cf81113762371dd5d89f318bfc9f7d49d2043e7e28b4cba3e65cf9a1b9dc646fb4ed74168d7c07528311e3efa85fcc64de3058d0c4672e35deca185e0b9c5908c4219da675cafa2f6d00185649ec2c8f2fdb845d2bfcafd03e75100a654ea2ebb4a2b82e19faf1e16211e8b244ba749149a0f06114aaa4fc8d6240132c11c932f57d750400a84f3d53103232080ea8af68e42dad862bf2b8dad723e3100e81d905e4b3702da400276001795e1df198b8824b497bee5aa9ba6cc1766e311c83541a6c5ecb9ef9ded1e4d792ebf53d398d193388b0718cfe73acfa95c336cb562dafa478094b5768549dec00635fb727af479d4212a88bf9356ece548b5d829e2cb40ad643874f120abdf89f89b5dcec302d46a90f9c3a3d6510929e3a84e3fad1f9f342b818d546c8bcdaece0a6b1372f7604c3a0572d2f6cf3abf33f8c022afc9af3f41413f5b51eb08fb11d60beb995cb92ef47c954d4cdad2afcec74280ac2d9fd0aac5a2d5779e65d2f7b927e715537765f4382a89278a559c9f427b2e983435e988aeaa9940e6e97bfaabd54ec22cd91d74af633a3df3d30d50423a6ff99ab5a5d0e584ee1482dc9a15c86a972a70de09b78c162012cd78896e2d43d9369864db5bb0ce3784a1910d3702dd1ce34430dba709fe6519479564079383394a34c005c86ed4ef9a980fc9b85c789c29050b53bac24095ca8a65368e651359b6f2ce05ff406aace9391e59cc27c3b8cf99dcdf7038a85bc4a04f08e41d2e2a26c87190d8476eec16d7e4cfd1fb70b19329d1b1f616387ee3f2c0a74c252fcdd95c6a9aa10f7f7ca45db1754f3cfc9019f01dc96e644ffd4c70503e5cffb9a515c816b37aa4d0a90d8722c8aed08b024ee32f1dc0fe34bbae851f30b225e3ee24627ec7cd33640fa2c1936504f45eff8b9c5b9c6644072dd864c7957410e54930a6f8756aa5d255e0aa16323a7a102e519ca90880c0beef58336107f1b6bbfdd58311e742a161cf737e0e58bbd4155518039dd1d17d1d484d8d2275b031363c61e85e25a00507ae7c1606c022a77a9f3b9f46cf9310b7aded221092e79d7fcaae768b31ced8da35d385af86cb4ef564da42142ed18c0a60462f6dcea4e50985e06b182676eb3d9a8274b1b1f2a998ea9c178e6139cf1207630e08e82b5dca2988c4dc604513445b0442b58380d2b7563eb931d441508e2a157c75ac677d165141b5e7e84e89c0794ab557b2b9a46758a8243aae3fd8096b1198e5c72c0309884cd07b120593918de152e22f95e1c20e02fe8616f2842cd1ac532241a462be92b2c51157215efc731c5edaedf0efa9712ca20587af92e3c52bc31ddbdafe50b980a36594186c9af91619126d5e7e2c0d464341cbb68e3e0e8cebc1f870eeb5f00370e863a30b05f54b2480ad787e027488df40b73c72fe2582dc6fea7a02cc25860a5bfd574cb1de57dac7065137c048617c7810725e001007829c14fecfeb8008f2214c011b96289b2601f36dd0267ab9abfbc485b2084309e503daa724a60677cb638d04c3c18b8ea65f0a752b1d4cbc321080d93d94d0d8039ad0014d788ecc217a5c2ef6f864aebe438a06018c4ede89b266a492068fad6d1c9cd494169167f6d283cd8484f4c8a75b251f910deba48908640db65e321fe7cdcd8f1b42982501d92d0f8bbafc1d0d37f4c4c157be663eb98d931824022ee67e0020b144a8cafd19c074f07da47bddbca76d20d4d598561cddc08d5c2709a718631430713dbc36d336c4ed67bbbd91a335cc0e336d30c690882f1918c8c78c24e229661fea7f14ed624885b2b65af18868818b8ea452d69b3b0bdeaf5bec9b70f992cf62802b915c13c3d3082d9f08ee7f23ae3b6a03267e03927bed2d2677307d417dd12b58474d20df88c9035764394967b17b57447d5b3be302600a6f91f027557df1cc0909f19a60d5ff205cd62f0da572635f67fee960c7a8713f7ede103e5d6e2085c728b887cb731a105264be8b07d75c5234e3377c5fe6f2a5cdcc95ecafba411db611105b41aad951e93621f095a24520788e936326bd35d19fbdacf3b28317d4339c3d0410a2478771e10d099e99351baa2c6677e0338b3008b211df4e7ac9c24928334dec0ab353a9a3a3721ffbbc0e021b55b9cd0bbd81f7cf1d6471b1c22ca89d0c1de020b3b4f8161f77846e20753c3803a606258c2a43f0e9c1fc74ec474e3a40a17d1457b148b63661b7977bbc6578f1fafe848432429db922653930af8a0c4981a2acdc28c7f5b40cd25a4ddc582ed3168d20dd134df25ce3b9ef33b85158beb3ee7beb31fb9637084a875846b68340d2dcb876ca24a810563c7dc236457301e5bb89fbf296c17fd9c034b3113c71309f41db0c74f4150781732a078ccd11b041b1b0fcf8f6aebfcc426e1e43a3e7117a318e12909079d30bfe99d6a1a424274159e873867d2de3f393958bbce1e7ba598df1bbf67403465ba499ac02e20e73d7bb9e3d8802b6096efc8dc9550b9960769c0109bc9dd9140d256ae18a8a79e0dc931e0926eb1ca50a093185a5fa9adea00ca22748b95f9d28a10f8cfc8f604c1a6895969085195aa35e62683f173876374955635aa5b8b298b93945f824a053eb8f92d7b12c6a4736758a0f3cbd60d160930298a00c37b135d825105f884938bef1449fd2a0a6b238422324a19f0f49f4cbe2b7a844e32d53c48b4eddc2465a7ca8c24d6b7b4178317701c814bcade2d73c4d4877e9958801ec59721b1aba03e08e53dd652a717af65769efb722a0e3ca2d7b6b7ac2d9132942169a109a35995556f9b930b4a817cab4c2b006e43eb0abbbbab9874596cb78c104ddf9600d1e6b14fb27015199ed452d05419cc91529fbb48f0f719c76c5574f952c5ed7b319112a97d56d24c2db1e02c4abba7d4015a8593d9bfc1f860e431f8f914b33cc600fc8295e3a543bcce9b12adaa4e1e3791b7401e7986c6a60cec89ea4247d96c8ea604b50f2939ea2c4590379cce4ffda28fa87c9c82f12e513d49c6573f7452978c1ebf148d18c300f983708783bcb4c54657eb205651c9a5189190c2096c66a57928f533bca7efc92794d6ba875460eee3eb4a9cf785d3772aec60c1467ae601b7a439e62aa5ec9e15bc6b16a3317d8568d48072c7ed2a868a23c7234fa82769b1a9608516c56879dd1b2bc771fd74ff2d25a2eab9fe092eae6d1066b4340c3c522a764202707052e8467d426a4c3269f346aa41b64d62a939f414f0771ced54601db5ff4c0c89954463913f6a831834baef0ef84861fc27a08d11d85f69ee0d95a01999516975be59c9384ee20f66d2cf5ccde270001f3962c4bc775582306b8ab42b8dc636928f2f56f80da34d7809cf10a34815ebdf3950b61790d3c63cd880ec1215e07d5c07f5149a2a87841ef795dce5aa61dac947607b108e976cb15281c79a414e4e090102cee0f47e8e9f569149cfadbe7a5f7588232534e0c97f275c4cd2656cc1a99ad855a72f65f3ecbb64c6ccf4e15539c3af583281025326442acc99f9b29d9189bc7989fdcd26f65f24f8d515b6ac934d9eb11e84d9ba8df033cca89cd02866d3284b2910466b732d9c7e1c80467fd53295c9301ba611f819bc65fcc7668a874f4e0b80c27ab8e1db5abc2de03e564e7318bf272cbc9a65b33581428183044846ef5273d92af7666852c63e94535b305f4ab8901ebafa41507aa83144e1c05b89d97a0bbb8fcc27e5df43f355a865d30e46bc8bb088fe32cfe3e035bd4e82598c63b33eee5d60c9ded42774c0a2d6b67624b67d6fb2ffed653e637c297c78b3f2c295d2102e686b2c1347e587f6cc6c88d4590f0bdc58228448de9560d2297168c11bafed83727ed328f2ea481d234f83515e8f3cbcd035517441fbc276256a60e3e884390ad67d142092b17eac448f2e3d1dc51939b3401b3b94ca8f1df362986ab15466c152c24bb89b6eb25342ce955fd401a19c8bd379b5ad75c90bbb5c8bbec7fbbafa156b64a04be251f5f94e97e4c2d001ea06f9d4d296069621afbcf7d9b6f6aff8f6cbf7b971e1f64d58a9883022955126bd2a0dee5b98691bd82565af9a59b4afdca8351aabf45d225af64a8503a9293ea10303eab2b5ecb86471953d1b6d8729924b48354bafb767db8c65566536e5bfb34f9b119d046781d03d72ac8fca6b32ee3821a0d96f54e4aefbe860380fd8b6f0a1d8927b2399c4b8126012e79622304f82c283d5d703fb547b9f5bae49507c2a65b96bc51aecb87c6ab18b96aa9486fd352cca9dc5cbc3ede9770bb219326ad72fd9aeb79773051f658d275b54f3e7df703df9926de50675662a4496ab3aae0047a5cb99a3f924078f0ace49ef5dfc4ca555c637c72edaabd7f4f33442716524e19533bfc764393fa53218ae9f8b1b56c29f8bd419abef825984a61f545ae980e5ecdeea2ddc35f85a88b02bf2fb6d7e4728a49a7bba0157e8ff7e74ccb9eaba07a51be3052b6972b7d9b5df42ec3b0cec4a6109f84d1c4dd30dad16c00882ef575051f69e488b19e67f281472961d79b22e0dd0021a0b91c5b414d422f64fe04ae5c64fc1a75aea31012d7845ae7cce577cc31738029327df28c13e61790719e24c00ebe26cf650e385a2b04c555503e1366d5ea9f89a639d727866e1ca55872c05f83737700b86c7870f01d094692e4d6dd1355d59f155f2ea0e08cfcde61f015b0bcefb02ece6340a53a4cf2897797d71a048f6c128e53248c06234c39db8e8e749fc431299b12b8da4fd1364f86c42471f640516d3aab634fa0e0636c5a3762a92967f4dd1adc39cf708e747cfb25f7db894d2b12435090a26299dcbd33ae984835095e9a56e0d5b94c88f93c498d3f5c0e9100eed93b04d2a4f5a15cd5002a509791ae98bbb46a6b143a68eb9291ae209cd61e34e28de5d10f440a870fb48df98583bf221bd209cb8b0a8cb382591835570838646b4a39d0116132a85d6d5d598d24d718ab9f141cefeef0d2c27bf34f7afab550926fb53e89be3412b1fd8a8cfe50427ab9b04a829d98a661adcd8a18b27f84284cee32af1d852f197f41d349295b15ccfff43c64fb6c74c35c78cfe19d5b041b0f33d2d5fa2402babc10a114f21a9b1b7c80b1196b3a48f62a6e18198ca3cf90006ee701e1fb90a91951beb6dedb7d3f48f77720d48db95c543a0b2b0deee906f58d29b9ce80a447950ef9584e6b71f606a1a6176f70d2abab0f7e419f1ecaddfdf6783351449f2cb9e7d07cb195c836f79c11f1e40d6bffb5276abe9123d329800e19f7570ede026477e2d8b740a3fcc99c37615b3d37c345f47b3c6a875ed78dea90237f3988495f90b38e97cfbf66d4f7eae6b92f6baa2390299af4659cd8de5d5e874a39b1402751488d640a3038a79d693c9c4487e6b4ebc7a8539b2d01f67b89fcce82af1d9560dfd73a17b8040812e8085ff8d16c0610c0bce9ceac9326f24f913db2a6db13fedf9dcd4389c9e12ba9432befea82cdde810a49acee269456ba9002865d3a0db76cf04490abfeaecc1871803ffdd6c1a089e57af4ce646f06c749ae6d5289b59633c1b9dd6e88d8aa08e4aa219717430504b27e40249f3916e4d3477116e42723882bc638349f706c7e166b149aa04be6e8942528f8399d46f85b7ec615442c6eef9a6fa603a77fc3f92d758adc306352270927fe80217de19b012aabd9e0b9265d4d6e23648dcde23444a5db364530599386c1891ca3708e073150ef868db984203495c83b8bbbccb0d25cffa745a946086ed9e9424312daebfab6b4b36a1b4051cc850d70df0431d00cf2804293a887b0dfe320634642042094bc17b33bc457059d7436436e496425652b1d8800404d3a6610728c8ce4658863af90216776e05e2a22f485c75903582201d486f00310dc11f8894531d015807007bc9ff282968f610713dee7de751707828ef0e276287a233749fe8d019625db01c0288e3be5c70540854861871c3716d48181bb75a63e5d4c0461a9d647c3be71973d599e10503307e320a660c6d89e1046188198cabf862cf5ee0d04547e6420b5bb8d68121240b162e5ba69c9e36b2bd79450d26e652514535223c1576b97fa778e96e2144b1a8dc163402a84b7d242465d5501921d65d1694623099b50754a0a8ef32453647eacdb33a211849bd9586f1079774848ea4128b5ddea559ef07814dd7a333d285b555542e6f14ed91a0b102ca9e356b8c9681cd74c7fb9fdfb8a0c9667183595914ea1e1d2c91b5e6c53d5dc14e19fbc8e0cb422fca617c032c82cc52e43590753300149bc9bf6744ce4c9e920ee92478296d3c87a575af49d1e6209352688d0f4cd43243f19e786a5ff4ea0edb3c3a6365f9b51fd592c2525471caef80607dfe1c06c2614c45a2c398c04eed7ce82aa162e8d3f7739eceb379ea1e749eeb6d9ed0b35cc69a0d098a68dcf9cd8707ff6b8a3a33a3344f19cd939bbc6c6b6eab68bf5938d2dd34e5eb12bae685dcc06b6e802d93b46316ebcb22ae6565b96c5b0a59b590c518b24e43163964850f590591a522b22a91f5f4843faf3f801ae480cdc57735823d7430438364090e18180df6959e153adefa5dadfe6414424565a9bfe757dee29156e3072494d7303a5d60250cc415545b2cc45fc263432a6b0a58b2027a0ec0421b2063222d49ba7156b7ecd8cdf315f01878d562d47bf6da7656cda752fa487ca98fd559b5e960ecd22e6bcc7eb6c92df0272b8d20185be5631781dc086c0632238657cd5f4b7133caafc931f4037743c02b823cb4ebbbed94cf8c22e98ebede457fc703784ac373e2e249f89168ac023f7771dd318fbd626acfb2eca5d6127eb8a4ead35ad29c8face77939e8923c2361ec570c575095490c8efb6a4756b3fa7abb446daf73b4fd07d0fa06d41d0fa17737a7b85011d2c8cf6b41454d0fe90595642fbbe5b0976f34190894f335ba9fbe0781aea2bc8b4df7f8d31e9330b2f8b1fab2fcb64ddf772dd2fcdbfcddba414b0eaf42ad486ae7da3131c0e327a12c996e2c3919970de3cacb97832ef75d1f7780f5a4148947660db6758d98eb8273b97258cc402e321b0772582c59a299176961dd0b12be47b69322456c7f8c64828a56171c1371a69c71ecaa6706b01f337b73c62bcf0abebb441e12d99c92c75209caae92f75b0ab2fd13ce4ef6df131cd6a9710d0756abc58147ed0b345cd4bafeb1e97d869bdcd2fc8711ad09384a0d187889ec96d4e84a3e37625bc0fd7297d50a0c65d2e59ec5cb115b9fbcdf3bd7d6946a60fa8b14b9d4141a4ad8adc23e433f9a2abe75766d377b17a13f396045d0ab0ac63fa5f602e3c7e0f5f2208faba7f0ab2b34c00a327e259df8a38ab945332e19768c9592c3b784fb7bc6721a2192eb794d55741a9659ad20810b3b633a1d210939b9edd3e0548af85f68269584864e175dd65a072bea88700ae4a8a03e847d43331301a03184b46b83c00f2fcf77b1fb3efdf05128a6e291a24f4e7ba0300fce61387399e69af1bea3819d45d1d9e8983d6ab9466253f666f0c64da09f726381ae1347dab8b635cec5343e4a987d4fd3430e937a987c405fe6380ea1c91ec574c91dfdf59b0ea82bf73f55a0386e62013b9a93411ca5552048bae857951f51f513344a4539ac725a51a3716e4c44c3f98f65fdbc8041eee22ebae1358b2e5e9a9adfb51f1e9b2e997a3f34eade35c9ae01ceb59ab79f39ec33d84f1a76f0684af020d7bb4ecc0256501ff5cc59989a7ef0bc313210f494e0f3a4d2193cebe7af7bcbdbb072cbd0ef91b8b2af4aa915d2c0335d904e4515d3aa9105ceb4e3dfcde4784935dcaa2ea30fe69831d96182d3b1dc93f6c9a0a22ce513d13380e403156427803de79cacd53ad1d305d829e42c0fca1149468a12604ca9bdfd4ae8649ff29e78e6676dfc213d2403c24b559fbb0e22db7e0b1a03c1f32e90b385cb5ae19e5feb0bfe9ac855ca5eaa210210945af7ed370828d9617e5041babaa520576af81c18b5fe4cd3e6ecc985ca82bf4944744a0d0efd693be24fe3ea8cf164af7ad0e419427c9e1b8a4ded9082c90c2fda8923578d099edc94c2452f973828746b1ee15ea63a2b379ae5fba134fb8063f1f55486c854ff21de7b2b4ad3ab48e6b2a07434d61fc1db16e4b64ab99518e8030b52637a21757b07c57daf93b4e2371cced9870c57aeda7abe2bc91d2e8f560dddc51e51f9de2d09dd76b22a042a5d66c0e48cc78414e9c9a28c5cef920a6050696de90a1c4b4f5009114be764797e3b27d3c179494d68f3564fb24cbc1d5ff2e2e1238698126810ec55a7e84418108999124fd5a6f81986327dda0d576219d4a92da5641446ab90b8d06aee5d780d8d274a273c76bf1b9cadabd82312903e1f5f9ee37a07ce4b10ba758bb1defb71d3e6b5c054fc6f20b2302d71785178031c175c3c632bd259d2d771c14cb02de9fa2ec829c9c42d280e1600256a3e7c663b7b9162cff7ae98e71f1fe0499b4abb998079d7668e3974b23e063503f68d7c7f3e924dbe7404a9866988564d572e03d3c27a5904d8b27831b04479828479d7190b6f4dfe9365812c5ffcfd83d0a261bd6ead1d9127e871d8442fbcea1087ebbf5e35d53e9735465b4ca72b8ac0aef6816fe4c061be96b68639f8306585e96d16534b03356c6137cbe914c270b5b6fffc8b5416e416903739e71c2c50af2f26e991807c3e9add68f3de7daa21698bca21001f39485f5de76a2fe52ed31490276945bad451e6cf252868e777f8942eb1002977ef3e0fe13fe01f873e0ed060ab7ede5414be1855e146d425decb059c988a2cb326f03edbe9cb8225d0bb4dfbd341e80bed0bd4408c4f41151255278b2d0bd50ba42c192a7b1835e9b5f26c1b88459d092c92293e705d1d12be17783111f40964801ee8f876d4af1ec8cc6b0c607b1719df130334f4eb63e2e7133106e81946ff89a5f6559c838455a310c13a8642a78a991544e43733006b58fa078648766c63078c698c891e319600b6905ac92135c39e8c1e2e264827aa55cb27c861a4ba111f9a79fd1f477c5cd225e0c08b79dc187d6ef89149ad7f583f0ba97bbadb03d4c486566d2128b63296c7aa4ebb8877b4bab41b33d104995a20f2c437123edfc838a4cba5fc820ef2525b97ae277c689b39042f168ef18de4230611431434bdc9376273b5bf88d81b719a97578d525b13ee40592827c2a76e329ffa5c4f59042cd496e7562fbc4c3d29cd2f303d98dc5c9bdf4e1a71a71122bfe338a71b7e22046bce2ff3172fc6897fb7d91cd1cc3514b7519dddd03d72983b309615df4ad0e409b9e067bf13c6996253607cf8c7e925424842256ce26dce9a44ffbde997578db380a6354d5f04403d3571a24c824af958897acf269e79004e1fbccf528228b5e6e1007c7aa76183af237fbad06e9f09fd81575ea055ec7a7344846c536dd69a50c9f5622409fcf59bd22e79fb0f1ca1c73ccd20eda55a985f0c220894d045659711196af4fbdd8644c00692c529f885030ab654a7daf29a4c3d3bdc53de31e9d2be29a43f829e86c98b505aa701d178adc073ec6e73fbc31acc88004888f31ebbbbf1aa61dfd24d9a4ba75ff44c72a4245f4b2220ba75a4fb8a670d54914e65383d8c4aca7167d23d411e106b808ea4f9bbddfa1b4bb661b3c806226fb4a461ff147a86897e2e6b9883cdf1319947c52f7eb8fbb8d0b78c987a0a1fd32d2c36cc4f9ad7361c848c225c490abab15568d5dc0a2186b13ff0d2c22017cf37c08480d976078f4bc478162ccb168150a312f99c5e2952aff99d5c38dcc2cbbaca2fff79ba73955bfe45c25fb494cee4dd00dc110e6cb9cee9ed47115ded5074f34a26fd6c4408be714ab2e7368882eaf8924551a4d17fa50c34847b32419842fea9a16dd31b42efebe57c9d762b6058a56a5381e4c9884c07b146574d12cb6e68783aa27cf755b1b2d503625a692feebc4039304d5e376ed3e3f1440d42e126c25257c5ca38d7342fa65751c48468d8fba9dbe53e262cddc9e4ea24a31ebf7f70535365325bfcf66d3447a32b60236c35e644feef3c110a36612f0d257d89a1c16b02ca3b4c8bcb1c84a6a21c00b7b1db214d892e96f077d5f8149653bee3a2ba0cfc93a0c75a8c9f27335ee3ed4438231d4ff439305a853d1428037087834aa6a3f1a6daf6a4bd6ac6229adfa9b85019c03e29149dd97135ace7aa23e0725b6271c30c61d5a5f56116baa0d54b6140915d851e54a1815f43933bcc6e94df2a44ed0f8b188dc0d7bf319588adc68a13200410f4796dbf2f38fb38250d92046d35d3b3d5bd6818f345f07fa983d6140aadfad08b9f0966aa2ffdff094749651fd87215e2017b2fc57a14d9d30d73602f5806e46e6c00d578ace76579295e38cb6862f86ddf96fb45af93a173ccebde8af3c1a57f4262870fc4dd84000db5e2838a9ccda8f172a164dae66ff709a308c4ef57c758434ac39639a09610acbf55c8187dde7c13cf7a075b6709205d414e6275e95109652a994ac28966349385aa67b28cee6844f50f59cd299cd47668fa9059921b360f0682264eab1918078dbc2bda64dfac285762ab2f73e458e332f54eb36c64be1ade53f6e01958a962aee7410f40e6061a467033dce577dc1d403f1dbf4c3e6aeb3808f71322b7f470e8d9e45f7ae6309317107006e6c9303c879679006243cfbd82b8a6b7a5c1a92ea7baa2f4a72962520daab48bb0e13c52962c64c4c57469d55881eecd340a89162a8d59675a0e7b8d2fb9231fae5abb76488df937824e444d384f085963254b9ab82075e29d371ce05b3cd2241ad91045a9f8ce869b0c2231dcee45b9ad765166d137472f6aa9468fd9257693bf053acee07d7a42fb5b8be2f7a1474b2e210c5422572c8b08d6e14b8554173ed1d398490826c75aa1af58819b71794f2d21d4696dc04a7c80e4b8ea5668a5f72ae0abe65febb08d16c496ae652d41a0b8f9562101873b7a13fabdd5162d1f329b773d92f7b6a05555e5573ee7b85310a61c49fb43ee86d5a8e5ff39e07cd734e91b48d463c6f4a3c0dc8e62b325baeb6ca6fb60749a046ab48ec7f8c0759e57abc27e5f8a96bd86443e0529808a5edb5e2cef6014276428647a9550d3f8fc735bb985a52a6a53ade1b178dc4220126981660a129f620dbe1061945e63a73c79162525c0527dd45bb14950059ded2a8412e832ccf8ae68cee58b94222ce387e2cef112fe3e59a3128e4847cfdb114aa7e6bfec6080a911a95358f654f3269ea5da080ed13a459239270f2332461e0fb007883da1cf44f3a9c09c3302f304db8fb62d75540ce64608faada2a899ce690a3728397952d6271c5ba46662f2cb7ea028a486e2d4c2f71d17205fa75163b84837b2061fdc2f2608b861ec8cdd022d6129d91a570e78a0c7f86eaf199d738fe9bbad54bf7a2764a5e75f047a5baf6223ce03648b283ae55150b5230ab3af3698cc7bbed1c039aa87874f867516d06614ae36c72fb599f7bcde502b49989e4d62d208cdbec1c5c8946c6fe43d05246adebf8aace1ddfdfa8d58b379470b55d95a4c1b49b53a4fbfbd4c47cd8fc8a3c0ffb1ed2e5aacaf29ebcf3645278a42dfa568eec58e32c4c1f49b9ada464cab89988d3332842f736ead60074cd962f939c68d31c07c02bd7ba405a0fccd5b780cafad880efb1239654c8ad70a6788726814d5c713b7712e2a532008153e287c12211fe42da9a592030c15643241e62314b0acbade5b5e25afa119461b7dab121f8061f4d12c6fbc0565cb4dbaf55d75f15104414a5cad9b4f7ce8f81877c720075a966d252cf29c66e263500c20484ac826a80fab96badd5d8a6151815c704165d80411a9b4ae2448dcea7207a913b2f57494ce1c335390ac71d5e569093e72f27724fbe6062d395ecca1edb833ab36bb3ff5820f603e46c8709b696a38ad40a998dda145ab4700538c00ef0024d414ea7a6abe9c3dd30af0a01e8c8eae19d0694617acb5b122ff8e750c79ac2ac9a25da8a1766ab2c32a94989203e42b4830cda11126790e3323dfcc67ce0245344b27e31c20ccb35f7d35cf3b076c4b476efd44ee5f15df58eb5ea5c8c4777e94e23990506e567444de878576b72c9936b9313012f7942acfdd49a803fb8946ec4967420aa207c3e83317eb701b08e15dae713404f031d2c4dc076dd067bb0f23c15225a63ab7eef18137072d6a0023fa3061cea2355d29436c413cde6c22945aefb34ba8dbac456b7ce53143a629a8508c28a4429dbc45cd5e6d05916876367e553dafadcf1885367e01f7291f12cdfc3968e7d6b58c140ba03ce1b6dccc432698707d6182345aef5c5adac45f0d7ea3a9aa3f506d6a024e00e718c530b86da62e9434ef35f5bf9f8e83cc86e5e0329f506b81661196478e22f1df765666edb9200edd4fd2acd6033c5fab8769361e6e1a7904c1569cf14cdc629e1831278e50b76a3308b7f7b0688563124bc82cc9d36832aee202a4797c7d3526810de0da63617df35f4b57d33375ed21f988e8f7252621e3e8e6a3e852e41734f27eefd8c6c02f5765748655d3e5f23228057835c8c406450651fcd92afb425bba61fe04209a554206567f9546ff6b4b3ecb14cf2360a4480f3b0401914fb11300b90e0b58f6ff177f07da18b5c16394447a30e800a60e0ba156384dd97b7c66b5b44e72ef63528d9f65fcb76ca07444067084868aad3394c14e4345940ba8319e89878c18e02b5390bc6aa81687a0c45e039700d7243bc25343ab52ef7827535ded4d8276c03cf39d5a8605d16c30f844e30001f24f2126d21fc907e844d251d3b3a3986c3049419f1baa35975a42e3f810bd48ba14fc52f419ef571104bfa182b7d6f11622a4fe463397295cc574a77d12aa773dbb4f8329a6df13bfc36692a6b7fab7e7365fafbf79f4b5fc8b47eba5295f112b99809ee3c7b64feaddb86c3e8b35ac3f56668833467629d54d037dcb268696544b68d293e7709a9b067618bb220a3ee6de4a3e4028d131aa3e66693c8d04317e92a884b4c70bde512248aa87ac631c3c0988596c720528e4074d0f2b0f64470a3779c99f4f403709f739b15dc25ef2d7bcef74d98e024f3b3256875b4892644f08748889a714e8939cec067801a8e070132f046d4f046536b68953cd4819c2edc476e697b452b77577a17aea43206fd69067f516abf690416c9e75d1324778df8f2c75a0251fa008ab6fd8affe9d9d3dbd03890cef33dd43489e42b672b34a152a2a568ab6883b276e09bdbd05cb303af17cdbde2a6366647fd492f17850ad3d80c27afcd3c7f5a834ec83e0318d6fa3fc978962ca4955fefa1ffe7f1144e42276a77e5bf88e1026ed590ff37a686cf1b86e77275bbe64dfcf79a40fe383d623054b2c7fa248c235028292b619f8b28828a6f207da75faf950375853f9b32d3a3808c728fe4bb33b81c36c5391cebd16e560903ff10696339b5efd0450bfad90e3345c192046f120f356495c291fe267c74d7f7d52b33872e3ec3b7696f2a5287fa64872e21f45ccce23836efcc9ff031ae6732153499096dbaf975710e6061c77897345c5cb2620ea0398750d2130860f5c60819d52a09b1f78be8b7630c868b7367121bc52bd2686bc0ca49f03e0344d9da361aada36caccca43bca38e1db8488e5846728ccbc4f9c415fcfe6374f01b596fcd403f64466a54e8a5a52a765b819f87c2b55b3e86dd80097d49ff93ffe0fab1ee2fc7bd4b50328c26814780fb992b78ea4d6ae8b2c864100058c584c37fc2cd049afd85b28a0e64a9ad26e08167880194785c7289292888b6edad055ce91b4b2eda59eb858f7152345fcfbeb84e34ce0dc173ab75b9548718e1a1a0dddbe95592ca74247da243d0f933c30f90f0878dc21be3114ed50d302f625a9af2bb6e14d62212f124f67b5e891256b011d287b50d84a153695cec013c6b7554f30737b63a807d4923ae71c4c4090094d854a34ef6a1ec35e3eff1448406a4c5d28ec2205e53b0107384caf82ba396d8e852aa828a4c4afe2b0336d6adf5a4d1dcc2a28c88b198482c8ceabad8fe89260c64926faa33bc87c9020e900369590e374ba5bce58494673e9a5a2c32953eb2d4e58d705d5095bea59f539c4b75ea99f757c53da259a1a8a9d0411f83ce0020b517ab7b61c34e74d56aaabfbf754d29e1e1f201144ac2b5b345c3e4ed4f39d2a47b125d492fd6d0573c6e42e50d0500c0bb00a0c7533972a6a43e5011598ec0fb3120f155f4efd82388018325ed6ee5f450a5dd9cfb414b4e9a8104c6ec4e81c3f9e111eb6a6f9830cf94aad7a846cfe895d450627aa921860d342e35bc7f1fbefa2f40ff3387666b40f35cdc4cb3c16cd381bc75c12a3ef34ca3680b37fae4a869d07a6d5339fcb39ac1dc0d17e2b03ff383216700c2ff38f5483556f179ef9bdbe6fb610189406aff8a6ad4c880a3b13269822386313c23e08e55491c2f3aece16f82252ef52ddb5b35e148466d2b8ba78389024796d88170ed5f3328680a4cf6f99436ce626ce194fbeba12032c3e5c884c2db2358198cb12247a4dd7fb67d7a6b53fcc26f082510f1cb7bb9fcc7138e9c1df465eb7be388d29b50aea3f0891e6f99bae38a563e9312b551700289df6258bd538046c264c38e17697721607ee72032ee8e54c1a9ceaa2fadfce35407d4702d620ad7037041658c1992ebd86fe0d2443940a205f701cfc44b7ffafd1e22e7fad99e7b4e741632c663b083febd26d76c72ff757fc58e1b5e063e5763b8de034c233e6ddd353b720babeb1f16132e6ca02c81e21cd87785f1a68622bf67e75e3c1eb0cb6f1280c8332315c4189871ac43b00186acabf51ce912829384aca0c822b6104d7b7f566e1ccc19d1380ce1656fd11828695910191a04a85495d87591638b66047e987db4c7c217a1aff97ab17bc06d6ad08992e9b426e2a08df1f82089380e6ecf76c307c9ccdcaea8c7f2565a783b97ef3500962b877de0eb054d3f40b84934f9c6d7ccc1e2ac0fc4295b36386eb1273e6c5f543b170ec4894ee2f887c2359c0bfbfb8df68284693ec0a712ccca09178b13129eb024d9190d0cf47ed66867744345da20331f8746668b3d6df4be1b09f95e02516b1915cc1a7921d91bdc47969eec49100bfcc36aacd4e3f6d42e5b39a7f10e6816aaa82842bdbd85cc2e5d0c20764443910d3560f529b9b0871099377ef10754979b93c97041a1d6066a178a4d69e6add81f6e8e915d7d0c3a19bcbd5672945b1a0366304862732c0262db59d51038365cb1fd086542888c4972ecc8759472000428470b16ea3508b20f27921a855437a2d2f44461944186202bdeda8de39b948c6a808989ba43d3b15a04c9ab4926f13e95443d45614c51d5e7e3b024bf332c7c875ec3490067c171a3784ede565a2fdf46269a0b3c3ed2ac130afe0d825fa6ca0e6708b6edaf4c2fdedc3d5376e28f82a8a877ccd5e309aaab4379d73541f08f2030a4da0ca5698f64d814e0f1dca502c605f49c28722a579f15565026cb408d7b46612bf5399c65425a4da80be4f7a63bfe62a45a4b0c3031fc2cc419a8889db5f24fe85ea816ff87113621098003253e00444679b1db8579cc9240c89c5cd461a0e2bb9ff1c77a9f20345c06de8c0fdb4baa86fda894231dc9f12fb8e102394125ca99ff233c51b76d202ca99885be0496581f289ff0c255e3e8526f47abf6c7a87d2fab06f09008a31cb0a27411ee16d221a6ddf12ce1543fc81193770bcc0ac0411ed0f89331901eeee63da64532328b412f580b30f848ece912a65365a4ff4aa7ca0595b749084bc952da547f806350817b5026eeae0006e6a9e903ca1bcb1e2f6d91c6f905ad03b80d922e2413d067a7bb900c2be2f0d440ec6d5b53eb0cf49e3cc0eaa3ec23922e500c30e976e30e05c0fffb32fb734704e5a6b8090a9528f5ef9b0e2d0800ff1b55899cd82fa8a84091ec81384329148696cc99bb6cf5575af993d0e59270fbc10661d9de54ab96bbd559bfef1bbd1f63390fc8d29891893346278bc4d74acdca88469fb975670282cc53ae972bba622eee5bdcdd2f423b26970f02cbcc7e6d61507cbae14d3c1aaee71e6321014037c4a41349d72384d0ccc8ab846d44b5a3eeddaedd02dbe81462a24d936205d86789fd4c561c897f55ec45c6948cb9c7a5e0f540ad2d46136f53497912b2e0a626693c527a9b15ff6bf496c8f1001835c3e273ce94d0dc4710f9213714d1fd23c6f39ce042355557d0af770468a1e7e31c6df820980811560ebb100e37e5abf27cf7520d81b2b433b2860f2923238b38397c19663baf539ebaaf5b2df1cb95e4418d7a53a3bd17a926fc31b39d244794fc0d449d0956ab96950bbfcb7a7c5a5ddf80cbdee1f0f71841e8677c92df0ce03cd8cc05c46e216326d397edcdc21bef998ce5f19893e883a08851dbd95aa6d87dffaef7da4056fbf1115a39aad913ed44ea77c42b1e903e11424b4f9b93bafa8c059d379c68e907e775a44ecfa7060aed8ed3733462ba9498c9b079be7e9b0178a4447f70185547a4f9e93861a883cb1c263314899e4b61848c86e078a0d2bc06a29d832db1ec3c9d1426a9cbcba29d6ab04df23e161584d39817e792a0f4205f066e60910b18eb8c29ee3d4e9b0af1d95c218bb792813a478622705f4abcf0c49e189e7b8704ab3c120c7b8034c495d4ab1bf5eca07fb5c70866008d80c63b6bbdba1343f6f4fd2d811c927637180796456c80247c25b982b085b094ca8caa4ad62b0fce47e50349305765ebc2d682ef718b205553fbd3c34293423678114ac0b9b0a60cab22f51d5746aedace914c33be85ebce46a5fac4825885f3880b3b2af683539bff2c4b37ebc9368558fd099c59e09d1954ddb7f5dc44751e2e5c3c8f736d138eaf88549c414dbe4e626ec6d2487cda72409bb264067414d97b3ad71228b2ea84a5860ea595f66fbf13ab28d8e40156b16afb8b3dc1dfe877f16818ad1f8a18895537503aa8eb3848ddb33e35c807db4c10b6cc4927e1f0ea140b0c52a6412f8c146a5a7850ae6e0076f98fa8aa5031beca975f92a08bfdf799a4cd4bf922d0c026523c83b33659ea6475425f21ca5ddd3278633e057e64810b71e1cbad074484ef89554b0e5e556c39da21fa9eb561a24a42c76192cbde08a5bd5ebd02eab89e18fcfcbf45e90eb379af373f772610f7b49c6dc200715ffd5b23eef607aadb0fc0a60cdfc31bfcee251ea7ec904190c7f8492644d4e3806593eb8e20ae43f657dc381f41ee002a2f2572a5aca99d58d3c57896ff1e82a581a4ec5951ccdbd35439f9c19796824be0ac0c91bee12ed96c16f15b7c5bd6197570ee62963e3bcdcc69a978067236f5f8205f6ef73cb8e489b01f000e9c8b42eff11680de68ceeb83dc3b84e931e55cd221056f3c3a160ab456ab01eb9e7198c2c157d18f07e00b88dc8e425b2697ea45e3746c78dfe02e181664e48ae460297e87a26d17f3fb5ec1a47b8c184f519ee6da3fa34319bdeb9972dd3f4243d6b61ce0eed72d1394c422dce64bc299df90662e3c24d4df135b52c34aa41dffb17c43502f4e1fac803dbc3d8a1984631a06f6a274cb3814b98d0c8a7ff377401733592e86048b8a869e6a5c914d3f716c40d0d2721e8b892ced8d422d202162e6081421634a014214b6b758443054ac029b489b61a911acd2e84f6ef41dd88253a33d3c1b3f781589db0cc431d7ec37760d35261f07df1d4393be05e0ac3d53fc11e25ae2d9c08c3d292204052925172201563533fcfa215f604f80418f63da92b7951614d201d3ff3b04b7b6a0150eb13d76419478aa002013a83f1101c7cd2c839900744a5532e85cac6be3265174eaf4121f3a2710ce52d12ee48be1f62903a3f7fbce3ff92709ef5bfced4f915c56fc9d41a72d81233e977751a8f45ca03d7a91df28b82527e2cea5bbf682daf78e27698aaea1da710a1e3bd7148a151a50b81ef0d2ee3c39623650d291e6ce14ea64f49c8442e197174df9a70c34e92c02b5f15008aa4d22a2126349050368edb65206bbf15b3ac711bcf0455df0362e92750a1a4d5355156267e025804ba4f10c6d3a5d87a213a4befb169b4e610c8016ca9c912a8aa803c16b6a43678cf4367d4728775edb6efc91daf240911f93c6a0da6dc8f292551f181431048828dc4eb86c6c456ee1779593224caa4e7ed9d700a396673d55502857dee06027704acee6e32a8a7951d58d042003fc86504899f2c31d0542731995ee9a09f1920484acc0b312d000a8188d601d37e1e43785964616107d43200f57fc68f0ee82c8d31f8ef28f39791ff8362d09626923e036e1a74eac10bad62ed2f53abca6d32f54e45b86da4fe58d54b21d84c9826df5b5357b02e8c752af25d29c9ae7441e495d6290cd6c684a53aab28961728712f66b308e85a14101553483d4b2a8511d7271896905e7318c5298b1c20296bc761e14eecc76e8021d511c4d36043fd5bc373027ab8e8126d823cd47395d4a8060cb51fcc15bff717574691b4378cb219029a37e628625ecb1ff5be7644dfa192204343ccf7ceda091040d87bc232418a9c3809a8538bba9d5f6c5fef3fa5a0fc631841b15d6055cb804e5a9ed93925f74b680479a1cea6ae58da1d95f93ca14dd7af161afb9f986bdc04c6ab67d1472fa238e4b470b84598b93af5aaa2c7125e17f6a472c654f1ae1815854e28da98bafa9b8914de4e80c1fe821ffb83011ae3230941f421dfb05f8d851e6aad667bb06feb45cc0c47d5e4a838f27e5868368c7f3708a8b9d57b25a372539f3da43d5b11f8e71ed3920583cb84cc99a605c21d24831f62740afb4830145ec445996ab9eb1ddc7b361a63c7a07508c2d32ae870ce5c3da3baa5176c10b512a0c691bf395dd35ca3644fa0145f88e6530e03264de976b45ec95591639ac2c67fa46d582daeea4bbd71acf0ad93e6f8ef9c2bf4432f5620dac7dcc1000aaa5f409abf4b5635b69367a02bb977e817774273e549c3211666306281b64f1d88ad1999d5ba026fb60842761c7992fc85b4d4526ed19c3015f4f3cc1671e8ea54cb3d41b5e1b6aa93499ec227d16668c0829b8278065b180bba0904cb41137dad440a20a98a8cb3e1aef5f29337e972440e7a94d58b12c8b7ce0a5325d776adb9e4278916de933d67bfcef2ffc45a05ec758367f67e3cee28b092609e5d75dcd8f4b18f981d8ca061ba86696e786799e4e2f8490bbe5c241103f44f433651803851c6f8c0a70fd7f540011c77fae446d3b2ee52cb660a3193f04585570e2afa664132eaa804f8783a07e051018dc6708c60baaa0640a4034f196d4bfa6bbebc27b50e99c106ec24ef05c4815dc38209ce364d0a8808e61b1bfc4eb8911820a298ecfc47b40b5394c7302f1744034166482ce7201bf7b48f3fcea0ca8c0c50b9a2922d064392b0ec9309fc3d8d4dedfc620abe4f9eff4694b1c75a61895e7131fc32f5df3824bb9d0fb21ba6cfc4f03ba3127e508b441b70431b36db5205be68576f48618fd131b0ddb860f2fa244c12cde62fe46449d6917e21ff24110d203cc5e8e8a2a8a19c66299618947d63d75181e2cc257302ff3c0ae5e76baa94c2893e0b960189c01ad74ed273b7a27e64f4b9039e33fd0fe27072088da9c071057304a4fe77fc6ccebbe01c7dbe18bfda058e9874a94b0d5dc090e786c5c4927f9e95f0673772a15137b4ce5e2459870bf0672692ddf46ddb63a204e31d07648b8bc0f7aa1e33ab5ef79ac442e08409d893c58e6a5cbaa2847c85d02adc44c91098f409d3d30c126a1c1930aa691b50b0ac70b823fba749ff8fa6342efcfc5dcadaacb9c7abc1f4c7d83b7025b36090fe6670ef363d03b9943bd61b812d455316f6336b1b3379a2dc998378c2cf22397b7ab545fb924b2980dbe28b4a0ccb409ea5d9098d8ec4559dfb64a273c30eb6f172c7e51b36af6f3acca33238d1d1cf925b04a4386290df1940aa9f5e6f515d2889620c1799ff7dba19ee4e9bac35f2eade63d5d48127560b34257faaa251cc1ab6bf94d75c16ce72ef621de23bed81fc5a7cb87251edb843ddcfac2395dbcacbd0272a39993e151ff3c7d1c6fa05c03a2ca8c318c1edf205e5a5803bf4250806df48906692dd2c5e7aed27c262c67d6cae3230597d9c34024ba5cd95697345f33537e3aecf2491cd7001bd3c005810eb24c1f69d6e40a9087f8ac313536408e453be3c9019b7c92c71173559ce68c00d0d7f1c17a2b7dbbde3aea4869d2df33400edbea4cba0fa524bd08d8d4c51368d1d5a27da90645eeb877259d698e38431f780a5a03bb9e20732cbe03ada648d2bb8a6e19784c7591e05658e4da41273fc42f0be553d8bcb40c2430efa9c3c06c19488f013251604ad3778a9911012ddc66da37adb11fc2d74ba38bcb0d0084f1f023a12340bf38b088a68a85dac4c55795eb0f9ff4a9a00d0604c38380bd3c124ccc52fcf3e7070138575b2d0c1fae53f0d0418b9a3df1c701032288ce173c371496dd821c14b450d40590908e04e36800a6df3f55eef445128071a10504403b9798aa9fe218bf30b103a3ceb3630b676eaf7481f190d944e0184d7a19ac700adb67c426749834c0d44c020fdc7406faeb8078748691ef0ea1e9ddb75f8f9803619a1ca2a60bb515f997bfb90708d4e506026cf21431ac97bc86e0a1a65a768dc83d5fab9503f1386aa8e61ea00e6a707b102f083b401648469fdbd19cbbe6ce12c100623745acc54274d56621285f2a9b3db9456aaff738f6d0fe75aafe4bee1918b4afce61d9f307b40dacf0841f19538f8450b81dfcf9d9797ff7380172bfcd7254b97cf3c9d6a02e675a9a0b4995d97b847dcc468b785817469e5323633190ea64c52625f033d447cb32c91dd56011ba2c9f4a663874e16a4a4ad436c28fae819e8549c7654a079fc3ca995a1514428c2bfb78391d76b33c1e9228c5a7ba9c62cbb4e8c0b444b4d96ca188f4b8aba736a8ebbf09d45fd625bb6faf0d873eeee060bb6184dcae77e9595cf42c6c4876ccd967f5b2393f490330c90eb598c66f93716054094ffc5e34f4f51c18016de499742c395aec2d0023010d742a10b07fd1eeecd891eb66d29a0bbe5f28786abce83094180eedb624a8fce915bd1be809d0ebd8215e16bbea0199bc790e8f28625a544277767a22dca4a16cc3fe3d346417d92e40d2aca4ddadbf1ebeb9e60ec645a095de486a36dddfa66483535c42d3a6e784d358a58c9fa32eba2abb11e1b81189a4fa092a033435951c17cb577f26ac03a1900b14cbcca24fcf075f1317c0d4c8d0b112fa017d3c4ebf7a5c20743edb1e1771751ac75d69e36ad6de5cd74d087c04be71d3e4d214abf2e65bb7f56e36b047d09cb0723b8ef0a7f504e6340c49f5e1e0e512ad561ff2b68efc8d7b456cb190945ce739f3f9fe07837626401018e6da29b9807e7054eacf2b5d669bb25e5382fa10cb28226d0331985239fef9621534d521c3fe54f080cdb186790ffaf1e070cc95fd29c5a2512cd1fc06d570328925f27f5142b25ed4aa8cb5c1ebddfdff965a4f44bbca4fda705284028fbabc04e338729817d82a83b2f90b03eaa3fe2be57621a0a100c182b7647f7f7d2086d9f6c2fe8bd59ed396ea963e299e9d49792a9f73a18688b639a62adffd9728d778a197e2aed79a769227d7633a742871f784b48bbfe87bc8f29c339b654606999df3db3bacc3cc67c2bb25310a99d1c2a81c4fb3c8d934a4289781f0e76896acfde1c0461929b1a19ff760e253065cf74d00c9921e7ce4577109676fe25a64c2c9f1151239156b722a0233db3b6fb9f3554553ca86ae8fab787521436abdb474ca3bdfb921588e29b4280c969329833d889bc276f0f45aca3130c249c5cab77ce26891f2b6c1598155dcc5d1bb0bad861dc86ed535f281d88a1fb4e170e2e8ac328e7869d515d6d52d0ffdf4409a8dcd167dc0108ee9d4fda88cd51e817e1a7838b0104c70214e83f8169cd02a1e12c6a42956759ec47ebec762c1af4df42efd4756d8659799d6967a952eb246de1906c28f80b750fa44c38f2358a56edc331816ad4e3afdebf51199855c884c2a32637805628473c793f366edfef064e4c3d808409c025a7b11f443eea834bc22ba2350d1b9f9c7c6d2f3d02b26ef30098a154a40dc4cabb2cddfe5d6a1534085e0da3db8ae44bcfcabdc0fda745e5047f5d11e8b71dc1b64fae3aff5f40bf8d56ba6d854d149c43e4ea7c611ab754c664ead9fc1f31802923499f7a06edd8aa6aa480936562664c556df646e45d5f4ad0f034ff16df7904fbe8f082f161c4d800b804b365bb0bb62e719a2bb06965e857d08be3404140cf4b76ba093ddc50d1e3ccf32a1016519164e8000760b79fd0bba8dc4ca2d20c15026b04af4c3e6d16fe2107a78cb451d19f0341d4ff35006762d4eb8ba2151acacf43f66655e16f04de8643b596c13a23b2792bc636687afe7e115c6e92ca3a82be25fe7286929f90ff173ef959cd65d0700470c0f49718428e2a5fcf23a0cf5580ec28b19f708c7a46dcb7e624ee49f1108b9a2177b744468c447d92b787506a759ddf4f49d482af2340862d65fae4e75fd511d5e6fed89e4b5cde4f4289a07f9996fd90b883caeab2f90b31f04fa0117c5148c80ce22c360e8af213fbb25cd309e61e1f3a4f8c5c6f89585a06f81885f1acdf858a8d4660741853cc59b201a07935942aebd336bb7e1b4eace4914635abab0a83e61b38a6e1e275c4f155d973e6283d1df03cc95e3630fbaf96d9c28cfd5529eba442675fdfd417b50c4d0cdc970d934914c487fceecf79e6ee465eac33305267b89e4419eb641c7880f804284da67146fd3996e5deca09ebc6449c52b3cf847ba1777573953367a2b7ba4050ebd02b6c3a2fcd4dbec749cf542e43baece4c5a075a393c4d5a27fc9cca1d0b5baeb2d3d67d3596e446cc64aa7fe7539d3378f64a75bcc9e8e111a1cf94293ea97b9d9ca8c161ceac8435e019b3939a1cb1c72f747c99ca61caf18d28edc06f0c93eb74d7636f4b42518ea821b12c882e129c96d55d4b2efc5dd363d2478675772dbaf94306ff6f6e1667fc57ef25d4c036a06e43b033b1bdcec073de9ba52ca6c9835a9c006ca3665b43d23414f24dd4216a9831810c7d17332470eaab8fd4973190933a48f0a5586863ad9db8ead4bc4ca7b3194612653f3acdb75e30999696cd3da132f83970265222edefb2f233359ea2917053c29d06f9eea7ea8c7223f29328b2e2d2fe29f1b401223fb573013c1a48b837498f790d1910955fde648d661cb1c56760762334f4d87b1891b913eee4a27f62061a5b3a9280babaaec7dd554ba640d2e5d46009e85df4fd1592e60d4b51987dcd8bf14e6f3a42e8a116ec95b9389c9642500a380c484b3f5b2f906ddcdf43d5629e9bc6e86700f415b2411fbaf8ebf409cf2356a109f79eefd105dcb1acb21f752a46e260eaa6ed42964cd34c8f05b3686034379ac958d38a376ddd96f41373fc5126f6f3d0269d7f4fb5e3201945722fe23b4fc587e7db33cfff9f73cb68d5912374ce86c12ce3c0f8700f8a880d132b42b804440f3a11a129bf16815f951923d0f7567d519be8473527fc16fa5b4ff41df7159c5804c4ef7df74d00f403665197aa7e8290b6a587c883f057bbfa37bdcb0722bc44d796d5bda4f0a6f33849ef4a6faf580a4a0fd2bbcde75102f7891a1f09a61fb112f3a86211447e8a3bbde353b41a8bdd84438c0055f273f9c3d1974034601083ab7f6369c1e795a6dc0887dfad16f891d9a46d831500925731881ddb058f76dc7e2241d26731a348cb6a3e28e582592c35247000c01afc140584b2f839426bafdbc0c46e05796dc2d48698025b4d6c11aa706400db06768d9366ff8307428e45c40ada0dcfa3a6e487ae4c60801afc2bf161267bcd327c57860499020e9e4a3e963788c50f36fe50d058a87c34a00ed5e6556969293742ccbff40aae3605ae82ae600b5c53b5252573ffaa641a4d62a315c8ea02a49863d8afff288bb800cba9fff792d5df716285f03942b9c5b1df916651555ec34c15fb727136abc603213aeaf63a5b5aedb5953f526a3a49cebfff0813b8d172ad7d4e31e16ee9bcfe3652d82bf57b0afd075b8ebbee5f6f94e5f880ec7a27e08f802993d60b3695aee70fcf639a4d6a6177f9f0b0fee68f65965367c9e336f98ca4c97097385bcabd7c93d9ed9e1f0ad96c54cdb55a52e3549fe82ee69d4c88b51b0bb236f3fd5fdaef1bdbe007be280081183df237f8c044d3692df706b931cd647e4295c3e122849960e2efb50ca6183028a8ab48741be3f7f2aa60085dc3496069dd3f97dfcdbbdff9107a9c795b1cc34c4948e3423ca48f4d430fe4c39ad451972b16571b86875b2190264fddae84427aaf9c297c02e19ef2e505060193bfe0c94676ad3e262b31106a3150bcfcd24291afd9ba2274525e4aeb81a26843b7f1838f0a844b086f94053b6882f82a18eb3845cfbde27f2234f2a572bad7922f6893368744f05fedc2d65841bb9ca0f6f99cfbe0347ae8b2ddd97a2a4b508d82c929ca06c28b3f275ad8e1f99c85f79201803310bd863cd521cd701708231e17742ea24f30c10245b4b5254df8406edbb5d810351fdf84229e91c3872081d1824626c85890b781641d57f172e4149a2d0e001a23e4866b03e2640180fc2a695cfdcfb2db3c85ae63d68dc92c54797f06e18a437fd12bb08c598796061bc6f171bcff279808be54de43be1bb585ad3c6a67e681ad919390df075cef1918e87cf348578b29562a674eda21bbb362856dbfa7f6256301a862237ffdbacde0d95a3ae33673a6de215e4f8915e49de02fdf88f6155469a2728cf9957586074550cf002ced50d6e4a189ec1aea447096bd0563d7845c005151f2b466fd949c44eb90302724b99c6759670775ba7cdd3ec15e1f8217a692535b42151ffd0538246ad11baa9eb65ecc97b52fe1b862ccb07070dfb2767aacce74070cdc38c97edd58026bab6601e58164c73fd37e5f6a5002645a2dfb0851a5ad6728a50c4678ccd7409d26621b64215f5aa38641449009101bb1b7adb96bec496e1f8fa510e853b442844964473c3ef1514e84c1521739c9fa67c0d384b2d7fd1457fd02d56606f58079de2e6c57cb6fe23148f656e5fb0daca51387d17452f10424ce8f5b6a6e4e25076d80b837db50220f67738312eaec9bc77be471874af78423f6c64b284ba3e172f21d2161426b0e5b1e38ea244718d2e048b5c181410535e7a2a8b4010fc92a9fd2203506cac73c8a1b7792020d7205cb3ad08c116ae64ed11e1fc95884a91ec7af580e90d22de45703d5e5f9dd794566dcc136abea204497eb77f8a0b84aa6dcc3d380236a0fc9a0281d222639d0c5f2412feaef7ae49417330629a6a5438333ae3270d56d5144cdaee3037b246f6d919bbbb66862d4fae151cbb84a0820daa6a07d11965c0a568ec6fb4de53ac11c88b99a8a4404242a10484a12f63843160d7904f3836367ccc583e4d1a92acd5b3412846eb3c0910221365b6e1a88390206e59661e18f5edbaeb820f4e4b95c684d42f418d37adb6504eaae98961f77520fca10bf2598fd69ae1c82d0e735eaecc24f33464a95638d751d4711ce36d3787f6ae925e7e3cae7c268c6e434bfe48b222403059682b92f79f36d83360abf6039516d2055c7a15a993e084e255955a05f83185ee295e92281639a63c9a9fbb7c0dccf732a34ee78ec9d24000c7dd0f5ab1a02d79c324195443468f54755547c2493c232a8357976d3f0cc4af4fadd69282b2c6fb5aad67d9920e09424bbc66c5efde181e80cbfd27394eb3a88db93aead9b5c4a89b03d4be124e78546ac4809776f09441721580516c99cff3f7bac84f0e8bead3ff0363869a291d56fd71fdb10231340ccefc15842620d826ec805e62e8d6a5fc977175cabb78fb60a74ddd27f595b3627d77e4687da60b4ad0e342cd70984bbaf1d50547788627b9e6f6b8596818cdf20a2df70a177b8106bb30d136bf16ea4059cbf6473a687bf41421ef292b4e643526a426c0bc984ee6407c57fa58abfa46757821f08a5e9e09e081336ef99d9d69662bc26e54c2082cc21e1672f2924e412a0e3d6b733c1d3e4e70d7a40e46b72a7f284497a330c002478cae2a2ed27a2e2b2d04263c061cb280b7a78737f521429fe408be040775097e3493eb2e106d14ccbde8da700d0d85ea9138e39a0af42773264a403c2cfbf7b09318446adc83b03b616935956ca1c6bd5e7044ed07102eb29ca27022deff239ca518480477ce40b65c55417443a263c1d15d293f5d1b3edc1229c92389fc71b3a48db4a869e8364e03d1eb7c354470cf005c642cbed53491ac322c670fdce1f497da8211a06d4a1c82d9a863910f8011a951800d4664c7c279f497ebb572ae75709dd14df06c43b2a548034c92626ec5772182cf4c80d60816446a9d0814cd7973cb50e486c07f98b281491001135a00d021b5faf5742888daa9aeccfc6af9933f5e8838277ad53228e11c593018c3b08c5443902a87a62c02320c94504d6420d51f27366e456fed3fe947bbd46bb72f826db9b33dd873046546905e6ea66a6ce2da9a00fc25510faf2fa6fae4892ab985f83cd0a46add4547de02c4c6632b4fa7ee597f45b58502ceff68f0d7cce04a5d7936f7b3fbc6ad13428d60de3c41d51861f145beb3d7a8156ffa718959115388c5bc8e93bab6847cc6ad346328c1a9097ecf8db6aec8f78a5ec190cb5cde3c11fd7e06aaa9d7a16adc686ab62c211e288eed8949890922602fab0753ccf90f3ba2ca93a59ac9400e2d66d5676c284d798fe796a30b6e0fc3bb6f55acca958c78a2dd5801c65e26f881d22719cd347bcf509fdc138031c8a8a2c54f1a45823934505878c6f659a2f5cbd31665729b9ef03206448679dcdcb7d9fdecb24a840299fd1dc13f6ae6aea20c2d17c7ae3044192b1462a1ea062f09b81cec2344835a495654bf3216854655df87c2ff3e71f9b8b2986b06d4761f17ccc20bc6f851bf31a8b031440fa10526601c8da84eac80af1a839caec0941fdecf24c42bd0c1cc726abfcab42e58380e844c3554a1bfc5892dbf3efada3304d4502e828e65fbd0fe9cf6f7b3a66065420bc5166593a664adc72ab0cead1eead7a1e03b4d266ae6d62926ec06427173c3593c081980a566401ef092ef8f7019c3f4dc1b077b082b15c2f18a704782d5415560ade48a62c2fdd51b0314516b0152794feec6f6fda89b963a19da63a637c9d567baade7a23cc3dbd04ef04c8d71ab7238cc5c172978b948b05ecbdc74a57b9818cd9bf29ac0187e009dd0dbbc8d5a85653fab37fdf515931d4b97d4f3d1b1260569871825e08c612e2763942141ba4cbb5f40f6e9f30900035129028a7777f9ff8266bc0b57f00b5a31936fe1d0238833cacf169f0a7ee99a0e4aa8506a234ddc5003ad1ea89bd1ef6edcc544416ffcbc81c3a72e3901242b290d3f8bd58edeb293326cc5f866e887bb17a22deabec2e3a2eaa74c4285728488746ef4fa3efc87b4c7ee5d640f5f407ba896a1a41d72491bbffb5f3d0bde2fafd9d2c2801648f5c616161b444e971890e44b160b134578189bd0855cb3849f1391b2e23a22918994ea5302cd30e9d9c58c203f7d78796b26cf911e577d236476b36f9819522a83cb33ef40cfabd103f4b8852fc525e179032fe60e853b01005258dc240459731c96fb94c4b4e6a40ac95284cd0801ab03160e1aecda3fb744bc23e20575de3efbbc831b374ab77411f089f698950c41bb18d499d10038da82c30e27f6e9155c8f4f2cf073dc9829fa4b6f7c91371d052fbf7ad7af899bd9e011f8c195cc7888d0456cd102225fa7a84ccf7a61af256a3fff23caf49584b852f38d43be7df1437b788590dbab6b7215940c1bc3285fe9ea250dc92f113843c37c29848a6d808b170368bbdd30ac805c5c139cdbe2cc566e58a69941816bc85c399248a29567ff816055a7b079188866b876eb82087898043968662172dfc8fc2d927c0c341dd4f1d556a427efa3f9beff0c409e3d8dc059e1571e408e5d8faba91be22e7f03977a2e145f79730f207611c1ce7535ee1c12b6985cbceabbb6160ffc0fce719e6597cab9a06ae41d1060a606ef513996ef18d574909f0573e1829c658e55f4108357097d1150439ee503ec7e9ffb7e9f6a351ac3ff90d2fd405977e0611ce706753c44bfcc0806bda7a0927772d068a3f47d6a7b45f49c54cf019f2f0d2b7b0d4954eef1be400690b1727f5709c5a674233715bb07a821703b232bd40735b0278080462405e6157b09b223f200bd12f29baa961e860d511b4a6f1558876d6bf1d640c5f09adeca19f25d74043e51d5dbe8fc3c432f5152438bea59997234bf1f4b2ef634c61b8b46f915487f375a0a4328f5fdd3c784003a715d7e8957c0b7c20528b4bdf08e806eba51202d47d5fc893c89c018d076f55383148ce936804610485b772db88b9c117185bbede264dc95fdb0f424610762c748657e9eba5d0aa5144d0cf790d9bb8f3fde03f1c15768e0469057d05f9d183529f1d40175f3f7bc2e4cbb934c123ae4934995a3447884cd28fb62079809df3ad5e41319ad8939f7ef3131520f2fc26a79b394d42dfa9cbce4ac758300e30a88103c284fa71f0683580ee9df05459364827f66d88619a58f59cca59355b9884a07ae6a3a08c9695b8bd52cd447d0bf0c11d10e698b565fee08199f5830991efafebed4b3684f382cdc2e673638be9b41b5d31934d9531cf4de62eb5d81571b5e15ea0136e078395d9ff207bd785cad54fcad54e1110a3b6f1e10f3b158f897f2632e136b4451e6271602b8d7b40fe12159b4b11abd89f727a1543d1587aa7af822e82e79b451bfa2cc3d58c2b29f984b1480a1b5ea2f37b9cd16131a589cd7f734320c0ccbcee23ebca7a7545f88615eb5a5f1c2a16ecd93ab69903c7d5e419d16a6c6040b1687df645df4914e03f08a64611d2198c6d213c5553e9911776ebc183605b86fcccbba06810ecdc7312893716358c733ad3d8c29a52bced5f9c7b84d17efe610776d49dc7f93ae05f3997235f7f8e8199a86ed5e4d83bb3114baa9f5f5ef775d36a96b8774c6c47c73f02ee9a3a8175951daf2982aacbe520a382ce976a25d35b987a8c13b23aede55cbf039571f96abc797c99ba4098d0db4f16b3bf16df256652116088ece3eb3d370b15e3ecdcaa7a233f843ede2b678b43ac646997f588c3fd0ee05a6311be3b56fc40265be22b9907f50180c48a9b4ae425c20031ac90774babe30443b95e54ee8d0ecd1966cd3296eba0513ae38d95e0eb7901abdbffd050c4f39a5e040d0982d4726a344dc163f6d52668d5239e48e5563703de72c59873bedce5a452f3898bca27041b4c5091f1bcfea65622cf70f978b0d7068d2005cbbabefce420d96c388074d905c986cf04a638a71c9e1d5ca550aadf852470dedca8b0700d07e70384e472f9e3b022c1250d02b62883c453ca15f1135f99dc4a9b59a313f7bcff14229f4de222263f6f6f75d945768ebce7f7700d5b9fd7974d54c0e129b9d55ac4710418450d468d2064486d4b29eb151b452ab2d0307ed427dc512fa68e8bf2fb425dd4beefb1b6ad0263137c8a0285964d69d429b1f2903648826be0bbe09fd0c1e6a277b384a4aa805cb2c202895c0d96b91969fca69710781d29dbae9052c1172e8e26f88bc4a8460186306dbaafda0f6dda11a1bfa2dee8d24bb13d30ca9d03c1762c9b32b7c40ea898d41223bb43a7fc083c499571a579b9aa97c0948e299322323c9d605e4eefd44f07f5d65eb889a5bb6fc742df62c6334d56a5de6c8b2c67d7fd2b699b1a444b51080bab93f6814d755985a57094412bc6a545cd8683b119177941d161bba84ee3bf3326c2a42beecd8669dd2126533673e098deab96394eca6b8f984c45cc6ba3515f26d9cce6ef1c2490056dd4083ab68341d790048ad1c97102b985dacbc95195f1ebc93bd388bbcff4408b6696f51064cbe9e82a23332dbf8eb9c4a27aee4ec724d87a25545fe877f5504a0237dbd9298aec721241e6d486d228c4690822622bb39d95dc934b4cb6f4de05eb00b9d2088d82aea561c8ee0479c6dab7ea953c7fa9a9a190a04a2ee7b3bc8b41e232092ab21a39b67d5e2ddac59001cb196085f6005deeb7074938d48f40d3bafaef8eff2a46be875bd89e820eeb0eb25dc5459029ca15fad641002c967bde0afd5202686c50423bd239f98194ba69a1de34ae9eab042566cdef38f8be8058685a8b2c3457e6b15672c4b90c537615d4f27817aae374e5c245dbb6de6bbc6e61b03bfbabf30ac6a0236c4b76739d1ea709e2a62b2883ddc26aa7b0797e0dc026b96f8d4e14892dec95de27a0edb93239d18ab4ee7100e028a503a97fc0228df24148c827a8beee9708338d4635e746310981d8f2f563f82c92a9e208d42b0c77d4cdea8b31cb1091f533fd224979db31bc186e566d4f1847b44d6d42263ef4bfcf91737c0c3f54ee5dcc6aa456548b5f39b817120013b9dedf08a588a00a3d6320317e8685d54866fa6f63e2e73c6aa46b4ed45c79e3e9da9c5bb789987357f0dc62e8686e62852be734888ecff0be60fd2956b1c45a6c633196d8c656ac6289cd58c5526cb18ca5d8c52eb6b18bad5862195bb18a8dfffdaffd53ddfefcf77f41fbf15d8b57f311b78e48ccd40cf62a3754a136f9e06a37b45db9eabf08d7e624f46f983c0240aaccd36c318285ea2c3dd1c2518d9b1cfe447cb9c7cadd18ac47a1b21e9cf7b424f6e6a5db6d89aa67953348a3352367f32f60eaecad1451860a85e05985730c3b3c260f1e6cde05a3e38e50a76d5569529c1ba035de710f5068ee9c89f65e0d8d0612a7bf7afd907fe2f8e7edf16197dfa35e26b32e896bbb435580e438be3b0d598abd15366c175dd9cffc62124822bde21592a9a663fa96395143c8ade2edb8954489134bcc081f0fa196354829eae48969ef639191528c6a41d0ebb80744ad306aab507d2e3dd3b5cc111b42ee6b6f458d248ab85862b65a1f00b59480570d83a276d7cc412ff96aa3d0b5926fde0476736dd1454ec6cb4aabb4516d0b6be6a4fe0fa8bf9e0de580c902fbc47d96f4cabbb90f9ce45a0b9fd374c09ab58d42637e2f1d0f1bc061c85b6f7d7d307bd36a19075015dc32601f0d45dc2e1b8a0111c16f8dd57dddc6119aebd39be42b30d09311a4e52d7e5acbef475e1e40b4bc27c2c0c4b2535ca40e41951f373660c011893fc8299920e45c5faf0879a0b78b7c195600e548a98a810aa416237088a1c1b2754597961b97f9acddf1ea6f35d13fffff7303b6ce2b7c6a55623383c6807202bd5335e465862ade10b67238a28d8b4f0af112388c85c40f90319b71e7ce76e2d4e027c3afc455512817c992329a45402a95941e0742f4b1197a6767607f5fc30c368cca1f57685597fac89ff345818d6bff33f70b3ffb7b5e71eafe7a9b127cf7fe8fb820c46ccf44b999897e4383adb7ac0117890ead20416f623163ca1ade2d481266306e6b4830b9e6f7376a14f74199f578eb4e327b8c3fa478be46f97383baca4645fb80b9e382cf29df570037c747ca6f0e0a02d711f31db0ace08d359bad41c5bcdd7b36af24c27123deb7afcc9c716b97b119cc1ac084efd428b0c1571352b088632c64eb2a4d0956d8f178f97054415132c7c62eccb7a961258d584d5451ff31698a8bd551c3cb9eea95afb0c77f582a803bbbce581b42fa8429482e821c17778aa29757a82adf64ff579e4a758e928d81a20f68c8c19515290c73f440fc263895a090ba2c0ca24aee182f05e52641d39a40132c8cf09a3527cb817aabcbf88d506078d98cbc96eb82f411adebcaf81f271d52f7b6f542529e453b76819ef0f8c80e0940e0802b3e861d28dd39656e8bee68ce5d8c82676ebb8cb8c1e4b29e1a43ec5ed80cda90f53f838ca3e98d167c686e17225090fee818f4eb9731137af1e9ef789710845d68a24487049c94611f0c3af72dc16280cd24fcd5dbde0268ea2d4d0e4c10a5f3662cbb05a13085285c308279207caeea59b4d6fd5fee98c3e74d1cde4e416c32994b628095f088f0a2aabb2498b065c53d9bbed54db13d2887b9c306efcb996243d19d50d7d2fc7f896774d15154fee0e7adb1158fe260292f60194fa88410e0dad7963621f22b13bfd076778724101962246e9095c1b13a9b9de51f011714b66194473ede2e5c1f8f975981db21285fd6912a665dfa7b727d515550fd0f019058b0b4200ace7b2c0f0ae225d722058967fb4110a0661c63bd71f0bbf1374b8b4b100532d0e1166f2d4f33dea00556754ad71f6a0ce4baf4c901a14e174cf002e99c1ba364d5a7e5ac5c5eee23f6e657a979e4510f1c8158fc806e8a99e53e37cc9d7592bff835869d389a268ed98f9aeaae19e5b57a78b5c0db7867152df3f84363834b0a1def7f30a1cf1f2abc11a2425a8d0f14acc08bf794ff74c9fbdf4be7be2e38c8636254d929d910050cd546f05f767aa1d5883b504b4082dd3414d9f694c992d381bf643bae02733e3725471ed4656c775abd2cc76b1e24d92d1900f0a16316b401a110d0f438fb786ee071f9cf0db523f3124a3bcf834b02a4d29d51085f36deb854e63f5aa93a112383ce0387a81641039a58a810b91db338123b82f430e572bf2b1e89f4b2c4b1b6494329d24b28027e38e612cc79b6e81dc42de0b3763ebb801c3accf8c88ab7a96e9e858b5aecaff6ad8611a416a06c1bfda61b6ef5b7589515476a17433304942a2a37ebd0b284602598bb2633bf8d303c06fceb2fb0b8585a03bc7b88628462c1619cc326b170dcc76dfb347c28833ec329c5401bca53f99578e6e115418319f2f689013998dd9a4ea78f752193cd0b4cdb26a1b4eab14b45b517f2498ad83fa184d4cfbf1ed18b372139233b07b821e4d1eeb3d202e9bfde177ca63e1683dabb27263dd58fa79b69abef3c8c13484378410d10966bc5b98c98cfccac6b948a6150bb749fe3cda2ea40255cf207dd020af7f8fbe16f1a05cc5a89e50a000df584a9a610c214b35cac52dff972104821306e62bc4172c2d56c21112dac4ff55efc525ea140f27c12381af7f134b2005803f428b0c32bba55f39e6d6ccf055242fa5632379bf47eaf5b075c5e57784e1fbd3fd7d898d551ac220cb85d4d8d3b48d612757b6b2346a5a7216e25a46e14019ca01e37238e3a31459b271502153a9416cbe387fd8826a4adfbd738dd3c2c356a2947656325df3a349f984ed20c72a4340d44b66a57a2b20d93c3320472f9a45431e921098a958a288e4e04016d10dcf6dcd8582040bbce8d87a757569b061d54f7ff6131ab81e15599f8a23471f09fbabd67c42e9ece680c41b59971619eab318f06ac67e6f091b62c897dfb934f550d080b71ac3c89b84e137739b9fc388942f7ed39732de7c0a47ba9e3cc6dd418191a3f79aa890433fa4d070ab4bfd4d5bd1b49b1c6ce63a6e850e0e8fd62238173b03416b439e05b1711d35e7a3b31449921b023ee833702378470e362e01b71ffb5c2d47829360640458c08cd49e1389476b7326dfe84cd78db427727b76e7f3fbdc7282e0f6cea615cff136f98921f49fd43157f07c2cb4e182fed0c4e4b554f47e5d10ef43430d18726f767114e5ab3569efb1fe9374e165d2978b9a01427f0247d293253dfefcd9384de45c9bc4e6ea568cc9c5cd358c7234fea4a96de607cd393b87912b66c42540eb0f93126b042c0fbf62fc08d6b3079e9c4bcb74874a0783f68c6114bad9cab60761564c3b3545c5ab91f704370237463f006506edc01bb49fe9968bafeed45110f33bb4b23286e8f9cba60fa95ed6d0ba1a9236d433b3c3154a167bd38b36be82a10ed1168a71fcf2771696b91776ec2319a095a3a96e5e40950e34b49abb55bba76fd5957e3570270e97166d76de329b005ce41247a5d7091878a25900c06306f2e033425c35c03ef96fc52b68d28cb84f66976d2553bce7110f0b114f6b1d2aad7f4c4c3efb15e91207f92c4bd434ceee8d87bc846c48b77ad4b5a462e984bbc408c586c28ea437287376929a1efa51ce7d3d6c743f1a15529e8b7da9448e4d5819358892700cde802517bafc064917723f13ad291b39f3de0dd47dba4034e12dd170c2c1114b7097ed2b7ef2368d4d336f7aa4aeb9ae3f0f03ad1b812484a871dcbb27b534e5960e8f953c9ef78f00ade1ce0476d1972f53b13b76016a6980029fdacd5ec4a66542ae4ac57456ed7751e6e5083d2a8dc851039e2a461e3752c78cad50ae335932c70cd6127d9f03e5d926a9bb73437c29ad7b16eecb4b0ef4b101c19775ce6a858f06964d51c026c3924b9715fc53e41cdd7992f9373d30dc437ca1e0a0789412c579bb4fb5607e4e7bf6912f75f59fd5102aeb626dc0bf3f005cc7eec71e728c7de93b4b459c242e1b8e9285852a8162f69304fbe91837867e8434eb7bea66b7a89e6ce39ba03f9ab700a89ac100e95b11630485652f4be58efd7df8e820fc04bcb2dc259f872d7fa58ab2c30371e99471442ec303b3f1ee74bdd2cfe996f28b5697fef2ef77b86ba230b0c424becf4cd155055603736bea845336ca73e38d27881e3ca2c3133c9a6fc5c41d3d10fc7e275c708a59ee5a565fc2600d8648724bd33b969e8a053ac7117fbfd295128d0ae4b4b15f6e203499930feb9b572b37c926abef594e66ea80c41120639f090af4da637d210267a40f0eb63e28d21a1a9b395f5d5f8d140b5764fcfd007304f20d655fb7f64040c2b3704f0177e91d22ee060c6d9601b0ad6ab0a8f7e54df95ca07e55cad2bc07a55b924f87413887672bc1b198c2060151e5ef2bcb9a830e47f0bbadaa1e40ac3884be6eaafe3b8af24c7e96b90b98810c242433b5ee17b6b85f9e3ac62af78de77575f2ee4bdd0a4d26e56901db84952ac3c1011d2ec0ece2ab73265e46b4e0c5edc1f7a0497957134336e6736ec6ab424971a15c9c93189f94ba7be568d8cfda8112a5505538364fba101278e7b034c03369550f7d0cb9e45113cf9566ecb3fde71223f38255bfdf641b62f36750b1adf054e985e6591b0f8c162210e241456ac23c8894fccc43dddcf2ccf6909642cdfda3663beab060cd3ca351a536e783d5a2433f66527c0d8c479a06c4516caf2396660d1d1ec4fdabe5afc6c6ba72f0bfdbedbb76ecef25e96c4ea2309ab7a834b1a477c3bf71ef15b4951e122db1dc4e675dd0392f3d724a239a39d039d5a382c8cadc92c7445aff78f8b67b889b755d8b179157d4df078e41b769c47190ad4db82fafb171c109ed71cbcdef48dc6994fffb8d3239f03f4440234d0035a07e39d5b30561d710e69a0fd5a4fe380229cc0977768965e18852881eff4a000dbabe43ed8e5fa30ca403691c27d3082ffad6ae7bd92a3f9740de623c7e903a915155485f4172fd1de7a18a08f9bb16fffdbcfda77e993d0d2922da59449ca900aba098509369bcd368e2d961071884389b2b269e2c771400234445484080f0a45a6522ad56a457b924ce95a45a2521959ad860005d1fe8e18fb8454467425b4da84955b10908f102150b75464c88d112f802455aa95ae957ec56209f1afe4bbbd23f9200e9188994a133e4384040d7184109428f8a708cd49d779df078261a83dd13d5d13752dbca1d6b5590e47ba16532a954a25140a85e281daa13aa16837cc3412a96432b59c74edff8442919e58fa92ae89ba860aad2667aa18d24875025b30d82c8634529daa378ba9411ad1a0b972ce61d775b318d2c80b3b4d7beffb401004c330d45acf62682f8e46e3389248a55289b424e99592356ad4a8417bd3e98442a1c8542a45f2f0f0f0f0f0dcb8c1c383e3c5eb7baa12217cd624052c961d1e6270cc38120017b0175290518fa017560831c411423ffc0060082bd5cdfed83835861620b6d8ac879be9430568c860d80193830e128fe746a9643a9d50a877adaa1093e984423d49ce4a93ae8d2f2e249952a95eab55e9224b2c564bd76a904bd74aef027abd60309f9f9fd2c6e7e75d2bb717675d6bf9ec8dcfc2327ef9e2e234fc63b9f3e232a3060d9144228de3972f2ea4902c85a4c9743aa1308a2453a971fcb2468d1a35be30d456d35e1c8d46e3cececece38eae8e8e8e8e8e8e8e8e8e8e8340902f48a312a67b60afcd0c4edc74f9092204260fa28c120793c0cd1d19283c5adc78605478c0eeb53d4b47654ec9801abd1a2070d1e590e60ec756dfc374ddacb55b2788cf1a2b96c25cc715de78d5efd3e10a4bd5cdf799fae8dff8561a8add65ea9a6d162c48811c3478f9d9d9d1d1eccb3338eb8495dc2c8ea35fb09d29143089a128b0b0e529123416e85454b0a54000493c5e879b1b1669830746ec468c4ecf0782e5da3bdeba56b28182ca66bb48ffd934662252023b0d66853d616d9cf5dbd4bbc4750b4590c2ef2628d48828c4ca149d022588bc57c7109758df6a10eb528eada0c357ab17cca250bf8181a490b5d890721c410479486b45a86407f7ccad5b3984558318060361c6c66bc784ca6130a4592295d6bf9d47d213e3e3647ec2d1224fefcc0708831a96be593b194aebd4ad764af2a7f1563e95acbb35ab6d5f24a5b2d4fbc3f968ae09f170c09901157cb87b512853cec65b3d96c369bcd66b3d96c3756b2bc982d4248a248092b41acd50f12232f73c1e1486988e7744291642aa552adec6ae595ae5648622e1b14ca88a952ad740df62b9627e220244882ca179298cb46bca531fff80809f548879dfec46ee323402c7305a30931c411422e4fc29fb8d91f5e64a4f5414362a805984cf84fba5642a14812a774adf5a9abb22a9557aa527922f9a3909185a40aa1b956370624a260364738b2092b3f5a4e13f24250a278125ee44a5881d9945e2312d70f50a9643a9d502852d7723cc922e589fea69a0b195a9d5ae9d8d1e3038542a150281a8d86a2d160baf67a584cd758af6b29fecbb2ac7953d7666fb278621502d3355a2bb65ab578bceb9a8a776b752df6f6de0b335d2e988f520bd305c3489121438ce89015c9c1a2055596a6aebd7a9e85a545a66bff321a9792a96be2832c61d5e2bf30c6586cd8a26be2bb84578bdfc35b965998f50dc74cc868bec060e6f83e8c5e60e39364356529ab297900b55a4027242d569e0e1815058ad5bba06bb114ba5657f0296254e81acbab589d1e000058e189e3bb9022aca50b005684174511305c588459c3f4a0b977765f60c18ed9fd17c6159e8e971ad37c0980113e6acc9e2324c9a3a5857c1e2de457c008cbf57ab15404915caf143ce028a14a65bd28195d5bbdcccc0b5debf9172e18306874ad7c9a1a5b53e395d6d4c8e81af994d6eaae6be3bbb5bad67a0bc38505c991a07aa4452ca8e5c95558cb4aa36bb4a7a9d13554ca448b11c3c91d3a7cf488751c51344ceed0e1a3c7c58a01da779ef77dba86fffbc2300c533695f24a539de824b943878f1e71dcd9d9d9d9d161a869af457134d235fca351d7683f9248249665b1bc5256273a49eed0510a499af625d2643a85275dc37f2251ba467b14499224f9b2af9757faea4427c954486adaa754a16ab5d235fc2b96aed19ed56ab59c245ba14bd3be0573e91aeac1d84bd7f0bf60652ce624f9e3a74c376e504ca3a168281acdbbbc0a3a891fe732234a0f1d2a4b3031dbf1820e2f0c015d21c4103e3bc2672e042588911e802451a4849527644a7bbbc0cbb533040f56e8c70bd80d341610236605b612461130b21a2c5841e325071f2e6020f2834f0658a4a0142ef0d4e81aed6b62e81aed63a81e06187c2463663b789c3c2f955034ac22c798198d1a30ece09183a3c293a63d8a2453614ad7f0a752a14ad768af5aad56a52d4bafb41c4732665662852b4d7b56abe572e91a7ed7eb5561305827fa8f64cc0c0618608081f631f2bf2c4bd23449161616f2c5bebc78a52f9de82339923468d0a0d103ed652d2dba867ad02574d135fc2e23ed5fc6d96c446151a0f04a5174a293e3f8128e65dd22499215488c1816a817e0e1b9e1b41b4eab4c9c87a7f4e3c5908fd1e34263ab4b5426583c080fc1103e907abcb0228922259eb037fbc312b145ac111ba4732aed103a329043070f9f01519508d102c4476ca787db0c93c6a8023560d87173006a81c4bb81b241b980c206470c0beb0504c41ad1ca1750cd8c6cc556ab160f1f97d86a07cd0bcc74b9603e5a98ae1e24183f3a84783c0c69c9c1e288add50685c205161c312410eb558e6835b3552b36c38587cfcb0e9a9d1f17cca4d1c2078c1ea41ab79e870952811f5e7512b224071b1b940b2840161616f0b6d89616afb4a5139df50202628d68e50ba86646b662ab558b878f4b6cb583e6458810214284542142901829f260fd6109495948822d362d360fba84644896147c09c917142f2139b3f91b27713c0813923021c9f2375efd69ac1710d08856be806a664f83c64f908a07c3d006e502398e248e27e95acc93487fbac97bef55f1477e682968658a183162c4700145b94447e706be8143493d00b471c45a7f626d220426485999a0566e3f7cf613a42404311e2aa24c392561fa80d18344c41619528447470b8b1c52d0535615d45a44959284cfea508c1435b6d60c971d3b345a946a18918939461c3a3784368a060484f2817ba068403132987fcbc686a6f517860b4bac050e529167d1e2736b0542d17af8c0b018196964c8cae69a955e2f650c56cba4195960b8f8a886c70e1d397c3a0ffc803e1044813e1e0c71d823a401c5c83ad1c9212b234686cc4aae959197f245d61b376ad083201886a1aea17ca0c43ad235d98f604e2229f5902449f63c59da6dcbb61ee59205bc0ff79d1ddfd971dfd9f19d1d14cd69a34f245d098fd283d8517a088c1cf12a9108c1a645c302c3e50707a948d08d1645582b545356262a2cc86f436c2e7f8931c31c7562228b1818342d5ac0d0411ac1a0699103478dcf8b65968a1c295d36fe23fe8dbd58eed6deab6b18639cc39ccd52e91a6f6eb6aec1d0411ac16891e363d0351c1f43edeb8d891845c3a3592aeb0c1ce29c69cf755d576badf5d65ac7711c59c4e8e8e8e8e8e8e8e8d0747494f83451adf8ed87ff04cd8670c44811f3e6d282e467085bc48c20a88a10d41542402d18a41c4ea56413573766613c3636b418316080e1e6c6e7e7c7577eefbdb5ea1a0d15b3f7ea1a0d63f26180a1c4f15bd758fcc6d1b596c719bd00748de60510838d2106af3486184c1909868bec6f4d8b97a0d5583262039491a068b0183e32249b362107aa8201d5873eb14feac4f677ea84ed536e28da5e89d411100bdba77daa927cbdf72a61041bdc1489224535a0538e588c31f6809c5822882a2528c1ed08911220c8d6fbf138175fe7d9eb7eb0d96f66a0423178266beac49c21121b5802576bad496bf8b141a58a119614e140131dec8033655022efa80ccf9f5983cf7e5071d9bc89e17a8c8b0686a0811324424d0002c7bff31fa5b0fd4f2aff771fb0b0fd53b84c18a3daf4890f43d8e1a64f7cd0c13e63beaa770052c71d0f22b68a0fb618638cb13b768c31c6d81d3bc6eed6b1c518638cab63c7f83a768c31c6d831c6d85ac716638c31c68e31c618e3305b6b33768cdd3c6d9410e088b69b3ad41eae96a40052d9e95274cb6a4723d895ed573030e233c56434e5de6b8ea660a2f11c35d9dec467fed72cc240fd6a8ea3281cd10046443122a3a1d1900cae1d1bc5886c277bc865a28ca6d4d114aac2ad0bc69190cb9ca326234a435d8a3000d2b7f65e0ddc6bafb5d65a6b6db5d6560bbafbb5b6bbeec3786f775dffaa93eae4ea303e724dd96cf6ae77c954d65a6badb51d47c41195600052d96912d9f8c16d65f4284db73137446758ecbf85bdb5e74966f5b1b73f5219d5a7feb435a2137405a5c96f4f6ecac6e7f7c4c60f826fdaa858f9ba6261f0abca32895a59544ea12af0672da324b230b01bf954bfae9465cb3c7910710d8cab6f95366c15aa6b18597fe3e595ca52529c5c9636f593e9643a9d9ebae9cfdfa7d936fd39db27255138aea35cd775a4fd3abbfd728d5de7d1cef33c97909326a4a7de3ac74dfa5c8e9b95ff4a0c66b59229574b568fdf55be7e546ae244a8f4ad122bc9f8af2b2ea3cae5682b01fb010b4241fa59f185f1f5848d9bcf706d7dce39e7565ead5a7995ffc6e65a9e2df3f584cfb009fbe133fcbae233cc4a924b71b394af220b833f56fe2082a564b7cc92e5c4c2e08795ac261606ff972c26168695c4c2e0d71555f9aae233fcacf2d584070097e68b8acfb079dbf8cf17958ddfbcfdf018411e87f5f8cd202e533e7ef347f5e5e36f95af0f9f95443f7e16133bf38f9fd5c4cec41e3fcb899d813dd6e29faf2b3b56b21e56c6de2c619f4bbd5949f6ebcfd2958d5d0f869dd8fab25cc2facf1fcb0fcbff2acfcb646797799e76fe5649a98afcac72a5da1d558173aa3c452c6cfc647976a8f284fdd8f84f2410364aa93cad124a8cca9335b4f18be579b5f8c439db272bc9c67f92409cb689f37565e3ef48206c12fb149f184068762611eba3f6a032e904748cbbfc61fdcce960a41b2788237430428023da3ad83ff9cce6603c5ddb5c72ffec5c76e69a8e016b59d0b750401946df14090d684aef8cd5348066908b73ed9f3408dbfe0e31db9ab6d15e72ffeca1f5b66f4975cd366e6b5207024865df077e1f86dabcb16179d623b699fffb340ddf7b593f8f87bef1ebfc69ad31d65a9767ccce3e7e1e7e6d7a06f0c76058f5f75a3bb1e78beddfe8bfa7d7a33bf4bcb0e685a3696762480fcae0dfbd87a8ff8cc0a7c7e19fccd3f1c7616c7636c2d3c73c8732bbd09fea934980d0f43eb3d5c5d8991b521886efd5226a8df79fa9cfd367fd234fcbf0bd67eae03dfe2ed47fc391fa64a2bed3e7f0fb48ee2d2a3c654dc5dddd1d67d31bdfcb5a84fe52697f548e3cf12f68be9d11cd189279bdf00bbffb2f7b5cf8fdf975dee7cfd37f6367688cad469c315b7fde995f65dcefbc1f99670cf8d508ef39b31a5157e0d746d41a9a73588da835dabbef995e28e36af37b2e3469e0fefb1bef6e2ebd4ebeac9ffa8c98627be6e9bd6886e6bd7150eb97c15f7fcf0ebdf20cb7a74beab3d003cdf3f6d8088d30c2c9aeb7f3517b3e8be2c1bd97de5affdedb7d750fc711e4bc191be1e6b87ae2ba1f18739d97e33da76b9e876d675d2602a1bdb56a1bee4bdfda5b041d220252d9291669414aad52150e41ab65e8b62db4ddd3fcf84f4ba5b33055beac5dfd985acb8c6dcde50f226cf818fccece58dfdf013c1b4a99b26d12bbbea552697dcfb4543abaef8de386325158d6edf5da2b9e38c4221fb7c75a6e0a9728bc43184f8a67f23bcecfdd6bedb5f839734990c7c9358ee2e41c8c679773309e315b7606b98f1f8cc158adbd41762d3da6eb3ad90db2a93e80e35c251626d3603c3bee9e34f4126120223f8cfeff83cb67d5962a2746d5d9b32b47b46be9e76c3bade50d55e13118fd4fea1d115b04a432fb9456776b816a756befc5b8ba6c369bcd66b3d96c369bedb65842c42020940861e3430307244998d846ec34870e1e4028c1e106aa26a9b656bf97e56eefb5c1d8b51262edd5b5928b4280eebd38678eeb3a9b15c699e3bacef36c56b534c6ccc81b244992240f0fc9c343beb804190982b584b4c87e7cca95cbc26c9c4ac386cfa6d42025d1e6fe8b07e3cc715de779fe72d96c369bcd66b3d96c98765bac227088222589a21c3a2a0f25364742c3b689784b63d10d140d87055c6b2fc6ae9ccb97ae912d9ad16cc17061391254a4c891161f5484454b0ce3cc715de77926cbc7aac97271ce1cd7759de77d1f17763e7a8020582af9e8b1b3b3b3b3b3b3b3b3b3b3b38323870eba82c76af65222848e1c362d1a1697ba4465a236d12268e35498ccd5636399238c2337441634627678eec539af38ce65833127c4c7133f67aeeb3ceffbc0950dc7759ef77d20b8b27114ad868af142d67b3ee3388ee3582a8d331d5c9ba880223112234aab45f6b3b2c9a1a3aee0f162e9043929c1441cee2771ced3b5f1bd1f100c2add2316d35e63a9542a956ea954725ab964010f629bcd66cb369b67b37558837a091f21413f41ac5511488c380e31806c576ce2c64f10c6610138eb1af9c367e477ba86face836a0dbc2068bd82a027562a567091ac6b2e7c8e71bae67a8ee63b5d7bf9ce2f0b6663c3da91a28505b3d101c3a5d57af560d1e2316a7124c8081050500e23386258681c87a4d3b5eae3adbeefc5ea3aeffb40300c3b9717182d4030d4bad6f35ad4b5d58b235d2b7ff41ac191c51ce99af82321a3ae3949d74a4f2a0119b9e348d2b56ae44b362653cc656fe6b80f85225329956ab5727981d1a2da62cc7079d981d162341ac791542a955c5e4aa6d309852249329552a966cc9831c366b3d974747474747474747474747470e40062bd826a664d52a082d80c1e2f343b954a5da232416b1337fff113a48487214574882d2c6e3d36346c1fa3e5a26207ac46a9070d233cb2219dd3094592a9944ac5623a8b49c3348c693c761859cd5e65a55297a84cb4685c7e70908a04899f434785c5c8765c3d2fac19230c9d2337622c68f0a05229d56af5458ec45c956651367f692389542ae9daf82593c9743a9d6aadb5d65a4ba57b4b2c62489224491e1e928787bc41ea94a8d4252a13b4fa8f1f212e2d487e4c212851586a11ad18319bcfaa9c01d341a154ba46f3291244fe90234046ae8febf55324a8c512b2b2b9e2bb5e369bcd66b3052a9579eed8f785874b8f161fab97511a555d99678fca7461db27cb1305cc39db76547afb3588a95472d23b6954a39837d4547ccbb3ef5b1cdd585e3a134723f3e45187c4b71f8ae6c95d53078ed35cf8a1cee1b8a73b6c317221c7bdd6399c19765687eeefdb325761ecde7bad733adbbdae795ef737ae754e679ecc1a6584818de23242dbbee8c4cac83db60f9242af994e1707e3f9db76dbffdbf4090b7cb6bf537dc220f9b13c9d519ceebdbf717faa1fa499ebbc0f3c7b76564155787d3729f51995f9ec6925853ebba68c08f4517b3e164780325b6b752f6a42e6325df8a3c538ee1befbc4d49bf6ba514097869feb36ce1805e76f4fa7bebe2b206eea9c9833e67b66ee7326eb6ae79808a73bad9d1da955cb653c6f3778c9da16f676eac5721ecd609a11328b1a990098028da54e8043d6c9b6fdbfab0eb531bbae75e06e7bd0ddf7b2fc37baa6b3bd86c003fbf8cfce187660ff073a83fcbc826f82d19b74a65d70f6b15d0ac4416c6ecf1bde7850f8644c0245f13271e93cfa4da86960ddc7bef993dbae7cc967dee7b70284e4bc6f7de531caa6d08a0389f29c3336be8be2583470f8e0f1caa6b685953c614aa757874a659872c51c55376c5c165cb86fcf8f1d0ae9ff3672ab9e80ee1245809918d99e024bb16d919fcf552d9952bef140b63037eee39b3c7c5a1383519556ed1ae3cf2df3e9c6c5ac0c78a202071c3b9e5bf445470d1ae393f369b9c77a8c40f566d03fe6c9e77080115e70e5d220bd30d39e98a441af4e006446e55a80a591e48e901945b151272f259c98215a2dc70ec532243496aadb7c9ae6f89d8993b5422d28012379c4a71aad00db2ab1d222aa252855e39edcdde76b54ec0aa65b0db4d4a55dc5b9e54a80441d8f60eedf30aedfa6e85ba9a1ca84008a7680a511dcab74d597c783dd7c51e2efdbff5f1d7d70177d5a494721ccdb4a3b4a34f29a5945a4be9e590784225cab625edc106eb121fd8b6acd9a037c1876d4b181bb44b0861db12c5066f0fdb962e1bc425d8601edab64c6d9063e2085d28836dcbdf20ed382fd3af0947006b13b4409f3421836d4bfa6483f489136edb96b15db92d68e1b6ebf77875a09f2bfbec4a604545538c97de6b1d7b59ade5329ed54a6797d27bff6b356bbd17bb9dd18caddfca899f09c001d43d1a290796467a6fa330dcf5bdbf25c6f86baeb17fc1de85efa754b6aec2997aa3528674a1aa46ffe98aa570f1c246e8a450e8108d42b3aa119f7e0ba5493d7d1714b4267cfa2aa8cce9e9b3a035a6a7ff02a5293d7d4c6bea4f5d41696a2db1a9aeeccdf79a3c32c6713757562894d50adcd79f4ae3debf56b1f54aadb902a5b1ef4c0cd99c6981b0fdab942849d8fe2a236cff5511285dc10ac2fdcfb39f1debd7f1dc60b15ca08ba03611a168fd18635df2dc0d134130aca5ef7ab333dd77666d62529f552526ecc66efdab3cc7fdfad7ab3c3b9ebb5f5fabc0cc4a85e5fd67aecb3c282bab50eb1ff67ab9fc0bf6b207613218acf5fad8b75ebf322ff559eb5dfeea9cd7c71e8cb55ea797cbebf558e7bccc187ce61f33afcf5a3742b19618ec5f6cc95ead92aec9cc16634bf6fad6cb6c11e0fff5af370ba067187ab5fef52cafdd7a11e055d6c0d7d7075d6585f26ab56e77637fff9a27385485eebf5c0ffbd777a5eb49e62d731546d7ebff573ac7f5b007612fd7d3fdaf75edcd16a3eb5dae67e91c97c900f3faec65520d7bd7eb5d1f2b299dc14cea33d7b35eae56885f158acbb8fe05ea1ae8fa1bf7aecb6c11a0d562e91b5abae6b1ca555969405588382051e5c9240452ad45e14bd3f0f9f5bd0f7e5e16bade1de53bfad1e3bf2fea9cd16393455d3a677447e068e48dfea57346a60d7c5ffa011816c3a4aeb142ea32985a7a415c7e956571cba6a55fd4aeb7339e655c49b9d5e55c57f7c24da8aa5d1fa66bd57cc0b65f4b1b2a91db5c59a1388c3f8baed9bf2e83bd6f08871b63fcbd7d500806e397f1839ff19b740e7ed0bce2bbcec19884453cc26f750ed6d95efc259d733f9b6109fe059fa46b2038c232ecb7ac42da001d149789806a0b0de1cfdeee762a1c2222a0dad767d484e959f883eb6ecedd4fb38bf96fdce66df12916ea9ab5df9ff2eb71bca7d7601996b656986bea9c6e5bdff5fe48e7dcaff64d9d7347ba66ad66c9e675164d7159b74cd360936842100fdbbeac25ff4ad76ea557ccefb74d597a603ebc075b008800f498187c37bbbb7750c8dfe59c04103be3eb3246d6450d56f277392fd9d9f318da0319d90ad5d0849cf3931e92b033be1e83a5de75b72a37c40cc137dff080221a96c80e11141c29820980348107406801be37742cdf05f2bd297c565f50220349688009459001117e30028f9ba5b8e112a1c839e39c67f909b79d77f6cf5e7743510a235682c880107c60420a47888293a53c61c21362ccd90846bacf19c5f12c84b5a68903022a332754c10954f639a3f2e37852b98ab0c54d9f2061689fe357eb4beebd17e72f2d724901092b1be0c110309002cef5818f11b8bdc3122a1a68c2480f4131c0b93db89fc265ee08440c7a38b281162401089cfb2f5c86f260dfbf49c2f6f6fd19eecb70196a837d9ff82c61df6780cb605ab46ffcc6679b3ef1316297367de223c4ad02d2a732dfb5d65aebec854d7d17b556ea5efd07a4389da5303ef3c725c5012badd4134f1cdb86a3dbd774285e073cc5dbbfdc5b4eb5b9e7cc93fb6c826557524a29ad6faf59e9ef6ac6d4188ca78bedfe2f5cb850d1991b0ae3af87ec930a51228b0593e9e433bfd7f4b7b421dbda548e3e231fb427f7eca23ed1997bfad3ee52cda9a321d55aeb9818105495a62f9578a74ca6af6422ffea1cd3df07afe9e926ffd335d26c319a4853677aac734c17a7ea06cf09eccb999e3399678e7d9fce469f75cea5ee22e96f5c55b6de4477ea6e3b9a54c5c8f45e324f1fa6b25215a3cfba467acb954aefaea95c827f55e22825b003cfb877a82b5426cf4ff98308d3a8249fa7dba99baeb404f52bd4abf0a74a0a749bacd1190550190aa03335288cd72435e84cf50085f1231cc6033ba84138c27bf7af443e834fbbbba7e7fdbec7250e0be37f2a797ce65f8908dfbf3229fd2d4b6f2acf9e6dfa1b2e53f23fef735f32a938eb2e99e7fdd1877a00f7497f632f1856ecd78634cc9e38fea62e53c79a58d2adc7b36260fb94ed8ec4955d77996cdf6cb13602e8f4de4ade50530cd4ce802a00ed011da25162464f3f060d9511ff058c176cea8ab3c5ece5bd9775295a33ab2bfc4d9b3e4db1473b738385f1f1861f8c55463663b833a4b0498b48d4c96457fba445dce392bb01bfc90e00ff35c55817b5a68617d8c6265bae441a4762c6ba0c65fce9b29afd19e03230166aa05290b2fdc3b2fad0993f583a805261d32704fa472fcff0c177ed2f3e587e1f926c6705b090852d6cd24ba067934c098ca68dee870578d8239302abedbdf8a249e9ecfc5e9b9f69f3381353cae2a439a83a16c6fe356558189b851f543840ae8e9d01325a18fb173f90fb40a805422d8c9dc1e66861e85b53a5da66aec298f2e13d6e4123409a62bcd6da5bca36577eefd1139f6135bbc7b5e7cccf75657dfab9bcb9bcd5f260a4760620959df8b6731ea5cc461a259c510da55432b55a7bafd7a5b8efba94cc90fd52df79cf21718129df73a4ef1efcf085d13ff07b610c4df6ecc2111c6f38f7e630f999b8509222898cc8a6f98650f2bf7e6c09f3b7e89c96cde33312e7852555954478b5f14f95ca34690f94e6f230125f4977fa4c845bcbc4fa56c284c8724d9a34b14fb8b5e2b609ab842d421d7298fcf608368999948fa282628bd8d956bf2b75ce7b38da99daa40e5d69325ec157c03a3474495788fb71222076fe2286d8f9f1a8635df59c798e2a13ecdc79f7dd575a639974e3a8bc3f5cc6771e4db944f7bc42f705e775c1e90db1f3bfcef1ee2dbf65a25fa51a4f2f754ec3f7e02c9c75f7461dba1d2bd695489d506833a6ea908b14b70ecd3851765b64239e9609780aefcdc2e49fdd1b91798e9c79761d95cd6083481153ea134aa038959f2652ec950bc449d7fcde5c06a6338eabcfaf5387ecccca5cfda962fd39b64a2d935a9699f5009a44d9f9af949d1f659edd4d62e72f99f7f6e55785a52db9f2bc3727df895c2e52c8f22ba94a529c9689bb7ce68685392d1317fbb44cce173e8385c98f7acbe4de6ecc6067ee0f87c94f324f953653e6fde1526f1bedd47bf7169ae73de2649e578834cf0e6596cc8f04de3e30053eec95e25054d310be779df7c478eaa73b9b5d107d6fe2481c8961e86a857ffa93a94389645e5387afd4af4d17369c57de0dfe78c267b91cfd0f2244d3c8eabacfddddc3d27b554971f068bb14f7dcc7bdc7c46172378eaab7964993f1ed9fdde6522d9dd39927f71d0df6532605eafeccd3ddfb30c5bd529c534ae37527ebde7c961f9ca53e2c8cfe671ddad95edbd9b78db67defee7c8fd8f90a5d283b135998ae1b47f354a93ef37c2792cd6083481153ea134aa038959f2652ec950b044b68af6ce7442e63fffb1dae4ae7d8931bfff43eb333968985c94f0245d3bdaaf22b3b9f3121994c2c1326df9ffea069fcefc1aeac6527c4a75a86512783fed37b894496fa759421229719cd7ac52476ce43bd92aa4f7859afd42b1ec493e40761c254f93d57826fed06bd14f5522051e952a86099d4fc9649ce7f79a03395c2789fbbcfffab1589e4fde96d4fc978c6ecd3866cdf280ddd19fffde13275e7fcf4bc4eba4ffdd93d49e77466d7791e67b62870b7f7b6d1f6debd52d3e03df7208ad02bedfec0c7a972fc6efcc6cee4a9db336f178228c2eefef059fe50f563abbbfbd99867fe3bdcfca2ce7193027577a635bdb23e217265a3d8f4099128fb6a19c6373d984bd483a854d7710f7adddb46bbeb9e7c92a6e17bcea440dd29f3f41f7fd43490be336fec8d932d029c4acf537518df64f2d42a84cb7c9fbf5492c0cfa379e347a5a8cb330036dba9133b7f3c2f4e17fb3a8c7f5885cbfe9e9358a7b76231e35bc91300c48f8f3e0eb884fbafa438b4b44ac6b312551ed04a44ab10b6ad48b8dbda3fe9942b65e75b56a22ae50aa367fa77235732c061569ea9e333fba44a64b3691f9705f0192572a24d59eebd40beb7dfdbef2df7cebd73efb79d2b2dad92d0a710055a4369ec675bc53a31ba14280d05fcb385c1ce6faf8c9688ed0668dfd339f63fee7d0a74742ca87aa0af9d65a8bb56f72ab6caa5b2f39f96c8ceef55f267af82daa87a5e2add3eb1d0ce7f4bb762ad30e2b73557b967aeb2f3e94976fe3327e1c09c3d0f2cb7af70e7b8efc107b9f2f3429b5d41f3e386fc2ee9de3bd356613c6d959df3955a85fbd33ab1abb80c67664d03f75ec565f25b2bf60aa5c9f1e74cce926e3608a52afcb9db0583409fb8369c3ef14000698a5b7fa89c58822261f440c491f875e1030143101cf5030975288ef48fa3d723f307150e10110811dc8f5efcd1eb3f3f53296e8bce14369bfee8c5b2b330f875893f8c79efb9c725e54821f72f8cb8f3bc0e73dce3e7e8131228d9987bd7350e575dcb165bbbc24fa9b7f1578aef6fcae283ebc9ce21c107305224800c6da7f6b501dcfa637c73ec3bdeb5744fe124a8d57b9ebaeb5b21c6fb76a62a57e689b767118cdd7fdd0e5de6ac94863bc1e77400294da53ec3949edeaefb9ad73671f13ecb18e37f407d3097b65a6bad6f4b6c9ef6beadd5bfbef52360cc4c48d535d9370a4ef6a9fa0019b065dbe29f31fffd4a3b8a84d1be0dd9be3238f378cef70601a45fcb4e8c5fa5dc33d89992c2dc87b1ef2df7f954c5bd4cc65b3150975c128c6fed8f96885b01043d6bafb5d71619eb5b4ae9bdf75e77ea36de9dbabb67a7945e9fe57a6badb4d6ecb5bea58eadbdd65edbe18ec36567619c526bdd1495b8d984e109c6be67cdbe2cf60d800a001785abaeb827ccbe2cfbded3dcf70cf7ad91d515f76c6d95cdbee5d8f9922e3cd59a99aad6a48871f162a41abd76e927853eab3535d015312e5ea0cc31c528469be20bb31c7d598eff25e96365e961a5e95fe5698602c8a8218a0d5485ff9ec17b7fea7d03e8ccbf55e65067feac120274e6bf52953614e07bf03bf04f477d2e51a83ff377cfda28fdf55328f31c407e3287ad51a4793a0075aa50e6f98053793ad9d87a1c6f94ca30e421955d8763ebaff52f8fad5f34290d776baa04cac4941d6e046c76e6b8ecd96d6caef7bc7cd41e6bb590da7d7f3f2f5f4628a106fef9b273569a94c67bfa2c5f771d0c2fb6dcadef3ffb52764dd9ccba39f399fd6abecfeccc65a8def4090b8eec5057954ae53395162fae55db086b9fbbe38a77104723120e8670f082ea84ceec5b1fc1f87606436b5c6fdf054ad37afb29280deb536f7f05a521df9ededa774169566f3f00b446f5f66728cdf8f661d09ad1dbafa134fac5b74fa335e1db8781d2806f7fd31c3a536f14c6be1d4d1f8407a31090e06ab1f0f64fe5ed4fa24edff62fadf4f65789a6512924b7afb6c39caced418c67bdd59bbbf59bbdbb76a87a82cac467f6eb09a84c114c5ca6a68082a6d0465813bf7b5015de1eaa05a80a1eaaad37aac2be13f1329fc96f4ba2c8815f6fbb96ac4d350d768fef3d690107762d479b6afaa488c806f1eedeb5ae894bea0f87b11f82548fccb3678f4c417c86f42ad3971e34953548bdcd6034d91f7fe3b8d299f8a452e630f6b5ceb95b8563df540e5207eab5ae05a646a8d40a5f27319488460400000000e316000020100a05c341a1280da51c6e1f14801170926c6246a58b9324c8611842c81063000000803100223030435a01d964a9cef42787c22f5b13691c0500ddb7af0f08af2c48a760e163c1923fe9364e380cc641c6fbcfe55aee5f6270e340701eecb9ffe1e230a81a4cf2b528bcc4f5e1e03e7a3d3a524865c95bdb3cc1fe1591cf7642972703fba463e9108bcd60734da82346d1e1473556d16019cc144283df5f2222df7dc9c056dde1b11c111e98a7093db154f7ddbb469b6ae1e8ac85099406a3b5a28230a53ca0e709bf68e7c92587227bb206cf925b376291f27171799694d7864aaeed4cd1146bb9078bbe6fa73c958072fe48680befbd225efb947a9ad22d4f24301124ffe935bdb3e43458eb38729e0b8a1b12ae18a23663229b2ef5dd51b90e8285c4dddf41d27a4e9285eef202c4ddc7a78027e925436798359f3781ab63eecaf6a99af75e71e8f28d1e0b2bb74be2c4eb0434dd2805a3574ac1ee10d7241b09942ed47c17e26b0790b37786e1d7463ee3f835689bdf4ddfd67c74aac3e52eb5c4868616619c0072a09067d624308b74e1781694984f6bc10a73dbb101ad7098f9ed59225c70a98a64670831348ee0f844a15e8b5765814a7028914382704fa27c9d3241c408333526684120cecf12629f3ef7a82964fbc732bf2a4752912799206f8c60a7e1e08c89f0c26f99929dacb0e362928e3f784931d5b2d64f94fbbd20120cbd6f10460323383769ec5efa67772798ff89c96be920f1d5773c9db689d94f1a874ce666525304717ea0cbc86371e220f4649e2bd0292bf964cbb9b24d0be1707560558683061502f1fe8f8fe9646a131cf72371b3e9bbfbc419f3e9b7eaa0f4c5eead13506ba171a6e8697a6d864c3c31da250c32a4e5e7cf6cf8c5106f9a3c8bc4136c34e06a88aab5a69b1e89cdbabb70f8b8992f2f390fcc4c73adf6dfbcef00bf33ff31be00bfa18056c8a37973584675170ce96e78c7a93d01c3d8fd29a70241a72aefef766e4dae34e8e588af10f32ceaf643bd7fc181c0bc3de7133cca3718fc0c7ef43163f4a8a1768ee918b716a527cd7d3d9e86802e058fc81084d6148d0da5c58a2c821aa5850e1edf1fe5d9b416eb1df046973cda39de45c7e632540f94a19a0c079837043b38985586601715d2a0815a650e3ddf3180f4d93005e1e1090775acc92e699698e5713400846a8fd5392216e53720d8764442eb35bb8c1325e2f7aba2ef804ada3fcb17b4a1a249c782c02112b36f3822107952d015b21b4b30867bca0267229678d0248f9942dda436aa3e2b694a26bf794f15b4c82a155081a0a1603d6094a43cf79183e8ceeea8ad0a189d4971eca2ae95f798a831646a207a2e41d349c9db3e18636afb3cba029a26dcc54f5dddb37467d61c46c233425d67135e84ad9a81658adf3fc43b4769b660906dde11c3235a189ea8d023664e411a2e74cb9a4b488583d32576ee0756156ea3f3c068098ac4c9ee6d08608bcd1ab176c830eafa11b1ea000bafb322bc0e59de5ff014ee60bf5b31ac4d49955a82e10833215bda869639724ff3e128b44d760ad3f35768adbf45323f46fe11c0a4013e9ff04f547dac004cab559d599732db7cbd01deb85c28e31b305bf0657ff3c3e82a8a9500bc50a584be5482f59a4bc13ac07ef48990b92bf84c0afa3b0086b6b1c88b48a6dfd91a3440f9a7197646924833463a7deecfc3247ea1aa204a4a7bf7219c6147d70407ecf513bf27de7efb149f86deaa0a6e5c0701fb21e549cfdbc2b3a059db46fb4753df5c0c62d17022b04fe02c528126bab6add93b74e3de0f2890f0a5e9025cdec73a8db438a8b26a29948728072b08323ef760c71d50627d285ffe1a697ce7a4c724a39bbbdcf7ce302e4406929a68250a4e5ddc0387c4bb6a5415da595d5f1306d0d4b47bddec71cfdf4ea3038473fa8912364afa58e398762b3de2d5564c44e8852906edca22d9a9888fa49340a56446c23f48658e8d4fb5996eab30dab12a5da92a420155d611180b1cac69e52d6cea01d8fbcf95e49b9eac70d354304ee4ca67c9af8d3b430525c1615c9acacf503ce30b09463b6eeb12fbbcada250531f5dba85f99f6f239881b21b7e3f857a727371fa616be045804eea1beef0ac128380eb302cee9681962d9d03a46dfd8a1b4f9d086b3d8ea0196e5a952f38fb245efa787e52f43e9bd971c526fffe044838a08a55446eaf2be5ba7707a39c9d98e89477caab9367a0b8278f57e65640eb19f46f0cdb67434bb24acdef7d2a7bd79d3ceccf1777f941cf3f1be05ab86c3fecc096a6db07373b7970277ca05c3ad2a65e35c50aa4d7267495d9f8a5a4b1a4bcbbc880f23a45a2f04114ea27e7be6f00196b3ead4754606c98f53673f9d7675b98734a679f67429cc580ee3353868dfad9858520e9d5e0e8d44e410245a0e9b1a020003d922ad93342bc51fd1fd61868a1a0cd3459f5b9cb4661712fbfd357d358b2f5e7e51c46a03a3374cab3992e8ff31bb2330c62a7d07295c3d99576d3cf6659110da618273449a7d14bc3b9a8e74b725ae1474418a914c5491c1037e3b1395d2316dbf037376616e1555748cad8827d0d57ee426954f41af947f4a5424b92431dc5ed548787d5198690162b7502581d06998bfc374b15c534a39ae9a753e4775cf4683977fa9890de50b2c6e128dec7a291025591bd645bc1dad28f74fa7d59e8aaac4e7ecdf30564c23608926f808188a0bf20ba942b5b62052c9a7bfb8017466b75edd4ee92755d7c377b2df3584cbc15be51dd5a0b4fbed0bc4427ff3ba40629faf1ec13a57b86f7378159f8685636dc013dc0b43ba0e7d6a52e4b3596c91d2dfb1257506a59a4a6d6b9f9347bd3a6e23183d4ed8e28359a7f91ad99f7de7cc1da95771838ec354a6cf1ed1e295d72c73dc17149f2d3979957cdf7196a01fece4f1f0e1c18f4ddb254b1cb1cc7b244a003ab66308087c5b3d717b8fb5e02d8405a66400a0d4e66305ffe5c0fb85f4ac55b3ec3a1945030c6386a5d21cd88b0d501368da89406a213ee532c4a0819fbd39cb99cacb7ed7a8e74c9785c5947f6fe4ac93b76f94978e248b1bd33c7e008b3f9dd10998dae01201161540532aee8c31de74645958b9e15518992ef341585ebf1a5e532b85a22c9c936e90962b5d5fc529c2d2e2421e46f15ca6284439841a492b53503487b1952622189e876e944bcfeb694838ed1596a942fe4ef14423b9f69b232e7f17d0c2e656afa185721b71658faf81b241b54ee9b577017834330bbb65c843f2fcf577d8f368a9ad4fb0a314d41d99a73943bf3c18211a62804baf23c4dba7f0017ed0793471c28c1ef20c6a8d09687b2faccd4e3fc12b4aa0e0e9c59ef03ff930f148cef8586c7447d918372a04db3d1294d231c7137cfb285af52c975dfa9f7b1667fb026fa2ab491fbba61ed42667f37b823fae2eaca4193f62ef331db685ee392893c8102edaa2f1bf8a8d05dafc805ff8dc4d443b41448be19b45d7d3164351b83f0e3baf9b84e123b1c635e0d178098c6068d3a2bb2dfac9366733cdaaf3f680d001b48171799e023d9496dafe912d8892c2539a4d7e4e75969fb4579c01dd0ec0c6d59fe73a2b725992d799d70aafa7427dd8143c15aa3f4bf6756342d3444a0c9e78de027090419ab6102d0cb15d644916205378d4f7b21628b5fcfcfcd7d2720cbd14361018e35aa9b2078148b029c489cdf4b917ad0d0c2e503935c0468bd76e51ff0fb20751cc0853989f862d2a51ff360c8421cb143e01026c301a02597469541d4e62e4ea8a0b568e24e3c87eed8b755e8db2f9ed3de1bf6499d38520760178c33fcb1b92ece6ccd7fc7d43eb73f8269885dcbc962509e92c5fde53999bb0cf35347f080772db1cfdaf4c253910f12dd06004ee8c81d2cde1c125da7c8325a299bb847694cdece449b6d17c7b27f964af73b7999bacead3c23efdd2a1e98396c358fcaea78d31baad6f93d0dea7acd0a6479d04dd3dd84141c223b527d2f4f7e56a0129ef2f018e5f3e1c3510ad0ff791fd3bb20fc876f399d7bf327fe843d73f80626970559afc437913d3baf09eda026de4f94cae7789718ae3638ece85429e95ed90a0e3df38640dd55e4aa49c899a3ea30efa57d404267e32217c0dc1ff7dbd76e8aa3bfbe77bc4986c4e650d06cc8dc0c2c9987742e6a57cf947e5d453ba338156f5c4a5a11a1a15dca3f7a0d0715f6f9332ea225be84c5dd9a0f3fbc90ad9ff0dcfbb2483b10a42152cd47670b93d056bc9439ed4cb2380d320d44d041c81d9ac885c70dac87d80dc1aa1bb33ae682debd8473c792dc70ba189ee83e58a129ae7c6912ba66c7b2696b08982f667de38a13a9e8e30466d33e74a6185a86ff54a6e693e3eaa015e19450c8d0355b2517c7fffc30f31bbf9668df2a61a2488b1ea69ce70e490d959c6b83ef3a5126a6d27050e3e1cc64c229b6d931efcff62c8fcdc4823db1817858656ecaf942af59825980f9f76571856c03832cf81ad74ae273ab4b218a22af0add381e862ae2ec3e11a2a0fd8ce395238f1355db6b4368cb38de2cf621c2fd17495b9c6b0b9d7f0c311f3e1f88a2721f8527e9ed7e13368c6ddb1bb9f5003d4f93e83b8fa36cf99f71ab03a70c642d2ef3539e272010ae4dd15f33e1ee9081d3a5c5d69ec605ae254549c2e6848b64900867aee2fd0e59602dc806c08f0b06f5a0c346c096bb7c63e8e4a6e8094a04e22d8718ac9c5d9e18dccb4c931cb62e1fbc147752c6b9b9969965c1f65c25fd9a98dc2687c21bdfaab2c3354252f230fc7ade5cfff94dd4ea076d2c72a83d0490a6c68a6e1afa66325eb83a6415c94c3b4b26ad9babb3612c916b85d4332cd31fd251293422735742db1f209c987205130a3fd2493827f7e3fe7c692d622ad2ec3bf1e5f1e2f3ec931d6e6584c0d3df8524325ea33acb92d24a1f3802c9517faf937fd3fbdb4fbb2dc986042729fb22b6b5b530916b3e0706cbb21837cd9a49a517dab8d27f25cb647b6122badf616e223ae96a9df9a667234e5d9848eb76e2007b92a201dc1102435d6369d2741d78d6e2c44087f6239fdc3780a61584f360ba45fb53d9ed27f4c3c954f484d1ea9db63e57a5ef3b1032f8c9d96f2286bc1325802fc305dba2e91ddf0f061d51b824d7418160a1b9d03a5c07c4f22d2f78b0c05364a8099a3ad90ea198b904ea4f376f88a39565d99e9af48d0cf7aec991a4b15d7a836616a83fd58207f797545b39c00280f913bc63dbe02dd794e2f77ea041f6717b51174d14c618c7173e9ddeaf6037fdd0856b11d3962cd6a71bb4b4b762df56c1864e9f5685d1c2763f77f535466bd11a15b5b922b5ac0c4ab8f81946e807113c765337572349260b349cbd9a4383a2bb02188107828565140a39f0e4328393b02087e5cf344c3ed9e3784784ebae0db6f6a92fca0e04700b153e219d373ce00b190ded04f91afa5689895cd57b5487b11168c9a5ed0bf1df28b04f561beb6a4680b4e99b7464f2c136cd745ef886a6e0a148f60a09726f08970b01d2d2cd292796b2f83d43db337a910df51f719e7c886c2841d6a6ac16d0bf804c929142f94c786999cf031de8a5e08f60b16631db2c3b54dd4aec38a980facbf78536004f04fbbb0aa2ebd8b826be699f69aed999ab7143cf25d77689d738a9dc788156a2e736bdca1840b772a59ef1a1f4ed82b0427137902e6370ed00d0ca1eae1416388fa150ebbe0cb09915348ebdf04568256e670ad3a4a1c4f45623abc1ec47497e6caf440667371fb2e141f3e4a0e0c2082b083708fb4b6613c0698305c53b530af62f3f0666d2383677d7912c2e188d6c50372521e16e7fd3ac4dca7d2949016e7fdce1e730d87474f42edc4424e13451ebb1c088dbdbdec265ca11c78cc74031ae0082c598533a191c003457e6ccca26ad81e15c0a9fd46d69c1e58aaf0186620ae857c3f05524c717b9a4a086c36d4edc1586f86fad7ac66c1c2cd10d3ec867258913be810522b7d08292b0a3c90edbc9c8ba6881a4302cb668e6b7008394f3a7a80ae8aa63d9e6b8b507cba72fed356910ac5998b323cc0d8fcc1bdf67530cee03948f36fd8968fdd4078f3a8a0b44390814de06cd9418d7d1947a0808cc94cfbec082193a1311119fd131b73049a668898c79a6e2ca0cb9818b7d6194769871af00c60375f6d592e9b7834105999f18a315859d891ef87b413c6f5c1fa6e6460a3f16c7c4181467700fa676d430eaac2f60d8eac0cbadf1c8bb684176d1005d725043ea914c5fdef14abadc8d4e4c6a68f2883d944a3b5e454b50749c3103f9644c5fd74b14e74a3568fe940e504cc9eb9b0c33a38f06e1917fca9e9d092c5da750d18c7f656cc3150868f842e6b23812f0a1fba327658c7d942a9674a97710987962f12443fcc9334fbb49e06002275d66ad9c7b6d772da957bfcd2d8d47a713f5b5910fd7b1e106a1a093004d0f087c79fb675d3318f7391022d738f506ed6d44fe1d11eb1ffad4da404811dfc51d57d35bb12b29db27d07367c4e4915cca3fddd9cea35bc284eddbfaecd7604dbd3a1a432f0d97840fbbaf9baf82e10cb6f08890e5d7557f49f972775526713542827e802591d809c175268a01dd217fe8f2b6ccb6dde466686d3338f93ff102cb31af4bf2a21d4e61be23bd9945d3fc407ea543b6396f3e216bc880afef3271a1e5b850b6324219964a4710e0f5bac9fd75ea82798362b84b52e609de1b057e98b042be6ab850a1fd50fad85387a89c6f4461e68ac49cb666c12dd912e6e19c4fbf0e815d610bcfbcfd2846ebaab6732ee169a256bd5be7a34b9d10e1a58eba69f64d9b159767f20f879aa258f26eca0e2b0cfae001fae8473853545d7814d3d102e0a6f4ae85f4ce545c35520d167f1ac47cec8fa38b7d80d3ff7a5caa2bb0b2380616b51a50d63348a913c2c2827a926a797bc22d1b54d428773a63d21119577a41464dd6ee1e3f940729c3cde6cd6bf78a58e94caacba25180e96c2cb64b3302e1ed45501e417724a9d52fba17c12150082a061c199bb76ce7d9c48884cd975f9415219e850495d6189651f5c931a8bb1b301b15060054187c2a3257fd4cb4c5daed89660f775695449ad572a1dd89d5932a58c01516b4acd3cd9dd311fbfab191afc8a325765607a3cedd50c724f41a401753e5c553caf31d61254ab40d4f44fad201b4f3c82adb7fc4351031e5c604bfa12170d66e660ec1f72a1482e28ef805725683e00740eba8332119f00981ef7934418aa0fc5e5937024a993cb3862807570481f422c5cd17b7fb3523c75e786f4b896e6bdc07160bcc50ad97795d86d9547a8156b206fdab2f4fec9e981df2738088017a840f8f01dec2100715f7d92bc0b39aa98b2bf1bd7383b4a78ca0d7f7d747fe45b18b5e9786bba45bb17ede9b974eb270eb8da06abeede102a404bd3330fcf660eb843d5bc7158a2de8c20f1db852c3855929dfe7395e3447cb98547aee4349ed53c045760ad0c334b9c994ed45e4ce836c65244abad523833d83bc6f642e1c0f49d3bd27e53a40a390a21294f863158a7971e70d48e6429bd775a4daf5c34e733441ce7115af3e34fe48f959bed923264c38dc02f2de8baf46e5a64986bd3b81a87ebb349638bb5c19acc4cb2dbc5e9d1ddd69d853efa97c8b13a4f0811360998f39abf29371710684402f5a9941f0b7f181804693f1e5c7df3dddcc6d75b0ed505e394326c78900158049029131a7bb93c6011b044b4f2b18efdcaec70542ab9401703bec341dc8b75db18c17fbdd4e3a361a39aee31ed39ac50ea90c0987332e48340bc842b007ad330b26c913dc4a46709e63fce31c04472dc98090e4a7a9bface87cce10455794ae8dcb1237201bfd5c28f01e1cc50e229ed8795ab7a6dc12bc8f75444e7090814e84d1918b30de41d389ecc07685db1918f193862cfa816b94470f2b20547296f16e4e5f1b90facc20f7fcbdbba284dfd67e30aac9f5d8c96eb2ae2af22f1514e6edb6615687e5a5d0f96b7c3c682ca619e66e58693ae2f4a4ce429d1ad0246981e1a75357d69ca8851c6572c0ab1f10a22625fe051ae5e4d6f1975d7632f39eccdf813235ddba91a18b9ce3aeb1218e745b3a23e480aa5af248fb82fac1553415c0aa9cf989396069063a654949aa6be9a2e74b4fa8319703537a962494809811a7c0fd0613853ebb445204e764b98026cf914943b1925373c3776c374737af4ebb68595abd69530b294c459c9b899f5bc2097c3b88f7c85bf9448bbb0c4264c15afdd008d90798e558af7c05688b7630fe68133f49146c3d16592e14ba796eef145a760dc6ceb26c46556505294dbf4205168ee8cc39ba33d6a95fdce7820044738ef6d7b4b65d1f90ebeb9e6481de63ae8f1bbb2ce23802ad40998606515b94d4b6bc80f02e9d1027d4c1a95274bcbf126d4bd1cd8bfeb238a4078bbb0e27b7e3723757ce9bca825ed92a97e46692859851d32beae0fc20c529ec0a8a7817c4a425e85e8aeb3f6641b71b46c5c6413c003737c553e59a93a85bc05a70b98bdb430a0bc39d292ac29b3aa75edcd904a203a30cc2c96f5d09b164f21457c4cc080dd0ef3ba42130107784f9200c87a0bf8f482868bd6346de6b9a6383f1935b24ee386e5621acb9eca73ae60c62fffd324cbe300e02fa652c04122fb3151704c5f4ee10808651e749ef244a3a2f79eaa3907eca72040adb0a0a22409397197b3913e3208beb87ce2ef165323ae6237acc4ec38d6a1f57f86f1a206dfa65e484c580d1531f4bd6561928ed2a4b62b26a2b0348c6ce66db3b14564cfdd6ad318a87cc0c58bfdabe8c0e366030c9c99969fa65c24324c55ea143f91a4e1fdd0c42de450c12c628ecb68b63d591f033cb6b8a91f99c726d87d2469ed2885ff1668eae18a6a40302fa04e8a3b4426dc3a6ee731c4af197416e5434a7ce72d5d1c792bb473e59bf6c1fe7fedaa5c408e704c5b713bb91d69ad15964468addf61941e76bb019b3586556fb2adb802a841ea82cfdacde9de718c6d8854601df55fb60705c866af4fa0c9964b11ade228ddf10c255a3445d4c221cfeaefca6f5d9d324f534c68438587a4160c95d7c55a952f01032f4b3ce4d73ec30983772fbcdb84f0e51924b24d6b3bd517090cb0b48a8605bbf153d68121597dfe8e20fa2e219f77831bd318651056b29f9c959b6778dc98b8c608082a5a4c6511db69ec8e53887b14995c104535a188bf8bee7bc85bd1747c4a7264fdaf1950fa4858286019e6fd2c7d0c7509fdea02c321f45e94be203b8c7c59f77abc4062d09428bfcced5dcdfed8d4a084bef5870a18f018dc4998f8694d5411ac5be294bb6b6821037895a2cc99c55a83a0befc7c8622c6a209cca6cd92dbae8327018021274a6ab972e5cd308b019f9810e72e37a396ec7a9388b6899e4de3d0402373183aa9465b955713d6b29c05b7e13812f9d9337fa4bd98fcb3a4fb4d650ef1c80b86f8c9da8e71f1df0991bd0fb58faeed02b49a68254bb84f76ec067ddc345ebfc938a88250262e86b351850a650d0f744510593b5f2918d965c91fa4104401f15068903078e0ad090164d7f410bce46d9454590c6f5e29631177908ece7ef88db6f0768fd82161da0e378afdb7f19d909e85599782730a5576292b7baf9ad32429c76be8beec90918a4dbaba91dc8d6de5e62f65c0699a9485b94008a706d0776b5bc00282d77a6caf9d7e769d6687311506ef100b03689b2eb9268268094663924043d3e99092ac2b22817f6c7d66ba3d0af07ba4a7bac2f3e7542a1679569c13be7dd2f5e0bc178d4321dcde1d32656b25be85da7d392e33e182e93f32d4e01475632aed582bfadc6630eaf415dcce37e6f54455bd995e82b9562a796702aff536659a2d65361548f6f5185f98a24e341b1375061c530c7d9fca62c9b7624e0321601950b50c30c2971af6ef286f716ad5aeb573794f713f38cbb7259815abb887ecd9293d62b50e8705713cd37497dd74d84115a865778bc61f5266042153be31b8cf15f31ca856b393471a5512e3a40a21c5209665a65e67bb8910b93cd021bf5dbec6f79a52dda151de1e319e82879587ddea9052000cc999ae99dc2c993d0ed0d8855f028dd282829127cacd8be24aa2c1ce67c190df6d41de7ce76269d19b74e0d846f49c26d0b53e2f02794fb4bea492a7a9c29c7c844ebb647a7c80b938c7728be37871d9b295d7c0b229224819ba866d7db3b568230c28ba911651588347671dfd0cdbb1afd88fa9f208a9076b4ac303d4c8f8477f24eac4841733bd07af9506eca8abfc7c99a7ae70e1f27cc53a368f3b54672cd692488179365427db23a22dcc6b10b9bbee6fea44ad6deabc62876334479c0ae48d99a960ade877ef44e8493bdcf9c5745fa395e0681a25ad731c3cb1bec65b8ac208a91c26af773344b91ae0980c34117c8aaa9a22ecd8c5976f692832ab7f896ca80980f23f95ceb919a417d429862123c196967225941e5631e573c53639ead533007900afc73cd535c9af08c316da0fe51b6e1aebb478300a1841d4d514b5f7ad6448819cd4dafd046b657e3f2dab1ebbf2a4ea17f0befdfa363d08c0c9868752726f0448a6535d5cb965420a14e461db1522befa980f099e17facfc43f57c0672de496f5d76290c8803c72896c3176986457bd7e2ce5821606518c0a38d21af81dbfb40fb9a1f864dc5df2ef847d57a8629a916c1a1666c2ee0849a63bedae2a92d1e5477cc4bcfd0cbc685aeba5628c81108a2baf8c3c0eba7d072691327534922c6a02ea621ac423be686413173e2bc4b3180371e142d5d4a4b8c618561d9cfdb9156255a0da33527a1c0c9401ab0a3a63f23c7f574acd3716b4fed3733509a6d6c2491d023b5dcd9c1f0b1646d5e790464787bf4be6dae20113c8d7ee2fd19855cd61976c2eb27bcae9be42145ec3383234fb6c3c762080f12f8c908d0b5281dd6d0381e4100dab0127d82cf5b1ea8796562b350af8e9716bff86ef1129486469ba2685c671fcc381a31b9665e588e79b2fe0fa9035035e4e40fbd05dc800cf996fcbb11d933ccf7a44bf795004a9d6e957b8e58a205ba83c1abfe3e46d248f01fd175a15410b8f00212bab1f57617ab80460e414d97107a8aa04bbbe988b6acf8e5f231bb2338fddc12cf52102360749903c076e7742837a34ba36b8109540cd6e46ae27b27dcb3a8c15181e7e159967eb013c58caddfe5569c44bec58ff0e02ad3474e7891956e4c7e30d61c9d13e21b5b51f7bb489ff15dc66d5df340dd0b7786346969aeb8a19fab6140c98c6829cde27f979d10c7740391969eaa7dc54d30c4f074216a8fed9691ae133a4dc400f8fd6050d51d2e30a532be33ca5eba3848e62374f98a4383c3cb8be0d4d0274adcfc1b73f7a9304516d746be8ef664864a7e2f40031900dc168a38156b680360242700bb95cae94b01a0fa0510954b80c0a070c538340c4480208e140518037c93a24a0623c76fa5b4436221a22d111c6eea8504cc109bb0c9f2858b51fad22111a3ad6e894204990045ebea43e86629366724152628641bfa9f41461595ce35d6db12102be5aa3e07248ebc6a955d36a40f23d0050a42225f9cf39b611bac354c13addaf6c3b4f078f4ab159b516267a9be49505664e480b1174fb1a673a079e5c13319d72d2c6a2dd81d685b60c8fd54634da93247eb07e5dc63ca8e69edc0f8fb306db11b9ea07ec87f34071f8f25748d4b5c8b9ee31a82fc5f660c9f0bbeac6a57af018c723e7f0f9ce9a023c4dc5d7af2b90ef6a750525f55f7b6b420f159664eb90d7cb337d4fce6452d0e438049ccd839a8b927142cc1ebfc4b18d577e1758bdf903e01b7cf6b1aa1ffccb6254de65608e3962a3290ff60ad5df7b98c9936df20683a55833037d0faa3146f1489cd2996830fa195b9b69d74b9c6c45e281b32148a6f94d3224775d6205e79b7916b6a1235b567f234c9030a610a20ec2f661b7c8904d7343582768b8b0ffb53a265672e9089f9fdf8a708f50fc30dfec143ec0f5336dce479461044b8f0f4e5b8aafd06b4c7f8ebaf77f1345e838415b94de0b273150d3ebd635590ebe7a289efdd9d865228c29ed2e85dd0cfb148a650623fa293341b9bd1f8cda844aa969aa48e94d986a49cf1f936c18552492b5358cc9e88d69b6ad336bf66214e284ac884bf8e7879c64b2201e3dd8e376e20ca651b0260ef98843531b6c4ba0a4abce08115fcea63fb4c7cf951c4cbe3739514f997bb3ae92463333448ef301caa8780f3f5c5147d851088d431b35ed92f43dae73eb0061b3cb2f207f5d7c1076b881f95d3c055703f41bd0f630619cde2095a1e6f989aa7c2244000dc9dd209b5e8e885219feb27dcc2a900ed1c1c9a3f65b2ae3299595653b9ce822a0c9af19a458270a534003705e9643758aa0048a3e6239f44e6e4d12a1f03ea21e3c58aeaeaffeb03407cdb2b004ee6f273826cf8e1693c40ff7feec1968c0c2dd90b61c082f17b436567842e5a0414d73bb78c62aa3f849d885870102ee8b862813e6a0174ecb5aa7d150254758db38c67b3c8ce3a96c845c3077e3b28fb50d1426fa3897c6f09828187f588c6ed09dc10c613810c642e02023b0ff050d3ff1e206638b106d1484f04fd0175ff40957036544e33a9c2012392aa2f3ac29bd42782265a08af66fa5611b71d4ebdf4e005aacf016c24198738c99a5c3f781521e796870e467ad0136f1f33fd4299ef101939022b5ea62f595bd58a6ae93731b6f0bc2dcc0cb5c55fb2c4c131b830b6bba1a085decfe78a03e9e5e2feb33eb3970adfa659a5a8d07881b6cc6f250f8c54a258e13158e945067df27249b220deac2dbfe29dceef0e1eb5d7e3baf120d1db540c070826f71311a16ed100badfbf13a1d9c2fd4142b7fa66e2e09f1024b19566a0e17a66e8a6f68641d0802fcb451f25388332e2a87a3dedb35aa0818a05f808af2ece500911d166ced27ca994cc3cf47a32df31081056d5eb96ca3e077d83d6e7408d8e184ca076f5b826ec4697f21bf9d9b8eb5807fb430b453f5f3742611a94c9bcee11f1b821882b45af0606522999e3bf714b379332537bbefe46a98a8371f3634fea7a61836bf7ab050b7d5fb6568c5bd5bc84d7a1a708c6a7c31bfa2e4bf199138ef80112521fa265bd445121d3dc62ad9b88af72df1604360332101d457973550dfb92f4d4acacee41a88d7990fa947e09cd6dc26d448844977c230c73622a59cc6d660db5fe5e3a3beb9e12b0db0a6914bb5b788bd6425d564bf95fb12f7c3d2d404018b7f686b29f679815341a058683199f1a9bd55d7500b8b94d8c8faff4a9832331bf4f989839d37fedf34f0f1c885cd08b20b30358906bf8bf0addf07a05572228ef6d5321fe17b8bd45119f76fce6fbc8208f04c37fda22c88c6dd8bd74ca4055b78f0f84922c0e40180c5fecf61d8c1d92b46f3b250cf28870b9f0a4e4f447f1c8abdcc6adfa4aae76df26047257aa60d7987257badc87e751e543e34d3da0b6abaa579635a2494a78741dacea5f2b192f2e34d6f5c5360c9d4c211e6cc05ccc7e3f4891aedab198cd7ae1831411844b9cf7b22225ef712f3805cca9463f03a70c00f0053b0a6b40ac95db0b2fb801e4b66e5dbd1c697a4f43de25655856e3907414d2dac8ba71c1fe08581ead1cf33a0d4606cfc29f75b7300916123d2cdc103ab9bee6b8a1ff0f177451d11023e5aec46537feb75d7831f25e3f2bc3078fc6d1c70fd73bf89363f6c22d4ef2b4c4701a378ec919a3c8d70cee3d6e71523e94290fc3fc537cd1cb5c366e1cdad9cf1e953f5da601754f602f95cfd0e34a85dccbe99b2c4b1af7a99c47ddf5d87d6fd427cda8dd43385fcc0b02237b477b7d35c84cdc2b48918baae5011cb381b1b7c874defc9dcc5e6a1f3ae4f03f785e0eb134e94e3459728dd435fba0bea6ba7722f039e4d5ab16950364951d61da1f91d76af65145363eb93f37155a6a4d554c7f128b04d2e4979816870fec3283e342e3b6f8229f1134e788b907520836adb838b8bf3c59467bb1fadd761cf2fef0a2452afb138acb8068a4de0bcb980b84f49d27af28b11def275c16bdc05b60a0ddeabab306fc354e617d5e81ce80e178c4e69132f7e0b54d56e80e443bf9504b6e393b99915d171f5868636515738dbc823b3a0bae008dd7fb6847930c89ef04c9f18c61dfc6a6bb3f1485b92d3358f74e78a11e00f6c5089f2ff97f9ff6c0f9714000ad85cfb73b50846b77474877dea4d00125c23b8f13f82b79b8773e11132061e0aec14c33fecee72471421103062f7e4828d7269e238cc0f521046abd73dcb57ace5244292b252115811274802579e710e84f8a406dd249681aa77837f83c82d667bdd190e061601a19b66181d8a2e716f2453aae021e5499e71ce7220d6072a801bbbbadc9c648d9680ae3d7e5d89690ec3c33c0009e32474628832c2fdf8eb2c76c8b189d578a40eb9c61d8fcf3aa2524593a1acf9e0d59da1796ec567ae236e3b0afcec71a176d4538f3aba37865a56ccd02bed66ee76abb02c5f71c8958f0bb25786d5b84964a0169a065873d658d410f07b5d324d59e432e52ad7cdf23d5d2a2f2f146b108ced1b21fb0ba71e38b9c314a1c57051ae18d5614b0e4e2ab4458e74851a32cf75daf637fe8ea0bd33139b82c6c141caa423e5d04acd7fe369244adb246d771ad5d93cfd0e65e90cf8bc854de524622f918aa10e1ff818a70741bfc0542b8525b403b7b790680a2bb4545a5d6295517575f8c016914c79a428c776663220643928873a7502290e0f40471b60d2547b10ea8a7e081aece5ed3bfb53108124ecde6e7aecb1526448a36e116f4d040161ae3666b1b3ee82bbd1f6821332bf46a11c051db72c6c0e1128323b1ecdde01300ef58145b360f0d873bda069ddffc0bbce4cbc0bff6b267044920308583d527c36d034b91494307c187d86c91925c92a6a000ca92fcaa14d50deac86b72f7dc2e4356e006d0aa06b547f6d344d2a36534830ec764d19117e212bfaf396fe88f9dddaf30f1c22852966947fba363a581ab4c5f52904a06da57dc92417811afc641de7e014c010e579628e6463d14405a83b56d494464885fe5726df145d008a80106fdf499cab42f256f2f70aab01a97a2e044307a4f0dbf23d07ff60ad29bfaebc804c0651077bbd1532a08e4aeaeea22157925d9794074f15c245030825a034191d022bc6a2002ac54d794deb4f6bcc1fa492cbe460343c032febdf070ff28b46134c16bd0f713c6b45730185906adbef13310bd2ef6519e9a5d5e7b56b8cf4f0cbe18769e3250a62594be039297509b9398e2a01e1822729bf05efd02ba829a33225fd89ad4f040b7ae5f92badbd2c7eed7213fa0633d43bb27e8726ff1a93599f1102bc1347301c1009d00a56788fbd73689367da5859a8a8c1ac0dd96f8f5ceaad89468702a67dff410409268150ea9d81855855fbd01cc2822b59eb1c7d8735410b65d299525c570ab56c11246faa84670ac4aa4631b33bf07721cd03e3d2cadbfcd877201a30266ac3124dc019c3e8e7ff5c566c28e4830de6a9b45313587f4a0455c1c33eeca2a0aef7ce3534f7033925cc82e66626838a53e84d05fc86b1dac1741c0338e089664c357e8539a9145284b48ba53b83eaa6428d031e065ae64867445f63208bc0a6eff9418b9c511ff9f4e9a32820ed871867e5619c8d94cc107a7a5671b88c81f9942c85e145e4a8b110701b9cb25841628dd154b1106076d89b0b032be95ccab12a1550106c9e10df08c3103f717678075764f3a234333cf7ec5cbc4aa611256276dae3a63bfaa23b445c0a856d8240dd84e5972a3907b80ffe6254bda820f19b194f73aeb60f042f26e86ca626ef8920f81ac1a17185aac448341268c692bee8c4b15ed8f1a5a5acb547c219945e6afb6f02e83e0ef05f7f5f2f0202800e4287219689c66523d4cfc1872070110cdc976008c94b3476c5995ccd9a5afec1322b04dee56ac03b7f01782901e6ae3d4fe1ead6330db934eeecdff2e81c202d21611fef0e682d822fa3aa84b08a44550af70a3a9eb69ec61c6b042f5dbf1f59895800116a052cb1536d44f05c29b0bccf7046189e8dfad60fa49e8371488380649d28d730ac4c54d2d7fd6ee182ae691c4ecd2f2ea729f1c303205ae1c010638ec63ce8bb45905a477273732eafd44c10c8a72aee55fa1bcca0ddb2c21b9bd57c98e86c81c4698641ec32d58d8d089aca6ad2ffa244373d339e7a3071f29d753d90f5d2a82fb2f621cc2dfa46479a46b3720dd238b5e0305e264d4cdbaa65f7df13d26cdacf957f2872b6a7a43d60b06c29ea6753a0a9a957c227d63c4608c20dd8ecedfe20ca42cc2e224303b360ebb768e9d6667fc81ade3041dbbbd0103fa92bd6af20c59dc41e812a0909b140ed6447ab0e05a2908e82b7e1fc9eb60d37407c3a962774fe976e22033b2e3f9e012398bb9e9c72164367b8e0bd0f4dbd8faa31c124edef13e3d181821d8f863fb04a76158f044489096704985aca12587fb310286d390d96fab15837289d91a8b81096796457558480919dba05caab20f839241803e144c10b3826fc4cc84dc238616c9cd86588134c30cd500d575fb9f84fc501d0e2ca371215deaeca75b44a0500f0479d5d56b0ceb20040976d6f0d8ed0075c9c45609f7f4eaa8a80f5de5207853921a83582855e8fd3e8864e3bf21293c0050e982709a20ed32a729227b0c18d7572f30ff510a910128fe993cbf8dc1d86d0427b2b274e1cd902b8b6a9054698fa040f6c127cbbea131944a94502203588ed01b5431e0ff78213b8239f334e93110463daed1bea0d4fd88f702bfe8ed1888888703a07479014fe88042414247fb72a13f1d2ce64c9bb250399344b536710c1548e2b0eddfc809dd8119415864bc3f1b409d34dac0931971ebc3fdeff717682afe05fe1a2403b89a055bb561e7dc164177328d27d86c11921963b3e03fc5910cf29b76b8cab120783f14b737c3fe6445cd310c7de2b0be712d2c3626114565a7d0839055cc9d0697022c745f32706a8079b745279607dedcfb090653218e2f16b3f7a70f820a5129ebe7f52f2291e4703cfae064778cb13be36f5090d7d76e2348b17dc5b9bac25d6b00fbbaffde04ff1dfe270ea6ede8a6a7b799d1765c081eb3559e693fe36c2297d6875f198a56b1e3bafa33cefd192c4a91b0d85762c7a51793e25d8924c80f328c42edfbc40e1a15b0a35e4181f042c4a4231682f8e88a5aae28ef196bea40c46182a65877b456de0878950b94adb7844a5b9bd27f0a4e81700e6b1e872b650139b8b8dc0af58cc300388060f252fddcab97dda109a86d7001697f6a3b6612ba5c2e204bd1ba7c2693c0af921e2ad285b3b311fb5f44c29e356d109309341e705569b111ae13025f2fdee98770e37c37592b4d70d6511fbe7d2c446b281c6cecb1d83166f39d31b39682a9c7ca114ffc5c26be3c7d4c82a4075b38babc07be963e8ea1d06c20187839808105777a1783cf32470fd528148a417b255d5e10e4c2b5f25fd12254a9684d9f1375749ee0de5a4061b905931ae269e4b2db1bce13dc47fa008b13cdd63b21e7f1c2abe7e8d0bcb10f89feacf46340a5cc4e9b162223de007c31f2a70147b0773f256046cc66e97fbbb86da512f414f4d31dc20296e5bd2c064cd5d28719ad08b87d8eaa5f99cf132d465aebb916fab3e098001f70100acc7340453421f405f4534f174b9630e1b5476c6c8ecb6c6de7676a64b686276dbedd08394f81cf6dcdeb84d850b61c191723a40530e78a8cbf9d27328cc7acfc4586952ee0ad7c9adf867fd46cd03bd236030893e57138c73a88a8299b2edc05420845245f78888f25095752197d820c306cb42b0087ad55fc646bc318e949870901b8017f47f49510cf782603bba52a09a8a948614e086d723e9b1bd6e2649bae15ba66a29ad7173f19d1477f3ba8531dce0754c95009fa806f377921053c24a0f612598f1da56e2d3e51c3a0857582a40136ad4570e3a617f51a93a365d9a908c9f545eb589b584d0d832d69556f10081ec1745cc9daee2da686e15d0dfb04f736d453c32a3c9ac2cf6258a79a84984be5bfc0abb2f1548297bdded19957dfe207907042e75d51e00096bf5629547258884a91ecd7f7275fec6c7bdab976fd416c1bbc808350d3a693caec0b3f865c41aba1437239f4eb3b1c0c0ec109bad46337630415239b5b932001f6474a141500ce0e9e67282e6761dba9a0b6ccdf0af3ccb937fc801e639c3bc46537308364e7f1e5b667343970ced291c1057e51e9fbbc0005390bce1661d3afcf972e4a473bd184a1cb900201884a2b11613801e6764b1e073231f94a6c9fbd44cb1576583153c1d5a58c67f9e15b8944eb304fc2cdcc2df30150c8e08ba23845553f4f6cc807b0daa35671f53040e17d09dae4aa1881409fc51fe58de2001f18a7393a9bd642b2501a4d0aad71aa0f96c4cbcef7af34e402abb1d00764b3c90064644d820eef22b72251a7eb89d4da2eb0ca97c5e4bd954cc0ad5e8b3bc2a961f60e087095b1947f5517a7dc331347207c5edf228474c3695cbd65042b0a46da07061a58466301196693919603cb535505e74c49c01f58749ad53b61f63401884be77d606b940c01490074cc093cc59e237546fe8715eaa69288f0f7ec27a7768fa3aa634077e1bcebf64102818dd675bf4722e095a8a906bccf1026c2c56476698ceba92525e2c076fc0ba86d0f59daee86dd880a2010d576f5f61fd19bec6f0d7cc65d8fbbc3cc2eaf4af6a1f39884e5a0af0b9567c459f24c61bbf92bba2b9ac31483938f8b81f4dabd4927dc6804f84ce7121811362992283192253892200be22998a648c0d9405623c2d5442c515cc6dfe7484e66d9bbe9f34b8490c6b32ac222143deed0d1a2e9bf814a3aae783eff399e6712c11af8d907182642bb6c9a80805393447c765559ed7f7f126a7c1b595d02647f1f2c5c4e05cbebf0dec13d1c10e0157901abfe3aec99b3bc42f1752ffb1456b983488abbc725130a08cf11f5d21af47111f750a163d52d216ae8665ccc7c767d80ee80fd295cc41df2c37f983cc4dfefc423d3f502bc1ed7e10ff0cc481d71170f9a18bc73a1b5ed102274ec2364e8c34c5b2f84f878ef821281e6c9546a9109db2878bde5128c4b157c6d32f553417429051224c73159131e152e5ba65f7c1e06bd074094cc704111a6916968402402b1d1ae358c9c6011cdf2d4520f03ce99b866a482f563ab7b54a2bb677f7f390233ecff8785db148e9cd20641220dafb7c52456e4e3789433447c736a53824402a6b25bb1d7d215abebce6f77245bb0b0edc399eb7d19043d98b0522ceb71a27b846b0b0a8782f71d3b4dabb74028e2764dbc81cf3d0522c5dd7233feec3293114672a350d1a15d2c8133cc47392599a0c36e792f914bd424e45a5a3f938b8d7a81fc2f6fd18b2a8b75b57b10b0f890c46924e0942ba121853b5ec155a26c2fc30727766b9c25a0c4c7200d334b3e043bd7b4553ff89488f0ade705cfa8d5e0ab0c136ac34fe4739a2d686170bf9ab6b9bae6a0c9d3a7df3c5340a59184d66dbec882306a1352837a3c3315c63628f56551c8bab2015a5956fbb74a608ea36edba74270bd9a864a47e83aa8d9e4a03e7166abfa718a17b7a61a8c741e3378d962b42e4ce052eaceea7a5fcac2d8d8d7241fa30e861f85afe42f07d791d8e487dcff22392fc8ec05cf7e52427bbf240b7bf8682f5bfbe611ba65dd57e456dbd07d8af2bd5ca5dc977ca95a28e62004b55c095825451b742adbbe5609a2e00c608f78a9f839b9225b1cac0e752d0ab748ed9ba47a3116e01056e9fb75cf48c24576a7156cfa29fd65ecae94e08742bbbc611e262d1345fdc1fc635125183978250c56c05b3951d281e871d0db8a55683c184bd5a0c4f923e4f6a328eca6e5430e1a6a87a265f8e92ab2af9ed7ad76c868ffbd0a0e53d00f56b2b0afaf9da62bb586974408ffc4f44eadc6e5c33fffb861e038cdb71a6b61382d22341a920c700337c69ed5981407e3dd90250b0f9d9c12e404c9792a6bbb29d887a8c54ee13256198b670baef0fe9538cc326245b42a1d563a0298f61d5b3ccb7a5a805dc12400e562a0f62e1d757444e890337bea3b9333b823af1e4f5d3f90cce296245b40b4d22af28bf0f867ecc74ff45b8fded05b234a70e9c2ae092214e2da79f4b49244761c96ec67ae8ec224580ce275d8cb5d1c3ae64099f01fb6b548f6cf00990b4c1c09a373073c06bd94aa255163a546d3ae1fdd7c66476250c99e4b722b17b9b0f3d1df70cd71bed9a4973483d716eed4e0c0448b1e02877d5a7a2712a3be4063409cf4c0ae73ad85d406c7b17a5c19cde4f8beafd8f47d2ecd342f5ca169c94a677473a1194b346ff3b3d9322869727becb528a95c9a93ab8b36528d07640b593bacf66dcd1666e6cac8804b9b04bf542efcfcc6d24897db371ae74f36926d9de5136234d6e32534f3f193b85d39aee26dadecdbc83ee29d769f442442211de1ccb5486ccf47935fe78f64718649efd64eda3e26d5830241e7c04a9586e6f73f362f80bee42f0803303c141ba63a6ce965c993561db695a1e682cdda72dfd3b2bc58e068fe57aef48414551c024dabbc611e2254044d7fc8f92369ddfc8aaa260088270f1432c4e8e5ac458a5b400c840e16b06c6787950ab2975970f29fb98ca0ec8156e7756f9e5c32616d1188c4ea836fd59d34f2882c32b5ee209a56f296ac67cfd83cc0e4fea999d47b1b21ebc7584e00cc15ae195214bc2e7d337e3a9990d0b32b43d3057876bb81b632c471eb8ea2d688f3635c00055664942a49f16863018785a68d7974f843ff67d5fe7f18a896549163742bbbc45baa5854982e18b2a6dc8a82503afb9e397c85103d4e37e6c4201120e6bf89bbda902487d405ea74b481df8dbf2777abe4a38407094468508e5fdd49b6ef10efc95e02501585197a2cd4c4f4f722a113c23d4d08cd7cb78b49a2b91e002ffdaf9f3c1729242fa6269725a5c94bdc2a3031462502244dda5506c0914ffd8cc0d2c9f1d448807d28257cbab1edbd93ce6b4f7a1db2e2b630b28f2ee14fd21e53d89587073c9e49ba2a4868f11ddef054e1b38e23c3c97d93bad23b3c4be6ac14339057061e4e67e599e7627cb892bbfd10189fd6a1f44232cb03fe6eec19e622550d1fb3ef77607c15c446caa1bddd12b0e115dbf5cd9f0fc69830efb6dbf4c2a48c8239bb60ae2ef4d27cace65298433aa81e64b615f727268e656d4a91fa6ee18b66acadfade271937c43d5f4df925c1aeba18d6eb14f82e38036c2cd22a031f0d102e52c053b09bfdc77da58ef4ad23728120a9a4895006403a5c73ddc103482cdebd700aa2f55ea92ba34c22f73cf09468347fc5b5505741eeb44ac062eba7665f791a4bb8088b69444185d648188a08ddf3a004b67e415393e2ff07de4f3f1d20a78e61cb80907b40d32cc6afc9cdd56b8bae65385f2e4409e053313960795151edf8b98baac1691b7f2056b60e8dbb7d28e5ac544a787d0574c2ceb5ec0281647220a640efc4aaf1473c68e78da17b0c136e5e81d2f61528fc05607c4d2effd7ea591d6415b3c83390c4efd9084da16947c2672f494a5a1729e03206965a358f9fabe00088376c99dfb1c78592c43983520f5c36cce714433680a639c6e050eb96433d1731a4047344e055155b27b058bb5370ee49f0c4d2bb6f162b70a47e147d4237794989f1791ff940ab3b9daf7f7789acde31fc20b4eb9f5ab216ee8dbed1cec6859d38c4e4d1d0256078524be302884b01c7b907d72ee222f09fd237d54e2cdfe3a9dbc0da6595674bb2301045ef324f60f4c4663d7154eb101258615ccc9d29b927380337e9a05752a9b3f5df893798e4567fb2e85848a2f0863fbfc75ba1df09a09c1c7925495109ec360756b26dc1b1c811a60f2923e21c30280a145176332386165e49709622ae8b0ccbbca36ca0a1a6a3b0a692885a7e2679cae4e39699c4926af0d8c27ccd69ec44ab9e81a17a51636f2b041a62fea15c988fd3a9b3e5ace342a9376b221b3e6906fd567a8a3f7163241c4d5188beddd7aff489304aa5936f25f1291586347d79c50d412febc03c31d7d8224949b8a5c0eb8a2fcc12a42f1c7a90d0460efd84df606e4605dc569ae305d7c6bc5d8fd5adfb343303a020b267c56d8f5bebe57e316f8abd3b69add1a9268e5a8ffa24916062c5a9fd10e6b26a4cd74814e390d284a71bbcb44f1239ce3aa5c315633fb46aa2482cb8e4a32424896c456e7809568acd6d4bf0cc6ef89b6566c636d8c8fdaa89bdfd2d09ec24910df8a85ab624a2f28c89dd84013739815e902846a5d1e1c3287483e545889cca22b947297a5dae3ef218b1e7fa7e95487df79ca0c49d1410391429b0162b81d2992ee6af6c46a4db1328814d64974412479d5228feea4a69d0f5f1acf18914a4ca5562e9993f4ef8e1dc332ad7cf503e7060b250400bbdf916ba2076eee36b543272955ce07ba96ce0887c84be0b0c7dbc3b66512ee8de9ed4c79c00bf8ef772d81299df68716fd21a1c38557bbce80e9a114b831b1d14bd66d2a8325cd6f18dd52adf1614a6f6ff5f28cd3b007312d3a8ca8c3e8d23c6496006e6aebc06477112690448980d447a9f003102f8c746c0823d7d136f49a0d86cbcceddf092d6e461449142c98036a1b98053e4dd237919e5ce0fa5ab06cef68acc802cb0d7711d5b1a582131fd38ed580e98965f9fee90401015a38d61ad7c702484225e2779375b5c49a28a8e9b19128fe023407f740e52c1f3bd67abebac165a181a3d2072666f15970bd5daf93383c375fea1864e3d14348f07f7f3e020d71ddb74a86f51870e313382ff7d48018298f42307974df04ce845bb1c0caf618433de5143c517a1585a8f52af3e9c90c9b1026ff7daa4a6a43fb42f89502de936f6d519faa553181bf237f4c8af81d5a98c2c72d8c8ac6211d59f675c109f2f6e7ee1feb45615747bc0b8c89c895678048b79c2a7fc1bb858ea085336feeb17884ab3a7434998bc99e9206b48acd8fb0714d15a1e0be6802369f616860ef4417308d88ff6d2397b733b07bcd0b69df0f8ba69ad0fa9466c11ab3edc23e9926156a2d1ac94b673313e739f3e1a68c278b4a4c2557a3186683883103a8844ce01ad5515358aaa25f13ef37c1a64d892e8650f0fc819af8bb1a7244e2f6ef4492fbe1468b055a8febecb59038a9f5ffee08b6b68e9fc94f4e61ed8f08ddec2c317bb9666e8fd8269edf5c1162b40a41e54ca01c28df58de65fb667e5abc0677cb3be337eb698eeb18b130409bfed1ecac8e6624205d863bd60a8572fa21d3d8142b1b690f7fcf66caac43ed4acfacbbce9edfdc0c9ed7de8acc6199374573b098373c0165ff58587d2ee3205acff31f0d04be4bb3188008e277c318911c8f50b6dcadb01bee9363e8568821608f060d6589935a52a8dcc980ae5b297db25d5d881c0d16ed227f3eed7b4fe8589bf1f03d1a02c89f30a6f46a0c5cfdff494ece88ed75e1d00f7f13495d7d25eaa60838435508837a9019406e6e2e0b5c0ce9291540946437828edd795220dbe189d023707f5be3f8bc74d059d2fc2e4609f3850af5a05400c94e05bdd991b96574d8c3312ee0da39345d323b657d18fa37cd073d4eabf813813842025c00b6e8fcb523402a76e8f85e90029203cae631ce20bc6b8b8c0c839d8392990c4e8a8d8124efb885229c674b3ae2fdb5e55c09d41e2fc57ab482d51958ea6bb00fd0806bd43dc573cf5119cb90179fbd161f3fa3b63f49b4be3935aa79cbb75dc539d5af3e2af9f7aa6e2caa3cd7ebf73b36ff0329ef6b1ef709aa4f0c6bc80fab16161920bbcb47317bbf9ca447086e3029dc04d6af619745e0e9b5352ea7b45d4635602f38433c02d22b102b511e34acb110ba50c8407aad88147a8a74b4563c3fd8009593e73800fb2ca621bbb007ec598768c08ff0018e207467d7c75767764d6de783b54622530a288213d5f246c05cce42ade08430c83da7f663dd8cef4537bc1de491e7769c317a2840b0215ea11e49868b8fa85c5968596290069abe93d765d2bd0df35f3ac54420cc566093c3f8604ff560c6617c49e260dde750b23068685e24f38d4a625a0854e00a4f8f4c372099bd8cf4053a3139641ee2f4e0da829f582a0342e3d2f4c44daa549335739f041529d98da68b39157b9f28374d8024f7782df9709bd611251d87aeb994486e32299745568dcac4f71b8fa52dd3f7bdbd699310402a60389a98e87f8408825d1afe8d328db9e427b0a8cac7012264354c0417b6f79bde79fc245d064782bd945badf6a55c5bc28b4a7f423e07213fdb82f922dbd739bc76d3274dfe9e01070620b85de0ab1caab50adf8878a65c14fc8477ad21b521dc96428ee1189cd957341dd71da6fdb5cd8e2ccc6adc6d4b938de3ea8d5ab9b4a68650bbc0c39af4c4672eb3fb7bd6504ec855dd2bd70a56ee173b9ac60013a401c9df8aa9f1d5cdf6dcc68d01b5363e219f6b270d23ad3e6fa5c0fd92f2a5ced1b5761c02bb5119d718a700362b57087f951eca2a4dbfe6fdd400de0f35a8b00d07097a49af69c9d274cd430407ce43633c9198f0356f43549b8a1b1ef7ec8bf59825db09da1e2543c812467e1a052cf9385827980512f74baf8e99b26c25dd187ca65bee1457841a1ce666efae8174c3ec8260b51cfdac0869700355dbc6b2340f4e3297217d60727af370fa53749fad8e6be5f1d2ef46021285075fa2850ae7aba1c58361297bb00224d5ceed734dfb55c5024939b6e151de9d58449babd151eacc749ed4ce8d72ce6ee4ac744981e7cd7d4d5190ddda336a7d4003b91deda494d709c05e966ab61bab20cd94240c65aecd9ea83fcd5c8848410c2ecd3846d8aa74c0d6607255760d469c617dc5a7f1a56cf012fd5ba6236286a5f25015240a7dae59e2631e8b8e45695749b7fc439f5ce9e506dfb7fdc0f8b641a24ffa04ad588aa06341ac803d581998c7e9f043140ee45c49a5fea13837acf628272dfa2e3725b22dc68447b6f3417dda8b6c18c0c841e9d51d2ed9902cf8791d86f0b02d36562901d8f2bd94de5e8dc42a1519ed79faed024f37d5b594a99e88475e8e696f331a8bb11b3b08ca3c9c83bea8e9317c6bbca50ac8af5895695ca0aeed4c0e46251fbb42c4c2b443859ab7651c485b6b5c0fcd2522013d6c67a71aa2f694cf8181210080d17ba2d09350b247f1542733da1340e71307e3e65455d919be39b1c0c89a706abe4c9071d4264260b0741ecb171f50ecb4c7af719725c814f3b659540dfcc81635ce002a881953e73ae820a3f619735acd5563317c9ca2c9cfdc6f1186cbc0f3a0049da9a48251ec4a0a0f184a94f284c4dc81775ff80b7393d55a9c9718048906ee3cbfbe4afa98d04dacf34c1f6ae8178a1dcf4dc506302a47db215f41c6882fae30ffcd4895c1fc29eea0ab4f1e408ee524238fb89fee159a4b4689c93bcc996bb84101e2ae384357ba12ea0a385ee8d732cba454e2e2a228fac4f00885ddfc8ec6b41b71751f54aad450c9d3b579053fc5e2ca63e9e218670d03ae611b95ad2e0ce99d121e838e8da19b4661891e1dae187acb65e9e736a933a69a2007d99d0800d4f8d80c99bc0104f82cdeb74e5d87266f338620375ea0eaece3e8f0c947bb03c242812390ce5dba87233a5616c6ce4a4511b521ba01a94df9d09b4797cc31618fd31a6f580b459abbf2b85a9cea7df23f83c7b7c1022906e3f1c732c55892a1c05913dd8a3f978479199306af9909094559ceccbbc9b478b803da226014acdb0f7916cea6a3ac8cc245521a55b43dbe88869635a32d3e888c2ed31e57e7ca58674f04a0f0c84b2b44b2ed303fcbc786f5a87ef621f54fa3ce627b43f9ba507118ed287fadd4a8c178157eda2bceaa382ed7d0fa34540f59398f6e5383839dadf0b48894c20ed87b7ee5860042244329e4c808ce5e415e5544f36e6519634ea9cb989404966d58ff9abdc6c1bcb192efbf8644daf695f67126e35bf7044338a521e6043e3ccefb4a532e0edebb2afe324fc5b881435e8aba566e074a63a80405365498bdafa7d65224dc872369d3303ed1990b663c7c121d982954b72d01eb2f0ed1758c33e128de63fd98ad21ef4d3de721718ed38b7da63c2213c504585a86d26f4d9078d8e3a0c2955720104ea0cda5e0b2e17509313d95e4b6c0178e7b1099521d60e2a0ca77dbc45267d0505c18ad7bf06fffa50b9719fb06ec1570abd83112420b56d8369932564bec6ea213653f0b3fffd3653a67384096945d6ce04b20f045d231b2137740d1b446251bb59a77ed0f6db23c5810e716901eae9d66d09517edcafd61d6bab50649d469bad4a12eb7ca782c47f4e17d91c357682b01613cadd94d3be5b12ceb853f5cf90bb4388244f5b4e27ffdd5b8ab7e1846c42b03a65b95ea8dac8af66cc8a5e03ab523fa8f9ef7a3bfff729685e6d01f2e1a8938b46671fcffa88036e3d8ce186f7dfd5f6ad653c5090b1c6b05cdec584a9ff3e2dd854986c3dfa8f96d815bd065294ca7fd73ac85bd28abb277f003c4a674fc09c0df03827755d81ca4bbc36fe40b34385e09a147cbd88f4591018c6f3a05581a978dd576e92cfa163c07ff09c03403d0ab6df6edc01d1a99a77b8e9f5e7ae2c3fa022035e545ed8b272cb1c61417dafadbbb6c90aabdb0b71b04216ad1af0fc25e295400c5128d3319be35145e22de31f8d1af06eafc8416f8dc7bdabff8cc27709b3a82c164eebdaece5ed7697860f9a208b4df0d2d4878de9ba80a7fb4d19d42a24a8da5efa11bf4b9ea2c87743c06333f05402ff0d3c46d35a893683e0f42338cacc3794820018585e55eefbe0da44c26e327a0a231a7d3b0202a6e3b6c0023da06519d3f460356ea1201e45bfb04b0155db5a9a6ddf9fed77c31b111b4cbcfbae3de8815786ed0b5a5dd1e5137469562f46e83c69a7b2fe48c652c50a8d989c7324f9692319cf31701336e86e9cb1c2dae7d49838f4bf155a563ce1995b22499f63ba1095b9d11abcb05581a963158c5cdf7ecbcaaa967a478933931ca640100faad509c258d287a80015961659c9fd6998a256c7cafee841ee0d07d71a118b583f4e5a72b9c741fc7569a51bf22b2b5629364ae0c30be3761ce0d19de88af904654cacd8016fc23a1f263e5563f39444302dd93f3215f707c437b886850b14afdf5907783a5c6463719a77ed6bd262e766b5b962f2655c336de6e2ce619299a26f38c01f3db9181d50f6050f50513c029d1803300345b732c5ad8933137106551307f8e38ff544ebae485ab5a1a1e1c635e88171a98ad4dceaa58aac42a4fadddccbcda132f5775cc50df07813fa27ad3057f58ea360b8c46c208a29a76b21db7d448084c3a4aa49dbb0c7afb078995f832786c5e3e93eb6756a677bc0bb48004accb887d4e4521f91a2cea4262bdcf731c3b013298b6c48a59352cb85034ac57b6b0a2bf9dea9f1fd28be2f3e75268973ab27ce54e71ab90a6d55d5f7f8593144207e089462213fc7e70394e3f210b5891ac145862a9ca86bf89ee4c5b4d5c05eb2a4ef39ff4b8bf28e9ab13809735d454458590fb96df64cf8fe493b912f6cda05964a9deb7c8b6c52bced696e03c1b0df14ebc2d38253d3c9c6daf02e0288449316efd99a91538205bbe77665c2ecf18cf9d5b6edf725d0d2bfd90efebf84b4e16a39cf1e859914ae7d8b374e7d4914a4e81ded7a81a76d8e3d47102327254cd5488ac3d1301a68942abf739db645ad2812f483cdefae6ae1733191503c180b6dc0a00f317302d93c90ce7a44b2e7050aaa8b8d7e3787e2135856fae1df7c2a1c04b205c35545ffa145678d6500bae8b26e50ff566066bd7323a6c38576ecfd22c8117ed612e8583a8a888378156b21b9e309309673b83b053152f554a5afd7d396b7dfd53469fa65d7def613c99911c7eb9a9feaf0b71e183dc4f27b40a788ef14226ad9dd8f7306e63e1156bc19b0de370bf66a2e4b42102a00213f0f21312a73b012b16f9fbf0343045600009f07d637f37ac9152125777daf4ce9f9ea26d322e97e155c5cb994bfa74188b51434122b6028e1aa76af94060008c6c9f6f739b30554340d38b95b5b7910c0ecaecb9f9145d94ccecd6d3b6d7d7db348811e2d3b73d5da3de087f7efef63347c99d4ff02593fafe4529743c9ee9d3b42f39a95dd531fb4991b542a2f8f87086ab16e1593547f0ed2e6ac2b38aaf415138e44deef0bd45370f8587375bfdf4ead5317317a3ba70f96e2a559aa823f2333ba2f4166632ed139a8f44de20a2f9817baa712dfbbffbc8e91ef0764a32be47979cff998f324053f7bc5b521d52e3315e561314ebe8d9b181af69d25a6e761d164c43c0bbdacc8b5c569748f168c4f46f30379c273e9d57de3a510483e119156ef605daa251f13ceca2ee56fffbb5e582ed5dad167a9fb794b13ad98860fc245a460c30d84165fe65754089754675d27f2b2206f1be348c398b0773e96b4db8a8cd841e163d0d6f34cb21fc8de95a320c12b43006f94cc088407d525d3f90913d93b3f610ba758fc05ba2bf73f61776833d65d7ca4310648c5864024a8c81415c3979552b27769f6beb1f7ff58165fa53bf0fb3ee5f212d4a5baff604c6ab46ada9d329c30adddb3b6fb4c688613c436e7f886dd3f45cf4426708379e34dbc185ff6eece357820ef570ddea1bb44a670235224c4e102529558c66ed3af19214bb09eca62098510bcda95323126dc870ba02b6c270f8f32b4c204d5bb00151328c3eaa2d853a511ce35f6ab68d73cf6b922a7d2849690d4f2d14b899f33737ce9b7dde3874cc95827c0c93e1cfa5ec2b52f14c275998f6810b903db66ba750986d9a9397114d41795f2cb7c2f0f29d29aa850ac051c737bd706049d4a37983293eeca7483fdf38aee9d323736dc0061dc2cc90c4fe943afb8c7a6c48af1ab174469dacd3e2393255ce016dd96617dad1cbf192ac3a4bad9f5130e76bab322100a21d2d43e3ad0d872d3c8acde3194edbf22bbaba2607e22001e9c24f16834379a8adda23fd14a5c89d2c4a759f3ae21b8738ee441f0631498a2f65214f70a1a485039a5f470bfe8e9d2e6677f0b014faa2f7a8df5294830de7c6b15cc96f9180ff508553b6964f6441966e33c95f36ffbd733d09fd1852b9d8b350a716d583d263af396f178a5e7812bea04fd20811acc53b9fc3c3b406be7b2c0f3089289a16f0155de5cc9de76b42914bda52b1f59bc5fd6758dfcfefc3ae4f93daec8f413bd23562d81e5c148f4e336c6d5f0c5531c2af5909dee8c638e040801048a2b276524549d727392c059331dc7980194140523d61cc04774b6288b06ceb38320a62f1398e30292e58bcbb64a6e6332c3f225111418fde9e026587a093905dcece4471844aeb97fcc3337f496139d9518628c362b1ad792f7e5b874bed837ec1c11b7097d0587b2977bb675da3b51ee19eb30f51be963ae2d10390b0d1d7892b7a360dcaa5fcf5dc7d9e90d801c0ab4f121a8fb0dc1e223d312e4f705f2e5c1008a74623840ad6b009476e7fd13438749b1104628c715371f6a32238945b11d42bc3a11304b15c9ced4cb07d9ee49ce98495a9f9081ed122374f19ba0285eabb18c8121c8123a0bf40166e3c5e7236e456eef743a4492b5b9e93f481e2aaf87295c3580f621ecc0d4bc42fd9ea42ba62d1477044ac177ba5a305c15271d994da5d7ebf57abd3e778fad63cd49eee2ea527711d793542aee8b7a21250b13bfdc5f3ed970c0023080c381011054cfdc0d73794c1f56832d58c4df8d642b002813e6dc07a2bfadad19d9468834b237d95bcabd03800bc00b440b2dbad0b7cd062e763eb0ca068634dc41dfbe1d5996691fb77db1ab3da66338fb68ae3679f4856a0f6177f942b42b7571648d2eb6f0674ae559d1659c3bd93563bc9af14e95cb55a97ba9fef1e20d27913b6f830d5cec12362719261176756c4e264c3870e78f3bb387530d3d486247768c58112b92e4cecfce07be31c62d79e7fbc793b3639186f6f9afb3dfb61bb80da4b2433b0a0eef6af7ee16232b0343151f4457fb022e056787495c1abbf1061a0fc714b6a8128dc8f0584295188b745c2ae5e489425c0cafe4913b9d846cdf981b6df7a1f4582ba7529a4d7df4f19057023417e471bd49e9a37b42421a69442a71a34f725f8ce1915e12c3eb2e647b6409d3c3db0937fa646cba9d70a9361d75ea982ee9664aa9ee46694b85a1e4a704490fd7c07aba0898ecd98a80692c7786e8150d617a30d513c830d6a49e4c86084be7a7c0c8aa148c663202c3a8139d70e9b716dce8935d412310f4eea76fde923642e970949cbfb5e06caac2c0c04c18cf48eac867b8973c76374ace2693c9e96447a7d3e9a59bac0918f2b597ba1ca99f4660c8a6d4519cfa442f919e9230182b61301206137de44eafe8777cba1ba04edb4274c99b91d6136968a7a0873749dd44de58100ce5908cca215cfacd05a7f5d52a9f87e83208aad73eb241f6f4cc908d301f41c2d4157ac87530dcd62e984e35e5a7ea46cf3d71a94daf44f45e8fecb91972e941305403199c3ebcc36097f6a5e7222351e8f31c37efe893dcc7895a76a2777743bbfd06721ddf548a879457047a9cc3452c402f7bb8d59d5e22e11677ca973b1475eda7f7ce0dd44fe76f3b7d25a7d34b523f629a1c743b3a0fd11d8d6e3aaacb516f021e216f0a0c4fd77eea72943e3add7b0988f2c3e8a8a34a1f813bb4d227bae90b250d2e25bdf4c921aca2a28744a74fe9d08cd26f37b08cf5061ae2eb8956216ff1b33de4ad60db700c0b64d98c3f46f4b0577bbf7f40209b65d916923ddc4329f7f49c6edc44a25068d467f042eee1420f7721ba28a5d48ee136ed1b5cfafef1f8f666ddb90e071ff46dc4953a7688a79cdc213ef5e1e11e4672016fbe251d72e96d26a7055db316a40769599665da41df32cdc60c8c399d905a7b2ea53e34ebe15606d22e4776fecc7ab815df48da27d2c8b2ac87529ad58470360ea685e88155f330ac9a9a5741976010ed02810488ab1957cd741220aee64150827216c1aaf91e1630c00ff338620d1502441af43d1ecc3ccb67e7559e70e57f1e7b6214ae7c98c39d991121224bde66aa842daa84ec73e704ef7c584d9c72a39d37b66b029735a48e6c999f5e9c40bb640d15d93253150c539ec737aab21a556c8095bcb24c4525b6b2f3559125b6e8393b334f7a9f9bc447e5cea9e283bc6ca50fabd0e0f5a9ce953a7332b34fa60629c5e59e95b91f5458a54a39213b0753183c516140e472d65990c7c6cd3b41dac6795782a15471ab8a3e41dd0f2aa108e44095950f853e1e9d4516b79ebf1e0810c410444cc0474d133752f0116ef127af8a5bdd0f2aa1e915f443052ee8077e0555ddfdc00781e11155d69038bc7b3979c85b63943558891b6badf5dbccaae5326b41b5ce7a813009256efdc671f5db516fb3a0b973de3b6bb5d6823c64ecd6575046c5adaba85a03c316559eb225144ac8054ae0090d755c9a4ad11a73297dbc26df441f0f1f51ec982f39caa5c8e40b2b10bb26242127d4e40beb4d9e7de1bc26e0129789627e3b293131e9ce1d9844d439f19e455689b2ecf42652113763138b42d99309f5fa1218ea30fd7493975cf4279f350143eff4454e996a8966e0c62cf23c91492a95ddc42b79e8a5ee7d47cac424756a9212a5401e25a0900c94fec3740b46537ca12f812a93aa575d02dfab265dc725fded7a5fd52ed34b25d3f652c874ee3f4aeffee374d07f445e4d30b47d1726ade861dad58161cc258d4e1fd3a36f87e781d92938bb2fd52b3ef7fdd840a097d124284dcd4e5bd8625cc5099cf6b3ff989f608c979026cacc2fcac88e63e4217e2271c308445fe6b7ab2fff8377e72afe877dff4736e77f343841af57f23f625cd5f77f54302c2203bd7bf948ccb79c6014fc06b71879d2c8497b2848d24ffbaca735a452e6d8217f822dfa30abc0c0cfadcf7c983a7aae7d36adf5bc54eafd68c4f464643ff05cb8c543ca68257844d06ec75537e7c5967ccf998cced975d62ec7bc7df6c95919bcd76e66de773fa85c09ce0e87fde411cf1d0e06e70e0af690778299123a979ec814a3da3449d4665e0d594edb403b6c2fb8ace3108b88e5914696e4954226eeb4a1b4921d523a98bc386141e126b7b21636f477f07674ec3dd58bc5b2d281484faf28bf7a455f3c7edbe1ab219f131dcedf54ba19e6de6ee026b74c3a7cabd55567f9964337c302c2f0562c2b1dbed5599ac562b14c67b1582c16e92c168bc5b267b1582cd69bc562b158a1b3580360098025c3e2ce625d560c2b00aced2c16005836583db0b4b3583558345833583b9cc58261b9582d960e67b162b064b07860b15c582f2c18ac1767b19ca5c2ca81d5c26281acb35cb0582c560aeb849562b1582816ab9ec5621d876e86350001c8dc980000c0460f3568cc8071b578901103c68b4b4b0e2ae05da49ca450d26463f3448944faf89a4816bc011c795ec8850d2e4020100804028140201197d222856f28b49da09c741ab703aa04b5e9c07707d00b5289546badb5d65aabc6e28d3cbe2f6ce53a2eabd96c0d748d71e070b9171f5ffe84743b7cb2c74a5bd33161a26157e3d9d7cbc76b878fcfb2fa22abf815e4d2bf5ef42cd0b715795fb00eef1f4f08e8da8d982fbe79a70dbb367be3f5c9fb8d05bbac0f0fc8a5fdeef70ebb36cbe3f5dcb6825ba8f75b0a7681ec14fdee770dbb403648bf81301276f1cc434e72b110409f7bb865dfe71c76b1cc43d6b9317d26c22def7d7e825d1c00003c64296c9c6db815baab7b78c8b01a34fa120b69845d3de3a13c2291dcedae8ef58a5ec6786831c1ae0e6513304209c50eef170f252c94af1bc61fd77cc5232ae00dc0ae69430401b8c50f63cc458a8973cd58af5a2cef6eb66917e835038676003602b0b9f41c6b97169301437b633120d55ed6a65df6d52bfa0080a10500f3d8609e1ec0d0d678d178d9196068616c5ca0cda535565faf7665b11618a678e8988c8ec500c3148ce679691e9757cb4b65d3aeec156b178dbd7a459fca010c539e0a187a1968933a18a63c1760e8c5ec0a0ced0427cf6bf26c381bce8693c3898d0db754a7df9ee0d6ead4e6aa423e38a47258c981efc9c777db5edb6b7b6daf4baf8252c14185878787e7d2df60026f001fc3a68f2feae3bb8162b158ecd283a47f7f0c835eed02d9f4eaf502bd4036201b900dc8e6d27fd6850d2ef8923ebe5aac5d9aa6699aa6699aa6dd4b69f16a97a6699aa6699aa66936844e504ef87a1f5f1b6b97b5d65a6badb5d6059732493d86edab5dd65a1bfbb2b12f6b636dac8db5b9f42d365409ea721fdf1a6b57adb5d65a6bad356507d3a9beda556badb5d65a6b4579412abdf8f8eef0f1cd62edca7878623c319e180f0f0fcfa53fc9bc51f66a576693bdb257f6ca6c329bcc26b3b9f4261c128598c6da457978623c319e180f0f0fcfa54fb170aeeef4d52e6ad32b7a6b5fd4e665633d1bf2f14429fa92ce077943ac2f94e4e5cd871bce862305b7f8b4ab696b3daf53ac8f2fcbc7b7d2eb40dff4db0a33f3d7b3b9d2d08b2fde15bd8a7e853e0722971e87292ebdca477f03cea507a1b8f4df1397fe1fbd0bfa16402e7dca073bf9e84dbec8b4a427f2ca54ca217da31ebc4fd4a970df52d84a1bafcf46d0906fb8e15cfaed05273b2dd268f046a446f00dbb9a904f64d1675f280c9145df59847cae8eb4018918c33ba1be498e06e7f2e3e5c090e5c6ee3cec4324baabb8b583bb8a55717bf7d1b66ddb48bbed7a0d5e7c7de43ef088be0fe8383046969041dcbbc730c8c39e7b77fec2d9cc85baf321f592773713232b44e28e9ea1dce4278fdd8d94a37c33f9427a4dbe49ce44883b7aca02eec8e4281fea275fe9b1cb81c345994cbe50476ac46374fb928f87cc221ee12696d1171ed1f701a36f277d3c460f69ee68863790877d3aee8cabbeb0883b437ba89b81016178037836806ccb6c501b361ec302f862aceae1960d1b32b3f119df667c95879edaf88d7a8455f3363e1bd3363e79eb974111e3d60ac80282a12700f08879eb8ccfd71e1b9fbc333ee3965bf633ce714b7ec6bb6e6606fd324a6fd40aa2e05879fdca69ee56ab95d33ec668eecacc0ac5693a84e914dccabec9092b72c3fe99b076754eafe65bc0d05acf638161f760c1ad97ecb95f23e156c83bddb3154186ac21e3f36d84d8ba9fef25c856eb329f6f1e6ed9f87c1fe1160f311e6a498835625c216bc0f87cb914628d97cf18e6e17ed90ca26abef5653890aa79992feb4154cdc380f16c07b2653e86e9990d62cbbc8c4f0691359f41215be66dbc80191551356f781684d832eb73f84b3d0e2ff52a8f9d0f2dee4b4d41b901e524b2eac197faefa5fe2ff536bc4456bd8b97c8aa6ff1524da5941229b2ea515eea4f5e22ab1e06189a3c918928940a75251d175995db501be804d24c9a8dacfad15fea4b350365f725b2ea43edbe6c73069146bf3c9341a4c19155fff22c8a484346567d7906c57ca101d218a650744ebb7848afe6ade5213187def012bc8e0d09a912bc151836099809deb652c3ad1618cadbfa8c9482618ff9f24d5810aff57086f43437664458f5f2ac4837f372baf22c8755b3f518deea17afeb5e3773bf795ca7c00be7cdbd8f612905ab70b6e664778387532134687c520a5ecdd74fd257a4e1430ee129c8e08512677ed6ccdacd64200caf6635a748eb6450704bc6e7b39b4823c6adbd2f8f6c93c896f997cbf8a88f189fbcf406c6e73b89cc5329cf6b992477d25764cde3d0f8329c5ecda984279f3d9c37d4751918df0b0f5f6ba6f518be1f8f18f2eacbe9bb9b99416f839e071c6ef1f018206c9cdedb50e601b8054300803c8ab83beab35f7639609c8228f21e8aac2b0fed4591a00f34f2050587fcca6fc8afbcac7c059cf230be70e52e19f436e879c87e5bcf7e9071dae5a020cacbe9576e9f7d282f97cf603cb4282fa00f34f7e5f22bafdf5e62bc7c28385e0ee3375e0ee3343776315e0ee330c0094e56ad3c2c62e530049057e632c0ac0c5e057b645d0164fe22655e2f41994b7087cc5fc01d77857e61057bcc2b737f683dfb05630cd8a3af8d07200400d8a32f0faf3c9c0261030ce5e5e1f43c7c61129766b754de0211ca67618fbe3c8061052e7dbd54d6f7e8d8c530c5c99e81618fa63c85470f05abe88c9a8b83822fadbfbc7c863d2de2d6cf2e078d0543dbe1a07f794cc39cda6f868decaaf11ebef2c82e1a87f11ebec82b1860686fadaf41e38bbc5a0143db832f8cc3bc7e77ed98f19773f743eb2f971d8e197f59f9a4fdc222aefd8c2fa4b933be7157009abbd2e5c8b2d7577065c66318c6d783efcb37c9cdf876d8bf7c83f1fac9226e16ef4a0ef9fad8adc8d7d7c30057ced9efe533bef817fbf1cd5e6e3f1402c49b5d5e9a8b82a3de9ee6d6c92a5bbf32030c93b82f77dd65e37d01677cc6d77aa8e3ba0ef385455cd7e90db7281424ef200f7484bcadd6e9d728f06a4c8743dcd0f51ef3b63e5badc7b0eb9b30ca7d31876645589593ad7cf16e95a32b9fbc5c3f5a69fd6c952b3060c4589141c10c8787674432222b60d6fae4e5e13362de309391ddb48bdef46a3e06185aef86de641308b78e9813c6ad97cfcf9a974f6ec1f8cbedcbb76ee6a5c11ef43c621659d0dc8d7e1148dd1df42b8ff1455b3ffb6c63fa08a4ee0ef995d3dc182fdfac05b91c6e51709ed4cdd8d39bca7535a4b9dfcb17729782afd9ed512f8c182fdf6a566be56a6e4839986ca9b53e7639380dc8968a423fefcb638028f4f6561820ca0b788d98940814ec3abd018bdc799a43843fc5a91477ced7bdc96e3228c6e0c59a5073c3ca934521b6549f672b48de426c719f671f4ec2ad179f2e9f6728441a3a7c9ea9106bb07c9eb3206bb03ecf5e88357678cb43aec2f52618ee7c953a95c7e5137d209f2dc4d8c28a5fb87c964f0b97afc31723ebc5c785214a95ea0a97a58ebcb11f078455960392651fa701d942296c050c8988476ef6ba72f9b892add04fdb6115a59a911bd6ccd6ecd3ac902df40ad942c109a24829e67c0e5f9819e1cee3f0855911eebcca176644b8f3377ca10de017baf8beb0459862c317a2b8f8c293165f6892f28525285f883a997c6129f585a4922f1ca1be5074c3ec260cdd30bb09bb5276436f42cefbc22aea902a716384bc61767373e7411336a45d51a6553f27ce9d1ae88a32f393045e18633d7b6a3bda4eadf5f6d3aea0af9f0c42c12646e085f1d5a7695aed80116847d838904d192a95cb80e9c1863bef9952591462075620043164600640f0c9a289580c0912ca05976c0925842009cc0a4ad80c2183112748812a01052708e902fd2185076c40050f8450061cac200a5700218786035988e2044d6080091c74000a5db8f3a65457c5058c20796ee812abb42ef1bbb8c880e921ce0d5897ed8a20e091e0721817192e9e8b06d39c10842b58e0b2691f8ce67217fae30a988b8b0c95ca5d5ceef426bd3307044dd85c64f00a0445a09a13364dca6c5bec14a0dd824880ae3d9c004e10f620fbcd726b9f7d4c4b22aa0e03319f813b28c8de64e9c34718421840f053869f199ce109718a40480d3860831c5cc08923c8cc1d2740e1049c3bc1f0ac9a9d1026ca8d547801e7ee6089ee8e9fb4fb737677cbee29a482b657933ed415e86e12e732b0d160a7edcf4d7ed1d6befcfaf4eb31af04e337250d656982adc4c697a22bc6887265e49e19f0e463c7200cef57b2121408e2810d28a1020e402104324e5009e76481b1aa1bf6eea1cdacc3c1b2846ce967f3eb6f14859e05765986dc18deb28fc5876c99afcdf2eaadfb9b8f5d0e962564cb7c463f997ab10f07a4b87d5a05078888e697b18c91a572b34f7bd33e48abdf8e186918c1437463644d56f51b0ce933edc6a6b9f4ebe8b5ce1655421aadcb900e813e80c56db9918a0fc02e0874eedb69e3708970d65acbfd24b1938148180f176a3764188c63200c63552739c2ad20220d1ecb2261122644af4a9f975c0dee7c284350a37164cb7ca831ac5d4d8457f39c6d10d6b1791034b1458e51ce50487381d031f0f85d87a36f9804e9313cd0b7185ebfdac776853bcfe035cf3cccf399371336a72994300924d288371657f3de4629dd6c9f4eb625b7dd0588eddcc6711f3d9db8184779933020dc327d5ed6441adde707ee7c573184d840881d93356064cbfcdb09777612ecb50f857b9f7bd7ddf4a170dfb87e710de3b8fb8834b8cff78fd8af7ea251d022680e7099e9f4edc4712527eea8a3ced56ea6a4e4b69b2981e171df46dc68b4c168d65efbdac6932d6f38b3cf6f57b8f3dd0d03c29d313c49845530edf5bbe70f2fec57fb2042911891d89c73cef97abd5eafd7ebe523c681b618c78dd3384ca48030f57127161c1b993f38ec0cdcf9067267fbe857cc5acfb3b190a738833755319f4efddcf9ba2a0abb1348177ad64d24d2883d6fade7354fbfe699b04d784fa4a0b8f32f96e2ce47c930564d9ee6c0d05acfe30ddc79585c4d582c06db352d8687c3e5582504abe61710591304ba06d248248ddbb46bdbd370374dfba66ddcc6511269e3362ab558c79a48e7441af69308777e563184e88201426c81a60e15729c709370fb49405efbd087b27dfb8ca0da77e4c66d0191c6f679064421b8a57d52018b1d32e878e1cec6c28c1189ac3983105747a820859d26e8cc23e418d19d471197f430f4d2b7d27679e70fdb45177ddbba19ef5c37e3791f0c6fa3020450dced5991fb1babc8000caef62d08088050f1012457e5462a3e9073371bb8ede3db7d3de6ed6e6c17954aa1ee874df4a9dc92e8d35edab68deb6e6cdbe66da51157da385276ee5a97637b76dbe1c8be6ddb6328019adb43725fe4c943b46936940144f669077de1e8ce6ffbb62ce360da15040f56a48a10715d9eb7d385a504e38946d17277f48952e27acc9bdde08efa66e26278a7d067e8a77740a85ced7207753f843eeda84fe56a0f15c1113a0786f286420f9de6c61b3b1cdc4360282f77837be81bf769dfe44471a14f3bf79d3e23e80d674ce56a0f7d2a772be14e33477b08e4ae06ce18ab26169ef6fe2462dadeaf5d0eeddbb30ec7764dfbd6751b18ee28bd87ec8f44129dfbec3c8ce66960e880ab812103aef621aef6d9f9b0dd82e102ae06060feb902b5f779ae7c5abc6403c896c51e5fcc59e4e78f4354cc8266ce4ab57d2c666ce9aee51d9e67b3cc71859e30ad2def1b31c358ecda17c62323733e3d0257874541515bab36e06c416235c36e9b0e9e679811352f0041f34510407324d85db8d84db3a82d0d11144cae8862a190c893a625ccc08829850ab43089d20384687471be20b28a0b566319036b2f5b203ba7ea0012ad0820d82208405361a90e12978c1090bea6055bb622a38022666a5976308101b0001621bd05c605c64c02c21b32350025433900056871041e804b15d3e0ed1ae0dd4f101e698042440d0021a6430851b1f1996c2e5181666906922108388c707f3100e1822e601ac6a1ec9cccc0cba910a11f4dc30c64c5ea029e2f6a5d43e3fcbb16a1e31edbc735e66d0d258c94aa8e088e8a02fe46ed74e4e19782051bc5d157da0e66c94380085de9eb45c8fc0cd03b3779763bb22ee6e884e7feb6714de7c28034feb92c8b9a0ed0b5d6e26a770b9436e0c4b911d0743b825bfc52b4f67e48cc2934364f6812daa1851dd2a822157e5462a44c0c4f571e38d777b9daff576ce09ea7c6023acdab80dc7166dec268efaed5b886b1778fdd03c833e0f024320eab7b95590e596acb49ba931d630e23dacd6e1a89fa07db5df36d0853002f4f9edeb21eff6fa85aabb7d7b0dbcc87539be3bc1faac5e64b2c9cebed0861e8808d5e5be498e3b7db63d86edf6f8596b254b5943b97ddccd6ca0dbd86d6048f31869f4fc7c0c831ed3a2cfb20a3c3945603843b6db3edae198afa079fbda0131b58c1e2143b2e3413cdf8b9ff173143f636b07054320e28f90f4936e1dcf8f2cf0e4ce7b055ee85de69697c2314f4d1c69c8196b6c9695861a0c1bb7b871c648a3bca5dddd2de2297673ce1f7e3bb41404c35473e3e4ccfbe85fa0d7f092e1efc89d1a15584a267faef4e9559665974658958172e7c88d9734e3d8531c18a6bccac5ce314929a594524e125d9c94b7b1181301a910c1cee57c489906b7b96df472475e959049a4baf4d2081014943ba03c92d32ee97311981302c314b871905ec910183e95f23822ac92e720670e62328a9a8bc31057f25926931de472ededdd408e4d18782107b93248160a692e115c65232627f9417429e84d19ee8ebeb318656298c49d32fcf14ba669647348a0220b486ea4220b46ee0e37529105286e0caff490e3b4da76638deea147ba117563490bfbd0450dfaf032d2a85c64f54b5f175bfaa44f1455dd423f2addbe67ba7d11eaf64327b7dfa1dc3ed7209055a1fd58becbb7341e593adc061b5ed8e0c2c5ca458b16aa1629292b29282839a09c9ce0706262a262924add902a29014b50a80f753afd6432d9602a955c9448a416a4d12865e479289e4874220a854c425d97ea38ae84db36d406029d409a66d2ac2dd95a4935cb46d96df9d0a3f37db9234bfe5da471236bab1f5f2ae3ec908c2cee9090c9a0e7b1280949231b0484910ff286bcfe4972ecc831efc0e6ca679f3db3652b5895edf06ded11721e6bb7910959c3aa4cc2260dbcceb2aa23e3e1d1e16917bf3cc97365f69a9d5f200da4df2cb3057db71fbfb9ca36abf65ac66cb3f3676d8c2fb6a94e4424974d29cf3e19f6b8dab36f36e1d96b1f11dccd62d8727340b2d70930125f83d207abd8f4137d8ec0f3a392da4f273cd0466b95e037b3ee5a6b6d597b03f5476f069ecac5cede096fb361153f71e2c99a770dad198e9452d33e419a94de174a292e7f03753353c6899efea8977919cd28a89bd1a4949a3581a76907d96ef91a7a7f5224afe8b309b90c04aa19383f29a574cacb83aef56bf64c6add8c3dc7ad08a4bc21773bc7ec92a71214d29d76f6f292e646273c9b559cacca197923a1b89cbaf2e686d246029913c8d4be5aade4805c6e8acbc1a89493d3806c999f1c631a5097d0404545650b5316894b446a1345d09bfc662b6516d1944a71cde51803e10ec816f9f8188e5c03929d8339e79c733eb5b594da4e36a976856c61fecfb412480d902ba700128223b7c68d548440c8b5a067d18705e2311163928e3b37ce9c768181893f118bf9782927fa28eaa27bdf184582d5b4b1d45e294b29b95e72a5af9ce8a3b75fe8b10bc22d0bceeeee1afbb06bac8b6d74f9fa2485160c2dcbbbf89ae7eb23add3afa2b37cdbe08028110ae8496e06e714cc53caab5dd3344dd4b5cf547253edb39b01452055c3adeef35a6bd3d95cb690d263090788e66e956b1678dee7356e893e3f3baf6de6e5ab5dec8357f3405ea5cf12d8437a48f7cd23760e61d50ada87893ba98e4ffb50b07d1af4d9668dad49cd29d81579e24c22bd89be7837edd376421aadcf22d1b5f717ca2ba27dd1b5afef7d14c5bbb67341b01bc39b48f3ba35ed0ad9a25df4900abc18afc4e2c535a003b9edd3493694129444496951b40485f4d59fbed417ef76eae4fba33216e9217d3ae1a1d807c37e58758272aef9c1695b71ea99d61e42bfb627c927c952a27c210749dd50fe904ebb99fec9576ff2123e9160eaa80d55ab949251cc2c254b59b56e8634849a2ea5949e6efa66fadac7c63b9d1ec324898222bb197a4eb9641f2de46b5cf4100b9e3e795b7ca659039a803525e0ac6196cc2cb7669a8e6b77b2f254f2575976d27633a47712fa698a9c62327db2ab4da673dd8c692b7d2be120d1dce98417ca9f185e6791451659c8b015330c726c3f7eb18f3bb1e016ffa787b46b32f1c3169c38ed8a6c2d8873e76b9fbb2747faba1a29dfa9cb6720fc1cfcfa2de3f8e3aee676b16bcf5f0744b6b4a45dd701d922e94c81471fd39476355d4d07640b3dfd4862f18a52dee05cf9275ef24762f1f18b6b50e035abe8f9934d5cf9e624bf47c879f42382bb3dcf40ee7c0c9361e7b2dc480519a0b8db16b9ede3807407f5bbef03bd3ff9f36295c4e263907db06a327165cce6782f1e9876b9b8a854e1530dd3300dc3383d2f7ffa0c3afd30e66ce17a5e779df27b00fdc683524a2548bf9983df343b0d4160968572668267d5104344567fcba6083cfe42f9baf33453b9fda9b3c9ac20954af5bd4f5a2b6fbf0778df78785e0eee208f7362235789e4329d4f0003e88834b4ce2be9ae7d03083d745b724397605872c3c7f04697dd8c90d23dd2ed65496adb8bb8db91d8b66b3779bca98731c6637b4873b76fdb25407337500226a9a3dc5a7b2d25a5c527a4e429d6821240018598c00c98fee3743a9d4ea8ff309dfec3f493ff4095fcc709ea26a976951cf5d09e1e7aa687a91230461418638cabb8d2c1a40f04e5e3a5ef7bf61ee8035d520a8a9de80bc5585482cc3e7909d0dce89d48706a8fe149d02635edf29a7c949a263f65539a11e588cc39238bb7fd07680365df3260ffa3da5abd766540fb0fab59d0539a06da40fdeda0a8e222e3c6ed8b6d7bd5abe67e0c8f8e26377337c770129586f2f4e96cd2f948e93b9bb31fd39f9335b04595b0fadc5905bb05183446fa2140951529e5e3cae5ca57246863b77e5adbb1a56aad1e3f4ac556f7f894d87af158638d97c750acb1f295c3004fb1867c098c472a9fd81e10a6aea5965218af1f11a94b634c677bf17112f6e12d44d5fcea632b48d5bceae32844d5fc4b156ecbfc8ad7322f190cb7653efba01059f3bc235be63b055ef61901e32e7ff98cc8cef295cf087bd6e56704fd0e30be1eded5e1d9d7c3bb2db75f0faf877745f2865bd3da5a6b05ebb329563ebd977a0b862b60368514ac9aa31730b45e064e29389be28688d4a5bf3181276d9e9037373d4be085d9cdcd6efa2b60682fc130757b08abe614deb39b6fa7210fa98fe14991277a8ca2b981a82a42a4413390ac918113265b26e81604bd821b38351059f3a4d349e90cc5198f02a895c2a8b5c62a915a79aa4e8dddf9da236fed6b37632dad3ad58abaf3b2f28275d8b88dfbcb4a17eafea2bb0e2ca1959addcaccce388c0f6600b39b71dddb9a715b36543030ad19365af7ba5c36fe72eab2e1d2542e970d57066385c677b3b2a95c9fe1b2e172b95c2e1797cbc5356386eb8bd77ed2e5fa6cb87c61ccd5cfc56377a3aa868c70b815573fab35c81af1d29217af3bc291a2e4a65d164499b7e17fbf2404a24c10e500f6a127e0a00d60f3f40af410187b65c1d8530a1e88eecc2a78f5a09bd0bb998b8d88deb92ec0d51a64cbf6ec0b5543ee567758255f8db04aa248c1aa1e8223bb2893c7a3f4dbe426153c52776ecb28cc4597badd0461f3f5baf5d937a7e055245e77728fdda4d73e9a3bbf1edae5409625640bad4758257b5086b4cb471429ef61ef491f450a6e19c1a387bd28efa3e0b478c95168106bb4700152d363bb4447d118fb27ae40eff9baa0d4d748a22a05ec9ea8025df4f9689ff802fa059278c988be71cad73d28df11f69a807d24aa40dfdae4eb2391057a8bbec205bdab105b40df66ca27c4fee41302b332f629b07b7a05bae8037da35cca97fafcb28b92fabcc94fbe23ec4d7d4be9664c40185eca24f5183ed21980e6a6c046c22ad0b72cd650f344d69482077a58cae99d5e818e6283db4785253b252b6edfb453b24758d53c36e4a460579489239cdb1f350fd7c311f1b89cdbf7b8d8ed7b9d0ece1eb13d968743c2957278d56faf095ec8ddb064a764676a9a565fca291581e2e6f64b3f261fecd27c4a56702b5601c591dba59e862207372cf970355030e186252c6e3ff46e95ad6805992152703ddc32dd7e094fbb42ef97ecb44b54b2532ac2ab3e85b52b047220cc54429982558d12bb8d32e4a2e0941829e129d99951f0686eac3b573ee47ab80505cf88a923087679b364a7eb6626d758bb5082b00f3d04228192800ad8871e65ac1016ac3193a9c4d59cae497c7c72a23d9dba99931156b5941ca897253cacea921d9d76d9cbe7d857c5e2ca5a89a85fc58255d2fa28e5b4ab64a70e69174a10a18b2e0291a83abd920f8175880cca043d56f553bdea9bc894724a764a39253bf69ec8933e95cc2478f22659f604af450bef66377a97d905e74293b25659b5739fa1af3e37bbf64160c2ee04430afc5c2226ac040a567509ceedc7929bc8eac74e47894daffa455855d26155db1b96724a39d6f2f0aa1f41282090e5b1478cdcbe56a335c12e938d45c2ad58850d8adcf674b0b87d3f6334c0c20d35d8edae268a58450d3270438d89db329af474b815469d1d6e8514e659c1ad5885db3c37f48cd0cbadb0942333440a588996d2b89e5ef535302cb9094b76726e9feb6957f374b419d7733b2cd9b9fdcd062e66549b73ced9c49d555622260c012c63c1dee955f6fa6507d06462b55a8336ae0b89bc51462a9950273969eaa44589898b981242c191440c9a2e89492b3bd1c4b68928f78514ab58caebc4aaa851c38dbd8adcc4c61de4468e31ee581eafc70746f582619b1bc619127d62d12727fae8dcf4dcf8dcfcdcf0eb866191a757cc13e3c9913c3a926747f2d897074bd53c88ca2688bc71f151f59c27b5c331c70546e57255ea1eeb34ac5f6532192a33655a8665a48c9599577861d75c7918b6893e3d371247f2fc04995778a18545db399125dfed481a5931b2228885bdb18a0e24b952015eaca20347ea8d5574200a973ba7bbb18a0e20410c928a1dd8e5a9c98721091caba467f24c9ec94696fc1ccd7f7615bc21e24a874bdc818d97314c45eb63a3fc43aae1c64b32dc78e985e8b29f12494b232e979a541a37e299ea58cf6baae3d3d67a3e6dade7b510ed319c9dea509deda34ae8db76718d9c351b4806afe8b9a65329aa53a343333993f598f06454a33abdca3a1b59f3b1035d5845df3e3aed334fdf4b8834e8291362ab4f4f9d105d2e5447d660a160b8f431522d5c4aa97069769776b50f8bac613d7b416065b9f45bd7773d8595dc4aebeb4d462ea912552cb195bdbb7edd33cbe2d53e1fda97b88c0646917da3dd4c8330bcacb36c569cd929b14516af8a1f412e7863153ec6703791a453ca7863f217b38c6783f48bf194360babbc209000e7c62edc48c5088270a9cd1663b482eb61dac870b95125bab8c6a65df3876bda357334303c67330a84bcf3a75d5c5cc99b2c07fea8b05c098644b88c40ae51656078b03ef4d0b986998834425f78aa930b558ee356b7dcc621e5b9b886573327b6f0fb918b791d433f127a288653f61b88a38fa18f6fd794e0e51384e74a14dc480509621787e86a5d0ed10db1b45cd685645665a699b81812792352890b854221b0f361de39b9d5a10e8788f3ba6f235257b2a693e5341ca252974374fb9b893bb1e4100a0ebe6105faf2dd4a9853b32ff74530d47143225c6eb79c21141c7dfb7d1b0c93b8a1cf6e15162fbb68443acfdb2cf0e20abc906b98a0d9697067eea1d06be51eaa620350dc50096caec7fdb8202658c562f0e6c3f904b7f8f3865b3beab4e156ff87c801c13df40e477de8b186b699d3ae2eaeea4fb6be3ea75d51c67a33876b16743ef0ed8772782ea1f7c6719d715cfdfafdeea16f47fd81c351450f891efa26e2b22f74d217afe8312ce248a1d081085df4d8cd84bc4ff4edc81ee21e4a819b889b44f0660bbc11d74d8a2c49a47edf0d87d91c0a2b704d39b4884d2496913443d32564d96355d8e2865c5363ef248266d2916c01826dd247ee7c30b18a9952f9801bf689487137b717cee66969d3669af59412b8116f8337e26530c34008423064c810969e9b2f08a974c2a1c6343a25f9f9f141224f4c2614ca8432fd8405c94c32e7c7d2639a730373ce1a9b5f109e464673741acd9e1e243f2693e90709d81a7a4c23941e23a6d3a9449aa69e76a1f4a04c9422a38f765dd7733a15199548a72153c472e69c467a4cdf4627272258d9b06ab50a3253a9d1d7f734648a584e483262ea993da64fde911d9548a71e2986c4727a78aefc098542753323934904debc89450b76c4a205162dccef74ea399d8a24f9f139f9c989cf952793098532a14e7efa42224e925cc982648ee43dc588e42431d2d36342954828530fb766cf9ca6d7d32bcae4c3e2c32ac982c4f4b1f44c21f4142991e69c736e45e69c52957134b41bedcdcae0cd20d332cf8d37b44d42d264b66506b247f6c81e8ee3faa77fba7f9e100155b7eaca37ab98e0e2e242241623326113f60466666e261c416f77cfb76c1fe47904404706073ddc3ae2cae0e008b7e28d323838d2c3e3f87941941ff8603c83f28a2dee000ca74872ca11218cecf01840a7c89471ce504873f94f99f3292a29943eabb7d7586a51d342214d6ce9c5243391e7a434cb6aadd65a2e06253830989430ace2579a5bc170d65a9570e9d72d322232c22d7909a60060ce24dc100097250f072e4b50c4135941f0425528e229c1995e88514a5999abac999473071eadb55a6be93cd7787d0acba4949990fa189e31c6ec339395cedab5e76378b466598682a1609a06d3609aa651a69f10db26f0423eed22917e7e42efca6cd22c9bb47bce466100054301a981a13030511898b09a4d5a61192c9b9f10edf4138282a180b0cb724bca6a727272424249494931d5f909a9a7b567f79cb046c17a4e1da06074523e0a56b3af6928a7a0618b71da94df90b7654e8c524ae6988517b64e901aa4045ebde46aadd6da181eea15513e2e007a6d9bf668a794b2a3c64b789366f3614a7e548741378657716ed83d5feff48a1f4a21f6d92724d4cdf494a49ac8e24f1c7821ead573eb5ba706e950af209f2623937821a9e6b443aaa1326463b35be7a7c9cfd6db4b785dfd26a5340103ea85f28182a15e2660300143a4116fb5a94158d504abf8219b76d983766e2e7fa3a857eb5c9e968235480d721d4e7ef3d24f88a61d4093b1ef90b443aaf94841423635a8972642e1be2844bbfd6097d1c0d013211b5290cb9f6c72727242fa244a4a4a8a697e51c8d34fc87c366f3f1f51d4b770e16226a354047227b23864c3aad013a19b2a6cb81582762ed730c1a420a426b8151231831cb413694494fc502f948f2ff404aff8a86ea6c1900d10bc306473f9a49a5973f9a817a35e11646ba699f8740b18c8eca1aec6ee9deedb688c517bddb0078362a7317ddce2a9c62b2cc0d50fab98be792cc7b326d6844df7e58df69e40affadd0db68b6f64957ddb3737375a070427d5d5c4a87d5d79fb51cbb61ae16195dc892ce983553056b59474b34c33de6c65cb9f76e617abecf99c51695f69a8b1d58f1156b14acef31238ede2beddbe77c29e6dc50d7ba79bb9412f7cd41c9dcb604844efdcba5a4305bd78dd17383786575880563fab35c8160ea863a804ecd70a931a65aa66040000001315000030140a878362b158305145b9fc14000d8da65272529c474914831432c818030c0004000098010081999248002e3302ed9ebd577decbb15e557dd765d8334e0e23d9cfb577cffc74ec4038fecd5bc35b0a119d0c930f272a3a1ae0558ee0cc100b274c5eadd9c2cf8d029451d1fb675b716600b8e69f4b75d0bd43f911abee1da2143d85186648d5dd10fb59df3ed902d147c06747aa9d1fb85fa822388a0f613d086886f137874304ce61c93e75878a9e435b2c4a0268ef24a27e3d9ef1d6333ba599823b0595d1bad0fb265fd64d14e395dce27807770617ef15dd9755d37abf41bee59875acb0cd824d71b99b76e296b41b06210155196441e8367d01327210806aca417765dac381090bd700717002141f4e8925dda174e7d3cacf0997c1d8c71a8f2dc131216d2dd3757f9e18efdae45b4386bb5593e47679ebefda5aa6095abd63c2fe2162b5ad9c6dfd2b11ab819b242206a59d241ac6986c2729a963e9f1956e81914faffc6c28cfef7db1afd67bbfe4199c52f38435fb20aa8b45480eaf1e708b9428864d6add5f457d0e0bfe8b034cfc9f875e16f33d8648960695b19a74ac6ec49061cbbfdc6d9aee2c5e27c247caea0275414ab0c5b782e5d309cfd73312864f532103fd6ee7a4b5e9313c1fa18e7fd6406da3aa86fc3db444c63513c8ec38534392be690663145ac8b948992546e5c826cb52f63231709594dd4ce411237198a65b2eba253801e660d072257c75bdc74f09ce9338612d9715430d04b44ec11eb3d857b73960ce27e6ac4b668ccaa8b01568e92123e6262123f65bf9333bb0b65f0991098371494356308e6fb31f0a4049872e680d66418dc590a136f06b6e09a0a1237e39934cca2aab107469950bfd0fb62cc0c8b83f9360a609b79d5f5c892632ef63ae9a4d6b91e823b978309499f5d1a5686d2ef3e2887c45bec6efb2a2eef32daba0c7079a7cf0b60dbbde876a64f34f43f68868d33a881ee6a2e7339163a01c0d640bf985ab66ccfb45ae8da65570e59a5d468260165e996ee2b38429f3afdd7a12c738a88b1f4c56bad16b5917e932139f5fc1b02b4383a9fa3b3ab336b9294ac8b3a298181720cbff68e80f825ff870bc665be8d22fdc824059e8e1cfc61d23c67b7e17319f3702e7fec287e36fd8914d09d824a2f4e80e4bbfcde40c9877b23bb619c8b57a0e6b05f1c12be4383522c2107e9a49442903e371d2369d97984cb0449d76555e8cca3b2ac6cdcd95371cbda2b89ab872b06abc07b83a7bad16065fbb71e46f4d30558f36b29d3b0d26e967dc96234930df2283bd5f35a72ef569be5fc0883155e7918d55b009f5ae93e9cd079684f99b47eb985c4006b135ee4648632f3890b870e11ae960a70c79f32999ad2bd0e0b55d6813a60ea742d6f808a6ba741acd49e7eae1bd6f4c103f2d4e285f281678ce89d834ff2199f82c280d2286aabd9d25118870572f3e04d9a36a0547751fa260a3e0f307a19a32623463fbb96c73da88f15dcbe0e8748c720ace0a813d2b16a7acf39f62b22a6ac09d53ce7557cc1d5b31aa7b402dc8465824e5dcf053cf44cf7253299ab061c3c247785b9712bc0d79457260a4ef24c6fe8be797f57def745b0ed6c80e0fb7b42742a4168992876fe1aa2ab1991dac4eea23532916a58a0996849acac768b469e98f765342bd10810618d20b2d96da8944bec79d4b2b0e46caac9d89d932ea4d2f275f60d89cb519c8437ba4720f4ed59504fd25b523e4edb31f63a7a82a4543b8b3eef05ca583487b95878712d3f4da1d88b93e42d54f9af46d6f27e72b113cf9a9b774b518dd0a5450f3bf9edaef17cb7a8bb66c65780af482ccabfbf81d76c87fb2fd3aa51ecb069e5e9ee5923ec52d0189c3b98a63f218dd7c5c7329933c2288c6818df195ab473e732d1d7fe1a1a85e43e25d01f53b4b1021cf8f88817254c6cbac4dbac77584755ddecd60a7b0efef4588365ccf0e067ee0a80463bba5590ffba9da832509f2020ca3c78bd81320902cadc084f4fc5427633354a5dc4f934e2a740ee782ef88e8d66ece1e6d4a63ad00721c3d13500917c7f207ef43435274f33a278fc010e12768e47a52b7154a4b94107b50d92c2e1dea11e0dc11260a209b81cce254f492febed7dbec2212446fe3f22e871a12c46b47d83dea917bef7bda9e72580563eb5f3c4d80e2cb5f5ff1c53eb0d41a43aecdfb93af44f7e36fd72bf612a70ed1fc92e44520e436ccfb65975675cc1f14e28087b6f9f5b26769cb8e6a722c3a06ea18e1e7ec38abe30711b352da7235e23d10c4364f8c5f9bc2bd61f4f52f3a75819c673d8f77b176d325f3a4815abb26dc9bc5448dac62822a8a3d74791efe857a53403cdd3cae98b9cf26baf4a4bcb6059a6e4c871678a5abb07c8a26400c03f2493687b4b20df12e4e3364cf5107274b1dacd2c76765f8b8e8123ad02532404e50166eccd88b6485e2eb9ece1e1989a584cb7c43711e08ea619c1d102a5a5b6561908c884cd7f2b786b258273ce834c34103f4430429a21913cc5ee6ff448ee6b16e51a657aa3500ebf76a55b8e6978f15f141ac857225223171ff6383e08a47b2820c38da23b1b1f0fdbf2ca5c7cd1c055c61fb2e5bb78e233c313412819be9755a071a4d44e6eee334f95f720261aaebd5a6c8ee6dea5834a515dfaf7463d7fbbac8729d1448e522dc1d3582b361f89830a23600b537d91e6a755f8be798e54dbc95a7e84acbfa0939d71909b559d1fbbaeaf05f645070fe0d10b34a1a8ff5d70783b0cf2abda80994588d1dd76edd93933b600c4d3d8336d4742fae7e2369872bcb6e3fa2b88b2a73608727a8debb48d732f587abea9ecb5fbfc2cdd56b1d3362405e78b34690c2eade68c32f68ec88839b7fa71ce28838a1ea142c0c065c6e173b026598a7d24310368f50ec9f43f49844564724e226a47c87e11b14e34566521d6388326052d4c9201b6d91de1c51f8e9d54fca6bc5907f8096f2f7bf34864db1d39cc95cf6b154d645f0be1d91db2d9dbe328d542e1bb1b33c58444d6eeb789fab2e3a285e1ae9663968b1a791fd8ad1b6dbbe9ba105880f6f9b87a254612e51d6b41a0551b40a49ae8a9e87783418fad8d6e5131bb578b2113070cf15d7262b2a8133adb85e840c7bbe8777cfcb2bd0713e2df0d8761dcef7e5901e02d36eec894485a2dae60519e4594689ee33ecf842d2103de151bf02f639826fd3978396c0e9d01bedd9c27a7bc4c25b8ba9d4ddf8608302e80b7296d63768beb71009de8d3a15afa21566d06a8929ef1c5093097667eb6ef2fc97130a1c9c6be18ef22525518629f87f1f1874a29cde7c5a6d254f2476cd2838640810a1d2284b4cf86b164dacc4346d4434c2327b1c16c7607695a13a6edd3cf33274aaaa542d9d85c4bda9bfe00d443ea15863b10030c3cb6c738dfff79ef18f4b1600469f8f8879e62a60c381e399f17b51d311eef1ba81efd213166c06c8fe2704d827ef594a36396bfa3ee2116cac554c4ba488ea4f607baa2142b3ca2384a4d0ef88d26ceac3b9a3d8c7712805fe3adf18e82ba5820e236f7f903eb392520649cd6b480a3028dd2e912a0b44cb3ec33c5c6f3273402c492b3a0b515b452b28a4b5c59fc116c17b90d0a0ec82a448ed5bcf5f4ded9f5224993435bc63152af1b8dd74279f4c175a82ef0d803fc5845e25ee0b549a098ca06ea52875f5c481fd5656daacb4d6d9f2551effcd3e51bd12703ed5002a27a48e0d3748c00bb8624a8189911449ceddb054d02f795b8f5df09ee1b070e321c73db961d61980a2c72023e4080fcf5af51d5cf757c3e788836d921785dbdd59b8c1b4671cf07335aeb72069fc03ad6f60cf9225957842627e442809751c8e0b978529897b3763d707c65f460b9d61d1cb911c24ec114a47d1cc4eec6fb81db4f530abd631a9733536887cbec0f2ecf4b10220ae71de4f900339677aa49ef3aec47620c2e57c1a08ca997907ee99d645e3af36dfbfd31bb4aa06bf15dda0d76f29defdf4fcbe1ad2a917c90443ca4d93c7a2f517ef6f745f9ee9532d40cc76e5bd9114ed209682fcfbdb46b6954fe0eb9f62d69f76726209377e681c619b2b60eb94700590de0c5a38a408007a366f5ff88e5c249bb7af4c16b6348204f6d735ebaaef04ddec718bd3dd6d1fe3524a055b39c7be3eee550ee09aacffb4dcb2f8d90d4a6b6f7df60ff505a6d73adcb22417ce490fc7f0dc4a3d70585ffa438e8a17364246c303818c4bf3dc330d0a000c80bf36d94853bc3b6283fdae380048566ca35b4e55802a95cd906ca9588da56da31418008d6fa32abb626495117f81ed13012347558f1ae270c7f1eeab679334c3b9117315a3b288c40ede70214b15e6c77b580dd9766d36d3950af564bb9c9224b3c66ed7d211b97d3bbf16ed832148729f3ee4cf1a63153f21712605d5530eae2f53b18a96bc67dba2fcd570eb7054a65d872aa4031208aeb135282600c7f6daa950801456a7d01d8d07a9e5ff606b9d7053d22f3dbcb6d31b62f773a5882b0464f3070c8c529d3642165f17e629995259e9b094992f26f9a83da40940da25fae73c738f67eb21fa4c2e870800169c8883e3b5c0442266470cecbd397409883beb04eceda7b92220f370335d8deabb9473442989d3bd784b0b737d2b887c90746fc0dbc0db29d295ba81a9c9a568ddf7acb38e206c58c6b8530a5c001acbb1270c7903f0828961e6b40fabcee8fb05dd94eec40a843620e4652f6635e77d0601a396f4c89997583ac5fe71b1ef4ad4b52f3c271bc9b400a1b5df594db22d978967dbb2cb1872c369653f71255fbd429451ec3e8ca1efbe30a572ee68717591bf3f0097ab070c171f3ee11e6857c654601526667da0488b106476aefe63e5ab23cf9adb8f82eb44ce973784416fbdf3a62cddb258059b43d0435528a0bf841dad7a9118508a04fedafec935ab78e4a2cb29d57dcb4dc4a0ab133ac9002dd5a621bd63531ab07db64c2e689568fe8d1ab1b6700973379fb9968f337a57bb02e120fc16b5d59ed33917e72cadffc80a5320c80193c9909b1be42491afc06a825ad0880407fc1d8db9b6d11f6be3678b2283f3a4db0d00ccb66b2626b1fc5a7d837b4bc921ca5904b63ae4ef482317f8398afc2c4619a62f57bc5602c3eaa3290139f7c83c10814c453bfa48d4534bf258e44b12158661c3d3794561ebdfb223cdf1ef311ff86a9f3637fa2c1b74398661c815583e1a642cb340d00ee8bff18ac2dd499daa1d688e9cff0a5463e9d6d28f32075be51aff268c69181c146cd423fc71324376ac97374f4c40932ec811fbb9db8633379a758c44a671c6ece3f59b957b1fff1b79f885128b1c6ba9a71e8c85e1c8ee0b7592a342e9b6dccbd74f9822b13c805d53e0741bbb1d67f4420e96fcd38d8cfd49f804dc1c80dca97bfe0468d39be6e771a2f403ce8b677929bc6e395d185661c3e5eec21f5919d619a71e4995e245402986ccaf212311144664e6d51692d3a18eaffbf16359154e19568a7cf0defbbfa21e0ab2cde56a83597413a542d14f974330eebced71a72b6cea14d763144dba519473805bcac2336bb416364446da00cc76cd0f8695cce4772b274634e9878654561d5d409e3699f1ff8b8dd1c3e8601cd38f2d608ddc03cf97e00c4adf01e1f2e6b0687e38fda2376fe48b6837dffae8987ece72733008687b41402cdaf4dddfe452fdfa9d80f7732aba49ab5779a71f4e6b8ab4235a83e259d549b3620ed09f9c44205eea6c75006b0e731a65b822a431f658c6ed494b50bc5746bc6119f47a400237ec41cebeaaaa446d4f440b83de30885d67732b617f7b9f26d129a2033e0fdb1ebb66d65aa83a6b5eb72c631097d3ddb587a2adc9da59551e961bd99b3c1f5301516089e6bf2e5d4520371b332b48f39aa6e21dc19d19fea18edae7271f86f6d2878b257a2352046b7280f03b48cad4af38315ec142557748945fc52ad3434772fe2136cb32036abd87625bf107d45bcc95a19f96269b2aa3351a2ad2e22d5ef64aefc8f92f703de1e5219a6455786cf1d688700a5c169f0bf25549cde4e3a9d241f870962eb6c86fe4f6f03ceab5fdbc467a5872970d23414bdc4b03bc175c14915b2497c4c8b98415604f5ea0447514c86cb73c75a4f724093436627f4252bfbcb366d88eca72955b2b2a6fe98bc6b7715877b634b36ab6977a458b955de284ee22f1f0ba40cefa48887f073107bdf2c5152692402e711cb7195ab18bbe38eea8a906b89213f8961304e32ebe80af21fa52c2000676561f61d63022ee31fed75dcb4c6ca877392e392ccfaf8afd474c5661cf6f397b037d200773460cb6d09884499ae486c95fad26a0fc7f2514a09720e0b5156c348adfc90799f2eb86efd4b919ddfb5be12f875e0c00fa10009becc94cebc818a56b75d18e09ae4b9c0427cc49c71460560d1d82a6ec779ae86a6e6105522f13a4ae8d3afa8d0c2c4f70a4f1fce61b9b0d4399d4244edd5da44d18b872dda3ee46f0882c7fe5d190e57cdadec3b216c6c2754e89c5bf932e88ed2c878e8b0ce25e98a154dde6791aaa0c96184a43aa4da2b835db485f1fa4f7f6c29bc5c9e24e70405ac120f44e9fd26a91ad114f6e0e481136b471c683e1db7f1d6c38f08e1dd729de455239042b10e34607fc560a8f03146d227af7229ee3fd4bc5ad80d951dd84e748e29e8400ad43f09e3fe5c9a6ffb402de3d1641be69abc9e28680cb2d2c2b0e324f9a7ed579ec935fe3cc4076a714aabd7c79623176f37b53c8641f57fb11b2f6eaaf04013e7cd68867e09c13bd9bb28b0b60f351703cbeee3ed810b7e7ba161a448695779464ee68960936cb2ca59e8b6c8fc643a03356d42d82aa91f0693b561485ac0f58835540d17c6ee0f1af6c58d35d586face8ea0b162acfe091dee4c46080fc5563f26b0db9736cef9bcf9a72f415eea56b739b7a054281d7b268c9733a9cfa148df2828ba3979946a178a446f109ee2c06a290fdbf1a12038f937022f94e3d7c3341d3d4f2aa8d50ded7630821ba6b4503c692c4779d60cee4660b6f3ebbbeb7ecc4f60476768f43a252650fa8c1730396b8f651e39e86b4e1e3c728cc08e90ddbbf0e090724b6d5e5b1169f371197e6705fa3aa5f37a5b46420e38d018c8acc74d7c7f9a453c53cba4b825ea4d604fc4d1951579de74c0a1bbe9dd64c8202611f8ca9b6c2345b363137c1d88e3ef67136941a3309ac9f7efd7912cf130eebffae2092e3c2e1d2ed87fef4e7425d36081e8b0a5889dbc3c2f3a22d1188d307adbbd0e288bbeec422126f48c3159e3a015919b3e0198e4c618fc889e89c896b0a2a552c4d29b81da6d1846ba02fc9ac1b5abd96f1dda97f12ef1bed92d1e61c475a3d611f9b945f459cf6051a4c3962f70af4d525a44a3106e96ae58b28780d0ab0570882472d7847f465692c34c165793e819688383f182e7d4f94eeca3fce276f6edc3c042b8e45a3ab5ed7a4dee2e01763012d13a1f4eb904808569327e1db50743821af3bc32b22c2afc2829dbcc1b67b8c574956511cf4efe0d519d4fd84cb56cd7b2c2648d845814494559cc1268d64bd0aa13b007b6622dd26415a26ccd11f17917bfaaaec38ad3f160876cb6a6b385b380b8be0bafd51a954a5411ef5632a5830bcbb60a6c82a479ce8595bf6f00bed385e895bd07d238c68c958c537f0f4d6865bc606e85c7a46f35b9b1212a0f03328361d144bd85bc148103e71a72dafe2a70562e4a0d59d924e3bf3837197f333cd5317f0ce5154ee03e6488669b5518bb140bc4d4bf9972f0af14776bce86b1d1b73954de37e62b8003a0aa4e5628bce886dccae018b19ef4f504696d156822d4778f72165b9cac3788ea211d2d048650a07947e94af77d621b416a82de9bc4b8138364c3ad866712cd461c827f819a93f0c472da152a761b58590e1307e83e696fe15791018420be5622d9ab4c31411ba9461ee527f28839f5068835eb08f74eff2214209a4b281381962bae835c776dc52fe88a00914e2297f7284215e0f01e9af60a5df1a9fbaa1ccf9494c2663db31bc57d66a932037a466ac7b10e073e66111655296f50f03c5abe701f127f4b07f1a9dbdd4fc861b023de0ff6be66a25b03467c16d0f258fff2dabdb90ce87252b43e75f928bb6e472af96f1e07cc7dc18003273b928bd270ba31b41a8dba814d764b157303cc8a60fc355392e5c5de170177d7af4847a0ad5da9daa9d42d5a00e30a70aa89441c30e22531b67ecfc5fb2bae5dbaee4256af265cfa76594e538c7d2c8327c7c4f67d347fc5813037c81c30b288ebfe2d3ac68cf1de49673f3c17539070fb36cef801b6cc2d44aa7f45771ac15d9131ff3adbbc71132cf7142d207610e5cdb86e7db35394d757a6903bec303a7adec186d701a87ac08e0696904b61c6e32a4e05cbd5c4f5707107b5278e0e89ea8ac99daede145549d01f3f841b12f467b32880380d27080be1ea9d8373c2b36115595df383a637f48b9a09c7eb65d1f578ddbd69c685c38b8e3e40a85c0bba1efd3cca764191e1d84c0447976e43f11d0dbe61141d240cb051c36d12552259d6a10db39ad995bef9ee14046e70901b0a860d4a3131b0d8a0d1140f09097aa540da3bf9aa9990a8fc420a6cfb64d6330b3a010c114aa638cdb669858cb4a3140352876843b3d8ec59ad8b5207193e09b711f1e42a56a9793a9680ae9954572ded55662a815109b6b858f31454628da666c2dc289ae9e781d468ec30d9780fd6e28326a4ac1ef2d22d783f5d311d70a5e16caa28f0239e73ce2cbf1e4bd523cf9d2529ae58f27f96f3608c8c5ab2adb80ed1c426e9a2a4950390df790aa1a2365230fd60002a05fb333dda508f0dce5d792af142436dd7fce0c97e35bcd59228bb5fe7eaa235b49a6144489ad98aa0e74e9cd76fea1b0162edc06e96d7aed8424c48285bc54e0640854d5d7d8fd6ae76190c50f81270000361aa8f248fc8a1ee5e9bd7b9c9d984ccebbe61003635d967d5355f872e01b0e0e0c03f715fb59cc38af5093221abf5bb7a0138c2b6815548ea35f4f701af4706d41bfe02a48d6f3439295a8ede7f01fabd5471abbd70e55c3f7fd49ead75503ca77e35a2bb419f675d0ffde93c5b4be1beb8bdc9185e9283285e09e451e8d894ea192128cba5fcaf07eb5e2f402500570d2c2abeed44a7f70a24eaf5fb895732cc93addd30e9e9ee746e389f88e4798c73918f1017f8c3df34ceec50b873f50a98829a17d46ce205dfbeef8e5d79ced203a91e75fffc057fc5e873991a2a6342b557f8af8eec5831c4854c2fb608c99646863bf952c5feace752952c405e2f4fec2bfd6a2b838afb5d6450ec3978bc1b38d38b9fb8e6d7bd2f7390ce7c54c4e543ab548f2e7ac4204b013467c88631aac7c9f04352254177c792169c34a51220914bf11824bf09f41e2c6fbdce380a2754c0c5db7f801d7209a2919b0f9253d0ed40cc71ca84d8e53491b793949396e8932a464e48a7350ec8378cd710b408037f82e41c0d3f1d01055528a9e446d60abb11c6df8f617e3d91fe09b847d9e812c4789bc885f67d6662ee5eff09095a8c2aa307411e00172c4c7a8051234963d76bc3b9fbf2ac3e7cf7b197a5a3e6d35292a87cc34553194b7d6343ed4ac8c7128c5bdde4ac987c07d1055530ab0ef3c47acbd1a598993bcd9076a5eb1ea46d996fd06235a003c8efa44090061b1a56284d5f9856522a824698d028592c40286035d93222b2315842eedf83c64dfaa419ea7d3f88839779fc5a6a66fa89f870a79a0552a9ccba0bd0af9b9254f78c3fd3cb5e70b424ed7c299583b9b28217a232aa078bf68d5b5371e6918fc3dfbcfd227f666518abc0e9384cfef8c95952ae79cdc8478fb23f09f77346945dc7c4ba0b69d3a6c301e6c637a33cd56e310c403702240717a5cb0fc01117eb4e8b19ea71a58f8023918501a375db8d55db5944fa9c82fbbf1f44c0aa411c81d86347b62e92d0737cf646e67b12d3396a3bc4b924ff1af4826b2bb559f9da9c4c1afc1a99387a92aca2077d38d49232d13d9f2f13c91805ee2d389c72c676877b4831d2b640813525b2d7e01b4a82e7bdb31b28ecb102fa6db0fcfae2dbe5c1136d16d7523d966695217248a34beca6803638d6aa387d15771aa0cbfef1adfe2973af6e63739ee1d238c0e5e3a43ba4818e626cf3828661d440cc9d8dee2b644469ab092158b90438cb1e626cc9ddbb504d83787e6d13c978a2103762f14c0afbc9519198d04591e65c2376e480c54f712ecee46314173dde3c7e758b222b0f097a8e220b3f62feeca5874dabd799e96089651e0c72775b6011745664f1572d4328697197ed04b2bc3472391d1bae0abb1ace14178f4ce4859def01704a3dd9e0603888a2ab08e2b2f728c970b793eb4bd7e370debd3f306008f287a360ae2182735529b464566cec6077f241b957fd8f99406a02a093ae9e9843f50795a3dcecc234096b3d27da1c1362c30dcdc109179323761e8acd63fe28fc563f7da4a41de6650dab33b68d275d2b4135a2800bf013e803113dc9b4917549301cb9219bc662d4a192b3243d8739bc758a68adfc09efa4f34f0a0187cf8da87d7e3ca5b440131a25cce2f6e4453bd070a890fa00d3a06a16eb31bac39370ad74a02ebb2346492317f3671c0d3e63ae529715c32ef78b4f5f844780f179a1ed7555d2c64e68cb917ff50d0b2dbaa5d19b6b7d8adc402597eb75600518710039038b5931931b763aab718c8f28e21ae1362cc9f8b820774cc12f8483194b04afb51fc8fa539cc2397f067c517567808559282e5f0f70741a58cc8b76ced0319d70ae500b15297f7d7b520f0985f4dc85d9fdaf5ad8e65b0744c507eaa2c01f327f36cd418c10947ca52217ca75a0f4603d84ab8ede2c2b8a590d9128a63cfcf0f055073de928c98a750ebac670d8279892b14ea1849e3202515bb04780eecc7c44fb462bae69e80d6dcf308c119b941f4b497af51773fb108a97b03c4d9df490b6188d00977400ae22ae506fa22b1248e04841f290f6d39b6805067ec2a10020b3824f8129285ee8f1f6630aa2369bd48845900bb4ed529977633bcb8830c9194217fb024c3228f89571543ae80567bb85d7f2f14d7f21d281398d0aaa8af297ebdf7cff385e9a2817301907cc4757b1947c98ae570cf099560c72792f01b04ee7064be2e185656f822f16cfcb620ed857c64fe18fe8adc6bdb7273ad2bbe0c7cf320c073afd5aefefc89359e30b0d78fb853d514a6dfd3fd6fa832ab6f5d79fca3d54a4d36b4d16ab46f44980d42a4512fc2d86131bdb0aed452c61c7b0cd2575b158a65f3a1c3be85b237b8aeda9d8ef0b73235ee68ba43e89c8aa7d5cb0f967123d7e62c7329a46c3349df91123cd6c8c0151c50a0436e104b52f95697a6e7c3054f2431c574f8e9fa0cdf5aab4f94ccaa532a345f6b04fc63e883569920a9f0c1b95b211d9b64bb1c15f82c4a1002c4c2bee69596153dcd452d897f58f31d04db8eec9db5ab8578be8a4b35cb57470a4eca89fad8df3203b11ea0f30e0aca9600d54cdad1b11620497b20b4d5d5668e17b6171418de5d32cf12bd1ab65c88bab223ccbc06ce570542f3d356e41f7cd9e9e78a5b71f660365b2b7d84870e89ec6fb6c9de18525e12f94254064450df0cf837ff9fc6556fe4014c09a075dba1a43edb0ea9f4fabf56ba1358b9ebc301d2ba792220dd55bd0bcbb8b9759f44694710bd3097ff106b6d11c4adccf4e613d05dbb8c10f6ab02b94d83e83bf3a0c0dfa9f28d25f3aa4d7422bc648f99c6ba5be9134958c77fb2f97acddffc66cc99765147eeaf9ea5d9cee3f460b9a4b02d75cf76234acb905c478c08232b3deff7c7bf25df6ed4b508e4657d9bf18ff86a61afe076f9b6ac0fffb7a5a4fae9328c0c91e0152aab47fa147690cf6d933d923df5a015457b176b2b2f2fbde115eb87856649846512ca0594187cc06c0abc5e331174c89e9daa6a07afefb5999cedcfeffd0c0714dd02f5964464326e5d54fafc5f44e7b45c3327ebd51ef84a27d5b5d46fbc4686f23303bf940df2a4479b4eb1b96b3f1453baf391310f7ce27df9c278065259b34ffff453c821281ad939f0875ce296d36d308f1821982ffdf2d1c0a9124d339cd0373cdab1e1ab39822150b29f9ef3be2d99d5a39673b1c9abce0cb064715d0b011ce90ad8aaf3652cbdc6bfca2744087b93b1762fae0730f6289d4bfe64698deae84007c67c15d60a89829b7316a43cd79a9a147a802d1a108a5df8ccc7a576276cc4200cb12b6fde43cc43da4620b957362912cf6fcaf9962701759d48c55beeb13e1941f11b22853d25675d0759cfecd74043bcc32da78c879bd133ebac523666a9d9adabf6e6f0a99af3637621c5e3a36642756f980c3b9ca7c3884e9c86eeae042031cab63c880695c95d6ff72d6f00c8c629da27f7f20508837c04c51b1ecf708b2dcbf536f4d7c05b031072fabde9cc47d11d49c2277a9bebec0967efa72c8e9a49e7aee74c11693ba81491665118ddd4958084c89df49cd1c92d8c2bc0a933df5f2592e6a3a3c5097963b3d2b1d4524153cef46e0dd1142b45fa70798d1cabc660dae377f5be74130476b73b224e4a460742e985f14f5b52294d0ff2fe3a495075f74d904bee48562e65b7981c384f1247dda918ef777e3be6b45e5ab61f6e1b249b0659fd8bcb0c813c0d40e9a86d9820817185ea09bb55832f1db9af5531031f7f2492333e1a823b19e7762c701a17170a1e0217fa7360ee1a511fbaf8dee88ae53eb49d9c8574807ffaf3f1c95704042286df338f089706841da6fd50f4e8e6f2e3c42cca26b98fa3c5d273aff3871600c21a36e4497d92b23a04850ae55d7abf5a4f42664d36c7cfa6b9eff4786a1fe44eb4e25fb8cb552c920fb6483b491b80d987956703880c80463932038487c7e5e0c216f7ec44f7c30b45353f4b4d68be5ecb9274229269b85f66e96f7740c4f6c529ba129de3d662e7aab5ba2e4803115726527b13db78e1b9679aad883b4f848c9a1db77a23860ba33b01189726fd793ebda07afb428882e1f06c788a4f9db59c815ae1c7ffe4c28f9a2441919465f5501ba17d88c34162cffcbc8d578ce3dcd902074e672d41ee0cff969826e2ae0cc4b91b8aa852a8c4afd9a3a2822f99c43c6d6f75d2dfb160190ccd0ea6de18373da16e109ae7147c6d6c6428619c263f3e99125861bfb76cc33cd31d0de7bf5795e8bb8a71313935b094348617ec4ad5657bb78b3756e42081bb8657f22c30e4f5f51495b2c89923d1acd044a3ef97b8aeed1e92d890f637205516584ecae84234c2be2860a159011d175ae6adbd10bd30f2110d10d49b4e6dbb9b3129b8b79930c8033b8369994e667900393295f4411b5142ceda6a7e761f701baf47f6a3080b4416bfbf0226a884db4748d82a4a6175dc082731ac8d76b9dd5ba054a9c150254b460440f99e515bff489a2cf9e0a3a7779c6bb0ec882d3ccbc75ad492a855e4e58f3cdbcd4bd219aeeb1ead49f46301013a0563e4a35b6f8ac4e5d1600baea1db625ac2f928f7d13dddd4f6dca4134dc924a2306030932c62087d0e5c6f1505e4fd2bd9bb59bb01732814030aad9a1c494e6298e1b1c2402af2a5cb99af4a98869b4a23b025022b489d1a85a8834814e749229d830a61a4840b09a461b8054ee000c89522d25f5e4d562b0d4c852d9ed77b316ad853803c4e63248e0778f4a03a13d3e45c5e51e3565ae1c904a357e5b8f4044914bb3753f637c2a0845dced065b470a899a6d5138333b285fb1379b5859cc26a73700b5613ff7cffb12c04e206df8f7fa36e06b7e54643332dbad7724fb56172c00068693ce26b857195d2328a3c15d0f6942fdb5ae7b4900f6fbe457aabc0d574678e3be16f238bd691070952f6a301ba7b416765f52a7b7ade7a5de8593e4a071204a60fb8b8dccac986fbbe68cc874188964330f7f13e707e0f05781cf50423e3f6728d0e1b03be8d56443a3fb5f89aeebeb9dc1b271904224af8d39fc2f6ba542b89de9c8fefd97f0ddc0ac27be498deb68af940e6ee13897eeb469b577457f72bfa9d026d94fb2d4aabf576d883bb85535c97e593e7306178b37eb676ce82f45fa78417534025a7fe84f5bcadffa48b9a6c75c5b8c5df2fd8b3960678e35c8474a65f647f34afe9616e112025c92034951506ecfbfc3db88fcf381ae4a076195a17d54a5554d3ba56a118d009e5a021ee959b3a9ebd4b239a74c590c15afec000fa7f25f5e091754a2f6a925828f409cb51c5a0e1b5e9808d559252380ac7b95a0c3f3e004ffab5f5740bf5c3ea7a6e2f79514a225cc170d95f6154b37247fdd63fbe3c38fb116fb81029c798362fb21a3714b75b34c4c2037f45a635ff831c512b70a98ed2e4277c61945c9364a12cff01b4626ba4e0bc2af77e571b05726065414a8b6876d84cf191ee1c35c5d571f9949818d583a5781874103cec56e64c268a670b55841a873a24bd8ef2987e7527fbeb8aa35cd5ebf1399caada5ef15928a06c16ec7703abf85fa45c42554d36fd98533fa80e13582d8a1bc793d8a2be34c347138f682842ee069e26ca9489be0e3ef19d29fdfa598c5416eabbdd5e0571963069b001acccfc1d2728367c4235928663814318a10f70c2167ba43744d553b0b7bf073fe29aced95b3bf2c4222e5ee2e4dc14272c05e7b59a59ac9b73a90a8e839793ed3b13d88086d09b68eeacc35fe45770e1dd0858dad3200458b2ae084b839d5e66eab58c32d333b8b0453a08462c33a372ed965221dc9478d8d5c4cfc865282889dbd86480ada62108924e95d6a281ae30cf5831d7ce560029f22b6c3ba0a51b1e872fb2662ab25798409bf5b48f04c98037cb87246171224af2e8a37160b540c07e8d5c926ff113a60eb673f0ca9ab6b7219ff281a9534fe1f9e8fc1380353ff45ad7619a8bf4745760c3364152bdda821fa97297dd82806052d1d504fc9574692aa25b2e4e160b48e65ccc9573a4478ba742d8ddb8007435dd581492286fb85a13eed4a08d96aa0d40b82837088f8c456eaf025b910d2733b14abd5a0575c5813ae56b1e000c4a0c87f3ab681792c788621d08586bb49436395d046b066e86f9ed2e113b82cf30bc44561e01b44ba89ff779c802b201ef778d749ab42aec97a1c74af81df7f2654e32eea6694dc2ac39f0bbd1087531e9a75851a7afb162d7bdbd80343cc2814d10c45b04051bb1692aec32d8841147066eab0dadbb848f86e9dae9adf2794e9fffa0c0051143b55cc373dc5bd63fab5a59ce8264891a79ccb9091a0945fc83f59832ee345107329ac43a92bd5a5fa216f57be5e936a28bd006375785ddc75d313f23c3ac4e9980746b6b8d8eab9850f1ca46306dd5aba1a8ea79de6f334b21b6e4d95332958a318e3daab2425cb0bf7e00caf9c8b39fd77da59d9cdf1099127e067bcd87dbdab4cb0774f3f1ce992ad79451cc4f36f94e21b4e00d4541db802d47f2242c6b929c5df512b3fe77fdc455014ed90a0d2ddead6fb8f2922f9db39c12e43749031bfa9561fee61b3723b997a23de9800711fc7168068954d641cfb319e7c2c95662693bebc8cfa67fad26ff58e43fa975fbf2f0d110a9975877e139c3fea875eaf37bfabe9434740444888ed0efb5155818fa3a9a2632c6250f106db1d7a90cd0dadfa9b8f1d2234c1fd94db97bf78b8c93c3198c078d9d92729b09559b1c124769f2909ae4751b031b9865d7195124edd607ce14c620b54c3718f64d18f90f28ec363eeb3e94612b5857fdea838fef91188adc54fea9bd6bd16075b62662670a490a88f3eed222a09775bd9ce501d2ba41fada5db657ec4b85410335286b120051a2d05bf9c1e18243eead860c413257997840da5bdf8deddd3905ae6e9ff3230d0ce0f184483bfb3866b02b389039e07c83856eeaf097efe96f1055cc53434c9e8d78fc37bb6d3536fa4b03032e9696af41def658c05786c18282abab17058421c0e9f800adf4fba34a467afa55e1df70cff12132043a31115d75acd0b94a53afa4871dca75efd738630c4974a3724785c91e17aa0e14837f732dfb849cb0d6141c131c252a6e31eabea3db1ebc5a54a65a2798df059c4c54d3abceaf5c9a0bb116e1fdd40c2d57600a2f4d7ef1b7477ccbe4d86ecf3a5253e151b8f709a303e303467badd16ac4a18854c514673746d15e44590f4682f4d8b3df92062f84e909529b4481f4e1e637c8a7e06b05288feaf715c3a0d189ef92efb4fa6484a6ca48f7c818c4de2e0c6a2e072255e916c3c483127201d3b1619d4ca8c05911949f54337ad357f5d665a0def6ac73228606ee03c22a4c215567df632e4c1adf1f34f68c917158fb514ee57c52f76cd1d3e90528da3eedc630c380058bb1fa5fac644597ff5000a204b97ce2890be2fba3702be6d43449ddc21cce6d19a0408e9f38090e9e6c6c9503d0c97b549712d2f35638991de5f7938b7c9a1999b6f824a0eadb686f4bb7035ed124f389967d3764d6982098f0d28c87a702f14354d03aa69db9a3c048fb8eead5b3ffbcd21620e610dad556c1e86be88298105df471c938e9edc00444cde3b3b8720779d93f95408903be91023b3ef83c6592277a17059996206eb2695b675ae741830eaa1f78ecdfb9d9661f8039b2ae823178329b1b9412ea6ba4f7b5bb0075e28590575b1b5a31ca5a96e5b4fb360c113f679b3bb7df8d46465233b4c98e20672695b141fdd3f0acf6af4a71fe5c790137bf64c9ef3251fca61b2319cdce3c346846af39ad73f1d267945fc4c695aba5b8d91c5061d37ffcefb75115990176447687c19be2b550cb444653c610f4ad0cfeeb774d2bfe7a981a21b176784200546cd919d6e88c89effe6f3bcb65b2e461898201dedc881af29cb1e24877dd174885339b7132d6756e2d9c9b987eecad04c79e98dd8af42063b682e00bf42be8707c6654e914fd4757951da9a2bfa0fe73dd4f9eaae128acb6318e522c1c20eb413dfba0bcb46d0743ec4df030f51f9c4ae0fd3cc13c20eb35fc547897a686f594ea684a51759e1e5d0c4bf7463c28c6c75e295c339c10a3f55aab41540c77086822a728dd1254179f95d4ea72c458da71c5ffd99b74ad94c60ea1ebc5f70e6978566e17bb1e9316a75ffbf097b678a4a9e1b8ade66b44b7010138bb5920bd604b6568cfadd6ec8602f92e6b65ef72b88606688bd06dfd4be002a8a132af0b98504bb33e68429bacd260675f48fe1497b218941adbc285f39bead824d15f3db35653b9103194843e939ad60ef12ec18627c49d31f571fba984a05ba50fe8c25013b0ec702391bf3f0831ee13d21333ca82bbc42925aa32c9e366addc4bf07c6e40510e293bd8d3f79e43e68cab852accdae9c1f49ebd825186ea267cad88997d8002f4da2730b44dda7d9d76c652f1c6b6e20aea846b4bb09d04bbda2b3fa452c6071fd1b38f41346436175618d124ba5d50807241077bf5f06f1c16b7f9dfb4f2e103a86e1ca1d81b86c1cd503f25f5339ffb53492b0c6f3e3c29aba46f4a378d786e90ee2ee7c1cacbc1eae718f460aade1b1b1f6ab0b1e981ab0eb4cd0cc14a17a19ddf6600e8efc69a398178286c6aabf2040112a6226632a5947555e71db21059b83837e7f5b97da2a77f3bdf70470be4ce4ffab0482d8c394aee88b590f97a47d3cab03ef4087b579463e380347ed972466ed7d2118934cef58a431434754e128ca286c70ddecb7374507ac64cf7ee876fbdaeaedbb2ce4cf801e56457bff28b258c009dcdda0b87d0ed68317e02cb4fe945bf69b6dee6e76aa1104b24a097656efcbea7ebbbd42ad8e5df60acae4734a9281ceb6941844e2b7345a382cbc603c1a62cec99608e7b02c6b6e140214c14ab06b2097e99b8b5eadcbc93749c359b99a33b52f6e01fa5f5e76d1409f7135c070d10c4596bded43c2c0615f720346730adc01a903e5f7ddf4b3c0a7d26427a7b9256a995600709ce55f84dc45224f53062ef3a0a5b285890d237116fecc5782982040829b5e70927c26d192772af26507aadba66a1c263e2c2fbe7a099562cfb9b07cae0595b92d7d3d0eaaf2fe9924ca39d68ca762f991d0a5f717960c1d9f924e891751becd6244dc792a7be9e4558bf061001d981c40f82e246074ba7feb44b4ae33dd4e17b59175317d5c001a2bec8952eacfe735b318d07a79a47fe523d17c33b046e4b16fd0d2122c8619549d1a064183d6cbf983041f8bccf298171392aaaf99a2c27c07ace33002f8ff2b7b650bca8b025b214b972f638dc8a3926cef14d6ee698db033aca18c80903a33301dd9c134844971a0a41aa6442984161d8564c408286db8acdc1b441408bacc5c22960a11e687534f6537a4d25851d02542092145d2ac10bf597f2b774b67e246cf35ab1dfcba6f0d67f0d69cab68dc2eb5f050c6a097f1d8a0c9c98b02cd2d6c1481dd985be99d4623de43cf592b4d83c447dfcac0c62f610a6e72360554de5c8e7f6f26c840a4071a229d4222e1c34238797b04738065ae7a06b5c607eeaca55c571ca94d2edb4b6129b8b536f3224d04d0a8c94158bc03d173f62cce4f222cf2d25a49a6291e18f24e9a395c28e0d0e1e1dde9c82a886c6ccb57dc65b6b87a250cca9e96a52849c260d42f16dd1298cf1ae93cfd32120a30909a78ad52d40e8c922b312f6a7444a50ea2c2b25a9abc6a9ac409aa5bd251f919c5ac23dc1e9ee10779f59fa35146fe3635d3cacb816201f9177585c58664f7a0d86270b3d697a272024a5ca2b0047fe0335f3267a7a82baf01910c97a3bb147d6c86a97a5c8c4325bcfd2ca5187cacd9d79daf20b925367d1c47708207ba4a9362e8a0ca1a72d310484feb88eae896de41d347e34160496fb621c0204bd2160de853d47650391e15ff796f48391e2dcfe4693c4f516eb30c2ffe6d10cc54390caf452e54c1579dbd62eb8e0201d8ed43abc2146fa38c1d00d4a1aef500985b9418a005f114c136225ca0b2fc0af7d6c3da0ba23efcbd19a296e7d18a20faacedc8e6888754949febcae025d0f88e52deaa24241d42650d5749c136273b50cba80f59172022921be09551e095242c56898a20175b3e9a1b4f29d42aa070b20f676e797758694f5e53625d1dd2c00ff6c0b3943939a40c62b95016777e13cb1b4a3646e9dd80460550906081550340de5da36673467660ddf92da0a3d8ac5c20ccc436b0f631a0110b391a29170bd099a9d62dd0efb02cc68e0aa2dd2d393cf94774c1d135d7c139adaf3bb55a7dd4f1a4b408294f01ec5d3d6186d0158a178302526b2ffa40b609f5cd8d722b1596c7fce958231a56bfe98dfb89c0028bb78009b2cf0dc1e0dfffe6eaf765a73a6fad71b58e74e130956d755975457d010ae9e07643494bc978efdf38011592c93d3a151f17fbfeb1b3c73218a4fcb7708fcda77d6508fee0d0fd27c29ddbc186f2da9a06e2c25ea7b4698f19d4d2d6d74fbf8ad610b4300296e150792f5dd312e5c8cc41cd0cc72911d6f753ab84df7ba30229395509f72a6da0a07312667a961422c05730f6b320b96cd7dad5ab6aebe5eacc8bf07a6cc510ac1cd426db52e548c2389eb6604ecb4c2f459580e109d462be06f3b2a3d0a30c1d4147ca938427175b0e2ee23042ede0c02526ba1eae9643437b79a8acc4d4dc39c33e3432758c03657a046805ecc89c56a441bf566d08f66382f6f6e5422d54af56577195e932faea9d2683d4d59d85b3264a40594559f524ae304137cf16a89181186224af5215388cfd20d5cc4be970255371a31770a95c4931e4a804caf56aa867bdbfe18bee9eaecbedf7c04d07923564582a2c9ce7fada7d39563a073547f850dc2c4aebdadf2ec5f1d8e1ca653407c27aaff7807743d5dfb01c2cff23f101e66a8933a867d2200932d8d0f5461cea1624771b42144f5074522476eca02fe15e1a3a245846f8a1c2f15030eca53d6e1f8a834c69234640941d0751b0a20666d5a353d5698eb59a16ac88b2ef173386dc88524e8c19678644e9a08c19008092f89f318f39ea0d5435664c67a234187ef81dcbf930c84c1c73e40845617d8e1978386de3f914d8c2a7eab5c75f8b43dfc44d613574fbee170e59c44b2cf2d3086717855d1ae3d272098110d027663532cbfffb6d218f6d94012aaa49a2b790188b14416970c40715e681adf0b7eb771800f2b26d035c7c5f38ef23a99afeb1c852bda22b7bb6a3d12dc6175c26954b323a5d68200eb3ac64302bd36083b46b3206137fb19083745ddead774fd22e11e474f6f0bba0b04cef881683d4369e6729b70d1ce05eb52357b0201e010f6cc5ea5a15e621243b154636098a81d4630b6498ab54938c87e3602f4d109ef293d2473c0a2cb4b366d2deebfb7f9981517446bdaebc5a6c70d910c6b13a63592c26a068575d1fc2a98b4e9ed8ca34026cd937de8ec99efe4b3fb552dce3e6ba52607b126e66e18f51ecb2fe02850aa36b31dd9a1395093ed2f43065e99a697264ca7a2387766b51381720bcc1d6cb54c1cb84b0bd93f8fd6058f8398eac419f52ca4e3371d845f25c3c208e0ac619162d23ee8c519f8caa3c42c0aac332d3f2d5da87a0b18179511a6511a74a601fbfc9d1f9f695bbd828a28d94f00e2330035acb94d26f64fc4eb825070dfb8c1216d8a5f3b6350ae0796fb430e80cdab600840a640f94ac3bb46da733dfc0ec4879ed7049f99db8acce9bfdb03dc5f0a1c7ea6eb59c2544debf9ecbf78eb8ab9464d353fd991bc304fccda028cafa5e937f0a0e8df4d1ceac493b83f8a484a9d283ee13f6a65df0f02b70686ad03f464963d0b56d9119c3beea720c326b2ad50b86e2c828ca55492366df369ca826c47c2b5650f19f421d2f0f2b4d91e8cb7d4506deb12d61223e5906a449ccb5d4e3266fdb55f022cd99fc3d987f50e78cce58b51729f5130b05944da63dec208e219106bd63cfcb9da82428baae272b3ee29ab740e2a9ca2f0c16799453baf2b62d824c8a4ec961d8086f3962ae40799e90b76d0b152baf1996e8da4284a13edecb6ecf607780eca07b5b0262c71e3a402a4955283cf2c4cdb7de106fdca2b248a09cd2ac8fc696a0fc549f7b28403079dbb281cff88db9d6348f2db5757a4d9c3dd2f3410d49ee748961d06d5b61900b713b518da3cb44a54511e8ccf6215b9adff34b82acaa92ab70234d96387ab8b70095b4f21456dadc64bb0c00085a2b24e46ce17ab1de3c9a0e50501a52658c737f08c58d94fb861ca42f23abe2dfd59ba36200978cd135ced5e051b169a78b7f92bebc1c49d6b2e030b169e15b501f263aa7f5d5ee5a2369e95b00e6c8fdb218009c6a71ae6ce65c2505e1985fc8d243e2fd7b18539e230902fd78289889918c70d3e3d1430995bcd0abb5620d715758885e3f2950a9f82d1c0c518bdb3691a8d95d5b192b376ef908a59ae4e6afcd52cd84711791b77ab55e96e521a66b7f6f688a3be0daedb4cf204acd8ea5c8077707561fb6021856b76306fd85a7e1d31229d9e3c5fd9ae5f0c3e5b3af32f5069db8a3af4108e52d1792a56dda65c6cfc539ea87441fa4f0a0920cc97e6524a0cccb81daa5b14fb34ce5668c1ac84b2556078be8e9d55f431f60d9b96974d72647afeac0db65ca97b6e0fb794797654f3560e135fbff54072267b21c57f27d311b4e790e888d0e7b56ad294bdc21501e08e2880359f05f620554813f89855407deeb01228bc44c279e5d6dd179597c96470f7df6c30932d3689132a0791dbc49f3eac7c4d65bcc80a1b0f3e19f594a4ffd3e2bf1600c6539223e33856329b4970335e2e4747086716ba46376762e984dfb4c9d0677f6ca1527a7426c818969010b81b575ed4adceb8a9c64d03e8e8ea56d67aa66ee0681da3b37e7398f551f00c122e610d9b7041a427b7ea3385b71c0f2c3b44242bd46e6ad84fc656b823d9ff849c8e9998287bb6d5858fed93ef50acabede20a7c77ef2e5f5bec70f79c9707aa45d81740135b815ad2703b043291b3f40e3bdd3b664216e230fcb30948abafa1a46164c649665bfddbdb29bf817b87b572a797b4249e22a29d1ed528d6c935c334baf0406535287c9aac9bd3e330b6369e10b49c3980ae9e33fd7016bf87205c60f99ba1d2528db8005fecbe733bfffd4a54f5343050345c784abab321abe5791e610cefdc5f512ee907fe1744523095202eb132ec6ed5976f839672ae8d4e8c44148a904409104d91812205fa5efb0213d37da532a9839653b98b8e9a8b9528ca64d524c8f04dfe645045e3fb79d2d7e532dc8da9f13914a98af93c55e89bc757aa421eccd02fb42c2bba308aec3645508871b9814c2b5a34ff6f8473e3783168a146f6b2037e3f8bbb438cca98e9992955dd35e74bf89c4c4ac1f7fa5980f5bda640f51ee227084451a708dbf3b35f8b73626fad0da56589149b568a0b9fae15e0e672a08bb0341af252d0794bf14f19c77fe86785ed996161dcbdf088c499644386259c4a9d97a7fb2d8a00f947f7f2d937e69c8c9f971a9189d6922e5289dc2f453d6163bedeec3816dc32a1db3a9428bbd99f90140a2dfa715a9a57a6f0f70d365185c601fa15fc21f1494556891e9c0f4d11bb6ef296868262232d16dd2c7150f3ac0ecf30beca6baaae8340d40ceb11beaa49fd36e3021a45cadde4fd565042efe2e48fc8a3c0539f0cd17f024532c86fedd4d5ad8a909deaf3b2c2674a73e73a3540bbc0a2135493917596d701212dbd43664303e8125c15837ec5883f6367c7dcdb7ca8dfb59d58b15b020cb7644abdbf6132f55e882fc1ef47ad02f05ccae2a747d915737cea6a2dbaadef8a2b1d14bb2e6b10b10dc9f1daeb19e8bae0f20fd205521f2c82148440e350207216dde6330bc94b0a9f32ea5f29dfb6c393dd170c86497f1f8321667f8f34bc1b7839b581bc82a140e5cdfff350edc1af77f4b57bb085f1adaba3c6f0a4db2397c8ad5f4a3c15b841480a046b8f0a8669b8372ef389b1297e71e6c92374f0d55178d6f0686ba889ce2f454b309af46ef8d0b032f529e9bdc9053299612727b06dfd4d13f1e345fb1b5fb11d500de0295b2d0d8eb56a4ed70c529286314aed2d27882023d66abad1c4e0657092f54eb2c2fc10daa913669257808d71de3102a0e620c03505b76842988ccfc67e9a84e4137d34c23209751d17756a05a17fd4c4015c8b61a80388b01e4d70a9bbb40149eda9b56c7d0419e830fa394e5333731081a72fa0071183b0a1921e0c9451b70e52220ce1578b2cbe379d4008956423d1edb2f88bb284fdbd010dc959c6c5bf525ba2ca95462a9fe958f8d662627075eb80316bd50c30b8d4b974fb9235261572935c472a9f2c3e1ca9451b8d4c7343e380aad3cc05a09c27728462f0e50056028700683461d50802feb87289dcf49e5719e0f446e3465a011116aad2b6e4bb044cc56cb5841adae2b180044f76525d449cf6bc5442bd6d9871252510b088c790bc9692390a24588c03db06979556e0f72048225d4294956b025477899bc1a953bec653f5edca47cba4542109a8348303431dbe5f2330eede4e3ad2710bae318e9d1d3234238645c4243c91c497b38326c9cd0085f9e7fb16550798771ae2162040c5b131136e8033e48e8145a57c4313f669e9819266a5423f783805461ec6739b2629837a0d25ec54f75c7d4032968cb00af6bcf0274c18ab5c5bbdd761ebfcbcedb197dbe7641cde6194ae58428161b88c305999045f98eb48d3ef4585b5a505b58d0cab5f50bc2ffd29fe877da74b4f636f2196d0120cf640877dd5fa3d8bb95002c90556970145c4a18910b4e08558f9854c20c570fb9a46a7a4fb3ae835919999448926292986a66c3b3b5201a4540758d758efa37b62a3f4915c0c23f198f40c1b914c3525f3ad3298d1e1d272338ff16569bcf0bb8b6b3ddd9adc19b577809920f17049fe1649d44982cd6ff5e738b16a21327415c3b5637aeb4e957dab7712a8dc2b4146362e6581756ba53d4e537bf2f724d8864b1c8029aa8c2dab43639d2262e084a50c98f08f15042ab76599fba8b89d99df9a1a999d5f5966c5ba64f57ecc2771eb5206771a86d78f274434be63624f4b2b92303dc5e47a4bc9c25407d0b85ec203dc0ba815d85a564794594b1cb467c0c11b0dc4b04c5cdd61fe60638edbe4d70ff45d7a0aeeb2b45c528a2e7b306bdfe78ab5140922f2b1ccd344c8d994a22a4c623dbead08c0d8b25deff1385e1cbdf862c8f753103ed32d0a400a0356b4a13ddc3a0e648059bd7d0dc02b5da5bd2540ae1e3636492aacbde2263de4dd778bcfa6ba9a1c4fcae910c17f54be33b41d52e5cbffbc80df01c63bbf05c5eece503c859ce0e01418261245d8f6cbc742635f5e0d2400a6a58361dbaaeb817f59f187b90797efdad29995fde39d9196e67d080a21d5412e889a8f47559c128dacece4f003702f27cd8c984b1efde3d0ed3adbe5eb66c17cdcce77676591aa9fa0bdb54830b13756d3becf749ad20293c0d243853857523c8a96f03a7d3a631eb5acb4544e978558eb55cf10a3aa0a9415562e5145bed1041ad7cc00c183ecfe0c5ce396d3e96b877a4f502bf3b41469b5f9658f6ae47d139afe384af8fd42e6b4ed79815e13d2ec4c6dff02f79efd835ced007b08213961aa974996d19f911f10fa765aa5c56f52022769e6a31e35f62a75e2b569bc93f52a3590262ec06e8d4795840dc638bf8e7c974b26f2050b3e48da089fd0b0fce41730646c9e5a452c37de82e6961ae1a181d15b1796472c80d9e778b8847621f55bc241da6c18282aaa2135045683c8d67bab4153034902765eff75ac3bed9e2fe9a62e2d1b00086cd7f2ddf29974d667087251c89c86425979672ca16b74b74f8c5c95485a4d526c926e2c1dda6245e4ddc461070a9d5fd1ad666e4d882698fe7d37d641f9b760091ad6f4f24bc9463bdd187e860877c73061fded036bd49f8d95620229e7a9fa119919ae1004935cb0dc5349ba12ec61351878ecf08efba3b840017fea813bce1b644fdf061f27a351c544775d5611df213e5bdd36e3aabc0286da9507a8cb576f21e684ed7ba860e7702559521bfa9612cb9bc5915d63dc0bc4fa81b12d4d08a3af0013866ecdda2e0c4a867a5d3f70c2e369983ce5209bb12a9b51b1cd5ae43c18eb24855db5b5f00b262d0fbc7c2fbea378c5d205b785a95e8e20c0a88d367e6988f270de1ed5de10ea1d0c73b1edf2dbbc8e3499caa55495deb4835e84b11c4686f13c04c75010a6aef38029bf58efe4b870a6602f9c2d383f149c8693f797ed4692d37b59a41000075c70879775e0f7da90ba6e2995d21923e5f5ed7b547e464a836c81102fc6fe7afda0baae5a67543faa53e9b23db43c6792601e884191666e8c01f330c0e7a44a0965281f46c3589a8cab922a1c801f9193af851cc410c926d6f9bca4c6ae3217023a94627aecc6a2592a1b60d6fe9d91b3dd119911d9597dd5ec85dcd5da63ee8fc349d275b6b49ea319cd31ede314cb5cd6b5129dbd8553aa3cf04a0af03720aea56a95b51a6330c1f40e6fa4c1f92dc00bf14608fa28c3ad030e919f01144731b70fadf8520bcbf1e857795dd789953793e3c6bebbb0926fe0d3efb223838bead63f1417cab514b56e3a1f49fae21b81576c1dfab3ef0fb5f8234aba6197495da03a4f9e2d35edcf7319884d95658800414d7425ced812bed5e686a5243a2acc0a62afcca20806609e927d6cd11d6cc52aabebe343d2337403fff5bedd95934443d1dedd79e0db008d90135b0744e6d740eeeeb990b28f6d7de3cabfbbc655fe5412cb76f35bca29c5efa3eb0af269fcc3fb9ebcc79d5d5d4a787d577a33128d4d9d0afcc810cfbb401ed2affb718195dc97257d673e4db10614de3e9aa6d8f0e17d3d93fc7dafc369e78f046301c4976fd07b1b036bc67bbae7f72a4dce6567be049ab648baa2986da477e1718ff9a96df29dc231e6f857e40638eb65c7e72f811633cddc7d9ab5b1fedf9c2453dd637c18ead88f704bacf7bb123c2da040ca4258c40581530e462c22a11edbdb6857e41d431e7f2336ee26a7177442a19c6108d382db730950dff38bfddce27dc0ea4b9ff944de31b66a33a3ae2af4e648f373bbb6a78f66441b56a19e98a7800e2b2f1b2f16a69113dd33e136f0b61dbae88bf2d8841f715cfd0b73618a6d6e05a0e1ab9898d16c2aea5110b23a5b6034c6bf7ca049eb0b06695962beea3f192c55ead9b1cb569db89ae208498cc6644d73f51c214e4ca3faee6428fbbb7d6c0a13873d109c1049cde6324dc4e376f89ff7e56f433e97cf9e8ab9cd71e318b4b5c34706348a40e5ba800401c88116e88f71c9b26e75d63a44d63eaa159d20dab3c398dcf23db48f7964f287f1a8783c877bea0ef4cd0313ffcfb03579b7bc1dafd7a3a17e5a55df6b90940ca1443ee1ea35eb4e4accfc07eb98a4d9fc02523df742f8ad3fe8caf5a4bec2505ae183a23488181736a83db66de23152ce74e637b71f22624678764b761afe1ec76744f43723ddacca9924bea5f9eab3e53dea7f62415f240bd59117b2c5e2e2d5f53d6c9465f408f5d986a2b435dfa389eaa72c09df3d25990c8953a437f28a6011391296634158fc5a33a10571f1faccf8e6c349c236568261a729f7756868dfa6ecff210a0688df618f93146ad9bb8087d2a95c5a08d3471b4639777f544db145f0fbd34a505b151553ba434b65a11c428426db704a3413f180bc801c5ffd587ab57f37a7f25122bf3f1b08b3f66f65c053544834b25c623b88443a616f708d98d8b72015e6317fd2b5321192f8269d47d9279e51fe21d222fac114fb0fe70fe15947a5eb0582770c038ec2ec345a2f2a463d3bad027438ed7fea691990b6dee5ffec11ae15b36c2382dba55d4a55c78e2b719738e9d39d5450b5f53034edb96ec374a9fa810cd0b68c0366f17d81fc9066aefeb7b04708e32b4b48199956285085f70e0fcf5c3395b5182561a7736e5a4d17cda2cc240d27c318a3dfc414acc5e21cbe9627003d2c7a4405521366f11cca3a1185fa508d2bd71e860296926aa41a68af50ddf2b6aca89225c03462b985ad472981c52ac96de38b51e0cb89ee2ff1d064dfe070bcaaf62581290c15b1c9f05363a05e74171892cfc0b19fed8e8b0ad382313ece7ddf467f9e2a4fd44bf9c007647612ef610ccbde8aca832504226ac6cf794421d79fd93160187352583377d946849d2a8809827b4669616b4870140afdbda3aac212569b5c7e526a7e57e7d358df0896f8ed89d3ef53d6cdbd64abf054c8026992556eab4460c71b182e539c2438b51c09b73bc68966a97dc1d68cbf1cd6480d51b9b06f256cdaa2f88377fbaf8e9cc42ce37c6515670426d5cdbabeca7dfa188382d777094bbcb4c911f715e0ba37477c424959270587e48875833603d1f62bc98cd57cc85384766341fc6513bf39ed940280ff9a66b9163574a6c87e3b95a4852e663bb65bdd1ca16036c5bec121c6ba1c009730f4a06bbf0e97a1203fc1300860252e41a40604039f65739220d80c1c92e2a598e46cc8abf219ed172eeb4a8286ef4a34b2998bba67047b317566892f3e800e97823a361a69f48999351dfc7e59794e4b0fa9068a33945ed97503edfb4a1e961d451fa551338c7c71eba9ff530067646b8fa4f0b4cd0a98b1fde7d6730e06e3e84317c34205ce3f6d50cf26992e2da42524168dd98088122b9130074009d8c70ce5ea053d69b53c3b5fbd0f08655dab06df4bcd422b7f0877eefd534b15ca577d0b11312cef6d64675509bfe43ce72ca37fde0ae2577d3b2c9a97172fcbaaf0b6b81741004a63e2e8b05fea33396f6fc91f11546d02df1e9b85f6ad48480c7f9c19b0802ece9d2cfccdf8157ccc0ca6be995f901ebed92185e657f17d25dbca4f1aec2f12181ed121977d561305e129a1a0b89bcc4543d893adb874511a4ce454eebfa0ee542fb59956aa60859a6951e274d4bf9dfa61ae1d6c2d13ce38ce8c7dbc9207c58b8323187e1e51348b4837c1e0599f75287cb3f417cd0e81547685b0a53ae3a4a133e7c152f9ee303e3f8a2675d867a646767d2cd4121590718f8f0364f8435a4ae924aed396dd2447b1ab356e2856531dc4daf232d3ada15c9f18f3d9dbf8df8187157f0fee5f004979f056033c34f54ff3572a8c592cef6bb2e74b7cfd19a9525b81932cc63e57906941e3ed876c71e1922e700a306a6612946c72d1a961400896cc99e88d409926bc4b14f88b986799d84611fc368068fcf96fa4822116bf3fcafc8024382ba6c4f3f23671fa4854cb24c5c6b0beeaca3592306104b8f33ea60b0c24d681b2cacd0cb40e75ce2c8a3d27e81ae79dfa7ceeb0e018319a5e9ecc75b193e0d8b9f3ffc895650cf7f476bd0d1ca369569fd4e5a8ff5c034308de8489b0717518b53dfe91083ddb1fc90c99c5ca9f39db0e09d8f785d790a99e7d712314bed60e8ce7a2a6a6472741b61b2383f7abee214eb0be6656e75e6053355791a7410cdf9b4a39de2c5e54a7a6e4d2baa740f0144d4e4b184e1b31237ecaf819d2a33e79fe5f4c804a2037f51345e733c27bdd768540bf2a75df52c0569c2adee029c370acbb98594b5b064cd06e550a5bef6409603ad272c7abd29bb7463b86fe76becfe05ea39a66db18be14b91fdffdd0a70a52ab09b15e3e3116b22f9329ef38c085e0a2fbdb8b3dd183bc78cb1c74e293350c1944373ae1492ba1ce378b581cb330c9aa458801cf551373d5ef9c76d7312b8e71e18bdc188fb3ae91743dab2241e5b00986bea03adaff001303a529550ee18ba72db63c9038c2db5fe01c09e76d5d4ad6567629af3782d2e0cec6632c6446877f80ca1345c3c28a949f54d52263451f36082506482c160c9dad92227509ec984490f3225f7993ac0af08c480b8197788e0a16c6db2f817e8044b62ba1c3a63beb1fa2f8e3379acbc5c9760582664b9dc6e849872f2f53076f461e8188071612c6ecc3078d382ef52ca2017b1efc6b00361b12ea9345449c7c4e857e7e30223d0833dcd75d4a5d02311cb12bc62b7bafb1963b0cfd2b5ad40f3250ae0ab435b008a6f1681cf89dbb2b4a333b57cc9a6c73cf42c847272218340e996aab089252c14b1745a49f3bd12b2008b5ac22bfe6a88803981658395e0f3e3c3b3b5ed2ac132d97f2cc0faedcab670d339f2683c46d8580d8d6248d11eeb61f63d0669b12b8e65e6b40f586a01c702df925e03247f31260a55c4b19c08ca181a259ac3679b1eafa44bccfc41504aec279617dd7bb478c6b1444cd7f2b2e902c557150b146c4811ccf6bbcbb18bfabd008df6b218c3aa123451a649d764e38cbb9eeec60972748652395a3d89bd9b3dbf77eeeae3cd3f2e750be0b6bf856c269c60b4462083d1a231c9f1e976a9db64a262974abcb04b0947ec4262017b008204288fff542c99f50717ae0d29607139ba6a96116bfc952671f4ccbb8cbb2a53659cabad65ec849f3da0f733a0402002c4bfd17db1e48f6bcbf5b86c28b43d57c5c216a106b5475878a17218c4a7e020600586350cc81b9c5d9ba315e1e06b10bc672b022e84144ba1ef8735b1edcfb77e828cac260864373502d949526cb710bc27e65d92a5a0d8bc61d52a45df50cacf7e2bd0affd6e11afdd28ad7229f14b39eb23246209c960b579840c9ebf9a6d1e0305c8356bda44c7b08b5e5690be98c05a02c40444f94b42b1a700009f7651bb8e009a7a01eca607fe81ae92f4b84fba8960fdf328f95b9d7101df1f8eda1b3d1dbc6486a0252a26de3c352d37309f3c9d495abf046998eda35522882d2937ea59f04d1b9339eefa00beb5c3d149fc945f73d18d3b72fa914bc9b7ac1401fd6195e67ef0707350dbf8a8e98678fe6bb4370c306cc1833db7f85c8a0845296d12e5abca7f98bc684f53551f65eb0fe3a825aefa142d01c66eff49dc43ea8dbd1971640bc71bcdcd00f03e2de7d9501337d88d0b0f67fd380e5b8a1d84824cc792cc946508babfaf1f9aebd22cd57a5fb7a56d7d10b45499a309515bf6f94e858dcf5a4e08c755a73f11247af666c1790cad53db202e5ea94a230b721dc4366c5ed7e5c4071e44a5908711b603c49d2d8a7150bf7b10a47dd921f5decae06970731936c1575798dd4b29d4f85e48e7ae0a6eef2b3ace5fc0de11832979511b8df77eb3fd883cb1ba85be8a286aaae054cb992719b3fcd4d54005b527c6fdd66309d5d7cead4ceba9a4a8f69ec6ba9a8de3ecd2ada19e5be8f952b23ecf94dc4373e7e79b9dbe2ee260ce8411c784bf67452da3528ba19a4eaa2e70214b19bbabb9e07957e398696a803988ce3fadc5021b5c94c9ebd0b8818841a90b4715729735a2384db4c0c4d1e9d386af5caf34908049dc106b4d7c299fe2d8b02ea10ef39c25e76aeeab575190d31646775630e66a5a2120309075a79536afc6528f129d5d9689f20a0874b5649f96bcb7e66a0c1c9e2db7aaa60a01ca17950790fc2329a95bd7cbcdd590a96184d6d90db5b8cdd55c54fa809307d92d5ab7359ffb401c9488179ad43b15743531b4a0a902d528f78d844af6d978925ac342b17799e68f0f8c288a37afa41edda1cf9429067f66382c4f79137de65a5c27edf1c637dcadce0bd222286eff2e67cec58b75772334a2ef99774537ea7551f9cb5cc852d3ffc49acae0320c7937b74adcba6986ee6ece571188312d75decd0e38690bf72f7f8eecc01638594e2eb57ffbe86c56a091529149ffc495f26e9c7ccdf80adcc2fe5fdd93bc1b6da950423ffbfdf86e664001711838bc54fe2d85bebd13a1c1b86420d4e8e7a76e03dcef3cc2e0a4049fecedb47d0a47177637c9a04c4a3389403af9e40af87e7d87dfd40def9997ace56f35979b4673168057ef1875cbb35f0ca4ea66372392d6a75c2800fd35a58ed7dfa568f8b5ffc31822f211aece049b011bdf6e2230c45238282a4c2a5bc400c3591b1779edb19d25cef553c74fd22f6f8b89529a890f2e64dafe326b375154f34051bed27087651153335aa6996a89b2fde30d17f3bc996e70fd24fdcb217b428e81a1e20d2a7759d01a94a22ba4d417dd3dcb24ece626f00935e84add505391606121a8b26b5a8754917c9822b346cc157d24e7177f67f8d1da162475b34e9f548bde50e9cbd1918fd00ea36454edf72f30f15a76e8d6dbaed3e1e800ef8b090b48a43d88c6c2f9ab69344730d74ec1c66342f6797075f1bf2b712486108b306c561fc4f05550ec3e9340881438554e61809e9bcf9338e6ac74138592415eec7793baee10553a68e457bce35ef2811a1624abed75d0c113b85037ae306fa2d4033b6f2d014478de91c12402384ceab8da3a631a4ad9006b5866171c68c7a4067c1858e6196102d5bf641855a3f45f91262c0574f020750715b6e15f31f223693a3757397aabc24b3a8accea14538a11a6a2f05fe6bb240bfb32a714448b9511cd5823cbeb44ebf2dbc0fcc313614b6fefdd421a8f1d39a623f8a27b040f987a6c47f96076c401988c6235eac50945a57ada9c620db19499bb4857746365c58f8331ad5f6d2e5d777e09a04b76c4358eb2d6fcde630f8f4a6b845b9fb03e32397f6280079e8e0c14689998be5de70abb91118a8df2f519670c3356c84d5a93b9da1c183dcec07db2a31dbf24a6d017479358e07c811f538de75616a3f4d58bd3696ae37f83d2e8c55157f33e6c456b5f903d9cf00f73ecfe54275a8c56500c360bb58a51fc17d1d77589b672a0a83001c7051f00cb68762a8107e0708671b2007e413e06b8ca75a82aa99f0e6ad1e99dd56008a26b2a799ba40fe3a85fdb2e58d1fd0b2dda2c83580447e2466fd02703d55cf68875ee16083d9e4d4485b735b29a870d49c56917a1cd6d45afe1b14268725a216bf3ad9128fc2c28951cfbe8dae128cb46ed424abdc63e593e91090602441d6d44e04edf8add207e63caf43a7a4cba6e54e4f6ca04467c9530ee5f9c29b6d4e8e58d96da12c61680585997e2d8eed83ab47f617f05efaa2ef650e9c6e87e3a8fdeb8a2b183e0ed3a1f5d205844e4a4dc4b124d04532546f3eb8f9579a412e95e02632af3c90a4e4e28721c849a6269a9a1f3a0073db399da4cc422d6a65f263e2bdd5946e3b4f49349ac45d87a8a78cf7dc740ac9c75c78b61c965c30a2bda91e73d9798b21b325df89acaf7e4500725277aefde4358829d4a82eb7b3f11df728a03cfbfb0b88c56c32dd1c2e4651903bbb3a47f0b4e10be031578de13d881b5d8811f98c0052a90400d64a022e6c00e3cf0811358600512488a6520811ee8c0061e8126eeec29626b426d69b43bc43efa3c6a2ad64dded18b62a8b02dc8de4dd46723a4e2266fcc92e12b688c4a1b05f89b3e2f96b642daab46a24df0fe89e0c86852c05f9b2bfa2636acdb2f5395642f61e9f3dab0c0c67142fdff2b4bed0bb40bf17767e9f3cebc8c715cc2b27dc00babe682b78579983e5b04bbc2dcdb74a29fe8fe69a0486b54c8f9b084bb076c587be08bd167a9979a57fcd1d3f4d99b221fc6e1b6a694c5ce35174e4ddbed02ebbdd71fa9c22f03f6c790df02352880dd2968526283fa28ba5b41929305ec4bca1046e1a480e96ade69c17404509c7f5785819e2c2f49045e8fdd1992999f5980796df8704412216c97285fa9e06668dbe7ed0091ee335a14948b7a5e396f16ab8ede34e05cf36c89167b80afc6acd02c2664b10a6fe49e25687748339c34b008cd3b3da5905087b8f153f08c071d829ea34e54f9929c1d4f0f7328fd36a3766fea63270f2758ae44ae7ca344e22f2fea3fcad6e9aedfc80e01f1f4daa05cef247717bfa6d6a48dc013019f4bac0dc06f082dc754a2112723eff81c2e9b0c023e4011b3d67794133fda76ecb7a522c23313af16e8301cf6ef92f6a27a9c283f5ae98524132c3f60435de5634cbca69c956ea33da46852e0108a7d41ca144cd4e0841144efcd93cf6da341bf50f32ff5af1e693f6bad6230d6c12f4560e0ac63d9bcd7b779a442860c3a518d1a40f1332690f34220bc308f337c2e08a4331e818809890dd9e0a781cadade7cb9cbdfcd97ecdf4cf8ec49ad7f49f2017237509b4cf06e044336c7746406432af9d5a15127f20c0bad0e587cf60aabf71230531fd5954dd36b2560e3169a001f0142bd78f4c2c48e6ceab1851822dc4a9e9cac84df1ec3e057e20971e70b8bf4a2d73e8c87730034d1feeb45d6f8d635ed9480e9d769b392addcbb8bfd7212adb196aff5c213d2771ec1fd46f0c15f6430e37651dfbc754ea7d5e66a3096eee202f1d94e2f4d5759c79553ced9d8c9878b30a1dd0feee0fe2c0846de1512a94d1caf97103c8f0d8d515f37f15d486040a3b95d2949296f38ebf8ba27a53eea7ff0ade981cd6e5d1c1605a236b3163d8d473eda968cc6994a08f8d979dd6d3dabd24191b43c8409d2528fa2a30d8fc00decd65ffe9e35a880163a8a5db846756f56fd87636b12a9ce2c015d563c7ab6dd315c84253c287f48dc5b621a0627c904fac5d5e159985ec966f247108eb49725c37a1b6e11bfd10203de7beaf6868e5f31d081681b2a031bd5522015bbb480db17331ecc663991b85d4055687f412e8312293666c27d5462a1bd2ecce1b66e75c23d64fa42db58d0c6393db855a338d7f3d69523917c1063388170f7e0556cc7020e4a4b16b33619d7768f7d4de913d92f0988cc6e21b62f87b3adee92de736fa46c62fba5c246d27e41bee33aaec4db322eac1ed632c527b0571228929d8507bbbed63c024c380c0b109c51f3edca62f22d02fae1eec054d8ea02ae0d96e0d9b557113870247a651ffafb270322d52ab8246aef6c332f353dca3ac513bd4f0a2c725d15ec1d1273a907db645c68bd2d3ac54fb8574f58a88b0a352745296ad7f74e82843a8d5a1125ff34ed0f3431b897802a6a7f610e4a39f099cf5564a8f1aaf3d0aa299bf07d3fb9f058e524f575f4949cf80998adc7edbdb6180e3f896384b2e61b0edf881ac4d8871371b8face84f4d496e03cf0d80182a19e7ad24393d1dbbc14f758525c6df2a4940e33fa759be4c593f69c537feaccbc91bd90917921d910af0e09840f2402640cd1796ab6150cd9ac2061152b02c40349c0b9e45f12f4d005b94feaee80c5623d1616123836eff6c0dc4f0a88b17bf09149f20e2e42bc55846af837003db608da415523245b5aa4a0501f941d56471a7d7e8fe3e0abe264e87b18bfe49f64056d7de1bc37cd287889207107dcb54a81802d8a42c88437b81e20cdf6b56ab9c90fb272b04a84b30d5703c64401324cc19a184577f4377c4ac1f81144ebd285165ec621d19e805f5a33aabca220645f9e9b7b9825d343f9d2fb9db37d9c815f118aea6d8d3048bbde73ceadce552994073ca30c1effec1c8212231310faa7faa2d274c709c54dbbc53eeef6248a5863d23747b4d9b2da291943838a8ec7de2d5e21a56297b9302d56762d2a2873a49a8b22ad3742831bd2a90bc4c8d52a4634275003692de7ce04f5cfdd0d1e7b3a57a15837e5b842ab55bc3cabd0b26f7da0f790a231bde6e68c3d788c4e14873b4b8bc910a3c5b262bd0bcae2a96cece0c49cc1661d9321a9b5b232380309801a50db60e1ec1c637cb9a5a5d2a30f8e87e1ca7fd0cc128a9b2b8ed68bd435ac013cd11c315963ca92985cf384b18130eac6cbcb274c8285487455cf99c929d5e7cf129201f44d04da9bd3b65720dcd5a803d2e58089d1a5e1e268c0a1e00b970f0602c680c084af7be5cc68b818bea29325461881c6370a72451e0b327be5e7681dead969b879d68c71006b1878422d42a9043f9e6f646b96ec267b37d97bef2d939429b50bad0b110b935237a2088ee328a51f781f6534f061ada38c114568e0882d4240c2c0877352eaee45be721ce7ee55aca30c06b8518688213050e43b2c32a0450b880fe7a4d47d94b940101cc799388eab15880b04018415ef09f1df283369ae3055600a29a4a800153ff83085141698a9a2c4715cd78d3215a0e2bd51e687f7c61d13fb508129a4b0c04c153b3c4184c80e505080872788f4d0812854baae23f2de28b30314ff8d3214f86fdc31310f3b3c41a487f78c321d788fcaa78c46294d4c0008c7719ef789042847294d4c0048ca7b469995f7e8f0e128e3c490177d0efa7dea8bb5c6d1377cc88b46855c1455ca264ce845a39485b8e81bfe212f42aed78409c5904c985013d88409e1782f1624180786fd4349264cc849cd8409c9944c98508ecd920913d2719204d76025d806eb2ca9787a611ba3a82a74436f68558807fd32614231ff024c98509326384c98108e3f02264cc8897f8e091392c91a30614239390e983021084c98b19d40113911e188706cce789580fd2f13b07bad6c1c13bb290bd84334d318d8df2446ab2a8ca2bc55d5058df237ad20e0f3d9741385681346c4aa348a7241ab2a151a75695fdcf0336ef8d00d55d51845790542a33cf464ba78a8365d3c0465ba78c8365d3cb4335d3c749b2e1e8a325d5cc4ea625455caca2474e8c98411d13ca94d18514bac41993022232114db8411b93cb69d09233ac2eddc268ce8f5a2fea12813468464ba44c1fe22d68411c1a60b155a05c241a3fcbdcbb21db3621ba7d8c623dbf806db3122db981669325dfc4d338ac241ab4c4e68947f935246cb24d04c185192d68411d5189949686a5a4a8c607f916b8a8e4cd16bc2886ea60b92099b36ae25476e5e4c906018f6efa255622d0ba623d8bfa4e35f7a425573049304ef5f8a4255b304ef6fa2a1aaf97a7f93ab719c9e039f4bb4524d89cf25db129f4b37ccc46713cbd412a36144494a4ec0fea524fe252554355def5f62e25f6ae25f724255d38bf75caa29d904f95cba11f2b914c31bf85cc229c992f85c9a61ff120b1a4654f3b9e402ec4f82e24fdaf12fd150d534f2fe2523543543f0fea5231af84cb2916e457c2eb18cf0cf2557e985c4e7120cfb93c668189192e9e2e1675216b03fc9060d23b2212da1aa89c5fb939850d52cf2fe24275435b3787f520e55cdd6fb9374a86a6af1fea328fe241a7fd211aa9a1e787f1212aa9a57bc3f2909554d9a173f93708081cfa41b526c88cf241c223e936419f84c22d130a906c467128bd40ae233c97581cfa497109f493052cd67920df61f91d130a22550a86ae6fd474fa8aa8af71fe9501515ef3f72425553bcffa8095549f1fea31f348cf73e2203f6d16d64b3c0e751ed87cf239a0f9f472359053e8f704437d3c57fa445c388988c96505507de7fa484aaa278ff5112aa82e2fd4747a8ea89f71f19a12a227f82cf2320e06982cf2310601fc546373d7c1ed950e0f3a88687cf23d8e8b5c3e7910bfb8ba0505513ef2fdaa1aa21ef2f8a42554ebcbf08090d238a4d17ff1b1a87e85da4834534209f45b5097c16d9b08b6e79c41ab59a4c987642ab1abba809f6ef254effe3863b43cc822849c725c1fea21a4f8d922b5282fd4536a20df6172d1997607fd18d888928364f704537d30457c40414c542373cf0de3f14f30f35f10fe17431ae89c749281373c619cbfb8774264cb70b8d0f9d88b2318765869d46488786cddf18d89fc5669005a0189e2eb00b218756843bc86117b21803ec1fe2e264c59a97159194c08a474860452323b061942336dcf1c2864f4460439d2e6c98e3b261132e6cc8640b1b2a09810d9318b1211210d8d0c8076c48a385f5ecb4ac074a16d6f3a488f5e460613d4e68ac87c915d6b3c403d6a3c40aeb41c2b29e2333d6538505a35061c11d8af29fc2825258b00316744251fe5158b00945f94361c1272c48c4824928cadf090b0eb1a0118af26fc2823414e59f623f9bfd6a36c0b03f132fecbf84bf12620bfba74416f6e7c00dfb2761c3fea81af6df000dfb0b9961ff2035c4b03f1237d89f061bec7f440df6370286fd8bb0fe00085dd85f033664617f1b37ec9f01226ad87f081af69f6186fd3120c3fe211cec7f63d85f881bec7f018f0df60fc25383fdad0786fd81f0bcb0bfc9e3c2fe204f0bfb5b8085fd7fb037ecef832d6bd8bf0234ec5f7a19f6ef810231eccfc30df6afb1430d76127c617f1d5cd87f02b6290a086bc5eefc9851cac49a28f6471bfd0425ad8f71582dc5140ca50ef63e8b702a45559a0964634538502873a5d16a13aaaa4f3ccbd5288ab37957acb5a88a62e75af56d201b07dd6037cd3ea29969e65e87c18f03b96eb6ba0be5171fe5020777185cdcd8803b0c2e8c6091105a84d338c0f72c6e2756176e63d8a4501303bb090998162945b26f060e4371ee943b400c5ed3ab6ff89b66d5c5a5fdc3f9ac08c756fe5079f92ae6fd4d0c787f53cd570d787fd3cd5732ef7f7af94ac7fb9f6e7cb5e3fd4f335f39e0fd4f375ff178ff9497af1ef0fe2937beeaf1fe29335f41e0fd536ebecae1fd67bc7c1581f79f71e32b1fef3f63e6ab1fef3fe3e62b09b08c37a36a7c7ef9cf38949f1bc77eeed9fddcb5193eb7cdc6e7be01e0f36cd1f079ba6af83c5fa8cfb326f579dad8f079dedcf079e2b47c9eb21b9fe72c009f67cde5f3b4bd7c9e37da1ac067ea22c067fa2ac0675a6380cfd446f599deac3e531c1c3e53d9013ed3198ecfb406f399da10f099de12f0d95bee5a80d7e0cf6e83b3697683a704acffb0eec3d208589a83a510b0b4879db407d8c9c34e98a7e63bc0eeb042786abe0e2bd300cb00fb796a7e8c759c43011601b61dc6e2c0c1ae700c600b3007e07ab12ed3766376830dd65328eb291a006063069ba72cc8b6a74aeba91a767eec0ff1e6efe411e18870ee874d26c02ec2e91b5c28f34703ffa3e15cdf2b3dcff33ccffb7e52af21873f5f7cfef3d4ac60ccfc901629e7f718a55833cd44382bb7960ffdba9507a3a9f99e0d9e9fbf1decfff97200b261f91ea769664d3393cea9753a627a62da31cd4eac93918f66823de6388efb195cab949527b126fbbeb23c9dbccf626d8296dc30a1aaaec66423c2c9094331ec6c6051549db5ceb0cb91f94a45094df92f9931a135a961577162c39e039a8174a2809f4db352a44566e0a0cc221cafce9c3af2f06a9d5e37bdd7c1a09c19080a0541c15e2f48465134c61f6473f2986634e5eff99a83d2f3dd7cd0b3ddac5e2a4ae7a56e5d7df032012d714255a0076463aac120284fb08374b083726a0c24a3aa89414eb0839a809850d5acb0538db15c58856da1ac0f7e16e13436cd7c65b269a1ec5ee484a2bc1cec8966221d116de6b6967d2aad3ea93578f2a9b54aab4fa6070739a026d8bfa505624251a0d80dc49aa7e25d1d147b624d844283fdc7d79884ae42e2ce0d76469ab135ba4624e20dfb7bb356588dc1a82a7fb4eae20e205cebfbca926bb58c6bb58c6be18085fa34afac5afed06187ece1870e3dc379453822277436ef27d2c1fe4346031ddc61d0c0092600ee3068f0c2205aad730ce5473355286516e198eacf7c4351fef5826c280ab46466d2111d61f64a84d32222b4276b1c1e5c4549c0fe2209c35ccb57624dacf9caa423d6c49a1fb211088d51624351ad9a85328bb5ef2bcbd3e91f857a79e15a3860816be99835908d0c68c29eb436e7cc09896ca3ef89a886fd7b02a58e219ba9ea8765f53f5f953f415f7f445735f6116ba5cc63a5cc57261d9a721314ec9f4b1aaeb5b2544219fa9a5386f50a22af866716cd30946a85b2be13baea188f86a708c757209bcbc1446faa61f9211fa6e16f4a726a1cd3f3296f6241c378de69a238fa4ed5ff6a95e62bb775aa569aed66b94e6b94d75a00f573cc629dd637ea9fba6f789c80ab8b81ebc42cf68bcfd3f85ca759161bfeb41d3e855f7f7c1a96c887c30f678415023338bcb3be5167ad429962b33b0167114e0dc4c47483fd2bf8d59bde6c31827305bdfae0acb785356fa5a8ae53e18c70b0efeb93327b4ff07c8f8b950ae5f79f07d9709f45389f6d9fcf89d37ade136faa8c50074fd17b6eae2decf9708e3233ea14cacf7f9f454aa8ca94c45443551ee945382e9251557d277de65a35ec7f7e26a67a3a7cffb95380e1fd149fd7a1c67fffdd29beaf716762eacde0735f69e5ad5228bb0a06349f9f54ac9136f064a4460d1afb77652f1560e840be7d2a3e57c5fff3e5974f2f15e455f1ab2281f23fcf03bdf9e3c1dab737c5935203153aa1284e36431ccf5f7441136c7187e10218d601acb3798a4bf180dfced5b8f9f33c7af3e3eef04fac1656f9a3c885bec18d469f43d2763ad1fca9e54e7f0805c19b8780787cfae308be5310bc2b3477a54551dc0a8bd55da1cc24174634a31655a9f837ce33231655f5adf194d6185fac4172a171f4ad5028c1cf1e7df1479b2b4e196d0b8d27a54619e2f88ac6b7d3685f7d5e953572d752f263afcfecf734ac6763a2e29067f3c908e67edaef4bf639b1d2c85365e6dd3c9bb7f3b576bed6db1145cdd4ed438e1fd27f04535152b75419930a25f99fcfa71a7f625195ff0c13159f46d286a0bbf81e2b8e4fed388ae328de518ba258239a57d542391ad18c5e2e2594ddd79c920b55e31c7bd4cfe11d2fad1cdda98fb6854551748a23088a20288e9e07c5d1333e0d69cc13abc68735c21a618db0c6e7c7a1e7a37efe288a7b9b67f08f589e8daafc47d3b365cfc199b4f9c4a2317e3eb142908ee253f1a9e7474be9e8e2f81ea7e3f8e2ad308ae2fee97f7d5114f7a3ad4828ea9ffbba85924342553654d52f6acb158ae2be76a1cc27ec6df314d72316fdd0e62bcf16da6ca10d73a0f7c438cdc3af61f30caef17394a9a12201fbe4fb60c9eb437b0a14dd669f552950fae183352ce9434b6de3d2ce18cf56c3dcdf546c372c8a2a3a14a542a328eeb959df001d0aa5533a6b7c8fd4adf8a39dc1b486f8393cb4a21755682adcabe85015131f5e79ee55668d83c69f5e458c86a1f1dec8447e68acccf06c9c67ab3885c6ca0c1596cfe743ca426365060d4abe0af929e487c5a63cb51d5e4979fa335e25e5c3d02833e30ea04c999142bb14fafdc96615276456a5a8d293e168cc674f145569651e9d5854756251159d22f879f233495a958f0a0d73ef2c8ae2beb39599b4b130f7a48daa3ccf3db943de9ee4c6f1562994e3e7112bfb6cd207c3ef71871882cefdec1bf4b3a7a728eec471dc8aabacc267c01ac5091e8669d3d45665f50dbfd94051147def8c406b30fd1518a6bf32f3557d95bf5dd77d2b2fbad219a1ccdf0b16fee8f31d7eb1588daf4ee2778aad08e1e8cacba472aaf1152dc5530da6a7d82886eb4e34a71645951d19e5f7271a3aee381919d15014c5e2cf710787c5b123a32c31e8434fc71d158b2390ee14e8bb53a1f771876371dcd18d027d372af475dc41b138cafca0c1028b538be529daed38b1aee8d637e8cf390299312b1ffa0c3b45fd950f0950aebcc0d0a1beca9d42e5ebafd82966fcca97af98e8765ab1eda994951f2bdfa304664cfd1cd474f3d5ca53b1fb3a4f47ea5e9ea2624c64f3557dfaa29baf549e9e6e2e3169ba4e9f2cddec35f1c53de9e6cf23be5e626ce57277fc149b4f2d4c3fe43490cd27d6c995dd76bfd1576a6c7416c3f4bf97afca17a6af622bcbd6eaf5ec375fd118fa3dae5055c959256a0b971f12a05c41425760c3fe5d90f1e7c78e4a3d5660f47b6ebc392587d273e3e9c79b4ddfdd95d773b7b682743f821ff218bf7b3afaf83c7755c8e71eecac0af9b9fbd0aa909d25df2b7de393fcc71ee28ffff97c37fae0ae4af83f5a95f04995f0eae89e7cf2bbff3cd97139fc10f9dce880893d2f5e21a00f3d6e7c80e73b4b7e8f1198d8d33d79bb3094dd83ef79f206f1fce70621fdf89de756d27bfe2329a5f4dd8f27d3f7dd57fa3ef2c70fb9b147067fcc000e9f1b73f01c32f8e48f971b73a098fb6ea682b474e4e13dc8f1c1f0e66eec56602b30ee2b6757602b2f2625f7796505c98fcf8f48fffc38faf060f1473bfaefeb46991189f4fc68c1f1bb5107f921387e9e9024c99b85783f8ea3fff018ddcfe770d2175acf01c4e28fecf83d8e20f8642786d2f3a1276d90b187f318fff3244992211547db7824f3e79b98c1e48be3f8a0ed96508e9f4950142df9e1371e795ef4a1ed51c713369cbdf75c21b5853f9f471feb2fb2b9891af63ee4fdca6b05097d2f9dc8fcc41ebb0fc307cb0f39eb192ff89c25491de37f7eb63017fe98673028fe98cb17a6df63975fbc413a1f65beef6c27f3dd1e13bbcb24c155bf0f233d19a17fe82e777577379dc9cc39298c524add9dbbdd6aed461997e99837ca90350ce5e3e0f48d7e2884dc16aa11bc5ae777dd247b728d638240a795b7e1a067e3544f9ea29eafac0d4af1ee653a0de90b9ed531393aad8874fe290cdd72b862c761edb8ef3e048d32ddc44e7698f6f7e96e7e556861d1ca289515a5b2be2e0f01db5b582d45ba96d6c7bac20cad0c3def71de79baae03bbd0d3751df87d077e1d48eb0a66778d3ec9f9814cd614e52a342494140965778f324b843db095010fa93f311d7b9ce88794523c6372d5dd41b0fba07c4f444ee4c4285dc59d8f669a7d34118ef82117be58ebf875941945ae082d62abdcd7ff5aaca34cdd2973d5c1f2e0871c128af2bc2337283fcf05c1a762cdbb5f2827f72c3687cf09a92d2cbe694615f075d7343f2ffc289f1bbdfa39ee3a65e0a4ba64c0a414c96a9c8d0cac80b3c8f661cda00b9c4551c0593f9a6946fb6854d579df07065317ad42dd20c4c8111c1081114f2bd54ab6d22df5e2473c20441327353644505183050ae050f4407381fc340cd1840e009820c061baf8cc0f5c5c11c4936e62249c19ad8acfa41a02dc07272610050fcf6a616088059263ba7812403c211bcd76a8d9906880164e0a994a3f72fd08b632b2b9f93c8ad1388920305dfc3da107765c1547163094a30e8ab9568da238282a3c90fffd77a950a94ffef7e4774cb53e46391a116b229428d84716f69146140376110cd8451b767107bb6c86703f795b6663c240a06d4c2f4c5d34ea88ce939d521423acc9d537fc8318f1368ce067165e08f9b9859123c4704212254c9a3811e251ae9f5a04792244f05464f13564e02db0050b5c006587c6c891d6059e060f14f14d84e075d082082ac6c8c212264e72747e781b43fc2c02c56ba0d5c3574163031c8ca2d01c41926402d38a209af82157e8303322634486264e749e4089620a1f3a5005059c30722489922593c80e4f0ce161f4032d80000251941d1c271425eb1b9e68860a90ff58ce763948480207725c677392c1565840c019256641059c0b80b358133b30c4450ba602cea5cecc869a00837080a4f404cf11dc1294e9c5cd259b909b4bb914651ab9d9944d3447dc6cca2623aed36729344c292b5101fb772e29c1d3757329979604b9b9743345704b4d6616b7e4240337977229676e71736966c4cda518344c08496906d8bf3369074f0fdc4cba61274529e2e6126b86e0968c4c2d6e2ee5d211226e2ebdb097905071730926c42575a1614230d217b07f6712130bdc4ccaa42643dc4cc281e26652ce6c5d924e0f97f464d2dc0bdc4cb2617fd20e1a269464ba380fac689850cd15d8bf3389665a7133c9481037935c4d5c129279c52525d1e166520d769292999b49363fdc4cbac13e7232c5cd2319f6518e0f378f661db8a32755dc11140adc3cb2611fed3871f3e836819b49426898909251170d13b2191161e44514378f704677c484871bc5e7d19221178acf23254fdc3caad9e18e9010b9443e8f8e607f91180d1392f9ea8617e12cc249b959a4b372b38806e4aadc263e8b7666dc2cba0df95c009c4538a29b472c273e8f68bc9b47ad79f3c885a226c02624426ce94909ca11b6c4016ba23105a9e199c51626234c2f5c9202154a4a4a42d852939293521136252d8828e1607f2a4aa519ad1483d20ca0b0a41e2c294ae902b674c49690dc4a2cec3f44132517f6d7a1344150aa2175e10b3396f483259172483a4158d293188924c3feb3086986fd354022d5b07f15d646da010f48344e58929109581212120f96d422b9b0fffc00e985fd31408261ff212492cd0dc90ad215b19193510e1076f4640465b4435123d96886fd276b44c3fe3b8c6ad85f8ad1e846c48e8e8c908c94d8d1123b624251a3d7685483fd574636d83f65348ae18c84d02efea32edac59f08232f46345644c38a764439322f5846ae71c4c2fea2e886fdabc826aa617fae03672231dac5454e70c281111c39c201122ca1c4088e30f12a41129f5d5c7091bb1012c4c5c506bc1001122e2eb8c85d0809925d5c6cc00b1120a1810f67ddddddddddddddddddddddddddddddddddddddddddddddddfd7d20e8f17842310c4531013608dbc64e39719e6977f7180ead66bbb15a2e5a637313c391cd6c3756cbf5a2b0971a8af6b3930c67ced80deb6b95aed3eb61a89a971bcaf6b513ad9ce1f0827af76fc678ab5b36a3d56caed70b06aba9b1b1b99975db58edeaee8e691c7c45fb68adbc793138e080030e3828e1ab9acfa6bc39d92e46095fd96e94d5f21a6ed6d4d4d4d4d4f8cd172b714eb2ef268dbe7c3569b4499b34d6d72ae78bbe5e99be64beb2bdd450b49f9d3e2a6bf9eae50585fa3f9dca92cacaef54fe09f52f287fee7e51afc7260e3961db58957ea69ec27c95c3cf20fef3d5e8e7e7124f2456def37d172a69bc4a8a893483adc172430d002040035e0031ef7203e600dfbe7ac0afbe7de580370003f00212f0edab1f9ec7b7af2af03b64be7db5c303f9f61506fec747e0db57403c04be7d6581f7a1071ebe7d45c4ebf0edab215e889f3be58ba941d4b80a3f7f90ef0f83d8cc55a733c68bf97c956a01748ad2cf264c3f041bfc7c513f880571b65f18f18f7ac101899b8f30c27e9ed240068818c20a712f60db53415c202ce0c3adc0a5c0dde1667ac313c8fd717dd8f654042e042e8fb963cadc06d8f614036e8c6d4fe19b696b013753177dc1dc595b5dd52dc0cd3326809b27ce94ddb837dc3c61a959c305c0cdf366869b27cbdeb7d3e52996a97267d8932ddd40b2f15a149edfcd2f38e019533bf6f9a43f8c5e6829922a6376b7f7f7e8c3bb1bf064b8bb4182389de9e6dc226c1bee343afef059fdbe9e312da781ef19dd4685d7e7c32ad2cf771d37ca749f595b96eb4ed5977bad05e03fda274e6b94e3ea2fde6e5477dfe01cb4fd85e7f78bef7ac889a3ad1fda0e835d18caeab14b54c1c2f5c350ac9c57f73ba73f0a01fd14f51d535f54c51de145bf7b9f5c9d5e9d3315c5fdf1cacacc867b06cec719e40f856a09a30651563386be2000f7a9002d53f4ef45ccd9c0fade3dafebca78e19c9211860428bfbe4998dc788d2b498283a793260eabcdd9c273d21d3ce7113c678dde541cee8632594275f09cd4e6e62cce455994264a123c67f79c945277afb5c66ae59ae0e87433cf6b32a1e03939239d91241eec88913995e0d9c2b37b4e4aa9bbd75abb2ec7cbf96a60ceec9e9352eaeeb556cf5b1965e68373dad831714c669263a51fdc2f36f5e9dc87de99001d846d238b688d6b1340ffbeeffb6c14d501283d1c7c5f91d45775813507251315675c391989e3837206c7aaf000bf53f23318b4dfe7d928aa7e2e8aaa9fd716764b71ad60286ddf5796a7d33f0af5f2e2361287744255df4da2b6489983efa30c48bfa04fe90c0eddaaf0f0f7debbd9dd6d14555d14555f64e3293094d9ab929a04d78a04d79d6a04d74a43a3e0fa6eabb5abdf775de6819e67f31539f3929c7d2d5c3f5287aa9aace1fa9f58ca3c551f7c2594600b2b4a94cf6b618d350a652667df27361543dbe743db27b4e5289f7b7908e8f9cfba7fdef71ecfdd7bb7dff779ceb785d25ffcc670e694f343b79ff7d9d4cd3fcf73cfbd0f3defc1ef3ccf3feffb402a94a10dd71975a7ac367246ce3239a336b481e579f781a3587150924fe68cd42169b5a5d532eeb7dea09c0fbedbeffbeedd7eef59f0f3ce1ffc3ea73b74d531e48cd4b1248da2ea572d94ee0aa05fc959a597f442e933116da5060128615fcf9622e473a38f1077640972a112ec3e5dd8759fb0fbb8f243e58365e339ca900d7e2ef8a1af7bb27c92f4bec4654b911616f92d4548b2bac85b8fd4d715caea1f7263e0f96317f07cf1c359b1470a787e38c618ad1283ba6d4e5cab358e4ef41daf950f02bd93ef1f7e481059426006939f197ec2e7843d9e9b5d0c9c4b4c5b8a746d61b5d01469695da16c69c1421878ae0581baf153419f4f98be675ad0cb5419a2f8e5180afd0702813e047d17ba79625088413dee008126c8bacd7728cafd6685b2fa93f663eb13caf1f389a2706ca041e1d8c04a95315dba5baa0c1b58a95baa8c4fb4426903abb242ef7410d20f4916ebe6c66b6a6c369fce798dc1512ccb8fc78296564b913a85d29fbec784aafaabb70457ef06576f7a57acefb9d96960fb8abef75e0dc3f7783eb4550aa5e7f39c1ff7a0c7f58c794d18fac4b0fb1353ad1e08fef7e1e8c37b0ebc4328aef50ea1f8f36ea6b8f415ac5fb220c7954acf3df8a5cf41c71a7e2aca84f13ee45032dc71dfe7bd67dce1792fd57d2a8a0dac0a7ef79ef53c67c1272bb68106e7541913467c8f96483e463753cc7d36b0b0572a5daef4b9f43d9a3e072d79e28b37cca6db837bcea6ca982ede55111ffc8e246bad9f8a3261b8f76eb68165030b77eff1984a13d78e24b9074d5d773a716f02fff3b837bde7b161f23fb62bc8bd09741b1c7296c3a2f87d5fc562e9b3a928d3c57bcf83b67e7e64c71759f1bdf2a7e5c4fa9ec779e2f59c8e957bd2cafc3ff49fafe8876ec5e4e721b5bb333a3194427c86c9db7d57bbfbdc8b1e1b0c7bf7dc0fa9f87bf26f17865288109f850f12c99b5138f5837c57ac32cfc8d5eec5300c9f1b65428ff510b4b3c3a09dd8ab5c579fe33a87eebfebd92c84ebb84bfbc4aaa033a387a610aaf0f09fd55f341aada13573ce09e4a3d128a59402f1dcdd1d4867abb502e1388e0352bb0e88378e0784764c2881cc18cef37dc1ddcf53f3fd7ef5fd298f7afd9601f7b8e34312f69c30b7a9dd5d83f2e449ed5683f2844669adbfdeba9f7bd2ddee4a646cba9f8bf577fd5d77f7dfa2ececdc6e51766cb5f6735dbfd7efed74b72dd684099358ce4c166bc284f644e786e39874314fd6fd1f93eebea9b5eb5adff7ea07fbc1eeee9e94bad7ea79b26e998ca7bbbbfb44a97baddfd78d3ac984dddd08a8a161fa61c8f33ceebf6fa1f95a8c78461ff5a73f4769feaaf538cff3ae87600e5dd79e6fa16969dda837bf3beef8fc375b582d455a5a54e5fde77dacaf6b61b5d04c98aee5bdcf415b8a4c98fa3404f9286fa62d2dec2055f9e1ed7e76efffdebd2af5b9ff7accc1fb79330fefa7f7f37bff169aeb39686e69e10f1c77847ede205fe8f3bce7a1efbeefe3429cdfe05a6778e777b6850664c72fadf8a4adfff9b4b0c8f08629fdf97def7d3fb91ede735785cef73c04f4781fa44eefbf9eefdefcd0e3f9962213a6b1a7c39e372787bd9f2d4526ccb3bcf73cf0fbbcf99e07cfbb03dacab2eee9c8d0af42a1fc9e35dfbb3904c4dccde1610b8baa8ab4b430ad8a39e339a80a21fd9052b29bcedb747e772a12f0be7b201d43838577bb8b05e7a9193cc71d93be97b57e0ee8db9151569c5d0c176307a9c283be7b5df7d941afcfaecffa467f7f0eea2f8871ef2f588dcd4d0ca7e59ac16a2dd70b5663f382fa53f97da7f24fa87f41e1d0f216adc6865372b68be1626c3506a78cc129399c922bb917adc676335938e587cb22aefea982678349e7fc15ac600546bcbaab20ca576f5584c241019f4842f03eb8c350010f3e1177182aa801e8c11d860a5ee0093d1e10c9b461a8a0083e91ba3086a2f0919125498691828a49b8c348410cca1109480c230521c0a7695340239a818511480c524aac74aa318d28388948bc4811e10e03090b9f1a9cf111c7b042c330a4392845d1399150247e83e9bbdbd4ea4930fdea48382698fa8b46a9d76a1467dd6a4e83290dd377772532b40917eb6ca8122f07d3f79c604a6b6c75e766e4bbd62dca0e7d5124b65813264c62393359ac0913da139d1b8e8b7939b219a3ff31a1b4eb683c9ad6f7bd666bd2783c3309a693d53d27a5d4dd6bad3219279f1319f804a4c93c4ec2ee3929a5ee5e6bfd3e907a50989e64c61d1307194cc130fcff1dffe1531b3e1d75844eaa3ca12a4e4547854655eee44f2c5f59f264ed89e5294eac5183734a92fe537c9ed4c1926f6fc7d09bc7174110fc7c2a51379e14f153b75419356ce36e94116bd41f01abee543e91517aa7fa6586923dce897bc1fef279d7b8ae6147f9eac506c7d9a028cf7a40103cc2fb107c8f5dc2f33cef2e01de5cbbafa38fefabf75fc7bd0d8ae2ba23a32471bdfd83284b708f3c483c5d4cc2b651863297d84b7f0a8421014aaf370441320c5b9cfdf9397ffc6fb193193f74b1ea701cd6faf5dd0699eff3aaf478fafe65e4e014dc3f98d9e0d07dfcd8aee3e76355788cf9f3e3cfe0f063f38ec64ad0f74f823e6d4fc7c4e3eb98e3d531f1e77347dc8956c671776719306773155680d3e6991eb30c98ebc4d07e9ed73d787bba7cdeede952ce8cb3f341d87d48eea8efbdf793fb9e651865be6eb6fb274f7c1dfcbe2a442aee5f82c47ddff333d807e5be2f91893b4f5f951e354877874cccdd1ac467c0494b10d6f0343414f9626a7cdbc8600d35ec8c0929c9e6ffa1b1309ca5cff3467f49a4eebd27ae230f920d92455154f72512a9c4228ac052c771f9be534afa928d8f5883ed981ab66368b01d43fafc82bb27bdf75d131ba4f4349ee5fdbb1f348e15ae867e9df1b57e57bfab1d8d6721b17c37e36bfd41921cdc48c0fd83241ee0c492e57e857b1a9f83b2882b760912db2f59168e23558ee3dec6a5aed107fdfae18d1a345c5c5092d87b961a33c6c71d15352305754ba4008835589a1943c32df231347c0d5be41443c305a37e6843a4b092c23e257dc3bf7de520507f1dc8c2fe2c9f3b508b568905d2802dd2d863ac79e2d17f3b2aefffdd6c54451a7bf48c1c667c7d128fee6be9bbfe649e5094f9aa63be43f1ff45b237dbc0ddbb0bcafadeadbf0489eba7a47cb5a44b5d97c8c4dcb78c3a0230030bcb8a7d50d9750e5fb1d45b50e62e86bb265415fb41e3c8f4ed07a197c6e7ae8b81687ca5f1245b9fc536a6f1214a64b14fb2a51cead3f8ff94a72faae26ebecf8d2c57a5c70c7ffffe0c3f471db5e6da5861795b02c08fa30f1acf72894cbc7273fd7f318703c0c655e9717f869fe1de20ff4326a6f13968a52a7b33a92aa12a1a370809fc461ea41a160c1da0fffba52752496f5f8548c54b4c1b8df78c3ee8932e91894b171c7db07cdf5c7fe573b8b5d445517f557a8082acfc9089591e7483703f64be88356cc754aa72fc958c324655346eee5779961ba43b1caa5ab94f515d8f193cfa9e28aafb7abb0f5dc43beee07ec8c4f455ec0c5b52548ae94fb78e3c4c5f5fa42ad3155d700500ae2ca42e368e3aed82126365dd51766217f3d5b47de9e613e9e6b27cf07378632e6441367f60ccf74f56defc91275c759460e75ee6ab0f8c4ef907e1d4834f86fdcbc17c82c1aeea74318a1a42e95ffd3fcf1f664255dfd79befc67c08c0fd75a57f8404e038ae56b0ab62ceac703744a141abc31d060d587896180c1b184fc0c8c11977186014019fc0889960091df5b9d73175d4eb65a9a356991d7447f783068b7e2c66df18712b2b366c9c4e75dce112e8beaf2cebb883ca646fecc828e953aa83eaa02139b137eaf840efc4ee6ecfb747ab615a5bb5956beb73792c8da945ca6cc3e5b7b65aefd1bc5afd72ace7c3aeebba9b6738ee3f9b5132ec75dca92c5d98ba2b07a55f5ae7d5ae725eed3a6e7ea247bb3084fe6d23936878ee94d97b956ee8e2628b101801c107b4686551040b9a2b3c60056ba60a2aa690a20351dcbc26bc219e131e11ef098f892594e040121b10122423718411384af93373d17087c185007087e1aa01fe88d19f59e3287dc845ab455a11b2c8b875c13606ae49410788b9f8fc6df1b90cc1e79311107c46e1f981cf2f78865a7cfe5a9fcb2c3e9f8a7c7e2c68c42b3e7f3897d873c29ec71e14f6bc604fcc53f4a928a5785c51507c7ec14f7c7ec1443ea3b0e78437c46bc263c2bb2df1f953e273c981cfa7243eff063ea3847c7ec141320a89cf9f4f461451fbc0fe2b1b012e0f7ef8122717afb9c56b86e0358dbcc49f20b819353f30b5b8a16cb66e289b59dc50368bdc5036b19834e4bce28aade9812bb6a615576c4dd6155b33555071c5d814578c4971c55807ae188be28a31289eb8f985c8cd28276efe21379f9ab8b96462893bda2871471b0edcd126893bda6ce08e36423eb0f183dcfc72330a899bff889b4f46dc5c16317e60e307367e60e338ceb14787f30c2ee2c397af423098eb05e3e205dbe2050bc10b66e4050381cc57a1ef03377f65793afda38a84323cb1085bb1ef2bcbd3e97fb2c4d68cd8c225153797a7296e3ebd14373f0a15c5cd2fe28dfe68e3abd1cdcb0bea899b514fe4e63f3971f3a91c7273d98478fb98b8f92b97b8b93c2971f3e93970f3a392b819b5819b5f701e6d30fdb1467a1172f30b2ac8cda8cf37ff09899b4fe5113797468cb5af3cfd07161313827d3eb00fec03fbc03eb0cfe717fa5e4c68f67d65793afd8fde452e9274912ed245ba4817f95584f37d65598a70ca2f9f1bb1e8835820168805628158a0cf2fdde886f4a4273de949ef8d6cf44935bef2bcbca050ffa753597afe72797a77c19954d371d58bb85f70fffacc3e345fb93cfd4fcd572f4fff73f355059e3ef9f2950f4f9fbc2167e4cd57403cfdf255de94b3f2067af96a88a70fbaf115114f1f34f355069e3ee8e62b0d3c3da170689c96f50cd536500d794e1aca09803c657346dac8d4455f0ff84c6b32cd9fd90c54f6b999da807ca6372b7e669fdd26fb8d06ac67c03a11960e6129062c15c2d20bd8590bc24e20ecacf154bf05ec6c79aaff077b84a7fa7db00ef0547f052cca53fd3d58c7f1543f0578681a407ed8f6940f1b81fe1c7a8547efb0ed291d2f63db5375468e05d8f6949700db9e3ac1d8f6140e7b805e5995017a00b65f6c7bcac572d643137d006efe6edc5c8abee5e693e86ff0d06cb81925fad4cd2e387b68289bc918492b5925aca48160a01888166261fa352c0dcb6257ac8a9d6153ecc99a6cc992ec674661a2cfac6f387f66d306e7cf2c86e97f6ca633d0d5389dcda0c9b2654a03bdd76786a3c2a30c78debcc42c0376fa144fbff3279eb73fecfee88c329f9dcf8d7e6814f5c475288a92ac5186a4a128fa8942516e5dc635d7d5ae733a3bcfe733eb1bf49bc878454a1e9485737d951edecf9f3708763bbfff28aaddaaf4b841bc39e79c73ceee7ec1d90fb7af42b35968460bcd6aa1992d34bb85661e2b34f35aae0ee6ea6a5c9d8debc61573e1b86a9fade46e27d6b730ed5c229ceec5e26c5837ac180b872563cd58b49bdb0dc7bae15a379ceb867bdd70b09b1a9ba7621f4e293bcd9e86aae151b561ee3373358efa2f37289b7fbd3e33d4cba34e5f7e66deabb6bc182e3413b946acd1cdc8e6bd3eb34abaa18ad54caa8a39e35c114c4079aa3eca5178deea2a7e758481020ed76f5982ebf79001ba2ad1ea1780aa3a8c254870fd5a5f6aebe01ae3b4a4aa5c4f2f85155c6de05abd8bf95f111fd4b9cf41fd43ef3329f3ccb0db915094085697886ea80d07931125712414e5600c014a514c46549950948b48197652e699d9ca0fcd57e4cb53fedf5796a7d33f0af5a17d688dc3c320265f950b4eca7cc5bd77cc6765b3fc617a979865f84a97358ea63028f34824f3ce08b4bb69777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777707a916a8442c17564d102a44230000000001e315002030180c078462a1300e0359b21d14000f76a24a724ea10c8431a694318a18220220000000000000081200eaa783925cc8b116f54a700b934c688af5a58bc9c0854604435c07f68e83e428c0c16090d859095a1b4aa5eda5f0d935ce861c41baabe47d5d9aefc6d139f4020b82b710044fdc28e99c361fde3ad45d154e19ee463940a847658eedd754064271d47fbde75857528fd37d04ca6e6c81658a1f8a36d6e8574954e3ebe759ab4765fa5efa21ed6732cc5c614788e9c70578851d4ff61174cdb2817e3cc9c5fd484395403d8d45cfc4d5ad32df846a2ba10b936909915dd34a519647f7f75f29504114c3e2c90c63034e3eac9ef59e2174936d0f2dc650f71715cef910082803aa56fb1f6a976674b381f39604dff6788b8b2a56460c31fdcc6339baf7b5b8f642a96ebcc1430736bd56eb320468d18086f390d0bfd0f5708661b0223c9ef45af9eb137d38518bb0b9c1fcbac76b1845738327196ed2b917258b36dd570fe30cd007e22904a3b765923bc2b4219bfaa4dbc02aa930baf0b6134c682850026f31307b04d549dc4e1fa467710d73fc5bbe0294deb7cbaa13cb348d6d262ff165c5570f374407130b58c65698fb192fc56f9b59e0a0a6cd73284a2a397b5a8af913010d8f107598cee9ccdff03560b73578b02a44720f626599ca248840e69c6820f88d8ca0b3f3e8a53a3d3d86adc12d790f29ce0e2a453168920fee556ae45fa912415f3affd85641be258c7ec14751c023505acc994b1ab88d6208710c4bb732ef0b1f8f8ade30cf9ba9c42fa0983886637c93338d0373a5a5311570e55d2deb4df4701c92d6df732ebb06b848d09fcebdaa89d9477fd1ae5745b95ddb50707e8374d3168765d5644ad39ea26300b91a3d3d1681320df03c65980e2a415a49b35bc1e484eacc8c2f9085fc522c09c79754cecdac5e8d1889fc58f4ba5d14e568cfc6b5a2ae1875fd0da966d4c3f2a5e2aef8404b378abe8927a56db9c2daac7b9f477b433767e975d248393fc9ba7fa4c5fb9cac968a3b1bde4da134eb29beeb2a947a9e92270904ac66671977ada18708e064433c44458cabde84c2449c2f72614b362f1955481006671213e7745690782dea77844608ee0b223c956c4eeee0d57d04956679895da6748e20815cf10319ca38e1998fa4749f4ec6486f1b18ab95b0a1cc217e6223c50842c8fce95b006edb84cb4a801055357613edaa642ed14be4ccfdb7d6098b6a94c99eaf003e13a5186ddab8c387bdd28b1d4c7cfc1bab430383be007a64a1bf08abcdb73874dcfe7c435964a8c3c468187167868365d50a2f03dfefc5511b6fb093573b77cf87bbbd9cfd847312dde97cb1e5492fed7b60a52d44889c8af0408301c3a2dab28011a65c2e87b2217996a4e160d622553df19129c7c279b7a6a2c990c3d8f3b3a635b95c74588b7b3ea11820dc12c593e2019e0bdab5a6484c26938567727c2f1fe0843ae0423595e9b697df10a6ce46ca0cbdc05f86c28246e61999f7cd41cf8a218a0c75b060a711d7dfc247baef8802ba1cf9fae4c225493abc9892a3dca33243029f254ea05506ca068917397acbeefffd2bfa4f87032cee319613d0be3470aa183431509a1ad004ee78d223c80b4441dbfe3e05fe68a6820aebe3805118e269e6c71da25896f9c2778b642a570a765b005ae3709d52cfd5a7bb140a2ecb15a381a8143c45b443cc355d3f022935f984ce452cb0bc098744a91a47f62747cdf88c9dd67521d50dc539ab04457dca0d7dea6750e1077270b51137d37fe50c5e687179fc86c138ccd49bf90583f7a6598869534a49bd1856782d7d93dd6713f2f3e9f240644db4c76e684b34859d7b1fa418235c4e2d3fa068de93d6b5401fd84e1bef6e271a3a719973eaaf8cd91bddf109256b308fc015319c581d874f35ab47c3c44dcf04f849746545b968583aa4526eb233f2266ba29d075775fd2084151f79fc91b9657c17839c784384e9013fe3afd384bd098e364fa75c5c43d4e7eda6f8fd425eed8e2762ea5624383817d5972996cbea05bf7cc00fbf219eebde7e9c89d5f3836d0d28d33e1b6b4a0f8867cbef1a21cef483d3272fc08125408fc173c86a5e3179b57b56c918bcf8443aecd345bdae0a2c4b1d6ab24de388ca1e314a8fb6f876771dcfaa98544710641e817483638c77e2ca34587441ccfe064461d6481b8036dcff5eed8829229114d329d8f40b50bd03b26e4da738f7eb2afce72b00007cb0297917c509e945db4c52451e38878579b69a1ad0187ef76aacc8c548ead1212c7098046198fb6961592755ca4faa018dd3a1a2c1704d2e6aaafde000f45cc9c5413907e4bd29ed778484cece3d41b8ed845d341f24e6939f41acf48cb6f36bab296262e5dc298cc03214446f53366a80d8a5e0969a05da876e2041a70274082e894fdd09039c90ea6311ed135d399336a04948261402421b30df2721096864830d52986d5b9e2183b8267b840d60e5a30ae0b5400431966009083810cf0d5763005a95ad80325bbb5ea34e567154def40d1956590767ef41b1beb0d9a894dd23e278e70debe7a8a02baebab91a2890e12349d8c35795343cc57de41ef31079a4cc94c0e845c160cf3d016f748a03ed204413d6074bd4018297d51ad56d7a061e462de21ed884d8ef492d64ee3fdfa6733581876a077118c560de57dd0dfb105e92f4c12abe8addf45bee96ee8baf2428bd78832d608f3f2838390c0849569f6b74ee96e40d2452edd4c423e23f961ba6e9a29c98c257a2f0e1ee588b077b47510aa1a362d1a14bd4142c04887032c12a08859a15ffaa6cee5dd35d9a3325d00a1b25b0a2d180c3ffc89a0b286a5556efcff643344be66fb4d3a9b240f67940ea5b522b7c1370c15fd195ca2df85a61831211808f0b7025689458753583956273f4f3fd8c28f60068ee1ab81c0003877b4ec977feb44bfc5f7c451dfb060f1ffab34ef70fda776aa74f06acd45bf9b9bb276635ead6f25f92e1f79aba445ff75e41cc8cba003b8077f64905aa1561d7428fdf03c1a1ee0a62561da016061a8787d5d653e7b01cf04a1fd1fb549c3c84d84d4ff8a715618e200b28c13f727f73edea6dbab461061cb3001a56128797c620a71b4c36b90bb5e8d2bb181bdd13afdf1ca5e66f87d817008e98107c57ee587e84c359f7abb171636076b8c25631c8d907fa6d25a192a85c10825fadcf36f05bea5dd9c4d0cf2439f0a426528117a24ab57007301f4e49281f101bf97cc3349c3968edcbaa01f7c96c5be052b9f48ff59f7f68516b981cb135e29b52ca803eb16f6e30b4e7feba9e4ce8c0d4b19586a8b81ffdbaaf8f175f31a5a2dfeb53030dfb70cc479da02ca634e35330066911374c7427b02c9799de12dae203d61a4a20fae26efb69f577c66a7423e1a0f13c9bdcb4c7633b302d20eceedcbae1b0522b3edb7ac0617c2a13a37cdaa9eac446cd1a3712caa7239544f1eee9d23cf42996027322035970ec22b32821575117c2e8449030090ab1aa61a954c0b42cbe500b1816b4246e20a32205afbd40b8cdecd10de1606012438be4fe2f6d2545932466b2cb8b93fb406c5144584224604dc0a4f9dab9257985bc8b9f25ad1eacfd737e3b604f379528de2a7c7e7c3ffd48cef6b78fdcd1eee62379b32406220896d46044b6821d1f0b434a3af31f669fa32efd614ee8984872dc6a058cc3a53195613847a04cbefe899d6540b116a8cbe5979e82e509d6a9db56a09b2aa60f4d330e676365dab51cbc1e82e04f50105cbc627f60e5fdee81a897fc0e5cbe420e54b11f2fbc42c31f169b125c56ccf59cbe2efd8323586a8fea4bd93cf3daa45c6a3d24545fc4f1bd64ff3cee92f1913897a48ce3b7a46b206a49dda1ce92e8bdb4fa1243404b53899f9df77ca80c162bac62788415c0504871eb029b1d642dffa4f892b9be4eb061642a832dab10a672adae7c24952985c5daed43ad397742d82bc6b13871f1a8da35e358c7d8a1b071c8cf30708712f3e2e7adba40acdfd09f30959b78bc1ca737b9066ddd9888126ffe0304925a805c9a7ce04b703397c237b6355c0047cb4552dc888fe0e31bd57dacaf8f21b2443e85799fea4045d809dc921805ae3ed04a6f5663a7a86d6ecdc6507eb01707b6d3f6ab61c1638a9db5568521adaa73d67735878cfcbe2c9ca3d140f1ad81dc4a913b37f82a93e361ac5afa96542c3e88337fd7cf49a5ea1acb7d4d8babfef792cb880afd3aa4477eeb1a2bd6ab5341b4a6ce598f7026658c00a8efe9dc4e8275e9ea784698210ef173893e5d5c6f8fea7931b4e8584b9ef41575458067076120dcaf636d15c648b21a604e66f4c67ee022fc69c0c82c3527500c47793856d7703474df967076f8ed24ba9154d45dfd414f1752fd400b4478106d04e75cb468bee32a2ac9ed1b408c2cdec5487cef4b7ac814c13e1985e5a44194114dad2fb003b9e6c8da39f5186f2d730d4157fa1f92d41785f226a23441ae43b5a3833269b6e33255981c45ccedd3af73c4ffa87e50903827da4f7d8967eafd789bb82be1efdf13c3be78ff75121cc1cab68ef712f91ebed8dcc58406ba4cdf88a74b6137194ce9391194715e5050669aa6c68c58d152fbb911e897c18b423da60ee8dc40e9c4676cb4a0d687dc5b4621f98714e320df5572a94869e2f188854a931969ac34d3946ac4a2a71a6108285563439504ab6ac4aa63d528c36bd578b898935523cd1c920259d3ab710660c9007dcd1a4b0bec19ceb935463d264a396567d7b8deaff1e08ffe89991c85fdf4bcf76f4a710dcad9c75d88cdcbad87534228f6a1d3dce3948e452c0cbb89ed9e620e1a4197b1fcc7291be9724ac5c13fb647f8c6cc9abd7ac4979408b26c659e77af53be723a4634544f699898874b6720a12fb06e93de58c270255612a3d3a871c396918ef1321175442cd0e44017e555b09c1a4bc86fd1ec629e0e13ee9cbd601db149c61801344d55ac5bc9156524a0258c22c854c4a1b2aab84245cd2de9a54a84a1fa992b124538dc0ae15d44dcadcb18d37146bcb8613e31db9a0848d24c5d1d8c00c7713ccbb876124d1deaaac51d859cad98ee96710a72ad04a01777b47eab8b11016aaf4cbd38682e1ece984d2d060071bcf53cef31a5b28a2c2638ab223053744eaefca4c895e1499380791ebb7bd154c4b9d464513004ae338154fde448b67c0755cb67ae7d1eeacf8228db452f5582eefe0aba6aa1384c4e7f650999c8a2eb622f27e3e14f7c66cbf1118d6e8b8e8f9df82374c8c75ab13d53137a8f4c02b5e46a18d2af6c822b39b3ed0e388d9b010709d25b55e130552149d2013b2334af614a947e45990ac417584283e0e20c10d1b27c3f13df47e4461ea1a71fd45875d6a9131821355d3279c498321fbe3b8fdbd5dae6511ec7aaa37224bddfcb913aa8361f984a0920bcc6675c6a608e0dbfd656192b4ec150baf301ebce1872e050c4e597d61647fff8d66a8b0f908786e37bf4cdf716d6db718592df2fd80d42a9e28b6df0443c42227aa6c4f1853d128ee863feddec4992c1650cdeebd02683382f8d678a13beb5ec48427c23ecfe8a4d341a12559d6d181b86fd28fe6b674aee5bc1a13c132f652df1d3c9f4426f64fef970c5934ce5b0f68a0be9a110f52639463e823679905a749d71e62efce31cc386559120f226cfe62a4099eab7cb1bfad13a4ade2134537736f8034c0a0e20360a693630375815fe24425af1cac7bf4708825456e784cd3a1e5522ecf25a9639d304b11b44bb61b4fcda6148d24e9ace44720ab482ad90160764f959d9c6238a332c21d8c197e9a0a1ef183260badb4c7fe86768c6466a325aa14734b51af0df8419e35b55826d40741c44c55d5582d80b9ab61611569540bcdd8e837dbaaa746274f3b8a7feaab2166751038759558e648064ae934e2f569606e4fb87130dbe19ff71232010263a2792aa5407277da883d3e1cd1a3da1288f0bb77bbeb27aa18396730b567ec8e133836192b5b80a57c327370c7c9e1f1c03e9a91ae13e2bde7ab9462f15f00eb2d61c877b0f9e7ec108eaccb786cbd6979e089427f2561d976337ba4f4ad5868bcb95f000c0919664e8f50aed6fb5752f465a76e1ccb2068efb2a127c7c1c1c9acac109edce24fdc427ec0db328787bae14622e2611e76387d693370409525e7dce42d4f610b209258600b3ae3ebc9d5c358bac8d98605934a5600532e833ea5c5360a0817b537724d8bee104c606c31b6d2a012b99702f7852c5d010e01d3040dca86daa03336f7dd48461cd63686acd438535ba3d3c52dd481d9e35ba73074a73f7f97ac327d9936205abd9b2a915de79d1f1310ba565bbb23503d4e14903d10fddeb74ff05db00b0a789355d5b425e099bc07bccb9f3267ca3e33446947bde0a52c3222143761b169d507ad97117438a697e7b7b8a4b9c4293552fa2dfc73d0351777b71c1f4cb116b56d3a1a92ee27b6afdf83cc132ce1721006c2dd58c1997f139b82aa9fa002b2cdea7b47046620c3ebe2aa91ac80ad677fa633dcba274d2e7d0812b7e80d59e765ccbbe2a4fb45c14f00a1f78bdd71ce9b2d68a733d970254d107aceff4c77a9645e9a4cfa10357fc00ab3dedb8967d559e68b928e0153eb8fecf01999dac3fec74d7ca260e4d44bc2e9f0c2e090c6de614f0b15a2b20da4bb563c6454c0eae4aaa3ec00aaff79a235dd65a71aee752802afa80f59dfe58cfb2289df43974e08a1f60b5a71dd7b2afca132d1705bcc2075eef3547baacb5e25ccfa50055f481fa5f3ed87c62f964d1bbd437733811627a3972507968b8315181c6d55861f13ea585331263f0f15549d54056b0bed31feb5916a5933e870e5cf103acf6b4e35af65579a2e5a28057f8c0ebbde64897b5569cebb914a08a3e50ffcb079b4f2c9f2c7a97fa660e27424c2f470e2a0f0d37262ad0b81a2b2cdea7b47046620c3ebe2aa91ac80ad677fa633dcba274d2e7d0812b7e80d59e765ccbbe2a4fb45c14f00a1f5cffe780cc4ed61f76ba6b65138726225e974f0697048636730af858ad1510eda5da31e32226075725551f6085d77bcd912e6bad38d7732940157da0fe970f369f583e59f42ef5cd1c4e84985e8e1c541e1a6e4c54a071355658bc4f69e18cc4187c7c5552359015ea7ff960f389e59345ef52dfcce14488e9e5c841e5a1e1c644051a5763e53f7f4605967a86b8db7f2d54ae1aca3a13848cc9ff5e26fc5653bcb0e836471934246725aec2c9d9f723ff5250c1d86de758eb959792f53213676e93440ef915cfcbb2f88d8beed4678cc661939b4232f4d774d503ad4fe1e7a79aecd6746791102751c283ee864739d7c689b526cfb892ab55b05ca8fabbc9c30e36138ae7a2a08911a3d3e008b212ef203850ec0ca84f121a358be45560a90870ced6a7b329b8d5f3130f306db5d7f4b45c27f694a48b05ebf41062e80264ec463b441a9d623f872f4048374583cebcdbbe8000b28a4e688bc3816eec3e593db64dbf0782f692b078738c355f5b70778f71ba5d7d0aa5944309fd0254d32faba07d1ac581166c46dda2a180ea39aeac5e34aa729dec4805ce3063d926d5607bdcdbfe7a51bb8f1f6997ebcaf8811240b194b887dbb8070d1770301ae921876a93cfce4e36cbc10f2cc74342fa18077cb6d4efc3c06689752a25aa23630722c1d141fb800a9f0af7d393a12149e730ebcae9f5fd5aaf22b22709a7a8adfd6da6a8b8b8b30dec8bdf7d1ddbabdff7341fba89e2655de630975225780f38405e2dd92983b01e962a255e7c710159ed6cccd4c054b11a410f7cdfb09e5f3e5d76ac85db5a97531f558aec9e2811cf1db85bbf4779e8bb8c16c47b29df7c84522f24d2bd27732b11f46bd91006bc7e95778dd1dcaf2faf3169fc75820893d15f9f63300bf737aaaed1c95f7e2d362e4c2582a70d453fa2ca6ea323cacc60dd80875f36e623e0702bea35250afbacd3da95ce47f59437b9ddb1c0b04824dde93996c6b96c21966523a465ef67b90f5e3f40be8d62a75e7891c438009e9bc302bfe023638824eb81293b09a6742107383653d947bd848dce29fe9aaa51c19923207c205b92c1a15709e5e31cfc400208f048a94c295c29f9bd033b68e653bbcf6edbd2ae956c1f4a701fcadd2769a6d00e52a89e5491c229a0f2013850b66b04865f7555458145bcfad4542451930b76908f5ec81e3a7ab9b8cfbb6f811bb0a5a0c325aa8c6ff431d8e0991c433e0fbd4093588b32bce42339bc4cbd847829206a2a6a2edb478c1dd8cfe20b697d93992c6860aa199dcbb93599888c5bd7c9c30cc51319a1090d684307a18d0df7289b6fd667653a720460b81f48e2aa663d074210555e8da05f112f8df61af7f19aad42eb8d417cb685656b53e1d3519107defcaa4a6a24a1577e2437bfad92cebe1bec3a16182029c402899a0ffa8a084454c79001cd6ced891844100bd174aed2297a1150b51e43d927fe6d64626017288f7783e545a88062534af4591385acd8a69b48ff0651f1e57f7467045a696130b8ccf60018281f351a7326442de4b72251439750d301006285b2a477344325b6b81f6fc0a9d47b031f50d2e096af0055464d6061aefe61272e8b14c60fc8b6210e04581f44073ffd30501988eeb76b1c93bf2a5a18fa6c0f8fe2c7e169848fde7d6493d2e2d1495bde93673f740f4418f5ae332778312000dfe9916fa9ee13f5d3937b9727f3ce6006559f05678f5cf4ec94e7b96ae659a3f2f854f564c1f4ac177a1e359136a183a8cd3ca92ee598500cef80cdce8229e06ca1c989dbc2197fcef170fe4014984fd54ced2b673342ee170c376ad37a1983554f10ef3c8973e8e54b0d9faa891f4b3de4fec02f3e79c5c3c2370d8d240cdaa0918eec0d8cfc70c3211ac131aae2b018a12aba716a93dda791dfe016445ec0a0d23c384ffed6a58bc5408c3ee2de7278031dae6ec1d2d982a207a4fcc9f36e19777e105b8acdf6fa0a975f53a41277e23fb7a3c7d67192aa01bdb037c5eaed2049b633e7b4f347a8852665a6d7e2fdc98abcad01f05094ea9fea0fb8d442d9bb1e8236b5b00b7bd2281a6debcc80cb6b5a826640e5b4afc10ca83a5f3c3b530be7f9c543d2a98585f36267137b6271d3843a011a75f42c91a73d4b9d05e5c7c62d96f51a556797b0f39f5740d36bd5483f010d35acf3cbac13ff41211ad53abbdc5be7f8739ded4b0e9ae3072e0d8cc76d08dd20b093700b3b736e40e5de46dd59840d195e260fb5ba6672a3903fdb571599cca9d788871873a9ab3c85f8d28c8c78a93675ffbfbff312ebfc19519e7959e7079d45ec32baf1c14c24e64a7b19a3b49a8cfde6aa21c75c136719837c1f2a7b6188785ec8b506ca1d49dffae9e68637a3e7bf2bae36da2c57d143aa6c365fe2dbed4f458f256a106921099c898963eff3b8470ce65f2b3d300e77fa6e4a5439449e0e68b8a1ddad5608b434a387cc340539614077810572b7e5ddae6c903888fb27c790de26f13ef440afe61a66cf6aff59443825510db93ec21cc20e8b8a321c4557f6cbb0fda207a3f047a42f77983537f5745e15c1e89dcfac80da89acbf14c4fd1ddfa0747893108cae8eed6af22fb3032ed860c3e5e383a7d2b490fc7ba89e245d3d2d88834bed679c20b58779b0fd0cf02b286886f4e04ff895b37adc0db049c7f16fa16f8ac8fb7f8c8db8bca582adb3aff1e4e6d741e5121c2e337199043492e3e6b4c2a8a1bedac120a3f64e636b09a74645ddcf1834dc4d7db71c00b5ca509816c2fa2caa1166ad252daf6912101dc2365614b1612bb98f4d0ab48d06b77b0b5d082ca5e3f1c508e78d003bc370d821652df4eda49505fef8a662d7870eda1a04f3674345a521b0a2d1483f533275973d2a454f0c392ceac28e31f635f717d3ecb31db734da55f59f9e4202a1da31720edfcbb2e416a15b8b307e3f5b3381a48a11439966480ef01956d50e05bf485cabbae61aa80df0ff292b0f2e0484d1f4ce9a483acba580588b6a46716acfea886f79e4035dc7405aa5f82fa53c266f04d339f1625a8812c4c4124bf81ca2eae2d8ad89b0a3e307f8334e593f50c62089cc854ccb100f74a921899b91411140e3191033d3c9766766dbe7750cea74d3310c8d95ddfccabc02c7c5fff278f1c5e5c082e34aff787f22c850e320b2ed98598e69d11f856366e164be2f168d4121b2a8f607ccf7a479825c7134bf6a9546482c89e0c3cfc42021b973da107900304abf08006335de82bea2f618e8d832a85cfdd513e60da859416e158ef58a789030a3cbe40f97857c84577499c5682a185cf00de6a4ff8d4c60b930b765ce1f967c4fa3e337e540f4913033f2eabf0e1fe6ac88edd68ada5bac5932609d21ec04d2ce755f5f5c49568a334d5b32ebd0cd30a83c0569206d4741b794130fbc9f8a6bc00db7c80755138b433acf8a6c5f53f70195479c5531ab6df990ba65a587c9b86fd0700ea1d32064b2464407e18dd604a6e1419ce1aad74cf47afc9799c5a3401f97f16bb08a7fc00db7fa062d69eb1d329927966952b69073a443b8cadbe75460a8b2e1d68f2e6add4ce7bb0b237a68281fd1766646b13c44d88939093c74d48c624a86b4825d53b0eaa4501a40e6da837c5d012e5e1d38029d9583d6f382bb7713af87ad039c4e01626da84eceb635007cced026127586da1d00dc6ac5c732eab7fbec0e48d53e3d99417e8237a06f32dc44946181cd400e6f15e3c40a706d1f41861cfe16833479a8e63cf35fcec37f37d37cb92a0ad446cdc35bb54eaf9fd879f78abc01c4d2941621bc87372c146870a0efd32df604b5d5447512f123406085af571163208af18d6006c3b0f3a9c88c2144cd75dc9d649426dd20f3f9606d67e118ab6387c125ef8bde37df0d12484dd1409793ab428b1536c73167eb6ab45fdb6096a8731a69e53cd3a5a8072796ac59a438a5820c112370464edf98256a6cbbb0d2fd369be8e252b017e3719e57a7d4d04b6ad3a55d57fd652106449a60a03b34a2f21e1c9f89daad270f9a22e85f927f5a6e8beb65d452ee6a4974de927b6f7bf8d45b4a3d32e136e2592978ea0c3203fca58bdde3330584306fb0402c9aad3be9d68ec9f05acb9e6feb71fac984f73daa7c1ffe0c41257100d77e10510883d8724db57a29d2606392a332cf8895b43ef540d5f19e0c288109e1e377bf561dd67f2e0474a4bbf42c024001c76db8f1b7e153b20eedc67f0e3986503f37fe0c5195e7e1445bac60a7e31ce62187675677d33e3eb1b6a4a216d8c75921ad58c15237e54ba522670cef8ae2f490afbcf204a2634a843e6ad43c3accfcdcdea683427000c2f02ee2e71d42a3298dab2357aa1697b0f222872fdc61499e611702180a0e6f5bda8c3ada403a69c8e3fc8f70fc1a313f5a01f8d35ee89b21ea7f7a4844e414d2d2f9b3dd84d1450c0dec45ecd16a788e9d2a8d0e7b0774fb18d2b30b3aa70e14103705b89e20c812a09a770afcc76922952ccf6ac14826d06fc32fb2258a616aaab895885a9a587ef1d71d22c37ae257377cabd77f5f5db095d1a006a96e5030757d8ba51612bf077aa1c127be0222d0492e9eac9d54202c974ad2ed4da5557a7888bed54aa4a60abfa21b3575fbc5898dd79ad8cf6ebc808777e251e01a4979cc13883ca0c50658bd9d9428e2958eafe5bc8c54e7bac5eb4847ccb84ea2f11aee30a8da0663edfc8892b3ab528a529d92a4402eac340d7d9d057bd34c1fa16f54e0d38f94c8d625c96305d89d5e423de05e78fc4ef11875dbed05ae8cf20dac68210c343c69710781d2fb33bf67228e5e26202f83b07a9a6bde1c122084844a08df22efb6e083b1090e1c01355d6c8521dbb0e0fe603825f7f621c17ed2f560937aef022224ee6228a4947d981f49e13060b04ad163c6831724174a68e57c0ed744b26b4ec7e67b8c58d7e80130b1f083a90e8bfa00d75cc09b3c1424273b2fa59d9f05cce062a87452780115611681d01845aa6898bc41adbe11c7d157631e37d9ae16e3adf20339c79c7528f28b22318dcfc0b8d18197637daf0855410cc037b4c1002519eaa8e8155f5c0aaab387a7346a76e0dde92cc052a8cab8042d3768db45afac78697e958fe1583f182a309408e98736d8c03416992623014715962891755f31b35a387cc40c175a1160eec6c340e410fd9435ed9e84a28758203ccb0060a9472358e8b53144d38d773fbf55b4c2aa9b45bdd7512d7de9f9e0fc98dbd35562518b850bbd0bb4219bff832056ad0f90a3b9fc2c7b093c4d3becef0f4264a540a371554cea7f790a3b28bbdb6302a177b8c2181e09c5a842c3bd504e7eaf3f08f41722cc947de28ade01608625d2ff1080ac2e115e200b159bb7b2c80dd037d5ae2c37e4188843703cf38da5c28bd2439e81d10f94c81344b86854a74c908c769cb53ae28bf23ff0184214450d6bad4718ce37257440b172f0133e4a2db3629f7ccde186195186f32ea47e19c75db9a6d1b99c5dd467ae4ed3474106c29c00d48f3da62e46a06508b10fc479b442077adf68e33597b3b2baef3e00da08a03b9f3def11dfc02c070c18f0d61804da56cefe6e394e409163edf73907fdda1c21ff9c7e5cfb6ec07644b0d71d04633b112c975d1f42b3fcedf9ed453a75acbdf9a828db57fd284c2640eeb976ccb12cc3028bd8f3ab25751a3dbaba2f9fb26405977ae30d2f7e5c3bbba26de88c28dff31657b9ecff047a7036687ea04efab82de6c10999ad65030f7568c63d511700805a8ceb5441ce94c92183ec14e4226b0c34acd7dcbcac7070f9ca2ee5e4018423f41ddbba1d7046674fec79cc94d470f459c35d77609622130e6c6f101274244409b211fc6cac2bb0778440c6998b13736a21d1f0f905d82e6b6e036ef9fe742e8053fc2f15b6620e7ea8a6dabc9e340ee3e9dd88fc4381ad854758abdd480c58866fdd88758c2b698daf5111ef67cc59ea6816034257ecf81d2009248e0d81eb34c3ccf6ca40ec89d7bde6123f7f9b83e832a1e919a0cb0c523942ef9d096e16d7d9714e7f08dead8e5853e631124c023a5e99da36ace6de2901aa49b94cb5a01deceed19a6d6d76a4549b96bf1217227ee5063fd1748839f5e9e61036b916775da0617d4f762a000a1825ce2e938affcedfe9774001d0ff1b4e60e5b98d2073b37a38bbbf67617d0df21d1f17b1d63c730c07d5679c82677e76794e675fc674a7331add765874ea32474c1a16d1c09382bd848e93eab9eb5a01836721c82811a037f330e5cc11e838453d5a32a0831d17b8a94dde27210a025db458201ce24f832675b1fbf71bd84787f7c846e3f62212b04e5b3894a8c92f5dab241186f51e3b958b4f309421e35bc287e937a4b8a93d89db9673386069d6a23017661bb99987ddea1c6cc8eafb58177ab3dcd3902bcfeec81703c8af6b5042884ef0bcdd9183658dabf912d07421a6f200ac34c8cc16b539025addde5aa02e7bae349a79b01ddf69bc8ad528b3f953ac6de0808fe946100ec6b658f555765c4d3f0f36dc35f20123abc7ebf5b461180e30bd21c65f58c9378c1a3429f78ec1d54a356907aa6d61f7a0d2638200f4257ddb799c96cfed6913456e95201421dff067d2077dfdf4417beaef34ce6781073411bba1684f465d9ec43ecb69b2629cdf04442393f93e6b05d170399e63f34f3ffda703cd39302b563395ce40285b11ac7704ced03be053e44e808e9cdb07560e81a45d055a54c60a2953f237aa157b685e67936d7a44003b8d75eb178c2c3678d943c19e19009ea2e46d81745603d58758257c2b7c997ff9d82d9d9003ca274a45a2c4041198f7d22c6fee1878a2865e5e3751afc640e1da112bf284b59b3456a21d51c7c677ff43a6c5b428a4b546b4933886c4e8efc284af5e4a8eb7abc4dd22876940a49d94b5659e98ffc7a302fa0ab6d7fbae2ba1d589ba4da7bfb28e087afe06f4ca9cb18ee8f67becce9bfafae3325ffa99846e62c33638d34f18ad0f1d44fa4384655b859bc2ffa62390033dbe2301b025c187340fabba37a00dca5b7808f1b09f8eb99d6d536955efcac370f2b235078c8e78f6af7b2e92fe36b978223a5688c2f055cc9f6769a0e08ba895e4a9031890f31633d9e54b58b754d1f7627617f02d052a7e9749a9682ecb54da79268147d001fce4cadb76ae2e6160969840083daf30b1efa28bc9a40d8aef64bf23ba7dde063ff8aca1275310e735fbbde6a3a01c0a7273803fa5093c74772d117d75cb1c03dbb010e5939a2c945716fe455634bbcfb0bee6ed39ba01652b607eb936022452e209f3d0568bb22d12494cbbfc1b5cc4ca2b1a39162c608dca8532d0d4078771f5c1bd4aa1463bd46e56b3058acb13dec4e3be22a3226b64d770ade759c324fdfa4a1231fb5b7e232072573da28100667644dc39366f4ee995d7fa96c30c595a648bf2b0157dde760efe0fa01e7120422815249c36169ac6f8932629ccc343508cd26bfc31b4520f98998639133fcd4c3a4b747acdd92f90e0c8e0a052f6904b1d92f29163693032070e174e008855ffd16c5e6e9c1e6e72e33a24ddb608ab0d60d555a81e9f6019d099efed1a99fad9479d3b6de81d7fe0488e442e1bead09054505b9a114bcfdddc5b8f25ba11c8fa63754863c5d22cb7f7eac11dc17438151779b3385f2fe012eaaf403d497a1aaa83f4c65bfb7f3749b0e357b45c4b9e25de22ea6730b1d1b428c0fcb3adc63f6df19095ad270981c7b3cbfd5c7502fc05767e99fcaf0aaa9d90b262fd2028d95cf0008020c86bbde4aa900979f29d18514e5dac38197a46c469ce593b45397d40be60facb9d2a34897f4fbfe6c89d4294750c5fd6addf1a0ea20a77ec75713498d418c3675588900e454ae7865f79b1f1b3c791182ef84b3157611cbbff667162982c993cd5514e590d328713bb1d85ce960794064395ccc314ed5acf1facc3c69ad24a24afd3487e26b5a31144ca08382ba55e5ac9a15e5fd1af627116bdf3d60c8758b194d22e85b6cbc0daa3b1606a1236b1944bc348e892e79268ee3208a5781f60bd1268ada18583aca033ae87713f64d86437fbda16ac02edebba3b4b9b4ef32f8b6341e2d4f6d17d49dd24857a14bcfe1d85701e3138e86e71b1777d61a2d659f49f23f36356e839ddf1ccf86118a8c221298a408480caa521c635540259aef9050177b9033f0a9f30d20f0a34a260b4be45fea55f62fb8312e4f28b0a2fd7517f099caa33f52aadfb6fe291960af597b8b999a8e0e1168b7b12b57a477abd02b8b23bb762a6067b8a6cc57b6a4b0da3583569a0e28f45e17bc8997ba7dcd5335c7e4a739f4945ad094872a0ddc6b4265e21ec44f0949a12625f051f8044a8cd40972bb0a32cf1e420dc620d056530790195cade34d7b8a86f6e6982b2493018c5d1c213513e1a56ce1d4b1859779d0eeec03f9190661e0cb298133d623b796f17f47ec8d58cad2ce05ee7e17b676ff3666a760d1666481543479ae3a68258c130b75110392a0d43c27100f3b9a232416449d7a11be4316cfc52a636b88b05891e645b877aa9f653165537eb6619452e18d54b35309bd0b5c8ae155565e85261b6169386a3ddb934247fa647c48154f02358008903b64f04534912f6f950d763fb606cb1c50e40f5e8dd5885b94af898daa666378da148fa24d28a85e6a462ec92902f7a3ae13096e58d74a528d35ff5f4a9fba7c57fa7e3c0b4441d9d1e5f4b7fe4acb82220cde64d288a8a219bb847d15dc7d0df7c0e1d408d1a50e9b2a6469e5379ac5897ee98999d4c7ff2d98b60717bec349c5737b7e926beeb029bd597fb43ba959b6da5da3f9ebee30d873917d2576d4bc1a6fc3f92c4e2c275a272654b642b616a107d118d48af2c774f85e7fa42a0eefbf2c97b86b38b20795fe87511f16ecf98e697a2e48b405feacab52960f33854c5b34abcf4159f7a89ca35c98de9f92449fa6db94dd6237c3b011604b80a47fccc0cb4bb639f37c126be8ba281ed0c408367af805977fa0018a88d78826996d9b94e0db692ae4081e62f938d4237b5eb888c4f8bc2591593c864d3b31163416e3481faa6d2a300488b4f56df6979ba90f16b456ff2572f4235935ab4fa39ff2f5303afd49bc32789b4d1e5799c299d3d90b9ab40b1c38b3b9d4592a2860912c328c8e514ffc0e5698228ccd5983427d87e4519f7fcb27d64143f3877c3e24fbfc6acf0169a35b7bbe5cd192e2a91d68bbf27749157c7751369a9f3f8b1ffa2c37f3de52e45aef92ae2266540987700e3dc6a7dfcc8b2211b1c1a085b0cfbfedfe80e1caf4756419b982eee91af58dd5327bae7eb8fa690cde97b4f1c58e971b04ab9c885baf7212285a0b4aef200d9aac35d19d4c2a23105305d8aa9ac95ddf23e7ef20e9d86a1eac727292257db7752ba071a430ec77d0c3fccb03008f20a6b0cbd81f8ed8a703f0ee5c24ac4f6d2d5b4edf52b378b11cb30efd134e30c6575db02ddbaa762d546ddee956a9997ab9a744b3f94ff72a01177fbe3ede6db85c7070ce00c9e69d2f877670571090a5dee02f16d7ad0bcbaa60e875c2622036321c9a48f81e27cf7a3f61b5ad160126a26490d1d5feca1cb1ea915e19f824b45dcac3fdfb19e433aa2768550115eb3b3cc4643c295b7092e559abd50a2f717fb17e62da5551ebe760615edf430d6fb25139371da090f478bd600f4e32c7fe1d6302ab44ff2f31e4749aee41f7f6d87f5d6274be83fd319bc045bf38c349ced0db6ce66c6e8f2ba7a0e0bba78346f9208d6284c01ffdee4bd0ad9ac6f55063ad9064fb92e1b39c2479bf16d8d2e9d4edbd2f363c5142e40fcbbdff9dee57807059d355e60f63802727f0883ee09c433dc2bd3b1b27e3d12855963f6df7e7a1fc5cacb68cbcb9101989d7041bf138496bf86235c7b41bdb094d3f5e7fa0570a69d2c59b04f34c39e335b5f9c886b6117934c7beaa4f766f17db01cf00031213c0685e1c3aefee35424004a73250180ab5eed2893c9f8af800b710ca6e63775e03cf5e944eb2088e2d1545122e7fe7c3f6ffeaef039b3885a1e83fa1a8e0e5e27e835730f3bf2948c9518ba5df08432548c70fc9545369964c85ec84d9e061bb6e4d1d607d20d5dc0bcae2260ab9aa01c9f86e03e145912be8b2d8b18646dab1eed1a831276ae34ef317eaceb03cb7cf2c9c71ff341f8c0df5a20e0bf1cdce7f1f1139f7ead07a7b22abcc0951ec5ecfaa0f50995a90801e168071f8c219d5b8965f718ea5a7d71f2b83028ed446dc9bdf980fcf686a98a7da488f2cb635b0d89efe0f8f105d217bc72246822fba4b601315e2d2bab45de92f9ceb65201b1a69c5ab34088daa1e60364e55972f54e5daa7c006ddc732994202cf1a841ccaad27b7165d61062f26abaf2e3479eec7ee334a25c526a5946e7936eeba03f0c42692be04b29d9fc20df07ee775af981ea0b3739b9753add7e091801959e1200791ff82eed2e700d4f0151123448c5a71f04766ac431b55031725ce618269cd0a3ef83373f2d56c87e960ebd1e006191f8fbedf30430a26685663c766f9070c65f2d06f859751fb8396de5c47d1a58465eac2305dbe5d2a55424d530b7331d9e5960aca1cc5d3f8c03ad2e947e825ea9da3f937018a8587d667e00b5cd7c8a740618ff4f8e8c43584c111a986e1575d3858cd8b3090451f9fbf26069f10e1337a63d6b0102c03ad1da936c6e1b3621cba016a0cae63630117930a8349ba1ae1fb30ca610bcb959f60ef28f5f6e761a17b2fd0bc3d5d9a30d474f747e850fdf361ade5f74a6dae058007666585443eaf858c99d33d85488b53635506df929b40210679357967bfa39f3ac8594a5a77d561b2e0f347ffd8b7ea896913b7c1d5379d820f3fa3216683c611ffcadc001b9f5f7c161fad169d2c693970e559c87cd6e2b72c4aea58c03ca22b6c7b91d6b1a47654902adeabcd5cf6ac76b4c560c58d017f5d821b7abe21f78db8a705dd126e2e2e50f43be3cb4824284c13592c6b20d09064a28a132644732c0c37a59d6ca80f5e5668c2029e208fb043c81d4cf40b9297549f76f8730a37f24bf272ff0700a7e17d16ef2ae55983483cca59d66b0f255a1ed0ed4186acb21bf7041eb2db085561c42132801f093d705d4c4d2367f7286025761d2a304e499b703a7c599bd29bc2669d04cc2187e7c595037d015834cd41dacda32b55d8448b2c5979595f43930aab7200cae19f9d97cb5a89509866488da1f17b8d65b85699f943aa7f47660c946df04173367e12c5847f8cca58ba78427281fc2780a5e1fad2dc2bead183c834ce5f3cb9f40063d0cfae7727245646ee36eb347c77c9b7d65acfa9028d46e7790c4e0b565260d669d80f58a96ce0b77b22049e8ddfecb0fcd67ab3faf8aef979467e10904e706fa4ff3d6ce59415d15ea994a555fe44807f3f0b01f92c118348705da1f6daeef86c1bdf25d317d0f0a08fa5e217a9217a76080f1f8e9bf78d6aa64575c237baeea12c491bf9644ad833005a5727eccf57f419f609a93fffb99fe451fdc4d6a7cd81dfe468fd0678b06bcd4250aecdc92ee1762904522ce222ae850841f21b40bf5f0e14468466ba2783e1fc5b2c8fb548b23eeb31d2ad96b92f452bed4f818e8cb406eaecaa8c98c88d1bbc534e5f4b76dcd2352faf819f6f96df30140491a971de2a23467bb6fc3b77b590b2de2e468992c39fb5315548bd159c5d7310e9f49da122aaeeb2f7982755ec09b44b90ff4767a0c674455cddb467a8a898a3f460eb8baa826ba834004d0636105d2ae594435a2bb5084e061ae6ab5a397893b94ab0abccc3260d2d2e41cadff8c6743732c6b35e76ed67d54fbe37f256af1bd7b64e6d19d6df187c3b063839e4ae698d98d8ffba03477483461d287348656c2df11c93936aed88d819e0145291aae2df0e6f989ff2287742c0068817ad67d8e901f068931b3a052849b426aaf04653a548aadd81e2dede22afb3824500043680653a0651dcd9b812a2442e6a1fdfd000c70d5b84aa8fd66538709ae38f17026d6f41e31cb1423627a7a1e73f4f137dea6d813d72d40dcb7f47d2e5cc666f45a107e52c458ec308636689a397a873856664c0ddce8d207533c19b97f85b95d98e69258691a48b2a2ac8d37a02020b03863a80d365fb3faf59f5e8aee6bd733a1b5103cd55744c6f7627a1d74278ecbe05413cd47ad006f2842a9ba906e17af17b532d03726611b797006633132d1da86fe46091a8e2969301ec8de8d43e3f3337d2e9a65b812a8467d30a999a0945adeb35069b4f067a5b4f364e1f937b5d20bf4a49d91cd937e7b97e82b52acd0da959ba7a81a00ab520bdb9566a86cb0f5b9039589d9bd68cf44f4ccd8a2dd917ef76b530acfbc53586267c888ddbc6f0b6b1ef07387f0810afda43ba06b9ef4ded20643b9a242ee1426b7219a9983259315ca2c24dcf0e7c15a48c71cde13d0d4bb1380ca13074647d56b9e86af7dd2b8a6bb520108d3905814374e765c57ca3eac32bad383b5454106cbcef614b02c4ca4824a2d12b1c2c905760ed9b4d20120c472ae99e742eb9ec1ba4a8e8bea3653f784b9b39564158dfff163a6326de2b24ecc74cbf9b14841df10cde47815f8b3cc09f0bd23f238cfc1c205f5cf617608ba790f9b783cb0079c43b238e89e4598ffad3b64227f7404805edc9aada58bba2f641e60540e714063521fc7d78cc3dbef193db6c1017952db1e70116abc01641954fff0d697b8600a12b1571c9d8290d64754c648fe50e0be41a7bfc7a4f691a9c1ec55824ed610b6f3bce1c3827e20bef117c8edc0e3fa81a7674d22a3d9946d8fde412f8fa9476ea15afe70ed65ae0d3a7e18061f7ac1754178ca12cc6a8b8cde65c7791678a87ea80a635257c4fbf0ce2e5be48ffe43d827af2b184a734e3154d0cd91c32fa8547138b1a0b1f0a2b1144523c10e75a989f418742c86d8b7caeccbc02c94f411cfbd2e563e84caab71cb50570ed673bfc4ce4fbba72b492ba63bbc82c0fe8460ee24ab14379ae927437d3e5b410cb01dd1ed590bd836f8502dd48c990618274aa39586331cf1c457d7a00f0d59a0780b5a652628ec3f787110e603862ccc30d828750a1637c720c1404f24a44faeff7d079429bdf214c802f527f14ac0d36ebdf1bed1c9ae78b4aedbac82f73c4a10a530168b24670801bafe2cf770d78ac316d8a05c2f6c84a213376e3fd8a9efb1de313a8101910a4412e1e7576d630954928f1d4209854f40a8477d65bd4ac730291488acb127504b44fc4fbfc1a7654acefc6a4f2066e66cfd3b1684512a0dba98e8fc99d73c357e5bbf6863b3ac156807a9aff99b34463c392e282a01bcec42d0344c9b0551b8c1edb538b97e83d26001165da7d8d141e6d3494ff6d009d50725dd54133c6c25058a2b611d576692ee2b63c0771e9f0400c944d7459a061858a5ed477c59a1b12b8d4e6d2378c711c0ab6f538aaea99dfc682a849f27b553b5ca139547a359b9c17878056c1acb62e6d09a72a9c7e83c73ddac93f72d7718d83cd441dc43c92379fd8fec9f369db74d20d0c8c17831a0fdb4163e1ab237c0d1c2eb4c259ad24e8740c1870b5ac20d1df7342b104bb36e99184eff5c787348a704884a03d3b789114922a5eb15c13b042d194df13440aee0e5017c9ee8f7a33f05d41da6f81a2dc3fb9faabba0d13b30983b12be0b6a78b89fb2eb31cb6317e443829c16c1ba3c26d7936ec84de4878b9b0e8f27daf15037170e838c624e8a3f836f9e06b76c44b8151159c5d50dc06e323e741d0665b544ec1e763fe8c17866b5f89086415f760630c666340b8b1a92c41a813177f96fa602f0c540e667bd745c476018c4cf56daa9a360908816d8fa54b10416436c3ac5123ef6455ddd0da899427173e26d9dc5609ac944d1421384f568ad67be10ef6d07340fe644d00236c24c68a69b01263ef32e63aa3046c09fce533dde600c037eca4346aeee56065475660ac02c2ecf46518b3cbdf41b1ad27e27bb4129cb1cf5a052d3e61c7a7d668455f90d2a483cc95c644ea1f55d5fa75009da88275776a402fddd46eb3da3611e8cd0faa1d89d3d254d97e9485119ec603ad5539cbf0c817dde61e60d1aeedb4990a878e885b105c74d261b986b7c82377c26b2ed5b2207bc3876c431a742fb0a0c72c832af04644c53c6bdf2c90b04dc7ed58b22e79c6ebd25a5039905d5ca2fe4fcda193b2a93b48813e70c50b116fe6099d8a444e77371aa6309db97a2a2bb55fb050379d3d5289bc63fc020d2080fd8af56a36b057b8bb09a28e6b3cde1470df4f392cbdc8afe63fb2c948f80e3b7f7f435cf0f6596fc706dd89288ac714e0b7ef75eef9642f1ac96d4032aac6a9d6a3f9f0eac5bd220d37b0691fb3be586cfdc1020d762f47d9a718b291e0345353c93d4da9b51a822567ca88c3e33c0acde75d9b546cf4d67515eb4f2b0b1654f77ae96abeac24bff92cb9f6b6747f13623dbab70a9a659bbed322a39c9cdce93446f1ab49b7537bf23b5b5b5613e0bad31507f3b3168b442c607fb0dbe7cf5d3710be9bc6a12c054e4c49c01a3145a85fd7af4bfb6dc633b019abe881f2ab0411569363a68749b8e3acfba475b85f003b88c1cb5b6e044dd29dd034f15f75cfc8b04638e620bd66f72423700892040c656f2246185d4c5d04638d3b017309df39c670a47ca8941c8e3339f19cf43abe160bacbf8d173ec4e9554bc3ec145fa4b4871660a478c55e926c9096a993bb4a660c414a621b3d8565758e925d2d0ab574baedf7756f117bd6492089cd058601f9f2346769f1e123ec3880a9ed562d39cf36212ab53ddd478dd5e4be0aa7a4af6da9a1e90c9760f7976c2346e3569a1c0aa17711b66400b6a4208bad751693b87c3b7929ec0c058433f4b4a91780c7377239214f5a07cbb5642c1a792491780d97162af43d5927506771e6013680d8153fb4c93e7adad0fe3a79b807641e3694dd000e29078734ffe50a6bb06bff25cdeb64290c420b5b76a6ae72110a4caeabde753a2efc3ad32173c0bf60b84a935b5def787aed08d2f4ec75bcaec4b1025860d1c7367ee08271daf49764a62f12f6686eb01881b94e83a22f5826957f62582ed14e4d19c007cef8e312186b5d1bd966f59c8a65a56adffc526d1a06028d28c5dbe291ca0a9de084725e5f262ee3dd615b4b0a797a5d813750a325e7abc571cfa84e72d7e96ec198aa28ee9efc3d01383c7cc7aee117b4394eed94bc3d1f57abd2381e2987ac0189f0baa0e23a631846839bdaddb697e4ae5e79dff770c49a9636223fa8dbe8b2703bd730604af7a437520781fc9ecf3f2c77890ac9d3709fa12b99858d5785e38092ba965122d8e071a4750b2bc2e253b08c902304780f8040acfd01a2afe0f4000a4eebc4da7e838a158f255021a29f855a738f5b43ca7ece0342e8a4259bd2431a2265bb46970e16f6b72e37cb4534b6e13c8c136cd54631b8666075bb7a6b7e7f834800eb380c6dd030198a6a442ed974697271fc06011d1468d098b93c0f2327f6a030569367a83f9824e292a7bb3e3d5baa53bc408c3b70583464dc8023704b4dd3650be1b9201008cbfc50f94d958d5d2641c0ee6a1eb30dbd035f69add83b64025aecd8158051a3c5c3b1163e1b40b89333ee14c27ad4c10e8db4e1eb5844e5a644ac6daee1a876e627d7163a6e941b59ff6260a429bf01cdff912f1f9a1b56ce89cad8905746e3eb73aaa33fabdba582e49cff51e1c690c6203c246b02ada9baa0d58f2fdb367fa710b982ac0d146af92dc85a367e241ada40cf593c99c989b285de88b810a44b0a0e45fc59da34ec0a808a2634e618a29e715f5345539d55edeaf7db4c754693d29462201b9e3950858d7fc4394840ff04fe63a75def7fa1f464817b223e0e67a1bd483cb9006649ae4581b509c06e378072d98bc9c3b5a7c01071878a01048706085320b1e9ee6836137bee51d018105a7da87384407619a52c806a66e5618bc0097560c0dfb7adbe1091ee4eddbc6b61d2ce06650540c299f4d46f667d5f83098b9c022505a57059421ced88a485fc03a7826823dc5300a7a78bcf37d069478384472cac0c02cd67c38f87dc160078091913e08f5abbc7fa55b648a3b2643530cdedcb9d05da5ec6d365d5e0483a044065bf1810b5ef89ba25dc6971ec41e343e23bed627e3292b1199b46b3f98c9516923c338804e5a525e828b684924ead05b030a2e26fb5600ff486068056c654b3b0f70d8b6bff66c0ee32f7503342aa0a5cd2b7f5fcc81c4a3f46a9e2dd40495709ddab81478a5f001206b28cfacb49195be0f4140025e0a7b6375d4ba245f9a9a80c53f97d1070e50b376a1413c4add6c649c4e0bbaa4aca39ec930e482ff1ea36a0757cc6c20673bb352944a1a27696a6da2726e94134f36720473092cb6f0324cce185b324ac229de4d2ab14a70a13739a1c890bdf6ba1c7e35b5229449330722e35c299366d43af6d40e566f9a7fea1cc9892128dff49806755e06d93a26f1a988ea5cb7167933d0c7e96a116a47bb21af17399d5c51b5cbb4418b60ca89d776af3249d20df60f38f43af381c12a30e323636a2429359aee60a16161983e76a22cbb5825d1687cbe64add3f817cbfd01e1504b4ac3c79d8aba682bb63acfb4b5f4cb627b74a7c89bb7c07e38f8c61ae2db674f710f3d1a1356e2a3aa4089398e86611cef0117821cbd38488a308da53193173de6c601d38b891b825ed244fef6c6b1f3a1dfd86e4c00109ba0cc9d3482813188f657da66e85f45549d4188fb919e86f89fee77eba431220ae6e9360a28471aea75dd9da2892bddff49636f9481347afcc12d69a15fe20c5e95e6b017512705181f1451098a77c07ea85877b85fa6fb4e06af6af660ff859ebeea6280d147613d21bdbe91f1d34d2c6b06f2bd469451d60522ec448f18d4bd8ab700e621488398163960255bfe5f561c101d1556697962111b482298ea895f9d7be0fb84fe5fa2b3709195ec99db1482cb3caaf94dc4f5881dda33134a70400fda97e3cd5a453559cb3f207c50b91162bd3903ef4a333cdeaa752801f347f090d4434c1b97a75fae63074ea4b1e5cd93e599138855c899aa6ceac918662bb584d8cf06211cec2b927b2918c2827ce6653ecc6d81b5f49ee1c753858c2c8e382810a58504603d08c4b88b78c23ce5ecb98d740a5ca5180a480224d1baf97b2bfeebeff0b2adce55446955ce0b1b9073e84753da60556901ce6cd6ffbca803ad585a42c3532c1b494a2c1f8b6adac0627e6eb1b7823f98106486da9cb96608bf9f2709eb88cd38d1210a955006ca2c3d83bbd833a85ccf5f0221f2f9afbf8c907044f213da16122190059c4a7ec8df7d26898047895154b125ac7eb430ceb58bcff24b58eb1431bf000305720c323e6f97887966a04556fe73b5e3b8d05ceead3dc8c712bc387083c96754210fd50a2820d686d62a4df6d29d1de784ac040d84bfe48cce80f0c3466b01fa177dc7b8efaebe4e569bebf780cfcaa66f254c15f23e265d630c76b5cae029de0b9c963a8e01d2800924837b989b32a5245bf31e2ca92de55894c4982e30d5188082baad63235a7cf573642c78476bfaa08d3703d7a17251b123b4dd10595e20f09b5bde5429791bd49ef044e7f1b28a3badfa987ff5e94eb2be9ad6b783a7ebabde0477a5169561c5930e1b375616d122eb3be7188c93232cb9faf4158e59be2122552b05a547fd1e9fbbee673ce39ebe979a635038ee22fad68e3e8003d247d0d217349bbe45e0c828d04b9fe392be99da14d0d773ecf3a55e7dc6591fe8d953eb23bd456b5d01a5f8177f7bf80dfa330d773cf13ec9f8f9fec9c31d66a3e7963fbe7717f4f8093d290ebdd744cfa9456ff44b6ac7fc64952bd096efbedecfb74d53a7f79025bfd0d577fae6e35a7cd2de7b8fb5e707b2c6c49f53d037989fa7b3978f225f9f6f1c743d279e37d43075e14f84defbec6d7d6c3b9fc41bdf0bfa9e57d495c4d82f1f7bd04c65cc35f231dd5b276051ef9bd84dd2f33c57c0f133f28d128225e91b8b9cc8a7fbaecbf8293e1cf2123ec93400002024b59e4d071f319a9ea6cb4cc59b200e2bfa2345177eb845f058747b106d275c4a34ff2714a4ac79da48f00bf1cb78bb56909ca2e6b6b57c9362a19f013fdf840feadbe3d3410993cb0429405f1f7b312c9ab256c1a2ac3d5d380a296122f450b7ebbe10f8500860bf7db4bfb50bbff0922899484cbd414fd35806b3e13416e5ae57ce4c04dc54d0830791e0e049335a3a9e4146de2cc13187a03b983ed4e8b79cc1a131026d0ebd6a8fe551ff694e680c4153fd17a83c58bd3f2e60c96a1563ce86bae7d23f1eb74dfd7605b0146faaf3adf8bc689773e167018e3398726209e210f70038cfe426977a503bf4edc9dff8a5e638cc737da1fb9ea583c5d3f80ffd61177094d2d99d3bd4443b6b70779477b081971bf194913725f3940819dd02127a93a9c721f63adcfb037cd08be1137d575aabae3f91dbd937f2fcaf05f29db61899d47e2dfdfdec3f5802cc2b03aa4414c59a3c827a6bf5aa056fc51509613df4e4c2196b34b41c45db71f2f745ac5c998f8a7deb5ceb2eba2c1eee9ead180048df1542f8df08c3e2ed535cccbe20455c167c44f19ca9a4f37af397abed1e63a43468d0150571995d0ec208f46dadd92cc023487bb1b4cecf216d3660ba8e7391bc236d9825e8e07c25d2c41a1f10393c26cd0969303738e4b54e89101750354eb982e09251756353550eaca2e63eb2c1c69b5506108effe1b062e51a30d68d276d08c3b806ea66e3a11bb94b060f80aab2b06a3c319f79483606766ea936aa11ac4837ee9b349bc19129bb8f0de9d7c6cfba62189f6a6c4b8ba8fe28c6165b34d0c456fea1e8a3c7d60c7647b34f0e808ab67240031fd81c8725c125982191eee72f178703ca31cc8911be7de3e05e7e00cac3eb6e837337a4787947ab810d56afe8f1af14a3647a517b7c6e3341495011b637c6cd91c1da47214517e6a70ac3af547512d1a31af805c950ab60c663b5681721df8447f5054baaa65b841228544a42ae41ea382c98de95ac6ac8d89b6aaf40b86cda5f041b1522232d3048b645c1372dc878b8e2a14185f7b48c49ecc59cf9454cf64b410663a59911f056b402d17d2f36d4a82e723bbcbac5806d62c792952482e32cbe4e8385871fdfc8ccd452bab7d8556e81df77ae34f0cf84fc7b553ea4c54b61a55705c2e2fd3d868bac900d97a502278c8ac301330e4fc8b589097e0a9d96237afe58b27ac6d3dc32017471b058ad0c1929146d1f68126c3124d40cd3b8ce89fe4a826b6dfa671e669d491f33bc1e6bb4e13481d67a8793e1f54a50e2ca0dae1356fd446236792d4ca131af19ad30fc62ee3e8d7bc6f410ee1cc26a4c1d73cedd9d608fd189a082c8645026244c998da88ba496269c159ecaad3880aa5e9cacdcc83a5e7c7109904645422e81bf47f03b8f6bc510ebddd9c8d1a905b4d864258d44617bf4598851534395f3654e9f2abff9055c6bf2bc8f6a098d459d030fdaf25e95fe6ef12b62554a2766433508378154a1f159802414d4801a6ab48123a88b1b9f0adbd9508c282835264371303e86514c1c3445b9a241272e7d2322695ac9759a6980962127045b3626ca59d4b890930f4ff15be4e1fcac590be4240e757d6893b284d73065a13776fd288843a0198dfddc34091ff4ed733d6d01b89db5d44ca61a81c06b7788bd745e195d02c2d35d5183bc4a4e715d2e9bf5c1888935e22eced9f7f9e176f01349771adda6be0acbf68435f760be957521fcec2ee9bd3703e366e03f21a3072a96d033a81eeee238f0546b742d3dd7be9d95ed0db79216a9864ea59c3b3076aede77e30a8b3e71a316d0d8e5d996d93773def1f23868cfc88286c723aaab41e9920c94888008229a576abd018a00feeee37853e4a3700c1fd21171f7c2d227977ee01a0cde8d9866b77b3399f5bcb758e6fc620bcb9ef35644c66764a2fcb9a80a1e06d2de29fecb081dcb9815dd0f4a59901b9df463103bef6866398c31604f727d843b19575178d8dfdf2d38d6aa7be7d881fd617132d687f975e1121b357cd9452465a6d2c93eb18b57421e0b14513baf8466420c9b38a85bf424dfa4e582ddc1dcc3d053eb54792d1c635d708147e4b50710b5eff6e0b28d4cd18a71adb0b386a73fbc5f9d4273f5d3d1e56503a0d60a7adbd003d9eecf0871a45776aa00f745e9aba05c3ee95bec6946c3f605630f8e5042de83e0be9c7e538d22dd184baf71da5264e08e553491a9489ea7d7f23dea95b1275d5c4418a01f923ea2a89fc6b52568a580f295fda99857cce4ee5caefa5753ca1710ebd4ae06cd2095c16b2bceafa17ca04313710f2f433cc1bf1059b8a52c0f5b1b4881038da545012e7ea469f066bbe465994bf525f88b37335669ea782b1e05a9b92fdbe4080e710aa226a91df45ba69020db5096169b32f4c469d4c0f12654f5be93ed7c7a6c96e585e2b897855b20e093b28bf4a079bdbb9e66e91ac4ae811300c9a0f3e521efe42a338c8703cd76982034eb189acbc62361af7405c3f61e36fc07962b3b3833d3046ed77a4582b8a51a848bc6572e68cfdb9309955e7f42de508692872c4926b8e69a7187ab71062b89079cc7e74b0bc0e8bde1e30deeb70da141db6f31772488ead129a706424ffbc4e68f8c2d36b5e8b9ae2b31077735fa67540e405e08b46433d7d451b1436b107400600b958c280f64df11bfdda356c9a3bf6147706657468fb8beaf06904ec9951431a4b9af90b89a20f53a903ef547f01d89e420f1ca7e7c2235329c75a4190167afa4c7a8e39069d2983bd6be9eb223643337ae0aac186aa77f5e7cd717a98e994c4e269850ec9ed070f1df74ec7ffd53fa254be061afa26903cfcd5fb1d2bda3886ffe7f03cc5dbf58a067313a5d843e01056a640f8547d67e8f092247991eadaa7dfeb64a12d5d06a42708e5c7f87e3a6cd6c33980c3a8bfd03814fd2ccac3c2e0fc4e3c04d7ec7dca8c88be153b5eb0b4e559a212bf49e206538423eef4ae41f0f6b3182c0a58c2c1b7de41fb9da84b17f25732a34df14b805a242ca0917983c1e364dec1274dd4f2cd6e132a0ebb5972e9530e490a6be7d3deb16ef07f04df5bbaf79c0908fcb9664392540bea87d7e73d3c8ccc2e1cd577ab68eb7f293cd8c302968b50444b1ff0ee97fd8845e58b184fb4721f6ef46b121d2db06ebdb4bbec5447a8682fdb22f6df2094001889313d9fa7e4090f2338db0efdff06f510b9d291408878882c6f57431987cc5a931430e6f24942e1a60fa6f9dc2ba0c1c40a8f15ec56724a6ef955dfb9252077a19661e41380c6bb4ef435094b8e9314862a2a251525ad82e6002c48544d01828ba32496a3edf791b7b225e6ae16746df1a98e596d607c720ed1e1c78732b43e10aad657965cc8c502edc3b4ce932f093af16db9a588a8c97342848f27adbf6492ae6b4919ab617c22191071ad022f4abdfd361e9b843cd95207c166539f68831e33f202c343d86ff0e3930615ba522b73d89ed29b4c6ae20764221f519419a54b453c4d1276500e94d0117c5997739d01ade73b6f1b6225c82481d94a0880bee5d2a9118d14295abea10d0a7ae4a760e48b74c1b314083a29522748258d7dfdc350eed5fd96b70f6fee62de6ecf8ca6b69c879b65a52bf11a0b4e92389c612c0ac25fa16e53081f622af84f2942208ad1edaf6799b7e4fd73e255fdef41264261dfc6f0cd1484e7e5999756208bd905ff3ba8f55fbba1571b45021ff178e44ee6439ed601feb37cba3f4d7bf22b3dd25037fd8fa26484004d3aba2883c6ad00b82060119e815c61342a04fa15a43cf3c748dfa3aa587f175105c75c20403291c8e1e75f05eb291a38d0de6921c93af5f0542e6e2c6fd09e71b7a86ac8920d5d4e2eae19dba90c7b0c466f34dbfe3f12841e104bc9ea159626a0b5ffca717bf0cca474d536868c8d7cb22725ab186900ac40589691cbcc22dc96e1f8154220d3dcb186a244b14934d49b10885773a9b3ebd7396a05f5c2bca700bb5649e7a3b3b97a0cb5cd77b5b0311cdac2a20346975a8c4add1dba2ea0b7a6b8a40b3f5120f5ea159eb04786efde4d65118fc086f4a5457bd0d0576f25dc047cebd70e51cf0eae4e96ce38c2bb0c931f7f460cd9642e57275e77e4366368627677ab19c30fe671a019049f705f93f50d77f322113c9c3112336167dcbc89ebbe9d1262a8de74ee34250a586e1dcd53d29742ce3e6b014b4372a953731f3168505354bd01e21e65a25356ba495de44e0507a784a8fa07b23524ae69a9da5c254f584a37db1f62b015dce38dd851f78fbb84d0c3d574eb981c740bd5147b64ccd06e1058ed8bdbbdde03fa58700a6b0068e8b41e5e873a9eda7ab3079dcec000ee19baf98ae52d19c9d412315a77531518d5a9c6978e36b6128788860671838717d7a8b91b0b3b1ee563b26f88518acaa9cbd1e71ec55563bf7744d46d7c302c78278b736998d93c25c93f55a2e0ea32f280b82a59a2b9cc161c65a507822012fffb6c3203072ba727081e54f1bbb6be3ad2e3e7ad5c4a5f3f0cdf5e103a10a74e187e86381c8a344ad6d8dc357c8c60de518e2150dd8610d19dca38461bca289d84b5e01b8443e77ba2a966f26f7c0aedfbc1e2a60c84dde040db9cd9af27c76c9c46615e912d6f097cdd4ae016031578668a388b3c4c808c9d8737a03c6a5fcb3bcecc886baf314be36dc049bd37d85c5f94e75f340b4621094f490e04ca55de39be99944767df5d262ed0899f3a137717ae986dba5bbeb2fe115d2f1b614e1d852ec915de1af4a731f5c0e37ec7a7987a2718798278df804356d85c0064ba127ef49b4347c34913ef0268d7cd8a7ce9ad7f98eb2b1235ec8959b9b0b6db6c69a79a1980c5607f824da17510b1d5a639242c597a4ea6149761b89d622a61c766412d806785f4eb27c8ca408317019decaba9111f1bd493231f6552a04b1acb774b3e5bb375f9342cdb50013817bcb3261fe7a09f9b6bc67b81de49238f5dbf7f65aa6b16d43539ed8353390d7a08d82df154e703ae40a48f222f64fcaabe8d85b80e0233efdedf2a3ab50dfdf2ff88f6415965e8bc941d7a332238f46f0640a681015b17b0debca49ff114c6561dd9279a6b0bf9295a40e24ddc6c8b91bc6c5fab96347318e6fc0159b9b0725da829e24d37c0f19398be8344838d06635fe9962fd5a38e713636bb204c0fc628addf3b84f5459478e513fd3f8205ed439a288526c95bf850cc166d1039688d10a3ed14fe0923e85192dddcd6fc131c31c058c10f4c3bcbdbc27651bd3f570da1faffa4399d4a501114744376100c2f5723784d44d46e2edacb9f0bbda283d64858050fcba7323b776896b118b20dc07ad610491d29410a421540dac6f2227ad232ee132a2f3ccfada0d25d0eb3cbef4c6ef7b68b357c632164bab0e584c89ebdb7570d5e223ed6e1531da2ac84f9c415539a487d0062e97abf7e44d8874675d327616e55954edc4e96eb2ae3ae1b0d37453dbf0c868d5d5c1b08b5e685a9a00467ad53bb94d2bf05159a4527ee922fde35553c74ae277d11dac9f9f2adaf18316231cd394db5c34c236adfffddbe67ad53f93e2953da2679f45d8dd2ef6aed170559b48a650d1ae683295f298dad7657a87ae49f7a420531d2d65664de6248c2cfc93bee46ca884e1c2e18d299f1c679729d328dbe2e554bcbaa48f4c01c7d79adb1636986604421450b0984397a4c252f57f1cab05ff38cd5cb8e4eae7cfc919c5dc74013f4b6b32227d91b708f81ec5427b6df1bf45375247e233e95d35e56b56388a771adc9ee2057a2998f69b6768e8b6c7cbe848c09d0a32a450737de423a1e298e05ccd1ebc9ac3114a2d708e48a21066d737012ac4312c9d5948f375cc996f67ba0ff9c7163b6296d45a938a38944f5675c4528feae9bb66734c41ebf336770c121c0529a410a08d03c8bb05b5f1841570ac56f3d15960ce7e18b82736417348c741af45bf00117d3f61d934f5a0b2ba065bf70bcf701a2379f5b4ab0911d9f622ae615f36bb85889aa6a9579df08670cf32642260276765b1efa3161e49e80b4d7c72619f9d65063a7a29b7ad9af18826c49d9bdd108401006b19f8fc1df20be2be1de6b1d481b68c8eebd7dc00b9740d7b110c1b9c282c1a4113d223991bcf9f2d1630c6141681f8d79e056e7b328a546c8da54477772879f705597c20857d6ef094996a20b873fa837fb15a80081ff11c7063f58f2032429498cfa1dcf664d006084170dad90eaaaaf1d908bb51b94935d87e3f4c1a0770988459fee53331d441e77430a19f7528591c5eb0a4ae39d7b37dbd87abfa402a4463c1f6dff8f3b0fbcaecd1ea153eff8f1727db6227fc374f68fbf2889de93844a1c54ae09420c6e64e453ffc80149c3d99ba98013fd8890d521b60861ddf5c8d7ef7f12191925bfaa5aa5cb7bbf145c1593349dd26c95fc5ce2c78771570a2ba9c05260a3f8db0dccf32220a47061231d6312a19457c5dc552b31090e156db4b987c6b0ec59cd6f2aa09f8be72edf59ee4ee87d481f092d7a20d9b06f309f98574ad1aab78a080b0b86e4b88a95a0b0de65b32d80c1565ba415960b1dfeb6c8a9ef01cce47ad7d503d69f56938a81b4577a1080646d5bf05a95f6fe80b9631117dba983a2099829bc7d3e8bebaf41e533ce76f465d327a8674302577a6c6c665114d8032c2cf0aa687b19911c8c3aa3bf29928a3c16fc80896ea15a9d188410c9834ba7d86a75621a0d13da8a2c84a30b1a881244e3fb249f0ee5460637617c018b4cd482198fe3f20c5f9d2ed059c03537ff118d02e9c1f6053361a506ce348a775eb55f4b8fff79112b4c9763a58fba07645fd942f4e31f4c50cd235f08fd05cbd6b25191f569272a121ceb70dd0f1822178fcf5500edc80a320dba4ca885e5df37c51a400b05951804fe61117c22119d1c3656e01d45b62a36c1397c55db796f8ae37fda39c18dddf9a37d411755cf0013b6c8ab0fe8e784f00ccf8620d4a1974d4567d3bccf54bd6687c344583d1ad7cb541b222959e3f7023c509e1bb64f1a688544156f5e3181828cd44661f07d472c39a049962dc240402a0270ba4eab9e39c89ded66dd4afd090a4a5feb4c5c3fccf460c86b773c194880e598c0dd6c73f0f81a6776faa6b0204c1fad554401369b70dec0a9e24036865e51e5ac3eb3d9d5b24558e5e46511dffd218aecab5dcc0cead763d5fd65e430cf1a37d4f4ee26de9d4eb723e60ed28ccf549b8a5f3187b9f3ea5710c2abc5679667a291bfb36aa52bc526d127ff641d767b3915476cdb0554d12ec1d2ba792c287ee53e2515c099d4f699e0755293a3baa339f2c67779ce26371ac91d58cbd110f42d79965f92b7fd5497add91e601e344e956604a3f4788b2453fabd97c05f488e0d50676e6b10be7f8e75c650df159300a31a4dadcf20f1204ae00867c25d4de1ae5e5b788413bc5963f09d8f7380971390e212f5d6c81a8da9bb15ba037dd4366606852c3b9622d573389adc304a6b85b60e91e565ad38f0c359a100a5a584393d3d57b9b4e2d2c940e8ac478412278797997e9709d3ab3928b0c906b9e69cb9262080853e1c8d0a856f9d3d571f9e48908e8a930a579a8c52314eb82e8d5e1e7662a4aefccb7c447328226aff9f4ca67e594ccbe4b38e0a6fc9c24459067b3cd839081e538b305723f4ebd37e38e73e571c9400bf9d1c73ae9101ed95a6c112ce330ad16e4a1933e510784684b31f86da0c98e335f1faea06964f9fdc8f109f14e89be56763c14b2833892d15bc97a44355adadcf0a624b73c69ff2a523d00b4caed5a22b198c3020d338ff7b5b079d227c074c7e3557ce0467b692aabd9112a6e4d2b2c8890f0e697838d629a6190a0f24dc74f4bf1d7437a2f10a6ed711437a79a763e4cdd3cba2fa8eb28acc2527b9c78ff9acb08e1072418ca9e1dfffda99bec6e0bdbdc8fd016edeefde8db653ebc30178dc5f8ceade90e1c091c5cb92e059bf22664775275c1ad81fe75e70f675fa528e1cb067f872bb0952add0ccaf385395583885c71139cbfb4b730280913baf92d706aa28067ff7b4cd3c3ea2e75dc42a6c9b6d1d0ea02cebb16361a8dbcfe9ebd73f901fccf040adf33c25520d65d491be1f5d7aef10f6581056dc186a4128d9a7d5b4f7b4ec5464bdaa95c7815ba2deb154e9093946a6cb502e0127fe986cc6b4fdfe86ad548fe595966f2aec2c47caf6ba7ae44f6b746ba0959da422b7b73cb8b0b4f0bc70c51272a4949a3f80aa5392037142ae42b08f7e9f455f395e94f3f03b74e534aede5cbea9ca44f29955452ddb9c964a25a13ea934a0d884a299d3399dea4692217e91395a2ce91fa92a252fc222464914751c75dd1b5a9fce5abce8776fc28df399977a8e2ab28857c954df11596e2ed50d70bdeeab600ee50282c80ae023fc15b99e08ebb095e0f77b9145f017593d4e49534a3d7e40f835b5e7de68fafb0186fc78fc078abfbf1e51770077201aeb4dff12bbc95e9e34b25b81395e00e6985d7235ae1688c236c9d546a798648537e92906a6053a6d1d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d05c147551173d72a74773a373a373a373a373a373a373a373a373a373a373a373a373a373a373a373a373a373a373a373a373a373a373a373a373a373a373a373a374a3d38fa60876fc79c4d18e6fca520b8f8b8ff3eff89afc62c79762fcc09d077774328cad24bb6085d74366e1e144b823bf4028db0b3bbe520d096a6a6c3061c3460c4bc410430da01a356894a0a1a191040d1a3390983143f5a352cd1c3133233302191919229021232606660c189854185229941828d4f665db4e60389d4c61984c180c8cb5254dbb5fb837fb22cbac17acad5e6ac5ba8061940b94ce2dec29a5d4c2eb1163ccc2ebe1ee58783de00fcda4a1b0a6599ba2b845b118dc9a3a7299d1dc1575a04ff4894ace196173201f2fc2d649156c7e84f847a28efd9814234fd4b15a2ac59baa958a52b04d146cf2670c1a944a5ce4c78f01b7fc6b704b7a7c4c89fe8cfe9e4352d7b68a3d2aed08dd9deae71c7d59e534c146b54a6fcec1230fa7089b4f39b4df0d26328c884c643442c5cb9c73ce095d62d0e7933edde7f439e79c73ce391f36b1515ab7397d7ead6ffe9c73ce39e974edb9730edda5ec629b0082920bb647eff3d594af6916da9e20cee3f0e12cf6d820d6da5ab57dfc36de12ca9759dea8e96bff3e0c1fcb5deec916f0f6b50fb34cbfff61bff2448bf1c48a65b899647006e13e1b9d1b31fc036318d5608c50ca5c717c35cbb28ce21fda6b4fb59b7f9278d67d1a0e23845aca85af4415618c576bf1a27b47d967b895d58b4d7cc36739becd1e730d3c9c938f651b9ccbd962838f278455014cb6bfa6f5c0209e69d9bf8771363dcc9c73d16b3817a3fc9eb73dfb37e9ce664b1d31635821841056582b849826fe83b807e21eed637e5bd352ee6b5fab9e51bc1ccdb778490f290503f9ee65c32124e741fc5d4ab813777c97af879c7bbe4f72f7e8da11734d97a579bae0ae33686eac38eb4fa32d40793feacf2db8a413aa23e3a37432e79c73ce396974f4a7cbb9a893645fe7633848f655573d839c8b3fe977ee7306f96a4e2717e31686decd4f923d0d0a728e3e9d4f27d5158a2dfbeda78b6edbd3ed793ccb343fb7dc3548fd4d7710ee5b357c1cdddbae7f210e12f7f6d78588637cd9f5a510718c3196d40d1f0e7d19b59a39e0bbfe7d55bf8743b574754ca493a0f9dd7caa839cd349e667b2cb5eba32e992aea8135df567746199b6afa43a483a19a2076e89cdbac4270b368899629cc35edb1896510cc35e9391b32c7bcd4a91f1769341b187c12d4ccfb0599ba5c890218320b4a3cb5752647cfce8240661693fa32028ed4eba60340c7b0ceba62ba599708f49462661300e736358889cbbd68905992fe79c271c44f6c8c7fe426d4693d8d70cfb194de64edb99e65c965d95265df283e25f2969a412d5c6249e317b48a5135fd160ffd2a5a71396c985fd1582e6ac39975dfa90e24a1fdb8ad2554f3d37ea279e534fd4cf2c1f02c11d6b53735a2d3578714fccd77f30ff64208437704bd60cb7647ecb18421a70060d0d1a1a8f42e94e8986d210b53d7e0a21fe8fc91dea339cc26f69ead7392bc401b76dc35abea59153afa21f1323374c43d4c36d460a8592337407231e82a2b4456d955bea65ea6bea9b54fc0eadc5a9b9c1c86c0fb747e5b7336e6d305a3a072337cc8c8621965ad65e6a52d77933ede11e49a5ee2c1eb2bd9c91f5537276be639ea66a4c0cfd6e0926a19438d88f791e4ffdbd9af64f0392dbb6750fb97b56dc23f3f5797c255f9352bed6a46a1fce6931f5a89cfaf91ad0ac5f67501635e35133348fa3ea867a38e6791c5567fcf6d27554d6feb432460b99d2a23ef534c87c3964be7c0d08eec89732f53215f7d498c7f090d4a4e9999f64d31d9c7888b6e7d3a464d4d4a4916ad12bf3b4d65afb31292da10b05f3aa2ce367327d1919d4f378955e5f563ddf7ea7444b6921566b34d9a35ebecc43ab53ffba29234bbfb131557e8a090db7689665b8e7dc2feb9610e6b34c2fc19660dd126ccf87401bf551befc1a03f331f36386c07c7d18547dd4a772c764a3b0257bfa6c2b65f6b40707c9b63a6b8ceee446bdcd44ec09a33526e00e148f0f5fa15ebb5a131ee734ad6df8e7c46ad69cb0698fafd4b29c42054694d2f56ea2ccd9325f48efda78cc9c1a5daae89a2ee99252da504929a518a55677f94d8cd23a25955352576af274812526212521c5f9cfa6db7694ce1961f38774d27f72734ed237e1fb8473fa43a9e39194aa0d618416b832ec16bb45165534bf41dae4436afdd57f1a53482ba41042e86e02ec51b0bddcc1a4188c12db0264c9371f7dd8c35e7d533fe9121f7938d1e30ceedbf7f46f3a5e00ecf1c71e5230369a20fed8fb3ffaf3ffe54efee03e1d5b0da2ec6754032739fb1905e195d4d5b92dd59de53aae46a8bb2dc69bdf5cd4812cf99bca68cbbf795b065080a77a46cf39c7fed5a84324c61a6bacbee95f22b56e9b148c8b3a44de8dfc5ab74d059bd834df6e0459b5cd572fc9716bab4e00d714534a299d26786e04641263fdc293c902f9dd128f790f5b5447fa9aafb443edd108c9a4d8cfe085b875a396d1b7ffe07361693f232e28a97c25c5fefc1a56a394d22e530cf764126b23542c2ad83fd5f60ce33085cc0d85cc5d2b74f78983c0f777c71aacfbd137e979297d2f348918d319fe841a9dd5085e4f1066b8a51c723fd34b7cc359ab5ee23bfbab93643f9554596bfd59ef09eeebb089740d0fb9bb5edc837dad4d5c433db3cc5e7b1008ee6415bafc99803bdafb12dfa721f1a43b9f5aabaf4413e20f7507278df6f26fad0f87d48740fa4278718f3fd49954a26d976f714ffd24a75a5dce2b5906a7869fd13765fc36dfc7f283b0d6aaeb6b42340de14f4bed4bdc937d120c6a3b63e241261cb7aea66519ccb409b1ecb444fb9be1eeb97fdf2918fefe57d76a99804cc0269e99c0d313b0e8653d6fcf3c1cfa4c98b1e1669e082ccbb22ccb52daa1b0bda22b4945457c459376f6f47ddca01aaaf11994eb834b881edfd967dfc1a19be5f9c4b66477f595683b7b228a803e0f710bfb0c671955c439d3677907e74c99bec139d3d32fea5f99650f87ae5d82dde7ae7eced9c7aef45596b1af36cb32ccd62ccbb2ecdea7f1e11cfdb783af34aaede01cf5c1571d9cb2e9532ddbf43cf46956ed4f274cf4b753d69ca3ef4ed84c0fa1c0285067534c0586a6bb0dbb1a53bd1b8ae56014c32cc51e8f8d15e5d4ba512eeaf0d83cfa188659ecafc56cc69aa6d98c5fcb40d8bf42586badceb256ebfdccda5bdf7e56df39ccc639cce3c322cd4d45d0c2cb3eed67a48514f643dd379b6c8fdefb3477ec3a1632638cee4ff3e37d7c04ecf83227799a26c80176fc03d00489638c01bb58c10bf2134cf7e91e638cdbf423b6a95f8331cea9242ec528837694414c26ac4fc0f7b21d6acfc697a094c86b463f024412124a2916e9a45a32a7af094310c2128e5064832934c19253903a478a8d6a1dd9c33f127532cdc51bf8524a2939a83b586d964a29a5941e4192740409162ed8c1c676c759b727a0c2e61b892f7227f1b36d5697a32848403ac215479002162e70c211998474040976440809291aa194124897a02e50a691d01196b14ae4e17225462564132578c0842248f1841596175c6820e7c532f7c3c205af24242245549d0d8dfd8ca4bcc05d4a29a59452ca5ab15ab35a6bcdaa75ac62f48b2dbecfe884bb75395be6d427e516a896524a29a59452ca9b65d9fdec667fb35aed575be5bc72aaae812df8c09c9c1a6a1134f41f8bca7ce9d2397f88df399963bf3d709187e3cf13fd7efc1a2f0ad531f17851f7c2e8afa5aea84c83c1a121b86dd74375a883ae5a9fc7a193d7033ad9554322a8c0d8b63054051d38147390fe4815638c9ccd9678036db2acb5fedba8bf40dcbf2ec4bdf7def75c75275128ecfd5e0cf5f71d156f4445faf2a7e0623fa329b2b813fb1951b9b2b140140af5b766215028140a8542bd670ce5140fb9ef28f928aae516690d6dd35d7cecefcc3cde7bfd33edc6d872ed6356a2daa76ce26143967d7e807440b1cd2b9bbbfbc04421a194521281014516c12d63d0e9ef918f79ec31bd3dd657e6f835dbc7f6310c8bf263263f6679a7c4b2af4f62768b2897b6e097735724114b94bc2487e2dc8ce2dc44d59a55999f6cf279a2120d26651972e1dcac1a6a716e6e714e4a1da340716e4e29667c4d8faf68fa2e067de4c2579a1740106d10e68338323f466b1f8a412798dcc5a46250cc8e4151071ee9930ebaf3bba8657814af8db162d895b9ca192516bfca39a38e49cec52e5b221751c020e7e013288bf6bbc124069a6670e73f9b0ebae615e8a3026373e8d01d3a74e8d0a143870e1d3a747777ce9df38a61980442fe9d42482925a63bf922fd29657cf933baf4e85086218ad2be27cfc1f67607a3ec30aaec67b474b479ec67b4e4d23cf131bb65c6a983a7729a126d0f83d3ca9d556c99dd02c21a5f8b134aecaf948b69ef2fd5aeb47fb394fa595ee2bb65f5bc346287d8dc58c6a6a4d3dd3fc97cfaf2e98c5309095fef11ab8f7d7c0c9352ffbdf79594faf06d20d51cf760da088d45853e1ceae00b56d9bee77b213177f015e57c52cad7f32e7c79cf2b352aaf4cddc1211ecec13fe299587c3fb3aa53edf778e27b3fa1f69e7c53bef752bef7b4ac99c68687afe043087fbeb60ebe12ed3a7e33c77f593e75fab26cd74f3bc27f7e620cfce29cffec60f3efe097ad677ca3200055d91e05c21215271eafb3e1c7bbf3700ec20dbd86af608435ee496ef82edddd1d4a97d21d42287586359c83bf6916346cb1c98fb3d3584ac50c903e470451ff4d8a416c3169c3fde73810eeb3e920fe976113bf992f359ce115bf990f4b4f1051624fb1d410c8b9b9e7852fb3d882903ad62022d4f095c5d671187f12cfc24f034619a56029a594d18b3da34c815bacc52dfb6ac52494724278058b73b3de373d8cf0c63799200563332d21c2b9f9f7067183983e4c88357cf9cd4bda7ce0b179f9eafe7ca9e00bce28b621e4869a73536cf2a304e33e4bab8cf56ada57ed4ac17fa7fc7aa5604cfdc88fe27b9628edb52a6925d56ab6d23eb5d6d2b7bae21eedb5a9c9c71acd566bce254569a1f64fa355b6fb4ab46d67c5aacd6ece2aab3558b336e77d4db36fa5977da52a26f9cd95f551ec049693de373dcd597d556327d809b883fdac28d40935e70943611886a9362d443ead3e843abdcc9a66fbec524a5ffec34de08efca92d7675d8b5ed84f98a87d818b97442e92b3f9bd8d3743536fd4ef6cc4f82d1ec7e6ae9d2a7a1bbed74b3ada8d65a6b3d690ff7d8c74d2c769299f0902b93b9fdaefa86799b3becda198cc5d94b6dc7a478735ffe53615ae2501f26264d9dcd37c9b8ef43f7effd19baabf76bc64de00efa5996cf136772ea65b2951193bb989b63fc5beb49bb73ce39757dd4cfd34fd4fd53bd9ae6f4f4ad133f7a17f530df79936d2fea377b3f096ade87d1a86edbd809b873b5b72653f62ca75386bb5a5ba73de5b7277602eed098a469dade979262aff92afbfa9bebe0af5a894ab5af490b997f2dc54ec01d54e31cbbc41bcd6698d5b223155b1793ee777e849db8f9ed13765d6b3f72b9274a35286352f4e2345d46402659cc23b836d3a34bf920c4fc3d3dc3864dd95e739dd7a54674f7d7e3de6a83c18ac7bdddc5bd1f8ecf82294ea49452c297923ea42dbea4704e0c4ef81e841305db94d3f6bc3da558d5cc0f90553d227c3527e5d980706ddae317824e1e1f40324a4d312ae7eea55f6ba514088ad9cc3e86518a515b316bbf52aa65866573764ca08b4227b38bd9f789983fe79c4e6cf73bd59c526c3490a0166a31bba453c36fe6cfa943e5dc9cd813617f5afbd5d2aa594cbf492955ed4955ef66523ae9a4934e3a298d94f2504aa976efd5ee6bd7dacc62b4528cce0ce225262c09a20b1390901029e203d2fbf8fff7c10384e71521212111e10182540489c812228240ea52a7431f2810420861ad7fb36c24be7a7fc4395884c7c70d72d6faded6f3fb6b709dfaf373301a36ccd28c52dd699a474ead5b86599e38710bcbe1f18a64cd3ccecd4702c4112fc2067ffea447dcec9fcd556131c6a83bcb45c543e0cbaac559314d4a29a3c681be76b166b5482079d281544b8cbe945b68b6affe7dab255a2e30ede3f3b8dd02eec0c7709471d3e46f76cbc6a4bc8ffda6837a08a5122112fb88699afbf5678c117bab05eec8c7f4b45bf6cc700f562106534db5664094527ab56a733c3d6adaa8bd70a83d84f1d6aae9635f35ac8560afd578b1ac69eecb9f9d92ed3b08b427fe4ef6c44f527754b2e9533665e93755774aa2ee34c0c46e61b7803b6fcf1de3dcd8c6ec167047e879b193c49fcf0b08e445148a8f4525dafc2a14759e16dafe53db2de08e18e9da8479729fcdfb220f4b1122ce41f964f3413ed9a02bdeb87625dcd86f99b3c7ba2addab2beadc20a2ced59ae260c3fe8873fe98460214751e104a7ce55dd5b69223d1fdfae0abfa6e8790bb833e49e477980c4273dd622651111f6a8c1ab502c2ba6463efc5a864acf61d2fe06d1c35edb5d7aece34938d69bb057c760bbb654b2617c2a48de53887e59eb7913c1ceca7945be10f5096af07dc32d8bab71489f05597b3b13a77ce0e40f8ca1ffb0b9d388761391bb3af445b698f7d0d3c7c05e14dc53887fa9b55cea1fe694dab7f65b5f5de0a0476b3ecabf6cfb92b9db3fa6aedbec6133b2635b3b57e9635205bebbd99aece699aa629c239ec1f74f90aeb8ec9c61767e8720e834ebc48e52e66a39e082c4e273614928b9a526cd8d3b05f1f22412d1babd57a94adcb893a9adf608f61183663b055ec8bb88fbdcdf48bed7ef6f6af5f591ffb1d7ca858c52a56b18ad55a91fe48f58a361e58ad58cdd918177588c88937d8d75ab3b7c9f23b574d18e37fa6c71988ecefe3373dfc4308ac336b6f9669d95ffbce551be7eab3c1741298a441d31086768c71cd94614a712bc37fbf8b663299b437695988394daf6521e69cd344dfe7fd89f57bbe54c3b98333ade94afe844dab5d955ce45391cf63fb34d11cc3d3bf1b548a4adbb67a398f7b13f42ebf6d7ca4d886f62eda959c8b153f7d932b79175fbdd8fd8eef3e3fce4588143f9bc982c595a494524a15c4d34c8d07e171a6a8e344783726ed479d1f757ed4f991ecb25d3b101e4efc2e5a61c797514a698a2dd84ea8e7712fce41dc33f32eb13cbdf84d97a2d7030bf4f9712ece2e148a8bfaecf854487bfa148aafe8d390d2459d380df2d5f3958dd7037f8c2a8f7e95eedbc8110bce7047a52faa6d8bdb7f297a38b18bec2245b09994dcf3e9b7dc45a33804cc1b4c4ade7719241cbaf86ae6695ebe631c54efb38be169fcd4dd0c2da76b1ad3d3985e6a9ac6a47f30d9a6976fbaa6d7bec7f4dad55ed3524bd367b9d3fef432dbf057f9cfd4d86cbca6b9efaffd7c9a69ee9b9ed25cfd83c9be6f7a0dd304b99f7dcffd0c679f691fc436691f638ae16d68fac5667a7f98bf18c50a88e1afe91f5e80490789e14d3a490c7f75921a5a0d21dbd3afa11f8dea250dd7dd8c999733efaa99f7199f6efaa9b9e9e9cf197fe95afa945d7ce53a521a9562971fdb5f7db7bff765e84be93388c7bccf2c334dba63b283d8707683b554ca7457bb9897f94f4964846c4164fe9a5e4646a3549bf493c97292f9f76ff6329b7e4ecdf4d264cab499efcbccbff3be8c39697ae64b2d657467c4be7ffad3cb681999bcbd77447610fbf451c957910b8dd4a7f412d9e397c62836e970fbe9976ca84ce99c74ce39279d94ce49a78f73d1579b5e22f746a16c3441361ae579fc9ab27429a594746e196e29e5944a01357f44103f7c3671909aaf7f6bce7a86ad26d7d4d4e8229508520eb9e68f640ac5dbe15f24db4c75c83402993a71ce7f0b639f82a2e95d47e7bd53d029a8550364f30faf4386c017c93e7ccd70e7c0fd35e5774e7746c039332cabe1446fa018c811865bb5e61b906b3e876c73113be4f7b89c6fad21006eddbb613e6a30cc535424d76f40ae9f43aed5e70745320fdf80ccc3e790b17de98fdff85bdce2e12f0f0fe3780ae4ab0c54a3e9c8f0cf573d7ccdd7e88e87bf99874c7d76b0e5efe84f4dcde7a8791cafe1961255abea9a9aafb5561c5f9395a876c691a98f7339ea5f1a362339bee6251e52f339f49c92e9175b8d91e79ec72f97e7949a7fdbc81b00b78ce8193423f80626bbe61f0e52c3e939a5e6fdb31e72e4f81ddcca9143e6d59093935b389ec7e94fe5e1fd29900e6ef1c0439629193e258336428543b571681b78f0784076c0670ed03f327c910c770332dc39647a376033963db06bdee32340fdec6a597e3ae41ddee6077c91fcb603f2033e874c7703f2db5783cf4df963083ccba65680986b73f1bfc43d64683534ac5215c90df81c72ec38b06bfcddd4c73848dd38fe62ad48cebe0139fb1cb24f215f25a97fdfdf01f5ef49bbf77ebdd9adb93536e0d6bd33a6981a13deb622397f0372fe1c32dcf903feb8ba71fcddf21b011f0e8ebf9863f049537e1e9fe22b1cda3f47edd6e839655f06649b27926ffc90ac3f8514752e5210dcb15b3c553fe847dc4f7dec16b8b32df974db45aa760b03fe4626f23a0ff9cf710fd1d28fc3c7e18e3c823b4e415c8e6d29fb5e40a6581e4e0fae781c0f76f070aebc9c23b2f270727083c70d4df1706c4003c8cd40e8e14889c1e360f0828703e5897350b0e0e1ac00058f737282876382269a3c1c122481c4c3f1c721d39f87e3cf68dfaff96adf5777f5ffbbfada3bfe51bfe68dd8f9a97f7e1b874c45f070fc6fc874040fc75f48a6473c1c7f05e4209902c9b42753261e8eff8f4c49f0e8130fc7df47a6ae87e39f804c4bf070fc59999a0072fe3bd31464aa8287e38f804c831e8eff01325dc1e3fc0d9069140fc7df864c5bf070fc773275c1c3f1ef916901328df270fc79642a45a6327838feab4ca53cce9f0099d6e0e1f8d790e99487e34f43a6541e8eff0c99da0072fe03c8948a87e39f93290e1e8eff8e4cab3c1c7f01649a83c7f9e364aa8387e3af23d300646ac5c3f10740a65768d1c3f18f0e45fdcfef5fb3cef68ac7bd278fe08e7da1bec39ceeaa57f170fc73e80cf78d6cad789c3f0eb9eb4ef60e93edf0af32ddcedeb58c87533f06194960626ac42849c1c880b9002a1593c2c086a24165e0b4bd3ecc1684697b7d1a2721b069330d517f06d6c0d54cda92ece2bb019b691907eac7d80e60dbeb775925826eafaffa885b17f3c09edbab8f12f403536e4f6282403e9cfad4c7919045c4ff09813f9cfa11b7f25f8f336a38f2db36d977fd24f5332bde154fe747864fe25932682af5ebbdf11207c9f28de7815b37f40c5bbd5171903af111e7fc7164b86d7c77355f3fe7ce889da4e6b3b7563c8b05b45abcd5bfbf45721dfac43f5314502720e77f2353251ee76fabf0b72fed3d2503e63bdf329def99d4cbf807f332313ff3bbe66faef92974a37beae3ab9a1bbabb5fbfbbafbd7e9ef839043a7746ecec2f161dca374df7795cc857af3b37023e9c8a15c0a4476e21de18fbfe14aaf1bf7a0a39e7738a7331e48eaa60fbd7c89d0c4dee6068e40eb53bead39db62a777677d4a7c376675f9d49c6ee2cf5e952bba33e7405fbeecebea80bb6ff491ed128b6bf467d8af0d5d518804744409f9bba1fae522c3c6251c1003cda738a5e128473fe5388e2a1ed43819c73da643bd5b2755348f3394500464026358c804cb00c2aa105153ef701fedb703a70147cb8b7d94e7b0b32f633ea828baddacfa80b2cbbfb1cb9056d06edc1580388981f734f23cc79e7a532fb80875493668b6022cef963f2f5a895be1ed8d4f9c178a3d90d1888dd4c9447bcf1c739e766afc7ec31ffe168788896f65693aa5de3b5ef6ca884a931b63f955143dda37b4aaa1d35102e65175fee6bb32cd3b497da4b2d88a6bd7635184dd33a24c7659a868768c5d7b07c55fb4ef5362ecca9c14d7ffe8c963232c6c4a86de8fcc7180fd1b28ffda6d5ef6c74e4c8bb53f0ed20813bba9881c7f94d1463fbc3f7c5f6b7c0eb818147027794cc903942f545296ad7ae96df1c426239eee71c0e627f6a1a2fda9fb1999561add666ac4ebfc249e73369f2dd9396f5c8e075194ab857d6e03936b478481a6dfe75701cc5626aa85455d36ab5f415452e3008e17cfaf4319b19b6f9f2f51022a49b1bbe4f29e5cb996d767c8923f220077b9148ccc209768c5f63a49452ec0926501475010a2e40780212134b5aa862473969d2a51c12a5f4664c3051a2891a308184164869810fbea08521cd39872149dd016043ce0777265541459744a43d62038a592de6943a2a1d818d4db1a022842c36a5540a1ddc112ca2f8b1cee5703ae491ee060cb438e79cdc4c3202912866949c0e8877c79db2c8911b112d8c2a362713929438429655c1920748910f204b43511675811da1414623911d908aec4085d76cc2842c62e4d1c205573a105db88e441d9e986404a74e440bd7098331c60806a478f3624624ea64fa48133f588209b250820a2e5040c2174c88555a2d7cb62805a478f36a13095089e20ad70cae80420abc2085a2298f965257482a229ac14912d901a9c80e611092569060669452ca2900cd9973448e9528c410e59c7336a1896c8293263cd9549b48d4e199483e34a2e40152e40348185c78c2f03203110b4e710a4853d8128f9032a0295a00a9608c2f584102172fb0069b6f624828a594984bc99313813807a116b6a0c10c9e90042f8696ba904455f02be7a494d26a55d5db8cfd8cba88b2b1fd8cbad8418c4a74493aa28405cf0d9aa0a6dd2ea59454488a54508a54e812a9b014957ca212500e9d3973c8c7c78704515c5a7378e4d4c0a3c80947db1fdbb29faf30cb83a772ca29e9113928728215720a69180f90221f40ba787551d4c55117485d6ce922a90ba52eba48201a5d4ce9626816494c56e9e3e3e3032465952d6324911d908aec3086cb6f5e5085b209a986fec515e56c1fe3c86fde2e6a82062dc860c9670a345081185c088318638c805e3133798014f900f28a92b0e414c67d0b4988c2f62d6664d19296231e242cd4c803a4c8079057d405a1a44d331239df51d2911b78c134eb0ef5683fa31134d9fed83bda741e51338224be90133b82ca39e774f9cd0baa50fc468a2146e5a812541ca18fbc228c1ea162896c3e9b3d146fde9612cb487608d2e2a58b137ee04305cbbb2041832e76b03d22215284278b251c5cd9520b9f85160a60042a4350c11550b08417ac2c3cf1aaebd4c8022a4f3201c21ecc408b000a2daa28a51116453d50c14e6d7162b3ce395b00858c1d73ce2925168e307757c37e4c5e3e68820a0a9e70820628c0c29c73ce39a751d07624b8fb4d96229ce004252041d214aceeb73b141f1f1f26585c76c76dcff1953f0f1f44dcdda5bc32853d5fceaf3b9862cfd77c8563cfdf76a0e585f62cc27e463c00a3007b7e4e0d3caea062cfb78107893ddfc77c20be7a46455bf62c7a485264ab2b2f016c510021be2b643145280a4488d203a12bf4780167648516dbb7b8e2823de39f54412b269de8620443480802129660032bc85985146c80824b065513cf39e79c33d299d158851635e2111446bb7ab20a25b088305892c0092975f022c200a04891032d98600a1d78c1624b022868d8667635fc146b22af5edd6dd9d48109648802697b61b11d298aa40bbf0a57a862092f78c214545421562cd6fa82a26767b3e79c44629e1461cfae86f77e03bf561e73ce39e79c930b02d87c3567f8fc81972658d1831148a14404168fa8f3f106fe1076a752da5d0d7bc29c2b6c229d92ba45619bf3a12ee21c7cb90311aa8bec6eca18895e3d2a8d0358ba4fc7a6bb259bbe126dc76a5ff66866adeeaaabb61f2a98aed963fa65d97b26f52cc2e61fa53fa92d944c5c9a22b2084d13691e0043c07a2f9f094be6a87f3ca31c4c810ff7649a1fcf2807429b27c6dc3111021ae520ca36c299b84321c8a7617befd5a3bb76af51cbecb3caf59f58e0f693324af9f1e6fd5339f71cbeefa48c52460c42973427de3c191f7c3146ddc5f83531fe9bf1a0bbbb3f19a573d1dd9d4228dfebd3524a39253dd5ba6defa17e917a7ead8a37ef7d8c0d9af6fbf7dac381104238e3e15c8750c3086b8c5bbc795f1f8cd5e18b31d65021e3bbba6da88edb36d3507f378d1f8919a899c7afa2f1a6d3cc8ceab599bf19896cc6cc8c4945636606e3b755db76828989e1f6844961a8192afa3130a7146a464686fe8c0c19999919999f9179192d840c2d6589984702c6b4f98dbf96d2d8514a72f0cfc7269dcfb1d41329a59452fe7bac1a619393ce79edc4a00a52ea524a50d1f645680a2e4210570187a884a1c5cbd2121884f6330a03cb33dacf280c2fa84cd9cf88ca93dd411fec6734450b1195735ee405765a696db4d6ad85f6d96ab35c881d00e859d83f1a6b36e10ef9dd69c713c0c3f1a779c2bc03618f02f0d05911a0061a6618c0a473ee98908b37fedc8ed763be9c120a206e0ce7f5b0d8d5687c28658c98aea19a11623632ec789d0156db5f86d743000f47c70c991ea86ce0f62300c7c9b7715a8e6a276c8b3a37efc6ff710f870518d6f17ad0f7e7b8a8f358a91a6fb697c2302447bd8009b59ffdcc9d06e10d4c6ad63029f15fd4d5396f725f016f6b1088dee82c853be2c307ff419b0db7efbe9bd1a12c176f68aafe01b7f6f7511fb74fbd09eb1753fa4594ae3a52cfbae5aee6943b9589e3e6cba284db561af9dfe77109775e8dffa0eef286f24ddd416ecffa381615ffd72532d1661686f064d7ec67240431f6a56143f20f572da68c86c0c5c6d9cf6808538a8e20b47fbfa22324b1b40493ee16a8f9683fb78bf6b2ef977dbbbca218e0dfd6b8658067bda61ce0dfceb8758067117d41c0bffdb8858067bd9af0fcdb35b8c5f32c222ff6bf6d03b7f6b388b8b0feed18708bf5acd79304fcdb35702b01cf22e2c2c7bf4d835b3e9ef572d2fab769e056eb59af9f1ffff60cdcfaf12c222f3dffb60ab77a9e45e404c8bf3d835b409e457425c8bf2d835b419e45a405877f5b066ee1f02ca22937fcdb31b875c3b3ac7811f26fc3e096906759f972e4df4ee1d69167113589c0bf8dc2ad083c8b084b0efff6865b393c8be86702fff609b726f02ca2273afcdb26dcd2e15944518afcdb18b78a3c8b28cbd1d670cbf42ca22aafc7dbfbe216f61e83ad9b5eb6df207656445797c82edb93f69d5c38578b2a963a54abd42b75a85641fd388702da969cdbbe54a972e54ad1d111cb8a46f3ffb60d9aec655fb6675efcc63f55b46d5c2755a4f215cd7c243f9f66fe63fdf05d8d27536fa3fe90535a720a2968bb5f4d4ba4b4e4145294ededbbf1b75b2cd2cedc055080817fb175292424d48b65e5ca95a3a3a2a32bb01c6d4b4c6a56c5574c5856aacc2a555cc7a4d4a5ae6c8fba432dd5ba6d2ad53fc7e56c4ba7201b248394f88587221eb24bd00675d565a3d42ab54b477de2ebb565fb979396edeeae72081dfbe29cabaa4fd537ab1aab3f2dc05e2dc0ae602f6ca8cad66151b6ff9531b8e22b0c8a7355f08b89dd820539e7d81325da954fb6fa8f6ed94eb56ca7596ee0a7a3eda72cdb4f2f796fcc322ccef9e9e59c9faec04c774c5eadbab2ac24f98a6525c9b9b75d7b1b4afb193961cbaed9cfc809af6d97a20eaee2378eaf6cffec9d2054a445cb26c07e455aa29873fedbd9ac794e9db3bf8187c4af36dec6c7dc69da86f6b8957d54025f813b70e32ddbdf46eef0d0632edbdf06fe01371e7262fb1a5cf38adff863c97c6616201d996bcb606359494ae2c2b2c28565c58b2cb3ac70b1626359c934cb4a87aa75085c76cc6659498a01c7c0b2b2c5575b585694923cfb7a6fcdb2af590d9c428a3a78480b1734f00d6f578d7af9aaa33e577cd55d245491af58565058e0cee9ca69e9f578d5a702015117145f0d615f7c85e485e86b2862425928169713ec09e6055bda4e3fe3a19e9aa39db5ec1ef28ff6feb489af8cbc3f75f9ca46b5ed1b396efc9554b6fa459c9b4f818f8122cd3fea82d8f16b7e1bdfc92c7b1b997eb1656fe30220b391334db1f84a6a0eb76a06e2dcc4e22b0e485a14f547dca3f55cc2c6c3db18c9314138389d4373b8956551cf873371641e725703cdb2fd7be8a893a965c6adaa65d10b8aafa06bbf6d80cc7a4189a28af212f2157c62bf7d80cc7a09bda6ccbca6102df90a3ab1df464066112d117d9121faf202f2156c62bfcd93592fa0571319af2649be824df6db3bb38892bc88f18248c9579004fb6d5666112911718121e2f20af2156462bf9d80cc7a05bd9ea45e4f88b6f80a2eb1dff69159445b88b8401171e1f21504da6fb732ebe572b23979f9f80a2ab1dffe91592f9fd7cfe9f5d3c5573089fd764f661175f162f2e2f2154462bf0d24b3885c4eb09397afe0cf7e3b486611bdae6857907c058fd86fe3905944485aae1622215fc111ecb76fc82c2221a22919d1942ebe8222d86f0bc92c2b5dbc582f56967c057df6db4732cbca92952fd5ca17205fbd31f6db11c82c22a0265893225fbd30ecb773c82ca2222c148b8faf9e18fbed09641691cfcffc09f2d5fbb2dfd621b388829ec827507cf5c0b0df2e92594450a2c42847be7a61ecb74d99457494c5b33c9cb7594443be7a60ecb7b1cc221a72ee6d165195cd22aaf270ded69062d1162d695b244d491b823bb64aa751b1351c106dcd8aed36bed3aed8aef5e065b15d0bc28def3422ecfb9d5665fbfd4eb372916ef8875b373c8f2f31fd8d3cb378383d78f38a69c59b448ff39779e2e071738a598387336df070fce794ac44db42a6d0a481b5b2fd6f0ecce19e1e7ec880efe3f19b23076e09818031c61863e3f03f70fcd4d595f1f0b2ba6a09de2ae6c891e323b6b12dc51bdf96ec1623f6c9db90279785a2d1b7312bd55d7d1bdab664f3aa6db3d996b42971906ae32d1423168a916c836c907d62a118d1a188d56cd8a06102d9d71c22166d501f237f5d5b23a822e76aadb5fe0070ab62eeb31c81af99fbeb5a5621fed1c3672319c9db205f21797ffbc4dfdb6e703702b93a97730fcfe5b791a2d6378e7cc643750d017398800e457c77d46708595d38e414967b030381fbc6135b477da84fd49942422d23df4da19b3917b30c17612cb88a7331872f61ab7ffdb7e75c87fa0000b7aefb4b9dfdd43e5167a9235fdd18554be6be7fe4efcda9a354d1952d5594c2e2f4bdce342e724e95f10b6371cef11105639bd99ac6559cf39738c8ccc65730e8a68ec9ceb412b6fabe659bd9cfe84b0f7645b2e1a8865d4f453adea606d5b7c1ad7a0ac243f5a7b4f11d8ffd5a773c78e47812b6ee221d6df1553785b6165f3d23171737b4a219af3a87b64fa1fa3870ab4e256cd4c78b7c7544a7b0b80cdccf291eaffbacb2fd65c0b3ba5c2ea834a71811049576adff3a98b4352554d176f2e4bfbe10b8ec2d4730fb1909a1ca164294fd8c84e0a4c67e465996f6a949d5ae986f7602824fc756bb2baafe8b7f6a8243d427a0939397945a6c102f811bbf9c7329b624f197c05dbf4369b175a88caf64fc7a0e619c263ce49cff17fe9f38479f083981b29d36e999fb3997fd603bbd3e05398771c041eaffdfcfaf230a8b738e7a0951515e4cd9f26739e7bf3b342459fb877b7a189a43790a492cdbfd6e0add9f539c73a5dde1a11a6c1dea35877c75df8f701f967d1e0fda9d12a8b4af10704bb15ace603b01e92d5bcd539fd7c3f7f61f63ccb9d11dc6384df5b56c1cdfd9a5ab05094a0e0a7c770afa1bdfe121eaf3704430c61633d35f249f0349e321c8c5eef0d0104e81dcf9ceb9d3b6e96beeea36bd91dccd9f2e67f720e44d7f03a06919c93f2ce4791cf5f2d5159417be7a1bc9d10ff6070720459d256478241e20c3031eb025ea2c51814742860ac8f0830c6fdf97b0c02351010bd8afc00ff607fb3fbcfd0abcbfa5f9e33af6e537fe2eb91cc92f3674579b6cdd6df3f564fb0ff52b505f8607d47740adb5565963fd5875e0568daf03b762cd02805bd9ef2df2e5abeccaf6a2f8b3757ee49fc557f11d89fafc68d9f090af1eaee2abdac2433f4280deceb2afb5d65a6bad357e26e5b561e3ff73f6364cb908e79c081b5577febe74cf8b5724dfbd285821b8c37f70f80e2271c377300921df4125827c079b00f90e36d1f31d74a2f51d3c818fefa093047c0751b0bf832ce0f90e428180efe013037c075fb02b84c1ce77300605f80e0af1f80ece40e73b4803027c07a7a8e13b3844c377f00603f80e5ac9f90e12edf80ebe70be833bd0f11de44100be8357dc7c07b1f458c077d00700f80e1609e03ba88319be8354acbe8335e8f11d8c7280ef6014acef600a7e7c079f782b057c07816e7cf7bce861f33c7cf7b8e81e12b8da3d1f7406e80880e3c2b173e4bb1bbbda40db2970470e456aec9a4de0abee9410e19c2fb1d5efde12dc12757c8b91bf5a08eed82124dabfbaa20ecae57255978b02d54581e7a1baa6c01d5bc5067e1475220fdf430f6f4477dbb6437027bee00e7f237feddd6a320ed48b43bd36f714d09dceee5055e04eaa08eeb0f27aa4b07838a9f8823b3608eef0ef41c7231eb46fbb14752e927da5b0783d6c15469ed39d4e0edde53c0edd7159775fa33bd5eeec52b54b7669bb8d8f5517e19c7f96d5bfb5d6fab3abb6f1595662e3e1967e9b7f10b7ae3c924030a23b9d1c4e77393970e8eeb3ee543535fbaa1921a9f643b60f81acc3fb908bfc9d4096c04b20bc1e5b180fc775727238eedf54ebd52143e0efcc5ff3100f793a29ebc30ecef9cb5d244b0152b17ef86dc97f0bc35f872c99f038ff1cb20cc2934738f29504de5f66719d1fde5f6a711dfb7efa777a9be90f123892290ce00e281ee738be26e3f89c3b26ef39e0cba1bb9ad7fee21f35cfed9cbb10ec9abf9ec3b6f9874aac78a8344c582a831a32342323000000011315002028100c86c442a170384d1459f10114800f92ac546e529aa74910430821430c0102300000000200813430003bbdc2bf263da8a4f0944ef9db508f2d0a90b7a8edf14e0f181c42f4eeab7bb0d81bb00f311372a7cfcb71c1e63f3bec715be85995dbae38faba3a5a1f1010b0c429d8249db05d3dc1ba891390b5c2bf68057c9b201021e4f5b05d981314256a193e4821ab1470ceb4dc6be3b0ab56dafb7f40b9231db0ddac6e2837ab9baa9be54677633f37cab50c7dc28701f887801ee1cf6ef3cd25bd3a2600f706fb0317f04369d9a2a003f8155d692c5b876c848436700cea6e37295897554fbb730ab5015804725db67320b2a1ad73eed44ff9b23772e1564812ff648b1cb9107883a80a23604e240c3228af08aad907bd1a0defadd77828ac92223f76415b3f3bece3c11c1bb0657bda4ec86c76d84aefc608afff5bfa4864265acc3809c65e68a71742f4ec110e845ef5ef6c5e91aeed8c776a5edbec3f878c6b4def036b7f7cbad6f6ff677a10124a38773bd7235d3af7edb539e1f4b930e7e95ca3b2ab03dfb5fefb69061c9e7636b82dcddcc2e465772f0e8fde2b9103583505e073bdf3d46d3f53f73b484ce839f5c9e68a9e2906b55be32cc7b0bd873a54cdfd5791da4691cf61418c4377a6ffb137c13f3c3f5c6609f43fe461ff256f8083e3d7a524da26936a924c62434dd4cc6dd15ab3b6d31a0bde950af9c08654c2fd7cac444ec36110ff8368778369dfbd3df9334b2e97bb974744487a74a0f7028c0a65a51ff405e7d3ea6f29f3d33a5b8f0ff4639801e648dd22f75192e74b5440000642b134bfc9bb83878202170ac0f0ad11d9bc1a3616e0e8a785098e5e8666f61858d3c887da1a121af8be94efaf1278b880d7c4fceb8b70f2cf071ef3721ad44cd5346a2f44e3957361d03a006e3be836b291836a91bdbd69dfc649e8322355b5c057614a759278520c1f2039cf4e4f27187e75f1ee10e6f6e0ee1cb24b0344f473f0556449dbf96f23a9b3702301991256727e4f082e7358a7f2842ccecde1830c76169db4e50bbfce42739fde4858313bf031cba16a76758375aa36305df0e63c1f9b73d9b49b349c4148abef7eaf13747a7d8bc89bd3716dad7c9683032b90d2255426b63a4252aac31971d5003220bd64e7342149886776f3bdda45e9f4b1b5ba42224c182d8bd4af6c5e011eee6a2b2f31f166771a8f0bda80926cdd533a22fe869d95ab028ccc332cd3338a2cd7ef10a3aa53d1fadf172c76749f7d07fe623874cb7f2e28cea638f4b8f3a7637884f00fe52435d33689984b124ccc8396ec9a0c9cf6552fc627499e81c42627f672399e22c8b00ba1d72aada7a64e312cd900160359fa74d704130e0fe051fd6f1d1b3357e9b55202a9a7f73e0ddda122e0323f3ee401e128556f7a6cd89cd56fe3e6bdbe1a983b7b6cc6fcdb6f53e6f09e9b9b077c68d25ce26743e6239f1a37a7f9d5c0bce86333e6567f9b323ffbdcdc1cef4393e6893f1b32d7fcd4b8f9eaaf06e6bc1f9b316ffedb94b9f7e7e6e6ef1f9a3407004eaabd0ee692b908c825a3df98dfa7b67479a4dee1212749aa75680d0fe07988ebc848702833247543e52220cbd8bd173604253ae8f58dcecc389b061e32d72a4e595a4a8403fbeddbc3a1a569bcd55ef030392dafc3e05a942c3418ab35f1a144366514a7e6c07f67040b2eb5deecafd7f9e2f3a3ae13de28cce742f011c4a887a9b510239871510c37a761336762acd94da37c8d7aa4e6f9b7a0b77b758c62e00b4997f04de44639963d56cc133bea67d6056961c4494450b8de5ce5fa6f22c8f7fcc3b6a2dc2422d05d0231412b02d64f4761c2461586ae5fdb89da451e62d3a36274ad077f7891e5288816fdddf033937c6e67c7757830414c091bff0b8a72b9553a6cded2ea71fd63442bf226374f2a864badef11bd5eba19874749c78090dcbb355ffdf7850016b5b83a35755198c1d1d4849ca206c1cb3ab60f67766c1e87fec0b5f1a08d6cc2c5e48d7c94eb1c18aa0b165cd3a6d541756413d201ac569b9c5a6663fadf0357bbd8d4102159f62070abec258c97da55b01f77d31722b84fd8f4e2c2588b85c0f4567a352b72e1e02bf90530b02a972ffceab64fa8536e9aeea2a753c89ac1df576e3432062fc7437a6a34023712120868fe2090287a49f64d3f0708ca70f1c7289667a5876df86e5ae683e6131ab678653f2341db8a23cb26195391c69e86692af5cdba75463e6e12decf6faf8dbc08c76018db2cfc2c06be6e90a269a18d18fea0bec998a2514b3afaa4eefc5c86928c9a9c60e0c53b2e47f12f4a8f2c4ac8572c2e86b36885fa9825f79e8a315f9585587419fde7efad03f8fe23740c9db80c24deeac228d5469ac33456f1df0ad03265cc872455db094c31000cffd7ff76f3342a156cd1c1d132d54fb8165bb619d7c38a842629cbd275c1788824de3d5cb6f03aeb09907d6e4cffe197aa024997a487a3670172e16c8e871bac742025181ec49e15996b10a4b8580d7575242d3f884cbf61588df7f673c5680dd36ccfa1301ccddad086c02bcc1d16ac6c159ad4ef4212423950290e29c89fa3c27aaeff10adb88e33491357d6feafc4559ab0ea73afdcd377d06a020b72a3f6b2dfd567c239cb484f7aa41d8c5f5f09b4ab111a22bf6ce94c5277e136c302acba6e28a6805b53a362a53ed6710a3333a8ea44c75464e959c7299eaec05c248e1395591098861ec03525250c10ffe67ebc2954b3423786898df7b590b7009ce00682998a04cfa6adfcb5a418c77e16b5d6c0f6e902eb8b999e0a1a15759dd6d6edf8414a6fab32606e0b7f9797b27e4f93ef64794dffdaa00749cb5c5ba21d905457aafe9dcb7d65df21c05954add4276fd8861f0af7dc235345245bc0f3006370b89501b4ea31bd318d6aed1429985fdaaef02722aba434320d37bf6cd337f03b45310e6cd17718f259ce60afb0aff3f91541881eef8f4d3ab24cfddc86ca69243b77c6a566bee266e19d4e7e1423e09551ec7a115122ab587b02839a24c5f099e2bd93bbea309affd02c30747cc6953a89737f219d6eb4620b26c3c2ed6d83055ce13f0e7c2fd9b48922d250a65d7cbba9c0cd15a9c1aea1e931c17d9a6a0d198c20ec50b1401ed3a6d4f92b0b1c6e0db8399c59362ab07fcede430c5b5091c5bb0ce89a678ac1302c9b6cb44138cf7cd99903ca94b64d6afde7dd8492535523c9adab42bde0fa1e62a47064f80e2827a002323bcc470750330ce1a610c03b4690a51451fa26210519fd53c08021a0d906121ee3135c3dcd74e9d56ddc4fcb34bb4bcadff40f6f3d32a7476d860ff43c8fc46d32840ab89ef8fe9d35e8600541883f7a55a4e2aa06cbee145a3080f173e18a1150591490f9e216cbdcba22de66a96c0151eba83b197a22599b97582c1d49a925948058a3dd1e6933451ecef080fe5dad21d299b02909abfb4b09efbd3924e180ebf409408899384ccf3ce83d54c0976125fb64a966f5769366efefd399e571668f7a31f466fff988cdfa71c8cddaf2198ff99b04663bef9447790ff1b8f3a47854b1a0c7f9ffba66219fe1515e4dadd97b4fe091e7497bd4fcda1ef7cec9638e25f568c75f5e5e62aa10c03f8d8d0a74d493d22023f721a29e9bd84545059d681cf7c33f056db59d4e7399a3b3baaaa1c58870169945f5683e705ea0715d0a226debfe781d31991399a4e60a4252fefa8046ee5ac24a3352013b154d119b5be8ac6af60a4d26ea8a2813e62210d088f7947d59b687a49d263767fcb09db4810babf18f1bc9e9fbb5bcb482480b623610692c90e66f373820b3ab68a147deaf8ec6f9c169a07c7c60e0239777fcb0ea6a836372d1d01aa6d260d9a3ae347d3dd343335cbaa64bb3c389a2a8d2dcb1aec781aafc5d38e6380e8e0bb047bcd7520584ee6e7adaf245141b322963c7268cfa1092638cf341f1c18318eba1f57e3cffaa255d638570e5d618c6ea7fd0f53505105c1140f54b7365159a164cd9c970a53bb5bb6b3e17b142d79b54f2a8f9a5a828fae2ed59ab3a44895bc0c379094acf27fc85b1235d24c94d3454cf7b7c672c8486d6a5af18a0a5e984d6ef7da93ff49dfd349e2ffec34a642668cd3eb7deca62e318fb019ef54d5ef70112f0d574b831e0e86bbc0ec51e8ed24d21e261ce64af1171d2014df672a1943ec11bc25f318f8ac2328de8debc1ef243e24da23d6238fdda1c0b99bf6b2cdb4c79ccb03e8c636d291cd1eeb183035dc4f243340f69417013f8a779d741b2bc866e0960516938a24f6906722ad83b24050d52f5805045f29d993820168db13cd4ab14647bc36cba17b0926dc86c1136957f5641088699ba210aac1a532564bd48b2a85eb5097dc66a3bab0826cea0d81ad917a13b29612a63498cb911c467e2a1ca92787aa4f4f42714397e6d9c0588ce5170011c078bbbfb6ae689d495a26dc9321479543ebd25eb4f54d4482d2531ec0712a8abb76298d460c32b6164435820f8ada15f0010dabf6e204151dbca90735ea40e8bdc0917ce1cc2b787e107aa51d9aa39412693121b1a402b87fc929b4f5ea6c2d3ec448d49501689a97f484071c65a5e7dc01f0fd546b1c266b1f6d4d98ff1c241450255a8aada08548123afcf1cc00f2b55805b1f699d40a1bcb31b5168e5ae490b8c54cc302397ac5a09fc3e9dd401a694bea829407025c6d0daab8343bb7e8e91ccf64177edc1e2d0b937fb1e6a6fe5f41d95adadf6a16ff2a40e80ef2118abb89b56d087ea0a51e7e3c6695cba8b5f895058f32584a5f188d566b471197d30bc3c237efdc6917284bc8af970e8ea99481783e415162ef71f79c93fe2bb69d60f6f268fd841553bdc7b432aa9317141490cc12c4d3c03a9571ed50db528cee52e58be1812fb6ec0db835f78bf8edc5437f4dc07d893e4fab5ae3797a9c50795198e0b39c170b43ca685cb869c06f30c644e78151a8b99ae5516adf8a7d7e83d8880c7aa8a60fee4296ac279e2d70396afe25686f239298f1b391317f88f61db7bf5491f26f6b47bdb6ef2fd9aff89a8f377a8a599add1684e705432d3988c8ad9a432b0f380ae7480130ed3dbc5b96d5dbdbf61d1e121515cd3169d46c54d1fe7dd446905c2b7668b9a0b8faf592402f3318bb81bd1ed0d183c6e86db08c83c68536c4b9ad1d548253098520e1153a3ec20e4bc59709cc6854f908ecb338c5791b2e8206cdb6490e3c3b06449fa59fe7efa9b6c691a5135c0c37bdd86d2a0504d285eb9750853c3e9c4176b764076e4aaa063d803c355f8658398d4c5c2fb77415cf5ba1913e418cdc81ae41ed6906eec4ec1b070b2426981b11a174488efb637702a2c0d180a5d6bb81dfd631de90a4af364a837844d1c5706360a4c03b823db02c5df14f214216fd671ad15570741554cb62569925fc1f4c523a8a14f52bab558e10d4a8ac22d25de43ce1a1dec68490095dc3c2875f7e557bcfd783f8a8583370f76dc83bd795e7887605ce7685630c48f4f6e553ca2d0003a42e8c1809c178812ac04bf6d17701e301b6f79fc46ce69ccce5bf169d86a2d97b0cca02f259e52efb54eb0c9809c4f31e84e294e0e9a3026ea88839c96c6b1dd9db0111a6c1016a5b2a11dfd0ae118fda5a40c31ac86389a332d2e84565966ad5a03f01597ba0017cbf723e35d77eac690be25c052edd34d69a474e0cae1e46897b4a2ede78e3f62c31d10959050831ece719c82af5677a871198347bacc53343e0bc61d8f3bd8c87521a769ffd69eed79735f42923e705a62b0be9a27f14c1c449d4c0bc222bf8493b8b0862244b4963d9bef7b709b76c0cf5a2cf9f7ef9bef9fd929c426062f95d38e135e38a07684c1ca837faab76c56be0acf9c718de00c05781bc99212e2bbe2e1adb209c2fefd298866928f2d1067a6109bca07022ed1ca06bbb12464b9648fc6963e124278648e07dfd888a62747111c114159e8a25582c287da442c2fb46aec192ef7faa2049e77ad0e25dd5c36e6d03950f4408ef727b8a2d2ff81f049c362d18bb1c64c4957927b4ffbc605af8d05f6a87813baf35642155403311667a032ce149134f6d4f37efa149128bfaadbd4f7b395df56fb558f852be5fe1caf7d4c38cc2d1da8c60afaa439971d3bb5c207bd73b774def5d15b69d4ed5e5dd949fba750101dd41f1342ba21d6b845103fa7c1527609066c58e6d1816dded1797b53257a0f0b3ca1f3e08fa161cdd546fd437827a0c5ead3cea69ce7e5fc84a22332355cfe90ca17eb41f942d368a31c20bd45bfd0ac70764bfcea18ecf805f424332f22678b2eb9654d1f039075c67bf9f46afcc50d92c8ae97079aa291a413e820ed971516d6c4cedb80c34844ad2e66b53750a3691a18d3b48136cd971ac3b2e1fa469c9c26346d585bb3b59aada161ad8c6a6eaa476d98d1de8c868db5c4a45106efde45e2585733e2d62808479b1943f5bc4d0c3df3a74540b2ec119d33c099720e58bcb2dba109e80a46f721857699abfc137f832715f98722c8fb125244c1c965c99216ae6580366b13f919d0e0cecd3ac0e5ee15a8b51d4895e210e58319bc93c54c4926cfec773608c320a85504818b84be397dd64300b04a111fe0f1eaa8315bdd1c00abc9ca1038db07803299e6018410851ce4a1d846acbe8cd2551fe4eef018777b272d19cd4c381c5d230134517f0d3c2e700b7f2e2431fa1ce4e041361fa8a6fe645a910084b2706866a466a8e5e93b671f8781331a90310e840ee893ef3d829b603f9cae580ffa131ab5cde4749744485925645e89e69690f2e70bba28ab4f4876fd553125ecb272d3dc335882e6f1be8cf2d5770bc5053dcad832fb233d45a1e001ee960584850143e9318e8ef033689f44a8ace5328d35879b2acb67aeb708a920e99a7bf3d042a5b32304c665d1739a8eeba96f0c8a5250204f0efd07970f8e411c6bdf09d70495b5fcc5900a3babac455dcae3e224a94f64600992193b86f7b5bc4e19d1cd0b3f3c9334a27c98f086cd3f87a3217a576adef1f2ed27590e071d99c5c8034ffc9241b5091cdc77eabce8f99defe29cacb497b6e926687862c2c4607b622c34a6459b5f23eeb242f61a235b5e1352c42b4aca2bfbb67cd01f8e1d084338bab2563300fa3a9a02117b50be545d7e82da223705756f645f9a04205a87bcf26e4fae0cc0d75eda2e77766a682f5c491206f55b1d29d16051cab198ce1b46a42cd7a04a2f6c8e06b10913b326e1a2ce465e8c54ead43fd02bb25684463811b3d4fae051a809341081aa368f52b7f9582c7b2e2c7d25efe6e6d94adf7454c289f6db0ddcb4b7d3fc3bd1216a16f270a16401e6144feb287bb3c8349ea24196885c953138fa42eec9fdfccb15e63d90da5b034fb63a3208f042f2538e2fff03bbc93397662dedc228dbc6ceca466f5796a6221a0920d8d28b9750c7ad3e7911778041d4aa343b8293efeb8e964534b8bbb999e6c500344bc007f0d2e629e873a43e6546efe180dfed1f98afefe30c70b97450d4590adbd436be8fb097ddccbec0aaf76e6dbcae878b01f4c0e0efcb620b3cb0e361a73e7eb65d7789349fd7044513d6f7982b448f473c99a96c1928362219f0f31a9b2915f83b051d94aec7611273e7cfe53e41ea5f4edf415b17a4bedba9e22eb8d67500631f25e27ec5f21a3b73beea26478fe5cee2abe719f2942191ad433051b78e1065393c3d8b0854aea9deda8267c205fda7b71fdf9a1ff0c7d239196938405146973f367ddbfd89c237c6364eec0de1a70fdc24eed48a9f5ec904c1ae06bb57e76bb717bb813b047c114b9e02799cb749c003ea1288cdf4c486d6b7a039d0f0d7b3e46ad7f3ba3a2bac4156347ae0d3c88e89eae5ae4bf85a5668e94912a33e0908c9d9380a74fab95a9ddfe6d48b729d5fbd43add9a56671823deedc01b9f49bca0e7b006bff7e3ef39085ffc92d889f607234187fc7551301f225fdd8cd698c567c48dc7052a35298bd440b3c4d4a5b7dbe996525d7187a9e4742d348ea71f9c29aa532a0cecdd54786d6b61ad950d8d61b320b2234e961202cf3114bef60d5762ceca506938e1c484d283d2765d8c1c1f9af37bfc1a705d08295d238985ca80d3bccdf2617d1154cfd4271f00080057e6b153745fe5a7412881f2e31d35fb45efd39b99e4911174b87668f908bd544be5ce3c43c3c8491b67ace00384cf830e0b529741bf0a4027b0ab46f428e054c92e11e001b4ea804404f539831902405e201c0b8844710dc01438b004636611d4005514824808e14381118d209e52890100c424cdd82487d08f30178c19b024a071cb72a34fef62ce6be35c05601273d94bd69b961bd5b87e2ea3fe7eeafc43e390ec068d6c3a870e94c2c7ca68d277f758731e6b6cb57000c8cbd047c01f1be581c187b5b7a52af5635d5b97a1f442f5f391e87dcfa03cfe8902d9de50c5948fdf02a2164782494a608d37236225cb440344ee430e3e54d01426372d49b9bb65726247463e370ade1caa09090d42f946b8bb399e20a65048f84f96658df2ae8a0ea2086a65d05f2fcf9078d80ee9fba4798d6c6d7fcbeab915735520f13cf2d6dbd1c033e7a295328ac300190e9e84ea051600a98b4ce6a65be524732166ddb1314f208bd5f9f6a7d006c0472e1ccf679a4517e800991828fe5b35ed68473b2da4c96af2cab404264759930264b4007ab983ccae3acc2cd01cff02d21d448e79929675397ee37eb2f39b1db796f5cbe08d637dadf216fd96068f60e3de03c720e4e2f6062ddb594c9790009ffe0bc7ed45765c900c613b31f0576fbcc90b0ce83b6fb3d17269123d9d3ffb470cd53f91af8aaa10b2f23860c9245aa9fcffe659c0c3d8c0537fd055d1bad01e526a9abd3bf7b401c80b871456f9a74eec74d4d7065ec751a43fb6d24c36734be41e8d0f53167764cb1560302b0881fe80e01c70924e601060c606b914e9894532c4a3e18b757aedcb68249573dc629655d83f9163b961973b623a530e118360dafa18e04c26f3061058391e101f1655d2b725161a0ba1df17860bdaa2c1aa8eaeefcee6cfdb17e565081f7e372cd09d76220094a0144d7fcba5c7d50e335ebcda748e535afe4d4e5cd7acd4b4c299252cde94acab1a4efab6c3d2ff611eb3c276fd43085ee4f508458ee107287d44ac0b027c5220a8bbf7506f8e97eff22318df01ce8a20e4e41e40a35928e29ee6c4e987d4fbf0ca88ddf1c14397b22f35019f8d05b106ae2534b51c9e806d003d8a5b46dcd9ecdfd55511b4415c018cae9a72a9e7c262287453621c4b8d5a39db7bd187d4689a87d386782aff9c5c89434fe8c7650f0697c9fbde1ab4b415fc221cb8c6aba5122e87109a69c216bbe36473d75545121f30f1a87c35a606d32ab06c35ab1f8a95a1e12eb8f0060c8daba066438c23434b2736be98484e05d165833fd5332a061b919b2a463320cd090ae931a67045a266181543051a8c515f55ca1038ca2c9a5d4b9adb88177c82fd8a2b67dacadaf317dbaa9958320c97c54625f604d391bed1c5efd1959082c857cdd44845c24838ac934a8c55883cab6006855aa802a8eaf53d24bccd256823f79ea51b07e5a7febc20338d6f70c1242ef90ab820f00e788a73d2e2f2e208cce0e2f4cc2b981d756d7b973feffc9c4d83484d9e2ff7f9e41e280e8279980b17d545e9ed9632387da35dc09ed98bc84d432d06a525329e5c3259a503bff26663eedff7789b74c8bd499666e960cf8b9c3bef906f8be2d49dd67406e645cd090ce4f7df7270fb1d27451fa30934edc42a5982e92a977310d923b2a2275811b14f3b74088855ad34797b8e1ed60f4cf99fc58f08966431ec66a12444ab03cba6bbdf3a1616bae3f7975b0300c3afff6fcb8ea7a13ac457493cbfc25ada9e32e982e1a6cf76da627972722514f83e817900435dae3d72f0663346b8092411396cdb8ad5de5b35ea120dc26225a0f6380bde52a38f989a385fda7fc51e5ce41838418216ca61534c145efc09cc914db67080df951602d299b203f23edaa1393a6ff19b3f95a3d815c4cdb5e12314f0c7b09106c5628a65f358eee9d96c36367b087be8f5afca30cc6a22970ab120575ee0a7a4ae1f5ee4c6e8a7d248262d3c073d3033285c7c7222d28cb0cde4c95f5db05f47d78c7ca98184c57c4ee38dcccf2974f8c401930c595ed605fabe148ab80a091f705a59d008311a68817f7fcb459f95cab1addd7a66f6cb9208e8804a4d9f647aa425d8ae34d349d0d7163a50f6d0034a80bacb6e3e297d2c76b67014296f9b611af19d33a5f7ac8b9071e59f24a6380d231ee724addf42918256c435e158408f0ad16f65af1c18a23af345141dfbb101eb248ef7be32887def68029b296f922bd8f931572e3134023f61ed74d7e3f88e47a3c78fe32d7b558bdd4e572fc48744320b3167565e5a052149bfc88d45a2548b5b3330f4481cfdcf39b08057a3330927b9c31eadeae3afea070944d1a98216dafcb10cb62330d17b60f1e2efe4ecc34bf40f54302d4fa9d1835cfc9157ec4b8ccdfc3f5c53378d3a9f3121fa098d0964cf51099ff941633a722e2e85e7cc1b32e287ef56e61099faf9f76af095478c6cb2e79b30edd3f1c8cfd215a8c6a029929676539da26511254ac1437087ae780b8037daaf49a5d89efe1c27010e95e20b2b039713502646cb3b7af3470dc553cf16c2110ff22754f74cdf6ce0497ce69123b09e44de0ed16358cb7a21836171041c028f87be00cfdb4595dd519795d03c20da7cda46f52d7596d49b702be94c7a2f588ae2b64ffa83ea6ea5b20c7680a5a730ff9302f5ab7ff67f9320265b1545a079d87c2c55b6075df09b4d8057c5681c659cba1c2e095da5980dc9a796a3ad5e31aa20b6c03819b1580e42e64a7981916c06ab03564b00b2bb7a144f4fa48accddb2d5e7a243a14be950c8f501c9452523f7c0542ad5b745d7d5fe421095e970a3171858b95fe60f5f1455530f64f144206952b18306c9a684485fec05d654a7d00c812181757d3b9e149ede3e3bb882f94de0ebe65d687667443d16bd1597bc4b2b3c5d868115f44b96993c17732fc40ff3d153029454b282701d726ccdc1291fcdd8f780b67a32edee3fddd333b55cd12632696b16e544e5cdaa35f3f62a7a2424b01cec9ab44877472458568cc950cf6803d8c4ff9bfd1f91b56ef78258325e56f2b4feecfed251e6806e13ae297ec29d846980502f4d2fc1575af51d711cfe18fd9f0600a00ab20a566eaffe73e4a632c67295fadbecda3f88630b0f1bf05c8a4d4e432235f8088397b3c4a70c1e68b0053a6aac49d0ca0cca0667c806c1563d906ab359d1c73fb00e17cae3beb594490345015ed3a716690167de40b51b6d0bc5424f0f359054fb99c085200df09281a48e85436a1887d7cacd5cad86ca884c1dbde5d3b2dfc18b79409c47fa064d452430d98fd2b8a410b450afeecd2416440ae8b37ef7fe7c15115e15492dfc732c8c3b634a077e8964cf2a2e8fd041418f1e0f455d5d6dcbb4faf9c404fdce38fc9c04b005682c8718433db8ac3746078043e38a6cdc87c4d0eed863f3e83c4bd5c80f71f11ccb031760a1e51f1e26dd72117082532602015ee03906991902068f8e20ac22dffe2a4dc379f427b517ecf64b441c12f170b107d4e764e192b55c50751de7d08693ea8ff5a5ba5fde86a900073a364c59f6e1ad4601df3969148b778992a2eeba4e16fa534af4c1408ad2557a01cd361056f387fbc737e796e6395c55e4a32fe015394d2b1c8e37c62990a53180efd96ce5787e48107fcaa059d66bed6259f6adba40791b40f1b3f747fcd249f0e3f0a200db5a3d4c8c04ebba1bc104694d2b423210692d271625a956116df84ee3705105d25ebf579a1bf7e65371696e9fe48ef51940ab04260b98faec806eb5e13ca18b14a15cf428c42a509e13923b0f91af07a1f45f6440c99c1535c2bf2ef405f0b3610ad8008c55b3d626c115826e84529c88829a4e39c5f5a35426762ffc7e6aa96597c7f0ff9561507138fe5f9e09dc34594860021f0573228de54d93479887fab4a1878421bc3043aa2656257c602c3a2d76e668002c433bf47b3bfff559ee59618fce5994f9bff3dcb2298ab2254d6d6eec3090fe0be78b4d1ca3a89dd61c1bd577586de639da21e487bcf03ba7912ee3d9e840a2532d5f23132ecd9d551d7246edfc90889be915813cc841818f69638c14910d7896b945206808a481587dd08358b2113aed8967214f4794584fec412547aa5dcca04f4dea2073783a70f74e0eeb333324e1120c00a711005ea1621811fba200411c97d288bb18c75bf21c1a8dc93bd0979837845020c5903de7452a59f8179e66a46b3d42c70ed784d14c239ca8fd129ca6326d5a046b69d31cb056e846058870ff8954f7be279a85e0c6d5172f0ecc96737e32bfb83a2f79af3dcdb57bd988f2e32739ae2d04b210d530a24fd1701d03fd58962ddbec80e05dda843323f09b8995a07a49115e7ed34861df6e30fe0f6c1926797a38932a1d07f9ff2f83750594de88b5a0125ddfb38fbbd1b0146156b1f6b89efe2f53295888290456e06c42eb26b9a7560079128db79138d7cea7d12530dcd836da4a1e8e6ad416b26e8af1a45448798fd787fc24c5973428407de66a82745e049b40c391b0b67a853b0eb3b19359e1051e42aa8bf47d1889c2f983fcc2cc6a6b490fba577073517e3c2036c5ceb83c3ca0afd80b1492377973e256ce08d3dbb49373be673283a03af25518fdea09e9678c1d9a7a6bac0202de0213d7b30958f575341c2f66f133047eaa49a413f327dab6f176663bb9ce1205876ae541a429613d99894e08296f9bd3235f7387264c15f549e28cde630dac9649948d0d95280fb3a043f8d25a336fb351d6d492994d4b89ce46a8aedad30a437e16608d92c5c176eb4de9095fcbf4b29e053c2853c575f73463983eaac3870509b23164fb3ddc871195e157eeaffd8381036a8726a9b1b208368bfccf0dc809a28039cb2fd73dd9d4bd30b7aae769c3e4d9356892d9ac6944224f82802ccc4bb851fd6000df4f52d286fdc1affabf6e26d1bae36b67cd7689fe1d14c51dee26e6682a89a40d5516cc0c0c68b171881bfcf656bda325839a2589465d4d39b866dc4926f341f69e2aa494af9f0597b09bbf92491f92302161d1a54c9428ba0c2ad3e1982d06b87acd00e7afbd45c4407f14aeecb8ba9df46be7fea5b36ee42345c9e8c140ee5c7e77d1114721cc08cdd49a2d64a129dd816270bbe3ed244716433f4b1b89b41e2a37be71ceb57346f3bc79e97539fc8484066f4ad1a6d45951d4583ec0437a44a8dd8b3f4ce7ed4cbe2ef150d68a712c8f6c391669de52856e4c34e5a6b780f855de8778296ecc7ec524874343de43b1d1ffa6369eb56456c45ceab701b2246a8b13353651f3d17dd09f0976763a412512c38e5ad86683f05d2a913be0b2d53aa3b18d09c8161ec2ac9a8b41157a4fb8b905ae1410c61749140a9610c2523cdead96810c6f20ac2f43494536feff6fd5e0fd95cd488aa9acf95677fc7d6a64fa8a5f43e7ed891f157ee0ad7ec9031e6fe58b215f8741f92636242e717c6d44eda8b19b27b420f4c659892c222bdd1ea44a197813f57117396e37196f4d1fcf3d892f7630f2cabfea6c807a8caf0c47a888e71c9677e81c239aea5224fa147f350a56b83a5fc2fb51e10e5c3c1944f8ebf5669c448391130de8c27260315b57cf0a9ad393c58e2b48fc79a98213d0d63eaa7e960b9f76c2e7831debbe525872ffbeb6a86ed33889c568d2480da30768c3fabf89f3a8e92eff43f0a1ee6c6ffec023108e2a0c87e5a08f2bf19ba9071158c5507865ea3d5235f61bb0d0d6a3a154c7e7f2934d19ca1a8ce5226bd10bc683b49f4f3ba259064056317abc448153fb688728fd49c1dc15050a668f2f069e0c302508f59a32a8bf80e4aa2fa1cc9435243c789cc67f48f7b748da8e4ffcaf6a9a44a62e28f2a0baa0d90614f3a281c123d8252dfbcb49140f18b0505d9fc0dab6be41eda901f29ed4d686724333b18639bf0d4e53228ab4cdf7c8bc87d739d2ad3f4622a223c76d6d15b336c9d2b081b3c4f4e6e9112d90e31fc88a25ae27e3888d143287f6d4c133b240635cf890f8f9532864d89ed28942c14115a8129f284146f75f1e8b8be2b3fc93345f40b1d1988dd1b8141e7048d7e18a179cd492a4514f632c831b71b5cdc5d2c296c08e3edc4bd84bec9c46ca631c77735045e9affb18f6573cfc25aaf1d50822dffff4155adb9908befee8466e7ce31f3bad059eef0b93c72b9e158f06a87b77e168b2a67ef910fb84e5b6b17c7eeb690b873af404114a2a2be9f46e8f8e1048425c746f78fefc731c1ab83cd6d7a91fb08cebb99c9a56ae65739f31f057be9f46cce33d465c8d65f478b99604e176b6aa2a09b1537fc73a924ee431cf7d8392dc43ed6ce01a50ba7ff4fe62b53be902e03ce94f0b0e20988cb3c19d00af70bfa220601dc23d3bd6faec1de96ab650f948850246f3a8a3f75810dd8fca430b89150fa43e40aa42a8b21aac22258be0bbdc95e8f78b686e2f22f1d551e667cf2addfa3be4984208f5eceb8ffaf52c5297deae7f811f4c22b197693421a51e0e2e8356c9ad14f2b93d7b019cdc97a4d8725c600914448eac91911eb45c9eb44c352ae10d1e09bec9a80f476476dbb45110411f44644636f154f6eec5eb1629ab7d38e0b0faafe90ccf1583fb74c1172eb03d76546d99d7f9b4dfd1b81ba571050775d56ebb638056d9e2d0c5716c127e0ddef8018d47378e3c7762863ef7f87f030558f375657dea42808145802ee36c5bc16d1d97e32c4d4da1c970e9c2bbb66df29f5dea224b17b98ca9eb4703b51db5a0a8859985edde10d9ff757272825be42cc0a8109ae62c2c801a004c7db08bbad20b84195068d6c4191ba846dc1b9a7603e0c2c4b37c49d0fd1ffbde116c8a191bfb42595fc776946c8434bd0623078c6fc214f99ef9ea6ed35a5cb2e693f074136431dd27a8478c86eb3e50088e0abb26896ca5907f4b1430f8c02126ab4ab5a9b8104608f4e051702c98a216f14a207ba881de28c8540b88fac4d55fe1093dbb2a82c135f117f6875601b16692cd7d14382f926b8c8d1be349f8742e7462c78470cd062897ae19ab3ff359f9166305c51f99eeafec212adc67aec7837c15f4bea665f8f0afd5088b8bd3424b2b611da2bd47badf46609df07818b4d0934e8e951790715d7a601fa4ae010800dbbc1d00388f0861732e8c682349b0c0f49e65b407e21b0a08e9c980b70d32b47ffa798461895bc25f500ac3e4d5fb51d741e58b1f9a167bd5b9945a3ddc09dc42c67353fcb54d1319db3aa3df8c33d6eff9746dd3eb57c776d973ee434d337b9686121737d61ae79f760fe395e8e0c1f4b2bffc23fe3f628aeaba0f0abf686c981aab278e60c908d99a56376604defae8499dcb9743ec28bdacf0067557d11081b838261ef177d3cce8f8952f5aceb93ee5dec05a9b72b0570740849f14206f0f6592decae6798ef6ec2981794ead1a47d797951e8bba032fbe5e5fbc0c48a78764417561a9d163abf62d10749a9f8c0e5fe97974c43a3e22fd9b183d069094736543af9707fde8c3f3c7b70e27886391ce6a50402115338b572028b6780dafbd73c757da226163d25e60fcf33dbed867e44c71837bdcd48fa8a048a412f542044b1a57cae3f193ca693860d8c5a99ba178a2f9701aa638706080c7cdda6d30034eec565b8c9cc0a2956a98c6cde78d379d830ec1de07b796e29bd05fb3ef194f30fcf95f4a014b4648ac43335a442574d14d28bcd5cfade8b47f3a04528e3df87fc40eed310c05c72ba1084fa11f8fb00d328b4a598d2e1f308cc157ce34e372dd4a4ab4daa51fbd758a694c0b456faa04b2dfa8fb62e21578df94b8f5d7c17ccf69a7b1e78d5b855aa31ced252b4d8499dc987cb814677c6a2e1d5b0144835d35d0342391b2c9fc5675e0539b3624e8b70f0985155a0e926c89262b2a0dd9de344bbb12de55f4c2d831f8ca57ba3d7aafb0de8760ad4c2fa1dd68920c5cbb781de8f50588987d9ed8b9a5a31effdb2c7c48a326a925fca91fe34e81306ca7840bd5ed530b2d3da00b7fa47842a40cca56172c4b75e9b846e3e68b28ff9bc93b5823ed0878aedb3b3da7ace3011100281f4833bacd9e843274d8c61106431cd91683e8fbd096b0c8dee8ae9d41530e0c3af3ea547e57ce92dfc137d802ea04c069f1c7f71befb8d50398628df008960b26a1a648986d613f5575b3956c5976a3356b09810a4c6e98a1cd103d5f73bf68d0db59cf20ce28757b325444c563096dfe339d3c639d752b700bc14db2309410451bc6bb7cb7e49a24295c90a4f4942d1361d8495008e1e6c6a82cbd267a1b17a6d8884f0b3caf3d567dedff845404e6341615c74c9fd3b5d3e00f4f755dd580a402494d6241a86fd491401b118df523afcc24b24cadfc49654c1eb0cd113b1730869b3c3d72755c9449ffaaed01bcb8c0255944f86113b9ac94dc00141556b265b584924ce444eaec4baa44c4f52adff27555cda04a242ea2c3bdcf1dff2d3c2b05d4a9595ba1b2834a1315e7c06ef39013708bf2c36ef52dd5d3ac2c4ee9defa4336dfc5f1d637d300009a91ce147c742580f634c27fd45af1dcc4bec61aac8736ad200ddb153d459eb993179a5762271424842978cc607b322c03894225825b5c87dbb4de99be1c20b1f5bb5174483e64180c1c8e100a345857e695434ed0697c127aed7632bf64781a4f42efdbfef0fee4dc4bb6aea5329818334c38edfb5cdd376dedc4b68787d39b085c29912b50d5442552a62cb92041d97c954670b009fc6506502ae4988727d4fda70302c2f52611dc5874e682b6a216f0b2428a871057df407640aa4cb329d0ac730880b9908b7b4aceaa5f92edc6d362b0d4aa72f7ca1731c177aa3080f93881a6835cb1a1be1ba0c9750e2bfc10c57d91e46406eca76b4de8b2e06e076058f06c02f30c46b0af71d01560bb03729fef4c465afe1677f13172efc1b04eff5272a84e2b08d92e1a9f88179191b2842fea8b0d5b776481aa73cb297fbdc4664afede8631dababb6329cec279fcb415a1cea4b146159c24a3bfd1448a4dd15e7dd9df0614cccb864cfa7c68e9a1333e2467f9e4446b03500edbb57404a0eecd08f1247a8452c697775eb99af91c4c799861c490c2401671896b96230ec50762a6ed9d311146d9f6b5678b7ef88fb463d1299e8ad3e5c814405600265d4d10c244c1716db39659eb5f105f1a6376d9eafdb48a02d3f3c4d6e45bb207ae473c55d77313548aa64eb97a49bb58159f5fe1686bc7ad8007c93a5035804f2b05d7ea447865845c7c73f6996ee168f7958ef301bf4867a275c95d8d4c37e7f69986ce677822eb54894886f12ff924968ce47cbbcf7b25228c6ac7a30c68eaf14c9f7faf4458d6544c7564ae0909c13e0382ea518979c67dc96a73a64ef07aa354f7cb53aa5583732c54389cd7ee0dcd894b565ca96db018139a9ceb312b0d7e66775de1f9003c38b4c68210f6c3483849466794713b3c3c46be9001ddbec50c74541c8839029b8aae8912564278165c0fe124b87577cce30079f8e3f1f73d2c22b72fa98cb0baf48e27a1ea176ed20599414c4d12a3dc3e1c21d584527a4d2477c5e0b21a94d102877761815a21f829aa012f652454e14278246f284bf5ee96ccc780a986dbbd1bd150f9c564503ce8aef91b05e60e16d926fd59e0589ff5bfd2d42f9dfeaaefbd2c75f109271d1068f71c57c08f675d4d56837530ceb57f5e87294f951c481424359620220e867f95f407b2f63d28dc14dae1a5d4cc34d0f113da080207531035290ec9ef040bba745d148ba49962f854749a55e45c9788aab6fead516736ad8025a5fc63e92e4d8c69edda99e098a9785bd0ec8d7f21c024e29063abec8c5345c73a127f8cee6c020f4e5e48a2a1a0c6fd2d8b7ebfbc17e5d2e3846213f862d357b5d063cd20ac64f11fa119e2be4ecdbbb573ef290cae652d6538430ace4be6c901973c571c75d3fba6e0f7599e04da256b534dd821b4a0ac31ecf1b2177888bce6f74c796911eb660313b1bc6c741008acd0c088535da93bdc8c51a0a390a26c9c65ac70e5a7afc89b388fec086a419e9c08bbd1a5ef627f87af9ac6587a1988653fd6a2e4df44ad7fe1c44bdda46300ad05f29145283270a4504b87083d15ff538a804bc0fb3b18fc46b5d55c8c4d965a8ed80ea75980865979ce4c69e0020e78050c149ab007140e5c186525a30231dab690c92ff9c5af2141cf5811f87fd81addcc09fa12852fd50f3686df41d1c161394b00b87586a67e220c2b0b3ee2dc82f31e0ec0b0d1b31a7e6523edf4a69eeb54ca07c6d91f1ad384d18b0803169a1212643237a0a01db65fc0cea36a2b4f56192db3d1b557c56e85cc3f8fd63010ea5979358093a0842388f2f80b9da40b8f70f473ee20f44a899e13925f358303e603e6978b8073c6a5263ff649a8ec2c06fde3f988e5982168bdf7178be974766b516d312c4cbc5c3fa153c9d1b941d2c10be3fed8130ec820e785323d05e31cc68a0a5ddbe30a85a830e831e1f26a0133d6483300ffacdcbb79ab2849de617fd0f9c6029fcafa12e57bfe420010560ef8861906530e589548c69127b7322fce3bcdd899da7d1e47b7d3d0cf093db181c9c1096760976ccface6dbd19e57780666a5bd7f51364b731c5b08cc0c20c2f85f44b2118ff6dc6bb498b35b2a24c354df54bb2228430b2f43dd09675311392ab753368ef1c5932296cb7c4f7b45a5b2776012b9b52fa943b0ea6d7abe09f478cf3207b567c106a988e357705229a7ee1714373ca9f1666dca0e8bf86d70a5bc68168418d7aa561738750ca38357ed2e9c7c5b14badea0cef976453fbda87c491958a7bf9b332bfeec1bf65da27124079daadceba65fafda170a0ab00f12ca8af929c2cd95ce502a32ecfb7c0a6b7bed49c7fd0ab1b8cac78861694fd513354b6592defbcddadbbfd8cdee8e4184fd73cf9ef19f230c6e48899b91688f731dccc91ce5905971ba0779107da53723a7130fa3c984623ea27b3e7164f4409918dd16a3ec41bfb32211967b01b800634280d01aa92ed734d8f277c2031532567bf623642866da29cfafd38015e2bfb7fc6507fc6ba80182fa7af191b7ce470dc392a50219cb91ada4828180ad2d34741f83a8d1687d3b522fd53edfc122f035c689058691b8b68c28e3e2feb960cc90b5fdad2cf0063454c98056fb15f762d40ea5dd922b14222d574d4e0b87ec437e01010b8921a26bc3483357c81239004ad834996ab6e6072de1172d13b3a314f8483f731105c623213a5c561b2e2036cbedf334ed7b22f221d702a727b40c27b04162623be80905e7cc9a4d651bcc7947ad49b11b2b945ebc3c366ec451411304206741d38732f108a3d4f6c90369bc1b60122b88f935b1d74e5c7a6c501f7dc74e4030bee3e1d05af36e55dc58920df7354a602fab0d5c382c221070dfdae50918a263294749bcdd39b831e9d814e143667cdcade992ff6e6f8b5561c27448881b27fa8ffc333e1c5e62762fe753ce73f26a2d793a11c905a0a86741a82238117d246ae47f8f42bf65f3111c40222a8b89962af4259d12b6a90656c9cd752a1047a95f7614428fe5ffac7f61f567570c5462279f2180895c0c1608962c328c871488d8fcafccb37038aed4500a23396fe6cef0d42c25acfd2f2831820bb2f28367c86da23f582fdf99e80bdf05443e3cd08c54eaca4285aad8e413c69d8216bc4866384ddc42a6ab965885a083d88d21283cde1294dcae04f45487e52b9c1aea9d7cf24e8b0c5a108f09050e6e59d1410d6e7b4168ea0f7a2853c891a5c7d431b50193ad1b08ba2f69d9ac9fa57b7ddf5641de14606824d2d133d47a641d2ffda4fbb265139e28733899a45631446c5050eee5b2e8a7df90628f4334652126d874b6ed888e926d6174718dacca2a47bd9a766efc17302746d16914733c7b529a06609a1e2511a1c73cd79ca22bd62f8651d5a3f66a506accde7e704b8bf771c41e1eb04c061f364189c4b873f4e6a186c660b858102566c91e83f409ddaac4637e5e314499d009188b7b41be1394e00c7f7b3b18157e321e6525dc3d08adf567363a932577de6aad58ac56361e4c412e5214abedb7132ca68c86a5fb59e942a24b413305f8c0f6c4a0f52eb387d8fb1796a1da74240aecfba0322c880cdf72f1c39cd22c770e4cbc0b363c3c1157263f027249c500f1eb004d598da55862781a4f8122d70ddc53df28ac61da37b17d52f2b274b86d4f2ab15de37b32db7a2d97ba0d21968d9c7c0efa2315f79ce7d14a6b904446bb3ca92c827cbc4218e9099fec778799c147f6ae37083f74c5a7ce9a87885be5acf5077e3f093e6f8c24c0fe087e34af71572dad2ab3085465397cb6f0291a61f97ec23c9703b2c22d27d4b99d6c9e68f0f8740cf3a0abb434875d1111d5c7fbf86911789f053d49f3bca44652964800507de02473ce59b716257a8c059f3da51415652668b879f482db041c737ee41aaef84c3118faebcd7f2af42adb9947d13a9f568255bba055c9b7920fc636508ce79a9b98de6a05de4a6a506fb3d8b620d1002b981df8b07aafa22a099a2f84211a159374a871ca9728348ded20f3b30a49f5583d4208c42c1a9a0ccc3584b001602e2e3c47308dc1a882112e3b2cf6ae3843bcc06d6c9ab2417067ba1baafb4bb3fa623b3281504526718c7861813e1ead418eed80839790296900505adba06043d95efab3ca0a04a7e37eb7fc99c45070505a8017dac560730443f961a8d18f1de924ddab207da8a05328f7c38a45e3969e44db0c4314e0b9ce3ee404ac54b44ee800473f4b82b065f68966f982088bc9cabb83ca7803aba08e38682b20bf497c81224024f812719be280061cd0b4d15cc1c74da8362959fc19e7d01fe12fb02196c6d072622ba9d838f115397e0163f7ff490723bdd74591f12513a39e9995217def063d14a2b8ac78955c0e27c078a4a4e09414d39ed9096751032ea0341139d1302e1c0f1c55c3cea4bc1e2d0711d2c8a218305be3239d29472981f05faeafad98459f55cf4f2ac700db31cc5dd6cd6a0dd3b2650bea8222fad010786e4a8e2bfec7c595bbedfbed7561598294e2dfe452adfa908884c8b13cb5ebfdae5df7c0faab7ad5bacec19b54e84967f2a09d490cb4892aeedbac1603d9beb3b30bbe46c5728e26968fbd36be8531a91164c8edf66d29a97c267f1c241eafd97f1fb5105ad589e4fed285963dc09a45857ed6beb27392b040d1680ca457e0790fa0e0891481df039a147c10946272d7e48ffe9cef35530a2ccc969b5106d90d9d6abb0690b129cb756f8b91b3fdbaf9c2da6add27c41b20668813cd288da71e1b9335e638ac34ce12cba045d40280e6872df8a8f7046ad982c7d54375f3184ce14ddeb07029144e719917ce1266838053c6ee66a1814de84310b64ead62a96be17a0e7a10af48b2133012d920f36d652eb2faae56e715f1f0ab5c3b2d482371fbea69c19b9993444754d2594ca29934670408c81bb27115f478e81f8724eb999067937b5915555485650ed5ed7ab2576e97e138ee7f164411cfb50fbc2fd9480edbc6fc1175a2c5b7eb78a6d98a768332ab1da19e0041170097b2d9082195386c13893cdc9149614e29d3b7d9cd11c583d1669b0460d594fd919bd425616b11d283671b195ec69a603401df79db7732c04eb8599fed9dc5b62ec2d5c006b1f1f2d83dadfe4a7323b40093b9246717752cb7e65e90f62243747fe2987e856b7daeab152fc039fb6f26564833e6abd83a76a60ebeccf0d0bd6261e5a20139efd21ffdab2408860de85f0916287044d259a53f5e18efd01a2fb25d5078a44c0245000204e33e195703b8701e7bcfee2071e242ffc5fef1b18a64b6846569ac04a4347ec80fc18b374b720e3efd919dd78c2e8fcaf7e3182b4d8a7ab3167fdfa38af4d8b65bad2f82a8a60f8e9da2553f9e67e23572bcc447c072998d2118fa4787f5d65376b777dd27f698787bd990926284850ff3c5dd7657d186d4e4d3b2e6691da462a84a6a2c696c07d7e98f95629937534d08a6cf0652ad72ba6b64158e18549e183c274916d3c9dbb488b8ef5dc44b982ee0457b640f598c4065cef04ecd8cff4f9c048155231c75625a605029e381fd70b720abaf3748428bddec56d56d69e6d8906d32f95473717b571d0efbbbc53a63cffcc2e787f52d5b7b9d9b72ccc46766ca8dfa0cba132132def3b12c7132809df225714d2b5397be90865b2187157faf65fc07d9e7e7b402de36b258c51aa819da95529186bcacbc452977d3739e71f8370e65732031ee68ef6d6e6d74616df4e36a08a23ff30ac03536c2c60124438bf34a2826387723ae592f7f568f24777967fb9af202da9925a89fb58006e3db283dbe8fe38c201b9b421da8b3c9e9055c98bb2b4e9df5aaff21b4632e1dfb036558fb4a2b4669a3bf56cf60bb5c77b3aa117a4a15a518d13239e2206d09a4b53840dffe00091520df8d7e75dd39295d95882b21c454b4e209bd42b162830e8bf7f96548321abd195d698f371f1ff3ede47c121524228726f1c78a2a6e6b62316f5f400d6ca85433d2264441645cba220c317a7e9f6bdad69e29860da2d9ce801582d9371538fb0754989501bd20bd5510cdce6261cd1bf951f03fffaa11a541825e982f3d419bfc6affec3d64c9622bd93dab1e80028f7d21903a0ba14deca99079fcfee047be1b454fac45ab618ed190391cd69ba0f06d16964281e838874d30d674a05028418f28f6d4358e0ad2b3e187691c83ff119bcad2168130ac179160ffb4fafdd42a85ece6e0ed3836f8284c9fcc7badf5cfa08b6f8dd8c7de427e01671dcb9dfdfeb88efc756fad02b753f485d27fd0f10750384742e490811a0df075d8ddfb9f89b91db84317fa6a9f2f3311b441bb90d033862b2b0c4c2d4225b3a8e506f02d9a6809916169f40bdb1a2d3797a945a2e3035531ebaf0a4e5a22ff80ccda01c75bc80cb51a443ccd8118cba8f907997d1b6838c4381102cb7e118d85eb88742ba2d4a0f95500c28f3126532fe8d83e774f707a7ba15c4d572421e531e1ba9a48e30aa58f2df2481f4681d4e7a91a8060259610d72f3f492b93d817aa1931d83c134cdbc2b7cc210b0d8c59b39a1189c11abbf2fca25d2e4c9d7d5dc0c592970536423940d38adcedefe4dfb82eac5dfddbfccb4b87a9324ac25c5e1ee053662b7b8ff77860767065449710091edc4d29ddab46b14d2a6adc2941b3cfbf00da915e2fd80302fbe13439097f9c1df4fee84031a859817fb5bed1c0c059784b4dbbad6a6999763b10d92c422db5985b15f7371fc32185a012f832608ba05c8148322a76ecb4a58b305f8ecd5d1b754ae39015f3113d2217d24655704c9ab250d70d087e61283ac9556943440e8b9124e5528f6b1a95f9c8561254ad127131b99de066efef0d6e158e2b43eb83ed34efd80a36722e349d7851c3b4770ca23e7ecbd013ac9009c7846824896987a21aad29f745b60b826f636d467fd9e0775f4eaa3958b8ec6cdb55f3d1578625982c49e87ae04ac8a0de6bab2d6675200e91757c2bb587819e55c2d33ccfd11ea3e2f1ca580c0fe9156e49430c32c981fc9701e50e40f282de6968b85a51e2ad833d8a66dd101c8cc7d4f161d4e9b811329462e4c6ae3a2557d76fb94aaf870ff7dc450c59341956d140c72e1f0f39fac1a0561c5a5f5edfbe8dea88096c18f88fa291ab005ef4b2216aa29458a68f41baade82ee2b2a82dfef8b9e49f62a5649a069f27db03f547b51df5624b2d3bf161ac536a895251b01c5bc9c8ad48eaf58060d61158f9ace219d50c2ca508a2d24355a03a956a402a454aa0e531e032aab8939b72b92547547e51f27b532f8ea8a0520746e50db58a8112f8e2ac5e1459eed3ae78a16e36e939db1bc772f1b8ffe340df329d2dc963979daa1385b7f8eaf73eb4272ccda1860647b6a72e954feef0220216ed1ccce8e9bc69457002a777af9f22ad7bda26631d7eea35819c02ed20440d77cf196e08df6a3f2300efe61f79ed558f064d3f0b9321395a27e82b79f57306f9eb39d0af7c76e422602881804397bf92d2d44a7bda1f4ba809271d44bb70ae909de3994fdbe8b545444d99c14749e5487d8b050bb470e6075685859a74b31649786abc1ed2b6d4a391a6530c41bd959f0b28b98c60d631296d7e781992ea2e1dec56dd8effa14451979a531086b8a4c5fee084ab3d362512bf73c006bf11999c04a32c8f4eeca2ec226beaa6a6836a4d1df9d08f6bb0e674b95da4a1440f3d638a3455745610df21123aec08109e92333edf3a5ffdbd8d4b8ba265880616b8cdfb851dad088077c993e09c6a95cb2ac3ae40b705b141d088436924f5573beb879f80216e1141f172d22d4c1e4ea62a490644357b1d64773ec29d9ef171c8cbb37b23f265057b15220aa045525ebb81e9f744b2cb244bea8edfbf125fdc825232d730473366749b317f2387dc0274f1db006575d6b99f6c8aacb091e4fc25e3b773f9440751a52909a9949ae55ba77b6d4d42c9d0981bc22ed5e9b2ffa44230025ae146493177d735f1d22b9957ee5bb1f403b06e97018836f367281df1b48f3035563564c26d9b557e0547e2095fa815435778fd84c691f8f11d20b0e5081b8fd003146b9c759ce04f997e6b777e3d398be554d060d6aa4b37131692530c0de72f01002fc0154eb6c36e215a2b9ba11d78a68df73fcde1f7da2bb35c9318e8888abf3679812dfada81adf2a1b0acf9b7d6e473ade6bf448e515c282d6422ca9c4110020fce98f03311db4bd3e4148377e279ab0726ec545387e8ce818f0851ee904b87919cce6ae9b8772003e695dffeb83346f239bf4032c4a0ca4b165972ccee7073375c269b1f3892ba1a688052879b2972feb050b168257f6d7312f7430bf385664a798c70028f8e8d94ed3f18f30a09b56d608a366511e23401846c0aff18fe00902be637f440d0f704f10bc1f0c65df0ec7b99d0d12bef4a071e141b4f108f2f4d4b6206d81ae9a765b4c82f284132dc5abcf73ea1952007996a811fb5b4b6457023abde199091af2064132e320431942fd952c3056498d64fa05f51f22bf7316e9386603e4ca7219c2994f7b9845f076c62216b2c50604c9eb1e17c87927dc2893cd0b949164b79d9d61fd0be48d688196eee8b37907d00266c83d60b634e77b260b5fbefc8a0cb8442b1e118049424cb87af41f1c72045d7d07a20520ec027b11866771f705a6730e1e43751b74a880cf76bd4296339d0100ab47eea986981ff52e25b2eaa703764946fbd503f59667f74caefe5df9b697c35ee53c31a5007f6ff02b369c32f376cd79eb8638643e1505d9f516f0f08a10dc31d2bf0406f717a40658f9d85f8a74821239cc5c94368380cd22104fe216c1986c8cfc41e16692d7d038fb162a10492272c2a6d49dc8c2b8f0b2502dde31f63f0d5fb6166c86b0fc4b2208aad8fedd0e63532cdd22c64062926946040ba2d08a7492471c78a65a31fc0f14133c208f19214117ddcbcf057058942fbcbc4161e03e7322d4dfccb0aaf22b5978e5d272c24fa137a7254519f0edb52c4dd60e87b3a46608262dd904a925f1756d375addd971cb4f2a1c6a4a7c12daa2e88ee9fa0143f685d8ef0250dd1d607e87875c94360078bd7101c3b4a12c9278927a74848eda0ab9372818e7204fc10fdb7cc71c325af0cc343ecd59f3bd1a13152fb7277fbba9fe19c2f73f1b933e903102905149a4bc2a788436c2b70507fde4d05d1bc7fe754b9d37cd5d281030333aa96fb66d55aecb0cbdd3f7da1b21a365b6fb9d3bd64176dd31f02a3a4a206cf4007fa9c9679ba1a8568fb555e0a33e34b50f79b10d7be6cc7410c664199cd95bae9a45e56578c940c1b1dbd09f80caf048ffb6356e715935457c5ae1aeafcc326566f9de4cc490fe7de954d81056481e01d599199c571d3150e9c8126713dae268046af531b95619d89193a60b2d8ab5805b2aec567736760ddca112cbaa16e2d4759e4cffa8f665bf477d53d1964f6fcce8530092a21b9d772f013dc3aa6a0206f39f7baaaa9cd2b65956de2521a6a8be45c43d0db52ecddb49922b660b5604a1cd354cd91b836d4d65f58089b317bb44d02a9f14205b08b76188f868136d1b23a506fe4f2056489b403560d70052ada25d43b9563294bcc4abeb1a60c9abc093ade24904871266a0ec06e49b03c1319d7fb77a0815e7dfcd18a41f980105dd181baacd302bfdda9c7f0300084e40a23b1da504a871aeb02f73cd97ac9c7d95204101360c8ff53e2a8764c9cadbd090ad1adeb896f3ef8fc7129e5a2317068deb551efa5d2bf42217b55880c45009260c53f781af5b7f8e64a60eecf0db05c6892c8170089045591fc704d5f16f04dbfe4cd96a197352be4330b0be58e54652717f30a42eb86d5bac1742816a00473cce686b577db435f7585cfb5d466ba0477a75193da25fb4f50339ffeeebbdb9689192bdcaa6ddfcc73edaf9775ae78bb5ee6312d8bf95f90ecebfd5e69ee8ac9cb46e0eae81e67f958d9a1081136dca708f48c3cd561a0c5ccb01841747c4bcc58bad051054c5b03ffb01493d39ce3b6e2238ff16b5998ac60d1e461f2c37d41562b52b55fe72feed90c5519f284f863096b14ed4fdabc4275db3d389d30607a634a8cc1944cdd6e1fa911ea51f9ee97b54f3c7bab1dad92986554e8ab00c5b715c14253ca2b1af9ec9f910befe8163d522ef354f7dfb3bdf13025f5be44cd3f2e2843c53ad033c809f382f06dcc04c1e3395008e3d2593b9f16f7febb43bb7be8ee6cc7db664a6d6c288dbdfb79513b868d7866dfcb85aaf81d4d376065360a214f6cada5885b0f90e547f36350c20d8970680177930925522389cad097cd5c3b3eea7c73310712723889a4330fb7c17c069f39e600e0a26a0bb9a314821660aac6318bf907d6a3462e03bfad9540431962327bc34e4e7e36b017cdcf07f1663a89cb790a4fac4249f7ee4b8ce74b428c75dce83b65d8b3aecf96b50942ac0ca0c10fb1f83a8d25647a44b3e87870c9e97a16fbb4a4b7f55cd8cd493d952328be1f32f03ea1952b6a3270cd9ab0262904f02850e1c48daa14856e448205107e4f0b4036d3ec66ddce3cfa6d3cf339f980322210a43db702445fb8a4ac600b815f80fc11d951c7f50c218afce8573221f27062d3bc48cd9df9a76cdc2afaea9e7869831841bc3cc6fbdd93299e98a6729151657b83e6f62875e571d98a4b3df092d01dc80b64777cd0c8e119bc30487617fbbbc519250aae3e74ecd785a87605ff383ee08314218cd8e8d3c8619d6d0b25b08b0f7f78ac4108f59d452879e949a8290794dbe5390d15a8204d0f58bd450f30348b0914b78c71a4fd2ffa14c489a2f84bd92882625b66fa822540ea2c46964c857bca71101327f6b287461e0e523ab4e3298c52ab66a655f3283b16d5d613edc00adac5c64c54939f1304cda1257093071d2c378cedf910dd05260d4788cb129442005c27dad3526a7e3b39a7d2c6c78fd6eefe48d61d7232d0faef1ce7faf1d81b46c6b9ab63a7f5cb4c798e772c49dd557a1d224485286fdf2839b5eb50fbb5f8b60d090917e63b4d451924606885fba6c736bf2ca686fa384c427a0013286beb4c47c21ca6c525d1ae9107b7599cbd77b8ac45daf7ebc8ff9d7512cdec520cc3e38072d253ca9496dd868c95c1de7bcb2fef3bd765c239b84b42ef207bc75b62cd67781b7406e107bc6a6ac3650db599ea0838a17458810cd818b5a64137fa27afc622f06b188492cb114ab58c42c76318b5d6cc4109b18c428a662885d8cc514733188254662f9a0faa036bc2e2ec1cef97f3134cb59c6fe9dc2ff40e18a8246adb35705cfe3edf903856743f7c4439de7b9f9c449c56bb079eaace771dc727253f038da9c3f56793ee84e3a54799c9a4f9fd5bc0c5aa78e5a1ec6eda777051e63cdd94385e7e3fee4838a5730ebd47503df390ecb382ec1f962b2aeca84bde8f8aa162e8e5a87cd1eea8d975f3a26db7e6d87041da72815c40b3e1a71f838b31e40e51f49555ac5a164e4a22d9cf621658987b8f4650154c30ba4333cdd4ab8986c6c3d9bd20e9399329afeded505233b75e80f480ddd09ed2d8f9bc172fef3a7f894eb6a7f5fdfc96b1e5175fa3be79f7a85ab6a6ef9eecb275dd5ab68bbfe8bf1566fe9c89f015fdd25d1b040758a5a70e9c7deaedb79c0d002d2734360ce82418f1e7e457f6d7ae12502bbe999d564a520863d10c33a1d80194902e2629c72533f21c4c74818744a1190f9bdecda54bb784950b7d1c2a9a9045672314686e6143ac8850df6d895117ab103e5d57411292316b153d4b2fc9ec906870b2e4089ab15c1dc839562ca68de93ca1a5728985497d21586cb19edf551d354ec1293db0e5a32e73173801c9c28988209caa57f27576eb651c4c2f4e010282096fe0a63708f69a3f4a7b692a9fc3aa204faa4e051ad85dafbc563bfde7a11a4e7070756c638773a9ba8ae13036b61f6002f6c551e28b67703dc033867b0804f22d60be3af4c42635009c2f59d48de9b6e68692b0b838c2ce52c70d7cf4f16c695b3f576732876d8ab0c90dfed4f09dd79b3d28b5208d67c614cf83d46fb6ebb84a599c8431b181e06ad6ceb7f8e0ffec11f463e48276a618854f5342a8eee21e42ea568630a56e384003dcd006ab40f957585528357f434526e81355c1f78f8d3613f0d2c452121ae9ebed33d41f35cab4081531eb337faad9e569ed7ab6cca69c6e6690a28437fed56e51ae2f5e1a3fff5b49e119cab8197d476906169743df3d2c85037105316e55220531474bfb0d27a9a7e74535895f30a3605708e12a45a5c608a99441e198193c3d448a3d713e972d1aa98375167abe99b2c33a65c65f16fb62a188b9f6e79a80ee63197f93593b22eee50b3e97c092de008e2960ac6da655558a3194982bf53920174ca53615a3cdcad745310854554c4d9b729f6a5b78f4c79ff2c435211a0310f16c06b2af31d1f2ed06f5d76b1a54f215cdb4dc7c91d2873d690ca928dd865627c307cc4384d50d41c0a8e16421644f13dc163dc23f8843718361a6d411be31d8f781428c637dcd9a99865634f07be508abdd2f51ed85d69a688be5d85167f01c7a6a76b431e611ea646261e5cd05eb6730a85f09ebae16c7e03b6727850265e150a6abfc092a1023301c3c03d2caccfbfd58e6f3c7c00459af06ec694a2cdc843b597293b5de503fa919671dc3af8cb944daffaf94cd6b896840fb92dec6a598c375a7596b4bbea60ed9f79b5d8f2e76d775c31ad22dbef348572da344f76e969c85757b71dfaceb615e56ddb122f1cd9f82a6c54a278c00799b91e83e10425d5f19e7b1e159732d72ae72917e66d8a0ee66c0ada6b6b7e922375ed4d5fb66e82ba1501816ad6ad96cd723d708800c19600861f4d1ebd7e35ac8e6a89b992b4081eec28c668723e148c387735caad5bb76b8251c7d5e2b568ab44871f61f0359094efefe76e1ee50d17978ac0687aca595c73926dc39ce7abeb8341d974d45b6e21ff4478b6c2afa2c2f046e363138627a889314dcc8bd3c0634bbec5c15a1c6b83fa62d559c06f3113700b7253d96429bcf3f1584aab5be9cf596603636a91fbc1caec3bcffbf636aa8b4efacd7a68629e33de05bcbc484b660a31de6ba371423fec87eb16091c9a817103e71fce01707274bc1c5d83ecca0f66ee1ebc4aa35addee3895c058464194845d1dafcb0c459e41c327331471cb2c2c701c6d08d8cef4dc8912d717bc29b5a93d22009a203520fc2cd30c781fa7cc55ca2a30b39e7694e681f32c603ed50e932ad5b66920a485ac438cc369e6558ff914efcdc090fd8594214b9f3e652fd15254421c558efeb45568059fad1a16a815642a04a3e02aabf601c2d552d4091db70fa17d5c2b34a09e653bb759eb4ef19ab34cc34f446fa1bcbb5e5b0af34526d03525308493f37343f74a41b32ccdf406758e8290620f949966fb7f3aa909d4166858f50355b0dc034f20f74ae00b2772d7a4ecbaf294ca3a843ef432a899c17d766e379d1f8826684bfb993782166505e5fb2178a5888b0806974aefa33fb816cdfee28e99502a095fc6203b905bea6e79dd83d27197236d2842282f458d5a99763ba828a9d1a18bbc9a3c6c1fc29e93866e16015c2f66af753f47e9f8282b7405d177708b9b5f35cdb38783239668b79916104545e7e94a0516b12320451022ec1a6d734bfa0d2e295734d5693429d8ae316ac7f487e65b4096feee83a6a385f35dfb44cab51bae73d82db26a01d4bebe5ae283f5ba9898e52b83944c8eccccf1cd80c57471e690642d59a32780d5386ecb222697d6ac932786472acdb66aca4534386ab997080e23898a3c27e5dc566da879a0a9360d1b3c9fb8759ee801c5e4f15c5b50dc628cb791187e6288894b987ef2f101f54a9c915576209afca34f10ea5ae183525dc0146b193e031e4490acff408fcc3651e7117c3eef2ff3aac8f2dc8c7be5c02bc68f2634f143603893d9d5ddc869e89b76add8067f9762fb7fd8553bb56433851755cc75788acda8dda23ba7e6f1c69a60b6edb932cff09cdf411f45bd718c3ad034ec7a7dd0ba0c09e7d1b15a65e5e0e12af7bca2f0533cb10c00663bd80887eed81f7a0d1ffb6f8da899d65d62779932fa20535a20a688d20071b2a241f642a0709a77a875d6f0cd161bc583413de01325bca7ae0407f4006f5b57ae037fcc6ad0ceee78041b3ead096342074f0c36292cf74875dd0487164e4aef8e7a30e4fb1b311b8ab5433e05c7814f59f7140286fc13b63b2e6e5c71720b3c278d67fa0d59d2667b7ae2678bb70d651b7b0e79b5ae61b3703c27341885c7ca07e0a726f66c6263e4fd504a1b1b04bba7b8a9765fd4cb1b9edac491fe75d3cb13f287273c612d62037ece9f92a94d6efb73d6a74d8b878c36192342b40220ee292dd88d3da049616162429a45871a66e22186f2547f54d7374c3a39829889c0e84911a6e634787e94f92d7086319197fe8d021cbd8dc54829be543948cbe2b8aacec34202c541e2854a4b6a30074bde60b1313e65362908f729efba3dc3d92c714ccfb2a2131f1a9039a6d93946a4b04c24e7a8c5dade7cac4503c965d02476816d559c31373000786ad66e8695f53fb483607b91caaf4b169c6df68d6d8ba3b039132b5188479ef17c16d0deea0acb4a7f961546d801fe6295e069a96e34b9bebe6fa91266ada1fa212ead33b1001f5013249bb947a429f68e1213c3e1c85029207415b75db32bb1842fdd768eac568322a691edc48c728763b9fc7a17c5f71f48d9c669c648284e6df56aa47bd84b712297e0342ebdd31d07484b5e716474a71a064fb838bd8dd5391d30e1a537c1445246f74d4b92eedc2990b8c40ea10a857777a08469b9c8fd8b256a4d6da9827d13a11bbcd49565658e08558db8811474c0c086bd1e8a25c100f51c1ce9dc0898285ca6478d56e734a8023063239f4a30645ae0aba737fa5186d9cdb2580cc54bc20058d276dd099e59c904ffceb2dd13f8c7682b62f9e4aeacb1d434b22762707683a50d46715b63035284f337c0bcdca6b13cd4b943d24cfaab738de42092c089519287fea91fb40d8223b7116a4a0a2080bdd7dbb2f4eedede146444ac266ea2df7aadd47c7fa3ad9b9832fdc966710417ad6028bb24ceca791ff22ef5e71c57f98a2aa8a20a6b8ae88881f85f489eafabefa7c901f5910e958711cef1c78742a288e9814b8e87f0a46e45ed94616c4a0e14b5f1857818b959ba3aa0ad396a551c9e86bd385413de9a165989cde21bc5263cffa6f2db55f99d18ab9f78ad23455727ea3ffe282753397ffbcb681e103d1cdcfd5b0a6e9cbaa1bb35a14084869ab427dde546b793552df0d217a45c6e885b9cd344b972910370c6130b7bdbfab1ee51af35e68f54207c27dbe106f527d660db7abdcf05c653dcf5754f0ceda6c2f6a530684de50fb8fdb27058db71b3495b7fa061a22da7c68d02c004ce048e861253a0537156899625d67685cee75f2856bba9f8540c62e01c3ec1f5f927527d639330bd65485abb652a14aed4c6d019e4497172183ce7196056f4f98f7ea348cca50766cef58da64849e0cc30249c5192a8ce86df5641e5b1bbfb5ae7d60f5962c1f5d08a38f9e519895633c129fdb9313a46c01b7b018a2eb0461d5d0ea377cc922d56ca7698016c92f2ab43a74cc6cf49cb8efa4ef94746ca4cf543f49ed0522498177aac8e9a43e330b2fd2a4ba5fc201f576e6388e055f20c722a7659dcc29f5052795aee158b618ddf62ab74d0c5cd1320013f4d4ee186ef20852a0d6056111cff4c4eb9a8238ca97092cd2e65fb265335d1001e91ec5b456665a93fa852205be7a472f0932e199794bf2d0249a6ea49a14aac1df147ff14713d02373231c21bb9d2bf3a48a9d3942c81884bccfe2057a338c869b917adf4d4af062665a182966453cac1a89daba2e2eec89771621df36daa7e2167eca18fbda0d98cbb51e6bf0721e353fe3dfd194cd2c538c1ae3d39f22c089e96423cc5ce829a7c63d3ba68371cec95333f25d44d0dbc0e9cd950c7a140090c04599c2faf5e139df5f699a035b86e2f19840fbfc8dc6e139fa072574bca5c8291615e1b515670880bbf72a8e1a36a97772a6a090a8608bc520df35f6c7f76cc8576de4d452d8b528be9589a82769df80584939883c4dced76abf6f8e932f0c0448b65eb0207d1603b09e36129f2e10be0e41466b75a4b8328a6eea632670f7a35aedf3e300957e8da8b410c98fde0d1dc43e3aa08269b33320e694b4f25eca1b8024d6278fc6cf4aca0b53d07302c3f87d0a0a1d268585b41fcf2dfe033d19c3fd25ab9170a784739de3eff5bcbd4818bce63116a98e636f5bc6e2aae8bedcde5bce35c0fcbfd535591f0102964b91d79206005587ea61ca1d5cff8f534946364d7735171aa0bd9fcc951457791bdee3c80eb4a30bd1ebdbc12ee32c0dc2a37d23ecc21f94276e219b22a634d571eab448a59078dfa105e0ad08aad2aff3bd94fba4cbf8cd4ed81057ef11609048312e090fd9402579ef57494cc29091d810129afa4a302cc855325ce83f940dac4ae195d849d00df031cd4459885e3ce48b8250e18c441b3366639939f6901358c4ce274165e9403512220be273320ad468c087c91b406114219f00a1d1d5257e4444304aa0b8fb2708c43c0133134880d9604a017e83b4400ced98bb4449fb5ad1b80fa8138814cde6c07e67c834e1f228c4e846b514c59990b59edb4cc6a48c1e7aeeff1a5cb1962fc47f8d23e58b4222dd74b1bb346a5c5e7fac800b9ae5172cb754e331e704b7ea4d134a8be13c5332742ce79f47f21e15583e70cdb268cc0bf29b4a3220acf9ccf6d3712430a34b54f1968d5bd386e5a75964b9945cd3cfb89ef4b3e743e669bc07a61965eb3f8261043877dcde449358519d90e0733bccc8cde9098ebe03e6e0b1a41bb028047b3e9868e4c0b448b2db4763be205d89f95e2bf9650c5fc17c825ac12c319b537e83fa3805363d9b47c619518ca75d91256cdc4afd8cb316da1208b35b61dbf6f89eac053a833bee37bde98f6533eadcbc8351d893e11c85e32781ee26ed5fe6d823fb87a21274bf199f1520208209374185402d5182b2a81a9a271588e2eb8173e2ef03f96db2610503511db9757f6c07a5b0ca3862ff5202f6484eef6f4c716a85e839b02b11775964babf2fe5e8bae8cb38c91bfb487f8ca6bf34d63b1090f02cd98cdee190fe884df4fde817ad8c68cb069ed3c708e09b337b884b4c2c9157e24be6c3e502e7172c7a4ba8fb302f36bd11d8244650e1bef94d7be548dbd59ccc55eb2f6d40b2ea3390b9d33d8d9184dba8e9b0a5050555964e88d304010c6a35d2aa2e6f01a94558c75592b907fc6f82c9c04a1aa71d2bb6e4c8066db22ace1df8d14304a3509809a5efd5466fc0664106f1e911d6204eecfe18a44b7f6a1fc0014b6af3f01ed6e36e8dfde4a52189262090828c08e2c953994d9bacd5d8c134f944903af592fb94cd6540b0e3dc040c6e675125156c3215f6074dd730eab6b1ea9e238b328a2f28d336675f95f8bc0586f8315b32bcd8806ac66af669dec8c8727577a93af0c4f482055913c7f2bf4ac85763482a11dd59255a67fe0b8fcb9a0e451922396c21305adae3a8ca08d9de20e75b5563ed1146e78ccc7f902c541ceb382d045faf7c301da460333b8ccd077976cf59aed8ae75f8d8b8c0230ae6233708f6d03a0d2e95ca77d8614018f9eefa54f39bab0c73b979a08579ca1a04921b61e566773b43f70894ef91cdd27000f7ca1078ac3490222ca4f265ebaafed9d05c1d8bd406cc37159477c4ccec90e76cc6891c9e004e3af655f4a2a2328528098549e043d168c46b743ece8e94ec7797cd32bb61855a9f9261240dbafde331117037c88e4923b4f101c4393b11c5183e75ae23c9985cab1c320023c14e837e6ec5ba907931f91c528a1ceaf1f15e0450a9f1887f3e6f05161d97306e1e3fd77a012ecd025c77c23f9918563f1765007b3deb4a3808462b458406f1b182a2f168b30a8e4d0985219a927c97ae89fe29dc9f9f145b6c51539c815c98d557cde01d5b1a55fd41664fa9ef4f347d570343053045842c028bb3c2257bd0d888fc099109d3f8173c0dbf0c2a63f54a3a08861960603d22db0e9d547f9656b66ad7002cc40ebbeb4a897aabc17711074ac74b6c2a39cc19cfabe474785d0db0befd8b6301ddbb8b225e10b851cb170558361223f95cb1a06a001e0710e734b2d33618ad3fb50a00e323859f3b3f3d39acb2fa69e9fa20498601c41d3eccd79a9184285144321db3c472655c1b16430ac7f3f477348310d40592707ab5362ca77bfc8e8e0240938261dea5b51e1936be86d15ec546b6741bb02a7f2c02f84e42211f99a11b2fb24e6afa348e00bbba1a5c67644442b83437a08dc0cea55732e86409e9d0a00ecb8e63d5a6b41ae8b4c4a387cc069eb459065fe3a0ddc27ce177f30c35c58893855037ac46e81e69f64d65036aea0589f112d5df7309a736091e436c8c436ab7d78ccea01147bef111e8f711d5108776c32cff83587533b619c3ea38bcc5be221950b5e364c970fbfaa1aa774d6b710b8567de204d00b6db2c250ba75cdc61efa2c9851ffd3a83f2c4e99b751b9f5582b2f18ca3f4ccacdf93cf8bafc03f47365becaa738534c1fd2409ba614250c600f67e9c5fcde4a71f5198e273641945d96afdf4efc8cbcaefe62c8237931987bde611ac01c8cdb89c603cbff4728e37c528984041095560aceb56883624745101e72840ddb48c2b500800878a89a7007ea2b0c4056c8d8a16d41d4383b7200d78abfb175b1ce373163dc2fd49b86c7a38f9725000122b3534b6177d489e4476c3594abf088d5ebe3f1820cb135e60dc106dc381270bf225e6d26271a324cfc02a6b9a385c719cd0751f4b68a70a37ff43d06f2d53d0f8204676f433073e5351102c1ae50a5064f9d747d0b2414a0abca0eaeaa96e475925a0b22bc3e12036032166af1591d510be94456b311640681c48e2bb4aa16584da403397f658ba6a188e5bde202a3040c78123b96b433d88622d5dbb4050d8a7afd91b71a1ecca1c5b507006c4c585116c5f0f915ee5ac0b33da68140657e665a15b13d80358b5a323d09abd59546502421456b8672739de6554fda8d9ba3c8bbfd2992ffb5080ed37d74f82ca8a83479ac913f03656736567d73648a62a09dd8fb20c97549567ec652c4d978419246431e4c862c56f89374b47092584b4933b9e3a37653df8356118214e45d727911859a1666709a0a866768a919c6b7f9d14be9f1fcd4c165521956dd5c7aee11115d513bbb2d68425aceb6594a777fafe735b5706232990087a2f13ac3bccab356c287908da53faab829b2f5e48cc0cab976191012bc55cced1efe80d6ff07f7b56df8510237193c6c17c4a4fcad4f2b624332f8a2dde1e45ffed36d9a3243c9c2ca38828763d9c41e9b3763cbe522722bcda31dc4ca155f37875e13a1cb33aeb442521640f9cee068cf57ac507710664cebf527c3e5a36ebb929cbeecfd1c5871a78e56f2bad4869a4968da52a25c5819b4f46da82124888b7c03b6f8e40f5c696ca8b9c4bee281f43e2e789927277198d4239f5457316a0c69afeaa165aaff562622ec08de2a3d7362aadffafbef4b5056defba6b9ec64dc45b9859c150e5a20eefcd5765a235a15fdb25b1a25610c9e0a819857cb43a8de43fae5a0cb4dbea90d153f6817e336ae04b8980cc3a49fb30794a9261ea0018bc5996e0ed0c2d076ed98522898729c89e6c7e6bb63671ad847ff5e67206908093cd1f6d81a944563609aa2a5d7ddb55652ec2024d58e6a18ed0cc847cb950b434cdd1f552c03b26a106a061c358e241606c9111a2fb54f605a3899b05ebcc01970a8b659ce10e19edaca1d904122570ceddcdfd80ce805751e9c40e314106dae6dcfc99ba2e509998d5a3b3474c4d95a049db4f2003decc7d80469e2625e7a59e7c1211f4a1b9c7facb2655825ec6a5ce29e25d84dc3fd8560efc93e256e0118352eea96ddc250112353794ff03d72eb79f96753f073ad48e4291e620389cdd3a1b00d116027b8142218d2184e3703346e641e3afa9e52034d035467e5cd36bdd511bc663fba7422ad34a922622db258e1b0ff213bbebbdea14252699a3e1bd4d9f0cd080860c75f430fb523e83cb0913f9408868a4292878fb39a25ff75b2a1e1220d422abd9a64c3732fe8af434a560b295c6d35212641c66b93b7abdecde36fe941dd080287300522ba6f1b75be209bf5c9ee5153370ad5206b9bdc73324b2f05dfda2c3d1cd3e15099ba148184c4a69c1aeb0f3e2bb9e4d17daebccf99e6300a0197a6acbd561df94dad042ec887f9811623bf70b00fd4436794989e1e79a4d413f215fe447090efc2851fc48fd06f279a8701ed45c3b57e5fcce66fd6d95479503ab60d5bb67f28db5037abc3d0973f9345425d11ccaf14e2c27d42265f8c40b57f9ca88d4f4f500071117daa5d92172e6df97cb52b68a58e0af66689a4298baa1eebe79b714809edc426bf93cfad18deaf5c79dd20c3d2506bb01952cc9f6e85cb93c1233e0db9069872b8adb609f4c8b0d211416436677a789b9c58650cabe94075d8f77cd998964fb15cd002fd8cfd9d25a003951aae13f41cb69d533cb0a048ed8b9bacaaa2ff941af186a61d741b356bc738898229ac56c6543c4640cdb4c069ae31a2457c750e8f9a6f280fd0a1f176b20f2e8e3f399648c66f1457b7f7f634b2b26dfc931ed80f53061d9a50dfb3f2f4aa2a5e720d1786b7805ef5b467f5c16ecab2aad4bd77c82e25d7586999633dddefd1cffd01736e88473c5b6f1099574538d5a7738d6b1cc304539dc008a6ad76e246a951bd86a88d0d32bd6c1c5310a29212f7e11ca1391ab441ae5469bbac713a5065862067fe697b15764acfdd19fb4389548aefc457f27032c6984834cfa2e9d706f6258d474d725a20f22a864f49cdbad164112d7dd79af522e6197a8d1a9e0a4816ecedf400405a656a8d6fc6932ec1f88329d51afa66ac24aef5cf9e61340f4706d8204b2846db1b73d1ea0e03b7e4a5ae3479a0aa03d7d0adc3cb2bfe78148c2f324e5310fc32167f10512a4e3e6f4ed4432362957838a9f14d74cc98b4a1681f98c276618492c310f2291e2b458f159fab3f3833ae869fbe91b39985403f86ab1d9220ab6b85caa6f2650f49c6735f560bab920dcfd2646d83475eb3e077221100c84d6790786f6a21228ed03f12cd977cfc3f9248b53a155a3886954bb0aa03d34d92e26bd235194bba6280e3a7f3484cc2841e27a2542942021569acd84d7a5d418fae89fe68f88256014c5e049e4cc4770e56105887dc1c7a86ca1fe539f5efb0121e47b58385cb3f3cbfbc4abbdbc4e91c0820ff610f2902ff188dac89eaea2d7a31c3ce29b909c204735c736872cedd879806a2bf27e9a3a41ae7caed4f90f5f6b6d1922d6592295d0ef00d000fa74725f1bebbfe8f85512cd15bb74d3a78e4e72d2751b76f37297233781ce4657d6f59de775e182eb13fc37f477c2dab93e0b7a305bdefee5f7192d377acd3cfec376b8602c324dedff1bff7581e26b16f2249fba8f0075ffbf7efa902f72f0ff6f9cfebdcba141454f183145d9288420bc25808ac2e98ebc4ca5bf8bb071e45145c740085194cb1842dec037cc7b29af45107f6ebf66f78a4490be67625f0b77fad13201450d084329d17d24dac8bc394873faa0755a83f791e089e7e428cc14fd18c28eca14014ca031fe58148502fc4432d2e1ec41310fd6bbcc036a66cb9de87ed191849de9ae2ad2ab766694bd2161a5c7ce78452ba1e06c118321e63ce0be9364e178b0d168ac4a00782f75eae0be74413de72bc459ccdee3de2fa8e0dfc4d7aa382b8963c538335c3648defa371e369dcb0a81bacef67cc907283068dafc19aa1aa90345ec85dd1e8505cf8e385a71a0f3e88ef57c3060fe47d0cde8bb778d8c3d7f3700dbcc5310d63d01b3906884a388f8b0f97b0f098fee0ff014110630ff585d7fb401b2fc43d1b2c0f75f21e3cb16622794118e4fd7e066b8622ef8c19bf5aad1ea4c13ad5b0610cb8061e3f95d7248d197f5fc85db17a868c8b0545c2f0241734637b4b54a5a490e065994e56098376c9036d10a00983d756b138a607b1c92a79cbf4971504fec1f731c617775e7ab052448e860dc0279640865cdd08435a2ac87e62094e20417b599e145f22ddc33ff74b3d07a35ba562d1a0dec50a3481a7cbea93c913bde518e3d388576f31b8fa136b85df84c9ac6ed0a8f23e342c1632f8c6f79fc0bfe1cf0dd722c58c6f61b9122c6fc2bbb83be1355010c1774ebf833d5cf256d8cd7025ec346e8d1b061c67b8c6384391e06a9cc120c171460bad9c58a1920963102f19bb292326d32d21ce5ccb9de28af11d1b6098301472675248d6c9b5f4abfd8ab7b0f811ed4b7d040e7fc07055e36bfc0c04b90888a6074de3cd491be3eaa4962aef43e39f80f8f14ae271869fb622418c4156dbc0644ea71bfe981e34996c8c356ad4a8710abb26444ce6fb6eb8c449d383a7f4e7f4a2e9c45a79ab3b9417b6b7ac89c6af4edfe1cf8a06ebb4024d2cf0572cd6699c391612371eb328e32d7fce03a23f6ef7fff0512ede65b0660ee6c54a64cd60a852a811f458337caf8731e856c0932b9d4c7e59bee4562c0e9e4921bdcfebde831126e9765490b734e3da6041a342d66c45862afb1d4723a2ac901b4a114de112eeada36c87342fc4395688e242311cbdd329fc3089ea4f8fa3882bf1455fe29c1b43d538b3e17fa1111c7e7fbb92155f12c39f9063b55da17e75798eac64fc8b079f267c57b23f54a15f21bf0f5f883fa7f299f558335f3a9d1efbe9345a7b3a7d873158558ee7348f7af18f5c9ea15be3bf1a658ce1db7186247cfbe15bee5d4994f128f11b9fd83f85e16a062afc1926c54e8629cad72b6fe44c2817ee45a552a9543427d4683fe7f2ac628c2f4657121fb3faf2b8f89f7d472e8f8b71e88eae0a9f267c8b8a8146f5a85035da40fdf7e20f5d1ed1fe67432334279a8fa27a57b9ca94a21967aa14d145944aa552b9950f253acf7dab7af0ed9852fde933dd500018654319a490347f7af13d8ce1f422929338b6b7c47116fef7586419119f7b4ea4119f7bee454f153eea55a990b622c1d1ad589cfba05bb13fac2f911fe6f065d9548c2e7f3aa1def4f83fdfa1a16cf79c29346113eaf1698667a8204e412805a1aa8242a1be300c8308c3d106113ef760db204294b7eeaafb8088faf041cf5a93352da19482a812849213246895ba0f8856e97613f8ecc7323da89aa1c8f0f4f7041a39d95314f29e4623a7ef1e87484edf8d34f2bee7423cb4627156de8792f259079345ecc40f95c4f08a182eb9d28baef42b95a74295a85279ca5722195a09ad8456422b5916c025540a9742a5f04ab8e44aab952bb9d20a7f28d261ac3e55eafbbed4f721abb10883fc5cfc54295f8556422bd7b30097702905830b969488c595520ffeccb960b93ca17fc8c2aa7126c220ddeb54aa7186223d0586ac952bb9d26ae54aab556825b4125ae14236005c8a2c2f5e844ae1951763b8145a79f1a1d28bf0ca8b70c995fe852bfdca85f833172f6e7c2e30cd2ab4125a09ad64112d07c5182c478c5c3ed4873a5914136044181d105797c78201b302b35a8181419829c45c316629540aad34c1a50b9726ba7069e570e0c6e3b069e58456c22b1d13e2eac6e3b069e57040fcdeae6e3c0e9b564e0b0c1818ac6ed8845642a515182ce4ccc1d40003c60a0a5402b37acbe534ae422b63504a60f71ca7e25e65ef673a810fa2dea4528dd704be09a50adf640a416f168657157e2a35863615a6b00af5a9ef94831fb250415c4f59fc032d61b478d182454b155207d95f3030c50cdbb7a3f78ebaa329895f93c9e4f5e9823f0b8d3c71d3173efebeef1b69524fc36aaf498d334ca65cf5a22a157ee0f899c69994bedcdf15378ab88a3263c816c8fe72812ee4970b6c217790fd25892cb290dd7b4dde9e617275f2897d6e6c6fecf0c7fb0e61d4387dbb674abadd77e098a57bf7995dba3ce2771fbe88c9f03b150b4586e3ec43b1da6bc0ef587e1aef9b460f8dcca43cb9e3ccae9ead72c719f6c627f6bbe7ba118f33fbf76639e18eca170c4041e620fb0b06b07cd99205698720fb8b963124a8fa6c38e859eb7d0af5296b7a7b72c1bd1127c317e252c84fbdea51ac192651a97761df45ea512e1e358ae30ca544a63a511c5dfc283e0d0deac5ee2dcd37ce30e9b950e1efd48be3ec234fefbd2a35626f7d286fd9d338ebde64c3ff1b47acb2dc04ac921dfb65936ca031ea6451e3d580f8c4f4dc8752429c89e2fd8fb4e2898b6dc27671eb84170b85ef74e34c8ad799469bc55b374b12bec36df19d6f039cbdcdd9b1fb2dde6940b4e44ccc80f8bd1561ac6ee0f8560c2039b3e4ecf40503559e8beff4170c24d91055c5e2701c9e39179be5d6dc4705617fd87126c59ec67166ab7069824853a598de66f9ba9305b1384211a92f471071042d261509f00ec031dd320215607704223aae6b1de4708404a0301450b7c3410e474001e500840fc886304140617490c3182f0c50d089ec278ec0c584839b83c4beff6a25055b5b44989c1c2e0ee26c725adee2c2e82007ccd958cbc37738dcba453220da6fd900057155f41067dfd730b0ddc79e01dc217ede7220c4bf2ccb91357a88b316992ce40c07e92b8bc3ff06aa4c0b6263900571e56ec700882e04c42136eeba0e002277646415b1e48b34e00a62631552b861439cb24453799fcf7bb80ec7715cc8755444fc2871ca1298fb11c45aee83a23d027e8700f1247a3f6509ee1fc7c7c4d44d11bf14c02296f46c702cdb4830892f899f6beba316fbd8da2040cf365680d8897d6b6c14b1a41d3fef3b2a62f7383c0ee3cf77ec8ebfe5461b782c6239b202d8768b7b2bc57770d3143b2ed17d0dfc6077c31f8c2dee7620efe3b01bbd91e0182e471a2009f7de38dc73b83b4037a6ddaf1fd9b8ebbc6eb47dc3f570b5d817e23709f08adc73dc95622d0da08b5396f01568bf71b0a0b83efe0d83b42b6fd9f71dd40c063913510ee821ce5aee45024d90fe36cee33eceb224c7ba7185ec2d9ca0010b18e1074838210b9f46d1a0bc855b025a2c793f00e215685045ca152666300311dc200b1848800807885fc0bc6004099618c10d764046050d1022d5046922fb091e60e165b62a028b2b6e2d16537600851d28c13ac10b05aa9c21bd64e981972c4ff092250b2f4c2c91ed858924d205d95e38300412544d5962092f36916cd68ac953f358416c7a7ba3bb65e8233dda6041fb20d864e31dcbbd65d9707ace5b4650e40c0441d0f41ecbf4f5e4bc0d0e6f591bbcd516c738ebb7c15bfee0cfec0379cb06dbffc48e3604cd7a7c2b44ffcf07d22d105140fdacb5403da19540fad3ec0f1816c777bc6f2390ce83dfdf89cc774cef7d04b2fbcffeb0572c8ec502c3feb047581cbbf4a1505848d702de407510c8212cd5d02d7f2f07a4fb80f4b77d65d6589058ec8f1b90fe4fde22d12f1aec113d701cb02c07e43b76d6ffbd0d8bf47bdfe4294c77eb1b57dee281ec1e6f04d500d928c4d9eab3f460a538a7fa8057c57f4e0e8f1e20fda2099c80a0213441053f88514111587cf0103ffc60058a05281fa4c8117b7278e49868b200020158088c5bf821073f0081470f902f409c804c91fd05082ea00ac06e8a58437c61c9c6477cc1b264bbb1247d818019945b0b013210c0e28a2f4528f1050b1457cc172c4d903314f9054b07c822b28034563364747ff78b41cedcb13b86f1c2058da84a8528f064fabc8ec3d76d7bbb778d1a29f1ca294ce75d8771bbf707c6abd25e157cddb69fc2d8ae518ebd65410fd5a1b5a82efcf94edf07c35bee71237e93f7733ab9f5c66e0e25aebafbbb176b0182aaeeeb6fadb5d671163c60212d0f59c83b629f0282e0ec9a21bbad7bf7cd45d93362f7597fda35c39272ad7f60a971dfdc8fc2a514fb893059c8991786a379614818e04fecc7b41579efca052f5e5861c60a32e267bb8d08f3a99ef8128132d8881260115c7cef12e6d2dee26e6085186bc6082d6eed1723923e23b22461bb3fa5cf0a1558b7d6afbb1528c020b06203e48ac3d88a2c5cc771aa212ccb8a29e4eaf3bc2ab2a882cc521562aa60c167fa3e0fcca7f4a14a603a994c556ce0049e4e3809339d14e20cb29fa842081005824f5441a58a1f4817a958022a44a170d28a0a2cc2541896a1420ca602cc47050952aa548a0a2da41df35171844a54a9a850faa6d8429c4209342e68684c51a03e21b810e3e2850b174f4c11c5135338f102c68b17282ea829b27c532c4da18027a4280303150346a8833d63b92bc5186c032c0514e4bd2c299a90620bf984145962c88811438aa54bf613522861b29f90a2cac3c842c60c19327a00d6a09302d360053350ab1933ae9c9cc8512289276870e5091a287d67c0158dd54a461068d4a04123c614356cd4a8f1c40ca0c04fcc0004e4ca5b369e988105da468d1ba9ee9b1e6f4a90039b455b6bad756bad75d40dfbdccb2ccddd31c61c57a5ebaa785e95cffbbecf851420b6edde472cc900118bedd72df60e984c9fc9143e74f4e8e0d1b1a3a3870e1e3a76e8d0a14347478e0e1f3a3d3a3c3a3b3a3d7478e8ecd0d1a1a3a393a3e323a72787276727a7470e8f9c1d393a72747272725e35d71bd1bf6a66d9fa2f3576de50a22f427fbda1dd2d01b775f7b7e840bd9a349bfa436b39e4e5cc68d14aa0bb63b4e8abee2839769a4f2ba1a0b59c7677d8cdc5609f882a23ba5b468b3601ddeda2457bc50baf9aad3f33ed817c26fa18ed86cad4af8165286aea8aa1359cb5569453148643c4a3a8ec2182e9e8e84104db9179720f0f5151118f1e3c3d652682e5e410f9c821e22182ede881035bd55b8aa3a6aeb556d4fed3ddab16edd7dd4774b7edee4ed134cd7f961fcb677a5b73fa276aaee57ae65aa6d96ae6af6699ae6f749aeb5ad652b4e8cbee36a2bb23d0dd45e0eec6d2dd2fbaad93ee8ea145fb6aea8265284247658a034b551c184aa395384869991299b4eee6ba7decee1b2db60d862954800004464c33bc2851238216f000848313041545c1230828da4f8bf5839e302f8e3ed713b01041094d0149987ac69a09e88479412308d7b5a94470c030ab82000b7c527808b880ed252989eceb5dc480e07df08edda4946b0500f6dbccbced370aba65b5146b77c0eff29c9e872955de87e381871efceff7601f7f0fa6ffbe471ea8bc0f37f2d08369acf23eb687eebfd11b7be8ec732310aafe1e3a7b5a1615fcf69d35a50a154bc57e97c7abe02955f0b8840e305059420718c8275596d00106f2be0eed85bc36303105132b20574800bbbbfbbb876a87683187fba639af4b8e24dbf5e5c1d884393cf36ab6e06ab4e830c6230c480f437a60bc2eb7c6df1bd30d419c7962bc2becfb7b633c31165bdc1f0ae442360038cc753981dfb0ab31137e8d16618e29a12a47922af5dfe5a1f9145e57ac7a1a560aecb8bf1e82355bd46c51b3c5f594e3284e35666ab4c89154a3458e29399230f6662d30aaeec3a713f8370cd99d5e9c9d5423ed8a49a5c213eaf4e0699c996ab6a8d9c23361ee0858146bccd46891638a58b3458d19f16bb410734c115de448c264f72e6868c6998bd98a69dec5c360f5a54989355bd46c51b3c51da372ae0ad838665e994b845bc68ea622e014caa6503e109f98bc3046106797cce5f1c278612e192f8ce83b5e9830be13fe27c67752578cf17ae09161a1fefbaf468bd064aa3153b3c5e841e12d2fdeba9e170f0a0f4c118870cd24d56cf179607c202611e192f1728950e666e13b384cca91f47d5e182f8c37c525738970b5a8d1a2c60c1994e9c4b2a66fb4974ccd165e991e5c8a774131297bbd334d71378520f737e5e3cc7e8a158e36546ca8d850b9770c78bbeefb3ecfce56530762d0f47d3654441c021a94cd140fdb50b1a13205db28619b2a268fe63dbc9a52e2987afc36546ca8d850c14945808d63f679c16fa78ca7206094c9a23ed30fc427a72f8b10c4a50f2f99be6f8befa094e0f235e13b5d58534e6f9374e2c6efcab7f461f996be2b1f16b00b02676f735b6ca8d8289d3e2cdd0f3a32a2f7f65b32fd4ef7a74f02bc5b6ca8581c703c9db27c59be249678ac4f1236542c4e6733c526092fd95099a952ac1d6da87c427c4964876d926ca6609b2a1f4e6ac26a3a9dbed56432996ca8d850b1a1b2721f7cde37abc64c8d169e97238974af7377d1431f67a7377dc784fb9e377e5eeac12b86fc5e35a35d31e0a3c071b662f29bad98bc3f6b81b962c8ef671fc62d30f78a21ed7f63cd16355bd46c51b385c72161003344c055c81683935ed0e83ae0ad2630011733a894f1945ec8c066f01783e338cee380e0beeb1101460e522f5a10c3450952344830811291b8c04985c411a61412546484488881d2810b308cea24810cc43049e088f09380102acf24841a35a0f14263cbca8810c8863041406174f085010a6a01a00320bee2b31f4d5bd18832e490b8ba41d32f4b7ee21723c6bc3bc0d660051552b861a3068dd50c193160bc704123aa52210a3c99bc0ef8132f5cd03801bc17f78d2a15a2c093e9f33a0e5fb7a5d85fae5cc1c2438421dd41f7eefb1bcdba2498624d692f3313093e262fd9e037cb933a04711452a9d403a1e2418a4fea410e95624d113b6c8eeb514beac30e0adf4b205329d40bf1be82c42fe44e600c697a1bfe74d3a0bc65329964908202b2db66c6fd7dfb9c89d55780dfac4ba6c2243288e0830f5e54c81adb0824c8a14256278104af37c6b6ab919a1d91601624f8b14ee09836ead7ee34cefa4395c13ac0407edd87e9da91a8c763c81e755881d40106d276a7b1dbe6bbd79bf9df915c6116cabf23f4370eb00572d623cd5b345bbfd21c524bf7521a09418fffc3df8ddc3885ca8d0ff7555ef8e0a7f90e0c72462369def2cf21673080a67044e2ac89c043f7ab5b23c5a7977084082620022e6392927c38d6142aeee37d95203ef8395695203e3c2c11849f071bc4f0b04490f7dcc8c3111e9608e21e8f3cb46e8d83692624a0055a8a60030dec8006dd12c4f691e20018980009249e10e30125f8b44ff73e9895843760c5023f54c0043e53a8dcf8e0aff2828615ce9cf1c12d90fe1dc66315ec839f1ba75001e283bf0af6e1b8e7cab87b46b4bd230c6fd95fad6e8d090b1089aadb5afca63782df649fc3d74d636804bf8f7e71636febdf6fc4bf2daa7bee83bae7bc6e1cdbdabee99742ded008c630380ec481e3c68d3b8e3682bae79e490776ddc9ddc81dbbf0c7472fbca311246ecf9026772377ecf7372285f442f74015eaa24ea6cf3b8b4d29bff79404aab807551cd775defb2df39121e3cf5df1864630fe3c6b2dd979dc7b5cf78d69f4c6ee1bfffb419f8f08f8a49078768d74a3167f6ed482c59c61390eb9116585b5d65afbf9181fe3eededd72b9cb5dee729dcf2d53067398c31ce773bf4b170e77491d777d2e37bacf7df04371acce0ad3832a1b48bae7de92524810e4462d77fc8c78df3dc7a47dce9003b03e78bc62ae985be323c55e1c4eb16d9d68c2baf524bc23fcfa8d805204a614914567040ee322c690abceebba22ae3839c176c3e0fb41114edc1be0c009452c7d4554c16206633142378d63f9016969fc06244b8ab53f58c4b8b558c06051a202b88a7577777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777f75ba5cab52f5ce1b37befbdf7de7befbdf7de7befbd66fc0a50065605579cc0f75e514410388caf74e1d2711ea7006bbbbf5c99805b7b05027edd1b70650157a870185ff181882b88d8e20b1144f0ae7c5340c19de0968008100c810825dc5a228ec0442c5d772292b2b0d676eb60cfe00e1bd0832938cc35008a06785935a009aee3b80624b16ac095ceebbc064cb1597c196208a4e3f03ecf1b220c14a6ef1ba2892f437021610c9165882ba924c0ae055f8698b21485cf2900368e998d3224eafb41140b9c71af9924f28efd2896fbcc307379ee278aa771c637ce9eac9105bc662e8f67e6d698fefb44d1cc35b90fd8be8322bf779fee970d995c1ff03d33974755e6d698deb4f2cc90261338ce00736b4c2fc45565aea97b6beaba6bfa1765b090a6bf5088b3196648d3cf5e94214da01633cccc402dba088a6c6f99c68e09e2375a33b31961487f0e8fa8cf4699ee09707697987c3e7d6bc4781632968b99f6a29a7d23cb5333a400b07e859b9aedc0c20a2aa47003a7660668e1868d1a34565c6ac643ab4bcd0e50e381393e1772a4ec4bb1160701368ebbd38373e342cd8e8fdcf1fac89748be828cdf9727008fe3fbf2b4f02cb49ef63208c0cb91314fbec9bb5d21051bef961cf2f3d6cbe5a9f1762503c6db3197c7c8db8f54f2ad442467f8c819be67887d373c01be2f0ff7f6c55b9af0fff45d1e1cdee6f04e0a507ea2b85afdb76cef18a05b9ebfa188abf56d52cb26e590616ca3fd3ed1d6bcd0c68fbc49fe3e3a175176938c8adc27b3b4c0f0b2cbe3638e28a25bad160200809fad324b8b901fba3c37e96eb93549748b02dd5aba5db86496162437cc6dc18501eb7db652814990911aff347e26cef8d9ea22e166d1adccd272c3cb2ecf1d43467c178f8fc04574ebc5a7ac4f6669c1e1878ee06e75abb512c5ccd242f4472e8f5d528055b2e1b64c6083c92c2d3c7fe4f2f8787f9b3f90af727cf78e67d12d7724742bcce5f131d68c9309b32456b935378c3573c558337ec770b9fed7ccd225936549e4b2e4586e0dce2c13e9632e0f8f1eefef652e0f8f8f1f552e0f90f7bf4b97e785cb038390f7bf5b2e97cb43e4f21479ffebe5f2184112c39277a0f7bf652e0f93f7bf662e4fd03b0def8fabe0a5cb63c3e5b9e1fdfb5b5581c56044acefd6b4981c461c0830da50c30c6393118895448618048084d5b7e6c86884c5650b0cacbe3541c6998b01c27a8d33f7d233ce2e969db107eb265d2f37cbdd72b9dc2e2c8c01180130b2585ec5971c0b8dd50c19b706c638b362fad6d08c335b4535ceec12cef2a287ebd77d006395b62c7042db6e3130b06ead0bfcba930173f1bd2bc01cc666a0e03a8efbe2755d7b692b4e18019a42fb85f65b077be68e77498c672163a6bd5851e2b3b2a5bf140c25b07b62c56dc799896c7b258823c856ca42690af20a91841264ffcc92412891de0b3185b48f7b40deb74a5090de5b283a78a4fd3b33fdf4ed15fcefbb4fc2b1302a4ce2a1442801281a94694425cd2ca1902baa84768b6519acc98a2a218d4e53b6a2a0bb4fd0dd9f09badb89ee2e0109ba7b04dddda5bb45d0dd21e86e1074771337c89a8dd272fd175ef8f406f33335ad27a8906aba6ad4e7a146e86dd4160b3cbc4d9a6367565b48f989101291900c96965915424acbd3247299babd0737d46c0d45289adafeff4ff361bfaaa8cc36e90fe4180a7bd91de59fe667d8893e12ed443f96d73266bb7d26fa55bdd5be5c4b2234ac598d9d5915426337359677305354b6de4aa115569eb9bb05d0edaf8e651dfe47b99631743d67a7f92a5279442b6b655adace5bd1f3ecd8a163aa486a27a0bb73b4582bd3ac474a3394fca7f9eb99d59cda3e133dbabe1acbf9fc2fd73226b466554d5d679ad7b5b4e1a4abdadd2c4e08c7a36f0cba7b498b36568db4428b35bab4dac4e83455d54cd2dd1e40b296361ca435c795e3d2b9418b4ef326d34a988ab343470f2cfb208af9f0a1630706cb3a373514e622bac956d308295d55d328a7dd46dd1dd4620d547777a0bb311635cd6691b99e3966feaade98bcba9eb96694d597ada5ed6934f2f5dae9a1e34877dfebaf661bd22a44e386283937158d52d6846cb55466a4d6f25ac6ccd8590ad56e6794b2b69e371486043bf34d879c16c5d2f2c876138a52d682c8d4f2489a896a37254f6028cd07a9a4e598d02d86c25e2f357599b652a8a69647383d884a221f3b3a383d59479979e41e311e1d453d3b7278dcac68ac7c42436d3cba6768714696eee652ae65ecd79bed346139860e39451d86c0447773a0bb973873e6cc99ee6eb4e8449263656a649b61554b19ccd53c91ec60d2cad32cf28344b3d9c828652d96a1a459cd6910a134dba2943598a99e66ba46c94f60288d4828ab25d10a2b6d3574c8eb05cb31141644c78e1b90340345296b41809ca8b9da96d0ca155d85a29435a3d34cd726af97904d4d33906a3520c6b0e91596d31485fd8a9e9fd3f2d5a34fbfc8fc585e61d91625bf6afe6759d0ff18124a51a1a197ade6d1c7b24c354fb3e87dd4d4a5ae66cda475b71276951999b9062222b966aee78d09528aae65ec2c93d0ca34db96d0ca5a8a2a51d5923644452a8150256a2680db5e5354a63e8aae32b594fd2bab698692d33f91a8a94ba696321c9c9da21d1e3b787ae0e8e828737876c078c476ece0d19393796ef25aa6ab4a745371d4f5863e8165190c67358d70720d95dda0466909c391a9a5ecf55a53d466bba942b956a645228c0e7477accc69ce45422a526953d59206cbab991e050962aba54780d8ca2439a7413eb4723dd11dcc1495c54c5a0925c88924d784624d5eaf6ca6ab904dcd6bb9c6d2f2e83c428918a9b5b5145acfacae674eb3ec34d50cc55ccd9a99c6ca2c1382e95013d2a116abd1b1e3f6363a76dc5a79075315cab77cd341289683d4c4b251cc4c89c8b7892129d312a805049669506142e66996b221b9bb37d0dd1ac83114968914a1680ab49e5925227f6cb5f448941c3b91a86a4e8d4e24b65a7a24ef6036c9b77c1b800cb69636d5248254d2329358998fc07448a2438d88915974a2435694d6443593ac28caa4bbb7c840cbe759ca86d86ae9115528afe5aa0a2195b49cbe5eb5bcaa48aad069963258999636a135d368a54d48bdd16eb51b6c4565aaad3c9be4b55c9b189da651a9aa39090278d025002a04c850046b29d4e1000934d1c44d12560f58c9808a0c10e981064141bc9083aebbb560e04cb72b96d7d5acd550d8139ec04aa28f651a0d4d3f13fd59c27e2d652bac54cf325dffcc36f45125dd7dd34da445b48a6bcdaab99ab4f24cf31a253fed445313caf9d3dd17103a8d4c5a29947730d5f586229532747712a7b9aa39f632d85ad6321afb9a56ceb0f486aa2eb428fa1071b40add9f8b8f86aa4c77e3607fe043e7837c9ade60397238d5d89c5aad03fc01badb02dd5d81eea6c0c9a6bbb374f704ba1b89eec6dd584e06f8b77903bc9aba5219ac966b387d438f9abad434c768e68d0867ad1575ef6075b70ed5d7ddffff6fd3420baf2b4421c6e4208583feb5fc587e0233cfd2b6de92a4689afe1ca1698afafc6b68e85f279ba1a17fad4599f67f1aaa59654666fabf16655a6be85fb14c33cba234ab6ad9ddb7c5d402502da6a4a46add4da3c55450f70b2fa8e60fbdd1699e5976f435ff02906fbd00e44fd32813a9a9ab5ccb9850770ddd31747797491a6aafe6356eaf391aebb5ca72326cca7e3a304fdf2b5805cfbf8fc3d7daf6b603c030d8f67e70ed6dadbd7ec45acfbab5b7dbc1ad5bcf6530b1b6b35ebb0d5dd7bbae757a8bddf192c5d6fac92ec1ada9398bfd666b676ead7f33b80db7de61b743706b3bb703b033acbdfea580bb5ecacab036c6776d16dbb9b57e85ace3938987a36c90cf7238ee8f3bd6b93daa1dcb052cc21bb75fc0e2dbc29cdbdb9c032c16b6bd45516cdb165bb746b09fe7b0d639f76bed0e8b633f8b7277ef86d816dcb1db9ceb02697c2cd8d0450d8780e59c86c5f6da7620ff93c5ed66d73f6485b8cd4a816dcebe56e0d776167b36b4178bfbf7bab6e75a77fc8e32b52c67ad978361a0c9b17eea3eb7d65acfda9775bfc1edacc9f18562473fba37d604bafd3ceb425c054fe1a670fbb655d9cedd8658bcd869b8bbed2c2eb2261c16e4dc7236c563adb5d6860ba0034d6e893e94e77600f6b3f6bac5f6884dc17df80d07dd73ce5eebd641f7b0bddcf561af6d599345596b7f5815fc743dfb61ebd6beaced64380c8bdd72d8fa70d05e57c1deeb8e1d5b1feeb6869facc97ed8adb52f9b829fbc6bf187adb53c6f5547d705ce5e6bb278654da61788830d152c00b075efdccb568c91031eb1d6ad5b6b6fda6b5b777790ee66d2ddad16432e33a0c09699c1d51fb403326182288005119a943bc819c00ec63410cb06bd640733c84b584e48400905d0254aca5919015040052514296fe4f860ad707a7690da004f19e2d8a1c0c9ee94360a3dc69c41a247962dfa660c1454b019b3c56d863080ba902527870b6f730415c63c4a852c335c74961739f41037443f06a2fb76c7cebc96af8a279f934daba92bd388caf534531b4e8ea130f3bc75534e017841528d175e93e7d13079dcbd3150413e2819bf5677fa7a300a06ca23006abde10d3f31404420a94bb967c236610a3d1c483ad1808a619b940fcec3063703b61d902f492fc840840608c7272c438d15498d00cbbd6c3e38ae716fa8487201080131543e08b8467c4840120d530d281811482a32e3fcd41313928688103dd30db92758014a3e7c98e6eaace043132a60ca51c594cf0c04520e7242683c1f38868c03971f5e70ad5391130b438e73783e7e1801058cfc300306e04c7122082892c05b911140843a5456044934767c38793ebad397ba3c488cdc144e453c1f7ca4d0e43b62e3a7c8c97404d52406c44b92886d764e9e8f176177027fc6026020e9f41d5181680149dc1539db0da03b713fba1c240ce0cdd4c277a43b79345243542a6025a619306ed090e36b2961c2820fa7cfe5ed0877f02001f250d8abc1bdee8e09855b78219ec93b611c2e06dc23c472362e8b939163fa60d70796a4ef24c3c4e3c3529205797c2d8c03e3e8349094238589702e702a9870e01b2a9d9bc20f492e1c7b8bee0dbe9c01c60210819e304062820361bc70614203490421e50051d42745193654002737d840c30c4d806410c09157cf8e160b0100c0e315a800862001186bd0f0b2c400065a3030801f185e29c440811d144e9060892d5a92b00005b2486086560b464480e886231841086d0003cca2203f4ede962196784c351093812d2f1f3b336080a7cfbb614304217092634b94080049911f24ac2820012ec6f43001131cd080941a68e0d959c1c03308a3041a82bcb063f2ba0920810403962809f2a3059485823fc19de0667099378293f11d7063ac0ddc0aafc244056a0a9f813be14feecce2f852e06e84347c86c7b030685e702e9cc68a38e5207772d3f739b6d7daaebb6b84aa6be39e20090b918465e872b4a288351f682e90c471288f051bf88029a08367a092d84017441296c124e374630544928900f886ab02b876a8afc8d7d39d6e4f8e17247d5d926038f1c1c4738598724323a07490c49d49e25035aa4842ad371f4832ad52eefde070b82b5562803420f003564a52b1c4bf373438df8ae6cc0f9c0b5f8f07e4aa2e906fbd3758061858dda95322e9825d0d6c03ea5c8b51d8e6548473c1234057a33b7533140c140cd30c308647801b851fba1a97cb0f1c98a400cc70ed850290027ea1541d0db6f7e60ec140610ccfbd1a3c91eb3c9afbe262a46c075e0ea3eebd7ebdfb5dd3e906bede0c9e0b15d089c6eb3c7b3dcc03e360fbd1b86392c0568f0d24a594f081a6c3363e223f601dfc300a7d9fd9020835103383302d0073336a72668b21967e7c607881073d8f60049c1644d5e7e170c312256764f084971518908305024222a0032ba260010a44c084161c170b42380fb8ad0c50d32520a1cc15544ca1021048e9a1004e6eb06189122345565061868c273851022638d0c3018452b8819e2ba8523ac8810eb530e9cc164d6082131c66c8a0b182052b7802052208410718604501420520400d4b94208942062b888109b01cb9810da290010b54808213602089052000082494b1820a149cc0090f4c49ca31243f3461191ff440072d50410948d04406861022c76a40f25343134621831648c08821a6e458010480a4c8cf8f572ac4ed831e44210317aca0042468a2031968809529390800c90b3f5e3c3c746a5cd0e03ee3831ee4c0052d58810a4a40820e64a001435811620a162010cac1090c382e2da020430caa140e52b8b1a4b4001b6ac8a980100b408ab2449fba3b002d9a98d0a633770b1c050e0afe846f0358039e01d76275b8cecdb12ef0c66dae0bf765ac6053f01b5e8d4bc357dc0c2bc3f4c2858b2b625598124318281ae08d138de9fb3aef761dc75ddb6aeaaaddceb45c553cd4dd30ba3b77b78d1671daed7275b7b78881f4d017a15ff36a5e91885aff3966aaa7f9aaf9abf93f90d2322d65b02f7f45cf57cd5f9188ba16f14d777f2de20074370b2dde33a110c4f007dd9d6a3114734310e113ba1b6cf166d139b85c2e1c5eb61a9d99f645e8679849533f458b6267fe6c749669778f2d5e5a778b2d5e27dd3e7cf4f8e0f1b1e3a3870f1e3e76f8d0e143c7478e0f1f3d3d3d3c3d3b3d3d7a78f4ece8d1d1a3d393d3e383a78787876787a7070f0f9e1d3c3a78747872787cecf4ecf0ecececf4d8e1b1b36347c78ece4ece8e8f1e3d3d787aecf4e8d183478f1d3d74f4d0e991d3c3078f1e1e3c3c7678f4e0c183c70e1e3a78e8f0c8e1e16347cf0e9e1d3b3b7aece0b163c70e1d3b7476e4ec085084d6ac0e7dec348b8674929cde686659d443ba817cfb682ee55ac616d0dd515adc01869abad628b99da39965d14f774fd147b0a0133a0b3575c5cefc0456129da60c56d66e622d66ecca4c328d66c6709495e4183aa449ac05311b1a89884654ae6769a62594cf273a24d6403d3d9a349141759d66293bd72765edd1f5d31c4bd13fcd4789ca3f42cf27259377c1b24dfd18d29a661b9ada7eece9a1aaa36af6e869d2e46379cdb1168cbceb2c612a5ab3aaa9794b6dbfaa3946435b6fcbf949ed93bcab76ab9951cadae77fa92cfcbb64b2a19ccad6574fb35c6b5a9f555a59e45d433a76dc86866e695011fa43b9569eb06c5387deb5aa28ed33d17f363232d3f57c743d51d8d0907a9be5a32f323fabb71296897ea8c6e6f50a6a0d7db621a939cd6bce456a09fbd3aca9e659ca60b9062bd33543c9b49b556664d25e4569307355cdd3aca579cd311566da4820195d6119ca9735396dfd9749deb5aa26ed878204011952cb9c7e263ad30c259faf9ab17c7b24da6ac24c5a2daf66cc95e658996536aefcaea1a14722fa35377957cd6a3eba7e14b505d556d65aff2e35cbd4525626b1596f365a59f3a7a9d2ca150d7a17112445a789a6f9861355926ba51258b6353991a0416a2c6725b06c6b02438386103951259c111c110408d3dd5c64a5aade5025ffaa69957f03126eb0a2bba5e897adccb2d7d010941f1a5af2ae9a1cabccc8ace568bd4a2bcf57735ad26039f6cf802e47c812012cd4d4457403ed06176ec0d1dd4666edd1f311700416ea0d01a6348d661609d9545568bda15915a2d1cc2742b2d53c12d2e1d2d171e5dc9c47684a24534b19cc869e239456946628b0d256c2fe656a79c46de03ef015d0c095559406fb286bbead67999646ff3614adc17472a9b17c669306fb1355cb9ca66811d3c9a5aa2551f9242d6b32d899893e458bcea2a795262cdb4c2a66908f90d09cd6100601b51edd82b628eb24a7dbfed8155ee86e2674f3402cfaba3b8c151d86030d02a220fa891428badb033278208abcd6a8eb99a1e0f059166432994e331499b51874d42693e9e432994ca71a9cac9644d928966947e8f904e7cc382a0c8de140c93117ce4bb5adabac95838ac3d7d055bd0d31994ca7ee465b6c12a665d0dd316815e7475b1b17daa21a0aaa90d169a69d9582bba67566da0b403e66d652452d32e9d2dd308012cb3afccd4933cb1f27fa44b55b0afbf2d52c536fb6cf31f41442d7d3148a9d19a6e658bee9906342b00c05473d51f3bbe9ee02b43880245ac7e7785b09138ad1d07fe185af69d94a98ab8896d51d1d57cecd8aa2a90d0b3d65002b3575e98082034bd51a2c8a90cdbf6cfe2594665aec2c65423638ff8ae5d8792bca298e7aa3d9d2dbbf5633965398d0690ad56051804220224043806a808e808c809c00b174ec98010d8a759b20cba0d268a43a24cd4064b99644981c6525ab5acab0aaa50c6a0db65a7a44a6964732cd66a6416850cc564b8fa8ab5aca00b321c7d0214d62269113fd5962ab1161a2a62eb32d0e0cf0412da27fc432d123d188caf556ab99aba99a45660cadfda09566ba7e917943cd22f46de8ba9a51728c76438f64e0a2e6954664aa2a6acbb2352d3f434189cacfb215553f96735afe8a24c750253e44b29906a5b0d37cbd886ab77408adbce99067a095b9494e8156146592cd34a86d0e6ba3ad79a2e66ac64e149653dbc750d99a6ba979d321a756a6a62e5836775c3a74b8726e886237d94cd71208c0a6bb5fd0dd2ee8ee160489659bcd4c57f55553cb23200e4377a72df2c0a57b6845d1342d6d7fa4be8484942c41d284c90f0d423f4648264b829a0809bd7e62290acb4ccab5248216c9d4f2080d317035cdc5d0c10d1a7f20964ddb0d0643bf482896d55be325d6331f7daea14ddea512ddd447cf97c1ce32f5e99b54d3425a6db52ca49a2ea4fc4488658dec4a658aee06d3dd2c1852724407caeb55a2a69aba884c1a14d309661ad4841545d347822b462408a2112090d20ce5737a5bcbd3c86cd25601302320b03818b1e9760195e91ae5e7f67ac1cc583e6790a9e591273094e653ae2591a05f4bdb2d4dd121ff62b28409939f7ca3a131f495d792662b6b3838b6b2f67afdd0f809f26376ff2b769a4fdee65f2f989aba70d4d52cd39b1a2c0a4e0d16e5444d557dbd5254a8068b22b4a619ca89c288c0881ce9ced1a163c751c92486244a8e9da5b9d26eb59cc662a4b9d26e497270f236eb0d7d9a1687bcd0dd3a2d0e4175b7cb767b1acd2c7a1acd245bf4e9d2a8b996a9aada441f1bbabbc98f1112480888fc39f2e8fa3a3d7278b8746c6596bdda427e241a512dab2a49946b20a5209d2093201b4006b59a8d4a9b102f48e8fa423620c4869d1ead578790202942d7dc44888d90140c4280214c0771c5b2517ab3bdd16966a2d49661674e73514e1f4df30e65921661c8e96ea3d3cc34537664abe57525bbfba7c52063da15a44bafe8191464a8cf5b1a3363485a0cf2f5dba4689a661c9cbceb85ac963985e5d8114aa3bdc0c3bb86209de51b9d261afbf586be70c30b1c005a0482459116811c612b737a9222909e3e6fe9a3ab79a49aff67699496b42742579aa996b21b10d68f30dd2e9a6aa24a7e54e96e178d762b7ad5cce95ac3bb90d20ce555138946b379d57c576c488662aa67b645c9ffaa0945e8f582a966edf5424d219b3af42a8d56c25a3f54d3a4b564e85f436b5685ce1286b49a51326da8c9d090a126efc20f89a130578b3f96747793165f5abc88f07ac1eb04af9af862bdbeee1c9cfc4abba9397d9b58566f42383871a9b78fe57cf4aa8f29a20f1960514e14a6965f0ea0c59e2edd64cf5017a1b17cde705aec69b52bd75058cd34531b9ada6ca5cd0acb4545f973cc54bf7c951c1afa2c0b72ade859b422f96c5b616594fcb1fc0485729a2e918709dd7da4451e0ef0ecc063437703b5c8f391218204c87a66283f3938f998f9383871251962c3efc4768874770e3d2ea3134d8f3e9f68ec8bccf48622fd13989922a9657ea434d3f02e9586c2d0154d6d4f2b6ba9aa66552d6d484436eab98379a2a90c76223579976aae678e9dd99663a759caf28a2a71a525ed0633d7b4b47df927fa6a8a16d9b901a687da63051e60bacd2722fad5ace58f9d657e5226e151c4c3070fb13ba7b01c9ce0e084147778819945262cdbd45ab923891d43edcaaba9a22bed5616e5d8cd899e652ce79809336f4dba1b86167788dd9d8313b4e8347170f22e241aed56a4aa1906bba91fcb6ba6d96a28ecff24451d62babbd1a213490c493e4da3f347bda967564f7408508e8effd173c3c1fc1cdfc3b3c38564e86f90f293cf271ac3d0908a949f0c7d113a842406243a3a9d21e84821ea3820851675a20441ca3120e527aea1219d95cebb00f4399ec78e1e578e4b3d51f3666808293ff92274086868a806c845bbc16825ec9168792dd31b0c563e9a8f3e8a59245bd31c3b6f7f7b74fd5f5194c9e747aae173e478fd042d51922387ebcf0cc53442ca4fbe546b793569b4f2693433869c21e444912382eede6931c7871c1dddada4459c1ee064e96e15293f21baa94839861c436132b594b9866818426143345a09337f5c47f98495e91a253fba7e91eef669d1a5831f2dba92e8206f5383d93004488a16a1d1ca21b472c8eb757abd56d82d5dd5138509a93976a3c14e53e8ccb1982913326da5904d7dbd8a6859cdc1894c2d654236a76964a6280e4ede15cb39fd9b13fd73897843a6656a79e4f50a8a218191af57500e4efe7170e24a730d75a2bb85b478c383ebcc9908478b3747ba71803c00bec9db64330d1af22f35af665ac3dffcbf0f91bf5141f0e57b7474b878fef5592d7dfea646a7b5e451f56d9000913f141b7a35ab33fc6bc808a509ada68ada726ce8d1f569b412f63a7fe3aa697d5e332dc73e453faf667af4d9a8d4f99ba11a9dd692a1bf0902e401e0ca66babe9a8d8ef2d9e4c6d5dd352dde70364ee8ee558b363be8ee1e2dda2861e3830d926883b6d0a2cd916e21351b9da50c16240866dad0554dd534d76eea89c282d4f28a6455b39149c408a5ad678692a1a036a12865ed2cd79248accc4756144d856a592d6540592d65b6203d3720b04cc3eb05cb505eafd8aa0ad9d4722d63eb794387146526ea7a6613661615dd5434c34ef45c4177aba0bba1e8ee1474f797ee7ea2bbbde41485adb7253ab06267f91956d26c397d744d83d4d4956165519ad7d3bcc1517bba9b01624d171b9ac6fe44ffcc4fca9506b4e8348568341426b4c2328d86c26a6cdd693eb3510d500d8f4ef393143daab92194c59a6e55884cab620b06ddad26babb552db68e28d73256aeb9d6526aaddd2d27dd276aaa69861233a1a0a9ed4b9fb639b22851c2b472badb6bb1154337101433c3321335964d9acd46a6e8daa4882b9f686abecdaf513291d35ccf1b5a2bd51c33d334434187d87096fff9682817c5ce52b69e37f43ccb4fd1a2b5546fafde644767567fcd48bfa2a7ed693473553fa7e5cf507e4ef393b4aca5792d8f1e28099323efca37a45899535af9e8a3e71799bf6655c9513e8bd0b4cc34d867a2582e42ff5d46a7594361a7f92ad1c7b299a625ec5533cd6b51f9b10ca5543f7696b11c2b511a119a8f3e5666d9bf2b964fb35c89d057cb23d554f3998d6a685af4e5a32aad7cd5a4113d5259534dd9fa43273af4a7f92e23577e9b22f4330c4d6d4ff43639458b722a839539d75e353f46cb66d1aba62ce85d69b6bd5a7e7a3b4b289996d3b5a4e534d750f58bd08fa1b0cfb2b53c8d4cf5f3d1cb60a6ece8d7723d735ada56b5a4c1805464aee8f9e8fa6b566b78976aae59fd1c86cab52412cbab6aaa69061ac24135bf7ca313a5bd5afeaa9a5132f9ae1c86d42c839539cdb2155d8f5c67b6d94a59961dfdf96b799ab11445614fa399479f66d99a8dd0f56367492b73fae56728a52c87a11c4387189d66eccc404338fc9965ebdbe41bad84f2e5aba5ec57f38b90bc0b8966b3951f3bcb5fcdacfe99f3d16a5353b4e88ff2995374551f5d3fd7f0b17306d5e8346db6929666284b80907c627935894c199a0219993e01a23ea8e40b57763d4b32a5d0cc0888000000003315002028140e0a458301711cc489e4f5011480097c9a4c6e42174cc482284671100621641421800042000c0001a931880023ebc8a4f917736295e480c3834f10d4848a3dbe44f02cce07f03d76708415f8b2620584da6780e7a4f0e72a51f9d7b84188c268546307c5d0f082027da03e65853aa8329da77b1497e9f22b58f1b2845c5d9eb4d91d0c22a5575109c9c686815d226e668247fe8671c97b579a917bda400fdb4d1b4c3bce7b79835ef30a34e953bb2d832e43281028a78b9f2fdb7332ed61a0cd3c949ff53069c35c685e9d45cce5eaa6dcaadab3202c7ac5f1b436dc114fda13352b78410281b1c7ceba56e2e07e39847fa2b19d8f62f106e4d1c97e74a3414e8c5792adcbc9770e22d4bff0543aa0b8c2b30ba1e0786d5f56da03f1c609187a15cec8632f5ec8cb5ddb66fac8764c31500f8adaddc8b0ac2963c0979539a7d2a631c8cf00b5f25990282debd94f19292f94a92b253353c164eef03288dfb5e475e6ef973440579a5b43b6a0c989e8faa7cc4ff012a2d5b4672c8697042be5a81b5f1f583088eb9db70088a4e1793fc4cf8b0a940eaac2deada6b0b63eed129bb1bd81f7aaacd32f4e2672bf853e9910a1f5e4e44863a5c2f37fa908a302a5ecb2dae420b7acc59e9f30a2dac25a7e9b396e0298168747718ff7f03848adb164f2bbeb01610951a1647df4a5290a1c722c6b90532a25fd8e8868460c0228c9e21440af44d1d350586e9dd1799e2bc69e3de2837c5f8ab19e50ff08727db319132038f9fbd512c93db2a099538d8301efb0044244732259fbe53d656803b09cca243ef7fe54f81d7198d849b839e20af443ca940bde86103c6ab9e989db1349b418d0304579a1f27df42ec78fa90b45a3f02fc4203fe669bd5044a90c3218f8c0849fe8f1b02dbf97cd60b4e183915ff51ffe5dcc2e0d5d653beda23b1ceba39d9ece60903c1386e367133c6fc1804e9335058914964b041564eed8118f65b96e94f98f6d7d05c15bd9c596498426a87111998a5ad2cf73d236f3f7b1503d0001ce611e9a2d0ef44ae010913037235d455d1e3a3dad8e15e557bd2edc79ba4ca4ba050c8f79b3b4b1ab85c360f9b5c1a04cd428b5eccd10ee79675977ea61194d52b299cda55c5eb80c49734255a3cd2c894803f81b62ec7702e57d54046091feae5af06a6fcd9b36c1b1d1ee08ac126b2fcc66ea40a0e3814c7d473023be4ff195174679b5a42282320cf95915a8b2a6ede9641a55ef4ad45cbd91d43ae0d924ecd54c310aed3586b17f76765db96c9d8452e992472848539fbbb2f7b91ea3cd7c0ec82fdf1cb0a56bc2c07a3c25f83ce01562598cf8d43871b92aec3fc17f6f7677193b264744e1695e7c8030e6b7cf78b71dd3132a98c1cb71064326dafb6492b35ee5f288503020e2f9f57e2599bf0e7df3d6dff59c55e488e6cdd350e749669c9d7bf98eb0da20707bd766a3fe1017f0fb30a4be46eb693280a1243d98dbd18d7c5341632fe7ade366f40067f75ffb9c96eddf3dc5268a9160675c787b92c6e462de98ab993cc5462364cd6d2b3a23ac3741a711914151520348db9e6a880ef719f2a11928e4b6d3744327bcc1522034a56a80d6d3c5efc018c1cc2cc2c72e1d67f62dde78fbeb5f3b75660136899a96d16c47ad1f60ec994576cfe486ae81c32be3b408b1a0b437c64077c29d7fcaa4f0594c2a6fdbaab23d760216fbc73d4b03a70dc05cdf79f0545890c74678e7c36e8e989c97259212affc9d1d4efb264628c3d6c8e4f7c9350270614028c7fa2d6d9289e758848109305b76c6a9967ac55b003d4f922aede5e008ce296bf2c6f52b482e28d9c78fcd2087aac33ff8e5f3cb65db9268fbf2c472f3ad74f725eb6008e9eece1dc048ac1162ff228cc05ddaa4ddbab7f9da1430c3dc10f98f4f668185ade23b507093b0505c767188b8192de3713ff3c1f91413b2d6273d7b0f72574b7d36b744c6785f229964d857ea391f509821c55af026f496faf583d73c447a6c9030e9a3c55c64a683d387971ee6e1d6105aa36f770f27fee7d97fd34fb972aeb096f1c7a6ff35b3e189d34a506e8f47a17dd1ad66138fe3bb1bb8c7e40982b0068d727c06ac112d2cd6a338e19343f525c573b07b7c6d7b32814e8102ff82d751f08b02a52bd2b17ae7bde45e1cd77ea4a5754a5b442ddc7bcc2bd1cfb193f0fbed41aed1c9790af5288b53aef36a17b837d646883cbf110e43c7b39b3963bea3a5d12fdcdcef14a8cd39cb0c8555917e30702093fd19f864abadeba080703c0aab008d36b1a823868b891463a3f25a52e31687e1bd5a5a1487918518b743095ff6ad8a545008370c972e4064278a0fb083c32b2bd8a42a7e7119fa534058a3c8fa7ba999eb50a893a490f5d4b10ea4e94c027ed466e34e66d28ece57d1a2035739d206e1aaa1b37f3cb3e84119cb039588a635d795240164e9fddae3318d78b27f90b5a9149034edcc8480785fc34a0e3b8d09456961eb20c23414a25234dee133c4990ec78ada8779bf7d21fde590b48af7fddfbc31abb94679029a87bd4967f0315098fdf60167930fd6b5b5710a4806684879d70894ad8192debfd0269be3c606c6f97f689e359f10fddad1b391437e1d9cb681fa52e8a0acfd63411142b3364067b63b786eaacd10e9cca6d5f37e229ae79e2e8af5e83a76f4d670f253c9b88f52d2b390c8dca3f759f0adbfeab33db221a4b4d11945a8732e78f70860d22848d7afb92a42d233159ac9f3283c2e0ee78d7f779361c2d6d40063f171dab81bd6b94fff2182ae21b1a38d787a960de8fee426f38b3475d5faee528d873eef395d8419c41ce2ac138bf960a682c2bcfed19ccda40256c6992cc677192cdb76df223607773398fbcdc3ab1ac289ba0e7494c165a13739992ccea553f7d58fe8be44533d17eec37dd96d9f4cf490486567c29b03fd1c290cde96bfe45f0291b07cb2755d9336c39946aff671a67694f50921761c151a8166721bdf8fc34c850183a24e00af223e0acc9434a505b115211d0cb3df2d489ef3f147f016a7bfcb19c6d973b6c3cd335f931c9499e70ad2d380aa2578786ae98e719446cc5162729d8bc6a9b4132407f926868fb395557ca773537306aa2a86c48480768639c2d086d5622b2e5f26464d1992e6a6e5a4aca12e012a5ba889d53e461d0e5f86fe8693e3d2ab629100398c503c6efccf98bf7d8ff2c335748643e8db39aeab9eb4838e3675e55224b00ede60b9f63d08264fe38bd5357f6a8d727f60d8f046bbb24075ea302c9b6a345262dc7bef92ff89cfcef0d9d1afe5fb81bcc920fef34a7e9f29e15a16ffbee175b5bb823ca346d953e76667a276b021336c635631a3b31814f0b69c66919907f6d13e383a911a451ff33b2ad662175ec0037780961bd69609cfc0aaf627a8ed5343037006a6a2cad7b6595fcc6b9d0fbbde03fe5d50b548865b8144d4b7465981fe973ad2d661b9e87b9891bf45256af1ac5f6060ae4afa4d01db75d27a0c1fad49bc270a03a0f52d79c84332502ac150840b5259d06b7b43694e4972b16743ea3a3a551eabbe64155f75e324240cec434e0928cf7c03cf9f07acba32330949cdff426c7d681abfd6191b300de39578ee7ec880660223d5624523a7c0618b942d40d89d5227efd251f771e23619f79c74be5fe9d1a7dbbb8f1de2c8bac5e181099f533ae753e8fa69e703d26ede1ab3d88b8153ef204959826a2c65746156b74f96de4a229f9ad0571dfd05b2929fc327f02d8f90cd4a1b1322a95abc923d621c63580ae964d6c57a03044dc1c7829cc041fbb9b5d221379b4c693e3841118f184b253e770e9314f6de2288fb9bf188dbfe0a76141bd99f3f4b286d1e98c47b16ff117f5db3a8a9c3edb61ecc7701b67d1afd05233640ff7d64e7e0c171d93184215c41232bb10617991b4d085c7df7f2b81e5f78d747db783cb96c3cf7c56000601b41c3d9dc6b01e05307d8e5f468168d5896061d17d3636df256003fc5666b11dddf62d3c520b78cb9db0725312c373f084082f34b7325369f3ed026f3c088d18db3f13d6dab320435c88b032736a22ebfa4da3fe240ae2470c883ddfc09053305d0c3e074de804c67f09a0ce53599e0685851276ae3e22aad0a80c037d9e2d4e651c91e330cc2c9761db6de9cc4983cbde0f71bcbc89b312dc7091833f05361dd03345d85d623a1405eb796b9bc68f87a3af23a0e6c6e52c05b4950231102c7b43b9f393f8e2332142a051e8132684b80c52f81e2fec9c8f2d39bdc70f858ad175033709d736115c50a33d6440becb009574da32cb3038afeabb088dfa4e93cc661839554169288ca930bdaf6e43dd29f7ad5cebb8cbcf52e83439cf60a222284ad977adf9dd21c3539492a600e929b2a792a213d629ac9d8dae626badfa5d18a6e1c04a4ad7ef27c2d9119a5c803ccf40838dca47456843943ec8e655014eb8406bcdc4f79f4d722a1682fd98905808d16c01cbcf376c68725357ed1be9c1ae630146ff10f625aa976ecb5d67b9b3ab25a4332c1a4ad57c247ed5be980840d8e2878a809b10fe294f3e60bc459ce9a8471e405a453acb7e7a10ed69fa7db5ade8ce2a712c0db87fc9919b75dd5afe8d6aaac9314e3635f2efaf606e83af39feecfefd42ccf0bae9f028a7f5586613bbc9095c52ca8a9a16f43728ee4d402c005d260295ebf0ed6c89ee350b03ebed63537e2abf27753e9a97ae125d9ac2aad801ef4e17f8de3c3ede27baf2b2e7d8ba86439a5ade1cb69877f278bba35d33c31f1dbe679b7caaffd7739d37b94786a66dba3b3b16a71745ef54bdd93f517484876238a1c62a16cf317dcf14653f1812800c86f2cf2ebedd1d6f3fd7cf4787840719340fbc925ae8a78ef2b38f710f1074fb6da85295e5b168c2bdf253df8737458ad14b4e092752ba2642bfc479f0841264a5b60b1de6737037ffd5f14d3b87cd0dd58131c8ed6978bf08d806b47570ec8311cbbb39f2a77af8e70b01b99f79f8e7dfd074e5264a8ab42d6f8ef75b01aac17fced3db902a9a9dfee3b0411ebc189dd5f5e8f935c58aeef4f87fbdb43c6c3a70c44db4b0ec5b046ff68e0fdb12c66c5bd64ad629516c45647a38c7d4c048ebcc20bd4b0f664cbb886c5defb56e93b6ffbc22dd26fbc91bb711dd34289ea9f663e5e4db65736fe52151b0faea2587a5944c517d966fac48912dc48c1aa21edf5f33a2be21ca375b0a70de06362e210a97b7af071b436daaff2b4fac97b2385b5d123addaf81c707470800338c8e2b91c9f25955ebc80344c7fc069b1d6099c1914f6e0dacb3d0c14cc5e88e11553585d25340a84f50317384b08679e6ba3c199712d74ab63470cbfd179406afd3a929b4110b6eb64775f4d43a44d25b2d706ec5698bfadcc946b77d8f4cce05657cab944af0b0091a1a1e43df054403d67d907a35e10ef2466539aee5f1978dbceaad8ee871b3659b862cb4d4b749a3b7058b1f105429ab4873d2d08cc3fdf95568017d8b3d6207b6e10bbe841df9f04deb20cc67ca0549dd5a293628335dbdbb01a935eda5fba219c2ff9db5e910152079642e4ec320bdf06816a413990aeb538a647c5e7962ab4a9d2247435c9e8cdaabd56ab8dcb100b84075ec8dfafa943fc89bb85eef1cc1ae33bc1759c4676bb9dfd3f65dd267ee52419725c5256186d8f31cafb261d8f530c15fef6f5f8279fd312faef504f89df7e8c3e3ffe5e46a7836845a675b9c66787fb788a2118203a06e4158307f281d39df1f09f06a1040fd837c704026810f0fc4ea6f935ba2d3a3dd058c64b019a055f32ad40b1c741906280d2086f319722e9287aa9c2a1af9ec9005811b52f323e1b7c7329601945f5ddb7d16d79264ddcf3e042ba5fb3d4e0f78d9dd6fb98cce4490f2c225aa51055f05a20567500fa86020c6a9a1b2054cbbe1fe595dacbd73998592780405cb6194f9139d1e373877ae4a6f85aafb87dfef427a9ccfa14bd4774b2e1ef4d0ba685df58e5d7059a9083f7b3b2d61ff1cad13fb432191b280aaf813a94f593f03a5616b9b67eb552d14de366589506cdae7895f081614dabb5649d7703563a24911da4ff3be88ef39497c3840311332ed596134acac5c6eecc271bce8fb81ec31cc8fd4decdbe93e9b6e8367e1cb4ea7b137f4ad1730f37ccb17d34c6ba58a4bfda5b410dcba06659941e2da6b9a0b58fd1b3154f8ed5c50e6544e11a4cfcd3f52ff3c34448c2f5fc12dde6bae13a6aff49ddf4a5b02ef3d80a4914da1ebdecf05eced1a36d801923f5fc03ad2b7dfe8798dbbe1892c2f6b2ce6ac12565800f23166266a34b28dcb2445f33e423b4e5dc72d33decb451b7aa77a238c9953f665b955952699edf8f742754ce5372f905929cd0d3e667eb0045ec63c18cc97ce953b2bc53c10da228676deed336d37131ab160da800637b29c45499bdd02620a7c149e17e65b2c5e150ac0a0d31fc2f296801c4281b79268505cc980038e32a36e798439d1a16463fde11d55f86a58555a22eda54487c67e0b529e00d6aee013e709987c574dfc84fee2dd5c8d7c016ff079d08ceeb34c7c162f72f4cf810f576aff437bebb5cdf7612f6b0eafc862864a537cdd85e195607e91ee084f9243b0396f24d21e2bfa5bf55fd32c804af4d2ac9c8efecefd14d48c37d436d09937fe44f7ff8b71f8cf44fe2610639a09360634f5f7194cef7edfe43e63d9417b5e8e340332ac8606e0f13d37b642a768bbb3216c5e1022c20e4342e84114357af70d09a637a0d6707e247ce891e0b29bea2152942ed6a5c1bbd9ef031842e34f597666062039f082fff5f2ef876abbf8c210e12c68dc31ff9442b1c31e760f1ee58ea336f4070519f297fd17627adf6953e97dd35b7fb252df1fa86b53ed7cccc16b5620ca6c2514ef61193ffab06fd41659590fe9e43423994e6e9e17fcb6bfcdf1074dd1f6376e7eaf3faa20c14f16f4b86c4fb418eed02d2d9f4ae63def65bb2cc1d9da7e86c8f2cc7488791dfdc86ebcb6a797f8e82fb68c6ea0f92191af3f87099e49ab8b1828051fd8c92d4550f6ea4c7b9ff6a0dcf2beef4cae9ee5513e76a9372ac0ee17aadc0f687b5d40ef0f8b6ad867282ab0ef04eb05b9a82a08c6eaa5aaab9e5cb2589978012ade419fbabf88c316e9d393ee3b9dfd1189c09a45fa4e40dc1fd787bf6459853989c9551edc9dfd064efcb4f637780ed0cb11b7c3c309679dd6c56aca2cc7dbb9c2342c6036c34dc89c57c3f101f8d85f9d6d59cf0f66a30be53af0d677fd4f69f89b2dd2ad299527ca25bffe9cf43f8e77de17bf93b1459bd9305c1d55f7ff0704f087ff32eed358856119e8719f760036f7fc4851233b6b3d8dc1359dd5d1184ecade4a92904978a3a43523f27515a5ce66bea03c7cdf1b600f41916ff8ba4ce63d6879165367b415cf5c097e38664c0be38f46933a063daff05b0db8cfc265bad8742612f50ed608fe52249ccb8fc4f6a2f0b17ece81e8758cba9398eda40c0ca35a1a179ff32cfd7a10b8389a7c2b5166239cceb93e82070ccf97d596d7579a20a62d4253e8c16e32499f8a38f8633583f690c64b81016a9781f6fc80a07844ed897fe72449cce45ec09b7c5c8eba63d66a2045e24ee662980463751a31dc745c954545342ea31ba987451f70709300b79063d4d3e46835e77298be462a1081cf5468cd040204e3df669038cae8fc6741d994e34b85a7bfcd11280dfa46085c74eb2d624e32cd09fcbcc0d0e9fbd45e964af7c6a02b56c671293c48a5a82ceea17e14600d6ae368823941ed9fe0285fe88d808eafd9d1bab0fef601aa76774043dde19a70ad96f52585db3617bc9e4e1bbc00b1a0cdb8f2ba780ae73b80615d3f46c90131ddd3a306dfadc334e56386ffe8ada1b7cb41af9502578bcc2812bc9188c77635755d840f354cb965345fc3a28b6fc0b9ae048d405171ef363dd0c1fc39b02ac129360d1653b80a685d80a8d2320cbc6513481ee499d40af7042c497753a25b900932b194b1d685f6982a4c2796fce0849a6f2fda0e92689db0c68de313e725409732391a4a0046a8249cb42068f410f4b96b9c261972474549d415e8dd39837e9e82bfd9dad509bfaa4ffc079207abefa4fbd44d2e26447ec261e34504a8b55c4ea7a467680a4788fb70544b3a3ae8e1eaba04e54d34676476065548d7dad0fd190e1ad42e32d6c94135d3bf98f8f816f536a30316042cbfdc76aa8108190369a52b8ccce111771670869d057d8976d1699c3fe0342a38d7418063ec59d9099f6e4521832cda1b94c7c086da557c22804bf07bb301719dc571811c99970abc56bdbea7a34cd8b18326e03d00974fc48813eb40e203bbbe72dd05f4ac27a9538e608d326adca51ad3cd1aec1d997a74b3b7e9f73c0a067deea051d9316684e3e191cf8c2ac8cb4f596e832ba6831715ab40b09d5511304078918db121e1330805b3d95190a3e66bbcb4a34db6244868b5bf3c308538ad2b300796132f9b64fcfb3f4c00ff13f8f4caf8e8c8207a6c6e1536ae879695f17c061eb6bbba0be947fe075e4d67763213640174ce645b72a434f4f3e0c6c1ed3d937b3592beefe7695db9115fe928372fc8be17a587433db8b5de59d6ea7fd80a24e04f48b0e780ae629bbc4a3ec0f0b79bfc8f3639cb7e3bebfdc31348870fee7f0c0ef573b680e80b647c6dddd165850b7b34e07ff6a4e00b36c338e7c3492f4784041937d983ff97cbc3a08bf760c00d7ae37f41d9c8d6bef0161acf7e2a8af1b2afe7ca92b140a5ae5a57d531fa656feef083190788ff5975780d2312503e11ba792d921b0accaceab9b7e7537d522ba063f18e7ab543174b755c2d6fb70a40de667ba6118918221758f0e06dbb9ecff078edf2a5d7005449d877fb553e087c22e1504f3896bcdb22ba8630889c3892c0346c536ad226b3e60217341107b7ceedfae870ff8500b047b60ed60f868b6d27227b83b68a3d7055d4507e79e4b1997becba2e6c17e50dd697b99dcab7c42d9c5f4c39646e714081b77b26a43f3502da129b6b0f59bb3a0b6508e0f9d50ce9010268e2b24201e4521cd71c152b4322b9300c3c05518bbe4d7c93534c385294011c00ae7f8cc68432d510f0edf4aa121f24a3cc5091af801280c1c536e928ef3e3e4c4fb22b3be74996cfac519e7debb9fa2b54453cf86a62d85bb6fb541134ca8161b5e0129135033a0dd9c5288fd50f5d331b0c20dc093f73c29335bc7043a45cafd136e5b4cccedfe6c8355963e36bb8a6333ce035a1ce2fd57a05e5a332c3e9a36f8c3f5c019fd84226147b864b3556ccdfc4bd520fa483bd57c395e8f91e8ca56d1fc45c4217da54ec92539956446894ba89677bb0445e9c9861268a71da8bb09eebb0fcecbeb2b909461010e71f9a48874b28268c7a1c7343c38579621bebdd160eef3f135ed82ab42183f9318f319fde41e09b0eb1604e5bcae2b0ff6996415098271db9db4f58e15890e15e0bc16e08d9575cb046d2f5b545740cfc543a60380630f842f3ded9ba57184a54afce5f9bcfdb3081a7ceac8e8853d31a886148816ed2d3503b5aa12d11520d17e62594c19bb3805c7ed7b0e488639441466e61885202d987cb9dca55529d738f77289f093fdab7bc958e7c9da35a38ad40157f77c11b999b27e75331e86d21eaaa165355f4642335b2b921f98e7a94d5a4cd3fad544a522840ddaa6b8487a4d6f051a7d833fd1a02c1dc5d33e5b100d3395a0ee6ccb49af4d16ee6f17e8e704bb17d828b3d812caaf5d0e61a5f105fab1a9d22e5b0d1f77a21b1f15427ef6513d118adc17f92bf215cc05a5fee8f4fca48a6152c40c948e59462bebc010503dff0294c37407be705ea82f75174ca2ef23139c78c2a5b9fe5e4025143f3b1bc6784672628733f229b2900586045d055681be74ad1364688621c912a25d3468c42ae54ebd32ea8f57f10a1d92384790e5461386e24cf4bbdbc854936291c78a94918a2a98d4e7495d359ce3997f9bc4dedc51b0cf471680c8c06227b2a69ef6e3075e7d1eadac7e7c1228cd73f82d75c78783ced002948a6d321774badede47b7715e9f5d7c574e4f00eaaec934b54447cf60b0d5937281200c10f93e0ba34c62d89c99fac6a2f72d50f5ac1c4735f1f7ae3dcdc0b9ccaac4c0d6d559b145043da2dbb7601f9a7c81c919a14a0c92ee35cf0eacd07df77e37cfd1a78c312f88ef9f95bc10f2681d688fe7f57e0c126505ab2dfaf830e4681ed997fbf0756d805b646f9f88dc00f8340ea18bffd3dfd895faaf8fe0b5030919e4d5b1438494fcf260a46d27b6a090ae9582c6578b5580e0581ded572325f77b10657f3b8a27ca74b9d360b5a5b93c77ff34da8f240af061f462c35b0c32f135316b33f172cec77846dd10f1343b407c6b96ce49bf871eaca36fe6fab71c2c217d21cdd0634d5ef4bf1d4cbe89a9f33f457d1b647289eaf65af0f57522fdbf6aac23b6fbfe5edbb6fbff5e6776f7bf3def7df7aefbd37dffce66deff2bbfef3dad1cf128198febc61a33feb5feff6d3a3e2b7f8bdfe79999166517888ec6c8163e1f39d38783b1451e29ad229d75567018bacb1cc0ad6ac65c92ad6596289d82d9d5c1cacd138c062803a091fd1b508846b8b0ef6107e832045fa54d64be2347509838660e5de50adcf4262c744ebfd4987c5d7dab1e690291facfcc5e72d09b129584e89bf807aabd84270c0ab7a188ca64b3f211bc27a20880ca0e61ed380ab1c8020c977cbf1b33e4a744a33e73c890cd689dee9f5e9a34462005144c96a574c3ca9c6ad67591e257aab62e8a591a7dc1cf1b17589fb5b30230945a24986d5d8e1c3a186ed600867e68567a9352478635f959cd8ca2683ab4d9d7994cf4c0ede6f9c511c75e6b18912dd5abe9bc28a5bf8254a34896dcf19c26e4c51a21fd5f45e29621c66aae0b985e80a18faa844db4fb73ad4933ce2c4e88e53cace2ace9e94660666941d4ae4e0651a11930f1e1e84245c60019b3b710f10a8b6dd7fdfb1fc62b993d7a5e2170658c0400e447009e8086e6ab8f35c1b184b4b51327bd345ad2be9c47c5ceab2044a33ec9d75239fbe084e7969b85377124d104ec810947831710e7cd073f695d284c7263abcd0f2111d3919cf1922925ab6045dd1416e3c9ae84ba671e27a81e9dc39523c3528dec0ba5ab84c3a0a204570bb3cdcb87fc373ca835a288556c80ca7cb0becfbc5e00b505f9d4f04c32be0e614d863a5354a2f4de17f5f6275c373477792d6b58b19483fa1b1a80efa7534c722eb08cb696769bdf28e46f183799fbcd3a4e2dacc4c0431a3ad1f6218dc2c92e40f6c6170adeb0b6461a0089a17d66e5426be8092c2e0c896601a3825f04cfe80c16d0d40ef7eb484010d95360de4f69c8504c683c3819ca75bb2667815e0f2491883893a0210ffaca92287a98c1654df6f3317694f98777d65178e330c08c46393d02018b9e156dbae3ce3535f0931a6358cac87d839ce79c8535b6f01e706675944450299ee94343bc17880d05087fd3a5c649be4be8f5a777f1d500cc6ea45287f67d530be24996e3e54b45d4ff0a6b260474a483d7dacb2cbf3749530a024b45d0aac7660ecd7644d17001c123e675481a98588a691b3f2386834280f59da60c233071e9194adda5d23efd03c718536c42162a1cfa160382b505f14427a383ee66b4368edd27a62d5c915f981fd4fceccaba288b5c86fbcea310bfe7025b69f610b2453824d9ef1c28d1d030356eeb3ded8bbde5f405fe3898f5ee42c9b2c1488279b3d4f53a97c2e765aa5393bd305c4f7745aca31a26a4a36d64255f06e64c72e05cb9f3ea287e7c8d445a3634562871f46e7724392689f81e0dc9a8400a9bb125123ca20072b36b558444e5eb2219e9f433cf43d6caf40f19ba36cfbf86fd370299aa5ddaaa91332f029f2ed44467fbdec42ba4172d1e9a2388b99dd1b6738e02f950bede874d173b6b1305b58757a8664cffc953ce8f10175b12ff8dd329b22d4452f2b072bdc23128df3a0fff247106fa362804875c030000317eb706347c08ee6fc1e84d1c085ddf60d1f734a71aec5e62e2704315d87f8570b9a2fb0ab29bf820571524bef4e368fb9795d1dfdcdc53b955cf9c592731c02d9512ced812504e11b0dbc2385afa1d075d45e7b61b06adaa47b227e0ff3e309080799040d1aa7783d0a038509b1b0dee0d54d03d9fe259909f4b34b4884a18d5a933d056a55e04fe3529c317883412527b7ed5ced15d0d611aa8556c1805c8ede821d3cae944ada5fecc000428db07f176038d6f63a993704864d9c7e30e1ea112af8ed4b59f90360be3f255c9ff000ae9d98fe866321b087a72fa2b159b5eb3ff2070aec6a4012add92f8cd00119ffb2646d235ca16606ddfc181ca012fe609c51620b2c55c40ebebd44744168a4db2fc88c0fdedbce47f73dcc031ca8211fe3ab0e0525a81309fb6ff522364ade80ce35da76e79e2a9af00557154742a004c3e354e1718b7d231ae11a354723e560a9d69b81717d0875a99d9213f119e7cb23810af267d18fc5c57f8b6bbb8068015f605ddcd7328fe4754c404d5a8ba6ebbe9235954f6922b202e3e4e06c210445cb14280cbd9f66ed3a1bb72a9cd0a1745d45f34d704addf6ccdbb56783c3b9c75e0c8a7b227fb767187a3e000b3628e01d8fdb3f892eb5ea12434a9eac4eb05f5d86298197f1bb7e49106ea9b890f66b7ffe5d30dc7101c7a82b684bb4b40801381d533e305bb8771d8760f4bb0012cab534e114f50b5e6d3788f6c70e27f92ee353a4d8f50db0c557bd23d47a65c693bdc4ef78e191c0554f0962dc25dfe45ee073b0f44ce2aba78931dd926f72aff13b5c7a2571d5d3c5586ec96fa957f81d2f3d9378eaa9626cb7d4b7b4577c8e96de495cf53431a65bfa5bd62bbeea635429a6c34e576242c20e673721732c893344b2279602a6c6b57e103505ee7a1b4ee6fd7055d1dda0359fb6bfeff4895adf2c77b4dbf497144fa1c58fc95ea4dc35aa08eb7dea5af64afe87646f52de1ab588f136752f7b29ff23b227297f8d56c4f49eb895bd967f2d3c156df31f389566fbd7194095b9cbc58ca2acb365a159734d1f885a017bde66a7e93eac5ae83ed8ce47ebaf775d92d67fd635ea66fe49c6a768b147622f216f8d5ec4f49e72977a95ff23a99728bf422b627b4fbacbbcca771d3e9566fb179842b3fdef0c48d55ccbc24cb1ec99b5a0a9b1a60f46ad807bafa6a3793f5c4d743b68e5a3f5f7bb6e52cb3fd31ded36fb25c653b0d823b99728bf862ec47a9fba95bd947f0d2e956efb17988ab6f9ef1c4895b94bc50c91ecb9b5a0a969ad1b445d817bde46a7691f5c5d743b68cba7e9ef7b7d92d677d615e536ff25c65364f15a786adad63f602a65ebdf39904a7397891945d967ab42a3e64a2f88ba0277bd4d4ed37d78b5c87da09d47cbdfd3e488484d43c96673ed51d08216cd59266616659ead0a8d9aebfa20d40a9c9b2a293d9f4d2b953ccf8aedb575b6ad66bf43d05abbdf5170155dd3bfc1edd0d8cb70c7edf4398e0c65de942c31f40c3610d3f8d7bf4706213ee3016322c1c9c3cbfa975dcf37f8cb90381177b897125f93573825a6da231640720901e9434536df2492cb35e66fd51771b5ca510bd471720489b9854011eecea57dbea99758d0cbe7018a0128507ab4fb0a627d1f83f806aa3cb4487257a1b858f21d66289fd203c2fa57994c67b4d86782ca77d2cd2ba426c5dc50b70df9a82ecbd6c00d89399d2cb1a261367e2808b25755ab11a7d5154be0e944d4acda4757c1d7531aa94e2823a06c09f61908a0349f5268df9cfbf3b70b97afa0bf35768eaa4e4938734cbe2dd68070747b2b28b02c3d11d68442f705f1478a8402e1bb5c166cf8857add440afab5caa1325aa3554a8534ec4f8276ca2b21081e03c413546a707b5a60cba4b3adad8db1c2632b630a31c58880d1f86191b354b1b5b0c44a0111901140f0dc602eb90932cdd63921863490334bb882534dc68c356bd79d2232091538016b6b6a0d5a7ff4d309ac0f69eea74c0b4e720033056a6c734299a4d7ea7900269861fa0e53ce775dcea9a94bc343d39adbdd17347f6fa603181b28e08c47014fb183f827cdb1444cc9c0b54a6a5934b981fe1797612d2b1ead2b7c9801c6953a3e2b97172c71afe52df5b1ea0f12d6cc798db5d6d691c8d70c6e10fa4c04450108991e5fb13158ae054070cdc486d47c4a50200c9b4c011032cc7d45c6bbf7f0675724653dd82e07ef0a419aaafac59571896eaf248e80db7df95b4843e81256c00b6c5a73af8742ebcb672d1b7da70e5d41a358b588ec7d341c2a73c0643c0bd307fbbf779aef5ab610b20e5c0177a9007d3b044db7cef35f4ffc4fa01998462e244d47e2145be31bbab98b8357fea9c0999c1c84e5a7ea57701fdd122bc21865a0940f989c938d8ddcf22bff032b41397340bdba126334fa1861d2d821b6aa1504cb0b4e2ab82878bb9cd151b0756d03cfa40bce9d06ab4ce016ac687381be8740e57e3162d9179cd07446dd38b90bb85711685cb585cc723f88188589a5b3ea976cba3e81d5fe7084aed9288e4013c90e01e0975699f0411c5e13c4cf62bff317d35916da2f191cd78daef965e8140cc39afb13cef616d1e9a196c7548e400b576392a57342d22c1292e642489ab442d27685a43f9a4c0730a898ad425604db8ff9bf73b249c6cd181a732407f7abdd7647fc7db8ab24f989dd66e84a391e66f4f2ac9a5d08ecabee96d5bcfb14245f3457a82468a1b1b2aae47858737e0df6e379aadd0559383193a80c589064f754b11464693624e98d97cf261bd9cde4a367818981470a0cfda9ffe96fb2547f98177c99ac1db79620d93f6091ecd212d34352fa3fd594207f9081e33d58faf843a301d2b7a662a5604180c8507d88144e90b1c77b0813f16e52381642e4413a9b95211acc8f362112897744cc67259bb97b84105ac930788f7819ad641ecc171a845c9a05f536600599898e025b0d8d66a5f9ce68625d079a951728ed40e5c5da8a062e15149ecaf3583311581d7769e11232676a6957785d32a5592900568408f7f84b83a2219cb30b6ba15e5256528279207cc41b4c8e95a2f70e314f3e1da0e29fd8397e74708f6acfce068a92db8e98fad0ca7f5575dd1c71112ffa7a0a6e6574ec7b83969772ca8413b1436cd75dae1373720ebdfa8beec3de931a21d971cf8f58233d695f0e59519914db3025e67c2f598aef8506f813389c79b8a6a88d4d338e4ae45cbd792e4661f5c127381e1795d0c5c3e7629e74dd608691d8fb5401261674cc38c8f3325ce8c33f6eb38f931a5c725d68a03eb9bea0c5855e13b09ba6caabaac83135c13819d156038850d78753b501a19bb3ed4df02041bde9b9be74b824057eb5670e1de0136a92baaccc637971e5616ff8e7e9cd7d09a5c1416d7efc39c8f92c635b2b84508ba6f438bec09810b569409a675842aaf3ef0886fdc74159ef9ba84a15fe2911314e3d18d1553ca8925029c4fa555cc4323130d8d34fe0fa7fc8bb4a364b9cf1de2d6f60b9288529a7a4d9735647ac4bcc46f0c02d97e37facc228e908e596e6f694d18ddcd6a9df4d7253a67f4ffec04e919aa54a18a2815c495b654e01e57f622ae6dec4916aaaed19aacc6d2049ab6a5d2eaaad8b93815a62fcecbe04ec3e3a935900fdee12086437113c9bb3711937752f54aee74921fb1b6989d98eb86c0edf64513e35c38f6ac67e751765564dd0cb4b4e9edfd6a89a14e7bb2779e36db233127172e02123de3c208cd83d84cd893fa95e9c236bf6c609acd9528c1f26fbcca9bf50af5237ebcccb29d192da0580ea719c7039fb455cd40797eb2e2b714398e727f13eb487d637bf05f1ea5fc419a06104e5cdeb669386911995dd6c7c6e259ff066f8921a26a25bc3a449ca19c8bb6dd8a8c25f592acab722a6007db8bba0394c01a62d73855a93d5b48d14ad18ed74da8267b82d425771e3a488851c3cc1a2ffb02bb977e29e14f153ceef59bbaa376f9e8681007493ef37e3414eb72402c3500e1f7513f163e2dd70c1564f5bd9ee021d0cbf7c45ecd93d7e6d9d64c478d6a2d617b02138168c253e059b686e2602a62586a247841e1f68259efbf874ebf8fe03c7302ed090bad7d430b9b15efef421880764a98d244556a9a132b86c4dac3032d01500d909fc7800c70119758893d968f0510696c6dafa57d8c8ed016df964a07ba00c62397fd74a0db015936b48efe2289c7ee24e2dceb6abfdc15924bafeb19603cab1891b0d2b24fcf6526d62d8090628655b0047ef13d720f7eb55405cce0cd0cae5c1311111fadb579eb1922a8c981e310a27ef83705537da3fc6c08b90bb42584e655238624335b594bb66cf75e3d095a1b97c9ea4a36755cfa3f73bc2908deafa2f20d025f3f82f50508ceec1bf780987ee332ac02432d602673eed0e711e58860519b2940112d72c955a2c127e8bc5790425c02ab3f6671a2a38931858c652bd77a58d170862d5c3387a24d5efc193251866598be6b43209ef339299b51b53321c0877d2ea084bdf8fd6e065cd7d796585f0a7256e8829b8383299960e98d82a51de1ca0377ad3d4c4e12d46a3b3419850d0a6aed9598da48b7e12cb71dcaa74e8572ae71704904816e2107e690a9913a98aa2dd87ed69800dc08c7c64553e344afd59ce742c1955005af2b1c4d9d87be514366f7f33fc1a4abcffc01699eca3777b10b4ee4a9bb10f2e794db3f85afeaeda7e01ad1b269b07a6766e487c2ee24bf4a4db43183e6e69021bb3f667f0801b0df7f1d578dea61547130968a17fedf37a181e4718668250fa42857258aef85e48c6a64691a9a460858b4690a9160692844e9941411d2abdb2dfde444d1c5ffcf0069aa3f8880c60883807db47193f6aed0a09b4d2bd9145dbdeeda28d80afa034a283b26743308030b181163ff50d7d96b675df072286dee075e3f64b284209098d6ebf5e8225845da2251c4a66a54e56de58a0165e42f6ceadab3aa2105a0da292e2d61f92598fbcb45a6c8b1c396303e9a12839e64e7ac931e60e847d1fd866bcda5d5c4ba3e581fe10ba99b4a45f40e3fcc00204f72c0f745932d052e9a56d8d524cb62230b23cd079f744b5389a35825bb9d2a9aa3fcfa197a073d15b29cc197191f5a9b1bb353b584328f6ae8712b41db5bc0e3dfe60fc746bfb01c855c4c7914267de9a429c5fdb91326ef0d4cd843e4c49721027db1655e7c099e7103168d42f3ae8467e4d788c1d0874294085307499503473c9abdda33a6a61a32aa0867d8fdaa0196db6fcac1f127ecedb00d2820b514844a52886bf6ce3c4d3c47a49dc6032cb29c953310160dd615038943434a478375a7ba90e99a2f8c12611e7ec13850a1ea4a13ef60c6e290779e657feabb185669a835311b6c0235c2c61b0790adfeaa8890ab762ebad010c10db58f84ff0e1616485f87f5609a2817a20a149f3678ae0580a581965e39f562705da09882fe6433217f54f8b64fa31a3480f1e4c809c907d9e138e9bce4404ab02bc55300d93224d12c1c53e3e3c65334720b880a4338904f3f2b8b5a70630118309c8cc6ad8f649c409e1f5f94de664d131a1f3eb724d1d55a1e818e4bcd530729de090dd3bb080d0a45dee2e09a84f5474a03a36945f1cc3ae34baf7cc706649d2cd4a9de4f65c7ee679ccf78a2d5ffff4bf4b595f8e9d5584a255279d0d99fd6efdb0b5c71292c927bfbac515341d83896401f8ec02b4e22af0dd7fb6ec79def4b7321f7f7245bd6b0831e2dda1c9a42f6c7930925fc612bd439afb201b32458555825e085aa69119e11d28370ea8b62c4d40d96a7990010e6f07ad0e9ba6fa275d108c0bfe4df7478be008a7438aa3de44d5348b514e034934df6d4980117cbc082aa112fc260f4bed08f7206cdb71964a971090032d7bb4652d9fceb7bb72337d7ac2fd32436d6bd209aeab38e5d6fbd479e1cf5b426cf59364e160b5f806dd8832917ff2c71cdf9f43a87c2b2c65942e2b13b0df944669a0eec7422c4e94587be9bcd00e955ef4ad1dd324fac0d2584393249e9a9ac80c67ac5b205aacce72154db281c1c554a3dcc3412eeb8b01303d072968714d7d656b9d0a180ee11df4a15bca936c8220849fad013931fd3a72aeb972a0fdf2aa45a7ea1cb83b69e7c6d31bf1c622354220536823a20a72a529c8940254b969179b44a29ec5a87ace8971fe31cc479cac16d575dd109205c7641d9b50ad5e83adb71c4447b8eb6ed9a6eeab69f8d7ff281444f58c9074d029dba8e74efd721c710609b7dc60f801d216738163b888c35e37a6480cbd62eeef63e0933da08f5591416daf58d13701d20530dc0a2b3c1c91c6b6d235090017486b0d537056ad70b178612cede01c81f03e5acf1e802e775e74dee04c0483b28b5e71605ae95565d94e29bac16984e78277dc5115758e48c5a79f7701736aaff7ae9e9d68c7cdfd738c004e4e3a2cd5b66c6c8453260205c777a3fac2596b397e15d56cec5bb23685f23255651d8c0aa4005d377b7307a2306de98222560f449a4f16df7a98caafbc624589f55292f8d95631cf571942f8218cea79739e46c77a8247fa669d52bbc3eea686abd5691ba2f13a61cddfdcd80a9fe37f481d08c6b3d60c75cac448e3605fa10fd053e68c0059ced27e5f2798583f84372cb7d414a830b06001a5db0cbd44b1c19c1c76e0cdc9f58082aec25db7f9e35210c824355565a1c466fe58825522942676163f166c86afa0bb10704aa68ac017fa9bc9b16a4e0dcf558a5415ceec4242bdd546b4ed9a0c3c23cc036ba02efe26911a9da67b5032f61c1403868f3db50f2b29c7f120bc0ecf0350f8dc3400c16e48150dcc70c80f130065ed795a419bf197fdeeace02234df4a22503be046c2339d100287ada6be61f210f7345f1e986d8925e1bb0b88a663872bfa4095fc3d61cfe665fb0b395ff5da3743bbc9f6640dbf135d77976ad0474c24817457d5868a330a1acb13f4bef7bf7d426eaab4a0d8eef32e78c6636842cacd731ddabcdf8f40bd50512cc16d42889e9df9e62d75ea0157e56fc9dc063e18b6c8fbcdab952ad67c978746fcc3a520808aeefc8c170e0f5e8e645a74e864a489f700d180d91471758050ed12a75c410c701ddb434190ba8ed9ddcd8b94f5d29652cbd96eea36290159c8387cd44b98be07502b7d1e9ba95fc7eff6509b398d99324a5c45631e4989a18d463d611e43200d4c2661702c0f334f7ffe3018cf7fa7c66e417bee5b9f2df30d516cb8fb70e53e0e8dcf183dd57a858b1ef3e8fc080c04cd53642ac9efe6a5e5388484fc277c67458bdb037b836c9131d1bb6c9c77b603e72b6894eb7f00690a96b292e6731f9af2566ad8829aa61706eddfbacfcb99ee88b86ea8373ca44330185f995956119da8921926a61c0274f06f6e501da71013ab79cd3d1804fffbfc80bc20419fc2b17598d5ce42fcbc0ac83242625341257809402557da8bf374da655211dddb51bc8d56c4f801a34d0ce795eaffb2f6257937fad756009fbdc686826d6a74ee9c31ebccbdab4209adfb56484bb67d30c4624c8ef6f06ec11557ab585ff35b5d7612726da4f21f11dab75b48a3c9fa2604211a8aa6e6e8a02fa22809a18af5e0abd27f38d6d710446a85a8287f94e2d053ddf6a5ad80a06fd766b154d6ddfa3381a4df327be2218bd4b18a04a475f0e765fe113eccf7bb617251167e6d5b19aa1f71997bfb2bd3c5be744281cbdebc48cc694d464ab60415c68f546043b8d4a047df3d97f31f9c40ec081876101c0b3a8aa21334642939499f6b1cc00fcccc2b248ef229234a42bd233d61ea2ac5982c950c41d9fa207545c9f7e5148df6df1d5197d401bf543905bc56c0cffa148480836987c5291664289fb66b6aadad0a76ce4d1d21786e6c26e429e80683f3d03f5961ac8905fa60d8281108740a48d211240f1c46d163152d5c7f22d2b81b9fb5d77043422f897680ed15be9e9148de15613611ce201d5a961a9749231c1f47ae07ea38e4443a72d30c67731abe7f77e50fb37648fd334f1438aa027ebd92654b1480832a62802e92520735f2ccaa2825048364791cd452470660f08c0de8f0f118e99c9a77122beb5901a26a341efcde9b81d31f92d973f9dbbfdbe49d595a578c31b49e93d9000da3bb53401b038832c9c1b88747706900fe43a244f7cd2e4fbf23f9aa6415cb25425f50b6fb5b4d9d951bd05f3f83d46f37d61e83e367900b9622864e7a0bb3241359494954182740e8394752c7519829de8672e64c3c22adb754146283f8f250b95239f2921e04721d65ca566f7e03cd06d04fb7576303d3dec845165cc38c381f573991e91541c3ff7f34ac5ec87971b68c51f9becc568c8cdf934ba7c0af4373f17f1d98d3236107d510ffa61eff1e07947bf270a15a1c3d22e439173e21bc3038fc0a82a3896e3d5c849cda46a089d744ccc4f5dc7c05f141d700c6c86e1732c56419fad4ae3445b3899f811393948827395650342e36c4a3d3f8815c93999b71e273cb4a194f7a3bf0355da632cc3c636de9db95086f9d9bbd3a948b26700d0dd7180ef6848603e451060544ed20901a85edfc04b1910f55d0d3516f1cd22c96c13c849fa33b5b4c5885002e407a89d275de5aac37ecebd2a4c2e5c016b837020f9de936e7deff1cd4d656129e7282773f948be900c52791977919ffc2e34b5a5f7c87b5f3b7998132ef958faf6d817747d4ff9148d704c660167515fdbb54a88ad5bccd3a9390d440a908b3c278229113e6a30b2a6372171792d57293a5fe056fc96505cda410735c530d22cfecd2e178c5af61482917403617d5408affe89ec58496b80fc12348e08c18da8caa976ddf95a86c6d43a94316d0d60356849595649bd88f11abf4c8e76cb6e0843b8fae5de2d25e05e2e7a1a6dc0b18ee91b815d64f17f938a05715ecc18f8ee136a8bd098fec477babe91a88e496787c7fd4d8a435c9a6931726252363aa99f55d0dad11c2d436d804a2df826e9410492aabe2abb2c061513c426e55cc015ee486e3fe5d2f35b8f977de98d0f1e41afc14a568c8ea6dbf23c81263d76f2114884a18f0eeaac6468577b1b9c5ca3ee4e0b013fc95557009fc39d04463f891f10b1653862a8c99100c19e80c4ae3736a4943ef74cc7812feb13c340069e0574d72e9fbace026ede6d22f836059b51b9f80270c7dcaefdb454dd4baac6613cef53d2b4338dd1f4c0f76774c284da00f8f0e08bee02357896b01bf6b2d73a09a9e98b256c1c0f8d70826d283b6d69e7bc6c97cf5f87f6e9e7a9595c2323f529e342bdbc2708299ed641209b03234c93c0097338293f8ae2134940291a309fa4b439281a651a206385ece16764de1e5886a68eb3efd2f3d1e5bf2592f917272f449ef43e3c3357885545a905982ea058ab204c3b310a018718bf4e983c156a84e94fc50d58ddc566bfaa0349df2101f02f64f0e149e552077a033abea414ce3193c7024b668ff57167037882976b501adee1a61e464a7ab48a160050f1a92b8be29be63ac97c4983b015888daaec9c773fd56b9669028d184ef8e1cca35df8b3ce2255a24ee6f9b72a4c1561b493abbb5510a044efbf84664c2e862a756732b8cfe4e015436508e7c6a6c6c365592aa697f073f70dde809197a894548d47765c517275e5225d8148381b2b58ef866ec477b329985da4ce4c960db3bbbdb4d4f5648032bd9b619356e1a2de3245bb753651d9648ae5c3dd63d536c7854a28fe08fe2234ceb0f7b50d881630fade1cdcf1fec7187253fa5efd8c0ab13469656849288fdb8f06a473031471cb288499e4ce6a87ce318f5e989f12881c7b071e440c60c32ffccff0cdd1e8b06ef509d1a7f1730fa3125bbd4b864e10f208d45d553642f0f2962b5087ee48bdfd5d3edcf64223ec36c3ebf2d9c652eed3983a2287c4673673114b24cfaf99ec3e8d32f93f4a0249c5505450439081859c6fb86f14ceb3fe3179e7800eb0189036698fec97002124724580b027abeecf20dc90080a2bb32567e09777b87bc60d240fac2311883b84e2687b2c9300e9a709d9a24f582db0ca6ea67dae8fa0ad5ad1712187a11e8efb0c1f385ef5c897a117710de7e77e18512859c6046f2b4a58dbbe856f6ce35d639bfa538c2d9049c59e04ad33dcb8e495a87bb38aaab4992f6dfc5efb13f00ecb829f40ebdf1ae3d52aa92efe283b42746826d62a9c88baa77c1a01e059d88b41b899bdc771127896ca7e658b12b1b8c40829ff8b7a6ab6a9555a7a07711773afd282a32ad08047d871b73704750f583f882b5144a3fa1e9d91ac54f473c70e6fccd46861a98b721df2c3a53831ffc6d54601ade56ae3d3822a9679098800a7af13282887078451d030d9eb38fc91ecfe35bcd8643917b1d66d5be28bea303137d04ac138280bcd0d8623d7c480908d6bde33263dfc8071f7b87cd39f8bd8602869a5054477d87542b1499e0c487d56a3398839c195abc43a55c278ae594c90a766eb63283c6f1f0b0c5bf7c4ba1b9d4f263062069d088ef3877debaaa7de3561fe2463fae109eacad45a26fa6b74fe19184bfb361fa44cc9ae29fe2a4bbc7d50292b2e21ae12e2de2bbcbc3465c82540cdc20e4a54152a4ad217807197f2ac9d030084eec584229a1f76d8cbeb7be5cec18c206018f0d40837c1893ae3ee424d650f1e367334ec9bf0dbb22dbe8a3eaf61ac5923844659970745e517c79857031547025181e0bf71e569966ad0e5b065c547318e581f22c8a9e0698a7586d1d2d5420afa295cfc24afe34ec4e0f1c84181260f1ffeca482f82279cfb097d644a487d0dce3d80b7d3264a7903c4187db4cb680681086ee323787b3520084cb121ca8efb5ddb7972454f980286d3bc985552e3fbce2ec06d24261a00c80411b15e40483eeb950e051438108dd908c80dd0e9fc6c2dc1f18d9f07568df2fd51074bf4fd22f07d0628ac8ab3850d4c803dfc873eacc853c0f7c65335c4f00e4d13d79cced8aec43d2ab4630e4b3b347ba728b30402ca2983f2c4574a5fa49a57e9a0baa8bc46ef340962542e08e719049f6636939e93312afbf0303938b1333ca941a345ffa537a7d13ca1441ddd4d9f0dffd85e3b261b09fddd6c82320d6f2cbbf29a484e5f071c20b9efeaf76a0aedf867fed1da6d823218968670a225d9afef1ec31e7aa6ddbd095c6a9882348ce9570bda81c788465f04e74087bb6583ad9313e085345c63fba92527cf3d71bde1ccb7b5ece6e1b2a6d0953e8e098d671a4f64543e336178206b9099422431520a9ac00f63746626a11792d61756148895c06a078dfe988b2a14d2f96e6270e89881ea2c25b481f4c48b1d6841e15d5c9766c5106cdafdde7447dfee522be9d819718313449f026d2dc4dc40c916faaab289d921c774e85ea7dbc28d21180c172c064f9923d2d0115a118dc6ab93552212e0f05dd9a540501445721e8fd4fd41dc447be645704f65ba5356188943851c84739ba4d26db4d59539819afa918b18fd674d614c8dfa75812344d5495ad928f50ba89c053a86082c0d414ecf18c8cf2fe567b39d8cd438f1ae2a2a0511905aa12cab31b1bd00799051a3b7796a48dc1c501fdf044ccbcbf98caaa55d7044f4adaba44e9bab458901e428ded6ca215409a9aa33678794aa0dcd7cbe0ebc7fab7a9ecccb0e7ad3a6e89d490d9f7f9bba4a2d617ca1eb6d1c069561a64ce764e8eef6bdccf7de4f60c735bcfa51082f44bb0bdb87cbb86e23831bdf0454270efd0be66faad605d6888d1efb772e861764b3c36edea9711c3af0d04dc385b7b680e2a5f028a957c9341729dd5b826b71e7d31abe53808b81ced989a748cb027f92b810c81d7adf6b13609430aa830ae5331d42754ddb8abf53c6a88ec4dbbc51b10c05870768c91069cc3676ab4d21c542facf204a849ed831615ee164d8967604916515b75ad4cfd7fdb831101d41a3f7d61143f8a1e2d73e3beb722cabaed4bb5ed97453156443c9f31f50e0432aa49b54fad215c34aca70d46cdd062f9b95eeb0ecc78c5a8ef1437866f2e968c3f5db238a81c050dc0c679b231750b6697216acf4e65d33c10c4fc316a4b11012ff1578c54f03b6a2bc8fd2312d8782e6a7d3009392289eb9fec04830dd52b3ce7ef407ad37f49f6c9813e2e4777961f653e476fa650f358cd01e436fa788c0f9370c36c0e677d19f43830f0c1c78b339da443aa4797686594a1a657f6e35cc75f551543f95e6528c8e75aa18ef80ad562666e364a030cdf82d272bae8d8a78a63561a70a4f67dadc3bce7097db4f6f9419e9f82cfeaa44ffc5990ccc3c1f4c5390f3e4ee8d961c0d8e781afd57c7e894608c733a3392b2df40181a0e66273deba0d962eb87dba75195cd647d32e5d8df1de721ad766cca79c1e514e1fb51cc689b6f8ea811f3c41eeb60b5685d8c67c545c8d4a4d63f04d3997d36024df4a200b17930cc3be6bfa5349768fe6a44e4c956aec1310b8c79e2a62265051089510f2ba5466df1252e3d29c4cefe875025a0dc73c3ae11e5dda46957a1f01554c04c48de29c18eed3b602aa937af486a7a43ae1da6b919a165a30455fd643f8888b556b759264d70322082c32927ba2b87f85bd221426d30dc6b15f0c341c4196195658a333ac5c5980c72468b9101f6156a59226280472c5640a53b5fb568420e88e1985ad93e70d63b84036876c2bc98c3820ab16fc214f66f82c4e4d38014bce6c726422096a2554d5ea2e0a9a48d66b0208ac41c0e0faa3dd55f37ed022f65c2bb953e672f0809f3885c034e9a8f478896970423645c226472661f078a2aed75f00cc4e2fad1162746d220605a95eb3ecce0cfbef5453266e34460c8c297298d82abeb1ccad8726ee097dd5d1c8d498d7d2780d6df64899e342f14cea831cf4d7adfe57c946abbe0cf6beb317c176f4a373c612356821a9588a21fa2467ec0d140fb3c05de2a418978d004cf180c4de05f9631bdd561edf01043e374bde20acf38a7568c20b94383f6fd055d1cccd251c1f40f19b2d6d9bb50c2d2a6a6f4135d0a67bc2c9ee7ac15a052084d6dd5286f3e2ed7008c2d97053d86897a8164efc175361a5de81ce48228b9aeaec7844f1f098fc2e684578ce0e44174f58409c0b801e6a037667244a59c3cbfc8539dff1a27369663ef7a6e5e9450ad6ffcc356bf502365b01b0dafec6e4b7e2e9fd538b04ed6614ed1cb3f6dea86c20a41cc23c0748eef9af7c420620ccde82e429e091a328f539875274160e0667a105542f23813b504cc761f036bb0048728223c34b85123d7ce6ace31880b0e1b69e4f093a95503ef70373f085a3bcece7772a3d8e726050245fe19a3fe0e4c3710b0b0ee10330243b2e013d31c4f60d379e45c347c98faf2124a2b030d35881040bdb8cc8641890cca51910e1813399c2ff9a03efc25331eab88d83fc676867d496d5a8ad73170f80803e40f34ec7ad900d57305744f8ee679107fedad6d056e46eccd6f7995d66ec99a924f10e8757609e5a0aaf449953c225c07405c7e3ce6b8e01c41bc9dfd3152442378b6e1d128b064b3ffd1a1614b95a3ac4d53934e5fb7a93e750fc50bd78411367eeade14718612a582718d335e5ddc78f940081b826596b3dfb3a424f4817b44de80582c0b544ee101ddf9ae9d2c78be9f23178b04370d62aa15caa7a3000a24b5f3dd6735c51cd0ed03df33e391274593155f44a8155f68ab21de62063cdcb6a0483e6cb4f948f7afac3b39e279e0437cfae008fd2bce69379f006032d48b49bfa2b9104594b2b3bb0fa020952ec82900e7c791480f5357fc34679464b4391ac0115e05ba1768250611c16970336bd206d4be5fd9aad7f1264640efe4191e0042e4c947af12433c4a7ebe16bf899e2c629dd26c2b30a39ee99d0210fd33b96c7693c5804cc8b934a94e848c1beca4f32a1d7c988f5348c4246f1d039c49964244e1fff38141d3557199fb253a2111855faf437ae013fb983f4d75354bd721e6f020ccf2afef0e3a97467361fd0fa4308e94e6df07c7496818ce0c31a2c6777fc32ed012d9eeeb435ecc877d7640102b9259d6932c6e9468bc69d50ca1550b1c9135d7c628f6c4b468396bd7b94738039d331dd391b3895a44244ce967a4add5042401b3aecd8218aa23766087ec7bb4af3a14ffbdb8376eca40e95fb77f3971e3bae4e387080dea0d731dbcee095b55e72e3828ce085df5b9f93c9708ec850c551ca1bfcddccc5a9cec7974d66579c6192800b6b2ceb353ab3b76315230e187461d30ce0e0e05d6ef2ccdac58b971e0001f0eb23cb78d85dabedde21a8cef41d5881def8bfab36347b5dc6ec724eeafbbf978b7abb7eb61bc1cf1b2d4b04d9596cf9111ea4199412d6494ade48de3086b5bafd4abd8f23d2b8c4695df2106fd582425ad5c7c8b10ff6c98357dcaca9144e1df0f211955aa49375dc626c3b722bd8d745d88b1de278941ee7e8c38d355f452d2129cd00ac607c0671dbf7ff7bd473e1332b7ad84c53f2deee9b3948e3792f1feb08111d8f72e744cd6c9bcf03e9a769a4c303213a1beafdc66c27a749702aab8575a644aad71d09c671166505addc5c42a4779e61bd8eea4913abb46a0624d58072407c1d27d88fcb28297d0b1dab744fac71e5eeb4df3acdb5ccab15db3054d8295122ca4419473134d2483b7db09c1309d8d8dd412592206fa23b71c42875304a7f59cb44251c53367a2d575a818c13e3a14689ab56a785d2229807294d8e447fceb5f075f34bd78180acd48089dd061fbd84990f0b291665d8ee1d7499035799a1a3a03bd5da4ff23bea40cfaa9b08daa184968da92963251bfdaebea13eed885e127b02ae48e21bc8c830c968b0818d10dc617e785fd454692455b4bc976a820784aea0c9a3f1eebd49a1d2568ee4187c49793dbba165dc5c2554335306fe2a5491507cc6038dc45ea037f103ab1a8d3d80b4f5090d5ccf55e5812475132a90e7c640bd3f26e45ab2666be38e3178133090b80579ec77d7288622e2470b1fecab8809a2b50db7a28cd79544f0f8d1e4f519d98f66b45445a05bfaa8ec6d7ab5df7d26deede736fe218e88d400ba117cf69855ea1be52f5633ecfaad1975c007ad88eba8648d290e781b75c80e5fb82ebea3d29adfb3baff97c844ce928c70d9c05e1a49513f50f18212035ea128c8e8893e54043aed4ab72219c9cbde17f563e009553eef1afbc673ab3c31063717c5358a9d74361c4de0d9286fc804138a8374a21c057d22ad1a94bbbd9b148efb0115ab8432a294e41668c415b984704b68c5aa585a760b74d2aa2829ba6534b14a2a15ee62a19ff4e3205e68bb5bd9bd4852f378d41192b9d206fb99cd2817f41e9954dbd21d48bedeb5b26d422ad180f3fd24b60dc8779c315518c4d0213a4dd6665a05c4e1f755ce1dc747fc5ee2c87ca146b12b104f5c473d7d2f6e55553fafc276846c092bcbb24a2e368a859989f268fa3c8a8c60ae76f6d3a37ca2d9b14982ea70ca121a30596a510143baa35427edb6d60f1dbd518b5a764c8610946d19fbf8afb62c8d669420d79bfd4e8309e790cdf46420f18c14c181bebb5b87bf225892f6c4ffcd88442057230fbf25a6cf48cd7b2256e4b8f9798d078b91149aba8edb290f99936c5743103bb7730d9cdb8ee63e192fa143c68ad9614041a82ff7fac63470264cb35531dec96b07498c3bc16d53e6b4e409c5a56baa4f5061c06d935e18526a45f0ed9e924824edd1b5e6a595549ec3b01418d1909cec184084e6dfdcdf4abd05790fbc099193a3e1a0f199affa652802a26ab4886c8fda9bfa1c11e0d3f3b43b1dc89b9cc94ec963c4fe78b1efe2c86c18b8aea56a8c3a2cf4d5d501d7c774dda59bf19a80e5958011110df98a51088905cb514fa3d97e39db052bf0238a9a23ca50f90ac000a0bd9b01938c7a1a0a6f56d8a5391904d4843f82d3e7c6f24c28261cadcb3346b1817280c30171f32241e01a04eda3830f924d122421ec2192d20968f6de42fa7139fb81c5adcc6572cd9f0f60efdbe2e6ebbddc11b6b8977401a46ac06a48086bd5a317dc50e50c2c82960b60900b2052b44972ce5e558c6c015c8fdfbd3dce04856390899f4a4a303462c18b3d11f253927ce4b096f18a28c79bfed7a966ba320fd684f4ab800dac06f371edcd625ff5ece7aa3f05a0dfd995e7325d9941351297c8a804f466dc8add36b1c1df4b2dd38c11e883c506dda02e75fc54ba3dad5d97da4b3544ffb3323161ecdd51af3d19f3016be372644ed7ee6376d8af751b5c5518fdcc0c2b2a0029e1991e5b87701cd0519287585c20712d1fbcb052506a36c061834ede64e228e2430de9012ea70801eda59d191ded38006381144e98cc47ea51a70a11dda385698a965c1521a7c43aca09d86452c7cb14134146d672f50424da030b2e1694c2e5ab35ba088e591e1df194d2b526ab743112c1c31ed0d1e7f3c622642bf73159959c3a5f27d1125a4a476b4b192ae735ade3ac8d73d111ba95e132eb889c1e9c3bc706b2e389cb310743e55a46b5fd7b216c9a38e0fd4dc4ec05ceecfc92b97ed8b6e416a3413f485cfc6796d8a5befdd7b9a9031fe2b6ad06b73ae5d9801ef533dbf7f9f387881818a11235c611ba4c43bcb4afdbf9f631331768dba9e364a1ed31dfd6099e09006ecc2ff3fdf48cf07c1d2d666d33e146fdb9f799372cb430eba0f174c04d18a40b0b1bd7f3cd9cb8ab322120ec5b708bd1b070407c8360c2aa3aa03e53e69c39de422bb1d6c2168e3676f08789e2904314c7c9bacc62dbea9fb2813bfd192c520e4bae8315b245385a0d6e1340e478a73c2b02f72d16081b2b2d3b4b78ae5850b9bd6da728630173ccb5d56861067c10cd8b3e4bb9e5296546c0bbf64bc48a45169dc58cd94e40b43aeea26754cc19955b51b9ed43f8d583046bf580030208bdefba4b2ac48760b64ae47e3f405a3156722db58dadbde02ad78f73e48dd7783c55bcaa5ae2a4af0b2e8fae333df1a83256adcc2269b4a7909434fd0bea7c1c4f14c81e96a408376b081e484af0c05648cccc98887317940bee0cbdc3bbc8a090083e37170de6038c118829f91ae9018a1f8895e3d36ad4432806d8e526cc3132d59760b13921ab49b73d4d41de89199d2fc8cda8c57ceeeb5fdcfcbb8418939392108c1ede87275fe910056a7f2920e80f71bbf6e86985250bf7684e753944e0a4307a2871867b1e1584882dd2da20df820f579054188bbe66db57b3b69d91f68dc321406ab27c6e0a1b3cb3269d1258399f73673ff45d4338064bea03a307f763147487dbad7b9d5cac3fdc3ba7fa877738613f418f9b633dea744c4d807f5b7f25e09a31e84d687292fd6e5ced23a92f5cbcd8c4e98cad4121a939d3a0a7b6db860659cb0832c3024acd071c7883cf60e36b1461dd0f8ef473fa3fb330c7d2038e8ce0804656c30a9969ea840b98322d74d6f146fe22411c9e61ca079e0498fb8c868713c15e329c1b48f4cca62149177d10038ed444d80d3c10b8dba403fcffffffffffffff31c2f0a325441b914694089229c94c910a55fdca1aff541f151f7fb2b5424a29a594522623cd5cd11020d6d62cd901b80f3b0d3d0dac4fb6e5ba5a07981dac940c9392ef56f25daa8911e443653e193976b4673420d6f07810e833981f6074a0d6be92721d4a95ee9826c695151f3e6c0851c9f19bcf901863ccb480548c6072b09833d6b4aba06a0caec613ead818c2e2f9f490df222446150c0e303858ec9915cbc98be5ea1e82b9817727a9f239e5da69490d17396ce0d8a2e56508286306c606dedbd8d7c27e724ef89aff649ed33cc4089311a311fec448024c0d927b8ab97be8abad26c3d0a0b5cda7e07ab2a5d7e61699417be67e95d47ba76fba11194cc9ecbb9d327dea2d05c5c0ed43eec96aa5760bca356090d8c2d55ecf7dd204d9650d86dfee39f84da92965d3c4c8e16c8aacf102b8e6763ff95ea1bb4ca197f74d31f866c3f578a9f939a25e53ded3c92477264f20234ae75b4ede53a143f5d44829b57a2fd36ca552264d8c20179eea5fcdfe9dae49c83431ba84dceaf69c62cc35976c5f13e30704e554523e3307254baf34316e3efe7e5bf9a7af7a8e5f13a30b1ceeba73dcd263c59cd4c4d8c22c3d6caa4df5a4bccfe281efedf54a3f5f97853c9e0eefdce476c1574f72b2b07c96dab3b4ba1a2ed3c44884b312eb72c7667bcbdd9e481165d5dcfcb4cbcb3bf4a01640f8da9baad7e76ab2d7c4e8fc9f1863ccfca6d3bfa45ccab42f4da51a5fff3a3de6e79e092e915d722d55cfdf594a6b4df5a5d69249cd7dce09aebc7b3f29f7ff39a9abcddf9cce3da5d39d4b8e3d964ce7392f2d1e19e3ca0a86a420887ca9bdd79eb9e78fa5d43431aee69279d0875bb6dfddfcf692f2949ec1d5c41863e885386ee9ded7a77dba1832f99c169721308dd97a7972a85e82f2fb33db2e695b7dbcd69c8fb100ba4eed1c36d953cd879a152cd5bc7ed35b70b57aadb9a10255ffd2abaa5a870f7a0a58976a123a94d0a5b65813a3737e33631412512055a74387f2bd8570361cce63c428e404ac094ae77fdbd0506eb05fbea552b7e77e86624f4dc956932e9f6af086196cc2c91e9b0eaed48d411f65789b6ff6ea53bc1abb152387f392c790f5abddb6f56bdfed4e17221f1c2a3b84c0c4aac1b7efdc75b553321cc2a4567fb186cf5dd3c4f84cb0df4faab66d6a4ec53ee3c5189ef6a7543753fb6a6fe21023b11bb0fddbda995263b82eff051b101197fe3082bcdf9676aed666e3b9aec9803631422049e74bdaccf536f5ed9a18637c96d7b4f087488c5f84c1deeec1e66e2d93ce4d258131e7949d1c6cca6a3147c4a57fe588ff5079221d2623c6129480f55add382597963e093ba0927ea4c51c4aa872f779a6f5a11a6c351564edda9b8d2f5c21f35765e9526de7399923ef9923ef9d11f478c5a694f2a55baaadd99a1875f0f05f95eb27b7d9effd343172f843e4b9a507dbb1b8b9f2f4d43ef90e932646df64bee52514e3ca4b07478c2f1d1ea2b23a52e25fbae073a56d2ea689716565e5b9a87c3ef44345478cfe9b96cf875ad839c6cf87361d5079c99c964c679369f17c3cc64fc893c33b1b231d974c0270a85773bdd9ae977c5d4b13e36a2e9910cb0c01099c3384d0b129df74cf5ae3c970382c637cd911a3d323c618412d1e3882a59e9874afb1a4d8d99cd393096d382d201c2badb85d33b66e176b565d78c19e64eb7e21b335d96a9a95a45c5e98d302daece0b4b06c54626c61d9c4c8e2d209a2f26652cc5a7f7b9c9ef2185f0d0fcb8a081ebfb7bd58334d6caad2c44fac1072fa9e9b56394d8c1fd648114076b8ab992fe51e73dd9a183f215066e58c943352422e2c1d50894f3a53eef7583684b3a126c6cce786639b5482aee93bb76c5b1363a6350675e963da4dfa92f035317e68f331a201b6ffd694ecebb5575d6a628c31c43263e4c082fef8d919fa27c68c3531fe7f260f055bbe67df991cbae4cf1223686642208f26f3317e915c136339b927afb5463c1f223736f53f5ccbd635afd49e2646ef7026e3f118635cc16163888a7c338c30194194572f86ed8a79fa6ca68991486753848b10b066ece9ddba6cef746962ccc4b86eb0783c01e842d364be5029b8144ac63431c6a86cf493dda494dc9e9f7cae89f1f31d102c56357f4ee7ef94a5d4c408f27f50c6ffc86666424f24c69514100b212346168f77f813a306c41a56017d80c5e3c910f9643201e0220372f9643212d8c2031e88400738f0810d48400316c840043090b2c50532608109548002149840062430432e1588c091d7643212b461a10004581eb099ffccccc713620a3860b50a34e0a5cd1cf11809598001443a1b0d8835290bf0800252029c16198d0c716710a08103283580070a10f27808b0c5006c0880880702f001002445e1e2e40226473e02259b4921c1848efc07221457986082149867e18e8909265ac10004741181362d5c002e0001223bb0810c38222eb6f0400738b0010d6400032917a800052620810840e0010e68000316a08004445a3c2025d2220894e802090d0810d9410d64c0114551f48128c2bc02f4b9f1f209753e042dccc2c3097488a2e83b9e2069a4a4113da1141b29d146ca74020c9c1072821929469a208b288a52a247632425c626d8a1095948e3f3e191464a87533a9e9434b8d8a2853f463a2e31a601d2845ade534273e32911f4b9f12126b251833b92090c6002880951282362d0e746184be04411c6074900a208f34544a413e22fc2a10c0783c1f0f8783e9f288acce0c98440cc017d6ebcb8b412d010b1c6484af44f097988803e373e1fe26ca6121aa0851230ef1ec9ffe9b8a4f8c74c442786400217a2774fe7640231e8a8c0868d152f52b838e29b2d42f3c388647cc408cd0f23252525a5a38235528ef826f344fc3345247fdad0031e9824c2c8774caa80041cbc94c08b95f99c8c733c273fbc5001414ae739998c733c5fa204942c84409ee2851729f263b285179ab2f20235a24de9c28b14cd8d27e2ffff0935c98608a838c1901f3a708c8143478a4aca11df04a0a4c5c40c9331809884a1c3849944208ac4e8fcf8908ea4468c2cf2480e278345a2e19d32a2088369e1cf101e1ecf10d07f0f229d4d103234d20588c733c4f3e99411fa785a76fc0b36428e301090ffcb233c9ce3f1f19ce690274814617a788678c7c5d323e409c2399ed39b1f214f100ec7a5c727d429c3bf53c67b826078ec2083c37109d229c33fb461d9841145911930f1f32097cfb7b808e910d9fce7d5f00809c222d18822cc4a4a47db1c5184c1b15ef8f3c1e1dfd9ccf74e19ede1e488224c23c108a295ffc88e474714619cc4f19cde10e9b8f4e8788278d17199518451d94c31382288224cfcd0a6b399bf238a30d0399b33b8d802f4b991518c247ec08328c258c0059b176c40cfb2f1b0a484d8c8773a2c8257c393027a11805a9012a48b147f0ee78da4f0e43c288d28c23c353621e68036443e0c0ecb4d47237f088fd0a65306873772e32e250881f8c308e1e04f8f50e79be581bcdc78cc60f174de593c1d4f8be73346873543fee3011245911930ce9f8583bc7470300b835cc070ce46a3e385d311238a30eee5c1c0b42fa2288ac5cb0e87409d1fa1e770d8cb17d1f4f26060563bf2dec12cf5f118097d27298fa2c80c9814fa704b1461f625b4e1f0c78533461461d484c523e43b9e20abb9e41012448c1f43740429a3041934700049e91049f1745232a0cf8d102c46013b6044146142104551006e44118b0b28e531281fcfe6f3a158b484e1d068683034161a0a8d84c6a2f19ff71145982e1e1aa0cf8d900b4bfb6f3e21941c390c200403443be8800e74e0052b38a1887b4a10819103154451b42608c2091754524ad65831f21d7763bb90af0687c32c208c4651e4c5242211456588410220390045a48407ac20d2e2069a288a8220e1080928c24a9128da18204a238a7c3ca77bd351400a222d6c008128fa7ca7b34911414ae1404ae7399ae20506523acf1962c4a3a30504071a582202b126c4633c0b778874e49b01dab4e0006d5a98d3c2b2017d6e24e5e2348001e8379fd08a8a7c3332a01feee94411093e1fda9cc81978144504f80426eac1ff09817ef3090189a22fa228ca445ac80006511463047d6e705a5836197743bb90afc60b7f3eec81288ad088b4880124223b10e96c3e1feafc1e0a41064c1a305788426488960f818a480f27a5b3f9ce7f9cb3d1c816cf90d8f981430a1820d18d972fc221d2d9d810800004208001e448b9117ad04be8b3f10fe3f816313c415e7103b4e1cf8e2b34e14121f0d7811a1e16010ca0e3f1805a5a3c1f0f81f83929214e7949e9e0c0810315445184880078668dce26251e31c4914d4451c48af062124535a0010cd688a2a8232d8c8022c421d016bc5386e7f32878c9d1f16c401b35363b3aff02cfa7870e1617964d6703c48887f3397eb3c3392e9e3340de71e9e109d2f9229e2163788210e96c3a1b6679323ecfe2c271710f9030429e8e2624060e06b9e4c1c3391d239e4e914e19a11697221e0f07d47149e93017463c9c971de6706f9102fa9f2fdc12da7036cd9d1fff7109b94c508a73a7843e9b4ee9704ae7464a87f99b39386e80fe8559441045181b63c07c60e5b9c448a4b3097d3c8d23c58535473ee5e5e3617996144c1491e185e3ef1ed9f994ff803e375e3a0302710b17a228d2445a7cf01045180b843adcd9b06c3e12b4f1141697cea7f88605c446401e1f2481007d4a1a41d248f93f636fa81ba90bf9ee915dbc84361f6ef187cb58fa8018e4f23da19697cf0a925a6d05ac715e8de770588d4c6c0171389bfefc18a0cce75b62949bd0b368429b0f675a4062e888228c169ccf8787f4703838381cd6e1df21b21102daecf0ccce8f28c2200063000c02a208738028c21800d31b2f3ca5b8c4113c114511e6079fb800179f13952f44514412068f1164e2071ef8c12aa2282a69c01008218a2530010e8688a2e8c409496005061151162488a208838954140106b058c2255c1445254f4803004dd0fca1059388a2a80502182d5ab408416404086788220ee8c361e95137f6c676c161e7f74007f41e27830d1d09a0a183830c9d8e2221f4a0b34614451088a2688b48035b78c009222d3a8288a2480ba0cf0dff10e83b99cf87361916cf67868e7c08e4abc1388c4387288a3c9f7f41ca4ba7bc6fd4d8384778d08208694411a600041800460042425f446e422c1be6e838b2c1117a213e5e8810efb8cc004451c4a0fff9e292834867e31c8f8f1f9f576343e4080f00648e30cbc7d382b2a3b321b2f988f1e1e7e8f87842443a1b9087a323d4f94dcb46fec73fd4f252e288cc1002bd8b0b9e8cceb788a1c3c8076961f9f88822cc09876508e461c984388331c194b0c82321d07b144569bc7c782337f33bdfa0d08340fcf9798459a20843f289220cc6379997cfbbb8e0411d4f0be8c978f9bc8b09fc431f4fcb737ec88e28c244a107817018e18f6b429b337af391a0760175cae0705e039a451131a22892c5e7c3238aa23462018b57b882155114ad228a22554451948a534451648a288a4a114511294411455128a228024514459f88a2c813511475228a224e4451b489288a3411455126a228c28425a228aa4414459488a26812511449228aa24844510489288a1e11459123a2286a4414458c88a26811511429228aa24468818334026efedc77ac5f82d086cae79ddf07860924a730c5fa395dbd5aadad96a0d4c448520a5e49dbb6f6f518645e4d8c3e484851009251f09acb7a29e7c4d4aff21dcf69178f3b8928946cea69dd74fcda96f2ce060c151c24a170eafedb10f2baa9dba0f8442b5e572bb54dab1aff16483cb1d059377ffdef4bbb13aaa4f27b4d7ba772f84f20e1044ff6d5966bf02d4ebb4e20d9c47aea74cd36374d7ead9a98ab92ba337d6bb29d539264e253534db197beffea1a09269ad3746ec9a632a5105ee2adc6de5367abccf15b9a33482ce1fc13544d3a645d70b94a4c5f95b01faa09bf156a280193ea5f4db9a50b5f5d13e34ae82731596be61e7c505f4bce3531c6184f402289f6f261d29fd33531ea2089c4b2b6e07a6ae9737e5d99ce6b4219202490589241989e2ed6a47e530bc923f6db6c2e156c56b6ce9ac692c7c8902fc29c1c2a322071847cdf6ffff9fb544d2a22248d60497a3f4f73364c5be43f0c95cd6748182a2a2720618464e8d6b3d4ba5f53872b61a890806411ce5ba64eaab7a77afa2fd2e9902882674bcfeea04be76b08074812b1eb98a5b9af528e1d2a3976f84b6e11f2f260a80c214104b7a4166c0dc2f99ab56796e4103c934bec7cb29373e1d3a480c4100fc2d4fddc6bcafd5ebe48c6ff478c2b24859012aedea4785d7aaf5713998410ee9653c7acde6a6bbb577ca8bc3c181a10fbc03c8164100a366fce4cb1e4d6254722886d8fddfb5beae05c2b69620cb9b06476401208f80fead3fde6da54d69a0c8841386e400208365d4ad9206cd8da946e06247fe8956dfdcdf65ec1574c08891f74d57bd225a7af6d9b521323cbcb80a40fabd53fd8ed3c2dc93c8d80840f53659373b2a40b57f3d5ece15d6bc6a67aaed664ed80d81862a30718367ca8e4d80144850c123db09d70ea2fc66f3d768d01491e946bfa93c1870adde7e3f087c70b48f0e0a4b756f8bd9a9f39be83affa5de57a32a73c5d1348ecd0e46ca8baa527999ceeeba0187bf0594fde6fe94e13e3cb27d4e111eab06433c820a1c3ec56d0f9ec65af10c22f48e6e01e7b4d25985a73d05d9283e4f9a473cca52bebc548e2f0bb5cbb97987ada6c190e3d77b97bb7f7dc0caaa6b3217943cf778f1793ef0e195c6e50f7aaa1ff53ccba5cdb007bc9670bddddb7dbec61a30c1b3f545a184888393d62ec7c28c49ca9f22161c32ab9b83d572cf52e630d1a2f0292352cf85e9d4fd8acde3fa118fd55583c9f1e2f9f21d143a2864d03091ae0d2d5cd293bf766bb75869d6fd5eab9da92ddee9a1849ccc072a9b5d85a4f5df34d246558eef7584339d372eb960c29ad4dceaaff41e88bc720135bde6bdb7a6e9f849a2511834ae62b216b6fceb92d6962840149181abe526a2e9b2939b81c0918b4274c8b25ab6dd79e6a62d441f2050697b25debabe0927079619d84ab5677f3d589bb074917b43df7e6adae909b4a122e24b6ef3bf1ae36db7b690b53a9fbfa6eaeaf49b12f86a8bc0b87d520d102eff62ec6eaced9b50c755e8d5f610149165eab5287ea3e35960eb1a08db9874f49e8cb25c5245778beaf7c59314faaadb3022f57fba64e7d6e77b526c60ca7b953468c1c0eeb60024915d8d2e4ab49f8d85a9fed1d974742852617dba9703595a4eed4c44832857e4f9b5cfc2d2df95e3531663a653cc6062452e8e51a32bf73bfa22346154c1348a2c0ae5e37ed7db9ea0d6a627c8e6f321d0fc77f74c4881154c4e3d1a48038850b1bca630b154902855f7335d5d6bbf9d292eb096f77d97fad752ced2b151f244e687eec2d37596312aaf5b409fe7c9983ca1f4ed654a93241613776d630b1e6d6722f4896d0dd7ed373fa4d719a50098c75927071823ba7f4e6628b1e2449d0d5d26d6a2a95154324b8e4d48d96ae35ed5e90e911dc99d5dbb573934a698de0503ae726177a6bc9a916c1a95b373ab1563967b3a7d2adac20052c202142532b79a996d27bdcd21cc24b50c9265d32a8ce0c85909a5b377afacae78eb9996482b3e3d9fc8831a5802408d03f2dc74e3205753910d872ebc6aad4ef6dba7d92e1531689c60fe062385d652f9b904de683b51ad46e6e397debb90a8b4423c69d243d788dd3ece50bbe6ea84be5f3fe1123c6334878a0ccd7fc552fd70e9c7be9c60a21d181ec9654aa255f39756ce6003226bff12eb94d3ea84870c0f82d73a9cd65723566243748b3f75df2c95e17b644620387db0c55fe844db59c243550d9f259bda99fcf956b0d4868b0d8aa1b102ec3a5899d7bf13e0d1a9859bcf6dc7b6ecedf5bef4a13e34a46816064017f366bd59cb3d92f5bd5079858a86c269dce7e6eb9f283059c70ddc3e4782df93ebd42beba6d726e820c4ad6342b2d9ecf8e185b3c1ff781718583fc8a2df86e539a2cb562aaa4d6b1e3245d3ab533c0b042b66e6fb6d9da29c8bc470e30ab78add8ec36d936f892b9a454d1bea162e6977aa5648cc1012615abdae467de8fa9d7d8d3c4b8528218836050f1de9a9a9e6a6aea29753b1e738a7706df33a85c7b70faaf668a7749c17f4bcea55c5a0eb1dc705a5cfc3dae0930a5604eec3f4128576aaf15299acb4d4aea92aa0ae76a62ec3c27235f8d8ce3c08c42bfe5749ae052cbe95b93e1705c7e7cc498fc619861030c1b211716961ff3c9980446144cf53198da3fe7143bc6c516a1686bae6e4a155bcfe04a6d41c1546763cb67f3ae55fc5c84603ee1a673d58a5ffd5c0927c7e3e932309ef06d6ff8ebbabbadfbe785bcf0191e2343621401a613bdb4fb417fc79292e9710226973c715adadc796a9b78523ae9af35cf953a77e5c7e78b7c982583e9014613ebda9363a952d2f53e9e964c0bb3ecc064a23599feb9eaf64afae73f64c448020c261e365c6b7152a5dacad6ac7cc7c3d111e3773c1c89c3460fcc25263f099553eff1eaf96ea5c70a0e9516602cb15eef6abb9cc276df26104c2564e2d59abbb4767bed91efc4b812e3182aa10da745c827c4020c25d6ae76525f92ceb5b927d1a46c73ce55d7ef498792785e5df532bd67b9988b44af365d3dc98da94ad5209160aba41ef3c7fa945c8f9070addb67ad92c1d6c9118a49c77465729adcf220292218928233308d6877df744e3667af299711ae4d1b32d656ce26153bf23e3e6fc41386c22c623f2565e98f2db6560301a388d7ef0caa36f76cb29289f8b750fd924e2af3d632473c46423d308898cb97f267ac4a3d7b4b13638c190ee78dc4b86a940073085fd6da995abcafe1274378b7c2f7f857399842b0a770d35be8925b8d6d0f308450ad20f4b66d59277f3b043388e494cdf5566a5ead1a042388f9a0ae55e993e4d5328d81094452aaadc365f3d7b16517ce6c1840a4a5f6bbbf9bd2b6d2d22ccc1f9aa5d7aabc4d06d7748cd34cc413c61321e209a3c5132446221e8ecac3f8c1c9349d5aefef17bbd9402a8ce9034c33a99c50353ff5dc0361f8a070e57a5ee709d56ad6983df084dfbf53579b53613b82d1837b0fb663eb395feeb679f84fac14eb62ea57555f3078586bdff26b756c7973abc1dc61eeb37fe57dcc566a0c038c1dda659a8cc9b69e4c4d360e3075505dbdd09f5cec4bc13f82a103e4b4fe947bd5a54931508c433073988e597bbfc9d66373ad1f122307c66037a5d69b9fbe4e0c0d307150ebe05a4caa35b9f9aac6317048fee0735d8da5d7da6cabb9bce17193eae782ac6afd6bcfecfc8801c60d0abe061fb3f35d925f9301a60dce256475c6967f39c79a18635cc1d11836305fc89f9abfdab76f0d0dd99c6c7d5a4d552f03bdf01820178c1a563b359743ff6d658fcd505901260d69a55a757638536b4dd190e4620ace34db35745ddff232e425e48239034fc7ad4da9da33fc5566780ba75b0adbc2d6b4189031d6aa11e3b3f067627a8029c3bb05a5e46e53beb4a1cc0a86a440c507860c8ba72e4cd0ede495528de15fb6c6186cb8ba1faa1876b9b7a6b6ecf952590a4373303d86adfff5aa7a302c0593d356fde4932c4d4d8c3188c17f5c401e8e5c638d18df5d38ff69f9826aec1aaaee9d3df79917d8e1afe76dedb1bba69a1855305d589b18b25ce5f39d6a6b860d3054629401860b93d7af67493687ddbf31c06ca1d59f3a27d5594e55416cf8501902460b4efe27c6bee7eefcc71ce21d58c06441616307ffa17afdd2312460b000df54ecaa57b9941e5ea1f164961aefbe5cc97a458509182bf4337399da648ebde75a157c5535a5aced6253bed7c4d861ce188ba182f29baad327e6d3212f9522982974626ecdd27f4367ca7560a4007b395cb33df89f74362460a2d02afd642fd9540e997250706e55ef544f49f8e44bff7103cc13d253eddabb833331a70aa3038c13a4ebc6143eb9cc7a629a00155b9e16fe339652934a0b304c689341f92ca1bea95cd9fc1d32c697900ecc12761bff73ca9ae3d77f221825a44ddd64ef4aaad5d24d8252134a574cbe7333b937468c9a10b7c4f8124a182424a74fdd83caa5a9ecb50c260f9823b42a26f51f4b4ffa4eae34967c805c30464872b1aa5b275daaf9ba084cb683afcaaadeba6c0886086ce9b3dff6bed6ed94426c9861030c951606d2c22c0f3304a6fb9c74af4c39e9fc3b3186382424468911826a4ddebc98933ff5d6c4f8031384768d575a734dc6d653100304d59a64c92974f556aed5c4e899185778645e421b34544a80f981fb7fa74af9ea26e7835f3cd753d55c33bfd21589e9c1940a197b93955d3b734d8c1fe3bb27488c31b6430c0f9eeae41fa3706d6e36de24fb41d95014abca57a765b8547aed11e96c5e769884a2997aff5663a7f22907353730018554fac9b909173b255d73d8c0a1126367c31af989a594748b994dc836ada562e28996939932e58b5bab529a18bdf342dca413ad2f3166cd4d31b99e3e1e8decf07f4860c2095fb87c996bdced716f42dd4b703275de1a4ef934e1cd89a5ece61c5c5e9f89f565bcfc6ea5836c35cd0e134cf074ed958b69f76f9a2697604d1b3bc97c26dfb4890c134b3c377536c554cbfef4d6874925166cf046ebbe56b79cdbc5a94d28e1d4ff4afd6f5b7bee5de885984c82d784cd96a5934a39bdc63f62ec309104b7066792adcd0d134c414c22d18a7b7b7d1bf2fbdc1d269070db9274c57cc1f61a04f2c2e4116f3194ae5bfb3793825313e3e2c0c411aeee3d25fb3de9d41f6a6274c1c7b8e2021e63c4d8c222cd306984db6d50a6d69fca4d4d8c78acb1b5d3bd97adcdd44c16d16ebe967edfae4ede07c4441153c9de4ed0fd2ec90f13f1e07b72364e69dd7cdd10f1de3b7775cd3915746ec8172687504b39dff932a94a6d394d8c1b151689c60f134398148235e7aad84d351532bf092156314eaff4f53567980cc27127b99a2575424c04c1dcf4799a6afe6afe4e029340385bfe891b4b8672bb57fbc204103fe19ccae7cfd4d6faf4875d2a29d6ce3d6650be663e9e8c11fe64424fc4c40f909d39a926956acb96a7a50c933ee84b093aa74e13ea6bcb62c207d5c6cd15af74a8dab63db8c4bcca2fa792a97dd3037bfd5e50b69f6c425e267950edd58dd95be7fc70e2e139b6aa29d91672e375877f3029d9eede3f9bbe1d649372fd5cce6cb99eb20eda782a832f973e7edb74e0b49662dbce3b95399c03b74badf9a6c75a72e7e4e0f6b525e59cf0675a6dc5a1b1fa4ebc9cf436a12738bc77f219db769792e27d83636be206985882ccf5b76b43394ddaf0ba1bd46736e1d2c9920d0bc2e9f337bd9a6c2a9335b07bd7d45a4f767bad654cd4f0cdb972aaedebb676c234b0326f9d1273c552da4783fe73f6e7269b26462e6cf88f2d9c6072863567eac76a49d58a1d3483eaa514ff928be77cee32aca7ec7659754f4f4f01c1840c9297522d59b9b97a6ebec9189aa92735534bdb94746b2286a7cf165407dfdc9e92352ea08c4918ba17fc05a1db872bbdff610286b9af3d3fabedc4edde13ca68402e2d61987c81a9e6b3b596be4db51233f1027c0d654a4db125e55ced9dcdcb0eabe11ce38a8e229243423e1913987441dd635e6c1533f692ad26c6344cb8a0eb2de7b72e4939d96f614275e7af935b139caf89310c132df85ba9f17c2fb9a6724d8d49161cd3d91e6b6d39ec87c9040b0e3e4c69f12bd654a7da5859b1b1f25cb6b0b1f25c3e3b62617205d798fe4ac92a31365f32b102930ebeb576e7bf572a995461d7ced5a654f66a99950a4dfe54af7ed52b7f4bfd309902abe9529b49269602943f1b74fd268490d9d2ac7c3c217e814914be616396e073dfeff44ca0a05c21cb965e3f053bb9ce863f9e3179829470219b922dd7b049e884e9e0c3c9d4724c597ba789d103ea7874bc983461d7cbf652e2c7ad94a9091364b3267fd0b172d5ee352b65982c81b99964d81cf232574f235760a204f6784de59c7beac136c32409fd7eae756d7e2dd73f132430b7b7986afd3d42fab71eee374b4f95731323f854add7bda7b46fe5dae0a1c2625284a95ef3768bf183d075a97866670d1322ec3ff69e6349cdb6e06f58362b406ce8b0314405e41d174f0eff239b1e317e3ec3228f083119823b08595255acbd72652204b70b2e57869339f4a53b3009427af97cb7f5f49eef12174a860d35c1169c16975006062640989fd6ddb2af9b4971ff80a5261393ab1c848ba99af8805b2ac6d493bad0a9f297d032e981a6c52674966c77b55e334c78f09ecfb92e5b6bff9093c90e7cd9bae6e072b7ec206b31d1c1eb345bd373b5ddd4539d4db3786432c9c162ac2d7bf796716bb834311ed9cc678283fea52677f7be5792491e263780c9bdb135f549971a261b784b2efb41f8d67dbf167201f29bcf9021263570e98f57ba43d84dbea789f1e3c97c67c3e96c625c11c38406f3a9c993dba92f566f352d99593cdd6750e16b6a7972b04416ee75eb4feb57697694c462a54cbd74bde96a29960ffd8871e5853f1f1c38545478c4a822df0c0e875984c4a862a404169ca0b37313b677e75cf97b425ff28ae9fef01f530ab99d95182aae909f145caae9957db71fa2127a211a10fb8025ad988df93d742d9d36f6c98ad6f6937752aeac494e4d8c2da0ce8647c92a5c726e8c9de2f7d6d34896b144154d993b259b4ad5c418e2cc4a492a1a536eeeeebfba316e54b4d9dfd8d437e15b394a4ec1dcbf32a65cd75b9d821253a85a10a67756ebe92a2b8582da2bbdb3247fd98a8d2e9490825fab5e6e7da576ea5b8c2095314a46c14efde47dcb5cee6a86841251f03fd8535572eb99c7b8f232379f37a38c9250b4b6cbc5cbbdfbf9ea12507c6be2f4df7c7b954a9f80eea91bcb925b4a327dffb56b4b3cc1d3f56b8ee563b02d4f4d8c669474422dd5e07acd164c0e27e444afb45a29b7f64b19849a18f9133af29a924d2875e8d69c4aaac79c743f5442ff852cd104dc75ec8e5bb71194644232e9bf78b9b4e02e6b2bc1c46237d35b5dddd479b3924b2ca7fb7829fda4ad2b35311e794d89259e75f9a5c6e6379d2e6962f4945442e57cdb64f3fc65a75c13a3094a28211bb35cfbdcaaf53b46c924563e742e29b69eb37f2689d76d6aab92f03597e4cb9248f8ecd5e0f4b752d2fd2652028987c96743675f3fdf27969247f4c20455a7279b9b4b4123943802aed65899e3091b2159a92ff5ed69fe72c5085e76eff5d36f2d2d7d8b90f3b9a4bc98ffd4e5b3855b18880a4a14f1cf76f73df8e67370be4a114a129194724e39c1d5dae2264b10d190f7a76a4b1def4f2f39446ad031974d17f34e89211a634eca94be367d991d79efd87095269414a299f3c3a458257fd7241a258448cf2777bfe652fa2b1ec44aeb35f9d0ff137c3071b1450a7c940862ea532e5f595f5b53d7c32909c4af6c0bd5946cf95dcabc12403853ba1e4c6eb2abfa1f20dcc92ee16a2b534bca0fcc98f2e79a42f90e26ed8392cebba77bcb565a2ef928e183ef2f9ebd5c7aef9cae3d38b79ce13f9838c957b2440f4ea5c2e9d682ba1264b3240faa95bec94a4228e15bfd82123cc0e5a95c7339e1b7552bdf0c2094dce1217bbcd27c0b726ad57678a76daea57cb66e7a85d141491dde33de6e6fae63b89e3b9b32543ca1ce0f2f4ae8c0164af65455ae620bb9640eefaa70b2b24fb5ea4939404e4b533f65b5e46fc7613da8aadfd69afa0fb294c0e1c1345b6349e76bfc98b694bc61a9edc79673cf746a732eb6b0a182c941891bd46aa96aa5c53ab9d4c6c3c60f9550c74523a448491b363d2ba666d2a7dde6beb42e256c60f07bdfc24fdd2e75aea139b5a4fcb174b545891ad284ce92fefb2aabe21694a4a1e5bfb4ca9282b2798f1234bc5f8db9aa656d2c695341c9197ca97790b1cfd70fba45a3c40c497d2639a1eaf2f65a65505d1036847397901232b0e64bbd345d3526dd1719256358770d5d4b73b919f70f2911c3cfc46d972fa598adda0c88332fb905f4f24542615095493e96124f85c93fe402448c1230a4b9aafeb2797aab774d8c2b2aef9e202a28f982522eb95b2fad722b5bd2c80e7fda0bcd3629d636795b6d9f349a922ef0924d7d3f5baa0c2a6b5a3c9f122eb8c470e9da86cd0edd6a625c79b9e108d902439f4bba3419644eab34314e7e4e8c2b3e546489165462bccba55227d5934e13232804628e0a4ab2b0d0d95b394f06a1dab0b08481a3040bfb9ad49b09b227e76e5b3a66945c0126d5b7d8316def255f9a18399ce11857e49b11248d122b40c79c2fe738ed324becdd13e44baae024a7a6dabaf51a5366ef9e202554d8fef496bffae4d2db19a30b7e878e9229a8f3d5349bf53d3515865c80c0a0440a2bb5fffe93ccbdda4a2551784c9bb5dca5dcfad78682329e132e3ba66f9f73c9139ef972cec15d8aade598c68c1227f47450727250265fbbec3f4a9af098be564db25c4fee7109133cb1bbf5f978b532e896a0040c942441c8054a90d02bf1bafcb4bcd34c4913e3f4643420f6b14a8eb069c1718618182831429249b526e7bef6ddbc4a8af0ada59974d5a9ce5f2582775a69b165ced44d6599d01309fd17b364089f1cb2f595fc0e5b2995e7341791afd131851221402597a69da9b5264621254100c20ffcdfb5345b3fe89cdca989b1c4079325c758da09d33ee659d203e54dbdd4de521743090fa074b339b9ff3ec9a98b4b76e0e4ab941c7bf5e4538d3d253a00a594e44032fffeb6ce9b9b4969090ef49f5b4e299996bf53a68931c6151394dce0b1326c4d5bf93e98541363118f47c3f18d0f4a6ca0ffa69b4a5d2d55ceb025c69597500b0b8f8e1836bcb301e3e5f32e26b061a30525359840090d949c3bdd52b29f6baf0f44320b4e4ba9e98cb5753c9b8d6f38ec051259f054faa6b636df9bb5a689f10624b1504bbdef730725536aa515fe848ef0b06183c3611d3654ca88110305125890bc42cd999aee4e663f7f2a3214892b5ab198dfedcf275f5d3ad3c448c28a0690ac82dd4b9d2dfbc9b7eb5cb322860e1b200e07870d336c848e7ca8e3d161e3d5d8d4804415fb3c257d9f2c57737a9a184940928aa6a9adf7aa72674939092a1e6a5cb8eda269179b34a56c91a23714bbb11538c1bc74170588422017324c304f845d887498130012d0e7a58b7b3e2d020012b5b0c836416945e841ac78353c2c2ccf02009455bcb448966741415185ca640280920ab509713420ce640480820ab5097d34204e2623009453706325196c8eddfb2917088a29b8d93e6bedb9df1f27cd17e1213182c24029c553b8eff519fc9518dc8c18a498e9579ab0f725c76fe9286693df58a9263fadc44a14c949b59a42a714fe32170a35d76c133a3fd89e540b144dce85df3a1fc3c92b3ff1e939b78ae76b2c392f4fc097da26e85eeddcb5be130b3ed45e754cfe5b2c714297d9faa9e0eab657de84da6f0535419ebd1a639a504f296eacf12f6eddcf842feba5ba789dfa3f63c2dbaaa7ad15f357cca54bb0d7a48249e5a6a98aad06c512709737e97213833a57aa84d3e4524a505b62c8f629b1a95f6ba558fb24526be75c72c7eff5845212cc0d7a7a8a41e6a0ff8b44eb6fd627593d4848a94eaee92e5d6beaf688c476f9674b72bdbdb91cc1fdaea64f995423e44af786f355ad5ad766a030c27bf683ad6df37d2dd317288bf8e5a6d6b9dd54a689c14051844a10ae94ad74cec99e27e23905e17b72a9ca04792162bef4e483cb9f7298563a84520b4ea789e99b3e1f33446bd2a9f54f4a57fd7c1642766a8d7f394e50f162427837db96ef9f1a264e8370cc31e8d237e8d6b247114493fc6e55fbbf9b2e3d9440e892ad4c3e5669654f06847c73e9aed4857f68eab9e96be17cfd6f991f1c3ab9647aaf5c2e65fb03a50f6abdc9d6cf6e727943c987b54ff152cc29aff9aff7c0ee56b973effeb83947d10343876c4a9514ca5e9662f402250ff2ed92bf4daea7507d62ce0850f0b0702ec59cbd394d4e7d51ee90927cf773aec54f7a6b767829599b5c704162a0d441cac94ae1936b39a81443a1036cc75aa5c46687e64603caa0ccc1b1a7cad6d7af279b7b463c3a629c287248aa966b49a65733b173287170d2df67af520837a54581c3d4e5e44aa6ebd4432551de00953fd7d2f324e15ad30d492e63cd35b65c2696300c9436246f69e12a08d54d095307850dce4165cfdb5bfbcbffade1c1d9b8b56763271fa3a84136e65232a6509f42222869980dba7a4acd94bea74b1434bc2475cad40bbd49b75c07e50c9d7e31d896ca5532f1ca7ccbcb901c2a3388467ef8411837a098012ad8a63f5d69aefa2ec35cf86eb27bc8cf1923837c70b6a70e26568c558fc131b83c5be2c5dce2b46268d35db59accabd62b158605593967b375ab2519fc0fb7a4810206a69eb36ccc5baf06dbd37c5280f2056fadeee562eb586305353172f843a04c118e4ba300c50b89d5f23a5567069d883f91cfb310e96c72384a17dc196cf916be427d6c6a6254a348c60c3080907801850bbacbab4d28a5dc750735285b600a273ba86baa5ad9a644d102e34f4bfa7be6285980fb2b255fbc982646100b7fb845080e142cfcfc9f8a3d98f413db47b9024ccdeb93520b97aa5b8d15bcdde56cd95e3535330d4a15dab57e6a8db7d9eaf6c440a182842e673b66e94c4da9384250a6a09493b2dd757e4bdd93c2e46e6faa666f2954f281a2d0f6dbf14bb6ca5e4287423bd84ef539b8ea2d7d423763cb579bba533de63a509c00d964d8ef9c7b0ba1a62f509ab03df535d98bb1f5664b4c902fa5d6544a69ade90d97b0debfd6b37bfc74ed54422b6ec834ed27f5e75a12d4540a2183abda3fa6bc0305099fbabd2a6b9adedfef113cf95cea395790fb41453102c39dce4ef957a63715175ba8284a11b8296b3b39a957d8e62302744bad7bac5ff2959e030da19f9a2d35d7c4522f9642e84eafc1c4e4eaf9b4a104c1f542f7bdbf332d5557060a10a4f7375b0bf71d9b50a1fcc07975b1c7ce57e14b89e203d91c4c337d62a8ce54f580bd74fdeca1ff83ebc113a0f0c0357409ae6bbff5246b64a0ec80db6b29ad9a9a5a2e569e50e7870e1c9b32a56df61c48d8dacd6ed656a5d75093d9cc39e4478f1e2c2036f2d231668ca0e0a0dd767ae72a2937339703e506eef9b34dce2d9e537da2d860eebfc9bc925bb39553941accf9a052c93b95746e8b42837d955231e5607a37ddd4c49889310c1c39c408e38b18fdbfc52341394e66c112cba65e49a9dff3b12cda3de59ce325e17ad0cd9358b8c397562d29d77b5a6dc1092c2483ef25297dad5ecee9e4157025d9694a7dde0fd39eb822a5d96fb9f996f9b17e1d25386945f2a64ab22a73ccdb72561ce064152f555a2ddd7450aea4709ea8626eeb245bb6675eec899ca4422eee991a2f05f777424d8c6a8071820ad814cad678f1a7967e59361a901a6bace1e3e414cab9c7bcdf4de55a621f7201e24e4ce1925a4dfd7a0917f27a9a183b3df4a414fee43276cd16fbc3e9a458707d3a7fbbfb2bf3289c4ff9d4bf753d5f4aed4414eb9aea3eb76eea52705d4e42e11032cbc44b290c4e40f1942db9de6a33c67ee7c927dabb37b854b5f6c838f1445bdf1e3e95763536a79e74e231fbe9bcee9413bdfbcadb4b5787eabb09f7563ed99e41d6d26c4b13cee04b6eaac63a1389359e9a94af5bdded30d1ea9957295e8ba5e7e4259e777ae933b15dce0b5aa213f3c66b429695804fb59da17c9468efdcf926d9dfbca99e845a6b4f242177baf5dc635dcbdbbd934848c64e356937b92d17ee4262bde5cdd96cc6e6548bd9e0e4116bae75f716640a75d7114eae8509b6b657df0c9e71d2886fed9b5bc95b72b3b13c678b13464ca9ea49b67465f393ade99345b8afb9543db9103ae7d689229e9c2eb9c2c7ecb9f53b4904d4e678b6aefae670f90411ef957bee7d5f63a6520fa15eb1bba9feb5d5e532f4e1315edc93e3e5c410abade19c3d7f2e36590bb1ee75976a7777c974ce1342a4a5a0beb95a95ba5f3608b9de0c3ea8cb25a594b99c08629552d5c5cc5b3fc81c88b756b7d5d649faa6b69a1340a86fbd7057ee7a6f7193c1c91ffaad9dea9827f50fb5854efcc03cadb2d458a50999ad3e34995e2d766e4e79c287f6bebd606b77c3c46ac7c91e78c96549216b0ff67ffb0b39d1c37bf5a4b24dfbed9ce5b69ce481bd87739553a88badab1e277880afb1c4d83f97eddc52179cdca1956c2edf41d689a9f52776504fe792eee1943b1deb933a249f2c556afde69b4eb917277458ce264b4e6aba25994e4d8c7c3287754cbab92cb55f90b5656324732287e549a5723dd5f4d68919f9ce9fc461aa4308613b93caea89052770f096a6cf9fcd2da5dcb99337347ddc92335606e57c5005276e58d3e173aad3a7cb491b94b6f94c5b826c504dbf3e13379f0dced7b09335b8b69458793ffca9aa6ad086cdada5eedf355c5013631ade7c53994c6eae5abb7c8c1334bc6350aae720a757dbf8431d26123a398363afbadeab36b19e0bc889199edc76ec6a5542674a65ca905aa9b5bd60d3397da91f2a9d0f754ec8f0968253595328156c5f276358b834296f4fcd666f77c18918a442a7be95b34efd260c83ab739f89df6b6ccd76203038a5cee1fc9d2b77d51ff40526174fb57ee7744ab2f49c782149e6e042e66f49a76a764ebae06b4ae7a6eae7d6cc05b7b43d3974d8e4b74b5b78d3e5fe466324e3099d68e11f4ac91a5370a74cfe4eb2d04ee1a6f50ee7f2e5ef18e116d00916a073b5de4cfdd4c91594b2769f5c4befe17cb682dc6e76d93cc125995a55e0097b657a4e1364c593e5840a3f5fb55ade8abd7f29a7901a5b6b3ed72ed5ead771f14821b9f66d31d6e65b69b56962cc60a2701205f786eb39d77ebaf3ba26c6222750f0c7eb3d872aada758ce969327787353d01f9bad3565eec4096a95576eafc4f45de326ac7ccade42c80cf6f2036d4e98305933f898f2dd061d36d0129c7d616b70d564fc2468c3f9d0466324137a224ad877b572bf395e8d2de6719204864ed7b69418ec954a9e20614df76b41d5e58e00dd635533412657a5572246902e5b7aeedd63d94d6a11963377289fdbe452bf3b21822bedb94aeabef4653e19425bb22997ad252ec18910bae77aad5bdb77f8e623721284e91a4a6deca65b9db3e500424b8d39bb07593373d3e3f9fcc90fd65466a88d4185ea2df3ce084e7cc09cbba4d4b1e41e6cc73dd84daba0aaeaf5e69a4e78009535b8a4aa36abcb79b283b9e633c9491f9b3b25b7e044078c5d8213aa564cbff1cb41abb78350b59554d7aec1090e52ef93afa5b3d7569a930627375049a5e75cbbb5ebe5fdc5890d54cddf9d4ab2e7b58cf138a9c1926ae9b67aee9eb576384e68f0cff96a572b93ba63ad89714563328bdfa593f9daf950d79b9a18631c81892ca49cf05d9f724aa6f63a16bce6f25b6f9dbe3575bd9bc0425b63cacf4aa9f4de539997fe8f2724a4e3d980402da020367ca8848ef08081c92b5ed792be9a63cdc1d7d626ae704ecfd4639dacc9c4b82224c81a26ad70a6ad94838b1dbffffa3061c54fb66f557b9edeafff55c8ff5d6dcd97bb4ac90dc34415cce684ae50e5b76489a542bdc650eaaec2d6da739a18a1092a3e39e6d2e3f7948685bf6324c3e414afedabe9ce3da589f1e51302bdece050f97c8c1925989862db2ba6e93506bbfdad492918538fb5c61af3df66d6c4e8384c48b18b4da6e4aef489936a4d8c992fc2a11841018fa2a844108623792410898281200642103a346604004311002030282412880412c18856ed1c1400025560546c4228281847439238200c06e3288882188661188622290ca2304529a70572ce17aa34df4519b01c7adfb7a2546be4a3f3edbc7e5df3f2a5cb5c3f82625af1a308da8ef45ac6e2ca9281651e422b142b0af118ffe4fe7dce3eff7758cd82664f96d21aedc3b7bd1a40c7d563f4b8c66ad0d709b6cdf920c3418c3db5712464af9c3a446db762b4ef9ae2649f5043bbe3b2e48ea356d0e93b19e20cf1b314592739d84d68bdf9a4e07da45aa4ddb8bba8843dfa6cc350aeccfdf444421fb812ee2287a847cc2c42237aab22c3ae98a332466e88236025aeceab87ed7d51205fa935693d03f85380d9b4b3ce38af92271298ab3ad2638e6a0c52f39f1fe77ae7772f384f4a694e838baa0fa71923de196ff15e5f4ed185847fe982544d99efc9b0548b3d5111ca71a546fdd0c1af0500053dcfd5a6c88e28e375ea961f44c2478065c30757cb50853b41d5453af7f38f14b8ac24a937da2f0569a62d3eb0af5ce8acdbce017b1774040ebf3bb66ca0c6a423ab648acae421b2872ffe1f3d6158d2b544076fe58e6242aa1e02ddf49b7a637a77601261eaa95373c43fc2e39ddc2eacd3f66446bc35bf0c6ce50df4932c7bdc0dd5b0754f66894c89755d4399793072c70c4042f44591636155e4922ded81a5698584ee496a54c37ab280bdb3cd8640642f6045dad5102cfb4ae6ddb9390cec444c2ed2e81c011f9d2d556c9eddc81b66d2bb3973aafc55dd79b9c56557c6f6792ef0a74482922dded87ff2905c5b4ed6cd3103894808e49f34e2c4d1f9d6730792534f0ce7d7fadc58982005eb8f80c01635c1986b983f03ad3b43c407d83e2a9d837f4d486f3b5f5c49ec17e5096715031b4ce374ae1d607df1a17d931e0b27965d2502d5d7a401db378d8705c8a813e20bdd078dce4cf4ff12e782a15686e7703399257342331d1d3c98c89576418dd0b88e0a5af0af9336dfab0caf7691d9f6fdba97833008d831baf3332694a9c6703876acd8638897d37563ac2f3e5c49f65b1354e29bc65fd31e199fc88c196d59a8c79545767810579a22f2e1e002bfe2c45eac9472fb1533ce79dbad6d39f44bcef35969e80742d34ecd995e0a7e34c00c87679431633b4363bf33d1207089754b495f55a1c0df1d574184a1d3ee9a99e425c4b9be4892bd334c11b668e0c1889db4108e3f195a1427a26f0f1e0f9411a7ab343ee214c0d21bdc001a6ae6a8cb4afb3d686c7575804c1c94990b7a6f09f74075b765d4ad92b50f7c4a9521f3c0bd986247c1649379dae0f16822d8bda98c42418fe714ff3a2cfafd2fe734b76f8922ec603493a8e08860963359e4644486cbec2c4d743292d60b14f97b652aa4a6ac6b69d771cc4a7b1c9c55f4e3cdd45b79bfc7dee5a00a34e7e5b0d92e7410dc8127586c0f8ad7f9dd53fbded2cbc434aa1c91cd50dee6661bb8782c97138ad6faf1fab9c73e63def36c0d7844095eddce8670aadd46bf45eab750b0e299c22f241b0f7f5c7f9bf90a3de24d4c3ff6ae6b732811b752c5b5d16356aa35edb4c404be84428b63d5644db51f50965ab573ab97b79c9a052017857df658d5af82df9757f0d14c5089af0930febb69dc9eb2eca574dff70f6a46bfee746451a2b6890210c2365f969cceb884b265cb130f4b5480d56790326d5aaad228c38db99221f1e359288b7809c4621d315a482e3ffdd7e284c0328a6d965970972825887ce6d3d0984323753b3a72fa8f8e248cd016135002c0abdfbc153e1bad27f9025149573b14fd6f75e9886e08c58679a1bb45a5da05f4ddb9be7a512f04a7307be432c6fdd2d9cf17164cc392a80db8fcdfd4f551892a0d5e97e0d429d8e020de8fa2b52df40f480a6ed52381d9424b5e91c645092735f4611e42340555b2b7c227b5b35da1206b881e2f5ab0ca69aa7cac213713de4a9c46a1a7e3e060ae613a7b9940faba873dfb07d438609e918c17204d673224fc2f5a9f8671dc1da5b96d58ef4af83e54b0b0e9394c9b2d645ed9fc6032cb92116686052ccab9cf8b694b6414063948b8cc30cfdb03ed62137792afb881640e9aa3d4422224973ce345216307c9bd51a2f2958b6da5d27f99e47eef114a105aaa5395a176cb6d1c092ab6bcf53a7164f6f85249cbb508afb9dcadc1c34a8299c1d04b1dc52da2ed3aeac41460cb23fde5ab4fedad4fb351c14f0e0959312cd4eca21bb4bb706e0c781854bdb804b014b405b337df436c25709112ac9109c11b3a451bcab6bc756af8cd5ef7c4577ba2be02161f69cc2fa0a83537250803d39a98a6cdcf238409cb54f86cdfe6110cd34c213fe254d149b45a650f436b1d8205bd18bd132ceb9755d0a37789e403f91c7420f59a0dcb78ab7ec39cd7ca01b63160a92781619c713d67d5adf91ebca97c87135e3bf535615077a535ed50365dee072bd2a470c6711252ba0da66433fdf56cd3472a86a46449db80c0aa5b8fac194f1877d0b0a949cb962b830c853feb2293a04ca7f7762e743469f8e62ce300869d2b29c21541c8b3e500094a026979cc12ac26ba50a6b212a2d22cef4ffaa735008bb4916c2d5a72100108df57889e377b5c8a5b7d88a9996f989063120d3e3dca0fcdc73947a78fd4e738b56771c895eb4599438fe60f5f536968f9e31d9f61a99c1ec2568ca6c6b525b9a22b36e56421e7c43af72e14c93e8f602c8468dfec08f92170225ee7057ba84259d6bb38ef84c23779ce8b00bac43985e2a1f10803b9764f066da14abf6549830e6322323a11356553d5f1c2a17a08eb2c1526751ce5ea3cb97f308dc8e0525226bc9512846a799a743faef154e2a42c575a0673981f24c81069d77f1cd6c0b4d9f800e670bad9ee8db3ac6938d3a40b24d5c5633417de31a35efbb203a8f6bea99837235b4ccbe3bc578e6d605fceafd2a13f2802d0971e16c177fafc47e602e68caf3e2ac89e0537b20c7193e4863508fd7f55b9288700227432d43f12b6999443d7a2eb3cf26edde8b66dcb0bc56409c61f1441065ec13ff381fe48de811b136480fe4ca6e4235b1aada71396d102730f3c5e227daf1b183fa16609028cd27490727066c9c5cda5172aabd26c62e547c28a5b84d09d873c7607b95f0c83b8bb09e2414269e3baa9a18a67a35ec9f969d6ff55589b6729a01f5cea86d97a06d57e98556c78e0dedb1ec30be610337a6a35dd0c78a8a3f589bcd078076243f1618e320b815a39dc8b8aa9e2a028ba96f2aa3cd1321c21a26df4f156bcd080307975da62ddf323b1c6ef38f3857310a142783889a543ac016f0d5e67b59be56faad8950f4a96e811f9826faf696ec73b3efbc2e1d44e4be062f13f5fc4804b7c5d4e0f010bb98b577169a3a65c730d9cdb2b1c32151166d0d40bb07fed5f6489ed66ea2299a90b00b9c0a7e01e6054f0b71b384dc147771945bab1f3629bb6d6729a946bf39f5e30e5688733872a6d5fbe8cd99652bc3400b9630dad5c1272384b978269b9ac5b70275f6a4936d366893957bace15c56349f0afb689f23b8027e670b5353020fa2b19e405332b7dbee0892700adc1e9c699263e074ce6c128732f036c4196c408fae6cb07ac2d1449b6aa08c271cb168eb9ef6e6a75cb78209a55c214e72ea18dd3beb4e436594c12ffa76b3cfb39deeb8ef7c602f1e86034f88e0aa9a7d46449f45d41eb0dc4602050fd748109cac9641f56b2f1fe2db6cd7fe41ecd61fea3095eb7ec6b2cdb74bb6474fd85457a3b635dca6bde52d59c13ae210afe6aa57f0ee3200e564fdd0a336506e500429ca783533ff0888924d0a5689996b087f7a3dc49251f728a0abc53748402b640bde320b5fcbf536ef6801c53c4764e8338ae54d04fd13b0e67b8106aaeabcb86ac812ecf678da086169682411115e86741d7bebda4cf396b7f7bcb7f8f1814daabac88fa967f001e3ec331609e25f8dddb04ba1bc9548bf5a959b9f434231c0878664481dc9cf972d5fc8dceec45c251bfc95df6ea161baf3814f4944a45c7095c40355112e1752519c587f58482ea89ae834c669db1653789dd48929cb46d7894455671c94b669d31c47fce0d85d11a229b84a9a0197279e2201025ef9176b95a1fc9cc11507f59ca02c8752c272bf7041909b11611fcd8d2085f1f222c1f582ddb361966842f8b08921f122d651b4314ca4dd4b060c118d45ecb944fa391f80bf0872f4ba6735d5a83a685796d0b4f7dd4740689796db0837cc614827b2200d171705528c23e3021a55c901152048d51eba2f9bc72b7c445f0ac44c6c38cf25bbf69399d8450804beba8eb4a9d483e300e48a9036f8b3f9341d41448fe112c9341e622646ada5e1b0db2c2b63d4740c7db20a591458ee091a5d2d947554acb010e0a3cab7b808001123b4ebe1e5259b6240d57863f1b5f0bfc03aa83d0e492cc1eaf17aba0c6ed33e9fb936f53d10bad33880a66e4bd9fc65665a3ee20b3be7ef568388abeb1e3acfad81b4e1d5d06e18f5b8c30d392fec4813e31d9cccb1f02852800a5abf9dd9ef1056ba2c4bf6f941e225831234137c7015bdd30743278817b87a0eb0638587a34bb1c5ef832ea5f2901d89d71a076f282cb4ac9a855e30e1aa054f147c4b8e2d9b731f667aa873ef05946596f35a158475140d1f2218b9833b0cb1e8792f805e93feae199bfefd4224b2eab02b61587e6da13dfd42b2169b917d0a5e57a8701087abcce6a0868f281f633c0ce74d29092f8cf5215e10cf2e0997499940e28fd85e9ad1fc9e595bf6f765f646caaa685291656e594f742ae45004d9b6348ed91cab4def32dae565bf52ba4d282363844526f2150bbd3c2b4a690895fcd44ff5ad116084b2890d43acb2d7a11384d06a97cc48147484d478497f11d5500c78a680341f5ffb4ddf08f6cefccc5e686983e9d9cc2fd2e8c7c3e4aa8bd796739500dbf4cdf2c293d0859f42fed39ae0384fd506c0372bd3ea10a1d99d673dd3df1a2fb5ac03dafb37663bc3bff3fdd9ef446b9fa4d3aacb3f3d0417bbe36ad6b13fffe9d8245b38f7af6611adac30326034592038dec1e0d05dbe1077d4d44d8c6c0014a9fb9b78f31b6d82815285486d283dbcd3f00515ad73fa6f5be50b6aa9a0cd23b646c2a0d0cfe18306866e5db060e6634fe1f16c00dfcc19b99010be6e4697c10f1d594563d7e0f606dac264b45be437d637feb66388ff708b587afc25cd1e0072a2587b389902abc2468fc8c0700f058ee1e45d198fdc6de79b27f5db5a1856cf5e4bbf3400e010f811a7c6027e8002bf8e7548f96152c49a6c0e3dbd86d6c369e64299e3922a1c17183f4a16fc8c65e7ce14454dfcdd7145c623486aac4e9716057e78dc2d0e84bd7ab75d61fd441353ed323621c48df2dbbaf6ebc379711f64e001f445b56b4858cde9e230d00d3a19b86347f66c5ef385a812e394703c05bfad87890ffa1b02a6fc84f2b382e412a5bd0c6707171012ae0c9ed286c24b032f533828652bd98b7e894693f4e5ec1887485bb7a59498fce48467caf218798b5546faa7f9d4dca2f6d8b76c6d583c7a9aa49e0e3b146e29ec3641b3b9e97e81ee1b0666fabb17d42bbe166e0419f61ca7b78bc3f4a142c9e81fdda7693419adcf4384b0113f1cb0f60f4d70f9bf9ec5cdcaa26b6f85aa07a1ae24851c7c4870bec2b4bc498ea04195fa573882ca9daefe25d316c7b6904f0cbb1a7da57d430cd745f8552c1bac4f25affd0c6498f4208a3cdda45871471f1a03023be269ac423b263b0f616a36bc085a78cdbfe2fe1395ec96741fb03a0722c3d369afc1a01633f0d7498a85c92915cf3e40ec394a47ff353432f05f4660a95b80833b280ea1f5f0300f41b9aeafa0a65bda0cc15860c80868c96a4f7e14441cff6f6a5a00b900762360a722b6a41e4ad8ccc2c1d325d3629f54cb9fcdce715c835db41a14224fde99c6bd88f7edb9f2b052bdbd03f8136f0c30769b33228e0d76ac12b4b700305b976ce6a40f3689a1ac54582601ab69cda93bb9a95a8b4aba71d3764f5229941b8680551be0055d55876f2ae36fdbaf27f9b13c6a33d580518be1fde5fdc854ecab05bc05c10eb6dd76767a1aeef8d778c1490cd7674ae1d0da61c21dc6cbf7180658fd1f3db6d55bb484d0db6799e99365ad3e61675af9742f3f596065e6bc0f4687640adf3fbc78c2e1e42c268816d01fd8590e4625d68be2c798aaefc68d2ab34ec39df2bcb0ab0e52eeed2ab74728199efbe0d42a36fc3c598178d64851279f9374e2fcf2eb1cd54513b6aeb25f96c8950a390689acfb50f02ba1a8f0baa23acb770e7de1b8be13746aa1605e50f1fea3a67e6b31f73857a6f7a7ffb1ca8d12a5d70828d566938128909b27dd007845c8d3569436027eb44c5858c42212d0a6bcb20cafec1b0c8043afbb84c9247661aa33ccb2d6702736b10b0fb69796c9197bf7205582bfd6b91934e0b7d2e56a67c4ea9c43c30d4083e49e387a8ecf2caf07ef0733028d48676503090e102d08461a9a0e4ab233c5ff551bde6ecb2cd6de4c23f0153d985d5b922d17f6bd3f82984eaa5739e8881fe5e9903104a99bf795780a4c2e558b8c7e6c25fff1870b77adfbe72bdfa648c1cdaa0cafdaa95e206153f06d461c8ca88f4c393216e112ccd54ba7c45f031eb2acdacc6a7b9349596e29941505779c19042f0fd334ddd6a8ec00a434629fd48c8f91b17c85b2611b57980061250d3056b5102c310434d9a33c097b293d55c3070646731b3521a09fee4882c89939e6e27a7af08ed0306ad5c8e5d50b4fa7989088165452a9dd3f4ad8eb1e151f6d2c79fe18c8f6fb83d3ef7acb3e2393d08c22663f05360c573140a82d11ac324e65564a5f376440dd138bb201ed9410519e0e0ad25078c751c9d9d546cbab26c91b279a172611dc5e26e4fd32ab2bba9891d61da65a87bab6586678e38e2b0b03dc621330f08998a0934f0a8499026ada4ff7ce5cd6e19dd1e31334624184761d7b5e7783a834594ddd7e70cfef32236ae1ca9d4e484ec3061a02130fb84de88149569aab587f3bda442139b4dccdfac4f78084ba93230740de608bfdbb449c5569dfa877e9d4f2f8d7ac0c6201ee6848a582505f6d78923c88c41ad0154ff3c8d310c63d9a9a155fcae7a793076a7769c54f6724e7ff42dc6205bd476ae0d63b05c5a479f9369a51546540b42c21189db637d99a02882b5c19c8013a6c3b2f85853bd2c9a025391017f0e1f525707074f9a06e607e501459a307136166784d74928416c8ea9b1b62d8beefe1d81016fd4b17b305700231ac429da782011e080d091191e7c6200ea81c105ae2575a9b682017571afb64b9b1826a5fe256df33e834d006a08cf8b52354ba18e1457b23a271876d77d987bf03931d371e9c50f8f92bdf3c0792d63618a37676dbd9687e14e31d9264c324a56b92628b84f59fdc0c2c5ee1ab1db73cacd6419e30465d44e3a243b669cd803803b86fae6329e7e19ff916ea4cd338c3034433c9aba9f58a66e79b18eea0d801034ed90bf7e3bdf600be8aa5e8eadcc063000eaa7b20d9b84c9602b04e6ed4cbd0f8bbd5fd5bae48fce32f78c9ae393a0e7c3474430813ad810aa4341b5aa1768bbd88c27f96c4d2bb98ea35ff727593609811dbea5baf8fbf3940379b6636f3e81b09aed4d979c3624b7637a257e6d07f944fd1eb730955dccc027985a4eda25be282f84047ad234ef5ee2245590fdaafb50bc92c0ca84e3c9e20c905cafcaa8ac9026eba8c4d24e498296d7ab55a498ef2e10b0a4b0e42dfb8afc3bcb578f1c83a23bee878830898b2f865e4acb25dcf28a50945391205cb3c28081eec105914de4fba31c286c6fefad6908ff69108f9cb6f668e767ce0745bd116231d2c4cfbd667d66416b049f8ea9cdae2a123a04ef66161718b0588d299ac6cf960a191bdd261c870264dcb3279c9f540dfe50d2f586754de0d5fec929d61501caec7b3a9896c720995011f4a26320c60b4275b96c9d3b2f28ffcc5fdad5cbb90e1652884263b4131a76384427909f8b211e8d10171694fed5d9776601d5e442697cbad52f87ee79c710a421db0be3441ad23c59636434e670d6b5bd7a317a197207f36e352d4086b1ce38b852613d00d8843089a73ae82322a7214fe2eb9d29625a269c3481363cd2724df05154326807c4750a530612db45e7d0a33fb6755542d090a52bb261c580ba5b17fd8f2348c215edf06f4312a0181da597367a063a4ea0acf29544ec38f19256248e289a9f2ff34c27c4ed82c00f8789e3f7b6bd8e33f7c4acc6f399d8a7f5f4d77dfa8a5099f79d568357c84153bdbe8b5d3185494cc7aee5e45a44b63b06116cb18205a832e0272c34c44fd0583bbc3d05a7cbe2cb05626e1a9b607546b90c2dfb7a1dd09c3785a6df261bb76f867b1061ac3d313565081edd576fa1d7853152943603e8e681d5ff9bb6fb4893b93272fde6efe74056077f7fd622208b200cd41c6eccdff36b011fe08ca54d20a1a4e80661ce5a4c148d5dd5c137d658f6d373776ec21c83ad929f59a4df868c80be216c4cd5484e74cc74d02095689c965ad134b5e5da33f6c04e0077a8eca494b3bedecab0e03c75bbaf28a26d46e41f3f5e902f9e0a2feaa78e312a9325b45ffba866e8c90cb91bb299fff2adea1c3815c2d430495710800697f7946988f2c6f664aa1dc582c5ebd22fb121ec7c488fc0cbf47c0d3dc16214d5545b050739da298779b42a6dce98244d8bbb915e9c627248e141a2a7092fa05565ac7ee96028866df311b312657d62b948a4cc6f02ab5b1afced3069b1c0b658efdc3365f3ee52aaeb232c95f5e97065d62e02eeb9199aab3246b4331d58fb792f8d342220ec6ef8000b8c98d878ec668472e2105b21ab03fd288e378acaabd51067dab3882570dcf07ad3a299693ee7fc273e9d97bfe2d26f9710a75b1ba04c584a3bb0663d01c63f61ecbd81236145e2ed9fe84a74494db4b56ccfb8d5a02c8a72e097bb0bcd260e9b78fa32091be8c318cdf76d949b423164277dd6e5bb1a4b7bbfffb3083adc55956723878d0e9fff2456d4b0245d32c32860a73d5a9c5ec84f64eac7b70bbad085afdbc4e7bf5cd86f1affb7fa217bc6391703dbe5254fc0351d02279cbc0260a8400d6f30d80d88fee5be6b334b1a2bc3b885df127760c0e3beed7e139088ec912daf319cb31f51121acc55fca45507a21b746cf662074c11be673fc1eb171202e6c70ab0dafb90d8f9f089140cf8a2472857c73ce5a1586f9888a137b14d0ce89feedeaa715b0685229cecc1c5b2452f746d74e4c9ccf4cd211c92d5da6a9606a2b033b647bce0dc1cd849d30ba49f7251384700a6aa77b89f6317cab26d1fe2041d34fcbe0f481b332644a6ad2eaf0b88fd6f2d42ce82cf3ace1b57afe42137ca1cf4ced7c321538a6f7a928e4bba45920f46b39134738be23bc72e65a3dd1f714d458e71535088a5fd2d64ad7f203860978b5ef2ffb9c12cc9f1da67c32612b0770902ee39865835dcdd797637b4362fa22c748b97a1a36b444a40385b5ab83cb87470d04ebef5833667ba88ff9e5a0a9a586608c89dc190b892ab2ee40cb55fc06b632ee660e7191006b8f7323be53b0551d8feb7b8d43a1835f7fb936995ae38745c1ed57894e58d580334cfd01a1b14b937282e933253e1b8f31f05639e38886c434101caf629f7ed6343af136bcdb4125301569fdd6f5e5d7f046e1430569c708a1e3eae322de41d37701cd36f5b5663ec2702972c6b6fc8888bc78146039e117c02535108205431bda2b8217829f4de6b3bf8eddcedb4515e6194366c94b72c9898846412e5a35a97b29071d550cb4f8e2ea286731acde3a38cd38fc75cd21eaf14f21c4e36a0c27aa0ddcca0b3636662071de068b721d22d00565192cc89f4fd57f39632cde06ae28c39f50a5c42779e4908f5b561973d85a510fe9d60075ab066e6651981666f2b739449c561464d93024a6050215f6aeb4b5b88797001ef62766cf7267194f2b1b0cb6157d202b5a751bf9a07a959af7ab5936450837a940750deb8cee160b40ab01aa9fa103554919a4910d48722efeec2452f0770690e95a791d89d1013e75eff2d885dc8a36ba9a1234f937f11bd93e2705d176ee847931c18c440e04f66cdbaf439ae1656ed1b881ad1b575394dc330c54751fac88ec26aaf252560649ba8d555d93b6cf636aafacc688af067a1e2e3d99fa6624d838c3e2fea61f8eaa3df0e06b0ca22159f5833dcd93902c0ce18a49e619bc675b03407563d2ec0668e2636edd8cc9761669e9acddbf20d6f08d988c33f7349c0a3de3acb84079318434411d198720cab68eaea3bc09154eede78c81c3affba9d9b67c2bd4a2425aa22c219b2adea91b4095b4e1b326d154819227af476fac047d9055b829bbe9fda875140368d6649708a53efbe856accf62a4cc928f808f2ddf309759825564f96f146e86e6f03ad5c4760b110cf03b62991e1fc2eae83abef253198c5f4a034ed42e8f0114bf93c69884c906103503e86d5ae14df8a3798cc45f796ad744286770f4623553755ad0bdd48c8cca866704d1aaaa0025d193aa1e404bb25416d5242b079e37ace3f03507c9b787d15e309a2bf71b57e8099e5bb8772926b0e9ae66b77fb92dfe9fdd4fbbc52e432a08cc7aa9197f400547c4bb9106132b28695c7091324eafd8e922d69831488eae16db5452ae464271f5ebf6fa3036930f690bb00e31a884c03d9a80a1229b9958d82193210c234b4dc06aa1d24feccd34914d60855cd32e3b7a5681fc82f9d0333603234082f1538beae1686a4d264aa3fac888d4ed02fddb465c75270f79dab7de7990a2e2165158a041a088ba0da4b327e48a8af2512ddfe21b4534f9297c99487639373be6fd5cdb510ebda12d7d0e57a50838bc4d714fda7d4cb5b0ac089461ae196805ab21edfa815bd7f0ea0bb52c5aa1f009eccf96c1dc6964014e33e616632181196b17c549374bd0784c04ddaede20be2c628d7d1b4ee3d99ed7ee2ae21f034b8f51374941df3b9c181f25189b7fd02154fffbd3bbd67e6a5379ae94c45c909f096ad27da443588e1fccd3091a5c7dbe483581a8dcf675e462f30a9d073b73a0b89f164b7266adcf503d6ae0cac932430eb06d0d67a6d19ccfa6c3f29e228d4b76fab91d0215a222a81a8d49f096ade86ad33ab72e0e7a1bb762fd26c09a4e19131a5e25e9448f47b12515e835c02259e7893d564860b7f00396f3bada08a8bef4fe419e9f64b066400ee6284c66170acb5ff3822c019b51cba00aa2be32b986412ef6983907734d43138162770413480332867494d033b3d4d437d5851b0abea67a4a19e8cf783b1220e68800c1a0674ae0a1627c08f4f8b2f2fc7e12877aeb007b030fa5b72711649d69888c4586b6988f083169f3203ac663023a663871431dc51225bad783014b4006ec44223fd346d6fc600c819c90eaa132ea209ad6b950d8db41bb6a21f340fc7335a9e9d0c2ecf3b819c5121c63c7c421ba843c148db4b4b323dd148eb2b28df30881fa43252535934d2078bbc8eaee920db359e6b502373f9c466bc65a4cb0c8d46ba842e206aa3910e458575991bd50f70703c0312baa3912e1d1f8d549e96ff5c78c29978485efa422ecf5f314bf5386209760d2303cbd27b5305ba67cf6ca9e857acc6cf40638847914ec571b4dc327f84c4e01f46e4528d64f1823960f84e466c5d55cc068957ba76c2443916ae25e697cb5b65c0b9dce3c80d21dbc06065054d2f7eacd4a99ac9fe9245c9af420e269b0e8c035320c7549f18ec5b317f047803dbff70b18f8bc9cc1324ce36b82de2af91fca54d0d7ec1d614d244542eb8d711e55bbe5816aa6af9f4be42e4226d552d33e8da12c99e0086160b69bc0dc20ba5b99a8e7ba344ff354309e516dc3c232720912142206742f43eb1e75b627e75331e73bb57e3ea816f792a311aa5e8d8554d90ad4826de721bc0dd7c73450646dcc3b044cfe1211e854ffc5d20aacc4ffe70225524455760a0f6037065be10389f86f30b9d87166080c70c7898d868286150c7c0e6cdce3736c2df62226354fa9f6a480686af2d9013157956c4191fbdfae467c435afe39f4dafcafe70be9d763080ba84497a54acdd5fe4b32344b0b4ce4708584c99a52997bef8b68f12ee7034555530d955a517203ce0b91aad2ce1da1ec712bb4d7297273547635e07e5e2ab7ef2a1b771cf3b3dea770ccfffe25783c45ef63ad564f61e7c1c6b6943c1a1538d41ebef6658e144c64da3d2fefb41385737b0c9c0837daa2da11418d455d29f1214d9ba566861eb2fe2f1dc1321707033e6beb40a87a02cf1e408a1391f7d880bd61edb2a5fc571294f47d0e2c76fd58bfd39e4c7530df0182fbf8fd08967b58fa0fb8af62ccf0ee824374785025745c7ea078793cdbe02db29d391dc777b303ccf4627e3537aaed9af522ffc456a814cef60cfcbbd71081077e279edc6688abec5faea056429fadfc51613df7d6a8f9bd7a978842371f552be1f1b37ecef5516bffef70909187ebb9c71ce5a7750777fccad05dbd2096592dd1885b1a8750b085b5594a8052adf6182f83d63547285d10d2e0d43cf54342c7382fa8c310e722b2b5d361960ef98e0108ccc73a83e3da11ba94a53995f7b453e4fc00e8ae354d84449fac7de861b3048e22237dec99d527fe1f8e803bcf9cbdd0714cd244d27fa733b9c9c0cdb3d979cb71b1c8bf439021945c5632054a4292ec6c1f74465c2df9e7ce4bc4f66837abcc1736a5ae0af5d9e2d4a4e7593a900a10d02c6dff7ec2e25097a0c5cca624a2e67150889e2f837b2a6a4ac0b420faae41c70f0cafd4b991ec23d4e408c0cca6f833ccbc2d3e5b4135d7c968e7d1166f56d6d821608416af3f489d89a0b8792ee000310fe3b007b1f76d8f79a35fa893a37a17aff71d683a9490a11ef35b46d46e5ee12d18756d48f80d2020fcda722df6600c69d16cce73ddcc9fb5d058be44377b5db386f704e72892e310c0b21ee610e114ad2d1bcc43774f7007f58e0ff4fd974b096fafa078e4f975548869a8cf3233a0c2fa09590f89c203d7daf7afd8f68cc74c1472ac441a4819f950f23cb5ad3edd977b363ee819e74b19baee623b73c0a753ff7f60e70a4bc6130d9da33af1c9c370e7a109bb84e97d906f5e91ec33d37de93656362d27b78df150d2434a8f736372cbd76ff5d455fba73fd25ff3e02cfc34f4d339a64500d93fce8ab0df118247133b5eb5834e3a07b440f7ae8d7123890b0461b8c84a1502b4df6d6c6edcb9c6cbac7bb9ea0b8eeaf7120bb5b005f8514718a204ae4d57021f6f34fb85b2c3c3d8332e846dc992d7e024ccd78b2c7202b197b3c3a67b823906eed092724128695769763553af540512345e5fd42929c22b872c0530ca20082553f46819139cee1c7e8cfde432a868d5449623311f9a9dfddb7a5e0c34b07f2a93e5eb42c472b23970a4eea3f9009c062a711d38057b67930c2f7dd69901860767bf477e4ee36e5a29f8583702a737ecb6ded4bf498676cd1119aedde656b9defaae6a827adbf9718958b50d6cdfe2819330a0ac95246c77a2abb1e4f2de03b18b2a1edffcd21b629694f6c04d5410c9caa196351bac8c445ef094efadc71b1f6a1cc926ec152362cab2b336f93c152df3644bf91ee6bf9b4897b13e6941f907bd78b4660be062f4bc0d5d0934ec5f7afe828f3be1e2e1fae1e9acd1a2dd9fb13df3c151d9777d85e4d7b9b6d8e8c6aee64b6454ee31728336c9977d69abdf58920680e60e8ef5b1e6a83a302f87447f3de1549ca7dbf5f4a32191d72ba0425270bb7bf6f17d282b3a172cb4287b954c625118da112319485a050f5cc97c79871098303bf669d6e8903fd98dc464d6374a24de1f8eb479ffcb2a901882577f95fe9a721cf4b48fce8c3667037dd3c2ed43ba138331e13dc30be40a6dd07ea7dc2b78f527f0e866c442575230a4e3152525cd3225a9280912b287502d9c24d0fecb9f0f8ed52f600a5cdaa157061e270445124d4960c0060e2b1c210c7f1ef6294924342b7c9c033dba5d3fadf6560b87e9b7616c2bfde253b7d2e31860d38bcaccc6699979696c47600bd6c1d8387d25e3b9a9a29d15dcf63d1b9a10717a5aba28948d55d353dc2302e3ee97a9315945d07caf75cf13d30b4c4b7881a0b2ba198336408db7eeff1a72ba35452f2229fd3392d264c1e046109a6a723f283fdd0b295067689d026bd26cc986d97e0da6179199b121565e2455a6fdc4b408e76e13494a23ea8b6ca8c438880a25aaeaa490434f660c58dd74be371b083b4e14cf1a029b8c6d5b7a3f8fb1994df0628a8c0567c43d0739da80aec11785634f9aec6d4bf7f7267ad42b74d0833628cc871718424334368cf24c9c980d22531c71c6329539926d1e3d33df6df9f24c1713a059a704ecf34927c4e4282856a38a0fe2a1685247e6f03de067fa84fafc8ecdf5bf62d68e8c49dafc3c2cc531a75db46bbfac79ff77e32795e2cbb45d2419bc2ea9ee37a2b4ef05da56daac9e55273dde8292e3bfde07d48c6fea5f6b947a8efd0ef5a0e0fe263fa229d1032c8b979f1fa9fd8420eddcdb6566302cd707c662bbc3c3efd024320814b97edd27fe60b29046652381948c605c66d4360dc7f915285d1559d27eb491bf6c58d400c4c2451653e522209f8c7597e5c375f32114510a522ff96350c0dd6e0527004432d4ac2da84a032c86a0e8b75ffe6f1348b4deaa238e09a8ff7a2cf2ce82beba3073d428f6361798ce59cdfbb347c55bc1a17361168841b072cb6c1041e27d0ab3de0f891b8ef913e4c59b23144fd1b84d06887f21a646b2d96bb8894a6759791c1b243812abeefa16a114d1f14ad5a5dd3834e3997cfe62d397371f953f4256def55fb9b88c783641868c5ae4fe4b61fec596ff97ad3662df86cb0b85950bb11929d4e1815247a60c37635afbf45f0ade00407f98f41cec52bb1b73ef2fe81fcb23a6541b8ea233abfea3ebb714439d54ca433ec96d32f40e762541cf9a67c750f7a643101aeb6bee2ce9e69a27f540db51fab67f55c5bc2dac4afd505b6ec7ebad2415cf3c3b311f0e15b4be4a9b1df76d14dc00cc4927ff8ba3d00276d8166dcf9a7c01ee0df2db64e818a821fe0205eeef49f056c3ffff051f94189c6bf6c7669402418417af5447d3b237c1eb9504cfad72fea840798d2077b66fee5e74b040515336957858afb47d595ee1ca3c7bdcf8b4bf477ec1dbd687f99a1209f885cc13c087ea133b42197edf66bfd8339e1f4322cf20b9ef9a5ef8938ff1aa71fdac3ba0698ffdbc3246016712e0e1523cb10bf7f1d0806bf35552b9691ddcd4f0710f6a2ca4a003e6409", - "0x3a65787472696e7369635f696e646578": "0x00000000", - "0x3a63": "0x", - "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01", - "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000" - }, - "childrenDefault": {} - } - } -} diff --git a/cumulus/parachains/common/src/impls.rs b/cumulus/parachains/common/src/impls.rs index 42ea50c75a8d..c1797c0a7513 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/common/src/message_queue.rs b/cumulus/parachains/common/src/message_queue.rs index 511d6243cb8c..d6f2118e454f 100644 --- a/cumulus/parachains/common/src/message_queue.rs +++ b/cumulus/parachains/common/src/message_queue.rs @@ -1,18 +1,18 @@ // Copyright 2020 Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// This file is part of Cumulus. -// Polkadot is free software: you can redistribute it and/or modify +// 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. -// Polkadot is distributed in the hope that it will be useful, +// 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 Polkadot. If not, see . +// along with Cumulus. If not, see . //! Helpers to deal with configuring the message queue in the runtime. diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml index 7bd91ae6774c..25796e7d64b4 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/Cargo.toml @@ -14,6 +14,7 @@ workspace = true # Substrate sp-core = { workspace = true } +sp-keyring = { workspace = true } frame-support = { workspace = true } # Cumulus @@ -26,3 +27,6 @@ testnet-parachains-constants = { features = ["rococo"], workspace = true, defaul # Polkadot xcm = { workspace = true } + +# Bridges +bp-bridge-hub-rococo = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-rococo/src/genesis.rs index 3a87322664d9..606d04060b6b 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 @@ -15,13 +15,13 @@ // Substrate use frame_support::parameter_types; -use sp_core::{sr25519, storage::Storage}; +use sp_core::storage::Storage; +use sp_keyring::Sr25519Keyring as Keyring; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, get_account_id_from_seed, - PenpalSiblingSovereignAccount, PenpalTeleportableAssetLocation, RESERVABLE_ASSET_ID, - SAFE_XCM_VERSION, USDT_ID, + accounts, build_genesis_storage, collators, PenpalSiblingSovereignAccount, + PenpalTeleportableAssetLocation, RESERVABLE_ASSET_ID, SAFE_XCM_VERSION, USDT_ID, }; use parachains_common::{AccountId, Balance}; @@ -29,7 +29,7 @@ pub const PARA_ID: u32 = 1000; pub const ED: Balance = testnet_parachains_constants::rococo::currency::EXISTENTIAL_DEPOSIT; parameter_types! { - pub AssetHubRococoAssetOwner: AccountId = get_account_id_from_seed::("Alice"); + pub AssetHubRococoAssetOwner: AccountId = Keyring::Alice.to_account_id(); } pub fn genesis() -> Storage { @@ -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 80d2376c6811..75b61d6a4cd7 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 @@ -24,8 +24,8 @@ use frame_support::traits::OnInitialize; use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, impl_assets_helpers_for_parachain, impl_assets_helpers_for_system_parachain, - impl_foreign_assets_helpers_for_parachain, impl_xcm_helpers_for_parachain, impls::Parachain, - xcm_emulator::decl_test_parachains, + impl_bridge_helpers_for_chain, impl_foreign_assets_helpers_for_parachain, + impl_xcm_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; use rococo_emulated_chain::Rococo; @@ -59,5 +59,11 @@ 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); +impl_bridge_helpers_for_chain!( + AssetHubRococo, + ParaPallet, + PolkadotXcm, + bp_bridge_hub_rococo::RuntimeCall::XcmOverBridgeHubWestend +); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml index 86d4ce3e7ac8..8e423ebbf9c2 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/assets/asset-hub-westend/Cargo.toml @@ -14,6 +14,7 @@ workspace = true # Substrate sp-core = { workspace = true } +sp-keyring = { workspace = true } frame-support = { workspace = true } # Cumulus @@ -26,3 +27,6 @@ testnet-parachains-constants = { features = ["westend"], workspace = true, defau # Polkadot xcm = { workspace = true } + +# Bridges +bp-bridge-hub-westend = { workspace = true } 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 219d1306906c..30e7279a383f 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 @@ -15,21 +15,23 @@ // Substrate use frame_support::parameter_types; -use sp_core::{sr25519, storage::Storage}; +use sp_core::storage::Storage; +use sp_keyring::Sr25519Keyring as Keyring; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, get_account_id_from_seed, - PenpalSiblingSovereignAccount, PenpalTeleportableAssetLocation, RESERVABLE_ASSET_ID, - SAFE_XCM_VERSION, + accounts, build_genesis_storage, collators, PenpalBSiblingSovereignAccount, + PenpalBTeleportableAssetLocation, PenpalSiblingSovereignAccount, + PenpalTeleportableAssetLocation, RESERVABLE_ASSET_ID, SAFE_XCM_VERSION, USDT_ID, }; use parachains_common::{AccountId, Balance}; pub const PARA_ID: u32 = 1000; pub const ED: Balance = testnet_parachains_constants::westend::currency::EXISTENTIAL_DEPOSIT; +pub const USDT_ED: Balance = 70_000; parameter_types! { - pub AssetHubWestendAssetOwner: AccountId = get_account_id_from_seed::("Alice"); + pub AssetHubWestendAssetOwner: AccountId = Keyring::Alice.to_account_id(); } pub fn genesis() -> Storage { @@ -58,13 +60,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, USDT_ED), + ], ..Default::default() }, foreign_assets: asset_hub_westend_runtime::ForeignAssetsConfig { @@ -73,7 +79,14 @@ pub fn genesis() -> Storage { ( PenpalTeleportableAssetLocation::get(), PenpalSiblingSovereignAccount::get(), - true, + false, + ED, + ), + // PenpalB's teleportable asset representation + ( + PenpalBTeleportableAssetLocation::get(), + PenpalBSiblingSovereignAccount::get(), + 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 608690218d2f..c44f4b010c0a 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 @@ -24,8 +24,8 @@ use frame_support::traits::OnInitialize; use emulated_integration_tests_common::{ impl_accounts_helpers_for_parachain, impl_assert_events_helpers_for_parachain, impl_assets_helpers_for_parachain, impl_assets_helpers_for_system_parachain, - impl_foreign_assets_helpers_for_parachain, impl_xcm_helpers_for_parachain, impls::Parachain, - xcm_emulator::decl_test_parachains, + impl_bridge_helpers_for_chain, impl_foreign_assets_helpers_for_parachain, + impl_xcm_helpers_for_parachain, impls::Parachain, xcm_emulator::decl_test_parachains, }; use westend_emulated_chain::Westend; @@ -59,5 +59,11 @@ 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); +impl_bridge_helpers_for_chain!( + AssetHubWestend, + ParaPallet, + PolkadotXcm, + bp_bridge_hub_westend::RuntimeCall::XcmOverBridgeHubRococo +); diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml index f3c0799ad0f6..231265085eda 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-rococo/Cargo.toml @@ -14,8 +14,15 @@ workspace = true # Substrate sp-core = { workspace = true } +sp-keyring = { workspace = true } frame-support = { workspace = true } +# Polkadot Dependencies +xcm = { workspace = true } + +# Bridge dependencies +bp-messages = { workspace = true } + # Cumulus parachains-common = { workspace = true, default-features = true } emulated-integration-tests-common = { workspace = true } 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 12778215b132..0268a6a7a1b3 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 @@ -14,13 +14,15 @@ // limitations under the License. // Substrate -use sp_core::{sr25519, storage::Storage}; +use sp_core::storage::Storage; +use sp_keyring::Sr25519Keyring as Keyring; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, get_account_id_from_seed, SAFE_XCM_VERSION, + accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, }; use parachains_common::Balance; +use xcm::latest::prelude::*; pub const ASSETHUB_PARA_ID: u32 = 1000; pub const PARA_ID: u32 = 1013; @@ -52,17 +54,29 @@ pub fn genesis() -> Storage { ) }) .collect(), + ..Default::default() }, polkadot_xcm: bridge_hub_rococo_runtime::PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION), ..Default::default() }, bridge_westend_grandpa: bridge_hub_rococo_runtime::BridgeWestendGrandpaConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), + owner: Some(Keyring::Bob.to_account_id()), ..Default::default() }, bridge_westend_messages: bridge_hub_rococo_runtime::BridgeWestendMessagesConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), + owner: Some(Keyring::Bob.to_account_id()), + ..Default::default() + }, + xcm_over_bridge_hub_westend: bridge_hub_rococo_runtime::XcmOverBridgeHubWestendConfig { + opened_bridges: vec![ + // open AHR -> AHW bridge + ( + Location::new(1, [Parachain(1000)]), + Junctions::from([Westend.into(), Parachain(1000)]), + Some(bp_messages::LegacyLaneId([0, 0, 0, 2])), + ), + ], ..Default::default() }, ethereum_system: bridge_hub_rococo_runtime::EthereumSystemConfig { 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 d8b8edaf2409..5ef0993f70a1 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/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml index ebcec9641e7d..8292e132809c 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/bridges/bridge-hub-westend/Cargo.toml @@ -14,8 +14,15 @@ workspace = true # Substrate sp-core = { workspace = true } +sp-keyring = { workspace = true } frame-support = { workspace = true } +# Polkadot Dependencies +xcm = { workspace = true } + +# Bridge dependencies +bp-messages = { workspace = true } + # Cumulus parachains-common = { workspace = true, default-features = true } emulated-integration-tests-common = { workspace = true } 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 4be68e510f4d..f72eaa30026d 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 @@ -14,15 +14,18 @@ // limitations under the License. // Substrate -use sp_core::{sr25519, storage::Storage}; +use sp_core::storage::Storage; +use sp_keyring::Sr25519Keyring as Keyring; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, get_account_id_from_seed, SAFE_XCM_VERSION, + accounts, build_genesis_storage, collators, SAFE_XCM_VERSION, }; use parachains_common::Balance; +use xcm::latest::prelude::*; 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,17 +54,34 @@ pub fn genesis() -> Storage { ) }) .collect(), + ..Default::default() }, polkadot_xcm: bridge_hub_westend_runtime::PolkadotXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION), ..Default::default() }, bridge_rococo_grandpa: bridge_hub_westend_runtime::BridgeRococoGrandpaConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), + owner: Some(Keyring::Bob.to_account_id()), ..Default::default() }, bridge_rococo_messages: bridge_hub_westend_runtime::BridgeRococoMessagesConfig { - owner: Some(get_account_id_from_seed::(accounts::BOB)), + owner: Some(Keyring::Bob.to_account_id()), + ..Default::default() + }, + xcm_over_bridge_hub_rococo: bridge_hub_westend_runtime::XcmOverBridgeHubRococoConfig { + opened_bridges: vec![ + // open AHW -> AHR bridge + ( + Location::new(1, [Parachain(1000)]), + Junctions::from([Rococo.into(), Parachain(1000)]), + Some(bp_messages::LegacyLaneId([0, 0, 0, 2])), + ), + ], + ..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 f701b3096994..e7a28ebf4a46 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; @@ -43,6 +46,7 @@ decl_test_parachains! { pallets = { PolkadotXcm: bridge_hub_westend_runtime::PolkadotXcm, Balances: bridge_hub_westend_runtime::Balances, + EthereumSystem: bridge_hub_westend_runtime::EthereumSystem, } }, } 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 6a28b1a9dddb..d4ef184ea392 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 000000000000..94d43c5eee2f --- /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.1.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 000000000000..e0f035c368e3 --- /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 000000000000..a15303a22e12 --- /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 000000000000..2640c27d016b --- /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.1.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 000000000000..239ad3760c11 --- /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 000000000000..41949843b02b --- /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 b14009933029..36a701d24c27 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 d385fbebc821..942ec1b31d2b 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/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml index 9e6b14b58598..743cd7dc54a2 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/Cargo.toml @@ -14,6 +14,7 @@ workspace = true # Substrate sp-core = { workspace = true } +sp-keyring = { workspace = true } frame-support = { workspace = true } # Polkadot 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 450439f5ea30..63510d233d2c 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 @@ -15,21 +15,23 @@ // Substrate use frame_support::parameter_types; -use sp_core::{sr25519, storage::Storage}; +use sp_core::storage::Storage; +use sp_keyring::Sr25519Keyring as Keyring; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, collators, get_account_id_from_seed, SAFE_XCM_VERSION, + accounts, build_genesis_storage, collators, 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; pub const ED: Balance = penpal_runtime::EXISTENTIAL_DEPOSIT; +pub const USDT_ED: Balance = 70_000; parameter_types! { - pub PenpalSudoAccount: AccountId = get_account_id_from_seed::("Alice"); + pub PenpalSudoAccount: AccountId = Keyring::Alice.to_account_id(); pub PenpalAssetOwner: AccountId = PenpalSudoAccount::get(); } @@ -59,6 +61,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 +83,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 AssetHub + (UsdtFromAssetHub::get(), PenpalAssetOwner::get(), true, USDT_ED), ], ..Default::default() }, diff --git a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs index 91793d33f304..92dfa30f2e83 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/chains/parachains/testing/penpal/src/lib.rs @@ -53,6 +53,7 @@ decl_test_parachains! { PolkadotXcm: penpal_runtime::PolkadotXcm, Assets: penpal_runtime::Assets, ForeignAssets: penpal_runtime::ForeignAssets, + AssetConversion: penpal_runtime::AssetConversion, Balances: penpal_runtime::Balances, } }, @@ -76,6 +77,7 @@ decl_test_parachains! { PolkadotXcm: penpal_runtime::PolkadotXcm, Assets: penpal_runtime::Assets, ForeignAssets: penpal_runtime::ForeignAssets, + AssetConversion: penpal_runtime::AssetConversion, Balances: penpal_runtime::Balances, } }, diff --git a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml index 9376687947e6..6db1263df8c7 100644 --- a/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/chains/relays/rococo/Cargo.toml @@ -14,6 +14,7 @@ workspace = true # Substrate sp-core = { workspace = true } +sp-keyring = { workspace = true } sp-authority-discovery = { workspace = true } sp-consensus-babe = { workspace = true } sp-consensus-beefy = { workspace = true, default-features = true } 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 074a1de5e185..3d8b5b1a500f 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 @@ -18,14 +18,15 @@ use sc_consensus_grandpa::AuthorityId as GrandpaId; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; use sp_consensus_beefy::ecdsa_crypto::AuthorityId as BeefyId; -use sp_core::{sr25519, storage::Storage}; +use sp_core::storage::Storage; +use sp_keyring::Sr25519Keyring as Keyring; // Polkadot use polkadot_primitives::{AssignmentId, ValidatorId}; // Cumulus use emulated_integration_tests_common::{ - accounts, build_genesis_storage, get_account_id_from_seed, get_host_config, validators, + accounts, build_genesis_storage, get_host_config, validators, }; use parachains_common::Balance; use rococo_runtime_constants::currency::UNITS as ROC; @@ -75,15 +76,14 @@ pub fn genesis() -> Storage { ) }) .collect::>(), + ..Default::default() }, babe: rococo_runtime::BabeConfig { authorities: Default::default(), epoch_config: rococo_runtime::BABE_GENESIS_EPOCH_CONFIG, ..Default::default() }, - sudo: rococo_runtime::SudoConfig { - key: Some(get_account_id_from_seed::("Alice")), - }, + sudo: rococo_runtime::SudoConfig { key: Some(Keyring::Alice.to_account_id()) }, configuration: rococo_runtime::ConfigurationConfig { config: get_host_config() }, registrar: rococo_runtime::RegistrarConfig { next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID, 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 b9f12932b84e..f8d43cf4648d 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,15 +77,14 @@ pub fn genesis() -> Storage { ) }) .collect::>(), + ..Default::default() }, staking: westend_runtime::StakingConfig { validator_count: validators::initial_authorities().len() as u32, minimum_validator_count: 1, stakers: validators::initial_authorities() .iter() - .map(|x| { - (x.0.clone(), x.1.clone(), STASH, westend_runtime::StakerStatus::Validator) - }) + .map(|x| (x.0.clone(), x.1.clone(), STASH, pallet_staking::StakerStatus::Validator)) .collect(), invulnerables: validators::initial_authorities().iter().map(|x| x.0.clone()).collect(), force_era: pallet_staking::Forcing::ForceNone, diff --git a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml index 7152f1dbc272..23edaf6bfe65 100644 --- a/cumulus/parachains/integration-tests/emulated/common/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/common/Cargo.toml @@ -21,6 +21,7 @@ sp-runtime = { workspace = true, default-features = true } frame-support = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-consensus-babe = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } pallet-assets = { workspace = true, default-features = true } pallet-balances = { workspace = true, default-features = true } pallet-message-queue = { workspace = true, default-features = true } @@ -42,5 +43,7 @@ asset-test-utils = { workspace = true, default-features = true } # Bridges bp-messages = { workspace = true, default-features = true } +bp-xcm-bridge-hub = { workspace = true, default-features = true } pallet-bridge-messages = { workspace = true, default-features = true } +pallet-xcm-bridge-hub = { workspace = true, default-features = true } bridge-runtime-common = { workspace = true, default-features = true } diff --git a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs index 8f2789eb2f3a..c0d42cf2758e 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/impls.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/impls.rs @@ -17,7 +17,8 @@ pub use codec::{Decode, Encode}; pub use paste; pub use crate::{ - xcm_helpers::xcm_transact_unpaid_execution, PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, + xcm_helpers::{xcm_transact_paid_execution, xcm_transact_unpaid_execution}, + PROOF_SIZE_THRESHOLD, REF_TIME_THRESHOLD, }; // Substrate @@ -30,7 +31,6 @@ pub use frame_support::{ pub use pallet_assets; pub use pallet_message_queue; pub use pallet_xcm; -use sp_core::Get; // Polkadot pub use polkadot_runtime_parachains::{ @@ -38,7 +38,9 @@ pub use polkadot_runtime_parachains::{ inclusion::{AggregateMessageOrigin, UmpQueueId}, }; pub use xcm::{ - prelude::{Location, OriginKind, Outcome, VersionedXcm, XcmError, XcmVersion}, + prelude::{ + Asset, InteriorLocation, Location, OriginKind, Outcome, VersionedXcm, XcmError, XcmVersion, + }, DoubleEncoded, }; @@ -51,7 +53,7 @@ pub use cumulus_primitives_core::{ }; pub use parachains_common::{AccountId, Balance}; pub use xcm_emulator::{ - assert_expected_events, bx, helpers::weight_within_threshold, BridgeMessage, + assert_expected_events, bx, helpers::weight_within_threshold, BridgeLaneId, BridgeMessage, BridgeMessageDispatchError, BridgeMessageHandler, Chain, Network, Parachain, RelayChain, TestExt, }; @@ -59,62 +61,62 @@ pub use xcm_emulator::{ // Bridges use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, - LaneId, MessageKey, OutboundLaneData, + MessageKey, OutboundLaneData, }; -use bridge_runtime_common::messages_xcm_extension::XcmBlobMessageDispatchResult; -use pallet_bridge_messages::{Config, OutboundLanes, Pallet}; +pub use bp_xcm_bridge_hub::XcmBridgeHubCall; +use pallet_bridge_messages::{Config as BridgeMessagesConfig, LaneIdOf, OutboundLanes, Pallet}; pub use pallet_bridge_messages::{ Instance1 as BridgeMessagesInstance1, Instance2 as BridgeMessagesInstance2, Instance3 as BridgeMessagesInstance3, }; +use pallet_xcm_bridge_hub::XcmBlobMessageDispatchResult; pub struct BridgeHubMessageHandler { _marker: std::marker::PhantomData<(S, SI, T, TI)>, } -struct LaneIdWrapper(LaneId); - -impl From for u32 { - fn from(lane_id: LaneIdWrapper) -> u32 { - u32::from_be_bytes(lane_id.0 .0) +struct LaneIdWrapper(LaneId); +impl From> for BridgeLaneId { + fn from(lane_id: LaneIdWrapper) -> BridgeLaneId { + lane_id.0.encode() } } - -impl From for LaneIdWrapper { - fn from(id: u32) -> LaneIdWrapper { - LaneIdWrapper(LaneId(id.to_be_bytes())) +impl From for LaneIdWrapper { + fn from(id: BridgeLaneId) -> LaneIdWrapper { + LaneIdWrapper(LaneId::decode(&mut &id[..]).expect("decodable")) } } impl BridgeMessageHandler for BridgeHubMessageHandler where - S: Config, + S: BridgeMessagesConfig, SI: 'static, - T: Config, + T: BridgeMessagesConfig, TI: 'static, - >::InboundPayload: From>, - >::MessageDispatch: + >::InboundPayload: From>, + >::MessageDispatch: MessageDispatch, { fn get_source_outbound_messages() -> Vec { // get the source active outbound lanes - let active_lanes = S::ActiveOutboundLanes::get(); + let active_outbound_lanes = OutboundLanes::::iter_keys(); let mut messages: Vec = Default::default(); // collect messages from `OutboundMessages` for each active outbound lane in the source - for lane in active_lanes { - let latest_generated_nonce = OutboundLanes::::get(lane).latest_generated_nonce; - let latest_received_nonce = OutboundLanes::::get(lane).latest_received_nonce; + for lane in active_outbound_lanes { + let latest_generated_nonce = + OutboundLanes::::get(lane).unwrap().latest_generated_nonce; + let latest_received_nonce = + OutboundLanes::::get(lane).unwrap().latest_received_nonce; (latest_received_nonce + 1..=latest_generated_nonce).for_each(|nonce| { - let encoded_payload: Vec = Pallet::::outbound_message_data(*lane, nonce) + let encoded_payload: Vec = Pallet::::outbound_message_data(lane, nonce) .expect("Bridge message does not exist") .into(); let payload = Vec::::decode(&mut &encoded_payload[..]) .expect("Decoding XCM message failed"); - let id: u32 = LaneIdWrapper(*lane).into(); - let message = BridgeMessage { id, nonce, payload }; + let message = BridgeMessage { lane_id: LaneIdWrapper(lane).into(), nonce, payload }; messages.push(message); }); @@ -125,10 +127,10 @@ where fn dispatch_target_inbound_message( message: BridgeMessage, ) -> Result<(), BridgeMessageDispatchError> { - type TargetMessageDispatch = >::MessageDispatch; - type InboundPayload = >::InboundPayload; + type TargetMessageDispatch = >::MessageDispatch; + type InboundPayload = >::InboundPayload; - let lane_id = LaneIdWrapper::from(message.id).0; + let lane_id = LaneIdWrapper::from(message.lane_id).0; let nonce = message.nonce; let payload = Ok(From::from(message.payload)); @@ -151,15 +153,16 @@ where result } - fn notify_source_message_delivery(lane_id: u32) { - let data = OutboundLanes::::get(LaneIdWrapper::from(lane_id).0); + fn notify_source_message_delivery(lane_id: BridgeLaneId) { + let lane_id: LaneIdOf = LaneIdWrapper::from(lane_id).0; + let data = OutboundLanes::::get(lane_id).unwrap(); let new_data = OutboundLaneData { oldest_unpruned_nonce: data.oldest_unpruned_nonce + 1, latest_received_nonce: data.latest_received_nonce + 1, ..data }; - OutboundLanes::::insert(LaneIdWrapper::from(lane_id).0, new_data); + OutboundLanes::::insert(lane_id, new_data); } } @@ -925,3 +928,49 @@ macro_rules! impl_xcm_helpers_for_parachain { } } } + +#[macro_export] +macro_rules! impl_bridge_helpers_for_chain { + ( $chain:ident, $pallet:ident, $pallet_xcm:ident, $runtime_call_wrapper:path ) => { + $crate::impls::paste::paste! { + impl $chain { + /// Open bridge with `dest`. + pub fn open_bridge( + bridge_location: $crate::impls::Location, + bridge_destination_universal_location: $crate::impls::InteriorLocation, + maybe_paid: Option<($crate::impls::Asset, $crate::impls::AccountId)> + ) { + ::execute_with(|| { + use $crate::impls::{bx, Chain}; + use $crate::impls::XcmBridgeHubCall; + use $crate::impls::Encode; + + // important to use `root` and `OriginKind::Xcm` + let root_origin = ::RuntimeOrigin::root(); + + // construct call + let call: $crate::impls::DoubleEncoded<()> = $runtime_call_wrapper(XcmBridgeHubCall::open_bridge { + bridge_destination_universal_location: bx!( + bridge_destination_universal_location.clone().into() + ) + }).encode().into(); + + let xcm = if let Some((fee_asset, beneficiary)) = maybe_paid { + $crate::impls::xcm_transact_paid_execution(call, $crate::impls::OriginKind::Xcm, fee_asset, beneficiary) + } else { + $crate::impls::xcm_transact_unpaid_execution(call, $crate::impls::OriginKind::Xcm) + }; + + // Send XCM `Transact` with `open_bridge` call + $crate::impls::assert_ok!(]>::$pallet_xcm::send( + root_origin, + bx!(bridge_location.into()), + bx!(xcm), + )); + Self::assert_xcm_pallet_sent(); + }); + } + } + } + } +} diff --git a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs index 7077fbbb0a9a..07fde111d3dc 100644 --- a/cumulus/parachains/integration-tests/emulated/common/src/lib.rs +++ b/cumulus/parachains/integration-tests/emulated/common/src/lib.rs @@ -25,11 +25,9 @@ use sc_consensus_grandpa::AuthorityId as GrandpaId; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; use sp_consensus_beefy::ecdsa_crypto::AuthorityId as BeefyId; -use sp_core::{sr25519, storage::Storage, Pair, Public}; -use sp_runtime::{ - traits::{AccountIdConversion, IdentifyAccount, Verify}, - BuildStorage, MultiSignature, -}; +use sp_core::storage::Storage; +use sp_keyring::{Ed25519Keyring, Sr25519Keyring}; +use sp_runtime::{traits::AccountIdConversion, BuildStorage}; // Polakdot use parachains_common::BlockNumber; @@ -49,8 +47,6 @@ pub const PROOF_SIZE_THRESHOLD: u64 = 33; /// The default XCM version to set in genesis config. pub const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; -type AccountPublic = ::Signer; - // (trust-backed) Asset registered on AH and reserve-transferred between Parachain and AH pub const RESERVABLE_ASSET_ID: u32 = 1; // ForeignAsset registered on AH and teleported between Penpal and AH @@ -60,32 +56,26 @@ pub const TELEPORTABLE_ASSET_ID: u32 = 2; pub const USDT_ID: u32 = 1984; pub const PENPAL_ID: u32 = 2000; +pub const PENPAL_B_ID: u32 = 2001; 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(); -} - -/// Helper function to generate a crypto pair from seed -pub fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() -} - -/// Helper function to generate an account ID from seed. -pub fn get_account_id_from_seed(seed: &str) -> AccountId -where - AccountPublic: From<::Public>, -{ - AccountPublic::from(get_from_seed::(seed)).into_account() + pub PenpalBTeleportableAssetLocation: xcm::v4::Location + = xcm::v4::Location::new(1, [ + xcm::v4::Junction::Parachain(PENPAL_B_ID), + xcm::v4::Junction::PalletInstance(ASSETS_PALLET_ID), + xcm::v4::Junction::GeneralIndex(TELEPORTABLE_ASSET_ID.into()), + ] + ); + pub PenpalBSiblingSovereignAccount: AccountId = Sibling::from(PENPAL_B_ID).into_account_truncating(); } pub fn get_host_config() -> HostConfiguration { @@ -121,33 +111,10 @@ pub mod accounts { use super::*; pub const ALICE: &str = "Alice"; pub const BOB: &str = "Bob"; - pub const CHARLIE: &str = "Charlie"; - pub const DAVE: &str = "Dave"; - pub const EVE: &str = "Eve"; - pub const FERDIE: &str = "Ferdie"; - pub const ALICE_STASH: &str = "Alice//stash"; - pub const BOB_STASH: &str = "Bob//stash"; - pub const CHARLIE_STASH: &str = "Charlie//stash"; - pub const DAVE_STASH: &str = "Dave//stash"; - 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![ - get_account_id_from_seed::(ALICE), - get_account_id_from_seed::(BOB), - get_account_id_from_seed::(CHARLIE), - get_account_id_from_seed::(DAVE), - get_account_id_from_seed::(EVE), - get_account_id_from_seed::(FERDIE), - get_account_id_from_seed::(ALICE_STASH), - get_account_id_from_seed::(BOB_STASH), - get_account_id_from_seed::(CHARLIE_STASH), - get_account_id_from_seed::(DAVE_STASH), - get_account_id_from_seed::(EVE_STASH), - get_account_id_from_seed::(FERDIE_STASH), - ] + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect() } } @@ -156,16 +123,15 @@ pub mod collators { pub fn invulnerables() -> Vec<(AccountId, AuraId)> { vec![ - ( - get_account_id_from_seed::("Alice"), - get_from_seed::("Alice"), - ), - (get_account_id_from_seed::("Bob"), get_from_seed::("Bob")), + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), ] } } pub mod validators { + use sp_consensus_beefy::test_utils::Keyring; + use super::*; pub fn initial_authorities() -> Vec<( @@ -178,16 +144,15 @@ pub mod validators { AuthorityDiscoveryId, BeefyId, )> { - let seed = "Alice"; vec![( - get_account_id_from_seed::(&format!("{}//stash", seed)), - get_account_id_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), + Sr25519Keyring::AliceStash.to_account_id(), + Sr25519Keyring::Alice.to_account_id(), + BabeId::from(Sr25519Keyring::Alice.public()), + GrandpaId::from(Ed25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Alice.public()), + AssignmentId::from(Sr25519Keyring::Alice.public()), + AuthorityDiscoveryId::from(Sr25519Keyring::Alice.public()), + BeefyId::from(Keyring::::Alice.public()), )] } } diff --git a/cumulus/parachains/integration-tests/emulated/common/src/macros.rs b/cumulus/parachains/integration-tests/emulated/common/src/macros.rs index 6f6bbe41e01b..68926b04bfe6 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,324 @@ 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); + }); + } + }; +} + +#[macro_export] +macro_rules! test_dry_run_transfer_across_pk_bridge { + ( $sender_asset_hub:ty, $sender_bridge_hub:ty, $destination:expr ) => { + $crate::macros::paste::paste! { + use frame_support::{dispatch::RawOrigin, traits::fungible}; + use sp_runtime::AccountId32; + use xcm::prelude::*; + use xcm_runtime_apis::dry_run::runtime_decl_for_dry_run_api::DryRunApiV1; + + let who = AccountId32::new([1u8; 32]); + let transfer_amount = 10_000_000_000_000u128; + let initial_balance = transfer_amount * 10; + + // Bridge setup. + $sender_asset_hub::force_xcm_version($destination, XCM_VERSION); + open_bridge_between_asset_hub_rococo_and_asset_hub_westend(); + + <$sender_asset_hub as TestExt>::execute_with(|| { + type Runtime = <$sender_asset_hub as Chain>::Runtime; + type RuntimeCall = <$sender_asset_hub as Chain>::RuntimeCall; + type OriginCaller = <$sender_asset_hub as Chain>::OriginCaller; + type Balances = <$sender_asset_hub as [<$sender_asset_hub Pallet>]>::Balances; + + // Give some initial funds. + >::set_balance(&who, initial_balance); + + let call = RuntimeCall::PolkadotXcm(pallet_xcm::Call::transfer_assets { + dest: Box::new(VersionedLocation::from($destination)), + beneficiary: Box::new(VersionedLocation::from(Junction::AccountId32 { + id: who.clone().into(), + network: None, + })), + assets: Box::new(VersionedAssets::from(vec![ + (Parent, transfer_amount).into(), + ])), + fee_asset_item: 0, + weight_limit: Unlimited, + }); + let result = Runtime::dry_run_call(OriginCaller::system(RawOrigin::Signed(who)), call).unwrap(); + // We assert the dry run succeeds and sends only one message to the local bridge hub. + assert!(result.execution_result.is_ok()); + assert_eq!(result.forwarded_xcms.len(), 1); + assert_eq!(result.forwarded_xcms[0].0, VersionedLocation::from(Location::new(1, [Parachain($sender_bridge_hub::para_id().into())]))); + }); + } + }; +} 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 25e1cffad543..7a289a3f1ac6 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 298be7362ec3..864f3c6edd7e 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 70f23ef8260c..53808bc5a801 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 37c14aa30352..cec2e3733b2a 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 9fbc773bc50e..6949a985629d 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 b4579da94cbf..3d40db6b03ab 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 @@ -16,6 +16,7 @@ assert_matches = { workspace = true } # Substrate sp-runtime = { workspace = true } +sp-core = { workspace = true } frame-support = { workspace = true } pallet-balances = { workspace = true } pallet-assets = { workspace = true } @@ -28,6 +29,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 f00945926963..12f440fdefee 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,23 +35,29 @@ mod imports { // Cumulus pub use asset_test_utils::xcm_helpers; pub use emulated_integration_tests_common::{ - test_parachain_is_trusted_teleporter, + accounts::DUMMY_EMPTY, + 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; pub use rococo_system_emulated_network::{ asset_hub_rococo_emulated_chain::{ asset_hub_rococo_runtime::{ + self, xcm_config::{ self as ahr_xcm_config, TokenLocation as RelayLocation, XcmConfig as AssetHubRococoXcmConfig, }, AssetConversionOrigin as AssetHubRococoAssetConversionOrigin, + ExistentialDeposit as AssetHubRococoExistentialDeposit, }, genesis::{AssetHubRococoAssetOwner, ED as ASSET_HUB_ROCOCO_ED}, AssetHubRococoParaPallet as AssetHubRococoPallet, @@ -61,6 +67,7 @@ mod imports { CustomizableAssetFromSystemAssetHub as PenpalCustomizableAssetFromSystemAssetHub, LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub, LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub, + UsdtFromAssetHub as PenpalUsdtFromAssetHub, }, PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner, PenpalBParaPallet as PenpalBPallet, ED as PENPAL_ED, @@ -87,7 +94,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 000000000000..99b31aba4be0 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/claim_assets.rs @@ -0,0 +1,29 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Tests related to claiming assets trapped during XCM execution. + +use crate::imports::*; + +use emulated_integration_tests_common::test_chain_can_claim_assets; +use xcm_executor::traits::DropAssets; + +#[test] +fn assets_can_be_claimed() { + let amount = AssetHubRococoExistentialDeposit::get(); + let assets: Assets = (Parent, amount).into(); + + test_chain_can_claim_assets!(AssetHubRococo, RuntimeCall, NetworkId::Rococo, assets, amount); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/hybrid_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/hybrid_transfers.rs index 7ff6d6c193c9..7bb25d7cec62 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/hybrid_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-rococo/src/tests/hybrid_transfers.rs @@ -449,7 +449,16 @@ fn transfer_foreign_assets_from_para_to_para_through_asset_hub() { let sov_of_receiver_on_ah = AssetHubRococo::sovereign_account_id_of(receiver_as_seen_by_ah); let wnd_to_send = ASSET_HUB_ROCOCO_ED * 10_000_000; - // Configure destination chain to trust AH as reserve of WND + // Configure source and destination chains to trust AH as reserve of WND + PenpalA::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), + Location::new(2, [GlobalConsensus(Westend)]).encode(), + )], + )); + }); PenpalB::execute_with(|| { assert_ok!(::System::set_storage( ::RuntimeOrigin::root(), 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 138ce419757b..88fa379c4072 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 8b9fedcd4947..302f71f89f83 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 @@ -14,6 +14,7 @@ // limitations under the License. use crate::imports::*; +use sp_core::{crypto::get_public_from_string_or_panic, sr25519}; fn relay_to_para_sender_assertions(t: RelayToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -60,10 +61,10 @@ pub fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { AssetHubRococo::assert_xcm_pallet_attempted_complete(None); let sov_acc_of_dest = AssetHubRococo::sovereign_account_id_of(t.args.dest.clone()); - for (idx, asset) in t.args.assets.into_inner().into_iter().enumerate() { + for asset in t.args.assets.into_inner().into_iter() { let expected_id = asset.id.0.clone().try_into().unwrap(); let asset_amount = if let Fungible(a) = asset.fun { Some(a) } else { None }.unwrap(); - if idx == t.args.fee_asset_item as usize { + if asset.id == AssetId(Location::new(1, [])) { assert_expected_events!( AssetHubRococo, vec![ @@ -77,6 +78,23 @@ pub fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { }, ] ); + } else if matches!( + asset.id.0.unpack(), + (0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(_)]) + ) { + assert_expected_events!( + AssetHubRococo, + vec![ + // Amount of trust-backed asset is transferred to Parachain's Sovereign account + RuntimeEvent::Assets( + pallet_assets::Event::Transferred { from, to, amount, .. }, + ) => { + from: *from == t.sender.account_id, + to: *to == sov_acc_of_dest, + amount: *amount == asset_amount, + }, + ] + ); } else { assert_expected_events!( AssetHubRococo, @@ -388,6 +406,38 @@ pub fn para_to_para_through_hop_sender_assertions(t: Test::RuntimeEvent; + let sov_penpal_a_on_ah = AssetHubRococo::sovereign_account_id_of( + AssetHubRococo::sibling_location_of(PenpalA::para_id()), + ); + let sov_penpal_b_on_ah = AssetHubRococo::sovereign_account_id_of( + AssetHubRococo::sibling_location_of(PenpalB::para_id()), + ); + + assert_expected_events!( + AssetHubRococo, + vec![ + // Withdrawn from sender parachain SA + RuntimeEvent::Assets( + pallet_assets::Event::Burned { owner, balance, .. } + ) => { + owner: *owner == sov_penpal_a_on_ah, + balance: *balance == t.args.amount, + }, + // Deposited to receiver parachain SA + RuntimeEvent::Assets( + pallet_assets::Event::Deposited { who, .. } + ) => { + who: *who == sov_penpal_b_on_ah, + }, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); +} + fn para_to_para_relay_hop_assertions(t: ParaToParaThroughRelayTest) { type RuntimeEvent = ::RuntimeEvent; let sov_penpal_a_on_rococo = @@ -469,6 +519,19 @@ fn system_para_to_para_reserve_transfer_assets(t: SystemParaToParaTest) -> Dispa ) } +fn para_to_para_through_asset_hub_limited_reserve_transfer_assets( + t: ParaToParaThroughAHTest, +) -> DispatchResult { + ::PolkadotXcm::limited_reserve_transfer_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 para_to_system_para_reserve_transfer_assets(t: ParaToSystemParaTest) -> DispatchResult { ::PolkadotXcm::limited_reserve_transfer_assets( t.signed_origin, @@ -493,9 +556,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 +589,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 +754,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 +812,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 +831,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 +887,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 +1002,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 +1030,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 = AssetHubRococoReceiver::get(); + // Beneficiary is a new (empty) account + let receiver: sp_runtime::AccountId32 = + get_public_from_string_or_panic::(DUMMY_EMPTY).into(); + // 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 +1082,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 +1103,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(|| { @@ -1135,3 +1200,408 @@ fn reserve_transfer_native_asset_from_para_to_para_through_relay() { // Receiver's balance is increased assert!(receiver_assets_after > receiver_assets_before); } + +// ============================================================================ +// ==== Reserve Transfers USDT - AssetHub->Parachain - pay fees using pool ==== +// ============================================================================ +#[test] +fn reserve_transfer_usdt_from_asset_hub_to_para() { + let usdt_id = 1984u32; + let penpal_location = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let penpal_sov_account = AssetHubRococo::sovereign_account_id_of(penpal_location.clone()); + + // Create SA-of-Penpal-on-AHW with ED. + // This ED isn't reflected in any derivative in a PenpalA account. + AssetHubRococo::fund_accounts(vec![(penpal_sov_account.clone().into(), ASSET_HUB_ROCOCO_ED)]); + + let sender = AssetHubRococoSender::get(); + let receiver = PenpalAReceiver::get(); + let asset_amount_to_send = 1_000_000_000_000; + + AssetHubRococo::execute_with(|| { + use frame_support::traits::tokens::fungibles::Mutate; + type Assets = ::Assets; + assert_ok!(>::mint_into( + usdt_id.into(), + &AssetHubRococoSender::get(), + asset_amount_to_send + 10_000_000_000_000, // Make sure it has enough. + )); + }); + + let relay_asset_penpal_pov = RelayLocation::get(); + + let usdt_from_asset_hub = PenpalUsdtFromAssetHub::get(); + + // Setup the pool between `relay_asset_penpal_pov` and `usdt_from_asset_hub` on PenpalA. + // So we can swap the custom asset that comes from AssetHubRococo for native asset to pay for + // fees. + PenpalA::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_ok!(::ForeignAssets::mint( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + usdt_from_asset_hub.clone().into(), + PenpalASender::get().into(), + 10_000_000_000_000, // For it to have more than enough. + )); + + assert_ok!(::AssetConversion::create_pool( + ::RuntimeOrigin::signed(PenpalASender::get()), + Box::new(relay_asset_penpal_pov.clone()), + Box::new(usdt_from_asset_hub.clone()), + )); + + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, + ] + ); + + assert_ok!(::AssetConversion::add_liquidity( + ::RuntimeOrigin::signed(PenpalASender::get()), + Box::new(relay_asset_penpal_pov), + Box::new(usdt_from_asset_hub.clone()), + // `usdt_from_asset_hub` is worth a third of `relay_asset_penpal_pov` + 1_000_000_000_000, + 3_000_000_000_000, + 0, + 0, + PenpalASender::get().into() + )); + + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded { .. }) => {}, + ] + ); + }); + + let assets: Assets = vec![( + [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(usdt_id.into())], + asset_amount_to_send, + ) + .into()] + .into(); + + let test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + penpal_location, + receiver.clone(), + asset_amount_to_send, + assets, + None, + 0, + ), + }; + let mut test = SystemParaToParaTest::new(test_args); + + let sender_initial_balance = AssetHubRococo::execute_with(|| { + type Assets = ::Assets; + >::balance(usdt_id, &sender) + }); + let sender_initial_native_balance = AssetHubRococo::execute_with(|| { + type Balances = ::Balances; + Balances::free_balance(&sender) + }); + let receiver_initial_balance = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(usdt_from_asset_hub.clone(), &receiver) + }); + + test.set_assertion::(system_para_to_para_sender_assertions); + test.set_assertion::(system_para_to_para_receiver_assertions); + test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); + test.assert(); + + let sender_after_balance = AssetHubRococo::execute_with(|| { + type Assets = ::Assets; + >::balance(usdt_id, &sender) + }); + let sender_after_native_balance = AssetHubRococo::execute_with(|| { + type Balances = ::Balances; + Balances::free_balance(&sender) + }); + let receiver_after_balance = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(usdt_from_asset_hub, &receiver) + }); + + // TODO(https://github.com/paritytech/polkadot-sdk/issues/5160): When we allow payment with different assets locally, this should be the same, since + // they aren't used for fees. + assert!(sender_after_native_balance < sender_initial_native_balance); + // Sender account's balance decreases. + assert_eq!(sender_after_balance, sender_initial_balance - asset_amount_to_send); + // Receiver account's balance increases. + assert!(receiver_after_balance > receiver_initial_balance); + assert!(receiver_after_balance < receiver_initial_balance + asset_amount_to_send); +} + +// =================================================================================== +// == Reserve Transfers USDT - Parachain->AssetHub->Parachain - pay fees using pool == +// =================================================================================== +// +// Transfer USDT From Penpal A to Penpal B with AssetHub as the reserve, while paying fees using +// USDT by making use of existing USDT pools on AssetHub and destination. +#[test] +fn reserve_transfer_usdt_from_para_to_para_through_asset_hub() { + let destination = PenpalA::sibling_location_of(PenpalB::para_id()); + let sender = PenpalASender::get(); + let asset_amount_to_send: Balance = ROCOCO_ED * 10000; + let fee_amount_to_send: Balance = ROCOCO_ED * 10000; + let sender_chain_as_seen_by_asset_hub = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let sov_of_sender_on_asset_hub = + AssetHubRococo::sovereign_account_id_of(sender_chain_as_seen_by_asset_hub); + let receiver_as_seen_by_asset_hub = AssetHubRococo::sibling_location_of(PenpalB::para_id()); + let sov_of_receiver_on_asset_hub = + AssetHubRococo::sovereign_account_id_of(receiver_as_seen_by_asset_hub); + + // Create SA-of-Penpal-on-AHW with ED. + // This ED isn't reflected in any derivative in a PenpalA account. + AssetHubRococo::fund_accounts(vec![ + (sov_of_sender_on_asset_hub.clone().into(), ASSET_HUB_ROCOCO_ED), + (sov_of_receiver_on_asset_hub.clone().into(), ASSET_HUB_ROCOCO_ED), + ]); + + // Give USDT to sov account of sender. + let usdt_id = 1984; + AssetHubRococo::execute_with(|| { + use frame_support::traits::tokens::fungibles::Mutate; + type Assets = ::Assets; + assert_ok!(>::mint_into( + usdt_id.into(), + &sov_of_sender_on_asset_hub.clone().into(), + asset_amount_to_send + fee_amount_to_send, + )); + }); + + // We create a pool between WND and USDT in AssetHub. + let native_asset: Location = Parent.into(); + let usdt = Location::new( + 0, + [Junction::PalletInstance(ASSETS_PALLET_ID), Junction::GeneralIndex(usdt_id.into())], + ); + + // set up pool with USDT <> native pair + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_ok!(::Assets::mint( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), + usdt_id.into(), + AssetHubRococoSender::get().into(), + 10_000_000_000_000, // For it to have more than enough. + )); + + assert_ok!(::AssetConversion::create_pool( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), + Box::new(native_asset.clone()), + Box::new(usdt.clone()), + )); + + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, + ] + ); + + assert_ok!(::AssetConversion::add_liquidity( + ::RuntimeOrigin::signed(AssetHubRococoSender::get()), + Box::new(native_asset), + Box::new(usdt), + 1_000_000_000_000, + 2_000_000_000_000, // usdt is worth half of `native_asset` + 0, + 0, + AssetHubRococoSender::get().into() + )); + + assert_expected_events!( + AssetHubRococo, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded { .. }) => {}, + ] + ); + }); + + let usdt_from_asset_hub = PenpalUsdtFromAssetHub::get(); + + // We also need a pool between WND and USDT on PenpalB. + PenpalB::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + let relay_asset = RelayLocation::get(); + + assert_ok!(::ForeignAssets::mint( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + usdt_from_asset_hub.clone().into(), + PenpalBReceiver::get().into(), + 10_000_000_000_000, // For it to have more than enough. + )); + + assert_ok!(::AssetConversion::create_pool( + ::RuntimeOrigin::signed(PenpalBReceiver::get()), + Box::new(relay_asset.clone()), + Box::new(usdt_from_asset_hub.clone()), + )); + + assert_expected_events!( + PenpalB, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, + ] + ); + + assert_ok!(::AssetConversion::add_liquidity( + ::RuntimeOrigin::signed(PenpalBReceiver::get()), + Box::new(relay_asset), + Box::new(usdt_from_asset_hub.clone()), + 1_000_000_000_000, + 2_000_000_000_000, // `usdt_from_asset_hub` is worth half of `relay_asset` + 0, + 0, + PenpalBReceiver::get().into() + )); + + assert_expected_events!( + PenpalB, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded { .. }) => {}, + ] + ); + }); + + PenpalA::execute_with(|| { + use frame_support::traits::tokens::fungibles::Mutate; + type ForeignAssets = ::ForeignAssets; + assert_ok!(>::mint_into( + usdt_from_asset_hub.clone(), + &sender, + asset_amount_to_send + fee_amount_to_send, + )); + }); + + // Prepare assets to transfer. + let assets: Assets = + (usdt_from_asset_hub.clone(), asset_amount_to_send + fee_amount_to_send).into(); + // Just to be very specific we're not including anything other than USDT. + assert_eq!(assets.len(), 1); + + // Give the sender enough Relay tokens to pay for local delivery fees. + // TODO(https://github.com/paritytech/polkadot-sdk/issues/5160): When we support local delivery fee payment in other assets, we don't need this. + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + RelayLocation::get(), + sender.clone(), + 10_000_000_000_000, // Large estimate to make sure it works. + ); + + // Init values for Parachain Destination + let receiver = PenpalBReceiver::get(); + + // Init Test + let fee_asset_index = 0; + let test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + destination, + receiver.clone(), + asset_amount_to_send, + assets, + None, + fee_asset_index, + ), + }; + let mut test = ParaToParaThroughAHTest::new(test_args); + + // Query initial balances + let sender_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(usdt_from_asset_hub.clone(), &sender) + }); + let receiver_assets_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(usdt_from_asset_hub.clone(), &receiver) + }); + test.set_assertion::(para_to_para_through_hop_sender_assertions); + test.set_assertion::(para_to_para_asset_hub_hop_assertions); + test.set_assertion::(para_to_para_through_hop_receiver_assertions); + test.set_dispatchable::( + para_to_para_through_asset_hub_limited_reserve_transfer_assets, + ); + test.assert(); + + // Query final balances + let sender_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(usdt_from_asset_hub.clone(), &sender) + }); + let receiver_assets_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(usdt_from_asset_hub, &receiver) + }); + + // Sender's balance is reduced by amount + assert!(sender_assets_after < sender_assets_before - asset_amount_to_send); + // Receiver's balance is increased + assert!(receiver_assets_after > receiver_assets_before); +} + +/// Reserve Withdraw Native Asset from AssetHub to Parachain fails. +#[test] +fn reserve_withdraw_from_untrusted_reserve_fails() { + // Init values for Parachain Origin + let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let signed_origin = + ::RuntimeOrigin::signed(AssetHubRococoSender::get().into()); + let roc_to_send: Balance = ROCOCO_ED * 10000; + let roc_location = RelayLocation::get(); + + // Assets to send + let assets: Vec = vec![(roc_location.clone(), roc_to_send).into()]; + let fee_id: AssetId = roc_location.into(); + + // this should fail + AssetHubRococo::execute_with(|| { + let result = ::PolkadotXcm::transfer_assets_using_type_and_then( + signed_origin.clone(), + bx!(destination.clone().into()), + bx!(assets.clone().into()), + bx!(TransferType::DestinationReserve), + bx!(fee_id.into()), + bx!(TransferType::DestinationReserve), + bx!(VersionedXcm::from(Xcm::<()>::new())), + Unlimited, + ); + assert_err!( + result, + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [22, 0, 0, 0], + message: Some("InvalidAssetUnsupportedReserve") + }) + ); + }); + + // this should also fail + AssetHubRococo::execute_with(|| { + let xcm: Xcm = Xcm(vec![ + WithdrawAsset(assets.into()), + InitiateReserveWithdraw { + assets: Wild(All), + reserve: destination, + xcm: Xcm::<()>::new(), + }, + ]); + let result = ::PolkadotXcm::execute( + signed_origin, + bx!(xcm::VersionedXcm::V4(xcm)), + Weight::MAX, + ); + assert!(result.is_err()); + }); +} 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 364fbd0d439f..29eaa9694643 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 16e0512da960..ac0c90ba198d 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 f74378d7631a..470b4d0f389e 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(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; +fn teleport_from_and_to_relay() { + let amount = ROCOCO_ED * 100; + let native_asset: Assets = (Here, amount).into(); - 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 @@ -390,7 +265,9 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { 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.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest + ) }); // Sender's balance is reduced @@ -399,19 +276,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( @@ -665,3 +529,54 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { system_para_to_para_transfer_assets, ); } + +/// Teleport Native Asset from AssetHub to Parachain fails. +#[test] +fn teleport_to_untrusted_chain_fails() { + // Init values for Parachain Origin + let destination = AssetHubRococo::sibling_location_of(PenpalA::para_id()); + let signed_origin = + ::RuntimeOrigin::signed(AssetHubRococoSender::get().into()); + let roc_to_send: Balance = ROCOCO_ED * 10000; + let roc_location = RelayLocation::get(); + + // Assets to send + let assets: Vec = vec![(roc_location.clone(), roc_to_send).into()]; + let fee_id: AssetId = roc_location.into(); + + // this should fail + AssetHubRococo::execute_with(|| { + let result = ::PolkadotXcm::transfer_assets_using_type_and_then( + signed_origin.clone(), + bx!(destination.clone().into()), + bx!(assets.clone().into()), + bx!(TransferType::Teleport), + bx!(fee_id.into()), + bx!(TransferType::Teleport), + bx!(VersionedXcm::from(Xcm::<()>::new())), + Unlimited, + ); + assert_err!( + result, + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [2, 0, 0, 0], + message: Some("Filtered") + }) + ); + }); + + // this should also fail + AssetHubRococo::execute_with(|| { + let xcm: Xcm = Xcm(vec![ + WithdrawAsset(assets.into()), + InitiateTeleport { assets: Wild(All), dest: destination, xcm: Xcm::<()>::new() }, + ]); + let result = ::PolkadotXcm::execute( + signed_origin, + bx!(xcm::VersionedXcm::V4(xcm)), + Weight::MAX, + ); + assert!(result.is_err()); + }); +} 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 f8190e11c51c..3320392b495d 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 000000000000..aa0e183ecdda --- /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/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml index 6b50b6f473ed..872a8ffa6a8a 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/Cargo.toml @@ -16,7 +16,6 @@ assert_matches = { workspace = true } # Substrate sp-runtime = { workspace = true } -sp-keyring = { workspace = true } sp-core = { workspace = true } frame-metadata-hash-extension = { workspace = true, default-features = true } frame-support = { workspace = true } 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 db8ada3f4ea2..906768b19b79 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,32 +26,35 @@ 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, + 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}; pub use westend_system_emulated_network::{ asset_hub_westend_emulated_chain::{ asset_hub_westend_runtime::{ + self, xcm_config::{ self as ahw_xcm_config, WestendLocation as RelayLocation, XcmConfig as AssetHubWestendXcmConfig, }, AssetConversionOrigin as AssetHubWestendAssetConversionOrigin, + ExistentialDeposit as AssetHubWestendExistentialDeposit, }, genesis::{AssetHubWestendAssetOwner, ED as ASSET_HUB_WESTEND_ED}, AssetHubWestendParaPallet as AssetHubWestendPallet, @@ -62,6 +65,7 @@ mod imports { CustomizableAssetFromSystemAssetHub as PenpalCustomizableAssetFromSystemAssetHub, LocalReservableFromAssetHub as PenpalLocalReservableFromAssetHub, LocalTeleportableToAssetHub as PenpalLocalTeleportableToAssetHub, + UsdtFromAssetHub as PenpalUsdtFromAssetHub, }, PenpalAParaPallet as PenpalAPallet, PenpalAssetOwner, PenpalBParaPallet as PenpalBPallet, @@ -87,7 +91,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 000000000000..de58839634f1 --- /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 15f4fe33bddc..9520659712fc 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/hybrid_transfers.rs b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/hybrid_transfers.rs index 49dfe8d58394..4d6cdd9a94d6 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/hybrid_transfers.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/assets/asset-hub-westend/src/tests/hybrid_transfers.rs @@ -450,7 +450,16 @@ fn transfer_foreign_assets_from_para_to_para_through_asset_hub() { let sov_of_receiver_on_ah = AssetHubWestend::sovereign_account_id_of(receiver_as_seen_by_ah); let roc_to_send = ASSET_HUB_WESTEND_ED * 10_000_000; - // Configure destination chain to trust AH as reserve of ROC + // Configure source and destination chains to trust AH as reserve of ROC + PenpalA::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), + Location::new(2, [GlobalConsensus(Rococo)]).encode(), + )], + )); + }); PenpalB::execute_with(|| { assert_ok!(::System::set_storage( ::RuntimeOrigin::root(), @@ -613,10 +622,10 @@ fn transfer_foreign_assets_from_para_to_para_through_asset_hub() { >::balance(roc_at_westend_parachains, &receiver) }); - // Sender's balance is reduced by amount sent plus delivery fees + // Sender's balance is reduced by amount sent. assert!(sender_wnds_after < sender_wnds_before - wnd_to_send); assert_eq!(sender_rocs_after, sender_rocs_before - roc_to_send); - // Sovereign accounts on reserve are changed accordingly + // Sovereign accounts on reserve are changed accordingly. assert_eq!( wnds_in_sender_reserve_on_ah_after, wnds_in_sender_reserve_on_ah_before - wnd_to_send @@ -630,7 +639,7 @@ fn transfer_foreign_assets_from_para_to_para_through_asset_hub() { rocs_in_receiver_reserve_on_ah_after, rocs_in_receiver_reserve_on_ah_before + roc_to_send ); - // Receiver's balance is increased + // Receiver's balance is increased by amount sent minus delivery fees. assert!(receiver_wnds_after > receiver_wnds_before); assert_eq!(receiver_rocs_after, receiver_rocs_before + roc_to_send); } 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 61eb70524fc9..73b73b239a1b 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 65d013a0eec4..10c27c338ec7 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 @@ -14,6 +14,7 @@ // limitations under the License. use crate::imports::*; +use sp_core::{crypto::get_public_from_string_or_panic, sr25519}; fn relay_to_para_sender_assertions(t: RelayToParaTest) { type RuntimeEvent = ::RuntimeEvent; @@ -60,10 +61,10 @@ pub fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { AssetHubWestend::assert_xcm_pallet_attempted_complete(None); let sov_acc_of_dest = AssetHubWestend::sovereign_account_id_of(t.args.dest.clone()); - for (idx, asset) in t.args.assets.into_inner().into_iter().enumerate() { + for asset in t.args.assets.into_inner().into_iter() { let expected_id = asset.id.0.clone().try_into().unwrap(); let asset_amount = if let Fungible(a) = asset.fun { Some(a) } else { None }.unwrap(); - if idx == t.args.fee_asset_item as usize { + if asset.id == AssetId(Location::new(1, [])) { assert_expected_events!( AssetHubWestend, vec![ @@ -77,6 +78,23 @@ pub fn system_para_to_para_sender_assertions(t: SystemParaToParaTest) { }, ] ); + } else if matches!( + asset.id.0.unpack(), + (0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(_)]) + ) { + assert_expected_events!( + AssetHubWestend, + vec![ + // Amount of trust-backed asset is transferred to Parachain's Sovereign account + RuntimeEvent::Assets( + pallet_assets::Event::Transferred { from, to, amount, .. }, + ) => { + from: *from == t.sender.account_id, + to: *to == sov_acc_of_dest, + amount: *amount == asset_amount, + }, + ] + ); } else { assert_expected_events!( AssetHubWestend, @@ -418,6 +436,38 @@ fn para_to_para_relay_hop_assertions(t: ParaToParaThroughRelayTest) { ); } +fn para_to_para_asset_hub_hop_assertions(t: ParaToParaThroughAHTest) { + type RuntimeEvent = ::RuntimeEvent; + let sov_penpal_a_on_ah = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalA::para_id()), + ); + let sov_penpal_b_on_ah = AssetHubWestend::sovereign_account_id_of( + AssetHubWestend::sibling_location_of(PenpalB::para_id()), + ); + + assert_expected_events!( + AssetHubWestend, + vec![ + // Withdrawn from sender parachain SA + RuntimeEvent::Assets( + pallet_assets::Event::Burned { owner, balance, .. } + ) => { + owner: *owner == sov_penpal_a_on_ah, + balance: *balance == t.args.amount, + }, + // Deposited to receiver parachain SA + RuntimeEvent::Assets( + pallet_assets::Event::Deposited { who, .. } + ) => { + who: *who == sov_penpal_b_on_ah, + }, + RuntimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); +} + pub fn para_to_para_through_hop_receiver_assertions(t: Test) { type RuntimeEvent = ::RuntimeEvent; @@ -493,9 +543,22 @@ 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 +fn para_to_para_through_asset_hub_limited_reserve_transfer_assets( + t: ParaToParaThroughAHTest, +) -> DispatchResult { + ::PolkadotXcm::limited_reserve_transfer_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, + ) +} + +/// 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 +589,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 +754,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 +812,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 +831,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 +888,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 +1003,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 +1031,25 @@ 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: sp_runtime::AccountId32 = + get_public_from_string_or_panic::(DUMMY_EMPTY).into(); + // 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 +1084,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 +1105,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(|| { @@ -1132,8 +1197,415 @@ fn reserve_transfer_native_asset_from_para_to_para_through_relay() { >::balance(relay_native_asset_location, &receiver) }); - // Sender's balance is reduced by amount sent plus delivery fees + // Sender's balance is reduced by amount sent plus delivery fees. assert!(sender_assets_after < sender_assets_before - amount_to_send); + // Receiver's balance is increased by `amount_to_send` minus delivery fees. + assert!(receiver_assets_after > receiver_assets_before); + assert!(receiver_assets_after < receiver_assets_before + amount_to_send); +} + +// ============================================================================ +// ==== Reserve Transfers USDT - AssetHub->Parachain - pay fees using pool ==== +// ============================================================================ +#[test] +fn reserve_transfer_usdt_from_asset_hub_to_para() { + let usdt_id = 1984u32; + let penpal_location = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let penpal_sov_account = AssetHubWestend::sovereign_account_id_of(penpal_location.clone()); + + // Create SA-of-Penpal-on-AHW with ED. + // This ED isn't reflected in any derivative in a PenpalA account. + AssetHubWestend::fund_accounts(vec![(penpal_sov_account.clone().into(), ASSET_HUB_WESTEND_ED)]); + + let sender = AssetHubWestendSender::get(); + let receiver = PenpalAReceiver::get(); + let asset_amount_to_send = 1_000_000_000_000; + + AssetHubWestend::execute_with(|| { + use frame_support::traits::tokens::fungibles::Mutate; + type Assets = ::Assets; + assert_ok!(>::mint_into( + usdt_id.into(), + &AssetHubWestendSender::get(), + asset_amount_to_send + 10_000_000_000_000, // Make sure it has enough. + )); + }); + + let relay_asset_penpal_pov = RelayLocation::get(); + + let usdt_from_asset_hub = PenpalUsdtFromAssetHub::get(); + + // Setup the pool between `relay_asset_penpal_pov` and `usdt_from_asset_hub` on PenpalA. + // So we can swap the custom asset that comes from AssetHubWestend for native asset to pay for + // fees. + PenpalA::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_ok!(::ForeignAssets::mint( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + usdt_from_asset_hub.clone().into(), + PenpalASender::get().into(), + 10_000_000_000_000, // For it to have more than enough. + )); + + assert_ok!(::AssetConversion::create_pool( + ::RuntimeOrigin::signed(PenpalASender::get()), + Box::new(relay_asset_penpal_pov.clone()), + Box::new(usdt_from_asset_hub.clone()), + )); + + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, + ] + ); + + assert_ok!(::AssetConversion::add_liquidity( + ::RuntimeOrigin::signed(PenpalASender::get()), + Box::new(relay_asset_penpal_pov), + Box::new(usdt_from_asset_hub.clone()), + // `usdt_from_asset_hub` is worth a third of `relay_asset_penpal_pov` + 1_000_000_000_000, + 3_000_000_000_000, + 0, + 0, + PenpalASender::get().into() + )); + + assert_expected_events!( + PenpalA, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded { .. }) => {}, + ] + ); + }); + + let assets: Assets = vec![( + [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(usdt_id.into())], + asset_amount_to_send, + ) + .into()] + .into(); + + let test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + penpal_location, + receiver.clone(), + asset_amount_to_send, + assets, + None, + 0, + ), + }; + let mut test = SystemParaToParaTest::new(test_args); + + let sender_initial_balance = AssetHubWestend::execute_with(|| { + type Assets = ::Assets; + >::balance(usdt_id, &sender) + }); + let sender_initial_native_balance = AssetHubWestend::execute_with(|| { + type Balances = ::Balances; + Balances::free_balance(&sender) + }); + let receiver_initial_balance = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(usdt_from_asset_hub.clone(), &receiver) + }); + + test.set_assertion::(system_para_to_para_sender_assertions); + test.set_assertion::(system_para_to_para_receiver_assertions); + test.set_dispatchable::(system_para_to_para_reserve_transfer_assets); + test.assert(); + + let sender_after_balance = AssetHubWestend::execute_with(|| { + type Assets = ::Assets; + >::balance(usdt_id, &sender) + }); + let sender_after_native_balance = AssetHubWestend::execute_with(|| { + type Balances = ::Balances; + Balances::free_balance(&sender) + }); + let receiver_after_balance = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(usdt_from_asset_hub, &receiver) + }); + + // TODO(https://github.com/paritytech/polkadot-sdk/issues/5160): When we allow payment with different assets locally, this should be the same, since + // they aren't used for fees. + assert!(sender_after_native_balance < sender_initial_native_balance); + // Sender account's balance decreases. + assert_eq!(sender_after_balance, sender_initial_balance - asset_amount_to_send); + // Receiver account's balance increases. + assert!(receiver_after_balance > receiver_initial_balance); + assert!(receiver_after_balance < receiver_initial_balance + asset_amount_to_send); +} + +// =================================================================================== +// == Reserve Transfers USDT - Parachain->AssetHub->Parachain - pay fees using pool == +// =================================================================================== +// +// Transfer USDT From Penpal A to Penpal B with AssetHub as the reserve, while paying fees using +// USDT by making use of existing USDT pools on AssetHub and destination. +#[test] +fn reserve_transfer_usdt_from_para_to_para_through_asset_hub() { + let destination = PenpalA::sibling_location_of(PenpalB::para_id()); + let sender = PenpalASender::get(); + let asset_amount_to_send: Balance = WESTEND_ED * 10000; + let fee_amount_to_send: Balance = WESTEND_ED * 10000; + let sender_chain_as_seen_by_asset_hub = + AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let sov_of_sender_on_asset_hub = + AssetHubWestend::sovereign_account_id_of(sender_chain_as_seen_by_asset_hub); + let receiver_as_seen_by_asset_hub = AssetHubWestend::sibling_location_of(PenpalB::para_id()); + let sov_of_receiver_on_asset_hub = + AssetHubWestend::sovereign_account_id_of(receiver_as_seen_by_asset_hub); + + // Create SA-of-Penpal-on-AHW with ED. + // This ED isn't reflected in any derivative in a PenpalA account. + AssetHubWestend::fund_accounts(vec![ + (sov_of_sender_on_asset_hub.clone().into(), ASSET_HUB_WESTEND_ED), + (sov_of_receiver_on_asset_hub.clone().into(), ASSET_HUB_WESTEND_ED), + ]); + + // Give USDT to sov account of sender. + let usdt_id = 1984; + AssetHubWestend::execute_with(|| { + use frame_support::traits::tokens::fungibles::Mutate; + type Assets = ::Assets; + assert_ok!(>::mint_into( + usdt_id.into(), + &sov_of_sender_on_asset_hub.clone().into(), + asset_amount_to_send + fee_amount_to_send, + )); + }); + + // We create a pool between WND and USDT in AssetHub. + let native_asset: Location = Parent.into(); + let usdt = Location::new( + 0, + [Junction::PalletInstance(ASSETS_PALLET_ID), Junction::GeneralIndex(usdt_id.into())], + ); + + // set up pool with USDT <> native pair + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + + assert_ok!(::Assets::mint( + ::RuntimeOrigin::signed(AssetHubWestendSender::get()), + usdt_id.into(), + AssetHubWestendSender::get().into(), + 10_000_000_000_000, // For it to have more than enough. + )); + + assert_ok!(::AssetConversion::create_pool( + ::RuntimeOrigin::signed(AssetHubWestendSender::get()), + Box::new(native_asset.clone()), + Box::new(usdt.clone()), + )); + + assert_expected_events!( + AssetHubWestend, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, + ] + ); + + assert_ok!(::AssetConversion::add_liquidity( + ::RuntimeOrigin::signed(AssetHubWestendSender::get()), + Box::new(native_asset), + Box::new(usdt), + 1_000_000_000_000, + 2_000_000_000_000, // usdt is worth half of `native_asset` + 0, + 0, + AssetHubWestendSender::get().into() + )); + + assert_expected_events!( + AssetHubWestend, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded { .. }) => {}, + ] + ); + }); + + let usdt_from_asset_hub = PenpalUsdtFromAssetHub::get(); + + // We also need a pool between WND and USDT on PenpalB. + PenpalB::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + let relay_asset = RelayLocation::get(); + + assert_ok!(::ForeignAssets::mint( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + usdt_from_asset_hub.clone().into(), + PenpalBReceiver::get().into(), + 10_000_000_000_000, // For it to have more than enough. + )); + + assert_ok!(::AssetConversion::create_pool( + ::RuntimeOrigin::signed(PenpalBReceiver::get()), + Box::new(relay_asset.clone()), + Box::new(usdt_from_asset_hub.clone()), + )); + + assert_expected_events!( + PenpalB, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::PoolCreated { .. }) => {}, + ] + ); + + assert_ok!(::AssetConversion::add_liquidity( + ::RuntimeOrigin::signed(PenpalBReceiver::get()), + Box::new(relay_asset), + Box::new(usdt_from_asset_hub.clone()), + 1_000_000_000_000, + 2_000_000_000_000, // `usdt_from_asset_hub` is worth half of `relay_asset` + 0, + 0, + PenpalBReceiver::get().into() + )); + + assert_expected_events!( + PenpalB, + vec![ + RuntimeEvent::AssetConversion(pallet_asset_conversion::Event::LiquidityAdded { .. }) => {}, + ] + ); + }); + + PenpalA::execute_with(|| { + use frame_support::traits::tokens::fungibles::Mutate; + type ForeignAssets = ::ForeignAssets; + assert_ok!(>::mint_into( + usdt_from_asset_hub.clone(), + &sender, + asset_amount_to_send + fee_amount_to_send, + )); + }); + + // Prepare assets to transfer. + let assets: Assets = + (usdt_from_asset_hub.clone(), asset_amount_to_send + fee_amount_to_send).into(); + // Just to be very specific we're not including anything other than USDT. + assert_eq!(assets.len(), 1); + + // Give the sender enough Relay tokens to pay for local delivery fees. + // TODO(https://github.com/paritytech/polkadot-sdk/issues/5160): When we support local delivery fee payment in other assets, we don't need this. + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + RelayLocation::get(), + sender.clone(), + 10_000_000_000_000, // Large estimate to make sure it works. + ); + + // Init values for Parachain Destination + let receiver = PenpalBReceiver::get(); + + // Init Test + let fee_asset_index = 0; + let test_args = TestContext { + sender: sender.clone(), + receiver: receiver.clone(), + args: TestArgs::new_para( + destination, + receiver.clone(), + asset_amount_to_send, + assets, + None, + fee_asset_index, + ), + }; + let mut test = ParaToParaThroughAHTest::new(test_args); + + // Query initial balances + let sender_assets_before = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(usdt_from_asset_hub.clone(), &sender) + }); + let receiver_assets_before = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(usdt_from_asset_hub.clone(), &receiver) + }); + test.set_assertion::(para_to_para_through_hop_sender_assertions); + test.set_assertion::(para_to_para_asset_hub_hop_assertions); + test.set_assertion::(para_to_para_through_hop_receiver_assertions); + test.set_dispatchable::( + para_to_para_through_asset_hub_limited_reserve_transfer_assets, + ); + test.assert(); + + // Query final balances + let sender_assets_after = PenpalA::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(usdt_from_asset_hub.clone(), &sender) + }); + let receiver_assets_after = PenpalB::execute_with(|| { + type ForeignAssets = ::ForeignAssets; + >::balance(usdt_from_asset_hub, &receiver) + }); + + // Sender's balance is reduced by amount + assert!(sender_assets_after < sender_assets_before - asset_amount_to_send); // Receiver's balance is increased assert!(receiver_assets_after > receiver_assets_before); } + +/// Reserve Withdraw Native Asset from AssetHub to Parachain fails. +#[test] +fn reserve_withdraw_from_untrusted_reserve_fails() { + // Init values for Parachain Origin + let destination = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let signed_origin = + ::RuntimeOrigin::signed(AssetHubWestendSender::get().into()); + let roc_to_send: Balance = WESTEND_ED * 10000; + let roc_location = RelayLocation::get(); + + // Assets to send + let assets: Vec = vec![(roc_location.clone(), roc_to_send).into()]; + let fee_id: AssetId = roc_location.into(); + + // this should fail + AssetHubWestend::execute_with(|| { + let result = ::PolkadotXcm::transfer_assets_using_type_and_then( + signed_origin.clone(), + bx!(destination.clone().into()), + bx!(assets.clone().into()), + bx!(TransferType::DestinationReserve), + bx!(fee_id.into()), + bx!(TransferType::DestinationReserve), + bx!(VersionedXcm::from(Xcm::<()>::new())), + Unlimited, + ); + assert_err!( + result, + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [22, 0, 0, 0], + message: Some("InvalidAssetUnsupportedReserve") + }) + ); + }); + + // this should also fail + AssetHubWestend::execute_with(|| { + let xcm: Xcm = Xcm(vec![ + WithdrawAsset(assets.into()), + InitiateReserveWithdraw { + assets: Wild(All), + reserve: destination, + xcm: Xcm::<()>::new(), + }, + ]); + let result = ::PolkadotXcm::execute( + signed_origin, + bx!(xcm::VersionedXcm::V4(xcm)), + Weight::MAX, + ); + assert!(result.is_err()); + }); +} 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 eb0e985cc0ce..761c7c12255c 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 cf429378cf6d..1a2821452155 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 a524b87b2daf..ee0f297792f8 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(); - - let sender_balance_after = test.sender.balance; - let receiver_balance_after = test.receiver.balance; +fn teleport_from_and_to_relay() { + let amount = WESTEND_ED * 100; + let native_asset: Assets = (Here, amount).into(); - 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 @@ -390,7 +265,9 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { 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.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest + ) }); // Sender's balance is reduced @@ -399,19 +276,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( @@ -668,3 +532,54 @@ fn bidirectional_teleport_foreign_assets_between_para_and_asset_hub() { system_para_to_para_transfer_assets, ); } + +/// Teleport Native Asset from AssetHub to Parachain fails. +#[test] +fn teleport_to_untrusted_chain_fails() { + // Init values for Parachain Origin + let destination = AssetHubWestend::sibling_location_of(PenpalA::para_id()); + let signed_origin = + ::RuntimeOrigin::signed(AssetHubWestendSender::get().into()); + let roc_to_send: Balance = WESTEND_ED * 10000; + let roc_location = RelayLocation::get(); + + // Assets to send + let assets: Vec = vec![(roc_location.clone(), roc_to_send).into()]; + let fee_id: AssetId = roc_location.into(); + + // this should fail + AssetHubWestend::execute_with(|| { + let result = ::PolkadotXcm::transfer_assets_using_type_and_then( + signed_origin.clone(), + bx!(destination.clone().into()), + bx!(assets.clone().into()), + bx!(TransferType::Teleport), + bx!(fee_id.into()), + bx!(TransferType::Teleport), + bx!(VersionedXcm::from(Xcm::<()>::new())), + Unlimited, + ); + assert_err!( + result, + DispatchError::Module(sp_runtime::ModuleError { + index: 31, + error: [2, 0, 0, 0], + message: Some("Filtered") + }) + ); + }); + + // this should also fail + AssetHubWestend::execute_with(|| { + let xcm: Xcm = Xcm(vec![ + WithdrawAsset(assets.into()), + InitiateTeleport { assets: Wild(All), dest: destination, xcm: Xcm::<()>::new() }, + ]); + let result = ::PolkadotXcm::execute( + signed_origin, + bx!(xcm::VersionedXcm::V4(xcm)), + Weight::MAX, + ); + assert!(result.is_err()); + }); +} 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 8cbce3e0d223..b70967184387 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 c01aa7825336..037d6604ea4d 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/Cargo.toml b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml index a5787885329d..9f6fe78a33ee 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/Cargo.toml @@ -28,9 +28,11 @@ sp-runtime = { workspace = true } xcm = { workspace = true } pallet-xcm = { workspace = true } xcm-executor = { workspace = true } +xcm-runtime-apis = { workspace = true } # Bridges pallet-bridge-messages = { workspace = true } +pallet-xcm-bridge-hub = { workspace = true } # Cumulus cumulus-pallet-xcmp-queue = { workspace = true } @@ -38,7 +40,7 @@ emulated-integration-tests-common = { workspace = true } parachains-common = { workspace = true, default-features = true } rococo-system-emulated-network = { workspace = true } rococo-westend-system-emulated-network = { workspace = true } -testnet-parachains-constants = { features = ["rococo"], workspace = true, default-features = true } +testnet-parachains-constants = { features = ["rococo", "westend"], workspace = true, default-features = true } # Snowbridge snowbridge-core = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/lib.rs index 04466a611c71..77e4c8183e65 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 @@ -16,6 +16,7 @@ #[cfg(test)] mod imports { // Substrate + pub use codec::Encode; pub use frame_support::{assert_err, assert_ok, pallet_prelude::DispatchResult}; pub use sp_runtime::DispatchError; @@ -23,7 +24,7 @@ mod imports { pub use xcm::{ latest::ParentThen, prelude::{AccountId32 as AccountId32Junction, *}, - v3::{self, NetworkId::Westend as WestendId}, + v4::{self, NetworkId::Westend as WestendId}, }; pub use xcm_executor::traits::TransferType; @@ -31,45 +32,55 @@ mod imports { pub use emulated_integration_tests_common::{ accounts::ALICE, impls::Inspect, - test_parachain_is_trusted_teleporter, + test_dry_run_transfer_across_pk_bridge, 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, }, + xcm_helpers::xcm_transact_paid_execution, ASSETS_PALLET_ID, USDT_ID, }; pub use parachains_common::AccountId; pub use rococo_westend_system_emulated_network::{ asset_hub_rococo_emulated_chain::{ asset_hub_rococo_runtime::xcm_config as ahr_xcm_config, - genesis::{AssetHubRococoAssetOwner, ED as ASSET_HUB_ROCOCO_ED}, - AssetHubRococoParaPallet as AssetHubRococoPallet, + genesis::ED as ASSET_HUB_ROCOCO_ED, AssetHubRococoParaPallet as AssetHubRococoPallet, }, asset_hub_westend_emulated_chain::{ - genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet, + genesis::{AssetHubWestendAssetOwner, 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, }, penpal_emulated_chain::{ - penpal_runtime::xcm_config::{ - CustomizableAssetFromSystemAssetHub as PenpalCustomizableAssetFromSystemAssetHub, - UniversalLocation as PenpalUniversalLocation, + penpal_runtime::{ + self, + xcm_config::{ + CustomizableAssetFromSystemAssetHub as PenpalCustomizableAssetFromSystemAssetHub, + UniversalLocation as PenpalUniversalLocation, + }, }, 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, + PenpalAParaSender as PenpalASender, RococoRelay as Rococo, + RococoRelayReceiver as RococoReceiver, RococoRelaySender as RococoSender, }; + pub const ASSET_ID: u32 = 1; 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 6053936487b2..0e1cfdd82aaf 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 @@ -25,6 +25,9 @@ fn send_assets_over_bridge(send_fn: F) { AssetHubRococo::force_xcm_version(asset_hub_westend_location(), XCM_VERSION); BridgeHubRococo::force_xcm_version(bridge_hub_westend_location(), XCM_VERSION); + // open bridge + open_bridge_between_asset_hub_rococo_and_asset_hub_westend(); + // send message over bridge send_fn(); @@ -36,10 +39,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); @@ -110,26 +113,17 @@ fn send_assets_from_penpal_rococo_through_rococo_ah_to_westend_ah( } #[test] -/// Test transfer of ROC, USDT and wETH from AssetHub Rococo to AssetHub Westend. -/// -/// This mix of assets should cover the whole range: -/// - native assets: ROC, -/// - trust-based assets: USDT (exists only on Rococo, Westend gets it from Rococo over bridge), -/// - foreign asset / bridged asset (other bridge / Snowfork): wETH (bridged from Ethereum to Rococo -/// over Snowbridge, then bridged over to Westend through this bridge). -fn send_roc_usdt_and_weth_from_asset_hub_rococo_to_asset_hub_westend() { +/// Test transfer of ROC from AssetHub Rococo to AssetHub Westend. +fn send_roc_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(), true); - //////////////////////////////////////////////////////////// - // Let's first send over just some ROCs as a simple example - //////////////////////////////////////////////////////////// let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( Westend, AssetHubWestend::para_id(), @@ -138,12 +132,12 @@ 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 = (roc_at_asset_hub_rococo.clone(), amount).into(); let fee_idx = 0; assert_ok!(send_assets_from_asset_hub_rococo(destination, assets, fee_idx)); }); @@ -179,88 +173,29 @@ fn send_roc_usdt_and_weth_from_asset_hub_rococo_to_asset_hub_westend() { assert!(receiver_rocs_after > receiver_rocs_before); // Reserve ROC balance is increased by sent amount assert_eq!(rocs_in_reserve_on_ahr_after, rocs_in_reserve_on_ahr_before + amount); - - ///////////////////////////////////////////////////////////// - // Now let's send over USDTs + wETH (and pay fees with USDT) - ///////////////////////////////////////////////////////////// - - let usdt_at_asset_hub_rococo = usdt_at_ah_rococo(); - let bridged_usdt_at_asset_hub_westend = bridged_usdt_at_ah_westend().try_into().unwrap(); - // wETH has same relative location on both Rococo and Westend AssetHubs - let bridged_weth_at_ah = weth_at_asset_hubs().try_into().unwrap(); - - // mint USDT in sender's account (USDT already created in genesis) - AssetHubRococo::mint_asset( - ::RuntimeOrigin::signed(AssetHubRococoAssetOwner::get()), - USDT_ID, - sender.clone(), - amount * 2, - ); - // create wETH at src and dest and prefund sender's account - create_foreign_on_ah_rococo(bridged_weth_at_ah, true, vec![(sender.clone(), amount * 2)]); - create_foreign_on_ah_westend(bridged_weth_at_ah, true); - create_foreign_on_ah_westend(bridged_usdt_at_asset_hub_westend, true); - set_up_pool_with_wnd_on_ah_westend(bridged_usdt_at_asset_hub_westend); - - let receiver_usdts_before = - foreign_balance_on_ah_westend(bridged_usdt_at_asset_hub_westend, &receiver); - let receiver_weth_before = foreign_balance_on_ah_westend(bridged_weth_at_ah, &receiver); - - // send USDTs and wETHs - let assets: Assets = vec![ - (usdt_at_asset_hub_rococo.clone(), amount).into(), - (Location::try_from(bridged_weth_at_ah).unwrap(), amount).into(), - ] - .into(); - // use USDT for fees - let fee: AssetId = usdt_at_asset_hub_rococo.into(); - - // use the more involved transfer extrinsic - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(assets.len() as u32)), - beneficiary: AccountId32Junction { network: None, id: receiver.clone().into() }.into(), - }]); - assert_ok!(AssetHubRococo::execute_with(|| { - ::PolkadotXcm::transfer_assets_using_type_and_then( - ::RuntimeOrigin::signed(sender.into()), - bx!(asset_hub_westend_location().into()), - bx!(assets.into()), - bx!(TransferType::LocalReserve), - bx!(fee.into()), - bx!(TransferType::LocalReserve), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - WeightLimit::Unlimited, - ) - })); - // verify hops (also advances the message through the hops) - assert_bridge_hub_rococo_message_accepted(true); - assert_bridge_hub_westend_message_received(); - AssetHubWestend::execute_with(|| { - AssetHubWestend::assert_xcmp_queue_success(None); - }); - - let receiver_usdts_after = - foreign_balance_on_ah_westend(bridged_usdt_at_asset_hub_westend, &receiver); - let receiver_weth_after = foreign_balance_on_ah_westend(bridged_weth_at_ah, &receiver); - - // Receiver's USDT balance is increased by almost `amount` (minus fees) - assert!(receiver_usdts_after > receiver_usdts_before); - assert!(receiver_usdts_after < receiver_usdts_before + amount); - // Receiver's wETH balance is increased by sent amount - assert_eq!(receiver_weth_after, receiver_weth_before + amount); } #[test] -/// Send bridged WNDs "back" from AssetHub Rococo to AssetHub Westend. -fn send_back_wnds_from_asset_hub_rococo_to_asset_hub_westend() { +/// Send bridged assets "back" from AssetHub Rococo to AssetHub Westend. +/// +/// This mix of assets should cover the whole range: +/// - bridged native assets: ROC, +/// - bridged trust-based assets: USDT (exists only on Westend, Rococo gets it from Westend over +/// bridge), +/// - bridged foreign asset / double-bridged asset (other bridge / Snowfork): wETH (bridged from +/// Ethereum to Westend over Snowbridge, then bridged over to Rococo through this bridge). +fn send_back_wnds_usdt_and_weth_from_asset_hub_rococo_to_asset_hub_westend() { let prefund_amount = 10_000_000_000_000u128; let amount_to_send = ASSET_HUB_WESTEND_ED * 1_000; let sender = AssetHubRococoSender::get(); let receiver = AssetHubWestendReceiver::get(); let wnd_at_asset_hub_rococo = bridged_wnd_at_ah_rococo(); - let wnd_at_asset_hub_rococo_v3 = wnd_at_asset_hub_rococo.clone().try_into().unwrap(); let prefund_accounts = vec![(sender.clone(), prefund_amount)]; - create_foreign_on_ah_rococo(wnd_at_asset_hub_rococo_v3, true, prefund_accounts); + create_foreign_on_ah_rococo(wnd_at_asset_hub_rococo.clone(), true, prefund_accounts); + + //////////////////////////////////////////////////////////// + // Let's first send back just some WNDs as a simple example + //////////////////////////////////////////////////////////// // 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 +208,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,8 +244,8 @@ 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 receiver_wnds_after = ::account_data_of(receiver).free; + let sender_wnds_after = foreign_balance_on_ah_rococo(wnd_at_asset_hub_rococo, &sender); + let receiver_wnds_after = ::account_data_of(receiver.clone()).free; let wnds_in_reserve_on_ahw_after = ::account_data_of(sov_ahr_on_ahw).free; @@ -320,6 +255,96 @@ fn send_back_wnds_from_asset_hub_rococo_to_asset_hub_westend() { assert!(receiver_wnds_after > receiver_wnds_before); // Reserve balance is reduced by sent amount assert_eq!(wnds_in_reserve_on_ahw_after, wnds_in_reserve_on_ahw_before - amount_to_send); + + ////////////////////////////////////////////////////////////////// + // Now let's send back over USDTs + wETH (and pay fees with USDT) + ////////////////////////////////////////////////////////////////// + + // wETH has same relative location on both Westend and Rococo AssetHubs + let bridged_weth_at_ah = weth_at_asset_hubs(); + let bridged_usdt_at_asset_hub_rococo = bridged_usdt_at_ah_rococo(); + + // set up destination chain AH Westend: + // create a WND/USDT pool to be able to pay fees with USDT (USDT created in genesis) + set_up_pool_with_wnd_on_ah_westend(usdt_at_ah_westend(), false); + // create wETH on Westend (IRL it's already created by Snowbridge) + create_foreign_on_ah_westend(bridged_weth_at_ah.clone(), true); + // prefund AHR's sovereign account on AHW to be able to withdraw USDT and wETH from reserves + let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( + Rococo, + AssetHubRococo::para_id(), + ); + AssetHubWestend::mint_asset( + ::RuntimeOrigin::signed(AssetHubWestendAssetOwner::get()), + USDT_ID, + sov_ahr_on_ahw.clone(), + amount_to_send * 2, + ); + AssetHubWestend::mint_foreign_asset( + ::RuntimeOrigin::signed(AssetHubWestend::account_id_of(ALICE)), + bridged_weth_at_ah.clone(), + sov_ahr_on_ahw, + amount_to_send * 2, + ); + + // set up source chain AH Rococo: + // create wETH and USDT foreign assets on Rococo and prefund sender's account + let prefund_accounts = vec![(sender.clone(), amount_to_send * 2)]; + create_foreign_on_ah_rococo(bridged_weth_at_ah.clone(), true, prefund_accounts.clone()); + create_foreign_on_ah_rococo(bridged_usdt_at_asset_hub_rococo.clone(), true, prefund_accounts); + + // check balances before + let receiver_usdts_before = AssetHubWestend::execute_with(|| { + type Assets = ::Assets; + >::balance(USDT_ID, &receiver) + }); + let receiver_weth_before = foreign_balance_on_ah_westend(bridged_weth_at_ah.clone(), &receiver); + + let usdt_id: AssetId = Location::try_from(bridged_usdt_at_asset_hub_rococo).unwrap().into(); + // send USDTs and wETHs + let assets: Assets = vec![ + (usdt_id.clone(), amount_to_send).into(), + (Location::try_from(bridged_weth_at_ah.clone()).unwrap(), amount_to_send).into(), + ] + .into(); + // use USDT for fees + let fee = usdt_id; + + // use the more involved transfer extrinsic + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(assets.len() as u32)), + beneficiary: AccountId32Junction { network: None, id: receiver.clone().into() }.into(), + }]); + assert_ok!(AssetHubRococo::execute_with(|| { + ::PolkadotXcm::transfer_assets_using_type_and_then( + ::RuntimeOrigin::signed(sender.into()), + bx!(asset_hub_westend_location().into()), + bx!(assets.into()), + bx!(TransferType::DestinationReserve), + bx!(fee.into()), + bx!(TransferType::DestinationReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), + WeightLimit::Unlimited, + ) + })); + // verify hops (also advances the message through the hops) + assert_bridge_hub_rococo_message_accepted(true); + assert_bridge_hub_westend_message_received(); + AssetHubWestend::execute_with(|| { + AssetHubWestend::assert_xcmp_queue_success(None); + }); + + let receiver_usdts_after = AssetHubWestend::execute_with(|| { + type Assets = ::Assets; + >::balance(USDT_ID, &receiver) + }); + let receiver_weth_after = foreign_balance_on_ah_westend(bridged_weth_at_ah, &receiver); + + // Receiver's USDT balance is increased by almost `amount_to_send` (minus fees) + assert!(receiver_usdts_after > receiver_usdts_before); + assert!(receiver_usdts_after < receiver_usdts_before + amount_to_send); + // Receiver's wETH balance is increased by `amount_to_send` + assert_eq!(receiver_weth_after, receiver_weth_before + amount_to_send); } #[test] @@ -341,7 +366,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 +398,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 +429,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 +441,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(), @@ -425,6 +450,16 @@ fn send_back_wnds_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_weste ASSET_MIN_BALANCE, vec![(sender.clone(), amount * 2)], ); + // Configure source Penpal chain to trust local AH as reserve of bridged WND + PenpalA::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), + wnd_at_rococo_parachains.encode(), + )], + )); + }); // 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( @@ -517,3 +552,12 @@ fn send_back_wnds_from_penpal_rococo_through_asset_hub_rococo_to_asset_hub_weste assert!(receiver_wnds_after > receiver_wnds_before); assert!(receiver_wnds_after <= receiver_wnds_before + amount); } + +#[test] +fn dry_run_transfer_to_westend_sends_xcm_to_bridge_hub() { + test_dry_run_transfer_across_pk_bridge!( + AssetHubRococo, + BridgeHubRococo, + asset_hub_westend_location() + ); +} 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 000000000000..e61dc35bdf8a --- /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 58c52e1328c8..767f74f6ad7f 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,8 @@ use crate::imports::*; mod asset_transfers; +mod claim_assets; +mod register_bridged_assets; mod send_xcm; mod snowbridge; mod teleport; @@ -35,21 +37,24 @@ pub(crate) fn bridged_roc_at_ah_westend() -> Location { Location::new(2, [GlobalConsensus(Rococo)]) } -// wWND +// WND and wWND +pub(crate) fn wnd_at_ah_westend() -> Location { + Parent.into() +} pub(crate) fn bridged_wnd_at_ah_rococo() -> Location { Location::new(2, [GlobalConsensus(Westend)]) } // USDT and wUSDT -pub(crate) fn usdt_at_ah_rococo() -> Location { +pub(crate) fn usdt_at_ah_westend() -> Location { Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into())]) } -pub(crate) fn bridged_usdt_at_ah_westend() -> Location { +pub(crate) fn bridged_usdt_at_ah_rococo() -> Location { Location::new( 2, [ - GlobalConsensus(Rococo), - Parachain(AssetHubRococo::para_id().into()), + GlobalConsensus(Westend), + Parachain(AssetHubWestend::para_id().into()), PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into()), ], @@ -68,7 +73,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 +82,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,23 +101,36 @@ 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(asset: v4::Location, is_foreign: bool) { + let wnd: v4::Location = v4::Parent.into(); AssetHubWestend::execute_with(|| { type RuntimeEvent = ::RuntimeEvent; let owner = AssetHubWestendSender::get(); let signed_owner = ::RuntimeOrigin::signed(owner.clone()); - assert_ok!(::ForeignAssets::mint( - signed_owner.clone(), - foreign_asset.into(), - owner.clone().into(), - 3_000_000_000_000, - )); + if is_foreign { + assert_ok!(::ForeignAssets::mint( + signed_owner.clone(), + asset.clone().into(), + owner.clone().into(), + 3_000_000_000_000, + )); + } else { + let asset_id = match asset.interior.last() { + Some(v4::Junction::GeneralIndex(id)) => *id as u32, + _ => unreachable!(), + }; + assert_ok!(::Assets::mint( + signed_owner.clone(), + asset_id.into(), + owner.clone().into(), + 3_000_000_000_000, + )); + } assert_ok!(::AssetConversion::create_pool( signed_owner.clone(), - Box::new(wnd), - Box::new(foreign_asset), + Box::new(wnd.clone()), + Box::new(asset.clone()), )); assert_expected_events!( AssetHubWestend, @@ -123,7 +141,7 @@ pub(crate) fn set_up_pool_with_wnd_on_ah_westend(foreign_asset: v3::Location) { assert_ok!(::AssetConversion::add_liquidity( signed_owner.clone(), Box::new(wnd), - Box::new(foreign_asset), + Box::new(asset), 1_000_000_000_000, 2_000_000_000_000, 1, @@ -145,7 +163,7 @@ pub(crate) fn send_assets_from_asset_hub_rococo( fee_idx: u32, ) -> DispatchResult { let signed_origin = - ::RuntimeOrigin::signed(AssetHubRococoSender::get().into()); + ::RuntimeOrigin::signed(AssetHubRococoSender::get()); let beneficiary: Location = AccountId32Junction { network: None, id: AssetHubWestendReceiver::get().into() }.into(); @@ -209,3 +227,35 @@ pub(crate) fn assert_bridge_hub_westend_message_received() { ); }) } + +pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() { + use testnet_parachains_constants::{ + rococo::currency::UNITS as ROC, westend::currency::UNITS as WND, + }; + + // open AHR -> AHW + BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), ROC * 5); + AssetHubRococo::open_bridge( + AssetHubRococo::sibling_location_of(BridgeHubRococo::para_id()), + [GlobalConsensus(Westend), Parachain(AssetHubWestend::para_id().into())].into(), + Some(( + (roc_at_ah_rococo(), ROC * 1).into(), + BridgeHubRococo::sovereign_account_id_of(BridgeHubRococo::sibling_location_of( + AssetHubRococo::para_id(), + )), + )), + ); + + // open AHW -> AHR + BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), WND * 5); + AssetHubWestend::open_bridge( + AssetHubWestend::sibling_location_of(BridgeHubWestend::para_id()), + [GlobalConsensus(Rococo), Parachain(AssetHubRococo::para_id().into())].into(), + Some(( + (wnd_at_ah_westend(), WND * 1).into(), + BridgeHubWestend::sovereign_account_id_of(BridgeHubWestend::sibling_location_of( + AssetHubWestend::para_id(), + )), + )), + ); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/register_bridged_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/register_bridged_assets.rs new file mode 100644 index 000000000000..44637670112b --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-rococo/src/tests/register_bridged_assets.rs @@ -0,0 +1,107 @@ +// 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::*, tests::*}; + +const XCM_FEE: u128 = 4_000_000_000_000; + +/// Tests the registering of a Rococo Asset as a bridged asset on Westend Asset Hub. +#[test] +fn register_rococo_asset_on_wah_from_rah() { + let sa_of_rah_on_wah = + AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( + Rococo, + AssetHubRococo::para_id(), + ); + + // Rococo Asset Hub asset when bridged to Westend Asset Hub. + let bridged_asset_at_wah = Location::new( + 2, + [ + GlobalConsensus(Rococo), + Parachain(AssetHubRococo::para_id().into()), + PalletInstance(ASSETS_PALLET_ID), + GeneralIndex(ASSET_ID.into()), + ], + ); + + // Encoded `create_asset` call to be executed in Westend Asset Hub ForeignAssets pallet. + let call = AssetHubWestend::create_foreign_asset_call( + bridged_asset_at_wah.clone(), + ASSET_MIN_BALANCE, + sa_of_rah_on_wah.clone(), + ); + + let origin_kind = OriginKind::Xcm; + let fee_amount = XCM_FEE; + let fees = (Parent, fee_amount).into(); + + let xcm = xcm_transact_paid_execution(call, origin_kind, fees, sa_of_rah_on_wah.clone()); + + // SA-of-RAH-on-WAH needs to have balance to pay for fees and asset creation deposit + AssetHubWestend::fund_accounts(vec![( + sa_of_rah_on_wah.clone(), + ASSET_HUB_WESTEND_ED * 10000000000, + )]); + + let destination = asset_hub_westend_location(); + + // fund the RAH's SA on RBH for paying bridge transport fees + BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), 10_000_000_000_000u128); + + // set XCM versions + AssetHubRococo::force_xcm_version(destination.clone(), XCM_VERSION); + BridgeHubRococo::force_xcm_version(bridge_hub_westend_location(), XCM_VERSION); + + let root_origin = ::RuntimeOrigin::root(); + AssetHubRococo::execute_with(|| { + assert_ok!(::PolkadotXcm::send( + root_origin, + bx!(destination.into()), + bx!(xcm), + )); + + AssetHubRococo::assert_xcm_pallet_sent(); + }); + + assert_bridge_hub_rococo_message_accepted(true); + assert_bridge_hub_westend_message_received(); + AssetHubWestend::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + AssetHubWestend::assert_xcmp_queue_success(None); + assert_expected_events!( + AssetHubWestend, + vec![ + // Burned the fee + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { + who: *who == sa_of_rah_on_wah.clone(), + amount: *amount == fee_amount, + }, + // Foreign Asset created + RuntimeEvent::ForeignAssets(pallet_assets::Event::Created { asset_id, creator, owner }) => { + asset_id: asset_id == &bridged_asset_at_wah, + creator: *creator == sa_of_rah_on_wah.clone(), + owner: *owner == sa_of_rah_on_wah, + }, + // Unspent fee minted to origin + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { + who: *who == sa_of_rah_on_wah.clone(), + }, + ] + ); + type ForeignAssets = ::ForeignAssets; + assert!(ForeignAssets::asset_exists(bridged_asset_at_wah)); + }); +} 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 652447fa5601..12f05742a080 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, }, @@ -79,6 +79,9 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { // fund sender AssetHubRococo::fund_accounts(vec![(AssetHubRococoSender::get().into(), amount * 10)]); + // open bridge + open_bridge_between_asset_hub_rococo_and_asset_hub_westend(); + // send XCM from AssetHubRococo - fails - destination version not known assert_err!( send_assets_from_asset_hub_rococo( 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 40a1968ec557..d91a0c6895f9 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 @@ -286,11 +286,19 @@ fn send_token_from_ethereum_to_penpal() { // Fund AssetHub sovereign account so it can pay execution fees for the asset transfer BridgeHubRococo::fund_accounts(vec![(asset_hub_sovereign.clone(), INITIAL_FUND)]); - // Fund PenPal sender and receiver - PenpalA::fund_accounts(vec![ - (PenpalAReceiver::get(), INITIAL_FUND), - (PenpalASender::get(), INITIAL_FUND), - ]); + // Fund PenPal receiver (covering ED) + let native_id: Location = Parent.into(); + let receiver: AccountId = [ + 28, 189, 45, 67, 83, 10, 68, 112, 90, 208, 136, 175, 49, 62, 24, 248, 11, 83, 239, 22, 179, + 97, 119, 205, 75, 119, 184, 70, 242, 165, 240, 124, + ] + .into(); + PenpalA::mint_foreign_asset( + ::RuntimeOrigin::signed(PenpalAssetOwner::get()), + native_id, + receiver, + penpal_runtime::EXISTENTIAL_DEPOSIT, + ); PenpalA::execute_with(|| { assert_ok!(::System::set_storage( @@ -560,7 +568,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 +676,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 1fb03748d926..8cdd9613dc52 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 6b83479eaf89..b87f25ac0f01 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,18 +22,32 @@ 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 xcm = { workspace = true } pallet-xcm = { workspace = true } xcm-executor = { workspace = true } +xcm-runtime-apis = { workspace = true } # Bridges pallet-bridge-messages = { workspace = true } +pallet-xcm-bridge-hub = { workspace = true } # Cumulus 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 = { features = ["rococo", "westend"], workspace = true, default-features = true } +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 3b0fcea57a26..76e8312921de 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 @@ -16,6 +16,7 @@ #[cfg(test)] mod imports { // Substrate + pub use codec::Encode; pub use frame_support::{assert_err, assert_ok, pallet_prelude::DispatchResult}; pub use sp_runtime::DispatchError; @@ -23,8 +24,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,39 +32,50 @@ mod imports { pub use emulated_integration_tests_common::{ accounts::ALICE, impls::Inspect, - test_parachain_is_trusted_teleporter, + test_dry_run_transfer_across_pk_bridge, 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, }, + xcm_helpers::xcm_transact_paid_execution, ASSETS_PALLET_ID, USDT_ID, }; pub use parachains_common::AccountId; pub use rococo_westend_system_emulated_network::{ asset_hub_rococo_emulated_chain::{ - genesis::{AssetHubRococoAssetOwner, ED as ASSET_HUB_ROCOCO_ED}, - AssetHubRococoParaPallet as AssetHubRococoPallet, + genesis::ED as ASSET_HUB_ROCOCO_ED, AssetHubRococoParaPallet as AssetHubRococoPallet, }, asset_hub_westend_emulated_chain::{ - genesis::ED as ASSET_HUB_WESTEND_ED, AssetHubWestendParaPallet as AssetHubWestendPallet, + genesis::{AssetHubWestendAssetOwner, 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, + penpal_runtime::xcm_config::{ + CustomizableAssetFromSystemAssetHub as PenpalCustomizableAssetFromSystemAssetHub, + 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_ID: u32 = 1; 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 0c0b04cd45a9..0856c9526009 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 @@ -24,6 +24,9 @@ fn send_assets_over_bridge(send_fn: F) { AssetHubWestend::force_xcm_version(asset_hub_rococo_location(), XCM_VERSION); BridgeHubWestend::force_xcm_version(bridge_hub_rococo_location(), XCM_VERSION); + // open bridge + open_bridge_between_asset_hub_rococo_and_asset_hub_westend(); + // send message over bridge send_fn(); @@ -35,10 +38,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); @@ -110,17 +113,26 @@ fn send_assets_from_penpal_westend_through_westend_ah_to_rococo_ah( } #[test] -/// Test transfer of WND from AssetHub Westend to AssetHub Rococo. -fn send_wnds_from_asset_hub_westend_to_asset_hub_rococo() { +/// Test transfer of WND, USDT and wETH from AssetHub Westend to AssetHub Rococo. +/// +/// This mix of assets should cover the whole range: +/// - native assets: WND, +/// - trust-based assets: USDT (exists only on Westend, Rococo gets it from Westend over bridge), +/// - foreign asset / bridged asset (other bridge / Snowfork): wETH (bridged from Ethereum to +/// Westend over Snowbridge, then bridged over to Rococo through this bridge). +fn send_wnds_usdt_and_weth_from_asset_hub_westend_to_asset_hub_rococo() { let amount = ASSET_HUB_WESTEND_ED * 1_000; let sender = AssetHubWestendSender::get(); let receiver = AssetHubRococoReceiver::get(); let wnd_at_asset_hub_westend = wnd_at_ah_westend(); - let bridged_wnd_at_asset_hub_rococo = bridged_wnd_at_ah_rococo().try_into().unwrap(); - create_foreign_on_ah_rococo(bridged_wnd_at_asset_hub_rococo, true); + let bridged_wnd_at_asset_hub_rococo = bridged_wnd_at_ah_rococo(); - set_up_pool_with_roc_on_ah_rococo(bridged_wnd_at_asset_hub_rococo, true); + 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.clone(), true); + //////////////////////////////////////////////////////////// + // Let's first send over just some WNDs as a simple example + //////////////////////////////////////////////////////////// let sov_ahr_on_ahw = AssetHubWestend::sovereign_account_of_parachain_on_other_global_consensus( Rococo, AssetHubRococo::para_id(), @@ -129,7 +141,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(|| { @@ -158,7 +170,7 @@ fn send_wnds_from_asset_hub_westend_to_asset_hub_rococo() { ); }); - let sender_wnds_after = ::account_data_of(sender).free; + let sender_wnds_after = ::account_data_of(sender.clone()).free; let receiver_wnds_after = foreign_balance_on_ah_rococo(bridged_wnd_at_asset_hub_rococo, &receiver); let wnds_in_reserve_on_ahw_after = @@ -170,31 +182,90 @@ fn send_wnds_from_asset_hub_westend_to_asset_hub_rococo() { assert!(receiver_wnds_after > receiver_wnds_before); // Reserve balance is increased by sent amount assert_eq!(wnds_in_reserve_on_ahw_after, wnds_in_reserve_on_ahw_before + amount); + + ///////////////////////////////////////////////////////////// + // Now let's send over USDTs + wETH (and pay fees with USDT) + ///////////////////////////////////////////////////////////// + let usdt_at_asset_hub_westend = usdt_at_ah_westend(); + let bridged_usdt_at_asset_hub_rococo = bridged_usdt_at_ah_rococo(); + // wETH has same relative location on both Westend and Rococo AssetHubs + let bridged_weth_at_ah = weth_at_asset_hubs(); + + // mint USDT in sender's account (USDT already created in genesis) + AssetHubWestend::mint_asset( + ::RuntimeOrigin::signed(AssetHubWestendAssetOwner::get()), + USDT_ID, + sender.clone(), + amount * 2, + ); + // create wETH at src and dest and prefund sender's account + create_foreign_on_ah_westend( + bridged_weth_at_ah.clone(), + true, + vec![(sender.clone(), amount * 2)], + ); + create_foreign_on_ah_rococo(bridged_weth_at_ah.clone(), true); + create_foreign_on_ah_rococo(bridged_usdt_at_asset_hub_rococo.clone(), true); + set_up_pool_with_roc_on_ah_rococo(bridged_usdt_at_asset_hub_rococo.clone(), true); + + let receiver_usdts_before = + foreign_balance_on_ah_rococo(bridged_usdt_at_asset_hub_rococo.clone(), &receiver); + let receiver_weth_before = foreign_balance_on_ah_rococo(bridged_weth_at_ah.clone(), &receiver); + + // send USDTs and wETHs + let assets: Assets = vec![ + (usdt_at_asset_hub_westend.clone(), amount).into(), + (Location::try_from(bridged_weth_at_ah.clone()).unwrap(), amount).into(), + ] + .into(); + // use USDT for fees + let fee: AssetId = usdt_at_asset_hub_westend.into(); + + // use the more involved transfer extrinsic + let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { + assets: Wild(AllCounted(assets.len() as u32)), + beneficiary: AccountId32Junction { network: None, id: receiver.clone().into() }.into(), + }]); + assert_ok!(AssetHubWestend::execute_with(|| { + ::PolkadotXcm::transfer_assets_using_type_and_then( + ::RuntimeOrigin::signed(sender.into()), + bx!(asset_hub_rococo_location().into()), + bx!(assets.into()), + bx!(TransferType::LocalReserve), + bx!(fee.into()), + bx!(TransferType::LocalReserve), + bx!(VersionedXcm::from(custom_xcm_on_dest)), + WeightLimit::Unlimited, + ) + })); + // verify hops (also advances the message through the hops) + assert_bridge_hub_westend_message_accepted(true); + assert_bridge_hub_rococo_message_received(); + AssetHubRococo::execute_with(|| { + AssetHubRococo::assert_xcmp_queue_success(None); + }); + + let receiver_usdts_after = + foreign_balance_on_ah_rococo(bridged_usdt_at_asset_hub_rococo, &receiver); + let receiver_weth_after = foreign_balance_on_ah_rococo(bridged_weth_at_ah, &receiver); + + // Receiver's USDT balance is increased by almost `amount` (minus fees) + assert!(receiver_usdts_after > receiver_usdts_before); + assert!(receiver_usdts_after < receiver_usdts_before + amount); + // Receiver's wETH balance is increased by sent amount + assert_eq!(receiver_weth_after, receiver_weth_before + amount); } #[test] -/// Send bridged assets "back" from AssetHub Rococo to AssetHub Westend. -/// -/// This mix of assets should cover the whole range: -/// - bridged native assets: ROC, -/// - bridged trust-based assets: USDT (exists only on Rococo, Westend gets it from Rococo over -/// bridge), -/// - bridged foreign asset / double-bridged asset (other bridge / Snowfork): wETH (bridged from -/// Ethereum to Rococo over Snowbridge, then bridged over to Westend through this bridge). -fn send_back_rocs_usdt_and_weth_from_asset_hub_westend_to_asset_hub_rococo() { +/// Send bridged ROCs "back" from AssetHub Westend to AssetHub Rococo. +fn send_back_rocs_from_asset_hub_westend_to_asset_hub_rococo() { let prefund_amount = 10_000_000_000_000u128; let amount_to_send = ASSET_HUB_ROCOCO_ED * 1_000; let sender = AssetHubWestendSender::get(); let receiver = AssetHubRococoReceiver::get(); let bridged_roc_at_asset_hub_westend = bridged_roc_at_ah_westend(); - let bridged_roc_at_asset_hub_westend_v3 = - bridged_roc_at_asset_hub_westend.clone().try_into().unwrap(); let prefund_accounts = vec![(sender.clone(), prefund_amount)]; - create_foreign_on_ah_westend(bridged_roc_at_asset_hub_westend_v3, true, prefund_accounts); - - //////////////////////////////////////////////////////////// - // Let's first send back just some ROCs as a simple example - //////////////////////////////////////////////////////////// + create_foreign_on_ah_westend(bridged_roc_at_asset_hub_westend.clone(), true, prefund_accounts); // 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( @@ -208,14 +279,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 +316,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; @@ -256,96 +327,6 @@ fn send_back_rocs_usdt_and_weth_from_asset_hub_westend_to_asset_hub_rococo() { assert!(receiver_rocs_after > receiver_rocs_before); // Reserve balance is reduced by sent amount assert_eq!(rocs_in_reserve_on_ahr_after, rocs_in_reserve_on_ahr_before - amount_to_send); - - ////////////////////////////////////////////////////////////////// - // Now let's send back over USDTs + wETH (and pay fees with USDT) - ////////////////////////////////////////////////////////////////// - - // wETH has same relative location on both Rococo and Westend AssetHubs - let bridged_weth_at_ah = weth_at_asset_hubs().try_into().unwrap(); - let bridged_usdt_at_asset_hub_westend = bridged_usdt_at_ah_westend().try_into().unwrap(); - - // set up destination chain AH Rococo: - // create a ROC/USDT pool to be able to pay fees with USDT (USDT created in genesis) - set_up_pool_with_roc_on_ah_rococo(usdt_at_ah_rococo().try_into().unwrap(), false); - // create wETH on Rococo (IRL it's already created by Snowbridge) - create_foreign_on_ah_rococo(bridged_weth_at_ah, true); - // prefund AHW's sovereign account on AHR to be able to withdraw USDT and wETH from reserves - let sov_ahw_on_ahr = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( - Westend, - AssetHubWestend::para_id(), - ); - AssetHubRococo::mint_asset( - ::RuntimeOrigin::signed(AssetHubRococoAssetOwner::get()), - USDT_ID, - sov_ahw_on_ahr.clone(), - amount_to_send * 2, - ); - AssetHubRococo::mint_foreign_asset( - ::RuntimeOrigin::signed(AssetHubRococo::account_id_of(ALICE)), - bridged_weth_at_ah, - sov_ahw_on_ahr, - amount_to_send * 2, - ); - - // set up source chain AH Westend: - // create wETH and USDT foreign assets on Westend and prefund sender's account - let prefund_accounts = vec![(sender.clone(), amount_to_send * 2)]; - create_foreign_on_ah_westend(bridged_weth_at_ah, true, prefund_accounts.clone()); - create_foreign_on_ah_westend(bridged_usdt_at_asset_hub_westend, true, prefund_accounts); - - // check balances before - let receiver_usdts_before = AssetHubRococo::execute_with(|| { - type Assets = ::Assets; - >::balance(USDT_ID, &receiver) - }); - let receiver_weth_before = foreign_balance_on_ah_rococo(bridged_weth_at_ah, &receiver); - - let usdt_id: AssetId = Location::try_from(bridged_usdt_at_asset_hub_westend).unwrap().into(); - // send USDTs and wETHs - let assets: Assets = vec![ - (usdt_id.clone(), amount_to_send).into(), - (Location::try_from(bridged_weth_at_ah).unwrap(), amount_to_send).into(), - ] - .into(); - // use USDT for fees - let fee = usdt_id; - - // use the more involved transfer extrinsic - let custom_xcm_on_dest = Xcm::<()>(vec![DepositAsset { - assets: Wild(AllCounted(assets.len() as u32)), - beneficiary: AccountId32Junction { network: None, id: receiver.clone().into() }.into(), - }]); - assert_ok!(AssetHubWestend::execute_with(|| { - ::PolkadotXcm::transfer_assets_using_type_and_then( - ::RuntimeOrigin::signed(sender.into()), - bx!(asset_hub_rococo_location().into()), - bx!(assets.into()), - bx!(TransferType::DestinationReserve), - bx!(fee.into()), - bx!(TransferType::DestinationReserve), - bx!(VersionedXcm::from(custom_xcm_on_dest)), - WeightLimit::Unlimited, - ) - })); - // verify hops (also advances the message through the hops) - assert_bridge_hub_westend_message_accepted(true); - assert_bridge_hub_rococo_message_received(); - AssetHubRococo::execute_with(|| { - AssetHubRococo::assert_xcmp_queue_success(None); - }); - - let receiver_usdts_after = AssetHubRococo::execute_with(|| { - type Assets = ::Assets; - >::balance(USDT_ID, &receiver) - }); - let receiver_weth_after = foreign_balance_on_ah_rococo(bridged_weth_at_ah, &receiver); - - // Receiver's USDT balance is increased by almost `amount_to_send` (minus fees) - assert!(receiver_usdts_after > receiver_usdts_before); - assert!(receiver_usdts_after < receiver_usdts_before + amount_to_send); - // Receiver's wETH balance is increased by `amount_to_send` - assert_eq!(receiver_weth_after, receiver_weth_before + amount_to_send); } #[test] @@ -367,7 +348,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 +380,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 +411,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 +423,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(), @@ -451,10 +432,20 @@ fn send_back_rocs_from_penpal_westend_through_asset_hub_westend_to_asset_hub_roc ASSET_MIN_BALANCE, vec![(sender.clone(), amount * 2)], ); + // Configure source Penpal chain to trust local AH as reserve of bridged ROC + PenpalB::execute_with(|| { + assert_ok!(::System::set_storage( + ::RuntimeOrigin::root(), + vec![( + PenpalCustomizableAssetFromSystemAssetHub::key().to_vec(), + roc_at_westend_parachains.encode(), + )], + )); + }); // 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)]); @@ -543,3 +534,12 @@ fn send_back_rocs_from_penpal_westend_through_asset_hub_westend_to_asset_hub_roc assert!(receiver_rocs_after > receiver_rocs_before); assert!(receiver_rocs_after <= receiver_rocs_before + amount); } + +#[test] +fn dry_run_transfer_to_rococo_sends_xcm_to_bridge_hub() { + test_dry_run_transfer_across_pk_bridge!( + AssetHubWestend, + BridgeHubWestend, + asset_hub_rococo_location() + ); +} 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 000000000000..e62ce6843258 --- /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 92e864229a9c..af11f0f7ba72 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,13 +16,12 @@ use crate::imports::*; mod asset_transfers; +mod claim_assets; +mod register_bridged_assets; mod send_xcm; mod teleport; -mod snowbridge { - pub const CHAIN_ID: u64 = 11155111; - pub const WETH: [u8; 20] = hex_literal::hex!("87d1f7fdfEe7f651FaBc8bFCB6E086C278b77A7d"); -} +mod snowbridge; pub(crate) fn asset_hub_rococo_location() -> Location { Location::new(2, [GlobalConsensus(Rococo), Parachain(AssetHubRococo::para_id().into())]) @@ -40,21 +39,24 @@ pub(crate) fn bridged_wnd_at_ah_rococo() -> Location { Location::new(2, [GlobalConsensus(Westend)]) } -// wROC +// ROC and wROC +pub(crate) fn roc_at_ah_rococo() -> Location { + Parent.into() +} pub(crate) fn bridged_roc_at_ah_westend() -> Location { Location::new(2, [GlobalConsensus(Rococo)]) } // USDT and wUSDT -pub(crate) fn usdt_at_ah_rococo() -> Location { +pub(crate) fn usdt_at_ah_westend() -> Location { Location::new(0, [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into())]) } -pub(crate) fn bridged_usdt_at_ah_westend() -> Location { +pub(crate) fn bridged_usdt_at_ah_rococo() -> Location { Location::new( 2, [ - GlobalConsensus(Rococo), - Parachain(AssetHubRococo::para_id().into()), + GlobalConsensus(Westend), + Parachain(AssetHubWestend::para_id().into()), PalletInstance(ASSETS_PALLET_ID), GeneralIndex(USDT_ID.into()), ], @@ -72,13 +74,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 +89,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 +103,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 +113,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 +131,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, @@ -227,3 +229,35 @@ pub(crate) fn assert_bridge_hub_rococo_message_received() { ); }) } + +pub(crate) fn open_bridge_between_asset_hub_rococo_and_asset_hub_westend() { + use testnet_parachains_constants::{ + rococo::currency::UNITS as ROC, westend::currency::UNITS as WND, + }; + + // open AHR -> AHW + BridgeHubRococo::fund_para_sovereign(AssetHubRococo::para_id(), ROC * 5); + AssetHubRococo::open_bridge( + AssetHubRococo::sibling_location_of(BridgeHubRococo::para_id()), + [GlobalConsensus(Westend), Parachain(AssetHubWestend::para_id().into())].into(), + Some(( + (roc_at_ah_rococo(), ROC * 1).into(), + BridgeHubRococo::sovereign_account_id_of(BridgeHubRococo::sibling_location_of( + AssetHubRococo::para_id(), + )), + )), + ); + + // open AHW -> AHR + BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), WND * 5); + AssetHubWestend::open_bridge( + AssetHubWestend::sibling_location_of(BridgeHubWestend::para_id()), + [GlobalConsensus(Rococo), Parachain(AssetHubRococo::para_id().into())].into(), + Some(( + (wnd_at_ah_westend(), WND * 1).into(), + BridgeHubWestend::sovereign_account_id_of(BridgeHubWestend::sibling_location_of( + AssetHubWestend::para_id(), + )), + )), + ); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/register_bridged_assets.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/register_bridged_assets.rs new file mode 100644 index 000000000000..7a7ad6da2d55 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/register_bridged_assets.rs @@ -0,0 +1,131 @@ +// 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::*, + tests::{ + snowbridge::{CHAIN_ID, WETH}, + *, + }, +}; + +const XCM_FEE: u128 = 40_000_000_000; + +/// Tests the registering of a Westend Asset as a bridged asset on Rococo Asset Hub. +#[test] +fn register_westend_asset_on_rah_from_wah() { + // Westend Asset Hub asset when bridged to Rococo Asset Hub. + let bridged_asset_at_rah = Location::new( + 2, + [ + GlobalConsensus(Westend), + Parachain(AssetHubWestend::para_id().into()), + PalletInstance(ASSETS_PALLET_ID), + GeneralIndex(ASSET_ID.into()), + ], + ); + // Register above asset on Rococo AH from Westend AH. + register_asset_on_rah_from_wah(bridged_asset_at_rah); +} + +/// Tests the registering of an Ethereum Asset as a bridged asset on Rococo Asset Hub. +#[test] +fn register_ethereum_asset_on_rah_from_wah() { + // Ethereum asset when bridged to Rococo Asset Hub. + let bridged_asset_at_rah = Location::new( + 2, + [ + GlobalConsensus(Ethereum { chain_id: CHAIN_ID }), + AccountKey20 { network: None, key: WETH }, + ], + ); + // Register above asset on Rococo AH from Westend AH. + register_asset_on_rah_from_wah(bridged_asset_at_rah); +} + +fn register_asset_on_rah_from_wah(bridged_asset_at_rah: Location) { + let sa_of_wah_on_rah = AssetHubRococo::sovereign_account_of_parachain_on_other_global_consensus( + Westend, + AssetHubWestend::para_id(), + ); + + // Encoded `create_asset` call to be executed in Rococo Asset Hub ForeignAssets pallet. + let call = AssetHubRococo::create_foreign_asset_call( + bridged_asset_at_rah.clone(), + ASSET_MIN_BALANCE, + sa_of_wah_on_rah.clone(), + ); + + let origin_kind = OriginKind::Xcm; + let fee_amount = XCM_FEE; + let fees = (Parent, fee_amount).into(); + + let xcm = xcm_transact_paid_execution(call, origin_kind, fees, sa_of_wah_on_rah.clone()); + + // SA-of-WAH-on-RAH needs to have balance to pay for fees and asset creation deposit + AssetHubRococo::fund_accounts(vec![( + sa_of_wah_on_rah.clone(), + ASSET_HUB_ROCOCO_ED * 10000000000, + )]); + + let destination = asset_hub_rococo_location(); + + // fund the WAH's SA on WBH for paying bridge transport fees + BridgeHubWestend::fund_para_sovereign(AssetHubWestend::para_id(), 10_000_000_000_000u128); + + // set XCM versions + AssetHubWestend::force_xcm_version(destination.clone(), XCM_VERSION); + BridgeHubWestend::force_xcm_version(bridge_hub_rococo_location(), XCM_VERSION); + + let root_origin = ::RuntimeOrigin::root(); + AssetHubWestend::execute_with(|| { + assert_ok!(::PolkadotXcm::send( + root_origin, + bx!(destination.into()), + bx!(xcm), + )); + + AssetHubWestend::assert_xcm_pallet_sent(); + }); + + assert_bridge_hub_westend_message_accepted(true); + assert_bridge_hub_rococo_message_received(); + AssetHubRococo::execute_with(|| { + type RuntimeEvent = ::RuntimeEvent; + AssetHubRococo::assert_xcmp_queue_success(None); + assert_expected_events!( + AssetHubRococo, + vec![ + // Burned the fee + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, amount }) => { + who: *who == sa_of_wah_on_rah.clone(), + amount: *amount == fee_amount, + }, + // Foreign Asset created + RuntimeEvent::ForeignAssets(pallet_assets::Event::Created { asset_id, creator, owner }) => { + asset_id: asset_id == &bridged_asset_at_rah, + creator: *creator == sa_of_wah_on_rah.clone(), + owner: *owner == sa_of_wah_on_rah, + }, + // Unspent fee minted to origin + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, .. }) => { + who: *who == sa_of_wah_on_rah.clone(), + }, + ] + ); + type ForeignAssets = ::ForeignAssets; + assert!(ForeignAssets::asset_exists(bridged_asset_at_rah)); + }); +} diff --git a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs index dee411bea8b7..ae05e4223b07 100644 --- a/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/send_xcm.rs @@ -79,6 +79,9 @@ fn send_xcm_through_opened_lane_with_different_xcm_version_on_hops_works() { // fund sender AssetHubWestend::fund_accounts(vec![(AssetHubWestendSender::get().into(), amount * 10)]); + // open bridge + open_bridge_between_asset_hub_rococo_and_asset_hub_westend(); + // send XCM from AssetHubWestend - fails - destination version not known assert_err!( send_assets_from_asset_hub_westend( 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 000000000000..4e9dd5a77dd7 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/bridges/bridge-hub-westend/src/tests/snowbridge.rs @@ -0,0 +1,597 @@ +// 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 emulated_integration_tests_common::RESERVABLE_ASSET_ID; +use frame_support::pallet_prelude::TypeInfo; +use hex_literal::hex; +use rococo_westend_system_emulated_network::asset_hub_westend_emulated_chain::genesis::AssetHubWestendAssetOwner; +use snowbridge_core::{outbound::OperatingMode, AssetMetadata, TokenIdOf}; +use snowbridge_router_primitives::inbound::{ + Command, Destination, GlobalConsensusEthereumConvertsFor, MessageV1, VersionedMessage, +}; +use sp_core::H256; +use testnet_parachains_constants::westend::snowbridge::EthereumNetwork; +use xcm_executor::traits::ConvertLocation; + +const INITIAL_FUND: u128 = 5_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 TOKEN_AMOUNT: u128 = 100_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; + + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::RegisterToken { token: WETH.into(), fee: XCM_FEE }, + }); + let (xcm, _) = EthereumInboundQueue::do_convert([0; 32].into(), message).unwrap(); + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubWestend::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; + + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::SendToken { + token: WETH.into(), + destination: Destination::AccountId32 { id: AssetHubWestendReceiver::get().into() }, + amount: TOKEN_AMOUNT, + fee: XCM_FEE, + }, + }); + let (xcm, _) = EthereumInboundQueue::do_convert([0; 32].into(), 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(); + + 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; + + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::SendToken { + token: WETH.into(), + destination: Destination::AccountId32 { id: AssetHubWestendReceiver::get().into() }, + amount: TOKEN_AMOUNT, + fee: XCM_FEE, + }, + }); + let (xcm, _) = EthereumInboundQueue::do_convert([0; 32].into(), 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(TOKEN_AMOUNT), + }]; + let versioned_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(versioned_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." + ); + }); +} + +#[test] +fn transfer_relay_token() { + let assethub_sovereign = BridgeHubWestend::sovereign_account_id_of( + BridgeHubWestend::sibling_location_of(AssetHubWestend::para_id()), + ); + BridgeHubWestend::fund_accounts(vec![(assethub_sovereign.clone(), INITIAL_FUND)]); + + let asset_id: Location = Location { parents: 1, interior: [].into() }; + let expected_asset_id: Location = + Location { parents: 1, interior: [GlobalConsensus(Westend)].into() }; + + let expected_token_id = TokenIdOf::convert_location(&expected_asset_id).unwrap(); + + let ethereum_sovereign: AccountId = + GlobalConsensusEthereumConvertsFor::<[u8; 32]>::convert_location(&Location::new( + 2, + [GlobalConsensus(EthereumNetwork::get())], + )) + .unwrap() + .into(); + + // Register token + BridgeHubWestend::execute_with(|| { + type RuntimeOrigin = ::RuntimeOrigin; + type RuntimeEvent = ::RuntimeEvent; + + assert_ok!(::Balances::force_set_balance( + RuntimeOrigin::root(), + sp_runtime::MultiAddress::Id(BridgeHubWestendSender::get()), + INITIAL_FUND * 10, + )); + + assert_ok!(::EthereumSystem::register_token( + RuntimeOrigin::root(), + Box::new(VersionedLocation::V4(asset_id.clone())), + AssetMetadata { + name: "wnd".as_bytes().to_vec().try_into().unwrap(), + symbol: "wnd".as_bytes().to_vec().try_into().unwrap(), + decimals: 12, + }, + )); + // Check that a message was sent to Ethereum to create the agent + assert_expected_events!( + BridgeHubWestend, + vec![RuntimeEvent::EthereumSystem(snowbridge_pallet_system::Event::RegisterToken { .. }) => {},] + ); + }); + + // Send token to Ethereum + AssetHubWestend::execute_with(|| { + type RuntimeOrigin = ::RuntimeOrigin; + type RuntimeEvent = ::RuntimeEvent; + + let assets = vec![Asset { id: AssetId(Location::parent()), fun: Fungible(TOKEN_AMOUNT) }]; + let versioned_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() }], + )); + + assert_ok!(::PolkadotXcm::limited_reserve_transfer_assets( + RuntimeOrigin::signed(AssetHubWestendSender::get()), + Box::new(destination), + Box::new(beneficiary), + Box::new(versioned_assets), + 0, + Unlimited, + )); + + let events = AssetHubWestend::events(); + // Check that the native asset transferred to some reserved account(sovereign of Ethereum) + assert!( + events.iter().any(|event| matches!( + event, + RuntimeEvent::Balances(pallet_balances::Event::Transfer { amount, to, ..}) + if *amount == TOKEN_AMOUNT && *to == ethereum_sovereign.clone(), + )), + "native token reserved to Ethereum sovereign account." + ); + }); + + // Send token back from ethereum + BridgeHubWestend::execute_with(|| { + 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{ .. }) => {},] + ); + + // Send relay token back to AH + let message_id: H256 = [0; 32].into(); + let message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::SendNativeToken { + token_id: expected_token_id, + destination: Destination::AccountId32 { id: AssetHubWestendReceiver::get().into() }, + amount: TOKEN_AMOUNT, + fee: XCM_FEE, + }, + }); + // Convert the message to XCM + let (xcm, _) = EthereumInboundQueue::do_convert(message_id, message).unwrap(); + // Send the XCM + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubWestend::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::Balances(pallet_balances::Event::Burned{ .. }) => {},] + ); + + let events = AssetHubWestend::events(); + + // Check that the native token burnt from some reserved account + assert!( + events.iter().any(|event| matches!( + event, + RuntimeEvent::Balances(pallet_balances::Event::Burned { who, ..}) + if *who == ethereum_sovereign.clone(), + )), + "native token burnt from Ethereum sovereign account." + ); + + // Check that the token was minted to beneficiary + assert!( + events.iter().any(|event| matches!( + event, + RuntimeEvent::Balances(pallet_balances::Event::Minted { who, amount }) + if *amount >= TOKEN_AMOUNT && *who == AssetHubWestendReceiver::get() + )), + "Token minted to beneficiary." + ); + }); +} + +#[test] +fn transfer_ah_token() { + let assethub_sovereign = BridgeHubWestend::sovereign_account_id_of( + BridgeHubWestend::sibling_location_of(AssetHubWestend::para_id()), + ); + BridgeHubWestend::fund_accounts(vec![(assethub_sovereign.clone(), INITIAL_FUND)]); + + let ethereum_destination = Location::new(2, [GlobalConsensus(Ethereum { chain_id: CHAIN_ID })]); + + let ethereum_sovereign: AccountId = + GlobalConsensusEthereumConvertsFor::<[u8; 32]>::convert_location(ðereum_destination) + .unwrap() + .into(); + AssetHubWestend::fund_accounts(vec![(ethereum_sovereign.clone(), INITIAL_FUND)]); + + let asset_id: Location = + [PalletInstance(ASSETS_PALLET_ID), GeneralIndex(RESERVABLE_ASSET_ID.into())].into(); + + let asset_id_in_bh: Location = Location::new( + 1, + [ + Parachain(AssetHubWestend::para_id().into()), + PalletInstance(ASSETS_PALLET_ID), + GeneralIndex(RESERVABLE_ASSET_ID.into()), + ], + ); + + let asset_id_after_reanchored = + Location::new(1, [GlobalConsensus(Westend), Parachain(AssetHubWestend::para_id().into())]) + .appended_with(asset_id.clone().interior) + .unwrap(); + + let token_id = TokenIdOf::convert_location(&asset_id_after_reanchored).unwrap(); + + // Register token + BridgeHubWestend::execute_with(|| { + type RuntimeOrigin = ::RuntimeOrigin; + + assert_ok!(::EthereumSystem::register_token( + RuntimeOrigin::root(), + Box::new(VersionedLocation::V4(asset_id_in_bh.clone())), + AssetMetadata { + name: "ah_asset".as_bytes().to_vec().try_into().unwrap(), + symbol: "ah_asset".as_bytes().to_vec().try_into().unwrap(), + decimals: 12, + }, + )); + }); + + // Mint some token + AssetHubWestend::mint_asset( + ::RuntimeOrigin::signed(AssetHubWestendAssetOwner::get()), + RESERVABLE_ASSET_ID, + AssetHubWestendSender::get(), + TOKEN_AMOUNT, + ); + + // Send token to Ethereum + AssetHubWestend::execute_with(|| { + type RuntimeOrigin = ::RuntimeOrigin; + type RuntimeEvent = ::RuntimeEvent; + + // Send partial of the token, will fail if send all + let assets = + vec![Asset { id: AssetId(asset_id.clone()), fun: Fungible(TOKEN_AMOUNT / 10) }]; + let versioned_assets = VersionedAssets::V4(Assets::from(assets)); + + let beneficiary = VersionedLocation::V4(Location::new( + 0, + [AccountKey20 { network: None, key: ETHEREUM_DESTINATION_ADDRESS.into() }], + )); + + assert_ok!(::PolkadotXcm::limited_reserve_transfer_assets( + RuntimeOrigin::signed(AssetHubWestendSender::get()), + Box::new(VersionedLocation::from(ethereum_destination)), + Box::new(beneficiary), + Box::new(versioned_assets), + 0, + Unlimited, + )); + + assert_expected_events!( + AssetHubWestend, + vec![RuntimeEvent::Assets(pallet_assets::Event::Transferred{ .. }) => {},] + ); + + let events = AssetHubWestend::events(); + // Check that the native asset transferred to some reserved account(sovereign of Ethereum) + assert!( + events.iter().any(|event| matches!( + event, + RuntimeEvent::Assets(pallet_assets::Event::Transferred { asset_id, to, ..}) + if *asset_id == RESERVABLE_ASSET_ID && *to == ethereum_sovereign.clone() + )), + "native token reserved to Ethereum sovereign account." + ); + }); + + // Send token back from Ethereum + BridgeHubWestend::execute_with(|| { + 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 message = VersionedMessage::V1(MessageV1 { + chain_id: CHAIN_ID, + command: Command::SendNativeToken { + token_id, + destination: Destination::AccountId32 { id: AssetHubWestendReceiver::get().into() }, + amount: TOKEN_AMOUNT / 10, + fee: XCM_FEE, + }, + }); + // Convert the message to XCM + let (xcm, _) = EthereumInboundQueue::do_convert([0; 32].into(), message).unwrap(); + // Send the XCM + let _ = EthereumInboundQueue::send_xcm(xcm, AssetHubWestend::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::Assets(pallet_assets::Event::Burned{..}) => {},] + ); + + let events = AssetHubWestend::events(); + + // Check that the native token burnt from some reserved account + assert!( + events.iter().any(|event| matches!( + event, + RuntimeEvent::Assets(pallet_assets::Event::Burned { owner, .. }) + if *owner == ethereum_sovereign.clone(), + )), + "token burnt from Ethereum sovereign account." + ); + + // Check that the token was minted to beneficiary + assert!( + events.iter().any(|event| matches!( + event, + RuntimeEvent::Assets(pallet_assets::Event::Issued { owner, .. }) + if *owner == AssetHubWestendReceiver::get() + )), + "Token minted to beneficiary." + ); + }); +} 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 64378a844f52..a5add3b82957 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 3012e2b19f53..c4d281b75a77 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 8af93a62f4a1..e2048b62c311 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 000000000000..f97599bda7f0 --- /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 000000000000..840d2da49463 --- /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 abd9a982c8ed..943f8965540d 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 a9f65df34b64..ef4e4885183d 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 000000000000..32f543406d75 --- /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 000000000000..28d9da0993ff --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "coretime-rococo-integration-tests" +version = "0.0.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-broker = { workspace = true, default-features = true } +pallet-message-queue = { workspace = true } +pallet-identity = { workspace = true } +sp-runtime = { workspace = true } + +# Polkadot +polkadot-runtime-common = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } +rococo-runtime-constants = { workspace = true, default-features = true } +xcm = { workspace = true } +xcm-executor = { workspace = true } + +# Cumulus +cumulus-pallet-parachain-system = { workspace = true, default-features = true } +emulated-integration-tests-common = { workspace = true } +rococo-system-emulated-network = { workspace = true } diff --git a/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/lib.rs new file mode 100644 index 000000000000..055bd50d8298 --- /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, Chain, Parachain, 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, RococoRelay as Rococo, + }; +} + +#[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 000000000000..e37b915174d3 --- /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/coretime_interface.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/coretime_interface.rs new file mode 100644 index 000000000000..9915b1753ef6 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/coretime_interface.rs @@ -0,0 +1,235 @@ +// 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 frame_support::traits::OnInitialize; +use pallet_broker::{ConfigRecord, Configuration, CoreAssignment, CoreMask, ScheduleItem}; +use rococo_runtime_constants::system_parachain::coretime::TIMESLICE_PERIOD; +use sp_runtime::Perbill; + +#[test] +fn transact_hardcoded_weights_are_sane() { + // There are three transacts with hardcoded weights sent from the Coretime Chain to the Relay + // Chain across the CoretimeInterface which are triggered at various points in the sales cycle. + // - Request core count - triggered directly by `start_sales` or `request_core_count` + // extrinsics. + // - Request revenue info - triggered when each timeslice is committed. + // - Assign core - triggered when an entry is encountered in the workplan for the next + // timeslice. + + // RuntimeEvent aliases to avoid warning from usage of qualified paths in assertions due to + // + type CoretimeEvent = ::RuntimeEvent; + type RelayEvent = ::RuntimeEvent; + + // Reserve a workload, configure broker and start sales. + CoretimeRococo::execute_with(|| { + // Hooks don't run in emulated tests - workaround as we need `on_initialize` to tick things + // along and have no concept of time passing otherwise. + ::Broker::on_initialize( + ::System::block_number(), + ); + + let coretime_root_origin = ::RuntimeOrigin::root(); + + // Create and populate schedule with the worst case assignment on this core. + let mut schedule = Vec::new(); + for i in 0..80 { + schedule.push(ScheduleItem { + mask: CoreMask::void().set(i), + assignment: CoreAssignment::Task(2000 + i), + }) + } + + assert_ok!(::Broker::reserve( + coretime_root_origin.clone(), + schedule.try_into().expect("Vector is within bounds."), + )); + + // Configure broker and start sales. + let config = ConfigRecord { + advance_notice: 1, + interlude_length: 1, + leadin_length: 2, + region_length: 1, + ideal_bulk_proportion: Perbill::from_percent(40), + limit_cores_offered: None, + renewal_bump: Perbill::from_percent(2), + contribution_timeout: 1, + }; + assert_ok!(::Broker::configure( + coretime_root_origin.clone(), + config + )); + assert_ok!(::Broker::start_sales( + coretime_root_origin, + 100, + 0 + )); + assert_eq!( + pallet_broker::Status::<::Runtime>::get() + .unwrap() + .core_count, + 1 + ); + + assert_expected_events!( + CoretimeRococo, + vec![ + CoretimeEvent::Broker( + pallet_broker::Event::ReservationMade { .. } + ) => {}, + CoretimeEvent::Broker( + pallet_broker::Event::CoreCountRequested { core_count: 1 } + ) => {}, + CoretimeEvent::ParachainSystem( + cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } + ) => {}, + ] + ); + }); + + // Check that the request_core_count message was processed successfully. This will fail if the + // weights are misconfigured. + Rococo::execute_with(|| { + Rococo::assert_ump_queue_processed(true, Some(CoretimeRococo::para_id()), None); + + assert_expected_events!( + Rococo, + vec![ + RelayEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + }); + + // Keep track of the relay chain block number so we can fast forward while still checking the + // right block. + let mut block_number_cursor = Rococo::ext_wrapper(::System::block_number); + + let config = CoretimeRococo::ext_wrapper(|| { + Configuration::<::Runtime>::get() + .expect("Pallet was configured earlier.") + }); + + // Now run up to the block before the sale is rotated. + while block_number_cursor < TIMESLICE_PERIOD - config.advance_notice - 1 { + CoretimeRococo::execute_with(|| { + // Hooks don't run in emulated tests - workaround. + ::Broker::on_initialize( + ::System::block_number(), + ); + }); + + Rococo::ext_wrapper(|| { + block_number_cursor = ::System::block_number(); + }); + } + + // In this block we trigger assign core. + CoretimeRococo::execute_with(|| { + // Hooks don't run in emulated tests - workaround. + ::Broker::on_initialize( + ::System::block_number(), + ); + + assert_expected_events!( + CoretimeRococo, + vec![ + CoretimeEvent::Broker( + pallet_broker::Event::SaleInitialized { .. } + ) => {}, + CoretimeEvent::Broker( + pallet_broker::Event::CoreAssigned { .. } + ) => {}, + CoretimeEvent::ParachainSystem( + cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } + ) => {}, + ] + ); + }); + + // Check that the assign_core message was processed successfully. + // This will fail if the weights are misconfigured. + Rococo::execute_with(|| { + Rococo::assert_ump_queue_processed(true, Some(CoretimeRococo::para_id()), None); + + assert_expected_events!( + Rococo, + vec![ + RelayEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + RelayEvent::Coretime( + polkadot_runtime_parachains::coretime::Event::CoreAssigned { .. } + ) => {}, + ] + ); + }); + + // In this block we trigger request revenue. + CoretimeRococo::execute_with(|| { + // Hooks don't run in emulated tests - workaround. + ::Broker::on_initialize( + ::System::block_number(), + ); + + assert_expected_events!( + CoretimeRococo, + vec![ + CoretimeEvent::ParachainSystem( + cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } + ) => {}, + ] + ); + }); + + // Check that the request_revenue_info_at message was processed successfully. + // This will fail if the weights are misconfigured. + Rococo::execute_with(|| { + Rococo::assert_ump_queue_processed(true, Some(CoretimeRococo::para_id()), None); + + assert_expected_events!( + Rococo, + vec![ + RelayEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + }); + + // Here we receive and process the notify_revenue XCM with zero revenue. + CoretimeRococo::execute_with(|| { + // Hooks don't run in emulated tests - workaround. + ::Broker::on_initialize( + ::System::block_number(), + ); + + assert_expected_events!( + CoretimeRococo, + vec![ + CoretimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + // Zero revenue in first timeslice so history is immediately dropped. + CoretimeEvent::Broker( + pallet_broker::Event::HistoryDropped { when: 0, revenue: 0 } + ) => {}, + ] + ); + }); +} 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 000000000000..bb0387a4b350 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-rococo/src/tests/mod.rs @@ -0,0 +1,17 @@ +// 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; +mod coretime_interface; 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 000000000000..d57e7926b0ec --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "coretime-westend-integration-tests" +version = "0.0.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-broker = { workspace = true, default-features = true } +pallet-message-queue = { workspace = true } +pallet-identity = { workspace = true } +sp-runtime = { workspace = true } + +# Polkadot +polkadot-runtime-common = { workspace = true, default-features = true } +polkadot-runtime-parachains = { workspace = true, default-features = true } +westend-runtime-constants = { workspace = true, default-features = true } +xcm = { workspace = true } +xcm-executor = { workspace = true } + +# Cumulus +cumulus-pallet-parachain-system = { workspace = true, default-features = true } +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 000000000000..ac844e0f3284 --- /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, Chain, Parachain, 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, WestendRelay as Westend, + }; +} + +#[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 000000000000..c8d853698444 --- /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/coretime_interface.rs b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/coretime_interface.rs new file mode 100644 index 000000000000..00530f80b958 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/coretime_interface.rs @@ -0,0 +1,223 @@ +// 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 frame_support::traits::OnInitialize; +use pallet_broker::{ConfigRecord, Configuration, CoreAssignment, CoreMask, ScheduleItem}; +use sp_runtime::Perbill; +use westend_runtime_constants::system_parachain::coretime::TIMESLICE_PERIOD; + +#[test] +fn transact_hardcoded_weights_are_sane() { + // There are three transacts with hardcoded weights sent from the Coretime Chain to the Relay + // Chain across the CoretimeInterface which are triggered at various points in the sales cycle. + // - Request core count - triggered directly by `start_sales` or `request_core_count` + // extrinsics. + // - Request revenue info - triggered when each timeslice is committed. + // - Assign core - triggered when an entry is encountered in the workplan for the next + // timeslice. + + // RuntimeEvent aliases to avoid warning from usage of qualified paths in assertions due to + // + type CoretimeEvent = ::RuntimeEvent; + type RelayEvent = ::RuntimeEvent; + + // Reserve a workload, configure broker and start sales. + CoretimeWestend::execute_with(|| { + // Hooks don't run in emulated tests - workaround as we need `on_initialize` to tick things + // along and have no concept of time passing otherwise. + ::Broker::on_initialize( + ::System::block_number(), + ); + + let coretime_root_origin = ::RuntimeOrigin::root(); + + // Create and populate schedule with the worst case assignment on this core. + let mut schedule = Vec::new(); + for i in 0..80 { + schedule.push(ScheduleItem { + mask: CoreMask::void().set(i), + assignment: CoreAssignment::Task(2000 + i), + }) + } + + assert_ok!(::Broker::reserve( + coretime_root_origin.clone(), + schedule.try_into().expect("Vector is within bounds."), + )); + + // Configure broker and start sales. + let config = ConfigRecord { + advance_notice: 1, + interlude_length: 1, + leadin_length: 2, + region_length: 1, + ideal_bulk_proportion: Perbill::from_percent(40), + limit_cores_offered: None, + renewal_bump: Perbill::from_percent(2), + contribution_timeout: 1, + }; + assert_ok!(::Broker::configure( + coretime_root_origin.clone(), + config + )); + assert_ok!(::Broker::start_sales( + coretime_root_origin, + 100, + 0 + )); + assert_eq!( + pallet_broker::Status::<::Runtime>::get() + .unwrap() + .core_count, + 1 + ); + + assert_expected_events!( + CoretimeWestend, + vec![ + CoretimeEvent::Broker( + pallet_broker::Event::ReservationMade { .. } + ) => {}, + CoretimeEvent::Broker( + pallet_broker::Event::CoreCountRequested { core_count: 1 } + ) => {}, + CoretimeEvent::ParachainSystem( + cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } + ) => {}, + ] + ); + }); + + // Check that the request_core_count message was processed successfully. This will fail if the + // weights are misconfigured. + Westend::execute_with(|| { + Westend::assert_ump_queue_processed(true, Some(CoretimeWestend::para_id()), None); + + assert_expected_events!( + Westend, + vec![ + RelayEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + ] + ); + }); + + // Keep track of the relay chain block number so we can fast forward while still checking the + // right block. + let mut block_number_cursor = Westend::ext_wrapper(::System::block_number); + + let config = CoretimeWestend::ext_wrapper(|| { + Configuration::<::Runtime>::get() + .expect("Pallet was configured earlier.") + }); + + // Now run up to the block before the sale is rotated. + while block_number_cursor < TIMESLICE_PERIOD - config.advance_notice - 1 { + CoretimeWestend::execute_with(|| { + // Hooks don't run in emulated tests - workaround. + ::Broker::on_initialize( + ::System::block_number(), + ); + }); + + Westend::ext_wrapper(|| { + block_number_cursor = ::System::block_number(); + }); + } + + // In this block we trigger assign core. + CoretimeWestend::execute_with(|| { + // Hooks don't run in emulated tests - workaround. + ::Broker::on_initialize( + ::System::block_number(), + ); + + assert_expected_events!( + CoretimeWestend, + vec![ + CoretimeEvent::Broker( + pallet_broker::Event::SaleInitialized { .. } + ) => {}, + CoretimeEvent::Broker( + pallet_broker::Event::CoreAssigned { .. } + ) => {}, + CoretimeEvent::ParachainSystem( + cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } + ) => {}, + ] + ); + }); + + // In this block we trigger request revenue. + CoretimeWestend::execute_with(|| { + // Hooks don't run in emulated tests - workaround. + ::Broker::on_initialize( + ::System::block_number(), + ); + + assert_expected_events!( + CoretimeWestend, + vec![ + CoretimeEvent::ParachainSystem( + cumulus_pallet_parachain_system::Event::UpwardMessageSent { .. } + ) => {}, + ] + ); + }); + + // Check that the assign_core and request_revenue_info_at messages were processed successfully. + // This will fail if the weights are misconfigured. + Westend::execute_with(|| { + Westend::assert_ump_queue_processed(true, Some(CoretimeWestend::para_id()), None); + + assert_expected_events!( + Westend, + vec![ + RelayEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + RelayEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + RelayEvent::Coretime( + polkadot_runtime_parachains::coretime::Event::CoreAssigned { .. } + ) => {}, + ] + ); + }); + + // Here we receive and process the notify_revenue XCM with zero revenue. + CoretimeWestend::execute_with(|| { + // Hooks don't run in emulated tests - workaround. + ::Broker::on_initialize( + ::System::block_number(), + ); + + assert_expected_events!( + CoretimeWestend, + vec![ + CoretimeEvent::MessageQueue( + pallet_message_queue::Event::Processed { success: true, .. } + ) => {}, + // Zero revenue in first timeslice so history is immediately dropped. + CoretimeEvent::Broker( + pallet_broker::Event::HistoryDropped { when: 0, revenue: 0 } + ) => {}, + ] + ); + }); +} 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 000000000000..bb0387a4b350 --- /dev/null +++ b/cumulus/parachains/integration-tests/emulated/tests/coretime/coretime-westend/src/tests/mod.rs @@ -0,0 +1,17 @@ +// 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; +mod coretime_interface; 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 6c23c2f1f292..06b0b6ba6005 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 000000000000..793200e1d06b --- /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 80c00021ca53..08749b295dc2 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 342a8f053f60..000000000000 --- 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 4410d1bd40dc..2619ca7591d0 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 @@ -248,7 +107,9 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { 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) + >( + test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest + ) }); // Sender's balance is reduced 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 f7e1cce85a2c..aa6eebc5458f 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 ce1ed9751a2e..418cfea07ddc 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 000000000000..42ccc459286a --- /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 80c00021ca53..08749b295dc2 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 28d1be853204..000000000000 --- 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 6fd3cdeb61fb..d9a2c23ac0c6 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 @@ -248,7 +107,9 @@ fn limited_teleport_native_assets_from_system_para_to_relay_fails() { 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) + >( + test.args.assets.clone(), 0, test.args.weight_limit, test.args.beneficiary, test.args.dest + ) }); // Sender's balance is reduced diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml index 98df41090a40..42adaba7a27c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/Cargo.toml @@ -14,6 +14,7 @@ codec = { features = ["derive", "max-encoded-len"], workspace = true } hex-literal = { workspace = true, default-features = true } log = { workspace = true } scale-info = { features = ["derive"], workspace = true } +serde_json = { features = ["alloc"], workspace = true } # Substrate frame-benchmarking = { optional = true, workspace = true } @@ -48,6 +49,7 @@ sp-api = { workspace = true } sp-block-builder = { workspace = true } sp-consensus-aura = { workspace = true } sp-core = { workspace = true } +sp-keyring = { workspace = true } sp-inherents = { workspace = true } sp-genesis-builder = { workspace = true } sp-offchain = { workspace = true } @@ -115,6 +117,7 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-asset-conversion-ops/runtime-benchmarks", + "pallet-asset-conversion-tx-payment/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", "pallet-assets-freezer/runtime-benchmarks", "pallet-assets/runtime-benchmarks", @@ -126,6 +129,7 @@ runtime-benchmarks = [ "pallet-nfts/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-uniques/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", @@ -230,6 +234,7 @@ std = [ "primitive-types/std", "rococo-runtime-constants/std", "scale-info/std", + "serde_json/std", "snowbridge-router-primitives/std", "sp-api/std", "sp-block-builder/std", @@ -237,6 +242,7 @@ std = [ "sp-core/std", "sp-genesis-builder/std", "sp-inherents/std", + "sp-keyring/std", "sp-offchain/std", "sp-runtime/std", "sp-session/std", @@ -258,4 +264,4 @@ metadata-hash = ["substrate-wasm-builder/metadata-hash"] # A feature that should be enabled when the runtime should be built for on-chain # deployment. This will disable stuff that shouldn't be part of the on-chain wasm # to make it smaller, like logging for example. -on-chain-release-build = ["metadata-hash", "sp-api/disable-logging"] +on-chain-release-build = ["metadata-hash"] diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/genesis_config_presets.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/genesis_config_presets.rs new file mode 100644 index 000000000000..dc98d00f8f63 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/genesis_config_presets.rs @@ -0,0 +1,150 @@ +// 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. + +//! # Asset Hub Rococo Runtime genesis config presets + +use crate::*; +use alloc::{vec, vec::Vec}; +use cumulus_primitives_core::ParaId; +use hex_literal::hex; +use parachains_common::{AccountId, AuraId}; +use sp_core::crypto::UncheckedInto; +use sp_genesis_builder::PresetId; +use sp_keyring::Sr25519Keyring; +use testnet_parachains_constants::rococo::{currency::UNITS as ROC, xcm_version::SAFE_XCM_VERSION}; + +const ASSET_HUB_ROCOCO_ED: Balance = ExistentialDeposit::get(); + +fn asset_hub_rococo_genesis( + invulnerables: Vec<(AccountId, AuraId)>, + endowed_accounts: Vec, + endowment: Balance, + id: ParaId, +) -> serde_json::Value { + let config = RuntimeGenesisConfig { + balances: BalancesConfig { + balances: endowed_accounts.iter().cloned().map(|k| (k, endowment)).collect(), + }, + parachain_info: ParachainInfoConfig { parachain_id: id, ..Default::default() }, + collator_selection: CollatorSelectionConfig { + invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: ASSET_HUB_ROCOCO_ED * 16, + ..Default::default() + }, + session: SessionConfig { + keys: invulnerables + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + SessionKeys { aura }, // session keys + ) + }) + .collect(), + ..Default::default() + }, + polkadot_xcm: PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + ..Default::default() + }; + + serde_json::to_value(config).expect("Could not build genesis config.") +} + +/// Encapsulates names of predefined presets. +mod preset_names { + pub const PRESET_GENESIS: &str = "genesis"; +} + +/// Provides the JSON representation of predefined genesis config for given `id`. +pub fn get_preset(id: &PresetId) -> Option> { + use preset_names::*; + let patch = match id.try_into() { + Ok(PRESET_GENESIS) => asset_hub_rococo_genesis( + // initial collators. + vec![ + // E8XC6rTJRsioKCp6KMy6zd24ykj4gWsusZ3AkSeyavpVBAG + ( + hex!("44cb62d1d6cdd2fff2a5ef3bb7ef827be5b3e117a394ecaa634d8dd9809d5608").into(), + hex!("44cb62d1d6cdd2fff2a5ef3bb7ef827be5b3e117a394ecaa634d8dd9809d5608") + .unchecked_into(), + ), + // G28iWEybndgGRbhfx83t7Q42YhMPByHpyqWDUgeyoGF94ri + ( + hex!("9864b85e23aa4506643db9879c3dbbeabaa94d269693a4447f537dd6b5893944").into(), + hex!("9864b85e23aa4506643db9879c3dbbeabaa94d269693a4447f537dd6b5893944") + .unchecked_into(), + ), + // G839e2eMiq7UXbConsY6DS1XDAYG2XnQxAmLuRLGGQ3Px9c + ( + hex!("9ce5741ee2f1ac3bdedbde9f3339048f4da2cb88ddf33a0977fa0b4cf86e2948").into(), + hex!("9ce5741ee2f1ac3bdedbde9f3339048f4da2cb88ddf33a0977fa0b4cf86e2948") + .unchecked_into(), + ), + // GLao4ukFUW6qhexuZowdFrKa2NLCfnEjZMftSXXfvGv1vvt + ( + hex!("a676ed15f5a325eab49ed8d5f8c00f3f814b19bb58cda14ad10894c078dd337f").into(), + hex!("a676ed15f5a325eab49ed8d5f8c00f3f814b19bb58cda14ad10894c078dd337f") + .unchecked_into(), + ), + ], + Vec::new(), + ASSET_HUB_ROCOCO_ED * 524_288, + 1000.into(), + ), + Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) => asset_hub_rococo_genesis( + // initial collators. + vec![ + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), + ], + Sr25519Keyring::well_known().map(|x| x.to_account_id()).collect(), + testnet_parachains_constants::rococo::currency::UNITS * 1_000_000, + 1000.into(), + ), + Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => asset_hub_rococo_genesis( + // initial collators. + vec![(Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into())], + vec![ + Sr25519Keyring::Alice.to_account_id(), + Sr25519Keyring::Bob.to_account_id(), + Sr25519Keyring::AliceStash.to_account_id(), + Sr25519Keyring::BobStash.to_account_id(), + ], + ROC * 1_000_000, + 1000.into(), + ), + _ => return None, + }; + + Some( + serde_json::to_string(&patch) + .expect("serialization to json is expected to work. qed.") + .into_bytes(), + ) +} + +/// List of supported presets. +pub fn preset_names() -> Vec { + use preset_names::*; + vec![ + PresetId::from(PRESET_GENESIS), + PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET), + PresetId::from(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET), + ] +} 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 f09647854cd0..ae5d2102ff66 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/lib.rs @@ -24,6 +24,7 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +mod genesis_config_presets; mod weights; pub mod xcm_config; @@ -37,7 +38,7 @@ use assets_common::{ AssetIdForTrustBackedAssetsConvert, }; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; -use cumulus_primitives_core::AggregateMessageOrigin; +use cumulus_primitives_core::{AggregateMessageOrigin, ClaimQueueOffset, CoreSelector}; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ @@ -61,8 +62,7 @@ use frame_support::{ ord_parameter_types, parameter_types, traits::{ fungible, fungibles, tokens::imbalance::ResolveAssetTo, AsEnsureOriginWithArg, ConstBool, - ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Equals, InstanceFilter, - TransformOrigin, + ConstU128, ConstU32, ConstU64, ConstU8, EitherOfDiverse, InstanceFilter, TransformOrigin, }, weights::{ConstantMultiplier, Weight, WeightToFee as _}, BoundedVec, PalletId, @@ -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; @@ -100,7 +103,7 @@ use xcm::latest::prelude::{ }; use xcm::{ latest::prelude::{AssetId, BodyId}, - VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, + VersionedAsset, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, }; use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, @@ -120,11 +123,11 @@ 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_016_002, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 16, - state_version: 1, + system_version: 1, }; /// The version information used to identify this runtime when compiled natively. @@ -172,6 +175,7 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = frame_support::traits::ConstU32<16>; @@ -210,6 +214,7 @@ impl pallet_balances::Config for Runtime { type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxFreezes = ConstU32<0>; + type DoneSlashHandler = (); } parameter_types! { @@ -225,6 +230,7 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; type OperationalFeeMultiplier = ConstU8<5>; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -262,7 +268,7 @@ impl pallet_assets::Config for Runtime { type Freezer = AssetsFreezer; type Extra = (); type WeightInfo = weights::pallet_assets_local::WeightInfo; - type CallbackHandle = (); + type CallbackHandle = pallet_assets::AutoIncAssetId; type AssetAccountDeposit = AssetAccountDeposit; type RemoveItemsLimit = frame_support::traits::ConstU32<1000>; #[cfg(feature = "runtime-benchmarks")] @@ -324,11 +330,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 +342,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 +368,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 +378,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 +415,18 @@ 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, + xcm_config::bridging::to_westend::WestendOrEthereumAssetFromAssetHubWestend, ), ForeignCreatorsSovereignAccountOf, AccountId, - xcm::v3::Location, + xcm::v4::Location, >; type ForceOrigin = AssetsForceOrigin; type AssetDeposit = ForeignAssetsAssetDeposit; @@ -542,7 +549,8 @@ impl InstanceFilter for ProxyType { RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } | RuntimeCall::NftFractionalization { .. } | - RuntimeCall::Nfts { .. } | RuntimeCall::Uniques { .. } + RuntimeCall::Nfts { .. } | + RuntimeCall::Uniques { .. } ) }, ProxyType::AssetOwner => matches!( @@ -663,6 +671,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type ReservedXcmpWeight = ReservedXcmpWeight; type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; type ConsensusHook = ConsensusHook; + type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector; } type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< @@ -798,11 +807,22 @@ 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, + >; + type WeightInfo = weights::pallet_asset_conversion_tx_payment::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = AssetConversionTxHelper; } parameter_types! { @@ -854,7 +874,7 @@ impl pallet_nft_fractionalization::Config for Runtime { type Assets = Assets; type Nfts = Nfts; type PalletId = NftFractionalizationPalletId; - type WeightInfo = pallet_nft_fractionalization::weights::SubstrateWeight; + type WeightInfo = weights::pallet_nft_fractionalization::WeightInfo; type RuntimeHoldReason = RuntimeHoldReason; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); @@ -904,29 +924,18 @@ impl pallet_nfts::Config for Runtime { /// consensus with dynamic fees and back-pressure. pub type ToWestendXcmRouterInstance = pallet_xcm_bridge_hub_router::Instance3; impl pallet_xcm_bridge_hub_router::Config for Runtime { + type RuntimeEvent = RuntimeEvent; type WeightInfo = weights::pallet_xcm_bridge_hub_router::WeightInfo; type UniversalLocation = xcm_config::UniversalLocation; + type SiblingBridgeHubLocation = xcm_config::bridging::SiblingBridgeHub; type BridgedNetworkId = xcm_config::bridging::to_westend::WestendNetwork; type Bridges = xcm_config::bridging::NetworkExportTable; type DestinationVersion = PolkadotXcm; - #[cfg(not(feature = "runtime-benchmarks"))] - type BridgeHubOrigin = EnsureXcm>; - #[cfg(feature = "runtime-benchmarks")] - type BridgeHubOrigin = EitherOfDiverse< - // for running benchmarks - EnsureRoot, - // for running tests with `--feature runtime-benchmarks` - EnsureXcm>, - >; - type ToBridgeHubSender = XcmpQueue; - type WithBridgeHubChannel = - cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider< - xcm_config::bridging::SiblingBridgeHubParaId, - Runtime, - >; + type LocalXcmChannelManager = + cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider; type ByteFee = xcm_config::bridging::XcmBridgeHubRouterByteFee; type FeeAsset = xcm_config::bridging::XcmBridgeHubRouterFeeAssetId; @@ -994,8 +1003,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -1009,9 +1018,8 @@ pub type SignedExtra = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. -#[allow(deprecated)] pub type Migrations = ( InitStorageVersions, // unreleased @@ -1019,6 +1027,12 @@ pub type Migrations = ( cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, pallet_collator_selection::migration::v2::MigrationToV2, frame_support::migrations::RemovePallet, + // unreleased + pallet_assets::migration::next_asset_id::SetNextAssetId< + ConstU32<50_000_000>, + Runtime, + TrustBackedAssetsInstance, + >, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -1089,14 +1103,81 @@ pub type Executive = frame_executive::Executive< Migrations, >; +#[cfg(feature = "runtime-benchmarks")] +pub struct AssetConversionTxHelper; + +#[cfg(feature = "runtime-benchmarks")] +impl + pallet_asset_conversion_tx_payment::BenchmarkHelperTrait< + AccountId, + cumulus_primitives_core::Location, + cumulus_primitives_core::Location, + > for AssetConversionTxHelper +{ + fn create_asset_id_parameter(seed: u32) -> (Location, Location) { + // Use a different parachain' foreign assets pallet so that the asset is indeed foreign. + let asset_id = Location::new( + 1, + [ + cumulus_primitives_core::Junction::Parachain(3000), + cumulus_primitives_core::Junction::PalletInstance(53), + cumulus_primitives_core::Junction::GeneralIndex(seed.into()), + ], + ); + (asset_id.clone(), asset_id) + } + + fn setup_balances_and_pool(asset_id: cumulus_primitives_core::Location, account: AccountId) { + use frame_support::{assert_ok, traits::fungibles::Mutate}; + assert_ok!(ForeignAssets::force_create( + RuntimeOrigin::root(), + asset_id.clone().into(), + account.clone().into(), /* owner */ + true, /* is_sufficient */ + 1, + )); + + let lp_provider = account.clone(); + use frame_support::traits::Currency; + let _ = Balances::deposit_creating(&lp_provider, u64::MAX.into()); + assert_ok!(ForeignAssets::mint_into( + asset_id.clone().into(), + &lp_provider, + u64::MAX.into() + )); + + let token_native = alloc::boxed::Box::new(TokenLocation::get()); + let token_second = alloc::boxed::Box::new(asset_id); + + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(lp_provider.clone()), + token_native.clone(), + token_second.clone() + )); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(lp_provider.clone()), + token_native, + token_second, + (u32::MAX / 8).into(), // 1 desired + u32::MAX.into(), // 2 desired + 1, // 1 min + 1, // 2 min + lp_provider, + )); + } +} + #[cfg(feature = "runtime-benchmarks")] mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_assets, Local] [pallet_assets, Foreign] [pallet_assets, Pool] [pallet_asset_conversion, AssetConversion] + [pallet_asset_conversion_tx_payment, AssetTxPayment] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] @@ -1107,6 +1188,7 @@ mod benches { [pallet_uniques, Uniques] [pallet_utility, Utility] [pallet_timestamp, Timestamp] + [pallet_transaction_payment, TransactionPayment] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] @@ -1226,16 +1308,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() } } @@ -1326,7 +1408,23 @@ impl_runtime_apis! { impl xcm_runtime_apis::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { - let acceptable_assets = vec![AssetId(xcm_config::TokenLocation::get())]; + let native_token = xcm_config::TokenLocation::get(); + // We accept the native token to pay fees. + let mut acceptable_assets = vec![AssetId(native_token.clone())]; + // We also accept all assets in a pool with the native token. + acceptable_assets.extend( + pallet_asset_conversion::Pools::::iter_keys().filter_map( + |(asset_1, asset_2)| { + if asset_1 == native_token { + Some(asset_2.clone().into()) + } else if asset_2 == native_token { + Some(asset_1.clone().into()) + } else { + None + } + }, + ), + ); PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) } @@ -1384,6 +1482,12 @@ impl_runtime_apis! { } } + impl cumulus_primitives_core::GetCoreSelectorApi for Runtime { + fn core_selector() -> (CoreSelector, ClaimQueueOffset) { + ParachainSystem::core_selector() + } + } + #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { @@ -1412,6 +1516,7 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use pallet_xcm_bridge_hub_router::benchmarking::Pallet as XcmBridgeHubRouterBench; @@ -1446,6 +1551,7 @@ impl_runtime_apis! { use sp_storage::TrackedStorageKey; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -1760,11 +1866,20 @@ impl_runtime_apis! { } fn get_preset(id: &Option) -> Option> { - get_preset::(id, |_| None) + get_preset::(id, &genesis_config_presets::get_preset) } fn preset_names() -> Vec { - vec![] + genesis_config_presets::preset_names() + } + } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) } } } @@ -1773,64 +1888,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 000000000000..12c0bc4e1688 --- /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/block_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/block_weights.rs index e7fdb2aae2a0..41e30725e753 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/block_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/extrinsic_weights.rs index 1a4adb968bb7..3bd48f061bba 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/extrinsic_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..182410f20fff --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/frame_system_extensions.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/ +// --chain=asset-hub-rococo-dev + +#![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 `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_genesis() -> Weight { + // Proof Size summary in bytes: + // Measured: `54` + // Estimated: `3509` + // Minimum execution time: 3_637_000 picoseconds. + Weight::from_parts(6_382_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_mortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_immortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 561_000 picoseconds. + Weight::from_parts(2_705_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_316_000 picoseconds. + Weight::from_parts(5_771_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 511_000 picoseconds. + Weight::from_parts(2_575_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 501_000 picoseconds. + Weight::from_parts(2_595_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1533` + // Minimum execution time: 3_687_000 picoseconds. + Weight::from_parts(6_192_000, 0) + .saturating_add(Weight::from_parts(0, 1533)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs index f20790cde39c..33f111009ed0 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/mod.rs @@ -19,8 +19,10 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_asset_conversion; pub mod pallet_asset_conversion_ops; +pub mod pallet_asset_conversion_tx_payment; pub mod pallet_assets_foreign; pub mod pallet_assets_local; pub mod pallet_assets_pool; @@ -33,6 +35,7 @@ pub mod pallet_nfts; pub mod pallet_proxy; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_uniques; pub mod pallet_utility; pub mod pallet_xcm; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion_tx_payment.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion_tx_payment.rs new file mode 100644 index 000000000000..0a639b368af2 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_asset_conversion_tx_payment.rs @@ -0,0 +1,92 @@ +// 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 . + +//! Autogenerated weights for `pallet_asset_conversion_tx_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2024-01-04, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `Georges-MacBook-Pro.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_asset_conversion_tx_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/ +// --chain=asset-hub-rococo-dev + +#![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_asset_conversion_tx_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_asset_conversion_tx_payment::WeightInfo for WeightInfo { + fn charge_asset_tx_payment_zero() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_000_000 picoseconds. + Weight::from_parts(10_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn charge_asset_tx_payment_native() -> Weight { + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `3593` + // Minimum execution time: 209_000_000 picoseconds. + Weight::from_parts(212_000_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(2)) + } + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn charge_asset_tx_payment_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `631` + // Estimated: `7404` + // Minimum execution time: 1_228_000_000 picoseconds. + Weight::from_parts(1_268_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} 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 5148edb0ee9e..c76c1137335a 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 4ee235830aed..cf4f60042bc6 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 df7ad2c63386..2cd85de00989 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/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..035f9a6dbe51 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_transaction_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/ +// --chain=asset-hub-rococo-dev + +#![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_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn charge_transaction_payment() -> Weight { + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `3593` + // Minimum execution time: 33_363_000 picoseconds. + Weight::from_parts(38_793_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs index 0a86037391b4..00ecf239428f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_xcm_bridge_hub_router.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_bridge_hub_router` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-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: @@ -52,14 +52,14 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) - /// Storage: `ToWestendXcmRouter::Bridge` (r:1 w:1) - /// Proof: `ToWestendXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) + /// Storage: `ToWestendXcmRouter::DeliveryFeeFactor` (r:1 w:1) + /// Proof: `ToWestendXcmRouter::DeliveryFeeFactor` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) fn on_initialize_when_non_congested() -> Weight { // Proof Size summary in bytes: - // Measured: `154` + // Measured: `153` // Estimated: `5487` - // Minimum execution time: 8_078_000 picoseconds. - Weight::from_parts(8_455_000, 0) + // Minimum execution time: 12_993_000 picoseconds. + Weight::from_parts(13_428_000, 0) .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -72,55 +72,9 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `144` // Estimated: `5487` - // Minimum execution time: 4_291_000 picoseconds. - Weight::from_parts(4_548_000, 0) + // Minimum execution time: 6_305_000 picoseconds. + Weight::from_parts(6_536_000, 0) .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(2)) } - /// Storage: `ToWestendXcmRouter::Bridge` (r:1 w:1) - /// Proof: `ToWestendXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) - fn report_bridge_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `150` - // Estimated: `1502` - // Minimum execution time: 9_959_000 picoseconds. - Weight::from_parts(10_372_000, 0) - .saturating_add(Weight::from_parts(0, 1502)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) - /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) - /// Storage: UNKNOWN KEY `0x0973fe64c85043ba1c965cbc38eb63c7` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x0973fe64c85043ba1c965cbc38eb63c7` (r:1 w:0) - /// Storage: `ToWestendXcmRouter::Bridge` (r:1 w:1) - /// Proof: `ToWestendXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) - /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) - /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: Some(105506), added: 107981, mode: `MaxEncodedLen`) - fn send_message() -> Weight { - // Proof Size summary in bytes: - // Measured: `448` - // Estimated: `6388` - // Minimum execution time: 45_888_000 picoseconds. - Weight::from_parts(47_022_000, 0) - .saturating_add(Weight::from_parts(0, 6388)) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(4)) - } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/paritydb_weights.rs index 25679703831a..e0b1985c659c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/paritydb_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/paritydb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/rocksdb_weights.rs index 3dd817aa6f13..c6e91b2fcffb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/rocksdb_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/rocksdb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 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 03d3785dccbd..7478ba8893c1 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-15, 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_364_000 picoseconds. + Weight::from_parts(35_040_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_755_000 picoseconds. + Weight::from_parts(43_650_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: 103_037_000 picoseconds. + Weight::from_parts(105_732_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_095_000 picoseconds. + Weight::from_parts(1_220_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_117_000 picoseconds. + Weight::from_parts(110_416_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: 2_907_000 picoseconds. + Weight::from_parts(3_050_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: 24_965_000 picoseconds. + Weight::from_parts(25_687_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: 83_312_000 picoseconds. + Weight::from_parts(85_463_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: 49_874_000 picoseconds. + Weight::from_parts(51_165_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/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index bee6bcdf21cf..f6a883c03e9d 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -16,10 +16,10 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-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-15, 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: @@ -68,8 +68,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 440_298_000 picoseconds. - Weight::from_parts(446_508_000, 6196) + // Minimum execution time: 99_552_000 picoseconds. + Weight::from_parts(101_720_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -77,8 +77,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_313_000 picoseconds. - Weight::from_parts(3_422_000, 0) + // Minimum execution time: 659_000 picoseconds. + Weight::from_parts(706_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -86,58 +86,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3568` - // Minimum execution time: 9_691_000 picoseconds. - Weight::from_parts(9_948_000, 3568) + // Minimum execution time: 9_665_000 picoseconds. + Weight::from_parts(9_878_000, 3568) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 10_384_000 picoseconds. - Weight::from_parts(11_085_000, 0) + // Minimum execution time: 6_959_000 picoseconds. + Weight::from_parts(7_111_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_438_000 picoseconds. - Weight::from_parts(3_577_000, 0) + // Minimum execution time: 2_682_000 picoseconds. + Weight::from_parts(2_799_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_126_000 picoseconds. - Weight::from_parts(2_243_000, 0) + // Minimum execution time: 656_000 picoseconds. + Weight::from_parts(683_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_126_000 picoseconds. - Weight::from_parts(2_207_000, 0) + // Minimum execution time: 687_000 picoseconds. + Weight::from_parts(719_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_105_000 picoseconds. - Weight::from_parts(2_193_000, 0) + // Minimum execution time: 588_000 picoseconds. + Weight::from_parts(653_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_999_000 picoseconds. - Weight::from_parts(3_056_000, 0) + // Minimum execution time: 690_000 picoseconds. + Weight::from_parts(714_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_091_000 picoseconds. - Weight::from_parts(2_176_000, 0) + // Minimum execution time: 671_000 picoseconds. + Weight::from_parts(710_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -159,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 55_728_000 picoseconds. - Weight::from_parts(56_704_000, 6196) + // Minimum execution time: 67_374_000 picoseconds. + Weight::from_parts(68_899_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -170,8 +170,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `160` // Estimated: `3625` - // Minimum execution time: 12_839_000 picoseconds. - Weight::from_parts(13_457_000, 3625) + // Minimum execution time: 12_896_000 picoseconds. + Weight::from_parts(13_191_000, 3625) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -179,8 +179,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_116_000 picoseconds. - Weight::from_parts(2_219_000, 0) + // Minimum execution time: 634_000 picoseconds. + Weight::from_parts(677_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -200,8 +200,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 24_891_000 picoseconds. - Weight::from_parts(25_583_000, 3610) + // Minimum execution time: 28_197_000 picoseconds. + Weight::from_parts(28_752_000, 3610) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -211,44 +211,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_968_000 picoseconds. - Weight::from_parts(4_122_000, 0) + // Minimum execution time: 2_678_000 picoseconds. + Weight::from_parts(2_803_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 136_220_000 picoseconds. - Weight::from_parts(137_194_000, 0) + // Minimum execution time: 22_806_000 picoseconds. + Weight::from_parts(23_217_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 12_343_000 picoseconds. - Weight::from_parts(12_635_000, 0) + // Minimum execution time: 6_221_000 picoseconds. + Weight::from_parts(6_347_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_237_000 picoseconds. - Weight::from_parts(2_315_000, 0) + // Minimum execution time: 653_000 picoseconds. + Weight::from_parts(676_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_094_000 picoseconds. - Weight::from_parts(2_231_000, 0) + // Minimum execution time: 621_000 picoseconds. + Weight::from_parts(678_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_379_000 picoseconds. - Weight::from_parts(2_455_000, 0) + // Minimum execution time: 770_000 picoseconds. + Weight::from_parts(829_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -270,8 +270,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 60_734_000 picoseconds. - Weight::from_parts(61_964_000, 6196) + // Minimum execution time: 71_654_000 picoseconds. + Weight::from_parts(73_329_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -279,8 +279,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_500_000 picoseconds. - Weight::from_parts(5_720_000, 0) + // Minimum execution time: 3_999_000 picoseconds. + Weight::from_parts(4_179_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -302,8 +302,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 55_767_000 picoseconds. - Weight::from_parts(56_790_000, 6196) + // Minimum execution time: 66_722_000 picoseconds. + Weight::from_parts(68_812_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -311,22 +311,22 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_201_000 picoseconds. - Weight::from_parts(2_291_000, 0) + // Minimum execution time: 718_000 picoseconds. + Weight::from_parts(745_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_164_000 picoseconds. - Weight::from_parts(2_241_000, 0) + // Minimum execution time: 623_000 picoseconds. + Weight::from_parts(682_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_127_000 picoseconds. - Weight::from_parts(2_236_000, 0) + // Minimum execution time: 664_000 picoseconds. + Weight::from_parts(696_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -334,22 +334,22 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1489` - // Minimum execution time: 4_275_000 picoseconds. - Weight::from_parts(4_381_000, 1489) + // Minimum execution time: 2_495_000 picoseconds. + Weight::from_parts(2_604_000, 1489) .saturating_add(T::DbWeight::get().reads(1)) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_132_000 picoseconds. - Weight::from_parts(2_216_000, 0) + // Minimum execution time: 645_000 picoseconds. + Weight::from_parts(673_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_265_000 picoseconds. - Weight::from_parts(2_332_000, 0) + // Minimum execution time: 643_000 picoseconds. + Weight::from_parts(701_000, 0) } } 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 c736d3ee4420..32fbfb6d0199 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 @@ -21,7 +21,7 @@ use super::{ XcmpQueue, }; use assets_common::{ - matching::{FromNetwork, FromSiblingParachain, IsForeignConcreteAsset}, + matching::{FromNetwork, FromSiblingParachain, IsForeignConcreteAsset, ParentLocation}, TrustBackedAssetsAsLocation, }; use frame_support::{ @@ -43,7 +43,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 sp_runtime::traits::{AccountIdConversion, ConvertInto, TryConvertInto}; use testnet_parachains_constants::rococo::snowbridge::{ EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX, }; @@ -54,18 +54,18 @@ use xcm_builder::{ DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, GlobalConsensusParachainConvertsFor, HashedDescription, IsConcrete, LocalMint, - NetworkExportTableItem, NoChecking, NonFungiblesAdapter, ParentAsSuperuser, ParentIsPreset, - RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignPaidRemoteExporter, + MatchedConvertedConcreteId, NetworkExportTableItem, NoChecking, NonFungiblesAdapter, + ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount, + SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SingleAssetExchangeAdapter, SovereignPaidRemoteExporter, SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, + WithLatestLocationConverter, WithUniqueTopic, 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 +74,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 +175,7 @@ pub type ForeignAssetsConvertedConcreteId = assets_common::ForeignAssetsConverte StartsWithExplicitGlobalConsensus, ), Balance, - xcm::v3::Location, + xcm::v4::Location, >; /// Means for transacting foreign assets from different global consensus. @@ -329,6 +327,28 @@ pub type TrustedTeleporters = ( IsForeignConcreteAsset>>, ); +/// Asset converter for pool assets. +/// Used to convert one asset to another, when there is a pool available between the two. +/// This type thus allows paying fees with any asset as long as there is a pool between said +/// asset and the asset required for fee payment. +pub type PoolAssetsExchanger = SingleAssetExchangeAdapter< + crate::AssetConversion, + crate::NativeAndAssets, + ( + TrustBackedAssetsAsLocation, + ForeignAssetsConvertedConcreteId, + // `ForeignAssetsConvertedConcreteId` excludes the relay token, so we add it back here. + MatchedConvertedConcreteId< + xcm::v4::Location, + Balance, + Equals, + WithLatestLocationConverter, + TryConvertInto, + >, + ), + AccountId, +>; + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -341,8 +361,8 @@ impl xcm_executor::Config for XcmConfig { // to the Westend ecosystem. We also allow Ethereum contracts to act as reserves for the foreign // assets identified by the same respective contracts locations. type IsReserve = ( - bridging::to_westend::WestendAssetFromAssetHubWestend, - bridging::to_ethereum::IsTrustedBridgedReserveLocationForForeignAsset, + bridging::to_westend::WestendOrEthereumAssetFromAssetHubWestend, + bridging::to_ethereum::EthereumAssetFromEthereum, ); type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; @@ -361,7 +381,7 @@ impl xcm_executor::Config for XcmConfig { ResolveTo, >, cumulus_primitives_utility::SwapFirstAssetTrader< - TokenLocationV3, + TokenLocation, crate::AssetConversion, WeightToFee, crate::NativeAndAssets, @@ -369,7 +389,7 @@ impl xcm_executor::Config for XcmConfig { TrustBackedAssetsAsLocation< TrustBackedAssetsPalletLocation, Balance, - xcm::v3::Location, + xcm::v4::Location, >, ForeignAssetsConvertedConcreteId, ), @@ -410,10 +430,10 @@ impl xcm_executor::Config for XcmConfig { type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type AssetLocker = (); - type AssetExchanger = (); + type AssetExchanger = PoolAssetsExchanger; type FeeManager = XcmFeeManagerFromComponents< WaivedLocations, - XcmFeeToAccount, + SendXcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = @@ -497,14 +517,15 @@ pub type ForeignCreatorsSovereignAccountOf = ( AccountId32Aliases, ParentIsPreset, GlobalConsensusEthereumConvertsFor, + GlobalConsensusParachainConvertsFor, ); /// 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)]) } } @@ -569,7 +590,9 @@ pub mod bridging { ); pub const WestendNetwork: NetworkId = NetworkId::Westend; + pub const EthereumNetwork: NetworkId = NetworkId::Ethereum { chain_id: 11155111 }; pub WestendEcosystem: Location = Location::new(2, [GlobalConsensus(WestendNetwork::get())]); + pub EthereumEcosystem: Location = Location::new(2, [GlobalConsensus(EthereumNetwork::get())]); pub WndLocation: Location = Location::new(2, [GlobalConsensus(WestendNetwork::get())]); pub AssetHubWestend: Location = Location::new(2, [ GlobalConsensus(WestendNetwork::get()), @@ -607,20 +630,12 @@ pub mod bridging { } } - /// Allow any asset native to the Westend ecosystem if it comes from Westend Asset Hub. - pub type WestendAssetFromAssetHubWestend = - matching::RemoteAssetFromLocation, AssetHubWestend>; - - impl Contains for ToWestendXcmRouter { - fn contains(call: &RuntimeCall) -> bool { - matches!( - call, - RuntimeCall::ToWestendXcmRouter( - pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. } - ) - ) - } - } + /// Allow any asset native to the Westend or Ethereum ecosystems if it comes from Westend + /// Asset Hub. + pub type WestendOrEthereumAssetFromAssetHubWestend = matching::RemoteAssetFromLocation< + (StartsWith, StartsWith), + AssetHubWestend, + >; } pub mod to_ethereum { @@ -663,7 +678,7 @@ pub mod bridging { ); } - pub type IsTrustedBridgedReserveLocationForForeignAsset = + pub type EthereumAssetFromEthereum = IsForeignConcreteAsset>; impl Contains<(Location, Junction)> for UniversalAliases { 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 ee1461b7f9c8..6e10f9168990 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-rococo/tests/tests.rs @@ -27,7 +27,7 @@ use asset_hub_rococo_runtime::{ AllPalletsWithoutSystem, AssetConversion, AssetDeposit, Assets, Balances, CollatorSelection, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - SessionKeys, ToWestendXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue, + SessionKeys, TrustBackedAssetsInstance, XcmpQueue, }; use asset_test_utils::{ test_cases_over_bridge::TestBridgingConfig, CollatorSessionKey, CollatorSessionKeys, @@ -48,12 +48,14 @@ use frame_support::{ }; use parachains_common::{AccountId, AssetIdForTrustBackedAssets, AuraId, Balance}; use sp_consensus_aura::SlotDuration; +use sp_core::crypto::Ss58Codec; use sp_runtime::traits::MaybeEquivalence; use std::convert::Into; use testnet_parachains_constants::rococo::{consensus::*, currency::UNITS, fee::WeightToFee}; use xcm::latest::prelude::{Assets as XcmAssets, *}; use xcm_builder::WithLatestLocationConverter; use xcm_executor::traits::{JustTry, WeightTrader}; +use xcm_runtime_apis::conversions::LocationToAccountHelper; const ALICE: [u8; 32] = [1u8; 32]; const SOME_ASSET_ADMIN: [u8; 32] = [5u8; 32]; @@ -85,7 +87,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 +95,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 +107,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 +219,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 +262,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 +301,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 +313,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 +341,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 +351,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 +359,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 +371,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 +484,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 +499,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 +513,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 +521,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 +529,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 +818,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 +861,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 +870,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 +881,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 +907,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 +998,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 +1017,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 +1108,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 +1152,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 +1166,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 +1182,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 +1217,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 +1227,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 ); @@ -1265,94 +1237,6 @@ mod asset_hub_rococo_tests { ) } - #[test] - fn report_bridge_status_from_xcm_bridge_router_for_westend_works() { - asset_test_utils::test_cases_over_bridge::report_bridge_status_from_xcm_bridge_router_works::< - Runtime, - AllPalletsWithoutSystem, - XcmConfig, - LocationToAccountId, - ToWestendXcmRouterInstance, - >( - collator_session_keys(), - bridging_to_asset_hub_westend, - || { - vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind: OriginKind::Xcm, - require_weight_at_most: - bp_asset_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(), - call: bp_asset_hub_rococo::Call::ToWestendXcmRouter( - bp_asset_hub_rococo::XcmBridgeHubRouterCall::report_bridge_status { - bridge_id: Default::default(), - is_congested: true, - }, - ) - .encode() - .into(), - }, - ] - .into() - }, - || { - vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind: OriginKind::Xcm, - require_weight_at_most: - bp_asset_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(), - call: bp_asset_hub_rococo::Call::ToWestendXcmRouter( - bp_asset_hub_rococo::XcmBridgeHubRouterCall::report_bridge_status { - bridge_id: Default::default(), - is_congested: false, - }, - ) - .encode() - .into(), - }, - ] - .into() - }, - ) - } - - #[test] - fn test_report_bridge_status_call_compatibility() { - // if this test fails, make sure `bp_asset_hub_rococo` has valid encoding - assert_eq!( - RuntimeCall::ToWestendXcmRouter( - pallet_xcm_bridge_hub_router::Call::report_bridge_status { - bridge_id: Default::default(), - is_congested: true, - } - ) - .encode(), - bp_asset_hub_rococo::Call::ToWestendXcmRouter( - bp_asset_hub_rococo::XcmBridgeHubRouterCall::report_bridge_status { - bridge_id: Default::default(), - is_congested: true, - } - ) - .encode() - ); - } - - #[test] - fn check_sane_weight_report_bridge_status_for_westend() { - use pallet_xcm_bridge_hub_router::WeightInfo; - let actual = >::WeightInfo::report_bridge_status(); - let max_weight = bp_asset_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(); - assert!( - actual.all_lte(max_weight), - "max_weight: {:?} should be adjusted to actual {:?}", - max_weight, - actual - ); - } - #[test] fn reserve_transfer_native_asset_to_non_teleport_para_works() { asset_test_utils::test_cases::reserve_transfer_native_asset_to_non_teleport_para_works::< @@ -1473,3 +1357,112 @@ fn change_xcm_bridge_hub_ethereum_base_fee_by_governance_works() { }, ) } + +#[test] +fn location_conversion_works() { + // the purpose of hardcoded values is to catch an unintended location conversion logic change. + struct TestCase { + description: &'static str, + location: Location, + expected_account_id_str: &'static str, + } + + let test_cases = vec![ + // DescribeTerminus + TestCase { + description: "DescribeTerminus Parent", + location: Location::new(1, Here), + expected_account_id_str: "5Dt6dpkWPwLaH4BBCKJwjiWrFVAGyYk3tLUabvyn4v7KtESG", + }, + TestCase { + description: "DescribeTerminus Sibling", + location: Location::new(1, [Parachain(1111)]), + expected_account_id_str: "5Eg2fnssmmJnF3z1iZ1NouAuzciDaaDQH7qURAy3w15jULDk", + }, + // DescribePalletTerminal + TestCase { + description: "DescribePalletTerminal Parent", + location: Location::new(1, [PalletInstance(50)]), + expected_account_id_str: "5CnwemvaAXkWFVwibiCvf2EjqwiqBi29S5cLLydZLEaEw6jZ", + }, + TestCase { + description: "DescribePalletTerminal Sibling", + location: Location::new(1, [Parachain(1111), PalletInstance(50)]), + expected_account_id_str: "5GFBgPjpEQPdaxEnFirUoa51u5erVx84twYxJVuBRAT2UP2g", + }, + // DescribeAccountId32Terminal + TestCase { + description: "DescribeAccountId32Terminal Parent", + location: Location::new( + 1, + [AccountId32 { network: None, id: AccountId::from(ALICE).into() }], + ), + expected_account_id_str: "5DN5SGsuUG7PAqFL47J9meViwdnk9AdeSWKFkcHC45hEzVz4", + }, + TestCase { + description: "DescribeAccountId32Terminal Sibling", + location: Location::new( + 1, + [ + Parachain(1111), + Junction::AccountId32 { network: None, id: AccountId::from(ALICE).into() }, + ], + ), + expected_account_id_str: "5DGRXLYwWGce7wvm14vX1Ms4Vf118FSWQbJkyQigY2pfm6bg", + }, + // DescribeAccountKey20Terminal + TestCase { + description: "DescribeAccountKey20Terminal Parent", + location: Location::new(1, [AccountKey20 { network: None, key: [0u8; 20] }]), + expected_account_id_str: "5F5Ec11567pa919wJkX6VHtv2ZXS5W698YCW35EdEbrg14cg", + }, + TestCase { + description: "DescribeAccountKey20Terminal Sibling", + location: Location::new( + 1, + [Parachain(1111), AccountKey20 { network: None, key: [0u8; 20] }], + ), + expected_account_id_str: "5CB2FbUds2qvcJNhDiTbRZwiS3trAy6ydFGMSVutmYijpPAg", + }, + // DescribeTreasuryVoiceTerminal + TestCase { + description: "DescribeTreasuryVoiceTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]), + expected_account_id_str: "5CUjnE2vgcUCuhxPwFoQ5r7p1DkhujgvMNDHaF2bLqRp4D5F", + }, + TestCase { + description: "DescribeTreasuryVoiceTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Treasury, part: BodyPart::Voice }], + ), + expected_account_id_str: "5G6TDwaVgbWmhqRUKjBhRRnH4ry9L9cjRymUEmiRsLbSE4gB", + }, + // DescribeBodyTerminal + TestCase { + description: "DescribeBodyTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Unit, part: BodyPart::Voice }]), + expected_account_id_str: "5EBRMTBkDisEXsaN283SRbzx9Xf2PXwUxxFCJohSGo4jYe6B", + }, + TestCase { + description: "DescribeBodyTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Unit, part: BodyPart::Voice }], + ), + expected_account_id_str: "5DBoExvojy8tYnHgLL97phNH975CyT45PWTZEeGoBZfAyRMH", + }, + ]; + + for tc in test_cases { + let expected = + AccountId::from_string(tc.expected_account_id_str).expect("Invalid AccountId string"); + + let got = LocationToAccountHelper::::convert_location( + tc.location.into(), + ) + .unwrap(); + + assert_eq!(got, expected, "{}", tc.description); + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml index 6b1bf769ace3..5fa48381b674 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/Cargo.toml @@ -14,6 +14,7 @@ codec = { features = ["derive", "max-encoded-len"], workspace = true } hex-literal = { workspace = true, default-features = true } log = { workspace = true } scale-info = { features = ["derive"], workspace = true } +serde_json = { features = ["alloc"], workspace = true } # Substrate frame-benchmarking = { optional = true, workspace = true } @@ -48,11 +49,13 @@ sp-api = { workspace = true } sp-block-builder = { workspace = true } sp-consensus-aura = { workspace = true } sp-core = { workspace = true } +sp-keyring = { workspace = true } sp-genesis-builder = { workspace = true } 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 +96,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 } @@ -114,6 +118,7 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-asset-conversion-ops/runtime-benchmarks", + "pallet-asset-conversion-tx-payment/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", "pallet-assets-freezer/runtime-benchmarks", "pallet-assets/runtime-benchmarks", @@ -126,6 +131,7 @@ runtime-benchmarks = [ "pallet-proxy/runtime-benchmarks", "pallet-state-trie-migration/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-uniques/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", @@ -134,6 +140,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,15 +237,19 @@ std = [ "polkadot-runtime-common/std", "primitive-types/std", "scale-info/std", + "serde_json/std", + "snowbridge-router-primitives/std", "sp-api/std", "sp-block-builder/std", "sp-consensus-aura/std", "sp-core/std", "sp-genesis-builder/std", "sp-inherents/std", + "sp-keyring/std", "sp-offchain/std", "sp-runtime/std", "sp-session/std", + "sp-std/std", "sp-storage/std", "sp-transaction-pool/std", "sp-version/std", @@ -257,4 +268,4 @@ metadata-hash = ["substrate-wasm-builder/metadata-hash"] # A feature that should be enabled when the runtime should be built for on-chain # deployment. This will disable stuff that shouldn't be part of the on-chain wasm # to make it smaller, like logging for example. -on-chain-release-build = ["metadata-hash", "sp-api/disable-logging"] +on-chain-release-build = ["metadata-hash"] diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/genesis_config_presets.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/genesis_config_presets.rs new file mode 100644 index 000000000000..758ce3f40609 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/genesis_config_presets.rs @@ -0,0 +1,148 @@ +// 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. + +//! # Asset Hub Westend Runtime genesis config presets + +use crate::*; +use alloc::{vec, vec::Vec}; +use cumulus_primitives_core::ParaId; +use hex_literal::hex; +use parachains_common::{AccountId, AuraId}; +use sp_core::crypto::UncheckedInto; +use sp_genesis_builder::PresetId; +use sp_keyring::Sr25519Keyring; +use testnet_parachains_constants::westend::{ + currency::UNITS as WND, xcm_version::SAFE_XCM_VERSION, +}; + +const ASSET_HUB_WESTEND_ED: Balance = ExistentialDeposit::get(); + +fn asset_hub_westend_genesis( + invulnerables: Vec<(AccountId, AuraId)>, + endowed_accounts: Vec, + endowment: Balance, + id: ParaId, +) -> serde_json::Value { + let config = RuntimeGenesisConfig { + balances: BalancesConfig { + balances: endowed_accounts.iter().cloned().map(|k| (k, endowment)).collect(), + }, + parachain_info: ParachainInfoConfig { parachain_id: id, ..Default::default() }, + collator_selection: CollatorSelectionConfig { + invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: ASSET_HUB_WESTEND_ED * 16, + ..Default::default() + }, + session: SessionConfig { + keys: invulnerables + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + SessionKeys { aura }, // session keys + ) + }) + .collect(), + ..Default::default() + }, + polkadot_xcm: PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + ..Default::default() + }; + + serde_json::to_value(config).expect("Could not build genesis config.") +} + +/// Encapsulates names of predefined presets. +mod preset_names { + pub const PRESET_GENESIS: &str = "genesis"; +} + +/// Provides the JSON representation of predefined genesis config for given `id`. +pub fn get_preset(id: &PresetId) -> Option> { + use preset_names::*; + let patch = match id.try_into() { + Ok(PRESET_GENESIS) => asset_hub_westend_genesis( + // initial collators. + vec![ + ( + hex!("9cfd429fa002114f33c1d3e211501d62830c9868228eb3b4b8ae15a83de04325").into(), + hex!("9cfd429fa002114f33c1d3e211501d62830c9868228eb3b4b8ae15a83de04325") + .unchecked_into(), + ), + ( + hex!("12a03fb4e7bda6c9a07ec0a11d03c24746943e054ff0bb04938970104c783876").into(), + hex!("12a03fb4e7bda6c9a07ec0a11d03c24746943e054ff0bb04938970104c783876") + .unchecked_into(), + ), + ( + hex!("1256436307dfde969324e95b8c62cb9101f520a39435e6af0f7ac07b34e1931f").into(), + hex!("1256436307dfde969324e95b8c62cb9101f520a39435e6af0f7ac07b34e1931f") + .unchecked_into(), + ), + ( + hex!("98102b7bca3f070f9aa19f58feed2c0a4e107d203396028ec17a47e1ed80e322").into(), + hex!("98102b7bca3f070f9aa19f58feed2c0a4e107d203396028ec17a47e1ed80e322") + .unchecked_into(), + ), + ], + Vec::new(), + ASSET_HUB_WESTEND_ED * 4096, + 1000.into(), + ), + Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) => asset_hub_westend_genesis( + // initial collators. + vec![ + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), + ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), + WND * 1_000_000, + 1000.into(), + ), + Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => asset_hub_westend_genesis( + // initial collators. + vec![(Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into())], + vec![ + Sr25519Keyring::Alice.to_account_id(), + Sr25519Keyring::Bob.to_account_id(), + Sr25519Keyring::AliceStash.to_account_id(), + Sr25519Keyring::BobStash.to_account_id(), + ], + WND * 1_000_000, + 1000.into(), + ), + _ => return None, + }; + + Some( + serde_json::to_string(&patch) + .expect("serialization to json is expected to work. qed.") + .into_bytes(), + ) +} + +/// List of supported presets. +pub fn preset_names() -> Vec { + use preset_names::*; + vec![ + PresetId::from(PRESET_GENESIS), + PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET), + PresetId::from(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET), + ] +} 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 178b886fc3e8..0da80098b28f 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/lib.rs @@ -24,6 +24,7 @@ #[cfg(feature = "std")] include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +mod genesis_config_presets; mod weights; pub mod xcm_config; @@ -36,7 +37,7 @@ use assets_common::{ }; use codec::{Decode, Encode, MaxEncodedLen}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; -use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +use cumulus_primitives_core::{AggregateMessageOrigin, ClaimQueueOffset, CoreSelector, ParaId}; use frame_support::{ construct_runtime, derive_impl, dispatch::DispatchClass, @@ -45,8 +46,8 @@ use frame_support::{ traits::{ fungible, fungibles, tokens::{imbalance::ResolveAssetTo, nonfungibles_v2::Inspect}, - AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, Equals, - InstanceFilter, TransformOrigin, + AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, InstanceFilter, + TransformOrigin, }, weights::{ConstantMultiplier, Weight, WeightToFee as _}, BoundedVec, PalletId, @@ -55,9 +56,8 @@ 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::{ impls::DealWithFees, message_queue::*, AccountId, AssetIdForTrustBackedAssets, AuraId, Balance, BlockNumber, CollectionId, Hash, Header, ItemId, Nonce, Signature, AVERAGE_ON_INITIALIZE_RATIO, @@ -74,22 +74,26 @@ 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, - prelude::{VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}, + prelude::{VersionedAsset, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm}, }; #[cfg(feature = "runtime-benchmarks")] @@ -119,11 +123,11 @@ 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_016_002, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 16, - state_version: 1, + system_version: 1, }; /// The version information used to identify this runtime when compiled natively. @@ -171,6 +175,7 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = frame_support::traits::ConstU32<16>; @@ -209,6 +214,7 @@ impl pallet_balances::Config for Runtime { type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxFreezes = ConstU32<0>; + type DoneSlashHandler = (); } parameter_types! { @@ -224,6 +230,7 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; type OperationalFeeMultiplier = ConstU8<5>; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -260,7 +267,7 @@ impl pallet_assets::Config for Runtime { type Freezer = AssetsFreezer; type Extra = (); type WeightInfo = weights::pallet_assets_local::WeightInfo; - type CallbackHandle = (); + type CallbackHandle = pallet_assets::AutoIncAssetId; type AssetAccountDeposit = AssetAccountDeposit; type RemoveItemsLimit = ConstU32<1000>; #[cfg(feature = "runtime-benchmarks")] @@ -321,11 +328,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 +340,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 +366,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 +376,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 +413,18 @@ 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, + xcm_config::bridging::to_rococo::RococoAssetFromAssetHubRococo, + ), ForeignCreatorsSovereignAccountOf, AccountId, - xcm::v3::Location, + xcm::v4::Location, >; type ForceOrigin = AssetsForceOrigin; type AssetDeposit = ForeignAssetsAssetDeposit; @@ -536,7 +547,8 @@ impl InstanceFilter for ProxyType { RuntimeCall::Utility { .. } | RuntimeCall::Multisig { .. } | RuntimeCall::NftFractionalization { .. } | - RuntimeCall::Nfts { .. } | RuntimeCall::Uniques { .. } + RuntimeCall::Nfts { .. } | + RuntimeCall::Uniques { .. } ) }, ProxyType::AssetOwner => matches!( @@ -657,6 +669,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type ReservedXcmpWeight = ReservedXcmpWeight; type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; type ConsensusHook = ConsensusHook; + type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector; } type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< @@ -787,11 +800,22 @@ 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, + >; + type WeightInfo = weights::pallet_asset_conversion_tx_payment::WeightInfo; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = AssetConversionTxHelper; } parameter_types! { @@ -843,7 +867,7 @@ impl pallet_nft_fractionalization::Config for Runtime { type Assets = Assets; type Nfts = Nfts; type PalletId = NftFractionalizationPalletId; - type WeightInfo = pallet_nft_fractionalization::weights::SubstrateWeight; + type WeightInfo = weights::pallet_nft_fractionalization::WeightInfo; type RuntimeHoldReason = RuntimeHoldReason; #[cfg(feature = "runtime-benchmarks")] type BenchmarkHelper = (); @@ -893,29 +917,18 @@ impl pallet_nfts::Config for Runtime { /// consensus with dynamic fees and back-pressure. pub type ToRococoXcmRouterInstance = pallet_xcm_bridge_hub_router::Instance1; impl pallet_xcm_bridge_hub_router::Config for Runtime { + type RuntimeEvent = RuntimeEvent; type WeightInfo = weights::pallet_xcm_bridge_hub_router::WeightInfo; type UniversalLocation = xcm_config::UniversalLocation; + type SiblingBridgeHubLocation = xcm_config::bridging::SiblingBridgeHub; type BridgedNetworkId = xcm_config::bridging::to_rococo::RococoNetwork; type Bridges = xcm_config::bridging::NetworkExportTable; type DestinationVersion = PolkadotXcm; - #[cfg(not(feature = "runtime-benchmarks"))] - type BridgeHubOrigin = EnsureXcm>; - #[cfg(feature = "runtime-benchmarks")] - type BridgeHubOrigin = frame_support::traits::EitherOfDiverse< - // for running benchmarks - EnsureRoot, - // for running tests with `--feature runtime-benchmarks` - EnsureXcm>, - >; - type ToBridgeHubSender = XcmpQueue; - type WithBridgeHubChannel = - cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider< - xcm_config::bridging::SiblingBridgeHubParaId, - Runtime, - >; + type LocalXcmChannelManager = + cumulus_pallet_xcmp_queue::bridging::InAndOutXcmpChannelStatusProvider; type ByteFee = xcm_config::bridging::XcmBridgeHubRouterByteFee; type FeeAsset = xcm_config::bridging::XcmBridgeHubRouterFeeAssetId; @@ -986,8 +999,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -1001,7 +1014,7 @@ pub type SignedExtra = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -1018,6 +1031,12 @@ pub type Migrations = ( // unreleased cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, + // unreleased + pallet_assets::migration::next_asset_id::SetNextAssetId< + ConstU32<50_000_000>, + Runtime, + TrustBackedAssetsInstance, + >, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -1134,14 +1153,86 @@ pub type Executive = frame_executive::Executive< Migrations, >; +#[cfg(feature = "runtime-benchmarks")] +pub struct AssetConversionTxHelper; + +#[cfg(feature = "runtime-benchmarks")] +impl + pallet_asset_conversion_tx_payment::BenchmarkHelperTrait< + AccountId, + cumulus_primitives_core::Location, + cumulus_primitives_core::Location, + > for AssetConversionTxHelper +{ + fn create_asset_id_parameter( + seed: u32, + ) -> (cumulus_primitives_core::Location, cumulus_primitives_core::Location) { + // Use a different parachain' foreign assets pallet so that the asset is indeed foreign. + let asset_id = cumulus_primitives_core::Location::new( + 1, + [ + cumulus_primitives_core::Junction::Parachain(3000), + cumulus_primitives_core::Junction::PalletInstance(53), + cumulus_primitives_core::Junction::GeneralIndex(seed.into()), + ], + ); + (asset_id.clone(), asset_id) + } + + fn setup_balances_and_pool(asset_id: cumulus_primitives_core::Location, account: AccountId) { + use frame_support::{assert_ok, traits::fungibles::Mutate}; + assert_ok!(ForeignAssets::force_create( + RuntimeOrigin::root(), + asset_id.clone().into(), + account.clone().into(), /* owner */ + true, /* is_sufficient */ + 1, + )); + + let lp_provider = account.clone(); + use frame_support::traits::Currency; + let _ = Balances::deposit_creating(&lp_provider, u64::MAX.into()); + assert_ok!(ForeignAssets::mint_into( + asset_id.clone().into(), + &lp_provider, + u64::MAX.into() + )); + + let token_native = alloc::boxed::Box::new(cumulus_primitives_core::Location::new( + 1, + cumulus_primitives_core::Junctions::Here, + )); + let token_second = alloc::boxed::Box::new(asset_id); + + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(lp_provider.clone()), + token_native.clone(), + token_second.clone() + )); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(lp_provider.clone()), + token_native, + token_second, + (u32::MAX / 2).into(), // 1 desired + u32::MAX.into(), // 2 desired + 1, // 1 min + 1, // 2 min + lp_provider, + )); + } +} + #[cfg(feature = "runtime-benchmarks")] mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_assets, Local] [pallet_assets, Foreign] [pallet_assets, Pool] [pallet_asset_conversion, AssetConversion] + [pallet_asset_conversion_tx_payment, AssetTxPayment] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] @@ -1152,6 +1243,7 @@ mod benches { [pallet_uniques, Uniques] [pallet_utility, Utility] [pallet_timestamp, Timestamp] + [pallet_transaction_payment, TransactionPayment] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] @@ -1315,18 +1407,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() } } @@ -1354,7 +1446,23 @@ impl_runtime_apis! { impl xcm_runtime_apis::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { - let acceptable_assets = vec![AssetId(xcm_config::WestendLocation::get())]; + let native_token = xcm_config::WestendLocation::get(); + // We accept the native token to pay fees. + let mut acceptable_assets = vec![AssetId(native_token.clone())]; + // We also accept all assets in a pool with the native token. + acceptable_assets.extend( + pallet_asset_conversion::Pools::::iter_keys().filter_map( + |(asset_1, asset_2)| { + if asset_1 == native_token { + Some(asset_2.clone().into()) + } else if asset_2 == native_token { + Some(asset_1.clone().into()) + } else { + None + } + }, + ), + ); PolkadotXcm::query_acceptable_payment_assets(xcm_version, acceptable_assets) } @@ -1475,6 +1583,12 @@ impl_runtime_apis! { } } + impl cumulus_primitives_core::GetCoreSelectorApi for Runtime { + fn core_selector() -> (CoreSelector, ClaimQueueOffset) { + ParachainSystem::core_selector() + } + } + #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { @@ -1503,6 +1617,7 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use pallet_xcm_bridge_hub_router::benchmarking::Pallet as XcmBridgeHubRouterBench; @@ -1537,6 +1652,7 @@ impl_runtime_apis! { use sp_storage::TrackedStorageKey; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -1851,11 +1967,20 @@ impl_runtime_apis! { } fn get_preset(id: &Option) -> Option> { - get_preset::(id, |_| None) + get_preset::(id, &genesis_config_presets::get_preset) } fn preset_names() -> Vec { - vec![] + genesis_config_presets::preset_names() + } + } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) } } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/block_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/block_weights.rs index e7fdb2aae2a0..41e30725e753 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/block_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_parachain_system.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_parachain_system.rs index fc63a0814d0a..ef1a6a41cef9 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_parachain_system.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/cumulus_pallet_parachain_system.rs @@ -77,4 +77,4 @@ impl cumulus_pallet_parachain_system::WeightInfo for We .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } -} +} \ No newline at end of file diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/extrinsic_weights.rs index 1a4adb968bb7..3bd48f061bba 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/extrinsic_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..e8dd9763c282 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/ +// --chain=asset-hub-westend-dev + +#![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 `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_genesis() -> Weight { + // Proof Size summary in bytes: + // Measured: `54` + // Estimated: `3509` + // Minimum execution time: 3_206_000 picoseconds. + Weight::from_parts(6_212_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_mortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_851_000 picoseconds. + Weight::from_parts(8_847_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_immortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_851_000 picoseconds. + Weight::from_parts(8_847_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 631_000 picoseconds. + Weight::from_parts(3_086_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_446_000 picoseconds. + Weight::from_parts(5_911_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 481_000 picoseconds. + Weight::from_parts(2_916_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 501_000 picoseconds. + Weight::from_parts(2_595_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1533` + // Minimum execution time: 3_927_000 picoseconds. + Weight::from_parts(6_613_000, 0) + .saturating_add(Weight::from_parts(0, 1533)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs index 4eebb1f8d786..b0f986768f40 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/mod.rs @@ -18,8 +18,10 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_asset_conversion; pub mod pallet_asset_conversion_ops; +pub mod pallet_asset_conversion_tx_payment; pub mod pallet_assets_foreign; pub mod pallet_assets_local; pub mod pallet_assets_pool; @@ -32,6 +34,7 @@ pub mod pallet_nfts; pub mod pallet_proxy; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_uniques; pub mod pallet_utility; pub mod pallet_xcm; diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion_tx_payment.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion_tx_payment.rs new file mode 100644 index 000000000000..8fe302630fb9 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_asset_conversion_tx_payment.rs @@ -0,0 +1,92 @@ +// 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 . + +//! Autogenerated weights for `pallet_asset_conversion_tx_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2024-01-04, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `Georges-MacBook-Pro.local`, CPU: `` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_asset_conversion_tx_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/ +// --chain=asset-hub-westend-dev + +#![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_asset_conversion_tx_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_asset_conversion_tx_payment::WeightInfo for WeightInfo { + fn charge_asset_tx_payment_zero() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(9_000_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn charge_asset_tx_payment_native() -> Weight { + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `3593` + // Minimum execution time: 214_000_000 picoseconds. + Weight::from_parts(219_000_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(2)) + } + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Asset` (r:1 w:1) + /// Proof: `ForeignAssets::Asset` (`max_values`: None, `max_size`: Some(808), added: 3283, mode: `MaxEncodedLen`) + /// Storage: `ForeignAssets::Account` (r:2 w:2) + /// Proof: `ForeignAssets::Account` (`max_values`: None, `max_size`: Some(732), added: 3207, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn charge_asset_tx_payment_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `631` + // Estimated: `7404` + // Minimum execution time: 1_211_000_000 picoseconds. + Weight::from_parts(1_243_000_000, 0) + .saturating_add(Weight::from_parts(0, 7404)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) + } +} 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 52ba2fd6c40f..2692de9aeb50 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 e78366b91cbe..d2e12549a45c 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 65cae81069c4..8368f6e583cc 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/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..b4c78a78b489 --- /dev/null +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("asset-hub-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_transaction_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/ +// --chain=asset-hub-westend-dev + +#![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_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn charge_transaction_payment() -> Weight { + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `3593` + // Minimum execution time: 40_847_000 picoseconds. + Weight::from_parts(49_674_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs index 21d15c75af55..c0898012e9f3 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/pallet_xcm_bridge_hub_router.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_bridge_hub_router` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-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: @@ -52,14 +52,14 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) - /// Storage: `ToRococoXcmRouter::Bridge` (r:1 w:1) - /// Proof: `ToRococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) + /// Storage: `ToRococoXcmRouter::DeliveryFeeFactor` (r:1 w:1) + /// Proof: `ToRococoXcmRouter::DeliveryFeeFactor` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) fn on_initialize_when_non_congested() -> Weight { // Proof Size summary in bytes: - // Measured: `226` + // Measured: `225` // Estimated: `5487` - // Minimum execution time: 8_363_000 picoseconds. - Weight::from_parts(8_620_000, 0) + // Minimum execution time: 13_483_000 picoseconds. + Weight::from_parts(13_862_000, 0) .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -72,55 +72,9 @@ impl pallet_xcm_bridge_hub_router::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `111` // Estimated: `5487` - // Minimum execution time: 3_436_000 picoseconds. - Weight::from_parts(3_586_000, 0) + // Minimum execution time: 5_078_000 picoseconds. + Weight::from_parts(5_233_000, 0) .saturating_add(Weight::from_parts(0, 5487)) .saturating_add(T::DbWeight::get().reads(2)) } - /// Storage: `ToRococoXcmRouter::Bridge` (r:1 w:1) - /// Proof: `ToRococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) - fn report_bridge_status() -> Weight { - // Proof Size summary in bytes: - // Measured: `150` - // Estimated: `1502` - // Minimum execution time: 9_706_000 picoseconds. - Weight::from_parts(10_139_000, 0) - .saturating_add(Weight::from_parts(0, 1502)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) - /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) - /// Storage: UNKNOWN KEY `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x3302afcb67e838a3f960251b417b9a4f` (r:1 w:0) - /// Storage: UNKNOWN KEY `0x0973fe64c85043ba1c965cbc38eb63c7` (r:1 w:0) - /// Proof: UNKNOWN KEY `0x0973fe64c85043ba1c965cbc38eb63c7` (r:1 w:0) - /// Storage: `ToRococoXcmRouter::Bridge` (r:1 w:1) - /// Proof: `ToRococoXcmRouter::Bridge` (`max_values`: Some(1), `max_size`: Some(17), added: 512, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) - /// Proof: `XcmpQueue::DeliveryFeeFactor` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) - /// Storage: `PolkadotXcm::SupportedVersion` (r:2 w:0) - /// Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::VersionDiscoveryQueue` (r:1 w:1) - /// Proof: `PolkadotXcm::VersionDiscoveryQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `PolkadotXcm::SafeXcmVersion` (r:1 w:0) - /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) - /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::InboundXcmpSuspended` (r:1 w:0) - /// Proof: `XcmpQueue::InboundXcmpSuspended` (`max_values`: Some(1), `max_size`: Some(4002), added: 4497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) - /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: Some(105506), added: 107981, mode: `MaxEncodedLen`) - fn send_message() -> Weight { - // Proof Size summary in bytes: - // Measured: `520` - // Estimated: `6460` - // Minimum execution time: 46_250_000 picoseconds. - Weight::from_parts(47_801_000, 0) - .saturating_add(Weight::from_parts(0, 6460)) - .saturating_add(T::DbWeight::get().reads(12)) - .saturating_add(T::DbWeight::get().writes(4)) - } } diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/paritydb_weights.rs index 25679703831a..e0b1985c659c 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/paritydb_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/paritydb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/rocksdb_weights.rs index 3dd817aa6f13..c6e91b2fcffb 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/rocksdb_weights.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/rocksdb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 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 fe8d18613925..0aeae3184627 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-15, 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_651_000 picoseconds. + Weight::from_parts(33_225_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_059_000 picoseconds. + Weight::from_parts(41_730_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: 102_780_000 picoseconds. + Weight::from_parts(105_302_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_124_000 picoseconds. + Weight::from_parts(1_201_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: 109_024_000 picoseconds. + Weight::from_parts(111_406_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: 2_887_000 picoseconds. + Weight::from_parts(3_081_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_234_000 picoseconds. + Weight::from_parts(25_561_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: 83_416_000 picoseconds. + Weight::from_parts(85_683_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: 49_271_000 picoseconds. + Weight::from_parts(51_019_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/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 127bc173c103..98ecd7bd3092 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -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::generic` //! -//! 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-15, 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: @@ -67,8 +68,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 415_033_000 picoseconds. - Weight::from_parts(429_573_000, 6196) + // Minimum execution time: 100_823_000 picoseconds. + Weight::from_parts(103_071_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -76,8 +77,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_193_000 picoseconds. - Weight::from_parts(3_620_000, 0) + // Minimum execution time: 600_000 picoseconds. + Weight::from_parts(686_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -85,58 +86,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `103` // Estimated: `3568` - // Minimum execution time: 8_045_000 picoseconds. - Weight::from_parts(8_402_000, 3568) + // Minimum execution time: 8_226_000 picoseconds. + Weight::from_parts(8_650_000, 3568) .saturating_add(T::DbWeight::get().reads(1)) } pub fn transact() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_827_000 picoseconds. - Weight::from_parts(10_454_000, 0) + // Minimum execution time: 7_131_000 picoseconds. + Weight::from_parts(7_600_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_330_000 picoseconds. - Weight::from_parts(3_677_000, 0) + // Minimum execution time: 2_589_000 picoseconds. + Weight::from_parts(2_705_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_947_000 picoseconds. - Weight::from_parts(2_083_000, 0) + // Minimum execution time: 667_000 picoseconds. + Weight::from_parts(744_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_915_000 picoseconds. - Weight::from_parts(1_993_000, 0) + // Minimum execution time: 646_000 picoseconds. + Weight::from_parts(720_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_918_000 picoseconds. - Weight::from_parts(2_048_000, 0) + // Minimum execution time: 633_000 picoseconds. + Weight::from_parts(669_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_683_000 picoseconds. - Weight::from_parts(3_064_000, 0) + // Minimum execution time: 671_000 picoseconds. + Weight::from_parts(726_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_893_000 picoseconds. - Weight::from_parts(2_159_000, 0) + // Minimum execution time: 615_000 picoseconds. + Weight::from_parts(675_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -158,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 53_116_000 picoseconds. - Weight::from_parts(54_154_000, 6196) + // Minimum execution time: 67_236_000 picoseconds. + Weight::from_parts(69_899_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -169,8 +170,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `160` // Estimated: `3625` - // Minimum execution time: 12_381_000 picoseconds. - Weight::from_parts(12_693_000, 3625) + // Minimum execution time: 12_976_000 picoseconds. + Weight::from_parts(13_357_000, 3625) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -178,8 +179,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_933_000 picoseconds. - Weight::from_parts(1_983_000, 0) + // Minimum execution time: 633_000 picoseconds. + Weight::from_parts(685_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -199,8 +200,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `145` // Estimated: `3610` - // Minimum execution time: 24_251_000 picoseconds. - Weight::from_parts(24_890_000, 3610) + // Minimum execution time: 28_707_000 picoseconds. + Weight::from_parts(31_790_000, 3610) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -210,44 +211,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_850_000 picoseconds. - Weight::from_parts(4_082_000, 0) + // Minimum execution time: 2_670_000 picoseconds. + Weight::from_parts(2_833_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 112_248_000 picoseconds. - Weight::from_parts(124_454_000, 0) + // Minimum execution time: 23_459_000 picoseconds. + Weight::from_parts(23_817_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_457_000 picoseconds. - Weight::from_parts(12_060_000, 0) + // Minimum execution time: 6_197_000 picoseconds. + Weight::from_parts(6_338_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_959_000 picoseconds. - Weight::from_parts(2_076_000, 0) + // Minimum execution time: 671_000 picoseconds. + Weight::from_parts(715_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_920_000 picoseconds. - Weight::from_parts(1_994_000, 0) + // Minimum execution time: 655_000 picoseconds. + Weight::from_parts(694_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_149_000 picoseconds. - Weight::from_parts(2_394_000, 0) + // Minimum execution time: 810_000 picoseconds. + Weight::from_parts(858_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -269,8 +270,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 58_011_000 picoseconds. - Weight::from_parts(59_306_000, 6196) + // Minimum execution time: 73_136_000 picoseconds. + Weight::from_parts(75_314_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -278,8 +279,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_031_000 picoseconds. - Weight::from_parts(5_243_000, 0) + // Minimum execution time: 4_515_000 picoseconds. + Weight::from_parts(4_768_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -301,8 +302,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `246` // Estimated: `6196` - // Minimum execution time: 53_078_000 picoseconds. - Weight::from_parts(54_345_000, 6196) + // Minimum execution time: 68_072_000 picoseconds. + Weight::from_parts(69_866_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -310,22 +311,22 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_936_000 picoseconds. - Weight::from_parts(2_002_000, 0) + // Minimum execution time: 696_000 picoseconds. + Weight::from_parts(736_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_855_000 picoseconds. - Weight::from_parts(1_950_000, 0) + // Minimum execution time: 618_000 picoseconds. + Weight::from_parts(681_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_882_000 picoseconds. - Weight::from_parts(1_977_000, 0) + // Minimum execution time: 647_000 picoseconds. + Weight::from_parts(672_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -333,22 +334,22 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1489` - // Minimum execution time: 3_912_000 picoseconds. - Weight::from_parts(4_167_000, 1489) + // Minimum execution time: 2_496_000 picoseconds. + Weight::from_parts(2_617_000, 1489) .saturating_add(T::DbWeight::get().reads(1)) } pub fn set_fees_mode() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_911_000 picoseconds. - Weight::from_parts(1_971_000, 0) + // Minimum execution time: 637_000 picoseconds. + Weight::from_parts(675_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_990_000 picoseconds. - Weight::from_parts(2_076_000, 0) + // Minimum execution time: 607_000 picoseconds. + Weight::from_parts(683_000, 0) } } 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 2deeb73eb127..cfd9fd2fd463 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 @@ -21,7 +21,7 @@ use super::{ XcmpQueue, }; use assets_common::{ - matching::{FromSiblingParachain, IsForeignConcreteAsset}, + matching::{FromSiblingParachain, IsForeignConcreteAsset, ParentLocation}, TrustBackedAssetsAsLocation, }; use frame_support::{ @@ -42,26 +42,27 @@ use parachains_common::{ }; use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; -use sp_runtime::traits::{AccountIdConversion, ConvertInto}; +use snowbridge_router_primitives::inbound::GlobalConsensusEthereumConvertsFor; +use sp_runtime::traits::{AccountIdConversion, ConvertInto, TryConvertInto}; use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, - DenyReserveTransferToRelayChain, DenyThenTry, DescribeFamily, DescribePalletTerminal, + DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, 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, + MatchedConvertedConcreteId, NetworkExportTableItem, NoChecking, NonFungiblesAdapter, + ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount, + SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SingleAssetExchangeAdapter, SovereignPaidRemoteExporter, + SovereignSignedViaLocation, StartsWith, StartsWithExplicitGlobalConsensus, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, + WithLatestLocationConverter, 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 +71,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 = @@ -94,12 +93,14 @@ pub type LocationToAccountId = ( SiblingParachainConvertsVia, // Straight up local `AccountId32` origins just alias directly to `AccountId`. AccountId32Aliases, - // Foreign chain account alias into local accounts according to a hash of their standard - // description. - HashedDescription>, + // Foreign locations alias into accounts according to a hash of their standard description. + HashedDescription>, // 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. @@ -349,6 +350,28 @@ pub type TrustedTeleporters = ( IsForeignConcreteAsset>>, ); +/// Asset converter for pool assets. +/// Used to convert one asset to another, when there is a pool available between the two. +/// This type thus allows paying fees with any asset as long as there is a pool between said +/// asset and the asset required for fee payment. +pub type PoolAssetsExchanger = SingleAssetExchangeAdapter< + crate::AssetConversion, + crate::NativeAndAssets, + ( + TrustBackedAssetsAsLocation, + ForeignAssetsConvertedConcreteId, + // `ForeignAssetsConvertedConcreteId` excludes the relay token, so we add it back here. + MatchedConvertedConcreteId< + xcm::v4::Location, + Balance, + Equals, + WithLatestLocationConverter, + TryConvertInto, + >, + ), + AccountId, +>; + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -359,7 +382,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::RococoAssetFromAssetHubRococo, + bridging::to_ethereum::EthereumAssetFromEthereum, + ); type IsTeleporter = TrustedTeleporters; type UniversalLocation = UniversalLocation; type Barrier = Barrier; @@ -377,7 +403,7 @@ impl xcm_executor::Config for XcmConfig { ResolveTo, >, cumulus_primitives_utility::SwapFirstAssetTrader< - WestendLocationV3, + WestendLocation, crate::AssetConversion, WeightToFee, crate::NativeAndAssets, @@ -385,7 +411,7 @@ impl xcm_executor::Config for XcmConfig { TrustBackedAssetsAsLocation< TrustBackedAssetsPalletLocation, Balance, - xcm::v3::Location, + xcm::v4::Location, >, ForeignAssetsConvertedConcreteId, ), @@ -426,13 +452,14 @@ impl xcm_executor::Config for XcmConfig { type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type AssetLocker = (); - type AssetExchanger = (); + type AssetExchanger = PoolAssetsExchanger; 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 +491,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 +539,16 @@ pub type ForeignCreatorsSovereignAccountOf = ( SiblingParachainConvertsVia, AccountId32Aliases, ParentIsPreset, + GlobalConsensusEthereumConvertsFor, + GlobalConsensusParachainConvertsFor, ); /// 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)]) } } @@ -569,10 +605,8 @@ pub mod bridging { ); pub const RococoNetwork: NetworkId = NetworkId::Rococo; - pub const EthereumNetwork: NetworkId = NetworkId::Ethereum { chain_id: 11155111 }; pub RococoEcosystem: Location = Location::new(2, [GlobalConsensus(RococoNetwork::get())]); pub RocLocation: Location = Location::new(2, [GlobalConsensus(RococoNetwork::get())]); - pub EthereumEcosystem: Location = Location::new(2, [GlobalConsensus(EthereumNetwork::get())]); pub AssetHubRococo: Location = Location::new(2, [ GlobalConsensus(RococoNetwork::get()), Parachain(bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID) @@ -609,21 +643,68 @@ pub mod bridging { } } - /// Allow any asset native to the Rococo or Ethereum ecosystems if it comes from Rococo - /// Asset Hub. - pub type RococoOrEthereumAssetFromAssetHubRococo = matching::RemoteAssetFromLocation< - (StartsWith, StartsWith), - AssetHubRococo, - >; - - impl Contains for ToRococoXcmRouter { - fn contains(call: &RuntimeCall) -> bool { - matches!( - call, - RuntimeCall::ToRococoXcmRouter( - pallet_xcm_bridge_hub_router::Call::report_bridge_status { .. } - ) - ) + /// Allow any asset native to the Rococo ecosystem if it comes from Rococo Asset Hub. + pub type RococoAssetFromAssetHubRococo = + matching::RemoteAssetFromLocation, AssetHubRococo>; + } + + 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 EthereumAssetFromEthereum = + IsForeignConcreteAsset>; + + impl Contains<(Location, Junction)> for UniversalAliases { + fn contains(alias: &(Location, Junction)) -> bool { + UniversalAliases::get().contains(alias) } } } 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 48e6c11d268c..ff84bdea69f4 100644 --- a/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs +++ b/cumulus/parachains/runtimes/assets/asset-hub-westend/tests/tests.rs @@ -28,7 +28,7 @@ use asset_hub_westend_runtime::{ AllPalletsWithoutSystem, Assets, Balances, ExistentialDeposit, ForeignAssets, ForeignAssetsInstance, MetadataDepositBase, MetadataDepositPerByte, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, - ToRococoXcmRouterInstance, TrustBackedAssetsInstance, XcmpQueue, + TrustBackedAssetsInstance, XcmpQueue, }; pub use asset_hub_westend_runtime::{AssetConversion, AssetDeposit, CollatorSelection, System}; use asset_test_utils::{ @@ -49,12 +49,14 @@ use frame_support::{ }; use parachains_common::{AccountId, AssetIdForTrustBackedAssets, AuraId, Balance}; use sp_consensus_aura::SlotDuration; +use sp_core::crypto::Ss58Codec; use sp_runtime::traits::MaybeEquivalence; use std::{convert::Into, ops::Mul}; use testnet_parachains_constants::westend::{consensus::*, currency::UNITS, fee::WeightToFee}; use xcm::latest::prelude::{Assets as XcmAssets, *}; use xcm_builder::WithLatestLocationConverter; use xcm_executor::traits::{ConvertLocation, JustTry, WeightTrader}; +use xcm_runtime_apis::conversions::LocationToAccountHelper; const ALICE: [u8; 32] = [1u8; 32]; const SOME_ASSET_ADMIN: [u8; 32] = [5u8; 32]; @@ -86,7 +88,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 +96,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 +108,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 +221,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 +232,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 +273,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 +312,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 +328,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 +356,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 +366,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 +374,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 +386,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 +499,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 +518,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 +532,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 +555,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 +835,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 +847,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 +884,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 +893,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 +904,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 +930,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 +1023,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 +1046,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 +1125,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 +1164,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 +1178,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 +1194,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 +1224,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 +1234,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 ); @@ -1246,92 +1244,6 @@ fn receive_reserve_asset_deposited_roc_from_asset_hub_rococo_fees_paid_by_suffic ) } -#[test] -fn report_bridge_status_from_xcm_bridge_router_for_rococo_works() { - asset_test_utils::test_cases_over_bridge::report_bridge_status_from_xcm_bridge_router_works::< - Runtime, - AllPalletsWithoutSystem, - XcmConfig, - LocationToAccountId, - ToRococoXcmRouterInstance, - >( - collator_session_keys(), - bridging_to_asset_hub_rococo, - || { - vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind: OriginKind::Xcm, - require_weight_at_most: - bp_asset_hub_westend::XcmBridgeHubRouterTransactCallMaxWeight::get(), - call: bp_asset_hub_westend::Call::ToRococoXcmRouter( - bp_asset_hub_westend::XcmBridgeHubRouterCall::report_bridge_status { - bridge_id: Default::default(), - is_congested: true, - }, - ) - .encode() - .into(), - }, - ] - .into() - }, - || { - vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind: OriginKind::Xcm, - require_weight_at_most: - bp_asset_hub_westend::XcmBridgeHubRouterTransactCallMaxWeight::get(), - call: bp_asset_hub_westend::Call::ToRococoXcmRouter( - bp_asset_hub_westend::XcmBridgeHubRouterCall::report_bridge_status { - bridge_id: Default::default(), - is_congested: false, - }, - ) - .encode() - .into(), - }, - ] - .into() - }, - ) -} - -#[test] -fn test_report_bridge_status_call_compatibility() { - // if this test fails, make sure `bp_asset_hub_rococo` has valid encoding - assert_eq!( - RuntimeCall::ToRococoXcmRouter(pallet_xcm_bridge_hub_router::Call::report_bridge_status { - bridge_id: Default::default(), - is_congested: true, - }) - .encode(), - bp_asset_hub_westend::Call::ToRococoXcmRouter( - bp_asset_hub_westend::XcmBridgeHubRouterCall::report_bridge_status { - bridge_id: Default::default(), - is_congested: true, - } - ) - .encode() - ) -} - -#[test] -fn check_sane_weight_report_bridge_status() { - use pallet_xcm_bridge_hub_router::WeightInfo; - let actual = >::WeightInfo::report_bridge_status(); - let max_weight = bp_asset_hub_westend::XcmBridgeHubRouterTransactCallMaxWeight::get(); - assert!( - actual.all_lte(max_weight), - "max_weight: {:?} should be adjusted to actual {:?}", - max_weight, - actual - ); -} - #[test] fn change_xcm_bridge_hub_router_byte_fee_by_governance_works() { asset_test_utils::test_cases::change_storage_constant_by_governance_works::< @@ -1419,3 +1331,112 @@ fn reserve_transfer_native_asset_to_non_teleport_para_works() { WeightLimit::Unlimited, ); } + +#[test] +fn location_conversion_works() { + // the purpose of hardcoded values is to catch an unintended location conversion logic change. + struct TestCase { + description: &'static str, + location: Location, + expected_account_id_str: &'static str, + } + + let test_cases = vec![ + // DescribeTerminus + TestCase { + description: "DescribeTerminus Parent", + location: Location::new(1, Here), + expected_account_id_str: "5Dt6dpkWPwLaH4BBCKJwjiWrFVAGyYk3tLUabvyn4v7KtESG", + }, + TestCase { + description: "DescribeTerminus Sibling", + location: Location::new(1, [Parachain(1111)]), + expected_account_id_str: "5Eg2fnssmmJnF3z1iZ1NouAuzciDaaDQH7qURAy3w15jULDk", + }, + // DescribePalletTerminal + TestCase { + description: "DescribePalletTerminal Parent", + location: Location::new(1, [PalletInstance(50)]), + expected_account_id_str: "5CnwemvaAXkWFVwibiCvf2EjqwiqBi29S5cLLydZLEaEw6jZ", + }, + TestCase { + description: "DescribePalletTerminal Sibling", + location: Location::new(1, [Parachain(1111), PalletInstance(50)]), + expected_account_id_str: "5GFBgPjpEQPdaxEnFirUoa51u5erVx84twYxJVuBRAT2UP2g", + }, + // DescribeAccountId32Terminal + TestCase { + description: "DescribeAccountId32Terminal Parent", + location: Location::new( + 1, + [AccountId32 { network: None, id: AccountId::from(ALICE).into() }], + ), + expected_account_id_str: "5DN5SGsuUG7PAqFL47J9meViwdnk9AdeSWKFkcHC45hEzVz4", + }, + TestCase { + description: "DescribeAccountId32Terminal Sibling", + location: Location::new( + 1, + [ + Parachain(1111), + Junction::AccountId32 { network: None, id: AccountId::from(ALICE).into() }, + ], + ), + expected_account_id_str: "5DGRXLYwWGce7wvm14vX1Ms4Vf118FSWQbJkyQigY2pfm6bg", + }, + // DescribeAccountKey20Terminal + TestCase { + description: "DescribeAccountKey20Terminal Parent", + location: Location::new(1, [AccountKey20 { network: None, key: [0u8; 20] }]), + expected_account_id_str: "5F5Ec11567pa919wJkX6VHtv2ZXS5W698YCW35EdEbrg14cg", + }, + TestCase { + description: "DescribeAccountKey20Terminal Sibling", + location: Location::new( + 1, + [Parachain(1111), AccountKey20 { network: None, key: [0u8; 20] }], + ), + expected_account_id_str: "5CB2FbUds2qvcJNhDiTbRZwiS3trAy6ydFGMSVutmYijpPAg", + }, + // DescribeTreasuryVoiceTerminal + TestCase { + description: "DescribeTreasuryVoiceTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]), + expected_account_id_str: "5CUjnE2vgcUCuhxPwFoQ5r7p1DkhujgvMNDHaF2bLqRp4D5F", + }, + TestCase { + description: "DescribeTreasuryVoiceTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Treasury, part: BodyPart::Voice }], + ), + expected_account_id_str: "5G6TDwaVgbWmhqRUKjBhRRnH4ry9L9cjRymUEmiRsLbSE4gB", + }, + // DescribeBodyTerminal + TestCase { + description: "DescribeBodyTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Unit, part: BodyPart::Voice }]), + expected_account_id_str: "5EBRMTBkDisEXsaN283SRbzx9Xf2PXwUxxFCJohSGo4jYe6B", + }, + TestCase { + description: "DescribeBodyTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Unit, part: BodyPart::Voice }], + ), + expected_account_id_str: "5DBoExvojy8tYnHgLL97phNH975CyT45PWTZEeGoBZfAyRMH", + }, + ]; + + for tc in test_cases { + let expected = + AccountId::from_string(tc.expected_account_id_str).expect("Invalid AccountId string"); + + let got = LocationToAccountHelper::::convert_location( + tc.location.into(), + ) + .unwrap(); + + assert_eq!(got, expected, "{}", tc.description); + } +} diff --git a/cumulus/parachains/runtimes/assets/common/Cargo.toml b/cumulus/parachains/runtimes/assets/common/Cargo.toml index c6740269339d..fb66f0de2322 100644 --- a/cumulus/parachains/runtimes/assets/common/Cargo.toml +++ b/cumulus/parachains/runtimes/assets/common/Cargo.toml @@ -19,6 +19,7 @@ impl-trait-for-tuples = { workspace = true } frame-support = { workspace = true } sp-api = { workspace = true } sp-runtime = { workspace = true } +pallet-assets = { workspace = true } pallet-asset-conversion = { workspace = true } # Polkadot @@ -42,6 +43,7 @@ std = [ "frame-support/std", "log/std", "pallet-asset-conversion/std", + "pallet-assets/std", "pallet-xcm/std", "parachains-common/std", "scale-info/std", @@ -56,6 +58,7 @@ runtime-benchmarks = [ "cumulus-primitives-core/runtime-benchmarks", "frame-support/runtime-benchmarks", "pallet-asset-conversion/runtime-benchmarks", + "pallet-assets/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/runtime-benchmarks", "sp-runtime/runtime-benchmarks", diff --git a/cumulus/parachains/runtimes/assets/common/src/lib.rs b/cumulus/parachains/runtimes/assets/common/src/lib.rs index 4bb593f98929..deda5fa4ab9c 100644 --- a/cumulus/parachains/runtimes/assets/common/src/lib.rs +++ b/cumulus/parachains/runtimes/assets/common/src/lib.rs @@ -29,7 +29,7 @@ use crate::matching::{LocalLocationPattern, ParentLocation}; use frame_support::traits::{Equals, EverythingBut}; use parachains_common::{AssetIdForTrustBackedAssets, CollectionId, ItemId}; use sp_runtime::traits::TryConvertInto; -use xcm::latest::Location; +use xcm::prelude::*; use xcm_builder::{ AsPrefixedGeneralIndex, MatchedConvertedConcreteId, StartsWith, WithLatestLocationConverter, }; @@ -138,7 +138,6 @@ pub type PoolAssetsConvertedConcreteId = mod tests { use super::*; use sp_runtime::traits::MaybeEquivalence; - use xcm::prelude::*; use xcm_builder::{StartsWithExplicitGlobalConsensus, WithLatestLocationConverter}; use xcm_executor::traits::{Error as MatchError, MatchesFungibles}; diff --git a/cumulus/parachains/runtimes/assets/common/src/matching.rs b/cumulus/parachains/runtimes/assets/common/src/matching.rs index 9bb35d0c5328..9ac2056a67f4 100644 --- a/cumulus/parachains/runtimes/assets/common/src/matching.rs +++ b/cumulus/parachains/runtimes/assets/common/src/matching.rs @@ -102,19 +102,27 @@ impl< pub struct RemoteAssetFromLocation( core::marker::PhantomData<(AssetsAllowedNetworks, OriginLocation)>, ); -impl, OriginLocation: Get> - ContainsPair for RemoteAssetFromLocation +impl< + L: TryInto + Clone, + AssetsAllowedNetworks: Contains, + OriginLocation: Get, + > ContainsPair for RemoteAssetFromLocation { - fn contains(asset: &Asset, origin: &Location) -> bool { + fn contains(asset: &L, origin: &L) -> bool { + let Ok(asset) = asset.clone().try_into() else { + return false; + }; + let Ok(origin) = origin.clone().try_into() else { + return false; + }; let expected_origin = OriginLocation::get(); // ensure `origin` is expected `OriginLocation` - if !expected_origin.eq(origin) { + if !expected_origin.eq(&origin) { log::trace!( target: "xcm::contains", - "RemoteAssetFromLocation asset: {:?}, origin: {:?} is not from expected {:?}", - asset, origin, expected_origin, + "RemoteAssetFromLocation asset: {asset:?}, origin: {origin:?} is not from expected {expected_origin:?}" ); - return false + return false; } else { log::trace!( target: "xcm::contains", @@ -123,7 +131,14 @@ impl, OriginLocation: Get> } // ensure `asset` is from remote consensus listed in `AssetsAllowedNetworks` - AssetsAllowedNetworks::contains(&asset.id.0) + AssetsAllowedNetworks::contains(&asset) + } +} +impl, OriginLocation: Get> + ContainsPair for RemoteAssetFromLocation +{ + fn contains(asset: &Asset, origin: &Location) -> bool { + >::contains(&asset.id.0, origin) } } 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 884b71369e79..c80222142304 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, ); @@ -1146,7 +1143,8 @@ pub fn create_and_manage_foreign_assets_for_local_consensus_parachain_assets_wor .with_balances(vec![( foreign_creator_as_account_id.clone(), existential_deposit + - asset_deposit + metadata_deposit_base + + asset_deposit + + metadata_deposit_base + metadata_deposit_per_byte_eta + buy_execution_fee_amount.into() + buy_execution_fee_amount.into(), @@ -1559,9 +1557,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 0b2364dbb8bd..d86761174740 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, @@ -545,14 +542,19 @@ pub fn report_bridge_status_from_xcm_bridge_router_works< // execute xcm as XcmpQueue would do let outcome = XcmExecutor::::prepare_and_execute( - local_bridge_hub_location, + local_bridge_hub_location.clone(), xcm, &mut hash, - RuntimeHelper::::xcm_max_weight(XcmReceivedFrom::Sibling), + RuntimeHelper::::xcm_max_weight( + XcmReceivedFrom::Sibling, + ), Weight::zero(), ); assert_ok!(outcome.ensure_complete()); - assert_eq!(is_congested, pallet_xcm_bridge_hub_router::Pallet::::bridge().is_congested); + assert_eq!( + is_congested, + <>::LocalXcmChannelManager as pallet_xcm_bridge_hub_router::XcmChannelStatusProvider>::is_congested(&local_bridge_hub_location) + ); }; report_bridge_status(true); 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 987372984682..4af8a9f43850 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/Cargo.toml @@ -3,7 +3,7 @@ name = "bridge-hub-rococo-runtime" version = "0.5.0" authors.workspace = true edition.workspace = true -description = "Rococo's BridgeHub parachain runtime" +description = "Rococo's BridgeHub parachain runtime" license = "Apache-2.0" [lints] @@ -13,19 +13,17 @@ workspace = true substrate-wasm-builder = { optional = true, workspace = true, default-features = true } [dependencies] -codec = { features = [ - "derive", -], workspace = true } +codec = { features = ["derive"], workspace = true } hex-literal = { workspace = true, default-features = true } log = { workspace = true } -scale-info = { features = [ - "derive", -], workspace = true } +scale-info = { features = ["derive"], workspace = true } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } +serde_json = { features = ["alloc"], workspace = true } # 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 } @@ -45,6 +43,7 @@ sp-api = { workspace = true } sp-block-builder = { workspace = true } sp-consensus-aura = { workspace = true } sp-core = { workspace = true } +sp-keyring = { workspace = true } sp-genesis-builder = { workspace = true } sp-inherents = { workspace = true } sp-io = { workspace = true } @@ -72,9 +71,7 @@ cumulus-pallet-aura-ext = { workspace = true } cumulus-pallet-parachain-system = { workspace = true } cumulus-pallet-session-benchmarking = { workspace = true } cumulus-pallet-xcm = { workspace = true } -cumulus-pallet-xcmp-queue = { features = [ - "bridging", -], workspace = true } +cumulus-pallet-xcmp-queue = { features = ["bridging"], workspace = true } cumulus-primitives-aura = { workspace = true } cumulus-primitives-core = { workspace = true } cumulus-primitives-storage-weight-reclaim = { workspace = true } @@ -96,7 +93,7 @@ bp-parachains = { workspace = true } bp-polkadot-bulletin = { workspace = true } bp-polkadot-core = { workspace = true } bp-relayers = { workspace = true } -bp-runtime = { features = ["test-helpers"], workspace = true } +bp-runtime = { workspace = true } bp-rococo = { workspace = true } bp-westend = { workspace = true } pallet-bridge-grandpa = { workspace = true } @@ -121,12 +118,9 @@ 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", -], workspace = true, default-features = true } -sp-keyring = { workspace = true, default-features = true } +bridge-runtime-common = { features = ["integrity-test"], workspace = true, default-features = true } +pallet-bridge-relayers = { features = ["integrity-test"], workspace = true } snowbridge-runtime-test-common = { workspace = true, default-features = true } [features] @@ -160,6 +154,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", @@ -191,6 +186,7 @@ std = [ "rococo-runtime-constants/std", "scale-info/std", "serde", + "serde_json/std", "snowbridge-beacon-primitives/std", "snowbridge-core/std", "snowbridge-outbound-queue-runtime-api/std", @@ -208,6 +204,7 @@ std = [ "sp-genesis-builder/std", "sp-inherents/std", "sp-io/std", + "sp-keyring/std", "sp-offchain/std", "sp-runtime/std", "sp-session/std", @@ -244,6 +241,7 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm-bridge-hub/runtime-benchmarks", @@ -304,4 +302,4 @@ fast-runtime = [] # A feature that should be enabled when the runtime should be built for on-chain # deployment. This will disable stuff that shouldn't be part of the on-chain wasm # to make it smaller, like logging for example. -on-chain-release-build = ["sp-api/disable-logging"] +on-chain-release-build = [] diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs index 779cc537ee96..5dca45d326b8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_common_config.rs @@ -64,11 +64,37 @@ impl pallet_bridge_parachains::Config for Runtim } /// Allows collect and claim rewards for relayers -impl pallet_bridge_relayers::Config for Runtime { +pub type RelayersForLegacyLaneIdsMessagesInstance = (); +impl pallet_bridge_relayers::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Reward = Balance; - type PaymentProcedure = - bp_relayers::PayRewardFromAccount, AccountId>; + type PaymentProcedure = bp_relayers::PayRewardFromAccount< + pallet_balances::Pallet, + AccountId, + Self::LaneId, + >; + type StakeAndSlash = pallet_bridge_relayers::StakeAndSlashNamed< + AccountId, + BlockNumber, + Balances, + RelayerStakeReserveId, + RequiredStakeForStakeAndSlash, + RelayerStakeLease, + >; + type WeightInfo = weights::pallet_bridge_relayers::WeightInfo; + type LaneId = bp_messages::LegacyLaneId; +} + +/// Allows collect and claim rewards for relayers +pub type RelayersForPermissionlessLanesInstance = pallet_bridge_relayers::Instance2; +impl pallet_bridge_relayers::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Reward = Balance; + type PaymentProcedure = bp_relayers::PayRewardFromAccount< + pallet_balances::Pallet, + AccountId, + Self::LaneId, + >; type StakeAndSlash = pallet_bridge_relayers::StakeAndSlashNamed< AccountId, BlockNumber, @@ -78,6 +104,7 @@ impl pallet_bridge_relayers::Config for Runtime { RelayerStakeLease, >; type WeightInfo = weights::pallet_bridge_relayers::WeightInfo; + type LaneId = bp_messages::HashedLaneId; } /// Add GRANDPA bridge pallet to track Rococo Bulletin chain. 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 d97e6a1d88e1..c226ed9c4fa0 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_bulletin_config.rs @@ -20,36 +20,36 @@ //! are reusing Polkadot Bulletin chain primitives everywhere here. use crate::{ - weights, xcm_config::UniversalLocation, BridgeRococoBulletinGrandpa, - BridgeRococoBulletinMessages, PolkadotXcm, Runtime, RuntimeEvent, XcmOverRococoBulletin, - XcmRouter, + bridge_common_config::RelayersForPermissionlessLanesInstance, weights, + xcm_config::UniversalLocation, AccountId, Balance, Balances, BridgeRococoBulletinGrandpa, + BridgeRococoBulletinMessages, PolkadotXcm, Runtime, RuntimeEvent, RuntimeHoldReason, + XcmOverRococoBulletin, XcmRouter, }; 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, - RefundableMessagesLane, - }, - messages_xcm_extension::{ - SenderAndLane, XcmAsPlainPayload, XcmBlobHauler, XcmBlobHaulerAdapter, - XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, - }, + target_chain::FromBridgedChainMessagesProof, HashedLaneId, }; +use bridge_hub_common::xcm_version::XcmVersionOfDestAndRemoteBridge; -use frame_support::{parameter_types, traits::PalletInfoAccess}; +use frame_support::{ + parameter_types, + traits::{Equals, PalletInfoAccess}, +}; +use frame_system::{EnsureNever, EnsureRoot}; +use pallet_bridge_messages::LaneIdOf; +use pallet_bridge_relayers::extension::{ + BridgeRelayersTransactionExtension, WithMessagesExtensionConfig, +}; +use pallet_xcm_bridge_hub::XcmAsPlainPayload; +use polkadot_parachain_primitives::primitives::Sibling; +use testnet_parachains_constants::rococo::currency::UNITS as ROC; use xcm::{ latest::prelude::*, prelude::{InteriorLocation, NetworkId}, }; -use xcm_builder::BridgeBlobDispatcher; +use xcm_builder::{BridgeBlobDispatcher, ParentIsPreset, SiblingParachainConvertsVia}; 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) @@ -61,12 +61,6 @@ parameter_types! { 2, [GlobalConsensus(RococoBulletinGlobalConsensusNetwork::get())] ); - /// All active lanes that the current bridge supports. - pub ActiveOutboundLanesToRococoBulletin: &'static [bp_messages::LaneId] - = &[XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN]; - /// Lane identifier, used to connect Rococo People and Rococo Bulletin chain. - pub const RococoPeopleToRococoBulletinMessagesLane: bp_messages::LaneId - = XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN; // see the `FEE_BOOST_PER_RELAY_HEADER` constant get the meaning of this value pub PriorityBoostPerRelayHeader: u64 = 58_014_163_614_163; @@ -78,33 +72,18 @@ parameter_types! { /// meaning of this value. pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; - /// Identifier of the sibling Rococo People parachain. - pub RococoPeopleParaId: cumulus_primitives_core::ParaId = rococo_runtime_constants::system_parachain::PEOPLE_ID.into(); - /// A route (XCM location and bridge lane) that the Rococo People Chain -> Rococo Bulletin Chain - /// message is following. - pub FromRococoPeopleToRococoBulletinRoute: SenderAndLane = SenderAndLane::new( - ParentThen(Parachain(RococoPeopleParaId::get().into()).into()).into(), - XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, - ); - /// All active routes and their destinations. - pub ActiveLanes: alloc::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = alloc::vec![ - ( - FromRococoPeopleToRococoBulletinRoute::get(), - (RococoBulletinGlobalConsensusNetwork::get(), Here) - ) - ]; + /// PeopleRococo location + pub PeopleRococoLocation: Location = Location::new(1, [Parachain(rococo_runtime_constants::system_parachain::PEOPLE_ID)]); - /// XCM message that is never sent. - pub NeverSentMessage: Option> = None; + pub storage BridgeDeposit: Balance = 5 * ROC; } -pub const XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN: LaneId = LaneId([0, 0, 0, 0]); /// Proof of messages, coming from Rococo Bulletin chain. -pub type FromRococoBulletinMessagesProof = - FromBridgedChainMessagesProof; +pub type FromRococoBulletinMessagesProof = + FromBridgedChainMessagesProof>; /// Messages delivery proof for Rococo Bridge Hub -> Rococo Bulletin messages. -pub type ToRococoBulletinMessagesDeliveryProof = - FromBridgedChainMessagesDeliveryProof; +pub type ToRococoBulletinMessagesDeliveryProof = + FromBridgedChainMessagesDeliveryProof>; /// Dispatches received XCM messages from other bridge. type FromRococoBulletinMessageBlobDispatcher = BridgeBlobDispatcher< @@ -113,35 +92,18 @@ type FromRococoBulletinMessageBlobDispatcher = BridgeBlobDispatcher< BridgeRococoToRococoBulletinMessagesPalletInstance, >; -/// Export XCM messages to be relayed to the other side -pub type ToRococoBulletinHaulBlobExporter = XcmOverRococoBulletin; - -pub struct ToRococoBulletinXcmBlobHauler; -impl XcmBlobHauler for ToRococoBulletinXcmBlobHauler { - type Runtime = Runtime; - type MessagesInstance = WithRococoBulletinMessagesInstance; - type ToSourceChainSender = XcmRouter; - type CongestedMessage = NeverSentMessage; - type UncongestedMessage = NeverSentMessage; -} - -/// On messages delivered callback. -type OnMessagesDeliveredFromRococoBulletin = - XcmBlobHaulerAdapter; - -/// Signed extension that refunds relayers that are delivering messages from the Rococo Bulletin -/// chain. -pub type OnBridgeHubRococoRefundRococoBulletinMessages = RefundSignedExtensionAdapter< - RefundBridgedMessages< +/// Transaction extension that refunds relayers that are delivering messages from the Rococo +/// Bulletin chain. +pub type OnBridgeHubRococoRefundRococoBulletinMessages = BridgeRelayersTransactionExtension< + Runtime, + WithMessagesExtensionConfig< + StrOnBridgeHubRococoRefundRococoBulletinMessages, Runtime, - RefundableMessagesLane< - WithRococoBulletinMessagesInstance, - RococoPeopleToRococoBulletinMessagesLane, - >, - ActualFeeRefund, + WithRococoBulletinMessagesInstance, + RelayersForPermissionlessLanesInstance, PriorityBoostPerMessage, - StrOnBridgeHubRococoRefundRococoBulletinMessages, >, + LaneIdOf, >; bp_runtime::generate_static_str_provider!(OnBridgeHubRococoRefundRococoBulletinMessages); @@ -156,31 +118,45 @@ impl pallet_bridge_messages::Config for Runt type BridgedChain = bp_polkadot_bulletin::PolkadotBulletin; type BridgedHeaderChain = BridgeRococoBulletinGrandpa; - type ActiveOutboundLanes = ActiveOutboundLanesToRococoBulletin; - type OutboundPayload = XcmAsPlainPayload; - type InboundPayload = XcmAsPlainPayload; - type DeliveryPayments = (); + type LaneId = HashedLaneId; + type DeliveryPayments = (); type DeliveryConfirmationPayments = (); - type MessageDispatch = - XcmBlobMessageDispatch; - type OnMessagesDelivered = OnMessagesDeliveredFromRococoBulletin; + type MessageDispatch = XcmOverRococoBulletin; + type OnMessagesDelivered = XcmOverRococoBulletin; } /// Add support for the export and dispatch of XCM programs. pub type XcmOverPolkadotBulletinInstance = pallet_xcm_bridge_hub::Instance2; impl pallet_xcm_bridge_hub::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type UniversalLocation = UniversalLocation; type BridgedNetwork = RococoBulletinGlobalConsensusNetworkLocation; type BridgeMessagesPalletInstance = WithRococoBulletinMessagesInstance; + type MessageExportPrice = (); type DestinationVersion = XcmVersionOfDestAndRemoteBridge; - type Lanes = ActiveLanes; - type LanesSupport = ToRococoBulletinXcmBlobHauler; + + type ForceOrigin = EnsureRoot; + // We don't want to allow creating bridges for this instance. + type OpenBridgeOrigin = EnsureNever; + // Converter aligned with `OpenBridgeOrigin`. + type BridgeOriginAccountIdConverter = + (ParentIsPreset, SiblingParachainConvertsVia); + + type BridgeDeposit = BridgeDeposit; + type Currency = Balances; + type RuntimeHoldReason = RuntimeHoldReason; + // Do not require deposit from People parachains. + type AllowWithoutBridgeDeposit = Equals; + + type LocalXcmChannelManager = (); + type BlobDispatcher = FromRococoBulletinMessageBlobDispatcher; } #[cfg(test)] @@ -235,13 +211,13 @@ mod tests { // Bulletin chain - it has the same (almost) runtime for Polkadot Bulletin and Rococo // Bulletin, so we have to adhere Polkadot names here - bridge_runtime_common::extensions::priority_calculator::per_relay_header::ensure_priority_boost_is_sane::< + pallet_bridge_relayers::extension::per_relay_header::ensure_priority_boost_is_sane::< Runtime, BridgeGrandpaRococoBulletinInstance, PriorityBoostPerRelayHeader, >(FEE_BOOST_PER_RELAY_HEADER); - bridge_runtime_common::extensions::priority_calculator::per_message::ensure_priority_boost_is_sane::< + pallet_bridge_relayers::extension::per_message::ensure_priority_boost_is_sane::< Runtime, WithRococoBulletinMessagesInstance, PriorityBoostPerMessage, @@ -255,3 +231,77 @@ mod tests { assert_eq!(BridgeRococoToRococoBulletinMessagesPalletInstance::get(), expected,); } } + +#[cfg(feature = "runtime-benchmarks")] +pub(crate) fn open_bridge_for_benchmarks( + with: pallet_xcm_bridge_hub::LaneIdOf, + sibling_para_id: u32, +) -> InteriorLocation +where + R: pallet_xcm_bridge_hub::Config, + XBHI: 'static, + C: xcm_executor::traits::ConvertLocation< + bp_runtime::AccountIdOf>, + >, +{ + use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; + use sp_runtime::traits::Zero; + use xcm::VersionedInteriorLocation; + + // insert bridge metadata + let lane_id = with; + let sibling_parachain = Location::new(1, [Parachain(sibling_para_id)]); + let universal_source = [GlobalConsensus(Rococo), Parachain(sibling_para_id)].into(); + let universal_destination = + [GlobalConsensus(RococoBulletinGlobalConsensusNetwork::get()), Parachain(2075)].into(); + let bridge_id = BridgeId::new(&universal_source, &universal_destination); + + // insert only bridge metadata, because the benchmarks create lanes + pallet_xcm_bridge_hub::Bridges::::insert( + bridge_id, + Bridge { + bridge_origin_relative_location: alloc::boxed::Box::new( + sibling_parachain.clone().into(), + ), + bridge_origin_universal_location: alloc::boxed::Box::new( + VersionedInteriorLocation::from(universal_source.clone()), + ), + bridge_destination_universal_location: alloc::boxed::Box::new( + VersionedInteriorLocation::from(universal_destination), + ), + state: BridgeState::Opened, + bridge_owner_account: C::convert_location(&sibling_parachain).expect("valid AccountId"), + deposit: Zero::zero(), + lane_id, + }, + ); + pallet_xcm_bridge_hub::LaneToBridge::::insert(lane_id, bridge_id); + + universal_source +} + +/// Contains the migration for the PeopleRococo<>RococoBulletin bridge. +pub mod migration { + use super::*; + use frame_support::traits::ConstBool; + + parameter_types! { + pub BulletinRococoLocation: InteriorLocation = [GlobalConsensus(RococoBulletinGlobalConsensusNetwork::get())].into(); + pub RococoPeopleToRococoBulletinMessagesLane: HashedLaneId = pallet_xcm_bridge_hub::Pallet::< Runtime, XcmOverPolkadotBulletinInstance >::bridge_locations( + PeopleRococoLocation::get(), + BulletinRococoLocation::get() + ) + .unwrap() + .calculate_lane_id(xcm::latest::VERSION).expect("Valid locations"); + } + + /// Ensure that the existing lanes for the People<>Bulletin bridge are correctly configured. + pub type StaticToDynamicLanes = pallet_xcm_bridge_hub::migration::OpenBridgeForLane< + Runtime, + XcmOverPolkadotBulletinInstance, + RococoPeopleToRococoBulletinMessagesLane, + ConstBool, + PeopleRococoLocation, + BulletinRococoLocation, + >; +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs index 01a762d4b99f..be7005b5379a 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_ethereum_config.rs @@ -14,9 +14,34 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::{xcm_config::UniversalLocation, Runtime}; -use snowbridge_router_primitives::outbound::EthereumBlobExporter; -use testnet_parachains_constants::rococo::snowbridge::EthereumNetwork; +#[cfg(not(feature = "runtime-benchmarks"))] +use crate::XcmRouter; +use crate::{ + xcm_config, xcm_config::UniversalLocation, Balances, EthereumInboundQueue, + EthereumOutboundQueue, EthereumSystem, MessageQueue, Runtime, RuntimeEvent, TransactionByteFee, + TreasuryAccount, +}; +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::rococo::{ + currency::*, + fee::WeightToFee, + snowbridge::{EthereumLocation, EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX}, +}; + +use crate::xcm_config::RelayNetwork; +#[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, +}; +use xcm::prelude::{GlobalConsensus, InteriorLocation, Location, Parachain}; /// Exports message to the Ethereum Gateway contract. pub type SnowbridgeExporter = EthereumBlobExporter< @@ -24,4 +49,184 @@ pub type SnowbridgeExporter = EthereumBlobExporter< EthereumNetwork, snowbridge_pallet_outbound_queue::Pallet, snowbridge_core::AgentIdOf, + EthereumSystem, >; + +// 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), + }; + pub AssetHubFromEthereum: Location = Location::new(1,[GlobalConsensus(RelayNetwork::get()),Parachain(rococo_runtime_constants::system_parachain::ASSET_HUB_ID)]); + pub EthereumUniversalLocation: InteriorLocation = [GlobalConsensus(EthereumNetwork::get())].into(); +} + +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, + EthereumSystem, + EthereumUniversalLocation, + AssetHubFromEthereum, + >; + 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, + }, + }; +} + +pub const SLOTS_PER_EPOCH: u32 = snowbridge_pallet_ethereum_client::config::SLOTS_PER_EPOCH as u32; + +impl snowbridge_pallet_ethereum_client::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type ForkVersions = ChainForkVersions; + // Free consensus update every epoch. Works out to be 225 updates per day. + type FreeHeadersInterval = ConstU32; + 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; + type UniversalLocation = UniversalLocation; + type EthereumLocation = EthereumLocation; +} + +#[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-rococo/src/bridge_to_westend_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs index fe854e20c244..29ea4e05f29e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/bridge_to_westend_config.rs @@ -17,37 +17,38 @@ //! Bridge definitions used on BridgeHubRococo for bridging to BridgeHubWestend. use crate::{ - bridge_common_config::{BridgeParachainWestendInstance, DeliveryRewardInBalance}, + bridge_common_config::{ + BridgeParachainWestendInstance, DeliveryRewardInBalance, + RelayersForLegacyLaneIdsMessagesInstance, + }, weights, xcm_config::UniversalLocation, - BridgeWestendMessages, PolkadotXcm, Runtime, RuntimeEvent, XcmOverBridgeHubWestend, XcmRouter, + AccountId, Balance, Balances, BridgeWestendMessages, PolkadotXcm, Runtime, RuntimeEvent, + RuntimeHoldReason, XcmOverBridgeHubWestend, XcmRouter, }; 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, - RefundableMessagesLane, - }, - messages_xcm_extension::{ - SenderAndLane, XcmAsPlainPayload, XcmBlobHauler, XcmBlobHaulerAdapter, - XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, - }, + target_chain::FromBridgedChainMessagesProof, LegacyLaneId, }; +use bridge_hub_common::xcm_version::XcmVersionOfDestAndRemoteBridge; +use pallet_xcm_bridge_hub::XcmAsPlainPayload; -use codec::Encode; use frame_support::{parameter_types, traits::PalletInfoAccess}; +use frame_system::{EnsureNever, EnsureRoot}; +use pallet_bridge_messages::LaneIdOf; +use pallet_bridge_relayers::extension::{ + BridgeRelayersTransactionExtension, WithMessagesExtensionConfig, +}; +use parachains_common::xcm_config::{AllSiblingSystemParachains, RelayOrOtherSystemParachains}; +use polkadot_parachain_primitives::primitives::Sibling; +use testnet_parachains_constants::rococo::currency::UNITS as ROC; use xcm::{ latest::prelude::*, prelude::{InteriorLocation, NetworkId}, }; -use xcm_builder::BridgeBlobDispatcher; +use xcm_builder::{BridgeBlobDispatcher, ParentIsPreset, SiblingParachainConvertsVia}; 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( @@ -61,26 +62,6 @@ parameter_types! { // see the `FEE_BOOST_PER_MESSAGE` constant to get the meaning of this value pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; - pub AssetHubRococoParaId: cumulus_primitives_core::ParaId = bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID.into(); - pub AssetHubWestendParaId: cumulus_primitives_core::ParaId = bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID.into(); - - // Lanes - pub ActiveOutboundLanesToBridgeHubWestend: &'static [bp_messages::LaneId] = &[XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND]; - pub const AssetHubRococoToAssetHubWestendMessagesLane: bp_messages::LaneId = XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND; - pub FromAssetHubRococoToAssetHubWestendRoute: SenderAndLane = SenderAndLane::new( - ParentThen([Parachain(AssetHubRococoParaId::get().into())].into()).into(), - XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, - ); - pub ActiveLanes: alloc::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = alloc::vec![ - ( - FromAssetHubRococoToAssetHubWestendRoute::get(), - (WestendGlobalConsensusNetwork::get(), [Parachain(AssetHubWestendParaId::get().into())].into()) - ) - ]; - - pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); - pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); - pub BridgeHubWestendLocation: Location = Location::new( 2, [ @@ -88,67 +69,33 @@ parameter_types! { Parachain(::PARACHAIN_ID) ] ); -} -pub const XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND: LaneId = LaneId([0, 0, 0, 2]); - -fn build_congestion_message(is_congested: bool) -> alloc::vec::Vec> { - alloc::vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind: OriginKind::Xcm, - require_weight_at_most: - bp_asset_hub_rococo::XcmBridgeHubRouterTransactCallMaxWeight::get(), - call: bp_asset_hub_rococo::Call::ToWestendXcmRouter( - bp_asset_hub_rococo::XcmBridgeHubRouterCall::report_bridge_status { - bridge_id: Default::default(), - is_congested, - } - ) - .encode() - .into(), - } - ] + + pub storage BridgeDeposit: Balance = 5 * ROC; } /// Proof of messages, coming from Westend. -pub type FromWestendBridgeHubMessagesProof = - FromBridgedChainMessagesProof; +pub type FromWestendBridgeHubMessagesProof = + FromBridgedChainMessagesProof>; /// Messages delivery proof for Rococo Bridge Hub -> Westend Bridge Hub messages. -pub type ToWestendBridgeHubMessagesDeliveryProof = - FromBridgedChainMessagesDeliveryProof; +pub type ToWestendBridgeHubMessagesDeliveryProof = + FromBridgedChainMessagesDeliveryProof>; /// Dispatches received XCM messages from other bridge type FromWestendMessageBlobDispatcher = BridgeBlobDispatcher; -/// Export XCM messages to be relayed to the other side -pub type ToBridgeHubWestendHaulBlobExporter = XcmOverBridgeHubWestend; - -pub struct ToBridgeHubWestendXcmBlobHauler; -impl XcmBlobHauler for ToBridgeHubWestendXcmBlobHauler { - type Runtime = Runtime; - type MessagesInstance = WithBridgeHubWestendMessagesInstance; - type ToSourceChainSender = XcmRouter; - type CongestedMessage = CongestedMessage; - type UncongestedMessage = UncongestedMessage; -} - -/// On messages delivered callback. -type OnMessagesDeliveredFromWestend = - XcmBlobHaulerAdapter; - -/// Signed extension that refunds relayers that are delivering messages from the Westend parachain. -pub type OnBridgeHubRococoRefundBridgeHubWestendMessages = RefundSignedExtensionAdapter< - RefundBridgedMessages< +/// Transaction extension that refunds relayers that are delivering messages from the Westend +/// parachain. +pub type OnBridgeHubRococoRefundBridgeHubWestendMessages = BridgeRelayersTransactionExtension< + Runtime, + WithMessagesExtensionConfig< + StrOnBridgeHubRococoRefundBridgeHubWestendMessages, Runtime, - RefundableMessagesLane< - WithBridgeHubWestendMessagesInstance, - AssetHubRococoToAssetHubWestendMessagesLane, - >, - ActualFeeRefund, + WithBridgeHubWestendMessagesInstance, + RelayersForLegacyLaneIdsMessagesInstance, PriorityBoostPerMessage, - StrOnBridgeHubRococoRefundBridgeHubWestendMessages, >, + LaneIdOf, >; bp_runtime::generate_static_str_provider!(OnBridgeHubRococoRefundBridgeHubWestendMessages); @@ -166,41 +113,99 @@ impl pallet_bridge_messages::Config for Ru bp_bridge_hub_westend::BridgeHubWestend, >; - type ActiveOutboundLanes = ActiveOutboundLanesToBridgeHubWestend; - type OutboundPayload = XcmAsPlainPayload; - type InboundPayload = XcmAsPlainPayload; - type DeliveryPayments = (); + type LaneId = LegacyLaneId; + type DeliveryPayments = (); type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< Runtime, WithBridgeHubWestendMessagesInstance, DeliveryRewardInBalance, >; - type MessageDispatch = XcmBlobMessageDispatch< - FromWestendMessageBlobDispatcher, - Self::WeightInfo, - cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< - AssetHubRococoParaId, - Runtime, - >, - >; - type OnMessagesDelivered = OnMessagesDeliveredFromWestend; + type MessageDispatch = XcmOverBridgeHubWestend; + type OnMessagesDelivered = XcmOverBridgeHubWestend; } -/// Add support for the export and dispatch of XCM programs. +/// Add support for the export and dispatch of XCM programs withing +/// `WithBridgeHubWestendMessagesInstance`. pub type XcmOverBridgeHubWestendInstance = pallet_xcm_bridge_hub::Instance1; impl pallet_xcm_bridge_hub::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type UniversalLocation = UniversalLocation; type BridgedNetwork = WestendGlobalConsensusNetworkLocation; type BridgeMessagesPalletInstance = WithBridgeHubWestendMessagesInstance; + type MessageExportPrice = (); type DestinationVersion = XcmVersionOfDestAndRemoteBridge; - type Lanes = ActiveLanes; - type LanesSupport = ToBridgeHubWestendXcmBlobHauler; + + type ForceOrigin = EnsureRoot; + // We don't want to allow creating bridges for this instance with `LegacyLaneId`. + type OpenBridgeOrigin = EnsureNever; + // Converter aligned with `OpenBridgeOrigin`. + type BridgeOriginAccountIdConverter = + (ParentIsPreset, SiblingParachainConvertsVia); + + type BridgeDeposit = BridgeDeposit; + type Currency = Balances; + type RuntimeHoldReason = RuntimeHoldReason; + // Do not require deposit from system parachains or relay chain + type AllowWithoutBridgeDeposit = + RelayOrOtherSystemParachains; + + // TODO:(bridges-v2) - add `LocalXcmChannelManager` impl - https://github.com/paritytech/parity-bridges-common/issues/3047 + type LocalXcmChannelManager = (); + type BlobDispatcher = FromWestendMessageBlobDispatcher; +} + +#[cfg(feature = "runtime-benchmarks")] +pub(crate) fn open_bridge_for_benchmarks( + with: pallet_xcm_bridge_hub::LaneIdOf, + sibling_para_id: u32, +) -> InteriorLocation +where + R: pallet_xcm_bridge_hub::Config, + XBHI: 'static, + C: xcm_executor::traits::ConvertLocation< + bp_runtime::AccountIdOf>, + >, +{ + use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; + use sp_runtime::traits::Zero; + use xcm::VersionedInteriorLocation; + + // insert bridge metadata + let lane_id = with; + let sibling_parachain = Location::new(1, [Parachain(sibling_para_id)]); + let universal_source = [GlobalConsensus(Rococo), Parachain(sibling_para_id)].into(); + let universal_destination = [GlobalConsensus(Westend), Parachain(2075)].into(); + let bridge_id = BridgeId::new(&universal_source, &universal_destination); + + // insert only bridge metadata, because the benchmarks create lanes + pallet_xcm_bridge_hub::Bridges::::insert( + bridge_id, + Bridge { + bridge_origin_relative_location: alloc::boxed::Box::new( + sibling_parachain.clone().into(), + ), + bridge_origin_universal_location: alloc::boxed::Box::new( + VersionedInteriorLocation::from(universal_source.clone()), + ), + bridge_destination_universal_location: alloc::boxed::Box::new( + VersionedInteriorLocation::from(universal_destination), + ), + state: BridgeState::Opened, + bridge_owner_account: C::convert_location(&sibling_parachain).expect("valid AccountId"), + deposit: Zero::zero(), + lane_id, + }, + ); + pallet_xcm_bridge_hub::LaneToBridge::::insert(lane_id, bridge_id); + + universal_source } #[cfg(test)] @@ -209,14 +214,11 @@ mod tests { use crate::bridge_common_config::BridgeGrandpaWestendInstance; use bridge_runtime_common::{ assert_complete_bridge_types, - extensions::refund_relayer_extension::RefundableParachain, integrity::{ assert_complete_with_parachain_bridge_constants, check_message_lane_weights, AssertChainConstants, AssertCompleteBridgeConstants, }, }; - use parachains_common::Balance; - use testnet_parachains_constants::rococo; /// Every additional message in the message delivery transaction boosts its priority. /// So the priority of transaction with `N+1` messages is larger than priority of @@ -227,12 +229,12 @@ mod tests { /// /// We want this tip to be large enough (delivery transactions with more messages = less /// operational costs and a faster bridge), so this value should be significant. - const FEE_BOOST_PER_MESSAGE: Balance = 2 * rococo::currency::UNITS; + const FEE_BOOST_PER_MESSAGE: Balance = 2 * ROC; // see `FEE_BOOST_PER_MESSAGE` comment - const FEE_BOOST_PER_RELAY_HEADER: Balance = 2 * rococo::currency::UNITS; + const FEE_BOOST_PER_RELAY_HEADER: Balance = 2 * ROC; // see `FEE_BOOST_PER_MESSAGE` comment - const FEE_BOOST_PER_PARACHAIN_HEADER: Balance = 2 * rococo::currency::UNITS; + const FEE_BOOST_PER_PARACHAIN_HEADER: Balance = 2 * ROC; #[test] fn ensure_bridge_hub_rococo_message_lane_weights_are_correct() { @@ -270,19 +272,20 @@ mod tests { }, }); - bridge_runtime_common::extensions::priority_calculator::per_relay_header::ensure_priority_boost_is_sane::< + pallet_bridge_relayers::extension::per_relay_header::ensure_priority_boost_is_sane::< Runtime, BridgeGrandpaWestendInstance, PriorityBoostPerRelayHeader, >(FEE_BOOST_PER_RELAY_HEADER); - bridge_runtime_common::extensions::priority_calculator::per_parachain_header::ensure_priority_boost_is_sane::< + pallet_bridge_relayers::extension::per_parachain_header::ensure_priority_boost_is_sane::< Runtime, - RefundableParachain, + WithBridgeHubWestendMessagesInstance, + bp_bridge_hub_westend::BridgeHubWestend, PriorityBoostPerParachainHeader, >(FEE_BOOST_PER_PARACHAIN_HEADER); - bridge_runtime_common::extensions::priority_calculator::per_message::ensure_priority_boost_is_sane::< + pallet_bridge_relayers::extension::per_message::ensure_priority_boost_is_sane::< Runtime, WithBridgeHubWestendMessagesInstance, PriorityBoostPerMessage, @@ -296,3 +299,98 @@ mod tests { assert_eq!(BridgeRococoToWestendMessagesPalletInstance::get(), expected,); } } + +/// Contains the migration for the AssetHubRococo<>AssetHubWestend bridge. +pub mod migration { + use super::*; + use frame_support::traits::ConstBool; + + parameter_types! { + pub AssetHubRococoToAssetHubWestendMessagesLane: LegacyLaneId = LegacyLaneId([0, 0, 0, 2]); + pub AssetHubRococoLocation: Location = Location::new(1, [Parachain(bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID)]); + pub AssetHubWestendUniversalLocation: InteriorLocation = [GlobalConsensus(WestendGlobalConsensusNetwork::get()), Parachain(bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID)].into(); + } + + /// Ensure that the existing lanes for the AHR<>AHW bridge are correctly configured. + pub type StaticToDynamicLanes = pallet_xcm_bridge_hub::migration::OpenBridgeForLane< + Runtime, + XcmOverBridgeHubWestendInstance, + AssetHubRococoToAssetHubWestendMessagesLane, + // the lanes are already created for AHR<>AHW, but we need to link them to the bridge + // structs + ConstBool, + AssetHubRococoLocation, + AssetHubWestendUniversalLocation, + >; + + mod v1_wrong { + use bp_messages::{LaneState, MessageNonce, UnrewardedRelayer}; + use bp_runtime::AccountIdOf; + use codec::{Decode, Encode}; + use pallet_bridge_messages::BridgedChainOf; + use sp_std::collections::vec_deque::VecDeque; + + #[derive(Encode, Decode, Clone, PartialEq, Eq)] + pub(crate) struct StoredInboundLaneData, I: 'static>( + pub(crate) InboundLaneData>>, + ); + #[derive(Encode, Decode, Clone, PartialEq, Eq)] + pub(crate) struct InboundLaneData { + pub state: LaneState, + pub(crate) relayers: VecDeque>, + pub(crate) last_confirmed_nonce: MessageNonce, + } + #[derive(Encode, Decode, Clone, PartialEq, Eq)] + pub(crate) struct OutboundLaneData { + pub state: LaneState, + pub(crate) oldest_unpruned_nonce: MessageNonce, + pub(crate) latest_received_nonce: MessageNonce, + pub(crate) latest_generated_nonce: MessageNonce, + } + } + + mod v1 { + pub use bp_messages::{InboundLaneData, LaneState, OutboundLaneData}; + pub use pallet_bridge_messages::{InboundLanes, OutboundLanes, StoredInboundLaneData}; + } + + /// Fix for v1 migration - corrects data for OutboundLaneData/InboundLaneData (it is needed only + /// for Rococo/Westend). + pub struct FixMessagesV1Migration(sp_std::marker::PhantomData<(T, I)>); + + impl, I: 'static> frame_support::traits::OnRuntimeUpgrade + for FixMessagesV1Migration + { + fn on_runtime_upgrade() -> Weight { + use sp_core::Get; + let mut weight = T::DbWeight::get().reads(1); + + // `InboundLanes` - add state to the old structs + let translate_inbound = + |pre: v1_wrong::StoredInboundLaneData| -> Option> { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + Some(v1::StoredInboundLaneData(v1::InboundLaneData { + state: v1::LaneState::Opened, + relayers: pre.0.relayers, + last_confirmed_nonce: pre.0.last_confirmed_nonce, + })) + }; + v1::InboundLanes::::translate_values(translate_inbound); + + // `OutboundLanes` - add state to the old structs + let translate_outbound = + |pre: v1_wrong::OutboundLaneData| -> Option { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + Some(v1::OutboundLaneData { + state: v1::LaneState::Opened, + oldest_unpruned_nonce: pre.oldest_unpruned_nonce, + latest_received_nonce: pre.latest_received_nonce, + latest_generated_nonce: pre.latest_generated_nonce, + }) + }; + v1::OutboundLanes::::translate_values(translate_outbound); + + weight + } + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/genesis_config_presets.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/genesis_config_presets.rs new file mode 100644 index 000000000000..d1b599967bf3 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/genesis_config_presets.rs @@ -0,0 +1,136 @@ +// 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. + +//! # Bridge Hub Rococo Runtime genesis config presets + +use crate::*; +use alloc::{vec, vec::Vec}; +use cumulus_primitives_core::ParaId; +use parachains_common::{AccountId, AuraId}; +use sp_genesis_builder::PresetId; +use sp_keyring::Sr25519Keyring; +use testnet_parachains_constants::rococo::xcm_version::SAFE_XCM_VERSION; + +const BRIDGE_HUB_ROCOCO_ED: Balance = ExistentialDeposit::get(); + +fn bridge_hub_rococo_genesis( + invulnerables: Vec<(AccountId, AuraId)>, + endowed_accounts: Vec, + id: ParaId, + bridges_pallet_owner: Option, + asset_hub_para_id: ParaId, + opened_bridges: Vec<(Location, InteriorLocation, Option)>, +) -> serde_json::Value { + let config = RuntimeGenesisConfig { + balances: BalancesConfig { + balances: endowed_accounts + .iter() + .cloned() + .map(|k| (k, 1u128 << 60)) + .collect::>(), + }, + parachain_info: ParachainInfoConfig { parachain_id: id, ..Default::default() }, + collator_selection: CollatorSelectionConfig { + invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: BRIDGE_HUB_ROCOCO_ED * 16, + ..Default::default() + }, + session: SessionConfig { + keys: invulnerables + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + SessionKeys { aura }, // session keys + ) + }) + .collect(), + ..Default::default() + }, + polkadot_xcm: PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + bridge_westend_grandpa: BridgeWestendGrandpaConfig { + owner: bridges_pallet_owner.clone(), + ..Default::default() + }, + bridge_westend_messages: BridgeWestendMessagesConfig { + owner: bridges_pallet_owner.clone(), + ..Default::default() + }, + xcm_over_bridge_hub_westend: XcmOverBridgeHubWestendConfig { + opened_bridges, + ..Default::default() + }, + ethereum_system: EthereumSystemConfig { + para_id: id, + asset_hub_para_id, + ..Default::default() + }, + ..Default::default() + }; + + serde_json::to_value(config).expect("Could not build genesis config.") +} + +/// Provides the JSON representation of predefined genesis config for given `id`. +pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option> { + let patch = match id.try_into() { + Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) => bridge_hub_rococo_genesis( + // initial collators. + vec![ + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), + ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), + 1013.into(), + Some(Sr25519Keyring::Bob.to_account_id()), + rococo_runtime_constants::system_parachain::ASSET_HUB_ID.into(), + vec![( + Location::new(1, [Parachain(1000)]), + Junctions::from([Westend.into(), Parachain(1000)]), + Some(bp_messages::LegacyLaneId([0, 0, 0, 2])), + )], + ), + Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => bridge_hub_rococo_genesis( + // initial collators. + vec![ + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), + ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), + 1013.into(), + Some(Sr25519Keyring::Bob.to_account_id()), + rococo_runtime_constants::system_parachain::ASSET_HUB_ID.into(), + vec![], + ), + _ => return None, + }; + Some( + serde_json::to_string(&patch) + .expect("serialization to json is expected to work. qed.") + .into_bytes(), + ) +} + +/// List of supported presets. +pub fn preset_names() -> Vec { + vec![ + PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET), + PresetId::from(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET), + ] +} 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 512c1199f439..f63e1f8fcf65 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 @@ -32,6 +32,7 @@ pub mod bridge_common_config; pub mod bridge_to_bulletin_config; pub mod bridge_to_ethereum_config; pub mod bridge_to_westend_config; +mod genesis_config_presets; mod weights; pub mod xcm_config; @@ -39,33 +40,24 @@ extern crate alloc; use alloc::{vec, vec::Vec}; use bridge_runtime_common::extensions::{ - check_obsolete_extension::{ - CheckAndBoostBridgeGrandpaTransactions, CheckAndBoostBridgeParachainsTransactions, - }, - refund_relayer_extension::RefundableParachain, + CheckAndBoostBridgeGrandpaTransactions, CheckAndBoostBridgeParachainsTransactions, }; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; -use snowbridge_beacon_primitives::{Fork, ForkVersions}; -use snowbridge_core::{ - gwei, meth, - outbound::{Command, Fee}, - AgentId, AllowSiblingsOnly, PricingParameters, Rewards, -}; -use snowbridge_router_primitives::inbound::MessageToXcm; +use pallet_bridge_messages::LaneIdOf; use sp_api::impl_runtime_apis; -use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H160}; +use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, - traits::{Block as BlockT, Keccak256}, + traits::Block as BlockT, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, FixedU128, + ApplyExtrinsicResult, }; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use cumulus_primitives_core::ParaId; +use cumulus_primitives_core::{ClaimQueueOffset, CoreSelector, ParaId}; use frame_support::{ construct_runtime, derive_impl, dispatch::DispatchClass, @@ -79,16 +71,13 @@ use frame_system::{ limits::{BlockLength, BlockWeights}, EnsureRoot, }; -use testnet_parachains_constants::rococo::{ - consensus::*, currency::*, fee::WeightToFee, snowbridge::INBOUND_QUEUE_PALLET_INDEX, time::*, -}; +use testnet_parachains_constants::rococo::{consensus::*, currency::*, fee::WeightToFee, time::*}; use bp_runtime::HeaderId; use bridge_hub_common::{ message_queue::{NarrowOriginToSibling, ParaIdToSibling}, AggregateMessageOrigin, }; -use pallet_xcm::EnsureXcm; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::{MultiAddress, Perbill, Permill}; use xcm::VersionedLocation; @@ -99,7 +88,11 @@ pub use sp_runtime::BuildStorage; use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use rococo_runtime_constants::system_parachain::{ASSET_HUB_ID, BRIDGE_HUB_ID}; -use xcm::prelude::*; +use snowbridge_core::{ + outbound::{Command, Fee}, + AgentId, PricingParameters, +}; +use xcm::{latest::prelude::*, prelude::*}; use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, @@ -114,8 +107,6 @@ use parachains_common::{ #[cfg(feature = "runtime-benchmarks")] use alloc::boxed::Box; -#[cfg(feature = "runtime-benchmarks")] -use benchmark_helpers::DoNothingRouter; /// The address format for describing accounts. pub type Address = MultiAddress; @@ -129,8 +120,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The TransactionExtension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -140,16 +131,14 @@ pub type SignedExtra = ( frame_system::CheckWeight, pallet_transaction_payment::ChargeTransactionPayment, BridgeRejectObsoleteHeadersAndMessages, - ( - bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages, - bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages, - ), + (bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages,), + frame_metadata_hash_extension::CheckMetadataHash, cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -164,10 +153,41 @@ pub type Migrations = ( ConstU32, ConstU32, >, + pallet_bridge_messages::migration::v1::MigrationToV1< + Runtime, + bridge_to_westend_config::WithBridgeHubWestendMessagesInstance, + >, + pallet_bridge_messages::migration::v1::MigrationToV1< + Runtime, + bridge_to_bulletin_config::WithRococoBulletinMessagesInstance, + >, + bridge_to_westend_config::migration::FixMessagesV1Migration< + Runtime, + bridge_to_westend_config::WithBridgeHubWestendMessagesInstance, + >, + bridge_to_westend_config::migration::StaticToDynamicLanes, + bridge_to_bulletin_config::migration::StaticToDynamicLanes, + frame_support::migrations::RemoveStorage< + BridgeWestendMessagesPalletName, + OutboundLanesCongestedSignalsKey, + RocksDbWeight, + >, + frame_support::migrations::RemoveStorage< + BridgePolkadotBulletinMessagesPalletName, + OutboundLanesCongestedSignalsKey, + RocksDbWeight, + >, + pallet_bridge_relayers::migration::v1::MigrationToV1, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); +parameter_types! { + pub const BridgeWestendMessagesPalletName: &'static str = "BridgeWestendMessages"; + pub const BridgePolkadotBulletinMessagesPalletName: &'static str = "BridgePolkadotBulletinMessages"; + pub const OutboundLanesCongestedSignalsKey: &'static str = "OutboundLanesCongestedSignals"; +} + /// Migration to initialize storage versions for pallets added after genesis. /// /// Ideally this would be done automatically (see @@ -218,11 +238,11 @@ 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_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 5, - state_version: 1, + transaction_version: 6, + system_version: 1, }; /// The version information used to identify this runtime when compiled natively. @@ -278,6 +298,8 @@ impl frame_system::Config for Runtime { type DbWeight = RocksDbWeight; /// Weight information for the extrinsics of this pallet. type SystemWeightInfo = weights::frame_system::WeightInfo; + /// Weight information for the extensions of this pallet. + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; /// Block & extrinsics weights: base values and limits. type BlockWeights = RuntimeBlockWeights; /// The maximum length of a block (in bytes). @@ -322,6 +344,7 @@ impl pallet_balances::Config for Runtime { type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxFreezes = ConstU32<0>; + type DoneSlashHandler = (); } parameter_types! { @@ -337,6 +360,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -356,6 +380,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type ReservedXcmpWeight = ReservedXcmpWeight; type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; type ConsensusHook = ConsensusHook; + type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector; } type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< @@ -518,174 +543,6 @@ impl pallet_utility::Config for Runtime { type WeightInfo = weights::pallet_utility::WeightInfo; } -// 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), - }; -} - -#[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)) - } - } -} - -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 = 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 = 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 = 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 = weights::snowbridge_pallet_system::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type Helper = (); - type DefaultPricingParameters = Parameters; - type InboundDeliveryCost = EthereumInboundQueue; -} - // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime @@ -743,6 +600,9 @@ construct_runtime!( // With-Rococo Bulletin bridge hub pallet. XcmOverPolkadotBulletin: pallet_xcm_bridge_hub:: = 62, + // Bridge relayers pallet, used by several bridges here (another instance). + BridgeRelayersForPermissionlessLanes: pallet_bridge_relayers:: = 63, + EthereumInboundQueue: snowbridge_pallet_inbound_queue = 80, EthereumOutboundQueue: snowbridge_pallet_outbound_queue = 81, EthereumBeaconClient: snowbridge_pallet_ethereum_client = 82, @@ -779,10 +639,8 @@ bridge_runtime_common::generate_bridge_reject_obsolete_headers_and_messages! { // Parachains CheckAndBoostBridgeParachainsTransactions< Runtime, - RefundableParachain< bridge_common_config::BridgeParachainWestendInstance, - bp_bridge_hub_westend::BridgeHubWestend, - >, + bp_bridge_hub_westend::BridgeHubWestend, bridge_to_westend_config::PriorityBoostPerParachainHeader, xcm_config::TreasuryAccount, >, @@ -795,12 +653,14 @@ bridge_runtime_common::generate_bridge_reject_obsolete_headers_and_messages! { mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] + [pallet_transaction_payment, TransactionPayment] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] @@ -814,7 +674,8 @@ mod benches { [pallet_bridge_parachains, WithinWestend] [pallet_bridge_messages, RococoToWestend] [pallet_bridge_messages, RococoToRococoBulletin] - [pallet_bridge_relayers, BridgeRelayersBench::] + [pallet_bridge_relayers, Legacy] + [pallet_bridge_relayers, PermissionlessLanes] // Ethereum Bridge [snowbridge_pallet_inbound_queue, EthereumInboundQueue] [snowbridge_pallet_outbound_queue, EthereumOutboundQueue] @@ -823,6 +684,11 @@ mod benches { ); } +cumulus_pallet_parachain_system::register_validate_block! { + Runtime = Runtime, + BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, +} + impl_runtime_apis! { impl sp_consensus_aura::AuraApi for Runtime { fn slot_duration() -> sp_consensus_aura::SlotDuration { @@ -1030,6 +896,12 @@ impl_runtime_apis! { } } + impl cumulus_primitives_core::GetCoreSelectorApi for Runtime { + fn core_selector() -> (CoreSelector, ClaimQueueOffset) { + ParachainSystem::core_selector() + } + } + impl bp_westend::WestendFinalityApi for Runtime { fn best_finalized() -> Option> { BridgeWestendGrandpa::best_finalized() @@ -1060,7 +932,7 @@ impl_runtime_apis! { // This is exposed by BridgeHubRococo impl bp_bridge_hub_westend::FromBridgeHubWestendInboundLaneApi for Runtime { fn message_details( - lane: bp_messages::LaneId, + lane: LaneIdOf, messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>, ) -> Vec { bridge_runtime_common::messages_api::inbound_message_details::< @@ -1073,7 +945,7 @@ impl_runtime_apis! { // This is exposed by BridgeHubRococo impl bp_bridge_hub_westend::ToBridgeHubWestendOutboundLaneApi for Runtime { fn message_details( - lane: bp_messages::LaneId, + lane: LaneIdOf, begin: bp_messages::MessageNonce, end: bp_messages::MessageNonce, ) -> Vec { @@ -1103,7 +975,7 @@ impl_runtime_apis! { impl bp_polkadot_bulletin::FromPolkadotBulletinInboundLaneApi for Runtime { fn message_details( - lane: bp_messages::LaneId, + lane: LaneIdOf, messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>, ) -> Vec { bridge_runtime_common::messages_api::inbound_message_details::< @@ -1115,7 +987,7 @@ impl_runtime_apis! { impl bp_polkadot_bulletin::ToPolkadotBulletinOutboundLaneApi for Runtime { fn message_details( - lane: bp_messages::LaneId, + lane: LaneIdOf, begin: bp_messages::MessageNonce, end: bp_messages::MessageNonce, ) -> Vec { @@ -1170,6 +1042,7 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; @@ -1185,6 +1058,8 @@ impl_runtime_apis! { type WithinWestend = pallet_bridge_parachains::benchmarking::Pallet::; type RococoToWestend = pallet_bridge_messages::benchmarking::Pallet ::; type RococoToRococoBulletin = pallet_bridge_messages::benchmarking::Pallet ::; + type Legacy = BridgeRelayersBench::; + type PermissionlessLanes = BridgeRelayersBench::; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -1200,6 +1075,7 @@ impl_runtime_apis! { use sp_storage::TrackedStorageKey; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -1378,11 +1254,46 @@ impl_runtime_apis! { ); BenchmarkError::Stop("XcmVersion was not stored!") })?; + + let sibling_parachain_location = Location::new(1, [Parachain(5678)]); + + // fund SA + use frame_support::traits::fungible::Mutate; + use xcm_executor::traits::ConvertLocation; + frame_support::assert_ok!( + Balances::mint_into( + &xcm_config::LocationToAccountId::convert_location(&sibling_parachain_location).expect("valid AccountId"), + bridge_to_westend_config::BridgeDeposit::get() + .saturating_add(ExistentialDeposit::get()) + .saturating_add(UNITS * 5) + ) + ); + + // open bridge + let bridge_destination_universal_location: InteriorLocation = [GlobalConsensus(NetworkId::Westend), Parachain(8765)].into(); + let locations = XcmOverBridgeHubWestend::bridge_locations( + sibling_parachain_location.clone(), + bridge_destination_universal_location.clone(), + )?; + XcmOverBridgeHubWestend::do_open_bridge( + locations, + bp_messages::LegacyLaneId([1, 2, 3, 4]), + true, + ).map_err(|e| { + log::error!( + "Failed to `XcmOverBridgeHubWestend::open_bridge`({:?}, {:?})`, error: {:?}", + sibling_parachain_location, + bridge_destination_universal_location, + e + ); + BenchmarkError::Stop("Bridge was not opened!") + })?; + Ok( ( - bridge_to_westend_config::FromAssetHubRococoToAssetHubWestendRoute::get().location, + sibling_parachain_location, NetworkId::Westend, - [Parachain(bridge_to_westend_config::AssetHubWestendParaId::get().into())].into() + [Parachain(8765)].into() ) ) } @@ -1399,6 +1310,8 @@ impl_runtime_apis! { type WithinWestend = pallet_bridge_parachains::benchmarking::Pallet::; type RococoToWestend = pallet_bridge_messages::benchmarking::Pallet ::; type RococoToRococoBulletin = pallet_bridge_messages::benchmarking::Pallet ::; + type Legacy = BridgeRelayersBench::; + type PermissionlessLanes = BridgeRelayersBench::; use bridge_runtime_common::messages_benchmarking::{ prepare_message_delivery_proof_from_grandpa_chain, @@ -1416,7 +1329,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( @@ -1428,21 +1342,31 @@ impl_runtime_apis! { } fn prepare_message_proof( - params: MessageProofParams, - ) -> (bridge_to_westend_config::FromWestendBridgeHubMessagesProof, Weight) { + params: MessageProofParams>, + ) -> (bridge_to_westend_config::FromWestendBridgeHubMessagesProof, Weight) { use cumulus_primitives_core::XcmpMessageSource; assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); + let universal_source = bridge_to_westend_config::open_bridge_for_benchmarks::< + Runtime, + bridge_to_westend_config::XcmOverBridgeHubWestendInstance, + xcm_config::LocationToAccountId, + >(params.lane, 42); prepare_message_proof_from_parachain::< Runtime, bridge_common_config::BridgeGrandpaWestendInstance, bridge_to_westend_config::WithBridgeHubWestendMessagesInstance, - >(params, generate_xcm_builder_bridge_message_sample([GlobalConsensus(Rococo), Parachain(42)].into())) + >(params, generate_xcm_builder_bridge_message_sample(universal_source)) } fn prepare_message_delivery_proof( - params: MessageDeliveryProofParams, - ) -> bridge_to_westend_config::ToWestendBridgeHubMessagesDeliveryProof { + params: MessageDeliveryProofParams>, + ) -> bridge_to_westend_config::ToWestendBridgeHubMessagesDeliveryProof { + let _ = bridge_to_westend_config::open_bridge_for_benchmarks::< + Runtime, + bridge_to_westend_config::XcmOverBridgeHubWestendInstance, + xcm_config::LocationToAccountId, + >(params.lane, 42); prepare_message_delivery_proof_from_parachain::< Runtime, bridge_common_config::BridgeGrandpaWestendInstance, @@ -1463,21 +1387,31 @@ impl_runtime_apis! { } fn prepare_message_proof( - params: MessageProofParams, - ) -> (bridge_to_bulletin_config::FromRococoBulletinMessagesProof, Weight) { + params: MessageProofParams>, + ) -> (bridge_to_bulletin_config::FromRococoBulletinMessagesProof, Weight) { use cumulus_primitives_core::XcmpMessageSource; assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); + let universal_source = bridge_to_bulletin_config::open_bridge_for_benchmarks::< + Runtime, + bridge_to_bulletin_config::XcmOverPolkadotBulletinInstance, + xcm_config::LocationToAccountId, + >(params.lane, 42); prepare_message_proof_from_grandpa_chain::< Runtime, bridge_common_config::BridgeGrandpaRococoBulletinInstance, bridge_to_bulletin_config::WithRococoBulletinMessagesInstance, - >(params, generate_xcm_builder_bridge_message_sample([GlobalConsensus(Rococo), Parachain(42)].into())) + >(params, generate_xcm_builder_bridge_message_sample(universal_source)) } fn prepare_message_delivery_proof( - params: MessageDeliveryProofParams, - ) -> bridge_to_bulletin_config::ToRococoBulletinMessagesDeliveryProof { + params: MessageDeliveryProofParams>, + ) -> bridge_to_bulletin_config::ToRococoBulletinMessagesDeliveryProof { + let _ = bridge_to_bulletin_config::open_bridge_for_benchmarks::< + Runtime, + bridge_to_bulletin_config::XcmOverPolkadotBulletinInstance, + xcm_config::LocationToAccountId, + >(params.lane, 42); prepare_message_delivery_proof_from_grandpa_chain::< Runtime, bridge_common_config::BridgeGrandpaRococoBulletinInstance, @@ -1509,8 +1443,8 @@ impl_runtime_apis! { parachain_head_size: u32, proof_params: bp_runtime::UnverifiedStorageProofParams, ) -> ( - pallet_bridge_parachains::RelayBlockNumber, - pallet_bridge_parachains::RelayBlockHash, + bp_parachains::RelayBlockNumber, + bp_parachains::RelayBlockHash, bp_polkadot_core::parachains::ParaHeadsProof, Vec<(bp_polkadot_core::parachains::ParaId, bp_polkadot_core::parachains::ParaHash)>, ) { @@ -1522,16 +1456,36 @@ impl_runtime_apis! { } } - impl BridgeRelayersConfig for Runtime { + impl BridgeRelayersConfig for Runtime { fn prepare_rewards_account( - account_params: bp_relayers::RewardsAccountParams, + account_params: bp_relayers::RewardsAccountParams<>::LaneId>, reward: Balance, ) { let rewards_account = bp_relayers::PayRewardFromAccount::< Balances, - AccountId + AccountId, + >::LaneId, >::rewards_account(account_params); - Self::deposit_account(rewards_account, reward); + >::deposit_account(rewards_account, reward); + } + + fn deposit_account(account: AccountId, balance: Balance) { + use frame_support::traits::fungible::Mutate; + Balances::mint_into(&account, balance.saturating_add(ExistentialDeposit::get())).unwrap(); + } + } + + impl BridgeRelayersConfig for Runtime { + fn prepare_rewards_account( + account_params: bp_relayers::RewardsAccountParams<>::LaneId>, + reward: Balance, + ) { + let rewards_account = bp_relayers::PayRewardFromAccount::< + Balances, + AccountId, + >::LaneId, + >::rewards_account(account_params); + >::deposit_account(rewards_account, reward); } fn deposit_account(account: AccountId, balance: Balance) { @@ -1567,18 +1521,22 @@ impl_runtime_apis! { } fn get_preset(id: &Option) -> Option> { - get_preset::(id, |_| None) + get_preset::(id, &genesis_config_presets::get_preset) } fn preset_names() -> Vec { - vec![] + genesis_config_presets::preset_names() } } -} -cumulus_pallet_parachain_system::register_validate_block! { - Runtime = Runtime, - BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } } #[cfg(test)] @@ -1587,49 +1545,49 @@ mod tests { use codec::Encode; use sp_runtime::{ generic::Era, - traits::{SignedExtension, Zero}, + traits::{TransactionExtension, Zero}, }; #[test] - fn ensure_signed_extension_definition_is_compatible_with_relay() { - use bp_polkadot_core::SuffixedCommonSignedExtensionExt; + fn ensure_transaction_extension_definition_is_compatible_with_relay() { + use bp_polkadot_core::SuffixedCommonTransactionExtensionExt; 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(), - ), + frame_system::BlockHash::::insert(BlockNumber::zero(), Hash::default()); + let payload: TxExtension = ( + 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(), + ), + frame_metadata_hash_extension::CheckMetadataHash::new(false), 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() - ) - } - }); + ); + + // for BridgeHubRococo + { + let bhr_indirect_payload = bp_bridge_hub_rococo::TransactionExtension::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!( + TxExtension::implicit(&payload).unwrap().encode().split_last().unwrap().1, + sp_runtime::traits::TransactionExtension::::implicit(&bhr_indirect_payload).unwrap().encode() + ) + } + }); } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/block_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/block_weights.rs index e7fdb2aae2a0..41e30725e753 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/block_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/extrinsic_weights.rs index 1a4adb968bb7..3bd48f061bba 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/extrinsic_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..64eef1b4f740 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/frame_system_extensions.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ +// --chain=bridge-hub-rococo-dev + +#![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 `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_genesis() -> Weight { + // Proof Size summary in bytes: + // Measured: `54` + // Estimated: `3509` + // Minimum execution time: 3_136_000 picoseconds. + Weight::from_parts(5_842_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_mortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_771_000 picoseconds. + Weight::from_parts(8_857_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_immortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_771_000 picoseconds. + Weight::from_parts(8_857_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 732_000 picoseconds. + Weight::from_parts(2_875_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_627_000 picoseconds. + Weight::from_parts(6_322_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 471_000 picoseconds. + Weight::from_parts(2_455_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 491_000 picoseconds. + Weight::from_parts(2_916_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1533` + // Minimum execution time: 3_798_000 picoseconds. + Weight::from_parts(6_272_000, 0) + .saturating_add(Weight::from_parts(0, 1533)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs index 942f243141da..74796e626a2e 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/mod.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 @@ -27,6 +27,7 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_balances; pub mod pallet_bridge_grandpa; pub mod pallet_bridge_messages_rococo_to_rococo_bulletin; @@ -38,6 +39,7 @@ pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; pub mod paritydb_weights; diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs index 4ce57b2e5016..a9cc2411a9c6 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_grandpa.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_grandpa` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yaoqqom-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: @@ -68,13 +68,13 @@ impl pallet_bridge_grandpa::WeightInfo for WeightInfo pallet_bridge_grandpa::WeightInfo for WeightInfo pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `654` - // Estimated: `52645` - // Minimum execution time: 37_206_000 picoseconds. - Weight::from_parts(38_545_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `933` + // Estimated: `52674` + // Minimum execution time: 61_893_000 picoseconds. + Weight::from_parts(63_358_000, 0) + .saturating_add(Weight::from_parts(0, 52674)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgePolkadotBulletinMessages::PalletOperatingMode` (r:1 w:0) @@ -71,21 +75,25 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 4076]`. /// The range of component `n` is `[1, 4076]`. fn receive_n_messages_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `654` - // Estimated: `52645` - // Minimum execution time: 37_075_000 picoseconds. - Weight::from_parts(37_757_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 5_776 - .saturating_add(Weight::from_parts(11_586_768, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `933` + // Estimated: `52674` + // Minimum execution time: 61_612_000 picoseconds. + Weight::from_parts(62_758_000, 0) + .saturating_add(Weight::from_parts(0, 52674)) + // Standard Error: 13_521 + .saturating_add(Weight::from_parts(14_530_846, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgePolkadotBulletinMessages::PalletOperatingMode` (r:1 w:0) @@ -93,17 +101,21 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `654` - // Estimated: `52645` - // Minimum execution time: 42_087_000 picoseconds. - Weight::from_parts(42_970_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `933` + // Estimated: `52674` + // Minimum execution time: 66_862_000 picoseconds. + Weight::from_parts(69_531_000, 0) + .saturating_add(Weight::from_parts(0, 52674)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgePolkadotBulletinMessages::PalletOperatingMode` (r:1 w:0) @@ -111,21 +123,25 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16384]`. /// The range of component `n` is `[1, 16384]`. fn receive_single_n_bytes_message_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `654` - // Estimated: `52645` - // Minimum execution time: 35_055_000 picoseconds. - Weight::from_parts(36_987_740, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 4 - .saturating_add(Weight::from_parts(2_316, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(4)) + // Measured: `933` + // Estimated: `52674` + // Minimum execution time: 58_971_000 picoseconds. + Weight::from_parts(62_999_984, 0) + .saturating_add(Weight::from_parts(0, 52674)) + // Standard Error: 7 + .saturating_add(Weight::from_parts(2_050, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgePolkadotBulletinMessages::PalletOperatingMode` (r:1 w:0) @@ -133,55 +149,77 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Storage: `BridgePolkadotBulletinMessages::OutboundMessages` (r:0 w:1) + /// Proof: `BridgePolkadotBulletinMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `621` - // Estimated: `2543` - // Minimum execution time: 24_326_000 picoseconds. - Weight::from_parts(25_169_000, 0) - .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) + // Measured: `900` + // Estimated: `5383` + // Minimum execution time: 43_066_000 picoseconds. + Weight::from_parts(43_878_000, 0) + .saturating_add(Weight::from_parts(0, 5383)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `BridgePolkadotBulletinMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgePolkadotBulletinMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Storage: `BridgePolkadotBulletinMessages::OutboundMessages` (r:0 w:2) + /// Proof: `BridgePolkadotBulletinMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `621` - // Estimated: `2543` - // Minimum execution time: 24_484_000 picoseconds. - Weight::from_parts(25_130_000, 0) - .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) + // Measured: `900` + // Estimated: `5383` + // Minimum execution time: 44_120_000 picoseconds. + Weight::from_parts(45_914_000, 0) + .saturating_add(Weight::from_parts(0, 5383)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `BridgePolkadotBulletinMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgePolkadotBulletinMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Storage: `BridgePolkadotBulletinMessages::OutboundMessages` (r:0 w:2) + /// Proof: `BridgePolkadotBulletinMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `621` - // Estimated: `2543` - // Minimum execution time: 24_450_000 picoseconds. - Weight::from_parts(25_164_000, 0) - .saturating_add(Weight::from_parts(0, 2543)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) + // Measured: `900` + // Estimated: `5383` + // Minimum execution time: 44_930_000 picoseconds. + Weight::from_parts(46_111_000, 0) + .saturating_add(Weight::from_parts(0, 5383)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `BridgePolkadotBulletinMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgePolkadotBulletinMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (r:1 w:0) /// Proof: `BridgePolkadotBulletinGrandpa::ImportedHeaders` (`max_values`: Some(1024), `max_size`: Some(68), added: 1553, mode: `MaxEncodedLen`) /// Storage: `BridgePolkadotBulletinMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgePolkadotBulletinMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverPolkadotBulletin::Bridges` (r:1 w:0) + /// Proof: `XcmOverPolkadotBulletin::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, 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: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) @@ -202,14 +240,14 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// The range of component `n` is `[1, 16384]`. fn receive_single_n_bytes_message_proof_with_dispatch(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `813` - // Estimated: `52645` - // Minimum execution time: 54_317_000 picoseconds. - Weight::from_parts(59_171_547, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 7 - .saturating_add(Weight::from_parts(7_566, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(10)) + // Measured: `1092` + // Estimated: `52674` + // Minimum execution time: 81_911_000 picoseconds. + Weight::from_parts(88_170_136, 0) + .saturating_add(Weight::from_parts(0, 52674)) + // Standard Error: 9 + .saturating_add(Weight::from_parts(7_233, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs index 9c05dae979da..b27bbf4ff6c6 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_messages_rococo_to_westend.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_messages` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-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: @@ -50,90 +50,98 @@ pub struct WeightInfo(PhantomData); impl pallet_bridge_messages::WeightInfo for WeightInfo { /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `658` - // Estimated: `52645` - // Minimum execution time: 41_396_000 picoseconds. - Weight::from_parts(43_141_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `810` + // Estimated: `52674` + // Minimum execution time: 62_750_000 picoseconds. + Weight::from_parts(65_328_000, 0) + .saturating_add(Weight::from_parts(0, 52674)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 4076]`. /// The range of component `n` is `[1, 4076]`. fn receive_n_messages_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `658` - // Estimated: `52645` - // Minimum execution time: 41_095_000 picoseconds. - Weight::from_parts(42_030_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 5_702 - .saturating_add(Weight::from_parts(11_627_951, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `810` + // Estimated: `52674` + // Minimum execution time: 62_275_000 picoseconds. + Weight::from_parts(63_714_000, 0) + .saturating_add(Weight::from_parts(0, 52674)) + // Standard Error: 13_139 + .saturating_add(Weight::from_parts(14_630_892, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `658` - // Estimated: `52645` - // Minimum execution time: 45_912_000 picoseconds. - Weight::from_parts(47_564_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `810` + // Estimated: `52674` + // Minimum execution time: 68_950_000 picoseconds. + Weight::from_parts(71_420_000, 0) + .saturating_add(Weight::from_parts(0, 52674)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16384]`. /// The range of component `n` is `[1, 16384]`. fn receive_single_n_bytes_message_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `658` - // Estimated: `52645` - // Minimum execution time: 39_175_000 picoseconds. - Weight::from_parts(41_674_095, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 4 - .saturating_add(Weight::from_parts(2_305, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `810` + // Estimated: `52674` + // Minimum execution time: 60_477_000 picoseconds. + Weight::from_parts(64_935_758, 0) + .saturating_add(Weight::from_parts(0, 52674)) + // Standard Error: 8 + .saturating_add(Weight::from_parts(2_008, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) @@ -141,69 +149,89 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendMessages::OutboundMessages` (r:0 w:1) + /// Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `501` - // Estimated: `3966` - // Minimum execution time: 32_033_000 picoseconds. - Weight::from_parts(33_131_000, 0) - .saturating_add(Weight::from_parts(0, 3966)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `779` + // Estimated: `5383` + // Minimum execution time: 52_939_000 picoseconds. + Weight::from_parts(54_637_000, 0) + .saturating_add(Weight::from_parts(0, 5383)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendMessages::OutboundMessages` (r:0 w:2) + /// Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `501` - // Estimated: `3966` - // Minimum execution time: 32_153_000 picoseconds. - Weight::from_parts(33_126_000, 0) - .saturating_add(Weight::from_parts(0, 3966)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `779` + // Estimated: `5383` + // Minimum execution time: 54_645_000 picoseconds. + Weight::from_parts(57_391_000, 0) + .saturating_add(Weight::from_parts(0, 5383)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:2 w:2) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Storage: `BridgeWestendMessages::OutboundMessages` (r:0 w:2) + /// Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `501` - // Estimated: `6086` - // Minimum execution time: 36_387_000 picoseconds. - Weight::from_parts(37_396_000, 0) - .saturating_add(Weight::from_parts(0, 6086)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)) + // Measured: `779` + // Estimated: `6144` + // Minimum execution time: 59_581_000 picoseconds. + Weight::from_parts(61_657_000, 0) + .saturating_add(Weight::from_parts(0, 6144)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeWestendParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeWestendMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeWestendMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, 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: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) @@ -216,20 +244,22 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: Some(105506), added: 107981, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16384]`. /// The range of component `n` is `[1, 16384]`. fn receive_single_n_bytes_message_proof_with_dispatch(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `789` - // Estimated: `52645` - // Minimum execution time: 56_562_000 picoseconds. - Weight::from_parts(61_452_871, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 9 - .saturating_add(Weight::from_parts(7_587, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(10)) + // Measured: `1140` + // Estimated: `52674` + // Minimum execution time: 83_530_000 picoseconds. + Weight::from_parts(91_297_344, 0) + .saturating_add(Weight::from_parts(0, 52674)) + // Standard Error: 11 + .saturating_add(Weight::from_parts(7_197, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs index 8eb291ea1452..3629d8797bf7 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_parachains.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_parachains` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-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: @@ -65,11 +65,11 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `558` // Estimated: `2543` - // Minimum execution time: 34_889_000 picoseconds. - Weight::from_parts(36_100_759, 0) + // Minimum execution time: 41_810_000 picoseconds. + Weight::from_parts(42_952_442, 0) .saturating_add(Weight::from_parts(0, 2543)) - // Standard Error: 102_466 - .saturating_add(Weight::from_parts(178_820, 0).saturating_mul(p.into())) + // Standard Error: 108_155 + .saturating_add(Weight::from_parts(340_328, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -89,8 +89,8 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `558` // Estimated: `2543` - // Minimum execution time: 36_501_000 picoseconds. - Weight::from_parts(37_266_000, 0) + // Minimum execution time: 43_567_000 picoseconds. + Weight::from_parts(44_746_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) @@ -111,8 +111,8 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `558` // Estimated: `2543` - // Minimum execution time: 66_059_000 picoseconds. - Weight::from_parts(67_139_000, 0) + // Minimum execution time: 70_654_000 picoseconds. + Weight::from_parts(72_314_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs index f8bb983e80aa..b7318361c7d9 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_bridge_relayers.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_relayers` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-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: @@ -49,15 +49,15 @@ use core::marker::PhantomData; pub struct WeightInfo(PhantomData); impl pallet_bridge_relayers::WeightInfo for WeightInfo { /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn claim_rewards() -> Weight { // Proof Size summary in bytes: - // Measured: `278` + // Measured: `306` // Estimated: `3593` - // Minimum execution time: 44_224_000 picoseconds. - Weight::from_parts(44_905_000, 0) + // Minimum execution time: 53_924_000 picoseconds. + Weight::from_parts(54_736_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -72,8 +72,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `131` // Estimated: `4714` - // Minimum execution time: 23_902_000 picoseconds. - Weight::from_parts(24_702_000, 0) + // Minimum execution time: 28_608_000 picoseconds. + Weight::from_parts(29_081_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -86,8 +86,8 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `231` // Estimated: `4714` - // Minimum execution time: 24_469_000 picoseconds. - Weight::from_parts(25_176_000, 0) + // Minimum execution time: 29_738_000 picoseconds. + Weight::from_parts(30_242_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -102,21 +102,21 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< // Proof Size summary in bytes: // Measured: `334` // Estimated: `4714` - // Minimum execution time: 27_518_000 picoseconds. - Weight::from_parts(28_068_000, 0) + // Minimum execution time: 33_174_000 picoseconds. + Weight::from_parts(33_992_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) fn register_relayer_reward() -> Weight { // Proof Size summary in bytes: // Measured: `76` - // Estimated: `3538` - // Minimum execution time: 5_484_000 picoseconds. - Weight::from_parts(5_718_000, 0) - .saturating_add(Weight::from_parts(0, 3538)) + // Estimated: `3567` + // Minimum execution time: 7_950_000 picoseconds. + Weight::from_parts(8_123_000, 0) + .saturating_add(Weight::from_parts(0, 3567)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..71d17e7259f7 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_transaction_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/ +// --chain=bridge-hub-rococo-dev + +#![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_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn charge_transaction_payment() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3593` + // Minimum execution time: 34_956_000 picoseconds. + Weight::from_parts(40_788_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/paritydb_weights.rs index 25679703831a..e0b1985c659c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/paritydb_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/paritydb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/rocksdb_weights.rs index 3dd817aa6f13..c6e91b2fcffb 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/rocksdb_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/rocksdb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_system.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_system.rs index c6c188e323af..3831111f0977 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_system.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/snowbridge_pallet_system.rs @@ -253,4 +253,14 @@ impl snowbridge_pallet_system::WeightInfo for WeightInf .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } + + fn register_token() -> Weight { + // Proof Size summary in bytes: + // Measured: `256` + // Estimated: `6044` + // Minimum execution time: 45_000_000 picoseconds. + Weight::from_parts(45_000_000, 6044) + .saturating_add(T::DbWeight::get().reads(5_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } } 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 057dc4313510..f2cee0e3e807 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/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index 9c58072d402c..9a9137c18093 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-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: @@ -68,8 +68,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 60_119_000 picoseconds. - Weight::from_parts(61_871_000, 6196) + // Minimum execution time: 70_133_000 picoseconds. + Weight::from_parts(71_765_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -77,8 +77,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 998_000 picoseconds. - Weight::from_parts(1_038_000, 0) + // Minimum execution time: 959_000 picoseconds. + Weight::from_parts(996_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -86,58 +86,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 6_327_000 picoseconds. - Weight::from_parts(6_520_000, 3497) + // Minimum execution time: 7_537_000 picoseconds. + Weight::from_parts(7_876_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: 6_783_000 picoseconds. - Weight::from_parts(7_117_000, 0) + // Minimum execution time: 7_774_000 picoseconds. + Weight::from_parts(7_895_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_589_000 picoseconds. - Weight::from_parts(1_655_000, 0) + // Minimum execution time: 1_577_000 picoseconds. + Weight::from_parts(1_622_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_013_000 picoseconds. - Weight::from_parts(1_045_000, 0) + // Minimum execution time: 973_000 picoseconds. + Weight::from_parts(1_008_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_005_000 picoseconds. - Weight::from_parts(1_044_000, 0) + // Minimum execution time: 1_027_000 picoseconds. + Weight::from_parts(1_052_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 964_000 picoseconds. - Weight::from_parts(1_011_000, 0) + // Minimum execution time: 953_000 picoseconds. + Weight::from_parts(992_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_005_000 picoseconds. - Weight::from_parts(1_027_000, 0) + // Minimum execution time: 949_000 picoseconds. + Weight::from_parts(1_020_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 980_000 picoseconds. - Weight::from_parts(1_009_000, 0) + // Minimum execution time: 979_000 picoseconds. + Weight::from_parts(1_032_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -159,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 56_726_000 picoseconds. - Weight::from_parts(59_300_000, 6196) + // Minimum execution time: 66_663_000 picoseconds. + Weight::from_parts(67_728_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -170,8 +170,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 8_962_000 picoseconds. - Weight::from_parts(9_519_000, 3555) + // Minimum execution time: 11_074_000 picoseconds. + Weight::from_parts(11_439_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -179,8 +179,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 999_000 picoseconds. - Weight::from_parts(1_035_000, 0) + // Minimum execution time: 943_000 picoseconds. + Weight::from_parts(1_021_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -200,8 +200,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 20_313_000 picoseconds. - Weight::from_parts(21_000_000, 3503) + // Minimum execution time: 25_123_000 picoseconds. + Weight::from_parts(25_687_000, 3503) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -211,44 +211,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_820_000 picoseconds. - Weight::from_parts(2_949_000, 0) + // Minimum execution time: 2_868_000 picoseconds. + Weight::from_parts(3_124_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_293_000 picoseconds. - Weight::from_parts(1_354_000, 0) + // Minimum execution time: 1_378_000 picoseconds. + Weight::from_parts(1_458_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_076_000 picoseconds. - Weight::from_parts(1_114_000, 0) + // Minimum execution time: 1_036_000 picoseconds. + Weight::from_parts(1_105_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_014_000 picoseconds. - Weight::from_parts(1_055_000, 0) + // Minimum execution time: 945_000 picoseconds. + Weight::from_parts(1_021_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 979_000 picoseconds. - Weight::from_parts(1_019_000, 0) + // Minimum execution time: 931_000 picoseconds. + Weight::from_parts(1_006_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_161_000 picoseconds. - Weight::from_parts(1_208_000, 0) + // Minimum execution time: 1_139_000 picoseconds. + Weight::from_parts(1_206_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -270,8 +270,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 62_250_000 picoseconds. - Weight::from_parts(64_477_000, 6196) + // Minimum execution time: 72_884_000 picoseconds. + Weight::from_parts(74_331_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -279,8 +279,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_286_000 picoseconds. - Weight::from_parts(4_476_000, 0) + // Minimum execution time: 4_432_000 picoseconds. + Weight::from_parts(4_542_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -302,8 +302,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `171` // Estimated: `6196` - // Minimum execution time: 58_253_000 picoseconds. - Weight::from_parts(59_360_000, 6196) + // Minimum execution time: 67_102_000 picoseconds. + Weight::from_parts(68_630_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -311,44 +311,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_026_000 picoseconds. - Weight::from_parts(1_065_000, 0) + // Minimum execution time: 995_000 picoseconds. + Weight::from_parts(1_057_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 993_000 picoseconds. - Weight::from_parts(1_015_000, 0) + // Minimum execution time: 956_000 picoseconds. + Weight::from_parts(1_021_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 966_000 picoseconds. - Weight::from_parts(999_000, 0) + // Minimum execution time: 944_000 picoseconds. + Weight::from_parts(986_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:2 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `XcmOverBridgeHubWestend::Bridges` (r:1 w:0) + // Proof: `XcmOverBridgeHubWestend::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) // Storage: `BridgeWestendMessages::PalletOperatingMode` (r:1 w:0) // Proof: `BridgeWestendMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) // Storage: `BridgeWestendMessages::OutboundLanes` (r:1 w:1) - // Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) - // Storage: `BridgeWestendMessages::OutboundLanesCongestedSignals` (r:1 w:0) - // Proof: `BridgeWestendMessages::OutboundLanesCongestedSignals` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) + // Proof: `BridgeWestendMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) // Storage: `BridgeWestendMessages::OutboundMessages` (r:0 w:1) - // Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) + // Proof: `BridgeWestendMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) /// The range of component `x` is `[1, 1000]`. pub fn export_message(x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `190` - // Estimated: `6130` - // Minimum execution time: 37_014_000 picoseconds. - Weight::from_parts(38_096_655, 6130) - // Standard Error: 61 - .saturating_add(Weight::from_parts(45_146, 0).saturating_mul(x.into())) + // Measured: `589` + // Estimated: `6529` + // Minimum execution time: 58_111_000 picoseconds. + Weight::from_parts(59_123_071, 6529) + // Standard Error: 167 + .saturating_add(Weight::from_parts(43_658, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -356,14 +356,14 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 996_000 picoseconds. - Weight::from_parts(1_025_000, 0) + // Minimum execution time: 950_000 picoseconds. + Weight::from_parts(1_002_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_001_000 picoseconds. - Weight::from_parts(1_044_000, 0) + // Minimum execution time: 963_000 picoseconds. + Weight::from_parts(1_012_000, 0) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-rococo/src/xcm_config.rs index 5ec545ee0590..2fb186703a88 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 @@ -17,11 +17,9 @@ use super::{ AccountId, AllPalletsWithSystem, Balances, BaseDeliveryFee, FeeAssetId, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - TransactionByteFee, WeightToFee, XcmpQueue, + TransactionByteFee, WeightToFee, XcmOverBridgeHubWestend, XcmOverRococoBulletin, XcmpQueue, }; -use bp_messages::LaneId; -use bp_relayers::{PayRewardFromAccount, RewardsAccountOwner, RewardsAccountParams}; -use bp_runtime::ChainId; + use core::marker::PhantomData; use frame_support::{ parameter_types, @@ -40,22 +38,21 @@ use parachains_common::{ use polkadot_parachain_primitives::primitives::Sibling; use polkadot_runtime_common::xcm_sender::ExponentialPrice; use snowbridge_runtime_common::XcmExportFeeToSibling; -use sp_core::Get; use sp_runtime::traits::AccountIdConversion; use testnet_parachains_constants::rococo::snowbridge::EthereumNetwork; use xcm::latest::prelude::*; use xcm_builder::{ - deposit_or_burn_fee, AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, - 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, + AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, + AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, + DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, + EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, HandleFee, HashedDescription, + IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount, + SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, + UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, }; use xcm_executor::{ - traits::{FeeManager, FeeReason, FeeReason::Export, TransactAsset}, + traits::{FeeManager, FeeReason, FeeReason::Export}, XcmExecutor, }; @@ -82,6 +79,8 @@ pub type LocationToAccountId = ( SiblingParachainConvertsVia, // Straight up local `AccountId32` origins just alias directly to `AccountId`. AccountId32Aliases, + // Foreign locations alias into accounts according to a hash of their standard description. + HashedDescription>, ); /// Means for transacting the native currency on this chain. @@ -208,13 +207,6 @@ impl xcm_executor::Config for XcmConfig { type FeeManager = XcmFeeManagerFromComponentsBridgeHub< WaivedLocations, ( - XcmExportFeeToRelayerRewardAccounts< - Self::AssetTransactor, - crate::bridge_to_westend_config::WestendGlobalConsensusNetwork, - crate::bridge_to_westend_config::AssetHubWestendParaId, - crate::bridge_to_westend_config::BridgeHubWestendChainId, - crate::bridge_to_westend_config::AssetHubRococoToAssetHubWestendMessagesLane, - >, XcmExportFeeToSibling< bp_rococo::Balance, AccountId, @@ -223,12 +215,12 @@ impl xcm_executor::Config for XcmConfig { Self::AssetTransactor, crate::EthereumOutboundQueue, >, - XcmFeeToAccount, + SendXcmFeeToAccount, ), >; type MessageExporter = ( - crate::bridge_to_westend_config::ToBridgeHubWestendHaulBlobExporter, - crate::bridge_to_bulletin_config::ToRococoBulletinHaulBlobExporter, + XcmOverBridgeHubWestend, + XcmOverRococoBulletin, crate::bridge_to_ethereum_config::SnowbridgeExporter, ); type UniversalAliases = Nothing; @@ -295,95 +287,6 @@ impl cumulus_pallet_xcm::Config for Runtime { type XcmExecutor = XcmExecutor; } -/// A `HandleFee` implementation that simply deposits the fees for `ExportMessage` XCM instructions -/// into the accounts that are used for paying the relayer rewards. -/// Burns the fees in case of a failure. -pub struct XcmExportFeeToRelayerRewardAccounts< - AssetTransactor, - DestNetwork, - DestParaId, - DestBridgedChainId, - BridgeLaneId, ->(PhantomData<(AssetTransactor, DestNetwork, DestParaId, DestBridgedChainId, BridgeLaneId)>); - -impl< - AssetTransactor: TransactAsset, - DestNetwork: Get, - DestParaId: Get, - DestBridgedChainId: Get, - BridgeLaneId: Get, - > HandleFee - for XcmExportFeeToRelayerRewardAccounts< - AssetTransactor, - DestNetwork, - DestParaId, - DestBridgedChainId, - BridgeLaneId, - > -{ - fn handle_fee(fee: Assets, maybe_context: Option<&XcmContext>, reason: FeeReason) -> Assets { - if matches!(reason, FeeReason::Export { network: bridged_network, destination } - if bridged_network == DestNetwork::get() && - destination == [Parachain(DestParaId::get().into())]) - { - // 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 - // - the SA of the destination parachain on this BH: this pays the relayers for - // delivering Target para -> Source Para messages - // We split the `ExportMessage` fee between these 2 accounts. - let source_para_account = PayRewardFromAccount::< - pallet_balances::Pallet, - AccountId, - >::rewards_account(RewardsAccountParams::new( - BridgeLaneId::get(), - DestBridgedChainId::get(), - RewardsAccountOwner::ThisChain, - )); - - let dest_para_account = PayRewardFromAccount::< - pallet_balances::Pallet, - AccountId, - >::rewards_account(RewardsAccountParams::new( - BridgeLaneId::get(), - DestBridgedChainId::get(), - RewardsAccountOwner::BridgedChain, - )); - - for asset in fee.into_inner() { - match asset.fun { - Fungible(total_fee) => { - let source_fee = total_fee / 2; - deposit_or_burn_fee::( - Asset { id: asset.id.clone(), fun: Fungible(source_fee) }.into(), - maybe_context, - source_para_account.clone(), - ); - - let dest_fee = total_fee - source_fee; - deposit_or_burn_fee::( - Asset { id: asset.id, fun: Fungible(dest_fee) }.into(), - maybe_context, - dest_para_account.clone(), - ); - }, - NonFungible(_) => { - deposit_or_burn_fee::( - asset.into(), - maybe_context, - source_para_account.clone(), - ); - }, - } - } - - return Assets::new() - } - - fee - } -} - pub struct XcmFeeManagerFromComponentsBridgeHub( PhantomData<(WaivedLocations, HandleFee)>, ); @@ -393,7 +296,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 5960ab7b5505..8be2993c68f4 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 @@ -18,11 +18,10 @@ use bp_polkadot_core::Signature; use bridge_hub_rococo_runtime::{ - bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages, bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages, xcm_config::XcmConfig, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, MessageQueueServiceWeight, Runtime, RuntimeCall, RuntimeEvent, SessionKeys, - SignedExtra, UncheckedExtrinsic, + TxExtension, UncheckedExtrinsic, }; use codec::{Decode, Encode}; use cumulus_primitives_core::XcmError::{FailedToTransactAsset, NotHoldingFees}; @@ -171,7 +170,7 @@ fn construct_extrinsic( call: RuntimeCall, ) -> UncheckedExtrinsic { let account_id = AccountId32::from(sender.public()); - let extra: SignedExtra = ( + let tx_ext: TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -183,15 +182,13 @@ fn construct_extrinsic( frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), BridgeRejectObsoleteHeadersAndMessages::default(), - ( - OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), - OnBridgeHubRococoRefundRococoBulletinMessages::default(), - ), + (OnBridgeHubRococoRefundBridgeHubWestendMessages::default(),), + frame_metadata_hash_extension::CheckMetadataHash::::new(false), cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), ); - let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); + let payload = SignedPayload::new(call.clone(), tx_ext.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); - UncheckedExtrinsic::new_signed(call, account_id.into(), Signature::Sr25519(signature), extra) + UncheckedExtrinsic::new_signed(call, account_id.into(), Signature::Sr25519(signature), tx_ext) } fn construct_and_apply_extrinsic( 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 1d3d9e55f7ee..01674287fde1 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 @@ -20,9 +20,9 @@ use bp_polkadot_core::Signature; use bridge_hub_rococo_runtime::{ bridge_common_config, bridge_to_bulletin_config, bridge_to_westend_config, xcm_config::{RelayNetwork, TokenLocation, XcmConfig}, - AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, EthereumGatewayAddress, - Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, - RuntimeEvent, RuntimeOrigin, SessionKeys, SignedExtra, TransactionPayment, UncheckedExtrinsic, + AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, + ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, + TransactionPayment, TxExtension, UncheckedExtrinsic, }; use bridge_hub_test_utils::SlotDurations; use codec::{Decode, Encode}; @@ -30,7 +30,7 @@ use frame_support::{dispatch::GetDispatchInfo, parameter_types, traits::ConstU8} use parachains_common::{AccountId, AuraId, Balance}; use snowbridge_core::ChannelId; use sp_consensus_aura::SlotDuration; -use sp_core::H160; +use sp_core::{crypto::Ss58Codec, H160}; use sp_keyring::AccountKeyring::Alice; use sp_runtime::{ generic::{Era, SignedPayload}, @@ -38,6 +38,7 @@ use sp_runtime::{ }; use testnet_parachains_constants::rococo::{consensus::*, fee::WeightToFee}; use xcm::latest::prelude::*; +use xcm_runtime_apis::conversions::LocationToAccountHelper; parameter_types! { pub CheckingAccount: AccountId = PolkadotXcm::check_account(); @@ -48,7 +49,7 @@ fn construct_extrinsic( call: RuntimeCall, ) -> UncheckedExtrinsic { let account_id = AccountId32::from(sender.public()); - let extra: SignedExtra = ( + let tx_ext: TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -60,15 +61,14 @@ fn construct_extrinsic( frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), BridgeRejectObsoleteHeadersAndMessages::default(), - ( - bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(), - bridge_to_bulletin_config::OnBridgeHubRococoRefundRococoBulletinMessages::default(), - ), + (bridge_to_westend_config::OnBridgeHubRococoRefundBridgeHubWestendMessages::default(),), + frame_metadata_hash_extension::CheckMetadataHash::new(false), cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), - ); - let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); + ) + .into(); + let payload = SignedPayload::new(call.clone(), tx_ext.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); - UncheckedExtrinsic::new_signed(call, account_id.into(), Signature::Sr25519(signature), extra) + UncheckedExtrinsic::new_signed(call, account_id.into(), Signature::Sr25519(signature), tx_ext) } fn construct_and_apply_extrinsic( @@ -120,39 +120,34 @@ bridge_hub_test_utils::test_cases::include_teleports_for_native_asset_works!( bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID ); -#[test] -fn change_required_stake_by_governance_works() { - bridge_hub_test_utils::test_cases::change_storage_constant_by_governance_works::< - Runtime, - bridge_common_config::RequiredStakeForStakeAndSlash, - Balance, - >( - collator_session_keys(), - bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - Box::new(|call| RuntimeCall::System(call).encode()), - || { - ( - bridge_common_config::RequiredStakeForStakeAndSlash::key().to_vec(), - bridge_common_config::RequiredStakeForStakeAndSlash::get(), - ) - }, - |old_value| old_value.checked_mul(2).unwrap(), - ) -} - mod bridge_hub_westend_tests { use super::*; + use bp_messages::LegacyLaneId; use bridge_common_config::{ BridgeGrandpaWestendInstance, BridgeParachainWestendInstance, DeliveryRewardInBalance, + RelayersForLegacyLaneIdsMessagesInstance, + }; + use bridge_hub_rococo_runtime::{ + bridge_to_ethereum_config::EthereumGatewayAddress, xcm_config::LocationToAccountId, }; use bridge_hub_test_utils::test_cases::from_parachain; use bridge_to_westend_config::{ - BridgeHubWestendChainId, BridgeHubWestendLocation, WestendGlobalConsensusNetwork, - WithBridgeHubWestendMessagesInstance, XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, + BridgeHubWestendLocation, WestendGlobalConsensusNetwork, + WithBridgeHubWestendMessagesInstance, XcmOverBridgeHubWestendInstance, }; - // Para id of sibling chain used in tests. - pub const SIBLING_PARACHAIN_ID: u32 = 1000; + // Random para id of sibling chain used in tests. + pub const SIBLING_PARACHAIN_ID: u32 = 2053; + // Random para id of sibling chain used in tests. + pub const SIBLING_SYSTEM_PARACHAIN_ID: u32 = 1008; + // Random para id of bridged chain from different global consensus used in tests. + pub const BRIDGED_LOCATION_PARACHAIN_ID: u32 = 1075; + + parameter_types! { + pub SiblingParachainLocation: Location = Location::new(1, [Parachain(SIBLING_PARACHAIN_ID)]); + pub SiblingSystemParachainLocation: Location = Location::new(1, [Parachain(SIBLING_SYSTEM_PARACHAIN_ID)]); + pub BridgedUniversalLocation: InteriorLocation = [GlobalConsensus(WestendGlobalConsensusNetwork::get()), Parachain(BRIDGED_LOCATION_PARACHAIN_ID)].into(); + } // Runtime from tests PoV type RuntimeTestsAdapter = from_parachain::WithRemoteParachainHelperAdapter< @@ -161,6 +156,7 @@ mod bridge_hub_westend_tests { BridgeGrandpaWestendInstance, BridgeParachainWestendInstance, WithBridgeHubWestendMessagesInstance, + RelayersForLegacyLaneIdsMessagesInstance, >; #[test] @@ -312,12 +308,30 @@ mod bridge_hub_westend_tests { _ => None, } }), - || 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, + || ExportMessage { network: WestendGlobalConsensusNetwork::get(), destination: [Parachain(BRIDGED_LOCATION_PARACHAIN_ID)].into(), xcm: Xcm(vec![]) }, 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!"); + + // we need to create lane between sibling parachain and remote destination + bridge_hub_test_utils::ensure_opened_bridge::< + Runtime, + XcmOverBridgeHubWestendInstance, + LocationToAccountId, + TokenLocation, + >( + SiblingParachainLocation::get(), + BridgedUniversalLocation::get(), + |locations, fee| { + bridge_hub_test_utils::open_bridge_with_storage::< + Runtime, + XcmOverBridgeHubWestendInstance + >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + } + ).1 + }, ) } @@ -350,7 +364,6 @@ mod bridge_hub_westend_tests { _ => None, } }), - XCM_LANE_FOR_ASSET_HUB_ROCOCO_TO_ASSET_HUB_WESTEND, || (), ) } @@ -363,12 +376,29 @@ 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, - || (), + || { + // we need to create lane between sibling parachain and remote destination + bridge_hub_test_utils::ensure_opened_bridge::< + Runtime, + XcmOverBridgeHubWestendInstance, + LocationToAccountId, + TokenLocation, + >( + SiblingParachainLocation::get(), + BridgedUniversalLocation::get(), + |locations, fee| { + bridge_hub_test_utils::open_bridge_with_storage::< + Runtime, + XcmOverBridgeHubWestendInstance, + >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + }, + ) + .1 + }, construct_and_apply_extrinsic, + true, ) } @@ -380,12 +410,29 @@ 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, - || (), + || { + // we need to create lane between sibling parachain and remote destination + bridge_hub_test_utils::ensure_opened_bridge::< + Runtime, + XcmOverBridgeHubWestendInstance, + LocationToAccountId, + TokenLocation, + >( + SiblingParachainLocation::get(), + BridgedUniversalLocation::get(), + |locations, fee| { + bridge_hub_test_utils::open_bridge_with_storage::< + Runtime, + XcmOverBridgeHubWestendInstance, + >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + }, + ) + .1 + }, construct_and_apply_extrinsic, + false, ) } @@ -401,8 +448,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 +467,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 +486,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() @@ -451,16 +498,26 @@ mod bridge_hub_westend_tests { mod bridge_hub_bulletin_tests { use super::*; + use bp_messages::{HashedLaneId, LaneIdType}; use bridge_common_config::BridgeGrandpaRococoBulletinInstance; + use bridge_hub_rococo_runtime::{ + bridge_common_config::RelayersForPermissionlessLanesInstance, + xcm_config::LocationToAccountId, + }; 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, XcmOverPolkadotBulletinInstance, }; - // Para id of sibling chain used in tests. - pub const SIBLING_PARACHAIN_ID: u32 = rococo_runtime_constants::system_parachain::PEOPLE_ID; + // Random para id of sibling chain used in tests. + pub const SIBLING_PEOPLE_PARACHAIN_ID: u32 = + rococo_runtime_constants::system_parachain::PEOPLE_ID; + + parameter_types! { + pub SiblingPeopleParachainLocation: Location = Location::new(1, [Parachain(SIBLING_PEOPLE_PARACHAIN_ID)]); + pub BridgedBulletinLocation: InteriorLocation = [GlobalConsensus(RococoBulletinGlobalConsensusNetwork::get())].into(); + } // Runtime from tests PoV type RuntimeTestsAdapter = from_grandpa_chain::WithRemoteGrandpaChainHelperAdapter< @@ -468,6 +525,7 @@ mod bridge_hub_bulletin_tests { AllPalletsWithoutSystem, BridgeGrandpaRococoBulletinInstance, WithRococoBulletinMessagesInstance, + RelayersForPermissionlessLanesInstance, >; #[test] @@ -507,7 +565,7 @@ mod bridge_hub_bulletin_tests { >( collator_session_keys(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - SIBLING_PARACHAIN_ID, + SIBLING_PEOPLE_PARACHAIN_ID, Box::new(|runtime_event_encoded: Vec| { match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { Ok(RuntimeEvent::BridgePolkadotBulletinMessages(event)) => Some(event), @@ -519,10 +577,28 @@ 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!"); + + // we need to create lane between RococoPeople and RococoBulletin + bridge_hub_test_utils::ensure_opened_bridge::< + Runtime, + XcmOverPolkadotBulletinInstance, + LocationToAccountId, + TokenLocation, + >( + SiblingPeopleParachainLocation::get(), + BridgedBulletinLocation::get(), + |locations, fee| { + bridge_hub_test_utils::open_bridge_with_storage::< + Runtime, + XcmOverPolkadotBulletinInstance + >(locations, fee, HashedLaneId::try_new(1, 2).unwrap()) + } + ).1 + }, ) } @@ -542,7 +618,7 @@ mod bridge_hub_bulletin_tests { collator_session_keys(), slot_durations(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - SIBLING_PARACHAIN_ID, + SIBLING_PEOPLE_PARACHAIN_ID, Box::new(|runtime_event_encoded: Vec| { match RuntimeEvent::decode(&mut &runtime_event_encoded[..]) { Ok(RuntimeEvent::ParachainSystem(event)) => Some(event), @@ -555,7 +631,6 @@ mod bridge_hub_bulletin_tests { _ => None, } }), - XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, || (), ) } @@ -567,12 +642,29 @@ mod bridge_hub_bulletin_tests { collator_session_keys(), slot_durations(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - RococoBulletinChainId::get(), - SIBLING_PARACHAIN_ID, + SIBLING_PEOPLE_PARACHAIN_ID, Rococo, - XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, - || (), + || { + // we need to create lane between RococoPeople and RococoBulletin + bridge_hub_test_utils::ensure_opened_bridge::< + Runtime, + XcmOverPolkadotBulletinInstance, + LocationToAccountId, + TokenLocation, + >( + SiblingPeopleParachainLocation::get(), + BridgedBulletinLocation::get(), + |locations, fee| { + bridge_hub_test_utils::open_bridge_with_storage::< + Runtime, + XcmOverPolkadotBulletinInstance, + >(locations, fee, HashedLaneId::try_new(1, 2).unwrap()) + }, + ) + .1 + }, construct_and_apply_extrinsic, + false, ) } @@ -583,12 +675,160 @@ mod bridge_hub_bulletin_tests { collator_session_keys(), slot_durations(), bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, - RococoBulletinChainId::get(), - SIBLING_PARACHAIN_ID, + SIBLING_PEOPLE_PARACHAIN_ID, Rococo, - XCM_LANE_FOR_ROCOCO_PEOPLE_TO_ROCOCO_BULLETIN, - || (), + || { + // we need to create lane between RococoPeople and RococoBulletin + bridge_hub_test_utils::ensure_opened_bridge::< + Runtime, + XcmOverPolkadotBulletinInstance, + LocationToAccountId, + TokenLocation, + >( + SiblingPeopleParachainLocation::get(), + BridgedBulletinLocation::get(), + |locations, fee| { + bridge_hub_test_utils::open_bridge_with_storage::< + Runtime, + XcmOverPolkadotBulletinInstance, + >(locations, fee, HashedLaneId::try_new(1, 2).unwrap()) + }, + ) + .1 + }, construct_and_apply_extrinsic, + false, ) } } + +#[test] +fn change_required_stake_by_governance_works() { + bridge_hub_test_utils::test_cases::change_storage_constant_by_governance_works::< + Runtime, + bridge_common_config::RequiredStakeForStakeAndSlash, + Balance, + >( + collator_session_keys(), + bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, + Box::new(|call| RuntimeCall::System(call).encode()), + || { + ( + bridge_common_config::RequiredStakeForStakeAndSlash::key().to_vec(), + bridge_common_config::RequiredStakeForStakeAndSlash::get(), + ) + }, + |old_value| old_value.checked_mul(2).unwrap(), + ) +} + +#[test] +fn location_conversion_works() { + // the purpose of hardcoded values is to catch an unintended location conversion logic + // change. + struct TestCase { + description: &'static str, + location: Location, + expected_account_id_str: &'static str, + } + + let test_cases = vec![ + // DescribeTerminus + TestCase { + description: "DescribeTerminus Parent", + location: Location::new(1, Here), + expected_account_id_str: "5Dt6dpkWPwLaH4BBCKJwjiWrFVAGyYk3tLUabvyn4v7KtESG", + }, + TestCase { + description: "DescribeTerminus Sibling", + location: Location::new(1, [Parachain(1111)]), + expected_account_id_str: "5Eg2fnssmmJnF3z1iZ1NouAuzciDaaDQH7qURAy3w15jULDk", + }, + // DescribePalletTerminal + TestCase { + description: "DescribePalletTerminal Parent", + location: Location::new(1, [PalletInstance(50)]), + expected_account_id_str: "5CnwemvaAXkWFVwibiCvf2EjqwiqBi29S5cLLydZLEaEw6jZ", + }, + TestCase { + description: "DescribePalletTerminal Sibling", + location: Location::new(1, [Parachain(1111), PalletInstance(50)]), + expected_account_id_str: "5GFBgPjpEQPdaxEnFirUoa51u5erVx84twYxJVuBRAT2UP2g", + }, + // DescribeAccountId32Terminal + TestCase { + description: "DescribeAccountId32Terminal Parent", + location: Location::new( + 1, + [Junction::AccountId32 { network: None, id: AccountId::from(Alice).into() }], + ), + expected_account_id_str: "5EueAXd4h8u75nSbFdDJbC29cmi4Uo1YJssqEL9idvindxFL", + }, + TestCase { + description: "DescribeAccountId32Terminal Sibling", + location: Location::new( + 1, + [ + Parachain(1111), + Junction::AccountId32 { network: None, id: AccountId::from(Alice).into() }, + ], + ), + expected_account_id_str: "5Dmbuiq48fU4iW58FKYqoGbbfxFHjbAeGLMtjFg6NNCw3ssr", + }, + // DescribeAccountKey20Terminal + TestCase { + description: "DescribeAccountKey20Terminal Parent", + location: Location::new(1, [AccountKey20 { network: None, key: [0u8; 20] }]), + expected_account_id_str: "5F5Ec11567pa919wJkX6VHtv2ZXS5W698YCW35EdEbrg14cg", + }, + TestCase { + description: "DescribeAccountKey20Terminal Sibling", + location: Location::new( + 1, + [Parachain(1111), AccountKey20 { network: None, key: [0u8; 20] }], + ), + expected_account_id_str: "5CB2FbUds2qvcJNhDiTbRZwiS3trAy6ydFGMSVutmYijpPAg", + }, + // DescribeTreasuryVoiceTerminal + TestCase { + description: "DescribeTreasuryVoiceTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]), + expected_account_id_str: "5CUjnE2vgcUCuhxPwFoQ5r7p1DkhujgvMNDHaF2bLqRp4D5F", + }, + TestCase { + description: "DescribeTreasuryVoiceTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Treasury, part: BodyPart::Voice }], + ), + expected_account_id_str: "5G6TDwaVgbWmhqRUKjBhRRnH4ry9L9cjRymUEmiRsLbSE4gB", + }, + // DescribeBodyTerminal + TestCase { + description: "DescribeBodyTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Unit, part: BodyPart::Voice }]), + expected_account_id_str: "5EBRMTBkDisEXsaN283SRbzx9Xf2PXwUxxFCJohSGo4jYe6B", + }, + TestCase { + description: "DescribeBodyTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Unit, part: BodyPart::Voice }], + ), + expected_account_id_str: "5DBoExvojy8tYnHgLL97phNH975CyT45PWTZEeGoBZfAyRMH", + }, + ]; + + for tc in test_cases { + let expected = + AccountId::from_string(tc.expected_account_id_str).expect("Invalid AccountId string"); + + let got = LocationToAccountHelper::< + AccountId, + bridge_hub_rococo_runtime::xcm_config::LocationToAccountId, + >::convert_location(tc.location.into()) + .unwrap(); + + assert_eq!(got, expected, "{}", tc.description); + } +} 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 e2671d3d606d..637e7c710640 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bridge-hub-westend-runtime" -version = "0.2.0" +version = "0.3.0" authors.workspace = true edition.workspace = true description = "Westend's BridgeHub parachain runtime" @@ -18,10 +18,12 @@ hex-literal = { workspace = true, default-features = true } log = { workspace = true } scale-info = { features = ["derive"], workspace = true } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } +serde_json = { features = ["alloc"], workspace = true } # 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 } @@ -41,6 +43,7 @@ sp-api = { workspace = true } sp-block-builder = { workspace = true } sp-consensus-aura = { workspace = true } sp-core = { workspace = true } +sp-keyring = { workspace = true } sp-genesis-builder = { workspace = true } sp-inherents = { workspace = true } sp-io = { workspace = true } @@ -89,7 +92,7 @@ bp-messages = { workspace = true } bp-parachains = { workspace = true } bp-polkadot-core = { workspace = true } bp-relayers = { workspace = true } -bp-runtime = { features = ["test-helpers"], workspace = true } +bp-runtime = { workspace = true } bp-rococo = { workspace = true } bp-westend = { workspace = true } pallet-bridge-grandpa = { workspace = true } @@ -100,11 +103,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 } +pallet-bridge-relayers = { features = ["integrity-test"], workspace = true } +snowbridge-runtime-test-common = { workspace = true, default-features = true } [features] default = ["std"] @@ -135,6 +151,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 +182,17 @@ std = [ "polkadot-runtime-common/std", "scale-info/std", "serde", + "serde_json/std", + "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", @@ -172,6 +200,7 @@ std = [ "sp-genesis-builder/std", "sp-inherents/std", "sp-io/std", + "sp-keyring/std", "sp-offchain/std", "sp-runtime/std", "sp-session/std", @@ -209,6 +238,7 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm-bridge-hub/runtime-benchmarks", @@ -216,6 +246,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,10 +287,16 @@ 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", ] # A feature that should be enabled when the runtime should be built for on-chain # deployment. This will disable stuff that shouldn't be part of the on-chain wasm # to make it smaller, like logging for example. -on-chain-release-build = ["sp-api/disable-logging"] +on-chain-release-build = [] + +fast-runtime = [] diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_common_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_common_config.rs index 9bae106395a6..0872d0498f85 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_common_config.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_common_config.rs @@ -22,6 +22,7 @@ //! GRANDPA tracking pallet only needs to be aware of one chain. use super::{weights, AccountId, Balance, Balances, BlockNumber, Runtime, RuntimeEvent}; +use bp_messages::LegacyLaneId; use frame_support::parameter_types; parameter_types! { @@ -33,11 +34,15 @@ parameter_types! { } /// Allows collect and claim rewards for relayers -impl pallet_bridge_relayers::Config for Runtime { +pub type RelayersForLegacyLaneIdsMessagesInstance = (); +impl pallet_bridge_relayers::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Reward = Balance; - type PaymentProcedure = - bp_relayers::PayRewardFromAccount, AccountId>; + type PaymentProcedure = bp_relayers::PayRewardFromAccount< + pallet_balances::Pallet, + AccountId, + Self::LaneId, + >; type StakeAndSlash = pallet_bridge_relayers::StakeAndSlashNamed< AccountId, BlockNumber, @@ -47,4 +52,5 @@ impl pallet_bridge_relayers::Config for Runtime { RelayerStakeLease, >; type WeightInfo = weights::pallet_bridge_relayers::WeightInfo; + type LaneId = LegacyLaneId; } 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 000000000000..dbca4166a135 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/bridge_to_ethereum_config.rs @@ -0,0 +1,231 @@ +// 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::{EthereumLocation, EthereumNetwork, INBOUND_QUEUE_PALLET_INDEX}, +}; + +use crate::xcm_config::RelayNetwork; +#[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, +}; +use xcm::prelude::{GlobalConsensus, InteriorLocation, Location, Parachain}; + +pub const SLOTS_PER_EPOCH: u32 = snowbridge_pallet_ethereum_client::config::SLOTS_PER_EPOCH as u32; + +/// Exports message to the Ethereum Gateway contract. +pub type SnowbridgeExporter = EthereumBlobExporter< + UniversalLocation, + EthereumNetwork, + snowbridge_pallet_outbound_queue::Pallet, + snowbridge_core::AgentIdOf, + EthereumSystem, +>; + +// 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), + }; + pub AssetHubFromEthereum: Location = Location::new(1,[GlobalConsensus(RelayNetwork::get()),Parachain(westend_runtime_constants::system_parachain::ASSET_HUB_ID)]); + pub EthereumUniversalLocation: InteriorLocation = [GlobalConsensus(EthereumNetwork::get())].into(); +} +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, + EthereumSystem, + EthereumUniversalLocation, + AssetHubFromEthereum, + >; + 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 FreeHeadersInterval = ConstU32; + 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; + type UniversalLocation = UniversalLocation; + type EthereumLocation = EthereumLocation; +} + +#[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 42d5ef3eebdb..aca51b320e9b 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 @@ -17,35 +17,37 @@ //! Bridge definitions used on BridgeHub with the Westend flavor. use crate::{ - bridge_common_config::DeliveryRewardInBalance, weights, xcm_config::UniversalLocation, - BridgeRococoMessages, PolkadotXcm, Runtime, RuntimeEvent, XcmOverBridgeHubRococo, XcmRouter, + bridge_common_config::{DeliveryRewardInBalance, RelayersForLegacyLaneIdsMessagesInstance}, + weights, + xcm_config::UniversalLocation, + AccountId, Balance, Balances, BridgeRococoMessages, PolkadotXcm, Runtime, RuntimeEvent, + RuntimeHoldReason, XcmOverBridgeHubRococo, XcmRouter, }; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, LaneId, + target_chain::FromBridgedChainMessagesProof, LegacyLaneId, }; use bp_parachains::SingleParaStoredHeaderDataBuilder; -use bp_runtime::Chain; -use bridge_runtime_common::{ - extensions::refund_relayer_extension::{ - ActualFeeRefund, RefundBridgedMessages, RefundSignedExtensionAdapter, - RefundableMessagesLane, - }, - messages_xcm_extension::{ - SenderAndLane, XcmAsPlainPayload, XcmBlobHauler, XcmBlobHaulerAdapter, - XcmBlobMessageDispatch, XcmVersionOfDestAndRemoteBridge, - }, -}; -use codec::Encode; +use bridge_hub_common::xcm_version::XcmVersionOfDestAndRemoteBridge; +use pallet_xcm_bridge_hub::XcmAsPlainPayload; + use frame_support::{ parameter_types, traits::{ConstU32, PalletInfoAccess}, }; +use frame_system::{EnsureNever, EnsureRoot}; +use pallet_bridge_messages::LaneIdOf; +use pallet_bridge_relayers::extension::{ + BridgeRelayersTransactionExtension, WithMessagesExtensionConfig, +}; +use parachains_common::xcm_config::{AllSiblingSystemParachains, RelayOrOtherSystemParachains}; +use polkadot_parachain_primitives::primitives::Sibling; +use testnet_parachains_constants::westend::currency::UNITS as WND; use xcm::{ latest::prelude::*, prelude::{InteriorLocation, NetworkId}, }; -use xcm_builder::BridgeBlobDispatcher; +use xcm_builder::{BridgeBlobDispatcher, ParentIsPreset, SiblingParachainConvertsVia}; parameter_types! { pub const RelayChainHeadersToKeep: u32 = 1024; @@ -54,7 +56,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( @@ -68,26 +69,6 @@ parameter_types! { // see the `FEE_BOOST_PER_MESSAGE` constant to get the meaning of this value pub PriorityBoostPerMessage: u64 = 182_044_444_444_444; - pub AssetHubWestendParaId: cumulus_primitives_core::ParaId = bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID.into(); - pub AssetHubRococoParaId: cumulus_primitives_core::ParaId = bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID.into(); - - // Lanes - pub ActiveOutboundLanesToBridgeHubRococo: &'static [bp_messages::LaneId] = &[XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO]; - pub const AssetHubWestendToAssetHubRococoMessagesLane: bp_messages::LaneId = XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO; - pub FromAssetHubWestendToAssetHubRococoRoute: SenderAndLane = SenderAndLane::new( - ParentThen([Parachain(AssetHubWestendParaId::get().into())].into()).into(), - XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, - ); - pub ActiveLanes: alloc::vec::Vec<(SenderAndLane, (NetworkId, InteriorLocation))> = alloc::vec![ - ( - FromAssetHubWestendToAssetHubRococoRoute::get(), - (RococoGlobalConsensusNetwork::get(), [Parachain(AssetHubRococoParaId::get().into())].into()) - ) - ]; - - pub CongestedMessage: Xcm<()> = build_congestion_message(true).into(); - pub UncongestedMessage: Xcm<()> = build_congestion_message(false).into(); - pub BridgeHubRococoLocation: Location = Location::new( 2, [ @@ -95,67 +76,33 @@ parameter_types! { Parachain(::PARACHAIN_ID) ] ); -} -pub const XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO: LaneId = LaneId([0, 0, 0, 2]); - -fn build_congestion_message(is_congested: bool) -> alloc::vec::Vec> { - alloc::vec![ - UnpaidExecution { weight_limit: Unlimited, check_origin: None }, - Transact { - origin_kind: OriginKind::Xcm, - require_weight_at_most: - bp_asset_hub_westend::XcmBridgeHubRouterTransactCallMaxWeight::get(), - call: bp_asset_hub_westend::Call::ToRococoXcmRouter( - bp_asset_hub_westend::XcmBridgeHubRouterCall::report_bridge_status { - bridge_id: Default::default(), - is_congested, - } - ) - .encode() - .into(), - } - ] + + pub storage BridgeDeposit: Balance = 10 * WND; } /// Proof of messages, coming from Rococo. -pub type FromRococoBridgeHubMessagesProof = - FromBridgedChainMessagesProof; +pub type FromRococoBridgeHubMessagesProof = + FromBridgedChainMessagesProof>; /// Messages delivery proof for Rococo Bridge Hub -> Westend Bridge Hub messages. -pub type ToRococoBridgeHubMessagesDeliveryProof = - FromBridgedChainMessagesDeliveryProof; +pub type ToRococoBridgeHubMessagesDeliveryProof = + FromBridgedChainMessagesDeliveryProof>; /// Dispatches received XCM messages from other bridge type FromRococoMessageBlobDispatcher = BridgeBlobDispatcher; -/// Export XCM messages to be relayed to the other side -pub type ToBridgeHubRococoHaulBlobExporter = XcmOverBridgeHubRococo; - -pub struct ToBridgeHubRococoXcmBlobHauler; -impl XcmBlobHauler for ToBridgeHubRococoXcmBlobHauler { - type Runtime = Runtime; - type MessagesInstance = WithBridgeHubRococoMessagesInstance; - - type ToSourceChainSender = XcmRouter; - type CongestedMessage = CongestedMessage; - type UncongestedMessage = UncongestedMessage; -} - -/// On messages delivered callback. -type OnMessagesDelivered = XcmBlobHaulerAdapter; - -/// Signed extension that refunds relayers that are delivering messages from the Rococo parachain. -pub type OnBridgeHubWestendRefundBridgeHubRococoMessages = RefundSignedExtensionAdapter< - RefundBridgedMessages< +/// Transaction extension that refunds relayers that are delivering messages from the Rococo +/// parachain. +pub type OnBridgeHubWestendRefundBridgeHubRococoMessages = BridgeRelayersTransactionExtension< + Runtime, + WithMessagesExtensionConfig< + StrOnBridgeHubWestendRefundBridgeHubRococoMessages, Runtime, - RefundableMessagesLane< - WithBridgeHubRococoMessagesInstance, - AssetHubWestendToAssetHubRococoMessagesLane, - >, - ActualFeeRefund, + WithBridgeHubRococoMessagesInstance, + RelayersForLegacyLaneIdsMessagesInstance, PriorityBoostPerMessage, - StrOnBridgeHubWestendRefundBridgeHubRococoMessages, >, + LaneIdOf, >; bp_runtime::generate_static_str_provider!(OnBridgeHubWestendRefundBridgeHubRococoMessages); @@ -197,40 +144,97 @@ impl pallet_bridge_messages::Config for Run bp_bridge_hub_rococo::BridgeHubRococo, >; - type ActiveOutboundLanes = ActiveOutboundLanesToBridgeHubRococo; - type OutboundPayload = XcmAsPlainPayload; - type InboundPayload = XcmAsPlainPayload; - type DeliveryPayments = (); + type LaneId = LegacyLaneId; + type DeliveryPayments = (); type DeliveryConfirmationPayments = pallet_bridge_relayers::DeliveryConfirmationPaymentsAdapter< Runtime, WithBridgeHubRococoMessagesInstance, DeliveryRewardInBalance, >; - type MessageDispatch = XcmBlobMessageDispatch< - FromRococoMessageBlobDispatcher, - Self::WeightInfo, - cumulus_pallet_xcmp_queue::bridging::OutXcmpChannelStatusProvider< - AssetHubWestendParaId, - Runtime, - >, - >; - type OnMessagesDelivered = OnMessagesDelivered; + type MessageDispatch = XcmOverBridgeHubRococo; + type OnMessagesDelivered = XcmOverBridgeHubRococo; } /// Add support for the export and dispatch of XCM programs. pub type XcmOverBridgeHubRococoInstance = pallet_xcm_bridge_hub::Instance1; impl pallet_xcm_bridge_hub::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type UniversalLocation = UniversalLocation; type BridgedNetwork = RococoGlobalConsensusNetworkLocation; type BridgeMessagesPalletInstance = WithBridgeHubRococoMessagesInstance; + type MessageExportPrice = (); type DestinationVersion = XcmVersionOfDestAndRemoteBridge; - type Lanes = ActiveLanes; - type LanesSupport = ToBridgeHubRococoXcmBlobHauler; + + type ForceOrigin = EnsureRoot; + // We don't want to allow creating bridges for this instance with `LegacyLaneId`. + type OpenBridgeOrigin = EnsureNever; + // Converter aligned with `OpenBridgeOrigin`. + type BridgeOriginAccountIdConverter = + (ParentIsPreset, SiblingParachainConvertsVia); + + type BridgeDeposit = BridgeDeposit; + type Currency = Balances; + type RuntimeHoldReason = RuntimeHoldReason; + // Do not require deposit from system parachains or relay chain + type AllowWithoutBridgeDeposit = + RelayOrOtherSystemParachains; + + // TODO:(bridges-v2) - add `LocalXcmChannelManager` impl - https://github.com/paritytech/parity-bridges-common/issues/3047 + type LocalXcmChannelManager = (); + type BlobDispatcher = FromRococoMessageBlobDispatcher; +} + +#[cfg(feature = "runtime-benchmarks")] +pub(crate) fn open_bridge_for_benchmarks( + with: pallet_xcm_bridge_hub::LaneIdOf, + sibling_para_id: u32, +) -> InteriorLocation +where + R: pallet_xcm_bridge_hub::Config, + XBHI: 'static, + C: xcm_executor::traits::ConvertLocation< + bp_runtime::AccountIdOf>, + >, +{ + use pallet_xcm_bridge_hub::{Bridge, BridgeId, BridgeState}; + use sp_runtime::traits::Zero; + use xcm::VersionedInteriorLocation; + + // insert bridge metadata + let lane_id = with; + let sibling_parachain = Location::new(1, [Parachain(sibling_para_id)]); + let universal_source = [GlobalConsensus(Westend), Parachain(sibling_para_id)].into(); + let universal_destination = [GlobalConsensus(Rococo), Parachain(2075)].into(); + let bridge_id = BridgeId::new(&universal_source, &universal_destination); + + // insert only bridge metadata, because the benchmarks create lanes + pallet_xcm_bridge_hub::Bridges::::insert( + bridge_id, + Bridge { + bridge_origin_relative_location: alloc::boxed::Box::new( + sibling_parachain.clone().into(), + ), + bridge_origin_universal_location: alloc::boxed::Box::new( + VersionedInteriorLocation::from(universal_source.clone()), + ), + bridge_destination_universal_location: alloc::boxed::Box::new( + VersionedInteriorLocation::from(universal_destination), + ), + state: BridgeState::Opened, + bridge_owner_account: C::convert_location(&sibling_parachain).expect("valid AccountId"), + deposit: Zero::zero(), + lane_id, + }, + ); + pallet_xcm_bridge_hub::LaneToBridge::::insert(lane_id, bridge_id); + + universal_source } #[cfg(test)] @@ -238,14 +242,11 @@ mod tests { use super::*; use bridge_runtime_common::{ assert_complete_bridge_types, - extensions::refund_relayer_extension::RefundableParachain, integrity::{ assert_complete_with_parachain_bridge_constants, check_message_lane_weights, AssertChainConstants, AssertCompleteBridgeConstants, }, }; - use parachains_common::Balance; - use testnet_parachains_constants::westend; /// Every additional message in the message delivery transaction boosts its priority. /// So the priority of transaction with `N+1` messages is larger than priority of @@ -256,12 +257,12 @@ mod tests { /// /// We want this tip to be large enough (delivery transactions with more messages = less /// operational costs and a faster bridge), so this value should be significant. - const FEE_BOOST_PER_MESSAGE: Balance = 2 * westend::currency::UNITS; + const FEE_BOOST_PER_MESSAGE: Balance = 2 * WND; // see `FEE_BOOST_PER_MESSAGE` comment - const FEE_BOOST_PER_RELAY_HEADER: Balance = 2 * westend::currency::UNITS; + const FEE_BOOST_PER_RELAY_HEADER: Balance = 2 * WND; // see `FEE_BOOST_PER_MESSAGE` comment - const FEE_BOOST_PER_PARACHAIN_HEADER: Balance = 2 * westend::currency::UNITS; + const FEE_BOOST_PER_PARACHAIN_HEADER: Balance = 2 * WND; #[test] fn ensure_bridge_hub_westend_message_lane_weights_are_correct() { @@ -299,19 +300,20 @@ mod tests { }, }); - bridge_runtime_common::extensions::priority_calculator::per_relay_header::ensure_priority_boost_is_sane::< + pallet_bridge_relayers::extension::per_relay_header::ensure_priority_boost_is_sane::< Runtime, BridgeGrandpaRococoInstance, PriorityBoostPerRelayHeader, >(FEE_BOOST_PER_RELAY_HEADER); - bridge_runtime_common::extensions::priority_calculator::per_parachain_header::ensure_priority_boost_is_sane::< + pallet_bridge_relayers::extension::per_parachain_header::ensure_priority_boost_is_sane::< Runtime, - RefundableParachain, + WithBridgeHubRococoMessagesInstance, + bp_bridge_hub_rococo::BridgeHubRococo, PriorityBoostPerParachainHeader, >(FEE_BOOST_PER_PARACHAIN_HEADER); - bridge_runtime_common::extensions::priority_calculator::per_message::ensure_priority_boost_is_sane::< + pallet_bridge_relayers::extension::per_message::ensure_priority_boost_is_sane::< Runtime, WithBridgeHubRococoMessagesInstance, PriorityBoostPerMessage, @@ -325,3 +327,99 @@ mod tests { ); } } + +/// Contains the migration for the AssetHubWestend<>AssetHubRococo bridge. +pub mod migration { + use super::*; + use bp_messages::LegacyLaneId; + use frame_support::traits::ConstBool; + + parameter_types! { + pub AssetHubWestendToAssetHubRococoMessagesLane: LegacyLaneId = LegacyLaneId([0, 0, 0, 2]); + pub AssetHubWestendLocation: Location = Location::new(1, [Parachain(bp_asset_hub_westend::ASSET_HUB_WESTEND_PARACHAIN_ID)]); + pub AssetHubRococoUniversalLocation: InteriorLocation = [GlobalConsensus(RococoGlobalConsensusNetwork::get()), Parachain(bp_asset_hub_rococo::ASSET_HUB_ROCOCO_PARACHAIN_ID)].into(); + } + + /// Ensure that the existing lanes for the AHW<>AHR bridge are correctly configured. + pub type StaticToDynamicLanes = pallet_xcm_bridge_hub::migration::OpenBridgeForLane< + Runtime, + XcmOverBridgeHubRococoInstance, + AssetHubWestendToAssetHubRococoMessagesLane, + // the lanes are already created for AHR<>AHW, but we need to link them to the bridge + // structs + ConstBool, + AssetHubWestendLocation, + AssetHubRococoUniversalLocation, + >; + + mod v1_wrong { + use bp_messages::{LaneState, MessageNonce, UnrewardedRelayer}; + use bp_runtime::AccountIdOf; + use codec::{Decode, Encode}; + use pallet_bridge_messages::BridgedChainOf; + use sp_std::collections::vec_deque::VecDeque; + + #[derive(Encode, Decode, Clone, PartialEq, Eq)] + pub(crate) struct StoredInboundLaneData, I: 'static>( + pub(crate) InboundLaneData>>, + ); + #[derive(Encode, Decode, Clone, PartialEq, Eq)] + pub(crate) struct InboundLaneData { + pub state: LaneState, + pub(crate) relayers: VecDeque>, + pub(crate) last_confirmed_nonce: MessageNonce, + } + #[derive(Encode, Decode, Clone, PartialEq, Eq)] + pub(crate) struct OutboundLaneData { + pub state: LaneState, + pub(crate) oldest_unpruned_nonce: MessageNonce, + pub(crate) latest_received_nonce: MessageNonce, + pub(crate) latest_generated_nonce: MessageNonce, + } + } + + mod v1 { + pub use bp_messages::{InboundLaneData, LaneState, OutboundLaneData}; + pub use pallet_bridge_messages::{InboundLanes, OutboundLanes, StoredInboundLaneData}; + } + + /// Fix for v1 migration - corrects data for OutboundLaneData/InboundLaneData (it is needed only + /// for Rococo/Westend). + pub struct FixMessagesV1Migration(sp_std::marker::PhantomData<(T, I)>); + + impl, I: 'static> frame_support::traits::OnRuntimeUpgrade + for FixMessagesV1Migration + { + fn on_runtime_upgrade() -> Weight { + use sp_core::Get; + let mut weight = T::DbWeight::get().reads(1); + + // `InboundLanes` - add state to the old structs + let translate_inbound = + |pre: v1_wrong::StoredInboundLaneData| -> Option> { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + Some(v1::StoredInboundLaneData(v1::InboundLaneData { + state: v1::LaneState::Opened, + relayers: pre.0.relayers, + last_confirmed_nonce: pre.0.last_confirmed_nonce, + })) + }; + v1::InboundLanes::::translate_values(translate_inbound); + + // `OutboundLanes` - add state to the old structs + let translate_outbound = + |pre: v1_wrong::OutboundLaneData| -> Option { + weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); + Some(v1::OutboundLaneData { + state: v1::LaneState::Opened, + oldest_unpruned_nonce: pre.oldest_unpruned_nonce, + latest_received_nonce: pre.latest_received_nonce, + latest_generated_nonce: pre.latest_generated_nonce, + }) + }; + v1::OutboundLanes::::translate_values(translate_outbound); + + weight + } + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/genesis_config_presets.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/genesis_config_presets.rs new file mode 100644 index 000000000000..2949ae01fdcc --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/genesis_config_presets.rs @@ -0,0 +1,136 @@ +// 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. + +//! # Bridge Hub Westend Runtime genesis config presets + +use crate::*; +use alloc::{vec, vec::Vec}; +use cumulus_primitives_core::ParaId; +use parachains_common::{AccountId, AuraId}; +use sp_genesis_builder::PresetId; +use sp_keyring::Sr25519Keyring; +use testnet_parachains_constants::westend::xcm_version::SAFE_XCM_VERSION; + +const BRIDGE_HUB_WESTEND_ED: Balance = ExistentialDeposit::get(); + +fn bridge_hub_westend_genesis( + invulnerables: Vec<(AccountId, AuraId)>, + endowed_accounts: Vec, + id: ParaId, + bridges_pallet_owner: Option, + asset_hub_para_id: ParaId, + opened_bridges: Vec<(Location, InteriorLocation, Option)>, +) -> serde_json::Value { + let config = RuntimeGenesisConfig { + balances: BalancesConfig { + balances: endowed_accounts + .iter() + .cloned() + .map(|k| (k, 1u128 << 60)) + .collect::>(), + }, + parachain_info: ParachainInfoConfig { parachain_id: id, ..Default::default() }, + collator_selection: CollatorSelectionConfig { + invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: BRIDGE_HUB_WESTEND_ED * 16, + ..Default::default() + }, + session: SessionConfig { + keys: invulnerables + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + SessionKeys { aura }, // session keys + ) + }) + .collect(), + ..Default::default() + }, + polkadot_xcm: PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + bridge_rococo_grandpa: BridgeRococoGrandpaConfig { + owner: bridges_pallet_owner.clone(), + ..Default::default() + }, + bridge_rococo_messages: BridgeRococoMessagesConfig { + owner: bridges_pallet_owner.clone(), + ..Default::default() + }, + xcm_over_bridge_hub_rococo: XcmOverBridgeHubRococoConfig { + opened_bridges, + ..Default::default() + }, + ethereum_system: EthereumSystemConfig { + para_id: id, + asset_hub_para_id, + ..Default::default() + }, + ..Default::default() + }; + + serde_json::to_value(config).expect("Could not build genesis config.") +} + +/// Provides the JSON representation of predefined genesis config for given `id`. +pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option> { + let patch = match id.try_into() { + Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) => bridge_hub_westend_genesis( + // initial collators. + vec![ + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), + ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), + 1002.into(), + Some(Sr25519Keyring::Bob.to_account_id()), + westend_runtime_constants::system_parachain::ASSET_HUB_ID.into(), + vec![( + Location::new(1, [Parachain(1000)]), + Junctions::from([Rococo.into(), Parachain(1000)]), + Some(bp_messages::LegacyLaneId([0, 0, 0, 2])), + )], + ), + Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => bridge_hub_westend_genesis( + // initial collators. + vec![ + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), + ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), + 1002.into(), + Some(Sr25519Keyring::Bob.to_account_id()), + westend_runtime_constants::system_parachain::ASSET_HUB_ID.into(), + vec![], + ), + _ => return None, + }; + Some( + serde_json::to_string(&patch) + .expect("serialization to json is expected to work. qed.") + .into_bytes(), + ) +} + +/// List of supported presets. +pub fn preset_names() -> Vec { + vec![ + PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET), + PresetId::from(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET), + ] +} 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 5d4c35d6610a..1d7cd5de40eb 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,7 +28,9 @@ 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 genesis_config_presets; mod weights; pub mod xcm_config; @@ -36,13 +38,10 @@ extern crate alloc; use alloc::{vec, vec::Vec}; use bridge_runtime_common::extensions::{ - check_obsolete_extension::{ - CheckAndBoostBridgeGrandpaTransactions, CheckAndBoostBridgeParachainsTransactions, - }, - refund_relayer_extension::RefundableParachain, + CheckAndBoostBridgeGrandpaTransactions, CheckAndBoostBridgeParachainsTransactions, }; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; -use cumulus_primitives_core::ParaId; +use cumulus_primitives_core::{ClaimQueueOffset, CoreSelector, ParaId}; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ @@ -83,7 +82,7 @@ use xcm_runtime_apis::{ }; use bp_runtime::HeaderId; - +use pallet_bridge_messages::LaneIdOf; #[cfg(any(feature = "std", test))] pub use sp_runtime::BuildStorage; @@ -96,7 +95,14 @@ 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; + +use westend_runtime_constants::system_parachain::{ASSET_HUB_ID, BRIDGE_HUB_ID}; /// The address format for describing accounts. pub type Address = MultiAddress; @@ -110,8 +116,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The TransactionExtension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -122,12 +128,13 @@ pub type SignedExtra = ( pallet_transaction_payment::ChargeTransactionPayment, BridgeRejectObsoleteHeadersAndMessages, (bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages,), + frame_metadata_hash_extension::CheckMetadataHash, cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim, ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -137,10 +144,35 @@ pub type Migrations = ( // unreleased cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, + pallet_bridge_messages::migration::v1::MigrationToV1< + Runtime, + bridge_to_rococo_config::WithBridgeHubRococoMessagesInstance, + >, + bridge_to_rococo_config::migration::FixMessagesV1Migration< + Runtime, + bridge_to_rococo_config::WithBridgeHubRococoMessagesInstance, + >, + bridge_to_rococo_config::migration::StaticToDynamicLanes, + frame_support::migrations::RemoveStorage< + BridgeRococoMessagesPalletName, + OutboundLanesCongestedSignalsKey, + RocksDbWeight, + >, + pallet_bridge_relayers::migration::v1::MigrationToV1, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, + snowbridge_pallet_system::migration::v0::InitializeOnUpgrade< + Runtime, + ConstU32, + ConstU32, + >, ); +parameter_types! { + pub const BridgeRococoMessagesPalletName: &'static str = "BridgeRococoMessages"; + pub const OutboundLanesCongestedSignalsKey: &'static str = "OutboundLanesCongestedSignals"; +} + /// Migration to initialize storage versions for pallets added after genesis. /// /// Ideally this would be done automatically (see @@ -191,11 +223,11 @@ 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_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, - transaction_version: 5, - state_version: 1, + transaction_version: 6, + system_version: 1, }; /// The version information used to identify this runtime when compiled natively. @@ -251,6 +283,8 @@ impl frame_system::Config for Runtime { type DbWeight = RocksDbWeight; /// Weight information for the extrinsics of this pallet. type SystemWeightInfo = weights::frame_system::WeightInfo; + /// Weight information for the transaction extensions of this pallet. + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; /// Block & extrinsics weights: base values and limits. type BlockWeights = RuntimeBlockWeights; /// The maximum length of a block (in bytes). @@ -295,6 +329,7 @@ impl pallet_balances::Config for Runtime { type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxFreezes = ConstU32<0>; + type DoneSlashHandler = (); } parameter_types! { @@ -310,6 +345,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -329,6 +365,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type ReservedXcmpWeight = ReservedXcmpWeight; type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; type ConsensusHook = ConsensusHook; + type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector; } type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< @@ -351,10 +388,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 +556,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, @@ -534,10 +579,8 @@ bridge_runtime_common::generate_bridge_reject_obsolete_headers_and_messages! { // Parachains CheckAndBoostBridgeParachainsTransactions< Runtime, - RefundableParachain< - bridge_to_rococo_config::BridgeParachainRococoInstance, - bp_bridge_hub_rococo::BridgeHubRococo, - >, + bridge_to_rococo_config::BridgeParachainRococoInstance, + bp_bridge_hub_rococo::BridgeHubRococo, bridge_to_rococo_config::PriorityBoostPerParachainHeader, xcm_config::TreasuryAccount, >, @@ -549,12 +592,14 @@ bridge_runtime_common::generate_bridge_reject_obsolete_headers_and_messages! { mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] + [pallet_transaction_payment, TransactionPayment] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] @@ -568,6 +613,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] ); } @@ -778,6 +828,12 @@ impl_runtime_apis! { } } + impl cumulus_primitives_core::GetCoreSelectorApi for Runtime { + fn core_selector() -> (CoreSelector, ClaimQueueOffset) { + ParachainSystem::core_selector() + } + } + impl bp_rococo::RococoFinalityApi for Runtime { fn best_finalized() -> Option> { BridgeRococoGrandpa::best_finalized() @@ -807,7 +863,7 @@ impl_runtime_apis! { impl bp_bridge_hub_rococo::FromBridgeHubRococoInboundLaneApi for Runtime { fn message_details( - lane: bp_messages::LaneId, + lane: LaneIdOf, messages: Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>, ) -> Vec { bridge_runtime_common::messages_api::inbound_message_details::< @@ -819,7 +875,7 @@ impl_runtime_apis! { impl bp_bridge_hub_rococo::ToBridgeHubRococoOutboundLaneApi for Runtime { fn message_details( - lane: bp_messages::LaneId, + lane: LaneIdOf, begin: bp_messages::MessageNonce, end: bp_messages::MessageNonce, ) -> Vec { @@ -830,6 +886,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) { @@ -858,6 +930,7 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; @@ -887,6 +960,7 @@ impl_runtime_apis! { use sp_storage::TrackedStorageKey; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -1065,11 +1139,46 @@ impl_runtime_apis! { ); BenchmarkError::Stop("XcmVersion was not stored!") })?; + + let sibling_parachain_location = Location::new(1, [Parachain(5678)]); + + // fund SA + use frame_support::traits::fungible::Mutate; + use xcm_executor::traits::ConvertLocation; + frame_support::assert_ok!( + Balances::mint_into( + &xcm_config::LocationToAccountId::convert_location(&sibling_parachain_location).expect("valid AccountId"), + bridge_to_rococo_config::BridgeDeposit::get() + .saturating_add(ExistentialDeposit::get()) + .saturating_add(UNITS * 5) + ) + ); + + // open bridge + let bridge_destination_universal_location: InteriorLocation = [GlobalConsensus(NetworkId::Rococo), Parachain(8765)].into(); + let locations = XcmOverBridgeHubRococo::bridge_locations( + sibling_parachain_location.clone(), + bridge_destination_universal_location.clone(), + )?; + XcmOverBridgeHubRococo::do_open_bridge( + locations, + bp_messages::LegacyLaneId([1, 2, 3, 4]), + true, + ).map_err(|e| { + log::error!( + "Failed to `XcmOverBridgeHubRococo::open_bridge`({:?}, {:?})`, error: {:?}", + sibling_parachain_location, + bridge_destination_universal_location, + e + ); + BenchmarkError::Stop("Bridge was not opened!") + })?; + Ok( ( - bridge_to_rococo_config::FromAssetHubWestendToAssetHubRococoRoute::get().location, + sibling_parachain_location, NetworkId::Rococo, - [Parachain(bridge_to_rococo_config::AssetHubRococoParaId::get().into())].into() + [Parachain(8765)].into() ) ) } @@ -1100,7 +1209,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( @@ -1112,21 +1222,31 @@ impl_runtime_apis! { } fn prepare_message_proof( - params: MessageProofParams, - ) -> (bridge_to_rococo_config::FromRococoBridgeHubMessagesProof, Weight) { + params: MessageProofParams>, + ) -> (bridge_to_rococo_config::FromRococoBridgeHubMessagesProof, Weight) { use cumulus_primitives_core::XcmpMessageSource; assert!(XcmpQueue::take_outbound_messages(usize::MAX).is_empty()); ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(42.into()); + let universal_source = bridge_to_rococo_config::open_bridge_for_benchmarks::< + Runtime, + bridge_to_rococo_config::XcmOverBridgeHubRococoInstance, + xcm_config::LocationToAccountId, + >(params.lane, 42); prepare_message_proof_from_parachain::< Runtime, bridge_to_rococo_config::BridgeGrandpaRococoInstance, bridge_to_rococo_config::WithBridgeHubRococoMessagesInstance, - >(params, generate_xcm_builder_bridge_message_sample([GlobalConsensus(Westend), Parachain(42)].into())) + >(params, generate_xcm_builder_bridge_message_sample(universal_source)) } fn prepare_message_delivery_proof( - params: MessageDeliveryProofParams, - ) -> bridge_to_rococo_config::ToRococoBridgeHubMessagesDeliveryProof { + params: MessageDeliveryProofParams>, + ) -> bridge_to_rococo_config::ToRococoBridgeHubMessagesDeliveryProof { + let _ = bridge_to_rococo_config::open_bridge_for_benchmarks::< + Runtime, + bridge_to_rococo_config::XcmOverBridgeHubRococoInstance, + xcm_config::LocationToAccountId, + >(params.lane, 42); prepare_message_delivery_proof_from_parachain::< Runtime, bridge_to_rococo_config::BridgeGrandpaRococoInstance, @@ -1158,8 +1278,8 @@ impl_runtime_apis! { parachain_head_size: u32, proof_params: bp_runtime::UnverifiedStorageProofParams, ) -> ( - pallet_bridge_parachains::RelayBlockNumber, - pallet_bridge_parachains::RelayBlockHash, + bp_parachains::RelayBlockNumber, + bp_parachains::RelayBlockHash, bp_polkadot_core::parachains::ParaHeadsProof, Vec<(bp_polkadot_core::parachains::ParaId, bp_polkadot_core::parachains::ParaHash)>, ) { @@ -1171,14 +1291,15 @@ impl_runtime_apis! { } } - impl BridgeRelayersConfig for Runtime { + impl BridgeRelayersConfig for Runtime { fn prepare_rewards_account( - account_params: bp_relayers::RewardsAccountParams, + account_params: bp_relayers::RewardsAccountParams<>::LaneId>, reward: Balance, ) { let rewards_account = bp_relayers::PayRewardFromAccount::< Balances, - AccountId + AccountId, + >::LaneId, >::rewards_account(account_params); Self::deposit_account(rewards_account, reward); } @@ -1216,11 +1337,20 @@ impl_runtime_apis! { } fn get_preset(id: &Option) -> Option> { - get_preset::(id, |_| None) + get_preset::(id, &genesis_config_presets::get_preset) } fn preset_names() -> Vec { - vec![] + genesis_config_presets::preset_names() + } + } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) } } } @@ -1236,47 +1366,48 @@ mod tests { use codec::Encode; use sp_runtime::{ generic::Era, - traits::{SignedExtension, Zero}, + traits::{TransactionExtension, Zero}, }; #[test] - fn ensure_signed_extension_definition_is_compatible_with_relay() { - use bp_polkadot_core::SuffixedCommonSignedExtensionExt; + fn ensure_transaction_extension_definition_is_compatible_with_relay() { + use bp_polkadot_core::SuffixedCommonTransactionExtensionExt; 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: TxExtension = ( + 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(), + ), + frame_metadata_hash_extension::CheckMetadataHash::new(false), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), + ); + + { + let bh_indirect_payload = bp_bridge_hub_westend::TransactionExtension::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!( + TxExtension::implicit(&payload).unwrap().encode().split_last().unwrap().1, + sp_runtime::traits::TransactionExtension::::implicit(&bh_indirect_payload).unwrap().encode() + ) + } + }); } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/block_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/block_weights.rs index e7fdb2aae2a0..41e30725e753 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/block_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/extrinsic_weights.rs index 1a4adb968bb7..3bd48f061bba 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/extrinsic_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..459b137d3b84 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/ +// --chain=bridge-hub-westend-dev + +#![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 `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_genesis() -> Weight { + // Proof Size summary in bytes: + // Measured: `54` + // Estimated: `3509` + // Minimum execution time: 3_166_000 picoseconds. + Weight::from_parts(6_021_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_mortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_651_000 picoseconds. + Weight::from_parts(9_177_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_immortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_651_000 picoseconds. + Weight::from_parts(9_177_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 601_000 picoseconds. + Weight::from_parts(2_805_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_727_000 picoseconds. + Weight::from_parts(6_051_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 471_000 picoseconds. + Weight::from_parts(2_494_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 521_000 picoseconds. + Weight::from_parts(2_655_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1533` + // Minimum execution time: 3_808_000 picoseconds. + Weight::from_parts(6_402_000, 0) + .saturating_add(Weight::from_parts(0, 1533)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} 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 245daaf8ed91..c1c5c337aca8 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 @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 @@ -27,6 +27,7 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_balances; pub mod pallet_bridge_grandpa; pub mod pallet_bridge_messages; @@ -37,12 +38,18 @@ pub mod pallet_message_queue; pub mod pallet_multisig; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; 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/pallet_bridge_grandpa.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_grandpa.rs index fa7efc260489..74bf144ac712 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_grandpa.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_grandpa.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_grandpa` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-yaoqqom-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-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -64,17 +64,15 @@ impl pallet_bridge_grandpa::WeightInfo for WeightInfo Weight { + fn submit_finality_proof(p: u32, _v: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `268 + p * (60 ±0)` // Estimated: `51735` - // Minimum execution time: 294_381_000 picoseconds. - Weight::from_parts(21_868_057, 0) + // Minimum execution time: 361_133_000 picoseconds. + Weight::from_parts(406_081_000, 0) .saturating_add(Weight::from_parts(0, 51735)) - // Standard Error: 14_649 - .saturating_add(Weight::from_parts(40_681_012, 0).saturating_mul(p.into())) - // Standard Error: 48_883 - .saturating_add(Weight::from_parts(2_466_672, 0).saturating_mul(v.into())) + // Standard Error: 26_551 + .saturating_add(Weight::from_parts(40_356_046, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) } @@ -92,8 +90,8 @@ impl pallet_bridge_grandpa::WeightInfo for WeightInfo(PhantomData); impl pallet_bridge_messages::WeightInfo for WeightInfo { /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof() -> Weight { // Proof Size summary in bytes: - // Measured: `522` - // Estimated: `52645` - // Minimum execution time: 40_748_000 picoseconds. - Weight::from_parts(41_836_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `701` + // Estimated: `52674` + // Minimum execution time: 62_015_000 picoseconds. + Weight::from_parts(63_891_000, 0) + .saturating_add(Weight::from_parts(0, 52674)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 4076]`. fn receive_n_messages_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `522` - // Estimated: `52645` - // Minimum execution time: 40_923_000 picoseconds. - Weight::from_parts(41_287_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 9_774 - .saturating_add(Weight::from_parts(11_469_207, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `701` + // Estimated: `52674` + // Minimum execution time: 62_034_000 picoseconds. + Weight::from_parts(63_355_000, 0) + .saturating_add(Weight::from_parts(0, 52674)) + // Standard Error: 8_231 + .saturating_add(Weight::from_parts(14_096_117, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn receive_single_message_proof_with_outbound_lane_state() -> Weight { // Proof Size summary in bytes: - // Measured: `522` - // Estimated: `52645` - // Minimum execution time: 45_946_000 picoseconds. - Weight::from_parts(47_547_000, 0) - .saturating_add(Weight::from_parts(0, 52645)) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `701` + // Estimated: `52674` + // Minimum execution time: 65_063_000 picoseconds. + Weight::from_parts(67_125_000, 0) + .saturating_add(Weight::from_parts(0, 52674)) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:0) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) /// Storage: `ParachainInfo::ParachainId` (r:1 w:0) /// Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16384]`. fn receive_single_n_bytes_message_proof(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `522` - // Estimated: `52645` - // Minimum execution time: 39_668_000 picoseconds. - Weight::from_parts(41_908_980, 0) - .saturating_add(Weight::from_parts(0, 52645)) - // Standard Error: 11 - .saturating_add(Weight::from_parts(2_209, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(5)) + // Measured: `701` + // Estimated: `52674` + // Minimum execution time: 58_688_000 picoseconds. + Weight::from_parts(61_404_716, 0) + .saturating_add(Weight::from_parts(0, 52674)) + // Standard Error: 7 + .saturating_add(Weight::from_parts(2_249, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) @@ -139,69 +147,89 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::OutboundMessages` (r:0 w:1) + /// Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_single_message() -> Weight { // Proof Size summary in bytes: - // Measured: `357` - // Estimated: `3822` - // Minimum execution time: 30_544_000 picoseconds. - Weight::from_parts(31_171_000, 0) - .saturating_add(Weight::from_parts(0, 3822)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `710` + // Estimated: `5383` + // Minimum execution time: 53_123_000 picoseconds. + Weight::from_parts(54_417_000, 0) + .saturating_add(Weight::from_parts(0, 5383)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::OutboundMessages` (r:0 w:2) + /// Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_single_relayer() -> Weight { // Proof Size summary in bytes: - // Measured: `357` - // Estimated: `3822` - // Minimum execution time: 30_593_000 picoseconds. - Weight::from_parts(31_261_000, 0) - .saturating_add(Weight::from_parts(0, 3822)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `710` + // Estimated: `5383` + // Minimum execution time: 55_140_000 picoseconds. + Weight::from_parts(56_456_000, 0) + .saturating_add(Weight::from_parts(0, 5383)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) /// Storage: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Proof: UNKNOWN KEY `0x6e0a18b62a1de81c5f519181cc611e18` (r:1 w:0) /// Storage: `BridgeRelayers::RelayerRewards` (r:2 w:2) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) + /// Storage: `BridgeRococoMessages::OutboundMessages` (r:0 w:2) + /// Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) fn receive_delivery_proof_for_two_messages_by_two_relayers() -> Weight { // Proof Size summary in bytes: - // Measured: `357` - // Estimated: `6086` - // Minimum execution time: 34_682_000 picoseconds. - Weight::from_parts(35_277_000, 0) - .saturating_add(Weight::from_parts(0, 6086)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)) + // Measured: `710` + // Estimated: `6144` + // Minimum execution time: 60_415_000 picoseconds. + Weight::from_parts(62_057_000, 0) + .saturating_add(Weight::from_parts(0, 6144)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) /// Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) - /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) - /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:1 w:0) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// Storage: `BridgeRococoMessages::InboundLanes` (r:1 w:1) - /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49180), added: 51655, mode: `MaxEncodedLen`) + /// Proof: `BridgeRococoMessages::InboundLanes` (`max_values`: None, `max_size`: Some(49209), added: 51684, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::LaneToBridge` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::LaneToBridge` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) + /// Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, 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: `XcmpQueue::DeliveryFeeFactor` (r:1 w:0) @@ -214,19 +242,21 @@ impl pallet_bridge_messages::WeightInfo for WeightInfo< /// Proof: `PolkadotXcm::SafeXcmVersion` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `XcmpQueue::OutboundXcmpStatus` (r:1 w:1) + /// Proof: `XcmpQueue::OutboundXcmpStatus` (`max_values`: Some(1), `max_size`: Some(1282), added: 1777, mode: `MaxEncodedLen`) /// Storage: `XcmpQueue::OutboundXcmpMessages` (r:0 w:1) /// Proof: `XcmpQueue::OutboundXcmpMessages` (`max_values`: None, `max_size`: Some(105506), added: 107981, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 16384]`. fn receive_single_n_bytes_message_proof_with_dispatch(n: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `653` - // Estimated: `52645` - // Minimum execution time: 56_465_000 picoseconds. - Weight::from_parts(61_575_775, 0) - .saturating_add(Weight::from_parts(0, 52645)) + // Measured: `965` + // Estimated: `52674` + // Minimum execution time: 84_340_000 picoseconds. + Weight::from_parts(89_615_003, 0) + .saturating_add(Weight::from_parts(0, 52674)) // Standard Error: 15 - .saturating_add(Weight::from_parts(7_197, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(Weight::from_parts(7_574, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(12)) .saturating_add(T::DbWeight::get().writes(4)) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs index b4748f141705..87c5057cf9b8 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_parachains.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_parachains` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-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-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -61,13 +61,15 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf /// Storage: `BridgeRococoParachains::ImportedParaHeads` (r:0 w:1) /// Proof: `BridgeRococoParachains::ImportedParaHeads` (`max_values`: Some(64), `max_size`: Some(196), added: 1186, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 2]`. - fn submit_parachain_heads_with_n_parachains(_p: u32, ) -> Weight { + fn submit_parachain_heads_with_n_parachains(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `315` // Estimated: `2543` - // Minimum execution time: 34_177_000 picoseconds. - Weight::from_parts(35_662_308, 0) + // Minimum execution time: 39_518_000 picoseconds. + Weight::from_parts(40_461_018, 0) .saturating_add(Weight::from_parts(0, 2543)) + // Standard Error: 98_154 + .saturating_add(Weight::from_parts(479_640, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -87,8 +89,8 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `315` // Estimated: `2543` - // Minimum execution time: 35_975_000 picoseconds. - Weight::from_parts(36_510_000, 0) + // Minimum execution time: 41_243_000 picoseconds. + Weight::from_parts(42_293_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) @@ -109,8 +111,8 @@ impl pallet_bridge_parachains::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `315` // Estimated: `2543` - // Minimum execution time: 62_837_000 picoseconds. - Weight::from_parts(63_562_000, 0) + // Minimum execution time: 70_926_000 picoseconds. + Weight::from_parts(71_681_000, 0) .saturating_add(Weight::from_parts(0, 2543)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs index 60d81dc3082a..74be73df1403 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_bridge_relayers.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_bridge_relayers` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-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-westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -49,15 +49,15 @@ use core::marker::PhantomData; pub struct WeightInfo(PhantomData); impl pallet_bridge_relayers::WeightInfo for WeightInfo { /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn claim_rewards() -> Weight { // Proof Size summary in bytes: - // Measured: `207` + // Measured: `272` // Estimated: `3593` - // Minimum execution time: 43_132_000 picoseconds. - Weight::from_parts(43_923_000, 0) + // Minimum execution time: 52_499_000 picoseconds. + Weight::from_parts(53_659_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -70,10 +70,10 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< /// Proof: `Balances::Reserves` (`max_values`: None, `max_size`: Some(1249), added: 3724, mode: `MaxEncodedLen`) fn register() -> Weight { // Proof Size summary in bytes: - // Measured: `61` + // Measured: `97` // Estimated: `4714` - // Minimum execution time: 22_765_000 picoseconds. - Weight::from_parts(23_576_000, 0) + // Minimum execution time: 28_706_000 picoseconds. + Weight::from_parts(29_434_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -84,10 +84,10 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< /// Proof: `Balances::Reserves` (`max_values`: None, `max_size`: Some(1249), added: 3724, mode: `MaxEncodedLen`) fn deregister() -> Weight { // Proof Size summary in bytes: - // Measured: `160` + // Measured: `197` // Estimated: `4714` - // Minimum execution time: 24_013_000 picoseconds. - Weight::from_parts(24_460_000, 0) + // Minimum execution time: 29_563_000 picoseconds. + Weight::from_parts(30_222_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -100,23 +100,23 @@ impl pallet_bridge_relayers::WeightInfo for WeightInfo< /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn slash_and_deregister() -> Weight { // Proof Size summary in bytes: - // Measured: `263` + // Measured: `300` // Estimated: `4714` - // Minimum execution time: 26_946_000 picoseconds. - Weight::from_parts(27_485_000, 0) + // Minimum execution time: 32_618_000 picoseconds. + Weight::from_parts(33_528_000, 0) .saturating_add(Weight::from_parts(0, 4714)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `BridgeRelayers::RelayerRewards` (r:1 w:1) - /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `BridgeRelayers::RelayerRewards` (`max_values`: None, `max_size`: Some(102), added: 2577, mode: `MaxEncodedLen`) fn register_relayer_reward() -> Weight { // Proof Size summary in bytes: - // Measured: `6` - // Estimated: `3538` - // Minimum execution time: 4_658_000 picoseconds. - Weight::from_parts(4_902_000, 0) - .saturating_add(Weight::from_parts(0, 3538)) + // Measured: `42` + // Estimated: `3567` + // Minimum execution time: 7_521_000 picoseconds. + Weight::from_parts(7_844_000, 0) + .saturating_add(Weight::from_parts(0, 3567)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..92c53b918792 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("bridge-hub-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_transaction_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/ +// --chain=bridge-hub-westend-dev + +#![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_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn charge_transaction_payment() -> Weight { + // Proof Size summary in bytes: + // Measured: `3` + // Estimated: `3593` + // Minimum execution time: 40_286_000 picoseconds. + Weight::from_parts(45_816_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/paritydb_weights.rs index 25679703831a..e0b1985c659c 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/paritydb_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/paritydb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/rocksdb_weights.rs index 3dd817aa6f13..c6e91b2fcffb 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/rocksdb_weights.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/rocksdb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 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 000000000000..23e2a9cffb0b --- /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 000000000000..153c1d363be1 --- /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 000000000000..8adcef076e00 --- /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 000000000000..3831111f0977 --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/snowbridge_pallet_system.rs @@ -0,0 +1,266 @@ +// 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)) + } + + fn register_token() -> Weight { + // Proof Size summary in bytes: + // Measured: `256` + // Estimated: `6044` + // Minimum execution time: 45_000_000 picoseconds. + Weight::from_parts(45_000_000, 6044) + .saturating_add(T::DbWeight::get().reads(5_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 4310b2456475..5bd1d1680aa1 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/weights/xcm/pallet_xcm_benchmarks_generic.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs index ba434ff29629..16c483a21817 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/weights/xcm/pallet_xcm_benchmarks_generic.rs @@ -17,9 +17,9 @@ //! Autogenerated weights for `pallet_xcm_benchmarks::generic` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-07-03, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-08-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-7wrmsoux-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-westend-dev"), DB CACHE: 1024 // Executed Command: @@ -68,8 +68,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 58_505_000 picoseconds. - Weight::from_parts(60_437_000, 6196) + // Minimum execution time: 70_715_000 picoseconds. + Weight::from_parts(72_211_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -77,8 +77,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 510_000 picoseconds. - Weight::from_parts(569_000, 0) + // Minimum execution time: 968_000 picoseconds. + Weight::from_parts(1_022_000, 0) } // Storage: `PolkadotXcm::Queries` (r:1 w:0) // Proof: `PolkadotXcm::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -86,58 +86,58 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `32` // Estimated: `3497` - // Minimum execution time: 5_597_000 picoseconds. - Weight::from_parts(5_884_000, 3497) + // Minimum execution time: 7_718_000 picoseconds. + Weight::from_parts(7_894_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: 5_320_000 picoseconds. - Weight::from_parts(5_594_000, 0) + // Minimum execution time: 7_662_000 picoseconds. + Weight::from_parts(7_937_000, 0) } pub fn refund_surplus() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_164_000 picoseconds. - Weight::from_parts(1_227_000, 0) + // Minimum execution time: 1_699_000 picoseconds. + Weight::from_parts(1_783_000, 0) } pub fn set_error_handler() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 528_000 picoseconds. - Weight::from_parts(586_000, 0) + // Minimum execution time: 977_000 picoseconds. + Weight::from_parts(1_045_000, 0) } pub fn set_appendix() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 509_000 picoseconds. - Weight::from_parts(571_000, 0) + // Minimum execution time: 971_000 picoseconds. + Weight::from_parts(1_030_000, 0) } pub fn clear_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 511_000 picoseconds. - Weight::from_parts(546_000, 0) + // Minimum execution time: 958_000 picoseconds. + Weight::from_parts(996_000, 0) } pub fn descend_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 560_000 picoseconds. - Weight::from_parts(600_000, 0) + // Minimum execution time: 992_000 picoseconds. + Weight::from_parts(1_056_000, 0) } pub fn clear_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 514_000 picoseconds. - Weight::from_parts(558_000, 0) + // Minimum execution time: 975_000 picoseconds. + Weight::from_parts(1_026_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -159,8 +159,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 55_871_000 picoseconds. - Weight::from_parts(57_172_000, 6196) + // Minimum execution time: 67_236_000 picoseconds. + Weight::from_parts(68_712_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -170,8 +170,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `90` // Estimated: `3555` - // Minimum execution time: 8_487_000 picoseconds. - Weight::from_parts(8_800_000, 3555) + // Minimum execution time: 10_890_000 picoseconds. + Weight::from_parts(11_223_000, 3555) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -179,8 +179,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 528_000 picoseconds. - Weight::from_parts(569_000, 0) + // Minimum execution time: 959_000 picoseconds. + Weight::from_parts(1_018_000, 0) } // Storage: `PolkadotXcm::VersionNotifyTargets` (r:1 w:1) // Proof: `PolkadotXcm::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -200,8 +200,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `38` // Estimated: `3503` - // Minimum execution time: 19_803_000 picoseconds. - Weight::from_parts(20_368_000, 3503) + // Minimum execution time: 25_162_000 picoseconds. + Weight::from_parts(25_621_000, 3503) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -211,44 +211,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_185_000 picoseconds. - Weight::from_parts(2_332_000, 0) + // Minimum execution time: 2_949_000 picoseconds. + Weight::from_parts(3_119_000, 0) .saturating_add(T::DbWeight::get().writes(1)) } pub fn burn_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 822_000 picoseconds. - Weight::from_parts(928_000, 0) + // Minimum execution time: 1_329_000 picoseconds. + Weight::from_parts(1_410_000, 0) } pub fn expect_asset() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 603_000 picoseconds. - Weight::from_parts(643_000, 0) + // Minimum execution time: 1_063_000 picoseconds. + Weight::from_parts(1_101_000, 0) } pub fn expect_origin() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 503_000 picoseconds. - Weight::from_parts(580_000, 0) + // Minimum execution time: 991_000 picoseconds. + Weight::from_parts(1_041_000, 0) } pub fn expect_error() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 534_000 picoseconds. - Weight::from_parts(577_000, 0) + // Minimum execution time: 944_000 picoseconds. + Weight::from_parts(998_000, 0) } pub fn expect_transact_status() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 694_000 picoseconds. - Weight::from_parts(745_000, 0) + // Minimum execution time: 1_100_000 picoseconds. + Weight::from_parts(1_180_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -270,8 +270,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 61_083_000 picoseconds. - Weight::from_parts(62_214_000, 6196) + // Minimum execution time: 71_203_000 picoseconds. + Weight::from_parts(73_644_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -279,8 +279,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_261_000 picoseconds. - Weight::from_parts(3_483_000, 0) + // Minimum execution time: 4_018_000 picoseconds. + Weight::from_parts(4_267_000, 0) } // Storage: `ParachainInfo::ParachainId` (r:1 w:0) // Proof: `ParachainInfo::ParachainId` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) @@ -302,8 +302,8 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `208` // Estimated: `6196` - // Minimum execution time: 56_270_000 picoseconds. - Weight::from_parts(57_443_000, 6196) + // Minimum execution time: 67_893_000 picoseconds. + Weight::from_parts(69_220_000, 6196) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -311,44 +311,44 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 565_000 picoseconds. - Weight::from_parts(628_000, 0) + // Minimum execution time: 980_000 picoseconds. + Weight::from_parts(1_043_000, 0) } pub fn set_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 496_000 picoseconds. - Weight::from_parts(563_000, 0) + // Minimum execution time: 944_000 picoseconds. + Weight::from_parts(981_000, 0) } pub fn clear_topic() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 518_000 picoseconds. - Weight::from_parts(557_000, 0) + // Minimum execution time: 930_000 picoseconds. + Weight::from_parts(962_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:2 w:0) // Proof: `PolkadotXcm::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + // Storage: `XcmOverBridgeHubRococo::Bridges` (r:1 w:0) + // Proof: `XcmOverBridgeHubRococo::Bridges` (`max_values`: None, `max_size`: Some(1918), added: 4393, mode: `MaxEncodedLen`) // Storage: `BridgeRococoMessages::PalletOperatingMode` (r:1 w:0) // Proof: `BridgeRococoMessages::PalletOperatingMode` (`max_values`: Some(1), `max_size`: Some(2), added: 497, mode: `MaxEncodedLen`) // Storage: `BridgeRococoMessages::OutboundLanes` (r:1 w:1) - // Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) - // Storage: `BridgeRococoMessages::OutboundLanesCongestedSignals` (r:1 w:0) - // Proof: `BridgeRococoMessages::OutboundLanesCongestedSignals` (`max_values`: Some(1), `max_size`: Some(21), added: 516, mode: `MaxEncodedLen`) + // Proof: `BridgeRococoMessages::OutboundLanes` (`max_values`: None, `max_size`: Some(74), added: 2549, mode: `MaxEncodedLen`) // Storage: `BridgeRococoMessages::OutboundMessages` (r:0 w:1) - // Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65568), added: 68043, mode: `MaxEncodedLen`) + // Proof: `BridgeRococoMessages::OutboundMessages` (`max_values`: None, `max_size`: Some(65597), added: 68072, mode: `MaxEncodedLen`) /// The range of component `x` is `[1, 1000]`. pub fn export_message(x: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `225` - // Estimated: `6165` - // Minimum execution time: 36_288_000 picoseconds. - Weight::from_parts(37_707_751, 6165) - // Standard Error: 124 - .saturating_add(Weight::from_parts(51_290, 0).saturating_mul(x.into())) + // Measured: `552` + // Estimated: `6492` + // Minimum execution time: 56_762_000 picoseconds. + Weight::from_parts(58_320_046, 6492) + // Standard Error: 162 + .saturating_add(Weight::from_parts(51_730, 0).saturating_mul(x.into())) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -356,14 +356,14 @@ impl WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 485_000 picoseconds. - Weight::from_parts(540_000, 0) + // Minimum execution time: 971_000 picoseconds. + Weight::from_parts(1_018_000, 0) } pub fn unpaid_execution() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 542_000 picoseconds. - Weight::from_parts(586_000, 0) + // Minimum execution time: 979_000 picoseconds. + Weight::from_parts(1_026_000, 0) } } diff --git a/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs b/cumulus/parachains/runtimes/bridge-hubs/bridge-hub-westend/src/xcm_config.rs index c2ca8e47f2a6..ae31ca4cedf2 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 @@ -17,7 +17,7 @@ use super::{ AccountId, AllPalletsWithSystem, Balances, BaseDeliveryFee, FeeAssetId, ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, - TransactionByteFee, WeightToFee, XcmpQueue, + TransactionByteFee, WeightToFee, XcmOverBridgeHubRococo, XcmpQueue, }; use frame_support::{ parameter_types, @@ -35,19 +35,25 @@ 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, + DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, + EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, HandleFee, HashedDescription, + IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, }; -use xcm_executor::XcmExecutor; +use xcm_executor::{ + traits::{FeeManager, FeeReason, FeeReason::Export}, + XcmExecutor, +}; parameter_types! { pub const WestendLocation: Location = Location::parent(); @@ -71,6 +77,8 @@ pub type LocationToAccountId = ( SiblingParachainConvertsVia, // Straight up local `AccountId32` origins just alias directly to `AccountId`. AccountId32Aliases, + // Foreign locations alias into accounts according to a hash of their standard description. + HashedDescription>, ); /// Means for transacting the native currency on this chain. @@ -193,11 +201,22 @@ 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 = + (XcmOverBridgeHubRococo, crate::bridge_to_ethereum_config::SnowbridgeExporter); type UniversalAliases = Nothing; type CallDispatcher = RuntimeCall; type SafeCallFilter = Everything; @@ -261,3 +280,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 000000000000..1a1ce2a28ea3 --- /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, TxExtension, 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() + 20_000_000_000, + H160::random(), + H160::random(), + // fee not enough + 20_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: TxExtension = ( + 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(),), + frame_metadata_hash_extension::CheckMetadataHash::::new(false), + cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), + ); + 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 763271fd7af0..e5b67353c0f3 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 @@ -16,25 +16,30 @@ #![cfg(test)] +use bp_messages::LegacyLaneId; use bp_polkadot_core::Signature; -use bridge_common_config::{DeliveryRewardInBalance, RequiredStakeForStakeAndSlash}; +use bridge_common_config::{ + DeliveryRewardInBalance, RelayersForLegacyLaneIdsMessagesInstance, + RequiredStakeForStakeAndSlash, +}; use bridge_hub_test_utils::{test_cases::from_parachain, SlotDurations}; use bridge_hub_westend_runtime::{ bridge_common_config, bridge_to_rococo_config, - xcm_config::{RelayNetwork, WestendLocation, XcmConfig}, + bridge_to_rococo_config::RococoGlobalConsensusNetwork, + xcm_config::{LocationToAccountId, RelayNetwork, WestendLocation, XcmConfig}, AllPalletsWithoutSystem, BridgeRejectObsoleteHeadersAndMessages, Executive, ExistentialDeposit, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, SessionKeys, - SignedExtra, TransactionPayment, UncheckedExtrinsic, + TransactionPayment, TxExtension, 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, XcmOverBridgeHubRococoInstance, }; use codec::{Decode, Encode}; use frame_support::{dispatch::GetDispatchInfo, parameter_types, traits::ConstU8}; use parachains_common::{AccountId, AuraId, Balance}; use sp_consensus_aura::SlotDuration; +use sp_core::crypto::Ss58Codec; use sp_keyring::AccountKeyring::Alice; use sp_runtime::{ generic::{Era, SignedPayload}, @@ -42,9 +47,20 @@ use sp_runtime::{ }; use testnet_parachains_constants::westend::{consensus::*, fee::WeightToFee}; use xcm::latest::prelude::*; +use xcm_runtime_apis::conversions::LocationToAccountHelper; + +// Random para id of sibling chain used in tests. +pub const SIBLING_PARACHAIN_ID: u32 = 2053; +// Random para id of sibling chain used in tests. +pub const SIBLING_SYSTEM_PARACHAIN_ID: u32 = 1008; +// Random para id of bridged chain from different global consensus used in tests. +pub const BRIDGED_LOCATION_PARACHAIN_ID: u32 = 1075; -// Para id of sibling chain used in tests. -pub const SIBLING_PARACHAIN_ID: u32 = 1000; +parameter_types! { + pub SiblingParachainLocation: Location = Location::new(1, [Parachain(SIBLING_PARACHAIN_ID)]); + pub SiblingSystemParachainLocation: Location = Location::new(1, [Parachain(SIBLING_SYSTEM_PARACHAIN_ID)]); + pub BridgedUniversalLocation: InteriorLocation = [GlobalConsensus(RococoGlobalConsensusNetwork::get()), Parachain(BRIDGED_LOCATION_PARACHAIN_ID)].into(); +} // Runtime from tests PoV type RuntimeTestsAdapter = from_parachain::WithRemoteParachainHelperAdapter< @@ -53,6 +69,7 @@ type RuntimeTestsAdapter = from_parachain::WithRemoteParachainHelperAdapter< BridgeGrandpaRococoInstance, BridgeParachainRococoInstance, WithBridgeHubRococoMessagesInstance, + RelayersForLegacyLaneIdsMessagesInstance, >; parameter_types! { @@ -64,7 +81,7 @@ fn construct_extrinsic( call: RuntimeCall, ) -> UncheckedExtrinsic { let account_id = AccountId32::from(sender.public()); - let extra: SignedExtra = ( + let tx_ext: TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -77,11 +94,13 @@ fn construct_extrinsic( pallet_transaction_payment::ChargeTransactionPayment::::from(0), BridgeRejectObsoleteHeadersAndMessages::default(), (bridge_to_rococo_config::OnBridgeHubWestendRefundBridgeHubRococoMessages::default(),), + frame_metadata_hash_extension::CheckMetadataHash::new(false), cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::new(), - ); - let payload = SignedPayload::new(call.clone(), extra.clone()).unwrap(); + ) + .into(); + let payload = SignedPayload::new(call.clone(), tx_ext.clone()).unwrap(); let signature = payload.using_encoded(|e| sender.sign(e)); - UncheckedExtrinsic::new_signed(call, account_id.into(), Signature::Sr25519(signature), extra) + UncheckedExtrinsic::new_signed(call, account_id.into(), Signature::Sr25519(signature), tx_ext) } fn construct_and_apply_extrinsic( @@ -211,12 +230,29 @@ fn handle_export_message_from_system_parachain_add_to_outbound_queue_works() { _ => None, } }), - || 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, + || ExportMessage { network: RococoGlobalConsensusNetwork::get(), destination: [Parachain(BRIDGED_LOCATION_PARACHAIN_ID)].into(), xcm: Xcm(vec![]) }, 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!"); + + // we need to create lane between sibling parachain and remote destination + bridge_hub_test_utils::ensure_opened_bridge::< + Runtime, + XcmOverBridgeHubRococoInstance, + LocationToAccountId, + WestendLocation, + >( + SiblingParachainLocation::get(), + BridgedUniversalLocation::get(), + |locations, fee| { + bridge_hub_test_utils::open_bridge_with_storage::< + Runtime, XcmOverBridgeHubRococoInstance + >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + } + ).1 + }, ) } @@ -248,7 +284,6 @@ fn message_dispatch_routing_works() { _ => None, } }), - XCM_LANE_FOR_ASSET_HUB_WESTEND_TO_ASSET_HUB_ROCOCO, || (), ) } @@ -260,12 +295,63 @@ 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, - || (), + || { + // we need to create lane between sibling parachain and remote destination + bridge_hub_test_utils::ensure_opened_bridge::< + Runtime, + XcmOverBridgeHubRococoInstance, + LocationToAccountId, + WestendLocation, + >( + SiblingParachainLocation::get(), + BridgedUniversalLocation::get(), + |locations, fee| { + bridge_hub_test_utils::open_bridge_with_storage::< + Runtime, + XcmOverBridgeHubRococoInstance, + >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + }, + ) + .1 + }, + construct_and_apply_extrinsic, + true, + ) +} + +#[test] +fn free_relay_extrinsic_works() { + // from Rococo + from_parachain::free_relay_extrinsic_works::( + collator_session_keys(), + slot_durations(), + bp_bridge_hub_westend::BRIDGE_HUB_WESTEND_PARACHAIN_ID, + bp_bridge_hub_rococo::BRIDGE_HUB_ROCOCO_PARACHAIN_ID, + SIBLING_PARACHAIN_ID, + Westend, + || { + // we need to create lane between sibling parachain and remote destination + bridge_hub_test_utils::ensure_opened_bridge::< + Runtime, + XcmOverBridgeHubRococoInstance, + LocationToAccountId, + WestendLocation, + >( + SiblingParachainLocation::get(), + BridgedUniversalLocation::get(), + |locations, fee| { + bridge_hub_test_utils::open_bridge_with_storage::< + Runtime, + XcmOverBridgeHubRococoInstance, + >(locations, fee, LegacyLaneId([0, 0, 0, 1])) + }, + ) + .1 + }, construct_and_apply_extrinsic, + true, ) } @@ -300,8 +386,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,11 +405,120 @@ 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() ), ) } + +#[test] +fn location_conversion_works() { + // the purpose of hardcoded values is to catch an unintended location conversion logic change. + struct TestCase { + description: &'static str, + location: Location, + expected_account_id_str: &'static str, + } + + let test_cases = vec![ + // DescribeTerminus + TestCase { + description: "DescribeTerminus Parent", + location: Location::new(1, Here), + expected_account_id_str: "5Dt6dpkWPwLaH4BBCKJwjiWrFVAGyYk3tLUabvyn4v7KtESG", + }, + TestCase { + description: "DescribeTerminus Sibling", + location: Location::new(1, [Parachain(1111)]), + expected_account_id_str: "5Eg2fnssmmJnF3z1iZ1NouAuzciDaaDQH7qURAy3w15jULDk", + }, + // DescribePalletTerminal + TestCase { + description: "DescribePalletTerminal Parent", + location: Location::new(1, [PalletInstance(50)]), + expected_account_id_str: "5CnwemvaAXkWFVwibiCvf2EjqwiqBi29S5cLLydZLEaEw6jZ", + }, + TestCase { + description: "DescribePalletTerminal Sibling", + location: Location::new(1, [Parachain(1111), PalletInstance(50)]), + expected_account_id_str: "5GFBgPjpEQPdaxEnFirUoa51u5erVx84twYxJVuBRAT2UP2g", + }, + // DescribeAccountId32Terminal + TestCase { + description: "DescribeAccountId32Terminal Parent", + location: Location::new( + 1, + [Junction::AccountId32 { network: None, id: AccountId::from(Alice).into() }], + ), + expected_account_id_str: "5EueAXd4h8u75nSbFdDJbC29cmi4Uo1YJssqEL9idvindxFL", + }, + TestCase { + description: "DescribeAccountId32Terminal Sibling", + location: Location::new( + 1, + [ + Parachain(1111), + Junction::AccountId32 { network: None, id: AccountId::from(Alice).into() }, + ], + ), + expected_account_id_str: "5Dmbuiq48fU4iW58FKYqoGbbfxFHjbAeGLMtjFg6NNCw3ssr", + }, + // DescribeAccountKey20Terminal + TestCase { + description: "DescribeAccountKey20Terminal Parent", + location: Location::new(1, [AccountKey20 { network: None, key: [0u8; 20] }]), + expected_account_id_str: "5F5Ec11567pa919wJkX6VHtv2ZXS5W698YCW35EdEbrg14cg", + }, + TestCase { + description: "DescribeAccountKey20Terminal Sibling", + location: Location::new( + 1, + [Parachain(1111), AccountKey20 { network: None, key: [0u8; 20] }], + ), + expected_account_id_str: "5CB2FbUds2qvcJNhDiTbRZwiS3trAy6ydFGMSVutmYijpPAg", + }, + // DescribeTreasuryVoiceTerminal + TestCase { + description: "DescribeTreasuryVoiceTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]), + expected_account_id_str: "5CUjnE2vgcUCuhxPwFoQ5r7p1DkhujgvMNDHaF2bLqRp4D5F", + }, + TestCase { + description: "DescribeTreasuryVoiceTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Treasury, part: BodyPart::Voice }], + ), + expected_account_id_str: "5G6TDwaVgbWmhqRUKjBhRRnH4ry9L9cjRymUEmiRsLbSE4gB", + }, + // DescribeBodyTerminal + TestCase { + description: "DescribeBodyTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Unit, part: BodyPart::Voice }]), + expected_account_id_str: "5EBRMTBkDisEXsaN283SRbzx9Xf2PXwUxxFCJohSGo4jYe6B", + }, + TestCase { + description: "DescribeBodyTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Unit, part: BodyPart::Voice }], + ), + expected_account_id_str: "5DBoExvojy8tYnHgLL97phNH975CyT45PWTZEeGoBZfAyRMH", + }, + ]; + + for tc in test_cases { + let expected = + AccountId::from_string(tc.expected_account_id_str).expect("Invalid AccountId string"); + + let got = LocationToAccountHelper::::convert_location( + tc.location.into(), + ) + .unwrap(); + + assert_eq!(got, expected, "{}", tc.description); + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml index 3ae43075000b..9cb24a2b2820 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/common/Cargo.toml @@ -12,6 +12,7 @@ scale-info = { features = ["derive"], workspace = true } frame-support = { workspace = true } sp-core = { workspace = true } sp-runtime = { workspace = true } +sp-std = { workspace = true } cumulus-primitives-core = { workspace = true } xcm = { workspace = true } pallet-message-queue = { workspace = true } @@ -28,6 +29,7 @@ std = [ "snowbridge-core/std", "sp-core/std", "sp-runtime/std", + "sp-std/std", "xcm/std", ] diff --git a/cumulus/parachains/runtimes/bridge-hubs/common/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/common/src/lib.rs index aac6eb036526..b806b8cdb22d 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/common/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/common/src/lib.rs @@ -16,6 +16,7 @@ pub mod digest_item; pub mod message_queue; +pub mod xcm_version; pub use digest_item::CustomDigestItem; pub use message_queue::{AggregateMessageOrigin, BridgeHubMessageRouter}; diff --git a/cumulus/parachains/runtimes/bridge-hubs/common/src/xcm_version.rs b/cumulus/parachains/runtimes/bridge-hubs/common/src/xcm_version.rs new file mode 100644 index 000000000000..72e6c697e44a --- /dev/null +++ b/cumulus/parachains/runtimes/bridge-hubs/common/src/xcm_version.rs @@ -0,0 +1,44 @@ +// 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. + +//! Custom XCM implementation. + +use frame_support::traits::Get; +use xcm::{ + latest::prelude::*, + prelude::{GetVersion, XcmVersion}, +}; + +/// Adapter for the implementation of `GetVersion`, which attempts to find the minimal +/// configured XCM version between the destination `dest` and the bridge hub location provided as +/// `Get`. +pub struct XcmVersionOfDestAndRemoteBridge( + sp_std::marker::PhantomData<(Version, RemoteBridge)>, +); +impl> GetVersion + for XcmVersionOfDestAndRemoteBridge +{ + fn get_version_for(dest: &Location) -> Option { + let dest_version = Version::get_version_for(dest); + let bridge_hub_version = Version::get_version_for(&RemoteBridge::get()); + + match (dest_version, bridge_hub_version) { + (Some(dv), Some(bhv)) => Some(sp_std::cmp::min(dv, bhv)), + (Some(dv), None) => Some(dv), + (None, Some(bhv)) => Some(bhv), + (None, None) => None, + } + } +} diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml index 44a8646142d6..915b3090092f 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/Cargo.toml @@ -37,18 +37,22 @@ parachains-runtimes-test-utils = { workspace = true } xcm = { workspace = true } xcm-builder = { workspace = true } xcm-executor = { workspace = true } +pallet-xcm = { workspace = true } # Bridges bp-header-chain = { workspace = true } bp-messages = { workspace = true } +bp-parachains = { workspace = true } bp-polkadot-core = { workspace = true } bp-relayers = { workspace = true } bp-runtime = { workspace = true } bp-test-utils = { workspace = true } +bp-xcm-bridge-hub = { workspace = true } pallet-bridge-grandpa = { workspace = true } pallet-bridge-parachains = { workspace = true } pallet-bridge-messages = { features = ["test-helpers"], workspace = true } pallet-bridge-relayers = { workspace = true } +pallet-xcm-bridge-hub = { workspace = true } bridge-runtime-common = { workspace = true } [features] @@ -57,10 +61,12 @@ std = [ "asset-test-utils/std", "bp-header-chain/std", "bp-messages/std", + "bp-parachains/std", "bp-polkadot-core/std", "bp-relayers/std", "bp-runtime/std", "bp-test-utils/std", + "bp-xcm-bridge-hub/std", "bridge-runtime-common/std", "codec/std", "cumulus-pallet-parachain-system/std", @@ -75,6 +81,8 @@ std = [ "pallet-bridge-relayers/std", "pallet-timestamp/std", "pallet-utility/std", + "pallet-xcm-bridge-hub/std", + "pallet-xcm/std", "parachains-common/std", "parachains-runtimes-test-utils/std", "sp-core/std", diff --git a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs index 0b3463f0df97..bc28df0eb829 100644 --- a/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/bridge-hubs/test-utils/src/lib.rs @@ -24,6 +24,9 @@ extern crate alloc; pub use bp_test_utils::test_header; pub use parachains_runtimes_test_utils::*; use sp_runtime::Perbill; +pub use test_cases::helpers::{ + ensure_opened_bridge, open_bridge_with_extrinsic, open_bridge_with_storage, +}; /// A helper function for comparing the actual value of a fee constant with its estimated value. The /// estimated value can be overestimated (`overestimate_in_percent`), and if the difference to the 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 d6dfa93731a7..320f3030b60a 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 @@ -24,12 +24,12 @@ use crate::{ use alloc::{boxed::Box, vec}; use bp_header_chain::ChainWithGrandpa; -use bp_messages::{LaneId, UnrewardedRelayersState}; +use bp_messages::UnrewardedRelayersState; use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; -use bridge_runtime_common::messages_xcm_extension::XcmAsPlainPayload; +use bp_xcm_bridge_hub::XcmAsPlainPayload; use frame_support::traits::{OnFinalize, OnInitialize}; use frame_system::pallet_prelude::BlockNumberFor; -use pallet_bridge_messages::{BridgedChainOf, ThisChainOf}; +use pallet_bridge_messages::{BridgedChainOf, LaneIdOf, ThisChainOf}; use parachains_runtimes_test_utils::{ AccountIdOf, BasicParachainRuntime, CollatorSessionKeys, RuntimeCallOf, SlotDurations, }; @@ -50,7 +50,7 @@ pub trait WithRemoteGrandpaChainHelper { Self::MPI, InboundPayload = XcmAsPlainPayload, OutboundPayload = XcmAsPlainPayload, - > + pallet_bridge_relayers::Config; + > + pallet_bridge_relayers::Config>; /// All pallets of this chain, excluding system pallet. type AllPalletsWithoutSystem: OnInitialize> + OnFinalize>; @@ -58,15 +58,18 @@ pub trait WithRemoteGrandpaChainHelper { type GPI: 'static; /// Instance of the `pallet-bridge-messages`, used to bridge with remote GRANDPA chain. type MPI: 'static; + /// Instance of the `pallet-bridge-relayers`, used to collect rewards from messages `MPI` + /// instance. + type RPI: 'static; } /// Adapter struct that implements [`WithRemoteGrandpaChainHelper`]. -pub struct WithRemoteGrandpaChainHelperAdapter( - core::marker::PhantomData<(Runtime, AllPalletsWithoutSystem, GPI, MPI)>, +pub struct WithRemoteGrandpaChainHelperAdapter( + core::marker::PhantomData<(Runtime, AllPalletsWithoutSystem, GPI, MPI, RPI)>, ); -impl WithRemoteGrandpaChainHelper - for WithRemoteGrandpaChainHelperAdapter +impl WithRemoteGrandpaChainHelper + for WithRemoteGrandpaChainHelperAdapter where Runtime: BasicParachainRuntime + cumulus_pallet_xcmp_queue::Config @@ -75,16 +78,18 @@ where MPI, InboundPayload = XcmAsPlainPayload, OutboundPayload = XcmAsPlainPayload, - > + pallet_bridge_relayers::Config, + > + pallet_bridge_relayers::Config>, AllPalletsWithoutSystem: OnInitialize> + OnFinalize>, GPI: 'static, MPI: 'static, + RPI: 'static, { type Runtime = Runtime; type AllPalletsWithoutSystem = AllPalletsWithoutSystem; type GPI = GPI; type MPI = MPI; + type RPI = RPI; } /// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer, @@ -94,15 +99,14 @@ 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() -> LaneIdOf, construct_and_apply_extrinsic: fn( sp_keyring::AccountKeyring, RuntimeCallOf, ) -> sp_runtime::DispatchOutcome, + expect_rewards: bool, ) where RuntimeHelper: WithRemoteGrandpaChainHelper, AccountIdOf: From, @@ -125,10 +129,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 +146,7 @@ pub fn relayed_incoming_message_works( test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< BridgedChainOf, ThisChainOf, - (), + LaneIdOf, >( lane_id, xcm.into(), @@ -174,14 +179,18 @@ pub fn relayed_incoming_message_works( lane_id, 1, ), - helpers::VerifyRelayerRewarded::::expect_relayer_reward( - relayer_id_at_this_chain, - RewardsAccountParams::new( - lane_id, - bridged_chain_id, - RewardsAccountOwner::ThisChain, - ), - ), + if expect_rewards { + helpers::VerifyRelayerRewarded::::expect_relayer_reward( + relayer_id_at_this_chain, + RewardsAccountParams::new( + lane_id, + bridged_chain_id, + RewardsAccountOwner::ThisChain, + ), + ) + } else { + Box::new(()) + } )), ), ] @@ -197,15 +206,14 @@ 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() -> LaneIdOf, construct_and_apply_extrinsic: fn( sp_keyring::AccountKeyring, RuntimeCallOf, ) -> sp_runtime::DispatchOutcome, + expect_rewards: bool, ) where RuntimeHelper: WithRemoteGrandpaChainHelper, RuntimeHelper::Runtime: pallet_balances::Config, @@ -235,8 +243,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 +275,7 @@ pub fn free_relay_extrinsic_works( test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< BridgedChainOf, ThisChainOf, - (), + LaneIdOf, >( lane_id, xcm.into(), @@ -305,14 +314,18 @@ pub fn free_relay_extrinsic_works( lane_id, 1, ), - helpers::VerifyRelayerRewarded::::expect_relayer_reward( - relayer_id_at_this_chain, - RewardsAccountParams::new( - lane_id, - bridged_chain_id, - RewardsAccountOwner::ThisChain, - ), - ), + if expect_rewards { + helpers::VerifyRelayerRewarded::::expect_relayer_reward( + relayer_id_at_this_chain, + RewardsAccountParams::new( + lane_id, + bridged_chain_id, + RewardsAccountOwner::ThisChain, + ), + ) + } else { + Box::new(()) + } )), ), ] @@ -328,10 +341,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() -> LaneIdOf, construct_and_apply_extrinsic: fn( sp_keyring::AccountKeyring, RuntimeCallOf, @@ -361,10 +372,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 +389,7 @@ pub fn complex_relay_extrinsic_works( test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< BridgedChainOf, ThisChainOf, - (), + LaneIdOf, >( lane_id, xcm.into(), @@ -388,9 +400,10 @@ pub fn complex_relay_extrinsic_works( ); let relay_chain_header_hash = relay_chain_header.hash(); - vec![( - pallet_utility::Call::::batch_all { - calls: vec![ + vec![ + ( + pallet_utility::Call::::batch_all { + calls: vec![ BridgeGrandpaCall::::submit_finality_proof { finality_target: Box::new(relay_chain_header), justification: grandpa_justification, @@ -402,27 +415,33 @@ pub fn complex_relay_extrinsic_works( dispatch_weight: Weight::from_parts(1000000000, 0), }.into(), ], - } - .into(), - Box::new(( - helpers::VerifySubmitGrandpaFinalityProofOutcome::< - RuntimeHelper::Runtime, - RuntimeHelper::GPI, - >::expect_best_header_hash(relay_chain_header_hash), - helpers::VerifySubmitMessagesProofOutcome::< - RuntimeHelper::Runtime, - RuntimeHelper::MPI, - >::expect_last_delivered_nonce(lane_id, 1), - helpers::VerifyRelayerRewarded::::expect_relayer_reward( - relayer_id_at_this_chain, - RewardsAccountParams::new( - lane_id, - bridged_chain_id, - RewardsAccountOwner::ThisChain, + } + .into(), + Box::new( + ( + helpers::VerifySubmitGrandpaFinalityProofOutcome::< + RuntimeHelper::Runtime, + RuntimeHelper::GPI, + >::expect_best_header_hash(relay_chain_header_hash), + helpers::VerifySubmitMessagesProofOutcome::< + RuntimeHelper::Runtime, + RuntimeHelper::MPI, + >::expect_last_delivered_nonce(lane_id, 1), + helpers::VerifyRelayerRewarded::< + RuntimeHelper::Runtime, + RuntimeHelper::RPI, + >::expect_relayer_reward( + relayer_id_at_this_chain, + RewardsAccountParams::new( + lane_id, + bridged_chain_id, + RewardsAccountOwner::ThisChain, + ), + ), ), ), - )), - )] + ), + ] }, ); } @@ -452,9 +471,9 @@ where test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< BridgedChainOf, ThisChainOf, - (), + LaneIdOf, >( - LaneId::default(), + LaneIdOf::::default(), vec![Instruction::<()>::ClearOrigin; 1_024].into(), 1, [GlobalConsensus(Polkadot), Parachain(1_000)].into(), @@ -509,8 +528,9 @@ where BridgedChainOf, ThisChainOf, (), + LaneIdOf, >( - LaneId::default(), + LaneIdOf::::default(), 1u32.into(), AccountId32::from(Alice.public()).into(), unrewarded_relayers.clone(), @@ -557,9 +577,9 @@ where test_data::from_grandpa_chain::make_complex_relayer_delivery_proofs::< BridgedChainOf, ThisChainOf, - (), + LaneIdOf, >( - LaneId::default(), + LaneIdOf::::default(), vec![Instruction::<()>::ClearOrigin; 1_024].into(), 1, [GlobalConsensus(Polkadot), Parachain(1_000)].into(), @@ -610,8 +630,9 @@ where BridgedChainOf, ThisChainOf, (), + LaneIdOf, >( - LaneId::default(), + LaneIdOf::::default(), 1u32.into(), AccountId32::from(Alice.public()).into(), unrewarded_relayers.clone(), 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 728b4e76b105..1da901e0bcdf 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 @@ -24,14 +24,14 @@ use crate::{ use alloc::{boxed::Box, vec}; use bp_header_chain::ChainWithGrandpa; -use bp_messages::{LaneId, UnrewardedRelayersState}; +use bp_messages::UnrewardedRelayersState; use bp_polkadot_core::parachains::ParaHash; use bp_relayers::{RewardsAccountOwner, RewardsAccountParams}; use bp_runtime::{Chain, Parachain}; -use bridge_runtime_common::messages_xcm_extension::XcmAsPlainPayload; +use bp_xcm_bridge_hub::XcmAsPlainPayload; use frame_support::traits::{OnFinalize, OnInitialize}; use frame_system::pallet_prelude::BlockNumberFor; -use pallet_bridge_messages::{BridgedChainOf, ThisChainOf}; +use pallet_bridge_messages::{BridgedChainOf, LaneIdOf, ThisChainOf}; use parachains_runtimes_test_utils::{ AccountIdOf, BasicParachainRuntime, CollatorSessionKeys, RuntimeCallOf, SlotDurations, }; @@ -53,7 +53,7 @@ pub trait WithRemoteParachainHelper { Self::MPI, InboundPayload = XcmAsPlainPayload, OutboundPayload = XcmAsPlainPayload, - > + pallet_bridge_relayers::Config; + > + pallet_bridge_relayers::Config>; /// All pallets of this chain, excluding system pallet. type AllPalletsWithoutSystem: OnInitialize> + OnFinalize>; @@ -63,15 +63,18 @@ pub trait WithRemoteParachainHelper { type PPI: 'static; /// Instance of the `pallet-bridge-messages`, used to bridge with remote parachain. type MPI: 'static; + /// Instance of the `pallet-bridge-relayers`, used to collect rewards from messages `MPI` + /// instance. + type RPI: 'static; } /// Adapter struct that implements `WithRemoteParachainHelper`. -pub struct WithRemoteParachainHelperAdapter( - core::marker::PhantomData<(Runtime, AllPalletsWithoutSystem, GPI, PPI, MPI)>, +pub struct WithRemoteParachainHelperAdapter( + core::marker::PhantomData<(Runtime, AllPalletsWithoutSystem, GPI, PPI, MPI, RPI)>, ); -impl WithRemoteParachainHelper - for WithRemoteParachainHelperAdapter +impl WithRemoteParachainHelper + for WithRemoteParachainHelperAdapter where Runtime: BasicParachainRuntime + cumulus_pallet_xcmp_queue::Config @@ -81,19 +84,20 @@ where MPI, InboundPayload = XcmAsPlainPayload, OutboundPayload = XcmAsPlainPayload, - > + pallet_bridge_relayers::Config, + > + pallet_bridge_relayers::Config>, AllPalletsWithoutSystem: OnInitialize> + OnFinalize>, GPI: 'static, PPI: 'static, MPI: 'static, - // MB: MessageBridge, + RPI: 'static, { type Runtime = Runtime; type AllPalletsWithoutSystem = AllPalletsWithoutSystem; type GPI = GPI; type PPI = PPI; type MPI = MPI; + type RPI = RPI; } /// Test-case makes sure that Runtime can dispatch XCM messages submitted by relayer, @@ -104,15 +108,14 @@ 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() -> LaneIdOf, construct_and_apply_extrinsic: fn( sp_keyring::AccountKeyring, ::RuntimeCall, ) -> sp_runtime::DispatchOutcome, + expect_rewards: bool, ) where RuntimeHelper: WithRemoteParachainHelper, AccountIdOf: From, @@ -138,11 +141,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 +166,7 @@ pub fn relayed_incoming_message_works( >::BridgedChain, BridgedChainOf, ThisChainOf, - (), + LaneIdOf, >( lane_id, xcm.into(), @@ -210,14 +214,18 @@ pub fn relayed_incoming_message_works( lane_id, 1, ), - helpers::VerifyRelayerRewarded::::expect_relayer_reward( - relayer_id_at_this_chain, - RewardsAccountParams::new( - lane_id, - bridged_chain_id, - RewardsAccountOwner::ThisChain, - ), - ), + if expect_rewards { + helpers::VerifyRelayerRewarded::::expect_relayer_reward( + relayer_id_at_this_chain, + RewardsAccountParams::new( + lane_id, + bridged_chain_id, + RewardsAccountOwner::ThisChain, + ), + ) + } else { + Box::new(()) + } )), ), ] @@ -234,15 +242,14 @@ 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() -> LaneIdOf, construct_and_apply_extrinsic: fn( sp_keyring::AccountKeyring, ::RuntimeCall, ) -> sp_runtime::DispatchOutcome, + expect_rewards: bool, ) where RuntimeHelper: WithRemoteParachainHelper, RuntimeHelper::Runtime: pallet_balances::Config, @@ -275,8 +282,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 +323,7 @@ pub fn free_relay_extrinsic_works( >::BridgedChain, BridgedChainOf, ThisChainOf, - (), + LaneIdOf, >( lane_id, xcm.into(), @@ -357,10 +365,10 @@ pub fn free_relay_extrinsic_works( bridged_para_id, parachain_head_hash, ), - /*helpers::VerifyRelayerBalance::::expect_relayer_balance( + helpers::VerifyRelayerBalance::::expect_relayer_balance( relayer_id_at_this_chain.clone(), initial_relayer_balance, - ),*/ + ), )), ), ( @@ -375,14 +383,18 @@ pub fn free_relay_extrinsic_works( lane_id, 1, ), - helpers::VerifyRelayerRewarded::::expect_relayer_reward( - relayer_id_at_this_chain, - RewardsAccountParams::new( - lane_id, - bridged_chain_id, - RewardsAccountOwner::ThisChain, - ), - ), + if expect_rewards { + helpers::VerifyRelayerRewarded::::expect_relayer_reward( + relayer_id_at_this_chain, + RewardsAccountParams::new( + lane_id, + bridged_chain_id, + RewardsAccountOwner::ThisChain, + ), + ) + } else { + Box::new(()) + } )), ), ] @@ -399,10 +411,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() -> LaneIdOf, construct_and_apply_extrinsic: fn( sp_keyring::AccountKeyring, ::RuntimeCall, @@ -435,11 +445,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 +470,7 @@ pub fn complex_relay_extrinsic_works( >::BridgedChain, BridgedChainOf, ThisChainOf, - (), + LaneIdOf, >( lane_id, xcm.into(), @@ -474,9 +485,10 @@ pub fn complex_relay_extrinsic_works( let parachain_head_hash = parachain_head.hash(); let relay_chain_header_hash = relay_chain_header.hash(); let relay_chain_header_number = *relay_chain_header.number(); - vec![( - pallet_utility::Call::::batch_all { - calls: vec![ + vec![ + ( + pallet_utility::Call::::batch_all { + calls: vec![ BridgeGrandpaCall::::submit_finality_proof { finality_target: Box::new(relay_chain_header), justification: grandpa_justification, @@ -493,31 +505,37 @@ pub fn complex_relay_extrinsic_works( dispatch_weight: Weight::from_parts(1000000000, 0), }.into(), ], - } - .into(), - Box::new(( - helpers::VerifySubmitGrandpaFinalityProofOutcome::< - RuntimeHelper::Runtime, - RuntimeHelper::GPI, - >::expect_best_header_hash(relay_chain_header_hash), - helpers::VerifySubmitParachainHeaderProofOutcome::< - RuntimeHelper::Runtime, - RuntimeHelper::PPI, - >::expect_best_header_hash(bridged_para_id, parachain_head_hash), - helpers::VerifySubmitMessagesProofOutcome::< - RuntimeHelper::Runtime, - RuntimeHelper::MPI, - >::expect_last_delivered_nonce(lane_id, 1), - helpers::VerifyRelayerRewarded::::expect_relayer_reward( - relayer_id_at_this_chain, - RewardsAccountParams::new( - lane_id, - bridged_chain_id, - RewardsAccountOwner::ThisChain, + } + .into(), + Box::new( + ( + helpers::VerifySubmitGrandpaFinalityProofOutcome::< + RuntimeHelper::Runtime, + RuntimeHelper::GPI, + >::expect_best_header_hash(relay_chain_header_hash), + helpers::VerifySubmitParachainHeaderProofOutcome::< + RuntimeHelper::Runtime, + RuntimeHelper::PPI, + >::expect_best_header_hash(bridged_para_id, parachain_head_hash), + helpers::VerifySubmitMessagesProofOutcome::< + RuntimeHelper::Runtime, + RuntimeHelper::MPI, + >::expect_last_delivered_nonce(lane_id, 1), + helpers::VerifyRelayerRewarded::< + RuntimeHelper::Runtime, + RuntimeHelper::RPI, + >::expect_relayer_reward( + relayer_id_at_this_chain, + RewardsAccountParams::new( + lane_id, + bridged_chain_id, + RewardsAccountOwner::ThisChain, + ), + ), ), ), - )), - )] + ), + ] }, ); } @@ -557,9 +575,9 @@ where >::BridgedChain, BridgedChainOf, ThisChainOf, - (), + LaneIdOf >( - LaneId::default(), + LaneIdOf::::default(), vec![Instruction::<()>::ClearOrigin; 1_024].into(), 1, [GlobalConsensus(Polkadot), Parachain(1_000)].into(), @@ -628,9 +646,9 @@ where >::BridgedChain, BridgedChainOf, ThisChainOf, - (), + LaneIdOf, >( - LaneId::default(), + LaneIdOf::::default(), 1, 5, 1_000, @@ -691,9 +709,9 @@ where >::BridgedChain, BridgedChainOf, ThisChainOf, - (), + LaneIdOf, >( - LaneId::default(), + LaneIdOf::::default(), vec![Instruction::<()>::ClearOrigin; 1_024].into(), 1, [GlobalConsensus(Polkadot), Parachain(1_000)].into(), @@ -747,9 +765,9 @@ where >::BridgedChain, BridgedChainOf, ThisChainOf, - (), + LaneIdOf, >( - LaneId::default(), + LaneIdOf::::default(), 1, 5, 1_000, 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 78b8a170f0d4..aac60bba0b53 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 @@ -19,18 +19,21 @@ use crate::test_cases::{bridges_prelude::*, run_test, RuntimeHelper}; use asset_test_utils::BasicParachainRuntime; -use bp_messages::{LaneId, MessageNonce}; +use bp_messages::MessageNonce; use bp_polkadot_core::parachains::{ParaHash, ParaId}; use bp_relayers::RewardsAccountParams; +use bp_runtime::Chain; +use bp_xcm_bridge_hub::BridgeLocations; use codec::Decode; use core::marker::PhantomData; use frame_support::{ assert_ok, - traits::{OnFinalize, OnInitialize, PalletInfoAccess}, + dispatch::GetDispatchInfo, + traits::{fungible::Mutate, OnFinalize, OnInitialize, PalletInfoAccess}, }; use frame_system::pallet_prelude::BlockNumberFor; use pallet_bridge_grandpa::{BridgedBlockHash, BridgedHeader}; -use pallet_bridge_messages::BridgedChainOf; +use pallet_bridge_messages::{BridgedChainOf, LaneIdOf}; use parachains_common::AccountId; use parachains_runtimes_test_utils::{ mock_open_hrmp_channel, AccountIdOf, CollatorSessionKeys, RuntimeCallOf, SlotDurations, @@ -39,6 +42,7 @@ use sp_core::Get; use sp_keyring::AccountKeyring::*; use sp_runtime::{traits::TrailingZeroInput, AccountId32}; use xcm::latest::prelude::*; +use xcm_executor::traits::ConvertLocation; /// Verify that the transaction has succeeded. #[impl_trait_for_tuples::impl_for_tuples(30)] @@ -128,8 +132,8 @@ where } /// Checks that the latest delivered nonce in the bridge messages pallet equals to given one. -pub struct VerifySubmitMessagesProofOutcome { - lane: LaneId, +pub struct VerifySubmitMessagesProofOutcome, MPI: 'static> { + lane: LaneIdOf, expected_nonce: MessageNonce, _marker: PhantomData<(Runtime, MPI)>, } @@ -141,7 +145,7 @@ where { /// Expect given delivered nonce to be the latest after transaction. pub fn expect_last_delivered_nonce( - lane: LaneId, + lane: LaneIdOf, expected_nonce: MessageNonce, ) -> Box { Box::new(Self { lane, expected_nonce, _marker: PhantomData }) @@ -156,37 +160,39 @@ where fn verify_outcome(&self) { assert_eq!( pallet_bridge_messages::InboundLanes::::get(self.lane) - .last_delivered_nonce(), - self.expected_nonce, + .map(|d| d.last_delivered_nonce()), + Some(self.expected_nonce), ); } } /// Verifies that relayer is rewarded at this chain. -pub struct VerifyRelayerRewarded { +pub struct VerifyRelayerRewarded, RPI: 'static> { relayer: Runtime::AccountId, - reward_params: RewardsAccountParams, + reward_params: RewardsAccountParams, } -impl VerifyRelayerRewarded +impl VerifyRelayerRewarded where - Runtime: pallet_bridge_relayers::Config, + Runtime: pallet_bridge_relayers::Config, + RPI: 'static, { /// Expect given delivered nonce to be the latest after transaction. pub fn expect_relayer_reward( relayer: Runtime::AccountId, - reward_params: RewardsAccountParams, + reward_params: RewardsAccountParams, ) -> Box { Box::new(Self { relayer, reward_params }) } } -impl VerifyTransactionOutcome for VerifyRelayerRewarded +impl VerifyTransactionOutcome for VerifyRelayerRewarded where - Runtime: pallet_bridge_relayers::Config, + Runtime: pallet_bridge_relayers::Config, + RPI: 'static, { fn verify_outcome(&self) { - assert!(pallet_bridge_relayers::RelayerRewards::::get( + assert!(pallet_bridge_relayers::RelayerRewards::::get( &self.relayer, &self.reward_params, ) @@ -267,6 +273,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 +285,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 +347,7 @@ pub fn relayed_incoming_message_works( message_destination, message_nonce, xcm.clone().into(), + bridged_chain_id, ), ); @@ -378,3 +387,184 @@ fn execute_and_verify_calls( verifier.verify_outcome(); } } + +/// Helper function to open the bridge/lane for `source` and `destination` while ensuring all +/// required balances are placed into the SA of the source. +pub fn ensure_opened_bridge< + Runtime, + XcmOverBridgePalletInstance, + LocationToAccountId, + TokenLocation> +(source: Location, destination: InteriorLocation, bridge_opener: impl Fn(BridgeLocations, Asset)) -> (BridgeLocations, pallet_xcm_bridge_hub::LaneIdOf) +where + Runtime: BasicParachainRuntime + BridgeXcmOverBridgeConfig, + XcmOverBridgePalletInstance: 'static, + ::RuntimeCall: GetDispatchInfo + From>, + ::Balance: From<<>::BridgeMessagesPalletInstance>>::ThisChain as bp_runtime::Chain>::Balance>, + ::Balance: From, + LocationToAccountId: ConvertLocation>, +TokenLocation: Get{ + // construct expected bridge configuration + let locations = + pallet_xcm_bridge_hub::Pallet::::bridge_locations( + source.clone().into(), + destination.clone().into(), + ) + .expect("valid bridge locations"); + assert!(pallet_xcm_bridge_hub::Bridges::::get( + locations.bridge_id() + ) + .is_none()); + + // required balance: ED + fee + BridgeDeposit + let bridge_deposit = + >::BridgeDeposit::get( + ); + // random high enough value for `BuyExecution` fees + let buy_execution_fee_amount = 5_000_000_000_000_u128; + let buy_execution_fee = (TokenLocation::get(), buy_execution_fee_amount).into(); + let balance_needed = ::ExistentialDeposit::get() + + buy_execution_fee_amount.into() + + bridge_deposit.into(); + + // SA of source location needs to have some required balance + let source_account_id = LocationToAccountId::convert_location(&source).expect("valid location"); + let _ = >::mint_into(&source_account_id, balance_needed) + .expect("mint_into passes"); + + // call the bridge opener + bridge_opener(*locations.clone(), buy_execution_fee); + + // check opened bridge + let bridge = pallet_xcm_bridge_hub::Bridges::::get( + locations.bridge_id(), + ) + .expect("opened bridge"); + + // check state + assert_ok!( + pallet_xcm_bridge_hub::Pallet::::do_try_state() + ); + + // return locations + (*locations, bridge.lane_id) +} + +/// Utility for opening bridge with dedicated `pallet_xcm_bridge_hub`'s extrinsic. +pub fn open_bridge_with_extrinsic( + locations: BridgeLocations, + buy_execution_fee: Asset, +) where + Runtime: frame_system::Config + + pallet_xcm_bridge_hub::Config + + cumulus_pallet_parachain_system::Config + + pallet_xcm::Config, + XcmOverBridgePalletInstance: 'static, + ::RuntimeCall: + GetDispatchInfo + From>, +{ + // open bridge with `Transact` call + let open_bridge_call = RuntimeCallOf::::from(BridgeXcmOverBridgeCall::< + Runtime, + XcmOverBridgePalletInstance, + >::open_bridge { + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into(), + ), + }); + + // execute XCM as source origin would do with `Transact -> Origin::Xcm` + assert_ok!(RuntimeHelper::::execute_as_origin_xcm( + locations.bridge_origin_relative_location().clone(), + open_bridge_call, + buy_execution_fee + ) + .ensure_complete()); +} + +/// Utility for opening bridge directly inserting data to the storage (used only for legacy +/// purposes). +pub fn open_bridge_with_storage( + locations: BridgeLocations, + _buy_execution_fee: Asset, + lane_id: pallet_xcm_bridge_hub::LaneIdOf, +) where + Runtime: pallet_xcm_bridge_hub::Config, + XcmOverBridgePalletInstance: 'static, +{ + // insert bridge data directly to the storage + assert_ok!( + pallet_xcm_bridge_hub::Pallet::::do_open_bridge( + Box::new(locations), + lane_id, + true + ) + ); +} + +/// Helper function to close the bridge/lane for `source` and `destination`. +pub fn close_bridge(source: Location, destination: InteriorLocation) +where + Runtime: BasicParachainRuntime + BridgeXcmOverBridgeConfig, + XcmOverBridgePalletInstance: 'static, + ::RuntimeCall: GetDispatchInfo + From>, + ::Balance: From<<>::BridgeMessagesPalletInstance>>::ThisChain as bp_runtime::Chain>::Balance>, + ::Balance: From, + LocationToAccountId: ConvertLocation>, +TokenLocation: Get{ + // construct expected bridge configuration + let locations = + pallet_xcm_bridge_hub::Pallet::::bridge_locations( + source.clone().into(), + destination.clone().into(), + ) + .expect("valid bridge locations"); + assert!(pallet_xcm_bridge_hub::Bridges::::get( + locations.bridge_id() + ) + .is_some()); + + // required balance: ED + fee + BridgeDeposit + let bridge_deposit = + >::BridgeDeposit::get( + ); + // random high enough value for `BuyExecution` fees + let buy_execution_fee_amount = 2_500_000_000_000_u128; + let buy_execution_fee = (TokenLocation::get(), buy_execution_fee_amount).into(); + let balance_needed = ::ExistentialDeposit::get() + + buy_execution_fee_amount.into() + + bridge_deposit.into(); + + // SA of source location needs to have some required balance + let source_account_id = LocationToAccountId::convert_location(&source).expect("valid location"); + let _ = >::mint_into(&source_account_id, balance_needed) + .expect("mint_into passes"); + + // close bridge with `Transact` call + let close_bridge_call = RuntimeCallOf::::from(BridgeXcmOverBridgeCall::< + Runtime, + XcmOverBridgePalletInstance, + >::close_bridge { + bridge_destination_universal_location: Box::new(destination.into()), + may_prune_messages: 16, + }); + + // execute XCM as source origin would do with `Transact -> Origin::Xcm` + assert_ok!(RuntimeHelper::::execute_as_origin_xcm( + source.clone(), + close_bridge_call, + buy_execution_fee + ) + .ensure_complete()); + + // bridge is closed + assert!(pallet_xcm_bridge_hub::Bridges::::get( + locations.bridge_id() + ) + .is_none()); + + // check state + assert_ok!( + pallet_xcm_bridge_hub::Pallet::::do_try_state() + ); +} 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 bc1c7ec5e032..24372f57ae7d 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 @@ -29,17 +29,15 @@ use crate::{test_cases::bridges_prelude::*, test_data}; use asset_test_utils::BasicParachainRuntime; use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData, MessageDispatch}, - LaneId, MessageKey, MessagesOperatingMode, OutboundLaneData, + LaneState, MessageKey, MessagesOperatingMode, OutboundLaneData, }; use bp_runtime::BasicOperatingMode; -use bridge_runtime_common::messages_xcm_extension::{ - XcmAsPlainPayload, XcmBlobMessageDispatchResult, -}; +use bp_xcm_bridge_hub::{Bridge, BridgeState, XcmAsPlainPayload}; use codec::Encode; use frame_support::{ assert_ok, dispatch::GetDispatchInfo, - traits::{Get, OnFinalize, OnInitialize, OriginTrait}, + traits::{Contains, Get, OnFinalize, OnInitialize, OriginTrait}, }; use frame_system::pallet_prelude::BlockNumberFor; use parachains_common::AccountId; @@ -51,27 +49,35 @@ use sp_runtime::{traits::Zero, AccountId32}; use xcm::{latest::prelude::*, AlwaysLatest}; use xcm_builder::DispatchBlobError; use xcm_executor::{ - traits::{TransactAsset, WeightBounds}, + traits::{ConvertLocation, TransactAsset, WeightBounds}, XcmExecutor, }; /// Common bridges exports. pub(crate) mod bridges_prelude { + pub use bp_parachains::{RelayBlockHash, RelayBlockNumber}; pub use pallet_bridge_grandpa::{Call as BridgeGrandpaCall, Config as BridgeGrandpaConfig}; - pub use pallet_bridge_messages::{Call as BridgeMessagesCall, Config as BridgeMessagesConfig}; + pub use pallet_bridge_messages::{ + Call as BridgeMessagesCall, Config as BridgeMessagesConfig, LanesManagerError, + }; pub use pallet_bridge_parachains::{ - Call as BridgeParachainsCall, Config as BridgeParachainsConfig, RelayBlockHash, - RelayBlockNumber, + Call as BridgeParachainsCall, Config as BridgeParachainsConfig, + }; + pub use pallet_xcm_bridge_hub::{ + Call as BridgeXcmOverBridgeCall, Config as BridgeXcmOverBridgeConfig, LanesManagerOf, + XcmBlobMessageDispatchResult, }; } // Re-export test_case from assets pub use asset_test_utils::include_teleports_for_native_asset_works; +use pallet_bridge_messages::LaneIdOf; pub type RuntimeHelper = parachains_runtimes_test_utils::RuntimeHelper; // Re-export test_case from `parachains-runtimes-test-utils` +use crate::test_cases::helpers::open_bridge_with_extrinsic; pub use parachains_runtimes_test_utils::test_cases::{ change_storage_constant_by_governance_works, set_storage_keys_by_governance_works, }; @@ -125,7 +131,7 @@ pub fn initialize_bridge_by_governance_works( // execute XCM with Transacts to `initialize bridge` as governance does assert_ok!(RuntimeHelper::::execute_as_governance( initialize_call.encode(), - initialize_call.get_dispatch_info().weight, + initialize_call.get_dispatch_info().call_weight, ) .ensure_complete()); @@ -166,7 +172,7 @@ pub fn change_bridge_grandpa_pallet_mode_by_governance_works::execute_as_governance( set_operating_mode_call.encode(), - set_operating_mode_call.get_dispatch_info().weight, + set_operating_mode_call.get_dispatch_info().call_weight, ) .ensure_complete()); @@ -219,7 +225,7 @@ pub fn change_bridge_parachains_pallet_mode_by_governance_works::execute_as_governance( set_operating_mode_call.encode(), - set_operating_mode_call.get_dispatch_info().weight, + set_operating_mode_call.get_dispatch_info().call_weight, ) .ensure_complete()); @@ -272,7 +278,7 @@ pub fn change_bridge_messages_pallet_mode_by_governance_works::execute_as_governance( set_operating_mode_call.encode(), - set_operating_mode_call.get_dispatch_info().weight, + set_operating_mode_call.get_dispatch_info().call_weight, ) .ensure_complete()); @@ -320,10 +326,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() -> LaneIdOf, ) where Runtime: BasicParachainRuntime + BridgeMessagesConfig, XcmConfig: xcm_executor::Config, @@ -333,14 +338,19 @@ 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!( pallet_bridge_messages::OutboundLanes::::try_get( expected_lane_id ), - Err(()) + Ok(OutboundLaneData { + state: LaneState::Opened, + oldest_unpruned_nonce: 1, + latest_received_nonce: 0, + latest_generated_nonce: 0 + }) ); // prepare `ExportMessage` @@ -391,6 +401,7 @@ pub fn handle_export_message_from_system_parachain_to_outbound_queue_works< expected_lane_id ), Ok(OutboundLaneData { + state: LaneState::Opened, oldest_unpruned_nonce: 1, latest_received_nonce: 0, latest_generated_nonce: 1, @@ -430,7 +441,6 @@ 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(), ) where Runtime: BasicParachainRuntime @@ -461,6 +471,7 @@ pub fn message_dispatch_routing_works< run_test::(collator_session_key, runtime_para_id, vec![], || { prepare_configuration(); + let dummy_lane_id = LaneIdOf::::default(); let mut alice = [0u8; 32]; alice[0] = 1; @@ -477,7 +488,7 @@ pub fn message_dispatch_routing_works< >((RuntimeNetwork::get(), Here)); let result = <>::MessageDispatch>::dispatch( - test_data::dispatch_message(expected_lane_id, 1, bridging_message), + test_data::dispatch_message(dummy_lane_id, 1, bridging_message), ); assert_eq!( format!("{:?}", result.dispatch_level_result), @@ -495,17 +506,18 @@ pub fn message_dispatch_routing_works< // 2. this message is sent from other global consensus with destination of this Runtime // sibling parachain (HRMP) - let bridging_message = test_data::simulate_message_exporter_on_bridged_chain::< - BridgedNetwork, - NetworkWithParentCount, - AlwaysLatest, - >((RuntimeNetwork::get(), [Parachain(sibling_parachain_id)].into())); + let bridging_message = + test_data::simulate_message_exporter_on_bridged_chain::< + BridgedNetwork, + NetworkWithParentCount, + AlwaysLatest, + >((RuntimeNetwork::get(), [Parachain(sibling_parachain_id)].into())); // 2.1. WITHOUT opened hrmp channel -> RoutingError let result = <>::MessageDispatch>::dispatch( DispatchMessage { - key: MessageKey { lane_id: expected_lane_id, nonce: 1 }, + key: MessageKey { lane_id: dummy_lane_id, nonce: 1 }, data: DispatchMessageData { payload: Ok(bridging_message.clone()) }, }, ); @@ -537,7 +549,7 @@ pub fn message_dispatch_routing_works< let result = <>::MessageDispatch>::dispatch( DispatchMessage { - key: MessageKey { lane_id: expected_lane_id, nonce: 1 }, + key: MessageKey { lane_id: dummy_lane_id, nonce: 1 }, data: DispatchMessageData { payload: Ok(bridging_message) }, }, ); @@ -643,3 +655,130 @@ where estimated_fee.into() } + +/// Test-case makes sure that `Runtime` can open/close bridges. +pub fn open_and_close_bridge_works( + collator_session_key: CollatorSessionKeys, + runtime_para_id: u32, + source: Location, + destination: InteriorLocation, +) where + Runtime: BasicParachainRuntime + BridgeXcmOverBridgeConfig, + XcmOverBridgePalletInstance: 'static, + ::RuntimeCall: GetDispatchInfo + From>, + ::Balance: From<<>::BridgeMessagesPalletInstance>>::ThisChain as bp_runtime::Chain>::Balance>, + ::Balance: From, + <>::BridgeMessagesPalletInstance>>::ThisChain as bp_runtime::Chain>::AccountId: From<::AccountId>, + LocationToAccountId: ConvertLocation>, + TokenLocation: Get, +{ + run_test::(collator_session_key, runtime_para_id, vec![], || { + // construct expected bridge configuration + let locations = pallet_xcm_bridge_hub::Pallet::::bridge_locations( + source.clone().into(), + destination.clone().into(), + ).expect("valid bridge locations"); + let expected_lane_id = + locations.calculate_lane_id(xcm::latest::VERSION).expect("valid laneId"); + let lanes_manager = LanesManagerOf::::new(); + + let expected_deposit = if >::AllowWithoutBridgeDeposit::contains( + locations.bridge_origin_relative_location() + ) { + Zero::zero() + } else { + >::BridgeDeposit::get() + }; + + // check bridge/lane DOES not exist + assert_eq!( + pallet_xcm_bridge_hub::Bridges::::get( + locations.bridge_id() + ), + None + ); + assert_eq!( + lanes_manager.active_inbound_lane(expected_lane_id).map(drop), + Err(LanesManagerError::UnknownInboundLane) + ); + assert_eq!( + lanes_manager.active_outbound_lane(expected_lane_id).map(drop), + Err(LanesManagerError::UnknownOutboundLane) + ); + + // open bridge with Transact call from sibling + assert_eq!( + helpers::ensure_opened_bridge::< + Runtime, + XcmOverBridgePalletInstance, + LocationToAccountId, + TokenLocation, + >( + source.clone(), + destination.clone(), + open_bridge_with_extrinsic:: + ) + .0 + .bridge_id(), + locations.bridge_id() + ); + + // check bridge/lane DOES exist + assert_eq!( + pallet_xcm_bridge_hub::Bridges::::get( + locations.bridge_id() + ), + Some(Bridge { + bridge_origin_relative_location: Box::new(source.clone().into()), + bridge_origin_universal_location: Box::new( + locations.bridge_origin_universal_location().clone().into() + ), + bridge_destination_universal_location: Box::new( + locations.bridge_destination_universal_location().clone().into() + ), + state: BridgeState::Opened, + bridge_owner_account: LocationToAccountId::convert_location(&source) + .expect("valid location") + .into(), + deposit: expected_deposit, + lane_id: expected_lane_id + }) + ); + assert_eq!( + lanes_manager.active_inbound_lane(expected_lane_id).map(|lane| lane.state()), + Ok(LaneState::Opened) + ); + assert_eq!( + lanes_manager.active_outbound_lane(expected_lane_id).map(|lane| lane.state()), + Ok(LaneState::Opened) + ); + + // close bridge with Transact call from sibling + helpers::close_bridge::< + Runtime, + XcmOverBridgePalletInstance, + LocationToAccountId, + TokenLocation, + >(source.clone(), destination); + + // check bridge/lane DOES not exist + assert_eq!( + pallet_xcm_bridge_hub::Bridges::::get( + locations.bridge_id() + ), + None + ); + assert_eq!( + lanes_manager.active_inbound_lane(expected_lane_id).map(drop), + Err(LanesManagerError::UnknownInboundLane) + ); + assert_eq!( + lanes_manager.active_outbound_lane(expected_lane_id).map(drop), + Err(LanesManagerError::UnknownOutboundLane) + ); + }); +} 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 c61a31e5454b..7461085330f2 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 @@ -20,12 +20,12 @@ use crate::test_data::prepare_inbound_xcm; use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, ChainWithMessages, LaneId, MessageNonce, + target_chain::FromBridgedChainMessagesProof, ChainWithMessages, LaneState, MessageNonce, UnrewardedRelayersState, }; use bp_runtime::{AccountIdOf, BlockNumberOf, Chain, HeaderOf, UnverifiedStorageProofParams}; use bp_test_utils::make_default_justification; -use bridge_runtime_common::messages_xcm_extension::XcmAsPlainPayload; +use bp_xcm_bridge_hub::XcmAsPlainPayload; use codec::Encode; use pallet_bridge_grandpa::{BridgedChain, BridgedHeader}; use sp_runtime::traits::Header as HeaderT; @@ -40,7 +40,7 @@ use pallet_bridge_messages::{ encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof, prepare_messages_storage_proof, }, - BridgedChainOf, + BridgedChainOf, LaneIdOf, }; use sp_runtime::DigestItem; @@ -48,7 +48,10 @@ use sp_runtime::DigestItem; pub fn make_complex_relayer_delivery_batch( bridged_header: BridgedHeader, bridged_justification: GrandpaJustification>, - message_proof: FromBridgedChainMessagesProof>>, + message_proof: FromBridgedChainMessagesProof< + HashOf>, + LaneIdOf, + >, relayer_id_at_bridged_chain: InboundRelayerId, ) -> pallet_utility::Call where @@ -82,6 +85,7 @@ pub fn make_complex_relayer_confirmation_batch( bridged_justification: GrandpaJustification>, message_delivery_proof: FromBridgedChainMessagesDeliveryProof< HashOf>, + LaneIdOf, >, relayers_state: UnrewardedRelayersState, ) -> pallet_utility::Call @@ -111,7 +115,10 @@ where /// Prepare a call with message proof. pub fn make_standalone_relayer_delivery_call( - message_proof: FromBridgedChainMessagesProof>>, + message_proof: FromBridgedChainMessagesProof< + HashOf>, + LaneIdOf, + >, relayer_id_at_bridged_chain: InboundRelayerId, ) -> Runtime::RuntimeCall where @@ -134,6 +141,7 @@ where pub fn make_standalone_relayer_confirmation_call( message_delivery_proof: FromBridgedChainMessagesDeliveryProof< HashOf>, + LaneIdOf, >, relayers_state: UnrewardedRelayersState, ) -> Runtime::RuntimeCall @@ -152,13 +160,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, @@ -166,17 +170,18 @@ pub fn make_complex_relayer_delivery_proofs< ) -> ( HeaderOf, GrandpaJustification>, - FromBridgedChainMessagesProof>, + FromBridgedChainMessagesProof, LaneId>, ) where BridgedChain: ChainWithGrandpa, ThisChainWithMessages: ChainWithMessages, + LaneId: Copy + Encode, { // prepare message let message_payload = prepare_inbound_xcm(xcm_message, message_destination); // prepare storage proof containing message let (state_root, storage_proof) = - prepare_messages_storage_proof::( + prepare_messages_storage_proof::( lane_id, message_nonce..=message_nonce, None, @@ -210,6 +215,7 @@ pub fn make_complex_relayer_confirmation_proofs< BridgedChain, ThisChainWithMessages, InnerXcmRuntimeCall, + LaneId, >( lane_id: LaneId, header_number: BlockNumberOf, @@ -218,17 +224,19 @@ pub fn make_complex_relayer_confirmation_proofs< ) -> ( HeaderOf, GrandpaJustification>, - FromBridgedChainMessagesDeliveryProof>, + FromBridgedChainMessagesDeliveryProof, LaneId>, ) where BridgedChain: ChainWithGrandpa, ThisChainWithMessages: ChainWithMessages, + LaneId: Copy + Encode, { // prepare storage proof containing message delivery proof let (state_root, storage_proof) = - prepare_message_delivery_storage_proof::( + prepare_message_delivery_storage_proof::( lane_id, InboundLaneData { + state: LaneState::Opened, relayers: vec![ UnrewardedRelayer { relayer: relayer_id_at_this_chain, 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 897fe0d0b0f1..a6659b8241df 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 @@ -20,17 +20,17 @@ use super::{from_grandpa_chain::make_complex_bridged_grandpa_header_proof, prepa use bp_messages::{ source_chain::FromBridgedChainMessagesDeliveryProof, - target_chain::FromBridgedChainMessagesProof, ChainWithMessages, LaneId, + target_chain::FromBridgedChainMessagesProof, ChainWithMessages, LaneState, UnrewardedRelayersState, Weight, }; +use bp_parachains::{RelayBlockHash, RelayBlockNumber}; use bp_runtime::{ AccountIdOf, BlockNumberOf, Chain, HeaderOf, Parachain, UnverifiedStorageProofParams, }; use bp_test_utils::prepare_parachain_heads_proof; -use bridge_runtime_common::messages_xcm_extension::XcmAsPlainPayload; +use bp_xcm_bridge_hub::XcmAsPlainPayload; use codec::Encode; use pallet_bridge_grandpa::BridgedHeader; -use pallet_bridge_parachains::{RelayBlockHash, RelayBlockNumber}; use sp_runtime::traits::Header as HeaderT; use xcm::latest::prelude::*; @@ -43,7 +43,7 @@ use pallet_bridge_messages::{ encode_all_messages, encode_lane_data, prepare_message_delivery_storage_proof, prepare_messages_storage_proof, }, - BridgedChainOf, + BridgedChainOf, LaneIdOf, }; use sp_runtime::SaturatedConversion; @@ -53,7 +53,7 @@ pub fn make_complex_relayer_delivery_batch( grandpa_justification: GrandpaJustification>, parachain_heads: Vec<(ParaId, ParaHash)>, para_heads_proof: ParaHeadsProof, - message_proof: FromBridgedChainMessagesProof, + message_proof: FromBridgedChainMessagesProof>, relayer_id_at_bridged_chain: InboundRelayerId, ) -> pallet_utility::Call where @@ -106,7 +106,7 @@ pub fn make_complex_relayer_confirmation_batch( grandpa_justification: GrandpaJustification>, parachain_heads: Vec<(ParaId, ParaHash)>, para_heads_proof: ParaHeadsProof, - message_delivery_proof: FromBridgedChainMessagesDeliveryProof, + message_delivery_proof: FromBridgedChainMessagesDeliveryProof>, relayers_state: UnrewardedRelayersState, ) -> pallet_utility::Call where @@ -154,7 +154,7 @@ where /// Prepare a call with message proof. pub fn make_standalone_relayer_delivery_call( - message_proof: FromBridgedChainMessagesProof, + message_proof: FromBridgedChainMessagesProof>, relayer_id_at_bridged_chain: InboundRelayerId, ) -> Runtime::RuntimeCall where @@ -174,7 +174,7 @@ where /// Prepare a call with message delivery proof. pub fn make_standalone_relayer_confirmation_call( - message_delivery_proof: FromBridgedChainMessagesDeliveryProof, + message_delivery_proof: FromBridgedChainMessagesDeliveryProof>, relayers_state: UnrewardedRelayersState, ) -> Runtime::RuntimeCall where @@ -195,10 +195,10 @@ pub fn make_complex_relayer_delivery_proofs< BridgedRelayChain, BridgedParachain, ThisChainWithMessages, - InnerXcmRuntimeCall, + LaneId, >( lane_id: LaneId, - xcm_message: Xcm, + xcm_message: Xcm<()>, message_nonce: MessageNonce, message_destination: Junctions, para_header_number: u32, @@ -211,19 +211,20 @@ pub fn make_complex_relayer_delivery_proofs< ParaHead, Vec<(ParaId, ParaHash)>, ParaHeadsProof, - FromBridgedChainMessagesProof, + FromBridgedChainMessagesProof, ) where BridgedRelayChain: bp_runtime::Chain + ChainWithGrandpa, BridgedParachain: bp_runtime::Chain + Parachain, ThisChainWithMessages: ChainWithMessages, + LaneId: Copy + Encode, { // prepare message let message_payload = prepare_inbound_xcm(xcm_message, message_destination); // prepare para storage proof containing message let (para_state_root, para_storage_proof) = - prepare_messages_storage_proof::( + prepare_messages_storage_proof::( lane_id, message_nonce..=message_nonce, None, @@ -267,7 +268,7 @@ pub fn make_complex_relayer_confirmation_proofs< BridgedRelayChain, BridgedParachain, ThisChainWithMessages, - InnerXcmRuntimeCall, + LaneId, >( lane_id: LaneId, para_header_number: u32, @@ -281,19 +282,21 @@ pub fn make_complex_relayer_confirmation_proofs< ParaHead, Vec<(ParaId, ParaHash)>, ParaHeadsProof, - FromBridgedChainMessagesDeliveryProof, + FromBridgedChainMessagesDeliveryProof, ) where BridgedRelayChain: bp_runtime::Chain + ChainWithGrandpa, BridgedParachain: bp_runtime::Chain + Parachain, ThisChainWithMessages: ChainWithMessages, + LaneId: Copy + Encode, { // prepare para storage proof containing message delivery proof let (para_state_root, para_storage_proof) = - prepare_message_delivery_storage_proof::( + prepare_message_delivery_storage_proof::( lane_id, InboundLaneData { + state: LaneState::Opened, relayers: vec![ UnrewardedRelayer { relayer: relayer_id_at_this_chain.into(), 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 ee3fc1ed2c41..c34188af5068 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 @@ -21,7 +21,7 @@ pub mod from_parachain; use bp_messages::{ target_chain::{DispatchMessage, DispatchMessageData}, - LaneId, MessageKey, + MessageKey, }; use codec::Encode; use frame_support::traits::Get; @@ -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 @@ -69,11 +65,11 @@ pub(crate) fn dummy_xcm() -> Xcm<()> { vec![Trap(42)].into() } -pub(crate) fn dispatch_message( +pub(crate) fn dispatch_message( lane_id: LaneId, nonce: MessageNonce, payload: Vec, -) -> DispatchMessage> { +) -> DispatchMessage, LaneId> { DispatchMessage { key: MessageKey { lane_id, nonce }, data: DispatchMessageData { payload: Ok(payload) }, diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml index 43fc9083937c..e03fc934ceaf 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/Cargo.toml @@ -14,6 +14,7 @@ codec = { features = ["derive", "max-encoded-len"], workspace = true } hex-literal = { workspace = true, default-features = true } log = { workspace = true } scale-info = { features = ["derive"], workspace = true } +serde_json = { features = ["alloc"], workspace = true } # Substrate frame-benchmarking = { optional = true, workspace = true } @@ -49,11 +50,13 @@ sp-arithmetic = { workspace = true } sp-block-builder = { workspace = true } sp-consensus-aura = { workspace = true } sp-core = { workspace = true } +sp-keyring = { workspace = true } sp-genesis-builder = { workspace = true } 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 } @@ -121,6 +124,7 @@ runtime-benchmarks = [ "pallet-scheduler/runtime-benchmarks", "pallet-state-trie-migration/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", @@ -218,6 +222,7 @@ std = [ "polkadot-parachain-primitives/std", "polkadot-runtime-common/std", "scale-info/std", + "serde_json/std", "sp-api/std", "sp-arithmetic/std", "sp-block-builder/std", @@ -225,9 +230,11 @@ std = [ "sp-core/std", "sp-genesis-builder/std", "sp-inherents/std", + "sp-keyring/std", "sp-offchain/std", "sp-runtime/std", "sp-session/std", + "sp-std/std", "sp-storage/std", "sp-transaction-pool/std", "sp-version/std", @@ -243,4 +250,4 @@ std = [ # A feature that should be enabled when the runtime should be built for on-chain # deployment. This will disable stuff that shouldn't be part of the on-chain wasm # to make it smaller, like logging for example. -on-chain-release-build = ["sp-api/disable-logging"] +on-chain-release-build = [] diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/genesis_config_presets.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/genesis_config_presets.rs new file mode 100644 index 000000000000..aec8e96cedc0 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/genesis_config_presets.rs @@ -0,0 +1,108 @@ +// 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. + +//! # Bridge Hub Westend Runtime genesis config presets + +use crate::*; +use alloc::{vec, vec::Vec}; +use cumulus_primitives_core::ParaId; +use parachains_common::{AccountId, AuraId}; +use sp_genesis_builder::PresetId; +use sp_keyring::Sr25519Keyring; +use testnet_parachains_constants::westend::xcm_version::SAFE_XCM_VERSION; + +const COLLECTIVES_WESTEND_ED: Balance = ExistentialDeposit::get(); + +fn collectives_westend_genesis( + invulnerables: Vec<(AccountId, AuraId)>, + endowed_accounts: Vec, + id: ParaId, +) -> serde_json::Value { + let config = RuntimeGenesisConfig { + balances: BalancesConfig { + balances: endowed_accounts + .iter() + .cloned() + .map(|k| (k, COLLECTIVES_WESTEND_ED * 4096)) + .collect::>(), + }, + parachain_info: ParachainInfoConfig { parachain_id: id, ..Default::default() }, + collator_selection: CollatorSelectionConfig { + invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), + candidacy_bond: COLLECTIVES_WESTEND_ED * 16, + ..Default::default() + }, + session: SessionConfig { + keys: invulnerables + .into_iter() + .map(|(acc, aura)| { + ( + acc.clone(), // account id + acc, // validator id + SessionKeys { aura }, // session keys + ) + }) + .collect(), + ..Default::default() + }, + polkadot_xcm: PolkadotXcmConfig { + safe_xcm_version: Some(SAFE_XCM_VERSION), + ..Default::default() + }, + ..Default::default() + }; + + serde_json::to_value(config).expect("Could not build genesis config.") +} + +/// Provides the JSON representation of predefined genesis config for given `id`. +pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option> { + let patch = match id.try_into() { + Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) => collectives_westend_genesis( + // initial collators. + vec![ + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), + ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), + 1001.into(), + ), + Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => collectives_westend_genesis( + // initial collators. + vec![(Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into())], + vec![ + Sr25519Keyring::Alice.to_account_id(), + Sr25519Keyring::Bob.to_account_id(), + Sr25519Keyring::AliceStash.to_account_id(), + Sr25519Keyring::BobStash.to_account_id(), + ], + 1001.into(), + ), + _ => return None, + }; + Some( + serde_json::to_string(&patch) + .expect("serialization to json is expected to work. qed.") + .into_bytes(), + ) +} + +/// List of supported presets. +pub fn preset_names() -> Vec { + vec![ + PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET), + PresetId::from(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET), + ] +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs index d843d6f6f776..8cb2e42cb31b 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/lib.rs @@ -37,6 +37,7 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); pub mod ambassador; +mod genesis_config_presets; pub mod impls; mod weights; pub mod xcm_config; @@ -66,7 +67,7 @@ use sp_version::NativeVersion; use sp_version::RuntimeVersion; use codec::{Decode, Encode, MaxEncodedLen}; -use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +use cumulus_primitives_core::{AggregateMessageOrigin, ClaimQueueOffset, CoreSelector, ParaId}; use frame_support::{ construct_runtime, derive_impl, dispatch::DispatchClass, @@ -125,11 +126,11 @@ 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_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, - state_version: 1, + system_version: 1, }; /// The version information used to identify this runtime when compiled natively. @@ -184,6 +185,7 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = frame_support::traits::ConstU32<16>; @@ -222,6 +224,7 @@ impl pallet_balances::Config for Runtime { type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxFreezes = ConstU32<0>; + type DoneSlashHandler = (); } parameter_types! { @@ -237,6 +240,7 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; type OperationalFeeMultiplier = ConstU8<5>; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -397,6 +401,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type ReservedXcmpWeight = ReservedXcmpWeight; type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; type ConsensusHook = ConsensusHook; + type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector; } type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< @@ -552,6 +557,9 @@ impl pallet_collective::Config for Runtime { type SetMembersOrigin = EnsureRoot; type WeightInfo = weights::pallet_collective::WeightInfo; type MaxProposalWeight = MaxProposalWeight; + type DisapproveOrigin = EnsureRoot; + type KillOrigin = EnsureRoot; + type Consideration = (); } pub const MAX_FELLOWS: u32 = ALLIANCE_MAX_MEMBERS; @@ -724,8 +732,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -737,7 +745,7 @@ pub type SignedExtra = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// All migrations executed on runtime upgrade as a nested tuple of types implementing /// `OnRuntimeUpgrade`. Included migrations must be idempotent. type Migrations = ( @@ -768,6 +776,7 @@ pub type Executive = frame_executive::Executive< mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] @@ -775,6 +784,7 @@ mod benches { [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] + [pallet_transaction_payment, TransactionPayment] [pallet_collator_selection, CollatorSelection] [cumulus_pallet_parachain_system, ParachainSystem] [cumulus_pallet_xcmp_queue, XcmpQueue] @@ -1004,6 +1014,12 @@ impl_runtime_apis! { } } + impl cumulus_primitives_core::GetCoreSelectorApi for Runtime { + fn core_selector() -> (CoreSelector, ClaimQueueOffset) { + ParachainSystem::core_selector() + } + } + #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { @@ -1032,6 +1048,7 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; @@ -1049,6 +1066,7 @@ impl_runtime_apis! { use sp_storage::TrackedStorageKey; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -1146,11 +1164,20 @@ impl_runtime_apis! { } fn get_preset(id: &Option) -> Option> { - get_preset::(id, |_| None) + get_preset::(id, &genesis_config_presets::get_preset) } fn preset_names() -> Vec { - vec![] + genesis_config_presets::preset_names() + } + } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) } } } diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/block_weights.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/block_weights.rs index e7fdb2aae2a0..41e30725e753 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/block_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/extrinsic_weights.rs index 1a4adb968bb7..3bd48f061bba 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/extrinsic_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..f32f27303135 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/ +// --chain=collectives-westend-dev + +#![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 `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_genesis() -> Weight { + // Proof Size summary in bytes: + // Measured: `54` + // Estimated: `3509` + // Minimum execution time: 3_497_000 picoseconds. + Weight::from_parts(5_961_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_mortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_240_000 picoseconds. + Weight::from_parts(8_175_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_immortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_240_000 picoseconds. + Weight::from_parts(8_175_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 671_000 picoseconds. + Weight::from_parts(3_005_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_426_000 picoseconds. + Weight::from_parts(6_131_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 501_000 picoseconds. + Weight::from_parts(2_715_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 491_000 picoseconds. + Weight::from_parts(2_635_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1533` + // Minimum execution time: 3_958_000 picoseconds. + Weight::from_parts(6_753_000, 0) + .saturating_add(Weight::from_parts(0, 1533)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs index a9a298e547ed..00b3bd92d5ef 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/mod.rs @@ -18,6 +18,7 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_alliance; pub mod pallet_asset_rate; pub mod pallet_balances; @@ -39,6 +40,7 @@ pub mod pallet_salary_fellowship_salary; pub mod pallet_scheduler; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_treasury; pub mod pallet_utility; pub mod pallet_xcm; diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_collective.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_collective.rs index 9133baa6120c..d456f5b8c460 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_collective.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_collective.rs @@ -1,42 +1,41 @@ // 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_collective` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-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-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-polkadot-dev")`, DB CACHE: 1024 +//! HOSTNAME: `runner-svzsllib-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-westend-dev")`, DB CACHE: 1024 // Executed Command: -// ./target/production/polkadot-parachain +// target/production/polkadot-parachain // benchmark // pallet -// --chain=collectives-polkadot-dev -// --wasm-execution=compiled -// --pallet=pallet_collective -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --extrinsic=* // --steps=50 // --repeat=20 -// --json -// --header=./file_header.txt -// --output=./parachains/runtimes/collectives/collectives-polkadot/src/weights/ +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json +// --pallet=pallet_collective +// --chain=collectives-westend-dev +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -63,14 +62,14 @@ impl pallet_collective::WeightInfo for WeightInfo { fn set_members(m: u32, _n: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0 + m * (3232 ±0) + p * (3190 ±0)` - // Estimated: `15691 + m * (1967 ±23) + p * (4332 ±23)` - // Minimum execution time: 16_410_000 picoseconds. - Weight::from_parts(16_816_000, 0) - .saturating_add(Weight::from_parts(0, 15691)) - // Standard Error: 59_812 - .saturating_add(Weight::from_parts(4_516_537, 0).saturating_mul(m.into())) - // Standard Error: 59_812 - .saturating_add(Weight::from_parts(7_992_168, 0).saturating_mul(p.into())) + // Estimated: `15728 + m * (1967 ±23) + p * (4332 ±23)` + // Minimum execution time: 16_539_000 picoseconds. + Weight::from_parts(16_884_000, 0) + .saturating_add(Weight::from_parts(0, 15728)) + // Standard Error: 65_205 + .saturating_add(Weight::from_parts(4_926_489, 0).saturating_mul(m.into())) + // Standard Error: 65_205 + .saturating_add(Weight::from_parts(9_044_204, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes(2)) @@ -84,15 +83,15 @@ impl pallet_collective::WeightInfo for WeightInfo { /// The range of component `m` is `[1, 100]`. fn execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32 + m * (32 ±0)` - // Estimated: `1518 + m * (32 ±0)` - // Minimum execution time: 14_418_000 picoseconds. - Weight::from_parts(13_588_617, 0) - .saturating_add(Weight::from_parts(0, 1518)) - // Standard Error: 21 - .saturating_add(Weight::from_parts(1_711, 0).saturating_mul(b.into())) - // Standard Error: 223 - .saturating_add(Weight::from_parts(13_836, 0).saturating_mul(m.into())) + // Measured: `69 + m * (32 ±0)` + // Estimated: `1555 + m * (32 ±0)` + // Minimum execution time: 16_024_000 picoseconds. + Weight::from_parts(15_295_443, 0) + .saturating_add(Weight::from_parts(0, 1555)) + // Standard Error: 22 + .saturating_add(Weight::from_parts(1_501, 0).saturating_mul(b.into())) + // Standard Error: 229 + .saturating_add(Weight::from_parts(12_430, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } @@ -104,15 +103,15 @@ impl pallet_collective::WeightInfo for WeightInfo { /// The range of component `m` is `[1, 100]`. fn propose_execute(b: u32, m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `32 + m * (32 ±0)` - // Estimated: `3498 + m * (32 ±0)` - // Minimum execution time: 17_174_000 picoseconds. - Weight::from_parts(16_192_764, 0) - .saturating_add(Weight::from_parts(0, 3498)) - // Standard Error: 27 - .saturating_add(Weight::from_parts(1_672, 0).saturating_mul(b.into())) - // Standard Error: 280 - .saturating_add(Weight::from_parts(24_343, 0).saturating_mul(m.into())) + // Measured: `69 + m * (32 ±0)` + // Estimated: `3535 + m * (32 ±0)` + // Minimum execution time: 18_277_000 picoseconds. + Weight::from_parts(17_322_061, 0) + .saturating_add(Weight::from_parts(0, 3535)) + // Standard Error: 29 + .saturating_add(Weight::from_parts(1_725, 0).saturating_mul(b.into())) + // Standard Error: 309 + .saturating_add(Weight::from_parts(25_640, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(m.into())) } @@ -131,17 +130,17 @@ impl pallet_collective::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 100]`. fn propose_proposed(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `322 + m * (32 ±0) + p * (36 ±0)` - // Estimated: `3714 + m * (33 ±0) + p * (36 ±0)` - // Minimum execution time: 23_970_000 picoseconds. - Weight::from_parts(23_004_052, 0) - .saturating_add(Weight::from_parts(0, 3714)) - // Standard Error: 123 - .saturating_add(Weight::from_parts(2_728, 0).saturating_mul(b.into())) - // Standard Error: 1_291 - .saturating_add(Weight::from_parts(32_731, 0).saturating_mul(m.into())) - // Standard Error: 1_275 - .saturating_add(Weight::from_parts(199_537, 0).saturating_mul(p.into())) + // Measured: `359 + m * (32 ±0) + p * (36 ±0)` + // Estimated: `3751 + m * (33 ±0) + p * (36 ±0)` + // Minimum execution time: 23_915_000 picoseconds. + Weight::from_parts(22_895_005, 0) + .saturating_add(Weight::from_parts(0, 3751)) + // Standard Error: 116 + .saturating_add(Weight::from_parts(4_047, 0).saturating_mul(b.into())) + // Standard Error: 1_211 + .saturating_add(Weight::from_parts(37_038, 0).saturating_mul(m.into())) + // Standard Error: 1_196 + .saturating_add(Weight::from_parts(203_435, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(Weight::from_parts(0, 33).saturating_mul(m.into())) @@ -154,13 +153,13 @@ impl pallet_collective::WeightInfo for WeightInfo { /// The range of component `m` is `[5, 100]`. fn vote(m: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `771 + m * (64 ±0)` - // Estimated: `4235 + m * (64 ±0)` - // Minimum execution time: 25_843_000 picoseconds. - Weight::from_parts(26_092_578, 0) - .saturating_add(Weight::from_parts(0, 4235)) - // Standard Error: 1_785 - .saturating_add(Weight::from_parts(67_298, 0).saturating_mul(m.into())) + // Measured: `808 + m * (64 ±0)` + // Estimated: `4272 + m * (64 ±0)` + // Minimum execution time: 28_571_000 picoseconds. + Weight::from_parts(29_711_839, 0) + .saturating_add(Weight::from_parts(0, 4272)) + // Standard Error: 825 + .saturating_add(Weight::from_parts(39_661, 0).saturating_mul(m.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(Weight::from_parts(0, 64).saturating_mul(m.into())) @@ -177,15 +176,15 @@ impl pallet_collective::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 100]`. fn close_early_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `360 + m * (64 ±0) + p * (36 ±0)` - // Estimated: `3805 + m * (65 ±0) + p * (36 ±0)` - // Minimum execution time: 27_543_000 picoseconds. - Weight::from_parts(26_505_473, 0) - .saturating_add(Weight::from_parts(0, 3805)) - // Standard Error: 1_054 - .saturating_add(Weight::from_parts(35_295, 0).saturating_mul(m.into())) - // Standard Error: 1_028 - .saturating_add(Weight::from_parts(190_508, 0).saturating_mul(p.into())) + // Measured: `397 + m * (64 ±0) + p * (36 ±0)` + // Estimated: `3842 + m * (65 ±0) + p * (36 ±0)` + // Minimum execution time: 27_742_000 picoseconds. + Weight::from_parts(28_014_736, 0) + .saturating_add(Weight::from_parts(0, 3842)) + // Standard Error: 1_221 + .saturating_add(Weight::from_parts(35_335, 0).saturating_mul(m.into())) + // Standard Error: 1_191 + .saturating_add(Weight::from_parts(193_513, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(Weight::from_parts(0, 65).saturating_mul(m.into())) @@ -204,17 +203,17 @@ impl pallet_collective::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 100]`. fn close_early_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `662 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `3979 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 40_375_000 picoseconds. - Weight::from_parts(34_081_294, 0) - .saturating_add(Weight::from_parts(0, 3979)) - // Standard Error: 196 - .saturating_add(Weight::from_parts(3_796, 0).saturating_mul(b.into())) - // Standard Error: 2_072 - .saturating_add(Weight::from_parts(50_954, 0).saturating_mul(m.into())) - // Standard Error: 2_020 - .saturating_add(Weight::from_parts(246_000, 0).saturating_mul(p.into())) + // Measured: `699 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `4016 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 38_274_000 picoseconds. + Weight::from_parts(37_886_500, 0) + .saturating_add(Weight::from_parts(0, 4016)) + // Standard Error: 165 + .saturating_add(Weight::from_parts(3_242, 0).saturating_mul(b.into())) + // Standard Error: 1_753 + .saturating_add(Weight::from_parts(33_851, 0).saturating_mul(m.into())) + // Standard Error: 1_709 + .saturating_add(Weight::from_parts(229_245, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) @@ -235,15 +234,15 @@ impl pallet_collective::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 100]`. fn close_disapproved(m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `458 + m * (48 ±0) + p * (36 ±0)` - // Estimated: `3898 + m * (49 ±0) + p * (36 ±0)` - // Minimum execution time: 28_793_000 picoseconds. - Weight::from_parts(29_656_832, 0) - .saturating_add(Weight::from_parts(0, 3898)) - // Standard Error: 1_214 - .saturating_add(Weight::from_parts(22_148, 0).saturating_mul(m.into())) - // Standard Error: 1_184 - .saturating_add(Weight::from_parts(189_860, 0).saturating_mul(p.into())) + // Measured: `495 + m * (48 ±0) + p * (36 ±0)` + // Estimated: `3935 + m * (49 ±0) + p * (36 ±0)` + // Minimum execution time: 29_178_000 picoseconds. + Weight::from_parts(28_752_686, 0) + .saturating_add(Weight::from_parts(0, 3935)) + // Standard Error: 1_230 + .saturating_add(Weight::from_parts(42_254, 0).saturating_mul(m.into())) + // Standard Error: 1_200 + .saturating_add(Weight::from_parts(210_610, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(Weight::from_parts(0, 49).saturating_mul(m.into())) @@ -264,17 +263,17 @@ impl pallet_collective::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 100]`. fn close_approved(b: u32, m: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `682 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` - // Estimated: `3999 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` - // Minimum execution time: 40_887_000 picoseconds. - Weight::from_parts(39_529_567, 0) - .saturating_add(Weight::from_parts(0, 3999)) - // Standard Error: 191 - .saturating_add(Weight::from_parts(2_802, 0).saturating_mul(b.into())) - // Standard Error: 2_021 - .saturating_add(Weight::from_parts(35_956, 0).saturating_mul(m.into())) - // Standard Error: 1_970 - .saturating_add(Weight::from_parts(235_154, 0).saturating_mul(p.into())) + // Measured: `719 + b * (1 ±0) + m * (64 ±0) + p * (40 ±0)` + // Estimated: `4036 + b * (1 ±0) + m * (66 ±0) + p * (40 ±0)` + // Minimum execution time: 40_296_000 picoseconds. + Weight::from_parts(41_629_338, 0) + .saturating_add(Weight::from_parts(0, 4036)) + // Standard Error: 162 + .saturating_add(Weight::from_parts(2_608, 0).saturating_mul(b.into())) + // Standard Error: 1_717 + .saturating_add(Weight::from_parts(29_637, 0).saturating_mul(m.into())) + // Standard Error: 1_674 + .saturating_add(Weight::from_parts(230_371, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(b.into())) @@ -290,15 +289,54 @@ impl pallet_collective::WeightInfo for WeightInfo { /// The range of component `p` is `[1, 100]`. fn disapprove_proposal(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `189 + p * (32 ±0)` - // Estimated: `1674 + p * (32 ±0)` - // Minimum execution time: 14_040_000 picoseconds. - Weight::from_parts(15_075_964, 0) - .saturating_add(Weight::from_parts(0, 1674)) - // Standard Error: 854 - .saturating_add(Weight::from_parts(159_597, 0).saturating_mul(p.into())) + // Measured: `226 + p * (32 ±0)` + // Estimated: `1711 + p * (32 ±0)` + // Minimum execution time: 15_385_000 picoseconds. + Weight::from_parts(17_009_286, 0) + .saturating_add(Weight::from_parts(0, 1711)) + // Standard Error: 1_192 + .saturating_add(Weight::from_parts(170_070, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(Weight::from_parts(0, 32).saturating_mul(p.into())) } + /// Storage: `AllianceMotion::ProposalOf` (r:1 w:1) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::CostOf` (r:1 w:0) + /// Proof: `AllianceMotion::CostOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Proposals` (r:1 w:1) + /// Proof: `AllianceMotion::Proposals` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::Voting` (r:0 w:1) + /// Proof: `AllianceMotion::Voting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `d` is `[0, 1]`. + /// The range of component `p` is `[1, 100]`. + fn kill(d: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1497 + p * (36 ±0)` + // Estimated: `4896 + d * (123 ±6) + p * (37 ±0)` + // Minimum execution time: 22_455_000 picoseconds. + Weight::from_parts(24_273_426, 0) + .saturating_add(Weight::from_parts(0, 4896)) + // Standard Error: 82_114 + .saturating_add(Weight::from_parts(996_567, 0).saturating_mul(d.into())) + // Standard Error: 1_271 + .saturating_add(Weight::from_parts(213_968, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(Weight::from_parts(0, 123).saturating_mul(d.into())) + .saturating_add(Weight::from_parts(0, 37).saturating_mul(p.into())) + } + /// Storage: `AllianceMotion::ProposalOf` (r:1 w:0) + /// Proof: `AllianceMotion::ProposalOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `AllianceMotion::CostOf` (r:1 w:0) + /// Proof: `AllianceMotion::CostOf` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn release_proposal_cost() -> Weight { + // Proof Size summary in bytes: + // Measured: `911` + // Estimated: `4376` + // Minimum execution time: 18_273_000 picoseconds. + Weight::from_parts(19_196_000, 0) + .saturating_add(Weight::from_parts(0, 4376)) + .saturating_add(T::DbWeight::get().reads(2)) + } } diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..5d077b89d564 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("collectives-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_transaction_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/ +// --chain=collectives-westend-dev + +#![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_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn charge_transaction_payment() -> Weight { + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `3593` + // Minimum execution time: 39_815_000 picoseconds. + Weight::from_parts(46_067_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/paritydb_weights.rs index 25679703831a..e0b1985c659c 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/paritydb_weights.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/paritydb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/rocksdb_weights.rs index 3dd817aa6f13..c6e91b2fcffb 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/rocksdb_weights.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/weights/rocksdb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 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 c68f230a16dc..f8e03303c32e 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/src/xcm_config.rs @@ -37,17 +37,18 @@ use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, - DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, - FrameTransactionalProcessor, FungibleAdapter, IsConcrete, LocatableAssetId, - OriginToPluralityVoice, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, - SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, - XcmFeeToAccount, + DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, + EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, + HashedDescription, IsConcrete, LocatableAssetId, OriginToPluralityVoice, ParentAsSuperuser, + ParentIsPreset, RelayChainAsNative, 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(); @@ -80,6 +81,8 @@ pub type LocationToAccountId = ( SiblingParachainConvertsVia, // Straight up local `AccountId32` origins just alias directly to `AccountId`. AccountId32Aliases, + // Foreign locations alias into accounts according to a hash of their standard description. + HashedDescription>, ); /// Means for transacting the native currency on this chain.#[allow(deprecated)] @@ -139,6 +142,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 +183,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 +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/collectives/collectives-westend/tests/tests.rs b/cumulus/parachains/runtimes/collectives/collectives-westend/tests/tests.rs new file mode 100644 index 000000000000..7add10559d84 --- /dev/null +++ b/cumulus/parachains/runtimes/collectives/collectives-westend/tests/tests.rs @@ -0,0 +1,134 @@ +// 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 collectives_westend_runtime::xcm_config::LocationToAccountId; +use parachains_common::AccountId; +use sp_core::crypto::Ss58Codec; +use xcm::latest::prelude::*; +use xcm_runtime_apis::conversions::LocationToAccountHelper; + +const ALICE: [u8; 32] = [1u8; 32]; + +#[test] +fn location_conversion_works() { + // the purpose of hardcoded values is to catch an unintended location conversion logic change. + struct TestCase { + description: &'static str, + location: Location, + expected_account_id_str: &'static str, + } + + let test_cases = vec![ + // DescribeTerminus + TestCase { + description: "DescribeTerminus Parent", + location: Location::new(1, Here), + expected_account_id_str: "5Dt6dpkWPwLaH4BBCKJwjiWrFVAGyYk3tLUabvyn4v7KtESG", + }, + TestCase { + description: "DescribeTerminus Sibling", + location: Location::new(1, [Parachain(1111)]), + expected_account_id_str: "5Eg2fnssmmJnF3z1iZ1NouAuzciDaaDQH7qURAy3w15jULDk", + }, + // DescribePalletTerminal + TestCase { + description: "DescribePalletTerminal Parent", + location: Location::new(1, [PalletInstance(50)]), + expected_account_id_str: "5CnwemvaAXkWFVwibiCvf2EjqwiqBi29S5cLLydZLEaEw6jZ", + }, + TestCase { + description: "DescribePalletTerminal Sibling", + location: Location::new(1, [Parachain(1111), PalletInstance(50)]), + expected_account_id_str: "5GFBgPjpEQPdaxEnFirUoa51u5erVx84twYxJVuBRAT2UP2g", + }, + // DescribeAccountId32Terminal + TestCase { + description: "DescribeAccountId32Terminal Parent", + location: Location::new( + 1, + [Junction::AccountId32 { network: None, id: AccountId::from(ALICE).into() }], + ), + expected_account_id_str: "5DN5SGsuUG7PAqFL47J9meViwdnk9AdeSWKFkcHC45hEzVz4", + }, + TestCase { + description: "DescribeAccountId32Terminal Sibling", + location: Location::new( + 1, + [ + Parachain(1111), + Junction::AccountId32 { network: None, id: AccountId::from(ALICE).into() }, + ], + ), + expected_account_id_str: "5DGRXLYwWGce7wvm14vX1Ms4Vf118FSWQbJkyQigY2pfm6bg", + }, + // DescribeAccountKey20Terminal + TestCase { + description: "DescribeAccountKey20Terminal Parent", + location: Location::new(1, [AccountKey20 { network: None, key: [0u8; 20] }]), + expected_account_id_str: "5F5Ec11567pa919wJkX6VHtv2ZXS5W698YCW35EdEbrg14cg", + }, + TestCase { + description: "DescribeAccountKey20Terminal Sibling", + location: Location::new( + 1, + [Parachain(1111), AccountKey20 { network: None, key: [0u8; 20] }], + ), + expected_account_id_str: "5CB2FbUds2qvcJNhDiTbRZwiS3trAy6ydFGMSVutmYijpPAg", + }, + // DescribeTreasuryVoiceTerminal + TestCase { + description: "DescribeTreasuryVoiceTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]), + expected_account_id_str: "5CUjnE2vgcUCuhxPwFoQ5r7p1DkhujgvMNDHaF2bLqRp4D5F", + }, + TestCase { + description: "DescribeTreasuryVoiceTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Treasury, part: BodyPart::Voice }], + ), + expected_account_id_str: "5G6TDwaVgbWmhqRUKjBhRRnH4ry9L9cjRymUEmiRsLbSE4gB", + }, + // DescribeBodyTerminal + TestCase { + description: "DescribeBodyTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Unit, part: BodyPart::Voice }]), + expected_account_id_str: "5EBRMTBkDisEXsaN283SRbzx9Xf2PXwUxxFCJohSGo4jYe6B", + }, + TestCase { + description: "DescribeBodyTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Unit, part: BodyPart::Voice }], + ), + expected_account_id_str: "5DBoExvojy8tYnHgLL97phNH975CyT45PWTZEeGoBZfAyRMH", + }, + ]; + + for tc in test_cases { + let expected = + AccountId::from_string(tc.expected_account_id_str).expect("Invalid AccountId string"); + + let got = LocationToAccountHelper::::convert_location( + tc.location.into(), + ) + .unwrap(); + + assert_eq!(got, expected, "{}", tc.description); + } +} diff --git a/cumulus/parachains/runtimes/constants/src/rococo.rs b/cumulus/parachains/runtimes/constants/src/rococo.rs index d10b5e7d3af4..be4b5c9711cc 100644 --- a/cumulus/parachains/runtimes/constants/src/rococo.rs +++ b/cumulus/parachains/runtimes/constants/src/rococo.rs @@ -148,7 +148,7 @@ pub mod time { pub mod snowbridge { use frame_support::parameter_types; - use xcm::opaque::lts::NetworkId; + use xcm::prelude::{Location, NetworkId}; /// The pallet index of the Ethereum inbound queue pallet in the bridge hub runtime. pub const INBOUND_QUEUE_PALLET_INDEX: u8 = 80; @@ -159,5 +159,11 @@ pub mod snowbridge { /// /// pub EthereumNetwork: NetworkId = NetworkId::Ethereum { chain_id: 11155111 }; + pub EthereumLocation: Location = Location::new(2, EthereumNetwork::get()); } } + +pub mod xcm_version { + /// The default XCM version to set in genesis config. + pub const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; +} diff --git a/cumulus/parachains/runtimes/constants/src/westend.rs b/cumulus/parachains/runtimes/constants/src/westend.rs index 607d91e8808d..8c4c0c594359 100644 --- a/cumulus/parachains/runtimes/constants/src/westend.rs +++ b/cumulus/parachains/runtimes/constants/src/westend.rs @@ -168,3 +168,25 @@ 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::prelude::{Location, 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 }; + pub EthereumLocation: Location = Location::new(2, EthereumNetwork::get()); + } +} + +pub mod xcm_version { + /// The default XCM version to set in genesis config. + pub const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; +} diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml index 1fcebb3f16a9..c98ca7ba3e74 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/Cargo.toml @@ -161,6 +161,7 @@ runtime-benchmarks = [ "pallet-multisig/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/runtime-benchmarks", @@ -203,4 +204,4 @@ try-runtime = [ # A feature that should be enabled when the runtime should be built for on-chain # deployment. This will disable stuff that shouldn't be part of the on-chain wasm # to make it smaller, like logging for example. -on-chain-release-build = ["sp-api/disable-logging"] +on-chain-release-build = [] diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs index e8cc9d02fb0e..40801f66a47b 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/contracts.rs @@ -72,7 +72,10 @@ impl Config for Runtime { type MaxDebugBufferLen = ConstU32<{ 2 * 1024 * 1024 }>; type MaxDelegateDependencies = ConstU32<32>; type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent; - type Migrations = (pallet_contracts::migration::v16::Migration,); + #[cfg(not(feature = "runtime-benchmarks"))] + type Migrations = (); + #[cfg(feature = "runtime-benchmarks")] + type Migrations = pallet_contracts::migration::codegen::BenchMigrations; type RuntimeHoldReason = RuntimeHoldReason; type Debug = (); type Environment = (); diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs index 47ce6f3628ec..2fc3fe4f3141 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/lib.rs @@ -27,13 +27,13 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); mod contracts; mod weights; -mod xcm_config; +pub mod xcm_config; extern crate alloc; use alloc::{vec, vec::Vec}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; -use cumulus_primitives_core::AggregateMessageOrigin; +use cumulus_primitives_core::{AggregateMessageOrigin, ClaimQueueOffset, CoreSelector}; use sp_api::impl_runtime_apis; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ @@ -87,8 +87,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -101,7 +101,7 @@ pub type SignedExtra = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -144,11 +144,11 @@ 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_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 7, - state_version: 1, + system_version: 1, }; /// The version information used to identify this runtime when compiled natively. @@ -234,6 +234,7 @@ impl pallet_balances::Config for Runtime { type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxFreezes = ConstU32<0>; + type DoneSlashHandler = (); } parameter_types! { @@ -249,6 +250,7 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; type OperationalFeeMultiplier = ConstU8<5>; + type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight; } parameter_types! { @@ -293,6 +295,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type ReservedXcmpWeight = ReservedXcmpWeight; type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; type ConsensusHook = ConsensusHook; + type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector; } type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< @@ -432,6 +435,7 @@ construct_runtime!( mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] @@ -653,6 +657,12 @@ impl_runtime_apis! { } } + impl cumulus_primitives_core::GetCoreSelectorApi for Runtime { + fn core_selector() -> (CoreSelector, ClaimQueueOffset) { + ParachainSystem::core_selector() + } + } + impl pallet_contracts::ContractsApi for Runtime { fn call( origin: AccountId, @@ -749,6 +759,7 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; @@ -766,6 +777,7 @@ impl_runtime_apis! { use sp_storage::TrackedStorageKey; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); @@ -871,6 +883,15 @@ impl_runtime_apis! { vec![] } } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/block_weights.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/block_weights.rs index e7fdb2aae2a0..41e30725e753 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/block_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/extrinsic_weights.rs index 1a4adb968bb7..3bd48f061bba 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/extrinsic_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/mod.rs index b473d49e20e6..850dae6fbd06 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/mod.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/paritydb_weights.rs index 25679703831a..e0b1985c659c 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/paritydb_weights.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/paritydb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/rocksdb_weights.rs index 3dd817aa6f13..c6e91b2fcffb 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/rocksdb_weights.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/weights/rocksdb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 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 ef5ded1731d0..39fdd30a0498 100644 --- a/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/src/xcm_config.rs @@ -40,12 +40,13 @@ use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, - DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FixedWeightBounds, - FrameTransactionalProcessor, FungibleAdapter, IsConcrete, NativeAsset, ParentAsSuperuser, - ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, + EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, + HashedDescription, IsConcrete, NativeAsset, ParentAsSuperuser, ParentIsPreset, + RelayChainAsNative, SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + XcmFeeManagerFromComponents, }; use xcm_executor::XcmExecutor; @@ -75,6 +76,8 @@ pub type LocationToAccountId = ( SiblingParachainConvertsVia, // Straight up local `AccountId32` origins just alias directly to `AccountId`. AccountId32Aliases, + // Foreign locations alias into accounts according to a hash of their standard description. + HashedDescription>, ); /// Means for transacting the native currency on this chain. @@ -191,7 +194,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/contracts/contracts-rococo/tests/tests.rs b/cumulus/parachains/runtimes/contracts/contracts-rococo/tests/tests.rs new file mode 100644 index 000000000000..02c4b7b3963b --- /dev/null +++ b/cumulus/parachains/runtimes/contracts/contracts-rococo/tests/tests.rs @@ -0,0 +1,134 @@ +// 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 contracts_rococo_runtime::xcm_config::LocationToAccountId; +use parachains_common::AccountId; +use sp_core::crypto::Ss58Codec; +use xcm::latest::prelude::*; +use xcm_runtime_apis::conversions::LocationToAccountHelper; + +const ALICE: [u8; 32] = [1u8; 32]; + +#[test] +fn location_conversion_works() { + // the purpose of hardcoded values is to catch an unintended location conversion logic change. + struct TestCase { + description: &'static str, + location: Location, + expected_account_id_str: &'static str, + } + + let test_cases = vec![ + // DescribeTerminus + TestCase { + description: "DescribeTerminus Parent", + location: Location::new(1, Here), + expected_account_id_str: "5Dt6dpkWPwLaH4BBCKJwjiWrFVAGyYk3tLUabvyn4v7KtESG", + }, + TestCase { + description: "DescribeTerminus Sibling", + location: Location::new(1, [Parachain(1111)]), + expected_account_id_str: "5Eg2fnssmmJnF3z1iZ1NouAuzciDaaDQH7qURAy3w15jULDk", + }, + // DescribePalletTerminal + TestCase { + description: "DescribePalletTerminal Parent", + location: Location::new(1, [PalletInstance(50)]), + expected_account_id_str: "5CnwemvaAXkWFVwibiCvf2EjqwiqBi29S5cLLydZLEaEw6jZ", + }, + TestCase { + description: "DescribePalletTerminal Sibling", + location: Location::new(1, [Parachain(1111), PalletInstance(50)]), + expected_account_id_str: "5GFBgPjpEQPdaxEnFirUoa51u5erVx84twYxJVuBRAT2UP2g", + }, + // DescribeAccountId32Terminal + TestCase { + description: "DescribeAccountId32Terminal Parent", + location: Location::new( + 1, + [Junction::AccountId32 { network: None, id: AccountId::from(ALICE).into() }], + ), + expected_account_id_str: "5DN5SGsuUG7PAqFL47J9meViwdnk9AdeSWKFkcHC45hEzVz4", + }, + TestCase { + description: "DescribeAccountId32Terminal Sibling", + location: Location::new( + 1, + [ + Parachain(1111), + Junction::AccountId32 { network: None, id: AccountId::from(ALICE).into() }, + ], + ), + expected_account_id_str: "5DGRXLYwWGce7wvm14vX1Ms4Vf118FSWQbJkyQigY2pfm6bg", + }, + // DescribeAccountKey20Terminal + TestCase { + description: "DescribeAccountKey20Terminal Parent", + location: Location::new(1, [AccountKey20 { network: None, key: [0u8; 20] }]), + expected_account_id_str: "5F5Ec11567pa919wJkX6VHtv2ZXS5W698YCW35EdEbrg14cg", + }, + TestCase { + description: "DescribeAccountKey20Terminal Sibling", + location: Location::new( + 1, + [Parachain(1111), AccountKey20 { network: None, key: [0u8; 20] }], + ), + expected_account_id_str: "5CB2FbUds2qvcJNhDiTbRZwiS3trAy6ydFGMSVutmYijpPAg", + }, + // DescribeTreasuryVoiceTerminal + TestCase { + description: "DescribeTreasuryVoiceTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]), + expected_account_id_str: "5CUjnE2vgcUCuhxPwFoQ5r7p1DkhujgvMNDHaF2bLqRp4D5F", + }, + TestCase { + description: "DescribeTreasuryVoiceTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Treasury, part: BodyPart::Voice }], + ), + expected_account_id_str: "5G6TDwaVgbWmhqRUKjBhRRnH4ry9L9cjRymUEmiRsLbSE4gB", + }, + // DescribeBodyTerminal + TestCase { + description: "DescribeBodyTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Unit, part: BodyPart::Voice }]), + expected_account_id_str: "5EBRMTBkDisEXsaN283SRbzx9Xf2PXwUxxFCJohSGo4jYe6B", + }, + TestCase { + description: "DescribeBodyTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Unit, part: BodyPart::Voice }], + ), + expected_account_id_str: "5DBoExvojy8tYnHgLL97phNH975CyT45PWTZEeGoBZfAyRMH", + }, + ]; + + for tc in test_cases { + let expected = + AccountId::from_string(tc.expected_account_id_str).expect("Invalid AccountId string"); + + let got = LocationToAccountHelper::::convert_location( + tc.location.into(), + ) + .unwrap(); + + assert_eq!(got, expected, "{}", tc.description); + } +} diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml index 2920bc428d90..a38b7400cfa3 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/Cargo.toml @@ -34,6 +34,7 @@ pallet-balances = { workspace = true } pallet-message-queue = { workspace = true } pallet-broker = { workspace = true } pallet-multisig = { workspace = true } +pallet-proxy = { workspace = true } pallet-session = { workspace = true } pallet-sudo = { workspace = true } pallet-timestamp = { workspace = true } @@ -108,6 +109,7 @@ std = [ "pallet-collator-selection/std", "pallet-message-queue/std", "pallet-multisig/std", + "pallet-proxy/std", "pallet-session/std", "pallet-sudo/std", "pallet-timestamp/std", @@ -158,8 +160,10 @@ runtime-benchmarks = [ "pallet-collator-selection/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", + "pallet-proxy/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", @@ -188,6 +192,7 @@ try-runtime = [ "pallet-collator-selection/try-runtime", "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", + "pallet-proxy/try-runtime", "pallet-session/try-runtime", "pallet-sudo/try-runtime", "pallet-timestamp/try-runtime", @@ -209,4 +214,4 @@ metadata-hash = ["substrate-wasm-builder/metadata-hash"] # A feature that should be enabled when the runtime should be built for on-chain # deployment. This will disable stuff that shouldn't be part of the on-chain wasm # to make it smaller, like logging for example. -on-chain-release-build = ["metadata-hash", "sp-api/disable-logging"] +on-chain-release-build = ["metadata-hash"] diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/coretime.rs index fa0c2644421e..3910a747e9bb 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 { @@ -216,6 +218,36 @@ impl CoretimeInterface for CoretimeAllocator { end_hint: Option>, ) { use crate::coretime::CoretimeProviderCalls::AssignCore; + + // The relay chain currently only allows `assign_core` to be called with a complete mask + // and only ever with increasing `begin`. The assignments must be truncated to avoid + // dropping that core's assignment completely. + + // This shadowing of `assignment` is temporary and can be removed when the relay can accept + // multiple messages to assign a single core. + let assignment = if assignment.len() > 28 { + let mut total_parts = 0u16; + // Account for missing parts with a new `Idle` assignment at the start as + // `assign_core` on the relay assumes this is sorted. We'll add the rest of the + // assignments and sum the parts in one pass, so this is just initialized to 0. + let mut assignment_truncated = vec![(CoreAssignment::Idle, 0)]; + // Truncate to first 27 non-idle assignments. + assignment_truncated.extend( + assignment + .into_iter() + .filter(|(a, _)| *a != CoreAssignment::Idle) + .take(27) + .inspect(|(_, parts)| total_parts += *parts) + .collect::>(), + ); + + // Set the parts of the `Idle` assignment we injected at the start of the vec above. + assignment_truncated[0].1 = 57_600u16.saturating_sub(total_parts); + assignment_truncated + } else { + assignment + }; + let assign_core_call = RelayRuntimePallets::Coretime(AssignCore(core, begin, assignment, end_hint)); @@ -263,6 +295,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 +316,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 9fd0093840d3..f2ccb9c552e3 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/lib.rs @@ -36,14 +36,17 @@ pub mod xcm_config; extern crate alloc; use alloc::{vec, vec::Vec}; +use codec::{Decode, Encode, MaxEncodedLen}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; -use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +use cumulus_primitives_core::{AggregateMessageOrigin, ClaimQueueOffset, CoreSelector, ParaId}; use frame_support::{ construct_runtime, derive_impl, dispatch::DispatchClass, genesis_builder_helper::{build_state, get_preset}, parameter_types, - traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, TransformOrigin}, + traits::{ + ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, InstanceFilter, TransformOrigin, + }, weights::{ConstantMultiplier, Weight, WeightToFee as _}, PalletId, }; @@ -65,9 +68,9 @@ use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; pub use sp_runtime::BuildStorage; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, - traits::Block as BlockT, + traits::{BlakeTwo256, Block as BlockT}, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, DispatchError, MultiAddress, Perbill, + ApplyExtrinsicResult, DispatchError, MultiAddress, Perbill, RuntimeDebug, }; #[cfg(feature = "std")] use sp_version::NativeVersion; @@ -95,8 +98,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The TransactionExtension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -111,7 +114,7 @@ pub type SignedExtra = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -146,11 +149,11 @@ 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_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, - state_version: 1, + system_version: 1, }; /// The version information used to identify this runtime when compiled natively. @@ -205,6 +208,8 @@ impl frame_system::Config for Runtime { type DbWeight = RocksDbWeight; /// Weight information for the extrinsics of this pallet. type SystemWeightInfo = weights::frame_system::WeightInfo; + /// Weight information for the extensions of this pallet. + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; /// Block & extrinsics weights: base values and limits. type BlockWeights = RuntimeBlockWeights; /// The maximum length of a block (in bytes). @@ -246,6 +251,7 @@ impl pallet_balances::Config for Runtime { type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxFreezes = ConstU32<0>; + type DoneSlashHandler = (); } parameter_types! { @@ -261,6 +267,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -281,6 +288,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type ReservedXcmpWeight = ReservedXcmpWeight; type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; type ConsensusHook = ConsensusHook; + type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector; } type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< @@ -438,6 +446,138 @@ impl pallet_multisig::Config for Runtime { type WeightInfo = weights::pallet_multisig::WeightInfo; } +/// The type used to represent the kinds of proxying allowed. +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + RuntimeDebug, + MaxEncodedLen, + scale_info::TypeInfo, +)] +pub enum ProxyType { + /// Fully permissioned proxy. Can execute any call on behalf of _proxied_. + Any, + /// Can execute any call that does not transfer funds or assets. + NonTransfer, + /// Proxy with the ability to reject time-delay proxy announcements. + CancelProxy, + /// Proxy for all Broker pallet calls. + Broker, + /// Proxy for renewing coretime. + CoretimeRenewer, + /// Proxy able to purchase on-demand coretime credits. + OnDemandPurchaser, + /// Collator selection proxy. Can execute calls related to collator selection mechanism. + Collator, +} +impl Default for ProxyType { + fn default() -> Self { + Self::Any + } +} + +impl InstanceFilter for ProxyType { + fn filter(&self, c: &RuntimeCall) -> bool { + match self { + ProxyType::Any => true, + ProxyType::NonTransfer => !matches!( + c, + RuntimeCall::Balances { .. } | + // `purchase`, `renew`, `transfer` and `purchase_credit` are pretty self explanatory. + RuntimeCall::Broker(pallet_broker::Call::purchase { .. }) | + RuntimeCall::Broker(pallet_broker::Call::renew { .. }) | + RuntimeCall::Broker(pallet_broker::Call::transfer { .. }) | + RuntimeCall::Broker(pallet_broker::Call::purchase_credit { .. }) | + // `pool` doesn't transfer, but it defines the account to be paid for contributions + RuntimeCall::Broker(pallet_broker::Call::pool { .. }) | + // `assign` is essentially a transfer of a region NFT + RuntimeCall::Broker(pallet_broker::Call::assign { .. }) + ), + ProxyType::CancelProxy => matches!( + c, + RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), + ProxyType::Broker => { + matches!( + c, + RuntimeCall::Broker { .. } | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ) + }, + ProxyType::CoretimeRenewer => { + matches!( + c, + RuntimeCall::Broker(pallet_broker::Call::renew { .. }) | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ) + }, + ProxyType::OnDemandPurchaser => { + matches!( + c, + RuntimeCall::Broker(pallet_broker::Call::purchase_credit { .. }) | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ) + }, + ProxyType::Collator => matches!( + c, + RuntimeCall::CollatorSelection { .. } | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), + } + } + + fn is_superset(&self, o: &Self) -> bool { + match (self, o) { + (x, y) if x == y => true, + (ProxyType::Any, _) => true, + (_, ProxyType::Any) => false, + (ProxyType::Broker, ProxyType::CoretimeRenewer) => true, + (ProxyType::Broker, ProxyType::OnDemandPurchaser) => true, + (ProxyType::NonTransfer, ProxyType::Collator) => true, + _ => false, + } + } +} + +parameter_types! { + // One storage item; key size 32, value size 8; . + pub const ProxyDepositBase: Balance = deposit(1, 40); + // Additional storage item size of 33 bytes. + pub const ProxyDepositFactor: Balance = deposit(0, 33); + pub const MaxProxies: u16 = 32; + // One storage item; key size 32, value size 16 + pub const AnnouncementDepositBase: Balance = deposit(1, 48); + pub const AnnouncementDepositFactor: Balance = deposit(0, 66); + pub const MaxPending: u16 = 32; +} + +impl pallet_proxy::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type ProxyType = ProxyType; + type ProxyDepositBase = ProxyDepositBase; + type ProxyDepositFactor = ProxyDepositFactor; + type MaxProxies = MaxProxies; + type WeightInfo = weights::pallet_proxy::WeightInfo; + type MaxPending = MaxPending; + type CallHasher = BlakeTwo256; + type AnnouncementDepositBase = AnnouncementDepositBase; + type AnnouncementDepositFactor = AnnouncementDepositFactor; +} + impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; @@ -481,6 +621,7 @@ construct_runtime!( // Handy utilities. Utility: pallet_utility = 40, Multisig: pallet_multisig = 41, + Proxy: pallet_proxy = 42, // The main stage. Broker: pallet_broker = 50, @@ -504,6 +645,7 @@ mod benches { [pallet_xcm, PalletXcmExtrinsicsBenchmark::] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] + [pallet_proxy, Proxy] [pallet_utility, Utility] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] @@ -724,6 +866,12 @@ impl_runtime_apis! { } } + impl cumulus_primitives_core::GetCoreSelectorApi for Runtime { + fn core_selector() -> (CoreSelector, ClaimQueueOffset) { + ParachainSystem::core_selector() + } + } + #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { @@ -832,7 +980,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())), @@ -1003,6 +1151,15 @@ impl_runtime_apis! { vec![] } } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/block_weights.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/block_weights.rs index b2092d875c83..3ff2b3550fbf 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/block_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/extrinsic_weights.rs index 332c3b324bb9..ab951aea5615 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/extrinsic_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..a4d09696a1a1 --- /dev/null +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/frame_system_extensions.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/ +// --chain=coretime-rococo-dev + +#![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 `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_genesis() -> Weight { + // Proof Size summary in bytes: + // Measured: `54` + // Estimated: `3509` + // Minimum execution time: 3_637_000 picoseconds. + Weight::from_parts(6_382_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_mortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_immortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 561_000 picoseconds. + Weight::from_parts(2_705_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_316_000 picoseconds. + Weight::from_parts(5_771_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 511_000 picoseconds. + Weight::from_parts(2_575_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 501_000 picoseconds. + Weight::from_parts(2_595_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1533` + // Minimum execution time: 3_687_000 picoseconds. + Weight::from_parts(6_192_000, 0) + .saturating_add(Weight::from_parts(0, 1533)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/mod.rs index f1050b3ae636..24c4f50e6ab8 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/mod.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 @@ -22,13 +22,16 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_balances; pub mod pallet_broker; pub mod pallet_collator_selection; pub mod pallet_message_queue; pub mod pallet_multisig; +pub mod pallet_proxy; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; pub mod paritydb_weights; 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 83e80e2e91e7..35708f22de20 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/pallet_proxy.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_proxy.rs new file mode 100644 index 000000000000..5f95906f473e --- /dev/null +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_proxy.rs @@ -0,0 +1,226 @@ +// 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 . + +//! Autogenerated weights for `pallet_proxy` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=coretime-rococo-dev +// --wasm-execution=compiled +// --pallet=pallet_proxy +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/coretime/coretime-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_proxy`. +pub struct WeightInfo(PhantomData); +impl pallet_proxy::WeightInfo for WeightInfo { + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 16_417_000 picoseconds. + Weight::from_parts(17_283_443, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 2_409 + .saturating_add(Weight::from_parts(32_123, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn proxy_announced(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `454 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `5698` + // Minimum execution time: 37_572_000 picoseconds. + Weight::from_parts(37_045_756, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 2_896 + .saturating_add(Weight::from_parts(139_561, 0).saturating_mul(a.into())) + // Standard Error: 2_993 + .saturating_add(Weight::from_parts(73_270, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn remove_announcement(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `369 + a * (68 ±0)` + // Estimated: `5698` + // Minimum execution time: 24_066_000 picoseconds. + Weight::from_parts(24_711_403, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 1_626 + .saturating_add(Weight::from_parts(128_391, 0).saturating_mul(a.into())) + // Standard Error: 1_680 + .saturating_add(Weight::from_parts(23_124, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn reject_announcement(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `369 + a * (68 ±0)` + // Estimated: `5698` + // Minimum execution time: 24_162_000 picoseconds. + Weight::from_parts(23_928_058, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 2_072 + .saturating_add(Weight::from_parts(152_299, 0).saturating_mul(a.into())) + // Standard Error: 2_141 + .saturating_add(Weight::from_parts(39_775, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn announce(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `386 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `5698` + // Minimum execution time: 33_858_000 picoseconds. + Weight::from_parts(33_568_059, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 1_816 + .saturating_add(Weight::from_parts(134_400, 0).saturating_mul(a.into())) + // Standard Error: 1_876 + .saturating_add(Weight::from_parts(57_028, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn add_proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 24_947_000 picoseconds. + Weight::from_parts(26_235_199, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_363 + .saturating_add(Weight::from_parts(41_435, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn remove_proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 25_186_000 picoseconds. + Weight::from_parts(26_823_133, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 2_259 + .saturating_add(Weight::from_parts(34_224, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn remove_proxies(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 22_156_000 picoseconds. + Weight::from_parts(23_304_060, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_738 + .saturating_add(Weight::from_parts(39_612, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn create_pure(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `139` + // Estimated: `4706` + // Minimum execution time: 26_914_000 picoseconds. + Weight::from_parts(28_009_062, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_978 + .saturating_add(Weight::from_parts(12_255, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 30]`. + fn kill_pure(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `164 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 23_281_000 picoseconds. + Weight::from_parts(24_392_989, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 2_943 + .saturating_add(Weight::from_parts(30_287, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..29d48abab895 --- /dev/null +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_transaction_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/ +// --chain=coretime-rococo-dev + +#![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_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn charge_transaction_payment() -> Weight { + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `3593` + // Minimum execution time: 33_363_000 picoseconds. + Weight::from_parts(38_793_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/paritydb_weights.rs index 4338d928d807..db09e9de7bdf 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/paritydb_weights.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/paritydb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/rocksdb_weights.rs index 1d115d963fac..855ec356bca9 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/rocksdb_weights.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/weights/rocksdb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.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 73a719805307..c8dbdadf7b15 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 c16b40b8675f..2eae13de2fd4 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/src/xcm_config.rs @@ -41,12 +41,13 @@ use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, - DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, - FungibleAdapter, IsConcrete, NonFungibleAdapter, ParentAsSuperuser, ParentIsPreset, - RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, + EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsConcrete, + NonFungibleAdapter, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount, + SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, + UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + XcmFeeManagerFromComponents, }; use xcm_executor::XcmExecutor; @@ -74,6 +75,8 @@ pub type LocationToAccountId = ( SiblingParachainConvertsVia, // Straight up local `AccountId32` origins just alias directly to `AccountId`. AccountId32Aliases, + // Foreign locations alias into accounts according to a hash of their standard description. + HashedDescription>, ); /// Means for transacting the native currency on this chain. @@ -213,7 +216,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/tests/tests.rs b/cumulus/parachains/runtimes/coretime/coretime-rococo/tests/tests.rs new file mode 100644 index 000000000000..2cabce567b6e --- /dev/null +++ b/cumulus/parachains/runtimes/coretime/coretime-rococo/tests/tests.rs @@ -0,0 +1,134 @@ +// 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 coretime_rococo_runtime::xcm_config::LocationToAccountId; +use parachains_common::AccountId; +use sp_core::crypto::Ss58Codec; +use xcm::latest::prelude::*; +use xcm_runtime_apis::conversions::LocationToAccountHelper; + +const ALICE: [u8; 32] = [1u8; 32]; + +#[test] +fn location_conversion_works() { + // the purpose of hardcoded values is to catch an unintended location conversion logic change. + struct TestCase { + description: &'static str, + location: Location, + expected_account_id_str: &'static str, + } + + let test_cases = vec![ + // DescribeTerminus + TestCase { + description: "DescribeTerminus Parent", + location: Location::new(1, Here), + expected_account_id_str: "5Dt6dpkWPwLaH4BBCKJwjiWrFVAGyYk3tLUabvyn4v7KtESG", + }, + TestCase { + description: "DescribeTerminus Sibling", + location: Location::new(1, [Parachain(1111)]), + expected_account_id_str: "5Eg2fnssmmJnF3z1iZ1NouAuzciDaaDQH7qURAy3w15jULDk", + }, + // DescribePalletTerminal + TestCase { + description: "DescribePalletTerminal Parent", + location: Location::new(1, [PalletInstance(50)]), + expected_account_id_str: "5CnwemvaAXkWFVwibiCvf2EjqwiqBi29S5cLLydZLEaEw6jZ", + }, + TestCase { + description: "DescribePalletTerminal Sibling", + location: Location::new(1, [Parachain(1111), PalletInstance(50)]), + expected_account_id_str: "5GFBgPjpEQPdaxEnFirUoa51u5erVx84twYxJVuBRAT2UP2g", + }, + // DescribeAccountId32Terminal + TestCase { + description: "DescribeAccountId32Terminal Parent", + location: Location::new( + 1, + [Junction::AccountId32 { network: None, id: AccountId::from(ALICE).into() }], + ), + expected_account_id_str: "5DN5SGsuUG7PAqFL47J9meViwdnk9AdeSWKFkcHC45hEzVz4", + }, + TestCase { + description: "DescribeAccountId32Terminal Sibling", + location: Location::new( + 1, + [ + Parachain(1111), + Junction::AccountId32 { network: None, id: AccountId::from(ALICE).into() }, + ], + ), + expected_account_id_str: "5DGRXLYwWGce7wvm14vX1Ms4Vf118FSWQbJkyQigY2pfm6bg", + }, + // DescribeAccountKey20Terminal + TestCase { + description: "DescribeAccountKey20Terminal Parent", + location: Location::new(1, [AccountKey20 { network: None, key: [0u8; 20] }]), + expected_account_id_str: "5F5Ec11567pa919wJkX6VHtv2ZXS5W698YCW35EdEbrg14cg", + }, + TestCase { + description: "DescribeAccountKey20Terminal Sibling", + location: Location::new( + 1, + [Parachain(1111), AccountKey20 { network: None, key: [0u8; 20] }], + ), + expected_account_id_str: "5CB2FbUds2qvcJNhDiTbRZwiS3trAy6ydFGMSVutmYijpPAg", + }, + // DescribeTreasuryVoiceTerminal + TestCase { + description: "DescribeTreasuryVoiceTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]), + expected_account_id_str: "5CUjnE2vgcUCuhxPwFoQ5r7p1DkhujgvMNDHaF2bLqRp4D5F", + }, + TestCase { + description: "DescribeTreasuryVoiceTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Treasury, part: BodyPart::Voice }], + ), + expected_account_id_str: "5G6TDwaVgbWmhqRUKjBhRRnH4ry9L9cjRymUEmiRsLbSE4gB", + }, + // DescribeBodyTerminal + TestCase { + description: "DescribeBodyTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Unit, part: BodyPart::Voice }]), + expected_account_id_str: "5EBRMTBkDisEXsaN283SRbzx9Xf2PXwUxxFCJohSGo4jYe6B", + }, + TestCase { + description: "DescribeBodyTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Unit, part: BodyPart::Voice }], + ), + expected_account_id_str: "5DBoExvojy8tYnHgLL97phNH975CyT45PWTZEeGoBZfAyRMH", + }, + ]; + + for tc in test_cases { + let expected = + AccountId::from_string(tc.expected_account_id_str).expect("Invalid AccountId string"); + + let got = LocationToAccountHelper::::convert_location( + tc.location.into(), + ) + .unwrap(); + + assert_eq!(got, expected, "{}", tc.description); + } +} diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml index 07a4332800d7..149fa5d0b045 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/Cargo.toml @@ -34,6 +34,7 @@ pallet-balances = { workspace = true } pallet-message-queue = { workspace = true } pallet-broker = { workspace = true } pallet-multisig = { workspace = true } +pallet-proxy = { workspace = true } pallet-session = { workspace = true } pallet-timestamp = { workspace = true } pallet-transaction-payment = { workspace = true } @@ -108,6 +109,7 @@ std = [ "pallet-collator-selection/std", "pallet-message-queue/std", "pallet-multisig/std", + "pallet-proxy/std", "pallet-session/std", "pallet-timestamp/std", "pallet-transaction-payment-rpc-runtime-api/std", @@ -157,7 +159,9 @@ runtime-benchmarks = [ "pallet-collator-selection/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", + "pallet-proxy/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", @@ -186,6 +190,7 @@ try-runtime = [ "pallet-collator-selection/try-runtime", "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", + "pallet-proxy/try-runtime", "pallet-session/try-runtime", "pallet-timestamp/try-runtime", "pallet-transaction-payment/try-runtime", @@ -206,4 +211,4 @@ metadata-hash = ["substrate-wasm-builder/metadata-hash"] # A feature that should be enabled when the runtime should be built for on-chain # deployment. This will disable stuff that shouldn't be part of the on-chain wasm # to make it smaller, like logging for example. -on-chain-release-build = ["metadata-hash", "sp-api/disable-logging"] +on-chain-release-build = ["metadata-hash"] diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/coretime.rs index 4f06e3e3669c..86769cb2da11 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 { @@ -224,8 +224,6 @@ impl CoretimeInterface for CoretimeAllocator { end_hint: Option>, ) { use crate::coretime::CoretimeProviderCalls::AssignCore; - let assign_core_call = - RelayRuntimePallets::Coretime(AssignCore(core, begin, assignment, end_hint)); // Weight for `assign_core` from westend benchmarks: // `ref_time` = 10177115 + (1 * 25000000) + (2 * 100000000) + (57600 * 13932) = 937660315 @@ -233,6 +231,38 @@ impl CoretimeInterface for CoretimeAllocator { // Add 5% to each component and round to 2 significant figures. let call_weight = Weight::from_parts(980_000_000, 3800); + // The relay chain currently only allows `assign_core` to be called with a complete mask + // and only ever with increasing `begin`. The assignments must be truncated to avoid + // dropping that core's assignment completely. + + // This shadowing of `assignment` is temporary and can be removed when the relay can accept + // multiple messages to assign a single core. + let assignment = if assignment.len() > 28 { + let mut total_parts = 0u16; + // Account for missing parts with a new `Idle` assignment at the start as + // `assign_core` on the relay assumes this is sorted. We'll add the rest of the + // assignments and sum the parts in one pass, so this is just initialized to 0. + let mut assignment_truncated = vec![(CoreAssignment::Idle, 0)]; + // Truncate to first 27 non-idle assignments. + assignment_truncated.extend( + assignment + .into_iter() + .filter(|(a, _)| *a != CoreAssignment::Idle) + .take(27) + .inspect(|(_, parts)| total_parts += *parts) + .collect::>(), + ); + + // Set the parts of the `Idle` assignment we injected at the start of the vec above. + assignment_truncated[0].1 = 57_600u16.saturating_sub(total_parts); + assignment_truncated + } else { + assignment + }; + + let assign_core_call = + RelayRuntimePallets::Coretime(AssignCore(core, begin, assignment, end_hint)); + let message = Xcm(vec![ Instruction::UnpaidExecution { weight_limit: WeightLimit::Unlimited, @@ -277,6 +307,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 +329,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 7907f252cf8e..2f944e79fe00 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/lib.rs @@ -36,14 +36,17 @@ pub mod xcm_config; extern crate alloc; use alloc::{vec, vec::Vec}; +use codec::{Decode, Encode, MaxEncodedLen}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; -use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +use cumulus_primitives_core::{AggregateMessageOrigin, ClaimQueueOffset, CoreSelector, ParaId}; use frame_support::{ construct_runtime, derive_impl, dispatch::DispatchClass, genesis_builder_helper::{build_state, get_preset}, parameter_types, - traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, TransformOrigin}, + traits::{ + ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, InstanceFilter, TransformOrigin, + }, weights::{ConstantMultiplier, Weight, WeightToFee as _}, PalletId, }; @@ -65,9 +68,9 @@ use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; pub use sp_runtime::BuildStorage; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, - traits::Block as BlockT, + traits::{BlakeTwo256, Block as BlockT}, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, DispatchError, MultiAddress, Perbill, + ApplyExtrinsicResult, DispatchError, MultiAddress, Perbill, RuntimeDebug, }; #[cfg(feature = "std")] use sp_version::NativeVersion; @@ -95,8 +98,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The TransactionExtension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -111,12 +114,13 @@ pub type SignedExtra = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( pallet_collator_selection::migration::v2::MigrationToV2, cumulus_pallet_xcmp_queue::migration::v4::MigrationToV4, + cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, pallet_broker::migration::MigrateV0ToV1, pallet_broker::migration::MigrateV1ToV2, pallet_broker::migration::MigrateV2ToV3, @@ -145,11 +149,11 @@ 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_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, - state_version: 1, + system_version: 1, }; /// The version information used to identify this runtime when compiled natively. @@ -204,6 +208,8 @@ impl frame_system::Config for Runtime { type DbWeight = RocksDbWeight; /// Weight information for the extrinsics of this pallet. type SystemWeightInfo = weights::frame_system::WeightInfo; + /// Weight information for the extensions of this pallet. + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; /// Block & extrinsics weights: base values and limits. type BlockWeights = RuntimeBlockWeights; /// The maximum length of a block (in bytes). @@ -246,6 +252,7 @@ impl pallet_balances::Config for Runtime { type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxFreezes = ConstU32<0>; + type DoneSlashHandler = (); } parameter_types! { @@ -261,6 +268,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -281,6 +289,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type ReservedXcmpWeight = ReservedXcmpWeight; type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; type ConsensusHook = ConsensusHook; + type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector; } type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< @@ -438,6 +447,138 @@ impl pallet_multisig::Config for Runtime { type WeightInfo = weights::pallet_multisig::WeightInfo; } +/// The type used to represent the kinds of proxying allowed. +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + RuntimeDebug, + MaxEncodedLen, + scale_info::TypeInfo, +)] +pub enum ProxyType { + /// Fully permissioned proxy. Can execute any call on behalf of _proxied_. + Any, + /// Can execute any call that does not transfer funds or assets. + NonTransfer, + /// Proxy with the ability to reject time-delay proxy announcements. + CancelProxy, + /// Proxy for all Broker pallet calls. + Broker, + /// Proxy for renewing coretime. + CoretimeRenewer, + /// Proxy able to purchase on-demand coretime credits. + OnDemandPurchaser, + /// Collator selection proxy. Can execute calls related to collator selection mechanism. + Collator, +} +impl Default for ProxyType { + fn default() -> Self { + Self::Any + } +} + +impl InstanceFilter for ProxyType { + fn filter(&self, c: &RuntimeCall) -> bool { + match self { + ProxyType::Any => true, + ProxyType::NonTransfer => !matches!( + c, + RuntimeCall::Balances { .. } | + // `purchase`, `renew`, `transfer` and `purchase_credit` are pretty self explanatory. + RuntimeCall::Broker(pallet_broker::Call::purchase { .. }) | + RuntimeCall::Broker(pallet_broker::Call::renew { .. }) | + RuntimeCall::Broker(pallet_broker::Call::transfer { .. }) | + RuntimeCall::Broker(pallet_broker::Call::purchase_credit { .. }) | + // `pool` doesn't transfer, but it defines the account to be paid for contributions + RuntimeCall::Broker(pallet_broker::Call::pool { .. }) | + // `assign` is essentially a transfer of a region NFT + RuntimeCall::Broker(pallet_broker::Call::assign { .. }) + ), + ProxyType::CancelProxy => matches!( + c, + RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), + ProxyType::Broker => { + matches!( + c, + RuntimeCall::Broker { .. } | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ) + }, + ProxyType::CoretimeRenewer => { + matches!( + c, + RuntimeCall::Broker(pallet_broker::Call::renew { .. }) | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ) + }, + ProxyType::OnDemandPurchaser => { + matches!( + c, + RuntimeCall::Broker(pallet_broker::Call::purchase_credit { .. }) | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ) + }, + ProxyType::Collator => matches!( + c, + RuntimeCall::CollatorSelection { .. } | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), + } + } + + fn is_superset(&self, o: &Self) -> bool { + match (self, o) { + (x, y) if x == y => true, + (ProxyType::Any, _) => true, + (_, ProxyType::Any) => false, + (ProxyType::Broker, ProxyType::CoretimeRenewer) => true, + (ProxyType::Broker, ProxyType::OnDemandPurchaser) => true, + (ProxyType::NonTransfer, ProxyType::Collator) => true, + _ => false, + } + } +} + +parameter_types! { + // One storage item; key size 32, value size 8; . + pub const ProxyDepositBase: Balance = deposit(1, 40); + // Additional storage item size of 33 bytes. + pub const ProxyDepositFactor: Balance = deposit(0, 33); + pub const MaxProxies: u16 = 32; + // One storage item; key size 32, value size 16 + pub const AnnouncementDepositBase: Balance = deposit(1, 48); + pub const AnnouncementDepositFactor: Balance = deposit(0, 66); + pub const MaxPending: u16 = 32; +} + +impl pallet_proxy::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type ProxyType = ProxyType; + type ProxyDepositBase = ProxyDepositBase; + type ProxyDepositFactor = ProxyDepositFactor; + type MaxProxies = MaxProxies; + type WeightInfo = weights::pallet_proxy::WeightInfo; + type MaxPending = MaxPending; + type CallHasher = BlakeTwo256; + type AnnouncementDepositBase = AnnouncementDepositBase; + type AnnouncementDepositFactor = AnnouncementDepositFactor; +} + impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; @@ -475,6 +616,7 @@ construct_runtime!( // Handy utilities. Utility: pallet_utility = 40, Multisig: pallet_multisig = 41, + Proxy: pallet_proxy = 42, // The main stage. Broker: pallet_broker = 50, @@ -495,6 +637,7 @@ mod benches { [pallet_xcm, PalletXcmExtrinsicsBenchmark::] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] + [pallet_proxy, Proxy] [pallet_utility, Utility] // NOTE: Make sure you point to the individual modules below. [pallet_xcm_benchmarks::fungible, XcmBalances] @@ -715,6 +858,12 @@ impl_runtime_apis! { } } + impl cumulus_primitives_core::GetCoreSelectorApi for Runtime { + fn core_selector() -> (CoreSelector, ClaimQueueOffset) { + ParachainSystem::core_selector() + } + } + #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { @@ -823,7 +972,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())), @@ -995,6 +1144,15 @@ impl_runtime_apis! { vec![] } } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/block_weights.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/block_weights.rs index 2bd7975bf98c..e5c41941a1cd 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/block_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/extrinsic_weights.rs index 898d72ec5b19..b72015884393 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/extrinsic_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..d928b73613a3 --- /dev/null +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ +// --chain=coretime-westend-dev + +#![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 `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_genesis() -> Weight { + // Proof Size summary in bytes: + // Measured: `54` + // Estimated: `3509` + // Minimum execution time: 3_637_000 picoseconds. + Weight::from_parts(6_382_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_mortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_immortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 561_000 picoseconds. + Weight::from_parts(2_705_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_316_000 picoseconds. + Weight::from_parts(5_771_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 511_000 picoseconds. + Weight::from_parts(2_575_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 501_000 picoseconds. + Weight::from_parts(2_595_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1533` + // Minimum execution time: 3_687_000 picoseconds. + Weight::from_parts(6_192_000, 0) + .saturating_add(Weight::from_parts(0, 1533)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/mod.rs index f1050b3ae636..24c4f50e6ab8 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/mod.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 @@ -22,13 +22,16 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_balances; pub mod pallet_broker; pub mod pallet_collator_selection; pub mod pallet_message_queue; pub mod pallet_multisig; +pub mod pallet_proxy; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; pub mod paritydb_weights; 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 d130b306f7a5..74b1c4e47029 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/pallet_proxy.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_proxy.rs new file mode 100644 index 000000000000..d3edc1a8b200 --- /dev/null +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_proxy.rs @@ -0,0 +1,226 @@ +// 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 . + +//! Autogenerated weights for `pallet_proxy` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=coretime-westend-dev +// --wasm-execution=compiled +// --pallet=pallet_proxy +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/coretime/coretime-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_proxy`. +pub struct WeightInfo(PhantomData); +impl pallet_proxy::WeightInfo for WeightInfo { + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 16_417_000 picoseconds. + Weight::from_parts(17_283_443, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 2_409 + .saturating_add(Weight::from_parts(32_123, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn proxy_announced(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `454 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `5698` + // Minimum execution time: 37_572_000 picoseconds. + Weight::from_parts(37_045_756, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 2_896 + .saturating_add(Weight::from_parts(139_561, 0).saturating_mul(a.into())) + // Standard Error: 2_993 + .saturating_add(Weight::from_parts(73_270, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn remove_announcement(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `369 + a * (68 ±0)` + // Estimated: `5698` + // Minimum execution time: 24_066_000 picoseconds. + Weight::from_parts(24_711_403, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 1_626 + .saturating_add(Weight::from_parts(128_391, 0).saturating_mul(a.into())) + // Standard Error: 1_680 + .saturating_add(Weight::from_parts(23_124, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn reject_announcement(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `369 + a * (68 ±0)` + // Estimated: `5698` + // Minimum execution time: 24_162_000 picoseconds. + Weight::from_parts(23_928_058, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 2_072 + .saturating_add(Weight::from_parts(152_299, 0).saturating_mul(a.into())) + // Standard Error: 2_141 + .saturating_add(Weight::from_parts(39_775, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn announce(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `386 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `5698` + // Minimum execution time: 33_858_000 picoseconds. + Weight::from_parts(33_568_059, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 1_816 + .saturating_add(Weight::from_parts(134_400, 0).saturating_mul(a.into())) + // Standard Error: 1_876 + .saturating_add(Weight::from_parts(57_028, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn add_proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 24_947_000 picoseconds. + Weight::from_parts(26_235_199, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_363 + .saturating_add(Weight::from_parts(41_435, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn remove_proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 25_186_000 picoseconds. + Weight::from_parts(26_823_133, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 2_259 + .saturating_add(Weight::from_parts(34_224, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn remove_proxies(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 22_156_000 picoseconds. + Weight::from_parts(23_304_060, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_738 + .saturating_add(Weight::from_parts(39_612, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn create_pure(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `139` + // Estimated: `4706` + // Minimum execution time: 26_914_000 picoseconds. + Weight::from_parts(28_009_062, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_978 + .saturating_add(Weight::from_parts(12_255, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 30]`. + fn kill_pure(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `164 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 23_281_000 picoseconds. + Weight::from_parts(24_392_989, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 2_943 + .saturating_add(Weight::from_parts(30_287, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..f159f877afe7 --- /dev/null +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("coretime-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_transaction_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/ +// --chain=coretime-westend-dev + +#![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_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn charge_transaction_payment() -> Weight { + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `3593` + // Minimum execution time: 33_363_000 picoseconds. + Weight::from_parts(38_793_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/paritydb_weights.rs index 1c6d2ebe568c..d056c8c46a6c 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/paritydb_weights.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/paritydb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/rocksdb_weights.rs index aa0cb2b4bc37..a32b65565a15 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/rocksdb_weights.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/weights/rocksdb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 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 ddfc599fa579..935636651eb9 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 b12765870bfd..1205be95c932 100644 --- a/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/src/xcm_config.rs @@ -41,12 +41,13 @@ use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, - DenyReserveTransferToRelayChain, DenyThenTry, EnsureXcmOrigin, FrameTransactionalProcessor, - FungibleAdapter, IsConcrete, NonFungibleAdapter, ParentAsSuperuser, ParentIsPreset, - RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, - SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, - TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, + EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsConcrete, + NonFungibleAdapter, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SendXcmFeeToAccount, + SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, + SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, + UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + XcmFeeManagerFromComponents, }; use xcm_executor::XcmExecutor; @@ -74,6 +75,8 @@ pub type LocationToAccountId = ( SiblingParachainConvertsVia, // Straight up local `AccountId32` origins just alias directly to `AccountId`. AccountId32Aliases, + // Foreign locations alias into accounts according to a hash of their standard description. + HashedDescription>, ); /// Means for transacting the native currency on this chain. @@ -221,7 +224,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/tests/tests.rs b/cumulus/parachains/runtimes/coretime/coretime-westend/tests/tests.rs new file mode 100644 index 000000000000..e391d71a9ab7 --- /dev/null +++ b/cumulus/parachains/runtimes/coretime/coretime-westend/tests/tests.rs @@ -0,0 +1,134 @@ +// 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 coretime_westend_runtime::xcm_config::LocationToAccountId; +use parachains_common::AccountId; +use sp_core::crypto::Ss58Codec; +use xcm::latest::prelude::*; +use xcm_runtime_apis::conversions::LocationToAccountHelper; + +const ALICE: [u8; 32] = [1u8; 32]; + +#[test] +fn location_conversion_works() { + // the purpose of hardcoded values is to catch an unintended location conversion logic change. + struct TestCase { + description: &'static str, + location: Location, + expected_account_id_str: &'static str, + } + + let test_cases = vec![ + // DescribeTerminus + TestCase { + description: "DescribeTerminus Parent", + location: Location::new(1, Here), + expected_account_id_str: "5Dt6dpkWPwLaH4BBCKJwjiWrFVAGyYk3tLUabvyn4v7KtESG", + }, + TestCase { + description: "DescribeTerminus Sibling", + location: Location::new(1, [Parachain(1111)]), + expected_account_id_str: "5Eg2fnssmmJnF3z1iZ1NouAuzciDaaDQH7qURAy3w15jULDk", + }, + // DescribePalletTerminal + TestCase { + description: "DescribePalletTerminal Parent", + location: Location::new(1, [PalletInstance(50)]), + expected_account_id_str: "5CnwemvaAXkWFVwibiCvf2EjqwiqBi29S5cLLydZLEaEw6jZ", + }, + TestCase { + description: "DescribePalletTerminal Sibling", + location: Location::new(1, [Parachain(1111), PalletInstance(50)]), + expected_account_id_str: "5GFBgPjpEQPdaxEnFirUoa51u5erVx84twYxJVuBRAT2UP2g", + }, + // DescribeAccountId32Terminal + TestCase { + description: "DescribeAccountId32Terminal Parent", + location: Location::new( + 1, + [Junction::AccountId32 { network: None, id: AccountId::from(ALICE).into() }], + ), + expected_account_id_str: "5DN5SGsuUG7PAqFL47J9meViwdnk9AdeSWKFkcHC45hEzVz4", + }, + TestCase { + description: "DescribeAccountId32Terminal Sibling", + location: Location::new( + 1, + [ + Parachain(1111), + Junction::AccountId32 { network: None, id: AccountId::from(ALICE).into() }, + ], + ), + expected_account_id_str: "5DGRXLYwWGce7wvm14vX1Ms4Vf118FSWQbJkyQigY2pfm6bg", + }, + // DescribeAccountKey20Terminal + TestCase { + description: "DescribeAccountKey20Terminal Parent", + location: Location::new(1, [AccountKey20 { network: None, key: [0u8; 20] }]), + expected_account_id_str: "5F5Ec11567pa919wJkX6VHtv2ZXS5W698YCW35EdEbrg14cg", + }, + TestCase { + description: "DescribeAccountKey20Terminal Sibling", + location: Location::new( + 1, + [Parachain(1111), AccountKey20 { network: None, key: [0u8; 20] }], + ), + expected_account_id_str: "5CB2FbUds2qvcJNhDiTbRZwiS3trAy6ydFGMSVutmYijpPAg", + }, + // DescribeTreasuryVoiceTerminal + TestCase { + description: "DescribeTreasuryVoiceTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]), + expected_account_id_str: "5CUjnE2vgcUCuhxPwFoQ5r7p1DkhujgvMNDHaF2bLqRp4D5F", + }, + TestCase { + description: "DescribeTreasuryVoiceTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Treasury, part: BodyPart::Voice }], + ), + expected_account_id_str: "5G6TDwaVgbWmhqRUKjBhRRnH4ry9L9cjRymUEmiRsLbSE4gB", + }, + // DescribeBodyTerminal + TestCase { + description: "DescribeBodyTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Unit, part: BodyPart::Voice }]), + expected_account_id_str: "5EBRMTBkDisEXsaN283SRbzx9Xf2PXwUxxFCJohSGo4jYe6B", + }, + TestCase { + description: "DescribeBodyTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Unit, part: BodyPart::Voice }], + ), + expected_account_id_str: "5DBoExvojy8tYnHgLL97phNH975CyT45PWTZEeGoBZfAyRMH", + }, + ]; + + for tc in test_cases { + let expected = + AccountId::from_string(tc.expected_account_id_str).expect("Invalid AccountId string"); + + let got = LocationToAccountHelper::::convert_location( + tc.location.into(), + ) + .unwrap(); + + assert_eq!(got, expected, "{}", tc.description); + } +} diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml index d20b62a557b9..09b4ef679d24 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/Cargo.toml @@ -136,4 +136,4 @@ try-runtime = [ # A feature that should be enabled when the runtime should be built for on-chain # deployment. This will disable stuff that shouldn't be part of the on-chain wasm # to make it smaller, like logging for example. -on-chain-release-build = ["sp-api/disable-logging"] +on-chain-release-build = [] diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs index 1b505ad3acbf..ad656cdbb83a 100644 --- a/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/lib.rs @@ -64,7 +64,7 @@ use sp_runtime::{ use sp_version::NativeVersion; use sp_version::RuntimeVersion; -use cumulus_primitives_core::AggregateMessageOrigin; +use cumulus_primitives_core::{AggregateMessageOrigin, ClaimQueueOffset, CoreSelector}; pub use frame_support::{ construct_runtime, derive_impl, dispatch::DispatchClass, @@ -102,11 +102,11 @@ 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_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, - state_version: 1, + system_version: 1, }; /// The version information used to identify this runtime when compiled natively. @@ -172,8 +172,8 @@ parameter_types! { type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< Runtime, RELAY_CHAIN_SLOT_DURATION_MILLIS, - BLOCK_PROCESSING_VELOCITY, - UNINCLUDED_SEGMENT_CAPACITY, + 3, + 9, >; impl cumulus_pallet_parachain_system::Config for Runtime { @@ -188,6 +188,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; type ConsensusHook = ConsensusHook; type WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; + type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector; } parameter_types! { @@ -234,7 +235,7 @@ impl pallet_aura::Config for Runtime { type DisabledValidators = (); type MaxAuthorities = ConstU32<100_000>; type AllowMultipleBlocksPerSlot = ConstBool; - type SlotDuration = ConstU64; + type SlotDuration = ConstU64<2000>; } impl pallet_glutton::Config for Runtime { @@ -289,8 +290,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( pallet_sudo::CheckOnlySudoAccount, frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, @@ -302,7 +303,7 @@ pub type SignedExtra = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -317,6 +318,7 @@ mod benches { frame_benchmarking::define_benchmarks!( [cumulus_pallet_parachain_system, ParachainSystem] [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_glutton, Glutton] [pallet_message_queue, MessageQueue] [pallet_timestamp, Timestamp] @@ -425,7 +427,13 @@ impl_runtime_apis! { } } - impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { + impl cumulus_primitives_core::GetCoreSelectorApi for Runtime { + fn core_selector() -> (CoreSelector, ClaimQueueOffset) { + ParachainSystem::core_selector() + } + } + + impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { fn account_nonce(account: AccountId) -> Nonce { System::account_nonce(account) } @@ -440,6 +448,7 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; let mut list = Vec::::new(); list_benchmarks!(list, extra); @@ -456,6 +465,7 @@ impl_runtime_apis! { use sp_storage::TrackedStorageKey; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime { fn setup_set_code_requirements(code: &alloc::vec::Vec) -> Result<(), BenchmarkError> { ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32); diff --git a/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..4fbbb8d6f781 --- /dev/null +++ b/cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,130 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("glutton-westend-dev-1300")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/glutton/glutton-westend/src/weights/ +// --chain=glutton-westend-dev-1300 + +#![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 `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_genesis() -> Weight { + // Proof Size summary in bytes: + // Measured: `54` + // Estimated: `3509` + // Minimum execution time: 3_908_000 picoseconds. + Weight::from_parts(4_007_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_mortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_510_000 picoseconds. + Weight::from_parts(6_332_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_immortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_510_000 picoseconds. + Weight::from_parts(6_332_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 651_000 picoseconds. + Weight::from_parts(851_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_387_000 picoseconds. + Weight::from_parts(3_646_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 491_000 picoseconds. + Weight::from_parts(651_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 451_000 picoseconds. + Weight::from_parts(662_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1489` + // Minimum execution time: 3_537_000 picoseconds. + Weight::from_parts(4_208_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml index a732bec2352d..373b82639def 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-rococo/Cargo.toml @@ -31,6 +31,7 @@ pallet-balances = { workspace = true } pallet-identity = { workspace = true } pallet-message-queue = { workspace = true } pallet-multisig = { workspace = true } +pallet-proxy = { workspace = true } pallet-session = { workspace = true } pallet-timestamp = { workspace = true } pallet-transaction-payment = { workspace = true } @@ -104,6 +105,7 @@ std = [ "pallet-identity/std", "pallet-message-queue/std", "pallet-multisig/std", + "pallet-proxy/std", "pallet-session/std", "pallet-timestamp/std", "pallet-transaction-payment-rpc-runtime-api/std", @@ -153,7 +155,9 @@ runtime-benchmarks = [ "pallet-identity/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", + "pallet-proxy/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", @@ -182,6 +186,7 @@ try-runtime = [ "pallet-identity/try-runtime", "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", + "pallet-proxy/try-runtime", "pallet-session/try-runtime", "pallet-timestamp/try-runtime", "pallet-transaction-payment/try-runtime", @@ -191,3 +196,8 @@ try-runtime = [ "polkadot-runtime-common/try-runtime", "sp-runtime/try-runtime", ] + +# A feature that should be enabled when the runtime should be built for on-chain +# deployment. This will disable stuff that shouldn't be part of the on-chain wasm +# to make it smaller, like logging for example. +on-chain-release-build = [] diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs index 4f007c3fc39d..f9499f9d1ebe 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/lib.rs @@ -25,15 +25,17 @@ pub mod xcm_config; extern crate alloc; use alloc::{vec, vec::Vec}; +use codec::{Decode, Encode, MaxEncodedLen}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; -use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +use cumulus_primitives_core::{AggregateMessageOrigin, ClaimQueueOffset, CoreSelector, ParaId}; use frame_support::{ construct_runtime, derive_impl, dispatch::DispatchClass, genesis_builder_helper::{build_state, get_preset}, parameter_types, traits::{ - ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything, TransformOrigin, + ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything, InstanceFilter, + TransformOrigin, }, weights::{ConstantMultiplier, Weight, WeightToFee as _}, PalletId, @@ -57,11 +59,11 @@ use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; pub use sp_runtime::BuildStorage; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, - traits::Block as BlockT, + traits::{BlakeTwo256, Block as BlockT}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, }; -pub use sp_runtime::{MultiAddress, Perbill, Permill}; +pub use sp_runtime::{MultiAddress, Perbill, Permill, RuntimeDebug}; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -89,8 +91,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The TransactionExtension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -104,11 +106,12 @@ pub type SignedExtra = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( pallet_collator_selection::migration::v2::MigrationToV2, + cumulus_pallet_xcmp_queue::migration::v5::MigrateV4ToV5, // permanent pallet_xcm::migration::MigrateToLatestXcmVersion, ); @@ -134,11 +137,11 @@ 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_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, - state_version: 1, + system_version: 1, }; /// The version information used to identify this runtime when compiled natively. @@ -186,6 +189,7 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = ConstU32<16>; @@ -222,6 +226,7 @@ impl pallet_balances::Config for Runtime { type RuntimeHoldReason = RuntimeHoldReason; type FreezeIdentifier = (); type MaxFreezes = ConstU32<0>; + type DoneSlashHandler = (); } parameter_types! { @@ -237,6 +242,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -257,6 +263,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; type ConsensusHook = ConsensusHook; type WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; + type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector; } type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< @@ -401,6 +408,119 @@ impl pallet_multisig::Config for Runtime { type WeightInfo = weights::pallet_multisig::WeightInfo; } +/// The type used to represent the kinds of proxying allowed. +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + RuntimeDebug, + MaxEncodedLen, + scale_info::TypeInfo, +)] +pub enum ProxyType { + /// Fully permissioned proxy. Can execute any call on behalf of _proxied_. + Any, + /// Can execute any call that does not transfer funds or assets. + NonTransfer, + /// Proxy with the ability to reject time-delay proxy announcements. + CancelProxy, + /// Proxy for all Identity pallet calls. + Identity, + /// Proxy for identity registrars. + IdentityJudgement, + /// Collator selection proxy. Can execute calls related to collator selection mechanism. + Collator, +} +impl Default for ProxyType { + fn default() -> Self { + Self::Any + } +} + +impl InstanceFilter for ProxyType { + fn filter(&self, c: &RuntimeCall) -> bool { + match self { + ProxyType::Any => true, + ProxyType::NonTransfer => !matches!( + c, + RuntimeCall::Balances { .. } | + // `request_judgement` puts up a deposit to transfer to a registrar + RuntimeCall::Identity(pallet_identity::Call::request_judgement { .. }) + ), + ProxyType::CancelProxy => matches!( + c, + RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), + ProxyType::Identity => { + matches!( + c, + RuntimeCall::Identity { .. } | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ) + }, + ProxyType::IdentityJudgement => matches!( + c, + RuntimeCall::Identity(pallet_identity::Call::provide_judgement { .. }) | + RuntimeCall::Utility(..) | + RuntimeCall::Multisig { .. } + ), + ProxyType::Collator => matches!( + c, + RuntimeCall::CollatorSelection { .. } | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), + } + } + + fn is_superset(&self, o: &Self) -> bool { + match (self, o) { + (x, y) if x == y => true, + (ProxyType::Any, _) => true, + (_, ProxyType::Any) => false, + (ProxyType::Identity, ProxyType::IdentityJudgement) => true, + (ProxyType::NonTransfer, ProxyType::IdentityJudgement) => true, + (ProxyType::NonTransfer, ProxyType::Collator) => true, + _ => false, + } + } +} + +parameter_types! { + // One storage item; key size 32, value size 8. + pub const ProxyDepositBase: Balance = deposit(1, 40); + // Additional storage item size of 33 bytes. + pub const ProxyDepositFactor: Balance = deposit(0, 33); + pub const MaxProxies: u16 = 32; + // One storage item; key size 32, value size 16. + pub const AnnouncementDepositBase: Balance = deposit(1, 48); + pub const AnnouncementDepositFactor: Balance = deposit(0, 66); + pub const MaxPending: u16 = 32; +} + +impl pallet_proxy::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type ProxyType = ProxyType; + type ProxyDepositBase = ProxyDepositBase; + type ProxyDepositFactor = ProxyDepositFactor; + type MaxProxies = MaxProxies; + type WeightInfo = weights::pallet_proxy::WeightInfo; + type MaxPending = MaxPending; + type CallHasher = BlakeTwo256; + type AnnouncementDepositBase = AnnouncementDepositBase; + type AnnouncementDepositFactor = AnnouncementDepositFactor; +} + impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; @@ -446,6 +566,7 @@ construct_runtime!( // Handy utilities. Utility: pallet_utility = 40, Multisig: pallet_multisig = 41, + Proxy: pallet_proxy = 42, // The main stage. Identity: pallet_identity = 50, @@ -464,9 +585,11 @@ mod benches { [pallet_identity, Identity] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] + [pallet_proxy, Proxy] [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] + [pallet_transaction_payment, TransactionPayment] // Polkadot [polkadot_runtime_common::identity_migrator, IdentityMigrator] // Cumulus @@ -687,6 +810,12 @@ impl_runtime_apis! { } } + impl cumulus_primitives_core::GetCoreSelectorApi for Runtime { + fn core_selector() -> (CoreSelector, ClaimQueueOffset) { + ParachainSystem::core_selector() + } + } + #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { @@ -933,6 +1062,15 @@ impl_runtime_apis! { vec![] } } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/block_weights.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/block_weights.rs index b2092d875c83..3ff2b3550fbf 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/block_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/extrinsic_weights.rs index 332c3b324bb9..ab951aea5615 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/extrinsic_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..fb2b69e23e82 --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/frame_system_extensions.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/people/people-rococo/src/weights/ +// --chain=people-rococo-dev + +#![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 `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_genesis() -> Weight { + // Proof Size summary in bytes: + // Measured: `54` + // Estimated: `3509` + // Minimum execution time: 3_637_000 picoseconds. + Weight::from_parts(6_382_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_mortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_immortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 561_000 picoseconds. + Weight::from_parts(2_705_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_316_000 picoseconds. + Weight::from_parts(5_771_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 511_000 picoseconds. + Weight::from_parts(2_575_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 501_000 picoseconds. + Weight::from_parts(2_595_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1533` + // Minimum execution time: 3_687_000 picoseconds. + Weight::from_parts(6_192_000, 0) + .saturating_add(Weight::from_parts(0, 1533)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs index 3396a8caea05..58480231f068 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/mod.rs @@ -20,13 +20,16 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_balances; pub mod pallet_collator_selection; pub mod pallet_identity; pub mod pallet_message_queue; pub mod pallet_multisig; +pub mod pallet_proxy; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; pub mod paritydb_weights; diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_proxy.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_proxy.rs new file mode 100644 index 000000000000..264213c94d44 --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_proxy.rs @@ -0,0 +1,226 @@ +// 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 . + +//! Autogenerated weights for `pallet_proxy` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=people-rococo-dev +// --wasm-execution=compiled +// --pallet=pallet_proxy +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/people/people-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_proxy`. +pub struct WeightInfo(PhantomData); +impl pallet_proxy::WeightInfo for WeightInfo { + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 16_417_000 picoseconds. + Weight::from_parts(17_283_443, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 2_409 + .saturating_add(Weight::from_parts(32_123, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn proxy_announced(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `454 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `5698` + // Minimum execution time: 37_572_000 picoseconds. + Weight::from_parts(37_045_756, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 2_896 + .saturating_add(Weight::from_parts(139_561, 0).saturating_mul(a.into())) + // Standard Error: 2_993 + .saturating_add(Weight::from_parts(73_270, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn remove_announcement(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `369 + a * (68 ±0)` + // Estimated: `5698` + // Minimum execution time: 24_066_000 picoseconds. + Weight::from_parts(24_711_403, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 1_626 + .saturating_add(Weight::from_parts(128_391, 0).saturating_mul(a.into())) + // Standard Error: 1_680 + .saturating_add(Weight::from_parts(23_124, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn reject_announcement(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `369 + a * (68 ±0)` + // Estimated: `5698` + // Minimum execution time: 24_162_000 picoseconds. + Weight::from_parts(23_928_058, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 2_072 + .saturating_add(Weight::from_parts(152_299, 0).saturating_mul(a.into())) + // Standard Error: 2_141 + .saturating_add(Weight::from_parts(39_775, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn announce(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `386 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `5698` + // Minimum execution time: 33_858_000 picoseconds. + Weight::from_parts(33_568_059, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 1_816 + .saturating_add(Weight::from_parts(134_400, 0).saturating_mul(a.into())) + // Standard Error: 1_876 + .saturating_add(Weight::from_parts(57_028, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn add_proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 24_947_000 picoseconds. + Weight::from_parts(26_235_199, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_363 + .saturating_add(Weight::from_parts(41_435, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn remove_proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 25_186_000 picoseconds. + Weight::from_parts(26_823_133, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 2_259 + .saturating_add(Weight::from_parts(34_224, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn remove_proxies(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 22_156_000 picoseconds. + Weight::from_parts(23_304_060, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_738 + .saturating_add(Weight::from_parts(39_612, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn create_pure(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `139` + // Estimated: `4706` + // Minimum execution time: 26_914_000 picoseconds. + Weight::from_parts(28_009_062, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_978 + .saturating_add(Weight::from_parts(12_255, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 30]`. + fn kill_pure(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `164 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 23_281_000 picoseconds. + Weight::from_parts(24_392_989, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 2_943 + .saturating_add(Weight::from_parts(30_287, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..555fd5a32fa8 --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_transaction_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/people/people-rococo/src/weights/ +// --chain=people-rococo-dev + +#![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_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn charge_transaction_payment() -> Weight { + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `3593` + // Minimum execution time: 33_363_000 picoseconds. + Weight::from_parts(38_793_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/paritydb_weights.rs index 4338d928d807..db09e9de7bdf 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/paritydb_weights.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/paritydb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/people/people-rococo/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/people/people-rococo/src/weights/rocksdb_weights.rs index 1d115d963fac..855ec356bca9 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/weights/rocksdb_weights.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/weights/rocksdb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) 2022 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 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 11c1bad9aa17..58007173ae1d 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 2364798596d5..4dd44e66dd5e 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 a50c8860c48f..729a32117041 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 cca964fb2441..a2e20e2778b6 100644 --- a/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-rococo/src/xcm_config.rs @@ -38,12 +38,13 @@ use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, - DenyReserveTransferToRelayChain, DenyThenTry, DescribeTerminus, EnsureXcmOrigin, - FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsConcrete, ParentAsSuperuser, - ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, + DescribeTerminus, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, + HashedDescription, IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, + SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + XcmFeeManagerFromComponents, }; use xcm_executor::XcmExecutor; @@ -93,6 +94,8 @@ pub type LocationToAccountId = ( AccountId32Aliases, // Here/local root location to `AccountId`. HashedDescription, + // Foreign locations alias into accounts according to a hash of their standard description. + HashedDescription>, ); /// Means for transacting the native currency on this chain. @@ -219,7 +222,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-rococo/tests/tests.rs b/cumulus/parachains/runtimes/people/people-rococo/tests/tests.rs new file mode 100644 index 000000000000..3627d9c40ec2 --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-rococo/tests/tests.rs @@ -0,0 +1,134 @@ +// 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 parachains_common::AccountId; +use people_rococo_runtime::xcm_config::LocationToAccountId; +use sp_core::crypto::Ss58Codec; +use xcm::latest::prelude::*; +use xcm_runtime_apis::conversions::LocationToAccountHelper; + +const ALICE: [u8; 32] = [1u8; 32]; + +#[test] +fn location_conversion_works() { + // the purpose of hardcoded values is to catch an unintended location conversion logic change. + struct TestCase { + description: &'static str, + location: Location, + expected_account_id_str: &'static str, + } + + let test_cases = vec![ + // DescribeTerminus + TestCase { + description: "DescribeTerminus Parent", + location: Location::new(1, Here), + expected_account_id_str: "5Dt6dpkWPwLaH4BBCKJwjiWrFVAGyYk3tLUabvyn4v7KtESG", + }, + TestCase { + description: "DescribeTerminus Sibling", + location: Location::new(1, [Parachain(1111)]), + expected_account_id_str: "5Eg2fnssmmJnF3z1iZ1NouAuzciDaaDQH7qURAy3w15jULDk", + }, + // DescribePalletTerminal + TestCase { + description: "DescribePalletTerminal Parent", + location: Location::new(1, [PalletInstance(50)]), + expected_account_id_str: "5CnwemvaAXkWFVwibiCvf2EjqwiqBi29S5cLLydZLEaEw6jZ", + }, + TestCase { + description: "DescribePalletTerminal Sibling", + location: Location::new(1, [Parachain(1111), PalletInstance(50)]), + expected_account_id_str: "5GFBgPjpEQPdaxEnFirUoa51u5erVx84twYxJVuBRAT2UP2g", + }, + // DescribeAccountId32Terminal + TestCase { + description: "DescribeAccountId32Terminal Parent", + location: Location::new( + 1, + [Junction::AccountId32 { network: None, id: AccountId::from(ALICE).into() }], + ), + expected_account_id_str: "5DN5SGsuUG7PAqFL47J9meViwdnk9AdeSWKFkcHC45hEzVz4", + }, + TestCase { + description: "DescribeAccountId32Terminal Sibling", + location: Location::new( + 1, + [ + Parachain(1111), + Junction::AccountId32 { network: None, id: AccountId::from(ALICE).into() }, + ], + ), + expected_account_id_str: "5DGRXLYwWGce7wvm14vX1Ms4Vf118FSWQbJkyQigY2pfm6bg", + }, + // DescribeAccountKey20Terminal + TestCase { + description: "DescribeAccountKey20Terminal Parent", + location: Location::new(1, [AccountKey20 { network: None, key: [0u8; 20] }]), + expected_account_id_str: "5F5Ec11567pa919wJkX6VHtv2ZXS5W698YCW35EdEbrg14cg", + }, + TestCase { + description: "DescribeAccountKey20Terminal Sibling", + location: Location::new( + 1, + [Parachain(1111), AccountKey20 { network: None, key: [0u8; 20] }], + ), + expected_account_id_str: "5CB2FbUds2qvcJNhDiTbRZwiS3trAy6ydFGMSVutmYijpPAg", + }, + // DescribeTreasuryVoiceTerminal + TestCase { + description: "DescribeTreasuryVoiceTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]), + expected_account_id_str: "5CUjnE2vgcUCuhxPwFoQ5r7p1DkhujgvMNDHaF2bLqRp4D5F", + }, + TestCase { + description: "DescribeTreasuryVoiceTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Treasury, part: BodyPart::Voice }], + ), + expected_account_id_str: "5G6TDwaVgbWmhqRUKjBhRRnH4ry9L9cjRymUEmiRsLbSE4gB", + }, + // DescribeBodyTerminal + TestCase { + description: "DescribeBodyTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Unit, part: BodyPart::Voice }]), + expected_account_id_str: "5EBRMTBkDisEXsaN283SRbzx9Xf2PXwUxxFCJohSGo4jYe6B", + }, + TestCase { + description: "DescribeBodyTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Unit, part: BodyPart::Voice }], + ), + expected_account_id_str: "5DBoExvojy8tYnHgLL97phNH975CyT45PWTZEeGoBZfAyRMH", + }, + ]; + + for tc in test_cases { + let expected = + AccountId::from_string(tc.expected_account_id_str).expect("Invalid AccountId string"); + + let got = LocationToAccountHelper::::convert_location( + tc.location.into(), + ) + .unwrap(); + + assert_eq!(got, expected, "{}", tc.description); + } +} diff --git a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml index 20c7e691ebc8..efb67adba49d 100644 --- a/cumulus/parachains/runtimes/people/people-westend/Cargo.toml +++ b/cumulus/parachains/runtimes/people/people-westend/Cargo.toml @@ -31,6 +31,7 @@ pallet-balances = { workspace = true } pallet-identity = { workspace = true } pallet-message-queue = { workspace = true } pallet-multisig = { workspace = true } +pallet-proxy = { workspace = true } pallet-session = { workspace = true } pallet-timestamp = { workspace = true } pallet-transaction-payment = { workspace = true } @@ -104,6 +105,7 @@ std = [ "pallet-identity/std", "pallet-message-queue/std", "pallet-multisig/std", + "pallet-proxy/std", "pallet-session/std", "pallet-timestamp/std", "pallet-transaction-payment-rpc-runtime-api/std", @@ -153,7 +155,9 @@ runtime-benchmarks = [ "pallet-identity/runtime-benchmarks", "pallet-message-queue/runtime-benchmarks", "pallet-multisig/runtime-benchmarks", + "pallet-proxy/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-xcm-benchmarks/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", @@ -182,6 +186,7 @@ try-runtime = [ "pallet-identity/try-runtime", "pallet-message-queue/try-runtime", "pallet-multisig/try-runtime", + "pallet-proxy/try-runtime", "pallet-session/try-runtime", "pallet-timestamp/try-runtime", "pallet-transaction-payment/try-runtime", @@ -191,3 +196,8 @@ try-runtime = [ "polkadot-runtime-common/try-runtime", "sp-runtime/try-runtime", ] + +# A feature that should be enabled when the runtime should be built for on-chain +# deployment. This will disable stuff that shouldn't be part of the on-chain wasm +# to make it smaller, like logging for example. +on-chain-release-build = [] diff --git a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs index 1378324ce7b0..7e3cd1670fe5 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/lib.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/lib.rs @@ -25,15 +25,17 @@ pub mod xcm_config; extern crate alloc; use alloc::{vec, vec::Vec}; +use codec::{Decode, Encode, MaxEncodedLen}; use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; -use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +use cumulus_primitives_core::{AggregateMessageOrigin, ClaimQueueOffset, CoreSelector, ParaId}; use frame_support::{ construct_runtime, derive_impl, dispatch::DispatchClass, genesis_builder_helper::{build_state, get_preset}, parameter_types, traits::{ - ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything, TransformOrigin, + ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, Everything, InstanceFilter, + TransformOrigin, }, weights::{ConstantMultiplier, Weight, WeightToFee as _}, PalletId, @@ -57,11 +59,11 @@ use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; pub use sp_runtime::BuildStorage; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, - traits::Block as BlockT, + traits::{BlakeTwo256, Block as BlockT}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, }; -pub use sp_runtime::{MultiAddress, Perbill, Permill}; +pub use sp_runtime::{MultiAddress, Perbill, Permill, RuntimeDebug}; #[cfg(feature = "std")] use sp_version::NativeVersion; use sp_version::RuntimeVersion; @@ -89,8 +91,8 @@ pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The transactionExtension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -104,7 +106,7 @@ pub type SignedExtra = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Migrations to apply on runtime upgrade. pub type Migrations = ( @@ -134,11 +136,11 @@ 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_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, - state_version: 1, + system_version: 1, }; /// The version information used to identify this runtime when compiled natively. @@ -186,6 +188,7 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; type MaxConsumers = ConstU32<16>; @@ -222,6 +225,7 @@ impl pallet_balances::Config for Runtime { type RuntimeHoldReason = RuntimeHoldReason; type FreezeIdentifier = (); type MaxFreezes = ConstU32<0>; + type DoneSlashHandler = (); } parameter_types! { @@ -237,6 +241,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -257,6 +262,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; type ConsensusHook = ConsensusHook; type WeightInfo = weights::cumulus_pallet_parachain_system::WeightInfo; + type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector; } type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< @@ -401,6 +407,119 @@ impl pallet_multisig::Config for Runtime { type WeightInfo = weights::pallet_multisig::WeightInfo; } +/// The type used to represent the kinds of proxying allowed. +#[derive( + Copy, + Clone, + Eq, + PartialEq, + Ord, + PartialOrd, + Encode, + Decode, + RuntimeDebug, + MaxEncodedLen, + scale_info::TypeInfo, +)] +pub enum ProxyType { + /// Fully permissioned proxy. Can execute any call on behalf of _proxied_. + Any, + /// Can execute any call that does not transfer funds or assets. + NonTransfer, + /// Proxy with the ability to reject time-delay proxy announcements. + CancelProxy, + /// Proxy for all Identity pallet calls. + Identity, + /// Proxy for identity registrars. + IdentityJudgement, + /// Collator selection proxy. Can execute calls related to collator selection mechanism. + Collator, +} +impl Default for ProxyType { + fn default() -> Self { + Self::Any + } +} + +impl InstanceFilter for ProxyType { + fn filter(&self, c: &RuntimeCall) -> bool { + match self { + ProxyType::Any => true, + ProxyType::NonTransfer => !matches!( + c, + RuntimeCall::Balances { .. } | + // `request_judgement` puts up a deposit to transfer to a registrar + RuntimeCall::Identity(pallet_identity::Call::request_judgement { .. }) + ), + ProxyType::CancelProxy => matches!( + c, + RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. }) | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), + ProxyType::Identity => { + matches!( + c, + RuntimeCall::Identity { .. } | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ) + }, + ProxyType::IdentityJudgement => matches!( + c, + RuntimeCall::Identity(pallet_identity::Call::provide_judgement { .. }) | + RuntimeCall::Utility(..) | + RuntimeCall::Multisig { .. } + ), + ProxyType::Collator => matches!( + c, + RuntimeCall::CollatorSelection { .. } | + RuntimeCall::Utility { .. } | + RuntimeCall::Multisig { .. } + ), + } + } + + fn is_superset(&self, o: &Self) -> bool { + match (self, o) { + (x, y) if x == y => true, + (ProxyType::Any, _) => true, + (_, ProxyType::Any) => false, + (ProxyType::Identity, ProxyType::IdentityJudgement) => true, + (ProxyType::NonTransfer, ProxyType::IdentityJudgement) => true, + (ProxyType::NonTransfer, ProxyType::Collator) => true, + _ => false, + } + } +} + +parameter_types! { + // One storage item; key size 32, value size 8. + pub const ProxyDepositBase: Balance = deposit(1, 40); + // Additional storage item size of 33 bytes. + pub const ProxyDepositFactor: Balance = deposit(0, 33); + pub const MaxProxies: u16 = 32; + // One storage item; key size 32, value size 16. + pub const AnnouncementDepositBase: Balance = deposit(1, 48); + pub const AnnouncementDepositFactor: Balance = deposit(0, 66); + pub const MaxPending: u16 = 32; +} + +impl pallet_proxy::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type Currency = Balances; + type ProxyType = ProxyType; + type ProxyDepositBase = ProxyDepositBase; + type ProxyDepositFactor = ProxyDepositFactor; + type MaxProxies = MaxProxies; + type WeightInfo = weights::pallet_proxy::WeightInfo; + type MaxPending = MaxPending; + type CallHasher = BlakeTwo256; + type AnnouncementDepositBase = AnnouncementDepositBase; + type AnnouncementDepositFactor = AnnouncementDepositFactor; +} + impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; @@ -446,6 +565,7 @@ construct_runtime!( // Handy utilities. Utility: pallet_utility = 40, Multisig: pallet_multisig = 41, + Proxy: pallet_proxy = 42, // The main stage. Identity: pallet_identity = 50, @@ -464,6 +584,7 @@ mod benches { [pallet_identity, Identity] [pallet_message_queue, MessageQueue] [pallet_multisig, Multisig] + [pallet_proxy, Proxy] [pallet_session, SessionBench::] [pallet_utility, Utility] [pallet_timestamp, Timestamp] @@ -687,6 +808,12 @@ impl_runtime_apis! { } } + impl cumulus_primitives_core::GetCoreSelectorApi for Runtime { + fn core_selector() -> (CoreSelector, ClaimQueueOffset) { + ParachainSystem::core_selector() + } + } + #[cfg(feature = "try-runtime")] impl frame_try_runtime::TryRuntime for Runtime { fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { @@ -933,6 +1060,15 @@ impl_runtime_apis! { vec![] } } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/block_weights.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/block_weights.rs index 2bd7975bf98c..e5c41941a1cd 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/block_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/extrinsic_weights.rs index 898d72ec5b19..b72015884393 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/extrinsic_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) 2023 Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/frame_system_extensions.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..0a4b9e8e2681 --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,132 @@ +// 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 . + +//! Autogenerated weights for `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=frame_system_extensions +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/people/people-westend/src/weights/ +// --chain=people-westend-dev + +#![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 `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_genesis() -> Weight { + // Proof Size summary in bytes: + // Measured: `54` + // Estimated: `3509` + // Minimum execution time: 3_637_000 picoseconds. + Weight::from_parts(6_382_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_mortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_immortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_841_000 picoseconds. + Weight::from_parts(8_776_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 561_000 picoseconds. + Weight::from_parts(2_705_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_316_000 picoseconds. + Weight::from_parts(5_771_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 511_000 picoseconds. + Weight::from_parts(2_575_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 501_000 picoseconds. + Weight::from_parts(2_595_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::BlockWeight` (r:1 w:1) + /// Proof: `System::BlockWeight` (`max_values`: Some(1), `max_size`: Some(48), added: 543, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1533` + // Minimum execution time: 3_687_000 picoseconds. + Weight::from_parts(6_192_000, 0) + .saturating_add(Weight::from_parts(0, 1533)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs index 3396a8caea05..58480231f068 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/mod.rs @@ -20,13 +20,16 @@ pub mod cumulus_pallet_parachain_system; pub mod cumulus_pallet_xcmp_queue; pub mod extrinsic_weights; pub mod frame_system; +pub mod frame_system_extensions; pub mod pallet_balances; pub mod pallet_collator_selection; pub mod pallet_identity; pub mod pallet_message_queue; pub mod pallet_multisig; +pub mod pallet_proxy; pub mod pallet_session; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_utility; pub mod pallet_xcm; pub mod paritydb_weights; diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_proxy.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_proxy.rs new file mode 100644 index 000000000000..e962123f216c --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_proxy.rs @@ -0,0 +1,226 @@ +// 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 . + +//! Autogenerated weights for `pallet_proxy` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-07-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-ynta1nyy-project-238-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot-parachain +// benchmark +// pallet +// --chain=people-westend-dev +// --wasm-execution=compiled +// --pallet=pallet_proxy +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=50 +// --repeat=20 +// --json +// --header=./file_header.txt +// --output=./parachains/runtimes/people/people-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_proxy`. +pub struct WeightInfo(PhantomData); +impl pallet_proxy::WeightInfo for WeightInfo { + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 16_417_000 picoseconds. + Weight::from_parts(17_283_443, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 2_409 + .saturating_add(Weight::from_parts(32_123, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn proxy_announced(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `454 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `5698` + // Minimum execution time: 37_572_000 picoseconds. + Weight::from_parts(37_045_756, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 2_896 + .saturating_add(Weight::from_parts(139_561, 0).saturating_mul(a.into())) + // Standard Error: 2_993 + .saturating_add(Weight::from_parts(73_270, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn remove_announcement(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `369 + a * (68 ±0)` + // Estimated: `5698` + // Minimum execution time: 24_066_000 picoseconds. + Weight::from_parts(24_711_403, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 1_626 + .saturating_add(Weight::from_parts(128_391, 0).saturating_mul(a.into())) + // Standard Error: 1_680 + .saturating_add(Weight::from_parts(23_124, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn reject_announcement(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `369 + a * (68 ±0)` + // Estimated: `5698` + // Minimum execution time: 24_162_000 picoseconds. + Weight::from_parts(23_928_058, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 2_072 + .saturating_add(Weight::from_parts(152_299, 0).saturating_mul(a.into())) + // Standard Error: 2_141 + .saturating_add(Weight::from_parts(39_775, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `a` is `[0, 31]`. + /// The range of component `p` is `[1, 31]`. + fn announce(a: u32, p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `386 + a * (68 ±0) + p * (37 ±0)` + // Estimated: `5698` + // Minimum execution time: 33_858_000 picoseconds. + Weight::from_parts(33_568_059, 0) + .saturating_add(Weight::from_parts(0, 5698)) + // Standard Error: 1_816 + .saturating_add(Weight::from_parts(134_400, 0).saturating_mul(a.into())) + // Standard Error: 1_876 + .saturating_add(Weight::from_parts(57_028, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn add_proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 24_947_000 picoseconds. + Weight::from_parts(26_235_199, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_363 + .saturating_add(Weight::from_parts(41_435, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn remove_proxy(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 25_186_000 picoseconds. + Weight::from_parts(26_823_133, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 2_259 + .saturating_add(Weight::from_parts(34_224, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn remove_proxies(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `127 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 22_156_000 picoseconds. + Weight::from_parts(23_304_060, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_738 + .saturating_add(Weight::from_parts(39_612, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[1, 31]`. + fn create_pure(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `139` + // Estimated: `4706` + // Minimum execution time: 26_914_000 picoseconds. + Weight::from_parts(28_009_062, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 1_978 + .saturating_add(Weight::from_parts(12_255, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// The range of component `p` is `[0, 30]`. + fn kill_pure(p: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `164 + p * (37 ±0)` + // Estimated: `4706` + // Minimum execution time: 23_281_000 picoseconds. + Weight::from_parts(24_392_989, 0) + .saturating_add(Weight::from_parts(0, 4706)) + // Standard Error: 2_943 + .saturating_add(Weight::from_parts(30_287, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_transaction_payment.rs b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..30e4524e586e --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-westend/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,67 @@ +// 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 . + +//! Autogenerated weights for `pallet_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2023-12-21, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("people-westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/release/polkadot-parachain +// benchmark +// pallet +// --wasm-execution=compiled +// --pallet=pallet_transaction_payment +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --extrinsic=* +// --steps=2 +// --repeat=2 +// --json +// --header=./cumulus/file_header.txt +// --output=./cumulus/parachains/runtimes/people/people-westend/src/weights/ +// --chain=people-westend-dev + +#![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_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn charge_transaction_payment() -> Weight { + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `3593` + // Minimum execution time: 33_363_000 picoseconds. + Weight::from_parts(38_793_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(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 b1fc7ad8ed83..b44e8d4b61b8 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 92d08a246180..8f6bfde986bb 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 861f03819959..1377d31f2db7 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 3926ddcf21ef..bec5b923d8ad 100644 --- a/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/people/people-westend/src/xcm_config.rs @@ -38,12 +38,13 @@ use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, - DenyReserveTransferToRelayChain, DenyThenTry, DescribeTerminus, EnsureXcmOrigin, - FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsConcrete, ParentAsSuperuser, - ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, SiblingParachainConvertsVia, + DenyReserveTransferToRelayChain, DenyThenTry, DescribeAllTerminal, DescribeFamily, + DescribeTerminus, EnsureXcmOrigin, FrameTransactionalProcessor, FungibleAdapter, + HashedDescription, IsConcrete, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, + SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + XcmFeeManagerFromComponents, }; use xcm_executor::XcmExecutor; @@ -93,6 +94,8 @@ pub type LocationToAccountId = ( AccountId32Aliases, // Here/local root location to `AccountId`. HashedDescription, + // Foreign locations alias into accounts according to a hash of their standard description. + HashedDescription>, ); /// Means for transacting the native currency on this chain. @@ -227,7 +230,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/tests/tests.rs b/cumulus/parachains/runtimes/people/people-westend/tests/tests.rs new file mode 100644 index 000000000000..fa9331952b4b --- /dev/null +++ b/cumulus/parachains/runtimes/people/people-westend/tests/tests.rs @@ -0,0 +1,134 @@ +// 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 parachains_common::AccountId; +use people_westend_runtime::xcm_config::LocationToAccountId; +use sp_core::crypto::Ss58Codec; +use xcm::latest::prelude::*; +use xcm_runtime_apis::conversions::LocationToAccountHelper; + +const ALICE: [u8; 32] = [1u8; 32]; + +#[test] +fn location_conversion_works() { + // the purpose of hardcoded values is to catch an unintended location conversion logic change. + struct TestCase { + description: &'static str, + location: Location, + expected_account_id_str: &'static str, + } + + let test_cases = vec![ + // DescribeTerminus + TestCase { + description: "DescribeTerminus Parent", + location: Location::new(1, Here), + expected_account_id_str: "5Dt6dpkWPwLaH4BBCKJwjiWrFVAGyYk3tLUabvyn4v7KtESG", + }, + TestCase { + description: "DescribeTerminus Sibling", + location: Location::new(1, [Parachain(1111)]), + expected_account_id_str: "5Eg2fnssmmJnF3z1iZ1NouAuzciDaaDQH7qURAy3w15jULDk", + }, + // DescribePalletTerminal + TestCase { + description: "DescribePalletTerminal Parent", + location: Location::new(1, [PalletInstance(50)]), + expected_account_id_str: "5CnwemvaAXkWFVwibiCvf2EjqwiqBi29S5cLLydZLEaEw6jZ", + }, + TestCase { + description: "DescribePalletTerminal Sibling", + location: Location::new(1, [Parachain(1111), PalletInstance(50)]), + expected_account_id_str: "5GFBgPjpEQPdaxEnFirUoa51u5erVx84twYxJVuBRAT2UP2g", + }, + // DescribeAccountId32Terminal + TestCase { + description: "DescribeAccountId32Terminal Parent", + location: Location::new( + 1, + [Junction::AccountId32 { network: None, id: AccountId::from(ALICE).into() }], + ), + expected_account_id_str: "5DN5SGsuUG7PAqFL47J9meViwdnk9AdeSWKFkcHC45hEzVz4", + }, + TestCase { + description: "DescribeAccountId32Terminal Sibling", + location: Location::new( + 1, + [ + Parachain(1111), + Junction::AccountId32 { network: None, id: AccountId::from(ALICE).into() }, + ], + ), + expected_account_id_str: "5DGRXLYwWGce7wvm14vX1Ms4Vf118FSWQbJkyQigY2pfm6bg", + }, + // DescribeAccountKey20Terminal + TestCase { + description: "DescribeAccountKey20Terminal Parent", + location: Location::new(1, [AccountKey20 { network: None, key: [0u8; 20] }]), + expected_account_id_str: "5F5Ec11567pa919wJkX6VHtv2ZXS5W698YCW35EdEbrg14cg", + }, + TestCase { + description: "DescribeAccountKey20Terminal Sibling", + location: Location::new( + 1, + [Parachain(1111), AccountKey20 { network: None, key: [0u8; 20] }], + ), + expected_account_id_str: "5CB2FbUds2qvcJNhDiTbRZwiS3trAy6ydFGMSVutmYijpPAg", + }, + // DescribeTreasuryVoiceTerminal + TestCase { + description: "DescribeTreasuryVoiceTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Treasury, part: BodyPart::Voice }]), + expected_account_id_str: "5CUjnE2vgcUCuhxPwFoQ5r7p1DkhujgvMNDHaF2bLqRp4D5F", + }, + TestCase { + description: "DescribeTreasuryVoiceTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Treasury, part: BodyPart::Voice }], + ), + expected_account_id_str: "5G6TDwaVgbWmhqRUKjBhRRnH4ry9L9cjRymUEmiRsLbSE4gB", + }, + // DescribeBodyTerminal + TestCase { + description: "DescribeBodyTerminal Parent", + location: Location::new(1, [Plurality { id: BodyId::Unit, part: BodyPart::Voice }]), + expected_account_id_str: "5EBRMTBkDisEXsaN283SRbzx9Xf2PXwUxxFCJohSGo4jYe6B", + }, + TestCase { + description: "DescribeBodyTerminal Sibling", + location: Location::new( + 1, + [Parachain(1111), Plurality { id: BodyId::Unit, part: BodyPart::Voice }], + ), + expected_account_id_str: "5DBoExvojy8tYnHgLL97phNH975CyT45PWTZEeGoBZfAyRMH", + }, + ]; + + for tc in test_cases { + let expected = + AccountId::from_string(tc.expected_account_id_str).expect("Invalid AccountId string"); + + let got = LocationToAccountHelper::::convert_location( + tc.location.into(), + ) + .unwrap(); + + assert_eq!(got, expected, "{}", tc.description); + } +} diff --git a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml b/cumulus/parachains/runtimes/starters/seedling/Cargo.toml deleted file mode 100644 index c76c09a31234..000000000000 --- a/cumulus/parachains/runtimes/starters/seedling/Cargo.toml +++ /dev/null @@ -1,79 +0,0 @@ -[package] -name = "seedling-runtime" -version = "0.7.0" -description = "Seedling parachain runtime. A starter runtime for solochain to parachain migration." -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" - -[lints] -workspace = true - -[dependencies] -codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } - -# Substrate -frame-executive = { workspace = true } -frame-support = { workspace = true } -frame-system = { workspace = true } -pallet-aura = { workspace = true } -pallet-balances = { workspace = true } -pallet-sudo = { workspace = true } -pallet-timestamp = { workspace = true } -sp-api = { workspace = true } -sp-block-builder = { workspace = true } -sp-consensus-aura = { workspace = true } -sp-core = { workspace = true } -sp-genesis-builder = { workspace = true } -sp-inherents = { workspace = true } -sp-offchain = { workspace = true } -sp-runtime = { workspace = true } -sp-session = { workspace = true } -sp-transaction-pool = { workspace = true } -sp-version = { workspace = true } - -# Cumulus -cumulus-pallet-aura-ext = { workspace = true } -cumulus-pallet-parachain-system = { workspace = true } -cumulus-pallet-solo-to-para = { workspace = true } -cumulus-primitives-core = { workspace = true } -cumulus-primitives-timestamp = { workspace = true } -parachain-info = { workspace = true } -parachains-common = { workspace = true } - -[build-dependencies] -substrate-wasm-builder = { optional = true, workspace = true, default-features = true } - -[features] -default = ["std"] -std = [ - "codec/std", - "cumulus-pallet-aura-ext/std", - "cumulus-pallet-parachain-system/std", - "cumulus-pallet-solo-to-para/std", - "cumulus-primitives-core/std", - "cumulus-primitives-timestamp/std", - "frame-executive/std", - "frame-support/std", - "frame-system/std", - "pallet-aura/std", - "pallet-balances/std", - "pallet-sudo/std", - "pallet-timestamp/std", - "parachain-info/std", - "parachains-common/std", - "scale-info/std", - "sp-api/std", - "sp-block-builder/std", - "sp-consensus-aura/std", - "sp-core/std", - "sp-genesis-builder/std", - "sp-inherents/std", - "sp-offchain/std", - "sp-runtime/std", - "sp-session/std", - "sp-transaction-pool/std", - "sp-version/std", - "substrate-wasm-builder", -] diff --git a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs b/cumulus/parachains/runtimes/starters/seedling/src/lib.rs deleted file mode 100644 index 1fe72604d373..000000000000 --- a/cumulus/parachains/runtimes/starters/seedling/src/lib.rs +++ /dev/null @@ -1,392 +0,0 @@ -// 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 . - -//! # Seedling Runtime -//! -//! Seedling is a parachain meant to help parachain auction winners migrate a blockchain from -//! another consensus system into the consensus system of a given Relay Chain. - -#![cfg_attr(not(feature = "std"), no_std)] -// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. -#![recursion_limit = "256"] - -// Make the WASM binary available. -#[cfg(feature = "std")] -include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); - -extern crate alloc; - -use alloc::{vec, vec::Vec}; -use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; -use sp_api::impl_runtime_apis; -pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; -use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; -use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, - traits::{AccountIdLookup, BlakeTwo256, Block as BlockT}, - transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, -}; -#[cfg(feature = "std")] -use sp_version::NativeVersion; -use sp_version::RuntimeVersion; - -// A few exports that help ease life for downstream crates. -pub use frame_support::{ - construct_runtime, derive_impl, - dispatch::DispatchClass, - genesis_builder_helper::{build_state, get_preset}, - parameter_types, - traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, IsInVec, Randomness}, - weights::{ - constants::{ - BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND, - }, - IdentityFee, Weight, - }, - StorageValue, -}; -use frame_system::limits::{BlockLength, BlockWeights}; -use parachains_common::{AccountId, Signature}; -#[cfg(any(feature = "std", test))] -pub use sp_runtime::BuildStorage; -pub use sp_runtime::{Perbill, Permill}; - -impl_opaque_keys! { - pub struct SessionKeys { - pub aura: Aura, - } -} - -/// This runtime version. -#[sp_version::runtime_version] -pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("seedling"), - impl_name: create_runtime_str!("seedling"), - authoring_version: 1, - spec_version: 1, - impl_version: 0, - apis: RUNTIME_API_VERSIONS, - transaction_version: 2, - state_version: 0, -}; - -/// The version information used to identify this runtime when compiled natively. -#[cfg(feature = "std")] -pub fn native_version() -> NativeVersion { - NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } -} - -/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included -/// into the relay chain. -const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; -/// How many parachain blocks are processed by the relay chain per parent. Limits the -/// number of blocks authored per slot. -const BLOCK_PROCESSING_VELOCITY: u32 = 1; -/// Relay chain slot duration, in milliseconds. -const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; - -/// We assume that ~10% of the block weight is consumed by `on_initialize` handlers. -/// This is used to limit the maximal weight of a single extrinsic. -const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); -/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used -/// by Operational extrinsics. -const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); -/// We allow for .5 seconds of compute with a 12 second average block time. -const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts( - WEIGHT_REF_TIME_PER_SECOND.saturating_div(2), - cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64, -); - -parameter_types! { - pub const BlockHashCount: BlockNumber = 250; - pub const Version: RuntimeVersion = VERSION; - pub RuntimeBlockLength: BlockLength = - BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); - pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() - .base_block(BlockExecutionWeight::get()) - .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = ExtrinsicBaseWeight::get(); - }) - .for_class(DispatchClass::Normal, |weights| { - weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); - }) - .for_class(DispatchClass::Operational, |weights| { - weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); - // Operational transactions have some extra reserved space, so that they - // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`. - weights.reserved = Some( - MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT - ); - }) - .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) - .build_or_panic(); - pub const SS58Prefix: u8 = 42; -} - -#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] -impl frame_system::Config for Runtime { - /// The identifier used to distinguish between accounts. - type AccountId = AccountId; - /// The aggregated dispatch type that is available for extrinsics. - type RuntimeCall = RuntimeCall; - /// The lookup mechanism to get account ID from whatever is passed in dispatchers. - type Lookup = AccountIdLookup; - /// The index type for storing how many extrinsics an account has signed. - type Nonce = Nonce; - /// The type for hashing blocks and tries. - type Hash = Hash; - /// The hashing algorithm used. - type Hashing = BlakeTwo256; - /// The block type. - type Block = Block; - /// The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; - /// The ubiquitous origin type. - type RuntimeOrigin = RuntimeOrigin; - /// Maximum number of block number to block hash mappings to keep (oldest pruned first). - type BlockHashCount = BlockHashCount; - /// Runtime version. - type Version = Version; - /// Converts a module to an index of this module in the runtime. - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type DbWeight = (); - type BaseCallFilter = frame_support::traits::Everything; - type SystemWeightInfo = (); - type BlockWeights = RuntimeBlockWeights; - type BlockLength = RuntimeBlockLength; - type SS58Prefix = SS58Prefix; - type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -impl pallet_sudo::Config for Runtime { - type RuntimeCall = RuntimeCall; - type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_sudo::weights::SubstrateWeight; -} - -impl cumulus_pallet_solo_to_para::Config for Runtime { - type RuntimeEvent = RuntimeEvent; -} - -impl cumulus_pallet_parachain_system::Config for Runtime { - type WeightInfo = (); - type RuntimeEvent = RuntimeEvent; - type OnSystemEvent = cumulus_pallet_solo_to_para::Pallet; - type SelfParaId = parachain_info::Pallet; - type OutboundXcmpMessageSource = (); - // Ignore all DMP messages by enqueueing them into `()`: - type DmpQueue = frame_support::traits::EnqueueWithOrigin<(), sp_core::ConstU8<0>>; - type ReservedDmpWeight = (); - type XcmpMessageHandler = (); - type ReservedXcmpWeight = (); - type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; - type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< - Runtime, - RELAY_CHAIN_SLOT_DURATION_MILLIS, - BLOCK_PROCESSING_VELOCITY, - UNINCLUDED_SEGMENT_CAPACITY, - >; -} - -impl parachain_info::Config for Runtime {} - -impl cumulus_pallet_aura_ext::Config for Runtime {} - -impl pallet_aura::Config for Runtime { - type AuthorityId = AuraId; - type DisabledValidators = (); - type MaxAuthorities = ConstU32<100_000>; - type AllowMultipleBlocksPerSlot = ConstBool; - type SlotDuration = pallet_aura::MinimumPeriodTimesTwo; -} - -impl pallet_timestamp::Config for Runtime { - type Moment = u64; - type OnTimestampSet = Aura; - type MinimumPeriod = ConstU64<0>; - type WeightInfo = (); -} - -construct_runtime! { - pub enum Runtime - { - System: frame_system, - Sudo: pallet_sudo, - Timestamp: pallet_timestamp, - - ParachainSystem: cumulus_pallet_parachain_system, - ParachainInfo: parachain_info, - SoloToPara: cumulus_pallet_solo_to_para, - Aura: pallet_aura, - AuraExt: cumulus_pallet_aura_ext, - } -} - -/// Index of a transaction in the chain. -pub type Nonce = u32; -/// A hash of some data used by the chain. -pub type Hash = sp_core::H256; -/// An index to a block. -pub type BlockNumber = u32; -/// The address format for describing accounts. -pub type Address = sp_runtime::MultiAddress; -/// Block header type as expected by this runtime. -pub type Header = generic::Header; -/// Block type as expected by this runtime. -pub type Block = generic::Block; -/// A Block signed with a Justification -pub type SignedBlock = generic::SignedBlock; -/// BlockId type as expected by this runtime. -pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( - frame_system::CheckSpecVersion, - frame_system::CheckTxVersion, - frame_system::CheckGenesis, - frame_system::CheckEra, - frame_system::CheckNonce, - pallet_sudo::CheckOnlySudoAccount, -); -/// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; - -/// Executive: handles dispatch to the various modules. -pub type Executive = frame_executive::Executive< - Runtime, - Block, - frame_system::ChainContext, - Runtime, - AllPalletsWithSystem, ->; - -impl_runtime_apis! { - impl sp_consensus_aura::AuraApi for Runtime { - fn slot_duration() -> sp_consensus_aura::SlotDuration { - sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration()) - } - - fn authorities() -> Vec { - pallet_aura::Authorities::::get().into_inner() - } - } - - impl sp_api::Core for Runtime { - fn version() -> RuntimeVersion { - VERSION - } - - fn execute_block(block: Block) { - Executive::execute_block(block) - } - - fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { - Executive::initialize_block(header) - } - } - - impl sp_api::Metadata for Runtime { - fn metadata() -> OpaqueMetadata { - OpaqueMetadata::new(Runtime::metadata().into()) - } - - fn metadata_at_version(version: u32) -> Option { - Runtime::metadata_at_version(version) - } - - fn metadata_versions() -> alloc::vec::Vec { - Runtime::metadata_versions() - } - } - - impl sp_block_builder::BlockBuilder for Runtime { - fn apply_extrinsic( - extrinsic: ::Extrinsic, - ) -> ApplyExtrinsicResult { - Executive::apply_extrinsic(extrinsic) - } - - fn finalize_block() -> ::Header { - Executive::finalize_block() - } - - fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<::Extrinsic> { - data.create_extrinsics() - } - - fn check_inherents(block: Block, data: sp_inherents::InherentData) -> sp_inherents::CheckInherentsResult { - data.check_extrinsics(&block) - } - } - - impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { - fn validate_transaction( - source: TransactionSource, - tx: ::Extrinsic, - block_hash: ::Hash, - ) -> TransactionValidity { - Executive::validate_transaction(source, tx, block_hash) - } - } - - impl sp_offchain::OffchainWorkerApi for Runtime { - fn offchain_worker(header: &::Header) { - Executive::offchain_worker(header) - } - } - - impl sp_session::SessionKeys for Runtime { - fn generate_session_keys(seed: Option>) -> Vec { - SessionKeys::generate(seed) - } - - fn decode_session_keys( - encoded: Vec, - ) -> Option, KeyTypeId)>> { - SessionKeys::decode_into_raw_public_keys(&encoded) - } - } - - impl cumulus_primitives_core::CollectCollationInfo for Runtime { - fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { - ParachainSystem::collect_collation_info(header) - } - } - - impl sp_genesis_builder::GenesisBuilder for Runtime { - fn build_state(config: Vec) -> sp_genesis_builder::Result { - build_state::(config) - } - - fn get_preset(id: &Option) -> Option> { - get_preset::(id, |_| None) - } - - fn preset_names() -> Vec { - vec![] - } - } -} - -cumulus_pallet_parachain_system::register_validate_block! { - Runtime = Runtime, - BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, -} diff --git a/cumulus/parachains/runtimes/starters/shell/Cargo.toml b/cumulus/parachains/runtimes/starters/shell/Cargo.toml deleted file mode 100644 index 8f3b2204cfe3..000000000000 --- a/cumulus/parachains/runtimes/starters/shell/Cargo.toml +++ /dev/null @@ -1,99 +0,0 @@ -[package] -name = "shell-runtime" -version = "0.7.0" -description = "A minimal runtime to test Relay Chain consensus." -authors.workspace = true -edition.workspace = true -license = "Apache-2.0" - -[lints] -workspace = true - -[dependencies] -codec = { features = ["derive"], workspace = true } -scale-info = { features = ["derive"], workspace = true } - -# Substrate -frame-executive = { workspace = true } -frame-support = { workspace = true } -frame-system = { workspace = true } -frame-try-runtime = { optional = true, workspace = true } -pallet-aura = { workspace = true } -pallet-timestamp = { workspace = true } -sp-api = { workspace = true } -sp-block-builder = { workspace = true } -sp-consensus-aura = { workspace = true } -sp-core = { workspace = true } -sp-genesis-builder = { workspace = true } -sp-inherents = { workspace = true } -sp-offchain = { workspace = true } -sp-runtime = { workspace = true } -sp-session = { workspace = true } -sp-transaction-pool = { workspace = true } -sp-version = { workspace = true } -pallet-message-queue = { workspace = true } - -# Polkadot -xcm = { workspace = true } -xcm-builder = { workspace = true } -xcm-executor = { workspace = true } - -# Cumulus -cumulus-pallet-aura-ext = { workspace = true } -cumulus-pallet-parachain-system = { workspace = true } -cumulus-pallet-xcm = { workspace = true } -cumulus-primitives-core = { workspace = true } -parachain-info = { workspace = true } -parachains-common = { workspace = true } - -[build-dependencies] -substrate-wasm-builder = { optional = true, workspace = true, default-features = true } - -[features] -default = ["std"] -std = [ - "codec/std", - "cumulus-pallet-aura-ext/std", - "cumulus-pallet-parachain-system/std", - "cumulus-pallet-xcm/std", - "cumulus-primitives-core/std", - "frame-executive/std", - "frame-support/std", - "frame-system/std", - "frame-try-runtime?/std", - "pallet-aura/std", - "pallet-message-queue/std", - "pallet-timestamp/std", - "parachain-info/std", - "parachains-common/std", - "scale-info/std", - "sp-api/std", - "sp-block-builder/std", - "sp-consensus-aura/std", - "sp-core/std", - "sp-genesis-builder/std", - "sp-inherents/std", - "sp-offchain/std", - "sp-runtime/std", - "sp-session/std", - "sp-transaction-pool/std", - "sp-version/std", - "substrate-wasm-builder", - "xcm-builder/std", - "xcm-executor/std", - "xcm/std", -] -try-runtime = [ - "cumulus-pallet-aura-ext/try-runtime", - "cumulus-pallet-parachain-system/try-runtime", - "cumulus-pallet-xcm/try-runtime", - "frame-executive/try-runtime", - "frame-support/try-runtime", - "frame-system/try-runtime", - "frame-try-runtime/try-runtime", - "pallet-aura/try-runtime", - "pallet-message-queue/try-runtime", - "pallet-timestamp/try-runtime", - "parachain-info/try-runtime", - "sp-runtime/try-runtime", -] diff --git a/cumulus/parachains/runtimes/starters/shell/src/lib.rs b/cumulus/parachains/runtimes/starters/shell/src/lib.rs deleted file mode 100644 index 1dfbe2b6c41c..000000000000 --- a/cumulus/parachains/runtimes/starters/shell/src/lib.rs +++ /dev/null @@ -1,450 +0,0 @@ -// 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 . - -//! # Shell Runtime -//! -//! The Shell runtime defines a minimal parachain. It can listen for a downward message authorizing -//! an upgrade into another parachain. -//! -//! Generally (so far) only used as the first parachain on a Relay. - -#![cfg_attr(not(feature = "std"), no_std)] -// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256. -#![recursion_limit = "256"] - -// Make the WASM binary available. -#[cfg(feature = "std")] -include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); - -pub mod xcm_config; - -extern crate alloc; - -use alloc::{vec, vec::Vec}; -use codec::{Decode, Encode}; -use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; -use cumulus_primitives_core::AggregateMessageOrigin; -use frame_support::unsigned::TransactionValidityError; -use scale_info::TypeInfo; -use sp_api::impl_runtime_apis; -pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; -use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; -use sp_runtime::{ - create_runtime_str, generic, impl_opaque_keys, - traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, DispatchInfoOf}, - transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, -}; -#[cfg(feature = "std")] -use sp_version::NativeVersion; -use sp_version::RuntimeVersion; - -// A few exports that help ease life for downstream crates. -pub use frame_support::{ - construct_runtime, derive_impl, - dispatch::DispatchClass, - genesis_builder_helper::{build_state, get_preset}, - parameter_types, - traits::{ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, IsInVec, Randomness}, - weights::{ - constants::{ - BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND, - }, - IdentityFee, Weight, - }, - StorageValue, -}; -use frame_system::limits::{BlockLength, BlockWeights}; -use parachains_common::{AccountId, Signature}; -#[cfg(any(feature = "std", test))] -pub use sp_runtime::BuildStorage; -pub use sp_runtime::{Perbill, Permill}; - -impl_opaque_keys! { - pub struct SessionKeys { - pub aura: Aura, - } -} - -/// This runtime version. -#[sp_version::runtime_version] -pub const VERSION: RuntimeVersion = RuntimeVersion { - spec_name: create_runtime_str!("shell"), - impl_name: create_runtime_str!("shell"), - authoring_version: 1, - spec_version: 2, - impl_version: 0, - apis: RUNTIME_API_VERSIONS, - transaction_version: 1, - state_version: 0, -}; - -/// The version information used to identify this runtime when compiled natively. -#[cfg(feature = "std")] -pub fn native_version() -> NativeVersion { - NativeVersion { runtime_version: VERSION, can_author_with: Default::default() } -} - -/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included -/// into the relay chain. -const UNINCLUDED_SEGMENT_CAPACITY: u32 = 1; -/// How many parachain blocks are processed by the relay chain per parent. Limits the -/// number of blocks authored per slot. -const BLOCK_PROCESSING_VELOCITY: u32 = 1; -/// Relay chain slot duration, in milliseconds. -const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000; - -/// We assume that ~10% of the block weight is consumed by `on_initialize` handlers. -/// This is used to limit the maximal weight of a single extrinsic. -const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); -/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used -/// by Operational extrinsics. -const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); -/// We allow for .5 seconds of compute with a 12 second average block time. -const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts( - WEIGHT_REF_TIME_PER_SECOND.saturating_div(2), - cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64, -); - -parameter_types! { - pub const BlockHashCount: BlockNumber = 250; - pub const Version: RuntimeVersion = VERSION; - pub RuntimeBlockLength: BlockLength = - BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); - pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder() - .base_block(BlockExecutionWeight::get()) - .for_class(DispatchClass::all(), |weights| { - weights.base_extrinsic = ExtrinsicBaseWeight::get(); - }) - .for_class(DispatchClass::Normal, |weights| { - weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT); - }) - .for_class(DispatchClass::Operational, |weights| { - weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT); - // Operational transactions have some extra reserved space, so that they - // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`. - weights.reserved = Some( - MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT - ); - }) - .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) - .build_or_panic(); - pub const SS58Prefix: u8 = 42; -} - -#[derive_impl(frame_system::config_preludes::TestDefaultConfig)] -impl frame_system::Config for Runtime { - /// The identifier used to distinguish between accounts. - type AccountId = AccountId; - /// The aggregated dispatch type that is available for extrinsics. - type RuntimeCall = RuntimeCall; - /// The lookup mechanism to get account ID from whatever is passed in dispatchers. - type Lookup = AccountIdLookup; - /// The index type for storing how many extrinsics an account has signed. - type Nonce = Nonce; - /// The type for hashing blocks and tries. - type Hash = Hash; - /// The hashing algorithm used. - type Hashing = BlakeTwo256; - /// The block type. - type Block = Block; - /// The ubiquitous event type. - type RuntimeEvent = RuntimeEvent; - /// The ubiquitous origin type. - type RuntimeOrigin = RuntimeOrigin; - /// Maximum number of block number to block hash mappings to keep (oldest pruned first). - type BlockHashCount = BlockHashCount; - /// Runtime version. - type Version = Version; - /// Converts a module to an index of this module in the runtime. - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type DbWeight = (); - type BaseCallFilter = frame_support::traits::Everything; - type SystemWeightInfo = (); - type BlockWeights = RuntimeBlockWeights; - type BlockLength = RuntimeBlockLength; - type SS58Prefix = SS58Prefix; - type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; - type MaxConsumers = frame_support::traits::ConstU32<16>; -} - -parameter_types! { - pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent; - pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); -} - -impl cumulus_pallet_parachain_system::Config for Runtime { - type WeightInfo = (); - type RuntimeEvent = RuntimeEvent; - type OnSystemEvent = (); - type SelfParaId = parachain_info::Pallet; - type OutboundXcmpMessageSource = (); - type DmpQueue = frame_support::traits::EnqueueWithOrigin; - type ReservedDmpWeight = ReservedDmpWeight; - type XcmpMessageHandler = (); - type ReservedXcmpWeight = (); - type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; - type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< - Runtime, - RELAY_CHAIN_SLOT_DURATION_MILLIS, - BLOCK_PROCESSING_VELOCITY, - UNINCLUDED_SEGMENT_CAPACITY, - >; -} - -impl parachain_info::Config for Runtime {} - -parameter_types! { - pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; -} - -impl pallet_message_queue::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type WeightInfo = (); - #[cfg(feature = "runtime-benchmarks")] - type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor< - cumulus_primitives_core::AggregateMessageOrigin, - >; - #[cfg(not(feature = "runtime-benchmarks"))] - type MessageProcessor = xcm_builder::ProcessXcmMessage< - AggregateMessageOrigin, - xcm_executor::XcmExecutor, - RuntimeCall, - >; - type Size = u32; - // These need to be configured to the XCMP pallet - if it is deployed. - type QueueChangeHandler = (); - type QueuePausedQuery = (); - type HeapSize = sp_core::ConstU32<{ 103 * 1024 }>; - type MaxStale = sp_core::ConstU32<8>; - type ServiceWeight = MessageQueueServiceWeight; - type IdleMaxServiceWeight = MessageQueueServiceWeight; -} - -impl cumulus_pallet_aura_ext::Config for Runtime {} - -impl pallet_aura::Config for Runtime { - type AuthorityId = AuraId; - type DisabledValidators = (); - type MaxAuthorities = ConstU32<100_000>; - type AllowMultipleBlocksPerSlot = ConstBool; - type SlotDuration = pallet_aura::MinimumPeriodTimesTwo; -} - -impl pallet_timestamp::Config for Runtime { - type Moment = u64; - type OnTimestampSet = Aura; - type MinimumPeriod = ConstU64<0>; - type WeightInfo = (); -} - -construct_runtime! { - pub enum Runtime - { - System: frame_system, - Timestamp: pallet_timestamp, - - ParachainSystem: cumulus_pallet_parachain_system, - ParachainInfo: parachain_info, - - CumulusXcm: cumulus_pallet_xcm, - MessageQueue: pallet_message_queue, - - Aura: pallet_aura, - AuraExt: cumulus_pallet_aura_ext, - } -} - -/// Simple implementation which fails any transaction which is signed. -#[derive(Eq, PartialEq, Clone, Default, sp_core::RuntimeDebug, Encode, Decode, TypeInfo)] -pub struct DisallowSigned; -impl sp_runtime::traits::SignedExtension for DisallowSigned { - const IDENTIFIER: &'static str = "DisallowSigned"; - type AccountId = AccountId; - type Call = RuntimeCall; - type AdditionalSigned = (); - type Pre = (); - fn additional_signed( - &self, - ) -> core::result::Result<(), sp_runtime::transaction_validity::TransactionValidityError> { - Ok(()) - } - fn pre_dispatch( - self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result { - self.validate(who, call, info, len).map(|_| ()) - } - fn validate( - &self, - _who: &Self::AccountId, - _call: &Self::Call, - _info: &sp_runtime::traits::DispatchInfoOf, - _len: usize, - ) -> TransactionValidity { - let i = sp_runtime::transaction_validity::InvalidTransaction::BadProof; - Err(sp_runtime::transaction_validity::TransactionValidityError::Invalid(i)) - } -} - -/// Index of a transaction in the chain. -pub type Nonce = u32; -/// A hash of some data used by the chain. -pub type Hash = sp_core::H256; -/// An index to a block. -pub type BlockNumber = u32; -/// The address format for describing accounts. -pub type Address = sp_runtime::MultiAddress; -/// Block header type as expected by this runtime. -pub type Header = generic::Header; -/// Block type as expected by this runtime. -pub type Block = generic::Block; -/// A Block signed with a Justification -pub type SignedBlock = generic::SignedBlock; -/// BlockId type as expected by this runtime. -pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = DisallowSigned; -/// Unchecked extrinsic type as expected by this runtime. -pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; -/// Executive: handles dispatch to the various modules. -pub type Executive = frame_executive::Executive< - Runtime, - Block, - frame_system::ChainContext, - Runtime, - AllPalletsWithSystem, ->; - -impl_runtime_apis! { - impl sp_consensus_aura::AuraApi for Runtime { - fn slot_duration() -> sp_consensus_aura::SlotDuration { - sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration()) - } - - fn authorities() -> Vec { - pallet_aura::Authorities::::get().into_inner() - } - } - - impl sp_api::Core for Runtime { - fn version() -> RuntimeVersion { - VERSION - } - - fn execute_block(block: Block) { - Executive::execute_block(block) - } - - fn initialize_block(header: &::Header) -> sp_runtime::ExtrinsicInclusionMode { - Executive::initialize_block(header) - } - } - - impl sp_api::Metadata for Runtime { - fn metadata() -> OpaqueMetadata { - OpaqueMetadata::new(Runtime::metadata().into()) - } - - fn metadata_at_version(version: u32) -> Option { - Runtime::metadata_at_version(version) - } - - fn metadata_versions() -> alloc::vec::Vec { - Runtime::metadata_versions() - } - } - - impl sp_block_builder::BlockBuilder for Runtime { - fn apply_extrinsic( - extrinsic: ::Extrinsic, - ) -> ApplyExtrinsicResult { - Executive::apply_extrinsic(extrinsic) - } - - fn finalize_block() -> ::Header { - Executive::finalize_block() - } - - fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<::Extrinsic> { - data.create_extrinsics() - } - - fn check_inherents(block: Block, data: sp_inherents::InherentData) -> sp_inherents::CheckInherentsResult { - data.check_extrinsics(&block) - } - } - - impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { - fn validate_transaction( - source: TransactionSource, - tx: ::Extrinsic, - block_hash: ::Hash, - ) -> TransactionValidity { - Executive::validate_transaction(source, tx, block_hash) - } - } - - impl sp_offchain::OffchainWorkerApi for Runtime { - fn offchain_worker(header: &::Header) { - Executive::offchain_worker(header) - } - } - - impl sp_session::SessionKeys for Runtime { - fn generate_session_keys(seed: Option>) -> Vec { - SessionKeys::generate(seed) - } - - fn decode_session_keys( - encoded: Vec, - ) -> Option, KeyTypeId)>> { - SessionKeys::decode_into_raw_public_keys(&encoded) - } - } - - impl cumulus_primitives_core::CollectCollationInfo for Runtime { - fn collect_collation_info(header: &::Header) -> cumulus_primitives_core::CollationInfo { - ParachainSystem::collect_collation_info(header) - } - } - - impl sp_genesis_builder::GenesisBuilder for Runtime { - fn build_state(config: Vec) -> sp_genesis_builder::Result { - build_state::(config) - } - - fn get_preset(id: &Option) -> Option> { - get_preset::(id, |_| None) - } - - fn preset_names() -> Vec { - vec![] - } - } -} - -cumulus_pallet_parachain_system::register_validate_block! { - Runtime = Runtime, - BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, -} diff --git a/cumulus/parachains/runtimes/starters/shell/src/xcm_config.rs b/cumulus/parachains/runtimes/starters/shell/src/xcm_config.rs deleted file mode 100644 index 741b3bcd752f..000000000000 --- a/cumulus/parachains/runtimes/starters/shell/src/xcm_config.rs +++ /dev/null @@ -1,100 +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. - -use super::{ - AccountId, AllPalletsWithSystem, ParachainInfo, Runtime, RuntimeCall, RuntimeEvent, - RuntimeOrigin, -}; -use frame_support::{ - parameter_types, - traits::{Contains, Everything, Nothing}, - weights::Weight, -}; -use xcm::latest::prelude::*; -use xcm_builder::{ - AllowExplicitUnpaidExecutionFrom, FixedWeightBounds, ParentAsSuperuser, ParentIsPreset, - SovereignSignedViaLocation, -}; - -parameter_types! { - pub const RococoLocation: Location = Location::parent(); - pub const RococoNetwork: NetworkId = NetworkId::Rococo; - pub UniversalLocation: InteriorLocation = [GlobalConsensus(RococoNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into(); -} - -/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance, -/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can -/// bias the kind of local `Origin` it will become. -pub type XcmOriginToTransactDispatchOrigin = ( - // Sovereign account converter; this attempts to derive an `AccountId` from the origin location - // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for - // foreign chains who want to have a local sovereign account on this chain which they control. - SovereignSignedViaLocation, RuntimeOrigin>, - // Superuser converter for the Relay-chain (Parent) location. This will allow it to issue a - // transaction from the Root origin. - ParentAsSuperuser, -); - -pub struct JustTheParent; -impl Contains for JustTheParent { - fn contains(location: &Location) -> bool { - matches!(location.unpack(), (1, [])) - } -} - -parameter_types! { - // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate. - pub UnitWeightCost: Weight = Weight::from_parts(1_000_000_000, 64 * 1024); - pub const MaxInstructions: u32 = 100; - pub const MaxAssetsIntoHolding: u32 = 64; -} - -pub struct XcmConfig; -impl xcm_executor::Config for XcmConfig { - type RuntimeCall = RuntimeCall; - type XcmSender = (); // sending XCM not supported - type AssetTransactor = (); // balances not supported - type OriginConverter = XcmOriginToTransactDispatchOrigin; - type IsReserve = (); // balances not supported - type IsTeleporter = (); // balances not supported - type UniversalLocation = UniversalLocation; - type Barrier = AllowExplicitUnpaidExecutionFrom; - type Weigher = FixedWeightBounds; // balances not supported - type Trader = (); // balances not supported - type ResponseHandler = (); // Don't handle responses for now. - type AssetTrap = (); // don't trap for now - type AssetClaims = (); // don't claim for now - type SubscriptionService = (); // don't handle subscriptions for now - type PalletInstancesInfo = AllPalletsWithSystem; - type MaxAssetsIntoHolding = MaxAssetsIntoHolding; - type AssetLocker = (); - type AssetExchanger = (); - type FeeManager = (); - type MessageExporter = (); - type UniversalAliases = Nothing; - type CallDispatcher = RuntimeCall; - type SafeCallFilter = Everything; - type Aliasers = Nothing; - type TransactionalProcessor = (); - type HrmpNewChannelOpenRequestHandler = (); - type HrmpChannelAcceptedHandler = (); - type HrmpChannelClosingHandler = (); - type XcmRecorder = (); -} - -impl cumulus_pallet_xcm::Config for Runtime { - type RuntimeEvent = RuntimeEvent; - type XcmExecutor = xcm_executor::XcmExecutor; -} diff --git a/cumulus/parachains/runtimes/test-utils/src/lib.rs b/cumulus/parachains/runtimes/test-utils/src/lib.rs index 3fc3822a63eb..36cf2bf4f83b 100644 --- a/cumulus/parachains/runtimes/test-utils/src/lib.rs +++ b/cumulus/parachains/runtimes/test-utils/src/lib.rs @@ -22,7 +22,7 @@ use cumulus_primitives_core::{ use cumulus_primitives_parachain_inherent::ParachainInherentData; use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder; use frame_support::{ - dispatch::{DispatchResult, RawOrigin}, + dispatch::{DispatchResult, GetDispatchInfo, RawOrigin}, inherent::{InherentData, ProvideInherent}, pallet_prelude::Get, traits::{OnFinalize, OnInitialize, OriginTrait, UnfilteredDispatchable}, @@ -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(); @@ -450,6 +450,7 @@ impl< require_weight_at_most, call: call.into(), }, + ExpectTransactStatus(MaybeErrorCode::Success), ]); // execute xcm as parent origin @@ -462,6 +463,38 @@ impl< Weight::zero(), ) } + + pub fn execute_as_origin_xcm( + origin: Location, + call: Call, + buy_execution_fee: Asset, + ) -> Outcome { + // prepare `Transact` xcm + let xcm = Xcm(vec![ + WithdrawAsset(buy_execution_fee.clone().into()), + BuyExecution { fees: buy_execution_fee.clone(), weight_limit: Unlimited }, + Transact { + origin_kind: OriginKind::Xcm, + require_weight_at_most: call.get_dispatch_info().call_weight, + call: call.encode().into(), + }, + ExpectTransactStatus(MaybeErrorCode::Success), + ]); + + // execute xcm as parent origin + let mut hash = xcm.using_encoded(sp_io::hashing::blake2_256); + <::XcmExecutor>::prepare_and_execute( + origin.clone(), + xcm, + &mut hash, + Self::xcm_max_weight(if origin == Location::parent() { + XcmReceivedFrom::Parent + } else { + XcmReceivedFrom::Sibling + }), + Weight::zero(), + ) + } } pub enum XcmReceivedFrom { diff --git a/cumulus/parachains/runtimes/testing/penpal/Cargo.toml b/cumulus/parachains/runtimes/testing/penpal/Cargo.toml index 1a2737f3aa22..14c4fe520384 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 @@ -42,6 +42,7 @@ pallet-transaction-payment = { workspace = true } pallet-transaction-payment-rpc-runtime-api = { workspace = true } pallet-asset-tx-payment = { workspace = true } pallet-assets = { workspace = true } +pallet-asset-conversion = { workspace = true } sp-api = { workspace = true } sp-block-builder = { workspace = true } sp-consensus-aura = { workspace = true } @@ -79,6 +80,8 @@ parachain-info = { workspace = true } parachains-common = { workspace = true } assets-common = { workspace = true } +primitive-types = { version = "0.12.1", default-features = false, features = ["codec", "num-traits", "scale-info"] } + [features] default = ["std"] std = [ @@ -99,6 +102,7 @@ std = [ "frame-system/std", "frame-try-runtime?/std", "log/std", + "pallet-asset-conversion/std", "pallet-asset-tx-payment/std", "pallet-assets/std", "pallet-aura/std", @@ -117,6 +121,7 @@ std = [ "polkadot-parachain-primitives/std", "polkadot-primitives/std", "polkadot-runtime-common/std", + "primitive-types/std", "scale-info/std", "sp-api/std", "sp-block-builder/std", @@ -149,6 +154,7 @@ runtime-benchmarks = [ "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", "hex-literal", + "pallet-asset-conversion/runtime-benchmarks", "pallet-asset-tx-payment/runtime-benchmarks", "pallet-assets/runtime-benchmarks", "pallet-balances/runtime-benchmarks", @@ -156,6 +162,7 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", @@ -176,6 +183,7 @@ try-runtime = [ "frame-support/try-runtime", "frame-system/try-runtime", "frame-try-runtime/try-runtime", + "pallet-asset-conversion/try-runtime", "pallet-asset-tx-payment/try-runtime", "pallet-assets/try-runtime", "pallet-aura/try-runtime", diff --git a/cumulus/parachains/runtimes/testing/penpal/build.rs b/cumulus/parachains/runtimes/testing/penpal/build.rs index c2fa89aa7028..e47e483bf9c1 100644 --- a/cumulus/parachains/runtimes/testing/penpal/build.rs +++ b/cumulus/parachains/runtimes/testing/penpal/build.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs index bf39c02a3f59..136592c56026 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/lib.rs @@ -35,17 +35,24 @@ pub mod xcm_config; extern crate alloc; use alloc::{vec, vec::Vec}; +use assets_common::{ + local_and_foreign_assets::{LocalFromLeft, TargetFromLeft}, + AssetIdForTrustBackedAssetsConvert, +}; use codec::Encode; use cumulus_pallet_parachain_system::RelayNumberStrictlyIncreases; -use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +use cumulus_primitives_core::{AggregateMessageOrigin, ClaimQueueOffset, CoreSelector, ParaId}; use frame_support::{ construct_runtime, derive_impl, dispatch::DispatchClass, genesis_builder_helper::{build_state, get_preset}, + ord_parameter_types, pallet_prelude::Weight, parameter_types, traits::{ - AsEnsureOriginWithArg, ConstBool, ConstU32, ConstU64, ConstU8, Everything, TransformOrigin, + tokens::{fungible, fungibles, imbalance::ResolveAssetTo}, + AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, Everything, + TransformOrigin, }, weights::{ constants::WEIGHT_REF_TIME_PER_SECOND, ConstantMultiplier, FeePolynomial, WeightToFee as _, @@ -55,7 +62,7 @@ use frame_support::{ }; use frame_system::{ limits::{BlockLength, BlockWeights}, - EnsureRoot, EnsureSigned, + EnsureRoot, EnsureSigned, EnsureSignedBy, }; use parachains_common::{ impls::{AssetsToBlockAuthor, NonZeroIssuance}, @@ -67,7 +74,7 @@ pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, - traits::{AccountIdLookup, BlakeTwo256, Block as BlockT, Dispatchable}, + traits::{AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, Dispatchable}, transaction_validity::{TransactionSource, TransactionValidity}, ApplyExtrinsicResult, }; @@ -85,7 +92,7 @@ use polkadot_runtime_common::{BlockHashCount, SlowAdjustingFeeUpdate}; use weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight}; use xcm::{ latest::prelude::{AssetId as AssetLocationId, BodyId}, - VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, + VersionedAsset, VersionedAssetId, VersionedAssets, VersionedLocation, VersionedXcm, }; use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, @@ -122,8 +129,8 @@ pub type BlockId = generic::BlockId; // Id used for identifying assets. pub type AssetId = u32; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -136,7 +143,7 @@ pub type SignedExtra = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; pub type Migrations = ( pallet_balances::migration::MigrateToTrackInactive, @@ -242,7 +249,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, - state_version: 1, + system_version: 1, }; /// This determines the average expected block time that we are targeting. @@ -413,6 +420,7 @@ impl pallet_balances::Config for Runtime { type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxFreezes = ConstU32<0>; + type DoneSlashHandler = (); } parameter_types! { @@ -427,6 +435,7 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; type OperationalFeeMultiplier = ConstU8<5>; + type WeightInfo = (); } parameter_types! { @@ -442,7 +451,9 @@ parameter_types! { // pub type AssetsForceOrigin = // EnsureOneOf, EnsureXcm>>; -impl pallet_assets::Config for Runtime { +pub type TrustBackedAssetsInstance = pallet_assets::Instance1; + +impl pallet_assets::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Balance = Balance; type AssetId = AssetId; @@ -500,6 +511,106 @@ impl pallet_assets::Config for Runtime { type BenchmarkHelper = xcm_config::XcmBenchmarkHelper; } +parameter_types! { + pub const AssetConversionPalletId: PalletId = PalletId(*b"py/ascon"); + pub const LiquidityWithdrawalFee: Permill = Permill::from_percent(0); +} + +ord_parameter_types! { + pub const AssetConversionOrigin: sp_runtime::AccountId32 = + AccountIdConversion::::into_account_truncating(&AssetConversionPalletId::get()); +} + +pub type AssetsForceOrigin = EnsureRoot; + +pub type PoolAssetsInstance = pallet_assets::Instance3; +impl pallet_assets::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type RemoveItemsLimit = ConstU32<1000>; + type AssetId = u32; + type AssetIdParameter = u32; + type Currency = Balances; + type CreateOrigin = + AsEnsureOriginWithArg>; + type ForceOrigin = AssetsForceOrigin; + type AssetDeposit = ConstU128<0>; + type AssetAccountDeposit = ConstU128<0>; + type MetadataDepositBase = ConstU128<0>; + type MetadataDepositPerByte = ConstU128<0>; + type ApprovalDeposit = ConstU128<0>; + type StringLimit = ConstU32<50>; + type Freezer = (); + type Extra = (); + type WeightInfo = pallet_assets::weights::SubstrateWeight; + type CallbackHandle = (); + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = (); +} + +/// Union fungibles implementation for `Assets` and `ForeignAssets`. +pub type LocalAndForeignAssets = fungibles::UnionOf< + Assets, + ForeignAssets, + LocalFromLeft< + AssetIdForTrustBackedAssetsConvert< + xcm_config::TrustBackedAssetsPalletLocation, + xcm::latest::Location, + >, + parachains_common::AssetIdForTrustBackedAssets, + xcm::latest::Location, + >, + xcm::latest::Location, + AccountId, +>; + +/// Union fungibles implementation for [`LocalAndForeignAssets`] and `Balances`. +pub type NativeAndAssets = fungible::UnionOf< + Balances, + LocalAndForeignAssets, + TargetFromLeft, + xcm::latest::Location, + AccountId, +>; + +pub type PoolIdToAccountId = pallet_asset_conversion::AccountIdConverter< + AssetConversionPalletId, + (xcm::latest::Location, xcm::latest::Location), +>; + +impl pallet_asset_conversion::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Balance = Balance; + type HigherPrecisionBalance = sp_core::U256; + type AssetKind = xcm::latest::Location; + type Assets = NativeAndAssets; + type PoolId = (Self::AssetKind, Self::AssetKind); + type PoolLocator = pallet_asset_conversion::WithFirstAsset< + xcm_config::RelayLocation, + AccountId, + Self::AssetKind, + PoolIdToAccountId, + >; + type PoolAssetId = u32; + type PoolAssets = PoolAssets; + type PoolSetupFee = ConstU128<0>; // Asset class deposit fees are sufficient to prevent spam + type PoolSetupFeeAsset = xcm_config::RelayLocation; + 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 = assets_common::benchmarks::AssetPairFactory< + xcm_config::RelayLocation, + parachain_info::Pallet, + xcm_config::TrustBackedAssetsPalletIndex, + xcm::latest::Location, + >; +} + parameter_types! { pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4); @@ -523,6 +634,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime { BLOCK_PROCESSING_VELOCITY, UNINCLUDED_SEGMENT_CAPACITY, >; + type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector; } impl parachain_info::Config for Runtime {} @@ -634,6 +746,19 @@ impl pallet_collator_selection::Config for Runtime { type WeightInfo = (); } +#[cfg(feature = "runtime-benchmarks")] +pub struct AssetTxHelper; + +#[cfg(feature = "runtime-benchmarks")] +impl pallet_asset_tx_payment::BenchmarkHelperTrait for AssetTxHelper { + fn create_asset_id_parameter(_id: u32) -> (u32, u32) { + unimplemented!("Penpal uses default weights"); + } + fn setup_balances_and_pool(_asset_id: u32, _account: AccountId) { + unimplemented!("Penpal uses default weights"); + } +} + impl pallet_asset_tx_payment::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Fungibles = Assets; @@ -642,10 +767,13 @@ impl pallet_asset_tx_payment::Config for Runtime { Balances, Runtime, ConvertInto, - pallet_assets::Instance1, + TrustBackedAssetsInstance, >, - AssetsToBlockAuthor, + AssetsToBlockAuthor, >; + type WeightInfo = (); + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = AssetTxHelper; } impl pallet_sudo::Config for Runtime { @@ -685,6 +813,8 @@ construct_runtime!( // The main stage. Assets: pallet_assets:: = 50, ForeignAssets: pallet_assets:: = 51, + PoolAssets: pallet_assets:: = 52, + AssetConversion: pallet_asset_conversion = 53, Sudo: pallet_sudo = 255, } @@ -694,6 +824,7 @@ construct_runtime!( mod benches { frame_benchmarking::define_benchmarks!( [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_balances, Balances] [pallet_message_queue, MessageQueue] [pallet_session, SessionBench::] @@ -849,6 +980,12 @@ impl_runtime_apis! { } } + impl cumulus_primitives_core::GetCoreSelectorApi for Runtime { + fn core_selector() -> (CoreSelector, ClaimQueueOffset) { + ParachainSystem::core_selector() + } + } + impl xcm_runtime_apis::fees::XcmPaymentApi for Runtime { fn query_acceptable_payment_assets(xcm_version: xcm::Version) -> Result, XcmPaymentApiError> { let acceptable_assets = vec![AssetLocationId(xcm_config::RelayLocation::get())]; @@ -968,6 +1105,7 @@ impl_runtime_apis! { use frame_benchmarking::{Benchmarking, BenchmarkList}; use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use cumulus_pallet_session_benchmarking::Pallet as SessionBench; let mut list = Vec::::new(); @@ -984,6 +1122,7 @@ impl_runtime_apis! { use sp_storage::TrackedStorageKey; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; impl frame_system_benchmarking::Config for Runtime {} use cumulus_pallet_session_benchmarking::Pallet as SessionBench; @@ -1024,6 +1163,15 @@ impl_runtime_apis! { vec![] } } + + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> xcm_runtime_apis::trusted_query::XcmTrustedQueryResult { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/parachains/runtimes/testing/penpal/src/weights/block_weights.rs b/cumulus/parachains/runtimes/testing/penpal/src/weights/block_weights.rs index e7fdb2aae2a0..41e30725e753 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/weights/block_weights.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/weights/block_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/testing/penpal/src/weights/extrinsic_weights.rs b/cumulus/parachains/runtimes/testing/penpal/src/weights/extrinsic_weights.rs index 1a4adb968bb7..3bd48f061bba 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/weights/extrinsic_weights.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/weights/extrinsic_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/testing/penpal/src/weights/mod.rs b/cumulus/parachains/runtimes/testing/penpal/src/weights/mod.rs index b473d49e20e6..850dae6fbd06 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/weights/mod.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/weights/mod.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/testing/penpal/src/weights/paritydb_weights.rs b/cumulus/parachains/runtimes/testing/penpal/src/weights/paritydb_weights.rs index 25679703831a..e0b1985c659c 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/weights/paritydb_weights.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/weights/paritydb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/testing/penpal/src/weights/rocksdb_weights.rs b/cumulus/parachains/runtimes/testing/penpal/src/weights/rocksdb_weights.rs index 3dd817aa6f13..c6e91b2fcffb 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/weights/rocksdb_weights.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/weights/rocksdb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Cumulus. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs index 08a2da260c57..b72d6d232a1d 100644 --- a/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs +++ b/cumulus/parachains/runtimes/testing/penpal/src/xcm_config.rs @@ -24,15 +24,19 @@ //! soon. use super::{ AccountId, AllPalletsWithSystem, AssetId as AssetIdPalletAssets, Assets, Authorship, Balance, - Balances, ForeignAssets, ForeignAssetsInstance, NonZeroIssuance, ParachainInfo, - ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, WeightToFee, - XcmpQueue, + Balances, CollatorSelection, ForeignAssets, ForeignAssetsInstance, NonZeroIssuance, + ParachainInfo, ParachainSystem, PolkadotXcm, Runtime, RuntimeCall, RuntimeEvent, RuntimeOrigin, + WeightToFee, XcmpQueue, }; use crate::{BaseDeliveryFee, FeeAssetId, TransactionByteFee}; +use assets_common::TrustBackedAssetsAsLocation; use core::marker::PhantomData; use frame_support::{ parameter_types, - traits::{ConstU32, Contains, ContainsPair, Everything, EverythingBut, Get, Nothing}, + traits::{ + tokens::imbalance::ResolveAssetTo, ConstU32, Contains, ContainsPair, Everything, + EverythingBut, Get, Nothing, PalletInfoAccess, + }, weights::Weight, }; use frame_system::EnsureRoot; @@ -45,19 +49,19 @@ use xcm::latest::prelude::*; use xcm_builder::{ AccountId32Aliases, AllowHrmpNotificationsFromRelayChain, AllowKnownQueryResponses, AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, AsPrefixedGeneralIndex, - ConvertedConcreteId, EnsureXcmOrigin, FixedWeightBounds, FrameTransactionalProcessor, - FungibleAdapter, FungiblesAdapter, IsConcrete, LocalMint, NativeAsset, NoChecking, - ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, SiblingParachainAsNative, - SiblingParachainConvertsVia, SignedAccountId32AsNative, SignedToAccountId32, + ConvertedConcreteId, DescribeAllTerminal, DescribeFamily, EnsureXcmOrigin, FixedWeightBounds, + FrameTransactionalProcessor, FungibleAdapter, FungiblesAdapter, HashedDescription, IsConcrete, + LocalMint, NativeAsset, NoChecking, ParentAsSuperuser, ParentIsPreset, RelayChainAsNative, + SendXcmFeeToAccount, SiblingParachainAsNative, SiblingParachainConvertsVia, + SignedAccountId32AsNative, SignedToAccountId32, SingleAssetExchangeAdapter, SovereignSignedViaLocation, StartsWith, TakeWeightCredit, TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic, XcmFeeManagerFromComponents, - XcmFeeToAccount, }; use xcm_executor::{traits::JustTry, XcmExecutor}; parameter_types! { pub const RelayLocation: Location = Location::parent(); - // Local native currency which is stored in `pallet_balances`` + // Local native currency which is stored in `pallet_balances` pub const PenpalNativeCurrency: Location = Location::here(); // The Penpal runtime is utilized for testing with various environment setups. // This storage item allows us to customize the `NetworkId` where Penpal is deployed. @@ -70,6 +74,10 @@ parameter_types! { Parachain(ParachainInfo::parachain_id().into()) ].into(); pub TreasuryAccount: AccountId = TREASURY_PALLET_ID.into_account_truncating(); + pub StakingPot: AccountId = CollatorSelection::account_id(); + pub TrustBackedAssetsPalletIndex: u8 = ::index() as u8; + pub TrustBackedAssetsPalletLocation: Location = + PalletInstance(TrustBackedAssetsPalletIndex::get()).into(); } /// Type for specifying how a `Location` can be converted into an `AccountId`. This is used @@ -82,6 +90,8 @@ pub type LocationToAccountId = ( SiblingParachainConvertsVia, // Straight up local `AccountId32` origins just alias directly to `AccountId`. AccountId32Aliases, + // Foreign locations alias into accounts according to a hash of their standard description. + HashedDescription>, ); /// Means for transacting assets on this chain. @@ -265,6 +275,8 @@ pub const TELEPORTABLE_ASSET_ID: u32 = 2; pub const ASSETS_PALLET_ID: u8 = 50; pub const ASSET_HUB_ID: u32 = 1000; +pub const USDT_ASSET_ID: u128 = 1984; + parameter_types! { /// The location that this chain recognizes as the Relay network's Asset Hub. pub SystemAssetHubLocation: Location = Location::new(1, [Parachain(ASSET_HUB_ID)]); @@ -282,6 +294,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(USDT_ASSET_ID)], + ); /// The Penpal runtime is utilized for testing with various environment setups. /// This storage item provides the opportunity to customize testing scenarios @@ -312,6 +328,28 @@ pub type TrustedReserves = ( pub type TrustedTeleporters = (AssetFromChain,); +/// `AssetId`/`Balance` converter for `TrustBackedAssets`. +pub type TrustBackedAssetsConvertedConcreteId = + assets_common::TrustBackedAssetsConvertedConcreteId; + +/// Asset converter for pool assets. +/// Used to convert assets in pools to the asset required for fee payment. +/// The pool must be between the first asset and the one required for fee payment. +/// This type allows paying fees with any asset in a pool with the asset required for fee payment. +pub type PoolAssetsExchanger = SingleAssetExchangeAdapter< + crate::AssetConversion, + crate::NativeAndAssets, + ( + TrustBackedAssetsAsLocation< + TrustBackedAssetsPalletLocation, + Balance, + xcm::latest::Location, + >, + ForeignAssetsConvertedConcreteId, + ), + AccountId, +>; + pub struct XcmConfig; impl xcm_executor::Config for XcmConfig { type RuntimeCall = RuntimeCall; @@ -327,18 +365,21 @@ impl xcm_executor::Config for XcmConfig { type Weigher = FixedWeightBounds; type Trader = ( UsingComponents>, - // This trader allows to pay with `is_sufficient=true` "Foreign" assets from dedicated - // `pallet_assets` instance - `ForeignAssets`. - cumulus_primitives_utility::TakeFirstAssetTrader< + cumulus_primitives_utility::SwapFirstAssetTrader< + RelayLocation, + crate::AssetConversion, + WeightToFee, + crate::NativeAndAssets, + ( + TrustBackedAssetsAsLocation< + TrustBackedAssetsPalletLocation, + Balance, + xcm::latest::Location, + >, + ForeignAssetsConvertedConcreteId, + ), + ResolveAssetTo, AccountId, - ForeignAssetFeeAsExistentialDepositMultiplierFeeCharger, - ForeignAssetsConvertedConcreteId, - ForeignAssets, - cumulus_primitives_utility::XcmFeesTo32ByteAccount< - ForeignFungiblesTransactor, - AccountId, - XcmAssetFeesReceiver, - >, >, ); type ResponseHandler = PolkadotXcm; @@ -348,10 +389,10 @@ impl xcm_executor::Config for XcmConfig { type PalletInstancesInfo = AllPalletsWithSystem; type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type AssetLocker = (); - type AssetExchanger = (); + type AssetExchanger = PoolAssetsExchanger; type FeeManager = XcmFeeManagerFromComponents< (), - XcmFeeToAccount, + SendXcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = Nothing; diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml index a0ad248bb704..bbc1185db0d8 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/Cargo.toml @@ -126,6 +126,7 @@ runtime-benchmarks = [ "pallet-message-queue/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "parachains-common/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", @@ -134,3 +135,8 @@ runtime-benchmarks = [ "xcm-builder/runtime-benchmarks", "xcm-executor/runtime-benchmarks", ] + +# A feature that should be enabled when the runtime should be built for on-chain +# deployment. This will disable stuff that shouldn't be part of the on-chain wasm +# to make it smaller, like logging for example. +on-chain-release-build = [] diff --git a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs index dff7046f1972..34bd45b6ef99 100644 --- a/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs +++ b/cumulus/parachains/runtimes/testing/rococo-parachain/src/lib.rs @@ -68,7 +68,7 @@ pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; pub use sp_runtime::BuildStorage; pub use sp_runtime::{Perbill, Permill}; -use cumulus_primitives_core::{AggregateMessageOrigin, ParaId}; +use cumulus_primitives_core::{AggregateMessageOrigin, ClaimQueueOffset, CoreSelector, ParaId}; use frame_support::traits::TransformOrigin; use parachains_common::{ impls::{AssetsFrom, NonZeroIssuance}, @@ -113,7 +113,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 6, - state_version: 0, + system_version: 0, }; pub const MILLISECS_PER_BLOCK: u64 = 6000; @@ -257,6 +257,7 @@ impl pallet_balances::Config for Runtime { type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxFreezes = ConstU32<0>; + type DoneSlashHandler = (); } impl pallet_transaction_payment::Config for Runtime { @@ -266,6 +267,7 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = (); type OperationalFeeMultiplier = ConstU8<5>; + type WeightInfo = (); } impl pallet_sudo::Config for Runtime { @@ -299,6 +301,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type ReservedXcmpWeight = ReservedXcmpWeight; type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases; type ConsensusHook = ConsensusHook; + type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector; } impl parachain_info::Config for Runtime {} @@ -653,8 +656,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -667,7 +670,7 @@ pub type SignedExtra = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -854,6 +857,12 @@ impl_runtime_apis! { ConsensusHook::can_build_upon(included_hash, slot) } } + + impl cumulus_primitives_core::GetCoreSelectorApi for Runtime { + fn core_selector() -> (CoreSelector, ClaimQueueOffset) { + ParachainSystem::core_selector() + } + } } cumulus_pallet_parachain_system::register_validate_block! { diff --git a/cumulus/polkadot-omni-node/Cargo.toml b/cumulus/polkadot-omni-node/Cargo.toml new file mode 100644 index 000000000000..a736e1ef80c5 --- /dev/null +++ b/cumulus/polkadot-omni-node/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "polkadot-omni-node" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +build = "build.rs" +description = "Generic binary that can run a parachain node with u32 block number and Aura consensus" +license = "Apache-2.0" + +[lints] +workspace = true + +[dependencies] +color-eyre = { workspace = true } + +# Local +polkadot-omni-node-lib = { workspace = true } + +[build-dependencies] +substrate-build-script-utils = { workspace = true, default-features = true } + +[features] +default = [] +runtime-benchmarks = [ + "polkadot-omni-node-lib/runtime-benchmarks", +] +try-runtime = [ + "polkadot-omni-node-lib/try-runtime", +] diff --git a/cumulus/polkadot-parachain/src/fake_runtime_api/mod.rs b/cumulus/polkadot-omni-node/build.rs similarity index 76% rename from cumulus/polkadot-parachain/src/fake_runtime_api/mod.rs rename to cumulus/polkadot-omni-node/build.rs index 29e2736b06ff..8c498735eae9 100644 --- a/cumulus/polkadot-parachain/src/fake_runtime_api/mod.rs +++ b/cumulus/polkadot-omni-node/build.rs @@ -14,8 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -//! In an ideal world this would be one runtime which would simplify the code massively. -//! This is not an ideal world - Polkadot Asset Hub has a different key type. +use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed}; -pub mod asset_hub_polkadot_aura; -pub mod aura; +fn main() { + generate_cargo_keys(); + rerun_if_git_head_changed(); +} diff --git a/cumulus/polkadot-omni-node/lib/Cargo.toml b/cumulus/polkadot-omni-node/lib/Cargo.toml new file mode 100644 index 000000000000..a690229f1695 --- /dev/null +++ b/cumulus/polkadot-omni-node/lib/Cargo.toml @@ -0,0 +1,122 @@ +[package] +name = "polkadot-omni-node-lib" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +description = "Helper library that can be used to build a parachain node" +license = "Apache-2.0" + +[lints] +workspace = true + +[lib] +path = "src/lib.rs" + +[dependencies] +async-trait = { workspace = true } +clap = { features = ["derive"], workspace = true } +codec = { workspace = true, default-features = true } +color-print = { workspace = true } +futures = { workspace = true } +log = { workspace = true, default-features = true } +serde = { features = ["derive"], workspace = true, default-features = true } +serde_json = { workspace = true, default-features = true } +docify = { workspace = true } + +# Local +jsonrpsee = { features = ["server"], workspace = true } +parachains-common = { workspace = true, default-features = true } + +# Substrate +frame-benchmarking = { optional = true, workspace = true, default-features = true } +frame-benchmarking-cli = { workspace = true, default-features = true } +sp-runtime = { workspace = true } +sp-core = { workspace = true, default-features = true } +sp-session = { workspace = true, default-features = true } +frame-try-runtime = { optional = true, workspace = true, default-features = true } +sc-consensus = { workspace = true, default-features = true } +frame-support = { optional = true, workspace = true, default-features = true } +sc-cli = { workspace = true, default-features = true } +sc-client-api = { workspace = true, default-features = true } +sc-client-db = { workspace = true, default-features = true } +sc-executor = { workspace = true, default-features = true } +sc-service = { workspace = true, default-features = true } +sc-telemetry = { workspace = true, default-features = true } +sc-transaction-pool = { workspace = true, default-features = true } +sp-transaction-pool = { workspace = true, default-features = true } +sc-network = { workspace = true, default-features = true } +sc-basic-authorship = { workspace = true, default-features = true } +sp-timestamp = { workspace = true, default-features = true } +sp-genesis-builder = { workspace = true } +sp-block-builder = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sc-chain-spec = { workspace = true, default-features = true } +sc-rpc = { workspace = true, default-features = true } +sp-version = { workspace = true, default-features = true } +sp-weights = { workspace = true, default-features = true } +sc-tracing = { workspace = true, default-features = true } +frame-system-rpc-runtime-api = { workspace = true, default-features = true } +pallet-transaction-payment = { workspace = true, default-features = true } +pallet-transaction-payment-rpc-runtime-api = { workspace = true, default-features = true } +sp-inherents = { workspace = true, default-features = true } +sp-api = { workspace = true, default-features = true } +sp-consensus-aura = { workspace = true, default-features = true } +sc-consensus-manual-seal = { workspace = true, default-features = true } +sc-sysinfo = { workspace = true, default-features = true } +prometheus-endpoint = { workspace = true, default-features = true } +substrate-frame-rpc-system = { workspace = true, default-features = true } +pallet-transaction-payment-rpc = { workspace = true, default-features = true } +substrate-state-trie-migration-rpc = { workspace = true, default-features = true } + +# Polkadot +polkadot-cli = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } + +# Cumulus +cumulus-client-cli = { workspace = true, default-features = true } +cumulus-client-collator = { workspace = true, default-features = true } +cumulus-client-consensus-aura = { workspace = true, default-features = true } +cumulus-client-consensus-relay-chain = { workspace = true, default-features = true } +cumulus-client-consensus-common = { workspace = true, default-features = true } +cumulus-client-consensus-proposer = { workspace = true, default-features = true } +cumulus-client-parachain-inherent = { workspace = true, default-features = true } +cumulus-client-service = { workspace = true, default-features = true } +cumulus-primitives-aura = { workspace = true, default-features = true } +cumulus-primitives-core = { workspace = true, default-features = true } +cumulus-relay-chain-interface = { workspace = true, default-features = true } +futures-timer = "3.0.3" + +[dev-dependencies] +assert_cmd = { workspace = true } +nix = { features = ["signal"], workspace = true } +tokio = { version = "1.32.0", features = ["macros", "parking_lot", "time"] } +wait-timeout = { workspace = true } + +[features] +default = [] +rococo-native = [ + "polkadot-cli/rococo-native", +] +westend-native = [ + "polkadot-cli/westend-native", +] +runtime-benchmarks = [ + "cumulus-primitives-core/runtime-benchmarks", + "frame-benchmarking-cli/runtime-benchmarks", + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", + "parachains-common/runtime-benchmarks", + "polkadot-cli/runtime-benchmarks", + "polkadot-primitives/runtime-benchmarks", + "sc-client-db/runtime-benchmarks", + "sc-service/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-try-runtime/try-runtime", + "pallet-transaction-payment/try-runtime", + "polkadot-cli/try-runtime", + "sp-runtime/try-runtime", +] diff --git a/cumulus/polkadot-omni-node/lib/src/cli.rs b/cumulus/polkadot-omni-node/lib/src/cli.rs new file mode 100644 index 000000000000..6ca328912bba --- /dev/null +++ b/cumulus/polkadot-omni-node/lib/src/cli.rs @@ -0,0 +1,403 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +use crate::{ + chain_spec::DiskChainSpecLoader, + common::{ + chain_spec::{Extensions, LoadSpec}, + NodeExtraArgs, + }, +}; +use clap::{Command, CommandFactory, FromArgMatches}; +use sc_chain_spec::ChainSpec; +use sc_cli::{ + CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, NetworkParams, + RpcEndpoint, SharedParams, SubstrateCli, +}; +use sc_service::{config::PrometheusConfig, BasePath}; +use std::{fmt::Debug, marker::PhantomData, path::PathBuf}; + +/// Trait that can be used to customize some of the customer-facing info related to the node binary +/// that is being built using this library. +/// +/// The related info is shown to the customer as part of logs or help messages. +/// It does not impact functionality. +pub trait CliConfig { + /// The version of the resulting node binary. + fn impl_version() -> String; + + /// The description of the resulting node binary. + fn description(executable_name: String) -> String { + format!( + "The command-line arguments provided first will be passed to the parachain node, \n\ + and the arguments provided after -- will be passed to the relay chain node. \n\ + \n\ + Example: \n\ + \n\ + {} [parachain-args] -- [relay-chain-args]", + executable_name + ) + } + + /// The author of the resulting node binary. + fn author() -> String; + + /// The support URL for the resulting node binary. + fn support_url() -> String; + + /// The starting copyright year of the resulting node binary. + fn copyright_start_year() -> u16; +} + +/// Sub-commands supported by the collator. +#[derive(Debug, clap::Subcommand)] +pub enum Subcommand { + /// Key management CLI utilities + #[command(subcommand)] + Key(sc_cli::KeySubcommand), + + /// Build a chain specification. + BuildSpec(sc_cli::BuildSpecCmd), + + /// Validate blocks. + CheckBlock(sc_cli::CheckBlockCmd), + + /// Export blocks. + ExportBlocks(sc_cli::ExportBlocksCmd), + + /// Export the state of a given block into a chain spec. + ExportState(sc_cli::ExportStateCmd), + + /// Import blocks. + ImportBlocks(sc_cli::ImportBlocksCmd), + + /// Revert the chain to a previous state. + Revert(sc_cli::RevertCmd), + + /// Remove the whole chain. + PurgeChain(cumulus_client_cli::PurgeChainCmd), + + /// Export the genesis state of the parachain. + #[command(alias = "export-genesis-state")] + ExportGenesisHead(cumulus_client_cli::ExportGenesisHeadCommand), + + /// Export the genesis wasm of the parachain. + ExportGenesisWasm(cumulus_client_cli::ExportGenesisWasmCommand), + + /// Sub-commands concerned with benchmarking. + /// The pallet benchmarking moved to the `pallet` sub-command. + #[command(subcommand)] + Benchmark(frame_benchmarking_cli::BenchmarkCmd), +} + +#[derive(clap::Parser)] +#[command( + propagate_version = true, + args_conflicts_with_subcommands = true, + subcommand_negates_reqs = true +)] +pub struct Cli { + #[arg(skip)] + pub(crate) chain_spec_loader: Option>, + + #[command(subcommand)] + pub subcommand: Option, + + #[command(flatten)] + pub run: cumulus_client_cli::RunCmd, + + /// Start a dev node that produces a block each `dev_block_time` ms. + /// + /// This is a dev option, and it won't result in starting or connecting to a parachain network. + /// The resulting node will work on its own, running the wasm blob and artificially producing + /// a block each `dev_block_time` ms, as if it was part of a parachain. + #[arg(long)] + pub dev_block_time: Option, + + /// EXPERIMENTAL: Use slot-based collator which can handle elastic scaling. + /// + /// Use with care, this flag is unstable and subject to change. + #[arg(long)] + pub experimental_use_slot_based: bool, + + /// Disable automatic hardware benchmarks. + /// + /// By default these benchmarks are automatically ran at startup and measure + /// the CPU speed, the memory bandwidth and the disk speed. + /// + /// The results are then printed out in the logs, and also sent as part of + /// telemetry, if telemetry is enabled. + #[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, + + #[arg(skip)] + pub(crate) _phantom: PhantomData, +} + +impl Cli { + pub(crate) fn node_extra_args(&self) -> NodeExtraArgs { + NodeExtraArgs { + use_slot_based_consensus: self.experimental_use_slot_based, + export_pov: self.export_pov_to_path.clone(), + } + } +} + +impl SubstrateCli for Cli { + fn impl_name() -> String { + Self::executable_name() + } + + fn impl_version() -> String { + Config::impl_version() + } + + fn description() -> String { + Config::description(Self::executable_name()) + } + + fn author() -> String { + Config::author() + } + + fn support_url() -> String { + Config::support_url() + } + + fn copyright_start_year() -> i32 { + Config::copyright_start_year() as i32 + } + + fn load_spec(&self, id: &str) -> Result, String> { + match &self.chain_spec_loader { + Some(chain_spec_loader) => chain_spec_loader.load_spec(id), + None => DiskChainSpecLoader.load_spec(id), + } + } +} + +#[derive(Debug)] +pub struct RelayChainCli { + /// The actual relay chain cli object. + pub base: polkadot_cli::RunCmd, + + /// Optional chain id that should be passed to the relay chain. + pub chain_id: Option, + + /// The base path that should be used by the relay chain. + pub base_path: Option, + + _phantom: PhantomData, +} + +impl RelayChainCli { + fn polkadot_cmd() -> Command { + let help_template = color_print::cformat!( + "The arguments that are passed to the relay chain node. \n\ + \n\ + RELAY_CHAIN_ARGS: \n\ + {{options}}", + ); + + polkadot_cli::RunCmd::command() + .no_binary_name(true) + .help_template(help_template) + } + + /// Parse the relay chain CLI parameters using the parachain `Configuration`. + pub fn new<'a>( + para_config: &sc_service::Configuration, + relay_chain_args: impl Iterator, + ) -> Self { + let polkadot_cmd = Self::polkadot_cmd(); + let matches = polkadot_cmd.get_matches_from(relay_chain_args); + let base = FromArgMatches::from_arg_matches(&matches).unwrap_or_else(|e| e.exit()); + + let extension = Extensions::try_get(&*para_config.chain_spec); + let chain_id = extension.map(|e| e.relay_chain.clone()); + + let base_path = para_config.base_path.path().join("polkadot"); + Self { base, chain_id, base_path: Some(base_path), _phantom: Default::default() } + } +} + +impl SubstrateCli for RelayChainCli { + fn impl_name() -> String { + Cli::::impl_name() + } + + fn impl_version() -> String { + Cli::::impl_version() + } + + fn description() -> String { + Cli::::description() + } + + fn author() -> String { + Cli::::author() + } + + fn support_url() -> String { + Cli::::support_url() + } + + fn copyright_start_year() -> i32 { + Cli::::copyright_start_year() + } + + fn load_spec(&self, id: &str) -> std::result::Result, String> { + polkadot_cli::Cli::from_iter([Self::executable_name()].iter()).load_spec(id) + } +} + +impl DefaultConfigurationValues for RelayChainCli { + fn p2p_listen_port() -> u16 { + 30334 + } + + fn rpc_listen_port() -> u16 { + 9945 + } + + fn prometheus_listen_port() -> u16 { + 9616 + } +} + +impl CliConfiguration for RelayChainCli { + fn shared_params(&self) -> &SharedParams { + self.base.base.shared_params() + } + + fn import_params(&self) -> Option<&ImportParams> { + self.base.base.import_params() + } + + fn network_params(&self) -> Option<&NetworkParams> { + self.base.base.network_params() + } + + fn keystore_params(&self) -> Option<&KeystoreParams> { + self.base.base.keystore_params() + } + + fn base_path(&self) -> sc_cli::Result> { + Ok(self + .shared_params() + .base_path()? + .or_else(|| self.base_path.clone().map(Into::into))) + } + + fn rpc_addr(&self, default_listen_port: u16) -> sc_cli::Result>> { + self.base.base.rpc_addr(default_listen_port) + } + + fn prometheus_config( + &self, + default_listen_port: u16, + chain_spec: &Box, + ) -> sc_cli::Result> { + self.base.base.prometheus_config(default_listen_port, chain_spec) + } + + fn init( + &self, + _support_url: &String, + _impl_version: &String, + _logger_hook: F, + ) -> sc_cli::Result<()> + where + F: FnOnce(&mut sc_cli::LoggerBuilder), + { + unreachable!("PolkadotCli is never initialized; qed"); + } + + fn chain_id(&self, is_dev: bool) -> sc_cli::Result { + let chain_id = self.base.base.chain_id(is_dev)?; + + Ok(if chain_id.is_empty() { self.chain_id.clone().unwrap_or_default() } else { chain_id }) + } + + fn role(&self, is_dev: bool) -> sc_cli::Result { + self.base.base.role(is_dev) + } + + fn transaction_pool( + &self, + is_dev: bool, + ) -> sc_cli::Result { + self.base.base.transaction_pool(is_dev) + } + + fn trie_cache_maximum_size(&self) -> sc_cli::Result> { + self.base.base.trie_cache_maximum_size() + } + + fn rpc_methods(&self) -> sc_cli::Result { + self.base.base.rpc_methods() + } + + fn rpc_max_connections(&self) -> sc_cli::Result { + self.base.base.rpc_max_connections() + } + + fn rpc_cors(&self, is_dev: bool) -> sc_cli::Result>> { + self.base.base.rpc_cors(is_dev) + } + + fn default_heap_pages(&self) -> sc_cli::Result> { + self.base.base.default_heap_pages() + } + + fn force_authoring(&self) -> sc_cli::Result { + self.base.base.force_authoring() + } + + fn disable_grandpa(&self) -> sc_cli::Result { + self.base.base.disable_grandpa() + } + + fn max_runtime_instances(&self) -> sc_cli::Result> { + self.base.base.max_runtime_instances() + } + + fn announce_block(&self) -> sc_cli::Result { + self.base.base.announce_block() + } + + fn telemetry_endpoints( + &self, + chain_spec: &Box, + ) -> sc_cli::Result> { + self.base.base.telemetry_endpoints(chain_spec) + } + + fn node_name(&self) -> sc_cli::Result { + self.base.base.node_name() + } +} diff --git a/cumulus/polkadot-omni-node/lib/src/command.rs b/cumulus/polkadot-omni-node/lib/src/command.rs new file mode 100644 index 000000000000..350dcfee1cdb --- /dev/null +++ b/cumulus/polkadot-omni-node/lib/src/command.rs @@ -0,0 +1,306 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +use crate::{ + cli::{Cli, RelayChainCli, Subcommand}, + common::{ + chain_spec::{Extensions, LoadSpec}, + runtime::{ + AuraConsensusId, Consensus, Runtime, RuntimeResolver as RuntimeResolverT, + RuntimeResolver, + }, + types::Block, + NodeBlock, NodeExtraArgs, + }, + fake_runtime_api, + nodes::DynNodeSpecExt, + runtime::BlockNumber, +}; +#[cfg(feature = "runtime-benchmarks")] +use cumulus_client_service::storage_proof_size::HostFunctions as ReclaimHostFunctions; +use cumulus_primitives_core::ParaId; +use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; +use log::info; +use sc_cli::{Result, SubstrateCli}; +use sp_runtime::traits::AccountIdConversion; +#[cfg(feature = "runtime-benchmarks")] +use sp_runtime::traits::HashingFor; + +/// Structure that can be used in order to provide customizers for different functionalities of the +/// node binary that is being built using this library. +pub struct RunConfig { + /// A custom chain spec loader. + pub chain_spec_loader: Box, + /// A custom runtime resolver. + pub runtime_resolver: Box, +} + +pub fn new_aura_node_spec( + aura_id: AuraConsensusId, + extra_args: &NodeExtraArgs, +) -> Box +where + Block: NodeBlock, +{ + match aura_id { + AuraConsensusId::Sr25519 => crate::nodes::aura::new_aura_node_spec::< + Block, + fake_runtime_api::aura_sr25519::RuntimeApi, + sp_consensus_aura::sr25519::AuthorityId, + >(extra_args), + AuraConsensusId::Ed25519 => crate::nodes::aura::new_aura_node_spec::< + Block, + fake_runtime_api::aura_ed25519::RuntimeApi, + sp_consensus_aura::ed25519::AuthorityId, + >(extra_args), + } +} + +fn new_node_spec( + config: &sc_service::Configuration, + runtime_resolver: &Box, + extra_args: &NodeExtraArgs, +) -> std::result::Result, sc_cli::Error> { + let runtime = runtime_resolver.runtime(config.chain_spec.as_ref())?; + + Ok(match runtime { + Runtime::Omni(block_number, consensus) => match (block_number, consensus) { + (BlockNumber::U32, Consensus::Aura(aura_id)) => + new_aura_node_spec::>(aura_id, extra_args), + (BlockNumber::U64, Consensus::Aura(aura_id)) => + new_aura_node_spec::>(aura_id, extra_args), + }, + }) +} + +/// Parse command line arguments into service configuration. +pub fn run(cmd_config: RunConfig) -> Result<()> { + let mut cli = Cli::::from_args(); + cli.chain_spec_loader = Some(cmd_config.chain_spec_loader); + + match &cli.subcommand { + Some(Subcommand::BuildSpec(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) + }, + Some(Subcommand::CheckBlock(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.async_run(|config| { + let node = + new_node_spec(&config, &cmd_config.runtime_resolver, &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, &cmd_config.runtime_resolver, &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, &cmd_config.runtime_resolver, &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, &cmd_config.runtime_resolver, &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, &cmd_config.runtime_resolver, &cli.node_extra_args())?; + node.prepare_revert_cmd(config, cmd) + }) + }, + Some(Subcommand::PurgeChain(cmd)) => { + let runner = cli.create_runner(cmd)?; + let polkadot_cli = + RelayChainCli::::new(runner.config(), cli.relay_chain_args.iter()); + + runner.sync_run(|config| { + let polkadot_config = SubstrateCli::create_configuration( + &polkadot_cli, + &polkadot_cli, + config.tokio_handle.clone(), + ) + .map_err(|err| format!("Relay chain argument error: {}", err))?; + + cmd.run(config, polkadot_config) + }) + }, + Some(Subcommand::ExportGenesisHead(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|config| { + let node = + new_node_spec(&config, &cmd_config.runtime_resolver, &cli.node_extra_args())?; + node.run_export_genesis_head_cmd(config, cmd) + }) + }, + Some(Subcommand::ExportGenesisWasm(cmd)) => { + let runner = cli.create_runner(cmd)?; + runner.sync_run(|_config| { + let spec = cli.load_spec(&cmd.shared_params.chain.clone().unwrap_or_default())?; + cmd.run(&*spec) + }) + }, + Some(Subcommand::Benchmark(cmd)) => { + let runner = cli.create_runner(cmd)?; + + // Switch on the concrete benchmark sub-command- + match cmd { + #[cfg(feature = "runtime-benchmarks")] + BenchmarkCmd::Pallet(cmd) => runner.sync_run(|config| { + cmd.run_with_spec::>, ReclaimHostFunctions>(Some( + config.chain_spec, + )) + }), + BenchmarkCmd::Block(cmd) => runner.sync_run(|config| { + let node = new_node_spec( + &config, + &cmd_config.runtime_resolver, + &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, + &cmd_config.runtime_resolver, + &cli.node_extra_args(), + )?; + node.run_benchmark_storage_cmd(config, cmd) + }), + BenchmarkCmd::Machine(cmd) => + runner.sync_run(|config| cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone())), + #[allow(unreachable_patterns)] + _ => Err("Benchmarking sub-command unsupported or compilation feature missing. \ + Make sure to compile with --features=runtime-benchmarks \ + to enable all supported benchmarks." + .into()), + } + }, + Some(Subcommand::Key(cmd)) => Ok(cmd.run(&cli)?), + None => { + let runner = cli.create_runner(&cli.run.normalize())?; + let polkadot_cli = + RelayChainCli::::new(runner.config(), cli.relay_chain_args.iter()); + let collator_options = cli.run.collator_options(); + + runner.run_node_until_exit(|config| async move { + let node_spec = + new_node_spec(&config, &cmd_config.runtime_resolver, &cli.node_extra_args())?; + let para_id = ParaId::from( + Extensions::try_get(&*config.chain_spec) + .map(|e| e.para_id) + .ok_or("Could not find parachain extension in chain-spec.")?, + ); + + if let Some(dev_block_time) = cli.dev_block_time { + return node_spec + .start_manual_seal_node(config, para_id, dev_block_time) + .map_err(Into::into) + } + + // If Statemint (Statemine, Westmint, Rockmine) DB exists and we're using the + // asset-hub chain spec, then rename the base path to the new chain ID. In the case + // that both file paths exist, the node will exit, as the user must decide (by + // deleting one path) the information that they want to use as their DB. + let old_name = match config.chain_spec.id() { + "asset-hub-polkadot" => Some("statemint"), + "asset-hub-kusama" => Some("statemine"), + "asset-hub-westend" => Some("westmint"), + "asset-hub-rococo" => Some("rockmine"), + _ => None, + }; + + if let Some(old_name) = old_name { + let new_path = config.base_path.config_dir(config.chain_spec.id()); + let old_path = config.base_path.config_dir(old_name); + + if old_path.exists() && new_path.exists() { + return Err(format!( + "Found legacy {} path {} and new Asset Hub path {}. \ + Delete one path such that only one exists.", + old_name, + old_path.display(), + new_path.display() + ) + .into()); + } + + if old_path.exists() { + std::fs::rename(old_path.clone(), new_path.clone())?; + info!( + "{} was renamed to Asset Hub. The filepath with associated data on disk \ + has been renamed from {} to {}.", + old_name, + old_path.display(), + new_path.display() + ); + } + } + + let hwbench = (!cli.no_hardware_benchmarks) + .then_some(config.database.path().map(|database_path| { + let _ = std::fs::create_dir_all(database_path); + sc_sysinfo::gather_hwbench( + Some(database_path), + &SUBSTRATE_REFERENCE_HARDWARE, + ) + })) + .flatten(); + + let parachain_account = + AccountIdConversion::::into_account_truncating( + ¶_id, + ); + + let tokio_handle = config.tokio_handle.clone(); + let polkadot_config = + SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle) + .map_err(|err| format!("Relay chain argument error: {}", err))?; + + info!("🪪 Parachain id: {:?}", para_id); + info!("🧾 Parachain Account: {}", parachain_account); + info!("✍️ Is collating: {}", if config.role.is_authority() { "yes" } else { "no" }); + + node_spec + .start_node( + config, + polkadot_config, + collator_options, + para_id, + hwbench, + cli.node_extra_args(), + ) + .await + .map_err(Into::into) + }) + }, + } +} diff --git a/cumulus/polkadot-parachain/src/common/aura.rs b/cumulus/polkadot-omni-node/lib/src/common/aura.rs similarity index 95% rename from cumulus/polkadot-parachain/src/common/aura.rs rename to cumulus/polkadot-omni-node/lib/src/common/aura.rs index 9f72d847926f..9e8837de7f87 100644 --- a/cumulus/polkadot-parachain/src/common/aura.rs +++ b/cumulus/polkadot-omni-node/lib/src/common/aura.rs @@ -18,9 +18,11 @@ use codec::Codec; use cumulus_primitives_aura::AuraUnincludedSegmentApi; -use cumulus_primitives_core::BlockT; use sp_consensus_aura::AuraApi; -use sp_runtime::app_crypto::{AppCrypto, AppPair, AppSignature, Pair}; +use sp_runtime::{ + app_crypto::{AppCrypto, AppPair, AppSignature, Pair}, + traits::Block as BlockT, +}; /// Convenience trait for defining the basic bounds of an `AuraId`. pub trait AuraIdT: AppCrypto + Codec + Send { diff --git a/cumulus/polkadot-omni-node/lib/src/common/chain_spec.rs b/cumulus/polkadot-omni-node/lib/src/common/chain_spec.rs new file mode 100644 index 000000000000..974d6ef2b611 --- /dev/null +++ b/cumulus/polkadot-omni-node/lib/src/common/chain_spec.rs @@ -0,0 +1,77 @@ +// 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 . + +//! Chain spec primitives. + +pub use sc_chain_spec::ChainSpec; +use sc_chain_spec::ChainSpecExtension; +use serde::{Deserialize, Serialize}; +use std::fmt::Debug; + +/// Helper trait used for loading/building a chain spec starting from the chain ID. +pub trait LoadSpec { + /// Load/Build a chain spec starting from the chain ID. + fn load_spec(&self, id: &str) -> Result, String>; +} + +/// Default implementation for `LoadSpec` that just reads a chain spec from the disk. +pub struct DiskChainSpecLoader; + +impl LoadSpec for DiskChainSpecLoader { + fn load_spec(&self, path: &str) -> Result, String> { + Ok(Box::new(GenericChainSpec::from_json_file(path.into())?)) + } +} + +/// Generic extensions for Parachain ChainSpecs. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecExtension)] +pub struct Extensions { + /// The relay chain of the Parachain. + #[serde(alias = "relayChain", alias = "RelayChain")] + pub relay_chain: String, + /// The id of the Parachain. + #[serde(alias = "paraId", alias = "ParaId")] + pub para_id: u32, +} + +impl Extensions { + /// Try to get the extension from the given `ChainSpec`. + pub fn try_get(chain_spec: &dyn sc_service::ChainSpec) -> Option<&Self> { + sc_chain_spec::get_extension(chain_spec.extensions()) + } +} + +/// Generic chain spec for all polkadot-parachain runtimes +pub type GenericChainSpec = sc_service::GenericChainSpec; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn can_decode_extension_camel_and_snake_case() { + let camel_case = r#"{"relayChain":"relay","paraId":1}"#; + let snake_case = r#"{"relay_chain":"relay","para_id":1}"#; + let pascal_case = r#"{"RelayChain":"relay","ParaId":1}"#; + + let camel_case_extension: Extensions = serde_json::from_str(camel_case).unwrap(); + let snake_case_extension: Extensions = serde_json::from_str(snake_case).unwrap(); + let pascal_case_extension: Extensions = serde_json::from_str(pascal_case).unwrap(); + + assert_eq!(camel_case_extension, snake_case_extension); + assert_eq!(snake_case_extension, pascal_case_extension); + } +} diff --git a/cumulus/polkadot-omni-node/lib/src/common/command.rs b/cumulus/polkadot-omni-node/lib/src/common/command.rs new file mode 100644 index 000000000000..a60fc9232d91 --- /dev/null +++ b/cumulus/polkadot-omni-node/lib/src/common/command.rs @@ -0,0 +1,161 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +use crate::common::spec::BaseNodeSpec; +use cumulus_client_cli::ExportGenesisHeadCommand; +use frame_benchmarking_cli::BlockCmd; +#[cfg(any(feature = "runtime-benchmarks"))] +use frame_benchmarking_cli::StorageCmd; +use sc_cli::{CheckBlockCmd, ExportBlocksCmd, ExportStateCmd, ImportBlocksCmd, RevertCmd}; +use sc_service::{Configuration, TaskManager}; +use std::{future::Future, pin::Pin}; + +type SyncCmdResult = sc_cli::Result<()>; + +type AsyncCmdResult<'a> = + sc_cli::Result<(Pin + 'a>>, TaskManager)>; + +pub trait NodeCommandRunner { + fn prepare_check_block_cmd( + self: Box, + config: Configuration, + cmd: &CheckBlockCmd, + ) -> AsyncCmdResult<'_>; + + fn prepare_export_blocks_cmd( + self: Box, + config: Configuration, + cmd: &ExportBlocksCmd, + ) -> AsyncCmdResult<'_>; + + fn prepare_export_state_cmd( + self: Box, + config: Configuration, + cmd: &ExportStateCmd, + ) -> AsyncCmdResult<'_>; + + fn prepare_import_blocks_cmd( + self: Box, + config: Configuration, + cmd: &ImportBlocksCmd, + ) -> AsyncCmdResult<'_>; + + fn prepare_revert_cmd( + self: Box, + config: Configuration, + cmd: &RevertCmd, + ) -> AsyncCmdResult<'_>; + + fn run_export_genesis_head_cmd( + self: Box, + config: Configuration, + cmd: &ExportGenesisHeadCommand, + ) -> SyncCmdResult; + + fn run_benchmark_block_cmd( + self: Box, + config: Configuration, + cmd: &BlockCmd, + ) -> SyncCmdResult; + + #[cfg(any(feature = "runtime-benchmarks"))] + fn run_benchmark_storage_cmd( + self: Box, + config: Configuration, + cmd: &StorageCmd, + ) -> SyncCmdResult; +} + +impl NodeCommandRunner for T +where + T: BaseNodeSpec, +{ + fn prepare_check_block_cmd( + self: Box, + config: Configuration, + cmd: &CheckBlockCmd, + ) -> AsyncCmdResult<'_> { + let partial = T::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, partial.import_queue)), partial.task_manager)) + } + + fn prepare_export_blocks_cmd( + self: Box, + config: Configuration, + cmd: &ExportBlocksCmd, + ) -> AsyncCmdResult<'_> { + let partial = T::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, config.database)), partial.task_manager)) + } + + fn prepare_export_state_cmd( + self: Box, + config: Configuration, + cmd: &ExportStateCmd, + ) -> AsyncCmdResult<'_> { + let partial = T::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, config.chain_spec)), partial.task_manager)) + } + + fn prepare_import_blocks_cmd( + self: Box, + config: Configuration, + cmd: &ImportBlocksCmd, + ) -> AsyncCmdResult<'_> { + let partial = T::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, partial.import_queue)), partial.task_manager)) + } + + fn prepare_revert_cmd( + self: Box, + config: Configuration, + cmd: &RevertCmd, + ) -> AsyncCmdResult<'_> { + let partial = T::new_partial(&config).map_err(sc_cli::Error::Service)?; + Ok((Box::pin(cmd.run(partial.client, partial.backend, None)), partial.task_manager)) + } + + fn run_export_genesis_head_cmd( + self: Box, + config: Configuration, + cmd: &ExportGenesisHeadCommand, + ) -> SyncCmdResult { + let partial = T::new_partial(&config).map_err(sc_cli::Error::Service)?; + cmd.run(partial.client) + } + + fn run_benchmark_block_cmd( + self: Box, + config: Configuration, + cmd: &BlockCmd, + ) -> SyncCmdResult { + let partial = T::new_partial(&config).map_err(sc_cli::Error::Service)?; + cmd.run(partial.client) + } + + #[cfg(any(feature = "runtime-benchmarks"))] + fn run_benchmark_storage_cmd( + self: Box, + config: Configuration, + cmd: &StorageCmd, + ) -> SyncCmdResult { + let partial = T::new_partial(&config).map_err(sc_cli::Error::Service)?; + let db = partial.backend.expose_db(); + let storage = partial.backend.expose_storage(); + + cmd.run(config, partial.client, db, storage) + } +} diff --git a/cumulus/polkadot-parachain/src/common/mod.rs b/cumulus/polkadot-omni-node/lib/src/common/mod.rs similarity index 64% rename from cumulus/polkadot-parachain/src/common/mod.rs rename to cumulus/polkadot-omni-node/lib/src/common/mod.rs index 9f5febafe304..37660a5347a2 100644 --- a/cumulus/polkadot-parachain/src/common/mod.rs +++ b/cumulus/polkadot-omni-node/lib/src/common/mod.rs @@ -18,14 +18,45 @@ #![warn(missing_docs)] -pub mod aura; +pub(crate) mod aura; +pub mod chain_spec; +pub mod command; +pub mod rpc; +pub mod runtime; +pub mod spec; +pub mod types; -use cumulus_primitives_core::CollectCollationInfo; +use cumulus_primitives_core::{CollectCollationInfo, GetCoreSelectorApi}; +use sc_client_db::DbHash; +use serde::de::DeserializeOwned; use sp_api::{ApiExt, CallApiAt, ConstructRuntimeApi, Metadata}; use sp_block_builder::BlockBuilder; -use sp_runtime::traits::Block as BlockT; +use sp_runtime::{ + traits::{Block as BlockT, BlockNumber, Header as HeaderT, NumberFor}, + OpaqueExtrinsic, +}; use sp_session::SessionKeys; use sp_transaction_pool::runtime_api::TaggedTransactionQueue; +use std::{fmt::Debug, path::PathBuf, str::FromStr}; + +pub trait NodeBlock: + BlockT + DeserializeOwned +{ + type BoundedFromStrErr: Debug; + type BoundedNumber: FromStr + BlockNumber; + type BoundedHeader: HeaderT + Unpin; +} + +impl NodeBlock for T +where + T: BlockT + DeserializeOwned, + ::Header: Unpin, + as FromStr>::Err: Debug, +{ + type BoundedFromStrErr = as FromStr>::Err; + type BoundedNumber = NumberFor; + type BoundedHeader = ::Header; +} /// Convenience trait that defines the basic bounds for the `RuntimeApi` of a parachain node. pub trait NodeRuntimeApi: @@ -35,6 +66,7 @@ pub trait NodeRuntimeApi: + BlockBuilder + TaggedTransactionQueue + CollectCollationInfo + + GetCoreSelectorApi + Sized { } @@ -45,6 +77,7 @@ impl NodeRuntimeApi for T where + SessionKeys + BlockBuilder + TaggedTransactionQueue + + GetCoreSelectorApi + CollectCollationInfo { } @@ -69,4 +102,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/rpc.rs b/cumulus/polkadot-omni-node/lib/src/common/rpc.rs similarity index 52% rename from cumulus/polkadot-parachain/src/rpc.rs rename to cumulus/polkadot-omni-node/lib/src/common/rpc.rs index 283a73d931d7..4879bd1eb7f4 100644 --- a/cumulus/polkadot-parachain/src/rpc.rs +++ b/cumulus/polkadot-omni-node/lib/src/common/rpc.rs @@ -18,16 +18,13 @@ #![warn(missing_docs)] -use crate::{ - common::ConstructNodeRuntimeApi, - service::{ParachainBackend, ParachainClient}, +use crate::common::{ + types::{AccountId, Balance, Nonce, ParachainBackend, ParachainClient}, + ConstructNodeRuntimeApi, }; use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer}; -use parachains_common::{AccountId, Balance, Block, Nonce}; -use sc_rpc::{ - dev::{Dev, DevApiServer}, - DenyUnsafe, -}; +use sc_rpc::dev::{Dev, DevApiServer}; +use sp_runtime::traits::Block as BlockT; use std::{marker::PhantomData, sync::Arc}; use substrate_frame_rpc_system::{System, SystemApiServer}; use substrate_state_trie_migration_rpc::{StateMigration, StateMigrationApiServer}; @@ -37,60 +34,40 @@ pub type RpcExtension = jsonrpsee::RpcModule<()>; pub(crate) trait BuildRpcExtensions { fn build_rpc_extensions( - deny_unsafe: DenyUnsafe, client: Arc, backend: Arc, pool: Arc, ) -> sc_service::error::Result; } -pub(crate) struct BuildEmptyRpcExtensions(PhantomData); - -impl - BuildRpcExtensions< - ParachainClient, - ParachainBackend, - sc_transaction_pool::FullPool>, - > for BuildEmptyRpcExtensions -where - RuntimeApi: ConstructNodeRuntimeApi> + Send + Sync + 'static, -{ - fn build_rpc_extensions( - _deny_unsafe: DenyUnsafe, - _client: Arc>, - _backend: Arc, - _pool: Arc>>, - ) -> sc_service::error::Result { - Ok(RpcExtension::new(())) - } -} - -pub(crate) struct BuildParachainRpcExtensions(PhantomData); +pub(crate) struct BuildParachainRpcExtensions(PhantomData<(Block, RuntimeApi)>); -impl +impl BuildRpcExtensions< - ParachainClient, - ParachainBackend, - sc_transaction_pool::FullPool>, - > for BuildParachainRpcExtensions + ParachainClient, + ParachainBackend, + sc_transaction_pool::TransactionPoolHandle>, + > for BuildParachainRpcExtensions where - RuntimeApi: ConstructNodeRuntimeApi> + Send + Sync + 'static, + RuntimeApi: + ConstructNodeRuntimeApi> + Send + Sync + 'static, RuntimeApi::RuntimeApi: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + substrate_frame_rpc_system::AccountNonceApi, { fn build_rpc_extensions( - deny_unsafe: DenyUnsafe, - client: Arc>, - backend: Arc, - pool: Arc>>, + client: Arc>, + backend: Arc>, + pool: Arc< + sc_transaction_pool::TransactionPoolHandle>, + >, ) -> sc_service::error::Result { let build = || -> Result> { let mut module = RpcExtension::new(()); - module.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?; + module.merge(System::new(client.clone(), pool).into_rpc())?; module.merge(TransactionPayment::new(client.clone()).into_rpc())?; - module.merge(StateMigration::new(client.clone(), backend, deny_unsafe).into_rpc())?; - module.merge(Dev::new(client, deny_unsafe).into_rpc())?; + module.merge(StateMigration::new(client.clone(), backend).into_rpc())?; + module.merge(Dev::new(client).into_rpc())?; Ok(module) }; diff --git a/cumulus/polkadot-omni-node/lib/src/common/runtime.rs b/cumulus/polkadot-omni-node/lib/src/common/runtime.rs new file mode 100644 index 000000000000..509d13b9d7a2 --- /dev/null +++ b/cumulus/polkadot-omni-node/lib/src/common/runtime.rs @@ -0,0 +1,68 @@ +// 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 . + +//! Runtime parameters. + +use sc_chain_spec::ChainSpec; + +/// The Aura ID used by the Aura consensus +#[derive(PartialEq)] +pub enum AuraConsensusId { + /// Ed25519 + Ed25519, + /// Sr25519 + Sr25519, +} + +/// The choice of consensus for the parachain omni-node. +#[derive(PartialEq)] +pub enum Consensus { + /// Aura consensus. + Aura(AuraConsensusId), +} + +/// The choice of block number for the parachain omni-node. +#[derive(PartialEq)] +pub enum BlockNumber { + /// u32 + U32, + /// u64 + U64, +} + +/// Helper enum listing the supported Runtime types +#[derive(PartialEq)] +pub enum Runtime { + /// None of the system-chain runtimes, rather the node will act agnostic to the runtime ie. be + /// an omni-node, and simply run a node with the given consensus algorithm. + Omni(BlockNumber, Consensus), +} + +/// Helper trait used for extracting the Runtime variant from the chain spec ID. +pub trait RuntimeResolver { + /// Extract the Runtime variant from the chain spec ID. + fn runtime(&self, chain_spec: &dyn ChainSpec) -> sc_cli::Result; +} + +/// Default implementation for `RuntimeResolver` that just returns +/// `Runtime::Omni(BlockNumber::U32, Consensus::Aura(AuraConsensusId::Sr25519))`. +pub struct DefaultRuntimeResolver; + +impl RuntimeResolver for DefaultRuntimeResolver { + fn runtime(&self, _chain_spec: &dyn ChainSpec) -> sc_cli::Result { + Ok(Runtime::Omni(BlockNumber::U32, Consensus::Aura(AuraConsensusId::Sr25519))) + } +} diff --git a/cumulus/polkadot-omni-node/lib/src/common/spec.rs b/cumulus/polkadot-omni-node/lib/src/common/spec.rs new file mode 100644 index 000000000000..8397cb778dcf --- /dev/null +++ b/cumulus/polkadot-omni-node/lib/src/common/spec.rs @@ -0,0 +1,407 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +use crate::common::{ + command::NodeCommandRunner, + rpc::BuildRpcExtensions, + types::{ + ParachainBackend, ParachainBlockImport, ParachainClient, ParachainHostFunctions, + ParachainService, + }, + ConstructNodeRuntimeApi, NodeBlock, NodeExtraArgs, +}; +use cumulus_client_cli::CollatorOptions; +use cumulus_client_service::{ + build_network, build_relay_chain_interface, prepare_node_config, start_relay_chain_tasks, + BuildNetworkParams, CollatorSybilResistance, DARecoveryProfile, StartRelayChainTasksParams, +}; +use cumulus_primitives_core::{BlockT, ParaId}; +use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface}; +use parachains_common::Hash; +use polkadot_primitives::CollatorPair; +use prometheus_endpoint::Registry; +use sc_consensus::DefaultImportQueue; +use sc_executor::{HeapAllocStrategy, DEFAULT_HEAP_ALLOC_STRATEGY}; +use sc_network::{config::FullNetworkConfiguration, NetworkBackend, NetworkBlock}; +use sc_service::{Configuration, ImportQueue, PartialComponents, TaskManager}; +use sc_sysinfo::HwBench; +use sc_telemetry::{TelemetryHandle, TelemetryWorker}; +use sc_tracing::tracing::Instrument; +use sc_transaction_pool::TransactionPoolHandle; +use sp_keystore::KeystorePtr; +use std::{future::Future, pin::Pin, sync::Arc, time::Duration}; + +pub(crate) trait BuildImportQueue { + fn build_import_queue( + client: Arc>, + block_import: ParachainBlockImport, + config: &Configuration, + telemetry_handle: Option, + task_manager: &TaskManager, + ) -> sc_service::error::Result>; +} + +pub(crate) trait StartConsensus +where + RuntimeApi: ConstructNodeRuntimeApi>, +{ + fn start_consensus( + client: Arc>, + block_import: ParachainBlockImport, + prometheus_registry: Option<&Registry>, + telemetry: Option, + task_manager: &TaskManager, + relay_chain_interface: Arc, + transaction_pool: Arc>>, + keystore: KeystorePtr, + relay_chain_slot_duration: Duration, + para_id: ParaId, + collator_key: CollatorPair, + overseer_handle: OverseerHandle, + announce_block: Arc>) + Send + Sync>, + backend: Arc>, + node_extra_args: NodeExtraArgs, + ) -> Result<(), sc_service::Error>; +} + +/// Checks that the hardware meets the requirements and print a warning otherwise. +fn warn_if_slow_hardware(hwbench: &sc_sysinfo::HwBench) { + // Polkadot para-chains should generally use these requirements to ensure that the relay-chain + // will not take longer than expected to import its blocks. + if let Err(err) = + frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE.check_hardware(hwbench, false) + { + log::warn!( + "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority' find out more at:\n\ + https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", + err + ); + } +} + +pub(crate) trait BaseNodeSpec { + type Block: NodeBlock; + + type RuntimeApi: ConstructNodeRuntimeApi< + Self::Block, + ParachainClient, + >; + + type BuildImportQueue: BuildImportQueue; + + /// Starts a `ServiceBuilder` for a full service. + /// + /// Use this macro if you don't actually need the full service, but just the builder in order to + /// be able to perform chain operations. + fn new_partial( + config: &Configuration, + ) -> sc_service::error::Result> { + let telemetry = config + .telemetry_endpoints + .clone() + .filter(|x| !x.is_empty()) + .map(|endpoints| -> Result<_, sc_telemetry::Error> { + let worker = TelemetryWorker::new(16)?; + let telemetry = worker.handle().new_telemetry(endpoints); + Ok((worker, telemetry)) + }) + .transpose()?; + + let heap_pages = + config.executor.default_heap_pages.map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| { + HeapAllocStrategy::Static { extra_pages: h as _ } + }); + + let executor = sc_executor::WasmExecutor::::builder() + .with_execution_method(config.executor.wasm_method) + .with_max_runtime_instances(config.executor.max_runtime_instances) + .with_runtime_cache_size(config.executor.runtime_cache_size) + .with_onchain_heap_alloc_strategy(heap_pages) + .with_offchain_heap_alloc_strategy(heap_pages) + .build(); + + let (client, backend, keystore_container, task_manager) = + sc_service::new_full_parts_record_import::( + config, + telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), + executor, + true, + )?; + let client = Arc::new(client); + + let telemetry_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle()); + + let telemetry = telemetry.map(|(worker, telemetry)| { + task_manager.spawn_handle().spawn("telemetry", None, worker.run()); + telemetry + }); + + let transaction_pool = Arc::from( + sc_transaction_pool::Builder::new( + task_manager.spawn_essential_handle(), + client.clone(), + config.role.is_authority().into(), + ) + .with_options(config.transaction_pool.clone()) + .with_prometheus(config.prometheus_registry()) + .build(), + ); + + let block_import = ParachainBlockImport::new(client.clone(), backend.clone()); + + let import_queue = Self::BuildImportQueue::build_import_queue( + client.clone(), + block_import.clone(), + config, + telemetry.as_ref().map(|telemetry| telemetry.handle()), + &task_manager, + )?; + + Ok(PartialComponents { + backend, + client, + import_queue, + keystore_container, + task_manager, + transaction_pool, + select_chain: (), + other: (block_import, telemetry, telemetry_worker_handle), + }) + } +} + +pub(crate) trait NodeSpec: BaseNodeSpec { + type BuildRpcExtensions: BuildRpcExtensions< + ParachainClient, + ParachainBackend, + TransactionPoolHandle>, + >; + + type StartConsensus: StartConsensus; + + const SYBIL_RESISTANCE: CollatorSybilResistance; + + /// Start a node with the given parachain spec. + /// + /// This is the actual implementation that is abstract over the executor and the runtime api. + fn start_node( + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, + node_extra_args: NodeExtraArgs, + ) -> Pin>>> + where + Net: NetworkBackend, + { + Box::pin( + async move { + let parachain_config = prepare_node_config(parachain_config); + + let params = Self::new_partial(¶chain_config)?; + let (block_import, mut telemetry, telemetry_worker_handle) = params.other; + + let client = params.client.clone(); + let backend = params.backend.clone(); + + let mut task_manager = params.task_manager; + let (relay_chain_interface, collator_key) = build_relay_chain_interface( + polkadot_config, + ¶chain_config, + telemetry_worker_handle, + &mut task_manager, + collator_options.clone(), + hwbench.clone(), + ) + .await + .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; + + let validator = parachain_config.role.is_authority(); + let prometheus_registry = parachain_config.prometheus_registry().cloned(); + let transaction_pool = params.transaction_pool.clone(); + let import_queue_service = params.import_queue.service(); + let net_config = FullNetworkConfiguration::<_, _, Net>::new( + ¶chain_config.network, + prometheus_registry.clone(), + ); + + let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = + build_network(BuildNetworkParams { + parachain_config: ¶chain_config, + net_config, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + para_id, + spawn_handle: task_manager.spawn_handle(), + relay_chain_interface: relay_chain_interface.clone(), + import_queue: params.import_queue, + sybil_resistance_level: Self::SYBIL_RESISTANCE, + }) + .await?; + + let rpc_builder = { + let client = client.clone(); + let transaction_pool = transaction_pool.clone(); + let backend_for_rpc = backend.clone(); + + Box::new(move |_| { + Self::BuildRpcExtensions::build_rpc_extensions( + client.clone(), + backend_for_rpc.clone(), + transaction_pool.clone(), + ) + }) + }; + + sc_service::spawn_tasks(sc_service::SpawnTasksParams { + rpc_builder, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + task_manager: &mut task_manager, + config: parachain_config, + keystore: params.keystore_container.keystore(), + backend: backend.clone(), + network: network.clone(), + sync_service: sync_service.clone(), + system_rpc_tx, + tx_handler_controller, + telemetry: telemetry.as_mut(), + })?; + + if let Some(hwbench) = hwbench { + sc_sysinfo::print_hwbench(&hwbench); + if validator { + warn_if_slow_hardware(&hwbench); + } + + if let Some(ref mut telemetry) = telemetry { + let telemetry_handle = telemetry.handle(); + task_manager.spawn_handle().spawn( + "telemetry_hwbench", + None, + sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench), + ); + } + } + + let announce_block = { + let sync_service = sync_service.clone(); + Arc::new(move |hash, data| sync_service.announce_block(hash, data)) + }; + + let relay_chain_slot_duration = Duration::from_secs(6); + + let overseer_handle = relay_chain_interface + .overseer_handle() + .map_err(|e| sc_service::Error::Application(Box::new(e)))?; + + start_relay_chain_tasks(StartRelayChainTasksParams { + client: client.clone(), + announce_block: announce_block.clone(), + para_id, + relay_chain_interface: relay_chain_interface.clone(), + task_manager: &mut task_manager, + da_recovery_profile: if validator { + DARecoveryProfile::Collator + } else { + DARecoveryProfile::FullNode + }, + import_queue: import_queue_service, + relay_chain_slot_duration, + recovery_handle: Box::new(overseer_handle.clone()), + sync_service, + })?; + + if validator { + Self::StartConsensus::start_consensus( + client.clone(), + block_import, + prometheus_registry.as_ref(), + telemetry.as_ref().map(|t| t.handle()), + &task_manager, + relay_chain_interface.clone(), + transaction_pool, + params.keystore_container.keystore(), + relay_chain_slot_duration, + para_id, + collator_key.expect("Command line arguments do not allow this. qed"), + overseer_handle, + announce_block, + backend.clone(), + node_extra_args, + )?; + } + + start_network.start_network(); + + Ok(task_manager) + } + .instrument(sc_tracing::tracing::info_span!( + sc_tracing::logging::PREFIX_LOG_SPAN, + name = "Parachain", + )), + ) + } +} + +pub(crate) trait DynNodeSpec: NodeCommandRunner { + fn start_node( + self: Box, + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, + node_extra_args: NodeExtraArgs, + ) -> Pin>>>; +} + +impl DynNodeSpec for T +where + T: NodeSpec + NodeCommandRunner, +{ + fn start_node( + self: Box, + parachain_config: Configuration, + polkadot_config: Configuration, + collator_options: CollatorOptions, + para_id: ParaId, + hwbench: Option, + node_extra_args: NodeExtraArgs, + ) -> Pin>>> { + match parachain_config.network.network_backend { + sc_network::config::NetworkBackendType::Libp2p => + ::start_node::>( + parachain_config, + polkadot_config, + collator_options, + para_id, + hwbench, + node_extra_args, + ), + sc_network::config::NetworkBackendType::Litep2p => + ::start_node::( + parachain_config, + polkadot_config, + collator_options, + para_id, + hwbench, + node_extra_args, + ), + } + } +} diff --git a/cumulus/polkadot-omni-node/lib/src/common/types.rs b/cumulus/polkadot-omni-node/lib/src/common/types.rs new file mode 100644 index 000000000000..4bc58dc9db7e --- /dev/null +++ b/cumulus/polkadot-omni-node/lib/src/common/types.rs @@ -0,0 +1,56 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +use cumulus_client_consensus_common::ParachainBlockImport as TParachainBlockImport; +use cumulus_primitives_core::relay_chain::UncheckedExtrinsic; +use sc_consensus::DefaultImportQueue; +use sc_executor::WasmExecutor; +use sc_service::{PartialComponents, TFullBackend, TFullClient}; +use sc_telemetry::{Telemetry, TelemetryWorkerHandle}; +use sc_transaction_pool::TransactionPoolHandle; +use sp_runtime::{generic, traits::BlakeTwo256}; +use std::sync::Arc; + +pub use parachains_common::{AccountId, Balance, Hash, Nonce}; + +type Header = generic::Header; +pub type Block = generic::Block, UncheckedExtrinsic>; + +#[cfg(not(feature = "runtime-benchmarks"))] +pub type ParachainHostFunctions = cumulus_client_service::ParachainHostFunctions; +#[cfg(feature = "runtime-benchmarks")] +pub type ParachainHostFunctions = ( + cumulus_client_service::ParachainHostFunctions, + frame_benchmarking::benchmarking::HostFunctions, +); + +pub type ParachainClient = + TFullClient>; + +pub type ParachainBackend = TFullBackend; + +pub type ParachainBlockImport = + TParachainBlockImport>, ParachainBackend>; + +/// Assembly of PartialComponents (enough to run chain ops subcommands) +pub type ParachainService = PartialComponents< + ParachainClient, + ParachainBackend, + (), + DefaultImportQueue, + TransactionPoolHandle>, + (ParachainBlockImport, Option, Option), +>; diff --git a/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/mod.rs b/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/mod.rs new file mode 100644 index 000000000000..bd4ff167d8f1 --- /dev/null +++ b/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/mod.rs @@ -0,0 +1,37 @@ +// 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 . + +//! In an ideal world this would be one runtime which would simplify the code massively. +//! This is not an ideal world - Polkadot Asset Hub has a different key type. + +mod utils; + +use utils::{impl_node_runtime_apis, imports::*}; + +type CustomBlock = crate::common::types::Block; +pub mod aura_sr25519 { + use super::*; + #[allow(dead_code)] + struct FakeRuntime; + impl_node_runtime_apis!(FakeRuntime, CustomBlock, sp_consensus_aura::sr25519::AuthorityId); +} + +pub mod aura_ed25519 { + use super::*; + #[allow(dead_code)] + struct FakeRuntime; + impl_node_runtime_apis!(FakeRuntime, CustomBlock, sp_consensus_aura::ed25519::AuthorityId); +} diff --git a/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/utils.rs b/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/utils.rs new file mode 100644 index 000000000000..0b1ed5d82889 --- /dev/null +++ b/cumulus/polkadot-omni-node/lib/src/fake_runtime_api/utils.rs @@ -0,0 +1,227 @@ +// 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 . + +pub(crate) mod imports { + pub use cumulus_primitives_core::{ClaimQueueOffset, CoreSelector}; + pub use parachains_common::{AccountId, Balance, Nonce}; + pub use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; + pub use sp_runtime::{ + traits::Block as BlockT, + transaction_validity::{TransactionSource, TransactionValidity}, + ApplyExtrinsicResult, + }; + pub use sp_weights::Weight; +} + +macro_rules! impl_node_runtime_apis { + ($runtime: ty, $block: tt, $aura_id: ty) => { + sp_api::impl_runtime_apis! { + impl sp_api::Core<$block> for $runtime { + fn version() -> sp_version::RuntimeVersion { + unimplemented!() + } + + fn execute_block(_: $block) { + unimplemented!() + } + + fn initialize_block( + _: &<$block as BlockT>::Header + ) -> sp_runtime::ExtrinsicInclusionMode { + unimplemented!() + } + } + + impl sp_api::Metadata<$block> for $runtime { + fn metadata() -> OpaqueMetadata { + unimplemented!() + } + + fn metadata_at_version(_: u32) -> Option { + unimplemented!() + } + + fn metadata_versions() -> Vec { + unimplemented!() + } + } + + impl sp_consensus_aura::AuraApi<$block, $aura_id> for $runtime { + fn slot_duration() -> sp_consensus_aura::SlotDuration { + unimplemented!() + } + + fn authorities() -> Vec<$aura_id> { + unimplemented!() + } + } + + impl cumulus_primitives_aura::AuraUnincludedSegmentApi<$block> for $runtime { + fn can_build_upon( + _: <$block as BlockT>::Hash, + _: cumulus_primitives_aura::Slot, + ) -> bool { + unimplemented!() + } + } + + impl sp_block_builder::BlockBuilder<$block> for $runtime { + fn apply_extrinsic(_: <$block as BlockT>::Extrinsic) -> ApplyExtrinsicResult { + unimplemented!() + } + + fn finalize_block() -> <$block as BlockT>::Header { + unimplemented!() + } + + fn inherent_extrinsics( + _: sp_inherents::InherentData + ) -> Vec<<$block as BlockT>::Extrinsic> { + unimplemented!() + } + + fn check_inherents( + _: $block, + _: sp_inherents::InherentData + ) -> sp_inherents::CheckInherentsResult { + unimplemented!() + } + } + + impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<$block> for $runtime { + fn validate_transaction( + _: TransactionSource, + _: <$block as BlockT>::Extrinsic, + _: <$block as BlockT>::Hash, + ) -> TransactionValidity { + unimplemented!() + } + } + + impl sp_session::SessionKeys<$block> for $runtime { + fn generate_session_keys(_: Option>) -> Vec { + unimplemented!() + } + + fn decode_session_keys( + _: Vec, + ) -> Option, KeyTypeId)>> { + unimplemented!() + } + } + + impl + pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi< + $block, + Balance, + > for $runtime + { + fn query_info( + _: <$block as BlockT>::Extrinsic, + _: u32, + ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { + unimplemented!() + } + fn query_fee_details( + _: <$block as BlockT>::Extrinsic, + _: u32, + ) -> pallet_transaction_payment::FeeDetails { + unimplemented!() + } + fn query_weight_to_fee(_: Weight) -> Balance { + unimplemented!() + } + fn query_length_to_fee(_: u32) -> Balance { + unimplemented!() + } + } + + impl cumulus_primitives_core::CollectCollationInfo<$block> for $runtime { + fn collect_collation_info( + _: &<$block as BlockT>::Header + ) -> cumulus_primitives_core::CollationInfo { + unimplemented!() + } + } + + impl cumulus_primitives_core::GetCoreSelectorApi<$block> for $runtime { + fn core_selector() -> (CoreSelector, ClaimQueueOffset) { + unimplemented!() + } + } + + #[cfg(feature = "try-runtime")] + impl frame_try_runtime::TryRuntime<$block> for $runtime { + fn on_runtime_upgrade( + _: frame_try_runtime::UpgradeCheckSelect + ) -> (Weight, Weight) { + unimplemented!() + } + + fn execute_block( + _: $block, + _: bool, + _: bool, + _: frame_try_runtime::TryStateSelect, + ) -> Weight { + unimplemented!() + } + } + + impl frame_system_rpc_runtime_api::AccountNonceApi< + $block, + AccountId, + Nonce + > for $runtime { + fn account_nonce(_: AccountId) -> Nonce { + unimplemented!() + } + } + + #[cfg(feature = "runtime-benchmarks")] + impl frame_benchmarking::Benchmark<$block> for $runtime { + fn benchmark_metadata(_: bool) -> ( + Vec, + Vec, + ) { + unimplemented!() + } + + fn dispatch_benchmark( + _: frame_benchmarking::BenchmarkConfig + ) -> Result, sp_runtime::RuntimeString> { + unimplemented!() + } + } + + impl sp_genesis_builder::GenesisBuilder<$block> for $runtime { + fn build_state(_: Vec) -> sp_genesis_builder::Result { + unimplemented!() + } + + fn get_preset(_id: &Option) -> Option> { + unimplemented!() + } + + fn preset_names() -> Vec { + unimplemented!() + } + } + } + }; +} + +pub(crate) use impl_node_runtime_apis; diff --git a/cumulus/polkadot-omni-node/lib/src/lib.rs b/cumulus/polkadot-omni-node/lib/src/lib.rs new file mode 100644 index 000000000000..a293ab225c6f --- /dev/null +++ b/cumulus/polkadot-omni-node/lib/src/lib.rs @@ -0,0 +1,52 @@ +// 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 . + +//! Helper library that can be used to run a parachain node. +//! +//! ## Overview +//! +//! This library can be used to run a parachain node while also customizing the chain specs +//! that are supported by default by the `--chain-spec` argument of the node's `CLI` +//! and the parameters of the runtime that is associated with each of these chain specs. +//! +//! ## API +//! +//! The library exposes the possibility to provide a [`RunConfig`]. Through this structure +//! 2 optional configurations can be provided: +//! - a chain spec loader (an implementation of [`chain_spec::LoadSpec`]): this can be used for +//! providing the chain specs that are supported by default by the `--chain-spec` argument of the +//! node's `CLI` and the actual chain config associated with each one. +//! - a runtime resolver (an implementation of [`runtime::RuntimeResolver`]): this can be used for +//! providing the parameters of the runtime that is associated with each of the chain specs +//! +//! Apart from this, a [`CliConfig`] can also be provided, that can be used to customize some +//! user-facing binary author, support url, etc. +//! +//! ## Examples +//! +//! For an example, see the `polkadot-parachain-bin` crate. + +#![deny(missing_docs)] + +mod cli; +mod command; +mod common; +mod fake_runtime_api; +mod nodes; + +pub use cli::CliConfig; +pub use command::{run, RunConfig}; +pub use common::{chain_spec, runtime}; diff --git a/cumulus/polkadot-omni-node/lib/src/nodes/aura.rs b/cumulus/polkadot-omni-node/lib/src/nodes/aura.rs new file mode 100644 index 000000000000..ec5d0a439ec4 --- /dev/null +++ b/cumulus/polkadot-omni-node/lib/src/nodes/aura.rs @@ -0,0 +1,452 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +use crate::{ + common::{ + aura::{AuraIdT, AuraRuntimeApi}, + rpc::BuildParachainRpcExtensions, + spec::{BaseNodeSpec, BuildImportQueue, NodeSpec, StartConsensus}, + types::{ + AccountId, Balance, Hash, Nonce, ParachainBackend, ParachainBlockImport, + ParachainClient, + }, + ConstructNodeRuntimeApi, NodeBlock, NodeExtraArgs, + }, + nodes::DynNodeSpecExt, +}; +use cumulus_client_collator::service::{ + CollatorService, ServiceInterface as CollatorServiceInterface, +}; +use cumulus_client_consensus_aura::collators::lookahead::{self as aura, Params as AuraParams}; +#[docify::export(slot_based_colator_import)] +use cumulus_client_consensus_aura::collators::slot_based::{ + self as slot_based, Params as SlotBasedParams, +}; +use cumulus_client_consensus_proposer::{Proposer, ProposerInterface}; +use cumulus_client_consensus_relay_chain::Verifier as RelayChainVerifier; +#[allow(deprecated)] +use cumulus_client_service::CollatorSybilResistance; +use cumulus_primitives_core::{relay_chain::ValidationCode, ParaId}; +use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface}; +use futures::prelude::*; +use polkadot_primitives::CollatorPair; +use prometheus_endpoint::Registry; +use sc_client_api::BlockchainEvents; +use sc_client_db::DbHash; +use sc_consensus::{ + import_queue::{BasicQueue, Verifier as VerifierT}, + BlockImportParams, DefaultImportQueue, +}; +use sc_service::{Configuration, Error, TaskManager}; +use sc_telemetry::TelemetryHandle; +use sc_transaction_pool::TransactionPoolHandle; +use sp_api::ProvideRuntimeApi; +use sp_inherents::CreateInherentDataProviders; +use sp_keystore::KeystorePtr; +use sp_runtime::{ + app_crypto::AppCrypto, + traits::{Block as BlockT, Header as HeaderT}, +}; +use std::{marker::PhantomData, sync::Arc, time::Duration}; + +struct Verifier { + client: Arc, + aura_verifier: Box>, + relay_chain_verifier: Box>, + _phantom: PhantomData, +} + +#[async_trait::async_trait] +impl VerifierT for Verifier +where + Client: ProvideRuntimeApi + Send + Sync, + Client::Api: AuraRuntimeApi, + AuraId: AuraIdT + Sync, +{ + async fn verify( + &self, + block_import: BlockImportParams, + ) -> Result, String> { + if self.client.runtime_api().has_aura_api(*block_import.header.parent_hash()) { + self.aura_verifier.verify(block_import).await + } else { + self.relay_chain_verifier.verify(block_import).await + } + } +} + +/// Build the import queue for parachain runtimes that started with relay chain consensus and +/// switched to aura. +pub(crate) struct BuildRelayToAuraImportQueue( + PhantomData<(Block, RuntimeApi, AuraId)>, +); + +impl BuildImportQueue + for BuildRelayToAuraImportQueue +where + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi, + AuraId: AuraIdT + Sync, +{ + fn build_import_queue( + client: Arc>, + block_import: ParachainBlockImport, + config: &Configuration, + telemetry_handle: Option, + task_manager: &TaskManager, + ) -> sc_service::error::Result> { + let verifier_client = client.clone(); + + let aura_verifier = cumulus_client_consensus_aura::build_verifier::< + ::Pair, + _, + _, + _, + >(cumulus_client_consensus_aura::BuildVerifierParams { + client: verifier_client.clone(), + create_inherent_data_providers: move |parent_hash, _| { + let cidp_client = verifier_client.clone(); + async move { + let slot_duration = cumulus_client_consensus_aura::slot_duration_at( + &*cidp_client, + parent_hash, + )?; + let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); + + let slot = + sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( + *timestamp, + slot_duration, + ); + + Ok((slot, timestamp)) + } + }, + telemetry: telemetry_handle, + }); + + let relay_chain_verifier = + Box::new(RelayChainVerifier::new(client.clone(), |_, _| async { Ok(()) })); + + let verifier = Verifier { + client, + relay_chain_verifier, + aura_verifier: Box::new(aura_verifier), + _phantom: PhantomData, + }; + + let registry = config.prometheus_registry(); + let spawner = task_manager.spawn_essential_handle(); + + Ok(BasicQueue::new(verifier, Box::new(block_import), None, &spawner, registry)) + } +} + +/// Uses the lookahead collator to support async backing. +/// +/// Start an aura powered parachain node. Some system chains use this. +pub(crate) struct AuraNode( + pub PhantomData<(Block, RuntimeApi, AuraId, StartConsensus)>, +); + +impl Default + for AuraNode +{ + fn default() -> Self { + Self(Default::default()) + } +} + +impl BaseNodeSpec + for AuraNode +where + Block: NodeBlock, + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi + + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + + substrate_frame_rpc_system::AccountNonceApi, + AuraId: AuraIdT + Sync, +{ + type Block = Block; + type RuntimeApi = RuntimeApi; + type BuildImportQueue = BuildRelayToAuraImportQueue; +} + +impl NodeSpec + for AuraNode +where + Block: NodeBlock, + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi + + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + + substrate_frame_rpc_system::AccountNonceApi, + AuraId: AuraIdT + Sync, + StartConsensus: self::StartConsensus + 'static, +{ + type BuildRpcExtensions = BuildParachainRpcExtensions; + type StartConsensus = StartConsensus; + const SYBIL_RESISTANCE: CollatorSybilResistance = CollatorSybilResistance::Resistant; +} + +pub fn new_aura_node_spec( + extra_args: &NodeExtraArgs, +) -> Box +where + Block: NodeBlock, + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi + + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi + + substrate_frame_rpc_system::AccountNonceApi, + AuraId: AuraIdT + Sync, +{ + if extra_args.use_slot_based_consensus { + Box::new(AuraNode::< + Block, + RuntimeApi, + AuraId, + StartSlotBasedAuraConsensus, + >::default()) + } else { + Box::new(AuraNode::< + Block, + RuntimeApi, + AuraId, + StartLookaheadAuraConsensus, + >::default()) + } +} + +/// Start consensus using the lookahead aura collator. +pub(crate) struct StartSlotBasedAuraConsensus( + PhantomData<(Block, RuntimeApi, AuraId)>, +); + +impl, RuntimeApi, AuraId> + StartSlotBasedAuraConsensus +where + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi, + AuraId: AuraIdT + Sync, +{ + #[docify::export_content] + fn launch_slot_based_collator( + params: SlotBasedParams< + ParachainBlockImport, + CIDP, + ParachainClient, + ParachainBackend, + Arc, + CHP, + Proposer, + CS, + >, + task_manager: &TaskManager, + ) where + CIDP: CreateInherentDataProviders + 'static, + CIDP::InherentDataProviders: Send, + CHP: cumulus_client_consensus_common::ValidationCodeHashProvider + Send + 'static, + Proposer: ProposerInterface + Send + Sync + 'static, + CS: CollatorServiceInterface + Send + Sync + Clone + 'static, + { + let (collation_future, block_builder_future) = + slot_based::run::::Pair, _, _, _, _, _, _, _, _>(params); + + task_manager.spawn_essential_handle().spawn( + "collation-task", + Some("parachain-block-authoring"), + collation_future, + ); + task_manager.spawn_essential_handle().spawn( + "block-builder-task", + Some("parachain-block-authoring"), + block_builder_future, + ); + } +} + +impl, RuntimeApi, AuraId> StartConsensus + for StartSlotBasedAuraConsensus +where + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi, + AuraId: AuraIdT + Sync, +{ + fn start_consensus( + client: Arc>, + block_import: ParachainBlockImport, + prometheus_registry: Option<&Registry>, + telemetry: Option, + task_manager: &TaskManager, + relay_chain_interface: Arc, + transaction_pool: Arc>>, + keystore: KeystorePtr, + _relay_chain_slot_duration: Duration, + para_id: ParaId, + collator_key: CollatorPair, + _overseer_handle: OverseerHandle, + announce_block: Arc>) + Send + Sync>, + backend: Arc>, + _node_extra_args: NodeExtraArgs, + ) -> Result<(), Error> { + let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( + task_manager.spawn_handle(), + client.clone(), + transaction_pool, + prometheus_registry, + telemetry.clone(), + ); + + let proposer = Proposer::new(proposer_factory); + let collator_service = CollatorService::new( + client.clone(), + Arc::new(task_manager.spawn_handle()), + announce_block, + client.clone(), + ); + + let client_for_aura = client.clone(); + let params = SlotBasedParams { + create_inherent_data_providers: move |_, ()| async move { Ok(()) }, + block_import, + para_client: client.clone(), + para_backend: backend.clone(), + relay_client: relay_chain_interface, + code_hash_provider: move |block_hash| { + client_for_aura.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) + }, + keystore, + collator_key, + para_id, + proposer, + collator_service, + authoring_duration: Duration::from_millis(2000), + reinitialize: false, + slot_drift: Duration::from_secs(1), + }; + + // We have a separate function only to be able to use `docify::export` on this piece of + // code. + Self::launch_slot_based_collator(params, task_manager); + + Ok(()) + } +} + +/// Wait for the Aura runtime API to appear on chain. +/// This is useful for chains that started out without Aura. Components that +/// are depending on Aura functionality will wait until Aura appears in the runtime. +async fn wait_for_aura( + client: Arc>, +) where + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi, + AuraId: AuraIdT + Sync, +{ + let finalized_hash = client.chain_info().finalized_hash; + if client.runtime_api().has_aura_api(finalized_hash) { + return; + }; + + let mut stream = client.finality_notification_stream(); + while let Some(notification) = stream.next().await { + if client.runtime_api().has_aura_api(notification.hash) { + return; + } + } +} + +/// Start consensus using the lookahead aura collator. +pub(crate) struct StartLookaheadAuraConsensus( + PhantomData<(Block, RuntimeApi, AuraId)>, +); + +impl, RuntimeApi, AuraId> StartConsensus + for StartLookaheadAuraConsensus +where + RuntimeApi: ConstructNodeRuntimeApi>, + RuntimeApi::RuntimeApi: AuraRuntimeApi, + AuraId: AuraIdT + Sync, +{ + fn start_consensus( + client: Arc>, + block_import: ParachainBlockImport, + prometheus_registry: Option<&Registry>, + telemetry: Option, + task_manager: &TaskManager, + relay_chain_interface: Arc, + transaction_pool: Arc>>, + keystore: KeystorePtr, + relay_chain_slot_duration: Duration, + para_id: ParaId, + collator_key: CollatorPair, + overseer_handle: OverseerHandle, + announce_block: Arc>) + Send + Sync>, + backend: Arc>, + node_extra_args: NodeExtraArgs, + ) -> Result<(), Error> { + let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( + task_manager.spawn_handle(), + client.clone(), + transaction_pool, + prometheus_registry, + telemetry.clone(), + ); + + let collator_service = CollatorService::new( + client.clone(), + Arc::new(task_manager.spawn_handle()), + announce_block, + client.clone(), + ); + + let params = aura::ParamsWithExport { + export_pov: node_extra_args.export_pov, + params: AuraParams { + create_inherent_data_providers: move |_, ()| async move { Ok(()) }, + block_import, + para_client: client.clone(), + para_backend: backend, + relay_client: relay_chain_interface, + code_hash_provider: { + let client = client.clone(); + move |block_hash| { + client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) + } + }, + keystore, + collator_key, + para_id, + overseer_handle, + relay_chain_slot_duration, + proposer: Proposer::new(proposer_factory), + collator_service, + authoring_duration: Duration::from_millis(2000), + reinitialize: false, + }, + }; + + let fut = async move { + wait_for_aura(client).await; + aura::run_with_export::::Pair, _, _, _, _, _, _, _, _>( + params, + ) + .await; + }; + task_manager.spawn_essential_handle().spawn("aura", None, fut); + + Ok(()) + } +} diff --git a/cumulus/polkadot-omni-node/lib/src/nodes/manual_seal.rs b/cumulus/polkadot-omni-node/lib/src/nodes/manual_seal.rs new file mode 100644 index 000000000000..d00d7adf27e1 --- /dev/null +++ b/cumulus/polkadot-omni-node/lib/src/nodes/manual_seal.rs @@ -0,0 +1,233 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Cumulus is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Cumulus. If not, see . + +use crate::common::{ + rpc::BuildRpcExtensions as BuildRpcExtensionsT, + spec::{BaseNodeSpec, BuildImportQueue, NodeSpec as NodeSpecT}, + types::{Hash, ParachainBlockImport, ParachainClient}, +}; +use codec::Encode; +use cumulus_client_parachain_inherent::{MockValidationDataInherentDataProvider, MockXcmConfig}; +use cumulus_primitives_core::ParaId; +use sc_consensus::{DefaultImportQueue, LongestChain}; +use sc_consensus_manual_seal::rpc::{ManualSeal, ManualSealApiServer}; +use sc_network::NetworkBackend; +use sc_service::{build_polkadot_syncing_strategy, Configuration, PartialComponents, TaskManager}; +use sc_telemetry::TelemetryHandle; +use sp_runtime::traits::Header; +use sp_timestamp::Timestamp; +use std::{marker::PhantomData, sync::Arc}; + +pub struct ManualSealNode(PhantomData); + +impl BuildImportQueue + for ManualSealNode +{ + fn build_import_queue( + client: Arc>, + _block_import: ParachainBlockImport, + config: &Configuration, + _telemetry_handle: Option, + task_manager: &TaskManager, + ) -> sc_service::error::Result> { + Ok(sc_consensus_manual_seal::import_queue( + Box::new(client.clone()), + &task_manager.spawn_essential_handle(), + config.prometheus_registry(), + )) + } +} + +impl BaseNodeSpec for ManualSealNode { + type Block = NodeSpec::Block; + type RuntimeApi = NodeSpec::RuntimeApi; + type BuildImportQueue = Self; +} + +impl ManualSealNode { + pub fn new() -> Self { + Self(Default::default()) + } + + pub fn start_node( + &self, + mut config: Configuration, + para_id: ParaId, + block_time: u64, + ) -> sc_service::error::Result + where + Net: NetworkBackend, + { + let PartialComponents { + client, + backend, + mut task_manager, + import_queue, + keystore_container, + select_chain: _, + transaction_pool, + other: (_, mut telemetry, _), + } = Self::new_partial(&config)?; + let select_chain = LongestChain::new(backend.clone()); + + // Since this is a dev node, prevent it from connecting to peers. + config.network.default_peers_set.in_peers = 0; + config.network.default_peers_set.out_peers = 0; + let mut net_config = sc_network::config::FullNetworkConfiguration::<_, _, Net>::new( + &config.network, + config.prometheus_config.as_ref().map(|cfg| cfg.registry.clone()), + ); + let metrics = Net::register_notification_metrics( + config.prometheus_config.as_ref().map(|cfg| &cfg.registry), + ); + + let syncing_strategy = build_polkadot_syncing_strategy( + config.protocol_id(), + config.chain_spec.fork_id(), + &mut net_config, + None, + client.clone(), + &task_manager.spawn_handle(), + config.prometheus_config.as_ref().map(|config| &config.registry), + )?; + + let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = + sc_service::build_network(sc_service::BuildNetworkParams { + config: &config, + client: client.clone(), + transaction_pool: transaction_pool.clone(), + spawn_handle: task_manager.spawn_handle(), + import_queue, + net_config, + block_announce_validator_builder: None, + syncing_strategy, + block_relay: None, + metrics, + })?; + + let proposer = sc_basic_authorship::ProposerFactory::new( + task_manager.spawn_handle(), + client.clone(), + transaction_pool.clone(), + None, + None, + ); + + let (manual_seal_sink, manual_seal_stream) = futures::channel::mpsc::channel(1024); + let mut manual_seal_sink_clone = manual_seal_sink.clone(); + task_manager + .spawn_essential_handle() + .spawn("block_authoring", None, async move { + loop { + futures_timer::Delay::new(std::time::Duration::from_millis(block_time)).await; + manual_seal_sink_clone + .try_send(sc_consensus_manual_seal::EngineCommand::SealNewBlock { + create_empty: true, + finalize: true, + parent_hash: None, + sender: None, + }) + .unwrap(); + } + }); + + let client_for_cidp = client.clone(); + let params = sc_consensus_manual_seal::ManualSealParams { + block_import: client.clone(), + env: proposer, + client: client.clone(), + pool: transaction_pool.clone(), + select_chain, + commands_stream: Box::pin(manual_seal_stream), + consensus_data_provider: None, + create_inherent_data_providers: move |block: Hash, ()| { + let current_para_head = client_for_cidp + .header(block) + .expect("Header lookup should succeed") + .expect("Header passed in as parent should be present in backend."); + let current_para_block_head = + Some(polkadot_primitives::HeadData(current_para_head.encode())); + let client_for_xcm = client_for_cidp.clone(); + async move { + use sp_runtime::traits::UniqueSaturatedInto; + + let mocked_parachain = MockValidationDataInherentDataProvider { + // When using manual seal we start from block 0, and it's very unlikely to + // reach a block number > u32::MAX. + current_para_block: UniqueSaturatedInto::::unique_saturated_into( + *current_para_head.number(), + ), + para_id, + current_para_block_head, + relay_offset: 1000, + relay_blocks_per_para_block: 1, + para_blocks_per_relay_epoch: 10, + relay_randomness_config: (), + xcm_config: MockXcmConfig::new(&*client_for_xcm, block, Default::default()), + raw_downward_messages: vec![], + raw_horizontal_messages: vec![], + additional_key_values: None, + }; + Ok(( + sp_timestamp::InherentDataProvider::new(Timestamp::new(0)), + mocked_parachain, + )) + } + }, + }; + let authorship_future = sc_consensus_manual_seal::run_manual_seal(params); + task_manager.spawn_essential_handle().spawn_blocking( + "manual-seal", + None, + authorship_future, + ); + let rpc_extensions_builder = { + let client = client.clone(); + let transaction_pool = transaction_pool.clone(); + let backend_for_rpc = backend.clone(); + + Box::new(move |_| { + let mut module = NodeSpec::BuildRpcExtensions::build_rpc_extensions( + client.clone(), + backend_for_rpc.clone(), + transaction_pool.clone(), + )?; + module + .merge(ManualSeal::new(manual_seal_sink.clone()).into_rpc()) + .map_err(|e| sc_service::Error::Application(e.into()))?; + Ok(module) + }) + }; + + let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams { + network, + client: client.clone(), + keystore: keystore_container.keystore(), + task_manager: &mut task_manager, + transaction_pool: transaction_pool.clone(), + rpc_builder: rpc_extensions_builder, + backend, + system_rpc_tx, + tx_handler_controller, + sync_service, + config, + telemetry: telemetry.as_mut(), + })?; + + start_network.start_network(); + Ok(task_manager) + } +} diff --git a/cumulus/polkadot-omni-node/lib/src/nodes/mod.rs b/cumulus/polkadot-omni-node/lib/src/nodes/mod.rs new file mode 100644 index 000000000000..ab13322e80ab --- /dev/null +++ b/cumulus/polkadot-omni-node/lib/src/nodes/mod.rs @@ -0,0 +1,57 @@ +// 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 . + +pub mod aura; +mod manual_seal; + +use crate::common::spec::{DynNodeSpec, NodeSpec as NodeSpecT}; +use cumulus_primitives_core::ParaId; +use manual_seal::ManualSealNode; +use sc_service::{Configuration, TaskManager}; + +/// Trait that extends the `DynNodeSpec` trait with manual seal related logic. +/// +/// We need it in order to be able to access both the `DynNodeSpec` and the manual seal logic +/// through dynamic dispatch. +pub trait DynNodeSpecExt: DynNodeSpec { + fn start_manual_seal_node( + &self, + config: Configuration, + para_id: ParaId, + block_time: u64, + ) -> sc_service::error::Result; +} + +impl DynNodeSpecExt for T +where + T: NodeSpecT + DynNodeSpec, +{ + #[sc_tracing::logging::prefix_logs_with("Parachain")] + fn start_manual_seal_node( + &self, + config: Configuration, + para_id: ParaId, + block_time: u64, + ) -> sc_service::error::Result { + let node = ManualSealNode::::new(); + match config.network.network_backend { + sc_network::config::NetworkBackendType::Libp2p => + node.start_node::>(config, para_id, block_time), + sc_network::config::NetworkBackendType::Litep2p => + node.start_node::(config, para_id, block_time), + } + } +} diff --git a/cumulus/polkadot-parachain/tests/benchmark_storage_works.rs b/cumulus/polkadot-omni-node/lib/src/tests/benchmark_storage_works.rs similarity index 91% rename from cumulus/polkadot-parachain/tests/benchmark_storage_works.rs rename to cumulus/polkadot-omni-node/lib/src/tests/benchmark_storage_works.rs index c554b5b3d6be..8502188af511 100644 --- a/cumulus/polkadot-parachain/tests/benchmark_storage_works.rs +++ b/cumulus/polkadot-omni-node/lib/src/tests/benchmark_storage_works.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Substrate. +// This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/cumulus/polkadot-parachain/tests/common.rs b/cumulus/polkadot-omni-node/lib/src/tests/common.rs similarity index 95% rename from cumulus/polkadot-parachain/tests/common.rs rename to cumulus/polkadot-omni-node/lib/src/tests/common.rs index 20926ddd91db..d3f41fb50bc6 100644 --- a/cumulus/polkadot-parachain/tests/common.rs +++ b/cumulus/polkadot-omni-node/lib/src/tests/common.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Substrate. +// This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/cumulus/polkadot-parachain/tests/polkadot_argument_parsing.rs b/cumulus/polkadot-omni-node/lib/src/tests/polkadot_argument_parsing.rs similarity index 87% rename from cumulus/polkadot-parachain/tests/polkadot_argument_parsing.rs rename to cumulus/polkadot-omni-node/lib/src/tests/polkadot_argument_parsing.rs index 9337da85d74b..d1f497c1187a 100644 --- a/cumulus/polkadot-parachain/tests/polkadot_argument_parsing.rs +++ b/cumulus/polkadot-omni-node/lib/src/tests/polkadot_argument_parsing.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Substrate. +// This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/cumulus/polkadot-parachain/tests/polkadot_mdns_issue.rs b/cumulus/polkadot-omni-node/lib/src/tests/polkadot_mdns_issue.rs similarity index 85% rename from cumulus/polkadot-parachain/tests/polkadot_mdns_issue.rs rename to cumulus/polkadot-omni-node/lib/src/tests/polkadot_mdns_issue.rs index e3ccb7fe0fbd..3b0b08e57f83 100644 --- a/cumulus/polkadot-parachain/tests/polkadot_mdns_issue.rs +++ b/cumulus/polkadot-omni-node/lib/src/tests/polkadot_mdns_issue.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Substrate. +// This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/cumulus/polkadot-parachain/tests/purge_chain_works.rs b/cumulus/polkadot-omni-node/lib/src/tests/purge_chain_works.rs similarity index 91% rename from cumulus/polkadot-parachain/tests/purge_chain_works.rs rename to cumulus/polkadot-omni-node/lib/src/tests/purge_chain_works.rs index 6415a914c7a3..65a946e890bd 100644 --- a/cumulus/polkadot-parachain/tests/purge_chain_works.rs +++ b/cumulus/polkadot-omni-node/lib/src/tests/purge_chain_works.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Substrate. +// This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/cumulus/polkadot-parachain/tests/running_the_node_and_interrupt.rs b/cumulus/polkadot-omni-node/lib/src/tests/running_the_node_and_interrupt.rs similarity index 85% rename from cumulus/polkadot-parachain/tests/running_the_node_and_interrupt.rs rename to cumulus/polkadot-omni-node/lib/src/tests/running_the_node_and_interrupt.rs index 0f4ae6992382..a45fd7f4575a 100644 --- a/cumulus/polkadot-parachain/tests/running_the_node_and_interrupt.rs +++ b/cumulus/polkadot-omni-node/lib/src/tests/running_the_node_and_interrupt.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Substrate. +// This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/cumulus/polkadot-omni-node/src/main.rs b/cumulus/polkadot-omni-node/src/main.rs new file mode 100644 index 000000000000..a86ec6f6fde6 --- /dev/null +++ b/cumulus/polkadot-omni-node/src/main.rs @@ -0,0 +1,60 @@ +// 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 . + +//! Basic polkadot omni-node. +//! +//! It can be used to start a parachain node from a provided chain spec file. +//! It is only compatible with runtimes that use block number `u32` and `Aura` consensus. +//! +//! Example: `polkadot-omni-node --chain [chain_spec.json]` + +#![warn(missing_docs)] +#![warn(unused_extern_crates)] + +use polkadot_omni_node_lib::{ + chain_spec::DiskChainSpecLoader, run, runtime::DefaultRuntimeResolver, CliConfig as CliConfigT, + RunConfig, +}; + +struct CliConfig; + +impl CliConfigT for CliConfig { + fn impl_version() -> String { + env!("SUBSTRATE_CLI_IMPL_VERSION").into() + } + + fn author() -> String { + env!("CARGO_PKG_AUTHORS").into() + } + + fn support_url() -> String { + "https://github.com/paritytech/polkadot-sdk/issues/new".into() + } + + fn copyright_start_year() -> u16 { + 2017 + } +} + +fn main() -> color_eyre::eyre::Result<()> { + color_eyre::install()?; + + let config = RunConfig { + chain_spec_loader: Box::new(DiskChainSpecLoader), + runtime_resolver: Box::new(DefaultRuntimeResolver), + }; + Ok(run::(config)?) +} diff --git a/cumulus/polkadot-parachain/Cargo.toml b/cumulus/polkadot-parachain/Cargo.toml index b20d2a28fa7f..5520126d0742 100644 --- a/cumulus/polkadot-parachain/Cargo.toml +++ b/cumulus/polkadot-parachain/Cargo.toml @@ -2,9 +2,9 @@ name = "polkadot-parachain-bin" version = "4.0.0" authors.workspace = true -build = "build.rs" edition.workspace = true -description = "Runs a polkadot parachain node which could be a collator." +build = "build.rs" +description = "Runs a polkadot parachain node" license = "Apache-2.0" [lints] @@ -15,22 +15,16 @@ name = "polkadot-parachain" path = "src/main.rs" [dependencies] -async-trait = { workspace = true } -clap = { features = ["derive"], workspace = true } -codec = { workspace = true, default-features = true } -color-print = { workspace = true } -futures = { workspace = true } +color-eyre = { workspace = true } hex-literal = { workspace = true, default-features = true } log = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } -docify = { workspace = true } # Local +polkadot-omni-node-lib = { features = ["rococo-native", "westend-native"], workspace = true } rococo-parachain-runtime = { workspace = true } -shell-runtime = { workspace = true } glutton-westend-runtime = { workspace = true } -seedling-runtime = { workspace = true } asset-hub-rococo-runtime = { workspace = true, default-features = true } asset-hub-westend-runtime = { workspace = true } collectives-westend-runtime = { workspace = true } @@ -40,93 +34,35 @@ coretime-rococo-runtime = { workspace = true } coretime-westend-runtime = { workspace = true } bridge-hub-westend-runtime = { workspace = true, default-features = true } penpal-runtime = { workspace = true } -jsonrpsee = { features = ["server"], workspace = true } people-rococo-runtime = { workspace = true } people-westend-runtime = { workspace = true } parachains-common = { workspace = true, default-features = true } -testnet-parachains-constants = { features = [ - "rococo", - "westend", -], workspace = true } # Substrate -frame-benchmarking = { workspace = true, default-features = true } -frame-benchmarking-cli = { workspace = true, default-features = true } -sp-runtime = { workspace = true } -sp-io = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } -sp-session = { workspace = true, default-features = true } -frame-try-runtime = { optional = true, workspace = true, default-features = true } -sc-consensus = { workspace = true, default-features = true } -sp-tracing = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } +sp-keyring = { workspace = true, default-features = true } sc-cli = { workspace = true, default-features = true } -sc-client-api = { workspace = true, default-features = true } -sc-executor = { workspace = true, default-features = true } sc-service = { workspace = true, default-features = true } -sc-telemetry = { workspace = true, default-features = true } -sc-transaction-pool = { workspace = true, default-features = true } -sp-transaction-pool = { workspace = true, default-features = true } -sc-network = { workspace = true, default-features = true } -sc-network-sync = { workspace = true, default-features = true } -sc-basic-authorship = { workspace = true, default-features = true } -sp-timestamp = { workspace = true, default-features = true } -sp-blockchain = { workspace = true, default-features = true } -sp-genesis-builder = { workspace = true } -sp-block-builder = { workspace = true, default-features = true } -sp-keystore = { workspace = true, default-features = true } sc-chain-spec = { workspace = true, default-features = true } -sc-rpc = { workspace = true, default-features = true } -sp-version = { workspace = true, default-features = true } -sc-tracing = { workspace = true, default-features = true } -sp-offchain = { workspace = true, default-features = true } -frame-system-rpc-runtime-api = { workspace = true, default-features = true } -pallet-transaction-payment = { workspace = true, default-features = true } -pallet-transaction-payment-rpc-runtime-api = { workspace = true, default-features = true } -sp-std = { workspace = true, default-features = true } -sp-inherents = { workspace = true, default-features = true } -sp-api = { workspace = true, default-features = true } -sp-consensus-aura = { workspace = true, default-features = true } -sc-sysinfo = { workspace = true, default-features = true } -prometheus-endpoint = { workspace = true, default-features = true } -sc-transaction-pool-api = { workspace = true, default-features = true } -substrate-frame-rpc-system = { workspace = true, default-features = true } -pallet-transaction-payment-rpc = { workspace = true, default-features = true } -substrate-state-trie-migration-rpc = { workspace = true, default-features = true } +sp-genesis-builder = { workspace = true, default-features = true } # Polkadot -# Use rococo-native as this is currently the default "local" relay chain -polkadot-cli = { features = ["rococo-native", "westend-native"], workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } -polkadot-service = { workspace = true, default-features = true } xcm = { workspace = true, default-features = true } # Cumulus -cumulus-client-cli = { workspace = true, default-features = true } -cumulus-client-collator = { workspace = true, default-features = true } -cumulus-client-consensus-aura = { workspace = true, default-features = true } -cumulus-client-consensus-relay-chain = { workspace = true, default-features = true } -cumulus-client-consensus-common = { workspace = true, default-features = true } -cumulus-client-consensus-proposer = { workspace = true, default-features = true } -cumulus-client-parachain-inherent = { workspace = true, default-features = true } -cumulus-client-service = { workspace = true, default-features = true } -cumulus-primitives-aura = { workspace = true, default-features = true } cumulus-primitives-core = { workspace = true, default-features = true } -cumulus-relay-chain-interface = { workspace = true, default-features = true } [build-dependencies] substrate-build-script-utils = { workspace = true, default-features = true } -[dev-dependencies] -assert_cmd = { workspace = true } -nix = { features = ["signal"], workspace = true } -tempfile = { workspace = true } -tokio = { version = "1.32.0", features = ["macros", "parking_lot", "time"] } -wait-timeout = { workspace = true } - [features] default = [] runtime-benchmarks = [ + "cumulus-primitives-core/runtime-benchmarks", + "parachains-common/runtime-benchmarks", + "polkadot-omni-node-lib/runtime-benchmarks", + "sc-service/runtime-benchmarks", + "asset-hub-rococo-runtime/runtime-benchmarks", "asset-hub-westend-runtime/runtime-benchmarks", "bridge-hub-rococo-runtime/runtime-benchmarks", @@ -135,23 +71,15 @@ runtime-benchmarks = [ "contracts-rococo-runtime/runtime-benchmarks", "coretime-rococo-runtime/runtime-benchmarks", "coretime-westend-runtime/runtime-benchmarks", - "cumulus-primitives-core/runtime-benchmarks", - "frame-benchmarking-cli/runtime-benchmarks", - "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", "glutton-westend-runtime/runtime-benchmarks", - "parachains-common/runtime-benchmarks", "penpal-runtime/runtime-benchmarks", "people-rococo-runtime/runtime-benchmarks", "people-westend-runtime/runtime-benchmarks", - "polkadot-cli/runtime-benchmarks", - "polkadot-primitives/runtime-benchmarks", - "polkadot-service/runtime-benchmarks", "rococo-parachain-runtime/runtime-benchmarks", - "sc-service/runtime-benchmarks", - "sp-runtime/runtime-benchmarks", ] try-runtime = [ + "polkadot-omni-node-lib/try-runtime", + "asset-hub-rococo-runtime/try-runtime", "asset-hub-westend-runtime/try-runtime", "bridge-hub-rococo-runtime/try-runtime", @@ -160,20 +88,14 @@ try-runtime = [ "contracts-rococo-runtime/try-runtime", "coretime-rococo-runtime/try-runtime", "coretime-westend-runtime/try-runtime", - "frame-support/try-runtime", - "frame-try-runtime/try-runtime", "glutton-westend-runtime/try-runtime", - "pallet-transaction-payment/try-runtime", "penpal-runtime/try-runtime", "people-rococo-runtime/try-runtime", "people-westend-runtime/try-runtime", - "polkadot-cli/try-runtime", - "polkadot-service/try-runtime", - "shell-runtime/try-runtime", - "sp-runtime/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/build.rs b/cumulus/polkadot-parachain/build.rs index dd0d112bca70..8c498735eae9 100644 --- a/cumulus/polkadot-parachain/build.rs +++ b/cumulus/polkadot-parachain/build.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/cumulus/polkadot-parachain/chain-specs/contracts-rococo.json b/cumulus/polkadot-parachain/chain-specs/contracts-rococo.json deleted file mode 120000 index b9f8e8f31e84..000000000000 --- a/cumulus/polkadot-parachain/chain-specs/contracts-rococo.json +++ /dev/null @@ -1 +0,0 @@ -../../parachains/chain-specs/contracts-rococo.json \ No newline at end of file diff --git a/cumulus/polkadot-parachain/chain-specs/coretime-polkadot.json b/cumulus/polkadot-parachain/chain-specs/coretime-polkadot.json new file mode 120000 index 000000000000..f6f2bc686917 --- /dev/null +++ b/cumulus/polkadot-parachain/chain-specs/coretime-polkadot.json @@ -0,0 +1 @@ +../../parachains/chain-specs/coretime-polkadot.json \ No newline at end of file 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 000000000000..44fead1c49e0 --- /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 45920cdb6146..ec2afc743de8 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/asset_hubs.rs @@ -14,32 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, Extensions, GenericChainSpec, - SAFE_XCM_VERSION, -}; -use cumulus_primitives_core::ParaId; -use hex_literal::hex; -use parachains_common::{AccountId, AuraId, Balance as AssetHubBalance}; +use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; use sc_service::ChainType; -use sp_core::{crypto::UncheckedInto, sr25519}; - -const ASSET_HUB_WESTEND_ED: AssetHubBalance = asset_hub_westend_runtime::ExistentialDeposit::get(); -const ASSET_HUB_ROCOCO_ED: AssetHubBalance = asset_hub_rococo_runtime::ExistentialDeposit::get(); - -/// Generate the session keys from individual elements. -/// -/// The input must be a tuple of individual keys (a single arg for now since we have just one key). -pub fn asset_hub_rococo_session_keys(keys: AuraId) -> asset_hub_rococo_runtime::SessionKeys { - asset_hub_rococo_runtime::SessionKeys { aura: keys } -} - -/// Generate the session keys from individual elements. -/// -/// The input must be a tuple of individual keys (a single arg for now since we have just one key). -pub fn asset_hub_westend_session_keys(keys: AuraId) -> asset_hub_westend_runtime::SessionKeys { - asset_hub_westend_runtime::SessionKeys { aura: keys } -} pub fn asset_hub_westend_development_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); @@ -54,21 +30,7 @@ pub fn asset_hub_westend_development_config() -> GenericChainSpec { .with_name("Westend Asset Hub Development") .with_id("asset-hub-westend-dev") .with_chain_type(ChainType::Local) - .with_genesis_config_patch(asset_hub_westend_genesis( - // initial collators. - vec![( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - )], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - ], - testnet_parachains_constants::westend::currency::UNITS * 1_000_000, - 1000.into(), - )) + .with_genesis_config_preset_name(sp_genesis_builder::DEV_RUNTIME_PRESET) .with_properties(properties) .build() } @@ -86,35 +48,7 @@ pub fn asset_hub_westend_local_config() -> GenericChainSpec { .with_name("Westend Asset Hub Local") .with_id("asset-hub-westend-local") .with_chain_type(ChainType::Local) - .with_genesis_config_patch(asset_hub_westend_genesis( - // initial collators. - vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ], - testnet_parachains_constants::westend::currency::UNITS * 1_000_000, - 1000.into(), - )) + .with_genesis_config_preset_name(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) .with_properties(properties) .build() } @@ -132,77 +66,11 @@ pub fn asset_hub_westend_config() -> GenericChainSpec { .with_name("Westend Asset Hub") .with_id("asset-hub-westend") .with_chain_type(ChainType::Live) - .with_genesis_config_patch(asset_hub_westend_genesis( - // initial collators. - vec![ - ( - hex!("9cfd429fa002114f33c1d3e211501d62830c9868228eb3b4b8ae15a83de04325").into(), - hex!("9cfd429fa002114f33c1d3e211501d62830c9868228eb3b4b8ae15a83de04325") - .unchecked_into(), - ), - ( - hex!("12a03fb4e7bda6c9a07ec0a11d03c24746943e054ff0bb04938970104c783876").into(), - hex!("12a03fb4e7bda6c9a07ec0a11d03c24746943e054ff0bb04938970104c783876") - .unchecked_into(), - ), - ( - hex!("1256436307dfde969324e95b8c62cb9101f520a39435e6af0f7ac07b34e1931f").into(), - hex!("1256436307dfde969324e95b8c62cb9101f520a39435e6af0f7ac07b34e1931f") - .unchecked_into(), - ), - ( - hex!("98102b7bca3f070f9aa19f58feed2c0a4e107d203396028ec17a47e1ed80e322").into(), - hex!("98102b7bca3f070f9aa19f58feed2c0a4e107d203396028ec17a47e1ed80e322") - .unchecked_into(), - ), - ], - Vec::new(), - ASSET_HUB_WESTEND_ED * 4096, - 1000.into(), - )) + .with_genesis_config_preset_name("genesis") .with_properties(properties) .build() } -fn asset_hub_westend_genesis( - invulnerables: Vec<(AccountId, AuraId)>, - endowed_accounts: Vec, - endowment: AssetHubBalance, - id: ParaId, -) -> serde_json::Value { - serde_json::json!({ - "balances": { - "balances": endowed_accounts - .iter() - .cloned() - .map(|k| (k, endowment)) - .collect::>(), - }, - "parachainInfo": { - "parachainId": id, - }, - "collatorSelection": { - "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), - "candidacyBond": ASSET_HUB_WESTEND_ED * 16, - }, - "session": { - "keys": invulnerables - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - asset_hub_westend_session_keys(aura), // session keys - ) - }) - .collect::>(), - }, - "polkadotXcm": { - "safeXcmVersion": Some(SAFE_XCM_VERSION), - }, - }) -} - pub fn asset_hub_rococo_development_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 42.into()); @@ -229,21 +97,7 @@ fn asset_hub_rococo_like_development_config( .with_name(name) .with_id(chain_id) .with_chain_type(ChainType::Local) - .with_genesis_config_patch(asset_hub_rococo_genesis( - // initial collators. - vec![( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - )], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - ], - testnet_parachains_constants::rococo::currency::UNITS * 1_000_000, - para_id.into(), - )) + .with_genesis_config_preset_name(sp_genesis_builder::DEV_RUNTIME_PRESET) .with_properties(properties) .build() } @@ -274,35 +128,7 @@ fn asset_hub_rococo_like_local_config( .with_name(name) .with_id(chain_id) .with_chain_type(ChainType::Local) - .with_genesis_config_patch(asset_hub_rococo_genesis( - // initial collators. - vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ], - testnet_parachains_constants::rococo::currency::UNITS * 1_000_000, - para_id.into(), - )) + .with_genesis_config_preset_name(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) .with_properties(properties) .build() } @@ -319,80 +145,7 @@ pub fn asset_hub_rococo_genesis_config() -> GenericChainSpec { .with_name("Rococo Asset Hub") .with_id("asset-hub-rococo") .with_chain_type(ChainType::Live) - .with_genesis_config_patch(asset_hub_rococo_genesis( - // initial collators. - vec![ - // E8XC6rTJRsioKCp6KMy6zd24ykj4gWsusZ3AkSeyavpVBAG - ( - hex!("44cb62d1d6cdd2fff2a5ef3bb7ef827be5b3e117a394ecaa634d8dd9809d5608").into(), - hex!("44cb62d1d6cdd2fff2a5ef3bb7ef827be5b3e117a394ecaa634d8dd9809d5608") - .unchecked_into(), - ), - // G28iWEybndgGRbhfx83t7Q42YhMPByHpyqWDUgeyoGF94ri - ( - hex!("9864b85e23aa4506643db9879c3dbbeabaa94d269693a4447f537dd6b5893944").into(), - hex!("9864b85e23aa4506643db9879c3dbbeabaa94d269693a4447f537dd6b5893944") - .unchecked_into(), - ), - // G839e2eMiq7UXbConsY6DS1XDAYG2XnQxAmLuRLGGQ3Px9c - ( - hex!("9ce5741ee2f1ac3bdedbde9f3339048f4da2cb88ddf33a0977fa0b4cf86e2948").into(), - hex!("9ce5741ee2f1ac3bdedbde9f3339048f4da2cb88ddf33a0977fa0b4cf86e2948") - .unchecked_into(), - ), - // GLao4ukFUW6qhexuZowdFrKa2NLCfnEjZMftSXXfvGv1vvt - ( - hex!("a676ed15f5a325eab49ed8d5f8c00f3f814b19bb58cda14ad10894c078dd337f").into(), - hex!("a676ed15f5a325eab49ed8d5f8c00f3f814b19bb58cda14ad10894c078dd337f") - .unchecked_into(), - ), - ], - Vec::new(), - ASSET_HUB_ROCOCO_ED * 524_288, - para_id.into(), - )) + .with_genesis_config_preset_name("genesis") .with_properties(properties) .build() } - -fn asset_hub_rococo_genesis( - invulnerables: Vec<(AccountId, AuraId)>, - endowed_accounts: Vec, - endowment: AssetHubBalance, - id: ParaId, -) -> serde_json::Value { - serde_json::json!({ - "balances": asset_hub_rococo_runtime::BalancesConfig { - balances: endowed_accounts - .iter() - .cloned() - .map(|k| (k, endowment)) - .collect(), - }, - "parachainInfo": asset_hub_rococo_runtime::ParachainInfoConfig { - parachain_id: id, - ..Default::default() - }, - "collatorSelection": asset_hub_rococo_runtime::CollatorSelectionConfig { - invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect(), - candidacy_bond: ASSET_HUB_ROCOCO_ED * 16, - ..Default::default() - }, - "session": asset_hub_rococo_runtime::SessionConfig { - keys: invulnerables - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - asset_hub_rococo_session_keys(aura), // session keys - ) - }) - .collect(), - }, - "polkadotXcm": asset_hub_rococo_runtime::PolkadotXcmConfig { - safe_xcm_version: Some(SAFE_XCM_VERSION), - ..Default::default() - } - }) -} diff --git a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs index 15e8a1bf11a0..839e93d0a67b 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/bridge_hubs.rs @@ -14,11 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::chain_spec::{get_account_id_from_seed, get_collator_keys_from_seed, GenericChainSpec}; use cumulus_primitives_core::ParaId; -use parachains_common::Balance as BridgeHubBalance; -use sc_chain_spec::ChainSpec; -use sp_core::sr25519; +use polkadot_omni_node_lib::chain_spec::GenericChainSpec; +use sc_chain_spec::{ChainSpec, ChainType}; use std::str::FromStr; /// Collects all supported BridgeHub configurations @@ -80,14 +78,14 @@ impl BridgeHubRuntimeType { "Westend BridgeHub Local", "westend-local", ParaId::new(1002), - Some("Bob".to_string()), + ChainType::Local, ))), BridgeHubRuntimeType::WestendDevelopment => Ok(Box::new(westend::local_config( westend::BRIDGE_HUB_WESTEND_DEVELOPMENT, "Westend BridgeHub Development", "westend-dev", ParaId::new(1002), - Some("Bob".to_string()), + ChainType::Development, ))), BridgeHubRuntimeType::Rococo => Ok(Box::new(GenericChainSpec::from_json_bytes( &include_bytes!("../../chain-specs/bridge-hub-rococo.json")[..], @@ -97,16 +95,16 @@ impl BridgeHubRuntimeType { "Rococo BridgeHub Local", "rococo-local", ParaId::new(1013), - Some("Bob".to_string()), |_| (), + ChainType::Local, ))), BridgeHubRuntimeType::RococoDevelopment => Ok(Box::new(rococo::local_config( rococo::BRIDGE_HUB_ROCOCO_DEVELOPMENT, "Rococo BridgeHub Development", "rococo-dev", ParaId::new(1013), - Some("Bob".to_string()), |_| (), + ChainType::Development, ))), other => Err(std::format!("No default config present for {:?}", other)), } @@ -128,26 +126,20 @@ fn ensure_id(id: &str) -> Result<&str, String> { /// Sub-module for Rococo setup pub mod rococo { - use super::{get_account_id_from_seed, get_collator_keys_from_seed, sr25519, ParaId}; - use crate::chain_spec::{Extensions, GenericChainSpec, SAFE_XCM_VERSION}; - use parachains_common::{AccountId, AuraId}; - use sc_chain_spec::ChainType; - - use super::BridgeHubBalance; + use super::{ChainType, ParaId}; + use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; pub(crate) const BRIDGE_HUB_ROCOCO: &str = "bridge-hub-rococo"; pub(crate) const BRIDGE_HUB_ROCOCO_LOCAL: &str = "bridge-hub-rococo-local"; pub(crate) const BRIDGE_HUB_ROCOCO_DEVELOPMENT: &str = "bridge-hub-rococo-dev"; - const BRIDGE_HUB_ROCOCO_ED: BridgeHubBalance = - bridge_hub_rococo_runtime::ExistentialDeposit::get(); pub fn local_config( id: &str, chain_name: &str, relay_chain: &str, para_id: ParaId, - bridges_pallet_owner_seed: Option, modify_props: ModifyProperties, + chain_type: ChainType, ) -> GenericChainSpec { // Rococo defaults let mut properties = sc_chain_spec::Properties::new(); @@ -163,86 +155,15 @@ pub mod rococo { ) .with_name(chain_name) .with_id(super::ensure_id(id).expect("invalid id")) - .with_chain_type(ChainType::Local) - .with_genesis_config_patch(genesis( - // initial collators. - vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ], - para_id, - bridges_pallet_owner_seed - .as_ref() - .map(|seed| get_account_id_from_seed::(seed)), - )) + .with_chain_type(chain_type.clone()) + .with_genesis_config_preset_name(match chain_type { + ChainType::Development => sp_genesis_builder::DEV_RUNTIME_PRESET, + ChainType::Local => sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET, + _ => panic!("chain_type: {chain_type:?} not supported here!"), + }) .with_properties(properties) .build() } - - fn genesis( - invulnerables: Vec<(AccountId, AuraId)>, - endowed_accounts: Vec, - id: ParaId, - bridges_pallet_owner: Option, - ) -> serde_json::Value { - serde_json::json!({ - "balances": { - "balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::>(), - }, - "parachainInfo": { - "parachainId": id, - }, - "collatorSelection": { - "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), - "candidacyBond": BRIDGE_HUB_ROCOCO_ED * 16, - }, - "session": { - "keys": invulnerables - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - bridge_hub_rococo_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect::>(), - }, - "polkadotXcm": { - "safeXcmVersion": Some(SAFE_XCM_VERSION), - }, - "bridgeWestendGrandpa": { - "owner": bridges_pallet_owner.clone(), - }, - "bridgeWestendMessages": { - "owner": bridges_pallet_owner.clone(), - }, - "ethereumSystem": { - "paraId": id, - "assetHubParaId": 1000 - } - }) - } } /// Sub-module for Kusama setup @@ -253,25 +174,19 @@ pub mod kusama { /// Sub-module for Westend setup. pub mod westend { - use super::{get_account_id_from_seed, get_collator_keys_from_seed, sr25519, ParaId}; - use crate::chain_spec::{Extensions, GenericChainSpec, SAFE_XCM_VERSION}; - use parachains_common::{AccountId, AuraId}; - use sc_chain_spec::ChainType; - - use super::BridgeHubBalance; + use super::{ChainType, ParaId}; + use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; pub(crate) const BRIDGE_HUB_WESTEND: &str = "bridge-hub-westend"; pub(crate) const BRIDGE_HUB_WESTEND_LOCAL: &str = "bridge-hub-westend-local"; pub(crate) const BRIDGE_HUB_WESTEND_DEVELOPMENT: &str = "bridge-hub-westend-dev"; - const BRIDGE_HUB_WESTEND_ED: BridgeHubBalance = - bridge_hub_westend_runtime::ExistentialDeposit::get(); pub fn local_config( id: &str, chain_name: &str, relay_chain: &str, para_id: ParaId, - bridges_pallet_owner_seed: Option, + chain_type: ChainType, ) -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("tokenSymbol".into(), "WND".into()); @@ -284,82 +199,15 @@ pub mod westend { ) .with_name(chain_name) .with_id(super::ensure_id(id).expect("invalid id")) - .with_chain_type(ChainType::Local) - .with_genesis_config_patch(genesis( - // initial collators. - vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ], - para_id, - bridges_pallet_owner_seed - .as_ref() - .map(|seed| get_account_id_from_seed::(seed)), - )) + .with_chain_type(chain_type.clone()) + .with_genesis_config_preset_name(match chain_type { + ChainType::Development => sp_genesis_builder::DEV_RUNTIME_PRESET, + ChainType::Local => sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET, + _ => panic!("chain_type: {chain_type:?} not supported here!"), + }) .with_properties(properties) .build() } - - fn genesis( - invulnerables: Vec<(AccountId, AuraId)>, - endowed_accounts: Vec, - id: ParaId, - bridges_pallet_owner: Option, - ) -> serde_json::Value { - serde_json::json!({ - "balances": { - "balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::>(), - }, - "parachainInfo": { - "parachainId": id, - }, - "collatorSelection": { - "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), - "candidacyBond": BRIDGE_HUB_WESTEND_ED * 16, - }, - "session": { - "keys": invulnerables - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - bridge_hub_westend_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect::>(), - }, - "polkadotXcm": { - "safeXcmVersion": Some(SAFE_XCM_VERSION), - }, - "bridgeRococoGrandpa": { - "owner": bridges_pallet_owner.clone(), - }, - "bridgeRococoMessages": { - "owner": bridges_pallet_owner.clone(), - } - }) - } } /// Sub-module for Polkadot setup diff --git a/cumulus/polkadot-parachain/src/chain_spec/collectives.rs b/cumulus/polkadot-parachain/src/chain_spec/collectives.rs index c0a9f195d89b..0d2f66b5acc0 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/collectives.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/collectives.rs @@ -14,25 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, Extensions, GenericChainSpec, - SAFE_XCM_VERSION, -}; -use cumulus_primitives_core::ParaId; -use parachains_common::{AccountId, AuraId, Balance as CollectivesBalance}; +use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; use sc_service::ChainType; -use sp_core::sr25519; - -const COLLECTIVES_WESTEND_ED: CollectivesBalance = - collectives_westend_runtime::ExistentialDeposit::get(); - -/// Generate the session keys from individual elements. -/// -/// The input must be a tuple of individual keys (a single arg for now since we have just one key). -pub fn collectives_westend_session_keys(keys: AuraId) -> collectives_westend_runtime::SessionKeys { - collectives_westend_runtime::SessionKeys { aura: keys } -} +/// Collectives Westend Development Config. pub fn collectives_westend_development_config() -> GenericChainSpec { let mut properties = sc_chain_spec::Properties::new(); properties.insert("ss58Format".into(), 42.into()); @@ -42,27 +27,12 @@ pub fn collectives_westend_development_config() -> GenericChainSpec { GenericChainSpec::builder( collectives_westend_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "westend-dev".into(), para_id: 1002 }, + Extensions { relay_chain: "westend-dev".into(), para_id: 1001 }, ) .with_name("Westend Collectives Development") .with_id("collectives_westend_dev") - .with_chain_type(ChainType::Local) - .with_genesis_config_patch(collectives_westend_genesis( - // initial collators. - vec![( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - )], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - ], - // 1002 avoids a potential collision with Kusama-1001 (Encointer) should there ever - // be a collective para on Kusama. - 1002.into(), - )) + .with_chain_type(ChainType::Development) + .with_genesis_config_preset_name(sp_genesis_builder::DEV_RUNTIME_PRESET) .with_boot_nodes(Vec::new()) .with_properties(properties) .build() @@ -78,80 +48,13 @@ pub fn collectives_westend_local_config() -> GenericChainSpec { GenericChainSpec::builder( collectives_westend_runtime::WASM_BINARY .expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "westend-local".into(), para_id: 1002 }, + Extensions { relay_chain: "westend-local".into(), para_id: 1001 }, ) .with_name("Westend Collectives Local") .with_id("collectives_westend_local") .with_chain_type(ChainType::Local) - .with_genesis_config_patch(collectives_westend_genesis( - // initial collators. - vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ], - 1002.into(), - )) + .with_genesis_config_preset_name(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) .with_boot_nodes(Vec::new()) .with_properties(properties) .build() } - -fn collectives_westend_genesis( - invulnerables: Vec<(AccountId, AuraId)>, - endowed_accounts: Vec, - id: ParaId, -) -> serde_json::Value { - serde_json::json!( { - "balances": { - "balances": endowed_accounts - .iter() - .cloned() - .map(|k| (k, COLLECTIVES_WESTEND_ED * 4096)) - .collect::>(), - }, - "parachainInfo": { - "parachainId": id, - }, - "collatorSelection": { - "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), - "candidacyBond": COLLECTIVES_WESTEND_ED * 16, - }, - "session": { - "keys": invulnerables - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - collectives_westend_session_keys(aura), // session keys - ) - }) - .collect::>(), - }, - // no need to pass anything to aura, in fact it will panic if we do. Session will take care - // of this. - "polkadotXcm": { - "safeXcmVersion": Some(SAFE_XCM_VERSION), - }, - }) -} diff --git a/cumulus/polkadot-parachain/src/chain_spec/contracts.rs b/cumulus/polkadot-parachain/src/chain_spec/contracts.rs deleted file mode 100644 index 4e89b81d1be4..000000000000 --- a/cumulus/polkadot-parachain/src/chain_spec/contracts.rs +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, Extensions, GenericChainSpec, - SAFE_XCM_VERSION, -}; -use cumulus_primitives_core::ParaId; -use hex_literal::hex; -use parachains_common::{AccountId, AuraId}; -use sc_service::ChainType; -use sp_core::{crypto::UncheckedInto, sr25519}; - -/// No relay chain suffix because the id is the same over all relay chains. -const CONTRACTS_PARACHAIN_ID: u32 = 1002; - -/// The existential deposit is determined by the runtime "contracts-rococo". -const CONTRACTS_ROCOCO_ED: contracts_rococo_runtime::Balance = - testnet_parachains_constants::rococo::currency::EXISTENTIAL_DEPOSIT; - -pub fn contracts_rococo_development_config() -> GenericChainSpec { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("tokenSymbol".into(), "ROC".into()); - properties.insert("tokenDecimals".into(), 12.into()); - - GenericChainSpec::builder( - contracts_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { - relay_chain: "rococo-local".into(), // You MUST set this to the correct network! - para_id: CONTRACTS_PARACHAIN_ID, - }, - ) - .with_name("Contracts on Rococo Development") - .with_id("contracts-rococo-dev") - .with_chain_type(ChainType::Development) - .with_genesis_config_patch(contracts_rococo_genesis( - // initial collators. - vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ], - CONTRACTS_PARACHAIN_ID.into(), - )) - .with_boot_nodes(Vec::new()) - .build() -} - -pub fn contracts_rococo_local_config() -> GenericChainSpec { - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("tokenSymbol".into(), "ROC".into()); - properties.insert("tokenDecimals".into(), 12.into()); - - GenericChainSpec::builder( - contracts_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { - relay_chain: "rococo-local".into(), // You MUST set this to the correct network! - para_id: CONTRACTS_PARACHAIN_ID, - }, - ) - .with_name("Contracts on Rococo") - .with_id("contracts-rococo-local") - .with_chain_type(ChainType::Local) - .with_genesis_config_patch(contracts_rococo_genesis( - // initial collators. - vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ], - CONTRACTS_PARACHAIN_ID.into(), - )) - .with_properties(properties) - .build() -} - -pub fn contracts_rococo_config() -> GenericChainSpec { - // Give your base currency a unit name and decimal places - let mut properties = sc_chain_spec::Properties::new(); - properties.insert("tokenSymbol".into(), "ROC".into()); - properties.insert("tokenDecimals".into(), 12.into()); - - GenericChainSpec::builder( - contracts_rococo_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "rococo".into(), para_id: CONTRACTS_PARACHAIN_ID } - ) - .with_name("Contracts on Rococo") - .with_id("contracts-rococo") - .with_chain_type(ChainType::Live) - .with_genesis_config_patch(contracts_rococo_genesis( - vec![ - // 5GKFbTTgrVS4Vz1UWWHPqMZQNFWZtqo7H2KpCDyYhEL3aS26 - ( - hex!["bc09354c12c054c8f6b3da208485eacec4ac648bad348895273b37bab5a0937c"] - .into(), - hex!["bc09354c12c054c8f6b3da208485eacec4ac648bad348895273b37bab5a0937c"] - .unchecked_into(), - ), - // 5EPRJHm2GpABVWcwnAujcrhnrjFZyDGd5TwKFzkBoGgdRyv2 - ( - hex!["66be63b7bcbfb91040e5248e2d1ceb822cf219c57848c5924ffa3a1f8e67ba72"] - .into(), - hex!["66be63b7bcbfb91040e5248e2d1ceb822cf219c57848c5924ffa3a1f8e67ba72"] - .unchecked_into(), - ), - // 5GH62vrJrVZxLREcHzm2PR5uTLAT5RQMJitoztCGyaP4o3uM - ( - hex!["ba62886472a0a9f66b5e39f1469ce1c5b3d8cad6be39078daf16f111e89d1e44"] - .into(), - hex!["ba62886472a0a9f66b5e39f1469ce1c5b3d8cad6be39078daf16f111e89d1e44"] - .unchecked_into(), - ), - // 5FHfoJDLdjRYX5KXLRqMDYBbWrwHLMtti21uK4QByUoUAbJF - ( - hex!["8e97f65cda001976311df9bed39e8d0c956089093e94a75ef76fe9347a0eda7b"] - .into(), - hex!["8e97f65cda001976311df9bed39e8d0c956089093e94a75ef76fe9347a0eda7b"] - .unchecked_into(), - ), - ], - // Warning: The configuration for a production chain should not contain - // any endowed accounts here, otherwise it'll be minting extra native tokens - // from the relay chain on the parachain. - vec![ - // NOTE: Remove endowed accounts if deployed on other relay chains. - // Endowed accounts - hex!["baa78c7154c7f82d6d377177e20bcab65d327eca0086513f9964f5a0f6bdad56"].into(), - // AccountId of an account which `ink-waterfall` uses for automated testing - hex!["0e47e2344d523c3cc5c34394b0d58b9a4200e813a038e6c5a6163cc07d70b069"].into(), - ], - CONTRACTS_PARACHAIN_ID.into(), - )) - .with_boot_nodes(vec![ - "/dns/contracts-collator-0.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWKg3Rpxcr9oJ8n6khoxpGKWztCZydtUZk2cojHqnfLrpj" - .parse() - .expect("MultiaddrWithPeerId"), - "/dns/contracts-collator-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWPEXYrz8tHU3nDtPoPw4V7ou5dzMEWSTuUj7vaWiYVAVh" - .parse() - .expect("MultiaddrWithPeerId"), - "/dns/contracts-collator-2.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWEVU8AFNary4nP4qEnEcwJaRuy59Wefekzdu9pKbnVEhk" - .parse() - .expect("MultiaddrWithPeerId"), - "/dns/contracts-collator-3.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWP6pV3ZmcXzGDjv8ZMgA6nZxfAKDxSz4VNiLx6vVCQgJX" - .parse() - .expect("MultiaddrWithPeerId"), - ]) - .with_properties(properties) - .build() -} - -fn contracts_rococo_genesis( - invulnerables: Vec<(AccountId, AuraId)>, - endowed_accounts: Vec, - id: ParaId, -) -> serde_json::Value { - serde_json::json!( { - "balances": { - "balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::>(), - }, - "parachainInfo": { - "parachainId": id, - }, - "collatorSelection": { - "invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::>(), - "candidacyBond": CONTRACTS_ROCOCO_ED * 16, - }, - "session": { - "keys": invulnerables - .into_iter() - .map(|(acc, aura)| { - ( - acc.clone(), // account id - acc, // validator id - contracts_rococo_runtime::SessionKeys { aura }, // session keys - ) - }) - .collect::>(), - }, - // no need to pass anything to aura, in fact it will panic if we do. Session will take care - // of this. - "polkadotXcm": { - "safeXcmVersion": Some(SAFE_XCM_VERSION), - }, - "sudo": { - "key": Some(sp_runtime::AccountId32::from(hex![ - "2681a28014e7d3a5bfb32a003b3571f53c408acbc28d351d6bf58f5028c4ef14" - ])), - }, - }) -} diff --git a/cumulus/polkadot-parachain/src/chain_spec/coretime.rs b/cumulus/polkadot-parachain/src/chain_spec/coretime.rs index fe60b09fd8b2..fa865d7458cb 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/coretime.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/coretime.rs @@ -14,8 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::chain_spec::GenericChainSpec; use cumulus_primitives_core::ParaId; +use polkadot_omni_node_lib::chain_spec::GenericChainSpec; use sc_chain_spec::{ChainSpec, ChainType}; use std::{borrow::Cow, str::FromStr}; @@ -107,8 +107,9 @@ impl CoretimeRuntimeType { CoretimeRuntimeType::Kusama => Ok(Box::new(GenericChainSpec::from_json_bytes( &include_bytes!("../../chain-specs/coretime-kusama.json")[..], )?)), - CoretimeRuntimeType::Polkadot => - todo!("Generate chain-spec: ../../chain-specs/coretime-polkadot.json"), + CoretimeRuntimeType::Polkadot => Ok(Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../../chain-specs/coretime-polkadot.json")[..], + )?)), CoretimeRuntimeType::Rococo => Ok(Box::new(GenericChainSpec::from_json_bytes( &include_bytes!("../../chain-specs/coretime-rococo.json")[..], )?)), @@ -144,13 +145,12 @@ pub fn chain_type_name(chain_type: &ChainType) -> Cow { /// Sub-module for Rococo setup. pub mod rococo { - use super::{chain_type_name, CoretimeRuntimeType, GenericChainSpec, ParaId}; - use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, Extensions, SAFE_XCM_VERSION, - }; + use super::{chain_type_name, CoretimeRuntimeType, ParaId}; + use crate::chain_spec::SAFE_XCM_VERSION; use parachains_common::{AccountId, AuraId, Balance}; + use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; use sc_chain_spec::ChainType; - use sp_core::sr25519; + use sp_keyring::Sr25519Keyring; pub(crate) const CORETIME_ROCOCO: &str = "coretime-rococo"; pub(crate) const CORETIME_ROCOCO_LOCAL: &str = "coretime-rococo-local"; @@ -185,15 +185,12 @@ pub mod rococo { .with_chain_type(chain_type) .with_genesis_config_patch(genesis( // initial collators. - vec![( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - )], + vec![(Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into())], vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), + Sr25519Keyring::Alice.to_account_id(), + Sr25519Keyring::Bob.to_account_id(), + Sr25519Keyring::AliceStash.to_account_id(), + Sr25519Keyring::BobStash.to_account_id(), ], para_id, )) @@ -233,7 +230,7 @@ pub mod rococo { "safeXcmVersion": Some(SAFE_XCM_VERSION), }, "sudo": { - "key": Some(get_account_id_from_seed::("Alice")), + "key": Some(Sr25519Keyring::Alice.to_account_id()), }, }) } @@ -242,11 +239,10 @@ pub mod rococo { /// Sub-module for Westend setup. pub mod westend { use super::{chain_type_name, CoretimeRuntimeType, GenericChainSpec, ParaId}; - use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, Extensions, SAFE_XCM_VERSION, - }; + use crate::chain_spec::SAFE_XCM_VERSION; use parachains_common::{AccountId, AuraId, Balance}; - use sp_core::sr25519; + use polkadot_omni_node_lib::chain_spec::Extensions; + use sp_keyring::Sr25519Keyring; pub(crate) const CORETIME_WESTEND: &str = "coretime-westend"; pub(crate) const CORETIME_WESTEND_LOCAL: &str = "coretime-westend-local"; @@ -274,15 +270,12 @@ pub mod westend { .with_chain_type(chain_type) .with_genesis_config_patch(genesis( // initial collators. - vec![( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - )], + vec![(Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into())], vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), + Sr25519Keyring::Alice.to_account_id(), + Sr25519Keyring::Bob.to_account_id(), + Sr25519Keyring::AliceStash.to_account_id(), + Sr25519Keyring::BobStash.to_account_id(), ], para_id, )) diff --git a/cumulus/polkadot-parachain/src/chain_spec/glutton.rs b/cumulus/polkadot-parachain/src/chain_spec/glutton.rs index 77a4123b13ee..ddfb961370ac 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/glutton.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/glutton.rs @@ -14,13 +14,11 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::chain_spec::{get_account_id_from_seed, Extensions, GenericChainSpec}; use cumulus_primitives_core::ParaId; use parachains_common::AuraId; +use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; use sc_service::ChainType; -use sp_core::sr25519; - -use super::get_collator_keys_from_seed; +use sp_keyring::Sr25519Keyring; fn glutton_genesis(parachain_id: ParaId, collators: Vec) -> serde_json::Value { serde_json::json!( { @@ -28,7 +26,7 @@ fn glutton_genesis(parachain_id: ParaId, collators: Vec) -> serde_json:: "parachainId": parachain_id }, "sudo": { - "key": Some(get_account_id_from_seed::("Alice")), + "key": Some(Sr25519Keyring::Alice.to_account_id()), }, "aura": { "authorities": collators }, }) @@ -44,7 +42,7 @@ pub fn glutton_westend_development_config(para_id: ParaId) -> GenericChainSpec { .with_chain_type(ChainType::Local) .with_genesis_config_patch(glutton_genesis( para_id, - vec![get_collator_keys_from_seed::("Alice")], + vec![Sr25519Keyring::Alice.public().into()], )) .build() } @@ -59,10 +57,7 @@ pub fn glutton_westend_local_config(para_id: ParaId) -> GenericChainSpec { .with_chain_type(ChainType::Local) .with_genesis_config_patch(glutton_genesis( para_id, - vec![ - get_collator_keys_from_seed::("Alice"), - get_collator_keys_from_seed::("Bob"), - ], + vec![Sr25519Keyring::Alice.public().into(), Sr25519Keyring::Bob.public().into()], )) .build() } @@ -80,10 +75,7 @@ pub fn glutton_westend_config(para_id: ParaId) -> GenericChainSpec { .with_chain_type(ChainType::Live) .with_genesis_config_patch(glutton_westend_genesis( para_id, - vec![ - get_collator_keys_from_seed::("Alice"), - get_collator_keys_from_seed::("Bob"), - ], + vec![Sr25519Keyring::Alice.public().into(), Sr25519Keyring::Bob.public().into()], )) .with_protocol_id(format!("glutton-westend-{}", para_id).as_str()) .with_properties(properties) @@ -96,7 +88,7 @@ fn glutton_westend_genesis(parachain_id: ParaId, collators: Vec) -> serd "parachainId": parachain_id }, "sudo": { - "key": Some(get_account_id_from_seed::("Alice")), + "key": Some(Sr25519Keyring::Alice.to_account_id()), }, "aura": { "authorities": collators }, }) diff --git a/cumulus/polkadot-parachain/src/chain_spec/mod.rs b/cumulus/polkadot-parachain/src/chain_spec/mod.rs index 19047b073b05..00dceabb0069 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/mod.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/mod.rs @@ -14,87 +14,314 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use parachains_common::{AccountId, Signature}; -use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup}; -use serde::{Deserialize, Serialize}; -use sp_core::{Pair, Public}; -use sp_runtime::traits::{IdentifyAccount, Verify}; +use cumulus_primitives_core::ParaId; +use polkadot_omni_node_lib::{ + chain_spec::{GenericChainSpec, LoadSpec}, + runtime::{ + AuraConsensusId, BlockNumber, Consensus, Runtime, RuntimeResolver as RuntimeResolverT, + }, +}; +use sc_chain_spec::ChainSpec; pub mod asset_hubs; pub mod bridge_hubs; pub mod collectives; -pub mod contracts; pub mod coretime; pub mod glutton; pub mod penpal; pub mod people; pub mod rococo_parachain; -pub mod seedling; -pub mod shell; /// The default XCM version to set in genesis config. const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION; -/// Generic extensions for Parachain ChainSpecs. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)] -pub struct Extensions { - /// The relay chain of the Parachain. - #[serde(alias = "relayChain", alias = "RelayChain")] - pub relay_chain: String, - /// The id of the Parachain. - #[serde(alias = "paraId", alias = "ParaId")] - pub para_id: u32, +/// Extracts the normalized chain id and parachain id from the input chain id. +/// (H/T to Phala for the idea) +/// E.g. "penpal-kusama-2004" yields ("penpal-kusama", Some(2004)) +fn extract_parachain_id<'a>( + id: &'a str, + para_prefixes: &[&str], +) -> (&'a str, &'a str, Option) { + for para_prefix in para_prefixes { + if let Some(suffix) = id.strip_prefix(para_prefix) { + let para_id: u32 = suffix.parse().expect("Invalid parachain-id suffix"); + return (&id[..para_prefix.len() - 1], id, Some(para_id.into())); + } + } + + (id, id, None) } -impl Extensions { - /// Try to get the extension from the given `ChainSpec`. - pub fn try_get(chain_spec: &dyn sc_service::ChainSpec) -> Option<&Self> { - sc_chain_spec::get_extension(chain_spec.extensions()) +#[derive(Debug)] +pub(crate) struct ChainSpecLoader; + +impl LoadSpec for ChainSpecLoader { + fn load_spec(&self, id: &str) -> Result, String> { + Ok(match id { + // - Default-like + "staging" => Box::new(rococo_parachain::staging_rococo_parachain_local_config()), + "tick" => Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../../chain-specs/tick.json")[..], + )?), + "trick" => Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../../chain-specs/trick.json")[..], + )?), + "track" => Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../../chain-specs/track.json")[..], + )?), + + // -- Asset Hub Polkadot + "asset-hub-polkadot" | "statemint" => Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../../chain-specs/asset-hub-polkadot.json")[..], + )?), + + // -- Asset Hub Kusama + "asset-hub-kusama" | "statemine" => Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../../chain-specs/asset-hub-kusama.json")[..], + )?), + + // -- Asset Hub Rococo + "asset-hub-rococo-dev" => Box::new(asset_hubs::asset_hub_rococo_development_config()), + "asset-hub-rococo-local" => Box::new(asset_hubs::asset_hub_rococo_local_config()), + // the chain spec as used for generating the upgrade genesis values + "asset-hub-rococo-genesis" => Box::new(asset_hubs::asset_hub_rococo_genesis_config()), + "asset-hub-rococo" => Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../../chain-specs/asset-hub-rococo.json")[..], + )?), + + // -- Asset Hub Westend + "asset-hub-westend-dev" | "westmint-dev" => + Box::new(asset_hubs::asset_hub_westend_development_config()), + "asset-hub-westend-local" | "westmint-local" => + Box::new(asset_hubs::asset_hub_westend_local_config()), + // the chain spec as used for generating the upgrade genesis values + "asset-hub-westend-genesis" | "westmint-genesis" => + Box::new(asset_hubs::asset_hub_westend_config()), + // the shell-based chain spec as used for syncing + "asset-hub-westend" | "westmint" => Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../../chain-specs/asset-hub-westend.json")[..], + )?), + + // -- Polkadot Collectives + "collectives-polkadot" => Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../../chain-specs/collectives-polkadot.json")[..], + )?), + + // -- Westend Collectives + "collectives-westend-dev" => + Box::new(collectives::collectives_westend_development_config()), + "collectives-westend-local" => + Box::new(collectives::collectives_westend_local_config()), + "collectives-westend" => Box::new(GenericChainSpec::from_json_bytes( + &include_bytes!("../../chain-specs/collectives-westend.json")[..], + )?), + + // -- BridgeHub + bridge_like_id + if bridge_like_id.starts_with(bridge_hubs::BridgeHubRuntimeType::ID_PREFIX) => + bridge_like_id + .parse::() + .expect("invalid value") + .load_config()?, + + // -- Coretime + coretime_like_id + if coretime_like_id.starts_with(coretime::CoretimeRuntimeType::ID_PREFIX) => + coretime_like_id + .parse::() + .expect("invalid value") + .load_config()?, + + // -- Penpal + id if id.starts_with("penpal-rococo") => { + let (_, _, para_id) = extract_parachain_id(&id, &["penpal-rococo-"]); + Box::new(penpal::get_penpal_chain_spec( + para_id.expect("Must specify parachain id"), + "rococo-local", + )) + }, + id if id.starts_with("penpal-westend") => { + let (_, _, para_id) = extract_parachain_id(&id, &["penpal-westend-"]); + Box::new(penpal::get_penpal_chain_spec( + para_id.expect("Must specify parachain id"), + "westend-local", + )) + }, + + // -- Glutton Westend + id if id.starts_with("glutton-westend-dev") => { + let (_, _, para_id) = extract_parachain_id(&id, &["glutton-westend-dev-"]); + Box::new(glutton::glutton_westend_development_config( + para_id.expect("Must specify parachain id"), + )) + }, + id if id.starts_with("glutton-westend-local") => { + let (_, _, para_id) = extract_parachain_id(&id, &["glutton-westend-local-"]); + Box::new(glutton::glutton_westend_local_config( + para_id.expect("Must specify parachain id"), + )) + }, + // the chain spec as used for generating the upgrade genesis values + id if id.starts_with("glutton-westend-genesis") => { + let (_, _, para_id) = extract_parachain_id(&id, &["glutton-westend-genesis-"]); + Box::new(glutton::glutton_westend_config( + para_id.expect("Must specify parachain id"), + )) + }, + + // -- People + people_like_id if people_like_id.starts_with(people::PeopleRuntimeType::ID_PREFIX) => + people_like_id + .parse::() + .expect("invalid value") + .load_config()?, + + // -- Fallback (generic chainspec) + "" => { + log::warn!("No ChainSpec.id specified, so using default one, based on rococo-parachain runtime"); + Box::new(rococo_parachain::rococo_parachain_local_config()) + }, + + // -- Loading a specific spec from disk + path => Box::new(GenericChainSpec::from_json_file(path.into())?), + }) } } -/// Generic chain spec for all polkadot-parachain runtimes -pub type GenericChainSpec = sc_service::GenericChainSpec; - -/// Helper function to generate a crypto pair from seed -pub fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() +/// Helper enum that is used for better distinction of different parachain/runtime configuration +/// (it is based/calculated on ChainSpec's ID attribute) +#[derive(Debug, PartialEq)] +enum LegacyRuntime { + Omni, + AssetHubPolkadot, + AssetHub, + Penpal, + Collectives, + Glutton, + BridgeHub(bridge_hubs::BridgeHubRuntimeType), + Coretime(coretime::CoretimeRuntimeType), + People(people::PeopleRuntimeType), } -type AccountPublic = ::Signer; +impl LegacyRuntime { + fn from_id(id: &str) -> LegacyRuntime { + let id = id.replace('_', "-"); -/// Helper function to generate an account ID from seed -pub fn get_account_id_from_seed(seed: &str) -> AccountId -where - AccountPublic: From<::Public>, -{ - AccountPublic::from(get_from_seed::(seed)).into_account() + if id.starts_with("asset-hub-polkadot") | id.starts_with("statemint") { + LegacyRuntime::AssetHubPolkadot + } else if id.starts_with("asset-hub-kusama") | + id.starts_with("statemine") | + id.starts_with("asset-hub-rococo") | + id.starts_with("rockmine") | + id.starts_with("asset-hub-westend") | + id.starts_with("westmint") + { + LegacyRuntime::AssetHub + } else if id.starts_with("penpal") { + LegacyRuntime::Penpal + } else if id.starts_with("collectives-polkadot") || id.starts_with("collectives-westend") { + LegacyRuntime::Collectives + } else if id.starts_with(bridge_hubs::BridgeHubRuntimeType::ID_PREFIX) { + LegacyRuntime::BridgeHub( + id.parse::().expect("Invalid value"), + ) + } else if id.starts_with(coretime::CoretimeRuntimeType::ID_PREFIX) { + LegacyRuntime::Coretime( + id.parse::().expect("Invalid value"), + ) + } else if id.starts_with("glutton") { + LegacyRuntime::Glutton + } else if id.starts_with(people::PeopleRuntimeType::ID_PREFIX) { + LegacyRuntime::People(id.parse::().expect("Invalid value")) + } else { + log::warn!( + "No specific runtime was recognized for ChainSpec's id: '{}', \ + so Runtime::Omni(Consensus::Aura) will be used", + id + ); + LegacyRuntime::Omni + } + } } -/// Generate collator keys from seed. -/// -/// This function's return type must always match the session keys of the chain in tuple format. -pub fn get_collator_keys_from_seed(seed: &str) -> ::Public { - get_from_seed::(seed) +#[derive(Debug)] +pub(crate) struct RuntimeResolver; + +impl RuntimeResolverT for RuntimeResolver { + fn runtime(&self, chain_spec: &dyn ChainSpec) -> sc_cli::Result { + let legacy_runtime = LegacyRuntime::from_id(chain_spec.id()); + Ok(match legacy_runtime { + LegacyRuntime::AssetHubPolkadot => + Runtime::Omni(BlockNumber::U32, Consensus::Aura(AuraConsensusId::Ed25519)), + LegacyRuntime::AssetHub | + LegacyRuntime::BridgeHub(_) | + LegacyRuntime::Collectives | + LegacyRuntime::Coretime(_) | + LegacyRuntime::People(_) | + LegacyRuntime::Glutton | + LegacyRuntime::Penpal | + LegacyRuntime::Omni => + Runtime::Omni(BlockNumber::U32, Consensus::Aura(AuraConsensusId::Sr25519)), + }) + } } #[cfg(test)] mod tests { use super::*; + use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup, ChainType, Extension}; + use serde::{Deserialize, Serialize}; + use sp_keyring::Sr25519Keyring; - #[test] - fn can_decode_extension_camel_and_snake_case() { - let camel_case = r#"{"relayChain":"relay","paraId":1}"#; - let snake_case = r#"{"relay_chain":"relay","para_id":1}"#; - let pascal_case = r#"{"RelayChain":"relay","ParaId":1}"#; + #[derive( + Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension, Default, + )] + #[serde(deny_unknown_fields)] + pub struct Extensions1 { + pub attribute1: String, + pub attribute2: u32, + } + + #[derive( + Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension, Default, + )] + #[serde(deny_unknown_fields)] + pub struct Extensions2 { + pub attribute_x: String, + pub attribute_y: String, + pub attribute_z: u32, + } + + pub type DummyChainSpec = sc_service::GenericChainSpec; - let camel_case_extension: Extensions = serde_json::from_str(camel_case).unwrap(); - let snake_case_extension: Extensions = serde_json::from_str(snake_case).unwrap(); - let pascal_case_extension: Extensions = serde_json::from_str(pascal_case).unwrap(); + pub fn create_default_with_extensions( + id: &str, + extension: E, + ) -> DummyChainSpec { + DummyChainSpec::builder( + rococo_parachain_runtime::WASM_BINARY + .expect("WASM binary was not built, please build it!"), + extension, + ) + .with_name("Dummy local testnet") + .with_id(id) + .with_chain_type(ChainType::Local) + .with_genesis_config_patch(crate::chain_spec::rococo_parachain::testnet_genesis( + Sr25519Keyring::Alice.to_account_id(), + vec![Sr25519Keyring::Alice.public().into(), Sr25519Keyring::Bob.public().into()], + vec![Sr25519Keyring::Bob.to_account_id()], + 1000.into(), + )) + .build() + } + + #[test] + fn test_legacy_runtime_for_different_chain_specs() { + let chain_spec = + create_default_with_extensions("penpal-rococo-1000", Extensions2::default()); + assert_eq!(LegacyRuntime::Penpal, LegacyRuntime::from_id(chain_spec.id())); - assert_eq!(camel_case_extension, snake_case_extension); - assert_eq!(snake_case_extension, pascal_case_extension); + let chain_spec = crate::chain_spec::rococo_parachain::rococo_parachain_local_config(); + assert_eq!(LegacyRuntime::Omni, LegacyRuntime::from_id(chain_spec.id())); } } diff --git a/cumulus/polkadot-parachain/src/chain_spec/penpal.rs b/cumulus/polkadot-parachain/src/chain_spec/penpal.rs index cb1cb632d638..b60b9982c49e 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/penpal.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/penpal.rs @@ -14,14 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, Extensions, GenericChainSpec, - SAFE_XCM_VERSION, -}; +use crate::chain_spec::SAFE_XCM_VERSION; use cumulus_primitives_core::ParaId; use parachains_common::{AccountId, AuraId}; +use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; use sc_service::ChainType; -use sp_core::sr25519; +use sp_keyring::Sr25519Keyring; pub fn get_penpal_chain_spec(id: ParaId, relay_chain: &str) -> GenericChainSpec { // Give your base currency a unit name and decimal places @@ -43,29 +41,10 @@ pub fn get_penpal_chain_spec(id: ParaId, relay_chain: &str) -> GenericChainSpec .with_genesis_config_patch(penpal_testnet_genesis( // initial collators. vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), id, )) .build() @@ -107,7 +86,7 @@ fn penpal_testnet_genesis( "safeXcmVersion": Some(SAFE_XCM_VERSION), }, "sudo": { - "key": Some(get_account_id_from_seed::("Alice")), + "key": Some(Sr25519Keyring::Alice.to_account_id()), }, }) } diff --git a/cumulus/polkadot-parachain/src/chain_spec/people.rs b/cumulus/polkadot-parachain/src/chain_spec/people.rs index db8756e68819..1735a904b8ea 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/people.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/people.rs @@ -14,9 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use crate::chain_spec::GenericChainSpec; use cumulus_primitives_core::ParaId; use parachains_common::Balance as PeopleBalance; +use polkadot_omni_node_lib::chain_spec::GenericChainSpec; use sc_chain_spec::ChainSpec; use std::str::FromStr; @@ -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")[..], )?)), @@ -119,13 +120,11 @@ fn ensure_id(id: &str) -> Result<&str, String> { /// Sub-module for Rococo setup. pub mod rococo { use super::{ParaId, PeopleBalance}; - use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, Extensions, GenericChainSpec, - SAFE_XCM_VERSION, - }; + use crate::chain_spec::SAFE_XCM_VERSION; use parachains_common::{AccountId, AuraId}; + use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; use sc_chain_spec::ChainType; - use sp_core::sr25519; + use sp_keyring::Sr25519Keyring; pub(crate) const PEOPLE_ROCOCO: &str = "people-rococo"; pub(crate) const PEOPLE_ROCOCO_LOCAL: &str = "people-rococo-local"; @@ -154,29 +153,10 @@ pub mod rococo { .with_genesis_config_patch(genesis( // initial collators. vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), para_id, )) .with_properties(properties) @@ -229,13 +209,11 @@ pub mod rococo { /// Sub-module for Westend setup. pub mod westend { use super::{ParaId, PeopleBalance}; - use crate::chain_spec::{ - get_account_id_from_seed, get_collator_keys_from_seed, Extensions, GenericChainSpec, - SAFE_XCM_VERSION, - }; + use crate::chain_spec::SAFE_XCM_VERSION; use parachains_common::{AccountId, AuraId}; + use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; use sc_chain_spec::ChainType; - use sp_core::sr25519; + use sp_keyring::Sr25519Keyring; pub(crate) const PEOPLE_WESTEND: &str = "people-westend"; pub(crate) const PEOPLE_WESTEND_LOCAL: &str = "people-westend-local"; @@ -264,29 +242,10 @@ pub mod westend { .with_genesis_config_patch(genesis( // initial collators. vec![ - ( - get_account_id_from_seed::("Alice"), - get_collator_keys_from_seed::("Alice"), - ), - ( - get_account_id_from_seed::("Bob"), - get_collator_keys_from_seed::("Bob"), - ), - ], - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), + (Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()), + (Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()), ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), para_id, )) .with_properties(properties) diff --git a/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs b/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs index 0434e5f7be8f..68383ac5c233 100644 --- a/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs +++ b/cumulus/polkadot-parachain/src/chain_spec/rococo_parachain.rs @@ -16,14 +16,15 @@ //! ChainSpecs dedicated to Rococo parachain setups (for testing and example purposes) -use crate::chain_spec::{get_from_seed, Extensions, GenericChainSpec, SAFE_XCM_VERSION}; +use crate::chain_spec::SAFE_XCM_VERSION; use cumulus_primitives_core::ParaId; use hex_literal::hex; use parachains_common::AccountId; -use polkadot_service::chain_spec::get_account_id_from_seed; +use polkadot_omni_node_lib::chain_spec::{Extensions, GenericChainSpec}; use rococo_parachain_runtime::AuraId; use sc_chain_spec::ChainType; -use sp_core::{crypto::UncheckedInto, sr25519}; +use sp_core::crypto::UncheckedInto; +use sp_keyring::Sr25519Keyring; pub fn rococo_parachain_local_config() -> GenericChainSpec { GenericChainSpec::builder( @@ -34,22 +35,12 @@ pub fn rococo_parachain_local_config() -> GenericChainSpec { .with_id("local_testnet") .with_chain_type(ChainType::Local) .with_genesis_config_patch(testnet_genesis( - get_account_id_from_seed::("Alice"), - vec![get_from_seed::("Alice"), get_from_seed::("Bob")], + Sr25519Keyring::Alice.to_account_id(), vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), + AuraId::from(Sr25519Keyring::Alice.public()), + AuraId::from(Sr25519Keyring::Bob.public()), ], + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(), 1000.into(), )) .build() diff --git a/cumulus/polkadot-parachain/src/chain_spec/seedling.rs b/cumulus/polkadot-parachain/src/chain_spec/seedling.rs deleted file mode 100644 index 32d516220545..000000000000 --- a/cumulus/polkadot-parachain/src/chain_spec/seedling.rs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -use crate::chain_spec::{get_account_id_from_seed, Extensions, GenericChainSpec}; -use cumulus_primitives_core::ParaId; -use parachains_common::{AccountId, AuraId}; -use sc_service::ChainType; -use sp_core::sr25519; - -use super::get_collator_keys_from_seed; - -pub fn get_seedling_chain_spec() -> GenericChainSpec { - GenericChainSpec::builder( - seedling_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "westend".into(), para_id: 2000 }, - ) - .with_name("Seedling Local Testnet") - .with_id("seedling_local_testnet") - .with_chain_type(ChainType::Local) - .with_genesis_config_patch(seedling_testnet_genesis( - get_account_id_from_seed::("Alice"), - 2000.into(), - vec![get_collator_keys_from_seed::("Alice")], - )) - .with_boot_nodes(Vec::new()) - .build() -} - -fn seedling_testnet_genesis( - root_key: AccountId, - parachain_id: ParaId, - collators: Vec, -) -> serde_json::Value { - serde_json::json!({ - "sudo": { "key": Some(root_key) }, - "parachainInfo": { - "parachainId": parachain_id, - }, - "aura": { "authorities": collators }, - }) -} diff --git a/cumulus/polkadot-parachain/src/chain_spec/shell.rs b/cumulus/polkadot-parachain/src/chain_spec/shell.rs deleted file mode 100644 index e0a9875fb96f..000000000000 --- a/cumulus/polkadot-parachain/src/chain_spec/shell.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -use crate::chain_spec::{Extensions, GenericChainSpec}; -use cumulus_primitives_core::ParaId; -use parachains_common::AuraId; -use sc_service::ChainType; - -use super::get_collator_keys_from_seed; - -pub fn get_shell_chain_spec() -> GenericChainSpec { - GenericChainSpec::builder( - shell_runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"), - Extensions { relay_chain: "westend".into(), para_id: 1000 }, - ) - .with_name("Shell Local Testnet") - .with_id("shell_local_testnet") - .with_chain_type(ChainType::Local) - .with_genesis_config_patch(shell_testnet_genesis( - 1000.into(), - vec![get_collator_keys_from_seed::("Alice")], - )) - .with_boot_nodes(Vec::new()) - .build() -} - -fn shell_testnet_genesis(parachain_id: ParaId, collators: Vec) -> serde_json::Value { - serde_json::json!({ - "parachainInfo": { "parachainId": parachain_id}, - "aura": { "authorities": collators }, - }) -} diff --git a/cumulus/polkadot-parachain/src/cli.rs b/cumulus/polkadot-parachain/src/cli.rs deleted file mode 100644 index d06354dda220..000000000000 --- a/cumulus/polkadot-parachain/src/cli.rs +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -use crate::common::NodeExtraArgs; -use clap::{Command, CommandFactory, FromArgMatches}; -use sc_cli::SubstrateCli; -use std::path::PathBuf; - -/// Sub-commands supported by the collator. -#[derive(Debug, clap::Subcommand)] -pub enum Subcommand { - /// Key management CLI utilities - #[command(subcommand)] - Key(sc_cli::KeySubcommand), - - /// Build a chain specification. - BuildSpec(sc_cli::BuildSpecCmd), - - /// Validate blocks. - CheckBlock(sc_cli::CheckBlockCmd), - - /// Export blocks. - ExportBlocks(sc_cli::ExportBlocksCmd), - - /// Export the state of a given block into a chain spec. - ExportState(sc_cli::ExportStateCmd), - - /// Import blocks. - ImportBlocks(sc_cli::ImportBlocksCmd), - - /// Revert the chain to a previous state. - Revert(sc_cli::RevertCmd), - - /// Remove the whole chain. - PurgeChain(cumulus_client_cli::PurgeChainCmd), - - /// Export the genesis state of the parachain. - #[command(alias = "export-genesis-state")] - ExportGenesisHead(cumulus_client_cli::ExportGenesisHeadCommand), - - /// Export the genesis wasm of the parachain. - ExportGenesisWasm(cumulus_client_cli::ExportGenesisWasmCommand), - - /// Sub-commands concerned with benchmarking. - /// The pallet benchmarking moved to the `pallet` sub-command. - #[command(subcommand)] - Benchmark(frame_benchmarking_cli::BenchmarkCmd), -} - -#[derive(Debug, clap::Parser)] -#[command( - propagate_version = true, - args_conflicts_with_subcommands = true, - subcommand_negates_reqs = true, - after_help = crate::examples(Self::executable_name()) -)] -pub struct Cli { - #[command(subcommand)] - pub subcommand: Option, - - #[command(flatten)] - pub run: cumulus_client_cli::RunCmd, - - /// EXPERIMENTAL: Use slot-based collator which can handle elastic scaling. - /// - /// Use with care, this flag is unstable and subject to change. - #[arg(long)] - pub experimental_use_slot_based: bool, - - /// Disable automatic hardware benchmarks. - /// - /// By default these benchmarks are automatically ran at startup and measure - /// the CPU speed, the memory bandwidth and the disk speed. - /// - /// The results are then printed out in the logs, and also sent as part of - /// telemetry, if telemetry is enabled. - #[arg(long)] - pub no_hardware_benchmarks: bool, - - /// Relay chain arguments - #[arg(raw = true)] - pub relay_chain_args: Vec, -} - -impl Cli { - pub(crate) fn node_extra_args(&self) -> NodeExtraArgs { - NodeExtraArgs { use_slot_based_consensus: self.experimental_use_slot_based } - } -} - -#[derive(Debug)] -pub struct RelayChainCli { - /// The actual relay chain cli object. - pub base: polkadot_cli::RunCmd, - - /// Optional chain id that should be passed to the relay chain. - pub chain_id: Option, - - /// The base path that should be used by the relay chain. - pub base_path: Option, -} - -impl RelayChainCli { - fn polkadot_cmd() -> Command { - let help_template = color_print::cformat!( - "The arguments that are passed to the relay chain node. \n\ - \n\ - RELAY_CHAIN_ARGS: \n\ - {{options}}", - ); - - polkadot_cli::RunCmd::command() - .no_binary_name(true) - .help_template(help_template) - } - - /// Parse the relay chain CLI parameters using the parachain `Configuration`. - pub fn new<'a>( - para_config: &sc_service::Configuration, - relay_chain_args: impl Iterator, - ) -> Self { - let polkadot_cmd = Self::polkadot_cmd(); - let matches = polkadot_cmd.get_matches_from(relay_chain_args); - let base = FromArgMatches::from_arg_matches(&matches).unwrap_or_else(|e| e.exit()); - - let extension = crate::chain_spec::Extensions::try_get(&*para_config.chain_spec); - let chain_id = extension.map(|e| e.relay_chain.clone()); - - let base_path = para_config.base_path.path().join("polkadot"); - Self { base, chain_id, base_path: Some(base_path) } - } -} diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs deleted file mode 100644 index fcf6c06f4222..000000000000 --- a/cumulus/polkadot-parachain/src/command.rs +++ /dev/null @@ -1,856 +0,0 @@ -// 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(feature = "runtime-benchmarks")] -use crate::service::Block; -use crate::{ - chain_spec, - chain_spec::GenericChainSpec, - cli::{Cli, RelayChainCli, Subcommand}, - common::NodeExtraArgs, - fake_runtime_api::{ - asset_hub_polkadot_aura::RuntimeApi as AssetHubPolkadotRuntimeApi, - aura::RuntimeApi as AuraRuntimeApi, - }, - service::{new_aura_node_spec, DynNodeSpec, ShellNode}, -}; -#[cfg(feature = "runtime-benchmarks")] -use cumulus_client_service::storage_proof_size::HostFunctions as ReclaimHostFunctions; -use cumulus_primitives_core::ParaId; -use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE}; -use log::info; -use parachains_common::{AssetHubPolkadotAuraId, AuraId}; -use sc_cli::{ - ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, - NetworkParams, Result, SharedParams, SubstrateCli, -}; -use sc_service::config::{BasePath, PrometheusConfig}; -use sp_runtime::traits::AccountIdConversion; -#[cfg(feature = "runtime-benchmarks")] -use sp_runtime::traits::HashingFor; -use std::{net::SocketAddr, path::PathBuf}; - -/// The choice of consensus for the parachain omni-node. -#[derive(PartialEq, Eq, Debug, Default)] -pub enum Consensus { - /// Aura consensus. - #[default] - Aura, - /// Use the relay chain consensus. - // TODO: atm this is just a demonstration, not really reach-able. We can add it to the CLI, - // env, or the chain spec. Or, just don't, and when we properly refactor this mess we will - // re-introduce it. - #[allow(unused)] - Relay, -} - -/// Helper enum that is used for better distinction of different parachain/runtime configuration -/// (it is based/calculated on ChainSpec's ID attribute) -#[derive(Debug, PartialEq)] -enum Runtime { - /// None of the system-chain runtimes, rather the node will act agnostic to the runtime ie. be - /// an omni-node, and simply run a node with the given consensus algorithm. - Omni(Consensus), - Shell, - Seedling, - AssetHubPolkadot, - AssetHub, - Penpal(ParaId), - ContractsRococo, - Collectives, - Glutton, - BridgeHub(chain_spec::bridge_hubs::BridgeHubRuntimeType), - Coretime(chain_spec::coretime::CoretimeRuntimeType), - People(chain_spec::people::PeopleRuntimeType), -} - -trait RuntimeResolver { - fn runtime(&self) -> Result; -} - -impl RuntimeResolver for dyn ChainSpec { - fn runtime(&self) -> Result { - Ok(runtime(self.id())) - } -} - -/// Implementation, that can resolve [`Runtime`] from any json configuration file -impl RuntimeResolver for PathBuf { - fn runtime(&self) -> Result { - #[derive(Debug, serde::Deserialize)] - struct EmptyChainSpecWithId { - id: String, - } - - let file = std::fs::File::open(self)?; - let reader = std::io::BufReader::new(file); - let chain_spec: EmptyChainSpecWithId = - serde_json::from_reader(reader).map_err(|e| sc_cli::Error::Application(Box::new(e)))?; - - Ok(runtime(&chain_spec.id)) - } -} - -fn runtime(id: &str) -> Runtime { - let id = id.replace('_', "-"); - let (_, id, para_id) = extract_parachain_id(&id); - - if id.starts_with("shell") { - Runtime::Shell - } else if id.starts_with("seedling") { - Runtime::Seedling - } else if id.starts_with("asset-hub-polkadot") | id.starts_with("statemint") { - Runtime::AssetHubPolkadot - } else if id.starts_with("asset-hub-kusama") | - id.starts_with("statemine") | - id.starts_with("asset-hub-rococo") | - id.starts_with("rockmine") | - id.starts_with("asset-hub-westend") | - id.starts_with("westmint") - { - Runtime::AssetHub - } else if id.starts_with("penpal") { - Runtime::Penpal(para_id.unwrap_or(ParaId::new(0))) - } else if id.starts_with("contracts-rococo") { - Runtime::ContractsRococo - } else if id.starts_with("collectives-polkadot") || id.starts_with("collectives-westend") { - Runtime::Collectives - } else if id.starts_with(chain_spec::bridge_hubs::BridgeHubRuntimeType::ID_PREFIX) { - Runtime::BridgeHub( - id.parse::() - .expect("Invalid value"), - ) - } else if id.starts_with(chain_spec::coretime::CoretimeRuntimeType::ID_PREFIX) { - Runtime::Coretime( - id.parse::().expect("Invalid value"), - ) - } else if id.starts_with("glutton") { - Runtime::Glutton - } else if id.starts_with(chain_spec::people::PeopleRuntimeType::ID_PREFIX) { - Runtime::People(id.parse::().expect("Invalid value")) - } else { - log::warn!( - "No specific runtime was recognized for ChainSpec's id: '{}', \ - so Runtime::Omni(Consensus::Aura) will be used", - id - ); - Runtime::Omni(Consensus::Aura) - } -} - -fn load_spec(id: &str) -> std::result::Result, String> { - let (id, _, para_id) = extract_parachain_id(id); - Ok(match id { - // - Default-like - "staging" => - Box::new(chain_spec::rococo_parachain::staging_rococo_parachain_local_config()), - "tick" => Box::new(GenericChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/tick.json")[..], - )?), - "trick" => Box::new(GenericChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/trick.json")[..], - )?), - "track" => Box::new(GenericChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/track.json")[..], - )?), - - // -- Starters - "shell" => Box::new(chain_spec::shell::get_shell_chain_spec()), - "seedling" => Box::new(chain_spec::seedling::get_seedling_chain_spec()), - - // -- Asset Hub Polkadot - "asset-hub-polkadot" | "statemint" => Box::new(GenericChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/asset-hub-polkadot.json")[..], - )?), - - // -- Asset Hub Kusama - "asset-hub-kusama" | "statemine" => Box::new(GenericChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/asset-hub-kusama.json")[..], - )?), - - // -- Asset Hub Rococo - "asset-hub-rococo-dev" => - Box::new(chain_spec::asset_hubs::asset_hub_rococo_development_config()), - "asset-hub-rococo-local" => - Box::new(chain_spec::asset_hubs::asset_hub_rococo_local_config()), - // the chain spec as used for generating the upgrade genesis values - "asset-hub-rococo-genesis" => - Box::new(chain_spec::asset_hubs::asset_hub_rococo_genesis_config()), - "asset-hub-rococo" => Box::new(GenericChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/asset-hub-rococo.json")[..], - )?), - - // -- Asset Hub Westend - "asset-hub-westend-dev" | "westmint-dev" => - Box::new(chain_spec::asset_hubs::asset_hub_westend_development_config()), - "asset-hub-westend-local" | "westmint-local" => - Box::new(chain_spec::asset_hubs::asset_hub_westend_local_config()), - // the chain spec as used for generating the upgrade genesis values - "asset-hub-westend-genesis" | "westmint-genesis" => - Box::new(chain_spec::asset_hubs::asset_hub_westend_config()), - // the shell-based chain spec as used for syncing - "asset-hub-westend" | "westmint" => Box::new(GenericChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/asset-hub-westend.json")[..], - )?), - - // -- Polkadot Collectives - "collectives-polkadot" => Box::new(GenericChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/collectives-polkadot.json")[..], - )?), - - // -- Westend Collectives - "collectives-westend-dev" => - Box::new(chain_spec::collectives::collectives_westend_development_config()), - "collectives-westend-local" => - Box::new(chain_spec::collectives::collectives_westend_local_config()), - "collectives-westend" => Box::new(GenericChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/collectives-westend.json")[..], - )?), - - // -- Contracts on Rococo - "contracts-rococo-dev" => - Box::new(chain_spec::contracts::contracts_rococo_development_config()), - "contracts-rococo-local" => - Box::new(chain_spec::contracts::contracts_rococo_local_config()), - "contracts-rococo-genesis" => Box::new(chain_spec::contracts::contracts_rococo_config()), - "contracts-rococo" => Box::new(GenericChainSpec::from_json_bytes( - &include_bytes!("../chain-specs/contracts-rococo.json")[..], - )?), - - // -- BridgeHub - bridge_like_id - if bridge_like_id - .starts_with(chain_spec::bridge_hubs::BridgeHubRuntimeType::ID_PREFIX) => - bridge_like_id - .parse::() - .expect("invalid value") - .load_config()?, - - // -- Coretime - coretime_like_id - if coretime_like_id - .starts_with(chain_spec::coretime::CoretimeRuntimeType::ID_PREFIX) => - coretime_like_id - .parse::() - .expect("invalid value") - .load_config()?, - - // -- Penpal - "penpal-rococo" => Box::new(chain_spec::penpal::get_penpal_chain_spec( - para_id.expect("Must specify parachain id"), - "rococo-local", - )), - "penpal-westend" => Box::new(chain_spec::penpal::get_penpal_chain_spec( - para_id.expect("Must specify parachain id"), - "westend-local", - )), - - // -- Glutton Westend - "glutton-westend-dev" => Box::new(chain_spec::glutton::glutton_westend_development_config( - para_id.expect("Must specify parachain id"), - )), - "glutton-westend-local" => Box::new(chain_spec::glutton::glutton_westend_local_config( - para_id.expect("Must specify parachain id"), - )), - // the chain spec as used for generating the upgrade genesis values - "glutton-westend-genesis" => Box::new(chain_spec::glutton::glutton_westend_config( - para_id.expect("Must specify parachain id"), - )), - - // -- People - people_like_id - if people_like_id.starts_with(chain_spec::people::PeopleRuntimeType::ID_PREFIX) => - people_like_id - .parse::() - .expect("invalid value") - .load_config()?, - - // -- Fallback (generic chainspec) - "" => { - log::warn!("No ChainSpec.id specified, so using default one, based on rococo-parachain runtime"); - Box::new(chain_spec::rococo_parachain::rococo_parachain_local_config()) - }, - - // -- Loading a specific spec from disk - path => Box::new(GenericChainSpec::from_json_file(path.into())?), - }) -} - -/// Extracts the normalized chain id and parachain id from the input chain id. -/// (H/T to Phala for the idea) -/// E.g. "penpal-kusama-2004" yields ("penpal-kusama", Some(2004)) -fn extract_parachain_id(id: &str) -> (&str, &str, Option) { - let para_prefixes = [ - // Penpal - "penpal-rococo-", - "penpal-kusama-", - "penpal-polkadot-", - // Glutton Kusama - "glutton-kusama-dev-", - "glutton-kusama-local-", - "glutton-kusama-genesis-", - // Glutton Westend - "glutton-westend-dev-", - "glutton-westend-local-", - "glutton-westend-genesis-", - ]; - - for para_prefix in para_prefixes { - if let Some(suffix) = id.strip_prefix(para_prefix) { - let para_id: u32 = suffix.parse().expect("Invalid parachain-id suffix"); - return (&id[..para_prefix.len() - 1], id, Some(para_id.into())) - } - } - - (id, id, None) -} - -impl SubstrateCli for Cli { - fn impl_name() -> String { - Self::executable_name() - } - - fn impl_version() -> String { - env!("SUBSTRATE_CLI_IMPL_VERSION").into() - } - - fn description() -> String { - format!( - "The command-line arguments provided first will be passed to the parachain node, \n\ - and the arguments provided after -- will be passed to the relay chain node. \n\ - \n\ - Example: \n\ - \n\ - {} [parachain-args] -- [relay-chain-args]", - Self::executable_name() - ) - } - - fn author() -> String { - env!("CARGO_PKG_AUTHORS").into() - } - - fn support_url() -> String { - "https://github.com/paritytech/polkadot-sdk/issues/new".into() - } - - fn copyright_start_year() -> i32 { - 2017 - } - - fn load_spec(&self, id: &str) -> std::result::Result, String> { - load_spec(id) - } -} - -impl SubstrateCli for RelayChainCli { - fn impl_name() -> String { - Cli::impl_name() - } - - fn impl_version() -> String { - Cli::impl_version() - } - - fn description() -> String { - Cli::description() - } - - fn author() -> String { - Cli::author() - } - - fn support_url() -> String { - Cli::support_url() - } - - fn copyright_start_year() -> i32 { - Cli::copyright_start_year() - } - - fn load_spec(&self, id: &str) -> std::result::Result, String> { - polkadot_cli::Cli::from_iter([RelayChainCli::executable_name()].iter()).load_spec(id) - } -} - -fn new_node_spec( - config: &sc_service::Configuration, - extra_args: NodeExtraArgs, -) -> std::result::Result, sc_cli::Error> { - Ok(match config.chain_spec.runtime()? { - Runtime::AssetHubPolkadot => - new_aura_node_spec::(extra_args), - Runtime::AssetHub | - Runtime::BridgeHub(_) | - Runtime::Collectives | - Runtime::Coretime(_) | - Runtime::People(_) | - Runtime::ContractsRococo | - Runtime::Glutton | - Runtime::Penpal(_) => new_aura_node_spec::(extra_args), - Runtime::Shell | Runtime::Seedling => Box::new(ShellNode), - Runtime::Omni(consensus) => match consensus { - Consensus::Aura => new_aura_node_spec::(extra_args), - Consensus::Relay => Box::new(ShellNode), - }, - }) -} - -/// Parse command line arguments into service configuration. -pub fn run() -> Result<()> { - let cli = Cli::from_args(); - - match &cli.subcommand { - Some(Subcommand::BuildSpec(cmd)) => { - let runner = cli.create_runner(cmd)?; - runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) - }, - Some(Subcommand::CheckBlock(cmd)) => { - let runner = cli.create_runner(cmd)?; - runner.async_run(|config| { - let node = new_node_spec(&config, cli.node_extra_args())?; - node.prepare_check_block_cmd(config, cmd) - }) - }, - Some(Subcommand::ExportBlocks(cmd)) => { - let runner = cli.create_runner(cmd)?; - runner.async_run(|config| { - let node = new_node_spec(&config, cli.node_extra_args())?; - node.prepare_export_blocks_cmd(config, cmd) - }) - }, - Some(Subcommand::ExportState(cmd)) => { - let runner = cli.create_runner(cmd)?; - runner.async_run(|config| { - let node = new_node_spec(&config, cli.node_extra_args())?; - node.prepare_export_state_cmd(config, cmd) - }) - }, - Some(Subcommand::ImportBlocks(cmd)) => { - let runner = cli.create_runner(cmd)?; - runner.async_run(|config| { - let node = new_node_spec(&config, cli.node_extra_args())?; - node.prepare_import_blocks_cmd(config, cmd) - }) - }, - Some(Subcommand::Revert(cmd)) => { - let runner = cli.create_runner(cmd)?; - runner.async_run(|config| { - let node = new_node_spec(&config, cli.node_extra_args())?; - node.prepare_revert_cmd(config, cmd) - }) - }, - Some(Subcommand::PurgeChain(cmd)) => { - let runner = cli.create_runner(cmd)?; - let polkadot_cli = RelayChainCli::new(runner.config(), cli.relay_chain_args.iter()); - - runner.sync_run(|config| { - let polkadot_config = SubstrateCli::create_configuration( - &polkadot_cli, - &polkadot_cli, - config.tokio_handle.clone(), - ) - .map_err(|err| format!("Relay chain argument error: {}", err))?; - - cmd.run(config, polkadot_config) - }) - }, - Some(Subcommand::ExportGenesisHead(cmd)) => { - let runner = cli.create_runner(cmd)?; - runner.sync_run(|config| { - let node = new_node_spec(&config, cli.node_extra_args())?; - node.run_export_genesis_head_cmd(config, cmd) - }) - }, - Some(Subcommand::ExportGenesisWasm(cmd)) => { - let runner = cli.create_runner(cmd)?; - runner.sync_run(|_config| { - let spec = cli.load_spec(&cmd.shared_params.chain.clone().unwrap_or_default())?; - cmd.run(&*spec) - }) - }, - Some(Subcommand::Benchmark(cmd)) => { - let runner = cli.create_runner(cmd)?; - - // Switch on the concrete benchmark sub-command- - match cmd { - #[cfg(feature = "runtime-benchmarks")] - BenchmarkCmd::Pallet(cmd) => runner.sync_run(|config| { - cmd.run_with_spec::, ReclaimHostFunctions>(Some( - config.chain_spec, - )) - }), - BenchmarkCmd::Block(cmd) => runner.sync_run(|config| { - 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())?; - node.run_benchmark_storage_cmd(config, cmd) - }), - BenchmarkCmd::Machine(cmd) => - runner.sync_run(|config| cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone())), - #[allow(unreachable_patterns)] - _ => Err("Benchmarking sub-command unsupported or compilation feature missing. \ - Make sure to compile with --features=runtime-benchmarks \ - to enable all supported benchmarks." - .into()), - } - }, - Some(Subcommand::Key(cmd)) => Ok(cmd.run(&cli)?), - None => { - let runner = cli.create_runner(&cli.run.normalize())?; - let polkadot_cli = RelayChainCli::new(runner.config(), cli.relay_chain_args.iter()); - let collator_options = cli.run.collator_options(); - - runner.run_node_until_exit(|config| async move { - // If Statemint (Statemine, Westmint, Rockmine) DB exists and we're using the - // asset-hub chain spec, then rename the base path to the new chain ID. In the case - // that both file paths exist, the node will exit, as the user must decide (by - // deleting one path) the information that they want to use as their DB. - let old_name = match config.chain_spec.id() { - "asset-hub-polkadot" => Some("statemint"), - "asset-hub-kusama" => Some("statemine"), - "asset-hub-westend" => Some("westmint"), - "asset-hub-rococo" => Some("rockmine"), - _ => None, - }; - - if let Some(old_name) = old_name { - let new_path = config.base_path.config_dir(config.chain_spec.id()); - let old_path = config.base_path.config_dir(old_name); - - if old_path.exists() && new_path.exists() { - return Err(format!( - "Found legacy {} path {} and new Asset Hub path {}. \ - Delete one path such that only one exists.", - old_name, - old_path.display(), - new_path.display() - ) - .into()) - } - - if old_path.exists() { - std::fs::rename(old_path.clone(), new_path.clone())?; - info!( - "{} was renamed to Asset Hub. The filepath with associated data on disk \ - has been renamed from {} to {}.", - old_name, - old_path.display(), - new_path.display() - ); - } - } - - let hwbench = (!cli.no_hardware_benchmarks) - .then_some(config.database.path().map(|database_path| { - let _ = std::fs::create_dir_all(database_path); - sc_sysinfo::gather_hwbench(Some(database_path)) - })) - .flatten(); - - let para_id = chain_spec::Extensions::try_get(&*config.chain_spec) - .map(|e| e.para_id) - .ok_or("Could not find parachain extension in chain-spec.")?; - - let id = ParaId::from(para_id); - - let parachain_account = - AccountIdConversion::::into_account_truncating( - &id, - ); - - let tokio_handle = config.tokio_handle.clone(); - let polkadot_config = - SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle) - .map_err(|err| format!("Relay chain argument error: {}", err))?; - - info!("🪪 Parachain id: {:?}", id); - info!("🧾 Parachain Account: {}", parachain_account); - info!("✍️ Is collating: {}", if config.role.is_authority() { "yes" } else { "no" }); - - start_node( - config, - polkadot_config, - collator_options, - id, - cli.node_extra_args(), - hwbench, - ) - .await - }) - }, - } -} - -#[sc_tracing::logging::prefix_logs_with("Parachain")] -async fn start_node( - config: sc_service::Configuration, - polkadot_config: sc_service::Configuration, - collator_options: cumulus_client_cli::CollatorOptions, - id: ParaId, - extra_args: NodeExtraArgs, - hwbench: Option, -) -> Result { - let node_spec = new_node_spec(&config, extra_args)?; - node_spec - .start_node(config, polkadot_config, collator_options, id, hwbench) - .await - .map_err(Into::into) -} - -impl DefaultConfigurationValues for RelayChainCli { - fn p2p_listen_port() -> u16 { - 30334 - } - - fn rpc_listen_port() -> u16 { - 9945 - } - - fn prometheus_listen_port() -> u16 { - 9616 - } -} - -impl CliConfiguration for RelayChainCli { - fn shared_params(&self) -> &SharedParams { - self.base.base.shared_params() - } - - fn import_params(&self) -> Option<&ImportParams> { - self.base.base.import_params() - } - - fn network_params(&self) -> Option<&NetworkParams> { - self.base.base.network_params() - } - - fn keystore_params(&self) -> Option<&KeystoreParams> { - self.base.base.keystore_params() - } - - fn base_path(&self) -> Result> { - Ok(self - .shared_params() - .base_path()? - .or_else(|| self.base_path.clone().map(Into::into))) - } - - fn rpc_addr(&self, default_listen_port: u16) -> Result> { - self.base.base.rpc_addr(default_listen_port) - } - - fn prometheus_config( - &self, - default_listen_port: u16, - chain_spec: &Box, - ) -> Result> { - self.base.base.prometheus_config(default_listen_port, chain_spec) - } - - fn init( - &self, - _support_url: &String, - _impl_version: &String, - _logger_hook: F, - _config: &sc_service::Configuration, - ) -> Result<()> - where - F: FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration), - { - unreachable!("PolkadotCli is never initialized; qed"); - } - - fn chain_id(&self, is_dev: bool) -> Result { - let chain_id = self.base.base.chain_id(is_dev)?; - - Ok(if chain_id.is_empty() { self.chain_id.clone().unwrap_or_default() } else { chain_id }) - } - - fn role(&self, is_dev: bool) -> Result { - self.base.base.role(is_dev) - } - - fn transaction_pool(&self, is_dev: bool) -> Result { - self.base.base.transaction_pool(is_dev) - } - - fn trie_cache_maximum_size(&self) -> Result> { - self.base.base.trie_cache_maximum_size() - } - - fn rpc_methods(&self) -> Result { - self.base.base.rpc_methods() - } - - fn rpc_max_connections(&self) -> Result { - self.base.base.rpc_max_connections() - } - - fn rpc_cors(&self, is_dev: bool) -> Result>> { - self.base.base.rpc_cors(is_dev) - } - - fn default_heap_pages(&self) -> Result> { - self.base.base.default_heap_pages() - } - - fn force_authoring(&self) -> Result { - self.base.base.force_authoring() - } - - fn disable_grandpa(&self) -> Result { - self.base.base.disable_grandpa() - } - - fn max_runtime_instances(&self) -> Result> { - self.base.base.max_runtime_instances() - } - - fn announce_block(&self) -> Result { - self.base.base.announce_block() - } - - fn telemetry_endpoints( - &self, - chain_spec: &Box, - ) -> Result> { - self.base.base.telemetry_endpoints(chain_spec) - } - - fn node_name(&self) -> Result { - self.base.base.node_name() - } -} - -#[cfg(test)] -mod tests { - use crate::{ - chain_spec::{get_account_id_from_seed, get_from_seed}, - command::{Consensus, Runtime, RuntimeResolver}, - }; - use sc_chain_spec::{ChainSpec, ChainSpecExtension, ChainSpecGroup, ChainType, Extension}; - use serde::{Deserialize, Serialize}; - use sp_core::sr25519; - use std::path::PathBuf; - use tempfile::TempDir; - - #[derive( - Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension, Default, - )] - #[serde(deny_unknown_fields)] - pub struct Extensions1 { - pub attribute1: String, - pub attribute2: u32, - } - - #[derive( - Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension, Default, - )] - #[serde(deny_unknown_fields)] - pub struct Extensions2 { - pub attribute_x: String, - pub attribute_y: String, - pub attribute_z: u32, - } - - fn store_configuration(dir: &TempDir, spec: &dyn ChainSpec) -> PathBuf { - let raw_output = true; - let json = sc_service::chain_ops::build_spec(spec, raw_output) - .expect("Failed to build json string"); - let mut cfg_file_path = dir.path().to_path_buf(); - cfg_file_path.push(spec.id()); - cfg_file_path.set_extension("json"); - std::fs::write(&cfg_file_path, json).expect("Failed to write to json file"); - cfg_file_path - } - - pub type DummyChainSpec = sc_service::GenericChainSpec; - - pub fn create_default_with_extensions( - id: &str, - extension: E, - ) -> DummyChainSpec { - DummyChainSpec::builder( - rococo_parachain_runtime::WASM_BINARY - .expect("WASM binary was not built, please build it!"), - extension, - ) - .with_name("Dummy local testnet") - .with_id(id) - .with_chain_type(ChainType::Local) - .with_genesis_config_patch(crate::chain_spec::rococo_parachain::testnet_genesis( - get_account_id_from_seed::("Alice"), - vec![ - get_from_seed::("Alice"), - get_from_seed::("Bob"), - ], - vec![get_account_id_from_seed::("Alice")], - 1000.into(), - )) - .build() - } - - #[test] - fn test_resolve_runtime_for_different_configuration_files() { - let temp_dir = tempfile::tempdir().expect("Failed to access tempdir"); - - let path = store_configuration( - &temp_dir, - &create_default_with_extensions("shell-1", Extensions1::default()), - ); - assert_eq!(Runtime::Shell, path.runtime().unwrap()); - - let path = store_configuration( - &temp_dir, - &create_default_with_extensions("shell-2", Extensions2::default()), - ); - assert_eq!(Runtime::Shell, path.runtime().unwrap()); - - let path = store_configuration( - &temp_dir, - &create_default_with_extensions("seedling", Extensions2::default()), - ); - assert_eq!(Runtime::Seedling, path.runtime().unwrap()); - - let path = store_configuration( - &temp_dir, - &create_default_with_extensions("penpal-rococo-1000", Extensions2::default()), - ); - assert_eq!(Runtime::Penpal(1000.into()), path.runtime().unwrap()); - - let path = store_configuration( - &temp_dir, - &create_default_with_extensions("penpal-polkadot-2000", Extensions2::default()), - ); - assert_eq!(Runtime::Penpal(2000.into()), path.runtime().unwrap()); - - let path = store_configuration( - &temp_dir, - &crate::chain_spec::contracts::contracts_rococo_local_config(), - ); - assert_eq!(Runtime::ContractsRococo, path.runtime().unwrap()); - - let path = store_configuration( - &temp_dir, - &crate::chain_spec::rococo_parachain::rococo_parachain_local_config(), - ); - assert_eq!(Runtime::Omni(Consensus::Aura), path.runtime().unwrap()); - } -} diff --git a/cumulus/polkadot-parachain/src/fake_runtime_api/asset_hub_polkadot_aura.rs b/cumulus/polkadot-parachain/src/fake_runtime_api/asset_hub_polkadot_aura.rs deleted file mode 100644 index 7d54e9b4be04..000000000000 --- a/cumulus/polkadot-parachain/src/fake_runtime_api/asset_hub_polkadot_aura.rs +++ /dev/null @@ -1,198 +0,0 @@ -// 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 . - -//! These are used to provide a type that implements these runtime APIs without requiring to import -//! the native runtimes. - -use frame_support::weights::Weight; -use parachains_common::{AccountId, AssetHubPolkadotAuraId, Balance, Nonce}; -use polkadot_primitives::Block; -use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; -use sp_runtime::{ - traits::Block as BlockT, - transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, -}; - -pub struct Runtime; - -sp_api::impl_runtime_apis! { - impl sp_api::Core for Runtime { - fn version() -> sp_version::RuntimeVersion { - unimplemented!() - } - - fn execute_block(_: Block) { - unimplemented!() - } - - fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { - unimplemented!() - } - } - - impl sp_api::Metadata for Runtime { - fn metadata() -> OpaqueMetadata { - unimplemented!() - } - - fn metadata_at_version(_: u32) -> Option { - unimplemented!() - } - - fn metadata_versions() -> Vec { - unimplemented!() - } - } - - impl sp_consensus_aura::AuraApi for Runtime { - fn slot_duration() -> sp_consensus_aura::SlotDuration { - unimplemented!() - } - - fn authorities() -> Vec { - unimplemented!() - } - } - - impl cumulus_primitives_aura::AuraUnincludedSegmentApi for Runtime { - fn can_build_upon( - _: ::Hash, - _: cumulus_primitives_aura::Slot, - ) -> bool { - unimplemented!() - } - } - - impl sp_block_builder::BlockBuilder for Runtime { - fn apply_extrinsic(_: ::Extrinsic) -> ApplyExtrinsicResult { - unimplemented!() - } - - fn finalize_block() -> ::Header { - unimplemented!() - } - - fn inherent_extrinsics(_: sp_inherents::InherentData) -> Vec<::Extrinsic> { - unimplemented!() - } - - fn check_inherents(_: Block, _: sp_inherents::InherentData) -> sp_inherents::CheckInherentsResult { - unimplemented!() - } - } - - impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { - fn validate_transaction( - _: TransactionSource, - _: ::Extrinsic, - _: ::Hash, - ) -> TransactionValidity { - unimplemented!() - } - } - - impl sp_session::SessionKeys for Runtime { - fn generate_session_keys(_: Option>) -> Vec { - unimplemented!() - } - - fn decode_session_keys( - _: Vec, - ) -> Option, KeyTypeId)>> { - unimplemented!() - } - } - - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { - fn query_info( - _: ::Extrinsic, - _: u32, - ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { - unimplemented!() - } - fn query_fee_details( - _: ::Extrinsic, - _: u32, - ) -> pallet_transaction_payment::FeeDetails { - unimplemented!() - } - fn query_weight_to_fee(_: Weight) -> Balance { - unimplemented!() - } - fn query_length_to_fee(_: u32) -> Balance { - unimplemented!() - } - } - - impl cumulus_primitives_core::CollectCollationInfo for Runtime { - fn collect_collation_info(_: &::Header) -> cumulus_primitives_core::CollationInfo { - unimplemented!() - } - } - - #[cfg(feature = "try-runtime")] - impl frame_try_runtime::TryRuntime for Runtime { - fn on_runtime_upgrade(_: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { - unimplemented!() - } - - fn execute_block( - _: Block, - _: bool, - _: bool, - _: frame_try_runtime::TryStateSelect, - ) -> Weight { - unimplemented!() - } - } - - impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { - fn account_nonce(_: AccountId) -> Nonce { - unimplemented!() - } - } - - #[cfg(feature = "runtime-benchmarks")] - impl frame_benchmarking::Benchmark for Runtime { - fn benchmark_metadata(_: bool) -> ( - Vec, - Vec, - ) { - unimplemented!() - } - - fn dispatch_benchmark( - _: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { - unimplemented!() - } - } - - impl sp_genesis_builder::GenesisBuilder for Runtime { - fn build_state(_: Vec) -> sp_genesis_builder::Result { - unimplemented!() - } - - fn get_preset(_id: &Option) -> Option> { - unimplemented!() - } - - fn preset_names() -> Vec { - unimplemented!() - } - } -} diff --git a/cumulus/polkadot-parachain/src/fake_runtime_api/aura.rs b/cumulus/polkadot-parachain/src/fake_runtime_api/aura.rs deleted file mode 100644 index ca5fc8bdf119..000000000000 --- a/cumulus/polkadot-parachain/src/fake_runtime_api/aura.rs +++ /dev/null @@ -1,198 +0,0 @@ -// 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 . - -//! These are used to provide a type that implements these runtime APIs without requiring to import -//! the native runtimes. - -use frame_support::weights::Weight; -use parachains_common::{AccountId, AuraId, Balance, Nonce}; -use polkadot_primitives::Block; -use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; -use sp_runtime::{ - traits::Block as BlockT, - transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, -}; - -pub struct Runtime; - -sp_api::impl_runtime_apis! { - impl sp_api::Core for Runtime { - fn version() -> sp_version::RuntimeVersion { - unimplemented!() - } - - fn execute_block(_: Block) { - unimplemented!() - } - - fn initialize_block(_: &::Header) -> sp_runtime::ExtrinsicInclusionMode { - unimplemented!() - } - } - - impl sp_api::Metadata for Runtime { - fn metadata() -> OpaqueMetadata { - unimplemented!() - } - - fn metadata_at_version(_: u32) -> Option { - unimplemented!() - } - - fn metadata_versions() -> Vec { - unimplemented!() - } - } - - impl sp_consensus_aura::AuraApi for Runtime { - fn slot_duration() -> sp_consensus_aura::SlotDuration { - unimplemented!() - } - - fn authorities() -> Vec { - unimplemented!() - } - } - - impl cumulus_primitives_aura::AuraUnincludedSegmentApi for Runtime { - fn can_build_upon( - _: ::Hash, - _: cumulus_primitives_aura::Slot, - ) -> bool { - unimplemented!() - } - } - - impl sp_block_builder::BlockBuilder for Runtime { - fn apply_extrinsic(_: ::Extrinsic) -> ApplyExtrinsicResult { - unimplemented!() - } - - fn finalize_block() -> ::Header { - unimplemented!() - } - - fn inherent_extrinsics(_: sp_inherents::InherentData) -> Vec<::Extrinsic> { - unimplemented!() - } - - fn check_inherents(_: Block, _: sp_inherents::InherentData) -> sp_inherents::CheckInherentsResult { - unimplemented!() - } - } - - impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { - fn validate_transaction( - _: TransactionSource, - _: ::Extrinsic, - _: ::Hash, - ) -> TransactionValidity { - unimplemented!() - } - } - - impl sp_session::SessionKeys for Runtime { - fn generate_session_keys(_: Option>) -> Vec { - unimplemented!() - } - - fn decode_session_keys( - _: Vec, - ) -> Option, KeyTypeId)>> { - unimplemented!() - } - } - - impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi for Runtime { - fn query_info( - _: ::Extrinsic, - _: u32, - ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo { - unimplemented!() - } - fn query_fee_details( - _: ::Extrinsic, - _: u32, - ) -> pallet_transaction_payment::FeeDetails { - unimplemented!() - } - fn query_weight_to_fee(_: Weight) -> Balance { - unimplemented!() - } - fn query_length_to_fee(_: u32) -> Balance { - unimplemented!() - } - } - - impl cumulus_primitives_core::CollectCollationInfo for Runtime { - fn collect_collation_info(_: &::Header) -> cumulus_primitives_core::CollationInfo { - unimplemented!() - } - } - - #[cfg(feature = "try-runtime")] - impl frame_try_runtime::TryRuntime for Runtime { - fn on_runtime_upgrade(_: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) { - unimplemented!() - } - - fn execute_block( - _: Block, - _: bool, - _: bool, - _: frame_try_runtime::TryStateSelect, - ) -> Weight { - unimplemented!() - } - } - - impl frame_system_rpc_runtime_api::AccountNonceApi for Runtime { - fn account_nonce(_: AccountId) -> Nonce { - unimplemented!() - } - } - - #[cfg(feature = "runtime-benchmarks")] - impl frame_benchmarking::Benchmark for Runtime { - fn benchmark_metadata(_: bool) -> ( - Vec, - Vec, - ) { - unimplemented!() - } - - fn dispatch_benchmark( - _: frame_benchmarking::BenchmarkConfig - ) -> Result, sp_runtime::RuntimeString> { - unimplemented!() - } - } - - impl sp_genesis_builder::GenesisBuilder for Runtime { - fn build_state(_: Vec) -> sp_genesis_builder::Result { - unimplemented!() - } - - fn get_preset(_id: &Option) -> Option> { - unimplemented!() - } - - fn preset_names() -> Vec { - unimplemented!() - } - } -} diff --git a/cumulus/polkadot-parachain/src/main.rs b/cumulus/polkadot-parachain/src/main.rs index cbb76fa214cb..c8464be937cc 100644 --- a/cumulus/polkadot-parachain/src/main.rs +++ b/cumulus/polkadot-parachain/src/main.rs @@ -19,37 +19,36 @@ #![warn(missing_docs)] #![warn(unused_extern_crates)] -pub(crate) fn examples(executable_name: String) -> String { - color_print::cformat!( - r#"Examples: +mod chain_spec; + +use polkadot_omni_node_lib::{run, CliConfig as CliConfigT, RunConfig}; - {0} --chain para.json --sync warp -- --chain relay.json --sync warp - Launch a warp-syncing full node of a given para's chain-spec, and a given relay's chain-spec. +struct CliConfig; - The above approach is the most flexible, and the most forward-compatible way to spawn an omni-node. +impl CliConfigT for CliConfig { + fn impl_version() -> String { + env!("SUBSTRATE_CLI_IMPL_VERSION").into() + } - You can find the chain-spec of some networks in: - https://paritytech.github.io/chainspecs + fn author() -> String { + env!("CARGO_PKG_AUTHORS").into() + } - {0} --chain asset-hub-polkadot --sync warp -- --chain polkadot --sync warp - Launch a warp-syncing full node of the Asset Hub parachain on the Polkadot Relay Chain. + fn support_url() -> String { + "https://github.com/paritytech/polkadot-sdk/issues/new".into() + } - {0} --chain asset-hub-kusama --sync warp --relay-chain-rpc-url ws://rpc.example.com -- --chain kusama - Launch a warp-syncing full node of the Asset Hub parachain on the Kusama Relay Chain. - Uses ws://rpc.example.com as remote relay chain node. - "#, - executable_name, - ) + fn copyright_start_year() -> u16 { + 2017 + } } -mod chain_spec; -mod cli; -mod command; -mod common; -mod fake_runtime_api; -mod rpc; -mod service; - -fn main() -> sc_cli::Result<()> { - command::run() +fn main() -> color_eyre::eyre::Result<()> { + color_eyre::install()?; + + let config = RunConfig { + chain_spec_loader: Box::new(chain_spec::ChainSpecLoader), + runtime_resolver: Box::new(chain_spec::RuntimeResolver), + }; + Ok(run::(config)?) } diff --git a/cumulus/polkadot-parachain/src/service.rs b/cumulus/polkadot-parachain/src/service.rs deleted file mode 100644 index 6a6cf15635e0..000000000000 --- a/cumulus/polkadot-parachain/src/service.rs +++ /dev/null @@ -1,1023 +0,0 @@ -// Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Cumulus is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Cumulus. If not, see . - -use cumulus_client_cli::{CollatorOptions, ExportGenesisHeadCommand}; -use cumulus_client_collator::service::{ - CollatorService, ServiceInterface as CollatorServiceInterface, -}; -use cumulus_client_consensus_aura::collators::lookahead::{self as aura, Params as AuraParams}; -#[docify::export(slot_based_colator_import)] -use cumulus_client_consensus_aura::collators::slot_based::{ - self as slot_based, Params as SlotBasedParams, -}; -use cumulus_client_consensus_common::ParachainBlockImport as TParachainBlockImport; -use cumulus_client_consensus_proposer::{Proposer, ProposerInterface}; -use cumulus_client_consensus_relay_chain::Verifier as RelayChainVerifier; -#[allow(deprecated)] -use cumulus_client_service::old_consensus; -use cumulus_client_service::{ - build_network, build_relay_chain_interface, prepare_node_config, start_relay_chain_tasks, - BuildNetworkParams, CollatorSybilResistance, DARecoveryProfile, StartRelayChainTasksParams, -}; -use cumulus_primitives_core::{relay_chain::ValidationCode, ParaId}; -use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface}; - -use crate::{ - common::{ - aura::{AuraIdT, AuraRuntimeApi}, - ConstructNodeRuntimeApi, NodeExtraArgs, - }, - fake_runtime_api::aura::RuntimeApi as FakeRuntimeApi, - rpc::BuildRpcExtensions, -}; -pub use parachains_common::{AccountId, Balance, Block, Hash, Nonce}; - -use crate::rpc::{BuildEmptyRpcExtensions, BuildParachainRpcExtensions}; -use frame_benchmarking_cli::BlockCmd; -#[cfg(any(feature = "runtime-benchmarks"))] -use frame_benchmarking_cli::StorageCmd; -use futures::prelude::*; -use polkadot_primitives::CollatorPair; -use prometheus_endpoint::Registry; -use sc_cli::{CheckBlockCmd, ExportBlocksCmd, ExportStateCmd, ImportBlocksCmd, RevertCmd}; -use sc_client_api::BlockchainEvents; -use sc_consensus::{ - import_queue::{BasicQueue, Verifier as VerifierT}, - BlockImportParams, DefaultImportQueue, ImportQueue, -}; -use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY}; -use sc_network::{config::FullNetworkConfiguration, service::traits::NetworkBackend, NetworkBlock}; -use sc_service::{Configuration, Error, PartialComponents, TFullBackend, TFullClient, TaskManager}; -use sc_sysinfo::HwBench; -use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle}; -use sc_transaction_pool::FullPool; -use sp_api::ProvideRuntimeApi; -use sp_inherents::CreateInherentDataProviders; -use sp_keystore::KeystorePtr; -use sp_runtime::{app_crypto::AppCrypto, traits::Header as HeaderT}; -use std::{marker::PhantomData, pin::Pin, sync::Arc, time::Duration}; - -#[cfg(not(feature = "runtime-benchmarks"))] -type HostFunctions = cumulus_client_service::ParachainHostFunctions; - -#[cfg(feature = "runtime-benchmarks")] -type HostFunctions = ( - cumulus_client_service::ParachainHostFunctions, - frame_benchmarking::benchmarking::HostFunctions, -); - -pub type ParachainClient = TFullClient>; - -pub type ParachainBackend = TFullBackend; - -type ParachainBlockImport = - TParachainBlockImport>, ParachainBackend>; - -/// Assembly of PartialComponents (enough to run chain ops subcommands) -pub type Service = PartialComponents< - ParachainClient, - ParachainBackend, - (), - sc_consensus::DefaultImportQueue, - sc_transaction_pool::FullPool>, - (ParachainBlockImport, Option, Option), ->; - -pub(crate) trait BuildImportQueue { - fn build_import_queue( - client: Arc>, - block_import: ParachainBlockImport, - config: &Configuration, - telemetry_handle: Option, - task_manager: &TaskManager, - ) -> sc_service::error::Result>; -} - -pub(crate) trait StartConsensus -where - RuntimeApi: ConstructNodeRuntimeApi>, -{ - fn start_consensus( - client: Arc>, - block_import: ParachainBlockImport, - prometheus_registry: Option<&Registry>, - telemetry: Option, - task_manager: &TaskManager, - relay_chain_interface: Arc, - transaction_pool: Arc>>, - keystore: KeystorePtr, - relay_chain_slot_duration: Duration, - para_id: ParaId, - collator_key: CollatorPair, - overseer_handle: OverseerHandle, - announce_block: Arc>) + Send + Sync>, - backend: Arc, - ) -> Result<(), sc_service::Error>; -} - -pub(crate) trait NodeSpec { - type RuntimeApi: ConstructNodeRuntimeApi>; - - type BuildImportQueue: BuildImportQueue + 'static; - - type BuildRpcExtensions: BuildRpcExtensions< - ParachainClient, - ParachainBackend, - sc_transaction_pool::FullPool>, - > + 'static; - - type StartConsensus: StartConsensus + 'static; - - const SYBIL_RESISTANCE: CollatorSybilResistance; - - /// Starts a `ServiceBuilder` for a full service. - /// - /// Use this macro if you don't actually need the full service, but just the builder in order to - /// be able to perform chain operations. - fn new_partial(config: &Configuration) -> sc_service::error::Result> { - let telemetry = config - .telemetry_endpoints - .clone() - .filter(|x| !x.is_empty()) - .map(|endpoints| -> Result<_, sc_telemetry::Error> { - let worker = TelemetryWorker::new(16)?; - let telemetry = worker.handle().new_telemetry(endpoints); - Ok((worker, telemetry)) - }) - .transpose()?; - - let heap_pages = config.default_heap_pages.map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| { - HeapAllocStrategy::Static { extra_pages: h as _ } - }); - - let executor = sc_executor::WasmExecutor::::builder() - .with_execution_method(config.wasm_method) - .with_max_runtime_instances(config.max_runtime_instances) - .with_runtime_cache_size(config.runtime_cache_size) - .with_onchain_heap_alloc_strategy(heap_pages) - .with_offchain_heap_alloc_strategy(heap_pages) - .build(); - - let (client, backend, keystore_container, task_manager) = - sc_service::new_full_parts_record_import::( - config, - telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), - executor, - true, - )?; - let client = Arc::new(client); - - let telemetry_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle()); - - let telemetry = telemetry.map(|(worker, telemetry)| { - task_manager.spawn_handle().spawn("telemetry", None, worker.run()); - telemetry - }); - - let transaction_pool = sc_transaction_pool::BasicPool::new_full( - config.transaction_pool.clone(), - config.role.is_authority().into(), - config.prometheus_registry(), - task_manager.spawn_essential_handle(), - client.clone(), - ); - - let block_import = ParachainBlockImport::new(client.clone(), backend.clone()); - - let import_queue = Self::BuildImportQueue::build_import_queue( - client.clone(), - block_import.clone(), - config, - telemetry.as_ref().map(|telemetry| telemetry.handle()), - &task_manager, - )?; - - Ok(PartialComponents { - backend, - client, - import_queue, - keystore_container, - task_manager, - transaction_pool, - select_chain: (), - other: (block_import, telemetry, telemetry_worker_handle), - }) - } - - /// Start a node with the given parachain spec. - /// - /// This is the actual implementation that is abstract over the executor and the runtime api. - fn start_node( - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, - ) -> Pin>>> - where - Net: NetworkBackend, - { - Box::pin(async move { - let parachain_config = prepare_node_config(parachain_config); - - let params = Self::new_partial(¶chain_config)?; - let (block_import, mut telemetry, telemetry_worker_handle) = params.other; - - let client = params.client.clone(); - let backend = params.backend.clone(); - - let mut task_manager = params.task_manager; - let (relay_chain_interface, collator_key) = build_relay_chain_interface( - polkadot_config, - ¶chain_config, - telemetry_worker_handle, - &mut task_manager, - collator_options.clone(), - hwbench.clone(), - ) - .await - .map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?; - - let validator = parachain_config.role.is_authority(); - let prometheus_registry = parachain_config.prometheus_registry().cloned(); - let transaction_pool = params.transaction_pool.clone(); - let import_queue_service = params.import_queue.service(); - let net_config = FullNetworkConfiguration::<_, _, Net>::new(¶chain_config.network); - - let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) = - build_network(BuildNetworkParams { - parachain_config: ¶chain_config, - net_config, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - para_id, - spawn_handle: task_manager.spawn_handle(), - relay_chain_interface: relay_chain_interface.clone(), - import_queue: params.import_queue, - sybil_resistance_level: Self::SYBIL_RESISTANCE, - }) - .await?; - - let rpc_builder = { - let client = client.clone(); - let transaction_pool = transaction_pool.clone(); - let backend_for_rpc = backend.clone(); - - Box::new(move |deny_unsafe, _| { - Self::BuildRpcExtensions::build_rpc_extensions( - deny_unsafe, - client.clone(), - backend_for_rpc.clone(), - transaction_pool.clone(), - ) - }) - }; - - sc_service::spawn_tasks(sc_service::SpawnTasksParams { - rpc_builder, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - task_manager: &mut task_manager, - config: parachain_config, - keystore: params.keystore_container.keystore(), - backend: backend.clone(), - network: network.clone(), - sync_service: sync_service.clone(), - system_rpc_tx, - tx_handler_controller, - telemetry: telemetry.as_mut(), - })?; - - if let Some(hwbench) = hwbench { - sc_sysinfo::print_hwbench(&hwbench); - if validator { - warn_if_slow_hardware(&hwbench); - } - - if let Some(ref mut telemetry) = telemetry { - let telemetry_handle = telemetry.handle(); - task_manager.spawn_handle().spawn( - "telemetry_hwbench", - None, - sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench), - ); - } - } - - let announce_block = { - let sync_service = sync_service.clone(); - Arc::new(move |hash, data| sync_service.announce_block(hash, data)) - }; - - let relay_chain_slot_duration = Duration::from_secs(6); - - let overseer_handle = relay_chain_interface - .overseer_handle() - .map_err(|e| sc_service::Error::Application(Box::new(e)))?; - - start_relay_chain_tasks(StartRelayChainTasksParams { - client: client.clone(), - announce_block: announce_block.clone(), - para_id, - relay_chain_interface: relay_chain_interface.clone(), - task_manager: &mut task_manager, - da_recovery_profile: if validator { - DARecoveryProfile::Collator - } else { - DARecoveryProfile::FullNode - }, - import_queue: import_queue_service, - relay_chain_slot_duration, - recovery_handle: Box::new(overseer_handle.clone()), - sync_service, - })?; - - if validator { - Self::StartConsensus::start_consensus( - client.clone(), - block_import, - prometheus_registry.as_ref(), - telemetry.as_ref().map(|t| t.handle()), - &task_manager, - relay_chain_interface.clone(), - transaction_pool, - params.keystore_container.keystore(), - relay_chain_slot_duration, - para_id, - collator_key.expect("Command line arguments do not allow this. qed"), - overseer_handle, - announce_block, - backend.clone(), - )?; - } - - start_network.start_network(); - - Ok(task_manager) - }) - } -} - -/// Build the import queue for the shell runtime. -pub(crate) struct BuildShellImportQueue(PhantomData); - -impl BuildImportQueue for BuildShellImportQueue { - fn build_import_queue( - client: Arc>, - block_import: ParachainBlockImport, - config: &Configuration, - _telemetry_handle: Option, - task_manager: &TaskManager, - ) -> sc_service::error::Result> { - cumulus_client_consensus_relay_chain::import_queue( - client, - block_import, - |_, _| async { Ok(()) }, - &task_manager.spawn_essential_handle(), - config.prometheus_registry(), - ) - .map_err(Into::into) - } -} - -pub(crate) struct ShellNode; - -impl NodeSpec for ShellNode { - type RuntimeApi = FakeRuntimeApi; - type BuildImportQueue = BuildShellImportQueue; - type BuildRpcExtensions = BuildEmptyRpcExtensions; - type StartConsensus = StartRelayChainConsensus; - - const SYBIL_RESISTANCE: CollatorSybilResistance = CollatorSybilResistance::Unresistant; -} - -struct Verifier { - client: Arc, - aura_verifier: Box>, - relay_chain_verifier: Box>, - _phantom: PhantomData, -} - -#[async_trait::async_trait] -impl VerifierT for Verifier -where - Client: ProvideRuntimeApi + Send + Sync, - Client::Api: AuraRuntimeApi, - AuraId: AuraIdT + Sync, -{ - async fn verify( - &self, - block_import: BlockImportParams, - ) -> Result, String> { - if self.client.runtime_api().has_aura_api(*block_import.header.parent_hash()) { - self.aura_verifier.verify(block_import).await - } else { - self.relay_chain_verifier.verify(block_import).await - } - } -} - -/// Build the import queue for parachain runtimes that started with relay chain consensus and -/// switched to aura. -pub(crate) struct BuildRelayToAuraImportQueue( - PhantomData<(RuntimeApi, AuraId)>, -); - -impl BuildImportQueue - for BuildRelayToAuraImportQueue -where - RuntimeApi: ConstructNodeRuntimeApi>, - RuntimeApi::RuntimeApi: AuraRuntimeApi, - AuraId: AuraIdT + Sync, -{ - fn build_import_queue( - client: Arc>, - block_import: ParachainBlockImport, - config: &Configuration, - telemetry_handle: Option, - task_manager: &TaskManager, - ) -> sc_service::error::Result> { - let verifier_client = client.clone(); - - let aura_verifier = - cumulus_client_consensus_aura::build_verifier::<::Pair, _, _, _>( - cumulus_client_consensus_aura::BuildVerifierParams { - client: verifier_client.clone(), - create_inherent_data_providers: move |parent_hash, _| { - let cidp_client = verifier_client.clone(); - async move { - let slot_duration = cumulus_client_consensus_aura::slot_duration_at( - &*cidp_client, - parent_hash, - )?; - let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); - - let slot = - sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration( - *timestamp, - slot_duration, - ); - - Ok((slot, timestamp)) - } - }, - telemetry: telemetry_handle, - }, - ); - - let relay_chain_verifier = - Box::new(RelayChainVerifier::new(client.clone(), |_, _| async { Ok(()) })); - - let verifier = Verifier { - client, - relay_chain_verifier, - aura_verifier: Box::new(aura_verifier), - _phantom: PhantomData, - }; - - let registry = config.prometheus_registry(); - let spawner = task_manager.spawn_essential_handle(); - - Ok(BasicQueue::new(verifier, Box::new(block_import), None, &spawner, registry)) - } -} - -/// Uses the lookahead collator to support async backing. -/// -/// Start an aura powered parachain node. Some system chains use this. -pub(crate) struct AuraNode( - pub PhantomData<(RuntimeApi, AuraId, StartConsensus)>, -); - -impl Default for AuraNode { - fn default() -> Self { - Self(Default::default()) - } -} - -impl NodeSpec for AuraNode -where - RuntimeApi: ConstructNodeRuntimeApi>, - RuntimeApi::RuntimeApi: AuraRuntimeApi - + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi - + substrate_frame_rpc_system::AccountNonceApi, - AuraId: AuraIdT + Sync, - StartConsensus: self::StartConsensus + 'static, -{ - type RuntimeApi = RuntimeApi; - type BuildImportQueue = BuildRelayToAuraImportQueue; - type BuildRpcExtensions = BuildParachainRpcExtensions; - type StartConsensus = StartConsensus; - const SYBIL_RESISTANCE: CollatorSybilResistance = CollatorSybilResistance::Resistant; -} - -pub fn new_aura_node_spec(extra_args: NodeExtraArgs) -> Box -where - RuntimeApi: ConstructNodeRuntimeApi>, - RuntimeApi::RuntimeApi: AuraRuntimeApi - + pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi - + substrate_frame_rpc_system::AccountNonceApi, - AuraId: AuraIdT + Sync, -{ - if extra_args.use_slot_based_consensus { - Box::new(AuraNode::< - RuntimeApi, - AuraId, - StartSlotBasedAuraConsensus, - >::default()) - } else { - Box::new(AuraNode::< - RuntimeApi, - AuraId, - StartLookaheadAuraConsensus, - >::default()) - } -} - -/// Start relay-chain consensus that is free for all. Everyone can submit a block, the relay-chain -/// decides what is backed and included. -pub(crate) struct StartRelayChainConsensus; - -impl StartConsensus for StartRelayChainConsensus { - fn start_consensus( - client: Arc>, - block_import: ParachainBlockImport, - prometheus_registry: Option<&Registry>, - telemetry: Option, - task_manager: &TaskManager, - relay_chain_interface: Arc, - transaction_pool: Arc>>, - _keystore: KeystorePtr, - _relay_chain_slot_duration: Duration, - para_id: ParaId, - collator_key: CollatorPair, - overseer_handle: OverseerHandle, - announce_block: Arc>) + Send + Sync>, - _backend: Arc, - ) -> Result<(), Error> { - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - task_manager.spawn_handle(), - client.clone(), - transaction_pool, - prometheus_registry, - telemetry, - ); - - let free_for_all = cumulus_client_consensus_relay_chain::build_relay_chain_consensus( - cumulus_client_consensus_relay_chain::BuildRelayChainConsensusParams { - para_id, - proposer_factory, - block_import, - relay_chain_interface: relay_chain_interface.clone(), - create_inherent_data_providers: move |_, (relay_parent, validation_data)| { - let relay_chain_interface = relay_chain_interface.clone(); - async move { - let parachain_inherent = - cumulus_client_parachain_inherent::ParachainInherentDataProvider::create_at( - relay_parent, - &relay_chain_interface, - &validation_data, - para_id, - ).await; - let parachain_inherent = parachain_inherent.ok_or_else(|| { - Box::::from( - "Failed to create parachain inherent", - ) - })?; - Ok(parachain_inherent) - } - }, - }, - ); - - let spawner = task_manager.spawn_handle(); - - // Required for free-for-all consensus - #[allow(deprecated)] - old_consensus::start_collator_sync(old_consensus::StartCollatorParams { - para_id, - block_status: client.clone(), - announce_block, - overseer_handle, - spawner, - key: collator_key, - parachain_consensus: free_for_all, - runtime_api: client.clone(), - }); - - Ok(()) - } -} - -/// Start consensus using the lookahead aura collator. -pub(crate) struct StartSlotBasedAuraConsensus( - PhantomData<(RuntimeApi, AuraId)>, -); - -impl StartSlotBasedAuraConsensus -where - RuntimeApi: ConstructNodeRuntimeApi>, - RuntimeApi::RuntimeApi: AuraRuntimeApi, - AuraId: AuraIdT + Sync, -{ - #[docify::export_content] - fn launch_slot_based_collator( - params: SlotBasedParams< - ParachainBlockImport, - CIDP, - ParachainClient, - ParachainBackend, - Arc, - CHP, - Proposer, - CS, - >, - task_manager: &TaskManager, - ) where - CIDP: CreateInherentDataProviders + 'static, - CIDP::InherentDataProviders: Send, - CHP: cumulus_client_consensus_common::ValidationCodeHashProvider + Send + 'static, - Proposer: ProposerInterface + Send + Sync + 'static, - CS: CollatorServiceInterface + Send + Sync + Clone + 'static, - { - let (collation_future, block_builder_future) = - slot_based::run::::Pair, _, _, _, _, _, _, _, _>(params); - - task_manager.spawn_essential_handle().spawn( - "collation-task", - Some("parachain-block-authoring"), - collation_future, - ); - task_manager.spawn_essential_handle().spawn( - "block-builder-task", - Some("parachain-block-authoring"), - block_builder_future, - ); - } -} - -impl StartConsensus - for StartSlotBasedAuraConsensus -where - RuntimeApi: ConstructNodeRuntimeApi>, - RuntimeApi::RuntimeApi: AuraRuntimeApi, - AuraId: AuraIdT + Sync, -{ - fn start_consensus( - client: Arc>, - block_import: ParachainBlockImport, - prometheus_registry: Option<&Registry>, - telemetry: Option, - task_manager: &TaskManager, - relay_chain_interface: Arc, - transaction_pool: Arc>>, - keystore: KeystorePtr, - relay_chain_slot_duration: Duration, - para_id: ParaId, - collator_key: CollatorPair, - _overseer_handle: OverseerHandle, - announce_block: Arc>) + Send + Sync>, - backend: Arc, - ) -> Result<(), Error> { - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - task_manager.spawn_handle(), - client.clone(), - transaction_pool, - prometheus_registry, - telemetry.clone(), - ); - - let proposer = Proposer::new(proposer_factory); - let collator_service = CollatorService::new( - client.clone(), - Arc::new(task_manager.spawn_handle()), - announce_block, - client.clone(), - ); - - let client_for_aura = client.clone(); - let params = SlotBasedParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, - block_import, - para_client: client.clone(), - para_backend: backend.clone(), - relay_client: relay_chain_interface, - code_hash_provider: move |block_hash| { - client_for_aura.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) - }, - keystore, - collator_key, - para_id, - relay_chain_slot_duration, - proposer, - collator_service, - authoring_duration: Duration::from_millis(2000), - reinitialize: false, - slot_drift: Duration::from_secs(1), - }; - - // We have a separate function only to be able to use `docify::export` on this piece of - // code. - Self::launch_slot_based_collator(params, task_manager); - - Ok(()) - } -} - -/// Wait for the Aura runtime API to appear on chain. -/// This is useful for chains that started out without Aura. Components that -/// are depending on Aura functionality will wait until Aura appears in the runtime. -async fn wait_for_aura(client: Arc>) -where - RuntimeApi: ConstructNodeRuntimeApi>, - RuntimeApi::RuntimeApi: AuraRuntimeApi, - AuraId: AuraIdT + Sync, -{ - let finalized_hash = client.chain_info().finalized_hash; - if client.runtime_api().has_aura_api(finalized_hash) { - return; - }; - - let mut stream = client.finality_notification_stream(); - while let Some(notification) = stream.next().await { - if client.runtime_api().has_aura_api(notification.hash) { - return; - } - } -} - -/// Start consensus using the lookahead aura collator. -pub(crate) struct StartLookaheadAuraConsensus( - PhantomData<(RuntimeApi, AuraId)>, -); - -impl StartConsensus - for StartLookaheadAuraConsensus -where - RuntimeApi: ConstructNodeRuntimeApi>, - RuntimeApi::RuntimeApi: AuraRuntimeApi, - AuraId: AuraIdT + Sync, -{ - fn start_consensus( - client: Arc>, - block_import: ParachainBlockImport, - prometheus_registry: Option<&Registry>, - telemetry: Option, - task_manager: &TaskManager, - relay_chain_interface: Arc, - transaction_pool: Arc>>, - keystore: KeystorePtr, - relay_chain_slot_duration: Duration, - para_id: ParaId, - collator_key: CollatorPair, - overseer_handle: OverseerHandle, - announce_block: Arc>) + Send + Sync>, - backend: Arc, - ) -> Result<(), Error> { - let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording( - task_manager.spawn_handle(), - client.clone(), - transaction_pool, - prometheus_registry, - telemetry.clone(), - ); - - let collator_service = CollatorService::new( - client.clone(), - Arc::new(task_manager.spawn_handle()), - announce_block, - client.clone(), - ); - - let params = AuraParams { - create_inherent_data_providers: move |_, ()| async move { Ok(()) }, - block_import, - para_client: client.clone(), - para_backend: backend, - relay_client: relay_chain_interface, - code_hash_provider: { - let client = client.clone(); - move |block_hash| { - client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash()) - } - }, - keystore, - collator_key, - para_id, - overseer_handle, - relay_chain_slot_duration, - proposer: Proposer::new(proposer_factory), - collator_service, - authoring_duration: Duration::from_millis(1500), - reinitialize: false, - }; - - let fut = async move { - wait_for_aura(client).await; - aura::run::::Pair, _, _, _, _, _, _, _, _>(params).await; - }; - task_manager.spawn_essential_handle().spawn("aura", None, fut); - - Ok(()) - } -} - -/// Checks that the hardware meets the requirements and print a warning otherwise. -fn warn_if_slow_hardware(hwbench: &sc_sysinfo::HwBench) { - // Polkadot para-chains should generally use these requirements to ensure that the relay-chain - // will not take longer than expected to import its blocks. - if let Err(err) = frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE.check_hardware(hwbench) { - log::warn!( - "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority' find out more at:\n\ - https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", - err - ); - } -} - -type SyncCmdResult = sc_cli::Result<()>; - -type AsyncCmdResult<'a> = - sc_cli::Result<(Pin + 'a>>, TaskManager)>; - -pub(crate) trait DynNodeSpec { - fn prepare_check_block_cmd( - self: Box, - config: Configuration, - cmd: &CheckBlockCmd, - ) -> AsyncCmdResult<'_>; - - fn prepare_export_blocks_cmd( - self: Box, - config: Configuration, - cmd: &ExportBlocksCmd, - ) -> AsyncCmdResult<'_>; - - fn prepare_export_state_cmd( - self: Box, - config: Configuration, - cmd: &ExportStateCmd, - ) -> AsyncCmdResult<'_>; - - fn prepare_import_blocks_cmd( - self: Box, - config: Configuration, - cmd: &ImportBlocksCmd, - ) -> AsyncCmdResult<'_>; - - fn prepare_revert_cmd( - self: Box, - config: Configuration, - cmd: &RevertCmd, - ) -> AsyncCmdResult<'_>; - - fn run_export_genesis_head_cmd( - self: Box, - config: Configuration, - cmd: &ExportGenesisHeadCommand, - ) -> SyncCmdResult; - - fn run_benchmark_block_cmd( - self: Box, - config: Configuration, - cmd: &BlockCmd, - ) -> SyncCmdResult; - - #[cfg(any(feature = "runtime-benchmarks"))] - fn run_benchmark_storage_cmd( - self: Box, - config: Configuration, - cmd: &StorageCmd, - ) -> SyncCmdResult; - - fn start_node( - self: Box, - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, - ) -> Pin>>>; -} - -impl DynNodeSpec for T -where - T: NodeSpec, -{ - fn prepare_check_block_cmd( - self: Box, - config: Configuration, - cmd: &CheckBlockCmd, - ) -> AsyncCmdResult<'_> { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - Ok((Box::pin(cmd.run(partial.client, partial.import_queue)), partial.task_manager)) - } - - fn prepare_export_blocks_cmd( - self: Box, - config: Configuration, - cmd: &ExportBlocksCmd, - ) -> AsyncCmdResult<'_> { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - Ok((Box::pin(cmd.run(partial.client, config.database)), partial.task_manager)) - } - - fn prepare_export_state_cmd( - self: Box, - config: Configuration, - cmd: &ExportStateCmd, - ) -> AsyncCmdResult<'_> { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - Ok((Box::pin(cmd.run(partial.client, config.chain_spec)), partial.task_manager)) - } - - fn prepare_import_blocks_cmd( - self: Box, - config: Configuration, - cmd: &ImportBlocksCmd, - ) -> AsyncCmdResult<'_> { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - Ok((Box::pin(cmd.run(partial.client, partial.import_queue)), partial.task_manager)) - } - - fn prepare_revert_cmd( - self: Box, - config: Configuration, - cmd: &RevertCmd, - ) -> AsyncCmdResult<'_> { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - Ok((Box::pin(cmd.run(partial.client, partial.backend, None)), partial.task_manager)) - } - - fn run_export_genesis_head_cmd( - self: Box, - config: Configuration, - cmd: &ExportGenesisHeadCommand, - ) -> SyncCmdResult { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - cmd.run(partial.client) - } - - fn run_benchmark_block_cmd( - self: Box, - config: Configuration, - cmd: &BlockCmd, - ) -> SyncCmdResult { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - cmd.run(partial.client) - } - - #[cfg(any(feature = "runtime-benchmarks"))] - fn run_benchmark_storage_cmd( - self: Box, - config: Configuration, - cmd: &StorageCmd, - ) -> SyncCmdResult { - let partial = Self::new_partial(&config).map_err(sc_cli::Error::Service)?; - let db = partial.backend.expose_db(); - let storage = partial.backend.expose_storage(); - - cmd.run(config, partial.client, db, storage) - } - - fn start_node( - self: Box, - parachain_config: Configuration, - polkadot_config: Configuration, - collator_options: CollatorOptions, - para_id: ParaId, - hwbench: Option, - ) -> Pin>>> { - match parachain_config.network.network_backend { - sc_network::config::NetworkBackendType::Libp2p => - ::start_node::>( - parachain_config, - polkadot_config, - collator_options, - para_id, - hwbench, - ), - sc_network::config::NetworkBackendType::Litep2p => - ::start_node::( - parachain_config, - polkadot_config, - collator_options, - para_id, - hwbench, - ), - } - } -} diff --git a/cumulus/primitives/aura/Cargo.toml b/cumulus/primitives/aura/Cargo.toml index 062b9ce736e7..185b2d40833f 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/aura/src/lib.rs b/cumulus/primitives/aura/src/lib.rs index 826b65fddd2c..aeeee5f8bafa 100644 --- a/cumulus/primitives/aura/src/lib.rs +++ b/cumulus/primitives/aura/src/lib.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/cumulus/primitives/core/src/lib.rs b/cumulus/primitives/core/src/lib.rs index 6eafecfc3ff5..dfb574ef3301 100644 --- a/cumulus/primitives/core/src/lib.rs +++ b/cumulus/primitives/core/src/lib.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. @@ -32,6 +32,7 @@ pub use polkadot_parachain_primitives::primitives::{ XcmpMessageHandler, }; pub use polkadot_primitives::{ + vstaging::{ClaimQueueOffset, CoreSelector}, AbridgedHostConfiguration, AbridgedHrmpChannel, PersistedValidationData, }; @@ -332,6 +333,10 @@ pub mod rpsr_digest { } } +/// The default claim queue offset to be used if it's not configured/accessible in the parachain +/// runtime +pub const DEFAULT_CLAIM_QUEUE_OFFSET: u8 = 0; + /// Information about a collation. /// /// This was used in version 1 of the [`CollectCollationInfo`] runtime api. @@ -395,4 +400,10 @@ sp_api::decl_runtime_apis! { /// we are collecting the collation info for. fn collect_collation_info(header: &Block::Header) -> CollationInfo; } + + /// Runtime api used to select the core for which the next block will be built. + pub trait GetCoreSelectorApi { + /// Retrieve core selector and claim queue offset for the next block. + fn core_selector() -> (CoreSelector, ClaimQueueOffset); + } } diff --git a/cumulus/primitives/parachain-inherent/Cargo.toml b/cumulus/primitives/parachain-inherent/Cargo.toml index 172af4b9ec63..a4271d3fd9cc 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/parachain-inherent/src/lib.rs b/cumulus/primitives/parachain-inherent/src/lib.rs index ad4b39b547c5..127a03b65259 100644 --- a/cumulus/primitives/parachain-inherent/src/lib.rs +++ b/cumulus/primitives/parachain-inherent/src/lib.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/cumulus/primitives/proof-size-hostfunction/src/lib.rs b/cumulus/primitives/proof-size-hostfunction/src/lib.rs index 8ebc58ea450d..f17b3d3f33b4 100644 --- a/cumulus/primitives/proof-size-hostfunction/src/lib.rs +++ b/cumulus/primitives/proof-size-hostfunction/src/lib.rs @@ -6,7 +6,7 @@ // 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, +// 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. diff --git a/cumulus/primitives/storage-weight-reclaim/Cargo.toml b/cumulus/primitives/storage-weight-reclaim/Cargo.toml index 3a98fdd017ae..e1ae6743335a 100644 --- a/cumulus/primitives/storage-weight-reclaim/Cargo.toml +++ b/cumulus/primitives/storage-weight-reclaim/Cargo.toml @@ -14,6 +14,7 @@ codec = { features = ["derive"], workspace = true } log = { workspace = true } scale-info = { features = ["derive"], workspace = true } +frame-benchmarking = { optional = true, workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } @@ -24,8 +25,8 @@ cumulus-primitives-proof-size-hostfunction = { workspace = true } docify = { workspace = true } [dev-dependencies] -sp-trie = { workspace = true } sp-io = { workspace = true } +sp-trie = { workspace = true } cumulus-test-runtime = { workspace = true } [features] @@ -34,6 +35,7 @@ std = [ "codec/std", "cumulus-primitives-core/std", "cumulus-primitives-proof-size-hostfunction/std", + "frame-benchmarking/std", "frame-support/std", "frame-system/std", "log/std", diff --git a/cumulus/primitives/storage-weight-reclaim/src/lib.rs b/cumulus/primitives/storage-weight-reclaim/src/lib.rs index f48dd927ee96..5471640695ca 100644 --- a/cumulus/primitives/storage-weight-reclaim/src/lib.rs +++ b/cumulus/primitives/storage-weight-reclaim/src/lib.rs @@ -30,11 +30,15 @@ use frame_support::{ use frame_system::Config; use scale_info::TypeInfo; use sp_runtime::{ - traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SignedExtension}, + impl_tx_ext_default, + traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, TransactionExtension}, transaction_validity::TransactionValidityError, DispatchResult, }; +#[cfg(test)] +mod tests; + const LOG_TARGET: &'static str = "runtime::storage_reclaim"; /// `StorageWeightReclaimer` is a mechanism for manually reclaiming storage weight. @@ -43,7 +47,7 @@ const LOG_TARGET: &'static str = "runtime::storage_reclaim"; /// reclaim it computes the real consumed storage weight and refunds excess weight. /// /// # Example -#[doc = docify::embed!("src/lib.rs", simple_reclaimer_example)] +#[doc = docify::embed!("src/tests.rs", simple_reclaimer_example)] pub struct StorageWeightReclaimer { previous_remaining_proof_size: u64, previous_reported_proof_size: Option, @@ -119,43 +123,35 @@ impl core::fmt::Debug for StorageWeightReclaim { } } -impl SignedExtension for StorageWeightReclaim +impl TransactionExtension for StorageWeightReclaim where T::RuntimeCall: Dispatchable, { const IDENTIFIER: &'static str = "StorageWeightReclaim"; - - type AccountId = T::AccountId; - type Call = T::RuntimeCall; - type AdditionalSigned = (); + type Implicit = (); + type Val = (); type Pre = Option; - fn additional_signed( - &self, - ) -> Result - { - Ok(()) - } - - fn pre_dispatch( + fn prepare( self, - _who: &Self::AccountId, - _call: &Self::Call, - _info: &sp_runtime::traits::DispatchInfoOf, + _val: Self::Val, + _origin: &T::RuntimeOrigin, + _call: &T::RuntimeCall, + _info: &DispatchInfoOf, _len: usize, - ) -> Result { + ) -> Result { Ok(get_proof_size()) } - fn post_dispatch( - pre: Option, - info: &DispatchInfoOf, - post_info: &PostDispatchInfoOf, + fn post_dispatch_details( + pre: Self::Pre, + info: &DispatchInfoOf, + post_info: &PostDispatchInfoOf, _len: usize, _result: &DispatchResult, - ) -> Result<(), TransactionValidityError> { - let Some(Some(pre_dispatch_proof_size)) = pre else { - return Ok(()); + ) -> Result { + let Some(pre_dispatch_proof_size) = pre else { + return Ok(Weight::zero()); }; let Some(post_dispatch_proof_size) = get_proof_size() else { @@ -163,17 +159,19 @@ where target: LOG_TARGET, "Proof recording enabled during pre-dispatch, now disabled. This should not happen." ); - return Ok(()) + return Ok(Weight::zero()) }; - 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.total_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. @@ -181,574 +179,34 @@ where if consumed_weight > benchmarked_weight { log::error!( target: LOG_TARGET, - "Benchmarked storage weight smaller than consumed storage weight. benchmarked: {benchmarked_weight} consumed: {consumed_weight} unspent: {unspent}" + "Benchmarked storage weight smaller than consumed storage weight. extrinsic: {} benchmarked: {benchmarked_weight} consumed: {consumed_weight} unspent: {unspent}", + frame_system::Pallet::::extrinsic_index().unwrap_or(0) ); current.accrue(Weight::from_parts(0, storage_size_diff), info.class) } else { log::trace!( target: LOG_TARGET, - "Reclaiming storage weight. benchmarked: {benchmarked_weight}, consumed: {consumed_weight} unspent: {unspent}" + "Reclaiming storage weight. extrinsic: {} benchmarked: {benchmarked_weight} consumed: {consumed_weight} unspent: {unspent}", + frame_system::Pallet::::extrinsic_index().unwrap_or(0) ); current.reduce(Weight::from_parts(0, storage_size_diff), info.class) } - }); - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use core::marker::PhantomData; - use frame_support::{ - assert_ok, - dispatch::{DispatchClass, PerDispatchClass}, - weights::{Weight, WeightMeter}, - }; - use frame_system::{BlockWeight, CheckWeight}; - use sp_runtime::{AccountId32, BuildStorage}; - use sp_trie::proof_size_extension::ProofSizeExt; - - type Test = cumulus_test_runtime::Runtime; - const CALL: &::RuntimeCall = - &cumulus_test_runtime::RuntimeCall::System(frame_system::Call::set_heap_pages { - pages: 0u64, - }); - const ALICE: AccountId32 = AccountId32::new([1u8; 32]); - const LEN: usize = 150; - - pub fn new_test_ext() -> sp_io::TestExternalities { - let ext: sp_io::TestExternalities = cumulus_test_runtime::RuntimeGenesisConfig::default() - .build_storage() - .unwrap() - .into(); - ext - } - - struct TestRecorder { - return_values: Box<[usize]>, - counter: std::sync::atomic::AtomicUsize, - } - - impl TestRecorder { - fn new(values: &[usize]) -> Self { - TestRecorder { return_values: values.into(), counter: Default::default() } - } - } - - impl sp_trie::ProofSizeProvider for TestRecorder { - fn estimate_encoded_size(&self) -> usize { - let counter = self.counter.fetch_add(1, core::sync::atomic::Ordering::Relaxed); - self.return_values[counter] - } - } - - fn setup_test_externalities(proof_values: &[usize]) -> sp_io::TestExternalities { - let mut test_ext = new_test_ext(); - let test_recorder = TestRecorder::new(proof_values); - test_ext.register_extension(ProofSizeExt::new(test_recorder)); - test_ext - } - - fn set_current_storage_weight(new_weight: u64) { - BlockWeight::::mutate(|current_weight| { - current_weight.set(Weight::from_parts(0, new_weight), DispatchClass::Normal); - }); - } - - fn get_storage_weight() -> PerDispatchClass { - BlockWeight::::get() - } - - #[test] - fn basic_refund() { - // 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, 500), ..Default::default() }; - let post_info = PostDispatchInfo::default(); - - // Should add 500 + 150 (len) to weight. - 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 a refund of 400 - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - - assert_eq!(get_storage_weight().total().proof_size(), 1250); - }) - } - - #[test] - fn does_nothing_without_extension() { - let mut test_ext = new_test_ext(); - - // Proof size extension not registered - test_ext.execute_with(|| { - set_current_storage_weight(1000); - - // Benchmarked storage weight: 500 - let info = DispatchInfo { weight: Weight::from_parts(0, 500), ..Default::default() }; - let post_info = PostDispatchInfo::default(); - - // Adds 500 + 150 (len) weight - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, None); - - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - - assert_eq!(get_storage_weight().total().proof_size(), 1650); - }) - } - - #[test] - fn negative_refund_is_added_to_weight() { - let mut test_ext = setup_test_externalities(&[100, 300]); - - test_ext.execute_with(|| { - set_current_storage_weight(1000); - // Benchmarked storage weight: 100 - let info = DispatchInfo { weight: Weight::from_parts(0, 100), ..Default::default() }; - let post_info = PostDispatchInfo::default(); - - // Weight added should be 100 + 150 (len) - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(100)); - - // We expect no refund - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - - assert_eq!( - get_storage_weight().total().proof_size(), - 1100 + LEN as u64 + info.weight.proof_size() - ); - }) - } - - #[test] - fn test_zero_proof_size() { - let mut test_ext = setup_test_externalities(&[0, 0]); - - test_ext.execute_with(|| { - let info = DispatchInfo { weight: Weight::from_parts(0, 500), ..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(0)); - - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - - // Proof size should be exactly equal to extrinsic length - assert_eq!(get_storage_weight().total().proof_size(), LEN as u64); - }); - } - - #[test] - fn test_larger_pre_dispatch_proof_size() { - let mut test_ext = setup_test_externalities(&[300, 100]); - - test_ext.execute_with(|| { - set_current_storage_weight(1300); - - let info = DispatchInfo { weight: Weight::from_parts(0, 500), ..Default::default() }; - let post_info = PostDispatchInfo::default(); - - // Adds 500 + 150 (len) weight, total weight is 1950 - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(300)); - - // Refund 500 unspent weight according to `post_info`, total weight is now 1650 - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - // Recorded proof size is negative -200, total weight is now 1450 - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - - assert_eq!(get_storage_weight().total().proof_size(), 1450); - }); - } - - #[test] - fn test_incorporates_check_weight_unspent_weight() { - let mut test_ext = setup_test_externalities(&[100, 300]); - - test_ext.execute_with(|| { - set_current_storage_weight(1000); - - // Benchmarked storage weight: 300 - let info = DispatchInfo { weight: Weight::from_parts(100, 300), ..Default::default() }; - - // Actual weight is 50 - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(50, 250)), - pays_fee: Default::default(), - }; - - // Should add 300 + 150 (len) of weight - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(100)); - - // The `CheckWeight` extension will refund `actual_weight` from `PostDispatchInfo` - // we always need to call `post_dispatch` to verify that they interoperate correctly. - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - - // Reclaimed 100 - assert_eq!(get_storage_weight().total().proof_size(), 1350); - }) - } - - #[test] - fn test_incorporates_check_weight_unspent_weight_on_negative() { - let mut test_ext = setup_test_externalities(&[100, 300]); - - test_ext.execute_with(|| { - set_current_storage_weight(1000); - // Benchmarked storage weight: 50 - let info = DispatchInfo { weight: Weight::from_parts(100, 50), ..Default::default() }; - - // Actual weight is 25 - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(50, 25)), - pays_fee: Default::default(), - }; - - // Adds 50 + 150 (len) weight, total weight 1200 - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(100)); - - // The `CheckWeight` extension will refund `actual_weight` from `PostDispatchInfo` - // we always need to call `post_dispatch` to verify that they interoperate correctly. - - // Refunds unspent 25 weight according to `post_info`, 1175 - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - // Adds 200 - 25 (unspent) == 175 weight, total weight 1350 - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - - assert_eq!(get_storage_weight().total().proof_size(), 1350); - }) - } - - #[test] - fn test_nothing_relcaimed() { - let mut test_ext = setup_test_externalities(&[100, 200]); - - test_ext.execute_with(|| { - set_current_storage_weight(0); - // Benchmarked storage weight: 100 - let info = DispatchInfo { weight: Weight::from_parts(100, 100), ..Default::default() }; - - // Actual proof size is 100 - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(50, 100)), - pays_fee: Default::default(), - }; - - // Adds benchmarked weight 100 + 150 (len), total weight is now 250 - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - // Weight should go up by 150 len + 100 proof size weight, total weight 250 - assert_eq!(get_storage_weight().total().proof_size(), 250); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - // Should return `setup_test_externalities` proof recorder value: 100. - assert_eq!(pre, Some(100)); - - // The `CheckWeight` extension will refund `actual_weight` from `PostDispatchInfo` - // we always need to call `post_dispatch` to verify that they interoperate correctly. - // Nothing to refund, unspent is 0, total weight 250 - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, LEN, &Ok(()))); - // `setup_test_externalities` proof recorder value: 200, so this means the extrinsic - // actually used 100 proof size. - // Nothing to refund or add, weight matches proof recorder - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - - // Check block len weight was not reclaimed: - // 100 weight + 150 extrinsic len == 250 proof size - assert_eq!(get_storage_weight().total().proof_size(), 250); - }) - } - - #[test] - fn test_incorporates_check_weight_unspent_weight_reverse_order() { - let mut test_ext = setup_test_externalities(&[100, 300]); - - test_ext.execute_with(|| { - set_current_storage_weight(1000); - - // Benchmarked storage weight: 300 - let info = DispatchInfo { weight: Weight::from_parts(100, 300), ..Default::default() }; - - // Actual weight is 50 - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(50, 250)), - pays_fee: Default::default(), - }; - - // Adds 300 + 150 (len) weight, total weight 1450 - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(100)); - - // This refunds 100 - 50(unspent), total weight is now 1400 - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - // `CheckWeight` gets called after `StorageWeightReclaim` this time. - // The `CheckWeight` extension will refund `actual_weight` from `PostDispatchInfo` - // we always need to call `post_dispatch` to verify that they interoperate correctly. - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - - // Above call refunds 50 (unspent), total weight is 1350 now - assert_eq!(get_storage_weight().total().proof_size(), 1350); - }) - } - - #[test] - fn test_incorporates_check_weight_unspent_weight_on_negative_reverse_order() { - let mut test_ext = setup_test_externalities(&[100, 300]); - - test_ext.execute_with(|| { - set_current_storage_weight(1000); - // Benchmarked storage weight: 50 - let info = DispatchInfo { weight: Weight::from_parts(100, 50), ..Default::default() }; - - // Actual weight is 25 - let post_info = PostDispatchInfo { - actual_weight: Some(Weight::from_parts(50, 25)), - pays_fee: Default::default(), - }; - - // Adds 50 + 150 (len) weight, total weight is 1200 - assert_ok!(CheckWeight::::do_pre_dispatch(&info, LEN)); - - let pre = StorageWeightReclaim::(PhantomData) - .pre_dispatch(&ALICE, CALL, &info, LEN) - .unwrap(); - assert_eq!(pre, Some(100)); - - // Adds additional 150 weight recorded - assert_ok!(StorageWeightReclaim::::post_dispatch( - Some(pre), - &info, - &post_info, - LEN, - &Ok(()) - )); - // `CheckWeight` gets called after `StorageWeightReclaim` this time. - // The `CheckWeight` extension will refund `actual_weight` from `PostDispatchInfo` - // we always need to call `post_dispatch` to verify that they interoperate correctly. - assert_ok!(CheckWeight::::post_dispatch(None, &info, &post_info, 0, &Ok(()))); - - assert_eq!(get_storage_weight().total().proof_size(), 1350); - }) - } - - #[test] - fn storage_size_reported_correctly() { - let mut test_ext = setup_test_externalities(&[1000]); - test_ext.execute_with(|| { - assert_eq!(get_proof_size(), Some(1000)); - }); - - let mut test_ext = new_test_ext(); - - let test_recorder = TestRecorder::new(&[0]); - - test_ext.register_extension(ProofSizeExt::new(test_recorder)); - - test_ext.execute_with(|| { - assert_eq!(get_proof_size(), Some(0)); - }); - } - - #[test] - fn storage_size_disabled_reported_correctly() { - let mut test_ext = setup_test_externalities(&[PROOF_RECORDING_DISABLED as usize]); - - test_ext.execute_with(|| { - assert_eq!(get_proof_size(), None); - }); - } - - #[test] - fn test_reclaim_helper() { - let mut test_ext = setup_test_externalities(&[1000, 1300, 1800]); - - test_ext.execute_with(|| { - let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(0, 2000)); - let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); - remaining_weight_meter.consume(Weight::from_parts(0, 500)); - let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); - - assert_eq!(reclaimed, Some(Weight::from_parts(0, 200))); - - remaining_weight_meter.consume(Weight::from_parts(0, 800)); - let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); - assert_eq!(reclaimed, Some(Weight::from_parts(0, 300))); - assert_eq!(remaining_weight_meter.remaining(), Weight::from_parts(0, 1200)); - }); - } - - #[test] - fn test_reclaim_helper_does_not_reclaim_negative() { - // Benchmarked weight does not change at all - let mut test_ext = setup_test_externalities(&[1000, 1300]); - - test_ext.execute_with(|| { - let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(0, 1000)); - let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); - let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); - - assert_eq!(reclaimed, Some(Weight::from_parts(0, 0))); - assert_eq!(remaining_weight_meter.remaining(), Weight::from_parts(0, 1000)); - }); - - // Benchmarked weight increases less than storage proof consumes - let mut test_ext = setup_test_externalities(&[1000, 1300]); - - test_ext.execute_with(|| { - let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(0, 1000)); - let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); - remaining_weight_meter.consume(Weight::from_parts(0, 0)); - let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); - - assert_eq!(reclaimed, Some(Weight::from_parts(0, 0))); + // 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(Weight::zero()) } - /// Just here for doc purposes - fn get_benched_weight() -> Weight { - Weight::from_parts(0, 5) - } - - /// Just here for doc purposes - fn do_work() {} - - #[docify::export_content(simple_reclaimer_example)] - fn reclaim_with_weight_meter() { - let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(10, 10)); - - let benched_weight = get_benched_weight(); - - // It is important to instantiate the `StorageWeightReclaimer` before we consume the weight - // for a piece of work from the weight meter. - let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); - - if remaining_weight_meter.try_consume(benched_weight).is_ok() { - // Perform some work that takes has `benched_weight` storage weight. - do_work(); - - // Reclaimer will detect that we only consumed 2 bytes, so 3 bytes are reclaimed. - let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); - - // We reclaimed 3 bytes of storage size! - assert_eq!(reclaimed, Some(Weight::from_parts(0, 3))); - assert_eq!(get_storage_weight().total().proof_size(), 10); - assert_eq!(remaining_weight_meter.remaining(), Weight::from_parts(10, 8)); - } - } - - #[test] - fn test_reclaim_helper_works_with_meter() { - // The node will report 12 - 10 = 2 consumed storage size between the calls. - let mut test_ext = setup_test_externalities(&[10, 12]); - - test_ext.execute_with(|| { - // Initial storage size is 10. - set_current_storage_weight(10); - reclaim_with_weight_meter(); - }); - } + impl_tx_ext_default!(T::RuntimeCall; weight validate); } diff --git a/cumulus/primitives/storage-weight-reclaim/src/tests.rs b/cumulus/primitives/storage-weight-reclaim/src/tests.rs new file mode 100644 index 000000000000..c5552b0f0a33 --- /dev/null +++ b/cumulus/primitives/storage-weight-reclaim/src/tests.rs @@ -0,0 +1,706 @@ +// 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 super::*; +use core::marker::PhantomData; +use frame_support::{ + assert_ok, + dispatch::{DispatchClass, PerDispatchClass}, + weights::{Weight, WeightMeter}, +}; +use frame_system::{BlockWeight, CheckWeight}; +use sp_runtime::{traits::DispatchTransaction, AccountId32, BuildStorage}; +use sp_trie::proof_size_extension::ProofSizeExt; + +type Test = cumulus_test_runtime::Runtime; +const CALL: &::RuntimeCall = + &cumulus_test_runtime::RuntimeCall::System(frame_system::Call::set_heap_pages { pages: 0u64 }); +const ALICE: AccountId32 = AccountId32::new([1u8; 32]); +const LEN: usize = 150; + +fn new_test_ext() -> sp_io::TestExternalities { + let ext: sp_io::TestExternalities = cumulus_test_runtime::RuntimeGenesisConfig::default() + .build_storage() + .unwrap() + .into(); + ext +} + +struct TestRecorder { + return_values: Box<[usize]>, + counter: core::sync::atomic::AtomicUsize, +} + +impl TestRecorder { + fn new(values: &[usize]) -> Self { + TestRecorder { return_values: values.into(), counter: Default::default() } + } +} + +impl sp_trie::ProofSizeProvider for TestRecorder { + fn estimate_encoded_size(&self) -> usize { + let counter = self.counter.fetch_add(1, core::sync::atomic::Ordering::Relaxed); + self.return_values[counter] + } +} + +fn setup_test_externalities(proof_values: &[usize]) -> sp_io::TestExternalities { + let mut test_ext = new_test_ext(); + let test_recorder = TestRecorder::new(proof_values); + test_ext.register_extension(ProofSizeExt::new(test_recorder)); + test_ext +} + +fn set_current_storage_weight(new_weight: u64) { + BlockWeight::::mutate(|current_weight| { + current_weight.set(Weight::from_parts(0, new_weight), DispatchClass::Normal); + }); +} + +fn get_storage_weight() -> PerDispatchClass { + BlockWeight::::get() +} + +#[test] +fn basic_refund() { + // 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 { call_weight: Weight::from_parts(0, 500), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + // Should add 500 + 150 (len) to weight. + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(0)); + + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()),)); + // We expect a refund of 400 + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()), + )); + + assert_eq!(get_storage_weight().total().proof_size(), 1250); + }) +} + +#[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 { call_weight: Weight::from_parts(0, 101), ..Default::default() }; + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(0, 99)), + pays_fee: Default::default(), + }; + + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(0)); + + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()))); + // We expect an accrue of 1 + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + 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 { call_weight: Weight::from_parts(0, 10), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(1000)); + + assert_ok!(CheckWeight::::post_dispatch_details( + (), + &info, + &post_info, + 0, + &Ok(()) + )); + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + 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 { call_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 + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(175)); + + assert_ok!(CheckWeight::::post_dispatch_details( + (), + &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_details( + 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(); + + // Proof size extension not registered + test_ext.execute_with(|| { + set_current_storage_weight(1000); + + // Benchmarked storage weight: 500 + let info = DispatchInfo { call_weight: Weight::from_parts(0, 500), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + // Adds 500 + 150 (len) weight + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, None); + + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()),)); + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()), + )); + + assert_eq!(get_storage_weight().total().proof_size(), 1650); + }) +} + +#[test] +fn negative_refund_is_added_to_weight() { + let mut test_ext = setup_test_externalities(&[100, 300]); + + test_ext.execute_with(|| { + set_current_storage_weight(1000); + // Benchmarked storage weight: 100 + let info = DispatchInfo { call_weight: Weight::from_parts(0, 100), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + // Weight added should be 100 + 150 (len) + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(100)); + + // We expect no refund + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()),)); + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()), + )); + + assert_eq!( + get_storage_weight().total().proof_size(), + 1100 + LEN as u64 + info.total_weight().proof_size() + ); + }) +} + +#[test] +fn test_zero_proof_size() { + let mut test_ext = setup_test_externalities(&[0, 0]); + + test_ext.execute_with(|| { + let info = DispatchInfo { call_weight: Weight::from_parts(0, 500), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(0)); + + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()),)); + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()), + )); + + // Proof size should be exactly equal to extrinsic length + assert_eq!(get_storage_weight().total().proof_size(), LEN as u64); + }); +} + +#[test] +fn test_larger_pre_dispatch_proof_size() { + let mut test_ext = setup_test_externalities(&[300, 100]); + + test_ext.execute_with(|| { + set_current_storage_weight(1300); + + let info = DispatchInfo { call_weight: Weight::from_parts(0, 500), ..Default::default() }; + let post_info = PostDispatchInfo::default(); + + // Adds 500 + 150 (len) weight, total weight is 1950 + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(300)); + + // Refund 500 unspent weight according to `post_info`, total weight is now 1650 + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()),)); + // Recorded proof size is negative -200, total weight is now 1450 + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()), + )); + + assert_eq!(get_storage_weight().total().proof_size(), 1450); + }); +} + +#[test] +fn test_incorporates_check_weight_unspent_weight() { + let mut test_ext = setup_test_externalities(&[100, 300]); + + test_ext.execute_with(|| { + set_current_storage_weight(1000); + + // Benchmarked storage weight: 300 + let info = DispatchInfo { call_weight: Weight::from_parts(100, 300), ..Default::default() }; + + // Actual weight is 50 + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(50, 250)), + pays_fee: Default::default(), + }; + + // Should add 300 + 150 (len) of weight + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(100)); + + // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` + // we always need to call `post_dispatch` to verify that they interoperate correctly. + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()),)); + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()), + )); + + // Reclaimed 100 + assert_eq!(get_storage_weight().total().proof_size(), 1350); + }) +} + +#[test] +fn test_incorporates_check_weight_unspent_weight_on_negative() { + let mut test_ext = setup_test_externalities(&[100, 300]); + + test_ext.execute_with(|| { + set_current_storage_weight(1000); + // Benchmarked storage weight: 50 + let info = DispatchInfo { call_weight: Weight::from_parts(100, 50), ..Default::default() }; + + // Actual weight is 25 + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(50, 25)), + pays_fee: Default::default(), + }; + + // Adds 50 + 150 (len) weight, total weight 1200 + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(100)); + + // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` + // we always need to call `post_dispatch` to verify that they interoperate correctly. + // Refunds unspent 25 weight according to `post_info`, 1175 + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()),)); + // Adds 200 - 25 (unspent) == 175 weight, total weight 1350 + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()), + )); + + assert_eq!(get_storage_weight().total().proof_size(), 1350); + }) +} + +#[test] +fn test_nothing_relcaimed() { + let mut test_ext = setup_test_externalities(&[0, 100]); + + test_ext.execute_with(|| { + set_current_storage_weight(0); + // Benchmarked storage weight: 100 + let info = DispatchInfo { call_weight: Weight::from_parts(100, 100), ..Default::default() }; + + // Actual proof size is 100 + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(50, 100)), + pays_fee: Default::default(), + }; + + // Adds benchmarked weight 100 + 150 (len), total weight is now 250 + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + // Weight should go up by 150 len + 100 proof size weight, total weight 250 + assert_eq!(get_storage_weight().total().proof_size(), 250); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + // Should return `setup_test_externalities` proof recorder value: 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. + // Nothing to refund, unspent is 0, total weight 250 + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, LEN, &Ok(()))); + // `setup_test_externalities` proof recorder value: 200, so this means the extrinsic + // actually used 100 proof size. + // Nothing to refund or add, weight matches proof recorder + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()) + )); + + // Check block len weight was not reclaimed: + // 100 weight + 150 extrinsic len == 250 proof size + assert_eq!(get_storage_weight().total().proof_size(), 250); + }) +} + +#[test] +fn test_incorporates_check_weight_unspent_weight_reverse_order() { + let mut test_ext = setup_test_externalities(&[100, 300]); + + test_ext.execute_with(|| { + set_current_storage_weight(1000); + + // Benchmarked storage weight: 300 + let info = DispatchInfo { call_weight: Weight::from_parts(100, 300), ..Default::default() }; + + // Actual weight is 50 + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(50, 250)), + pays_fee: Default::default(), + }; + + // Adds 300 + 150 (len) weight, total weight 1450 + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(100)); + + // This refunds 100 - 50(unspent), total weight is now 1400 + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()), + )); + // `CheckWeight` gets called after `StorageWeightReclaim` this time. + // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` + // we always need to call `post_dispatch` to verify that they interoperate correctly. + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()),)); + + // Above call refunds 50 (unspent), total weight is 1350 now + assert_eq!(get_storage_weight().total().proof_size(), 1350); + }) +} + +#[test] +fn test_incorporates_check_weight_unspent_weight_on_negative_reverse_order() { + let mut test_ext = setup_test_externalities(&[100, 300]); + + test_ext.execute_with(|| { + set_current_storage_weight(1000); + // Benchmarked storage weight: 50 + let info = DispatchInfo { call_weight: Weight::from_parts(100, 50), ..Default::default() }; + + // Actual weight is 25 + let post_info = PostDispatchInfo { + actual_weight: Some(Weight::from_parts(50, 25)), + pays_fee: Default::default(), + }; + + // Adds 50 + 150 (len) weight, total weight is 1200 + let (_, next_len) = CheckWeight::::do_validate(&info, LEN).unwrap(); + assert_ok!(CheckWeight::::do_prepare(&info, LEN, next_len)); + + let (pre, _) = StorageWeightReclaim::(PhantomData) + .validate_and_prepare(Some(ALICE.clone()).into(), CALL, &info, LEN) + .unwrap(); + assert_eq!(pre, Some(100)); + + // Adds additional 150 weight recorded + assert_ok!(StorageWeightReclaim::::post_dispatch_details( + pre, + &info, + &post_info, + LEN, + &Ok(()), + )); + // `CheckWeight` gets called after `StorageWeightReclaim` this time. + // The `CheckWeight` extension will refunt `actual_weight` from `PostDispatchInfo` + // we always need to call `post_dispatch` to verify that they interoperate correctly. + assert_ok!(CheckWeight::::post_dispatch_details((), &info, &post_info, 0, &Ok(()),)); + + assert_eq!(get_storage_weight().total().proof_size(), 1350); + }) +} + +#[test] +fn storage_size_reported_correctly() { + let mut test_ext = setup_test_externalities(&[1000]); + test_ext.execute_with(|| { + assert_eq!(get_proof_size(), Some(1000)); + }); + + let mut test_ext = new_test_ext(); + + let test_recorder = TestRecorder::new(&[0]); + + test_ext.register_extension(ProofSizeExt::new(test_recorder)); + + test_ext.execute_with(|| { + assert_eq!(get_proof_size(), Some(0)); + }); +} + +#[test] +fn storage_size_disabled_reported_correctly() { + let mut test_ext = setup_test_externalities(&[PROOF_RECORDING_DISABLED as usize]); + + test_ext.execute_with(|| { + assert_eq!(get_proof_size(), None); + }); +} + +#[test] +fn test_reclaim_helper() { + let mut test_ext = setup_test_externalities(&[1000, 1300, 1800]); + + test_ext.execute_with(|| { + let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(0, 2000)); + let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); + remaining_weight_meter.consume(Weight::from_parts(0, 500)); + let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); + + assert_eq!(reclaimed, Some(Weight::from_parts(0, 200))); + + remaining_weight_meter.consume(Weight::from_parts(0, 800)); + let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); + assert_eq!(reclaimed, Some(Weight::from_parts(0, 300))); + assert_eq!(remaining_weight_meter.remaining(), Weight::from_parts(0, 1200)); + }); +} + +#[test] +fn test_reclaim_helper_does_not_reclaim_negative() { + // Benchmarked weight does not change at all + let mut test_ext = setup_test_externalities(&[1000, 1300]); + + test_ext.execute_with(|| { + let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(0, 1000)); + let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); + let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); + + assert_eq!(reclaimed, Some(Weight::from_parts(0, 0))); + assert_eq!(remaining_weight_meter.remaining(), Weight::from_parts(0, 1000)); + }); + + // Benchmarked weight increases less than storage proof consumes + let mut test_ext = setup_test_externalities(&[1000, 1300]); + + test_ext.execute_with(|| { + let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(0, 1000)); + let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); + remaining_weight_meter.consume(Weight::from_parts(0, 0)); + let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); + + assert_eq!(reclaimed, Some(Weight::from_parts(0, 0))); + }); +} + +/// Just here for doc purposes +fn get_benched_weight() -> Weight { + Weight::from_parts(0, 5) +} + +/// Just here for doc purposes +fn do_work() {} + +#[docify::export_content(simple_reclaimer_example)] +fn reclaim_with_weight_meter() { + let mut remaining_weight_meter = WeightMeter::with_limit(Weight::from_parts(10, 10)); + + let benched_weight = get_benched_weight(); + + // It is important to instantiate the `StorageWeightReclaimer` before we consume the weight + // for a piece of work from the weight meter. + let mut reclaim_helper = StorageWeightReclaimer::new(&remaining_weight_meter); + + if remaining_weight_meter.try_consume(benched_weight).is_ok() { + // Perform some work that takes has `benched_weight` storage weight. + do_work(); + + // Reclaimer will detect that we only consumed 2 bytes, so 3 bytes are reclaimed. + let reclaimed = reclaim_helper.reclaim_with_meter(&mut remaining_weight_meter); + + // We reclaimed 3 bytes of storage size! + assert_eq!(reclaimed, Some(Weight::from_parts(0, 3))); + assert_eq!(get_storage_weight().total().proof_size(), 10); + assert_eq!(remaining_weight_meter.remaining(), Weight::from_parts(10, 8)); + } +} + +#[test] +fn test_reclaim_helper_works_with_meter() { + // The node will report 12 - 10 = 2 consumed storage size between the calls. + let mut test_ext = setup_test_externalities(&[10, 12]); + + test_ext.execute_with(|| { + // Initial storage size is 10. + set_current_storage_weight(10); + reclaim_with_weight_meter(); + }); +} diff --git a/cumulus/primitives/timestamp/Cargo.toml b/cumulus/primitives/timestamp/Cargo.toml index a50011bc3f0e..cb328e2f2cc6 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 82d18c8c0aac..2ca8b82001d5 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 9d5bf4e231eb..8530f5b87487 100644 --- a/cumulus/primitives/utility/src/lib.rs +++ b/cumulus/primitives/utility/src/lib.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. @@ -99,6 +99,10 @@ where impl InspectMessageQueues for ParentAsUmp { + fn clear_messages() { + T::clear_messages(); + } + fn get_messages() -> Vec<(VersionedLocation, Vec>)> { T::get_messages() } @@ -381,7 +385,8 @@ impl< FungiblesAssetMatcher, OnUnbalanced, AccountId, - > where + > +where Fungibles::Balance: Into, { fn new() -> Self { @@ -407,10 +412,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 +441,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 })?; @@ -524,7 +546,8 @@ impl< FungiblesAssetMatcher, OnUnbalanced, AccountId, - > where + > +where Fungibles::Balance: Into, { fn drop(&mut self) { diff --git a/cumulus/primitives/utility/src/tests/mod.rs b/cumulus/primitives/utility/src/tests/mod.rs index e0ad8718b89e..80e72ef28263 100644 --- a/cumulus/primitives/utility/src/tests/mod.rs +++ b/cumulus/primitives/utility/src/tests/mod.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/cumulus/primitives/utility/src/tests/swap_first.rs b/cumulus/primitives/utility/src/tests/swap_first.rs index 2e19db498816..69239c552b8c 100644 --- a/cumulus/primitives/utility/src/tests/swap_first.rs +++ b/cumulus/primitives/utility/src/tests/swap_first.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/cumulus/test/client/Cargo.toml b/cumulus/test/client/Cargo.toml index fbbaab73ce76..33023816c718 100644 --- a/cumulus/test/client/Cargo.toml +++ b/cumulus/test/client/Cargo.toml @@ -53,6 +53,7 @@ runtime-benchmarks = [ "cumulus-test-service/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "sc-service/runtime-benchmarks", diff --git a/cumulus/test/client/src/lib.rs b/cumulus/test/client/src/lib.rs index f26413e441e7..eaf81699f6d7 100644 --- a/cumulus/test/client/src/lib.rs +++ b/cumulus/test/client/src/lib.rs @@ -25,7 +25,7 @@ pub use polkadot_parachain_primitives::primitives::{ BlockData, HeadData, ValidationParams, ValidationResult, }; use runtime::{ - Balance, Block, BlockHashCount, Runtime, RuntimeCall, Signature, SignedExtra, SignedPayload, + Balance, Block, BlockHashCount, Runtime, RuntimeCall, Signature, SignedPayload, TxExtension, UncheckedExtrinsic, VERSION, }; use sc_consensus_aura::standalone::{seal, slot_author}; @@ -117,7 +117,7 @@ impl DefaultTestClientBuilderExt for TestClientBuilder { /// Create an unsigned extrinsic from a runtime call. pub fn generate_unsigned(function: impl Into) -> UncheckedExtrinsic { - UncheckedExtrinsic::new_unsigned(function.into()) + UncheckedExtrinsic::new_bare(function.into()) } /// Create a signed extrinsic from a runtime call and sign @@ -135,7 +135,7 @@ pub fn generate_extrinsic_with_pair( let period = BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64; let tip = 0; - let extra: SignedExtra = ( + let tx_ext: TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckGenesis::::new(), @@ -144,13 +144,14 @@ pub fn generate_extrinsic_with_pair( frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::::new(), - ); + ) + .into(); let function = function.into(); let raw_payload = SignedPayload::from_raw( function.clone(), - extra.clone(), + tx_ext.clone(), ((), VERSION.spec_version, genesis_block, current_block_hash, (), (), (), ()), ); let signature = raw_payload.using_encoded(|e| origin.sign(e)); @@ -159,7 +160,7 @@ pub fn generate_extrinsic_with_pair( function, origin.public().into(), Signature::Sr25519(signature), - extra, + tx_ext, ) } diff --git a/cumulus/test/runtime/build.rs b/cumulus/test/runtime/build.rs index bf579f4121e5..7a7fe8ffaa82 100644 --- a/cumulus/test/runtime/build.rs +++ b/cumulus/test/runtime/build.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Cumulus. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/cumulus/test/runtime/src/lib.rs b/cumulus/test/runtime/src/lib.rs index 274f16ab630d..5443bb5f526b 100644 --- a/cumulus/test/runtime/src/lib.rs +++ b/cumulus/test/runtime/src/lib.rs @@ -42,6 +42,7 @@ use sp_api::{decl_runtime_apis, impl_runtime_apis}; pub use sp_consensus_aura::sr25519::AuthorityId as AuraId; use sp_core::{ConstBool, ConstU32, ConstU64, OpaqueMetadata}; +use cumulus_primitives_core::{ClaimQueueOffset, CoreSelector}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{BlakeTwo256, Block as BlockT, IdentifyAccount, IdentityLookup, Verify}, @@ -132,7 +133,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, - state_version: 1, + system_version: 1, }; #[cfg(feature = "increment-spec-version")] @@ -146,7 +147,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, - state_version: 1, + system_version: 1, }; pub const EPOCH_DURATION_IN_BLOCKS: u32 = 10 * MINUTES; @@ -268,6 +269,7 @@ impl pallet_balances::Config for Runtime { type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxFreezes = ConstU32<0>; + type DoneSlashHandler = (); } impl pallet_transaction_payment::Config for Runtime { @@ -277,6 +279,7 @@ impl pallet_transaction_payment::Config for Runtime { type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = (); type OperationalFeeMultiplier = ConstU8<5>; + type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight; } impl pallet_sudo::Config for Runtime { @@ -311,6 +314,7 @@ impl cumulus_pallet_parachain_system::Config for Runtime { type CheckAssociatedRelayNumber = cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; type ConsensusHook = ConsensusHook; + type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector; } impl parachain_info::Config for Runtime {} @@ -368,8 +372,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckGenesis, @@ -381,7 +385,7 @@ pub type SignedExtra = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -392,7 +396,7 @@ pub type Executive = frame_executive::Executive< TestOnRuntimeUpgrade, >; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; pub struct TestOnRuntimeUpgrade; @@ -528,6 +532,12 @@ impl_runtime_apis! { } } + impl cumulus_primitives_core::GetCoreSelectorApi for Runtime { + fn core_selector() -> (CoreSelector, ClaimQueueOffset) { + ParachainSystem::core_selector() + } + } + impl sp_genesis_builder::GenesisBuilder for Runtime { fn build_state(config: Vec) -> sp_genesis_builder::Result { build_state::(config) diff --git a/cumulus/test/service/Cargo.toml b/cumulus/test/service/Cargo.toml index f766d1236320..3ef9424b9ed6 100644 --- a/cumulus/test/service/Cargo.toml +++ b/cumulus/test/service/Cargo.toml @@ -18,6 +18,7 @@ clap = { features = ["derive"], workspace = true } codec = { workspace = true, default-features = true } criterion = { features = ["async_tokio"], workspace = true, default-features = true } jsonrpsee = { features = ["server"], workspace = true } +prometheus = { workspace = true } rand = { workspace = true, default-features = true } serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } @@ -109,6 +110,7 @@ runtime-benchmarks = [ "cumulus-test-client/runtime-benchmarks", "frame-system/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "parachains-common/runtime-benchmarks", "polkadot-cli/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", diff --git a/cumulus/test/service/benches/validate_block_glutton.rs b/cumulus/test/service/benches/validate_block_glutton.rs index 6ec338c7f142..6fe26519a3eb 100644 --- a/cumulus/test/service/benches/validate_block_glutton.rs +++ b/cumulus/test/service/benches/validate_block_glutton.rs @@ -43,7 +43,7 @@ use sp_runtime::traits::Header as HeaderT; use cumulus_test_service::bench_utils as utils; async fn import_block( - mut client: &cumulus_test_client::Client, + client: &cumulus_test_client::Client, built: cumulus_test_runtime::Block, import_existing: bool, ) { diff --git a/cumulus/test/service/src/bench_utils.rs b/cumulus/test/service/src/bench_utils.rs index 4ace894b392a..76717b4136fa 100644 --- a/cumulus/test/service/src/bench_utils.rs +++ b/cumulus/test/service/src/bench_utils.rs @@ -68,12 +68,11 @@ pub fn extrinsic_set_time(client: &TestClient) -> OpaqueExtrinsic { let best_number = client.usage_info().chain.best_number; let timestamp = best_number as u64 * cumulus_test_runtime::MinimumPeriod::get(); - cumulus_test_runtime::UncheckedExtrinsic { - signature: None, - function: cumulus_test_runtime::RuntimeCall::Timestamp(pallet_timestamp::Call::set { + cumulus_test_runtime::UncheckedExtrinsic::new_bare( + cumulus_test_runtime::RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: timestamp, }), - } + ) .into() } @@ -101,17 +100,16 @@ pub fn extrinsic_set_validation_data( horizontal_messages: Default::default(), }; - cumulus_test_runtime::UncheckedExtrinsic { - signature: None, - function: cumulus_test_runtime::RuntimeCall::ParachainSystem( + cumulus_test_runtime::UncheckedExtrinsic::new_bare( + cumulus_test_runtime::RuntimeCall::ParachainSystem( cumulus_pallet_parachain_system::Call::set_validation_data { data }, ), - } + ) .into() } /// Import block into the given client and make sure the import was successful -pub async fn import_block(mut client: &TestClient, block: &NodeBlock, import_existing: bool) { +pub async fn import_block(client: &TestClient, block: &NodeBlock, import_existing: bool) { let mut params = BlockImportParams::new(BlockOrigin::File, block.header.clone()); params.body = Some(block.extrinsics.clone()); params.state_action = StateAction::Execute; diff --git a/cumulus/test/service/src/chain_spec.rs b/cumulus/test/service/src/chain_spec.rs index ae71028ad486..3abffcff794f 100644 --- a/cumulus/test/service/src/chain_spec.rs +++ b/cumulus/test/service/src/chain_spec.rs @@ -17,24 +17,16 @@ #![allow(missing_docs)] use cumulus_primitives_core::ParaId; -use cumulus_test_runtime::{AccountId, Signature}; +use cumulus_test_runtime::AccountId; use parachains_common::AuraId; use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup}; use sc_service::ChainType; use serde::{Deserialize, Serialize}; -use sp_core::{sr25519, Pair, Public}; -use sp_runtime::traits::{IdentifyAccount, Verify}; +use sp_keyring::Sr25519Keyring; /// Specialized `ChainSpec` for the normal parachain runtime. pub type ChainSpec = sc_service::GenericChainSpec; -/// Helper function to generate a crypto pair from seed -pub fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() -} - /// The extensions for the [`ChainSpec`]. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)] #[serde(deny_unknown_fields)] @@ -50,16 +42,6 @@ impl Extensions { } } -type AccountPublic = ::Signer; - -/// Helper function to generate an account ID from seed. -pub fn get_account_id_from_seed(seed: &str) -> AccountId -where - AccountPublic: From<::Public>, -{ - AccountPublic::from(get_from_seed::(seed)).into_account() -} - /// Get the chain spec for a specific parachain ID. /// The given accounts are initialized with funds in addition /// to the default known accounts. @@ -106,42 +88,11 @@ pub fn testnet_genesis_with_default_endowed( mut extra_endowed_accounts: Vec, self_para_id: Option, ) -> serde_json::Value { - let mut endowed = vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ]; + let mut endowed = Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect::>(); endowed.append(&mut extra_endowed_accounts); - let invulnerables = vec![ - get_collator_keys_from_seed::("Alice"), - get_collator_keys_from_seed::("Bob"), - get_collator_keys_from_seed::("Charlie"), - get_collator_keys_from_seed::("Dave"), - get_collator_keys_from_seed::("Eve"), - get_collator_keys_from_seed::("Ferdie"), - ]; - testnet_genesis( - get_account_id_from_seed::("Alice"), - invulnerables, - endowed, - self_para_id, - ) -} - -/// Generate collator keys from seed. -/// -/// This function's return type must always match the session keys of the chain in tuple format. -pub fn get_collator_keys_from_seed(seed: &str) -> ::Public { - get_from_seed::(seed) + let invulnerables = + Sr25519Keyring::invulnerable().map(|k| k.public().into()).collect::>(); + testnet_genesis(Sr25519Keyring::Alice.to_account_id(), invulnerables, endowed, self_para_id) } /// Creates a local testnet genesis with endowed accounts. diff --git a/cumulus/test/service/src/cli.rs b/cumulus/test/service/src/cli.rs index 37ca27542cbf..220b0449f339 100644 --- a/cumulus/test/service/src/cli.rs +++ b/cumulus/test/service/src/cli.rs @@ -14,13 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use std::{net::SocketAddr, path::PathBuf}; +use std::path::PathBuf; use cumulus_client_cli::{ExportGenesisHeadCommand, ExportGenesisWasmCommand}; use polkadot_service::{ChainSpec, ParaId, PrometheusConfig}; use sc_cli::{ CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams, NetworkParams, - Result as CliResult, SharedParams, SubstrateCli, + Result as CliResult, RpcEndpoint, SharedParams, SubstrateCli, }; use sc_service::BasePath; @@ -122,7 +122,7 @@ impl CliConfiguration for RelayChainCli { .or_else(|| self.base_path.clone().map(Into::into))) } - fn rpc_addr(&self, default_listen_port: u16) -> CliResult> { + fn rpc_addr(&self, default_listen_port: u16) -> CliResult>> { self.base.base.rpc_addr(default_listen_port) } @@ -139,10 +139,9 @@ impl CliConfiguration for RelayChainCli { _support_url: &String, _impl_version: &String, _logger_hook: F, - _config: &sc_service::Configuration, ) -> CliResult<()> where - F: FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration), + F: FnOnce(&mut sc_cli::LoggerBuilder), { unreachable!("PolkadotCli is never initialized; qed"); } diff --git a/cumulus/test/service/src/lib.rs b/cumulus/test/service/src/lib.rs index 51cdebbaf54e..a3e519a68b91 100644 --- a/cumulus/test/service/src/lib.rs +++ b/cumulus/test/service/src/lib.rs @@ -32,13 +32,14 @@ use cumulus_client_consensus_aura::{ ImportQueueParams, }; use cumulus_client_consensus_proposer::Proposer; +use prometheus::Registry; use runtime::AccountId; use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY}; use sp_consensus_aura::sr25519::AuthorityPair; use std::{ collections::HashSet, future::Future, - net::{IpAddr, Ipv4Addr, SocketAddr}, + net::{Ipv4Addr, SocketAddr, SocketAddrV4}, time::Duration, }; use url::Url; @@ -78,8 +79,9 @@ use sc_network::{ }; use sc_service::{ config::{ - BlocksPruning, DatabaseSource, KeystoreConfig, MultiaddrWithPeerId, NetworkConfiguration, - OffchainWorkerConfig, PruningMode, RpcBatchRequestConfig, WasmExecutionMethod, + BlocksPruning, DatabaseSource, ExecutorConfiguration, KeystoreConfig, MultiaddrWithPeerId, + NetworkConfiguration, OffchainWorkerConfig, PruningMode, RpcBatchRequestConfig, + RpcConfiguration, RpcEndpoint, WasmExecutionMethod, }, BasePath, ChainSpec as ChainSpecService, Configuration, Error as ServiceError, PartialComponents, Role, RpcHandlers, TFullBackend, TFullClient, TaskManager, @@ -132,7 +134,7 @@ pub type Backend = TFullBackend; pub type ParachainBlockImport = TParachainBlockImport, Backend>; /// Transaction pool type used by the test service -pub type TransactionPool = Arc>; +pub type TransactionPool = Arc>; /// Recovery handle that fails regularly to simulate unavailable povs. pub struct FailingRecoveryHandle { @@ -181,7 +183,7 @@ pub type Service = PartialComponents< Backend, (), sc_consensus::import_queue::BasicQueue, - sc_transaction_pool::FullPool, + sc_transaction_pool::TransactionPoolHandle, ParachainBlockImport, >; @@ -194,15 +196,16 @@ pub fn new_partial( enable_import_proof_record: bool, ) -> Result { let heap_pages = config + .executor .default_heap_pages .map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| HeapAllocStrategy::Static { extra_pages: h as _ }); let executor = WasmExecutor::builder() - .with_execution_method(config.wasm_method) + .with_execution_method(config.executor.wasm_method) .with_onchain_heap_alloc_strategy(heap_pages) .with_offchain_heap_alloc_strategy(heap_pages) - .with_max_runtime_instances(config.max_runtime_instances) - .with_runtime_cache_size(config.runtime_cache_size) + .with_max_runtime_instances(config.executor.max_runtime_instances) + .with_runtime_cache_size(config.executor.runtime_cache_size) .build(); let (client, backend, keystore_container, task_manager) = @@ -216,12 +219,15 @@ pub fn new_partial( let block_import = ParachainBlockImport::new(client.clone(), backend.clone()); - let transaction_pool = sc_transaction_pool::BasicPool::new_full( - config.transaction_pool.clone(), - config.role.is_authority().into(), - config.prometheus_registry(), - task_manager.spawn_essential_handle(), - client.clone(), + let transaction_pool = Arc::from( + sc_transaction_pool::Builder::new( + task_manager.spawn_essential_handle(), + client.clone(), + config.role.is_authority().into(), + ) + .with_options(config.transaction_pool.clone()) + .with_prometheus(config.prometheus_registry()) + .build(), ); let slot_duration = sc_consensus_aura::slot_duration(&*client)?; @@ -262,11 +268,12 @@ pub fn new_partial( async fn build_relay_chain_interface( relay_chain_config: Configuration, + parachain_prometheus_registry: Option<&Registry>, collator_key: Option, collator_options: CollatorOptions, task_manager: &mut TaskManager, ) -> RelayChainResult> { - let relay_chain_full_node = match collator_options.relay_chain_mode { + let relay_chain_node = match collator_options.relay_chain_mode { cumulus_client_cli::RelayChainMode::Embedded => polkadot_test_service::new_full( relay_chain_config, if let Some(ref key) = collator_key { @@ -281,6 +288,7 @@ async fn build_relay_chain_interface( cumulus_client_cli::RelayChainMode::ExternalRpc(rpc_target_urls) => return build_minimal_relay_chain_node_with_rpc( relay_chain_config, + parachain_prometheus_registry, task_manager, rpc_target_urls, ) @@ -292,13 +300,13 @@ async fn build_relay_chain_interface( .map(|r| r.0), }; - task_manager.add_child(relay_chain_full_node.task_manager); + task_manager.add_child(relay_chain_node.task_manager); tracing::info!("Using inprocess node."); Ok(Arc::new(RelayChainInProcessInterface::new( - relay_chain_full_node.client.clone(), - relay_chain_full_node.backend.clone(), - relay_chain_full_node.sync_service.clone(), - relay_chain_full_node.overseer_handle.ok_or(RelayChainError::GenericError( + relay_chain_node.client.clone(), + relay_chain_node.backend.clone(), + relay_chain_node.sync_service.clone(), + relay_chain_node.overseer_handle.ok_or(RelayChainError::GenericError( "Overseer should be running in full node.".to_string(), ))?, ))) @@ -342,9 +350,9 @@ where let backend = params.backend.clone(); let block_import = params.other; - let relay_chain_interface = build_relay_chain_interface( relay_chain_config, + parachain_config.prometheus_registry(), collator_key.clone(), collator_options.clone(), &mut task_manager, @@ -353,7 +361,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,12 +384,10 @@ where }) .await?; - let prometheus_registry = parachain_config.prometheus_registry().cloned(); - let keystore = params.keystore_container.keystore(); let rpc_builder = { let client = client.clone(); - Box::new(move |_, _| rpc_ext_builder(client.clone())) + Box::new(move |_| rpc_ext_builder(client.clone())) }; let rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams { @@ -482,7 +492,6 @@ where keystore, collator_key, para_id, - relay_chain_slot_duration, proposer, collator_service, authoring_duration: Duration::from_millis(2000), @@ -490,7 +499,7 @@ where slot_drift: Duration::from_secs(1), }; - let (collation_future, block_builer_future) = + let (collation_future, block_builder_future) = slot_based::run::(params); task_manager.spawn_essential_handle().spawn( "collation-task", @@ -500,7 +509,7 @@ where task_manager.spawn_essential_handle().spawn( "block-builder-task", None, - block_builer_future, + block_builder_future, ); } else { tracing::info!(target: LOG_TARGET, "Starting block authoring with lookahead collator."); @@ -861,39 +870,41 @@ pub fn node_config( state_pruning: Some(PruningMode::ArchiveAll), blocks_pruning: BlocksPruning::KeepAll, chain_spec: spec, - wasm_method: WasmExecutionMethod::Compiled { - instantiation_strategy: sc_executor_wasmtime::InstantiationStrategy::PoolingCopyOnWrite, + executor: ExecutorConfiguration { + wasm_method: WasmExecutionMethod::Compiled { + instantiation_strategy: + sc_executor_wasmtime::InstantiationStrategy::PoolingCopyOnWrite, + }, + ..ExecutorConfiguration::default() + }, + rpc: RpcConfiguration { + addr: None, + max_connections: Default::default(), + cors: None, + methods: Default::default(), + max_request_size: Default::default(), + max_response_size: Default::default(), + id_provider: None, + max_subs_per_conn: Default::default(), + port: 9945, + message_buffer_capacity: Default::default(), + batch_config: RpcBatchRequestConfig::Unlimited, + rate_limit: None, + rate_limit_whitelisted_ips: Default::default(), + rate_limit_trust_proxy_headers: Default::default(), }, - rpc_addr: None, - rpc_max_connections: Default::default(), - rpc_cors: None, - rpc_methods: Default::default(), - rpc_max_request_size: Default::default(), - rpc_max_response_size: Default::default(), - rpc_id_provider: None, - rpc_max_subs_per_conn: Default::default(), - rpc_port: 9945, - rpc_message_buffer_capacity: Default::default(), - rpc_batch_config: RpcBatchRequestConfig::Unlimited, - rpc_rate_limit: None, - rpc_rate_limit_whitelisted_ips: Default::default(), - rpc_rate_limit_trust_proxy_headers: Default::default(), prometheus_config: None, telemetry_endpoints: None, - default_heap_pages: None, offchain_worker: OffchainWorkerConfig { enabled: true, indexing_enabled: false }, force_authoring: false, disable_grandpa: false, dev_key_seed: Some(key_seed), tracing_targets: None, tracing_receiver: Default::default(), - max_runtime_instances: 8, announce_block: true, data_path: root, base_path, - informant_output_format: Default::default(), wasm_runtime_overrides: None, - runtime_cache_size: 2, }) } @@ -958,7 +969,7 @@ pub fn construct_extrinsic( .map(|c| c / 2) .unwrap_or(2) as u64; let tip = 0; - let extra: runtime::SignedExtra = ( + let tx_ext: runtime::TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckGenesis::::new(), @@ -970,10 +981,11 @@ pub fn construct_extrinsic( frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim::::new(), - ); + ) + .into(); let raw_payload = runtime::SignedPayload::from_raw( function.clone(), - extra.clone(), + tx_ext.clone(), ((), runtime::VERSION.spec_version, genesis_block, current_block_hash, (), (), (), ()), ); let signature = raw_payload.using_encoded(|e| caller.sign(e)); @@ -981,7 +993,7 @@ pub fn construct_extrinsic( function, caller.public().into(), runtime::Signature::Sr25519(signature), - extra, + tx_ext, ) } @@ -1005,7 +1017,22 @@ pub fn run_relay_chain_validator_node( ); if let Some(port) = port { - config.rpc_addr = Some(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port)); + config.rpc.addr = Some(vec![RpcEndpoint { + batch_config: config.rpc.batch_config, + cors: config.rpc.cors.clone(), + listen_addr: SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::LOCALHOST, port)), + max_connections: config.rpc.max_connections, + max_payload_in_mb: config.rpc.max_request_size, + max_payload_out_mb: config.rpc.max_response_size, + max_subscriptions_per_connection: config.rpc.max_subs_per_conn, + max_buffer_capacity_per_connection: config.rpc.message_buffer_capacity, + rpc_methods: config.rpc.methods, + rate_limit: config.rpc.rate_limit, + rate_limit_trust_proxy_headers: config.rpc.rate_limit_trust_proxy_headers, + rate_limit_whitelisted_ips: config.rpc.rate_limit_whitelisted_ips.clone(), + retry_random_port: true, + is_optional: false, + }]); } let mut workers_path = std::env::current_exe().unwrap(); diff --git a/cumulus/test/service/src/main.rs b/cumulus/test/service/src/main.rs index 9357978b769a..caa672e611f7 100644 --- a/cumulus/test/service/src/main.rs +++ b/cumulus/test/service/src/main.rs @@ -61,36 +61,39 @@ fn main() -> Result<(), sc_cli::Error> { let collator_options = cli.run.collator_options(); let tokio_runtime = sc_cli::build_runtime()?; let tokio_handle = tokio_runtime.handle(); - let config = cli + let parachain_config = cli .run .normalize() .create_configuration(&cli, tokio_handle.clone()) .expect("Should be able to generate config"); - let polkadot_cli = RelayChainCli::new( - &config, + let relay_chain_cli = RelayChainCli::new( + ¶chain_config, [RelayChainCli::executable_name()].iter().chain(cli.relaychain_args.iter()), ); - - let tokio_handle = config.tokio_handle.clone(); - let polkadot_config = - SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle) - .map_err(|err| format!("Relay chain argument error: {}", err))?; - - let parachain_id = chain_spec::Extensions::try_get(&*config.chain_spec) + let tokio_handle = parachain_config.tokio_handle.clone(); + let relay_chain_config = SubstrateCli::create_configuration( + &relay_chain_cli, + &relay_chain_cli, + tokio_handle, + ) + .map_err(|err| format!("Relay chain argument error: {}", err))?; + + let parachain_id = chain_spec::Extensions::try_get(&*parachain_config.chain_spec) .map(|e| e.para_id) .ok_or("Could not find parachain extension in chain-spec.")?; tracing::info!("Parachain id: {:?}", parachain_id); tracing::info!( "Is collating: {}", - if config.role.is_authority() { "yes" } else { "no" } + if parachain_config.role.is_authority() { "yes" } else { "no" } ); if cli.fail_pov_recovery { tracing::info!("PoV recovery failure enabled"); } - let collator_key = config.role.is_authority().then(|| CollatorPair::generate().0); + let collator_key = + parachain_config.role.is_authority().then(|| CollatorPair::generate().0); let consensus = cli .use_null_consensus @@ -102,15 +105,15 @@ fn main() -> Result<(), sc_cli::Error> { let (mut task_manager, _, _, _, _, _) = tokio_runtime .block_on(async move { - match polkadot_config.network.network_backend { + match relay_chain_config.network.network_backend { sc_network::config::NetworkBackendType::Libp2p => cumulus_test_service::start_node_impl::< _, sc_network::NetworkWorker<_, _>, >( - config, + parachain_config, collator_key, - polkadot_config, + relay_chain_config, parachain_id.into(), cli.disable_block_announcements.then(wrap_announce_block), cli.fail_pov_recovery, @@ -126,9 +129,9 @@ fn main() -> Result<(), sc_cli::Error> { _, sc_network::Litep2pNetworkBackend, >( - config, + parachain_config, collator_key, - polkadot_config, + relay_chain_config, parachain_id.into(), cli.disable_block_announcements.then(wrap_announce_block), cli.fail_pov_recovery, diff --git a/cumulus/xcm/xcm-emulator/Cargo.toml b/cumulus/xcm/xcm-emulator/Cargo.toml index ba1097fba075..8598481fae76 100644 --- a/cumulus/xcm/xcm-emulator/Cargo.toml +++ b/cumulus/xcm/xcm-emulator/Cargo.toml @@ -13,8 +13,8 @@ workspace = true codec = { workspace = true, default-features = true } paste = { workspace = true, default-features = true } log = { workspace = true } -lazy_static = { workspace = true } impl-trait-for-tuples = { workspace = true } +array-bytes = { workspace = true } # Substrate frame-support = { workspace = true, default-features = true } diff --git a/cumulus/xcm/xcm-emulator/src/lib.rs b/cumulus/xcm/xcm-emulator/src/lib.rs index 8de3660c2236..b91246a7bda2 100644 --- a/cumulus/xcm/xcm-emulator/src/lib.rs +++ b/cumulus/xcm/xcm-emulator/src/lib.rs @@ -1,28 +1,33 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Polkadot. +// This file is part of Cumulus. -// Polkadot is free software: you can redistribute it and/or modify +// 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. -// Polkadot is distributed in the hope that it will be useful, +// 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 Polkadot. If not, see . +// along with Cumulus. If not, see . extern crate alloc; +pub use array_bytes; pub use codec::{Decode, Encode, EncodeLike, MaxEncodedLen}; -pub use lazy_static::lazy_static; pub use log; pub use paste; pub use std::{ - any::type_name, collections::HashMap, error::Error, fmt, marker::PhantomData, ops::Deref, - sync::Mutex, + any::type_name, + collections::HashMap, + error::Error, + fmt, + marker::PhantomData, + ops::Deref, + sync::{LazyLock, Mutex}, }; // Substrate @@ -44,7 +49,9 @@ pub use frame_system::{ pub use pallet_balances::AccountData; pub use pallet_message_queue; pub use sp_arithmetic::traits::Bounded; -pub use sp_core::{parameter_types, sr25519, storage::Storage, Pair}; +pub use sp_core::{ + crypto::get_public_from_string_or_panic, parameter_types, sr25519, storage::Storage, Pair, +}; pub use sp_crypto_hashing::blake2_256; pub use sp_io::TestExternalities; pub use sp_runtime::BoundedSlice; @@ -221,7 +228,7 @@ pub trait Chain: TestExt { type OriginCaller; fn account_id_of(seed: &str) -> AccountId { - helpers::get_account_id_from_seed::(seed) + get_public_from_string_or_panic::(seed).into() } fn account_data_of(account: AccountIdOf) -> AccountData; @@ -296,9 +303,11 @@ impl Bridge for () { fn init() {} } +pub type BridgeLaneId = Vec; + #[derive(Clone, Default, Debug)] pub struct BridgeMessage { - pub id: u32, + pub lane_id: BridgeLaneId, pub nonce: u64, pub payload: Vec, } @@ -310,7 +319,7 @@ pub trait BridgeMessageHandler { message: BridgeMessage, ) -> Result<(), BridgeMessageDispatchError>; - fn notify_source_message_delivery(lane_id: u32); + fn notify_source_message_delivery(lane_id: BridgeLaneId); } impl BridgeMessageHandler for () { @@ -324,7 +333,7 @@ impl BridgeMessageHandler for () { Err(BridgeMessageDispatchError(Box::new("Not a bridge"))) } - fn notify_source_message_delivery(_lane_id: u32) {} + fn notify_source_message_delivery(_lane_id: BridgeLaneId) {} } #[derive(Debug)] @@ -440,10 +449,8 @@ macro_rules! __impl_test_ext_for_relay_chain { = $crate::RefCell::new($crate::TestExternalities::new($genesis)); } - $crate::lazy_static! { - pub static ref $global_ext: $crate::Mutex<$crate::RefCell<$crate::HashMap>> - = $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new())); - } + pub static $global_ext: $crate::LazyLock<$crate::Mutex<$crate::RefCell<$crate::HashMap>>> + = $crate::LazyLock::new(|| $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new()))); impl<$network: $crate::Network> $crate::TestExt for $name<$network> { fn build_new_ext(storage: $crate::Storage) -> $crate::TestExternalities { @@ -475,10 +482,10 @@ macro_rules! __impl_test_ext_for_relay_chain { v.take() }); - // Get TestExternality from lazy_static + // Get TestExternality from LazyLock let global_ext_guard = $global_ext.lock().unwrap(); - // Replace TestExternality in lazy_static by TestExternality from thread_local + // Replace TestExternality in LazyLock by TestExternality from thread_local global_ext_guard.deref().borrow_mut().insert(id.to_string(), local_ext); } @@ -487,10 +494,10 @@ macro_rules! __impl_test_ext_for_relay_chain { let mut global_ext_unlocked = false; - // Keep the mutex unlocked until TesExternality from lazy_static + // Keep the mutex unlocked until TesExternality from LazyLock // has been updated while !global_ext_unlocked { - // Get TesExternality from lazy_static + // Get TesExternality from LazyLock let global_ext_result = $global_ext.try_lock(); if let Ok(global_ext_guard) = global_ext_result { @@ -503,10 +510,10 @@ macro_rules! __impl_test_ext_for_relay_chain { } } - // Now that we know that lazy_static TestExt has been updated, we lock its mutex + // Now that we know that TestExt has been updated, we lock its mutex let mut global_ext_guard = $global_ext.lock().unwrap(); - // and set TesExternality from lazy_static into TesExternality for local_thread + // and set TesExternality from LazyLock into TesExternality for local_thread let global_ext = global_ext_guard.deref(); $local_ext.with(|v| { @@ -524,7 +531,10 @@ macro_rules! __impl_test_ext_for_relay_chain { <$network>::init(); // Execute - let r = $local_ext.with(|v| v.borrow_mut().execute_with(execute)); + let r = $local_ext.with(|v| { + $crate::log::info!(target: "xcm::emulator::execute_with", "Executing as {}", stringify!($name)); + v.borrow_mut().execute_with(execute) + }); // Send messages if needed $local_ext.with(|v| { @@ -548,7 +558,7 @@ macro_rules! __impl_test_ext_for_relay_chain { // log events Self::events().iter().for_each(|event| { - $crate::log::debug!(target: concat!("events::", stringify!($name)), "{:?}", event); + $crate::log::info!(target: concat!("events::", stringify!($name)), "{:?}", event); }); // clean events @@ -738,10 +748,8 @@ macro_rules! __impl_test_ext_for_parachain { = $crate::RefCell::new($crate::TestExternalities::new($genesis)); } - $crate::lazy_static! { - pub static ref $global_ext: $crate::Mutex<$crate::RefCell<$crate::HashMap>> - = $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new())); - } + pub static $global_ext: $crate::LazyLock<$crate::Mutex<$crate::RefCell<$crate::HashMap>>> + = $crate::LazyLock::new(|| $crate::Mutex::new($crate::RefCell::new($crate::HashMap::new()))); impl<$network: $crate::Network> $crate::TestExt for $name<$network> { fn build_new_ext(storage: $crate::Storage) -> $crate::TestExternalities { @@ -771,10 +779,10 @@ macro_rules! __impl_test_ext_for_parachain { v.take() }); - // Get TestExternality from lazy_static + // Get TestExternality from LazyLock let global_ext_guard = $global_ext.lock().unwrap(); - // Replace TestExternality in lazy_static by TestExternality from thread_local + // Replace TestExternality in LazyLock by TestExternality from thread_local global_ext_guard.deref().borrow_mut().insert(id.to_string(), local_ext); } @@ -783,10 +791,10 @@ macro_rules! __impl_test_ext_for_parachain { let mut global_ext_unlocked = false; - // Keep the mutex unlocked until TesExternality from lazy_static + // Keep the mutex unlocked until TesExternality from LazyLock // has been updated while !global_ext_unlocked { - // Get TesExternality from lazy_static + // Get TesExternality from LazyLock let global_ext_result = $global_ext.try_lock(); if let Ok(global_ext_guard) = global_ext_result { @@ -799,10 +807,10 @@ macro_rules! __impl_test_ext_for_parachain { } } - // Now that we know that lazy_static TestExt has been updated, we lock its mutex + // Now that we know that TestExt has been updated, we lock its mutex let mut global_ext_guard = $global_ext.lock().unwrap(); - // and set TesExternality from lazy_static into TesExternality for local_thread + // and set TesExternality from LazyLock into TesExternality for local_thread let global_ext = global_ext_guard.deref(); $local_ext.with(|v| { @@ -824,7 +832,10 @@ macro_rules! __impl_test_ext_for_parachain { Self::new_block(); // Execute - let r = $local_ext.with(|v| v.borrow_mut().execute_with(execute)); + let r = $local_ext.with(|v| { + $crate::log::info!(target: "xcm::emulator::execute_with", "Executing as {}", stringify!($name)); + v.borrow_mut().execute_with(execute) + }); // Finalize the block Self::finalize_block(); @@ -870,7 +881,7 @@ macro_rules! __impl_test_ext_for_parachain { // log events ::events().iter().for_each(|event| { - $crate::log::debug!(target: concat!("events::", stringify!($name)), "{:?}", event); + $crate::log::info!(target: concat!("events::", stringify!($name)), "{:?}", event); }); // clean events @@ -1022,7 +1033,10 @@ macro_rules! decl_test_networks { &mut msg.using_encoded($crate::blake2_256), ); }); - $crate::log::debug!(target: concat!("dmp::", stringify!($name)) , "DMP messages processed {:?} to para_id {:?}", msgs.clone(), &to_para_id); + let messages = msgs.clone().iter().map(|(block, message)| { + (*block, $crate::array_bytes::bytes2hex("0x", message)) + }).collect::>(); + $crate::log::info!(target: concat!("xcm::dmp::", stringify!($name)) , "Downward messages processed by para_id {:?}: {:?}", &to_para_id, messages); $crate::DMP_DONE.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().push_back((to_para_id, block, msg))); } } @@ -1035,7 +1049,7 @@ macro_rules! decl_test_networks { while let Some((to_para_id, messages)) = $crate::HORIZONTAL_MESSAGES.with(|b| b.borrow_mut().get_mut(Self::name()).unwrap().pop_front()) { - let iter = messages.iter().map(|(p, b, m)| (*p, *b, &m[..])).collect::>().into_iter(); + let iter = messages.iter().map(|(para_id, relay_block_number, message)| (*para_id, *relay_block_number, &message[..])).collect::>().into_iter(); $( let para_id: u32 = <$parachain>::para_id().into(); @@ -1045,7 +1059,10 @@ macro_rules! decl_test_networks { // Nudge the MQ pallet to process immediately instead of in the next block. let _ = <$parachain as Parachain>::MessageProcessor::service_queues($crate::Weight::MAX); }); - $crate::log::debug!(target: concat!("hrmp::", stringify!($name)) , "HRMP messages processed {:?} to para_id {:?}", &messages, &to_para_id); + let messages = messages.clone().iter().map(|(para_id, relay_block_number, message)| { + (*para_id, *relay_block_number, $crate::array_bytes::bytes2hex("0x", message)) + }).collect::>(); + $crate::log::info!(target: concat!("xcm::hrmp::", stringify!($name)), "Horizontal messages processed by para_id {:?}: {:?}", &to_para_id, &messages); } )* } @@ -1064,7 +1081,8 @@ macro_rules! decl_test_networks { &mut msg.using_encoded($crate::blake2_256), ); }); - $crate::log::debug!(target: concat!("ump::", stringify!($name)) , "Upward message processed {:?} from para_id {:?}", &msg, &from_para_id); + let message = $crate::array_bytes::bytes2hex("0x", msg.clone()); + $crate::log::info!(target: concat!("xcm::ump::", stringify!($name)) , "Upward message processed from para_id {:?}: {:?}", &from_para_id, &message); } } @@ -1079,12 +1097,12 @@ macro_rules! decl_test_networks { }); match dispatch_result { - Err(e) => panic!("Error {:?} processing bridged message: {:?}", e, msg.clone()), + Err(e) => panic!("Error {:?} processing bridged message: {:?}", e, msg), Ok(()) => { <::Source as TestExt>::ext_wrapper(|| { - <::Handler as BridgeMessageHandler>::notify_source_message_delivery(msg.id); + <::Handler as BridgeMessageHandler>::notify_source_message_delivery(msg.lane_id.clone()); }); - $crate::log::debug!(target: concat!("bridge::", stringify!($name)) , "Bridged message processed {:?}", msg.clone()); + $crate::log::info!(target: concat!("bridge::", stringify!($name)) , "Bridged message processed {:?}", msg); } } } @@ -1295,7 +1313,7 @@ macro_rules! assert_expected_events { if !message.is_empty() { // Log events as they will not be logged after the panic <$chain as $crate::Chain>::events().iter().for_each(|event| { - $crate::log::debug!(target: concat!("events::", stringify!($chain)), "{:?}", event); + $crate::log::info!(target: concat!("events::", stringify!($chain)), "{:?}", event); }); panic!("{}", message.concat()) } @@ -1592,17 +1610,4 @@ pub mod helpers { ref_time_within && proof_size_within } - - /// Helper function to generate an account ID from seed. - pub fn get_account_id_from_seed(seed: &str) -> AccountId - where - sp_runtime::MultiSigner: - From<<::Pair as sp_core::Pair>::Public>, - { - use sp_runtime::traits::IdentifyAccount; - let pubkey = TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public(); - sp_runtime::MultiSigner::from(pubkey).into_account() - } } diff --git a/cumulus/zombienet/tests/0008-main.js b/cumulus/zombienet/tests/0008-main.js new file mode 100644 index 000000000000..31c01324a77e --- /dev/null +++ b/cumulus/zombienet/tests/0008-main.js @@ -0,0 +1,18 @@ +// Allows to manually submit extrinsic to collator. +// Usage: +// zombienet-linux -p native spwan 0008-parachain-extrinsic-gets-finalized.toml +// node 0008-main.js + +global.zombie = null + +const fs = require('fs'); +const test = require('./0008-transaction_gets_finalized.js'); + +if (process.argv.length == 2) { + console.error('Path to zombie.json (generated by zombienet-linux spawn command shall be given)!'); + process.exit(1); +} + +let networkInfo = JSON.parse(fs.readFileSync(process.argv[2])); + +test.run("charlie", networkInfo).then(process.exit) diff --git a/cumulus/zombienet/tests/0008-parachain_extrinsic_gets_finalized.toml b/cumulus/zombienet/tests/0008-parachain_extrinsic_gets_finalized.toml new file mode 100644 index 000000000000..a295d3960bfe --- /dev/null +++ b/cumulus/zombienet/tests/0008-parachain_extrinsic_gets_finalized.toml @@ -0,0 +1,25 @@ +[relaychain] +default_image = "{{RELAY_IMAGE}}" +default_command = "polkadot" +chain = "rococo-local" + + [[relaychain.nodes]] + name = "alice" + validator = true + + [[relaychain.nodes]] + name = "bob" + validator = true + +[[parachains]] +id = 2000 +cumulus_based = true +chain = "asset-hub-rococo-local" + + # run charlie as parachain collator + [[parachains.collators]] + name = "charlie" + validator = true + image = "{{POLKADOT_PARACHAIN_IMAGE}}" + command = "polkadot-parachain" + args = ["--force-authoring", "-ltxpool=trace", "--pool-type=fork-aware"] diff --git a/cumulus/zombienet/tests/0008-parachain_extrinsic_gets_finalized.zndsl b/cumulus/zombienet/tests/0008-parachain_extrinsic_gets_finalized.zndsl new file mode 100644 index 000000000000..5aab1bd923a5 --- /dev/null +++ b/cumulus/zombienet/tests/0008-parachain_extrinsic_gets_finalized.zndsl @@ -0,0 +1,20 @@ +Description: Block building +Network: ./0008-parachain_extrinsic_gets_finalized.toml +Creds: config + +alice: reports node_roles is 4 +bob: reports node_roles is 4 +charlie: reports node_roles is 4 + +alice: reports peers count is at least 1 +bob: reports peers count is at least 1 + +alice: reports block height is at least 5 within 60 seconds +bob: reports block height is at least 5 within 60 seconds +charlie: reports block height is at least 2 within 120 seconds + +alice: count of log lines containing "error" is 0 within 2 seconds +bob: count of log lines containing "error" is 0 within 2 seconds +charlie: count of log lines containing "error" is 0 within 2 seconds + +charlie: js-script ./0008-transaction_gets_finalized.js within 600 seconds diff --git a/cumulus/zombienet/tests/0008-transaction_gets_finalized.js b/cumulus/zombienet/tests/0008-transaction_gets_finalized.js new file mode 100644 index 000000000000..3031c45e3a4b --- /dev/null +++ b/cumulus/zombienet/tests/0008-transaction_gets_finalized.js @@ -0,0 +1,69 @@ +//based on: https://polkadot.js.org/docs/api/examples/promise/transfer-events + +const assert = require("assert"); + +async function run(nodeName, networkInfo, args) { + const {wsUri, userDefinedTypes} = networkInfo.nodesByName[nodeName]; + // Create the API and wait until ready + var api = null; + var keyring = null; + if (zombie == null) { + const testKeyring = require('@polkadot/keyring/testing'); + const { WsProvider, ApiPromise } = require('@polkadot/api'); + const provider = new WsProvider(wsUri); + api = await ApiPromise.create({provider}); + // Construct the keyring after the API (crypto has an async init) + keyring = testKeyring.createTestKeyring({ type: "sr25519" }); + } else { + keyring = new zombie.Keyring({ type: "sr25519" }); + api = await zombie.connect(wsUri, userDefinedTypes); + } + + + // Add Alice to our keyring with a hard-derivation path (empty phrase, so uses dev) + const alice = keyring.addFromUri('//Alice'); + + // Create an extrinsic: + const extrinsic = api.tx.system.remark("xxx"); + + let extrinsic_success_event = false; + try { + await new Promise( async (resolve, reject) => { + const unsubscribe = await extrinsic + .signAndSend(alice, { nonce: -1 }, ({ events = [], status }) => { + console.log('Extrinsic status:', status.type); + + if (status.isInBlock) { + console.log('Included at block hash', status.asInBlock.toHex()); + console.log('Events:'); + + events.forEach(({ event: { data, method, section }, phase }) => { + console.log('\t', phase.toString(), `: ${section}.${method}`, data.toString()); + + if (section=="system" && method =="ExtrinsicSuccess") { + extrinsic_success_event = true; + } + }); + } else if (status.isFinalized) { + console.log('Finalized block hash', status.asFinalized.toHex()); + unsubscribe(); + if (extrinsic_success_event) { + resolve(); + } else { + reject("ExtrinsicSuccess has not been seen"); + } + } else if (status.isError) { + unsubscribe(); + reject("Extrinsic status.isError"); + } + + }); + }); + } catch (error) { + assert.fail("Transfer promise failed, error: " + error); + } + + assert.ok("test passed"); +} + +module.exports = { run } diff --git a/cumulus/zombienet/tests/0009-elastic_pov_recovery.toml b/cumulus/zombienet/tests/0009-elastic_pov_recovery.toml index b695f8aa9376..1cf0775a2e17 100644 --- a/cumulus/zombienet/tests/0009-elastic_pov_recovery.toml +++ b/cumulus/zombienet/tests/0009-elastic_pov_recovery.toml @@ -1,6 +1,14 @@ [settings] timeout = 1000 +[relaychain.default_resources] +limits = { memory = "4G", cpu = "2" } +requests = { memory = "2G", cpu = "1" } + +[parachain.default_resources] +limits = { memory = "4G", cpu = "2" } +requests = { memory = "2G", cpu = "1" } + [relaychain.genesis.runtimeGenesis.patch.configuration.config.async_backing_params] max_candidate_depth = 6 allowed_ancestry_len = 3 @@ -23,7 +31,11 @@ command = "polkadot" [[relaychain.node_groups]] name = "validator" - args = ["-lruntime=debug,parachain=trace", "--reserved-only", "--reserved-nodes {{'alice'|zombie('multiAddress')}}"] + args = [ + "-lruntime=debug,parachain=trace", + "--reserved-only", + "--reserved-nodes {{'alice'|zombie('multiAddress')}}" + ] count = 8 # Slot based authoring with 3 cores and 2s slot duration @@ -32,17 +44,29 @@ id = 2100 chain = "elastic-scaling" add_to_genesis = false - # Slot based authoring with 3 cores and 2s slot duration + # run 'recovery-target' as a parachain full node [[parachains.collators]] - name = "collator-elastic" + name = "recovery-target" + validator = false # full node image = "{{COL_IMAGE}}" command = "test-parachain" - args = ["--disable-block-announcements", "-laura=trace,runtime=info,cumulus-consensus=trace,consensus::common=trace,parachain::collation-generation=trace,parachain::collator-protocol=trace,parachain=debug", "--force-authoring", "--experimental-use-slot-based"] + args = [ + "-lparachain::availability=trace,sync=debug,parachain=debug,cumulus-pov-recovery=debug,cumulus-consensus=debug", + "--disable-block-announcements", + "--in-peers 0", + "--out-peers 0", + "--", + "--reserved-only", + "--reserved-nodes {{'alice'|zombie('multiAddress')}}"] - # run 'recovery-target' as a parachain full node + # Slot based authoring with 3 cores and 2s slot duration [[parachains.collators]] - name = "recovery-target" - validator = false # full node + name = "collator-elastic" image = "{{COL_IMAGE}}" command = "test-parachain" - args = ["-lparachain::availability=trace,sync=debug,parachain=debug,cumulus-pov-recovery=debug,cumulus-consensus=debug", "--disable-block-announcements", "--bootnodes {{'collator-elastic'|zombie('multiAddress')}}", "--in-peers 0", "--out-peers 0", "--", "--reserved-only", "--reserved-nodes {{'alice'|zombie('multiAddress')}}"] + args = [ + "-laura=trace,runtime=info,cumulus-consensus=trace,consensus::common=trace,parachain::collation-generation=trace,parachain::collator-protocol=trace,parachain=debug", + "--disable-block-announcements", + "--force-authoring", + "--experimental-use-slot-based" + ] diff --git a/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile b/docker/dockerfiles/bridges_zombienet_tests_injected.Dockerfile index 60698de1d6ad..b1f4bffc772a 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.7.0 # metadata ARG VCS_REF diff --git a/docker/dockerfiles/polkadot/polkadot_injected.Dockerfile b/docker/dockerfiles/polkadot/polkadot_injected.Dockerfile new file mode 100644 index 000000000000..3dbede4966a8 --- /dev/null +++ b/docker/dockerfiles/polkadot/polkadot_injected.Dockerfile @@ -0,0 +1,52 @@ +FROM docker.io/parity/base-bin + +# metadata +ARG VCS_REF +ARG BUILD_DATE +ARG IMAGE_NAME +# That can be a single one or a comma separated list +ARG BINARY=polkadot + +LABEL io.parity.image.authors="devops-team@parity.io" \ + io.parity.image.vendor="Parity Technologies" \ + io.parity.image.title="parity/polkadot" \ + io.parity.image.description="Polkadot: a platform for web3. This is the official Parity image with an injected binary." \ + io.parity.image.source="https://github.com/paritytech/polkadot-sdk/blob/${VCS_REF}/docker/dockerfiles/polkadot/polkadot_injected.Dockerfile" \ + io.parity.image.revision="${VCS_REF}" \ + io.parity.image.created="${BUILD_DATE}" \ + io.parity.image.documentation="https://github.com/paritytech/polkadot-sdk/" + +# show backtraces +ENV RUST_BACKTRACE 1 + +USER root +WORKDIR /app + +# add polkadot and polkadot-*-worker binaries to the docker image +COPY bin/* /usr/local/bin/ +COPY entrypoint.sh . + + +RUN chmod -R a+rx "/usr/local/bin"; \ + mkdir -p /data /polkadot/.local/share && \ + chown -R parity:parity /data && \ + ln -s /data /polkadot/.local/share/polkadot + +USER parity + +# check if executable works in this container +RUN /usr/local/bin/polkadot --version +RUN /usr/local/bin/polkadot-prepare-worker --version +RUN /usr/local/bin/polkadot-execute-worker --version + + +EXPOSE 30333 9933 9944 9615 +VOLUME ["/polkadot"] + +ENV BINARY=${BINARY} + +# ENTRYPOINT +ENTRYPOINT ["/app/entrypoint.sh"] + +# We call the help by default +CMD ["--help"] diff --git a/docker/scripts/build-injected.sh b/docker/scripts/build-injected.sh index 749d0fa335cc..c37ea916c839 100755 --- a/docker/scripts/build-injected.sh +++ b/docker/scripts/build-injected.sh @@ -40,7 +40,7 @@ VCS_REF=${VCS_REF:-01234567} echo "Using engine: $ENGINE" echo "Using Dockerfile: $DOCKERFILE" echo "Using context: $CONTEXT" -echo "Building ${IMAGE}:latest container image for ${BINARY} v${VERSION} from ${ARTIFACTS_FOLDER} hang on!" +echo "Building ${IMAGE}:latest container image for ${BINARY} ${VERSION} from ${ARTIFACTS_FOLDER} hang on!" echo "ARTIFACTS_FOLDER=$ARTIFACTS_FOLDER" echo "CONTEXT=$CONTEXT" diff --git a/docker/scripts/polkadot/build-injected.sh b/docker/scripts/polkadot/build-injected.sh index 7cc6db43a54a..8f4e7005b816 100755 --- a/docker/scripts/polkadot/build-injected.sh +++ b/docker/scripts/polkadot/build-injected.sh @@ -9,5 +9,6 @@ PROJECT_ROOT=`git rev-parse --show-toplevel` export BINARY=polkadot,polkadot-execute-worker,polkadot-prepare-worker export ARTIFACTS_FOLDER=$1 +export DOCKERFILE="docker/dockerfiles/polkadot/polkadot_injected.Dockerfile" $PROJECT_ROOT/docker/scripts/build-injected.sh diff --git a/docs/BACKPORT.md b/docs/BACKPORT.md new file mode 100644 index 000000000000..0b4a97e6f667 --- /dev/null +++ b/docs/BACKPORT.md @@ -0,0 +1,21 @@ +# Backporting + +This document explains how to backport a merged PR from `master` to one of the `stable*` branches. +Backports should only be used to fix bugs or security issues - never to introduce new features. + +## Steps + +1. Fix a bug through a PR that targets `master`. +2. Add label `A4-needs-backport` to the PR. +3. Merge the PR into `master`. +4. Wait for the bot to open the backport PR. +5. Ensure the change is audited or does not need audit. +6. Merge the backport PR. + +The label can also be added after the PR is merged. + +## Example + +For example here where the dev triggered the process by adding the label after merging: + +![backport](./images/backport-ex2.png) diff --git a/docs/RELEASE.md b/docs/RELEASE.md index 653e6a2a3e92..bea367411359 100644 --- a/docs/RELEASE.md +++ b/docs/RELEASE.md @@ -55,9 +55,10 @@ The Westend testnet will be updated to a new runtime every two weeks with the la **From `master` to `stable`** -Backports in this direction can be anything that is audited and either a `minor` or a `patch` bump. [Security -fixes](#bug-and-security-fix) should be prioritized over additions or improvements. Crates that are declared as internal -API can also have `major` version bumps through backports. +Backports in this direction can be anything that is audited and either a `minor` or a `patch` bump. +See [BACKPORT.md](./BACKPORT.md) for more explanation. [Security fixes](#bug-and-security-fix) +should be prioritized over additions or improvements. Crates that are declared as internal API can +also have `major` version bumps through backports. **From `stable` to `master`** @@ -164,5 +165,6 @@ Describes how developers should merge bug and security fixes. 2. The Pull Request is marked as priority fix. 3. Audit happens with priority. 4. It is merged into `master`. -5. It is automatically back-ported to `stable`. -6. The fix will be released in the next *Stable* release. In urgent cases, a release can happen earlier. +5. Dev adds the `A4-needs-backport` label. +6. It is automatically back-ported to `stable`. +7. The fix will be released in the next *Stable* release. In urgent cases, a release can happen earlier. diff --git a/docs/contributor/CONTRIBUTING.md b/docs/contributor/CONTRIBUTING.md index 7d54b2681b41..53f42b9ae4fb 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 @@ -122,11 +161,11 @@ test output there is a script * `./scripts/update-ui-tests.sh` to update the tests for a current rust version locally * `./scripts/update-ui-tests.sh 1.70` # to update the tests for a specific rust version locally -Or if you have opened PR and you're member of `paritytech` - you can use command-bot to run the tests for you in CI: -* `bot update-ui` - will run the tests for the current rust version -* `bot update-ui latest --rust_version=1.70.0` - will run the tests for the specified rust version -* `bot update-ui latest -v CMD_IMAGE=paritytech/ci-unified:bullseye-1.70.0-2023-05-23 --rust_version=1.70.0` - will run -the tests for the specified rust version and specified image +Or if you have opened PR and you're member of `paritytech` - you can use [/cmd](./commands-readme.md) +to run the tests for you in CI: +* `/cmd update-ui` - will run the tests for the current rust version +* `/cmd update-ui --image docker.io/paritytech/ci-unified:bullseye-1.70.0-2023-05-23` - +will run the tests for the specified rust version and specified image ## Feature Propagation @@ -136,7 +175,7 @@ We use [zepter](https://github.com/ggwpez/zepter) to enforce features are propag If you're member of **paritytech** org - you can use command-bot to run various of common commands in CI: -Start with comment in PR: `bot help` to see the list of available commands. +Start with comment in PR: `/cmd --help` to see the list of available commands. ## Deprecating code diff --git a/docs/contributor/DOCUMENTATION_GUIDELINES.md b/docs/contributor/DOCUMENTATION_GUIDELINES.md index 96811a2772d7..5ac99fff1cdb 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 083b30b4a356..99455c985076 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)*. @@ -33,8 +33,9 @@ possibly integration.* # Checklist * [ ] My PR includes a detailed description as outlined in the "Description" and its two subsections above. -* [ ] My PR follows the [labeling requirements](CONTRIBUTING.md#Process) of this project (at minimum one label for `T` - required) +* [ ] My PR follows the [labeling requirements]( +https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/CONTRIBUTING.md#Process +) of this project (at minimum one label for `T` required) * External contributors: ask maintainers to put the right label on your PR. * [ ] I have made corresponding changes to the documentation (if applicable) * [ ] I have added tests that prove my fix is effective or that my feature works (if applicable) diff --git a/docs/contributor/commands-readme.md b/docs/contributor/commands-readme.md new file mode 100644 index 000000000000..52c554cc7098 --- /dev/null +++ b/docs/contributor/commands-readme.md @@ -0,0 +1,43 @@ +# Running Commands in PRs + +You can run commands in PRs by triggering it via comment. It will use the context of your PR and post the results back. +Note: it works only for members of the `paritytech` organization. + +## Usage + +`/cmd --help` to see all available commands and usage format + +`/cmd --help` to see the usage of a specific command + +### Commands + +- `/cmd fmt` to format the code in the PR. It commits back with the formatted code (fmt) and configs (taplo). + +- `/cmd bench` to generate weights for a runtime. Read more about [Weight Generation](weight-generation.md) + +- `/cmd prdoc` to generate a prdoc for a PR. Read more about [PRDoc](prdoc.md) + +### Flags + +1.`--quiet` to suppress the output of the command in the comments. +By default, the Start and End/Failure of the command will be commented with the link to a pipeline. +If you want to avoid, use this flag. Go to +[Action Tab](https://github.com/paritytech/polkadot-sdk/actions/workflows/cmd.yml) to see the pipeline status. + +3.`--clean` to clean up all yours and bot's comments in PR relevant to `/cmd` commands. If you run too many commands, +or they keep failing, and you're rerunning them again, it's handy to add this flag to keep a PR clean. + +### Adding new Commands + +Feel free to add new commands to the workflow, however **_note_** that triggered workflows will use the actions +from `main` (default) branch, meaning they will take effect only after the PR with new changes/command is merged. +If you want to test the new command, it's better to test in your fork and local-to-fork PRs, where you control +the default branch. + +### Examples + +The regex in cmd.yml is: `^(\/cmd )([-\/\s\w.=:]+)$` accepts only alphanumeric, space, "-", "/", "=", ":", "." chars. + +`/cmd bench --runtime bridge-hub-westend --pallet=pallet_name` +`/cmd prdoc --audience runtime_dev runtime_user --bump patch --force` +`/cmd update-ui --image=docker.io/paritytech/ci-unified:bullseye-1.77.0-2024-04-10-v202407161507 --clean` diff --git a/docs/contributor/prdoc.md b/docs/contributor/prdoc.md index 0c8165af40f4..4a1a3c1f0688 100644 --- a/docs/contributor/prdoc.md +++ b/docs/contributor/prdoc.md @@ -14,28 +14,39 @@ the [CODEOWNERS](../../.github/CODEOWNERS) for advice. A `.prdoc` file is a YAML file with a defined structure (ie JSON Schema). Please follow these steps to generate one: -1. Install the [`prdoc` CLI](https://github.com/paritytech/prdoc) by running `cargo install prdoc`. +1. Install the [`prdoc` CLI](https://github.com/paritytech/prdoc) by running `cargo install parity-prdoc`. 1. Open a Pull Request and get the PR number. 1. Generate the file with `prdoc generate `. The output filename will be printed. 1. Optional: Install the `prdoc/schema_user.json` schema in your editor, for example -[VsCode](https://github.com/paritytech/prdoc?tab=readme-ov-file#schemas). + [VsCode](https://github.com/paritytech/prdoc?tab=readme-ov-file#schemas). 1. Edit your `.prdoc` file according to the [Audience](#pick-an-audience) and [SemVer](#record-semver-changes) sections. 1. Check your prdoc with `prdoc check -n `. This is optional since the CI will also check it. > **Tip:** GitHub CLI and jq can be used to provide the number of your PR to generate the correct file: > `prdoc generate $(gh pr view --json number | jq '.number') -o prdoc` +Alternatively you can call the prdoc from PR via `/cmd prdoc` (see args with `/cmd prdoc --help`) +in a comment to PR to trigger it from CI. + +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. +- `force`: Whether to overwrite any existing PrDoc. + ## Pick An Audience While describing a PR, the author needs to consider which audience(s) need to be addressed. The list of valid audiences is described and documented in the JSON schema as follow: - `Node Dev`: Those who build around the client side code. Alternative client builders, SMOLDOT, those who consume RPCs. - These are people who are oblivious to the runtime changes. They only care about the meta-protocol, not the protocol - itself. + These are people who are oblivious to the runtime changes. They only care about the meta-protocol, not the protocol + itself. - `Runtime Dev`: All of those who rely on the runtime. A parachain team that is using a pallet. A DApp that is using a - pallet. These are people who care about the protocol (WASM), not the meta-protocol (client). + pallet. These are people who care about the protocol (WASM), not the meta-protocol (client). - `Node Operator`: Those who don't write any code and only run code. @@ -64,10 +75,10 @@ For example when you modified two crates and record the changes: ```yaml crates: -- name: frame-example - bump: major -- name: frame-example-pallet - bump: minor + - name: frame-example + bump: major + - name: frame-example-pallet + bump: minor ``` It means that downstream code using `frame-example-pallet` is still guaranteed to work as before, while code using diff --git a/docs/contributor/weight-generation.md b/docs/contributor/weight-generation.md new file mode 100644 index 000000000000..a22a55404a44 --- /dev/null +++ b/docs/contributor/weight-generation.md @@ -0,0 +1,71 @@ +# Weight Generation + +To generate weights for a runtime. +Weights generation is using self-hosted runner which is provided by Parity CI, the rest commands are using standard +GitHub runners on `ubuntu-latest` or `ubuntu-20.04`. +Self-hosted runner for benchmarks (`parity-weights`) is configured to meet requirements of reference +hardware for running validators +https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware + +In a PR run the actions through comment: + +```sh +/cmd bench --help # outputs the actual usage documentation with examples and supported runtimes + +# or + +/cmd --help # to see all available commands +``` + +To regenerate all weights (however it will take long, +so don't do it unless you really need it), run the following command: + +```sh +/cmd bench +``` + +To generate weights for all pallets in a particular runtime(s), run the following command: + +```sh +/cmd bench --runtime kusama polkadot +``` + +For Substrate pallets (supports sub-modules too): + +```sh +/cmd bench --runtime dev --pallet pallet_asset_conversion_ops +``` + +> **📝 Note**: The action is not being run right-away, it will be queued and run in the next available runner. +> So might be quick, but might also take up to 10 mins (That's in control of Github). +> Once the action is run, you'll see reaction 👀 on original comment, and if you didn't pass `--quiet` - +> it will also send a link to a pipeline when started, and link to whole workflow when finished. +> +> **📝 Note**: It will try keep benchmarking even if some pallets failed, with the result of failed/successful pallets. +> +> If you want to fail fast on first failed benchmark, add `--fail-fast` flag to the command. + +--- + +This way it runs all possible runtimes for the specified pallets, if it finds them in the runtime + +```sh +/cmd bench --pallet pallet_balances pallet_xcm_benchmarks::generic pallet_xcm_benchmarks::fungible +``` + +If you want to run all specific pallet(s) for specific runtime(s), you can do it like this: + +```sh +/cmd bench --runtime bridge-hub-polkadot --pallet pallet_xcm_benchmarks::generic pallet_xcm_benchmarks::fungible +``` + +> **💡Hint #1** : Sometimes when you run too many commands, or they keep failing and you're rerunning them again, +> it's handy to add `--clean` flag to the command. This will clean up all yours and bot's comments in PR relevant to +> /cmd commands. + +```sh +/cmd bench --runtime kusama polkadot --pallet=pallet_balances --clean +``` + +> **💡Hint #2** : If you have questions or need help, feel free to tag @paritytech/opstooling (in github comments) +> or ping in [matrix](https://matrix.to/#/#command-bot:parity.io) channel. diff --git a/docs/images/Polkadot_Logo_Horizontal_Pink_BlackOnWhite.png b/docs/images/Polkadot_Logo_Horizontal_Pink_BlackOnWhite.png new file mode 100644 index 000000000000..ef2b997100ea Binary files /dev/null and b/docs/images/Polkadot_Logo_Horizontal_Pink_BlackOnWhite.png differ diff --git a/docs/images/Polkadot_Logo_Horizontal_Pink_WhiteOnBlack.png b/docs/images/Polkadot_Logo_Horizontal_Pink_WhiteOnBlack.png new file mode 100644 index 000000000000..421a38e1bdfa Binary files /dev/null and b/docs/images/Polkadot_Logo_Horizontal_Pink_WhiteOnBlack.png differ diff --git a/docs/images/backport-ex2.png b/docs/images/backport-ex2.png new file mode 100644 index 000000000000..97ccf6b00fb9 Binary files /dev/null and b/docs/images/backport-ex2.png differ diff --git a/docs/mermaid/IA.mmd b/docs/mermaid/IA.mmd index 37417497e1f8..0f14e200df9c 100644 --- a/docs/mermaid/IA.mmd +++ b/docs/mermaid/IA.mmd @@ -1,13 +1,13 @@ flowchart parity[paritytech.github.io] --> devhub[polkadot_sdk_docs] - polkadot_network[polkadot.network] --> devhub[polkadot_sdk_docs] devhub --> polkadot_sdk devhub --> reference_docs devhub --> guides + devhub --> external_resources polkadot_sdk --> substrate polkadot_sdk --> frame - polkadot_sdk --> cumulus polkadot_sdk --> polkadot[polkadot node] polkadot_sdk --> xcm + polkadot_sdk --> templates diff --git a/docs/sdk/Cargo.toml b/docs/sdk/Cargo.toml index d3e48de5d181..b86ce9868208 100644 --- a/docs/sdk/Cargo.toml +++ b/docs/sdk/Cargo.toml @@ -22,6 +22,7 @@ frame = { features = [ "runtime", ], workspace = true, default-features = true } pallet-examples = { workspace = true } +pallet-contracts = { workspace = true } pallet-default-config-example = { workspace = true, default-features = true } pallet-example-offchain-worker = { workspace = true, default-features = true } @@ -30,7 +31,7 @@ simple-mermaid = "0.1.1" docify = { workspace = true } # Polkadot SDK deps, typically all should only be in scope such that we can link to their doc item. -polkadot-sdk = { features = ["runtime"], workspace = true, default-features = true } +polkadot-sdk = { features = ["runtime-full"], workspace = true, default-features = true } node-cli = { workspace = true } kitchensink-runtime = { workspace = true } chain-spec-builder = { workspace = true, default-features = true } @@ -38,8 +39,10 @@ subkey = { workspace = true, default-features = true } frame-system = { workspace = true } frame-support = { workspace = true } frame-executive = { workspace = true } +pallet-example-authorization-tx-extension = { workspace = true, default-features = 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 +110,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/assets/header.html b/docs/sdk/assets/header.html index f55c31b53216..c24c10940759 100644 --- a/docs/sdk/assets/header.html +++ b/docs/sdk/assets/header.html @@ -14,12 +14,13 @@ headers.forEach(header => { let link = document.createElement("a"); link.href = "#" + header.id; - link.textContent = header.textContent; + const headerTextContent = header.textContent.replace("§", "") + link.textContent = headerTextContent; link.className = header.tagName.toLowerCase(); toc.appendChild(link); - if (header.id == "modules" && header.textContent == "Modules") { + if (header.id == "modules" && headerTextContent == "Modules") { modules.forEach(module => { let link = document.createElement("a"); link.href = module.href; diff --git a/docs/sdk/assets/theme.css b/docs/sdk/assets/theme.css index a488e15c36b7..1f47a8ef5b0c 100644 --- a/docs/sdk/assets/theme.css +++ b/docs/sdk/assets/theme.css @@ -9,9 +9,14 @@ body.sdk-docs { nav.sidebar>div.sidebar-crate>a>img { width: 190px; + height: 52px; } nav.sidebar { flex: 0 0 250px; } } + +html[data-theme="light"] .sidebar-crate > .logo-container > img { + content: url("https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/docs/images/Polkadot_Logo_Horizontal_Pink_Black.png"); +} diff --git a/docs/sdk/src/external_resources.rs b/docs/sdk/src/external_resources.rs new file mode 100644 index 000000000000..939874d12f13 --- /dev/null +++ b/docs/sdk/src/external_resources.rs @@ -0,0 +1,14 @@ +//! # External Resources +//! +//! A non-exhaustive, un-opinionated list of external resources about Polkadot SDK. +//! +//! Unlike [`crate::guides`], or [`crate::polkadot_sdk::templates`] that contain material directly +//! maintained in the `polkadot-sdk` repository, the list of resources here are maintained by +//! third-parties, and are therefore subject to more variability. Any further resources may be added +//! by opening a pull request to the `polkadot-sdk` repository. +//! +//! - [Polkadot NFT Marketplace Tutorial by Polkadot Fellow Shawn Tabrizi](https://www.shawntabrizi.com/substrate-collectables-workshop/) +//! - [DOT Code School](https://dotcodeschool.com/) +//! - [Polkadot Developers](https://github.com/polkadot-developers/) +//! - [Polkadot Blockchain Academy](https://github.com/Polkadot-Blockchain-Academy) +//! - [Polkadot Wiki: Build](https://wiki.polkadot.network/docs/build-guide) diff --git a/docs/sdk/src/guides/async_backing_guide.rs b/docs/sdk/src/guides/async_backing_guide.rs index f2f4dcabfd29..25ef3a12cbf0 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 bc4f36c271fe..812e674d163b 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. //! @@ -84,7 +85,7 @@ //! This phase consists of plugging in the new slot-based collator. //! //! 1. In `node/src/service.rs` import the slot based collator instead of the lookahead collator. -#![doc = docify::embed!("../../cumulus/polkadot-parachain/src/service.rs", slot_based_colator_import)] +#![doc = docify::embed!("../../cumulus/polkadot-omni-node/lib/src/nodes/aura.rs", slot_based_colator_import)] //! //! 2. In `start_consensus()` //! - Remove the `overseer_handle` param (also remove the @@ -93,7 +94,7 @@ //! `slot_drift` field with a value of `Duration::from_secs(1)`. //! - Replace the single future returned by `aura::run` with the two futures returned by it and //! spawn them as separate tasks: -#![doc = docify::embed!("../../cumulus/polkadot-parachain/src/service.rs", launch_slot_based_collator)] +#![doc = docify::embed!("../../cumulus/polkadot-omni-node/lib/src/nodes/aura.rs", launch_slot_based_collator)] //! //! 3. In `start_parachain_node()` remove the `overseer_handle` param passed to `start_consensus`. //! diff --git a/docs/sdk/src/guides/enable_metadata_hash.rs b/docs/sdk/src/guides/enable_metadata_hash.rs index b9cbae853353..930afd4d8ff7 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 3c0c5fba2158..cb6960b3df4e 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 @@ -56,9 +58,9 @@ //! > that this step in the guide was not //! > set up correctly. //! -//! ## 3. Add the SignedExtension to your runtime +//! ## 3. Add the TransactionExtension to your runtime //! -//! In your runtime, you will find a list of SignedExtensions. +//! In your runtime, you will find a list of TransactionExtensions. //! To enable the reclaiming, //! add [`StorageWeightReclaim`](cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim) //! to that list. For maximum efficiency, make sure that `StorageWeightReclaim` is last in the list. diff --git a/docs/sdk/src/guides/mod.rs b/docs/sdk/src/guides/mod.rs index 9384f4c82ab3..a7fd146ccdf3 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 da4624f5ac2b..fcfaab00e552 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: //! @@ -16,12 +16,12 @@ //! //! ## Writing Your First Pallet //! -//! To get started, use one of the templates mentioned in [`crate::polkadot_sdk::templates`]. We +//! To get started, clone 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. +//! > `source` button at the top right of the page. //! //! You should have studied the following modules as a prelude to this guide: //! @@ -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`] 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 //! @@ -319,13 +319,13 @@ //! - Learn more about the individual pallet items/macros, such as event and errors and call, in //! [`frame::pallet_macros`]. //! -//! [`pallet::storage`]: ../../../frame_support/pallet_macros/attr.config.html -//! [`pallet::call`]: ../../../frame_support/pallet_macros/attr.call.html -//! [`pallet::event`]: ../../../frame_support/pallet_macros/attr.event.html -//! [`pallet::error`]: ../../../frame_support/pallet_macros/attr.error.html -//! [`pallet::pallet`]: ../../../frame_support/pallet_macros/attr.pallet.html -//! [`pallet::config`]: ../../../frame_support/pallet_macros/attr.config.html -//! [`pallet::generate_deposit`]: ../../../frame_support/pallet_macros/attr.generate_deposit.html +//! [`pallet::storage`]: frame_support::pallet_macros::storage +//! [`pallet::call`]: frame_support::pallet_macros::call +//! [`pallet::event`]: frame_support::pallet_macros::event +//! [`pallet::error`]: frame_support::pallet_macros::error +//! [`pallet::pallet`]: frame_support::pallet +//! [`pallet::config`]: frame_support::pallet_macros::config +//! [`pallet::generate_deposit`]: frame_support::pallet_macros::generate_deposit #[docify::export] #[frame::pallet(dev_mode)] @@ -395,11 +395,11 @@ pub mod pallet { if sender_balance < amount { return Err("InsufficientBalance".into()) } - let reminder = sender_balance - amount; + let remainder = sender_balance - amount; // update sender and dest balances. Balances::::mutate(dest, |b| *b = Some(b.unwrap_or(0) + amount)); - Balances::::insert(&sender, reminder); + Balances::::insert(&sender, remainder); Ok(()) } @@ -417,7 +417,7 @@ pub mod pallet { let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; ensure!(sender_balance >= amount, "InsufficientBalance"); - let reminder = sender_balance - amount; + let remainder = sender_balance - amount; // .. snip Ok(()) @@ -433,7 +433,7 @@ pub mod pallet { let sender = ensure_signed(origin)?; let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; - let reminder = sender_balance.checked_sub(amount).ok_or("InsufficientBalance")?; + let remainder = sender_balance.checked_sub(amount).ok_or("InsufficientBalance")?; // .. snip Ok(()) @@ -717,11 +717,11 @@ pub mod pallet_v2 { // ensure sender has enough balance, and if so, calculate what is left after `amount`. let sender_balance = Balances::::get(&sender).ok_or(Error::::NonExistentAccount)?; - let reminder = + let remainder = sender_balance.checked_sub(amount).ok_or(Error::::InsufficientBalance)?; Balances::::mutate(&dest, |b| *b = Some(b.unwrap_or(0) + amount)); - Balances::::insert(&sender, reminder); + Balances::::insert(&sender, remainder); Self::deposit_event(Event::::Transferred { from: sender, to: dest, amount }); diff --git a/docs/sdk/src/guides/your_first_pallet/with_event.rs b/docs/sdk/src/guides/your_first_pallet/with_event.rs index a65aac324f07..a5af29c9c319 100644 --- a/docs/sdk/src/guides/your_first_pallet/with_event.rs +++ b/docs/sdk/src/guides/your_first_pallet/with_event.rs @@ -54,11 +54,11 @@ pub mod pallet { if sender_balance < amount { return Err("NotEnoughBalance".into()) } - let reminder = sender_balance - amount; + let remainder = sender_balance - amount; // update sender and dest balances. Balances::::mutate(dest, |b| *b = Some(b.unwrap_or(0) + amount)); - Balances::::insert(&sender, reminder); + Balances::::insert(&sender, remainder); Ok(()) } @@ -76,7 +76,7 @@ pub mod pallet { let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; ensure!(sender_balance >= amount, "NotEnoughBalance"); - let reminder = sender_balance - amount; + let remainder = sender_balance - amount; // .. snip Ok(()) @@ -92,7 +92,7 @@ pub mod pallet { let sender = ensure_signed(origin)?; let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; - let reminder = sender_balance.checked_sub(amount).ok_or("NotEnoughBalance")?; + let remainder = sender_balance.checked_sub(amount).ok_or("NotEnoughBalance")?; // .. snip Ok(()) diff --git a/docs/sdk/src/lib.rs b/docs/sdk/src/lib.rs index e211476d2514..86ca677d7cef 100644 --- a/docs/sdk/src/lib.rs +++ b/docs/sdk/src/lib.rs @@ -5,16 +5,13 @@ //! This crate is a *minimal*, but *always-accurate* source of information for those wishing to //! build on the Polkadot SDK. //! -//! > **Work in Progress**: This crate is under heavy development. Expect content to be moved and -//! > changed. Do not use links to this crate yet. See [`meta_contributing`] for more information. -//! //! ## Getting Started //! //! 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,9 +22,9 @@ #![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" + html_logo_url = "https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/docs/images/Polkadot_Logo_Horizontal_Pink_White.png" )] #![doc(issue_tracker_base_url = "https://github.com/paritytech/polkadot-sdk/issues")] @@ -35,9 +32,13 @@ /// how one can contribute to it. pub mod meta_contributing; +/// A list of external resources and learning material about Polkadot SDK. +pub mod external_resources; + /// 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. pub mod polkadot_sdk; diff --git a/docs/sdk/src/meta_contributing.rs b/docs/sdk/src/meta_contributing.rs index a029595254c8..e1297151b231 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/cumulus.rs b/docs/sdk/src/polkadot_sdk/cumulus.rs index 9bd957c7c1c0..c6abf9f7b4d1 100644 --- a/docs/sdk/src/polkadot_sdk/cumulus.rs +++ b/docs/sdk/src/polkadot_sdk/cumulus.rs @@ -96,6 +96,7 @@ mod tests { >; type WeightInfo = (); type DmpQueue = frame::traits::EnqueueWithOrigin<(), sp_core::ConstU8<0>>; + type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector; } impl parachain_info::Config for Runtime {} diff --git a/docs/sdk/src/polkadot_sdk/frame_runtime.rs b/docs/sdk/src/polkadot_sdk/frame_runtime.rs index 39255c8f51ad..8acf19f76413 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 124d391421b9..c089b6729ce5 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,12 +103,13 @@ //! //! ## 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) +//! * [Avail](https://github.com/availproject/avail) //! * [Cardano Partner Chains](https://iohk.io/en/blog/posts/2023/11/03/partner-chains-are-coming-to-cardano/) //! * [Starknet's Madara Sequencer](https://github.com/keep-starknet-strange/madara) +//! * [Polymesh](https://polymesh.network/) //! //! [`substrate`]: crate::polkadot_sdk::substrate //! [`frame`]: crate::polkadot_sdk::frame_runtime @@ -116,7 +117,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 e2dcca4dc7df..69532f323b9d 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 69d74d86db1b..56b89f8c9c2a 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/templates.rs b/docs/sdk/src/polkadot_sdk/templates.rs index e87eb9c2bc8a..ab742ad5c3a2 100644 --- a/docs/sdk/src/polkadot_sdk/templates.rs +++ b/docs/sdk/src/polkadot_sdk/templates.rs @@ -7,42 +7,35 @@ //! //! ## Internal //! -//! The following [templates](https://github.com/paritytech/polkadot-sdk/blob/master/templates) are -//! maintained as a part of the `polkadot-sdk` repository: -//! -//! - `minimal_template_node`/[`minimal_template_runtime`]: A minimal template that contains the -//! least amount of features to be a functioning blockchain. Suitable for learning, development -//! and testing. This template is not meant to be used in production. -//! - `solochain_template_node`/[`solochain_template_runtime`]: Formerly known as -//! "substrate-node-template", is a white-labeled substrate-based blockchain (aka. solochain) that -//! contains moderate features, such as a basic consensus engine and some FRAME pallets. This -//! template can act as a good starting point for those who want to launch a solochain. -//! - `parachain_template_node`/[`parachain_template_runtime`]: A parachain template ready to be -//! connected to a test relay-chain. -//! -//! These templates are always kept up to date, and are mirrored to external repositories for easy -//! forking: -//! -//! - -//! - -//! - -//! -//! ## External Templates -//! -//! Noteworthy templates outside of this repository. -//! -//! - [`extended-parachain-template`](https://github.com/paritytech/extended-parachain-template): A -//! parachain template that contains more built-in functionality such as assets and NFTs. -//! - [`frontier-parachain-template`](https://github.com/paritytech/frontier-parachain-template): A -//! parachain template for launching EVM-compatible parachains. +//! The following templates are maintained as a part of the `polkadot-sdk` repository: +//! +//! - [`minimal-template`](https://github.com/paritytech/polkadot-sdk-minimal-template): A minimal +//! template that contains the least amount of features to be a functioning blockchain. Suitable +//! for learning and testing. +//! - [`solochain-template`](https://github.com/paritytech/polkadot-sdk-solochain-template): +//! Formerly known as "substrate-node-template", is a white-labeled substrate-based blockchain +//! (aka. solochain) that contains moderate features, such as a basic consensus engine and some +//! FRAME pallets. This template can act as a good starting point for those who want to launch a +//! solochain. +//! - [`parachain-template`](https://github.com/paritytech/polkadot-sdk-parachain-template): +//! A parachain template ready to be connected to a relay-chain, such as [Paseo](https://github.com/paseo-network/.github) +//! , Kusama or Polkadot. +//! +//! Note that these templates are mirrored automatically from [this](https://github.com/paritytech/polkadot-sdk/blob/master/templates) +//! directory of polkadot-sdk, therefore any changes to them should be made as a PR to this repo. //! //! ## OpenZeppelin //! //! In June 2023, OpenZeppelin was awarded a grant from the [Polkadot //! treasury](https://polkadot.polkassembly.io/treasury/406) for building a number of Polkadot-sdk -//! based templates. These templates are expected to be a great starting point for developers. -//! -//! - +//! based templates. These templates are a great starting point for developers and newcomers. +//! So far OpenZeppelin has released two templates, which have been fully [audited](https://github.com/OpenZeppelin/polkadot-runtime-templates/tree/main/audits): +//! - [`generic-runtime-template`](https://github.com/OpenZeppelin/polkadot-runtime-templates?tab=readme-ov-file#generic-runtime-template): +//! A minimal template that has all the common pallets that parachains use with secure defaults. +//! - [`evm-runtime-template`](https://github.com/OpenZeppelin/polkadot-runtime-templates/tree/main?tab=readme-ov-file#evm-template): +//! This template has EVM compatibility out of the box and allows migrating your solidity contracts +//! or EVM compatible dapps easily. It also uses 20 byte addresses like Ethereum and has some +//! Account Abstraction support. //! //! ## POP-CLI //! diff --git a/docs/sdk/src/polkadot_sdk/xcm.rs b/docs/sdk/src/polkadot_sdk/xcm.rs index 58f540686424..20841b0b55b9 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 0d1aefcc5277..36ab0ce5ed54 100644 --- a/docs/sdk/src/reference_docs/blockchain_state_machines.rs +++ b/docs/sdk/src/reference_docs/blockchain_state_machines.rs @@ -21,7 +21,7 @@ #![doc = simple_mermaid::mermaid!("../../../mermaid/stf.mmd")] //! //! In essence, the state of the blockchain at block N is the outcome of applying the state -//! transition function to the the previous state, and the current block as input. This can be +//! transition function to the previous state, and the current block as input. This can be //! mathematically represented as: //! //! ```math diff --git a/docs/sdk/src/reference_docs/chain_spec_genesis.rs b/docs/sdk/src/reference_docs/chain_spec_genesis.rs index 557795cb410c..a2e22d1ed1eb 100644 --- a/docs/sdk/src/reference_docs/chain_spec_genesis.rs +++ b/docs/sdk/src/reference_docs/chain_spec_genesis.rs @@ -1,4 +1,4 @@ -//! # What is chain-spec. +//! # What is a chain specification //! //! A chain specification file defines the set of properties that are required to run the node as //! part of the chain. The chain specification consists of two main parts: @@ -165,8 +165,10 @@ #![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs", list_presets)] //! ## Displaying preset with given name #![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs", get_preset)] -//! ## Building chain-spec using given preset +//! ## Building a solo chain-spec (the default) using given preset #![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs", generate_chain_spec)] +//! ## Building a parachain chain-spec using given preset +#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs", generate_para_chain_spec)] //! //! [`RuntimeGenesisConfig`]: //! chain_spec_guide_runtime::runtime::RuntimeGenesisConfig @@ -178,7 +180,6 @@ //! [`pallet::genesis_build`]: frame_support::pallet_macros::genesis_build //! [`pallet::genesis_config`]: frame_support::pallet_macros::genesis_config //! [`BuildGenesisConfig`]: frame_support::traits::BuildGenesisConfig -//! [`chain_spec_builder`]: ../../../staging_chain_spec_builder/index.html //! [`serde`]: https://serde.rs/field-attrs.html //! [`get_storage_for_patch`]: sc_chain_spec::GenesisConfigBuilderRuntimeCaller::get_storage_for_patch //! [`GenesisBuilder::get_preset`]: sp_genesis_builder::GenesisBuilder::get_preset diff --git a/docs/sdk/src/reference_docs/chain_spec_runtime/src/runtime.rs b/docs/sdk/src/reference_docs/chain_spec_runtime/src/runtime.rs index c45f0126337e..5be3a59dc7bb 100644 --- a/docs/sdk/src/reference_docs/chain_spec_runtime/src/runtime.rs +++ b/docs/sdk/src/reference_docs/chain_spec_runtime/src/runtime.rs @@ -32,10 +32,7 @@ use frame::{ runtime, }, prelude::*, - runtime::{ - apis::{self, impl_runtime_apis, ExtrinsicInclusionMode}, - prelude::*, - }, + runtime::{apis, prelude::*}, }; use sp_genesis_builder::PresetId; @@ -49,7 +46,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, - state_version: 1, + system_version: 1, }; /// The signed extensions that are added to the runtime. diff --git a/docs/sdk/src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs b/docs/sdk/src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs index d08f547bba61..cc273685fcb4 100644 --- a/docs/sdk/src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs +++ b/docs/sdk/src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs @@ -104,7 +104,66 @@ fn generate_chain_spec() { "bootNodes": [], "telemetryEndpoints": null, "protocolId": null, - "properties": null, + "properties": { "tokenDecimals": 12, "tokenSymbol": "UNIT" }, + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "code": "0x123", + "patch": { + "bar": { + "initialAccount": "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL" + }, + "foo": { + "someEnum": { + "Data2": { + "values": "0x0c10" + } + }, + "someInteger": 200 + } + } + } + } + }); + assert_eq!(output, expected_output, "Output did not match expected"); +} + +#[test] +#[docify::export] +fn generate_para_chain_spec() { + let output = Command::new(get_chain_spec_builder_path()) + .arg("-c") + .arg("/dev/stdout") + .arg("create") + .arg("-c") + .arg("polkadot") + .arg("-p") + .arg("1000") + .arg("-r") + .arg(WASM_FILE_PATH) + .arg("named-preset") + .arg("preset_2") + .output() + .expect("Failed to execute command"); + + let mut output: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap(); + + //remove code field for better readability + if let Some(code) = output["genesis"]["runtimeGenesis"].as_object_mut().unwrap().get_mut("code") + { + *code = Value::String("0x123".to_string()); + } + + let expected_output = json!({ + "name": "Custom", + "id": "custom", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "relay_chain": "polkadot", + "para_id": 1000, + "properties": { "tokenDecimals": 12, "tokenSymbol": "UNIT" }, "codeSubstitutes": {}, "genesis": { "runtimeGenesis": { diff --git a/docs/sdk/src/reference_docs/cli.rs b/docs/sdk/src/reference_docs/cli.rs index 5779e0f8d049..6f393f267b0d 100644 --- a/docs/sdk/src/reference_docs/cli.rs +++ b/docs/sdk/src/reference_docs/cli.rs @@ -1,7 +1,7 @@ //! # Substrate CLI //! //! Let's see some examples of typical CLI arguments used when setting up and running a -//! Substrate-based blockchain. We use the [`substrate-node-template`](https://github.com/substrate-developer-hub/substrate-node-template) +//! Substrate-based blockchain. We use the [`solochain-template`](https://github.com/paritytech/polkadot-sdk-solochain-template) //! on these examples. //! //! #### Checking the available CLI arguments @@ -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 83a70606cb8d..083ed9f77e10 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 9828e1b50918..82d624b01d97 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 9ba95dfa0329..a5f38bb280de 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/extrinsic_encoding.rs b/docs/sdk/src/reference_docs/extrinsic_encoding.rs index 31ce92c67e98..1d4b0405b324 100644 --- a/docs/sdk/src/reference_docs/extrinsic_encoding.rs +++ b/docs/sdk/src/reference_docs/extrinsic_encoding.rs @@ -12,7 +12,7 @@ //! //! What follows is a description of how extrinsics based on this //! [`sp_runtime::generic::UncheckedExtrinsic`] type are encoded into bytes. Specifically, we are -//! looking at how extrinsics with a format version of 4 are encoded. This version is itself a part +//! looking at how extrinsics with a format version of 5 are encoded. This version is itself a part //! of the payload, and if it changes, it indicates that something about the encoding may have //! changed. //! @@ -24,7 +24,8 @@ //! ```text //! extrinsic_bytes = concat( //! compact_encoded_length, -//! version_and_maybe_signature, +//! version_and_extrinsic_type, +//! maybe_extension_data, //! call_data //! ) //! ``` @@ -56,18 +57,38 @@ //! version_and_signed, //! from_address, //! signature, -//! signed_extensions_extra, +//! transaction_extensions_extra, //! ) //! ``` //! //! Each of the details to be concatenated together is explained below: //! -//! ### version_and_signed +//! ## version_and_extrinsic_type //! -//! This is one byte, equal to `0x84` or `0b1000_0100` (i.e. an upper 1 bit to denote that it is -//! signed, and then the transaction version, 4, in the lower bits). +//! This byte has 2 components: +//! - the 2 most significant bits represent the extrinsic type: +//! - bare - `0b00` +//! - signed - `0b10` +//! - general - `0b01` +//! - the 6 least significant bits represent the extrinsic format version (currently 5) //! -//! ### from_address +//! ### Bare extrinsics +//! +//! If the extrinsic is _bare_, then `version_and_extrinsic_type` will be just the _transaction +//! protocol version_, which is 5 (or `0b0000_0101`). Bare extrinsics do not carry any other +//! extension data, so `maybe_extension_data` would not be included in the payload and the +//! `version_and_extrinsic_type` would always be followed by the encoded call bytes. +//! +//! ### Signed extrinsics +//! +//! If the extrinsic is _signed_ (all extrinsics submitted from users used to be signed up until +//! version 4), then `version_and_extrinsic_type` is obtained by having a MSB of `1` on the +//! _transaction protocol version_ byte (which translates to `0b1000_0101`). +//! +//! Additionally, _signed_ extrinsics also carry with them address and signature information encoded +//! as follows: +//! +//! #### from_address //! //! This is the [SCALE encoded][frame::deps::codec] address of the sender of the extrinsic. The //! address is the first generic parameter of [`sp_runtime::generic::UncheckedExtrinsic`], and so @@ -78,7 +99,7 @@ //! signed extrinsic to be submitted to a Polkadot node, you'll always use the //! [`sp_runtime::MultiAddress::Id`] variant to wrap your `AccountId32`. //! -//! ### signature +//! #### signature //! //! This is the [SCALE encoded][frame::deps::codec] signature. The signature type is configured via //! the third generic parameter of [`sp_runtime::generic::UncheckedExtrinsic`], which determines the @@ -90,32 +111,41 @@ //! The signature type used on the Polkadot relay chain is [`sp_runtime::MultiSignature`]; the //! variants there are the types of signature that can be provided. //! -//! ### signed_extensions_extra +//! ### General extrinsics +//! +//! If the extrinsic is _general_ (it doesn't carry a signature in the payload, only extension +//! data), then `version_and_extrinsic_type` is obtained by logical OR between the general +//! transaction type bits and the _transaction protocol version_ byte (which translates to +//! `0b0100_0101`). //! -//! This is the concatenation of the [SCALE encoded][frame::deps::codec] bytes representing each of -//! the [_signed extensions_][sp_runtime::traits::SignedExtension], and are configured by the -//! fourth generic parameter of [`sp_runtime::generic::UncheckedExtrinsic`]. Learn more about -//! signed extensions [here][crate::reference_docs::signed_extensions]. +//! ### transaction_extensions_extra //! -//! When it comes to constructing an extrinsic, each signed extension has two things that we are -//! interested in here: +//! This is the concatenation of the [SCALE encoded][frame::deps::codec] bytes representing first a +//! single byte describing the extension version (this is bumped whenever a change occurs in the +//! transaction extension pipeline) followed by the bytes of each of the [_transaction +//! extensions_][sp_runtime::traits::TransactionExtension], and are configured by the fourth generic +//! parameter of [`sp_runtime::generic::UncheckedExtrinsic`]. Learn more about transaction +//! extensions [here][crate::reference_docs::transaction_extensions]. //! -//! - The actual SCALE encoding of the signed extension type itself; this is what will form our -//! `signed_extensions_extra` bytes. -//! - An `AdditionalSigned` type. This is SCALE encoded into the `signed_extensions_additional` data -//! of the _signed payload_ (see below). +//! When it comes to constructing an extrinsic, each transaction extension has two things that we +//! are interested in here: +//! +//! - The actual SCALE encoding of the transaction extension type itself; this is what will form our +//! `transaction_extensions_extra` bytes. +//! - An `Implicit` type. This is SCALE encoded into the `transaction_extensions_implicit` data (see +//! below). //! //! Either (or both) of these can encode to zero bytes. //! -//! Each chain configures the set of signed extensions that it uses in its runtime configuration. -//! At the time of writing, Polkadot configures them +//! Each chain configures the set of transaction extensions that it uses in its runtime +//! configuration. At the time of writing, Polkadot configures them //! [here](https://github.com/polkadot-fellows/runtimes/blob/1dc04eb954eadf8aadb5d83990b89662dbb5a074/relay/polkadot/src/lib.rs#L1432C25-L1432C25). -//! Some of the common signed extensions are defined -//! [here][frame::deps::frame_system#signed-extensions]. +//! Some of the common transaction extensions are defined +//! [here][frame::deps::frame_system#transaction-extensions]. //! -//! Information about exactly which signed extensions are present on a chain and in what order is -//! also a part of the metadata for the chain. For V15 metadata, it can be -//! [found here][frame::deps::frame_support::__private::metadata::v15::ExtrinsicMetadata]. +//! Information about exactly which transaction extensions are present on a chain and in what order +//! is also a part of the metadata for the chain. For V15 metadata, it can be [found +//! here][frame::deps::frame_support::__private::metadata::v15::ExtrinsicMetadata]. //! //! ## call_data //! @@ -150,53 +180,63 @@ //! are typically provided as values to the inner enum. //! //! Information about the pallets that exist for a chain (including their indexes), the calls -//! available in each pallet (including their indexes), and the arguments required for each call -//! can be found in the metadata for the chain. For V15 metadata, this information -//! [is here][frame::deps::frame_support::__private::metadata::v15::PalletMetadata]. +//! available in each pallet (including their indexes), and the arguments required for each call can +//! be found in the metadata for the chain. For V15 metadata, this information [is +//! here][frame::deps::frame_support::__private::metadata::v15::PalletMetadata]. //! //! # The Signed Payload Format //! -//! All extrinsics submitted to a node from the outside world (also known as _transactions_) need to -//! be _signed_. The data that needs to be signed for some extrinsic is called the _signed payload_, -//! and its shape is described by the following pseudo-code: +//! All _signed_ extrinsics submitted to a node from the outside world (also known as +//! _transactions_) need to be _signed_. The data that needs to be signed for some extrinsic is +//! called the _signed payload_, and its shape is described by the following pseudo-code: //! //! ```text -//! signed_payload = concat( -//! call_data, -//! signed_extensions_extra, -//! signed_extensions_additional, +//! signed_payload = blake2_256( +//! concat( +//! call_data, +//! transaction_extensions_extra, +//! transaction_extensions_implicit, +//! ) //! ) -//! -//! if length(signed_payload) > 256 { -//! signed_payload = blake2_256(signed_payload) -//! } //! ``` //! -//! The bytes representing `call_data` and `signed_extensions_extra` can be obtained as described -//! above. `signed_extensions_additional` is constructed by SCALE encoding the -//! ["additional signed" data][sp_runtime::traits::SignedExtension::AdditionalSigned] for each -//! signed extension that the chain is using, in order. +//! The bytes representing `call_data` and `transaction_extensions_extra` can be obtained as +//! descibed above. `transaction_extensions_implicit` is constructed by SCALE encoding the +//! ["implicit" data][sp_runtime::traits::TransactionExtension::Implicit] for each transaction +//! extension that the chain is using, in order. +//! +//! Once we've concatenated those together, we hash the result using a Blake2 256bit hasher. +//! +//! The [`sp_runtime::generic::SignedPayload`] type takes care of assembling the correct payload for +//! us, given `call_data` and a tuple of transaction extensions. //! -//! Once we've concatenated those together, we hash the result if it's greater than 256 bytes in -//! length using a Blake2 256bit hasher. +//! # The General Transaction Format //! -//! The [`sp_runtime::generic::SignedPayload`] type takes care of assembling the correct payload -//! for us, given `call_data` and a tuple of signed extensions. +//! A General transaction does not have a signature method hardcoded in the check logic of the +//! extrinsic, such as a traditionally signed transaction. Instead, general transactions should have +//! one or more extensions in the transaction extension pipeline that auhtorize origins in some way, +//! one of which could be the traditional signature check that happens for all signed transactions +//! in the [Checkable](sp_runtime::traits::Checkable) implementation of +//! [UncheckedExtrinsic](sp_runtime::generic::UncheckedExtrinsic). Therefore, it is up to each +//! extension to define the format of the payload it will try to check and authorize the right +//! origin type. For an example, look into the [authorization example pallet +//! extensions](pallet_example_authorization_tx_extension::extensions) //! //! # Example Encoding //! -//! Using [`sp_runtime::generic::UncheckedExtrinsic`], we can construct and encode an extrinsic -//! as follows: +//! Using [`sp_runtime::generic::UncheckedExtrinsic`], we can construct and encode an extrinsic as +//! follows: #![doc = docify::embed!("./src/reference_docs/extrinsic_encoding.rs", encoding_example)] #[docify::export] pub mod call_data { use codec::{Decode, Encode}; + use sp_runtime::{traits::Dispatchable, DispatchResultWithInfo}; // The outer enum composes calls within // different pallets together. We have two // pallets, "PalletA" and "PalletB". - #[derive(Encode, Decode)] + #[derive(Encode, Decode, Clone)] pub enum Call { #[codec(index = 0)] PalletA(PalletACall), @@ -207,23 +247,33 @@ pub mod call_data { // An inner enum represents the calls within // a specific pallet. "PalletA" has one call, // "Foo". - #[derive(Encode, Decode)] + #[derive(Encode, Decode, Clone)] pub enum PalletACall { #[codec(index = 0)] Foo(String), } - #[derive(Encode, Decode)] + #[derive(Encode, Decode, Clone)] pub enum PalletBCall { #[codec(index = 0)] Bar(String), } + + impl Dispatchable for Call { + type RuntimeOrigin = (); + type Config = (); + type Info = (); + type PostInfo = (); + fn dispatch(self, _origin: Self::RuntimeOrigin) -> DispatchResultWithInfo { + Ok(()) + } + } } #[docify::export] pub mod encoding_example { use super::call_data::{Call, PalletACall}; - use crate::reference_docs::signed_extensions::signed_extensions_example; + use crate::reference_docs::transaction_extensions::transaction_extensions_example; use codec::Encode; use sp_core::crypto::AccountId32; use sp_keyring::sr25519::Keyring; @@ -232,34 +282,40 @@ pub mod encoding_example { MultiAddress, MultiSignature, }; - // Define some signed extensions to use. We'll use a couple of examples - // from the signed extensions reference doc. - type SignedExtensions = - (signed_extensions_example::AddToPayload, signed_extensions_example::AddToSignaturePayload); + // Define some transaction extensions to use. We'll use a couple of examples + // from the transaction extensions reference doc. + type TransactionExtensions = ( + transaction_extensions_example::AddToPayload, + transaction_extensions_example::AddToSignaturePayload, + ); // We'll use `UncheckedExtrinsic` to encode our extrinsic for us. We set // the address and signature type to those used on Polkadot, use our custom - // `Call` type, and use our custom set of `SignedExtensions`. - type Extrinsic = - UncheckedExtrinsic, Call, MultiSignature, SignedExtensions>; + // `Call` type, and use our custom set of `TransactionExtensions`. + type Extrinsic = UncheckedExtrinsic< + MultiAddress, + Call, + MultiSignature, + TransactionExtensions, + >; pub fn encode_demo_extrinsic() -> Vec { // The "from" address will be our Alice dev account. let from_address = MultiAddress::::Id(Keyring::Alice.to_account_id()); - // We provide some values for our expected signed extensions. - let signed_extensions = ( - signed_extensions_example::AddToPayload(1), - signed_extensions_example::AddToSignaturePayload, + // We provide some values for our expected transaction extensions. + let transaction_extensions = ( + transaction_extensions_example::AddToPayload(1), + transaction_extensions_example::AddToSignaturePayload, ); // Construct our call data: let call_data = Call::PalletA(PalletACall::Foo("Hello".to_string())); // The signed payload. This takes care of encoding the call_data, - // signed_extensions_extra and signed_extensions_additional, and hashing + // transaction_extensions_extra and transaction_extensions_implicit, and hashing // the result if it's > 256 bytes: - let signed_payload = SignedPayload::new(&call_data, signed_extensions.clone()); + let signed_payload = SignedPayload::new(call_data.clone(), transaction_extensions.clone()); // Sign the signed payload with our Alice dev account's private key, // and wrap the signature into the expected type: @@ -269,7 +325,7 @@ pub mod encoding_example { }; // Now, we can build and encode our extrinsic: - let ext = Extrinsic::new_signed(call_data, from_address, signature, signed_extensions); + let ext = Extrinsic::new_signed(call_data, from_address, signature, transaction_extensions); let encoded_ext = ext.encode(); encoded_ext diff --git a/docs/sdk/src/reference_docs/frame_benchmarking_weight.rs b/docs/sdk/src/reference_docs/frame_benchmarking_weight.rs index db77547a4bf0..cf9e58791492 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 301fa7ef83f8..1b03c6a2e35b 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 1ec9212e2306..b0aaf1789d4c 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 be464bbbf835..a22137f979dc 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 1eed9857a1d5..ec7196cea662 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` @@ -134,7 +134,7 @@ //! * [`crate::reference_docs::frame_origin`] explores further details about the usage of //! `RuntimeOrigin`. //! * [`RuntimeCall`] is a particularly interesting composite enum as it dictates the encoding of an -//! extrinsic. See [`crate::reference_docs::signed_extensions`] for more information. +//! extrinsic. See [`crate::reference_docs::transaction_extensions`] for more information. //! * See the documentation of [`construct_runtime`]. //! * See the corresponding lecture in the [pba-book](https://polkadot-blockchain-academy.github.io/pba-book/frame/outer-enum/page.html). //! 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 f9a69b892a31..065cbee25709 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 3d9edef398a0..4fbfb4a5cc83 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 523fe7043084..c93e1196ea7e 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 57b493fafa59..a76e524ceb85 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 96f92ac0c412..485614088140 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 c69c79365427..9cf5605a88ba 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. @@ -39,9 +40,12 @@ pub mod runtime_vs_smart_contract; /// Learn about how extrinsics are encoded to be transmitted to a node and stored in blocks. pub mod extrinsic_encoding; -/// Learn about the signed extensions that form a part of extrinsics. +/// Deprecated in favor of transaction extensions. pub mod signed_extensions; +/// Learn about the transaction extensions that form a part of extrinsics. +pub mod transaction_extensions; + /// Learn about *Origins*, a topic in FRAME that enables complex account abstractions to be built. pub mod frame_origin; @@ -52,8 +56,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 379b0c11b2ad..c91b66b944c6 100644 --- a/docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs +++ b/docs/sdk/src/reference_docs/runtime_vs_smart_contract.rs @@ -20,8 +20,8 @@ //! #### Smart Contracts in Substrate //! Smart Contracts are autonomous, programmable constructs deployed on the blockchain. //! In [FRAME](frame), Smart Contracts infrastructure is implemented by the -//! [`pallet_contracts`](../../../pallet_contracts/index.html) for WASM-based contracts or the -//! [`pallet_evm`](../../../pallet_evm/index.html) for EVM-compatible contracts. These pallets +//! [`pallet_contracts`] for WASM-based contracts or the +//! [`pallet_evm`](https://github.com/polkadot-evm/frontier/tree/master/frame/evm) for EVM-compatible contracts. These pallets //! enable Smart Contract developers to build applications and systems on top of a Substrate-based //! blockchain. //! @@ -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. //! @@ -115,7 +108,7 @@ //! - **Deployment and Iteration**: Smart Contracts, by nature, are designed for more //! straightforward deployment and iteration. Developers can quickly deploy contracts. //! - **Contract Code Updates**: Once deployed, although typically immutable, Smart Contracts can be -//! upgraded, but lack of migration logic. The [pallet_contracts](../../../pallet_contracts/index.html) +//! upgraded, but lack of migration logic. The [`pallet_contracts`] //! allows for contracts to be upgraded by exposing the `set_code` dispatchable. More details on this //! can be found in [Ink! documentation on upgradeable contracts](https://use.ink/basics/upgradeable-contracts). //! - **Isolated Impact**: Upgrades or changes to a smart contract generally impact only that diff --git a/docs/sdk/src/reference_docs/signed_extensions.rs b/docs/sdk/src/reference_docs/signed_extensions.rs index c644aeaa4165..6e44fea88ded 100644 --- a/docs/sdk/src/reference_docs/signed_extensions.rs +++ b/docs/sdk/src/reference_docs/signed_extensions.rs @@ -1,131 +1,2 @@ -//! Signed extensions are, briefly, a means for different chains to extend the "basic" extrinsic -//! format with custom data that can be checked by the runtime. -//! -//! # FRAME provided signed extensions -//! -//! FRAME by default already provides the following signed extensions: -//! -//! - [`CheckGenesis`](frame_system::CheckGenesis): Ensures that a transaction was sent for the same -//! network. Determined based on genesis. -//! -//! - [`CheckMortality`](frame_system::CheckMortality): Extends a transaction with a configurable -//! mortality. -//! -//! - [`CheckNonZeroSender`](frame_system::CheckNonZeroSender): Ensures that the sender of a -//! transaction is not the *all zero account* (all bytes of the accountid are zero). -//! -//! - [`CheckNonce`](frame_system::CheckNonce): Extends a transaction with a nonce to prevent replay -//! of transactions and to provide ordering of transactions. -//! -//! - [`CheckSpecVersion`](frame_system::CheckSpecVersion): Ensures that a transaction was built for -//! the currently active runtime. -//! -//! - [`CheckTxVersion`](frame_system::CheckTxVersion): Ensures that the transaction signer used the -//! correct encoding of the call. -//! -//! - [`CheckWeight`](frame_system::CheckWeight): Ensures that the transaction fits into the block -//! before dispatching it. -//! -//! - [`ChargeTransactionPayment`](pallet_transaction_payment::ChargeTransactionPayment): Charges -//! transaction fees from the signer based on the weight of the call using the native token. -//! -//! - [`ChargeAssetTxPayment`](pallet_asset_tx_payment::ChargeAssetTxPayment): Charges transaction -//! fees from the signer based on the weight of the call using any supported asset (including the -//! native token). -//! -//! - [`ChargeAssetTxPayment`(using -//! conversion)](pallet_asset_conversion_tx_payment::ChargeAssetTxPayment): Charges transaction -//! fees from the signer based on the weight of the call using any supported asset (including the -//! native token). The asset is converted to the native token using a pool. -//! -//! - [`SkipCheckIfFeeless`](pallet_skip_feeless_payment::SkipCheckIfFeeless): Allows transactions -//! to be processed without paying any fee. This requires that the `call` that should be -//! dispatched is augmented with the [`feeless_if`](frame_support::pallet_macros::feeless_if) -//! attribute. -//! -//! - [`CheckMetadataHash`](frame_metadata_hash_extension::CheckMetadataHash): Extends transactions -//! to include the so-called metadata hash. This is required by chains to support the generic -//! Ledger application and other similar offline wallets. -//! -//! - [`StorageWeightReclaim`](cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim): A -//! signed extension for parachains that reclaims unused storage weight after executing a -//! transaction. -//! -//! For more information about these extensions, follow the link to the type documentation. -//! -//! # Building a custom signed extension -//! -//! Defining a couple of very simple signed extensions looks like the following: -#![doc = docify::embed!("./src/reference_docs/signed_extensions.rs", signed_extensions_example)] - -#[docify::export] -pub mod signed_extensions_example { - use codec::{Decode, Encode}; - use scale_info::TypeInfo; - use sp_runtime::traits::SignedExtension; - - // This doesn't actually check anything, but simply allows - // some arbitrary `u32` to be added to the extrinsic payload - #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] - pub struct AddToPayload(pub u32); - - impl SignedExtension for AddToPayload { - const IDENTIFIER: &'static str = "AddToPayload"; - type AccountId = (); - type Call = (); - type AdditionalSigned = (); - type Pre = (); - - fn additional_signed( - &self, - ) -> Result< - Self::AdditionalSigned, - sp_runtime::transaction_validity::TransactionValidityError, - > { - Ok(()) - } - - fn pre_dispatch( - self, - _who: &Self::AccountId, - _call: &Self::Call, - _info: &sp_runtime::traits::DispatchInfoOf, - _len: usize, - ) -> Result { - Ok(()) - } - } - - // This is the opposite; nothing will be added to the extrinsic payload, - // but the AdditionalSigned type (`1234u32`) will be added to the - // payload to be signed. - #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] - pub struct AddToSignaturePayload; - - impl SignedExtension for AddToSignaturePayload { - const IDENTIFIER: &'static str = "AddToSignaturePayload"; - type AccountId = (); - type Call = (); - type AdditionalSigned = u32; - type Pre = (); - - fn additional_signed( - &self, - ) -> Result< - Self::AdditionalSigned, - sp_runtime::transaction_validity::TransactionValidityError, - > { - Ok(1234) - } - - fn pre_dispatch( - self, - _who: &Self::AccountId, - _call: &Self::Call, - _info: &sp_runtime::traits::DispatchInfoOf, - _len: usize, - ) -> Result { - Ok(()) - } - } -} +//! `SignedExtension`s are deprecated in favor of +//! [`TransactionExtension`s](crate::reference_docs::transaction_extensions). diff --git a/docs/sdk/src/reference_docs/trait_based_programming.rs b/docs/sdk/src/reference_docs/trait_based_programming.rs index ace313880707..90b38f63a580 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/transaction_extensions.rs b/docs/sdk/src/reference_docs/transaction_extensions.rs new file mode 100644 index 000000000000..0f8198e8372d --- /dev/null +++ b/docs/sdk/src/reference_docs/transaction_extensions.rs @@ -0,0 +1,103 @@ +//! Transaction extensions are, briefly, a means for different chains to extend the "basic" +//! extrinsic format with custom data that can be checked by the runtime. +//! +//! # FRAME provided transaction extensions +//! +//! FRAME by default already provides the following transaction extensions: +//! +//! - [`CheckGenesis`](frame_system::CheckGenesis): Ensures that a transaction was sent for the same +//! network. Determined based on genesis. +//! +//! - [`CheckMortality`](frame_system::CheckMortality): Extends a transaction with a configurable +//! mortality. +//! +//! - [`CheckNonZeroSender`](frame_system::CheckNonZeroSender): Ensures that the sender of a +//! transaction is not the *all zero account* (all bytes of the accountid are zero). +//! +//! - [`CheckNonce`](frame_system::CheckNonce): Extends a transaction with a nonce to prevent replay +//! of transactions and to provide ordering of transactions. +//! +//! - [`CheckSpecVersion`](frame_system::CheckSpecVersion): Ensures that a transaction was built for +//! the currently active runtime. +//! +//! - [`CheckTxVersion`](frame_system::CheckTxVersion): Ensures that the transaction signer used the +//! correct encoding of the call. +//! +//! - [`CheckWeight`](frame_system::CheckWeight): Ensures that the transaction fits into the block +//! before dispatching it. +//! +//! - [`ChargeTransactionPayment`](pallet_transaction_payment::ChargeTransactionPayment): Charges +//! transaction fees from the signer based on the weight of the call using the native token. +//! +//! - [`ChargeAssetTxPayment`](pallet_asset_tx_payment::ChargeAssetTxPayment): Charges transaction +//! fees from the signer based on the weight of the call using any supported asset (including the +//! native token). +//! +//! - [`ChargeAssetTxPayment`(using +//! conversion)](pallet_asset_conversion_tx_payment::ChargeAssetTxPayment): Charges transaction +//! fees from the signer based on the weight of the call using any supported asset (including the +//! native token). The asset is converted to the native token using a pool. +//! +//! - [`SkipCheckIfFeeless`](pallet_skip_feeless_payment::SkipCheckIfFeeless): Allows transactions +//! to be processed without paying any fee. This requires that the `call` that should be +//! dispatched is augmented with the [`feeless_if`](frame_support::pallet_macros::feeless_if) +//! attribute. +//! +//! - [`CheckMetadataHash`](frame_metadata_hash_extension::CheckMetadataHash): Extends transactions +//! to include the so-called metadata hash. This is required by chains to support the generic +//! Ledger application and other similar offline wallets. +//! +//! - [`StorageWeightReclaim`](cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim): A +//! transaction extension for parachains that reclaims unused storage weight after executing a +//! transaction. +//! +//! For more information about these extensions, follow the link to the type documentation. +//! +//! # Building a custom transaction extension +//! +//! Defining a couple of very simple transaction extensions looks like the following: +#![doc = docify::embed!("./src/reference_docs/transaction_extensions.rs", transaction_extensions_example)] + +#[docify::export] +pub mod transaction_extensions_example { + use codec::{Decode, Encode}; + use scale_info::TypeInfo; + use sp_runtime::{ + impl_tx_ext_default, + traits::{Dispatchable, TransactionExtension}, + transaction_validity::TransactionValidityError, + }; + + // This doesn't actually check anything, but simply allows + // some arbitrary `u32` to be added to the extrinsic payload + #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] + pub struct AddToPayload(pub u32); + + impl TransactionExtension for AddToPayload { + const IDENTIFIER: &'static str = "AddToPayload"; + type Implicit = (); + type Pre = (); + type Val = (); + + impl_tx_ext_default!(Call; weight validate prepare); + } + + // This is the opposite; nothing will be added to the extrinsic payload, + // but the Implicit type (`1234u32`) will be added to the + // payload to be signed. + #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] + pub struct AddToSignaturePayload; + + impl TransactionExtension for AddToSignaturePayload { + const IDENTIFIER: &'static str = "AddToSignaturePayload"; + type Implicit = u32; + + fn implicit(&self) -> Result { + Ok(1234) + } + type Pre = (); + type Val = (); + + impl_tx_ext_default!(Call; weight validate prepare); + } +} diff --git a/docs/sdk/src/reference_docs/umbrella_crate.rs b/docs/sdk/src/reference_docs/umbrella_crate.rs index 0b3445cfc4bc..1074cde37693 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 0e91e65c55e3..55b5cb204dc2 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/polkadot/README.md b/polkadot/README.md index 47af79a3aa92..fa14995e9af3 100644 --- a/polkadot/README.md +++ b/polkadot/README.md @@ -103,9 +103,8 @@ Connect to the global Polkadot Mainnet network by running: ../target/release/polkadot --chain=polkadot ``` -You can see your node on [telemetry] (set a custom name with `--name "my custom name"`). - -[telemetry](https://telemetry.polkadot.io/#list/Polkadot): https://telemetry.polkadot.io/#list/Polkadot +You can see your node on [Polkadot telemetry](https://telemetry.polkadot.io/#list/0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3) +(set a custom name with `--name "my custom name"`). ### Connect to the "Kusama" Canary Network @@ -115,9 +114,8 @@ Connect to the global Kusama canary network by running: ../target/release/polkadot --chain=kusama ``` -You can see your node on [telemetry] (set a custom name with `--name "my custom name"`). - -[telemetry](https://telemetry.polkadot.io/#list/Kusama): https://telemetry.polkadot.io/#list/Kusama +You can see your node on [Kusama telemetry](https://telemetry.polkadot.io/#list/0xb0a8d493285c2df73290dfb7e61f870f17b41801197a149ca93654499ea3dafe) +(set a custom name with `--name "my custom name"`). ### Connect to the Westend Testnet @@ -127,9 +125,8 @@ Connect to the global Westend testnet by running: ../target/release/polkadot --chain=westend ``` -You can see your node on [telemetry] (set a custom name with `--name "my custom name"`). - -[telemetry](https://telemetry.polkadot.io/#list/Westend): https://telemetry.polkadot.io/#list/Westend +You can see your node on [Westend telemetry](https://telemetry.polkadot.io/#list/0xe143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e) +(set a custom name with `--name "my custom name"`). ### Obtaining DOTs @@ -147,7 +144,7 @@ Then, grab the Polkadot source code: ```bash git clone https://github.com/paritytech/polkadot-sdk.git -cd polkadot +cd polkadot-sdk ``` Then build the code. You will need to build in release mode (`--release`) to start a network. Only @@ -185,7 +182,7 @@ You can run a simple single-node development "network" on your machine by runnin cargo run --bin polkadot --release -- --dev ``` -You can muck around by heading to and choose "Local Node" from the +You can muck around by heading to and choosing "Local Node" from the Settings menu. ### Local Two-node Testnet @@ -214,11 +211,11 @@ that we currently maintain. ### Using Docker -[Using Docker](../docs/contributor/docker.md) +[Using Docker](https://github.com/paritytech/polkadot-sdk/blob/master/docs/contributor/docker.md) ### Shell Completion -[Shell Completion](doc/shell-completion.md) +[Shell Completion](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/doc/shell-completion.md) ## Contributing @@ -232,4 +229,4 @@ that we currently maintain. ## License -Polkadot is [GPL 3.0 licensed](LICENSE). +Polkadot is [GPL 3.0 licensed](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/LICENSE). diff --git a/polkadot/cli/src/cli.rs b/polkadot/cli/src/cli.rs index 3e5a6ccdd3c2..eb67a3956342 100644 --- a/polkadot/cli/src/cli.rs +++ b/polkadot/cli/src/cli.rs @@ -93,12 +93,6 @@ pub struct RunCmd { #[arg(long)] pub force_authoring_backoff: bool, - /// Add the destination address to the 'Jaeger' agent. - /// - /// Must be valid socket address, of format `IP:Port` (commonly `127.0.0.1:6831`). - #[arg(long)] - pub jaeger_agent: Option, - /// Add the destination address to the `pyroscope` agent. /// /// Must be valid socket address, of format `IP:Port` (commonly `127.0.0.1:4040`). @@ -151,6 +145,13 @@ pub struct RunCmd { /// TESTING ONLY: disable the version check between nodes and workers. #[arg(long, hide = true)] pub disable_worker_version_check: bool, + + /// Enable approval-voting message processing in parallel. + /// + ///**Dangerous!** This is an experimental feature and should not be used in production, unless + /// explicitly advised to. + #[arg(long)] + pub enable_approval_voting_parallel: bool, } #[allow(missing_docs)] diff --git a/polkadot/cli/src/command.rs b/polkadot/cli/src/command.rs index 62d99122c301..d124c8fb7eb7 100644 --- a/polkadot/cli/src/command.rs +++ b/polkadot/cli/src/command.rs @@ -23,16 +23,15 @@ use polkadot_service::{ benchmarking::{benchmark_inherent_data, RemarkBuilder, TransferKeepAliveBuilder}, HeaderBackend, IdentifyVariant, }; +#[cfg(feature = "pyroscope")] +use pyroscope_pprofrs::{pprof_backend, PprofConfig}; use sc_cli::SubstrateCli; use sp_core::crypto::Ss58AddressFormatRegistry; use sp_keyring::Sr25519Keyring; -use std::net::ToSocketAddrs; pub use crate::error::Error; -#[cfg(feature = "hostperfcheck")] -pub use polkadot_performance_test::PerfCheckError; #[cfg(feature = "pyroscope")] -use pyroscope_pprofrs::{pprof_backend, PprofConfig}; +use std::net::ToSocketAddrs; type Result = std::result::Result; @@ -109,17 +108,6 @@ impl SubstrateCli for Cli { "westend-local" => Box::new(polkadot_service::chain_spec::westend_local_testnet_config()?), #[cfg(feature = "westend-native")] "westend-staging" => Box::new(polkadot_service::chain_spec::westend_staging_testnet_config()?), - #[cfg(not(feature = "westend-native"))] - name if name.starts_with("westend-") && !name.ends_with(".json") => - Err(format!("`{}` only supported with `westend-native` feature enabled.", name))?, - "wococo" => Box::new(polkadot_service::chain_spec::wococo_config()?), - #[cfg(feature = "rococo-native")] - "wococo-dev" => Box::new(polkadot_service::chain_spec::wococo_development_config()?), - #[cfg(feature = "rococo-native")] - "wococo-local" => Box::new(polkadot_service::chain_spec::wococo_local_testnet_config()?), - #[cfg(not(feature = "rococo-native"))] - name if name.starts_with("wococo-") => - Err(format!("`{}` only supported with `rococo-native` feature enabled.", name))?, #[cfg(feature = "rococo-native")] "versi-dev" => Box::new(polkadot_service::chain_spec::versi_development_config()?), #[cfg(feature = "rococo-native")] @@ -139,7 +127,6 @@ impl SubstrateCli for Cli { // chains, we use the chain spec for the specific chain. if self.run.force_rococo || chain_spec.is_rococo() || - chain_spec.is_wococo() || chain_spec.is_versi() { Box::new(polkadot_service::RococoChainSpec::from_json_file(path)?) @@ -209,18 +196,6 @@ where info!("----------------------------"); } - let jaeger_agent = if let Some(ref jaeger_agent) = cli.run.jaeger_agent { - Some( - jaeger_agent - .to_socket_addrs() - .map_err(Error::AddressResolutionFailure)? - .next() - .ok_or_else(|| Error::AddressResolutionMissing)?, - ) - } else { - None - }; - let node_version = if cli.run.disable_worker_version_check { None } else { Some(NODE_VERSION.to_string()) }; @@ -230,7 +205,7 @@ where let hwbench = (!cli.run.no_hardware_benchmarks) .then_some(config.database.path().map(|database_path| { let _ = std::fs::create_dir_all(&database_path); - sc_sysinfo::gather_hwbench(Some(database_path)) + sc_sysinfo::gather_hwbench(Some(database_path), &SUBSTRATE_REFERENCE_HARDWARE) })) .flatten(); @@ -241,7 +216,6 @@ where is_parachain_node: polkadot_service::IsParachainNode::No, enable_beefy, force_authoring_backoff: cli.run.force_authoring_backoff, - jaeger_agent, telemetry_worker_handle: None, node_version, secure_validator_mode, @@ -256,6 +230,7 @@ where execute_workers_max_num: cli.run.execute_workers_max_num, prepare_workers_hard_max_num: cli.run.prepare_workers_hard_max_num, prepare_workers_soft_max_num: cli.run.prepare_workers_soft_max_num, + enable_approval_voting_parallel: cli.run.enable_approval_voting_parallel, }, ) .map(|full| full.task_manager)?; @@ -319,7 +294,7 @@ pub fn run() -> Result<()> { runner.async_run(|mut config| { let (client, _, import_queue, task_manager) = - polkadot_service::new_chain_ops(&mut config, None)?; + polkadot_service::new_chain_ops(&mut config)?; Ok((cmd.run(client, import_queue).map_err(Error::SubstrateCli), task_manager)) }) }, @@ -331,8 +306,7 @@ pub fn run() -> Result<()> { Ok(runner.async_run(|mut config| { let (client, _, _, task_manager) = - polkadot_service::new_chain_ops(&mut config, None) - .map_err(Error::PolkadotService)?; + polkadot_service::new_chain_ops(&mut config).map_err(Error::PolkadotService)?; Ok((cmd.run(client, config.database).map_err(Error::SubstrateCli), task_manager)) })?) }, @@ -343,8 +317,7 @@ pub fn run() -> Result<()> { set_default_ss58_version(chain_spec); Ok(runner.async_run(|mut config| { - let (client, _, _, task_manager) = - polkadot_service::new_chain_ops(&mut config, None)?; + let (client, _, _, task_manager) = polkadot_service::new_chain_ops(&mut config)?; Ok((cmd.run(client, config.chain_spec).map_err(Error::SubstrateCli), task_manager)) })?) }, @@ -356,7 +329,7 @@ pub fn run() -> Result<()> { Ok(runner.async_run(|mut config| { let (client, _, import_queue, task_manager) = - polkadot_service::new_chain_ops(&mut config, None)?; + polkadot_service::new_chain_ops(&mut config)?; Ok((cmd.run(client, import_queue).map_err(Error::SubstrateCli), task_manager)) })?) }, @@ -372,17 +345,17 @@ pub fn run() -> Result<()> { Ok(runner.async_run(|mut config| { let (client, backend, _, task_manager) = - polkadot_service::new_chain_ops(&mut config, None)?; + polkadot_service::new_chain_ops(&mut config)?; + let task_handle = task_manager.spawn_handle(); let aux_revert = Box::new(|client, backend, blocks| { - polkadot_service::revert_backend(client, backend, blocks, config).map_err( - |err| { + polkadot_service::revert_backend(client, backend, blocks, config, task_handle) + .map_err(|err| { match err { polkadot_service::Error::Blockchain(err) => err.into(), // Generic application-specific error. err => sc_cli::Error::Application(err.into()), } - }, - ) + }) }); Ok(( cmd.run(client, backend, Some(aux_revert)).map_err(Error::SubstrateCli), @@ -405,22 +378,21 @@ pub fn run() -> Result<()> { .into()), #[cfg(feature = "runtime-benchmarks")] BenchmarkCmd::Storage(cmd) => runner.sync_run(|mut config| { - let (client, backend, _, _) = - polkadot_service::new_chain_ops(&mut config, None)?; + let (client, backend, _, _) = polkadot_service::new_chain_ops(&mut config)?; let db = backend.expose_db(); let storage = backend.expose_storage(); cmd.run(config, client.clone(), db, storage).map_err(Error::SubstrateCli) }), BenchmarkCmd::Block(cmd) => runner.sync_run(|mut config| { - let (client, _, _, _) = polkadot_service::new_chain_ops(&mut config, None)?; + let (client, _, _, _) = polkadot_service::new_chain_ops(&mut config)?; cmd.run(client.clone()).map_err(Error::SubstrateCli) }), // These commands are very similar and can be handled in nearly the same way. BenchmarkCmd::Extrinsic(_) | BenchmarkCmd::Overhead(_) => runner.sync_run(|mut config| { - let (client, _, _, _) = polkadot_service::new_chain_ops(&mut config, None)?; + let (client, _, _, _) = polkadot_service::new_chain_ops(&mut config)?; let header = client.header(client.info().genesis_hash).unwrap().unwrap(); let inherent_data = benchmark_inherent_data(header) .map_err(|e| format!("generating inherent data: {:?}", e))?; diff --git a/polkadot/node/collation-generation/src/lib.rs b/polkadot/node/collation-generation/src/lib.rs index d38516a4ff71..50adbddea413 100644 --- a/polkadot/node/collation-generation/src/lib.rs +++ b/polkadot/node/collation-generation/src/lib.rs @@ -45,7 +45,7 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_util::{ request_async_backing_params, request_availability_cores, request_para_backing_state, request_persisted_validation_data, request_validation_code, request_validation_code_hash, - request_validators, vstaging::fetch_claim_queue, + request_validators, runtime::fetch_claim_queue, }; use polkadot_primitives::{ collator_signature_payload, CandidateCommitments, CandidateDescriptor, CandidateReceipt, diff --git a/polkadot/node/collation-generation/src/tests.rs b/polkadot/node/collation-generation/src/tests.rs index 0feee79e763c..7f76988bb035 100644 --- a/polkadot/node/collation-generation/src/tests.rs +++ b/polkadot/node/collation-generation/src/tests.rs @@ -1090,7 +1090,6 @@ mod helpers { unpin_handle: polkadot_node_subsystem_test_helpers::mock::dummy_unpin_handle( activated_hash, ), - span: Arc::new(overseer::jaeger::Span::Disabled), }), ..Default::default() }))) diff --git a/polkadot/node/core/approval-voting-parallel/Cargo.toml b/polkadot/node/core/approval-voting-parallel/Cargo.toml new file mode 100644 index 000000000000..3a98cce80e92 --- /dev/null +++ b/polkadot/node/core/approval-voting-parallel/Cargo.toml @@ -0,0 +1,54 @@ +[package] +name = "polkadot-node-core-approval-voting-parallel" +version = "7.0.0" +authors.workspace = true +edition.workspace = true +license.workspace = true +description = "Approval Voting Subsystem running approval work in parallel" + +[lints] +workspace = true + +[dependencies] +async-trait = { workspace = true } +futures = { workspace = true } +futures-timer = { workspace = true } +gum = { workspace = true } +itertools = { workspace = true } +thiserror = { workspace = true } + +polkadot-node-core-approval-voting = { workspace = true, default-features = true } +polkadot-approval-distribution = { workspace = true, default-features = true } +polkadot-node-subsystem = { workspace = true, default-features = true } +polkadot-node-subsystem-util = { workspace = true, default-features = true } +polkadot-overseer = { workspace = true, default-features = true } +polkadot-primitives = { workspace = true, default-features = true } +polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-node-network-protocol = { workspace = true, default-features = true } +polkadot-node-metrics = { workspace = true, default-features = true } + +sc-keystore = { workspace = true, default-features = false } +sp-consensus = { workspace = true, default-features = false } +sp-consensus-slots = { workspace = true, default-features = false } +sp-application-crypto = { workspace = true, default-features = false, features = ["full_crypto"] } +sp-runtime = { workspace = true, default-features = false } + +rand = { workspace = true } +rand_core = { workspace = true } +rand_chacha = { workspace = true } + +[dev-dependencies] +async-trait = { workspace = true } +parking_lot = { workspace = true } +sp-keyring = { workspace = true, default-features = true } +sp-keystore = { workspace = true, default-features = true } +sp-core = { workspace = true, default-features = true } +sp-consensus-babe = { workspace = true, default-features = true } +sp-tracing = { workspace = true } +polkadot-node-subsystem-test-helpers = { workspace = true, default-features = true } +assert_matches = { workspace = true } +kvdb-memorydb = { workspace = true } +polkadot-primitives-test-helpers = { workspace = true, default-features = true } +log = { workspace = true, default-features = true } +polkadot-subsystem-bench = { workspace = true, default-features = true } +schnorrkel = { workspace = true, default-features = true } diff --git a/polkadot/node/core/approval-voting-parallel/src/lib.rs b/polkadot/node/core/approval-voting-parallel/src/lib.rs new file mode 100644 index 000000000000..1a7ef756bdfc --- /dev/null +++ b/polkadot/node/core/approval-voting-parallel/src/lib.rs @@ -0,0 +1,958 @@ +// 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 . + +//! The Approval Voting Parallel Subsystem. +//! +//! This subsystem is responsible for orchestrating the work done by +//! approval-voting and approval-distribution subsystem, so they can +//! do their work in parallel, rather than serially, when they are run +//! as independent subsystems. +use itertools::Itertools; +use metrics::{Meters, MetricsWatcher}; +use polkadot_node_core_approval_voting::{Config, RealAssignmentCriteria}; +use polkadot_node_metrics::metered::{ + self, channel, unbounded, MeteredReceiver, MeteredSender, UnboundedMeteredReceiver, + UnboundedMeteredSender, +}; + +use polkadot_node_primitives::{ + approval::time::{Clock, SystemClock}, + DISPUTE_WINDOW, +}; +use polkadot_node_subsystem::{ + messages::{ApprovalDistributionMessage, ApprovalVotingMessage, ApprovalVotingParallelMessage}, + overseer, FromOrchestra, SpawnedSubsystem, SubsystemError, SubsystemResult, +}; +use polkadot_node_subsystem_util::{ + self, + database::Database, + runtime::{Config as RuntimeInfoConfig, RuntimeInfo}, +}; +use polkadot_overseer::{OverseerSignal, Priority, SubsystemSender, TimeoutExt}; +use polkadot_primitives::{CandidateIndex, Hash, ValidatorIndex, ValidatorSignature}; +use rand::SeedableRng; + +use sc_keystore::LocalKeystore; +use sp_consensus::SyncOracle; + +use futures::{channel::oneshot, prelude::*, StreamExt}; +pub use metrics::Metrics; +use polkadot_node_core_approval_voting::{ + approval_db::common::Config as DatabaseConfig, ApprovalVotingWorkProvider, +}; +use std::{ + collections::{HashMap, HashSet}, + fmt::Debug, + sync::Arc, + time::Duration, +}; +use stream::{select_with_strategy, PollNext, SelectWithStrategy}; +pub mod metrics; + +#[cfg(test)] +mod tests; + +pub(crate) const LOG_TARGET: &str = "parachain::approval-voting-parallel"; +// Value rather arbitrarily: Should not be hit in practice, it exists to more easily diagnose dead +// lock issues for example. +const WAIT_FOR_SIGS_GATHER_TIMEOUT: Duration = Duration::from_millis(2000); + +/// The number of workers used for running the approval-distribution logic. +pub const APPROVAL_DISTRIBUTION_WORKER_COUNT: usize = 4; + +/// The default channel size for the workers, can be overridden by the user through +/// `overseer_channel_capacity_override` +pub const DEFAULT_WORKERS_CHANNEL_SIZE: usize = 64000 / APPROVAL_DISTRIBUTION_WORKER_COUNT; + +fn prio_right<'a>(_val: &'a mut ()) -> PollNext { + PollNext::Right +} + +/// The approval voting parallel subsystem. +pub struct ApprovalVotingParallelSubsystem { + /// `LocalKeystore` is needed for assignment keys, but not necessarily approval keys. + /// + /// We do a lot of VRF signing and need the keys to have low latency. + keystore: Arc, + db_config: DatabaseConfig, + slot_duration_millis: u64, + db: Arc, + sync_oracle: Box, + metrics: Metrics, + spawner: Arc, + clock: Arc, + overseer_message_channel_capacity_override: Option, +} + +impl ApprovalVotingParallelSubsystem { + /// Create a new approval voting subsystem with the given keystore, config, and database. + pub fn with_config( + config: Config, + db: Arc, + keystore: Arc, + sync_oracle: Box, + metrics: Metrics, + spawner: impl overseer::gen::Spawner + 'static + Clone, + overseer_message_channel_capacity_override: Option, + ) -> Self { + ApprovalVotingParallelSubsystem::with_config_and_clock( + config, + db, + keystore, + sync_oracle, + metrics, + Arc::new(SystemClock {}), + spawner, + overseer_message_channel_capacity_override, + ) + } + + /// Create a new approval voting subsystem with the given keystore, config, clock, and database. + pub fn with_config_and_clock( + config: Config, + db: Arc, + keystore: Arc, + sync_oracle: Box, + metrics: Metrics, + clock: Arc, + spawner: impl overseer::gen::Spawner + 'static, + overseer_message_channel_capacity_override: Option, + ) -> Self { + ApprovalVotingParallelSubsystem { + keystore, + slot_duration_millis: config.slot_duration_millis, + db, + db_config: DatabaseConfig { col_approval_data: config.col_approval_data }, + sync_oracle, + metrics, + spawner: Arc::new(spawner), + clock, + overseer_message_channel_capacity_override, + } + } + + /// The size of the channel used for the workers. + fn workers_channel_size(&self) -> usize { + self.overseer_message_channel_capacity_override + .unwrap_or(DEFAULT_WORKERS_CHANNEL_SIZE) + } +} + +#[overseer::subsystem(ApprovalVotingParallel, error = SubsystemError, prefix = self::overseer)] +impl ApprovalVotingParallelSubsystem { + fn start(self, ctx: Context) -> SpawnedSubsystem { + let future = run::(ctx, self) + .map_err(|e| SubsystemError::with_origin("approval-voting-parallel", e)) + .boxed(); + + SpawnedSubsystem { name: "approval-voting-parallel-subsystem", future } + } +} + +// It starts worker for the approval voting subsystem and the `APPROVAL_DISTRIBUTION_WORKER_COUNT` +// workers for the approval distribution subsystem. +// +// It returns handles that can be used to send messages to the workers. +#[overseer::contextbounds(ApprovalVotingParallel, prefix = self::overseer)] +async fn start_workers( + ctx: &mut Context, + subsystem: ApprovalVotingParallelSubsystem, + metrics_watcher: &mut MetricsWatcher, +) -> SubsystemResult<(ToWorker, Vec>)> +where +{ + gum::info!(target: LOG_TARGET, "Starting approval distribution workers"); + + // Build approval voting handles. + let (to_approval_voting_worker, approval_voting_work_provider) = build_worker_handles( + "approval-voting-parallel-db".into(), + subsystem.workers_channel_size(), + metrics_watcher, + prio_right, + ); + let mut to_approval_distribution_workers = Vec::new(); + let slot_duration_millis = subsystem.slot_duration_millis; + + for i in 0..APPROVAL_DISTRIBUTION_WORKER_COUNT { + let mut network_sender = ctx.sender().clone(); + let mut runtime_api_sender = ctx.sender().clone(); + let mut approval_distribution_to_approval_voting = to_approval_voting_worker.clone(); + + let approval_distr_instance = + polkadot_approval_distribution::ApprovalDistribution::new_with_clock( + subsystem.metrics.approval_distribution_metrics(), + subsystem.slot_duration_millis, + subsystem.clock.clone(), + Arc::new(RealAssignmentCriteria {}), + ); + let task_name = format!("approval-voting-parallel-{}", i); + let (to_approval_distribution_worker, mut approval_distribution_work_provider) = + build_worker_handles( + task_name.clone(), + subsystem.workers_channel_size(), + metrics_watcher, + prio_right, + ); + + metrics_watcher.watch(task_name.clone(), to_approval_distribution_worker.meter()); + + subsystem.spawner.spawn_blocking( + task_name.leak(), + Some("approval-voting-parallel"), + Box::pin(async move { + let mut state = + polkadot_approval_distribution::State::with_config(slot_duration_millis); + let mut rng = rand::rngs::StdRng::from_entropy(); + let mut session_info_provider = RuntimeInfo::new_with_config(RuntimeInfoConfig { + keystore: None, + session_cache_lru_size: DISPUTE_WINDOW.get(), + }); + + loop { + let message = match approval_distribution_work_provider.next().await { + Some(message) => message, + None => { + gum::info!( + target: LOG_TARGET, + "Approval distribution stream finished, most likely shutting down", + ); + break; + }, + }; + if approval_distr_instance + .handle_from_orchestra( + message, + &mut approval_distribution_to_approval_voting, + &mut network_sender, + &mut runtime_api_sender, + &mut state, + &mut rng, + &mut session_info_provider, + ) + .await + { + gum::info!( + target: LOG_TARGET, + "Approval distribution worker {}, exiting because of shutdown", i + ); + }; + } + }), + ); + to_approval_distribution_workers.push(to_approval_distribution_worker); + } + + gum::info!(target: LOG_TARGET, "Starting approval voting workers"); + + let sender = ctx.sender().clone(); + let to_approval_distribution = ApprovalVotingToApprovalDistribution(sender.clone()); + polkadot_node_core_approval_voting::start_approval_worker( + approval_voting_work_provider, + sender.clone(), + to_approval_distribution, + polkadot_node_core_approval_voting::Config { + slot_duration_millis: subsystem.slot_duration_millis, + col_approval_data: subsystem.db_config.col_approval_data, + }, + subsystem.db.clone(), + subsystem.keystore.clone(), + subsystem.sync_oracle, + subsystem.metrics.approval_voting_metrics(), + subsystem.spawner.clone(), + "approval-voting-parallel-db", + "approval-voting-parallel", + subsystem.clock.clone(), + ) + .await?; + + Ok((to_approval_voting_worker, to_approval_distribution_workers)) +} + +// The main run function of the approval parallel voting subsystem. +#[overseer::contextbounds(ApprovalVotingParallel, prefix = self::overseer)] +async fn run( + mut ctx: Context, + subsystem: ApprovalVotingParallelSubsystem, +) -> SubsystemResult<()> { + let mut metrics_watcher = MetricsWatcher::new(subsystem.metrics.clone()); + gum::info!( + target: LOG_TARGET, + "Starting workers" + ); + + let (to_approval_voting_worker, to_approval_distribution_workers) = + start_workers(&mut ctx, subsystem, &mut metrics_watcher).await?; + + gum::info!( + target: LOG_TARGET, + "Starting main subsystem loop" + ); + + run_main_loop(ctx, to_approval_voting_worker, to_approval_distribution_workers, metrics_watcher) + .await +} + +// Main loop of the subsystem, it shouldn't include any logic just dispatching of messages to +// the workers. +// +// It listens for messages from the overseer and dispatches them to the workers. +#[overseer::contextbounds(ApprovalVotingParallel, prefix = self::overseer)] +async fn run_main_loop( + mut ctx: Context, + mut to_approval_voting_worker: ToWorker, + mut to_approval_distribution_workers: Vec>, + metrics_watcher: MetricsWatcher, +) -> SubsystemResult<()> { + loop { + futures::select! { + next_msg = ctx.recv().fuse() => { + let next_msg = match next_msg { + Ok(msg) => msg, + Err(err) => { + gum::info!(target: LOG_TARGET, ?err, "Approval voting parallel subsystem received an error"); + return Err(err); + } + }; + + match next_msg { + FromOrchestra::Signal(msg) => { + if matches!(msg, OverseerSignal::ActiveLeaves(_)) { + metrics_watcher.collect_metrics(); + } + + for worker in to_approval_distribution_workers.iter_mut() { + worker + .send_signal(msg.clone()).await?; + } + + to_approval_voting_worker.send_signal(msg.clone()).await?; + if matches!(msg, OverseerSignal::Conclude) { + break; + } + }, + FromOrchestra::Communication { msg } => match msg { + // The message the approval voting subsystem would've handled. + ApprovalVotingParallelMessage::ApprovedAncestor(_, _,_) | + ApprovalVotingParallelMessage::GetApprovalSignaturesForCandidate(_, _) => { + to_approval_voting_worker.send_message( + msg.try_into().expect( + "Message is one of ApprovedAncestor, GetApprovalSignaturesForCandidate + and that can be safely converted to ApprovalVotingMessage; qed" + ) + ).await; + }, + // Now the message the approval distribution subsystem would've handled and need to + // be forwarded to the workers. + ApprovalVotingParallelMessage::NewBlocks(msg) => { + for worker in to_approval_distribution_workers.iter_mut() { + worker + .send_message( + ApprovalDistributionMessage::NewBlocks(msg.clone()), + ) + .await; + } + }, + ApprovalVotingParallelMessage::DistributeAssignment(assignment, claimed) => { + let worker = assigned_worker_for_validator(assignment.validator, &mut to_approval_distribution_workers); + worker + .send_message( + ApprovalDistributionMessage::DistributeAssignment(assignment, claimed) + ) + .await; + + }, + ApprovalVotingParallelMessage::DistributeApproval(vote) => { + let worker = assigned_worker_for_validator(vote.validator, &mut to_approval_distribution_workers); + worker + .send_message( + ApprovalDistributionMessage::DistributeApproval(vote) + ).await; + + }, + ApprovalVotingParallelMessage::NetworkBridgeUpdate(msg) => { + if let polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerMessage( + peer_id, + msg, + ) = msg + { + let (all_msgs_from_same_validator, messages_split_by_validator) = validator_index_for_msg(msg); + + for (validator_index, msg) in all_msgs_from_same_validator.into_iter().chain(messages_split_by_validator.into_iter().flatten()) { + let worker = assigned_worker_for_validator(validator_index, &mut to_approval_distribution_workers); + + worker + .send_message( + ApprovalDistributionMessage::NetworkBridgeUpdate( + polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerMessage( + peer_id, msg, + ), + ), + ).await; + } + } else { + for worker in to_approval_distribution_workers.iter_mut() { + worker + .send_message_with_priority::( + ApprovalDistributionMessage::NetworkBridgeUpdate(msg.clone()), + ).await; + } + } + }, + ApprovalVotingParallelMessage::GetApprovalSignatures(indices, tx) => { + handle_get_approval_signatures(&mut ctx, &mut to_approval_distribution_workers, indices, tx).await; + }, + ApprovalVotingParallelMessage::ApprovalCheckingLagUpdate(lag) => { + for worker in to_approval_distribution_workers.iter_mut() { + worker + .send_message( + ApprovalDistributionMessage::ApprovalCheckingLagUpdate(lag) + ).await; + } + }, + }, + }; + + }, + }; + } + Ok(()) +} + +// It sends a message to all approval workers to get the approval signatures for the requested +// candidates and then merges them all together and sends them back to the requester. +#[overseer::contextbounds(ApprovalVotingParallel, prefix = self::overseer)] +async fn handle_get_approval_signatures( + ctx: &mut Context, + to_approval_distribution_workers: &mut Vec>, + requested_candidates: HashSet<(Hash, CandidateIndex)>, + result_channel: oneshot::Sender< + HashMap, ValidatorSignature)>, + >, +) { + let mut sigs = HashMap::new(); + let mut signatures_channels = Vec::new(); + for worker in to_approval_distribution_workers.iter_mut() { + let (tx, rx) = oneshot::channel(); + worker.send_unbounded_message(ApprovalDistributionMessage::GetApprovalSignatures( + requested_candidates.clone(), + tx, + )); + signatures_channels.push(rx); + } + + let gather_signatures = async move { + let Some(results) = futures::future::join_all(signatures_channels) + .timeout(WAIT_FOR_SIGS_GATHER_TIMEOUT) + .await + else { + gum::warn!( + target: LOG_TARGET, + "Waiting for approval signatures timed out - dead lock?" + ); + return; + }; + + for result in results { + let worker_sigs = match result { + Ok(sigs) => sigs, + Err(_) => { + gum::error!( + target: LOG_TARGET, + "Getting approval signatures failed, oneshot got closed" + ); + continue; + }, + }; + sigs.extend(worker_sigs); + } + + if let Err(_) = result_channel.send(sigs) { + gum::debug!( + target: LOG_TARGET, + "Sending back approval signatures failed, oneshot got closed" + ); + } + }; + + if let Err(err) = ctx.spawn("approval-voting-gather-signatures", Box::pin(gather_signatures)) { + gum::warn!(target: LOG_TARGET, "Failed to spawn gather signatures task: {:?}", err); + } +} + +// Returns the worker that should receive the message for the given validator. +fn assigned_worker_for_validator( + validator: ValidatorIndex, + to_approval_distribution_workers: &mut Vec>, +) -> &mut ToWorker { + let worker_index = validator.0 as usize % to_approval_distribution_workers.len(); + to_approval_distribution_workers + .get_mut(worker_index) + .expect("Worker index is obtained modulo len; qed") +} + +// Returns the validators that initially created this assignments/votes, the validator index +// is later used to decide which approval-distribution worker should receive the message. +// +// Because this is on the hot path and we don't want to be unnecessarily slow, it contains two logic +// paths. The ultra fast path where all messages have the same validator index and we don't do +// any cloning or allocation and the path where we need to split the messages into multiple +// messages, because they have different validator indices, where we do need to clone and allocate. +// In practice most of the message will fall on the ultra fast path. +fn validator_index_for_msg( + msg: polkadot_node_network_protocol::ApprovalDistributionMessage, +) -> ( + Option<(ValidatorIndex, polkadot_node_network_protocol::ApprovalDistributionMessage)>, + Option>, +) { + match msg { + polkadot_node_network_protocol::Versioned::V1(ref message) => match message { + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Assignments(msgs) => + if let Ok(validator) = msgs.iter().map(|(msg, _)| msg.validator).all_equal_value() { + (Some((validator, msg)), None) + } else { + let split = msgs + .iter() + .map(|(msg, claimed_candidates)| { + ( + msg.validator, + polkadot_node_network_protocol::Versioned::V1( + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Assignments( + vec![(msg.clone(), *claimed_candidates)] + ), + ), + ) + }) + .collect_vec(); + (None, Some(split)) + }, + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Approvals(msgs) => + if let Ok(validator) = msgs.iter().map(|msg| msg.validator).all_equal_value() { + (Some((validator, msg)), None) + } else { + let split = msgs + .iter() + .map(|vote| { + ( + vote.validator, + polkadot_node_network_protocol::Versioned::V1( + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Approvals( + vec![vote.clone()] + ), + ), + ) + }) + .collect_vec(); + (None, Some(split)) + }, + }, + polkadot_node_network_protocol::Versioned::V2(ref message) => match message { + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Assignments(msgs) => + if let Ok(validator) = msgs.iter().map(|(msg, _)| msg.validator).all_equal_value() { + (Some((validator, msg)), None) + } else { + let split = msgs + .iter() + .map(|(msg, claimed_candidates)| { + ( + msg.validator, + polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Assignments( + vec![(msg.clone(), *claimed_candidates)] + ), + ), + ) + }) + .collect_vec(); + (None, Some(split)) + }, + + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Approvals(msgs) => + if let Ok(validator) = msgs.iter().map(|msg| msg.validator).all_equal_value() { + (Some((validator, msg)), None) + } else { + let split = msgs + .iter() + .map(|vote| { + ( + vote.validator, + polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Approvals( + vec![vote.clone()] + ), + ), + ) + }) + .collect_vec(); + (None, Some(split)) + }, + }, + polkadot_node_network_protocol::Versioned::V3(ref message) => match message { + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Assignments(msgs) => + if let Ok(validator) = msgs.iter().map(|(msg, _)| msg.validator).all_equal_value() { + (Some((validator, msg)), None) + } else { + let split = msgs + .iter() + .map(|(msg, claimed_candidates)| { + ( + msg.validator, + polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Assignments( + vec![(msg.clone(), claimed_candidates.clone())] + ), + ), + ) + }) + .collect_vec(); + (None, Some(split)) + }, + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Approvals(msgs) => + if let Ok(validator) = msgs.iter().map(|msg| msg.validator).all_equal_value() { + (Some((validator, msg)), None) + } else { + let split = msgs + .iter() + .map(|vote| { + ( + vote.validator, + polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Approvals( + vec![vote.clone()] + ), + ), + ) + }) + .collect_vec(); + (None, Some(split)) + }, + }, + } +} + +/// A handler object that both type of workers use for receiving work. +/// +/// In practive this is just a wrapper over two channels Receiver, that is injected into +/// approval-voting worker and approval-distribution workers. +type WorkProvider = WorkProviderImpl< + SelectWithStrategy< + MeteredReceiver>, + UnboundedMeteredReceiver>, + Clos, + State, + >, +>; + +pub struct WorkProviderImpl(T); + +impl Stream for WorkProviderImpl +where + T: Stream> + Unpin + Send, +{ + type Item = FromOrchestra; + + fn poll_next( + mut self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + self.0.poll_next_unpin(cx) + } +} + +#[async_trait::async_trait] +impl ApprovalVotingWorkProvider for WorkProviderImpl +where + T: Stream> + Unpin + Send, +{ + async fn recv(&mut self) -> SubsystemResult> { + self.0.next().await.ok_or(SubsystemError::Context( + "ApprovalVotingWorkProviderImpl: Channel closed".to_string(), + )) + } +} + +impl WorkProvider +where + M: Send + Sync + 'static, + Clos: FnMut(&mut State) -> PollNext, + State: Default, +{ + // Constructs a work providers from the channels handles. + fn from_rx_worker(rx: RxWorker, prio: Clos) -> Self { + let prioritised = select_with_strategy(rx.0, rx.1, prio); + WorkProviderImpl(prioritised) + } +} + +/// Just a wrapper for implementing `overseer::SubsystemSender` and +/// `overseer::SubsystemSender`. +/// +/// The instance of this struct can be injected into the workers, so they can talk +/// directly with each other without intermediating in this subsystem loop. +pub struct ToWorker( + MeteredSender>, + UnboundedMeteredSender>, +); + +impl Clone for ToWorker { + fn clone(&self) -> Self { + Self(self.0.clone(), self.1.clone()) + } +} + +impl ToWorker { + async fn send_signal(&mut self, signal: OverseerSignal) -> Result<(), SubsystemError> { + self.1 + .unbounded_send(FromOrchestra::Signal(signal)) + .map_err(|err| SubsystemError::QueueError(err.into_send_error())) + } + + fn meter(&self) -> Meters { + Meters::new(self.0.meter(), self.1.meter()) + } +} + +impl overseer::SubsystemSender for ToWorker { + fn send_message<'life0, 'async_trait>( + &'life0 mut self, + msg: T, + ) -> ::core::pin::Pin< + Box + ::core::marker::Send + 'async_trait>, + > + where + 'life0: 'async_trait, + Self: 'async_trait, + { + async { + if let Err(err) = + self.0.send(polkadot_overseer::FromOrchestra::Communication { msg }).await + { + gum::error!( + target: LOG_TARGET, + "Failed to send message to approval voting worker: {:?}, subsystem is probably shutting down.", + err + ); + } + } + .boxed() + } + + fn try_send_message(&mut self, msg: T) -> Result<(), metered::TrySendError> { + self.0 + .try_send(polkadot_overseer::FromOrchestra::Communication { msg }) + .map_err(|result| { + let is_full = result.is_full(); + let msg = match result.into_inner() { + polkadot_overseer::FromOrchestra::Signal(_) => + panic!("Cannot happen variant is never built"), + polkadot_overseer::FromOrchestra::Communication { msg } => msg, + }; + if is_full { + metered::TrySendError::Full(msg) + } else { + metered::TrySendError::Closed(msg) + } + }) + } + + fn send_messages<'life0, 'async_trait, I>( + &'life0 mut self, + msgs: I, + ) -> ::core::pin::Pin< + Box + ::core::marker::Send + 'async_trait>, + > + where + I: IntoIterator + Send, + I::IntoIter: Send, + I: 'async_trait, + 'life0: 'async_trait, + Self: 'async_trait, + { + async { + for msg in msgs { + self.send_message(msg).await; + } + } + .boxed() + } + + fn send_unbounded_message(&mut self, msg: T) { + if let Err(err) = + self.1.unbounded_send(polkadot_overseer::FromOrchestra::Communication { msg }) + { + gum::error!( + target: LOG_TARGET, + "Failed to send unbounded message to approval voting worker: {:?}, subsystem is probably shutting down.", + err + ); + } + } + + fn send_message_with_priority<'life0, 'async_trait, P>( + &'life0 mut self, + msg: T, + ) -> ::core::pin::Pin< + Box + ::core::marker::Send + 'async_trait>, + > + where + P: 'async_trait + Priority, + 'life0: 'async_trait, + Self: 'async_trait, + { + match P::priority() { + polkadot_overseer::PriorityLevel::Normal => self.send_message(msg), + polkadot_overseer::PriorityLevel::High => + async { self.send_unbounded_message(msg) }.boxed(), + } + } + + fn try_send_message_with_priority( + &mut self, + msg: T, + ) -> Result<(), metered::TrySendError> { + match P::priority() { + polkadot_overseer::PriorityLevel::Normal => self.try_send_message(msg), + polkadot_overseer::PriorityLevel::High => Ok(self.send_unbounded_message(msg)), + } + } +} + +/// Handles that are used by an worker to receive work. +pub struct RxWorker( + MeteredReceiver>, + UnboundedMeteredReceiver>, +); + +// Build all the necessary channels for sending messages to an worker +// and for the worker to receive them. +fn build_channels( + channel_name: String, + channel_size: usize, + metrics_watcher: &mut MetricsWatcher, +) -> (ToWorker, RxWorker) { + let (tx_work, rx_work) = channel::>(channel_size); + let (tx_work_unbounded, rx_work_unbounded) = unbounded::>(); + let to_worker = ToWorker(tx_work, tx_work_unbounded); + + metrics_watcher.watch(channel_name, to_worker.meter()); + + (to_worker, RxWorker(rx_work, rx_work_unbounded)) +} + +/// Build the worker handles used for interacting with the workers. +/// +/// `ToWorker` is used for sending messages to the workers. +/// `WorkProvider` is used by the workers for receiving the messages. +fn build_worker_handles( + channel_name: String, + channel_size: usize, + metrics_watcher: &mut MetricsWatcher, + prio_right: Clos, +) -> (ToWorker, WorkProvider) +where + M: Send + Sync + 'static, + Clos: FnMut(&mut State) -> PollNext, + State: Default, +{ + let (to_worker, rx_worker) = build_channels(channel_name, channel_size, metrics_watcher); + (to_worker, WorkProviderImpl::from_rx_worker(rx_worker, prio_right)) +} + +/// Just a wrapper for implementing `overseer::SubsystemSender`, so +/// that we can inject into the approval voting subsystem. +#[derive(Clone)] +pub struct ApprovalVotingToApprovalDistribution>( + S, +); + +impl> + overseer::SubsystemSender + for ApprovalVotingToApprovalDistribution +{ + #[allow(clippy::type_complexity, clippy::type_repetition_in_bounds)] + fn send_message<'life0, 'async_trait>( + &'life0 mut self, + msg: ApprovalDistributionMessage, + ) -> ::core::pin::Pin< + Box + ::core::marker::Send + 'async_trait>, + > + where + 'life0: 'async_trait, + Self: 'async_trait, + { + self.0.send_message(msg.into()) + } + + fn try_send_message( + &mut self, + msg: ApprovalDistributionMessage, + ) -> Result<(), metered::TrySendError> { + self.0.try_send_message(msg.into()).map_err(|err| match err { + // Safe to unwrap because it was built from the same type. + metered::TrySendError::Closed(msg) => + metered::TrySendError::Closed(msg.try_into().unwrap()), + metered::TrySendError::Full(msg) => + metered::TrySendError::Full(msg.try_into().unwrap()), + }) + } + + #[allow(clippy::type_complexity, clippy::type_repetition_in_bounds)] + fn send_messages<'life0, 'async_trait, I>( + &'life0 mut self, + msgs: I, + ) -> ::core::pin::Pin< + Box + ::core::marker::Send + 'async_trait>, + > + where + I: IntoIterator + Send, + I::IntoIter: Send, + I: 'async_trait, + 'life0: 'async_trait, + Self: 'async_trait, + { + self.0.send_messages(msgs.into_iter().map(|msg| msg.into())) + } + + fn send_unbounded_message(&mut self, msg: ApprovalDistributionMessage) { + self.0.send_unbounded_message(msg.into()) + } + + fn send_message_with_priority<'life0, 'async_trait, P>( + &'life0 mut self, + msg: ApprovalDistributionMessage, + ) -> ::core::pin::Pin< + Box + ::core::marker::Send + 'async_trait>, + > + where + P: 'async_trait + Priority, + 'life0: 'async_trait, + Self: 'async_trait, + { + self.0.send_message_with_priority::

(msg.into()) + } + + fn try_send_message_with_priority( + &mut self, + msg: ApprovalDistributionMessage, + ) -> Result<(), metered::TrySendError> { + self.0.try_send_message_with_priority::

(msg.into()).map_err(|err| match err { + // Safe to unwrap because it was built from the same type. + metered::TrySendError::Closed(msg) => + metered::TrySendError::Closed(msg.try_into().unwrap()), + metered::TrySendError::Full(msg) => + metered::TrySendError::Full(msg.try_into().unwrap()), + }) + } +} diff --git a/polkadot/node/core/approval-voting-parallel/src/metrics.rs b/polkadot/node/core/approval-voting-parallel/src/metrics.rs new file mode 100644 index 000000000000..1b4ab4bd9b88 --- /dev/null +++ b/polkadot/node/core/approval-voting-parallel/src/metrics.rs @@ -0,0 +1,236 @@ +// 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 . + +//! The Metrics for Approval Voting Parallel Subsystem. + +use std::collections::HashMap; + +use polkadot_node_metrics::{metered::Meter, metrics}; +use polkadot_overseer::prometheus; + +#[derive(Default, Clone)] +pub struct Metrics(Option); + +/// Approval Voting parallel metrics. +#[derive(Clone)] +pub struct MetricsInner { + // The inner metrics of the approval distribution workers. + approval_distribution: polkadot_approval_distribution::metrics::Metrics, + // The inner metrics of the approval voting workers. + approval_voting: polkadot_node_core_approval_voting::Metrics, + + // Time of flight metrics for bounded channels. + to_worker_bounded_tof: prometheus::HistogramVec, + // Number of elements sent to the worker's bounded queue. + to_worker_bounded_sent: prometheus::GaugeVec, + // Number of elements received by the worker's bounded queue. + to_worker_bounded_received: prometheus::GaugeVec, + // Number of times senders blocked while sending messages to the worker. + to_worker_bounded_blocked: prometheus::GaugeVec, + // Time of flight metrics for unbounded channels. + to_worker_unbounded_tof: prometheus::HistogramVec, + // Number of elements sent to the worker's unbounded queue. + to_worker_unbounded_sent: prometheus::GaugeVec, + // Number of elements received by the worker's unbounded queue. + to_worker_unbounded_received: prometheus::GaugeVec, +} + +impl Metrics { + /// Get the approval distribution metrics. + pub fn approval_distribution_metrics( + &self, + ) -> polkadot_approval_distribution::metrics::Metrics { + self.0 + .as_ref() + .map(|metrics_inner| metrics_inner.approval_distribution.clone()) + .unwrap_or_default() + } + + /// Get the approval voting metrics. + pub fn approval_voting_metrics(&self) -> polkadot_node_core_approval_voting::Metrics { + self.0 + .as_ref() + .map(|metrics_inner| metrics_inner.approval_voting.clone()) + .unwrap_or_default() + } +} + +impl metrics::Metrics for Metrics { + /// Try to register the metrics. + fn try_register( + registry: &prometheus::Registry, + ) -> std::result::Result { + Ok(Metrics(Some(MetricsInner { + approval_distribution: polkadot_approval_distribution::metrics::Metrics::try_register( + registry, + )?, + approval_voting: polkadot_node_core_approval_voting::Metrics::try_register(registry)?, + to_worker_bounded_tof: prometheus::register( + prometheus::HistogramVec::new( + prometheus::HistogramOpts::new( + "polkadot_approval_voting_parallel_worker_bounded_tof", + "Duration spent in a particular approval voting worker channel from entrance to removal", + ) + .buckets(vec![ + 0.0001, 0.0004, 0.0016, 0.0064, 0.0256, 0.1024, 0.4096, 1.6384, 3.2768, + 4.9152, 6.5536, + ]), + &["worker_name"], + )?, + registry, + )?, + to_worker_bounded_sent: prometheus::register( + prometheus::GaugeVec::::new( + prometheus::Opts::new( + "polkadot_approval_voting_parallel_worker_bounded_sent", + "Number of elements sent to approval voting workers' bounded queues", + ), + &["worker_name"], + )?, + registry, + )?, + to_worker_bounded_received: prometheus::register( + prometheus::GaugeVec::::new( + prometheus::Opts::new( + "polkadot_approval_voting_parallel_worker_bounded_received", + "Number of elements received by approval voting workers' bounded queues", + ), + &["worker_name"], + )?, + registry, + )?, + to_worker_bounded_blocked: prometheus::register( + prometheus::GaugeVec::::new( + prometheus::Opts::new( + "polkadot_approval_voting_parallel_worker_bounded_blocked", + "Number of times approval voting workers blocked while sending messages to a subsystem", + ), + &["worker_name"], + )?, + registry, + )?, + to_worker_unbounded_tof: prometheus::register( + prometheus::HistogramVec::new( + prometheus::HistogramOpts::new( + "polkadot_approval_voting_parallel_worker_unbounded_tof", + "Duration spent in a particular approval voting worker channel from entrance to removal", + ) + .buckets(vec![ + 0.0001, 0.0004, 0.0016, 0.0064, 0.0256, 0.1024, 0.4096, 1.6384, 3.2768, + 4.9152, 6.5536, + ]), + &["worker_name"], + )?, + registry, + )?, + to_worker_unbounded_sent: prometheus::register( + prometheus::GaugeVec::::new( + prometheus::Opts::new( + "polkadot_approval_voting_parallel_worker_unbounded_sent", + "Number of elements sent to approval voting workers' unbounded queues", + ), + &["worker_name"], + )?, + registry, + )?, + to_worker_unbounded_received: prometheus::register( + prometheus::GaugeVec::::new( + prometheus::Opts::new( + "polkadot_approval_voting_parallel_worker_unbounded_received", + "Number of elements received by approval voting workers' unbounded queues", + ), + &["worker_name"], + )?, + registry, + )?, + }))) + } +} + +/// The meters to watch. +#[derive(Clone)] +pub struct Meters { + bounded: Meter, + unbounded: Meter, +} + +impl Meters { + pub fn new(bounded: &Meter, unbounded: &Meter) -> Self { + Self { bounded: bounded.clone(), unbounded: unbounded.clone() } + } +} + +/// A metrics watcher that watches the meters and updates the metrics. +pub struct MetricsWatcher { + to_watch: HashMap, + metrics: Metrics, +} + +impl MetricsWatcher { + /// Create a new metrics watcher. + pub fn new(metrics: Metrics) -> Self { + Self { to_watch: HashMap::new(), metrics } + } + + /// Watch the meters of a worker with this name. + pub fn watch(&mut self, worker_name: String, meters: Meters) { + self.to_watch.insert(worker_name, meters); + } + + /// Collect all the metrics. + pub fn collect_metrics(&self) { + for (name, meter) in &self.to_watch { + let bounded_readouts = meter.bounded.read(); + let unbounded_readouts = meter.unbounded.read(); + if let Some(metrics) = self.metrics.0.as_ref() { + metrics + .to_worker_bounded_sent + .with_label_values(&[name]) + .set(bounded_readouts.sent as u64); + + metrics + .to_worker_bounded_received + .with_label_values(&[name]) + .set(bounded_readouts.received as u64); + + metrics + .to_worker_bounded_blocked + .with_label_values(&[name]) + .set(bounded_readouts.blocked as u64); + + metrics + .to_worker_unbounded_sent + .with_label_values(&[name]) + .set(unbounded_readouts.sent as u64); + + metrics + .to_worker_unbounded_received + .with_label_values(&[name]) + .set(unbounded_readouts.received as u64); + + let hist_bounded = metrics.to_worker_bounded_tof.with_label_values(&[name]); + for tof in bounded_readouts.tof { + hist_bounded.observe(tof.as_f64()); + } + + let hist_unbounded = metrics.to_worker_unbounded_tof.with_label_values(&[name]); + for tof in unbounded_readouts.tof { + hist_unbounded.observe(tof.as_f64()); + } + } + } + } +} diff --git a/polkadot/node/core/approval-voting-parallel/src/tests.rs b/polkadot/node/core/approval-voting-parallel/src/tests.rs new file mode 100644 index 000000000000..215a707147fc --- /dev/null +++ b/polkadot/node/core/approval-voting-parallel/src/tests.rs @@ -0,0 +1,1178 @@ +// 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 . + +//! The tests for Approval Voting Parallel Subsystem. + +use std::{ + collections::{HashMap, HashSet}, + future::Future, + sync::Arc, + time::Duration, +}; + +use crate::{ + build_worker_handles, metrics::MetricsWatcher, prio_right, run_main_loop, start_workers, + validator_index_for_msg, ApprovalVotingParallelSubsystem, Metrics, WorkProvider, +}; +use assert_matches::assert_matches; +use futures::{channel::oneshot, future, stream::PollNext, StreamExt}; +use itertools::Itertools; +use polkadot_node_core_approval_voting::{ApprovalVotingWorkProvider, Config}; +use polkadot_node_network_protocol::{peer_set::ValidationVersion, ObservedRole, PeerId, View}; +use polkadot_node_primitives::approval::{ + time::SystemClock, + v1::{ + AssignmentCert, AssignmentCertKind, IndirectAssignmentCert, IndirectSignedApprovalVote, + RELAY_VRF_MODULO_CONTEXT, + }, + v2::{ + AssignmentCertKindV2, AssignmentCertV2, CoreBitfield, IndirectAssignmentCertV2, + IndirectSignedApprovalVoteV2, + }, +}; +use polkadot_node_subsystem::{ + messages::{ApprovalDistributionMessage, ApprovalVotingMessage, ApprovalVotingParallelMessage}, + FromOrchestra, +}; +use polkadot_node_subsystem_test_helpers::{mock::new_leaf, TestSubsystemContext}; +use polkadot_overseer::{ActiveLeavesUpdate, OverseerSignal, SpawnGlue, TimeoutExt}; +use polkadot_primitives::{CandidateHash, CoreIndex, Hash, ValidatorIndex}; +use sc_keystore::{Keystore, LocalKeystore}; +use sp_consensus::SyncOracle; +use sp_consensus_babe::{VrfPreOutput, VrfProof, VrfSignature}; +use sp_core::{testing::TaskExecutor, H256}; +use sp_keyring::Sr25519Keyring; +type VirtualOverseer = + polkadot_node_subsystem_test_helpers::TestSubsystemContextHandle; + +const SLOT_DURATION_MILLIS: u64 = 6000; + +pub mod test_constants { + pub(crate) const DATA_COL: u32 = 0; + pub(crate) const NUM_COLUMNS: u32 = 1; +} + +fn fake_assignment_cert(block_hash: Hash, validator: ValidatorIndex) -> IndirectAssignmentCert { + let ctx = schnorrkel::signing_context(RELAY_VRF_MODULO_CONTEXT); + let msg = b"WhenParachains?"; + let mut prng = rand_core::OsRng; + let keypair = schnorrkel::Keypair::generate_with(&mut prng); + let (inout, proof, _) = keypair.vrf_sign(ctx.bytes(msg)); + let preout = inout.to_preout(); + + IndirectAssignmentCert { + block_hash, + validator, + cert: AssignmentCert { + kind: AssignmentCertKind::RelayVRFModulo { sample: 1 }, + vrf: VrfSignature { pre_output: VrfPreOutput(preout), proof: VrfProof(proof) }, + }, + } +} + +fn fake_assignment_cert_v2( + block_hash: Hash, + validator: ValidatorIndex, + core_bitfield: CoreBitfield, +) -> IndirectAssignmentCertV2 { + let ctx = schnorrkel::signing_context(RELAY_VRF_MODULO_CONTEXT); + let msg = b"WhenParachains?"; + let mut prng = rand_core::OsRng; + let keypair = schnorrkel::Keypair::generate_with(&mut prng); + let (inout, proof, _) = keypair.vrf_sign(ctx.bytes(msg)); + let preout = inout.to_preout(); + + IndirectAssignmentCertV2 { + block_hash, + validator, + cert: AssignmentCertV2 { + kind: AssignmentCertKindV2::RelayVRFModuloCompact { core_bitfield }, + vrf: VrfSignature { pre_output: VrfPreOutput(preout), proof: VrfProof(proof) }, + }, + } +} + +/// Creates a meaningless signature +pub fn dummy_signature() -> polkadot_primitives::ValidatorSignature { + sp_core::crypto::UncheckedFrom::unchecked_from([1u8; 64]) +} + +fn build_subsystem( + sync_oracle: Box, +) -> ( + ApprovalVotingParallelSubsystem, + TestSubsystemContext>, + VirtualOverseer, +) { + sp_tracing::init_for_tests(); + + let pool = sp_core::testing::TaskExecutor::new(); + let (context, virtual_overseer) = polkadot_node_subsystem_test_helpers::make_subsystem_context::< + ApprovalVotingParallelMessage, + _, + >(pool.clone()); + + let keystore = LocalKeystore::in_memory(); + let _ = keystore.sr25519_generate_new( + polkadot_primitives::PARACHAIN_KEY_TYPE_ID, + Some(&Sr25519Keyring::Alice.to_seed()), + ); + + let clock = Arc::new(SystemClock {}); + let db = kvdb_memorydb::create(test_constants::NUM_COLUMNS); + let db = polkadot_node_subsystem_util::database::kvdb_impl::DbAdapter::new(db, &[]); + + ( + ApprovalVotingParallelSubsystem::with_config_and_clock( + Config { + col_approval_data: test_constants::DATA_COL, + slot_duration_millis: SLOT_DURATION_MILLIS, + }, + Arc::new(db), + Arc::new(keystore), + sync_oracle, + Metrics::default(), + clock.clone(), + SpawnGlue(pool), + None, + ), + context, + virtual_overseer, + ) +} + +#[derive(Clone)] +struct TestSyncOracle {} + +impl SyncOracle for TestSyncOracle { + fn is_major_syncing(&self) -> bool { + false + } + + fn is_offline(&self) -> bool { + unimplemented!("not used in network bridge") + } +} + +fn test_harness( + num_approval_distro_workers: usize, + prio_right: Clos, + subsystem_gracefully_exits: bool, + test_fn: impl FnOnce( + VirtualOverseer, + WorkProvider, + Vec>, + ) -> T, +) where + T: Future, + Clos: Clone + FnMut(&mut State) -> PollNext, + State: Default, +{ + let (subsystem, context, virtual_overseer) = build_subsystem(Box::new(TestSyncOracle {})); + let mut metrics_watcher = MetricsWatcher::new(subsystem.metrics.clone()); + let channel_size = 5; + + let (to_approval_voting_worker, approval_voting_work_provider) = + build_worker_handles::( + "to_approval_voting_worker".into(), + channel_size, + &mut metrics_watcher, + prio_right.clone(), + ); + + let approval_distribution_channels = { 0..num_approval_distro_workers } + .into_iter() + .map(|worker_index| { + build_worker_handles::( + format!("to_approval_distro/{}", worker_index), + channel_size, + &mut metrics_watcher, + prio_right.clone(), + ) + }) + .collect_vec(); + + let to_approval_distribution_workers = + approval_distribution_channels.iter().map(|(tx, _)| tx.clone()).collect_vec(); + let approval_distribution_work_providers = + approval_distribution_channels.into_iter().map(|(_, rx)| rx).collect_vec(); + + let subsystem = async move { + let result = run_main_loop( + context, + to_approval_voting_worker, + to_approval_distribution_workers, + metrics_watcher, + ) + .await; + + if subsystem_gracefully_exits && result.is_err() { + result + } else { + Ok(()) + } + }; + + let test_fut = test_fn( + virtual_overseer, + approval_voting_work_provider, + approval_distribution_work_providers, + ); + + futures::pin_mut!(test_fut); + futures::pin_mut!(subsystem); + + futures::executor::block_on(future::join( + async move { + let _overseer = test_fut.await; + }, + subsystem, + )) + .1 + .unwrap(); +} + +const TIMEOUT: Duration = Duration::from_millis(2000); + +async fn overseer_signal(overseer: &mut VirtualOverseer, signal: OverseerSignal) { + overseer + .send(FromOrchestra::Signal(signal)) + .timeout(TIMEOUT) + .await + .expect(&format!("{:?} is more than enough for sending signals.", TIMEOUT)); +} + +async fn overseer_message(overseer: &mut VirtualOverseer, msg: ApprovalVotingParallelMessage) { + overseer + .send(FromOrchestra::Communication { msg }) + .timeout(TIMEOUT) + .await + .expect(&format!("{:?} is more than enough for sending signals.", TIMEOUT)); +} + +async fn run_start_workers() { + let (subsystem, mut context, _) = build_subsystem(Box::new(TestSyncOracle {})); + let mut metrics_watcher = MetricsWatcher::new(subsystem.metrics.clone()); + let _workers = start_workers(&mut context, subsystem, &mut metrics_watcher).await.unwrap(); +} + +// Test starting the workers succeeds. +#[test] +fn start_workers_succeeds() { + futures::executor::block_on(run_start_workers()); +} + +// Test main loop forwards messages to the correct worker for all type of messages. +#[test] +fn test_main_loop_forwards_correctly() { + let num_approval_distro_workers = 4; + test_harness( + num_approval_distro_workers, + prio_right, + true, + |mut overseer, mut approval_voting_work_provider, mut rx_approval_distribution_workers| async move { + // 1. Check Signals are correctly forwarded to the workers. + let signal = OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + Hash::random(), + 1, + ))); + overseer_signal(&mut overseer, signal.clone()).await; + let approval_voting_receives = approval_voting_work_provider.recv().await.unwrap(); + assert_matches!(approval_voting_receives, FromOrchestra::Signal(_)); + for rx_approval_distribution_worker in rx_approval_distribution_workers.iter_mut() { + let approval_distribution_receives = + rx_approval_distribution_worker.next().await.unwrap(); + assert_matches!(approval_distribution_receives, FromOrchestra::Signal(_)); + } + + let (test_tx, _rx) = oneshot::channel(); + let test_hash = Hash::random(); + let test_block_nr = 2; + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::ApprovedAncestor(test_hash, test_block_nr, test_tx), + ) + .await; + assert_matches!( + approval_voting_work_provider.recv().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalVotingMessage::ApprovedAncestor(hash, block_nr, _) + } => { + assert_eq!(hash, test_hash); + assert_eq!(block_nr, test_block_nr); + } + ); + for rx_approval_distribution_worker in rx_approval_distribution_workers.iter_mut() { + assert!(rx_approval_distribution_worker + .next() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + } + + // 2. Check GetApprovalSignaturesForCandidate is correctly forwarded to the workers. + let (test_tx, _rx) = oneshot::channel(); + let test_hash = CandidateHash(Hash::random()); + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::GetApprovalSignaturesForCandidate( + test_hash, test_tx, + ), + ) + .await; + + assert_matches!( + approval_voting_work_provider.recv().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalVotingMessage::GetApprovalSignaturesForCandidate(hash, _) + } => { + assert_eq!(hash, test_hash); + } + ); + + for rx_approval_distribution_worker in rx_approval_distribution_workers.iter_mut() { + assert!(rx_approval_distribution_worker + .next() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + } + + // 3. Check NewBlocks is correctly forwarded to the workers. + overseer_message(&mut overseer, ApprovalVotingParallelMessage::NewBlocks(vec![])).await; + for rx_approval_distribution_worker in rx_approval_distribution_workers.iter_mut() { + assert_matches!(rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::NewBlocks(blocks) + } => { + assert!(blocks.is_empty()); + } + ); + } + assert!(approval_voting_work_provider + .recv() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + + // 4. Check DistributeAssignment is correctly forwarded to the workers. + let validator_index = ValidatorIndex(17); + let assignment = + fake_assignment_cert_v2(Hash::random(), validator_index, CoreIndex(1).into()); + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::DistributeAssignment(assignment.clone(), 1.into()), + ) + .await; + + for (index, rx_approval_distribution_worker) in + rx_approval_distribution_workers.iter_mut().enumerate() + { + if index == validator_index.0 as usize % num_approval_distro_workers { + assert_matches!(rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::DistributeAssignment(cert, bitfield) + } => { + assert_eq!(cert, assignment); + assert_eq!(bitfield, 1.into()); + } + ); + } else { + assert!(rx_approval_distribution_worker + .next() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + } + } + assert!(approval_voting_work_provider + .recv() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + + // 5. Check DistributeApproval is correctly forwarded to the workers. + let validator_index = ValidatorIndex(26); + let expected_vote = IndirectSignedApprovalVoteV2 { + block_hash: H256::random(), + candidate_indices: 1.into(), + validator: validator_index, + signature: dummy_signature(), + }; + + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::DistributeApproval(expected_vote.clone()), + ) + .await; + + for (index, rx_approval_distribution_worker) in + rx_approval_distribution_workers.iter_mut().enumerate() + { + if index == validator_index.0 as usize % num_approval_distro_workers { + assert_matches!(rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::DistributeApproval(vote) + } => { + assert_eq!(vote, expected_vote); + } + ); + } else { + assert!(rx_approval_distribution_worker + .next() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + } + } + + // 6. Check NetworkBridgeUpdate::PeerMessage is correctly forwarded just to one of the + // workers. + let approvals = vec![ + IndirectSignedApprovalVoteV2 { + block_hash: H256::random(), + candidate_indices: 1.into(), + validator: validator_index, + signature: dummy_signature(), + }, + IndirectSignedApprovalVoteV2 { + block_hash: H256::random(), + candidate_indices: 2.into(), + validator: validator_index, + signature: dummy_signature(), + }, + ]; + let expected_msg = polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Approvals( + approvals.clone(), + ), + ); + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::NetworkBridgeUpdate( + polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerMessage( + PeerId::random(), + expected_msg.clone(), + ), + ), + ) + .await; + + for (index, rx_approval_distribution_worker) in + rx_approval_distribution_workers.iter_mut().enumerate() + { + if index == validator_index.0 as usize % num_approval_distro_workers { + assert_matches!(rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::NetworkBridgeUpdate( + polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerMessage( + _, + msg, + ), + ) + } => { + assert_eq!(msg, expected_msg); + } + ); + } else { + assert!(rx_approval_distribution_worker + .next() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + } + } + assert!(approval_voting_work_provider + .recv() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + + assert!(approval_voting_work_provider + .recv() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + + // 7. Check NetworkBridgeUpdate::PeerConnected is correctly forwarded to all workers. + let expected_peer_id = PeerId::random(); + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::NetworkBridgeUpdate( + polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerConnected( + expected_peer_id, + ObservedRole::Authority, + ValidationVersion::V3.into(), + None, + ), + ), + ) + .await; + + for rx_approval_distribution_worker in rx_approval_distribution_workers.iter_mut() { + assert_matches!(rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::NetworkBridgeUpdate( + polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerConnected( + peer_id, + role, + version, + authority_id, + ), + ) + } => { + assert_eq!(peer_id, expected_peer_id); + assert_eq!(role, ObservedRole::Authority); + assert_eq!(version, ValidationVersion::V3.into()); + assert_eq!(authority_id, None); + } + ); + } + assert!(approval_voting_work_provider + .recv() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + + // 8. Check ApprovalCheckingLagUpdate is correctly forwarded to all workers. + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::ApprovalCheckingLagUpdate(7), + ) + .await; + + for rx_approval_distribution_worker in rx_approval_distribution_workers.iter_mut() { + assert_matches!(rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::ApprovalCheckingLagUpdate( + lag + ) + } => { + assert_eq!(lag, 7); + } + ); + } + assert!(approval_voting_work_provider + .recv() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + + overseer_signal(&mut overseer, OverseerSignal::Conclude).await; + + overseer + }, + ); +} + +/// Test GetApprovalSignatures correctly gatheres the signatures from all workers. +#[test] +fn test_handle_get_approval_signatures() { + let num_approval_distro_workers = 4; + + test_harness( + num_approval_distro_workers, + prio_right, + true, + |mut overseer, mut approval_voting_work_provider, mut rx_approval_distribution_workers| async move { + let (tx, rx) = oneshot::channel(); + let first_block = Hash::random(); + let second_block = Hash::random(); + let expected_candidates: HashSet<_> = + vec![(first_block, 2), (second_block, 3)].into_iter().collect(); + + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::GetApprovalSignatures( + expected_candidates.clone(), + tx, + ), + ) + .await; + + assert!(approval_voting_work_provider + .recv() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + let mut all_votes = HashMap::new(); + for (index, rx_approval_distribution_worker) in + rx_approval_distribution_workers.iter_mut().enumerate() + { + assert_matches!(rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::GetApprovalSignatures( + candidates, tx + ) + } => { + assert_eq!(candidates, expected_candidates); + let to_send: HashMap<_, _> = {0..10}.into_iter().map(|validator| { + let validator_index = ValidatorIndex(validator as u32 * num_approval_distro_workers as u32 + index as u32); + (validator_index, (first_block, vec![2, 4], dummy_signature())) + }).collect(); + tx.send(to_send.clone()).unwrap(); + all_votes.extend(to_send.clone()); + + } + ); + } + + let received_votes = rx.await.unwrap(); + assert_eq!(received_votes, all_votes); + overseer_signal(&mut overseer, OverseerSignal::Conclude).await; + + overseer + }, + ) +} + +/// Test subsystem exits with error when approval_voting_work_provider exits. +#[test] +fn test_subsystem_exits_with_error_if_approval_voting_worker_errors() { + let num_approval_distro_workers = 4; + + test_harness( + num_approval_distro_workers, + prio_right, + false, + |overseer, approval_voting_work_provider, _rx_approval_distribution_workers| async move { + // Drop the approval_voting_work_provider to simulate an error. + std::mem::drop(approval_voting_work_provider); + + overseer + }, + ) +} + +/// Test subsystem exits with error when approval_distribution_workers exits. +#[test] +fn test_subsystem_exits_with_error_if_approval_distribution_worker_errors() { + let num_approval_distro_workers = 4; + + test_harness( + num_approval_distro_workers, + prio_right, + false, + |overseer, _approval_voting_work_provider, rx_approval_distribution_workers| async move { + // Drop the approval_distribution_workers to simulate an error. + std::mem::drop(rx_approval_distribution_workers.into_iter().next().unwrap()); + overseer + }, + ) +} + +/// Test signals sent before messages are processed in order. +#[test] +fn test_signal_before_message_keeps_receive_order() { + let num_approval_distro_workers = 4; + + test_harness( + num_approval_distro_workers, + prio_right, + true, + |mut overseer, mut approval_voting_work_provider, mut rx_approval_distribution_workers| async move { + let signal = OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + Hash::random(), + 1, + ))); + overseer_signal(&mut overseer, signal.clone()).await; + + let validator_index = ValidatorIndex(17); + let assignment = + fake_assignment_cert_v2(Hash::random(), validator_index, CoreIndex(1).into()); + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::DistributeAssignment(assignment.clone(), 1.into()), + ) + .await; + + let approval_voting_receives = approval_voting_work_provider.recv().await.unwrap(); + assert_matches!(approval_voting_receives, FromOrchestra::Signal(_)); + let rx_approval_distribution_worker = rx_approval_distribution_workers + .get_mut(validator_index.0 as usize % num_approval_distro_workers) + .unwrap(); + let approval_distribution_receives = + rx_approval_distribution_worker.next().await.unwrap(); + assert_matches!(approval_distribution_receives, FromOrchestra::Signal(_)); + assert_matches!( + rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::DistributeAssignment(_, _) + } + ); + + overseer_signal(&mut overseer, OverseerSignal::Conclude).await; + overseer + }, + ) +} + +/// Test signals sent after messages are processed with the highest priority. +#[test] +fn test_signal_is_prioritized_when_unread_messages_in_the_queue() { + let num_approval_distro_workers = 4; + + test_harness( + num_approval_distro_workers, + prio_right, + true, + |mut overseer, mut approval_voting_work_provider, mut rx_approval_distribution_workers| async move { + let validator_index = ValidatorIndex(17); + let assignment = + fake_assignment_cert_v2(Hash::random(), validator_index, CoreIndex(1).into()); + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::DistributeAssignment(assignment.clone(), 1.into()), + ) + .await; + + let signal = OverseerSignal::ActiveLeaves(ActiveLeavesUpdate::start_work(new_leaf( + Hash::random(), + 1, + ))); + overseer_signal(&mut overseer, signal.clone()).await; + + let approval_voting_receives = approval_voting_work_provider.recv().await.unwrap(); + assert_matches!(approval_voting_receives, FromOrchestra::Signal(_)); + let rx_approval_distribution_worker = rx_approval_distribution_workers + .get_mut(validator_index.0 as usize % num_approval_distro_workers) + .unwrap(); + let approval_distribution_receives = + rx_approval_distribution_worker.next().await.unwrap(); + assert_matches!(approval_distribution_receives, FromOrchestra::Signal(_)); + assert_matches!( + rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::DistributeAssignment(_, _) + } + ); + + overseer_signal(&mut overseer, OverseerSignal::Conclude).await; + overseer + }, + ) +} + +/// Test peer view updates have higher priority than normal messages. +#[test] +fn test_peer_view_is_prioritized_when_unread_messages_in_the_queue() { + let num_approval_distro_workers = 4; + + test_harness( + num_approval_distro_workers, + prio_right, + true, + |mut overseer, mut approval_voting_work_provider, mut rx_approval_distribution_workers| async move { + let validator_index = ValidatorIndex(17); + let approvals = vec![ + IndirectSignedApprovalVoteV2 { + block_hash: H256::random(), + candidate_indices: 1.into(), + validator: validator_index, + signature: dummy_signature(), + }, + IndirectSignedApprovalVoteV2 { + block_hash: H256::random(), + candidate_indices: 2.into(), + validator: validator_index, + signature: dummy_signature(), + }, + ]; + let expected_msg = polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Approvals( + approvals.clone(), + ), + ); + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::NetworkBridgeUpdate( + polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerMessage( + PeerId::random(), + expected_msg.clone(), + ), + ), + ) + .await; + + overseer_message( + &mut overseer, + ApprovalVotingParallelMessage::NetworkBridgeUpdate( + polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerViewChange( + PeerId::random(), + View::default(), + ), + ), + ) + .await; + + for (index, rx_approval_distribution_worker) in + rx_approval_distribution_workers.iter_mut().enumerate() + { + assert_matches!(rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::NetworkBridgeUpdate( + polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerViewChange( + _, + _, + ), + ) + } => { + } + ); + if index == validator_index.0 as usize % num_approval_distro_workers { + assert_matches!(rx_approval_distribution_worker.next().await.unwrap(), + FromOrchestra::Communication { + msg: ApprovalDistributionMessage::NetworkBridgeUpdate( + polkadot_node_subsystem::messages::NetworkBridgeEvent::PeerMessage( + _, + msg, + ), + ) + } => { + assert_eq!(msg, expected_msg); + } + ); + } else { + assert!(rx_approval_distribution_worker + .next() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + } + } + + assert!(approval_voting_work_provider + .recv() + .timeout(Duration::from_millis(200)) + .await + .is_none()); + + overseer_signal(&mut overseer, OverseerSignal::Conclude).await; + overseer + }, + ) +} + +// Test validator_index_for_msg with empty messages. +#[test] +fn test_validator_index_with_empty_message() { + let result = validator_index_for_msg(polkadot_node_network_protocol::Versioned::V1( + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Assignments(vec![]), + )); + + assert_eq!(result, (None, Some(vec![]))); + + let result = validator_index_for_msg(polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Assignments(vec![]), + )); + + assert_eq!(result, (None, Some(vec![]))); + + let result = validator_index_for_msg(polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Assignments(vec![]), + )); + + assert_eq!(result, (None, Some(vec![]))); + + let result = validator_index_for_msg(polkadot_node_network_protocol::Versioned::V1( + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Approvals(vec![]), + )); + + assert_eq!(result, (None, Some(vec![]))); + + let result = validator_index_for_msg(polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Approvals(vec![]), + )); + + assert_eq!(result, (None, Some(vec![]))); + + let result = validator_index_for_msg(polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Approvals(vec![]), + )); + + assert_eq!(result, (None, Some(vec![]))); +} + +// Test validator_index_for_msg when all the messages are originating from the same validator. +#[test] +fn test_validator_index_with_all_messages_from_the_same_validator() { + let validator_index = ValidatorIndex(3); + let v1_assignment = polkadot_node_network_protocol::Versioned::V1( + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Assignments(vec![ + (fake_assignment_cert(H256::random(), validator_index), 1), + (fake_assignment_cert(H256::random(), validator_index), 3), + ]), + ); + let result = validator_index_for_msg(v1_assignment.clone()); + + assert_eq!(result, (Some((validator_index, v1_assignment)), None)); + + let v1_approval = polkadot_node_network_protocol::Versioned::V1( + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Approvals(vec![ + IndirectSignedApprovalVote { + block_hash: H256::random(), + candidate_index: 1, + validator: validator_index, + signature: dummy_signature(), + }, + IndirectSignedApprovalVote { + block_hash: H256::random(), + candidate_index: 1, + validator: validator_index, + signature: dummy_signature(), + }, + ]), + ); + let result = validator_index_for_msg(v1_approval.clone()); + + assert_eq!(result, (Some((validator_index, v1_approval)), None)); + + let validator_index = ValidatorIndex(3); + let v2_assignment = polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Assignments(vec![ + (fake_assignment_cert(H256::random(), validator_index), 1), + (fake_assignment_cert(H256::random(), validator_index), 3), + ]), + ); + let result = validator_index_for_msg(v2_assignment.clone()); + + assert_eq!(result, (Some((validator_index, v2_assignment)), None)); + + let v2_approval = polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Approvals(vec![ + IndirectSignedApprovalVote { + block_hash: H256::random(), + candidate_index: 1, + validator: validator_index, + signature: dummy_signature(), + }, + IndirectSignedApprovalVote { + block_hash: H256::random(), + candidate_index: 1, + validator: validator_index, + signature: dummy_signature(), + }, + ]), + ); + let result = validator_index_for_msg(v2_approval.clone()); + + assert_eq!(result, (Some((validator_index, v2_approval)), None)); + + let validator_index = ValidatorIndex(3); + let v3_assignment = polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Assignments(vec![ + ( + fake_assignment_cert_v2(H256::random(), validator_index, CoreIndex(1).into()), + 1.into(), + ), + ( + fake_assignment_cert_v2(H256::random(), validator_index, CoreIndex(3).into()), + 3.into(), + ), + ]), + ); + let result = validator_index_for_msg(v3_assignment.clone()); + + assert_eq!(result, (Some((validator_index, v3_assignment)), None)); + + let v3_approval = polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Approvals(vec![ + IndirectSignedApprovalVoteV2 { + block_hash: H256::random(), + candidate_indices: 1.into(), + validator: validator_index, + signature: dummy_signature(), + }, + IndirectSignedApprovalVoteV2 { + block_hash: H256::random(), + candidate_indices: 1.into(), + validator: validator_index, + signature: dummy_signature(), + }, + ]), + ); + let result = validator_index_for_msg(v3_approval.clone()); + + assert_eq!(result, (Some((validator_index, v3_approval)), None)); +} + +// Test validator_index_for_msg when all the messages are originating from different validators, +// so the function should split them by validator index, so we can forward them separately to the +// worker they are assigned to. +#[test] +fn test_validator_index_with_messages_from_different_validators() { + let first_validator_index = ValidatorIndex(3); + let second_validator_index = ValidatorIndex(4); + let assignments = vec![ + (fake_assignment_cert(H256::random(), first_validator_index), 1), + (fake_assignment_cert(H256::random(), second_validator_index), 3), + ]; + let v1_assignment = polkadot_node_network_protocol::Versioned::V1( + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Assignments( + assignments.clone(), + ), + ); + let result = validator_index_for_msg(v1_assignment.clone()); + + assert_matches!(result, (None, Some(_))); + let messsages_split_by_validator = result.1.unwrap(); + assert_eq!(messsages_split_by_validator.len(), assignments.len()); + for (index, (validator_index, message)) in messsages_split_by_validator.into_iter().enumerate() + { + assert_eq!(validator_index, assignments[index].0.validator); + assert_eq!( + message, + polkadot_node_network_protocol::Versioned::V1( + polkadot_node_network_protocol::v1::ApprovalDistributionMessage::Assignments( + assignments.get(index).into_iter().cloned().collect(), + ), + ) + ); + } + + let v2_assignment = polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Assignments( + assignments.clone(), + ), + ); + let result = validator_index_for_msg(v2_assignment.clone()); + + assert_matches!(result, (None, Some(_))); + let messsages_split_by_validator = result.1.unwrap(); + assert_eq!(messsages_split_by_validator.len(), assignments.len()); + for (index, (validator_index, message)) in messsages_split_by_validator.into_iter().enumerate() + { + assert_eq!(validator_index, assignments[index].0.validator); + assert_eq!( + message, + polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Assignments( + assignments.get(index).into_iter().cloned().collect(), + ), + ) + ); + } + + let first_validator_index = ValidatorIndex(3); + let second_validator_index = ValidatorIndex(4); + let v2_assignments = vec![ + ( + fake_assignment_cert_v2(H256::random(), first_validator_index, CoreIndex(1).into()), + 1.into(), + ), + ( + fake_assignment_cert_v2(H256::random(), second_validator_index, CoreIndex(3).into()), + 3.into(), + ), + ]; + + let approvals = vec![ + IndirectSignedApprovalVote { + block_hash: H256::random(), + candidate_index: 1, + validator: first_validator_index, + signature: dummy_signature(), + }, + IndirectSignedApprovalVote { + block_hash: H256::random(), + candidate_index: 2, + validator: second_validator_index, + signature: dummy_signature(), + }, + ]; + let v2_approvals = polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Approvals( + approvals.clone(), + ), + ); + let result = validator_index_for_msg(v2_approvals.clone()); + + assert_matches!(result, (None, Some(_))); + let messsages_split_by_validator = result.1.unwrap(); + assert_eq!(messsages_split_by_validator.len(), approvals.len()); + for (index, (validator_index, message)) in messsages_split_by_validator.into_iter().enumerate() + { + assert_eq!(validator_index, approvals[index].validator); + assert_eq!( + message, + polkadot_node_network_protocol::Versioned::V2( + polkadot_node_network_protocol::v2::ApprovalDistributionMessage::Approvals( + approvals.get(index).into_iter().cloned().collect(), + ), + ) + ); + } + + let v3_assignment = polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Assignments( + v2_assignments.clone(), + ), + ); + let result = validator_index_for_msg(v3_assignment.clone()); + + assert_matches!(result, (None, Some(_))); + let messsages_split_by_validator = result.1.unwrap(); + assert_eq!(messsages_split_by_validator.len(), v2_assignments.len()); + for (index, (validator_index, message)) in messsages_split_by_validator.into_iter().enumerate() + { + assert_eq!(validator_index, v2_assignments[index].0.validator); + assert_eq!( + message, + polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Assignments( + v2_assignments.get(index).into_iter().cloned().collect(), + ), + ) + ); + } + + let approvals = vec![ + IndirectSignedApprovalVoteV2 { + block_hash: H256::random(), + candidate_indices: 1.into(), + validator: first_validator_index, + signature: dummy_signature(), + }, + IndirectSignedApprovalVoteV2 { + block_hash: H256::random(), + candidate_indices: 2.into(), + validator: second_validator_index, + signature: dummy_signature(), + }, + ]; + let v3_approvals = polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Approvals( + approvals.clone(), + ), + ); + let result = validator_index_for_msg(v3_approvals.clone()); + + assert_matches!(result, (None, Some(_))); + let messsages_split_by_validator = result.1.unwrap(); + assert_eq!(messsages_split_by_validator.len(), approvals.len()); + for (index, (validator_index, message)) in messsages_split_by_validator.into_iter().enumerate() + { + assert_eq!(validator_index, approvals[index].validator); + assert_eq!( + message, + polkadot_node_network_protocol::Versioned::V3( + polkadot_node_network_protocol::v3::ApprovalDistributionMessage::Approvals( + approvals.get(index).into_iter().cloned().collect(), + ), + ) + ); + } +} diff --git a/polkadot/node/core/approval-voting/Cargo.toml b/polkadot/node/core/approval-voting/Cargo.toml index 65985c0a5db9..2c3db866566c 100644 --- a/polkadot/node/core/approval-voting/Cargo.toml +++ b/polkadot/node/core/approval-voting/Cargo.toml @@ -22,13 +22,13 @@ kvdb = { workspace = true } derive_more = { workspace = true, default-features = true } thiserror = { workspace = true } itertools = { workspace = true } +async-trait = { workspace = true } polkadot-node-subsystem = { workspace = true, default-features = true } polkadot-node-subsystem-util = { workspace = true, default-features = true } polkadot-overseer = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } -polkadot-node-jaeger = { workspace = true, default-features = true } sc-keystore = { workspace = true } sp-consensus = { workspace = true } @@ -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 687063dd0eb3..e202d1ee229d 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 @@ -53,6 +53,7 @@ fn main() -> Result<(), String> { stop_when_approved: false, workdir_prefix: "/tmp".to_string(), num_no_shows_per_candidate: 0, + approval_voting_parallel_enabled: true, }; println!("Benchmarking..."); @@ -74,15 +75,17 @@ fn main() -> Result<(), String> { .map_err(|e| e.to_string())?; println!("{}", average_usage); - // We expect no variance for received and sent - // but use 0.001 because we operate with floats + // We expect some small variance for received and sent because the + // test messages are generated at every benchmark run and they contain + // random data so use 0.01 as the accepted variance. 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.01), + ("Sent to peers", 63995.2200, 0.01), ])); messages.extend(average_usage.check_cpu_usage(&[ - ("approval-distribution", 7.4075, 0.1), - ("approval-voting", 9.9873, 0.1), + ("approval-distribution", 0.1, 0.1), + ("approval-voting", 0.1, 0.1), + ("approval-voting-parallel", 18.0758, 0.1), ])); if messages.is_empty() { diff --git a/polkadot/node/core/approval-voting/src/approval_checking.rs b/polkadot/node/core/approval-voting/src/approval_checking.rs index 96eb25626de8..3774edc69981 100644 --- a/polkadot/node/core/approval-voting/src/approval_checking.rs +++ b/polkadot/node/core/approval-voting/src/approval_checking.rs @@ -22,9 +22,9 @@ use polkadot_primitives::ValidatorIndex; use crate::{ persisted_entries::{ApprovalEntry, CandidateEntry, TrancheEntry}, - time::Tick, MAX_RECORDED_NO_SHOW_VALIDATORS_PER_CANDIDATE, }; +use polkadot_node_primitives::approval::time::Tick; /// Result of counting the necessary tranches needed for approving a block. #[derive(Debug, PartialEq, Clone)] @@ -1195,9 +1195,9 @@ mod tests { struct NoShowTest { assignments: Vec<(ValidatorIndex, Tick)>, approvals: Vec, - clock_drift: crate::time::Tick, - no_show_duration: crate::time::Tick, - drifted_tick_now: crate::time::Tick, + clock_drift: Tick, + no_show_duration: Tick, + drifted_tick_now: Tick, exp_no_shows: usize, exp_next_no_show: Option, } diff --git a/polkadot/node/core/approval-voting/src/criteria.rs b/polkadot/node/core/approval-voting/src/criteria.rs index fb9d281e43bc..669b6001538e 100644 --- a/polkadot/node/core/approval-voting/src/criteria.rs +++ b/polkadot/node/core/approval-voting/src/criteria.rs @@ -16,8 +16,11 @@ //! Assignment criteria VRF generation and checking. -use codec::{Decode, Encode}; +use codec::Encode; use itertools::Itertools; +pub use polkadot_node_primitives::approval::criteria::{ + AssignmentCriteria, Config, InvalidAssignment, InvalidAssignmentReason, OurAssignment, +}; use polkadot_node_primitives::approval::{ self as approval_types, v1::{AssignmentCert, AssignmentCertKind, DelayTranche, RelayVRFStory}, @@ -25,9 +28,9 @@ use polkadot_node_primitives::approval::{ AssignmentCertKindV2, AssignmentCertV2, CoreBitfield, VrfPreOutput, VrfProof, VrfSignature, }, }; + use polkadot_primitives::{ - AssignmentId, AssignmentPair, CandidateHash, CoreIndex, GroupIndex, IndexedVec, SessionInfo, - ValidatorIndex, + AssignmentPair, CandidateHash, CoreIndex, GroupIndex, IndexedVec, ValidatorIndex, }; use rand::{seq::SliceRandom, SeedableRng}; use rand_chacha::ChaCha20Rng; @@ -44,56 +47,19 @@ use std::{ use super::LOG_TARGET; -/// Details pertaining to our assignment on a block. -#[derive(Debug, Clone, Encode, Decode, PartialEq)] -pub struct OurAssignment { - cert: AssignmentCertV2, - tranche: DelayTranche, - validator_index: ValidatorIndex, - // Whether the assignment has been triggered already. - triggered: bool, -} - -impl OurAssignment { - pub fn cert(&self) -> &AssignmentCertV2 { - &self.cert - } - - pub fn tranche(&self) -> DelayTranche { - self.tranche - } - - pub(crate) fn validator_index(&self) -> ValidatorIndex { - self.validator_index - } - - pub(crate) fn triggered(&self) -> bool { - self.triggered - } - - pub(crate) fn mark_triggered(&mut self) { - self.triggered = true; - } -} - impl From for OurAssignment { fn from(entry: crate::approval_db::v2::OurAssignment) -> Self { - OurAssignment { - cert: entry.cert, - tranche: entry.tranche, - validator_index: entry.validator_index, - triggered: entry.triggered, - } + OurAssignment::new(entry.cert, entry.tranche, entry.validator_index, entry.triggered) } } impl From for crate::approval_db::v2::OurAssignment { fn from(entry: OurAssignment) -> Self { Self { - cert: entry.cert, - tranche: entry.tranche, - validator_index: entry.validator_index, - triggered: entry.triggered, + tranche: entry.tranche(), + validator_index: entry.validator_index(), + triggered: entry.triggered(), + cert: entry.into_cert(), } } } @@ -223,60 +189,7 @@ fn assigned_core_transcript(core_index: CoreIndex) -> Transcript { t } -/// Information about the world assignments are being produced in. -#[derive(Clone, Debug)] -pub struct Config { - /// The assignment public keys for validators. - assignment_keys: Vec, - /// The groups of validators assigned to each core. - validator_groups: IndexedVec>, - /// The number of availability cores used by the protocol during this session. - n_cores: u32, - /// The zeroth delay tranche width. - zeroth_delay_tranche_width: u32, - /// The number of samples we do of `relay_vrf_modulo`. - relay_vrf_modulo_samples: u32, - /// The number of delay tranches in total. - n_delay_tranches: u32, -} - -impl<'a> From<&'a SessionInfo> for Config { - fn from(s: &'a SessionInfo) -> Self { - Config { - assignment_keys: s.assignment_keys.clone(), - validator_groups: s.validator_groups.clone(), - n_cores: s.n_cores, - zeroth_delay_tranche_width: s.zeroth_delay_tranche_width, - relay_vrf_modulo_samples: s.relay_vrf_modulo_samples, - n_delay_tranches: s.n_delay_tranches, - } - } -} - -/// A trait for producing and checking assignments. Used to mock. -pub(crate) trait AssignmentCriteria { - fn compute_assignments( - &self, - keystore: &LocalKeystore, - relay_vrf_story: RelayVRFStory, - config: &Config, - leaving_cores: Vec<(CandidateHash, CoreIndex, GroupIndex)>, - enable_v2_assignments: bool, - ) -> HashMap; - - fn check_assignment_cert( - &self, - claimed_core_bitfield: CoreBitfield, - validator_index: ValidatorIndex, - config: &Config, - relay_vrf_story: RelayVRFStory, - assignment: &AssignmentCertV2, - // Backing groups for each "leaving core". - backing_groups: Vec, - ) -> Result; -} - -pub(crate) struct RealAssignmentCriteria; +pub struct RealAssignmentCriteria; impl AssignmentCriteria for RealAssignmentCriteria { fn compute_assignments( @@ -469,12 +382,12 @@ fn compute_relay_vrf_modulo_assignments_v1( }; // All assignments of type RelayVRFModulo have tranche 0. - assignments.entry(core).or_insert(OurAssignment { - cert: cert.into(), - tranche: 0, + assignments.entry(core).or_insert(OurAssignment::new( + cert.into(), + 0, validator_index, - triggered: false, - }); + false, + )); } } } @@ -549,7 +462,7 @@ fn compute_relay_vrf_modulo_assignments_v2( }; // All assignments of type RelayVRFModulo have tranche 0. - OurAssignment { cert, tranche: 0, validator_index, triggered: false } + OurAssignment::new(cert, 0, validator_index, false) }) { for core_index in assigned_cores { assignments.insert(core_index, assignment.clone()); @@ -583,7 +496,7 @@ fn compute_relay_vrf_delay_assignments( }, }; - let our_assignment = OurAssignment { cert, tranche, validator_index, triggered: false }; + let our_assignment = OurAssignment::new(cert, tranche, validator_index, false); let used = match assignments.entry(core) { Entry::Vacant(e) => { @@ -591,7 +504,7 @@ fn compute_relay_vrf_delay_assignments( true }, Entry::Occupied(mut e) => - if e.get().tranche > our_assignment.tranche { + if e.get().tranche() > our_assignment.tranche() { e.insert(our_assignment); true } else { @@ -612,35 +525,6 @@ fn compute_relay_vrf_delay_assignments( } } -/// Assignment invalid. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct InvalidAssignment(pub(crate) InvalidAssignmentReason); - -impl std::fmt::Display for InvalidAssignment { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "Invalid Assignment: {:?}", self.0) - } -} - -impl std::error::Error for InvalidAssignment {} - -/// Failure conditions when checking an assignment cert. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum InvalidAssignmentReason { - ValidatorIndexOutOfBounds, - SampleOutOfBounds, - CoreIndexOutOfBounds, - InvalidAssignmentKey, - IsInBackingGroup, - VRFModuloCoreIndexMismatch, - VRFModuloOutputMismatch, - VRFDelayCoreIndexMismatch, - VRFDelayOutputMismatch, - InvalidArguments, - /// Assignment vrf check resulted in 0 assigned cores. - NullAssignment, -} - /// Checks the crypto of an assignment cert. Failure conditions: /// * Validator index out of bounds /// * VRF signature check fails @@ -820,13 +704,13 @@ fn is_in_backing_group( /// Migration helpers. impl From for OurAssignment { fn from(value: crate::approval_db::v1::OurAssignment) -> Self { - Self { - cert: value.cert.into(), - tranche: value.tranche, - validator_index: value.validator_index, + Self::new( + value.cert.into(), + value.tranche, + value.validator_index, // Whether the assignment has been triggered already. - triggered: value.triggered, - } + value.triggered, + ) } } @@ -834,7 +718,7 @@ impl From for OurAssignment { mod tests { use super::*; use crate::import::tests::garbage_vrf_signature; - use polkadot_primitives::{Hash, ASSIGNMENT_KEY_TYPE_ID}; + use polkadot_primitives::{AssignmentId, Hash, ASSIGNMENT_KEY_TYPE_ID}; use sp_application_crypto::sr25519; use sp_core::crypto::Pair as PairT; use sp_keyring::sr25519::Keyring as Sr25519Keyring; @@ -1053,7 +937,7 @@ mod tests { let mut counted = 0; for (core, assignment) in assignments { - let cores = match assignment.cert.kind.clone() { + let cores = match assignment.cert().kind.clone() { AssignmentCertKindV2::RelayVRFModuloCompact { core_bitfield } => core_bitfield, AssignmentCertKindV2::RelayVRFModulo { sample: _ } => core.into(), AssignmentCertKindV2::RelayVRFDelay { core_index } => core_index.into(), @@ -1062,7 +946,7 @@ mod tests { let mut mutated = MutatedAssignment { cores: cores.clone(), groups: cores.iter_ones().map(|core| group_for_core(core)).collect(), - cert: assignment.cert, + cert: assignment.into_cert(), own_group: GroupIndex(0), val_index: ValidatorIndex(0), config: config.clone(), diff --git a/polkadot/node/core/approval-voting/src/import.rs b/polkadot/node/core/approval-voting/src/import.rs index 3ddef1e01c45..e50a2f911489 100644 --- a/polkadot/node/core/approval-voting/src/import.rs +++ b/polkadot/node/core/approval-voting/src/import.rs @@ -28,7 +28,6 @@ //! //! We maintain a rolling window of session indices. This starts as empty -use polkadot_node_jaeger as jaeger; use polkadot_node_primitives::{ approval::{ self as approval_types, @@ -44,6 +43,7 @@ use polkadot_node_subsystem::{ overseer, RuntimeApiError, SubsystemError, SubsystemResult, }; use polkadot_node_subsystem_util::{determine_new_blocks, runtime::RuntimeInfo}; +use polkadot_overseer::SubsystemSender; use polkadot_primitives::{ node_features, BlockNumber, CandidateEvent, CandidateHash, CandidateReceipt, ConsensusLog, CoreIndex, GroupIndex, Hash, Header, SessionIndex, @@ -62,9 +62,10 @@ use crate::{ criteria::{AssignmentCriteria, OurAssignment}, get_extended_session_info, get_session_info, persisted_entries::CandidateEntry, - time::{slot_number_to_tick, Tick}, }; +use polkadot_node_primitives::approval::time::{slot_number_to_tick, Tick}; + use super::{State, LOG_TARGET}; #[derive(Debug)] @@ -110,8 +111,8 @@ enum ImportedBlockInfoError { /// Computes information about the imported block. Returns an error if the info couldn't be /// extracted. #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] -async fn imported_block_info( - ctx: &mut Context, +async fn imported_block_info>( + sender: &mut Sender, env: ImportedBlockInfoEnv<'_>, block_hash: Hash, block_header: &Header, @@ -123,11 +124,12 @@ async fn imported_block_info( // fetch candidates let included_candidates: Vec<_> = { let (c_tx, c_rx) = oneshot::channel(); - ctx.send_message(RuntimeApiMessage::Request( - block_hash, - RuntimeApiRequest::CandidateEvents(c_tx), - )) - .await; + sender + .send_message(RuntimeApiMessage::Request( + block_hash, + RuntimeApiRequest::CandidateEvents(c_tx), + )) + .await; let events: Vec = match c_rx.await { Ok(Ok(events)) => events, @@ -150,11 +152,12 @@ async fn imported_block_info( // short, that shouldn't happen. let session_index = { let (s_tx, s_rx) = oneshot::channel(); - ctx.send_message(RuntimeApiMessage::Request( - block_header.parent_hash, - RuntimeApiRequest::SessionIndexForChild(s_tx), - )) - .await; + sender + .send_message(RuntimeApiMessage::Request( + block_header.parent_hash, + RuntimeApiRequest::SessionIndexForChild(s_tx), + )) + .await; let session_index = match s_rx.await { Ok(Ok(s)) => s, @@ -200,11 +203,12 @@ async fn imported_block_info( // by one block. This gives us the opposite invariant for sessions - the parent block's // post-state gives us the canonical information about the session index for any of its // children, regardless of which slot number they might be produced at. - ctx.send_message(RuntimeApiMessage::Request( - block_hash, - RuntimeApiRequest::CurrentBabeEpoch(s_tx), - )) - .await; + sender + .send_message(RuntimeApiMessage::Request( + block_hash, + RuntimeApiRequest::CurrentBabeEpoch(s_tx), + )) + .await; match s_rx.await { Ok(Ok(s)) => s, @@ -215,7 +219,7 @@ async fn imported_block_info( }; let extended_session_info = - get_extended_session_info(env.runtime_info, ctx.sender(), block_hash, session_index).await; + get_extended_session_info(env.runtime_info, sender, block_hash, session_index).await; let enable_v2_assignments = extended_session_info.map_or(false, |extended_session_info| { *extended_session_info .node_features @@ -224,7 +228,7 @@ async fn imported_block_info( .unwrap_or(&false) }); - let session_info = get_session_info(env.runtime_info, ctx.sender(), block_hash, session_index) + let session_info = get_session_info(env.runtime_info, sender, block_hash, session_index) .await .ok_or(ImportedBlockInfoError::SessionInfoUnavailable)?; @@ -315,7 +319,6 @@ pub struct BlockImportedCandidates { pub block_hash: Hash, pub block_number: BlockNumber, pub block_tick: Tick, - pub no_show_duration: Tick, pub imported_candidates: Vec<(CandidateHash, CandidateEntry)>, } @@ -328,9 +331,15 @@ pub struct BlockImportedCandidates { /// * and return information about all candidates imported under each block. /// /// It is the responsibility of the caller to schedule wakeups for each block. -#[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] -pub(crate) async fn handle_new_head( - ctx: &mut Context, +pub(crate) async fn handle_new_head< + Sender: SubsystemSender + + SubsystemSender + + SubsystemSender, + AVSender: SubsystemSender, + B: Backend, +>( + sender: &mut Sender, + approval_voting_sender: &mut AVSender, state: &State, db: &mut OverlayedBackend<'_, B>, session_info_provider: &mut RuntimeInfo, @@ -338,17 +347,10 @@ pub(crate) async fn handle_new_head( finalized_number: &Option, ) -> SubsystemResult> { const MAX_HEADS_LOOK_BACK: BlockNumber = MAX_FINALITY_LAG; - let _handle_new_head_span = state - .spans - .get(&head) - .map(|span| span.child("handle-new-head")) - .unwrap_or_else(|| jaeger::Span::new(head, "handle-new-head")) - .with_string_tag("head", format!("{:?}", head)) - .with_stage(jaeger::Stage::ApprovalChecking); let header = { let (h_tx, h_rx) = oneshot::channel(); - ctx.send_message(ChainApiMessage::BlockHeader(head, h_tx)).await; + sender.send_message(ChainApiMessage::BlockHeader(head, h_tx)).await; match h_rx.await? { Err(e) => { gum::debug!( @@ -374,7 +376,7 @@ pub(crate) async fn handle_new_head( let lower_bound_number = finalized_number.unwrap_or(lower_bound_number).max(lower_bound_number); let new_blocks = determine_new_blocks( - ctx.sender(), + sender, |h| db.load_block_entry(h).map(|e| e.is_some()), head, &header, @@ -400,12 +402,15 @@ pub(crate) async fn handle_new_head( keystore: &state.keystore, }; - match imported_block_info(ctx, env, block_hash, &block_header, finalized_number).await { + match imported_block_info(sender, env, block_hash, &block_header, finalized_number) + .await + { Ok(i) => imported_blocks_and_info.push((block_hash, block_header, i)), Err(error) => { // It's possible that we've lost a race with finality. let (tx, rx) = oneshot::channel(); - ctx.send_message(ChainApiMessage::FinalizedBlockHash(block_header.number, tx)) + sender + .send_message(ChainApiMessage::FinalizedBlockHash(block_header.number, tx)) .await; let lost_to_finality = match rx.await { @@ -449,26 +454,13 @@ pub(crate) async fn handle_new_head( force_approve, } = imported_block_info; - let session_info = match get_session_info( - session_info_provider, - ctx.sender(), - head, - session_index, - ) - .await - { - Some(session_info) => session_info, - None => return Ok(Vec::new()), - }; + let session_info = + match get_session_info(session_info_provider, sender, head, session_index).await { + Some(session_info) => session_info, + None => return Ok(Vec::new()), + }; - let (block_tick, no_show_duration) = { - let block_tick = slot_number_to_tick(state.slot_duration_millis, slot); - let no_show_duration = slot_number_to_tick( - state.slot_duration_millis, - Slot::from(u64::from(session_info.no_show_slots)), - ); - (block_tick, no_show_duration) - }; + let block_tick = slot_number_to_tick(state.slot_duration_millis, slot); let needed_approvals = session_info.needed_approvals; let validator_group_lens: Vec = @@ -509,7 +501,7 @@ pub(crate) async fn handle_new_head( }; // If all bits are already set, then send an approve message. if approved_bitfield.count_ones() == approved_bitfield.len() { - ctx.send_message(ChainSelectionMessage::Approved(block_hash)).await; + sender.send_message(ChainSelectionMessage::Approved(block_hash)).await; } let block_entry = v3::BlockEntry { @@ -566,7 +558,7 @@ pub(crate) async fn handle_new_head( // Notify chain-selection of all approved hashes. for hash in approved_hashes { - ctx.send_message(ChainSelectionMessage::Approved(hash)).await; + sender.send_message(ChainSelectionMessage::Approved(hash)).await; } } @@ -574,16 +566,19 @@ pub(crate) async fn handle_new_head( hash: block_hash, number: block_header.number, parent_hash: block_header.parent_hash, - candidates: included_candidates.iter().map(|(hash, _, _, _)| *hash).collect(), + candidates: included_candidates + .iter() + .map(|(hash, _, core_index, group_index)| (*hash, *core_index, *group_index)) + .collect(), slot, session: session_index, + vrf_story: relay_vrf_story, }); imported_candidates.push(BlockImportedCandidates { block_hash, block_number: block_header.number, block_tick, - no_show_duration, imported_candidates: candidate_entries .into_iter() .map(|(h, e)| (h, e.into())) @@ -598,7 +593,8 @@ pub(crate) async fn handle_new_head( "Informing distribution of newly imported chain", ); - ctx.send_unbounded_message(ApprovalDistributionMessage::NewBlocks(approval_meta)); + approval_voting_sender + .send_unbounded_message(ApprovalDistributionMessage::NewBlocks(approval_meta)); Ok(imported_candidates) } @@ -609,12 +605,16 @@ pub(crate) mod tests { approval_db::common::{load_block_entry, DbBackend}, RuntimeInfo, RuntimeInfoConfig, MAX_BLOCKS_WITH_ASSIGNMENT_TIMESTAMPS, }; + use approval_types::time::Clock; use assert_matches::assert_matches; use polkadot_node_primitives::{ approval::v1::{VrfSignature, VrfTranscript}, DISPUTE_WINDOW, }; - use polkadot_node_subsystem::messages::{AllMessages, ApprovalVotingMessage}; + use polkadot_node_subsystem::{ + messages::{AllMessages, ApprovalVotingMessage}, + SubsystemContext, + }; use polkadot_node_subsystem_test_helpers::make_subsystem_context; use polkadot_node_subsystem_util::database::Database; use polkadot_primitives::{ @@ -642,7 +642,7 @@ pub(crate) mod tests { #[derive(Default)] struct MockClock; - impl crate::time::Clock for MockClock { + impl Clock for MockClock { fn tick_now(&self) -> Tick { 42 // chosen by fair dice roll } @@ -656,9 +656,8 @@ pub(crate) mod tests { State { keystore: Arc::new(LocalKeystore::in_memory()), slot_duration_millis: 6_000, - clock: Box::new(MockClock::default()), + clock: Arc::new(MockClock::default()), assignment_criteria: Box::new(MockAssignmentCriteria::default()), - spans: HashMap::new(), per_block_assignments_gathering_times: LruMap::new(ByLength::new( MAX_BLOCKS_WITH_ASSIGNMENT_TIMESTAMPS, )), @@ -800,8 +799,9 @@ pub(crate) mod tests { keystore: &LocalKeystore::in_memory(), }; - let info = - imported_block_info(&mut ctx, env, hash, &header, &Some(4)).await.unwrap(); + let info = imported_block_info(ctx.sender(), env, hash, &header, &Some(4)) + .await + .unwrap(); assert_eq!(info.included_candidates, included_candidates); assert_eq!(info.session_index, session); @@ -947,7 +947,7 @@ pub(crate) mod tests { keystore: &LocalKeystore::in_memory(), }; - let info = imported_block_info(&mut ctx, env, hash, &header, &Some(4)).await; + let info = imported_block_info(ctx.sender(), env, hash, &header, &Some(4)).await; assert_matches!(info, Err(ImportedBlockInfoError::VrfInfoUnavailable)); }) @@ -1086,7 +1086,7 @@ pub(crate) mod tests { keystore: &LocalKeystore::in_memory(), }; - let info = imported_block_info(&mut ctx, env, hash, &header, &Some(6)).await; + let info = imported_block_info(ctx.sender(), env, hash, &header, &Some(6)).await; assert_matches!(info, Err(ImportedBlockInfoError::BlockAlreadyFinalized)); }) @@ -1122,7 +1122,8 @@ pub(crate) mod tests { #[test] fn imported_block_info_extracts_force_approve() { let pool = TaskExecutor::new(); - let (mut ctx, mut handle) = make_subsystem_context(pool.clone()); + let (mut ctx, mut handle) = + make_subsystem_context::(pool.clone()); let session = 5; let session_info = dummy_session_info(session); @@ -1185,7 +1186,7 @@ pub(crate) mod tests { }; let info = - imported_block_info(&mut ctx, env, hash, &header, &Some(4)).await.unwrap(); + imported_block_info(ctx.sender(), env, hash, &header, &Some(4)).await.unwrap(); assert_eq!(info.included_candidates, included_candidates); assert_eq!(info.session_index, session); @@ -1378,8 +1379,11 @@ pub(crate) mod tests { let test_fut = { Box::pin(async move { let mut overlay_db = OverlayedBackend::new(&db); + + let mut approval_voting_sender = ctx.sender().clone(); let result = handle_new_head( - &mut ctx, + ctx.sender(), + &mut approval_voting_sender, &state, &mut overlay_db, &mut session_info_provider, diff --git a/polkadot/node/core/approval-voting/src/lib.rs b/polkadot/node/core/approval-voting/src/lib.rs index d4b6855a44d0..0cb977c58021 100644 --- a/polkadot/node/core/approval-voting/src/lib.rs +++ b/polkadot/node/core/approval-voting/src/lib.rs @@ -21,9 +21,6 @@ //! of others. It uses this information to determine when candidates and blocks have //! been sufficiently approved to finalize. -use itertools::Itertools; -use jaeger::{hash_to_trace_identifier, PerLeafSpan}; -use polkadot_node_jaeger as jaeger; use polkadot_node_primitives::{ approval::{ v1::{BlockApprovalMeta, DelayTranche}, @@ -40,8 +37,9 @@ use polkadot_node_subsystem::{ ApprovalCheckError, ApprovalCheckResult, ApprovalDistributionMessage, ApprovalVotingMessage, AssignmentCheckError, AssignmentCheckResult, AvailabilityRecoveryMessage, BlockDescription, CandidateValidationMessage, ChainApiMessage, - ChainSelectionMessage, DisputeCoordinatorMessage, HighestApprovedAncestorBlock, - RuntimeApiMessage, RuntimeApiRequest, + ChainSelectionMessage, CheckedIndirectAssignment, CheckedIndirectSignedApprovalVote, + DisputeCoordinatorMessage, HighestApprovedAncestorBlock, PvfExecKind, RuntimeApiMessage, + RuntimeApiRequest, }, overseer, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, SubsystemResult, SubsystemSender, @@ -55,9 +53,8 @@ use polkadot_node_subsystem_util::{ }; use polkadot_primitives::{ ApprovalVoteMultipleCandidates, ApprovalVotingParams, BlockNumber, CandidateHash, - CandidateIndex, CandidateReceipt, CoreIndex, DisputeStatement, ExecutorParams, GroupIndex, - Hash, PvfExecKind, SessionIndex, SessionInfo, ValidDisputeStatementKind, ValidatorId, - ValidatorIndex, ValidatorPair, ValidatorSignature, + CandidateIndex, CandidateReceipt, CoreIndex, ExecutorParams, GroupIndex, Hash, SessionIndex, + SessionInfo, ValidatorId, ValidatorIndex, ValidatorPair, ValidatorSignature, }; use sc_keystore::LocalKeystore; use sp_application_crypto::Pair; @@ -91,9 +88,11 @@ use schnellru::{ByLength, LruMap}; use approval_checking::RequiredTranches; use bitvec::{order::Lsb0, vec::BitVec}; -use criteria::{AssignmentCriteria, RealAssignmentCriteria}; +pub use criteria::{AssignmentCriteria, Config as AssignmentConfig, RealAssignmentCriteria}; use persisted_entries::{ApprovalEntry, BlockEntry, CandidateEntry}; -use time::{slot_number_to_tick, Clock, ClockExt, DelayedApprovalTimer, SystemClock, Tick}; +use polkadot_node_primitives::approval::time::{ + slot_number_to_tick, Clock, ClockExt, DelayedApprovalTimer, SystemClock, Tick, +}; mod approval_checking; pub mod approval_db; @@ -102,7 +101,6 @@ pub mod criteria; mod import; mod ops; mod persisted_entries; -pub mod time; use crate::{ approval_checking::{Check, TranchesToApproveResult}, @@ -123,7 +121,6 @@ const APPROVAL_CHECKING_TIMEOUT: Duration = Duration::from_secs(120); const WAIT_FOR_SIGS_TIMEOUT: Duration = Duration::from_millis(500); const APPROVAL_CACHE_SIZE: u32 = 1024; -const TICK_TOO_FAR_IN_FUTURE: Tick = 20; // 10 seconds. const APPROVAL_DELAY: Tick = 2; pub(crate) const LOG_TARGET: &str = "parachain::approval-voting"; @@ -165,7 +162,8 @@ pub struct ApprovalVotingSubsystem { db: Arc, mode: Mode, metrics: Metrics, - clock: Box, + clock: Arc, + spawner: Arc, } #[derive(Clone)] @@ -484,6 +482,7 @@ impl ApprovalVotingSubsystem { keystore: Arc, sync_oracle: Box, metrics: Metrics, + spawner: Arc, ) -> Self { ApprovalVotingSubsystem::with_config_and_clock( config, @@ -491,7 +490,8 @@ impl ApprovalVotingSubsystem { keystore, sync_oracle, metrics, - Box::new(SystemClock {}), + Arc::new(SystemClock {}), + spawner, ) } @@ -502,7 +502,8 @@ impl ApprovalVotingSubsystem { keystore: Arc, sync_oracle: Box, metrics: Metrics, - clock: Box, + clock: Arc, + spawner: Arc, ) -> Self { ApprovalVotingSubsystem { keystore, @@ -512,6 +513,7 @@ impl ApprovalVotingSubsystem { mode: Mode::Syncing(sync_oracle), metrics, clock, + spawner, } } @@ -551,12 +553,21 @@ fn db_sanity_check(db: Arc, config: DatabaseConfig) -> SubsystemRe #[overseer::subsystem(ApprovalVoting, error = SubsystemError, prefix = self::overseer)] impl ApprovalVotingSubsystem { - fn start(self, ctx: Context) -> SpawnedSubsystem { + fn start(self, mut ctx: Context) -> SpawnedSubsystem { let backend = DbBackend::new(self.db.clone(), self.db_config); - let future = - run::(ctx, self, Box::new(RealAssignmentCriteria), backend) - .map_err(|e| SubsystemError::with_origin("approval-voting", e)) - .boxed(); + let to_other_subsystems = ctx.sender().clone(); + let to_approval_distr = ctx.sender().clone(); + + let future = run::( + ctx, + to_other_subsystems, + to_approval_distr, + self, + Box::new(RealAssignmentCriteria), + backend, + ) + .map_err(|e| SubsystemError::with_origin("approval-voting", e)) + .boxed(); SpawnedSubsystem { name: "approval-voting-subsystem", future } } @@ -620,11 +631,7 @@ impl Wakeups { self.wakeups.entry(tick).or_default().push((block_hash, candidate_hash)); } - fn prune_finalized_wakeups( - &mut self, - finalized_number: BlockNumber, - spans: &mut HashMap, - ) { + fn prune_finalized_wakeups(&mut self, finalized_number: BlockNumber) { let after = self.block_numbers.split_off(&(finalized_number + 1)); let pruned_blocks: HashSet<_> = std::mem::replace(&mut self.block_numbers, after) .into_iter() @@ -648,9 +655,6 @@ impl Wakeups { } } } - - // Remove all spans that are associated with pruned blocks. - spans.retain(|h, _| !pruned_blocks.contains(h)); } // Get the wakeup for a particular block/candidate combo, if any. @@ -825,9 +829,8 @@ where struct State { keystore: Arc, slot_duration_millis: u64, - clock: Box, + clock: Arc, assignment_criteria: Box, - spans: HashMap, // Per block, candidate records about how long we take until we gather enough // assignments, this is relevant because it gives us a good idea about how many // tranches we trigger and why. @@ -961,20 +964,20 @@ impl State { } // Returns the approval voting params from the RuntimeApi. - #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] - async fn get_approval_voting_params_or_default( + async fn get_approval_voting_params_or_default>( &self, - ctx: &mut Context, + sender: &mut Sender, session_index: SessionIndex, block_hash: Hash, ) -> Option { let (s_tx, s_rx) = oneshot::channel(); - ctx.send_message(RuntimeApiMessage::Request( - block_hash, - RuntimeApiRequest::ApprovalVotingParams(session_index, s_tx), - )) - .await; + sender + .send_message(RuntimeApiMessage::Request( + block_hash, + RuntimeApiRequest::ApprovalVotingParams(session_index, s_tx), + )) + .await; match s_rx.await { Ok(Ok(params)) => { @@ -1143,9 +1146,36 @@ enum Action { Conclude, } +/// Trait for providing approval voting subsystem with work. +#[async_trait::async_trait] +pub trait ApprovalVotingWorkProvider { + async fn recv(&mut self) -> SubsystemResult>; +} + +#[async_trait::async_trait] #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] -async fn run( - mut ctx: Context, +impl ApprovalVotingWorkProvider for Context { + async fn recv(&mut self) -> SubsystemResult> { + self.recv().await + } +} + +#[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] +async fn run< + B, + WorkProvider: ApprovalVotingWorkProvider, + Sender: SubsystemSender + + SubsystemSender + + SubsystemSender + + SubsystemSender + + SubsystemSender + + SubsystemSender + + Clone, + ADSender: SubsystemSender, +>( + mut work_provider: WorkProvider, + mut to_other_subsystems: Sender, + mut to_approval_distr: ADSender, mut subsystem: ApprovalVotingSubsystem, assignment_criteria: Box, mut backend: B, @@ -1162,26 +1192,17 @@ where slot_duration_millis: subsystem.slot_duration_millis, clock: subsystem.clock, assignment_criteria, - spans: HashMap::new(), per_block_assignments_gathering_times: LruMap::new(ByLength::new( MAX_BLOCKS_WITH_ASSIGNMENT_TIMESTAMPS, )), no_show_stats: NoShowStats::default(), }; - // `None` on start-up. Gets initialized/updated on leaf update - let mut session_info_provider = RuntimeInfo::new_with_config(RuntimeInfoConfig { - keystore: None, - session_cache_lru_size: DISPUTE_WINDOW.get(), - }); - let mut wakeups = Wakeups::default(); - let mut currently_checking_set = CurrentlyCheckingSet::default(); - let mut delayed_approvals_timers = DelayedApprovalTimer::default(); - let mut approvals_cache = LruMap::new(ByLength::new(APPROVAL_CACHE_SIZE)); - let mut last_finalized_height: Option = { let (tx, rx) = oneshot::channel(); - ctx.send_message(ChainApiMessage::FinalizedBlockNumber(tx)).await; + to_other_subsystems + .send_message(ChainApiMessage::FinalizedBlockNumber(tx)) + .await; match rx.await? { Ok(number) => Some(number), Err(err) => { @@ -1191,13 +1212,24 @@ where } }; + // `None` on start-up. Gets initialized/updated on leaf update + let mut session_info_provider = RuntimeInfo::new_with_config(RuntimeInfoConfig { + keystore: None, + session_cache_lru_size: DISPUTE_WINDOW.get(), + }); + + let mut wakeups = Wakeups::default(); + let mut currently_checking_set = CurrentlyCheckingSet::default(); + let mut delayed_approvals_timers = DelayedApprovalTimer::default(); + let mut approvals_cache = LruMap::new(ByLength::new(APPROVAL_CACHE_SIZE)); + loop { let mut overlayed_db = OverlayedBackend::new(&backend); let actions = futures::select! { (_tick, woken_block, woken_candidate) = wakeups.next(&*state.clock).fuse() => { subsystem.metrics.on_wakeup(); process_wakeup( - &mut ctx, + &mut to_other_subsystems, &mut state, &mut overlayed_db, &mut session_info_provider, @@ -1207,9 +1239,11 @@ where &wakeups, ).await? } - next_msg = ctx.recv().fuse() => { + next_msg = work_provider.recv().fuse() => { let mut actions = handle_from_overseer( - &mut ctx, + &mut to_other_subsystems, + &mut to_approval_distr, + &subsystem.spawner, &mut state, &mut overlayed_db, &mut session_info_provider, @@ -1269,7 +1303,8 @@ where &mut overlayed_db, &mut session_info_provider, &state, - &mut ctx, + &mut to_other_subsystems, + &mut to_approval_distr, block_hash, validator_index, &subsystem.metrics, @@ -1291,7 +1326,9 @@ where }; if handle_actions( - &mut ctx, + &mut to_other_subsystems, + &mut to_approval_distr, + &subsystem.spawner, &mut state, &mut overlayed_db, &mut session_info_provider, @@ -1318,6 +1355,63 @@ where Ok(()) } +// Starts a worker thread that runs the approval voting subsystem. +pub async fn start_approval_worker< + WorkProvider: ApprovalVotingWorkProvider + Send + 'static, + Sender: SubsystemSender + + SubsystemSender + + SubsystemSender + + SubsystemSender + + SubsystemSender + + SubsystemSender + + Clone, + ADSender: SubsystemSender, +>( + work_provider: WorkProvider, + to_other_subsystems: Sender, + to_approval_distr: ADSender, + config: Config, + db: Arc, + keystore: Arc, + sync_oracle: Box, + metrics: Metrics, + spawner: Arc, + task_name: &'static str, + group_name: &'static str, + clock: Arc, +) -> SubsystemResult<()> { + let approval_voting = ApprovalVotingSubsystem::with_config_and_clock( + config, + db.clone(), + keystore, + sync_oracle, + metrics, + clock, + spawner, + ); + let backend = DbBackend::new(db.clone(), approval_voting.db_config); + let spawner = approval_voting.spawner.clone(); + spawner.spawn_blocking( + task_name, + Some(group_name), + Box::pin(async move { + if let Err(err) = run( + work_provider, + to_other_subsystems, + to_approval_distr, + approval_voting, + Box::new(RealAssignmentCriteria), + backend, + ) + .await + { + gum::error!(target: LOG_TARGET, ?err, "Approval voting worker stopped processing messages"); + }; + }), + ); + Ok(()) +} + // Handle actions is a function that accepts a set of instructions // and subsequently updates the underlying approvals_db in accordance // with the linear set of instructions passed in. Therefore, actions @@ -1338,8 +1432,19 @@ where // // returns `true` if any of the actions was a `Conclude` command. #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] -async fn handle_actions( - ctx: &mut Context, +async fn handle_actions< + Sender: SubsystemSender + + SubsystemSender + + SubsystemSender + + SubsystemSender + + SubsystemSender + + SubsystemSender + + Clone, + ADSender: SubsystemSender, +>( + sender: &mut Sender, + approval_voting_sender: &mut ADSender, + spawn_handle: &Arc, state: &mut State, overlayed_db: &mut OverlayedBackend<'_, impl Backend>, session_info_provider: &mut RuntimeInfo, @@ -1371,7 +1476,8 @@ async fn handle_actions( // Note that chaining these iterators is O(n) as we must consume // the prior iterator. let next_actions: Vec = issue_approval( - ctx, + sender, + approval_voting_sender, state, overlayed_db, session_info_provider, @@ -1407,25 +1513,17 @@ async fn handle_actions( continue } - let mut launch_approval_span = state - .spans - .get(&relay_block_hash) - .map(|span| span.child("launch-approval")) - .unwrap_or_else(|| jaeger::Span::new(candidate_hash, "launch-approval")) - .with_trace_id(candidate_hash) - .with_candidate(candidate_hash) - .with_stage(jaeger::Stage::ApprovalChecking); - metrics.on_assignment_produced(assignment_tranche); let block_hash = indirect_cert.block_hash; - launch_approval_span.add_string_tag("block-hash", format!("{:?}", block_hash)); let validator_index = indirect_cert.validator; if distribute_assignment { - ctx.send_unbounded_message(ApprovalDistributionMessage::DistributeAssignment( - indirect_cert, - claimed_candidate_indices, - )); + approval_voting_sender.send_unbounded_message( + ApprovalDistributionMessage::DistributeAssignment( + indirect_cert, + claimed_candidate_indices, + ), + ); } match approvals_cache.get(&candidate_hash) { @@ -1440,7 +1538,8 @@ async fn handle_actions( actions_iter = new_actions.into_iter(); }, None => { - let ctx = &mut *ctx; + let sender = sender.clone(); + let spawn_handle = spawn_handle.clone(); currently_checking_set .insert_relay_block_hash( @@ -1449,7 +1548,8 @@ async fn handle_actions( relay_block_hash, async move { launch_approval( - ctx, + sender, + spawn_handle, metrics.clone(), session, candidate, @@ -1458,7 +1558,6 @@ async fn handle_actions( backing_group, executor_params, core_index, - &launch_approval_span, ) .await }, @@ -1469,22 +1568,13 @@ async fn handle_actions( } }, Action::NoteApprovedInChainSelection(block_hash) => { - let _span = state - .spans - .get(&block_hash) - .map(|span| span.child("note-approved-in-chain-selection")) - .unwrap_or_else(|| { - jaeger::Span::new(block_hash, "note-approved-in-chain-selection") - }) - .with_string_tag("block-hash", format!("{:?}", block_hash)) - .with_stage(jaeger::Stage::ApprovalChecking); - ctx.send_message(ChainSelectionMessage::Approved(block_hash)).await; + sender.send_message(ChainSelectionMessage::Approved(block_hash)).await; }, Action::BecomeActive => { *mode = Mode::Active; let (messages, next_actions) = distribution_messages_for_activation( - ctx, + sender, overlayed_db, state, delayed_approvals_timers, @@ -1492,7 +1582,7 @@ async fn handle_actions( ) .await?; - ctx.send_messages(messages.into_iter()).await; + approval_voting_sender.send_messages(messages.into_iter()).await; let next_actions: Vec = next_actions.into_iter().map(|v| v.clone()).chain(actions_iter).collect(); @@ -1566,8 +1656,8 @@ fn get_assignment_core_indices( } #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] -async fn distribution_messages_for_activation( - ctx: &mut Context, +async fn distribution_messages_for_activation>( + sender: &mut Sender, db: &OverlayedBackend<'_, impl Backend>, state: &State, delayed_approvals_timers: &mut DelayedApprovalTimer, @@ -1582,15 +1672,6 @@ async fn distribution_messages_for_activation( messages.push(ApprovalDistributionMessage::NewBlocks(Vec::new())); // dummy value. for block_hash in all_blocks { - let mut distribution_message_span = state - .spans - .get(&block_hash) - .map(|span| span.child("distribution-messages-for-activation")) - .unwrap_or_else(|| { - jaeger::Span::new(block_hash, "distribution-messages-for-activation") - }) - .with_stage(jaeger::Stage::ApprovalChecking) - .with_string_tag("block-hash", format!("{:?}", block_hash)); let block_entry = match db.load_block_entry(&block_hash)? { Some(b) => b, None => { @@ -1600,21 +1681,37 @@ async fn distribution_messages_for_activation( }, }; - distribution_message_span.add_string_tag("block-hash", &block_hash.to_string()); - distribution_message_span - .add_string_tag("parent-hash", &block_entry.parent_hash().to_string()); approval_meta.push(BlockApprovalMeta { hash: block_hash, number: block_entry.block_number(), parent_hash: block_entry.parent_hash(), - candidates: block_entry.candidates().iter().map(|(_, c_hash)| *c_hash).collect(), + candidates: block_entry + .candidates() + .iter() + .map(|(core_index, c_hash)| { + let candidate = db.load_candidate_entry(c_hash).ok().flatten(); + let group_index = candidate + .and_then(|entry| { + entry.approval_entry(&block_hash).map(|entry| entry.backing_group()) + }) + .unwrap_or_else(|| { + gum::warn!( + target: LOG_TARGET, + ?block_hash, + ?c_hash, + "Missing candidate entry or approval entry", + ); + GroupIndex::default() + }); + (*c_hash, *core_index, group_index) + }) + .collect(), slot: block_entry.slot(), session: block_entry.session(), + vrf_story: block_entry.relay_vrf_story(), }); let mut signatures_queued = HashSet::new(); for (core_index, candidate_hash) in block_entry.candidates() { - let _candidate_span = - distribution_message_span.child("candidate").with_candidate(*candidate_hash); let candidate_entry = match db.load_candidate_entry(&candidate_hash)? { Some(c) => c, None => { @@ -1672,7 +1769,7 @@ async fn distribution_messages_for_activation( let ExtendedSessionInfo { ref executor_params, .. } = match get_extended_session_info( session_info_provider, - ctx.sender(), + sender, block_entry.block_hash(), block_entry.session(), ) @@ -1770,9 +1867,16 @@ async fn distribution_messages_for_activation( } // Handle an incoming signal from the overseer. Returns true if execution should conclude. -#[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] -async fn handle_from_overseer( - ctx: &mut Context, +async fn handle_from_overseer< + Sender: SubsystemSender + + SubsystemSender + + SubsystemSender + + Clone, + ADSender: SubsystemSender, +>( + sender: &mut Sender, + approval_voting_sender: &mut ADSender, + spawn_handle: &Arc, state: &mut State, db: &mut OverlayedBackend<'_, impl Backend>, session_info_provider: &mut RuntimeInfo, @@ -1786,11 +1890,9 @@ async fn handle_from_overseer( let mut actions = Vec::new(); if let Some(activated) = update.activated { let head = activated.hash; - let approval_voting_span = - jaeger::PerLeafSpan::new(activated.span, "approval-voting"); - state.spans.insert(head, approval_voting_span); match import::handle_new_head( - ctx, + sender, + approval_voting_sender, state, db, session_info_provider, @@ -1858,7 +1960,7 @@ async fn handle_from_overseer( // `prune_finalized_wakeups` prunes all finalized block hashes. We prune spans // accordingly. - wakeups.prune_finalized_wakeups(block_number, &mut state.spans); + wakeups.prune_finalized_wakeups(block_number); state.cleanup_assignments_gathering_timestamp(block_number); // // `prune_finalized_wakeups` prunes all finalized block hashes. We prune spans @@ -1872,53 +1974,36 @@ async fn handle_from_overseer( vec![Action::Conclude] }, FromOrchestra::Communication { msg } => match msg { - ApprovalVotingMessage::CheckAndImportAssignment(a, claimed_cores, res) => { - let (check_outcome, actions) = check_and_import_assignment( - ctx.sender(), - state, - db, - session_info_provider, - a, - claimed_cores, - ) - .await?; - let _ = res.send(check_outcome); - + ApprovalVotingMessage::ImportAssignment(checked_assignment, tx) => { + let (check_outcome, actions) = + import_assignment(sender, state, db, session_info_provider, checked_assignment) + .await?; + // approval-distribution makes sure this assignment is valid and expected, + // so this import should never fail, if it does it might mean one of two things, + // there is a bug in the code or the two subsystems got out of sync. + if let AssignmentCheckResult::Bad(ref err) = check_outcome { + gum::debug!(target: LOG_TARGET, ?err, "Unexpected fail when importing an assignment"); + } + let _ = tx.map(|tx| tx.send(check_outcome)); actions }, - ApprovalVotingMessage::CheckAndImportApproval(a, res) => - check_and_import_approval( - ctx.sender(), - state, - db, - session_info_provider, - metrics, - a, - |r| { - let _ = res.send(r); - }, - &wakeups, - ) - .await? - .0, + ApprovalVotingMessage::ImportApproval(a, tx) => { + let result = + import_approval(sender, state, db, session_info_provider, metrics, a, &wakeups) + .await?; + // approval-distribution makes sure this vote is valid and expected, + // so this import should never fail, if it does it might mean one of two things, + // there is a bug in the code or the two subsystems got out of sync. + if let ApprovalCheckResult::Bad(ref err) = result.1 { + gum::debug!(target: LOG_TARGET, ?err, "Unexpected fail when importing an approval"); + } + let _ = tx.map(|tx| tx.send(result.1)); + + result.0 + }, ApprovalVotingMessage::ApprovedAncestor(target, lower_bound, res) => { - let mut approved_ancestor_span = state - .spans - .get(&target) - .map(|span| span.child("approved-ancestor")) - .unwrap_or_else(|| jaeger::Span::new(target, "approved-ancestor")) - .with_stage(jaeger::Stage::ApprovalChecking) - .with_string_tag("leaf", format!("{:?}", target)); - match handle_approved_ancestor( - ctx, - db, - target, - lower_bound, - wakeups, - &mut approved_ancestor_span, - &metrics, - ) - .await + match handle_approved_ancestor(sender, db, target, lower_bound, wakeups, &metrics) + .await { Ok(v) => { let _ = res.send(v); @@ -1933,7 +2018,14 @@ async fn handle_from_overseer( }, ApprovalVotingMessage::GetApprovalSignaturesForCandidate(candidate_hash, tx) => { metrics.on_candidate_signatures_request(); - get_approval_signatures_for_candidate(ctx, db, candidate_hash, tx).await?; + get_approval_signatures_for_candidate( + approval_voting_sender.clone(), + spawn_handle, + db, + candidate_hash, + tx, + ) + .await?; Vec::new() }, }, @@ -1947,8 +2039,11 @@ async fn handle_from_overseer( /// This involves an unbounded message send to approval-distribution, the caller has to ensure that /// calls to this function are infrequent and bounded. #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] -async fn get_approval_signatures_for_candidate( - ctx: &mut Context, +async fn get_approval_signatures_for_candidate< + Sender: SubsystemSender, +>( + mut sender: Sender, + spawn_handle: &Arc, db: &OverlayedBackend<'_, impl Backend>, candidate_hash: CandidateHash, tx: oneshot::Sender, ValidatorSignature)>>, @@ -2007,7 +2102,6 @@ async fn get_approval_signatures_for_candidate( } } - let mut sender = ctx.sender().clone(); let get_approvals = async move { let (tx_distribution, rx_distribution) = oneshot::channel(); sender.send_unbounded_message(ApprovalDistributionMessage::GetApprovalSignatures( @@ -2087,32 +2181,33 @@ async fn get_approval_signatures_for_candidate( ?candidate_hash, "Spawning task for fetching signatures from approval-distribution" ); - ctx.spawn("get-approval-signatures", Box::pin(get_approvals)) + spawn_handle.spawn( + "get-approval-signatures", + Some("approval-voting-subsystem"), + Box::pin(get_approvals), + ); + Ok(()) } #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] -async fn handle_approved_ancestor( - ctx: &mut Context, +async fn handle_approved_ancestor>( + sender: &mut Sender, db: &OverlayedBackend<'_, impl Backend>, target: Hash, lower_bound: BlockNumber, wakeups: &Wakeups, - span: &mut jaeger::Span, metrics: &Metrics, ) -> SubsystemResult> { const MAX_TRACING_WINDOW: usize = 200; const ABNORMAL_DEPTH_THRESHOLD: usize = 5; const LOGGING_DEPTH_THRESHOLD: usize = 10; - let mut span = span - .child("handle-approved-ancestor") - .with_stage(jaeger::Stage::ApprovalChecking); let mut all_approved_max = None; let target_number = { let (tx, rx) = oneshot::channel(); - ctx.send_message(ChainApiMessage::BlockNumber(target, tx)).await; + sender.send_message(ChainApiMessage::BlockNumber(target, tx)).await; match rx.await { Ok(Ok(Some(n))) => n, @@ -2121,8 +2216,6 @@ async fn handle_approved_ancestor( } }; - span.add_uint_tag("leaf-number", target_number as u64); - span.add_uint_tag("lower-bound", lower_bound as u64); if target_number <= lower_bound { return Ok(None) } @@ -2133,12 +2226,13 @@ async fn handle_approved_ancestor( let ancestry = if target_number > lower_bound + 1 { let (tx, rx) = oneshot::channel(); - ctx.send_message(ChainApiMessage::Ancestors { - hash: target, - k: (target_number - (lower_bound + 1)) as usize, - response_channel: tx, - }) - .await; + sender + .send_message(ChainApiMessage::Ancestors { + hash: target, + k: (target_number - (lower_bound + 1)) as usize, + response_channel: tx, + }) + .await; match rx.await { Ok(Ok(a)) => a, @@ -2153,9 +2247,6 @@ async fn handle_approved_ancestor( let mut bits: BitVec = Default::default(); for (i, block_hash) in std::iter::once(target).chain(ancestry).enumerate() { - let mut entry_span = - span.child("load-block-entry").with_stage(jaeger::Stage::ApprovalChecking); - entry_span.add_string_tag("block-hash", format!("{:?}", block_hash)); // Block entries should be present as the assumption is that // nothing here is finalized. If we encounter any missing block // entries we can fail. @@ -2222,7 +2313,6 @@ async fn handle_approved_ancestor( ) } metrics.on_unapproved_candidates_in_unfinalized_chain(unapproved.len()); - entry_span.add_uint_tag("unapproved-candidates", unapproved.len() as u64); for candidate_hash in unapproved { match db.load_candidate_entry(&candidate_hash)? { None => { @@ -2343,15 +2433,6 @@ async fn handle_approved_ancestor( number: block_number, descriptions: block_descriptions, }); - match all_approved_max { - Some(HighestApprovedAncestorBlock { ref hash, ref number, .. }) => { - span.add_uint_tag("highest-approved-number", *number as u64); - span.add_string_fmt_debug_tag("highest-approved-hash", hash); - }, - None => { - span.add_string_tag("reached-lower-bound", "true"); - }, - } Ok(all_approved_max) } @@ -2384,7 +2465,12 @@ fn schedule_wakeup_action( last_assignment_tick.map(|l| l + APPROVAL_DELAY).filter(|t| t > &tick_now), next_no_show, ) - .map(|tick| Action::ScheduleWakeup { block_hash, block_number, candidate_hash, tick }) + .map(|tick| Action::ScheduleWakeup { + block_hash, + block_number, + candidate_hash, + tick, + }) }, RequiredTranches::Pending { considered, next_no_show, clock_drift, .. } => { // select the minimum of `next_no_show`, or the tick of the next non-empty tranche @@ -2439,30 +2525,20 @@ fn schedule_wakeup_action( maybe_action } -async fn check_and_import_assignment( +async fn import_assignment( sender: &mut Sender, state: &State, db: &mut OverlayedBackend<'_, impl Backend>, session_info_provider: &mut RuntimeInfo, - assignment: IndirectAssignmentCertV2, - candidate_indices: CandidateBitfield, + checked_assignment: CheckedIndirectAssignment, ) -> SubsystemResult<(AssignmentCheckResult, Vec)> where Sender: SubsystemSender, { let tick_now = state.clock.tick_now(); - - let mut check_and_import_assignment_span = state - .spans - .get(&assignment.block_hash) - .map(|span| span.child("check-and-import-assignment")) - .unwrap_or_else(|| jaeger::Span::new(assignment.block_hash, "check-and-import-assignment")) - .with_relay_parent(assignment.block_hash) - .with_stage(jaeger::Stage::ApprovalChecking); - - for candidate_index in candidate_indices.iter_ones() { - check_and_import_assignment_span.add_uint_tag("candidate-index", candidate_index as u64); - } + let assignment = checked_assignment.assignment(); + let candidate_indices = checked_assignment.candidate_indices(); + let tranche = checked_assignment.tranche(); let block_entry = match db.load_block_entry(&assignment.block_hash)? { Some(b) => b, @@ -2514,8 +2590,6 @@ where )) } - // The Compact VRF modulo assignment cert has multiple core assignments. - let mut backing_groups = Vec::new(); let mut claimed_core_indices = Vec::new(); let mut assigned_candidate_hashes = Vec::new(); @@ -2544,26 +2618,16 @@ where )), // no candidate at core. }; - check_and_import_assignment_span - .add_string_tag("candidate-hash", format!("{:?}", assigned_candidate_hash)); - check_and_import_assignment_span.add_string_tag( - "traceID", - format!("{:?}", jaeger::hash_to_trace_identifier(assigned_candidate_hash.0)), - ); - - let approval_entry = match candidate_entry.approval_entry_mut(&assignment.block_hash) { - Some(a) => a, - None => - return Ok(( - AssignmentCheckResult::Bad(AssignmentCheckError::Internal( - assignment.block_hash, - assigned_candidate_hash, - )), - Vec::new(), + if candidate_entry.approval_entry_mut(&assignment.block_hash).is_none() { + return Ok(( + AssignmentCheckResult::Bad(AssignmentCheckError::Internal( + assignment.block_hash, + assigned_candidate_hash, )), + Vec::new(), + )); }; - backing_groups.push(approval_entry.backing_group()); claimed_core_indices.push(claimed_core_index); assigned_candidate_hashes.push(assigned_candidate_hash); } @@ -2579,42 +2643,6 @@ where )) } - // Check the assignment certificate. - let res = state.assignment_criteria.check_assignment_cert( - claimed_core_indices - .clone() - .try_into() - .expect("Checked for null assignment above; qed"), - assignment.validator, - &criteria::Config::from(session_info), - block_entry.relay_vrf_story(), - &assignment.cert, - backing_groups, - ); - - let tranche = match res { - Err(crate::criteria::InvalidAssignment(reason)) => - return Ok(( - AssignmentCheckResult::Bad(AssignmentCheckError::InvalidCert( - assignment.validator, - format!("{:?}", reason), - )), - Vec::new(), - )), - Ok(tranche) => { - let current_tranche = - state.clock.tranche_now(state.slot_duration_millis, block_entry.slot()); - - let too_far_in_future = current_tranche + TICK_TOO_FAR_IN_FUTURE as DelayTranche; - - if tranche >= too_far_in_future { - return Ok((AssignmentCheckResult::TooFarInFuture, Vec::new())) - } - - tranche - }, - }; - let mut actions = Vec::new(); let res = { let mut is_duplicate = true; @@ -2647,7 +2675,6 @@ where }; is_duplicate &= approval_entry.is_assigned(assignment.validator); approval_entry.import_assignment(tranche, assignment.validator, tick_now); - check_and_import_assignment_span.add_uint_tag("tranche", tranche as u64); // We've imported a new assignment, so we need to schedule a wake-up for when that might // no-show. @@ -2704,33 +2731,23 @@ where Ok((res, actions)) } -async fn check_and_import_approval( +async fn import_approval( sender: &mut Sender, state: &mut State, db: &mut OverlayedBackend<'_, impl Backend>, session_info_provider: &mut RuntimeInfo, metrics: &Metrics, - approval: IndirectSignedApprovalVoteV2, - with_response: impl FnOnce(ApprovalCheckResult) -> T, + approval: CheckedIndirectSignedApprovalVote, wakeups: &Wakeups, -) -> SubsystemResult<(Vec, T)> +) -> SubsystemResult<(Vec, ApprovalCheckResult)> where Sender: SubsystemSender, { macro_rules! respond_early { ($e: expr) => {{ - let t = with_response($e); - return Ok((Vec::new(), t)) + return Ok((Vec::new(), $e)) }}; } - let mut span = state - .spans - .get(&approval.block_hash) - .map(|span| span.child("check-and-import-approval")) - .unwrap_or_else(|| jaeger::Span::new(approval.block_hash, "check-and-import-approval")) - .with_string_fmt_debug_tag("candidate-index", approval.candidate_indices.clone()) - .with_relay_parent(approval.block_hash) - .with_stage(jaeger::Stage::ApprovalChecking); let block_entry = match db.load_block_entry(&approval.block_hash)? { Some(b) => b, @@ -2760,82 +2777,12 @@ where }, }; - span.add_string_tag("candidate-hashes", format!("{:?}", approved_candidates_info)); - span.add_string_tag( - "traceIDs", - format!( - "{:?}", - approved_candidates_info - .iter() - .map(|(_, approved_candidate_hash)| hash_to_trace_identifier( - approved_candidate_hash.0 - )) - .collect_vec() - ), + gum::trace!( + target: LOG_TARGET, + "Received approval for num_candidates {:}", + approval.candidate_indices.count_ones() ); - { - let session_info = match get_session_info( - session_info_provider, - sender, - approval.block_hash, - block_entry.session(), - ) - .await - { - Some(s) => s, - None => { - respond_early!(ApprovalCheckResult::Bad(ApprovalCheckError::UnknownSessionIndex( - block_entry.session() - ),)) - }, - }; - - let pubkey = match session_info.validators.get(approval.validator) { - Some(k) => k, - None => respond_early!(ApprovalCheckResult::Bad( - ApprovalCheckError::InvalidValidatorIndex(approval.validator), - )), - }; - - gum::trace!( - target: LOG_TARGET, - "Received approval for num_candidates {:}", - approval.candidate_indices.count_ones() - ); - - let candidate_hashes: Vec = - approved_candidates_info.iter().map(|candidate| candidate.1).collect(); - // Signature check: - match DisputeStatement::Valid( - ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(candidate_hashes.clone()), - ) - .check_signature( - &pubkey, - if let Some(candidate_hash) = candidate_hashes.first() { - *candidate_hash - } else { - respond_early!(ApprovalCheckResult::Bad(ApprovalCheckError::InvalidValidatorIndex( - approval.validator - ),)) - }, - block_entry.session(), - &approval.signature, - ) { - Err(_) => { - gum::error!( - target: LOG_TARGET, - "Error while checking signature {:}", - approval.candidate_indices.count_ones() - ); - respond_early!(ApprovalCheckResult::Bad(ApprovalCheckError::InvalidSignature( - approval.validator - ),)) - }, - Ok(()) => {}, - }; - } - let mut actions = Vec::new(); for (approval_candidate_index, approved_candidate_hash) in approved_candidates_info { let block_entry = match db.load_block_entry(&approval.block_hash)? { @@ -2898,9 +2845,7 @@ where } // importing the approval can be heavy as it may trigger acceptance for a series of blocks. - let t = with_response(ApprovalCheckResult::Accepted); - - Ok((actions, t)) + Ok((actions, ApprovalCheckResult::Accepted)) } #[derive(Debug)] @@ -3176,9 +3121,8 @@ fn should_trigger_assignment( } } -#[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] -async fn process_wakeup( - ctx: &mut Context, +async fn process_wakeup>( + sender: &mut Sender, state: &mut State, db: &mut OverlayedBackend<'_, impl Backend>, session_info_provider: &mut RuntimeInfo, @@ -3187,16 +3131,6 @@ async fn process_wakeup( metrics: &Metrics, wakeups: &Wakeups, ) -> SubsystemResult> { - let mut span = state - .spans - .get(&relay_block) - .map(|span| span.child("process-wakeup")) - .unwrap_or_else(|| jaeger::Span::new(candidate_hash, "process-wakeup")) - .with_trace_id(candidate_hash) - .with_relay_parent(relay_block) - .with_candidate(candidate_hash) - .with_stage(jaeger::Stage::ApprovalChecking); - let block_entry = db.load_block_entry(&relay_block)?; let candidate_entry = db.load_candidate_entry(&candidate_hash)?; @@ -3209,7 +3143,7 @@ async fn process_wakeup( let ExtendedSessionInfo { ref session_info, ref executor_params, .. } = match get_extended_session_info( session_info_provider, - ctx.sender(), + sender, block_entry.block_hash(), block_entry.session(), ) @@ -3225,7 +3159,7 @@ async fn process_wakeup( Slot::from(u64::from(session_info.no_show_slots)), ); let tranche_now = state.clock.tranche_now(state.slot_duration_millis, block_entry.slot()); - span.add_uint_tag("tranche", tranche_now as u64); + gum::trace!( target: LOG_TARGET, tranche = tranche_now, @@ -3351,7 +3285,7 @@ async fn process_wakeup( // Note that this function also schedules a wakeup as necessary. actions.extend( advance_approval_state( - ctx.sender(), + sender, state, db, session_info_provider, @@ -3372,8 +3306,14 @@ async fn process_wakeup( // spawned. When the background work is no longer needed, the `AbortHandle` should be dropped // to cancel the background work and any requests it has spawned. #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] -async fn launch_approval( - ctx: &mut Context, +async fn launch_approval< + Sender: SubsystemSender + + SubsystemSender + + SubsystemSender + + SubsystemSender, +>( + mut sender: Sender, + spawn_handle: Arc, metrics: Metrics, session_index: SessionIndex, candidate: CandidateReceipt, @@ -3382,7 +3322,6 @@ async fn launch_approval( backing_group: GroupIndex, executor_params: ExecutorParams, core_index: Option, - span: &jaeger::Span, ) -> SubsystemResult> { let (a_tx, a_rx) = oneshot::channel(); let (code_tx, code_rx) = oneshot::channel(); @@ -3416,39 +3355,29 @@ async fn launch_approval( let para_id = candidate.descriptor.para_id; gum::trace!(target: LOG_TARGET, ?candidate_hash, ?para_id, "Recovering data."); - let request_validation_data_span = span - .child("request-validation-data") - .with_trace_id(candidate_hash) - .with_candidate(candidate_hash) - .with_string_tag("block-hash", format!("{:?}", block_hash)) - .with_stage(jaeger::Stage::ApprovalChecking); - let timer = metrics.time_recover_and_approve(); - ctx.send_message(AvailabilityRecoveryMessage::RecoverAvailableData( - candidate.clone(), - session_index, - Some(backing_group), - core_index, - a_tx, - )) - .await; - - let request_validation_result_span = span - .child("request-validation-result") - .with_trace_id(candidate_hash) - .with_candidate(candidate_hash) - .with_string_tag("block-hash", format!("{:?}", block_hash)) - .with_stage(jaeger::Stage::ApprovalChecking); + sender + .send_message(AvailabilityRecoveryMessage::RecoverAvailableData( + candidate.clone(), + session_index, + Some(backing_group), + core_index, + a_tx, + )) + .await; - ctx.send_message(RuntimeApiMessage::Request( - block_hash, - RuntimeApiRequest::ValidationCodeByHash(candidate.descriptor.validation_code_hash, code_tx), - )) - .await; + sender + .send_message(RuntimeApiMessage::Request( + block_hash, + RuntimeApiRequest::ValidationCodeByHash( + candidate.descriptor.validation_code_hash, + code_tx, + ), + )) + .await; let candidate = candidate.clone(); let metrics_guard = StaleGuard(Some(metrics)); - let mut sender = ctx.sender().clone(); let background = async move { // Force the move of the timer into the background task. let _timer = timer; @@ -3500,7 +3429,6 @@ async fn launch_approval( return ApprovalState::failed(validator_index, candidate_hash) }, }; - drop(request_validation_data_span); let validation_code = match code_rx.await { Err(_) => return ApprovalState::failed(validator_index, candidate_hash), @@ -3572,20 +3500,24 @@ async fn launch_approval( "Failed to validate candidate due to internal error", ); metrics_guard.take().on_approval_error(); - drop(request_validation_result_span); return ApprovalState::failed(validator_index, candidate_hash) }, } }; let (background, remote_handle) = background.remote_handle(); - ctx.spawn("approval-checks", Box::pin(background)).map(move |()| remote_handle) + spawn_handle.spawn("approval-checks", Some("approval-voting-subsystem"), Box::pin(background)); + Ok(remote_handle) } // Issue and import a local approval vote. Should only be invoked after approval checks // have been done. #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] -async fn issue_approval( - ctx: &mut Context, +async fn issue_approval< + Sender: SubsystemSender, + ADSender: SubsystemSender, +>( + sender: &mut Sender, + approval_voting_sender: &mut ADSender, state: &mut State, db: &mut OverlayedBackend<'_, impl Backend>, session_info_provider: &mut RuntimeInfo, @@ -3595,17 +3527,6 @@ async fn issue_approval( ApprovalVoteRequest { validator_index, block_hash }: ApprovalVoteRequest, wakeups: &Wakeups, ) -> SubsystemResult> { - let mut issue_approval_span = state - .spans - .get(&block_hash) - .map(|span| span.child("issue-approval")) - .unwrap_or_else(|| jaeger::Span::new(block_hash, "issue-approval")) - .with_trace_id(candidate_hash) - .with_string_tag("block-hash", format!("{:?}", block_hash)) - .with_candidate(candidate_hash) - .with_validator_index(validator_index) - .with_stage(jaeger::Stage::ApprovalChecking); - let mut block_entry = match db.load_block_entry(&block_hash)? { Some(b) => b, None => { @@ -3630,7 +3551,6 @@ async fn issue_approval( }, Some(idx) => idx, }; - issue_approval_span.add_int_tag("candidate_index", candidate_index as i64); let candidate_hash = match block_entry.candidate(candidate_index as usize) { Some((_, h)) => *h, @@ -3664,7 +3584,7 @@ async fn issue_approval( let session_info = match get_session_info( session_info_provider, - ctx.sender(), + sender, block_entry.parent_hash(), block_entry.session(), ) @@ -3706,7 +3626,7 @@ async fn issue_approval( ); let actions = advance_approval_state( - ctx.sender(), + sender, state, db, session_info_provider, @@ -3723,7 +3643,8 @@ async fn issue_approval( db, session_info_provider, state, - ctx, + sender, + approval_voting_sender, block_hash, validator_index, metrics, @@ -3742,11 +3663,15 @@ async fn issue_approval( // Create signature for the approved candidates pending signatures #[overseer::contextbounds(ApprovalVoting, prefix = self::overseer)] -async fn maybe_create_signature( +async fn maybe_create_signature< + Sender: SubsystemSender, + ADSender: SubsystemSender, +>( db: &mut OverlayedBackend<'_, impl Backend>, session_info_provider: &mut RuntimeInfo, state: &State, - ctx: &mut Context, + sender: &mut Sender, + approval_voting_sender: &mut ADSender, block_hash: Hash, validator_index: ValidatorIndex, metrics: &Metrics, @@ -3765,7 +3690,7 @@ async fn maybe_create_signature( }; let approval_params = state - .get_approval_voting_params_or_default(ctx, block_entry.session(), block_hash) + .get_approval_voting_params_or_default(sender, block_entry.session(), block_hash) .await .unwrap_or_default(); @@ -3785,7 +3710,7 @@ async fn maybe_create_signature( let session_info = match get_session_info( session_info_provider, - ctx.sender(), + sender, block_entry.parent_hash(), block_entry.session(), ) @@ -3866,7 +3791,7 @@ async fn maybe_create_signature( metrics.on_approval_produced(); - ctx.send_unbounded_message(ApprovalDistributionMessage::DistributeApproval( + approval_voting_sender.send_unbounded_message(ApprovalDistributionMessage::DistributeApproval( IndirectSignedApprovalVoteV2 { block_hash: block_entry.block_hash(), candidate_indices: candidates_indices, @@ -3907,7 +3832,7 @@ fn issue_local_invalid_statement( candidate_hash: CandidateHash, candidate: CandidateReceipt, ) where - Sender: overseer::ApprovalVotingSenderTrait, + Sender: SubsystemSender, { // We need to send an unbounded message here to break a cycle: // DisputeCoordinatorMessage::IssueLocalStatement -> diff --git a/polkadot/node/core/approval-voting/src/persisted_entries.rs b/polkadot/node/core/approval-voting/src/persisted_entries.rs index 59a461810051..16e231aa1a2d 100644 --- a/polkadot/node/core/approval-voting/src/persisted_entries.rs +++ b/polkadot/node/core/approval-voting/src/persisted_entries.rs @@ -36,7 +36,9 @@ use std::collections::BTreeMap; use crate::approval_db::v2::Bitfield; -use super::{criteria::OurAssignment, time::Tick}; +use super::criteria::OurAssignment; + +use polkadot_node_primitives::approval::time::Tick; /// Metadata regarding a specific tranche of assignments for a specific candidate. #[derive(Debug, Clone, PartialEq)] diff --git a/polkadot/node/core/approval-voting/src/tests.rs b/polkadot/node/core/approval-voting/src/tests.rs index 64ae86bc013a..db5ffd441c0d 100644 --- a/polkadot/node/core/approval-voting/src/tests.rs +++ b/polkadot/node/core/approval-voting/src/tests.rs @@ -17,6 +17,7 @@ use self::test_helpers::mock::new_leaf; use super::*; use crate::backend::V1ReadBackend; +use itertools::Itertools; use overseer::prometheus::{ prometheus::{IntCounter, IntCounterVec}, Histogram, HistogramOpts, HistogramVec, Opts, @@ -35,19 +36,19 @@ use polkadot_node_subsystem::{ messages::{ AllMessages, ApprovalVotingMessage, AssignmentCheckResult, AvailabilityRecoveryMessage, }, - ActiveLeavesUpdate, + ActiveLeavesUpdate, SubsystemContext, }; use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_node_subsystem_util::TimeoutExt; -use polkadot_overseer::HeadSupportsParachains; +use polkadot_overseer::SpawnGlue; use polkadot_primitives::{ - ApprovalVote, CandidateCommitments, CandidateEvent, CoreIndex, GroupIndex, Header, - Id as ParaId, IndexedVec, NodeFeatures, ValidationCode, ValidatorSignature, + ApprovalVote, CandidateCommitments, CandidateEvent, CoreIndex, DisputeStatement, GroupIndex, + Header, Id as ParaId, IndexedVec, NodeFeatures, ValidDisputeStatementKind, ValidationCode, + ValidatorSignature, }; use std::{cmp::max, time::Duration}; use assert_matches::assert_matches; -use async_trait::async_trait; use parking_lot::Mutex; use sp_keyring::sr25519::Keyring as Sr25519Keyring; use sp_keystore::Keystore; @@ -130,17 +131,8 @@ pub mod test_constants { pub(crate) const TEST_CONFIG: DatabaseConfig = DatabaseConfig { col_approval_data: DATA_COL }; } -struct MockSupportsParachains; - -#[async_trait] -impl HeadSupportsParachains for MockSupportsParachains { - async fn head_supports_parachains(&self, _head: &Hash) -> bool { - true - } -} - -fn slot_to_tick(t: impl Into) -> crate::time::Tick { - crate::time::slot_number_to_tick(SLOT_DURATION_MILLIS, t.into()) +fn slot_to_tick(t: impl Into) -> Tick { + slot_number_to_tick(SLOT_DURATION_MILLIS, t.into()) } #[derive(Default, Clone)] @@ -262,7 +254,8 @@ where _relay_vrf_story: polkadot_node_primitives::approval::v1::RelayVRFStory, _assignment: &polkadot_node_primitives::approval::v2::AssignmentCertV2, _backing_groups: Vec, - ) -> Result { + ) -> Result + { self.1(validator_index) } } @@ -535,7 +528,7 @@ impl Default for HarnessConfig { struct TestHarness { virtual_overseer: VirtualOverseer, - clock: Box, + clock: Arc, sync_oracle_handle: TestSyncOracleHandle, } @@ -543,18 +536,14 @@ 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; let pool = sp_core::testing::TaskExecutor::new(); - let (context, virtual_overseer) = - polkadot_node_subsystem_test_helpers::make_subsystem_context(pool); + let (mut context, virtual_overseer) = + polkadot_node_subsystem_test_helpers::make_subsystem_context(pool.clone()); let keystore = LocalKeystore::in_memory(); let _ = keystore.sr25519_generate_new( @@ -562,12 +551,14 @@ fn test_harness>( Some(&Sr25519Keyring::Alice.to_seed()), ); - let clock = Box::new(clock); + let clock = Arc::new(clock); let db = kvdb_memorydb::create(test_constants::NUM_COLUMNS); let db = polkadot_node_subsystem_util::database::kvdb_impl::DbAdapter::new(db, &[]); - + let sender = context.sender().clone(); let subsystem = run( context, + sender.clone(), + sender.clone(), ApprovalVotingSubsystem::with_config_and_clock( Config { col_approval_data: test_constants::TEST_CONFIG.col_approval_data, @@ -578,6 +569,7 @@ fn test_harness>( sync_oracle, Metrics::default(), clock.clone(), + Arc::new(SpawnGlue(pool)), ), assignment_criteria, backend, @@ -651,7 +643,7 @@ fn make_candidate(para_id: ParaId, hash: &Hash) -> CandidateReceipt { r } -async fn check_and_import_approval( +async fn import_approval( overseer: &mut VirtualOverseer, block_hash: Hash, candidate_index: CandidateIndex, @@ -670,14 +662,14 @@ async fn check_and_import_approval( overseer_send( overseer, FromOrchestra::Communication { - msg: ApprovalVotingMessage::CheckAndImportApproval( - IndirectSignedApprovalVoteV2 { + msg: ApprovalVotingMessage::ImportApproval( + CheckedIndirectSignedApprovalVote::from_checked(IndirectSignedApprovalVoteV2 { block_hash, candidate_indices: candidate_index.into(), validator, signature, - }, - tx, + }), + Some(tx), ), }, ) @@ -693,25 +685,31 @@ async fn check_and_import_approval( rx } -async fn check_and_import_assignment( +async fn import_assignment( overseer: &mut VirtualOverseer, block_hash: Hash, candidate_index: CandidateIndex, validator: ValidatorIndex, + tranche: DelayTranche, ) -> oneshot::Receiver { let (tx, rx) = oneshot::channel(); overseer_send( overseer, FromOrchestra::Communication { - msg: ApprovalVotingMessage::CheckAndImportAssignment( - IndirectAssignmentCertV2 { - block_hash, - validator, - cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { sample: 0 }) + msg: ApprovalVotingMessage::ImportAssignment( + CheckedIndirectAssignment::from_checked( + IndirectAssignmentCertV2 { + block_hash, + validator, + cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { + sample: 0, + }) .into(), - }, - candidate_index.into(), - tx, + }, + candidate_index.into(), + tranche, + ), + Some(tx), ), }, ) @@ -719,7 +717,7 @@ async fn check_and_import_assignment( rx } -async fn check_and_import_assignment_v2( +async fn import_assignment_v2( overseer: &mut VirtualOverseer, block_hash: Hash, core_indices: Vec, @@ -729,22 +727,27 @@ async fn check_and_import_assignment_v2( overseer_send( overseer, FromOrchestra::Communication { - msg: ApprovalVotingMessage::CheckAndImportAssignment( - IndirectAssignmentCertV2 { - block_hash, - validator, - cert: garbage_assignment_cert_v2(AssignmentCertKindV2::RelayVRFModuloCompact { - core_bitfield: core_indices - .clone() - .into_iter() - .map(|c| CoreIndex(c)) - .collect::>() - .try_into() - .unwrap(), - }), - }, - core_indices.try_into().unwrap(), - tx, + msg: ApprovalVotingMessage::ImportAssignment( + CheckedIndirectAssignment::from_checked( + IndirectAssignmentCertV2 { + block_hash, + validator, + cert: garbage_assignment_cert_v2( + AssignmentCertKindV2::RelayVRFModuloCompact { + core_bitfield: core_indices + .clone() + .into_iter() + .map(|c| CoreIndex(c)) + .collect::>() + .try_into() + .unwrap(), + }, + ), + }, + core_indices.try_into().unwrap(), + 0, + ), + Some(tx), ), }, ) @@ -1125,26 +1128,18 @@ fn subsystem_rejects_bad_assignment_ok_criteria() { ); builder.build(&mut virtual_overseer).await; - let rx = check_and_import_assignment( - &mut virtual_overseer, - block_hash, - candidate_index, - validator, - ) - .await; + let rx = + import_assignment(&mut virtual_overseer, block_hash, candidate_index, validator, 0) + .await; assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted),); // unknown hash let unknown_hash = Hash::repeat_byte(0x02); - let rx = check_and_import_assignment( - &mut virtual_overseer, - unknown_hash, - candidate_index, - validator, - ) - .await; + let rx = + import_assignment(&mut virtual_overseer, unknown_hash, candidate_index, validator, 0) + .await; assert_eq!( rx.await, @@ -1155,59 +1150,6 @@ fn subsystem_rejects_bad_assignment_ok_criteria() { }); } -#[test] -fn subsystem_rejects_bad_assignment_err_criteria() { - let assignment_criteria = Box::new(MockAssignmentCriteria::check_only(move |_| { - Err(criteria::InvalidAssignment( - criteria::InvalidAssignmentReason::ValidatorIndexOutOfBounds, - )) - })); - let config = HarnessConfigBuilder::default().assignment_criteria(assignment_criteria).build(); - test_harness(config, |test_harness| async move { - let TestHarness { mut virtual_overseer, sync_oracle_handle: _sync_oracle_handle, .. } = - test_harness; - assert_matches!( - overseer_recv(&mut virtual_overseer).await, - AllMessages::ChainApi(ChainApiMessage::FinalizedBlockNumber(rx)) => { - rx.send(Ok(0)).unwrap(); - } - ); - - let block_hash = Hash::repeat_byte(0x01); - let candidate_index = 0; - let validator = ValidatorIndex(0); - - let head: Hash = ChainBuilder::GENESIS_HASH; - let mut builder = ChainBuilder::new(); - let slot = Slot::from(1 as u64); - builder.add_block( - block_hash, - head, - 1, - BlockConfig { slot, candidates: None, session_info: None, end_syncing: false }, - ); - builder.build(&mut virtual_overseer).await; - - let rx = check_and_import_assignment( - &mut virtual_overseer, - block_hash, - candidate_index, - validator, - ) - .await; - - assert_eq!( - rx.await, - Ok(AssignmentCheckResult::Bad(AssignmentCheckError::InvalidCert( - ValidatorIndex(0), - "ValidatorIndexOutOfBounds".to_string(), - ))), - ); - - virtual_overseer - }); -} - #[test] fn blank_subsystem_act_on_bad_block() { test_harness(HarnessConfig::default(), |test_harness| async move { @@ -1226,17 +1168,20 @@ fn blank_subsystem_act_on_bad_block() { overseer_send( &mut virtual_overseer, FromOrchestra::Communication { - msg: ApprovalVotingMessage::CheckAndImportAssignment( - IndirectAssignmentCertV2 { - block_hash: bad_block_hash, - validator: 0u32.into(), - cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { - sample: 0, - }) - .into(), - }, - 0u32.into(), - tx, + msg: ApprovalVotingMessage::ImportAssignment( + CheckedIndirectAssignment::from_checked( + IndirectAssignmentCertV2 { + block_hash: bad_block_hash, + validator: 0u32.into(), + cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { + sample: 0, + }) + .into(), + }, + 0u32.into(), + 0, + ), + Some(tx), ), }, ) @@ -1299,7 +1244,7 @@ fn subsystem_rejects_approval_if_no_candidate_entry() { }); let session_index = 1; - let rx = check_and_import_approval( + let rx = import_approval( &mut virtual_overseer, block_hash, candidate_index, @@ -1340,7 +1285,7 @@ fn subsystem_rejects_approval_if_no_block_entry() { let candidate_hash = dummy_candidate_receipt(block_hash).hash(); let session_index = 1; - let rx = check_and_import_approval( + let rx = import_approval( &mut virtual_overseer, block_hash, candidate_index, @@ -1405,7 +1350,7 @@ fn subsystem_rejects_approval_before_assignment() { .build(&mut virtual_overseer) .await; - let rx = check_and_import_approval( + let rx = import_approval( &mut virtual_overseer, block_hash, candidate_index, @@ -1428,68 +1373,6 @@ fn subsystem_rejects_approval_before_assignment() { }); } -#[test] -fn subsystem_rejects_assignment_in_future() { - let assignment_criteria = - Box::new(MockAssignmentCriteria::check_only(|_| Ok(TICK_TOO_FAR_IN_FUTURE as _))); - let config = HarnessConfigBuilder::default().assignment_criteria(assignment_criteria).build(); - test_harness(config, |test_harness| async move { - let TestHarness { mut virtual_overseer, clock, sync_oracle_handle: _sync_oracle_handle } = - test_harness; - assert_matches!( - overseer_recv(&mut virtual_overseer).await, - AllMessages::ChainApi(ChainApiMessage::FinalizedBlockNumber(rx)) => { - rx.send(Ok(0)).unwrap(); - } - ); - - let block_hash = Hash::repeat_byte(0x01); - let candidate_index = 0; - let validator = ValidatorIndex(0); - - // Add block hash 00. - ChainBuilder::new() - .add_block( - block_hash, - ChainBuilder::GENESIS_HASH, - 1, - BlockConfig { - slot: Slot::from(0), - candidates: None, - session_info: None, - end_syncing: false, - }, - ) - .build(&mut virtual_overseer) - .await; - - let rx = check_and_import_assignment( - &mut virtual_overseer, - block_hash, - candidate_index, - validator, - ) - .await; - - assert_eq!(rx.await, Ok(AssignmentCheckResult::TooFarInFuture)); - - // Advance clock to make assignment reasonably near. - clock.inner.lock().set_tick(9); - - let rx = check_and_import_assignment( - &mut virtual_overseer, - block_hash, - candidate_index, - validator, - ) - .await; - - assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted)); - - virtual_overseer - }); -} - #[test] fn subsystem_accepts_duplicate_assignment() { test_harness(HarnessConfig::default(), |test_harness| async move { @@ -1539,7 +1422,7 @@ fn subsystem_accepts_duplicate_assignment() { .await; // Initial assignment. - let rx = check_and_import_assignment_v2( + let rx = import_assignment_v2( &mut virtual_overseer, block_hash, vec![candidate_index1, candidate_index2], @@ -1550,19 +1433,15 @@ fn subsystem_accepts_duplicate_assignment() { assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted)); // Test with single assigned core. - let rx = check_and_import_assignment( - &mut virtual_overseer, - block_hash, - candidate_index, - validator, - ) - .await; + let rx = + import_assignment(&mut virtual_overseer, block_hash, candidate_index, validator, 0) + .await; assert_eq!(rx.await, Ok(AssignmentCheckResult::AcceptedDuplicate)); // Test with multiple assigned cores. This cannot happen in practice, as tranche0 // assignments are sent first, but we should still ensure correct behavior. - let rx = check_and_import_assignment_v2( + let rx = import_assignment_v2( &mut virtual_overseer, block_hash, vec![candidate_index1, candidate_index2], @@ -1608,13 +1487,9 @@ fn subsystem_rejects_assignment_with_unknown_candidate() { .build(&mut virtual_overseer) .await; - let rx = check_and_import_assignment( - &mut virtual_overseer, - block_hash, - candidate_index, - validator, - ) - .await; + let rx = + import_assignment(&mut virtual_overseer, block_hash, candidate_index, validator, 0) + .await; assert_eq!( rx.await, @@ -1658,13 +1533,9 @@ fn subsystem_rejects_oversized_bitfields() { .build(&mut virtual_overseer) .await; - let rx = check_and_import_assignment( - &mut virtual_overseer, - block_hash, - candidate_index, - validator, - ) - .await; + let rx = + import_assignment(&mut virtual_overseer, block_hash, candidate_index, validator, 0) + .await; assert_eq!( rx.await, @@ -1673,13 +1544,9 @@ fn subsystem_rejects_oversized_bitfields() { ))), ); - let rx = check_and_import_assignment_v2( - &mut virtual_overseer, - block_hash, - vec![1, 2, 10, 50], - validator, - ) - .await; + let rx = + import_assignment_v2(&mut virtual_overseer, block_hash, vec![1, 2, 10, 50], validator) + .await; assert_eq!( rx.await, @@ -1731,17 +1598,13 @@ fn subsystem_accepts_and_imports_approval_after_assignment() { .build(&mut virtual_overseer) .await; - let rx = check_and_import_assignment( - &mut virtual_overseer, - block_hash, - candidate_index, - validator, - ) - .await; + let rx = + import_assignment(&mut virtual_overseer, block_hash, candidate_index, validator, 0) + .await; assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted)); - let rx = check_and_import_approval( + let rx = import_approval( &mut virtual_overseer, block_hash, candidate_index, @@ -1823,19 +1686,15 @@ fn subsystem_second_approval_import_only_schedules_wakeups() { .build(&mut virtual_overseer) .await; - let rx = check_and_import_assignment( - &mut virtual_overseer, - block_hash, - candidate_index, - validator, - ) - .await; + let rx = + import_assignment(&mut virtual_overseer, block_hash, candidate_index, validator, 0) + .await; assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted)); assert!(clock.inner.lock().current_wakeup_is(APPROVAL_DELAY + 2)); - let rx = check_and_import_approval( + let rx = import_approval( &mut virtual_overseer, block_hash, candidate_index, @@ -1852,7 +1711,7 @@ fn subsystem_second_approval_import_only_schedules_wakeups() { futures_timer::Delay::new(Duration::from_millis(100)).await; assert!(clock.inner.lock().current_wakeup_is(APPROVAL_DELAY + 2)); - let rx = check_and_import_approval( + let rx = import_approval( &mut virtual_overseer, block_hash, candidate_index, @@ -1911,13 +1770,9 @@ fn subsystem_assignment_import_updates_candidate_entry_and_schedules_wakeup() { .build(&mut virtual_overseer) .await; - let rx = check_and_import_assignment( - &mut virtual_overseer, - block_hash, - candidate_index, - validator, - ) - .await; + let rx = + import_assignment(&mut virtual_overseer, block_hash, candidate_index, validator, 0) + .await; assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted)); @@ -2033,20 +1888,17 @@ fn test_approvals_on_fork_are_always_considered_after_no_show( .await; // Send assignments for the same candidate on both forks - let rx = check_and_import_assignment( - &mut virtual_overseer, - block_hash, - candidate_index, - validator, - ) - .await; + let rx = + import_assignment(&mut virtual_overseer, block_hash, candidate_index, validator, 0) + .await; assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted)); - let rx = check_and_import_assignment( + let rx = import_assignment( &mut virtual_overseer, block_hash_fork, candidate_index, validator, + 0, ) .await; @@ -2076,7 +1928,7 @@ fn test_approvals_on_fork_are_always_considered_after_no_show( futures_timer::Delay::new(Duration::from_millis(100)).await; // Send the approval for candidate just in the context of 0x01 block. - let rx = check_and_import_approval( + let rx = import_approval( &mut virtual_overseer, block_hash, candidate_index, @@ -2146,13 +1998,9 @@ fn subsystem_process_wakeup_schedules_wakeup() { .build(&mut virtual_overseer) .await; - let rx = check_and_import_assignment( - &mut virtual_overseer, - block_hash, - candidate_index, - validator, - ) - .await; + let rx = + import_assignment(&mut virtual_overseer, block_hash, candidate_index, validator, 0) + .await; assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted)); @@ -2205,17 +2053,20 @@ fn linear_import_act_on_leaf() { overseer_send( &mut virtual_overseer, FromOrchestra::Communication { - msg: ApprovalVotingMessage::CheckAndImportAssignment( - IndirectAssignmentCertV2 { - block_hash: head, - validator: 0u32.into(), - cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { - sample: 0, - }) - .into(), - }, - 0u32.into(), - tx, + msg: ApprovalVotingMessage::ImportAssignment( + CheckedIndirectAssignment::from_checked( + IndirectAssignmentCertV2 { + block_hash: head, + validator: 0u32.into(), + cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { + sample: 0, + }) + .into(), + }, + 0u32.into(), + 0, + ), + Some(tx), ), }, ) @@ -2276,17 +2127,20 @@ fn forkful_import_at_same_height_act_on_leaf() { overseer_send( &mut virtual_overseer, FromOrchestra::Communication { - msg: ApprovalVotingMessage::CheckAndImportAssignment( - IndirectAssignmentCertV2 { - block_hash: head, - validator: 0u32.into(), - cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { - sample: 0, - }) - .into(), - }, - 0u32.into(), - tx, + msg: ApprovalVotingMessage::ImportAssignment( + CheckedIndirectAssignment::from_checked( + IndirectAssignmentCertV2 { + block_hash: head, + validator: 0u32.into(), + cert: garbage_assignment_cert(AssignmentCertKind::RelayVRFModulo { + sample: 0, + }) + .into(), + }, + 0u32.into(), + 0, + ), + Some(tx), ), }, ) @@ -2443,21 +2297,23 @@ fn import_checked_approval_updates_entries_and_schedules() { let candidate_index = 0; - let rx = check_and_import_assignment( + let rx = import_assignment( &mut virtual_overseer, block_hash, candidate_index, validator_index_a, + 0, ) .await; assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted),); - let rx = check_and_import_assignment( + let rx = import_assignment( &mut virtual_overseer, block_hash, candidate_index, validator_index_b, + 0, ) .await; @@ -2466,7 +2322,7 @@ fn import_checked_approval_updates_entries_and_schedules() { let session_index = 1; let sig_a = sign_approval(Sr25519Keyring::Alice, candidate_hash, session_index); - let rx = check_and_import_approval( + let rx = import_approval( &mut virtual_overseer, block_hash, candidate_index, @@ -2493,7 +2349,7 @@ fn import_checked_approval_updates_entries_and_schedules() { clock.inner.lock().wakeup_all(2); let sig_b = sign_approval(Sr25519Keyring::Bob, candidate_hash, session_index); - let rx = check_and_import_approval( + let rx = import_approval( &mut virtual_overseer, block_hash, candidate_index, @@ -2606,13 +2462,9 @@ fn subsystem_import_checked_approval_sets_one_block_bit_at_a_time() { ]; for (candidate_index, validator) in assignments { - let rx = check_and_import_assignment( - &mut virtual_overseer, - block_hash, - candidate_index, - validator, - ) - .await; + let rx = + import_assignment(&mut virtual_overseer, block_hash, candidate_index, validator, 0) + .await; assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted)); } @@ -2633,7 +2485,7 @@ fn subsystem_import_checked_approval_sets_one_block_bit_at_a_time() { } else { sign_approval(Sr25519Keyring::Bob, *candidate_hash, session_index) }; - let rx = check_and_import_approval( + let rx = import_approval( &mut virtual_overseer, block_hash, *candidate_index, @@ -2891,11 +2743,12 @@ fn approved_ancestor_test( for (i, (block_hash, candidate_hash)) in block_hashes.iter().zip(candidate_hashes).enumerate() { - let rx = check_and_import_assignment( + let rx = import_assignment( &mut virtual_overseer, *block_hash, candidate_index, validator, + 0, ) .await; assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted)); @@ -2904,7 +2757,7 @@ fn approved_ancestor_test( continue } - let rx = check_and_import_approval( + let rx = import_approval( &mut virtual_overseer, *block_hash, candidate_index, @@ -3359,7 +3212,8 @@ where F1: 'static + Fn(ValidatorIndex) -> Result + Send - + Sync, + + Sync + + Clone, F2: Fn(Tick) -> bool, { let TriggersAssignmentConfig { @@ -3388,7 +3242,7 @@ where ); assignments }, - assign_validator_tranche, + assign_validator_tranche.clone(), )); let config = HarnessConfigBuilder::default().assignment_criteria(assignment_criteria).build(); let store = config.backend(); @@ -3449,11 +3303,12 @@ where .await; for validator in assignments_to_import { - let rx = check_and_import_assignment( + let rx = import_assignment( &mut virtual_overseer, block_hash, candidate_index, ValidatorIndex(validator), + assign_validator_tranche(ValidatorIndex(validator)).unwrap(), ) .await; assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted)); @@ -3462,7 +3317,7 @@ where let n_validators = validators.len(); for (i, &validator_index) in approvals_to_import.iter().enumerate() { let expect_chain_approved = 3 * (i + 1) > n_validators; - let rx = check_and_import_approval( + let rx = import_approval( &mut virtual_overseer, block_hash, candidate_index, @@ -3767,31 +3622,34 @@ fn pre_covers_dont_stall_approval() { let candidate_index = 0; - let rx = check_and_import_assignment( + let rx = import_assignment( &mut virtual_overseer, block_hash, candidate_index, validator_index_a, + 0, ) .await; assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted),); - let rx = check_and_import_assignment( + let rx = import_assignment( &mut virtual_overseer, block_hash, candidate_index, validator_index_b, + 0, ) .await; assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted),); - let rx = check_and_import_assignment( + let rx = import_assignment( &mut virtual_overseer, block_hash, candidate_index, validator_index_c, + 1, ) .await; @@ -3800,7 +3658,7 @@ fn pre_covers_dont_stall_approval() { let session_index = 1; let sig_b = sign_approval(Sr25519Keyring::Bob, candidate_hash, session_index); - let rx = check_and_import_approval( + let rx = import_approval( &mut virtual_overseer, block_hash, candidate_index, @@ -3815,7 +3673,7 @@ fn pre_covers_dont_stall_approval() { assert_eq!(rx.await, Ok(ApprovalCheckResult::Accepted),); let sig_c = sign_approval(Sr25519Keyring::Charlie, candidate_hash, session_index); - let rx = check_and_import_approval( + let rx = import_approval( &mut virtual_overseer, block_hash, candidate_index, @@ -3945,21 +3803,23 @@ fn waits_until_approving_assignments_are_old_enough() { let candidate_index = 0; - let rx = check_and_import_assignment( + let rx = import_assignment( &mut virtual_overseer, block_hash, candidate_index, validator_index_a, + 0, ) .await; assert_eq!(rx.await, Ok(AssignmentCheckResult::Accepted),); - let rx = check_and_import_assignment( + let rx = import_assignment( &mut virtual_overseer, block_hash, candidate_index, validator_index_b, + 0, ) .await; @@ -3970,7 +3830,7 @@ fn waits_until_approving_assignments_are_old_enough() { let session_index = 1; let sig_a = sign_approval(Sr25519Keyring::Alice, candidate_hash, session_index); - let rx = check_and_import_approval( + let rx = import_approval( &mut virtual_overseer, block_hash, candidate_index, @@ -3986,7 +3846,7 @@ fn waits_until_approving_assignments_are_old_enough() { let sig_b = sign_approval(Sr25519Keyring::Bob, candidate_hash, session_index); - let rx = check_and_import_approval( + let rx = import_approval( &mut virtual_overseer, block_hash, candidate_index, @@ -4249,7 +4109,7 @@ async fn handle_approval_on_max_coalesce_count( async fn handle_approval_on_max_wait_time( virtual_overseer: &mut VirtualOverseer, candidate_indices: Vec, - clock: Box, + clock: Arc, ) { const TICK_NOW_BEGIN: u64 = 1; const MAX_COALESCE_COUNT: u32 = 3; @@ -4547,7 +4407,7 @@ async fn build_chain_with_two_blocks_with_one_candidate_each( async fn setup_overseer_with_two_blocks_each_with_one_assignment_triggered( virtual_overseer: &mut VirtualOverseer, store: TestStore, - clock: &Box, + clock: &Arc, sync_oracle_handle: TestSyncOracleHandle, ) { assert_matches!( @@ -4996,7 +4856,6 @@ fn subsystem_sends_pending_approvals_on_approval_restart() { })); } ); - assert_matches!( overseer_recv(&mut virtual_overseer).await, AllMessages::RuntimeApi( @@ -5062,9 +4921,8 @@ fn test_gathering_assignments_statements() { let mut state = State { keystore: Arc::new(LocalKeystore::in_memory()), slot_duration_millis: 6_000, - clock: Box::new(MockClock::default()), + clock: Arc::new(MockClock::default()), assignment_criteria: Box::new(MockAssignmentCriteria::check_only(|_| Ok(0))), - spans: HashMap::new(), per_block_assignments_gathering_times: LruMap::new(ByLength::new( MAX_BLOCKS_WITH_ASSIGNMENT_TIMESTAMPS, )), @@ -5157,9 +5015,8 @@ fn test_observe_assignment_gathering_status() { let mut state = State { keystore: Arc::new(LocalKeystore::in_memory()), slot_duration_millis: 6_000, - clock: Box::new(MockClock::default()), + clock: Arc::new(MockClock::default()), assignment_criteria: Box::new(MockAssignmentCriteria::check_only(|_| Ok(0))), - spans: HashMap::new(), per_block_assignments_gathering_times: LruMap::new(ByLength::new( MAX_BLOCKS_WITH_ASSIGNMENT_TIMESTAMPS, )), diff --git a/polkadot/node/core/av-store/Cargo.toml b/polkadot/node/core/av-store/Cargo.toml index 4274c8b576a3..1d14e4cfba37 100644 --- a/polkadot/node/core/av-store/Cargo.toml +++ b/polkadot/node/core/av-store/Cargo.toml @@ -25,13 +25,12 @@ polkadot-overseer = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } sp-consensus = { workspace = true } -polkadot-node-jaeger = { workspace = true, default-features = true } [dev-dependencies] log = { workspace = true, default-features = true } -env_logger = { 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/lib.rs b/polkadot/node/core/av-store/src/lib.rs index 7b245c9e3c52..9473040e8f5e 100644 --- a/polkadot/node/core/av-store/src/lib.rs +++ b/polkadot/node/core/av-store/src/lib.rs @@ -39,7 +39,6 @@ use polkadot_node_subsystem_util::database::{DBTransaction, Database}; use sp_consensus::SyncOracle; use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; -use polkadot_node_jaeger as jaeger; use polkadot_node_primitives::{AvailableData, ErasureChunk}; use polkadot_node_subsystem::{ errors::{ChainApiError, RuntimeApiError}, @@ -1315,10 +1314,6 @@ fn store_available_data( }, }; - let erasure_span = jaeger::Span::new(candidate_hash, "erasure-coding") - .with_candidate(candidate_hash) - .with_pov(&available_data.pov); - // Important note: This check below is critical for consensus and the `backing` subsystem relies // on it to ensure candidate validity. let chunks = polkadot_erasure_coding::obtain_chunks_v1(n_validators, &available_data)?; @@ -1328,8 +1323,6 @@ fn store_available_data( return Err(Error::InvalidErasureRoot) } - drop(erasure_span); - let erasure_chunks: Vec<_> = chunks .iter() .zip(branches.map(|(proof, _)| proof)) diff --git a/polkadot/node/core/av-store/src/tests.rs b/polkadot/node/core/av-store/src/tests.rs index 04a223730bcd..958917a3104f 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/backing/Cargo.toml b/polkadot/node/core/backing/Cargo.toml index 1b52afc309bc..bd56a3ad693b 100644 --- a/polkadot/node/core/backing/Cargo.toml +++ b/polkadot/node/core/backing/Cargo.toml @@ -14,6 +14,7 @@ futures = { workspace = true } sp-keystore = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } +polkadot-parachain-primitives = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } polkadot-node-subsystem-util = { workspace = true, default-features = true } polkadot-erasure-coding = { workspace = true, default-features = true } diff --git a/polkadot/node/core/backing/src/lib.rs b/polkadot/node/core/backing/src/lib.rs index 5bcd47a2434c..4463fb34b510 100644 --- a/polkadot/node/core/backing/src/lib.rs +++ b/polkadot/node/core/backing/src/lib.rs @@ -89,8 +89,9 @@ use polkadot_node_subsystem::{ AvailabilityDistributionMessage, AvailabilityStoreMessage, CanSecondRequest, CandidateBackingMessage, CandidateValidationMessage, CollatorProtocolMessage, HypotheticalCandidate, HypotheticalMembershipRequest, IntroduceSecondedCandidateRequest, - ProspectiveParachainsMessage, ProvisionableData, ProvisionerMessage, RuntimeApiMessage, - RuntimeApiRequest, StatementDistributionMessage, StoreAvailableDataError, + ProspectiveParachainsMessage, ProvisionableData, ProvisionerMessage, PvfExecKind, + RuntimeApiMessage, RuntimeApiRequest, StatementDistributionMessage, + StoreAvailableDataError, }, overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, }; @@ -100,17 +101,18 @@ use polkadot_node_subsystem_util::{ executor_params_at_relay_parent, request_from_runtime, request_session_index_for_child, request_validator_groups, request_validators, runtime::{ - self, prospective_parachains_mode, request_min_backing_votes, ProspectiveParachainsMode, + self, fetch_claim_queue, prospective_parachains_mode, request_min_backing_votes, + ClaimQueueSnapshot, ProspectiveParachainsMode, }, - vstaging::{fetch_claim_queue, ClaimQueueSnapshot}, Validator, }; +use polkadot_parachain_primitives::primitives::IsSystem; use polkadot_primitives::{ node_features::FeatureIndex, BackedCandidate, CandidateCommitments, CandidateHash, CandidateReceipt, CommittedCandidateReceipt, CoreIndex, CoreState, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, Id as ParaId, IndexedVec, NodeFeatures, PersistedValidationData, - PvfExecKind, SessionIndex, SigningContext, ValidationCode, ValidatorId, ValidatorIndex, - ValidatorSignature, ValidityAttestation, + SessionIndex, SigningContext, ValidationCode, ValidatorId, ValidatorIndex, ValidatorSignature, + ValidityAttestation, }; use polkadot_statement_table::{ generic::AttestedCandidate as TableAttestedCandidate, @@ -121,7 +123,7 @@ use polkadot_statement_table::{ Config as TableConfig, Context as TableContextTrait, Table, }; use sp_keystore::KeystorePtr; -use util::{runtime::request_node_features, vstaging::get_disabled_validators_with_fallback}; +use util::runtime::{get_disabled_validators_with_fallback, request_node_features}; mod error; @@ -625,6 +627,7 @@ async fn request_candidate_validation( executor_params: ExecutorParams, ) -> Result { let (tx, rx) = oneshot::channel(); + let is_system = candidate_receipt.descriptor.para_id.is_system(); sender .send_message(CandidateValidationMessage::ValidateFromExhaustive { @@ -633,7 +636,11 @@ async fn request_candidate_validation( candidate_receipt, pov, executor_params, - exec_kind: PvfExecKind::Backing, + exec_kind: if is_system { + PvfExecKind::BackingSystemParas + } else { + PvfExecKind::Backing + }, response_sender: tx, }) .await; diff --git a/polkadot/node/core/backing/src/tests/mod.rs b/polkadot/node/core/backing/src/tests/mod.rs index 10eb45b82d12..d9c1fc9499e5 100644 --- a/polkadot/node/core/backing/src/tests/mod.rs +++ b/polkadot/node/core/backing/src/tests/mod.rs @@ -30,7 +30,7 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_test_helpers as test_helpers; use polkadot_primitives::{ node_features, CandidateDescriptor, GroupRotationInfo, HeadData, PersistedValidationData, - PvfExecKind, ScheduledCore, SessionIndex, LEGACY_MIN_BACKING_VOTES, + ScheduledCore, SessionIndex, LEGACY_MIN_BACKING_VOTES, }; use polkadot_primitives_test_helpers::{ dummy_candidate_receipt_bad_sig, dummy_collator, dummy_collator_signature, @@ -434,7 +434,7 @@ async fn assert_validate_from_exhaustive( ) if validation_data == *assert_pvd && validation_code == *assert_validation_code && *pov == *assert_pov && &candidate_receipt.descriptor == assert_candidate.descriptor() && - exec_kind == PvfExecKind::Backing && + exec_kind == PvfExecKind::BackingSystemParas && candidate_receipt.commitments_hash == assert_candidate.commitments.hash() => { response_sender.send(Ok(ValidationResult::Valid( @@ -651,7 +651,7 @@ fn backing_works(#[case] elastic_scaling_mvp: bool) { ) if validation_data == pvd_ab && validation_code == validation_code_ab && *pov == pov_ab && &candidate_receipt.descriptor == candidate_a.descriptor() && - exec_kind == PvfExecKind::Backing && + exec_kind == PvfExecKind::BackingSystemParas && candidate_receipt.commitments_hash == candidate_a_commitments_hash => { response_sender.send(Ok( @@ -1287,7 +1287,7 @@ fn backing_works_while_validation_ongoing() { ) if validation_data == pvd_abc && validation_code == validation_code_abc && *pov == pov_abc && &candidate_receipt.descriptor == candidate_a.descriptor() && - exec_kind == PvfExecKind::Backing && + exec_kind == PvfExecKind::BackingSystemParas && candidate_a_commitments_hash == candidate_receipt.commitments_hash => { // we never validate the candidate. our local node @@ -1454,7 +1454,7 @@ fn backing_misbehavior_works() { ) if validation_data == pvd_a && validation_code == validation_code_a && *pov == pov_a && &candidate_receipt.descriptor == candidate_a.descriptor() && - exec_kind == PvfExecKind::Backing && + exec_kind == PvfExecKind::BackingSystemParas && candidate_a_commitments_hash == candidate_receipt.commitments_hash => { response_sender.send(Ok( @@ -1621,7 +1621,7 @@ fn backing_dont_second_invalid() { ) if validation_data == pvd_a && validation_code == validation_code_a && *pov == pov_block_a && &candidate_receipt.descriptor == candidate_a.descriptor() && - exec_kind == PvfExecKind::Backing && + exec_kind == PvfExecKind::BackingSystemParas && candidate_a.commitments.hash() == candidate_receipt.commitments_hash => { response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::BadReturn))).unwrap(); @@ -1661,7 +1661,7 @@ fn backing_dont_second_invalid() { ) if validation_data == pvd_b && validation_code == validation_code_b && *pov == pov_block_b && &candidate_receipt.descriptor == candidate_b.descriptor() && - exec_kind == PvfExecKind::Backing && + exec_kind == PvfExecKind::BackingSystemParas && candidate_b.commitments.hash() == candidate_receipt.commitments_hash => { response_sender.send(Ok( @@ -1788,7 +1788,7 @@ fn backing_second_after_first_fails_works() { ) if validation_data == pvd_a && validation_code == validation_code_a && *pov == pov_a && &candidate_receipt.descriptor == candidate.descriptor() && - exec_kind == PvfExecKind::Backing && + exec_kind == PvfExecKind::BackingSystemParas && candidate.commitments.hash() == candidate_receipt.commitments_hash => { response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::BadReturn))).unwrap(); @@ -1932,7 +1932,7 @@ fn backing_works_after_failed_validation() { ) if validation_data == pvd_a && validation_code == validation_code_a && *pov == pov_a && &candidate_receipt.descriptor == candidate.descriptor() && - exec_kind == PvfExecKind::Backing && + exec_kind == PvfExecKind::BackingSystemParas && candidate.commitments.hash() == candidate_receipt.commitments_hash => { response_sender.send(Err(ValidationFailed("Internal test error".into()))).unwrap(); @@ -2211,7 +2211,7 @@ fn retry_works() { ) if validation_data == pvd_a && validation_code == validation_code_a && *pov == pov_a && &candidate_receipt.descriptor == candidate.descriptor() && - exec_kind == PvfExecKind::Backing && + exec_kind == PvfExecKind::BackingSystemParas && candidate.commitments.hash() == candidate_receipt.commitments_hash ); virtual_overseer @@ -2753,7 +2753,7 @@ fn validator_ignores_statements_from_disabled_validators() { ) if validation_data == pvd && validation_code == expected_validation_code && *pov == expected_pov && &candidate_receipt.descriptor == candidate.descriptor() && - exec_kind == PvfExecKind::Backing && + exec_kind == PvfExecKind::BackingSystemParas && candidate_commitments_hash == candidate_receipt.commitments_hash => { response_sender.send(Ok( diff --git a/polkadot/node/core/backing/src/tests/prospective_parachains.rs b/polkadot/node/core/backing/src/tests/prospective_parachains.rs index 15bc0b4a1139..57b2fabd43b0 100644 --- a/polkadot/node/core/backing/src/tests/prospective_parachains.rs +++ b/polkadot/node/core/backing/src/tests/prospective_parachains.rs @@ -276,7 +276,7 @@ async fn assert_validate_seconded_candidate( &validation_code == assert_validation_code && &*pov == assert_pov && &candidate_receipt.descriptor == candidate.descriptor() && - exec_kind == PvfExecKind::Backing && + exec_kind == PvfExecKind::BackingSystemParas && candidate.commitments.hash() == candidate_receipt.commitments_hash => { response_sender.send(Ok(ValidationResult::Valid( diff --git a/polkadot/node/core/bitfield-signing/src/lib.rs b/polkadot/node/core/bitfield-signing/src/lib.rs index e3effb7949ea..474de1c66abd 100644 --- a/polkadot/node/core/bitfield-signing/src/lib.rs +++ b/polkadot/node/core/bitfield-signing/src/lib.rs @@ -27,10 +27,9 @@ use futures::{ FutureExt, }; use polkadot_node_subsystem::{ - jaeger, messages::{AvailabilityStoreMessage, BitfieldDistributionMessage}, - overseer, ActivatedLeaf, FromOrchestra, OverseerSignal, PerLeafSpan, SpawnedSubsystem, - SubsystemError, SubsystemResult, + overseer, ActivatedLeaf, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, + SubsystemResult, }; use polkadot_node_subsystem_util::{ self as util, request_availability_cores, runtime::recv_runtime, Validator, @@ -80,11 +79,8 @@ async fn get_core_availability( core: &CoreState, validator_index: ValidatorIndex, sender: &Mutex<&mut impl overseer::BitfieldSigningSenderTrait>, - span: &jaeger::Span, ) -> Result { if let CoreState::Occupied(core) = core { - let _span = span.child("query-chunk-availability"); - let (tx, rx) = oneshot::channel(); sender .lock() @@ -118,15 +114,12 @@ async fn get_core_availability( /// prone to false negatives) async fn construct_availability_bitfield( relay_parent: Hash, - span: &jaeger::Span, validator_idx: ValidatorIndex, sender: &mut impl overseer::BitfieldSigningSenderTrait, ) -> Result { // get the set of availability cores from the runtime - let availability_cores = { - let _span = span.child("get-availability-cores"); - recv_runtime(request_availability_cores(relay_parent, sender).await).await? - }; + let availability_cores = + { recv_runtime(request_availability_cores(relay_parent, sender).await).await? }; // Wrap the sender in a Mutex to share it between the futures. // @@ -140,7 +133,7 @@ async fn construct_availability_bitfield( let results = future::try_join_all( availability_cores .iter() - .map(|core| get_core_availability(core, validator_idx, &sender, span)), + .map(|core| get_core_availability(core, validator_idx, &sender)), ) .await?; @@ -234,8 +227,6 @@ async fn handle_active_leaves_update( where Sender: overseer::BitfieldSigningSenderTrait, { - let span = PerLeafSpan::new(leaf.span, "bitfield-signing"); - let span_delay = span.child("delay"); let wait_until = Instant::now() + SPAWNED_TASK_DELAY; // now do all the work we can before we need to wait for the availability store @@ -253,28 +244,16 @@ where // SPAWNED_TASK_DELAY each time. let _timer = metrics.time_run(); - drop(span_delay); - let span_availability = span.child("availability"); - - let bitfield = match construct_availability_bitfield( - leaf.hash, - &span_availability, - validator.index(), - &mut sender, - ) - .await - { - Err(Error::Runtime(runtime_err)) => { - // Don't take down the node on runtime API errors. - gum::warn!(target: LOG_TARGET, err = ?runtime_err, "Encountered a runtime API error"); - return Ok(()) - }, - Err(err) => return Err(err), - Ok(bitfield) => bitfield, - }; - - drop(span_availability); - let span_signing = span.child("signing"); + let bitfield = + match construct_availability_bitfield(leaf.hash, validator.index(), &mut sender).await { + Err(Error::Runtime(runtime_err)) => { + // Don't take down the node on runtime API errors. + gum::warn!(target: LOG_TARGET, err = ?runtime_err, "Encountered a runtime API error"); + return Ok(()) + }, + Err(err) => return Err(err), + Ok(bitfield) => bitfield, + }; let signed_bitfield = match validator.sign(keystore, bitfield).map_err(|e| Error::Keystore(e))? { @@ -290,9 +269,6 @@ where metrics.on_bitfield_signed(); - drop(span_signing); - let _span_gossip = span.child("gossip"); - sender .send_message(BitfieldDistributionMessage::DistributeBitfield(leaf.hash, signed_bitfield)) .await; diff --git a/polkadot/node/core/bitfield-signing/src/tests.rs b/polkadot/node/core/bitfield-signing/src/tests.rs index eeaa524d1c63..c08018375cf3 100644 --- a/polkadot/node/core/bitfield-signing/src/tests.rs +++ b/polkadot/node/core/bitfield-signing/src/tests.rs @@ -40,13 +40,8 @@ fn construct_availability_bitfield_works() { let validator_index = ValidatorIndex(1u32); let (mut sender, mut receiver) = polkadot_node_subsystem_test_helpers::sender_receiver(); - let future = construct_availability_bitfield( - relay_parent, - &jaeger::Span::Disabled, - validator_index, - &mut sender, - ) - .fuse(); + let future = + construct_availability_bitfield(relay_parent, validator_index, &mut sender).fuse(); pin_mut!(future); let hash_a = CandidateHash(Hash::repeat_byte(1)); diff --git a/polkadot/node/core/candidate-validation/Cargo.toml b/polkadot/node/core/candidate-validation/Cargo.toml index e1a98f80783f..fcacc38cae65 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 76619bd391f2..e875be9b5df9 100644 --- a/polkadot/node/core/candidate-validation/src/lib.rs +++ b/polkadot/node/core/candidate-validation/src/lib.rs @@ -27,37 +27,38 @@ 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::{ - CandidateValidationMessage, PreCheckOutcome, RuntimeApiMessage, RuntimeApiRequest, - ValidationFailed, + CandidateValidationMessage, PreCheckOutcome, PvfExecKind, RuntimeApiMessage, + RuntimeApiRequest, ValidationFailed, }, 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, PersistedValidationData, + PvfExecKind as RuntimePvfExecKind, PvfPrepKind, SessionIndex, ValidationCode, + ValidationCodeHash, ValidatorId, }; +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, @@ -83,12 +84,11 @@ const PVF_APPROVAL_EXECUTION_RETRY_DELAY: Duration = Duration::from_secs(3); const PVF_APPROVAL_EXECUTION_RETRY_DELAY: Duration = Duration::from_millis(200); // The task queue size is chosen to be somewhat bigger than the PVF host incoming queue size -// to allow exhaustive validation messages to fall through in case the tasks are clogged with -// `ValidateFromChainState` messages awaiting data from the runtime +// to allow exhaustive validation messages to fall through in case the tasks are clogged 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 } @@ -153,30 +155,6 @@ where S: SubsystemSender, { match msg { - CandidateValidationMessage::ValidateFromChainState { - candidate_receipt, - pov, - executor_params, - exec_kind, - response_sender, - .. - } => async move { - let _timer = metrics.time_validate_from_chain_state(); - let res = validate_from_chain_state( - &mut sender, - validation_host, - candidate_receipt, - pov, - executor_params, - exec_kind, - &metrics, - ) - .await; - - metrics.on_validation_event(&res); - let _ = response_sender.send(res); - } - .boxed(), CandidateValidationMessage::ValidateFromExhaustive { validation_data, validation_code, @@ -223,6 +201,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 +232,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 +280,238 @@ 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)])); + + // We could've checked discovery_keys but on Kusama validators.len() < discovery_keys.len(). + let is_present_validator = session_info + .validators + .iter() + .any(|v| keystore.has_keys(&[(v.to_raw_vec(), ValidatorId::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_validator +} + +// 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 +592,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, @@ -427,170 +633,6 @@ where } } -#[derive(Debug)] -enum AssumptionCheckOutcome { - Matches(PersistedValidationData, ValidationCode), - DoesNotMatch, - BadRequest, -} - -async fn check_assumption_validation_data( - sender: &mut Sender, - descriptor: &CandidateDescriptor, - assumption: OccupiedCoreAssumption, -) -> AssumptionCheckOutcome -where - Sender: SubsystemSender, -{ - let validation_data = { - let (tx, rx) = oneshot::channel(); - let d = runtime_api_request( - sender, - descriptor.relay_parent, - RuntimeApiRequest::PersistedValidationData(descriptor.para_id, assumption, tx), - rx, - ) - .await; - - match d { - Ok(None) | Err(RuntimeRequestFailed) => return AssumptionCheckOutcome::BadRequest, - Ok(Some(d)) => d, - } - }; - - let persisted_validation_data_hash = validation_data.hash(); - - if descriptor.persisted_validation_data_hash == persisted_validation_data_hash { - let (code_tx, code_rx) = oneshot::channel(); - let validation_code = runtime_api_request( - sender, - descriptor.relay_parent, - RuntimeApiRequest::ValidationCode(descriptor.para_id, assumption, code_tx), - code_rx, - ) - .await; - - match validation_code { - Ok(None) | Err(RuntimeRequestFailed) => AssumptionCheckOutcome::BadRequest, - Ok(Some(v)) => AssumptionCheckOutcome::Matches(validation_data, v), - } - } else { - AssumptionCheckOutcome::DoesNotMatch - } -} - -async fn find_assumed_validation_data( - sender: &mut Sender, - descriptor: &CandidateDescriptor, -) -> AssumptionCheckOutcome -where - Sender: SubsystemSender, -{ - // The candidate descriptor has a `persisted_validation_data_hash` which corresponds to - // one of up to two possible values that we can derive from the state of the - // relay-parent. We can fetch these values by getting the persisted validation data - // based on the different `OccupiedCoreAssumption`s. - - const ASSUMPTIONS: &[OccupiedCoreAssumption] = &[ - OccupiedCoreAssumption::Included, - OccupiedCoreAssumption::TimedOut, - // `TimedOut` and `Free` both don't perform any speculation and therefore should be the - // same for our purposes here. In other words, if `TimedOut` matched then the `Free` must - // be matched as well. - ]; - - // Consider running these checks in parallel to reduce validation latency. - for assumption in ASSUMPTIONS { - let outcome = check_assumption_validation_data(sender, descriptor, *assumption).await; - - match outcome { - AssumptionCheckOutcome::Matches(_, _) => return outcome, - AssumptionCheckOutcome::BadRequest => return outcome, - AssumptionCheckOutcome::DoesNotMatch => continue, - } - } - - AssumptionCheckOutcome::DoesNotMatch -} - -/// Returns validation data for a given candidate. -pub async fn find_validation_data( - sender: &mut Sender, - descriptor: &CandidateDescriptor, -) -> Result, ValidationFailed> -where - Sender: SubsystemSender, -{ - match find_assumed_validation_data(sender, &descriptor).await { - AssumptionCheckOutcome::Matches(validation_data, validation_code) => - Ok(Some((validation_data, validation_code))), - AssumptionCheckOutcome::DoesNotMatch => { - // If neither the assumption of the occupied core having the para included or the - // assumption of the occupied core timing out are valid, then the - // persisted_validation_data_hash in the descriptor is not based on the relay parent and - // is thus invalid. - Ok(None) - }, - AssumptionCheckOutcome::BadRequest => - Err(ValidationFailed("Assumption Check: Bad request".into())), - } -} - -async fn validate_from_chain_state( - sender: &mut Sender, - validation_host: ValidationHost, - candidate_receipt: CandidateReceipt, - pov: Arc, - executor_params: ExecutorParams, - exec_kind: PvfExecKind, - metrics: &Metrics, -) -> Result -where - Sender: SubsystemSender, -{ - let mut new_sender = sender.clone(); - let (validation_data, validation_code) = - match find_validation_data(&mut new_sender, &candidate_receipt.descriptor).await? { - Some((validation_data, validation_code)) => (validation_data, validation_code), - None => return Ok(ValidationResult::Invalid(InvalidCandidate::BadParent)), - }; - - let validation_result = validate_candidate_exhaustive( - validation_host, - validation_data, - validation_code, - candidate_receipt.clone(), - pov, - executor_params, - exec_kind, - metrics, - ) - .await; - - if let Ok(ValidationResult::Valid(ref outputs, _)) = validation_result { - let (tx, rx) = oneshot::channel(); - match runtime_api_request( - sender, - candidate_receipt.descriptor.relay_parent, - RuntimeApiRequest::CheckValidationOutputs( - candidate_receipt.descriptor.para_id, - outputs.clone(), - tx, - ), - rx, - ) - .await - { - Ok(true) => {}, - Ok(false) => return Ok(ValidationResult::Invalid(InvalidCandidate::InvalidOutputs)), - Err(RuntimeRequestFailed) => - return Err(ValidationFailed("Check Validation Outputs: Bad request".into())), - } - } - - validation_result -} - async fn validate_candidate_exhaustive( mut validation_backend: impl ValidationBackend + Send, persisted_validation_data: PersistedValidationData, @@ -622,49 +664,15 @@ 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. - PvfExecKind::Backing => { + PvfExecKind::Backing | PvfExecKind::BackingSystemParas => { let prep_timeout = pvf_prep_timeout(&executor_params, PvfPrepKind::Prepare); - let exec_timeout = pvf_exec_timeout(&executor_params, exec_kind); + let exec_timeout = pvf_exec_timeout(&executor_params, exec_kind.into()); let pvf = PvfPrepData::from_code( - raw_validation_code.to_vec(), + validation_code.0, executor_params, prep_timeout, PrepareJobKind::Compilation, @@ -674,20 +682,24 @@ async fn validate_candidate_exhaustive( .validate_candidate( pvf, exec_timeout, - params.encode(), - polkadot_node_core_pvf::Priority::Normal, + persisted_validation_data.clone(), + pov, + exec_kind.into(), + exec_kind, ) .await }, - PvfExecKind::Approval => + PvfExecKind::Approval | PvfExecKind::Dispute => validation_backend .validate_candidate_with_retry( - raw_validation_code.to_vec(), - pvf_exec_timeout(&executor_params, exec_kind), - params, + validation_code.0, + pvf_exec_timeout(&executor_params, exec_kind.into()), + persisted_validation_data.clone(), + pov, executor_params, PVF_APPROVAL_EXECUTION_RETRY_DELAY, - polkadot_node_core_pvf::Priority::Critical, + exec_kind.into(), + exec_kind, ) .await, }; @@ -710,6 +722,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 +770,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,9 +783,12 @@ 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, + // The kind for the execution job. + exec_kind: PvfExecKind, ) -> Result; /// Tries executing a PVF. Will retry once if an error is encountered that may have @@ -784,18 +801,21 @@ 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. prepare_priority: polkadot_node_core_pvf::Priority, + // The kind for the execution job. + exec_kind: PvfExecKind, ) -> Result { 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 +826,14 @@ 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, + exec_kind, + ) .await; if validation_result.is_ok() { return validation_result @@ -879,10 +906,15 @@ 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, + exec_kind, + ) .await; } } @@ -891,6 +923,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 +934,17 @@ 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, + // The kind for the execution job. + exec_kind: PvfExecKind, ) -> 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, exec_kind, tx) + .await { return Err(InternalValidationError::HostCommunication(format!( "cannot send pvf to the validation host, it might have shut down: {:?}", @@ -933,6 +971,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 @@ -994,12 +1036,12 @@ fn pvf_prep_timeout(executor_params: &ExecutorParams, kind: PvfPrepKind) -> Dura /// This should be much longer than the backing execution timeout to ensure that in the /// absence of extremely large disparities between hardware, blocks that pass backing are /// considered executable by approval checkers or dispute participants. -fn pvf_exec_timeout(executor_params: &ExecutorParams, kind: PvfExecKind) -> Duration { +fn pvf_exec_timeout(executor_params: &ExecutorParams, kind: RuntimePvfExecKind) -> Duration { if let Some(timeout) = executor_params.pvf_exec_timeout(kind) { return timeout } match kind { - PvfExecKind::Backing => DEFAULT_BACKING_EXECUTION_TIMEOUT, - PvfExecKind::Approval => DEFAULT_APPROVAL_EXECUTION_TIMEOUT, + RuntimePvfExecKind::Backing => DEFAULT_BACKING_EXECUTION_TIMEOUT, + RuntimePvfExecKind::Approval => DEFAULT_APPROVAL_EXECUTION_TIMEOUT, } } diff --git a/polkadot/node/core/candidate-validation/src/metrics.rs b/polkadot/node/core/candidate-validation/src/metrics.rs index 28fc957ddb1a..76ccd56555f9 100644 --- a/polkadot/node/core/candidate-validation/src/metrics.rs +++ b/polkadot/node/core/candidate-validation/src/metrics.rs @@ -20,11 +20,8 @@ use polkadot_node_metrics::metrics::{self, prometheus}; #[derive(Clone)] pub(crate) struct MetricsInner { pub(crate) validation_requests: prometheus::CounterVec, - 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. @@ -48,13 +45,6 @@ impl Metrics { } } - /// Provide a timer for `validate_from_chain_state` which observes on drop. - pub fn time_validate_from_chain_state( - &self, - ) -> Option { - self.0.as_ref().map(|metrics| metrics.validate_from_chain_state.start_timer()) - } - /// Provide a timer for `validate_from_exhaustive` which observes on drop. pub fn time_validate_from_exhaustive( &self, @@ -70,21 +60,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 { @@ -100,13 +75,6 @@ impl metrics::Metrics for Metrics { )?, registry, )?, - validate_from_chain_state: prometheus::register( - prometheus::Histogram::with_opts(prometheus::HistogramOpts::new( - "polkadot_parachain_candidate_validation_validate_from_chain_state", - "Time spent within `candidate_validation::validate_from_chain_state`", - ))?, - registry, - )?, validate_from_exhaustive: prometheus::register( prometheus::Histogram::with_opts(prometheus::HistogramOpts::new( "polkadot_parachain_candidate_validation_validate_from_exhaustive", @@ -121,33 +89,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 491ed7a335d8..2f7baf4abb61 100644 --- a/polkadot/node/core/candidate-validation/src/tests.rs +++ b/polkadot/node/core/candidate-validation/src/tests.rs @@ -14,16 +14,79 @@ // 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 crate::PvfExecKind; 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 sp_core::testing::TaskExecutor; +use polkadot_overseer::ActivatedLeaf; +use polkadot_primitives::{ + CoreIndex, GroupIndex, HeadData, Id as ParaId, OccupiedCoreAssumption, SessionInfo, + UpwardMessage, ValidatorId, +}; +use polkadot_primitives_test_helpers::{ + dummy_collator, dummy_collator_signature, dummy_hash, make_valid_candidate_descriptor, +}; +use sp_core::{sr25519::Public, testing::TaskExecutor}; use sp_keyring::Sr25519Keyring; +use sp_keystore::{testing::MemoryKeystore, Keystore}; + +#[derive(Debug)] +enum AssumptionCheckOutcome { + Matches(PersistedValidationData, ValidationCode), + DoesNotMatch, + BadRequest, +} + +async fn check_assumption_validation_data( + sender: &mut Sender, + descriptor: &CandidateDescriptor, + assumption: OccupiedCoreAssumption, +) -> AssumptionCheckOutcome +where + Sender: SubsystemSender, +{ + let validation_data = { + let (tx, rx) = oneshot::channel(); + let d = runtime_api_request( + sender, + descriptor.relay_parent, + RuntimeApiRequest::PersistedValidationData(descriptor.para_id, assumption, tx), + rx, + ) + .await; + + match d { + Ok(None) | Err(RuntimeRequestFailed) => return AssumptionCheckOutcome::BadRequest, + Ok(Some(d)) => d, + } + }; + + let persisted_validation_data_hash = validation_data.hash(); + + if descriptor.persisted_validation_data_hash == persisted_validation_data_hash { + let (code_tx, code_rx) = oneshot::channel(); + let validation_code = runtime_api_request( + sender, + descriptor.relay_parent, + RuntimeApiRequest::ValidationCode(descriptor.para_id, assumption, code_tx), + code_rx, + ) + .await; + + match validation_code { + Ok(None) | Err(RuntimeRequestFailed) => AssumptionCheckOutcome::BadRequest, + Ok(Some(v)) => AssumptionCheckOutcome::Matches(validation_data, v), + } + } else { + AssumptionCheckOutcome::DoesNotMatch + } +} #[test] fn correctly_checks_included_assumption() { @@ -376,8 +439,10 @@ impl ValidationBackend for MockValidateCandidateBackend { &mut self, _pvf: PvfPrepData, _timeout: Duration, - _encoded_params: Vec, + _pvd: Arc, + _pov: Arc, _prepare_priority: polkadot_node_core_pvf::Priority, + _exec_kind: PvfExecKind, ) -> Result { // This is expected to panic if called more times than expected, indicating an error in the // test. @@ -390,6 +455,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 +1006,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,8 +1022,10 @@ impl ValidationBackend for MockPreCheckBackend { &mut self, _pvf: PvfPrepData, _timeout: Duration, - _encoded_params: Vec, + _pvd: Arc, + _pov: Arc, _prepare_priority: polkadot_node_core_pvf::Priority, + _exec_kind: PvfExecKind, ) -> Result { unreachable!() } @@ -1071,6 +1033,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 +1098,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 +1165,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, + _exec_kind: PvfExecKind, + ) -> 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), + }), + ..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(keys: Vec) -> SessionInfo { + SessionInfo { + validators: keys.iter().cloned().map(Into::into).collect(), + discovery_keys: keys.iter().cloned().map(Into::into).collect(), + 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()])))); + } + ); + + 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()])))); + } + ); + }; + + 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()])))); + } + ); + }; + + 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()])))); + } + ); + }; + + 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()])))); + } + ); + + 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/dispute-coordinator/src/initialized.rs b/polkadot/node/core/dispute-coordinator/src/initialized.rs index 5f86da87f21c..9cf9047b7273 100644 --- a/polkadot/node/core/dispute-coordinator/src/initialized.rs +++ b/polkadot/node/core/dispute-coordinator/src/initialized.rs @@ -34,8 +34,9 @@ use polkadot_node_primitives::{ }; use polkadot_node_subsystem::{ messages::{ - ApprovalVotingMessage, BlockDescription, ChainSelectionMessage, DisputeCoordinatorMessage, - DisputeDistributionMessage, ImportStatementsResult, + ApprovalVotingMessage, ApprovalVotingParallelMessage, BlockDescription, + ChainSelectionMessage, DisputeCoordinatorMessage, DisputeDistributionMessage, + ImportStatementsResult, }, overseer, ActivatedLeaf, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, RuntimeApiError, }; @@ -117,6 +118,7 @@ pub(crate) struct Initialized { /// `CHAIN_IMPORT_MAX_BATCH_SIZE` and put the rest here for later processing. chain_import_backlog: VecDeque, metrics: Metrics, + approval_voting_parallel_enabled: bool, } #[overseer::contextbounds(DisputeCoordinator, prefix = self::overseer)] @@ -130,7 +132,13 @@ impl Initialized { highest_session_seen: SessionIndex, gaps_in_cache: bool, ) -> Self { - let DisputeCoordinatorSubsystem { config: _, store: _, keystore, metrics } = subsystem; + let DisputeCoordinatorSubsystem { + config: _, + store: _, + keystore, + metrics, + approval_voting_parallel_enabled, + } = subsystem; let (participation_sender, participation_receiver) = mpsc::channel(1); let participation = Participation::new(participation_sender, metrics.clone()); @@ -148,6 +156,7 @@ impl Initialized { participation_receiver, chain_import_backlog: VecDeque::new(), metrics, + approval_voting_parallel_enabled, } } @@ -1059,9 +1068,21 @@ impl Initialized { // 4. We are waiting (and blocking the whole subsystem) on a response right after - // therefore even with all else failing we will never have more than // one message in flight at any given time. - ctx.send_unbounded_message( - ApprovalVotingMessage::GetApprovalSignaturesForCandidate(candidate_hash, tx), - ); + if self.approval_voting_parallel_enabled { + ctx.send_unbounded_message( + ApprovalVotingParallelMessage::GetApprovalSignaturesForCandidate( + candidate_hash, + tx, + ), + ); + } else { + ctx.send_unbounded_message( + ApprovalVotingMessage::GetApprovalSignaturesForCandidate( + candidate_hash, + tx, + ), + ); + } match rx.await { Err(_) => { gum::warn!( @@ -1351,6 +1372,12 @@ impl Initialized { } } for validator_index in new_state.votes().invalid.keys() { + gum::debug!( + target: LOG_TARGET, + ?candidate_hash, + ?validator_index, + "Disabled offchain for voting invalid against a valid candidate", + ); self.offchain_disabled_validators .insert_against_valid(session, *validator_index); } @@ -1375,6 +1402,13 @@ impl Initialized { } for (validator_index, (kind, _sig)) in new_state.votes().valid.raw() { let is_backer = kind.is_backing(); + gum::debug!( + target: LOG_TARGET, + ?candidate_hash, + ?validator_index, + ?is_backer, + "Disabled offchain for voting valid for an invalid candidate", + ); self.offchain_disabled_validators.insert_for_invalid( session, *validator_index, diff --git a/polkadot/node/core/dispute-coordinator/src/lib.rs b/polkadot/node/core/dispute-coordinator/src/lib.rs index daa384b36ffb..84408eb96305 100644 --- a/polkadot/node/core/dispute-coordinator/src/lib.rs +++ b/polkadot/node/core/dispute-coordinator/src/lib.rs @@ -122,6 +122,7 @@ pub struct DisputeCoordinatorSubsystem { store: Arc, keystore: Arc, metrics: Metrics, + approval_voting_parallel_enabled: bool, } /// Configuration for the dispute coordinator subsystem. @@ -164,8 +165,9 @@ impl DisputeCoordinatorSubsystem { config: Config, keystore: Arc, metrics: Metrics, + approval_voting_parallel_enabled: bool, ) -> Self { - Self { store, config, keystore, metrics } + Self { store, config, keystore, metrics, approval_voting_parallel_enabled } } /// Initialize and afterwards run `Initialized::run`. @@ -478,6 +480,18 @@ pub fn is_potential_spam( let all_invalid_votes_disabled = vote_state.invalid_votes_all_disabled(is_disabled); let ignore_disabled = !is_confirmed && all_invalid_votes_disabled; + gum::trace!( + target: LOG_TARGET, + ?candidate_hash, + ?is_disputed, + ?is_included, + ?is_backed, + ?is_confirmed, + ?all_invalid_votes_disabled, + ?ignore_disabled, + "Checking for potential spam" + ); + (is_disputed && !is_included && !is_backed && !is_confirmed) || ignore_disabled } diff --git a/polkadot/node/core/dispute-coordinator/src/participation/mod.rs b/polkadot/node/core/dispute-coordinator/src/participation/mod.rs index b58ce570f8ff..2220f65e20a7 100644 --- a/polkadot/node/core/dispute-coordinator/src/participation/mod.rs +++ b/polkadot/node/core/dispute-coordinator/src/participation/mod.rs @@ -27,13 +27,11 @@ use futures_timer::Delay; use polkadot_node_primitives::ValidationResult; use polkadot_node_subsystem::{ - messages::{AvailabilityRecoveryMessage, CandidateValidationMessage}, + messages::{AvailabilityRecoveryMessage, CandidateValidationMessage, PvfExecKind}, overseer, ActiveLeavesUpdate, RecoveryError, }; use polkadot_node_subsystem_util::runtime::get_validation_code_by_hash; -use polkadot_primitives::{ - BlockNumber, CandidateHash, CandidateReceipt, Hash, PvfExecKind, SessionIndex, -}; +use polkadot_primitives::{BlockNumber, CandidateHash, CandidateReceipt, Hash, SessionIndex}; use crate::LOG_TARGET; @@ -387,7 +385,7 @@ async fn participate( candidate_receipt: req.candidate_receipt().clone(), pov: available_data.pov, executor_params: req.executor_params(), - exec_kind: PvfExecKind::Approval, + exec_kind: PvfExecKind::Dispute, response_sender: validation_tx, }) .await; diff --git a/polkadot/node/core/dispute-coordinator/src/participation/tests.rs b/polkadot/node/core/dispute-coordinator/src/participation/tests.rs index a80553828ac6..a6ab6f16df05 100644 --- a/polkadot/node/core/dispute-coordinator/src/participation/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/participation/tests.rs @@ -26,7 +26,7 @@ use codec::Encode; use polkadot_node_primitives::{AvailableData, BlockData, InvalidCandidate, PoV}; use polkadot_node_subsystem::{ messages::{ - AllMessages, ChainApiMessage, DisputeCoordinatorMessage, RuntimeApiMessage, + AllMessages, ChainApiMessage, DisputeCoordinatorMessage, PvfExecKind, RuntimeApiMessage, RuntimeApiRequest, }, ActiveLeavesUpdate, SpawnGlue, @@ -116,7 +116,7 @@ pub async fn participation_full_happy_path( ctx_handle.recv().await, AllMessages::CandidateValidation( CandidateValidationMessage::ValidateFromExhaustive { candidate_receipt, exec_kind, response_sender, .. } - ) if exec_kind == PvfExecKind::Approval => { + ) if exec_kind == PvfExecKind::Dispute => { if expected_commitments_hash != candidate_receipt.commitments_hash { response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch))).unwrap(); } else { @@ -450,7 +450,7 @@ fn cast_invalid_vote_if_validation_fails_or_is_invalid() { ctx_handle.recv().await, AllMessages::CandidateValidation( CandidateValidationMessage::ValidateFromExhaustive { exec_kind, response_sender, .. } - ) if exec_kind == PvfExecKind::Approval => { + ) if exec_kind == PvfExecKind::Dispute => { response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::Timeout))).unwrap(); }, "overseer did not receive candidate validation message", @@ -487,7 +487,7 @@ fn cast_invalid_vote_if_commitments_dont_match() { ctx_handle.recv().await, AllMessages::CandidateValidation( CandidateValidationMessage::ValidateFromExhaustive { exec_kind, response_sender, .. } - ) if exec_kind == PvfExecKind::Approval => { + ) if exec_kind == PvfExecKind::Dispute => { response_sender.send(Ok(ValidationResult::Invalid(InvalidCandidate::CommitmentsHashMismatch))).unwrap(); }, "overseer did not receive candidate validation message", @@ -524,7 +524,7 @@ fn cast_valid_vote_if_validation_passes() { ctx_handle.recv().await, AllMessages::CandidateValidation( CandidateValidationMessage::ValidateFromExhaustive { exec_kind, response_sender, .. } - ) if exec_kind == PvfExecKind::Approval => { + ) if exec_kind == PvfExecKind::Dispute => { response_sender.send(Ok(ValidationResult::Valid(dummy_candidate_commitments(None), PersistedValidationData::default()))).unwrap(); }, "overseer did not receive candidate validation message", diff --git a/polkadot/node/core/dispute-coordinator/src/tests.rs b/polkadot/node/core/dispute-coordinator/src/tests.rs index f97a625a9528..48762a1d80be 100644 --- a/polkadot/node/core/dispute-coordinator/src/tests.rs +++ b/polkadot/node/core/dispute-coordinator/src/tests.rs @@ -580,6 +580,7 @@ impl TestState { self.config, self.subsystem_keystore.clone(), Metrics::default(), + false, ); let backend = DbBackend::new(self.db.clone(), self.config.column_config(), Metrics::default()); @@ -2796,7 +2797,7 @@ fn participation_with_onchain_disabling_confirmed() { }) .await; - handle_disabled_validators_queries(&mut virtual_overseer, vec![]).await; + handle_disabled_validators_queries(&mut virtual_overseer, vec![disabled_index]).await; handle_approval_vote_request(&mut virtual_overseer, &candidate_hash, HashMap::new()) .await; assert_eq!(confirmation_rx.await, Ok(ImportStatementsResult::ValidImport)); diff --git a/polkadot/node/core/prospective-parachains/Cargo.toml b/polkadot/node/core/prospective-parachains/Cargo.toml index 97da5a1e94a0..705014e67a05 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 2b0933ab1c7e..4b332b9c5de5 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 f87d4820ff9a..b060897d4391 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 26ee94d59d8e..3332cbeb03cb 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_shuffled.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 e4b6deffdf4a..b8b5f159e71c 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,10 +43,10 @@ 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}, - vstaging::fetch_claim_queue, + runtime::{fetch_claim_queue, prospective_parachains_mode, ProspectiveParachainsMode}, }; use polkadot_primitives::{ async_backing::CandidatePendingAvailability, BlockNumber, CandidateHash, @@ -55,8 +57,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 +72,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 +156,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 +184,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 +228,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 +268,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 +277,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 +305,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 +479,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 +491,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 +505,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 +672,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 +682,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 +711,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 +760,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 +798,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 +814,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 +836,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 +939,7 @@ async fn fetch_ancestry( cache: &mut HashMap, relay_hash: Hash, ancestors: usize, -) -> JfyiErrorResult> { +) -> JfyiErrorResult> { if ancestors == 0 { return Ok(Vec::new()) } @@ -1004,12 +1018,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 5abd9f56f306..78561bc878ac 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 221fbf4c4e60..14a093239e8e 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 3f622a60a059..9a06d9cff0cc 100644 --- a/polkadot/node/core/provisioner/src/lib.rs +++ b/polkadot/node/core/provisioner/src/lib.rs @@ -27,13 +27,12 @@ use futures_timer::Delay; use schnellru::{ByLength, LruMap}; use polkadot_node_subsystem::{ - jaeger, messages::{ Ancestors, CandidateBackingMessage, ChainApiMessage, ProspectiveParachainsMessage, ProvisionableData, ProvisionerInherentData, ProvisionerMessage, RuntimeApiRequest, }, - overseer, ActivatedLeaf, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, PerLeafSpan, - SpawnedSubsystem, SubsystemError, + overseer, ActivatedLeaf, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, SpawnedSubsystem, + SubsystemError, }; use polkadot_node_subsystem_util::{ has_required_runtime, request_availability_cores, request_persisted_validation_data, @@ -95,13 +94,10 @@ pub struct PerRelayParent { signed_bitfields: Vec, is_inherent_ready: bool, awaiting_inherent: Vec>, - span: PerLeafSpan, } impl PerRelayParent { fn new(leaf: ActivatedLeaf, per_session: &PerSession) -> Self { - let span = PerLeafSpan::new(leaf.span.clone(), "provisioner"); - Self { leaf, backed_candidates: Vec::new(), @@ -110,7 +106,6 @@ impl PerRelayParent { signed_bitfields: Vec::new(), is_inherent_ready: false, awaiting_inherent: Vec::new(), - span, } } } @@ -270,12 +265,11 @@ async fn handle_communication( }, ProvisionerMessage::ProvisionableData(relay_parent, data) => { if let Some(state) = per_relay_parent.get_mut(&relay_parent) { - 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); + note_provisionable_data(state, data); } }, } @@ -295,12 +289,10 @@ async fn send_inherent_data_bg( let backed_candidates = per_relay_parent.backed_candidates.clone(); let mode = per_relay_parent.prospective_parachains_mode; let elastic_scaling_mvp = per_relay_parent.elastic_scaling_mvp; - let span = per_relay_parent.span.child("req-inherent-data"); let mut sender = ctx.sender().clone(); let bg = async move { - let _span = span; let _timer = metrics.time_request_inherent_data(); gum::trace!( @@ -359,7 +351,6 @@ async fn send_inherent_data_bg( fn note_provisionable_data( per_relay_parent: &mut PerRelayParent, - span: &jaeger::Span, provisionable_data: ProvisionableData, ) { match provisionable_data { @@ -373,10 +364,7 @@ fn note_provisionable_data( para = ?backed_candidate.descriptor().para_id, "noted backed candidate", ); - let _span = span - .child("provisionable-backed") - .with_candidate(candidate_hash) - .with_para_id(backed_candidate.descriptor().para_id); + per_relay_parent.backed_candidates.push(backed_candidate); }, // We choose not to punish these forms of misbehavior for the time being. @@ -794,9 +782,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 7444f7927f56..13fcdc69a99a 100644 --- a/polkadot/node/core/pvf/Cargo.toml +++ b/polkadot/node/core/pvf/Cargo.toml @@ -24,6 +24,7 @@ slotmap = { workspace = true } tempfile = { workspace = true } thiserror = { workspace = true } tokio = { features = ["fs", "process"], workspace = true, default-features = true } +strum = { features = ["derive"], workspace = true, default-features = true } codec = { features = [ "derive", @@ -60,7 +61,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 97a03e6596d1..342128b7cca2 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/build.rs b/polkadot/node/core/pvf/build.rs index e01cc6deecc2..e46f2dc5f55a 100644 --- a/polkadot/node/core/pvf/build.rs +++ b/polkadot/node/core/pvf/build.rs @@ -16,6 +16,6 @@ fn main() { if let Ok(profile) = std::env::var("PROFILE") { - println!(r#"cargo:rustc-cfg=build_type="{}""#, profile); + println!(r#"cargo:rustc-cfg=build_profile="{}""#, profile); } } diff --git a/polkadot/node/core/pvf/common/Cargo.toml b/polkadot/node/core/pvf/common/Cargo.toml index 18b3f959c955..903c8dd1af29 100644 --- a/polkadot/node/core/pvf/common/Cargo.toml +++ b/polkadot/node/core/pvf/common/Cargo.toml @@ -17,9 +17,7 @@ libc = { workspace = true } nix = { features = ["resource", "sched"], workspace = true } thiserror = { workspace = true } -codec = { features = [ - "derive", -], workspace = true } +codec = { features = ["derive"], workspace = true } polkadot-parachain-primitives = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } @@ -42,6 +40,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 7ee05448d3c5..b0cdba9501db 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 46862f9f80b6..cff3f3b86e95 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 81e165a7b8a4..4cd1beb30991 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 e2ac36a2406a..4019a8d8b0d0 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/common/src/worker/security/change_root.rs b/polkadot/node/core/pvf/common/src/worker/security/change_root.rs index 9ec66906819f..fcfaf6541c29 100644 --- a/polkadot/node/core/pvf/common/src/worker/security/change_root.rs +++ b/polkadot/node/core/pvf/common/src/worker/security/change_root.rs @@ -124,7 +124,8 @@ fn try_restrict(worker_info: &WorkerInfo) -> Result<()> { libc::MS_BIND | libc::MS_REC | libc::MS_NOEXEC | libc::MS_NODEV | libc::MS_NOSUID | - libc::MS_NOATIME | additional_flags, + libc::MS_NOATIME | + additional_flags, ptr::null(), // ignored when MS_BIND is used ) < 0 { diff --git a/polkadot/node/core/pvf/execute-worker/Cargo.toml b/polkadot/node/core/pvf/execute-worker/Cargo.toml index f24b66dc4a0e..6ad340d25612 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 35858ab36cec..4b7c167cc9ec 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 9e0d01fc438b..56235bd82192 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 d531c90b64b5..49b30dc33ceb 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 ef33d11720eb..f8ebb6effcec 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/artifacts.rs b/polkadot/node/core/pvf/src/artifacts.rs index 119af34082a9..1126a0c90c8c 100644 --- a/polkadot/node/core/pvf/src/artifacts.rs +++ b/polkadot/node/core/pvf/src/artifacts.rs @@ -56,7 +56,7 @@ use crate::{host::PrecheckResultSender, worker_interface::WORKER_DIR_PREFIX}; use always_assert::always; -use polkadot_node_core_pvf_common::{error::PrepareError, prepare::PrepareStats, pvf::PvfPrepData}; +use polkadot_node_core_pvf_common::{error::PrepareError, pvf::PvfPrepData}; use polkadot_parachain_primitives::primitives::ValidationCodeHash; use polkadot_primitives::ExecutorParamsPrepHash; use std::{ @@ -144,8 +144,6 @@ pub enum ArtifactState { last_time_needed: SystemTime, /// Size in bytes size: u64, - /// Stats produced by successful preparation. - prepare_stats: PrepareStats, }, /// A task to prepare this artifact is scheduled. Preparing { @@ -269,15 +267,11 @@ impl Artifacts { path: PathBuf, last_time_needed: SystemTime, size: u64, - prepare_stats: PrepareStats, ) { // See the precondition. always!(self .inner - .insert( - artifact_id, - ArtifactState::Prepared { path, last_time_needed, size, prepare_stats } - ) + .insert(artifact_id, ArtifactState::Prepared { path, last_time_needed, size }) .is_none()); } @@ -384,21 +378,18 @@ mod tests { path1.clone(), mock_now - Duration::from_secs(5), 1024, - PrepareStats::default(), ); artifacts.insert_prepared( artifact_id2.clone(), path2.clone(), mock_now - Duration::from_secs(10), 1024, - PrepareStats::default(), ); artifacts.insert_prepared( artifact_id3.clone(), path3.clone(), mock_now - Duration::from_secs(15), 1024, - PrepareStats::default(), ); let pruned = artifacts.prune(&cleanup_config); @@ -432,21 +423,18 @@ mod tests { path1.clone(), mock_now - Duration::from_secs(5), 1024, - PrepareStats::default(), ); artifacts.insert_prepared( artifact_id2.clone(), path2.clone(), mock_now - Duration::from_secs(10), 1024, - PrepareStats::default(), ); artifacts.insert_prepared( artifact_id3.clone(), path3.clone(), mock_now - Duration::from_secs(15), 1024, - PrepareStats::default(), ); let pruned = artifacts.prune(&cleanup_config); diff --git a/polkadot/node/core/pvf/src/error.rs b/polkadot/node/core/pvf/src/error.rs index 8dc96305eadb..a0634106052d 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 bb00a5a652d6..2ac5116912eb 100644 --- a/polkadot/node/core/pvf/src/execute/queue.rs +++ b/polkadot/node/core/pvf/src/execute/queue.rs @@ -34,14 +34,18 @@ use polkadot_node_core_pvf_common::{ execute::{JobResponse, WorkerError, WorkerResponse}, SecurityStatus, }; -use polkadot_primitives::{ExecutorParams, ExecutorParamsHash}; +use polkadot_node_primitives::PoV; +use polkadot_node_subsystem::messages::PvfExecKind; +use polkadot_primitives::{ExecutorParams, ExecutorParamsHash, PersistedValidationData}; use slotmap::HopSlotMap; use std::{ - collections::VecDeque, + collections::{HashMap, VecDeque}, fmt, path::PathBuf, + sync::Arc, time::{Duration, Instant}, }; +use strum::IntoEnumIterator; /// The amount of time a job for which the queue does not have a compatible worker may wait in the /// queue. After that time passes, the queue will kill the first worker which becomes idle to @@ -68,15 +72,18 @@ 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, + pub exec_kind: PvfExecKind, } struct ExecuteJob { artifact: ArtifactPathId, exec_timeout: Duration, - params: Vec, + pvd: Arc, + pov: Arc, executor_params: ExecutorParams, result_tx: ResultSender, waiting_since: Instant, @@ -136,7 +143,7 @@ impl Workers { enum QueueEvent { Spawn(IdleWorker, WorkerHandle, ExecuteJob), - StartWork( + FinishWork( Worker, Result, ArtifactId, @@ -162,7 +169,7 @@ struct Queue { security_status: SecurityStatus, /// The queue of jobs that are waiting for a worker to pick up. - queue: VecDeque, + unscheduled: Unscheduled, workers: Workers, mux: Mux, } @@ -188,7 +195,7 @@ impl Queue { security_status, to_queue_rx, from_queue_tx, - queue: VecDeque::new(), + unscheduled: Unscheduled::new(), mux: Mux::new(), workers: Workers { running: HopSlotMap::with_capacity_and_key(10), @@ -222,9 +229,13 @@ impl Queue { /// If all the workers are busy or the queue is empty, it does nothing. /// Should be called every time a new job arrives to the queue or a job finishes. fn try_assign_next_job(&mut self, finished_worker: Option) { - // New jobs are always pushed to the tail of the queue; the one at its head is always - // the eldest one. - let eldest = if let Some(eldest) = self.queue.get(0) { eldest } else { return }; + // We always work at the same priority level + let priority = self.unscheduled.select_next_priority(); + let Some(queue) = self.unscheduled.get_mut(priority) else { return }; + + // New jobs are always pushed to the tail of the queue based on their priority; + // the one at its head of each queue is always the eldest one. + let eldest = if let Some(eldest) = queue.get(0) { eldest } else { return }; // By default, we're going to execute the eldest job on any worker slot available, even if // we have to kill and re-spawn a worker @@ -236,7 +247,7 @@ impl Queue { if eldest.waiting_since.elapsed() < MAX_KEEP_WAITING { if let Some(finished_worker) = finished_worker { if let Some(worker_data) = self.workers.running.get(finished_worker) { - for (i, job) in self.queue.iter().enumerate() { + for (i, job) in queue.iter().enumerate() { if worker_data.executor_params_hash == job.executor_params.hash() { (worker, job_index) = (Some(finished_worker), i); break @@ -248,7 +259,7 @@ impl Queue { if worker.is_none() { // Try to obtain a worker for the job - worker = self.workers.find_available(self.queue[job_index].executor_params.hash()); + worker = self.workers.find_available(queue[job_index].executor_params.hash()); } if worker.is_none() { @@ -266,13 +277,15 @@ impl Queue { return } - let job = self.queue.remove(job_index).expect("Job is just checked to be in queue; qed"); + let job = queue.remove(job_index).expect("Job is just checked to be in queue; qed"); if let Some(worker) = worker { assign(self, worker, job); } else { spawn_extra_worker(self, job); } + self.metrics.on_execute_kind(priority); + self.unscheduled.mark_scheduled(priority); } } @@ -293,23 +306,25 @@ 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, exec_kind } = 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(), }; - queue.queue.push_back(job); + queue.unscheduled.add(job, exec_kind); queue.try_assign_next_job(None); } @@ -318,7 +333,7 @@ async fn handle_mux(queue: &mut Queue, event: QueueEvent) { QueueEvent::Spawn(idle, handle, job) => { handle_worker_spawned(queue, idle, handle, job); }, - QueueEvent::StartWork(worker, outcome, artifact_id, result_tx) => { + QueueEvent::FinishWork(worker, outcome, artifact_id, result_tx) => { handle_job_finish(queue, worker, outcome, artifact_id, result_tx).await; }, } @@ -352,15 +367,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 +389,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 +424,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,10 +611,11 @@ 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) + QueueEvent::FinishWork(worker, result, job.artifact.id, job.result_tx) } .boxed(), ); @@ -608,3 +647,297 @@ pub fn start( .run(); (to_queue_tx, from_queue_rx, run) } + +struct Unscheduled { + unscheduled: HashMap>, + counter: HashMap, +} + +impl Unscheduled { + /// We keep track of every scheduled job in the `counter`, but reset it if the total number of + /// counted jobs reaches the threshold. This number is set as the maximum amount of jobs per + /// relay chain block possible with 4 CPU cores and 2 seconds of execution time. Under normal + /// conditions, the maximum expected queue size is at least vrf_module_samples(6) + 1 for + /// backing a parachain candidate. A buffer is added to cover situations where more work + /// arrives in the queue. + const SCHEDULING_WINDOW_SIZE: usize = 12; + + /// A threshold in percentages indicates how much time a current priority can "steal" from lower + /// priorities. Given the `SCHEDULING_WINDOW_SIZE` is 12 and all job priorities are present: + /// - Disputes consume 70% or 8 jobs in a row. + /// - The remaining 30% of original 100% is allocated for approval and all backing jobs. + /// - 80% or 3 jobs of the remaining goes to approvals. + /// - The remaining 6% of original 100% is allocated for all backing jobs. + /// - 100% or 1 job of the remaining goes to backing system parachains. + /// - Nothing is left for backing. + /// - The counter is restarted and the distribution starts from the beginning. + /// + /// This system might seem complex, but we operate with the remaining percentages because: + /// - Not all job types are present in each block. If we used parts of the original 100%, + /// approvals could not exceed 24%, even if there are no disputes. + /// - We cannot fully prioritize backing system parachains over backing other parachains based + /// on the distribution of the original 100%. + const PRIORITY_ALLOCATION_THRESHOLDS: &'static [(PvfExecKind, usize)] = &[ + (PvfExecKind::Dispute, 70), + (PvfExecKind::Approval, 80), + (PvfExecKind::BackingSystemParas, 100), + (PvfExecKind::Backing, 100), + ]; + + fn new() -> Self { + Self { + unscheduled: PvfExecKind::iter().map(|priority| (priority, VecDeque::new())).collect(), + counter: PvfExecKind::iter().map(|priority| (priority, 0)).collect(), + } + } + + fn select_next_priority(&self) -> PvfExecKind { + gum::debug!( + target: LOG_TARGET, + unscheduled = ?self.unscheduled.iter().map(|(p, q)| (*p, q.len())).collect::>(), + counter = ?self.counter, + "Selecting next execution priority...", + ); + + let priority = PvfExecKind::iter() + .find(|priority| self.has_pending(priority) && !self.has_reached_threshold(priority)) + .unwrap_or_else(|| { + PvfExecKind::iter() + .find(|priority| self.has_pending(priority)) + .unwrap_or(PvfExecKind::Backing) + }); + + gum::debug!( + target: LOG_TARGET, + ?priority, + "Selected next execution priority", + ); + + priority + } + + fn get_mut(&mut self, priority: PvfExecKind) -> Option<&mut VecDeque> { + self.unscheduled.get_mut(&priority) + } + + fn add(&mut self, job: ExecuteJob, priority: PvfExecKind) { + self.unscheduled.entry(priority).or_default().push_back(job); + } + + fn has_pending(&self, priority: &PvfExecKind) -> bool { + !self.unscheduled.get(priority).unwrap_or(&VecDeque::new()).is_empty() + } + + fn priority_allocation_threshold(priority: &PvfExecKind) -> Option { + Self::PRIORITY_ALLOCATION_THRESHOLDS.iter().find_map(|&(p, value)| { + if p == *priority { + Some(value) + } else { + None + } + }) + } + + /// Checks if a given priority has reached its allocated threshold + /// The thresholds are defined in `PRIORITY_ALLOCATION_THRESHOLDS`. + fn has_reached_threshold(&self, priority: &PvfExecKind) -> bool { + let Some(threshold) = Self::priority_allocation_threshold(priority) else { return false }; + let Some(count) = self.counter.get(&priority) else { return false }; + // Every time we iterate by lower level priorities + let total_scheduled_at_priority_or_lower: usize = self + .counter + .iter() + .filter_map(|(p, c)| if *p >= *priority { Some(c) } else { None }) + .sum(); + if total_scheduled_at_priority_or_lower == 0 { + return false + } + + let has_reached_threshold = count * 100 / total_scheduled_at_priority_or_lower >= threshold; + + gum::debug!( + target: LOG_TARGET, + ?priority, + ?count, + ?total_scheduled_at_priority_or_lower, + "Execution priority has {}reached threshold: {}/{}%", + if has_reached_threshold {""} else {"not "}, + count * 100 / total_scheduled_at_priority_or_lower, + threshold + ); + + has_reached_threshold + } + + fn mark_scheduled(&mut self, priority: PvfExecKind) { + *self.counter.entry(priority).or_default() += 1; + + if self.counter.values().sum::() >= Self::SCHEDULING_WINDOW_SIZE { + self.reset_counter(); + } + } + + fn reset_counter(&mut self) { + self.counter = PvfExecKind::iter().map(|kind| (kind, 0)).collect(); + } +} + +#[cfg(test)] +mod tests { + use polkadot_node_primitives::BlockData; + use sp_core::H256; + + use super::*; + use crate::testing::artifact_id; + use std::time::Duration; + + fn create_execution_job() -> ExecuteJob { + let (result_tx, _result_rx) = oneshot::channel(); + 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()) }); + ExecuteJob { + artifact: ArtifactPathId { id: artifact_id(0), path: PathBuf::new() }, + exec_timeout: Duration::from_secs(10), + pvd, + pov, + executor_params: ExecutorParams::default(), + result_tx, + waiting_since: Instant::now(), + } + } + + #[test] + fn test_unscheduled_add() { + let mut unscheduled = Unscheduled::new(); + + PvfExecKind::iter().for_each(|priority| { + unscheduled.add(create_execution_job(), priority); + }); + + PvfExecKind::iter().for_each(|priority| { + let queue = unscheduled.unscheduled.get(&priority).unwrap(); + assert_eq!(queue.len(), 1); + }); + } + + #[test] + fn test_unscheduled_priority_distribution() { + use PvfExecKind::*; + + let mut priorities = vec![]; + + let mut unscheduled = Unscheduled::new(); + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + unscheduled.add(create_execution_job(), Dispute); + unscheduled.add(create_execution_job(), Approval); + unscheduled.add(create_execution_job(), BackingSystemParas); + unscheduled.add(create_execution_job(), Backing); + } + + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + let priority = unscheduled.select_next_priority(); + priorities.push(priority); + unscheduled.mark_scheduled(priority); + } + + assert_eq!(priorities.iter().filter(|v| **v == Dispute).count(), 8); + assert_eq!(priorities.iter().filter(|v| **v == Approval).count(), 3); + assert_eq!(priorities.iter().filter(|v| **v == BackingSystemParas).count(), 1); + } + + #[test] + fn test_unscheduled_priority_distribution_without_backing_system_paras() { + use PvfExecKind::*; + + let mut priorities = vec![]; + + let mut unscheduled = Unscheduled::new(); + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + unscheduled.add(create_execution_job(), Dispute); + unscheduled.add(create_execution_job(), Approval); + unscheduled.add(create_execution_job(), Backing); + } + + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + let priority = unscheduled.select_next_priority(); + priorities.push(priority); + unscheduled.mark_scheduled(priority); + } + + assert_eq!(priorities.iter().filter(|v| **v == Dispute).count(), 8); + assert_eq!(priorities.iter().filter(|v| **v == Approval).count(), 3); + assert_eq!(priorities.iter().filter(|v| **v == Backing).count(), 1); + } + + #[test] + fn test_unscheduled_priority_distribution_without_disputes() { + use PvfExecKind::*; + + let mut priorities = vec![]; + + let mut unscheduled = Unscheduled::new(); + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + unscheduled.add(create_execution_job(), Approval); + unscheduled.add(create_execution_job(), BackingSystemParas); + unscheduled.add(create_execution_job(), Backing); + } + + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + let priority = unscheduled.select_next_priority(); + priorities.push(priority); + unscheduled.mark_scheduled(priority); + } + + assert_eq!(priorities.iter().filter(|v| **v == Approval).count(), 9); + assert_eq!(priorities.iter().filter(|v| **v == BackingSystemParas).count(), 2); + assert_eq!(priorities.iter().filter(|v| **v == Backing).count(), 1); + } + + #[test] + fn test_unscheduled_priority_distribution_without_disputes_and_only_one_backing() { + use PvfExecKind::*; + + let mut priorities = vec![]; + + let mut unscheduled = Unscheduled::new(); + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + unscheduled.add(create_execution_job(), Approval); + } + unscheduled.add(create_execution_job(), Backing); + + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + let priority = unscheduled.select_next_priority(); + priorities.push(priority); + unscheduled.mark_scheduled(priority); + } + + assert_eq!(priorities.iter().filter(|v| **v == Approval).count(), 11); + assert_eq!(priorities.iter().filter(|v| **v == Backing).count(), 1); + } + + #[test] + fn test_unscheduled_does_not_postpone_backing() { + use PvfExecKind::*; + + let mut priorities = vec![]; + + let mut unscheduled = Unscheduled::new(); + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + unscheduled.add(create_execution_job(), Approval); + } + unscheduled.add(create_execution_job(), Backing); + + for _ in 0..Unscheduled::SCHEDULING_WINDOW_SIZE { + let priority = unscheduled.select_next_priority(); + priorities.push(priority); + unscheduled.mark_scheduled(priority); + } + + assert_eq!(&priorities[..4], &[Approval, Backing, Approval, Approval]); + } +} diff --git a/polkadot/node/core/pvf/src/execute/worker_interface.rs b/polkadot/node/core/pvf/src/execute/worker_interface.rs index d15d7c15426e..77bd6bedd75c 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 462631d33b52..37cd6fcbf74a 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_subsystem::{SubsystemError, SubsystemResult}; +use polkadot_node_primitives::PoV; +use polkadot_node_subsystem::{messages::PvfExecKind, SubsystemError, SubsystemResult}; use polkadot_parachain_primitives::primitives::ValidationResult; +use polkadot_primitives::PersistedValidationData; use std::{ collections::HashMap, path::PathBuf, + sync::Arc, time::{Duration, SystemTime}, }; @@ -108,16 +111,20 @@ impl ValidationHost { &mut self, pvf: PvfPrepData, exec_timeout: Duration, - params: Vec, + pvd: Arc, + pov: Arc, priority: Priority, + exec_kind: PvfExecKind, result_tx: ResultSender, ) -> Result<(), String> { self.to_host_tx .send(ToHost::ExecutePvf(ExecutePvfInputs { pvf, exec_timeout, - params, + pvd, + pov, priority, + exec_kind, result_tx, })) .await @@ -147,8 +154,10 @@ enum ToHost { struct ExecutePvfInputs { pvf: PvfPrepData, exec_timeout: Duration, - params: Vec, + pvd: Arc, + pov: Arc, priority: Priority, + exec_kind: PvfExecKind, result_tx: ResultSender, } @@ -539,7 +548,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, exec_kind, result_tx } = inputs; let artifact_id = ArtifactId::from_pvf_prep_data(&pvf); let executor_params = (*pvf.executor_params()).clone(); @@ -558,8 +567,10 @@ async fn handle_execute_pvf( artifact: ArtifactPathId::new(artifact_id, path), pending_execution_request: PendingExecutionRequest { exec_timeout, - params, + pvd, + pov, executor_params, + exec_kind, result_tx, }, }, @@ -587,8 +598,10 @@ async fn handle_execute_pvf( artifact_id, PendingExecutionRequest { exec_timeout, - params, + pvd, + pov, executor_params, + exec_kind, result_tx, }, ) @@ -598,7 +611,14 @@ 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, + exec_kind, + }, ); }, ArtifactState::FailedToProcess { last_time_failed, num_failures, error } => { @@ -627,8 +647,10 @@ async fn handle_execute_pvf( artifact_id, PendingExecutionRequest { exec_timeout, - params, + pvd, + pov, executor_params, + exec_kind, result_tx, }, ) @@ -648,7 +670,14 @@ 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, + exec_kind, + }, ) .await?; } @@ -770,7 +799,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, exec_kind } in pending_requests { if result_tx.is_canceled() { @@ -793,8 +822,10 @@ async fn handle_prepare_done( artifact: ArtifactPathId::new(artifact_id.clone(), &path), pending_execution_request: PendingExecutionRequest { exec_timeout, - params, + pvd, + pov, executor_params, + exec_kind, result_tx, }, }, @@ -803,12 +834,8 @@ async fn handle_prepare_done( } *state = match result { - Ok(PrepareSuccess { path, stats: prepare_stats, size }) => ArtifactState::Prepared { - path, - last_time_needed: SystemTime::now(), - size, - prepare_stats, - }, + Ok(PrepareSuccess { path, size, .. }) => + ArtifactState::Prepared { path, last_time_needed: SystemTime::now(), size }, Err(error) => { let last_time_failed = SystemTime::now(); let num_failures = *num_failures + 1; @@ -966,7 +993,8 @@ pub(crate) mod tests { use crate::{artifacts::generate_artifact_path, testing::artifact_id, PossiblyInvalidError}; 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); @@ -1184,20 +1212,8 @@ pub(crate) mod tests { builder.cleanup_config = ArtifactsCleanupConfig::new(1024, Duration::from_secs(0)); let path1 = generate_artifact_path(cache_path); let path2 = generate_artifact_path(cache_path); - builder.artifacts.insert_prepared( - artifact_id(1), - path1.clone(), - mock_now, - 1024, - PrepareStats::default(), - ); - builder.artifacts.insert_prepared( - artifact_id(2), - path2.clone(), - mock_now, - 1024, - PrepareStats::default(), - ); + builder.artifacts.insert_prepared(artifact_id(1), path1.clone(), mock_now, 1024); + builder.artifacts.insert_prepared(artifact_id(2), path2.clone(), mock_now, 1024); let mut test = builder.build(); let mut host = test.host_handle(); @@ -1223,13 +1239,23 @@ 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, + PvfExecKind::Backing, result_tx, ) .await @@ -1239,8 +1265,10 @@ pub(crate) mod tests { host.execute_pvf( PvfPrepData::from_discriminator(1), TEST_EXECUTION_TIMEOUT, - b"pvf1".to_vec(), + pvd.clone(), + pov1, Priority::Critical, + PvfExecKind::Backing, result_tx, ) .await @@ -1250,8 +1278,10 @@ pub(crate) mod tests { host.execute_pvf( PvfPrepData::from_discriminator(2), TEST_EXECUTION_TIMEOUT, - b"pvf2".to_vec(), + pvd, + pov2, Priority::Normal, + PvfExecKind::Backing, result_tx, ) .await @@ -1382,6 +1412,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,8 +1428,10 @@ pub(crate) mod tests { host.execute_pvf( PvfPrepData::from_discriminator(1), TEST_EXECUTION_TIMEOUT, - b"pvf2".to_vec(), + pvd.clone(), + pov.clone(), Priority::Critical, + PvfExecKind::Backing, result_tx, ) .await @@ -1438,8 +1477,10 @@ pub(crate) mod tests { host.execute_pvf( PvfPrepData::from_discriminator(2), TEST_EXECUTION_TIMEOUT, - b"pvf2".to_vec(), + pvd, + pov, Priority::Critical, + PvfExecKind::Backing, result_tx, ) .await @@ -1534,14 +1575,23 @@ 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, + PvfExecKind::Backing, result_tx, ) .await @@ -1570,8 +1620,10 @@ pub(crate) mod tests { host.execute_pvf( PvfPrepData::from_discriminator(1), TEST_EXECUTION_TIMEOUT, - b"pvf".to_vec(), + pvd.clone(), + pov.clone(), Priority::Critical, + PvfExecKind::Backing, result_tx_2, ) .await @@ -1592,8 +1644,10 @@ pub(crate) mod tests { host.execute_pvf( PvfPrepData::from_discriminator(1), TEST_EXECUTION_TIMEOUT, - b"pvf".to_vec(), + pvd.clone(), + pov.clone(), Priority::Critical, + PvfExecKind::Backing, result_tx_3, ) .await @@ -1636,14 +1690,23 @@ 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, + PvfExecKind::Backing, result_tx, ) .await @@ -1672,8 +1735,10 @@ pub(crate) mod tests { host.execute_pvf( PvfPrepData::from_discriminator(1), TEST_EXECUTION_TIMEOUT, - b"pvf".to_vec(), + pvd.clone(), + pov.clone(), Priority::Critical, + PvfExecKind::Backing, result_tx_2, ) .await @@ -1694,8 +1759,10 @@ pub(crate) mod tests { host.execute_pvf( PvfPrepData::from_discriminator(1), TEST_EXECUTION_TIMEOUT, - b"pvf".to_vec(), + pvd.clone(), + pov.clone(), Priority::Critical, + PvfExecKind::Backing, result_tx_3, ) .await @@ -1755,13 +1822,22 @@ 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, + PvfExecKind::Backing, result_tx, ) .await diff --git a/polkadot/node/core/pvf/src/metrics.rs b/polkadot/node/core/pvf/src/metrics.rs index bc8d300037fe..745f2de99e58 100644 --- a/polkadot/node/core/pvf/src/metrics.rs +++ b/polkadot/node/core/pvf/src/metrics.rs @@ -18,6 +18,7 @@ use polkadot_node_core_pvf_common::prepare::MemoryStats; use polkadot_node_metrics::metrics::{self, prometheus}; +use polkadot_node_subsystem::messages::PvfExecKind; /// Validation host metrics. #[derive(Default, Clone)] @@ -105,6 +106,28 @@ 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); + } + } + + /// When preparation pipeline concluded working on an item. + pub(crate) fn on_execute_kind(&self, kind: PvfExecKind) { + if let Some(metrics) = &self.0 { + metrics.exec_kind_selected.with_label_values(&[kind.as_str()]).inc(); + } + } } #[derive(Clone)] @@ -129,6 +152,9 @@ 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, + exec_kind_selected: prometheus::CounterVec, } impl metrics::Metrics for Metrics { @@ -323,6 +349,45 @@ 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, + )?, + exec_kind_selected: prometheus::register( + prometheus::CounterVec::new( + prometheus::Opts::new( + "polkadot_pvf_exec_kind_selected", + "The total number of selected execute kinds", + ), + &["priority"], + )?, + registry, + )?, }; Ok(Metrics(Some(inner))) } diff --git a/polkadot/node/core/pvf/src/prepare/pool.rs b/polkadot/node/core/pvf/src/prepare/pool.rs index 4e11f977c9e7..67cd71812e52 100644 --- a/polkadot/node/core/pvf/src/prepare/pool.rs +++ b/polkadot/node/core/pvf/src/prepare/pool.rs @@ -343,14 +343,13 @@ fn handle_mux( ), // Return `Concluded`, but do not kill the worker since the error was on the host // side. - Outcome::RenameTmpFile { worker: idle, result: _, err, src, dest } => - handle_concluded_no_rip( - from_pool, - spawned, - worker, - idle, - Err(PrepareError::RenameTmpFile { err, src, dest }), - ), + Outcome::RenameTmpFile { worker: idle, err, src, dest } => handle_concluded_no_rip( + from_pool, + spawned, + worker, + idle, + Err(PrepareError::RenameTmpFile { err, src, dest }), + ), // Could not clear worker cache. Kill the worker so other jobs can't see the data. Outcome::ClearWorkerDir { err } => { if attempt_retire(metrics, spawned, worker) { diff --git a/polkadot/node/core/pvf/src/prepare/worker_interface.rs b/polkadot/node/core/pvf/src/prepare/worker_interface.rs index 22ee93319d84..718416e8be76 100644 --- a/polkadot/node/core/pvf/src/prepare/worker_interface.rs +++ b/polkadot/node/core/pvf/src/prepare/worker_interface.rs @@ -81,7 +81,6 @@ pub enum Outcome { /// final destination location. RenameTmpFile { worker: IdleWorker, - result: PrepareWorkerResult, err: String, // Unfortunately `PathBuf` doesn't implement `Encode`/`Decode`, so we do a fallible // conversion to `Option`. @@ -211,7 +210,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 +220,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 +268,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) => { @@ -281,7 +286,6 @@ async fn handle_response( ); Outcome::RenameTmpFile { worker, - result, err: format!("{:?}", err), src: tmp_file.to_str().map(String::from), dest: artifact_path.to_str().map(String::from), diff --git a/polkadot/node/core/pvf/src/priority.rs b/polkadot/node/core/pvf/src/priority.rs index 0d18d4b484ca..7aaeacf36220 100644 --- a/polkadot/node/core/pvf/src/priority.rs +++ b/polkadot/node/core/pvf/src/priority.rs @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . +use polkadot_node_subsystem::messages::PvfExecKind; + /// A priority assigned to preparation of a PVF. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum Priority { @@ -35,3 +37,14 @@ impl Priority { self == Priority::Critical } } + +impl From for Priority { + fn from(priority: PvfExecKind) -> Self { + match priority { + PvfExecKind::Dispute => Priority::Critical, + PvfExecKind::Approval => Priority::Critical, + PvfExecKind::BackingSystemParas => Priority::Normal, + PvfExecKind::Backing => Priority::Normal, + } + } +} diff --git a/polkadot/node/core/pvf/src/testing.rs b/polkadot/node/core/pvf/src/testing.rs index 8c75dafa69c2..9a4004f39037 100644 --- a/polkadot/node/core/pvf/src/testing.rs +++ b/polkadot/node/core/pvf/src/testing.rs @@ -72,7 +72,7 @@ pub fn build_workers_and_get_paths() -> (PathBuf, PathBuf) { "--bin=polkadot-execute-worker", ]; - if cfg!(build_type = "release") { + if cfg!(build_profile = "release") { build_args.push("--release"); } diff --git a/polkadot/node/core/pvf/tests/it/adder.rs b/polkadot/node/core/pvf/tests/it/adder.rs index 455e8c36c88d..1a95a28fe077 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 9ad486657512..4cbc6fb04a8e 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,16 @@ 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_node_subsystem::messages::PvfExecKind; +use polkadot_parachain_primitives::primitives::{BlockData, ValidationResult}; +use polkadot_primitives::{ + ExecutorParam, ExecutorParams, PersistedValidationData, PvfExecKind as RuntimePvfExecKind, + 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 +85,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 +105,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,8 +122,10 @@ impl TestHost { PrepareJobKind::Compilation, ), TEST_EXECUTION_TIMEOUT, - params.encode(), + Arc::new(pvd), + Arc::new(pov), polkadot_node_core_pvf::Priority::Normal, + PvfExecKind::Backing, result_tx, ) .await @@ -159,19 +161,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 +189,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 +236,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 +251,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 +277,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 +297,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 +329,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 +359,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 +370,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 +410,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!( @@ -582,8 +583,9 @@ async fn artifact_does_not_reprepare_on_non_meaningful_exec_parameter_change() { let cache_dir = host.cache_dir.path(); let set1 = ExecutorParams::default(); - let set2 = - ExecutorParams::from(&[ExecutorParam::PvfExecTimeout(PvfExecKind::Backing, 2500)][..]); + let set2 = ExecutorParams::from( + &[ExecutorParam::PvfExecTimeout(RuntimePvfExecKind::Backing, 2500)][..], + ); let _stats = host .precheck_pvf(test_parachain_halt::wasm_binary_unwrap(), set1) @@ -652,3 +654,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 b8fd2cdce0ce..b3023c8a45c3 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/jaeger/Cargo.toml b/polkadot/node/jaeger/Cargo.toml deleted file mode 100644 index 90a6c80e3d0b..000000000000 --- a/polkadot/node/jaeger/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "polkadot-node-jaeger" -version = "7.0.0" -authors.workspace = true -edition.workspace = true -license.workspace = true -description = "Polkadot Jaeger primitives, but equally useful for Grafana/Tempo" - -[lints] -workspace = true - -[dependencies] -mick-jaeger = { workspace = true } -lazy_static = { workspace = true } -parking_lot = { workspace = true, default-features = true } -polkadot-primitives = { workspace = true, default-features = true } -polkadot-node-primitives = { workspace = true, default-features = true } -sc-network = { workspace = true, default-features = true } -sc-network-types = { workspace = true, default-features = true } -sp-core = { workspace = true, default-features = true } -thiserror = { workspace = true } -tokio = { workspace = true, default-features = true } -log = { workspace = true, default-features = true } -codec = { workspace = true } diff --git a/polkadot/node/jaeger/src/config.rs b/polkadot/node/jaeger/src/config.rs deleted file mode 100644 index 702a22e1245c..000000000000 --- a/polkadot/node/jaeger/src/config.rs +++ /dev/null @@ -1,73 +0,0 @@ -// 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 . - -//! Polkadot Jaeger configuration. - -/// Configuration for the jaeger tracing. -#[derive(Clone)] -pub struct JaegerConfig { - pub(crate) node_name: String, - pub(crate) agent_addr: std::net::SocketAddr, -} - -impl std::default::Default for JaegerConfig { - fn default() -> Self { - Self { - node_name: "unknown_".to_owned(), - agent_addr: "127.0.0.1:6831" - .parse() - .expect(r#"Static "127.0.0.1:6831" is a valid socket address string. qed"#), - } - } -} - -impl JaegerConfig { - /// Use the builder pattern to construct a configuration. - pub fn builder() -> JaegerConfigBuilder { - JaegerConfigBuilder::default() - } -} - -/// Jaeger configuration builder. -#[derive(Default)] -pub struct JaegerConfigBuilder { - inner: JaegerConfig, -} - -impl JaegerConfigBuilder { - /// Set the name for this node. - pub fn named(mut self, name: S) -> Self - where - S: AsRef, - { - self.inner.node_name = name.as_ref().to_owned(); - self - } - - /// Set the agent address to send the collected spans to. - pub fn agent(mut self, addr: U) -> Self - where - U: Into, - { - self.inner.agent_addr = addr.into(); - self - } - - /// Construct the configuration. - pub fn build(self) -> JaegerConfig { - self.inner - } -} diff --git a/polkadot/node/jaeger/src/lib.rs b/polkadot/node/jaeger/src/lib.rs deleted file mode 100644 index 7de458606816..000000000000 --- a/polkadot/node/jaeger/src/lib.rs +++ /dev/null @@ -1,168 +0,0 @@ -// 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 . - -//! Polkadot Jaeger related primitives -//! -//! Provides primitives used by Polkadot for interfacing with Jaeger. -//! -//! # Integration -//! -//! See for an introduction. -//! -//! The easiest way to try Jaeger is: -//! -//! - Start a docker container with the all-in-one docker image (see below). -//! - Open your browser and navigate to to access the UI. -//! -//! The all-in-one image can be started with: -//! -//! ```not_rust -//! podman login docker.io -//! podman run -d --name jaeger \ -//! -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \ -//! -p 5775:5775/udp \ -//! -p 6831:6831/udp \ -//! -p 6832:6832/udp \ -//! -p 5778:5778 \ -//! -p 16686:16686 \ -//! -p 14268:14268 \ -//! -p 14250:14250 \ -//! -p 9411:9411 \ -//! docker.io/jaegertracing/all-in-one:1.21 -//! ``` - -#![forbid(unused_imports)] - -mod config; -mod errors; -mod spans; - -pub use self::{ - config::{JaegerConfig, JaegerConfigBuilder}, - errors::JaegerError, - spans::{hash_to_trace_identifier, PerLeafSpan, Span, Stage}, -}; - -use self::spans::TraceIdentifier; - -use sp_core::traits::SpawnNamed; - -use parking_lot::RwLock; -use std::{result, sync::Arc}; - -lazy_static::lazy_static! { - static ref INSTANCE: RwLock = RwLock::new(Jaeger::None); -} - -/// Stateful convenience wrapper around [`mick_jaeger`]. -pub enum Jaeger { - /// Launched and operational state. - Launched { - /// [`mick_jaeger`] provided API to record spans to. - traces_in: Arc, - }, - /// Preparation state with the necessary config to launch the collector. - Prep(JaegerConfig), - /// Uninitialized, suggests wrong API usage if encountered. - None, -} - -impl Jaeger { - /// Spawn the jaeger instance. - pub fn new(cfg: JaegerConfig) -> Self { - Jaeger::Prep(cfg) - } - - /// Spawn the background task in order to send the tracing information out via UDP - #[cfg(target_os = "unknown")] - pub fn launch(self, _spawner: S) -> result::Result<(), JaegerError> { - Ok(()) - } - - /// Provide a no-thrills test setup helper. - #[cfg(test)] - pub fn test_setup() { - let mut instance = INSTANCE.write(); - match *instance { - Self::Launched { .. } => {}, - _ => { - let (traces_in, _traces_out) = mick_jaeger::init(mick_jaeger::Config { - service_name: "polkadot-jaeger-test".to_owned(), - }); - *instance = Self::Launched { traces_in }; - }, - } - } - - /// Spawn the background task in order to send the tracing information out via UDP - #[cfg(not(target_os = "unknown"))] - pub fn launch(self, spawner: S) -> result::Result<(), JaegerError> { - let cfg = match self { - Self::Prep(cfg) => Ok(cfg), - Self::Launched { .. } => return Err(JaegerError::AlreadyLaunched), - Self::None => Err(JaegerError::MissingConfiguration), - }?; - - let jaeger_agent = cfg.agent_addr; - - log::info!("🐹 Collecting jaeger spans for {:?}", &jaeger_agent); - - let (traces_in, mut traces_out) = mick_jaeger::init(mick_jaeger::Config { - service_name: format!("polkadot-{}", cfg.node_name), - }); - - // Spawn a background task that pulls span information and sends them on the network. - spawner.spawn( - "jaeger-collector", - Some("jaeger"), - Box::pin(async move { - match tokio::net::UdpSocket::bind("0.0.0.0:0").await { - Ok(udp_socket) => loop { - let buf = traces_out.next().await; - // UDP sending errors happen only either if the API is misused or in case of - // missing privilege. - if let Err(e) = udp_socket.send_to(&buf, jaeger_agent).await { - log::debug!(target: "jaeger", "UDP send error: {}", e); - } - }, - Err(e) => { - log::warn!(target: "jaeger", "UDP socket open error: {}", e); - }, - } - }), - ); - - *INSTANCE.write() = Self::Launched { traces_in }; - Ok(()) - } - - /// Create a span, but defer the evaluation/transformation into a `TraceIdentifier`. - /// - /// The deferral allows to avoid the additional CPU runtime cost in case of - /// items that are not a pre-computed hash by themselves. - pub(crate) fn span(&self, lazy_hash: F, span_name: &'static str) -> Option - where - F: Fn() -> TraceIdentifier, - { - if let Self::Launched { traces_in, .. } = self { - let ident = lazy_hash(); - let trace_id = std::num::NonZeroU128::new(ident)?; - Some(traces_in.span(trace_id, span_name)) - } else { - None - } - } -} diff --git a/polkadot/node/jaeger/src/spans.rs b/polkadot/node/jaeger/src/spans.rs deleted file mode 100644 index efc1a9f91d19..000000000000 --- a/polkadot/node/jaeger/src/spans.rs +++ /dev/null @@ -1,520 +0,0 @@ -// 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 . - -//! Polkadot Jaeger span definitions. -//! -//! ```rust -//! # use polkadot_primitives::{CandidateHash, Hash}; -//! # fn main() { -//! use polkadot_node_jaeger as jaeger; -//! -//! let relay_parent = Hash::default(); -//! let candidate = CandidateHash::default(); -//! -//! #[derive(Debug, Default)] -//! struct Foo { -//! a: u8, -//! b: u16, -//! c: u32, -//! }; -//! -//! let foo = Foo::default(); -//! -//! let span = -//! jaeger::Span::new(relay_parent, "root_of_aaall_spans") -//! // explicit well defined items -//! .with_candidate(candidate) -//! // anything that implements `trait std::fmt::Debug` -//! .with_string_fmt_debug_tag("foo", foo) -//! // anything that implements `trait std::str::ToString` -//! .with_string_tag("again", 1337_u32) -//! // add a `Stage` for [`dot-jaeger`](https://github.com/paritytech/dot-jaeger) -//! .with_stage(jaeger::Stage::CandidateBacking); -//! // complete by design, no completion required -//! # } -//! ``` -//! -//! In a few cases additional annotations might want to be added -//! over the course of a function, for this purpose use the non-consuming -//! `fn` variants, i.e. -//! ```rust -//! # use polkadot_primitives::{CandidateHash, Hash}; -//! # fn main() { -//! # use polkadot_node_jaeger as jaeger; -//! -//! # let relay_parent = Hash::default(); -//! # let candidate = CandidateHash::default(); -//! -//! # #[derive(Debug, Default)] -//! # struct Foo { -//! # a: u8, -//! # b: u16, -//! # c: u32, -//! # }; -//! # -//! # let foo = Foo::default(); -//! -//! let root_span = -//! jaeger::Span::new(relay_parent, "root_of_aaall_spans"); -//! -//! // the preferred way of adding additional delayed information: -//! let span = root_span.child("inner"); -//! -//! // ... more operations ... -//! -//! // but this is also possible: -//! -//! let mut root_span = root_span; -//! root_span.add_string_fmt_debug_tag("foo_constructed", &foo); -//! root_span.add_string_tag("bar", true); -//! # } -//! ``` - -use codec::Encode; -use polkadot_node_primitives::PoV; -use polkadot_primitives::{ - BlakeTwo256, CandidateHash, ChunkIndex, Hash, HashT, Id as ParaId, ValidatorIndex, -}; -use sc_network_types::PeerId; - -use std::{fmt, sync::Arc}; - -use super::INSTANCE; - -/// A special "per leaf span". -/// -/// Essentially this span wraps two spans: -/// -/// 1. The span that is created per leaf in the overseer. -/// 2. Some child span of the per-leaf span. -/// -/// This just works as auxiliary structure to easily store both. -#[derive(Debug)] -pub struct PerLeafSpan { - leaf_span: Arc, - span: Span, -} - -impl PerLeafSpan { - /// Creates a new instance. - /// - /// Takes the `leaf_span` that is created by the overseer per leaf and a name for a child span. - /// Both will be stored in this object, while the child span is implicitly accessible by using - /// the [`Deref`](std::ops::Deref) implementation. - pub fn new(leaf_span: Arc, name: &'static str) -> Self { - let span = leaf_span.child(name); - - Self { span, leaf_span } - } - - /// Returns the leaf span. - pub fn leaf_span(&self) -> &Arc { - &self.leaf_span - } -} - -/// Returns a reference to the child span. -impl std::ops::Deref for PerLeafSpan { - type Target = Span; - - fn deref(&self) -> &Span { - &self.span - } -} - -/// A helper to annotate the stage with a numerical value -/// to ease the life of the tooling team creating viable -/// statistical metrics for which stage of the inclusion -/// pipeline drops a significant amount of candidates, -/// statistically speaking. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(u8)] -#[non_exhaustive] -pub enum Stage { - CandidateBacking = 2, - StatementDistribution = 3, - PoVDistribution = 4, - AvailabilityDistribution = 5, - AvailabilityRecovery = 6, - BitfieldDistribution = 7, - ApprovalChecking = 8, - ApprovalDistribution = 9, - // Expand as needed, numbers should be ascending according to the stage - // through the inclusion pipeline, or according to the descriptions - // in [the path of a para chain block] - // (https://polkadot.network/the-path-of-a-parachain-block/) - // see [issue](https://github.com/paritytech/polkadot/issues/2389) -} - -/// A wrapper type for a span. -/// -/// Handles running with and without jaeger. -pub enum Span { - /// Running with jaeger being enabled. - Enabled(mick_jaeger::Span), - /// Running with jaeger disabled. - Disabled, -} - -/// Alias for the 16 byte unique identifier used with jaeger. -pub(crate) type TraceIdentifier = u128; - -/// A helper to convert the hash to the fixed size representation -/// needed for jaeger. -#[inline] -pub fn hash_to_trace_identifier(hash: Hash) -> TraceIdentifier { - let mut buf = [0u8; 16]; - buf.copy_from_slice(&hash.as_ref()[0..16]); - // The slice bytes are copied in reading order, so if interpreted - // in string form by a human, that means lower indices have higher - // values and hence corresponds to BIG endian ordering of the individual - // bytes. - u128::from_be_bytes(buf) as TraceIdentifier -} - -/// Helper to unify lazy proxy evaluation. -pub trait LazyIdent { - /// Evaluate the type to a unique trace identifier. - /// Called lazily on demand. - fn eval(&self) -> TraceIdentifier; - - /// Annotate a new root item with these additional spans - /// at construction. - fn extra_tags(&self, _span: &mut Span) {} -} - -impl<'a> LazyIdent for &'a [u8] { - fn eval(&self) -> TraceIdentifier { - hash_to_trace_identifier(BlakeTwo256::hash_of(self)) - } -} - -impl LazyIdent for &PoV { - fn eval(&self) -> TraceIdentifier { - hash_to_trace_identifier(self.hash()) - } - - fn extra_tags(&self, span: &mut Span) { - span.add_pov(self) - } -} - -impl LazyIdent for Hash { - fn eval(&self) -> TraceIdentifier { - hash_to_trace_identifier(*self) - } - - fn extra_tags(&self, span: &mut Span) { - span.add_string_fmt_debug_tag("relay-parent", self); - } -} - -impl LazyIdent for &Hash { - fn eval(&self) -> TraceIdentifier { - hash_to_trace_identifier(**self) - } - - fn extra_tags(&self, span: &mut Span) { - span.add_string_fmt_debug_tag("relay-parent", self); - } -} - -impl LazyIdent for CandidateHash { - fn eval(&self) -> TraceIdentifier { - hash_to_trace_identifier(self.0) - } - - fn extra_tags(&self, span: &mut Span) { - span.add_string_fmt_debug_tag("candidate-hash", &self.0); - // A convenience for usage with the grafana tempo UI, - // not a technical requirement. It merely provides an easy anchor - // where the true trace identifier of the span is not based on - // a candidate hash (which it should be!), but is required to - // continue investigating. - span.add_string_tag("traceID", self.eval().to_string()); - } -} - -impl Span { - /// Creates a new span builder based on anything that can be lazily evaluated - /// to and identifier. - /// - /// Attention: The primary identifier will be used for identification - /// and as such should be - pub fn new(identifier: I, span_name: &'static str) -> Span { - let mut span = INSTANCE - .read_recursive() - .span(|| ::eval(&identifier), span_name) - .into(); - ::extra_tags(&identifier, &mut span); - span - } - - /// Creates a new span builder based on an encodable type. - /// The encoded bytes are then used to derive the true trace identifier. - pub fn from_encodable(identifier: I, span_name: &'static str) -> Span { - INSTANCE - .read_recursive() - .span( - move || { - let bytes = identifier.encode(); - LazyIdent::eval(&bytes.as_slice()) - }, - span_name, - ) - .into() - } - - /// Derive a child span from `self`. - pub fn child(&self, name: &str) -> Self { - match self { - Self::Enabled(inner) => Self::Enabled(inner.child(name)), - Self::Disabled => Self::Disabled, - } - } - - /// Attach a 'traceID' tag set to the decimal representation of the candidate hash. - #[inline(always)] - pub fn with_trace_id(mut self, candidate_hash: CandidateHash) -> Self { - self.add_string_tag("traceID", hash_to_trace_identifier(candidate_hash.0)); - self - } - - #[inline(always)] - pub fn with_string_tag(mut self, tag: &'static str, val: V) -> Self { - self.add_string_tag::(tag, val); - self - } - - /// Attach a peer-id tag to the span. - #[inline(always)] - pub fn with_peer_id(self, peer: &PeerId) -> Self { - self.with_string_tag("peer-id", &peer.to_base58()) - } - - /// Attach a `peer-id` tag to the span when peer is present. - #[inline(always)] - pub fn with_optional_peer_id(self, peer: Option<&PeerId>) -> Self { - if let Some(peer) = peer { - self.with_peer_id(peer) - } else { - self - } - } - - /// Attach a candidate hash to the span. - #[inline(always)] - pub fn with_candidate(self, candidate_hash: CandidateHash) -> Self { - self.with_string_fmt_debug_tag("candidate-hash", &candidate_hash.0) - } - - /// Attach a para-id to the span. - #[inline(always)] - pub fn with_para_id(self, para_id: ParaId) -> Self { - self.with_int_tag("para-id", u32::from(para_id) as i64) - } - - /// Attach a candidate stage. - /// Should always come with a `CandidateHash`. - #[inline(always)] - pub fn with_stage(self, stage: Stage) -> Self { - self.with_string_tag("candidate-stage", stage as u8) - } - - #[inline(always)] - pub fn with_validator_index(self, validator: ValidatorIndex) -> Self { - self.with_string_tag("validator-index", &validator.0) - } - - #[inline(always)] - pub fn with_chunk_index(self, chunk_index: ChunkIndex) -> Self { - self.with_string_tag("chunk-index", &chunk_index.0) - } - - #[inline(always)] - pub fn with_relay_parent(self, relay_parent: Hash) -> Self { - self.with_string_fmt_debug_tag("relay-parent", relay_parent) - } - - #[inline(always)] - pub fn with_claimed_validator_index(self, claimed_validator_index: ValidatorIndex) -> Self { - self.with_string_tag("claimed-validator", &claimed_validator_index.0) - } - - #[inline(always)] - pub fn with_pov(mut self, pov: &PoV) -> Self { - self.add_pov(pov); - self - } - - /// Add an additional int tag to the span without consuming. - /// - /// Should be used sparingly, introduction of new types is preferred. - #[inline(always)] - pub fn with_int_tag(mut self, tag: &'static str, i: i64) -> Self { - self.add_int_tag(tag, i); - self - } - - #[inline(always)] - pub fn with_uint_tag(mut self, tag: &'static str, u: u64) -> Self { - self.add_uint_tag(tag, u); - self - } - - #[inline(always)] - pub fn with_string_fmt_debug_tag(mut self, tag: &'static str, val: V) -> Self { - self.add_string_tag(tag, format!("{:?}", val)); - self - } - - /// Adds the `FollowsFrom` relationship to this span with respect to the given one. - #[inline(always)] - pub fn add_follows_from(&mut self, other: &Self) { - match (self, other) { - (Self::Enabled(ref mut inner), Self::Enabled(ref other_inner)) => - inner.add_follows_from(&other_inner), - _ => {}, - } - } - - /// Add a PoV hash meta tag with lazy hash evaluation, without consuming the span. - #[inline(always)] - pub fn add_pov(&mut self, pov: &PoV) { - if self.is_enabled() { - // avoid computing the PoV hash if jaeger is not enabled - self.add_string_fmt_debug_tag("pov", pov.hash()); - } - } - - #[inline(always)] - pub fn add_para_id(&mut self, para_id: ParaId) { - self.add_int_tag("para-id", u32::from(para_id) as i64); - } - - /// Add a string tag, without consuming the span. - pub fn add_string_tag(&mut self, tag: &'static str, val: V) { - match self { - Self::Enabled(ref mut inner) => inner.add_string_tag(tag, val.to_string().as_str()), - Self::Disabled => {}, - } - } - - /// Add a string tag, without consuming the span. - pub fn add_string_fmt_debug_tag(&mut self, tag: &'static str, val: V) { - match self { - Self::Enabled(ref mut inner) => - inner.add_string_tag(tag, format!("{:?}", val).as_str()), - Self::Disabled => {}, - } - } - - pub fn add_int_tag(&mut self, tag: &'static str, value: i64) { - match self { - Self::Enabled(ref mut inner) => inner.add_int_tag(tag, value), - Self::Disabled => {}, - } - } - - pub fn add_uint_tag(&mut self, tag: &'static str, value: u64) { - match self { - Self::Enabled(ref mut inner) => inner.add_int_tag(tag, value as i64), - Self::Disabled => {}, - } - } - - /// Check whether jaeger is enabled - /// in order to avoid computational overhead. - pub const fn is_enabled(&self) -> bool { - match self { - Span::Enabled(_) => true, - _ => false, - } - } - - /// Obtain the trace identifier for this set of spans. - pub fn trace_id(&self) -> Option { - match self { - Span::Enabled(inner) => Some(inner.trace_id().get()), - _ => None, - } - } -} - -impl std::fmt::Debug for Span { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "") - } -} - -impl From> for Span { - fn from(src: Option) -> Self { - if let Some(span) = src { - Self::Enabled(span) - } else { - Self::Disabled - } - } -} - -impl From for Span { - fn from(src: mick_jaeger::Span) -> Self { - Self::Enabled(src) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::Jaeger; - - // make sure to not use `::repeat_*()` based samples, since this does not verify endianness - const RAW: [u8; 32] = [ - 0xFF, 0xAA, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x78, 0x89, 0x9A, 0xAB, 0xBC, 0xCD, 0xDE, - 0xEF, 0x00, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, - 0x0E, 0x0F, - ]; - - #[test] - fn hash_derived_identifier_is_leading_16bytes() { - let candidate_hash = dbg!(Hash::from(&RAW)); - let trace_id = dbg!(hash_to_trace_identifier(candidate_hash)); - for (idx, (a, b)) in candidate_hash - .as_bytes() - .iter() - .take(16) - .zip(trace_id.to_be_bytes().iter()) - .enumerate() - { - assert_eq!(*a, *b, "Index [{}] does not match: {} != {}", idx, a, b); - } - } - - #[test] - fn extra_tags_do_not_change_trace_id() { - Jaeger::test_setup(); - let candidate_hash = dbg!(Hash::from(&RAW)); - let trace_id = hash_to_trace_identifier(candidate_hash); - - let span = Span::new(candidate_hash, "foo"); - - assert_eq!(span.trace_id(), Some(trace_id)); - - let span = span.with_int_tag("tag", 7i64); - - assert_eq!(span.trace_id(), Some(trace_id)); - } -} diff --git a/polkadot/node/malus/integrationtests/0001-dispute-valid-block.toml b/polkadot/node/malus/integrationtests/0001-dispute-valid-block.toml index 43e55402e68c..fe1836bd71e5 100644 --- a/polkadot/node/malus/integrationtests/0001-dispute-valid-block.toml +++ b/polkadot/node/malus/integrationtests/0001-dispute-valid-block.toml @@ -1,9 +1,12 @@ [settings] timeout = 1000 +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] + max_validators_per_core = 1 + [relaychain] default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" -chain = "wococo-local" +chain = "westend-local" command = "polkadot" [[relaychain.nodes]] diff --git a/polkadot/node/malus/src/variants/back_garbage_candidate.rs b/polkadot/node/malus/src/variants/back_garbage_candidate.rs index b939a2151e23..d6f1353a46a8 100644 --- a/polkadot/node/malus/src/variants/back_garbage_candidate.rs +++ b/polkadot/node/malus/src/variants/back_garbage_candidate.rs @@ -67,12 +67,10 @@ impl OverseerGen for BackGarbageCandidates { RuntimeClient: RuntimeApiSubsystemClient + ChainApiBackend + AuxStore + 'static, Spawner: 'static + SpawnNamed + Clone + Unpin, { - let spawner = args.spawner.clone(); let validation_filter = ReplaceValidationResult::new( FakeCandidateValidation::BackingAndApprovalValid, FakeCandidateValidationError::InvalidOutputs, f64::from(self.percentage), - SpawnGlue(spawner), ); validator_overseer_builder( diff --git a/polkadot/node/malus/src/variants/common.rs b/polkadot/node/malus/src/variants/common.rs index eb6988f81811..66926f48c5e7 100644 --- a/polkadot/node/malus/src/variants/common.rs +++ b/polkadot/node/malus/src/variants/common.rs @@ -21,7 +21,6 @@ use crate::{ shared::{MALICIOUS_POV, MALUS}, }; -use polkadot_node_core_candidate_validation::find_validation_data; use polkadot_node_primitives::{InvalidCandidate, ValidationResult}; use polkadot_primitives::{ @@ -149,59 +148,21 @@ impl Into for FakeCandidateValidationError { #[derive(Clone, Debug)] /// An interceptor which fakes validation result with a preconfigured result. /// Replaces `CandidateValidationSubsystem`. -pub struct ReplaceValidationResult { +pub struct ReplaceValidationResult { fake_validation: FakeCandidateValidation, fake_validation_error: FakeCandidateValidationError, distribution: Bernoulli, - spawner: Spawner, } -impl ReplaceValidationResult -where - Spawner: overseer::gen::Spawner, -{ +impl ReplaceValidationResult { pub fn new( fake_validation: FakeCandidateValidation, fake_validation_error: FakeCandidateValidationError, percentage: f64, - spawner: Spawner, ) -> Self { let distribution = Bernoulli::new(percentage / 100.0) .expect("Invalid probability! Percentage must be in range [0..=100]."); - Self { fake_validation, fake_validation_error, distribution, spawner } - } - - /// Creates and sends the validation response for a given candidate. Queries the runtime to - /// obtain the validation data for the given candidate. - pub fn send_validation_response( - &self, - candidate_descriptor: CandidateDescriptor, - subsystem_sender: Sender, - response_sender: oneshot::Sender>, - ) where - Sender: overseer::CandidateValidationSenderTrait + Clone + Send + 'static, - { - let _candidate_descriptor = candidate_descriptor.clone(); - let mut subsystem_sender = subsystem_sender.clone(); - let (sender, receiver) = std::sync::mpsc::channel(); - self.spawner.spawn_blocking( - "malus-get-validation-data", - Some("malus"), - Box::pin(async move { - match find_validation_data(&mut subsystem_sender, &_candidate_descriptor).await { - Ok(Some((validation_data, validation_code))) => { - sender - .send((validation_data, validation_code)) - .expect("channel is still open"); - }, - _ => { - panic!("Unable to fetch validation data"); - }, - } - }), - ); - let (validation_data, _) = receiver.recv().unwrap(); - create_validation_response(validation_data, candidate_descriptor, response_sender); + Self { fake_validation, fake_validation_error, distribution } } } @@ -251,10 +212,9 @@ fn create_validation_response( response_sender.send(result).unwrap(); } -impl MessageInterceptor for ReplaceValidationResult +impl MessageInterceptor for ReplaceValidationResult where Sender: overseer::CandidateValidationSenderTrait + Clone + Send + 'static, - Spawner: overseer::gen::Spawner + Clone + 'static, { type Message = CandidateValidationMessage; @@ -262,7 +222,7 @@ where // configuration fail them. fn intercept_incoming( &self, - subsystem_sender: &mut Sender, + _subsystem_sender: &mut Sender, msg: FromOrchestra, ) -> Option> { match msg { @@ -281,7 +241,7 @@ where }, } => { match self.fake_validation { - x if x.misbehaves_valid() && x.should_misbehave(exec_kind) => { + x if x.misbehaves_valid() && x.should_misbehave(exec_kind.into()) => { // Behave normally if the `PoV` is not known to be malicious. if pov.block_data.0.as_slice() != MALICIOUS_POV { return Some(FromOrchestra::Communication { @@ -336,14 +296,14 @@ where }, } }, - x if x.misbehaves_invalid() && x.should_misbehave(exec_kind) => { + x if x.misbehaves_invalid() && x.should_misbehave(exec_kind.into()) => { // Set the validation result to invalid with probability `p` and trigger a // dispute let behave_maliciously = self.distribution.sample(&mut rand::thread_rng()); match behave_maliciously { true => { let validation_result = - ValidationResult::Invalid(InvalidCandidate::InvalidOutputs); + ValidationResult::Invalid(self.fake_validation_error.into()); gum::info!( target: MALUS, @@ -390,109 +350,6 @@ where }), } }, - // Behaviour related to the backing subsystem - FromOrchestra::Communication { - msg: - CandidateValidationMessage::ValidateFromChainState { - candidate_receipt, - pov, - executor_params, - exec_kind, - response_sender, - .. - }, - } => { - match self.fake_validation { - x if x.misbehaves_valid() && x.should_misbehave(exec_kind) => { - // Behave normally if the `PoV` is not known to be malicious. - if pov.block_data.0.as_slice() != MALICIOUS_POV { - return Some(FromOrchestra::Communication { - msg: CandidateValidationMessage::ValidateFromChainState { - candidate_receipt, - pov, - executor_params, - exec_kind, - response_sender, - }, - }) - } - // If the `PoV` is malicious, back the candidate with some probability `p`, - // where 'p' defaults to 100% for suggest-garbage-candidate variant. - let behave_maliciously = self.distribution.sample(&mut rand::thread_rng()); - match behave_maliciously { - true => { - gum::info!( - target: MALUS, - ?behave_maliciously, - "😈 Backing candidate with malicious PoV.", - ); - - self.send_validation_response( - candidate_receipt.descriptor, - subsystem_sender.clone(), - response_sender, - ); - None - }, - // If the `PoV` is malicious, we behave normally with some probability - // `(1-p)` - false => Some(FromOrchestra::Communication { - msg: CandidateValidationMessage::ValidateFromChainState { - candidate_receipt, - pov, - executor_params, - exec_kind, - response_sender, - }, - }), - } - }, - x if x.misbehaves_invalid() && x.should_misbehave(exec_kind) => { - // Maliciously set the validation result to invalid for a valid candidate - // with probability `p` - let behave_maliciously = self.distribution.sample(&mut rand::thread_rng()); - match behave_maliciously { - true => { - let validation_result = - ValidationResult::Invalid(self.fake_validation_error.into()); - gum::info!( - target: MALUS, - para_id = ?candidate_receipt.descriptor.para_id, - "😈 Maliciously sending invalid validation result: {:?}.", - &validation_result, - ); - // We're not even checking the candidate, this makes us appear - // faster than honest validators. - response_sender.send(Ok(validation_result)).unwrap(); - None - }, - // With some probability `(1-p)` we behave normally - false => { - gum::info!(target: MALUS, "😈 'Decided' to not act maliciously.",); - - Some(FromOrchestra::Communication { - msg: CandidateValidationMessage::ValidateFromChainState { - candidate_receipt, - pov, - executor_params, - exec_kind, - response_sender, - }, - }) - }, - } - }, - _ => Some(FromOrchestra::Communication { - msg: CandidateValidationMessage::ValidateFromChainState { - candidate_receipt, - pov, - executor_params, - exec_kind, - response_sender, - }, - }), - } - }, msg => Some(msg), } } diff --git a/polkadot/node/malus/src/variants/dispute_valid_candidates.rs b/polkadot/node/malus/src/variants/dispute_valid_candidates.rs index a50fdce16e4e..5422167545ce 100644 --- a/polkadot/node/malus/src/variants/dispute_valid_candidates.rs +++ b/polkadot/node/malus/src/variants/dispute_valid_candidates.rs @@ -84,12 +84,10 @@ impl OverseerGen for DisputeValidCandidates { RuntimeClient: RuntimeApiSubsystemClient + ChainApiBackend + AuxStore + 'static, Spawner: 'static + SpawnNamed + Clone + Unpin, { - let spawner = args.spawner.clone(); let validation_filter = ReplaceValidationResult::new( self.fake_validation, self.fake_validation_error, f64::from(self.percentage), - SpawnGlue(spawner.clone()), ); validator_overseer_builder( diff --git a/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs b/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs index 6921352cdfc2..ab2d380fbaf4 100644 --- a/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs +++ b/polkadot/node/malus/src/variants/suggest_garbage_candidate.rs @@ -315,7 +315,6 @@ impl OverseerGen for SuggestGarbageCandidates { FakeCandidateValidation::BackingAndApprovalValid, FakeCandidateValidationError::InvalidOutputs, fake_valid_probability, - SpawnGlue(args.spawner.clone()), ); validator_overseer_builder( diff --git a/polkadot/node/metrics/src/tests.rs b/polkadot/node/metrics/src/tests.rs index e720924feb60..4760138058eb 100644 --- a/polkadot/node/metrics/src/tests.rs +++ b/polkadot/node/metrics/src/tests.rs @@ -1,18 +1,18 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Substrate. +// This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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 Substrate. If not, see . +// along with Polkadot. If not, see . //! Polkadot runtime metrics integration test. diff --git a/polkadot/node/network/approval-distribution/Cargo.toml b/polkadot/node/network/approval-distribution/Cargo.toml index a85cde303b61..8d674a733470 100644 --- a/polkadot/node/network/approval-distribution/Cargo.toml +++ b/polkadot/node/network/approval-distribution/Cargo.toml @@ -16,7 +16,6 @@ polkadot-node-primitives = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } polkadot-node-subsystem-util = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } -polkadot-node-jaeger = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } itertools = { workspace = true } @@ -26,6 +25,8 @@ gum = { workspace = true, default-features = true } bitvec = { features = ["alloc"], workspace = true } [dev-dependencies] +sc-keystore = { workspace = true } +sp-application-crypto = { workspace = true, default-features = true } sp-authority-discovery = { workspace = true, default-features = true } sp-core = { features = ["std"], workspace = true, default-features = true } @@ -37,5 +38,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 d48fb08a311c..876cc59b9c28 100644 --- a/polkadot/node/network/approval-distribution/src/lib.rs +++ b/polkadot/node/network/approval-distribution/src/lib.rs @@ -24,10 +24,9 @@ #![warn(missing_docs)] use self::metrics::Metrics; -use futures::{channel::oneshot, select, FutureExt as _}; +use futures::{select, FutureExt as _}; use itertools::Itertools; use net_protocol::peer_set::{ProtocolVersion, ValidationVersion}; -use polkadot_node_jaeger as jaeger; use polkadot_node_network_protocol::{ self as net_protocol, filter_by_peer_version, grid_topology::{RandomRouting, RequiredRouting, SessionGridTopologies, SessionGridTopology}, @@ -35,33 +34,46 @@ use polkadot_node_network_protocol::{ v1 as protocol_v1, v2 as protocol_v2, v3 as protocol_v3, PeerId, UnifiedReputationChange as Rep, Versioned, View, }; -use polkadot_node_primitives::approval::{ - v1::{ - AssignmentCertKind, BlockApprovalMeta, IndirectAssignmentCert, IndirectSignedApprovalVote, - }, - v2::{ - AsBitIndex, AssignmentCertKindV2, CandidateBitfield, IndirectAssignmentCertV2, - IndirectSignedApprovalVoteV2, +use polkadot_node_primitives::{ + approval::{ + criteria::{AssignmentCriteria, InvalidAssignment}, + time::{Clock, ClockExt, SystemClock, TICK_TOO_FAR_IN_FUTURE}, + v1::{ + AssignmentCertKind, BlockApprovalMeta, DelayTranche, IndirectAssignmentCert, + IndirectSignedApprovalVote, RelayVRFStory, + }, + v2::{ + AsBitIndex, AssignmentCertKindV2, CandidateBitfield, IndirectAssignmentCertV2, + IndirectSignedApprovalVoteV2, + }, }, + DISPUTE_WINDOW, }; use polkadot_node_subsystem::{ messages::{ - ApprovalCheckResult, ApprovalDistributionMessage, ApprovalVotingMessage, - AssignmentCheckResult, NetworkBridgeEvent, NetworkBridgeTxMessage, + ApprovalDistributionMessage, ApprovalVotingMessage, CheckedIndirectAssignment, + CheckedIndirectSignedApprovalVote, NetworkBridgeEvent, NetworkBridgeTxMessage, + RuntimeApiMessage, }, overseer, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, }; -use polkadot_node_subsystem_util::reputation::{ReputationAggregator, REPUTATION_CHANGE_INTERVAL}; +use polkadot_node_subsystem_util::{ + reputation::{ReputationAggregator, REPUTATION_CHANGE_INTERVAL}, + runtime::{Config as RuntimeInfoConfig, ExtendedSessionInfo, RuntimeInfo}, +}; use polkadot_primitives::{ - BlockNumber, CandidateIndex, Hash, SessionIndex, ValidatorIndex, ValidatorSignature, + BlockNumber, CandidateHash, CandidateIndex, CoreIndex, DisputeStatement, GroupIndex, Hash, + SessionIndex, Slot, ValidDisputeStatementKind, ValidatorIndex, ValidatorSignature, }; use rand::{CryptoRng, Rng, SeedableRng}; use std::{ collections::{hash_map, BTreeMap, HashMap, HashSet, VecDeque}, + sync::Arc, time::Duration, }; -mod metrics; +/// Approval distribution metrics. +pub mod metrics; #[cfg(test)] mod tests; @@ -86,6 +98,9 @@ const MAX_BITFIELD_SIZE: usize = 500; /// The Approval Distribution subsystem. pub struct ApprovalDistribution { metrics: Metrics, + slot_duration_millis: u64, + clock: Arc, + assignment_criteria: Arc, } /// Contains recently finalized @@ -161,7 +176,7 @@ impl ApprovalEntry { Self { validator_index: assignment.validator, assignment, - approvals: HashMap::with_capacity(candidates.len()), + approvals: HashMap::new(), assignment_claimed_candidates: candidates, routing_info, } @@ -320,7 +335,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, @@ -343,9 +358,6 @@ struct State { /// Tracks recently finalized blocks. recent_outdated_blocks: RecentlyOutdated, - /// HashMap from active leaves to spans - spans: HashMap, - /// Aggression configuration. aggression_config: AggressionConfig, @@ -354,6 +366,9 @@ struct State { /// Aggregated reputation change reputation: ReputationAggregator, + + /// Slot duration in millis + slot_duration_millis: u64, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -488,11 +503,17 @@ struct BlockEntry { knowledge: Knowledge, /// A votes entry for each candidate indexed by [`CandidateIndex`]. candidates: Vec, + /// Information about candidate metadata. + candidates_metadata: Vec<(CandidateHash, CoreIndex, GroupIndex)>, /// The session index of this block. session: SessionIndex, /// Approval entries for whole block. These also contain all approvals in the case of multiple /// candidates being claimed by assignments. approval_entries: HashMap<(ValidatorIndex, CandidateBitfield), ApprovalEntry>, + /// The block vrf story. + vrf_story: RelayVRFStory, + /// The block slot. + slot: Slot, } impl BlockEntry { @@ -646,6 +667,41 @@ enum MessageSource { Local, } +// Encountered error while validating an assignment. +#[derive(Debug)] +enum InvalidAssignmentError { + // The vrf check for the assignment failed. + #[allow(dead_code)] + CryptoCheckFailed(InvalidAssignment), + // The assignment did not claim any valid candidate. + NoClaimedCandidates, + // Claimed invalid candidate. + #[allow(dead_code)] + ClaimedInvalidCandidateIndex { + claimed_index: usize, + max_index: usize, + }, + // The assignment claimes more candidates than the maximum allowed. + OversizedClaimedBitfield, + // `SessionInfo` was not found for the block hash in the assignment. + #[allow(dead_code)] + SessionInfoNotFound(polkadot_node_subsystem_util::runtime::Error), +} + +// Encountered error while validating an approval. +#[derive(Debug)] +enum InvalidVoteError { + // The candidate index was out of bounds. + CandidateIndexOutOfBounds, + // The validator index was out of bounds. + ValidatorIndexOutOfBounds, + // The signature of the vote was invalid. + InvalidSignature, + // `SessionInfo` was not found for the block hash in the approval. + #[allow(dead_code)] + SessionInfoNotFound(polkadot_node_subsystem_util::runtime::Error), +} + impl MessageSource { fn peer_id(&self) -> Option { match self { @@ -662,12 +718,26 @@ enum PendingMessage { #[overseer::contextbounds(ApprovalDistribution, prefix = self::overseer)] impl State { - async fn handle_network_msg( + /// Build State with specified slot duration. + pub fn with_config(slot_duration_millis: u64) -> Self { + Self { slot_duration_millis, ..Default::default() } + } + + async fn handle_network_msg< + N: overseer::SubsystemSender, + A: overseer::SubsystemSender, + RA: overseer::SubsystemSender, + >( &mut self, - ctx: &mut Context, + approval_voting_sender: &mut A, + network_sender: &mut N, + runtime_api_sender: &mut RA, metrics: &Metrics, event: NetworkBridgeEvent, rng: &mut (impl CryptoRng + Rng), + assignment_criteria: &(impl AssignmentCriteria + ?Sized), + clock: &(impl Clock + ?Sized), + session_info_provider: &mut RuntimeInfo, ) { match event { NetworkBridgeEvent::PeerConnected(peer_id, role, version, authority_ids) => { @@ -689,7 +759,7 @@ impl State { }, NetworkBridgeEvent::NewGossipTopology(topology) => { self.handle_new_session_topology( - ctx, + network_sender, topology.session, topology.topology, topology.local_index, @@ -697,7 +767,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 +790,19 @@ 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, + runtime_api_sender, + metrics, + peer_id, + message, + rng, + assignment_criteria, + clock, + session_info_provider, + ) + .await; }, NetworkBridgeEvent::UpdatedAuthorityIds(peer_id, authority_ids) => { gum::debug!(target: LOG_TARGET, ?peer_id, ?authority_ids, "Update Authority Ids"); @@ -743,7 +825,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,27 +843,34 @@ impl State { } } - async fn handle_new_blocks( + async fn handle_new_blocks< + N: overseer::SubsystemSender, + A: overseer::SubsystemSender, + RA: overseer::SubsystemSender, + >( &mut self, - ctx: &mut Context, + approval_voting_sender: &mut A, + network_sender: &mut N, + runtime_api_sender: &mut RA, metrics: &Metrics, metas: Vec, rng: &mut (impl CryptoRng + Rng), + assignment_criteria: &(impl AssignmentCriteria + ?Sized), + clock: &(impl Clock + ?Sized), + session_info_provider: &mut RuntimeInfo, ) { let mut new_hashes = HashSet::new(); - for meta in &metas { - let mut span = self - .spans - .get(&meta.hash) - .map(|span| span.child(&"handle-new-blocks")) - .unwrap_or_else(|| jaeger::Span::new(meta.hash, &"handle-new-blocks")) - .with_string_tag("block-hash", format!("{:?}", meta.hash)) - .with_stage(jaeger::Stage::ApprovalDistribution); + gum::debug!( + target: LOG_TARGET, + "Got new blocks {:?}", + metas.iter().map(|m| (m.hash, m.number)).collect::>(), + ); + + for meta in metas { match self.blocks.entry(meta.hash) { hash_map::Entry::Vacant(entry) => { let candidates_count = meta.candidates.len(); - span.add_uint_tag("candidates-count", candidates_count as u64); let mut candidates = Vec::with_capacity(candidates_count); candidates.resize_with(candidates_count, Default::default); @@ -793,6 +882,9 @@ impl State { candidates, session: meta.session, approval_entries: HashMap::new(), + candidates_metadata: meta.candidates, + vrf_story: meta.vrf_story, + slot: meta.slot, }); self.topologies.inc_session_refs(meta.session); @@ -807,19 +899,12 @@ impl State { } } - gum::debug!( - target: LOG_TARGET, - "Got new blocks {:?}", - metas.iter().map(|m| (m.hash, m.number)).collect::>(), - ); - { - 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,21 +951,29 @@ impl State { match message { PendingMessage::Assignment(assignment, claimed_indices) => { self.import_and_circulate_assignment( - ctx, + approval_voting_sender, + network_sender, + runtime_api_sender, metrics, MessageSource::Peer(peer_id), assignment, claimed_indices, rng, + assignment_criteria, + clock, + session_info_provider, ) .await; }, PendingMessage::Approval(approval_vote) => { self.import_and_circulate_approval( - ctx, + approval_voting_sender, + network_sender, + runtime_api_sender, metrics, MessageSource::Peer(peer_id), approval_vote, + session_info_provider, ) .await; }, @@ -889,12 +982,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 +1001,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 +1019,22 @@ 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, + runtime_api_sender: &mut RA, metrics: &Metrics, peer_id: PeerId, assignments: Vec<(IndirectAssignmentCertV2, CandidateBitfield)>, rng: &mut R, + assignment_criteria: &(impl AssignmentCriteria + ?Sized), + clock: &(impl Clock + ?Sized), + session_info_provider: &mut RuntimeInfo, ) where + A: overseer::SubsystemSender, + N: overseer::SubsystemSender, + RA: overseer::SubsystemSender, R: CryptoRng + Rng, { for (assignment, claimed_indices) in assignments { @@ -956,24 +1057,36 @@ impl State { } self.import_and_circulate_assignment( - ctx, + approval_voting_sender, + network_sender, + runtime_api_sender, metrics, MessageSource::Peer(peer_id), assignment, claimed_indices, rng, + assignment_criteria, + clock, + session_info_provider, ) .await; } } // 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, + RA: overseer::SubsystemSender, + >( &mut self, - ctx: &mut Context, + approval_voting_sender: &mut A, + network_sender: &mut N, + runtime_api_sender: &mut RA, metrics: &Metrics, peer_id: PeerId, approvals: Vec, + session_info_provider: &mut RuntimeInfo, ) { gum::trace!( target: LOG_TARGET, @@ -1001,18 +1114,23 @@ impl State { } self.import_and_circulate_approval( - ctx, + approval_voting_sender, + network_sender, + runtime_api_sender, metrics, MessageSource::Peer(peer_id), approval_vote, + session_info_provider, ) .await; } } - 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, + runtime_api_sender: &mut RA, metrics: &Metrics, peer_id: PeerId, msg: Versioned< @@ -1021,7 +1139,13 @@ impl State { protocol_v3::ApprovalDistributionMessage, >, rng: &mut R, + assignment_criteria: &(impl AssignmentCriteria + ?Sized), + clock: &(impl Clock + ?Sized), + session_info_provider: &mut RuntimeInfo, ) where + A: overseer::SubsystemSender, + N: overseer::SubsystemSender, + RA: overseer::SubsystemSender, R: CryptoRng + Rng, { match msg { @@ -1033,14 +1157,19 @@ 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, + runtime_api_sender, metrics, peer_id, sanitized_assignments, rng, + assignment_criteria, + clock, + session_info_provider, ) .await; }, @@ -1054,38 +1183,59 @@ 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, + runtime_api_sender, metrics, peer_id, sanitized_assignments, rng, + assignment_criteria, + clock, + session_info_provider, ) .await; }, 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, + runtime_api_sender, + metrics, + peer_id, + sanitized_approvals, + session_info_provider, + ) + .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, + runtime_api_sender, + metrics, + peer_id, + sanitized_approvals, + session_info_provider, + ) + .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 +1282,7 @@ impl State { } Self::unify_with_peer( - ctx.sender(), + network_sender, metrics, &mut self.blocks, &self.topologies, @@ -1146,9 +1296,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, ) { @@ -1167,40 +1317,32 @@ impl State { if let Some(block_entry) = self.blocks.remove(relay_block) { self.topologies.dec_session_refs(block_entry.session); } - self.spans.remove(&relay_block); }); // 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, + runtime_api_sender: &mut RA, metrics: &Metrics, source: MessageSource, assignment: IndirectAssignmentCertV2, claimed_candidate_indices: CandidateBitfield, rng: &mut R, + assignment_criteria: &(impl AssignmentCriteria + ?Sized), + clock: &(impl Clock + ?Sized), + session_info_provider: &mut RuntimeInfo, ) where + A: overseer::SubsystemSender, + N: overseer::SubsystemSender, + RA: overseer::SubsystemSender, R: CryptoRng + Rng, { - let _span = self - .spans - .get(&assignment.block_hash) - .map(|span| { - span.child(if source.peer_id().is_some() { - "peer-import-and-distribute-assignment" - } else { - "local-import-and-distribute-assignment" - }) - }) - .unwrap_or_else(|| jaeger::Span::new(&assignment.block_hash, "distribute-assignment")) - .with_string_tag("block-hash", format!("{:?}", assignment.block_hash)) - .with_optional_peer_id(source.peer_id().as_ref()) - .with_stage(jaeger::Stage::ApprovalDistribution); - let block_hash = assignment.block_hash; let validator_index = assignment.validator; @@ -1218,7 +1360,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 +1397,7 @@ impl State { modify_reputation( &mut self.reputation, - ctx.sender(), + network_sender, peer_id, COST_DUPLICATE_MESSAGE, ) @@ -1283,7 +1425,7 @@ impl State { ); modify_reputation( &mut self.reputation, - ctx.sender(), + network_sender, peer_id, COST_UNEXPECTED_MESSAGE, ) @@ -1296,7 +1438,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, ) @@ -1309,37 +1451,50 @@ impl State { return } - let (tx, rx) = oneshot::channel(); - - ctx.send_message(ApprovalVotingMessage::CheckAndImportAssignment( - assignment.clone(), - claimed_candidate_indices.clone(), - tx, - )) + let result = Self::check_assignment_valid( + assignment_criteria, + &entry, + &assignment, + &claimed_candidate_indices, + session_info_provider, + runtime_api_sender, + ) .await; - let timer = metrics.time_awaiting_approval_voting(); - let result = match rx.await { - Ok(result) => result, - Err(_) => { - gum::debug!(target: LOG_TARGET, "The approval voting subsystem is down"); - return - }, - }; - drop(timer); - - gum::trace!( - target: LOG_TARGET, - ?source, - ?message_subject, - ?result, - "Checked assignment", - ); match result { - AssignmentCheckResult::Accepted => { + Ok(checked_assignment) => { + let current_tranche = clock.tranche_now(self.slot_duration_millis, entry.slot); + let too_far_in_future = + current_tranche + TICK_TOO_FAR_IN_FUTURE as DelayTranche; + + if checked_assignment.tranche() >= too_far_in_future { + gum::debug!( + target: LOG_TARGET, + hash = ?block_hash, + ?peer_id, + "Got an assignment too far in the future", + ); + modify_reputation( + &mut self.reputation, + network_sender, + peer_id, + COST_ASSIGNMENT_TOO_FAR_IN_THE_FUTURE, + ) + .await; + metrics.on_assignment_far(); + + return + } + + approval_voting_sender + .send_message(ApprovalVotingMessage::ImportAssignment( + checked_assignment, + None, + )) + .await; modify_reputation( &mut self.reputation, - ctx.sender(), + network_sender, peer_id, BENEFIT_VALID_MESSAGE_FIRST, ) @@ -1349,52 +1504,17 @@ impl State { peer_knowledge.received.insert(message_subject.clone(), message_kind); } }, - AssignmentCheckResult::AcceptedDuplicate => { - // "duplicate" assignments aren't necessarily equal. - // There is more than one way each validator can be assigned to each core. - // cf. https://github.com/paritytech/polkadot/pull/2160#discussion_r557628699 - if let Some(peer_knowledge) = entry.known_by.get_mut(&peer_id) { - peer_knowledge.received.insert(message_subject.clone(), message_kind); - } - gum::debug!( - target: LOG_TARGET, - hash = ?block_hash, - ?peer_id, - "Got an `AcceptedDuplicate` assignment", - ); - metrics.on_assignment_duplicatevoting(); - - return - }, - AssignmentCheckResult::TooFarInFuture => { - gum::debug!( - target: LOG_TARGET, - hash = ?block_hash, - ?peer_id, - "Got an assignment too far in the future", - ); - modify_reputation( - &mut self.reputation, - ctx.sender(), - peer_id, - COST_ASSIGNMENT_TOO_FAR_IN_THE_FUTURE, - ) - .await; - metrics.on_assignment_far(); - - return - }, - AssignmentCheckResult::Bad(error) => { + Err(error) => { gum::info!( target: LOG_TARGET, hash = ?block_hash, ?peer_id, - %error, + ?error, "Got a bad assignment from peer", ); modify_reputation( &mut self.reputation, - ctx.sender(), + network_sender, peer_id, COST_INVALID_MESSAGE, ) @@ -1526,14 +1646,74 @@ impl State { }) .collect::>(); - send_assignments_batched(ctx.sender(), assignments, &peers).await; + send_assignments_batched(network_sender, assignments, &peers).await; } } + async fn check_assignment_valid>( + assignment_criteria: &(impl AssignmentCriteria + ?Sized), + entry: &BlockEntry, + assignment: &IndirectAssignmentCertV2, + claimed_candidate_indices: &CandidateBitfield, + runtime_info: &mut RuntimeInfo, + runtime_api_sender: &mut RA, + ) -> Result { + let ExtendedSessionInfo { ref session_info, .. } = runtime_info + .get_session_info_by_index(runtime_api_sender, assignment.block_hash, entry.session) + .await + .map_err(|err| InvalidAssignmentError::SessionInfoNotFound(err))?; + + if claimed_candidate_indices.len() > session_info.n_cores as usize { + return Err(InvalidAssignmentError::OversizedClaimedBitfield) + } + + let claimed_cores: Vec = claimed_candidate_indices + .iter_ones() + .map(|candidate_index| { + entry.candidates_metadata.get(candidate_index).map(|(_, core, _)| *core).ok_or( + InvalidAssignmentError::ClaimedInvalidCandidateIndex { + claimed_index: candidate_index, + max_index: entry.candidates_metadata.len(), + }, + ) + }) + .collect::, InvalidAssignmentError>>()?; + + let Ok(claimed_cores) = claimed_cores.try_into() else { + return Err(InvalidAssignmentError::NoClaimedCandidates) + }; + + let backing_groups = claimed_candidate_indices + .iter_ones() + .flat_map(|candidate_index| { + entry.candidates_metadata.get(candidate_index).map(|(_, _, group)| *group) + }) + .collect::>(); + + assignment_criteria + .check_assignment_cert( + claimed_cores, + assignment.validator, + &polkadot_node_primitives::approval::criteria::Config::from(session_info), + entry.vrf_story.clone(), + &assignment.cert, + backing_groups, + ) + .map_err(|err| InvalidAssignmentError::CryptoCheckFailed(err)) + .map(|tranche| { + CheckedIndirectAssignment::from_checked( + assignment.clone(), + claimed_candidate_indices.clone(), + tranche, + ) + }) + } // 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 +1729,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 +1754,7 @@ impl State { modify_reputation( reputation, - ctx.sender(), + network_sender, peer_id, COST_DUPLICATE_MESSAGE, ) @@ -1590,7 +1771,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,35 +1787,27 @@ 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, + RA: overseer::SubsystemSender, + >( &mut self, - ctx: &mut Context, + approval_voting_sender: &mut A, + network_sender: &mut N, + runtime_api_sender: &mut RA, metrics: &Metrics, source: MessageSource, vote: IndirectSignedApprovalVoteV2, + session_info_provider: &mut RuntimeInfo, ) { - let _span = self - .spans - .get(&vote.block_hash) - .map(|span| { - span.child(if source.peer_id().is_some() { - "peer-import-and-distribute-approval" - } else { - "local-import-and-distribute-approval" - }) - }) - .unwrap_or_else(|| jaeger::Span::new(&vote.block_hash, "distribute-approval")) - .with_string_tag("block-hash", format!("{:?}", vote.block_hash)) - .with_optional_peer_id(source.peer_id().as_ref()) - .with_stage(jaeger::Stage::ApprovalDistribution); - let block_hash = vote.block_hash; let validator_index = vote.validator; let candidate_indices = &vote.candidate_indices; @@ -1652,7 +1826,7 @@ impl State { ); modify_reputation( &mut self.reputation, - ctx.sender(), + network_sender, peer_id, COST_UNEXPECTED_MESSAGE, ) @@ -1672,7 +1846,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, @@ -1685,33 +1859,19 @@ impl State { return } - let (tx, rx) = oneshot::channel(); - - ctx.send_message(ApprovalVotingMessage::CheckAndImportApproval(vote.clone(), tx)) - .await; - - let timer = metrics.time_awaiting_approval_voting(); - let result = match rx.await { - Ok(result) => result, - Err(_) => { - gum::debug!(target: LOG_TARGET, "The approval voting subsystem is down"); - return - }, - }; - drop(timer); + let result = + Self::check_vote_valid(&vote, &entry, session_info_provider, runtime_api_sender) + .await; - gum::trace!( - target: LOG_TARGET, - ?peer_id, - ?result, - ?vote, - "Checked approval", - ); match result { - ApprovalCheckResult::Accepted => { + Ok(vote) => { + approval_voting_sender + .send_message(ApprovalVotingMessage::ImportApproval(vote, None)) + .await; + modify_reputation( &mut self.reputation, - ctx.sender(), + network_sender, peer_id, BENEFIT_VALID_MESSAGE_FIRST, ) @@ -1726,18 +1886,19 @@ impl State { .insert(approval_knwowledge_key.0.clone(), approval_knwowledge_key.1); } }, - ApprovalCheckResult::Bad(error) => { + Err(err) => { modify_reputation( &mut self.reputation, - ctx.sender(), + network_sender, peer_id, COST_INVALID_MESSAGE, ) .await; + gum::info!( target: LOG_TARGET, ?peer_id, - %error, + ?err, "Got a bad approval from peer", ); metrics.on_approval_bad(); @@ -1831,10 +1992,54 @@ 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; } } + // Checks if the approval vote is valid. + async fn check_vote_valid>( + vote: &IndirectSignedApprovalVoteV2, + entry: &BlockEntry, + runtime_info: &mut RuntimeInfo, + runtime_api_sender: &mut RA, + ) -> Result { + if vote.candidate_indices.len() > entry.candidates_metadata.len() { + return Err(InvalidVoteError::CandidateIndexOutOfBounds) + } + + let candidate_hashes = vote + .candidate_indices + .iter_ones() + .flat_map(|candidate_index| { + entry + .candidates_metadata + .get(candidate_index) + .map(|(candidate_hash, _, _)| *candidate_hash) + }) + .collect::>(); + + let ExtendedSessionInfo { ref session_info, .. } = runtime_info + .get_session_info_by_index(runtime_api_sender, vote.block_hash, entry.session) + .await + .map_err(|err| InvalidVoteError::SessionInfoNotFound(err))?; + + let pubkey = session_info + .validators + .get(vote.validator) + .ok_or(InvalidVoteError::ValidatorIndexOutOfBounds)?; + DisputeStatement::Valid(ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates( + candidate_hashes.clone(), + )) + .check_signature( + &pubkey, + *candidate_hashes.first().unwrap(), + entry.session, + &vote.signature, + ) + .map_err(|_| InvalidVoteError::InvalidSignature) + .map(|_| CheckedIndirectSignedApprovalVote::from_checked(vote.clone())) + } + /// Retrieve approval signatures from state for the given relay block/indices: fn get_approval_signatures( &mut self, @@ -1842,14 +2047,6 @@ impl State { ) -> HashMap, ValidatorSignature)> { let mut all_sigs = HashMap::new(); for (hash, index) in indices { - let _span = self - .spans - .get(&hash) - .map(|span| span.child("get-approval-signatures")) - .unwrap_or_else(|| jaeger::Span::new(&hash, "get-approval-signatures")) - .with_string_tag("block-hash", format!("{:?}", hash)) - .with_stage(jaeger::Stage::ApprovalDistribution); - let block_entry = match self.blocks.get(&hash) { None => { gum::debug!( @@ -1882,7 +2079,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 +2224,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 +2255,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 +2283,7 @@ impl State { .await; adjust_required_routing_and_propagate( - ctx, + network_sender, &mut self.blocks, &self.topologies, |block_entry| { @@ -2137,7 +2334,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 +2369,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 +2413,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 +2440,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 +2477,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 +2564,7 @@ async fn adjust_required_routing_and_propagate, peer_id: PeerId, rep: Rep, ) { @@ -2408,17 +2609,48 @@ async fn modify_reputation( #[overseer::contextbounds(ApprovalDistribution, prefix = self::overseer)] impl ApprovalDistribution { /// Create a new instance of the [`ApprovalDistribution`] subsystem. - pub fn new(metrics: Metrics) -> Self { - Self { metrics } + pub fn new( + metrics: Metrics, + slot_duration_millis: u64, + assignment_criteria: Arc, + ) -> Self { + Self::new_with_clock( + metrics, + slot_duration_millis, + Arc::new(SystemClock), + assignment_criteria, + ) } - async fn run(self, ctx: Context) { - let mut state = State::default(); + /// Create a new instance of the [`ApprovalDistribution`] subsystem, with a custom clock. + pub fn new_with_clock( + metrics: Metrics, + slot_duration_millis: u64, + clock: Arc, + assignment_criteria: Arc, + ) -> Self { + Self { metrics, slot_duration_millis, clock, assignment_criteria } + } + async fn run(self, ctx: Context) { + let mut state = + State { slot_duration_millis: self.slot_duration_millis, ..Default::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(); - self.run_inner(ctx, &mut state, REPUTATION_CHANGE_INTERVAL, &mut rng).await + let mut session_info_provider = RuntimeInfo::new_with_config(RuntimeInfoConfig { + keystore: None, + session_cache_lru_size: DISPUTE_WINDOW.get(), + }); + + self.run_inner( + ctx, + &mut state, + REPUTATION_CHANGE_INTERVAL, + &mut rng, + &mut session_info_provider, + ) + .await } /// Used for testing. @@ -2428,9 +2660,13 @@ impl ApprovalDistribution { state: &mut State, reputation_interval: Duration, rng: &mut (impl CryptoRng + Rng), + session_info_provider: &mut RuntimeInfo, ) { 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(); + let mut runtime_api_sender = ctx.sender().clone(); loop { select! { @@ -2446,56 +2682,112 @@ 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, + + if self.handle_from_orchestra(message, &mut approval_voting_sender, &mut network_sender, &mut runtime_api_sender, state, rng, session_info_provider).await { + return; } + }, } } } - async fn handle_incoming( - ctx: &mut Context, + /// Handles a from orchestra message received by approval distribution subystem. + /// + /// Returns `true` if the subsystem should be stopped. + pub async fn handle_from_orchestra< + N: overseer::SubsystemSender, + A: overseer::SubsystemSender, + RA: overseer::SubsystemSender, + >( + &self, + message: FromOrchestra, + approval_voting_sender: &mut A, + network_sender: &mut N, + runtime_api_sender: &mut RA, + state: &mut State, + rng: &mut (impl CryptoRng + Rng), + session_info_provider: &mut RuntimeInfo, + ) -> bool { + match message { + FromOrchestra::Communication { msg } => + Self::handle_incoming( + approval_voting_sender, + network_sender, + runtime_api_sender, + state, + msg, + &self.metrics, + rng, + self.assignment_criteria.as_ref(), + self.clock.as_ref(), + session_info_provider, + ) + .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. + }, + 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 true, + } + false + } + + async fn handle_incoming< + N: overseer::SubsystemSender, + A: overseer::SubsystemSender, + RA: overseer::SubsystemSender, + >( + approval_voting_sender: &mut A, + network_sender: &mut N, + runtime_api_sender: &mut RA, state: &mut State, msg: ApprovalDistributionMessage, metrics: &Metrics, rng: &mut (impl CryptoRng + Rng), + assignment_criteria: &(impl AssignmentCriteria + ?Sized), + clock: &(impl Clock + ?Sized), + session_info_provider: &mut RuntimeInfo, ) { match msg { ApprovalDistributionMessage::NetworkBridgeUpdate(event) => { - state.handle_network_msg(ctx, metrics, event, rng).await; + state + .handle_network_msg( + approval_voting_sender, + network_sender, + runtime_api_sender, + metrics, + event, + rng, + assignment_criteria, + clock, + session_info_provider, + ) + .await; }, ApprovalDistributionMessage::NewBlocks(metas) => { - state.handle_new_blocks(ctx, metrics, metas, rng).await; + state + .handle_new_blocks( + approval_voting_sender, + network_sender, + runtime_api_sender, + metrics, + metas, + rng, + assignment_criteria, + clock, + session_info_provider, + ) + .await; }, ApprovalDistributionMessage::DistributeAssignment(cert, candidate_indices) => { - let _span = state - .spans - .get(&cert.block_hash) - .map(|span| span.child("import-and-distribute-assignment")) - .unwrap_or_else(|| jaeger::Span::new(&cert.block_hash, "distribute-assignment")) - .with_string_tag("block-hash", format!("{:?}", cert.block_hash)) - .with_stage(jaeger::Stage::ApprovalDistribution); - gum::debug!( target: LOG_TARGET, ?candidate_indices, @@ -2506,12 +2798,17 @@ impl ApprovalDistribution { state .import_and_circulate_assignment( - ctx, + approval_voting_sender, + network_sender, + runtime_api_sender, &metrics, MessageSource::Local, cert, candidate_indices, rng, + assignment_criteria, + clock, + session_info_provider, ) .await; }, @@ -2524,7 +2821,15 @@ impl ApprovalDistribution { ); state - .import_and_circulate_approval(ctx, metrics, MessageSource::Local, vote) + .import_and_circulate_approval( + approval_voting_sender, + network_sender, + runtime_api_sender, + metrics, + MessageSource::Local, + vote, + session_info_provider, + ) .await; }, ApprovalDistributionMessage::GetApprovalSignatures(indices, tx) => { @@ -2579,7 +2884,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 +2939,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 +2963,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 +2973,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 +2988,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/metrics.rs b/polkadot/node/network/approval-distribution/src/metrics.rs index 60c7f2f6d3b8..2f677ba415e4 100644 --- a/polkadot/node/network/approval-distribution/src/metrics.rs +++ b/polkadot/node/network/approval-distribution/src/metrics.rs @@ -30,7 +30,6 @@ struct MetricsInner { aggression_l2_messages_total: prometheus::Counter, time_unify_with_peer: prometheus::Histogram, time_import_pending_now_known: prometheus::Histogram, - time_awaiting_approval_voting: prometheus::Histogram, assignments_received_result: prometheus::CounterVec, approvals_received_result: prometheus::CounterVec, } @@ -80,31 +79,19 @@ impl Metrics { .map(|metrics| metrics.time_import_pending_now_known.start_timer()) } - pub fn on_approval_already_known(&self) { - if let Some(metrics) = &self.0 { - metrics.approvals_received_result.with_label_values(&["known"]).inc() - } - } - - pub fn on_approval_entry_not_found(&self) { - if let Some(metrics) = &self.0 { - metrics.approvals_received_result.with_label_values(&["noapprovalentry"]).inc() - } - } - - pub fn on_approval_recent_outdated(&self) { + pub(crate) fn on_approval_recent_outdated(&self) { if let Some(metrics) = &self.0 { metrics.approvals_received_result.with_label_values(&["outdated"]).inc() } } - pub fn on_approval_invalid_block(&self) { + pub(crate) fn on_approval_invalid_block(&self) { if let Some(metrics) = &self.0 { metrics.approvals_received_result.with_label_values(&["invalidblock"]).inc() } } - pub fn on_approval_unknown_assignment(&self) { + pub(crate) fn on_approval_unknown_assignment(&self) { if let Some(metrics) = &self.0 { metrics .approvals_received_result @@ -113,107 +100,78 @@ impl Metrics { } } - pub fn on_approval_duplicate(&self) { + pub(crate) fn on_approval_duplicate(&self) { if let Some(metrics) = &self.0 { metrics.approvals_received_result.with_label_values(&["duplicate"]).inc() } } - pub fn on_approval_out_of_view(&self) { + pub(crate) fn on_approval_out_of_view(&self) { if let Some(metrics) = &self.0 { metrics.approvals_received_result.with_label_values(&["outofview"]).inc() } } - pub fn on_approval_good_known(&self) { + pub(crate) fn on_approval_good_known(&self) { if let Some(metrics) = &self.0 { metrics.approvals_received_result.with_label_values(&["goodknown"]).inc() } } - pub fn on_approval_bad(&self) { + pub(crate) fn on_approval_bad(&self) { if let Some(metrics) = &self.0 { metrics.approvals_received_result.with_label_values(&["bad"]).inc() } } - pub fn on_approval_unexpected(&self) { - if let Some(metrics) = &self.0 { - metrics.approvals_received_result.with_label_values(&["unexpected"]).inc() - } - } - - pub fn on_approval_bug(&self) { + pub(crate) fn on_approval_bug(&self) { if let Some(metrics) = &self.0 { metrics.approvals_received_result.with_label_values(&["bug"]).inc() } } - pub fn on_assignment_already_known(&self) { - if let Some(metrics) = &self.0 { - metrics.assignments_received_result.with_label_values(&["known"]).inc() - } - } - - pub fn on_assignment_recent_outdated(&self) { + pub(crate) fn on_assignment_recent_outdated(&self) { if let Some(metrics) = &self.0 { metrics.assignments_received_result.with_label_values(&["outdated"]).inc() } } - pub fn on_assignment_invalid_block(&self) { + pub(crate) fn on_assignment_invalid_block(&self) { if let Some(metrics) = &self.0 { metrics.assignments_received_result.with_label_values(&["invalidblock"]).inc() } } - pub fn on_assignment_duplicate(&self) { + pub(crate) fn on_assignment_duplicate(&self) { if let Some(metrics) = &self.0 { metrics.assignments_received_result.with_label_values(&["duplicate"]).inc() } } - pub fn on_assignment_out_of_view(&self) { + pub(crate) fn on_assignment_out_of_view(&self) { if let Some(metrics) = &self.0 { metrics.assignments_received_result.with_label_values(&["outofview"]).inc() } } - pub fn on_assignment_good_known(&self) { + pub(crate) fn on_assignment_good_known(&self) { if let Some(metrics) = &self.0 { metrics.assignments_received_result.with_label_values(&["goodknown"]).inc() } } - pub fn on_assignment_bad(&self) { + pub(crate) fn on_assignment_bad(&self) { if let Some(metrics) = &self.0 { metrics.assignments_received_result.with_label_values(&["bad"]).inc() } } - pub fn on_assignment_duplicatevoting(&self) { - if let Some(metrics) = &self.0 { - metrics - .assignments_received_result - .with_label_values(&["duplicatevoting"]) - .inc() - } - } - - pub fn on_assignment_far(&self) { + pub(crate) fn on_assignment_far(&self) { if let Some(metrics) = &self.0 { metrics.assignments_received_result.with_label_values(&["far"]).inc() } } - pub(crate) fn time_awaiting_approval_voting( - &self, - ) -> Option { - self.0 - .as_ref() - .map(|metrics| metrics.time_awaiting_approval_voting.start_timer()) - } - pub(crate) fn on_aggression_l1(&self) { if let Some(metrics) = &self.0 { metrics.aggression_l1_messages_total.inc(); @@ -288,13 +246,6 @@ impl MetricsTrait for Metrics { ).buckets(vec![0.0001, 0.0004, 0.0016, 0.0064, 0.0256, 0.1024, 0.4096, 1.6384, 3.2768, 4.9152, 6.5536,]))?, registry, )?, - time_awaiting_approval_voting: prometheus::register( - prometheus::Histogram::with_opts(prometheus::HistogramOpts::new( - "polkadot_parachain_time_awaiting_approval_voting", - "Time spent awaiting a reply from the Approval Voting Subsystem.", - ).buckets(vec![0.0001, 0.0004, 0.0016, 0.0064, 0.0256, 0.1024, 0.4096, 1.6384, 3.2768, 4.9152, 6.5536,]))?, - registry, - )?, assignments_received_result: prometheus::register( prometheus::CounterVec::new( prometheus::Opts::new( diff --git a/polkadot/node/network/approval-distribution/src/tests.rs b/polkadot/node/network/approval-distribution/src/tests.rs index 2d08807f97b6..063e71f2f528 100644 --- a/polkadot/node/network/approval-distribution/src/tests.rs +++ b/polkadot/node/network/approval-distribution/src/tests.rs @@ -16,7 +16,7 @@ use super::*; use assert_matches::assert_matches; -use futures::{executor, future, Future}; +use futures::{channel::oneshot, executor, future, Future}; use polkadot_node_network_protocol::{ grid_topology::{SessionGridTopology, TopologyPeerInfo}, our_view, @@ -24,6 +24,7 @@ use polkadot_node_network_protocol::{ view, ObservedRole, }; use polkadot_node_primitives::approval::{ + criteria, v1::{ AssignmentCert, AssignmentCertKind, IndirectAssignmentCert, IndirectSignedApprovalVote, VrfPreOutput, VrfProof, VrfSignature, @@ -34,12 +35,17 @@ use polkadot_node_primitives::approval::{ }, }; use polkadot_node_subsystem::messages::{ - network_bridge_event, AllMessages, ApprovalCheckError, ReportPeerMessage, + network_bridge_event, AllMessages, ReportPeerMessage, RuntimeApiRequest, }; use polkadot_node_subsystem_util::{reputation::add_reputation, TimeoutExt as _}; -use polkadot_primitives::{AuthorityDiscoveryId, BlakeTwo256, CoreIndex, HashT}; +use polkadot_primitives::{ + ApprovalVoteMultipleCandidates, AuthorityDiscoveryId, BlakeTwo256, CoreIndex, ExecutorParams, + HashT, NodeFeatures, SessionInfo, ValidatorId, +}; use polkadot_primitives_test_helpers::dummy_signature; use rand::SeedableRng; +use sc_keystore::{Keystore, LocalKeystore}; +use sp_application_crypto::AppCrypto; use sp_authority_discovery::AuthorityPair as AuthorityDiscoveryPair; use sp_core::crypto::Pair as PairT; use std::time::Duration; @@ -47,24 +53,43 @@ type VirtualOverseer = polkadot_node_subsystem_test_helpers::TestSubsystemContextHandle; fn test_harness>( + assignment_criteria: Arc, + clock: Arc, 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) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool.clone()); - let subsystem = ApprovalDistribution::new(Default::default()); + let subsystem = ApprovalDistribution::new_with_clock( + Metrics::default(), + Default::default(), + clock, + assignment_criteria, + ); { let mut rng = rand_chacha::ChaCha12Rng::seed_from_u64(12345); - - let subsystem = - subsystem.run_inner(context, &mut state, REPUTATION_CHANGE_TEST_INTERVAL, &mut rng); + let mut session_info_provider = RuntimeInfo::new_with_config(RuntimeInfoConfig { + keystore: None, + session_cache_lru_size: DISPUTE_WINDOW.get(), + }); + + let (tx, rx) = oneshot::channel(); + let subsystem = async { + subsystem + .run_inner( + context, + &mut state, + REPUTATION_CHANGE_TEST_INTERVAL, + &mut rng, + &mut session_info_provider, + ) + .await; + tx.send(()).expect("Fail to notify subystem is done"); + }; let test_fut = test_fn(virtual_overseer); @@ -79,6 +104,8 @@ fn test_harness>( .timeout(TIMEOUT) .await .expect("Conclude send timeout"); + let _ = + rx.timeout(Duration::from_secs(2)).await.expect("Subsystem did not conclude"); }, subsystem, )); @@ -118,6 +145,41 @@ async fn overseer_recv(overseer: &mut VirtualOverseer) -> AllMessages { msg } +async fn provide_session(virtual_overseer: &mut VirtualOverseer, session_info: SessionInfo) { + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request( + _, + RuntimeApiRequest::SessionInfo(_, si_tx), + ) + ) => { + si_tx.send(Ok(Some(session_info.clone()))).unwrap(); + } + ); + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request( + _, + RuntimeApiRequest::SessionExecutorParams(_, si_tx), + ) + ) => { + // Make sure all SessionExecutorParams calls are not made for the leaf (but for its relay parent) + si_tx.send(Ok(Some(ExecutorParams::default()))).unwrap(); + } + ); + + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::RuntimeApi( + RuntimeApiMessage::Request(_, RuntimeApiRequest::NodeFeatures(_, si_tx), ) + ) => { + si_tx.send(Ok(NodeFeatures::EMPTY)).unwrap(); + } + ); +} + fn make_peers_and_authority_ids(n: usize) -> Vec<(PeerId, AuthorityDiscoveryId)> { (0..n) .map(|_| { @@ -332,6 +394,30 @@ fn fake_assignment_cert_v2( } } +fn fake_assignment_cert_delay( + block_hash: Hash, + validator: ValidatorIndex, + core_bitfield: CoreBitfield, +) -> IndirectAssignmentCertV2 { + let ctx = schnorrkel::signing_context(RELAY_VRF_MODULO_CONTEXT); + let msg = b"WhenParachains?"; + let mut prng = rand_core::OsRng; + let keypair = schnorrkel::Keypair::generate_with(&mut prng); + let (inout, proof, _) = keypair.vrf_sign(ctx.bytes(msg)); + let preout = inout.to_preout(); + + IndirectAssignmentCertV2 { + block_hash, + validator, + cert: AssignmentCertV2 { + kind: AssignmentCertKindV2::RelayVRFDelay { + core_index: CoreIndex(core_bitfield.iter_ones().next().unwrap() as u32), + }, + vrf: VrfSignature { pre_output: VrfPreOutput(preout), proof: VrfProof(proof) }, + }, + } +} + async fn expect_reputation_change( virtual_overseer: &mut VirtualOverseer, peer_id: &PeerId, @@ -375,6 +461,86 @@ fn state_with_reputation_delay() -> State { State { reputation: ReputationAggregator::new(|_| false), ..Default::default() } } +fn dummy_session_info_valid( + index: SessionIndex, + keystore: &mut LocalKeystore, + num_validators: usize, +) -> SessionInfo { + let keys = (0..num_validators) + .map(|_| { + keystore + .sr25519_generate_new(ValidatorId::ID, Some("//Node")) + .expect("Insert key into keystore") + }) + .collect_vec(); + + SessionInfo { + validators: keys.clone().into_iter().map(|key| key.into()).collect(), + discovery_keys: keys.clone().into_iter().map(|key| key.into()).collect(), + assignment_keys: keys.clone().into_iter().map(|key| key.into()).collect(), + validator_groups: Default::default(), + n_cores: 20, + zeroth_delay_tranche_width: index as _, + relay_vrf_modulo_samples: index as _, + n_delay_tranches: index as _, + no_show_slots: index as _, + needed_approvals: index as _, + active_validator_indices: Vec::new(), + dispute_period: 6, + random_seed: [0u8; 32], + } +} + +fn signature_for( + keystore: &LocalKeystore, + session: &SessionInfo, + candidate_hashes: Vec, + validator_index: ValidatorIndex, +) -> ValidatorSignature { + let payload = ApprovalVoteMultipleCandidates(&candidate_hashes).signing_payload(1); + let sign_key = session.validators.get(validator_index).unwrap().clone(); + let signature = keystore + .sr25519_sign(ValidatorId::ID, &sign_key.into(), &payload[..]) + .unwrap() + .unwrap(); + signature.into() +} + +struct MockAssignmentCriteria { + tranche: + Result, +} + +impl AssignmentCriteria for MockAssignmentCriteria { + fn compute_assignments( + &self, + _keystore: &LocalKeystore, + _relay_vrf_story: polkadot_node_primitives::approval::v1::RelayVRFStory, + _config: &criteria::Config, + _leaving_cores: Vec<( + CandidateHash, + polkadot_primitives::CoreIndex, + polkadot_primitives::GroupIndex, + )>, + _enable_assignments_v2: bool, + ) -> HashMap { + HashMap::new() + } + + fn check_assignment_cert( + &self, + _claimed_core_bitfield: polkadot_node_primitives::approval::v2::CoreBitfield, + _validator_index: polkadot_primitives::ValidatorIndex, + _config: &criteria::Config, + _relay_vrf_story: polkadot_node_primitives::approval::v1::RelayVRFStory, + _assignment: &polkadot_node_primitives::approval::v2::AssignmentCertV2, + _backing_groups: Vec, + ) -> Result + { + self.tranche + } +} + /// import an assignment /// connect a new peer /// the new peer sends us the same assignment @@ -388,89 +554,97 @@ fn try_import_the_same_assignment() { let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); - let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - // setup peers - setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V1).await; - setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V1).await; - setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V1).await; - - // Set up a gossip topology, where a, b, c and d are topology neighbors to the node under - // testing. - let peers_with_optional_peer_id = peers - .iter() - .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) - .collect_vec(); - setup_gossip_topology( - overseer, - make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), - ) - .await; + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state_without_reputation_delay(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + + setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V1).await; + setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V1).await; + setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V1).await; + + // under testing. + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + setup_gossip_topology( + overseer, + make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), + ) + .await; - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 2, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 2, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + // send the assignment related to `hash` + let validator_index = ValidatorIndex(0); + let cert = fake_assignment_cert(hash, validator_index); + let assignments = vec![(cert.clone(), 0u32)]; - // send the assignment related to `hash` - let validator_index = ValidatorIndex(0); - let cert = fake_assignment_cert(hash, validator_index); - let assignments = vec![(cert.clone(), 0u32)]; + let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); + send_message_from_peer(overseer, &peer_a, msg).await; - let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); - send_message_from_peer(overseer, &peer_a, msg).await; + expect_reputation_change(overseer, &peer_a, COST_UNEXPECTED_MESSAGE).await; + provide_session( + overseer, + dummy_session_info_valid(1, &mut LocalKeystore::in_memory(), 1), + ) + .await; + // send an `Accept` message from the Approval Voting subsystem + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportAssignment( + assignment, + _, + )) => { + assert_eq!(assignment.candidate_indices(), &0u32.into()); + assert_eq!(assignment.assignment(), &cert.into()); + assert_eq!(assignment.tranche(), 0); + } + ); - expect_reputation_change(overseer, &peer_a, COST_UNEXPECTED_MESSAGE).await; + expect_reputation_change(overseer, &peer_a, BENEFIT_VALID_MESSAGE_FIRST).await; - // send an `Accept` message from the Approval Voting subsystem - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( - assignment, - claimed_indices, - tx, - )) => { - assert_eq!(claimed_indices, 0u32.into()); - assert_eq!(assignment, cert.into()); - tx.send(AssignmentCheckResult::Accepted).unwrap(); - } - ); - - expect_reputation_change(overseer, &peer_a, BENEFIT_VALID_MESSAGE_FIRST).await; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(assignments) - )) - )) => { - assert_eq!(peers.len(), 2); - assert_eq!(assignments.len(), 1); - } - ); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers.len(), 2); + assert_eq!(assignments.len(), 1); + } + ); - // setup new peer with V2 - setup_peer_with_view(overseer, &peer_d, view![], ValidationVersion::V3).await; + // setup new peer with V2 + setup_peer_with_view(overseer, &peer_d, view![], ValidationVersion::V3).await; - // send the same assignment from peer_d - let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments); - send_message_from_peer(overseer, &peer_d, msg).await; + // send the same assignment from peer_d + let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments); + send_message_from_peer(overseer, &peer_d, msg).await; - expect_reputation_change(overseer, &peer_d, COST_UNEXPECTED_MESSAGE).await; - expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE).await; + expect_reputation_change(overseer, &peer_d, COST_UNEXPECTED_MESSAGE).await; + expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE).await; - assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); - virtual_overseer - }); + assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); + virtual_overseer + }, + ); } /// Just like `try_import_the_same_assignment` but use `VRFModuloCompact` assignments for multiple @@ -485,97 +659,106 @@ fn try_import_the_same_assignment_v2() { let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); - let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - // setup peers - setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V3).await; - setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V3).await; - setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V3).await; - - // Set up a gossip topology, where a, b, c and d are topology neighbors to the node under - // testing. - let peers_with_optional_peer_id = peers - .iter() - .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) - .collect_vec(); - setup_gossip_topology( - overseer, - make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), - ) - .await; + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state_without_reputation_delay(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // setup peers + setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V3).await; + setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V3).await; + setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V3).await; + + // Set up a gossip topology, where a, b, c and d are topology neighbors to the node + // under testing. + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + setup_gossip_topology( + overseer, + make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), + ) + .await; - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 2, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - - // send the assignment related to `hash` - let validator_index = ValidatorIndex(0); - let cores = vec![1, 2, 3, 4]; - let core_bitfield: CoreBitfield = cores - .iter() - .map(|index| CoreIndex(*index)) - .collect::>() - .try_into() - .unwrap(); - - let cert = fake_assignment_cert_v2(hash, validator_index, core_bitfield.clone()); - let assignments = vec![(cert.clone(), cores.clone().try_into().unwrap())]; - - let msg = protocol_v3::ApprovalDistributionMessage::Assignments(assignments.clone()); - send_message_from_peer_v3(overseer, &peer_a, msg).await; - - expect_reputation_change(overseer, &peer_a, COST_UNEXPECTED_MESSAGE).await; - - // send an `Accept` message from the Approval Voting subsystem - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( - assignment, - claimed_indices, - tx, - )) => { - assert_eq!(claimed_indices, cores.try_into().unwrap()); - assert_eq!(assignment, cert.into()); - tx.send(AssignmentCheckResult::Accepted).unwrap(); - } - ); - - expect_reputation_change(overseer, &peer_a, BENEFIT_VALID_MESSAGE_FIRST).await; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( - protocol_v3::ApprovalDistributionMessage::Assignments(assignments) - )) - )) => { - assert_eq!(peers.len(), 2); - assert_eq!(assignments.len(), 1); - } - ); + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 2, + candidates: vec![Default::default(); 5], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + // send the assignment related to `hash` + let validator_index = ValidatorIndex(0); + let cores = vec![1, 2, 3, 4]; + let core_bitfield: CoreBitfield = cores + .iter() + .map(|index| CoreIndex(*index)) + .collect::>() + .try_into() + .unwrap(); + + let cert = fake_assignment_cert_v2(hash, validator_index, core_bitfield.clone()); + let assignments = vec![(cert.clone(), cores.clone().try_into().unwrap())]; + + let msg = protocol_v3::ApprovalDistributionMessage::Assignments(assignments.clone()); + send_message_from_peer_v3(overseer, &peer_a, msg).await; + + expect_reputation_change(overseer, &peer_a, COST_UNEXPECTED_MESSAGE).await; + provide_session( + overseer, + dummy_session_info_valid(1, &mut LocalKeystore::in_memory(), 1), + ) + .await; + // send an `Accept` message from the Approval Voting subsystem + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportAssignment( + assignment, + _, + )) => { + assert_eq!(assignment.candidate_indices(), &cores.try_into().unwrap()); + assert_eq!(assignment.assignment(), &cert.into()); + assert_eq!(assignment.tranche(), 0); + } + ); + + expect_reputation_change(overseer, &peer_a, BENEFIT_VALID_MESSAGE_FIRST).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers.len(), 2); + assert_eq!(assignments.len(), 1); + } + ); - // setup new peer - setup_peer_with_view(overseer, &peer_d, view![], ValidationVersion::V3).await; + // setup new peer + setup_peer_with_view(overseer, &peer_d, view![], ValidationVersion::V3).await; - // send the same assignment from peer_d - let msg = protocol_v3::ApprovalDistributionMessage::Assignments(assignments); - send_message_from_peer_v3(overseer, &peer_d, msg).await; + // send the same assignment from peer_d + let msg = protocol_v3::ApprovalDistributionMessage::Assignments(assignments); + send_message_from_peer_v3(overseer, &peer_d, msg).await; - expect_reputation_change(overseer, &peer_d, COST_UNEXPECTED_MESSAGE).await; - expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE).await; + expect_reputation_change(overseer, &peer_d, COST_UNEXPECTED_MESSAGE).await; + expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE).await; - assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); - virtual_overseer - }); + assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); + virtual_overseer + }, + ); } /// import an assignment @@ -587,55 +770,65 @@ fn delay_reputation_change() { let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); - let _ = test_harness(state_with_reputation_delay(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - - // Setup peers - setup_peer_with_view(overseer, &peer, view![], ValidationVersion::V1).await; - - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 2, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - - // send the assignment related to `hash` - let validator_index = ValidatorIndex(0); - let cert = fake_assignment_cert(hash, validator_index); - let assignments = vec![(cert.clone(), 0u32)]; + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state_with_reputation_delay(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + + // Setup peers + setup_peer_with_view(overseer, &peer, view![], ValidationVersion::V1).await; + + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 2, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + // send the assignment related to `hash` + let validator_index = ValidatorIndex(0); + let cert = fake_assignment_cert(hash, validator_index); + let assignments = vec![(cert.clone(), 0u32)]; - let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); - send_message_from_peer(overseer, &peer, msg).await; + let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); + send_message_from_peer(overseer, &peer, msg).await; + provide_session( + overseer, + dummy_session_info_valid(1, &mut LocalKeystore::in_memory(), 1), + ) + .await; - // send an `Accept` message from the Approval Voting subsystem - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( - assignment, - claimed_candidates, - tx, - )) => { - assert_eq!(assignment.cert, cert.cert.into()); - assert_eq!(claimed_candidates, vec![0u32].try_into().unwrap()); - tx.send(AssignmentCheckResult::Accepted).unwrap(); - } - ); - expect_reputation_changes( - overseer, - &peer, - vec![COST_UNEXPECTED_MESSAGE, BENEFIT_VALID_MESSAGE_FIRST], - ) - .await; - assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); + // send an `Accept` message from the Approval Voting subsystem + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportAssignment( + assignment, + _, + )) => { + assert_eq!(assignment.assignment().cert, cert.cert.into()); + assert_eq!(assignment.candidate_indices(), &vec![0u32].try_into().unwrap()); + assert_eq!(assignment.tranche(), 0); + } + ); + expect_reputation_changes( + overseer, + &peer, + vec![COST_UNEXPECTED_MESSAGE, BENEFIT_VALID_MESSAGE_FIRST], + ) + .await; + assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); - virtual_overseer - }); + virtual_overseer + }, + ); } /// @@ -650,77 +843,88 @@ fn spam_attack_results_in_negative_reputation_change() { let peer_a = PeerId::random(); let hash_b = Hash::repeat_byte(0xBB); - let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - let peer = &peer_a; - setup_peer_with_view(overseer, peer, view![], ValidationVersion::V1).await; - - // new block `hash_b` with 20 candidates - let candidates_count = 20; - let meta = BlockApprovalMeta { - hash: hash_b, - parent_hash, - number: 2, - candidates: vec![Default::default(); candidates_count], - slot: 1.into(), - session: 1, - }; - - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - - // send 20 assignments related to `hash_b` - // to populate our knowledge - let assignments: Vec<_> = (0..candidates_count) - .map(|candidate_index| { - let validator_index = ValidatorIndex(candidate_index as u32); - let cert = fake_assignment_cert(hash_b, validator_index); - (cert, candidate_index as u32) - }) - .collect(); - - let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); - send_message_from_peer(overseer, peer, msg.clone()).await; - - for i in 0..candidates_count { - expect_reputation_change(overseer, peer, COST_UNEXPECTED_MESSAGE).await; + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state_without_reputation_delay(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + let peer = &peer_a; + setup_peer_with_view(overseer, peer, view![], ValidationVersion::V1).await; + + // new block `hash_b` with 20 candidates + let candidates_count = 20; + let meta = BlockApprovalMeta { + hash: hash_b, + parent_hash, + number: 2, + candidates: vec![Default::default(); candidates_count], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + // send 20 assignments related to `hash_b` + // to populate our knowledge + let assignments: Vec<_> = (0..candidates_count) + .map(|candidate_index| { + let validator_index = ValidatorIndex(candidate_index as u32); + let cert = fake_assignment_cert(hash_b, validator_index); + (cert, candidate_index as u32) + }) + .collect(); - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( - assignment, - claimed_candidate_index, - tx, - )) => { - assert_eq!(assignment, assignments[i].0.clone().into()); - assert_eq!(claimed_candidate_index, assignments[i].1.into()); - tx.send(AssignmentCheckResult::Accepted).unwrap(); + let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); + send_message_from_peer(overseer, peer, msg.clone()).await; + + for i in 0..candidates_count { + expect_reputation_change(overseer, peer, COST_UNEXPECTED_MESSAGE).await; + if i == 0 { + provide_session( + overseer, + dummy_session_info_valid(1, &mut LocalKeystore::in_memory(), 1), + ) + .await; } - ); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportAssignment( + assignment, + _, + )) => { + assert_eq!(assignment.assignment(), &assignments[i].0.clone().into()); + assert_eq!(assignment.candidate_indices(), &assignments[i].1.into()); + assert_eq!(assignment.tranche(), 0); + } + ); - expect_reputation_change(overseer, peer, BENEFIT_VALID_MESSAGE_FIRST).await; - } + expect_reputation_change(overseer, peer, BENEFIT_VALID_MESSAGE_FIRST).await; + } - // send a view update that removes block B from peer's view by bumping the finalized_number - overseer_send( - overseer, - ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerViewChange( - *peer, - View::with_finalized(2), - )), - ) - .await; + // send a view update that removes block B from peer's view by bumping the + // finalized_number + overseer_send( + overseer, + ApprovalDistributionMessage::NetworkBridgeUpdate( + NetworkBridgeEvent::PeerViewChange(*peer, View::with_finalized(2)), + ), + ) + .await; - // send the assignments again - send_message_from_peer(overseer, peer, msg.clone()).await; + // send the assignments again + send_message_from_peer(overseer, peer, msg.clone()).await; - // each of them will incur `COST_UNEXPECTED_MESSAGE`, not only the first one - for _ in 0..candidates_count { - expect_reputation_change(overseer, peer, COST_UNEXPECTED_MESSAGE).await; - expect_reputation_change(overseer, peer, BENEFIT_VALID_MESSAGE).await; - } - virtual_overseer - }); + // each of them will incur `COST_UNEXPECTED_MESSAGE`, not only the first one + for _ in 0..candidates_count { + expect_reputation_change(overseer, peer, COST_UNEXPECTED_MESSAGE).await; + expect_reputation_change(overseer, peer, BENEFIT_VALID_MESSAGE).await; + } + virtual_overseer + }, + ); } /// Imagine we send a message to peer A and peer B. @@ -736,86 +940,94 @@ fn peer_sending_us_the_same_we_just_sent_them_is_ok() { let peers = make_peers_and_authority_ids(8); let peer_a = peers.first().unwrap().0; - let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - let peer = &peer_a; - setup_peer_with_view(overseer, peer, view![], ValidationVersion::V1).await; - - let peers_with_optional_peer_id = peers - .iter() - .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) - .collect_vec(); - // Setup a topology where peer_a is neighbor to current node. - setup_gossip_topology( - overseer, - make_gossip_topology(1, &peers_with_optional_peer_id, &[0], &[2], 1), - ) - .await; + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state_without_reputation_delay(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + let peer = &peer_a; + setup_peer_with_view(overseer, peer, view![], ValidationVersion::V1).await; + + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + // Setup a topology where peer_a is neighbor to current node. + setup_gossip_topology( + overseer, + make_gossip_topology(1, &peers_with_optional_peer_id, &[0], &[2], 1), + ) + .await; - // new block `hash` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 1, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - - // import an assignment related to `hash` locally - let validator_index = ValidatorIndex(0); - let candidate_index = 0u32; - let cert = fake_assignment_cert(hash, validator_index); - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeAssignment( - cert.clone().into(), - candidate_index.into(), - ), - ) - .await; + // new block `hash` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + // import an assignment related to `hash` locally + let validator_index = ValidatorIndex(0); + let candidate_index = 0u32; + let cert = fake_assignment_cert(hash, validator_index); + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_index.into(), + ), + ) + .await; - // update peer view to include the hash - overseer_send( - overseer, - ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerViewChange( - *peer, - view![hash], - )), - ) - .await; + // update peer view to include the hash + overseer_send( + overseer, + ApprovalDistributionMessage::NetworkBridgeUpdate( + NetworkBridgeEvent::PeerViewChange(*peer, view![hash]), + ), + ) + .await; - // we should send them the assignment - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(assignments) - )) - )) => { - assert_eq!(peers.len(), 1); - assert_eq!(assignments.len(), 1); - } - ); + // we should send them the assignment + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers.len(), 1); + assert_eq!(assignments.len(), 1); + } + ); - // but if someone else is sending it the same assignment - // the peer could send us it as well - let assignments = vec![(cert, candidate_index)]; - let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments); - send_message_from_peer(overseer, peer, msg.clone()).await; + // but if someone else is sending it the same assignment + // the peer could send us it as well + let assignments = vec![(cert, candidate_index)]; + let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments); + send_message_from_peer(overseer, peer, msg.clone()).await; - assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "we should not punish the peer"); + assert!( + overseer.recv().timeout(TIMEOUT).await.is_none(), + "we should not punish the peer" + ); - // send the assignments again - send_message_from_peer(overseer, peer, msg).await; + // send the assignments again + send_message_from_peer(overseer, peer, msg).await; - // now we should - expect_reputation_change(overseer, peer, COST_DUPLICATE_MESSAGE).await; - virtual_overseer - }); + // now we should + expect_reputation_change(overseer, peer, COST_DUPLICATE_MESSAGE).await; + virtual_overseer + }, + ); } #[test] @@ -827,116 +1039,134 @@ fn import_approval_happy_path_v1_v2_peers() { let peer_c = peers.get(2).unwrap().0; let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); + let candidate_hash = polkadot_primitives::CandidateHash(Hash::repeat_byte(0xBB)); + + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state_without_reputation_delay(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // setup peers with V1 and V2 protocol versions + setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V1).await; + setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V3).await; + setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V1).await; + + let mut keystore = LocalKeystore::in_memory(); + let session = dummy_session_info_valid(1, &mut keystore, 1); + + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![(candidate_hash, 0.into(), 0.into()); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + // Set up a gossip topology, where a, b, and c are topology neighbors to the node. + setup_gossip_topology( + overseer, + make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), + ) + .await; - let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - // setup peers with V1 and V2 protocol versions - setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V1).await; - setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V3).await; - setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V1).await; - - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 1, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - - let peers_with_optional_peer_id = peers - .iter() - .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) - .collect_vec(); - // Set up a gossip topology, where a, b, and c are topology neighbors to the node. - setup_gossip_topology( - overseer, - make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), - ) - .await; - - // import an assignment related to `hash` locally - let validator_index = ValidatorIndex(0); - let candidate_index = 0u32; - let cert = fake_assignment_cert(hash, validator_index); - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeAssignment( - cert.clone().into(), - candidate_index.into(), - ), - ) - .await; + // import an assignment related to `hash` locally + let validator_index = ValidatorIndex(0); + let candidate_index = 0u32; + let cert = fake_assignment_cert(hash, validator_index); + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_index.into(), + ), + ) + .await; - // 1 peer is v1 - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(assignments) - )) - )) => { - assert_eq!(peers.len(), 1); - assert_eq!(assignments.len(), 1); - } - ); - - // 1 peer is v2 - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( - protocol_v3::ApprovalDistributionMessage::Assignments(assignments) - )) - )) => { - assert_eq!(peers.len(), 1); - assert_eq!(assignments.len(), 1); - } - ); - - // send the an approval from peer_b - let approval = IndirectSignedApprovalVoteV2 { - block_hash: hash, - candidate_indices: candidate_index.into(), - validator: validator_index, - signature: dummy_signature(), - }; - let msg: protocol_v3::ApprovalDistributionMessage = - protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer_v3(overseer, &peer_b, msg).await; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportApproval( - vote, - tx, - )) => { - assert_eq!(vote, approval); - tx.send(ApprovalCheckResult::Accepted).unwrap(); - } - ); - - expect_reputation_change(overseer, &peer_b, BENEFIT_VALID_MESSAGE_FIRST).await; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Approvals(approvals) - )) - )) => { - assert_eq!(peers.len(), 1); - assert_eq!(approvals.len(), 1); - } - ); - virtual_overseer - }); + // 1 peer is v1 + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers.len(), 1); + assert_eq!(assignments.len(), 1); + } + ); + + // 1 peer is v2 + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers.len(), 1); + assert_eq!(assignments.len(), 1); + } + ); + + // send the an approval from peer_b + let approval = IndirectSignedApprovalVoteV2 { + block_hash: hash, + candidate_indices: candidate_index.into(), + validator: validator_index, + signature: signature_for( + &keystore, + &session, + vec![candidate_hash], + validator_index, + ), + }; + let msg: protocol_v3::ApprovalDistributionMessage = + protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); + send_message_from_peer_v3(overseer, &peer_b, msg).await; + provide_session( + overseer, + dummy_session_info_valid(1, &mut LocalKeystore::in_memory(), 1), + ) + .await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportApproval( + vote, _, + )) => { + assert_eq!(Into::::into(vote), approval); + } + ); + + expect_reputation_change(overseer, &peer_b, BENEFIT_VALID_MESSAGE_FIRST).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Approvals(approvals) + )) + )) => { + assert_eq!(peers.len(), 1); + assert_eq!(approvals.len(), 1); + } + ); + virtual_overseer + }, + ); } // Test a v2 approval that signs multiple candidate is correctly processed. @@ -949,103 +1179,123 @@ fn import_approval_happy_path_v2() { let peer_c = peers.get(2).unwrap().0; let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); + let candidate_hash_first = polkadot_primitives::CandidateHash(Hash::repeat_byte(0xBB)); + let candidate_hash_second = polkadot_primitives::CandidateHash(Hash::repeat_byte(0xCC)); + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state_without_reputation_delay(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // setup peers with V2 protocol versions + setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V3).await; + setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V3).await; + setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V3).await; + let mut keystore = LocalKeystore::in_memory(); + let session = dummy_session_info_valid(1, &mut keystore, 1); + + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![ + (candidate_hash_first, 0.into(), 0.into()), + (candidate_hash_second, 1.into(), 1.into()), + ], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + // Set up a gossip topology, where a, b, and c are topology neighbors to the node. + setup_gossip_topology( + overseer, + make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), + ) + .await; - let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - // setup peers with V2 protocol versions - setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V3).await; - setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V3).await; - setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V3).await; - - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 1, - candidates: vec![Default::default(); 2], - slot: 1.into(), - session: 1, - }; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - - let peers_with_optional_peer_id = peers - .iter() - .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) - .collect_vec(); - // Set up a gossip topology, where a, b, and c are topology neighbors to the node. - setup_gossip_topology( - overseer, - make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), - ) - .await; + // import an assignment related to `hash` locally + let validator_index = ValidatorIndex(0); + let candidate_indices: CandidateBitfield = + vec![0 as CandidateIndex, 1 as CandidateIndex].try_into().unwrap(); + let candidate_bitfields = vec![CoreIndex(0), CoreIndex(1)].try_into().unwrap(); + let cert = fake_assignment_cert_v2(hash, validator_index, candidate_bitfields); + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_indices.clone(), + ), + ) + .await; - // import an assignment related to `hash` locally - let validator_index = ValidatorIndex(0); - let candidate_indices: CandidateBitfield = - vec![0 as CandidateIndex, 1 as CandidateIndex].try_into().unwrap(); - let candidate_bitfields = vec![CoreIndex(0), CoreIndex(1)].try_into().unwrap(); - let cert = fake_assignment_cert_v2(hash, validator_index, candidate_bitfields); - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeAssignment( - cert.clone().into(), - candidate_indices.clone(), - ), - ) - .await; + // 1 peer is v2 + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers.len(), 2); + assert_eq!(assignments.len(), 1); + } + ); - // 1 peer is v2 - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( - protocol_v3::ApprovalDistributionMessage::Assignments(assignments) - )) - )) => { - assert_eq!(peers.len(), 2); - assert_eq!(assignments.len(), 1); - } - ); - - // send the an approval from peer_b - let approval = IndirectSignedApprovalVoteV2 { - block_hash: hash, - candidate_indices, - validator: validator_index, - signature: dummy_signature(), - }; - let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer_v3(overseer, &peer_b, msg).await; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportApproval( - vote, - tx, - )) => { - assert_eq!(vote, approval); - tx.send(ApprovalCheckResult::Accepted).unwrap(); - } - ); - - expect_reputation_change(overseer, &peer_b, BENEFIT_VALID_MESSAGE_FIRST).await; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( - protocol_v3::ApprovalDistributionMessage::Approvals(approvals) - )) - )) => { - assert_eq!(peers.len(), 1); - assert_eq!(approvals.len(), 1); - } - ); - virtual_overseer - }); + // send the an approval from peer_b + let approval = IndirectSignedApprovalVoteV2 { + block_hash: hash, + candidate_indices, + validator: validator_index, + signature: signature_for( + &keystore, + &session, + vec![candidate_hash_first, candidate_hash_second], + validator_index, + ), + }; + let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); + send_message_from_peer_v3(overseer, &peer_b, msg).await; + provide_session( + overseer, + dummy_session_info_valid(1, &mut LocalKeystore::in_memory(), 1), + ) + .await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportApproval( + vote, _, + )) => { + assert_eq!(Into::::into(vote), approval); + } + ); + + expect_reputation_change(overseer, &peer_b, BENEFIT_VALID_MESSAGE_FIRST).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Approvals(approvals) + )) + )) => { + assert_eq!(peers.len(), 1); + assert_eq!(approvals.len(), 1); + } + ); + virtual_overseer + }, + ); } // Tests that votes that cover multiple assignments candidates are correctly processed on importing @@ -1059,187 +1309,203 @@ fn multiple_assignments_covered_with_one_approval_vote() { let peer_d = peers.get(4).unwrap().0; let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); + let candidate_hash_first = polkadot_primitives::CandidateHash(Hash::repeat_byte(0xBB)); + let candidate_hash_second = polkadot_primitives::CandidateHash(Hash::repeat_byte(0xCC)); + + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state_without_reputation_delay(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // setup peers with V2 protocol versions + setup_peer_with_view(overseer, &peer_a, view![hash], ValidationVersion::V3).await; + setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V3).await; + setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V3).await; + setup_peer_with_view(overseer, &peer_d, view![hash], ValidationVersion::V3).await; + + let mut keystore = LocalKeystore::in_memory(); + let session = dummy_session_info_valid(1, &mut keystore, 5); + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![ + (candidate_hash_first, 0.into(), 0.into()), + (candidate_hash_second, 1.into(), 1.into()), + ], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + // Set up a gossip topology, where a, b, and c, d are topology neighbors to the node. + setup_gossip_topology( + overseer, + make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), + ) + .await; - let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - // setup peers with V2 protocol versions - setup_peer_with_view(overseer, &peer_a, view![hash], ValidationVersion::V3).await; - setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V3).await; - setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V3).await; - setup_peer_with_view(overseer, &peer_d, view![hash], ValidationVersion::V3).await; - - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 1, - candidates: vec![Default::default(); 2], - slot: 1.into(), - session: 1, - }; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - - let peers_with_optional_peer_id = peers - .iter() - .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) - .collect_vec(); - // Set up a gossip topology, where a, b, and c, d are topology neighbors to the node. - setup_gossip_topology( - overseer, - make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), - ) - .await; + // import an assignment related to `hash` locally + let validator_index = ValidatorIndex(2); // peer_c is the originator + let candidate_indices: CandidateBitfield = + vec![0 as CandidateIndex, 1 as CandidateIndex].try_into().unwrap(); - // import an assignment related to `hash` locally - let validator_index = ValidatorIndex(2); // peer_c is the originator - let candidate_indices: CandidateBitfield = - vec![0 as CandidateIndex, 1 as CandidateIndex].try_into().unwrap(); + let core_bitfields = vec![CoreIndex(0)].try_into().unwrap(); + let cert = fake_assignment_cert_v2(hash, validator_index, core_bitfields); - let core_bitfields = vec![CoreIndex(0)].try_into().unwrap(); - let cert = fake_assignment_cert_v2(hash, validator_index, core_bitfields); + // send the candidate 0 assignment from peer_b + let assignment = IndirectAssignmentCertV2 { + block_hash: hash, + validator: validator_index, + cert: cert.cert, + }; + let msg = protocol_v3::ApprovalDistributionMessage::Assignments(vec![( + assignment, + (0 as CandidateIndex).into(), + )]); + send_message_from_peer_v3(overseer, &peer_d, msg).await; + provide_session(overseer, session.clone()).await; - // send the candidate 0 assignment from peer_b - let assignment = IndirectAssignmentCertV2 { - block_hash: hash, - validator: validator_index, - cert: cert.cert, - }; - let msg = protocol_v3::ApprovalDistributionMessage::Assignments(vec![( - assignment, - (0 as CandidateIndex).into(), - )]); - send_message_from_peer_v3(overseer, &peer_d, msg).await; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( - _, _, - tx, - )) => { - tx.send(AssignmentCheckResult::Accepted).unwrap(); - } - ); - expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE_FIRST).await; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( - protocol_v3::ApprovalDistributionMessage::Assignments(assignments) - )) - )) => { - assert!(peers.len() >= 2); - assert!(peers.contains(&peer_a)); - assert!(peers.contains(&peer_b)); - assert_eq!(assignments.len(), 1); - } - ); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportAssignment( + assignment, + _, + )) => { + assert_eq!(assignment.tranche(), 0); + } + ); + expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE_FIRST).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert!(peers.len() >= 2); + assert!(peers.contains(&peer_a)); + assert!(peers.contains(&peer_b)); + assert_eq!(assignments.len(), 1); + } + ); - let candidate_bitfields = vec![CoreIndex(1)].try_into().unwrap(); - let cert = fake_assignment_cert_v2(hash, validator_index, candidate_bitfields); + let candidate_bitfields = vec![CoreIndex(1)].try_into().unwrap(); + let cert = fake_assignment_cert_v2(hash, validator_index, candidate_bitfields); - // send the candidate 1 assignment from peer_c - let assignment = IndirectAssignmentCertV2 { - block_hash: hash, - validator: validator_index, - cert: cert.cert, - }; - let msg = protocol_v3::ApprovalDistributionMessage::Assignments(vec![( - assignment, - (1 as CandidateIndex).into(), - )]); - - send_message_from_peer_v3(overseer, &peer_c, msg).await; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( - _, _, - tx, - )) => { - tx.send(AssignmentCheckResult::Accepted).unwrap(); - } - ); - expect_reputation_change(overseer, &peer_c, BENEFIT_VALID_MESSAGE_FIRST).await; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( - protocol_v3::ApprovalDistributionMessage::Assignments(assignments) - )) - )) => { - assert!(peers.len() >= 2); - assert!(peers.contains(&peer_b)); - assert!(peers.contains(&peer_a)); - assert_eq!(assignments.len(), 1); - } - ); - - // send an approval from peer_b - let approval = IndirectSignedApprovalVoteV2 { - block_hash: hash, - candidate_indices, - validator: validator_index, - signature: dummy_signature(), - }; - let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer_v3(overseer, &peer_d, msg).await; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportApproval( - vote, - tx, - )) => { - assert_eq!(vote, approval); - tx.send(ApprovalCheckResult::Accepted).unwrap(); - } - ); - - expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE_FIRST).await; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( - protocol_v3::ApprovalDistributionMessage::Approvals(approvals) - )) - )) => { - assert!(peers.len() >= 2); - assert!(peers.contains(&peer_b)); - assert!(peers.contains(&peer_a)); - assert_eq!(approvals.len(), 1); - } - ); - for candidate_index in 0..1 { - let (tx_distribution, rx_distribution) = oneshot::channel(); - let mut candidates_requesting_signatures = HashSet::new(); - candidates_requesting_signatures.insert((hash, candidate_index)); - overseer_send( - overseer, - ApprovalDistributionMessage::GetApprovalSignatures( - candidates_requesting_signatures, - tx_distribution, + // send the candidate 1 assignment from peer_c + let assignment = IndirectAssignmentCertV2 { + block_hash: hash, + validator: validator_index, + cert: cert.cert, + }; + let msg = protocol_v3::ApprovalDistributionMessage::Assignments(vec![( + assignment, + (1 as CandidateIndex).into(), + )]); + + send_message_from_peer_v3(overseer, &peer_c, msg).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportAssignment( + assignment, _, + )) => { + assert_eq!(assignment.tranche(), 0); + } + ); + expect_reputation_change(overseer, &peer_c, BENEFIT_VALID_MESSAGE_FIRST).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert!(peers.len() >= 2); + assert!(peers.contains(&peer_b)); + assert!(peers.contains(&peer_a)); + assert_eq!(assignments.len(), 1); + } + ); + + // send an approval from peer_b + let approval = IndirectSignedApprovalVoteV2 { + block_hash: hash, + candidate_indices, + validator: validator_index, + signature: signature_for( + &keystore, + &session, + vec![candidate_hash_first, candidate_hash_second], + validator_index, ), - ) - .await; - let signatures = rx_distribution.await.unwrap(); + }; + let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); + send_message_from_peer_v3(overseer, &peer_d, msg).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportApproval( + vote, _, + )) => { + assert_eq!(Into::::into(vote), approval); + } + ); + + expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE_FIRST).await; - assert_eq!(signatures.len(), 1); - for (signing_validator, signature) in signatures { - assert_eq!(validator_index, signing_validator); - assert_eq!(signature.0, hash); - assert_eq!(signature.2, approval.signature); - assert_eq!(signature.1, vec![0, 1]); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Approvals(approvals) + )) + )) => { + assert!(peers.len() >= 2); + assert!(peers.contains(&peer_b)); + assert!(peers.contains(&peer_a)); + assert_eq!(approvals.len(), 1); + } + ); + for candidate_index in 0..1 { + let (tx_distribution, rx_distribution) = oneshot::channel(); + let mut candidates_requesting_signatures = HashSet::new(); + candidates_requesting_signatures.insert((hash, candidate_index)); + overseer_send( + overseer, + ApprovalDistributionMessage::GetApprovalSignatures( + candidates_requesting_signatures, + tx_distribution, + ), + ) + .await; + let signatures = rx_distribution.await.unwrap(); + + assert_eq!(signatures.len(), 1); + for (signing_validator, signature) in signatures { + assert_eq!(validator_index, signing_validator); + assert_eq!(signature.0, hash); + assert_eq!(signature.2, approval.signature); + assert_eq!(signature.1, vec![0, 1]); + } } - } - virtual_overseer - }); + virtual_overseer + }, + ); } // Tests that votes that cover multiple assignments candidates are correctly processed when unify @@ -1253,182 +1519,196 @@ fn unify_with_peer_multiple_assignments_covered_with_one_approval_vote() { let peer_d = peers.get(4).unwrap().0; let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); + let candidate_hash_first = polkadot_primitives::CandidateHash(Hash::repeat_byte(0xBB)); + let candidate_hash_second = polkadot_primitives::CandidateHash(Hash::repeat_byte(0xCC)); + + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state_without_reputation_delay(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + setup_peer_with_view(overseer, &peer_d, view![hash], ValidationVersion::V3).await; + let mut keystore = LocalKeystore::in_memory(); + let session = dummy_session_info_valid(1, &mut keystore, 5); + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![ + (candidate_hash_first, 0.into(), 0.into()), + (candidate_hash_second, 1.into(), 1.into()), + ], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + // Set up a gossip topology, where a, b, and c, d are topology neighbors to the node. + setup_gossip_topology( + overseer, + make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), + ) + .await; - let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - setup_peer_with_view(overseer, &peer_d, view![hash], ValidationVersion::V3).await; - - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 1, - candidates: vec![Default::default(); 2], - slot: 1.into(), - session: 1, - }; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - - let peers_with_optional_peer_id = peers - .iter() - .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) - .collect_vec(); - // Set up a gossip topology, where a, b, and c, d are topology neighbors to the node. - setup_gossip_topology( - overseer, - make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), - ) - .await; + // import an assignment related to `hash` locally + let validator_index = ValidatorIndex(2); // peer_c is the originator + let candidate_indices: CandidateBitfield = + vec![0 as CandidateIndex, 1 as CandidateIndex].try_into().unwrap(); - // import an assignment related to `hash` locally - let validator_index = ValidatorIndex(2); // peer_c is the originator - let candidate_indices: CandidateBitfield = - vec![0 as CandidateIndex, 1 as CandidateIndex].try_into().unwrap(); + let core_bitfields = vec![CoreIndex(0)].try_into().unwrap(); + let cert = fake_assignment_cert_v2(hash, validator_index, core_bitfields); - let core_bitfields = vec![CoreIndex(0)].try_into().unwrap(); - let cert = fake_assignment_cert_v2(hash, validator_index, core_bitfields); + // send the candidate 0 assignment from peer_b + let assignment = IndirectAssignmentCertV2 { + block_hash: hash, + validator: validator_index, + cert: cert.cert, + }; + let msg = protocol_v3::ApprovalDistributionMessage::Assignments(vec![( + assignment, + (0 as CandidateIndex).into(), + )]); + send_message_from_peer_v3(overseer, &peer_d, msg).await; + provide_session(overseer, session.clone()).await; - // send the candidate 0 assignment from peer_b - let assignment = IndirectAssignmentCertV2 { - block_hash: hash, - validator: validator_index, - cert: cert.cert, - }; - let msg = protocol_v3::ApprovalDistributionMessage::Assignments(vec![( - assignment, - (0 as CandidateIndex).into(), - )]); - send_message_from_peer_v3(overseer, &peer_d, msg).await; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( - _, _, - tx, - )) => { - tx.send(AssignmentCheckResult::Accepted).unwrap(); - } - ); - expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE_FIRST).await; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportAssignment( + assignment, _, + )) => { + assert_eq!(assignment.tranche(), 0); + } + ); + expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE_FIRST).await; - let candidate_bitfields = vec![CoreIndex(1)].try_into().unwrap(); - let cert = fake_assignment_cert_v2(hash, validator_index, candidate_bitfields); + let candidate_bitfields = vec![CoreIndex(1)].try_into().unwrap(); + let cert = fake_assignment_cert_v2(hash, validator_index, candidate_bitfields); - // send the candidate 1 assignment from peer_c - let assignment = IndirectAssignmentCertV2 { - block_hash: hash, - validator: validator_index, - cert: cert.cert, - }; - let msg = protocol_v3::ApprovalDistributionMessage::Assignments(vec![( - assignment, - (1 as CandidateIndex).into(), - )]); - - send_message_from_peer_v3(overseer, &peer_d, msg).await; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( - _, _, - tx, - )) => { - tx.send(AssignmentCheckResult::Accepted).unwrap(); - } - ); - expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE_FIRST).await; - - // send an approval from peer_b - let approval = IndirectSignedApprovalVoteV2 { - block_hash: hash, - candidate_indices, - validator: validator_index, - signature: dummy_signature(), - }; - let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer_v3(overseer, &peer_d, msg).await; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportApproval( - vote, - tx, - )) => { - assert_eq!(vote, approval); - tx.send(ApprovalCheckResult::Accepted).unwrap(); - } - ); - - expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE_FIRST).await; - - // setup peers with V2 protocol versions - setup_peer_with_view(overseer, &peer_a, view![hash], ValidationVersion::V3).await; - setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V3).await; - let mut expected_peers_assignments = vec![peer_a, peer_b]; - let mut expected_peers_approvals = vec![peer_a, peer_b]; - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( - protocol_v3::ApprovalDistributionMessage::Assignments(assignments) - )) - )) => { - assert!(peers.len() == 1); - assert!(expected_peers_assignments.contains(peers.first().unwrap())); - expected_peers_assignments.retain(|peer| peer != peers.first().unwrap()); - assert_eq!(assignments.len(), 2); - } - ); - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( - protocol_v3::ApprovalDistributionMessage::Approvals(approvals) - )) - )) => { - assert!(peers.len() == 1); - assert!(expected_peers_approvals.contains(peers.first().unwrap())); - expected_peers_approvals.retain(|peer| peer != peers.first().unwrap()); - assert_eq!(approvals.len(), 1); - } - ); - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( - protocol_v3::ApprovalDistributionMessage::Assignments(assignments) - )) - )) => { - assert!(peers.len() == 1); - assert!(expected_peers_assignments.contains(peers.first().unwrap())); - expected_peers_assignments.retain(|peer| peer != peers.first().unwrap()); - assert_eq!(assignments.len(), 2); - } - ); - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( - protocol_v3::ApprovalDistributionMessage::Approvals(approvals) - )) - )) => { - assert!(peers.len() == 1); - assert!(expected_peers_approvals.contains(peers.first().unwrap())); - expected_peers_approvals.retain(|peer| peer != peers.first().unwrap()); - assert_eq!(approvals.len(), 1); - } - ); + // send the candidate 1 assignment from peer_c + let assignment = IndirectAssignmentCertV2 { + block_hash: hash, + validator: validator_index, + cert: cert.cert, + }; + let msg = protocol_v3::ApprovalDistributionMessage::Assignments(vec![( + assignment, + (1 as CandidateIndex).into(), + )]); - virtual_overseer - }); + send_message_from_peer_v3(overseer, &peer_d, msg).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportAssignment( + assignment, _, + )) => { + assert_eq!(assignment.tranche(), 0); + } + ); + expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE_FIRST).await; + + // send an approval from peer_b + let approval = IndirectSignedApprovalVoteV2 { + block_hash: hash, + candidate_indices, + validator: validator_index, + signature: signature_for( + &keystore, + &session, + vec![candidate_hash_first, candidate_hash_second], + validator_index, + ), + }; + let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); + send_message_from_peer_v3(overseer, &peer_d, msg).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportApproval( + vote, _, + )) => { + assert_eq!(Into::::into(vote), approval); + } + ); + + expect_reputation_change(overseer, &peer_d, BENEFIT_VALID_MESSAGE_FIRST).await; + + // setup peers with V2 protocol versions + setup_peer_with_view(overseer, &peer_a, view![hash], ValidationVersion::V3).await; + setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V3).await; + let mut expected_peers_assignments = vec![peer_a, peer_b]; + let mut expected_peers_approvals = vec![peer_a, peer_b]; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert!(peers.len() == 1); + assert!(expected_peers_assignments.contains(peers.first().unwrap())); + expected_peers_assignments.retain(|peer| peer != peers.first().unwrap()); + assert_eq!(assignments.len(), 2); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Approvals(approvals) + )) + )) => { + assert!(peers.len() == 1); + assert!(expected_peers_approvals.contains(peers.first().unwrap())); + expected_peers_approvals.retain(|peer| peer != peers.first().unwrap()); + assert_eq!(approvals.len(), 1); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert!(peers.len() == 1); + assert!(expected_peers_assignments.contains(peers.first().unwrap())); + expected_peers_assignments.retain(|peer| peer != peers.first().unwrap()); + assert_eq!(assignments.len(), 2); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Approvals(approvals) + )) + )) => { + assert!(peers.len() == 1); + assert!(expected_peers_approvals.contains(peers.first().unwrap())); + expected_peers_approvals.retain(|peer| peer != peers.first().unwrap()); + assert_eq!(approvals.len(), 1); + } + ); + + virtual_overseer + }, + ); } #[test] @@ -1437,79 +1717,87 @@ fn import_approval_bad() { let peer_b = PeerId::random(); let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); + let candidate_hash = polkadot_primitives::CandidateHash(Hash::repeat_byte(0xBB)); + + let diff_candidate_hash = polkadot_primitives::CandidateHash(Hash::repeat_byte(0xCC)); + + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state_without_reputation_delay(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // setup peers + setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V1).await; + setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V1).await; + let mut keystore = LocalKeystore::in_memory(); + let session = dummy_session_info_valid(1, &mut keystore, 1); + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![(candidate_hash, 0.into(), 0.into()); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; - let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - // setup peers - setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V1).await; - setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V1).await; - - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 1, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - - let validator_index = ValidatorIndex(0); - let candidate_index = 0u32; - let cert = fake_assignment_cert(hash, validator_index); - - // send the an approval from peer_b, we don't have an assignment yet - let approval = IndirectSignedApprovalVoteV2 { - block_hash: hash, - candidate_indices: candidate_index.into(), - validator: validator_index, - signature: dummy_signature(), - }; - let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer_v3(overseer, &peer_b, msg).await; + let validator_index = ValidatorIndex(0); + let candidate_index = 0u32; + let cert = fake_assignment_cert(hash, validator_index); - expect_reputation_change(overseer, &peer_b, COST_UNEXPECTED_MESSAGE).await; + // Sign a different candidate hash. + let payload = + ApprovalVoteMultipleCandidates(&vec![diff_candidate_hash]).signing_payload(1); + let sign_key = session.validators.get(ValidatorIndex(0)).unwrap().clone(); + let signature = keystore + .sr25519_sign(ValidatorId::ID, &sign_key.into(), &payload[..]) + .unwrap() + .unwrap(); + + // send the an approval from peer_b, we don't have an assignment yet + let approval = IndirectSignedApprovalVoteV2 { + block_hash: hash, + candidate_indices: candidate_index.into(), + validator: validator_index, + signature: signature.into(), + }; + let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); + send_message_from_peer_v3(overseer, &peer_b, msg).await; - // now import an assignment from peer_b - let assignments = vec![(cert.clone(), candidate_index)]; - let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments); - send_message_from_peer(overseer, &peer_b, msg).await; + expect_reputation_change(overseer, &peer_b, COST_UNEXPECTED_MESSAGE).await; - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( - assignment, - i, - tx, - )) => { - assert_eq!(assignment, cert.into()); - assert_eq!(i, candidate_index.into()); - tx.send(AssignmentCheckResult::Accepted).unwrap(); - } - ); - - expect_reputation_change(overseer, &peer_b, BENEFIT_VALID_MESSAGE_FIRST).await; - - // and try again - let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer_v3(overseer, &peer_b, msg).await; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportApproval( - vote, - tx, - )) => { - assert_eq!(vote, approval); - tx.send(ApprovalCheckResult::Bad(ApprovalCheckError::UnknownBlock(hash))).unwrap(); - } - ); + // now import an assignment from peer_b + let assignments = vec![(cert.clone(), candidate_index)]; + let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments); + send_message_from_peer(overseer, &peer_b, msg).await; + provide_session(overseer, session.clone()).await; - expect_reputation_change(overseer, &peer_b, COST_INVALID_MESSAGE).await; - virtual_overseer - }); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportAssignment( + assignment, + _, + )) => { + assert_eq!(assignment.assignment(), &cert.into()); + assert_eq!(assignment.candidate_indices(), &candidate_index.into()); + assert_eq!(assignment.tranche(), 0); + } + ); + + expect_reputation_change(overseer, &peer_b, BENEFIT_VALID_MESSAGE_FIRST).await; + + // and try again + let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); + send_message_from_peer_v3(overseer, &peer_b, msg).await; + + expect_reputation_change(overseer, &peer_b, COST_INVALID_MESSAGE).await; + virtual_overseer + }, + ); } /// make sure we clean up the state on block finalized @@ -1520,38 +1808,46 @@ fn update_our_view() { let hash_b = Hash::repeat_byte(0xBB); let hash_c = Hash::repeat_byte(0xCC); - let state = test_harness(State::default(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - // new block `hash_a` with 1 candidates - let meta_a = BlockApprovalMeta { - hash: hash_a, - parent_hash, - number: 1, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; - let meta_b = BlockApprovalMeta { - hash: hash_b, - parent_hash: hash_a, - number: 2, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; - let meta_c = BlockApprovalMeta { - hash: hash_c, - parent_hash: hash_b, - number: 3, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; - - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta_a, meta_b, meta_c]); - overseer_send(overseer, msg).await; - virtual_overseer - }); + let state = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + State::default(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // new block `hash_a` with 1 candidates + let meta_a = BlockApprovalMeta { + hash: hash_a, + parent_hash, + number: 1, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let meta_b = BlockApprovalMeta { + hash: hash_b, + parent_hash: hash_a, + number: 2, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let meta_c = BlockApprovalMeta { + hash: hash_c, + parent_hash: hash_b, + number: 3, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta_a, meta_b, meta_c]); + overseer_send(overseer, msg).await; + virtual_overseer + }, + ); assert!(state.blocks_by_number.get(&1).is_some()); assert!(state.blocks_by_number.get(&2).is_some()); @@ -1560,12 +1856,17 @@ fn update_our_view() { assert!(state.blocks.get(&hash_b).is_some()); assert!(state.blocks.get(&hash_c).is_some()); - let state = test_harness(state, |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - // finalize a block - overseer_signal_block_finalized(overseer, 2).await; - virtual_overseer - }); + let state = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state, + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // finalize a block + overseer_signal_block_finalized(overseer, 2).await; + virtual_overseer + }, + ); assert!(state.blocks_by_number.get(&1).is_none()); assert!(state.blocks_by_number.get(&2).is_none()); @@ -1574,12 +1875,17 @@ fn update_our_view() { assert!(state.blocks.get(&hash_b).is_none()); assert!(state.blocks.get(&hash_c).is_some()); - let state = test_harness(state, |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - // finalize a very high block - overseer_signal_block_finalized(overseer, 4_000_000_000).await; - virtual_overseer - }); + let state = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state, + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // finalize a very high block + overseer_signal_block_finalized(overseer, 4_000_000_000).await; + virtual_overseer + }, + ); assert!(state.blocks_by_number.get(&3).is_none()); assert!(state.blocks.get(&hash_c).is_none()); @@ -1597,81 +1903,89 @@ fn update_peer_view() { let peer_a = peers.first().unwrap().0; let peer = &peer_a; - let state = test_harness(State::default(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - // new block `hash_a` with 1 candidates - let meta_a = BlockApprovalMeta { - hash: hash_a, - parent_hash, - number: 1, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; - let meta_b = BlockApprovalMeta { - hash: hash_b, - parent_hash: hash_a, - number: 2, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; - let meta_c = BlockApprovalMeta { - hash: hash_c, - parent_hash: hash_b, - number: 3, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; + let state = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + State::default(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // new block `hash_a` with 1 candidates + let meta_a = BlockApprovalMeta { + hash: hash_a, + parent_hash, + number: 1, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let meta_b = BlockApprovalMeta { + hash: hash_b, + parent_hash: hash_a, + number: 2, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let meta_c = BlockApprovalMeta { + hash: hash_c, + parent_hash: hash_b, + number: 3, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta_a, meta_b, meta_c]); + overseer_send(overseer, msg).await; + + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + // Setup a topology where peer_a is neighbor to current node. + setup_gossip_topology( + overseer, + make_gossip_topology(1, &peers_with_optional_peer_id, &[0], &[2], 1), + ) + .await; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta_a, meta_b, meta_c]); - overseer_send(overseer, msg).await; - - let peers_with_optional_peer_id = peers - .iter() - .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) - .collect_vec(); - // Setup a topology where peer_a is neighbor to current node. - setup_gossip_topology( - overseer, - make_gossip_topology(1, &peers_with_optional_peer_id, &[0], &[2], 1), - ) - .await; + let cert_a = fake_assignment_cert(hash_a, ValidatorIndex(0)); + let cert_b = fake_assignment_cert(hash_b, ValidatorIndex(0)); - let cert_a = fake_assignment_cert(hash_a, ValidatorIndex(0)); - let cert_b = fake_assignment_cert(hash_b, ValidatorIndex(0)); + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment(cert_a.into(), 0.into()), + ) + .await; - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeAssignment(cert_a.into(), 0.into()), - ) - .await; + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment(cert_b.into(), 0.into()), + ) + .await; - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeAssignment(cert_b.into(), 0.into()), - ) - .await; + // connect a peer + setup_peer_with_view(overseer, peer, view![hash_a], ValidationVersion::V1).await; - // connect a peer - setup_peer_with_view(overseer, peer, view![hash_a], ValidationVersion::V1).await; - - // we should send relevant assignments to the peer - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(assignments) - )) - )) => { - assert_eq!(peers.len(), 1); - assert_eq!(assignments.len(), 1); - } - ); - virtual_overseer - }); + // we should send relevant assignments to the peer + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers.len(), 1); + assert_eq!(assignments.len(), 1); + } + ); + virtual_overseer + }, + ); assert_eq!(state.peer_views.get(peer).map(|v| v.view.finalized_number), Some(0)); assert_eq!( @@ -1688,42 +2002,49 @@ fn update_peer_view() { 1, ); - let state = test_harness(state, |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - // update peer's view - overseer_send( - overseer, - ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerViewChange( - *peer, - View::new(vec![hash_b, hash_c, hash_d], 2), - )), - ) - .await; + let state = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state, + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // update peer's view + overseer_send( + overseer, + ApprovalDistributionMessage::NetworkBridgeUpdate( + NetworkBridgeEvent::PeerViewChange( + *peer, + View::new(vec![hash_b, hash_c, hash_d], 2), + ), + ), + ) + .await; - let cert_c = fake_assignment_cert(hash_c, ValidatorIndex(0)); + let cert_c = fake_assignment_cert(hash_c, ValidatorIndex(0)); - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeAssignment(cert_c.clone().into(), 0.into()), - ) - .await; + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment(cert_c.clone().into(), 0.into()), + ) + .await; - // we should send relevant assignments to the peer - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(assignments) - )) - )) => { - assert_eq!(peers.len(), 1); - assert_eq!(assignments.len(), 1); - assert_eq!(assignments[0].0, cert_c); - } - ); - virtual_overseer - }); + // we should send relevant assignments to the peer + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers.len(), 1); + assert_eq!(assignments.len(), 1); + assert_eq!(assignments[0].0, cert_c); + } + ); + virtual_overseer + }, + ); assert_eq!(state.peer_views.get(peer).map(|v| v.view.finalized_number), Some(2)); assert_eq!( @@ -1741,19 +2062,26 @@ fn update_peer_view() { ); let finalized_number = 4_000_000_000; - let state = test_harness(state, |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - // update peer's view - overseer_send( - overseer, - ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerViewChange( - *peer, - View::with_finalized(finalized_number), - )), - ) - .await; - virtual_overseer - }); + let state = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state, + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // update peer's view + overseer_send( + overseer, + ApprovalDistributionMessage::NetworkBridgeUpdate( + NetworkBridgeEvent::PeerViewChange( + *peer, + View::with_finalized(finalized_number), + ), + ), + ) + .await; + virtual_overseer + }, + ); assert_eq!(state.peer_views.get(peer).map(|v| v.view.finalized_number), Some(finalized_number)); assert!(state.blocks.get(&hash_c).unwrap().known_by.get(peer).is_none()); @@ -1776,164 +2104,176 @@ fn update_peer_authority_id() { // Y neighbour, we simulate that PeerId is not known in the beginning. let neighbour_y = peers.get(neighbour_y_index).unwrap().0; - let _state = test_harness(State::default(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - // new block `hash_a` with 1 candidates - let meta_a = BlockApprovalMeta { - hash: hash_a, - parent_hash, - number: 1, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; - let meta_b = BlockApprovalMeta { - hash: hash_b, - parent_hash: hash_a, - number: 2, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; - let meta_c = BlockApprovalMeta { - hash: hash_c, - parent_hash: hash_b, - number: 3, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; + let _state = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + State::default(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // new block `hash_a` with 1 candidates + let meta_a = BlockApprovalMeta { + hash: hash_a, + parent_hash, + number: 1, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let meta_b = BlockApprovalMeta { + hash: hash_b, + parent_hash: hash_a, + number: 2, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let meta_c = BlockApprovalMeta { + hash: hash_c, + parent_hash: hash_b, + number: 3, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta_a, meta_b, meta_c]); + overseer_send(overseer, msg).await; + + let peers_with_optional_peer_id = peers + .iter() + .enumerate() + .map(|(index, (peer_id, authority))| { + (if index == 0 { None } else { Some(*peer_id) }, authority.clone()) + }) + .collect_vec(); + + // Setup a topology where peer_a is neighbor to current node. + setup_gossip_topology( + overseer, + make_gossip_topology( + 1, + &peers_with_optional_peer_id, + &[neighbour_x_index], + &[neighbour_y_index], + local_index, + ), + ) + .await; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta_a, meta_b, meta_c]); - overseer_send(overseer, msg).await; + let cert_a = fake_assignment_cert(hash_a, ValidatorIndex(local_index as u32)); + let cert_b = fake_assignment_cert(hash_b, ValidatorIndex(local_index as u32)); - let peers_with_optional_peer_id = peers - .iter() - .enumerate() - .map(|(index, (peer_id, authority))| { - (if index == 0 { None } else { Some(*peer_id) }, authority.clone()) - }) - .collect_vec(); - - // Setup a topology where peer_a is neighbor to current node. - setup_gossip_topology( - overseer, - make_gossip_topology( - 1, - &peers_with_optional_peer_id, - &[neighbour_x_index], - &[neighbour_y_index], - local_index, - ), - ) - .await; + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment(cert_a.into(), 0.into()), + ) + .await; - let cert_a = fake_assignment_cert(hash_a, ValidatorIndex(local_index as u32)); - let cert_b = fake_assignment_cert(hash_b, ValidatorIndex(local_index as u32)); + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment(cert_b.into(), 0.into()), + ) + .await; - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeAssignment(cert_a.into(), 0.into()), - ) - .await; + // connect a peer + setup_peer_with_view(overseer, &neighbour_x, view![hash_a], ValidationVersion::V1) + .await; + setup_peer_with_view(overseer, &neighbour_y, view![hash_a], ValidationVersion::V1) + .await; - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeAssignment(cert_b.into(), 0.into()), - ) - .await; + setup_peer_with_view(overseer, &neighbour_x, view![hash_b], ValidationVersion::V1) + .await; + setup_peer_with_view(overseer, &neighbour_y, view![hash_b], ValidationVersion::V1) + .await; - // connect a peer - setup_peer_with_view(overseer, &neighbour_x, view![hash_a], ValidationVersion::V1).await; - setup_peer_with_view(overseer, &neighbour_y, view![hash_a], ValidationVersion::V1).await; - - setup_peer_with_view(overseer, &neighbour_x, view![hash_b], ValidationVersion::V1).await; - setup_peer_with_view(overseer, &neighbour_y, view![hash_b], ValidationVersion::V1).await; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(assignments) - )) - )) => { - assert_eq!(peers.len(), 1); - assert_eq!(assignments.len(), 1); - assert_eq!(peers.get(0), Some(&neighbour_y)); - } - ); - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(assignments) - )) - )) => { - assert_eq!(peers.len(), 1); - assert_eq!(assignments.len(), 1); - assert_eq!(peers.get(0), Some(&neighbour_y)); - } - ); - - overseer_send( - overseer, - ApprovalDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::UpdatedAuthorityIds( - peers[neighbour_x_index].0, - [peers[neighbour_x_index].1.clone()].into_iter().collect(), + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers.len(), 1); + assert_eq!(assignments.len(), 1); + assert_eq!(peers.get(0), Some(&neighbour_y)); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers.len(), 1); + assert_eq!(assignments.len(), 1); + assert_eq!(peers.get(0), Some(&neighbour_y)); + } + ); + + overseer_send( + overseer, + ApprovalDistributionMessage::NetworkBridgeUpdate( + NetworkBridgeEvent::UpdatedAuthorityIds( + peers[neighbour_x_index].0, + [peers[neighbour_x_index].1.clone()].into_iter().collect(), + ), ), - ), - ) - .await; + ) + .await; - // we should send relevant assignments to the peer, after we found it's peer id. - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(assignments) - )) - )) => { - gum::info!(target: LOG_TARGET, ?peers, ?assignments); - assert_eq!(peers.len(), 1); - assert_eq!(assignments.len(), 2); - assert_eq!(assignments.get(0).unwrap().0.block_hash, hash_a); - assert_eq!(assignments.get(1).unwrap().0.block_hash, hash_b); - assert_eq!(peers.get(0), Some(&neighbour_x)); - } - ); - - overseer_send( - overseer, - ApprovalDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::UpdatedAuthorityIds( - peers[neighbour_y_index].0, - [peers[neighbour_y_index].1.clone()].into_iter().collect(), + // we should send relevant assignments to the peer, after we found it's peer id. + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + gum::info!(target: LOG_TARGET, ?peers, ?assignments); + assert_eq!(peers.len(), 1); + assert_eq!(assignments.len(), 2); + assert_eq!(assignments.get(0).unwrap().0.block_hash, hash_a); + assert_eq!(assignments.get(1).unwrap().0.block_hash, hash_b); + assert_eq!(peers.get(0), Some(&neighbour_x)); + } + ); + + overseer_send( + overseer, + ApprovalDistributionMessage::NetworkBridgeUpdate( + NetworkBridgeEvent::UpdatedAuthorityIds( + peers[neighbour_y_index].0, + [peers[neighbour_y_index].1.clone()].into_iter().collect(), + ), ), - ), - ) - .await; - overseer_send( - overseer, - ApprovalDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::UpdatedAuthorityIds( - peers[neighbour_x_index].0, - [peers[neighbour_x_index].1.clone()].into_iter().collect(), + ) + .await; + overseer_send( + overseer, + ApprovalDistributionMessage::NetworkBridgeUpdate( + NetworkBridgeEvent::UpdatedAuthorityIds( + peers[neighbour_x_index].0, + [peers[neighbour_x_index].1.clone()].into_iter().collect(), + ), ), - ), - ) - .await; - assert!( - overseer.recv().timeout(TIMEOUT).await.is_none(), - "no message should be sent peers are already known" - ); + ) + .await; + assert!( + overseer.recv().timeout(TIMEOUT).await.is_none(), + "no message should be sent peers are already known" + ); - virtual_overseer - }); + virtual_overseer + }, + ); } /// E.g. if someone copies the keys... @@ -1942,89 +2282,105 @@ fn import_remotely_then_locally() { let peer_a = PeerId::random(); let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); + let candidate_hash = polkadot_primitives::CandidateHash(Hash::repeat_byte(0xBB)); let peer = &peer_a; - let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - // setup the peer - setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; - - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 1, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - - // import the assignment remotely first - let validator_index = ValidatorIndex(0); - let candidate_index = 0u32; - let cert = fake_assignment_cert(hash, validator_index); - let assignments = vec![(cert.clone(), candidate_index)]; - let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); - send_message_from_peer(overseer, peer, msg).await; - - // send an `Accept` message from the Approval Voting subsystem - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( - assignment, - i, - tx, - )) => { - assert_eq!(assignment, cert.clone().into()); - assert_eq!(i, candidate_index.into()); - tx.send(AssignmentCheckResult::Accepted).unwrap(); - } - ); + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state_without_reputation_delay(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // setup the peer + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; + let mut keystore = LocalKeystore::in_memory(); + + let session = dummy_session_info_valid(1, &mut keystore, 1); + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![(candidate_hash, 0.into(), 0.into()); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + + let payload = ApprovalVoteMultipleCandidates(&vec![candidate_hash]).signing_payload(1); + let sign_key = session.validators.get(ValidatorIndex(0)).unwrap().clone(); + let signature = keystore + .sr25519_sign(ValidatorId::ID, &sign_key.into(), &payload[..]) + .unwrap() + .unwrap(); + + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + // import the assignment remotely first + let validator_index = ValidatorIndex(0); + let candidate_index = 0u32; + let cert = fake_assignment_cert(hash, validator_index); + let assignments = vec![(cert.clone(), candidate_index)]; + let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); + send_message_from_peer(overseer, peer, msg).await; + provide_session(overseer, session.clone()).await; + + // send an `Accept` message from the Approval Voting subsystem + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportAssignment( + assignment, + _, + )) => { + assert_eq!(assignment.assignment(), &cert.clone().into()); + assert_eq!(assignment.candidate_indices(), &candidate_index.into()); + assert_eq!(assignment.tranche(), 0); + } + ); - expect_reputation_change(overseer, peer, BENEFIT_VALID_MESSAGE_FIRST).await; + expect_reputation_change(overseer, peer, BENEFIT_VALID_MESSAGE_FIRST).await; - // import the same assignment locally - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeAssignment( - cert.clone().into(), - candidate_index.into(), - ), - ) - .await; + // import the same assignment locally + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_index.into(), + ), + ) + .await; - assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); + assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); - // send the approval remotely - let approval = IndirectSignedApprovalVoteV2 { - block_hash: hash, - candidate_indices: candidate_index.into(), - validator: validator_index, - signature: dummy_signature(), - }; - let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer_v3(overseer, peer, msg).await; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportApproval( - vote, - tx, - )) => { - assert_eq!(vote, approval); - tx.send(ApprovalCheckResult::Accepted).unwrap(); - } - ); - expect_reputation_change(overseer, peer, BENEFIT_VALID_MESSAGE_FIRST).await; + // send the approval remotely + let approval = IndirectSignedApprovalVoteV2 { + block_hash: hash, + candidate_indices: candidate_index.into(), + validator: validator_index, + signature: signature.into(), + }; + let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); + send_message_from_peer_v3(overseer, peer, msg).await; - // import the same approval locally - overseer_send(overseer, ApprovalDistributionMessage::DistributeApproval(approval)).await; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportApproval( + vote, _, + )) => { + assert_eq!(Into::::into(vote), approval); + } + ); + expect_reputation_change(overseer, peer, BENEFIT_VALID_MESSAGE_FIRST).await; - assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); - virtual_overseer - }); + // import the same approval locally + overseer_send(overseer, ApprovalDistributionMessage::DistributeApproval(approval)) + .await; + + assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); + virtual_overseer + }, + ); } #[test] @@ -2035,94 +2391,100 @@ fn sends_assignments_even_when_state_is_approved() { let hash = Hash::repeat_byte(0xAA); let peer = &peer_a; - let _ = test_harness(State::default(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + State::default(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + // Setup a topology where peer_a is neighbor to current node. + setup_gossip_topology( + overseer, + make_gossip_topology(1, &peers_with_optional_peer_id, &[0], &[2], 1), + ) + .await; - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 1, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - - let peers_with_optional_peer_id = peers - .iter() - .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) - .collect_vec(); - // Setup a topology where peer_a is neighbor to current node. - setup_gossip_topology( - overseer, - make_gossip_topology(1, &peers_with_optional_peer_id, &[0], &[2], 1), - ) - .await; + let validator_index = ValidatorIndex(0); + let candidate_index = 0u32; + + // import an assignment and approval locally. + let cert = fake_assignment_cert(hash, validator_index); + let approval = IndirectSignedApprovalVote { + block_hash: hash, + candidate_index, + validator: validator_index, + signature: dummy_signature(), + }; - let validator_index = ValidatorIndex(0); - let candidate_index = 0u32; + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_index.into(), + ), + ) + .await; - // import an assignment and approval locally. - let cert = fake_assignment_cert(hash, validator_index); - let approval = IndirectSignedApprovalVote { - block_hash: hash, - candidate_index, - validator: validator_index, - signature: dummy_signature(), - }; + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeApproval(approval.clone().into()), + ) + .await; - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeAssignment( - cert.clone().into(), - candidate_index.into(), - ), - ) - .await; + // connect the peer. + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeApproval(approval.clone().into()), - ) - .await; + let assignments = vec![(cert.clone(), candidate_index)]; + let approvals = vec![approval.clone()]; - // connect the peer. - setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; - - let assignments = vec![(cert.clone(), candidate_index)]; - let approvals = vec![approval.clone()]; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) - )) - )) => { - assert_eq!(peers, vec![*peer]); - assert_eq!(sent_assignments, assignments); - } - ); - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Approvals(sent_approvals) - )) - )) => { - assert_eq!(peers, vec![*peer]); - assert_eq!(sent_approvals, approvals); - } - ); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) + )) + )) => { + assert_eq!(peers, vec![*peer]); + assert_eq!(sent_assignments, assignments); + } + ); - assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); - virtual_overseer - }); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Approvals(sent_approvals) + )) + )) => { + assert_eq!(peers, vec![*peer]); + assert_eq!(sent_approvals, approvals); + } + ); + + assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); + virtual_overseer + }, + ); } /// Same as `sends_assignments_even_when_state_is_approved_v2` but with `VRFModuloCompact` @@ -2135,112 +2497,118 @@ fn sends_assignments_even_when_state_is_approved_v2() { let hash = Hash::repeat_byte(0xAA); let peer = &peer_a; - let _ = test_harness(State::default(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 1, - candidates: vec![Default::default(); 4], - slot: 1.into(), - session: 1, - }; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - - let peers_with_optional_peer_id = peers - .iter() - .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) - .collect_vec(); - // Setup a topology where peer_a is neighbor to current node. - setup_gossip_topology( - overseer, - make_gossip_topology(1, &peers_with_optional_peer_id, &[0], &[2], 1), - ) - .await; - - let validator_index = ValidatorIndex(0); - let cores = vec![0, 1, 2, 3]; - let candidate_bitfield: CandidateBitfield = cores.clone().try_into().unwrap(); - - let core_bitfield: CoreBitfield = cores - .iter() - .map(|index| CoreIndex(*index)) - .collect::>() - .try_into() - .unwrap(); - - let cert = fake_assignment_cert_v2(hash, validator_index, core_bitfield.clone()); + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + State::default(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![Default::default(); 4], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + // Setup a topology where peer_a is neighbor to current node. + setup_gossip_topology( + overseer, + make_gossip_topology(1, &peers_with_optional_peer_id, &[0], &[2], 1), + ) + .await; - // Assumes candidate index == core index. - let approvals = cores - .iter() - .map(|core| IndirectSignedApprovalVoteV2 { - block_hash: hash, - candidate_indices: (*core).into(), - validator: validator_index, - signature: dummy_signature(), - }) - .collect::>(); - - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeAssignment( - cert.clone().into(), - candidate_bitfield.clone(), - ), - ) - .await; + let validator_index = ValidatorIndex(0); + let cores = vec![0, 1, 2, 3]; + let candidate_bitfield: CandidateBitfield = cores.clone().try_into().unwrap(); + + let core_bitfield: CoreBitfield = cores + .iter() + .map(|index| CoreIndex(*index)) + .collect::>() + .try_into() + .unwrap(); + + let cert = fake_assignment_cert_v2(hash, validator_index, core_bitfield.clone()); + + // Assumes candidate index == core index. + let approvals = cores + .iter() + .map(|core| IndirectSignedApprovalVoteV2 { + block_hash: hash, + candidate_indices: (*core).into(), + validator: validator_index, + signature: dummy_signature(), + }) + .collect::>(); - for approval in &approvals { overseer_send( overseer, - ApprovalDistributionMessage::DistributeApproval(approval.clone()), + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_bitfield.clone(), + ), ) .await; - } - // connect the peer. - setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V3).await; - - let assignments = vec![(cert.clone(), candidate_bitfield.clone())]; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( - protocol_v3::ApprovalDistributionMessage::Assignments(sent_assignments) - )) - )) => { - assert_eq!(peers, vec![*peer]); - assert_eq!(sent_assignments, assignments); - } - ); - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( - protocol_v3::ApprovalDistributionMessage::Approvals(sent_approvals) - )) - )) => { - // Construct a hashmaps of approvals for comparison. Approval distribution reorders messages because they are kept in a - // hashmap as well. - let sent_approvals = sent_approvals.into_iter().map(|approval| (approval.candidate_indices.clone(), approval)).collect::>(); - let approvals = approvals.into_iter().map(|approval| (approval.candidate_indices.clone(), approval)).collect::>(); - - assert_eq!(peers, vec![*peer]); - assert_eq!(sent_approvals, approvals); + for approval in &approvals { + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeApproval(approval.clone()), + ) + .await; } - ); - assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); - virtual_overseer - }); + // connect the peer. + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V3).await; + + let assignments = vec![(cert.clone(), candidate_bitfield.clone())]; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(sent_assignments) + )) + )) => { + assert_eq!(peers, vec![*peer]); + assert_eq!(sent_assignments, assignments); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Approvals(sent_approvals) + )) + )) => { + // Construct a hashmaps of approvals for comparison. Approval distribution reorders messages because they are kept in a + // hashmap as well. + let sent_approvals = sent_approvals.into_iter().map(|approval| (approval.candidate_indices.clone(), approval)).collect::>(); + let approvals = approvals.into_iter().map(|approval| (approval.candidate_indices.clone(), approval)).collect::>(); + + assert_eq!(peers, vec![*peer]); + assert_eq!(sent_approvals, approvals); + } + ); + + assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); + virtual_overseer + }, + ); } /// @@ -2252,276 +2620,466 @@ fn sends_assignments_even_when_state_is_approved_v2() { #[test] fn race_condition_in_local_vs_remote_view_update() { let parent_hash = Hash::repeat_byte(0xFF); - let peer_a = PeerId::random(); - let hash_b = Hash::repeat_byte(0xBB); + let peer_a = PeerId::random(); + let hash_b = Hash::repeat_byte(0xBB); + + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state_without_reputation_delay(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + let peer = &peer_a; + + // Test a small number of candidates + let candidates_count = 1; + let meta = BlockApprovalMeta { + hash: hash_b, + parent_hash, + number: 2, + candidates: vec![Default::default(); candidates_count], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + + // This will send a peer view that is ahead of our view + setup_peer_with_view(overseer, peer, view![hash_b], ValidationVersion::V1).await; + + // Send our view update to include a new head + overseer_send( + overseer, + ApprovalDistributionMessage::NetworkBridgeUpdate( + NetworkBridgeEvent::OurViewChange(our_view![hash_b]), + ), + ) + .await; + + // send assignments related to `hash_b` but they will come to the MessagesPending + let assignments: Vec<_> = (0..candidates_count) + .map(|candidate_index| { + let validator_index = ValidatorIndex(candidate_index as u32); + let cert = fake_assignment_cert(hash_b, validator_index); + (cert, candidate_index as u32) + }) + .collect(); + + let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); + send_message_from_peer(overseer, peer, msg.clone()).await; + + // This will handle pending messages being processed + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + provide_session( + overseer, + dummy_session_info_valid(1, &mut LocalKeystore::in_memory(), 1), + ) + .await; + + for i in 0..candidates_count { + // Previously, this has caused out-of-view assignments/approvals + //expect_reputation_change(overseer, peer, COST_UNEXPECTED_MESSAGE).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportAssignment( + assignment, + _, + )) => { + assert_eq!(assignment.assignment(), &assignments[i].0.clone().into()); + assert_eq!(assignment.candidate_indices(), &assignments[i].1.into()); + assert_eq!(assignment.tranche(), 0); + } + ); + + // Since we have a valid statement pending, this should always occur + expect_reputation_change(overseer, peer, BENEFIT_VALID_MESSAGE_FIRST).await; + } + virtual_overseer + }, + ); +} + +// Tests that local messages propagate to both dimensions. +#[test] +fn propagates_locally_generated_assignment_to_both_dimensions() { + let parent_hash = Hash::repeat_byte(0xFF); + let hash = Hash::repeat_byte(0xAA); - let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - let peer = &peer_a; - - // Test a small number of candidates - let candidates_count = 1; - let meta = BlockApprovalMeta { - hash: hash_b, - parent_hash, - number: 2, - candidates: vec![Default::default(); candidates_count], - slot: 1.into(), - session: 1, - }; + let peers = make_peers_and_authority_ids(100); - // This will send a peer view that is ahead of our view - setup_peer_with_view(overseer, peer, view![hash_b], ValidationVersion::V1).await; + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + State::default(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; - // Send our view update to include a new head - overseer_send( - overseer, - ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::OurViewChange( - our_view![hash_b], - )), - ) - .await; + // Connect all peers. + for (peer, _) in &peers { + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; + } - // send assignments related to `hash_b` but they will come to the MessagesPending - let assignments: Vec<_> = (0..candidates_count) - .map(|candidate_index| { - let validator_index = ValidatorIndex(candidate_index as u32); - let cert = fake_assignment_cert(hash_b, validator_index); - (cert, candidate_index as u32) - }) - .collect(); + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + + // Set up a gossip topology. + setup_gossip_topology( + overseer, + make_gossip_topology( + 1, + &peers_with_optional_peer_id, + &[0, 10, 20, 30, 40, 60, 70, 80], + &[50, 51, 52, 53, 54, 55, 56, 57], + 1, + ), + ) + .await; + + let expected_indices = [ + // Both dimensions in the gossip topology + 0, 10, 20, 30, 40, 60, 70, 80, 50, 51, 52, 53, 54, 55, 56, 57, + ]; + + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + let validator_index = ValidatorIndex(0); + let candidate_index = 0u32; + + // import an assignment and approval locally. + let cert = fake_assignment_cert(hash, validator_index); + let approval = IndirectSignedApprovalVote { + block_hash: hash, + candidate_index, + validator: validator_index, + signature: dummy_signature(), + }; + + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_index.into(), + ), + ) + .await; - let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); - send_message_from_peer(overseer, peer, msg.clone()).await; + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeApproval(approval.clone().into()), + ) + .await; - // This will handle pending messages being processed - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; + let assignments = vec![(cert.clone(), candidate_index)]; + let approvals = vec![approval.clone()]; - for i in 0..candidates_count { - // Previously, this has caused out-of-view assignments/approvals - //expect_reputation_change(overseer, peer, COST_UNEXPECTED_MESSAGE).await; + let mut assignment_sent_peers = assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + sent_peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) + )) + )) => { + assert_eq!(sent_peers.len(), expected_indices.len() + 4); + for &i in &expected_indices { + assert!( + sent_peers.contains(&peers[i].0), + "Message not sent to expected peer {}", + i, + ); + } + assert_eq!(sent_assignments, assignments); + sent_peers + } + ); assert_matches!( overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( - assignment, - claimed_candidate_index, - tx, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + mut sent_peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Approvals(sent_approvals) + )) )) => { - assert_eq!(assignment, assignments[i].0.clone().into()); - assert_eq!(claimed_candidate_index, assignments[i].1.into()); - tx.send(AssignmentCheckResult::Accepted).unwrap(); + // Random sampling is reused from the assignment. + sent_peers.sort(); + assignment_sent_peers.sort(); + assert_eq!(sent_peers, assignment_sent_peers); + assert_eq!(sent_approvals, approvals); } ); - // Since we have a valid statement pending, this should always occur - expect_reputation_change(overseer, peer, BENEFIT_VALID_MESSAGE_FIRST).await; - } - virtual_overseer - }); + assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); + virtual_overseer + }, + ); } -// Tests that local messages propagate to both dimensions. +// Tests that messages propagate to the unshared dimension. #[test] -fn propagates_locally_generated_assignment_to_both_dimensions() { +fn propagates_assignments_along_unshared_dimension() { let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); let peers = make_peers_and_authority_ids(100); - let _ = test_harness(State::default(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state_without_reputation_delay(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; - // Connect all peers. - for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; - } + // Connect all peers. + for (peer, _) in &peers { + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; + } - let peers_with_optional_peer_id = peers - .iter() - .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) - .collect_vec(); - - // Set up a gossip topology. - setup_gossip_topology( - overseer, - make_gossip_topology( - 1, - &peers_with_optional_peer_id, - &[0, 10, 20, 30, 40, 60, 70, 80], - &[50, 51, 52, 53, 54, 55, 56, 57], - 1, - ), - ) - .await; + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); - let expected_indices = [ - // Both dimensions in the gossip topology - 0, 10, 20, 30, 40, 60, 70, 80, 50, 51, 52, 53, 54, 55, 56, 57, - ]; - - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 1, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; + // Set up a gossip topology. + setup_gossip_topology( + overseer, + make_gossip_topology( + 1, + &peers_with_optional_peer_id, + &[0, 10, 20, 30], + &[50, 51, 52, 53], + 1, + ), + ) + .await; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + // Test messages from X direction go to Y peers + { + let validator_index = ValidatorIndex(0); + let candidate_index = 0u32; + + // import an assignment and approval locally. + let cert = fake_assignment_cert(hash, validator_index); + let assignments = vec![(cert.clone(), candidate_index)]; + + let msg = + protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); + + // Issuer of the message is important, not the peer we receive from. + // 99 deliberately chosen because it's not in X or Y. + send_message_from_peer(overseer, &peers[99].0, msg).await; + provide_session( + overseer, + dummy_session_info_valid(1, &mut LocalKeystore::in_memory(), 1), + ) + .await; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportAssignment( + assignment, _, + )) => { + assert_eq!(assignment.tranche(), 0); + } + ); + expect_reputation_change(overseer, &peers[99].0, BENEFIT_VALID_MESSAGE_FIRST).await; - let validator_index = ValidatorIndex(0); - let candidate_index = 0u32; + let expected_y = [50, 51, 52, 53]; - // import an assignment and approval locally. - let cert = fake_assignment_cert(hash, validator_index); - let approval = IndirectSignedApprovalVote { - block_hash: hash, - candidate_index, - validator: validator_index, - signature: dummy_signature(), - }; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + sent_peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) + )) + )) => { + assert_eq!(sent_peers.len(), expected_y.len() + 4); + for &i in &expected_y { + assert!( + sent_peers.contains(&peers[i].0), + "Message not sent to expected peer {}", + i, + ); + } + assert_eq!(sent_assignments, assignments); + } + ); + }; - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeAssignment( - cert.clone().into(), - candidate_index.into(), - ), - ) - .await; + // Test messages from X direction go to Y peers + { + let validator_index = ValidatorIndex(50); + let candidate_index = 0u32; - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeApproval(approval.clone().into()), - ) - .await; + // import an assignment and approval locally. + let cert = fake_assignment_cert(hash, validator_index); + let assignments = vec![(cert.clone(), candidate_index)]; - let assignments = vec![(cert.clone(), candidate_index)]; - let approvals = vec![approval.clone()]; - - let mut assignment_sent_peers = assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - sent_peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) - )) - )) => { - assert_eq!(sent_peers.len(), expected_indices.len() + 4); - for &i in &expected_indices { - assert!( - sent_peers.contains(&peers[i].0), - "Message not sent to expected peer {}", - i, - ); - } - assert_eq!(sent_assignments, assignments); - sent_peers - } - ); - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - mut sent_peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Approvals(sent_approvals) - )) - )) => { - // Random sampling is reused from the assignment. - sent_peers.sort(); - assignment_sent_peers.sort(); - assert_eq!(sent_peers, assignment_sent_peers); - assert_eq!(sent_approvals, approvals); - } - ); + let msg = + protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); - assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); - virtual_overseer - }); + // Issuer of the message is important, not the peer we receive from. + // 99 deliberately chosen because it's not in X or Y. + send_message_from_peer(overseer, &peers[99].0, msg).await; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportAssignment( + assignment, _, + )) => { + assert_eq!(assignment.tranche(), 0); + } + ); + expect_reputation_change(overseer, &peers[99].0, BENEFIT_VALID_MESSAGE_FIRST).await; + + let expected_x = [0, 10, 20, 30]; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + sent_peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) + )) + )) => { + assert_eq!(sent_peers.len(), expected_x.len() + 4); + for &i in &expected_x { + assert!( + sent_peers.contains(&peers[i].0), + "Message not sent to expected peer {}", + i, + ); + } + assert_eq!(sent_assignments, assignments); + } + ); + }; + + assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); + virtual_overseer + }, + ); } -// Tests that messages propagate to the unshared dimension. +// tests that messages are propagated to necessary peers after they connect #[test] -fn propagates_assignments_along_unshared_dimension() { +fn propagates_to_required_after_connect() { let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); let peers = make_peers_and_authority_ids(100); - let _ = test_harness(state_without_reputation_delay(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - - // Connect all peers. - for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; - } + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + State::default(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; - let peers_with_optional_peer_id = peers - .iter() - .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) - .collect_vec(); - - // Set up a gossip topology. - setup_gossip_topology( - overseer, - make_gossip_topology( - 1, - &peers_with_optional_peer_id, - &[0, 10, 20, 30], - &[50, 51, 52, 53], - 1, - ), - ) - .await; + let omitted = [0, 10, 50, 51]; - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 1, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; + // Connect all peers except omitted. + for (i, (peer, _)) in peers.iter().enumerate() { + if !omitted.contains(&i) { + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; + } + } + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + // Set up a gossip topology. + setup_gossip_topology( + overseer, + make_gossip_topology( + 1, + &peers_with_optional_peer_id, + &[0, 10, 20, 30, 40, 60, 70, 80], + &[50, 51, 52, 53, 54, 55, 56, 57], + 1, + ), + ) + .await; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; + let expected_indices = [ + // Both dimensions in the gossip topology, minus omitted. + 20, 30, 40, 60, 70, 80, 52, 53, 54, 55, 56, 57, + ]; + + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; - // Test messages from X direction go to Y peers - { let validator_index = ValidatorIndex(0); let candidate_index = 0u32; // import an assignment and approval locally. let cert = fake_assignment_cert(hash, validator_index); - let assignments = vec![(cert.clone(), candidate_index)]; + let approval = IndirectSignedApprovalVote { + block_hash: hash, + candidate_index, + validator: validator_index, + signature: dummy_signature(), + }; - let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_index.into(), + ), + ) + .await; - // Issuer of the message is important, not the peer we receive from. - // 99 deliberately chosen because it's not in X or Y. - send_message_from_peer(overseer, &peers[99].0, msg).await; - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( - _, - _, - tx, - )) => { - tx.send(AssignmentCheckResult::Accepted).unwrap(); - } - ); - expect_reputation_change(overseer, &peers[99].0, BENEFIT_VALID_MESSAGE_FIRST).await; + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeApproval(approval.clone().into()), + ) + .await; - let expected_y = [50, 51, 52, 53]; + let assignments = vec![(cert.clone(), candidate_index)]; + let approvals = vec![approval.clone()]; - assert_matches!( + let mut assignment_sent_peers = assert_matches!( overseer_recv(overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( sent_peers, @@ -2529,8 +3087,8 @@ fn propagates_assignments_along_unshared_dimension() { protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) )) )) => { - assert_eq!(sent_peers.len(), expected_y.len() + 4); - for &i in &expected_y { + assert_eq!(sent_peers.len(), expected_indices.len() + 4); + for &i in &expected_indices { assert!( sent_peers.contains(&peers[i].0), "Message not sent to expected peer {}", @@ -2538,1123 +3096,1029 @@ fn propagates_assignments_along_unshared_dimension() { ); } assert_eq!(sent_assignments, assignments); + sent_peers } ); - }; - // Test messages from X direction go to Y peers - { - let validator_index = ValidatorIndex(50); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + mut sent_peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Approvals(sent_approvals) + )) + )) => { + // Random sampling is reused from the assignment. + sent_peers.sort(); + assignment_sent_peers.sort(); + assert_eq!(sent_peers, assignment_sent_peers); + assert_eq!(sent_approvals, approvals); + } + ); + + for i in omitted.iter().copied() { + setup_peer_with_view(overseer, &peers[i].0, view![hash], ValidationVersion::V1) + .await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + sent_peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) + )) + )) => { + assert_eq!(sent_peers.len(), 1); + assert_eq!(&sent_peers[0], &peers[i].0); + assert_eq!(sent_assignments, assignments); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + sent_peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Approvals(sent_approvals) + )) + )) => { + assert_eq!(sent_peers.len(), 1); + assert_eq!(&sent_peers[0], &peers[i].0); + assert_eq!(sent_approvals, approvals); + } + ); + } + + assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); + virtual_overseer + }, + ); +} + +// test that new gossip topology triggers send of messages. +#[test] +fn sends_to_more_peers_after_getting_topology() { + let parent_hash = Hash::repeat_byte(0xFF); + let hash = Hash::repeat_byte(0xAA); + + let peers = make_peers_and_authority_ids(100); + + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + State::default(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + + // Connect all peers except omitted. + for (peer, _) in &peers { + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; + } + + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + let validator_index = ValidatorIndex(0); let candidate_index = 0u32; // import an assignment and approval locally. let cert = fake_assignment_cert(hash, validator_index); + let approval = IndirectSignedApprovalVote { + block_hash: hash, + candidate_index, + validator: validator_index, + signature: dummy_signature(), + }; + + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_index.into(), + ), + ) + .await; + + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeApproval(approval.clone().into()), + ) + .await; + let assignments = vec![(cert.clone(), candidate_index)]; + let approvals = vec![approval.clone()]; + + let expected_indices = vec![0, 10, 20, 30, 50, 51, 52, 53]; + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + // Set up a gossip topology. + setup_gossip_topology( + overseer, + make_gossip_topology( + 1, + &peers_with_optional_peer_id, + &[0, 10, 20, 30], + &[50, 51, 52, 53], + 1, + ), + ) + .await; + + let mut expected_indices_assignments = expected_indices.clone(); + let mut expected_indices_approvals = expected_indices.clone(); + + for _ in 0..expected_indices_assignments.len() { + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + sent_peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) + )) + )) => { + // Sends to all expected peers. + assert_eq!(sent_peers.len(), 1); + assert_eq!(sent_assignments, assignments); - let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); + let pos = expected_indices_assignments.iter() + .position(|i| &peers[*i].0 == &sent_peers[0]) + .unwrap(); + expected_indices_assignments.remove(pos); + } + ); + } - // Issuer of the message is important, not the peer we receive from. - // 99 deliberately chosen because it's not in X or Y. - send_message_from_peer(overseer, &peers[99].0, msg).await; - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( - _, - _, - tx, - )) => { - tx.send(AssignmentCheckResult::Accepted).unwrap(); - } - ); - expect_reputation_change(overseer, &peers[99].0, BENEFIT_VALID_MESSAGE_FIRST).await; + for _ in 0..expected_indices_approvals.len() { + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + sent_peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Approvals(sent_approvals) + )) + )) => { + // Sends to all expected peers. + assert_eq!(sent_peers.len(), 1); + assert_eq!(sent_approvals, approvals); - let expected_x = [0, 10, 20, 30]; + let pos = expected_indices_approvals.iter() + .position(|i| &peers[*i].0 == &sent_peers[0]) + .unwrap(); - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - sent_peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) - )) - )) => { - assert_eq!(sent_peers.len(), expected_x.len() + 4); - for &i in &expected_x { - assert!( - sent_peers.contains(&peers[i].0), - "Message not sent to expected peer {}", - i, - ); + expected_indices_approvals.remove(pos); } - assert_eq!(sent_assignments, assignments); - } - ); - }; + ); + } - assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); - virtual_overseer - }); + assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); + virtual_overseer + }, + ); } -// tests that messages are propagated to necessary peers after they connect +// test aggression L1 #[test] -fn propagates_to_required_after_connect() { +fn originator_aggression_l1() { let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); let peers = make_peers_and_authority_ids(100); - let _ = test_harness(State::default(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; + let mut state = State::default(); + state.aggression_config.resend_unfinalized_period = None; + let aggression_l1_threshold = state.aggression_config.l1_threshold.unwrap(); - let omitted = [0, 10, 50, 51]; + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state, + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; - // Connect all peers except omitted. - for (i, (peer, _)) in peers.iter().enumerate() { - if !omitted.contains(&i) { + // Connect all peers except omitted. + for (peer, _) in &peers { setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; } - } - let peers_with_optional_peer_id = peers - .iter() - .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) - .collect_vec(); - // Set up a gossip topology. - setup_gossip_topology( - overseer, - make_gossip_topology( - 1, - &peers_with_optional_peer_id, - &[0, 10, 20, 30, 40, 60, 70, 80], - &[50, 51, 52, 53, 54, 55, 56, 57], - 1, - ), - ) - .await; - - let expected_indices = [ - // Both dimensions in the gossip topology, minus omitted. - 20, 30, 40, 60, 70, 80, 52, 53, 54, 55, 56, 57, - ]; - - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 1, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; - let validator_index = ValidatorIndex(0); - let candidate_index = 0u32; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; - // import an assignment and approval locally. - let cert = fake_assignment_cert(hash, validator_index); - let approval = IndirectSignedApprovalVote { - block_hash: hash, - candidate_index, - validator: validator_index, - signature: dummy_signature(), - }; + let validator_index = ValidatorIndex(0); + let candidate_index = 0u32; - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeAssignment( - cert.clone().into(), - candidate_index.into(), - ), - ) - .await; + // import an assignment and approval locally. + let cert = fake_assignment_cert(hash, validator_index); + let approval = IndirectSignedApprovalVote { + block_hash: hash, + candidate_index, + validator: validator_index, + signature: dummy_signature(), + }; + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + // Set up a gossip topology. + setup_gossip_topology( + overseer, + make_gossip_topology( + 1, + &peers_with_optional_peer_id, + &[0, 10, 20, 30], + &[50, 51, 52, 53], + 1, + ), + ) + .await; - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeApproval(approval.clone().into()), - ) - .await; + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment( + cert.clone().into(), + candidate_index.into(), + ), + ) + .await; - let assignments = vec![(cert.clone(), candidate_index)]; - let approvals = vec![approval.clone()]; - - let mut assignment_sent_peers = assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - sent_peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) - )) - )) => { - assert_eq!(sent_peers.len(), expected_indices.len() + 4); - for &i in &expected_indices { - assert!( - sent_peers.contains(&peers[i].0), - "Message not sent to expected peer {}", - i, - ); - } - assert_eq!(sent_assignments, assignments); - sent_peers - } - ); - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - mut sent_peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Approvals(sent_approvals) - )) - )) => { - // Random sampling is reused from the assignment. - sent_peers.sort(); - assignment_sent_peers.sort(); - assert_eq!(sent_peers, assignment_sent_peers); - assert_eq!(sent_approvals, approvals); - } - ); + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeApproval(approval.clone().into()), + ) + .await; - for i in omitted.iter().copied() { - setup_peer_with_view(overseer, &peers[i].0, view![hash], ValidationVersion::V1).await; + let assignments = vec![(cert.clone(), candidate_index)]; + let approvals = vec![approval.clone()]; - assert_matches!( + let prev_sent_indices = assert_matches!( overseer_recv(overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( sent_peers, Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) + protocol_v1::ApprovalDistributionMessage::Assignments(_) )) )) => { - assert_eq!(sent_peers.len(), 1); - assert_eq!(&sent_peers[0], &peers[i].0); - assert_eq!(sent_assignments, assignments); + sent_peers.into_iter() + .filter_map(|sp| peers.iter().position(|p| &p.0 == &sp)) + .collect::>() } ); assert_matches!( overseer_recv(overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - sent_peers, + _, Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Approvals(sent_approvals) + protocol_v1::ApprovalDistributionMessage::Approvals(_) )) - )) => { - assert_eq!(sent_peers.len(), 1); - assert_eq!(&sent_peers[0], &peers[i].0); - assert_eq!(sent_approvals, approvals); - } + )) => { } ); - } - assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); - virtual_overseer - }); + // Add blocks until aggression L1 is triggered. + { + let mut parent_hash = hash; + for level in 0..aggression_l1_threshold { + let number = 1 + level + 1; // first block had number 1 + let hash = BlakeTwo256::hash_of(&(parent_hash, number)); + let meta = BlockApprovalMeta { + hash, + parent_hash, + number, + candidates: vec![], + slot: (level as u64).into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + + let msg = ApprovalDistributionMessage::ApprovalCheckingLagUpdate(level + 1); + overseer_send(overseer, msg).await; + + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + parent_hash = hash; + } + } + + let unsent_indices = + (0..peers.len()).filter(|i| !prev_sent_indices.contains(&i)).collect::>(); + + for _ in 0..unsent_indices.len() { + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + sent_peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) + )) + )) => { + // Sends to all expected peers. + assert_eq!(sent_peers.len(), 1); + assert_eq!(sent_assignments, assignments); + + assert!(unsent_indices.iter() + .any(|i| &peers[*i].0 == &sent_peers[0])); + } + ); + } + + for _ in 0..unsent_indices.len() { + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + sent_peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Approvals(sent_approvals) + )) + )) => { + // Sends to all expected peers. + assert_eq!(sent_peers.len(), 1); + assert_eq!(sent_approvals, approvals); + + assert!(unsent_indices.iter() + .any(|i| &peers[*i].0 == &sent_peers[0])); + } + ); + } + + assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); + virtual_overseer + }, + ); } -// test that new gossip topology triggers send of messages. +// test aggression L1 #[test] -fn sends_to_more_peers_after_getting_topology() { +fn non_originator_aggression_l1() { let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); let peers = make_peers_and_authority_ids(100); - let _ = test_harness(State::default(), |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - - // Connect all peers except omitted. - for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; - } + let mut state = state_without_reputation_delay(); + state.aggression_config.resend_unfinalized_period = None; + let aggression_l1_threshold = state.aggression_config.l1_threshold.unwrap(); - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 1, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state, + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; + // Connect all peers except omitted. + for (peer, _) in &peers { + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; + } - let validator_index = ValidatorIndex(0); - let candidate_index = 0u32; + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; - // import an assignment and approval locally. - let cert = fake_assignment_cert(hash, validator_index); - let approval = IndirectSignedApprovalVote { - block_hash: hash, - candidate_index, - validator: validator_index, - signature: dummy_signature(), - }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeAssignment( - cert.clone().into(), - candidate_index.into(), - ), - ) - .await; + let validator_index = ValidatorIndex(0); + let candidate_index = 0u32; - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeApproval(approval.clone().into()), - ) - .await; + // import an assignment and approval locally. + let cert = fake_assignment_cert(hash, validator_index); + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + // Set up a gossip topology. + setup_gossip_topology( + overseer, + make_gossip_topology( + 1, + &peers_with_optional_peer_id, + &[0, 10, 20, 30], + &[50, 51, 52, 53], + 1, + ), + ) + .await; - let assignments = vec![(cert.clone(), candidate_index)]; - let approvals = vec![approval.clone()]; - - let expected_indices = vec![0, 10, 20, 30, 50, 51, 52, 53]; - let peers_with_optional_peer_id = peers - .iter() - .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) - .collect_vec(); - // Set up a gossip topology. - setup_gossip_topology( - overseer, - make_gossip_topology( - 1, - &peers_with_optional_peer_id, - &[0, 10, 20, 30], - &[50, 51, 52, 53], - 1, - ), - ) - .await; + let assignments = vec![(cert.clone().into(), candidate_index)]; + let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); - let mut expected_indices_assignments = expected_indices.clone(); - let mut expected_indices_approvals = expected_indices.clone(); + // Issuer of the message is important, not the peer we receive from. + // 99 deliberately chosen because it's not in X or Y. + send_message_from_peer(overseer, &peers[99].0, msg).await; + provide_session( + overseer, + dummy_session_info_valid(1, &mut LocalKeystore::in_memory(), 1), + ) + .await; - for _ in 0..expected_indices_assignments.len() { assert_matches!( overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - sent_peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) - )) + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportAssignment( + assignment, _, )) => { - // Sends to all expected peers. - assert_eq!(sent_peers.len(), 1); - assert_eq!(sent_assignments, assignments); - - let pos = expected_indices_assignments.iter() - .position(|i| &peers[*i].0 == &sent_peers[0]) - .unwrap(); - expected_indices_assignments.remove(pos); + assert_eq!(assignment.tranche(), 0); } ); - } - for _ in 0..expected_indices_approvals.len() { + expect_reputation_change(overseer, &peers[99].0, BENEFIT_VALID_MESSAGE_FIRST).await; + assert_matches!( overseer_recv(overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - sent_peers, + _, Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Approvals(sent_approvals) + protocol_v1::ApprovalDistributionMessage::Assignments(_) )) - )) => { - // Sends to all expected peers. - assert_eq!(sent_peers.len(), 1); - assert_eq!(sent_approvals, approvals); - - let pos = expected_indices_approvals.iter() - .position(|i| &peers[*i].0 == &sent_peers[0]) - .unwrap(); - - expected_indices_approvals.remove(pos); - } + )) => { } ); - } - - assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); - virtual_overseer - }); -} -// test aggression L1 -#[test] -fn originator_aggression_l1() { - let parent_hash = Hash::repeat_byte(0xFF); - let hash = Hash::repeat_byte(0xAA); + // Add blocks until aggression L1 is triggered. + { + let mut parent_hash = hash; + for level in 0..aggression_l1_threshold { + let number = 1 + level + 1; // first block had number 1 + let hash = BlakeTwo256::hash_of(&(parent_hash, number)); + let meta = BlockApprovalMeta { + hash, + parent_hash, + number, + candidates: vec![], + slot: (level as u64).into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; - let peers = make_peers_and_authority_ids(100); + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; - let mut state = State::default(); - state.aggression_config.resend_unfinalized_period = None; - let aggression_l1_threshold = state.aggression_config.l1_threshold.unwrap(); + parent_hash = hash; + } + } - let _ = test_harness(state, |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; + // No-op on non-originator - // Connect all peers except omitted. - for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; - } + assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); + virtual_overseer + }, + ); +} - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 1, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; +// test aggression L2 on non-originator +#[test] +fn non_originator_aggression_l2() { + let parent_hash = Hash::repeat_byte(0xFF); + let hash = Hash::repeat_byte(0xAA); - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; + let peers = make_peers_and_authority_ids(100); - let validator_index = ValidatorIndex(0); - let candidate_index = 0u32; + let mut state = state_without_reputation_delay(); + state.aggression_config.resend_unfinalized_period = None; - // import an assignment and approval locally. - let cert = fake_assignment_cert(hash, validator_index); - let approval = IndirectSignedApprovalVote { - block_hash: hash, - candidate_index, - validator: validator_index, - signature: dummy_signature(), - }; - let peers_with_optional_peer_id = peers - .iter() - .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) - .collect_vec(); - // Set up a gossip topology. - setup_gossip_topology( - overseer, - make_gossip_topology( - 1, - &peers_with_optional_peer_id, - &[0, 10, 20, 30], - &[50, 51, 52, 53], - 1, - ), - ) - .await; + let aggression_l1_threshold = state.aggression_config.l1_threshold.unwrap(); + let aggression_l2_threshold = state.aggression_config.l2_threshold.unwrap(); + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state, + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + + // Connect all peers except omitted. + for (peer, _) in &peers { + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; + } - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeAssignment( - cert.clone().into(), - candidate_index.into(), - ), - ) - .await; + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeApproval(approval.clone().into()), - ) - .await; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; - let assignments = vec![(cert.clone(), candidate_index)]; - let approvals = vec![approval.clone()]; - - let prev_sent_indices = assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - sent_peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(_) - )) - )) => { - sent_peers.into_iter() - .filter_map(|sp| peers.iter().position(|p| &p.0 == &sp)) - .collect::>() - } - ); + let validator_index = ValidatorIndex(0); + let candidate_index = 0u32; - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - _, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Approvals(_) - )) - )) => { } - ); - - // Add blocks until aggression L1 is triggered. - { - let mut parent_hash = hash; - for level in 0..aggression_l1_threshold { - let number = 1 + level + 1; // first block had number 1 - let hash = BlakeTwo256::hash_of(&(parent_hash, number)); - let meta = BlockApprovalMeta { - hash, - parent_hash, - number, - candidates: vec![], - slot: (level as u64).into(), - session: 1, - }; - - let msg = ApprovalDistributionMessage::ApprovalCheckingLagUpdate(level + 1); - overseer_send(overseer, msg).await; - - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - - parent_hash = hash; - } - } + // import an assignment and approval locally. + let cert = fake_assignment_cert(hash, validator_index); + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + // Set up a gossip topology. + setup_gossip_topology( + overseer, + make_gossip_topology( + 1, + &peers_with_optional_peer_id, + &[0, 10, 20, 30], + &[50, 51, 52, 53], + 1, + ), + ) + .await; - let unsent_indices = - (0..peers.len()).filter(|i| !prev_sent_indices.contains(&i)).collect::>(); + let assignments = vec![(cert.clone(), candidate_index)]; + let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); - for _ in 0..unsent_indices.len() { + // Issuer of the message is important, not the peer we receive from. + // 99 deliberately chosen because it's not in X or Y. + send_message_from_peer(overseer, &peers[99].0, msg).await; + provide_session( + overseer, + dummy_session_info_valid(1, &mut LocalKeystore::in_memory(), 1), + ) + .await; assert_matches!( overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - sent_peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) - )) + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportAssignment( + assignment, _, )) => { - // Sends to all expected peers. - assert_eq!(sent_peers.len(), 1); - assert_eq!(sent_assignments, assignments); - - assert!(unsent_indices.iter() - .any(|i| &peers[*i].0 == &sent_peers[0])); + assert_eq!(assignment.tranche(), 0); } ); - } - for _ in 0..unsent_indices.len() { - assert_matches!( + expect_reputation_change(overseer, &peers[99].0, BENEFIT_VALID_MESSAGE_FIRST).await; + + let prev_sent_indices = assert_matches!( overseer_recv(overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( sent_peers, Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Approvals(sent_approvals) + protocol_v1::ApprovalDistributionMessage::Assignments(_) )) )) => { - // Sends to all expected peers. - assert_eq!(sent_peers.len(), 1); - assert_eq!(sent_approvals, approvals); - - assert!(unsent_indices.iter() - .any(|i| &peers[*i].0 == &sent_peers[0])); + sent_peers.into_iter() + .filter_map(|sp| peers.iter().position(|p| &p.0 == &sp)) + .collect::>() } ); - } - - assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); - virtual_overseer - }); -} -// test aggression L1 -#[test] -fn non_originator_aggression_l1() { - let parent_hash = Hash::repeat_byte(0xFF); - let hash = Hash::repeat_byte(0xAA); + // Add blocks until aggression L1 is triggered. + let chain_head = { + let mut parent_hash = hash; + for level in 0..aggression_l1_threshold { + let number = 1 + level + 1; // first block had number 1 + let hash = BlakeTwo256::hash_of(&(parent_hash, number)); + let meta = BlockApprovalMeta { + hash, + parent_hash, + number, + candidates: vec![], + slot: (level as u64).into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; - let peers = make_peers_and_authority_ids(100); + let msg = ApprovalDistributionMessage::ApprovalCheckingLagUpdate(level + 1); + overseer_send(overseer, msg).await; - let mut state = state_without_reputation_delay(); - state.aggression_config.resend_unfinalized_period = None; - let aggression_l1_threshold = state.aggression_config.l1_threshold.unwrap(); + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; - let _ = test_harness(state, |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; + parent_hash = hash; + } - // Connect all peers except omitted. - for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; - } + parent_hash + }; - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 1, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; + // No-op on non-originator - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - - let validator_index = ValidatorIndex(0); - let candidate_index = 0u32; - - // import an assignment and approval locally. - let cert = fake_assignment_cert(hash, validator_index); - let peers_with_optional_peer_id = peers - .iter() - .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) - .collect_vec(); - // Set up a gossip topology. - setup_gossip_topology( - overseer, - make_gossip_topology( - 1, - &peers_with_optional_peer_id, - &[0, 10, 20, 30], - &[50, 51, 52, 53], - 1, - ), - ) - .await; + // Add blocks until aggression L2 is triggered. + { + let mut parent_hash = chain_head; + for level in 0..aggression_l2_threshold - aggression_l1_threshold { + let number = aggression_l1_threshold + level + 1 + 1; // first block had number 1 + let hash = BlakeTwo256::hash_of(&(parent_hash, number)); + let meta = BlockApprovalMeta { + hash, + parent_hash, + number, + candidates: vec![], + slot: (level as u64).into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; - let assignments = vec![(cert.clone().into(), candidate_index)]; - let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); + let msg = ApprovalDistributionMessage::ApprovalCheckingLagUpdate( + aggression_l1_threshold + level + 1, + ); + overseer_send(overseer, msg).await; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; - // Issuer of the message is important, not the peer we receive from. - // 99 deliberately chosen because it's not in X or Y. - send_message_from_peer(overseer, &peers[99].0, msg).await; - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( - _, - _, - tx, - )) => { - tx.send(AssignmentCheckResult::Accepted).unwrap(); + parent_hash = hash; + } } - ); - expect_reputation_change(overseer, &peers[99].0, BENEFIT_VALID_MESSAGE_FIRST).await; + // XY dimension - previously sent. + let unsent_indices = [0, 10, 20, 30, 50, 51, 52, 53] + .iter() + .cloned() + .filter(|i| !prev_sent_indices.contains(&i)) + .collect::>(); - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - _, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(_) - )) - )) => { } - ); - - // Add blocks until aggression L1 is triggered. - { - let mut parent_hash = hash; - for level in 0..aggression_l1_threshold { - let number = 1 + level + 1; // first block had number 1 - let hash = BlakeTwo256::hash_of(&(parent_hash, number)); - let meta = BlockApprovalMeta { - hash, - parent_hash, - number, - candidates: vec![], - slot: (level as u64).into(), - session: 1, - }; - - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - - parent_hash = hash; - } - } + for _ in 0..unsent_indices.len() { + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + sent_peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) + )) + )) => { + // Sends to all expected peers. + assert_eq!(sent_peers.len(), 1); + assert_eq!(sent_assignments, assignments); - // No-op on non-originator + assert!(unsent_indices.iter() + .any(|i| &peers[*i].0 == &sent_peers[0])); + } + ); + } - assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); - virtual_overseer - }); + assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); + virtual_overseer + }, + ); } -// test aggression L2 on non-originator +// Tests that messages propagate to the unshared dimension. #[test] -fn non_originator_aggression_l2() { +fn resends_messages_periodically() { let parent_hash = Hash::repeat_byte(0xFF); let hash = Hash::repeat_byte(0xAA); let peers = make_peers_and_authority_ids(100); let mut state = state_without_reputation_delay(); - state.aggression_config.resend_unfinalized_period = None; + state.aggression_config.l1_threshold = None; + state.aggression_config.l2_threshold = None; + state.aggression_config.resend_unfinalized_period = Some(2); + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state, + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + + // Connect all peers. + for (peer, _) in &peers { + setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; + } + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + // Set up a gossip topology. + setup_gossip_topology( + overseer, + make_gossip_topology( + 1, + &peers_with_optional_peer_id, + &[0, 10, 20, 30], + &[50, 51, 52, 53], + 1, + ), + ) + .await; - let aggression_l1_threshold = state.aggression_config.l1_threshold.unwrap(); - let aggression_l2_threshold = state.aggression_config.l2_threshold.unwrap(); - let _ = test_harness(state, |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; - // Connect all peers except omitted. - for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; - } + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 1, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; + let validator_index = ValidatorIndex(0); + let candidate_index = 0u32; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - - let validator_index = ValidatorIndex(0); - let candidate_index = 0u32; - - // import an assignment and approval locally. - let cert = fake_assignment_cert(hash, validator_index); - let peers_with_optional_peer_id = peers - .iter() - .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) - .collect_vec(); - // Set up a gossip topology. - setup_gossip_topology( - overseer, - make_gossip_topology( - 1, - &peers_with_optional_peer_id, - &[0, 10, 20, 30], - &[50, 51, 52, 53], - 1, - ), - ) - .await; + // import an assignment and approval locally. + let cert = fake_assignment_cert(hash, validator_index); + let assignments = vec![(cert.clone(), candidate_index)]; - let assignments = vec![(cert.clone(), candidate_index)]; - let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); + { + let msg = + protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); + + // Issuer of the message is important, not the peer we receive from. + // 99 deliberately chosen because it's not in X or Y. + send_message_from_peer(overseer, &peers[99].0, msg).await; + provide_session( + overseer, + dummy_session_info_valid(1, &mut LocalKeystore::in_memory(), 1), + ) + .await; - // Issuer of the message is important, not the peer we receive from. - // 99 deliberately chosen because it's not in X or Y. - send_message_from_peer(overseer, &peers[99].0, msg).await; - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( - _, - _, - tx, - )) => { - tx.send(AssignmentCheckResult::Accepted).unwrap(); - } - ); - - expect_reputation_change(overseer, &peers[99].0, BENEFIT_VALID_MESSAGE_FIRST).await; - - let prev_sent_indices = assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - sent_peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(_) - )) - )) => { - sent_peers.into_iter() - .filter_map(|sp| peers.iter().position(|p| &p.0 == &sp)) - .collect::>() - } - ); - - // Add blocks until aggression L1 is triggered. - let chain_head = { - let mut parent_hash = hash; - for level in 0..aggression_l1_threshold { - let number = 1 + level + 1; // first block had number 1 - let hash = BlakeTwo256::hash_of(&(parent_hash, number)); - let meta = BlockApprovalMeta { - hash, - parent_hash, - number, - candidates: vec![], - slot: (level as u64).into(), - session: 1, - }; - - let msg = ApprovalDistributionMessage::ApprovalCheckingLagUpdate(level + 1); - overseer_send(overseer, msg).await; - - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - - parent_hash = hash; - } + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportAssignment( + assignment, _, + )) => { + assert_eq!(assignment.tranche(), 0); + } + ); + expect_reputation_change(overseer, &peers[99].0, BENEFIT_VALID_MESSAGE_FIRST).await; - parent_hash - }; + let expected_y = [50, 51, 52, 53]; - // No-op on non-originator - - // Add blocks until aggression L2 is triggered. - { - let mut parent_hash = chain_head; - for level in 0..aggression_l2_threshold - aggression_l1_threshold { - let number = aggression_l1_threshold + level + 1 + 1; // first block had number 1 - let hash = BlakeTwo256::hash_of(&(parent_hash, number)); - let meta = BlockApprovalMeta { - hash, - parent_hash, - number, - candidates: vec![], - slot: (level as u64).into(), - session: 1, - }; - - let msg = ApprovalDistributionMessage::ApprovalCheckingLagUpdate( - aggression_l1_threshold + level + 1, + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + sent_peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) + )) + )) => { + assert_eq!(sent_peers.len(), expected_y.len() + 4); + for &i in &expected_y { + assert!( + sent_peers.contains(&peers[i].0), + "Message not sent to expected peer {}", + i, + ); + } + assert_eq!(sent_assignments, assignments); + } ); - overseer_send(overseer, msg).await; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; + }; + + let mut number = 1; + for _ in 0..10 { + // Add blocks until resend is done. + { + let mut parent_hash = hash; + for level in 0..2 { + number = number + 1; + let hash = BlakeTwo256::hash_of(&(parent_hash, number)); + let meta = BlockApprovalMeta { + hash, + parent_hash, + number, + candidates: vec![], + slot: (level as u64).into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + + let msg = ApprovalDistributionMessage::ApprovalCheckingLagUpdate(2); + overseer_send(overseer, msg).await; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + parent_hash = hash; + } + } - parent_hash = hash; + let mut expected_y = vec![50, 51, 52, 53]; + + // Expect messages sent only to topology peers, one by one. + for _ in 0..expected_y.len() { + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + sent_peers, + Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( + protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) + )) + )) => { + assert_eq!(sent_peers.len(), 1); + let expected_pos = expected_y.iter() + .position(|&i| &peers[i].0 == &sent_peers[0]) + .unwrap(); + + expected_y.remove(expected_pos); + assert_eq!(sent_assignments, assignments); + } + ); + } } - } - // XY dimension - previously sent. - let unsent_indices = [0, 10, 20, 30, 50, 51, 52, 53] - .iter() - .cloned() - .filter(|i| !prev_sent_indices.contains(&i)) - .collect::>(); + assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); + virtual_overseer + }, + ); +} + +/// Tests that peers correctly receive versioned messages. +#[test] +fn import_versioned_approval() { + let peers = make_peers_and_authority_ids(15); + let peer_a = peers.get(0).unwrap().0; + let peer_b = peers.get(1).unwrap().0; + let peer_c = peers.get(2).unwrap().0; + + let parent_hash = Hash::repeat_byte(0xFF); + let hash = Hash::repeat_byte(0xAA); + let state = state_without_reputation_delay(); + let candidate_hash = polkadot_primitives::CandidateHash(Hash::repeat_byte(0xBB)); + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(SystemClock {}), + state, + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // All peers are aware of relay parent. + setup_peer_with_view(overseer, &peer_a, view![hash], ValidationVersion::V2).await; + setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V1).await; + setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V2).await; + + // Set up a gossip topology, where a, b, c and d are topology neighbors to the node + // under testing. + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + setup_gossip_topology( + overseer, + make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), + ) + .await; + + let mut keystore = LocalKeystore::in_memory(); + let session = dummy_session_info_valid(1, &mut keystore, 1); + + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 1, + candidates: vec![(candidate_hash, 0.into(), 0.into()); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + // import an assignment related to `hash` locally + let validator_index = ValidatorIndex(0); + let candidate_index = 0u32; + let cert = fake_assignment_cert(hash, validator_index); + overseer_send( + overseer, + ApprovalDistributionMessage::DistributeAssignment( + cert.into(), + candidate_index.into(), + ), + ) + .await; - for _ in 0..unsent_indices.len() { assert_matches!( overseer_recv(overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - sent_peers, + peers, Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) + protocol_v1::ApprovalDistributionMessage::Assignments(assignments) )) )) => { - // Sends to all expected peers. - assert_eq!(sent_peers.len(), 1); - assert_eq!(sent_assignments, assignments); - - assert!(unsent_indices.iter() - .any(|i| &peers[*i].0 == &sent_peers[0])); + assert_eq!(peers, vec![peer_b]); + assert_eq!(assignments.len(), 1); } ); - } - - assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); - virtual_overseer - }); -} - -// Tests that messages propagate to the unshared dimension. -#[test] -fn resends_messages_periodically() { - let parent_hash = Hash::repeat_byte(0xFF); - let hash = Hash::repeat_byte(0xAA); - - let peers = make_peers_and_authority_ids(100); - - let mut state = state_without_reputation_delay(); - state.aggression_config.l1_threshold = None; - state.aggression_config.l2_threshold = None; - state.aggression_config.resend_unfinalized_period = Some(2); - let _ = test_harness(state, |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - - // Connect all peers. - for (peer, _) in &peers { - setup_peer_with_view(overseer, peer, view![hash], ValidationVersion::V1).await; - } - let peers_with_optional_peer_id = peers - .iter() - .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) - .collect_vec(); - // Set up a gossip topology. - setup_gossip_topology( - overseer, - make_gossip_topology( - 1, - &peers_with_optional_peer_id, - &[0, 10, 20, 30], - &[50, 51, 52, 53], - 1, - ), - ) - .await; - - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 1, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - - let validator_index = ValidatorIndex(0); - let candidate_index = 0u32; - - // import an assignment and approval locally. - let cert = fake_assignment_cert(hash, validator_index); - let assignments = vec![(cert.clone(), candidate_index)]; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V2(protocol_v2::ValidationProtocol::ApprovalDistribution( + protocol_v2::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers.len(), 2); + assert!(peers.contains(&peer_a)); + assert!(peers.contains(&peer_c)); - { - let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); + assert_eq!(assignments.len(), 1); + } + ); - // Issuer of the message is important, not the peer we receive from. - // 99 deliberately chosen because it's not in X or Y. - send_message_from_peer(overseer, &peers[99].0, msg).await; + // send the an approval from peer_a + let approval = IndirectSignedApprovalVote { + block_hash: hash, + candidate_index, + validator: validator_index, + signature: signature_for( + &keystore, + &session, + vec![candidate_hash], + validator_index, + ), + }; + let msg = protocol_v2::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); + send_message_from_peer_v2(overseer, &peer_a, msg).await; + provide_session(overseer, session).await; assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportAssignment( - _, - _, - tx, + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportApproval( + vote, _, )) => { - tx.send(AssignmentCheckResult::Accepted).unwrap(); + assert_eq!(Into::::into(vote), approval.into()); } ); - expect_reputation_change(overseer, &peers[99].0, BENEFIT_VALID_MESSAGE_FIRST).await; - let expected_y = [50, 51, 52, 53]; + expect_reputation_change(overseer, &peer_a, BENEFIT_VALID_MESSAGE_FIRST).await; + // Peers b and c receive versioned approval messages. assert_matches!( overseer_recv(overseer).await, AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - sent_peers, + peers, Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) + protocol_v1::ApprovalDistributionMessage::Approvals(approvals) )) )) => { - assert_eq!(sent_peers.len(), expected_y.len() + 4); - for &i in &expected_y { - assert!( - sent_peers.contains(&peers[i].0), - "Message not sent to expected peer {}", - i, - ); - } - assert_eq!(sent_assignments, assignments); + assert_eq!(peers, vec![peer_b]); + assert_eq!(approvals.len(), 1); } ); - }; - - let mut number = 1; - for _ in 0..10 { - // Add blocks until resend is done. - { - let mut parent_hash = hash; - for level in 0..2 { - number = number + 1; - let hash = BlakeTwo256::hash_of(&(parent_hash, number)); - let meta = BlockApprovalMeta { - hash, - parent_hash, - number, - candidates: vec![], - slot: (level as u64).into(), - session: 1, - }; - - let msg = ApprovalDistributionMessage::ApprovalCheckingLagUpdate(2); - overseer_send(overseer, msg).await; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - parent_hash = hash; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V2(protocol_v2::ValidationProtocol::ApprovalDistribution( + protocol_v2::ApprovalDistributionMessage::Approvals(approvals) + )) + )) => { + assert_eq!(peers, vec![peer_c]); + assert_eq!(approvals.len(), 1); } - } - - let mut expected_y = vec![50, 51, 52, 53]; - - // Expect messages sent only to topology peers, one by one. - for _ in 0..expected_y.len() { - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - sent_peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(sent_assignments) - )) - )) => { - assert_eq!(sent_peers.len(), 1); - let expected_pos = expected_y.iter() - .position(|&i| &peers[i].0 == &sent_peers[0]) - .unwrap(); - - expected_y.remove(expected_pos); - assert_eq!(sent_assignments, assignments); - } - ); - } - } - - assert!(overseer.recv().timeout(TIMEOUT).await.is_none(), "no message should be sent"); - virtual_overseer - }); -} - -/// Tests that peers correctly receive versioned messages. -#[test] -fn import_versioned_approval() { - let peers = make_peers_and_authority_ids(15); - let peer_a = peers.get(0).unwrap().0; - let peer_b = peers.get(1).unwrap().0; - let peer_c = peers.get(2).unwrap().0; + ); - let parent_hash = Hash::repeat_byte(0xFF); - let hash = Hash::repeat_byte(0xAA); - let state = state_without_reputation_delay(); - let _ = test_harness(state, |mut virtual_overseer| async move { - let overseer = &mut virtual_overseer; - // All peers are aware of relay parent. - setup_peer_with_view(overseer, &peer_a, view![hash], ValidationVersion::V2).await; - setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V1).await; - setup_peer_with_view(overseer, &peer_c, view![hash], ValidationVersion::V2).await; - - // Set up a gossip topology, where a, b, c and d are topology neighbors to the node under - // testing. - let peers_with_optional_peer_id = peers - .iter() - .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) - .collect_vec(); - setup_gossip_topology( - overseer, - make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), - ) - .await; + // send an obviously invalid approval + let approval = IndirectSignedApprovalVote { + block_hash: hash, + // Invalid candidate index, should not pass sanitization. + candidate_index: 16777284, + validator: validator_index, + signature: dummy_signature(), + }; + let msg = protocol_v2::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); + send_message_from_peer_v2(overseer, &peer_a, msg).await; - // new block `hash_a` with 1 candidates - let meta = BlockApprovalMeta { - hash, - parent_hash, - number: 1, - candidates: vec![Default::default(); 1], - slot: 1.into(), - session: 1, - }; - let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); - overseer_send(overseer, msg).await; - - // import an assignment related to `hash` locally - let validator_index = ValidatorIndex(0); - let candidate_index = 0u32; - let cert = fake_assignment_cert(hash, validator_index); - overseer_send( - overseer, - ApprovalDistributionMessage::DistributeAssignment(cert.into(), candidate_index.into()), - ) - .await; + expect_reputation_change(overseer, &peer_a, COST_OVERSIZED_BITFIELD).await; - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Assignments(assignments) - )) - )) => { - assert_eq!(peers, vec![peer_b]); - assert_eq!(assignments.len(), 1); - } - ); - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V2(protocol_v2::ValidationProtocol::ApprovalDistribution( - protocol_v2::ApprovalDistributionMessage::Assignments(assignments) - )) - )) => { - assert_eq!(peers.len(), 2); - assert!(peers.contains(&peer_a)); - assert!(peers.contains(&peer_c)); - - assert_eq!(assignments.len(), 1); - } - ); - - // send the an approval from peer_a - let approval = IndirectSignedApprovalVote { - block_hash: hash, - candidate_index, - validator: validator_index, - signature: dummy_signature(), - }; - let msg = protocol_v2::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer_v2(overseer, &peer_a, msg).await; - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::ApprovalVoting(ApprovalVotingMessage::CheckAndImportApproval( - vote, - tx, - )) => { - assert_eq!(vote, approval.into()); - tx.send(ApprovalCheckResult::Accepted).unwrap(); - } - ); - - expect_reputation_change(overseer, &peer_a, BENEFIT_VALID_MESSAGE_FIRST).await; - - // Peers b and c receive versioned approval messages. - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V1(protocol_v1::ValidationProtocol::ApprovalDistribution( - protocol_v1::ApprovalDistributionMessage::Approvals(approvals) - )) - )) => { - assert_eq!(peers, vec![peer_b]); - assert_eq!(approvals.len(), 1); - } - ); - - assert_matches!( - overseer_recv(overseer).await, - AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( - peers, - Versioned::V2(protocol_v2::ValidationProtocol::ApprovalDistribution( - protocol_v2::ApprovalDistributionMessage::Approvals(approvals) - )) - )) => { - assert_eq!(peers, vec![peer_c]); - assert_eq!(approvals.len(), 1); - } - ); - - // send an obviously invalid approval - let approval = IndirectSignedApprovalVote { - block_hash: hash, - // Invalid candidate index, should not pass sanitization. - candidate_index: 16777284, - validator: validator_index, - signature: dummy_signature(), - }; - let msg = protocol_v2::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer_v2(overseer, &peer_a, msg).await; - - expect_reputation_change(overseer, &peer_a, COST_OVERSIZED_BITFIELD).await; - - // send an obviously invalid approval - let approval = IndirectSignedApprovalVoteV2 { - block_hash: hash, - // Invalid candidates len, should not pass sanitization. - candidate_indices: 16777284.into(), - validator: validator_index, - signature: dummy_signature(), - }; - let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); - send_message_from_peer_v3(overseer, &peer_a, msg).await; + // send an obviously invalid approval + let approval = IndirectSignedApprovalVoteV2 { + block_hash: hash, + // Invalid candidates len, should not pass sanitization. + candidate_indices: 16777284.into(), + validator: validator_index, + signature: dummy_signature(), + }; + let msg = protocol_v3::ApprovalDistributionMessage::Approvals(vec![approval.clone()]); + send_message_from_peer_v3(overseer, &peer_a, msg).await; - expect_reputation_change(overseer, &peer_a, COST_OVERSIZED_BITFIELD).await; + expect_reputation_change(overseer, &peer_a, COST_OVERSIZED_BITFIELD).await; - virtual_overseer - }); + virtual_overseer + }, + ); } fn batch_test_round(message_count: usize) { @@ -3664,11 +4128,26 @@ fn batch_test_round(message_count: usize) { let (mut context, mut virtual_overseer) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool.clone()); - let subsystem = ApprovalDistribution::new(Default::default()); + let subsystem = ApprovalDistribution::new_with_clock( + Default::default(), + Default::default(), + Arc::new(SystemClock {}), + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + ); let mut rng = rand_chacha::ChaCha12Rng::seed_from_u64(12345); let mut sender = context.sender().clone(); - let subsystem = - subsystem.run_inner(context, &mut state, REPUTATION_CHANGE_TEST_INTERVAL, &mut rng); + let mut session_info_provider = RuntimeInfo::new_with_config(RuntimeInfoConfig { + keystore: None, + session_cache_lru_size: DISPUTE_WINDOW.get(), + }); + + let subsystem = subsystem.run_inner( + context, + &mut state, + REPUTATION_CHANGE_TEST_INTERVAL, + &mut rng, + &mut session_info_provider, + ); let test_fut = async move { let overseer = &mut virtual_overseer; @@ -3814,3 +4293,420 @@ fn const_ensure_size_not_zero() { crate::ensure_size_not_zero(super::MAX_ASSIGNMENT_BATCH_SIZE); crate::ensure_size_not_zero(super::MAX_APPROVAL_BATCH_SIZE); } + +struct DummyClock; +impl Clock for DummyClock { + fn tick_now(&self) -> polkadot_node_primitives::approval::time::Tick { + 0 + } + + fn wait( + &self, + _tick: polkadot_node_primitives::approval::time::Tick, + ) -> std::pin::Pin + Send + 'static>> { + todo!() + } +} + +/// Subsystem rejects assignments too far into the future. +#[test] +fn subsystem_rejects_assignment_in_future() { + let peers = make_peers_and_authority_ids(15); + let peer_a = peers.get(0).unwrap().0; + let parent_hash = Hash::repeat_byte(0xFF); + let hash = Hash::repeat_byte(0xAA); + + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(89) }), + Arc::new(DummyClock {}), + state_without_reputation_delay(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // setup peers + setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V1).await; + + // Set up a gossip topology, where a, b, c and d are topology neighbors to the node + // under testing. + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + setup_gossip_topology( + overseer, + make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), + ) + .await; + + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 2, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + // send the assignment related to `hash` + let validator_index = ValidatorIndex(0); + let cert = fake_assignment_cert(hash, validator_index); + let assignments = vec![(cert.clone(), 0u32)]; + setup_peer_with_view(overseer, &peer_a, view![hash], ValidationVersion::V3).await; + + let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); + send_message_from_peer(overseer, &peer_a, msg).await; + provide_session( + overseer, + dummy_session_info_valid(1, &mut LocalKeystore::in_memory(), 1), + ) + .await; + + expect_reputation_change(overseer, &peer_a, COST_ASSIGNMENT_TOO_FAR_IN_THE_FUTURE) + .await; + + virtual_overseer + }, + ); +} + +/// Subsystem rejects bad vrf assignments. +#[test] +fn subsystem_rejects_bad_assignments() { + let peers = make_peers_and_authority_ids(15); + let peer_a = peers.get(0).unwrap().0; + let parent_hash = Hash::repeat_byte(0xFF); + let hash = Hash::repeat_byte(0xAA); + + let _ = test_harness( + Arc::new(MockAssignmentCriteria { + tranche: Err(InvalidAssignment(criteria::InvalidAssignmentReason::NullAssignment)), + }), + Arc::new(DummyClock {}), + state_without_reputation_delay(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // setup peers + setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V1).await; + + // Set up a gossip topology, where a, b, c and d are topology neighbors to the node + // under testing. + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + setup_gossip_topology( + overseer, + make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), + ) + .await; + + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 2, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + // send the assignment related to `hash` + let validator_index = ValidatorIndex(0); + let cert = fake_assignment_cert(hash, validator_index); + let assignments = vec![(cert.clone(), 0u32)]; + setup_peer_with_view(overseer, &peer_a, view![hash], ValidationVersion::V3).await; + + let msg = protocol_v1::ApprovalDistributionMessage::Assignments(assignments.clone()); + send_message_from_peer(overseer, &peer_a, msg).await; + provide_session( + overseer, + dummy_session_info_valid(1, &mut LocalKeystore::in_memory(), 1), + ) + .await; + + expect_reputation_change(overseer, &peer_a, COST_INVALID_MESSAGE).await; + + virtual_overseer + }, + ); +} + +/// Subsystem rejects assignments that have invalid claimed candidates. +#[test] +fn subsystem_rejects_wrong_claimed_assignments() { + let peers = make_peers_and_authority_ids(15); + let peer_a = peers.get(0).unwrap().0; + let parent_hash = Hash::repeat_byte(0xFF); + let hash = Hash::repeat_byte(0xAA); + + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(DummyClock {}), + state_without_reputation_delay(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // setup peers + setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V1).await; + + // Set up a gossip topology, where a, b, c and d are topology neighbors to the node + // under testing. + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + setup_gossip_topology( + overseer, + make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), + ) + .await; + + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 2, + candidates: vec![Default::default(); 1], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + // send the assignment related to `hash` + let validator_index = ValidatorIndex(0); + + // Claimed core 1 which does not have a candidate included on it, so the assignment + // should be rejected. + let cores = vec![1]; + let core_bitfield: CoreBitfield = cores + .iter() + .map(|index| CoreIndex(*index)) + .collect::>() + .try_into() + .unwrap(); + let cert = fake_assignment_cert_v2(hash, validator_index, core_bitfield); + let assignments: Vec<(IndirectAssignmentCertV2, CandidateBitfield)> = + vec![(cert.clone(), cores.try_into().unwrap())]; + setup_peer_with_view(overseer, &peer_a, view![hash], ValidationVersion::V3).await; + + let msg = protocol_v3::ApprovalDistributionMessage::Assignments(assignments.clone()); + send_message_from_peer_v3(overseer, &peer_a, msg).await; + provide_session( + overseer, + dummy_session_info_valid(1, &mut LocalKeystore::in_memory(), 1), + ) + .await; + + expect_reputation_change(overseer, &peer_a, COST_INVALID_MESSAGE).await; + + virtual_overseer + }, + ); +} + +/// Subsystem accepts tranche0 duplicate assignments, sometimes on validator Compact tranche0 +/// assignment and Delay tranche assignments land on the same candidate. The delay tranche0 can be +/// safely ignored and we don't need to gossip it however, the compact tranche0 assignment should be +/// gossiped, because other candidates are included in it, this test makes sure this invariant is +/// upheld, see https://github.com/paritytech/polkadot/pull/2160#discussion_r557628699, for +/// this edge case. +#[test] +fn subsystem_accepts_tranche0_duplicate_assignments() { + let peers = make_peers_and_authority_ids(15); + let peer_a = peers.get(0).unwrap().0; + let peer_b = peers.get(1).unwrap().0; + let parent_hash = Hash::repeat_byte(0xFF); + let hash = Hash::repeat_byte(0xAA); + let candidate_hash_first = polkadot_primitives::CandidateHash(Hash::repeat_byte(0xBB)); + let candidate_hash_second = polkadot_primitives::CandidateHash(Hash::repeat_byte(0xCC)); + let candidate_hash_third = polkadot_primitives::CandidateHash(Hash::repeat_byte(0xBB)); + let candidate_hash_fourth = polkadot_primitives::CandidateHash(Hash::repeat_byte(0xBB)); + + let _ = test_harness( + Arc::new(MockAssignmentCriteria { tranche: Ok(0) }), + Arc::new(DummyClock {}), + state_without_reputation_delay(), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // setup peers + setup_peer_with_view(overseer, &peer_a, view![], ValidationVersion::V3).await; + setup_peer_with_view(overseer, &peer_b, view![], ValidationVersion::V3).await; + + // Set up a gossip topology, where a, b, c and d are topology neighbors to the node + // under testing. + let peers_with_optional_peer_id = peers + .iter() + .map(|(peer_id, authority)| (Some(*peer_id), authority.clone())) + .collect_vec(); + setup_gossip_topology( + overseer, + make_gossip_topology(1, &peers_with_optional_peer_id, &[0, 1], &[2, 4], 3), + ) + .await; + + // new block `hash_a` with 1 candidates + let meta = BlockApprovalMeta { + hash, + parent_hash, + number: 2, + candidates: vec![ + (candidate_hash_first, 0.into(), 0.into()), + (candidate_hash_second, 1.into(), 1.into()), + (candidate_hash_third, 2.into(), 2.into()), + (candidate_hash_fourth, 3.into(), 3.into()), + ], + slot: 1.into(), + session: 1, + vrf_story: RelayVRFStory(Default::default()), + }; + let msg = ApprovalDistributionMessage::NewBlocks(vec![meta]); + overseer_send(overseer, msg).await; + + // send the assignment related to `hash` + let validator_index = ValidatorIndex(0); + + setup_peer_with_view(overseer, &peer_a, view![hash], ValidationVersion::V3).await; + setup_peer_with_view(overseer, &peer_b, view![hash], ValidationVersion::V3).await; + + // 1. Compact assignment with multiple candidates, coming after delay assignment which + // covered just one of the candidate is still imported and gossiped. + let candidate_indices: CandidateBitfield = + vec![1 as CandidateIndex].try_into().unwrap(); + let core_bitfield = vec![CoreIndex(1)].try_into().unwrap(); + let cert = fake_assignment_cert_delay(hash, validator_index, core_bitfield); + let assignments: Vec<(IndirectAssignmentCertV2, CandidateBitfield)> = + vec![(cert.clone(), candidate_indices.clone())]; + let msg = protocol_v3::ApprovalDistributionMessage::Assignments(assignments.clone()); + send_message_from_peer_v3(overseer, &peer_a, msg).await; + provide_session( + overseer, + dummy_session_info_valid(1, &mut LocalKeystore::in_memory(), 1), + ) + .await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportAssignment( + assignment, + _, + )) => { + assert_eq!(assignment.candidate_indices(), &candidate_indices); + assert_eq!(assignment.assignment(), &cert.into()); + assert_eq!(assignment.tranche(), 0); + } + ); + + expect_reputation_change(overseer, &peer_a, BENEFIT_VALID_MESSAGE_FIRST).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers.len(), 1); + assert_eq!(assignments.len(), 1); + } + ); + + let candidate_indices: CandidateBitfield = + vec![0 as CandidateIndex, 1 as CandidateIndex].try_into().unwrap(); + let core_bitfield = vec![CoreIndex(0), CoreIndex(1)].try_into().unwrap(); + + let cert = fake_assignment_cert_v2(hash, validator_index, core_bitfield); + + let assignments: Vec<(IndirectAssignmentCertV2, CandidateBitfield)> = + vec![(cert.clone(), candidate_indices.clone())]; + let msg = protocol_v3::ApprovalDistributionMessage::Assignments(assignments.clone()); + send_message_from_peer_v3(overseer, &peer_a, msg).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportAssignment( + assignment, + _, + )) => { + assert_eq!(assignment.candidate_indices(), &candidate_indices); + assert_eq!(assignment.assignment(), &cert.into()); + assert_eq!(assignment.tranche(), 0); + } + ); + + expect_reputation_change(overseer, &peer_a, BENEFIT_VALID_MESSAGE_FIRST).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers.len(), 1); + assert_eq!(assignments.len(), 1); + } + ); + + // 2. Delay assignment coming after compact assignment that already covered the + // candidate is not gossiped anymore. + let candidate_indices: CandidateBitfield = + vec![2 as CandidateIndex, 3 as CandidateIndex].try_into().unwrap(); + let core_bitfield = vec![CoreIndex(2), CoreIndex(3)].try_into().unwrap(); + let cert = fake_assignment_cert_v2(hash, validator_index, core_bitfield); + let assignments: Vec<(IndirectAssignmentCertV2, CandidateBitfield)> = + vec![(cert.clone(), candidate_indices.clone())]; + let msg = protocol_v3::ApprovalDistributionMessage::Assignments(assignments.clone()); + send_message_from_peer_v3(overseer, &peer_a, msg).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::ApprovalVoting(ApprovalVotingMessage::ImportAssignment( + assignment, + _, + )) => { + assert_eq!(assignment.candidate_indices(), &candidate_indices); + assert_eq!(assignment.assignment(), &cert.into()); + assert_eq!(assignment.tranche(), 0); + } + ); + + expect_reputation_change(overseer, &peer_a, BENEFIT_VALID_MESSAGE_FIRST).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::SendValidationMessage( + peers, + Versioned::V3(protocol_v3::ValidationProtocol::ApprovalDistribution( + protocol_v3::ApprovalDistributionMessage::Assignments(assignments) + )) + )) => { + assert_eq!(peers.len(), 1); + assert_eq!(assignments.len(), 1); + } + ); + + let candidate_indices: CandidateBitfield = vec![3].try_into().unwrap(); + let core_bitfield = vec![CoreIndex(3)].try_into().unwrap(); + + let cert = fake_assignment_cert_delay(hash, validator_index, core_bitfield); + + let assignments: Vec<(IndirectAssignmentCertV2, CandidateBitfield)> = + vec![(cert.clone(), candidate_indices.clone())]; + let msg = protocol_v3::ApprovalDistributionMessage::Assignments(assignments.clone()); + send_message_from_peer_v3(overseer, &peer_a, msg).await; + + expect_reputation_change(overseer, &peer_a, COST_DUPLICATE_MESSAGE).await; + + 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 6083a90e4812..4467941c849c 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 ec2c01f99b01..438453814978 100644 --- a/polkadot/node/network/availability-distribution/src/lib.rs +++ b/polkadot/node/network/availability-distribution/src/lib.rs @@ -22,11 +22,9 @@ use polkadot_node_network_protocol::request_response::{ v1, v2, IncomingRequestReceiver, ReqProtocolNames, }; use polkadot_node_subsystem::{ - jaeger, messages::AvailabilityDistributionMessage, overseer, FromOrchestra, OverseerSignal, + messages::AvailabilityDistributionMessage, overseer, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemError, }; -use polkadot_primitives::Hash; -use std::collections::HashMap; /// Error and [`Result`] type for this subsystem. mod error; @@ -104,7 +102,6 @@ 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 IncomingRequestReceivers { pov_req_receiver, @@ -156,24 +153,16 @@ impl AvailabilityDistributionSubsystem { }; match message { FromOrchestra::Signal(OverseerSignal::ActiveLeaves(update)) => { - let cloned_leaf = match update.activated.clone() { - Some(activated) => activated, - None => continue, - }; - let span = - jaeger::PerLeafSpan::new(cloned_leaf.span, "availability-distribution"); - spans.insert(cloned_leaf.hash, span); log_error( requester .get_mut() - .update_fetching_heads(&mut ctx, &mut runtime, update, &spans) + .update_fetching_heads(&mut ctx, &mut runtime, update) .await, "Error in Requester::update_fetching_heads", &mut warn_freq, )?; }, - FromOrchestra::Signal(OverseerSignal::BlockFinalized(hash, _)) => { - spans.remove(&hash); + FromOrchestra::Signal(OverseerSignal::BlockFinalized(_hash, _finalized_number)) => { }, FromOrchestra::Signal(OverseerSignal::Conclude) => return Ok(()), FromOrchestra::Communication { @@ -187,15 +176,6 @@ impl AvailabilityDistributionSubsystem { tx, }, } => { - let span = spans - .get(&relay_parent) - .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) - .with_relay_parent(relay_parent) - .with_stage(jaeger::Stage::AvailabilityDistribution); - log_error( pov_requester::fetch_pov( &mut ctx, @@ -207,7 +187,6 @@ impl AvailabilityDistributionSubsystem { pov_hash, tx, metrics.clone(), - &span, ) .await, "pov_requester::fetch_pov", diff --git a/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs b/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs index 6c632fa7efee..5e26ae4b7a70 100644 --- a/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs +++ b/polkadot/node/network/availability-distribution/src/pov_requester/mod.rs @@ -25,7 +25,6 @@ use polkadot_node_network_protocol::request_response::{ }; use polkadot_node_primitives::PoV; use polkadot_node_subsystem::{ - jaeger, messages::{IfDisconnected, NetworkBridgeTxMessage}, overseer, }; @@ -52,18 +51,7 @@ pub async fn fetch_pov( pov_hash: Hash, tx: oneshot::Sender, metrics: Metrics, - span: &jaeger::Span, ) -> Result<()> { - let _span = span - .child("fetch-pov") - .with_trace_id(candidate_hash) - .with_validator_index(from_validator) - .with_candidate(candidate_hash) - .with_para_id(para_id) - .with_relay_parent(parent) - .with_string_tag("pov-hash", format!("{:?}", pov_hash)) - .with_stage(jaeger::Stage::AvailabilityDistribution); - let info = &runtime.get_session_info(ctx.sender(), parent).await?.session_info; let authority_id = info .discovery_keys @@ -189,7 +177,6 @@ mod tests { pov_hash, tx, Metrics::new_dummy(), - &jaeger::Span::Disabled, ) .await .expect("Should succeed"); diff --git a/polkadot/node/network/availability-distribution/src/requester/fetch_task/mod.rs b/polkadot/node/network/availability-distribution/src/requester/fetch_task/mod.rs index 278608cc858d..5be6f2d223a8 100644 --- a/polkadot/node/network/availability-distribution/src/requester/fetch_task/mod.rs +++ b/polkadot/node/network/availability-distribution/src/requester/fetch_task/mod.rs @@ -31,7 +31,6 @@ use polkadot_node_network_protocol::request_response::{ }; use polkadot_node_primitives::ErasureChunk; use polkadot_node_subsystem::{ - jaeger, messages::{AvailabilityStoreMessage, IfDisconnected, NetworkBridgeTxMessage}, overseer, }; @@ -129,9 +128,6 @@ struct RunningTask { /// Prometheus metrics for reporting results. metrics: Metrics, - /// Span tracking the fetching of this chunk. - span: jaeger::Span, - /// Expected chunk index. We'll validate that the remote did send us the correct chunk (only /// important for v2 requests). chunk_index: ChunkIndex, @@ -154,21 +150,9 @@ impl FetchTaskConfig { metrics: Metrics, session_info: &SessionInfo, chunk_index: ChunkIndex, - span: jaeger::Span, req_v1_protocol_name: ProtocolName, req_v2_protocol_name: ProtocolName, ) -> Self { - let span = span - .child("fetch-task-config") - .with_trace_id(core.candidate_hash) - .with_string_tag("leaf", format!("{:?}", leaf)) - .with_validator_index(session_info.our_index) - .with_chunk_index(chunk_index) - .with_uint_tag("group-index", core.group_responsible.0 as u64) - .with_relay_parent(core.candidate_descriptor.relay_parent) - .with_string_tag("pov-hash", format!("{:?}", core.candidate_descriptor.pov_hash)) - .with_stage(jaeger::Stage::AvailabilityDistribution); - let live_in = vec![leaf].into_iter().collect(); // Don't run tasks for our backing group: @@ -190,7 +174,6 @@ impl FetchTaskConfig { relay_parent: core.candidate_descriptor.relay_parent, metrics, sender, - span, chunk_index, req_v1_protocol_name, req_v2_protocol_name @@ -279,7 +262,6 @@ impl RunningTask { let mut bad_validators = Vec::new(); let mut succeeded = false; let mut count: u32 = 0; - let mut span = self.span.child("run-fetch-chunk-task").with_relay_parent(self.relay_parent); let mut network_error_freq = gum::Freq::new(); let mut canceled_freq = gum::Freq::new(); // Try validators in reverse order: @@ -289,11 +271,7 @@ impl RunningTask { self.metrics.on_retry(); } count += 1; - let _chunk_fetch_span = span - .child("fetch-chunk-request") - .with_validator_index(self.request.index) - .with_chunk_index(self.chunk_index) - .with_stage(jaeger::Stage::AvailabilityDistribution); + // Send request: let resp = match self .do_request(&validator, &mut network_error_freq, &mut canceled_freq) @@ -313,13 +291,7 @@ impl RunningTask { continue }, }; - // We drop the span here, so that the span is not active while we recombine the chunk. - drop(_chunk_fetch_span); - let _chunk_recombine_span = span - .child("recombine-chunk") - .with_validator_index(self.request.index) - .with_chunk_index(self.chunk_index) - .with_stage(jaeger::Stage::AvailabilityDistribution); + let chunk = match resp { Some(chunk) => chunk, None => { @@ -337,14 +309,6 @@ impl RunningTask { continue }, }; - // We drop the span so that the span is not active whilst we validate and store the - // chunk. - drop(_chunk_recombine_span); - let _chunk_validate_and_store_span = span - .child("validate-and-store-chunk") - .with_validator_index(self.request.index) - .with_chunk_index(self.chunk_index) - .with_stage(jaeger::Stage::AvailabilityDistribution); // Data genuine? if !self.validate_chunk(&validator, &chunk, self.chunk_index) { @@ -357,7 +321,6 @@ impl RunningTask { succeeded = true; break } - span.add_int_tag("tries", count as _); if succeeded { self.metrics.on_fetch(SUCCEEDED); self.conclude(bad_validators).await; diff --git a/polkadot/node/network/availability-distribution/src/requester/fetch_task/tests.rs b/polkadot/node/network/availability-distribution/src/requester/fetch_task/tests.rs index 2cd4bf29a563..9d4ac5bc4b1b 100644 --- a/polkadot/node/network/availability-distribution/src/requester/fetch_task/tests.rs +++ b/polkadot/node/network/availability-distribution/src/requester/fetch_task/tests.rs @@ -365,7 +365,6 @@ fn get_test_running_task( relay_parent: Hash::repeat_byte(71), sender: tx, metrics: Metrics::new_dummy(), - span: jaeger::Span::Disabled, req_v1_protocol_name: req_protocol_names.get_name(Protocol::ChunkFetchingV1), req_v2_protocol_name: req_protocol_names.get_name(Protocol::ChunkFetchingV2), chunk_index, diff --git a/polkadot/node/network/availability-distribution/src/requester/mod.rs b/polkadot/node/network/availability-distribution/src/requester/mod.rs index efbdceb43bdd..233825032724 100644 --- a/polkadot/node/network/availability-distribution/src/requester/mod.rs +++ b/polkadot/node/network/availability-distribution/src/requester/mod.rs @@ -31,7 +31,6 @@ use futures::{ use polkadot_node_network_protocol::request_response::{v1, v2, IsRequest, ReqProtocolNames}; use polkadot_node_subsystem::{ - jaeger, messages::{ChainApiMessage, RuntimeApiMessage}, overseer, ActivatedLeaf, ActiveLeavesUpdate, }; @@ -112,21 +111,13 @@ impl Requester { ctx: &mut Context, runtime: &mut RuntimeInfo, update: ActiveLeavesUpdate, - 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")) - .unwrap_or_else(|| jaeger::Span::new(&leaf.hash, "update-fetching-heads")) - .with_string_tag("leaf", format!("{:?}", leaf.hash)) - .with_stage(jaeger::Stage::AvailabilityDistribution); - // Order important! We need to handle activated, prior to deactivated, otherwise we // might cancel still needed jobs. - self.start_requesting_chunks(ctx, runtime, leaf, &span).await?; + self.start_requesting_chunks(ctx, runtime, leaf).await?; } self.stop_requesting_chunks(deactivated.into_iter()); @@ -142,13 +133,7 @@ impl Requester { ctx: &mut Context, runtime: &mut RuntimeInfo, new_head: ActivatedLeaf, - span: &jaeger::Span, ) -> Result<()> { - let mut span = span - .child("request-chunks-new-head") - .with_string_tag("leaf", format!("{:?}", new_head.hash)) - .with_stage(jaeger::Stage::AvailabilityDistribution); - let sender = &mut ctx.sender().clone(); let ActivatedLeaf { hash: leaf, .. } = new_head; let (leaf_session_index, ancestors_in_session) = get_block_ancestors_in_same_session( @@ -158,15 +143,9 @@ impl Requester { Self::LEAF_ANCESTRY_LEN_WITHIN_SESSION, ) .await?; - span.add_uint_tag("ancestors-in-session", ancestors_in_session.len() as u64); // Also spawn or bump tasks for candidates in ancestry in the same session. for hash in std::iter::once(leaf).chain(ancestors_in_session) { - let span = span - .child("request-chunks-ancestor") - .with_string_tag("leaf", format!("{:?}", hash.clone())) - .with_stage(jaeger::Stage::AvailabilityDistribution); - let cores = get_occupied_cores(sender, hash).await?; gum::trace!( target: LOG_TARGET, @@ -180,7 +159,7 @@ impl Requester { // The next time the subsystem receives leaf update, some of spawned task will be bumped // to be live in fresh relay parent, while some might get dropped due to the current // leaf being deactivated. - self.add_cores(ctx, runtime, leaf, leaf_session_index, cores, span).await?; + self.add_cores(ctx, runtime, leaf, leaf_session_index, cores).await?; } Ok(()) @@ -209,22 +188,12 @@ impl Requester { leaf: Hash, leaf_session_index: SessionIndex, cores: impl IntoIterator, - span: jaeger::Span, ) -> Result<()> { for (core_index, core) in cores { - let mut span = span - .child("check-fetch-candidate") - .with_trace_id(core.candidate_hash) - .with_string_tag("leaf", format!("{:?}", leaf)) - .with_candidate(core.candidate_hash) - .with_stage(jaeger::Stage::AvailabilityDistribution); - if let Some(e) = self.fetches.get_mut(&core.candidate_hash) { // Just book keeping - we are already requesting that chunk: - span.add_string_tag("already-requested-chunk", "true"); e.add_leaf(leaf); } else { - span.add_string_tag("already-requested-chunk", "false"); let tx = self.tx.clone(); let metrics = self.metrics.clone(); @@ -270,7 +239,6 @@ impl Requester { metrics, session_info, chunk_index, - span, self.req_protocol_names.get_name(v1::ChunkFetchingRequest::PROTOCOL), self.req_protocol_names.get_name(v2::ChunkFetchingRequest::PROTOCOL), ); diff --git a/polkadot/node/network/availability-distribution/src/requester/tests.rs b/polkadot/node/network/availability-distribution/src/requester/tests.rs index 09567a8f87d3..021f6da7e2e9 100644 --- a/polkadot/node/network/availability-distribution/src/requester/tests.rs +++ b/polkadot/node/network/availability-distribution/src/requester/tests.rs @@ -15,9 +15,9 @@ // along with Polkadot. If not, see . use futures::FutureExt; -use std::{collections::HashMap, future::Future}; +use std::future::Future; -use polkadot_node_network_protocol::{jaeger, request_response::ReqProtocolNames}; +use polkadot_node_network_protocol::request_response::ReqProtocolNames; use polkadot_node_primitives::{BlockData, ErasureChunk, PoV}; use polkadot_node_subsystem_util::runtime::RuntimeInfo; use polkadot_primitives::{ @@ -208,7 +208,6 @@ 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 block_number = 1; let update = ActiveLeavesUpdate { activated: Some(new_leaf(chain[block_number], block_number as u32)), @@ -216,7 +215,7 @@ fn check_ancestry_lookup_in_same_session() { }; requester - .update_fetching_heads(&mut ctx, &mut runtime, update, &spans) + .update_fetching_heads(&mut ctx, &mut runtime, update) .await .expect("Leaf processing failed"); let fetch_tasks = &requester.fetches; @@ -231,7 +230,7 @@ fn check_ancestry_lookup_in_same_session() { }; requester - .update_fetching_heads(&mut ctx, &mut runtime, update, &spans) + .update_fetching_heads(&mut ctx, &mut runtime, update) .await .expect("Leaf processing failed"); let fetch_tasks = &requester.fetches; @@ -252,7 +251,7 @@ fn check_ancestry_lookup_in_same_session() { deactivated: vec![chain[1], chain[2]].into(), }; requester - .update_fetching_heads(&mut ctx, &mut runtime, update, &spans) + .update_fetching_heads(&mut ctx, &mut runtime, update) .await .expect("Leaf processing failed"); let fetch_tasks = &requester.fetches; @@ -281,7 +280,6 @@ 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 block_number = 3; let update = ActiveLeavesUpdate { activated: Some(new_leaf(chain[block_number], block_number as u32)), @@ -289,7 +287,7 @@ fn check_ancestry_lookup_in_different_sessions() { }; requester - .update_fetching_heads(&mut ctx, &mut runtime, update, &spans) + .update_fetching_heads(&mut ctx, &mut runtime, update) .await .expect("Leaf processing failed"); let fetch_tasks = &requester.fetches; @@ -302,7 +300,7 @@ fn check_ancestry_lookup_in_different_sessions() { }; requester - .update_fetching_heads(&mut ctx, &mut runtime, update, &spans) + .update_fetching_heads(&mut ctx, &mut runtime, update) .await .expect("Leaf processing failed"); let fetch_tasks = &requester.fetches; @@ -315,7 +313,7 @@ fn check_ancestry_lookup_in_different_sessions() { }; requester - .update_fetching_heads(&mut ctx, &mut runtime, update, &spans) + .update_fetching_heads(&mut ctx, &mut runtime, update) .await .expect("Leaf processing failed"); let fetch_tasks = &requester.fetches; diff --git a/polkadot/node/network/availability-distribution/src/responder.rs b/polkadot/node/network/availability-distribution/src/responder.rs index fb08c4712503..6512fcb7f656 100644 --- a/polkadot/node/network/availability-distribution/src/responder.rs +++ b/polkadot/node/network/availability-distribution/src/responder.rs @@ -27,7 +27,7 @@ use polkadot_node_network_protocol::{ UnifiedReputationChange as Rep, }; use polkadot_node_primitives::{AvailableData, ErasureChunk}; -use polkadot_node_subsystem::{jaeger, messages::AvailabilityStoreMessage, SubsystemSender}; +use polkadot_node_subsystem::{messages::AvailabilityStoreMessage, SubsystemSender}; use polkadot_primitives::{CandidateHash, ValidatorIndex}; use crate::{ @@ -193,8 +193,6 @@ pub async fn answer_pov_request( where Sender: SubsystemSender, { - let _span = jaeger::Span::new(req.payload.candidate_hash, "answer-pov-request"); - let av_data = query_available_data(sender, req.payload.candidate_hash).await?; let result = av_data.is_some(); @@ -228,12 +226,6 @@ where // V1 and V2 requests have the same payload, so decoding into either one will work. It's the // responses that differ, hence the `MakeResp` generic. let payload: v1::ChunkFetchingRequest = req.payload.into(); - let span = jaeger::Span::new(payload.candidate_hash, "answer-chunk-request"); - - let _child_span = span - .child("answer-chunk-request") - .with_trace_id(payload.candidate_hash) - .with_validator_index(payload.index); let chunk = query_chunk(sender, payload.candidate_hash, payload.index).await?; diff --git a/polkadot/node/network/availability-distribution/src/tests/mod.rs b/polkadot/node/network/availability-distribution/src/tests/mod.rs index 3320871bceb5..078220607c37 100644 --- a/polkadot/node/network/availability-distribution/src/tests/mod.rs +++ b/polkadot/node/network/availability-distribution/src/tests/mod.rs @@ -45,7 +45,7 @@ fn test_harness>( let (context, virtual_overseer) = polkadot_node_subsystem_test_helpers::make_subsystem_context(pool.clone()); - let (pov_req_receiver, pov_req_cfg) = IncomingRequest::get_config_receiver::< + let (pov_req_receiver, _pov_req_cfg) = IncomingRequest::get_config_receiver::< Block, sc_network::NetworkWorker, >(&req_protocol_names); @@ -65,13 +65,8 @@ fn test_harness>( ); let subsystem = subsystem.run(context); - let test_fut = test_fx(TestHarness { - virtual_overseer, - pov_req_cfg, - chunk_req_v1_cfg, - chunk_req_v2_cfg, - pool, - }); + let test_fut = + test_fx(TestHarness { virtual_overseer, chunk_req_v1_cfg, chunk_req_v2_cfg, pool }); futures::pin_mut!(test_fut); futures::pin_mut!(subsystem); diff --git a/polkadot/node/network/availability-distribution/src/tests/state.rs b/polkadot/node/network/availability-distribution/src/tests/state.rs index 97e616f79fb7..53d6fd2c530f 100644 --- a/polkadot/node/network/availability-distribution/src/tests/state.rs +++ b/polkadot/node/network/availability-distribution/src/tests/state.rs @@ -60,7 +60,6 @@ type VirtualOverseer = polkadot_node_subsystem_test_helpers::TestSubsystemContex >; pub struct TestHarness { pub virtual_overseer: VirtualOverseer, - pub pov_req_cfg: RequestResponseConfig, pub chunk_req_v1_cfg: RequestResponseConfig, pub chunk_req_v2_cfg: RequestResponseConfig, pub pool: TaskExecutor, diff --git a/polkadot/node/network/availability-recovery/src/lib.rs b/polkadot/node/network/availability-recovery/src/lib.rs index 167125f987ab..114faa2859c4 100644 --- a/polkadot/node/network/availability-recovery/src/lib.rs +++ b/polkadot/node/network/availability-recovery/src/lib.rs @@ -57,7 +57,6 @@ use polkadot_node_network_protocol::{ use polkadot_node_primitives::AvailableData; use polkadot_node_subsystem::{ errors::RecoveryError, - jaeger, messages::{AvailabilityRecoveryMessage, AvailabilityStoreMessage}, overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, SpawnedSubsystem, SubsystemContext, SubsystemError, @@ -387,9 +386,6 @@ async fn handle_recover( ) -> Result<()> { let candidate_hash = receipt.hash(); - let span = jaeger::Span::new(candidate_hash, "availability-recovery") - .with_stage(jaeger::Stage::AvailabilityRecovery); - if let Some(result) = state.availability_lru.get(&candidate_hash).cloned().map(|v| v.into_result()) { @@ -403,13 +399,11 @@ async fn handle_recover( return Ok(()) } - let _span = span.child("not-cached"); let session_info_res = state .runtime_info .get_session_info_by_index(ctx.sender(), state.live_block.1, session_index) .await; - let _span = span.child("session-info-ctx-received"); match session_info_res { Ok(ExtendedSessionInfo { session_info, node_features, .. }) => { let mut backer_group = None; diff --git a/polkadot/node/network/availability-recovery/src/task/strategy/chunks.rs b/polkadot/node/network/availability-recovery/src/task/strategy/chunks.rs index b6376a5b543e..6b34538b6266 100644 --- a/polkadot/node/network/availability-recovery/src/task/strategy/chunks.rs +++ b/polkadot/node/network/availability-recovery/src/task/strategy/chunks.rs @@ -107,9 +107,10 @@ impl FetchChunks { state: &mut State, common_params: &RecoveryParams, ) -> Result { - let recovery_duration = common_params - .metrics - .time_erasure_recovery(RecoveryStrategy::::strategy_type(self)); + let recovery_duration = + common_params + .metrics + .time_erasure_recovery(RecoveryStrategy::::strategy_type(self)); // Send request to reconstruct available data from chunks. let (avilable_data_tx, available_data_rx) = oneshot::channel(); @@ -136,18 +137,16 @@ impl FetchChunks { // Attempt post-recovery check. Ok(data) => do_post_recovery_check(common_params, data) .await - .map_err(|e| { + .inspect_err(|_| { recovery_duration.map(|rd| rd.stop_and_discard()); - e }) - .map(|data| { + .inspect(|_| { gum::trace!( target: LOG_TARGET, candidate_hash = ?common_params.candidate_hash, erasure_root = ?common_params.erasure_root, "Data recovery from chunks complete", ); - data }), Err(err) => { recovery_duration.map(|rd| rd.stop_and_discard()); diff --git a/polkadot/node/network/availability-recovery/src/task/strategy/systematic.rs b/polkadot/node/network/availability-recovery/src/task/strategy/systematic.rs index 677bc2d1375a..8b8cff549912 100644 --- a/polkadot/node/network/availability-recovery/src/task/strategy/systematic.rs +++ b/polkadot/node/network/availability-recovery/src/task/strategy/systematic.rs @@ -125,18 +125,16 @@ impl FetchSystematicChunks { // Attempt post-recovery check. do_post_recovery_check(common_params, data) .await - .map_err(|e| { + .inspect_err(|_| { recovery_duration.map(|rd| rd.stop_and_discard()); - e }) - .map(|data| { + .inspect(|_| { gum::trace!( target: LOG_TARGET, candidate_hash = ?common_params.candidate_hash, erasure_root = ?common_params.erasure_root, "Data recovery from systematic chunks complete", ); - data }) }, Err(err) => { diff --git a/polkadot/node/network/bitfield-distribution/Cargo.toml b/polkadot/node/network/bitfield-distribution/Cargo.toml index b1becaf319d5..6d007255c574 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/lib.rs b/polkadot/node/network/bitfield-distribution/src/lib.rs index 029401e0bd51..3003f970a641 100644 --- a/polkadot/node/network/bitfield-distribution/src/lib.rs +++ b/polkadot/node/network/bitfield-distribution/src/lib.rs @@ -36,8 +36,8 @@ use polkadot_node_network_protocol::{ UnifiedReputationChange as Rep, Versioned, View, }; use polkadot_node_subsystem::{ - jaeger, messages::*, overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, PerLeafSpan, - SpawnedSubsystem, SubsystemError, SubsystemResult, + messages::*, overseer, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, SpawnedSubsystem, + SubsystemError, SubsystemResult, }; use polkadot_node_subsystem_util::{ self as util, @@ -177,22 +177,14 @@ struct PerRelayParentData { /// Track messages that were already received by a peer /// to prevent flooding. message_received_from_peer: HashMap>, - - /// The span for this leaf/relay parent. - span: PerLeafSpan, } impl PerRelayParentData { /// Create a new instance. - fn new( - signing_context: SigningContext, - validator_set: Vec, - span: PerLeafSpan, - ) -> Self { + fn new(signing_context: SigningContext, validator_set: Vec) -> Self { Self { signing_context, validator_set, - span, one_per_validator: Default::default(), message_sent_to_peer: Default::default(), message_received_from_peer: Default::default(), @@ -304,8 +296,6 @@ impl BitfieldDistribution { let relay_parent = activated.hash; gum::trace!(target: LOG_TARGET, ?relay_parent, "activated"); - let span = PerLeafSpan::new(activated.span, "bitfield-distribution"); - let _span = span.child("query-basics"); // query validator set and signing context per relay_parent once only match query_basics(&mut ctx, relay_parent).await { @@ -317,7 +307,7 @@ impl BitfieldDistribution { // us anything to do with this relay-parent anyway. let _ = state.per_relay_parent.insert( relay_parent, - PerRelayParentData::new(signing_context, validator_set, span), + PerRelayParentData::new(signing_context, validator_set), ); }, Err(err) => { @@ -430,9 +420,7 @@ async fn relay_message( rng: &mut (impl CryptoRng + Rng), ) { let relay_parent = message.relay_parent; - let span = job_data.span.child("relay-msg"); - let _span = span.child("provisionable"); // notify the overseer about a new and valid signed bitfield ctx.send_message(ProvisionerMessage::ProvisionableData( relay_parent, @@ -440,11 +428,9 @@ async fn relay_message( )) .await; - drop(_span); let total_peers = peers.len(); let mut random_routing: RandomRouting = Default::default(); - let _span = span.child("interested-peers"); // pass on the bitfield distribution to all interested peers let interested_peers = peers .iter() @@ -487,8 +473,6 @@ async fn relay_message( .insert(validator.clone()); }); - drop(_span); - if interested_peers.is_empty() { gum::trace!( target: LOG_TARGET, @@ -496,8 +480,6 @@ async fn relay_message( "no peers are interested in gossip for relay parent", ); } else { - let _span = span.child("gossip"); - let v1_interested_peers = filter_by_peer_version(&interested_peers, ValidationVersion::V1.into()); let v2_interested_peers = @@ -594,14 +576,6 @@ async fn process_incoming_peer_message( let validator_index = bitfield.unchecked_validator_index(); - let mut _span = job_data - .span - .child("msg-received") - .with_peer_id(&origin) - .with_relay_parent(relay_parent) - .with_claimed_validator_index(validator_index) - .with_stage(jaeger::Stage::BitfieldDistribution); - let validator_set = &job_data.validator_set; if validator_set.is_empty() { gum::trace!(target: LOG_TARGET, ?relay_parent, ?origin, "Validator set is empty",); @@ -914,7 +888,6 @@ async fn send_tracked_gossip_message( return }; - let _span = job_data.span.child("gossip"); gum::trace!( target: LOG_TARGET, ?dest, diff --git a/polkadot/node/network/bitfield-distribution/src/tests.rs b/polkadot/node/network/bitfield-distribution/src/tests.rs index dc37f73ec8a1..66a3c3f70909 100644 --- a/polkadot/node/network/bitfield-distribution/src/tests.rs +++ b/polkadot/node/network/bitfield-distribution/src/tests.rs @@ -25,11 +25,7 @@ use polkadot_node_network_protocol::{ peer_set::ValidationVersion, view, ObservedRole, }; -use polkadot_node_subsystem::{ - jaeger, - jaeger::{PerLeafSpan, Span}, - messages::ReportPeerMessage, -}; +use polkadot_node_subsystem::messages::ReportPeerMessage; use polkadot_node_subsystem_test_helpers::make_subsystem_context; use polkadot_node_subsystem_util::TimeoutExt; use polkadot_primitives::{AvailabilityBitfield, Signed, ValidatorIndex}; @@ -86,7 +82,6 @@ fn prewarmed_state( }, message_received_from_peer: hashmap!{}, message_sent_to_peer: hashmap!{}, - span: PerLeafSpan::new(Arc::new(jaeger::Span::Disabled), "test"), }, }, peer_data: peers @@ -124,7 +119,6 @@ fn state_with_view( one_per_validator: hashmap! {}, message_received_from_peer: hashmap! {}, message_sent_to_peer: hashmap! {}, - span: PerLeafSpan::new(Arc::new(jaeger::Span::Disabled), "test"), }, ) }) @@ -137,10 +131,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 +245,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 +305,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 +427,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 +532,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 +637,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 +809,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 +893,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(); @@ -1048,11 +1018,7 @@ fn need_message_works() { let validator_set = Vec::from_iter(validators.iter().map(|k| ValidatorId::from(k.public()))); let signing_context = SigningContext { session_index: 1, parent_hash: Hash::repeat_byte(0x00) }; - let mut state = PerRelayParentData::new( - signing_context, - validator_set.clone(), - PerLeafSpan::new(Arc::new(Span::Disabled), "foo"), - ); + let mut state = PerRelayParentData::new(signing_context, validator_set.clone()); let peer_a = PeerId::random(); let peer_b = PeerId::random(); diff --git a/polkadot/node/network/bridge/src/network.rs b/polkadot/node/network/bridge/src/network.rs index b31359f48a56..1f438df2d148 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 56965ce6ba40..bb99536f7833 100644 --- a/polkadot/node/network/bridge/src/rx/mod.rs +++ b/polkadot/node/network/bridge/src/rx/mod.rs @@ -45,8 +45,9 @@ use polkadot_node_subsystem::{ errors::SubsystemError, messages::{ network_bridge_event::NewGossipTopology, ApprovalDistributionMessage, - BitfieldDistributionMessage, CollatorProtocolMessage, GossipSupportMessage, - NetworkBridgeEvent, NetworkBridgeRxMessage, StatementDistributionMessage, + ApprovalVotingParallelMessage, BitfieldDistributionMessage, CollatorProtocolMessage, + GossipSupportMessage, NetworkBridgeEvent, NetworkBridgeRxMessage, + StatementDistributionMessage, }, overseer, ActivatedLeaf, ActiveLeavesUpdate, FromOrchestra, OverseerSignal, SpawnedSubsystem, }; @@ -89,6 +90,7 @@ pub struct NetworkBridgeRx { validation_service: Box, collation_service: Box, notification_sinks: Arc>>>, + approval_voting_parallel_enabled: bool, } impl NetworkBridgeRx { @@ -105,6 +107,7 @@ impl NetworkBridgeRx { peerset_protocol_names: PeerSetProtocolNames, mut notification_services: HashMap>, notification_sinks: Arc>>>, + approval_voting_parallel_enabled: bool, ) -> Self { let shared = Shared::default(); @@ -125,6 +128,7 @@ impl NetworkBridgeRx { validation_service, collation_service, notification_sinks, + approval_voting_parallel_enabled, } } } @@ -156,6 +160,7 @@ async fn handle_validation_message( peerset_protocol_names: &PeerSetProtocolNames, notification_service: &mut Box, notification_sinks: &mut Arc>>>, + approval_voting_parallel_enabled: bool, ) where AD: validator_discovery::AuthorityDiscovery + Send, { @@ -276,6 +281,7 @@ async fn handle_validation_message( ], sender, &metrics, + approval_voting_parallel_enabled, ) .await; @@ -329,6 +335,7 @@ async fn handle_validation_message( NetworkBridgeEvent::PeerDisconnected(peer), sender, &metrics, + approval_voting_parallel_enabled, ) .await; } @@ -398,7 +405,13 @@ async fn handle_validation_message( network_service.report_peer(peer, report.into()); } - dispatch_validation_events_to_all(events, sender, &metrics).await; + dispatch_validation_events_to_all( + events, + sender, + &metrics, + approval_voting_parallel_enabled, + ) + .await; }, } } @@ -652,6 +665,7 @@ async fn handle_network_messages( mut validation_service: Box, mut collation_service: Box, mut notification_sinks: Arc>>>, + approval_voting_parallel_enabled: bool, ) -> Result<(), Error> where AD: validator_discovery::AuthorityDiscovery + Send, @@ -669,6 +683,7 @@ where &peerset_protocol_names, &mut validation_service, &mut notification_sinks, + approval_voting_parallel_enabled, ).await, None => return Err(Error::EventStreamConcluded), }, @@ -727,6 +742,7 @@ async fn run_incoming_orchestra_signals( sync_oracle: Box, metrics: Metrics, notification_sinks: Arc>>>, + approval_voting_parallel_enabled: bool, ) -> Result<(), Error> where AD: validator_discovery::AuthorityDiscovery + Clone, @@ -766,6 +782,7 @@ where local_index, }), ctx.sender(), + approval_voting_parallel_enabled, ); }, FromOrchestra::Communication { @@ -787,6 +804,7 @@ where dispatch_validation_event_to_all_unbounded( NetworkBridgeEvent::UpdatedAuthorityIds(peer_id, authority_ids), ctx.sender(), + approval_voting_parallel_enabled, ); }, FromOrchestra::Signal(OverseerSignal::Conclude) => return Ok(()), @@ -826,6 +844,7 @@ where finalized_number, &metrics, ¬ification_sinks, + approval_voting_parallel_enabled, ); note_peers_count(&metrics, &shared); } @@ -875,6 +894,7 @@ where validation_service, collation_service, notification_sinks, + approval_voting_parallel_enabled, } = bridge; let (task, network_event_handler) = handle_network_messages( @@ -887,6 +907,7 @@ where validation_service, collation_service, notification_sinks.clone(), + approval_voting_parallel_enabled, ) .remote_handle(); @@ -900,6 +921,7 @@ where sync_oracle, metrics, notification_sinks, + approval_voting_parallel_enabled, ); futures::pin_mut!(orchestra_signal_handler); @@ -926,6 +948,7 @@ fn update_our_view( finalized_number: BlockNumber, metrics: &Metrics, notification_sinks: &Arc>>>, + approval_voting_parallel_enabled: bool, ) { let new_view = construct_view(live_heads.iter().map(|v| v.hash), finalized_number); @@ -962,6 +985,22 @@ fn update_our_view( ) }; + let our_view = OurView::new( + live_heads.iter().take(MAX_VIEW_HEADS).cloned().map(|a| a.hash), + finalized_number, + ); + + dispatch_validation_event_to_all_unbounded( + NetworkBridgeEvent::OurViewChange(our_view.clone()), + ctx.sender(), + approval_voting_parallel_enabled, + ); + + 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 +1046,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 @@ -1081,8 +1105,15 @@ async fn dispatch_validation_event_to_all( event: NetworkBridgeEvent, ctx: &mut impl overseer::NetworkBridgeRxSenderTrait, metrics: &Metrics, + approval_voting_parallel_enabled: bool, ) { - dispatch_validation_events_to_all(std::iter::once(event), ctx, metrics).await + dispatch_validation_events_to_all( + std::iter::once(event), + ctx, + metrics, + approval_voting_parallel_enabled, + ) + .await } async fn dispatch_collation_event_to_all( @@ -1095,6 +1126,7 @@ async fn dispatch_collation_event_to_all( fn dispatch_validation_event_to_all_unbounded( event: NetworkBridgeEvent, sender: &mut impl overseer::NetworkBridgeRxSenderTrait, + approval_voting_parallel_enabled: bool, ) { event .focus() @@ -1106,11 +1138,20 @@ fn dispatch_validation_event_to_all_unbounded( .ok() .map(BitfieldDistributionMessage::from) .and_then(|msg| Some(sender.send_unbounded_message(msg))); - event - .focus() - .ok() - .map(ApprovalDistributionMessage::from) - .and_then(|msg| Some(sender.send_unbounded_message(msg))); + + if approval_voting_parallel_enabled { + event + .focus() + .ok() + .map(ApprovalVotingParallelMessage::from) + .and_then(|msg| Some(sender.send_unbounded_message(msg))); + } else { + event + .focus() + .ok() + .map(ApprovalDistributionMessage::from) + .and_then(|msg| Some(sender.send_unbounded_message(msg))); + } event .focus() .ok() @@ -1131,6 +1172,7 @@ async fn dispatch_validation_events_to_all( events: I, sender: &mut impl overseer::NetworkBridgeRxSenderTrait, _metrics: &Metrics, + approval_voting_parallel_enabled: bool, ) where I: IntoIterator>, I::IntoIter: Send, @@ -1160,7 +1202,11 @@ async fn dispatch_validation_events_to_all( for event in events { send_message!(event, StatementDistributionMessage); send_message!(event, BitfieldDistributionMessage); - send_message!(event, ApprovalDistributionMessage); + if approval_voting_parallel_enabled { + send_message!(event, ApprovalVotingParallelMessage); + } else { + send_message!(event, ApprovalDistributionMessage); + } send_message!(event, GossipSupportMessage); } } diff --git a/polkadot/node/network/bridge/src/rx/tests.rs b/polkadot/node/network/bridge/src/rx/tests.rs index 392ff7391a1c..e3f2715ef2b0 100644 --- a/polkadot/node/network/bridge/src/rx/tests.rs +++ b/polkadot/node/network/bridge/src/rx/tests.rs @@ -16,7 +16,6 @@ use super::*; use futures::{channel::oneshot, executor}; -use overseer::jaeger; use polkadot_node_network_protocol::{self as net_protocol, OurView}; use polkadot_node_subsystem::messages::NetworkBridgeEvent; @@ -124,6 +123,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, @@ -521,6 +528,7 @@ fn test_harness>( validation_service, collation_service, notification_sinks, + approval_voting_parallel_enabled: false, }; let network_bridge = run_network_in(bridge, context) @@ -1372,12 +1380,7 @@ fn our_view_updates_decreasing_order_and_limited_to_max() { } let our_views = (1..=MAX_VIEW_HEADS).rev().map(|start| { - OurView::new( - (start..=MAX_VIEW_HEADS) - .rev() - .map(|i| (Hash::repeat_byte(i as u8), Arc::new(jaeger::Span::Disabled))), - 0, - ) + OurView::new((start..=MAX_VIEW_HEADS).rev().map(|i| Hash::repeat_byte(i as u8)), 0) }); for our_view in our_views { diff --git a/polkadot/node/network/bridge/src/tx/mod.rs b/polkadot/node/network/bridge/src/tx/mod.rs index 7b6dea748572..6c353195d41a 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 9265358196db..30b2c3421372 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 f0ef038d5eb4..9accd56d86ae 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 d41fc7ebe8dd..304cb23bb6aa 100644 --- a/polkadot/node/network/collator-protocol/Cargo.toml +++ b/polkadot/node/network/collator-protocol/Cargo.toml @@ -14,6 +14,7 @@ bitvec = { features = ["alloc"], workspace = true } futures = { workspace = true } futures-timer = { workspace = true } gum = { workspace = true, default-features = true } +schnellru.workspace = true sp-core = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } @@ -29,8 +30,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/mod.rs b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs index 5c201542eb56..af9beb535f46 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/mod.rs @@ -23,6 +23,7 @@ use bitvec::{bitvec, vec::BitVec}; use futures::{ channel::oneshot, future::Fuse, pin_mut, select, stream::FuturesUnordered, FutureExt, StreamExt, }; +use schnellru::{ByLength, LruMap}; use sp_core::Pair; use polkadot_node_network_protocol::{ @@ -37,21 +38,19 @@ use polkadot_node_network_protocol::{ }; use polkadot_node_primitives::{CollationSecondedSignal, PoV, Statement}; use polkadot_node_subsystem::{ - jaeger, messages::{ CollatorProtocolMessage, NetworkBridgeEvent, NetworkBridgeTxMessage, ParentHeadData, RuntimeApiMessage, }, - overseer, CollatorProtocolSenderTrait, FromOrchestra, OverseerSignal, PerLeafSpan, + overseer, FromOrchestra, OverseerSignal, }; use polkadot_node_subsystem_util::{ backing_implicit_view::View as ImplicitView, reputation::{ReputationAggregator, REPUTATION_CHANGE_INTERVAL}, runtime::{ - get_availability_cores, get_group_rotation_info, prospective_parachains_mode, - ProspectiveParachainsMode, RuntimeInfo, + fetch_claim_queue, get_availability_cores, get_group_rotation_info, + prospective_parachains_mode, ProspectiveParachainsMode, RuntimeInfo, }, - vstaging::fetch_claim_queue, TimeoutExt, }; use polkadot_primitives::{ @@ -201,6 +200,11 @@ struct PeerData { view: View, /// Network protocol version. version: CollationVersion, + /// Unknown heads in the view. + /// + /// This can happen when the validator is faster at importing a block and sending out its + /// `View` than the collator is able to import a block. + unknown_heads: LruMap, } /// A type wrapping a collation and it's designated core index. @@ -279,9 +283,6 @@ struct State { /// our view, including both leaves and implicit ancestry. per_relay_parent: HashMap, - /// Span per relay parent. - span_per_relay_parent: HashMap, - /// The result senders per collation. collation_result_senders: HashMap>, @@ -340,7 +341,6 @@ impl State { implicit_view: None, active_leaves: Default::default(), per_relay_parent: Default::default(), - span_per_relay_parent: Default::default(), collation_result_senders: Default::default(), peer_ids: Default::default(), validator_groups_buf: ValidatorGroupsBuffer::with_capacity(VALIDATORS_BUFFER_CAPACITY), @@ -849,12 +849,6 @@ async fn process_msg( result_sender, core_index, } => { - let _span1 = state - .span_per_relay_parent - .get(&candidate_receipt.descriptor.relay_parent) - .map(|s| s.child("distributing-collation")); - let _span2 = jaeger::Span::new(&pov, "distributing-collation"); - match state.collating_on { Some(id) if candidate_receipt.descriptor.para_id != id => { // If the ParaId of a collation requested to be distributed does not match @@ -1083,11 +1077,6 @@ async fn handle_incoming_request( let peer_id = req.peer_id(); let para_id = req.para_id(); - let _span = state - .span_per_relay_parent - .get(&relay_parent) - .map(|s| s.child("request-collation")); - match state.collating_on { Some(our_para_id) if our_para_id == para_id => { let per_relay_parent = match state.per_relay_parent.get_mut(&relay_parent) { @@ -1142,8 +1131,6 @@ async fn handle_incoming_request( state.metrics.on_collation_sent_requested(); - let _span = _span.as_ref().map(|s| s.child("sending")); - let waiting = state.waiting_collation_fetches.entry(relay_parent).or_default(); let candidate_hash = receipt.hash(); @@ -1199,9 +1186,10 @@ async fn handle_peer_view_change( peer_id: PeerId, view: View, ) { - let PeerData { view: current, version } = match state.peer_data.get_mut(&peer_id) { - Some(peer_data) => peer_data, - None => return, + let Some(PeerData { view: current, version, unknown_heads }) = + state.peer_data.get_mut(&peer_id) + else { + return }; let added: Vec = view.difference(&*current).cloned().collect(); @@ -1229,15 +1217,18 @@ async fn handle_peer_view_change( new_leaf = ?added, "New leaf in peer's view is unknown", ); + + unknown_heads.insert(added, ()); + continue }, }; for block_hash in block_hashes { - let per_relay_parent = match state.per_relay_parent.get_mut(block_hash) { - Some(per_relay_parent) => per_relay_parent, - None => continue, + let Some(per_relay_parent) = state.per_relay_parent.get_mut(block_hash) else { + continue }; + advertise_collation( ctx, *block_hash, @@ -1283,10 +1274,13 @@ async fn handle_network_msg( return Ok(()) }, }; - state - .peer_data - .entry(peer_id) - .or_insert_with(|| PeerData { view: View::default(), version }); + state.peer_data.entry(peer_id).or_insert_with(|| PeerData { + view: View::default(), + version, + // Unlikely that the collator is falling 10 blocks behind and if so, it probably is + // not able to keep up any way. + unknown_heads: LruMap::new(ByLength::new(10)), + }); if let Some(authority_ids) = maybe_authority { gum::trace!( @@ -1311,7 +1305,7 @@ async fn handle_network_msg( }, OurViewChange(view) => { gum::trace!(target: LOG_TARGET, ?view, "Own view change"); - handle_our_view_change(ctx.sender(), state, view).await?; + handle_our_view_change(ctx, state, view).await?; }, PeerMessage(remote, msg) => { handle_incoming_peer_message(ctx, runtime, state, remote, msg).await?; @@ -1333,26 +1327,19 @@ async fn handle_network_msg( } /// Handles our view changes. -async fn handle_our_view_change( - sender: &mut Sender, +#[overseer::contextbounds(CollatorProtocol, prefix = crate::overseer)] +async fn handle_our_view_change( + ctx: &mut Context, state: &mut State, view: OurView, -) -> Result<()> -where - Sender: CollatorProtocolSenderTrait, -{ +) -> Result<()> { let current_leaves = state.active_leaves.clone(); let removed = current_leaves.iter().filter(|(h, _)| !view.contains(h)); let added = view.iter().filter(|h| !current_leaves.contains_key(h)); for leaf in added { - let mode = prospective_parachains_mode(sender, *leaf).await?; - - if let Some(span) = view.span_per_head().get(leaf).cloned() { - let per_leaf_span = PerLeafSpan::new(span, "collator-side"); - state.span_per_relay_parent.insert(*leaf, per_leaf_span); - } + let mode = prospective_parachains_mode(ctx.sender(), *leaf).await?; state.active_leaves.insert(*leaf, mode); state.per_relay_parent.insert(*leaf, PerRelayParent::new(mode)); @@ -1360,7 +1347,7 @@ where if mode.is_enabled() { if let Some(ref mut implicit_view) = state.implicit_view { implicit_view - .activate_leaf(sender, *leaf) + .activate_leaf(ctx.sender(), *leaf) .await .map_err(Error::ImplicitViewFetchError)?; @@ -1368,11 +1355,36 @@ where .known_allowed_relay_parents_under(leaf, state.collating_on) .unwrap_or_default(); + // Get the peers that already reported us this head, but we didn't knew it at this + // point. + let peers = state + .peer_data + .iter_mut() + .filter_map(|(id, data)| { + data.unknown_heads.remove(leaf).map(|_| (id, data.version)) + }) + .collect::>(); + for block_hash in allowed_ancestry { - state + let per_relay_parent = state .per_relay_parent .entry(*block_hash) .or_insert_with(|| PerRelayParent::new(mode)); + + // Announce relevant collations to these peers. + for (peer_id, peer_version) in &peers { + advertise_collation( + ctx, + *block_hash, + per_relay_parent, + &peer_id, + *peer_version, + &state.peer_ids, + &mut state.advertisement_timeouts, + &state.metrics, + ) + .await; + } } } } @@ -1429,7 +1441,6 @@ where ), } } - state.span_per_relay_parent.remove(removed); state.waiting_collation_fetches.remove(removed); } } 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 13601ca7a005..23954f8d781b 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 @@ -18,7 +18,6 @@ use super::*; use std::{ collections::{BTreeMap, HashSet, VecDeque}, - sync::Arc, time::Duration, }; @@ -42,7 +41,6 @@ use polkadot_node_network_protocol::{ use polkadot_node_primitives::BlockData; use polkadot_node_subsystem::{ errors::RuntimeApiError, - jaeger, messages::{AllMessages, ReportPeerMessage, RuntimeApiMessage, RuntimeApiRequest}, ActiveLeavesUpdate, }; @@ -239,11 +237,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(); @@ -303,21 +297,33 @@ async fn overseer_send(overseer: &mut VirtualOverseer, msg: CollatorProtocolMess } async fn overseer_recv(overseer: &mut VirtualOverseer) -> AllMessages { - let msg = overseer_recv_with_timeout(overseer, TIMEOUT) + overseer_recv_with_timeout(overseer, TIMEOUT) .await - .expect(&format!("{:?} is more than enough to receive messages", TIMEOUT)); + .expect(&format!("{:?} is more than enough to receive messages", TIMEOUT)) +} + +async fn overseer_recv_with_timeout( + overseer: &mut VirtualOverseer, + timeout: Duration, +) -> Option { + gum::trace!("waiting for message..."); + let msg = overseer.recv().timeout(timeout).await; gum::trace!(?msg, "received message"); msg } -async fn overseer_recv_with_timeout( +async fn overseer_peek_with_timeout( overseer: &mut VirtualOverseer, timeout: Duration, -) -> Option { - gum::trace!("waiting for message..."); - overseer.recv().timeout(timeout).await +) -> Option<&AllMessages> { + gum::trace!("peeking for message..."); + let msg = overseer.peek().timeout(timeout).await; + + gum::trace!(?msg, "received message"); + + msg.flatten() } async fn overseer_signal(overseer: &mut VirtualOverseer, signal: OverseerSignal) { @@ -607,7 +613,7 @@ async fn expect_declare_msg( /// Expects v2 message if `expected_candidate_hashes` is `Some`, v1 otherwise. async fn expect_advertise_collation_msg( virtual_overseer: &mut VirtualOverseer, - peer: &PeerId, + any_peers: &[PeerId], expected_relay_parent: Hash, expected_candidate_hashes: Option>, ) { @@ -624,7 +630,7 @@ async fn expect_advertise_collation_msg( wire_message, ) ) => { - assert_eq!(to[0], *peer); + assert!(any_peers.iter().any(|p| to.contains(p))); match (candidate_hashes.as_mut(), wire_message) { (None, Versioned::V1(protocol_v1::CollationProtocol::CollatorProtocol(wire_message))) => { assert_matches!( @@ -743,7 +749,7 @@ fn advertise_and_send_collation() { // advertise it. expect_advertise_collation_msg( &mut virtual_overseer, - &peer, + &[peer], test_state.relay_parent, None, ) @@ -853,7 +859,7 @@ fn advertise_and_send_collation() { expect_advertise_collation_msg( &mut virtual_overseer, - &peer, + &[peer], test_state.relay_parent, None, ) @@ -914,7 +920,7 @@ fn delay_reputation_change() { // advertise it. expect_advertise_collation_msg( &mut virtual_overseer, - &peer, + &[peer], test_state.relay_parent, None, ) @@ -1035,7 +1041,7 @@ fn advertise_collation_v2_protocol() { // Versioned advertisements work. expect_advertise_collation_msg( virtual_overseer, - &peer_ids[0], + &[peer_ids[0]], test_state.relay_parent, None, ) @@ -1043,7 +1049,7 @@ fn advertise_collation_v2_protocol() { for peer_id in peer_ids.iter().skip(1) { expect_advertise_collation_msg( virtual_overseer, - peer_id, + &[*peer_id], test_state.relay_parent, Some(vec![candidate.hash()]), // This is `Some`, advertisement is v2. ) @@ -1146,15 +1152,25 @@ fn collations_are_only_advertised_to_validators_with_correct_view() { distribute_collation(virtual_overseer, &test_state, test_state.relay_parent, true) .await; - expect_advertise_collation_msg(virtual_overseer, &peer2, test_state.relay_parent, None) - .await; + expect_advertise_collation_msg( + virtual_overseer, + &[peer2], + test_state.relay_parent, + None, + ) + .await; // The other validator announces that it changed its view. send_peer_view_change(virtual_overseer, &peer, vec![test_state.relay_parent]).await; // After changing the view we should receive the advertisement - expect_advertise_collation_msg(virtual_overseer, &peer, test_state.relay_parent, None) - .await; + expect_advertise_collation_msg( + virtual_overseer, + &[peer], + test_state.relay_parent, + None, + ) + .await; test_harness }, ) @@ -1203,12 +1219,17 @@ fn collate_on_two_different_relay_chain_blocks() { .await; send_peer_view_change(virtual_overseer, &peer, vec![old_relay_parent]).await; - expect_advertise_collation_msg(virtual_overseer, &peer, old_relay_parent, None).await; + expect_advertise_collation_msg(virtual_overseer, &[peer], old_relay_parent, None).await; send_peer_view_change(virtual_overseer, &peer2, vec![test_state.relay_parent]).await; - expect_advertise_collation_msg(virtual_overseer, &peer2, test_state.relay_parent, None) - .await; + expect_advertise_collation_msg( + virtual_overseer, + &[peer2], + test_state.relay_parent, + None, + ) + .await; test_harness }, ) @@ -1241,8 +1262,13 @@ fn validator_reconnect_does_not_advertise_a_second_time() { .await; send_peer_view_change(virtual_overseer, &peer, vec![test_state.relay_parent]).await; - expect_advertise_collation_msg(virtual_overseer, &peer, test_state.relay_parent, None) - .await; + expect_advertise_collation_msg( + virtual_overseer, + &[peer], + test_state.relay_parent, + None, + ) + .await; // Disconnect and reconnect directly disconnect_peer(virtual_overseer, peer).await; @@ -1365,14 +1391,14 @@ where // advertise it. expect_advertise_collation_msg( virtual_overseer, - &validator_0, + &[validator_0], test_state.relay_parent, None, ) .await; expect_advertise_collation_msg( virtual_overseer, - &validator_1, + &[validator_1], test_state.relay_parent, None, ) @@ -1502,9 +1528,10 @@ fn connect_to_buffered_groups() { } // Update views. - for peed_id in &peers_a { - send_peer_view_change(&mut virtual_overseer, peed_id, vec![head_a]).await; - expect_advertise_collation_msg(&mut virtual_overseer, peed_id, head_a, None).await; + for peer_id in &peers_a { + send_peer_view_change(&mut virtual_overseer, peer_id, vec![head_a]).await; + expect_advertise_collation_msg(&mut virtual_overseer, &[*peer_id], head_a, None) + .await; } let peer = peers_a[0]; diff --git a/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs b/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs index ea8fdb0e04fb..348feb9dd1db 100644 --- a/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs +++ b/polkadot/node/network/collator-protocol/src/collator_side/tests/prospective_parachains.rs @@ -36,8 +36,7 @@ async fn update_view( ) { let new_view: HashMap = HashMap::from_iter(new_view); - let our_view = - OurView::new(new_view.keys().map(|hash| (*hash, Arc::new(jaeger::Span::Disabled))), 0); + let our_view = OurView::new(new_view.keys().map(|hash| *hash), 0); overseer_send( virtual_overseer, @@ -45,7 +44,6 @@ async fn update_view( ) .await; - let mut next_overseer_message = None; for _ in 0..activated { let (leaf_hash, leaf_number) = assert_matches!( overseer_recv(virtual_overseer).await, @@ -147,18 +145,10 @@ async fn update_view( let parent_hash = ancestry_iter.peek().map(|(h, _)| *h).unwrap_or_else(|| get_parent_hash(hash)); - let msg = match next_overseer_message.take() { - Some(msg) => Some(msg), - None => - overseer_recv_with_timeout(virtual_overseer, Duration::from_millis(50)).await, - }; - - let msg = match msg { - Some(msg) => msg, - None => { - // We're done. - return - }, + let Some(msg) = + overseer_peek_with_timeout(virtual_overseer, Duration::from_millis(50)).await + else { + return }; if !matches!( @@ -167,12 +157,11 @@ async fn update_view( if *_hash == hash ) { // Ancestry has already been cached for this leaf. - next_overseer_message.replace(msg); break } assert_matches!( - msg, + overseer_recv_with_timeout(virtual_overseer, Duration::from_millis(50)).await.unwrap(), AllMessages::ChainApi(ChainApiMessage::BlockHeader(.., tx)) => { let header = Header { parent_hash, @@ -238,124 +227,156 @@ fn distribute_collation_from_implicit_view() { let head_c = Hash::from_low_u64_be(130); let head_c_num = 62; - let group_rotation_info = GroupRotationInfo { - session_start_block: head_c_num - 2, - group_rotation_frequency: 3, - now: head_c_num, - }; + // Run once with validators sending their view first and then the collator setting their own + // view first. + for validator_sends_view_first in [true, false] { + let group_rotation_info = GroupRotationInfo { + session_start_block: head_c_num - 2, + group_rotation_frequency: 3, + now: head_c_num, + }; + + let mut test_state = TestState::default(); + test_state.group_rotation_info = group_rotation_info; + + let local_peer_id = test_state.local_peer_id; + let collator_pair = test_state.collator_pair.clone(); + + test_harness( + local_peer_id, + collator_pair, + ReputationAggregator::new(|_| true), + |mut test_harness| async move { + let virtual_overseer = &mut test_harness.virtual_overseer; + + // Set collating para id. + overseer_send( + virtual_overseer, + CollatorProtocolMessage::CollateOn(test_state.para_id), + ) + .await; - let mut test_state = TestState::default(); - test_state.group_rotation_info = group_rotation_info; + if validator_sends_view_first { + // Activate leaf `c` to accept at least the collation. + update_view(virtual_overseer, vec![(head_c, head_c_num)], 1).await; + } else { + // Activated leaf is `b`, but the collation will be based on `c`. + update_view(virtual_overseer, vec![(head_b, head_b_num)], 1).await; + } - let local_peer_id = test_state.local_peer_id; - let collator_pair = test_state.collator_pair.clone(); + let validator_peer_ids = test_state.current_group_validator_peer_ids(); + for (val, peer) in test_state + .current_group_validator_authority_ids() + .into_iter() + .zip(validator_peer_ids.clone()) + { + connect_peer(virtual_overseer, peer, CollationVersion::V2, Some(val.clone())) + .await; + } - test_harness( - local_peer_id, - collator_pair, - ReputationAggregator::new(|_| true), - |mut test_harness| async move { - let virtual_overseer = &mut test_harness.virtual_overseer; + // Collator declared itself to each peer. + for peer_id in &validator_peer_ids { + expect_declare_msg_v2(virtual_overseer, &test_state, peer_id).await; + } - // Set collating para id. - overseer_send(virtual_overseer, CollatorProtocolMessage::CollateOn(test_state.para_id)) - .await; - // Activated leaf is `b`, but the collation will be based on `c`. - update_view(virtual_overseer, vec![(head_b, head_b_num)], 1).await; - - let validator_peer_ids = test_state.current_group_validator_peer_ids(); - for (val, peer) in test_state - .current_group_validator_authority_ids() - .into_iter() - .zip(validator_peer_ids.clone()) - { - connect_peer(virtual_overseer, peer, CollationVersion::V2, Some(val.clone())).await; - } + let pov = PoV { block_data: BlockData(vec![1, 2, 3]) }; + let parent_head_data_hash = Hash::repeat_byte(0xAA); + let candidate = TestCandidateBuilder { + para_id: test_state.para_id, + relay_parent: head_c, + pov_hash: pov.hash(), + ..Default::default() + } + .build(); + let DistributeCollation { candidate, pov_block: _ } = + distribute_collation_with_receipt( + virtual_overseer, + &test_state, + head_c, + false, // Check the group manually. + candidate, + pov, + parent_head_data_hash, + ) + .await; + assert_matches!( + overseer_recv(virtual_overseer).await, + AllMessages::NetworkBridgeTx( + NetworkBridgeTxMessage::ConnectToValidators { validator_ids, .. } + ) => { + let expected_validators = test_state.current_group_validator_authority_ids(); - // Collator declared itself to each peer. - for peer_id in &validator_peer_ids { - expect_declare_msg_v2(virtual_overseer, &test_state, peer_id).await; - } + assert_eq!(expected_validators, validator_ids); + } + ); - let pov = PoV { block_data: BlockData(vec![1, 2, 3]) }; - let parent_head_data_hash = Hash::repeat_byte(0xAA); - let candidate = TestCandidateBuilder { - para_id: test_state.para_id, - relay_parent: head_c, - pov_hash: pov.hash(), - ..Default::default() - } - .build(); - let DistributeCollation { candidate, pov_block: _ } = - distribute_collation_with_receipt( - virtual_overseer, - &test_state, - head_c, - false, // Check the group manually. - candidate, - pov, - parent_head_data_hash, - ) - .await; - assert_matches!( - overseer_recv(virtual_overseer).await, - AllMessages::NetworkBridgeTx( - NetworkBridgeTxMessage::ConnectToValidators { validator_ids, .. } - ) => { - let expected_validators = test_state.current_group_validator_authority_ids(); + let candidate_hash = candidate.hash(); + + // Update peer views. + for peer_id in &validator_peer_ids { + send_peer_view_change(virtual_overseer, peer_id, vec![head_b]).await; - assert_eq!(expected_validators, validator_ids); + if !validator_sends_view_first { + expect_advertise_collation_msg( + virtual_overseer, + &[*peer_id], + head_c, + Some(vec![candidate_hash]), + ) + .await; + } } - ); - let candidate_hash = candidate.hash(); + if validator_sends_view_first { + // Activated leaf is `b`, but the collation will be based on `c`. + update_view(virtual_overseer, vec![(head_b, head_b_num)], 1).await; + + for _ in &validator_peer_ids { + expect_advertise_collation_msg( + virtual_overseer, + &validator_peer_ids, + head_c, + Some(vec![candidate_hash]), + ) + .await; + } + } - // Update peer views. - for peed_id in &validator_peer_ids { - send_peer_view_change(virtual_overseer, peed_id, vec![head_b]).await; - expect_advertise_collation_msg( + // Head `c` goes out of view. + // Build a different candidate for this relay parent and attempt to distribute it. + update_view(virtual_overseer, vec![(head_a, head_a_num)], 1).await; + + let pov = PoV { block_data: BlockData(vec![4, 5, 6]) }; + let parent_head_data_hash = Hash::repeat_byte(0xBB); + let candidate = TestCandidateBuilder { + para_id: test_state.para_id, + relay_parent: head_c, + pov_hash: pov.hash(), + ..Default::default() + } + .build(); + overseer_send( virtual_overseer, - peed_id, - head_c, - Some(vec![candidate_hash]), + CollatorProtocolMessage::DistributeCollation { + candidate_receipt: candidate.clone(), + parent_head_data_hash, + pov: pov.clone(), + parent_head_data: HeadData(vec![1, 2, 3]), + result_sender: None, + core_index: CoreIndex(0), + }, ) .await; - } - - // Head `c` goes out of view. - // Build a different candidate for this relay parent and attempt to distribute it. - update_view(virtual_overseer, vec![(head_a, head_a_num)], 1).await; - - let pov = PoV { block_data: BlockData(vec![4, 5, 6]) }; - let parent_head_data_hash = Hash::repeat_byte(0xBB); - let candidate = TestCandidateBuilder { - para_id: test_state.para_id, - relay_parent: head_c, - pov_hash: pov.hash(), - ..Default::default() - } - .build(); - overseer_send( - virtual_overseer, - CollatorProtocolMessage::DistributeCollation { - candidate_receipt: candidate.clone(), - parent_head_data_hash, - pov: pov.clone(), - parent_head_data: HeadData(vec![1, 2, 3]), - result_sender: None, - core_index: CoreIndex(0), - }, - ) - .await; - // Parent out of view, nothing happens. - assert!(overseer_recv_with_timeout(virtual_overseer, Duration::from_millis(100)) - .await - .is_none()); + // Parent out of view, nothing happens. + assert!(overseer_recv_with_timeout(virtual_overseer, Duration::from_millis(100)) + .await + .is_none()); - test_harness - }, - ) + test_harness + }, + ); + } } /// Tests that collator can distribute up to `MAX_CANDIDATE_DEPTH + 1` candidates @@ -505,7 +526,7 @@ fn send_parent_head_data_for_elastic_scaling() { send_peer_view_change(&mut virtual_overseer, &peer, vec![head_b]).await; let hashes: Vec<_> = vec![candidate.hash()]; - expect_advertise_collation_msg(&mut virtual_overseer, &peer, head_b, Some(hashes)) + expect_advertise_collation_msg(&mut virtual_overseer, &[peer], head_b, Some(hashes)) .await; let (pending_response, rx) = oneshot::channel(); @@ -625,7 +646,7 @@ fn advertise_and_send_collation_by_hash() { // Head `b` is not a leaf, but both advertisements are still relevant. send_peer_view_change(&mut virtual_overseer, &peer, vec![head_b]).await; let hashes: Vec<_> = candidates.iter().map(|(candidate, _)| candidate.hash()).collect(); - expect_advertise_collation_msg(&mut virtual_overseer, &peer, head_b, Some(hashes)) + expect_advertise_collation_msg(&mut virtual_overseer, &[peer], head_b, Some(hashes)) .await; for (candidate, pov_block) in candidates { diff --git a/polkadot/node/network/collator-protocol/src/validator_side/collation.rs b/polkadot/node/network/collator-protocol/src/validator_side/collation.rs index 96ffe9f13db3..58d9ebc57726 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/collation.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/collation.rs @@ -36,7 +36,6 @@ use polkadot_node_network_protocol::{ PeerId, }; use polkadot_node_primitives::PoV; -use polkadot_node_subsystem::jaeger; use polkadot_node_subsystem_util::{ metrics::prometheus::prometheus::HistogramTimer, runtime::ProspectiveParachainsMode, }; @@ -319,8 +318,6 @@ pub(super) struct CollationFetchRequest { pub from_collator: BoxFuture<'static, OutgoingResult>, /// Handle used for checking if this request was cancelled. pub cancellation_token: CancellationToken, - /// A jaeger span corresponding to the lifetime of the request. - pub span: Option, /// A metric histogram for the lifetime of the request pub _lifetime_timer: Option, } @@ -339,7 +336,6 @@ impl Future for CollationFetchRequest { }; if cancelled { - self.span.as_mut().map(|s| s.add_string_tag("success", "false")); return Poll::Ready(( CollationEvent { collator_protocol_version: self.collator_protocol_version, @@ -361,16 +357,6 @@ impl Future for CollationFetchRequest { ) }); - match &res { - Poll::Ready((_, Ok(_))) => { - self.span.as_mut().map(|s| s.add_string_tag("success", "true")); - }, - Poll::Ready((_, Err(_))) => { - self.span.as_mut().map(|s| s.add_string_tag("success", "false")); - }, - _ => {}, - }; - res } } diff --git a/polkadot/node/network/collator-protocol/src/validator_side/mod.rs b/polkadot/node/network/collator-protocol/src/validator_side/mod.rs index f5c9726f3f6a..deb6ce03f43e 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/mod.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/mod.rs @@ -39,19 +39,17 @@ use polkadot_node_network_protocol::{ }; use polkadot_node_primitives::{SignedFullStatement, Statement}; use polkadot_node_subsystem::{ - jaeger, messages::{ CanSecondRequest, CandidateBackingMessage, CollatorProtocolMessage, IfDisconnected, NetworkBridgeEvent, NetworkBridgeTxMessage, ParentHeadData, ProspectiveParachainsMessage, ProspectiveValidationDataRequest, }, - overseer, CollatorProtocolSenderTrait, FromOrchestra, OverseerSignal, PerLeafSpan, + overseer, CollatorProtocolSenderTrait, FromOrchestra, OverseerSignal, }; use polkadot_node_subsystem_util::{ backing_implicit_view::View as ImplicitView, reputation::{ReputationAggregator, REPUTATION_CHANGE_INTERVAL}, - runtime::{prospective_parachains_mode, ProspectiveParachainsMode}, - vstaging::fetch_claim_queue, + runtime::{fetch_claim_queue, prospective_parachains_mode, ProspectiveParachainsMode}, }; use polkadot_primitives::{ CandidateHash, CollatorId, CoreState, Hash, HeadData, Id as ParaId, OccupiedCoreAssumption, @@ -421,9 +419,6 @@ struct State { /// Metrics. metrics: Metrics, - /// Span per relay parent. - span_per_relay_parent: HashMap, - /// When a timer in this `FuturesUnordered` triggers, we should dequeue the next request /// attempt in the corresponding `collations_per_relay_parent`. /// @@ -724,10 +719,6 @@ async fn request_collation( collator_protocol_version: peer_protocol_version, from_collator: response_recv, cancellation_token: cancellation_token.clone(), - span: state - .span_per_relay_parent - .get(&relay_parent) - .map(|s| s.child("collation-request").with_para_id(para_id)), _lifetime_timer: state.metrics.time_collation_request_duration(), }; @@ -1067,11 +1058,6 @@ async fn handle_advertisement( where Sender: CollatorProtocolSenderTrait, { - let _span = state - .span_per_relay_parent - .get(&relay_parent) - .map(|s| s.child("advertise-collation")); - let peer_data = state.peer_data.get_mut(&peer_id).ok_or(AdvertisementError::UnknownPeer)?; if peer_data.version == CollationVersion::V1 && !state.active_leaves.contains_key(&relay_parent) @@ -1265,11 +1251,6 @@ where for leaf in added { let mode = prospective_parachains_mode(sender, *leaf).await?; - if let Some(span) = view.span_per_head().get(leaf).cloned() { - let per_leaf_span = PerLeafSpan::new(span, "validator-side"); - state.span_per_relay_parent.insert(*leaf, per_leaf_span); - } - let mut per_relay_parent = PerRelayParent::new(mode); assign_incoming( sender, @@ -1339,7 +1320,6 @@ where keep }); state.fetched_candidates.retain(|k, _| k.relay_parent != removed); - state.span_per_relay_parent.remove(&removed); } } @@ -1984,10 +1964,6 @@ async fn handle_collation_fetch_response( Ok(resp) => Ok(resp), }; - let _span = state - .span_per_relay_parent - .get(&pending_collation.relay_parent) - .map(|s| s.child("received-collation")); let _timer = state.metrics.time_handle_collation_request_result(); let mut metrics_result = Err(()); @@ -2068,7 +2044,6 @@ async fn handle_collation_fetch_response( candidate_hash = ?candidate_receipt.hash(), "Received collation", ); - let _span = jaeger::Span::new(&pov, "received-collation"); metrics_result = Ok(()); Ok(PendingCollationFetch { @@ -2094,7 +2069,6 @@ async fn handle_collation_fetch_response( candidate_hash = ?receipt.hash(), "Received collation (v3)", ); - let _span = jaeger::Span::new(&pov, "received-collation"); metrics_result = Ok(()); Ok(PendingCollationFetch { 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 44e25efd4dfc..86c8bcb6bdcd 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/collator-protocol/src/validator_side/tests/prospective_parachains.rs b/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs index 472731b506ab..dff98e22e3db 100644 --- a/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs +++ b/polkadot/node/network/collator-protocol/src/validator_side/tests/prospective_parachains.rs @@ -103,8 +103,7 @@ pub(super) async fn update_view( ) -> Option { let new_view: HashMap = HashMap::from_iter(new_view); - let our_view = - OurView::new(new_view.keys().map(|hash| (*hash, Arc::new(jaeger::Span::Disabled))), 0); + let our_view = OurView::new(new_view.keys().map(|hash| *hash), 0); overseer_send( virtual_overseer, diff --git a/polkadot/node/network/dispute-distribution/Cargo.toml b/polkadot/node/network/dispute-distribution/Cargo.toml index ccf1b5daad7c..b4dcafe09eb6 100644 --- a/polkadot/node/network/dispute-distribution/Cargo.toml +++ b/polkadot/node/network/dispute-distribution/Cargo.toml @@ -38,5 +38,4 @@ sp-tracing = { workspace = true, default-features = true } sc-keystore = { workspace = true, default-features = true } futures-timer = { workspace = true } assert_matches = { workspace = true } -lazy_static = { workspace = true } polkadot-primitives-test-helpers = { workspace = true } diff --git a/polkadot/node/network/dispute-distribution/src/receiver/mod.rs b/polkadot/node/network/dispute-distribution/src/receiver/mod.rs index 2409e6994f60..77c1e41aac05 100644 --- a/polkadot/node/network/dispute-distribution/src/receiver/mod.rs +++ b/polkadot/node/network/dispute-distribution/src/receiver/mod.rs @@ -66,9 +66,12 @@ use self::{ const COST_INVALID_REQUEST: Rep = Rep::CostMajor("Received message could not be decoded."); const COST_INVALID_SIGNATURE: Rep = Rep::Malicious("Signatures were invalid."); -const COST_INVALID_IMPORT: Rep = - Rep::Malicious("Import was deemed invalid by dispute-coordinator."); const COST_NOT_A_VALIDATOR: Rep = Rep::CostMajor("Reporting peer was not a validator."); + +/// Invalid imports can be caused by flooding, e.g. by a disabled validator. +const COST_INVALID_IMPORT: Rep = + Rep::CostMinor("Import was deemed invalid by dispute-coordinator."); + /// Mildly punish peers exceeding their rate limit. /// /// For honest peers this should rarely happen, but if it happens we would not want to disconnect diff --git a/polkadot/node/network/dispute-distribution/src/tests/mock.rs b/polkadot/node/network/dispute-distribution/src/tests/mock.rs index ccc050233e84..baa857e2eb68 100644 --- a/polkadot/node/network/dispute-distribution/src/tests/mock.rs +++ b/polkadot/node/network/dispute-distribution/src/tests/mock.rs @@ -19,12 +19,11 @@ use std::{ collections::{HashMap, HashSet}, - sync::Arc, + sync::{Arc, LazyLock}, time::Instant, }; use async_trait::async_trait; -use lazy_static::lazy_static; use polkadot_node_network_protocol::{authority_discovery::AuthorityDiscovery, PeerId}; use sc_keystore::LocalKeystore; @@ -60,64 +59,60 @@ pub const ALICE_INDEX: ValidatorIndex = ValidatorIndex(1); pub const BOB_INDEX: ValidatorIndex = ValidatorIndex(2); pub const CHARLIE_INDEX: ValidatorIndex = ValidatorIndex(3); -lazy_static! { - /// Mocked `AuthorityDiscovery` service. -pub static ref MOCK_AUTHORITY_DISCOVERY: MockAuthorityDiscovery = MockAuthorityDiscovery::new(); +pub static MOCK_AUTHORITY_DISCOVERY: LazyLock = + LazyLock::new(|| MockAuthorityDiscovery::new()); // Creating an innocent looking `SessionInfo` is really expensive in a debug build. Around // 700ms on my machine, We therefore cache those keys here: -pub static ref MOCK_VALIDATORS_DISCOVERY_KEYS: HashMap = - MOCK_VALIDATORS - .iter() - .chain(MOCK_AUTHORITIES_NEXT_SESSION.iter()) - .map(|v| (*v, v.public().into())) - .collect() -; -pub static ref FERDIE_DISCOVERY_KEY: AuthorityDiscoveryId = - MOCK_VALIDATORS_DISCOVERY_KEYS.get(&Sr25519Keyring::Ferdie).unwrap().clone(); - -pub static ref MOCK_SESSION_INFO: SessionInfo = - SessionInfo { - validators: MOCK_VALIDATORS.iter().take(4).map(|k| k.public().into()).collect(), - discovery_keys: MOCK_VALIDATORS +pub static MOCK_VALIDATORS_DISCOVERY_KEYS: LazyLock> = + LazyLock::new(|| { + MOCK_VALIDATORS .iter() - .map(|k| MOCK_VALIDATORS_DISCOVERY_KEYS.get(&k).unwrap().clone()) - .collect(), - assignment_keys: vec![], - validator_groups: Default::default(), - n_cores: 0, - zeroth_delay_tranche_width: 0, - relay_vrf_modulo_samples: 0, - n_delay_tranches: 0, - no_show_slots: 0, - needed_approvals: 0, - active_validator_indices: vec![], - dispute_period: 6, - random_seed: [0u8; 32], - }; + .chain(MOCK_AUTHORITIES_NEXT_SESSION.iter()) + .map(|v| (*v, v.public().into())) + .collect() + }); +pub static FERDIE_DISCOVERY_KEY: LazyLock = + LazyLock::new(|| MOCK_VALIDATORS_DISCOVERY_KEYS.get(&Sr25519Keyring::Ferdie).unwrap().clone()); + +pub static MOCK_SESSION_INFO: LazyLock = LazyLock::new(|| SessionInfo { + validators: MOCK_VALIDATORS.iter().take(4).map(|k| k.public().into()).collect(), + discovery_keys: MOCK_VALIDATORS + .iter() + .map(|k| MOCK_VALIDATORS_DISCOVERY_KEYS.get(&k).unwrap().clone()) + .collect(), + assignment_keys: vec![], + validator_groups: Default::default(), + n_cores: 0, + zeroth_delay_tranche_width: 0, + relay_vrf_modulo_samples: 0, + n_delay_tranches: 0, + no_show_slots: 0, + needed_approvals: 0, + active_validator_indices: vec![], + dispute_period: 6, + random_seed: [0u8; 32], +}); /// `SessionInfo` for the second session. (No more validators, but two more authorities. -pub static ref MOCK_NEXT_SESSION_INFO: SessionInfo = - SessionInfo { - discovery_keys: - MOCK_AUTHORITIES_NEXT_SESSION - .iter() - .map(|k| MOCK_VALIDATORS_DISCOVERY_KEYS.get(&k).unwrap().clone()) - .collect(), - validators: Default::default(), - assignment_keys: vec![], - validator_groups: Default::default(), - n_cores: 0, - zeroth_delay_tranche_width: 0, - relay_vrf_modulo_samples: 0, - n_delay_tranches: 0, - no_show_slots: 0, - needed_approvals: 0, - active_validator_indices: vec![], - dispute_period: 6, - random_seed: [0u8; 32], - }; -} +pub static MOCK_NEXT_SESSION_INFO: LazyLock = LazyLock::new(|| SessionInfo { + discovery_keys: MOCK_AUTHORITIES_NEXT_SESSION + .iter() + .map(|k| MOCK_VALIDATORS_DISCOVERY_KEYS.get(&k).unwrap().clone()) + .collect(), + validators: Default::default(), + assignment_keys: vec![], + validator_groups: Default::default(), + n_cores: 0, + zeroth_delay_tranche_width: 0, + relay_vrf_modulo_samples: 0, + n_delay_tranches: 0, + no_show_slots: 0, + needed_approvals: 0, + active_validator_indices: vec![], + dispute_period: 6, + random_seed: [0u8; 32], +}); pub fn make_candidate_receipt(relay_parent: Hash) -> CandidateReceipt { CandidateReceipt { diff --git a/polkadot/node/network/gossip-support/Cargo.toml b/polkadot/node/network/gossip-support/Cargo.toml index 83fdc7e26191..c8c19e5de070 100644 --- a/polkadot/node/network/gossip-support/Cargo.toml +++ b/polkadot/node/network/gossip-support/Cargo.toml @@ -39,5 +39,4 @@ polkadot-node-subsystem-test-helpers = { workspace = true } assert_matches = { workspace = true } async-trait = { workspace = true } parking_lot = { workspace = true, default-features = true } -lazy_static = { workspace = true } quickcheck = { workspace = true, default-features = true } diff --git a/polkadot/node/network/gossip-support/src/lib.rs b/polkadot/node/network/gossip-support/src/lib.rs index 4dfdd1f7208f..cd327c11e408 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 42197d00e6f3..399f29db67da 100644 --- a/polkadot/node/network/gossip-support/src/tests.rs +++ b/polkadot/node/network/gossip-support/src/tests.rs @@ -16,12 +16,11 @@ //! Unit tests for Gossip Support Subsystem. -use std::{collections::HashSet, time::Duration}; +use std::{collections::HashSet, sync::LazyLock, time::Duration}; use assert_matches::assert_matches; use async_trait::async_trait; use futures::{executor, future, Future}; -use lazy_static::lazy_static; use quickcheck::quickcheck; use rand::seq::SliceRandom as _; @@ -56,39 +55,29 @@ const AUTHORITY_KEYRINGS: &[Sr25519Keyring] = &[ Sr25519Keyring::Ferdie, ]; -lazy_static! { - static ref AUTHORITIES: Vec = - AUTHORITY_KEYRINGS.iter().map(|k| k.public().into()).collect(); +static AUTHORITIES: LazyLock> = + LazyLock::new(|| AUTHORITY_KEYRINGS.iter().map(|k| k.public().into()).collect()); - static ref AUTHORITIES_WITHOUT_US: Vec = { - let mut a = AUTHORITIES.clone(); - a.pop(); // remove FERDIE. - a - }; +static AUTHORITIES_WITHOUT_US: LazyLock> = LazyLock::new(|| { + let mut a = AUTHORITIES.clone(); + a.pop(); // remove FERDIE. + a +}); - static ref PAST_PRESENT_FUTURE_AUTHORITIES: Vec = { - (0..50) - .map(|_| AuthorityDiscoveryPair::generate().0.public()) - .chain(AUTHORITIES.clone()) - .collect() - }; +static PAST_PRESENT_FUTURE_AUTHORITIES: LazyLock> = LazyLock::new(|| { + (0..50) + .map(|_| AuthorityDiscoveryPair::generate().0.public()) + .chain(AUTHORITIES.clone()) + .collect() +}); - // [2 6] - // [4 5] - // [1 3] - // [0 ] +static EXPECTED_SHUFFLING: LazyLock> = LazyLock::new(|| vec![6, 4, 0, 5, 2, 3, 1]); - static ref EXPECTED_SHUFFLING: Vec = vec![6, 4, 0, 5, 2, 3, 1]; +static ROW_NEIGHBORS: LazyLock> = + LazyLock::new(|| vec![ValidatorIndex::from(2)]); - static ref ROW_NEIGHBORS: Vec = vec![ - ValidatorIndex::from(2), - ]; - - static ref COLUMN_NEIGHBORS: Vec = vec![ - ValidatorIndex::from(3), - ValidatorIndex::from(5), - ]; -} +static COLUMN_NEIGHBORS: LazyLock> = + LazyLock::new(|| vec![ValidatorIndex::from(3), ValidatorIndex::from(5)]); type VirtualOverseer = polkadot_node_subsystem_test_helpers::TestSubsystemContextHandle; @@ -119,6 +108,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 +806,313 @@ fn issues_update_authorities_after_session() { ); } +// Test we connect to authorities that changed their address `TRY_RERESOLVE_AUTHORITIES` rate +// and that is is no-op if no authority changed. +#[test] +fn test_quickly_connect_to_authorities_that_changed_address() { + let hash = Hash::repeat_byte(0xAA); + + let authorities = PAST_PRESENT_FUTURE_AUTHORITIES.clone(); + let authority_that_changes_address = authorities.get(5).unwrap().clone(); + + let mut authority_discovery_mock = MockAuthorityDiscovery::new(authorities); + + test_harness( + make_subsystem_with_authority_discovery(authority_discovery_mock.clone()), + |mut virtual_overseer| async move { + let overseer = &mut virtual_overseer; + // 1. Initialize with the first leaf in the session. + overseer_signal_active_leaves(overseer, hash).await; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionIndexForChild(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(1)).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionInfo(s, tx), + )) => { + assert_eq!(relay_parent, hash); + assert_eq!(s, 1); + let mut session_info = make_session_info(); + session_info.discovery_keys = PAST_PRESENT_FUTURE_AUTHORITIES.clone(); + tx.send(Ok(Some(session_info))).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::Authorities(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(PAST_PRESENT_FUTURE_AUTHORITIES.clone())).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::ConnectToResolvedValidators { + validator_addrs, + peer_set, + }) => { + let all_without_ferdie: Vec<_> = PAST_PRESENT_FUTURE_AUTHORITIES + .iter() + .cloned() + .filter(|p| p != &Sr25519Keyring::Ferdie.public().into()) + .collect(); + + let addrs = get_multiaddrs(all_without_ferdie, authority_discovery_mock.clone()).await; + + assert_eq!(validator_addrs, addrs); + assert_eq!(peer_set, PeerSet::Validation); + } + ); + + // Ensure neighbors are unaffected + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + _, + RuntimeApiRequest::CurrentBabeEpoch(tx), + )) => { + let _ = tx.send(Ok(BabeEpoch { + epoch_index: 2 as _, + start_slot: 0.into(), + duration: 200, + authorities: vec![(Sr25519Keyring::Alice.public().into(), 1)], + randomness: [0u8; 32], + config: BabeEpochConfiguration { + c: (1, 4), + allowed_slots: AllowedSlots::PrimarySlots, + }, + })).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeRx(NetworkBridgeRxMessage::NewGossipTopology { + session: _, + local_index: _, + canonical_shuffling: _, + shuffled_indices: _, + }) => { + + } + ); + + // 2. Connect all authorities that are known so far. + let known_authorities = authority_discovery_mock.authorities(); + for (peer_id, _id) in known_authorities.iter() { + let msg = + GossipSupportMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerConnected( + *peer_id, + ObservedRole::Authority, + ValidationVersion::V3.into(), + None, + )); + overseer.send(FromOrchestra::Communication { msg }).await + } + + // 3. Send a new leaf after TRY_RERESOLVE_AUTHORITIES, we should notice + // UpdateAuthorithies is emitted for all ConnectedPeers. + Delay::new(TRY_RERESOLVE_AUTHORITIES).await; + let hash = Hash::repeat_byte(0xBB); + overseer_signal_active_leaves(overseer, hash).await; + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionIndexForChild(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(1)).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionInfo(s, tx), + )) => { + assert_eq!(relay_parent, hash); + assert_eq!(s, 1); + let mut session_info = make_session_info(); + session_info.discovery_keys = PAST_PRESENT_FUTURE_AUTHORITIES.clone(); + tx.send(Ok(Some(session_info))).unwrap(); + + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::Authorities(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(PAST_PRESENT_FUTURE_AUTHORITIES.clone())).unwrap(); + } + ); + + for _ in 0..known_authorities.len() { + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeRx(NetworkBridgeRxMessage::UpdatedAuthorityIds { + peer_id, + authority_ids, + }) => { + assert_eq!(authority_discovery_mock.get_authority_ids_by_peer_id(peer_id).await.unwrap_or_default(), authority_ids); + } + ); + } + + // 4. At next re-resolve no-authorithy changes their address, so it should be no-op. + Delay::new(TRY_RERESOLVE_AUTHORITIES).await; + let hash = Hash::repeat_byte(0xCC); + overseer_signal_active_leaves(overseer, hash).await; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionIndexForChild(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(1)).unwrap(); + } + ); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionInfo(s, tx), + )) => { + assert_eq!(relay_parent, hash); + assert_eq!(s, 1); + let mut session_info = make_session_info(); + session_info.discovery_keys = PAST_PRESENT_FUTURE_AUTHORITIES.clone(); + tx.send(Ok(Some(session_info))).unwrap(); + + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::Authorities(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(PAST_PRESENT_FUTURE_AUTHORITIES.clone())).unwrap(); + } + ); + assert!(overseer.recv().timeout(TIMEOUT).await.is_none()); + + // Change address for one authorithy and check we try to connect to it and + // that we emit UpdateAuthorityID for the old PeerId and the new one. + Delay::new(TRY_RERESOLVE_AUTHORITIES).await; + let changed_peerid = authority_discovery_mock + .change_address_for_authority(authority_that_changes_address.clone()); + let hash = Hash::repeat_byte(0xDD); + let msg = GossipSupportMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerConnected( + changed_peerid, + ObservedRole::Authority, + ValidationVersion::V3.into(), + None, + )); + overseer.send(FromOrchestra::Communication { msg }).await; + + overseer_signal_active_leaves(overseer, hash).await; + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionIndexForChild(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(1)).unwrap(); + } + ); + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::SessionInfo(s, tx), + )) => { + assert_eq!(relay_parent, hash); + assert_eq!(s, 1); + let mut session_info = make_session_info(); + session_info.discovery_keys = PAST_PRESENT_FUTURE_AUTHORITIES.clone(); + tx.send(Ok(Some(session_info))).unwrap(); + + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::RuntimeApi(RuntimeApiMessage::Request( + relay_parent, + RuntimeApiRequest::Authorities(tx), + )) => { + assert_eq!(relay_parent, hash); + tx.send(Ok(PAST_PRESENT_FUTURE_AUTHORITIES.clone())).unwrap(); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeTx(NetworkBridgeTxMessage::AddToResolvedValidators { + validator_addrs, + peer_set, + }) => { + let expected = get_address_map(vec![authority_that_changes_address.clone()], authority_discovery_mock.clone()).await; + let expected: HashSet = expected.into_values().flat_map(|v| v.into_iter()).collect(); + assert_eq!(validator_addrs.into_iter().flat_map(|v| v.into_iter()).collect::>(), expected); + assert_eq!(peer_set, PeerSet::Validation); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeRx(NetworkBridgeRxMessage::UpdatedAuthorityIds { + peer_id, + authority_ids, + }) => { + assert_eq!(authority_discovery_mock.get_authority_ids_by_peer_id(peer_id).await.unwrap(), HashSet::from([authority_that_changes_address.clone()])); + assert!(authority_ids.is_empty()); + } + ); + + assert_matches!( + overseer_recv(overseer).await, + AllMessages::NetworkBridgeRx(NetworkBridgeRxMessage::UpdatedAuthorityIds { + peer_id, + authority_ids, + }) => { + assert_eq!(authority_ids, HashSet::from([authority_that_changes_address])); + assert_eq!(changed_peerid, peer_id); + } + ); + + assert!(overseer.recv().timeout(TIMEOUT).await.is_none()); + + virtual_overseer + }, + ); +} + #[test] fn disconnect_when_not_in_past_present_future() { sp_tracing::try_init_simple(); diff --git a/polkadot/node/network/protocol/Cargo.toml b/polkadot/node/network/protocol/Cargo.toml index c9ae23d756cf..3d51d3c0a565 100644 --- a/polkadot/node/network/protocol/Cargo.toml +++ b/polkadot/node/network/protocol/Cargo.toml @@ -15,7 +15,6 @@ async-trait = { workspace = true } hex = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } -polkadot-node-jaeger = { workspace = true, default-features = true } codec = { features = ["derive"], workspace = true } sc-network = { workspace = true, default-features = true } sc-network-types = { workspace = true, default-features = true } diff --git a/polkadot/node/network/protocol/src/lib.rs b/polkadot/node/network/protocol/src/lib.rs index ca0f8a4e4849..f4f1b715b926 100644 --- a/polkadot/node/network/protocol/src/lib.rs +++ b/polkadot/node/network/protocol/src/lib.rs @@ -21,10 +21,9 @@ use codec::{Decode, Encode}; use polkadot_primitives::{BlockNumber, Hash}; -use std::{collections::HashMap, fmt}; +use std::fmt; #[doc(hidden)] -pub use polkadot_node_jaeger as jaeger; pub use sc_network::IfDisconnected; pub use sc_network_types::PeerId; #[doc(hidden)] @@ -91,31 +90,16 @@ impl Into for ObservedRole { } /// Specialized wrapper around [`View`]. -/// -/// Besides the access to the view itself, it also gives access to the [`jaeger::Span`] per -/// leave/head. #[derive(Debug, Clone, Default)] pub struct OurView { view: View, - span_per_head: HashMap>, } impl OurView { /// Creates a new instance. - pub fn new( - heads: impl IntoIterator)>, - finalized_number: BlockNumber, - ) -> Self { - let state_per_head = heads.into_iter().collect::>(); - let view = View::new(state_per_head.keys().cloned(), finalized_number); - Self { view, span_per_head: state_per_head } - } - - /// Returns the span per head map. - /// - /// For each head there exists one span in this map. - pub fn span_per_head(&self) -> &HashMap> { - &self.span_per_head + pub fn new(heads: impl IntoIterator, finalized_number: BlockNumber) -> Self { + let view = View::new(heads, finalized_number); + Self { view } } } @@ -133,8 +117,7 @@ impl std::ops::Deref for OurView { } } -/// Construct a new [`OurView`] with the given chain heads, finalized number 0 and disabled -/// [`jaeger::Span`]'s. +/// Construct a new [`OurView`] with the given chain heads, finalized number 0 /// /// NOTE: Use for tests only. /// @@ -149,7 +132,7 @@ impl std::ops::Deref for OurView { macro_rules! our_view { ( $( $hash:expr ),* $(,)? ) => { $crate::OurView::new( - vec![ $( $hash.clone() ),* ].into_iter().map(|h| (h, $crate::Arc::new($crate::jaeger::Span::Disabled))), + vec![ $( $hash.clone() ),* ].into_iter().map(|h| h), 0, ) }; diff --git a/polkadot/node/network/protocol/src/request_response/mod.rs b/polkadot/node/network/protocol/src/request_response/mod.rs index fe06593bd7a0..296c462b508d 100644 --- a/polkadot/node/network/protocol/src/request_response/mod.rs +++ b/polkadot/node/network/protocol/src/request_response/mod.rs @@ -51,8 +51,8 @@ use std::{collections::HashMap, time::Duration, u64}; -use polkadot_primitives::{MAX_CODE_SIZE, MAX_POV_SIZE}; -use sc_network::NetworkBackend; +use polkadot_primitives::MAX_CODE_SIZE; +use sc_network::{NetworkBackend, MAX_RESPONSE_SIZE}; use sp_runtime::traits::Block; use strum::{EnumIter, IntoEnumIterator}; @@ -123,10 +123,12 @@ const DEFAULT_REQUEST_TIMEOUT_CONNECTED: Duration = Duration::from_secs(1); /// Timeout for requesting availability chunks. pub const CHUNK_REQUEST_TIMEOUT: Duration = DEFAULT_REQUEST_TIMEOUT_CONNECTED; -/// This timeout is based on what seems sensible from a time budget perspective, considering 6 -/// second block time. This is going to be tough, if we have multiple forks and large PoVs, but we -/// only have so much time. -const POV_REQUEST_TIMEOUT_CONNECTED: Duration = Duration::from_millis(1200); +/// This timeout is based on the following parameters, assuming we use asynchronous backing with no +/// time budget within a relay block: +/// - 500 Mbit/s networking speed +/// - 10 MB PoV +/// - 10 parallel executions +const POV_REQUEST_TIMEOUT_CONNECTED: Duration = Duration::from_millis(2000); /// We want timeout statement requests fast, so we don't waste time on slow nodes. Responders will /// try their best to either serve within that timeout or return an error immediately. (We need to @@ -159,11 +161,8 @@ pub const MAX_PARALLEL_ATTESTED_CANDIDATE_REQUESTS: u32 = 5; /// Response size limit for responses of POV like data. /// -/// This is larger than `MAX_POV_SIZE` to account for protocol overhead and for additional data in -/// `CollationFetchingV1` or `AvailableDataFetchingV1` for example. We try to err on larger limits -/// here as a too large limit only allows an attacker to waste our bandwidth some more, a too low -/// limit might have more severe effects. -const POV_RESPONSE_SIZE: u64 = MAX_POV_SIZE as u64 + 10_000; +/// Same as what we use in substrate networking. +const POV_RESPONSE_SIZE: u64 = MAX_RESPONSE_SIZE; /// Maximum response sizes for `StatementFetchingV1`. /// @@ -217,7 +216,7 @@ impl Protocol { name, legacy_names, 1_000, - POV_RESPONSE_SIZE as u64 * 3, + POV_RESPONSE_SIZE, // We are connected to all validators: CHUNK_REQUEST_TIMEOUT, tx, diff --git a/polkadot/node/network/statement-distribution/src/legacy_v1/mod.rs b/polkadot/node/network/statement-distribution/src/legacy_v1/mod.rs index 264333435a00..8270b9809194 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/mod.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/mod.rs @@ -33,9 +33,8 @@ use polkadot_node_subsystem_util::{ }; use polkadot_node_subsystem::{ - jaeger, messages::{CandidateBackingMessage, NetworkBridgeEvent, NetworkBridgeTxMessage}, - overseer, ActivatedLeaf, PerLeafSpan, StatementDistributionSenderTrait, + overseer, ActivatedLeaf, StatementDistributionSenderTrait, }; use polkadot_primitives::{ AuthorityDiscoveryId, CandidateHash, CommittedCandidateReceipt, CompactStatement, Hash, @@ -632,15 +631,12 @@ pub(crate) struct ActiveHeadData { session_index: sp_staking::SessionIndex, /// How many `Seconded` statements we've seen per validator. seconded_counts: HashMap, - /// A Jaeger span for this head, so we can attach data to it. - span: PerLeafSpan, } impl ActiveHeadData { fn new( validators: IndexedVec, session_index: sp_staking::SessionIndex, - span: PerLeafSpan, ) -> Self { ActiveHeadData { candidates: Default::default(), @@ -650,7 +646,6 @@ impl ActiveHeadData { validators, session_index, seconded_counts: Default::default(), - span, } } @@ -901,12 +896,6 @@ async fn circulate_statement_and_dependents( None => return, }; - let _span = active_head - .span - .child("circulate-statement") - .with_candidate(statement.payload().candidate_hash()) - .with_stage(jaeger::Stage::StatementDistribution); - let topology = topology_store .get_topology_or_fallback(active_head.session_index) .local_grid_neighbors(); @@ -933,12 +922,10 @@ async fn circulate_statement_and_dependents( } }; - let _span = _span.child("send-to-peers"); // Now send dependent statements to all peers needing them, if any. if let Some((candidate_hash, peers_needing_dependents)) = outputs { for peer in peers_needing_dependents { if let Some(peer_data) = peers.get_mut(&peer) { - let _span_loop = _span.child("to-peer").with_peer_id(&peer); // defensive: the peer data should always be some because the iterator // of peers is derived from the set of peers. send_statements_about( @@ -1513,11 +1500,6 @@ async fn handle_incoming_message<'a, Context>( let fingerprint = message.get_fingerprint(); let candidate_hash = *fingerprint.0.candidate_hash(); - let handle_incoming_span = active_head - .span - .child("handle-incoming") - .with_candidate(candidate_hash) - .with_peer_id(&peer); let max_message_count = active_head.validators.len() * 2; @@ -1699,8 +1681,6 @@ async fn handle_incoming_message<'a, Context>( NotedStatement::Fresh(statement) => { modify_reputation(reputation, ctx.sender(), peer, BENEFIT_VALID_STATEMENT_FIRST).await; - let mut _span = handle_incoming_span.child("notify-backing"); - // When we receive a new message from a peer, we forward it to the // candidate backing subsystem. ctx.send_message(CandidateBackingMessage::Statement(relay_parent, statement_with_pvd)) @@ -2079,7 +2059,6 @@ pub(crate) async fn handle_activated_leaf( activated: ActivatedLeaf, ) -> Result<()> { let relay_parent = activated.hash; - let span = PerLeafSpan::new(activated.span, "statement-distribution-legacy"); gum::trace!( target: LOG_TARGET, hash = ?relay_parent, @@ -2095,11 +2074,10 @@ pub(crate) async fn handle_activated_leaf( .await?; let session_info = &info.session_info; - state.active_heads.entry(relay_parent).or_insert(ActiveHeadData::new( - session_info.validators.clone(), - session_index, - span, - )); + state + .active_heads + .entry(relay_parent) + .or_insert(ActiveHeadData::new(session_info.validators.clone(), session_index)); Ok(()) } diff --git a/polkadot/node/network/statement-distribution/src/legacy_v1/requester.rs b/polkadot/node/network/statement-distribution/src/legacy_v1/requester.rs index 8a8a8f3d624a..c0346adfe101 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/requester.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/requester.rs @@ -28,7 +28,6 @@ use polkadot_node_network_protocol::{ }, PeerId, UnifiedReputationChange, }; -use polkadot_node_subsystem::{Span, Stage}; use polkadot_node_subsystem_util::TimeoutExt; use polkadot_primitives::{CandidateHash, CommittedCandidateReceipt, Hash}; @@ -82,10 +81,6 @@ pub async fn fetch( mut sender: mpsc::Sender, metrics: Metrics, ) { - let span = Span::new(candidate_hash, "fetch-large-statement") - .with_relay_parent(relay_parent) - .with_stage(Stage::StatementDistribution); - gum::debug!( target: LOG_TARGET, ?candidate_hash, @@ -102,11 +97,7 @@ pub async fn fetch( // We retry endlessly (with sleep periods), and rely on the subsystem to kill us eventually. loop { - let span = span.child("try-available-peers"); - while let Some(peer) = new_peers.pop() { - let _span = span.child("try-peer").with_peer_id(&peer); - let (outgoing, pending_response) = OutgoingRequest::new(Recipient::Peer(peer), req.clone()); if let Err(err) = sender @@ -182,7 +173,7 @@ pub async fn fetch( new_peers = std::mem::take(&mut tried_peers); // All our peers failed us - try getting new ones before trying again: - match try_get_new_peers(relay_parent, candidate_hash, &mut sender, &span).await { + match try_get_new_peers(relay_parent, candidate_hash, &mut sender).await { Ok(Some(mut peers)) => { gum::trace!(target: LOG_TARGET, ?peers, "Received new peers."); // New arrivals will be tried first: @@ -205,10 +196,7 @@ async fn try_get_new_peers( relay_parent: Hash, candidate_hash: CandidateHash, sender: &mut mpsc::Sender, - span: &Span, ) -> Result>, ()> { - let _span = span.child("wait-for-peers"); - let (tx, rx) = oneshot::channel(); if let Err(err) = sender diff --git a/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs b/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs index 8e6fcbaebbf1..5e00fb96d74f 100644 --- a/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs +++ b/polkadot/node/network/statement-distribution/src/legacy_v1/tests.rs @@ -121,7 +121,6 @@ fn active_head_accepts_only_2_seconded_per_validator() { let mut head_data = ActiveHeadData::new( IndexedVec::::from(validators), session_index, - PerLeafSpan::new(Arc::new(jaeger::Span::Disabled), "test"), ); let keystore: KeystorePtr = Arc::new(LocalKeystore::in_memory()); @@ -467,7 +466,6 @@ fn peer_view_update_sends_messages() { let mut data = ActiveHeadData::new( IndexedVec::::from(validators), session_index, - PerLeafSpan::new(Arc::new(jaeger::Span::Disabled), "test"), ); let statement = SignedFullStatement::sign( diff --git a/polkadot/node/network/statement-distribution/src/v2/mod.rs b/polkadot/node/network/statement-distribution/src/v2/mod.rs index 47d350849b20..f9c2d0ddbae8 100644 --- a/polkadot/node/network/statement-distribution/src/v2/mod.rs +++ b/polkadot/node/network/statement-distribution/src/v2/mod.rs @@ -45,8 +45,9 @@ use polkadot_node_subsystem::{ use polkadot_node_subsystem_util::{ backing_implicit_view::View as ImplicitView, reputation::ReputationAggregator, - runtime::{request_min_backing_votes, ProspectiveParachainsMode}, - vstaging::{fetch_claim_queue, ClaimQueueSnapshot}, + runtime::{ + fetch_claim_queue, request_min_backing_votes, ClaimQueueSnapshot, ProspectiveParachainsMode, + }, }; use polkadot_primitives::{ AuthorityDiscoveryId, CandidateHash, CompactStatement, CoreIndex, CoreState, GroupIndex, @@ -570,7 +571,7 @@ pub(crate) async fn handle_active_leaves_update( for new_relay_parent in new_relay_parents.iter().cloned() { let disabled_validators: HashSet<_> = - polkadot_node_subsystem_util::vstaging::get_disabled_validators_with_fallback( + polkadot_node_subsystem_util::runtime::get_disabled_validators_with_fallback( ctx.sender(), new_relay_parent, ) @@ -2237,7 +2238,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/network/statement-distribution/src/v2/statement_store.rs b/polkadot/node/network/statement-distribution/src/v2/statement_store.rs index a3b2636d2ffc..56a54f6316c0 100644 --- a/polkadot/node/network/statement-distribution/src/v2/statement_store.rs +++ b/polkadot/node/network/statement-distribution/src/v2/statement_store.rs @@ -292,7 +292,7 @@ impl GroupStatements { mod tests { use super::*; - use polkadot_primitives::v7::{Hash, SigningContext, ValidatorPair}; + use polkadot_primitives::{Hash, SigningContext, ValidatorPair}; use sp_application_crypto::Pair as PairT; #[test] diff --git a/polkadot/node/overseer/examples/minimal-example.rs b/polkadot/node/overseer/examples/minimal-example.rs index 86a1801a5f2d..807e7405ff1b 100644 --- a/polkadot/node/overseer/examples/minimal-example.rs +++ b/polkadot/node/overseer/examples/minimal-example.rs @@ -24,15 +24,17 @@ use orchestra::async_trait; use std::time::Duration; use polkadot_node_primitives::{BlockData, PoV}; -use polkadot_node_subsystem_types::messages::CandidateValidationMessage; +use polkadot_node_subsystem_types::messages::{CandidateValidationMessage, PvfExecKind}; use polkadot_overseer::{ self as overseer, dummy::dummy_overseer_builder, gen::{FromOrchestra, SpawnedSubsystem}, HeadSupportsParachains, SubsystemError, }; -use polkadot_primitives::{CandidateReceipt, Hash, PvfExecKind}; -use polkadot_primitives_test_helpers::{dummy_candidate_descriptor, dummy_hash}; +use polkadot_primitives::{CandidateReceipt, Hash, PersistedValidationData}; +use polkadot_primitives_test_helpers::{ + dummy_candidate_descriptor, dummy_hash, dummy_validation_code, +}; struct AlwaysSupportsParachains; @@ -73,7 +75,9 @@ impl Subsystem1 { commitments_hash: Hash::zero(), }; - let msg = CandidateValidationMessage::ValidateFromChainState { + let msg = CandidateValidationMessage::ValidateFromExhaustive { + validation_data: PersistedValidationData { ..Default::default() }, + validation_code: dummy_validation_code(), candidate_receipt, pov: PoV { block_data: BlockData(Vec::new()) }.into(), executor_params: Default::default(), diff --git a/polkadot/node/overseer/src/dummy.rs b/polkadot/node/overseer/src/dummy.rs index fc5f0070773b..d618c0c7ca95 100644 --- a/polkadot/node/overseer/src/dummy.rs +++ b/polkadot/node/overseer/src/dummy.rs @@ -88,6 +88,7 @@ pub fn dummy_overseer_builder( DummySubsystem, DummySubsystem, DummySubsystem, + DummySubsystem, >, SubsystemError, > @@ -131,6 +132,7 @@ pub fn one_for_all_overseer_builder( Sub, Sub, Sub, + Sub, >, SubsystemError, > @@ -155,6 +157,7 @@ where + Subsystem, SubsystemError> + Subsystem, SubsystemError> + Subsystem, SubsystemError> + + Subsystem, SubsystemError> + Subsystem, SubsystemError> + Subsystem, SubsystemError> + Subsystem, SubsystemError> @@ -183,13 +186,13 @@ where .statement_distribution(subsystem.clone()) .approval_distribution(subsystem.clone()) .approval_voting(subsystem.clone()) + .approval_voting_parallel(subsystem.clone()) .gossip_support(subsystem.clone()) .dispute_coordinator(subsystem.clone()) .dispute_distribution(subsystem.clone()) .chain_selection(subsystem.clone()) .prospective_parachains(subsystem.clone()) .activation_external_listeners(Default::default()) - .span_per_active_leaf(Default::default()) .active_leaves(Default::default()) .spawner(SpawnGlue(spawner)) .metrics(metrics) diff --git a/polkadot/node/overseer/src/lib.rs b/polkadot/node/overseer/src/lib.rs index 4e13d5eda76f..87ef63d8a5d7 100644 --- a/polkadot/node/overseer/src/lib.rs +++ b/polkadot/node/overseer/src/lib.rs @@ -60,6 +60,7 @@ // unused dependencies can not work for test and examples at the same time // yielding false positives #![warn(missing_docs)] +#![allow(dead_code)] // TODO https://github.com/paritytech/polkadot-sdk/issues/5793 use std::{ collections::{hash_map, HashMap}, @@ -76,19 +77,19 @@ use sc_client_api::{BlockImportNotification, BlockchainEvents, FinalityNotificat use self::messages::{BitfieldSigningMessage, PvfCheckerMessage}; use polkadot_node_subsystem_types::messages::{ - ApprovalDistributionMessage, ApprovalVotingMessage, AvailabilityDistributionMessage, - AvailabilityRecoveryMessage, AvailabilityStoreMessage, BitfieldDistributionMessage, - CandidateBackingMessage, CandidateValidationMessage, ChainApiMessage, ChainSelectionMessage, - CollationGenerationMessage, CollatorProtocolMessage, DisputeCoordinatorMessage, - DisputeDistributionMessage, GossipSupportMessage, NetworkBridgeRxMessage, - NetworkBridgeTxMessage, ProspectiveParachainsMessage, ProvisionerMessage, RuntimeApiMessage, - StatementDistributionMessage, + ApprovalDistributionMessage, ApprovalVotingMessage, ApprovalVotingParallelMessage, + AvailabilityDistributionMessage, AvailabilityRecoveryMessage, AvailabilityStoreMessage, + BitfieldDistributionMessage, CandidateBackingMessage, CandidateValidationMessage, + ChainApiMessage, ChainSelectionMessage, CollationGenerationMessage, CollatorProtocolMessage, + DisputeCoordinatorMessage, DisputeDistributionMessage, GossipSupportMessage, + NetworkBridgeRxMessage, NetworkBridgeTxMessage, ProspectiveParachainsMessage, + ProvisionerMessage, RuntimeApiMessage, StatementDistributionMessage, }; pub use polkadot_node_subsystem_types::{ errors::{SubsystemError, SubsystemResult}, - jaeger, ActivatedLeaf, ActiveLeavesUpdate, ChainApiBackend, OverseerSignal, - RuntimeApiSubsystemClient, UnpinHandle, + ActivatedLeaf, ActiveLeavesUpdate, ChainApiBackend, OverseerSignal, RuntimeApiSubsystemClient, + UnpinHandle, }; pub mod metrics; @@ -466,7 +467,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, @@ -521,7 +522,7 @@ pub struct Overseer { ])] bitfield_signing: BitfieldSigning, - #[subsystem(BitfieldDistributionMessage, sends: [ + #[subsystem(blocking, message_capacity: 8192, BitfieldDistributionMessage, sends: [ RuntimeApiMessage, NetworkBridgeTxMessage, ProvisionerMessage, @@ -550,6 +551,7 @@ pub struct Overseer { BitfieldDistributionMessage, StatementDistributionMessage, ApprovalDistributionMessage, + ApprovalVotingParallelMessage, GossipSupportMessage, DisputeDistributionMessage, CollationGenerationMessage, @@ -581,6 +583,7 @@ pub struct Overseer { #[subsystem(blocking, message_capacity: 64000, ApprovalDistributionMessage, sends: [ NetworkBridgeTxMessage, ApprovalVotingMessage, + RuntimeApiMessage, ], can_receive_priority_messages)] approval_distribution: ApprovalDistribution, @@ -594,7 +597,19 @@ pub struct Overseer { RuntimeApiMessage, ])] approval_voting: ApprovalVoting, - + #[subsystem(blocking, message_capacity: 64000, ApprovalVotingParallelMessage, sends: [ + AvailabilityRecoveryMessage, + CandidateValidationMessage, + ChainApiMessage, + ChainSelectionMessage, + DisputeCoordinatorMessage, + RuntimeApiMessage, + NetworkBridgeTxMessage, + ApprovalVotingMessage, + ApprovalDistributionMessage, + ApprovalVotingParallelMessage, + ])] + approval_voting_parallel: ApprovalVotingParallel, #[subsystem(GossipSupportMessage, sends: [ NetworkBridgeTxMessage, NetworkBridgeRxMessage, // TODO @@ -612,6 +627,7 @@ pub struct Overseer { AvailabilityStoreMessage, AvailabilityRecoveryMessage, ChainSelectionMessage, + ApprovalVotingParallelMessage, ])] dispute_coordinator: DisputeCoordinator, @@ -634,9 +650,6 @@ pub struct Overseer { /// External listeners waiting for a hash to be in the active-leave set. pub activation_external_listeners: HashMap>>>, - /// Stores the [`jaeger::Span`] per active leaf. - pub span_per_active_leaf: HashMap>, - /// The set of the "active leaves". pub active_leaves: HashMap, @@ -801,11 +814,10 @@ where }; let mut update = match self.on_head_activated(&block.hash, Some(block.parent_hash)).await { - Some(span) => ActiveLeavesUpdate::start_work(ActivatedLeaf { + Some(_) => ActiveLeavesUpdate::start_work(ActivatedLeaf { hash: block.hash, number: block.number, unpin_handle: block.unpin_handle, - span, }), None => ActiveLeavesUpdate::default(), }; @@ -858,11 +870,7 @@ where /// Handles a header activation. If the header's state doesn't support the parachains API, /// this returns `None`. - async fn on_head_activated( - &mut self, - hash: &Hash, - parent_hash: Option, - ) -> Option> { + async fn on_head_activated(&mut self, hash: &Hash, _parent_hash: Option) -> Option<()> { if !self.supports_parachains.head_supports_parachains(hash).await { return None } @@ -880,22 +888,12 @@ where } } - let mut span = jaeger::Span::new(*hash, "leaf-activated"); - - if let Some(parent_span) = parent_hash.and_then(|h| self.span_per_active_leaf.get(&h)) { - span.add_follows_from(parent_span); - } - - let span = Arc::new(span); - self.span_per_active_leaf.insert(*hash, span.clone()); - - Some(span) + Some(()) } fn on_head_deactivated(&mut self, hash: &Hash) { self.metrics.on_head_deactivated(); self.activation_external_listeners.remove(hash); - self.span_per_active_leaf.remove(hash); } fn clean_up_external_listeners(&mut self) { diff --git a/polkadot/node/overseer/src/tests.rs b/polkadot/node/overseer/src/tests.rs index 8e78d8fc8921..46864a482e2a 100644 --- a/polkadot/node/overseer/src/tests.rs +++ b/polkadot/node/overseer/src/tests.rs @@ -25,14 +25,14 @@ use polkadot_node_primitives::{ }; use polkadot_node_subsystem_test_helpers::mock::{dummy_unpin_handle, new_leaf}; use polkadot_node_subsystem_types::messages::{ - NetworkBridgeEvent, ReportPeerMessage, RuntimeApiRequest, + NetworkBridgeEvent, PvfExecKind, ReportPeerMessage, RuntimeApiRequest, }; use polkadot_primitives::{ CandidateHash, CandidateReceipt, CollatorPair, Id as ParaId, InvalidDisputeStatementKind, - PvfExecKind, SessionIndex, ValidDisputeStatementKind, ValidatorIndex, + PersistedValidationData, SessionIndex, ValidDisputeStatementKind, ValidatorIndex, }; use polkadot_primitives_test_helpers::{ - dummy_candidate_descriptor, dummy_candidate_receipt, dummy_hash, + dummy_candidate_descriptor, dummy_candidate_receipt, dummy_hash, dummy_validation_code, }; use crate::{ @@ -104,7 +104,9 @@ where }; let (tx, _) = oneshot::channel(); - ctx.send_message(CandidateValidationMessage::ValidateFromChainState { + ctx.send_message(CandidateValidationMessage::ValidateFromExhaustive { + validation_data: PersistedValidationData { ..Default::default() }, + validation_code: dummy_validation_code(), candidate_receipt, pov: PoV { block_data: BlockData(Vec::new()) }.into(), executor_params: Default::default(), @@ -802,7 +804,9 @@ fn test_candidate_validation_msg() -> CandidateValidationMessage { commitments_hash: Hash::zero(), }; - CandidateValidationMessage::ValidateFromChainState { + CandidateValidationMessage::ValidateFromExhaustive { + validation_data: PersistedValidationData { ..Default::default() }, + validation_code: dummy_validation_code(), candidate_receipt, pov, executor_params: Default::default(), @@ -950,7 +954,7 @@ fn test_prospective_parachains_msg() -> ProspectiveParachainsMessage { // Checks that `stop`, `broadcast_signal` and `broadcast_message` are implemented correctly. #[test] fn overseer_all_subsystems_receive_signals_and_messages() { - const NUM_SUBSYSTEMS: usize = 23; + const NUM_SUBSYSTEMS: usize = 24; // -4 for BitfieldSigning, GossipSupport, AvailabilityDistribution and PvfCheckerSubsystem. const NUM_SUBSYSTEMS_MESSAGED: usize = NUM_SUBSYSTEMS - 4; @@ -1028,6 +1032,11 @@ fn overseer_all_subsystems_receive_signals_and_messages() { handle .send_msg_anon(AllMessages::ApprovalDistribution(test_approval_distribution_msg())) .await; + handle + .send_msg_anon(AllMessages::ApprovalVotingParallel( + test_approval_distribution_msg().into(), + )) + .await; handle .send_msg_anon(AllMessages::ApprovalVoting(test_approval_voting_msg())) .await; @@ -1101,6 +1110,7 @@ fn context_holds_onto_message_until_enough_signals_received() { let (chain_selection_bounded_tx, _) = metered::channel(CHANNEL_CAPACITY); let (pvf_checker_bounded_tx, _) = metered::channel(CHANNEL_CAPACITY); let (prospective_parachains_bounded_tx, _) = metered::channel(CHANNEL_CAPACITY); + let (approval_voting_parallel_tx, _) = metered::channel(CHANNEL_CAPACITY); let (candidate_validation_unbounded_tx, _) = metered::unbounded(); let (candidate_backing_unbounded_tx, _) = metered::unbounded(); @@ -1125,6 +1135,7 @@ fn context_holds_onto_message_until_enough_signals_received() { let (chain_selection_unbounded_tx, _) = metered::unbounded(); let (pvf_checker_unbounded_tx, _) = metered::unbounded(); let (prospective_parachains_unbounded_tx, _) = metered::unbounded(); + let (approval_voting_parallel_unbounded_tx, _) = metered::unbounded(); let channels_out = ChannelsOut { candidate_validation: candidate_validation_bounded_tx.clone(), @@ -1150,6 +1161,7 @@ fn context_holds_onto_message_until_enough_signals_received() { chain_selection: chain_selection_bounded_tx.clone(), pvf_checker: pvf_checker_bounded_tx.clone(), prospective_parachains: prospective_parachains_bounded_tx.clone(), + approval_voting_parallel: approval_voting_parallel_tx.clone(), candidate_validation_unbounded: candidate_validation_unbounded_tx.clone(), candidate_backing_unbounded: candidate_backing_unbounded_tx.clone(), @@ -1174,6 +1186,7 @@ fn context_holds_onto_message_until_enough_signals_received() { chain_selection_unbounded: chain_selection_unbounded_tx.clone(), pvf_checker_unbounded: pvf_checker_unbounded_tx.clone(), prospective_parachains_unbounded: prospective_parachains_unbounded_tx.clone(), + approval_voting_parallel_unbounded: approval_voting_parallel_unbounded_tx.clone(), }; let (mut signal_tx, signal_rx) = metered::channel(CHANNEL_CAPACITY); diff --git a/polkadot/node/primitives/Cargo.toml b/polkadot/node/primitives/Cargo.toml index cd642bf16ff9..7185205f905b 100644 --- a/polkadot/node/primitives/Cargo.toml +++ b/polkadot/node/primitives/Cargo.toml @@ -12,11 +12,13 @@ workspace = true [dependencies] bounded-vec = { workspace = true } futures = { workspace = true } +futures-timer = { workspace = true } polkadot-primitives = { workspace = true, default-features = true } codec = { features = ["derive"], workspace = true } sp-core = { workspace = true, default-features = true } sp-application-crypto = { workspace = true, default-features = true } sp-consensus-babe = { workspace = true, default-features = true } +sp-consensus-slots = { workspace = true } sp-keystore = { workspace = true, default-features = true } sp-maybe-compressed-blob = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } @@ -25,6 +27,7 @@ schnorrkel = { workspace = true, default-features = true } thiserror = { workspace = true } bitvec = { features = ["alloc"], workspace = true } serde = { features = ["derive"], workspace = true, default-features = true } +sc-keystore = { workspace = true } [target.'cfg(not(target_os = "unknown"))'.dependencies] zstd = { version = "0.12.4", default-features = false } diff --git a/polkadot/node/primitives/src/approval/criteria.rs b/polkadot/node/primitives/src/approval/criteria.rs new file mode 100644 index 000000000000..0a1a0ee2367f --- /dev/null +++ b/polkadot/node/primitives/src/approval/criteria.rs @@ -0,0 +1,177 @@ +// 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 . + +//! Assignment criteria VRF generation and checking interfaces. + +use crate::approval::{ + v1::{DelayTranche, RelayVRFStory}, + v2::{AssignmentCertV2, CoreBitfield}, +}; +use codec::{Decode, Encode}; +use polkadot_primitives::{ + AssignmentId, CandidateHash, CoreIndex, GroupIndex, IndexedVec, SessionInfo, ValidatorIndex, +}; +use sc_keystore::LocalKeystore; + +use std::collections::HashMap; + +/// Details pertaining to our assignment on a block. +#[derive(Debug, Clone, Encode, Decode, PartialEq)] +pub struct OurAssignment { + cert: AssignmentCertV2, + tranche: DelayTranche, + validator_index: ValidatorIndex, + // Whether the assignment has been triggered already. + triggered: bool, +} + +impl OurAssignment { + /// Create a new `OurAssignment`. + pub fn new( + cert: AssignmentCertV2, + tranche: DelayTranche, + validator_index: ValidatorIndex, + triggered: bool, + ) -> Self { + OurAssignment { cert, tranche, validator_index, triggered } + } + /// Returns a reference to the assignment cert. + pub fn cert(&self) -> &AssignmentCertV2 { + &self.cert + } + + /// Returns the assignment cert. + pub fn into_cert(self) -> AssignmentCertV2 { + self.cert + } + + /// Returns the delay tranche of the assignment. + pub fn tranche(&self) -> DelayTranche { + self.tranche + } + + /// Returns the validator index of the assignment. + pub fn validator_index(&self) -> ValidatorIndex { + self.validator_index + } + + /// Returns whether the assignment has been triggered. + pub fn triggered(&self) -> bool { + self.triggered + } + + /// Marks the assignment as triggered. + pub fn mark_triggered(&mut self) { + self.triggered = true; + } +} + +/// Information about the world assignments are being produced in. +#[derive(Clone, Debug)] +pub struct Config { + /// The assignment public keys for validators. + pub assignment_keys: Vec, + /// The groups of validators assigned to each core. + pub validator_groups: IndexedVec>, + /// The number of availability cores used by the protocol during this session. + pub n_cores: u32, + /// The zeroth delay tranche width. + pub zeroth_delay_tranche_width: u32, + /// The number of samples we do of `relay_vrf_modulo`. + pub relay_vrf_modulo_samples: u32, + /// The number of delay tranches in total. + pub n_delay_tranches: u32, +} + +impl<'a> From<&'a SessionInfo> for Config { + fn from(s: &'a SessionInfo) -> Self { + Config { + assignment_keys: s.assignment_keys.clone(), + validator_groups: s.validator_groups.clone(), + n_cores: s.n_cores, + zeroth_delay_tranche_width: s.zeroth_delay_tranche_width, + relay_vrf_modulo_samples: s.relay_vrf_modulo_samples, + n_delay_tranches: s.n_delay_tranches, + } + } +} + +/// A trait for producing and checking assignments. +/// +/// Approval voting subsystem implements a a real implemention +/// for it and tests use a mock implementation. +pub trait AssignmentCriteria { + /// Compute the assignments for the given relay VRF story. + fn compute_assignments( + &self, + keystore: &LocalKeystore, + relay_vrf_story: RelayVRFStory, + config: &Config, + leaving_cores: Vec<(CandidateHash, CoreIndex, GroupIndex)>, + enable_v2_assignments: bool, + ) -> HashMap; + + /// Check the assignment cert for the given relay VRF story and returns the delay tranche. + fn check_assignment_cert( + &self, + claimed_core_bitfield: CoreBitfield, + validator_index: ValidatorIndex, + config: &Config, + relay_vrf_story: RelayVRFStory, + assignment: &AssignmentCertV2, + // Backing groups for each "leaving core". + backing_groups: Vec, + ) -> Result; +} + +/// Assignment invalid. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct InvalidAssignment(pub InvalidAssignmentReason); + +impl std::fmt::Display for InvalidAssignment { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "Invalid Assignment: {:?}", self.0) + } +} + +impl std::error::Error for InvalidAssignment {} + +/// Failure conditions when checking an assignment cert. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum InvalidAssignmentReason { + /// The validator index is out of bounds. + ValidatorIndexOutOfBounds, + /// Sample index is out of bounds. + SampleOutOfBounds, + /// Core index is out of bounds. + CoreIndexOutOfBounds, + /// Invalid assignment key. + InvalidAssignmentKey, + /// Node is in backing group. + IsInBackingGroup, + /// Modulo core index mismatch. + VRFModuloCoreIndexMismatch, + /// Modulo output mismatch. + VRFModuloOutputMismatch, + /// Delay core index mismatch. + VRFDelayCoreIndexMismatch, + /// Delay output mismatch. + VRFDelayOutputMismatch, + /// Invalid arguments + InvalidArguments, + /// Assignment vrf check resulted in 0 assigned cores. + NullAssignment, +} diff --git a/polkadot/node/primitives/src/approval.rs b/polkadot/node/primitives/src/approval/mod.rs similarity index 98% rename from polkadot/node/primitives/src/approval.rs rename to polkadot/node/primitives/src/approval/mod.rs index 66883b33367b..42342f9889a9 100644 --- a/polkadot/node/primitives/src/approval.rs +++ b/polkadot/node/primitives/src/approval/mod.rs @@ -16,6 +16,12 @@ //! Types relevant for approval. +/// Criteria for assignment. +pub mod criteria; + +/// Time utilities for approval voting. +pub mod time; + /// A list of primitives introduced in v1. pub mod v1 { use sp_consensus_babe as babe_primitives; @@ -25,8 +31,8 @@ pub mod v1 { use codec::{Decode, Encode}; use polkadot_primitives::{ - BlockNumber, CandidateHash, CandidateIndex, CoreIndex, Hash, Header, SessionIndex, - ValidatorIndex, ValidatorSignature, + BlockNumber, CandidateHash, CandidateIndex, CoreIndex, GroupIndex, Hash, Header, + SessionIndex, ValidatorIndex, ValidatorSignature, }; use sp_application_crypto::ByteArray; @@ -118,7 +124,7 @@ pub mod v1 { } /// Metadata about a block which is now live in the approval protocol. - #[derive(Debug)] + #[derive(Debug, Clone)] pub struct BlockApprovalMeta { /// The hash of the block. pub hash: Hash, @@ -128,11 +134,13 @@ pub mod v1 { pub parent_hash: Hash, /// The candidates included by the block. /// Note that these are not the same as the candidates that appear within the block body. - pub candidates: Vec, + pub candidates: Vec<(CandidateHash, CoreIndex, GroupIndex)>, /// The consensus slot of the block. pub slot: Slot, /// The session of the block. pub session: SessionIndex, + /// The vrf story. + pub vrf_story: RelayVRFStory, } /// Errors that can occur during the approvals protocol. diff --git a/polkadot/node/core/approval-voting/src/time.rs b/polkadot/node/primitives/src/approval/time.rs similarity index 95% rename from polkadot/node/core/approval-voting/src/time.rs rename to polkadot/node/primitives/src/approval/time.rs index 5c3e7e85a17a..465aae23c90e 100644 --- a/polkadot/node/core/approval-voting/src/time.rs +++ b/polkadot/node/primitives/src/approval/time.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Time utilities for approval voting. +//! Time utilities for approval voting subsystems. use futures::{ future::BoxFuture, @@ -23,7 +23,7 @@ use futures::{ Stream, StreamExt, }; -use polkadot_node_primitives::approval::v1::DelayTranche; +use crate::approval::v1::DelayTranche; use sp_consensus_slots::Slot; use std::{ collections::HashSet, @@ -33,11 +33,15 @@ use std::{ }; use polkadot_primitives::{Hash, ValidatorIndex}; +/// The duration of a single tick in milliseconds. pub const TICK_DURATION_MILLIS: u64 = 500; /// A base unit of time, starting from the Unix epoch, split into half-second intervals. pub type Tick = u64; +/// How far in the future a tick can be accepted. +pub const TICK_TOO_FAR_IN_FUTURE: Tick = 20; // 10 seconds. + /// A clock which allows querying of the current tick as well as /// waiting for a tick to be reached. pub trait Clock { @@ -50,6 +54,7 @@ pub trait Clock { /// Extension methods for clocks. pub trait ClockExt { + /// Returns the current tranche. fn tranche_now(&self, slot_duration_millis: u64, base_slot: Slot) -> DelayTranche; } @@ -124,7 +129,7 @@ impl DelayedApprovalTimer { /// /// Guarantees that if a timer already exits for the give block hash, /// no additional timer is started. - pub(crate) fn maybe_arm_timer( + pub fn maybe_arm_timer( &mut self, wait_until: Tick, clock: &dyn Clock, @@ -173,7 +178,7 @@ mod tests { use futures_timer::Delay; use polkadot_primitives::{Hash, ValidatorIndex}; - use crate::time::{Clock, SystemClock}; + use crate::approval::time::{Clock, SystemClock}; use super::DelayedApprovalTimer; diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs index 660b504e97fb..a525b2bc9776 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.16.1"; // For a 16-ary Merkle Prefix Trie, we can expect at most 16 32-byte hashes per node // plus some overhead: @@ -105,7 +105,7 @@ pub const MAX_FINALITY_LAG: u32 = 500; /// Type of a session window size. /// /// We are not using `NonZeroU32` here because `expect` and `unwrap` are not yet const, so global -/// constants of `SessionWindowSize` would require `lazy_static` in that case. +/// constants of `SessionWindowSize` would require `LazyLock` in that case. /// /// See: #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] diff --git a/polkadot/node/service/Cargo.toml b/polkadot/node/service/Cargo.toml index c0ddbf7dcfc3..3edb3f4dadbe 100644 --- a/polkadot/node/service/Cargo.toml +++ b/polkadot/node/service/Cargo.toml @@ -18,15 +18,13 @@ sc-consensus-beefy = { workspace = true, default-features = true } sc-consensus-grandpa = { workspace = true, default-features = true } mmr-gadget = { workspace = true, default-features = true } sp-mmr-primitives = { workspace = true, default-features = true } -sc-block-builder = { workspace = true, default-features = true } +sp-genesis-builder = { workspace = true, default-features = true } sc-chain-spec = { workspace = true, default-features = true } sc-client-api = { workspace = true, default-features = true } -sc-client-db = { workspace = true, default-features = true } sc-consensus = { workspace = true, default-features = true } sc-consensus-slots = { workspace = true, default-features = true } sc-executor = { workspace = true, default-features = true } sc-network = { workspace = true, default-features = true } -sc-network-common = { workspace = true, default-features = true } sc-network-sync = { workspace = true, default-features = true } sc-transaction-pool = { workspace = true, default-features = true } sc-transaction-pool-api = { workspace = true, default-features = true } @@ -50,22 +48,17 @@ sp-block-builder = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } sp-io = { workspace = true, default-features = true } -sp-keystore = { workspace = true, default-features = true } sp-offchain = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sp-session = { workspace = true, default-features = true } -sp-storage = { workspace = true, default-features = true } sp-transaction-pool = { workspace = true, default-features = true } pallet-transaction-payment = { workspace = true, default-features = true } sp-timestamp = { workspace = true, default-features = true } sp-consensus-babe = { workspace = true, default-features = true } -sp-state-machine = { workspace = true, default-features = true } sp-weights = { workspace = true, default-features = true } sp-version = { workspace = true, default-features = true } # Substrate Pallets -pallet-babe = { workspace = true, default-features = true } -pallet-staking = { workspace = true, default-features = true } pallet-transaction-payment-rpc-runtime-api = { workspace = true, default-features = true } frame-metadata-hash-extension = { optional = true, workspace = true, default-features = true } frame-system = { workspace = true, default-features = true } @@ -73,18 +66,15 @@ frame-system = { workspace = true, default-features = true } # Substrate Other frame-system-rpc-runtime-api = { workspace = true, default-features = true } prometheus-endpoint = { workspace = true, default-features = true } -frame-support = { workspace = true, default-features = true } frame-benchmarking-cli = { workspace = true, default-features = true } frame-benchmarking = { workspace = true, default-features = true } # External Crates async-trait = { workspace = true } futures = { workspace = true } -hex-literal = { workspace = true, default-features = true } is_executable = { workspace = true } gum = { workspace = true, default-features = true } log = { workspace = true, default-features = true } -schnellru = { workspace = true } serde = { features = ["derive"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } thiserror = { workspace = true } @@ -93,13 +83,11 @@ kvdb-rocksdb = { optional = true, workspace = true } parity-db = { optional = true, workspace = true } codec = { workspace = true, default-features = true } parking_lot = { workspace = true, default-features = true } -bitvec = { optional = true, workspace = true, default-features = true } # Polkadot polkadot-core-primitives = { workspace = true, default-features = true } polkadot-node-core-parachains-inherent = { workspace = true, default-features = true } polkadot-overseer = { workspace = true, default-features = true } -polkadot-parachain-primitives = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } polkadot-rpc = { workspace = true, default-features = true } @@ -128,6 +116,7 @@ polkadot-gossip-support = { optional = true, workspace = true, default-features polkadot-network-bridge = { optional = true, workspace = true, default-features = true } polkadot-node-collation-generation = { optional = true, workspace = true, default-features = true } polkadot-node-core-approval-voting = { optional = true, workspace = true, default-features = true } +polkadot-node-core-approval-voting-parallel = { optional = true, workspace = true, default-features = true } polkadot-node-core-av-store = { optional = true, workspace = true, default-features = true } polkadot-node-core-backing = { optional = true, workspace = true, default-features = true } polkadot-node-core-bitfield-signing = { optional = true, workspace = true, default-features = true } @@ -149,7 +138,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 } @@ -172,6 +161,7 @@ full-node = [ "polkadot-network-bridge", "polkadot-node-collation-generation", "polkadot-node-core-approval-voting", + "polkadot-node-core-approval-voting-parallel", "polkadot-node-core-av-store", "polkadot-node-core-backing", "polkadot-node-core-bitfield-signing", @@ -189,13 +179,11 @@ full-node = [ # Configure the native runtimes to use. westend-native = [ - "bitvec", "frame-metadata-hash-extension", "westend-runtime", "westend-runtime-constants", ] rococo-native = [ - "bitvec", "frame-metadata-hash-extension", "rococo-runtime", "rococo-runtime-constants", @@ -211,33 +199,29 @@ metadata-hash = [ runtime-benchmarks = [ "frame-benchmarking-cli/runtime-benchmarks", "frame-benchmarking/runtime-benchmarks", - "frame-support/runtime-benchmarks", "frame-system/runtime-benchmarks", - "pallet-babe/runtime-benchmarks", - "pallet-staking/runtime-benchmarks", - "polkadot-parachain-primitives/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "polkadot-runtime-parachains/runtime-benchmarks", "polkadot-test-client/runtime-benchmarks", "rococo-runtime?/runtime-benchmarks", - "sc-client-db/runtime-benchmarks", "sc-service/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "westend-runtime?/runtime-benchmarks", "xcm-runtime-apis/runtime-benchmarks", ] try-runtime = [ - "frame-support/try-runtime", "frame-system/try-runtime", - "pallet-babe/try-runtime", - "pallet-staking/try-runtime", "pallet-transaction-payment/try-runtime", "polkadot-runtime-parachains/try-runtime", "rococo-runtime?/try-runtime", "sp-runtime/try-runtime", "westend-runtime?/try-runtime", ] -fast-runtime = ["rococo-runtime?/fast-runtime", "westend-runtime?/fast-runtime"] +fast-runtime = [ + "rococo-runtime?/fast-runtime", + "westend-runtime?/fast-runtime", +] malus = ["full-node"] runtime-metrics = [ diff --git a/polkadot/node/service/chain-specs/kusama.json b/polkadot/node/service/chain-specs/kusama.json index 5d2413ac1e02..ff38192906da 100644 --- a/polkadot/node/service/chain-specs/kusama.json +++ b/polkadot/node/service/chain-specs/kusama.json @@ -37,7 +37,8 @@ "/dns/ibp-boot-kusama.luckyfriday.io/tcp/30333/p2p/12D3KooW9vu1GWHBuxyhm7rZgD3fhGZpNajPXFexadvhujWMgwfT", "/dns/boot-kusama.luckyfriday.io/tcp/443/wss/p2p/12D3KooWS1Lu6DmK8YHSvkErpxpcXmk14vG6y4KVEFEkd9g62PP8", "/dns/ibp-boot-kusama.luckyfriday.io/tcp/30334/wss/p2p/12D3KooW9vu1GWHBuxyhm7rZgD3fhGZpNajPXFexadvhujWMgwfT", - "/dns4/kusama-0.boot.onfinality.io/tcp/27682/ws/p2p/12D3KooWFrwFo7ry3dEuFwhehGSSN96a5Xdzxot7SWfXeSbhELAe" + "/dns4/kusama-0.boot.onfinality.io/tcp/27682/ws/p2p/12D3KooWFrwFo7ry3dEuFwhehGSSN96a5Xdzxot7SWfXeSbhELAe", + "/dns/kusama.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWJHhnF64TXSmyxNkhPkXAHtYNRy86LuvGQu1LTi5vrJCL" ], "telemetryEndpoints": [ [ diff --git a/polkadot/node/service/chain-specs/paseo.json b/polkadot/node/service/chain-specs/paseo.json index 35ac9aa6aa93..aacfdb025786 100644 --- a/polkadot/node/service/chain-specs/paseo.json +++ b/polkadot/node/service/chain-specs/paseo.json @@ -20,7 +20,8 @@ "/dns/pso16.rotko.net/tcp/33246/p2p/12D3KooWRH8eBMhw8c7bucy6pJfy94q4dKpLkF3pmeGohHmemdRu", "/dns/pso16.rotko.net/tcp/35246/wss/p2p/12D3KooWRH8eBMhw8c7bucy6pJfy94q4dKpLkF3pmeGohHmemdRu", "/dns/paseo-boot-ng.dwellir.com/tcp/443/wss/p2p/12D3KooWBLLFKDGBxCwq3QmU3YwWKXUx953WwprRshJQicYu4Cfr", - "/dns/paseo-boot-ng.dwellir.com/tcp/30354/p2p/12D3KooWBLLFKDGBxCwq3QmU3YwWKXUx953WwprRshJQicYu4Cfr" + "/dns/paseo-boot-ng.dwellir.com/tcp/30354/p2p/12D3KooWBLLFKDGBxCwq3QmU3YwWKXUx953WwprRshJQicYu4Cfr", + "/dns/paseo.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWMdND5nwfCs5M2rfp5kyRo41BGDgD8V67rVRaB3acgZ53" ], "telemetryEndpoints": null, "protocolId": "pas", diff --git a/polkadot/node/service/chain-specs/polkadot.json b/polkadot/node/service/chain-specs/polkadot.json index 553ff1bb3e41..7e1e90f6a8c1 100644 --- a/polkadot/node/service/chain-specs/polkadot.json +++ b/polkadot/node/service/chain-specs/polkadot.json @@ -38,7 +38,8 @@ "/dns/ibp-boot-polkadot.luckyfriday.io/tcp/30333/p2p/12D3KooWEjk6QXrZJ26fLpaajisJGHiz6WiQsR8k7mkM9GmWKnRZ", "/dns/ibp-boot-polkadot.luckyfriday.io/tcp/30334/wss/p2p/12D3KooWEjk6QXrZJ26fLpaajisJGHiz6WiQsR8k7mkM9GmWKnRZ", "/dns/boot-polkadot.luckyfriday.io/tcp/443/wss/p2p/12D3KooWAdyiVAaeGdtBt6vn5zVetwA4z4qfm9Fi2QCSykN1wTBJ", - "/dns4/polkadot-0.boot.onfinality.io/tcp/24446/ws/p2p/12D3KooWT1PWaNdAwYrSr89dvStnoGdH3t4LNRbcVNN4JCtsotkR" + "/dns4/polkadot-0.boot.onfinality.io/tcp/24446/ws/p2p/12D3KooWT1PWaNdAwYrSr89dvStnoGdH3t4LNRbcVNN4JCtsotkR", + "/dns/polkadot.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWEymrFRHz6c17YP3FAyd8kXS5gMRLgkW4U77ZJD2ZNCLZ" ], "telemetryEndpoints": [ [ diff --git a/polkadot/node/service/chain-specs/westend.json b/polkadot/node/service/chain-specs/westend.json index 9059d525689d..08c5bd33b4bd 100644 --- a/polkadot/node/service/chain-specs/westend.json +++ b/polkadot/node/service/chain-specs/westend.json @@ -33,7 +33,8 @@ "/dns/wnd14.rotko.net/tcp/35234/wss/p2p/12D3KooWLK8Zj1uZ46phU3vQwiDVda8tB76S8J26rXZQLHpwWkDJ", "/dns/wnd14.rotko.net/tcp/33234/p2p/12D3KooWLK8Zj1uZ46phU3vQwiDVda8tB76S8J26rXZQLHpwWkDJ", "/dns/ibp-boot-westend.luckyfriday.io/tcp/30333/p2p/12D3KooWDg1YEytdwFFNWroFj6gio4YFsMB3miSbHKgdpJteUMB9", - "/dns/ibp-boot-westend.luckyfriday.io/tcp/30334/wss/p2p/12D3KooWDg1YEytdwFFNWroFj6gio4YFsMB3miSbHKgdpJteUMB9" + "/dns/ibp-boot-westend.luckyfriday.io/tcp/30334/wss/p2p/12D3KooWDg1YEytdwFFNWroFj6gio4YFsMB3miSbHKgdpJteUMB9", + "/dns/westend.bootnode.stkd.io/tcp/30633/wss/p2p/12D3KooWHaQKkJiTPqeNgqDcW7dfYgJxYwT8YqJMtTkueSu6378V" ], "telemetryEndpoints": [ [ diff --git a/polkadot/node/service/chain-specs/wococo.json b/polkadot/node/service/chain-specs/wococo.json deleted file mode 100644 index 0ad7334685f1..000000000000 --- a/polkadot/node/service/chain-specs/wococo.json +++ /dev/null @@ -1,218 +0,0 @@ -{ - "name": "Wococo", - "id": "wococo", - "chainType": "Live", - "bootNodes": [ - "/dns/wococo-bootnode-0.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWQC541JNa6dguvifYYjwPnviscJHqbwvoNDMX3WBubPJZ", - "/dns/wococo-bootnode-1.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWG9v9Aexs6EvBYAwy9cqLyw25BRi2U1RQNQ2r5QJRxfFm", - "/dns/wococo-bootnode-2.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWNza3xSzCbw6phggjKD4QyqF8xvVpDFk7ctkoM5c1PQz2", - "/dns/wococo-bootnode-3.parity-testnet.parity.io/tcp/30333/p2p/12D3KooWJ4ngb7S1Lkq5C4ZYqfFuJswxTE3UC5zjui5TLhAULTRU" - ], - "telemetryEndpoints": [ - [ - "/dns/telemetry.polkadot.io/tcp/443/x-parity-wss/%2Fsubmit%2F", - 0 - ] - ], - "protocolId": "wococo", - "properties": { - "ss58Format": 42, - "tokenDecimals": 12, - "tokenSymbol": "WOOK" - }, - "forkBlocks": null, - "badBlocks": null, - "lightSyncState": null, - "codeSubstitutes": {}, - "genesis": { - "raw": { - "top": { - "0x0595267586b57744927884f519eb81014e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x06de3d8a54d27e44a9d5ce189618f22d4e7b9012096b41c4eb3aaf947f6ea429": "0x0500", - "0x06de3d8a54d27e44a9d5ce189618f22db4b49d95320d9021994c850f25b8e385": "0x0000300000800000080000000000100000c800000500000005000000020000000200000000005000000010000700e876481702004001040000000400000000000000000000000000000000000000000000000000000000000000000000000800000000200000040000000400000000001000b00400000000000000000000140000000400000004000000000000000000060000006400000002000000190000000000000002000000020000000700c817a80402004001000200000005000000", - "0x1405f2411d0af5a7ff397e7c9dc68d194e7b9012096b41c4eb3aaf947f6ea429": "0x0100", - "0x1405f2411d0af5a7ff397e7c9dc68d196323ae84c43568be0d1394d5d0d522c4": "0x03000000", - "0x1809d78346727a0ef58c0fa03bafa3234e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x196e027349017067f9eb56e2c4d9ded54e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x1a736d37504c2e3fb73dad160c55b2914e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x1cb6f36e027abb2091cfb5110ab5087f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x1cb6f36e027abb2091cfb5110ab5087f5e0621c4869aa60c02be9adcc98a0d1d": "0x10006078f6e6a00db1f40097f0d07953008b04cda71ad831e70f37e93eb2b40431010000000000000022371e9715d00b3a21c9a899ba3eafd11f5143b821b159b864025ba1eabdb6310100000000000000e6b8162c3e767f8e61892f7fcd06d27041d806e5e0335c59dcdafa5c8e181c5b0100000000000000585a72774ca9465ba0e7407e4e66d239febbe906cbf090169b6cfa15dd44e5770100000000000000", - "0x1cb6f36e027abb2091cfb5110ab5087f66e8f035c8adbe7f1547b43c51e6f8a4": "0x00000000", - "0x1cb6f36e027abb2091cfb5110ab5087faacf00b9b41fda7a9268821c2a2b3e4c": "0x10006078f6e6a00db1f40097f0d07953008b04cda71ad831e70f37e93eb2b40431010000000000000022371e9715d00b3a21c9a899ba3eafd11f5143b821b159b864025ba1eabdb6310100000000000000e6b8162c3e767f8e61892f7fcd06d27041d806e5e0335c59dcdafa5c8e181c5b0100000000000000585a72774ca9465ba0e7407e4e66d239febbe906cbf090169b6cfa15dd44e5770100000000000000", - "0x1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef": "0x0100000000000000040000000000000002", - "0x2099d7f109d6e535fb000bba623fd4404c014e6bf8b8c2c011e7290b85696bb3": "0x10b691bfd2cd584abd1531b7deff6d0e34893960b59ae550348c33abd76af4cb490e93248544c963f34bb9cde63c97f85ef7a1939d3c9075907b26edf368fe846e5ed9fdbd8dffeb5324935a7fafc536de96d62abee0a05d7eefa961c1cf3de266ca24971e2ec596d510c673f4f8d36d0a8a407b59ffd0643f621369973a335656", - "0x2099d7f109d6e535fb000bba623fd4404e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x2099d7f109d6e535fb000bba623fd4409f99a2ce711f3a31b2fc05604c93f179": "0x10b691bfd2cd584abd1531b7deff6d0e34893960b59ae550348c33abd76af4cb490e93248544c963f34bb9cde63c97f85ef7a1939d3c9075907b26edf368fe846e5ed9fdbd8dffeb5324935a7fafc536de96d62abee0a05d7eefa961c1cf3de266ca24971e2ec596d510c673f4f8d36d0a8a407b59ffd0643f621369973a335656", - "0x26aa394eea5630e07c48ae0c9558cef734abf5cb34d6244378cddbf18e849d96": "0x000000000794e321d00fb2d42000", - "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", - "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", - "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746b4def25cfda6ef3a00000000": "0x4545454545454545454545454545454545454545454545454545454545454545", - "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01", - "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da942cd783ab1dc80a5347fe6c6f20ea02b9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00": "0x00000000000000000100000000000000000064a7b3b6e00d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", - "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da994dc96e49150ac7c3ab5917a8d347ea0aa7ca70cae6201086232336a1535399c34f372320c0aa15d68c4cfa493079f27": "0x0000000000000000010000000000000000407a10f35a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080", - "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da99a0d9ba64d584162e7d1fc85d6d19ad1005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f": "0x0000000004000000010000000000000000407a10f35a000000000000000000000000000000000000000000000000000000407a10f35a0000000000000000000000000000000000000000000000000080", - "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9a1e0293801ecda3bccddad286cfce679fa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c": "0x0000000004000000010000000000000000407a10f35a000000000000000000000000000000000000000000000000000000407a10f35a0000000000000000000000000000000000000000000000000080", - "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9e39abd9d6d25130391c9ff6fc64a35ef18caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758": "0x0000000004000000010000000000000000407a10f35a000000000000000000000000000000000000000000000000000000407a10f35a0000000000000000000000000000000000000000000000000080", - "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9f4c6172605184c65d6c162727408dc0be4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b": "0x0000000004000000010000000000000000407a10f35a000000000000000000000000000000000000000000000000000000407a10f35a0000000000000000000000000000000000000000000000000080", - "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0xb9921c77657374656e64", - "0x2762c81376aaa894b6f64c67e58cc6504e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x2aeddc77fe58c98d50bd37f1b90840f94e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x2b06af9719ac64d755623cda8ddd9b944e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x2b06af9719ac64d755623cda8ddd9b949f99a2ce711f3a31b2fc05604c93f179": "0x104a611c52c43142e11767e4443eb56b908babae266b4f446271d11ffaaafbb16ece83a2b5c733f98b4018856a1fb0bdf0138dd883cc93a883f97de48b762d6b12ded28f03696a0c9f9dec223f3cbc44c4895d8b243ebe5cee12f9f02bf0c5043c9e3e67bfc0daed31db022fce484b2cf0d757e9aafded1988293da74301275b38", - "0x2f85f1e1378cb2d7b83adbaf0b5869c24e7b9012096b41c4eb3aaf947f6ea429": "0x0100", - "0x2f85f1e1378cb2d7b83adbaf0b5869c298ef7dc060436e4ed803af07632b89b65153cb1f00942ff401000000": "0x481a2bb5d6b9d282f3597f76299e767b1bbf06577a886d6def364451d4a95a5204000000", - "0x2f85f1e1378cb2d7b83adbaf0b5869c298ef7dc060436e4ed803af07632b89b6b4def25cfda6ef3a00000000": "0x481a2bb5d6b9d282f3597f76299e767b1bbf06577a886d6def364451d4a95a5204000000", - "0x2f85f1e1378cb2d7b83adbaf0b5869c2ff3ae12770bea2e48d9bde7385e7a25f": "0x0000000002000000", - "0x31a3a2ce3603138b8b352e8f192ca55a4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x3a636f6465": "0x52bc537646db8e0528b52ffd005894a2041e01468413521028ee4c3a03850c0b278ae1c05fe510045e30c88789ed5828071801ae10048d27c39f9eff086b9b6f23fd1d87552800107259f316bc3f938f9f81ae1d78d1903cc5c228dfe9c050dc7b93bdf796322599028915a61196126d79ea34800c255ac677be934ced1499782df3671103be5364d28fd4930a906ff7cf6e8bd4b5393500e74f1202e3cd66bb25bdfdde7ccf633fe29e95e39d5f8e97ce19c5a7f7f447eae9eeeef3dd67f77bb76dcc493ffd9e19cc6f5bf67bcfa9057250f9b71fe4008c202b19f9fd5964c23fc52622d86cb62b972db7acf46e3fd821b7d1fc36e296f523b593b465fd476339deee07616dc4b71f9ce1d846fd3c6de4df0f6ba379fb5964e294b412c185aa7977be77a78d39994f7f3eb551f3ba6591c9b4e5e4a0b64b7f19a8e6735a01f2e5a072bcfda0d74625100aae8cf3cbf0f697fedc327ed0c924e37c05cc5fe29695f4f223353849bf212f799a5bf3fbc1194e92de90973c4daeebd45d2b3deefc7e91973c4ddb75b2e05a09effc7e1c5ef2346dd7c9826b85bbf3fb7378c9d3b45d270beefc7e1633a036db9d8fd46087cc4be697fedc327eaf8dca79fdf94127bd96f1178dfefc2c5e405bc6efd66b193f52831d4eb26fc84b9ee6ed5ae1eefc7e91973c4ddb75b2e0ceef9fa20246db9d1fb611df7e163398b63b1fa9911aa9919a496e193f07b55d1a2f03d57af6182037c85c13e37c7e7e25d1a27f40d3e695a489246e24d94ab244122592dc923891a44cd11b49b614bd507447911a454220f9a2e88c22348a42509446911c48d214f9501444111d455f8ac0147900091792358a862882a3680a24531471a0a805246f14d990cc81040d247420c903091e48d61495510404923b8adc20f1a2c88c2232908081440d246f90c081240e24669090416205923690c881c40d246c20d12aba02899b242f247121090b455b90d851c4a6284dd116456314c581a40b2468909c4112022475146d21e1a2088c222a8acc24c12a12a3488ba22f8ac2282a53d406899a222c3f27f870116405e48b4c0b912000d0449028826c395744741c01e3481547bc38b28634e288185cd6912fb83a9ecc6b7930381dc0e1008e961e2d7ae0003a1392f14f78d66c06c70188866f8aefcc3c63aa31e77818de082138cc1626b063ca118a11e4871f32260833011113a099e0cc045b4ca0c504464c70c4ec61080e212708c9d236d0db04369c159a061f5bb40c568b69e342d03708a11282c6871600a2f82a8ace04e182134311acdfe1ad78153e88bfe157f8241e8b17e251f81f5eebcbfc97e7c0d0d6bf30d4c5501443594363866810fa3244c4501148a818da61a8035fc39f301447cf143d65becbf7f0576058de09224d1059828812b32366453c1244789885a95d33232640629685238790aa1f567e35b44576466685ac0a1c15e81c436010a9304447ad6288d6903543b6866831248c2169867c3104cd102b867831648b216a868831a48b21600ce162c815e11a4249082121f48690182130e411424f08951182c26261b5849c1022039484101540480845012446480a202584a6003a42c88cd018a02580c2e4a090a3454809a13c84f010a243680e203184ba84e410ba432804424c0875114283d00e423e70250835d1d3069011422c0861cdad203588b8217246cf193d680455116486c81a3829f84843223181160e17223b10f152ad009aa2c895213986cee80941112c3331403600d500644565b06f9c89a1376618cfc6bbe1acfe8c08ee184ad37366e80ccc03436e43a8a074f4680d9102b683c5a3c78a508d908d212d863cf1d3c64c882155846d009d300404302086b6f859e3b70c19d383054c871fae19113f6c005d195266081343cc0c89a2a78a214df4a0015f18320550094026c4de0c210384a5278b1f356279f49881fd40e5a03b0c71e26db02f301f864001f322e445880d1c08c912fa41880e3f050c4c111b28e64b781e46aaf7020be32088208f7721880786e6e81963288f66c189a8558d058435abe1278c190d311d462484d4308af1f1c30f184fc6cf18432efc6cc572188241a807211d7cf4f023c69bf165fcb0f914be852229fc1213042181580fbee6a9be0a081e0038c1d5781f22c0e38b8009d143c79025e81943b21863800d21f40656c40f1c436aec1d30227aec80bd016b031b03d605901b8ab470573d6e0cb9111a6202218e702114840f20261842c80c426e98d930d4829007848410f2c20718528c8f21c62992702131a3e7081f5e90a4e1a34b511b3f667c5570577ca2f0c1e203059984cf989f363f5f08754186f986f819be309f98a13486c6f826be0344c8980d31f4450f153d5bfc11301e6c1e40290055c9da7c60da04224504b501e2d25d7c404c31b80e10ad80e40cd81148b2f8be3417afc35bfdb851d7f0127cd2206133040bda45b3fcd657401c780f5026a80f4031046d016d01d2020443510a8d03100b3d5c00cd00d4012246c07aa8b61f33640c3721888ca03282d87c37a017820881440bcf010805ce8e1e2fdc8aa88e590c45687ad2e821038914456a7abee8b9e26789cf123445cf9a1e36453d14b1f0f3464f9b216d884040c404d18da889b103130dd00af54acf56671561d1a3a6c8861e307aca40d206280b123186b001ba1a42c6c7d0d385102c402e246921d68107025ca2888b24b61e357e941872a69a415206500b40321459118b014914496010fac0cf1a2120623c8c4cc476f0e183100f3f5ec470189d1893f071c5e8858e31761979105a414805a11484b408a120748277a9587c98c7eae9ea71f357cf042582f6e05544cce89903266602377ac2187263e88e1c3886d0bc14435e501ce80d425c7e082015605d80d4e86163088d2036681b1f85bf41b982cc781b7aeab06c0c750dbd19b223e88ca13080e0701bfc8608de0c893114829e3886d608c500fb006dd323076844cf1b435cf4ac010b6288cd0c852049c08c182283560d7105b9a16c1e049f45101543cae04ce8e102e2ca39c10716a2d5d00b6411454aa86e0051f598d123c6509bca06908d4819f6cc58424f9abf62b4fd2de4a23c80508036803380348059a00ea013e00d6013600de013200ee00ee11aa22d360dcb65d518aa63888da13582b882e40872e3080f477c38d2c5c7161f2dc8e29075c9e438d2c2110e1c7161c8367445f66656c2cc16048d206b044983481c940c227208591169038819d40d206e828c1184cd11218e147164082279fca0f0a325e887202282809099217343e606481040c4001162c88c213c86ca206283680ea236666d6668ccc8808d8191814101d405f406a80e225510d9828815416e08e243101c80e4000408203ac84a90a120c342a4070743c4072220202205112680d4b40f405c0ca9e12c0cb5e12b10214174055112631651184468106d11b540d4012217884210e211de31011e445413e4f139bc12ff8117f3543c11cfe55978135e86a7e1a178338fc363f92cbf52c5f8dad427be313e2b3e293e2abe321f990f04df125f0e5f0f5f97af86cf876f852febfbe123e2e3f271e083e17be1bbe1b3e1a3e1dbf2b1f0b5f0617d1ee0b87c42d4339f0edf0cdf07380e7074705ddc1b9c1b5c159c190e0dee0cce0d670657064706d78663c38dc125c189c19de1d0705770487062b830dc119c115c111c11dc109c105c101c18ee039c07b82d2e0c0e0cee0b6e0de705d705c705a7864bc36dc169c145c141c18de19ee09ce0a8e0a6e0ca70645c0cae06ee06ce068e064e062e0b9702a785b371287027702b703170581c0cdc0bf54dcda3e251b92a9b9a4645a39e315da83cd426aa13b586fa43bda1da50b5d4126a0a3404d40e1a079d81a641d1a0773817dda26fd03aa819b40c2a86b3e16b20e9a2705027681395066f837aa1587405da855ed114280d9405da8297416ba043d02f9403f4054a4583a042d4351406aa023d81264191a046d030f4082a866ea139d01f681114086a03d5c1dd7034aa09455c1e858f71285c0a47a26885ea8307f1055175f00eb80e3e43bdc2b5780a9c0b5c0bed45d7d173f417cd469bd170349be6ea33da8d2ea3c1e8375a8c5ed374341a6d4787a0c9e8aebea3c3e831ba4d6f751b1d47cbd169f41aeda6d5a85e2a1deda57f681dba868ea1b934077a86cea13b507b987974d56461de314330ed98757c2ecc35661ab5cb44639631dd9874cc37a617138c59c5e4626631cf7c66e69aa935bff02fea0ef387e9c3f432393061b0124214d4531981064cac07cc2a077ce0c1930b5880011b2820013306240468e0e40018346162800258305fa00089d191a40f0d705e9e3b467ced4a5050309054058ad2074949e074294d4a4949af181e0c258a4a084e49504d4953aa5c0f9aa62c41896ac04fec0ea612951402568ad20485090a0692a844254145354da11214b383a1a43c41c980d2d3942a178a890a950d9aa6804025013656479791181d44b1399898a0446162825200393e88f2a04989290e5652ea20894a5452d4071e4c51cac02c060743314d8112a524254949a90309626f30950e9aa6248df0a4148253d2942a37aa49098411a06cf0313758294a1395a62428519aa82420ca0d12e39242258a929408626d30d4084a4b5023283969001963036a8a0146b8646c0d0a626a04c5d26011949a7ac4d0e033f8832854aa28c5626ef829040fa674d044254ad2942a57090350683d3133248895a12446064b999214a504f51442941fb1360ca534256aca13950fa2428092e441d2942a174a15294d509e2e101263c350504a4c416263ecc4c4d8e2a8a610a84449ea008a12534f2c0c7e0201041010901303833ba042e5a94a5295291f403d293565804ad2084a4b42b12f588a52930753a09a428842c5ca94109c9492a29ea854517a328aade12825a8242f186a0ad4081d28296120694a953b42074a4a349f58170ca514154215a829527c625cf00750503eb03135acf4542549e9694a084e4a4f49501d58a902144bc3514d4a207460a58a2cb60543294551b19294d444e527a6058f80812434504c4a4d4d503e8892540584a70f92a434854005034d53ce4435518992e40482942c180a04284f50aa243d51c182a9740024a6c550514d4a5694ae600f9aa6486952aa92a4140545ca14294d50a2148959c14a52a8440912ab829fa87400a5046586a1a242a81215029521312a4008010a0a8a506c0a861205454a521395295294a2a0a6403d295591205686a1949ea844491a216a0ad3140c40619a02c50a948f9161a82a215079f22049484c0a867aa21205450503284f503680c5a2e00c4ca9729f94969ea8444001640c0a56520a4129840538408a92071e4071c0506c0c432d4551fa20ca130c15d5a4f4a4f441d3948f39d134a58358ac098e3205aa69ca5394084a49233055a90225e949490ad39410684b51a830d17e62378602126382a124fdc440c0202441898222054a94120274624b68600a13942951539aa6f4c494e0a52854983090a4141542142511947ac492e0272a0508792a3161004a5453081d244545517a9a22a5694a52d28f263b591dc867cab09d21a3eb720de49bcd7667cd7f705f1a5f1ab3caec684c285663b5c66aadb50a4da0ee6ee4aef38e763d3277eecdccccdc51eeee66ee3a6606996b771cd31cf6ca1dd3d0f30eab3b129feded1030e2a0bb3bc88ea4411ed01fc003823ddd7bce6ef72110e4ced199ed808f7dfa00290fc875ce5c77fb9c5f03dcd9c13ec25d77c43b4a3d2fa49476775d73c8ceed3977cd4e2973ced42975dade75ba7bbb7b5d1006e2a0fb6cf68e015d7b17c21848c83427877ae8ed79d4d3d1e9605de7dcb5bda3edeeec614e377bb6c75d91912e80739a67d8711ec8cd3edadb79d28675be41b7d75ed7b9b333656705544e00d8b5334936f51c012c343570ef3aca0eb213a20988ba09dc3fe6cf9d9939ce39e738e6f873671de73866e738678e391c6ee6388e73c6e1388e63678efbf8e3188763ff98a773cc4dce999bd971983f9c8fd9793abb73b3e7d15a996b4729f53ca6ddde5c6953ea850e80d8ecba7bcec9516a01103a33ed3a6f721fe0a313e4c9a041c76036051dbcc079dcfb0765ef26c8ee3983dcddd81ee49ec7ee79edce1eed3af62031a849539fee5c698e7b8e91168570c784727777eededdee4e475a8436a5a304eeafaedd3ba75d7b03754073769d01e6ecba6e4eef66e798326d8f36b357bb4177aeb53aed997b538f9967773b13e18e1974f77e396de6d9b9778e7b74ba479d763b1070086477afbb69d775dd8feffbda81747b7beeb9bb33b3b37b17a0eb3aaf0bbb473a76de799e4723e2ec5d77eda60d3a77333373d77533e7ee66efbaeb983d9e2137737787eeeeee733ab377f3f4ae767b77b367d7753b3c3cb6eb3acbc37d4366666f76a7b4760c32651e42ddbd870fb377eecddeeded3d643fdcd99d65ee3dbcdbf33ccfbdbd87f774f7e93edda7cfe993b677d7deeeededdd7993ddbd0787d9dde3d9b39dbd2773b777ee3cdbd99ddd9b6958dd27fbecf6e9dc4e296d66e76ed1bbf6c9ce4dd9b9eb3a77666fa79fe7eed51d67327b74a7bfe6a8736177c779dedcf5e8e9c13db9ddc7bd63ea4e43cfa39ce879f727b677ccdeed941964e7f666e7913bee98c97677dadd71473def80b477dc75dddd5402ea1dd376caccb0eedc7b3ad85dd731e8d4636ea79d7bedbaa6ee4e29a5ee79cc5dd74d29a5cced4cb99d3265cacc4c29336577da75dc31779d3be5cee36e6f88d79dc7deb1333ba5eedcee94b9e3aeeb9cdd9d99b9e35ad9d9a937927b3b3373e7eedddedd59d075ef79dd7973d68e0003a8e05f0015d6755dedba9d2501e80aa3d5ebba9c6e6fefbaaeebbabb4ea7761d775c531ad2a6d49bbb7677e79cd6aebd634fa2459234dec33dc21315109440e03e26252b4a4c4922400121821f1e50614af2a0698a071e5061fa815305042851504a204c89fa1f0c84003553824a02818a9426284f16270a2a69e9894a06a2949a827e40c994c88ea4344149527a825205042a497a3041894285898894294c50ac2441011949517a5292f24425c98802244a539ea28848f00309152a4f4096a240c10013139527221440517a02f223e4e7474f14d4141194b8a82850a09aa03c4525454d0101042a3224533a507aaa627d624d4a55aa40997c040421aca4f4d441d21395282851a8303141f9e123204c896a0ae1c9fa7410154210104268f21141e983a4a8a6294f5592a2404d01e1a72789511011a864204a881105487a94203992844469090a1306923c689af20114940f7c88a024a5694a52d314281f44e9a0032a9f044a8208949692a244506a2a124194920712f87882a2c4142549c903284f54a2a092a4304df9204a52145308503a509232e3a29ea04441498004a8a8c9832950a40e1f811a41692929ca14260c845045f60425f462245294a0a0949eaa8040254ad29392152a51949e92a0404989a2947464c988022455a228411d7d1f4489828281a40fa0a6344de9402664840ea63c295901b2d2a4e441f84852139529504f4a569294a2a03c2935297990148023145080448a521295a82a233c45498a124149c84a93921fc911a33faee6dc547d3de15a8deb6ab529ef09d7a6a65c7c529bb5599b3953535da3fd646ad6a6a6dc9f4c4d6faa3635459fd4e6d454835dadd63de1da543fe1da54ad466b944e4d71ed7bc25353dd93da9c9aea27b5599b9a9aaad5dca7a6fa094fcd27b539359f706d6aaa366bfd646a6a8a6bb5eec9d4e427b5c93de1a9a95a8d3e999ab55a3fa94daed527b5c94f6ab356ab798d3ee15aad9f70ad56f327b5599b4fb8369f44a0663199798200058503f4b9dfb2e672df6dc0010b574efbe1b2368a71ff41b2271f6ce15269417ed4b8b5481b95dccbb8b2f78e41c8c19336aa4c4683369ab73e110b636efd249512ddca68c8dcfadc463f6ec96d6e151550e576dffc51dced0769501bd57fea293a49badd7bdd377796b9085bf0e35edcf397b3fb263ddb911c59d62eb75476cfcf891974dd77b624e1f6f3e56c396f37e90fcef66f2793b34ee677fd1f106beb72649d576ee93ddfacc68c204f1b715f9f8a17785f92f02683f99c2dfbcaf51ee4b6791d89e4dc953bdbb93c376059c1e5a39ce71fdb487c7e9e367a3df3ff7c501b79cf2f6b23ee6bf7458aef913510041fa94332e6fd7765bbf4c513b807b1409e5723dfb0b22e7d903e08d666f8df073e38c177f20b3eb81473d27da51d4ee7a4c3e9c0f71efc5ecff77bd926de7fff695dfaafbf5dba54ffb3e5bcdd87ef91f37e2e3679bd5e2fbb54bfa40f55530054ed86bfc43d5500fdce96dc87f67b24bf9f07d690c5d09652377c8e2ce9e53e87f4b6623e326954396fc57c84fb4943f290046bc891fe3924d33cd2c96797c4a72f3e8b4c92bc19c5770e7cce96e28336067ef7d5097dd1c640ebc47bee3d90235fdf2d795ee7c4ebbc0ce87fb6e41e7c1024cbf063dff3059f23639f6d521fe49e2f16984b1f7cb0c3a5d783b69cb7e43e7cd0c317197e396fd862133003d0321b29c1f7ff2c1b29bf7705d0076df97aeec179b979e7e56699a482cbcfee8553007de5f2e3f012befc444aa666edd5e10a2b90f12e14c66451418769420836059b9c0f5632569fbbeb4f8e8cd59fb7e34e87be04d7bf7b26eb3773cc31d7cd676e4e92d7dc49f67724f748ce91f582959c0fce89659c7fc5c34ac35ac326e75726b384713e58c526bc86eb6438b39244b7d98e2d93e07a8d9b9e05c8538591beaf30f6072edf60c8e1b60d976f2e505dd9e55b0b4464108585eb963525b85b86c04214973f67ae30ba13976f1d60e3ce31976f31f8708b5cbe71c9628a17bcaad8ba4e4f2e570dd7690ae79651638001b3e196515e6c00c7b865140a63d45b427151c410125ab7840aa375d9b3d9f8cde5bffcfd02e8342f7d9092f56b4d732702fcdb96371be2b8f4e9cfef49c69cd434977e4d734ba8daa55f49be4efce6cd9bb276fb6b1c773ec85246beed60e69297bc60874d46702b59d3dc295ef0567aa68d6a277ffb9d04bbc50be69beb34df541bcb60beff05f3dd46817cab81eb46f5adb6ecb732af7fed3a799d246f478197bf5667df01e64e7bfd27f7cc04e5c8d9936ae45b0a59d7bba0fbef975eef7dfdf0fd418eec0771c818cef32d6b17e743b2e438eb9473ad44f5c5f916c918cecf9bf3200d9b2cbdef079b8c65406db60b3ebd7ec16fb26f8b17e0bc48e67c48e23c477a2892f482340c4996e38aa45fb08621c921b822d917a43db97694cbf9fe90643caec87536c58939e127debcb9fd7ecb9a1236dbed90e43597239be43e87141fc945b2f252bff7ae418d09efd9f3fab9c9fcfe2966d0ef3d8843820fce108764362ed8210ec96f5cd0431c92e3b8200d39127c1c12aabb56fa7af0342ff8f5ca051fe4c48965049fc559c248c526bce6820f72f53969cf3939201cf0798cad848b43125df07b7d83e2331bf940f1c38f2cfdbe3e7c85dfeb41f2291445eec3d77f6439efcb321779d98fdfbb5cedd8326aed750b6b9938bb24c011467af996820b238cf5f22d052ecc468044310c45f1270982288aa2f81c247681e0eb05823f4910401004c1e720f08deff3bceff3befbeffbbef778c9f71cf4d9a571aa415acd014eb1b95c58cbd848d7dd246d59e7b191ee27090208ddd38f9730f1784919202b8d5df760ce057c8340ce9d737776e7bae7c8908d74d4631af99602d5addfd147ea8efbae7b8ebc80eb5a07f002be390f32c95b2eac65640b97d908cf6772de29b2919c908de47c934c23ce8b1f3ef84ce3ebbff7be7ba691fb5a7a3727e7435ed29ff3222fe19bf39d0306e80f3a9993417781b7f871dfdefbf7de73ee1ef7819df74e5a99d7f3be9bdc8ee3fe6eff7a76c9fbee594480f7d9b276bff94979eeee3d923b49dd9eefb593dff6fa913a0363ff0473989f8cf9cff76f32e6ef24064897b948d97df74ef2edbef39ea2c22ad77b16337872bdf7f8828e2cbd5ff2ef1ef448fbe4c45c36db8dea715fef1e15ded77bcfa202aadcef91da239f9c2cb8cd46fca3b8ebf5f5ffc827efa3b8fb7a169d24ddef23b8df7ba4930577b291cf3fcb5cc45f6c52dff3c8f95d392f7f25cbfef92c5e30af3b39b68cbfe6cd8e0a90ab8ed707ab3f38c57e1ad8b52d6bb7a754c7ccfc1ddf493a49ddd939f965713e528339d3325952cf9b4cba3b756fdebcb9e37a4d3af9f5ac93d767ee3bb2ecdeca7899a8edca2dfb9dba3baebcb956bcf25ba2ef3ddb72bcfc4d86fd563aa7272bdd85aadd6999f0233993dc7754dfd773ffb24ef38e4b3f32aa2f7d1bcb60deae7f8b4cfc3992cbf9dc3b69a5b92eb9b7a593d4a55fcbdaed66e7d952ea7adfe4eceef67e42d52e7fbf9337e1efe79cfcd24bed92ff7c169d5027f3dd2ef1377fd3dbd2b2287880e5d8a296db3f194b5e32ffde449fd436daee9cb6cb7380f3c11cbee1f333d1fdf8f5bc6486e4b311a2cbcf65e091a4f79e23f524f94ef105be9a7c39f3822c32e14e676cd9ebbf077f8a4ca62d6b777ee48b043dd2cabce5bcdf4fd2cabcdff71ec99782ded31d675a27bfb1267ee74ffb6c847f5e8ffcec92f7e053d1c9bbdc832198c355277cfadf4f5184ee3fcb3f418f2cbdff5eb6acddd764f2026d2975c19fe4477a4f2e32bf3c408d89cb5c64fef748ee2475fdf317e9e4d79f3f3203e378fd91ba49be1d69e472a4478233f4c8b2fefc8e8c4deb342f67798ccd76876e37391e40c7baf49d741a97ea4b70cb6aa79696f1e59bd518706a6923bef49578c913d1edc25fe3327e3eb3e52c9595111af7573b342d6dc473e90349d235964c776a69197d223236a0e27e3e525319cba9e5d22f998c4b5f8a7ff4991c331c61c31160b66c361af79436491bfd41851c4ac061091a959511dafcab1d1a3f9555d3babf22006d3e475e118026f5c501f3a536f019fda975e9732ff5c501dd73560ac967f43b2bf5c501dc4f2bf53ea3cf5922bedde697acc5739850a6cb1a5df82046167fe95350c2c8b4da0b6696a8a18626d40801078d69fc25d1a5cfa203de66a34d2d6d24c1a53fb1ba690d20f39292a8966394c18b7ea574ea7a6573a9ad25d7d1ef6c13674bee993c08ae5b2df7a5db52ea5277c256ac7039dbc5ab5f4e5da6da0c976b1a00d5edd62fa92d45b8dec45660ddfaa5062ee56c13b7b9d56a7901c104699ca05ac0dc9fcb372d2e5cb0c34a7691e29fca79f3e6cd0cb4af8bcd078c20b09c61a33f9dfccd9bdbc51624851d5cc87a12cafa00195b54156e73bbd82648e384cdca00a86e22d8d80a2c1a7fa9815b9f5900cc13947c3bc1cc8d9ab74b09dc86f6591bb7a1b195e29f6aaae1062eaedc61b3d13c6ba3b2d968fca5d4bb2dab8034f4487e4afab7088109d234f186a62306183ce481e5cd1b1a3fcff5e696009d52b2fe9c9d57ebfb7be4582bd7e11499740a2ed69f976f27c470612dab4fc979410fe97395ce4bbbbf00f9691bf17bbcc4a77befdf3bf7cebdffc7bdc7f93bf7debdbb831cc9b732e91790ba9ffbc97d8cfebc7d639403dcd78ea3249dd76323dc6b805c9ff212eef92b2fe1c8242dab285ca296d567d14baff4de8f5e5f5fe647e0d7ff6923da32efeb2be125cf46bcaf0f9263cfbc7f915ecf3c1f9e1fc17ae67d7d581b7d5f9fd5b865925bdf072f99b73ee7bd5f712477defb6751737f5ae67dfffc297a1febde6fdf58679de69bdb3ddf4e58e1f2ed84142eac65de734ef47e965be65536c2cf226523fc48cd91f34e75adb60701721b75fed496f3d2b023e7ad17d4a7df95749a6f9af8d34f618b4504f8d3f79edad2bbb4fb293a894055c215db752a3310023cde5ceea16a97b350f5b9659d2de97725993caa12ae5ca7f9a614a145279e2d450059bca03e7d2a36e19ed948593b725e8e749a6feefcca84da5806fef4fda95deaa7d649ea967ebbce7e02ec1e9c2213f0c3afef91e2332fc179ee411cb249ed96e183cf62130f67c97bfe902cbd9f0fcecbb713a86e65235c8b4dba5f24bd7f91f382208b08e8ffbe17c9ef5f24cf6791c967cbef3bfcc879c1476a90c9f041922fc8e2056ccb79f9c3073b042f785d6623253f08ce100c1fa93904498f0c5be6bf34860ffeeb965e06de0dedd2f70d92e5f7f3919c4527fddf149de69bfb7a2447ea17c9f723f97a7c39b29294a42de3703a1790a18cf44bd8ad9e9236aa44b77efd24f5616b6efd9f3e6a5aade0d622b7fed846fdb5d6fa1c54ed12dfa640e6c93ca580dce9842da33c1bb451f92ec46ec9682efdfa9d57ff76dc97ace67630a4362a3d0cdaa81c3f68a3ee2b68a31fb77b0eda886f59c2dcee2bd04794e6ac86c7dceeb98d80dc92e7964a6e571fa97fc0263b33f3cced1eecb0c9be302d6ef720f764c7719a6f2e77cfd346f4bbeebbe7a0ce2e31977b01b983916f5ae2b8a577ab41cdf5e7eb955e7b4bb23632c14dcf2f613f3ce6368fc3aebff33c9a34ffd1792e009963622c4322262f09ea11641c708491b68ced738f3f2561e414d09f834abe997087fbed1fdbc87fdcfe0f6f39dea0b0653006701c380ca1668e225a60210d1aebe84cd97d256d548e976f573adcfe227dd4b4fe0a9c9c776c1fb73f9c36bc7cbb72e1520b6bd9e49b1d204719db0b8540a6c0d80fe274012fdf4c98e1c27e402b4770c99286096bd8d042e3109ccf41251139c1495b36692b80b60c0459bc80b3e55fee3dee7468cb6c19e5af87b511f8fe3f6dd481ddf7d9f2fbd77f5dd8b2b18dbaeffdc18e9c17fc5a16fe142ff0b9a12dc37f7d47f20dc928bfdf83b3793a4e47f20549beaf0f76e77b7e94e569dc336623e5cf9db6e4bebe3fe87372245f0be67b6454bd33043b14e172cf64e9b9c89dce7ca622579db065412df3effe5bd65924679292e5bcfc1c19e5977f9263cbfaa7c8846db55ecb7abceff911b5d96c361bcd5fc64bfc7ad07dcd4a83bf930f1845088ca5574d70e1765b8db9fd3f9584b56c963f773e8b0f18e7f3bc745601b94190c39a036111640c8c7cb322e2d6cbb7aa3597756e93d2283083d165393e1730b27880daa5d47a764e03185180a41b1877e6fe0ef95bd4a07697d83a4d5dfeb27f9c4954dd2edfaab26ee95dfa43976f54715c0a722438aba841edd20be6e5beac5dce7a4d5270a53e484526d5450d6ad759e43ec6d926f372cf59af65f3795e0ea27669e4026630bff4ef4926c9634e6e02f20246ae7a7f5b7f5ab90bfafd919adb28d6a4dfdfb9b2fe923f7d8e7baf8dfa7237901730d23badd732faf4c19c0b9ca62e656a3100727b8ed746fefdf4b98d28d822133a450d6a949c9745af00c86dd41e3209b29291def082394cbdb08dead35f7327f9346f7fbf93f45964e2342bc9372a37179ce124f936e924df4a8a34ac24dfaab42eb751d39fefb5d1bcf35b6432c3cb62136add7a4dd6e89c50801c446526bc446d5456f06d54ca2a6823fafe45daa8bbfe631bf18d4a89ebcfd3474d0bea6e99e4fa8333e43e1a7de6cfcf4cdb68a97f3e4f1bf5fb731fb1cf9cea70cbc296cda70f76383f9ccf7dc434fef076f9a7d8cf62937efa19f4d3b08d9a6f6d05c80df27350396db7795a8d7c3b21cc9db6230f99741a97fcf996d3d6976f2790b9f3ce9fa202e695cbb69c36fa4c5aa1979f924e722ebf93cc4b4afab10c5e975aa79ccbcf692ed12df9cd2dfd9b2f39b78cf3e7e5a6807f8a4eef345eb7d3d654800c65ec2fbdebfeeeefee58bc5c7777ca41ce8485aa04354a00f36dd4df2f6ba392deee0fba5db9e3c8695da46ff973fbb99f0ad194916f5794b87cbbe2c22d65b7bfe8f2cdb67559640281b11c917a1cc336e2effa971fac245f27e70559c9382fe76125b99f2213e79e450d6a9703a798417dce96f5eb832d6630defa2cd296d10769e8e4bca0871c597f8adcb292e7ce074116395bd62ef74e965e7d77b2a4977ba4069d2c0d70fd41163b5b8a70bb77b2e4dbf5af64c92d13a1ca074f38b8fe25b7acdce0fa971583eb8fe495e4db914efee6cd9bae5bdfc9b2824b1f9ca193f42bc997450574d739d2a9bbd596f3ba759a6fdebc7973cbdaf5a724b76c5adab2f94497816adca45740268232f2cda6753d32973feca349e387b511df6c5c2effcfe5e720b600e425e37c7efe4090db88e79dcf0fe6701b316da37e7e708234e436e25b7a9759a7016410d132be4edfbfdf452601e12dc77b99244bd87d91e506ecb5b1a90c5dd7755df7484db9e3265d13abb94bdd7bdf91fef4bb0ee7f98b1025e125e0f3fff491cf98d3438700574febe1d9797e591db24bcfeff08c3edf3a3b0f6b59f7fd3d48dab2ee77489e9675ef437ecfba7f91b296f520f9ea907589f1fbf7a31e9d570fe9f5ac7b1d726c59f72349d4b2ee73c8242deb1e873440cbba17490c5ad67d486ad0b2ee41720336d23dfb91929e75ddcf9f6293be2fcb2debbccf862de3efe8dce9ca033867b73ba515e4c2f99dc8040666645bf27010235b6e8a19f92b0e7b62870ed257fdb8d0f35ac6d4f3affe4b95a77799993b9c52844bafe75dbe3c69fc92835207bbc9fd6023954a39a5e11bd12fbd861388efbe20835d05823cc01474e97313f4c227ff817ae9772213fa3f2de3e78eabd47bb287036323fc55c624a2682dbbaeeb28574639e8c20cfb04b6250657c9a53f8718e7334f268a1031ceffa15fbabb331b296597614a5cfaee3f8b18e73b138fb9742ae1484ee9bb130118c167ad5b2629791a899770c046c42f1fe74bd99192227d24f39987dd336def3d3b9918cbf10523fa1eeca0fb7d8b4e34a0850f5a605d2622341ab44ceb4e9cd167539c2139af48d625c65289123fca797fa41c927d36c3cf8f787ae65df8201895dc97123fa2fae2bdd5d372dedf006df4bd67e4bd3f066dd4afff3eb4e58fbfc0772625f77b179d4895d9a20398cbc46a5e24bd2c7eb665391da964b256d8dc11debccd57732bac8f30f0597d253eabcfcf498cf4a55a562b12632d62fcc9a58dfadb46cdcb648636eab28068a3ce7601d34661da28d653cbadcfb71b7d56bf8e97b92c65aebac4581f030e78491363c95bb7fe13296de47dfd0f6c555aaa8d4a26d99ddf5f5f040d3c5b321a179970368a4e22d848fda6a0e4e9c8ba04fbe4d2f33696cc756bfd2a51a51211a617aa2ff4ad9ee65f7fead0467366b511fdfa15b4d1ec8cf8d60e03be9e65e2314e36b043166eb62e136f79f47224bd9464da14cce7e923a679341e6fa59545ae7f9db76e055a6b65e798f9613cb37d0b121ba9404905828c600aaa49f86541b3fc9f89c4e45a49ce0d90861388d2fbae1ce97931b6f5287ae7f7876d34c7a9c5dd97eeee1d13c980f87e7002c17d7f254bd8e5ae563642df7d7264c9c3b7926578d94bc246ec58e500e9fc26a7065b6ecb0daeff244ba23be79cb3945d0d5ad6ef241311a3b98dd4b2fec963ae920ae65473c928a164c9d4c45b7769da1a9d2e46c9edf2bbe781558f49e879484db9839e954c7e1e58c9f1b48c83fde5385bc92ebf299d5c71fa5964a2c49b350d0882fc4df21721bacd632a1074f9a538aafcb94c419793dc1e5bd63cd3d6971579264f279392cb4fbb9978cc9dcf4d4f81be3bf3d72f398e9fe35fe298df997d3ac13f8118e797f4b677a713e3fc19067801572b737daebf44bf6919e5b73efde1a95f524a2b69cb27b73e25e707c6f934aade5a2db7aca45fd6ba54e7176aa98fb58d4abf6077777b7b9b00f697eeee4fbd79bd96cd257e4b66667a998dfccbeebbf4d4d7dfbc611600fdd2bd979c924ff346f56527fce6cdbccc4bfccb26dd8b71deb65e543bb1e0d67cba0b39979b60c3c3bc324efe014ef2029e4c7ae19a73766bf1920758432a3261faf4071be9a7e20564155964422d4fcbd848bf93208c7ceb0188cbf363142fdf7a9821e6c49f3eb5a506ae5bbe7407907bfa7397f3b4e574e29bccbb4ad6a2b694b92d65773e7fffdcd20246e7bb1fc7d7e9dcf851cf8fb2b948e829bbcbe708e6e3c3fcb0cda56fdfc146b1c3f8acc1f8acdb8bcf3aebe685cc2d27176bddb26ff4cace2cd8f7f0f99deff9f93e4a0fd6c396ff3bb684d972cc6a2e5c3e3d5d3e226cf9f8d8dcf85cf95c71f960f96075f574dd925e91c1e30a1a101f2d1f1f981a18ecfb7bcb8f7cfc88c52ccb8000b13f7efcf061a90f1f21ecb1f44c988fe57efecc9a59647aba19e7d6f3effc54f39cf34cabe2f9a9f539e487669c36e727999e1f3eb42619355a55587adec7c2aa7c1e4bcffc614980591f1f3bdd40d56edfd848378f2dbd1d5b8e3d6c09d3b1a56cb4e5f7e7907de3aeae33626ee800196ee4409335192b35e838618d37b4cead0853060db63a92a07d5d471c3cd84cb0f54003d1a8c2a2468b2f96a0b1cf705e7cdff271738587125c58dec585da48a05924502f4fb44193f1a0e696f44aebf60d47261b5fb6847db68479b6fcdbd9dbedf6cb6e593e632f9c2d3d30d59663189ff1a5b6842179b9f98cafdbf22f989dde9101e4a092deaecffb84f1f1230c981f3e7e4ccac567fd3ee89c5a5d3c3d3c3c3e3e3f7c7c7cf8f800e9e9e1b1555878be0af6f33eeff3dd13fbe98000f998f7ec473eac8f07f2fdb0e0330d6649f0b124f4fceb418a058a4fafc49ca7b61c9df7aeefaeeee2ea5be7613c07f33dbb1722cf6b37ee5bf4ab7aacabe9792c3c3bcfb4aa1eeb5abf43522e538b8bd6eddff9726a79b965dbb888bad8bacb8fda8bcffabd11d65e6e3f68bbdad63bb6bd4c5b7b193dd838b5a697d94566d2fa695683e2e73c1799db5cb7b558cb8f7a78d4c07e039fcd2d1f3ddcf83cfb6cfc9e9e679fe13c16e779f659f8cd63d967e0833ddef3bce863d967dff77c8e0fcb3e7bbdcfeb48c12cd1f7532e7ee4c36ee0b3f93e3d6cc96aee7c1d5b7a3da32d79ebcecfb1e5c863d96738b6643777be684b58684be6baf341cae5f613f9d1cb96de67cbd123ea88bc6abdf9defd6a3dbac71b200781ec47dff3835d5c93f69193c65b97b5a8179fd9bcab118b9fdafcc83f0bc665c4babaed8dd4d580d1f223a6a9d9a26ea81730bdc55c7ee54755533b34ef3d2fafd04b56f8cae2f2555221172c3faaea1e0be759bff2597f671dcbfdaac3dcabdbef6a2cbf774f9ffbf92fcb6ebbb3cd59f6d9c4ea2d375c6e7fd9616e7f63f9d1e8c1467735306abbdd58358ca583994c7bd82dc7fb914c9bb7e9c64dc771cd1b98d945268c4debd6576ac8f8acb9b9d5d4cb6deac58f1a8828c020a3032a4c41eba760fcc85fb0e38e2e3ee0e004ad9f86f1a3698502176fbade6c41eba7373f3a22450c63bcb11a43eba764fc681e51470b57726cb1d19a4bffe4e2475293067ebfbebf3f0ae347dcf75709fb45f023d062e0b3c662dafce86537e89f577ef4590efa2796679f90c0d90f7cd6df4d5d0d1be97735b7dfdda77bff0de3a45c5d8df60885087ec4a0f77d39b95cb69ab4ef73741e879f5faf073f143ffcf173be9c5797df2375ec0ce366b4138cd5a4e588767a19f937b09a349d7f795f32992ff9067ea9e472f825d1e597f991d406cfaf434e32640e39d5e090738b9c6ebee7f744f099ff063e139f7f14413baf5e7662b52d617672f1d9b4e55fd6d22233bf9c59a5ecca3cf0fd89bcd07b7f259e47bfeffd31f023107c99cfe683f63b5b32993bbf7cce967c837d76acb65472e797a3e7336a4ba23b6b7f25801c54f66dbe7fc95d4fbf642d6a4bb6a5ecb22db9ebfae73096330bcc2db9ab8bcb8fd4a8d9da72e3a69c64fc48eaa77668fe33cb8fa4c4e7be76e1835f3299aebefefb926fb5f3befb52c92d67168e952241e4accc672d4502f7e5cc0aed83646e2f0bfbf816c6b363a7040c673df6594974fb55eba64f802307fb765a3bee719eff43efbf17188a3cdff3fc9ee3e48c3a3b3d3e7635693c3d3e3e803c959547fbf130a7b222a2c52c901f240f8cdcf1e1d343c278c81f7c64fe0ee975df8b8f802190d80f1f092224023e8223e68c3a3d804c772ca991bee8fbad6df5e9872fe5e0cd766b5b0e16f7be7b29f7a72f155aa9e6f29983a942347e38e0f87a291f5bcb672e35b5a4786265813abdc5552b35b97e82c9f95be8b6efd636db2d24fab8c07081f9beeb2d707ca6815f7696f89a5923ce973ce6d8c7b19e96185a1868c7c6faece85998d6d40eadb39ecffa99c659a651cfa9cd7e5501725039b9bc8eabcfff7e449f9f232b89c52989c53b52aae73d52cac74fedd0a8ac441ae5de6ad2382c4abfd297f2de6ad2bc97aaaf8feb5b4d5af557cfced6ebad26edd563a5a8ac441ad59505b49eb79a34a92f0ee0f99e97f261a57cacd5a4f5f8f3f8ef58a9b9e533ff1ed66ad25efe3ab68acffc3f2bf5c467fea3b59ab4ea9f635f0ac75a4d9a67a5443bb3a4d867fea1b59a34ce1fb413cb675a1ef7dc58b3e68d6a71cf5b441d735d7f7d39b75e766a8756ffb3533b34fa4cebbc679af7e504e3911dc99195a4e4fb6c4e9edaecaee3ba23fd1256fe2d651f9af1a93ef7fc2f9cf7ef7b4b82087ebf5ea025e10b9f3efb51684978e5fc7cf6a3aaf043333acddb91a155852f755544cbb12480389684b0e3bab82e3f126d95285aaecb67fea1ad0ac3ee2799ce960fda2a109cb7694bd8cb56bd1e8bf7552fcb617ce64f2dd7f5d9aaefb17896042cf30ded0b7da6557d967dd63fc1f8acb37d68c627eebb8b87abf642c60bdf78b8ba1ca735bd78f123292c3eb543f35eff2f0f06f3fe358eb79c5ea4ae8a681f1e5a342c4e02fbcc022e9a970fcdf8b76d399de87f68c626fd654766d2304e1ac6b2cbe2baca2e4bcdf4d2b7ecc87464fc687af199bfe78d230c76cb8eccf567ffbfb62eab23d365719b5b725a5c17a785e4969c8df3c2d92a1835150ccf2de956bd7add9262d13025c5aab7f49bbb712e7e6b2ee742a66caeceb291f172bbbc94b38b68dabe643544a5777d668dd38671defe727ae9b82e034d79b5da396ec01f13d0b0f8168d008bdf01a4439e9fa06e07090d4bdbfaad6647f31c9afba07904349780e6568afbab225a535d19a161f12e9b1547ebaba6f58bd63d680d84d696d644686da5ea5f15715c0115968e764544ebb7729a579a8b34efa179109a0bd1dc4af95f15b5d3da568afed40eadeb9ae31e8bc36ae5ece856eaaa88e67f554493da71cb3e9b3fb543bb2aa27193dec0f7a3abb19d3e95d5c368dd53598d34eec1e7f7fc88ea2a098d8ae7ad94d05e6f15d2a8ac9ef6bdf7fc303fa2bafa09c51c9c1fdf2a88063eff487525a3515929a1e93c9515116de7ad64b41e6f05a38d4f654544e364b4ca47e653593d8df291f9cc14cce7df2171f8c8fc1ea4c847e6eb90397c64fe488e4cc1fc1cb2878fccc72179f8c87c91f4e123f343d2071f990f92302e9aff223b3e32ff23433e32df233da6808fcce748207c647e257ff8c87c4a06e123f39d14c247e63719011f993fb533db0a90a36fb5c315505d11d1fcad28ad9d56fafc9df7bdeaf387d57a3839a34e0f7f7e1eaee08af6700557a10f5770c5e3832bb8fa81710557413fb882ab22b4b6b0185770e5fd7005576310aee00a26842bb87a5a3f7f045cc1958cc61550cb2257e07604c215b47d9fcde79fa2b3b7400e2aab960c6359bd5432e263a1b730df63e1334bd401e62a098dbe14162f7e64a5dc9a60014db4525236ce4a716f8205b4cf4ad58070c2846aa546a842e22a88298878439332c1021ab5525366ccd005172f6a5aa039fdfa5456218d0bf21ed7edbfe2a17d5ce584fc8b666d551f4f79de074ffd1ead08be8716c5a2f65d7ca92f0e20dfbe14f8e44bc51ea47fbb0d7b20d4f60f7b29dbedbfb908f4413e3f2ff5c5013beff352bdf352dd4b5df1d0fc430ae6b67339981f8ff352606e3fd7ed202b253e907d6ba546d24a2181e0c7ac14bd01b1521466a5fcaddf7c5829e6e1f91e2b45b55c2b024bb17460ffb2525488a53488b52a42f3fefb72bc7dde0f908ff578d1c773dd7ebd4ed66bebf67b593dff656df156cc4a890fc43ef159bf8f95dac067fd3b568ac867fd9d95b22a42eb3eb452148c73399806f3c336d7b3161107137df8bc8ff1b99d9c1fc1dcc6f91cacdbe2e33856f8229696cd8795e2dec7ce1e56aa8acffa75acd4cc7a5929df92f2accf4a75568fed2dde62aeaccac3ed58a92f0ed0f91e2ff5bdd45512daeba5be38a03ea775fba5be38c0fbdab75b0f2bf5bd8e9da3959a607cd69f63a5268e95722cd14a3556685bcb36c1f09925eac0a2e067a5a8ac42dacb4a7d71c0f7f4a5e6d6edbf4a42a356eab373cb67fdf4392b35b57cd65fad547bb66f93b3030a3aac28828a2b536b7261b3831969ba60e9ec544b4144105bb0b843061ab5936bcbb9e85616d5c2d2a2376abb791605c37de95c60b81c0c672b97adfaa5676dbdc9aab6623916fdb2b5ba376ff2e022cd143260515baffa36d9d8a20b363690e982c634ffb26db7bb2c38b0851813aa5883c634b7d5e6b3fe7272ddfe39c338bfacb6db5fb52e034dd9da6c9f1576b8e302be73ce39e79c930cd948efa0c60e655ca6916f35a8b9bdc3181e7f73976f3bacb9b0490711ecf6f3cf97b511ccaaebf6ff1469a386b58c87c90ff823b0426e19b600b6ac5ebed5e0c667fc8cc34728259dc625fa12dcb2d6ead4a55f7e086036b7da2e5e7d26bdaf2425ab07c145f3ac8dadc0a25f7ed71fc92929c105278b1390e04ecd5aedce82798a3beff42bd76d396d974527f352eacf6459bbfcec34af3f33b311fec902c80f088740a779bb051d6ef8f59b849ab7bf450cf87e7669fed74f938dd48ff2ae13bfb9e0b7d824fcd70bb421c06e14ecd6ef8fe42bfa610b2edcf0bf07c11af6ebbf169dd00cbe0fc19f24f81f19be8b4ebc9fd3321b9965dbc946e67f0f9265dff959f1ae93e7618b9ab77f7e8d9bbdc664fa4337dd8f6dc4372eba6ed77171c7edba8eb363cbe8fb0923df912d65616c7fca12e459886e6a6650639b210d17561a30b6a4c9424b9a301d88e0f22d4d0c17e7f22d0d0a69ae9c60870973506db106165ae4c1826fb1020c545bec0003d516496871aa2db6d8420ac71254448d30f028a32a051e8ca8e3882ddfe59b167268c1058d07dca6430b4d04d1460d31bcc1a34b0b2f2be431e4f24d8b2b2e77f9a6451926dee0d178108d9d1804a79da787a3f57decf478cd10f438f6f32347084c07c8e7130187a68b2d0b343854f12d0b342ea8f059a059a16acc020d0a545e1668aeb0d02cd060a9ea2ccedc61421667daf8cc5c61450eef716fc1d5f7ea1533a470860d3ca810620e3a50b0ba42a3e30c1be399326e397e0a200795ac4544c437240c0c8081066d5432055d5993480638a375c6cc35d3c42d89c88c5f18ad33429439d365fc86028711043414c1e58a16c4a8e0c4992c469ca122e20d1376082147155c41a401a60c2ac4f0c09a21d21c91451455842193c4134a8060cc58c5003156229a00f3050824bc48a1c31359b719ace0b2840b1fc0ba3d45165a90daddb3b8baeece17a92d6b7d4760d175392517cce934e314934c4771e5363905c063aedc36aa9ee884b3612593748dfefef53b91499d7ffdffba9dcfdf894ce60599c379a3da39272fa9f391dca9bb9f5daa4f4bfa50b55be79c5a3a6071758512578cc1e16fb1895fb64e7eb99f5ea3b92fee59ac8fd42293cee36a061c579f726037c57a39ebb191f948cdf463235f69d0028bc6020b2c80da1012811d47b49186082670a8620e8ad3849823b2ba60c14518397c08297187095b62182166883884782cd882861b34d08839230738668d8918b884d1410e2754c87ac3b611d4060b9d1455407401430a255410c38d2da310369aa0218e2460d042838ba4c20133a6f88289243820a60d164221388083184250f96045171b5bb8a63138d0859736389801c61a2cfcc8c0c4095cb080e8620726d478615187981cc6d80a030c34696ca92fd070460520b276f0210c1a5b7e9c71238b2b9cc80185338a3863cb1759f3851757e8f8001a17dcf8019c08e30a398ac0810b0f98214249424c9b2a8630030818cac0718375071a14d098238f26c8d8e25150c7950c3cb031c10626dab0108406ad1956508335039a366cb6e46c91214d550b6cc6546d31c6161d074c61c21a62c8e8e1033088c1428c871daa60e80281196cd26c6d89a003319480e14a1a6adee0100690019c29238c1b5b43c0e104183d6eb719dc50820520b88ef8620bac6675a3e1035b361adc4063cd169f1f2e9210e384aa3ac084c08b1e266ea860f3a14bab0c25ba60a18fbc18e1810f98218607d470b1c3682491031a798c49022b0c355bbe342c809d0504be943122cb863a4030038ddba2cff06b714bd8eda4ae159c6093c51d5d7c8036fa116d4d0d5c64d1f0450d1968fd7f59ecbf48cd4133ccf318ee2bad7506132a0f8cab473f622b60b8d5c6f3b5d66ae6d63d587145adb0b99bc1c34c171e17cc8171f37084444597cff8de10e6c83a630bab336668a071672e67c676393329a4d05dfa0ab07682177668c9a005870c6b689c05d40e3b30f76c2cc8c441464bc3904287e58a32545c9913b0b8e04d31c3145a6e4f81c5e7f2adcc1a655ca06568b86ac1ba2db3c3550b65be58b550660813ba051a74f956a64c1924b82bc0cf051abc1dca7ce92edfca0c41ab0e2077fbc8c17b90a03c5754365c1b17164e728a1080267861d7759de7519145c596d7cee51b1560c07092543cf1c28939e1ae7fdf72042a05d83438f779bc643e7bd8e3061136040e79f90605153950a8318693fcb97c8b02850b6b59adb5725d98b1cb2bfcbeef7b81516cf9b87c8b820c4e288aa2889323850b40976f5170f1bc0e3de12423b87c93620c4fb8e3beb3c3bfc3d3e3b111b652dcf1e3f24d0a36fcfa3c1027e624bcfe7e4ba8ebf63303e4fec08ce10b5bb66c1913e6092b7a055a29ad0a88a3082caea4a1421d4ed068994bc790a1ea145e976f63e000c1182e2c5ac6a841a565cc1958b48c3973bbcbb731665a85460185ce12c45169f127b0b43c31c3094ff090a54fe07c2edf9e08733f50b100a942acd70c39dfe5db133c5c187b4fa638b30ae40e46faa557d25b9f6f4ec471fdbd7efd00e4067f765963e64e3277b6b925cc89196ee939b1e6faff30d1e6fa24a7ed5eb64ca6a52213a7a03b27d545ead9dd5623df9cd0724bd8edaebf97738aeb0f53e2faffdc9a3073fd833c0a4e6c32a760232202babffbdb965d86975072966123b3dfe3256d9d7809517d01e4204a29a5944ec14bf8b2a5e0ca38c9dcd2bb5d23ce3c42ba818067d308e91605cbf8963ed7a711976fd9e322ddc27038058074538227e03bb58ef07a47adf39dd908992e04394a88640f1baf3c9ad32efe6428a5d4bb94524aa92d29a5341ca37aadb57aad95d65967a5b5ce699d66a5b5d65aab2d6badb536273707e84d1a36defe9b1a779299fd0a98649a6a9cb7c7e522030e236b884ea6146d38cd3797cc14005ffeae917f76e1255093eace2e6c847f09d42cc3031be16fcac3a5960c2f81e236efb6f49f525cb7930c1be16faa916f8fcbdf5846f0f28d0935e1104c90b9acc5addffeb1eeea91f7f58b2831401b4defe7d69ef1974447af2f2b789163cffa3fd2ebd9acbfe35ccb7baed1205fa62037f87ef4f3fc1854f1237f8e3dffbcf9d17c3d3fd2077e347bfe89e547113cdbe71f95f8133f0af21c3e073dcfef3c3f077ed4e379c8f34f2fcf2ff323d8f36fe047429e5f043ff279269f882dbd4be49b8cc95e8217fa4afed82a20fff31c6981defe7f474660ab38a197bd47ce6c55d79f3d4806d9aaa07fa017c920fdf5bdd72187d821cfbd04df4392b6ca921ff43e4821b66ad6f3deff20ab625f25e497e8ba449ea7082d8890fff91cb24a88cd3244ab125fc803f917109b058716c1c76cd58fcff91f9ba58756d53d9087c59ee75fbf4356c578fee7717e1ee7796c16a755f9f89cffc8aa1f9bc508ad4ae77f70fef594acc2b1590640ab025fc8cb66f9a155bd1ec8c76c161e5a55ece9f720ab7a3c9be507adca7b20df368b47ab8a7dbfcf6c9649abe2f99fefb159385a15ce0bf96ab3f4a055f57ccefb9055329b2546abaa1f93c06609a255c13ee7877c48560db1595eb4aa1e9ccd9243ab0a5fc80bd92c4a6855dc03f991acc25255a305d92c12d0aa62efff36cb8c56e5f339dfff933fc92a209ba56955e3ff3c96aa1acdda2c04a055e5bc105bf5d9aaf1ab74beaac757f1fcce679934214fda2c47b4aaef81d82a209f65d2de56cdafeaaff2afaa4f3f02b22a66abb24c5aec85d82aeeabbaaffa7e7e10b26ae77f6c55cc56f57c95cf57f9f8aa1f0ffb2c9306c456815f157e95f855398ff3484e849cbadd1f248c94f98cdf07b981cff87d48117cc6df43ce2c9ff1f3909ecff87748229ff1f72039f099cd67fc2339bdf88cf97148253ee317c9273ee30fc979e5337e909c607cc6ff22613ee3ff48249ff17be4073ec3f2193f47ce303ee3afe4fb8c9f9218f88cdfc92a3ee36f7272f1d9cd67fcb539356baf0be7f3fa175a2d4f3692d8c2d55a9350e1d65adb502449a490c3c85dbe2561c22d7f72ed5a545a2ba572bbe3073b6278c30b17ad36c1061d31f8081beb582ff0450e611071060aaa386855cc15a1182f5a60e3f95cbe21e1c62dc7f733aa5377ca468511e6f3ba2391e6ba169abbbbbbcf36469ccb3724ca84976f482c71ebe51b1261e800cb2ed4edd417fe2f4b4c4cfc6d9beefca9aecd6e027a6dd44d7af399e79cb59e730a0210800004d0825d30a71b4b25d7c87f727194e32819d4320f7cd532115d8ee338fb3e9b39801ef56ae5b830335c8e0b83c3e5aed038ae5236d4b97e1083e58e1cd0b0230d9a5b701d8923aec32e5223758744d61d2fdf90c0aa68c8e00820c6cce53819408e0b2f37398e7bea3dc7711cd766e4b88ea42da31cf7238cc65dae4e36235ffaf43d0ea22c705367d868228b356dd26c410027ae9d2a3e10870976ac40c31d021083c327e6871b6aadb5221113c3f7859598155e47bc500572109718135460336b1e1fa51485365668038b095814b1240c1b310c970a6cc25c8113e60b3639976f47587139dc8c501346cb113770d58af8e28b13a2e0001848b010804b7f3ce2d23048bcc086e7f2cd88372e78f966841964cc18b7fc887333b9b8a9e533ce92c0d9d4705d5b57136b7211c1cb15911f75df5f2aa94fa3e4fb8cd3aa640c02f4eb574b82f794c6341a8b4c3658c0a4755fe977768a7b5aa5be4060b251c414369af7f4a5a6b8efdeb353dc9330d5599baf49c3051b8d3eaddf0ff3234a81dbda4bd940dcf95e6210a8cf7d7d4ac620409f7bfadca49123696badbba30124f2a3a6f183395eaee73cce1307afffbe7bb0c8819487d40c101f7cd092d0e34507693aef9609ede1e9b8b9f3e9d69ddf7179cf539fa73a5d8f17bd07c50745d0c6fabfb669f96c7e0f35b1eebaf371faaab31aabb9dcf9957caa2f82def7f81e96049df79e69628fdff91d4b42f73d9e69e0b765d23cbfa3f33ccf2207ddef3cd6d59d2f72b9f379c818f7351acf83957ceae720e7bff77fe2e0f538efef040129f0c3cf790848893ffeebc12972a0f3de4f9183ee7bfc0654def708dffb1e3646dfc78b083e9baf43da627466ddf93d160c0f49e6cedf21635c98db9d2f7224613e7b829ad7c9e989010c78a7270e6210787dcebffa9f388841208704f1739e693dbe2d93faf475be7b50e759e440fcdb8324d22163fd359af7201519c034aad7e74000fcd7b7c881f8394f3908fff52c7230da1c1bf3c7d112431224d9672f32e676036e0ad47864ac6b34f6d9d458abed9d01b9c71823680c2222e0b822a20d2aa0cb3722cc5c269e2bd133a571441877bc49c1863234a34b7f24a2844b4da0d10f72cb44348a976f44f870bdcb37228e5842646626828819de00b941fa54866bb992948db4378d7c0343c465ca4beaf7575ec2b30317369da4538b9ca3c9ac00d1498e15ca3e27e0077b16a501b98d687bd7fb8e97741c2fe12a2fa9ce4bbc79494f5e32d908f71ec9dcb44bdcfb73b439d0eb7e4ecf96def52ef75dc771b552eadebce47acffdcca0bbd563efb9f63aebd4dda57e2ffda16ab76d7793ca007a0c5baacf7d19c26477ec5e6cd25d66235faba51e4ce6f96c723dd198930c07bc440af8252cfc92b54a465326b93a9ff3aff1f93568a3eec8f359ebd4af7bf14191c47910f4beeffb6c599f7ba4f6ca0dee12597edf971b5cef91fab325d1fddeaba577716cf95d912c3dcb44743f269d0d496ed908e690fc6aa3fa738ab1fcefe3580925899210895d63008f18673fc28af012ae497697e8d7eecba0db0f56f27b0eae7fadf43fb274cb24bbfe1446edc83ee3f96123f367995abfab2572d2ebd632ddb84903ce5b59c1e5247de4d16e4390b90901c624337e501b79fdf945cae96450cb828869410d195edca0c695247378795051cb44746badd59f2b6381040a2868c1b505133a14b5a967a4f02f83e283de8f463feaecd7c260b199a20937e8500303adbed746486efd51cde58600e3f2ad7e902d99882eb50fc538ff83c22c6ef944f58a1b613c65b2f4082bc7cb030214aa0d63c5893f502c401a96e31d61f5cb221318b9093166aecee526c2b4a95fc6f9e37cd84f4999822e0a251c511a6d19fbd1d8b20fe94d88142e7d8a85462fb52553d0e596f98f63461efd887a4d8e3c3d9b5f71187d5cbe09e1c2a5976f4260dd72bcf369bb1620b38ed7b2222dfb52e63a3c2d8b515dfa31ce36e9cb3ddf40c075eb2319208edb5f45aa8ffc66b3d9aed0fa356823be8159739b68cd6d5a395e0cda686c2a6aa3ba25bb39a20ab96c369b8df6856f41e8704b8ee3f6736403c8e0221b3006d98031b45ac697a88d7a5e2569a3090070cb0a1a40461c4ef2651bd4b2eed2fdb4ac751ac066bced614d0f70b9f4bb07733c8f965dc73db5657ff71e39bfb8b9de775fd45ceebb69c5d83f29dff0f5fc2017fed42625fdef395b76ffb2b10cb8ff9efbcfa3cfd9b27b4ecca07befbf8d38491e6367973a9e0cbae7de4504703f9d7d1847563bbacf00727f4138df0357977efdd275812edf8098e2821e7ed84663cb380c5d6c52cea7dfd9d18617843a0d6063c6867689fb7e6acb9fb23e0f7dce2e55fb2de3ef2d353142e000868b2e38e0008266e4323f524de27d4469fc1c3447983e84f961861eb47a5073fbc11c0e9a5d8ce5ffd77d831fc9538af1f57c5f3ffbd52dd1a70f5691c9a741edce09ba9841f7d3964bdd4f917e472e711f39afd7d16791a3f39bce06076b7ace676666e6c9fcccccec313119256e7c0073b9efb807bfd65a6badb582e0d767b149fd7ae4d1e67b7d346d369bed8ae65935b7f494f8d1cef773c04b7ae87ce9ddefb98f9e5419bff4eeeba79ab19cb6696b23ef73826e15eb87f5b98fea83df83dc808dd4df21897a560dd0556a1dade795b20b3e0e59fe055f244bd8053f24cbf182f689de72daf856b219cf7a9ca5168c4ed338bc3bb7b4f007bda7a447bf92256f6ddd3ad38c257789e047ed7dd349279d74d2497fd22eda45bb6817fd52762d51cba82d2710b79fb6c8a4da699978eb723f45272268e1831657b77a7ef479b7bb89dddc6a97a8f5c296cd2d8a830702499287d326a2bbe41fb68c1fecdefbe69e7ec94474bdff1ef448af65518cddf3adde653ff268fd9ea7002bf34e4b6d13d1e5ec12fd6a476f360a58b8bbfb7cf7d9dd4f1d0c22cf6f063d3e68f103d17ca23e650aba4e6f54df0c7ec2b8d1e6cea7245310bdf3e95c33452693c559df4526ee64d73fc5f92d7acf390758bf6466f66a994e346477bc38cfef2d31bee8e190329fe17c77f7e1731f853debbe7bb07b1c5264225aaf65dd23794896de9db6e47991e5d83d4c21c6d2bb1c67270557461e73e70c337affa4b611af91a17933301ed3557094a467f53bcf1b4718ec5f46d4b23a7664395db89ce5b15dbe476abe75ed5f445b12a151c3662edb52fc293211dd26a2bb14feab0c6d4974c30fe279fe6f239d92e7ee7c8fe70a5ad6cf4326e9d98e057fec41becfe6e704c178ae28fee8473d46f6d968a72dc3ef1ec973c8f2aff83864395ed19601a03da8c409954b94899a24a5530acdd00c82800623156040402c160d482492a6e8f50114000e94b04e5240934bc324c63114648c3106180300000400200446866cac003eaf82cb8762cecfb5d69ac2b5b976b3a285b3e016443f2c8212281b4d9a62047eb73106fceb9e929881cfa5c24c2e5c64699e1cb73040233b3f120b4f0ea9a64ddafda0210d0dad697261b0131fa73ec8ce8bb7741d1eb8e40067e26f738d2a23536ae20d0bb48bf66b7723b79b8b4355592db0a1048cad7565ef4d6dd2262a4fb3efe6db2f69eafe8c7b55f1f1f2822be9e0471579b298153a6357d17fb35900ba581d6035b772a40c9a7d57ebe026f1b85b8ed51c69f66f6ae8f1cabd79ea8894bb73574af906db9db503bd2250fe2532581d15eea62d5130ddf849ef45aaa84fa3b544dc4e716a8d16611fdcd957db746d2e2b3a6b8595de76b3a0db565bf46d2e2b1a6bc54ad776b7a0db565b7436372b7a6bc54adf76b1a0d956597436172b7a6bc54ac78e4bf767aeeef5c3706ebba5b0154fa92bebbb98b85d222f26aea7e03c9f20db9b43bb8f5cb1cd9a06723f121366eaeceb3666c46d56b38dcdd4da751833629b1f8d8537dc4f9e29c471623c6f04b75e2b8913f1a61285ad81f9124caad0129b59425997f331e0d8cf0e0b4344ebe0496bf73473172f5c18b0ca0c8a8a0d9408a4ae8ad146228056dbaaf084e1759afdd721488fa5ce01a0213a4f7e33f8b0cb535feb9d2f55f43524f67e3500d36bdf17c06713203ef960fdf9049b9729bb7cc294ad6d482509a0c7f268272c0f8635b6fdc948e319d0d6b009d24c6e643b444caa19d0e07369032869986d0506df0b1358e52170fad77c0d56b6412f38f0ba98c0160f9153866c2a84785dba002a2f88d3b17636f13264d7dba058e8dae9392285d8cb329ede8c6183d0805000170205aa83affb536497d0e251ae2cfbfaa8daccee07cb8eaf9d1a0c4cf9d7cb5cdf66d210ab1d9a397f1f4c554997e5788a4c5b9919bf6d350644ef023efc4150cfdeee60fd6c8d0ac70d3172f0034401a2c1065510439da39aa8f21751b2f9ea4524a21bd0784f10d9bc63e754f2321dbb36a5d9bd3e6184a82557e2b9f311610cc117d731603e8efd8d3fa52fb4d5e6c2745abe22118535af8084ada365cec08d000717973990641229e184ed27a4cbf83993c813b4e308dbe6095d7251a81dad02f93c53a4a95e86c39d9d232486a20f46aa36cc3805112b9f5e04a4c0b253dc26cf40abd127871fdb9d8c5a8152bce49a16b005120fc2df87b56e6d515694c58529564a25f306311696deec25d0e055564eae4dcaab8e5fd2a9aa492ff1734bb1731481358a86ac6b6cc7d4f36b3d16530db734263dcf0ebade076df71228f8d86bb9aa12d737f7f7167345d80fbd81b5487ff53c0a80f95a5bf43f60afb286d4afde8002305ecb36e8652193cd0f7aaa67ef9f67d512fd2d9ef749eec406fd21304cbfbe0db4482dec7fb68e152a053d9237b10dfda185202cc7ba45574a8ff48f7b7f5700c272ac5ba02b5d7c97dc99dc827e158a40d88eb545477983f4996cd17f8282f1f3f691ae90dfe8f1fdc426b93fd98e8ed222004cdfda0c5defc516b23fb1195da88a70308e650bf487161b64fee46674a55184c276ac5bf48b37a47ff44a06c1fcebdb5fb25209f3df4d6215aaa84df226b6e817c3c1f8f94d638ab542ce771b2b933e921ff7aac2c70dd4b138117c4b8b3eba6deeda3ce55a10f8b22d7a89926243a7cabd0302df7d953462df25e92e45d1490c96b50093fd37062b000995c5604bae3551d9e08636eb0e1f2922e0ecb2649a79863b40ccfed4382ea62e007674278a7853d42ea2e05716537610f31156ad7187703accd757039c5c4659554e62e924180895ac23442acd0cab2ee5891fe750299157088e6fa42dc2c2e90d331a4b4a0eeb1e465d67530d898a1cea28104953428ba6fdd52f7f42d1caa05d766eabaadb45f048047cea499ccb6614ac0a28ce668b0058d1f4af49e8639de41b9fc38caa2e6dd2c95fae219ce658b826ce3091fa2f2ca9b92425137f2d925cc5141b07fb82b7c9401211ba46ae8f8073f3203384fda9d21976b6159fce446dde30b099d891a5f804b478dd0f88e5c1c795aae44d564b51c794ffac07ee7a99bceb5b391f8869f2c319c7bbff8bb2cd6705f41f0471404f8417b489f4da895e1c90b2df62b2a41f1e37f2818e13a4d021f818f940f5b6eaf49fb503649c650ce3e3b95cd817257518f41d7fc4c15550e103677051f7c88ea4ae6304751fc110ec9b9cee01b463f26c5ee776ea245dafd98598397cef2ee10be32e00d09c780e5b4584db773d0bd6f43c7a16d9e57ec27e80c7be749be9b6bc3ad47bec109535220eb6b4f4b2a11688b4d8e467960e9071e8face4cc436dc564be2057c0a4f8564b43525f285730a351f51ee38977fb6034ee773f562b878bbf1c8023f097c0bc15d3d2bd643616b5f066c14fdd6743b7b411dadce4b2cf4c3844db5048bb2264042119ef6ef98e0400927223b05a2c85be30ba66f999503c1551191f26afb72463b08c3a77260a7cc26f6e95becf0d014c7778e036a8c6cf447c019f8251aa8b11adb1c97f28dbfa081a96f3081ecccbd7e6082875109ce1f536db93e2c933d5a49f8eeb5afcf1300fa5d5deba0643ca31e885230ddfae9c545af766e187883f673d5b9475b43aae2ed0e0bdb411edb410816311d01cb4abd370d8e62f766e2a9831a5346a455f3cd8844fe67348588e9fea6f845f45c24850efdf382f77c583e243edf7b787d1898dd1e0db84ae2f0c9f19a33227b56b14d6cde4098c3fe8f6796a113a6f214d9c424bd6e907cd4a96c3de522d1450f5b3a69711fc781fde320b5ad0d3201cd60826589bfb98129ca8bf7a50130bbc254b964e2299af09004d2fdf462cd05d382d9ec4a6f73291850da4d9cfceae618f6b9fc6f54ee0e22be96033a95c54499d4f0b9b5238d307104f2ade1e5121f9739a1141ba2b4a52e8e4574fe6612859878f81d38b43cbb71c6b1caf219d1d632c41843eca660ec5b8f1a206d8ee4c93494370fcda6ad43f91e5a068f5e5f5457e44e265a825baab93dd29016a8cda7cc5b85db0949ef68c9408a2389182b71139087aaf806bd86baaac6efa846e49da0646f4f8de5793ae29ad1d73fd8b8c6e9fca0136ce8b941a8fd029c0d4e1afff42bdbf6c6c270152e92cb8ef6c66114e69f132a90950b9b3293bab2e7bed2f2c55119de913760e42f5c9868d13c28b2b544c4cb55c570b371bbf45fe4292bb6ea073a7195719dd04314497ab71152c69fbcdb0e211dacce55dfa1fade46b1f4a7b4ffe62b797a994b063dd72a002573e687b0961b88f1512c4a491666d6c2ca23a40ebdbc6ffe06261f50df138d50c4a69c50094dbaf21017203329144aed8dc30713d1edb5ca11ece2527e10bbc358c415be3458c0f48ff9ef1015af9d961aceccd875f163c22ce46a01bf79c674cc8f5be9a90324f39c0ea699ddcbe503653aa34ab53777edda9dbcb17e8660f3e09fe8f4f0e78ec9cb51054a5ebad7c5c7457f39b1af6e1f70a2a0d618d00d613226c85b4787bf192bfc40323bf502f65718d1a4be772c4e5e19b9d48ab2ec8df8b37f545dc10267028842ebb5045dafa5582daaadc0760ba805b601b72c6c55a3eb0fb40761fcd34a67cfc7fa298282fbc2a3841bd9faf5fe2665694aff3d4cde122ce2464ce5b5e277eb561dc812d6909745589f8b7023a677415b5a21e0442ceaa0b6f2d0d8b532bd571683ad5286f8372049a7b6d7ff4d695607db7173f317c2307207634140ab4697ad91797f2a05f0b01975876b10d9ae616009012a50b070c3a9d35baa0877864182c7d729fd13dccfb84f87f420dd92fb54d97f66dda04fb2ff42aab61077f8b5ac2d40f345d343904f6c99fc34afbedeb1bc2ef4356737e894414bc52878ffd111af22984a3b0e8d834ca37b7975608bdd45a751e10816e65cf7a958744c9c4a0471f9b336d28782df1c4b4a074cdfc7cb1957297b23f74b2f6ceba491ef61d496d3e9d763cbca2a852fb8504df1724891755056e5a33141003f6de2521d109812097dbb4c4bd0f0adf5fc28c5e8cdd1931af507f4fc7773eebf8ec17e0c835dfe309434f8291f8bd2292869fe086ffabe8dd9833178a58e269af51296e089d21b08e925757c46edebe58463b34141f00bec9b7d9f57893b561206dc3aa391c9d26e76ef0df8ccf24495f6d701851e382cb81f74f18d4f1718249e0267fe1bff021b4cc7c08bb8c24c7fe76ed3565dd854c7fc15c0dee13c9476bc6dfc086435288787bfb982a776e9aa290b297b9e8b7c834ab24ff2626e811ac2186231edb0114d7373dab53b98c8f8c3f27ab095321349581d9ab3f901164a3fcd6058ddb031dbe1e3c56d500eb7e727a00ab793e42d04b4a5b6524d25c3b543a9a89cec89c351aadd423471cf883d1a7147b7789a1be71cb97143512431d586f3d950bc068ac8e624faf03bf67374a31e4bb3b9c667e70d02c449c9c0ef604d2f3181fad84ebeffcaf4a856cdef3670fa7c6b4e8f436705c135bf04008939d81cfd9fc1344836281b375fc075bbd8e3629f4c4a1e1d164f14c3c84cc2d683a2be1724d2c6c6ad3d69b84398ca59ef9de1d4c08cc5a1c15808c026cca8bc7c1b894d35882fa6730b9df4016b1a74d86691502504dc18188f6d2ef3e948169ef43e23af8e2388890179df775479bafe7c39715ae747f0c1832462f6d6f9688a0d201a9996d540fb59dc8e0517d01ac8ea50b5a49ac2a3947b6c564aa146e1d802ae903d04e504e8b0af2aec4d2c86ec62f7e0722d509e5f388e5a472d00c7a889b1c86656d70ab81263a8843c35b980809e77d684cd9b18fce0507c6227e7664f823bd5b1c4bf50a0b93431009aafc1be750d4e94931d8aad58ca2d0a67b99d388a50799bac45e277deb2c158a40e1cd5292b2065d2818dbf0e7ec144381c72598292358f692c0cdbb18ead17433d90a2902211623b2bb2d3316c0bc8fc073c87792b2a0834d056f6be63862368503007fabeac5a6e37d8243d42c62f49a60b3f702ff8adf6ae0b7d1103c0192a2dfa82f3d0d7af7e32579f4205a90fec8a36be6f645ca416f1a6f2b09dafc872202bc4d4f65cc1ed55638028508991c6d2988fc954c71ab40ec46c04834f958c8ff241b5c0617ff93df3610a39264aa9526e2ee336975134b99bace08d179b640858a4c06af0f93b0b9978420856b2dc02679649ea078eb4c7c264db17e358a6b2fd94d599176c6da5b801f22785e364936e34f3d17574c47395015f21b36dbecca695c57852987a0f212b70c234effd22f16d588c1c665061a2a890f65ff16602e0a417cb0f77f366cd19ea1bb2152df36739bb6ba51a85b9e10a75149e17c0cc426ceb59f3edff614cf4962fd529f6ee374bb81bd1ec352231ea41cf99e5c4943c12e28a5c9ed5de708413d3ad334708769836d837606d09af0a1aabae4adfccfc135b693f59dd041ad92ea50283b71cbdc1c89ca61a6b1289c1c7930db16fcfba1988d5b208e5228b7da9df858c25ce86257336736f8397be46d18aa9a88283108eaed9ab4b92f6df953ecf5b80f359d6124a3c33a1bb7450eac8014c2e6c6f23314ba1daa20679a275e5b675f6e97a34ae9973b735d8dbc43b057eb89475f8286b185b50071bb64041867a9ec18cc8f0be06051fc1255ecf67c0840a408da017e464a580d284f9132cdcfd27c890c2ba717c0394b546a4dde92938c19ab2a47daddc6c9850667c4da0727716b54025a7e464548c0f2cca7cce9f4b87f8f1c9ce107c9ecab899a11686cff8281179e1c9c172f69e91a73d2bbf76f20412a14d31327b8cb820c5e10e82f0112b1d373182e03fe490a3081d0ba6b67977c43d68d6ce478295b7e0678309448ea13a0f12899f0a6be27f8e08efa36d177088568e1dd4e2ecc53c53c6ce28e730a6e2f0a4ac6d9d555afcc3805638f2200214f2b8872368e8db1ec79f3707b4765ff0a1abfde7a141b736cafa428742465efe61cce10287227448280d932d4bf37a996d398ad58f4546d4d776428b8a409019f824244d12d26c9a8220209182dcb93b10bc2cfc7c3d1129af59899c015f1724489c7b3be79f37824c6427dd9ff129e671f36fc5037ecfd74832ffd6119f6248764d0c27125e23c05d1a20f2cde3fa0e58552312c24677a2e31e9198fba43a6aabcf66c358175d133147b41fc27abae6ab291202994fe056f1074f4132cd094310fc7b3647bd41fb20b97e6f4696a2ceee219f2035ac7e1f5d184a545fc167f7eb76a794ea94106ecf0e46d0cdb4d712935ac3c5acdaa9ede4ec3ad662f4f78f4e8e10417bf47303e58543942b24cb457dfe6d04f54d64ddcb8a6a19add0532fff8bd29f9d306bcc00a151766821325916511747e1565f29aa1bc0f65ba8fe6bece2abcc0b9e745b3a624c0364ca8d377dd234575dcd5a11854014538a91761961f546f7db96638bdedc076bc69cbb40d6835111cc9cac3c94bf76b2c6e76fcadeae6ecb2b6a4a050e3c4d022c391191200e2331b555240e54cce04c407e9029d0579e35bcca2e03b4d4b5a5c0028e87990e0fd511318c998a6a8d0573ac5268a2c43f8f367b88c6a527204485f2eb30744e32a0fa618778abdedfcd917cecb480b04b36ecaef6752784dd7e812f4dd69ea941b5247625dd5383c0dbbc3d970aeca28153c98b063a6bfdf075ea90553099499631bc39910426bc4df15e05d4b986e19d470deed8add9ac6a2e5822c78fdd7fbacaecf93444e5380f66a04280312d0a6014adb33e0eaaeea300dfceb401cd57306eb21f48b7ce3bec03ce82020b03751c08a0330f2363b0661c7990f6ecaef03935f9deae0558b8612c6e967abe56a986ee8cc7c8e9ec64c86c8c92056b5a966663e995538d88bfbb2368a14d824b1cab3412b297420dfaf94f53931c303b16397a243b5f4e9020abe2eb3987860f2e4314baeabd039cc2c799270fcb0c83463d6139ec2adab5e06ed873f2d74c63988c837d0a1b2b686e3b966813830cebc6e003c5c20e61651f982dc24a39455e458475af067fb9fb302f601974b7156b0fd345722fcff232932608262a63b12ae4d82571cf36f28691714877f141a2b36ace71478046c960030d5107834d8e6b4b1e523c46be157c3f08a937eac4f647ce1efea3dc1c001a950b5877ba75a0666dfdd7df6d1b5489397a841db6d7f6a7424afb0617246a3f6cde24995ee53538b2d4248a420fd1d1004f9c4780e5a28379b65c8bdd3300e2143bac63d1bbf3653d0d90cf3e3aa318dd4638bd5df39340732d58fbea060f181854359a6d324f8a9fb91a0d72a5aa69f1d54e25578d80734df34860ad6de4aaab51961528afa8fc199e0985a0a55fc0e0cf5213a5ccaf2c19ae216e625f7bc19decac39a8a4e4c9a8bd6c99530a9a159a9828315f0d0de303dd19c9084f4f82ac7cafef3824fe76347c63a78f3bd3ca748d6181b3aae4589f3dd9a158a31354fda8f23842950fbdecff517af1abdc582d3729655bb3d62ebf82b2d76202b030ab3edd6b3bcf9872a21020d098cfe474131d9f8881b8e320b1d2f92a1e6a6155ac7c825afaea89859cb6925f8db13a1b368bf035f966c361322d16cc9c7c432b89e3fb4c9f5ede8060703ba617e0ee3e1be41e8878e61e691dcd91971a1eab52bb2094206f3ed31a90a9c7425791b93596adb98188dba61a0ae98257d82925271625a1561e25fe62a5f4ec490cb33f1f84f291e709047901a3d230d647ae10e81eddf6059a3a14f3f0aa1dcba6c58ad04fbd54c860925e988a20112329eb460e6b766d7c632a0c995e75cf2525126e0454b7c703cb30ef606c5cbe3a620e6254bcb7ca8bb31cf844bda553c800a5dbe1fdeb65a9827a40ceb129e8cc8c64857030d5b2ace7aaa7d6448771bad1ee3eb5d33446ddf86c5340cbc30eed683ce3154670352da535a4ae9ca877ee99d01da38f76b0761796b9ab45fc4132b95dfc91eaecac6d3641156fa3af3e9d7e5d58686c8fb1dc59e312c5f8610c9a3f461c14c33a8cc29d3dbca82fa0905d291fad098fce9327bf3532eb4e80e41124c7f7d6fa25969148e92796844f79b9b14a1a775ff7679d81647cdfbac382f3478b3b10c861c42d1b9eaa7998aa9de41b83946f682f8aeb0dbcb1b7007df86e6fcc6a4cb5bc08562bae4233c01a32dd8e2fc98cd8e2da5162b48ea349c46318c13d941b79f7b9017a1abd747550b30ae18250f4c9ee2569f77ae15411261d39c1c4d8cff22d71ba34249f7805cca4e0357178e9fd05bf89eb50775e10cd84868345c6c19246c124a82535508004e488ccdee4287b70e51d1c48cf2cdb65925c82a54f6d2bde84654497bd64446a74890674443317ad4bbef9e48e7acf7f1cac6a7add9cba48340aa658292fff206192b2378fff77e64831a0247b663aace9094902e6eb7c8320db16c9af5ff806e02ace02bc30a0e22dfb0a0b1a457b10fc1cb1e90c2f215ce9cb11882650895dae92d4a29cd625c6401713c8c2c8805f00988201352816c6039d3e6940624e396af85bc5b2134e0fed64a53847d6be900bc525e93b1627789b4e2a8d94986eca33ddc4c2ca4c68d895d5c6d1bd70cbe2683f9d7603e67570a04604593c6e14f003064186e9048bac1342ffb4f09d369e4e42f3f816e1122b211b6fda741efa7a66ac9c44d18999f0ef7d1599f3446fd4f543d63d1326271b94317358cf39f19a8d56a0cd99a323b8f1cf3dc9505705877e4ef2b042e12e2a7e5c04a4e40487694133e740fa73127b9e371fd5ddf549a7e242a405e1af5ffa45a71a2492f73b840a28bb9e5d6636664e06fe53ba09dd289b400292d86def32387d22d79a4e63ffec3a170a95cf7fde59a8ce47bc1ea19794da82272661351f8826e261fc9cc4a4a748a8a88e0257772d98c821f2643cdfddd7044c4cdef8fb4cc22a1222286e49c69638eb59530400a4112a5240cf8b74f458ccd6d989ed13c52e16f0052a5a064bd78415466aa9a88aee0f0c936439d7a0c0e36749b66f8ced871d8ca8aae5f9c0ae7e7c5f69b1e42d70dbbea1321e922bf10e92d5e5713a5cfbff493459395622337344fe1f1c194a02dca875cd68446816d23401f3b45340b9795e33b6f5dd26b22ec2d04b6c20a0cebe12e58c3631d323007d6dbba7717d602432eca6c06424342e21373b78f45585f65c466783a445fe101750795d558f944d2c2b2bcc618562cd8af6207ec66713b460b523020115bbca4838b84077e0c84c8264dad76ae4048c29671554ca45da725d2bb84bae4b6ebbce50ad02580a28a2b460b8f1de23d99e7152204bf5e8e99a00406b08af4f3b70fd25c3b63ef07f5a148904af9a06be3649702f69bc8cb594034539c8055f06f7de2f988e0a0fba5996630ff34f0628fa3398515e9888d72125991169b1c957d4777445eccdc86f00c871ccb28e68d5211b3a9d97f910d5ac17451bea92b1371d4423956a3670743e0fdc94fc15d668e7f67dc9fa77755663d2ba5bc5289e839bcf36ee0a7ab7c0c7b3b6273b0b95ba65c30d0057e4272a3dec8670c32b03176ca5e0c0564a5c682bc10719fa01d0486eb8ccbb65121561aecae76102cb1fd130f39515656430584f2eaa8bf83a31cb928a59bd0c5ec33084323ae99060bd19bad9a6ff4db1302b8d23d957c21d256b11b73fe9c8442a46a54e1a194406a7655556b34d7551d4a873a373e98336b12b7ffd5f1ac623bc89efaa95227444d9402902da3656e2dd42224356fecbb90c100896b103f18127fe06348828f7e95f138c1dda1bfd3b80af0eecdb44c0fe55373848d88bf6773ca637f18331816c4e1f514adcf5888885c4e82cbb5aa6981666dcb083a28a5528abce836ba58cda4ac12866c25a53b439a35325571cb418c59cbd5f4b0a14435fae728a6c22eb63ba21f0b02ea2c88fc6931185faaa8bfb170bd997c49fad6c4c10ec4e85af1a8c0551b2c071552727596e7a4c6383ee81591c8d51e04b0348e40668cf0864db44c470607b66bce09bbd9d49aca8af8422db542406249450b70c2a88b5474aa05ac6f02541531b1a3278774a52ef50243b7e684e5cf89e21967a60f66f59d95f665af2a46132cbb3a40df1fbd2597b46d04ac644b14d8d44edbe6ced96b750c35d7ef65a705cdb35782dd7817a771cb830a69582b64ec18fbb470b69de10b744205b2b716c1a45f84b35602affa802c781ecf05a855512adc67601ad6066ed965e7d09c66d4aa3f07c1b3811ab615dee36719a67fdb391ba28c101822f0e947fe6c40e29a2461f883045d5236c6acf98c0d4e516d92bda8ca55b8e86305f984477984b78ee01a071e50aadbc6d8ab4e18b65b40a35963bae13d0d8d03567c6265cd69087cb48255b55c8d084eac238b3217c5ba8f431d1ee73956585bd296b339df433356d3cdd003708daad999fe7548a5836ce2cb614013208e2710719fe7d7cc959e5ad28f9b2d2fa8e6005044f000c636eee67ce69c2c488f9059dcbcd6445fdb0582467c26e8529c410a3a35dacb2d4f909c21033f090c5909f5cec4aceca0f84639f6fa8cb5592bd2d98dec5c945fc4de62a410d4684fb0cb10745872293a626bbb63fb4d5cec198789dfca975030edc7303d840b4d270da1e501a54704f93d6ec1b760d006e107ddfa245070f3049f423f512795b690beb048cac6ab104e6d8110a3d95668ef1ddde484f24866e74c6d05234985483dd58a2883896e0a096d090b2ccfc5743cf49bd84912e521a93345511cce6733dbc0cde1447a1f17c7d970279fef0113a656fd0c67090c154ecf47f79c15d315f5bc5f4431880d4bd71f733a54e1f72374db709cc62f6fe04b38e6fd57cd18ff31c08c4904180dce7972eb2819181ec8033f3cff01bb91f8193a858065e1d784f1258a2341d823856b5540c34f8bea03c9f184648040b4e15a404f17d7a4861e0d3d06472b05904e3a09bf5c84baa6be6db017b810fac420fa7593d0fc364d40726300897a58b4bf0379d470245036ea5842be219028d27c120ac55cb4dd390543216ca982372eea7599706757bad8b70de3512cf63e37aa5bf7f18c017c047a3a40db8949ba7c75981a12cdb6232847eb244bb58e5addaa71491a1c38d7873555d1195ba9bd300bfd56d5fa4a39b577f4e8768b08c820f17b6e2c83f881998e108488ffc03be9e18ceed0cb1e13f768d62015d10952be1042d612e023d189e7261c2fb4ff6d155e563a330b5b0074dc8c2c702cca6257435070d63781ca0f9e6cd9707485ce13a144ebe98a8671d8cc4e03be923d102034a14d5b3bae298de44a9a3b98127742014a90bfda0eb4c554c4125b5165c8ae33bbc8b061e37383a01311d55669b99a4900ee76b2557c14caa389dc69fb56046612bf1035f44aa8d7d4688b85a2f272c74120f667e81e696af47b9dc0da3c1df39fdb836d60bcee929b5775a45c799fded0457f4fc00be748648df675fd1601db4122ebe132aecc9842e16fec36246f444adad8618f3161b71ac1127c22300d35a323ae0f85fac514c2e2cd319f2457965303b24639825e55c98463ea021693af1df30fde2c8ec6affadd3864e0f0ad06b9168b0d0c14c7a5073490150ea22b9f87a9f36981a3c68e54a9bc47066681be04a5dee16d6d4aecc8bbdfec2aa01a8d6159c7b99a1f5194d3eeb4c6fe818d6ebdc5343ce0fc379e6a00b9a1d5e5b869480eeb868dab03167ccd0a55ca4de06879308f49daa2f715d0d6c97bf50f4f42708ca49380172195a1595a672380633b6cedd1b05ea060b6ff7049f67352aed578b16161345c4eb0fd44a42d55566234916a2d84a079065aec1450dccbe353ec376275fc8fbe3856e95a799701755d821cfa047dc05dc734c5b62acc58f0523fe0f68effa2755d9329662c1c67da38fb806348d9f06a9957d84a7a7d905efa582ce6212b564d0fcade56ec6e5cd899bfcc1f6960cc5e12228a757992bad2ecd074b3605e912c9033c595d0825ed60f89cb9cc2fb14c03d3e5865db4bf2ed76db903c3b8849797558e53497a6cacaab99016b29423b3d399297a093806c6a4b385f75c2bb2781582517417de24e744c3f2289395784d549e3366b99fefa9edad9b67691dd2d1bcc990091e4e786ed8a1bbc12b45a48005d83dfb439985f39e983a89a4b52ef6b82592e26affc2145d50f75110a3f4e84b0484b9fa67c8ca1b323f66e9b1b28e73e7f673734a42263ca57fd68a3f1efb29952f6a68310ec53a18c815fab46a52a375f07253763788165256f45940a4386d9563b9bf00a009b42218848a4f3e77d23735971b941462a9001807f46c8ce58293a5ab526443391d6d07befff21e20ae805fcaa225d336dd0142e9149c2a63d883c6c1aca1789b76defe3e2ef3571de63dda4eb1ec57b86477a5b8d674ac2ee963193a804b78c73b9c5cac05eae8f6b819bd574a4d94d731b6047b2b24684b72989be179e2b241de3c4fc57366424ed7877ab483b1be00b912d3a38fc262bb00342f81d94e1d8c9b432bf09d6fbb8429b73abe4ce58b3ee5d352c8d68fa96aaef56266a0f0b467defd9c0adcc0884683b2e6276280651624dbe5c107a6535980792f472ae2e28490b9c14eb309346d2ee2488d9890a2a4df78172ccdf422ad98502a333e1eb7c77d01b8885a03a13bf84bd46c05b899b0ae87b50f2e46ca2566918feff7bb2ba06c244d7974d9de6d3fa0c86893e3aa91ce4d3ecf223a4b931b6eec80374ff3306e23a8dbdf267979172a8a4d8cd918821926d3e93ee2598c3d03ce99ebea59523b2f578ae365860f99a3ec9b1f11267f878f279d274c0b740a6b3fcfc2f74e60f50a92d0189b9a36511ff3db9c8d28bb643595a5adbbc87cfdd213422562cf307ab0a88c8e528c52612b35cf27c8fc03e41ee9e40a7353d333a1de661a7cccd91da7e5ee1b660aab410a3d35ba4b80b95ac67c4d1bed1e3f8e41be022a76e48f290cc5b7ce8f7b3efaa74136271262b8bea133efd87b7b8b0e40df52f220b0f4bd6dca9eb30c69ea89dd187e94a8b5491c4f2376a740fffdb4ee5c61c202e01f903e8de6658c6fa97ed23ce494472da69e78da422df06f92b944710a521d648d243b2c31df30bea187b2a6184e86b6d9174a35a888c25419505530a81d89cdf0e53284215b7994967971a2a3f288c1b09061669f595e191ab202e53576d5c7445cd42e2876e393ed1d7ef2b074e2f344afc1566fb7d10854ba1e0207b52d13bc235cadf0c77afe27417881ede993174093ad11804c8016383e8021228543858594d17ff2c0bc8850e52d2a6ff939caa8a50fc96d4d8d7294be8715a405219c85f607540038fe8da71d73cb17954001bd0d6d64e478afd09dab1831278e8400e075aec38effc78f819f5f9a9b9626e10c29e9acdac9f3cbb3fde043b5850af8720662b1b2a3d3ec2dad1aef992798e91403c8fc5d004b85075e72cdcfd17277332c73bcba6a5008271196b006fc34b4d4b86d5fa169131f4b0d970a26cbcb16d5ab44635c2110c16c49dec6ea7c61a3f2a4c2a0b8f495b795dc704c8a7a40f7299f191e400004ffd0401221295210ed78537d53fa5a197865acaf5d06c271ba08f664ff4a72a40bde666af7db6122cd1d2ebc1a08ba0d8dc3b0688091d626b7039513254cf367c90641b65f017d654ecc1397cbc380cfe89a615024bc8d979fe4aa3c11ce5073a204279a53f437068b33386c6e6b583ec8a5c538e68d1614fe2c5d1cfda510493ba803162360a98d522644091a30f11153e8123c9d04cd166233a0172062231c0b85c0b0e810f5d68970b3a3fcd4443587d88778e07800ff0fc8650b89148ae7d61e62cb89135f25ade7e4f80612ef765326564dfa6c8a458e6319dd0e2e3713422c52742f2c27ee814bbed56f037fa4318c6ca8ca406bd4119cd983e0368ec684bb2262c3dab68ce27fe52aad9237ba6543b6dac382ec64e3466e2078b5824aa5a03d0c66edf71a70bc8e4b0a6d7d32f8a93ee70df2601cb3ca4beeebbdc0b016fe8c2f29e1998ed8a9a7bc67d7794ae275bc0379ffbe2e2076bd8d882374a52dc20d49220d955009c01dd5f35fe3fc5b0f0f26068747e74e6d410e8bb7c258998e2e1351d91261232e6ab8cb7693551bbdee21f07dac98bd4c2c06f96689410d4871bc4a33aa4f42e4c871c9c067643a19880be554c3ddb2b91795987d6f4f00501f24cc87750508966be3c27f681c35fe4aa37166557431ae96e21d8db35c6ef8a4923aab921ff83fb42f8290e3aaa97eed961bcd54b024f37c446f87e2d4bfe41c79767c6c4842cf002e4b94d438f9c7910c68e858e1233d204a14cf1e28bbf95ca976158f4a2f002ef6191d800840fbb3880eda65dd763c360e25b25c9bfaccb14a09116eaf8907e3a749b9e944f06daca1bec60fedb8940142cb596adb2908927d491a3cc00a5912936aa14eaf78bcd822058cc6b9bc81ea951cba07bccb33ca03d0f078efcf8f944e01337a2e3e1f740a620a9ee6e0cfc181068473be6008e410f67cd134ed81c81d219fe0d58dc7810ea1bab2b3f37bd46ea7e0df1d8a2e22d944c05e13bc09da9c1554ad12043f5e4656e0b845fa4768ad419061f862a2f39677929c1e2b140fa471e01fb5c8f8ddecc13dfb6477940b444f2708325e6518837631837d07399ba49802db594ba2fcde6957e8b1e2ef01beb0486f55834f58a12a641b4f3c1e5011db971be73dfb351116296e0b6d2ffded4ea717492ccd3d4ff85c584bde21b6ff38c77b09ab9517ac8f6c1adba5fecd8e69f76573332436650c19a6830012b822f585dc0e754ad9d5ffb80736f17610d02ee211a1f4b691242831405c4da0f3bb63ccb0b8842c679a9844e1769b406afd9df8f1c185f7a5cdaf27030a8089abe04a43bdfee115689cd5d49709e73baecaccd3c35065e4c5016bf02da8635da9b863921fa74694198797d1f4c476fafb62acdd9cd6ace13811a1e7698817981a511990981c94b263925093493cc42c1324f437a505f79f91c8805a087f6c2bc4014e09d46155f1a07f5bcdf1655e42622f119d89442cf2f04e3e302ca8bdf706f68c6b1544f7b4f0c1f873f767502402bdc1a9e6c4b57fc0c7b8a532e63d858b1402d5342916a118f47b481aa82e62954d6b1fa79ac1ca6e16a1ea4a81ab6c3bf2d6fef8865f04ff8a5fdc9de2167d223ed628d9502292b90708cf3b9956bb3863130d4426b43ad384ffa40d3abb59f05489ae7b4a4a15a03ba654e996213e493cb471a5c2694832ea0735ca94c7f9a2e11a2ee5c27db0ca397367947313c24ba8ca9da0d5202f0879487ac3a0938ae7ab8f4f12c3868e376e283409dd46d7a90a680199bf1cbd0c016a9b1f3b3890559697a64d1f36b1549a718491efe5bf4821ae0db4e7de2c86948527e62560332b5de90b3131f2207eecf27de8e248defc14190016b621045225f40403a16846be7465520144315583cc7930dcf928662522c1c542111268e5c3e5eebfbdfa50b0ba25130525db8a30fad0198c02598a4041a1c3a28ae934d3152c182d08ca21302b81a29f93234f0882c50f4c2aead4fe0a982e011ca49ec43dd89ca65e9fd4e3d8ae4d7e7043d263d349593976b8af67cd9826f28f49649a7682b9e7901ad1e04249174ed60a39804469cd95a9d10d81ed0f2e6eadf5157d10c91bd661c1a805fb18050cca10edc8002c83c12ab16bfb787fa354a71b4cc7276adf4e9be5e474adfd2b76b5ac02dc8e17f325235ad142e4f3d890ca1789b1534bd4800f421fcc0e1fdfee96e7bab63302e20781aea6dd03bc6981d488612f279d149bb2f84b83eeca1a5c1a32cf9791991f6e38c06608db697be973dc1bf697783906b156747a42e02bcec59564899fe6763a52d3cd1a84a776a4675e695bccede27ba13a60ab79e7aa6a6e509fd5616250527ea86a00a3bd609c926a4bc07f4c20ebae18ea8e5ec2dcd020a4025a3049743a162e90292f64adadca2933f8ff4c4496da1794aca21bfd3f19f8eea592600afd480c95ca5a7904745a9561c6b733051e757232b8920fe6b617629719f7e867fcc38d9dc76c41e217bc9cc92443ddbc6650a11bd6ce36e3b20a01c314d244d52ae85bb1d0ecb36ad42eaa5193986eafa5d216ac67e483b1d4c21e6fdc730f81200c5ebcf3ef30da45fedfc2965e4d6841fb1121542222b4fc11d168a2cd6edb567eca780a9cf5c21f9c624686dbc9737c7f5e3339a8442a11446ecb6cd2cc18d0946a30cc4157317bee4e162061afe05d49bf6bdae800e1e3053f01e9438a507801c53c1b59acd5d5c9c9a10bf2fdd369fa574b591c6c7fade3b8f5fa830730b3e37b82b1b4e92b0124ca5a0a10c15915417a206c056744823bbe521968388bd8e980922d25df6f431dd1b3dc3e80802dbadbb6afdaf8b22d5fdb25ed7d8bf5b5b8eeae646da02873b2605eb86785f75c38cfca59eddc9787e5e0500e9eae39de9ccb5166b9818e6e5478f6f7b542703a4356bf004e5b41c5a7cc6efba5ced0f01aef42bfa2aa0cf1d941e833205ae7dbca6f5e232788f00cc65035626c0aa0e77e381e952b544757a815141c5eb6524f4e7d54cbbaaead0aca33bf3dba9ecfb58259107636f517737d3f8501c6410749d8583b8bd11708f7a007929040c05dd1bc763f06899e0540e26715fe3f88bec8d2dd0feceedf8cf7bdc0981296e1fed5ebdeb581d9d85d24fff1dfee8cdcf9f85405405a1d63e7fe4226dd132a19975198d9071affe8541a18b1ce3665d6464f94bcc356210d7cd24e8db6ac709a8a5d17d2f52bd9b05234901c962d8314f4d077a709a0e7ba526852ebc61908b48d3240bed75c769b8895e0f14fc880fdd07e5229373971a4ecc463a8e7130d5bb1dd3f2f42bb7306b6c5e070a849ccbc5dab181bd1a2f3d4ddb73ac1399e133feea459ed8d555a0add025cd11634b39fddaa61b84b875805e3857d092239f4f5873f4fcc2a93a3952131a61bf821231172893574ae9674f94c7ab0a8e061cae60bbb56b6024b51e14b7d31f6eb6aa3a491058502e0d0f4f0572b85100513128d02c046b6d56cec21c8c9aa4a411a32a42bcfcb49d57319ed71a29cecca6c0f6de8862390d7e37b78a77ec196ea8239d1d1b06c16816e58ed2711ea9ef781d30770fdad5d9d16eb0788d718f55863db9fefa4e03d7a213f5b897189c2974ceb06fad5bb6944cb88050a6713991adc5d3f511f64bfc4195ecca2edad235ac6d39b431881bf145b88fab84ec5bcb77872773e783b9eb7646d474084518cafea8f906d0d93dda09e89b4fd7a246d0f36a68448211c4b02852f042d4b783aecd0482a0d70e6180fe838af8e9df78e2bb5c304a9af4d44a80973aa8f03a7325170da19f0f4650ca02e0950dde9d3d12ff0e94090c373e5344ee7de32add94ada20a30c9579bae908d89fb9b4542a730b784e2dd6d878c2852e566a01de3e98465d42759ae35447bbf10c8fa4809f93335aa1b01b0a10b363687bfcf4c55e7995c237e35a1bc9ed7c4e78a9166b38517ed17176f94215b63128c613141f48f11afa0380ab1069ad336cb7df1096234add69ca6ac5251fc48306d53f506426eb0c7d6c21389818a3196efc2448ed07ceed9eb602354a44ef682b4e1b60865964f54a3a601429cfc0e30d2226cdf3ed3236e850fbbe3a2833862fb2562379d215f8301dc6c3b15806a78f41def7bae83827d7e617d80b55a5b11e929376e3917da90471f30c928f0b59a8cedfdcd225bc9f939394bd00cfac11cf3e2c59b368d340451af5684c87cb6239e3280c137ba7f84d04a53fc6829ff65b169cc3384e326e385a1788884ddc5c12d436fd6699b863e1a73242a01b349277207b78d53622521c069e124a2c942bacacd7f65d663cb1bf16d32f63329cd15e81306681e87358473967cd33ee8826e632c05ad2d53f85c73981c9260a01a2c8a89a79007dc1b4483e144ee238ab52945020a53da023945fe074f500129126aca5a5b6036b0705b4c4b6fd9c6ab03a2f91286aad0400cd5db4ba28faab50a7e7f6c4509d413f73e6652a5b41d36b27ab08fbc216ffd7cdc1337363b0a96baa56ae00c04af90fb7cbc2b2a79964e0940c9e86095cca56b40d3931a98f1fd5d8d2e283f3652afb720efc78883582b9c3ee7612e54bd5e0cd2f10829b77f9bf93a7e955f30b33fef351f090600045f5e7d8048e65abe2475817d70a4dc824558dafb7dcdd813cc9f9dc7315177dd7252908faaf23419d14c19159a959d562751c26160e760718d905dae85b95b17690c9162cd6ce71bbba576ff5b8bc0c35245b3c5aed8b63f3d2e8358dbf3e396e71de18af3e934e5660402ca00f0da9701fe9a9f8a0a2b48521f3becbd7684410ffc6138e073aad52c8237a2d18691a7fae91b780186c8a2e2c1d8a614f36994620cc9960dfff9c64cf8d9f653e84129ec7483550c43e09191c4a711496b165fee52f9703db2bd9c7827e74e54d812a0e5b11fbfb0f47842475abb538b7d68b128e95469d5b53fda076b44bc08cb1d0ecf0d56cf498257e8d611df02726377a3e98225981bda288e5c830be82eff9382ce3baf58829b164cb941d2788b4869eb2e4d726c8c57a372c342d50672508cdafca699f039dcb9e9976f9135cf88d24915b1a82505eba34adb37dad3743d1e21f1cf69a8edfec93e9ae17b8eb50e72989e36899bbfa8ad67388fe954c987a31625699fc358348d7379cba9899cce1a9f1fa0edfb01a39ccd1db3b0515f929705ea91cb0def5061a6f146cc56a8f92147401c8aaa7afbb96b2f8b02bdf3e28a141efe8e080b9f4c90187c2aed72d33ff8270d2ebbe915ad3fe19d60d67710ec7caf0e37d0ef451ff76e00f9abee414e0cdd9d150f2fb2c846c9057cc0bea80a21a0dbc10aacfb1e15877e5ed5bbed932d34f5b53aa29990294a4436dbbbedfd3a14b92042bd7311a8286c55821c71bd4238b54ab46b58052c850ab5178734a8eef11a0d5834e22f617984fe6bda844a90182b1847a14547ab03b18e552f28f1ef885f21c23a44741a5473b1157e34753bdb9eb9fb53cae4fc5085ed9f34a8c03e597d3f71ded7ea05262a0c29bbe11c303a662ea23597ecbb1d90e7e87014efbb5eda763c60d7e00de3c11a4e05209721227894a4607aeb0d345293f540abe61af357523dac4a8183211c93c88be70d324c390ed0fdfe15ee18144fa11016c5c2f5d6920edbfd8d12f17423a5ace94b535ed840b6985fc80a68a14d3d5518ac970a79973a990a87d4aa664e87834aa2766713ad41edc85ef9659e504cc99626012ec0e2127137096e4904edd1e7eef44a0ed16f3a55ce1f48ad06b78054ea818a72ce76623fddb460a4d0dcc056b5300db058ec0451ffd91624d047e6f804aa8c1621265d84263f775209f25e6a04be2bfe3dba127dfdd2423ce673b187f0b2af791025003dc221aa1a0ffb180282e55b6bd028bdf6919b6a64154d226f7c24a3d14cbf25ec66d60aef96bbabf19820d0f9f935c88bf2c28b2a6d29ab96d194c5a6e02a39bd14836629d0409d730f32fad846ea64d5c9adbe9b6a41cf302826497a2bb605836177cdd8716435d01fd6bcd4d3cf2bcbdfb16dd5b8dd94c72faad3e1e06fea6065015abc3621e71fececa9f359c608a85085d84a6cac8c78fe7993d23a75f37c390b86b1182f92987ef3c8884caf1d71da327dbc8089ce2d578aafeb000013cd7c38ca879c62d442a25523627420c0509471ccb3c66543780c962cc8d7fb87b9d8730fd00efe21f806b5252a41838bb16e2d6454f747da4c329f03f27fe1ff34442da8b899602ec124c19fca9423643b09e487fdd10ed257f7a2177bf7afc9ad1dbbe18800791a965e55a528c433063a4dc9f90dec4a51128f7900bc90b1bdca0dca45cf610b657dd897b055a1b478e79e326042ca212eb4b314e6726db888e3bbfe407452d201e610c2bca69d580fe55fcdc0e1f90676892b1255c5a65d716222145c9ea4273b3e1b725cb33708331a3f3d7350363bafa0c24e0330d92d7514c3633bbcc7b0e45abd0a957cadab2f65a56fa8ccad50d3d2f86091d392123d9684cda1e1ef7e27e162913547206d70dda236a302c8a104837b1e4a6f22a8102527d3e4869db0ea03fc4ff34fee564b71bf784a6c3b0dab7f69ec34e8dc629ff62581830e6290684041acfbea00c8d04176ba0a8127ec1a5c66584594eb51604ab753b9240516e14a563e75f285cf2b093f422961400683daba17e4926bb9e2c18b928f02d39a044599b0005c0a25230b6122024e1059a02094f8792eef5d2bb4edeb1fd6647dac018586e76feb2eba6db812aadfec394c7a50ad3880512189d9f3b26f30ef33771ed3a826d65286d39eef9b46c409bd150769e1da02b1f033603af6ba75f1d09f02dfbe1d3a2cb32bd4e9cee44fd435f7a870c28b1633290fe4ba8b1ee4ba1195109973315015d7cb7001c3ef242f22a5c5b0412adc938773559f7439cdce4356f901cfff034648b76cb9485b4dc0baa875182062627e15703e36cf1c021e5796f7b7f5948de6d711eee38d1beab86e689b08c562ef263da3b0256a090a01cc7f29986ad2465984a82d2285b29ffb8b4d1609b6977c313f389f0742bfca305e96dbc52b9222c2fa96455c4b81c6657e0cf32b5307a4bf84dd7ce2b78f69341434ba5c73af70b88d46ec9d9ccb8aa311e40e9499f0641103a346531e0e705a4b00d7eb6024096e47467b2fd340cf009d0244931a3016cf4f3f299ad062130c7b759ec0b455d8819532bbdd81e619ecd52ac946b791cff8395df53d0c43e702b8f5bc7fa23e2113f6df8aa4a260a3c0c78773c43b45474e2b8ad21721a90dddf1938bc2ae2d673932d854a82aeb2f2f9e109c0882a224c2a29a1f29425616a970fd6b1171bd9369a14a541a943f6dedb97d523f9b76f8c094f18d9d14d908b641a74a175b94ef9176411bd3af459057e7169a2ebf0837c465b39b1bbe5b623a1f51523fa5fa8422f4ea8b0a0d2a810c238b0992cc0c17ff41e38b80490b987f0a4bd35b0b010283d61ae8f8aad7325e1fbd949be78c3fe2829178b047fb31dabe020c816996f3833636093f50a58c74398f0b2096bea02e75268c0f3875da06528ceacd992c09214e9cc2b5172b010c1c7c5c4ba648de01e7a9a65e170a4ac6f9076a129b34e367b8b61e2ce0ee576b620a34f4aeb6a1e0c5a0f8cac3f166ab29e930b0d0fc3f11a46360b8e6ade77efa3874da75fca5abd5d7783e253082c5c7d28748dd17e6820ef342e525c48c4574bbe38c371d80d6a7ebeba9064219687aefd1a0a8c71655642203793889aecda940ea85b96d1dd266a0900e06bf6ebe66e027ace0017e9a782805bcabd5832fba43c4511f1496962b1cc531ea511d2f434dab7f3f1728813d7959f65533f878b1c1677e65700cd0f886605058d8ef71a43ede73ef200f1965cbcb5970920e77dc8d9db47bfee212044baa074fc89b337fad2afdd509219b61104f4db903526344cb1b000951ea55e99780a0b177cc0fc8623130c40e044174d6e055a4dd6b2fb42de21d647f39fe081dc22a5f5577c8260e031fefc54323b8887c9baae08c4643b0a8ea7f2073ab3ef8bf556a0e9864e8610bd2633b411f00d0207d90503cd684c2c079b47bac495f0d2ec6e0d1188a23645e91df49a3ce4d59922f25e4d4bc3e4e34ff965db18f78bff91c27e2d7dc8b33bea9186bce80eda2f072d0f4010126ad4527ac06cfb100f00da150022fdd9a552acff0a5398e38dcfb85bd364eeb87087cce3210b2069a61fce68fac169d1e3974ae5e8b871143cf16bbbaffa7e27857c077db17a8fb0f81abd21db1b3f952d848983d995023d2510ce92a1f7a1d10d40ea4141b426acb2cb274d3a051fd02f04b010dc0b5521d5519eb2bb1868b4f3449ad131e0b93f8e67b11cfd88da7d00ea7c4d80596ec2cfc26bae226bcd6cb5aa7cc828c8a17b0c51f35b320ffa711f0bc19b8fb87844d5479904bad7cc0131b9965e90585529015e128723266172ce89d40569709989f34d0bbfc80e466b7130f679cc2d66a318c9428e619dfabdcc2c116539333ebd7d7ae5d8034626e7d872879628bafae12cc12b9e4107a502c5dd344d6604e03b1c9f20056bb255a2fc972aff986b3366dbcaff5cb4a3dc27d6c2972e18e64b47760c46c731da94c7f6427950ac7975ab2c4137a5a38548cc16520b79bdc74320c0c4ee5d05c8985fdbc0178e46291829bc74212af80158020b35b46acb10f4bc1fc1aec672e169bdfbabb2480973455af4b98e0eed42988cf5db15dc4547b94aae7d0933a58e7e0c62f1e1447d255bc564ee1a6e2aec9fc222b69149cf45500bb19a086329d780b442a24ac98e5d9a98593f2142c97713fff18be0d33f69a325fb7a8e09888a0d411b5dfe1daf57ab1da01b21f95991d9ca3010bac9420123142f3ed9aae8bb3533b2beb0c6cf5a47266de9f013a19e19ba8b75e052272838d81becdd34c488c088ec856200c94db4ac655f98e475f98b6d0d667fab96bfb474675bba5b7c348486cc542ae8c314f522d3e6a648e0da2dbfcfc727636a34484820de1b1245fbdba5284254dc704dd140317a99ebb209c3c4190fe837e0a9bacda2bdded31681c1976a56912efc9aad35f5eb945fdd341d94bc06ade6ee631243d59aa8369c8ad8275a5b2637cd7ec522a3b99cba7dfad92eef7119fc33c68feb71949925ed195d5140b47e9c2c0debff9e4a1a96ed25005889a5a3dcc9d0ef912f74a98a71024d3b57488d6f467798efef8004f17335f905a6042b27174cb0f3ff70e0ff4347bddec9100623a069e82015359ad1c8b008ecf75c02359571a64348caf4177da4d75b743b3f10bc24776711c0409f8b4d40ea5682a0e34027f3e75ae85e786882d7747b7e5e7012e32430731776aa14f05266f43b375468a52e83e926d2660b5e8d299249dd197aba85bef1e634db6ebe9eaefd0ed3a938cbdd48166c6cb75be3b3c9a49ed2c8076da9406ae30b964f3eedf92eeb97e17d8e1957292908997a90c34117fca37eb6f309093acb80a2c957d60ea26bd8cbe1e3b06e79ba99a18306eb0ed8152572847c27187878c6564e6c834bb6cc59849aaeb814d0eb22d33fcd193fde201d383afe17138fffea71605a4a30578b1a2b5cb0b0a4405720d6568fe3379bd68c58cd907941000b6bb03255988ede0148d1d0c40af65c804245f20f62f7f5a4d488f80db71b18f97ee9d592ce3c96982bea82fbfd08e877c22702f980b55428796925ee10281095129c9c851fb642c2ed9c9583474e25dbfaec645c13dcc4928723cc59471b9e8a03ec98c026a2e24b75dff0321693dc8a947c43a4a1b00c4d8b0d132aab4ddbccac38fbba37b3c0854e0e512d263eeecbf1da16bdd1b9b0c10294226cf350621bb37a980ecd37e63ceaa308c3c2b9a7701800818d607227fd02b1fc11a5bd2a0a468d807ae337133537db20f1e9b0bff969f241dff4fce387b4a9984750b09d9ef2fd14b3cc06934a9d874a8ef4201fa1f45a2927834246fba5f825b164132add32b5f824c0e9bdbf8ad95da535a9b392e3fc1d476f3617f58f34e92783dfb34ac33dde1a6a223aebb66d2142098775d82788e5e30f4f08f46385718d3676b9b8291b924079e15cce146ca885007d263bad75b17290a9617dfd5bd32ad616edd80eae20b2682b2f12aa8d24a84cb48355c2998b235edcc0abfbcb938ab128ac40aa043218e22035952504171dafae1e772e6442c7a4aa2adcd4066c61920d3058b647c74685cfa6b85e3a24c926dad2c25ec945ce0a849cda6c0642aea96a4f39f5197db3828ecd3f1b6970e14acb17195c7dd14a8ef5e5d5ea33e2c1d8ab4ab400d69aabb49e21c665d0a8d7a3f6b6d34b9babb6eb61712c098c1bbf99cf86f7d4a776129acd8da0e3505b3c44ce91805b7c85b9f7db3e692b358472a3184b1a8300a7c872a593320d87aae2604dc37dd141f8dd30aa8ee696ec3a0ed87860af25b9815024e4d623116af07dddd840ff6874c7f9309b40e605a9117799462b03fbc6009eb7b2bc0c80e31e89398393df1371c2730a9da598230c6a33d74ca46586e6e4a15e8581ce6c758cec6c13410304a6ababca34b2f2222e833996066ee30c15885a0d209d4539d5c1649a01af7c047d96b06bcf179eac6ac84c40e2a7525d072ec6cb3cf1afd4277ef8cd171eed848ac72c75a88590f18537597dedb298cf0d89efd2b544949ea6375cec96dec66d1b64a15ff7961844f6c5da0be5be9c75adfbbe8c5ebfcb5dd9e7008938357a00c0a97a55b105cbb2e901f9d42e61d37ead65f6edbc78ab95e7ce644ecf479ad6da4d0d3a2c037417e96aed421103d1481b3bde161ffcb7d717ace7224ef92ae8c7490a840741bce7edf8f4ecb8d73b9e2229b1fea44c725dfcf608c911a138516e9be057c6f672bc6d5881abe68ae211b2765c753195ae9d5f836f000a7ca2376c33a4b96ac606946159495a6a7eb206567ca49d361211f684f3730bc483507c76eb469463f34717047f581ad9094688c0a4e805c066bf6ff4b7496ec25b3e7654e4503ed2cce07a173330d79d3ef439c5e24b485ff918766966c3f0417e2b269a42aec98758ed262824461b2461190205a0f64b09ad0d5cbcb8a5475b3a102071c788f28d299d5ed249e8a31191483cac336c9b669d4b588cf6ae8cf6c3428bf9ef121ba781490bc3067fe9524b49455d9f3c63040fc5aa21e2ee1a9c4cd5a4db1e62a5d6096e6767e9d1306ed4505529badcb592ecfb02f535651991028c04684024cfd83ec6b70d7a2abb0e2b809dcc3df9b4030b16c1d271061418328008b51cd13869c8fb8e3dc55fd910cf60756f3fcddb187406b9c936e2b328c725077cdd3260d6965cc4e625a4f7537cb4584c7111c7769912dccbd83901e1acc0e85f62361b5931353991cbd153a8e651e3cd2b7e0d79aef4fbef7d7ddb866042d40dff4a8438c8de185c7bd9fb07e9fce07c58ac019b1e3c1815b755b2d7c60601d90d4ca6e2765429028c79ce84b2c45afb8270bd8b8923c0b0e3c67797e283f0d7ffff3b18f3141e19d502c678c06fdd096e27a72a4c36983deaed3955a897916c87a25ec2e9fd4bcf51f81fa70203863a747f21544824184cff1031572338a6376404799a05a81accd94eab18aece2db6cd112c615dd05cb14c81c80c049450d67884a07f2dc27c4d6bd11533c258fc3acbd2220745e7866626ddf3de4d738a9f4c7ab4da342b0c0b1fbef982d8b378d68f9c63bdb1a12d5166d7ddedf57ea1e258da88517a17409f6dfbb7d93d35408db035e7c395e34214e3d2dc14fabdf7fde8156c51036a07279c5b304ec29274bb8a9f70fa3bb5581935bedc72750d77cebe5f39e3ba8e1bdce16d9e025e32a8012709ee806172d9f10f45c0418511326320c4fa324dbe4880612983341679a985267fd89707d8527d1fff6e8d10d2c82664efbdf70e280a1e0a840930c78c59a80b62a4b502608e79230e608e1f2feb80d6c6ebcefa0af3acee619e1eb1bbc7193a4269e8c527cd13a1b779383a217ab7ce457c42fcd16c1e311b695de4ddcb45db6d6720c0c6b9c9df968db4160e329b3bf57ebcbfa4ce6cfeb6c96a90f46ccbc2f0177fda09d9b97c346bd0883572d3876a1cc21cacb3a8d038f478b0bcfc25b5f72f7e75ae35a7945dfee257e7dec246483dfb4b8a469387286e546a4098c3289e039863c66c03e6983b4e30a2b2f47ad387740e610eef4628243595576efad0eb10e6e8de51d1c93fd3a7cb545ef9d52361f335300c7b2061f334b090c763c56375e871f93a244cb3363cf1d149f36cb98795a1630c317f20c036d2ba3ec8ecfa4f9b41e69765238d87c836bd6d9a35b803f6b41defc295ff7e3ac8ecf889236d64786f2da59411e390b028a594b2fe7b65ffae264f218456be5ad2fc6d1d6f83b621b8b5900cc3d58830e8421f1804a70f4f4730a0be908236a195d2dac319564439a20b233988d1240d16309c2963c9059c9a346150a521635cd79279860d4dc66d358c22e387fe2e65818c2858c32832ac20430568220c5022d10a92b4e0c4922a59c06012060aa048a92a94a182242790218a0d3ec07084909aa72c672c21250a2e5e384305031479840c22b36a99a6699a96a1b92e4dd396ce6c9b1018509880c203d5192918d29c5a4b03050c67b274c185a9cb134baa34350d654bc21862c9942890e8c0c517225050040d4ac0449168c0e862e9099a23619041e40c4593c688a5336184d11306174d6c2c90a9b77ae1620b1446b408a3045431c9174a645f988005321998a1f2810b9ac4926c184575c58c172e8e6c2172132509aa245fdc400535b940f24510934c060da3cc983133a6bffbcab4c59831669a78610506108b1880507a6205438841128f98b981c8ccc28c1066aa68f18217fcd46c3ecb9ed45cf5448855d100f25476b1034eeb2c0e2263ee26984b69853bec2b26a2364308fbb26bbfd5f3317d8ca0b357fc11d12eca1e44b63db775d123a26de3a471b26ad7ac5d4866f788b267578b330b072150959202510865072744d882114228699465347921a55bb4d2e811510873c4493d1f1ed1942f9af952096b0a77403aa394a14c94324e554899a5c7434e28e3a39705dc31e79cb5c619e7a49389c639a38882461169a54bb668a506219416c2ac07ae669add2c948a4f54326a3acd298aa5669ad5a49ea864d4749acab40c4a3d51c9a8e9446b56a59ea86414ad54ea896a4221a594500a0a5751cb4cb1c01cf016098ed64cb39bfd718a5154f2494ad19a6956fb7ee054748aa2924f35d3b2efa7e154748aa2a235ab59748aa295fec0a9e844e7cf07a7e4e5f73363114a99a594fc548239ac1417532f1b301c29b830aa8c527f2faafeeccb060c07cf08d96103914a43dbaf663111261d43d99becd0b6652b34a7090918d33053e1a1478251432a645741a34074ca7c7aca03f308da699e001cd2324da2b20ac1c5a04c0c9426970ba3b890eacf72a1c4059718343504229586b467a7a2e5ecf84ba169d1916c9a83cc86c769e8f91040c34c45050a44a79c555512425855359451c90ebd0a7c3094e5532b36082184509b19ad9566134208ad0da2b75a17cd393728a5b666eb0f4208a99cd375a3a89d84c10975b709756d47a8ab7584ba5947a85b7b425dda11eace8e514ca82b3b36d1f013ea6edd84bab0e39c1342281b465a63765d383a68ad74ce154c08218410c2292d9c70bee69c52374648e7dc5622b8351031030b6450a206254f3811450d468c4832658816889043087141892c5166b85ce1c450e6c2163c2c21020a0729276503a8c6508d99ea32c605635830446c61cc146354101404617d869bec509651207728ab95662a197c86e1f4d122280852f8798e074f7648a4c90ed96fd770931dd20ef1270488541ab2df30938e212d08ed7a1ea2f834f3278427cb2368870de40ec11d490d2f34a3525b0c4df8ac4f95740b375b70e1a59431cfc9820b2f63532c30071052167167116cc195873b64cb4f5c95608e08c54d2f930a0be1e76a0821a4ffe69c738a39a71415fe9b734e0a735017048210f6dd9e70ba7ae274d1e4e69cb4e10aa8a45a67adb5f77eaf20087de6617e430dbac805371e526abb19c58df0a3dba684fb6174523a55706dc3a8314b3c31e604ef197384ac32c68619269d4e8c5902c5a4713284182c9c0c91d3304a4c97179021434669cb16366c5165891e46c47b5ea76494d2a9a527622045142da0d03054896cc142dda2880c4454326932326b881071d3304a8c11bdd3304acc1315a7969f26b85fa6be9421f365ea4b94724e4a6bd53129ad35cb344bad9d32da9a659a66eda659bb6dab15d7d1ae9b3276db6ac5715de7756151166bcac8e2b2eab8aef33c16abc56241b57c4b4bcbdfdb4d6c23addcd09b9b29e38dac2261f26ad44824b2498d54529346aacb172f5da4ba708956629528a54629f18954930696a9653ef079203fd8e5f3408784c97351ca3929ad19cdb2296316e59c94d69ac9a8d19a659a66edb6a2abd59471a5d96d5bad38aef3a8e74d19bd15d7759ec762b52ebd77ca783d56ab75af8dcd0d0ec5c19932e2dce0b85c39393468d478d1d76bcaf8b2e16e7070ba895d1e08b15f1236f109b4733c1072ba8969c01ab4468d29630dcbe2f1317b3ef687d413e6582bbd48983c08379a6a81394e703fdb5ae08e9c96af4d7007ac4e0618829387102e408b10420821860459c44861218b1825629880f89159f4e1ce865162967ab8b261949821dfc54c1854f5bcebf593c1808cfefe339f7ea815187431afdc551617062d4832b3689aff45e2893cec3d302df233e81e065894e8e07abd4069f2706fc328183c350c064fe6d4b480a245136d880e3be8604455c60c3334712a628cb8d48466e125cbb2ac669183992154b0400c5392a18c052d94322d9894ec20a5699a0e57d3b0b841fa402cacd84b801228d9e18521674c118338040ba88a452cc90e5946352c82a85814b1b4c3902a3f557aa68c602187a91f5c9839ec348c9a7232b504879e1965eac8549139c534a51406cd9130655c7012468b262761aa30e2248c1461a24ca9b4560a258732d6c8d04512481c31a404860b0d0c18d7752f09392c010410506081e24915982a565a1461a12006532aad95c22996f8e209314fc4e8a18535608c5430501ca9b75ea1a62e69baf7bac210b1c31565ae60614ef14087261bb27c011304d4503d03cc11158c0992541e6e28a50c0053821598254d0c00e3640566880b538657c328306284514225108f0f696357ed45ab67ae8eb948fb8ae29a8ba6b77ac51b2edabec23ee4370d7f49add94c63cf9c646344c17c22e374c282294306cd40d1f20512499cd800859a39e73c921d3f67944a4a4a4a4732cc8c21869e187e60f881a1c7e9ae1a467d49f385ca0a30ace8e26659c6e46699154a481fd89b155da40feccfdeb6620a2bb040329b5cf1735f3f2c5372b586515570e9ef875511357da07d4f1551aa90a1bfffbcae69dad7dd9fefd5dae1764dd38e5ced54cbd60553d20792913e3048c80554d207d60d5bec9230146c80810d450cd9e28392195528d92a9a94c05e195d9dd63b7de8e9675b2ba3036761eede06e3d89c758524bd0dfe6877f9662a61347f498d93bfc8800b633520e9f91c353def3ac7c5aecedb1d0ed6dccf843e9a5de4fa3cf444c8b9f7e1bcc667fe681cba8a5aa76fe1da14df2ad3ad7bb1127ce9f99c13b13e6d3e5fbd1ff4ad1ff7f8a3ddd970197210c0f9fd6ce5ee75de9c464f84ee33f3709f679d621e2e13dd73b739f571cf9d953fa49e36b9c53d0b2136ce6fb202865c9abd1f386fe5229cdf5ce4bd7524bb958f64e3e42efb886f3d7a445e86af7c343be7f4adfcc1fcd1c847b35da739f98bed72e14f48cfd6bb731d6ee1e811cdae037d278d9e081ff7d6bb4c25ec3b9aedcadf0a6dbbcee3b1fac4728ad0ca54c2ba73f9e68ffe687697bfa349654fa0ee337f47b3a513775e5e4876e9d2dd295e7de20fa9e727eb1c0b7f2974eb38e720073be9fdb867dd06b7f247dbe62c0c25cce6d1eb7193bfa4be394da16dfed9be67e54ec25a17923678fe067bdd5918e7acdb642b61adb3f047bb75e8fdb0c954c25a792542ec2e17ada447b4ca5f524f1cfc659f581361eb8e420964f39bbf23798ff3a223d938ff5c876fdd0643096be5ef48f6fd77248d6477e72e2eb2396c0ec6a6782e5602a8e6b8d9410f049bfc09699bb37ef19742db6ee9fc1ecafbd67530943eada2351d24f6cd61db60d8f6d3eb111b270789ddfd62d82e7c24896477b988fa88e7ceddf50ee3dc85897058f94bea5ffcc5beb90deb2d6cf31b7c59d8bb8dfdc5b2b9d851fc71eff0179b87cd3b7cdfc21f52b76e83896e8612d67a47bb0e73671db6388fa8cb5efe843477d87538f68ae655fc3c4aa1436a4a0f3d4a673642eaa3d831e6747c0d79bfa04f9420899a31c87c212589288e78a23f30a9b706608c22ae009344ccc816a82369e8113538c49e5ef0f3ba659eb0e8ba3852a728d19242093dfde2e48c2bb09082e2a2ca962bf40726515346a8b8a411828b17461c69b24d71ea1ac69e5aa0c36d8d7452fad40492d85394112ef4e98a12b7b00c19acd8912249bad45b8d4c21e9628086311ad6f46d18a3c10b321905f3a5bf7fb9374d84b9341ac6680882aee0b61ac668c081b2204683136ac5bd6918a3a105155caf618c04699a0454596c4a98ae0d6353aa18e21533221573814c9922ce50c2d444ff9edf8c1319265b921091aa41cb54cb8c121a502021860f6188b1c3154395882e5d2c899726daa5d53036c50922b22935c450a7286942cd6032c12063246629608c70c90d6352a0da6b1893e2837d2226e509c60eea0538eaa48b9329b4a56ce93f675cd3346d8634358a528dd254a338d5faeb625aad344d5b729f4463f284c9d38f8553df2bcbb20c8a12d20776b153dc2f2f2da40f845206d69af6c35429a5558b413993699aa6695ae682c6f49f6c053186a718aad417b8bc2095314d891509154bdb8603932f8c0061354dd334a9e903ad912e90ac564c61e212271903550c69cc60a23ac24292180a4c30840c4a456ee68299e9d4249748fd4c19a6a40f6c19c8d8fb1e09d3344dfb7b7eed9fed980c544cda2f61308dfe5ed35cf8ffb346d3340d0625a40f6c18bad8ab691a5396d11f622f78a182ad844b1225524c4b44cac54b37998a4274166b42c605da650acac49719a79452ce4b39e315386ad470c6071c4cc48a90e923d945aa348c3191e9988d3e6814de10e6c84129a551b2c22139a91377524aeb51a8231099978f5fc498bcf4775bd0a2e75db116caf4ece969b36c0585a486431991fa80a463387deef49947c1892b3fbf4b75a505466c7152521a8243578ae851a059041a48266ac37960c488541d89b5f0c40b223122638ad0238844b5ab618c881538d5f4f630d2dba802a4357d08406450064e4a4a4a4380608c8527fd71a0a3e9c4e2037dba02634b4d34ace9b31ae9d253d3209a66e9cfd514ce202a7de2e9ed855332090ad52383885022d9895c8967820d3da9bf782984e95996e5a2792ae30438288130070f6f70570611217285e967a81e66c8f4a12bf4490dbd1eb6a906544262e40067255052cbc31d19dc611bfe1e19697d64a47552438f47aceaa4183d408615306c482021c30a183624906c0045005d74128882d185ce6c2da4b1214c74d6303684c94d42911420c22a85522c95d35a09460baaf1e4c51866383571c61243110817861c691a42a408185c14419345139a98521435cd94561a2b4ab49ac6c9437226960228549090811233c60f638ca18db10686334a6374918d110611a52825aeb84bb5d65aa5bca85be5a56467098e5164694c12413cb992c5932358c4e872c5f8c2033d4dba12c391303698a98229053e8861a525c6961766e882091b9cf0b266cc0d3d88d182184ca0d888a1871c4e20a50a1dca5c996285060c15344bb090504a29b582260b8706892629689a5e689e98700d634a42d840b98e0822e6c30c3b249182072938b0e82284124b9ab26061071d4d9b64e00a2a33be280286142774e88a8605a6a720a6c494b24c21a9c59474e8efbeaaea0a5dbab6614ca9043125253f02380060d0250008b808a302a83252c4804a95333cacce08b185bed6334fb433342039433d8882c3162baaa4a0a162a85209e30cd6992349cee0348caa32a386269e8651555355524e9452baa64a8934554274fcadbad28486ea348caa6a32cb58f3459135655a580306defb9a73aea1a2089a1b144811d740b930e79c66ac01e2755d5d0efddd9fd1fabb61f8b07426022a50aa12c5499a1f7cc8218c285d9f9638a12d545a2bcdf9a10a8c2643b23c85c1218c178c9c0963090b67ec9a26aad59a0d8d111dae6c11c30f4a88bce00630a86870358c3a038b0d9a6b514dbe5a5ee62fc2182d75dd2c7f2f1a63cc166ed0f0ff6e34fd97d3f49fd7f415066ddfa0cb9fe5329cab0ce796219c4111fac4cf53b883a7a5cecbe6ce8d1a51840c2668ba41c30dfa99a437503a339a61f86a6affdded9f9d59a6356f56a3b235258d3566514a29a39410f6e4ac71a12f50c38194f247fb47a9a438e8912b8fe5c6aea7266d099d8c138c32aa920ca96a5a930607ba74461367405111a77cb0a4276ac474f981c9174d4031246d68f92bff9f1f29c44882da920311246862c904b11ae01429c80203314d5445bc94008525630c81260c1250a0787942010044c85c41021ec814e142c3093d989902e6092926579c48808207b62471450b66920881c3949b2866ce78610c274a674429f5abb5d619b3fa2ffe933282a12ec42e6e861a0bfb39d3f31c0895d184a7e7cd68f2f33ac34affc02e3d3fd70f0424d07b9e030914a3f4fc4b8d969eb7315f1ef48cf387edf86d8712b6610bc2a6c11c47b3351fdacd5938bff873fd9eb3f966730873acbe3a17e18e20b6bb2077c21d415edd3d3e9e4220d842b3fbbcb79ef3ae0b627b7b6cb5aeb58783c4c38e39b7bd1d85a4ee8cba1f19699d9383d8ee320712f6e3adb09084cddb600748d83cda1e3968ad1edfddfbfdf77342eb5c766ee5ad56ddca6be1a3d9ad67b828bb4dce5739b9a8bbedd585a4c7b93aeeabb770d1eaadd79553ed13821869dddd2856b591eb473c446fefb0bd5c6414abbacb416cc7cc810bc2e21ff38794b3e11320cc71647bbbd0e4a2d1ecee42b2bbf71cfc25757721e9c23fd8c80101f1b13e1151a515d0303604550f11d5b086b1219ef41052cd75774ad5f45c0fdc61737821074820ed9f0d570e0534f420e82bbb01b7c2f2f224f0fcabb1f3ef7ef6b334feddc971ddb66d5b878b56d06e5b7cd7e93c1acd5cd47df5c3469b3fd972c60f4e7dd00573ce4f478edffccc73cb45dd7734fb9b597bc5dfed9a25210949a16b8c95aae92ffb912ca271213df137bb5e7a44b3b789ebb57ca6bfd8db8fed2eedd9b9ef48fe488a304f43368d47fc51aace221553d70551c4289882cef907b998f00373d634b4472d3e9ec68564d4a24c9841bf9c8512084784559ef8d3c95b5e5d7b46c20c8a4e3ae7c95f8ddef1fecaafd7f042237b692a0251fdfc513fe36999d8c17cccdb9cdfceb37f94ea8bf334def27e745d1fb57b9ddccaf7b2ce6bd4f82b3bcdd7b7935bf52c0f84f8a22d7bf762ade772bdcd3ab9cebff2f7d3d96be4569cf7bafad45c57b36eceeef0a421243f5a06843a2f3473b0cd5d58c3c1acc7d52ffe6accacc30942a0af46d37f96be07ee084102dd8060731df4b6cb9fdd7474cc5f8dfe74348d556a748af71fd4a2b7b8dd5c54df7dfb273bea45ec20bb512f2e531c703b1cac89f9fb8947b51341fbd61175f1f51bfe8e64c7cc63af3dbb09332846c52a356adc7b2fdd9e95c04177ff4ae0a07f5a3b92ddddfb475bbb0d7ec11cf1d603a17bd1cddc35ef47d79d0ef489a73f54f85cdcf154e6af040e7a7b2b7f3f2cbcddcb1fedecd48bd841973f14927a3b778f87962955af3057b3b69f0a5dcfc12825eb1b41d7dab42dd75aa65e44036479ea155fa51ae12261346481caf2d45c8b936fd25e4fc4ab8f1cf75a3daed6ba4247428b7217b29d72b8e943dc3dbcd462d2cebde21584ac4eb3d2eaddbb4c84493b3dcf7c933d9753e878382434271ea17e859b3e947dc34b2d5b0f8734bcf4c1503dc530cb4c35ab404f339c3e51c82aca32b5a936fdc482082296a54b55928258104a3455177ee8d2b4610c082dfddd7b81ad41064d81c0d29489f938a90b5c3c8e3f94e1d24af626d1772f8ae10a574e0032946519a96624ed40b8d7ecf4ab8ce4e548b5ca48d46a07e29dbed6af0ee4e6f51c969c73df72bc02c4f5ec3723d9e49b91329b91b48c44e9b97b4f36f7ceca518af59bac94fde6393962a9c7c94837198995913c29efabdbbc012d236967dd26c727fa564662ad32d2eadcbd3c02d21520f65d46e232d22ae76bc27cdc7274a28a727afd4c61894af751ea54d6e6d79496af5496ed3f18759314a55d524a6a2e762f1df7470bccdaf8246a79327de6e123ae97988876643a9a3e66cb9678b68e06b7514a870b4fd4ce9bf06fdcc83bd6f264387d7432eded1c8fed37b16dbec25f0acdf3cff52f3e290201f6f6ed1ed38683afd4ef481ae7242ea2ef4e0092c1770e04c7750e7532d2959ddf388e0ca74f06b625d28d8cb414ab86aed4efe4781d0cbb633de7acc3865e8fd8f13458a771d6699c8b5de52162bd3beb1d8fc7fc3af478d4b8907ce1cfc5c1162271c71380e8dcc68164709d2b2700b9719d676023c3bc824e46d2f90db8bac43a45461f5455ad691ea29c73cf3977a883e150ac818d62c7cc43c49dc6b9d3c837bfcfc146d1e6d2e3c143c4bd3bf72e07995de4cab08e1e8fd6639a1944052f998b740588ce77be9375f2a7cf84dde7df1dc0bff31c0e11e0d7c13b8fd8023adfc948397a3c12d8b9ce2db093756e01a11b02381ce2b9d0bc81e1f44162fa10cf77ae839b00f09d13b9113d1fb463fe84743cc7edec9c931e09446eecec7c6705211b9ce7366a27b54ec3d80f4e4d420be9d7390f464a1ae239573d1288ec9ce9433a171280f31c7a1568e9e01584fc3c59e9b7711b99081300ae739e1100f0a69ef31c0eede0a60fedfc065e6a3101e03c1b5c48cafc69df2c90afc383938662fe58df727cc4de6f0e32fb8375917c7c0b1365ed9d0078009884e933ef8361f803d3675e0029f4f741a9e3a60f6df000e0a556555555d5d006990900cfefc14b1f0cad0080ac42ce7048fb0a7f45311fcdd62e876cc4c284bff3f9146690ce27cfa78dcf0c3ecfc23630928d33e11fcd8ee7c1483c67c247d23913fe0d8c757093ce7f1edca4f31bb7819b74ce730f176997e732c04d3a87d327030c878e6fe02d7f4793e76876cc3af80acd461f74cc45f630aaa39719b4f309e947989f56626ee9839ab9df78065ff1e41534381cd2f9dfc119c4b4f4c19006e7f977347bbb6d08633f7cf94187e668f71914bd5c1d3ff5c8fda2162a133c10a6d107fdcca4c16dbce3f209b2e59934f88d7fdba3971904876666d2e03a5fe56fcb47b3650e92b5cd5434c82a6460af979ecf00c3e993693948d623cca01b59c75a1b7927d6b59ee6222a3ba754745eab8ed4e1d1c13cf985a5527314c3a8dec12aec601574ce456f049d6cbd09c0219d7ca74f54438fc7083a592ab554a221779c903009f45d255ade0610481a4764023617bdd80f50585a1e07f48ce8920e456ec0e2e415cb0b4c5890b4e0c3181fbca0103b09abd0b3a1801656240cc22aede15618624fb1ae42f38351332ac619ee07a38222f499f25b179b9e9fd7e9adbf974d7f2f9dfe5e33521f2e8fcac2133028d1f50ef8800492b74f5c16748557d0292365659d65aa31380e7a705bd6defb7ac15af2a81192e9af7ef5ecabec8910939e7409904cc77c24916ab5f5f35cc5b2ebb755fee68fa48d5d8d84d80bc988635bdc437e491dbbb831536ac54a9ac72b52b687277b5f363a2b61d3f640f59eee9140966ea150c4ac54b9e1880d312b53fafb4f0b9ea4fcfd8b00e18c2c659499e28297344bd4292fb4e062069918f8305451d0b5d66a9fac48996225ca0fa45694b8ea82bb358cf1102340c3180f643a6b18e3e1052fd42653b6263918a99f0d4770e0014a4b539312b4c91225f4b4491353520b5f7028c2f4248910349c8089199449950b536071ebad5bb68022028acc1157c29880091395499718ba58170f34f4772fb7f090d0c3def32f9139c598952443ec10eb9c86b11dacfcdcfac3323a299dd4cb5d358cf1d0448c8718e5f2f7f090a549052650dc52bdb532a952995c59b203193b6cb1c5153a1489e2de31aab82d3254dceecb14b79392e2ba1ac6aa40d11654d941aaca932a4e036818cb618c1cc0682249149b2215085654117a6a9b9a8e9c8006335600262a49119b6409127ac6eacc4699b8f4540c8b56d151b1c48de19888612dd52a3a2a96e82913978aa58c04081692a822f414490f1409554252820dc90e44febf07378ce5b044d36818cb014b7fffb15f3858c3996803177983163adff5777b5abeb3742acd0993e8af87e2e0454688632c87272d8fc303fb751289fe6c646a2677cee69c4df71b6c933fdaf7147fb6efa3c7837528816e7e2f346df0679bfe2677f2e256dfbba721ac714cedca0ca965d1566bce09e3b80e6b1dce7aabede97038fb8ee6f1d8ce6d1c27b36f9be72356d11eda1aeeb06c4eeb3a1c81b818bf248cdae839ffc3a55f61050cb9f69986b743cf6e767a3e60156dc844d3f8b8fcf534f70ce7df6d48a0968532c87a39af38b9cb48c0daf57a07e0fce6f53f1208e7c3590175af34f26737178d4f2f04d834f251f53182aaaa2aa92ee1a7bb2e07df8569e374bfe96e835bb83beb6db1edb84dcb5db649377196b17ac430c218e36a750ec2c715f7898de08acb2bbc7a9176bbcadf4fafae7dbe751874836c6036f8f8855b2cce831c6bb5c2b023ed819be776aa941bc20c62dd0fc64502499140b06f90401d0fefe7e22d8e31bbb6d2342dd3f20a1b7d90651677b7d923ce628c51b3efbaae7b66332139bd1eb6bfbb65efb68d0c439843cb9f2b3bd7d95b57401f8e8ee7380e56ab7bd5e3e19deb70769bbff855b7bad0f4563a665074faa9435cf82f3e7985307de45bf9b3f65e2e5cb81e09a4e1ed1f88a712887bf41e9f61792381bacbdf649d4bc278acf29530a3687109afce1ebd10a80d228d91242c2ad95809b33087ec88b8f04a4f884b1b4a685711de4804cc2855d727f80cd6a79b655a966959ad35a35419c5d589938f506212242c52aa84c4f510471ef9e8d431aa85244782f4e621862d53e82a65c542d348eb2aa4e57fe098424d8a4e12162f1f9bd2355aa620424b7f47f22b8183ce3e29b594d20be92aa9643dc7cd67194603d04b4ccbb4f478cc1fd48b6800f9ec328b414501111487e26d17b91424a654129664a4359cac4b20994fb37035eaa9b58c83210835cc284c5ab191f6cd4803743502cd5f6c4fcb3dece785267d12443b9d4443c3305d3384396a3c0a496de1f47ac4dbf9ee5c0d5c4f03d7a4bef9c43854ad9dc7c7bc769d6b3c5eaf18def5ed2d1be5d4da6b9452739faf4f9cf38a59f5d9b49f337f499c0782769c5b8c731b5cc4dde62d7c83795e874d63ded76b4c1d9d73d7c93cafdc23a96bfcbec6efef8e07c2bcb5af816f4e03df3c077fdeed5db8c8e6da6bfe921a277fdced85e60ebeb1c145f65772ef700fed36f39c1ac52a6e9b1b554fbbc5a99e7935bf59eb3d2029899e19421cf69a2702bd263da3d83de8b57f34d34f99e11f09935158b88638eafcc41fa5f3f007cd1f124f0ff81692124218a4b9087ebee42a08cee5da70ecafdbb08bc9ddfe759d5d3b35caa53618d0f421c900f9f9eb3a5dbd66587a3cb2735de6a980bcf709c87b39a937fcd9debee2f017b757ed96835eecccea5c496946ab7fc52c1ec253a8696bd5f2d7f576f86a21dc3119b0eae4fc0adbe9537db8df7bc6b8c588a98459ad8370079cf61589fbc1a8a33a1f820370cca9e18b5f32dc78a865db495885e1c28e19c21c529a129628a10ed3226e0831c61863cc1fbdd00cd7040993778084c9f7e8de14ebe80e771206a5469841d6de2be58010b8fc597bef96bfd7eb30d84fa740e365093a7cdcdc900218e29374c42630877c8dbaaeef158bb8dfebf57abd92b8985171ce76360509f421b596bf791362b8b1e351d719764998bc094732e84a2aa957b3dcef2da5bcc49270ea9911c11db17b64d772440708b1e08e0eee881d3fedf3161769405488da20aacfcee160ebddd890401991aee7f1619fddf50a7b7a37ffb2b3b4cf3ee7b3cf6e40a2496b5de6f1b8b9c5f7365acfdee3d2fb51afe52ffbc1dd66ceeb7a3caf4752dbdc8604a2399e7aa798e7e6382058d773f097dd0777d7b9bb32cfcd797ce0dc3bcebd1196e250138407f8ece7691c07dbfc06f7486a9b4ce3e2a25666e1222f6f588784c5fc7559f60eee40814aa02c476b351cabc546b16a6e266cda8f328b4fd87e6c6065bf6956a3210845af47f68c76300784393e160f2298235e48b69098e49256697eb6ce7acbbaea3f1b3bbc7f76459f9dc57a77da43cf51d65b871eab5559b5b26a8639e23b2cf7b318aeba7a3cb647af87bd76a1b9e1795b424fcf98613a1f69969e0f1b5abec862b2e214433f4f37ae9b56c222dc3e4ae97744eb6114fd808b52090e76e0c258124a2d2fef5b2debb97ab23ef3a7bdbe851530e4b6befdcda3f57be8b56e08b05b997a3e608be561bbbaf651fea852296f692bce2bacb5d65acd5eb3d67e9b9cc5dcb76b78d3364d4866759ba26ee7b6c32db397b0ace727b3d80856d5aa652b7afb8a43d0d345dab343099f75f62e890b25ac669a19f9f98162ed4f4f8f134a7b5eaf27af1b3ba249ec8824360d63506a8eb8a15f1226e5122256b7b2590b1e70500645a5ef477640a1caf4777bda2662505f62d5f2d1a65446a818949586b12d518d8086b12d4a9a6b5979eaf1a85a6efc8ea6762189a9846995d2cc515c9b5cfa9a6d0de2d6118090103b885d1f935cd930b60549d363590107250793301c3862ea7a6556484e6dce995dcb2285924a4ae9948ff1f58ed4e883aaaaaa4ec2609d210a387bb8af1933428d11696214353ed9ed96769c734e4af3e76a9abf98a3069b9e4aa0861d4fa92410bdc5100861360e98038f70975c2f1f98d6defb7afdb00f9221e1fb998279b9148d92ff9174e2fb947969ea378c05d1458834fdd3302604136d04992640c358115f3a5a5b3ff805da6d1e7a3e563de1ab0782760a3f614f2313ca6bf81b8655a71bfffdd8634002f5c4ae9946c7cd0d2960a2e3e7350016ecd082973caaf4a8d617669c61a8bca2be10a7f4e4398977384873e761d3476f1e7af247b5635555557bb14af628a7e65adc59361aceee1046ac9de3e2773ba336b3f17675211df1373be36ca49fd9e7b55c2ee266ab88fbca7b9c5efe6473f63ba2d1e622eeabd34af3479bded624a42c66df0a337ef547b2685e4853fc4da2d95a96d5db78fbc52699968b28f57e7c124aa0d6bfe814b97fdbb32c7fd129e372feb47c24bf2d6759f62f9b998df45ce659ddbe12c57b3fe2e94990404db103fa2ccf0bcd9ef4b379b5d730cbcb2cb5c947b2b35f9bd1db65f98b9c5d793cb618d51c8761d38cc3943687299d343675462ff1cd3ddc3dc3f52d9c91206135c695d56ea35dd947576f187634123ba8acfa1dc95844b3dbfcc52a8938fc1d4d1eeddeab7d5d79590143ee7734b7dfd8d777199757af466207d17ef5ed24508fc7e6d4356b0dc3a694d2d6b21c8d44035421318925ef1053dd759d4ba8c46b17ec9a9864cca119010010000316000028100c098542912c8f035d1f14800980984a6444150e235992a32888a120066218438831c600640c40062968cc06c7d6aa6cf15efb8212c56a10b70dd666790d283b4401ca2d5ad676b843b80de83885b0fff6b496b450287d2fb03940b9a5edfcd1235cc7eb090f5e05af9e0e80ddb55e9221b9a3b423cf2fc1c6328a41f1a53ff4ee92cdef7efa5dcb4b5255c905eeec7ca8243e146cf16c3333f79bf7a1968581ddccb18897661dfc79258478454a2c27754b26a6f52e7eed08b25f15b8a75270b85059415056ff99310bf578b27c600e3c18cc0f5aa93a6041e6b68afeb8da1f184e13e471bac2c836be96d12bd748203b38c2861359581b8a953c1991c0b085cf3da0c241959072f035703d45d0d3afe19b71a616b552ac40ba21863774ff0616d76101903231a510d0c32f2a0f3c54fe58e97ecd14dd1429fcd5dcf9dc03dddc1fa88f45bf649bab3317d6ffb410096b3a7fca0b7038b50ca820b929817433ac87d5260bf59041ef8457a20199e31525084fdf5a0305e21128005afc71ddeba585092a6cda5565411fd3ced687355ef39e86b03a70a18d2bca2e429fc8503af4018aee5bf68cc3cbd44d0d4569f3a79d1d077b1045e4939676cd9171c8cb5376a85a5ac0f7503f20ea8caff640513468d1940ca5eaa12173c98e063d93e7bc1cff26a0dd9028c3dd11e7b5670064a90fe5e6732977f8a76ff15db05ec89ed03aaa246e353087766446ce3beb75f1e06fa206ccc10d61ee400d053c0ee279e8a2d86984e6343e4933c72f388362f511bae7097493d0d17343d5d4d1e01a043c8864a50c48269072030b0b852ecbdd622e845695032d1bf2d95c994a7a115420b9694e78140fd269b917c41eec6a7a623be660cbceb563a9c023f760cac14b83d453682a248ed7d3ca9989bc80783a3bc9f3baf59c6664b648daf094e48690f30260dbb135730cc152d34447d3a218b3af0c3af77b91f184d3896c989200528d7c688b33eb27e133cb029d58d5dee8a95684dc530cd8a166220277f8852c30e78cb196c1937639ae73fd2478eff23af9b20cdc2332a5e9af48db22b123d9bec1c13be74e309e179c22ce70a19c995079ec30beb41a592a01b37990768069b164a4ef7643b3d3a3e5128cd29cd9fd002af84eaefd9bb517daaa32b5931b8284bc9d3c2b1d2d8d0915812c6684b9f212ba5a37cc15f1199960db6e486ce20a88b8d0511c8da23688b226cdc5c0842fd096f67c10774ef10991e5ad44cdfd2db77bd0ae5e92ae2aff8d9be7299fd8c98ca27a9cf05aff568510c1165f8f05c154b6eac195ec18149777b6a14bd73454b1c8f8b0a0465f15487331efaf87f0f75f97ed2f04845712c40484e9d27f6f0ef423045421d49201ecdbdb903db2ba846f79ebb293cd76a32734738504ed6c7fe57523da0ae84c619c202e41b8255a45a0bdbb6001cd3d75cae76d38fd6ebbbf6acb90cd3a0f306a60b2637a1a33b4e7926b296c5b8ee9844cb92371f4a4d46d14e04715d6c9797ad2ee088ffb74e2ba397d8d06602833a6a0934b1f74c7249b0d0007095488aefcc0832c8a4e1b16ef74885157804d6e996423d424ef371aa3d2d341b5de1582ce3cbd25b6953ad7f05211a8ddbe159838c161486adb51faf2d41eaa08911afd5d88c0e21e4ae48ed424cba8212f5e2c7048576010fb9ed429bba1c372c8cb8525afd111884dd3ca64fa99e1afddb87973a922d6de849fd2ba5f1f28f043151cdec077ddb1db82a0608f88dcf070fc3ca8283ef86422001f54ddf2733c956ba9716a33ff21d214117d0853f5a053148216e74d1dc3776586d5b67b327d8e45442a369656c06c414576dfbf7f6019f79df604145f407be3fe8a793024bb92804d6a63fe1874441579857d8d5c8be3153ac73ae402d7fbbb61af1e526840a2fdf3e46d3e83390453e0c4b6f0e65c76711e860080486ad7ac862653889da7594261ac6b1e971aa8f088466f225b11f9fc932ca31ddfd89fb6c93f02cf95cbf5e1b2c6f1a808fe360fa0ae1dc9e713f3840e7b21b61db2fe3cabc5989d0207b90bb1f4ab296ed1bffda0deafb8d2f8e333eb6290d59d8f3b6975b9bc7b4e80e059d0510b0a4fb47edfa89cfaf8e281397a8bbf8a243074259a9a05776ecb98a8cdcf3b71fb8ab137061ec2270b698884763e1e2f9870eae07b5bea0046ba15bcbfc16b9e71da2cb7f10c88acbda5448ba2ae10caf364cd645313e585b2c37814c189b15265276d3a13d84c8dfb4d09d61f3870deb64002e656d6dc1e00907407f74b29677e92c251914c1e5e188d085c4e436e20af21de19853cc69f3ba600b2078851142c0349791b9ea6338ee153cb7405cfa3de9ef6623df13e033ef52fa5cc29210a6b66b9af3f9ecaadc62f36b80550cbc800503fe36b140b19b72b253039b6dec6689bd1b6346ed6c3ed6186861a57b352b18e13833fcf35d069f315ca6b8d82b6d7fde34107b56efb7d5dcef698da71ed86e2fc79a2bbf426d5df1530a5f576e4e00af49181fa4a8f70708a2030d8670238b9d50b6d5c5f0b68f334a797598d5a142bfc373378523c571b820844ce86dee05c888add0942038628497feb52cfb2c6276b889f6ebcc4515c07339c573723f77490b247b205d62dd64f613abc4e546343ecc333635b2ecb8d653946937f29607e3fef560dc8ff222a3d71a9f3c1b4a80786e524a347d1cdfda5a3ea18208d1e5586a70d57d9d156237c3cf65d0486b3e904e1a6b34302e2120387b3e8e99ca21f6cb3692618727fda2d6f7f57160d48e4677f19db9319b2c894ad0535a2b5cbd7a22a211c49c99cd9ae76edeac5adbca24525e56ca667b234e154cc7e2a411658f057093fb954bd3d90650f64809518bf5b5c9c40da1560652ffb1b7af91d0b46644a6caf5f293e68fa2e150a2cfdbece235fc112800513052f0970937a57b57dd8d9bb4d284aaabe8451d2b9d604c0eb6cbb1619b67665c4ab74f91759204001d55b98927a22ac84b2fd0810a3af83aabb50b07079bf1649d43d72b8ee827da3a28ebd2fe268bbd6a632052abbfc271c99ffe3cd92a4e7c3faafcdf2472009125ec29821d6a4a66395a6a0e5922f29024d92e7c099d8888490bd304117be10c16e38e57c66c7c4e2b85a5eeec889779caeeda6e15c6acf4b9186a4579c9924133ebf74221f9d370999030f4d129fe52d6d357c3a625ec56e783d76d77987644ddae926e7220556bfefff2d4c268857f87bf2b9179e99680f3d2829f80576eecfe383fcc64acf15b6f24a206560c62e310298ee20c60638a44e486ff1684a3603a1ad1602bb52407f67721f22aa2a3755d5120de44c0da0c81f4cf9ec307ee388b2f702b959d0f7c470fbfb8dbefcee814ed7fbc79325207274bfa142da1636ae51f6eb6db2fad33da00fb904570ae90a32e162425fdd6c235ead51835169442eeddc9f9ced91f6f625a5116b1441b1e3bf2a690925de4982e16ac29c2523a35ed106ac92252774002df30f2ee8c35b39015bb21a1eaad635ae9040008aaf56f30032920ae4955d902bad3262067993fcb0dc509475f8b8558d5ca5103bf684bca77acc2667473993ffcd09e80fa3c43dbd80545688d674024ea496054e6f1ab6d999882c6fe8c6e195c1af35be01284b510475ba4226c9deb8970cf6563e820b9811cbbe45e9ae8ea29a1ea4488b197e9969c87d8b7717b73c87598d4a6f91318ff02ebccc2408147c1f14263bd4f82b933a90092e618fc39e4c7e4ce4736504bd4475ae9e532aa731268a8d463c0ff6804e25e2cc12f346e45fb3594b275146d02484177833565c598ab765d3dacbe24bb60cb7b8ce27cf6f5b905e420160ba614330d35a1f7d6eb3c0d23f074c4b5d81b768e0bf59b278155333b07958bee4977d1400efa4daa7b78e0eac6ef48f308b3042ae36388d2e183dfcec1663c7766475e757fe2d449ec9c14de72bd5aa033bb623fafe0c7cb7b07d4d34ccfe56ab3fffac847e6d08d1596976ae38663d0bea0d220cd1c5ae4555b312ec59ca86322eb0eaa52e5192ee224fc822d2d23258d3911a0cf8e2295deca0d9ab23fcd08e00305422a0d5868a555b4d5b3faedae3e1e935864f3b701a13f9ab16d07d15b41a08104c60568bd4f2e951974f8b593b1acce185605c1239e12b2a361bea9983c56651a44d97e8a1b024a9aec307782ee8d3d94f996236a845d810dd1e88986df5c87ba9d581b46403e2aad4534bc3effaff6ff316a24c7c3d5bd958975097e404a537a761f40809207a96aa3ce8b2b0df2aa4af642e5c462dd1f7ef64342ab5547d34f7f40dd9d42cebe246628c443014fd960bfdb40873ecdbb67c9f1f933163e6a34b3a05d3ea58af89ffea5cce1d057a80c62d939473bec8004d51194782f9cef79f20ab64b56364bcc1851bf19f9100229921fb25f26d0ec44f5d8e903c19ab41434ff4184e1a94fdc3730a34e57d732222a0db7348723428c4f31e829819092f0eb4281f9cad903ae8e8bdff57c9c72ea76990a0aa685294c14df494aa96f115b79d5443b5694ec77c3881519db863f5f7b5327f61db6b6b63b72c6e7ddbe1d1bfd72967db3ff9a211067783d5f16070064400a3252859059e623801720fca17df6a434762bfa5de879cd2b24fcb5225f43d970f08468865f21a5a20cddc4811d472d2ec5926eb96a0173bca4c1898a7777149740b553c00f291c8816524b6f388bc5d946e70777a972aa6243865a36790b9120fcc1e91d4a7b8e88627ee80dac6578d0274bef7cc20f93de209cc92e88728080dbf47b2f746ea874aaeb32978b984a05b50fd6bfb9848eaa7d90e254fb2d1048a25181f6dfd64b2e2b679576d73baeba9b1e3687eece1e5e4ab9e4955b196112b34061fa24e067efc76f3346b9d644a12b2cc0a7e61101c0533bf6601c97eb6ab51e4ea3bc4088881373198e5f1b60fd08a5105f8a67c4f144fc6199b7588de0fdb3a31cefcdd2f225ce7358f9d16cdfc7d4326c440a1779e5f93edadde2e01d6fcd0eb91f74581927d11fcd694d685172d13c971ae385c23ed65dd78be06c07dfeff10fd2d44d419b6b7bd4c7c22236061358383d5db8b0aa56aeafc406115fcce24ee778c4812b5b0b1bc05bae35ab8a009c4a59b9d7ad8131d64a4f261a1c12ff998538971ccbf748ec0a0dc5881893b62082e9d118f2d1a64eee150815b45a096a96611f22beceeb71245af0566886f249fbfccd8ea1a8836247f552301eb461f52f281606b7e40a0e44de2fa8880174862031f612754d839e815b4d0d386802b0781c1004b2278138005e3dcfdd0d85746ad253531daf2a54fd1f1af4b7eb3696578684ae94b509d043a64d2742c07ede78a20c2a7f8cc2be6832e1d39dce86d1a3e3c97f324f3836bd6063432a90c0e6f9b320bae1ba8a0a9934bfb9046c48191e496ccd817b93177357e33885bb246dcdc1d3f6a0a3323f18b9c8c0d466f6571c63866157b143a0406a8e7388a63b5d0af7088441f9a4b002955251a462effc72c27a603f8b5c0f4f418c5573e65b4d7de19e699f03a436d142b08b4d84b315d34fd324b18ed0d23d4f01a742c9a1f3e6075c1964b2a56afad1128555325d29cc101dc80a9a3807d3f93dd3253cd780ebfeb7530bd06d7bbe271c0c86ebe3d8b57c2d4f0ea2c677e349106028a75270c67250afa46909252269dec56ecd8e0189dd8f1cd661d7629eb7549c51b38f299ea49a4183444193fd1bb99989b252f09915d7d010e7c058e3220f1d53171352b9bca134fbf2a9a576764ef8897f040ce936e7b2da421933f93115ebb9517b6a96464432f91b31cad710b53a0417d5679e32c3d814b38fb02738f19ae0f6abb374ccfc9ca7def3064df14605eccb08752281826f9624544d5d55539bad9d580aa85790a13fbeb33f0128229ff0abffc1b48c5d7ca38dd600074c5b692975bc1960d1cc82758aa6a5e6a9f85c598a5bd9b8e6e90a21a7f27382a334e0b09b7816a5cc856b99218fa0dd16c1b9486842ea5c0426d8b3fa52478684a6add5a4daa9157f437589f1c864763eb348bdb6ecd4b7b678269eb3ea69a1a1dca51d2a8816875908a13eb65e8135cf7a7effa0e63363655a11074afb52d5650a2be9648242e164bc1ea69a0a492a08c9947b0fe1bbeb7e640f09999ee8108d4c3a2449bea5d221bba05b8c67065959a86d8bbff24aa89338687d0002711bbdbc6d87cbf8d013f177b05d9a38cbaea5164dc2d5e97909b15069a3b86e2aa3d28a541d05717e5938871f79c0c2e2ecc7cee6a9c1574ca9c52a12dca8ba140b80b999122b9a963e4bcb601e56e26bb9492d0eb7496d0e2d2b26d4529aa80265e3875870fa78ad215abdde436bbed15a81eeb9a9eed20a38e4e1476d01413a0f3ed4251a41cbd5ca54df10758a5265b150e56114c5ac001c93d4c61a3a8fb2bcbc9e7532ce9bca75d378af6c7375024462ae80269b7cefb5cb7cdd890f7ed2cfbdcbedcb2d9371106fd8ef349cb93b6884e10706a87d794fb3315dc9231399b0d21fe75c35a78b05f59e1a609256c6a31014d3a6c672272ff44573ae043e220496792514e0e090dec069edcf3d2917a14b1684fb7668cede95f7fc2ed009ffaf96d1bb4ce5428f92fdb66065b9aff5fb3007fca851f001e6a9d7a6c2fee5c6ff000a52443a164db3a2b64b652ec191853ed6913c5d09a5c331988c31d5946dd0b56bcd60fe84335ae49b61b0d04301157be4ab220245eb6d33a6f60b1fcb37ad3e039b1265df048b8b2681deee6b5a50c8ed94d33febcaf2b246e8248fb5782f16d47b4bec466d2e9014ba7844c386630655d361eb121495f46078642c0891266d3c4548f8c52fe9aa1f7ce2954bcfcb3fbbabf783bb014c00c3fffc04428002950a57050a7418c3685339a05be3e5e231683ca87770ec4a2aa8f6655739475b774780d271d145a5d58c43666ba27c369199ef2f503ef06fb041a5c7ec4bea4f90bcd5e1d06d2f97c837095922af02391c526d3ebd03b7ebabeeb288ef398b6489477e96f58a9df4e15c7d960596e83f0620ed14be7540df0673f4adb1e74ca547c088ae3f4ac0c314fbf1725466392e543488e0983ad25bde5b1b0c412d9db7dc3d21f87c0ca55e39d9273d187407ab7c9f1f7a9b6c8be763410cff6eb522966808110a80ae50057044280aab96fe4a8e58823b0a5adb5f503b0b1a043a2859bc565315503b76850a642ef36204c5d7b859b645f7e3a99fbd4b72ae0017ab66c519a2d54507698b74517698be03d5f4793b9e01469bee052d3ba790fb1bc71d3a0b7d37c06d14306a39aeceb3fcb34225f4cdc494abe71a461e83c07badad06adba1c650532a560f8491ad02482c11e56518a50ebce273f222974d61555e75efc7952bb19f5f7473565e8ec7f29ae192b586ef27c3496ae02f54c27cc76224f0fb084d89566ebac2377d7168853167f3b00e812e2a4b7f72d9223e26f53a51274f5e169b4f4f269d6d8241e58de388d2377ee9d00aff5030cd75e86a6818a4c4c2509a3ba1f12c5b45cb95b1e7f577791f3fe016571a1cdf5409993010f52fa9cfbd2678a88657192d10a0b12a63582d0dcd130e863a900885ef0ad2952e8de9958fef33dff29665051e8055571099a52faa8afc21021359b8455183e281460ac3a31ac47a2d018e36fc72c05b9b368ef13487880412c648db879bdf8510baaf55149c24efb70ce0ab8064971e03f79040df765536d8b1561316b0c964c109b2ffb1e5d58184b1533f0a2210d90b4b91df5dc7294a848225b0c213ff407f121a5a25ad9882d80b9e48e5ca6776b7ecb2096e3f0617c9394d08f598b4978525c632af99c26bb17c0e03f4d50944e147382fc6f76d805d03945188b3962478c0b6343701296267089a3edba182cf3ca5ff9eba65a56c41bcc11a4291febf35da25c58c2fc24e44786a3177a18d8920850ccb523b5c4309a9a155cb45b3d6a2fef4dab2eee3f42c0308b9a24505020545f1925565c336bc9f080ff80023fa13663492614e41db01707102a8120ad7395021bb11f23e81a55b81751c569c9e8eb80010a8b4188d3b1314df973255b311c5cdde162111962a52fd9c4ec1106b0fe7583f0bb112a84fa260da185fc83f1363263a13093f3195133233faf58a1376734c82c502da5c0f0a6b3d17a404eff93ce504190f7a30664b1a9d10b45547d4ac6200ad998e5a8ce398123e18a658548f3f31e2d04b7e62cd2d5e44bdc926c060d0097f7ba8efafbae641bf3e561006ec366f8d6e1e581b72185219068a6996f67410378e712073eed8909243cac8e35a34b5b4af2bb1d9d2c2c30d87c02f340f7a215e4f01dd04beeb6467213b8286c87a1fd43e4094c40c34fd4ee791a4062e7528b22b8164c8c32b8156388aa65a291a99e5bcb33dc195b4ca9307095c0a81b7e18cf45652432b763755279f3a605a51fa3975f30066e1749c2c2ca4d0210bfe34cc1073a6d93ecc5818cd8bb071300c794ff761e4084867592ae2f041f4c25f30ed08e15bfe7152e4a53bcc3c62eec15be40193e150dbfd02bcc3e1c1c110737fb476d29ced5c40a86cb476e46c724ab1b25d1e0bb9c1cb2ec3026efb8442377048edd5b5710e7f2188d8524623d15d11285bf86fffb6f03988356825dec96ee6bda8db1d3e433ffed76e4807176043939e1b9296b9e104dd59eac28c7e12770b6019598f78e33befa1bb606bbca0b9eed3059d66b3f4a154b4372db1327e75cb0688554905ba9c5cad48d3513d72c188c53ed9c945790622d1a427ae6f277ee6b519f7d8af822b7ee50d647c5bca816ffed298a345830dea5ba6cb860091cd6ade07dc43346ffd508204d72d651f98c33a4ac5310fd9777f518c936aec46f643eb42dced05017f0dc17964a6c9c3212501f81d7c17fc9cb2fdc9051e8cd004fd91afcaa2d86568c7e952e9b3a2d9791325a58b95382d6ee12f5aa3063c48081fae17f0f35d062fad442059c640650442c46390e0eed547613ae7bd9eb59b1c56526dc4d9d94678fe3d9de1762fb34896e18a80e4706a35597d4a6388cbdd5f4f957bda701f117cc1a94c3417c01b1ac2e827c3090f220e223a48c921f1fcdd4499b895d8c3e54f099747760d8e92ff5749b8f30317c49aef2874be7bc9c56699e96d82b235e5562181e3b6de50bf1cffe537451226c9f057eb43ef2c60d1084e80a89cc2ed4b73845bf16c800d240c7cc5a85ca7d8cd51cc1cbe7eb8f1fe860f4a5d41968397d871e1bd59c67b2b0ea0f5f8f813867f94b4504d2420b094200b43e690616abea555beac01fc87dbf60314986bffdbeb7397072b7d8b1a8efe3b5404557cc80b61abb0c52592c75eec1a7067aff372d4a55ce3384640925c1a3d35ca1d0eef0e81481a31c8ad4bc0e3fed25905130130f02bdb885a393fad88c94ce861772aaaca8c1ddd8a665554cb3d8722b25b56bd92fdba74ec847703a4cc7cc28a68f01ca7351b1ae28e9055e3d8cc603afe9b312d4eb66a3ae26921a751c8427031cdd3fb3137ffe0006c92066ecc0989160560e48170fe89710b6c708d348b3dceb2d0c52f8522285f2c14b8ebbfacb17ee13ce8702c2aea21dc099512ed4b448224e49096ff72e4db296f693acd99cc96181bb380a8491a0caf81afa24a6e42b626d7f3785eb08e31cc0e035968a34e33678976ab254bbfdf05bd47c7c0412489d33b1f53a23fbf4f257164a5a7a7baedd20e535da24153b1b5a4ee7acf262e3ae10c724e0871981a9fc85c49f0ca6770854002ddbcb1bcc3ddafe5899e98b11bf6e12217211bcac19de9785448127e4baa876cb00dc273cfe34d93f7c11cd970a6a05810beb10a5f71c58ca2f622428ef1ff03c7e8df8dd0a90bb4714cdf7b2e81c7e8ae41e66c3dda953515410adb0ee3bbe15495c34bc83097a1ab1703e16e31922f48f32e9df65e71adbdcf98abdeab3277a4c93ac8c58965d674603b79ec5f11ae88ce92869c0fe3a214aa7048f5759db4df02d0a0a167bfc6ad086c53c82abd97e88b0dbe9bb7c2f58d5e3f8ae8362272895351b1cc5c8a80de2f76dc4b9daf2215661521fb54118fcd03c21f573a67980c1f46978ba1366c515d8b360bea577010fe9fd2da66fc83305b320086e30e3a31edf6ac4ad71a93a0ad79716aed6671e189f089f3603a85f605319b0ec31a58a7d731eb3aed37cf59cf18e34223abed453845ef1002b4e4fc41d37840c6c79f8dc3ef144920f05e191e8d1bf5d48e15ddc16746a7583688061946d68b6bb027cc5ffb39a279a6565f30c6ac0c893b1588013fced2582554a8d312058a8161602e996b435e05cb7c3f8ea7fa5e0ccc7b17580b72148dfadbca34dc7c2dd3a9d97c4203021de590d34371f917c3dcce11270200db35699a461c73262b1d2760b7199711cd07bde1fa1d2797ad1150ef6f5b944a414c44e33d1dc71dfa60b70001f9e535b35eb3d8f53a32e10c82678fbfe2a5008a24eb1d5806c393a55499e58b0fec0265df7a2dc67c16acb04ad8f4ea3364a1cec30025a4226edacfe4614f9b82c2393309b18924bb77224b7bc2052c06f39388428cc1361377f23850b460a39006c714ac9aaa1cf6a80cccc4edfbfa71f10b940828b971ad6045985206b05260481c36d283d2c23b022fa6fef61e87799900d5254c2bcf4d5d9f06a6f729184fcab5ca2384db8a5b626c6178e1b49d815c1d3ed11f9014b12273690bd82de336a01f5f55dcacef1fb31f00cc8f001d228312c7fd3acfe77b19fbe2222f56f445e57ee1356d3e178a89b3e38fb4b925bb561064c9bc819a9b22f468bc9d47f0913ca812ee284e3247c8214ea5a6c44501738789c15b841e462c319cba24f951219203cc53e9a104131c1020868060f0467a4242a08e33b178b5c73e9d7755425795eca72431b03443ad05fa408832535f277a6e9becf0b30829c008a21d3ef669666587d607b465dbd521d2ab4a89728023fd0ad9c1750a0d1490f0e83513028ec54c0d23a15588af731bb3ceec4fc452d5d93674e5570f9de939998e3d424d5e49eae634a4b312269e12bc0e54ba2ec36605696c0a00035d2130374a12d150228b081f350eab00cd7f4e1565d020dd28c247b8464d316b709ddff78a9f92c5ab03653e352cba4e70d94aa09e70b9be13ee3a3988ffc46e09072f557d32a14e3a18a42487812c5cfd4453c212b99bee5e9d2b6714816265a6cae3f9b12ff9b9543fd1c7995d226a65d6abc8e425d1a0aaca155a47d85b52066bcafca582dbe7869649db20c0a3f9494050bb836b23f23da39fb5d9ca634b95dd495fe0461375235d91b9af9fe87d2d2cfdbea89d3ed8390330718ade607c80d50ec049cb93c308d4ac0ad15a7fa2c79361c4c5cc2c5101b8fa94befb358dc4bc408b5778f1c1c658a583fc99331d7c1a9310ca9e030166499e4a616be4b17ab21345565019c2639652a7481e313041a51f116007527db0512e978a18cd009c7ff50a4fc471212a7086cacdb69728055c090aa2363fe19b931e14e421c68495ee01550d825305462db56857f5e5fc8e410a754153ad3c9021905b6bfec3c32207bc0e9a5e508f30e2a1408e7b1f1380fdac824e86721781b38b4aa1c7698fe45473fbcc68b5c06cc7c31f65a5bc23c89dd5f8e7db80dedf20b1c4b3f6a4d7f01fa505390784cd0bca3c3d80d5fb0bf09e4211b2d35bf8d5e5c8fadb38bf2205074096637e58def35484b929f290f24d02e1a3f5d008b7ad5a5864cb1f6e3b9d6c4061ff33563bb4fb13e7167ad7ae620d015759a0c74b8b68b685da5309df3e0d2e6ab112768c608191a45897ce2fe42ce288c023996ab748fe7520249fcdfca0496d7e977f1a88869141fc181d49936ba5d637f55f617bad72335978f3cd324140defc4efeb3a111cfaf60fef8a42bdf84ff1204eedea657525c155850f0265eb298bc4a4511cd82607d1f3e495b616f35b7255ee78499376c872fa5db0cc9198b1a33f1214c74d6e72c69a53c72e2e85036b841e7aa092d600db4ce3e60721ff9a2d110c80b56c0e41e49ef642098d1b24c23e852eb442293da81af607240b8dfd4300d43ae9f8c59ec7067240ef8550d3da90835032d132a3dfb2e911dbc1ca0590631ac66d247d7d25b625188d03b1a2663a2e32f1904909505a297ee4f7d144dd40fbc7394946f32d9ae07a552993a54dc25c753ee8470577fe5d92096925af781767b8e122d1665a4f9226716008e8dd158cc31813dce4261d6b4cb362070b6f508dd44d5f3b06913d4e3b6c866d0402170e06c82edd24235e02156c3b1c674d467d3700a200b664ef0517f9368091c292ba6ca69b18ae6df3ec8e5f7336bf3923b65278c95c615a327b4d2727f4786bb98b7c61aadb4184d559cb2b81c18c720e347f51deb82052dc75ca51950d305f33f027ac5a02f60da4d003d57c7dd41d8c526461e4d1fb1214b3be26359fb3009c5036aa34cdd8853511c6a37239b2a8f7c1867bbf2aa17cb34f430d56d15a00a0259c41019ef4edee4222e1c0000137253957647eebf0571f7a026671f174781c06b51d9ad0016bb621db66e44dd3b0b514b1f8dd766b22bfc766ddd6934a17b2e62426552c5deb30e018815900f3d3067414b12785c99f2363b9fe9b7599eed9b6cb7d809a29a784985c97745d931e747bd84a8297e1b79641e019cc5645338a591c85d33749e159bedf41353178d4870a78a63ac7fc2a9be8dd8249c64e25ad141b17ef426040efd19f5c8ab4f65a4b121379fea7548aefe9a280897207a05075a7f989f9676cc1f378afabfd6594830e1b8fd7ed923ad58baa8549bfda2743c4f14e5bb5c3773f0b8124fc1180c61d7022d058182058b33561b3b121bfa08c3bbb10509dc3b32bfb5d6afee9317ee61ffe6ad619132b8ab3b747b851977bbb94db951c4b9d7cc11cc8a95808e4c789d39c4c606c90de8b1b3df6ee04a879d3367e50afc53c9b5ea81ca0c864d078afa883b3e9f595d630980061d8fac0a531cd98bba02d3c33afeae8a2e5a7459a8a71d84bcf14876b08c603f38ac8163ec22ee8b15314be0587ecf6862592bf5a2399b19f855fb04e5da7d0fe5ac383db990fcd27a5763e8bb8b19a3d8a47331a5b8ec9c1a63e4447ce92e7b204a64a951c72152c730c91fc3213d380debb1713d10f8c54790b21b8fa484ebb1651eae7bbe3b8852c214b6c2163f2f5d4f60c44aa72cc0c13b4df1af4912b8cf2d966416ecb8f62de26cd793f4000680ec9afc1229dddea6ce94e9f413850c708d2bc332d1c382917b32f876d93cc76dc552c7c3788f0eac2bba57b2756eccb3bfacd017b2cd8a011ecf952ea59a79712878e90bc6f4f7f47d8de4f5910f23c2a2c836b28fce656d84eef186c2d780d9548b93491fa477356b89e30e27db37e005116a53946ccc07aa5f90c73c147c6acc0f12b3d1fe7198678fb5da0ad0ce011b86e6720bda4fcd5b2c9506c790484a93d127f8040a06bed9079bea637af7fd36f760a8da33d1c8cfc69a7fd42ca289b9072a858a092c0f25129fc6a54b948ef3ee61f0d627222870467b6b20fa045e1440a75fd3cb4f04224b7eaa522e33bc086833fee829696e09429813f5302bd0593f02c4f6104b47b6ba58f81a5e09fc0f75e4b93d1e0574509c90e884b840ccb7778121f5a6228f4e468813296e2c47655be4505f3657825ab3f31e4a1ccd39d91337aa09cb7252b31ad223defed728c52ee26bd8e09dff503750bf4d6ccb2718cb6720d81e5717e9d6fe17c08fc607a6b1da238fdcbdefe2c7f0989113b804db2881839269a7a6bb8e8f354cd5553fcbb1aae84e31e8daaebaa6f0c25a07e9cb4d3b3e6d59adfe15ca3d2b44a943c725f8e2721eedb9d2f1d16cc0d7792d30c4fb5de7607886f5740a4612e8f2bbb9c2a0c871819ca707ef7802c29166ea55624dc007cf36df4922f482bab26b03d9b8b6ce222b50fc6c8a1cce983d98ee58c36bdc189b1f1bf36942598ef0d8e104c80b05c659e60170c260745dcaf2abfa2016db3ba30822d1202e139dd46a2b281984b88554c6277eb87d033ec5ebe5e0c2308363fcbad7cb89745d485e398264dd918743ca9264a04dc244a5a5aa832850912a79f120a026418b205aed0ee02903098c0afd6a69899a8fccdec6542c894b47c74fa0c5c5c89b7b636edd87c4478154f947ee8d43ea9abb173bc2a9fd055a130f25948fd855f4d52151371e73cc8157f66c747406a716501d09efee0f8e9ab9f548b532164a64dc8b019791bf3b11166de98efc818c9d07d63b508f3395d4337b9286ed370ee30b9bca8a7da489799a66c2b35b8bae4fa3c54470388a08b0bd54887a4c0e7310186971ce8628443851d7c059c136d03ef4309b2c59d196ced534e9cd0a1b8c4ac783f2d22de95ef13c3846c5f0e21246848c5a5bb0fa11821e8cd4ddda6223c0d4537af5d0d0acfb7ed405a6e5a806d981df0211537b5f7e4b7fdb1766da1adc70ad1e256490ccea08bc1e756b3bfe6bdaf573afd34f483d342db89cf81ba9a29352736c80c776748ef67806cc810af38b274812c27f364366d475612d77b2a62fdf4785e72db5de881f7855d773616cc1979afaaee1b401278a2696441e1b2ec5ca6a31cbd76a672d24426c8db989ec839fa2426a8614bcd39b501af308e13ede8ffd7091570f9c813235f080fa68313a4bfd87d81d6eb5c49969c30850843229773f5c8951a697150d6fd9715422e8bdcb9b9deec94b06dd4376d3f2d749c6407f6a63d699142ad3bf76ddf228d04096f0ce29ecd8a7d1b580b37fc7cbc7ffad5d0f582372f3a19e2c4daf2c44c1a68818b46acfea1e034bb94d6b35b3d62a67ebdcc2cc5e4e027e74429dd9b582f049a398299cc8344261c09cf5bba1e4cefdb7b1465b7f0265ba9c47d4fc8b728b4854aece7e7732430e1c685641b4a2e34ba19daafc95b9b5d11470c2c474ef537de8558e9e9a195a7ad5e7221223b08dc480e749d5957771cd920c484d797411f3c1b1103a6682733eff6061cd47bbf032ad4156f0a97b16bb2a062adb76ac7d6377bffb4edbc40ee47d77e96d4a3e112e50d4b9a6b83765c3b68d89419cbf3a00d8c199df11a2cd333b64e677bfe92735537ff126df850e5035ece0b5d488abb723d910cd1bbd2c8df8ddb190614e5ea5921b09c3ac445621277ed7ebbd4a672041294fc9f51b03f3aaae4f33b2ab64aaaa9233279b1e57f6f1f36c09dc16684f302cd42692e92dfd9c422b946c652bba057108979edacb18509a1013b0b378885f46fe7af83ff939d045e44dc86223a62a446b7185136cd73dc99a69545c2aeb2d692daed276fb6be7243666105901ee2ec36e26a511820c178f8cbe9aee3e343366939a7a994948451822845a27288a7c88f4bc71eb97139b5518af8d1053f8edbed85c6130d8eda72430d68e6c842ae9912c7e6f3c88182587df144395013fae5d814494f077f526f6521e9bcbac44581a1f3ad523227e0d7d1327a45dd08b160d8385ce09bed4a6d9af86b278b23b0d31ff7b54a136e275dd07ee0304378009fe09bfe7276f9e815948a8f88b1d522a32ca64ef56cb46b5830680c57eb7ba1a7518dff8001f2973aafc1635c9caf583e90db0502bed409dc11dd65997fae8e07c50aeb1d6d303a00bb7a16b063592e66dc9ceca0a5d7301dd6b1257de7adb0b91113aa15c6f4742e23d310c4a44c30db3cd7e6cee70e6ec7e4f587f1b2e96dfdd225eedc1d0ad513705df13a56d641656128f34ab673873d04326cd1ed45f0edaf8e24dd8c2005958bff6eaf848065f06100ef124a7d6d1ee9fc52b80b59c9473dff0072a88def6a902d20d67b436a7131a9949988e36a4033f406a5363f52cb0aeff1999466e940ab9274ced4ef565c3e9e792ac3a4c57caafa0ee4ef62d5017199c74e0005d65433fc06906a262a17b24212d73c6adcd0a3e414cd994fdbf1bf36f562d3ab4126a56fba10b584177b545e1e19e5d2e82f201a95d1ae1f3b3599f94766a7abb59fa1e47a4c6d8e6689ed50367e12dab77e180b0d5d5606f5f5d3d92007798f2d1ca8e44006eebf381cdd918fa3a0b2c00c16bcfe6cabf8a7bb308724e3b854583a6226af7c53b4551dca41c4008fb145d83a04c9b44c980a26ea1522e8c45cd02d9645fbb85eeb6e9e0abb4285a1975ef9fb7f82a86359b9ddda2584894c58cce689ac0fd8060a92ac9e4fae9eb32f8bf4b54a3c469d9bd37e0ec022d73f7f61e5814f2363eb2d295de67e4f8c778e8a269734c2d6c351232ae614a72a261454815822e91276097f9f45fe28215c1de875ec2bfb518fe0383a446799cbab5346093e16a6a8037bb6066aab1d0a80b26d5ea1979215a8d9a1a865e633284daa888696b7870bfc6963c8c3bb537cebfb66b142508bc8333d296708edca5263e126ee82d3813a069a1b79875908728c11f29c219753961a7e0c1ac03ecb61303552207d2cc413c8923f9687337773b4176783c015734209fa9f55c2a301d69fc729c12556a42fec8b5fe36df6ca296f79f476e915024974baa2b34a820e7e3d3d9b7275c80eaa0030c8477f011bde9610115e3398774a129af37450a7408a5f5a66dcf1c2fc4185d7a85261443d286ac838ef08c3ae5803f5f274f48f809a8e8a887e36956416cdbae7cda4975f63732f60b295cedd6518b0ef9c01c7bcf5bffc20f5655b3cdd1448185da6a84bbf9a0099c6f68e96ddab22a80fed7f0445a47a53b380e7baa0ca7df3c0cd937d21ced1e66424215e8207b08a5dec4e4bf8efe680b037ba49424de2ed21c670f3f5fbfe96e10acc2bb0eedd15a1944fc59b99e9537188f3ee2e1bc8663f2b363f14561c342f016a284713ca4c28d9b9fb21714928592aa4f7157069a2fe587d592b3b454529c5025d59da8a4e9eaf44bbd11e2d38dc182d1a39d0d3b20d713b2bf2ec01b84f93f6889064038bd76208010eb550e2ca5bb9c712cf4edcf43b8b6ba70a1c0ce65c2c467252825a44f36f5a7b5016ce0708f4044a7357319b9d63f05d75d2f328d819c7aa81ee57d6e1d528c0ccfd65e27049423b65831ebe04740fe1310195cc7ae049588d8e72ff2c12bd3491e747412eaf4ddcab40b9490f2ca742e41f6cf75446ead4c47888376bee3f50494246b12fb60189990382f4110c34b8513e4bf993bcd4dadc74391c0fa05e47d0e18fd2ce8d4e79beb377526d845e7c4632fd1555e447021ad4138c59517ef2a8689dc34079163c01bf2205c1dc6f15c5e9d6e314db332ec252625894b3709d2cf9b7b4367864b54ef44b2463dfed4b286496d82cb7dccaf38905a89379132557f6bd0706b84d4ca751cea6adbf5962970d65322a4f2c473ea65dac6e464e1e2ffe24e7b7a9e59e9ef6f2b3602b87b4a201a2fd8d61f08e017520aa3008b4fb2e5647eab8cb53317c3904ddb0522b4a97ab86b189e678fbfa3e15b9a05fe8634b5528f5cf529e4c5ba9637c95217fcf3f68e56415ec1723d4cb96f4aa0d4015319c2267a417ebaa7e815d2d699a1ec310c70947e3c123c358ce6d3256cd6ba8f34f62da6ff67e5cd111ea0142038bd2232dacaea817f2a7af66a07dfb85ca91eb945470fcf9c3fdc1e3163dd61cefcea3634c3622c4ae897e4ac36b0a16cb0f6fd7b37de0ac567149d277d65dc525f7b07339c509590fde99fb489fe5d20ebd114839c5760ce3956867adf90700a9a3654a8b72668e21cbf71b6b03f5f62dee43f877fbac927a45064d4c06fdf551204b38e0b64e468b03605e59633653b94e6f1103eaa1748e67386db1a50a0c9d27eb487339bfee8243c3e00a688eaa2bab66fe557540635fb3be3eba80ce9ce13c0e6509f66bd0a6385d1c810c6221f0e6a980be45229f9f9b90b3ae99034332b73c99607f171e8ed69191dd6299bf128cb6fc05ce49aecb7e0e73da83aae60a024d491b4bd32e3fb5fc588743a40f9e84c5b229cccf50d7b9546dd4c26194d6a6426518fb0259a9133c2965e56b2a0fd76076b60cf5e780b80228c4db5b83c2ae77d5840993a361eb41de02dd815f0f9f01c69ca85dd0ba054fb93ef67d56f43ddc70052d1b50cdb38b216b850c2e8adaa696fdf4938093416e40d6e2c8b9a30bcf00c72d8325a6fe8503cd40250026a55c6b90a0ca855d6ed97198b45fea374982e0232ef23a5f560c855ab1c87e0b0b3f41d7fd2be210990c97905f22ffe7d88e5729604da2c2e0cceaa58b067e4e98170192081eea355341941cc007ac885f992c690017b030219fe0ee653b9edafcf90c55aebe6823f3c13ccca04bb6af869e78f50ebf893f78667cd50dcba94d93c00d8dc56ede45f406908f82abae471e91a6e55d7e887573603785c611007c743fa995f92901f2167f046424fd02715e15859d993a23fb06be33b59287297052ffa0649ad3b5573ec8a1e3bc107f442e88055f493f9f08233bef448e3a31e71dfb64f8070a36d826f3273678d731c26415099de10fc613c9f3328b49263e332bec8a6849e7d9944dd4a17bb870ce6eb6525a7f70fea139a465050f32236842e82506cc8573a669076ac27d8727d3019a199713e69033c2ca2bd47c584b090ee463efa420c7cb2a64534d389816ee4be8fc2f069ed8a1d5af85bb128b9b7dac14c42d8ea3c22da4486366a88d5180285af55910d3dd40d095a95629c1a5afa15ad3928fe8db55cb3669975fe1f83d327a14371943e91ca35b3fde43ea6b8eff6d9335e3e582bd875a168212e2be5bdee74b5567b0640bd8bc7057041550250639b3f10dda7ba720d59455274e5e0d788b9845481ed3a5c5327067c988feb0b626bce89f4bc0c47b74eb10a08364b7be65e69c8c8330c4f471c167a0458bcc4345725812640115ef9c13b5f4a039b36f51da68b338255da43a7e100c8cf8c11e1724b5739918897e82a378c534ee9d633549f54c6d871e1977f98e9a329f45647068277fac21e5ae41b0de697946557108143e8373b408003e49ec0d1049b6690ca88883d6c4863fbde0c7c88762d5800b00484a1dbe566d7964884cb8ed0906935fefa897c38621490be2cc5009db028d9dd37e4f29b8107d16bdee514e88de670a23b15d20f35d786d25d420d04736eb7f285dee5b88803adb9081463d9ba9c1a7e52f42a051e29c5c7caed8471f9336ff911e4ca4eb341776498aab4e5b4d7a93be347e8e002a8a3e071a59f79058a2ac388c40d833954e15c3780dc5071d33d0ebcc2a70051db367a63a5a03be0303df446d6ee182df467b4625ba4cc1932818b5b1cf029f7b88a4c034f8e90959d204de867aac866033aa704c27c846b889d3357655f3c018c22c6ad3c05005f7887451c64da4e6c81184e690c9df59074ecf6ef7409e84ad064c53985e75cc836868458321d84fd69473a94abe37c7b6d94f75ac23f09cedfc2e8bedba3cd37b27da476646ba547da11e6e3a713f6cc19c4d280e7ca4aa82f62b37d55c0fe9576c5d7439a0cca6a235e7e113f65f3e472a431e9511d00419c5cee4e4ce7b4e44c475d0b85be7ca17a48a36080adadef9d090ccc2021546019bdfe232a1a748e54ff9191ec2fae0e3dc6751148a0dbcf4fcc7a128321897958bd3402d9d4116864137e02a34325f04326062552e0244ac69c0a1a0f97955830f3e7130a773e59801b51f062ac1db0bc24476025133070a00a8fc6e30c61ca725f85a6267c66d3d361c4d3c605080946fd178ede29c62b618d3b454e4886138916112a051f9cc92599c8fe4373c17447e1b1c29b10895c7ee4d4dffcc3ee0098e3aa0cef08866c22811b994d096c353349fcc980df74335563a822ff00098420a40f67add5de7480946a7afda320b56f2020dcc11228171e200a5171a2ee3b0461c96d2992a931c5173a2ce86f9038dd68a78715f395310a942f8d9040f281643d90207a6f92cc423ab596c0013f15112b21715cdb33dac1b2d3b1262359431f17179d326cc4a1319ea2cd848e54027b257a473060a76ce3a09665a05e0aae208cb9fb16c4949fb381cd8ca52b083ebecc3a87611e2ef75723d97cc06f9e4a33a9ca436e06520486367444552a0ae8ead41007dff37f1bf9032416fd1b101abbd5771720d34ee963a498618241de0c23e9db5ab38ac6c3de3c6ec2c9bdcedba3472b78cce0f0309fbe63b9477dd4064eb2e854bade4885d906efee473e152cf1b3d73b4ea5bd6d692aca9d6523923b502f4115df15a31832935e03217e493158f1f25594e1d8969bda0dc630926da5b4c1375093e7021c01b8d4cb7430b83c6cc54103c2f65db6b3ff5018c3d24444234634a8fdc74db6bd8bb0fe331505b480a01d1926834a8d5147c52d2621c535dcfdeb525b5d593da377976fc94f3caee650b9ae6a5667aa48abd5e91e03ff7af89e9f41ee2388df4c50ab7b3f51d368f99487ec89f9af479fd624ea986a78678005a3b41affec490ed424742d98b3786ed3f2b8a8abbcd420b58a85806da8b4548ba15623cde091355cf42fae38ca03c6cdd6e1dc23648e3772fc81e82da65ad3272c106d6a2c568d9c8a44c925ab6350b280171db8180f8308873a7e018d9b460b76327deb813edfcd0e18e3f7a59255e74a56c9f3a51358385889f1476762faae57df924a663b07d4b0c593b59bbdaf48dbe11616322d7e3247750c65e4c2d5bbb1073eb6140645ecfd4db3ed6e7ac6511090af3904ec3abd0210180af84f8b3361a9b84ffc6a6e9882dcb0e9cf7068f97086ddfeef52022552da0c640a1090ca946864f9821434387a3150582c7ed6f22b42365a57ac4e71926b306b521c8251d090d907d65f29ec525241babf43ed9426e6ca6eeed209d8ca7c5e33299720193308ed6c6352b092cfdc089619a1457f0f8a6f5750617c6ad9e7cd0385dba6ebf8e55888aefd911e0fc0c0c4350d63a19e8e1e459b442a6f1c0315b6729f5184bab2b7f5f064831b5413e45072d9391973a663073c61c58cd00e014f133ea9ea482aa45d90090012d99438053fbf6cdfe37ced73312fbe43256483b0dd9f46af1e39bee4397a59b27feeecf8cb27ccb5cc88eb4c409879110533a159f5ac9f7a439290df8294cae6564e59fb2f487102be04cecbd3f52ce2e6abe3d0b0692426e035d08e2022e90537d9e67a5dd0cddc7c04760ec2908cbb2db5c587f71538c2def77521dddb71f4dc8168ee6b8a1483e8c98fdedea3ffd80adafa14150aafa6182c118bde0be8938808e25ba9d360e50bb6a53513698bf58de3af16c4f8c98dc750d42277a060596c568cfa97bec61275d1d6b469c78a36a11bf007ab13ba1acdadcb907af0f1f0df96f914f6e7566254fc020bbea44a3ae178a5f18d93beba6c9fb2eaa73416a817bb8f706b4f15525ea1710ef404ed5798e001779aa1dc7b728af181552abf577c01bc60320a5940d80a04760ad4e31bbfe6f301e76332f4997cbaa9ecb358809b30b8480954d8c7818289269d4de4d0b2467c14bfd423e8c138d0bdb883e2f1d2dd2c9e8eaacaede62057529f49d9ee02c3e2451c8b8d7b2df454ee40dfec170864268e8de62e755691115d8f23309a5c6a00370ba98328ca5070e2fa532257ba20cf03368ce3999ddf2bd102609078481a02554b5fca1d454348fd05e282d3d21aefea64610272aa1bb47875c21b8f7edaca793435791e9e4cfeb506a02f641ac5d2eb083dc23339ade6cb5c657de9be9b04d92416751ccd04662be131c84ee6fa1e0a38c94766880151f0b53037608acba22e7bb2b2a8077c5e5b91c8263a481694d385b0cee5cc38701a71bd2e9ac9771ec0e7b4e661f67acb2ad7a9a2cb0ba7da9d8a5d5f6b75fcfa6206a4c482ff049b7a3a04709cc083a1be54c7610a1f508822f73afa6611e9afc78b576484fed6ae822959cb78f69422b98508954ab7c79b95824b1482172258e88969377268fd1b348b619a76db8e9fdf0fdd8e8d80045ba87d9d75f5c5a9f64391ebd5eaac69c8daa3b519d5f7f023fb26d329c7ee932307fdd47d527ff411ba29a1b08a29635da8055d86e74ff59784695bc28abef3661a4898834dbd7615c28a08d9150cf64312957f9fa91cd9049937c8e5196d372a1af0f31c7c0fee2eb42f20e289f99b274f485d67b450fec3ab60715f234bb8c4e88c4f6fa6a890a9df59c281148cab187fd13cd746dbde2e34eaa1b8221b4491e0911b2fafdaf0fbbe7469869bf2d7713cd66cd64cff5aabb39363f924a4f35323787ae977b95e5ad71d768915834911bb1fee75cf6f4acb4ed0414d756eeb646e56bca5a13823382e481357bc8eae2815ed85fbf3708bb11da9921abeb33f76f13384d73062555ff33354b9bbe2ac1a195ee83bfdd6e9da9578de214ca5c72bcd87268a413adbf31bb4abc909d838f36e30a131f4e6ad133ba8798672fcba0843935ba1dfab93a478da81461854c9d91ddd87bf21391196e603f8b04dedd75e8de045315e40de25ed81ed24b5df8980cb752bbc3d5c242d8ecd51048d20584e61998f5101eb746fd392cadddff1da0ed90ba3d59e8ab4de9abb48489ba60ccaa6b46e065833be418eb7f5936c0c31291901e469bdaad6ca6ac3020132afcf0439d45ce5a44bd9b5a41d2be81af88051ef584a2f293c0a3cd2641c52d1a4b6c97426a8482140fef9a106e59f44ae74b694092956ff40c509d708e095f872743e36281d0f33270aad9a994a1555725e34efbaed519bb8be302ef913f92377e6eb60a63c5bf77679292ddf6582567e51facbb8b96af850cede7f5dbd8ad6efcaa0295f2cffb26e7e1dac5e3942b18ba32ffb9f4bd556e3f8bf7e81cd315231dac98c2aa286dfba488828e1dc9beea9fe3c858d0faeff15516c808b1519250de18e1523f894463ef93793dc2388d8fc56d25703834758037fdf304cefecd07c43029cc46f2550bc0d8be3aeb45050b97b62ad3750cbfe4abd83e1c8a646011b65db92ff612096e819e33aaff68b769590686b5e6fb683c02cb507df1359ded7f8cdba091db2258c0a53d06607c85cb84d0a507c5eb2f3a56c7fa21032485fe37b06ab50c0d171c283aba1e35a7e577fddfcf4d2958329e8f8aa2d25dac7c37d5ce0ce75550018edc35717705e614e76e15d9ffdc751c4425da2290c84d775736a74b6a50b2f33cf63f6ae54d9ba27d9604d3e3ba784f0978f8df4f308a28e0c1e46c6c66446dad54808e1a6c65937580aa8ede59396a57d5e182b76150b87151378968a11dd1bdd135ecf85ae055ecb44f335439f6a050f594723ed36570b3e3c5a55eac21616e8e87c55d1a60142b1875710314f90fc6dc682b8e2d3ee908cdf302bab5df7fd17e4422ff0c7b5810118997a1c602b30e2364637c1d161e8044a93abd422b0d8011ce092f93018f95296490485f6bd5305810d082d077760b4d36125ed811927cdf46955475613ee5a235fc7a2326abca841a03d7732f4741a55b27948349b14b514c97c50484518c0cb21df7878d02fee7785c707c618f053c00708c539bd8a087fc87198f876260d03ea35c4c4400e0194474a979e39ef9a835cb18f4a659923b5aebb3f36815eccef8bf07eb5dabc0292109f2e8b870a812f8ee60b7f1277b1c495706f98abf9d06e970d08fc8cd0019571dac46bc0697742f688bf43c60b9d328b45b17e67ac5ad46efb28876de3cfb87e7db43ed6ea098391f9960b0136225e44a24992aa674d42c94443e69fcc78bdd4869e17e62571ccfba5146de0c64c7bd9bc9bebdaa0a4884ed4badd217e8a0bc2d9ed00abe7530ac025f166c027fe54eb26ea9380601ae10f9021e734d909afe8bd40a4828ae476d784df2408376a827a27b5f41fcc70eb9449184c31794219f4e532fe70ef5e8bb0c85edadd9942a20e19c906d0b4dc3706741a5eaa714069132aa4f35e02d78f729e7cf261d8b9246792bf2e0e0024c9c2e376f72a5958776e6702a98c6a5aeafe04928dd86635b7f4ba980a9de4fabad617517081e6cd6a2cb3c756baf921513863a3a881a2444627ca9dccef87a173d36bfed09a1135f02b3794422d933fc9fa5814e0df6777d8f20f3b799f42f3df20b9363291f907b8ab4912289dea57a6c04e6b72e40cdf328d357cec17f878eb0ae192117d589cda5b81f123fdee172eb359285d7e5aed07e1a8e54d802565955cf31f462276cc53fcb984cbaf39c8712b618ec73ac0b837ba4734bec072f00b642082a8553fb061683bbb5398abdbdaf19a96348e89f8aef7322df731728d54f502321c55410b6cd92c9ff15bbd0fd4b10b4c7db050bed9aa0654af012a5e65485c30d0514a3ad532f37f2e47450000583da200024082214aa8d26e4e0324b2d1ac75c32a68eedd333e057f5d8038be5058e139ae8eeb3c8fdb89e380cbbb8f0a34c4810b5e7982c3c919e14d4a29fbe0dfa2b60921e5b78490bdf7de321a045f047904f7d36bd500bf3a0cfc0ac7a078c08b63dbe5bf7e6d61e72fec9794ae8967ae6240f234c32227f3e49ee140e9152c5e320da611d46fd7688e9ed7869deab5a81ea79e97a5a161a611d8d7a88a3f273dd2248abd22a4a7a74d9b2dce16a7bb08e92e42341390682620c92aa5a5073c49c9f5d48a1ca0107a30fd9455ecb4d2926b1ecd5915397956cc81ba06ca295321aaadd5de58e189939b35609cdabcaa17253a3428e7665484cc6e6062c1a498514992c35e11ca3dbbc242de72cfae10d9ce51a4f96675175df2a7483d5d839f610c0aa6eaba09fb4e714c7a13df4b89b66f67e154df83e9bb6ee21814cc44d04d040149f97a987cad97e7c130d65998069638664489b69b78103681632ff0f612b153a2ed40b83b187ef742158e41b56af4bc3bace71d8e41f13ca68281ff704c0aa144dbc1cb4bacc2b110285187278e49274ab4bdc3725ece4f1c7392db558f79bf46abf7abd3cc8bd2e9e7fdda7cde2f79f105ed09fb0586fde24291dbfe13c6a060dd7d704cbe3a26d57b7e432628986a7bcf9958e400b19481126ddb5938a930530c8a02fdb2d7deaf1ecc64bfbdbeb05f5ed82fd5bcac72240be59e559121773d7b7e4b6cbf9a02fdd20e827cd9570f6d58494aa1736b6265a80e59b1563eaf56d741d05a0bbeb360e87d077dac8d13d876df771004c1bbfa0eb6badb107aeb3650fcc441cf7ad6eb700bc35070e00d45affbc0ef20f8893783206ead70ab86d05b87091df679a0f87d608795541e0882e03b1004411004c1d63d47914e248117c267e5ef47e8365a5808db38819f41100441a196d0bd6fdd7b2fd81da8f5d5bd0714c25a58e83f3e610d0f7cbf75e92581f8bb5dadc2993d10045bde57ffde0a4f5c284401deae42d8891a2770eb5f08438185c05fd0de568dd64f1cd6c227304c08831f7d714dcc1f31ef42f146ee6afd7eefc5a2fdeabbd174dddbb053f22eebadf7febebd0f3ed6745dec894b2cafde4024d71b7ce45aeb69ad9556fafdfebb7df7859afc9d6227dfaba6c4c9d5e7157cbdf53eb8ff3e58bdfbe7590fb7402c63853bdcafb7de7d56df3d6cafd52bbd09d857dc5abddefb0d5bab77bf1c27defcb55658464f97f79eaeee1df6b07823d76ff3c47bf1122b7bafd7bc155652fd2eb13ebcc4ca3fb8e2abaaf6b7565bebf7fbee86dfadb7abd5fbf76b6bfdeebd0e8bb65e5a7b3c8ae5d6534ac74c1973bddfb06725deece373aef3094556aee02bbe1ffefe8282ffc2d56da8f2fe62de13d7e7d68298b5c4f2eeeabeaff79efb1753be9b822577bf2b2c36e5d56df885e28dfcfde7e6ef2097bf83170ac17f5fafc22f9c1e56badf7dff3b7823e962ef1604c39957a1d883975879aabcf0da7bf60bbddf50bc21e3fe931e0c7b7089057e788995559eaa090a8d1b5c4bbd20e584953dd0522f48c16062ae5c9899c9629dcdc0cc665b6633391548d7b39344b8eedc79cebd37086f97cdd5662b824c2f6bbfa3754afa894db93b85ec66cf5309394ff6daa0dcb328292da30f28d88143102549c87881c1cb131f760c919e164aa8b51699a3c29c147cf8a105515e568c1721d5cb90a71ce480391c91c23f14058328186cd390382cd071410e282b300993b7281d798b1202e44c2692430aee304142ca8d54de7eede4cd4b113fb05008f8886a52a5c7d4ec04306c52982f32427152021263643a6c51415a3471ea0c91c38720468058f9e2250642ec192369a494d288141d80644489e6c501a418ca111000071e4815f36298c5d398aee95980124dd91c842055cc8f4073d398471f982eb1edd4ec0482791be10421480ee411a9c2c88308d42cbac02c1a515c3929f2860fcc2359a65df353529944537220a54815f313cd1da9439e1765903ca553cc8bf20431a408d2c89568b63927a55a501625920074117d0d3be8227a8e22bd8928529051a6ae17995e4ac9743af1e0c8c14c173a6da28e9c997599ea22666a6a6ad605ca8c0b175ba60b9620645ab9675c58c0c5890d3b8c1973c4aa2c50d792416f1f83e2a67ced9d372d14eb95ec459ecb53194adb79de8395e4edad2743debe477b4f2893c8da7b249ddc371226ebc6ba5e86ed59cfebbaf7e9904af57defcf2f6cd78ae90a7345a34c912e758d567c9f4af5beb452f743d7c57d3748817e3dedf0de7dc777d5a5d7aae1bd3bccc31d867d3889dc4d154da2f1e4bddbf1e1a6443b54f8e24b89fa5a13cfe47ae8e49dacbdbfdd6e9193b55beb2535599e933073ed34557b31aa27c6a60bf0e276cdfb407b8bf4deb583a18fbfc0db30167301e2580cfc087ab298efc9e2fb40bbed7987aacfb03bf7f16cef4231964512a6d89435b96df69db94f2f89b35bdbc6ad19999bf588f6d992c7ed1917205976cd75629defe49453ab732ad94f5a513032cac271465ab09ca0258c0f2d674ab038685a66a0054ec7c5d88cc6b47089170c451e2cac9bb7ed60c851221e8945a09903acace14d62126af66ea95cb105cfb6852c70dcedf21cb7711b9dd10194ec7d3bfd56abbb82ad7eef731c6b7af9ac66ab55a39e1e04d683dedace7d0bba7c07864c2b28d8ea4067ba4038e673f0b19f7f0f0a5bda83de2f1ab634dcaa714f0fc2ea411833059dbe5f4cb2171432f97c751a3205bd55e3e7f7367cbe0a0aa142266e4b62851c25e2790d79b8190e69722371afd680f72c69ba4df5e158d32b0625ff7d25c3a617688300b96759e6642d44b2d7aa417f6f23e8ab7314e9ae5a367cbe3aece717c7a0b8ffc07c5e3e3354df3c1a4fdfc12d0c615e9479ab41bfba8da053a4d5e5e5bdda633fbf18b67ac5319faf30b7c4a2de0c158d12ef0c3371a0bf981ce56ccf61f5abc3e8ef6d95eb318107fa173205fd63058550ddbf90e97b094ecab649d936b1b11889acbc6d6f9e737293de0734ab5458844ea20b61e08178368e156a4bac1906907a41cac47fb00f7651227b164eb75f2630d47c09ccc4f4739f0361a6efe045178da71d3fb8c5f9e0d6b6e3c3ad9eb7380c83dd5310b77a708dd5eb5b1b0661f5fa7bfa1608f7f4176b5f18d335afbd00b3c03cd232a08523c8acdd4cee647b494be4b51a52f9399287ae67d743484f3d595049bb2a31372dbd3db598a32fa8bc06c4a5956a162fa9329d2fe8824c504ae98a2217540b97abc888530195b84874403fb7df5ae773bf0e5fe27339ba0b74ab218ebb2b582c10d6cdc6df5dd1b526e5ce4f9c7b362526f7065d37b7aa801b2ad3d5b3292f59662dcad56470c5b79847a2ca681e892d1c308f241df9a189245f2bb29424a05e12a51c5c91cbb5d65a25a5de6c61c99d2b9517d8346f8694dbf66dce229da7ba4f50d51e773d64514c226b9358d365574c977dd174d9bbae415dd1e5b2b7ddeb8a2e17daed8b8c387b953d50d5704f8f8ee73e414dfa27a8966f56c7ddae9b97abdd27285abf00344972cfce30c908c83d9b2a2277a00bd7872b5ee225f4f392627b5f4ca943ed6e2a5588570325f74c0d938c807c5b4c5710d7034abb978b7a7aa0591a3b999eced46cc974898fbf2aa672ce183a1832cfdb5b07436679e95f50253a8ebbb7fb3e41f1f88b355950a026779e9b427345029a445a0aae6abae6e5e4d4df7934e7edb685dd2ed15e9bf6b3ede9cc13c7d0a45cf383932c1ae55944631ecd0b4860de480e963cbf62ce1eb2d860f2ec54da2b6651226e68bae6f3a533acb4b8de16cda38a6f9a2b7fd453d239bfee1494dedea6d9529b72e7160c304a0051775fd2194d36f42c5725fb69b7a730709db9c9ca99a58a5a4b206ecb8b20cba95569ad2ca9605852694aac94714bc66e16738d74c52dec25d7528d07e3d69eeb5f504acf256dd20660d3704bc63cf680cdd5c889665597956b9db756956dd3b648db924a6372af5c79f152ab69784995ebe50bb5258303aaac74e910f3ce23ed12690450b35219f51a164facb073279d732ac92b1da7c5e02a5129cdd489cda6867cb967533cb2fc6d3ca717a3bd9e4d25994d3de94ed1d307ed08a575d36ca55372e0f6cc4c9b5c6b0d5d4f0955cd4c9989d363cb925551519a547043c3161de312a91cdab0c033abb6564b274b9112ac99fac10c10362a7c3340d990c4cc103327ac596266878f32449409224a7dadf5b59e709bf3922c9612f77469d1768cd05cdef0f8c10447a4941c5113860004b334427aecf084c6870f9088dcf590bb6a3a341d649af49715d891f5406448112767ca4cf1290366c8900c5f782c0903a58434536562d8cad400848332dbc1ce6c071334993453264e0fed6995258365a484808cd39814eeb41419213a8c20a30219148e28a2082644fc880194212e30e24299313a469e21c4b40973041133f8a092050a1b3b4d80903b88a943270c99303a8479626b28ba440b6497945cf8b07a49769e864bae3ca515daf2e6499eaf4b2ea12d6f66e0e6aca1ce1043586b2d105ba5b5d6fe30917b261525558309d0481559018d940940d0ac72cfc0cc91c2319dee1cfa854dee4f1c77becb3dfb3226f76512b7e69e7d0193fbdd803877daf005060be7aa72cfbeb060df7c91593777cb3dfbf2c37ec1e1824e4e39299247bbe5e46e93bb7bc5f41ac5d0069a685e883cbb081c79be872bc125332ad242a220cf4b7c63cd95f7a06e378558012fb44de465bb61b10399069786ae8ae625cc1a20ea1841040f241d0f131e2356361c385831f2a3ce953063b8cc2714cd0d3c26f8b06809b3810a0788913077b63cdcd48279ffeefd7b0f65564fd78dd1d9d5295c9d429ea34494a8674331d483c5a17abab1e691b8a4129754d2a962250dc8729346753de73d01c2155d4379bae014899c9c31e4295f513a99bb763deb8e9ce79cc0ec4d1d4979a65c794a69e87a7e060749cfe0c8a02487b1860102a5862751a48e308101098ab41d1ac62a6390c584acd1ac91693d8e4822e4383b40614a9a1ad89861f23497e81052447b83429015888c2a645bc6a6c1b8b59c27697a1053068e0a9458f951846b400b4a2823c40c737880325d70e3a508179f04f0303e4066c78c2b999d517bd34210233b8c6846997ce1c7d874cc8c0e9045913f7499156c9093024d268170e91ce4938ee2314e19bd5c2665304e194d30aa5818652518657208a0b941b3429f51520339839e49138c18629c1a8f64478c358c1b1c4026934f498c0b90a501e334ca6418eb141939902d2933ca1e258e1865dd430b9944a18190748a185b8751460227a391cc881690482a50903833fe304a1c58d66b84d0ec4ce226851edb4c41dedc3cc99ec8240a904959bf09e382b1875187232e64b2ca281bd271646d240ef28bac4da7d122b784e9199c30b21965438c6e464ef62588b103991063016431b494dc21c9b4606c1efa4a1799182cd285a632031c15481f1d4410306393b16b40345eb98214b24ee24e0a5de704b288f18651fa30caac8c329e2e467e54e141899311b385376a8c344046664432800c0b0ac639308c7072b46c85ac719077a48cedc38ccdc882110c80ec05515a46993432350a692f5d462ba34bf666446244800c8851eed059240c54181920333316c99888195b2764e19812ba8ad4dc0831ca5a8d948c3346b580053cb8d0650ac90a1305b3372b3032676421837223d53411a30ead069a96c49d3b94522a4fa95419dd015a40912d708042705745f0e49eb199937bc6264df674905f93468d1d6d0629ac82d47fe867038427485d33c75b834410adce87d84c6143038f498446c748a36324d3c4c93d431327afc83d43f3248ba0e2be983dd41d7408503366cb1d2832929b6a9b5e52925b3539570e75d4daea66b6fc517dd419334bdc9d62f366ccd36b1e8cf91773ce1918c039cc4af5d3fedacf6b5e52a594ca4aa0fda0fd2045a049dcc9d249768a29372cdb654550731d413b095c1e81849bed65abb035363babaa1ed054d49351b326e9b76d58046ae711b5a14b71bb76f333d4a26e5173d01de04aa0484a29ef80e9926f315d73ae072d281227258b355dd0cba3b89406b82fe68b3975744477835a6badf545ae6b50b785abbed6ee755dd3857d7d9151bdea40f3c862570c9965cdd1c190b95f00cce32f6eb2d05e9b5c7a133a02dc183f1d0c9907707bebeeeeb6aff573c9c6620d5dcca2445daebd0f9d006ed70ef774313f7178a56440f7dbb5d35a534d9776edcb0dc0b517394d0200a094dee95a51e482e18aae16f3a8bbaa36a04107436614abae75bb5ad574598ab516aef8dbbbe06eed0542c1e113f7096af3b25df651fded6e4053dca297d9664be7acd20949d67d82923cfeeac9a203811a2c5aa87272c57b8158281e042bcba43bcfc5e8fc0fe6aa55ef656e1eb5ea4790ad8a4590995ee6257df9da6ae6ccf2bcc074cdc3028e80a8d4eb570c7b523ae668040000005315002028140a07c562c1481829a3f80114800b7f883a563e2a1305e280300c08034118c3200083000000010080300882501008a1591ee2edf6dbefb4632431d2638457e0950f90e50fec5f3819971108be0694fb6ceacfa0deac733f030dd040acdf8de7c501c297974a675e52dbfab1762036ebf7e827fefc38fcc96afd7b4a85d254231da45b38712592239d16bdc0b443ff6ab70e4206ae8619aeccf46a64bfbd2d2f064c7a4de210a918dc964afa1ba5efcb55b2adb69154569056991759e5dbd4a656a81a986d9c93a788b2b7bdedc63c9f5ef8b21800baafa6a6f250a55a63b03aeaf0a24728e38cc8b162cd68b2f7e8f11ca84a44d021c43c346116bdcc4c067caa684048115b99c938071c6598e78904b10fc7146638d86eeabb45951d151385531182fce71929ca662aa680f74b105872eac4cbb44414299b4cc72ed9914d4bdcb86e40e98dee59934b466cc8a3338e280aef86583e6c88a6f01575e73e4440f4023b7d43fa98d1c7ded49d206bc780e22384a1f8d1989c489c3d39b75e76f25b1209737ca2599ced168126417b17fde707e1538cea3ea118036d6fbb9e3415184935a3d16126757e492deeabb9a7bb75b90bfaf126159675aa5cf90d1a9bee9afe04dea81b4fc78c5f8a3db935d964c330f2b7c97663ebf6bbfabc022bd6c584b87912e1d2a3bb82b8dd2ab094d736f72d39d159dea273d37eb14ee8154b8d3811dfc15fadc48515ea84c9b7d6160f30eb96f360e47c609550a51c36d8ec8ec1c01995a46eb0d758ebfe2bf07592f4050fbe6ec0a68306fbe74263ae99cd33de641742d5f3371904e8a1ad95cf1551b191415001c185bb5552a402602443bb6a1ed34ebdba9f2532fa261e6eb407ca16a3320fd5580e9fa7bfcf59fd5d24e9281ddf75cf1909638a975ac7b38c64b555414c73c229f7706d16873da1ba0b618fc50642e5ab548aaac919d3394891098f93246c6d4fa15bf17e0e0044c8e7a3e5e61ebc1f52fcf42ccccd03c6c3b4596c905f8a6c0f73108c7992d680504d9a3aa702c8637cb300f730e22e823c8a382d021226fe0e1a3dd3ac76fa5110a93bb3ca3d4ab703efe256f2a73b5ea0e229abb10ab1a2d623b3010cc2a7be67bb66e1eaf9ba071f3e3da041c0816020427d2e178c0715ac3d4acd30c4a287ee0f233db809e2a2c6632ee733e70173403ca8f8f6ac6bb1aaeb9b8369e8ca87dd23dba9d8e079b4fc43f42cd35b642fca4e55011a7a15aa1e3ce8913d53385684d0c74d957ab8e1f7170fb9b33e94f693be63113c0f2c68ba5e2ce7b3631021224fd43619844508af0fe33d38f5b081a01fc445ba27b26ef6601e4c358b404fa4ee02d803a983229007691b7cb0c0ce370e1c482ef2fb81c7ea36218414161ee3368bdbe3c31920fa3e40722a44f1666316328e8abbc1032eb702ce03778e84f0f9f658dd2cb2792e274d888b569ef566e8e197102a1e1e98ba9eabc7300df00729403c0f1a1f0fe63cb406e2e2c753b2b5c2437bb3621dbdee478fcb191e84591d8fe9cd02db63b9cd10ae108b3e78214610740ab182eeb18bf329f3c4dd24f1a082e3a1dbb4205ef981c1b40166d44a25bd568c7945fd6af6ce4941f001077f02eac32d8db749a3ab864cab0bf6aebee7d8600cc21abe0f3ea37a78dbd21e341089405cacf604eaa400f44c1dc007ed1af0a062c7a3bf81c5fb0474a5d3be3ce8a1b8a11f68f56601f7c8840df1fcb8e31ff80f7511817b03fef351c2d9da8371353f78218cfe7082b0f1a13e1017340f649c8a98c752c74c0179823a2904780c75650578366916829ea43b20449e753de69b05cbc31ecee7e181b76631f3c4b8481ede1f12f5b038889f2d0f480dff414220ca02abb778fd70f82b64ffe2503e26e2963d54370441f903570f628866105b88be0f753dc843581be202e2b1db9585d163daf83f98206a1ff87c20fd41855c4f6b530bf18118f1c00c62f310de8815681ee38e72f11e94c6405ec5ad7bbb20ba170fc9b1d27f74b362b9f5354f8f5b337c4172b57c0d20b131d0867fe4f3637ab320f370ed6a63e0b1340a3c58507878ee6d102b7e3c65772a44e3693d98130fb17f0837a82c24eeef27c5f303cd67e62174c37b90108829583daa8d1084951079727a70ea18573d071ae00f16201ea7e30f41138459aed1c808ca8e7f193f2f1ee71753e159b2d5023105bd67e6c0fa403d44283a1e4e3a15550f0b348bcca342ee42e6d9c0a988f7b0b059e43c2a701772cf906dce43680f748170a7650fb866c1f2b097f3797ae0ad59cc3d31d7481078763df4b6ed871442b1c784cbab2aee97db0d0fc10181c803ce43b3da565a9667e348bac001fd042385e5b1dcf8ce552e981e375a3c84e70f2978cb2de2c385215685cbd1f2b613a2dd22b2792ed87452c83d0cd32c528fa04384e8f480b80762fe8253145d7ae0d03b12b028e7b1634df60b60023b43a07ad97bfeb985ee56e6dada45630f3bfadb1443b81202cc98e0c0125b5ee2c17c40911f31fa8f70a2c4e7614a8f32575b4a66cfe99a8eec32ce74002557ca3a3210faf6bf365beb225250cf601e0e972b780b41962be7e0d21baea8575dacbd7ad494a21cc60c8e9953e3fd75220d9503a3e7945944e780a92f6ae417f1b37bfd0c1f1955221184e8c77f88749a708f5a8aeccae89d95b9c2eb8e6744f81a1d9a8e593271185d2e42c8789de397102a3538c6f33e16b41cbe84448160e240fbbe8d036bf4dc717c566030590c214c10fcee5d914d1170012a9d51f3b411e2ae1e7ed6a729ee390dca342ba4a9aaa7a14b01bf44360f3d9c8050d6da5f320ce4d189d38db0b09e2349424ebb11f0014670bfa6e8d47eb1a74c2bceb2acb8adff1e70f75d96ab1fa1e8ea08edd7b0dd95a88e03444af1b35aa58c4406026b083affa05fa7c8fc9a9da02bb8ce0c702e3fb4ee15a23ce8964e6a7f5195bd53763c8b48100f335f72e9ff09a08c3170134ece422d212a9498b410918f46e155e9c8912c8a68f24e2d1cd188991caa69f3df9e9f7229162a862f7e3bd65c21fa47d7d7b21a6e735b08e414111753275098fd5f89494e20f02163b0ab81e2a1131bd44a2d3dc637537e35e4a2e3ffc05a2428dd32402eede9822607c8476c5cdc7bff23a05b03fe24d7c99cee8eafed0c1933dd8f560c78669c2c692a31622c3cd4f9548c5cd5565916396f13c14d08dcddeb5d31600a1541c2b1f17c8936048c69640171151a0a28fc7784cad2f04d7255e794fd767a0f90e3ade1b4428dcf5928d4376aada0d0a153a481125a7eca2b2f22ca1607829a008ba378e129dac44d10be352c165aed0ff17e528a6071489f4b5910dfa2429580809188cf21ae9609997de2526be78f54b9431f6ece33538a58c7f581d332f69262513d5d3fa21a5bb71224b1e3dcab0545d9c94713013a71c7ac8028443a27178f83b3005ec4393cb8581dad901f9b57c70d03d27f7dfc1576c7d5cd3238f420bec1d81cfe41f64242594924439ed2f0ba5bc0e41ecae1d99aea454f0801da82477b1420ea9dbb9238b820e50a048e00ad9fbc29e26b5a3cfa8d8ec871e84260446db2b999cc3219fcfc86f0b0c0e93b9eaafefe75fb8d40fd7c990f09762df1a2be369be08bc0c90710304f87ec367b35127c16ea4094b78e10e54f8d7cf1eea287e3e64fd90a68e1a91af66c681acec05f0186cb325821552f19beb5652014ee277c539ab592f1642c17fbf02054585db2804fbd262a5483c5a9d2276ef4fe1990ff785dc4712a13821ea9d6419d72dc576279f3c6aa16dae5b3cd211c5146c4f1161031408c9c2bacba5a49bd2065106e837277a06623e866e17028d81b23b0585c7cbf0728c4226462e23fb4166dc421f3f4734b735ea00467adf44dfabe191cd0447a5754421e510d221203ea6b0e79d5f39a8ae1d851407c47fa09065cf59c7d446ed8fa49559f216ef2e600a3661a0e3e330c3e086a5f598056b7481b9d310f530324199d8707e19436616b00893021b50cdc80694103717e50a731d62602cfa9dc26bd016113f8c03c33555f90d322b3d8ce881ff46bfeeadcdeabce3c4020268ced7c0933816729dd66dc232497f4cb8ed0069bf7fcc9f9be7fcc8e069f6ee2c207a2ea0b4b79229af5aaa4b42e5015ee9024e2df142c04144e407dd0a73ca68c80966410bd94d77798338834d45045902fe282e80cec78b376cc2d1672430f7f370245491a171ba12ecb83adb1f4328cc3e6477ebb00d04c848ad105be62adcb5beb1a23846a828d6b2e6c927e4d7274bf88409643d801ad0c674b1e75b39449a361b1cb200221f3d82d74206764f421d05b35f13ad3daea5210f150d0bd893f864b85a4fa3667d830cc56c3056132ef55c2cc2a2ec8ef6109792208a17f928d0f8eef96132b7281a8add9ae1e97885a5682e7128373b86ce584489808e738f357b3b0780a917ba89af76e19e8bc0f1d35b52bcabbd963166dedad2a520afb7ab8cc32e88a4e156bd4e886354d3463ad9db35c23edb3aed8d70eea6c94a20dfdfa455d2f34219ee49ebee88658f9206137cd5d355b45ada842924868085011a0c9ac95d5e00ea3e33d8a6d42a0b5aca5bee8c43c0d9cb9bf407248c98b20c5235464e3910d75a48486c8a5909c416d20a77a7159af20be7569de6819abf6e9f81abf4cf4b94198398b5fcc5201492cb2c4e5b7beda7d6b70a9f920d3503d05763106c1a98f4af801d976993cf74d6a220f76224215884d083a592f2e9095ac330a2511b40d25c400babd1f040771b7101f9961926e20d0932a2ef86818ad4d408a8b040f368c02550b0beec27f1b7d140c6a64e30ab9cbd896a7bdfda80dfea4c81c96aa1b1fcbb130c9644ab40d51009a87153683e08abb9049a6bd7f055d4cd4b1c003539664ac68ca1faa396afbb6dbc80ae4c921826a167b94d7b99420e9e3e4ea7d3d5682bb2e5daa2b6188522292ee40e5d94f938493426c3eabe2531e3d26dd17c234363016988e703746a96120b9d8bbcbab4652e4afcda56e7e15b4588f2029ed83b44a24d2703d02206456bf859563044044f1e78190762d681bd3717fb4b5b86a512afaf1bef1ac607f8c9b7b01088fe8fe91ab083da6c5d9c7a716b9ae31c831a055313f35bdbd61df1e327bdb1d6a69ab3be7914ab4faa46f8ad563a4d99030de430f6f429258244ed3cdeae15157577621b586163110eb02b5574ff3a728e9719527d9bb92bf70a9b6aac6f793f201d263166a99682b9ce312559360abb49272f8c0fc17fd0ce063b2fc5c07dd2448903b7dacf784069785ea4673ed6c806b2d0308b8130892943748fc3241a620acea31d05c05f1ca77f05b05c6dded530aec54a12856393b14e8b36206947772ea412ed2fb40ff06ec7a3b3e66c36868fc5d0d47da604b61e0abbb4134680a989042b3825aed0ab179243a1e02e500fa7b1230730a81a5dca50c7e1f43a0c839b3f0312f462c741ccf8dd6b6aa1871619948a2efd3bf2170574af0a5a1023bbfcf128712a8cc2446745ac76d0a51a9cebb4644c6ff6fdabfb8e8674c8553d20ed48cf906f17190d14a0cc9011dea0414a1d5d97cc7b829f441694c9881de47969bc8cd55f11c9530cc127bef75d1c1c4f0c212b25d8b0a2d25ff9ef1a8bc99b02258001d309e96f609547aae9eb9aea7d66c9fed926a1db1f54810267901fd8d0842cf65500a4c308038ff42afc6e61e368eb44cf9785474c77aae1dceb08b1d9704c5224effb85568a41a24602e637bd4300d4b0dc38bb4f2ab7b82671e03e297a015c9e3e8a99f6c15595003bab193a835651b28a479a3bfedc6fe76728322274f11f1fba2a44883302af587a0fed3cf67a039ef998fcba4192a92c1427eccaa4223d670ecac4f4d8138e3aad52a16b1ec526621303b224e0fc81c14bb5b6dd0033f9f8844f7607c1ec6d654354ef604d52040bd1e66dca302231e1a4a8ba2f8a3f8706d653e3336cae37bb15f7d7e1bc3269f392ac09f859d432c4f7ca0dbfba0cb1cc7583f74089d021ae93812e01135cb58daf6c4f7e165868d4e285b2a265175051878b0c4ba168d8dcc19b8986ba346a4dc566211e832fc2892b227faf955e46fc1711faf70fcf9c2345e7ca22df0fa7a95b5b314f07ecd618d3f4bc38e195d2257c0b7c00af2ea78e6a4f99e532c11f9bce3c6ebce68ec60b99e72c70efbe087d97135ecf5a309a915e5ee12908b7182f8cddc92c48358025f8a80ddd27587a23b8e85eda6c09f3b548fa1ab35029842252e6482c10950beca836591af7739a217e137d7d3dbef6c18cd41197a261132f0650c48046ffdf18531797fd82a8444f899f04de2dcb95aed9c1f72bda9c4ba7f93c9fe8a4f52464c75fad5d029fa1b955793bf45a0a282f812726804e7529f2cea109afe5c4dd71efa6d9a4e6c75d7d3a597125f79dec530b0dfa53617f6d480e6b49f6df051d89a8a026d3e8c1b31e6367c87ee8ded494cdc56bddfb9f493b47f1bd472f8ad9a297a891bb8e54390ada64768845c17eb1f8918480a5f6cbe23dfa63c8faa491fec967cb708a8bb5600601c362563ff5169ceefb9a141ff5cf6b758504054fb0d599f80608d8b572f8f366950d3f954574b2607e0c8705cc53a5f2d684c3cec6ad0fd91075f745cbdd1e4d039fdb37ced06d8628c9fe820d3a5db08b6d904b4008f091d7e21c0305455edbbf45713f15ac93d5885a6989b55d105a9955aea4cea5bdfb58fbdba99574344b5e4bd708313b369753c84f4f7b795d9fb740a83dfb63aa56968b38fc54617cb74cd97129b11541635c07d6aaa2b40c9316e31449cdb86946dcfc64d0246d156c6e2cbe333d7920c3d0bd028f53821b4a04cb8a999484ca0081ee070123174b09ab04cb24543e1debd7ba1c1036de4972fd1a3a80351e56bf0d07c157530f00195c1555e8f71d988a54831e223f988d6c99da0fafe3511ed4847860dbeee1ce88640d5292187bff05fb592152c864bce893c454296e8466c575a85a725b87a5f1c7539f598a8eacf3c9693d28955ffcf50611873bbd24c7fe35979c86900dfd71329f167505efc38e8e0ef818412721583d59782301f36362029656d68534d4b1961dd25610a3c8338dee31b163b65b6fbc0b435f1dbed0289422cd1b8f06409df03d9ecc19150a224f8f90ba32536c073dd2bfc0c60897d9a2c020f0d4b003329d14106868ec6156cd820329a4b7d12ea45d49bc86e70acfd475c51ca8803913efd08f771dfd2c5b2ee10c725511d2fd25336651a53040efed31172ebd2a067a92ddfc9641486f91de77e3a90f6ff202e975c42e4ddccbc9763e1411d980a311dfe2e1b9114608f006a0ccbcf949584211b6666c19838e0c8f645c7882b2f050b9623f9fd8e37f5dbbe9a7edab58cbdf615d6aaeaa212837ea171a95189fa3ee9d69a5cb6c02441b18968204f30f28a9fd75b51a934600938977cbc4b583885641e54d891e7484863772246d94febe22589ebc204ae10b452f68d4534518288ded5f4edae8ab54b65878bc408d021c89e65cb3729c151b432fec9338c59bd129c359b4cd9adc9c3901d70dbfe8d578333d2fbdb0d20eefc1075c3503f75eb5b52cf22bce4a39587fea0c9bb52e8853ee1de60d6615593d6275adf804834ca00cf57b7c0eb6d32e1a39c659606cf45c5ab7c547eaefc9c0b826e3700a614bb393f47141d102238d9feb071ebf6ef9809bbd48d3d6f9635a30ea06d8a8bd399785f212bddc1fc52bda3afdc11c50ababf90a6171ccd6e202b334181ef1260b0f22499e03580078f63c388b45c20564d1f2fde7c5ae30c1fb2692c63517cb23420bb4c145b7cbd89eb175f30910be31343a2bc6d3e04e37c890483c77a07b43556b0b3a4c5f7ce607ae431fbc123e7031f0e54f53bb580f1e3c0340735af1547e0ba73254396ed03d9ebe92bc68ec300b417ccf32dea983bb313d16be65e34205032b9e7d4da6e580bff49d063658a0205856159e52297c4d6cc3d41d3f5e610bd32a9661c6996a315b6edaf48e4a304a621fb718c25af9ca321287d353a1b74c5ea167bec2cbbd0e82b458fdf6dc52ebd755abc4bbae65578206cd807c5a7c9456889cb9df7750040d6ed8319fe81cab9ab5ba5d3b18c94c4dbf45881980bdd9b36146a961333f444ff16def30073ebbe2422397b5859c63508fb77cb395e75d980848c489ae1d64b6e96ca722802591a121ac153026a2c2b40e7b73a845b9faed3a99e09a787145f78f9c347a54a5799fb16966980179c6d036b88dd06a110747610938df9cb15718d97f2ad6f5245019f2aea649c7d1d5c7681fdaff09077198c4304d4a24a58feb62d89cf6d4f79145ccca206ea76e72ec1aa63420eedfb9950c1a3e729420ed42bcc3e01b1b856f46a3a16f28e0a73e82ca8ef62283ff4f6207d6b830264f70081915381cb63c784e794a825823e0e94260b194588e304377b6def672e6d74b1836e5a81adb206572279b8749ff0598ba9f69f84064669a7c569fe340bf91def17a3257817cdbe1042ab9424471d01b75a207ab39e18f31c2d17ac4b840a113875397ec1d2b7798e0e52428f21543bf8ac29d78aeb251dd89002d5c66d868e2038eef9d41d03629d6be33812e2d0c651836b2226a9c0e7ec1fa211764cc30540f88850277c5511e3921d9bc556477e95c58bb76ab1b483db38f0dd4ee4b11defdec7fe538962ba95113c05d09541987df907d1869c16f8d3a1c6057674f174c3ddc7c7378a8864b9c5ecfb99ec8aadae183c9f69ee129672bf9124a6f2a7fd80be1f9910490af5ac05d197e706f3861a5ceff1025d573e28d87c1999fb265b963b348e70ef247e1953cbf045506c8c7408f7550943358e1b1b78907ad428e17229f23b89b3603f3ac2c86d0c74b02df6c18873655bc2f95b9012287ca08161c601e7584f773b74b4631c9bed3636b655f82fff20e4de1d9569a9730c87b3fbd23ff18b87c41a6dccc4141fd496a1a8679d4b247e0d1b4e6b9526eb20a503713465f96d29f2eb9f6ed7ce046c05edb27be3882bca1c9828aa5c02bdff02780801c4ee39d4d698e18f6aa09f5f327602a17ed5ed06812475542efa2b29e2786063d7193f37ffcd39d05d13d4a1332fe1878f7a7f334784b9e70afdd6b98806225d2a7e5eb08ffe3d761672bf6d7d86fd5b89cf652b7cc1c5c67e4a332b6da9369e6d68ea526b5d6756593050bc9f1c10777dbe79dc048a9efb0c5f8c607e014842a9d3dd067c0068c651d594a3b6211f49b250a265b9492f1e34732d9d87580e7bb20417b517c86a075213a312d4a71029b255f72447fb6b1866a19bc278ad525f0991ac7034cbc5d86690cc3d931cf370f093a187409799d85cb06fa7b03ad6d71c6a7324615d9fd134783544c624f2045dfd19a4d287907c08dd72fe958fa50f3ce37e6eec3375ae0ee5e985ef15268808857a2b6e991732ef98f6b9b3cdb7a3e57f8aa07ae71c6ffdb6f6297279506bc71e4c2434d1ccc5dbaa096fc96d780efcaacd2c9970a99b1cebb6d07a8d19e776c32589f0f390b20fa249320b310a42b37fda82f26aed5e8c852ce3c6812f7e3031efb9a7f3b55e6487096caa1001e091d033862c5f59949471fb7863128d266728eadeb00d21ab2943ed65d0924fe9bed4aac9276039a5b4fa2d331c51c943460940cfd8887368dd36c4106748101ec2771ac47d6ddf0fd42c09a6212904c3a4f3bdd24c8c5369a340e8230c6dff21c9b7bb8a3ae3781ecda7fdb150c4dd60fc2fc8a7fdb162b2fd654daae46fe9a37364aeabcf064a9cbd0c2207a2aa3936b5a83ea31d17c0d58b5d4fdf2c90949d37febe66c6b5dd14356a6fc8325e4418ee6be17c3c54842e8ae3737247bf35debfb03da16d748303b9484faca395a6ba11fdb47d4445eea2e6a0346a1dcf761c4edb0eecd4b6b0a982bb12ed4e592906312f1f7aa211561a8e0189b5d8866954ceb31db74c391162fb8e7ab4e65256e2f503591d70d423e37fcb6a4ff5fd15f532c156d72c0a1ee11ddb20f2382a762e8a9ed3932456de9df35cbd1f953ee3fb0fbe010165158661751d29e4d653b3110399a8ca03eaafa441030ae21f875fe2c731a747be546e6a059c7c87f64563afc3f98c897098ced67e9cad036e167c7f41aade1469a15d3cc047454e1d31f12e6e275c113a2ad8c2fed9505839c7da1781dca4d6d180eec1c9c3be3740d462a4b87ced13a61250750e2eba8addde2e64cc73e343777812f04902f886c373169f51149154e50863c9ca634746723fc8c7037b87aed78e669af242ea569c6a0bdc00d43bfc208f6b2d5bee0f2f45699107768aec7d22e4f4094407f745b93e97781fee3f1067487f1fbd783f18b60a721f08fe4097be6cce2de41c3a9145c1372eaf55480f2462f5803ab34d2cd1f5ecacad36dbf9af94cc75ee103abaf9c4e197e5e67169feb2a35fe8dfff97eedc88947419c83d70a8b8c6661481467413a7cb195e5af69f77fa6d27fc53d95f530ad5578e2a9c2deb32e87943d7b4c95ecd01afb7ad0afd73532f9965053d2a77df0aa3435120634336d51dca6c8d2735a413ec6886935a38ad1d2ee097a6bc6e0e333def699ba3b90baef2c9ad71ac92b93c1047d0ffabc7a55f856bca93f3ebabbbd21107b7149d48114a572456a2c55d68d5995ad55b2307720443712ebb502425d41bfddd742b359210d5c73eca955be3ff31f01ce8f54c456d8483b360510f5fe323f393becad2b39bce57a59160483347d2a4d6bc93b5ff018cabd2cc1322f4ef7bd2fc07f33f171663dd661304e1e4243a8f7a0e0b24b14390f4ea2c077685c6b9f954d45fd26ac4b0269276bfed04cbb86ca7ad290ebc97e208cbb4bcb3978cb97f7bbe74d1a615250a8b065d8bcd4aacde4e2b96e7a1dc3e3afbc6457894dad26c08076aa914f0ba01a6f61069a78a35a3f22c5e0a626211dab76019d512a47b5a06a17745de35e0298aaa520a2152bdf54175df99f1a97ce70ceb313ac54d6286169dbc7901127c456b5df91641c21a390650e19a5e4a9c49e78d07c8fd79ef0a3e6266060e498c7796016ccc1e6891c103b44cf6649fd1d0a8d80377e3751a55274d22c9d4590f708ca9938b015c0756b19fc7b55aaafe47f2f8c3fce9b591956202dd722dca77ff29fac3152cd857484fa2601ab51db913e397d529c215bc02f38808019ec3168d4115b7f049b9cc042b85687965e7121e6bc87184cbab6a41b73f227736698c6fbfd7b2a0e556820b3af3938c38a3fb0ae59515309b4c91b966712e540a43e68aaadf3c17028b752c2fa59a1eef5d5a09516dce5e8fc8923fc9398f7b7cf96443920295b633bf6b5584fa88ebf98ec4bd066ff1e220ccac8f56338c1c7dce599c2c7a14d6d52bc342d17ecd01d2a3af9736f4fa7d96444f038bd638e230f421c8662df253c827c92e1532e413d3ea1913e153f2e476dc3ce09e52abc3f2d47a5387ac5b774a882f87d784d822d5c74d212ed62eee95d077d14c3f8134b41698a9b34851ee75d2bd2560fd09d6213f58e40e7ef9a3dd6cd004c863b3c88e366305f6943482c4bf7b1608410e535c9a36aba1ac7debcf626c107302c4b99bf112650e9767603052d721a619a3c159305c0f1285b7885dafef140cb1ce773e21d115bfeb09866cd361d76ffe86addc517cb5a09d39652b0e8095f1e2db6d4db3fc19a5274334de7679198e3f74032e81fafbd2cf4cc8c2c8743634e4128260a8598773b0a87bf3032c4911e259464cb27e363355a4b720081925c38faed0515dcad10e6803c6f0fb2e1c7e12d6ccdac261b4f61b6ca0447f018aca8145809e51ca84be86a3729c509a1aacc61306f6107e3e8b037b8ca2751e4ac2b3535d150ad093ce4e3b4597a3138e2a3a677cf67f9be48de44cabc8a73295851a22d8b1db987b943e14c3d3c065c7097f9458fb3d2e19357bd0b3c6f5b888bc9774d8ba2fe3510e1725c70925ad1d70cf8544a9c6bfe2240a1ca24a5a2507672d31b6633d473bc20b380600fd355065d7a2847483e5c719ecd76e4592812745517808147dd9c2a87ab1a9108255d1c2e58a34e10b0fd85cc0e43a88c088d95a10f52a46601d09464cd58fd7b0c64972a27fedfd696066a2901c51c4493bd2050ec0e668a49c445c9a66051b6964ca3e7f2db35741dc4880cd3f995b1eea5d4ebc76a4af6aecc138d92d48587a69e8026cb2c0fe66ecb37352f35792d2a622db150d6f5bcc6308b05dd0e4a3b7972d05020cb570f24200a9f21d15970740bacc67119e2b77ad02094511c28616d5837bb96bb5005d0732f769ce59afbc511d7d99f38bec675ee1acb8ef60b32e593ffcdeb7268bf4cbaeeb2e533c283440bd3569297836b4f9d67ed064a37b9542f1474d7cb3445ad47580fae772893607eb29d64b8c6fcde5b543d0ea1b0aa72093cdede472832ae87a4d7717689e7df144906cc004f4ad8d6871c1b7b6e36e2d83eae122c330d3329035642d4895ce99c7820160f3e41932f0c8e649944a3563471e169bc7527491bc86193ff81cdf4375d310eeb2d6b4b777b98f8a4b068e7218024fee652d9c9d974d39b4367f819d990d9ec09ff1038d31bbb4e4463f0a44ea8d5b8974cbbb805998a2f94383e054d213c12f4db8eb9fc82657659123fce94cb7fa3c6772abe0ad55c9cef2ce36bb06c2c40a0875d716713deb7122c2ecf6c35d0244537c32fcebbb9cb1a6c0ab3acb4bec9a76c20bf7140f924e8ecaf337c4623e4d2cfdbb669c2972a3f0b7f8aef52152c053e235bcc0013ff671e5f5ff328d1a6d383029006bb00e1c5c57dd80d515c5e5351434746bdfef258e3fac55a1afdaa098fa9b469cf470e24eb6f8d29ca2ee3ddcaac5bb397309d748036853d1ff50e0138dec27a930b7360a3d452c4f03aa7b728058304c5a4a071711631ab52662bccb7ad70acaa50c92f2a50430bc2699cb9bd5ae999f297e27f1be956c2f8e2ab63eea22181e3e158747dea1c635755764cd95960bb1d3fac69ad8879f300f43fdd2dade7b6f29654a524a19b20881077b07fdb1f38704e6fa49fa40e4cf2cf6ab951f85342430fd08c43ea604ee8ffd32dac0bebf312fc84f7eeca517665f28e31da1be8d3288fd6ecb2ad484c9f6af961cf37d3639831ca560e0f24a326f1f5aebd2cac6ee5fedb7fad6dbacb52e6b1fccf7377bb5cc36c5a890ce12f4b79f4b7eef4202b3bdf602916fff7e28df75dfbf2728df7eaefbdd095afb6df4e38757c96a181238c84f96b148c6af562e4cc9d685a61c73cc5819fbec35a24923a44f947dd82d1f635c0e29bf1676c9dfbe5d52b6d47c7eb290cef7953afbd66541ddf685f2b9b751dac942b8ec5dfedbe705b19f8b1b21fbb0cfe58fb9631f66dfaf615efdf6b2daedb9faedbbfae3d77e30639f615f2c92616757bbfa430273134d3072d242d162b41144daf9c2f92ed77e342229296172943f3f977f4f3469d0100459bebbb42e24304720f233b094a7fc5c4860962f3fffc2fe8200913fe5cf8f68522552b4641b394a45a923058315189a3211510af2eb4f17fd9094fae6a81f97c0324757fdfe76d58fefaa0f66ff0f09cc4e148be2f3b03de6b427f7db5ab31b23f7ae4ccbb0cd5ea4fa91dbb42c04a26915054ed6fed6c9ad032b02cfffa4d4e1c2b2b731c60f2247b89f1049391efdf11322b39d1cfd7450195dd8db7f4d72f473611f1298eddf1df5239aa08c51931309285c3210fa6dc3bfbe7b417eb2f4c23ab911e8d3ef39bfeb5276d1289426b996b027fbcb3a997ec3c9f33136997ebf540b64b49ffb5af8960b0173059139be90cef283fc64f969f61322fde52744e6f8fd84fe29ecc03903f3b1b7af4d4bbdd05f49e6c69e621f100c04397a21f6b17b07f6f3b5f64299fb72417e7206622ce24179ccc7da132285c8dcf773edb04f5f49e6fa3590f94a327b109983c83c33d9337cbfb5d27fa55ae092efd77e193bd6185fee4202f38c09d2efbce5f01503b3c24164269a20fd07bbc7af4ce7107dd944997e8cb0e9635c8eea91878c9bf7e476ccafc3cd0315b0bc5c8e5ec0521ebadf7fdfb91d3588ccf6ed174e212328c9dc55158916278d2012abc261bffc3a4bb5d04488ccf4bb0ed07e6291fc9f6823fe0b2bdca76816b2706a0aa24d9b1715350e21f5a4082916a49eccc1dcd0c98c38f63d6fdc20012587208e1c0d0b55578a052b23d8d48b1ca59e483d2183f9e0162842c74d0c4d554cd1c41195caf48991dce116cd51ea09d3c4a24915132c1f8a8ce0e614e97fa1771f5c60c00c1a288488f29282a7233f33a6cd28b961c3b2196101c8c99391ee7692c4499a6e62076b628593344ea8c83e394a39b19272e745c09c528709b461c1ce961f9690c28c991ed0a0799de9260d21327206965a4548ad2047aa490f6646861f2e4fcc9ca953e68a16288a1c7999254a32a9252d34b9b2522be869828d915a0244fec9516a89188c0c0f9898172f2530312f2ad5e444d672946a52220a336384d51378ee3ca96192b1d24f2cd41ca59aa85a4a29a594524ad98f630ad18a5d2b864172b395a3f2da89ddfb4550be8c5c0833538fe648811eb00239394a35a5c95a46ffc3b81068a6af65514eda3ef4bf9a070383e7471adb9573d298f4a3d26e96b1ef74da218d3286f2bbf507a74d69532ad5b425532a4794524a293582bd0478705fc1963451690167394a35b1905b4ac955ce729452f28409fef532f2194637bad70c29256e32cd514a499b7cc3f890c3970f3cd8a72ff6cb965be68a0c542c104a9ca450a244852c7a98022b52e7e21027cb117982b850d43499b152e4604350c39593a5aa8afd014a9215ee144998965401270a3b022690c0b92abc99e204189233f648981c6eb8754a00830c760629b709244c6e0d488a5819acb0b273a7892594b84d86b04cd81481e6ae20c6668183dda2e5122102ecc90b728e38b958478e582bf4d82bf0604d4e5ca6aaaa226c560a2c961e6e123231783981096e1123b0384cb15e8cb0b084912497092cae1057d80a746c9515582e465c2653547eb04d94e1010cc684cb3d024b1231d81b8ab4104491a6db258b0e1516092892c811011263dcdc2780b04444d91774b836d8f00309ac15a72857052a2cb1a2820a9607ac5b458aa939764d122b10e236ad712365b5ec70a1a0b298218610b8808226f7881493915b822bdedc7962654ba0024b4584a50205174d9a9bc498a72e4ed0e094f5648fc882e172c97a72a9b2905827f6ec90a7c8133b2ce102d5fdd2c6b6f1c10ec1c3942f36055b4c90c5952b9505958b250b27ac49164af46461ab98c2481d3671aed5116782b050a8b164cc189103096ab82f64598345952e5840d182c50a73b060ba46aa1083b1289c608c093c1883b307636f2cd49a28686c93317abc6049b6a8c172a3f65499b227ca8db387c985628f91337a6c0b79ac0b74b0e2d82790b860de5c5963078d11632c09bc5c24b664c172e1e8a972f7e88962023d4cace83102464f993c4cd0b13dc4b12c20a1c41b356bdea04933c686f162a3d8729560b9575754997345947bc3154cacd41546a8e8b933e4b15174ccc4b14a90b039bcd161cd6501cda562cc0d81172cb68800cb94155560b022ca1d6305136bc60a2356083df64a9e3a744e10e7224162046f745873a5a0b150c60ce1a5862d3460218355850d561429584c6c142c2362f414c9b3023a9892385b90b82978e3c39a2ad0d81963dd78b1366cb95eb0e4a9124494364ce25461c45eedb177a6b874a2b84a348145954d638475e2063bb226877f69a0224d0e5fafd7192ac834bd627e4571b0478b930bc6c95ef550afa692f815114dfa6a054de855144dae982289d3142f646bf000c164c323c4120d8f122b64160dbe56e0105f81c338d53c6a98f89b16faeb9ce03c7b56b842d2e4aa0524779e68536a122a323c40e01162c3a304a5b41dcf159e26ec566badf63a6547b20dc3302cd3f268c9f3847118a04d7a795a6c32cf9b9f9f9f1f8cf3d4c92327cf1e24ad56abf5e2c5d594ab16362dc338ad083c5994e0d9d2240b3c3ac8b992b3042381339183cf298325cb997026be14a9599706bbc28d224bf30163c267ec133117883b5eb21ccfdca1e14e95a965c1b325164505e09192c30d4f933d39bc57399eb923e7cc1d387782c03e211aa7c50341adec42ef31cd191c11f47f39b7691976639aec5edd566bbd3f2a9caa51762cd336ee861acc7d1877dd3f08be5e46463da84c79df006a4a73a56f64a7aec1dde7766f75f7eeae39d09a83df0d1be5f946797e5d1331ee9a468ded938cdce0c8be10d7cd2b610e51af9223a5db6f238ba5b5be043712ce1b34699284ec2feb67d8fd91734cafb58db29d3bab97f7bf491b98bb5d2fc6a13be4d6cd8ed63673ccad73b5725b866df7c0d9fe4b7b652fec8757f75763b39bd06ac7ab2c9f29cb194a35f757adbeac5d3fec059191959535f1f5af3ffaaf19b386cfd321aa548b28610ed17f5a0387fd7cbff6ba09d6ef87121c39efe350ffe6c5d8a3ded7a2b2282caa6a750b7bc7e7ce31df6b5656d61552ed60d36ea94ea8fc7e2aa97c295b4af9c5392fdb9b7c8c79ad01d7aa65b1bae63b3e57fbb5b5b5fefceadf956bc9ed23702ade42eef715620d4c879aa28dfafd1941ad69caa11be55cbf4c4d2c0ae351610604942c73a6cc75a8cc4ecff084a4b13aad4778ec1bd968b8e5d5daf2c3b8eb1a77ad0ef3fa7ef5fbc5d7ece6312c6d6e47fd227737487271ab9313290eb13919adbb629996f432d3695dd661dded9eee86bba19e2822fa9d494162b07f5f8c5f5c5eaf202120a064099a92737df35bad5273a91d8803d8607bd7eadd995eb1ef34aa23583f563b69a451c4f62994a7d0fca2db0b7203e5c66a0d2c9426c3ae0c1d9eeb67148be86b8025f64d123a41c8b36c76383055a1a6a850158a4dbd2128fb57a35c4b6a548daa50f2694a4b85daecb44fef6e2aa750a8bb81004a4e4921a72e1b9753536c72fdb00566ff64d504e96f7364d5ddb09c6a2aa250c9294a8536e51eb2146689ccd297dc5fac53bf85727c2cea97de1784667d8d511f10602877fbbc176be037ea3e83bb49b046d567d36464ffec0b6564ec1b1206cb27a13b1b6bffc8ed5899d2343f4ad02c91e6c9f280b9edfd9fd6f0a9d7c8cd8c081a75f55e119c41c4c77b0eecd7e6e138e4af7938f3302f468c51c04646b9bfaeb34b5099ec6753ab6470fdaedfc51bcebe07418b69c0f2c3a826aa897d9366b8a04ac10a4e98c1d44c3acaae76fe06bb7774764622306a23afb55b88671a1c487bcfc0c2cda33fa5e95e4b579a48f20b42b3e078d507a664f92f050ee594906bc03c8a74e89b49d32af74fef7ed704ea34ad50b0618995eb875d9e4e0da047f6a3afa98915ede47062dd0d4fab598709d4b4f2aaf6924175c08e3bd1c10de54e21100eb9bfa192dce987a88286caa13f6590fdc3a606e0c69f1a871cfa53eeeb4ef287268cb853cea07c883de3635a837bf7bf5fa8e4461cc9de080a4c4c4c4c473eaf699a578ffca88f34ba691e3d9a475add344f1e71dbfd987f249e81855d483f40fc71e89f6b07cef2b1667d702ca2afc9cdbf06e27fbffd43eaec5f3da0407228fb03f2b97664ffbaf37625bf92e9edf4a6ce8e658c89606d224d6d56cf335a14129a207d70d2a060f8edf3fda24450f045372df3f1301da2336c9003961f5e14b0cfbf29d906bf7c14e8b5b57a765e087cbdb8afec4202e242f2af5fbf10c8d61fce665361a9c724305b8b06dbccfb38e4efd8ad60f6215e3d5b7fe93747ce4f00a9b4de2218dcdf17d7cf82e5874f635f7aa5be70d240541695fbbf0adc8f834e2f298b9a21501625e34b0c0f54c099995c3f04caf427a7e395fdcba66211fda021b07c1c34cca632fdcea2e2126892dc2c2abf708a027537902814caddddf21b4b3a44bbb91cf3c338fb30a6c97d63065118d4ea846ae0a043f4c3edfa7c48733b0814901d5c195078ab11270524083176609f7e471f7f21fef97cbe70e630c2b9dc175e8cb58fca26cbe590d9b36c924d2578264cb066ff7ec422fa187cc1f237eba520efdfad4635b95f72483e56c2dc896a724f5042d92d4a324051b1ca910a558eff94e3fb546e2919a272bf8d3684b4e572b862f49064964a7db911e4c7b7dc08f60b3d7af5e9ad9b679bf4427f97f48f55c9da11c22597ed1cde2e976c97ecbc791cc7433e752ab2ecb12c7b4c8a942836510a9165d4c5ae75ecb3b71c12fdec2bb703fbb2cf85fda663663c4139f3b42fb91dd7de2577935193c67d99464db635dbcf031570bc9ef40662ffeeb05fbb328e99c3ceec7ec4ff56b93ad244df66c9f6ef12fb97be5b9192fdab8b8a55ace50273d1a2f18b4db29934688e30381d322adbaff3bd7d5fb6000272df1f8843e276dcaf2778ffde98b34fc7cc7182dacc38a8d5b64ee87543041f3f92861c71b2a265d2f83269ccdcaf59e0dc7664c36eb7c5f940eedbfa9b643369704852caca97cbedb8b8b5a37efdd1d93252f791513f53347fa72a4c394ac590850a56fe4935249b95957595bd68a1d6f16b1d5a9c5168cef9d7b7cbf1f0c7fe6a3b341fee351f7c5b139ce187af792efbc5095a6d6a5b1099b5cfe77d7ce47dce0bc19cbda671a1f30092615253ea64ee43dffcb5d7ac177b29db2ff4a7dc08a1cb7e7b739fcb02c9b0f76f577f7d211ed967df7e9fa78c396255d89d680aab33a36bbe957a012b47a917a46401e428e58255bedb9efc394ac100276bbdb54fcffa332066c7ecc718d85f8ec750ae9be442983b865c48a0ccae1d33cf177281a51c73f3a83fbf70ee703d98fd8b6cb4385f7efeedd9c8e5684ab1eab6524ec7ac2f65c8e998efb28ff1a85ffdb1ef19a49f2a332ac833b9bfbbb4cdfa6462699f4b3079c5326d9b4166d332ec8a500235ad26f665a3750cf10d54958aae40a9144335d9f4fd9bd193ce395a767db80d3b537d5edceb0ae55ba713e9aea2aa7a9d2ec54e63396555cfee57ee9e5ffbb196f432a361158a8fa01005ac7defae65a2268724ebd7b1c897724c416f755ab51afc6ed84d557577f75a6b9d23a03d5c2cd336231d36dc755dd7753d66989aba1b36726a015bac6a9b731c56a9bbfdf68e92b1a55f3df0bdb39e898a6d42d7e51befc51d6f5f8cc14f0204635f6a85bcd85e2cab75c35dd7753306143c12b5567797d46badd475907de78c7aec547777f75a6bbd17e3aefb07411c5aa2bca913b1facd2cf68d712593b9db8bd92cfbb06b9da6ba8ed16ef45a6badd473f00c886c8c166bb595ced8d47a75afb556fbc5bdb6dbbbe4156dd4770777f0bc0802207bcdf5fb58e4fd3fbe5b09bd97462aabfc6299f7ecd9b3b1110c466d14fbb65012afd5dddd5a6b8974ed1384a86ed8650c3f88e623e84244b4acb18b310ad82725136badf47aadb5de08fac188cedd2eb6b7a3ba1763b006257d6f7577ea1fb9103008132b06619ee8396787b1db5627f45814789b52be9aa63ab04ac7be58d2f49de2dd699e6aadee3ea17a4aa982d675541bee2e7e7579d5971a4d66d9f3fba32ea4a66a3aca845cbb2ed7d851fd11b16f7717ac03bd2252bfd486bbe1f844e4823b3a44a7a72465d7961c3c42ecfb3bbcd0b535c3ea77336c7e999a7a21f03617dcb346d206e648923ff2e8813fb681dcd103f740bdde11193df05bdd566bddabc3d1be3541da94cb516badd5c60e6ad7ccb3ea6d39daa9e35627dbc818630d2fad0dfed7ebf58a7de514f7c936576033faaab5d638e4debc436e23f14a6164ffaa13004660a7a9eead6141f4c6c1825883cec7c2e6faa52073f8b16fd339e7a9babbbbbbd75aebbce285fa7037dc4ad45a659d357aadb556ea598c62df24ee9473592d02bb9d79f2e8f58280cc3ae23e02c421ff2004ef128007f62ae042aa9dfea5bacb2adbebf42b75cba54a8dc31d72ad7bbd5254510f3ddaa8565be264fbe18b21446211fd9f2811cb7318b1366c85d59901072b5985037d22061911455f5300a534ea540a707f5ffc3edf3df87a9752e453eeee3855a37c1213ab6416ef5baf70dcc9aa2064550e25a592589762c522fada172c9f52d1482fc5c2aa02024a1659953d2a86a8bead32d76e015b54ea627aab33f1bbe188a77a9d26f0d8774a3997982a21fb7727055ddb5dbb2031f7628c810a3c688a6659aed3361f2fd221ecdaaf443cc657c6beaf3ba91576eed56efbe6f5a04354f31eafa91e5353537d2f363b091294720fc97d9340796b74fd0deed075d706f510debb61b0bbd8b958a6b9fbf7c518638cc34b5454ecdb4426d02eb617cb76c061252aea6eb8c1f8e489fac558a66d9c52f5a1ebbaaeebba8e0419a8a8ee869faeee0ba397da0aa2a9b55afbc3da21d756b7eeb5da7a44f528a9727728d5c8289fee24973855adba68e97cbef0725d47353087dd2b8b8e99efd7690610c453776bc9217d9256fd45cf9a2bad9cc945d04051770bb5296d2a4b2943b7ea80940e4cc9b2034e59034c5963cafed30b93dc2af7cbe8148be447ae017d14e990b4ca52ca2cdc9f75a92d74acaa5c3f74ac3eb29f467505961f6a54474ba146956975abec502f14c95edd2a0345390ab4f8011e932b9a1c7639dac0d4406d9d91d1eb05821fbbaeeb2177fd8de321b91d314a666d46397dc2a5dcd12bd8b53dd7d003b9e5fc3ace16753777293ec59fb29c69b2f43413f4a926fb4bf7efc6ac9e69a69a59e37e7fdd1410b3cab9cc21fab99627dc13742dae254da6b4ebfc63d80fad9d6c0a96924db1d9944cb3e4d0b54cd1244da64ce58e2ab23d16a6977a111168d16badb5d65adddde90b318afeb1536df818fc26e2e16eaedd9b791bf4b877eafefdf0e69003086c2081eccd087ebe5f583b90db659c3ef793b1c8678db1c87f89c6be44165cb9b28128f75761b876eef6859436c9d42977966fb3fc9a727f3f1dfc622af717ceaf49142af7d70b4788dc3fa7be688742e50027fb540e69148c5cbfea3441fa00c042a3a61039a477c374def0050aad2d07b7a49c4ea5f47b6db531bcdbbbbf8d89eaeeee5e6bad93041b6e2a056ef9f4762f48c4dcffbeb41e63014bd9fd9bf385fa42dd0fdef042e00469f4e697ee85c08e83214c30c4edb295163fc03f51415d9452762b7778658cb1c3a496b5afc9f0e6a9798c45336ce1db2a73efcf0fe80a037ab70c4085cd9c566e298c5bdf57a973fd29e787e3ac5e03775c70ab139a43fdbd94ebfe1a428b1fe07edcc25882e04a348aa68075fbdfd7a496959543224c4cb9bf14b0ee16323356eb178416b5bcdb047b3629d1aca6b99de2540366769b0ad3463e60dcba715488037b2d6a778b5cfdc225a85cbf3dad65529ca237c77d1d92434a406e2c7e3e48f87a58c0c28c7da7b6395ea84c35b14c77c3d7cbce79a4511f8b33dac836ebe31df1f9247ff4f31de5b850d6b89b371441ff1fb5aaaae801d8500472ff47397db2efc6227f0cfbc20de4eee881dfea81ffac77c3d55a9f91fbd36675d395e9034de61511f32a4e2db97f6689555743c42cce6582f4f113da34b5e490365dcd2a2e48e655eecab4839dba41142d9ebe8d35623cc59e7e0ccfc621ec5b783482d80379d85fe0616f6564ec3beca3dc0818f68db54cdf028f3e0e5a2541b8b103fa1d804cff4746a6ef9365fa8549461ce7853387b26a48d6bccc8b2d3ba8f4b3fd5dff7c72316593279c7295328928637f2f51bed8c55edd927c719ce7630ed51034a714879f5b84affff15cfe3fdf7aecb91ac873f5e76a00d073ef03e8b91afaf381ffc547a4f540bf74e4e3b91af0f3ad77f9e7e3e75b2e1f3edfc273f9bff8a523179ecb3f57035c7c8bf7e1e25bbc7f8b8f480dfef968f12f3e222e7f4c87ea2f1db578222eff52f0f1e261bc03e2d1914b87eab71ec64784088c87f1bdf8968e5cfcd2910745f011c77df1a805baf0e2510b2f1e0179f1087bf1e8c75b3af2f1968e364fce4fa99230c1fad41bc0093036e563823d306883e9cfc7416b705f3f05cc211c13acaf55c1fe3d9decbc4fc4973f279671f6f4a0d3cb31230b7f9e1fca276f08add1803844df08a625327d2732a55e2c92d3648231872fea3399b27f036883697c2128986a5330a54734db21340d4880e58715a783246784b0a2085043022c988200bb817a0e4080186e609b065058fed00a583ea594524a69e490524ab38fd1831cc618a3b66160c700dbc6819e02705b8c34aaa4b43ffaf2d96244d1c1cf8697c418638c45780b72e2e0026d423864004281418b0dc885f642c6e9132e5dd0da06b044f7627be5b1e0c2d886a08061c1d6b179d16d1aec09ba60e3e04dab636c18cce0c2b5c5a0a145d00636015d0c360e6cc0196c728ce0bc8400d97c4cd3ddc87106518e2fbf2b611081e537a59452aab58c4d0325b2fe6d003c5c6f7bb1a9dff66aa235d85e3050a16d033158c6d911001b57446eb0bd9460f95402404883cf7b19196010e48a312ee862b400c68b968b1640f8c787037de204e34f1713f4d24bb7f7f6895c0e0cd4e2714c17b171eb855e337028a0878f1f25a0a0c474c4494a96818969a638b520a7489902c4e5903d48f925a6916470e4ec79a8b26982934904476413c6524bcd144a013774b8310485275828280df9b1c2ca8d2c2218993132e10714ab1f2598e073c7c968ca02667c9941428f28543d7c90c039218fcc68d2e355e625020e2b510d0e0588b02d81f5924c3e88a2888c5e2c18bd6618694ed421ba22013c0382ef02f84260664515684501a11d92843a2c85bef6daedeecfc9e5b850dc2c492867707e806470cc3c25cf59967d77831870a6c53ce73797437baad11282c6d8cfbca4202d0c0a83b296655d967d3868cb3b2128872584f4afbd37ee64fa25056517d6c5674227553ff392baae6bb5ec6b2774393421d3bfd5bebadca2b6304a6a89d93ef3925ab715b67296354da35f987ddd4e68e530c9b91c5b15a25f522b036d404428e01c7eda6ad9873828a88574b68fe3a4f1f33d6bf41c92206cb203ed7ff0cf5b2f44216fcde5f8f9943ae38c5f931bfe6467a52d8ccf675ed266b5ee664fc36dcb99176e597bea855bf6d1dee7af04e1ca0eb4205bae5fa894b7c731339fa75c0e9fd7b2b2b2acc8db97b465ae33e5be213903a3e0f8d43ff39468a6f289d22d7bda050575b8d5c25ba665f6ab10ed338f7af45b82106507f4370f07fd82d0dcf5a93724dbbf958764626262722135a0e1c280e32300488f122f983017841c8ca991024c948b2530ce510a0c940b1ac06c712103982b645c5803a68909ee295accc1148f194ca500428235396bb0abc0c51078f3a155678796121b5a1481b91ca5be8cc0096b394a7d4982efe09f2a6cc0581451700c2154802f9bd614d87f6871046e3438087cc7b4a0c058971660b0dde2e20a5f2c4074bc5469517991d2f201df2b5a64e992670ab675701250745e14c13707a039d8e628d5e5861c6217497429410e1f57813b47a92e5780cae09aa354172b524f7ac8d090c37fdda777c58fd9a543e6f8fde498437e6440d49ce019fa351cf52398efc7d068aa071df294e61045a107bc4d30dece625cbd97cf008620fd05ccefba4887260e29259df3f33141da6382340337b8f354c0a4c124673b1169f487734e1957e0ce73769043196da49c722e4d29ab341b3fb168ca3658e6f027cf973fd146cc22782e19b128462e030c825c312ee82c80f1a2e5a20510fef1e1362dc3aeadb1281671f471cc1af48b71487e8c20904b734e39af2111fa8cbb467ca13d784a29a517e79578344d6a4ef07c6dce386577c7a739242225a5d487062dc61af4e5df5863befcee4b201e08a69480162308734ad94108ddddfdc590524a638c31c69e4c9a4610fe8557dae897d1bf7eed9e12f5eaf14ba173a7a029a57fe3bd4dbddb7bd23975ceb9013d408e10b3d65ae3a431ebdf5823c3708e1cd24fae1f2386710b58aa9f17d656961fd552bd76b56d6bd8dedd400f8823e7e73712b8fbb7ee966d25d9e0f0f31335d003e234a1fde109d2f03e9df369831d94a81fbdfa309ac0f3c36995ed19ec02e10b3aef8740027c90e5df1962190816fa635efb17ca1a7f831df0a4534e8ef1b153d2bc82e2d4d556acd65ab3af2fa30d98adb5d65a6bb5ef66b4ba550ffbcccedaf58478464c1554f735fbbe24c5b8fa0f3078ab35c3aea5b8d57584e3f6de97bb7badf5bbae5a5badadd5daead6bd565ba99dcea4dded7aadb5d65add37dc755dd7755d8f104c4ddd0d1bb999aa5a88a0a014a972f74ffb34d73d63125911a84e80fbfb6211680d07397caf1aaa463695b16a42a5052106864b25a35ec05db451adb576e6fa75b1c82f58ba383a0a436e755badf54b6de8d7a665443c8011f4dfb4cc8522d8ee6d83163fc0d14cae1f1020fb90770150c4b2fb191b603c066af1da17be8bd6635ff87af18d617c2f8c8c5aaf970b106cf10fd475f8fbf9cec4be372e05a1c5a8f4eb1a4b82cea119100000005000e3160000180c0804c321b170246771b60714000d6ba24262422e1ecc62418ca4308e8294410819420021c010023364354e004537f1204098669d1d42ac3462d2c53de8a8328b40eba4ad3dbf83fbc6b37bc8bd36424f55ebc4f293d5ac06eec74ab957233e8243f47de080008d98030f1a84a231ec52f64724bac43872d6f2bca42a59468ca3249eb08c2546741f8902e7e14d890d6a44bb7291f1d40f4a03b09bcad3dc422353fafd8586691e58cbc31f877826a4bdf66b2089efbe03c00b3969af6f91f2f0c7eda3299bc75c8d5b483d97c957e62b6f62983c4bf265d65a21db8ac137f5db83dbdea3a98df1181b572f7891f20ef5b6a62481036f44b20ae80861f430557b8d223435de8b26ae00735432a3b4fb3610bca06415d863f59ec65c21a2bb728fddefbfc8c17d2326f79ea421fad4f1bdff0bb7431dba4c6e4580faf0cd228b00babbfba569b1735935a814a3e4c3177bab6dc53632b644c0798ca5422def76f9f86401459dfca7cc7eee1a4d6c1fc2d27dd76502522e208ec03de3092af7916cde6e5cf2794e97380101bf91351e7ae7d931a2baebb8c7e9e8bc6f71c6675496b04b6721c04e13d6f8730d0ece03f4d2e6b28444358baebb7262e6ef43f5fc4af6dd7d5cf51d39082ad3451b80bea0582330b10d78c4423c4a04b57c04fcaf5a5600ad745d438966f65a3e04403a623e0997f1c170aa6d5da17521552b685912bb68ff58d1a57e8a6d5714cf55efea284be6a8576f2b96613086924aefeacc1732c60cf1c1b534e152f57a5f81d83c61d7119e7d9fce517c904e8bcd512f65460242bf368c1479d7077615e42d189974aea3e75d7f96ee3cc8ed2e83f6fabf5e24572e17f50ac8cf40add54297235240840ffe1f1cb6be09b4f9081c521f00d48399ea84a156e322b2bbb71b0307d927ccf9fef2de5c29777deb9914dbf270f77ec89f9b904ee1f5d342cc7e59a1567dcd172fa1308ed87e1490a364abc3ce7cbc4795ee460f84872d4bef5f3d1362e133e73f305cce160d78a1952462d6ba5228b6d4b0871e235dc1e5ba1c7ffd3d00d0c34309645e9bf7551f3b4b32df397c8fb89de1e2f42a0d3129941696d27401516e1e157a7e309ee9716c634d880bdeace90053991f97f68119bdb28f830d0d8b9f8a0c3356ee029534d055e526660c481747bebc5b6a4ed4df4afd6ca84f8952209acc88dea0d77f84477bfcf236c1e6660770210318c90998e54b2981cd966aa7a1c2b2f74236e48a801896ce192b1582b804beb8d2619014b0fbbe8e3c99c24bf0921e6c5d61d673c5410140a31c1901088ac937ab7100e72dc71901d49d5b2654aa17126f8d801fb35f165b356b6246ad3a6000514ef61920e05255e3ff12e94aa888c5a370e82f8ad67a9824fb8042fc0bdc4e5881254e6541f33d84a995d468bcc2cebce44acd81b1e1d05d1d523a05ee5d40ac4a2a6a72e2d8fcd2f06be15e25d04d1e9bbe34254754fd5878d0d376431022608c3a7c14dce8e6054af0fcc7fc099bc54dc1e4bf63fd9276550521458a28409feb32df3178c245224cb496780e32f00230198c00520027814a2b589f85039de2e675e0cd06c6035a1f67579babc59b64c546b75aea5a65c78af224dd5a99d32770c35662ca6c3f1af8ff4634349423565aa85100d44c96cec5094d9ad7ee46704119c1c83abf6c7bc7a26d4da74c537f062703c566f6d368bde2171af315dae19a996e2ba2c145c425087b2ad063ad355d2badc20ada21387b28d4e15d235d8b63ec805559320f971f324de5e92e83594fafc7cac296605f8151e0f875c2153256a5545addf36154a33b33cc7a25252baa0dcc5eb2c4afd052995ddbb1f3f7c830baaf519365a8e6b9d634ab99287f84e0198c1de0b1ba87719fe8dfc083f40e5ba9ccc9980f28e33c72a09ace9c712370fc9f991f5e827a7f1869139e24b73060ae9f02c3fc01da4dc0bc1230c1113a9ad5f8ac43bdc69396c86fecc47f9f322866a6d9844496526a640b837e734160c7be6f07141f16b78dd1c9dc997e2046f603dd48ebd4ad8b62a743dcc7dea6ae64a0162e6c08a335b0971ab85594492111cbe275164253c67bce0f5ef0ffbbf387210d902dad7f38ee6ec5faf9c0b6621720a26a523c52f81e9bcb73ad43f6046413086aa524aab68216e7f2d34c8bcf867fa4d6f14f7ef0d9440bd662cfcef3412ce54c27288f88439a5a029c4d46e8113069594839b1b0eac3b028968f9d484acbf2332552e93fae60498188802174a924f7968ba66ff46188f0945497c527e4aac3877b1010b0a07a45508baba9e3a1d62c16a3d939a648524b903fed28eb1297dfedd7b2413b4ab8f9ea6db912689db7a8178bbbf956bc4a5af7ee2a7434bfcb69689bf57727a9d65033f7a4cc1bf17f7aef30e7e4bc3f7b1952dae0573a9d0005dfd77e1485807da9a5f9d46d1628f1173e9cfa485ae30284b29b57c06b24aafbc802218740fd8a441254aa6be674a125183ab0d3af6c3bcef9bff92e64f0398b6360d07c48beb0293a3b73790b42f161d41b184aa1b6c898dfc38a5bab1320a28af339b1b53aec3bee52e55aa7274af34372e089d457c210504383fa555f744dfac828f220511080747df5be53f6349c3750b5b8787b9b74670454702b11decf259e26d53a71b3ce1117c3fe226a6a70640af6479b162f416e1ba400524c51abc74d83f8298ba22abe59d0e86f8cfc8bdf88135e6fb87a37faa72817d43e98e3144d8e27e4973e76d44caaa56fe39451627a238a639766f2e0590d70b09c24e00155491613a810229e08a59099a3869cf6a41d36c593c4ee68813dc1d43696289d42b7934abdc4a2b7e8bdaab35569d5346d432d1c1648751873e6167134b1772738b94bd491bf717d8b2f7fd29a798261051f6d7b16ef9f8615d6faecb86851ff5422f61bb6e031fa03604806a7dc4ba0612ba74ac576a4d1096ba759ea6c2ddccba16dd48d338b9027a22be34c650d21c1dc07e2cf4acfa2701e192a99fef600457dea54efe25036e69bf7d89b9e6b00c22bf26cd60f59af269081add21368d94e084b93c9c4b757d8d6a1ed1683a14a66a7e69a40295a23039a2e3699bf877b77bd52863c3159f8ba0560220cbdd7f26873dcf2bbca4ff5c4d3fac439223e6db06a00764bb5f543e4996b361f282fad3434077c0cd0f7c9c7ba0bb7524ba424f1627dd86fe27c764a99b2aff669cae9931becdb6c9c18cc17327a6d59c88929bcc686d49731493191a6a560225a0045bff1dd9434b8fddb1f2d25c101352fde95062f3495222de6cb9b5edfd002e76b4788fbc3e273406cdf8218134f46dcfdb5c3649a528e34e0246a0cafa72d6a95615831a61f67dc216ebecfa65f56d0e7f2d9614dade0dda6687c98376c2fcba247d149bebd742502be6257b80368b732df38faf7904bd13d6b58c786f9936a4723e3757b642abe31698f0da91e7729581e4ff930fcc2f6f61f628dd0974be4be0aff5430046c9b7fca4a818299a52aa6fde9fdcdebaaf9cb84cf19824a329543b0a01969f95b7a77b1b6aedfad4a6085fcfe7d4956056ffbcd4dc74fbe3c26746d911f563e48f21247f61055b8b8d540931309bb66b09a5108dac72a078442a5385dc05f52264463a75372965967ea74baf305de0ac02221d59b989cec9045be911523277d299fe03e59cf340467d23df6d54b1653bd0a7d253eaf22338b83c9454faab25d7690eb8a9bc53d96c957c8eaac44c55dd8d4d659690cc971b56c132b1745ce8843570adf143d86879aaa46a4dcc8d11731df4946f26bba6230566de3e520fc8c2cad7f4f8a123b5fa90df3465bc2907ad09216bdef6451958736ce122d99735b2d9761c48cd568abaad92e885c5c3bfcb80acf38d76db1802d3d63bbf01f651061fe8be941ab412b002e183d4e5150fe28a5a437bfa3ef338f1651dd12e80e148631d48d974905cc096e46774e32418abc0c8c4844ee1ec5fd558bb71188a3a8bff0c495da4be7f1192025ce9dc1951032548c2b4650df823c44a6632065b9626e349649e55abcbc1c2886bc9b2617187ff57ed60cf0948319fa05cd4dc81b3c4d5aba7e463318e4b0757f2cc52def6353a6f4e785c53820def6e45245bae401c1b13c7a67fc9abaed72f4ee868f1d732f99e4e388f65d2d50966d84b9e598061673025b9be74f7eacd839af3f2b492d8afd4a1692e36fe182953469b3e1cd7610ba6ae796c5007f64d516bfec467b1ce8a303d0dff2e97691187a97b8891a6b81796ba7718753d74fe96995a195d2b056356e946a22dfa9304c2f1f02372b8ad924653f48c90f212824bf7756f5ae398d50b9cb439dac010b77a765ca0573fe2d2f88194b46c9b130fda564ece68af56a087fccde015265e49aa67c0d00f3154fb50322de75011e69d1c9c4f844874a2c7187b572a978f1de4e873c1b3c523116d563558133f21f09762332a3b02fcd3d6336c5494cdd875b1e4ee61e293fe2999ac86eb765b99e101e2c9d1c6aa4fa0086d6a24c9348f4c06bcfa46342132105472bdf6dc723d56546a30eb5a4d75518d2c62ba82d1f68c1b164314fd6066ed81b48c94541c847b8364577c58cce2d02c422a9d818d6b0f63401baa4ed3138cb6d4705ebd6b0091a46442aec265d0744ea5cb0e7e41d2953cd1475952253386abff5e6c042efd5a029b8471cb5c8600e2bac5862c12258924a79a0222b053171da45c01d77580a8c6bf2ce49f4f902b9f15bf923ff7c02701fd62f2b480396ea778028be42e9f9780017678797f222275442a0f894f014467909a8548fc2078a291dfd6e8483082d8fbd805b147b200741202855eadded19e17594c22f9f016c16a9b441a7b4d221c1be8b82927fc26e5b4620b01f32fa864d6f5ca82a6c4b7759294c3237a332435881f21dad3ced5e23209083e778122bd86c28ac58a906cc07cc5f2fa40e40d135247da7bcc4352b0cf703e00f692750e7a73e0dfa0f909878de1fb7dff43554aeb49d413126956d1b8b0c15f1f12e366eebe394520daf071e0eb964db8a6930707206e5990e61fb8257a70d58e3d789b30e7d977fa5231612e84a4cadc167aac0660055952bf66fd7ac7480704539d2ee374d3060567934ab1914e3e520d10cc6a38af8af560e528d23b30b7abee9086cc4e91fb8ab97f69321c34a5d20bc904c32a24fafcf3d19de525da9078de43a0317177a48a0d4bb6eb03688c99068696687362adee054e8e8abee46701bfbf0d9d95031c5851ed6d793bf37069ef4017b3e9a49b720acbbedaf8cc1f5fc505e1bd7db115634566c2534700d143b01f58ad027fbb4ba10b3847ae1ddaca1ebee871f4f43fffda3ae5011dfa3c6fedfda3bdb9eeb2f9093f49a78ca04fd1cb52c7694c93f0d090cb59de09173b26e846d4e591622d6257e1775d7e2712fbffd0a41408585b0830d566d9cc76d4ffb9c5c0d9c0832e2eafa7eb3b7781aaabf758865aeb4b75a62d71c21710c0ab2306056a4059d25a5a072999ea50b7c02e4e7918180bd065407e4b214920986947c002b2b7bb884ba42540fa911087c172a810b50122c6b76084b793f14cffa724d114c4049c47726d9a6940da2a8da4a9211495ea5022bfcdf93af2d11ebae4871913995fe1303b3ff5ee5cab0f6aaade1fee8534d15ac4171492a885ea3bc8be9a9bbcc03b933143a1a8ed70db473e872b5550ef0056952e88e27e7e10a1081524cbf45d1664a751693fb52a8eb251a2461d98061576d0f00502da2a686d0554982204ab9b9c324789e854d08edf8d4b1bbb7ba5477a8e2da4cd87a6879e904b130ffb5001ab68c5e9aaa59a92d1318e6dbb31886a95868f296424879df0785c9550545ccc857da849b1829542e738cf6aec6c4521ab3f20dfab9a27471a394c23f1ce31c0a2ec96b4ec18e11e669e1888de64d34f2464c46074b7b3cc947198360780ef38f1feb59d91c053eeb88489351685f9860f15db08ceeb9f96c7b445f25f6d98c435ecfaf457921d03e05071bd2f1a812f64d82db4dc6cd1249a565502c6d045bc1a1387fed9c24ccc5c4fe98b086862f5e981f8ed17870a6bb14ebae117de40a75112e3b6ba1cb420d856b82c0feaac3357773d38df8494657efaf1736cee2f1df30eb00810f959511f1839203c50f42e34f0c67baad4833da8e0370ce221539a829043a5138ded465b2a06a717ab00f7d94710046e31b13033dbe92921e2fb913d8736f10c8ea495c4809b72b04784a3da4ce9b13fc6162b867a61ddfa37dc581422a45d3dca020c95e1ed974bdccee0f55725176a1924b561e15cf960e503c97ff591caab065fcf8f21c89fe54202fd799a43c96ca3ffe247b2394b7cf3bae2992a6ed1741cd4a0c5701e7c7681562a4267ec92db4022f46fb1858db88bedf7ebb089e12369f553c449955d81664dc26cd0314ae6c217d91e080e466b07950d3ac5d983759b176ddce22dc37762297038d348b54b8018f955bf4a647469959c86925389f2637a046fa4eeb5d927973abe49a4031c76f0fcd120c08490dfbae127ba6d50bf3a754fde660bea7d8ed87bbcbc7a1885b59970f07770505f00b17958c1395a74cba31ac04906ef02bb52066cab6017e2611ad2d5a11c1bb3d687412636e218dabb21964a50976c4e14b894e8b0e1e43dcd6aaa27ea4ad252399250a020823601dc15d12b76dba5196a9b8e523ba1dd4e6555a4fca62ce9fa71803c63a6a5faa19aeb1816d5b3ae534b44a9b58b9027435d020e535ac481722c914120473b91259b350206bcecc617136c1d1ccaa4412fcc80000aebfc6c3ed00f486c55e339208acd4d75a8bf6534631a30ecd42a08739ebc788d81b6b740126f79988bcce5b1730988cf85cb1ec3d49db6fe212acb91ce5ed91b6467bd34802b08cfe57222e3e670515de8162cd1bcb12c815d9f360dee239d8fbc4c64e671473f1ec32356a251b3a34527a0a44440c222bca7b25cec4fd523ff692b5ff80e309a1f4d9254aefaa46eb2d45661070d4c1ba70c7cc51a3f7cf7bbecd2287f31380438cfaf74f4deb62b3f308f3fa7b2f95779311ff386ffd71843cdb5a45c628ec79562238a322cc6afb8120ae3b434caa3c352b0c6a8b04cc68a9af7b03c46688df855ad90220654cd364dd93e4699da98c4bb4fda37307aa3a1bd2e5d504ce6a960b26bed5fc845ec748db0760fb5ea574929fc6ddccf94b6804b0a76fdb1ad8f6ff97fd9bc94ed34c0ca6b3f883cdfc52e9185fd9e574fa73f036563852d1924a635628638ce8a509c33d0ae5192ae581f2f0205589e545c2982c3c24e2a2ce2270fc95b62b65a4105fa621818771d3468b5c58687daa56d2089382782488f85969cbdd7a17c999c0fb7e01c91c5c1c3106a32b7bef3131b945eeb16b5c14d6ab60e295e5805cc52637560c1a872508f5e0f3c08a067dea7118619aa0896ce1ceb979a710b9e2bbc17a83cef70f9fb8e17578c61557cb8017367136b397961a82a8fa7d37421fe070f68bcb6e151688aa7749f4803012eaf0f2d50dd899d32f5d4419d7c7fbe767ed7a44f3ea022afd4181362f808062573ff9b172f84a5aa426e66f18e691727ba9310b269f2a43da6ab6347e27ad1db2e3f15c7972e107abccc464f6dfd3d08e0e119b7c434507275ba9d4fb300935b5941b022d85592fb208563e20e2dd24810c2ba8841b04eea969af085941c0689a8245c79bfeea7640f53a1cefbe0253145975fffe89ec4abe4338713f310657bcc84a021e35f8eb9e51dc4e14336272663a08af5150bc8b71e601829ed7a255684793e9b06a77681a7ad9a1a001977cf9c3748bdfcc2c77a812b028b2db9d46ce341e6ef6d96deaeb5ebdc7fc6700ebfdbdc1cd25bbb00fea7eb0e910e61ff736ab56844abbcde86428f45f1c6ad583f9257d2e8964db9e90b1fa72778fc02898ec9e02ced6d22c2427c5f497e1bd8cfb5b469a940606ea1bb1aad8e73429b26f07c2b697bfae9bf8b64ba85de219e67924271d20e4f2d0fb464cb7582d9ef65d4f5e89202959fcd77832fe3081e74eb3e4b232c6c377733432fb5567d9b38fafb3dd88c674bfb222b73eacc66670cea3678d963d907b15740b9b45ff6628da799d86b857239f0a2c334f3ea8f6dadde0a9cf4b018c3155fdadab661b0301372fd26ec1892a3db86352cd72bc56ffe4825d768c5a79dac8aae4f5c9d2a7d5d72e2fda5d915188d2a2579d30049b2e9a42e6ce2af008dc4f139f8ba293c8690ea455bb64f514692ec0b7098be4210816ef8bbbeff759193c3097eb4283641c2753660741899f97d91c3d1581475a1cefd46d24c314b7cdc2dd80333dd62901cd3981c6c8d71b507c74745bb6d6474b2736e30c4c863e8a42cb10d850dd280856d2c57cebfb50d190414557e9836e95090cd599a3164aa281317b55cce0604634824f8155c615aee7a414187491b00caf1f63c3ba4e50e18411485aa2906acd31303b9403f31ae7d983952cc0dc5436343aed0f41ed09511fa04c06375d53d2cfeb49b16f522bb8a5f7af755f182bd02a3816ad32f9bbaceccbbb099f35a662a8d8ac43d279a4ef7bc5f7a61bca549fd5433b6dc620108f65e2d1b21905b732e64e1bb00cb51155dc932b3a6d5e8c702eed6d6e1c8a35030b8f45cfa2a5ed895dc8d1666de1f6df55db55a3201bc8a832e46d7f0e8592d76def18ef9285dfdae14505b5789f3cfb4e4e5fa4051f0dd93a03b2d3f731e77bd1ad93166e32968b8e4b802faa890bb5cc33631f0af86634e8ed396ab8490b979c005426b6fc5d78a8cee25f0e6c546f2baed71a03473b5567e39aeabc7e6f493bd45992b7c50c0fb96d46ddf824c6961ef33b1edef0eb446e8b1965479838e6d01e3ec1517ff38db0b9add8e17cd789608f38b06e9a6a5a7acc0dc7bac96bd0842fcc9eef6aa04dad4bc11240a5ad5e924e651328bd7cf360951f870237d7890b113f9373f3fca2197247e62f5a1857db5d1bec4b856a50656a1c18e8241736773b2e3723295cf8644a1319686ec988d67d0e054b636abc976c3f6bbfc59ecea1f46328f16e41c4d2067c9742f0e87ba510ad9496d04e000e82aba721dd347557226e9378ca275680683be3ee3178db50e30a63fc69bba7dba2fa85aa28ba797245441ba367a2795ce0e6b3450d74144991312f871655771b7ddc310e8b1f680485b6f4892c59a1177c05f63056a891bc3055dc7720a83f585eed1d75c03d0a807338dd558b8112716e5edf797c8bc00a65ca319c83a80aaca8f0bd794da50f01654d79dbf4980d951bc3db460a1fadfbcc9c2c4db6708f4e4e2e95af4bf7dda5c3515be3bb44082163d5b340745442ace13eb73cfe35834d177359022fd04b3233af577b53710e6fec36f79c4f30b69a0369d58f0519fc26cf8e3c674ab5bd55809416fde0a2b1aa9355e57c4a2ea81abb6359a9d25313374ca2542caa2e814dc5a0158011c8be688a9ad291cda7a90175a0c038f336cec9aded85b797da10f75ccf733effbdbeb9e619af3da2a57c10ff20b160bfa4a0863ee36ba07e8720da4bd26babf7bd97a003001f6ce86e1b406241dcf171e8699dbc2eda696dac135371c3140e800da5e390f7f1bf04472934157e827705ac9a316b667e4d40673079aa582a43307537755177d58769adae52f1bd1f34897071eba7908dfab4d66abc6b4d14836a7b0c05159cc80b39fec4401d51fa3b820e6f7b5a6150a0aefe3dd946d9e609a5d23aca8207c0c2c31e91c5e0c24e61aaf142c42520c8fa920eaf8813060f39781ce300302c71acf4141cf897c782821ae3fc01bf939eeca6700540eb6ffada1f6abeb9a7b57ab584618a0ea5d113a901d0748f2555785eee32bad03018736019a1612b1924da14b830918d25941033f9171c9c7aef27a3e53bcaed403a500b24b5ff8828554706221bfbdaaf5d0d05826a067f211c949143e76f06bbe3205774411c693a714770d28e50060e630633c4f5eefc72a031592cc869a4fb4d1b94931fb1c82af83bb2c1ab369680b0469dfc1c4b67637e1b0921748bbad5750f1b4436a3253c3bc0eb785f2cf97f23f1c981e681b6d85f980725363d480757a58bfdb984cb592ac709eab610bc34189bfd871bc5c2035e45320b3696070aca618cc348dd779829adedeb048a24b629a23c4dc0de1d8dd4bea80108e3999dc1649f8e7703e61ad37a8ce402a1dfccd60613eb2e266ff37dd1f3c7fe642efaf399e774fb5fa903aefea4e9273536ced5a289b8a805249df7759e33b80edc1fe3399f49f5e639f50af83b0705b12b3084e24c56579828b495e56cb3d818751f41a0dc793b9c662f109570a3cb2bfbadb48b7fc0e64c62da0cacd261e950fe20f70096c1790ed05de4578fd3ec83646f2da8d053b3434fe740e164c9772925cbea9b32b2883ccdbae6bcdb4e569fcf2b59d9badf9c95e2b12b00e2eaba0e6d1c9427473f62beb92830d0bce0228e7c6f86c37768a08c93cd64a43ebe032df7cadd57aff524705c2434a9c52794b25b58b272417847742798a3fce053400e84b9a02b94cb3adc7352e50fb8eb6d0c831c7f18dc05381ff6f307e81ebaf11c9972da53515b3c1c83c554e452a3c0e23b2c04dd1ecd360f0d659e72e15d7bc75f65f7c9c30401505df05283f84965ca16cf983c9e2fc6d2b194a006b92b148b956d7920d4769256b806f20c64859a524b2af6d47f3471b733f06083bfaf0aa328acd8767760161107a2fbf44d1b4da93e19632d8c092a03b452b8e355b47366f0ce44d07ce7dadd4c7e6596b79cd7f9af8d910dcb71c8b22b69cff629b1ef559679e72a622e971cd9fba274904f6be889a615d41ea230444db24391d4b15572c9acf2a8409aeebf15c72a4b0d9b39c5d52e82da799fa579d4fbe2bd20b71b701c29ef2b4f08b5fa414a0014b40377fa92153518fe091a130322775f73448fa39eedecbe80c6cd332cf74ee8432a12bd025a10d3410919625ecb95f8310ba557d3f14ed8e7731e6d9cacc8a7ffd7b265ece2077decba0a95246102add7a8ec4fef73a4762f5de8320803d385c96dfef62306999ac48565d15a32a919e02c0b13bfb58654d9edce1085cc8eca4bf11de91c89014c983648a290a6911e693c30d163b677e04ad3257b28687fba51ab45264bf925d994b3ec10ea50ac2055c2cbf7c3e31f541306457605f99d40437fee0cdf54264f9a6d6f34fa7e4cb6f00b3eb3efefccf91a0e16d8995f9c731d30a13e4a0c1fc1602d0d0832075470872aa3ce4a6d0a7c071fe99c0213d29878c23d05a4a0aac2cfc339aa010ec8c632511915331eac10c42cdd7812df8afb895160dc51b30f51d49cb9ae88904a4ca89af4606c86325f286e15804452938574a541743640597b4dc1444ca2d9401cc455ac2b1740c936e2039a9ea35741524a88d22a4459030f5e62c4916445865fd050594950cfc2d81f6195a6e054811561f4389049c54b9a63186890f79c1e4a43d4815883f5065617d32317186392c5c0ef64fff81848d45298fce425e202f012afacc46c59b8c85131f812cf46c2b1f872b613a5e5a0c02f10ff742e02cd29cba30f9f7b85c9a296c28a3b7084129be6a00dcb05c724b17d959cd56afaa04aff4f362946d822eb6c6bb59ef4c400cf04d981125991271554c4a124e30c4890be55a45d16e9673e3f30f5d51162103bccfe7b2778c76c63801939116da462bdfad6093ea196001e698202260739559ffd79ec2f767f679dc2b68daaff32b6e9fc142c8a8da1cb0097202e6655082bd71e4a470a734fdba57e1195158b12a099f59afab45790f795e6bf2c3900ee7165de261f6c1ecebb14f2f01d79ed01ad848a90151fdcd92558db54b653defff1b7b3430a42451ecbfabc43d8ad1fde3bc444056a055c2b3abae14a0c991a2e0b8f1a6168ff0fdf3efcced9b9209f11dccea5382434b7878c0a395ffdacdea0fed51628232ecc8bb134be464c6d02c8f91d6cb0ab3dda4e7cc29b07b5887ed9a2cd39f689081b9f61b3b34260b8239113db45912ce6d5d18c964cd3729902ffbafc3bc3f1846463b221af38b71981c0c575016bf6707b8fd32d91624fe4daadc136d11af2dbcd4e7dd6718c13f9a08dee831cf0f41f22f2cc3bfab49c1c5eee358d714356dfa7efe49c8d833f69e3adac4cf46c8393606f71165192cfe67809d45637bd223abbed8ca63fbd2923673f45363890322f624bc0897d5c56b33210a59f8a369ada30b8976ce00ba3d4837ab00cd65c568f5c0ee6d2907090136eeb70a5f1755e6816eee74d51d39e9fdc244b96ed45550127ff8d9d9e7deff2386733ace8062daeb3e028455854fc992e9198091c44693949356310c04f7df476c16fbdadfe03fb978dbdf11aab2d6e2079490e980c1487d1e751e7d8d892da11eb0b3e3bbdf5bf403dbc4c12784de1941530e86990c4538728a0668dfda43000a79fafc9093bb9446f39142805bdf19a3c2f41fb3326e853751a1684fff93b534437a76988e699a214191551422bf7959ac4e49b0acba0d9904c82c2a5a677c3283bd0c627cbf491180bf369ce894dd2477c26a071c1ebdc71922dd200020fa5d1aaf3c68f8d57b4ca9be90ff23b4e26730817c47a0a2493302f91a5a405bc23968dbd93b5e18269854d459889cb108eeac40b398c2d7cca85d705d6bd878033cca24151965185ae97268779a3be2b166a87c1c92d3e87904d93f5198b64558ec64fdbb4d81ca5b15161d618f4164129f5448ec8bc4a017db75beed4a807b8fb1e45a52429c4509f52a7a8beb524dd7e1c0efcd2ce1e7dbd5d25fffa91694c6b6267e36ed15aaf5137704f7ba26370b0580857c8b6cbd0bd3754e47c5770910cdc2511aa5066178bc75c7c579939f0018a82619aec8671b85517e04288128a5451a009bf9b00b480960e7fd0ce322d386753069574e1159417a677a74eb9f6d46719d598cbfb78da040c89b33062d441905f6ad711b580124637d8311525910a2f15da35b85cf16ee4b63ff35bd31952798fcb645c2c02059695892caf323282b70ba79405631480c886579e0c3e91cdc463b2d43081da8a3670b7c62320818a07b68df01b5d56038e162d3728bd3840534e8e8d60b360742d4e638bfc90a08f7ebbc02d0735db8ad259059e1b6035eb40885e4d4e67b9adacaa2da338fd1cfb0c4f0972ac70808c02802b8a58919d08aa0aab95b3730fc67e4a03b87ed1a8606f934a58e095d8a1f762dd226071792ae5e0052b27388736e9ee3a098d5eabed81325eb98b395573896b8661f5fbde9171981f04a1041da243ee960fbdee1e634dd3b5d6a8d907474301c3821149e2a9db4f2e878c22eed1f4d6d003c9623b591c71e196c4eb1efaa7d38b2fc2d256785ffa86047e3943e34a7e5109244eefc30a8de1c7d5503800d2c0db3c2585b73b61c8088e39cde54fc7165715cbdcbc4b004335ec5b319c93302fe809f1887cc319dc8e205898e45f39cd2902b3bcb41e2df9d518e6493c1a6a9e4667a331fab4ca605fd8c699d1782c085895572b1ed891f18c12c09d8f13962a8449f1718f14b529b79a309868f40bd4592d4326772c6e852793f0e28a92cda7918189d0ce7fd116943964778484e911e2067aa90108f14c2153031505a92a9efef80332fc4484f029068184894efd54c7f15c0c9331fdadda472e1ad8376a406c397d10e865196fdd308296706b428fc70aa6cd8cb2a090b8ffca6e3d7a75f153bad7cd1bc3e891d84086ec02731689e5de6ac2c2c3565f3bb16ed1230598e367a815fb282840ef4fb48fc3e1ce24fadd7392ad1b33edeb89ba5edc9438cdfb11d56c620225937221855fc6b94d18bb459fb2fb218a0667dbe4f8540e1809ca1989ac9113504c887e4bd36cf10988a83f2203ed25884c12405a1d0fd2ad7721e4163d26d254a247b602e0cb7525631376140a8af84133fbe5f57ae183bdd7e6a3192027375bf201e45e0a38c58ebfc83cec52af2386519a8a1c22873de1a9916636295bbc8fda5aae8016885a516359b019659f16c884fa26fb81182080d00360690c669863b66e61f936858050ef28d1c4853173ae1cd992bbd253912ce03ad8d3ed02c219f854c54e2f24a5ff4fc9c2a5d3fb2e9c4b90a2ffd6f5efc82a245297d89a2e19755a773847b9b65ace7b245de542aef594db563114e0079a4e89b8d7b844dcd11a1a5008e37280e222ff44bce9f2f3552c9d3ca76ec5546b8390e1556143b11419957765af818eb048e067884b94af53b66a5478551d3b1ea513fbf51f78dd10e308dc1662eb47012f3f6e4ca1085a7dc0491f19179a20ef4d4dbe7e9f9d0953c98659461410b76ce636631503ba55cb95d2d4a28ad04913863acae09bd42e0d0ab297d16503c5bdb4ef9de466eb52220c457c18356aa58f360406d059d7f1237e69124bc876f17cc37e4b1e668fc8814abcb5f204d3886ec519561c41c7ce89a94e04bc9c4fe16bb3828e5dd928ca2573fdf07aea351f2630e5747c8cc0493b0f4543f329ee64d4ce57fc24196d8c2f255e6d9c1212063861e1217d728dda92da6932dd49721387ad07b9ad03ff55c291bc1172ce7320eee7d39ae6d774c0ea1330e7fa38ef79d5aeb8d36c82c8af296afc9590fc6c2645e2c558763a5be1a750779666b0994d08a35170fa250ba54f18d2ebc0f4311b998fd1d15a348da10145cfc68e7f6db433900e1a3b5f1d996e4653665fb8ba79a18e44bcc3d83fdb52784b88cca80994743c856044708a47847c832040764c6795d64803c858361154336d8de2454bbc24a9c916dcdc89e2c0e0313cc0a640837b8326f8a376c403c2ad11abc4e22f7457cf7ebd8a421228e8f60d175069c6b4c84abf1cab17f212e44cba8e3c63802f7762ff5e954352363d1f54944b8fc123d3dde20da549c8e2d56d3784fea93c8eddc0791f553c993dc3b20ad088e20f3e469190d6cd01acf4f6fd5a8937b761c40f27f426c28f414a719d31e11ea8e6d8b1edc9d03a3e66287502a7e901a36f311492ec3313d6efe1e580b792dc5695a8f122ed142d4cf05849ae57107c28d4650bc480250b92a547ef497602763e14cdad20772bc7209f787439f53d9780ef48e6436f7e1017753552eb222e115f157f202f08eea1ff8d4e132b021d600e579ecec2551f44685a645500b3fb7d96f645a06be9344314f44738cb94dff929cacf7d51ef3fdb5b6cd8b3563d05faeb9a1f41e7a873fe622bcb9056041c98c47e61c52149f96dc9034ac99dadf404ee02dc0a9c1ea93d81862400f03d0fd0c61394748472f613a2faddb723a896c48a6039945a42a811bef4ccbd2795acf8d1aa64ae815b2b352025621c32963d9b4d3356a0e658559afb1c5caf84b646a826331e0e6ba699aa6c0ab5b1a10e622be199ad14282daad931c6b02db7b80edddcb11a616c3880b62a579987711d36f6aef6fc6493485d9e3b703591f6e8bc2e82b11e2ed002f4e8a51474491a494e0ba87e1e6e913fd12d89fcd82e65655eb39443550723928082261a3de1d8e067d6f8699663aa153676a1591854704bd94edd31278ee4dc524a73a28c12039342645579af50ab5691ba5f34f5ba8697118a4d9c5636926efe535701bff43331cfc25f6cba8728a348e10b714bef3104f93c429729b52daf6386101676c14a0013630998d617085104295222e3e26b6f5ecfbe6bc29d776accce90695b1919236c88d8e59c3c62c5da1049f54ad773bc69ca184542726cfbda6d790421dfacf75b4e3f85228306ab21b05ffb25ba1de79d6d915dd23c510ac4337c78fda5bd2faaa8926b89d612ff84545d8fbabfa08f2758616b6d796c4c3246a2fc2ba93b1732fe290c79b2fc4a64020ff3c49afeb3e75c763a4f69ae68a6c0282f967d62125e4463f9618a426512936cddfe1a14948c4b5b23c9c16354431cde981044975ee83ecaabb2a61de18933518e56ed7f54380c61d9594bb0884224b8229bb5b03858688998cfdc6c56b6e36fbfd86cb485f5ca60bb6c888de80f6247105849bcdd65ed21bbf195c6b2b3a4158e6d7499ce5141f0fb8e9908374d7f321cc6f38e142638a9852c2f5cc22f7f1202342cbb2921cb8721d10a44df8b22025b4525f914f9d7ce208e5e9bd993b41315c555f84200aafa3f10189dacae82fce368450ae3e103c1a98fbefeb0296ed27db2b429cee84ef6a9bb14ee895f0b916f8283824d08fb6823850958e6b73d25b05437ea94b23fd01223c9f1fbc82764f3523e52558c8b7ef95ee531f39a15c2a6f8999d0cf30e0c7abdceee2b603dac090d96963f03943f6d85becce3b470704af2feefde22162cbb892caa0882de665aeb3b958bcbfab09cca6f145840ad6dfc588d2d643b606c7b9a33c1ec52e4d195a390879c5abbfd3d4297e85f11c0532840d8c2398a0c7bab081bf6887c415aa28ee1fb24c743a9395eb8748886c0630c191166bc60c64113272244dacb917a9b04a1a76638776443dd27feab2e7b3c7b2066a7c4d1a83786f2696003253e463e653b2cc21e36b3311742f22977285127f9650d2af273198a3a09f5c4ef4587c8e8500bc22015940b566b4f859a07cc49aab416db2b25e9f8bc5df4db51d15a0b628f03bf82904783e492052efd0479cc4a504934c363b085faddd9502469333844ed51dd91e50636f25f35accae352e9bff265a4245e1d4a7132e9349bb00975571682707b1042082eb121eea2da0d2ac4032d4aa2db4603aa54157209a5a8e0b0283433aa5afdae38ef5486cb79ca34d5f62463a28e04c5e6586fe2a7240d27018eb4295581f8e9b4eccdd3921d14d41d67262e3c1aa0b08141e1279d96272f1a8dffc7847614bc194deab718744a984e1a5efd38b7b8242e152a9d0f3519e1c777955126a7a00be80f90ca550273d08603cc4bad30a36c59e545d22f3f5d00dd7fd964c2011a76168ca4e681c4ee0c1e0562498c13bd32ca92496268896cc3c8dea4f387934593a9bfce91948e78ce0c0058346f2c1b77b1c4f38283113e57495fa0825741a78b05726675468585b9c7010b42d1700b85f0d131f0f7e7b2ae8a4509c09b09df2ba531de55987d70bd5d31623bf8d77f9c532808bcc611f78b3ddda2e4a042f906061beb8b217aac230209a1f2e060c145e249cdcb3b2eb2d7fe8fafa12cbe630e5b2dcc60eb265164bc85aff27b1f875c3a5b7142b06742e349af1024085905d67b7550d6e775da89756a497894451d1c73af8edc4333b60e10c51b8968c30a5a0107718e1421b89df7dc270f73653a448be76e8725475bbee7b8bb58ced24329bf7afe78f681cfcb5faada2396981826de59327255546f9f47a92988ce988dfa227dbd0198fe96f0f7b776f8f532e3d534702346f73b780789c2b8868342099390e5f65b1981e5cc33ea255bd96deb1d079ec6a15296a5a20da47980f42e49bcc2fd48674f0f6c473f2e2eea749d042938cac486826af0ba4879f8a4a6cc92fb30b929e97f711c2710f3683f3d9c525fe0ed9a61a186294894087410296a94b61e0e85429edd007f3d88b24632cb6e3f7e8df8c5e27c72ff055b20601472f5727d6f0094937f5103008e932969c910d94a5ece242b735af0eae7e9baccb3a71adf072d25d2d88d54990142be4ecf91a8ce684b949dba0634f887ca7b71935ab169a10021b0524fe799850fdee4b75651bc6e8968d33971a0229e39fca932105ce49ec0198481652e5a16a123334c8f575460646593f2d4b71f50e1f445f1130a3700786f64c815ac01cf822f92083913c2a81e075eb7c0f0420b275b149a65912bc2d4b10afefa21aee309d702cb2b51715d54fce35ffacbcaa4d10cd43647dc7c506cf861aaa06cdd63522013460667b6acabf5f4d68ea8ddb668787dd01b55ed6545abe849c22c1abf3be2eda0dca8bdf260023ecda47e6f5fd508d6614a0bc07ce446b435415425f2b8c0277e553a7fadef744bf9e81a56c78a3191d8152c1e18a17b8e10b8a71db20413ff69c4664161c2691b171a694bacdeccac8d688992a793cc3000154a281682975f303a2f6d0c1eec89285853072f0c3f93423f0df6bea003c102b07f2ed0bd08c1945e193fc0b10057d74cb0062b0380a95940d4cffd97a1cd7fc694afecdb7d2fef3fa248b3000e740bd031bd98c99864eefc7da5f2b289fe4d555bf49f136fcb6a01127a85e5499ece29676c7978a777b5ec6fd13a0d6c2840f976820805547bd876efd072363d865c5580623cdcc969e95da7a287f727b7c3beaaf681730788c91d13eb3fbf565a6a7d42c15dd85273a8fbd3f819a036d4ec5e37cbd9def065d00be7d34ea70b00504093cdf01168c56f52c786ac9ea23a57952fca8aba27aa6f4e7baef016129edad125c9c967ee4f8ef3287cec25a0911a47386a2ea6c89058a780f71cc7de86ba982219c478c68ae5ddeff428dfb7a6a4320c36ab637bcbb01263dd0133e6d8acb7c153d569090b0355ae09666483c2ed0c4e4d7d63e29f70f40bbb8b5cb7f06df40124a32b8d335a8577880ed1e837dde0d010b00f4bcbfe20bebc2ccbeb4bbe7ea0f7326a4adf7a2648f3187ae24365e91c191f88eabdb1d868fd0076fb827551493ed4306c54c5e2f89f0d1ad6f5022fcbb0040b03d5ece3a3ead037ea8d2433bc928ea1d77b0b9b39c2cb1c355244b188e7d4cf4de5831c4a72fafc9e9f89ffd2a94f7e68c4d6a42eec19d02ffc65752568659751de5a81b592c57f8b47007f50fdd01c354d57f69955154b1ed00d39c6d464c7bbc13b2acb86198500d1f58edb82da5721e0fbf6781ea99ceb9c2206ac37f8a628aabd0ffd36c14d087c54a9b16fb8783214bf9f1101588bfbe99104ff0747dd7d4f3687e3e65ae5a7c6b3f0ba117ce38872d378a6af300e1335bed149b9e43c07d0d6cbe08c8e182212bdf88da265088f529cbd678bf6fc3d2e270cd0126124a140e5051c969ea4147070e220eeb912781de9615bbae9fa1dd043049c91afa75cfb3b20aa43130ebf9b1fa7d8c5436ec1320c5cdef60ca6fcc1a4a6baffc1c7c868211add81e63e0b6925c28cf143513796eef271885c2f5ce83a59740df059576529fffe3dc575d2a342469474aa7c3f32c732514ed7101f3f496556ef0765c7f068d14f2d90d74918707b3531ffc023ef9f3fb098f0d59fe745865b01e5d59c429fc58353ed2775341cd97f501ab80f9345e69165e4758a6b147c84e66698a645e976202f9728e164e324269c3a117e3e6c543f1fa66c71025ca7e78303aa832ab0ccfbf375b396288911ac2de21d0ab05a79536fd3f3567940d607463e18a793f87c550be0a335bc44b1c886c22acbd298afac8d737a5b1a30ab37e4b063d4d21daada28152c7afbc6bf9f8ab323c102e0b244ef189f4e934a30ace1ae5d4d5acda32ee9fe84c1fc9661b8d3333608fd3c4fdcdd05e697f90d27131c498c9e190374038bbcf504cc4f681470d4aaa3e58c9efe3b102a17c1df6bf5296f1d19d7f0bafba75b13c9cacda73ef854e3447e0281125f64673d43790751483be4a3e490708506905dc4c2fed074ff96b9cc311996149ebf7df31c2cef81f9840efc46e72b97b1358f3d4224439602a2d333d06df47af5bdfa80054649eb43e8d1c2f1512f51fb6d862bc69f6297a2c7859cb2ef366a47ba4fe2dba220d04271bc41e835a13d7e100152be16e3034014367bafed000066668fc023a701f68d0c2ee343de46c8142e1361c7ef2b8b20598f73838fb3a8f02614c029f919c8d35aea5175d2ed6bfb2dd256aa2b71739ca5cc5dbe59df0a9a07123cc908a00fea922d4c0e1e78d125cb3a6b65986015a428ae8483120ae019b106d5ee5b1c950014474d0e69a6368888383cd841282ca6d0ac1d96093e6c13f8825de136b333c432a2b491b3a2f427f8f3bad64c195b7535c156bfb3d5075a2aa5a2fce8ee39504901e9d39696b1195567e79b7a1a91af090301543664ec60b6b76b1d002c32eef821dce153a3d0ab4aea03eeefdd4206a781376a395c1597d3e6a1264ee58b719936fe339c4c57aa0a35125b072205c247bf61e1da9b3786427854c893309d2706c7b210b71d89d67687da7e0907540b7fde869853962ebaccca98fe0d2851e43b54bf2f42a404782fdaca31c29398bee519b08ef34861a25810e5994541a0468a924595e5f845bde8bfdaab81cc67e230b9d75a8d1bed62669f5027258b3681c5b93c5998909673725e478d2c7f83cd3505a33a02e9e1003348d2081a707ef197585814bba8c920f4351bd24327d04747dc67118415edc23e5da530f042491db8d6a0ecb82b87e9659ea5240348d1f5d85365b18b88815306b5b96430a18581c294fd6569193104a7503276bd52509dda5a7db7d676583e7659d38aa78a58052ac61644a48d2c6e075720369aeb3d6a4ae35def2e12e74a65d0ddc2eb3c030eafe03a6d736c0adc4684b9344267b8b61df9b200b14706ddc4f1ef057a6eeb0d9d0ac18b4ae558366572c12029824dba6bca497a2af6473f9a82f0ff813ef07c23f052ac2d76b7133befc9b659f2d5e04c1be47f4d8acb3ce5c84eb81c4a4a1528958468862dea7e8c555a6e24825021a6b4982bcc2c322edd1c9ee7be21eb7bf83fc5923b14d62ea17617b107355670f769803197e0823382b1924e24c4509ef4cb4f01139c1194ff50bd0017c4a451c2f0a54806477cd8e708f41cf3d0da5c7fa7c1e01e260485d1f8fdc47ebba92e9a487df58ce6e6ab5c816ade8f2405f2d2518b325f031d17df1a353a89801daab9e3bf4cd4d7a8960c49b20a4574577fc61e162f94b3ae16705532c1ceaaf615862951524ed189bf0a99f29c46a59e0fa36698f803987638c496abf9cebe69038fa53e85126e98e3fa9037e45e08d45fa473fe91b0a9accc7cb0c7951647903510ad037f82fe328766c122332c46748c208ed7434a882be380afb489cfa02aa8a48c954362b81db9c517666d634a4049ec472a4a53f151c6a67df2e8043a59f2530d9aaad1e3fde621d921769db4fc88872a8a452aa510b332d10df25d1567d7d18c814245367615b57faa1db87e425bb5680fed7d247fa512016ab54c03ec41dd31eb48cee89b7ccd3ac0d7d815e50b61d1f7c5f7e5649a94f5d2fb86fdc2918807b2f3d9177b3632656316b642521f1004c0d4ce6b208117d51477f25745539eb56df676f9ace2493dfe9f3cde7543f15f64927b1c7ac5c0c0a1d1632766afa17c13c5c65ce670499a3bcdfdc4fa5b1b1b3c8dddd359d9a51c902bd36f44b5bbfd518570439bb1a6b897636502830c2cc7a30993e9dd9c4674c934916e6ffdae50377ca71138b6659067d7646ad0e4d97ba66cbf8ef39ac292f2a3262f0050c8bef2e92f95aab23955dbaa558f1c401d73d7b2a003511377bba5a933698935481391f5b38770d4513d9878bcb81d0d26d69977fbda81f206816eec2bd86bd7490fe9240105b9f3143acd7f9cc029dc9b94502feee672dce6d1231a088f085113f4d15300ac10814eea3c658c3cf2e6a4c2edb185350fd05b574c6780baeedcf02368d9702724251a4a7603b06a2a992a59c4649d20b567d81fd5f667b928d31d76fa5aa6722aeede4afa8e487f885fea162e547698c3f29a9cab8fb641b6e3222a55e95f124929b63526cacdca2f55eac60c54469bb82429fca549c470d38a825dc77561a8ba61f0b26949382c4478e7a899f45bbe48d71ca5dc7111f393cdf355383f3ac8c864425f7accefe5c7c1cd59c77df9890103d43b7215da0d9277bfc34eddf72983c5fac7651e0661a87cafd3a2df19408dfe05d2679382d02eea73624fb22ade7a4580d45549f20bb957c4fd32731257a5c76aeafc81941c656169cfb43b6f9d28e353fed2ebc4fdf8bb163eb2662525cba89b45464e9c62d92b3a06a796007594dded2352d5043a9925fbd45643eeebc2db0fb06aa553709c131fc269020483972f7ebb75f2a787f3c4600a734eb35514ddd61f5eb01d9b52e67c4c3a20d982a86e014b74af0e91b078836bd0044ef511f1e11de462e0eece781f040be4aea39231d9a909a7b051b5c294363837c6946bc3c07f0eb9a266046788f323f7221b326501e62e1044e7985865b6b32aefb514f4e83bfb2f786390e561015f308cbed514576850f1b3893944787bd79c1bb74abc824fc6a7df04e70853c8269f62291abfa2f7f7c6b2c00bf98a49d4e6a3702009274feb8d6dae69ad4867f1b375b2e728e2196cf3d051d7ee92deac28f44125bbd8400fe390524cc453a0dc41167c34a61c16da1fc58c1a3d7011cf70bbc28a2594426a4b318d6b551adbbc45cb8abd901686d8eef7c5e5dd8e9a574372207a8b268dd22db4b49ae88d7843610b5998d1613b8b38376e16c8274ff1fe87a61514318d6ad7eaa1a2ba33ae578fd6295ee6005948b66e406479ebfe9b0fbf36c3b0b9db4a1d2adf232b76f7851eab71abf0caaca84366b10ff21aff76585ca272d24119c50c1107cdf35ed6e9c36f60bde593c16437e1620eedc70e67421906a2702ec138eeaed890bd2054d9c5f296611b443570bfb99b506734326186457077a5c4e3eda2cdbd7f3f5738685f8e37f7811459ddb6770e488744549b742d20c974200c8e522c96a9b2236ca9b9f71735ccb790abd46627828684263a1ac10b37eb2869d7996f39939a281f10ac724781425494041b0cd1272a9379967fe85fefc0746ea854f806687089badc1b1c850c805f20d523d0966a2bfe0c4dccfdfdc88ce00464b89a42d943718426f1448f2aad939d78d11e7dd284b4f9cce72337e3dc2c6c622128c6868f8b946884fca3cc3d1015383a8619e0c22c23988413bda433f7b7cadf132c3dc2eaaa8196ccbdac2b6eef8e0e5bb77121c4a32b08d76d05e0f0b756d561a5e66a56c28b212e269a7e378bbbc0a514690da57ecc93dcd26ebe6ce9e4d1ca00d89e9681853f8c0973008be73704e9990bb472059a0f570797a5990c8a4401590b739e575425424780600d6c2c1aaa42cf7beb7910517b5adc8046126e66e60556fa81d82c5faf6078e8301f55308ac7098e9f9d787304a021026c4fe26af0b8d2aa61ebd15ba8c27a8ad847920cfcf42836b38e8fb8dcccc6d9fc5df77e0726db388a7327a2b4bf4d2f81b26a4fafc7383970d4ef7b2ace91866618cc51e51966eee5723e219c2c8da621616d94a1b829f96695d3bcf1c5e701a0e7989ca284f4f8a0089a9cfe2bc98cc6d46d732a417da1f9f46721151dfaf96bee119ebcc355b9b899a15a58d8beab4c3cbdac6da3e124123a68284f4442d9e18381a92fb8d032d9dfbba7aac84ab327b057fa9e33e653d391c1b909629d410bead3e8db46bf7a10ff999b6adbcf9c8b2b411aba15633e7564c4c9843ea3c9d9b26277b49c65c701f14cc102fcda00a4c9fa3595bac1055490f8b1cfde75e1c44eb15fdddfee6ed20ca9cc66fed32165c22b864921c69e4430679f1acf4c25732582a9a3e3bc2ccc524670968a041e784356348b4272bd756b41003026155050a9adf39c81aaac633c2ae453706b7c214d98b34ae87d4c391d049d357e62bda59599db6a816c84393884961ec9db3470ab2bd99a2db2c81c350e6b19d5f8f44d1a507b7555acf83fe2b21f30f5168348b07fae23d50b77b3a3aa3120e9acf650aaf77c526974260c607c77f7801636ce2c2b3decd2c4f2a868c31494a3ae1a9b3eb0b80a56e231e0120d57f3803ee5e050ab86059d9e5a094f9126de892608ed3083b121d1c3cf4a2c113eb7da787d279d9c5087bee5e381cb7911d7547e75bd2a71d3229f7fae4f546023b420950acdd6dd900b9a5104b2673c2b7a69529eeece9a10a114e741fc4d5db5cacea392881f097b934399585e34b1cef20d05e8d992ede2848220a9c770e3f706576e09bfbd937d115d5435bdd6770a7be580df35477e48243c7d67da58c4b3f113e30eec4f995a36b58688b0c5397f76c3e11de8ffc22591ee4372568b076c77b8cb16918bf835489abab23a12653671bc2f30baaf4e75b74323ba72bb83020c7450b0e526f5ff2d46a563843471c5e0a20deb84e94aae718979cc7f80e2dcc6e0fe275066ac398f8bf9234ef31cfe0f7a7cbfc8a990231726a270eadfdde087b2c5ebb5e4767248849ab0e051ca1240c826a6536c1edc907aff2077c2d613da4d9c89a0c2e95ca2c58a238d94d485be6406c3fcfddb5978108aa3e392192ccdb4a17d3256340f7e9207cbbe293c200e9593d6c55aead3f54da81351ddead8bf6332c9f4944259fcdf2f313e897292d78cb405a1a66e3d8ac8ade847f35d3e5c0fb5d897ea07c25c391d9e42f6d69e591a836f380fa4f34b73e58610c42359e3f38246ead4ebd69de4275fa023b181ac60b6d976637653de4a81610d94bfa03e9ba25f9f99de6ea8fc5600c2e5f14a36f0b0f61d445dff6ef86ce9ca1b599c353373466fc47dc19be1fdc0beddea45a2797033e63251d4fa33868e630d992f78c339ef11fd92bca66b32479dbf92697b7e8669bde9ef2b39743da2a6a68f906cf27edc44026e5f8835ce71f46ad750f1e845eb90ff74c27c7e4283bbbe37682abb550ca8e0aeb2b70864b296720c3a29d05ca01c1b474942def66859419dccc37be3cb5fa2a5da0e238abdac9176ca3fb342259ecc10c8e294ac87ea12d0d614d15e603a438848e8386b39324e15b68e46fd1288a7ce261e4434b6f41aaf64de6914d1b444f59da7d5c8ca0febdf190e5616a57cffc42af2cecc654cca81efa251b5fd97090744069d4adcd36b67b346446c9c41883b9a1e4d7c90a4d705b343c31a4834001489cf9169419420d891ab0b4b1f78fcdc29952e85e074746698ba3fad9538d8d3febfe38a213a9538a323db9f43f9c0e7e2b9ac606d16977906ecded9b2579fe059cdc7c8bd706b19895db5dc1b1a9a9d76e1475e695b68ade8f2a0a4470253643d99ff64e0242a042f7134a0cede28b3773ace0d1886f055c128b1127bb72ff58472b3fbb357e6816ff0f8a637bea0685c239377c16432fd918980c8932760c08488b85635bd4ed8d07f3f7f2fc8345e326d811b2e7c43d7c06e692a4d16c5e5f62d979373b6f831f941b48ddb5e5a6f2c6a2ca9dda3ceeae70a9eadf7888d816ed8313c975fa948213781be7a9350af17607e902f7e6f944822322bb885c1e21a370a15128e903376711ae4d0f3a0a82c6d40765307fc2bc1fc2bde0ff4829952f22d618c9aa447e3552bc353aaec1272e5471d0de4484e135e416953a4a0b73483dce11472c3f3065a0d1479924f6f0939838c35afc6e2ac6e442a6c0b6c8fbdea829de695d26876856e50a87ee3c500818bed4505578d318e5e8a7eabb0fa37429995ba630738dd248c68ae96e15c9b91e9f7bd8409f28da82ca4fcec5371a56fd11c7346c2e158d3cc2a201fb3c9c1ff445994ec8307f0e04fd081b3800fd6804a57e97195bf5af69de73ed74da7d6d79f6b60fd5a7172c0a05da505c7d1a5d42ad0169f09e8f06d761559a5ad1aa0292144183f168b16edb23178fc37cd69549dd1f295eb3ac1717c4d7264c566d7b1f4cfcaeceac67e0a23af1f1d015d130e324933d0bfc555719726d6558d949082cf4c8a1a4d675a7d5de95bea64d058903d757baaf95cd003ee495b2cf8ccfae950b37cf92482695b338b34d673287ebe10954d0fd57e4dc2443f099b2ed66815dd979c72b1b1ebb8c0e906a5c6c1ecd4eb3f0551eaa83efd680e3a0d8e973fab72a37b3ba0036f0dc6226f49220badceac1df6accc5165754a15f864a5016f705ea3db451bf1039d623aa54c1676e7b5209ca53ad575827328daa51bcb316f55f1acd6f50e7e80888224a9b00cd5f1554f9c1d817475900402e429b4232e34d190d28e10c89ae2d8eca07253f37021bb8c4b180da854ae2bdade8c2d8c4a61295db236b15001a8905401acdb008c8faea2b7801b1d63909cc4d075f61ef1fec1eb4d071f0b2b360afa2cdef866377617d6d7c574622026a90d2bd6ff9bb14b54319cb14e24c0d788ab82aba96b563a953dbb465d8e3425b280c277711fc691bf61abd83b7896b543dbece055618fc9c95e1662c55821aa3990f33c2f2d77640e3f316d8f9ce258d14cebfd934a1f7abe51e3de00757c4c739c7a721b97388983b5af4c71bbf5e7d7a620c2397b5a27921ab57cc78c9bc543e9349aac14dc1f077fc50ffafcf2237fdc105a659c8bee5b3fae351dddb067bc6bee552eb36989f6d8e4dcb2730068e4dd8271f9ecd3f46f18731c2f47a9f6a059587d37766e84f2bb2c8c32375fb89f012e0127e7d2637c0618f77bd464da4742dbfd4bde65eda98385e41f7d9330da7af57250efb3424d790b1be60ff4c18c2422feb0c630d530b94bd6bb81f9239528569c6b542bb41aa86cd680aba1aa59618a11d460b32f81207b5a70d5ac5595bf19e9594d2bca4af85e4989fcbb175108a9ebf61075fa0d16cbe420f4b9f350bb141ada1499b4480c1cbbddea0708914932621186b4517970637aa40808914fad5727b6eb949a60f8ac3aebc18c66c3e623cca8ca0f51823633b488d4268ed01069ae70a2acf213c5a915f4b5170d01fecda19b8f1a0bfba2264dae0b97c394c473bf39db5be11c50c4aa77b0e7b2c2ee65cf96ac2f0502e455032a41d7b35c20cc59451dd40e978334902c07e15d18bce9d600a41b8dc742351a088416d3bed988622a8a590fb1c9899778bae1bb9523f340fad9c50946bf5df00e5fb86ed2fb1d79ceee810704d8b197c779dcd7f3e897a46bc9de7b6f29939401820a2a0b680ba39dcd72264751c4168f78c4e3cd36e3d9ac2c45d5be5a5e91887befbdf742f9a47ae2d5dd1d2f0fafb23cc053655003cf1663dbade96f2e97cbf5701110d46a9bcb1a6329fea8ba72ce244966f2e648922473cea5bacdb73fd37cac62759b6aa9beff3cc0389ff1d0ab1bf67a38cff9cf82e8d4ac09bdcd501dfff10715ca80d1a2ea4267ca553ec4a60e22c0e8ed250a3d38b9d2db7b62265f2d44354cb614a1b7e7c6578b9c6f30c14918bdaf3057dd709d71cc41af167924df7f5413a38a8c37400cd601c4abaf623e2ccfebf0e8e8bccedb2f314e84200eb8678af8207b9e1761e7653cea081e67c96e67e77754cfe9a4370b1f5dd447352e5bdbe34f5ffb46a6b4fd45c1d13b0bb5fd1519eabcb32beed09eb80cf0d5797788eebc1ba530ce4ee901cca12ffaa4306ec50b3e40fd7e18e762bd2f4e89408c83f100840fbbdc7a5f0c629cfde58259887126826033842fb7decf438c73d164ce7ac511fb1dea8baa5b14eafb1e605cbe8aa930f5de9cbea608a5ef93eabe3c7da7f4cebb5e9612de17873b8cbb543ea408d7fb9997aff0a81b7ba354ee8957764dfac284a7d357dce99b77220fab5bcce9fb56dd396b44afd8e547eb35708f0188ce9f3dcdef7abd699aafd49e0e82a8f32866cf3f74bfb6d4ec4777b52ffc03fa59db2a451081e136ab77b47542a404edd774cc73d9dace1758813892e4bfcda6a6c06633528a81739712c1608d4d166be328021147123416f6c40f8e913ca1a8b68ba5b25370e66f16ba25ed3867fedb6cb75b93b6b5214baa1498224769be8917a6331569fb576db98864675c27cd3dcbbec3719ccdb33c6b7cf11f1f21b9395f42b499dbd2a0f7f70c160bb2dac0d4367bc24cccb3806ee8fd4344a03af7ba76787c6836786c8f4e656ec33521b29e4b43a6bb3addc266448f0f4fcd6d41467c7c69ffce5292deafc9b2246db6db4d934a4f3f332a1d20f096660684028f8c00da1fabe9fd7a2ccfd9ecdfb3ec89590f4142b01a893742b4978cf6ab4d2501979080a00dc139b3b2f4908f2122d794bf4a413f888a5a0bf0593d0b1fd96614bd7995906ef8f4b4ce540e6b48505295a491f0a25a671ab515417e144b48d4ba88c1a0945a89b32a6bbb73903d41440923db294b7a7b02077adfa882f3f5c3e2a3396805a775a6daa5a1b2d9ec95b31d9d34991ff9d71ce759b8fdda657af4ac2b473deb2603bdef3a3aad33d9b47d97eda802a31235126afa365b10d0ecc7e6d313b3d9643c3b3a28ec75ba5a369bcd669636d236da3000c37987fde8cbffc5d9ab4691e12a9dc951ff20493351cbdb024a9224a96e5114c51ff7ed893727b4bfb22c33f918cf66a31dd5adb14d63704549410179b221c0f9c076606f4b355b8b30ae1fa82b76fdba4c964becd78ea5de2e70de2c2c6a9aa669fa2d4bd9ac242f49925634c0bdaa1d495d5ebfd7afdf8bfd71c62216b18865497889e636bfe52d97b71a7aeff5f975f5030bb46569b65caef3b4544bd65a186c8cc562622c63bf317bc2b608bab4274c1375c97c0984112daa01dd378dfa7dd97cd7f15d6f17ae1a3ecfd70b06b3c56228aaa36381b7a5246b6532ecd77cbd5ceb64989001cab205cc9e983535611ee7b9a27df486ca744e1ebfa58ecece0e0f8f4c166b71f371a1e55902e5ab647f6787874766976c4f8fcda7366bf1f3e2c0b5cc9eb03f4b87e855373ab4aa8232f5ebf1b84f2174e960a9e976cf9bc9a057454b7214b31016121212f26b61b0ed420b39605cc76fe96d02fd63544b7cc4d3f373ef7541a1fb14af92cc85f6c8d0598fcfab458b9fa0202122d0abde9692c4a1a1a13c34847d68e80e0d0d0d599fd90ce8d52228484888461b1a72594b44545484b6f8d29e989d404157c862d81e416757d0290b9ac972168ebe6919d4d57dea1bf432c0d54231daab057aefbdf7e27cba9a6343e918f4aafb242afaf4d542bde4bdd69e6cce7befbd379f188dd9576a04eaeace3ed0921c4b98b0ed420ff90cfd0ccd808686868686827a8686868686fc56005bb7b8accb854e15d4f6452a2d667124f348966669b65c2dd7f9b2f6b42f1bbb9d3c60b0286d3fe6d336456dba1d4a5b1eda7acf6df6b3b01c86e7b0b2b0aea6a05001a14c41f95d1ebd7be3f26edc9d6369fbf8aacabe58e5c1922fdd5cd71de39cc5eb18e72c8a6316c79124cbd2244bd36cb55caeb3e53acfd70b068bbdce0b3b6f2c765e546767e7b436dda5ede939ad8fcf697f2e0fcf7953d98b03db73efbdaa03dd6651f85cd6da6bd5105cd65dbe5de87c95ee936174de206bebb61707a22eed891ff8736e8e1e5f11d059b15ac6ae7695a7a721b89a0421b03ee8f2950052df1fba20f747612e97cbade62b0146faaa24b87f733084baf54a808fbe6a08363075b627ee6f806a2b667f952f9284ed1268d8eb057b89b0d7eb057bbd60b0d7e97ac15aafd7cb086645ec37db1809732b8c314e5d34a0f74590f52eb1fb6b03f1af3d614370e7e0bc4710da00d5f6adde595f545b9cd56c4f94e0d343617075676dad0838c0babc4af73930656e2b5ddc7b7ff474fea88702e24f30ae2e16021cf4832b1d0faa763a08960470b170dbcfde96786a2d7a6e4e4d1293382555d4257e0f3e5d964f6caf1d4ff15af1baccf3049241016af57c2bc6337bc166b0d7eb63feb222a27bb6fff76d3769d0b4a3ee9b8eba6deafe98ba6730f564e1ad1e9e54b6442aca7a91fd1511115d19a2b118b27e940361f401817ab108e2d6b4745bd2fbe658f0e83dc1889a8468d4581c9150280c23868cc50d093d37041c5a55d16e4ee8b76dc945f323fbb3bfeb130adf34f16eec6c6c098bed96644bd2dbfe9668c040876e43341a15a1a0df9f2414a45a3f1adee084b0935a9d24aab76587a95fd3dbfe92b0ae3e70db7d9f97cff758cd63754bbb2cedb541ebb17ac3b5619958b0389afa3bcfd38c99ae173fe67a20e82de18565c2d636c3e28454d2de5cef3a8dc08586e9e084ccd7514fb7394f67e7e07695f2a3ea2ef505ba6df782a925aadc763eff2d08c8fe6a5709bf6afde80ac7df49b7158a20e7627adfdc8541e717dd56e50156774d63d3344dd3344dd3344dd3344dd3344dd3344dd3344dd3344dd3344dd33481ccccf4af12c69836c318d3f4beb95a97600742412f1412120a83828442e10fdd57b86f6e687555f543fb0192a1970782089c4200da0ce88c347fa3321a8b5ad08ff9b39909125a788018637c060131ee5d24024e17a903dbb94e17f836dbce0f2c1d810b0dbb4012eba8db49984a7495f205c6d471867f40b7652ab7f9ce773fdfe1b840dff90e07f4590664fda8bcc059d3d2ed0748f6f3030444b423229aa157c99ca9d98fcccf663e3f9025d96ae80e1897fde8dca59d02427eda0c8a751cd0cce512cffbe2a0f5a6ba4f6dfeec344182037b947f93424cb0c7cf637140afc1799e27ece634205dfaf5d63a9556e9fc57ecf12b01e7dfa91f8d73b19dbf4e3a8f3e7ed24983abf481eab63c1505c550d43b85ad0dff2c25735883eb64c91fec5a271d810bed7a7f2100a373e66897fa57e987711aa8bb545de30ccfd40bb465fe0cc4b82bc447f9b31028547140f74d97cbbf999fffc4697995ccf26ca5fb837314bf27bd5a965ecd935e6daf2eafd649af46d3ab6357bfae765d8d0b72ad6adc4f596ad79ba9bd4aaed3f53332f6db8436496853032126f4774c9bbf79f48669f34feb74855729bf697e36c922262849aa33b7e5306ef6f9ff3ae13973749106fa98c5cd1ea3f9b1650a3624ebe8623d1a62f604e3844855841629c208e61c2a66a6d6727cf34d5504f34755a8837104db43efc85aba5080163b68b958cd54a803b374b1126d41ad5d5ba2280a75307eeb5baa08ad1fdfc54aa6421d90ef7a972a82ebc977b1ba5ce9dbbaa02d222ea875db5d6feab68d7ee0587635adabc0698d0623a7ef3b61c2335aa273ce6648ba81ee92e74c6165a28a1012a3127ece231cec8592038c95d5756764f458c9d466b959ef93322f60ad2e7c8ee99d21c3ca6a25533bc5c3eab2e29d2224861c2b99da2a2bab0be8144a7214c404907649c08ae1855584116640842bf923dc281beb98d904ad56114620b192aa751532c67554adabb043b4293ff0f0a3e5142958f9ad2ea2f3beb30933945a7194363ca6ae9ab748596ff08852182530298c4031ce4ee14dedd61f1b1ce3d0eb2482fb94a8a921b78ed0d2c25b830819c056e9fbb64adfed42498b93dceaaa9d29caa0d9615836644988f81c19c69040e91cf9015665e42956448d8b063409d68f949053490a5a46a2e848c5408fb08149f9503b92431092140025e9018604078f92283b455029393f48aee82819c28e0811fb622ac92166240518122433253fd1c80d4148c2c8928c8949f1701d910195521233920586232675065582024f122d4758801951b35384cca9444b7924064c490c3c4570bca2aa5c44a488437c98446028a3905c79153187cc907f6511dd6bc8d3586408932ce24389dc400e715312a10a1a624546adc94374d8611353521229614705344a86d71021446e9043c2b488d0500e5143f27002f18a6a131bb2a58cc2c15564ca8cfa220e319f642267cc21c056911bc42146ca23a2d06022534a677269fb9667fc8d39d1850e7c0b145ec1fc0a7d8d3bd30a49e0ce7de295ff6e6e04febcf713e21f292c7322b0dc61e028bcbd7aa2effa7a39bc23af7aa38ffc9dd8777b18e739581a35d7dd1d632b7ded8a6b87c0d06edd88cb45037afdfa891ddb13f9955f1b5c7b42c422c61ca05af5142ec7802ae37b7189dfbf5ca2dded7db57035ae98b8cbd93d97270f8d71b62bec5ffb6aa18a3bb75d372fcc7092830d14e4a870040d2366085170e2f3f2a2088aa9ad131f15a9ad4a16c04542dd20d0245cea5b67cad61fe7b2442db557e9df3a531ecb53e69fa2b20a8c52ebb9f5d6998ede3f8f65eb9cbd7f11ed8f6cd67339f4d6994cbc7f1ecbd609436b49fe44b624134847b60a8c4ad4544f4fbc7f1ecbd609437764feb7267fda52d389241348d67379a2416f9d49e9fdf358b64e18ba23f3997d40d3fe2c06e02fa4c10094509c4832817464abc0a8444df534c5fbe7b16c9d307447e6330ba2114001fe400750408a9b128a1349d67379a2b2d9cf5b67bae0fdf358b64e18ba23f39905d188bea6fd3b9880ffec0113b8c0821437251427ace7f24465331af9fe792c5b270cdd91f9cc826844afd63cd80012d4df07031b50b1748105296e4a28ace7f2446533da7b2ac3a13891c4644205d2d2d105360b2a4861742ba154fb0004ff1e1080806352b1748105296e4ad67379a2b219ed6b9e8e00504271a2290967820949c5d192ed820a2c304a51e2567bf70f21e7cff3f6c58108390034e198542c5d60418a9bf55c9ea86c46fb9acd539db7cee4f4fe792c5b270cdd91f9cc826844afd68c6c4849286e4b3068f8efe86838ad0040138e49c5d20516a4b829a138916402e9c8568151899aea2906ef9fc7b275c2d01d99cf2c8846f46acdc8869484e266c152d38e7704f5476ff03060e1b402004d3826154b1758603d97272a9bd1be664bbabd4e4f6101b020c52d03250c50b038e1f4feb3201ad1ab35231b52128a9b054b4c4d1fb078e2e11febf108400618b0705a0180261c938aa50bace7f2446533dad76c49b7254fb3bec082141adc02a094010a0c4eb0487232b1020900474d365c054c462a4a2cd546289fff0b884f6b10800c3060e1b402004d3826154bd67379a2b219ed6bb6a4db5253ecf4d4f5d69904f0fef93a2dbdff789d2eb0e0fd5bd7694df1feb0eba4df1fbd4eb7f7dfb94e1abcbfec3a29bdbfcf750ac0fbcfae138af70fba4e19bc3fed3a9d787fa2eb84c1fbff754a7a7ff53ab178ffda7532f1fe46d7c909e9fd91aed38af74fba4e47ef8fe23a01e0fd6fd7c9f6fe165ca7a6f75fba4e15bc3fd375c2bd7fd375327aff15d789e9fd595ca712ef9fc17552f1fe1a5ca7da8d4aef12ff534abd4b0490aea3f6d72dedaf410076b47f063eda1f8320edcf8248fb3ba9da7f8591f6070092f66f42a1fd7116687f2626edaf6285f65f4aed55f2bf20f5abe46f419aaf927f8ab4bc4afeb7542945af923f8a547695fc4fa4b3abe49f94d2ae92bf89f4af923f525abb4afe47a9ed2af9dbd2a4abe45f417abb4afe46e9d255f22f91365d25ff5acae22ab92a3b5d35a0a84b1cc9d26cb9ce172c86eee8c048a46a9aa69f16a57b3694d2d27ddb2cb685324bb7a5d2f87ff0fba43de9b6561abf2cdd164be3e749b7cdd21886c6af83a64f1a3f0c6adf287d97e09fdd08e04108bbbca22d75bfcd547793fd95eab6401b24d551dd37a713d57d79bd7d7dfa264db96c4d6d01d33ee9e64c58085ffc5e8e64cee5488ee398cb91ccb91cc9711c733992399723398e63bee907a6fdb1d0f8bd1cc99ccb911cc731833042f958942399733992e33866164f3c9abc1cc99ccb911cc7319b4be548e65c8ee4388e7989c6cdcb91ccb91cc9711c733992399723398e632e4732e77224c771ccb9242f4732e77224c771cc495658362f4732e77224c771cc36e1b0e6e548e65c8ee4388ef9831a5597c7efe548e65c8ee4388e190471d3b4f8ad3197188fb9cc39e3990c3d73ce2a56dd84b2815908208040769b357d200b41e30741e37224cb911cc7717c274b932ccdf2cb59a98670ce40c80fc2b945d025ced915444404add1de769d32b84afe654a4bbf56c403dd1968ff3183eb24aaf62a617c3aceaefe77c70cbbe5c80b296d56909a636415835a7c418b28646449a2a6078f5f142d2ce435566690a10d0d64cc647943837421898ec8550e3288b182e54d8c34bb29554b56903ac2062a3964065458628236f0680343106c4852acc22128670d9a16c0007145da1e80c8b5c0438c1150bd2b6598aaccf074668c0fbb1dc0aa23533c64612204101c575686c099a0468e0d4286e0f0429520e922852e6f72ac70028c2c6ca80021ba817155839c1ad6b440c39429a2288aa228ea40040a54d0e880e605333ff0f0b57ff1dc411591c6461b2162d6ec83ce3f9d73cea2288aa298a489912b2798b11292c47b70930437ae3dda3a91e1041e222a09ea0cabd4cc8bac2b1f328490d19a9261c6913145864f8609478669848c2732701647b2345baef3a5d3e3e136f7b9ed46b9cddff358b64e186a6f94e3eeefb704ca71d7e7f33d39eef67a3c768ebbbbdd85e1b89ba3a1ed87f081e33cf0c0710ac047fe58f6f6c78ce64ce58fafd91f7f5b6a72a61fcfc2995eb01f4f00678aa16f5f01416fbf0367d279fb0f70a69db73f0167faa1fb55e8eda7bdfbb350eebde5abc53d82061f0823a986d76331a66f72ec9a44dd8da5ace6885cddb09c1ec2244fe1a0e913ba2ff076f9a1fb95f63cef7fa93c03dafb5fa033f1d0785a62d07327fd21f4463a219d212a4b7f04bd912ec8e58a996a501ad01be9805e56d0da8fd91be966af970b0834c9e636fff1f3635241976e6ef31f3e3e96c4425934b9cd7ff47c8f88033a801fb237d25d2a3fbac015d003b8cd9f006ef3d791c1c49334594fd2d478216218f2bc6972c51d6d74c4da0059a2053646caeef024cac60ebc2657a6b27298593314b9002f851d478ce88218712955799883a5aa81f4818d2faa284bef4a8e109ff9ea4adb78a52e9468809ff7461092bd4c7ace7a2e3792427755038d7ff7272c93b8acb6e697ba9de941e9364bbb1dce824d5ac4b3198afa85d2fed3e2af258e20cce5ac508b2e7af6878022fc177b36e3b2d862fb98fc22f79114c7573dc0aba0f6efd9619cb6e12a3706c75005366b0ebd7b7827d8a1c995188c88a143c6ba7b7a9aa7770f54d2950a5474594a7858adbbc7e782de3d52da7ff7fcb4ffee813246e9a93146e9b1d193ebd169efa1318535052728130687c12bed2f83c2381731c24cb901cacb0f4684ac2de82df315210306166c58a2a6c6ba65521ae3d05bf62b929542929e1aa08e75cb6ee82d036aff2d0b6adfb22ea30e598f5187ec878c27eb01e92de331f66434c69eec862fcb27cb6d994efbf3fc30cec593951d67726489e184322b0b7af34ccd30860a18149e788962c3ba79807a05bd7982082032e7c8092f549841c8ba7954d09b67a8fd37cf150fd61a1e266b789af0f878a4b4f388593c6216cfa8e319753ca38e67278871299c12b85061d31b23c43bbd77d4e40893664dcec81632ebde196a1b7aef5c4d400629147ce4baec08b2ee9d2c9d82de3c39edbf7974da7ff3d0c0b28305cb8e969da91da0f61daae0922094e18e6fef48697f9d2b8c83400f5a9854ada9f16bb2e21a7aeb6c29f20688304f65daf858f74e8e86de3b3a0708717246386307189ed6bdb34341ef1d5e8f87f6df3b503b40c4203a66c4203a6874843a43ed3a56a24f87cad7e5a7f3fbe94cfd80da5f478771568e9424249ce0c3148d124ed05b6767c20c99253f689022e58675ebf0b4097aebf4703cc9b98a01c4c90d32ebd681d23abd757cda7feb4869df3a4b70e8c4c0a133c30a0b8e761d18220f0d8a3c5428f286da1fed61dc0a83eac96e871c1d7a2b9ea1378ac5081ea66ea4a0838da875a33e2d436f54aa05c41597286a8850b265dde82f86dee894f6df2850a354620c54871803dd81c24069a037b4a34fa22e962585712e7ce86cc8b041851f479cb0c2d03bf6fb5923430a1141cc21d364ddb1a9177ac7807b8ac70b7290a430049a75c782ba04bd63c2a195f6dfb1ab18969758112fb12331a8984f7b2c4a187b12c6785cc57457b1dd558ca7fd61408c73b16308d50e47600189a8c124e80d0bc2b0a3d2a1431703140feb8609714e6fd8b00a09951ea8c84c91938275c3e6e80ddbb1188c22302a456056603fd89476d814295894146cc914ac37058382f9b4ff6b88712e9a0451c20e2345a2b4e890a3f7ebca043a60b901072f0b971fd6fdcad271f48689b942058798a7184480ac1ba683a3376c7783de301eec29d7788dc9355e645ec19750fbab2aef5e535e54b9f7927afdf26b4afbbf7218775550e2e4ca9ba7ac39eb1bbd5f3aedbc145e2c01e2451160d6fddab9d1fbc5539f9cb440c3191e5e08b1ee571bbd5f50da7fbf7cafa83171c6ccb9cad27ec2199e55c3d32aeb04669dc12ca1f63f7918e7e2871b334222acbc59e188354befb3e7019829210e2a1c5a0062dd27141bbd4f1f1a1678109a70264c0deb3ea552a0f7f9d3fefb9c3aa75c39715cd1f7f7e98276c13973a7eedca17a9f37a8aca8b0b4bfcb87712e4890423363481318ac80ac6bf476b93012e3c91a2d504d8cd0b06e1796de2e2d63866a5648014c8c34eb76a9f1df2e218e5cb7ab0a337105c14c5c425c375c4f2e1ea7de2e20f8e782817f3480c2ab56166e67dd2d3818472b0ac6d192d2926afdb4b7a0605e0b082f4a3b143ec2ad1e6e0931ce850bc2334d8218e105051fd623f4368746dc049126cb1a1cb0acdbbc4aa3b79955a5cc0c573c20094324c8ba5b577ab774da7fb776ad1b6ec6f4e266cc2f26d00c6a37bb5c9950fc6a8af6377da6d4367fdabfccc2383bf461f93043e3c98696158dde66ce4e09218ca1460c9b9c6fdda6ee8cdee64e7b0d35783e72e0d2244a93759b66f4367bda7f9b5026102c6bb0b029bb945556da4bac6039152c81c1a0f62f7718575af1f144881833b08258adf42e79598260434557e5f3a1cabacb9e117a9766e01c41454610389cf1adbb2ca37729a5fd77f92ba1ec50d6d8a1b48105a78421a47749038a1fdddf6495762856be1f090ca33719d4be6eb28bf7207b780ff2074983bc413e69ff4df280ca8222739bd44d614084114eb0449d6075c2ba47a02e42ef3138d4fe7bbc1ab1e28c4ce28c4d46df28a57d5ce2b991470e88f61f77236f8f3ded20303324492e8735715058877a8b46ac80c30b3324e400c4c8bac52119bdc5abd91b2961649409734388758b5944f81e75238d312296315aca758b4bb60845bb3845bb48a57d888f7cc39ca5137940df220f266698a0c9c26190ded9ea97a97eb90b30ff80790a0804e30608e0902668b6ac3b8fd13bf77696dad13b2fc19163e0d0f7779e919573da330ced3c6cc5c382c241ed58e842071d32f42893c6cc0b1e6b95de182abd2108205d789070e4ccbab14f8cde58ca49ae4c0e090d412552d68d7f61f4c6534636a6ba31b08e1b43dfdf7887c630b4bfdd58877798a73dcba530ce5a098961aa87353bf0c06405a3b7ff4a807983c310bb304760acdba7844ec5820b319c19daa05ab707f517bd5d38b4f22b526fc7a28017b15e8e385494f627ed3c78dab7efb4ebac930aab44458595a628ed4d4b44de0a59b2f818a690c33a84de3738ccf2b11dc63a45dffb76bfc868ff0c58a79755baef7a5f9e178d0229283e2938d82027c6baafae8bdef60a1643460e34360c093659fd27e038bb1ea00967ed32bee48045b5054cf0caea5cb48b1e5747f410e64a162c6e56dfe22287325582f0e2e480e2b2ba104ca3f657cda04a24a0dbb5d3f751c8a961a1bb35d4f76b6ad0ddcad2f753d480a68042770ba8efdbd8a0bb95d3f76d2940776ba7efa76801dd6650df4f8103dde650df375102bacd9fbe7f4402ba4d287d7f48886e73a7ef0f59a1bbccd2f7915280ee52a8ef979881ee724adf47ba4277e9d377ca8f9d26c97ff26d78467326176bf9b1578b12f66a41061581ee92a7efa78882ee32a7ef0f55a19b1ceafb29a2d04d02f57da439e826a5f47d5a0d74933d7df7e9e587274368fc65128d1ffd010a0f1affe0638ac6ff7ab5c0363d3e3a468fe3f8b671fcd94def53e3a72e1a0ba171151d4534fef3d502a3e497d6f56a41b65e2dc65a10748f57fabead0cbac7297ddf5604bac7a0be1f1485eeb1a7ef071141955a40b798a5ef2bdd40f7a8d3f76f57e81683c320314080e95242e3378fc8a05bf4e9fb4744a05bfce9fb331e505115a360d7cf99ac0f5576686a1a7f8904447716eafb4856d0211ee8ce52fafe100de8ce53fa7e900fb407ba734fdfb7c540371eeafb3618e8c6595cac74c9014963268bc5063d8a484ed08d79fa3ed20fdd184adf27c105dd7ea5ef93d8826e9cd3f7512041b707f5fda127e876287dffc604dd9ed3f76f4bd0ed3b7dbf66028aee40d118d05b18f40606dd174ab7d1f965355bfe19cd715e459bd0a2c50dd5e871a3975bf197166757ecaf16f9ea30ced5c347f7afab175b836e574fdfdf2e297ddf25e54c4bee153940b4aa3176413953ef1607fd1b1cf49c839e72d05b0e559a53414ebb801f887ad1f04ddd6c7fb35d12bc84e05530887759474fca27ba807f418df1efd734a6000492324aa4172ef389e7836a1da1711db9190683c39385f34a9779af1a3cdf0d980a31a41be80b2fddd8d35d9dce0ea89fd4ce0952c026cc830210283bfa017b6640fd6cef836403eae7fa39aa22059cd2f85d3318b2c65d561610520b407138250886d0110f3cdf8c7644e51ce686743d2917518c17701c669ec6ef2ae205af82c1cf21ccbaaa0a12509b2299707df7ef94bef7fefd571715bfc8c3b8b32783a2f944298d4f9f2328fea339b953f70aba48e47a525f3b7d8ea04838501b44189fb67ff29c69bf867a1c6afcafa133ed5750e3c7ffea624bfcbac272b97ea0d773ceee6f67492da0a3deafed1654e405357ea0be39bbc5476e94138b9871a497039a4204911c5388209263bd249c0c7d58302aa35404295ea1a0a4c93ac2cf708591cacd3ac2d0d43acef4c5b81437640cd792cc3e1f737aeb98fa151dab08b74910619aac23e42b7156f2c754040b0497758413a8be0a78c010400d08e005bda54df8c85fa90b7a2353d79530c4d43aa6970417566fc1841aa0d631bd466eac2eb2cc5ea60c99e03aa6178d95d5d53aed7d71c297e03a065946310621da6431020607197284b09a01e6e39980cc1a3725d000d38209eb189462441c538a958ca7f2c90c2d4f66fc744cdb273372c0d222813241a498e111216c83b3a0985a41890e5e7468c30563f91c3e6e70128304333a48cd9a4c692b84b64e74b0d2285902d15dea7bee406966d03dbb679660e90cb475b2244a0b39404784116e1042aab7eabc75287f2dc0ae3a3a2aea630b2eff5d9b31c619bf288ee2288ea288313e4770b5891ca8433910ddbbcd86d51a0d74a3da51d47fe39af147f2fdfe78bd063eaba1b85aabd63f805d61daa3fb68e9692c15f277fd5d61a990fff9792553215737c01abfeb99945bd9d2b60a9b307aa33717ba65a6dba64d9254b76961697eb568fd7d6d805be29b1fd8f4f84ebe7d3939fa4b5df2a352bf44f556ea2012d40cb537dd520dec89fb4126a0af77e9d2b64a1a2edad5b2e5a3ce95b3bbbb6aff031f82c06daeba75b76e1de79cf39679ead302ea3f8b01bb19c9b224c72360a46024c9f1861646b2345b2db32447373c18e2a3214772446a73de7b84d5187224c714aecfaac84896a65992a38e23ac46921c7f7073a507940c7224c7204fba287132a6857194338e24902339c6c87ee443e6c3921eb21c6a0e21d345a920eb61c90e16a8e43568016a1af4be5f6bcb6ff3e3fb982471b624eaf9b105f47d2c922ef4bd591473a431ce30ac8abba8968b3abb02bffd8b44dfb7d7ae660e9e7b6d30a4af6afaec097f211d39b727448c028d5da38f26c8246f07a4332d4ecce1231773624ecca91520dfe5d75e0ccbea25f36adf3566ecb04cbe38b062f4f8fedae0c82c4bcfb0b195fbe112eae1abd376e31745f1e6b2548f30bea9601d70577fd77b04fdc3d511ae63ac273213d0d7151ca83975062d7f3a5c64317ec860a0798d4e148a8fd8510115bfc84e40c2e31123532303fa06e5624386c30bb21725047770f4d8a0838605ab305b60d8c981eee830859646748aa0a490aa730679a3e7c6a07ed436385c799566e0ace2766bd5da647189d45b0c92297010472d1700816e83339236b500a780812c53e017a54906bd7131421c4a63b6b42801812d24362d170a9bcba0322eff62b1de62d0bba43072be92c4da90170c8d8961cc76061643fab7d96e370f3a12438f94624075e6d8e0ec689cc3d2d92153411517ed2f1e0d7778d818fd8c0a4f09a1f6ac149388231383b591851185f185f866a74667c59036dbedd6d4342251f5a438d221f165b431ce10e7b0415392c9123d2bfb10945da16afb60c4a03d1164c3cfec4b1a0cb66c26cc807e44120254f4454c172345091222831291f8820ae5d36d2874a00d896866b42128434442312a444552f4f62cfb3ec7e244213e22fec642c6dff807f91bef10832e5cd9d02e0e6790627076d37b36f2b4bf18c447a80c62b0e8bf0005833ac33fc539b64f6740a88e18b447fed6bec8c5e23c4b7c3353831a518a6232e6a5ea69456f3168c52fda4b40ed0a9cb6ef4ad5f48b88d2215a2a940601a5e92c4d7f529f9e589a653c3b3a689aa6a959a6e428a6d8d3f4620026065f62306857d89e5c8a125caa1bf4be7525dd0e3537bf5248004a5b1c0c523cb1c8473054e4a1232ec848591694414628a5389254234254daae86ca202920a51db3f2b6e6271f15e133abd223877691b0c8f2500d3c4137ec5cdb093a483e3423f1e0ca24842d51c49edd1f7b391485ccb72a233a435011b9cc81de77ecb717e8fdf2838066294cc8003edafff5e680765546e5321163a603ba73920d7497474a486441773e8f4077a96d76858bd65aebd65a6bef0e97084028b5ff7d970c7497362b025283506aa10db0f7b02730072f6d55e725a580a23c06f85ae2233f4a82ee8c2e41793ce73953fe5d6a9d97d3582d5106e5c0753e9d9c2327a7b17aa6417799452cfab50f739d8b0861525b274b725e4a1b9aaf462bc8691790e90336dd81fc52b40b138430def8c008d1c604cc83ce34bb226b4bb59b11040e14354ad8ace33fe07afed1f5cbaa4bcab5440574bba4fc97b46dd2d655c4288eab88d11ca32a232b232ced4670a48c8052464129a1f637e2619cad92821738526478f283308ade463d3447a4a4c42899a2c2ba8da03414bd8d7cb92d4dd00c0922c30c69d66df4446fa39ff6df465346535c358c70b86a18b960a433da6937bae1dac171ed8c60b87ac32b57af4496f62fe1c338dbe5ca8b255a803f6a20013bd1bb846fcb0b6aac54ad80e5c5ba4beca07789a906ecc0c342048b1a2266d65de2a77789a0f6df258425aac6940832a6849012bd1250da4b001996b8312cf19455229755425762a7fd6b53403cb97253f5a3a189de3520961a2635048181cc9a75d7825a07bd6b3f64958172041161e204d75d63a277ed4afbef5a560d4e8b492d4a8b494d4a4d4afb4f7b0dcaaf06e4578b02d678c05aaf06a5fd490831ce0e212c22e4c7952531aad6257a9310ea40f5420c45b2f0725837892bad446f12595b786fa8a81932c5c2ba6b49f4aee9b4ffaeed6a375a3590f0d2aa81c4171250484c2141a59d440b088916107d7f9358a2fdd52c8cfbc091210c2266b06145b722d19b448ec44efb1b2b53c670598363ceba49f0b494de2436091240e2ac89c366788581de2a564eed92ab6aedd4a9d64e05b6766a50fbab3b8ccb808d174a644cd912c411bd552f47544172c6061abe2feb567bda88deaa7d93a5431539327a40a265dd6a11bd5529edbfd59f0ac5546b98aa0d35a7eab4ab3482f8c80cc219a6c2e17078a5fd53288c5b81c29cac5f112cdcc0244aefd40160825015c11a62820aeb4e89e89dfe56189cd4f025d7c40a9b75a743f44e81da7fa7c1b40b93b40793f4474a23bd913e694f79fcb27e692ed569ffff61dc8f1416568842254b9b22d61cf4fea967c1871edcbce0bde9d1c3badfa7f70fb5fffe2b2cb3c733317b7c93e7f1403e4afb2f31a1de847a13ea8b8218b7424e1a1b457038a1861d84e85de4e2c906126cb0d1029c15d0acbb0807bd8b461e0a37b8bc0903a565dd4541f4fe9cf6dfaf7b1a668d222c668d222d454b8aa0144d59d2bb88cadc154199bb22df2e9222cad215f1b4ff2eea15f15863660d1a222aa22e4455da89acb2887e5944535940ed4fa4c3380f50cda0d21d412487901588de443b385e6008b243814c967513f16ed09ba877e288950ebc34bd1a4dd64d046583de44be357a1349112df14214c30bd10c2b2c38da8960088782c221a170a8fd877a1867bd649541814b121276bfb506bd87a04a6832868d9a2f5f86f4d63d04a5f7909406e4d028218a90c90b22eb1efaa1f7d094f6df43c021aa28433aa20ced1882314463e8460abd879ea6685753b4aca9a19cf6a749619c15c286609037737a6d7ef0a137ed07d42ed4fe9b36d4fe9b665506a1152983d08ed09e683c6840b4d3a24a9aaea4ed4a1a4ffb0b0131ce6a6943c29c345cda38a9d1436fa1a0d05028ab4a6f5a8e06a3c42144a5c46145bb50949094d04f684abbd0149e508f2704b5857cda3f68887176c8c20c537c6082a5872f2b0fbd83ae2eb0f1338302950d6194ac3b284bd3a0b7508ec6973342b0f060268799750be9f40c7a0bedb4ff16e2093dc5091a1327884cd09420aaa02e28f40eaa2a83a4caa05f1934a5e3054169ff1de40b8a1a1367cc1ca02a2b2ced40708640c021507028d4fe403c8cb3728ee8a2be544163e58d0c7a03f5807cda898021851d622013e7c6ba81a47a7a03fd78d01b684a3bd0142a4038a800b900070806108d24bd816e0087c02b6096f69ff9300e045382d83862640b112ff00ebd6743ca1cd126852e3964e1b1ee198e41ef599a2a3162868849018fc6ba6740ad43ef5950fbef997056556416a4c84cc8ecc6ec69c6c384de332052b39cd44c27b5d3fe3f531897fef0222589148f2b403ce9fd0314fe5c69fffd93f50387d4f11385d4f123e507c84fd4cf12ed3f50c81f1ef9d3237fa0b4bf8f10e32c1a1c6cc0700299aba71d5618f4f6198e09e24b95135e8f20d4ba7f5ed0fb47a7fdf7cf4efbef9f1ba4093e5e48137cbef84099b27d80c0ed4375a4b74f1792864f144943dfdf3e4b723b9f9ef6df3e50dad7ed03c4cc1a336c744f971ee1f04a7b0fd655cf549e6ba854891bb06a1e430a8dd00c30000800d317002020180c0a265194c33018a8f80114800f57d4466062349587032946410619639001041000000084101828a2a1028567d1b226b4bd4aa59c74df112fe9e745961ab089a06531c51865e1868367715b8b3ee44983ebbca863a5773581d46121ca4663cba6cd4e0343c4d04673c1d5e7ac7d4ca5d49a8a52d86c639fed8a8b53ad8d484356b2f15da32175023c5fc1a1a3406aae947f48ed9b5b460b9a4d5bd7db88c6be3fe1c1ca7c60d8bfd9407f0c2509760f9f687fa5869b0978248ac902e205ce24157cc869dcdcc279362e2dc234c9d64ad65cf3bacc921ded1c2908afd2b8a90c0ced1d3b51b5ac94de5dd89131936765151e21bab3a28e5847cd3639f6d321ab887fbac5a7489530ee2052d3f73d3ec92aa346609b5bd42c5c733a10bdc4d189ee47eb5f105567229052bccd95dade9f3c9a3cb901f0de6ddfba5f1b3c0ba5a64046cd269ceee38df62d9d5759420046eb4a22e92f545c77935e85aa3873e962a4d61790ac017f8d8041b62b4c1d6d07a096110d7641b481ab4530c9240d7a106ca74b45111886559b373f21036996b03a3eface203126c1929a0290dc1cdd73498cbc29e224310f46d68cd41753b372cd27ea7672120712ca92066b3f3e342fe9cb3fe3979619c98399fa90d8cac953500bddfff3782a7673ef857c703a275484638e631d55bc5c8683ea81e3b2397812174e72ef64762d26bbac995189a33a50b9f1aba67050ffd359bbfca6bde5373d90dc96d312d0342c4dfa498d22973c4a2ad04b56fb8dc30c150b00998a885acc67c2b0bd4ace29bdec4c75e3484c2a5e642a47e31245a87e440544a057268c2353fb3372892516cd5782e6e25da7d3a25c45556c9e0f4ff21582cbb96192aeae59c05cb5e01c51f615802a46339bc463b0b84f264f2ecf6a93c4f09f00f63ffcb14f0420059e02a411e59cf116b0bc95778e49f28201595f96aac13a961b84ecbdc97228473f85a22a9d7c598e510a0c265ebc3b94131afb280b09b54470987f43b6f1e71c6bee53941322254474f2d010c398198da6561582dc7411df68d6599d2fadfa528ffdff6f9c95f985ee388ba1c500249e55d6b2cacafc1fddff87e4a4f43ba903975ad434713bb177a999b640a92aafd452a6bf4cb9d0538af63b4aad4f25d336a5789b5002998203eae2f7e737c5aef2444cafc3a383dc68eff571b06f34ebacb232ae8fcea11db5540ffd7bc70dbb47def4a5bc118c853a91177d6f9e43f3e80f8d47ffd102f536df9cc1631fbaf9a24ee4c5ef7d7e1855ea7bbca4b2f3d2cf131f950ab22af5dd04988070c6a17f9442154d9a892de5f2fc94b9b94e602c4b8ecc5db611f17526c389f751ba5c2f10d1a8077f8c1a48c942839843dd5f41271aeff52fd08538eb9759211e697a1999e804a12fb0e8c584dd2f985a6169b3e59578a6a020f341d1397d4e52e85a1ba67098f43b87735909425ac10f2175b1cfb46f35a17b6e7c7d2cd0101b81bde7894cdc708291c5237415eceec07282d278fe506cad1ccaade18bd176a20ea2030fa84a30c2158dae71c199330fdb114f199d9ae04a85062ba6e8c111e27863b4fc4c37eb1304b2e753bccc3122117b0d3147bb809f72d7847fedeb897fde4ea9aff7dff4e223f7ebcedb48d945a29e904eb2a694797707b43287e155a2a6e08777ec35167c8946eaa18dcb15bea2d20d87aadba98cc825b71ef8d46f3d64e7e5fa5c72591e78a45df446a5a579f472c9072d54a791f92676684950142d2aa602a91cc422bd3c44e8ff2025cb6a2ea81bdef5113c9f9f8fda7440866650176dfc4da3e4159f51b2c02345cd75e72bf41670993b0228bf78604d8d34c99bbf6e43ee982d81661ecd77386183097842cac467d0ee659e022248fbd1950e168a9b2a8f5587c04116ec5021d03074a5f6685c81f5a493c2294f99e43a7e43f17dbfc44a0ebf17455de1f77cae669e79e37450880ba930c10f9dea0d92c375067bf00f0e7e30c206fd543c432a57acb63b0bc3efa813c644fc73dd07b058fc8359eb3911bf7228c07ccd59c0f92c72ce021668fee6e8382a7f19d150f2f746529f09a0fda529f91bf3c084298937db7ceb9f032a3f1fc46598242a17d63190c43dcdab7d9331ac70f3808993201dd575d044aee4b6dbdbfc981a58d0111ff588a1d359b5fedf77d290ffd13442b56c90090e73c8fa2700f9ecede018d5cee57999d28dbd5b48b2dad44f39d44027c01feb69d853d488c0451d267dfb78c78ba0734921d160fc45cd86fb7d86b85552ad4662692d6df52b93006f7b1a373b7a6f3d5b77c80eb9e51a0f6d6eaadbecafe6aeb883808693df48b55a07e13d3f0706046950687b68f7ad37beca9641ff79a0c2e0b8402de30e4cef6a3b39897c2783f508e9497bbad79b0260778a527b07e189f7b2f918d0a13c8e5404d15d2f8ed982c379eaab88783372e8d074a9ddd99db710b6c1872f57e79cc91cb8737f0422c9d0ea5d62bab1a109148c24bb35e9cef7d2ef3f0155967cc64e075e0dec6f46d72d24c5be29b919f89dd651e4f522be9414b7455572a4c2aae1f57181b1d674e20b76e78bb6958d4d821c2016cf0a6a6a0a8d6e75be026dc4b689afdd3cd2cf2838ce73b38c1cc2733567d618944c7874d939629c762e6b24f211a07a54925c7000dc8d48db39a73b10191a48914541df8ad9918ea0c46241c2ffa4f8b8a24102e1b1912ff428964ebed4882f6b10a84aace2f59914e782ec559ae703b6b0dcf2b4c06800ada5fe480cf9705d8d1b339a5226c9cfa3a96457721029c1b6f5876809b0f7159d6d12484634c2110a0320b9499edae7d03057f54bc87d4a3ff5141e822e329513bf2a077be5c6ca62ab8a9a8a140fc9e54f0d717496273551e062372cd6ad0d4b85a207b9b009fd5cf7f61cb32780d619b7f9a0f9e8ce646ce5cfba5e12a0a639d3202e42dca0eaf9ba2f8323fd1a6dc34c58875bb4044b03893cc11fc7b77d6a20830f4e5b5a24437c4b87d7f5d96b2258860fe01f86796d1bd11536b125fdc8be02aa2efcfdbaa2e97dbc1b77978354f675e7dbde6fcd95d1b22d7501aac64268414c5bc939eb3020b137ca5722ab5c16909b976fec16e9390007d4b678ccc3e356ad977c784b40496f1bfeb27fc7649a0f1a28966fb1f834eba1753297e8604b5058a37de7c076deb2ea8e450b4b56b4e47f0e89f3021d5680f3f87e9ae0b97083d8d8aad8a9ce5f64d3f3fdfb057d7a0bfaf50b7bf50bde61473b77f6ec17ecdb2f74c7ce5edd027dfb85ec3c1d1470dcd98753508b830a1dc273677f4e413375accb2ba8c1a1426b71ee7011ec74f2f63b930d3d8ffd6a65965b9f5b5c017e0353b9df2c8fd9fbe21530d34e9e3b7abe4ce285a2466f9707a6b33deb6eaf450d2487afeff2ba21164091469c783bccef45e927b9fea057078f1233d69f0924248a1d6c2712ee45e89e39261d79392b51e82e2a670cbd7c8db998fce4305da877b85e3eb7574e3905c4286d6458a333cbde24a5623e325f5f96910ce1f53cb97816650b8eb3430e6a9892c282a237ed55ad9e3278835a83b5247e478877fb1a2a3eb90bf41361b9024dc17199ee9f1148f47824be669f6e43bfce83dce230c598b0db7b95f5a72baa661b1188ead1696108ec74f856efa6564ec5e523d757072e4955f913c109735d514c4009458b569a72eb621835b4813dc750b60562feee80d4f13955e79685e3bca22f843fdc393487af7c0daf7b34dce7d00adae649bbe62fbf98867f338aeddcfb9c697a5492a6aef43982f5f3e7bb02f0cda3cf2bf322b77922963d6a7a83207ac661b7c61e79450304608150da40dda562d261472254ecb95e7f88d2ec5de289fff0ad3f75c0fe0941996247d82a0a3d1b62411caeab5f5f50e22a0e3eb4158c5b95499550348ca6f91bff91dbc0db282cb24ea729667a0c71eeb6b631f2ae6b1d3bff222a210e534969d5766bca7212538918b2ef5477af396468fdaab81ec8d4876c9f4d1b941a03dfd012d79e234070d053757e72142ab2e49c9cad9a7aa907432dab14832def283cdaf021bc2aae20416f3fc979a87c7e0394666f3f2b98bf15bba04b262e3847251aa568a2044bf629f0cc3ff820a72baeda9c8e5841bc756f2c4cfd2e409aa563ed87425da2ba5a77ee11a129249a06df0f41444cafc91f0f45f3908f2acb21ba7f5587b3c5aded7a81a6586d3ee091c4984aa0edab4d921e3bd171d5e4aac059d120df811fb17cbb409e5770073682a8979aedb3997414dc2d13646e15eeefcace6113fe29e0f08a57361c1f87a3146be1171454897bbc2e96f66b97beb8135e545dae14fe51f1338c15b0f6d8b1e881cffa66df5aaf269736b56e488d29fe7ce176ceed92c7219b3053b15896195225be4a2d9a62808e7fa42d8fc273799b92a633ac81a5c6cd8ba6908b5e6b753b12093c56a4da3ec816672240c2a181f6127ee30250d426c0b99841b643840e848249cfff7d83443aa6de74654c12e0f48d39d6a2afc799949680c7106b74570a424f66936fa7b062973ea4fbddd33c27aaa21ca283efc9358d64317bb1c55e041ceea0e95d2b0caf7d7a65751410b5736848ed24f82b56eff78a68605126c998837017f1d99e7d646ff8a4cca18a7dd5a7a5e185383403d7a1c9c3782f604cf072c5747101f6c6e7f5a2921a086f60d5d7abe6acb1f4f2ac9c91c6e8f8e986014cada507ea12e471f4c21d016d2fbe187724a5699bae881d11f76f74b09aeb9a67ced28417b5331950e2fac3ca6691f83f4952c695e82906025c39f6abc9ac2ec43258a01b61340c22d7e5892dadd5cf5690697a600ceee77a0a4beb7afb5d35c314417af0ba2c5eb94b235589400af20760600b05d2681128575f6bf668b177ecd90fbbbf24dfc606f8902f4282f6888ce0eb82f6d858483e7c22da033e445f28373659cc196d6cb79ac686b11d0e432a823d35d8a303e5889bf581e6ec9ad382ce74cbef14f5c233c6ff6364bb69d4f660373eccb5aebc5befd1f13cbc787640e3bb8c104e2c63a8d43eb4ef8fd084b11e198d65cd9ce8d86b9d118bc8fcb308718c4a152cf0023f000a2f5b43782b4f985b25742f06388e3556ff9cd7f7954cd2f6d2ba79b82b25b7a98a20a5d4fcce6f14dabdce4016084a664ec485fcf738d55b832a3e75d080ddaf2e32e9566c3d66fc30dec78b722394df27d9e157ede7b68ece25f0a40f0264737e0e2f1389de87099e0a3b31c8daeb7333964662aca9bbbe3c7cf5f87c7a4e8afc65b9e702224d4fb1100f47d986d2a8ca60250de7f478bce06ef0ae81cfcde8e1b1d64d190224878754af858f2aa01282e74111eefc677c6018d8b48eba0e536944ad8e45c9205cae6f76a2d1b1410f67b8317e0259a84ea119b77c501a5234577202f09bed685de86aee0493b5e7bf743fef78d6395e5a2b5e800bb07a2a48be2126524ecae1f4b93a06e2ec6c08abd08fdfff615dd7bbc6e5921ebe320d757fb77ec0c4ffdb7c6f0d17596f7e514af4efeefede5a03e9bf6bd3b8ec19b9f1a96f0501f56eec721997db30d26154c2012a33c492b0e9c33a97d7bc63e168b10f6cbaa3537c321c78d6d6656fd040ec0d5129223d26cd445fe7094baf17f61b90212442c69599cbead1f48059a37fd37bfd4ab1affc0d7b8ec77622316b26d6d05ce27093ea064e3ba655870fc4936a21af4aa5c46a982c9d9d0d4a79afb583fa9345727c99ca696186cf96dff78eaa5db7fa415723431364c324eef73e0ae89f96e5f60b9876964558e239a85ee3655ae8c9355ea490997197a1610ddc19192342e89f3009165cb3a16e4e9be718bd02baa9b07c0d06449a47e9555c3564891d76b3b40cacb5ae403399194c1ece526b9392fd19c7b772bc50a8a4112450071e9db6471f26b2df469a28fd1a4763851322cb89d80f3caf01596740b5aacb4936c1fe70ae6f8e83faaf638a472abe4072b6ba0a07550d7b85ea0a5293fcad69b215605e162c3684da7e2844a9068ad9fe7af78d25b81ea379eb3fbf7a7d0ab175462d06e818e7a1d3a1ed6ffce0cb879661892ce96408c1197dd3eb7ebb45b47618447247a81e958468957239e9b68f20ca183c34688254011dc1f04f13f336e723fdafd02f7489c51c22c0c65caa1b3785b00f51720094e8ee82abb94c375dae55e40b25610a6b3314ac9b7a1d4852d4f1421616bce457d168bd575bd30834f7ac090f5fdaef2019e5e972330e2291e9abfce61973a275d580239dc0588a0bf20a0a0cbcb7ea1452396e555076f698c230d0409a394d059c2939b6b6068799c6561f881940d4783c7757f249c0e43150ebdb46a7bfa35ee8116270fdcc543c8c384c4ee3b6708268888c711c96badb4bd94f3ea1446cd28954d0dde9f6f0aa32d958cbc888c9007ec16fbf9781d2affc84bfc4fd61b22591fa2f3394a26eeec3621a9691b98ba1191f6a26e202485d91f707e6338a442da1af8c0736f28542e60c7709bd07d65a60ecdc35ec16758404a8485091a777335c80e28c74f8d274a72e0cdfe023daa9bcfcea45ed1eb15e6b717ea7fd344d9d949ed93be01e4a61c3fc3e9dd269151dd5a16d55432033c79990f314d8b13f11d34112a1913e31b0cfc2087951b224bba2656bf57548143e0e66c20d7c807763135f7f1ede1edde019f061a58f1b8d5b20d0a3f320bee3ee0014084a2ff19bd6e55aea5130ea93410c87393729020cde15958ce506af4bfd1fccd2a569747df2db5e50a551de30b02de3170dac3d52217c0313adbd213cb0b7a3d8f59dfd57de8939fd884815ed9d67909cf4db43bcf71c33a7122b9655459c1000ab2bb3556c404f9d6349babae05d1c69c1e532bdf64cc952f0df2de1e2d4418711d670653b40b2442d89efe14e07ff641adc805998984b362f5da445067e2154e56b158dc9c51fd3373d76646497ad798ee7aea6c6f625819ff2e7a76c623c46806cca3bfb9861ac348d2523f8ad089cac7f642f883e9577e9630a8c6c4d402538b42b4da3bdd853984d76602be7ca06bb7fe9291e426c25456e3692bf8608c0634ada05c8786818290a87e1c8c1f22d19552f452239ee72e1cfb9b340252d1cece58c3645353ab8ef9702a93236a55a10c50f7de444211a462c2c00a585328d0ec47c5cd323a43f0cb798160bd190c813076ed7080659baa38fccbda191699185cd64e8e69b4983b739d2cc9c3edbc266364a87b235896d7e6735a8775e89538e42f099a39e889dc6c51b4edc2967959a2980fa00e5671ec08b48fde8f9022f1753013a5faebf182b007d4249c70ffb9985c7b6a8849f8699cccbfb6641934059925bbb51f0385499a48b2762871a96cfb3476c322c7f186314439a66f0aa4225e491c5675b151278bffddc6f2825d15cb1c0d2342fb20302cad79a54a4ff38cbbf1dd74d087abb4beb57f1e353bf7c690bb72efb47556916082c4315ceb2f3ea8f0ad12678f328acccd750230f213eeec8a74560c08a5ec12a5530a1117a1ebdc93c92afb32fe87c5efd30d84c140b2eee3b879d30c9f7283977c74dbdfcc9d7a89f942dbf71a1678adaffceaca09bfbf34655f60c34e72b05ef848293669023e68a3f95bd5ae8e474023041e81bea132c9277514a208e64b64a89376f76f06ada142887412aab912eb542a3492009193e3e1c3eeeab1e13ede5705a2afb94b24720df5f0ee2d7589ef12c0d1c8a1371de62c953b2116f8084f3464952051eab56876095d7f419a3ab8931e2482a783f7c5f034891c612b7122297e03c343c76b4a080d35db53265c1165a2c73564150bbd6560815f3f3e13aeca3ae20d0590db6eb3cb64de7df43b112a27cce72c47f9bc4bdc540a2c603e3c570093438b3d5eec5657d2cd67ccb5a402d11ed8bfa569b6659ac2053f645f2a4103f87a7cf1db1fa721fa24fa09c48e7a6abbad7e924cacc2f01a7f498f066546c42dc185d8574791f83f2c5d9913ef0d805ff55ce4efb32c769ae26667a12bfbeca27acc8ec22c753120ece2b72102d4beac253ec18f014cfeaca7839c458a8600a81397adc23acf24d0e97260695ea5926dd6b7f8b05f579b0a670b790474b4f367d4c219ab5c42d3b656b3918d448f311d5e9160701b31b92a2e445fff06f08afc1eb09d0c11d14b06e00615e14465fcb5998396a5782d09dea6fa6480d1daf972cafa083ce4dfefa8d0e7be1d88ec7d34934ec42a9ff4817ef12cfdcb2ec3544899425c5224f659d665fa09ca9d2803c49740c6276de2af4d3c6021f6aa5a936a44e651fdc6e8a663ec3dba3f635c3c8bb97f37ecff498da8d89e22a7d89133589abce94c7affc6e7c02d6b0406afdb20ad1ac4fc1e838a520afb287e81e57026ef8285272826f77309a60c1dfee4b2e271c390ab98c0bd7660a2afa669f42faf5be6a1efc66fbb407f9ea12113a63e40265bbaa98590354b604012760d34de84cb3e768dd62bee137d02af13d1a6869de9257f94da6795e0d64be436942ba7b67a206184071c26551ab221c017d1d20824cc2d5eb61c288a77d89dd7fff174b055e0c3c40b924657775e94fcbb7f9010a95ac3adad9604a0cd9c0812298407315fd7933223d3f0b172cb41e30f4451109380604d97dd5d383faee1b76f5566576f7c3631fa962b86a2aa9aaaed904e539536f886b94f392c93c5ebde8295b815813ebd77e566b212aa0ca10aff53752693b6087d54508e3ea0f5e40d1a757335280704c69b78d2b72b4e9eb3379f02510971b667f212da94b6a492d82f743d2e0e6da7dabd71e9da373701dd9e37b688fcca17d7c8ed375b29696f36a5ef4777b780eeea17d648ecea13db08ecf91393c8753a327d7c406cde46bc7f6db2373681c9bc37b740fce017360d2f9d7f357b373b4201dbce305bbc7424a224bec29755a4fae893df55f31fc93f2e07dcceb4cb4f74cdf395c9d7bbd6d77fd7ac86139b8723d743fec87ed61bd0bb5cfda31ba6b41bd4b2500b80be8aa271f91ab7fee8f74aea50f885700f68cfe398185ddb844ec45e3abe69d45d756db93e408b27252e2d93fc9bc3e5a1d2ee46fe6534a7dbe8f94e2f32f44daa28544259bbce0ef01ae791f30858791be5d850909df32437d8feab36c7e87ed6a6d2702b4728523e57e11140a3ee7287007a4747c8c1727d5a48408c062546f750bd27d19e2955dd0602327892931b62814cad2f14afbae02a61dafb7ce0bec9f9549bd3ed068132fb2383bc3e8f19d5ba6608a40167122d318b50fed5b9d04e085363c3a26408a80268088986b33151256edcf6fecd7e96ce75b3b4485815baf6a29f2f5d0a3e284cf5a6a18f2050863de89a1b3333ef86d34aabb8088932e23a470d9252e94dc1fa04df083f5494e208bfc1bd017e406f30a3f1a78da234d755ee809602aeedf6394ccc1fb0136e27f526ad102c5bdf6da0680e0f1ca5171be99c6f1d01a09a6283102b21e50d1e23b296dd55ac3014027fe946f0b3562667cb5b0cfa4b188932ca030b1e0c9803111763f50d327cb2489bed2f93f3382e84c21ea4d2ba78cf6b2ec6dd1c144486d9ad55e504324ce8ebe92295b4e251a38020307fdfbdc10626604289e4e4f5f8ea3439a144f1b2d073035eac09e0cae7406482313f8810c17ba02a61faf544f8a6968f4db2ccfc4a76a69f7dbedb9491a57c90faddf9f1a0141d6bcb8c5b00014d0c89b6ec324346ec7fe9756827811c1d622296b65ae0e2b6d0527769b704a4113309c4ba8415e54aeb93c46b57cab965000c12d94f3718f1936e00312aee53f120c4ce03ec4c6be50a636a7c45ee98644d4b7a1365133414596eacd5ead2ab245c4cf78b23a33040d309c6331a4ee4010fa1934a8da4ced4c8047055502f0127350707608354098dc29234bef41e2fd5ed10314592bf079370c38945b0578643907cd3cf8fae0569e07afc681178e0a8142b0962ddacee3ef8c452b162f8e9ff3273744fc073714fcf71b04fd158d0db6fddfbbdea60002fc899980cebbec04f3c287e5bf4cb30e873133dfc35c783d44b0547844b1303c905888785cb22c7a78ecc1465a5df4f6f0e04254c2138f19eaead357d2ec9f4a5a22cff4c5316270262f6c96f4789704f45497a2f6f096d0f49097ae7a565df2f48851e9aa6d89b9ba53b370f78cec400514d89dea00f55f2beeebe98eaf0e873157e276bff068c6d9368e2f396ce3e89283da38bfe4b08dc34bce6ae320b5b336cebe376be3107ae261603419506ce4a2cc84948de18b28c814d70c470b975f8633d9311e11dee1669c78f7a2dfab984433c1a07ea6be2a473e987cc41f405b3812d1dd15d9b5511d2a2a450ea965389be9cc0773b38205e30815c41df02196a445293b13d1d1a26fd6c6c4cc909bd0a8a088654885f3a3deba262be87326ed18b68ebd62960bbdf1cb3cbde89609bd57cbeb7b3dcba27a2b96a37b99cbc87a89972f7b17963dbd027144206ccbd684b1f27a43d70a97bbe5617bc374beb3a0c3cbbce99df3bede0d771104234f774ae4c9b3de6e85a4eb91542f5eef403d9a9b591d819b50fd967b81ba835b4cbd1677bc3a831b499d9efba6fa2ab7a74b41b96f5b7120532721d556167660ff85bd17ebb5d2314be469e989f2eb5af32a9cbd7d06092abbe057824317ce2538ebc219090e5d3896e09c0b27253875e1840447550d2438e614f59fb98f36d4a76118a86ee0ccc4cc98d5fb98093e74948a8e963257cce7a2f9dae06d947596ea122fc8235a70f752bd9de988c119261a0eb30d406605c6f4abf244a0c2756d696ca76337dce3a9328286c0a05986d02958fc3d82d718e8dc08a750f72b6be9f1ccd25cc649ac96892aa10f2ab57a629ba77549eda1d95b9ffd16cc6c2a7094fbea48badaa42fad157de354faba147d0ae7a7e434cdbba79f31ce265aa40a80b61c8a2b7c5e317913fa7d144f9ebbf823d6a677061847ab17f38ec44d8d68db16c080ab804144e8c2806a257926ba3c9e566095db1a86ec6df7e799f65a96101ca89fd16ed28f0ad83c60d7fba8f9fdab29659c2206f1406ddc512a664cff8833b102dce8d19d0cedb615bf1293d08f5bf1b88a6cb407f8804ec13f432eadc2e2030062230332ec9a5dff825a0690d67684b3f61cd9ccc064a802982a647fb2cf1313d4b317e5e09b2ec6ed650e5415220d82cd48264109ddf685a09767e70c63d2a0d81542523b55c353f1fd6f538f39574ac2e77080b4e66fafc71ca746c24ff383f8ed6eab8b39a782de550097187478acd5216c1bd91b0ec8466a5600e01ee950f87eb7adc79c15be743ae0fb6c1202c832b9cca327fedacc55eb62ee0a7c4d057d9f4d826e2c635293c240f1eddc5e8fb9bf022f9a5b949110b9a5e463fb620d31b5c29cbd73f640d113fd6ac7aaea317785444b5dd6f84020a378092c492f2152384cbf9ab94a5dc8bd95723fc60de2dbbbad16736e35301fa261f9dadd5e8b72be02f85d9f4bf59962658660894f1ed79c504e25770613e3a174fd6f578f392b30242df839f6099e82b8404d488be577775b3de45a01fe55f0f3d9255c29d18338513896aefd6d75216785a75d057d3e7b0308a52980e861107d75c72ab52877056ffb4d329b723781bc0bd70a09174de891aa1345fcc3fceb1dabd4c59c6da1484fb147717a27229326d0532b72e1f55e6c7831c4bfcad98e151d76ba0563a81928211dceb0e54ece84ed2cea3bd25c11824642d7e4bcf37664512eb435c7ef0f851900c735ccf4c382c6cdf374e7fedae8e9e52f2ab89193f30fe155838ae33869157f59b684c153df87f4316e70b8e36db83783ce8fe12e80cc62f54d48d3dafe9c8a29a78702d257110ee6e7641404edfac842e9a07309f02b6229e2ebb99fbd8551ea96c639d183058e7e13bcfc791612270f8a8680e62df22e6c75a68b95c1a017514fc6bd7b018c64c47c9bacde136e2d1d30b8bc4e3b1b33e948a9ec0e833d48faeb2242dc2d1668f7a25734ccd281241e90fa3d940ddb679f6fffd1713b467be7fae0ee21d150b7a3bb8744a3f05f3084e47044cee5d1264bbf13f38c5a65f3b1e1b63f6ec0a23ef8430e18902889184ff82aad61359131700aa3292841770ef8114ab9ecf609cf7a98a841e22eebf3045b1702f547c46551db1544826ac12c0fe9ba185c45dc7fb7fc6953d9a2559c97715008e885cf92eb320f5f0f816ea24f4067a01be806ba897e99f4efc0e4fdebb04cf9dffbd7d1bffcc1fbd74999e67ffdee80a61073107c6d38f1116dbbd3d4058e717901f254fdee3972666b801b1678fbcf35657620146b81630c1798a4ed0586ff0103ffe50623b017dee2cc87ba4d5aa8908a4f93e6f355e1bed98a0f6020f4f0e31c98aabe5b3597834c00ad0a10e052f025d48738a0fd9f1e8174e84d8e0ea976121a2d46d8ee822e00f654e65c1b67ab2cb8489b869ee2b80f98dc1d47d2caa08802ad049fbd7007220f225a546aa05abd1cfdd4b47106771a385fcd07aaf50e51085f0fcc91808c54b9f04062016e3ea3713eaaca3228b493b436befd8647726a53bb484dcf1b1b03cf75aaa5725b89a96861c5c6f03d972c39e1692faa4f2a70f00cdf29bd0f8afc7dc07cef7f46d7393004343761a6cbb5d4c0c000920234b6adaa43689be9b7be08631b6819b3ff95e2239629f569d5a8a0d63a204111954c1a6b1b5ff5cf3e11f6443e9c09f5d8799827a4f046e73ba3a389c7aacb8a9a0022dd547dd65dd3915e50432640d4914f8062e24aae004167cf927f675e80ab0afc5a0bf96f7a03d1a3e2a6ac932688d6a81bbe0e60b28105264c6c614dc2043a865203ea4bdf27b190ed85dbb5ebd16ef39ff9d84d5d388f1e08cf0e2ba868fca8aeab8afb3f6d561b702d39d2aea62f0ca5b7d26518908dc83300e29af1a554b98800c40e7773f9773e09138b1a37bf8df3df447219f7284c62b14bb15bfbf32d4dfe709cc3f8d1b4aa665d872b978006f2b9959c502a0a19d5c9095bb24609c55eced6af4b0ef753725cb06ba2796c4cc5fdefde4f0a1d8863c612148f811cd46e9716c910943223e0c2f860e8d11313e4fea18129e0553140672f149cd8e1b0449cda0706cd7d53aa46b894ba29507d2ea91d59c12d2384451890950d8814b93f4750e0d00b3828ed99e4348230bb7ca7d7dc7610bdd519b89939b207d6ef9d0a3b90c0210a1e768e2518a4171d25ec4bae23ed4cf423201dedb4a79945cb2f16a9b56d8b16bf32bbdf79d42d3e9d8f9ef7e742a91d406890e34267c532d34951567ffec2fdabd79c7627e52d04122441d3c48954d6cd6d460e22059e98aed1b84038d72c73300b48564844f3ec7515ed13b93a50c4a2ac1b9245ce754d25db94ebd36b6202b722223c045dc24dae00d1ca6d2cd30a98d3952d27945519d31552127332d5b8e187a9975c9d9e513f5c0d08889719bbf200e616f3fb8c15efc3b1c8853123c6a2a4e15fe0ee646eafcc7d312483e1077029374b3c1f404865e1c7e455c48bfdc1a8002b268ab16fd3297be05c19a12608feb9b2d613d54799543e0e697e1415facf1c18eb2dc0e60e2dc3a3312fdc3ed6dae375bd532793f3986ee8904d1dc5b8b12c1a498636ffdf8854efd07791298deecd21d71f13720f58a13620cb31da41592e40224070337301f7a035915c4c0f5353b03f086c41c202932cdc18d0bbe73bce7ad6c6281f0b885b1d202a36cc433d9fbcb8e8cba2de3174ea6adbedc6b2ff77b4eee8f913aafe2c609315bd5b6d7d00f91b053e577415bca05ce93efa9679a009e418a86d6611f10b4fba5cbbd820eea42b464148d79fc873fb3244ed335166262d8cfd8f5cedc873543b4300529c35e9c3950f1b32c281e87852989839b21e7580c57cfc6ccf3490761c32b831f97850d7226012a14f0a6931a6ffabdff8e2e9de5b05bcd84d013e037dc88d1740e8f7a52f9f464ce248eb3da9ec7b200e0442df92aa20cd071ebd5d825e91fc2132d168a2834a5abcfee500c8e185594b7f24b6de524dedf0ff4f5e35fda40cacc3849f68a198b1599097e19878a22d3e19d12d129d5aced427c8eaa9db502a367f74c3fdff949c330a7ae27e9e2970c508634da8a1316791a12a931c08d8313a6840f268c2e75b4c6d81ca6692f3ec3dd784ddea53330659eaa075fed6fd8b6168580938cb5f162b8502c5c68b00d2b024069641265cb02e2e176b40b071756c76efedd69b1f152ad3f99d4eadc5c8b1384418ef2c5acf5c17148089861725b145e4b1c707cfbb6733dcc93ef8dcc277d6e730dd1b3bf6912fa31cc9b876cf39f67c2853c03ce2af404a9730011804c724d60f4a29921565c0c7a50c5d98280f42a1f3a9cf501a2960b183602f3a657224c03f1831c6501396ee74630f9b327fcb782ce2cacb0fa4f74ea54c93440e31ea501a836e381ae2877f03c9b6cbab911cbc3e5a6a409d03ea62520f6f53cb4615cdb89977c40fa0c41fac30f87f57536b991b148ab5978f7c80705910d1c2d4abdb3b7ee14cce8f6043f3dc86cf60979f0fd2f48269405f1bc2586a022ae9d5abf6dec3f678c4bb1cce343a267032098a6ba6f9053948cb9799b0d2bf052574b1c401995954c13810d1ba899afcc0928e13b2e7256880dba3d21906ab312469bb44e4f4ce9f30622375c687377951b36681b3d706359ebf52b0ebeaae35614eedcbf19cbaa9b339ad43788dd31def415e456cba24bb9137afd07f907beb8fb760d321a4c9b8156e55ff8abd81992cc8350e803d9102b27c2d2ee31c443bad80ed05e409cd1783b9c813bb14568eae9f6d696c7ca30c8363fd8a639a8e2d36b83abcefc378777621d1d49267e441146573e065cf870efe1dba001698fe135a17dcd58d06a312ed03ab477d85afd134e9590adc96965c3abda91fab64d13b043d14e1491eed12f5edaf405d43cfb52bbb8c242919ee4b76177c55dbd2c29ae5dec778bd99f723a175fc28c6a5f95f6a66f9d651890176a4745c7146101afac940fbcc6999f111461153ab359caf4e083d4e1b8ac932d4fe6c807f950681a87eeb65394e03f86bd5ac195a0c5cc98ae71b416e4371b78cef8f5b25f1673b39eb1cd13bdd7b04847a95908173c54f480dd4de8ea70fd983d60764a9718c6650268528153e6d43e4e33330570414979911e5c86574660483a4f09de2eb87646354f704943d56dd1c598e00a74fed12a9949eebadb7a915b46bf40be5e6a1af00b8a6693a965ff3fc22d4a778311f42de5fe7739d2d18eab0a256a894fd3704d7e56c9a48edd8004c6d03946973c10965f14fa39d29d8f94ba61356c486f3b184aa1b06652b97128847d1ac732899b7f8a4de6f49088f40894d200eb8c66499b956600fb9bdd0aeafe6680eb99537d76be89e01ffff5546018f0eb85d4d10566e6b10da940e877442d2d6fecabf3c790896cfc821e2910235f3029d0f951cced15ed4f034e13db06bac69085438e4fb9ecc2a619946bd462a66a84bfc950fbbcdc6bb7ec03bbcd100387dba042b3f0d5e0be12cc21ffd972253d3a337a9ad019787a63971a66d47a6963dd361e1ca1aa1e9179105e9262a08cbdb9fdf3812696cb0be08afc13bde57688a27781c8d06dfddcd218dd8060d809c77d5b8edc2ddf29c81dfcbc9304eb0d22df8796540303232f900a48c3ac68783f2d2fc97541918b1a72629f3eb17eb035c5f94a5c86eb1e468b23c94e344f067ee83e4cf98fe570ac8b4a73b8c7665282db0ee9dc191bd75dd82913269faade8d646d1802698991bfd21367ac1a3e34e3b40e01d0fddbfd74e6c26b50741330cfffac215a4e180a75a1f71df3ae137d20f8b508512db6e31429cfc46ed9390126c1e5d0c9f45b194221284e0306691a03124a625546c10759f01c7fe2c21a8a901d8b8d63192fc440c714b3dfcf809bbd9ea10ac64f3a4bb82d655b6d87942c63f47ab1838e607100c5e97b19aead2d705a9e12299a84238518a0c58585e94233f4ec00fe7be027a899f67edc633b8e9d2d08c335212aed5e6ce8c636af6f7404ce3d7876173b5fc88228b0ac1977639624b9005694284551eaa7bddbe3c7f28e6ae7b95ccd4cca36da2be974c3bb430accfbbad0fd6136de14b390494152e523a689861098bcc326c4873def0e0b0910c5cf0641910cccf4421318f1b60a2de169a622f5abe1df6533fe0cdd118da80c68bd412c624e5fd0104b3b9cd8d69a6a096a64dedff94554f5b078b5e3f5286907f0918618b1ddedcd874deab8125d012b0be9efbd8b5c95f78a5ba1bd86dc733aa708685ed6c49bbb65f02366f4cfb0d31c2bc8cf9107163586c376be1635e86a691cbc46f78450dfb898dd418fbf10d8425a3cecfd22cb6c3d9a1e466f2036d88cfb17943cd205ed514a8b0be831403d2a8a2bdf4d439f0ec6a365259cc8d557d099aa83b7577e33f7b1cb68af3b3765b50ef1b1dc7860970be9b1e98f118b749d8d71690a88ed77c88f5aa70e1e76d44433d71e4cd46e9bf67f3d37d65fa8326109b1b130bb12451af9b7afa4cc3e5df7da16d05644e4a2bb4753b037d0c5e2ac00ab937a4d31b36312645d6753b3f6a5eb58f4a0765fbec04368b033517491997a3da3da37faa168a45bb995336b7774dc8aed81a69a646a2e08a3cf67de7494eb5387bb89074b833eca7b902caa2bc1015567b9301b52175703ac71632c511ccffce2c8070a08c33b66f2c9e949e13240813f735d88077e8676b078d6c75c07fc204977023d0b657fc00b3e31b01a53d7eb711dbc28700abff02b88dc00d81d60d3c11c545aa188466301f881b0937792c8b768805cd4208cd73736ada525fc8c782af35c4cfd224143aa62e46be898f411f6c668426e8c33a68b073125e44a4419f3245fc1504d2da3a4cbbff70fc74c46c94ba9a1a76c4c3879fb69e84d3813ee7e9fc81e9df6286f85720608a894afcc912fa763373353cf2617eb40186e92987a22a5fd3710b0769018a3f106b1318518c1c0ddedadc63cfd9b074dbfb534173cdc53fdbc60010f5c9aa1aac82f40f983d97e53f9ebe7032037643f0b9db9eccc250cedc93507bc95018cb6e77465434b599e57963197091f8195205fec4f167ce1b03a0e883dd002152d0941a6e28d271db486718655d7d2b1308f1a765cd8dec57b7deb13c0437ec6fde2b57ae38f14fffddb11bd0419c2583baeaad3aac00afba6033c67cb3922699ff036986bfad45238c6b05fd2acde7a86ff49648187395b7ebf6dcee53b1f71b81f768eb2b2840236644da9eeb7ef210eaaad08481d8ae5d3897e6505e291a684726c6936909a03f48163984303ec0d5f8db6b93ad20cb95f7f071df6020cbd08edc38049c787d7311362cd5a4108a5bd5a62416b581d1193bd51a2ffd472c5101d89a3367360a8dc32d80975c07e77875c4136c204f2434e1419d9a4b894193a01c2d5a1dfa239d69272f0b925cc606a082cabee18f40278ebde45b6cf1970e6c380ea9e19c089c066b23b1a6e5a5fa330823e0aad7720c793cb468512b334c53a39bd62320ed505fbcba97c6b760c80480000820cd66de59fd510bfb1960d3c7ea2b1b54bdac4227303457957245d25509512c4e93739ec2afb53dbaa73853ccb117a672bdc149a85adbee9fc168b9d40d35074708bc5c46b66047833e6345bed87786c79c160e0c1c4574aecccd09f55e7c284b4fea038a2cb54d339e6663ff69cec6c81932fab2ae4f090997bd482c56a97c47a50063651a58b7a91123657298aa8c94fa840b7d3b3a9b0869c7f94200aaef806395c21b2c3f566fd8108db8f6049934d13120a0313512a8fe54cda45e3b1b0155ab939dc0ca90110770e3076d75b6958f0d8c89c9a9bfec020dac11e46cbca59a10a16d2fdef55ad60f83d59656e64c9a27bcf09c664d59fd4d0afcd00cc7e648c7431b9f17c81752a0573f8cedc2a75d0e18fa11582ebd949dd7c740c4d829f12095f307c082918654d7d6c14030f44c323a0a4f9a6cdf86ed908a475f7afc0634dc44c44e284c9548d903ac2dacf762a363f27c5eee6a6091897325c6070ecb54bcd61d1b003ebafe19d6f0822aad3363c4e9e8c89b6fc8e103b07b9b96b49dae3b071e932c3a2d50d30905c6391dc70bf1d8c8c72b3a9dcceaff228f113ab9d9b32cb263ede28c45ea9946f1bf390a0c43b29841fd46c7de1a18453be4a26865652faa42761deff2a2146589506928b56da4cde2cab07a203b8557606431438eca2de8a82fbd0dc7d4431c7ea94d28c05a0f1b704acca08bfd454d80127a03c46b60f8f3e82c28abec20e5b6a8aafda09fb02bd29335d8d5f4c10595dbe0b39199c75cf07fcc0053461ccb96670768af79a356560e9d9e6faf8bde9f3dc0059ac5317337f01c1d348490882408e8457b45665e5843f0013755c3faf689318d49872c77fff511fc1b449b565f9b20bc871ca0d475cce1fd7fd80a86ece074c5cc815556c5766ac8922cf81ea414ec7bbbb2ef1244a9b966ce8bd7518111bdcfeb49a780351efefe6be758fa8d2c458802f1b31b471a0bebfa8157c2d0c0eef8cf38e0fad744ca3af32122f95b6c4c12e9aff3ac388b65bbadf75dc15c8a6c9baf16d58bc3a0f78e4a983a78999181f06fdaeeeec2c3c780ff77e4b7622143109f59e3b5ad08d4ea1335c11ced461aa86985f183400b4d1e63ca800d058f0f6134286a72ceca0f6f2728710fe6619afbb23a58b6c4b0ae238de05d828ad92e212cb7ff13b48891035a72b67f201c572299ea77e31a213ae305639b6cd3eb43c8cf9bd0a7545283c7be8601f1d89f52436ae3a5c41a312e3bfcc1d80d864cd6edf9219ce7945d2921226d5f6249a60ab33438ebc282276424593cdc632bd0e44858c5469a80a7345103ebf7442aa7465f6d0eb0de58c73da48f634ecbcb35e53bbaf7210e7880089b7cb43ebe51f11c3953dc991dad8e51cde111509452d5a6ce1107560489c00122a9cbf58b6005e385b06966acfdf94a0880d4cb20dc513bf0466d38be6ee6f04b27ac26be728608d2da3fe657497c27a4754bc75b537e3720c22ac16448f888c60cc82b108890dcc39e7f64fa101f26a1c526d9e99ac8f59f44fe111fe0b619b693bec9de4255175374ac438448c33677ac55c58c1e3f2a20d2f1e61aaaba98e2e33522443aa6b963b52a66e4f8d5039106ec371b75ba22ff55030ac907b90455930891e6b86bbefc4ccb678a85684014e615508125c236371ac462c4d302bd1a0d2d05a23f4892a38ab63cdcd569f0ddaa031198c6039908414265bec58105bb1586c04b2642bfb0c8b5daec6d707ed782bd3e28f6abada80f73c6a698f1dfa155af140ebffce40bb67b4e5c4d494ab2414c0c792b71757274020cd5fee1fea5a888e92d184f85f039672661a878e3c2a727f72f57a3248fe718c5ff0c01cb65a659e21f060d96a1bafc4865e5cf81af6f2cf3f08982999f0cb9de55b4b3e6f5049b8b85a9da501517ef92ba97cc67e0608514ec5b88946a17454b7298cdce4c3716e616ed3004ba06e539f8819881ef8c9bdcb6666b3549d8e561b3bd10a154a85cbd99d234c107acfe7971ae72ab052bab4bd5cabf5255e662bc0c501740ad431a6eaa6e62984dd978535d766eea8a9cfbf80695992e1d05b38084583104c1280085c0bc4ba286fec61b60ed2b2c5ad276b5731438b2546a7ce3552ca3e5e935c054764cdc46d1824e529407179c71b8d164e78e00660b20ff56e8be331c9370ab9b933f32bcba588314a8006086d9587db7a6bcd3f412e30968723b51d28b816ac0db93d9a23641d715120193274a9a9ba7672d948941a3d9619c44716b426ad3df25d37332c9dc6d2f83902e0390d87463f821a4e69f3158d8741149f204333e18afd55765fcddee8dd07cca0d080ab786c6827c195dc7ef22ea6e97a71c8be03a9280f86dbad1569fe9a68862bc004612058cf04c77fd00a25bf7a4addcdfb30a536c30f30fa44e1c5bf6bb1b2f66ccd5f8aa98888237d3b42c0d29ce3d005f0d914ad084333d3baf9754df851f59c79d58ac0f757be6fc9c18bbc290737e887e7a5271fd4ffebed2f0be7f1876b43fb6bae3aca3a395d5900a334234c209bb2e0abe53fb08b50fa792c9fe12ab2f405312be4f81737bf8216b1c9c25e82c3312775fcc1690055a0a63d77dc514eb9cee5685863d020b7a1097475d6be7254ae258be7dbb5ccc8b4ee8a6a94e0259c32dd765bb6a6b40b98d6481b8faaeb96992fd948150c7fdcb4537447f5658677053f564b416bd6fe5670e81d8f154aa682bfc744105eff8c19d02550015d3bb6e042fbb03dbab781684401e214f74dbd90b54a01fb581ff6c49e1c0791a077e13b50157ba655d2d6f07b80ce3fa172dae9f9a7f7afa7f8c098fce93b693a12bd6fa3da45b8f617d0bfb7bff8b1f8ff8f3b300dbfd6fccbdfcb928f5c8fe512242d7b96a8421aae4003727b500998d8e454b3787138fa864c5b6b46f1a209de9c3f02af4f45521f8359111f157ba59be8fa25b83b47839f84c37d112caddf0f5fdfaab531ca97a325aab1eb7e22bae5fb79aeba7eddd507fcc7ff83c7f8da1e7038b95a29e26b64dec95f07d45b61a0baae9f04d6f02b15647ef3692f2d2f48c98bd376ecbdaa06eb64a3c00af251c28dbee8c26226b087ecf06824a0cd9f73c8cb91efa9eaa0b6144167644ded947b0a7446907be0c909add06b0fe049bb2a4424b35eadc591683636f0394e1e51d1e9e8653c15e10bc83dff12bb48409fb92a8a1af5985a938b224009d8f8416b3e9af838e98e3de49146a588007f94d3b94a7eabe88cb5beca323c056429fbde4b0c34bcd6e6f82d0e9f1aab02faed1d6e3ec23b356018162f66a09a75281af460c29728535e84b7f8e390afbc6ba9e5852b29c04e37efd03a516e6745908b930bdd5ef4daed39244c2704abe8556fc02c5904cb6178252b625039810f53c877ef87fdfd8f252afbcfd034d1c1c58622e4bc212d681b51d08db9a94a035da3889880f78555a73de07784380b2f1b243b1bf8f9337dbed3c8b715926a6dd38a053b5c69f6bfa309f515e6aedffe191a514997758be5b8c12cba1eff8b75f69087a42e1711ef078114c0a8ed9a8d5f2e4e2ec1edc457d724281f3fd58d98b3e901f8ff88d9e79e2a4ad3587ffce60d48685f7a171360a72dc45d79a2beb41496b15ea85ed41c68f0783fd515be44bd3103ace6e54f7eb0738cab3031df84c8c7a80e29bed08079ce086aa9709b62f8b211e7d7554c480abb19b5fd3531652a665102a474837e8a4d2c0fb9819b412086166db4c2ca5754a1a78e1a03053dc95714f79d4d226f407390dd53252c2fede0c6abf44d9a0ed5526962652bf3f2451274c92674229c19932dfa71c7b369eb0548e9ccd54d9288dd20e12e59faf84bde276f99b49d866a200551038c60d94a2b13ed104654ede6062e8493914dec00e350ec9e0b42833a68faf2ba142ea2612dec00fc62e5f4369197461c9ed67e2105ed31f94a1783fbb77c85d498832ff42720a43d69938086fbe0f0839e6c7eaaf88b9db1a9512a0976fe216624a74a978201d6d2feb74ec8810abd413646267f7d4fb09b39dc0c1e1c449230adf4af95bbb06df8613b3c93f385f9e1050c69dac6317b7beffbfa27ec701ca498e6f771f0449022acbf40328283e1b82e04d8185e7ebabde41f2058a7fb2d51965489405a21b9c1be0e79ce7f8b7790c7a466ff8772272b0abf3cd3ffa26120bae56ec0bc3724a932b52f29f04c84f6d498c6cd398150dc34e9e35cdad0a76960039f009982cdb4573b1263e0ac213e006030a22ec0952aec6a39ae6919f952f83dc416c0440f3aac0e41008c79d6031ba0e93bd2ade7edb7ecaaa7e051625d41f3363e9b6cfedc11cbb1b4319e64e82b970c75a1008db60cb8bb45000f64130041e96407fe30bb96853bc5a936fd3961a45d1b6731074ac32cb4788d572f860cd7725c8972418286564ab180bea1a00668c71168f57c4ac1abd7659587b25977041a7bff8071464e21007a5c08c54bc9d30eb41830902cc2f19c9ba5dcbe2589adfd2377289a3494b9e63c0a48cce3891665daf16cd77c8d721bd3924bf59bf64dde264cac94d35bc2083eb60fcb15a0a28cf91a584bdc3043ddf3041c5457d3beccd3be99947baf1ca1d03c6106405cf4d08c68ec79223202b95468781c1732c3431590086ee69b844fc690edd4d26390942a527e34b6010ce1f4edca1949f1ca605a67180394d5dc98b7f006860fdd81078ef586b1011604a2ffa20525374b9391f5b9ceec44a4bc8188aa6f0771d7c47032a8ae2815920d2324e07ae1bb517385f946d1f81df40133407b665049b347fc5178c491eec9d8374f88277766276dfcdb9f8e9bb110a11e230102fa2f89b8e723b995efa8190e1daacc12108ee5bfe957286691482f66eeb4da49432a514fb0711080f08eda2fea35da8a77e8342bba453d7591c7e4a5da35ef541a54ebffa5a986c170e29b0d06094c1217cb55a55ab1e1a354d93a9a749049a403f745d9992e40cdc6432991ef04529b236c88ca166320d1541f1a607b0011459fb7325c64f55cddfa1308230ad214d4e27c5228c15cc28517bfc0e2191910592110c69b625cc0beaccefd00e92bcfc1ddac2c687de8a51b6762d0a2f6728690d46dfe2473364916c2b00d69d04a443a1d9d9b65b814a13357d343beb279fc0fae993546a9faa59fcda0e2faa77bf57ccb8c1872dce3553c720e95b13eed14e74f91da18152236b7d61abb891b5d217169d6b7ac1c8df4d83eb377b94032d6798dc24cf602829cfe9222121219a18076140c57ca4507cf10dcc2e5988a7481f16f2915fc8322939d949393b0e65f2f6e89426a7d4644a7ddc44b338e52d4c68aa2ae731608bfb56d13b5f18e7e1ca0704d29d972324b2643b3a33223cec498c4a82c2ca6fd1ef10143d4ad4690fbcfc9ef13bd4031b1c4bb552e547afe28b8180ec8b650c145f4522507cb10681f8fcc319e17143fc8054a75a65f1c541b023f1ec7189671917b11110cf7a68ab153d9d346d8b31517a4dc56ca89389524ab90a3b47a901925d90b8b3397793b37d606c71334a07c6c35180f8681b02cd904582991c8a6988c935d73e249a9bbe8531a047f6b1db31b9b6327db19b80e60b3375b78f6ec59bc88a1dc1c82e407d3a095f582183d1a8c00e856627950a13264c1898e943e233fc763bf4a3d160f5a3d9998b04ebd13bd4e77784064a8b7e0e4656f7f47422abe3e742bb918cb29fbef1d19c4a693c21a414a4b9c64a4a3f4ab128907ea5f81d8a62889705cd668065968493df7270ec755769d9d1d64a428d4633b1e0f49a22a6f0177692e3d05ad6deb29ec2445b79a176b514bb5186025b9c34b8ff75d1cf5e2143e9c34e52cdd49a22aa7fd8493d6656ab9fad4d991e85c70d0de42588af91712d0df6518325085175b0af06da9eb2383798ed829f1e723fc4be7a8a113fbd26490ddb68a36baba5180bb9c89a2e25a51c77ce28de987af48edb5037ba20d2b98300759366f22af5ed98f25183d353ac794af34d6a50fb2d06c5281da7fc0c9a517efac6296de4a3034b18a3166089d4ef1535c6f8c1b55a211ffdf4255e8a1b90369ab335adf694130a393c5419b4a7699fe13f6ca39e48ed8597226bbaa605958044dd7829be7a8b654dffe2b9fcf446e3a76f3a38ea315283d36953cadd4a318bc2e7270b0d45f183521ada810f947b5b71d4db9ae3a5f85a58ece7fc69a3b5991e838c627eaf7459e2c3fa2ca0ba20fd0939753aa8ef08c3b6a0069f10404b95daf427314a0c929f0b732a45d6f412c4a893c6e44ea3c3301a2245226bfa0cb09cdee123c307032bc517ea8b2d128c66088ac6088c631f0d946d61532ed1661744fbd8c7e7a76f1eff44d67494c74091357d87cf94df13c9410d4e0e3ae2a47619b5ab7d3a6b31791ca541290d4e5fc9aa7fd846517efe5e4143083f3d0a3538dd871ab2901635cda49962151f94e4f4a2c892453f4f260f694ea7fee9adc5c94fefa3e8e3b149bf72fc3452bbb60aa5253f7dca4f0fdbcbcfa59fb33366303ba12a948cf8302ef9d9493ffda4997a4abbc218f4d3a7c7a076ed1091949f1e9fb46bb9fcf47ea25d51cbcfef54a03a14f1f463194ff1f88906a77f2ca853a2cc03c3be955043dd82cc9805c5885ce0e44f7e8a3f284e9327d946dd009a211c121a2831ceb0230c4339e70bbba274c53717e3a7c578286fe5536bfaf30da9414e6ab041f61284a80d665f6cc5f6d2e2f0b3f71aeb6223c6b2af5e5ad2f2ec354918a95d26676ea3f8e22f96c5cee599d178f63594be8df848e9287e6127f938511a513126c62f4cc5a09ca97792d414e3c9679f7c9e5a4bb3d837e6da88070d6d147f7cad6fa3f8e23c7e212b01b9b979d6111259393b7c64acb4c3473a0db2b3d219332bd29059e1c597df2207051561a61829a5d3a3a79add04226cfb0010450ddb28063724197acddba85d27676f2dd1fb18e9f7826abed02c9ae8f2e357248ceaf4f74a196a7ce469d0490dd7680212c63b66d58780c387bbc401220df251fc39b5ca0654b01cfd16e1970a16629c2133e3e88ca0df347e878abce021bb05463364ce8f262e4c763bd3e9778406cacabb092c4c0149eac21609b6301a28d417b62ae37df40782ade9dd4456cb0c25be51d8fd72643a421a64dfe153fdc33d52eaf9fec2557221dc231ece4b65e758a4ec4afd04cb47ef28edea3e6ae9178fa0e82da55d3b44c54acb3ec69f2f3eeca28fb12476884a113e6c2c610b7de481d187fdc4476f1939de134aa03dbbda8805256b1bd0c3d7c186b23d3ec96559d2e5ee490846420c6a2897a4cf2519fe52de58da555f7a0bf5146f59eca2c5e197deb376edd0d00f5ece00939a94dc412d35d952b2c719c43b78ca8e70700ed6c1377886554c6347fa4583222fa538e9d948bb68bc93b216af5888326fce414664473416a5f308ebead3f1852be939beb04ac7318f545fa8cd7c618d2115fae8724916656a294aef38e93de40c921ea5a3e229464d3a8d2bce69c927ec0afc1408c34ba742b36c47c778d13ebfa5da0b0044fbac22273d8d93e24bca3a56145ff2a8270be160a0993935eef9769ef89ab336d22e1e3ee3b6955e5389c6bbf7cb47e7e119392a8ac5a018fd285c19551d5f8e2f5ce1f8c2aa8acd7ca106543f68f55e510d39a5679f3323a599ac8867e18ac6eba02865d157d5953ec68ec99e7d3e7a4d633cfa048686522a976a951e64d023ebaaaa6aa5438a9c2043898c1e72e0c345193ea83298fc506b55d55fa2151861e15bfca048660b178c10f12647487c2d6c66fa6068d08c4abf560744951e0a0db6695685163e55402105d58286ede7a36f13169e7e71345f2827cf69d9ddecd26432994c26d3f43297941a4401900e2bfcc24c7a197d5b3295e6520b138602c287274deb52e8ef30df2454a98cda3ca751dec6dac5d1376f4697b0ed5490a78f867d61aa6645d73e1a76edf9ab3b54fa69b1f3a1ce9f067bfba1ad45f9a1872f5874fc122531828732ba1cfda8b5728d3c5932c7ef86add47067617d1e17c0f0123d9a7e8968a841fdae4035d4fea88c280db0445d7ddd0eb50357981851c105131cbf44350c612b420f3a442b607aac7451e35bfa704dab9ab6ac76ed0b4d9e364211883cbb16351666885fe8cf1f68a5defc68ef0e7fec501b3b7cb86a52e50f926509fa25cddab4ef58139acab8420c13264c988fdf8e05db67a7825c21c6f8c5109f7ef3a3cf9fd1d9d31aec72a8ecdd458df5823ea2ebec74df68252ce176a9f5bb9b7baccc7284a0d0ae28c632370760c3c973bac6c552851a7bfaa9802c0efd20c07ffa6aec4ddf8fa55a63bf4f3d3ac73ea7270b61939a2c214bbdc9892fead223abe553a99b3c5c2dce0276ec0bc78a960f5843ddcdda485583d24df446264da93740728ac8d0af95100a6c7c5961313ada2e4555d5a3a6aaa6a4b249df56e392e8dd679e796e8f86bffaace3d95b3d773b37f77ce3993d9a49335df514f53c9ddb2e66676da457606da4b7d73d4fef07973a95e2ab15595bac2b671a2dce517c9d5c8673c9f58005a58753cb4bcdc399f452ba84f403d6b5c282f2a4e90859419eb4d64a0042bde1892ca9d3daa2f2f76b5e17a785b5912e5d665f13609674108c971e7a2fc3fdc14b0f77e8ac8d741298a8dccee60fef8c499f33c9ec9366cef9d277a4f3b40b072fe9178f1f179efc76991d6a2b95ecf1b2690cc5c396002a68dcb871d7b7188f81e24f0e2726d3899e28cd31445d9fce42dd3fdc84813ce4273f43d5a3b849b3a6871c35f93e7f3e757ae43c6eb20d6edfcf8fea43fee956b061f5546784f98db91e7e26e8b7c85129c3e7974a972b9e3d1afac510db883d7513def59be4d8ab45e858e237ca4b634c0cf14fbe92a2e8b7c971ecd9239111b2e74f86fe18524f02ed4fbe518ebd1b4cfc66e2d8e37af09bc6b177c38aa731f95251daf226678fc6e4aad77c4371eca13e7a4b458908bf6d5cf44cce9ef6834b1d81fce95428be60a041ac8b63148806d1295c037542a3fc848163ed621fcee1d5dfc63f413e7d03e7b0e4d9e78c12e3fdd06ffaac0d7f355abb4e58ccb67cc87d8de92e860a1a34bcc983d241a0fbfe9a78dd7317847f1a9cdebaa1ee771ee3ec1fe33a2dec6c673bf3d15a1ce6616da64f3fc0be9809b3a6cf70c787fcb37ac1cfd64f16e2a787a70f5bfc43021315e49ff91359d43bcf07508dad0df5295b1c1c3f9dfed0e9b336d473fa67fe746ed2ae1d62234abb70fc7496b5cb4abf7afc0c7d41fab933294271680c363ee4299a5212d0875ce567c841b31ad0c74ebb6292969f637cb8483fa9c71da9ac3a31c2cf734af61b73eba9a29415a3674f2dd59e7ee998a5b0b46b87b84c79fe30555453b376d5e7a467a1212e491fa6949e838290c387a92fcf736fda158ee0f3ec2bc6b383ad1ebca9277e53523a15e54bc95e8baf007869163ba79af8d4133fbf5491fc02a0d4a00967d4f53055f42c01b0c1f511aa241d4de9e18a0d003ee8ee6eea39624b2f3d47acb2b66bfa783f3a7d7e492f7b9b37ae119ba9354e3ba16eaccd9cf9090294875ad68d5e16ea670928a5bc3b3da7e5f46dc648294571ab7669ced3773bcaa98a81a547b934ae68a494720c51bef6c9152a88ea136314001895bde7943e130537efc6daaf93afaf64d6e646083e9e962523828f2c797a69828f53ce2394d229e56ef45dd39ad6b4bbfb710d4aa72af7699f2524283197b893b5dda76ba2d428a38c174d82da0acc775d03c6572b168bd500636f85373860195e2c447893ca08d7cbef9767ee619f2d53bcc94475087aea93fba97a39bf98e227183bfc0463f6d39dc91738ecbe0ca004d38a3e54fd091f5d3be3a8061f7d81d0c447efddd722c1ba7907dbde545003659545bcb367203c796915946be46489357c0802119ec0208c97b27b29a5943dac50f161cd950f7d843f8070f1850fb4c8404b144fddbbe8e1a9835d1c3df596173378ea375e2c3df500c8bc04910200ce142f5de302cacb1f6879e93dba20b25640280856a6502386c4114868704129a534a71f60b1051b2f9d4755ba42db51e5c31e3e3eac711941f1d4575be4f0d47d8b2a8c7e9efaaa0b42c11960b04312432c99014689d0162f3b4829a5d4c1a97a64f9b0468ba7aee9f0d46b16264f7d9505e9a9bb1638c8c2064f3d078880289c70620635c8e2450e60128c20c860464a297140b15750d7b010f1d42b16242cb678eaaa2e08ddad428c31c298d2e58a1b80895f0c01071d4aa2b8e20a0d0b262f7da60b222b481bf01428073a50234b1757102107183d22ead14186a7df58e9323fb158ec860674f1819352ca2a554f7dc31e4fe9873f3e04f274ab8c508518b32733242b6eb0a2ca154a9efa5611c5534f15a93146aa0a255e4a8f91415e745922e6a9dfa04029a574eb6ed70591b30aa0498217394043c98b95a39e0804329456fb94524aa76f6b7445e3a0582c868316bd7829fd06051d29a5d4eaa90b329faa6a9efaf8d1830f81845b85e8c3b5f2b4084f5db6cb004f5dab519efa8aba33f1d4c129bc3cf5160d9efa8d15223cf59c279eba9076ed1015609ebad605a13b53ead94c61bc749a84b5502a639b21f70d78e91a151fd4f0d265f59bf85a201031eba189227cd97283d8c51092361f0438aa2108b6925ebee410c8d3a2a7be1af54abd15d3f3c09ae00388dabf73a29cf3586473ce91a0bc73249b732e3ddca4c91dfbf4783c179a1539df1c49e72847c2f9d639ca8770bea1bcf32128ef3e6e73ae8b007b39d4e9d4c335e27161714e1e1d03eb62c082d119c8da44df50a6afd51f78030408c56c8c94925c9ceed74d5812b238351f9d059d1d02f8a09a7c6bce0045b57fb737e650ce5d10289c73f75b8842a15028946f1724a7230b424eaea1b62dba109d766d93066348a8a2b687cc71634cc7749ed331d3883a4a8804368e3a4ac8e9033d4632ea94b31a6e9190188b620a3544139a5fa21e29c07819e19748499526cc84c9951db4d44085ab616527050b4a426469a3870a304813cc92102bfb2d4da2736cf976d47882294292d8c5971aae08716444c31195ab5aa8fd5119b277bb77bbb77bbb9db9bbbb5bc951d2168443195fc0c880b38163c79ef5a045e968e7070f8fce8ca7d65a797476663a3b3c3a3b3c370db2b71a64d6e1d969970bfc5a1ba0f8d0ebc686dcc152116a1c39f970e5a4872c86da0863c41361a010220b16a2243e59200d81a1011320303fa06109498911db972caa0c855182490db498f925ea2182c915552c99bf443d3e4149315f7c51228a6d1182131e6aa3890f5731499dfd7005155d946c21424e01c66c8a2dc89892b74fbf443474f15b98a94311ac84012344962628986428b025727348693b752a842953ca4ebf707a4296db83ac6c8ecccc28b48b59fe6817110d3c7cb8622299d8b6464ae93cf1c5f513e95c4a29a59452cafef0e606885cd2a094dbe4780821633af1454369e847d302e7313ea4f3d487248524899d94778e24464a27125f33eeabbd599ceec66a1539c6935a2a3fe75dcf62e0df5c07b57d1ceb3c4eba942ee5b7234b9ddfb7415a532f663e8e8e889c1ae5454b91c8919050bbc25d8ab23848aceba641230b3b61a5c8889400846a24fa682d2eeac951ce421a0bc5578e905094b53172c2baa430129b630292b5c0a519d5210b27381c51654e188807557393170132dd008aaf1b5f2bb2a2d66ab9a7c33ad8d76e0b3676170cb438257c7476b238719545a5a207ab1a7ce424baf8bae1f186e3702433ae7224371c874f9fcd747416a73d7a0bfbe2202a032151f98c23c1e1377c7afb8eca677c0787dff0ed68fa6b41e5333e44f5ddf08dac2138be1b331f658244c3e637edda3c02f1d1c3129e5d00d16f78a8cdb8cac3150e67af591ce9ec383c06f236b266bc8dac8d0175f3de7c7b01dc505e8b4be5df3c6c6dfea3c1a8d3eecd2e05d3f708bfb9c75504da52cede07da53be3587a9be2970ce32be1d7b0a31ce5fcddac8f80c3442f6d953d8e7aff350becc17be007efdc27694cff039bd796f1ee3c5c0618ab48bfbd65f58b238d2638f97d68f7eb113066a31508b815adf8a2f09cb294245dfe1a56a1fd81d5125b8365d65a98ed1a2584a69de30e4e0528dc0c0ff4a79e7610f0f6b3ebcf9ed26e5edcdd27c7a95f56d6f6fdff617aa2438842a1b9ca8f837f1a55ad6f4e93b9ca8eb6c5a47799b3c44a1d651a8da2e546b5a45edeb665927af5c83bdee27cd7b3f233068dbe5bbb7cb0b444a7cf89b226abbd4b8d8a94d58a896968c70f746d626fa669364c926499d1eee929156177573cefb4798eaf373e2cb51d4b9d307c3da448fd1f4c97c55653f10c128729431c618390412026922253a3c57351d6aa8fd9113e69b9b1b1e42d49097382fe1e118d3b0ae4a24be5691151de5330b46bf591b9b2435be4e7b78b39ad4a47d1c9b8934ecd26a47962a635744954ab2e8218a016104162fb1258c90f9f9d8e22fbc94034e9a50529e1423ab466b7d6b6db0b0d05a1ccda31f605fcca5557dc0a0f287ad6f99b0549b07345669714c1fbd531e7a9fb438de474f79bbac5323f1b18bf8d8416c1e360d6b08a93e032cd25c20e5d577625cc6d965be2349f0b793f2fa1d497d7506182f8af70b65984f1df46d90c6ee0bb5ed0beb6a89cfda44cf69d6c223881a72d2c7460d46ef5c50f98785e28b85ee32432ad2220bc11fd63e4e5a587f42369347a9c72f9ce4949778c42a1351d9a3cccfd69b0f22b3f4a8d5ba5af92fa1a89063294aebaaba66a2a813cb2879501a6aa30b27ddb7b2a8d1898b61333c6d99d4e6c33fb2aebed03f828ffac2cfa7c125339e91c8ead8fc9cc86a6fa3c64feb86a8ec1dc5b892a5892b587c214a92044cecdb9b73f6e4e738aa9ba3bcd560cbdf6e3fd084a5aa81ed71574dc0b713591cfe9e59038defe5f2ed0c14bdea71deb6de0178a8db2d2faaea439204fbcc872487e3f06db0a369e186cbf8ce8d6fa3ccb793e3d3725ae52d6cc65b18c8a46e8326ce0b6f9edb422d04ffc60c0e6fbd5d56e733deee0dafdb640b0b5bcec106bbd5ae9039865b7fc3d95703bdd615753d04a9cb783cf1b5a7ae617d235fe7af15390984f55bdf6db52bc69b3fa6f3f5c2193e8cf1d44dfd42235f9dbd30ca9e390a1f013dcf9e7d9e7d7362f56230f2d543157c2a06d3d72fdc94e734c738fb16e3b53c308d9af2ee039daf7fa073ceb78b40e79c0745c63b19f7d12f196f07653c179ad57df3f05052b7cfbf55835d10d5e36a833596ea0d072c331f9aa6692d50080b3e1446cbc723c6d8b6664630084fbb46c09c83b589ce375813a24777a15ffc44b3a2f314238d27b26430410795faa4503618e26bfb6ee28d520addf3ac4d741f4018f12c4ef7a72e85eef9e3296b13bde5454592c40eca4f8e44f3cd91a0fce4d265ef80dfa132a23c77ec5bab8b8a24899d93a31cc9e69a233939ca650b9b6b3ee4e4289a1634df7c88e6db7724899d8d3504e5a7ef080058b045085162b0ed5b45d611454962b08525c14222abca0bbeb1977393029006a3f30a235451ca71993c3a907ef550a9c29b0f4fd4706542725a3744bbbbcc656b83be9232caa8ead1aee8926fa8eccb4d98a3047110476957d086fcf3f3ec424f64354051c34cc49bf5ec3a74a84588c4f080a52c7b1b757d03914ea73c2498c14ce70eec6550a972777757daa089adb97671fd238718f5a6156343abbb5b56832b1b3d6eceee6e8cdd2bb041ca78747472d6137283fed9767458588ecc8c024bced9a29431c6d821f79ab74b2f279e342981683f5a6094abcaa60f985c36689ab1638c4647d835df2e0254869603b80177c39430ba8a96bace521aeca674b9a8358db2cfb2da69518332ae227396fcb2d94a0d5936a5a85d56dad5cccccca1369b425baa98f0840d5b92383b18dbbd41b0bba6c1c8f9681758bd5514757d7182b0edeeeeeeeeeeeeeeeeee7677735134dab62646891af678f6ae02801fd42efa5ad6a0137559f6ecb314f8dc5d972ba59431b089ba6957fa7a5a8f1eed9a6ef2612e11c020c5f892b2582cf604b6becccc31f2501b43fdc3b6350dae0d8f8e0b66558e7a543a74505795631d293640f1ae09aa52e0c0be52397faa06bb6a26a75fb8dfaaca181afc87e6400e306a112248ec113759c9bd76c5856dab4495a886f307020178d9af57a2da523a33730fef05f039257bf49c3c670ccd0ae0b3f78716784ec52d32cfc9cc2c5f88421bbb147a3cb7bc61db9a982715f5a409d414a106fbe3a2862821d41494107ba820541421d445013d3b8a898982b6bb1be5eeeefe18604b77445ddf2844134aa670376ce9196a430996eb6adfad356ada4af0476cf1f0304ea9034c8d344ad4e81c75a9f96a9a474d7a74d30b5c8c73a3976d6bbcc15eb92683945a556d8f5d2937a60555484e1a753d5c764dab75b5720f35ed679465a7c096260dee3b7b65fe56aae9a66fb575a52d55ae450359bb7dbb18824487007f478f9350c0560c47bee312d8466d99610cdb2e8d39a787375f77a8d3432d32a1c49a56eb2e98b3365f54168a14217254a4d65a8b10e1c011110e1489443850a475841cadd177b8472fb42bec1de7aaa64485a493e3d7cd4dd6e8e9b238e9c18b13a2580d49b6343104c68c2446bea34b8d5fed90a8ec32a4e1a447071770ed6aae5dfddbaf9e932b7118cad77755ed5a5f2d57f9358fb5a10d055e3ac7983e706d22cb0235ab80e827cf5701d129f835efdf5f4bc9b151bba34fa98294809447ba3df637828eb304fdcd1d4d5466d9b6a67fdd6b166705fab33dcde35d1bcd9935fa8d8046e73521763853108105a3cbeea88546b4a8d576cda83820ab9a1924454a4b699774a17e492dcd9a8e34a58bcc4b91fc32eb315af27367939f2d64240021eaf4b085b40539862351e8a7d3c4c853da35d35dfa15f3f3049616ea26b4fcdc643238e3c346fac95306523ecae619b482c98349cd2106453e6186f881dba8126377778c313633470370a9a1169be2439735c62c26ff68d56788c15a1a6f268eb18fa6695a4f748ecd22447a7a89121de289301fae92fcb024090e92b010b4d05046121bc4d840c592990f4dd3344e72861041f01024a5062321e634d139a3d6b19db08154030bc688d1243114c60922a6f4d5aab72356416fa332b70abc2cc1648c2c3c309102e628c993a13690bef480d141932eb31811664409c02f910d67bcc08a1220a29e35ae18e32706414b4a73ce394da7d3696a4e4f27133dcd93364d7482e08d0b1a7bbb18417c41aac109d73fc34bd4b41abeb0218a2e8266663f6441225212e5c77892860f609a5019424e89524a29a594329a20ab21479404880f9d65f18a1664c41eb460d2460f0d3cd044df5f57799cacaefaabdd95ba9e0122767011461a51887cb4c861064d6491a38c31c6c83ca80cb54104eda3a861630716d55d7ad4b4d5aae67783f0a1734a78a8ccc387da3951d91f30afb0a28551684e53a36a426234455914a2699a2624a73b27e6a020240e85b13293411882933037240123238a7911625ab146951d597770a9d5e46df2d8a636f1f8536f8d7af48dceeee841a2e4995cc6b441fca244085e3c91e397c8061e3e5ccd7e884c3c3ad8eb608d8fef6fd520b89520a56ecc95a045e56ea150aff145bfdd41a5caafdba2aeb76f4d7fe1eee9dcdae9a469da69e3b4537f45909c36edd4ae793c2e346b3b3992cd519c9f7cc8e6a893733ee4e4dc7764e37a615bf7476fa845a8464d9a0975a293eb340afa68fad1aeb0d5bb141d09a70323471647d620093ec2071db88dbd93ff68d7a9571e578ec391e470952359390e9f289741fb986d974eb0ace84690a83c8723c1e12b67df51790edfc1e12bdf8e86bf16549ec387a83c870e5f7d34ed0bd391a3bf1bbe7908fe8ccff82639ee866f93f36ed43a232333939ab971e264bc9af246207f1b810cf5b92e5decbe50d3f2f214b03738bc9cd6a91524d31a125d5e1ceadb3b9a0ad2355ff500dd29f595bb69004ed470f5916a1f8d693bd30781eebf69970664714c1fb736d1a3ef783281f0b8e651d3d835d79c6a9ab62c1e4f4727f2d09c06a3b7c3e342ecee6e55d7ad89261c52b3b935a76a30ea9055eab3fae26cee51abe17cf704ce3713966a0be0e2d07cf4d6e29c565cea17bbc56a97ca02629c6bf57659298fb5a8fd4222bfdfa1bcf3f6d79361be167a1fbd864ff0d684e89184efdf3c5f9be828af7aaad50e222a9d433535db7a1671c4d506bb5f3e6171742c8ed4a458b662790b2a1f25af3850c4355b87cacf9dc9bb0b32024aa9ec99951144e54e4ed248f944bb76888c263ea63e7ae917af4089abb46b87ba1c3dcbc820fa908fb61f32aaf890bb701163f9e8726eb1b963a8f671a048830c3bf9eae4d521b47aa445ac3bbad060f42dc6efc6e47dd3d427ca656894f782f781b5891e9da7a854ad75953d6d152212000000000315002028100a8603c2b1703011255df70114800c819e4a72509689a35112e3484a21630021c00000000002402432800ec2a808552a4fb95e25c5402877b4a5322d7db62dad6c132e8cc756a4ab81e467b797e7045abb852912568df70f2650b5325d894d86cb1fc2cceaa7f4a53b2411aa121acdd32841150f884341ff71075239aa00e0526bd5454689f81feed7cbe5330f6f6f72b81670d41b36820203c55794f2836f7a796f07e164cb9b3b43d0016f70e564abf27eb4606e107015389585f2baba0c8c52640f1b1faefdd18d9055e4ae3f183452f2c3b66a93c019d85ab8db0c9a7b9b136bb06e96f31e62b54639297b856d4f5dffbb68f348d062a8428b6f611e3b2c76bff2327c84eddbb32181e5292ec5284bc410db3dd79ee29ba29864a41b021cf7446b00d8ac59741a00aa43ec6f1fd360fb1b4836eae4be14065841aac902320d092400b8a798f35921e1d51d4ff3f147acce69c0f460f8396c2a22c5b7ff9c50b7aa5bbf9544aa1c0ce3d95293916278f35f190aeb3a3b54bdfca840eb9f550d09049291ea61c5d00bfe950224b653fb8406dc248996a80eea5ab516c74c6d51be03e63642d4ac53c20bc5601d4086d6991607992d789bc818b9659ca6fbd2fc77c3996afac980ca8c8aa9557e11041852b0db177de6785769f8b49423c0adfcb36f48dab1ef4bf1b349e6df0bf8e8890bd33aedca4b1689ca362fd2474b522b57a577d2f56cd7bb92cbdc466675c74ccb2bdd8689419dd5fe3a6c44d030c386f35fbd9bd9a9ca498b5289ea49700a75f87e22562a6269701704e77a9a7e4480b610bcbd0fe25d3735f7a2a43e078501d2f9af3b59b8a5a66440f5e38471bd6cf69fa3f90932d28687fc13351cef734ae645ab5f29cedc44d8817098093dbbf291e9187bc99e8338aa37af87134a5fc516b17500146cad14cc38a7608757295d269bb159af1fa6109de23b5a714f1aeaeba285c7cd7eb65c39e79f267d9b29685752b2b88af24c37c1a6c3967c726a5fcb6bd1d5fa89f69092be5429f631a294585afff90e75fa52ef394fe4b2e0fe97ceb8aee2e283ce4b46e8dc1f18a9521ddc908423b1c4ecd4bd2acc3f24c6478b9953e8dfc7d5875812b7dc4ce8bbedb54901748eb158e356d49810288b124a72f5b6d435665baf2b8cb75096b319ff67452bd40cdce4294b6ce9fdf5af6be2bfda72adb6f6b9723e63a662172d86a72002c924541e502b94bae59c33286660c22b142ffd1f98446c5f126030176f82b2f4880fe2209090c54cce25b153f5d41278cbd6c77f65b646848d19accd5f525623fdeb31ee6b37a429ba7b2b9cab8ca746afd325db899c31211d89849a3f13d066b1c1c82208a0c293e4baab5a3172bb148c91d0751ee8d6794dca74a6ce15a8e4c9f2acf084aac54ea835ddb951b78e42c56a12604453ad76e0588316e79e630022e155121fb728956d9b76811ffb0ce937023c1d7fc14726302557195794b42d74395a4c6e109feefd1746c751979075f45c15627b13447ca5eb12dabdb048c69f6b57dfdab4cce0937faee28a92691933da5abc34254f0ed4a6abe8b3efa618bdb6c4ecb559b46767514d52ebfa1013ba60cd565893b26c8ed10cb1b2e78c29bac76f7331f8d8bdad6382f9e655b80c50231fa9370ae1970134101afa358bbb95ebd91e9890b60d34a69a7f54ba088177bb87f51f28cc05e7f33352ec8e2f390c6d4fd6460feb20890c3accdf720a74ce331fc07f3fdc30ceecfcaa3e1a1654611724779164b12356a17bb06e34fea13a73e82db1931752ae161b988091310fb0178b06b301acefd8d260fa04902d20075eae7b7bfaaff3abdfdda2f5f5e79151dbc8149ccb305cf86b0334e991fda2892ae2700d445a095ebdb940cf412bfc549df3fa26b572d04c744b619c405d11c802a9ca58bdc8de369d9b0239be6a0506777a896fcb6b24345cca61cf87bcd6ef55f86ed6970822b2870f1310f08bc9737ce0ee6d2206af904c10fe6797a711cd8a1e250f42deb59981232a19f3dee4632f17adb33d5610af42943df892e6ba7aa64d4e6bb62fc6a06d12843650c310ac4b2e029378cd6144948c0d6e014d0bb8cca0568e591bf220975977724d48a3de1fd542f5357f4b3de0dc2187d89d4fcfaf6a0f3358bbc9d93149c1b463199cf5d9f0b1d90f2432f74f1bfd3b81f2709154832542c5e468504ec664a982205732bdca8b6ee4fdd2dccc7bb118c72306f47efe4554c98e90d8b51abcf094501279343567862e011460778d1bf114dee3585745627a44745b196b9d2276a810a6b327ced8fdb186845f59eb566201a617d6bf523c5ab83af73c578487239e3d48c725826560b7f99c623237ec9b71508160067a13bf28138c78d9bd65062c827a3272ef80fbad6aca177f0b5cd6f173d0277df712be1a44c2b54cb1c9e29362219b72baa2e2b457f389fd05accdfe0a589c31e53d5c04d06bc65a6e8c10d9bb6bed9e7224583e40805f1304c251b8d4bb028fb74a38e71c22139cd09382a323dc625e2390dee832172017b7d039976528f78c71062247a796dd27046ae42a3ed64270406fd0ea1dfb5916522ac5ea2ae86af1f080aa94ed907988ebd543c0a545c56644e595bbf39d10528afc2255ffaa7787730956b206f3db977fb6aa8b342f56a79c94f041cd6836379e8805b65dee2e410ac10f95767d87225c31733938e818cc5c4b469ca7204c79d72d682d32036d18d14b2c8f656e92940437ac0bba5b916409eeb5782e2d7951b9f5b708784f608ba7a00b2a335e4c050d251c5608ffbc1be4948c24e4ccb21f065f1c04fe681901e59e6492125ef744e2e98383f2fa442c63039cb224a06a128dbb4843142a17637ebb289380cbf280e12fecb68f4339407b8da83d45632c22dceecc156c962840235d25c4bd3b4edbf400115dddfe5f39785d87ab2b8b32d832406289e8c4b55e31d6e9e3ae1f589afbce00d42e944f91e34dfa49712abcbe3ead43d6d9c0ff44d54a31d623275ab89e8f7eb21e9f1a384457c6087ce273b46ffeda4568a9ff255206e2d9eea6d89a9feab252cf05c848cb4e1666cc24a5167d96850a33ea51fb387b966c434179cafbf7117eb8452449874cd3bc8f116209570c5544c873e91c5540c39a0f944c615b971c1b8bdfc4f7863a1c2a4792bd5b34279b13594776348647bf43c49f5e3533fefa0143ab7a838913f1885118996d9e01b25aa73fec0c500df6ccaf657be6ddf4617b83efe0e1b948ff2f75e67133fbffd7bfd358796c50c58628cce8985da8600fe27de7e01c4645be40fbb4fa36965b28586d7230c457c4a0ac0d50f64a8f2b7fc4befa72fc3202dec915acb054fce64d020b15812f31ea363e602b88bc809982841404bdb4373832e52762e490229d0990965642a84585c504d8a7774acfc68efe24842f97392817f5e8cd01a407220dd2ee666866a95b0f56404542cf2cf260fb33bd1bd503a0345ca6f8795f256f24e7d70a9bc3dc6b74663f0aa66ba497734a4c42f947bc7d920f26cb9409dae8ae3a50c4aa175f286e158b49c779cb40ac970b41ce465d1400ca9fac15fddb8b003bb716775818859f1cde3d5825ff9d3b28bdf58e08300b9519a4746b3123a84c0222f70ea6756eb6f2efaf2c31bc12349e35971fa222c211174177709e20812fbad902887a647be6ee7c8e8cce768f3ceb3f31a653e725087fd234d37a3f889c94ce2bcb3eddb26cf71a7fc6a638fd3809c7dc2755a6f9a5805df71be07364dd414864ffc1cba49ef49b1c4891a395cc0430d12e2b63bcd4184a9171c102008010696f7efbbfb72fad429475639b5087b270501d64373b3bb86edb8bbe381f37454fb9b449cf75d3b0526c0865a9b92f1ca8f3a0a5fc1b605bab481afd2b68d415d0e33b083d0faddec5e43fadc4482c8d1a42c0ca264835adbf5a3a1e87d40df4f617ae81ec061088c0d387e6a1c99e7038cb1bab9185663156f827dcf500cb8b91ed11f1d7c212219bd1bc781bffb1f131c65f40b787e223cbde936c2df7c23a941c94cc768303d25289c99ed202f63b0736fb0698abe47cde91c70b3e9d33a5883a07bc9859171d6b7db2ff157f737dc83826bdb6c8ca1b71df1ca807b08ab2429d790c91b5bb7bf36d79876b393d4e2c5aa608866d26d48e9262f09206188151881afc08b93c26ad1b1445730540b221edfae68fe16fcd8b420c1e48fc0562f9db0a2eab33de100e333dfb4a0b1a55262bf09534e07795483f5c10a5a46912ae088e205c88ce5e1a38a1c846571b2032e008849c5c8324e042cd53770a519739f7c508b37753f91105e88008f72d6a8bf6c2027a76b3b0b0280965c8b8f817c85f9f889d5464bf47a6e66cfd8a09a4721ea586dc82697aa6a581ef0c7cd76302fc6e1575c551109d02c3460215a800fb27030695a0703cad545ced9cd18cfb14e71e80dfd89bdf75c8df576c80fe5d9e00c41718425afabe6de4d3e61f180e42491a7a909053c959f70659f813ae9c3af5d34289cbb39f52fe57f6b39de01f9b9e761f383ff6ed3f6bba26d383c6732edde05b97e65aba099eeed9331f2fa4b7dcd34515fcaad39e19c2ab9139cb4b274bb55fde5324d5f00457edfe73fe683844238b3c17e1c79acb2d7e5401c27a915cc57d1e5b25148d2c7b5081b1cca4175f4c5dc88094ca5125b66e10aa80e61d30e1c632818d34566ef28e46780ce21c841f0a599986fda3b4d4fd7cdea9a199d0174ad401fb74cb49379903254b7ee5b630b32e600cc44cedc0f53037a8dc0f7b3fb15c11f75e270e8af42f7196d1b222dac9ae3b7da27fa45ec9b6aff45ed42129087b66da5f9e659f65f45f94d2879dac8afa01129d0da1f511e919ea44475e612ece7abff5b3deb8c484ec93e9c5178357ae7128998e7bf83dced982d0c0287897bc817fa6d9bcc990e0433bc02f9b43b17a84539835d99a2896a6164fad2c2ac160fd99696bf54434f011ecb891ec7108f765db3d2c4541d4d8bfb13910f057284b6741dfa0be56c8c7d8e52ff0c20a9d01f5931e82cf23ea3b0aa764d32f152a99e4b5b05fa6104837397f138e99f3f82844cad4dc16f429e0e0b7ea3e1f2d9890390dae6d004e5a43a76e501e81f8b077774a0f6264f74d213490281f60c65ca604143b3eeaa9bb63ab4bac530f79d5a0ddeb7089abb754fe6755551efef6432aea5ee0f6ec2e19681e8e676059f5428383ec7f456040e624d1e840f31fb1811b04a7b30206b20afc9a62aaf65400585099160ddcacdebdb556c6d13dd34c003678b5618129ab3b0c355446eb4d94e00a69730bec25c3a20ed4624889fd2fd59ec8f5cc4a34146fbd179227e06b607d7e0fa0100a2ef832ab07358ddc28af6844bb0aa3a5639855a5634c08e806fddc225c981b66c378ae56ba5d70e160150618086a2368e2b262581e50fa1b29a5fcbc9bc5dae05ad30ae7c28d1d9b85d6ad4994e073ab74a50c13a6ed2e5d7b33af534f04655322e3cb63ae8234c1e6161a7616a5814a0981816279488a96e1551d5c5342bcad5bae2998176451ff42a8de544d0624f02830bd5d87cf84c6acb4dbde9a63e3db1fe66d9fb84e66e096d2d35b4595a8f0a86576f7b6e98605447f4fb643774df77d595032f9596c79449f36a5de9953959569ca84e8f5b2733f6bf08386a0cabb23d56c9ff6742c5e2d3ac0620e3677fbbf8f52f37b3956231fc64c19279b3fc650ec3db12fe4e2d8962179e80358f6e76d76d6c53660e8d279b67beb98a0812de38c03e8574c2610f14bb08d89e29987a072864a53c101ffbf61ab18ea55b3eaca7b3ade282a63efe5a3175bc2b3f09100ccf1c1d43584d432a4368b5d2373fe3971f2161d46dfa498b7b371c72fee807bf5c2eca052f8e6a40b0c9d76d47b11e858e6a885a8e82980cc7cb0a6830e8f16cb644b4dd5a9edee77db4c0b4ab352e3570599cec618d498e23e7152bb4da0921ed19e168746beee3abd6897a3f4883046e85fc3eb1b8088b8e9afa71f60b37123b53e6c34a08ec60be102f7ef59fbadf8b87881c5e7c803758fb9c23d577560c8e44244a716b17d27c7cc6a27a90acd1c868c5e15e2f051916d7162244af5758355ff02694affee61386b05c5e5efbbdf4238254ccb5b1e84a873d9e9d49d900df30fa2bba1e586b20a149d087dfd214e553920c61d339f8f26d483ea53e0f629bf88322bd0027c42816415e0eaeb3a33c063a795d2399287c30454b90b358059dd792f47b7e0de3e5cd7088f9c0b266d87170b3e5c06c1377ff203e31081fac0b59e180d3a2366abb56320344c66fd4d988b695a9a82b1abdf700d78a45542170e02a0f3a1a6b6b8ec70e5af774501b437c92e14dd35e057637ef69a7e464f25e530885fa7c4df7da5cd2d4ae0eecb16a8074506c05dac22de0a84169a7e8e78194f646684cc99f5ee8253edd0a6351f4deba98798357341a81b03f8e0a81237385f6458b44aca09e2507ddb7e17cc9d29cf0855f8ca46124cdfb0b6fbcef933dc0f2d9667450b8da186271b658760d7bb341eebc1eb0d7547435485ddf74762b7bda2715a14b25bde8fe160a485a69a79e717457ecdfc4a6d27e3c2fd8909440030329e69bf91e4b88c2a34eb9b20fb9756044fda72ef6765e8a2d481fb0ab41e7c501d8b765c20ed5aa5e8e99930aff86b0ffaf584b044432b93e6ecc92129147f97e9fa1cfe02755c74a70daaf2ec1bc4f02b784217197513c68368d578fb05b49861082700622618196047ffa57937199da5430b9abd64a742fe062f4a09cc62e08ed91197d9dd3f9fbb66769b53f1ef4155bef863362570c14e21709c1045259418b6a38ebb7f7d0cef00266c660d88677e33eba8e346afc9fd9b9987af6e227bbb525d08e5949bc667e3822c21cf696f955eb0bd4abf2cdd44ec5a19599b91e991d8692ee54927079e5d2da0b6aeaa05956f86ed35824e603a965a7e87879b1c468463ee02afe038a6217de7e470f9d06eb3fed212e6b85185a323363978ac299171752d3f71f8e5ed114c276797cea9c939db076823c7cd1e43ad138534a31fac2158f149418137e78c9a2a999b1b8a0758390d1c02c19f83f7606d9534999d731109ed88c46a2fbae928dff18a7005faa4fc7f906c8907d5447131213418150cd65169a9222e75d292a236a38738af53c6f9cd2334ae16e94ed185e8cdc65490f30fb7340c8808ed09e43bdb5902c7530b1cc75b01a89e07457bd87e3dd577965b7ecfe7334401e27ec1bcd2b2d718873d602324a22d6bb391cfd8422e1472d2d130013c2f622aa97ff1788ede82d061dff9bb1942bf327cc1793ea43f14cf4f2dcaf3a9e58cfdcdc225b11f3b7d4db6f345154354f4a5e9e164c5e3fd9d74b22f0d9bfd7cd61e608807b8c43e60f9ec275c484d49ee064476f0f63dddeb761ce8a23950683d6bd04938e97faa68a191934987087afe3eebb45c31f7284be837311e8a78badde14be6e32f8d05f9cbb25e702a684a327f0f26ecf6f8829357a18e1c6ec400c6d2ee2afbdaff08c5dbe7dfbcf0ae44cea24494fb2af785054ee380974440fa7a9de9e43fe0f430b2ab8ed2008c9f61d4803f855a596153ba1e4c08c508008be4f53b7d210e7048b618b0fa4a09e55213ec64f01968589293272116724be2b4fddf5e6eb8e4ad01f89ce03be24bfd6043c3ce5da58ec1360a5fc22191c02b4c11de47f8bda7ebaafab0a99257cd3ff9d74d8466d9b923e05f167072cb48df748638e5f770cc730aefba7550d4e36da07ce56cd81f02743af15085ca23ce7b446d317eb9d66c9c2a7e111314b743331feb623e4c0f8976f686ad85a08b8754e761bfb8d722286358db2e05f782d3fefb6a9f09bbea62c7484a032d6e0e7d7df3a0780ab127ae914ea3608fd0447230d2aa86fe9d74943a6633414cd45f34c2b2bd7667a65756128cb7ceef3ac488a98956395f0aa423dbb3d0f67ab66e0f100a44803a72674b708ac3e21491c93c861bf8613c5980cffcf6a0287433c42811556c2e5aea46f7feb515a9c3b59a001c662062d1244f3929349bea716973c447a8522df25016b1accabc96cd2660aed5a7ee4adfb07dddd5b14765ffff875c08829810f832ae60bec71d4cc0f6b725f2aca084aba5fbb723109593a822defccbd14b780059f10a7ffd11c0a223813aeb0128744b067b2b26dd2e8081a8f5029922be06180426a12ad24ea1edbb9d800eb2510cbeb874ec9603e287bc0740e8ee23553ebb21cbfbe378dd723308b1d5cb401dfa10361d79dcf24ea9ce298934a3acd06bc29f9b65dcc047e21d8233970a25daf91b1162aca18a89d576024aa59adc023fd1ceb1e0f80310940a810b73e3186e18af795b38a5e1883216a20ead6efa701c85d8d3b96ebf0424b8dab333833a3912904ea94fce5d8b1dee9e52bb436453e445f62e47d040fa7d6d7fa395fbf31d4440298c7bf0942ec73bd1f2650166aebc6b82030cb1a448a70d2c3c5d34e5e3cefece78a053ab24a430929ecd644ebd283819339269c130e1ed2eb9b14f946cceed5a6b8b81e165a147bbf047f92a02f5b90e67c8ffd1cc3eab31c136a325c67f89a335d44093181bff05dfa66e43ecb800f6ee3ae898063489165374f059d133ef60ccf8ebaadd88af388c06c0b20aa9848b853dcc8b3ee76524a59a70be573095c428c18631b4874811602933942b55b353911828a2ab041164f63c3cb1a8d4a0faee8ed2e835d08a350c6a6e0da73b45d7e5891c91bc7b336015e6ffb485b5c6c39d2c079895fc10663a50d4b54689f32392f17a512ea781002ab53563cd5edb6f17e8179f621ea1648ff2d3043538f48bd5acae50e8f40e8c59cb93ae58612b75e44ff7f982f53d08dbde05c638328726fbc57a271bb27e976be6c8c237c941fb8d6e003e772c44d06f10322adab5f7057f84de73ed289210543ac1e8d61bca04746fdd2025cf5e8e756bb065bdec5f444e2e665557d84b540982c6d8cbca1052ae827bf9857b172469fabd1ce5edb5315e39fa5ee674be04db51c19194b33527c1435c8e3e915b3102bc949c61a397e8367f7466bfd9c339fa2553b9c2712e93f0f80665ed62bdba01f147b607e92bcdee5e99ea2b25ddbd7526d76181e306fd2596b56bcf3f74361edd5dafa42b8edcaaeb3ea43072ad2ec4ccaa8d8b511bafcb663a97c457ded1482e79974851bec3fde53f24340b689c3bf9223a779dfa30b4075d5b4ee5c4dd4196ed311ceefc73ec541afc733546f16ad1cbd467520469b180acc12c337a63c318c7c45000394b10e2b5f2729911db28a70f7b23de1a6652aaaaaff025ff792a4c3677222ffe055dae072597875220059fde7192e859ccd9c8b0b0b7019334654e8c42aba7ea771806f13cd6969f8b3577074a9a24ba5f393ae93ba09776c1c3ede2d7859884a3ee117af959ff1b3f0bc27eb2cfac902ce9784fd2e00fc14ef04a1b547a464a765919f1a2688f5b1453f95b491f18c9d9b2f8878bfb88611f9efe9de432e95e1eca1351fcff06fbd76de318ed459113a488a46fea0cde8445fc48650e46caac39c01cfb07d94c7418a84bfa00eb5f095c45f08338d0a4e5576f23b71e846e05a422e252a44f1a55b3707fabe45bf16aba908f824fbb9124c5d29bc9cac674b39751911d49b1dd7b58f5563ce2d675910f4c7c78b065cd4bb1e036261960b4bb30b5a93f4b0cc613dec7593f523a8dab3c3e113027553e11d846411355f0b080e2dbfb9652f132b04a7e883b7362067fc7bb4653250f77e1ee98b4d75462af2be22873b2266ff3199c2e77434de3c7b71fccdb78cc82448f864a49923812b9d18b8dd65f33376280ff989108684b31bf8a99366021f39a7170b70537922d9ab953772d17c291858d2c62829367030dd94fffcf5a0bf1119ad55d52cb48437110dde5745b7bdd944e4fa9c0f83d5d37ca9c83decfc2e0508404e217f7cc459b73336a17d94cd8cd7e1059160231691a1398a5af42c7c95123f680fcd59a57ca08d935c80ad86fa9a61812aac52e804e613b49cef4b9a16eb8ba1ca77867235a4b38190aa2efaaeca564ebb7e55088b1c81050f841813646f47a47e051ea2bd19c0f586cf467b23ee6db094039afd1e609d25c808b4842c7fa310ee7d35e5261d27610ef6976888ce064c8005ab4a86c4eca818ceee60bd85d110dca0e463772fa48c390c11bcf52a91ed79da2620a55f2c5cc78d5a730676de0a2e2fbe65ca184958cb7cd191569266aa259b1619a0d0fed1b5de08bea0f84ff26874db511c274f1c7dc8ca10f981779ee57255b078ac71992ccc0d46243dfc391f083105d1b170070d8f07b8a605e206fd8e12e9f0e56442e61978f7723fa3d2ba2e274244475f12c5eda44208aae74a4247e5ef5ba51a22e9abf0137dc87b413fd9b6ab3896fd1827eb18d21114798c1ec351099763dcf370679e5923c2ba485420eb94b6b7a3977cb9768c2e80bbf6340bbbf39e2750a508691f7e8f7767adda94f952171af6df48907216bb84e9a7dc4da8039b63fa85ee1d400d0d16b147918a2291f40d69b4759bda84c54d44c94b51b0816335dd16af028d226a4d0a2acba998e67c15c944674bd22a2a9527391b535d925c30e595edc8c3198d0521eed115025f580736ece28abf8dc3b1a27623ac00722d3fb8322a6be927b4b82b37e4a919518898abab14c30cc9ef2af219a9b21bd1e040a15d82aa6ba6c18ebda9271e0750d42f27ad683018761e4196adfb40bdba6930c016187617a9c0ac518bf9ee3f21889f0fe402b77d5993761332bb6b0309fad100640c59305209be186ab8b0b1f0aa3c03c0c7d25273f058879bf4fc3965129040d247ff7b697328a843970c86b6182a4edbab4e4f1aef954934a90ff8e45ca6053cde370d30a2485f4f50b13e93bbb9462d6b277c274a743f97ab5a0effa9909c998e5d036d99a7e5eb3198fb15f4d286eec617f2e6f5edaf47b3571145d0ee726ab0dda81c2c7bcf3d1a66226c6056084c4b6513a5d08ffad865d39819c1e354308cd0978d78a7a6262dd941ebcd232e01043e48040519df68f85e98b18d7be3608e618c9851e42ce1e0d39a8bf388d3a95780ff8f8d5c6c558262b182f8b9fd14b8df9d09facd8b0a0cef1c3436b1fbd34379c25342d89e6446ac220b04e10f15ca07e52f6a99ec06aa1f80b5e7c47cac1f70e8a90cf60b8dfc2953d62b8a20eff90c1c8a2e65453954f21634c56d62d17e67135ae13ab5b05a1dd441309ef81ad6b9a5c599823fdbb1107641a6273053a2eacf1e5de558ba72079965accf28fa5b09bb8d48464f830c16aca8f4f3c08139c90a5013ea3956b9934f8ab72f987fff7b599203f6d4ed67143273a30e987281792ca7d508ac8da38a3fb96eb419638c7b3eea6a36363a463cc1a4195eb82c697630a87e46b17f11f2239f32b231ffa2137cdcc20dc40ee6e31ab0676c24902151864ebc0d09526ac3903869ce4bd0a264a065cde78dbab18fcc7c4133171b1e69bd4e57b4877701326b13d34da52ec1947941ddcb94061e6f68237b3e40c7a52ad300f915a65e0b64d81199c5602e82cf477f5c859546770b2e816c8fe5d03c58498477e804df1da3574e6c5e0c97226d8c92d330db14ccf8dffcbd27b51b0dd3bd450981b7ad5d9ce5cab02b9ffa6f24f5a348a3197fb6324eaf86166abf238488002f018844338c962b70d8750200672d098391d9e2c45aef54e09d91174bc02ce6d0956d9347d08357fed0619c8de225d0446e4d72788be38458cf6c15e7cebf2cd8811361f178e4d74729ccbef8a0de8ed6c99beb156ca465c1d2291e1d23c87559a567e0a461cf8d2e3f728129fbaef387c7436dd524d5fa166e9d356c86289d7460f0f9944aae5dc3474dc300e48c09f61f409e4f4cdbb29165c2818c9eadbc41e81f9923f702a317e4e06d3a38ada5162e8c899f9951f3de0a19771e68fbab6708b9aeddb16a4dbe4a968dcaec3c407389da6bd92cd0c65fa5161d64faa8344cc680e3252936e9188a6540ad8e26f5d113a5055e439df0a8cffd81d567085b93252772f61ebb019ee97660b77e78d52511a22ee5050409c215e1e67636caefed4f2c90e12fecb8d19f689686f6d169eec4cd0f43f7a2d3e7b84475bc7bfcba39a928234b9ff4aba8bd1debe83e8f927cfd568d8c11711f19610962ebdf78830c9bb44ef8cc2bc3342d5eae70033bb89254b179693a1b5247e6dd62a68e1a24236e8c1101b000bf7d14230a90736270b3ccca483aff9bcb93b41e53e8d6dcb82583ab745802f53a1943b08c9ddc40ff6958b5d8ce4eb0d542a9ddb596a227844fae18bf0ee835761576665c02d878677a180317492444202f4cafcba7e2f86ee301f96a61c3fc107acb7d36684e7ee4efd52fbb1dff185b664fa3a3398cca908b380cc877c520851c9ef3589765f1d3adcf88869a2fda3584afd61fe8a1818238fe59c21c19c4b054b5c0c46b812e45952622b66d809227968e7f50c2d19173a6d470dd249520c74bf1089a1f50306030f665cdb31904b7ca0f534c5c5ad92af887618a94716d3d5461f628a568aa0b5e36d5942d8954d19f42e813340090926ed8fd68d2bbd46688414be9ac4406e28d292e5d42f496197e5848812468d86632304e72571542f1af3413ba296a18182a82990c554d1e9758df5c3ba4ea48d4756c3a79345722b24ebb3a0e6982ceeeae46c921aa6b735a4b69b6936b1a0f2d3302a101155311f3c5e8976744508c2cd3d96101fdaff1b27b72e7d1f97a669b3dbc795292be76735878c6ab4131060af817a794e6b6b6823517d0de6ce2634f3e29137304817c9cfc6181c2c977494f21a749a9ae1838c1e0a5650b4e6d370c0a5fac91b5364883b26f988d4104bd41b0d2e95d344f1a691c970c90837b23275baa872366014223be4aefc2c230d229b7b29921ff665a6c4ded0bbcfc87f8ecd010d9046882c8bec836b0f6461defc16c8999d98dd0bc9e650884fa113560112be501342813ae5990de32f01850cdd57ab967cb5069e387c7c455d50aed64b71047504d495ee22f0bca340f5f7d812e2a1f53ec10183ebc67decce1239f204066676f735180cb3bb0d002eb78814f58ec80e96908ad56d690bbeaf25e4d985cbc18960cd212792e697226835b3964dec804b23c5a9855a57f6051c31f9aa16a1d043f12d13e768c326aa28fcf547d37e9cc2895c122b8df44b7817d33a228585640c8b474dd39b0e751045ac7e0894253dae41f98f222b9668408e0796c61f49cf01e1b0351cce659a875317415032dfea0cbe13a6e4ded76893b3fae48a03e08bab72e1a0e8efbd909e11178fed8351f5d545c1139750fc061ec6bc9f38aacd045c73c32c77aaedf16cb24314d64f58427ee5a3d695d7353fc4bf4e925f6bf1f2431d20927a036d12c5e62e9a5e9bb110d642a0153f0161036e40b357219b69ee27d546a9cbae3b99f24c0e8dabfd1207ff9d14743a274411ced4aaf5c25090970df5501243c418def9e4b2522d41812b45abc0b21280ba3b9da5dbedc76c336100059ac69b2f2d38ec5aa950bea0d898a57e6e5ddcc73e545f538b5889e47a6e0444e41f0ce3f870e5e6f31eb2e33acb21b807e2a195be733b2457c002beb281d879c02a48f37a691823ef83ca4181a346bf7f90567806734ec1c4aca334ab69f1d49bd154591068d341f52a2d650be0bbc3a7a84e2c9c50e0ca0b70cc9b39be6505565d9113587220e2665bdd20a4e32080516585ccdaa4214b01c9849820a3c8871f69f03503b4cc08273d3260c3452bb938775cc9b151ddeee3ee3cc841ed320ba1237d819904410aface7eb71b773abc45d251b755e799288b4d63f0ba373d84ec4b8ad973d824c2f6d57781949c12af5a7ae72ed8bf97745fcf44b588c4582fad6460b562e783dcea0ac4c52a6502981046c3997786703ca5a32b8c9dff99e9e8ee4595212c1e7cd930e4bd69e48134302d1613976fc2682cf184a0233df653c65939ca5a845b674b81fe387d4077f09e42f426e4df9fc3211797125dbd5ea41242c5730b7d21ce2e75b21e8151a7664f9c9810743e50908ab7161fe87c2166c8ef2391c4d5b1987f869f80b8caf3c64a45cdf6160cbf6b84db051bcf87f974209ae7eae64d190fa00c30863c010681e3af6646d57b7c2cf09fe7fae7d9166d9b85235b232733ba64b46f048020e3de84514775f25a4bafa16c5c488f8511b7daab4f03c3cad651f2ac654109de20632e9b452c52ab0566ea0c9835b42195023c8a97405fb38a5d34eb7dbda2704b6387595d01c88e57e58b70673db036bebce155252597bbfe10d59fb4291724721387bd87c3bb36dd596a41f05bf49d6e0f235905b84208d124358b994e1d438c63923a331a308e1794ef41de6dae1ba8522a7a35bf78b770475d70cb5979f97c194b333c8b0db7db656519f855f55c6e4b68fa5608e9f948cfa97b6ee00ffe50666357d4ebf115f6e2c9b4b5341946c564e3d9f31934a326bccd07078f6c3c807d940bf5af88c2bde5ea59d7868d4073c1aad997d2b6219b696af9ac8eefeb368202c8b10e824f4a59ea281905da0e43d4c3356e3cad4dbb8286b95271b63a6a9bc2b16fccec6ded99b89304c7517e7e619426de64c61b4bf08f266a70df417b2627da759bb83ea4f2a18c148236b1a50a6cae115009fa27b1a3e9fcef9598dcf2a585a49e24b1afbb842a7e3550280c2c3d801bdf0fb264dab30d091e4f9f74c01cb89e8d0c9b85241254b9ce330f98b90e72450305744e8b05d1b854edc4d2d4469e3c50d1ef870fc5721da6132c95cd7b0c44adc4db039fcdb2a1087f2d5058ab6d3b723a7a145b6b02deac6a7b069b0c6cc61e7be7fb9a7bdf13505bd11b02a57212e08c5333a2973bd62d4436b5640be6665c269580582b868fb1204008e6e292a539299563692a650a319c6b5a426f4523ebc69afc74b334999f5f71bdb9785d3d59fcd4b164e9720153a852d8a205a08f35894e936f460146ffa1e0715f56283e7216d0d8b3658bf3f0a5cc0a7abfb0a69d6de130d801bcc1306eae3c2219d192065ad138a08ac57fd51ed1ff34e2411be2020d63d83de2d2767bd0507763fa8c0b574988c0a67b5efce75aadac42995e65fbdc1aac7b47a98bd4787c15820309e39328744c08123f365c2a13abb04d8d763e01ac20ab4e5b2259bc6a738ed0146c0a87ffab50775ae16b56e3ff714957a33aec254a8c86a3424652edbafcd9b0ade51d0a74b4d3f6a56b41cf1bc4b7d6a584d4dc8a0ab831bd7121a39a79e974b172dfc8d12e8bdd0f136bdf40acf712244da352f5c61962a94e8b2d44bfa81bcdfeeee22e24fa8743f5ad0df096efdf172249247904021ae8efe15422900c00c3eff20a16050f83ebcb5d3d02c4300e44aa52f83a0702306dddbba84209b96feeb11e0498264cc50babf4545716102301459c9eec3cfeb4e55cdf1f3ea903f709f2f8f3aba7e3fda513c62951264f2028089a7fbb8b409bedbb3a73c22607cba5f646004b19eb537e9a0ca6893de572c00633487a8cef45870234e3406f4c6e2f85ea5d5559a277ed076bca495a8b682fbd7e40d346a8c53cb723158df84a05b5df3e69dd5d0c2ecd3f5d20b37389ca5c45f763bf77a37b5d274f0d43028ebd991186aac32b2e565c4081e64068340485e9a16ff12eaadf5684a87f31cc17a27fe7ea86fb6c055429bff042975cb51aa8ecf2af6ca113dcc59504886cad62318161d8542d0a08270136143ba2ce4570f81fe09a68337b1a73a50b372143de237e4848299d755f9e33b7e681c8ebc993ba1035a7c1407120bd63715e9c99a529cdb3b6980b756f19b0acb850ef62eec5af6b38482146c54847c25b81ac1989de646f191df313bb571628c2b08f2e7f8d7e710f8e14faf4c48874d40515d211fad5becd201d060e9518c3f271f1208456d86affb134294f9235fd3f6fadca72e835be09f727891ff126340a2217e746795df2ca29a340fc0237cc9d2a5fb83a682ec4896dc3b34b9abbbf8fcccde25a0a22dc78fbc806fc54389f2454c2cbabfde26e6ac67dce8f592a536425c321aa1f49a1e2a05cfa708b903b6fb1109b01970669e955668533c3295e107d65dbfc2c26c7a678b4b88c3d3bfa8bfec9dcf7cc888cf58902a128ffec68d9b006d89887836a7bf32fa84982d996b94cbde669db19df1b606ea50f23e06fd616c900c1a04e7800fa5dd62160043d6a1374d043630093a388f014d26f7f8428e6644d0b5d0825a3fd8155e2ee8fec9add6e992269d148528a551552c4bd45daabd0a7621f5c93e043d6de44f2e9a15e5ff19b7201424bbb4037c4e4a517f7da55b45a1e43cd5ada7b90115d7a5a0020ae94a5c08d5cffb2100d2fa24a8b889aee275a582966c51566144948454b70c732ce4fd5732aa6f19846660f3f8ebc4fcb471e5ac46d5e726341551e40b6423a158138cf32d7c4f8faa72fe42884a7a11ee538e21b06953eeb2b2d42a459368ce074101650f4b4fd9e29ac78aa0413b03182a0a119d9fad4a37fb7e1fd39a8eb9f15512e7217a21b215cec76011f2a70b84b6ae3f6763d3a9cd0b07397f1a91ba9bf73582483f4890b80ddbb3eaa099e42b7248f2742b92b89ee7e84e0991bb8ce15c58aa6b0d478cdff13bd04890bee0c3eb3d352a2959bc0b642c5cb2daef458844ddbdfc4eb0863e88c2d462634de9012dd88bdba5f89001b64bef1ab18bb90c06ad32bbc640e07874e96fdda94dd77b0c5b7c443eeb3656d3b843ecf0ed98b0980568ac67bc0ccdf39d8e503892ae348105070cc046f3631185873c22f81c0c0e87403d1a72e4c91af386211f8fdcb26e1320966ff3216ccc2e44c54d0c6041d9ed3be79f1fef9cb68165bcd58a03f410ca2ffed909a3b331377b40f7785b42d8989db773150ac0fe839e924e0f1239b7c9f9b06ee03c1f4fa2c22fd1d16eb731d86aca6c5aed6e8dd8d151bf44000a970464880b33678be32582b3f7e6f182aa95e97b50010cb34fd642ded0ca23d708fb364f7ab36582039b7a34cb006670fda09a2c1f5bf3f0da2978bb0c8395abf5cc7ed676b2ebf7227f52601e27144f54d6ad740c3e3c8fcf67bf7a86f6a62abafe7729952519a01e5a01b81e9a57f257f38f310f410e322b9d07b800a0aab4e3f5c5af2fe5d0dfcfeb2046b7b53485b8ac9d70c600683cd70da2a6e336a867c084d4c55101716fb1b0cf9a37aaacab24e7147517d9fad0e72a2dc8b63c488260a6600c5582da101d75626cc85c34613a4f2cccfc24863a628fc47a5c812d3876f501e94e09695e05165a298f56a8d1043a6c23c06fb0d3e0d7c81b9dfecd43a535e0adce36743b5f2c2a8e591fdec67849249acd45339b77037e5688859586e2b8527686648ecba0f1ebcd5812508a296aefccffe1011f59eac70ff2e6cca1b781e26651b9a8f0a853c51ede9a0060e189705abba66312a9fb5c743aa0908816491822aa30b298491b7afce5489a7ddb4663904376656cd8e8cc113bc5f095092d9852382428e9e6cdc6112eb124aa17a91196c97e53bc66d1f7c1a3cb96efffcf8b526317cf410530512a661782375212aa73405d4543600e5682510d1a222c60938144c0bfa7c36e0c60f2ca2359c0f413eb31059e45580a6ab975835f3f897364c787bfa60ac80b6dcd2a7a09fcbeca5d8c4a57d37c3779879a198a5be3dd8dc74f5039a11360b9952eff5f8bc0ceba9effda60027092c5ada7912d9e8ea9a881c9e2782549725445843f451bfd99c52d2acb64f7b6d07f9ce6ebdb474ed9dbda55825801dc21336196c48faafa2068d9b8e75674e94b54978206d24987a0197f12e22ca50044e41d17f7acf9f52c59a1a51efb1f082e99dab7be12a57115145b8cab507b976b28105340aec6c0dbf316178c64dfb384d84f89a525256933082cf79e9849878ea29b1c8b30e8ca6167556eefdb01dd31c70868dd791427b72220722f513321d3360584f13e53718d8e5d4addca8b92a3189207d8c331fff6bfedbae65a770ca88512cb6c82f12f6c9d9b6e109873ee17bc6f2475f0972a17b5eb10275817fd12677ffe50bbc82f6d20858ca622b9344f0db6693d15ebcc1090c0b655bb77c2fd5b2efb15a067076e79cb6b7dca71f244c9dc66488b716c7c3c607c14d02f4510cf9d37ed98fe978ec9182c3a220fc460bafdf2302f9419fd7c445002b0a51810b388747db44f3698db0c72c476345948bf99179130230b536a6fcdacf12b9301d5a59a8c56dbb9875d5132e75fa7070b9a7b342a599d74cfcd400dcedb9337850ec75cfea95c72f0419bf2920c760d39bb82dd76772a09daf08471ddd72896625b621a1e26b929a9667e77a654fdbd1a5ccf570b9b2b7a583a97de53f320ff4807576d82867f6398cbd514d3e26bb3fc37fa0fa8759fe8f87d09acff0cf4cdc752f0e873b67f9770c948e4b4247a5e7dd1640d0f549d116a5463d82c665f9b81c17124f10f1a27cb490b73654cb59bf7d93045deb21568392a890e6e40d9de8bb2e4b433d1a925f989a43830f0d751cc4e38e7b26ae25864cf89500b8687151159a7621276e45685757a309775559dafe2cd0cdf03fb16bf307176089c33e1d8f540cd8dfe7238477280d0dbce0bb6cacc01d09374bf04a40a927ac25c4e4adb7a6ca45e49a4157bc444640765c629999ffb4ab00748684b749b13c7caedf82fb8c2aa51cff1abc06e0310d06f6ca3206db4f7de2b2f1f0ed7c2631f984d4a7a7fdfb404070d9fa98cd760e4757867325558b01e00e5e4b859d6a9b49ec0d467a9d7fe4054c8762bd0b8f5f1fbcbf420b5671de585db87b69c19e52cfa62654c50b1362ed6d964f1edb5ec89c75027e32d9d5e9e48186dbe49f09e893aab69a54925b1917333009a9664cc60e5c570f5af34a81a0b0fc6b423fdbbfdadb3b84b4cb353d1755ed7a7b889294a839939f533e7b9316073984b512123b3f45930d6ebbdd9876c29c557debf32fc50c0bdf3651307c51daa06fce71f19a99026b1736db47d5c3eecb1b5b6a222c6d981e27928ed18285cf369ef2f61e86b5acb7fb1f36b11cd88402bc2861675281c82468edb800c7afa177e6dfbc134518c08c54f7cbe1d5e3f696161736300df90a79853e8e8674c591eccdc7e4847166d860d25f01fccf33368cf55ff14dc92303bba0ff7d72eaf58793823c109ce6defb5b2b35615a0e11d130b60b5a6c05a0829412619a325c400b8cd26c5d66b5c6d3462ab8e9f17c67095f67d6a89aff37e50d0b8f0b0b78cd4114863f0dcfa90f218a9753b2e13f1f5bb7e724831c24203ad16ecb96197327997e7e5e9e84ffee65f2abdcff45f18dcf8b868c41397e845207f19d92f8455569a6986911ece9c540d9032fbcbe41377b0fe555caeaf94d1acb771f2a8f5aa7a1e081e01dcc75b5e90153bcc273550c5c928c23ad17635e3b3796d4981b3a4bbbb6b8961f1fdb9debd12fa6e8885c77c594ffd50da3ce7f90643cb448949dca8e7e9b3ffd622c807920915da568c66bf68ee24127661a503148e83ca14e0e3945f2c4db94120ea62e7f19bf1a49732b3728193076343dd50c8ab38999b02eddc94a3f15465a84d4d4ca0c3b227214fe601f1708c0335559e3599b38e64754630ea889bbf388afcaf4a03f1cac116be6becfa46f3898adc332aa6b42f98412a6543c325162271b42f9474f676a0d3c6a08dd7600b2deeff48e312e15622941a8db9b001f679a920cc7f5ccc4a4b205b0c137ba699125d2f51b03ee246d27e1270e0a2948c0e263658a8996d3b290e3748ca6e420f017817a24386422731266c82d3cfeb7923fd5825d67800843ec312edd94a0c3e78c6e9de955b68a614e16e1cace32e3e90b3217db517fb8fda6cd49c13fc07891469fc9f949a1118504c9c6c339c66bb9dae28b5a23bb588c7c245257a140ab95ff6e909d59d4e69b57d2cf06406d3850d34d5e609574b26457585b1a0fa610bf8dad53cd7d173a41e89f6ac95d999f9264f7c20fb887ec0317b00c8247a13a120fff976f81269d57d3026a95c7855b8bae352e5d30838755012779645fe7580c8772fcb8787431694b780dbc58fb47b4a8d1cb2074588074b20b9a10ed024c1fc80141e3ba170f0778e045eb34b3fc00cefdf196997d587dd964f87efb26f62a0579af24276a934a4958bea1b54834ae07e42c9ba21b0b70e1d5c3a1918955773706d97d8371b13a2adb59d00f276fcc7ec80a87f4ac7e6aeb918d93dd02582e88449e30899c752bd47db30c6cb6c6049e9c44a4d698da3cbeeda3c314bd7912bd1780252b9944f512003a711c2b8b7cf8624aaed96171aaf50fc11d941c58acd79a31101b3122a740e326871b6694cefe771397f3c7ca7c0f24d8276dc1c3af0abfbfe1229bef80ba6753c327647fe9638a591209b694b3a0f49ddbeeb1fd17c4e9b4491c642d3afd131bb7f6cd67b475e4f63c0cbfaad87ab9f08bac8fc45812cd79f75cea5ae1001d957772e82b1c15f4be7cad543504d578a38b0a3a339775fe44d207cdaa1c7a6ed851cf09fd04ed9d0c3316e2f6d4feb43ed0b1932b625eac149693abcee031b2b9dfec38da3b7f0b5c526f07eedd0e4405bd3f1980959f80b35c105938eb9e826a8052cc022a78b927d53e1a4e7c2dbdae05d5cadcd29f7200834fd3f253e408d3565d9798e03f00eba3db52e302401d2b223c13dbdb271e317472dea84bce7628e1a4e71724ce5e3e2152d8d239e6b6690df69220e262c55b786657200c4fc8e257f9e3fcd127a0fa95cf646f0da9c345528307aeb297771a162e5079b7baff9d18fcdeade68f2e00c8f8f25aa6b663c9dd719bdb6a423c02f09566a858b496fa564a998d7581004629c23ef19724a4678acbe1088538877291d6c010e7f16efe732ec4597b07a06501c61971a001d6754ea7c431a028e053752596b9dd52f55781633b62d1ec2b634102d2cd821eb90c95bc13d8af2d3c2977560e73377b6fe2e1dc035d92e31d3e67de794ee811bd0fa83ec9b17c1a5724f82a918397d59958394e5b41a91583567db30015b68414205742aeb9fbd088327502729dad9315fa0ff52164a4f86d41bffa1b279a951438e4d7724746a617d55c8998fad29ce3604bbf299fdaeee26e1a5d6e7129af07732c819badd5cabb79b138c4d59cabba6f08087258c0bba8cea50abce7fdd217797e9a2a5bbc6a12f1100aa7f3ebf7ce049485ca8627a07d63b9d9f07a1bc6f35efc86d3f01114932915800e7f64d26ae80ae1268c159f89493c92e60918027e88b6dc67f301417d9e30c3e8da6e34f365988fcaed473b2ec90618a2cfff308bcbbec65d1cd0c1b3c4b3b3313af64b2897b6e8f8600347bb3752c9e6c21b7803366d09a08c98ebf0884c6c15e5840fcab092c7bb0da44bf0d4ffa2210e3800534b8c7fb2a9db40c0f7f343667a6fde031e9b3b39e8da1d8151d3725b3651c7068f602edfeed979b04dde5ac73a25f6983e1da1a389171578e182fcc5f2441bedd29a68199a0b5a7deb538689435db0fe9d3d462511253dd457bd1afc1c52f1b9b607c80a024204436c8bf4cd7c789c529b43bd02117bd0dd2d8fab1c39941552cb2c01cdb8972105f5164620c2fd534f13ffc0ac5b80773b9d077779a68e091c9f2c940dc0506fe2fa3be52921aef990bccea222a6c06546c39e89d9c2c0880068e10d01248a5b86ad801ee705b114960d2e5517b7f355d8078a70c0746c89fc5375052c730e1f0c2e933267d808fc168d4997113727cd30cb8dcf380f2e85e42f676c32bc4ae2e23a1d031c04d3a57970f59bf819bf35bc658d04b09eadff8ad7887306574e7fed804400ea432edc0b0a3c966865d5edf81297414d972d5d494f4fe4c4b641eaf028fb5971c74315bee15e5240d68a7e0236b2b508dd54850805814ef946f19fe642494d489913744718fb06cb1d82904f7d1dfa098b349e4188008737b0f87b07c2a5b0113cfcd7dc5d32971aded4ae19de2365a4be2b4b2938ed6987e118aae431a8bf3d87597b485821270fe3480d166c20cf1a0da38719ae7f873807e82dcd3172ee1b99c650930fe4c54a90f6fcca49e0573b64b7aacdd160e5943a339a4e862a22e7f7a352e3a275b39d46433e9923f881c198ced76faabcef021a69b90d5413ece452df6465bb83d56272c8dce599363016f546f577f113d6a39585125c01f6bccfe84064c8e1a85f625ec0ead56c2b5bb00c7e31d63ea284b0ec93919099b32318a029205c6f307318374d66aadbfa6c3cc79269ffbda3b72efaa828e0bbb9063846bf3307c54bedccb4dfd567545f315411230fec3b30c1314f7e072dbf4d8178c3b36e428df152cf5e27a97f70e69c159b07b5e8b4873244d276d27f7196c29ae2d6f3c39df5787e8c18567a33e63f948ca8300b2f0ae1c37595242da3e9ad1355666f32cd44bf5baf3742857d4ea6af83b981d85d5be1b2ccacf9590ac67745f433f6d432fe11a152e549d4d9bb581e4b0d44395d895d717c710abefb56e564c4267682ab408eec0f793fe9597c97dc506ddeddade255e8c02b81ad7bde44535e78d7d2ecdbe4e5ebff4b92b15deba365be43ba8ef4f559d9958538e402998193c13dc6d6073ff6dd9f1240c573ace1310b3c0de1511b704b1f47e1b840d2c4555a3fecd422819076f3d208fc6bef066cd26ff70082fae29cf3da1059c50cac77ccd52d5b856ca1c7b2fe1d8c4d5053923e3c78363559e3115f23a9965350bc4f4489e894fa3e561b75b81117f8c46b80ecbd71849419073e4c131bd5746e709638a4fee14fc921490a455899b4212df1aa782fd633214704a3c8a7ab9b1611bb1138e67180aca70d801eb07d6c8ccc667346d17e20a5089b00967bedc0f7b6872d433550f0422510014b59a9afe458ca36c3e71a3bcac368543ae33a15314773593d7026d0f6e8f8a1c8816e216f8b3db51bbdd004d0b5ca53ede082cf999978285edd26cda35a891b708eb2a0e2722f9038e8965c1fb08fef374dade4b0d974abd24d3f922b17c5c9841329c7ca6f75e58a58b324b4b36288b7a4279344a4dec1d7209c68707c63e76c6e6e349a36646351c4803b38ad8ce0a1d1a958cfa294ce65094f1a7a2572c4c020742f9eb3bc1fc44fd7e0d216bb39356c984187ce40e829d192de3d92fdd8466e1b548e8fc8d8ce2385b88df7b3b83e98b1112fe2d3e4ce94389de905aa3c0959789d25ef34fd5e9091cfdbb1833a84d6a59c341ac9f9eb5c511b573c40d1f3321790a01a8531e11013d6cb92f6320e6eccdd96bed1bee7aa4055f1ece91c61ddbf7e0d5c27fd489da9045cef1c280e5bfc096e246da436791539fcab8cbe2bd362bfed42afa363b82e1072e27f256f7dfd202d0fe568c4a5ad757101fda7a479fc5b9f2a83d9e615067d4a7775dc094f750ce33b0e55f4d04bcb2b794698f4b551613d2245856c6ed4546968227bbeb00eea07d2999835c1b94a3319efce077f4c056ce1636eabdfb40da7d50ce25d78c17083b809ffa1c1625e41090e45284b4c60b0ca231ea6a60fe4a8a35755d4c6d10eb600c45d5033b20ce42d00395e4cd5cab140ac091e67005e3dd200c9dc5c10d37414549a5a7f523165abdb762a25bc974b006eaa960e19a6472b369d9f5d62d9fd80f1218c2b1dbd4d64d94a863f2c4965b46631679a5dda65e81d35530d8ce8fac79f4b9ab2ad50292857237a6d395098eec9c9f6b87901c6cee8538ee7d34882fd077f19a193b11e9c83264bd29840a34d7d52f6517b6e03145374874b730fbc8e301b8427b0ceb8d2ace0d7b8829c2f8b7b48a2f3dc10564b09c3a2bb180589aa3391ca002049b91e4b192e373cc4d28d26132e500d1a515fa6fba9327ace55f42f5ffc667c19cee3a099021cd0133ddf8b884b1d62ee6115400f6ebc1f1048ed955153e4b79bc0b2eacad34d239d193613c52019b912cb4fc9b862258d5eaf33bc924e46a47b9f3e4c6acaa04e4944f080b8f2929e298cce19c1e671c24d493e85b79357739444ccc8df8bfb0471aeb0c27a4b12fbfeef4506c094aeeea63a49127206226744e4e95ba555609218dd4930018752fd4c4aa63b868d83ea7b8fd0e800f1a45661befd7bec24a35c35b0837edcb24c39dcb54e2a00a18cde5362271e6da2ec20a97988fef4569948d3d3b562037fb67e1a80d43d1df838c00a469da3ed5c392e0877eee70b1dba11aa2c1f8ec6ae5cd456425eb7a05734f24f0fa89fa5bc48cdcc3eff48ada1193c83e31834a88676d938f3e6898f8ed1e0ed54bb726c2befddec0ec35b771fe0778f8e53c8efab2d4b8726c8d1a4bcb0597a34a77ba2f038197472f0b04cd7e9244dea459361030b1c958c8b320d58925104545b23f38db098d338f9db5b0b92101c6f29962314f6f18d26716037640fbb883184defacc02a192a7501ba2f000401ccc561cb39415d6ad2a1ae24292b88434e89ce082725b52966e8223c213d2c6811c1bbbe069cbbbaef502ba7003f4532a1a73406fb700b2c50dee7b38068e006d229ed367a6dd94f8cbb485b2e4816517eb9af9fb35179989b29a0264843a48aef208aa0c2c56e3ebef47822ca61823f7d2a2ccfca60b487986cfa57ea5a067e182e579cfb3a0db9d05f5f2f1237222aadff5fffb14e724d15daf0b6943f98a3441ad29d4a85fe09e4efe6c3a6a459d8ca4dc83e12ef039e77d8ab3f384a786f71c9ec53d91b12f4296b0e0a3a02a84dca24930bbae36b6080b174658d2e2a148d0e6b9f65b0a18290696edb47d83945d7e64b1be93525c4a06e21494691a5ab1a30a18e89131e840d6d2fc3979e6ff09998bca72ab992e8bbc08c2b387363ea0f20e4adab26137533dfe49930af6b5c692c6c2b51f2f7e12fd8f55829f366595b0cd80f6045f4d1afdf11846fc1c6a4545e47726316b1f8f6bf12f25df23a63fade7c81589f41d3ffd71a51d5f2e97407907eb4efaa7bf2a371f1279b403fd24c1c4a495546cf693661453ae30b82214e1ad9ec51125d00c69252ea172121dc1aa5ae52468d403682484df7910d30e0f9c6695d7471df5de22bc35426ee49ef5a8a52118e053360a8b0330ca7e14d4a3e06622d2b1d2bf75851c3c5bc2daa7c3cffd6d2a1d2060ff22552fdc0a323617c9fb749c693e811f5b6ec29234d6a679416956143b0077a2ff3be93859ece54b8e558a4f4c8c6192b870d682167ad9f839258ab3a7bd92e244d594abe9ecf72d2472b96c80063c603d274be0cd4c4a08b189931c3c607172f298a1ab3430e760eccd784521c3ff7bfd75f5734c96996ad851331f13cadac914d362a9582e5c7b178b31dd5e9d8f60e6242a466758cfe024100965d049ad0d4afcc8f91bbaaa1904eab5484079259e6396333a686769ac44fba7a9c96bfc5945189d6d1fb1be68e4c289bc244ce998753b029695603cdb8d4075acac5c779ab3529a9508af7cc9e816f610d76271182b7e65f8ca33a1e4ea9569e9d125539928d4409734cd54a455328bb17f2482ee1a5a89b447a2093dc4f89dd4253797625f8df74eca2a65435944290f95039a7ea3816e55bcde5187d3612c067f16f367512877f262ae34a78d99bbaf8a79980dee5e5042fd416bdc1ac3bea313c7cbccea36ac56e9ad659561a2bc38ad703584367de559a764dc22638b5cb3fb76b44b228e50be00a9d02b4e377471450e24f13325f001f2481663155726ba3912b10a303aac52cff9524796c79cb33a53c1492c29769937732e285968eced219cbf395e5885302de7a929962273d6949568b0163252e4e6f4283b34a7706b1e9131d89b2d90a851380b79382ed5912bacfd00f5891ba5e63b641593172b9659a34d6ddb3054e7d8610dce671e79be4ecf33ce2be9079998eec51e300a426541601bc7066e66163b54c1771c708e35fef3aa314ce92ff59efc702abe825bd6e3c4d8b8ad26938e252cdb8a62635c25598606c1d6d13648b640e74a9ca11c3ac36439e9b2622152638bb8b1de3d16be08e066cc1040dfb2c86fd3e57f4e4c64c54817c989aad6f5f54e5627af7ab1fd53589a6ec7a9537fd6494c1e25c67fcba3061af34959de4710637c69b05228b0e0b3e80582402894969d45b7341545523c40c3b3d86f09ca8e1529529d4661dcdf88269480033a720e805b30ccc24a0799a9bf0c88b14bc38603246a0a987ab69e85a65cdfa5bd72cdd838e9037ad41c38c5a386d94db9f48a2df06000106faa88d3f3a167dcd5e41d40410bef82b89745b06b53dfbed761212ed4ca4636d964cbbda54c49a6a007b5073d083be84b7e22238fbc9741ad6f8548244c08b60a2794962d66330dbe262db528574dcb1632f9ab8efad7439c2bbab35a752f9ba47c799473e54b26e9d43efd6ac924f952495e91bfea28087f8b1cb9f31770c19d43524952611c4a300ed9c44e968cd23c124946995de54ac9a55b1ef9d1917b87b2c7dae431791284eaeeeeeeee7dc5abbca32fbb70b0418288b01798ad2533dc30a94c1a0fd99236ad746f31a198ce201268d9d205f999b1fc3e96a6d4081e00fd8c40c2088ca3dfda124620410891f6b18f64a643826b369bcd74fc4041d911922cfd2dfc27818ccbba46805a927253e3e1e423c8c9c9c9e9471945d663bb39a6ac0fde31e3f607f10ebf5d5140858b9ac04f5f46396a71262b280b129ddec9a9abddcd4d77a2a14697388e9bcc851ca74365abfdae8dc2f04ca6b05029cbe53e44a8b26577d7da4d5b65d053d9eda993070dfeb428e23c507b3ffe9a30afbb0891dbbd578bd85bc391c8edc221deaf4058bdf71f921a1658b1416ebe6bdd8022742d10488b3e70b0a34be4c0c56a9c29384038cf7a2af33b649c0ebd077290fb55bf7f95b5b9324edb076a0e1ac7823490b05b68d558f97587c5e31b234f91031d1eb4cf28b20ed15f765ad7b66d9cf8a3a345dfc2b2b88264664a397e4efc3576bef3b70adb73d5973f96c0ba6a2cf7cc00ee87f06f3f4b605d2e9cb27a0657ab4b63cd19cbdf3d53ca263563d95c0fd9410aecc84e22b48ff6995fc170d52bb2dc6208cce3cfc4a3c0dd7d7bfe919db65a6dadd60757f7cab25e59567a19ad4ba3ebfc342e6f51e2e49c0a52e79b7a43f4db62f991b0f3d0cb6ab21cba6cab488e6116583c454484201f4ef2458471f46b20c56e2e570b091123ed73f3fd4764ac7dec0d7773f3d6da9c9c9c9c9c1f2552ce0d0e0c18383716b461a4fb6e9056ff6365bd08c4abea85ab07f20eac5c3361f620c238a4d82d1c3db82d3615fd6584ea5d4fc4b6a268e2b23077dcd538b2f3fde933a51b83459889aa70dbaaeb6a573bb0088f4666f71cfd154854f4b02af237e6ba716864fe48000f91bffdea3d5ac1078d34f79b91f92301555555979b5356ff63e31dfe7939b43030e1a45600a6ea8a3bba947c9374a21940d8f9f2e74549e4dffb4b59fb30d843be0712098d2c56c68eb46eb0fddf03b5e38cadffde6b136cf10202ebbf9fdf07acef5e8238f37760bcefc0083fe80be30892daf5d6f59747441349862fae53e91751dd3203d2f59fd2c45b6490c1f0a610bfe23a1716c6b3ff94f0e3af23b5be171211d2831d194acabe3f09edc33821f390191af1fbbd0c8df8657d7df97dc0faef5be0900ffc1b199c807f7cf9dd4b17984118cb4a382dddee3baf82a3fc311fc8d9ebba50c6901cb9dd94442dfa4bd916b6a725058eeccacc2003083b8a326ad68479c7bfffb2dbeaedc87a0e2dd0c172e0fd8dc779fbfd50ae7d1c1c1c9df774741e04be3aa18eabf3423ae028dfc2f89c6750e84a23f4c208092073589d166f8cb5f5a3fdec78a3b6c26fd10b57f43bd084c9c9a79ef5d78d8fc2f2e7c8ad8a273bca952fa300f990524a29a59453148887bcf289b40f5f09c34c4b1654ae7cc962ae7cda3c1d50c5b4d665dff552268de41107f97256ca1e188d2f6c873544da6eb0331b488e344b1d41d23edc0fb12f85f8eb041d223064132ec22fd17998fca5e3c5ed27c23b6a8c1f41213140e61c7090e1f63327e991c2324c27dc09829193f31b0e0e33b37df9a3b438cc8ff3d632b39065599061800ccbb9224bbc3d8a2bb1138f2089110979174bd9d9143e3b90024442e4c76d9c5eb36aafea2adcf9b17aee415885957ba1bb715ba8e335f9d6e16b7203e522f8c851023b2b37a4fb8d9ed0faef7bd6f7cf05e21ddded97b21fde0132133db3622c5f86b5c29d20d6ef00f99edfaec2ad566bbd2146e8283b505e79bd5f7d07cabb715d81a3d0ddb66f7b064d98f272208326ccfbd65aeb4384ed037f9ca76bc43e1b6ea056bdf52047c98576d2a8597ec952324bc972b214414ab9b93f3333f3d87339195358e73e4858023f5de692b0948653ea7308a45ff5db5f1546b9f06b18d99fcc9bb59cab371dbbb95bf701d46250102f2e2f5e9ef5f588e7eec93ee3e45bbf5b8256c795054341c19793fe7cb9c30feb381950557eb785fe358a2c9d2f43b75115a3f4729d6b51da67c8ce75bd0fe14be3fd6512ef1001bf5c4ec45f40327ec633c778e69c67066512e3f0a7014a24504669d145c03c33c2517279c5084729c4f5d70947574e0823c409ad75adb89a18c67268b3b0fc74869c5c3cbe61431ad1b8884c02f3ba7a661f01b0e8ef7ddffa1eceb76f81412c0178a1d8c3535cebe9790e5ddcef5bfc3b90c2ce7f4fbaf8b9c93d3ff73605565e8e8774ab70e747f7f541e8c25538f26f40de4ea803b9e70a7e9cf71b38c57b9d7e790fde689e6bfd356b306939b1dc399464a625b924979268605aec7fa239cd69fe92b0db6896e4d2683d944a5e2305e950be0473bfa4d23edcf707dd7cdde8ec64ec260ce2daf5327cb0fb207fd5ee168ac19ea060abb7fe9247368869fc5d00f9ddd6348566195143b8bb872c841725f524c60bad89cb1526252a5190a6a8c8d4a0a29c9ab80dd40866b03cc80050c508f541c70d19ec4f8f16eeee38cceab2e17a19f2bbc0e7d0868c31b67bcae666d7e6da5c2e39bfe50c02f4f3c3850b171e445177145d722ba2bab2c49a28312c33d07400f1f00114b055b8e4c60d503021ab62d4c40958957effeaaf1c231518014543115670817912d117221078a15a010de6310ce1440b2a0002052a70df0d8b09d250819aad914aea64ed231d8bf6612d6b9eeeab3ba32b9f86b33476e075d1b88d73bb5f86dcd7a3c31d0f8bc82af07ec1620716a7f4d7ead4a9a6d2fdaae97b619dea6234ec6254758a2ab5cf54176b1f6ea516975ab4b29e5bf8f598b615d5a26411b558a306db4aed23252b1ce9b7c00f64c96255ac7fa502a7b07e822ca266c5da87be7c16d8549a1573964c498ded62619d6ab135b3632baa15d53e3b2e1b756aec64379a36eb819a53e21dfe7c31c0c1e65c2ea28922ae09f28e9c522b79ac6200023bb6d2c829d13356032adbfa0dd0d8b14e6d10b335a8528d9115e3942655baf23f247f713225eee8ca1fbfa52b3fa62bbf46019258897465ada82bbf226257be9525d99193c9fc85f3b24ad5ca3c96204a3160673ec3bade19f6d4ec8004b6bf93daa743c9d4f2700aeb815a89a5c40aeb14a754a738261d9c524f0fce92d739495eb549d8fa2cd78fe5d2b2125a2e768bdd0244e4f18d9183baf3d348562f4903d0b06932c7fcf9ed03eff0b09b48c1d2f7fac28861e0c53a7db2341c19aa979cc7359be63cf3aba5cd2eec9af3cce79eeeec69c2f6d7d0b438394a39fadcc655ae7295e3e8acb5387f9b5339d0d8da9c3b73ce71d6ee9ccf417153ba780eb999b9796edcc66ddcb6f156a7ed208de50fc093e56dfe56abf4e4e4386ec61d49ee890bc23c521ec99984d2a2dc5ede2963475a9492e8693eb1ac31a8eaec5ce0bf516277786acc1d3f0d147f9d838de51b523675e5dbf679970d69c30f35530390b2fcde063a587f29bf9b78475f07798cdd794078c2dc79407702fdee19c65f7f863b40e6f6d38350ee3ddc01e248e87b178ace63c57a0e4e50047b7e8036864d9061eeaa01a5a90cd31d9ba6636d437545bafd9ef4ea847778a8e54a7ffed12f3ff7c4c441c13b64d841308efee6dbb2319f63e47c727f6e8a7178c13cfd2d1b733bc9ed97dc93f37c378717763ef98b6b729efef9c43579b4277f414903f8f75727dc0af8d55bb8cea4013ceca69019c7b85af5f40840001860b0b3939323313081f51fb9a6d175594f7664a9a6db2fa6c5213ba15a7c6a41b13bae266b2f3311050bb75f724fced3dbb715efd84c4ffe6a26e7e9af341cab65e29eaec3b6b09f9ca767aa7f9c4f524fb7a7092bbf2235e99e0d921749deeeededdedd6ab55aadbc6738428e34ce8594cbaa75031dece84744fcc5fa9ef542b09b23fe6abdf74230fb4230f97ec43bfa08112b76e49acb3a8ffc015c91038d1d19eafb2f44227edffa8f05b27680787fe342d1113198f74230d600aab0e3fff4388ffc0e4660c71e1f1874b12337b9b8acc67c61a3c57525b034dd916b4c7e6500454b0e24288af5257f71171e60f29da97de47b96f6e1ae0481af8e2acbdd1d7f2d3664b9fc81c05d576a5176e1e17a1447f2a416650f3f6a71c8fe955fcea4704719cba1c6cee90911b201cb06a0dfdd77230869634910b2024da85f0485d85d75947e3dbaeb9c73e88cb0ea6f498ca5d3dddddd3d69adb3ce3aeb9c3d9148223568d490995a9a52f21c8c0aa28a1873e5f2d7c3c33a25350515e58e3c05e5ca472265463743f6480662ac0946ecf52caee01c72c60f96b57481e68e2e15259f6f1733a75273e58e2ea586ca95ef64daa7a8985bcaeed1b63f10e6fba7a3cad27710fc52facc38e6d3903b2c767a38762369517e7da0f6a8f6e910aa7d6acd4165479eea701c10a5c46e9f838de50240c5dd31d05277887f87637dfa9e9f70d4521fb4ae4b25b13556efb05528c4799abe83f5479eea516b448c801b8e03a2aeb0052c6bf142eab2162fa0ae7c242ee5f506f67352e30947d7a5c0ee3fa0713b21ce337bb850582ba1a5c8f8ab03b27e471887f49a4bb528ff63b2a390d44dccf2c77260a85c477f88f48c20063d906bc92209cdae5cb19e931b47eb5bd0c53eb76df2e9cb8d6e9259bf052111827dad1f6b502be8db79008c6ffdcef6f237efbd0f3cc11fc9cdce03fc5bdf0a19c66a8127dc00b9790fabf3d4bbeae72f02386f6180d579b897b547d0172211827def6d1beb83aaf3480efa80f8b72a1018df0a91dc3c8cb03a0ffdd1fd0604e76d0c2702feadb7808b1dabfcc013beb7ef09c9150a387f332fdd444a2bf7b4886f9bdfeeb72e2c226b384a8e03b9b9cd184e58a5dffad7809b7007c817ee3ca0f5feadfa81adef0fc8f7adef817ca3a0119f5db392eaf7bccd23447484d81182d4a0e9e3d69ba7df0335f74cb97f2ebc790b84b063a5bfbde436ae72ac258dd1bd794e3e077e3da4f4af876c85a3d06d3d07eefcb0bffd0ef75cfd71b5f3a332d5bd796e0387ac565fc3d9e2b67ddf02fb7b9e94cc366f9e0baf63f127b57041a5050d997bc380efb7afa3ac5f0f19c2f7db03f51742ebb7705c7d6ba4dd618001fef52d30c28e555e7048ebbb9f5f09fdab6f3d078ecfb2a1c3da46bb6df4b722dc463790efe75555a37394db9a6b0cf477a17f1f6ce14e085cb8f3a3be7be3bc5b0db7979c91b69f64c55023862c1cf8f001d4e4a3d65a7d00f16802e2e10388870f79449d9569b38db37497d25dba4bf7210a054487b5d66e340848902020415c02524a295768824a29a594533cbe31c57be23d90356591652d5ad0eefcbf9eec29476a2a8ff9912b3915bfd2af19504e1475e5bbcca1c8a66a51c6a65a94376ab0634f5d39e5b1e68203565c01668d105b54b125863376881528a1a245a52b71a2c1249504d1f2999b13a651e982c9134e3c9121c184e18895344ed470683302a6f9829218585c4910058b12496ad6b030a12891ddb460835ccec305cd077ec26989232d94a4bcf0329f6c51a2649b459469439db00f6089154e30540598232749cad8eef76cb4cf9c377e86366cfbcce962efd60ced0ad679a094f2130738810d391ca93113049926f475fc504aa9d74aaabcc31b890829bacc5e08b3048a2c9ecc9914dd1313c0a02e687024c56989194cc0a60817b2dc74f885851c9ca84266892fb3851fb8762299e8e0d127494440fb659439e7ecaeebc2ae5b385a1a4a77274157213bc2882b64a290010a264d3cdac439ca09055ed6d87046cb10462b70667a92e0219b7a010c132d4bcc4c169224e9da49c7aa2cc142658531544eb0b9029a6f87a44fca704f29a594524aa907599a82e0824492279a8051152ea594524aab0e16db3fdab83abc8376173e6527f8dc0e218015ac70822ea868e9c10bd84cc189305fb091a228894bcc045e3b99928522563e73631ca04cf1214c973654cc5094854a913506112a185521c5cc89159660a1592c2389c2a585262e9234b182a887eee739adbb134a2c4102043740bd1055c5900d394fa058347ca9a18cd2136698288981fb49b375123d9c846a0461ca30c981851f66922db1211d9171c8a04201fb93282db448b1028c1398196bb3cd1f323f3d45efa8ea02e60b0d8a1665aaaad254273db236510111290062080b2a947c71054bc6161346448f7340822a555a9a98e1c2429b2a315f076460ee5de40e9a0e48cc906ce0a18aaaca8b950184955183d12a658ed89eb49525684c9420f64312166ceefce72e55586e9cadc021091a155c8cda04b1a6ca4a4dea090ca5400567c898a0062b5ed0a083802a1560d0266d9d78e9e243d3942ca2a6aa564e325083c2c8051e9048e20b3577fe7b1935d52bd0a5c6860627ba3c99d245988d86a02150c508881e6a59ac400b4ff385961833d9c3955663f9c20aa54ea068511475441651303ca1f9624a6d29424555c28ce182091f5450c2b9f882c8a33ddf35ff25d39ad5f6a4f90c12558c9081082956b50554ebc9b7b7d684a9624a0d4458a1428b25e68ca1ed2513a11ab644e1044d1924ae58521302c66d58f38e221a014f706813851a154ec0c2191fbae5acc692051a5a5400d305549b12b031b303d733488d1d6d50ed298877f0e859050b189668218d175bac81cd3277bab084e8872e5176488a0136c9207949d89e908336767471d0405d04dda087ed04963639c9ec8febc7c5b936ea4c3e27bbbbcb8072da7577779f6ce386d5a1cd24e41834dc0d9415519c58fa48bafe22681943268b3b32980da8b0233f6df4fd3798c2b6e8a328765e9d5b85413a77ce372af3a74f2e277f107f09c4b8fe5206a55f39342d6d66d77db274ff225e97d3d1a54da9a4316220d1aa65e9205551bbf3c1777d308ef9ab2bde0e88b0bdfaed837441dcfb20e23cf33790132f7f3b0dd8be3e90edebf709dc77bf024fa8d22110eebb70a74fd8be863b1d06c12898f91d1844e30b4b9fe84783a5b43b5fec442ff4616be80ac2b2124d50dd919db68f8323dbfd73caa9bbe5fb1021e8c80ba70684cd911835998aca16e718a93beae009d5bd454d769f733233b3e419e5a66b3758e9b700de289ded459779bbfc0df26c6219ac183a393070ec4dab67b064d4d6c7f2565df5195f0893c17e6a302db29c1df22b2d3135556f59cffa0889abc5b6af87cf39674d800c89d65aa766fd0b18caa7acb53afb5b77f95ff71a030833563a27db9835cc4072eeee93a3dcc671ed5bd39eedee19dc9983c7bca399673061d56ee798c95cfe464375f967e8445d7b69302da6a3b8eee911454f003f1934544dc4790123266ae3a85cfe2b553ac7715c68745b124d212d72731c94cb512e3ff5a4cb6e24a59424b4c82f638c95928316b9bbbb5d3b3fee88020c25a6ecee6e29657777cbeeee39635b73ddb8d093dcc68526cc4b85584929e55c8554ae6449da684b972ebf735a6d475bba74a72b4aa9fface66a257f25dd12396de9d2a56c2f9587afea6ab55a8523fdd97577d565e8f726856dce16a791bed2485ff9fd84598a0ce69c73eb2bbbdda5cb6a5df4cef60fe6edb07e61e44dde41011083f28b33e057ebb9fbb100970f70998db8ccfcc465293e90d2df40df9ec34b2970fd63c0dff985b04d9673b6b850320e4ae7106eda9a36f16afb7c358605802b83c72116e00097c3d15f76ff7c3a19874fbfbbbb14a61b27ece4e532952b5992b6366a281da58928ad950c1aaa28e6995eb9d65aa5918412e5f24b222783868a84e621a7d35aabbb3b4b674ef71b159c37e698c3917ea5949bdb9c7352caee54b20ef3f05329a5942c49a170e138670dc7ea944afadb7bb47f9c736e28c8ee2c6e3696ddac5cb970745df60d344299524a299d4f277b13b5beceec5651d85964e5773d228650c35f41617ba965b774972e25925b2347182b7ff5f23de01dfeaa60105b1086f5d3a383fb7ac84929a51dc7753bb37bca715cd7e35f0ffaae1bccbd7cf60224b1fe3bf4a7dc9c7a4b6fe92dbd654b29a5cc80c9fa338ffc4ec746dfb8cd38e437795578f31d1cbba022095bfd0a64310edade23118279ef75ff1023f316a93ff26fc0ef140f785f90170e09c560434850a822628a336ad8b4a98279bf4408e6854b58bf0ac322f5e96f44ee164ef19e05a220634d483319919224b021ae82c968c0bc5005ef97a0b04408b67acff3bee807e63d0a5eb85aad566f8114ebdf4b50c0414415396839c304089e846455101111c97e60de0ff91731984ce4a8623198cc05f37ee8662a168bc16415e63dd1d0cafb2111c90b51109a1246c99a1d68d021491330a2ba45e98b241811d1d005b50a5bfd5002a05cb0d5130d71555391085b7dd14fcccca262df7ef2749ad35d937264443a57375896f428bc5aeb98525db24caea67712693d4f975952363b1a25d28a99198ac7e7d1ba9078ce3959f393dc0b1eb30fddb6e9328a8e2757aeb34bda5a766ffcb4d2aedbf869edaebbbbfb19765de71d333b1934542474775dd8ddee3c24b3bbbb4f1f6f796146923539d5b1cb724932c926e9246931e791b323242429aef1948c597e621aff5cee69fe5e629a1c823f436faa178463b516840c80906d84e3ef841e8e3d34c2f1e77a758563b533c2d1ca084797d718e15875c29c100a46d804355a28a87a138eb5157e61c7905c8e149bb1199b3177f7a6ef69e2a62e1cc51a8e3d3f488ee4481ef398c7a0a0a0a02652add6363d3b235124d757eb426a71de71224da409ca1ca997d2dd5dfed859e4732fd5ea944ad29c735a1a268bf6d91e5975382dbbea5637f6266c7de19c82f31ac87056dd94ac5b75329c38385fe0bc831ac8706490dd342745dfc0d1e0932ca5e4592d6ff040cd93e52dd5491b3cf795f681f1fccdd43e599ada4783e76f2eed93c1f3b753fbdc78fef6d2621aaaa39ad62f1751bfaa918572f96554bf2a198be6caa47e552a52579ab991c454230be592d02f59c958344e542e312c25f340a643a6546533663237027dd6620d5d96c6ce16fb5dd643f4573b89566c0c7eac2128e47fac17fc682df8d105801fdfc68fe2ce8f3d97a5dca95a97729efe6aa792f3f4cb26558bb516c94c342d4e510d409a01486520356ab11f07a433257f4d27e7e9a74a4ea3dc9e52764a6120154a81b20fc77a41385a0bc2d10580707c1be128ee84638fcb9cbc1a4e349cee2a1c5dd7a55ce10c975a4d998c70ac752ae92829ddfee9b4b1604c279cd043d6db66fd4db3bed59d24a6f5dc44ad703c81ea655494eb2f5949ac7044410c110a541c1585b964b9c11a4857159e0d969db31a99b35a164be9eeee5e7dcc7477f6ba6d1cc7715cebf85e4ee736fe1b22072cb69e57ef6dfef560fdf7c3ef275be1d7faef6f5ae16cf1036f78a11653ba9516abbb0abb9fab1eab6e0b3924eca663a7d8775083220bde689ed7c1ca58ec7a68a3c5a25673683cbe3176352676a4506e277d2725b55447855deb31c3850e4ad7cdd4748d429968fa45e9a47482e917ad626cd484d2af6d369b516649332ab7e795db33cbe4727b9c5ed0f46ba3d1a86893886674fb1d4cbfb62ae64691b9cdd52c96cbcccb6d6ec979fa2b073a96a8dcfe46d32f8e1ef9ab83d23cfdaeb16bb5f66e86a4a33476b3a5ee0ad36d1dd4a99b1959f96337bbddd12aadcdfcd5cd66dd6cd6cd5eece9f16d46f357add568355a8d76fbb79abf2acd79fa6935da569bf9ab2e2dcd96664bb3dbcf2df9abce664b4b348ee62faee63c4d6994465d2e6b395a477375b48ed6cdfce7a7a74714ff5dae6e36e7acd56a351a8d465b5a5a5aaab3d9acce6e733577b998abdd7eef6a9d945134a72d2aa1e7ce8f59a90110195861e52b7d415564a568563427b3ff9ccc25341a4fc70f43f55cef3beebaae63fe6ee53dcf3c4695f54079d491b1accab560e567251479246753581bb318bdc2f349ff03796d48b9bd8df6e9b9b15aedd3a22c7623076ef7b5ec6eb5c2c9383cef0bc70fdcee59f43c24b7ebc2c96ddd5d1cddbc60e5bbd46556adb5d65a2fa8b6b9982e65ed9f55ca8a739946e73dc3ca381c0720544caef0a209095868327d30734435f3e568dbb66d6b800f4d358480c90c0886983d98b1e28b90a06688e08c78e205a31c365a78cc3e733ab7dcfe029f397d2680ad8c924e1627dbb66d5b992f1d519db587299e243134e50b125073e9882bdd154d92b0ccec4064868905445b983ac50af4a99911b090086228095dc31d110ba3e4ffff460a5277fc9e4f0492d987a5e4d9b327cf4df23b13ef8e76dbb629a5b685d7068ab53a34427047fb32565e6bc6d7126aabc5baadd657b088cf78a0a63e3e592f19cf6fe3bde7ffe9d70c18393a31deeab0885363d7282408bfde2d68754ab8372c4b4407ac2c2339e06411c7e2dcbc7c1820b388f3f25b805ffbdc3e1c8e48eecd4d38672b2cfa58a08f163b0402d3581e3e589c0d96d54306c8636371fb7c3404c2c24db5d65a6baddcd699b1365c57a7bb1e3cfeb1f3fa8c19e67b2fe5b394f2b92bdff90b8113e2ee04c77e0d085d69a42fdd7e30984bc39d1f3de4b2971496c47081b7c899ed8042cb10496ef092041a2b4558d46dc6e5029fe9a49958b30ec63c41d1224605158480872225fb33ac406489216614c590104c72a8521402da529a73ba12822a15c8b23051297aa1e584cf6451810f3f7051827261872226b59b7092182b9820620b1e8c7862ea20053700162c103b5145b5b80ca166dbb6add665674b114d86eaac12cb192cba335cc8eac42133a36ad344a6450a660e67d8e4d45a8081524aa9cf103de8f0c30d4b2091c554aa25e5d4b0381142c51341a490e5882f4773ca19256ece88694106029dcb5b642d744870146cd274f1830d35f0602465c9190b9e9879428211ec606609a9852982252b603df9a425b41c30466f789e5e45061a84a04226b543088e58b9649461b2f2a5cbd30f52a6e08106822553749e54b9a4898c0aa559786269167b82c50a163878e17ad2b206053039c126071cba78b10352540c26445d76a6133944d483cb09910d392ebb9b58c94ea6a81da18594238080e1062ee69cb3461296efbcfd339f36dcf92fa3c2520ccc50022d4c65b068920446670d972a3143c40ab21234a5604d94a1a78e82f4e9f6f5b6ab41d29284d2941254340c7d5975a165ce89e48513a927589431028a19868ea83b247512da70660829696a35c8305404dd21a9ed11b4dc1ea5d982821c5ca87a4a22651e0d4599c14cb60cb5d0a24d9454ddf02ba186a8942d18f538cad0d808000000019315000028100a0544229168344c6459f40114800e6e90467a5c2e15c8a320087214859031c000420020001042666686a62800a065093dbf6c504496aa7ddb404fff664ab1060d8e68a73476cca6ed2024646232ca16e72b5cae526abf39f664b3f6501b51220d29896a1c7917971a598a8bdf6149c9eae39135a8054f6aa4b2d2a44968f119f4b1558bf43f21741db85b2587145fb623740d14e974fdb37067c4e55d115e45277b1327be339cdda378dc1706440ead81da87e513ca87adc32e68692ffc3ecbaa548e0772080ac324bfe3d7dfb46fb673a36d93913303aa827844d94d8ca129ab2e517f57b21215f57df0997e516ccd05f36ba74760d61afad47d15d5fb70032dec4bc712658790e5a18fe233aaf7235271e429e2aba44a2dddf0652a33a467c7a1f7419caa98936881152a439e592f2843710091c18d892ce30cded80f7f2a2e6c89bc5b53aed1aa7ce5647870ac9418a027c8269e48c16f60a3221c24094c1fb3508009d610cd4423e638d04602bfa72999722eb78a9885e3426abcf2ac779153025321cedca34b2b6ea542c8f4d0a33559e6c9569d49b11caa14e2df02984b210e23c52ff20b402a76a30eb380facde81aad14c86be08827846f868a386952fc6a29b20c01634cc59c755a3ea81009c65ea4f9805090c917a1fe7d7138f609f1d2c0f9d0c4ad89aaf4231e636091165f105e4f39087c0a338d9e01fc4fe365ee729b9bd4fc98e50750657557dbcc4f68fcf18bc24b35be2a21e608d6410a0adb27f350de37a14aa5f5e8585bd83d8e56f5ecc5fd401b5772f161c45a7957ba4a0553b1b440d486adb1d095fcd27c350ae726de169984d78ffc561f4ceec2575904358d1846d2503950009427ea931c76f3c9df2a3811eff245df237df6b9f14cafc7b55baad2792be93b88c385c4b81edafa40b6e139be65a7f5b7d8cb04570951e166b5405cab1c6a7c4c3345ff2dfdf03370cfa9e1dd15e80bbdf81e459f24c2346334bdb2a0e797c4c794fd4e3ed737d4d4001d1f40467a15ef4e53e050a5ddab8d277269c8c189d544de76cc31f4d9e1744d1d670af7636f2415cfd398a0323fc7de3f3c27154a24aca7ccf33eb2767800eb54f7fca9e84e67b1420ce7ac0d2ca3f8561db1d79dc24e7985bc2010e4adfe55f12dd1759cde71e505c27aeed68cf3c492796f8bdbc2371c0ea5b670a936ae89334f31d2a1e5513fb79a2d989fe972fc9a186232ff36ea5e536e87436cbceda0a463bde6d3fd2256138d81677e6384178dd6ed12465d3d9f2ee6f698a62b31b33b88d70db67fceafb83f84894a8a42bf060c3ec78f69f889a2791a261e990e078747bb260cc2b0a64f264825f78f92f36da8990b99e6268f31967f358f2ab1ed9b03d8e3b05e2a75280db2acfc999d5033df7339c0c6f937ea29d04213f927097708eaeec3d22a17ab7d580a7984022855e49a4194acd4eff7ff372d4b5e3371b85224107bcfff78cd8ea228b945c79fb0718fd42e47a8c7fc1a5898e67b29cfb87ef0e29a0cce1d35c6ab3e47c181e2fbcb3072407fd055fabea29fd6838f94de4b9c56547b4f910802421db18b66c874d1d2c8aa40dbb7725ed6b5c7e0998b44bbc9f30b68ed0630e544a7c43e0ad4924fbb0649e6bbf213e77f052913598ef443b884944583668554f58805ce335154c2b0f9f4dcf29521f94eca229ec2fcaf2979698492c116ed33c3a71e1d66d81cb9bf55c5a7fc814d642f63816b858861c953394ca605869f9c8101e1b6276e68c3d137350a0a0c034e60b0c8a57425742534280203f22282e9770e04270dd721d6ac24f5b4767a3114b520c8599defa88fc0b082db03c76da5dc2114fef67d139f15fae1425f7e097685b50efd4af36b773f5227bbba5351a45551464e23bce1c4d8139b5a3c792e2f8fddc88e20c1eeac58160b52f147aa62f652ecb545db0bd82011a1c8209216ef27ef95ea67dfd96fbef1b1962415fd805c83627cc6ad24d147c155bd6840eb896664c873bec27fe360367b34d7804c7a0e3714c809048739b929dd9c1852d11c882cebb0e58e3b6b7160676816794e4181c966250318881fcdeba17302b7fa9415e2d24b1cd07f619d422b527d76b235860dac82a3670af26d9c5ccb993c2d3595ce6a42374bd11b04042b0f6cd4c0af45369d88fd473f725903af10baeaed4d78651767714791a924da4541c1901f242f7974686860910da5e5015c4f6a0505aed81446b6aa93c45d6c741e185689ef245c505255240c5416ff1b0031d0f6a36b94fd0556df128920a1f4d7a2fac4158e6bf4652bdedc8b002c8f70e44f2e83cd11e13cbd59a49775df661fd4e6b3482e511da432d16f5681c609da701c989e853a9d4c9d1f8b79fa8939a6fc2fda568da02cd381d47aa70eb12ea02e669898a3ee2be20c30e60306b536b6a8f215269ed4cd705b330426133ddc90d00991a6f9a8e981ff2a9c168aba817f725b6c8ddcbc03572d4f458e123963594a382b1326ef0fef325ff407aec894644d1770577a3660408797277a72b2e234e3b054da1aadac966e54414369dec98e29cded083dad1ee720ebcf7c7072dfffdd41e5a16d41f4f81861e636954f738f970f690159a9e5b38c16297e9867acbfc30572f43a571282d771a8b08e63acbbacb38e063e757904d8984bc9ee7a357e3ab3b94b9938699562670267be5c1fcb17b56401fc0403a8a0b94c322b283cd5595f135d8628bd8cb040c8e1db824b81f99a494305b01c1fae5686ee21ffa014d50519330383e06ec6f29e5e256ba62abe511269e31415143545515244c90eea3ea24851494679155dc440105224ea8a314a5e673465f0eb64521bf16f23edd24ef6b339e5cac99ba55f99f2b89118620ee9874e73483b30d41351e81cd277c959e897c924fdb94bd1964d480935d5cff66e56503ba23f359b52c1a710b3112b25feb320fc76f904823f23c52b08d91cfe3cb5150a77b55112e00d0ca9423c9d716de94220c403548e6b3eb9cec53f453143973d127348bee6b28cd1111040b91c6de30878f51fb64f50dfc5f55d58c5cd3f48dd2fb28009bc944ca7328bf9392b030f2a87f4c88279e5e5b9055906399c23cb27d9e8f624205a5ca3bba5b2b1c1ab7931a1c852bfde5334b6235f35376d67fddcd74ed798e8de81298b4d256cd64473b3e9cfe15dff217e3d1e5f0601c90abca48ec41758f0100b9544e09b54d893c3445358356b21ac8376c6f6776728a13bf1d13557e44c6ca519babcf7ecec45be63fc524ca6d48f05c21c40ff57a97aa4a90f81c7faa489402da6db3ff69b313ab804121170a8281028b78e18593af0542ee5794a2369459c144c20c803bbe493699a13f6180436de47054c2500d5ef801bf434b5d7eb44f9f128727565ac2e882213995a939498ea4d1629ab10837c18e020eda17ef90352dcdf942501b5c177b28d36e420e2a7a6412bb3d848e58e1349f847476353ae28a744a5b040288797abde9abec0a03333c780c5d13b81cde57e2e8b19d912ed535110c7aa72a614498ca969a5bd8531a02f031544f542e7f2d213323dee6913fdd64d7b5da11455a69052a4f36a0404a638458c41fc6d696ddca7795d99f412c7c2efceaf38223eaaf5f6007856d6f5d0c00bc93d046e0ed1a009485e9e06daffc55349451928d83656f8746e2a43b1782750aa293a86fd53bdc0918e1b75c6d5ffaedd7d6f55b8d3b1607ec9d50d492b869abb416438c91319651e699e5ed710ae6ce461e7b7c78597830fce2c4b31048e6b5358b0895d50397fc2acadc67a7a0e6f6ab947a8fc92b2b53ca35575eb5ab28bae1f4140152466779fc0d1e9dface6919fd554fa2b6538b857cda5c03fc62e30d6dc381b94200194a49f58c5bf71c817be00e09ba0900581615f7a427f67df259a53ec2df5f30d6dff18867e5136d1d502120190cd5345242fd4089938008e582bb78c9b107e34a1f3dd9e13c6fc98282332a183f13b152a86b5043d676059eaef05d42d024dd8a345e74651a9a8eb17b7af5de6357cbd199a0986cd7af543c0af938e406192e7f9c4d2d797f5bfac88f478b67382e452e7c893741754dfbc85bd37acb62d8af1397c7b7b62ffa65617dd62bc5628eda850beb702e46c149ceb670a58de59b83b6aa0a3f111668e193e5f2527fa48cc1be7ca19be08c82ec02ac816c096f0b67f30e3dcdb83923867b7c5e71c823ea8f87229c4bdbfdab1b781f7af3df637707fb467df4a0174b78d0a29b8deec4e819aaa958544a7ee28acf486e649a26026934330cc2f9c27c090632d271913e2209a474ed7e31fb1f88f9c3efa058d1bb1dcdaa8bc1b0a94d30f8ca5d4643a0cb7c9daba4131324ea917c8ebed05026f671c0ec55c22f3cc0536bf878f06ad2b0fcfdfa8b52f1aed249acddda836e2161d68f4fdd14efba11ac89f75537a191d74992e19eee045c705adda4dcbb09c4c086932458f4feae4e6ca1a8b53e01c9fa8c1211a0535fd9121164e6e3d097d2512f8869279a6be29bb220f59578e35a545cafd31657a2e90e2a3e6173fe1050796c9be751f87f0d7cbb92877bcdc7bb21a3e81a2b4449b916810795804b70c1ee835d29de063e3c11d76f7496856c69abf6b08d88cdf8dba5d75282e4253d21e5f6727533bbeb0674c4dad10ae43d643fe3c7a3756815d21d76763fbebeb57a676c7deb32a701ee91b649a738f1ea7e98502c0c0a7aea68a9ad25c9328ab968b7ab8766400234296ec21f2705327d94cf0dbecfa922e55434ced87e18eb673bf8875bc402835f59c40f87218dd88cfd6d4f1d6019502149dd6e312a1c12b52ad406a150c425e7d4ac0c4bdfeab516cb5db4a615952e90efff8c0a95fe5e2f567101dd081b3b9909cb9dcc913df642d291869d2b7f2d227a211a1399328722c64ad260c3a1cc309d3d859340e9e442c7a89c30d9867f46aafd4947ed8a830345d62945c02253e051aa2087c2c2addee5235368ca20809611e5474e1b77c635214bae3ee3099c3cf381c9f5a31acfdd66d1fe938aa931ef3f0e6c9638541973712352262945234aadba2cf7871d97d74e705b03bfb2d1e98c92a7477a1d82b9e469439e537d65c2471b20d389b977f95cfcbcffab0ca650b79dab1c4c036aa132e47db89809ca78c8db9f2bc5bdb93092820728e52db84cec26e434cd03ac3ac022c4457b4b7582139ff1692eaf0036fec2a20718f855c64d401f8f26cd85701dee53e5c47fd9e553135a3387ef64d523027a4b3ab21184287a38f184287b991f43a5d233a6e9a6aff4d54fb8ebad91a8297c273a013a30ba32a26ecffe9fe4819fd9d07faf0eafc5272684da6db9fbd3a7f760cff0b62a3754ac8f86f7753cdb5f0bf443caa432fc403d727f423965cb3f927c12905b8a324d47f5f62f6604b3e4bd5d46fff22a8a78f0c841a39531c770c82b019eb7541eae96cf570baaed7501fc7ac126a217aeccdc5aa3fe1213d4a0ebb8bce5c9b4c07621585fed13e07f51904b6f16331d97509d019436c090fd02320bf2f2e4f823437a88886a991775bae47c505c426b7990182c23928833aa10c28a965a6ce88d0e79aeb164d0a10fe1889868a0643afc945b4f5b0f1ed249ea0cebc915f69354130bbb0fe770e089a5479716e32da2c1a50388747b2511b28721a3c2f288a9a553d127726a3d11d6b1ca607c2ee3e6ceb01638cf6f885d998d4dced1c2763b722f58eaf14a444b6ba3766fdeb46b3929485e62df897559a4297461d00c1ab184eef05fc64463b64e7b04bf563186abf5b08deec51881483faf549b64ea429c99bbdc3c181a086f7e495d741779ece2da2e4cd9555276f42b79d0728e5cd3253645ce74d59a5a8cb06370c3e480aad45fff1efe43abc495823fd841de39936bdb327b199b93662d65e2c3ed426ad838fc45bb6026d4b7e7333da1c4d12938130d1444c8ed435c96beb6b926da81278d07a3d186694a2515b20e9b8de574f4194fe8e2b9f3d46f63fac16518f24d421659723c57b4658db8673734f0cc2507e0141864e0dd143304b87d146c26ff54d9f7462e2b8aaddaa0d82783a4dbae1579bfd193a874bf5ed63ef38dc034b5a4bee5fc2683597d00a8c119c7ddb2841da7da13e506485c82be5120c794fbb205cc2299bc32be0a730d6c7aea321893bf25d652064d4575b872a41fe77d641244b610ef5144244ea0c3898fd232e118f912f04f7541921c3cd0fcc9139f03947f8d36aba1632d52c3147730420d100921c1c80e6bbf016285cae4522d163c51137d7789e1846cdd453ced01581cab226804f2156d3ff671ef1a38fc02620fa26ba1be00ba05be203a5ed3e71b271beaa3b9615730c97737cffc14bdfd255ec13911bf4625f05f60b3ade365d8c31397aaefa9c1b8666e7a3d77531a98f1f0681627d98de82ad95b24262a9532b1a17f85856542fbc90b8e21cf2b5eaf77fc2c1c676b81d9e8a5d8272c87c0cc032868432c3b2f02acc5f04db773942cd77aa971f60499f7bde6451271150689957b52141f7cced7163e919219533970c0c40a7f0b13330bbd35b72c41cbac2f9aa8e7c2b28498309c3939c28bbb140d9f7bfae812240e04052e1c8d40d49bbb866d5601161e789c515a53bf160dce1f86fa02116dbd3963ae3552e5fa811b506564517f93243b7476373c9b40e2549b333899c8b66508d5e4e192b22f30877f5e91179e4fb61e198ea98fdf1225e43d865f5f9cac666ab4903dafeb8a48135100f462a878090cff895daa9e89da47dc603849e357bafc21a7bd2881dec5820366b97b823b9b9e54c8f45cac662d8f3aefcc9323a4f9cc9c4845c0d76da07e431b6cac3bde5146f2ade50b2c72c53f59bd2b323ab47ae4b21f5956e9aa4db07a0e824036a6d5ba9382e448d99ede78883b5c47d6ee89a540e9a518dbc73ac84fbbe89f1c7b41ae58acec27930c913054b2c0ebab033355fcbef42e26f85b64f41208051176a0743994fdda0738f5b6a8b698591f12e4dff18d8f78f623406d7b0b74e5dd62bae8885a02533a49847e23fb8803247731fb41c4da084d88596257193a48b023edd10ba81ab58905ca9ce95a80a57432874d3bb920834a957e83c578e0090d50e70a291677d42441f9334035d6327c163471e03c667d4140567f342b6d1e40fd937d1632532b885ac7cc4bd90e2f8ac14d8f7889a3c027730ba369015207537b863a40de12b4196dc615e02f4c3a274022626f694c9b8a2c0228acdb5c65778bb9baba8fb172d2883a9861b6f3f6104441813f06e17852b8cabc19ae28fbdd9aaae263148b4800c99e9fb83c583191a7f545a67bb3c17c2626a5723a3611829e08e60035c45baaf8c86163668ad0b435f62da346b37774b438fd3573d17834aef4fe8383fa60042c418b5a62082959115588fa7d16310c8457cced8b1156a556799c00646e4049b0c46720e44e1446328ac76d4df84acfbc0a729b1bfcf380c65cb1d37e4c005b6986a63c8a661e040dc1054cf8a0d4ba29262c8197d9d50f71f900d1a96d94bdb56f0c9e025f32f1fc4bf06bae929ada326dc5c313137780cf00a4a0b8721caa6470a9962291b308e8f99e3777af824e2de7cd20a7e2a716a58bb8eef172d51e570856d9f66a5bf15a80fd4b11a35b07799f8471558cbba42f18b4766a6ea73fdc241d2a98533622bfa284ca6baa2b2c1d9492052e1dcd6dad17236ac157c167871d76456fcf274805634393a34c5b2d6dfecf49c5f9c5b6533a538568cd4dfb5be14446841b7ac5ba51ea5cb9fa47293406002116307b20de5c9543d142be9113be570a1f28e976acaa1be9d5f9caea408fe7a7d3a9417fc5f62a02933d7382a9b6910cf7b55ea85479507daba4eea2d90e78b78db939c285cb280496444a713584ca79ff9b40ba0db389624bb382b9f0f9a968e3b72050c3b746a31ed70326fe9de0d6c4cda5caeb5803cb7bbf294e06bb907930e3e1832d932a2da98b29a7130cb61c2d0d0033e03a56392ec53ef8d509a9129fa9e2a9d2e4b4394c6ed26bc6d488754d59a6a8b119b8e35d27b586111b555690731f9bccce207ea69eb884ab73b1b8cdca07e09a6f00a3ba7576e63b6efd5f83795aa4735c34baae27e615a81a2578e80b9d2fd23f4427238b34eda88ba7bcf32c3c3757d5b0c919c0ef3936d2918b492c577bc0860a4ff718c54d9493ccbe24bb69b1c6a832943a43df9367e2e08cd6ecbe18b04f032380f0eaf37a99a017b603048ce63f070b1c9f3d57a10cdb712dd571df5d825551a2ace482a75031ed10246e55f5aded649fec41b984010e78b55780a27c763551668eee2cb87aa44edf8c13763f44315a16247d840a4611b7883863f0f01157952df07a92feec012fdbd56455d7806d8b431ec284fe18d4097ab625f583fcc7412d9cea5a18919024f626131e7e391e3ed8656976637afcb74cb4b6f1845c0cf59e63298b915d013f0af616dd3f485cb6794d065f0c849c734d5dc1c67daebd5553ea009d1d2586e8b2dc6162ff09c4fa369595427a27bd9098f2d33889700f14ecca7fbf489d4ce93df5c77344b5f95951082f854f8aa79a02751a63fd906c8f31e7e1b33f502aa10fa99825d6eab147861e41f3814bcfb063d5c31418c04d19263d2456872c13cf7cabda24feac75fd74e1ed5ae1f38444aca26ac4bb123e4e5ecacd5222a1cbdeb6578965fe5287a7642792a9b91dc8ae41851a80a2edf192a3b8d47a369c259a76803517d91800869898f1c2e51608c74df167c6d62d6e550df86f920042dc71ca3862063ef02225dad6b9c5d08d50a1fa5ea20738c567855a366407312e9802c4681d11ca3db883cdf9c2ababe724ec14585a6d00970b7f23b7782f117421558ceed2b47b9a8b73fdfee016e5df0b5b7144ebed4102c93cc5e4123999d853d2a0315501cf1ad062ccf5e8770c08ab53d231fc098458b2b6af149abe84e81fe23065b2c923d7caa2591a8865b17bd4bd1c9bceafc9268574a9b75d211bab0726157d758474e14f3e7e501170bf9546a723ee6bad48516019a99b1509db9b8cf24862019995073ff25ea52770790bb7ccc46b43b44adfd68be9ea1e316958d21dcb1820653468468d1e1182931391d736b46fc81912a70e96552ecc08be14a7bfc2212e16c297c8f145214d92a06a3e2a84e1db35376b16f00e14287a4fd6656f5f47162e383845f6082ad45d5c41c0ff779ad87e0bdd983e1602972502754558e05bd67188c516c97d7d2130dd743edcdf387369574decbc75276dad3277fa311d7a9e191b17a1072cbc420ab91eb2c2a1e156bc280cc81f65c12f7f2428e6829ed2c9edbbc36a4b935c82098edd1a4c0d2e9417113e59efa56ac35956bef0abee79ff0efdf9a3a4e287f673b921fd2affceb4b0e0d34af51300f5e40e14863938687f2f40c84a49a951513bd55fdb1a11b28cd64310c90b45c9bef227626e36fb220c74973c8514151571d19ad1129e1699b006946e2653460fb862d08e22cfd4adee90ec77ad529662e9eb072c1cc6963c8ae00c4932580aeea306ce20e1a7da908a7af520693ef98c95618f6f37148884711976d78afcc15439bdc60d3f585918f89daf552d149d3d81455966ae29977e1dfeaacc40ca55db3a47af48f11a4e76421970d40e088ba85ed7022967ef0390bec7315b8eedb5dc47a22cd16986e8f5ba5910b5121c06d57b2e073f82930d8015b2b65e6855c9aa02fb5f1e44a02d71f2ecc4c3551202e8fe323de716e1f83d63008afeb5788697ba52787c27e42c6d6a470988fcd4d083c671bc5200da87d46009133da257ca0c893d43cf622045e8aa187a93017a8e829c9ad979798de23309344634ed4398751109e885d75ff35a682d97472a48353bd55300b13d604ca6d580c518e30836f324073a12c5f69ec2a77ecc01696da5465d4ac085f48e400b9a236df8b96497485a67511919c14c41944ad4d260c00f03fbe051a74b18eee885aaf67d5d2fc624203c90e2796bbb0462fe8b987942fb1ba008a11606301ddecaa95372e041743853f8ad1733434b387823a4790259c4fc352e3c56e2e231a7fac7e6bbf82b02c74005250e760193f973fadc7565e3e6e41f43bd0c319b94879f8e935ac9fb1ba5fa81d697ac5421871ae39dd02cc94cf1dc52309e79a855288fca8c14fae5e8f345f6ee68b8cb8f0a80e1d25cd917a15b9b13aaaacbeb5946461b3388667e81000165cefa952a189db9b5dc043ac511290a1e757d801fcea739265ddeb2c0c63f6b7fb1fdadc7b9c934fe9ac2a1026c3cb94e127beb194d24922c379a8bac470b1085dec6f8eeb412a1fc2b39ef07c1c24cf8bcfbf38092d614130c661a262324b4eb40a623f68aad2af3bec53b3cc53e3414ca1268bf1450b7c85219a9a52b1fb15d3cb4650243714ce16a450932b30d0d1a189023265cdeed3ad34bac0c2195d63f16055a9c6e8cd3b5cb41a1402c97378e54dc26245195508ae45a60f23d919e14d53367856e98faa023e0f5a272eb5e33b707708684f485395f9a0446162414cb51f3eb82a1d1e2eda68cae9e8779382e4b351ee739532df23b4d5e649c7717816db2953762a6abfe490ee09210a5a10b43041f4547b34f5575a8b46085267e4b8a62cd287ca68b8c3992b8158e4045b715fb9a38501791e27b551bb4b14245256da1cc000ea844553e4c0a421f5bcf0ccf556d9dc3990a3abd5be94ed041cd5700c590854ed03ca0eb3602d3bf6c57bb7c5d7443c9625e6c11e520f6f87b49dc824df319efc5d4aa3976dc9ca24f46c638f3f37dc896ac989ffeee5612433bf554eb5fa50f3d624bfcf514f1a64f6a9eb8a6c745f0b53362c9e64dac1b378bcbc24b1c63438dff71e203ad2d1cf241041d2c5c1ea4cf5718782a455ab5a021b6a19a19b8b70fdbfd362946b6dfa58602f34dd310eeb1367e078b851fb53b5de0cf50c49b8b910dc47ab492345c05a721193b191d11d185e86fd52e1c9bc41008c9b5aa09f022e5e1463e66d5f2c6933c550dcb33bc8771cbe24758b9cde905e88f62ce969f4c61cbdb2a5384418a9905181743a24bd87dc88a877891e4673c38bff5b9dcef9ff4d4b680ec8513054f7a25c114aa34fe100556960903f479541b145726dd74008a9c407a762ed531e8af332914079432f50318797dd74ad980064048b853eec9b8d6b4435bff03dc74be662d98bbe56a2fe39698874a121999e57606593359c5a04ad28dd218d2d89984b48e6137425750d8d33166b28ac58ea6470a93b588a658450ed57177538e9b7f907eeb62867c39faed6ca0bcbfc97f41c726e2e53758bd4756a45609a7784f305b2694f91327df19605244f2c10430d361c25894d934762e1d70d962bbf3c4cb4fa8ba63ce250c1a73d6a3551952b4ab82306ff73c507d76dad79c7dc722f9a7a8e5814dafaf930f052bbc832b061000dc9f06c184306dc32b420d702c26a22c904aa05d6e9b1d4593f519f3a5180a6f104243c4521a464ce1b46885875106a5122dc6c75379f8d22cac0429272d101daf4c90abadb50d3716fda708a06064ccbcc8d384cf070dfe75b17fd5793276f465c114e23f4d391d19fc9ebffbe657f7f81b8c34c4a4147f4191d73860e4a08421106fa995c62c6e55e601d621b91e31af0445f0a9fcea90ba3308cd2361ac8c3849904e2ba50986b5a1c0e1d9b92ed008f8a082a6783c607ed6f16dd8cf47df04541484130473915e620ae96aad9d0ba28e20f0b22a699e7db17f5cffe2b750826fac492ff33dbb95623fd13aca35fed5ee3c361942524aace7fe0a907bd10125b032d4c56a669ea50a4252cbf1acb9738cc46545d8413edbc6b70311db9317a9dceb59c605819730d01a4e2ce8ae578415a7397cd6a9e348d70502cfd81d421b90b8d4b772c63de7c3454b4537628d9c9144c47be6d09fcd53eaf7020314551783d9c78289bd163550b273f6092966fd1f379a639104519c2905ab606b75c4e2e611ae24c2de20e48c7e549265a3d04770d7ce89385c4fc5894bc6b406da0cdc073f54cc137ffa292e6aeccc45420815f24a66ac33233fff885239ab024ee0cee950af4d536b5580422b1b9952f5c712aa07c3d38a456eb9faeb42080c7390c59a4a889d6986db142c8e7c6b34db8d8b65a31115e07d35ec4c279586bbcc205b929fbbeb911786d9dc2675157ac493ba1f188a4511101ab5c385ef49b0d9ad18d74e161628a145273d8ad292e6329a9c9005314c5a4b145d4142faaa3de889b4d4a9d415420adcbcc1266933eff510b387dd68fb900d7940c1a152a828fd0ef02fbcfb830bc4547fb03190cf5c9878bab97f1b034582658d2c8f51039bc04f1e3542736352be29137836616a60c4a308e93010d63125ad3121656bb22b984d92ab03214f7c131add49e978177bf5031722bbc26f1c304a9bdf42e1c450e0102b6d0940dca33d4d6b447d03d152d32a623d9652e732e0f2f5281d27b4de058f10a52f1fe989651441e3e2d7eb2d9a731c15c4a55781e2b82cf06ca0c440d777c087708782b335ca87b32dd8a14612c98bef99c24f862bd52d408c3101d3fba752305d56317b8b5fc484044844a901481a0498395e178a7fc6d2d96aff4ca881fa39324ba574751bdb1c6a5f5c0bd69cd644144d13e8ba58ecbd5e68e8f97b89f7d3a138c02b206108dba40246938664cdb5e4011fe6fc3d4083ce41faa469fd03d0c72da0cbc692c477e784b501e12f167b24606802d0c4d110e0f227efc108ca1ec50be5b9fd3ea83679104c2078888b290cd554280c58461a4cf437787f7d397b84996de8ade2006bba191a7aad241734d0f2ea4397fbea860af7b67b70d9180be2775a163afab5ede52d6be4a188ee6ce6377cf46cd9d058186f761f3109d5313d6005fae63c2b40f92504432cca10ea626b2282ff0ca9b6e43242e6d5782798ee9e38cb5e257fb3130d134489ab7318be6e625aaa52c27f53526fc90e62ee95abbd76195d452e8e9da028cf2cfa76525dad856cff524bc93113a147d694af9f979cacff9b6dfda464847f869943c29a8bf840657eb63106b520f55a5b6f0a2406483fd0086e4a2118f1d1b74253578bf11c75433a0073091bb78a109049cdfbb8148aebc597721c0f71fe2f243f60992f6fa584bef85139290a81192a201c330be31b40d1eab08c4c40224434705cc634da9d61c4ec6c21958cc30000e78b1a5abaa78481bd9d946423099d079b5955c1128fba89674541684fd07e44946c56af4a0ce7725176693483c7dc41d401e827b9ea57f1813592d5f306b43ab572f7facc85572010d279b707ea0b50ecb26aecaced20165a0ec4641f55588a322fc3ecb851151846f555a7f32a98b5d1d04b5648e220647258489dfceeb82a6d52d2eb40aeab252ebb2b7fd8e107b00365df95adaafc417fc2492db94f66d71fdc15eccb9e5c376fa7eeb8c674127eb8aaa1eb91a19336ed7678f0513b4fd6d34ed54ae57881a5a4d6643af3512cb58d32269235ac533b93174984118f39dc5bb88955aa88903847200f53b408d29daf821d601658337453729d2e6471ceb504566bb32b4126af9c005980c23301318a71309033ad542109e845753250480bafb50d8f9687f663a90bdfeee663ca0f921748cc0f6b5857b1dd5e0039e6d6dfcd3cef4992e95df30f3936ed66eb7d0797c6f9c53a34c1fbf278ae8b3331b6834a845f6f4dc2837b4a5bfc70ee3db07f00887ae0216513bffdda6169a4d1b661fad79556b6278b33291e3570fbbfa710faebbf3b05cca2b68a16feb6677b3b40292b0a21f0bd38cfd6d64f2e40424f2d4397d90c826b1b8a28df020f86c6e221629e6ea26e2917931817c220cf6338aad2ec501b0704dd8366479f995c32449c3e8932e32fff4c01088b7d103b6147722eed3712955a3308acf0bd4b6c48600d01c11dc95e3a7a4df7f9469fba1bdcb07b40039fd4d5e7e4c66f0fff8b145bd60833d6f34d6b95e4f76c15edae47a4c3ba274ce81f05210bd55389f8b248a2ae01ddadb23988d5042929fe26e47ebc0474ffd1f6ef0f90ab67e73a307bb11190cbd39bf8d409ccddb2fedbe7d54258fd4340732984cda953c1b047c0dc63cf9e60634c7439126f5eb9e045b2c729422de9b04e9ad44ae7fabb85bdc3fe5b73bda650082c4f7c654195f15c6c301d52c082eb28c98d5598ea2e6550dd9fa66e591980a1074c85b1a8b8896c1e816fa6b7e1803b9f83d821e9283f6c8a20162876a4c985ee4d94892f38ce1c2e984913f2a70e3380280258240efe79a74897d3d160c23fe8773a64843471c5c978b77d4e327c7229349524719834e03258be06b1391a4d8178c7c98a988850f9cd5695865ef15838d6f853b0a262ed31113e6bd62c091c625ad205b25a032c9d94dc001612d1c0776d58615313a5245118b4c0b91ae7c83a0a2c08e64d33daa2f19a10d86db15a9d2256b3cb469848674c993ebc060c62104ed690019820c82297a2fe08c47ddb2083c7ed2d233cd370081c8fd634450201c58b2fae6350ad36d48bf21ae9d484556c5beff0a3d4fcfedfda7d9c95fb145a5621410ded5318739ed405a7e714c1792a42f13139ce59718be22a0ec17eb83fae87ff2cf380f2cec44d080ce793e20a1c1dea1289307570fe60eb0abdeb90364862b1dbd2c1d824c329f1800aaafafbd1f9f98205692a723cc666538a44f5db2feafeb5462632a53f2c41d22625136064ff41cc0ff3c9b92b0c65d375ab6ce69aa8b1729bab958e9ff20e676f266ab3d07c11cc894c8f17c57264353c686b1c08f37b912a79d98f834490231952d49f408e61934d602b40a929b3be021bbf0a5b5c6c148022611aeafb58c620722115b54392935078fcd5a4ba8d9c99e0c0872fb9266708c52e41c4e625657bcc2952c040eda7f1aa49e4040f989de08ededc9b8ef35145921dcf159137893a9f6dd89d28c96e1b4905bf2b88200501e433042258c5ce6b0948819c2d108cabec3d57d7cff2bfb11d7212031328b1b0b58039a11fb6c0f2ba2aa5a31170a9d0ca0c0dcfa99fdf90f024abf8c40ff411cf364431cf0e047fb4c58f7a0ce3c6acccee0ac503d11c02c24156e4291cc0590aa0b91d0c2f6357df111a55a0402738a120f4c698b38f83aa32a540c1998a3205c1c75336726a897246909ddcb9948635ee5dc36b71cdc6f09e265c1d46a4905151cf685dea21a54614bc160a82c5acab1d23832dcbacd74a7900606220bca802fa82193b8f49a849cff8642813d0db9f3553dd606f2015d0ebcff6e602b5db02b00ac46419e3b1dc2067ba44dd1499a38bb2ee5d2e1fa950198f2016c6ce62794e2e8e23108bac3c105d00b3da024fb00818564feadbd7304766abc8fb83f8a191b2e3e5b3f012bdd2b0bbc82a7473e0f047e27ebfdb0db52fc3f52e8a05c39d21de8b0c332639ea281623871210d9b28dbac557b6a650d051b1c9bb04cd8478a98182473fe66f2dcbfb0412abf5a5fd7f8de8ad38c90685c50d9492b46d0f108175a67359b326e0e924dd2c679946b3f2b40d00d855833de01350eebc1b0b42122e319e009b78ebe66afa451c9a6a02ab35aea04f50e414728f2e5383ba9c6248bec5b6e210c5dd809a24941328d87881ac81860ead46c715dbeff9335625c56a03f28e2584a8d2591e6294b850825a664b7dd1e359344b28f7734a25ce785a9aa579ff73927367b91bc9f91444f1f1a0670c03ae655a0c99403826d5348cdefc1ccab0842748714c1c419c4821f9fec081a8087123b5bb1e79c179792870151edfdb5b84d878775cda460a95a1507236c9d673231ce6ce73028ea481e2c8172395a4ec836eda25b8838f9076757ce42622ab1639ff82aa2210322f215a4cf49a0c3c60cfc2b11001a914f8f858d751a03c395628cce3e4e9b5d88962504e8562d21c455026af654e510631361144b2ec48770a0ec1284df1653c5fb317f57ff4bebaef2cf1bdb356cdf7a16852dcbde399d15e752531c4bf513247f284ca138db46e1a9d0d6529e2459c1b61efb9f5a90c13bf56a11eeaadd6713dd2eaf601958a1c014ffd2f4615e72d79c2e94094e990202a0cc939bde89cec17793cbb08ee61462684faaab5685ccf94c71c661ac3643edace8b6b8044f3c642062841a6045fa221684d31e6d3e1f03a5e3ad502b41aaf55be90945aa8cbf13c5061d5d53ff4363d987334088766c40b107510087718ad2d93c86e17b7cd563e1e84d454cad49c7583075821365c37968cf795da6ca8c0c94a4737cb38cbc6c146e0a6fe6ae38f257823c98d7b66b656fa24f24222439e13f8a57c372574e770d15f8f70a47cdc62911985c6b5a77c2f3c351beaf5527cfd5c44640e3c97297d9b4109b05204ad13e771acd73ce406a9307aacac8233ea03ad7d6c63ede4ff98fbda0d9482405c032f525523bf2489bbbcee0b8d1099121cf62ed1b5fb2727ce88ccaa70f5d7fdca9aa0bf0e651811aa36608fcaecfbf2d718688c7f22128893f04bd0ff7d4c9b3743c7f892e33553b43dc09803f0c330b7aab0f016bd2719675bc521325331ffa34c5ae7d6788dabb45b1b13fc155d1ddfdc70d9f2be5b65e8a26eafb57b20ab4369a31fc0fa65d61f75e9aa3fe4aa360f5defcf11dcb33bbf16f8a0cb727ed34f11789782e95be7dc9b6016ae7a3952ad03817db3acd6c4668857812430c58692656af2d50154b4b3bdc8628328ffbeecf4b30c1226c9aa5d11105bf215595da1ce3d20130b1a72761b3470f355ce3a326f28a8dcb3ff48d6d34fd6925df59f26b9182f5726341907ab623d09f9d44364102ea4433fe0410050ac4d12b5a53a000f3e49d41370ae5c23df7058c3138e4d0ff85c4038ffd51953007fcd6be5eb65ad35e80c78f5e07223787a7a924ee0a8caaa7aea63106d8b30da083e4dd666e2d4aba2f2e66b3924c776473aa32ac459bd5740621f8bc758954b565cda150e3312e52fdd247e996f428cba1021a2fc366644a677dfbe2498a165dca0635b445b0fdc2682e49ae5965c9690ca72bb285cca9ad85e6c5cf70e1144b095d1ac160421ddbd0e8c436fabba076217bc0df2e69098a94dc61cfa27f77a44f931903ab8e91476d6c84432f44db63b687ac7c02678e1900688cd583f4a3365865fcaf4a66121bfb3d934a51a3553afc33bc1fd77f69a1e508e3c9b51f0341d6fe840f48a1ad883fcbb5190096e26a73ff80f01e80eab14f49fff97d7bc0b59324ddc3de48e8e8f7cc0400eb8f1f23d8c588a935607dcc83607a066b512448cee86bd614a8c9e5a43807a3d0bafbe64b240b475c348f98480519635c2e12cb1a0b2b06c696193bbab880baa2ebc861f34ebd88567cb5dfd94c1cca7225e4e9a5c659772e68cb8a2421497a41851dfff759df3c68701b0325a3a564668fd41696d627ce4928d52c59a924eb67f69058d87fbde1daf65ff3a850d1007d3df8f928a95c4ed1fe464a6f90850fe852571849137edb0308fd5ecaead386fc9a10bccb654fcee75c8f4d7be7743b54380898208ec7e00b825fbc3cfbe043f8f8e984a78211f5239b55a02085bcb0c826800e86baa5ce80d0971a0421caf6983a99c9293fcbde9b4adca7e2a2046c8b82c46520407b59c3b6ec71671584096aae4a5599378a4105aa98a1880fada3a425e4be9a8e04089f90ad259420241e53b6985aacd0114ea26c2de6525b032484ce1b8e4f84ad1411ab8e6b418c946974d9b80c10d6359719432885f6cca4800ae38d37aad0be12041924c7991b0e125210d48f3ec8afb195ae8df38729abc9d8f0420375873902a1cecc0465c036d00f4cf82090462a11bf0e86d3692b4407834ffa296d534547ce5fbe8ace3f05642644c0103e0a5740f415736a8ea459601e19e97651e8519ee21f5a1ba608c4a9c7d578fe2341f0d46c82cb680616c6bc64508b182c66def08959218e632d01514187ec8f7aaf120887f0b6f62af4c5e1573a5fbd69d9cb828824c9f6fb5196712b151c0b4bd399b603612122ead94dfb45d9d9166b1d586f2f48bfcf64cea22e44065b0ab69c9c8fd28f94f7b1b72e1a6a8f8f8b1d10062c5a4f6469478c824a3b803272ce6ead3bc0bc19e500802ca65a93e3cee933cd714a8acc95ad4273509f3ec9312a5c099ea2ce5c433716e4eed08ecbec1c61adfe9b8d1ce6a416267506b456ef4e0a3d613ea3f1d5e5a9a25e4a419a32cec9a55a51d3db8a5c6ecc5366b4a57d1e49138c8088bfae02a5b6b6b4af3d210f78634fa95c2f10fc0055c5824dc7ad3c1db3510cce39b0cd5a3ab1918d886b3f684b90fefef9ff90eb8b33d82c8fc289bdc52b6ee50a4936f9ee16d6c60be67449b5feff1e69caa548a2e9e8b946f40984f23696af49a382aa1601e72f6b7820dee37e986eb88faf2482159d787d66b0f047aeecabec55772c935692c55ea28ad62febaf88875051169598ab1934396227076f698c0a3f89110c0c4700f4673a62a90297e88f3da14b5a2d3aa58717c4f89866c4a9c00eebfdedff9d668e2c6f6d242eae85a9084f426c410fe1d44ae6741d094964aeeec02ff42c8875dcde95047b246f0fbabd94a1c49ab000922c1ad692b9f05e09108bcaaf3c43d9504f2d84cab2dac7268b1d2eeb24c9deca36192dd2c8336054ada7d8cf1dda0dbee65abe717dd1bbe4306ea0f08a8adffb9457aa6a70bb10e260dcf5e469604f521844d92640c8d659e1dde8dc99b2e8d52a7224b99cccfe2561f3e5b81a5f18f4025d72af11d838a599049cfb4bcaec88a1f7ae5f817a2b815d76b4b512051ba8760604a423d981f0612c035a0c4da439384ba284755890b5e5b896977585b41ed1ea82f93efd3fd3e1809174ba5783447558466889180296c4bea8b1845d7fcfddb878230fb9b57703a80890b1efad457b3a47fb51940b2566b4e9df38c0c2f5f819181f3698d1aed7aa5f8a1ce282acc4a301e76a00de92b1de5472300d563d0af93b11ba4c57f1abfe3227d477d0f4c00db2ab01aee036eddc2979af698db533f34b0a8444f3348617a469278a26100c71bc923851590c43e92a489a200aa06d132d7ef6d870f74245276d6b6fb3705c1e394d68a626599e3e68d65dd5e77e0c20efaa0c0526201b21c15265a6f8ba04b610752401f03731cd59176888b08c4fa601d1643c5860fb5b05ef664596429bc55c9a73f1b922247ee85fa00125f7483ab40601e150471a07a217979239e125030aa8c604899803569798945f16e8b4b25a3a3017221f275dfba39a4285cea54c41487ca6f41edf641a4e37d88dac49a37274398cab476c5a41995a86f8a7b363fadd101066d17fc3acd7f97bf48198541f98635db7976b460bd4316996698568ba71b05111ba2c7107cfa865716251774d00a611ec93bb1db5ee478c6368f023001592c63219e6c60571f6692b8f0b743959ca23139007983ac00c6fcfcafef4744eea2d84fe8b6a4537063b6b5f60d7a243af9f736ace6d0181a1c4ea5ca5e86b6a74e2a15150b368462359ae456c49dee344166aeeff851949001687c9c5c2c8d07ae87d02d2a43416f215ab08b41bc01ab5ab4ea8a50fadf5a26372cae6aea42b4974e5b7b79c00c954d0b20ea6a250246b8faaa54331b60f929dbb5ec0daf0bb825a70fb9ed9bce41ada71a6480226748b3a77c046124bb2806b1cadd3600cccc2c9d67fd60e488324723ede4110573fbcd51103fbb1d9d99d00729548cf0eaf9e32f42c8cfa884bf291ba89d39912010a1a757e1964c013bec0474e88839956bd6fc1625e418e4817321ee27a3c0ac9aa445e5062cd9a4dda1cd03618855890d505191527ec18bf0242d41d1c2c8e18b515412ce9c5c25cbdb0babc51012751c5ca96a8acd9430c24c63382320002dfa7658c7075621cf5506c4c42216ee4d37ef2e8575ff51b50536e11ee0cdadb6ba14d96619209838955f55d10d1dfd1c81c44147b3482a71c5482f1d22ab8fcb9b3842c846af5fbd50eb0a52c34a8153fefb2e2549af0dab472000468795110ddd0f9acac0e8e6865a4da3277bad91a6dce137f2e59b1c4bd58f9c643842dd7bb6f1eee70dc6f100f2f4bd795b9593de1b013ea8183343130b189607f1523371fb34f1ea0b682aba5b85e58af42941e15da5195cde5e21a9e9460adee2e007dc17c813389817131f8b73629e29984db0c538aabdfbcb03a7ca261ce0d71c2d2224acfc72c097b869549a793d74f51b9a852dac9658dc565017b1720f86ae3ad6a319ce19d5d5158b6063fc20b4a252aac4d8088d283228385c9dae38606c74802e7687b7c56b7315a194873e0bdeaca6ca2e155ab085bdb7a774681a384c77c563bf89e007786a007036a9cb72dc96686d1a50586892d438484864eb6c87c2af3d1a65fa25ed3cc6336a2361aef15951d7230a15234a366784881c601cb6a985dae6bb84e6b0658e4ceb99142712ebb12d92243233c6283ae260569e26a73411d6d52400f23dd2a596696ce47a1ec23755029f82484428bce73a9c1c914988bbfc3457fef481e26c779640350ed24df20572422bcfaa1cc2ee25df8dc58c2c6fcae8c41a3e3bec21326dace00b43ec224e7980c6d14cc2d53887d07567b6ca7b52e5340745244a565616680b1d8a273460031268c1bc37699829f047830509e1eff340729b319132acd0d51823e2505a5c9da66812111b2f073b7725676acd95c5bb7ecdd0036f16ce4613378846f6e48b04968a54dd66d60a5dddc4b1bd0b7bfc1de38ed37f8a660859d866f169e006ea5595c34236b59f26643c6210a461e24079a6c42104287c43ddc58ba90bfcf5e2fd41282c56d83281446a0be7a40e4325db217c95972e30396e40344b6566b3bf3ba5e9b3048bf62c7ab17277e456342a4d89d47eaab541bf93139b3e309edaf0382c00ee76d80897583d867a84d04b69edc69869c8ccd893b3b700f73eca19b9c9b948487b4262a54b7ea3ebec5d07d8b901b434f60c6cc06f9f8c4dcb991a998afcd5f2be90a797e7c820d9c9796e064a868593309b851e2fb1933e65ab1a61e013019afdc28740a2240877f43dc15223de8b5125c8700cc2290d7476984c6c75c7ead9b557076bbb61fb29ef92069aedd66d03bf1fb1202e979a45e6f624dc9ccac9297a24a6bac975f85e26488037947ee907648d2a3791f9ae7e7ab132aeb7390841463e863e520c475247adcabc09bae7de65d1e30bc9982b58c643c1a4b172b346759f1182d8b2248dd18a90064fc5b3b71941daaef704e1a74dbc018b0c6b34eb712b03aad7367ca9685aebccd2c392545a6d5e94a459fb770491ec0328beb138c4773f3e8bf761b2a70ca5dcdb2a8091ee6aae4a8874a1f1c3a3de48d9657a08875bf0ef2ff67d800771d5b986f78c775bfa835d22274626918c15b9a00aeb375bfe04569e1cbcf40f2780e9af3f13cc0b45cbcd318e68d8aaac87ce119eed8c55d5283b2dc557fa95c0d9555276ffe569c1b7866d1da6cc4ffe8531c939843e8aeb2381c8dcd9d094a3b3908eb49c8672dd0f513fdca68d9dfe3dfd91f4f2f9c748ca93c6b701cbc501f605542bc3c97d725b7b6390ab240d1091a76aae011d50174b2bd22898af32edb2617a88d0d8dc21da2224750f84528ff9cc4faa691ff0df48cb1f0644f72075ce7d484ebef7c8efdd6a36e5adeb9a0fc5b41eba288c1f91a3257890f542661614ced1df3187a53cc0217e20cf03e585b1ac191176e87fee82af1466dfc775f3a4673b0d1ededecce65a92d379f17391a704b53abe695032038c656a77991879aa7b72b8da7de34c07908ff89fff57afa5f2f2d55493bb663599c28bef515df8463ca1a318923a1a993c1fe7b4948054f1f429c702914628d6ed229484085b174dad8067795f7d26dcf96891f25bc5d869e8db5e98f43701a5f3fc5e1266c0c2b991815bf82b3608f31b84542209eb4e4c6042af3181a59148834feb037f6e59185148370a10bcfb48784e28539d126d720b2292c7bfb8f8edd1a61d5487df099652ee9a225c6d6f2f8fd7d0d17c6e9811cc6d00a8876c0c0a085e78556cbbe08687e293196b5b61b812f0d36c5b093e2438d51dd386219cb72563c36018398dafc44858b1f3889c53277655c73d4953af814f852454ec39fd94766487bb24a263ed18542a1071ab91dbfcea59f0109c5ba588c6232d4b07f3a6ef3767d6a553c757b66c719174cd0a01007319edc3ede26487ac2b98f68c9dd540fe300588e7b37fb4e206c3c0511d7e2027f01f6dbfb59694f5075c8fb611d50365cb757b1a2519a325be31290621a1ca4c428a3d1025b354bfd8b8057605fa3c91b50d6f4be8944d55c54659bd472db65c58d9fcb962b92b371ffd3a30303ae709f886ffdcd43ad66a8a712dc280553fb64fb092cff36fbf125960224344cbb28ae91f2577407ec036ba6f7b7905cb259512470112c3cda89cd5e42897c2947bc65585a0baad60aa64080824bd66596c85db037b5e6c321c58225720cde8671736577595bb37b3ab21f0e56f580f43dde22b4ed0e4ce1aa56a1f6004f833c3fff1c2908d1414daedf9230b9b25ac72a746da7abe0432b44d5a0fc58f11400faade84edf9bace4e00184226033a6ee810323b6e42bc8d1ae567476e9f350c857c66092d61c46d7da01a4d7358f65c306ac4a9dbb5dc35c84a470b178454d61f2899160b52883de05d1ba7f671a600a27f24710eb51cd5233eb061c22c0e1d677402e45615910a2fcf05ea652649a2801f9e073b2cfe2425e4360200b6411407a26e029160a8e10ff1f385e3da663eefe4000b9f2dc12bcd2ff1ac8436602ccff0fe6fec342cbc9d0352e22240b56dea0671c984cc6eb35d97a65ff15f48e005c72b553f873f7604e13d8ae26f8885aa08ca81446503a424d6ed8710054cb122acac5e8e04856a16e8029101a3d438947ad409f863cdbd083b7812cdcebcdd70dd8c4389640b930e8de5d725acdfb2aae937d595932c5acab8e221c531c007e89c3c8beabc422aa8d427c09dda74b54e2be9d81669bd2fdee0e3b1a0a5a514103921c593be91049441d701085a0624170cd677505c79aa68619a3e359a32338e4cd20be1a1ba8a38ada1f603662dcbb301205a25e1d2a83ec0bff82316334688c37386ddd9f470b971b23d3b21ab05260f86f49dab32634f465dc7cd4789b20672d251d8ca37f71f4d88454fa274644734d345c9b1986532d009a639c76b84f1d22563c2ad752b99a99b39b4956d9dfcf964f339bb9cdc66a08fc3026fd2c60ce3df7a83ad128ad1adb9602cfb189041a2bdd6979b1542269c14253e76e188bc2373c4eaa7bf015f49a75f6d1b09c653b951be3c156db45d4562234aefe52520f5bcef29c4ec1d2f9fd56a69cde9040b0c4e32067a320bdd662e82607b826bdeceaa0adc4d36a35c014377816a67e90e225f855490e788b00abadf893d2082d04ab7c58abe7697ed078380c6a180e2e2e95037838a183c72df89773fcc749c62516d9a7e97486e16516ca8ac4ed3fcce0dc6419b348d1eb3ca7bafa4e07241639ae5386346623ee99ff99d177b915b204d008fa0fc039451d722c1a674bf633652320ccaa03c8f54dd89673cedc2e7afb3ac16c75edc44f03a9731d02bcf8ef80d720420f3c1a22e005ad8800b3dfeca1682bf46efc0005239ba00a87003c286bd88d8d7670cf7108f809cc0ab835bc93db9c1480159cd1122f456e3d04c464fd3f8e7fa75640f22c00ecf6b43aa97e6c91816cef9cd1fe08fdb2c57dc77fbaab0752fe5179b9af0692891c72bdd041f338d9136ffd9b68ce0ac603c7763e0890303c5d553b9e2b5dfc0df3ce29b81d8521449f6996f4d1b2f1cb6833b65b631d5ca7c35e382a4f18ae80c68056452a269eb33ce2c1463f71696e38c4cce75bd0b94e97a438bb133b65606b12bd173319303a5d9c830a17ac6798e8076d3ae7ba96e92f48b6afc2b4cc0a5d921a83af00f45e2e46140df51af25fca2c06affae02dfd3f9e88baea2621bf4e6d9d73d6ea550cc80743c76d98df57193a61a6f52b4e389bd6c8296cea196e9a136a2bd2711f543f3f0fd2707262cd9f865d80ac98814de31ab2e5add261d448c4a6397304b8c697c487dae57a09714b907a77b88178c1a10561c2cd657a183ca31bc229234428501ecc3a3f438afe45a391a9a632796bde66f5de5932371f33f21f3d105c7551d45d3ef3801fa88dfd247d32e99995396e297fcd218470f14c81959e0aa0ebc6c828f009266305964f8b5997ef9393fecb42387daf570ce7346d2a4b765b998fce3b85b8dd22facd2101a10f01f41cf0dcb1aa76df5a2708de4ed664560a19730ddb08c473458a4ad8ec254d041023674c25d330e060e0d37c9f0d6d9002a923a726c6409eee403865b584a533918949c6fd4f5a842af43783a1ee80ede83a32a6d1821562100a47708fc5d3ef81733c0012f4f12506fc632ec1a2217de3daba7eb4367ab340749597230a9be0430f3d3bca0c3d8f58923d8b7e061410f7b50ed84ff3ea142720317eb653f9ee6203bd5e113471f6f6bc35fb0a2bd93004e14a2451713553130283fc8d1d8bcaf62c38a164853881ebe5ed7d3c0891e81c9c21e97b15c6a67474a7f025685baa6f8000616172cd3af61e94ff376f6667cab9ee5755d4ee674594012db8d85f4111082ec35ea86857d20ef57b749101f06524fcc9ac7ed96af2ffea419d149e7334b1c218f7df12938103573f70f47fca209b114b787f878b4c00ccc523d96069c2dbfd63090bd03c8615ff10621f2a10fe3a7c62e1c0ac997fd9c3d027dcc6dadc96e5311985d330a57bc4c437060ab825911ce9f92a2fb458e206d8dd0088f9708c60663c36870157ad5e1a0103bd4ff6cccf0b6de03ef722e647fa4d6ee0fd56bc4619cfc8d5c192185904ac87f6448e38c9ff4dda09402e86de0bbb24fc9c2c310557e126895b1e866268100211616e5c3818e9e94368d37d4f57b06002217c0be9f53ff58e20c6a10bd55420addb251c778cbec661dc046ba5b7fb5a10180fa80464dbb055e23ef9a7b1d22413fb97779bf811647c7ff04909dfb8a3059659ca5ccaaadc8f3576a72e039ed6d927c8b0c125ba4ca2811e597e67ae803dbd13e1f71fa5b3e75f0413b03f153d843aef9651ad23cece89762fb9d4260b7fd354e2433f29787fe7e967361e7b4af457bf3a1794901c89d5d905be55eed84f02e2b70802edf7823b3de9db2ed9c30b86085875b7f821a5695f8bba7bbf3977784b822cfcb0a551efa30a865ed193987bf0c3222e3464feb738d61b36bcaecfdea84219ad07d83e022ae172e7c1daa637c37daadb68d6743e3a0e19877eef584bf16641f87033ec606a3f183f8ae06a0b80fe100a8e3ca805f16575eeabec5917efa6f66c5ebbdc565ab94c3c2d65cb191bdee9f52005c58043a1cac32a9f3682634aafc4c88ad3c10538bb4ac8cab72368cd9e47d18576023c5861a8dcd4cd5a37bdc7544e13db55cebe54f8e9f54d5231e2fa670fbcd40b220b968cb7f643ea7416473d670ea67e62d362dc0435470093bd9449bc5a83ec6dcf3c74aaef4dd92319c092cb094320c9c6e4c3e3e15c8d0ffe8b361b850d5ec2776b6c9efacc511dfb6e65d2c6bfedc8d94ec87cd079606b4478422d7e695b7c5bb517206209fdcd682bfd65dcf8929b2d639ad98aa14374c22a17e8484862d13473489e520e159046f76bea9618563cb75608649457b05ede1b8458cd818969ee0cb1ca388dd3eb2838ea832d700a5fd2ad009730e04b2d28fa9a3b8f13ae2f9bd023cd4faa1ba8d3bd0a28db2076b8d0e9ed9ddd79a1f2517917c470a7678bdc63e5ac9ed11ae74955ee36ef002a423338b69d2d04cf5e9ba6a4490eb38210cf058901ffcd6275cccc815a6914c362ad90b797128c43ba854b21dd520dbc7cb0a5f2cf96ac8bb98e8ff5930ac39acbdd398f29cfe873f6bf396dabb0a638791aa13ab80079935341fd03757f42d395df7399c8c6442cd003ff139bc6a69dbd4c47e77d32cfdbaa772ef25881025718907dfbd874169ff110141868aab505ce4727db30e8da258030d5f27abe7d45d0d10abf151149e2f1121f44ec984db3dd7171de2017122f0eafebc95ef37ab58cfda03e215e038bf4d004fc5b8156bc2092966b237f1d61307833a7013d9f546260b80549e786f485d74188aac80836b09e038a30f4a09fbc2928da8dff24c44754a5ebe225cc930221d9516543b930f645f9846c7c02a103d5431fe031e18a669ac52d58feb56ac0440c4b51152b17248455f5e247f857de8ffa2d921733f030889d538f4536801f4f45b40eb63b1ba2f46f5498f9e1eb3861d9fe69fcd90145f41030a217195417ad9136ecf67a29d69fe45103322244cfb4e53386c566a482f750d50efdab3ac3160905c9a7021d1f3bb6d3b1529186a15dd75ae19c60a967c8fd9cd50a7b76ac0abf7777d754f2766b41b1a16e466e0065f94becc730e6f8c26f8628fb0d8a25f4715da1b29151dc7364c18d59cbf6f3b6a46b81131a0c006fa97cd8e118ab58ee04a16cd1ad7ebdbece865eae347b259f4c739af7bf1651752aea438c4f532eac5c7009c9b0e27b7b3f32d7caf445d156577446d4cdd90559a170f14119260af106681929f04f13fb882820a8c55a892b3af68aa6462ebaece5b71916e2a5ae18512783fb6a081cbc4a77477afbdcbe06c53ed53f25a151f40e06c68af8bd440493b56e555760d3170b5735786eb655c886a72aeb30595ab237760992e898078df48bb2fa253ff2de8c8588cb02c27c4038dac6b3028c437e45bd2adc2566e28c8260f8d5bfed16aa4e34b1cf63d62c632585a6c5817091794a7b0aab9ce2ab5158847b36cd71c89773421a9d67efe9101bf3cf4ad44bf4b5bd057998ade1f59bdcc81795f3eac169ae23b60c0649c37e1598577ee6af72e6d7ffd6b212c29cc25464f4aa73fec6aa1510747262843b52bcb6331aca9c35439d6997165ae6af13fb6b6a81c14cbccfc4db0077e3f9365ab5bf70d8e3c56022d8f3c81b25eefa81049017dfa933c0bcc39511b67e716b7f0fc6a812458ffa60224c0e54c258ea8f88457b62e14282b3153cd1cf388a7416a1496d0e1290abeb21bac42c7a9e6862d5b03e0f5dc5cacf8c2340e08641088a725da64b5e5c1f175cfac24694e8fb2cbb7029f7d6e69496e2fbdc20ce74a6aa78c3561c378f97fa3b405fccecb5da286281c5f45f5b5767507cb6e39d04535fc5916c9d0b58843bcfdbf43a0c5bdac3aee06e92b66a1cc9fa81fa6446c04930e68e5a839f08dd3d6c9b19080567fa2b18406c058c824ab5730784fd267dc0f77a205a6c499c138e1c4692e0ba9203bf3245e82092fceb81d1d256af900535879fa50c83160bed8900fccce560e4a4a93d117247403c405303ce5bc119ed3c533b15a3089f4c273ca6bfb87513d6a158d493115d7adf8866416bfc0618dee93ff283dfc16db386d381fb42127be0575422eb6fc8bcf2655fedad96d5a5e3ea8d7e58126d3a5ba3ff032c5e29fe7e1d76673e07780544b97ade0e18bbb023c88c5fea11e97cd33cedc475d89ba678c61ec7d32fd3e58ab1f231481027639688688848e4cb7b15240b05e0e3bdda93b8e752f5d18df440d09cef84f81e5d595ee3d48ce05ceb6b7b95d84da29125372624a6319e84cbe57d655cf8905c9774b60175162e9a68db790df257e71bc8c2fb4ad855ecce84110616e0f22889482e0bf8de7d2e4115cc7be4c4ca99bd7b8a638e5265ac02f7f3e47c01d2a0b2e7c7d1c87e302c136a09fe64795b527124d31b848cfa71f5548da638757a98973ffef2623b8f0758fb7ebd594ed9231e9b01c992ed98e52c3b5e485418ef82fbfcc880ba5eab4d3139d81fcde0eedce82b673e83a8221a6b752dd0a513fb0e6cd8066a67196be7d7f40c00a03fc71ec42e964d5ef77e4cdd1debe93ce46cfc7c4d251229a6fe4cbb53fe0664abd4446ab2bd4cd33251d4135020a66d522f9eeeada961fb63670761e5f0508318ff96ed0ba1e98ccf354de95f3cb10a9021e48637ac2cad1089274a7bd21fa2dbe790b21b558fdb17b61df4d1188e09e327164bfc9d8d5db2c9d4d2efa6cceb4d994582c8aba5488d66fd3523d09fe40e4ac1de4a12cd936b43bf46984b6b52b32604b670307982ef0addc94ac1b5930a7de2a9af13e6b09246d0023a49bcd37c52012dba814b04c945c837700498f7be48e227258e0007accb1919a90c486cfd3ac0dd0924f3cad159c763e59d282b61b09bf04e8305b8a82b952736aba0510f5eb61bbf1ab405a7df18d368705445910c0bc65342c8ccf3c101c3dc7cfee7345055e6cb176956ec114a92d4d71b0c84de90660e8109a06ad376a4c5b9502064ae97678929f0f5956d0e24ec5d6e6e00184585552e9e5c748bccf5ec0eeea19f8d7c32f279c4e7d19f478ba74260230575a710afe867aae3c90d28c4dc47781afd646499a28dddc5c50408f14ced91799a2a6088a657f56b9ac15a2333eb441575b9d36c0268e5601513bb0df1853404ae3abd3721f6f89d3e5e4c606e19aaebdec9baed58a2f3f801ad8c5b80480e47449e6d52e6aed02744c293a014cddd175399d0a5e75ae0f2d3411462eca12b797659630c04e95768f9e9d3417502d21ce74f25a73fb3c2ed76b5b84a694fdcac365ea11f89ce3e4d8417f7d1c5e8b8de25ac887ffee36083e6cba4bd356a5c32e92ee15dd86e300858420842c96926083d7701370cf4e7d73457de25b777b316f8295f3b02de61b7d714887f85cba3eae2752fa07c9575dc4e35dee11eefcaa6ecffb7ce782870b9c576f6c35be3e8a576285881adcef1c74af0e7b2c476135845e89802da40846075f773426e99c810a376ee6df1cb94f318202ad08765e5714590f412fcec02ba656a805d304cca9a0e75dbb9e7efd7dfbdfcb6fdfb38350435fa7aa56dcbd93c7a83eeead8ecf8fd86055072cb6ae45320bae5eb43bb8b1a8886efeee7d5817b13737641c193c51d2ea63ebd7af2cf7d8817514a7eb790b6f7de524a29b7945206a4076907d2072cdee35a3ce743e77ae81314b92a3d86ee38e8145d3f47a5733cf4096ac089dc0e7d822d38fd28d80ec304fd3aa3091abcee3a011867e89ea381f7bbc5efaf4c5e0baf8506238edc735ee765bc2ab95f674cc1f69cfd1b0063a9c7b1e4e258be7e2c3f83b12463178ce58bfd1884c1e2d6c39780ede11516fe0e5f45f80a9f8ee5bfe86118be1ecb172cc459c9f07344ae92e15b20ea4a86bf42fc2a19be8f7d89b48722eb5588a5de5f8178024781587efb5de27e1c1105dbed875cc91a6b5ddae0cfbe7a8f7e2b91760fecdef7519086fdee2992cad3ed0d963266a761ad0cfb29d8eef7de13f4be8f0c0e2e743d6f0cf8c8e090a46bfdca607ea07fffd4d9a309d646560f8e7853a79cdae3624ef7abdb8936f8afc61c38cfff8a365acf1a7384dffa1f8297934904126ab0c04f31f84dbc82df63dc75afbdbfef7963d9d9ee5583045014c1bbd7fb6e86f75d775de2eab9134ae0c2d0e5ea72ce99036978cfd92f145bef12f95f5183f0e9bdf7d65fe6fafeae2586cf45d77722b8bbaeeb401a22386e318331f277600c8e86f7b3929d0663e4ef4e28c146abf53a6425d877d996fe4f74a1dfd31bfc1efcf45f1a7b6f9dabce9a6a9a3d0f863792b68793e1d94524781dcb4ad5bdffa67ad745f5ae7ba8debd4fe540f67fb4cbef75627eaf25ae9e8bacdd755d476927e6ae1bcb1b95caa7eed1a72a0d3975fd9d1054a6faf71d1759df12575f03bf0839032a5c0609638d4a8225b87e35e6d868fdea572dd69863835fb1e458651dd3336b55a5e7b17b0fa4a1bf1b3d9caffb278297f7bd1a95c4f8b5d8e98739e12664a0fbe9d4f177630d126ff0fbfb205412ff279628d49ec7fde057307f5f411a5fce9fbf6ff4795149fcddfb541feb7ddf9e32175f155d88af4ae2e7e29481e2f72e5185f0b9b7a20a382229c62a8969ef9e25e6d02163bd377ebf1f14bfe7c00678a393fc17a491bf1bbd09ce70b21a57b0410312f0fb2c1432e0bd373a61d990f318fb44b2925e774118de7b9e27ee2d42f719648027727d1cc26427925079f48f5f492d7ae19c0d9cb73ff280f1d7a83c12e0be35e6d8089ff5e1eb904db004fb7cccb181c37a9c91bf0e191f7535407dcffbaefb95986363f5fcf99883ffea75c858628e0dd6b7be35e6683deb75c83c2ece2e54d6c85a620eaf0b0f468cc856a8008a8533b2590dd03dfdf1f1041336191727182132c82608a35be96eb3c609a5ab054c5898ae24d5a4151010c4089264f79de0bf39a88c525518ad239d72c3bf979c89177af95f105e6ace5d2f1f126a4f0637164340b11773e95d544a5549fa742a00697859912897c37174aaf250559ea944a4aaf254d0e957a20ba0de549ea934a4aa53207c6ba1971549a744844b2f6b519d555b2795120035bcac489d7ed2fde251ce9a94e3386b5a6b31a5f59df0e86b1d7b315f5bfc5b33fffaafffb7fff38399648ddcd0e9e30c99f0b04fa521b37f32045b15103f38d16f9f4a361fbdfc98116551fa3c4da7f4756e9c7a09e865e962de6c39bb00a097b3a977a0a65ed25a11bda443ddfe2ce992559f6fba7dcebef601a6dbe73e4ad0edff8fa36e9ffc71a6db8f092575fb2f7c6cddbe084cbafd1a50ba7d0954004cb7af815a996e9f033574fb1e00f2440302650b22058950b74a4296e8469d726eb8124d8ad6bf930342324001e4698b5013a427aef4cb5f5bb88ba44f6f962160a0b203922b4666326e8a10679cb47e01af4a6ee15e956716e1a5ee940bf2583d38473fa7e63187f7f87374bf5f87582327a77ef73a6439c61c07ecc76f633ffe5a471bf647ebd16ff325fc8eadb963f5a8ebfffc80cf9d07506eb4b65a25365dee54d72f7e823fff7b8b6491eadbaf36c9f6e4d8587dfd6a450febb2d2bafe0ec5133f3107bf0e99751273f05803c8325998c61e1401c4e5c2a70cfc1a16a6ff3f870df6f5c72c4c7fd78d397c2c4cff37d631871d73bc65fa9f32a82459f765aceb37000f2eebc69c3d56a092fa3560615aff8a197f2dc41927bde45dfffed23275ed8122bc9c55746661faada88114ad736cd8af6f47eb64758e8deeed7b50786999f468c29daa1547c15e8e312bf9deb4009f37a15ae7a04f2f462c75cfab9e950e725494aa72552337453b5dc2f1935079ea63ad395f5918c67fc1b3f86973be85a881a823ce09c3790bd208df5ab001fa5bcf7f82325cff3d97399d0227e2c89dfb3205db9ff53ef604da5d6279635ae9c43205dbed7b9b8523b6c4509c9504c5fa24ce1a25e2c8238edced58a52a499f8584d727b5a74ed55aedb1b55687ea122a45f5c61e3da93d768ab33d357559aa22e5095d42876a5254f3cd8ddac31d91507bb89b8bdac34d59187efc64e501ffa9a90b082c480e099fb23d15686aac53629db2d91e3ae66d19d828a645f42f386271443fe768a9d3b7602cedad63fa2bc6d23ad17f8da585a2af622c6d54c76fa76c0f05aab04ac138e51aa73a7ece667b2e70441f672c5fe15872fabad91e9d0a9b02a1d3eed6319d62801ecb3aa6533086fd146c97eaf4331e4db8360c2aaf920204e8e507490b5a901f90883a7a12448734605a6996602201279c304ac24c0d619a7039a8e1b1b3a8112ab23a62105334e6091a8854c920b3529a988a6080c71494162812a09122c3210d934f091f384d0d77c73c0a99f03443564c6855f2106e523a29a594ce3927a594d24929a5a212c783629ec71ac2e9dfa8b7aee64e3df79c576f130274a8872fdec27f7bbbc08485bf80090b3ffc0cc6f2153e0663c9c3bf609c0a9fc558eaf073c692876fc158be567047e1636ec2c2f05f47e1ab380abf82f02908df153eceec32e80b082f756fc0ace44e82d42be82b9658eae82c16088e390cf81e7c19df833afadea504fae63fc1b0e3e304a807abdf62e9a2af58a2eb5722ce7fa2b741182b0674ffbd8ceebf5147f7c4502c73f4f0b7f889a504baf75efd76f83e55470f45146a678d13a01e80ef89a58b0eba1e1471bea31a67fc6048e1e58d02f4fb1cfd9658d6a2cec5135c48755aa34f3a96aab53cdea854bdbe8e0de8ca0b6fb56a2c90c562ad2a0ec769f1b0b562b142d13e8ec8378bc56271fedc86ad15c8024116eb2b4883c562b13e90f581ae50051c16e71febc1ff4056abc5f9fb58ceaadfeaabab55ad2c91eb6088c3398b87227f1cb1c55babd56ab55a7d2b90c5fac015ceafa042d6e2cfc356c80a71582bd68ac55aad56ac0f64ad3e10e77178785b5c74bd8be384add6ea592bd66a05d25e592bd68ab7be157231fc9087630b27e45d0540101e6ee5f0e77b61f53acff3bcef30ee76015eecdb75b1de9195c4f85f58189e780482cbef4895675531a8c2f7afc0fd3b6fb1c3c97bef4d690bec3e77bbfbd5efc711edbbc4d65323a395488d565f52a2911ab55adfa2e0ad1d27f8e1c7bf12a1a811893fd7ae133fbf9769ac56abd103f8f78a252ea092f871564f81985382c5e1c49c1238155cde4af41121870e59ebbb71f5f559e2ea2bd8802efcfc7677616b77df8d4e5aef635b22f854125323dcd1e886b851e5f12c08c3f3b13d9ccccebacef75db2a8f1d241e49ae249df0a360dd5bb57e1288b65bea110eb9d8ff5c41b5ff7722f69d7e306629dc5dfa776e057100638a2503b7f3c925c5f895c7ffa2d71569857bbca71de57c3c3093f667b5a1f3e088260ede1c08d58cfcf5f3ff0fc2577bdc82e5cffc71f7b3e7af569110c2fb9be376bac7904c30f5dbf820a59abf52d9cd0c7e28853e63a81f3c40bc2e81e479cb2187e9738657b855f87f4becc0faec0f7c0d56a7fce1b7c13bad7dd7bbf4513baf7c69c3dc6a07dbef72f29f8633e61fb31ffc95a8d63d979fa393eeaf8698742d58fb1fefa7da1e87a17ce07c2f0f658ae10da68b5eedd39bcfb8e658d0e7ea13865dbfb4ebcddedba0efcd52d2714b81a3db0acd1bb07c50dc47a59a39be07d37de8875ed7d19d39af3d7eb7f6ae3df6417ce7afe78f5187c4cfebf9e8bf3668d61e8af25bade8503c35ba177bf5be29863a395630fd124062ab21cad77d57ea04271cca160cc318d58d224cb11fe0a2a64ae6f0515329c7156039420f48d63769f3f14a7ac4523d6f7e3a07d03b1bec7b246bf11eb9a627af32a00d0789be36e70daf33c4ef49e8a3826f83ef57a0fd28f9b1facde7e969b9ce33c8ef3eed5747a4fbdfbe07bf6f3e8eac1fd6d4e7bf62fa7bb7af7e7794b1b844aeef9c1eef3f5475be2fd509c5d53d7534a690e1c972f96d8e8d03793622fc8d893af59717e56ef3d7c6feb43fc5d71863862a9bb37967cbf4b7fdc58ce1bd62b2fa97b2fba17f3be7b7cbfe7e9f7bef7bc7d7fef172d0ac6f2e57a41862f5ef4f245dfaffb0467643c86ef7df7adc4dbf5473b7745d673d07371163a2efab6208cd54f105c79a0e77ddea8bb91ae686b4c93319d459f4a4d983aebfed557fce64efdf91be053e985aa5e9f4ed1672d53b01d07adeaf439fc93e299bf3e383f98f3b6be39959a4cd139d081f7a9d484aad3afcfa25713e67847149ab4a1f5fa3866b55e3c1cf4e7cfece1c84d9058bb7a2b70f53eb5d4fb27ebb553e8d1b0eaf03b11c7e49e3f276e60deba09e173efb5debbeb5e8ba5a7350883b6996ae1a86f5adf3fcb6aebfb675997f45dd5770f27f3a9df7b4a31dc98aafa56228aea3d55b64bfaa6efdaa56f9085052cdea77a6e662d34d997cefed96227bfb11d79e29cc6d0be634a336ee7df0665f00fff25ce1edb4f55493a1505df3ffb544222d56b2f6bd298de4365fbeb6d7692d32fba26bbfeaeb97efd5ce5c9e1b1e0f57f9567c5eb91e3388eac3c15fc579244e27aefd72359c91d95032f51b87dc5e32f69148b1c0b7ebfe8ae587791ddf5ddf5ea2ede5d3fab6bbfeb2798c1dc69b1f3e2ec95a9f2e871ebf7de637d2c100685e2200cfa54c9913ad513dc8ed82a130744bf4f509ee77dce5f6fc7c58e8be7c0c5cececef53ccff3bc5283d7b9b7a53fa703aa3c5bffed53c94852df397d7fa5559bed01ba47468ee8fb2b92cab3a4f600eda4a15adf5f8b6acf8c22692339eafb6995edb1b2fd1da7932a4f9941dfbf4b3aa6efdf2575eafbf753a7ca93392b5d6a53e5a1336efe155f4f98b1e263ff5af11e99f334868a264ebf7b154d54fc2aa92bb9ffa58453b0475ec9fd52c27d2c8da2529527e7f7f7bdfa8df3fbe99bdaf3b2fd15a8f64cd9fe0ee07c4ebf1e8c3036f818544518ce2575ee87bec1dfcf79eff5fdbeeffb3e17bff3b01d173b1cb878dd39e860031777e7eedc1d17238edc37780ec6146cdf60e4602229d6a44aeecfe004149451972a2900f1870302e0441c4e682f13c0cfb9e344009c38e74e37bb00c429a3417069ea9c88834eb07b9f1a55c9fd9d48a72ab9ff8a94aa92fb0520d22a0b93aae47edde25ebf06dfe2035b4a85cd2a4b5d9a9e661819a3e5c74dc74135ecbdf71e01aaaac2e64cd3b8ed85e48948a3d808628e5ecc262b629a8430e2490d125b9a96e82d63dcb440857e70b4468c0f5b76bc2942864b3044638c318611c6696f8c31aee11ac585b683140e9025ccb4a182540226333c09cda5a61d435a781282169e1cb1c46da162fa51017e8db748716649128efef08c80f01777711e46484bce3967194d20b1b0c919e1c3105e02b262cf2c9989ba41353614904c52445104c3945a18126c6123c54792eca4c5461bf2b37715ff7122f223c622a1a4a6889604638c4560a2cac2a6662ac31454b1bcd853e5ab6f4eefedf5bdf7de54153683de68205e7b0dfd920a9b307a1455d8c42f3a80c18c97216b82fcf0862b02cd952a6c7ad08047fcd58e31c6980d5285cd24cd54619bcdadc2662f5f7d6f9b44c76ea03a56724366a846618bdd4a54be78f66b4a6d7d2a4131ea59072232241d01e5079b28b24cc4d0678548a8eb7e7ace3f1dd59310206183b204872170121349bace084f49d7357156a028c95e2c1017db8f33453fb85084171e444e9ae0c20c09c55a53678e9c5ab60c35b1f0029a293780d122a4082b448fd7f9b7b01db02c0124042c1c197db15243579a320282f1c61b6f404a96a9265fcadc3044966f3d278de979cb1a37b60c88882da185c683054e001f784f016248c460d02425ebebfa1f8beea1603b9d41ff56100667394bbf0ea1449484525a6b138ee3b87b95889e281155e192a8a8717befada00c97e9585b8307dd6bede5eefd399f35c4c7decbcdce71b509d1adf2bc5ed46216887cf35455aad631757e6daaf42708b3e7365558fd273d864bbda8febee91503f58a6b16d85aaf5f826055743ade5b016ab38e8bcc0f864c04d0e9011db2f303fcf53d9a450b546175b4b31d1c2fb1e1218c048ffaf38886e008b0837337ee51d795a42020400fbc524e8f3abd477d82f6a8fb540a78ac1e7cc5acf7ef28458e8dfddd7775bf0e598e8d6e5c41856c8f36d0d721abd3963509927ebf7295b4138a0317a815b0b5d63c4bdd80fad4a2c999e3083afa7c159ecc9f321b9e66dda336e905a2c9d94ad541a83de14d498954a7559c2701f592ec7409512f0bc0535a5a7f5379b8a57a81115e914cda9a5fd62adb53a3aa206082a24aceae01db539fd67f52ebacdbb47853a703291cd75aabfe4cbf9e73075238ee400ac77d762085e77941155ed623fb765679802ccdda2acf50b5327bb8230bb3ffcd0f3657a60a2a8d93999b182612247de99643d2923fe73c9e4061641ecac3bd051bd03180fbea7197c7579f9f7bb1e05ef5a80329fc4af99278451aeb5125ed13f129abb17a50ac5516665f8b95aa1ecd1dfbdc91eda951266c469511034502a72f372d4c56bafdba03529dba48bafd8ba4f22c29aa3cfaedd47354758a7b43ab806aaddb2278598fbafdb23275bb7afb15c9f6806fbf2679d5c7eca113469b1fd0bd69a5adb0345e56daacb3fa19a8d7c7b4ca8d2b11fcee91a7c63b41a7b4b73eeb539c1dcf7aedb37b49955cba20899735c9ce2802f8d3b74995673e7dbb547be854f89607a5f727edc93f29a5ab67b99e7e65b23d384fed5285d10fc7d276e9948b76463da05f67b6c7f2a030fa94359616a9531dc0b1b423e8f4bfb1ac47de585a1aaad11e4bdba4d3d7635989f2585a17ee585a229d52981d4bfba36b6a932e708197352a69667beaacc2e6539ab6d11b5ec3c29832514f509d52a7da25aa97af790beb25e27d80d73e955c58c223c06dda30588ec2602962e3cdecc5638c294c528766c22aac4bb23d9d9385d5cad3455532cce4e99a98647da72427db73bdcc229c3acb3e53bf37caa3ae8eaa3c17a9925c8766f6dcae4daf7f75b063c5d7ea7091e845ba48310cfa8ee250b837bb6bf2d3bf368f52ca3da5f869e74d166bef09d0ecbe5c4da1dba7ba82a0dba7baeba4e4916eafcb52eec518634c01fc02c7e92bb4f941ee93766db6471bc0fedd31790630c98adf1ee0ed48bba48ecb24eb9797c8f67448d7c7e4e99884e023b6e722591853e5c1b48ecbe4c142934442b23d5d9909ab5fd1f4faa5c6b4ee664b161dbb9ba5d4720e743a8377fa611a0567e84e31adf2cc49d2af94cee03ac542668fc6471e74d22207bce2c60aa306d01e45dc2d3873e0944e8a7441c734fb7a611ae6fe3b6b478759b3b2bbd1b983adcd9875bb81526aef9c734eeefae8b3e7fa9830adb3b596e7fa98640b2ad65a7b6d13afeefb544a65def1d2acb5d33e9d77367766dd4f5a4cb15c8b29f339eef5e25c6b7aefbd39449cbee5b87b4147eaf35a6a9f5210dcee51e79ee7708ffa7c3b764194524ae9cc52269cda25b87b83eec5e106d191e2c08d73ee70d65a8b4410479f8917172970ef0bb72e5dcb71341a85a3511be58e74ee5c2d347ac1d4f5ce2817254aa7630e0c9cd6a3f90106f3ce2aebe85aeee7732f8f054ae957c9178dda39db19959d510c0cfaca69eed4e750387d8fab74764673a7febd53cf1e1693003ef0f2125da2ca53d419f1e02c70faf55a5a579d5167d419b18e381a28a51c476905b99fd3ceba7272dfa7d212a8ec8e3954905d9bad75062356f853c70b45db3dfa8522d7bd19869fc552855acf8f2352b085136e9f8584570fbed41d7cc9777ebaf85273f025df00003a1ab40880477a30cfdabcffc46ffcecf713d4956785052f16ebe8d539ef7cf2f05b5f6f61f81edcc2efe016fece48c74c5818be8b193e07e16f609bb070860fb3cdf049db0c3f00b6197e0b6b9be16b606d337c9db18c3df5f00130962f80262cfcf0c75b1308638ccd1c55d8444ada32cc30ededa6ffbcb14a5c68d52a2e3522ce54c081921f6bb0d4209444c8fdf191a4262134c49281a9c2e60d860c4efa628cf19526523ac6242822a281e887500c97479accc350125bc570098292aa008c143055c02c1911c3123ac2915350c617638cf197a28e31c6180b69ca39e759adc2e6909e315bc25f51685a1047a46e89aac2ddaa30422b261b9c202002274830c8e0449829ee0e162e103f8ef01777718e874ed0fd88f07383ee114494001d868c647c31c6185f0952d431c6b8468450abb6d912c51426a4ce39e79ca59a2a6c3e8d910a418a0a9339e7a01ba4c78c31c618e79c73ce38e79c73eef145a79905d19bc50489854d8df10f3a15b350b3d90c864aa7fac4d204149d7a9d2d5dd02ea245e04b1927d87821a2c8963b6b43c5aafa89e1c9d7f91f9273d85396f8c95df6de7bebb0a4c266d113295542d06109c7b009a02859b2959e9862e801c492b958e39d8d1c55d8444a62bac530e2b4a17e68adb5d64fe81f410cdd278c31c6337e60da1b07c566888049cfc0c3b6cdf0d4e15a0e8ac2352c738b0faa302b7e9e7c9dff225214fc0411a180cc11192432499f73ce5989a7abc498ab84d45582ea4df0a42594c72c097131e49c739e42626153df5ad7e59c8942109b402459d8d44f95f6e4ebfc733ce89031c618e31c442dc8de7bef1fa30a9b4748494c23fcdc706c4b112edaba8031c63dbce918631ca4c98311a6dc5004cb9a26211edc146d767c3b18d99b08a19a85e93219e514817283f0b76d606f80600b24d10509342efc90d122c51331dc1f74890452f72e19d145087f7117e776c82e71e151e5028d31ab7950521536a942807ac35f510c310424e70064db5898a45ea7882692448fa1a322316c8132858a8537536e8e3cf93aff78e8b66507d14107310523882a5cabfdd423b800c1d084eb4a11aa9f5be3b151b83001a3e66f8c236e9a8885e55625087f7117e7b8b6267673ce99095285cd11982469fe83338773ce39671c948386c421319d71de37e79cab3855d8849a51254ad32841232033858d922e5038e91ba08acc608364f16c5a6ea0629b5a6ca0b2b5127e6062046ea072908205ee0441fba7822b4c8c02e0048a3053c84045197263c38aca9029c594a316923c51e5049baa2a2db0aacc30e408204a724083b444941b17a33654805ca142f4e4ebfc43d14247e5e88706258810e2862778f821e4e14b0b686c8582a20718920cc088cb0e188ccc36341d3dec1003458a8793241c38364b2cf8e0b4b4b1c59069b53b173084b613c524c60c1a1794da50910189aca9716b3e3559781009f1cf39e79cf30fb5fbc3102f00192b4c84b450b325e1d42c01c25fdcc57976b2e50711007102c91fcd66b32217499f4c225842c25d3cd810fef01777f1c999ac24ad8640189262176b9c31c618cd5085cd25454fa4541901cd527ea1a3e6880f486badb5ae6bcef4b003153261764863045093a1275fe72f00a64d15102e360c8d996a0aca4d408498e1b2c80014d5731eca72039adb65c684885110246a1033dac7f295164954dd99a58814d31291294236454154a0e8f1f444173436cc04d5100ba48c3e9673ce67de54d804aadd109c18fa9c99e09c73ce79f6f8dda5cac2a6be351c369b8c2fc618e3304015366b3b8430432f3a9566684c063a7e3461c30e4c9cf010c4893646865e370c646f2821fe96895b626b736a01b4aad9027cd09684d6f4087a414b144e41578b1448423c27292a6084642172c2e10c950f239cce38ef9b73ce4574a9b0d92442114ff795998060a2c65fdcc5276f13829ca58d0d4143c812d8701027e37664538253e616ab5e9c5e27c893aff36f95a859c01cb12df1a58acbf2e58d92bdf7de49552a6c2e75697a1a232523890a27bd19aae24d6e865ac641684f208e88f1310b3215e408291fbea22db60e98e4e0a44689251ace345134c3292a02c3de144869869f5d04d5020b6fc10070ac3405f5c8926ba042f23d4006344194a18a326485891d43b05e4a52bbe5fd0548164dad0b2ae6521b2a8aaff090a646c4accefa54f2416ad67f9218e129a98153f2319cc354ec669ca166b359909c73ce39e779a5cdade73cd57daabe0ad822359b8208881d4666a2e813ec20822543f9044a0c19c118e399a587a68ef10d5bf9e9f85d4344bc0e213339dc9c6ae801081da29ef012249673ce4f482c6cea5cc3f20485c3f2c56631c6184fa9aab0399b8144bb5553b3d94c48ce39e789c546eb3957753a332245a7543405d01014b19c733e32abb049b3dd194790fc90edc9d7f9671a53c3772404b69a962344b896731055cccec045c994a9bff8de7befbdf7de4b63aab07973828a9aca31685539bf48624449d011962233475c19212e999f179e08f122468b11646e43b7f0ae2102a766fbd9b62f40f636c10c31f4e8888c7ef01777716e6b5451b3d90c08c618cf2b4a48758ca36e103913c38f1e40587e8c298374af94e981c91015f7e05e679cc3a82a514b515d7854d3eb8170427e899fb9232937d93b96a03df93aff4cba9665c76dd78480b1a9b0b52d53f860c2057194df8ba10489854dade586b11891fac15fdcc5798daa9b518608071182d6272e2cf830a3b110a41f1968b6d96c3664d3fa54425a428b715c882c6c6a261873790b91ceb2c588080d374db0e9a18d9317922c9145cb9955962e4e465982a0dd294c827c0c3f89dd344916367518aafbf3e4ebfc3f55234fbecedb40e2855bd5134f88e008a704161990e0b6a8c162a496f1c57a573253163675d0ed02db0217234554ae9e73ced98c940a9b556e0866965e59e8079029ea0844b3208e83c4405d3a279636433d67a8be4208277e4c69117204164e4c11c7c388097f7117e7380d96aaa2d6951e7c0c71c3a960c89b4b92854d7d827cc3a089dbd663ec5299237a78a1618476a6523c55d81c23452582146f44980228c79098603d05b9f75edd612eff30d1749773ce415ab014bdc966d6d4780461b5112f5d6078692287a061472541ebbaf9e64a1311da88ae8b8ab23f765fc880126a7c3842ca06c5170e4a088721199058a1b929b2238935666c2e8c6c94583f5b9e0881f76302af078dcd941a5a8fbd340589fbf331175e550aaac266d416416aea55839cb03380d0b6c632cb526f7bef9b86a8d48b5989635a2a64230000000802d3160020300c08060442b1348fc338ed3d14800b659050664a2e248742410e03298661180641108461106308410618a6a454492000145cc4f1f5c5acd8677a00f47d7aa2bfe9581490966cb80a536ef0f5dc93f51788c7ffb28c22f55f7c6d68b8a7b681db8c8f8ba539e401d52bd96b7ff35198cdeafc4f13eb65a523ae8d31048f5a5112e2a3c06e53b28bfd76246aa452445322aaae0cd70acfe5d5218305725b227e7754979bfdf45162e3d76c410dcb302b1bdcb1ffd120847f7ee7502c4cb50ec073d93cc81df03e123562372519533e4f45fa99159edacfa47df528bc3515096b1ae98f7f8b8a2abbb077549e626674860ac0d1f5c2ac7fe351f4b86adbaa969c4a8e730ee0b5603920a92b2d3ba2fbd5218e79c3fef8c010529700452ef4094674dd75fea9e459f1e3036a85f71247cbd135693c11bf44da6a56edccc465d64a5b998a1f3534e1578fdac71b75f9f1d77b0024e0fef17ed73e205dd6d308faab382ae44a379a806267f40f61d133ac3185c614ecdea3af9ebe38e8205dbb4aecea2032f7946c8cf92f32d402a7ede3cc80fa394b0fec1d608feb8e85c5121beebcfd60800bc01e514a15c33412fef3410a002d0960cc90e5410ae0f880918487b67d42321beb3e1af8b4232612e89d1e56e25b306c5882875f11a65c12604b6360c0190d907605adbd1b9113003a30714d9b134c710a2f2f6eef2eed055f4ed311794cb762f0b48495dc744a08b2d833a5ec2e576b9c1857cb0db30fab18056d3d8f665257ae14c971b96394b93c01b04dd102e2a4a533be836ca441ee06d584aadabfca6db57beb12b07bab0b472eb7265033b2adf6c75237067c695e916ec2a8cf25c3e525f67005479386510b1fae51e8e23c45597b0fefbb49ee33636538dc884ffa7e2a46db441be4e0e002d75db7f5f85c990c47a477a768909d8ed7c1d7aa15080538127b76cb9dc85aa317a0a1c18ec21fd0324106b82b6ec9d170121f654e5f3d5f5998e89318297238f09ad95a2fa176971389d21962c46a85eb6b583bfed7b168747ae9f84da607e5c6204569e2471b7dad3494f2863b9c969e6bcfd6f99132a3c26b6b98b27b428ec70cb5d89d0ec59db2939011cfd8442de96904b2da2855851811f8f2162c135619675646eabeddec779158b2b8cd10d10841a13d9f1c15a3f01a0fed93759b4cc79bf863850ff213ab10442909f91ce48db6e60c579ac04fa915cca4e8ceffda425386053a95cf06e6a8dd71ea15207fb8ec1e9ab06b65e173e45a2ea4054c396f0fe95d7f0ac3684bfd7fc0166061d151700dbb890f26cc31a49f04117ca6b0182bcb949b35a944086765b2f0623d77072f10b46de2ccb0796c93ed6773ba2cdf05655777822539f309488576d3d80983c9a1db0923cf0c041e954d61850f5749babf566bc2a42bca5a915ffbe4f17a505588c984311fbd30bde360bda14b94a0f6b5715ec602a2bf64c1ea77952f1c8c44cdd7020e3febc425fced38feff9445bd84d347958b2b0be63156d5bec0c5af6b6c15f12e043b2c10e055946ed5d574a38a4f5fffe421fe79bd3b312ffa5278ef36dbe830a377e90e999fba1ec9350d7c59682f0d4d4017d8fa394cd8cac28d0b40a0006c6ba49e7878c0de92ab4fb9f0e9b716eb7b4aaed8959f2979d421c9975f6bac8e2b7ed29622aa99c5365864ec4e1dce6a3f052dc4690713531b0b9d3ff8a001ae846c6c48d4970016bbb079aed682b6177d24ab913243ff207d3910733c12da76ba4a7fb3aa79052296688f5844a31e15d3c0383cc3506d35196c8d16ba4b09a69646656d800e8e22476274d0c0dd8b4e769110d5f0aed94eb0398f44749bd0906bd3caf1e44e246e11753b7e3ff721fc2e05d4c223aac11b68aa7158af220af9f6d05c43d2500b4b426f1cde69951f1e91acee0b21857932413773f1dc5c8dc32cad148a8336d23aea8b6421e07840c587e52ac3041baf6dc98dd9e5247b5e819dbfd2921621b69722559efb945744a3529ccc8609aa46e560d116ec7055f9c23549e5e006bce60eccb620328516048716e6f54cab190162a22bc33a1d6d72be471e93163b7d3f7eaf6a604f9665697bd2fcf13303ffba588c6c5980e03498c180e9f29a63cedc90a6b1702bfbbfb5af3da10dc2f3316673f1237f1fab898ea92f1b7d711f0b74652df2564379105afdccbccf267771358f42d22f818676808e65b05973a2a15d27fd091a9a76841bd0fb67adcb342be0f2322bd7296d651c368c30b315fd8177c2f11391d51a4b900368345a102a94a8dcd58e550f6cee1a4177b793d230ef04058ee5babc6223a6931a57e1abbf22ab84b8e427e4352a952ae3c3bb325b97fba0f088737084d5742eaa9e5a36efd9c545a125526959d34b18119ab91bd59b72058e265261a3e51b2badcea2177efd978d3cc23549dfbc03471a3fe7b0f5f1958ac933e5d652011b6392cd41249d2f63ea75d9fe31c8aed70a1755b4a46f343b758bbde235a03ac4ffe58e361b789676d29fd0d84c9c23a5f49a5c0df8077edb4beb88610c0a4c4e9cc90cabcd0e1a14d2221ef71df60e668f3874b8ba669ee21d124711bbbbeab192a7bac54fb889ccde28419f2b394963f25a97e309cd422798c9b33418ed2813067c5e119cdd339a0fabb59ae94641887e689c43a3f16de572b9c6c7f7031ba1b4bc109c90ce980ef5f864c734a715e54f9c9036c446d016d0e1a16f610a974a4947ccb456044fd79bcf3f7d83acdbb73caa50bf600fe299f8dbdb3ecf58139ed8682807cb271326b04788f64d8c286428dd3950a7241047fa1c048048d7981a764fcce56d4cb8cfaa08eab1bbace4ebd9776d4f42a08fb1ad484c4726cf0deb6f7427caee5d7c004f9940e5ad384573bbc8510e8694f052a159347482c72a282c9e3cbce1705cb91850c6fcbfca7c0711ec57bcfa5af6719759f8ed1e8df861fca0c6b05224c491dd86fd49d28772dc6f4fa7fbccc1a0a6ecd7d60518bd8d6732c43399298cb01395bacd951a8cd806456c4e8086c4359328d1e0990cf512a28a3029624b43ebd1115eaca4f21a7b9842a9a80289f097dca19e9514aeea4617c7315cf223630072b4cb56343930b2145770c595080a20870b9c3c1bdf48492fde25ba8608015f459a987e14731466bda3f11cf750a1166494861633be59cff4878b42ab1f88f141b34307225288a1979058608a2f55b5b953b6470cf9bcdb5d32c3c6b8400d9fb5413df5d8c6cb36addb8aeca37cb5d719a5c9adfdead54f9b14b340511416487dedc755af3469f6591be5021f253038e204b940908d9e73f457dd6c127d76dde6d83559c367526d84b3d183fed52e2a877e7ea81180848ebf691b921c89f36812454c3c90a06c61744fc99ce31a81e18872d23bd22e1490f207f40e575a467aeaf1fec90a47ae159a2923575567c895181ba7eff1628dac31dde6d3e005c04f20b9be56203a0b8bb59de1e4c1c06d36c55fededd6d5da21b966d1a0c345e2b0dc38a6150e0b92a2538ae44333dc45456d8b22e3dc56f4871c20ef5db0c79478d4a8833978a42b5e1eb7749b960dd23a2bbc646ef0f178a70bd2ee4e3de8bc041b071c3d96b45df32a0b4109feb5f13023f70023ce1b861c7316d75d0f225bd0eb15af59f68f27b19a5b69bfe4989dd1e4e386bf09edc480bc284e62faa548d2207231c9bc3210a87f73846a641e6889c663a0493daaac742d3a68285d410da1519f440a8788a7e77e9a3dd35cf2cefe0be4aa2cbecdc7781187c18d3efc24563dbef10190470ab87961c6cf401040441ddee3cef718ef1054b133b48b4a3a3b16512051dc6a4b7bb1bfe78ed65d3f6b469305b2839f6772c8d621be5979342c53c0bc9507daf7470d98ad3a10f1d613a56e6b8de6a22296661abe95359619e4bbbf7791ac5217c34bb1a188e93a33749a83f35cc82bacc9908f46dfc008643249a923241e5cb4b274583e9649c10c60cef2b7aa79d0a06cb2cc95230ee28e31f33d64cb45a13dcf778210dc98188d09d490f0a60b6fb658aa6fe9184fd651941c069799f4e2fb7af2158e71565e3cedf5e8dab0224b4fe8102e1e31a184a0cd1d94c583f485816b265e4b421964ec835e79b63f802214341b0f9960a49ec14161f11ba27465c2e46a1596161c69783cd98cd2ea83703694a55b634d818a0a8422e3922c2588f765afdf637a3c97f243db741660a5a3a9929bb812966a78bea0fe324bb7f60b4c345813f61e09815dc93ca5f88292a9013bd0cda87917b2e69eb402cf73518eff8a93ba3a663233b28749e09bc8e63727e1140559786c5008aa5be33654190510f4e6990c8a08d8dc187fd741ab15987fbfa24c792632f01133fb29dfea5b866286c53420b1d2ccbab23c5457f730220f1e9fdb604e1793615d9b6518ab544f3d31dd939a4cf05514b1f29e49f79b7bb2c655bb9825bd9d98b1f3809cc87999980c44d0cfffa6d8082f7bacc4f734fdb2509160f1d366643a5556deb713c8d39eb899f5a69f75ce56ccba28e0cc2d1ab7120da15185ed84a93a28eebe3e99fccf60f65f3dd42459e31a95c4f384a0603aff91d3be37df9fa910b78e3b2049b7e23bcdfdd7f73e59ca88503d06d6c471ceefa2b4a6ef3550e34431523bf562837fefe8be66dfacacf1ae75d419d532f88858db7a1a357d564a0661a8fae818ebb8fbcb2e9278ed1321065d602eb82f50635fe83f421d3a841bad38c7f1b9d599b1ef65afa43b808ad07c0aa1043b327946994e9c4d7bc98ab41dc3e2b473e36724f94fdbd024d20a09a025dbdc2c54249e130ca4486673c632481e4f6b032420aaa7cc0a847c695d3502322688e2a422cc5a33d2aa1bda03a3c53cd206481b64102df4caf2932f17383197897e5c836d941a91385dd833c637b15d75445018fb035f3d00df9e59db60781f5240c68651359e315c5e1e65c65742c9e23543d4a2e8f50606257588cb9398caf7569d70ac9fd1b6c5fb939550d02d0cd700f3b1e507bd6dd459185d7d9e817d6c346ecadddbc0118265b6351b3e565b6b59ccc47d3501965c2a866572ecef491cd285c3159f6f11caa632a5230476cda523c29c5712b159e50be8076d0e631371320fe360dfad8225d5c0820dc6c72d5a81f58311527ad378a742c65805c33f0bb57a364a04ab29d84de9d7b0ee2daf1f5152131c8177eabc40a33a4789976c7876d52aef93edc575a2600b6f90290567345fb07fb5897fef3c865808afafa0eba3f6b9480a85747d97115998681f2e5153f7709ece09f3b5c355ac0a1882f07fb964d2531eaaa82eb427a6bd52804c6bdc1e475ff3c1b08067a0e2d0847a7138f736ca511499f501bb2dc1b2d230231a227eb8ca76d39a987ecad158bd9d010d5a51b1fd916a45e435118dd796be418648281c6762ca02521f58f32105c1a0feb77314eedb1e83865652d981374874420a042deba90932514ad2b706a5ffec4fb3a6fbf84159db945601d7f84c83dfcd8ffa854eb42185ee10e23fc9ff698ddaafbc365f0104f87ab53316c75960ca83582186c10569594ec52ba39e7d3428218812e31c6fbcb1e595ab268dc95a7a7c0067256abca9902aabe5532b825d490d1b8c08f7c821581aaecee613036c349b1fa54247648e13e9b3f9c0caa151e22bc411a13a8f4c92882ef5089324ac21b0d6a1e5ea381953a9ef174d3fb7ce662028e5a8f341a4d9af33e737658ffd8e86b03fd89ab29c6512cceedecb1e1703f6e2c51a49fc260288bafc976e19c161e4442495291df0e083e7cfe81c543dcac7d3af62f70b4e2b75443573f62a77cb1e87010d6b3cfdf4ddd9231819dffa9afab8a5e2d92f64ee9a743028f3317f6d29b74ca0d53571285d5494eb0b350979f20d20e4b46499c496a69b1b99d4607e92db7904c2ab05df4a4798fdb78a6b03ce26ced6290d4b625757ffeb1c0d339906d9d896989952c59119b8cbcc7b1a4a72dfe06ceacb09b94cf2d3a4973e181b18c49f94212a9b950c7e7992d94fc94ed67453369ead79a9200529d2c32fa1af88b4aeef4049f358b22dd17a2778f134dd8ecc8cd0a644684ab8517a0a89d60bfd2344f79d5b2f7b526a1caaeb0484cb5cb874b31d5768896864c9f6fa805085ba540a70c025e66e85ba4281c9bd5a340e956f3581bb0ac9e9649d23a6a17280f3369628e14376151853ca301a6445cd74e14dee6c65682cec5a1cdf362f527b35c768f486e5b4c9c9df3e3568db0d2a6d3707837a2ae78cc1c8647fe8c1b5e304db5251d7b2979c96ece6ca6a0d747d301675a4fb71712b98e0eb418307e597f9e3a28edca92b8a89f77a1011cee88999da98f8432c68c58aa4f1049856ebaa675dcda8e419c2315887a6c73342693ec9133ac9c0036271f35eab122715eb5bad3d17468771a21d74f9daed68a30d08e52f1e8800b5b85e569670813c093fb156d8ab074c5bd1fa45c118cc4a589500ba025d8973835f75748a5e2e17034aa50a36d4f781255262f5d8ecbcb7c1da674a9f6872cb23a601421a13af29d1708b61227d9228d9798013184111409b5b62bb1f60932c3bb15e7700dc3eb9dbf27248a8f8ed0a4d8149ff43b1d3ed7bf86497088d980587efdf6ffb561a3e66f3e06659a435bc5b455ca6ebbe05ff067c1988861d860caceb407a6562ab0da54a417e5ad55c6e0ae3f44d91bbc9877f623f211fe501e6c8f5572a777464474078c4cdcce73656170bc58598c87887aa7a05123c96937e3ca28ab39769dae38e3af4a5e36bfa0b2fac019160c95482758645af214163343f124206a5607b0c5a579823291992324fd4cec2effe45cd5486740b3e3650914989ce4ed27e586ca28fc0b600f53f6a1358fee1d97f6251e89549811a26ebdaae93fa16132aac6f1aa110314dd11475eadfe6605170be4431206b0ddc53008e1c11f87dc2a90698c8450dac600626802c1191314300fe29ab01c46213d085269733985fd7d40eac2788521fb5d627dd79652fcd884bb63b42d52047d212e30b773001f3065a5fde3c65572e90fa18ea654a870736c116e4185a194bc177c4e48da42c8e029874d4e39238b2c70e9fe148c6c1430305f7fc557b8f552037382e33c68121da15268ba01e0f86dfcc5a08e15952e27724fb949eabbca72e0a8500f4e6f3def9e378806e07e954c91eb9a0c6f91481d92c18c156bb95b313258a40fd138bc881afbc906815ced8de33609e367d5b6aa377f3f97a8737c0157a27bfc15c727445940bc7fe44358410bff3f9cc0e5cc95d6ece8952888f41199ef09096d9aea4671da7db0ec61fcb6e5b5488ab5b2c50a668b953f7009a9e8def04b79d2ca6066bc846ba43f11d83216f267a08f8ae1683d5dd596b0f756b37bb7bc98ae76e932aee5efdae819adeee36334a67517e4aac530dfed6a31596287f287872676c57a89894691c60a41afc099c83887bc90c8d72dcbb3b2c723e358156bcad4225ca954c715de43eaa84c8d302f33e4a9eec86318a2fa6bae0da6a1c59b8aa7623277681a8cd78b8c4d6e4b125701a3c98d5cdc83f0a1b41d8f47638b1d112bbe8317b19ba5316ba6376835014483d009d7dae6e0cf13b984a9d140fbc4a276a0a6a5afdb6535dddaec8f4dbaf8806d07cfbe135b43a110f23618cd115d3d9b8a8638cd752335ef086697c548094da524d40bc3aca36c9694f325377ed0d5626075544d7e34ddfa8e4f5099425470f99df2eff57590d9c00f1d9487e04c15827dc16b38fbd09701f1be5f5f1c73d9621d2df5ba47f0d6eeb60989cb3724286560ab80c92c865bce530785412f695f6df6b3771f7c7fabcd7f6d4d472949b1f50c6a74e7862432a49e9ad325cf99ade2f8a7683139135905551cf773bc1a7c7928e381027f38dbca8a5fb8dc3a9e576b4979e0eddbbe3cf867f97a1d2153a6a507114dec1db730eef84dfe66f824373a96da85bd728f8e261c3058bba8c43568fe18cfb0398489357910737b48a8a0aa9b9c4c6b70f3ffb81a368ee891f4862d500fa2f2122c08b53b4587d9a5854dcea0f8594ed58c385c46a8942e7631e138e4b9bfeaf7c718081d53cbf81b855b56229e2fb29b4ef08fb2a2b9bdaa1bb4b6f1105a3da5dfaac1708920a3722e668ad9be499d5e40685240950e6187799c99d76810f6c3369ff6e63262d67e030e8dd6e7f209d315371d8d5d21ba366028a7cc720cb2c9883aaacfb1b29f5e123c8ff496a578a4db060f9880f09d4ca7b8842bc73d30a85be39a4e7d11ec6afa46c438bc9b1b4118bcf2d1ad27ddbbe3196369bc10bd49901c427a82eecb766e6f840b71f04d1b88f7ba57ef4c2858d8f97248be5b918c357daac02e1f79aff2f4a06e783880fc4f2d29c08c5b286d3a62da19ff5269f3f049dec4514dc46dcd187191540737df54479cf4485a2f5c0fb7891091e9d0eea9843b710f866f511ac2789e815dd9cc7862ae35f3e2b4b26a5ea16082c99bae6117611e972f010127ba9162c9c06cde264e71155e47e697f404824d0c71ddd18c21c359bec9b16ddd7805bc8b05ac43ff4537a3de5136fca10d1226f7a6aa6ad4a17755f22fb672e7967082c8bd9c0380cbdc590d1753e849ad8bb8ee4d03524457afdea5a352f1dabd5d11fa0df0a57d9218bf9fb24784bec82f273ad8e1b498cfe6f70d94ccab3a7ceebe6ed60a4a19992dc38bf5add5b80a5ca20ccbed33ce140d03d2423a9cab858209350aacc00e434d654f3772867be118759556526b6be89b3a63c7a7a545385c0f0ae5d258fb3a5b2fbe32b2b7d4f40951b79bcaf4905122ce5ba3146969ff5ace88d6d60d3a0808333f225582e800edbc405716e7090c7deb05dac382ac4e82c66e4724f7a876c2167099c31b1e7587a1922bef0af7fd9443cb92742a071be9b678502584cb931e0e44de019cb1cb6bf07fbdbe53b235e00b0316c2fe249540731f684e9074aa07e15071b75133e779f1062f856b21d1dc2662616748323349f38bb6d4965d199ca7e2d71eec6caff402d5e43cead273e3912cb8650c748ce24d8c0409c47883f3da46026c4995b828cc8e0255f474a0b0e2894f6ed20afd2aa8607349fe1f7fc0ebf0184ba3f8988840afa2b202fb55dfc5797d7fdb005ecdfda5191ecc5c0b2489fa249a41bfe623b01991188eac13d6f320a836887fa091871d8f88bbeccdfa1dbc26e45edb88aad83a464405a5e976a7f11a9f4cef88e93cfa236879826a0e8186dcfdc67cd33d05ca56b45252288523bf35fca50ada65a9f20e57eaa0e8a28b900b48dbdb323cc312eac053043682e235e6805a1d50de9b771065a8cf77e3d21a0522136467e0260c05fe4591882f08fcb46f11c87649843725ff536dcf788436792cb3b9a446fd9c02aa2b5773b4d7474ab7307e8836e157a17446c7692fded6dadec52a300cd95e214735a7675adac5aaee5dfec255dcd178dc9b890f8f0876264a9d840a1d7da44502ff19133a9e781a1ab6c17cd2800922ac4f7d251e21c9d43d9ad1e0261b7f0dee137cb5f57fc65a274bf8241c89e856e9f129434fc48f1c711d8449942d785a515c38df209bcf41fc665be73ab583c32d7f4b31ede1e19d41acf9f10d5e91fe9f624d733fc3a19cb3d2d59619290e94e1feaaa9b7c807027a973a0b8d6cdafdcb3625a5ab1b40825f92fe8a53a275e88110f2693df378875598bbd15a72045c50dc061cd41730263d1903cf2645f55f18a230e69618c0d90872ecd3489845ee286ce4f4829ead84f3261bffc6bf1be9efcd0fef090400d0c8a36caea68df0d88d4b37ba88ef7047fc8a47ec2b10a791d4dc9997d3e0bed6c780edf953e3099cf9274545e078cb5d6499f868d1cf0b665f69f276f87b5bd8b8ab93c3783278e0915612d39513e025582411a6f0030c8c6283dd69cb1df1ba539b309be5eddc9b90098c1567de59c4a4f0990d1a38774850213eff7f4e048010a2f56ba0ed3929cbb48cd57c2563fd50091cc3c13114e66acbce96d0d03f37e3076515b981d1c606ce395f832baf1ff43d57af47b0e0dbb60db3c598b5ff6b908f6d6ed61efa9995404825a342ad1da40c78947456f5c1cb1401db0828b2929a5d33a89b50ffeed9be412206edf52780baac3ab2c6d3d1a38f0c80978af9c44d53f1b0c27d3c330d26485737fc560035d34ee26af95ed91f4117611e1afbab95bbafdc5bbc4a5ab79220f8fd09f46fbbaa6e030d950fc9bf90e3b35a765c0b1919a64e7f701591902a0528980b718cc78b4241a5e25a761bd014ad8490429fde16e1a895d2b12c505e0051a13bf2b732dd4c6e9c01870266d1ea083792919ed879957533a1a7216b89d2b2e3600ccb688a24a16c7f392495148134f3d5078a7499934f15208a9c19facdc72f28aaa7a38c5297ab150f640be12b0a9fd1aa90a48f3926271f0dc5b46d028ac133b4fd88ce951843e405dc5150a77a339896a6eb12bbd318a43cf6f2efc2c275dd19d9de1747b8da94b9810fa41a7c62cb26c374b72357c013665f21b50576458f5a06dcd73a23cb7769195b0e38c24371fa8e69321c0beeeb6e5a3b7588591766a3562ada6f24f837b429032ee9176ec1ec5583c271c47634ff35b4cefacbaf940b7e31a7c7d3b4faeda2401b46c25fa2e3eaf3ae99a537ba3166ac4a68e7469a710e1130447a552122bc227eb78641b1cd1254be7956c264cf179cb1f2e7884fcd6c5a1e90a41ef2cca5862a5ead2efa0c43e4247163b6694cf1fbac73cc55c9debda94847b2ee3461c6170cf353fc64b5a6a77d22888dd16237a2ad23a9c5aaa1c7bef733b2efddc58b096d5659ef33b41cd47cffd79ac5daf0ad6ac1d70a8ad7b5c93e0ba2653e8082825af58806bcbe43f7138b2b93e618252c0cf3c85fe76a53f1522bb8ac153a3459c1844a130caad5856c4ff9ee09e2ef604b35fd3f6dc873948dd40f93ca41edd1626a3ac3420ce835a429b051cf6857f22b070ed90a05e3912f408b64f790f3c00dd3b9d86ddc0a8c82d0647e9efd10243afc288582c1e79aa7fe8c0d8a2f3c482a0f3fe0dd117113610ef0f81cb0f39a7a1f9e43a1f504a5c2dd1a261bff4a6025a426fd6e6b62db933b5b6473d558c53da96760b88e0adbd56fa0e98da85ebb07176fd7e2c7fc518b431ca5b25ff42c198b994c7a30f02f568f6b27412a3bff85d010cfafb42d81596f1821001c1b1ae5dc0452bfc9e14136cff29c57f94fc29dbf2c38178272f4b81be1d2c586671e63f761e43982e064d94cb79ce38cdbaeb87db35fa5b68224588c09d54b0f17a7eb6ef30b323810d7ecf30929907b42179c0a1826d1f678c54fe9a68641f989997412255f016317eb9123aad5e903095cb23884a7f9bf593fa57202abd01c59282a9a5759cf5f0712fa917fcd5168b97be8787a25f481e9f12d67e233de7bee99600bd0e316108d2e8ebba72c15a2d9b1994689eab0a21ac86930d340de12b439462215b92d29f05f59ae2cdda3509a866565e66ea5da096e2d76f918eaed266684eb7761bf782f80c2a32640260814b9a5c6d5ec5fde49f173d1252e54c767750d118d4a778152d76904167e95f781e6ae033042136632a40faab62f4d3ef31783914e6d9575e5432ba5404a1395e70c361bfeb3fa3f93d218bf51b59925b3d6e7b1019136c2a34f152f734e3ff896f93c443e34061db9ebea0b4eb3b1eadd916b63df842ec427c1297d9a29cfc3c54fcea36f79b88abf8f4556fbdb0e58dad5d23100ca50bcc8877be225baeb020d486409470f2c51becfc2a5042b640f79d0dc2bc04a3bd1578b27a471f1221c87c08de0883e1f60a9873929444d5c6cca3481732cc8946a83501783f9eb96b8c45d84022941808db8b135fe5ed5abb6eebdee1d609c2aa91aee045c4d59b9141c0d01d13d28c5500b76d6e67f90ed2593701c0f85a2852474ff0d13c8efa2658e4998421214378b3cf9dca22fa858821f189de812cf34ac5bc595662a16c725126634940bc494b994ca558318be04f63ba9d3886fe5aae44add493de1f11a0c05e01138d97590eda5257418591013176b735ceb6160991458425fdd1a28b747a3092aaca17844d445b71c5af25f6ce4487f02bbc71f96db7af99f63c1f0fa944d009115ad12c0192db328f1b222289634ce6535352c848455a9723d50de8dda51776b29630d0d96c6750c90f2de9548e27af9c3d3108bfc052d7961e98e609f784fa0708ca908cb72253383e0e015387e45af5865b1c4faeb69c49ccb5fd54b9ba307b01f67580be33164d157b9463c95a9935bae271ee01c6dde6d9928d406abd9f1b3759410ed3fc6cb8e89dc6fbbfc4795287311f8e2f2ee6bd1126ede90e41ad4a3f0da04c3e957c24c28b693749aff1ab218ab66d46cb168e442becde62a5000faac101c768a4eed28c9e57b01bbc97ceb6f1b2fba46469d01c6cb889956b374f2d0ae129db4ebb275edec2cb803ed113d088c3070fd5ee4503c895557ea554e37a0e46ae5526d5aa54a07f59bac03194e89c88bb4267cbffe442b169936768c43ad974269a7400b7cf6761650498e106d50b95001ecba8d5a89fae53c28a7744fa979a433950e10d243e282e2d98dd02ef6121ee010aa0e2faeffe085d9b813fcf39f144d80d7db5908848e951e8f1f14abab096ed187d76434b52674221714c43e3f6a855de037f5fef75d16b4a1c4943e1de9a5c37d43ce0d3f6a008ec4643729307e0a79822c9df08ec2e71959662a737b782098001388d7662b211fb80ddf4033c08c3bdae9e95d33c39a2ebee067a33c9fc6de9c7738336b9c4cd4f196f4ca8f5c496e730c6acfbce980be9a92e7790e53eccfd785ab7cb0a7b93f9aced503a66d3e3747ea432c33b88d923c8bdd884e5e6fee0f009ad4b8953ddca736e760b93d64d3971fdb9fadcb65b603d07af2a671107c9b957b6583a3410f04dbdc40d4a3fada90b6fa7ae4601e0f0a8ce008816371042619cf9f9df9131ea9ef8a07c8d1987994f81b869901356e77e6eb503edcb21acbffa425514606ddc471d198746f47a403ed25481afa12cc854ec5dbec02e0832eaf4d0ecd73d024eb7df1c62204f52a75ef557b36012b0fc191cc8a77cb319ee90f88e31e5e8bbb57644a3c2926a155f30c54f2a9d6f4a3d3796d605527f99ca408c79d2f0db6714fae9e2aa96474b61d5521e50197d6dba13b507973de61bc973f3d32adcb468f21832e930e266a71b3bc7da11c40a490459793c9f1ef56a4b87ccca436e9c6907cf2942f494420fb40756df2b25f6e854eb3fc971e8f16a9c2020f79f1ecf4987bd3bf05ed79e5ac06ae9a30701d14c54b09f65d68fd6b84a7e6285e1c77899f02169f9618af2b05266b38eff8692f7ce892bf70612fa2eecddafd94491d9c96a6aa3bb2263dc68e9f0a5569ba145e3d14b4024296bd5843c32fd46ea1b2be331fa5872ef525fd7050e1608488d8c1dd5ef35b3a30d91ee4692da05c1b76d8dc780dc844095e695dbbb78bbc78343006748154800879597eb52452e7da2846855e6a6ecbf7b05ef7bcc2bdc3d8048851a3207f6d8bde9f120428af4a1f13abca1fe427b2cbe1be8c344bd74bde366b95042e2f7d0c0e863b053c0c9f67c831b4ec711a616900a0017576a363c687d520bfd934be8a337f90f806cbff14ad9022049ce6d244e769a3b067ae285cb9f6dee0ca2949fe5f360c3386a735d27aefb4e31101c73151b1f3c639eb725fbb2565cb63bc8b4380db3dc9f601cda9a496499eaf55f88d23c735d70b727aed17fd3cfa83c2c368df544bd88580a2ae3931822a6c56a9082b2d94a5d1089af18c7cd4840ac189aa265590f0110c328bf970853abc92568a80404a8bb1207af3c5b819cd6f3760e38d2320a1b3e6948715b8e22eedf23334f80225a3bdd679c46c664e88217e3615ccd992764343870c08a4ec26e8e6a24fc2e14d1e9a4121e0e6c31ca15edd180ca52be8f6ecc8f5c881ba12ec5ed0260a52c2e7af3b15cb8072149d62241ac7026149a4398ef62bfb063a4a905b1cc7653e443a3333bccc81d4f73595e615e71f516c680116c3c2642d98b76f710f9be08d49e1d1a44e79fc51d88cca4e25e572385b571c91e9917b18921a263d82137a42a888c615ac097230be41613997c181167da7249abbb3072bf8fa49c277f90238b61dbc94e3932a9d1cfb35f51587fe6648ac847d94a194d71f0e4107cb096647e6d120cab11f07df345b410c4eaf93c484e602a0e551d111c84669354f49d7af2978e979b42981065e4bb49d0a1f3115191417021e141b1f66396310a26884884ab87dc124d2b40be5fee5fed0dcc248bdb49bebb9b7165336fe73f0c16994b24a6ade844df7184bf3c7931a8895e567bd4931c18882acba27ae5f29c8c54d317becf0d9e083aa3e2c3028f91306052e33e08aade03e71864451a57237b15aa6c63a42b32d181008af1eadf60d2a788eacf5e1f8f5e519e9c1da2bed8c88b37d3a033087e47059f060b41b4f1703a0839cd0b9c7c535ccb66ec014ade130438da545e9559b3a0fd205c2bc5cd3b4f37888670b8328d026b137e081b7992a9cde4228ee5b2c7c262e3a9a3c48c11000749e508cca15f3bfca860ab5d6272a93eccef9d27d34e81f77a999d17e04d8a340d8262c8e52a69c14b51684dab046c2d10f22f186b4a7be4e287c7866398c01d08568b808128b196b4cfdf5a50a519e89d665aeaa01f116132631710a69b18b52db21a6afc84d6b259a19a2adcb01313f51da8e52a64222a12c6d10fc5a67a4fc3741cd17eaf06697096743e29067966b788de258203209a8eb033f5922189acf0def82aa49c085982049ddc137adb121c47253a6067255c84c978933ceca7b8a9619e5f5bf951b9a20dfc4003ad09ea2585f1e1a7fffc2c40461c0b3bf22efaacca329214ed3fdd3c1140c843ec5c27f26ff15f291e6c6dceab5d2daa3aae8b4d77999c120d039a0f5a7db9db20570a4c76bad4cb4dbfc4c254f37d0890bab72f88997ac5b709270e582546be6fa5344674b668e3ccc20e31a5cd810cd13e4ccb053f6ca0fc0327e1e87440fd3198502359e635040674a0fe1fd456791b3ba0c2515a70caa0152587ee9e0e033a4b15a87cc313e2ddae6bee1b03fb6fd3b0f09a1a1613d912238ab9edcc30add23af84a5839e597087c28796073830c432f958f0ac92f3e79d0b75d9d3808b8ec25d94375b30250173aee472d1f433fb8097ca9190310fe15d5f95e3f8656b8c0fdc4e18b16350589ea34556a446e8f46cb127540ded72e39a8904e60b7b1901a48c03fcf060d9dcbb365460b6bb22a7de751bd1c57b1c1c8c4d3c6dd2eaba87e274df7319a8275f9ca8cabf57d4d42a0cc1b6c46eef8e86f66f125b35eadf8ef5f009818948b37b5e3786c8f8c4d3b61f088ecb623c91d4c1d063b548ec70ff93698ec40fb1b351edcc0abc2f9d9c231ea7859b4b703ffb1ba0d84767f9d59142643028de6589a61c81f9d9612a4b9fc0058a3a0ef4af08f4e1b267e4d09856a8080b5768b434cfd115f226799a599c3d292b9260c458692468beeca40da7742ab40de86390a70fd80d50ff690072e54c12dad1e7c01421f49bfdf93837db8502e015cead83c11513619db7ce8244b9c836d36e3725aa96acb14e0f2137ce2d9581437958c0722cecaa8be8e51a55f0ccb324c521e5a29aa73ded909f8ae2ba61b1a9114c2309ef1a86a3033685c5c855ff09cc2d8a3c8a18eb01b2ea275d4c339735dcee3d97293f50c47605f8b43270e42e56a3fa37894303cf4e500a8ca5bab2a0d1c3ed271a66cd663bd99c362bac00cbda72b0e87c11d2131528f91c281fdba0cfb100ef3a7f724a6eac92dcdd3b77975c315860af8a66396611291d8f0a4474679d75c454aa54f9eca62223c62618dab43b44d259395a73e02c8cd8807e26093558c10d6ad747fa082463f4ee98cc8b1130c6a759110f3f43f5635e64684e094b51a38b56ebd000efdf8535e3593cc04887d89b2ff9bb2df8f51f178f2fd520844c8023badb7703d622ba228cc2d6669746361c752bc23b80a1eabcb567d2b0c6abdfb748b8239b50b2fc946563f6c135d20d79a174c4cea6dd6d804a927900f1ffd3096b57b091200d00ca52934f3c0776587c9f83d8a905de1b90c02411f3f04a2c75a9d6562a800786afd1076934c412747ca8faa480a018da09c06be6343a242cdcb502663c48fb7559223be7c384b69dfea943208e5e6a241b51fe268248c7c8965e639dc2098bd28171da4b9424fba41e8e2d07bce483ec863e355a1c3eace14c58c10ee4dddc64a1ea1a9b430c831b324e16a7cae069d7b89106e2d37b4067a2b64a28ee15b4543755fac47e00a3c19a90639feaa0940a6a4206a1f868cba562757ed6b4ec01de866f88d07158b2b3e55bfad0b6f4494a678818e5e270b65f3796cb0c41ed9c8004eb13cd8c447b3333811c4bdc66eede360e6f662490ed04948f13554958a93002a8c27218d61f3b7766aea829244ef63a4e537220c5a02db087e9ed0b2735c402df274f43b7243f7b0b3767b317458b9721fb440856ec89437372902a36913e09975ac73cae56945fe5e68154ec0d0d41350c60bf25a5648bc8318fe5e651f0c90503cba7189860b361507b2d6dba6b8f957d8a62d31e38aa10eb95dde55a586db1c908cd316d9dc6da4cb02f101a00092f8cc4e2437ef332167d708451175afe9f414b599bd45c751ad33b432d0d30eb9a7caee0b4dd5905726c3741e323c7f48513f77ee4ea717554b4398010e17ab3b5a1c258df1157a1f64dcd5b81f877b62aa9137e59c591794f79ad02a6b6db127d138adbe3244d4a1603edc735e7d4848e578c883562dd6861881d3854af25b97b94c22bc03e4f56daf83cf50e2289db4b3a88bd4595ffc1349039cb6e74edb37bf3bfa19f89f1e7d7a12d59c3d137b59c1b0591823ca82f70c6c0ef7999547b4f25a253a2222b6b6dc8538067aad7b23864535888c3f07c23570ee4c166b51431ee47348e3bae6d7cddfbfde562d6aa524d2c09aa6dae8867cb706865d17f07ef29fcddc7e6b4fef0b52ab9b93cf8de14af0d80df470e5f1e9221f6b19e4fe70f7e163c6b982972759afaf64be7146f4b9dd1d3eaf152755607403913d0980a90291234b704c2c078c15f82388754ff6228f90a4bbb5ccebf9137068afa6efc90097b006f6f6c8a29f890d1048df750048b800491cdc8cd5370fd7ec369cead78045932a308e5eaba1c58371e6316a30fa1f313da0b95209252cd3368582f80e3b00041000f88048fde4beda159c613e6030f1b2f506d23d1dfef3a90c81a3af931d37db4dce2ec9af02ea4874d9513b81a086cc958b54e29010bd70bfa39240c0a15211838a94f31e103d380817e04d270de59c426bb82b1f303a53953480d22c0e53acb70df4388ecbaa626892af12cdcadb8f6d78bd5a7407db58b21511d0658745f6ad0e80840f3ad83a6f02b0dc8efff2bd3f1db664a758da63782c76ebcba36162c7607664a6cb16412acf7ca5c1a445e8cc6ff1395bb31f7463250633034dd2a2fe447f55c69811ace8b56763e6c88bce2f384a480e9c884cbd9bb0ba342bb5aef03f4cadb0576f7ad60fce87b7f5417d34829cb16ee7b914265f7bd694881f79bdd9fa84c307c52ad2804b87c728467f055e986386d8cac36d861e6ddcf8c1db922d5132254b0296e431d4140ba0d506c873a7dd838a448d8304711531bb32508cc1e938f5cedc037810b6fab436433d8e6c705cc298adcd1b2ba5e29998d6e6162ec11f290d9b0a7060d0f373dacbe367992bbd5426522a9aadc1f53dc884f36b44fc9a3cbeeb5e20a032549162d369fafdf8638593bf672383096d0ed0c61fa770c1408018f33d30e12f3ee1562360ab27e6ead08c5f8f0285144e03c086a02e0fdee50654ae935d97f5f7e1490b2bba10b22db7449cd51ffd794e8f813fa5cb6ae924ed8f5d6a41d72999a8477eac0e1fbf6ef382d5505db31284f4842864bc087fdccf693f24240038556366bfa0167e2829fa976dea3d59194a3e9b238694a400e5dad742414dcef6c83459725fb2e08e725bc29489f3a11e9d5cb7aab02e73d5ed0bdc9d5474e98325dbf29635d8f3b6a595998aa7421ce226220faa6793fc66b56164ad01e744f4ed000c28785e92821205c4f4db68bfcd2dbfe945a084e83a39ae513825b87380a365f5714ca9208e3fba00f40e1fee8414dbacdbad1c836463d87646438cdc1706b34bf5da10e25e9585a451f90265c381ad722cb3d09f430140fe9c34077500019bd2e1b1c3b7149019218b4607a551945e33ac509c150a7edf42dc0b80d9fb425f17812abd2d46df5955460f6acbc219a08921b3dd4ede1c5624da88294db4b7605f082ccfa8b298b10ae24be1c4e78f19edd466465bee2c6d5a4445ef790df1f29521d34f907b9d48c57f6ce82c91bcefc5c2a2d6e6a9e6f66b13a53063bb75a020f37fed04f0e81155991bbb6584a9c4a18eeda6d88c01cb5965e5a4434032ff7c9df0bc9b5dbdd16b57a1bf749381d17e8edbbea62380216cdfc6d5e6ba4ccf692cf9b420c25e104b414026cae1cf54ff13a2cbd4bf9b8b88731647c3bc9b9b688d72e208139594ac36f83ed2dee804c88df06bff5709b013af34edfa6483317d962741d7166f8f4161b370d4e92454b7b065bf9f73ed982f81e6b4843c6d62a2f5623eeaec53148f8e1abdd543d32cf5819701293eb29c3c2859c3467a30cf7dccddc24bafa1b6ae1b14221e20ed836f2377d0c2bbb9c3fc0d8cee131ebd901277202068b98e1e89888a01455066734243a76ecc15ffcb0eaba89129cc5c861be43ecc539b97d73e1ec898a4ee623f589be0b75e72ed67ddda6ddb7fe6c880e9eecab18d80a67335596dad9f0a68514f085042786992ef749de1ebef0071c6a857da30227cb446689cc4ffa23e15cefa8bb2f8a040ad3b1a2b1d675b611b4aab0deb2d24640506105edb8f6a3eb1d8f8319e68f638196c11d015099f5fff75774edb3900b152c8cd39629fab9f7a024d0849bbf8a8c53460a407cf714f73e8e5269f9b17bef455619efc620b6e0eec68496ee70217015822d16ee92c0ad1893746fe659d2f3ba7d0f73591f71594a966ffdf8bc922361b499e8d4677a85a51c8349eb7d3bba0290f5f581937299cc1be593a30b4387333bcb4003c9d31d14fe60d7b1fd59db58bdce62d690d7d9a1cc81d963b00212d3bdea37309cbb3bb6b7204c8a54a005fd5073859f591fe36a0bc398dc0ce16e3cecfc04be0e3ecdfcb07316dc484d62735a63c77f18298ca8c8cbae4064f768e0d77283213855ead0075e22dddc5100c2099d1f5b2e0817c4343e6e04a80ef18410f20c18f78296770c5e53bddf78f562e91f0a37e06b55c1c1c7027f2cea3a45781b4e5da097a40e83195b7b7dc8a1947d9bc430b66dae5618980ae11a7069eb26d8593c76ffdcc73d3c76e0f7cc56df32e05d6d4220c6ec5524587b3e70a726b69c2f402bc58c9b4646e5d08443a8966cdbe439d491e49277903ba4686bf5c65f50a369738492d6c351d085507cbffa3926015da181f1c68082988896a4ab0e691a82a8d7a4a4e4ad6b664a4d692e402b4d2c4538297c606013d1136edca4c645901a6ebc3eaa6aadba4a8aaaa8737392f3fa5e9f3561534bca77eec11378700f534c99f65c506b207e5cf85d2ece6f4922d73315a0bd092b50d2a38951befd976bd844a73be9dfd474fa7cad624d20c5925016de07b220de4e8d7d08a635b05810116f8519d17048e86cfc049bb5035d1a91a72f70408e89a8a58886480ef81e678b267ecd1d59e502b567e574157bdb8f0385fa284168f409625543ff536fed657dc955dbc60371e4bef0275ba6f55fc6db29db67e54c18d7bc4cff130300302b3c1644d58c831ed7eb9bcc89f45232d48ff877ab84176ecc5da6cc3606d7e033974306b47b22fde33f17e9c2147bc883c2eb39015c94a233c09b1ea814eda96e51c3707d43da7c757a222ffec34d7c01b5bf33d95037dc4033bc6b8b2d73de8790db9659f40ad74bbd0174aa727574b0a68adec9fc6564d1c478d6652a5889bb292f5e4dcf0c2e2ac499dc28b1f838e73b8f99ea0b3efd12046c795938f7cbc7ebe04d5ac4adf4bbf2498a3742ef7038289bc1a5515cc0d2ac54eea0e91aff090e31f646fceac42083b46cf2bfa7af3c1211146fd1987562c8ffdfb491e6a8193aa12e71a177b8f40b7c81399f8e80efe2f9b47a2d7cdeda16c0a1310bc2d3b2f45d9c6bb82db9a4d47c991b657f01d418a30e61f1efec955b5d4033419582d7e0a41f42c8c184fbb8746c06a3b0476af310f3ff0a872407d17a2f939a5946648900346303eee8eee293885f9c7f80b23bcaef5aa05faa87e0646b65c3590f62001d7990b118ce2ec6edf76034a3c3c3b3b293072383cd47f2cca0da7a28e978940306ddf833f3ca489e8de5d86adfd2b5f065048706394c3401fe77d69ab0f0ed1b6dc23f55c01bbe3e3f906672e33805c33b63c32d9f33454450cc546d98326333b626743c175ca30347c5a5293609dc498906b222211fa035a2222ca32b3679a1f847843546081df85cfebed718858759452a9c1ac518f4456c9db745277f8f63fc82e0503b5cde39e8266342ae9f5c68500acff458594779d7d2ca1480ba664b571bdaf62866d163aa2ca9d8b350908f148458e96f847072bc0eeb52ec0547cb3975f080467aab76caf7c983a3a1a3d6b2ffe73614b55437a01f705ca29e4c2eae81771c53e95ce6415b55f5c3d8f94435ededa5ab23e2ade3f1c9c6aac2ca01723de4c066c3fcb7bcd7da2b6c723acf5cfa38d0d7b1ffdaa9d2c8c3655f5cc8d4aa39768d4c3f34a0ddca9e98df163758790e3dbbcc627042034f95688201656651e11d9210797cdc28a88cec1b754658ca45cee421c3836f3d44e698673eea1111366a0ddb45301340aab3a591208045420e6cbbddd69d7ef2713213fc4f7e8694ecfc9c663845df46e15aa9dcdb2b9b91258e543ccf12c288e9f9291e2dccad994f56729e45643ba7bd2e76c33d17900a9d574906d66baa2d3823d288441a5a84f4e2dab902d6ecedad32ea9a7d204377783825181e5d38c90834f5c778b0b6495cc97862b96389480e556a3344d9280e40d1804844594393ee26d865ae2f36197a6e09b00be72b08c4f71bc2d372a96995d29e25f62caf78d3f754cda66da871d31c5f64eaefeb9735b34dc4654ebc0ed37d30746b91283040e9e47f5a68d72b2ba0964e890bce4118cc569b9e31c501568b4c211849e20801ef32c6411113f5da6e778207d73c0d5c01c2780d1e14393021da7c54925a0ca2ccd271d996566eb12b8073ed43b3a9ac761b4841bf7226a9c41ca0c7067626c28e139e801f81b0b6cd430772ac75c024272dc8d7635208166dfdfb262e8920507508adee94ed3c10a03530e39c2a71534f13c28685a9b2e0b83d8d5c074661e7d26af6c3939b771df5ead9ef9e650a039c8981af5815f50f27b17f1a1fe08d5dd45efb26bee6252911c4ffa8bef1382bf00864e3d3b174fa57fd0c5d72360fe74b56be05098dd9e7830dd76f70d309116f85dcb5ee172e871aab69b219b74360e6d0684bafbe52e3104333f4150884562185b983c3c046511235832cc1ca922f1d64f1d1c026cabd828031930a95219bb593dc7e3ce7e08d77bfb9019690f641fd2db115d0d832dd04ce7109deb548cdaaba424def333cf8a9a4d9dced2bafc5236cc82377b40c04bbfa7ca00cddeb8493851b7e27cb9de1ea2d26da382a7bc3d54e8a8a231374613c2c928e9fbde524677abdc7b6d82677893506227ad6dd7edabd627384e95c0e56ec5ec2c4278e01f445cdeafa2db586830cb666e44614be938c6b5ffeab87ff61b3a272062b844ae111ac2e6cd86cb8992c18540b59cae6f57588cbe34600d079b8a32c541c1128d0650822dc0071726696cdcf1bdc0c399b19bfcf2dd92906d5cc6d949045ac1e9ddb916000f1e228912021b28d7c129dffbdd02afb0b61797ba5aca603d83dc9d2fa074b021d8a5f3c05e22208261ae1b6311e7cf2e575c1eb17c4ff33c484800f2438a92f571b6207a29b962e8e3c58c3859beafccfdb4e1edb6ddbac22c184a161200f645ab435fde33ed86d22d5e27c6fc6907c5fe471eaf4d442d8cd7c099d79bba947b977288dce0effb2b845101aae2983156708e65753ab40f498a72929fc9824c545f13672fc6b5863fc09a5df3a7e862bf074b7c304d8ad6137fe399b736d0b39cad0df424f752d23650b21e0bf59ad7f235abfeb6d8eda7c1cd36584fb30bb0d0e44e916dfbcbfc020b03f502ad4d6badb5d6607345dc10d7dd30ec8ef8577eaa6f8646a55e2429351f717717d278733804becfe78ab821ae3b94bdbbbbbbc7ee88ff18b08af0a9d01ad1ac6b9822fa94d1a7903ea5f429a6fbffeb58a2a12affff9ffdec773a39040b9a6d694d2cef5f0677651050bdd5dd1daaa6be39b74da07a206e5455cc45d0c5c265455dbda8ad44071b094f37927854d32f171d7b5049aa6f5e369dfa44e529b2c401d782b4b4b63dced4ada496172cd90c4ea1bb3b2eaabe59ea552bc9e55880b48072f0dcdd999a3653d466aadafb88094b87e53c4e44114a9fa409ad9329453011d0047f20a3d575856401bea05b7a0098e668c94e2ce794055be3d9ecc819368bdfddddddab82ea9b8946e40e51a5dc3b031835a951d58ccd51b35435b55531f1002c0ac4a0f32b624dec18443912d91186688ca24440a39c3e789dfbf0bb45938c860fb0e27162815f526d79036cffffffc56f7d33ab6d2d484b6b5b1e8e569dfa2811b3b7cd6d3adbc6aa37c09e31b1a3140b6e527023800bacc024999f1466a209e0717beff6d6fa748f9d0e74038a817c472d9c329cde7befda507d73f1985c36496aceafaf2f9f1a3f391b28342e0682ae5f2e4a3a57546820e16cf6afe399eb5a85fa3434a8a1440d356a28526b764742a64254df6c44a2a828b70bff586bd01c1b039f667edc7bef7d0453df7c8b7d41a283e831baaf3e8711852185e115a3f6aedddd3d7adcdb6f23fb69a9413c35db55d76c78b17baa98d99cbd2901a894544c2aa598cde7ee3e2daa6f3e2651a64bde503af46a6532483eddae0569696d0b4b8b9270a4b4d61c42dfc85493b6e1939bcdba543c9e197dadc4ae881be2baf1278dac339b2be286b8ae0a4aa8e08a0a24d74dc33822581c2b399cfbffdf04eb7df8d7cda552c32a5c5c8b1fb20b2a6631f784da326ac1878aebb6e215b48d80366490524a8e8beb9bd94f71117a97a68bdaf5ff6f13d5206ca4ed7f4b05be7b1e6bb59aceb3110b5e4f77df48ac67d5edad42f3eeeedbb78b4c45e0183a62c63bfaf63782d099aa85049615a3539629cd1467ca33059a12f54b1396264e6d0e2390c9f9a03e8a767a689aa3e11fb140f3ffff248eea9b93cb260a09a71629f6863c57e5e3bd1f56da7b6f64527df3b2e97c424f9051dfc0dd7dc409adb54ec152df3c05bbc53e1295e06f205c7d30b8ffff38c5f5cd6cee1fce33c3f5cd7e3483ecc542c8d1837b86acba66e819977875aa2fd472ae23d1e9b06cf1082761d3cdfcffdf30d5372b3545e9939b2a91141c84ffff308f01563657d6d2767b43751b9c4127d1697422b5fbff2dbbddbb7615a6a7bef9370c01530471dd97b2fbd1810acabb2087844bd48197d813763640e3274091749f147999c0fc91bad2a5f4e07ce0c00fde744af20ab021b569ad7515527db392a9d454521565e42d484b6b5bff2f0a5b14b0ee926090b200e8b9e1ec304a45457d68fc8406007a89a20d4901d881707ae9e13aeefc64e9112b7b3724a3838c0d878b1e24b36548cb086d90c94af969a9b74c75d31d1e00b7a3466f018f898066448e4b6badf5ad4a7d33d614c40dec066225fe9196d682b4b4b695f9845cd775fe5aaa6f6e3a35085f4f374f9b3646349588a9e9c4f0d0e9a0ecc1dc38117376963b27ed23fae2e18188476c23bb71775f7153df1cfb82c49315c61ff9ff77f5fbd4231541387677af515bdfccc64bf1948a9a989cb0a508d751949c2d8df7ff0f77698021800d37c00cd1f5cdac6de981039c5658c1c51d61301a6697037228417272a06379636822e5c48b7e699292354de134e049aa8172b9eb7c1eb6a236ca5655eb6e9bd183092be7834503cad5ebe0e375cb1ebb652694ea9b99214c28c9340a0c4d77f85dbbbbbbd5d09395540537456a17980d2856b5cdbaeb46feffe19a0601e75add22739f50eff686eaf6de9b0798fae65bec0b124d7a18dddde19c550a4ad55619b38b9da2d35557dbbf0cc58d7d429fd1a7f4e9f5540b09732106e7b24a9f3228a355d824e8fa66d60dc1bdafb10b003086eb9bd95746edc7448f8a334bf374f85e078d106edd954b00f507ef88954d76d0cd3a8c0c9c9f38455720f14b711cf6806480f48e0ac6369a4eb1c06a89b318b7202dad6db93c66dddfdd7d17ab6ff60589c6103be48f046f0e128d274ba488bb3bac13f12b5c8f999f1ed197618bfacb350d254cff718ddc86ddde3d5c2dd6d99c98242e894da293f8dc22303b174a5e2f98bf79087449572216713b8367331f49433d3a32e828837084c21e3ede622436288edbcfa7ea1e29e0d552f2c452ea0791c5a17909bb85c561beb0601831cc18860c53c22d484b6b732b9461efbdf72642d53747a52644af5ace04a7e77bd7eeee8e4354df6c6491ed098e12c48d47d4a41be22daacc2506d569ad754d7d73aef71b168f499bbc145ddfccbac32331a68d92e78ab821ae1b1bb13e2dc2cd484f4a5a8b2bb813844206158a1b97979169415a5adb96c0a36b07d4910ca3095d82c587b73a32c68eb91d1f0d98b1b475f06393c2c666f22c854c3a29be70dc347974dae647a765e1fbc97cac4f8526792b8ae633c6828405cb028c66cbebbbbbbbf7620fb2f570eeee4e7223e9116f25ad58881896b2d80922132dfeb2181191ffffffcbfcffff7f8da109c4a924339e6bfcefc26ad75aebd75aeb9da2fae66372d9743edf6407ba59994f46830364d290a9e5b2efef45f5cdc7e4d2d571091933a7cadddd9d17c74a9a7a1eeb098839a08699a8aff1c933b9c23ddeb90b9fa6af98c76319a422047cd7eeeeeeeeeeee62c5f2833b0a492b668ab4286ca7872e706cb2173439eeee59b9f5cdec1a2fe522e853e8f4eeee70507d33d188543243c04a3e1c9665599665996ff37ff84a6bad35b2a7bef9372c1e4140267f64e8a9450b3f3c9b0533406f7d21a5994250c5b670d8eaa93d378497036ea47dd3746d04a32d2dc76feeee2b39f5cdbd9fc9ca70bb6ec4e2c4f9d820d962078ea0db12ae31ca41e5cc31942eeedba66c64303647dc90789cef011a5eb6d5d9d24cb4acf1d4030f18c2bdf7dec8a0fa66a211a9649620957c03f7382b6beb9bd91a3da11b5f39828e5f3aa8c2650775ffff9fa01ffeb5d05bd7b611b5e686c43bc519bb652f76c98bd629b7211ed1cebabbbbefe4d437f77ec3e2916427a979accbce40ce7ee2988dc6885a60a9f173b30e3bb70cbfbdf76619aa6f2e1e9301b0ce75bdbe68aa6f763e35082fa06ed6d78d0b272420289d6b415a5adbdae054145014d199a28699250777dddd8db76d8cb7d1b78d41d771203d113f61046cd56c4b31a9212f1bc160c650ae46315ab064ad3062394277748a77edeeee24b7dede502a782b8a0ed4639f6e28592afe6b9e8e313092d851a3868a28b40aa940d5bc09189d60d1f134e5ade81e1b0f5082e0081ed2dcd411f5ffcf7345dc10d76d6ac8fdffc31cf874093140e123f4d1555342540472812115d58e3112a99ebb4bcd0e1f47b71dac1756348fad0943c316a5a83ddd7d32f4664c8496614c3a6060c9b2b50043ef08b1b81e985ac996b6e63ac4f984aaf90ffbec7839255982dd4884621b1b242e3a1306c3920eb349c4b3daf0d2c61b51d90dac5d3eb95ac2ce18566e7d33fb2b86be762eecfbc76620ce609c0109022c8e50c1710304d228ae963c407daa2eee74541ed41e3ba22ce0ff7f727df3ff7f0cb3e400b3b41be9e086d4986e1946f6eeeedbb7cb7a559f330c91538cbd7041c1883003561334bdfab1a44f1ca132a463d58bf2e6256b0628e71793318c736e39b1ffffc312743ddd88efdadddd91788e1fdcdd7902e8648e62741a11f5d0c0c321da80e38c5fe8d5a2b5d6563ff5cdc3e2315962b514b6de234464816eed74ce55d4beb28a59aa20622ce378bab648baf9a145a3400c9085af3124e3c1ea42528960176ec4037022aa6f3622952038315de4ff63b4d65aeb7777ffffffb7c1c5764c96a313755099ae2ae754a5b8b4987c2e4b136d692debffff51ebff7f9c77c55218b2b162e9c6891c321f78f145f65c76e0b5202dad6d6302587e0b6b6bba0526bd49e3ffff7f9665599655c1b923da48c16a93048cc2b1a16ab10ce6b7be998db5d65af792ea9b974de7131a35e94985ef83c66a3a6e7bcb6493a35f7348c3126f6d693a65ef1b29450cc8f80130e57c188af0d6ffff3aa6fa66a5268da28bd27ab318e898b1d212450586a35988b142d5c0ffff5246f5cd48a506418ae9e26478ea095241369aa71d463cda440c345a645432847a46cc6b95d66a35e19a9bc05acc6bd9c6bff4c5923867d76dc6368dd2963e35904aa8f46c9e08e50014f31998040d0371280ce418e3061400070e8888c87468e0381e0804e290300c060442412018000480c16030181c0800e150326bf978007ecc1c439bcdb579f4ddb22aa2219d581ce6b8205eb04a0af55dc41b5218cb40237be5343fa500a58c387f0643eb08620753abcebfc05d14105b7ced075e454aa2b5dc89a2191f2e10f7e078f1ca4db72fe924efa56e8c4b1e092b5df28ffa87f6c6b2c0a4cecdcf3c02febf37a1796abe834ec1eca425dfe134a0383a878650b17a383a5bad599eedb2bfa2310aedea97028c2a77696d167f1b2e0516c79945925ac38e986e0507d3e098fbda2a9b72a3a1286c099e2189e7f2491e93e94fc76368f92df029385f9b2c5c763da187f0d3156f7d03d7e5edc61b3c2e187954b6ea4b5cde7e5347aafa44fbc63cc0db7a1641443bfa687bf1014411289e74dab42a10b5f75c8d83a4ce314ec5eb1937f38638584938755ffd375c2ef57d02500169f092e3b4e301e21840f03e395570a6cbdd7ba624f3eb06c09fcc12210bda7b7e85ee6a366368332557052d85364b61087e3e5cd048fc42138c4cf569b12c6f12fae10488a351e19f87228b9614c87fb86a8087d73328b9e6540d10794ab38e76a1aefe0f811eeb3d2e8f2a0a94dc69047328c44417e891071e2e796cae4b70a8def412b093056d10c4c1f501051e62d33a83ffe1016a01b20ccaa94e4afd9742a9e83fc862893a57d2c4a270ca3233d26bfe5640ab04020dce44ac54d4fc059760d89814abe8d0ae0bce31a80fe112ab1b632de2bf7877175a988dc3423f10173de33454cc54b7bde2a59d1021a3eadbbb30c8cd59f5e7a3b341533858f09f9e57d3bd3592ad6d019bbe910456508f6f47f9c1eeb64fc80ccb2919e422b8a928a38f2c94307d43b8956a26af0224d2c85fa8be93067e80d13a240449bae09a617a086f87ab236efd433815390066cd4dc8d1e7241617046d4ee3c00eb23d9322ae1b878124638c5b8ddba1c4fb1fa2503e2674468c9ade1335497e74db048952a2ce42ab7d4091973278b1b173abb9f9a307611d761f4f2102a9bd5469b6cbb1037ca407a092d47a79157910e7322f837ba7f25db036538e76d118ed5c0acf2f718510046fc9c575f757d68c25e3324c6c7a97ca6a687324b60fad72d4c629b4797385547a9d57c4537d584dc520b61608e5b739ba17061d3672f659365d3dde4822a4b10a2fba79a63e0d4fa6331a97ffc3c00fe81d25964a10f99531ebda1a366a1b98d852ca4b28d662c437e231a76472634facd946fbb8afd9fb52e7310129f98da2316e4fb30e61731f59299b4c1dc8c7cec7e7d9d3ff409113f7238f718a8903778a95704efbeaea53ab39fd0fc37b677ea9b5544d4a42feadb97bcf35ae40c4c3a32d5e7b2bd31b71f9976f13d723f56399a184b36be76d3fec3c498d60c4af634432ebba81dc99a882c1f0e77a52be34b510254bcbd9eb63252b6e0d7e4574a62d51fe34d340ff162d05a0a456a704c85879b4e61f3acf6a8bae6a59661921c8e6b1fbdedc06f1b1b455cdc4067e18a5f8c077875a2bf7be871ebe1ed3bbfe72f0fd46402b55bdf2396429105a8e0e1459705beb4742ef268527044babf053eb22e4ec511b5649ab8dcdfa8b669420da024d850817a5b24f4c0d346dde2f412107f5b191f91140dc09824cdd18483d7b0df8c3c70dec819a3cdc4603376187495639f65801300e8cd00ea8e5e136211d17f6006310bfe710002c91db4639fb88a704d4940b55a46af179206c614bf78ed6457ed3f8295575c9ece4d1aaeb0a18f8d3767302941e5aed1a778bd3b7efb1d27c973ce6c808c1b540aa3d6f3f4b17d1ddb2692dfb882697fcf6728b6f62b49eb2c22a5acbfc644b927f052cd8a5cc365a22c76c9a314ebc7d55e70aae315aa4530afe2cbe2668245dd5af01eac10ac709b51148dd6b6e6c97cfb37c21e9a016c102a1cd3707ed5a5ffcf61b6b7b43838cc520954966373ff65836447edd03855106b1f042bfd9bb2a5362bf26f2cbcd1f5b0a471f9647d7106d42bce9bb6493cf214d88d5f51711346dfa781ab183bcf12b6548e3d64882c8d8e568135699876e3fcf6e0a6a6bb28c93111c91d0f98e1239ca2f06d19f846eb271641d7c05883af3ad7d424381a8f8905e4e153456ea3cd2ffd8e6755da9a687b4e6f13a80f3fe559082aceaa16e4305a7b3d14fc35ee73705ab1c8b63763d2a6fa43321b131675123ca543eb9005714bce255c802200a7a41b5656190d24da920200d5699b9b6709c8aa62a1ea5b86dfc2a9abddf8f24d29e96d3e646c27240be3dadd8d6d1c762f28f59ceb1203a1e28d5062d6e7c1802d59a113d502d8507c38819188dd6e2f3f040dd190a820943b40d40effe8de5bacf4743e6cefcd35e03d935adbbc945a035878d4370bd8de552d6644d9edf4c4534175f6ef3104e6b30f9668a66d26fd434887612c3a2809d506cf2ca5c3aed3b72830053a9a0dc65c7a03fe324860ff36e006c8bf04dda145f2082ac03b570931ae03b098d4a7ef14816eb1a2a96ab5e3825641d38e305035ac1022ba663cfe59102ac384db8093dc1f7e727a6912d133c45e33a1131be947c075db85fa38b95ae4596b1e91dd3a6fcad250fb051e338941420c9fd1b8d7640340aa5bf6d9e03983d3b2bdd2789714f4df6001f0a43b3d579b03882407a03a7bfa4ad41d2f83ad15ad231e4907bb93bb7a18ea02e44f0f3982adf6444a2af453c032741fa8d7ae61b0d7c36f1ed2c2e65778e6fadcb17f80842be8b0c5e8ec942def2cb49d6e170c4b1fb1f4e74e8ed5ad047706391d9e9b461d1e60a62a3ee3854aacf9c29348a920350ccccf7cbb33e01038f98e6d0ba1e178c866f39cc27fcee7fc0655b98592bab48d7f811426a99b1c121aadb55858c3c401ebb278cb6e95ebac4c6bb2dc6643bcfe2aed104e9ac0cfe96ce95b56eacc185f27eff04274ba0297842d1d04fa04dfb1ca5304308b8c42b34dc40724ac41bd49fc3265adaba394a60aa8d71c163a257ee016e70cd714f2f9dc4d3be796192cf22cb290930f5689706655206789352d374a585378666634b04a946279265175b581a2e96ade44ced9550d4236cab62b28b1f626bed264e6768ed0cf07ef873133f6488c93edad42854788976c7705d299caf0f60fa6790f378828e43d5b071da24d3e6a6e44c891f7e8997fe04211dd8028fa4b09e2028b10568b8ea7bba237ceead691d31e5c97e52f0c3163d57ab58c541098be009797ca4e00a7ac1e9e2e08afe34657b0e345148099f1c28d936fb923dc77a43832c964aee807a267baad381651887a19feafec85c73f3638a8e3f182ff83bba669a4a73ad44656327b4d521422899e827191bc4b9ff2b6b269cbab5de885adaf83aa8e08459c634f682b6a84d46709281ba36b4f9a65ded307eb5b5dfd7043a56b2e16fe8655e973e3d40e3f08a89690fe45bc87711c1c9cb2a478550c18acf7f0568bb0865f501b54e8f1ea07a6c7eb374e285e5a4141377b8924979aaf9dbe1867a4ba06e694a7c79e1c644bfe16ec7bd008c959f614f9cf9bd4893979380ba4b01765b7334a4ab57d7bce189aa0b81aa9ad38b04ce3f93665ba25ed8f32d2631906525482e8eb037e5ae76412988ce4e299a4d3482206aeb654052f2263e4fc7a6d659f20d1cc72dc7065df33c1e116b9925326d6e4b54eefd748348b43d3d1ae1947a767802c845e4655e84b525485eacdd8381cd6913638454c5d623f006d99ec1629b4579621e51d71c4aa7ac4b7dd215302c12ad0a0273d7b0923e90127c28c93d35cbd7bfd65c2012b4668ad9cda92c498fd98040566b6e159dda5465f6d9adbd076909b7506782fb007fc3bf27b5b8799d8acb606f6fd47563fa7eb0534ace2fefa1001d484baa1321cc266d360557fd2159844d056aa2ad1a69f0e55658c92570abb6a7287cc3dbb88e714a194e8171256c6b37e5fa0a3a1a70811ad6bee4a1e8e68ab09f1064c428c5dcb98cd1b7a14a76f3005cb67042a99bc9340bd9dc01e300a2677eb27b1890ce48afd02e333ab49fe921c55486a750736ae158c2c95d0ac381cd0ef1ba245a2aac7506a5f7c6b2b770b1c0335ec3d29af73d3c509c9475715b3b9edbc9e234c3b31eded60e21e60316a7e4371e53fcf1dcc601851544e6272f6dfe484f23b4a4e045a117ac962c80a2d044747f682337c51fef2ae9766d1f50f9e7c42ab475bdaf9ee4ba75f21dc4bc27c2c3e99c09dd826530f240e0210690835115f75578681b8ef20ce684368a5584d808c434cf33a6e66608b710478bec4f3cb232d2859dcf85799725634f7dc2984c3631831aff6218fe034ea37a9b327ca1884208baef8b8b10655ede148d665c4dbfb8bd2d83167414662c409f317272a5127b774c9bcd4849ebdb571e5264711a1446bfbc3a49c3d0277612da1d22b29963030abc76c891655318db238fb89634c0990f5fe047ab2da16513d6c4c21d8dba5e63142b8e81345be26f1d5cd9b9ea1484e741f8700fba7352346e6060c2132f9a2664d56db2f98a391cdb5e32b72155612a235d7e71cc9d65ba049539b073aef48c313b2c213832d248534e6dca314d6f3ce90240aa1b2600249e850ed61c61b1e153e0b5eb7c7ba4b31e58c0ea7f64817f8b0e283a9b0ce5c599a1edf0918117d5ce5a1d7d58342a584dabc0819bd782ecfb7c2ed9d1228fb8691ed8782d56eddbde20cb6d97a46e09caa272d0e46f798918f5f241150b53b4a6986fd4353c608727eced89587e66fc11448a08a611120793f4452664fcb976696a9efd74f18b8206d0d3883f05d6a0302db1b4b1ee1ad1632336d27a721f6c1e18efdb5aa351b3e5e6539e56a0d4b883e8b948ed5f936d56fcd956fe71c08fdb1a25aef5c7eeae7d664e538251f6baf673d849fab8514e64e133e106ee7f8aaa03a6c47c4d1f17d6b0298e2b77cb29fba3927a87163d7bc2c0693700e962f364d5156a13f3ba3a868e26412ce9caeda4f09c437025abb792e996250922d53c5b2d0de4317ed96ae3725e98cc2b42223e4f067f3fea04291f3c66a8dc7e83fa1730593f0748dfd7457a743ccb9ad7edac2a2455a6e619404477bac5eb1385b6ccf5371d0e29718a8c4372549bd914c3f876c7513997b75da2599d158f388c1f77bdca954e49adb0cc753b2048cc7f714315cf214b81c8739497c49b750c7dd33bd6a282e69280c6f45e921ad2d3372aff5b1547808c23547e33ae6fbc0372c36fec6029c546f923cd737fc90065cc97100a3d007e39a23072d217728188f198f3afe4ada875674a52c842978041b5c2cb5ed77525629b4cc3159bd26f84e181ef29d533d3e24ecce8ed5ef399171fa357ec5de94220d3e0142243fb98d3f1f1542609a34b061cd1cb418ba71d166648a9563cafac0ac586171c643626eb3875c433571fe8137e61b74ad945f134e30673793a4d01418d3df26c89256a49f33401cdb660e652447fe103586331238f8ad7dc9f5963b6cc44fe9ec622e3f1f1740d9a9e4e076f136ea89b9b350fe275a695d7b37d8939f1e96285fc235e48e98c52c33a8096c5e03c447f1c81a6ccac42b6d9475963dccad0254c24cb916c97c2e0e15ab6a961d94a0b1c541f41c4fc171faa3893053c84a33b6b0ec25c532f703d8d1b400c377cfbf590540f0e4498fd800830be952f37f124d03a8d6c8b03910dac91d680cd40cf898d4a79c91d3a645fe9d60c64aa958bbde2f71c8e1971ca2210e1199f143882d4cb005d3c5cd1b1a65f5e8855e466b32dda216204e86391b2e6559137b17b388fdaf7feb3e1a001ca90aa1e1fa658856695aaac3020a686ac1ce494ec8d15a8f5bd3b272b8216394d0d9b5d5f8af8206b82306509f832e0c585ead66dec6df749b0c7eca105574472dec734983a1cc32993d05d0ae559d65a89c2b21629a90bbe508dda51f4dcdb2813470293f7409fdcd335b1cf8953c8de21f9887a483e69030e90c3d2d17c37dd0632fa1579b822d3ffde15f61f4868aafa7ce89b1944e9a212387bf47cea2103476522a66f5a7f5297129625c702705fc790b0b35ad5c3ba31e3e0972f82041e6791833b4e27b4d188642bad5ad127a46c96dc14785d27019785d97bd819063e8d75badf0a27ec30a016f1e514247d750c6bdd124fe3c0318889418425a6b15d2a989b38a270838f421120de66a6a78f5385a33beaf4ff13af909957f740fe31d071b403e7b27153a4b73438dd7b1a14d78459d6ac73b9560aef244deb0cea099c993490f2544a1e05337869fca053f16d395518dfc5349cbe7bd36d0abdfa0d4dc397c89f1637a2dde4ad83d15cb3c23dabde9ab69946f5a319779271892a52022d0a7454e78b61718b7b79d1646a5587fc36a99c562f6c817799b0e6bd42972a7a32b4a6cf73e50a63109f0270b75e699b3305f22e44aed0d7eeedc2310efbe542245912689fe43cfd95ca414336241339e0e5611556a56c0df0960412b74293b9ce780bf0f5511421c138a6c4f904c049fe2680dc6ba304beb9b4d1f89b93a3431072d0a92a1c739552de036b3ee30b69c9e031ea4c400f12c6d341dd01951a971c0a931e1cb33792468e8896f8acea7fb908337bdf8e3bec6b14e85cfdbedcc458bf6600031336a3e8683dbfe06edb37b80f19846e0adeab5403b83050aa4386be5039e94db5e62e9deb3cadecb9a64d03c9806d5c584b7d9a03731a527fe036f30483269aa051dde6c770cbd08067f1d81b480bb4497b63862e8898c236cb4510936cd2ccfcb4b3e50003603430020e36a4ab26aee0262e7158aefaf2c4b447cc16ce1a5d0d114943b2a4cdf60b8840834b6384b1a150b5a3c45cd9aaecaff8dfd0922005b844b7f610c5c1478c5373a6291e06673337bbff92396f638162e149f7adfa84dd8bd5fc2a51edd27924a9135a8e42baf1f31cb8ad293f9d5c61a849ef2be47907839c10fc435f55eee4e47156ddb9e6fdab77bd259623ceba59d14c98819c1501f30d5c5a6566db13424c0b41d48eacbb58a6d75b028f120d06e7196f21c9dd5f7e62e4d1a4725810cedc7b479344161c09e5fc9edd277a38d9c45f9d3faaf84ba75ea24b68848e35adf7fbb36efdc412109a042a1d744d9cf3afe09d1ee5f379ab36fdd0c3f4f3c00ffdc7e7632ba3115dc637a001b4c631e9c2313a62eb9f9db79e6da229668867f0467556d02ac4df488275faa2bf50e73920d46c5a301d6ab508d0c3844e1fa12ce26c8fc7398885983e1aec2ce91a9ff4d79c52746896c316016d5945a107307b80553411e52e15d22f9adfe2819006aa85d8fdd1d7348e8fa541cb8e2605f0d903e9467f2c9f9d8be2214d4a4a6a2ab647d1b1b6382741c71c9fb7c7be066dad42cb68998feb50c44fd9536f45cee8197192a59c87b130941b38e07ad5cafddaca1b0eb5017fc0e7195a88d679eea0e04f9745d31073058c73992aa956a2c8c4d06f055297d4ff090f98c47a981aa1973801e19fa164b378c05e5708147fc502462d1aa0f752e3b95d65114ce2ce220d4e0fb4637835b217a34d9a6be536bd1cd4839defb0da4cac08c98d49a117685cb9494b74caea90260e05e95eff663a3ed2f249dcc61449f545b397a8b6e88022417e0d279383ba937e707a7d139cd3c9e0402bb5536d18b43bcadf75ceb4449f785c1e9c76a72bcf3c7dabb856435352c470d45c5abff838d1c115e621128e799d5b015474b88b2b646c5507a9833ea3d585689de582edbe6d8e1ea16e94cd6f171ec961286cc8b202f2359eedb94c90b49840a666c25df5cea04c23ccc106646a66084ef8bbed85e0a4b65a3170bd80c23591eefef70537ba023d4e7bd475e95e0ae01f993d384d36b424e77b1ca683449ce55183d114cf0a5a2302080ad9a0c64680be41741905f103c92a5b87f2add2aa71ca8319ac93c094f54b86ded82a4059f55edb04b850ab036d328fe7e9826e440ee22872406790e50fd28a4d9d51a9af681b6fe69ae595c1c97e077425425d8a76d2b248e7a8f002868d2d8b1de7299733837508c7111c0a150044b2f1407c4a09ea8fade288d1930fefb7e3abdf3d80934a3b1883e2c19805e116ad506a6012284883408758034490b9cabc410ac812c1100dd87024be46a031bf83edb2398fcc58cf02a077b07be5feda2cc206700899926731abd95872980e7f36b52a370c2ad9142f4a64139859cb7031226ae288926450e678250115814698ce4ece839125e5e32889da946f24e06bcbb27d39b7589208da63bd47ace879b6f2245d2ca7ae186265b3f9bf91aab440014a015e0c09af3dc639866067b7b6c1169d6e0cc63918e8288c88dd19127c865c340e223c9bdb30ba03a4eea229a51a62be35bfd6ee5fa1b021dc369bfbd1e71eeb82691fe38477424920763d8be4e6a19237bcfa6f3228119d73c973d5e4fde2bb972e7de4a51ee27e620894a479ee350f05c6cb0dd931bd9b75c60660b65d903924aeec5d51c7397ff571e4f59cd14c2b35cd3d341b0bdf79f06b354cfd44e5e9f116a646c06d3f577a747cd945cabd16f491eecf6af0bd48b6643c485a34bf1764612b3f9a97fb8825e4fd921efd16391374a083c8b0ffb4ef64161ead6684901278817f467f18210da480aa7925c039f8a2cc7a81afcb75b5b5dc747d3ed681d4b55029a25376667f9d44f6f22a155342baa764595e21960aa04cee7f3df0c50d9fd53b5a58406d8981589dad7184002fb8fdf5a8e35a1e8d386d7bc841dca238abe4342613c0ce28db32e3c40d807447fa484106cf8b244531b00602d8b48923e0825d6db061e92493004ca88e5c56a39911d316c02b2e8fba525bc9a05053f42ac4ae481de82504c0281abb85a171ff362d6bf5d0d62b0190eabc8e39c117b9af5891c98ca1e9da879225f81a9ce96d6847cf4a4d1a3c8f0c3d11d5b0e539e45864dc58fd406c6903e578baec9a89a44765cd6e45b14b7c6cac13a72428a7c78b430bdfd8c0fc2b88c88f144b832b589d541808adf6a21cdab0be327546e1eb249681961a2cfdfed236557d6cdbdcce58da5614f41458f421371b47b6d268bd25ee58cb6d34e807641ac8339bb1689a62004d30decf6b7851a94cac0a3d124f30ba7003aeed29ddef00f82ddc2ee6588dd9e1b1f96f9f75ea06d6f6465a1e4f5321ec9acdea72c5266a9f59adb5ecfc031f4b1ffc58d3c9026e29d07260cb4049c760aa4dbc51c8f6d832366ec7f6b4b6ce95b37a2cdb30c8725e4fabb5beb9825aa68fc03684cd241a585a88cc4f8588fffec5faad031ae6693246b2f70dae97d7b9581d593a5b683ce0c262e1d224dc5058a737c1a24360f75770586dad22255c559aebf76e8156c1aa901539c2fc0054d511702fbc3572a445ab5edd116c11f3f9c96557f54644c0d66494d587f23e14c76ada816ce316f27e132891f51887b44b41ca5049978f60dc133a9ea7598cb633873c09ba51254ba313b53385711afcb0836de736e59579573c9b7aa2570c58a6676c6d7df767b0d0065f30b476b115e2bda6f4c95a8e99e79b80bc3a93cd8b3eb4989192418a7211c1cbcf2a0786190674016f8fb00b92cb2d17dc52421b6d2a52af7c8b3658ae8eae2a65752451f5eea46e3c6552a7e9c1275466de0e70b440fdccf8515613bcc80ef5af9edc6765fe70ba8cc9cc88ee06f61c0579b543cf3dd384553ec748ed02263156bd57b01842ba4cfc08b14864eec0ecdd441a192804a39a3f20c82cc2d51b269fa02b8af2974bb7349c4fc480ba794c1bdefd7f10063a5d3244279bb988f1285ec3094c3fbefa0c5bc9b024b5025063176670edc4e5dc0bb44662c2cbcd55ba0a51012447d3e86a6f498a56c21dfa429a12efb09865f06df8f038f8be9af855af6db89ae78ed3931bc6976bbec4c55d470216fad2f6a09e09e4e592792dd07cb4b970104953f24f956dc320f350cdc32196487c605508fe1a1097c6d76892ab79bb6d8523ee0577d334137b1eef821c977b3c78140e2d85013aa30e6efb79c2f3ae1113929f0d1b56dda226ef43b3bf9542ad4ccc10374d7c5e90e91065b3d0a453140273ca2c90a8aed1f6a963ea87ba0351a08fb2f44829225b287ca11d1d5c837e441e2ada06b6324fcd9c5dcea8bc004727a48e87aaa19c1399545a224fde195bc80214ebe2f54353778da3078e165d8bf726a8e4bcf18dd2e8ba8f8de964c5b422b4e3966dafbc30a6cfad6e0689c5348bcdc858a4865cd743114336d60a8265cc31d92d15a62ba4f91c4c5cb140354b699114cd279b7582a43cedbe60a89a43bf38264ced48737728f942108593828482af3ca1f26034fee6a6485177f13dc548a3f8f240a1374e6afc2b7a5e2b4bd94d91a00160c26907682dc8406d5652adb8bbb481fe85994c9ff21fabd5fd49e21c3d1d741fd1570fe420347cd0bf4c6d22f4c82fa30f701581d0fb60eb1bd1fa17c473df6e4ed19ada68e0c5efea39814d783fe70101ccb0b85f812e9f5596ed7b8253605c5792fd8ffc3bc326e44b0d047c401cb4bc017a28e7c7bc63d790ce2ef356243ba69ea3ed018f24d3075b0d641bca696bf4567503b0948d5c4d94ae114eb927e913deeed182160918873ae99c3f2d4c9b6230e60ba2fd6c4edca2bbec40b8ca00a0e085839c6b2037504eef9c77b2e79e62f19d12ebc179618f3ed45bde8981f4a626f6370317d0d35dc462d15bc35db41bca6cad7efa465bf9a81c14dbedf29847a1cd05a75684956f74eb01aa37b9425e508a49a30eab46d71126c6a7313efd19913061ba07847b235e3e4e88c67591e33855cc68f90431b196583174658a63708c240008220002200900200808c31825052145b3a475cd9326b392d6c2d22a2ff25b93d77b0449db5ba6249394325904f3032f045cdf838085cfaa4bddff7f0b3a2a71c1e71920e98251c5246928054782e5b708b9500d0d493d54dea3cb0c92ac32614887c4fbfe302d3ef5367b1b68f991b32bf7de0b24acb749f40e80ac662dfa07806e01a3a8f5ffef4192073d4c3f11c4b87a7aa91bc0aea0df74814968d2e0e1f8d9df63e9691e126f89e7c493fac9a18667f882a84b88c631046a7d2149922467f8ea6d028346494c276640596981f5fcfffbf418efdf0e3c58f536b7c2f8099e317e62858fedf2c808f19a87efbdd7cae77eefbd426070f589876f74904e8290dc922449923288ea6d16212d39494d7d0732aafebf098ca9c34876fdffbf8a55bdcd6216178a2a5d28ae7417b7a2e7eeee7e7b4d9544c554feef62e8ed7629d8005a21872e8a4a7d656991a1d7fe65e536cdd84d251e19e68767242b0745481cec9664d89f1c46afae2fdd17efcbf705fc0a7e195d1243603076b6c9bc31c667e687247d58e2fb7aa6109167022ea89eb2dae0426bebbeffffbf0ca47a9b4b24036438cdbe0bae3e11f66d8ef7de7befffff7f0d8ce3b248bc233f20d3f7a27b94498e251f76d8efdf7befbd42a0ae7caf5b71a0ddffff172179f0b3f4fffff3ffcf63abde66980d788cd9a0878f09c2a72be2ae9c9535e52cff6ff8dce89541374cd8a2a5eb4b92233f3283871d6176b667e4ffffaf98fa365f44170d879a680df5064af06aa14425a84372a81e2a522afcf0d2c4032da27cc08df4c4b041841befdfcac4d4b739fe154d6f491351e6bb498c7e1eab5f5ae4c00537a3d5abb7f923da40ab6886bba084502faabc6c78111aeeffff7fd0a4faa2c1d7236a0292e4e9aec85ac1b5a2cbed7c127c629483ecc1605d25c93381a732592e9d4ed78356a63c957cf161c27141f31812f5c81afae2bf1001b8d098c19544c50716cf8f2f27315b570c106e365dd5dbc46ada2a9bc2cc70f77c066e8a118a294925f9f3f28379f93911894311872c1cb870e8d23d076378ff3dcd010b5c2ed4c3367c83f110d9db41aa005289d9b154030b583b1662ccb4803d54375d8251bc25514292d778e491aab7c93335f25495b351868c48546fb308a903e2d20a42841479a005312b9276aeaf90af2de2f12967654d59fe604a7c04ffbeffffbf922346f9bf01512f04e9b9c012036c7ac14aa90165005e8a3f3540f428e1e81bbea066622528fcff47c2d1ad1a61ca59af876df806e39f4fe6bb3e4b867a3908611bbec1580879a56749500d1706b59234127dfeff3f86effd6081801f4f760c591756305c507a4203c8510e1ccee4e20677e11564bf64512e55495946b8d4e0f581a5a00f3a61bd4da295a3d015b1d10ab1234245bbffff203d32c88f0c4244062922832091e4470dc9bf24c6ec85d1d2d01130bd2a5b25d8f0012212833ad90245076fc78f18620c89817f2ae9d5dbfc8d4465d1cc032548d876048b058e2cc5ac2c5a42969e8008afc01003110b8fe9c7d2d6122536d408428166ac7861b6c028d06b743282b89682c244a5cafbdcfbe28771fe9359d1f56d8e3fe5acac29cb1d0e06030fdfdc1eb6e11b8ca5048e2bbd364742b6af03ac1fab38a7f3cbd16c757c5587061541b15b9a4f2be3800eb07580b5daae75ce59c3f645a6d87d330786e99871bc42705ebec54c312cc72ad35a4e04db248aa9099196f97c40603098e7c4ceeb1ce7f5cd4270a4ccdddcb837e94e828f257cb973b14b4bf468d74af0ba84101541f1fde112ae6c803c874aaa72acce313b2ee1ab36fa4eadb5b66b1d74f63d0f1c241260a276adb826c3b51b56b371c00ca6c120cc609ada0829c41a568bd54098996d1bd8c00636a062758c5aec18b65875227c694eaba1c04639e21c0e875347d83a426669301c8b591acda2e5545c12f2cd72dab0c8529ec3272805e4397cd2e5f283b16f141740ab9c7d13c1e6145dcb4d3a0315d1d8715b3a031561b18fb3a412bbe082d98dabb56bad55576badb5d6da15d75a97544aebdc35dcb480b6920455313a2db0b6bbdb005cdddddd6d69770b2d43abd495227c002b25ceb959eefaca395ba696ae28296e5a299bb41a8f724e4c43e048d4113613285631bdd302da36dd33101463106e28a594769d976219adc9f4d21baa149bd3e6df6badb516ac46b5d65a6d5e3188eac23a73a54cfec050098e58c5f38646332d684c6d28b585c8ca8d71121800d4900731b7d414260d7bd490739338346a41eb1cf628e6c6354b720e04b679da0ac5dddd7d45f53691969ca4a6aa2e037c57f702657aca59595396f706dd7b2f96a47a9b4c1b6081f2d948f5f3ffff6f141444516c49dab9d57f8f78a5ea6d4e5509ddbbeb26de7dffff7f5edfe6f8ffdfa3a23748fdb0f58008d0c72b9a7256d694a5ac67c348a5687b312f2b8235624b564bc5a5ac25aea52e213a21bcfeff8f81556f732b458c30ff3b2c5f6a34f160eaa1a16406d59c32b24fffff77de778743212b050a5c6517a17b65be1ec6790d3ac583ed7abc7f49bff7de2fa29ff8b22a7d630f045652a5422afebfa0204b308b51f90383179157911792d792979397d4c5ddeba167f774939490f4ff8fc3a586f4b258113d0e21efe91101dedf58b7804ed8baef1fe2cae7aa573e960f6da128d8231fe6c3367c8371932e22556f73aaea8a4c5104cbe67816af2e16293f30d8c5e3b55258883fb8cae5a310ecab46a17befdddd7bef1554dfe658b4fbf2ffdf34a6dea6cf89157a636460707112bed0bdf70e21f66d8e5734bd7256d69465cf865aa4576ff3474432a0481116fa72dfff532431a5e881fadfc9764bf5369da4a6aaae50ecb02e09628c86bbbb7b540e191a394c5696c6143109ca91846a848a42638771f7a7bff0701f496a21b222c38910304945973292e4090c8cbbf7de17c07a9b41a3142f921cffffff93bb7b7755a6074dc2db498ea03cf45ca6becdf17f2e17a175f20161fd4c7119baefffff2f14e2e57ffb630b0625e64554d1d69799609504941047002265edfab6fc1b665f6ebc08d365384647b4e355b24bb9e539f471946772e45c894b18f1cfffff67dda19407ec7c5e909c80c971c5850e1838feffdf0acc05157777cfa105d8547424c9c0000390e730cacb5101ae8a3676316a0067f81419b4ecfeff9f0b8d91de1066a4e7eeee50becaceddddbf2cc58cf4dc2a4aced9421c111f0255414c925c8199b1647824240319a9140d80430b26a09f989f211d4ea29031ecf8ffff7f20bf3ff60a8a4673218943c4e4dcb4ca3dafba8754e13050ace7ffff0a16d8951a64fc5cb8bbbb0f1956d0055094d1084f0cdf5490e7b008950c803c8745a4720ee3c6296182514f86a04811f291f245a3257482631bbec198449409c4312a146fa0c1a3eca001c9c969e0f23def79ef46092be7306ebc81afbbfbd80e5b4a355eb470b72d58ec38b553c96727653be4390c72f594242be8f3f7ff0ab73029d5b8b63c87467e467a4627c480be7c294d3980d1c211e30b4a8e20a0ef852cc3af21158e7441f2a5eab564f998ed3fe498e75029f847ff3df80689f971ecfff747e6e23a219215c3758e8a1f528cac90c5c89413a91d225388d450a79002c0af223a23567e98bcf0e501098ce11c33e44a0c4641475c7afc49949328ab1e4d56b910249aba480d9b92e4ee1e3609c911e4396c227216b32c2d3e8e6df806e3ac1764bc0d6cd15a821185051d4a4e6e978f5a9471866f6253720ee36498bdffbb4d91a20b202a28f9f2216a0d814105656815c99caba1c973a834c649591c1edde8e0353c223201f733821e9074075f47f930a53d4cc155100c35940f443aca0c51354cfd21478b281d921a4a0d8ef6e003821f1d6589afe78b945c0c875c6532cf219115462c6a5e74140f4f5dc6d041224128508dd4532d4a08158b1d43c1ddce74e106f7d3655996351e9e72aec4bec2038f9e072732a2fcf36c392b6bca92ca7fcadbb13c874a5e9ee0fee7ffff9180e9915950422e45862f3c212e3ddfcfa96678600d2d563feef41f48c9e80e83e090bbf10c3793e73008973c93e75009c8580582136cb020e3f9f27324f1d061545499e7300a09d528fc27e5cd7318a5d5c14609cb731855cc396c6b866cc9dd3f8c0a66993c87512f74d5ac181ec108aa756f78b4cb398c836201ddd30d4850e00174a3c9025a859150cc0e0a9520aa17a67c3801a01b41865e90806424c1d9f8bb7f0ae20d136028066940d97126d9dd7de6f0118b10c3239fb2666834264b755f9c77dcc400a771fa0374a962779a456d1077afb94fdaeff718e0309813dbfe39d2cdafac58d52d4f631fe7acc16a393be79ce338ce398e739cd7f1949976c44eb378a4e56891e6e98e1fcfec343be79c53459e7f5d28d6b55fe6448d4d99ee5895b57f379d3d33b1117edac54deb5f6ea96ca2c61c97fbbb296e99138d6bfffcfd65d531a0223af6b348bb69fdab7536adcd6aa359fa4bfd035152e02b6d8d69cd75feb2a5098049999b184899c3188926310910c0535aa44c36c17c74e6a929e7687e309f5561e62937b6b400704d0b90b2066cce7da0f9e5c64efb00556d8d33e852561013e49a6e5ad038032ee507a80988b9590b15f0a606147b2d675598b590bb1641307705bc0c6a9415e72620e66e3c017102ab9a4e02a8dc13e40a8a36496cde64f0e4eeab2129478a1bcb4a10d886c3e1c086d6ae959132e7beead547fad896b78633c59370a8ca9cfb72e746a73a22e7bdecab237e75c463ebf693ea081b8ba72f79af8e98998e53831a9b1b00b9a1b64cacc7caf5f7330499894ab1b02896a340b188bc9ad9826235291bc3203a9501e162af91604377bcc693ed5cccb33b3e8e77e30e9d1758fc20d89d5bdbf5d0ec38ae3bb6cade6b735e60b1894abb52a6d8ce9c7d04c81144bd99d13ab082c4303c02ac661381710412c36aa5cc07a48a146c66fefbb5842362907204791e11e3cb944e1d982ecfbee55a2398b72a1bcb39656674b6a4445133516d5486a9b435779c9b756085e3c7235cfc359b083c1ef158ebc0ad957da3f86b29d87c3071b6e5d22b369b44e330d70c5747cc8a558b2eac595ce8c2ec5db5e84217de1fb15c0893388ad0e5d4a0dea92bbcc44b458b5d2ff112f3a8bbc24bbc442a3109747e3a3e1da00e30eb08757c3ac022b1594738edbdbe7706284ecef53b549e5c6ddf6dc5d6da766badf5b78d41ff9b707737515598a836fff69a5388d99a3362d99c502470335b99a675aa2b787b7b75aa4eb96ee5ea549ddaaf2e36a94ea53a3911709e448bf1ffe36ac3187bf5fe9a3392305b6f3792666bc596fe77775b776f5bbd7bc4c6ce194958acabad74a94e5cdb02e9102aa2620bb4c06c85340968813b5f2f53cc79b586001e272d1e6d2d2782b54953030194e895e095f095f0e512502578257c5cb15947e44290602be744a8311a146d6bdb0073c5df1264555bedffef6f1cb3ff5fcba9c8d904bff1db0c5111b5bdbdaab009b6db04b30d51822c9913956613ac36dbd5d2d93356b1776c698e6d755aa5cd8a8d9ce618274facaf55a6e26edbde3e76e34aabfd458bebe3bcb5b63e4eb559ff3a9dbe8e9963244824c0c405726e8a1cd8aaf096a56d0b6125e7706aadddb359f794951db1538308f2c43745a829dbe528ab1941bbcaa495793a0ee7736377a74066aded9b22f18a446e9c81b8cab99bb173261e9bce16eec4d3628be9ac8d73ce2e7e502fa5f3d6a9719cc1c394e270b859a3bcb2fc119b37398f8b1fcc1c12736cdcccc1cd9cb26f22d41b0664282dd707c44924e270389cd36a69a7c515c051b17983279d934e3ae73f9d18a839a5a53aaa2ba98ef4a2f3e920f02a29d7139e2164c73d628bc92165d7644aeb07b52b0501945da8c4adfa7ce7cc0809009000b3170000280c04850382288a9234c7743e14800a378a446648344a1c0d85026150140844410c03311083300cc44018043028c8d2d0e4014eed174c4bbd5e4256559250678a784d071a2f4550eaab072e2e6854e9a3f81910214337feaff0952191194d4bf7df3623633e8fbffe23e2e1abf5cbb8de99f2ba5e9fbb47a08cdc7d96814d56ba2a2295e7737051601d17a23d3c97b8e212077e4be1389db2039b9b1841ee45f8438c54c8f1a0bb2357f6bf2ebb1aad5dd3ebc70c5a3f8d9abf52e17516cfb34db02154928c205c783a5ff59e5eda33140ae64c2ed10b8386535d645489c4a62baeb8bdfc8a858ad34e631fe2e28cf1b51500e076bdd24a7a313119a71988baa1775755e6a79cbdb7dc58a67edce494b24228b57d67c4a27ecbf6ba89063681a17b03051d09510d29e39d38ce8ac221772ef56459c1795da054118952853296edb506a5dadba6f56fa74d29d2f2943046799df33c8fbabda8596113844b4b85abd86626913dc2a9c681ab5593ffda7c74c520582b3593703b6e56a022353dd23480d6f0d9d93333ba39b5cb64cc0090bc6bdade45c3403b31f1413312780a430314a98ca31fb180244405e862101aa0bb829f091f88f0ce1a1c1b6736a688f97ab168b152d590037db7e85efc4de597c12327ed45c0865e3b886373dad8351077e3cd5bd91c16ad172b669081f1bba7780df11a5f3a09aed4d6cbe2f7c3fcbccfb5eadc80a808bc97bc1f8a04fae12254fd5f0b069395314fa204c5113e992839ad0cf9a68bd75ee1394a95678ab7cfe1ff68b0ea68a16836613fd93a9b35ae6918d13ebce980972b40e722d958c93471d194797047883a60d6542ccf6f1b907dedff81584fc481b56a231ec6bbac7fe98e3a2260aebeb9245cb3bc76904c5b766cd4eeef46f5ccc1338d4db58128a51a64a07fa156ff2e54d5e2a7005b5671f77d6d9cfee5df37fa2c4cb0d9840c19a77edff35cc92bb12178900b6d99ed99e0b8ceebacd6f2ac190ab6845a2ae51b4f4ee211677789c906eccbf28b08142a6ea8c7d4f4a83249478d99a4d2f96c851bbf36f681cdb51ac4b5ddcf326062bc36d0d6c673d187c76ab2a37ebaac2c99ec1a4f85bad5dba4a6175402d3c513085b374496696d6f52a395a4d2904aa338de892311081447fad1fa5572aa275b7f095a58b5598d02141da5d969daf9789457c0e3df9b51661b5cd94a3abe79864ae3d439b489b3acdb7216b187a75fa42c1037b1bb1efbee9cbe90d701f1711118a4f09da710753ea52f3217978244908b8cb2b4a2dd9b29fad1cdcf7238f930dae7a1631416b187a75fa42c1037c1fa9ceec7f81eb825d7e91d331cafb60eee6bc1d08c7d92b4102260afd7aa52087d0017d02421f2d18a7e5d93519090c8e7d517c561d9330ab089c222fbf1f48b6871ce2a3cddf4eb5dc653d00d78088e38c05791926804b86cce41b27d7459f933646ea8bd8a971bcbe504cdc08ae3de741a2cfbf95b7fcb01c7f56c556c24c1819bfadfd3e7a5a4b19ad3d0e54e9f7031646f7219cafe4b14cd5b2fee3b802f38d1581f5b7a56ddb7fe7b2154e4bde4b0698d31cf76e6aaf447957e398e52b67be46f042453a9dedc530e3e43e1ca2431f5f41c4ef10366c2b20ba3203cdaf1431bf32a24fcf7d109f526daf710da18574dbd7f4aa17b1e7b29e133fe63a9946cc101a0c31e6b54982c55653488b1f0b8d546f317e9f74cc9b80c66253909c8861be06c15de5fc53f33410ba953cadfe05dd5b3fda2a22c54d2cc9a4c6bf3276b07bb43e6b5f88b04f0556cb07a97b03c3bfdb5b1424ac188503e367356c3d860940fac6f0a93579c01077c60c72a2a962ed6624de0bd0fe88bf8c924c2ec98579b0de7d7648d2169152a026593a4749ae464fc826a7cdc63adc62a9267242fc31c8ccfe37f299f563da3e3276cbeb3a461da4c3cb3fc243bb952a341714c0f88ab7e81dfc3d8c6602a75e56e09d1552170c260554a966263032b85c90529f79851950e805f3a0df574ff7e5a0200b8721bc22b684951be1cbc453412f8c1dd72608323987f931013a5072bd0f3b7a754529d689f63336a36bf1b8f94f74e100b41e78e9c1feda952cead86179e40b21b750f3a3e47279b84d6f01a6463b52e98ded4bb7c0ad4f5646bac849bd17f783749cdaa48832b68c33a9a279e78a240634541779e0feca9937033b3121df74b6077252551e37afc6d12999dc7250ebbc92ac13f2bc6900089ff0cde51cf3fcdbc24ae0a82fe9c6933f3eea8be9cec72f066970d52fde815e5a7e578dfd04a3d6b19841877a851b4d3560944317d1505a4da58095d96b9a2c6f9c00e8c8f836448927d2e6791fdf7f48fe92436ea9ca8ad51d2af74194f5937e0213882af63cb506c500a0a72d4217fd58301087c07f4d414558f106b88184aaa91dbf2c77042c8081cc55ed40178ab43e2f8f8f02c791770688221faccf55f87c30d3de10686cfef779055557b7f672500d0cff9adac065b37d6e5c064087c95a44d80d7a542ea032bead38b4badea4fe0762418f637fbd852327ab894ef0a8d1b6fcafd2e8c844ec9c2a078114bda8a6e1680c19a048686ab5f3d1be2fcd7e8bb98c4b914653521408f528a94661e4a7648fc5f26628d561a63a24a06d893b0ed329e89ceb097dee6c27b28acc477fdc3754f6098fc4339c03662ca46f9836844177ef7005bc7a91656f3db16efd61825ffddc88ad5585f1141c402d8f4716445777ef0a3988cd618fce3fc8f1c52657d051f466f00f9a937a913dba55c496f5860c406ff86e405124b5fa0d363e90d402f4fff436f263a24b54cf82bc38a4aae795eba96556f4c5b08e52286b79660def27f24ac2a412c7d05f9172a0785a8fcee34a9552c462b57b391c4548faf0e7256f29957d16bf0d95448d96493ba0e0c60da685e4c57d7200069129169b67b9641c3ec47874ce2c8b3cb0eeeb8770a4957d94239a6ebc0865bba29d55b20744ebcfae8b8caf4b29663a946388065d7590a622a983514b282957649826c139244373e8c1566cd80e5000e027879cad4c7069801b530a70437d2d42bad24ee4c3b003c0d3b2632fa0a3f369e0450f7ee9cb328367853cea081ab115e2ae1c864bc88e7f4709d0e0ed3b09a3f687ff8f49fd28dbea9e5c042cc64f2b83afc9b3b642875cc53a5b4c7ab4a5c562b894c5169065462423e1a0c4a1a1b0a7578b6333099cd5026af52e80bc361eb94a6ba3446891ed19739ff8f749d1ccefbc2626935e1cf3207094a0b5a28c5329b280661ff0c26d5851344151886c9dcb235e168d2c5f6040dae5b85b13d27ba9279ab043f3214f6082e3c05b892d013782e150d03a4a725932e055fceae3f443f3adc1ce1e63a08c1c20c821f0ee347b43ed25f6aee46d7c73b0c9689440290a6a8116ca721bd03329a8da193c2bd60cb1b1b46e6e8e1db463c6b8d89eb119806850e9ae5ace16e361c6ed10d5a4d72fa38a7fd3b5488dcfa2e5bd3b0f10c15f9eed13d675b2e1f0796782b7c075a7994b9f8f419fbbc6f89c2b3d1ae83d84aa1b311893617650964a38d9424167a7fc815ea64b0abf3820558b2f2063f14322db01f0297c567ceb028ea6365ff8dffacf1b49c94a8b88545da540d200053c97c67f4ab1bb3c740e4ff307ee67cb84b092c4e474b1f78270f62cef62ad40cd07c25c214778e731c92b81a41d2e8cdae0777579820696b2024e9562f0cda3bd67f7a989eb6a4c3a5d96f76b4e2e5d2fe68334e5e97b68f58b862c0cf30e4aae53eb6df73da17e3bec6adb63b08e9483d5c86e0c84477755c9a874fe673434ce9ac731b3fdc817c6923899e5bc67f67d2b5f4bf5b335e7992b39ccc6704cd21c6a1c00b73f692808eac28e51d922bc8cad28a3ea762bd61c657140fd080c7a7d90f04ba29f7f1be7f04efa0fb09f0e7fea9598f1bae408a27cdd899d3c08a43e2046c4b58b688c0ea6aabbb9df44c9cfa714e67837a82ffa6093fb7cb94bd35e6a0456d60515c5afbc2361eea8e182716f8bd936d8cd6a2b09de73eda909ce4b3adc3985d2920224f613076e1ba17e081cf8942b235d26ab7bdedba443c0d0aff5b32b3678d5b6efa67abcc515044be2507e0b7a8fa8a7eeb344a101cf2b0c0f2104094b2992f0b66e18e9077d9e0601d07420ff93232e020f0f9560a8c965a0e4cd010d9ff1666004284961d9e9102591b2e7f31ec7a6dfee3225c879fdc432754f2c53e4abdc5d2abe5b09d484bc192b83ae3bbba022189711d228e33d95f5cd414c7630198f7acd5baa10b2db99e38814e4576717cfd0e25e6a551fc535a819dffdf23a5e2c079a988b2c2a2a228f5cfc238a9018978c2b6c6b979e8fb10e44908b02ad12148327e754d295df3c493a2693bccd6d72612d74616a8d61a6ca6faab184b82dd9b8c290cb1926ee22ae0985bab94742eb42a4da8d6412c4fc8579a3c23ec00c92a95e02472e1ecdd24de3a98898f2065b7b9384e7ff51f4a1f03d6a6c4c8aa7a5691983842bab2f97ff5c3477538672c27575a8cff1ebaf9c34336a65ae222dcfbbc20642d32a2e461f0a2dca0887ae42a94254de708f4f94f01034139bd8efb842b881081f12cf0e6c6266aed4c7341d494a6702cd4c16892d27b29095b7484010190a54962357be24d2aea7834c5930105b8a242edbcf76b1fb9a7b8b11a037abfba267b280a879b7d1e3206fe6427115559408efc772fb931051afe87db2660144741385f08834444bcbf5d9bde54317e954210bfbd8fb786c9603ddcff590ecb402a59eea7469f7a37d1d2782c791ac703460b6560ab909e73cbcae5299cffec0e01f3d50589e4c642f8468c6cb439d3b30f1fd09bc54b1f9062a0d7aa699a0d30ab7e188c117e65717cbdee4cac1badea10f1bc22b420498fbffb20098356c5cb93b0546bc3804d0452a49e0a92063d9cf1dd18a21bc5e1fb1fa5f17013cec7e72f2eb2ca4c7541c8a71f86cd2c640c5e500aa25fe97610cc87a71bded107a2c161f1f0dbc164e1f2a02bbe0b31394b4e8806a7319f90bdeed33823f6dd0f600353d8be7ff1fd2b0fd4d3947aff74bbeebaf7b7000a666e2c287ebb087abb2804b5503ce71700653c780551a29b64bde174499f67862ed4815233f175d024c6fe7d91a56b351b8ee14d76816c2f4a44f29c84a57bd514c1cfa627bc6aaccc3c5a7773071940fa6a20d7cb722ed17c665f3868c694631579cea9a99ba9a5ce146d7c8f1551a8e131bdffa9665b38bccb6bae1a65337cbbce5d2bb175d71e12e3d093c9724a63cdb6382dc84760a1ea878691e49fa9464dfe2b94785a3f3902a3e6117b120ad5c2ca7cb2358395be67dfd28d99907d0d91a4bad064d6a8a418c342a1bb7c314dfa8f3d2e7a70dffbdc0a09e34a3953f40c2bd821dd41efc2be496b5831e9694c65c03ccca1d71d82d89128d01c1c278c8d28d06caa003daa83e4685d6e47f6f1e5c6ff1c872d01a24ac9511718187da197e017fa66ad488318866177421cb168729563e15682a1e28621c553880e3bd5bc5df16a1015d4b8483ffa88c1cc3329e063400437e819e330f85f16d30c6237c19a7a5e1f771053125e56ec4ddc4e493f3a31b4607473d29bac4fe1d61e65f14c72ce576c03e1a52aa86fd00910da9eb552ecf2b0c963f835e164fd43de567a7c78c9d701bc658a3bcd38e9c23c31f0b80d01fa2a66d6c0b6db54637b7e7c817cf6a757fc59b6efdd0d1728537f6e9b3483bed5c2f29967af2a0146e19698eee12c51c31517b1bb692b0fb78296a4c6ecd70afdc62338a298b84bef98c46ece8d181f7841449fa8de22d2fd70c7cc350bc11572fc27311669a943f5c3d0cf188aca77bfaf4cb5ceb31cf98fa3559e82684e9c18ad2da52076336fb0c53320a0edb858a3c3b706228d9063740451d2f16ae82682d5b28f5a5fe21889b98fbd785dd55267c6fecc9bab0dc2e4c2eeec025860610aa039a5d448d9a0c27b5bd553daf571272c22ef86105b0919a2ec94a34130e03bf6b7d2bd229e5467885dc68de1a4b4f0c8683b028a499f87dfcbecb61ec00344a4a023fdc1be3e02ceb3e2aab3476b7f9da64f8ba68d7c4fac2420085f4ded87371c8db3032e900b30116ec4416788da10e4b425d52070273f6a0956746728301f0f3e564dcaf348fead42ae28ef007433c3349dbe8eb8aab8622b5387ea77b6ddafa21d02da7c9dbe9d314f806a7b906177e6c49800a6b646ddb36379c9d529ca1d6dd7c987c6fbc5cb79bf9dedb1bfead3abebff79d5f1b26bdbe5341df53a6f46cf7a027e077d87a4429b03143b724775ee341dedae833a008c75292757e72fed5258a877d0dd107adeeedf3b72bfb3dd3d546c0bb4f8cf7f27c4359965f5420e4dda7aabd4c5d654bd0266947028d22625f2409696b15b4a9736a7f38fbc3dc4ca155e91a63ea376aca8790941701dbdbeb39d7e6e619c65d5d4a9dc792539a666815976bece9fce31400f6b6c9027d27d8aeb8c6b94a74db56c46fd23475fd0063e44c5622b723a9576a8ab1d411e01861549d91d1a128dd9d1a5da2915f55bfb6ea61191d46db4cd9fdd421cd6e81d1cd7ad4f87c0b0e769f6cb4883f612ec38acf3aab3ca9b7af288e231e1e344ff0e2386385e2afc72afdb5c84c76e969b2cab591e67692bfc56d5c6bd8b6ea12ef7ae00c3dcb306770d6715d8472352172e22d906279f80010c6be21049b584168f5d1eed045ac076e28454d0c36f8da2e304da957ed71505a81ecce373779fae48eb78d9b4363ad30dd591a081a227534d78bb35ddcc1deb6a182fee2ee93f371471cf0fc8772f06a7aaf69ca81b447f5864a0dc5048b07951fee89262def05f979ab72f0273d8718e7c00a302b89cbe8e8b43649ad432699963ee2585527303db6884b8bea4e8e4ef06e8d315d6cbc4865b6480db59e438fb722372cbb499b8c21d4903cc3e99e8322d496d0b32717ba3048f8d3aaa81a49201ea4d089bea53dbf5ced8c2ac9e2a1f6c5e14969a06298deb1f6700c22f875d94c1bc4058064ae4d5f6f59a8445777e646344fa05a087e4431f1427c07b2a757c066a18df2a532aa996e15d700fe454774e2e110801ec15d1ec88a0bede61e9d48f2b363a6abfc5459e0e925de2bf74c684679e7617b085b27edd8be8c8702359eecf36e90c31e9b145bc259dfcc598523ac33f246dd45a610b1721b2168ed30afae4022746b4e07e73397bac093b63a79f2d8c598fa4effc3bd155e0f42049df0734f723ac78a78d7d47ecaa9771d68f0224f7a413bf97efeb7a2eb511fc39c16d85f22efccb4dfcf43dfe6e09f23bec395d7a5d837ea3fd718fae7ddbf2d4dd2b4f7d80e98c9a46203624ccc8394ec028967d50f3d4c5412e8334481059360a592006cec83cf51c78b09623089b391327c8e5324f5dcf93f5a4e78b051320cb41522854dac1c5c8a8d27f014b8ac06d40cae9cb77f92ac1b603bb413f936a8d70cd210942acc194da9256863abadde39128cbaf1bbf00a638be735435d1ff47a1a5e4c477639d129baaa42cf77ce646109297644b1678574e3b790b8708bfe4d3e42d3d5c6e8d0cf0d3f393ac3ae9efe5020943ebf62121e4d43698a3219ff7294c93b43b5df4da6067db29985bba96a9bd6b6dca544023e920b271a072afe162c825e76bf89af798fefe8ff34c41372e85105d1c14380451c2ee94474d8ad5f1d6566af0ad63b90d0245306e3725ccf7e4582eb2f60eb47eadfc2a9bf65d497ec979ddcf1845c5c7f78da0c88135daf2e81779018711078a6f7cad048be9f92f5b469f2348084dd1c6ad637f5c94994184a6a4d6210eddd2b32728d6888760cb3d16d6188fe1e3ef9aba8833a67dd1ac00ae03a91e85a128ca0f261176b8dce8114214cb41824ad00c210a069e7e18090bdf8f8f228fe60492955e4aec8b5c6300aa8d0bcc6bc2175d3344ef0124bbc5bb82184d9d9ca02c26b36abb3236c9f7991d8fb6922189c831cdd35eac5273be86ae2e701f4d0f4cab6c2f5d0b79a24fb3dc25a68101b495253025c3119f64a6f64ec508692d9625e37b8e4454fe63206cc27e6e25c19dd7faaa8307b5f4ae497bc53f0a06bf1cd9249d4c0d8d9aa3bdac0314d2ffaa76dcf0a62b75d869a2a46002bd42d8e3c2fffaf429b3c41d390e0cc752ecfa859a9a9bbef342f86ed23a256470bfc18bd3dad9b0cb423a6d6cda30f088da51a4de97237cdea0969e3d22308ec89a4a8f346def193f8583f63d97c1b620c069869dd1466f7c86b9aed63ac8deba4712b2514efc505cd8e58fb191ee421d0622d218b90485fd5aa8a4dfa79c5ceb935905dab4aa282c3886014b55178b87ae822283279ad67f74c2e19c95089ed147bc6ead21bfb8d00889ef5552c9d35747daed3c06502fed52154d23ed026535b3e1093065484539f03f78a9f6b7e0ccdf88661283d9ac68d6fec011d19a6a4f892e80d52e0d5b0d882a84f2d173374c586cea81c2c08d4827c7eef741825dcd3327a8c82b5e6c081373b64445cbffea60f7848494a3269380daea20d65e55462b809caef920a9ce2ce72f7dc4d2d9b0a08bcec92ab6472f7fe4771029bedf167115445e9e45d822dbf088cb3562df5612a8d4b56e74d76c05b47751d9e0f47d8dbbee564292c004b7a003c52426982a64ea16ea8c0f671aac521e36129ea736378c57701401c5e94561e2edc10f620499e97af8e971af78cc0aef62825acb8435b003967d4e76ca28849d8535ecf597ee3e1c772a87a695adede38a855845b97cfe981b225c7f24758cdad0d9c38a7b2050d07160081421e542990b6951228372cdbbe400fdb6025b07ee63b75fec8911a012b5e6ae7ffdf41741070480abad0bb864e7262dfaba3074674fa52cb7a614ea116850284dfae5163fa8ce273cb63dc25672858a9581e86d5c0a522d4143ae7d80bbae160be05301f23716165366a16c68dc8fc6401c45b1f098ae5270704547543a8bd0ec30fd116db9034cb75fcb7e338e4e1de5cc6d6177fc27f2a9c3e62d4b84f98bb93488f939aedd5f8ec92f411f7d8876b0029029307797694519a681acfc4bb5b4005c75b173d0cab15591e826ed0c688cc0316bc1a7e2818d6cddc41933623ca8713a3a8048d9c233383f3790ad432d25e1eeab9dcc07021e91d075611cef6328cbcea50b79bcdf1e292fb52589fafd374f0b5615e353cabf7b72ec2f067136d357638af6ec725fed91401241fdd8117627cfe58601ec3cc20c9a15427d2de78bbdf27cca425c8e02841656491a490c2539d225293627e0b31295ffd8ebdf89ec2e5bdbaed054dacc4a9470ec36a218613ea85575282435c8a00853cf473ab650334cd691b5b27747a13821470d60622bf0b1c8ecf0c85d5f621a98198da6d2aaa3655234dc89e36b15a680c88678a2f1557912b369e2ce9b0a7d858d6cb745f1b531426b488efd37f3741acf2577ae6f1f15595f8ae54a33fb7bb447dd681bda9c883fb3cbba63ab5295ea7601ce753daced2a92b3296dd218ccad7887244efc374528eb71da2e4f2eb43a44c493378726abbe92502dc02fe1e175b5c06448371e143a68b91d235d1d5fbfd937967648ca5bfe589cf79759f146ed6f6533d478e782858d758eca964c07227d94190cfac7064a5e753418b37e7ca37a255d76cc04bab062df30361648f521168a696d90a95443a991e8b8c87f92f902f7102761a1e94343c98854323f58bcd7daedf88a9196c700f2e07a542d553307cf554690da9031665bf4768334d6579802100ac568856ab8d4264cc4d999f338273e9b487f4361b16a7d44d45b2c68846cfb8c1c843c69e683c1f5e562b71566d388a96423020963f8881cf7339d6a5b7c9ae0c088422cb9bacb5a88be4ad6981c742c5a1e9d1c97138efd6dd0172ddf61ba0ea6586836511d5314ba99c258ac4fa9b493e5988c70221bf5426d4ee7764882af094e68e56ca288f504d243a98452b36fbb0bdf5e6d06435cb12b8e835c790405a331a2b6d8e9b5e543272c87288a8ab88889822438ba498d0c65c5d083556bc6c1ef018899d7ba4b20be937c8a616531314ba01743e956e7a1cbc862dc025f15001bec29ee0dd14fb022ef4102b4ce684e78c22f08f37f484b11d4d508fc13807a2a7c085eddff9c8a7b1863419ce5c65bf4b41f0f82de8ba4801903a0f7c0f6b61aae7dcfb6d93b33c5a94dd8bd612def927a76d9ee99dd201ab1aadc3217696e8841fc49a6be8e04c71d3db4647e5ea2d9c5ff23f84744fe2ec0c6e30260642e22d6d54d7d9c84917adacd1b86f4309ea19b4f32b067e46e4cff89f56a7c3f6085d7a147a1625153ea513f1b5139afff626e370023534caf5b677d26454f34e54cb7244826a89bf3cb50466054eca273ed2e6af2916e05134fcce004e50cad8ab567ab59be868e74076199b0a3d46650c0b8b88e1c5152d1699af18bd27e22ff0e8bd2c9f999ef8a8dee38b38dda500e67f78087166db7c96021db6c53eb470d22a32babca348d27a0ab5152da10881c965e22a3aac0b3d6230a8d26a049c13ad0073a70783ffa99d1aba82e346c62a06db055705114d0e19ec8e0d2439e770a173a4fc781b27523626d27c52dfd755f339b3acaefccc08a5a57e37fd1d34e27a7064e530d8a1c877bb6a44bd64d13bcd52e0caeb3664f32f220ec8db716c39028155987046da14885bdf560df441fb046440c24c4f8df456ff6c4a15852cee9e2bb1d2d740569a237d84b95435054295046d246c16b1ad5851f1b72a914485ab3ad295f7ba57535aaf6397aaca8d7d5777d0f786ac96f1b9f30e5dc92e0f28009b4889c5c4b27e63010cf61c33dce42276c2a599206a22209b432937e283160d501bb114427287eff7494c84bfda77fd7ec4166089f5db796832f346ffb58c269f91adecaca06b23c9c886c29068354cd0e2aaab5c31bb7d6edffc890add6e03c49e2c3a2dc1ea077e264d51b44ae2aa20cbdcce33eccf02da8ad606f8e63247bae24c29888131905294c497dd0f3b8afc4bb943ef5afdfa0c48e513e1b365fd0c507e53e79b3411a2e04fd564ca3d0264effbebd4007034bda66ddab911d1222ec9379f316b93afbba2f610ee5423062d717b10ba322279a48ec2cf753a32a129ca120d08192d038b22b02c2e12a57c60f37f46389bb822de419b33b7276adf0b1fa69861f07457c159cace0043c5b9b2b26baf48cbc0387588d4a4efb26cfd6aaf6c5d2e874ea4606f40a98f4b23d7b34984d3ab5e83bed512d26b67a7891decf494883976b7eb3a4db61348870184aa2c63682e61ac5561a824c273e45089ae4800b3531e157366348794899e63944ae41bc845d468ad519380eb78088ff96bdb9302876d9d4659712b34738cab0a646211365188da9a561d305473394f52064bf991904e0624c8221ff29be1c0a571ac9031cf268299a335dfeeb4e6ed08699c7f711e050d23f961c82f6f33e118a517651e9d7a6c5fe5962506480c6e2b652928e81ec37ce174bc6580cb6de821947aea2696ae7b98e5ab2e78d77d4f1cd3b5ef082c06268033d736616226bca938ebc822165710fd7806c2cccc68ee4c310e85b492bca15a5f7a1bd1a672ebf0b1b032c3ef090e0f412b7e650a8b54ed2a84240ab90db3743a638d3e2ec145413b32c03df97f0d5289bdf9f51c6f7336b628562a79014995a23481e5335acd6f2a64273ef6e0df0f97a2575f0a46ee5a0f95c98d885f96470cff4e32854d988ee6e261301ac083dae3fb73caa28fc666576b805ed0e0800654382ae946c42a15e9bf6bd31ecfebe8b6b78322e897206cea0096a1137413345650a347808f5885a651519b30b6825fb9b02a9d8ed20a7403f6604bdb2208b91a7fb59ce643f12ee483251acbf8bf847b83f45d7fe65412c9143debb7ac3c846d1354323066e0ef0924e932670e7e6d25cbf27dc405ff6fec38f67a5795053bfc04e91058b1fcf15ddecbb96cbaa87467c1ab06320fa35bd938da682c4d607d40d60c0b50e5367f06240d4fdca5b0490a3f97178b6c6eb56c9678c7dc8f5a44172668beb38da136b823e6be144ff29b6f3cfb5e48640c670f78dfd6cfe40e1296c581ee91debe739cae80e47ad80a2dd9d7d94bbc6078bbe470f67bb217642032b35f213e0797cd0c3286e7ad0b6fae370484a4dbf772d11164067c52a46f8bb96abea4c8f56628f27680d672b1b77f8e9bebffef7641ffa623c7c226d137b027036e1365dcc4c5515a1c8cbeb67d25644421f4cae292ad35315f60c6d2833a6e81b7131ce6b0a044b4913728e120363632b09a1abe437acbf232db2e9508c1bf547079ae2b378ac4c18b55a4b66b65b2257f18006172b4de292225915c96a34d617a665a3685cf5bdfc24a47a660817e55a489d39a63af44d49aadc71dc2762b5dce66ee25461eb82a154546116ee8de15a9e497c44fc092b223d98394076c537963fc7e0d5cdc55ed9d91872451c36374d237a236974d64cc2a59bc400cea9dd07ed2aab28256faa85580bea0bd48762ae977ffc1facb24d101a866305cf1c1c24e0fafd8f31ddd17417166879b0c5647a97323ae81a45b4abe1334f2f52b6dff6974ebd235e605b9f2bfd6e0d9bc273d26a913fb0b0f6a36e28a3669fd85177979b5a6c03ed48874e8a084ad468a07fa69784ac34430eef6c278459c914dd12741924357ade724149e91709fa95f202ca4e750ae1afe658938d73484def6c0ae52f360f824614f4be6d9bd39bdaaeafb15c9ad7d4980e11d6ea10df44066ba1a8afbc2e49c564207d125d3757fb1dbc6b95086abc4d2d7da11647e2b83d2b1e44c71f98a1284b82231901dbddca530803ee7436a23d70a269ac4adee089701d0098a300cab055ca464083202e37ae0739ade1b2bedf905e3232ae2adb40f8139195b04d2fcd64c17e14fb2381fe168efd52f915a875e5d5bacd83cd6eee0941248e27188a9516ef71a31fe2d30880cec39decfad5c844308600d1a7205e80e5a3354e7089aa7a8568d00341ca63aa574a36a150afdddb1e18afc6287a8fef2138f15a9904ef1e058b26c5742f9ba3f670893a3e21f83b12cdd623f6751dce7d6b1b453d827c78af32e7f0da7962ad448cfe5a4c6784de2980bda9e1ccd1bbcef8f9adae72b10974ee88b6a80fff67315592d1eaf89ed567ca5c3b8cff34a6c37be24c704d299ce83fc5feb8c8dfc4ff42d49f428d785d03a00380c3e7a47077ed90516cf2ed7a385514e784def81704ab98a99486df617cf6407c10ee6f82a1dc8b41ff8dfc722667de016f81e0894edac7b2992962dfeb49aaf868e511d8ee67fc7a8c5caec10c426f77ac1f3e4b44cef874c0134998d67aa1a3c9f1ca2ca47462feb3d8eb07a80ddef585490d9606c1bb1b07ee7340e74d50832ecaa81bcd9fb0335e79fcc6793787c952c42d11dba50d20ffe0496da0392d32edde32018c3fa363c3ef282cad20125a08c07a40850c21c291d19634f3c3413469c74e49e02e88d87e3597c84eaa8bd56942e124fdecec881004615b63cfd55ade023d207b417f2d3b84f05f04459e379d0e0c364eecbc1b682874ad2f0cd90d8def363f3cc39423c18d3b35e538c4351f32b95734bd065a23a7b30fab871c52500d8f417bdd2a7ce0fadb3e398afab18cf587b8b15272d2e5fcbff82a2b2cb568a342bebc420d6a4938588549945e02441f42c70d3a5db313d045c0b81c6af942b8ac3f367ad35b3bbdcbdb0a4e5bd454f9e86094f070222b1d2b795d82cd7c22834fa8aaa91886c874cbab380b6ea4dea4f3394c13f1f3b9423f99c19cf3d215fc889f594bfe5a84b67a2880484b6c7bce2d99d89c5ffd9e8cce5a96adbb9bd6a15102b64590ae40a7a834a64ed2543cb4f76b364177bcd20a53f271b454d5f8359f4e1c4d4b0468dc046c1cfa64da4ecdd2c41d5a6919e071ec6f7a8d36b83bad89891f4a862cb5ce64e1462f8cb75363291a5038896d36aad2cf5e72ddd7dac63c275aaa453990c6d4d55d36c6c70f32ca8c131ae78fa065831bb40f4c876df499c7e98c7f61fbc5fe476862c593021b93ec245f5dd760a7b2b284d1949fc27a594cc9215893dd49de270ac1d695f80d2ae5d658973a6f3dddb73079eda5ead98efd557e84984d1f9a147c4612bf9cb17b9966a5344c2899b86ab817c3545ca3d3c6d36b747332657be140fb7c1d0dc01a3ea2e4344479248c723d9b34f0500e0977a20ff42ce657ebba3bcce06deccde5f8f5624d9723a712343e67f0432567d68bc416c8657eed3e8c71013fcd22edede9257ce27960710dcfde875c4e51ee9cea40b8873880418142d0412a95319244554bf1a0ca90a671270735e9b7b344417a47f49b6af1727b34823c2152ff98f3f20e5fb34bbad7997354a82abbdd74d5da57541f4a630bc1774d4dd516328d869d4411909bcdb3e621db115874247c2dd789489e1568ef9ae6b3479208d00fa921ce8d4cee9a6bd93f4efb7531a40761a97184999aef965afb27dc712dd0802319df80faa47a220271148520615b03489737a13ee8067af853e5d42481073315e93ed487ed67eaa6630e4b687034be9f946fa60cf01341e2516a90c5832f68523efcccb4d65658ce182947a1e3ef3b988a365fa036d719cfaba3bd1dd4e812de3478dde16ff3d4f43f6cc2153fe432feba75595969fe69c582618759eaef5b0d715433085a52ce61e59f5e2681f4284e31244c8dea186e1b67cbfa8004c851222fda6791658fcbc8bb19bcd62e128f6829837df5e64aa44ce2dd6d857ca55ba77c547c97d76ca4da0ca5ba0a79b7edc3355be5a36f20fe7074571334eb2bbaa26034078e5e208bb514cdc8e834d52b9b33024b27baf67ff148d00e577afe05dc7193276450c86d23da1ef3fe1c8e18723b01b3167bada30e0761054266b2085562df5685beddd88ea27154472e43209080904f354ef8064cea3b9ae6ba9293583a97bfd49cfd4db4c515e84871ab7d8202dd3cfa023b9ed445ee585a29c9346837225ab107d7428107a605b2024809f08bcd49e77e31d8f8fa3bade8201853700377628b6b27868db75a82651277ac750586a267a8d6b84e95d743311db89459036e5c64fe904e1f2860e5cfcba6f684b70cdb023a20f05f71d34ff6794d53fbff5f42d4da69283ea778cc71f78481260498fdc80216a2b8aca8bf30ad8bf71947662987552b09d81e210448e8e4d907bb9f0fa82131aa06bb6290d39e235c64e822105f47c2e5912c8f9aa673c4a6f0ea872eae181e89f5ae0ff862240d50c9365ac3f66ac3dc091cf87e450309041235ba254313d4d119b0830f5325467475e3e25daceb4b20be2c13cb84867ccf5750e34febae47d51db582bfc5ca150dfd10351da5b758c595077404d34e4f277a736d94df0173de10763601258295911a59414aeaae97bdf50a01c1a924e83a89550547eb8dd5e493d670736557f43783dc3da162ee48836b1319216dba35556bd5993c7f31219ca5d90f8640a8aa1603539ef4a70528c591e3d98ba0beff6e1a373b84172e5916727370bcd6d064cd9e41d2fe381aa2382cc7a0894443cdbd35c25ad847b304083dfb5db2e964e1f21693030bad5350faf263408e88ef15aea1061a316db71ee63c389e8e001be13b646d9f0d16092423db0bdbebce8435992cc08d06486f4c2e2a563b377baa4b55a9ac9ec9332fb38a1f404eb41a8bc70325be2b2f4d7696d8da5b48cf36103bf94937ae8cce21ea836d40297e2337aaa7a24fbb7d59826d95b9fd148a39507e903182e3ed090f02ac4ef637ca3b9089e250ecb4435a53965a6b41cd0c44c52d102dd34d50b72d4be85885d17711ad1017c189b716383776ca1aeb6d50f66d9a1da4d8385873d4edbc325eb4888d0a8e032583ccc092b5778bddffd7c39e6cc2ef36daf3b4a78e9e378cb6faf4675fc6747ccb4d0fdfc0c8bdbdb6bd0036f4b934fdd3fcbe4590667b626e726670a3a76fda64c1d581f8c0f48ee6f1266944ae9be9f618b44c1a11f6441234f4bc601dbd770f794349e0f89d877c536f79c19e354151cd773352a0d26041b8c6f5ba787960a517d176181a42673e1016acc23c47cd3306dc3fa090eeeb38605510617c6e7fc47c0a5a9bc23600392239455a5886b4bcd5c27408646404fa58cba456305e55a503b96d31dc07edd030740ae233d813a4e45a32669b93e5c430b61421ac57a8c39cdbcdb3819d3984f60a00301cee0910e6eafb824e49e7346bbcc7dcf57fe4a2eab20dc2e1ed73e8efbdc9965b4a99524a01b00a4e0ab509f25d4a28656729df9a8dca739d98d59dd42bd46f73cef41f4cd131aca9a35e58548952332c4a3ecde2a36c10aa9276a1caa743eb83a462d83e53d01743c714d42994976f3a6212ea14e9e5a37cccca638874ca5f888318a87e3174be183a3e957bea174327864e8c1f31763ad5285505c8694c19fd66c6423f6f4505880e752f29dd4b517bf249dd8b92f6e46fdd0b114af792e46528c8695e781c25bfc76765020a9aa6208b7e322d2e70a6772f55ab27753b75355c689d4014a72f40967091d39e34d29e741703ecfabdc3315aa904a900714f6c2a409d822f5fc588dc41652a3d7c194ec35d0fad8755c26f7fa669f396469bba98e328f8a52eaa1c059f83524a19736abc542be50c17114e5655aa9c4605a851f2e5f6a900c9c7ac2fe50c559a825480e67fa53654f956d7f56c8c748113e402a73df93f9461833cac3646fe0f64d85ce0eca0ba5e460e55f917fda01426a8f2a3434d6580e07f3ba8aafc2f864e95bf83fc1d749e87d5cee0aad0f5ec8cf912a7cad9efa20660676b12120ce37e6c1f4cdddf196cfb8bc216e6d3a1a867b42c98c519236f391bbf943408cb8a2635d9715a12927254368ed046b356bad30e29c75f8521b57c482249248924113cf1583eaa3f770a2a91459249a7a06c62e15839968f4e4d95139dfab1d3292096904e9d18aeda939706a32679e0c1b675bad5c59df674bab0c1ef48e5f20f46d83e4ef5ab2cce38b1911647518b916ef5d772ba19a11ffa1536b1d9919c68cfbbeb56ea47caf95577fda14ff2444a56d6b4689095202a6f3dc9076985329517ec919acd88ebc1f6653c4dcac1c1f6fdeaa4fa2624648dac6c43b2096539cbcda0fa3b0783ada200d9f865c430af36dd5070b0adb64b8317d4681016b8d1202b324619317a8a3488ca674384a86caa51b6333386ad258a6de5557854e8a908ae07cb73bf352c3d3c56e8a988952f7d89f650f9955f56298285621cc57454ba9e287d568d31c196604bb0263e2b2999994816c100c2829c46e57989ca194e65c886ad47ab9cca2f89a60e06e4287e16161e0f145487a0d126286c4962c708b78004bb8ab6708494d33d5b0843d016dc10619372b650fd93449f2482d6f4d10feeee9646fa8f4409f93920b0fb15507bff1364836b626924d1a25c8e210d2bcde67fda3b7155c9f6fdea312e63cdc649b531febd011b2e2aa4365cd4a63353f975144b6c89f839d53508aca3547e63e418636c9793af0315be0a954cb41a1bb0e1551b5e859ac639812d93faa4b9ac995b9bc96283afd908a2f290663e3895d3a8d04ce7e464b4aa186739eebf52c1489a0dd6a43ddf843626d57f43a9fe1b932667a8fdb06867c0df95c9db32194ea3f2590ecbaaf2c09ce15790c214713a9baa5331d53f73a269b81f3f6aafbc4a8a3ac7832d08e7de4939b248e5bbbbbbb9c3f13f8d32d29ebf4aec20fd5517e4c39854efd8dd29affa4715a7c3b2c324c3a9fe180a0a6632f93eb692ad68367384f234ba351bda4c16dbf6a3971f7fb5992c2c78d22dfb90c2559b525d536b35200e13c7a9da0b0018b638bb95bfb62dda606958a82906895190b68c67cb7a3ad543f5cf86340d91ea8fb50f51d874c026653f7606bf4a76494122c217915099970791676770e461e14a1c4fcbcad4c2d4a2454b8bbbbbcb3ce96c4c0c36a8c3d0136ba4669f0e4ea83a04551d84b227da3fe3f96213f58b3c3564937254b575764e1b2117643b7d9c0ad3d918ffeebafac30cf8e354964efd4c264ef565f581608a7606c7169535caccc572c1ed60d3d919d005f5c2c6dfdddd9de0cb8bcf68928d5f05feea60e36751c1d998f8f185f5449acdc6396836db43fa4d6d4731d826d604b0e907bf17557edb174d50a12c924452497bb40b1b3fdc8ab2ae7ff53f8d7a4e061bcbb350ce89469172542829a7fb7f9a8685723acda9de48733c476a8b0fb66f2454f96591d370efa552f72b477194ae74009a21c3b64be851e980ba8e6652497bfe94126d8cffb685ac67dbc2503d3343751e1b6c19cf0800598ea33ccb21e5643930c2786a6e48a72c1f22dc4fa72c2023dc914e9d20749911a2c2454619a54b7b0ee98c15b68f9443d221f14098f1746abb5b31b5376386ed93445be4d9a139641c902d07ad8657331e8d497bae35a91c900dd32113d26c3624ed3907562f86adb9c3315ac180e1799a4de6a1000000e6549c8a7322068546633df4001db2e0542cbb62e848dd2bb610547fa87bc5500d6acf0ccacf6836271f2d8e4705c3461ba9b91f31462b5a3162a3f7b746188659d8c8e280b4c713b34b9b57cc2e6da27c76691313fa70a0bca5d974443919c000341b58b3f069a015612a4b6936d66327196b36463f3386ad47086c48094a0e7400da19d9fb8b0a3538a1849248d36a5835a331c7af7ead7f76ebe084ea8f75b167a4d9f02aa428377081c306e3a8fb24c5117b349b297f76f065b4309a8ccbc126835a61e35f79963fd570516155f9f83b7fb5fdea57abed4a461261a46c9d4665e55768a5fb2047f9ab740f44ca5ab6fca01ffaa05ffdea7f3aa5fd9117fa9f37f2407fa43da15fd1701a0dbbd15b1d0e14ad3915c454b019a517df0e05c8e1708055ff8cc769a28ed0f671aaa8c339c18d3ee360b03346b59f9786532dd782a5d9845aa83aa7d9340b4ebdb41f569bd0ce58695959cffde0ba65cb7e6ea74776dc4e7bfe9c4ae3549c133a1c108ea7539c13dc0fcae9b4c701891dc7a3916013da86b6ee043721a7813332ee061ba6c2e35404cbaffc0aed71ea67f9d2b3fcd6a8504ce7574e45a83cf71ced716a1ac4f4352bf4a6a6e987ed54fe8edb71947fa933759caa07e099eacb742a3f7c49e42820182708c6a94d25d7ae3198d83e4924896491ca69e6dc36938994f39ec795321e7eb07d3a04a5d47dccd4a9affbd829dbc75c325565272afb307524550fc0bf44da8140d790721ce50f0020dbc7a9be5f459d9557a19c8ea3fca15684ca479d5f390dcbfb3f50a71a32914443d5ff8d348d24924c1e49f42189389df65828d7c30fb6f81f2987dbd9bea843c3f23df55ba9dfaf9ee6574143aa037d51877feac7fde09c68943f6b35bcda9453b5e78f92c1f6653cfda736f1f0c6f4ab7473052b8001b2edd4a9860b58bdbacf03131ba7c281906206c87669587eb3289686859256b6215415520e15d5bf856643cab1c1c62f8976c66867c3993907c8b615184f3a7fda719a958c6706eb3994bfaa2bdd49676234b81a6c1f2967a53bed384a7ec63303af30e3e154271d156cd67f9c4a487ba49c4ef90cb68f9443ca69cfffa5b6ac36c69fcbd93e524ef58f537d51a77e9c8a24a4fac3ee3bc5e0d453fd49399d8a3e549dd2f941da21f174ead4bf24219d9a3d433a45a45393b422fd908c7c50fd23edf91bf99f07fa9566c3aa3acc9061e3fa71aaef5755070119278046cd341e62c4f4e0030050de0e3074900980007e9819408a46064c0e04a0330a608003748f8004d0a8304a6f5e9993dd987e4e559d53714ee8547f4ea753a6eacfad38234d3383fbd1a92de2031527a4470af5e37caa5b42b4503fee87dba9fe32c2d54fa7a216aaeb206fb6669d1e144055001d02e4b824404e2480ca075b188cfbd1317667d3276793b965460cdb375b0b620757ac28d2a1ca98926a066c61be169cea8fedefc79e9db152f7a3cfce803b83ab34db448cc10dea7e33161dad3606093c3bdce0635063137189e8137f28c366c3455dd91961d1826767f0632b48bf163c1861b1c2a405cfc6f8a314ad30a9fe2845284c5676760677116d8c4f0b4edd1c7618aafefbad5874a46a4927c65994a2eec39e45128c03a6fa0f7e0a29cb20e59c724acb92f39a02323377b725a324f204150c1b32cbc72073949625f789fabdb7351d3569e67fb57fca04b9e20c62acc21663d48480383831c6d561c52c0ae1d57accca628c1a10d69c3487578beec6b084d70c20197a5b8860ebc76407f3a31c6cdcd06b1482676d252a3f4b8e1f08a4d48480d6f6b427578739b5a0a068db2243404185fdebbc3d4c545b67b98728422208bbc0441107dbf68630085811204081bf88138434f14d537b1bc4774a18d704ae3bc992c9d4e2bd056df13d4cbf359ed0f6f5cee628ed3f19557baf5337e663af6559463f1c48d4f9721d35a2f2afee867c6c76362f8ab136c41228797d7bda6a9493b4474a799595f715ace525081bf74248b4b7b897f4d340fd30ceb43f3939c9b2ec6dcccf581ebbd9012b0be52eb00fda5fddc7437aa73dab81b4676d5cb7d215c17d89f680a2c7e9b92fa2f44e7bf497aef7cbbf08ef7795ebeabfbe290f28ae76e9ee9493bf1cf7277ababe54faebf4f2b153c77d77a5f7aea5ebfe1edb3232329ba3ac6ffadea3290d47594338cafb94fdd60f87a95e9fc92cb3d622aad667970c3ad2190de2a2db9eca4b3ac412dc979e86ab741bd7f9735f447f89f6287d3f47fb7b9cde7f6b52baad75dab3de89f6acdfba56b5677d0341f9759a93e4be8896ff165a04f72ddf427b949ea35bc3f2d49da4949408976fa13c4aeff23c4eeb5b7cee2500dfe569b4ffe95b5c680ff73fd193fcee2f7d7f899e1ed0f2a73f9d4e44949e7b7eecd4f997ba7eae6be94e1d0f2888387d89f2e0010504b666891e5010e1f2a5efb18e7af91e2ef40847595ffa177fa2eff2a7ff58258217540343382fb44419c75196e582768ea3acef010511a5e75abe4789f2cec7382270396d4d0bdd1c3504673dd7358ea3acbf640685f0635951240427aaf52bf4fdd00fc860613b4388eae73eb2ebeb201ea29e269c64d529ab71aaf5d68957ed59bf957fdab3de8a5e4852bf16e285faf5902ed41d2e5843d69b56dbb391f6ac97cf40ed59cf40d5abca7a4b552deeadef1ca729bdf518d76d4df378a05e5476dff5f2fa2ffe975dff99aa4b954fc3af97dd07ebf572ce396a203b3b4e036bacbf9e3599d11f5bf6f3b98e6b5a49a7b2b75e761cd49ef5a58e851c653d4ac8b6f5244bcf3d11a5e7b82f51498968297d0bdd66a93b8dbee56f6ab8ee34a2a707705ffad197280f28469488d2b7501ea511fde4ffdfd49046ffb550b5fe74a27d2fe9d4d73bd57aeb74426b743d197d5bdf482c8b89e358ef39eec33a0d59df49a460fd8936dab1be8158cf418c2e9a3d57eab626fbd6aecfe6f3c4b267ad01a30e87a9ce1f75df56b94ada994addd6704b70137eabdf7aeb7d07a55fb20099610efb80bd2b43199900c28937a6351bd8d56671604987ff6247ac31c6998e041bbfcb77fab9bb5b724e93094208654011f4776a6b0c99994e5dfbfb5bd6ed9a82e6f33f8c274306109bb533f009ce19c90c01638c1126a1614cb1edeeaeb71b1318b69ddac760f7d7f68fbbbbbb67f7c9fa14a8c07667585e5b903094dd19563cb168ac3792b9081b6536c66e1921840288bccbb0c9feff7f8c4e31f6f23301f9efbe8cbdd0b045a86d9091051ad547bc60f3e720be3acd4c33c866492f88b70f1bdec0081f9fca44438c584a77b88f8f107c7c563f30a2841864c157f13b868c2adb8b21434a79e1489691e1a1adb340a32cd05e29071b44e11542e95062344a97c3b3f87daa80e62fe1600bc222aa283f040a35a2872a782c1a88a818814e8d120d06151b6aa0906f816f875c58b17d2e4db3bd05b64e031d7b2118c14ec9bfe6100a688fc60b156cdf06d5789665fe43d050801114e0557d49c2f6c9703df90ce59b3213c6e11c56310feb00ad56688788b6a888559cb3f57b55460603a504610f79aa86423f233e192926952ea52375281d0eef84624046d5e8b7802efba8d9640f71784180200646c0c053318a434695d222aa237a5ae86a10aadf16656d8146391c8a58633a65b0edd0830d5343d1aac61f091a3ba38f68cf73b0f5b305e8113237d8f89977b44e1902130d31b1002341a623dcc35d6022266cdf0a0d19ea15ecf866a6d83e191468850455151d0b362a4a700422fc9010abb3d9c4363308e113b64fc6f487f3ad2e89583989ae4c6fc0f76f20d7299a198c8bc9c7d635486a7b92da9d620117c0752aec322ab66f8928cff6795ed1ca58e11729d8ac7708e3d58c025c007e31c2f6c9b03e3ec397fd1898a95214e971a248143e3e4070708eac400d8c066ca8fa0a0c1aef080b744ae5f791e854caaf367f31f829eef759480f0f611f26c241473ab5fd3e0bed0cd26f12262afdb6fc5a6153a6f6fc4febf9e3681a995db24d96a8eba3eebad48571a1919d36c53958cf7f877d1ce5af838c4f276384d3f09007dc7f48e88587de646a41b3c3afc3e876f895966e2bc47cb6f2b497834df513ebf9384daf7c7e6da29ccd67e3c074d7eafa81b15b79224f6c6a4e317ddaf39f2b47f9cca16752facd174de497e9857ea6cd05fd3617ea3f4ff49b2dddacdb76e95c395e31cfae557bfed35ec55a6bc0c461c1f65d446a895e403fed390756a39518462b0d036a2f46d983fd50cc08b66aaf071a6cab4efd74ea4ad21890d35cf41aa26fd8becb7baea0eb48d3ecf0fe1791e9d3298c083ba7c08854c77ab0211d36574e83f154ffd192119351130c07cbc1583a4c85613ad88fd16a94d28d80da1b196994ff9189644b12a404d58dbc6ea4ba60745792468d761ce57f296994bf8fa9a7faf38c7cfc68095393ed5aa2d315a5eb7ad271d5eaa8db24f5ea24aaeb150e4e8dd76d15ab2da8706ae66a065d3a3e9938cdd6acdef4a6edd299db6452fd61745b0329b6447b5d4d546c7f0d557f0219c450571c04c6b643071bd51f2b3bc6cd214d03e3fdbd676867c08740aaf7ecd0c180d1c146313694439b8e802d0cf76377bb6ca5b9d7638703b60e210e0f622890abd0c1c68fe3b0c745f57ae34c04cfd3ce76dad9fcf99d6be019b07e0ca506770d1bf0bba94ebd2fd6fd1a504606324766ef010f90e1287e198edac7a2b4566468cdda0366d6da037cdddd3d467f9b0dd818d56863549dce1a432c410212d8cc6451796a367863f87966965683b75e5a8d4bb3d170a4f963281090b181a13cc086b6dcf3c47f32363a815f234648215f41583fd61db7838d7d67276a3652a542e176b07db0a7c76668a8baca55bd2a2ae21ddef936682bff9e740da71288298a6d6adaffc024a3f483d20f4a526cee991a648f6f526c526c41d86ef733333333f3f22eefeeb5ee733608d68b1b585489de2c2a7ea42ba8f1bf8d4b50e3a2a1460dac0ff1a453281fdf009dda3e3e8dd8e3341b855c3027ab3007fa8828759d46468cf16bbce28c5ba4d27993f6e2a774cec497745ed4b992f6e29f744ed45e7c194ee33d8e8a1f818266ec9ca2eeeeb6a4775317d239edc5b7baf6d15e7cd9b5aabd18bdfda38cf1f752917a6201c33820def291fa03c66388435d4d0894ba746e4c0ef72cd650591362ab4b4f45c89afe51fd3e5083349d8eda7d1766c8220eb535215aea5214ae18d46c5c158858bf1e756ecc641f5cb381283a6a5875bf46d7a5f382975f57bc668cd7755d578c56c7c832c618d73b616e6603b6305f0076aae4ddac3d8790218419f7df8a4b898e548e0ab267c826b72aa34f95454b4052bfb8aa52ae963086fa452355feb478d4237f34a45391a8ca1f85a17e2322558241461564f9a3203882262ac7be1815a66914d0bf344c6ed88c18a2858f8ddfd4556c5fbf9f4fc0c248fd64e0cb604b43f455f5a2b85a51c057ab59db61ec6ed8706780f5ebd8a51f7f8e1d5c77633e0ef8e7b02aec7ae3aca3fdf9e3f388f402dedf0572f0a8961039bc5af3b1ed2e906337467e90cb9a17c891cdf6ac979605a3e5b3ba95c34ac26b7710fea59d2d13e286530c783d0541bf9b2fed6cb0bd660718c1a99b1121d5a56e1123aa5a440766dbaa8a9edaef1263657fabf41c1bb8a92eedf2feec2e5d873bacfe34dae9e7f406fc7df9fb939e2e7ac37ffedac8e1d21e7fdffcd1c7a7df4dc57e6b86fd37fa484d23eca71018bd31fffa1b7334ff7ae1862dfea4dff537ac3fc9df7a536f4c1beb0f5df6a10e21205d8ae5b0a65585155318a95d5d2ba6e0a9180a3f8672f3e2c706e3a1c4d1470ca3a720e0636f033e466f2af3c779719474bbafd052fab1c17708dde9891f568690fb198bf762c8c88610d25310fcf06df043da7db0f2befc79ddd41500fb209f865b0de30c5b578880d1f73f3df9c39a82ed653211aca490d9c5b83d9aecd7a1b432f8b36510ae87fd621e1801016b5b72d44e04cb267477f7010884b0ddddddd79977d9e3df801b638c71cac8d46563f6473a309960e66fda19ed6fe297ef3fd9b21a4a973242e855b8649dd262062c78691b88ebc5ab031004d58180ce909ff99d067a9b0309a5e52058132cc1c08b20901a10977481cbceb0b229eb7e8cce114687b15d7646accd9a7f47fa37b0a035bdaef374d9195dd7f9b27179749e7334fb8b36feef2b3672d9199625652e2bb085819833bbbb333bb3bb67edc11fdbb7451e2110c61e1a6c23222bb056571149b49a423e62133a569214401d39a938836559564ea4220b17ac98544c9ac069d4d66f6e4e3401441343965564a5836a499a0560c1c451a624acc4ba4590a0d298c062821e202a45b612159b17b6ae6e911e2aa4b861fbba457ad89092646ba95b440a1890966c2eea1691420a9a209090e3a887f9a16e11299e5061dd22ab21f57b9924eeeeeef2dbfade19496c75672461aafcb0db24e6af06bb244e40d4486fccda1bb8a99c837f470eabae0c8df60cd01f239dd918ff4865a6f3afc51cd99237e2cf0a7f568e6f25e1358755573a057baa47246031c2e7c840c867fac5282d18234ba8011173be40a4a8fa50b708112a2ac6d9c2a659028a5310bec3ab3f135f03057fa43ba47cf8b0012fde7a6865ad09c11d4be698b5c7c409dce3aebca64557d26beeae9846802defeef62e6f154a3e98d9dbfda699add8c11165d0c577b9306cfbee1e3dc61833eb2d8fef91dd610fef6edc655ee6ac891c82544689c1046fc31a27b5e9f6085c3881dd6b1ac26e25b8b9096f0c0a8cf25f48ef1cee37915b0dddf0bb97b7616fed35a4eba82177d38c75c76c2a707cde5dc89561e38f304ace8263e49f58ef46b62cb9bbdd4b186e8cbf1620fd62c591d5cec27e7c76dfe57f40d7344d09416525b85b083baf7424d8f699ab43c885aeebbfbe0ca13b8410babbcb38ad69b9bfe16d6c85f23f7777e9524a194d1bb3045b195b8a776185dbf4d474eb55d710dd7dcedd6f87338e0c72120873209f004208dd23d436c6b38de1973a5808368613ee42c81176f127a42b04f601c238d9074208b7bdddb803561e089d77f73714cbdd37777722308890c07c7d77d97ddd7757ae15d9e9b631356821b2ed77ffc670f70df38d3977777787e839e784bb3256bcbb2b572c4bf02c14ffb6e8c6851f29ec87102ad1dd3cc03ab8bbbcbbbbbbdb8960db67662deceeccc6bcf0c0bc4b7bfcbebb307e59dd328f7523e4c802feab5b66ef26f3fc6be5e73fea3ec8ccccd12d19a78df42e7aa0728cf1999d99a373e50ec66ddfdd8d69d8e50b075b7f13d65d67de5d76385760f6bebb7177bb07f0b196018420c618e5ee7ef20633ee3abd0117c6107a1d6ec38731c5eeaeef3a1530ff5e15d2b6158124dbddddddfd829db3427803424f02363bb5b066b3bbe7f47f71d30c4980c19e106a42c00e52e40948ea2723f38423b57f8646d72e62c5121aae59aec0b6412c585523fdb57f26a80923b5bb7b9d9979f4a526b6eb4f1e7bd97d292f3feb74a0bcca6ff7b13cb6dbf6b6bba4dd256dddbbddfd396664342a6392f6afcf5e7b79d2e920fdc98f3a1ddbaf3c4ac7d261ab6d07892c24425de9b66e87d7ed51ba1bfb288f5d9d8eeb7778b5b9680eabde5869c00abd91bdd67d39ac7a7d0a4dc2eb45bf8cee8fba8f4473585b77e3e4faafd75f3409af237a02e22bca7f45a14978cda020a476f5df2e1bedc907e1b4ebdbddddddddbf7e73eccf6c4c2f75d998feeda6414cf4ea603aaf33407bfd5c67cd5eef7d4884eddedd9984d7a5b0bd5ee90c09d80e8e68f3ef7064ebb94b2c02063f891018e9eed2a55b32ca8fef7f23ca6949e952baf4fd02063bc6ae91eb8df8ec438c52ca186394b1932e31d20dc58350a45ce952ca13a45b63f52598bb4308e90de8188531848803ba43ffa5d3795cc667daed4599f66eabccccedab44df7877181620830b32902079382a36f838f807ce6bbea45f67bd5b0f9f465f73be35d78fa4e0540c05a742fa6d0b159bbf7cfe66758f5b5352702a8dd601941be3524a098ff85e52eaf25dbae528801042226afcedb02d040cf9b99b58802f5fc6a80c219431ca18a3c2d6c27f6eda98a5524ad957f049a7e4688aff6ff042ed77d927345137186c9ff7fcd64b3afb372bb6a146c6915549d98a9625fb07a7f2f1968c452041ed35d47e18202c2caab32f0f363819c14f09509af0f302136831c61885a4c1045524610c4b38c2179480445302162cc8fe6188d0440718ccb7b7d05d3c4666e6f69e30c2b853acef95c1c86baee4d1e8e5cf39929347c320d963108b0c63224eba2fdfb22c26a09490660926be26fb116833fb7654185d3af53b626f54af118f3a3d06d1b621db965128fc61e4f85b37fce30042b0d9c88e6b36d773c8037e0c9a12932329a59412c69101b099189fcb0a0c94f48395f7a7deb8247c39b47185504a7ac25e62d8cfeeb480add85bffc13afa9b1310f1b1b7111fa338f647c2b9f0e662188339c22cf8d74fa7f1c7a837a2d7dc2e997a833f997a59968543a6f2cbc7641a36ae9675fd1c3dff474f230a44d78feb097bbfa9183d15111f3e0422c52103ffa64eeb67675950fa8d54c2db9d102d282d19a7e4872f21c4e17d61e30aa1fc68fdc7929e2c4ac43aeac3e1d5283fbaece0c70e421fd8ca8ae4f6160a1beff433b94cbad210a6dee087a9567cfef811074cf5ce64868df906d3d3fc8f2b3d4d2b09ae32d613a00005302ef0627c2276c727e210282bd8f87b6a0cb8a990ea80b56930c5143744f6a7f67b4eeccffe0861bb872ef408b6fd888d6033d16d4ea087239b7b50f061aabb3156f854ef93f19d8a5507acb14623476ad74433d46f26ca872720fcbbbb9b3b1d49c01d2720aaa4376812b3423a5319e35161d4b11b03e90e779ac3abbf7cb77663befda9103acbf0954e39836164b57739ac4e87e760a73b72e4b0aaf6b34b228755359b13fa25e155a3dfbc6a464ff3b77e36cdf4ab31626b7ee7b0ac3ae90729d34f099cca4ae054ff52135be9c8667d7fe9c8367f7f4e1d8d5373588e5361241cb08589f186b631fe48449bb91b13df7aabfb9088d2b1d6acee460ecea22631abf548e8689c3a690e8b66edb9c935ea5bf37fb3bbbbbbbbfb17c69180313337e14162e44757f7eeee529edccdd643c8902143e896a5811d1ee8d49416ec38e8eaf888507b8ee308242c30b4434349883ac55f64830ecae15eb0f512d577f7374bfeae543d2ad944b59ba8c6a7d157737773f7c518866118d67cf10df7822d0a176c5fafbe8ea27f3a8a9db195e7e39dabe39e9d06d23c3ca43d16386c1fefec3010e6e9a0511558d685921a36decf610a5bfcc2c6ec9752f053f7f71bd2c05c1461eb8fcf71bb1b76ef0ed943459c5004480b1543813b7634bd21df7fe90df8fd315248d7c60eaefdfecb2f78b0f9cf954e71e5ce8ec42123b67737a8aa68d0c0baa9b7109d76a0104beae748b0ce85da7b2183ed5b28f80f418411429c64108794aca66d27ff7d45f97d6ce8a6a9ebb4079f2d6b63fc4fba1731d83e8b8602fc2d297fce193f7b1bf1339afd4dedbebaeb459d05b3ebb666617cd4de032c0859af98300cfb936e1d8565dcafbd8d7eed6feaec3e58a796751776532f2925c7945b2f5f846c2e03574c2e0fe3b505a1f439e79cd0ea97d875132b36bae0b4e04309218cbb9a50ab59a781fefd5a37dfda9a9697216cf05dc674cdd1c7c73ac6c774baebbadec6d68bce64b1fdf537b5bbef6536ea9b3a3b0d649485c03e584fc331cba5bdf5e67a6ff99cebbb128259ec0bd83adfc6d6f937b5fb8ea83359c47ed9ddd4a502601f662a0b01db4eb5ff8eaecc1a5301b00fce837a85ee0efb318c339f73be0df8f36f2a77d65a3bba4aea2c601ffca1c50c84dddd5db8bb70777737b2c092d29216fc852e2974f77508954068c54bdffd1bd1dd7de19b868023460861840b172efca5d0a3304dcf84052740f9524a990a21f4604c01abc07621847083d07ddd7dddd77fb777b00b77f7fb17ba69fe0b08e1ee3a5c1dfcfc0c1952840940f60507849999b98f307f5cc264495194c9184669314b6b5e56c6f31a3133377333377733777337333333337333f328632ce34c3b41e1666ee6e66ee66ee6666ee6e66ee66eee66666666666e66eee6675ec26449d1cf91a01fa09f153be130b28a9bb9999bbbf9086ee6666eeee6e6666ee6e66ee66e6e6ee6666eee66eee6e6666ee6e66ee66e6e6ee6666eee66eee6e6666ee6e66ee66e6e6ee6666eee66ee6666666666e666e66e6e6ee6666eee66e6519b9fe9f6f0836d33333333333333333333333333333333d3853fc0b69f07256cfc71ce39e75c21c833957d2800e7ac0ffd5f4c910e44958798eb762f86b0f15bd65b5fd83ecea97dc339dc710e3facc11fb3d3ccc9809bca70fe09be6c8d0127486157d89ecbf06e7e3264649ad4f8be84a1911a1f2efde04f8dabe8bcb1a33cf92b0b5bfc1c5cdd710a82e9a744650a8b2a8dc62e2c6c417266cd35c408388b9a6ba65331daf3fe7ba2966cdf09fefec76ef90203b6301fd3e88c860216c000d53637c346994906b6c98c645cf4eb213e4ca43d9f93552b43c646ca3ded390b710b1f391df480aef180a3fc5b54a162525dd56e8450751f9240576421a77ed91559c0a97b0592a22b9024a97b0592235720b1a26a75af40b2aa3cbdba340925b33d1e148142109c400436b1b407988dd576999fa0e4094dfa8753e1477b333b753eb62f41f5487d31d2deea6705e4f342a4723f5e80549e3a513ba81576755bbbebcb0e6a2775bde8a086d4f91fcaa7ce971f6c729a1455d18eca0b50048921458551173e2e5675becd45449cb0dba8d0f6a5ac5e55677fa81dae88e1b0cddfba45a0f85163fd5e86be9455116aa7535d86cfa4d2a934b066be0c91a17e2821a89def45a7ea3815f1f2f123edf1e2c2c5d06f0d0076b688da41f1d4f93bf86043ed380dfcf9281ea789b4a7ce77c153e763336378d1a9f363cfcbb753e78b903a7320da98f92d516c2e74eafcef858807a4a722648de5a288477cf12f688f9a222cea8288bad84959653bf58b45acd918a1434b4bd0923a7f3f97faa5ace0971234a393a3a4cedf2f36914bb8d42f16750b13465245528e4549397f53133b528fa326ec4824a2eb62c3757d93945c2d3a5211690993f65454baeb5b742392924e2d29494722222921ea54ffca0a0a0aca9cdda5f8e4f0e4905429909254357a74b5b8ac7c888cae1e430b9377293e9dc27e7e8aca697e60b2692d061e08238f90a8d9a080486959735ed768c4861e8cd8f41084f50094659a767282e201226488cff66ccc146283ead9341bb0a27836663e46ca38201be9495a0dafa27c78c8696ff2e0a3bd99a2d9a086b4377f34ea0ed5d3dea4289fd56c503c2a2a2b59ca68842282c353d150abf626b692719a0dea877b4eb34111696f964a5ceaa6289ff6260b0bc7955040341b148f89c56432ada8a4984ca4cd6432a1984e3493c924773841a5f438cd890808694a4f0a8fd39c88b01ea6f058f41d357f3522ac8794077c8b9a1c35df058b6df4a8386c5fff45bfd1aa6e1d6160b4aa713d3ba9c5e5f429485a5c5c5a84300076a20032dfe5d432a39a71a253510cb04b014a09d26c864859396abe090a5bca639ec10ec5e3a81e47cdc720335cd2c9f7813afa8149a76eea7c2cfec0c4697e1872d4fc39fa8189d46a78f587a1f6e6a3deb0ed155f3852bf1f86ea7c17382e723af5fdc0a4ce1fadea87daf9614635a3da195c678aea6508b5b333463f4754d48f6bfff7325443a68ee8d2abc5635f7f8bf78ea6a83ae5d5f9d83ae9c2469f8204c39688c247369442b444872125757e4a90d3c09af9d86868b4b3311305a453110b9e4eb108e9e9d4c910944fa7567e3e8a48a722181a00abb7307513686f7ea9fb5044ea7caefb50ab3a9fa5fb483975fe4af79178ea7c95ee23f9e8602d4555e7a7743a20a9fb4c28ddb729a9f3793ec9a7c8537cf0909234cdac998fe9ec8cad736b564c7aea7c92929efac5a213fa9174b09dba15f1d41290d378a4a1f9a4261b90d36ccd0cda84bca14d680b4a59b5913a494275fe87ad7c10c3e6e25fbe3f33e208213e2d2d707c7ec422d7c2e8ea22a2c84448e200c5253336a9532ed19a8d96bdb8f8cf5461ea7e10d0884e653f7f029dd27efe119dea9fbf00a7913f7f08a7b17ebe37e7f48a88efe2852e01c548eb0ec5d3dec4ae6bf4578763b40ae2e269f4cc286a2732894d244e9da89d0e05a4bdf92e3a144f0f6016396a7e7fca6a3ed61d12edcd4f59d599b29a9ff2333f05687e4ad1fc9426f3538ccc97a13aff4b415267ca509d294475a62ca93325a8ce1f5dfd32d4a96f895e92c47a21d1a9f9176aa276eafc991d9696c185a02abfb4836d6bb6263efc518fcfb96da31db953a55c47c997f387912a3f0275ea48d3d0d51659c2901aa8d2a864cd96653d0b198d0010000200f314002020140c87c462b16834ced3104c1f1400117e96527a581749d324c8610a19640021041043000044046666260d020ebda43f7ab3ccbe7a0dc09a74248965857fb3b7d0aa343991d131898af16686613d801f00902eefe80fd6c5e0372a4d0c6021d9337fa777e9e1581a3e59a1887a142aa468729f587169e065bdf718488758729e1c071f2877d33118c6f816767ccf0a992361cf633c054dc8b06a36418a45fd29c76587983c9616c4100d651c269c36ba92290a182d002c0144a9549140dc557b155efad27f1afd1b1743e893bba442645fe0b342e64848372376fbf2967909bddf3fb247865d2221c3de048e98238c84b02fdbe847b9c87163ebb023237a1861b42d4252b3974ae865cb23be07bf0dcbddaf319c45d8ca06aa56262a56d1d08ddc0fa294ead932601153b44d84d419e705880dd32f9f2f9974e6f3bf1e4bc0363f22961967ab22aaeda5641c2717980ee6010078a6af1d456da08184589e6a475d06c583e7db9898c2d543747304a174989ccbeda7c838ad4a8bf4ccdae45bb7a8c1cf2562577f143049c69331ce1b9b513a21025b4b513dc33d2b05f19e89289fbbc255179b60af2ee0272322ab1a91543c4c193c40a235a3e1bfc6e24c1ac6cd254341f70e9c3f4f513d681316d1006cf704103f2c81ed7de523901a16c04c53b72f988064974a6bed0008ab40fd6e61e4d3facf5a6dc0eda9c88a976350533a6b2593c704249ddcf15a8ee99c8fe62f718d43f3cb3bab457891f9e823bf392955050da096e39db6ca7d2bbe3b58831b0a1065fddc33c2f4a4d5c353771f3fb577487668fdd4f3f8181719b2d5c73f49879c426284d85fe6baddd61fa4a08588de3e859b42de9b598d9496d7cfba3830acc7ee3b55ee5698863fa7f01f716b4d7b5caa98207d52d6a27585b5cfa30532395b9f5215ca0cb31ef1aebf758844015b7f850c001ba295326d16d9cea28310d0066a190d1f29288822104934f4fbcd64aca97602f43e6d20691ee576b1d07f83c7c9d48bbf7b57e6769cad132483d763bfcc8e3686a8aca268e5d4e0f47c5119f814054ba41b65790976db62b9869dcae109869e19d07c0fba0946885f02e25444a731052edd7022301627f9a8ab6f4ee7c7890819a0c7726adca0ba3fb4b9d2b5a731b8ab11c68ddf9ef08d80f8cfd3d5bcb4baafd47ee29c0a7ec925747bc739f3294b3481720f3c8480f79c4febae43e1f9338b5e783b0035bd8aa52ae18d7ba9f26308c61646d2233e9782f885e6ccdf3d7b4c2722bdf7077e345a6621e1f4048525e1ad0e5260b7b39d01f034bfca2a08438c73f900c978a1690e8c8a824b2c9cf33b880570f42c5de80621eaf07a60c252fd90e494609a96a033278b72ed1912155c8973f54d930d20bf4fbba751f88fa2932c189c2cc85b3504c7b611cc030da5c884a73e16afea03609b2f04b1d180e1e4d3187c7516e4ce7ca83110129c1b9b66011aaf2436ec73ea17d8e39584c0c5c1332ae202c81bd0e23a2a08fbdfabe66760a1fbc836d8b92a2e1c35021101e68003ba58f71b817b029e39c27a6149f828c10a5ca2b85215341e20ec20ea1829db06f41eca0c068dfafb586e455f775e0cff6b455d2e5fe94f0f09456170b2e210afc840120d7dbb536b6b55266b2fb2a1905b94954a2573411b0f83265fd7287a81e89966f535a2461b41f0808ed8b177075bfe7ebc576cd5b1a3637051df711e3f00f8a6008ea877b5ffd139e7485d17c5460c7673c013c0e58262c636e896aaba1fca6aacf9f7f291bd0243b500de1d07e77901788ca064c6b200618c17c722c9d57c5de683ed2cc6e5f09fc0b0898fcd9789e975802f5f679622b2951b2d68af53b9364debee750863c6081411ad40f2a9ce0facfca042f979f49bbee9ac6ef4439a59805f87522d04c26315c5e0f453a3b02f1c26cebea5acbd7eb2bc88f5577172e53353ccab5328cf4404e2dca8ddc5f1d669c32c4710fbbdd941206a7674ad4c2fbae0b0e2e5c9e54be3e699432f0cb76505fe5b0444f6d3803b6fe063c134227f69482ab9e88b89d537c49ec113d971bf1c6d12b7fe1896d227f07156cc4c91f99c8ab815fef95d3368f335c40194d4e036617eccdd4c102b88137ee004b9c74a9e21fa38c2c0b4362eb44ff5ff71158e7077f5fe18e2c8faff704191102a6eaa4ee39e79b5492cae949a8c66f9263d4dd8ed2249859c99d7d79b0d69f817a658678c95fe43a6dc6b62f3d3b39d9d84abc4e21badbf69aea5ac230384804c3ed0af81c8780da526da55bfd950b6b8e36554a07364999b4701e7fa711bd451ac53c4e1de8010ef7d2c56424bd11de74a56af02bd01317a85b94e5f360e5112ac2500c163aab8ec20d47ac3ef7f755479a96b71604afbed1ae76e9e09b244cefb9509c82ada2c9c5d5777a22c202a9377ad1cf101a1476e9992513c12366321de1fb9b780329fac0aa3c51ebab72f4eb2c9d5a4b21959c445dce49374ff8382d261103fbe24dd001793dbaa765e72b7d20d593e9815e85e9094b94fef5c7f835af572d055fa62248356f19c6bdf2f727be3ce5ccd9f297371ff9a1a18d46c779746c3150e65d90cb88521e30865e602e1edd97ef8aa735a2459c047af581ea64164423cd70faf3602fac4d2b0562f89b4909e34143275bad74f4d261fae702a2030aa3275af4bab4316837f228e98c0b04efb3c8dfe67081cff743e4053179881fb567a9591af0d169921ccc447ac77eaec3eb4ee99e44fa6102e3555ab24d97aac56d25d34c87c1ee37abeb6ee0933168d81d6ada10c84856f9eddd15baf4b29111772a71f9f129151d17b5ae77bb7f0324858c6a7b12924a497fed34905852261cea2b834a77eea7b4a47195634ec62e9548df4cd5cdee36381d95b959213601f0522b4f8eb1ceb66e4c7d473fa5c1d345b57688bc0a0d935d7241f1c28a069e22ac0621b9c01b6ba4d2978ad1ac368ff646a63cbfcc16e383aafc9621e22f57098d6e25134c90e250d68f4704e548c173ae3b21b26921b8712217900292dda6a9e5c02b7ee016d2b35fc604f70baf999e9a3c3fa93d4e2181d0e65a273f9f09aedac56feb291b4679e84299f4c06c6759b8586801354592731238913244c81b2ecfbb30897c4bb8854f958c8b98cdda971e328bf50fc0fddc11e43f6c8e5255c0f36926244a9205cb2c5b5c97454cd43922647e48505a5687c7205dce139bf7c53454237039ad37486e34dfa269ee9c24f608c1ee8a5510afc0a784e7af94dc80a8698685d8dee15cc612d144cd3ff711154ee70a83563b66eb64a14b127ef0ce8077d29eca70f3982822534290ea3592e5242f27bc8d425f5c8af1145278eaa111f03ab4a7f04128bd38385ea27e6d4606922b93e0eac6e5ef8c07da489198d372ebd570c0b97dff7736c724e96e6b7e496e96ab4d55ba921ac26ff8bb563345587caff0af7a9a58433558db0aaa4680be3f2708f79ed3d78afdd805517f9382876f0677332925558c0e6bf8b7939449dee3e447a7cb0daf98721cd625c7026b8f0802b04fd09b52b4110520e32a6c84d479acb0f0b571d4216245c311d1b5823255fcc9affad019f1cabc520dac89ee1701afe3d22c7d4af6519eba4d8a6d1867a8832b17072e702143fe9a3709d2d61bb828406b7a81fb5fc791d9d1bb36f71eba5c29eee17d50acbcbefc7f46dce4adb86519ae0d33ecb4e274ad259d73ccc9802395fd550ffb81c9e35dd97b9883331a0be88d9242518d417bfa81fca9b65db892646b35a415547ec09af411b8dd568ff1128e0eb37c24c677ffcca819e18e4095b531fb5ce0b228216067e30fa6915801a806c2c33060e05d21fda2b7e0159a04dfdf14bae5509f71b19cb6e08344a9f0308a22fdcbf6bea7de189a308d451ac52871afaa3b4734b51040653e7cfef2f28331ebcc361e6f6af1b486f39f5512b89bcaccc84aa54dabd977eed0398242632b872e43aca54881503fba875824fc098841cb07158da3224dbe2ef5189095d1e5dc16073606db98f5a17db0008682c55c6a206636fc0fa8268554d432d34a78a3e5ee15d46c24d90c24d925bb0a62fa8cd58db5c1fb50a530107438f7b99de7ff5f8f60543f800813ba7bf952d277f99e6ef724f1fb5ae0b134856a31aa0f1034b27f5a6eb62badc61346515310fe5a6cfaa71b9e3bed03eaf5e7830b678d245de013131aa7219313d75c20b9bde72494efaa85552382af938d0279ee1aa87797eadf581bd7e92431f90da5a18870ed0278d457e2014ebf204e35e2e60a5f8faa3ab73defece45c80a2bd14f6bc624586c6060808cd8717d6c97338ca65c393a8151e130dc7e005b52262e32d23268ccba10f003662a5746814c410cfffcf3b5cc124c7814545c99f02888c82bed7923243d5cddbfd5f228737b51e9ad9fe6a7179e20e22350b444c5be72517764b53d56b4b2f5fe40d040cbea3212da985a6f5edf808acc80ac8fa064cbafe9e30ba690b8112c2c21715fbcc85d52dd8e2bac597d3f2830a2b2764c09b68cb697af3742a22650e627011fb58e56073983bf47b7d9b637b40e2c3713ed603f78dfffc4d49dfd4227a364988b4f57ead845fed029d6915e759a25a2d79db08af8a553ac23bcea344b44af3b6115699316b7a619d4ecd415c437a5154fab3ca6de13a3903679617cae4b57786a7cb7fb7da079a0759d661119fed38351d1781a5eb154440c0ae5f218750d3d8114604e1c97e3e87fc15d8e3b3ca5b913b3e281caffad88016a2f5a1cb38821c2eb7136a5b06829a25a8e1287c23c677a4f9b9c34c12ac8a800ef2b4f1911872e90e62105d4e9f97ad4471fd202c0044455767cb5c3811757fe15a447817aff8fc0fcdb60f46f9a7c9c1388082eb412ab46a1f418a1d8b8294cdd138d39ddcb953d31303164fc7d371adb36f1bc36a521c0da5ab4ee5de48656e07697fdba0a862a2c41115059e874a27acb8b3d9b557bd4503d3a4ac759bce186dc1a44f8d11a90a1a94b22502eb944a4c0ecda333a8fb0fc75d166432a368f42d3640e0f119eafd898ec285d354d32061cac83b2f4981abc4dbcff38ed48c04f4fbd7dbd0f9d27bb70d37780fc6f90915df7b071bb7c07a8431d0c6cfe8f6571544453dcc1f665a6b11150e6872a13a48fd201e90e162bba6389a30edf970a98232710d9fd9d182380ab346fd2b38e7b0e9411ab9a71ba04412a353b14e4f0f2ec14a313281e78340987f3ba6227f230124c27e620e20ecf4b5022ce579852807a2eacece9bb24fa28cad162d05d07ea76086ab8512a4e4ffefe6d1a2632aa2e7699d64d23e19e455c163c892fa43a5708b778bc1ea82d9ce592300911ae0aa5e15f4b6170e24a808616038c50ee2c5682a9d70628f555ba41503d7046a0709777dc8c8537d9cca28b91868417176d493ee481c20f0d13673673d3fb179ecfa6475b360a7c985a6e2060cdf273c273dc9313c0fac319aeb5430f770b106df17e061e60952555d64caa9e206e21b8f482b8ad82290f1ad06c6bad7d07eac79543b69ed3d951289bbe51f41d9fb1b494805dda2a4d53294ca13b0f209c2f5f87e1d0f245db88024c63d777d4e76b8ca2c645ecaa3894ddbca33e7f42d1d2c932519357e63e04373bc01287857a2f61897db68fc4333d9c5b9c09bd46244d62f17ec07013361188a26f00ffa4ee91143584f5cc39f407a1eea88a886a2bc9d10aac5553ea8bbf68539a428839da65afce98c107e643a4e3e5be02204a9d7735a9715cd93d885a9ec71fbcc357604d444b5c5f7a6c73a5f74ee5d7c260fea1934d1f02b79b9c23547a0ff44474879e263b565d108d9eb735becdd4744a4a5274018f9fb5f5a5b05d680f46699d5cb078e2ae22f09ee763fa0e2e014636ce6579940b231768124b778432f72e2968805b3d726549404f5f88a84a443694bea6f406b4c3b72cb341a0a98177a09d90065c4e24f039980b56cd4ff28bf962a450e0b0f506655ed72fb3ce14065bf6cae925c8b6fea6b339bf5963452ea45192a2d6bd3788300d88b5114909a3b2d32176c274509440394fc0f02f2b414460048d9e1cb0badc2ae049e00f2542c0f38971a2eda721d5f9e08e216f0d829cd68d7c01d720209536bc279a98dff9c1ec16ce7bb29b7407d88cc5211037291b37aa2ec628190dfed98b81a051b7584c83407ed4791b514b33bdf5cda9d7b21182c55fd176eee826b61c4f50db1319ed308dbaf88146e9dc40ca9f1632fb96300ac7b523c11c294ba46e36033116ca7e068f1107da0eb005c81727cee235d1f808463c1b04023013c34f2de13fc588176f171ddafcf99c60c4d55100f53b3a20b5363947871dcb01bb25eb93cf25203eef18991e8d75efca90725d0727260b47d9ba10dd7bf06eebf0b6e1a61bea948e19a49284dd5e60d97c2ef3ef988981708c3e017cde1c28a74be3eaf7f340ea9c00a48098daa434199fc5602546601d499a70db315ae99a04832ebde01e426a1767709c48fa76be175ea4a98e7798e0f1414632b7ce5c1b3696f645450a9b607ad8e787d7c6e2d56907bc33eaf807448bf95bf9fe6c835dcff7bad4963f38c4ab267612e032215a2803cd0e47a1c6f38f0b3e9697632ac35a8406adbc206359ce3a70f0668cb35fe31507868034b408600b33b8c6a598e82be768727359b8139c99a34c5b10e3561d93d13f0beadbdad44df561acea2924d2306e256443550a8a9c868e1e4399dd39509b127ac608f008d52bb78e26a0098a9cb77b9e21a881e880920b444275e516cfa9919e65d3546a81c95da7e780d8c20674e01ec68c9a88c4f778866d22424233f53fa350570fd510e4c4ccba81b42c97bc04e94af3f98b2006cf9ae5fc55951e260b70835797f02103110f10b87effce9e06012e6f1949a0ff87e96871a1cb7239715a661d90d7d617ed5850fb84403fe185de1b4fc4f545ff09e5f20741fbe02330cc1d751d2636fa5b1620b5b22641ff509fc5b3ce3844b5522b96104539cbcc9fecb473cac4b60508f59d090e030ee4c3a3ab8fae9112174cc48c0205f045a524eedd0f31de47ee9eee6f05818c04a9b55bf4ece38a243faf3e474a60f334e20f9210bc32e75ef3175ae5ccab55610282841744df7ebdbfd25f9c5d3e45c8b17cb880b730ef0b19828875fb6dea9313afb0078e1ade9494c7feee1b521b39793d4424115b1585c7600ebd2228a9bd45a42e1ba4c1c76f0056afb64b95a7c199c925e634d5b0c4454783f6f497656f5e1ec89d80b7f3dfb2c6fb15036f8fbe01889fa8d821cbaa607afc79dee644e9b152bdf4c501da7342d09740d9976671ded8f102e6db2bdbad4137c6353d07c62928842f58a1ff1be61f5adb280cfd8a19aed81a96f9c3d54cb7f686b14f05dd1431c4bb279700f03bab229b696597640e3a49218edf6d8fbb811800b25310ad93c0b0f51b09e57876d77cfd13e2b00aca86291db63ba8443bbe49223a88be21a53e6612cd8152ee044803881a9dffb72344132152815d8773ab550e166384aef86ba5d085d71097d6e2dd68ecd6d6805c0e3bda86158390c097b0bf0099580000e4377e014609b921bca7d5f44660f47e0ba47308111a265533d889492dc077a1d8708d85d9dc65277766e0b7a6db019181630e56642978112ccbabc88316be830bb3aec64c32292e1706862bc84be8a78abeaf8b3d3b98ff02abfd7bb31792136e4e08190ba4288126e4a57e5b26b7e933233fdfa5661d3b677caa32deae9491a0e8a1b4f4884121fd40cc34659e511b5f1764ba3869c3a29c609ca95adb1fb9f77fc263a969fdfa6126fe218c91c1a73978c907032e9844bb52c20e8f807428f64258380106a057222a6a3a64b2c12303e3dbf0182eaed2a0924b21a13c6bfd6c18db74ed7490ba92640bb9edc9af0ed2b397ea201d6c384798fffdc78d92d2b633d07ae9e5ba4607e9b45bc9b57913a15dfe283f07096a842e0efaa808aa9ec6f1aec88ac65e84f6f2ed0fed8ced5d305fd784108ebea61214d74ee02d5e3c398902dbc65c8fb218d30709b3278f525c54ba012baefcbe7434353dd98834f71cd45ded711829e28aab2166644f7c6a457181065f9971722287e5c75adc96cae31819a48556b2a176434fa137a9cd53334c0181d66d079982759bee99ebddc4dba39e4f35b84826aaa424458c57c28444350053fc1c9e426fb735868b1974ccf4f6518ea6a272df105882475abcde4de227de0229ed1e4d020a8505a3fa8e21748e26342ffb4071a1c8649456a8ce9406344f99e56a3d110eb80b32e2ba5c26e0fe3d016b70a604239e59f7a9952ea5ed40270e07d648fbee50a4e7104ba17439930510bbf83236dceb5190eebc0a6b79eb99eb8390d7aba7580d3b7c433e94bd0077df3572cc060be2318153d0bf71f9fae3e4b7701e3eb1a52cd0edc13b7cf8a0961afd2c4dbc0f5cfc4b975cdc707f081cf265a710c1b68c6a9f07305af9cc9f5b1263235a34e586bb1a7f31299cdfaa83b0fce234fb8c82049fdc71d78787dfc9dd487052e46b6dfd7690d9bce247e6c8fad0834ee7b0df15220d5bffd2ba6082ba8f6ab1ab498f5cb37b06b082113b79d249cc81d1e9fe7de075565f9aa27341c0216717ccb17c3639b9109c95d72b4343917b53977f2b0baab1596a1b526db8c3986441173ae27b1f15e64562b7ea17e058efeff412cc6160e8357e785e371f17812954350cd1739079121934cca83910520f69df3ca739530cfa36e10c8c4880bbb55bacba515291684338c805df9c117334942e0e3eb671f219ee22f1ef651e12dc8c2451d6401a210f30ede7f15e37940e5a21a67f5774a05980f8ed32b4face018d9e3dfc03a4b596d89bf5524e25cb686f06b25e835c01be43f4dfeb0e0841d2eb072accc26122ad115465e02e9cfc86562e957f750631bae26eaad962b55c2678caa5c6deb81f3bb12c574210f1acdff73cecfdde0a39db03c058116629a4558fa4992a0eb88f02002fae04244ba9bf17cc08906134649b194018f17bc95ee4c772fd1325e31c0b3f318e7525b19191c3ba9a9aa9e6bc80ed27b51805645953b1ff3c674b110f658dbbd3d8a97ce1514867b6ab20ad8625b70d342955023018171b013478d0b610a306399c4f7989d56bb7482a3a28bd3f3b55516c2002065de59a8bed1b10eaaf4abc0176b478c1e576734549fe185457589c57a2d39f3a7ba4e9e66ab32532eef82e5bf80f9585cca5422888dad240266f938e4a49888b24446e7cf42275e72ddbca377e0a102d6120136e6752f6b2bf2c3c5312f47fb2e678b3081a90bdee9060cfce12bc70fec16ed7526ec339f2716ccc827c42b4705ba1e4156db5a9051128d47c3ab73c7d5ed2b8d902a4885a49c395f8db9f5529c05be93311120181fddba14126a03d9ba12e8a8389956687d13a8b95b49e297d02cae01c4a6acbbbe1d59baa26ba0e5371d2b53ea0a600e6add41b6f64fd91d816fde115aa715019d105536ce78981adb49f0c8dad9223229a5144acbb4aad089e1220af4f33a5aad647d54127154d53b5c0f922453e6ee4b1a3d229953209ae6152e10164a2c5c08d965d8d327cda24fe5fb2a6235746881ad15a164cbb8de1730b454fcb3ec5079194cf694d224da933857978617a45a309da26f7999e06ffbdc25308918291d8c48063833250cbb5483d74f8cc1342d372371168954b51a471512b32ff504f260d21d83605e43585723bab69333341799eacf37e9f2878cf3b5c6054547164a75ebe6378672e6432cfc7e8b34419cc72ddce61bc2e5f3761bbdabc5b34c0f7ce10d258decbc2c42bef96ecc016020bafab552d94a2fd9840dcc1bda9f20e37b803a6eb15bb376d59f1d6ca8bfe3332d6ee7f28616c22d92e534d9aab2568cdfa8a56709b1f71676623bd5c2bb670f743b637a8ce599e8046aaf6363e55f2236a82b8761f0b951d19828ea23694dcc9e9c660c0f1494f833ee9ebb82a1bb34a32d5950b645fd7b10a28e3fc5f3bf2f507020fd1cf1620926ac82bd2d856d6a8838215ddfaa0cd08a7f5b51018bc7673fe750ac7ad6416df27164412eb7e10c0dea6f71092f6d2fcbf6e5431790a4f5b336d5f25c1bc529ce9e1b7ae8660a8fcdc927d4de21c4d759209d97838e7c0372b64f901820f1ae18982123fe49cb6fd90ed865055b663e02c60b20f7cc38131fc0ccaa109c9eb515b10955896a9541864205a0219b02d4b7c5792a772f2a4402aa4d3b2aaf1025d8d091ab12cee3fc6821b1946b5340a88387b71479ca5528f14b03064293a68c8c87084851dd8bf65c0b976827cf2c38984907bfc55f2cd93cdcd58b8c564a2b32dc522525551adba2bda8ec3aac2e7119a1879035f35eeb4a0c05b2d018b0d36dcc16d9707e6ab93e6e82dc4576acfddc2068850eb415015b6374434856bb9a30dcdd0691ecb6fee349667050262f9975cd718537b2abe0311d7ab25bd954a377145712e95f6800da866b61fbd3d049ab99455bf83ccd9207de6200d5f5c2cf7cc1cc8136a9d9f994830c0fbb86671155ca451079867237519bed9c5aa9718aed1c6e794373ef68d33b5259a49c3d96a5458bb0e9ce5a0cb98c204f06e8367cd7420a7c902056ed0f0ec7b93307e4e927e754bbcb84365fb24f953c0200b6020a9c2ea9a2f987c6c9e80f0da56461c6019e4c4fec01d6a9a4f70e3832baf290c5d80dddcc0a102ccc3005499f81e5135abeaaff2a40671458e15e3a81196d8f578e24e26f28121e758d6146e393cc4dd3c43be01d4b62f5629c947e6a70c0da0a45ff9163dbadc03057105b46abad11db7c0988958037bd437fb91fa61abe08998862f1dafed53db7ffc9ef13ae2724224d337bbca48ab817ba5f920a3a03418f7c8e60acc7d1bdb94f6e44d747bd0ec56a8614043a6ed30800c914807e3020173afa580968a09762791d0b90230628e02af5314d1741091b0fe17b04e9b6a6d7c62db661bf55264c75eb92891c4d9f51adf5c0fe47777b3fb90d291dd490c059edce9d20161f1f2448d124ec98bf53cfcc9854adbb5521e6cdf0c51835a5a931288da758269fd15b657c0b31697c24f2c286141564e735eded7d8615af2893c7a345a0422f2481e44552b156ab793c9e867d718990ea056418047d7e868a435462c2857a2e7b6149d1e46d834e1898e6fb8fd483962981b1226f213acaf20d758c59f171dbf74661c324de5ca4fce748972ee7147ec0938592359afde74b3be78231001fa065563b911b73604b939f8b1a3ff43b65fa417aecc1012ae5f511fd845bad91bd6b49472fe2ee314870046adfc2e79e9ed6a98ef553d2f83ca8a0b8796ca741a2a4e441897e2116c8fe84907ce9c4cb52d9e60c45330969cb1fb9f3510064b425605313a35362e7f9f5e1e466b5d96669a815f158f14294fc634344984e60787346eca1df173c00383de39c6a7538998a20370176f5a82b47a24632e4cb4e1598fe03ec3232ec5a9740546c07638da69f4783b031c11ca84673091ae0771aa031bb5d962d1091d663ca678a5a6b4d80e22189fe736825a5e01dd24c6eb4aaadb608b14ec03425603e33ef798a2c50b813fe3a87a1129140e1c0df6b0b61af1e2a5f52fae3c1effd67a013b3bdfd0212bcf07fae45e180ecc626bd0fc22acb84d6d2ccd9ad90f7c57d247593bfb440b184999990cbfb5b9763e2cc6099373088e67b8b8577a8f89f3d703b9319ff714f62342b2993ec81db60cb5635addb088249fe192ea2954b00ed0ac4494050aeb88cc196109bb87c4220e241752a8d26f97365a8792cda735bc3f6081cd56ca9a561f8a28c5a876aeb1729934f19f71377ee17fb83d2e33a99e27123c6efc85d04d1545889452b3fcbddb1c66c15bd3916cd730cd6d90a5cde97b8506a17aace9e35f9ad84027436ee0e03ae02025e800ba5864ae68ff4c8d2e9c31d0667e7b290946bdac6e9b7c248b5f4450a4b3db6c4cfee4d8fda1d9ca783eaa9c6bca600aee7d930adcd5c0711244f078374bda6ea47b4fbfa81845e5536429141201c1c605ee75c1545a48074316ca384e6938313f7e4a4bee086e472e36a0349eb2ead70005bb8489fddb5709174ccd05e428c5b31292a6293be6aa4659e0f81ab6eaebe63581f25c610e773ac266f95d617034c654ad7e60ade9d793cdde2c6c7150b2d6044bcad73cda8a473520bd041a3be83b4343aa028b3b02c0bca7905725a15b9e379210f778c3ce3203804ab09414030f782e91821129b333541e2674b2b8e55c8ef72d9c806798c77b44a050e6b64236a55eb8c0b63318000df409f9daaba074a753eb56df52c79f5231b0dc5d738ca0f19cd92a39e128ba787a29e83b50de15b6ab509b817b442abb7668e5f4336c91567139292e7ff0b60e5d8a7c376a3743b8f9466de73c48ac332a5c11d7cdc005a0532804ed5a84593dddfce520f41b1589312535e557b3d1081f2d922d206727b3c8955c2909e0feb0acdb39845368d770b6a2b5c8597d11feae810fc01aefba41c7b7fb4744fa00ae557cceb96878b0d646895a82afe8d63c140694a901cd969f95b7e856e96b8d6f6317b97a99716aa26faebecb7f04b4505e51c34bf34899df1a90ecb8c33c05f8563d2069c5633d21d0462bb072782378d18a8485a74f27ce5befa570688417c24248892d353bf46d8c5e93be7774228d5829f4e93b6fe1893ee07071e0ae50db5dee2940d1faf4f872624aaed2f29d9e2453aa045918a0ce7a0168b14aa370ff5a3c9bb7dea8437a2bed39e410e9310a503eaeac5fc6ce3e84badb64b50bd0afb6039669d71292a7bb682ba47aed37ec16949efaa58ee604c3e31b74f3564049fb3ca50e10d40297c77d5a08d37c7df62e7b5a5249811c9c1e74f824a4073121c5961840324c33be30dfaf3682fc6f43a68174379209af03846e64c2a1c62f5fb21eda84837c50284fd389e0c42dae4f6d69919e8e4960e2428cc2da2a22bc066f496753e72a134d88f8ab46e37edbd278d228bbcb3f4bb388549de2ef746b1c6a7c3e5290a49f96d85608a583996b25e60a9284dcc0e48078394316349cf2e347e2e084e7926366855c97286514614612da0a1b337f5a050010a19b855852f32064f071624a03a29cb5575769817d588477584663dda2047b6999e28c8de5a6224a64021d96f5bd9a502742834af2047d164fa09927d1c1cf551fe6070285a9be888999fbc5a15a5dd105f09cd30250f90dfcc8bc4a6ae36cec8141052d16c616bf0d58face3455172ae43bd003b079e05aea0f1d90454566134ebaf2cf69153e0ca38e0f28c8a7d4e99f4ae5570747bede8b02c8319d5eaa3a8e947a5a5c31b989f17c8caefb2ff331eecb6b90a18b00a872437957a8472802a90b2800dd957314d565b85f62b449f8f67a7082d96a3e46ee70bae9f41b909662178573083075de851a869256da034f1cff29ce605ce9aec7b6e3065fcb3c93363cf20f6bb354e6e06fcfb0fb764f3e68b70d1074b203cde63b6e5a50ef153ec79f29e6d40c80686fbba6ab185553bd743b1661876ab650e60d76665d159e3209dd9106646b2dcae1e490176255ae5a031e6fe087f628b9b9cfae5710aee80adbd831b3a641e0b20f7b0f9b9033bedb16d807aefa38f5ce28fed307bccc071def3663e758b07920988f832f3b82bdb4fb0ae7631ec2e6771aee5d77611d591fc5cd541836e20a1268f1b648935c949b1305c1f7a8a839c143e882e7064949b2805af97db067b607b14fc37f389b56ce9e3402dbac35bb5d0e0ebdb3ed0631fccdbfdee3dcc9be4f2b2a3ea7f84dba22e6f647c60509ee7104c456b83435bfd8a889b4451117f9e70c4826103ec542c142e4d5a02d781e7c381530b4e1008af96913c0219771381c09aad1830f7833fa1a08b1551fc57b954fd3c68e6e0b72e083090a5298d6a255f3b6749397ef2ca95893c1eadce08cb13407bbfbecda46b873f6a1700cedec08f830dd031c9b03cf0d46789c33e78e878373d200e3cb883f4a1ac244fe174e2bb7044a8cf94158600987bac4c88c151327cb224ae0cb05e2264344883a1deb1888c94256f27acf9a07246d1c4246c67ecc60e41d03e4c41cb1f33e38a39c33f163481d9bbdec34268f2057968404ab42ce94b0176074a9357226d8f396deb1510ad776e2d970a682796749b7b0b74ed66cec0e4feb22a569cdf4d8aec99fa8936b985203c3574c0f4d0eee041f25b6ea0c6d3c591a0b81b1e937dc6e62c67bc7ae9a627c37dc1f80b65657eb03b1013cf1bb6a817caf7ba277c371713556fca618e596aaf2751044416e999a9df65ff6c1768ab51176b3c50ba8a7d1030da56ee8d53f820fb276d5fcb3e014cca7aedbd66ad5d7a5b88179938381cb7fe4259de7acd7117ece63a3e25f76445f661ed03a8fafb7408b98c43f3675854c2ad9477de2ba7fa437b3d382a3a8262569ecec1692712e39b9dad67cdfaf533ac64fe316fc86151462628beb9c32f902fd32df6062460c80f7ea4ec3135f8636722a802fa5ef13416b9f6e04714b2230cfa2fe37a1105decc2ccbf1a9e495aed3614235e7daea635383198b27bf1631a4ae3d151015c1512704655d3cf97307a4ac612c56b0262161a908d2fab7683d2355629727adb25d8b52e76fca6e684c2c14ff3117902848c1b42e9dc23fd708c5b928819c030525ed45f1a3b7623b1d387c95c3e5af1940775bfadc8ce2b533c189b83514f5a0650402a95ed2a2a2ca5d6b3d46f10fdfaf0b407a79c2809b8b81041d7d4964251fc2e5f4fc1af34e66caf82f4864d2f61254468185f0300530132d0e003080af5caf801e6e4715d80419a3a486a19a817cf0dfd7af4d80407234841f5dc2db86b3377e73876b1b33eef2145f92fa3dc343eefe02b2984d10ce07069a7e503febcff834f45f7a31d3ca66f7779ecd43ebb4c7c6be4b12f94ae1bb593a17dff9c276e05e9e60c0b2c04d28abbca44e53b5d0e6949167a77283155a20929876e266db6e17f8282f9bbf84cef9b8dea88c38af58d919892617044bba51d20a9534a5d251f2dfbce27d62034e040b0212480d1a61d2a2d6ea7c8da9c028c8da6c893f6c6ef96d1d72653527a998766a11bc20fbc7042a3afaad81e8cfe572699defcf83f0247918ad4da2c1cf702930e2c22c9da491517c28f19f7cf50d6cd6129da58c3f7ea649e75558124c405ed956abdfc4892c22bd78c2a3da204782f878c931317df8a6d53cf1cc36c609116b82b1c299cfa3db033c63c69be7e3cbdcdd415c0bac43b6c49c8f159fa7008013e62200f0ee5cc74faef7e91ebb4cf6b8711fcd39a19119b16130bf0cdcb5867031b18b65adf1a26b99383c7f9120e2350e58d68a0c7828ea205de67aeaf9376d9833d1298e7c6487c2dfcbf42a53aa0a0f99ed410fe26f3e4e5d24fadeaef8b4b80e9428c06f2047845201ed7cf6db84fc93d9a294a9587a8129d60b354d84e400835e7353c2899b029240e0afadd8c9a05bf2677f492f50e78d493e6e97b9c54042b418bb54c293c5492d5e050f62197292d1dac08ccb4e773fc4bf11775e815f8524ec7c7535c87dacbb5b27a4ac24684863b04519691cc915594b038a1b341d8330658d7102a224db2d5ecf49413593855105fb89fc635e447e848a58134c0e36a5412ad69d5957f1bc5ceb2d1edb34ac2df0c3430e79ad9fbae694bd1a6ee41bb4510a57531e672401c082a40b995a33bbc0282cbe27b49abce90c059b7c5be86ea96e2c048e6f16e8bee66361db8a0e21e8225c025d08cd3416e4adfb0492f5089ce506c21853efbac077e316c11c894d09fd06ed7311011311bf5650c282801c6c711030de0fa0c42b683c627da4b650e36224394253e457de767572953bf919f23b904b941e238364c737fe0ecb886babdc69680cdc59529cd0a94ebe4e0b77c9364b3ba54b6f5f508c1b3e4836f07dcb985c0f4b679d937c219c53f800af589918b77d7e896da010e8efde020d0c84fcd85537a7682d3925c81e15bb21403c48cf6389b4422ef9eca2ffdf2b44c0c6c8fb6222506922cb5d14a2eebc67ce634550332e231bf29e35b2fb14209edd16c738821ab91dc682534df8a6815ba338f35b2813c85d2e58387b16be1240a174b0e19223a6a93c1e494a2f33f8a604930811f4b20b9de6d86f928f3c2afe6366d250ef27dfc371fdb7e321c852fdfb0bb6e0e3d754bc2006c0cf9f5ad44a75199068d3aacd6610979ad0d2336acbbc9671dc484b4d53cc0bb0f986e54d3a13760696f2ae2b0e4dc92a52570f2c014d2a4982871474ec4fd1ded035da6ed4369213b63a5861a3df30854679b2c0b96e2b0c4ef1aafd85fcd94c47c5d583c408ac392e735c04509514ee2ee4ca3b290d8879926f20294e2b0c495d577e63c1e822f743c6c4bd2d385662f5a1a872555821ef24844cf4cd84ec0f3d5b66e5d46ba814cf464155b054e0f0fa8f1b1d11780685c6edab535f11ccfbd1eb58e71b9455f8891f215d282b200ff4fe15ef658b1d57f365e3e905b9fecd086b1407e7735507f9c3309b943e1964b5d1ba3ccf0304a3236615c6918e7c9c6cd088dff0076bd07b8cb05da31bb8e7d53be1a3a2f35149d32a3a3b7afd4ef417ef850de8c7cdd2d6f5eb4aad603ecfb00716e9dbd15a52a43066ec7d129ecdb834e23ebefe89dea48fff861303f7b6ff2f2e465cae8b104f037df9fa4043f5562d95cea51484b8944dcff3c728930c801f69856713ecb365d0701ad76051e8204cafcb50add00f9e0d6d0c76a1c3b03b55192d3f9759391748d4f4c136463da8c2734e17422eea51234e4d213c18d3de89db53387a3fcbb3852218f462fe48ec2ff32e8b572659a52b1e7d6e50d967b6aef649f2409a06fc7c05a015326a9aebac06fe839a5ab9e9bc14928910cc8b6379eb354a78db5ed94443c163dd9c3def17870311666446c15a89292e92f04d25bf78ab9503b7df02688a6e902c75b51ea03248c0675ea4ec5ffe5c63b5f6e8ec4f6c21daec248349455f26224d5a6282260d6fbc5249cdcbfd1f902d1aa39b5ed9932375ccb9ccbac28b12c13edfb67949da00f50cdda7d3f0f04804234762547d20c40a0bbd9ba62a49d822048d279ce5f85705da7b85fa24e30153dca19a90cbacb06d9c5c41a633bd65e008fbc6e25d161cd6916195e719146f285b42c313c2964135e064c03a0a8000c50e0c0b638b752aa689eba4aaed8a2fe24493da19dc35a1fd6d7a19e17c82836b2421d4133646315b017b567c9a618dcd4282345032b1649e5cf0c451267909f03b62e278ded470cd43dcda5649625fc33d1c42f0259a30c0ebe838e9a0f4b9d128da068734e25ab3dc09ca0a4cfd6bd9e48b821755c4f5738c96f20e6984e56420778cd13252cb973c74426720c19bc4334d8aae5a5dce625f06d722e67a93dd6f6cd486a2babbde889e32beefcc33fb690b57501d0134e68342e63738ecb3e0de7fb46e5adffccf84b9f7981a9d3de575a9f8bca96517041a8d937c6e5b96ec1dfd634110a5cda48e498b5a78ecb61a2a4464a22719cc9c4ab02298c4a60e5c9eba5917b757d30032a7b6418b6a56045f8cda0d251a0b47912064127e3b74e99c57893359f819708763f1ac698be9f7ea45986311a59999a4b497f00d2658a305133581c99238c7247b0251ab4c5a046ef8b9130feff03cef07fe6e82c3c4d64e126bc5c71422c916da7896f2f9a8877406a62c4089e07987980fdc159f624d6ec396893d000039a4ce7f0594c42cf39cde13b572f6a64f551a91c7088319c74b9d28a7505be9fbcf28d55880bc4377ba34885e1135cfece59396ef3cbe442d99b7992472e89c3ae619048969593ad102b859885742928261329f617c1f9a59d8a8a1a3249130a1c3c94a0e1be8b8bbc80a55eb314c6b8fca99805ac2827e3958853097016010037e731a27d969d4837977109a7aee5acd298305be2a57e78db7b98fd29c050866f8351db498070400d1f75fea1216b6bd85b61061f9956886eb4a1f404cb22a728127a4c8d78e69011c66e44270029af75cb14708ac70e75915bb8d238afeebc268f241a1989cb343d1d181805233b706b0f383b2222890fefbc80334261324cdf22ea9c63f8b659126fb8553c31311138b1a6e959fe5acf600567ee4369883721b4e80d90af4cdc1dd293f938b98c6009481c0ccc1f4843120227527dd00b7f1c7df930203b463f25034bbe035a96d79b1f2908fd5f6bf366aea321e97ce642e5a025ce8d77b39ade9a39a46a5e12b2f3c44bbc5b5f6297f1a3c2a4272a739f2229f9e2fe84fe2609e8e1ab97091e71ff21f3e3856515d0888795425f269650342ea3df80c67d2c678a5be24ce30392c64dce50c71c9e0f49145b7e6033af2c0820fdca07b04d53d90fe235efb6c054237fe620b67652f218b2f9a2dfc0fe4ac199b65bffbf11583d46286474a4d726cb3d6f3efa0327d054a3cebbe3725a4654386faaa0536a36163d6b0b74b0c215bc9150be753600387e664456ff17436986452f4469fd03aa6124e4abe7b974bad040a0f8b35a8c88da98e475cf4832bf71f648eaf68bb88a6029c373e08bdf043452a5abfcc9c37e82468eda73d7e9fb5aa18957b7189bf84b1dfd400f94390cab8e1a77b938205393464481b88c54e28865b0ed0e6c75033fd6097748c8b38287c801541c4c29192d416e39e5208d2da8a00538bc9a654685da6799d022bade6a866d74bd41cd0de98f4a8da8e8002c8421dd05da08113b28615b68168530a79799453721c7065b4f8d49560e908373d5e7f34e112d3387323700f5bf8807b5e57ecaaad47f663fa44e849e9a8862c9757865791c97ab6662a1d6c248cc70389a2b351cf3d149c71a6ea3b2a635c6a3ddb243b4bb2622b75ad1fbf117d4ee21e07db3e6f37c1d61a237dca4dc2396774ef69aefdbe002175ff86161430de034c802c9aa86b227e8a6ba3a96a0ec4c906ef5c5c576fce083219d8e765a212c2adeb74bc79a8bdd59ac5b55e5894d8b5658aa4d061a675ad201cd13caca7c4b27f24c5a245599f855734d2b272251f3888d26184b5c127d3d356a0d763595ac100b081a834fe4ec20b849d59ba6f5961fded27b30a15cc4a022251258da5df25954df1027b80eba515e1990bfea6a4ee228ed4dcb69c39ca47111913cfcd99aae6df8784b88b6598343dae2b7a826ce98f71f90a796a382eae88f16d46f162a23eac9d423e1e2b16151d0b05ffd731c601f1af9ffd3bfc064f98a32e35efc6e3fad756ce46dec4899f66c090d4139c43f66a370e61183f6ee0feee0a0b2613a2fedf7cd65badeac6d23cd9c27f4ded8940141104f81e4f422f6025aca5f024a3d016170a2c325366b7117fa1ce0af85f53c7002072d22c37c92f708f1bc32de98723bfec26ed8fa328ed8f49e4fe939121b779304ddb430370182c24df4be4dfecef7a35893a2054b1b1ff78b8919ff6250a23ce1e1530ce1b88e9b01e019c7ad07a64ecb758fdc1c5cd906c78bdd7b10de453839c0c8281c135c14be3a1af4ad904822a1af63b0d162268317b29760811a099f066dbf85b9b2f262ba5e922614ea63c68c9287c3bdf05f4352f3207c73193da6f22c63500659dd313cbb017f6a421ec38f1a67a2625366109de50c746d0b825e3d67696405dc6f1c31630e00ef86bd9f7b13440e02ae2c49da91f17a28eb1502b5dcb3bfae9e7e9800594f01e615f6d50f15693a41fbead2bf4500ead0c352ea46b9dcd17d512223393f9c4e7da660b27ac8013da763dcde938515efbdfa6839a8e149de287e3ec1526b944f80f3b1970ad68acdcac4f595dbce3b4edecd83e2fc3c897f09bf09f73304fa56473b398e99cc7d7420a03b83c39d262e9ce6f45574904c16385f46e3c1c742307e6f8d1842f1d4586433442a11ef90ce4fb3e4e8c222981c752502913f42639a15dde86c9b99bcfab25a13eb2f72526a183d6b7fed40a0098156aade6e87e89aef13ac03140b2a7536a76571c51715e97c70682e92ca9c1490c4f1b27f7925e0b8af745294fbbdec33ce750e3352f16e8ab56211a3b44e3127b2080b0fd89418dc9cbd525ba5ce5002d213def2782a9c5e9653568efaec602b0c6ed9b6ed2dc4076a241486782113e376037b1d205fa9244ec1a9d71fa1815d1a0b548916ef3d8979beeb1e3cefedab402ed67db1279e0668c7095452b9be3246de5dbee1d0357d7dea7e0b9534a67b939cf8f75825b1ba3f834ab3b1a82473c05139160e4dd69b2616f82927930358f7aff61d081b7cc704f50d62189fb6a0150ada8c41922bec42c121033358f4a7aa040768d3e6ab92c42685e6a50a5bb7089e59585651ae43ab0110db310cfa9524d90ea7195c6e8e3480a2279a26572278b1092a74c0bb279fe8bddf17409e714b7b2297e865700c1d644cfa4b7c7ca200f60912827a4953a88046f7c0f1a9fd7ce80d7f20ab17194f3c8a670085e1d189e8152e151b04d4439bec81261c017ad6064678055089a8b0176f237730dd17bde55a1bdc35a96668abe78b6d2ac2912de5f063b17e49dbf34f0c178ed81cba9f986914b46ccd5023c70db9205d8e07fc4ccb31be44ac88141a5d0bb89f9e2237f9806424cc23e2d4487dc9c99dd8102b0211b6221e20ee7227122e74c64181f2c677a198b908e61bc29368d100c97c95c71e8b6da2e2fcf45d1a83dfab1647d2f2d7682f21f65700ba6f5078a938ea7f5cbf7ee45d1c795e3ccd94923df3e31a236ae7fbfb4435e275c8434a6a1af10e4bfb63bedb3826a48adb21586ce9d3728a743a11511334fa1f61eaf431cc4ba2896e57105244f508eed7b49cb34a2aabbc0bd6283f23dcdc36a28cd28e526593e99c322392cf00a3f1e21d779f10217865864713e08334d9ddd34c5cd1a5055fa64379b72127b79ba5a3f60e9b2516dc26f1382f34a96d3ba742ef04082b0043799498e07de278fbf19451dfcb378657d1c6df4fa6e74fb9157ad287ebbc4f52593cce3bc61fbe648860381f35fa3d92de437d48993fecbfe8f507f3fbd017605aa0c5673facf249bc6ad5b0daeaf8cbf7ff6ab16ce66720a2a44f7db5421b5d7f6bf8449bd8adce853205d3896594be02a5fbc2cbdb50d7315b11c7df3f9d1709c3e457415461bf1f9816c6b5c1c83fc76ac010f9b741e8bf0301d2160bd59234e8cb2b737d4087de22a55d80f04860f9c2a110312d1b3028f66f380df4e684c6c8280511065accb3d4e215ec2542fc632f4f08aab82d2a8eef7ff78967421b0ec19c90d2937d6e209d0318414e33f4890c40fdcffb9a27094bcfa35ebdf607ab9342678279b21fca4f7f4355cbe1ff4de91bc500f80e0807fc4466e1e6f258e8a47727f4574fa982b29ec616a43b1b97957b12d14db8c742af0340c4ecc82ac69eab2ce8fe6858b8fd5d073f66a994050a4f7110188698d355119454f8c79460709565976014370b25acd8a9f11714d01a50ab805886384ca16022065479c915c6d7eb816e6af7b99618cefb716e2d9889489eb6e2f28afdcc14ae8508d922b5b6bd1464b59b1057836d9585ced5ef2183e3a0cf0195f9c9551b8017d368bd8a2f1d1f82c9cd35cc90668cd1dd7317d066946c475bc1d51eaae65066194550000ad372baa2b880625fc2f426f036923b86c113b5bb2a256a447ea77a7aa2991536c423a330d0c758ab36c7bf2bba71d2cc43a76c04f5bb5c5e3dedd7c12f1e73231018177503eb45c9cc38c563bbe40ca8416900503c79d53d8d82f44490af414c849d9349ae42a8126cb2d040a8cb08b703696cb083409d81bc404ab19f260057c33b30d35368e61415f0f6f09aeb26e84b73351841f1d0c52bae47955dbca4a85f8ff98c2fb74ed08220bae0384081352a59298355a2f6f61b0a232048b03e0d267f0260941e6a283661f3b8585371c267023afe8fdbbdfb1293368f101ddb17a0ca7b9fac82183608a7652e39bcb8b59522ba6df813740037c639df81c5479ec8ae65f6510b1792b8d45cc3a5b168042a0e05493aae69b82ce89521e666a653f8bf8402bf2e7595bb4d1daccd216726184138710483e40eb8e74408752c79d08f17ba089640b98669c9d509c4613a52a8fe3c81b4245b19170a2bd0558fc734589df664ae62e2b1596593871d1c14539225d7e0a12b63e04ac4811dcecf95156a4a5766cb0a9e20833607c785f30ffd9ed931b432669948470117172929ee0f073b1e8bf4cde4daf4d8b4a45e26dd9c2410aeba9b08ca3d38268bfc9a450d04c127dd347d8c7a92b7e16be785000de369ba0911796193122bc74184f62922e679e3e89b83a62fa891c5f10cb9f1506d8c18c94a09a3acf0d713cc336c855eb46409fec463d0f9126a101a419deeda53bc8dfb415885541874bb16a7446361d62cd639e8232bd92d61c60356925c96f41f103048e9cf79aa5b9d11e93fbccef538f56e49867efb5c4f751d6b173b6e210c8039ccadf8a9c47c5d8f36b5c64f2f467428a833f87b0c4cd83775de45b87d7f937178c577b17b2fb573c07c9ff5527f3456030a3026992d096cd88a5700e7a1c42a6699ea13c6a92460244bda9178310f6656b1c69c656415752e1ea1a842b4046a649384fc6d6000db4a3b011273dcf5ec7b7f316c9271ea843d7a3961a439064703815f7e3a401f269ed8ddb1bab90157650542c02436c3271093cf3af5127a3b5520648f64d60b30521b8c077c7f3cdabf8ae3c91c0e8a07c620ec90410f5d2b60da632c39e608ccfcb1d1603c0037f3783c44664dc91d0f9a6504e8d2ae6be1c4dd3df7d78740d9638dd59d2a3ea61eadb219774f630d169ba402dd026127fa16121664ee0fe6b6d807e0f857123a913023514a5e700f4ae4387f7c70c3a6c1784a459729de554a7011004c4e89a7be259248c02c3b80e2b14ebc00ae4472538c0fee7e3da913fa73cd6522498e31658825cc448a2267550e76a23efb86f1f21dc6655b1fc26ef18bcb2f3cb4c5d2dded5f5fbc20cd9db7383cc71318da43dc9f30b72f7ea6ea8546e05db1e28683d72c8798f2bb0875d02f35a2d303b26c72a97a7ab5561a6eab92025e85a4b80cfcd5c0c00fa4b831fe12f4da8d874ed434a84bb3d1fe92711cc79b2bf4c4b23aee08faf239f18ddda7bd8cd9b173751d5e9586686ae82b0cea682ee7b9f5d74a03c2011e0d9e0e2af53a6d4a6d0abb692de70ee7be39557710e1c9dc4f657b1d9769103f242eab355c59089fd573220870e0300ee91ae4437f47d8c4b6014419c687746514d82a83a6fb0b0cff1bbcdfdedda33d2ced1f228a6514b400956be971c17aa0ef1bd749a51f00fe0e6f24b0e888c91c4567c9168adbb628f63ac335d180462e6992a8040d6d60ad8c57bfce2d6248f8ed60828614d817762b4f4f62d553ceaaa17b1a266adc7fff0d4d412eacb739c16e68f508d9000f2a56339a5bd89eb16ea0815ae93347cdd09c327ab602af4f1f94a5b411ee133d31e2ff149afb6bc3081f2743beb1b8392510d4510a45b9dee80cfbb6fd3c2ab8a57fede921bc3eabbd83737ca0086c343cbe23eb6f8e499e4022e5f50a860eb377f82557f11bd7367123abfa96873e8e8bdea8f56ce37e15730c63e7435637d2c03a7d553f32583a4841cc8478ad7486bd48d0906c0c330d09277c94c4927e89e185e8e067cc68c205d44914570af084397c4f14972ece02c3aa821cb3c778f9327523e5a445f996593bf8036f1f09f8936969ace749d4d2944b3812e0a7a81d33bb5406699345c03afe500ed4edc87b385cd5bd2f9902774cace66c25234e96da38cdd40c0daecdeb08ebd2f51f0fc56e8ac562c20e459e8a7838be336020101fd9ad9c4e7d49456fa09c39f412d60d7cec3424c115049c76748ba7793e54431b0b131883c3d6160f3440a2d40129cb1d9e1668d4c1eb66729c822d9ffbb36a11c1d9a560066f9ed1bd964970103e1c3246b48291ed6b6d8ddc8450f4ba632b6b284730b465d338bf927eae182a974377ea4103f40f29b31725d896d54ba2aeb4a93be942626680b3e9be88845c4b9fbeebf6aae8d12dda9aa1fab58dcbb6fa2f24f0d1cfbc20c10b26b4900134b4ab4c18ff0e3a3528e8ba697448cb07991ce47f93fb1f1c2c56f846a7715df0f88808b778875b826d6e67b4ee2077f452b67db801439d976ead1b46163df770e18377974d0412263d9c7f59ea91c1a10a09d2d35a026261a06970d0f5e62863df06cd5a9d2601e340f7023db77a90b782ea2d18971585e5a3acf249c8f02374100498f6bd402217e959e58a3fbd3f9df3962eb93a818e8a3b1968c2e90c1240a1ac2f0a7f4b100a4192e4d6a9c789a70138ca587d01397371dd7218588cbd8eddb8e13fb1fd7793e1a611f2a53fb1c97d74a5f7f0e26f2311f958c6df2421eb89f9673d3ee301d470edbb702ee77e9720888f7b3f0b282e70d4aae5a4098b4e4f8ff906167f8964455a4a2119659ce3747a4d6fb86d06a7bbc3fa5790251929220d01e1c26a240ead266d6a761b6eb574f306dff937dfb72b799e0dc07ba72a7219e5c228fc1cce4ebaf13a0d231b6f8b38cb091ae0b40863f4164804cfa31637acef0c491aaa1e0568cf91f967f1041f250abc4a91e6f5615b0421c5cd56d7255ec71a8da04808c343a7748008388d4c20b9b7c15002926f1ab23b00053eb9c03e8c8b443f4ad76a67aacbee3dd957c493ada9eccd552397bf3049ade7f128a3e72de932fbd33728dddbb819a501d611214a083a46eeee74b71dfebd2ab31d9d887686bfedc5c6feec41f40e4cf0c9dac1af4e5f30f7940624027512e02f19a9968203f080d20a9c8d31682e59e8517e4a7016a9de6369caf2240c00144fe0f0e32d1a09fd7f432622193fc88882524558e2a8d0b0a5139a73040ac87cdb4af357bcad7dd3e6a527613800a2da0d812e8d092deccf94b20221ffd33ca528aa0502322e5d0dbae226c5505483c29a1ff439a5c2eea9099a39530215756d112749b8d28acefa3a862b348e1f543fedde7f851c55a0149c714b870ca452dd9b7f3d023577bd5e5c00b354ea4b0c372f5ed28cec8dccc5d210ef8033283ae50b174353fd61436bcc25e1bc9469ce4b039058e8d61f00ead8feda468afd15618016d587b0c66968c6fab7606c91cf8f863c25e9d8ab2acf21443789358489e90ea46a183c560e00b65200aea1cbd01a50dc218a50a886c495e6b2bcf29ecc7e7075b443c88cd823508451f51d4cf929499cf6911b87c8cea2ce8c07b6635b2187e8681e847a7e1c1b3db2f55ac5972da3f02732685cf371c53ca0cc45394ba744cde7a8aa60a79d701abe5b3491a03e07c4c5149cbfa8e4ebafdd7fa3b2cf1cf92af9f0e60bcb9ea55a7540334cef7ff813adce29c78e828b22354a6e144af1d48eef825e66f32ecdfd974e27e938f333cd741ddc7a02ba85c4454e0bab7ebff8df4a0be9ba7e1496e328b12cb6f50b9d81e60bc99d0a7725961c2f3f74b31068aa3df291c1290e9b2d89bd11652b50809ada92d8215e6262d5d330e1c472a4571593f7114228df9b1288f157790ce1c9090192ebff1638720b509a58985bf9ab3bf5bd2712f89e034dd15d6dd05f60b6122d070355a9f5c43d56bf27c5ad7fcf42f5cf2c3115866295cd55ec8b2762bd8d4d9d49ce42efb2348cba6b11377aec20345b0177649f8e14111a2a0cbe3274a4c011b69e931af1f4d40526c10b350108c66a4242852d4d76ea204356fd2df8e8f82913039a137b306525828258f49af9ba1966d9fd6907bcb3687839b115f249a7aa0500f17ec4f831c11f50b0d8fd614be4006b7408eec34d1c423e5eb964dc8d8601fb2cd7f705a01af427bc78fc12d4723d5ae0d043d74d1512fd92f34cf0e0e8f8718fe506c525f7947d5a18709981a1710871936ec6bdc4c077376304a451afd9933079f82126b17a0a68af052c4c02737e057b932ff5ca21e01ac1f6fc2daea40a5b3d669335d2dd83dee46a8f7846ab7a4a3b52f11b96916071f8091abc8b084f4e30bffb405bf34a9734476f4683d55f892560a7e967fb02a7d516c8089a298217370fc6651c29068da5aa851b9ca6e89526714a460c79da5d9fbb570110042d7c0fbc012d048cf6d317bfa4cdd63846c06ccfafb839d91ed699fd6baa116ce3710baae375992541542884464867ea45f88b309b6b353d69de23d4ed51b1b254f471b1754f945e6500564fdaae9b57122dd338e758ad5a66be8bc8f332da8717091d1d18a64ec926427992a35c5f29e0810fdc6e761cdacb1424979e61c1017d1770d9aeb27e605c1e0eb857d399b90054248d9de5dd425569c857d614901320b46fa85e3f02af61ed5b237483c00c788da3acfdd33b728554b49e43f3e35ae160b3bff54cfd44eaeafcda5d0fdd386ae3024b25f898e0280c86716ba6e7d49acca80bfc6d9ae2a6f7b2e1576863e3e10a1481a8f1a324475dfaaf74803da1005d164a9a054e740571a11a4f9cbb68874fed11b6276ced89d91fc1e42df7df2802931191e0138fe49f3c41299d861027186197b15142ff3907bc633c15e6b66bb07ab80bf6863fe1dfa90518b0ce0eff4829887a8dc0c00824bda431115ab3dec2215eb26bad6137065c2cc29a8335be62ee76ec51e2df4ced7010238eb779fb157801b85d86e737eb52663f86ad3d22cdaa19de634c9dac3a115274059d19ecc81e4288851c4c698da92a07ee6ff05af0a4771729290d62cc3c68c66a493eb9763d7ac464add0ca4b6c05cf737474a40975ebbdafbad40bdb5760b2b778cee9a33f88e139acfa116730724b4a3799eac29af292a1cbcbeee61167fdc57fea94f92a534a226fe30452f89aafac0554d5a40af1fc9fbb82b0652b1ea925d151d67d50c5d9fe7ecbf5ba7c8936135a4031adfed82c17137dea5f77e5c2f198e420b1fd8ac3ba3521210f04ef2cbc598c9f73a03c12e0f429a44223dcf903f610e0c919f2bf0f44fa50946800422ce400badd767ba9e2639821bf12aa575feb091c7b505dd80da65f2112440bda30f80d5267d90814a60f12ed8fa8d9c0d25ef069ebe32c36cae60d2681d80dc181ca2d3cd1245fe08b4ab55dbc4fa111fd820e48ac03c9da8f81d934a7506173e5aee824165d58c3a0d5611e8aa73474d5c22916a7f0b9e03152d669dafb209d51d05f7f953212c7e690feffdecad66a97a19f75abd2f32cd055ba1648ff5314197166819c330aa292315882a736dd068640c1aff10f571220e1d8335d0d729cd1dcef251a775551053f9a05a746cf2c4a998c04c4bd37d3561359ff752a65153404ae981e1666d514f2cc171a41774ff7eedd2db667be2b8dbd5d7a49c048c0d97201e6f6be118b46feaac62bc4be75146e02da7debe806c875d97d37c0a5dfa8b014d0ce1f77a918e0c380652d010254c047184d320eabf81f9d4de0061c787d0680ca390168f14aede3f2cc2e1446f2426142acd0e2be52632133d42fc9186157c01620a449aca7e295931ee037e9071781c15f795726e0e591f107a7f0e2cd3503b6cfbaa2374067649f191dbdc9f5d2aab04813101999b0ce54f2cd3b3106db9a43a82fbe3197a4c0b7abcf41db710be10b266882be4b927a12696c38995a57fa09499af533f128f4cdc370a303b98229bf5c1f60e84d500b9af33f732f9161d373889797a543676c9e9738b9a2053e36934878a46234569ccabb9ac51d0c972f16d32fb20f71cb5337318d97d1f3c145a8f31b334a0969c83620d805b5e8d886f875261b270df5592a3238c039cc6336ccbbab2d8582de7884549bc679f2e7501b4791fb35e61845d2b90f9c3773b0cbd146bc017c6e4d638e4e8fe3e13f9194900eb2018ce88806a35811d40f0281b418a4f6e20ce4edfe041a3c9cea7db10be6ea154c92132d697fa53ab04b304432d55c3b5aa49aa6642163b0d7813f2029579a56d2038022c2250b30ef8f82195613d9712344d25e752629835f7efef199bc49bc9bee40176d365055747149d53ee6d2c3f540d4aa45ee28bc104c1f63ce37464ebc4dbdc1a04c54f23937f43c231f8fa5747118a4f8fb78217819a157245ef942b161c3b430b7693e3b638852b8796230f74aeab38a9a0f88cb1d637241360335a58339666e202aef2b33d8443391ddc20965b195d5bde4dc4432ebb965e1a49bb9ffdd647c395a3db5fea4d245bcc5580efdb297c07306327652054a4e32732445a29e657e7955ce39effac409e69c412bdc604ed79110c7a1d4c247d7a896c361f630eb7102ff9bf36c004185263ab47cc6f2dfecd28ce0ac3b9bf47b32290e52125a515a417644a20a231063e05e3c2254b6a199e39c2462743d221fcb132752cb45b7d817a1fc940c362812c07883b80e6c42c6fc7f9c05138c2eed91666f30b61dad593b958cda767e8414d58cded5a8e7ac20680c0e732673113fbc900f746df0e3d8576083795ec9452a4d723b28c5050a261105a05d574eb969d4f03b712b91ed40b802a7af985ae28ef1bb8b46776151ba2e41c3f90c0d34f931a1a2db5d58e5d3f3ead0991256a7b6ac217b4fe1e2ac2f6f355f6a473d4b3bc6971188c71f20fc03fe675481a206c23fd0a9f9e37590579a8e23b721da080233c0da08131caa8e956b8b7c0ca657380883c97ca9443d557d0db7dcfbbea079c88a0aaf2e9fef3259db5e8807085eed4077abb05f954e8e83c9cd5b4f491fc6face21acc841d7ebf2f8163b75af76b0a0e79cba3b7bedcdfadd6295ffb377c6c65b64cbb245cb7a1c6bac59badb1fac1bf30fe19799c35529dfb84e9dc55a5e7f3df31119068c02c3ad063abe30eda0e73746ab2d264c4fecd3cd94e46b05ed9fb83c31b8fffa24c042a830a144b9314164460958e11ecb0f70bb4493fc27b8651f74877787cc55f5abb125172625ee16cd2d3880bd3239f9a9b469843461b1fbfc64fb7ac3719ddf94c0355c19498f208eda70fdb3ad0c8abc0fef27bf18a0065259be35861340b7577550194b5502a4370d632fe555cc1098cc500905b3e49bb3d267869ef508a52382f69d5f3277e05581bacb426c5eb5a63f1ec59ea1dd2510d02219158e98d9e1ea5b6cab047a39909204170cd8cd083a1d73e91517945ea003c3ae922156e4fac1f0a6b6b3e25e21d99c1e0ce606881765793044d63ac18698d7482e9d29aeff2a672e6886c507c356a4203d71e3b734ee60bd4197d947a02b18ef6309603ad2bae5f67a56b3edf59800ce5e59d08405256765e310ede2920f6fc21d85d78a8e76dfe87111582700b289562ce14e311743640a5cd63ad2d3eebda9fd2dba5a1e8fd6844c53dbfd6f1e52dbb1765ee61f73c27549002bbd7ddfdd8362156b56cb4509887aab5198fcf442ecb4380e591ded27ed42cf295f213dcdc4ef640354ded3b3548ccdb21a82ec464aa93b147c1f45118d99794cb79f87381390676e52b6207f9147e402f4b55a77bc4b863409d06d14028a8a6bec2cacf263bee494bd358ad1f1ae721eb7e4f1336564d640473f17aa5702d28e800c49ee61f3bd07c2dfb367a1935b6a28115fb3417186367606f05c16a83316bbb684ed01b4426a3f87f4708e1b983a9c569e952142eb194a7bee5bda5549755f321c1ea968c0bb40be7ec1c98571e814a85585e485253cad90166b808649dd11a798f734be11e3201df7ef0bb6c40e5aec2750a241a2c18a5c11646a8805b9744d804f5824a9b874143dfa4f6131e51a6955e23914085882228bba5275dc0aafe2d7a496bf74e86e36d0d0b7dfebecf08807caf37270e584f2131f4774e2eb2254c79b81b3a9de9b0a08f549df53fb77e43eddf5aaae9a817abc53cf08c6f9c9bf8bf27fcd9561a3c851333a218cbebea89e1077af8e2948d484837d2923362925c22794123e936de5df2793cf7160190bdd4b9b7d7716eeed16af4be4f4c660a357481080d70f74bd43e78a168f7daa3e887b693b42a62228f09fa2ba06c823b0fcf422a40eca3e39010b89c51d2df06558eb01b90ed29759a74d59a7def9247e822b686d42ebf6a40d2dd81ac06ca24b1592c2f9abb692ba20755d91b9224a7f1eeefe2fde0ed86972cca5bafd6615b3f8b8b189a99c2a86554411e41031ccc06de31670625fbe0b04ac0302a4332bf171b62390f79205725df6a14a7f4287b6b7dd9db9dbe9f2ec0cda855815e87337b987ac4726c7798a687ead64ab75d972ce0daff55c424f970f1b6ef7aa3eb02e123fcd4aa87ff6068382939b35a3dd642e04272b77ccb766e37680267f9ac91fa887653ac3093c0c31ceb3552851da5474f8bfcd6b63f992d00884f14f0b0d64517e941fdb13348c0db52645ca1d1b643a8bb24c98e32b793489ee5995cf489e81e54d280bd0b27f939f202919fbdb2ef0f28333ecde59e70c4b0111e40784eec32dbe4a86668d99180253831b1f5aa0fb577333931538e85fb412363c0e992c233d87196580446c6e3a0e9b4ca3af006295dba8181a7ca559b0d94b60528a96c4a1852e4111180bb7315a427b887cbbd5b397175c059e082e3aa3f45af30ef9da26d80dffdce66e1987a7d8fafd578bf83078daeec007d3256d14da1461d6bf746a9e83bb0d69a0f6bdede3bb1c4b99629f0054a81546f95f2c42cb91ace7c5f6094e110c0f634cf12fd89b47ca62463c6f0a30c1260f8026868828b552c481baafdfefc6b6ad6c0b98b685b037c3468e6197dfeddd71c31fbbf4033e451d821327d1310090dc9a13da0895750ada5107767866b95b4d5308cd1ba22300a62d55a48955c6cba6a09917dc4d2f29f5ab2e4a5e8b5a4849f03ee65480e43a1aa37792a17f468064da81dae738d1055b174c7572c27ad3318834c8a7ea41d91789f325321b818f997face9e54f86cd2fd3e8e810b9ef82495f52f002f39dfe79416767c7971ca78f9a5dfa22080b43c39a0caac2880450bfb676ab75c6a24afac0e36826e93aa64aea9935ab04230382ef26813dc68a112aa826867d319cda03725c5e9af791ae074da51fccd6f5c481e1d7cea928f32d62f435ebd73d76d86b35c1414587afeca427cd928b741ab4965a54f3b4f95ef449ebb4a91821396fd671ecf1ac1bfa2b13daea981c3118ed575c0f16bfd41bae96be70dbae25096ad3a41306d00e57b1136ab49308b3989365481e2f8a1c28aae369bf8278fe88ed26dd977085501d0cc146dbdef0c7da70e05c70c89e6ca7c45a55a2adf1e496ebd2c8e62b8187aa2366fcd5e016c5dd74b86a8a6ab0d96ef9ae822ff1df09562294580691d3466799d6ca6af376a274ccbdab583f97a53dfc1ed4e8aeb70638bfca8369a6e88b11255a1998591a2b473854ac02223683ef5d138384a5ffe31f551efd6b012bb6fd2f0abd841a2973a173ae256fdd28b70b033043c042f284ba651c230a13cb07c0fcd54ab4f3b7e31a1064b9ba4134a6ca4608edae5f0216b1f227f5c20d769d7a4c0e80a649a17767c5cec0dbc7e9b29121bc46da0213ef9c1d576c7d94c860eb0e5c0b8bd7f02b7b6d6d184a003d96d37f532e5917c0840fab6e3e076b22a9d144496a327f54d2f13971f9c3bc4deda09358132ca35b0f1cb0b4310481e0b9d7f6f303ef99984c92fd0074e0648b423efa6199d2d9d1374bf0c40671f9d11eeca99c03d976b50406c25b9098fa63f088871f3ba208d65b47d1607f0b56238d5760deedb6a2b8faf424709597db7a598821924a119694beb8ebed553d99d1db023ed27d5909578408d5f60b91b14194243736ca311b5f9069a5dad726c24db15aa9960829e3ff28174f69061b5091c7c9506792fc551270a185480b9b5e0b49104931e99fba22d59703ddebecc87a2ec176b2696de400486e2f800104560229ca9004cbf44bd7fa7cfb971ed745eead24a145e87a4881e7b66f23307048b1c35ce44950ac64496c652739354fa7be895d82d1a2e591062155a2e97cb19c7693db123628e042b51bbbaacd0b5c3c586186b10b5fb09d8b17a8862c5bc6bf04dcc952f8376589348916bc6ab53563e8ca24586f28254ad705d975e76761b2465c052c79fd10b81c81abc576e8e89c2955ce7aa67225a953400dcfa6b4f1d99e3b891685785a7dc1b86d1b0b21b721a90aae49c0c170231266110b3eb44813c1ce478a70c4c96c6e803bcd5658fd402b50b954bd20c6225ec9cd0789f697eb519518003e77444fa6a135788c33c3d5ca193b73283997cac63867514afd9a7e36f1188ee7f6b7b5cfbdc21bac2cda14d839bbc5cfa644343e17396483c220465f10d3a20661f617dd0f96edf9968ec0f5573b0e1fb64c0333af5e97169063d6418598d3e79918fe0d6e2b344de5742aa39fe22f786ff7ba4cfd14d0051065554c3286567c2fbb7c5fb6614b91077a9d043f9a8c930429271e1c3c6e75dee520d04efc2e18b5d36ac84895e33d85ddec5209e9971d6c1479b4ef21f840cb4b214f171c6bb0a9f5cfd6722865d327ac09dab35582a03ba8625a04848a49543c3a9d53790a6b942d3c0610499cb8eef606f80f077b599aaa638b25b557499f9eaf8b3f84cc6be39908f40fe108f626878ba25277816e7622757b0754ad0086e93a422221f795cbe2eb0ade33c454ddde8b4f6fe51f0c866271cbe9fb1af4d1c6490bdb7d04c78e1aada5f6aac296288c4fd20957e948d7d992d75883c1d21c3af091e98a86af81801967a6a29e969575fd442f3ea56e751727d5fa22c28a13de38f54554d4d75f4cfd753ec786950a0556f330265807a9822a6a0033e6f209308ab83f372dda24ec67b314d9e10c7a28bbdc3d6fb7117b7f6780496709a6571bd1918ec3ea7b563563e9489fed1592add8c6a3b3a1cd19d8b4f949092028e8a0cee123042d15cda6cf8928fe429fe6e50ec64dab6ecde6a5b59ed6192823c6b14997836268e868e646139fdcc85baa1fc6adea93b2d8a376b6397706bd91b22d4d74da4df53b937c770cc492fa44dd45ac74f3f431f532b80e60fea0dc77be8f63b37d2c806e88892786b962e023423bbf46bfb3f588f9b9d13bcb4708c3ca27dd98dce6ab2483876c2b2ed942982567c6017119bbda2a45860025832f732ca959bb92a1b1122fab647bf7736fdcd19aef771c4f623b234c25ee3b2295b5e14082a2537f5fbb896259e7234166fd916d3af6925ef06ec15195e7199fd310a2d4b8761ac63325825419e08ee11778723752acab59a9759b73055be692d6121ee600fe207c8c803381fe065f0d94a65eea8f454c4e21571db4835b67a63c2512ca9d78eb6be55fc0a9a64c48609a57476dbb6cf4003b7ca6708730d14b2eaf2dab69d40d920839ccd7300ed6deff6742314b26faa9a176d8391d9fc66ffbf896ffcf6333af5bb0eb0da2454a675efd415b1755aed8cc672c13243414e53d03fbbb4f68d14c8b642280728021abe8a34bc32a296faeae4831300276693c4b572eebc41326768ae655571ef70fb52341aaea33b52e6141d35ed3ea3c027cf4829566add92a529f4285e0f0d41922830b4ea8fa5cfa1027a86004d55d626f6b69309e1c4ad9603562152e356667a902239fc75a37e8a964e2a9b85b9149718807ff3cd2d42a32af01c6cc178dc80bd050740ca347f13ad6c435512f854191d5c94da4de425597f1339fbe898104a487341a2a2ec2298d4fd0c995d408ba56b67c25d81f57f731fd2c997a969c9639995a0cd12d6352eb6fc25059480466118af8c6a01d4275977b3bcf8f266318083383e193ac7c69b5c733fde412db20770efd2d61ad9da611fcc5b750b554fee0914784ccfd2d414a4b7546ece9273af5edf7c499aa11e458562a5a366a756734b8d95b3bae7edadaa78c8e3f16760800040e4005aaa04400e00f1507f499b343251661c355bc5dfbb1aec32300c11c4dcf5c266c240c21f3969e88d5b345b2ef8c16db39027fc4ad4bd10cf4946d26db32150f2aa6bfb6acbaad68bfee66a8cc95f79f81cbb2ef09d86e07b9e59bc7894290db74f7d250e350449c786c3692d30bf25615c8ad13128ac332d222e1cb556424f70deb220825eb5bb9b43887ada31e835794b852c8f6eff5239f2fa301bf0e2b440dd6e4656338078aca805cdbefe92dbb47947de3cffc028ba214784b86dc10f54c849a2300fee4a97af4e3154e87c130b0ef205cb7484a49fe788f29c569a6cab98c112eb0ab3364f9d4efc7ff1e2381a9144d31dfc1d4ee21cca69ef95efc490b76201df50707eba8c515584c48b070f8e8bbd1e5a241d353d7e7404f1b703cfa07c507d9425c27f63d193bda5521fb6c29414ad0099b58140e07ad94e35ec0eaaa4ab57bff9d57430b0ed18eab6029765862b53926b74b1202d3c1fb42a82e114618b9ec2384dee0c5701d02d08fe37494e52ac98b841b93764cb712932e2269b370345195b2fe1a8472b550ce9092a49f835b81f3f03c0536e5723b21442dda5f2c15abc53ff30b4acf09d377046060f2a7a4f755613b4fef62d64323f07ac9116c68c65925ae0b2f9fad7339bcbbee1a4d485bab2f1a00c746f9749a4ea347be3ecbfed92354c8fe5d92223ac4f347881f5525d0a675dbe9a9a0723ba33d8a80cc65cb4cda4e9392d32597f46f54995f0fb5abf65caf02e59065c63242b7ebac20089772cf5f6775ab67c565329d7fbf7cc29fbeff37825432c2cb722a360f40b3e4173ed936429e327db4558ed9f7987b445d84c8c126f4ebe9f7ccddb0f97776709408b89a5e8d46f79a0ede2761ea19bad432e013428298a3bf768301fec9a67e62b628d92121b33923fc7ff1327751f47beecce2b37554bd8d0dc151a67c6c865c1c659cf8ad2a4e854dd0877cd58f6bb5712b1895f1f71e19e03adf3489115ac776272fa3964871573994d2d268287f3d8bfe408b6d97308b95a19672b87c67e58992c0a6cdf390b2ccd5272003fd87ab66592bfd75377a03624a1b0435b14a02969a4dcbd1585d06532fe23dad0e504211a5948b75fe0f8bdc10e1385971c40bdd450c82917ce0c042bd5e8413d233e1e3989f0f8dcd8cb7a1ffa2f6db0976efeb9760d7625e1daef685f4eb2d89e9c50e07c33ba50af50833c8a66c282ca0a291dfe539f050a62d981e9d63900375416e35bae4803937ac851a979400ab04f20b6c6b2982d5771757df59421b4eea69e052e461f767157920aa8ad167a996fa78f96c1be5acd2a77d41dd6e2be32929fb8c13bfa48bc6cc95029857a628bcae691580d119591443224535ce58b11b035346c1d5d8974f9afd26b45d206c0297f1bed225d141786eff326f1907ab4838fa2ce8cf2fdc22240d62d9fcf0be72ea3ad1cb73f58ff599d0d37b97a1b3c887577b6383100a2ce37da58b443ad0ca503499e02dee9e64e8998b2d9c90952cecef1ee68990247c384dc8d01564c998deda6fd9e1a4be855e86667f459f3c3886525ad4a90af2a9e56dee92de6a6856bc8babc22e408c8902799a4ab6a31f44b1155bfbf7a4fd26e7ef1a210fe457760fe75a2ae0231920928ba47efbf807f244b02aa7e1fc181b4aeb0089d25c380072c15e835aefc1d1746720d43aed4b5128cb764f506f8531cb50a33e105a510fbe2f41dc12ff5e7335957ed36f6c692d866eb0042f4859558757bcc97934bd52f75b40582f4ad850208e824113b12aaa2f25e810d01c168f590af6f0a5f53fbb4ae253d2d7afce2d4b70518c3a8df4fbd0241176837ed7f9e7b57ca2689875baebaba7a81e588524408b3ad58bf038e1471febaf45cd33a9264245a5eb9b647d8762c2a700510da3850b0448db40de2c211c89f8c06b64ab82dd66bd471d40b9687672cba17aa2e0f84ac0cd96572d6c2aa9be6cd4c0a7ba8530f30a8a1639f713781530cd8baeeb974c70e7256a5e19b31f0e5270ed5fd551913550613f6c8456f3892922a60b2c35032a30d66f5930165aa5037d958bad7613c6141c0347cbcf13a2ae9d53eddff1b4921bea3249ba41918cb938996f64f8b1e320defc7c7e1febf81e26c6eb0f33b1d4b0ac6e504789f78cf18deea5051f1f6a9092ca46f6de64cbbda54c29a5b5062907f50648dbd7d96d5f0f6793d6c2557e83f1be7f7b2efbcf7d58409b88fb7ac8c4030af3610fc1782aeaab6ee1b42fc6f46bfa587be3957fe39fa5e91df04f1bcb982f2e2cddb3f646f59a969ab2f5bc7bcff6f5e8aafa5c48e5a28cf4f1abc1feee099d1ff2cb0704ff552a4a597bd3dcc4d2fceccdf60d842ae30b0d50b52ffd4e7fa82f9c34a4aaaafd83557bee63fde6b19646fb62b4e7efe13534400d1789b534ec44a8d5d07b42cd009d648018946a194cd87666ce4612c14fec74620f989aa15847f3cca041031ab298555936332ca19f2580a0821b585125c75f060aa80c97dd3802e50f456054311110d57e1c8f431a2974a31d5f358a75701d4ab2ed4c11f1f9670a1d954fc8ae1ae3170e69a4eadf1474a9af96dc7851166333010f497a7288146112f800054f4e7c2245fc891459b5408828e4c42fd2a5000805396ef32487489125929213bf26fd455eb4c8f1af09ff7e91e6076c1b71909f0307bc627f43c6b3f6173bf05fd728fe63efdb433829c88832a2cca83dd92e3d935266ef9ef4ac17734fbabb673273bfc1a5c4fcf3ef27d9cc24866558e69e3d69d03329a709fad52f492489b4e0a0c84131c60954e7d1049a4013c8db316f0692076620b5b0040d690d87b4506759966531ae1817105c98abbad11240090db9daedc2a44b4a77b9cbc8594ace64d6e9c46c6eefae6c99652f9755f7cbb26c6659f6383d33ecd7e3cf8432ac6ec4a4e024878883f8d348d57f6223618dd448fdf29fea44eed32ffff19f8dfbaaec23645f42a4902edaddb1f640e7c88123070a5e9ed8dd23dbcecc8fc9322cc618635e31c61863c464fc187fe712ce313a629b93a3363cba66c610aa67b89ba30e1b2931a7e0c0c13a24588a13473ff7cdf9a6676179adc3c13a58e4e230f5943a196ae9719c0ba34d0e1c93c53a16470e29774a0fcd91a3722773c8219a4012aa5f770a212a533801545975a768c24afda9560c655ce439e74b3a5f0bb9ce974fbd9303b63abfe6fa35f98bd3dbe4b876a1f62c2f3dae74fa187fd26fc6f9b2f3c14c510dfaabf6436a7aa14a1ceffab749a536529d9f753adc05dfe8d7bc207e711077c13ab6ce9f9a79fb0365247feef8ddd418115d9d54e3cf460f3d97a6bf9becdada084ff537c2038f5e8c7c1c70aabf9118f9c5e0420dfe4ee369d47e1a0b88a6da8f0335d57e538d3abbf5ccccfe5b1be12bb5bdb0880eb55bc7bd0d74cd81eb5ea95b717c63fcb7d6b0ef5f0c2ed47e1c76a8ee1703830bb5df85da5fbc52b7c8c5591483bd641dad43895bd6c15ce4d451f7a5a6356ad4f9dd50a3f6a0f5064eaaf3067e75de264cb234407ea9e469a5ae73805c400d7b763e1650e777c302eadc9be5d81e4d1be8ca01ac4ef9c5af312c367e2a5edcd340444654aa08ea9c26aaaa2aa4d47e19d0862a0ea5461097c6555ff98bbebdbb2d05125c84d9adfd6e5e9a1eddc5267999635c949f67abe86d7777ac65c7eef6ee96e284139397398a8d852b1c8bed29ca85dd9dc7d8766765e6ee66ee3e62b9f9c5aac17efd9391338b52b1a0523502a28aa7f05203ea88be01ebb0cc2c3414f217a5c9b470bbea5f17c79e33971ae2a3ead6ad61fc62604055ec5195db6ef9e7636b44a2b5d4c854c53b90ff2d02c46d810db6e64d5f052008cadf2d194cb6aa1836808a49a0c6de1556aa180726f604a05ed3b22bcc838932c68e31c6c85b32c98f6769ab56b6903cbb4658a041e3094e64dc76a2542362bd55e8003486abca0f95eee1e6719ebd7123a39e410da70e554c9ea5e9971e10959f9e88b1509bc76b32293d537ca8d4eeac4aed6c0ca31a4a9e1e2f557e9911112e82d048e5a5914fa36b603f6cd84e214514f760aaaaa6a28cfa52330fdb5534d58843ede91eaa6e18e79e4bdd32cebd53dd26e75e0bad5b89738fa56e9ca96e1ce75e57b7cec4b9b7d58d8573af54b7162ed3ead6b29d38f732ac6e28ce3d59b717cebd58371929d516336386c93fb934f123086a232086a0f68c988e467c4b648b8121db6f379659b7e5eeac1a89dc816dbb156304000530b92c8b312301a67a1778196cbb37fd52438cee9cc4c60bc6d8fe72bb4df2dbe86d443291c844702936f94fe8607bc03b6463c362ad0f2ab6831a87bc36b1ed4c36ebd7dbac04213629c3f5aa9d852894c15eb5371b6dbb37546b5998ba600b15a8d1e3292766811a33d3fc7869b0ae5811e998acedd5c06a66cd3b1dfadee9b070a4a88deb4290aec75facd92e8879c5be585b1e8380111504e920060aa068428423e4645ecb177298b735d790488d6179fab17ca8215c35d118025d7062a58f1b6b29931d0cb1ce2f8c35235231ecb18ee76cfe0c06dbd240d707422055ec6362f0e6b86b00f61a4f2fe42b755ea95ae600ec596ae64d166e2249a70aab9ab1a75aaafb7de3dff4dfbf8f715950ebedaa59eddfffd27457ff61d0c20b680b2fa0fcaeda1fcaeba191eade132337e602176473069105d11263ee7418f4c2670b9672370a8542c5e9cd8bcdcf9d8b744765f6bc79cac93133f7c79c7136a27b748961980dcf21f3fb9aac3859323b434580a4ab5cd15582ba8d784e4d2b95b66d9779dbdd65664dd36280e8d6dddd1d876ac40065df3534c2dc4ca7e238aeeb3a1b269085858552dad272da5545c1cccccc5dd799be72ccdc73ea98220b6d51a9a2601365666e693971a7938b8b0b9d28144b47468a53454197994f27171717e6dd17666695aad3f190687f21e5eeeeeeeeeeeeeeeeeeeeeeee8f99b3ec9bbe72715145415f5e64a4524582d8a809ac8a8251a8f9425f50d29d7993c1c9e874646ca9948ae3182f687fccac52a960603a9d193366c4c4c4c8c8c8b0c0b1c0c2b63468d4a851839959d5f56066d40c957467f6f6f6f6e62d26468693e974a87b8c3246140b5e12687f214783468d1aff1ec72cc3020daec67352782bb43fef6b814b434b88dff103eddf5ca4331c771e18d4bf30522e0aed6fe6e149b57f4e19676c58a0af5a0aa1b60c7ca3378c33aadcc5ce22a6c46b9a49cbc03a9a057ba3ff493b69172c4d7fd835dc22ffdad582122ce37850db05d3ae6ed7aeda055bf3e309550ea80d5a890acafaa3052594334e15050dc159358f4e24df2d51f92a0048402cc6bd99459d8e1b551ca251fcdab53571ad27692a400d01841abe0b0eb4d0012a0b2aeb4aa185901641438d6198c4a4aa772693999c4fc9e248185f7ce1544551aaf66a34c2ab4e1e2c70168a6312c3304c0a2c5e1593ab6ab0478a1045c9ba524831a286f4977012c347082940b838a12f75a5c8a24a104d8a210b2429b2f89182083ec8a288270348c2891fb872a2c7297922c70528b208ca895e4c0f72b6e6a2d78a62a5b801114439455894a02ab300837582185408ca298275e16d41ae1ce911712b496c90945384a506440e608411fce414c18ee05dc020477a445a8b2326ace414613922671b015818d5708620780594da6fc3264a92da3f33a31451fb3970334c4ef76f2e0d7f15400c01e5446fbf4092e3416cbbbbbbbbbb46f844196394438ec304951f820df02b5778417ed0796fc47618c0ed16dbe8567f32d94ad99ae1f0b081880cac175e4819167b72cccc4fa63ad141a0926e612c560e214376f4cf16d9acd11e61b27fba154e1750925622df3f2848486888d5acfe384a01aaf029a25bfccd641f2be9964c50fc62db9824625b30915cf69ed74de37496687d44e5031ab6cf775bc9d443cf62757372946e9f7b7f21585b00a2db3caaa72a7f07f21a1c39fe1ee42ee443ee446ed4ad95e2c84af5f728dd3a619f6201c53e6c1f77f9ca7f4e4a55aa0759c7e4c9da5d47a8fc42cd35bf7b9aa741f7817a51b7b0f7f718b85c49b7e2113df0e18aeaef407b13bfa50506c6aba1bbb8ee835f4cf69b3313933dd7ecfb1ebc148488993fe6c580c1807d31b3725018a2861e84727a64598789a7eef7dedc345b591aff8d89bc2612f9cabf25ffe8c8c888886868e83dfcf06d9c80862fbf08a54157f1c05d2e55dc1091a7330209092968bb62343434448420b8087717b53a688eac5d35ab52c76a54f77fe7ffca5f87fe81dfc76f614820628b306a0f21043f0ac6430d41095c710431a4f0021d9eb0018b6505f82c56945045c48b872a3108630a3c47c076a8fdb409a130784933e15bfc37c1232042153504a5137e650c122481e14c20810c181411a98aa228d5764055f71f5cea16f548e118639312c4b430b1041260d058b7688914b868a96ed11224c096e82188d4ce38bd6842852b5016303ef935d96204282ac50a1e9a4041a9a0b46e51131cd03068aa6e519324a068520294942b271eca8971a2826e484130c9a288899110a722e86907340ad445095a040a53b78849095ca0d059b7884910a7218aaa5ba4441496f0851529585019758b94802288bed42d5282064aa05ddd2225a8aa488921b222257ea85bdd222552a005618300a507202215464544aaa2284a8340c5944c88ad080815a8ea16f534a19eea16010104152e84117530120410485c56e8c0053bb0c0098c270c1c5850610a57c8e0892190d0c4d1912200c51bf088c1846d0b221fa41c77d2440644394e9690c349497216014173917686fc28c981e8880d3d3e495ef8d1ad1094214af5b937d8af0f6eeae2a8fb03d81a70a5cd16af4e70fb42ce769a7f6797a67f89a64d0fca9ecc603118d6d32d2440d5a1748d0f49c1850f122ba1d51928f2702154430e4ae2e2a886fca4fa6351ee744b5ea95e05fb257451778d50f721b0352c0fd81b8de5dbf195bf69ceeef3a90a02dd1ed4f504d45d03f8dcd5f44045420abd0bd438e79c99f6cd7f61ce1e22fed8cf3d7352ba2163df2f0d7b1790697049693666246bcd67db993006695c8360806abbeba7a7a7a787b537daf3647e013508feab5498a669da6b1be74dd40ed989da3d27a5fceab6e7dac7a77dda47e3b40ff9a56d40c07ec76b60bedf86cfa28931ffbe6f03da4f96d76c6fb3a357363fa0fd218b3dc667c97696ec8f95433a2056e740575f37658fd391c56a50fe6fdef495ccd1a0fced9648f9d393f2713a004ea88d0dce4e0e3ce4ef0eb95498c8f7c83cd808640f453d2c38a20739c5951791ccde6c9592d99dd99dddb9c80724f80e2f222a76f0a2093c7bce28258665d99c1a7bfba5fd5269db38aedb5dd3e4eddd35e9b0743e629db4a57b4869686b399ddc770818b2f7f2224306cb40a15e64743a5bea25954aa15c4ea9540b4da5522c2953974aa5301905b0a5e005dbb651e8fe76745358436da3069767db9970c66fccdcb1b12b68482b95284c15312ce3743a1f319b736a9a562a95b60d5bba343adc6f9c8f58b94e87e5b7aed3e97e3399d6d4e9d0df58b869fa8d72a56efed6b2bd1ef724b16c6aa5d3eeee6edc9958680b4cddb4ba71dd4a1ed78df3b86e9be4388febd68d722a2250feada5bb61e3c1eb4acd619feb763128612529e2914c4c8e21abd47d49a53120af99f1fb12698988b691847cc87fbc46f59bfa2a781175df89d8565b41a2e219a3a9748df3f8ca676fb4df69ea1ce84813197f8d50d288e5b7f4266f65bcb0705c894371a78e4a2b720a13f93a7d385b3ea426d6242af1f84ad334a4a30d664b9c7b8b691be71e6b1e637d4a72fad1a697ba754ad2328a3cead6494983fd35ea01ac40f21a2ea93667a5a23c9694f285c54ab3acd39999a675a75cb2aa3cce2835e3897c1a2ce2874bc205c17f5898d0175f4de955bf7c65732bcd6eefa3ed9b41d9d44ed4e4a1a8a092aa5819c3a77f7c2514e4527262325db8166e7aa8176a0a8a0a2a0955a557fd45fc9c7e4e4127a0d3cf29c9e987ab8b42725169258f2b578e6bb7795b5d38f7ba1924bb7b3a61613c588f7c49a424d56b6998043911e2e28994dae00c2b49af2954663665aa05b5b5ad14fd33753adc9b3a1faa28133b7dc0080b82021624b3c4e5b7e65e5e3a9deca3b731aa2397122089c5731faa5c3ba241c3f33a9dd2eeff12e83e8eaf271fdbbecde35c0d3637868d731c5843ed48d3269276a41dcd17932027427e6472b1f349affa5fbe925e0df6f74a29e9ff4e47fbef7cc4aa8a4243f9f2a13ac2c92ce5c24af3f4b57cdf1776952a1ff7953e0e68f654964e24d0d2f06b4192898c815422d5821900e0dc7381f19a40607366683c2ca8f1b4f69372f5f8aaa79329349fcca11527a3ce6f0635d8134af6a16a6e1f3fac475ac1782492275f1a92f6eaf11a49a557495ea325f94ae3e9968685c6c3b634290bf657d17a6a6b47d4e3da05c0b4220047804e47be07868d0270d3e35c4a98785c5083eda457fd5154158afb7cd24bc9d38e8cbca6c74bcd70fc007bed48320d57c22a8bc74bf3324ad7a80ac0b91753b71b9c7b336ac95be2f2d25b3263c6278dda05ea2b16e71e4c95de12978fdf3400e75eaa6e598671a54ee794a4c1fe80d143816ad89f5c0df649eb743c202bddd2302f87e9d5e9c8292c5c0e1d68d7f99855fbb4a3a5e9cfc1030d4f3f3f5ed3d26265f2d01ed5c967fbba4af6f9917ac4d4f590b1030d4f3fd817ce199e14f215d7b89c5e642480530d81aaa25019ec4bb9e46b477bc3c15449b97abc54ec8349e25e724ad7b860fd2e29405382a8085519d288a66846934aca25a9683f5ec331e19c682eee89f6c341d182b822ed27ca506d2944dc14cd489be2d28e1a9cc101cd4c9312d3e9649f7694cd29b992b61d803379ac1a0295e9b0eff443a1c8b4a36e695298744dca957239a14f5450b822222e4aed9411272575c44dd1a6d4fe2de5f21a14955ef5a3aa00a1c6a0478490a45c45a4885e92d4ee1725b5fba4e4f4e3e29d92d0c03e14121898b6a5aa8b774a52a3d3d1bed30f57057b896d1fc53c2df31220bd25311f63647c7f8c979ae1cd97375d0db6922a365458f2a572529bc97c184f26492bbeea57795ccae35ebe6af9e28c96a67f7adc0f97a43917a7a40adbda6d2bdde2aa58b0bfdf799cc7795c556578da91affa5f3ceda521f9aaffbb1eaaca955c9e028143aa25ae0a07867644fd6275683f7ca37f6fb4ef4f29e91a97ef4fb95c3c4d4aaffa5b3892f18243e2a8746bfb7e2e6906cdd7de38e91a4e8a942953b4a350beb4a350beb4a350beb4a357edafd1f578a9d1f595a2abf26f4f4bda4f8b4be5ff013b9df960e72356ed03d0f978a9dbc7e1f8010d39a423fe9043aafd1bd8c1d0b16af24bde4fe5f0f4533d2fe5621dbb377aab9cd2c1b9a7ede0dc9b9b02302f36b8373294c574eab8ada4cd98192663016e2cc09b5b644cbb34fca53ac355b785229a9196de80128bcdc73e22e09439d3db1ca63ba57603768a3c82944d4ba2cccea876246cce7a4d36c3fcd247b32f7d325f500cfbcd9b5ff2b28f5e581a9a61fbf911d9bebb194a9f7d44be3b086c8eca57fe31a734a43494b3d872ced6cb8add4298af7999f6d94744a54da0f4f323529abe72da5ff23647f33647cae77580fcbcb909dbd63135025ef72eb8dfb9ec53fdfd6d7877778360b75836d8c78a159fbaefed9f799c118e3b28c4cc06b956a1ca641f3666562a65d9c65ffae2a66ddbc6a59fa5df7e2b6ddadc782bb13699b3e8ee49f0145514a2a5811285c6fd26e5787797774ed74ad7d206b9c94d1a7d72541ec9a1068d429534720f6551946e85544ae956288b6451b7d6f59248dbcf708a07b48500f9b146cccc3c51a4cb9f5bc39f8ad6904e943fe5f5969510534c501bd5b570ef25541b7b3fd4b61f8b0914dc82f2ef744f813b61c2ea9ff99918dfc683144608cabf7be38fead6ca8f5b4fb972b033fe97bdc1af0a7764d4e885d55b7a30357a18a858163fa25eb02fac0135a4364790e744a12236c49c4ef8b66db387f60cd9f77bc65f4f7fc83cfdd8f33bc6cc53f9f9f9f999c75df3ee0682f3a3c12348768424c9f0b45a61144287f0a8a73258184938383b7264b1356b6476c53fc3d9a8ccfd82d780be923ffd0b553c1afc81ca6f0ea75bed80af210d34094a98436d106401a121870d222936502246c4932bbc98d881358661ad8abb62907330eb9fa592a1b307576441a44550e829a21205231b1f39c6d831c618658c3146ee6d87211c1e2fc810e72cea81a2072936f95b8c33f42ac9c6c8c686394a299923330c0f462c4b8c3737b75286de1dec779f86067798336615efb490ee15b2d3bbb33f6ce20b391ad2bd42768e6818d240ba45dbdb8b2c67724e37cd389fd86e059438e49ec52594e03f66e041126468a900d9a4b5724462ad90bef0c3a388eb0fafc1414285d8f0e307c6e367698468b846fc535bbc6c2323111bc98cadcd0e9bf9fe3b6ca8541435d70ab49f5d563889821b25d990838b099117120ff8fc60212b64211aa8c44eeb627cc69ef7469431e29001092223f64082b8cc62361fa7810009e2cd204b34df231eac1c4358635730334b8eccdc3f8880044142348fc098689f4e7da657fe362cd51428ab5291e9964d4f8e1d51c8d0509006e90f28702285cd9edfb3dfa102cdf86968d0f9736ca77b47080d42765cdbf12c46410856aac418b128638ccdd18806a39d2146b1a84707db143220b69df1191b9d6347dd95e999d6667809a1c187930c19638779b827c3e4048abcae52c55ef94e691d357e02f6c60e1e933f1cf8739835014b13ffa647edf7a9809001b5df63f0cafc8509a83e6abf0bf1176abf4a45296bdedc55fc92b74176f8a31e88fc41bac59f3710ad3f195e20e261c3fac0061d0a54c8cb3d48db81fc4d4658236a7a4da986e33c54afe4cba7316835fe16e7cbdef057853bb583c16bc681ae13a6c2106bd69a865a1afff085aba1c6b82baef640c1406b4824beec96420fbf94eeeece557abbbb7b1047dcde3416314c6232722c35dca1fd6e7534606ff8c74f8655103404b9bde91d3ad4cb13d4866ef9f70be956d7f8de42220d3146efb1cd68faee77ba25a4c1b8d360dc69303e0dfd020515e23bdddace371a21ea41f64625049d5e57f76ee02bfed30bb2343374ab9f7a110d52d6d200a9b1028ac3e3856e953e3e4bd6bdc2d108511a211aeb6accdbf3fbd89edf4825f295fb92c7ee38f886f6ed711efd62bc6ede36f8cdd0609c3dbace2f882a899abefb991ca5f78fa5ee2bbdd7e08f6a307ad43eecde3ece49690bd99efb6df3541e457d8dce3de7d1294ae5a5cf068c1e63906e457777ff21d650649f0e054fae80d453d4c3048924a0cc259048e28314824e498a30a380841090b80071c41149f0988e8c684136059398c9aa457e2ccaa8699f69f363d4a216b538638c32fecce2cfd0ad6ce587d360b429a23fba35438ccf030735046b8c2f5f4974aba38bca0fd1941f7e20628942fbe5ee6a4621f9b204b109c9051055663edeb33747427e24680ce9d353b221530f4a50654744951f4a2e3a9fa5918f79426300fdb0696869e4c72091b150331fafe1a6f44a3e959f2a2e6e0ca02abb234155764884aa2cf90c55f9cdbd1a944f83082a3f2cf9b42c0d9f2abfcc40ed9758a8814aabfc2dc6c8340994dc2c3ed914323eb40e57a86264a31b9b734e1658802c68e3f0701f865055604482969147d6bddddddd94d2a6ddb1bdbbb1ef054fb2e19543337f405c0734e4923c9043b7c245226264f4c35705947982e82c82babbbbbbbbbbbb637b77472050a0f80b3f24a9a1ca08f945ece2f5b2b1a33f768c317ee923c738e78c33462cca18637f38fcb1c006fde3122d51f7b7ffb00912238d31fee0450de98cd90e5c042849188f2c46c6be92174ba552292bcdac548a338bdf0b2c8f8b6818d24595e722d6ce90219c23453f2c51b91891a03b68820fcbcecc9aad09f6334a25194adc6c8900129434b8d8cb1d0d4aec931810f67e605f7a4ccad2ae344dca9f5262ff43fe9801fb701a943645345ca31f0b45ca8552e5f328ea21a2ca5f425f4ff054b92ad59c35dc079ef7a8b44df844ad648a46000000006315000020100a088422a1682c8c7449451f14800e73884276583a9647931cc9711c848c210611430c21041822333344346a01a564d300cea0c9ac1a2203948275aa1d91c069ce227dc9b8cf622de73110dac35c5c5cf6ab97188ad269b41d59fac43d0a6921abb0574d5491f74264ff4f4d1f41379c5ffce0299dd8c009874bd37be50477288c8a9c320d28f6c675e6dba70c040ecdae9c2bf624d4ec16e35c78dde8f728eaf4db2c39b642f668b23d06c796171c43644676207ced8847d2599a8a62a4ec28e50e4d0252e095ed8b786d0b918896ec53b300e0ccb3b2f95cc8990042322293f49b1704568006afc09840eb2ec68efd40015035d05289fbd5cc89c43ec2459d85800c3d27a03d409bb6ff400601c401fa6f7d6809b1204399d1968149664a4f3097a11f6919b1b145078fc6a7e6181cdbbd2efbf00db2848c223180659af3480e17099f05ecf823f63247cb08ec6226bbe892b42d60876f46625875412ea2c643fb98097cb54b0e66ba781189e1658d4160bf64c6f3c990200d357fbf8f6a457106b36c1e9794c3c62915201bfd0dac603c9d6829b03a892eca892d3909fa5d5b2a6fb65f834efe8abdd4a90c3344cfea1c74ceb3e9f7358868a5c398f95598763a15f773177f2f5c8eedeb5eb1620f1cba264dcbb932d633117d8923d53731ae9ccc00cb82bd4a466e3518238fddf60a514aa63ffd82f57b7e45ab76b5ff5c6937e712c4e79461896703df60fc90abe088d7db1e1cabbceaef18c508fdb21cd460c8d0250f9e2b71195eafd761676fe564df88a1717345dcb34a534b5a63417dba9a00b9394a3771503ce1ca3c156762e6b27b31c8d39e402bac0ae1af3ceb09589c5d77494d3528982b050fc8d7e9b6b11a2584a15d28c158e6cd12b0c3cfda0d57b72eb6290845a01de0b6c242b576c2fb80eb767a87a185c3fef73f9718cbb809089e387b0800654a4cf0b0b867be9518c41a46410153de74703e4de6226a8a1246c4f3352767fc9147dfc91745ff24b8209538657b5762e8a12f876150f94f4f432bf777e87e3d22f1204616afc32d5e7a576b1961d64a132f03b7899ad8f7795a799711513eb09398f9710806e19384984533e73e763fa6babe09c371fb6e4d4f69c67958078c129ec6364a80cc1e7c99aa76094d2b33eabd05d027ab064c019273622564a71a3bc8db4cbd93883ebd0147700ad700df13a4b6480391bd1bbbc616b75226d2e2d8e889989c1b087321349e2bcec7409432fd4d5fe1ce324b25b0fc2bcb08699412a92710d381f8f71340a115b11edf1b052fd962afac38f6b5cbadc438d38866289065c3a117721dbb33964f1be7a1a728d68330cd4aefc1de374f17d72a7fc3c73648bb6e1855a2de08f43bdff0cdd2c9635d24343d70a42857f5f4552d03a6f157b2f674328ce4adbd38fb67839225167d478fd1ea9dee1966ea5a924bbad31979833e0170b38e436743ad560202bc6527384df10a3453260a8bc5b773588768f238a156aee152a000988c88f5c5603ae9679615d8305d6b88eef66d1128b1bf5cd11bd6e1de8f3ec59fb839ac431947f6330b17344ff48294b2665b03031f6d949cf6b00ead92416997393774bb5e496a1c08a2d18b73091d22e4139ad51fbc006a8499a4befab5d0857b9f3f10825dcbb2b5911366403ac45694bced2a7fca4865eddb9fcee07d34351028a7b7dcdb8fb699d8a700dd64f25cb6e601a7e30f2afbf76fe581726a5512ded92203180a9f6be9e67b3555ae84f5e5eb828420c87e3e8344205a00dc75360ed32ff01429752329c93fcc3e361c810af2d00149679e648f6ea66ad1c246f63cb75f929e64782eeb53d326580c1208af10d6d5d0ae85ac6e864c4cedc48315be13d71153073004226851b0463ec769754216cc8b2f5889641d4f5f9710cd2bc079b2fa3464f40a7c5f160cb53b6f22d1df294b1d756a81707afd4c564ddc3d80372a879b76a0db4c8cdd5fe0b51d31e412ea84bca4e5282682dd455197534356f78ca4c47b75f108e59489f16afaea6206bd7a0e2acb4eb9ac9c73a3fa4338fa7ea12783283d4b90f9888897c8c474fb12f6e8f01a0b1e2d4a16a476bc6ae3a342b6ddc6e0af7342f898129d27faea1f3af2fc9d932912f6f4fc483456722c3cb6bad492c07b079de5dbe31a200fde8e6e600c2ce660fa4fe5a08ba10000026ad5bba916873674000221c308be9f53721ea05590cc406281602df5876f00edf3ca1265df2aca81f60de3c83cc4808761a17cacb91134134d1097fb12ead24420e276d623409b630e4043a763ec88c9e23c0ca0041604977cf56227164bf69a4ac62cc71d7ba35e02767929761b3a0faa54eb5813f654332781e20f1c20155b855cb390d7304919a6c981a2242847cd0b050aed31cc4adebdd56f02188284071ed7be2a19c6b1d53a230c8ca79e7438e0a749fdd80dc7b896fed30c629ed670cf33cabbee0842042cd7976290c116a3b66cdd6b4bce7aa6fd73baef7afdde2df4761bdefb4fb7abb4b3d9769bf7a545fd58f625f32d66bfdd976c99cdb588b7908ebd79936cbad4cf71f731034cd9036ef03df3f41c15d60363c2152d5280d4674ac66fd2cd9964c92f6a2006ecf6e5bd0445baa1dcf538070897a471e045c55518328bfb988de426167e93435aba81dae739ffd335cc83a43041d78cea65a29f226b4b78f0e83dba7f15cb9d6809fd068b76b756545ee2a17e4683a80728137e98dc56855c78db6abe4c30d96459ac188558c22f1c8558f4c78a748744d10f6af4d565ab29c9024f3a68342b36abcda717813abd15b77374532abdb1402ed3874ae47372d5419115802cfa19e3bf538b627dda8709b330fe865f1af85b4bae2ea4d9bddfdcf2d8a8a567eff26156f3d4bbf4c75a6cf11390977a2d5a302c67bd18e6957bf6ea675b6a69d2794594c547d2ce855c9744739882d9e0fbe332eaaf1ea581369bc22dde627034319a8006fa337236dea12fbe66d4d5271beff600edc7ca786b63696ca047fcd124fad5c40304f66b9e54f1c7adce1ad33d5a0cb61f422a4fb2e2bf8609d16b6257759e5a9d3110a9dff99108bf2f889efebe1e72cb341c430c292880a1310d1872cb866338830a2911537c5f406c4cfa1ce82c882fc21e0f83ae5506239dbf8bffcc30c56b6e04830afcd6b24d7468cd6d683a8e9356471e8da3a0ba9be2eb0a43d68e1adbf4d2dd96244ecf21fa3c183967acbb8becd0c4ab7956406361878cf547dc807106ee19556041f474b25c0b781674b02f1a1400ac75474da0f026fcacc6c7be804938bd45ad7b157bcdc22e1b753101b5e43aeada54e7dace1ff44b8478f0e904e15327c38f883dbeff19b7c5f59b28a1397f904b5d95af7bd847d259bb75f012d88e14ca7b0f029af554ae78dd3a9857b5b9c96bee01a48c357acf09ca582d74e69c66fcf175ebcc2420a7bd6fc71b45e870a8962f6d3f204f5ba72c771769d73ac31bca7e04e6f08b968041cf9ffc61cdd2a38b606a463e83140f177380d6fa9bef68f325636a705a4435ae01d5787f53dd8edc7563c5c785b7d50b458185e60c14920bc05a3a0a577595aa9cdb555943ab2668363835eccdc88573e2dc1aa7182a25d5440ad306489c6cef378daa2bee676e9d84d40f779144ee2260241610b34e5177d6b81b31a4ed2ec61022181e95342342e590e6ffe14269ff72e39218e3cf8a323670ae62069704b38e9f160014fcc1dc8e389a989d80845e1b7c266da9166dfb5ba67c7eb84903ca894204ea3c380fc97c83b5eefa0a8e1c29991163b6f3c4a182da02d0a28b4eca9ff508161689488895cd6b502b5a4adb2926aa8b20f55f1f14a1eed308129ff2678c3b656daa0c7e5971dd80e009760bd6e527f886f914a6cdb04245e3f268b8f74d36ba8805273a67d01e7c4560a83b6d41471d50abc0134c8bf1bdc28f04fd81b5b3483d8574ca04028a927dba0f66864a0542b0c348259bf9b0c2fc511a5d7054385bba269970626513929016b378daf291404ccb9b8067015fe5a5114a94631407f930ed251091ee7326e802078ba9e0ca054b8e7beff971ddc56b7c7e7ce77c943be438f2215d50b3bc8c9a91fd4fb318371e35d97284a54987f2384e46fe73e3fc10b548efb5ccc77495e3d1653e1c91178950725c8a12391e471a06b23054998ace1e31efabada48a5729ea9e7419bd96ee8bbe4ba77be596baceedaf754ca5ac4ad7623e46002eb8f0268b8f9f3ac4f44bd9ea58930e1adc792a5918ce918eaa5d2c6a8d8a34d36e325d4e413adb5d6ad12393eda6d92766ce4426639b644c762f7d63d10580a231c0d2d949a08735a01e536a24cd8adfe77b2951158437b5122956f709eb8a91f3ff38679fd3c7d2540296e60b9151cc8219967eab30528f2f1736a12854ee4464375e1dbfd200efc6850b615457fdb9227d06e81994e094a86efcf112b23198eddd4ed45f744898e95f70c08b54f96e58878f90066f076da291033ad3ef310935df18a1ec1c7184ae9f6103d72f7b42f2be5d7e2d3425954b21423d8c707838a9cbe21c41d3f6405bbcab14333d9659655b9c6b87d3234f8dbba0f5e13a93620671d926cc7d2e32893e8e45ce8a60b8ed555ab3b888b386130e0e60313fc87bdcf96368d33078865ee743b3c979683d08b63b5deaac54491595658f2e3a2f27f11f1390d81bf8148328b2975d13d610bd196ab0eff4199622d60af727878dbc090da5f8cceda7c1f404cd1b34f595691f99ed08db9837598ff835bf0534a10c0fe7a4e3cc8bbe1f1268b816cf9d752d3113caa0b820e2a15deab489750f17103d5903ce4c2062aeb9d0d0e064d03f494d37627e2e5f043cb869c1411898eeac319c4fb06da4f4ddea90e0cd5c970823da5167dc746ad11a823967a188c45f13c7eefe313ed3d49910558c79f5065d22a778c5662a333b28b4519057eda0cb4db07c92c633ddffc5db251b8fd2a7d54715088c015a76c055672f5efaad29436e9d8f5bebfeb45dae770b08a0b1573e9329660e2cfce960337d29a3df98c8bf7bd400f4dee0a620adc0b58afe554bb35acb6a3755dacf3123762221aa95c4c9cec6086a99cd5c6770961f088addc1ab289b54af08379fa764b6783857ea2db73317d286768fa16287ce58397e048a3e5beefb887f4e7bde7aeaada410f1e73a41170fca1f8cac7567f6e31e0846a4766f03f667140bfe7cfcf8f09414ede47c3d1700c4db84c04ddbc242fd6d090dd1a493dba57b74b56725dc0899a4fd555bd3d9ea11473a42c96243f0148a3113a4937e4aa32237873e5a4189b5b32da07e9a455786d60f1ba25935e9fdf0b9231c706a644e2441f9e903f4c1468e164481c988cfe3c022e9ae1287136329cc2e66be825adde773b3e4d6125455851cf42d0d2f869d86af2c9511bf0c0868b41e60a8c2997dc314e8f334eb7adbd28266a4627cab616b4b612d129f0c709c369e4d86abb4ad541bb040cf139692dfc16a3c35b4eaf1b71e4c5fb2027b686788ba15e54feb9ee5689c038f21c00dfee12ce6aef638bbff99fd15c726a6e7f5e022978e43edb748c2f1614232011f96207c31e1d47b388d66b98faa905000b675198b810cae7569055f182ace474034a13a7d4e9e139f9ea722eaa221388d483de40ee5da25f33248b543cd8a280955af06312d05f646c444fd9a4816d2e019302cf3c65f64cbf03253557b3930954c13951f7bc741436fa3588012d5b7be2ce0e5543c64c8396a7ff657af4911a81e01fb40d577c014b5d7298d6fa5e8a06138284bcdb9c9a8dc0e29d6576fba07a88a4007053df6f158462d0324ae6751932b9c0552db8f4cdd49224ea9d9f1dd44fac3a91cfab0fc9194434cea8fc709ea99fe18537e8cf07974aa59cf17e421d0afbc58470ea807a51c6d8ab7968e47738216f050bcba075d498613b97abb3b482b6af2cd7927faa4865c9d3323d35822e23e1ce689ecc1cfa05a2b7964484f641cb1768610b552c4614b5ddd9c09999901c013aca942c660f65c3c706a65da865cd2d51bf42e4ca6d00820003a8d9babc4796c5610a364daa66c62783d7461d17d538e41be62d94c95f24c5fc22e91e2c04b356ab1ae7f1996db9842e9002edaa163e76b36115f23283188eefa3a40d9098c6591baab6c4aea0d023f2ea3324a3deef5942a3f7fd9c338d253424a5f169a4101c3b1f998afffe49b355b2422812b0dd4de06d1b7a29a801b34593a6e975f2dbcd61be3c6b264e5ab20e518b906ef43caeb479749a485d4ebfb1c8ee02860cf9df9647b5a9b6bded8916ae882945cc5b3c6f631b9e5f0d63d96ab46d00677c91fe054e51b27bce8024af39cf0ec3283ba8d59c66ed7ffc0d7982c6c4ddb495a60235655d2bbe5c15545abb7ee6defe23bbafbda0525f0dc6af316bb97b94bc868e30a67023a767c250728f74160163bf5f1f529d7ce05ba10bcaa5b5e80b8bcd59f214beecc431bcd895b13cf528ae56fc0f5a33e38ed182965be713cf073e3162d21b9844b3e6f4cb645bd753974a08964571e163dc5929c2dea5ff5a4f56429aa22994dd06c6e9606ca618dc909f967525ab067bea08e576cd5cf7d8b9b406eddc06ff2c4551b8280bbb1d74f269b5bf2b05eba780e98177bf4432e8490b257f637ed360c6edcf7276e837b8830af9c6163be613a99bd19dac659803fe32e6da22e4a1c2481c951ffec3e2a47536fcb57cd84157418f9e8e8eaf88ea07b7b5ab5af2961f72428f6bdbc31d328340a94a988aad226e8dc908a5ff36b21a5816c8d6b60e8634482ef12040cf17f278e4dafdc3bbec06692ba1ddf1c0efe61d32fd4fa5af59451c38e6cf2480dea46d5d8e0ab0947464f01fd57c0e3bcd1c05d1ab77aa8bb5b72a592117f662a4842fb27fdfbad2dc6639c80af4b9e0372beacc2be5daa1d2b8f27bb077a087ca54c1855665df429ffe1bf0a8dade0305f0f7983bd8e52cffcf09a6665f9687d1a2c6c034af9c4fe1deae8e07314a1a5b36a079942bb9fa727058483ea13f6531d187d5bbef6c19a56ea2f5ba7d90b6153577a6d0f49194f54e1b401cb2c8e60423c24b9485b63697da0b90cd821f378b541d89b65ec0fb582d499a2f5c25cca60e71f204e2aaf0781ea443cb4d57173d4b205a7a8aac01190df9993587eee56af083fc62aa9144b6cc02849412e3fb9541882738203402fa3fe787571b700976c520141263087480d8792ba9d398a4fff8298d35652f7105dbde4996039c818d46c8c74e12e34711149460228f0bf0a7f0b7755c8432d778c8531ddde08c02d3d13b65b0fd0324d0f335bb8dbd253b180c9762d87a07c579b49f2622d04590a308b43f2fcb13235261ce2b3660d86e133965d87f43d88cfb6282d4d80e12022ad90b3ddf26e2c97f3541fa2440631e892c51ad44f41c3e5cc3dab515851edcc81c586b275e49a724d93e956cb3b4e0679e1ce57bafd008694bf36ba40a8dbed9dcd76c058cb81660b56f341579fe8e586c5d259321919738cab8a1c3c1ab702218a2adc6f9917fa34ab750129b8657570576499a071d7640de7c66c05236842e76ec78fb20864ab4e9d2cab4013e7b65b0b94609f3950cdb2b9581350876b19475bd722742b318566319a8415c011330828160646935c4a6ab0023c53dc652b8b6007e200d1135bdba7d67f5a3f8e41b95f542bb24a5df08525c205baf7459372abbea27d8b158bf90a5ef46e12171e80cceb35c90e108f84c168e87995020b7930450d77d2163c824eb6cb7376003c19923b98effa4a4c64a71ccc8dd94369b2643103b218309a3f5e8d551008de9e6151b7f4fb9d9f82993e0223225f35230b59067e083e11f1a9d3e0b80a62d6ab8cd05c33aa3a29ff8f14c2fd3651ec0256737cec9cf8f6216da733dea3390d8b0b74221483010259932829b69d8e7a6d470ab1f340d289b2078e9c33a9364d37f4230ab17b4832a6ea86c2a3cf7df57b0f2bbd86ec64659657f7ac3b79acb07fe56b6d9a9f3b344f1afbc240bd6a15c00cd974cb484cc44dd95e9889b6c9160f6a36e4b326678826d2230a3075c206ae725eea9801df5d9973745729251e9778a99371cd383c78385e79ae942b6c41b47da8dc15e81ee894989254bcd515cde252ae3a0c9610a023267f7b019c7ab7804d02c15414b955c9d71f9fe2ede2d8475b114b913756c37e57d933890f9d0b0c60e6ac690c62ec3b12d5700e71ed8c975a90cdfc3c7498ee04071dc590ccd06d548c5d91b2c9ef61b216560be9c887a4e5c061ddfe04f9c50c46491b4168fb2ce1cb7c3664921237fb1a51d419525792776b5b615d63a5f44649d1de99c63deca0162a7bb213fa858f22a1a294934c4924112b56fe2b81ca0af5e4df817690ae6726ae24c18ed18139dcbc5534e7e5001cb2588290af8c974bc284abdeb0f2741b017eceedee0cedc16af16005cbabb12607273e0c8f8808d3f37cba3c5b0cd5cdbcfddc065e14c4867d660ecf1de8cc0f08185498f07ba5670e4ee206e3e47ab1b10c3384e84f7d40c85b3660164a27e4f6247f24799ac3ac8606c630e0efe8245171e2ab13686fb18db1f8871acb4cf292b48317265b61e14270c443aa88739e86990cbb8b1108154f28da0dc93bfdc3b8315ce6046d3d370620e6065a414e274980bd190d7b65804eae04ef8782ae5b95baa0c404f39a30b7eb32b31d8f1576237cecc85cc04a1f8aba55345cbb71af3b5b8a3c327ba4c51f8e7cd8784efa6049e10ac79fc4718d576eb6ceff8f83c22c394ef5eaba2d720f2fb042f6be6d695947b8cf972a2920fc85fd17a54364aca817c75bda24cd244d81a79c30d400bd219d9723efe424e5460e062846388787db7e673edfa57996dd9a5d83009bdac74db8a2ee116b2c42b82011c8aa32fb283e9b836de14138a81139b2f997fd4521702a54388fe52b8aa1f95df26436828004fe13444a1ea33a1dc3b956ab22b97adb754ffacca8b397dd8f58742841ec699129718f11fe2c094b2a4161a55e261dc3a2c77696e122e379f97f2668214596bef74be4d6a84f20f22eb7e9ca680b9d33bdd65c39461bf902a1c0cd94383ecef820b518e1b57ff583653a8bb9e32e2d20a97c3afb77c3033bcab41cfd93e5fb1bb45f2139a08b7fe1967de43c69b3a541d88feb26d6a4af7fa4d6b32bc3526b473144b0d461eab842cfa0a7470b50d7215b7a6f5e6f5ea1aa26beeef4437d2a4ac44a68031b09b7ba40186594c36674401a0de29cac6ac1b3a92ef0e9fdedd9e44c60a29b2a765844376a0b52612c6bea042953da1b3b4b3bc9343f55a4ba4bee8df4f8a8c99e8a7581491fcb2906ccdea4f82367362e1b8eb0039c611a8d208c1a43c51cfba7ff1b06a698391cebc2eb08a5a8be5ece3fa2a84f2e927b2db9704b90ced7b11bf5e60692c6be6f1218b1a015a15459c4ab88236eacc6f36d58bac0dffab6ce6abc87f5950893a2b524e5b54548594bb716467047fe4cb3b4c32c91c845d4fde8c153564012fb54776f4729d5d7fc6ccc3e8daaeea2ce448be3ce28cbe3f4970c1c20fac51df700682e9d9007dd442a3a6fa514dd21dee8cc3a2c089534308fddc0bf8ee4d6742fde2805e4099d27178defc07f6fee7b474de3fcc11b7aba4ea9476e7d48cd1d40e141aaafff27dc7f4291755223c515f75d998947408a0e2821f86a53caf23f17f2100a5eda6280288bb1028f0000927a3c51628c482a7d276ad8c4887ed5b1c0e90fd6eeb9a965426f7d8de17bce152984c76aef60095ae8c8468fa80ebc0c83ec01f1255b813ff2e564c0933fd05b6716868818a27f138ee2c2e630ca49da2760c5f8ba5766ce264f9e9c6857bf4ffcf9c7dbdfaea63c9c0ffcc96b519a2765d2a0d7e11fce728ff440123dca04062d669e0249a4e6c1907df80100a606f5f6c13a21f755615a000f980cbe2db0e22e04e81b02459e3e99bc2ecf4591753f6ede9701be91e17c5663550c949bdd498eb0ca82302022111e25864b687ed3934aa0ac0c38e0597cbd42a18c83ba32f099cb79a94f84de00df861f91406849bf57d7ea6bb132790fdf65be39040858c8703b529c61282f1da19d2a675193ec74e5b2063b6f0743fb29074e56eb9b8d98fd335719a0c890e7977178cf3b10a8745e6629de440587afdbcbc5b64d86f22e9f1c80e24432d42c87b5ba9834fe0841b0bee226534c22ca22de25498f9f4a12c0ee1b8510e81aa04b82911c4009fc6aca705ee8cdf5c208de15e380c26f501f142fcd92ee96cd33f4a4530b7ed7345405e6f0b22c78fdc00cde1c15af49ce7df831f446869292e7fea6de1ba63b44a1ea3118165501ca0f9a811379179e5efadd8b1501147204535d6890d0f1ac503a3094845acba2c47b122d9124b0b871cff4ec99f717ecc2997ca82f719e5afcbdfcf426ab20f670dfdeb87480152bade227ff7657d64f6e4786338578efb5642da1e8e17c975788e013c3c7190d6aa63b3a2dfd50342fc2e3c18dd1cd5297e668ca9af7d43d5420e9b9b5783b85634845019c62d9ecbc851ed333db894950aad994c6aebf67a2078e025627664a1574b7547adb496a6ad03944be562600ecdeb3b059af34f531e825bbecc91b724004d3a23f2b306609a82ee1daeab9550865b62b8f261ea0a6bdf277a174fe8a61e4c675e4f91062cbfedb6dc15b6a1b9de2767f2fcc02fb84d9d418a882d498d449efe22266d1f17037a3daf4b9431af68acae32bb3af30c1ca79fbb1361e36624a53eefa1e168af7eee53407256ce862febcdd93507662ee1d5ff34cb9b21922bb7c4c18fe5331d2ea13cb8cd04cab11cca0304766ab1be3bbda347b21b2daee5070a3b1b30a4a309120c6acb9b0496c8e194a8c23b5508068aec0518ccf220be97725d71d80ab38ad713a788d29d7c680552c59263c25fbcc933d17b71d718bf3f01158d564d81f3f6d2047cf9ba2b62562c55892a49cf70d795b0edebcefe88b93c369b257b467ed9af22b3a28856beac0098addfe28b868a60eb87cb23e00deedb1497768386f0f4523a3dfdb533243c3db1b8e8bbd96cec1ab8e9a39a112c2449805ac11416b2fb35d5acc68bc7ce8711f5a0c9091f2906082a26f093f43211ebb28fcb49074d98550ea9e4a2f6d2e8a4660fecbd3b1e87040fd6f47159b25a5e2792b12527bea93c59abcb2341c6bf08439f365de145bd360e60abbc0b144643373435fe2e66a5e0414d57df1de383f27d5ebe5aac14ec2af9758964ec76797b1dc27f0859c9c507860a101358a7ac29f2cf479c0abb33835457d57bc508eaa9892716553e31e4aa718040d290dfcca986789e65c7096b98e70e1831713a305a4832f2dc1d9b82018650ea1ad909868cd1ee42fcead511dfaf4a38253bb0d372802087998760f42dc1a288ec8760979079db60740de531118767e0e1e3193c3ccfc2a624f1421e77f82e5a927d14ec6fcbc62b91f6d67688d54ddba655002e11346deef10642640bec650d143b88277596aaf2412f1aac868abd7fb84baa33ed754f8860126085aed77fe6cb237e65f33dd8293d5f1d4eb7e3c71f106c3855666a4070642299977095cbe9b565a733fa7b7a2d0fbf90f5a80ae83226097203fdfdaf9d58515855dd4cc40b60b6f2a7643f368c140c2a68c93d319b58850b0369248ef6f6f265324bf53ac49dc2cb248f1c0c20dd61b78abf1ebca2cb18e631cbf8f58fb540f7347d4eb46d4f560ba2297a2ab076b161f84dd69904a37500993d120035d476b613878b78257ec2284762a44a1e95b3d0691219500e4feb9ec9555626489904216912a61bc8c99f534531c1322d919c4718597053f8e68706a75604008c065b9094eecf144e09b1488b3002be84d6e4a54a35eb124de03196b653810eb42e1473be4811dc57aa05936c56a059afb3b814229abd30ec6a602acadf77aac0a6479c88f559333fa36a1910a79d3443274a36d49b5e7f89b68414cdbbaf11867ebe3d2a36c8ce5b67e74452f47672d07e7d9e542171e7068f1832bc155995a7dc7093e06dbdd5b47b326daa6ad659eb55b08b6e793735fb16b68cb16b88bccab69a6d3600a120c2510b830d4a856149f68360055d52b69bd14d0b2636dd5462d979dd2f16330f513242a6194436fc133652036bd3ec2294d94f621ba1ff4807ae04a0373976375923fa32dfeb36d2903412eb889ae6f4b19f0fbe22020e4d20e56e06629833261a697a8b74a12c86a405cf6903c21856b46654cf81f726b3899d67a6175914850379bfbae2cb240aaf9e4253410b1ac21332caf0eb15b804dbca870670d1591fbbdca4324adba945336004ddc1144c899a165cda946bf11e0ca39c77e0723fff3b81626d8a625f006d80c5d3e1c5eaa8f7c33c1225e6c27b88089dd4ae91f2e506cdf7cc9bef5a3c02fa266e857d9c7aa316311b78408a7c401804528c702b57c0b5d763e7dd97f06b5fc7249635614131992f5e241d215b9fbd90aff1a64c5b729f85fbfe9ca66efdc905bbfaff6e684351d3c3a0634860b6945c31e464e096e5a7d0bd6c12cdc3a3b74595a97c166969bf22bb9b1ae0c6496e07d0e7775ff1466196b7d0ea790f35bb611f2371bac2b7d6b283ae5163039e4735014a890284450b2158a1eae95e2790fb0811ebd6bb78a928a2fbc5b56d9feffe49ac361d90c97ca0f5a74ecd04e1ae98c2945290c2e4bca2e11c0e07e048d182f26f8c1478c6413c1d36cd3ffed2e00daa2d9e929edfdaf4a6fcd99a750ce105acd5d231d3fd77d06d0f6df041f46c0ed9d858cdfa27f1f7bb7c2a3d2c7800255ea1d3da2ba7422ad56ff5720725ddfc2a0db6f5da0e7cd7fe37df60aeca395da2e77bef94700683c70a4ab0c6094bda8eb236dd3c489b5072438f76f9fee25b4480fb07803d2a863150fe80ff365847d76ed606d8bcd8c53e15a30bc0639e36c6278618281b927a13f68111134aea64cac007ac1b9bf52dc938809707ae8b69183972be68aaff327f7169e2d1228069d5fd979e303e650378a741dd747652fc9186e756fb2ff2fe13aae4682bea633d24be85214391e8cfe38aa05a72d4f1e84072ebce7d24603562f67ad6e49bd0a153fb99a0de77f915c66a7c57045368fc623fc1992fff8f5ab008f4b6fa0a283f070bbe04e0ff9ae35cd3c02b88d669b60486cc3066a12cceff85fcbdc6261e0314ec3b038597cd1207d33c1cde2de9ebd7a856d491ba61d084abba56b8fa0ae9b014de35fd6a61d8bfda42b7430896dd820d184080d588bf40d65087167b3b88712c75381b77a95f2a79524fbddd4a2f3bea680e655a4b22591e132deea53f7c44428d7facc772a450ccbbea805102772080c4a44bb643fa3b27f4f05574ffc3d2a3a5310726dd8a143da8c10915b1d5245497c5b30064516b02a5fc8cc129f10ee97896126bb290046f09fd177ecf9ba13f12abe904d2b517f49ecdd2f73e0948c191be4dfb157b17a35a02b9134124f508876b0b51fd9402d2f406ec58530f54e7b7c275e1e2c9ec09e935ded31fe63ff3579b65d91f03f0dadcecfc09b5e710f52d851531a33f07c11f06fdaa7cb678c95f069614dee53992b665846d2a61642bab11d24e7b8deaa8a2c01699a120db70cbfabde42014e331246988a39f2d5d880822190f2fa9b316824197c4b330fd8463d13855a88a3ad2481447b00e94a296c6dd4e042a6486b7d341ec64ea6d29fbf46346aa4e169d4f92ba53385f663ec781ab394ffea238d7ff4a196db3dbd8fc2a149237bbe3504c975d0afbc0e75e494d06d78d3bed49b10344dab1b61d547d6d0480b0a24b10d1c1a1ede9f6b4a71d56dfd2da48d403806da531ca75e24bb23cd52be6e0f86b29a27e6e587c9ff12f2dc272406baa47765c44b2f7601a3879e81c777d82a58469829b74697cd3bf6c8f5166f9a3ed56a43ce47183c7b15fec0ed66d13dec7c7b3497a4098b795c78fb0ef41a8400a42849adfc61ce9c4d9219f761362d65e7e8b26de09cc66dd46c4cd2a34f215cbf26188535a146cdc8cbcc8b87fef353c1bac4aa6e1fa9ded4bb94a166e5666098db7cef8ff689f2fb33eaa5a9be2e995db34d2c3f775aa6a0bc37cebe4ffceb42ec15926d545b2264879483d38a68398cd7500fc8dc2936ce2c8b4a73c49bcb193cb50838050d5b23f46db21b6111ca201b1272b48cc83524d064d36176892f1cf5d80b3bfcd7043cdd52102c2f192be4e558eb7fb1a362c002a2116ad39b697022888d385ed42c192883190c8e156a2cbe91596d3a840d178150ce12de2d6ae6f1544dfadbbc1350f17e94b57431d4c138908514d0d4f482505add3888462aed9f15340d30f361ee83b81b392839923d5f50c24288d6aed45cbe30d92e9918df682e43cc74648352e352891bd63ce7625cecb128114d2a3d8b29e46b4a791f88ccdb737858cd08cafdb9dd612f3b3ad8d20ed12b8324fdf9b1263d0131fc3f94e437698ad9a1a5cdc8a6782ca9595084fcf49fada6cfd7e83e1801378a9a680948197722c92df68fd42c3bf412372163b4cbf1ae9fa1867d3d5720ddfad74696480196b6027e2135ab3c7ca51165b949d8c56005da63d05a910f4efec09b5048cdaa6e2dd64df1063543bbb980ab6f0b8ea910163ecc4255a0626162659af13c036d8cb8c32d70ff8bbec85d758c3d5e93bcdfa4d485d8d0ebdd55f126faa44bd1649c05074c47cde296bef9ea8490f3b9d5e6ad35942fea51ae37d8bf51334b60c4569d6f09657484f67e5ec83999b978a146cdcf03ea56004ca3e6158c838acbc3eae3dfb0fae757ce541d9aea55946b2c2aaf5df747158d2be5879fc4c1bbbb4346cdb5c0546ca03f9b316a664fb0caf1384a16a63f38a62fd11d56050196b73cd734f84aca9de410b9b1d89184f241275d30c189ca7c4c86f321995028a6662757d45c0697746e766996397c32a5f3f65b22ae579f710e5b484c5b81024f5968b49ba266e68245de5464e69792f9a02444aa08915ec0f0375133e9fbbf5c92ef6756169833ecea4f44cd0ac7de5aef05ec7507dd1e06fce39eebd493a48bd47775baebe960493d6e3b9a91a95b3ae396d98d5dc7243de6943d57e34b6b676797d042772c436086c17f909fdea8c2fce633196a3e66b28449640d3f4365b8c6c56c1b7e3f8584626f65869a152c762278e145bfe77e4657688a0d00c04ab1071561d2ba481bdc43bce715723282a5220ca99a09ba9fccdbb42ba2041f814ec406e9073bd6e39df7727c2ba49258a6a54ac5d14e26ae88e626cb0146d74158fc170a2a65fd5b3dda8a0b6007a2d7883e4757a0d70913aa1a0e71673f8300bed97688f8dde82910ee465afcaf844e9a28ef8d761cbf5bfdbde3d86c476a5e4d6ec49066abf4b4380b608c3e6aba4ff0a211c01e679ab9f1a85ba222c6244c83040e872b83a1ddde3329d4a74fde63eca5a3f0898fe6751bb5b20a2d081d34111154fa4c81e5b7579518b7680d42d0dd971255adec5d12a149f9d783eb957f6e4594d5e196d0376b6d5e9d085d16c4b3af8ec7255aa81b1d0908ea484cfb2d0f07eddf71d0e48fb94e9c40cb4bcd24e9e7857432ae56809743cc04e9afcd5186d333d4ec982fd942c1f054e42fc39112c45a8c83f9b5b68a853d58fae328033e961b38821c48365112d70e4fff10417dff0142959c40bfc0472051edd4a0e310fa49fdcf77548ed040f9e1b1ff7894f47fc2dc45e944064c0f338a706a3d8c066c0d1092bb2a958fde4a0c94df30ef134595edad2fcbcb6ab11e2db80a1637a97f9ae18d6f86c2f714daab10a197078817faa3dc075b835d3af2b90c8db2654b27bb04f1ecd4876104939856b8c0b9af61411c753ded80dce74b8eef08d075485df56d9c8ad94c4a3b450501df3f778e572bd8b951cd0e2c5b3e56073387332894885711d5d5340e8af0b5fffc36a115376d6d2ee18baacdb573a52841b96134aecfaeb622150a3363d60b4ee8f60b0918973cd0b260d2234342623f9114dc5abdfec730df48b27c203623fc7e0eff065f8870972c27d6dcd4d5a4a3402403c9d456083cc9ee3ef928736750023cdb938cb1b946e4a38236c523f880b120537c8f3fcabebc11293009cdbd821b4a860f0a359a6a6ca952bc02959a13acf83af0d06123845334897dd1fdf3095bd94e0d1a76acf32c7e14132005953cd750172aaae69e891988d03bf25ddcd0ef7a850cd6e5cdfe6fe5453f1063a5ad81b3b4c3a834091bb912ff48d8e38a5174986f36bcd219d07a510f4aaed8f3514024c321062cc6ce7a2320c1c1b0077de004d01a716194446a479b4b87b40707dd59cc5c0223ebda9bc0f8661f69e5de5eccfadb282c6295e5837fb580f33b74f86fcc61fa3cfad6a91f0b2717783093d61693abbfa5a93c598610b91a1c4d42480037b43b1e51f798be3052dbeaf2373ca30773964cc21e872280029a08fb83304cf2022a7ee0cfb1a8dda7b5bab7cabb053c443387d3cf567fc0718bd44f4463586a70bca1e96617eabe8f04751e6974590b29490fefa2b3e3127867cd3cb629ee02fa9d07ee2363358e6db390f8d0bd54c17c278491c9550d62f3091a9c1213e2e416050a1a8c7585e0057c308223320d817327b8e94f9915d9de5694ecce8847abdd0751417057bb2e368bf53cb7480d4039c36742260c61dd744f453b9db1553283f1d37f75e172f10d9589fdefddaa015178715710d3a2800c5e0a22a1d72910249171ad5458666eaabe3e246d0368d4a2af7e1294622be487263ea466ded9213bc24a7b0f5ce42e19b030a3fd81aab6561b778b1acad2912760f548344f5b1fe012f83249463a91fac36906e69b965834a766456bdc80f6ea8d971cad07cb163dd0bd1f50c41499e311e9a703848ff950c5604e9ecb50f99e5861bab58a1be56cfd56c208706f8af76805fb564fa4693a08265df50c6eb67c7931b488f1baab70773174a5c28a785799e97f6875de05a7774939ea4426e7ddf0fe41f2c0909cdccbbcb788fdbd48d97bc55f558a64131e11c810339eaef0e82770ac45c90b97bc780eaf7b87b73eddbb3657d63b76d97d69747c14121fc060820930e3b6e1e2280c2c73aa7fe1a324a5a96b685f9b0443a806ba3ec547731f7b8f4970bff051c90251a909cb766d1a697bd2e693c36c4ced36c810038a5afc9ec176049df4e1b4e72fbd3c799980175126fc8bf16d06c6a6ea4d3e94c2aa2a3878367635e3326b3dfa017a04c77d24743e53e072b6b830401948ca0b42c596ce9483a1b4b8ae435e751f329707d2f52c80f5a1f72c76f32564af24ee574a157c788c3da86ca747499afb6a091e36ec7c6d773f45581ab15afb313a1045ad2d300262e7f60025b337fcf9441ff9c0e3b4e663b0326265840cdc2b5b4df7f8a519de49da06b5c77e2d3ba44f0cf4b08aa9b4338d731107696481c7666c06912840d68c2097cfeff95df2f60ba0d481b22b9441e2b1c57d4318e89a3511f4d858ece53082dc6198a5549eb2840cc222e86e49efeaf1daaeeaea8ebfc9930b5fcd085c092d2add35fd5da326b4f268adc358e67b8f0ccfb2eebae0dc3c31f4e5aa58f36b4069cb201fb0d514397a015262d2ec36b409a2a2a217dd60ada5887fb8244cbe5a328fa07db48892efd90a0fd693b34161477cf6729cd62a0e7e5e506765ca75a2f2abc1958632c53493e1559bafa8d82c20779af442bba558c0b274cf4f8294223270641a245336b71be32b75cf878c886b0e8e1bfeee4181029303511e058c0bf5ee7ce296e80c3252ec3a4ebbca62ac390cfaf573db8df4560771ca2edcae35799edb494314ccb45d31b7510791ccf11d503e0a7d864fcb3c57fe801232863b3d4f1e4f89e06b85b8332588fae16a800d5b5475137457961c5350c01f2f101f8e1396bab5fa2f288ba938efd6f19207c0e9aa75681a5d5f240930a948f67d352e73d50496a98f672c97aceadb2e725284b99c171980f9b5c1f22bee24ef379b5d673bb5e9f3bfaa871daaf6eddd2bac49c013f27dd36534dc5d3fd0c2d9e5a4339bd60f0a4a09ca7e14d5a91281ec45ff1cee3e2d456f852243a0c0d32f887d00d19936ee37e663122fc6798f7b1dfd3cc2fccbe1b6bf78a31f246a16af0b77833df327b3798083c4d17140dba702f4fb5aaa3d090a8482a875f45349e3186f2805a252bee9c6e42ec2941e73d94db8677118f110fe729cad428c4d123aa907df2bb193721b1c8017ef2370d45296bce7f7028cbef920be8eafd38f5e325dba1517752c2f460b50133ac9ffa264bfef3d570ee497585b81faee653a28f7a9db1d120c6f0750555d17cae5d869419b5a45fd800039dc979fe1adb447e2b4017556dae3abb121c6cd400184fece4076a4b30a44e2c40c860da55ff075ac5ffa12e11c21ac7cad4f65e17c0f8538962c3ab5cb5e2ce0352426416411cf81871705dc8063920aa887a1b44491cae9e78838c1baf6ebd90af718df28c531d09db877b8ce84f49e4d421aa2ce75d16e21d2c8cc284110acec2d610febf1ad579692dd004ac28b35bcb9c54d27c2dc8dadb749ddf83615a76d12f40e48f35def7ad54036075ed09820eac3d504f24b2d8826f69271fe2d40e023be9b792629fae805c2a88067da57ef5d0feca1582a20c39c97cadb8a493ab16d4249eeebce27e02a4c2dd53e822f2361870148fbe210e4645d01923f6e2ab6cf5faadb67af8aa283daa913be0d3d31b886358823edf43bf4e32191dd987d2b2653bf16e8bdd85acbf1320da62eed80ab45ac955bbbbd2dfda60c93a1f132e9e43738acc82bb546838793bc55884309951d726657b38b674d44b5df216efca7d18bff7f383c6cb953c3633b956f75a8b1038a4b3d67b01e69dee7be60b072678be9f790f2fe645f08fe664560e90f3a670e336c36dd147fb118d17c16a8b6c454b310aba7992b016d40e063e5fb7d64550f9458d7032122b8c445907a49b0475484d9e3440e94c6872139ac2f957d596f9b0c54e88cc401022e34d0d4f86283b37c169e09d2a8a40ed931458fc41c08e2f956a93b6196145837e50f8b1d0d5bdc3f888b42ca105ec609000e4fb373a778f0c698a9d4b1bdcf03746f2cf0546bb2333004f35b58256d1ab25917abd93d4cb61675df821cdf0759b3f48b19829e041538423513e913467b4a830ea57e2200b3c932e90fe5d395f4fdac69669ad7b6bac9496f278e585583b78c7b118b725539ccfd0c2b96fb412bdc2b3b4a9519af8aadd3e11ff1614022199e60e739513a7ab567cf8496c7d14fb6f37802562492be2c87563f5cd5c63e79d55a1acd42057841aaba3edef5651b26ca6d43f9c0f36a05b05fc9f159f89bb3bca882171403d2c7d9d523bc829da9b69beaeb2af83f70382ce0c2e61c65052e341ca27e0d2b97f676d1aab539258961e3db1ba4199060988b36833cd10166960c9f55ba2d2a6d9c598151296bb6cd1066a740452eea5ca83a6c84c019073eed6e698da24ce3e03fb3ea60a3f891e7d89d910506b2fd14bba68e114a6b0137955e8a1f918966b94ce6200f471030d5770950002a17aa6fc82cb1eed1cc122393e4d2b537a1035c3a02e7e714e814f70e1a72b0ecc65a5ac44ea4f5a925c16a881266a98f3250e540b72782fbe9d76549e291108dfd200ef590a815d54185498b338a10185fda89c8811479ff62b0aa99dbd880ead58de12dd21b19c09fa1a9ff2051892c79c17c526ec6a44dd2dda1c64170794eb882a33cffe576d7e6bc208481027a591d88ce7e3672056c2d2ab97cc046eedf3c2ca738756b8212e1819cbd5c16091ac44052a0eb44813f8636b24231d54e8995fc27eebc13f7203c756c024b304f5426107a0f3ccd5c1da7dc697adc61bb1f73b348b1e1107cb9635ca428f33025b6fb03220584b0969b418e697093830b7e374e9b101d851b42c80fd0371b7c51bc0ffd53db8be0aa5bb8d58f52e62dcb9474f6d462829fd117b962b5afb1814d33ce7857d86c303f0195d899e26e363b59c82b37d0cfa29c515a96c05c0c555ad94dfb52ad367d48960a2d4b6bf357adf8be01e2188aea388cf2f05b5270f9f7f428002b2b29f60ff63d40480d30cc23cd5c27bb83050e9b7f3ae485ffa68723c61e29ac850a70262c5f8adda2eb2374aaf94b1b169ba8e7b0b761125a84e9e17f992759af0f1ffd9ec8ef95be9523011e99127e7d6140a426e4141dbf404b58c651ff94bb45c181a85ed24214e7f7bbc0481370eb6c168fd0f22388940eddadd960599a38ea50337a2a9628290b2ec40aeb6cb90ad080c1c3b9fc973b41e85d5915eaf4a668ec1de8d9a12f8ad98549139d116f4652d80fd540d4a04da7d85ac68664a90eacd345499d96c72caf8872ed680a5b50c51b19e0bc80fce10ea6e50ddd4a0b579d5521dbf871e99344ba926082aec0fafd10d34da455b09a323d6b2be95fb127b5b63613b22e8eef7eb87b4df949dee3f197ac912b36470eb754154c855b056f230702d5b37a62d95cc2d792714c946379a6ac2cc3cc8214d903a8394ce6175dcec4afb435a6a3e87ba5c57376851cee485c0481ea1547637667dee15ab1c67be1d0c89292664e841de5f1656a90ad04fec771bcd56e9007764167c1f45f66ecc1f6f3e4e2518e113d87c8e4926b2a3ddeb5a7d09a139f6abe70cf182398b9e02e0c44d8058576b06c5303e6f49116a2b99a783f19c9aaccd926009143bd26eab40659bb7ef8cd502b7be8423ff3ee3ca738f27a073ec46ab6be789c157d6952fdf6e760d1d65aed20b4f8b433386e7326e3c736398fde62fd582347e1bf7063fb33e87c68f5cdae66518d4c2bd22f38464cf92fb768998044cf67bd0a6bee224479722a34f37c703bd059c1cb5eae6b8bc480d580af626a8b6077f1474a1c593b20f75f430178d7e2eda4e93f2cc417e524f36436970eeb48beb64c00521e118e88bae00c718a5822ef1c0e44f0a4ad1eac5b8123c0901eb73973024f03429eb8059fa3118143fa4b426dd5adb900875a4e80731665039b82e09bf30b71fe92e3d260ec5ad3cee71ee480d28c69a85ac284d05617f8c05c8861565a3c0ed2a18f9094dcbf87c652dbdf039abed8ea7a185f222e2c97815fd2171931a8997ec9704f1a20b1b9eb6bba32c09afedc531290f2ac9957cfdcc68e75b3f26c1d90ae208b0529d479296172265738e3622261fb1a142e4f65ee6ad0b93d4a830e3149159953a8ae2cbcdc1c9100a51633144b0233ef67d1f684ac61cb60c647a9228753a9533b108dc7d83585e65f4429100db52773cdca60fdc5676807b2c29e4cfbb9374c8dc10e343d9c450bab9e4c0e0fc76a61dbf5cd75a1f3a16b37400f036a9ad6788b33392ebe7db4d6d8e62783b9d868b496484e79482da57da6a3ca8d09a0ad88c581cc68442104bd5cab9c27a1ba9038612f7d774ffc5d3fb28ee32825797e895363d1b7c401bd536c0e388cef100f08e27d75d56ac85fa4e0ba0c4ccc2ab2fb7221814e38ed048ba0a3b1fe20fb1861d45bcac37521a216c6af787360350f44d193f297a7c120311aecd4f4a5bc7b99ea9e908dc6c797e9bffeecc0045b9d16938f867323cd13b9c262f2aa772899fb246ad8dcd001a521f683ba62ddd0305a91321077554c4e7746a4a338a48cab08bac32d5109d78bf927ade143b154deb8dea8c30fc20675c551ab2a2279664349f42631fdb5a5c3a561123a9198ae945ac39c4327efd05d0d5dd68115d32e8ab2da58633e97ee61977bca4d52f29c4f01e38992ec211ff20beb0eaedf4c35475f982e3f31cafa82da8d50ea950ddde46712b23d6b4c62e19e0e855d574fd98c28a1882b0284069eefd8a4099b94d6b50c6e24debd2fa5f2a02ab6bae5c10c2b2a05c05f3ca80f254fd890860aec3a442f49c35681cb2595881a494ba56dbea34db1becf4fac2024447c70201d398f5682b915822f690e407d3c6107402a7f02f50fb04331c70b3397d1a0b03c083b574ab78ea15bf3c508712a33cfaf0e034940e709a2db66b558ad2328074b57fe1c6c1ba5868861d707ff9bbaee664283de8e41f99cb94a64f16b745866405207e7c4c841e3d902d828b3ca09689a443e6140544bfe0b59f93263d7695c41ac76aeb062feb5742c5390aa2ee52443a8a88e25280fa15ceecec44e87243d90171af93fd2757eca2722a3636945796c28d6a1a22f729aa6f6207a34286acb0c2c8d569fb004a5d63424fe79cb6c15d1311fb1899d7b457159895ec05c22d423bf614168001d7d84504291758beaefba84665321fb38a5c61a4ffbe893b9f7ac6e32b69f327eb495e02051464fdb1d2b4a443d8b1b505052e2aa18b8ae660e02ba19b1edc4f7514a84bdc81e20808b742f029e891601e12b95e538f620d1e9e96332ffe9636434a88f29ddb8cef0994a9ca541aa8fc589d1c68cf7541c856d5a827b309b5544fc20ab6075124509434ecc5a16183a836967ee53bc53173cfec21e659815b3b05a5466e7daf4a7973bfbd415294c1ef82aa33a006d9d4f235882fa48adba24add53a6f1cd5e9b7133d5ba23df6d8541740a7cccea9cec83b783bf614cf7640dab7cea718442a03ddffecca23b30efe244522166e863ddb9912d746b650e9243808e4c04cdfd1654a395049efd31c76d2f9cb1d01881f1c4263df0a119bde59ca279d85e23cacc60e30c56c1691f03ad389c38d63d6cfd43f53964260ed610600b63fdde9ee66ed3ba8aaf24b787af1384c9ead95515139f13f2f9fd42797f2ed381bf3817a9681aa4a8a79864013e966635a65d59090043afcaf254274d97b116d2df16274cdda682d3386a28e55452cf911381d2cac3ba07fb004339eb67bf1532676597fd00f6a79bc55e331069cfb77b8be986477031fd79b540d529601ff38ee9230f7674c7487ea436ee15313da24869638342e1c3d08b3dcba7b14447b7ec125647c3cf2c5546e45bba5c4451c9999425b9c48a9dc081a80d90c7811e6cae593544b9f84ba5f93c62e01ec903593c6a7829bf2520a8106f8fce58fdd271415947b6a50132de245731188b725066838f490b3f463fa483e213b5ee2e74618277a691177278aab4528b901ad764eb207147f70ca972b177ce88de4b50babc7610d3ac42e05b8ee7c1b0727ea9348dc8fa3e22c538c41bbadb48a5f6c1a71467568000093673e4649500cd95765497d1897e1f36207d5e144970149fe327884a987c15ed78b13f48c65c802d2733c7bef5e3c6e7ff9da7d072a717d0068884191b85adfbc7621de843948425a16a5ee3f64274e6d2583e89c6773c024fdaf360ede8913d7a8834b0546dd101c196305127687098a0fe1d1f12727463e848453f15a0f799f873960d36353f35898c7a600154b66bd0010eed898ed0537a38908289be2b500dd3b58e6066b1296b679100a8cdf6fef73c3ed76f3d53a99c0f2416fc465c9685c958dbc9c6e667a89cc24ab483d258899aef92d3cea39f3cd983fe9744df868b74fc68b045a89dcb44bd62d4f77997d0b4e97bf5365df0b694e829b325e689d8878c786e732fafc195c227f85ab4f2803bb19a702051574a5f058b746ff62bd64e36a9f19bbd88e8a6ebe9685381f76aef7516eddd92f0e26de040f1e30e99fb7ce1991f2a0b37f037961394f0e8aeeb0a19ab84b4257a257e419c0f497496cc68375b1e1348c6b69af3cbdaf292b474434c91289f01ae3b91fcda47c0e5102136418f71b37b9180827544d83d1c038f0a172c10528513cbf8606436a13ae1848c2b6623b346e65f30f8574571fe28fa7196e4151c8fd6c1f44c7dc900c3bdb93d13ea98f185e5bb9c02724c6fb394cc6e26ad0cb6e0e8c6c7cda5f53915715b37eabf64f7b7b899cab0ea5f510ac84372c007661f14cd3505f64732dc42e1fedb5e8baf47a6b9f44608e7e5b5f17a4c8335b5b65b5cc62e016ecabac3a6ff62b953ccd7e4c187732cc6e8206aef7d08f575d50c8d80de4bbf3bf81b49c72ef2ddc0b2cb7adbb86e0f6abf3a13eab615942580f553ca436fade7ac08893bc57e53544f221819c715215c89d0e83ca248fa98cf06379eac253d938f9aa1522c903ccd980100f1b939052ef9471c1e97c4a31328e17d09cdb6c7c8a4c82ea413ec7abde291aa1a3ecbe16a6ba53ccfb9558d9ff19421e1625a0196b79baa39bf9337d327c7d980442b34f5b34295a5658344965ec2018860f7841daffcf04776f9f1ca6152b4c98b2bc36ba3abc94f2bcf4ab2570d5fe012999123be1d5f90799f1ee075e4aeedfc8abccdfeefb0dd8f106ef426923143ac2fde916ac68480ef35d28ea4f293dc297e19cca4301c8b4aeeeaa8e63f9bb427e8d272ab1880e3c0d010a45b1e4fd3e081516bb13677927236d8bf1dac0fca5eff0706906802adda38ca6330c5a1c310557607d7724d2dd7e1566e56497026b4bd0cbe273824102dd4dc80749c02a495fea8007ae42703374c8d436b606af9c1acd233bdd209f39e3c36b2e57669b2405f6b683825a3b7fe54578da23db7f573c018d650ae2917d925929f2c47d1aee2731038b4fa2b31deb12fef669a232b8fdb1c595c600385c1adb2cd5b484b55267b7e53c0dc63098ed6d0dac39155bb00a2dfaddb57c3c258e05b923812b5f47d038b8909ca3ed80df7ce08ee1e812d9dcac0a4b011105f85cb037f2e556d13cb84dafdd7c0ba1134fa1f9c01686631281970c0cfc98c2f0c21b7d89ef51201c97a0fc9bc2306898bbd51168d82977d1c136370ee50d6b68bd1070218ca46c1c91fff78001e851d923fe9090c34fbdac82a7ac10188fd65311210384bac5ef0896250a4c021a1a13d7b6fab8718fa8f95e8eb2e9e5334a1b572160cda8296f304dace4cb0120ea8d56d4020e609099625c8953cab475048ef868e0a3cb13d20fafe9532f078fe5b4b613b89924f3c63f83ed3bf5cc678270b407e8307514ef3d89058da445d5ffbaaa507e1b60c4e3a69a4f5f01b12a058079e95df1b3ce7ed70389849e5beb0c5d4e56814a5607459851a57f31783c99859d986a718c7d503a103c2678e823e904f9defe09700d6ecec5835906f7c10532474e82966bac9526e4abe781398fd4b8f8e340a8c6935b24386849a164d51cd6fff7383cbd77d8991393588031d98ae211b3436e20351475ab2352ea99e107318d6467ed5a912d4788a3781824095473d905c93c9814b5c88ed23a1a3aedc6c3840521b32ae3f9372409cfd558447bcbd56c6ab912e4b62143c2d93d662d8343b1eca5e2de0ef63366a2ca5bbb9da494b15965ef34627aa35340395b931bb2130ac1905b89eb1a0a81d84e0a747b5eff9ab93838610585be7beb400c53dfbe5139971e9b4198daf5925602cc1f326cf48bd5c1684ed968d90deb892981b859c1965b3600b36468a553d6748e74814c1ece14c0190651c04093e887f299c082ef4e4fdbe56a0cd73c5258c94ee7fb264852f60bcfe1e633d1e212d438f8863181148158aa8b27d89811f4726cd3ee2565e370818a7dbd3c81084c3089dd3c3110e71e1631c55a7bf5ad40b310e3b4ece36cceddffcafe5f2997d0b9f122c9ccabc7022be455d994bcf0120d4fe8182feb8ce702ef8f4b38acd281d94e618ba1fe9f782b0e81f1677d9142c61f8ba9d153f4119b2619751b4adca0455f27dd34d62680737f5480c4c97eeef5c38f37c7b89994382c35cc23fa911ac798beccdfccfd258dc7ae1778d44003330da771b10907ed9b055191169902c43915bad2e6bac38fa78baec7b7e214f8864c883214a419aae09c6fe049eeb954ab3d4bb0e2e0475d74f37c994dc9e4ce30b9b2c55a4c0beff32698641ecb15ee4bd3d4785513f6a8242d4c69d6c56c756071bc38ca4bd5760288f42d1133866125c7e3458ca8ad036f672688741d3e1252074cbdf08c05bf14b1efff540bf549e0ccd1660c28fbb08c5d434ba0cbac0a1c17206a26a8e266f28051ce80fc7e7898972b188832a316380d236a117550db3f749700415de5058ca65bb248786c668e3e514b01cf0c3c5d14d3a238aca4fe98a84798608a836770c6183d99e8ee233f5e00edda2c294ae5ddadf1191cc1f34942e11f9fefcc31240efaa6ad7a4f61f5c3c2d5c35eac418b8c7080da1c4af0233cb10a0b851f12e44f937861914740b46d6a3a98a4b9961ba39c6709ba1fb14e34e149856f52609e07aa867f62213149ab091ca52724ba8a120eed232b8e65f8d90aa517a77a3dc72b3c0bae66d655f2c71c6cb84aeaaaf607117455b1a0bb016810f804608003626e6182015077b317ce5be114170b2909cfba44ef8c626c9c6d993dc19a8bd23b125928ac390044de9cf0eab2ca3922da2539622f3a068fe49cccf5e42fb39db64c228b1f611269ac654ea6f8272489ff53dd2711526c209d6667f7472431dd992bbb4654bf7fdf7bcd6e304b276b9b4aa20cdca0a43024959c20beceba773c9820a6121fe26b7bf8ac67e7530591051f790be5f8e8a9670d89da721973c894c16c521f03a12bafa0688e01577b228da14c7e485d748f38f7b1ffc0b463729fc1911f59666af96977613edec814ee3345fbb1c5db4a4fa7a9df2ffcea36266fa4b8274d489347c85f3ca183227816ed00e5c525e873af678138f0d000febcf10af03ea6461e9ac74bb98e5711740a30cacaee36132934eced014f3d653b1ccdc3c2f0f4c447489dc8b9186b59bd8cc56faebcd42284a125497b3d25beb1b3505d7b9c05dd860ef90a76c771db676f3ad66f81d4495a3247f2811ad47a1f8ad8b30905da319cab956b7abbec564df8746e163a39f8704a36a0786b260d0e2c15695c1ce72f17563be5b8b4c5f7a7235c444d703eb7b3de92c463859f4f1cd78ae7389882d0bbae6381c0963a2c8257bb1ddcd0136adcdf5cae38e10ba72f141cb7be7c2ea4d388048f2c639e520feb16393ecd82f5666c00eabec7303310bf01172de690c366a6e7a4ebd758b775689f86bb5485028a9941535a304ec29a0eba960768b7ab6bd04ab9023b9dc204bf4150b15308b8fb766da3990025bcf339c46dde1c8f2b9b41d61d4375a4c200ed43c94ef93c4e2a6cdd22bab164f223c029945dd3906275374fd4965937215b6e29534a3205ef042805f4042cb3b1d0130b7db29a930caab6bd7a9daafac5e89e76fd27c3c9a1445f8c5aed97d57a88c6643932590d4726abc956b0ed603f104ca8f265b67ebd2895d96ad042c681cdc5a8ac5ec2628c87bd954c8a6359266aa38cd1a34b973fec480943416d178e5825ec0435d6a44b9942f4a49d627a0e10429d356c8722a0637ffa39689af5ff16c9a55ad016f1d1110bd1928c2cf1df30615ce082ba462420017352fa7afd82b04316d89ef6f6a78323fa41232320415bc43529341f4fca28e37cf96f0ffce5169c4ceee10271739ae0dc74b911f2431819c205e2c83032cbc85db7ad24388e939c7495b0662a3b8e48654e6f6db1293d458d5162a1a5a62a4c9ef7867eb0569b62eb245642aca47af5f4143566f5c442ab2816fa56b715d42acc8a86981afaad6c2bdbcac9575253700dd6e0181e6a5b952d3568834fd17d82bcaad437b818ac754f3f075ee8f60d98e4e486d73c0aedcc928f17759b4a62a19a133865c6acb6400018d00f42d85aea25dac028659c738534060aca391413b7077e27a8bc3f7bc319aaf17fea6e366cd86c6c738682d2a57bf428a56cae045c8b6081e04b1374ecfd81ef3e707092bb37320edc1f8fe14ac7996166602dd4c1f95aa81f6881a36127c628a3d4e0e36105bcf73eec3595554c72500395dd0b7bd227085655a759cbe8552c647404dd00990102583fcf6331d10f52412ac8c6f9068f714c972a36c2424a29b986707b985bfdc51354347e7c1677ec1863437974972e635c62ce1e275c4c921a5b146b2c6001b304ac082e2c50ff7accc7fe04a0488d2d8a5e34112390f941fe46f72f1fd9efac84c1cac17ad6831f61df8f042abbb73fb00785ca20c09fb05f10a0acbac73ee063d6fd3531327b1e006aa0be038cb0ae0c21c3d6f702f46d1cf7ae50b0fa59fe0ddb059234a48ccccccccccc2ca3f31be81ce7ec6a00ac134d3c01b70b2c4d0019053f3c695458f09b33a22368b405be36463d3043d785c38504fd5a19d8159cd00d6c4c052f68104a247821a17d83151da3224b141433a8f6e089aecb6504ddb7c15a70b0d0392711745d2e1bddaffdc0892245d7e51a82ee63202a68841c36bed0fda64d9b7a41220ad6ca3ea6555e3e32628f6529a01f1bf1111b2d0c52b15715049514cb032e745d2e26ca347884065e6890ec09259a7d41bfb5cd499b591e78a1eb7275a1fb523fd26c4195041757dcd8c0be49b4b1b2ae96122a5b19581e44a1f26d30944d188db9a02884b3a9c8719ce4a4c7588ec042eea34a67752bba94fc1c47d96c89790f7e1321a1dfec687facd06f6d397c8b565667c90f5b207e8f6174c9304ad8052aa43e5c53c8312a1c9cf3b5e3d28c142b98bafbcc864c0a28e3e89b4977fb897a68b6397ac8c6f6f0efd74285947e0b889a17748b38ca183dbae4d616c5f7fd993f398f8bf9b047a58b4949a58cf2bdaea35bc44f5c5c287c0650fa7afd7b3964506071e9527292f3d85541e72afcc8d2a3092acbb81e7cafdddd63f104ce73d2a29b2f5b28fb7a7900747eb5a10c21ad376884eeeefe157a7777bf972e5dba74bb5b76ec6ee619377737f30658689eafe666ee4908b4051db3dec142d0db333eec757bcd43c70ef6ba0b8ffd915104fdbcda3a884461a13d27a5afd556d6fecee491f954d6b3964829638cd13061f5f149587d8c2dee116b17430004623debc55eb3623cecf5372b0944e8e779449146fcad2ea39865dd3ef89bdfc5ccbbdf7a166ced43f8dc1046e968f1a4ecc2d162c10a8d5e013960b82f567c7105911aaf90c28aa51a778770ba308104cd69ef7c50bdcf64a9fdaf336d6aff4ad5ee2188c4e5073335a31b7c83b983dd0c0f83a89c24dcab40535d56dd6140c3e1afa76f56dfa91baac4e0e5a8cc0e6d24911c2f553e28a145298a891c0225a40a2420843946d0a08a7e3311563254c9b10066a8a8336afc199fbaa9b10a227272a041b5ea5c8844fd8cc1715c99a9a39ca5269d32688ce07c7c5aa6aa88ab2a278621ad9dd7138e1116169bcb8622aba3560e43ba1acb0a9189e568d58484f3c1a8eba2447631127c689a4242c20aa2a6aa1842c295a729354448c8b2341503dace6b89d63d3bcd0c39c25465a6091112988cf8b586467768782dcdb8d951c62833f081d2ba5f9838c3c522135535464e7ac1e1a8c6bd559d354274a8501c263a2aa03875bf8091a203d5a9fb05cc151580e1f284baea7e01b344064cd056dd2f60c8fc97db9268040b5656ce562701bee127612bc782ded06f5f04b0f2f7c2231b51a4f550176b312fe6b1177dac60b47be27c45ff78a6898b1512e9871abf8df010676bda22788649aaabdc7a4a543bb1f5122aa2355c889048b6fd719da9727bb251517db36a9b05d97ac8b5c4e5e4c93525ca55e5c624b5e58c8dca45fb66d5360b9a512af77c726ccdb3ea03b0b2c329f44537284245b0451c0d1a757f831561020bd42fb7889ddda1430eaac1637f68a071beb68869cec44210d47f7776bc6374e65a8ce503f58fd1a1140b50cab7f4883ad43fcef6879be36251ca8f3bdf7b519d1bfd6b8399cbb833fbb3f825c738209fbbd1ef39ee1c77e72674778ffe12eed7c3658c5344aaf06d4c1ff5129e62ae6aa336c24d3c9573d8a1d5c73dd47d2fb59f9b7a68157330b687d947962871543f1e8f6f7cc6dd18c009fa4527b53f3a61a18f972a13b7455c632d0231a3d1b6ea296a0c0958a87d00995ef70c800dfd96aa851e378fd15f3c42bf1eb38f0a5b5d2505c2163190d9cd2748fe745057c60e79ddd354d46fd7d4fe4fa8ea981e17933232344a673dfe1c0f883958ab1c0fc8b1822b10b688a5229b0eeae8d46d03050152183a8c2b43c870e132e33057172ca9f2d76b04cac4fd87cb84d9b50c64236676f723a054100b357c8aba4d3d45dda0c210d56f46349bcd66b3d90a3235f483361b740a62a16e4939992fbcd577942c08b9830b34b9ae38ef3858ac2bae5bfdaa9b93151b817b7ac5838dc5f2c2cbe1d1dda3cf085c4822ab55952dc6f7a6e733e347e7b808a3374bc971124ea4b6b1522b45dda65ae9eba6aed24c68ea37abb7af6b5d536ab5adc38861a18d1e63f46efd593afbc3efc1ef563bbfce0231b350618c2d0f7e531d0f38e4a84b2334f8781ea3d39fb5d6e3a73fb39143070bcd08f3f5b8557dbaf77085976a18b38ad23400466867b10253bb71cf2385a3252bb051a10a1a19e1dcfb018525faed8d689fe091020a4423904c5483b9e56702e91c510da21a4435b626c56ae95246199db9e17250c67c1569384a19b955f7d0f31c5fd00821e4f6f6d8cc62c9282778dc9d8ac7aecabfebf1afc7421c3c4f5d16d2934ae973e4ab8810461c8f45256a7f74444b32b2e496438326fa412323205ff3f13c46ff800faed52d68499732cae8b345b570d116a60b0704d3c5d3bdfbce1582cadf10f6a8ecabeff759b59c89e81ee7b3628ccc1e29fd246d6483cff019a662a18fab180db3e1a60db0d763847e2cc5523ce56dc49061b132847cc41f0a6ae458571637dce82e6b9b1d1e73ee60ef032a4c3a2da874c778631d98d1243417023ed70863f4e89099ab4b45c668f73057d7c5c31eef53c961a505aac760b1e48747441532a96728b3c1b19dd131909225334320c8524ae66676ba72d9730daac77ac4246696c1ef497b366df5d3c89a25f8a8fdeefce6618d6f06df659c5cdcee7e81830d036bb2d0c7fdc63e66c8c19c9d9d9d5d46f7f61c58dcbbbb3d2264d93d1d638c13896500281af7e5c3e52407e4fbdf683fc7391786c1d240080a7737f62f8017d8065c719268d21554e8b29061b5785af85f4a052929a3a6b29385b6ea4205198244901fb6b9bb0cfbbcba905bf6bac7637428fccfed71b09ff399bd4c99c25f5890b7c53bcce3b32177b9b59cc2d486bc69411627cc3cb9c1452a3fdda232bf6c282e191919f130d43c3e4135eab74e61766ad12c9b75032580fac12ab57fe196a0fa41272818664c6d3885864d6de8068853fdd88898faf11227eac74ea6d4a81f5761e22db59d188ac37041ab41b57f522e9c6affab8b26b5ffbb4853fbbd599593da4f54d5a6f6db88c197da9f4387174d6a3f0f15bc58aafd1b88a1f6b740822f90187d41e6c88d0e34375a24d5c040525a0203872630d8d89c9ea2c2a8ba4925b15fde88a9fdb0aa072323314757683fda24c190446d8a520c6e969a9a6a3fdb160a8813940c4e6ead96ad2e172852f5eb6ed95a43540ef453cbe9066c39d575e160d84df97c716154a64b1b281bb40122892edcc8f795ce4205a85129070c7d99b3b13d1ba99723319bf18c6594326600069b2d4f663cd36172e3a1c80d882046d567f68ac2c25ad9a7b3348d7632640155d18f917a88f541ed67da166df7bbabf76fc1e0514323031441f93f3ee2261eb25dece31d621f43a9a1369297aef6a4abd8475f1f7cf200baf981872ca9d9e10c14a91a6e8cd4dcb43fcd46b0cab585c2ff6095ce9215ff62529551f7a3d1166d4739ff84ee67cc851e76f4cf7781bf8b27b8d03f63375cf0bac7bf7b1766dde33f1f7eb3e7f5108d1db1a5b1637eff8ccdee81557f1faffe3c56e0211e5a109b25d5dfc9fd39195fe6fc4e158486afc7684480bf633e7af0f7d1cfaf1dabe7e7980ffe558cee6b670ffdbc017d88b59302f7c4f77a8815dba9eb10ba4b97ee4b2c34b75b029368af14d88bb78fde7804a5a132e965ad87f89b047372d58475c044bf176b86d4972dc6dc966a844d3542a7c9097daf14e2abc0429e26d6f8df43fdf1a58d0323030b1832aa509ac512c59962e7294a46923543c8385ab3b446c9c682b1e76566b8ddddceb0ee6eeeeee62582993dc6e8edeece0cabdbdd8aae12be7280df67c702c891dbdd63c710ea0160b0d3396297583175bfceb950090abf5b9dbac1eca10780fd37d7e97c0fed8d7dda2869637ff8d76603c7cae4dc6547f7e8eeee4210c20819026d4308bb074777778f9ebb7b373919bf17ea42a0fd5983500a84522094e2d1a394125d4a81508afc95fe90ebc8c98e5c6c22471e3d4a29d1a5148feed16cb4e852ac40111672d7918b524a29b919a10890adbc66d0624038c434d8c3af040af57f8ce53583c6801fd3daf6b2616bd1edbacf40f1595d0745e80a93d885c3634c8b81722eff8ea5ffe45e1028ce8898c6b48e9569fbc3efd2c66bc662af014c81b00585248543afeee18fabfb7145d881406c6bd16c345a123b415a20fe2a532acfb03fbc43a3ad3a9801164474e65ece1138e8300dfe8ce88aa90c98c6ab8747472ca93913322d55b7c3533b59ed7c6a57bfa0dafd22d5ce4bedbaa7b7dafd2b4d0eb5fb4fa3a676efa9f9a1763fa31a52bb9f2e1c1dd19c5c111c27ab9cab7e3e952ba2721c1640540e0b302a876688ca6501e48a2eb8dde8015054a42affd6a0a89c994b628830dc99b441051e4550a2b93fec85aac00347c8adc6e589886633f87ac1dda53250e8d1dd3d762c7963bbb7d0f2b8bb7764d9eaeeee5e085bddddddf37ba1e244a192713ad775773bd5f081ddc1acdb7b3e146015e8cabd8ed705aa731042d83b7c822c6445d97fe7d1238f1dec31cfabe5ea1d4a77e868b1375b6e20b7c7990e0b4634e5be3e7b458d4d6a1360bdf82c69c2026af733961fd47842edd81280025c0ca24072ad6ed6d60a419f997744bbd58a1565ff1debe716753c5de4b589785e2d57ef50eac209e21e9ecd3a46570938adb945ddec98556539c9ecdc3326632e1cdcccccdeb284e5584e2073dc2e17f61f59724aaeb9c9b383dd5cf9b3d0ce9db3cbc3f9afd9eb5f0f458507a818398421d3218a0e69aaff0c287260dac085c35b709312c59418aaff6bca98eaff72e1f07777e979abbabbbb03004a69125f468c6ab4d09da2014409e2449431fe19bc7b0d5b6c41630c004a923050caa011801351103de9010a1c8454c741071cdcd49ea069a6101354ddc9069a0d553734e184290547aaff8c484a75a814b8c959410d567880c324c6938caa23511d2a0989ea3548a9fe2e170e8f31c6b864886cd174e3c2cc953137620d3562b154638c31c62825c2c7535d56dda7facfa045f533504ba06002447528266daa43351153a168e0a1e604c1c48e92284cb099a14bf55fadd1d910907e80528254fde98b4c08f5dba1814132aa9e6385c683575d05323740d5e713266114f9a2054b52d59b956f51fd766afc36112a09971ae3bf604318a5355982148962ca0da7812a890ef41bd0a19028ad0b9a60497164861f5bf57f7df9160c1c809974e6701c57436a9dc1b9c2dae9f3ca8d7bd6015728114d565a945a459e50d231d95845ac489a586aab1f50b82c525d141a240b96e60f4d225315a74412df79311d750f9923ed002c51110b24bcf3caa2d43d3ba18cc4e0880f35a823418e38c08728fafa9d2c2ff85ab3441052a0c9e00a4a4388113446dd2f64a2d4efb520c33403192f65a8a84235a8fb854cd5ceeb83ba5fa64062a4fb19a76b0ced7ebe8cd0cf8b2fdba3356a7cefdce5ac154972d9bd0d8e1911ab7b2cd41e7b3e6c226b29420d41431352bf8de2a4a0882831bb60d0a8caffaeeb3ad7b3bc05e30b600c853c5e6cfd36ab8b7d3d560fbf83c918fc0ed6170bb986a8eb7b55d7efba5cadd83759b1af475cb92000eb629ffb204016b40755e7d4d4dd833dff30dce31d05bdca1f0707fab5a89a7aa893ba878985e0df6e51514f4f365b53d30cf796aaee1d55ddbda95c89c7dfe8b97b17a91a942caa6c579ee062a4090c4abcb822c90c9124649808d105cd90b894113414a698fa8206c5140bdcc825475574fc080a8bb64112499e4c11c2840aa6663842a245d055a8dd8af871a44d112d5249182f3c49424452153b60614510242ea6e73c45e8f79aecb6b601221172c311f2551323429e9670d412c30b162243985b91a5a8224c34215626ed322d90c2889a268c9c18934488137777774e729cc338c903039d81850cc960d5a45fb84149073260806881a484a4fabffcd185bb03e068d64393bbaf9851c39921b298b2c3174ef248999d85e213cc50fd3873268b911c8c6c1341c050115c86cacc4cae5853a58d151954ac6862470d9b17c4d0924514394eaca96d704333840c28aa2c1c9c49b385979cb9bbbb5c5ca9fb414423e8d8ddf78dcd9ea2709f27e5270ed7b93f32f3ee72961947ec10216bc611d421ec8405bc79f3e6cd8df92c87edee98b11add1d3ae52186bb3b4308934120d83caea4394a01a0a83f74ee5dfe748f2fe194d1a57cc6da999a626f91a8a08a51351082b6bbfbb7ddcd42372d004cd0ee9e5272dc199dc6199595f3b17fdc814010b6fe31b6fb43bd6342f159cc321669651b0299a6a894adba8cd4b1d100080053160000200c0685c30181409aa88134b60f1400115a80427c5a3619c763418cc3300aa218800108310611638c210421a610111e75f981451cc4099e59853b1abc58b45cf63d339aa5ea852ad448e43b8d6ed186b1fcad85e08d4dc5bbce427949c70002f11a255ae68914ba7c3e195f9bf7713de11ff974e5b4aa45c4b0d742cde91c86af6e818ea30e1e0105a389695b35c2f47d4c320cbb6e11d47249fe4da06793aaa541913fe04275cf05aac4990925861d1ba5817496f05eec82382fbea1692cc07684f445f4769204b913224b130ebbe6fd88b3a36554e05abce84a227498981d6f7bce573538d3b2b4b7fc39daf2f31e36465fd36bb4b077891c9d3696f994f7feb8a30f360faeba432c88ea02d4d5acf13be068a4f5a3ffa7ea1ceddb8e8ddbdba96dd4ef38ccbd61e0db4b744e47301536eacf31809087c7c7ac3482a2864177cf5cbad1c60e5a240cd468c8eae9ea7bab3b2fe0fc582632256b77ca82640d5ad555256a263e563f429837b983818dc07625ded0d0941b05f30cec1d458387dfff9dd1706b3db848c808d5d6facbd9cbfe57c4ed0ba9e4830d9456c57006b3ba51557e21eee864424c556588aea1408f35cee3f454b64fa02933cf4ac925e659660e0d4c81075afb1649d7aa2fe1a0e1c567b1c9e59433d9712cf57180c07acd480716770579a2a98d08c8427356e833b4e13b3d0bfb9e0878d40ce9a3363cc574771c48f2b577150ea0eb163dcb7aa6f83fe9da45ae50a97344fc637bb2c64f44a88228c09f16d2e5a7cb666e5d0ee92b3972dc816a9ed0d64eb030d79e0d4c7bd7e858233240a6a8611f71b2616c019101e257ed917a9b2a90e7c519138a75dda7204026002489cd8755b41a1e7c4e8d12c32f236a8668607d15c24165bc138ab1b941768a95c278eb8fdb0d2db215060229717a70a510a8d8b0d5f4822547d6f0952755fd2c276c1b8d5e1040e0f22c0c98be1ce58a3568145d4edbe110902736584fa6c2788dc5a7c25d50caf419dcd1630f4c52e5f949006f5a024cf17e10dca9f6e6f11f46f83aa138a5316b97926e29d3c5531e18f24a47d84d80de4972a1263675da5cd44269cd7936a1acc6bf8be0d6fcd52bda276df08cec518190fd0e2f7eb50f52bd2341dd79a49745d363bb48709a2dcbdc3d9c0317dbea3b988a57805965587fa39e69a2a54638aaec8dc6dc5d81ed50506a339591a05469f6a406f11fc2e226442cf40a9a34a7d0d992f84688bc22a48c49f173729315410efdda53fc1c7fad457bb68ced758f476cf9c8f0fcf45aa19f072855185d082536569194e649a977724cdbe043914e4b8b45170737758dd37276ffd5dc8831cb335bf18adb887a9f61c22e1734849175eaeca4af8f5c8fc88af74038f33c73ac0d4042ef1086bbc71472c5c31f4476dd1b2a187529ed1d1cba7d8dcea83d3bf677bbe38cccc51c4b27ae6083e5725e9518662ef028dfbf4c37e1037c2b3ba93f64804e9168648df62eff1380b6351943cec710d0fdaab2af7bffc90acf089f35ffc8b85dd105199fc41cd858bf70d42a59ccde8f8f0b63bb8619aba054aacb9b4e4518caf7c9770b153328253a678ca865967a7c476b33a709efa1b164fa7efcf311f2db0f1f204c2c9440314b59ed90d9631aa0652b1c4ab64c39e1e0fa4e38d7f76a38276050d03a7cf4fa5826f5a923c3ab467b802958e7fc4d5e38e95b05558f69d827c39a478e6b03a077d1b2eb9979f3dd9fd30b2444530285bb4ad38ab82171d7dcc93bef6cfa8580eabd88ee415d9f58f4627b65ee0021c3b248079c03fc7286362690c06c15416a2ac09b76ee1c698640a61de511e008b507c46a6714d49d10332053bedda1bcc3fa62f164cef3bc216fdc8efac20de86015c76635e99138cfa8f589db0801c03e9c57b23fc89a285534b1a2469299c444403f91d1c5cb9579541e3efb095e17e66a60eae48234026748504c8db4aae81d67f2551eaf13fd74e4d74d0c7c3ec5dce658ad8407451a0059f6cf74ef51c14ca9d877eb2456c90e9a9759d43ac304a94e99f5efe2535d10a0fee3fc80230575834b6c0a98070198fd8bd01a05caf52d202d460c2f5e25f5dbbf81db81b41b48989761686d61630b07403e834717730ac41e172c737d89611a246cdf8dd4c33f87ce8266e2864cc10c5b4de0a2863e3b76e85ff222dfb040f3c8ba3b1986905da0c23eabf28c81ee0065f65244e49bfcd26959f1aa4e569d01b5e1ae0d9c9c2b0edffa4f495784efceb80d385e225b8f4f507a4655c7b0141445eda3c30ec6edbd1cc74532083534509899f52fe055651c730affbd0d85f9c5784ed05374bea2d282bd9ea85e1b42b76453cfb614b05ee9e86ae0b2f2b1efe15bfb4c18aa592236551199db4be3dee0af527949e2eb0131ae11bca465bcb41aa3f41f78b5aeda853599f5ab2c3291ad62fff4deaa1f3af478acb08c782d9c5770e2ea736c38094f91a2affd6936035f610afc8bfdb19b40163740ec8d5702111f5072393c1422d3f64f15e94bbc3dd0a884126e387d840848658b88d888d638bfc7442a65c97499dc7dec2dce11cce1e59be47b1f820c646d63aab4b12069d535b4da24d19eaa37722b8de0abc682798722890ebf4b8d51a9644d96bc584c5e641ef0490e1c1b84d378fdd3467356e41703a7c86c24959318906f6054f3910cb314f849c4ae883832e27886e0c3f7c137ce17c7dced7abbc4a674ce30f3d85e13bd62d8dd454cedaeb913cbe52627179f15afe721df9bad493525d534eff6f77ad0abd94a6b9742e63cdbd9ef316fcd36a9e94b74ca0f67f64467e3802f7cfdc4faf38406603b52529d4da944bb06f073ce9d3c1e9f9067836930af7aec69a266e48f3d3686d08a723efce7ddb80201a3125018fe9ceb279c1361d934a1de105e4b0742accf77725c8ef9c4b8672679e65919db6132394173a90885f875d60a8660c3d8b828569c74ba5609d13de1535b61d07d63d857dd7c2438bab92ffa50ecc7d12cddd791c9726e3b30ce2d191a7ea1c31d0648acac0d2d4d857b6a59aa6422147e35f1b2cf84bd2448bc00cb04455df09b550e25cb8475bd98cfafc854e16b148f10a4a44e1a55269995d4ffb12830be03a5536249404e3518a3542185986e03652eea3782619286e289131fd2436883251a14983c4062327e3ca09e60f27d1b3c84f11e61095081bd004a4168d841afc68b6444ba650f12ceb9d84a33af744475d6b907c5e915bce9b8f5abc0ca5c525e42155ce819363340a6accc5bee1b5d11d3a25d3362d7466b1b9944987460ebb8f0143a64feedda734da26c489ea5e7ec780af0fd58bf47bf012127482ca3b7d1c75545d6a4e9780449cb20d9e66b83e6c14b5853d013c2037c34e0e6125777e3a88a23eb26d3d3a8bb0db7d8ec59d43244af996622793c64e62ab7cd90d6ac807c88318f45de408cd494d899fecc69f660f460cdb44a62a7e44d7968e0593f9330802875c707f64d8e3497484d47ebee8e91a4cc776b186f9e27c8dcb47e33040279e5af69de092c7778f74e3ecba87efc7e3fcafe4c0c94eb844f80408e712fd674128167b0b5812586c63f9e617115eb031a3b4b6700e1bcf51324f13319a6465fb05b80c43cadd31130c5c8f3f38bc21e290bd54b3eca42ca8b6be342ca2a621a84802251682603745bb441bd04068ac426dfc2cf4ef27b2712f1fc457acaacfb9d25a9bc307e00479d6522443d9a0ccdfe77de3d592f219f5e0ab250b1f2d2e4dc25cb6b3eaa80d784666a3ffdf25839ac4037b7e85852087052deacca052d172e7cc908b63ea598ce53b59623927fa301738c00344c5091287753d2eb64ae62ff8ff550b07e4077367b38e29174c8ce525aa3af7937a01dd80dc033c932fd08cfe742ce8151598c0c1af34a73acc849bfc52fdb6b4104e025a0eb65785037134e6c51e5a51e2ce1ac1a2466cde452c265b9d1f4b0db1820dbb2a34b9d6cb2f12b6d7d7fa998fad2ef4ac68965e8c83fc360f1029061ba7b6506983721c8369cbb8035f2f1c86cda0cb14ddec29a01483753ae08b794256681feeb0a135435f863119a10397cf05834e13d18b3f1c9ce8d94db88dad8c762c9a494dcb7c9fa5874ecefe543c9202115019450c1ebc4e76db369b05b5028b7e698b693e0ef566bad97c11bb6ba14dd80f8918a9327377419c488aa19dfe2a5c89674897b8b3258e3969d14b6bad1dd7620cd42ce80a6188bb45c8dd60cac486f2e5737ce8e38af5cda6c1dbec26a71507cb771e4188334b4d68f5d5ee7b9e67e06c5febb4bb0102ca4fb3e0ded265effaa11ca98a04e1475ffac3ced828dede66d4235d87d6919ffe3b14ef843fe19f30e76d51de9e9cedd62bf0afd67e7177f4c98afac30818f1a2c774ec4a9ff53005300a349a3a91d63e42ec536526f8e05f2a97c6b1380c28facdf340c56d192c84973226df012e8606225a8bc202841ea9748403d4c3b462b1c6d97019542f56c330846f0e1e487e01c4c1f640c714701960ab9ee01330bf9a2009603b9ee00330079a201cb86dcee00330179a200cb875c1ffc4c1d494a4a01ebaaab848263b5201d4f5d047d834e516de3008c4d60d0dc47f77d10601340caa50c03c7b202ee7571d49a8a2cb8bd8c02ab44f263e6b0ea5105c22be2dd517b377b407928aac396a784a1ec1765ec3dbdd8fa29d2da63ce798ec5fd2318c72c2c75d320a21854ed9efa53b930ebf64ad43e3b8f115ed583c107ff9cbc040b4ab192011cf3c0b1dc8ea6a3c32e1480c0848dd796e03007ef87045a80cac00cf8d633de764a854c411067bab5672d20c17fbc25a696435ddd03c404ce85af4ccd671115245942e57c48c7f9f5029ce8d614e19ee30ef6c757d34134ceb2952d64e4375c85eb71ebc9931c262aed672e59256b351e9536425091a636bbeb752f628d1be5b2958bbb08e78041684094721104b65b78592a96062931be31fdedabfe07c042d13aed36769d3c1a0626eb0e573b686a8134f42e503b1d82bf53f0876218020204d070af3c0e3640b080a7382d857c0247bef6fc3801cacb8ae8caf6cd1ca071cc1b25f6c27116601ec6446a5298fe59693b2078d6087e9667a40aa3a25d83464ae43edb28a93470a220e23452e4d934cbdb7a8c6df92e8accad5608377ca67212d2d7ebdacd3a6fb1023d5064dbf1094f062aaeb75e881125a76460480f726314466f118ac45a0d6da91fa8ca971c31a6624ee5e207154cdfc590ad6ee1eaae212dd1cea777d037c3087445b1832f1a121c0d04f0c1f496aa45aafdd6770b87cab1c9086836df0ab03a16e98d7b375e21a4bf7f41d187e6aaaabb96c16d32bace6bbaca20a2d935b1fb30e78a502be0c1ce11962eaf4a25ecb4c191c1c2c7c8e7a1c2e9a5d0b533b498ccab83d8355c4cdfd5379d7159638bfd57ffea1c8e2fe900815ffc20c8a134bae1b1a3693c5bd03f65884df1d89fda934c62b054d4f68a0c145b2ea890662da436171353d8efa49d0797dd8106c354cc991537bbee0319429d95f3f134719336b4ca47e3d44d8373a50a37f300c6ddf2ef527338f014856dcbc830da4db524d05f3c0ef25ec0b7a964d204eb4f604adc8936e1b0bf8d4658c230ff9b2acd642cd0dc79b68f28045ce8fca2f36d2465d387ca34ff590bb52877fc39348c68a24327990333d00de74b3b4834a69dad1e74d7dd2024f9df8084bfb914d3808efdb4bafb2900021a24388b5c45335c459083f419b9797945430dd6129aaf6add04d5c65327dd24f995e2d22a4864178fd4ed136102aebcda6201a59140caad4812c5578555fe34ba5fdd1a59ea3605b907818bedcb94c69c3ba3bec41d54b29e58c155d5073ffccad80be7c09f2d755090c9c93ebb35cbe5017ac2944a5fd3171b62049a65c2a4dd0d91dc8e6fbefe6447b8f78642c7b9955bc2887a847ea23002e1a80767d60c8bcf45a4d004e6287b840aeb68b78cf51d605dc457891bf771f06d6d7f3d584dac98eb5ddb96c7f5f4d1256282a06d39656babe588295d8b122d578c967e0402c01efed26edc358b26944fac9590f06884ea4e9c3c3a4d770167b6999997f2fcc43d6befcc8aa291a24149dfea17bd7a3c491f68e38364d8a6c9d0e8b7f63adb628dae65198169af833885efdac645dc8ef66466e207d829811e0416ca8efa86bb28539354dfe003f3e93bee09f41c4c8976167cd4b854467daf6fad627ea7b5583121465f75ec7550100b8d8039a52802029791997da738c4b1812ae82020b39cde02b4de26dd501669b5332c80d0e9279721635eb8f50a462e5b2b9f110eb817dec4caae4f766eaac3a08ebd69d09fd46515735f7e417ddcd9ba73982da2064f415aa5071235185edeb068195153613f1cb5c4c7a7b261743de29c9c965c342d2068c637122808079a1d7c70e02f7ba49e61d12289c8d1a5b86254c4b527ff3862cdc980f5d907c520400872b1025e75a68a09ae19235037542d228b68175095932394a860cf01cb234cda77573284e3027957a7d349281601a5b5d5534997f1e074a93b6c110726c5febac236adbf276a37f63e8a52d9f4783928c3dc67f2c0ca9ce4c31c14d45052ca385d89f3fb11d004e965ea7a4ac701d93b08ed24c967a304a0be021e49aa18d905790c8dc9bcfb9556380e326bc18f4fc1982d10872f882da106c97a71d993b9f5413031fc4e9f02b78d53461591845c92ce421e44653c0b27613b236f4c0a0a8455f83ab3a75f16a04860bb2255618c91c46725d6dcd0b4b60a6599c0a6fd5382f407b77f0037bc453286451d5bf8948218886368534c79b702c1df12ed6e6862d1516c2e6f946da95377e48d8ba544859137b0ffd7065379c02d75f306054ae98ef0b92a750b69ebf93583b2338f932ac7e3cef4518d64d3509500a8c9ee28dcff756bc28a47280984548b5a1400bdd60f1a1d66b0e3572f4bacfd56fd96db9d6489361d121f1e855a757bae50ced7ae99c1257bc02c7911058d46f6ed96db717229d88e3bfef92133f9f9888cff350b75bad2ff5a4bab88e478c3bfa602122667fbd7742bf5197ff5037b5f5b1c9bd9ebd5cbbec6807c289f87c994cd82ffe4dbfadd964095eceb16bb41780f40bffb7b6dd0ccbdb6fcf6b58718b4d7f474ae47ff7085cdb4c2254abbb6364148d741dd63692e3ec146dfcde511f429ed8dbfa93a784188a1c02783dfb2484614c694ca7b0b25c1995301f150f5fb84f9c3c09e3c3a9ed63ed9a6e2769702f9d0e8da2e524dae876ee7e2cb039b3951ae09fce6875af9456ba3c8ea216fe0cd3b822d7b653548962b62e06cd1cdee2ae62531cd3b60843389eeb1589493e3c550b16bca43931d74bc824234ad2d07ade83966d1aef427f2f4a9faaff326d146e9b1fc9c7145e8bdfcc6b81e9e6b94a247ae824e3cf8bebc58039f3f1af242ef8fcccb3dbe75212028c4d30b03764da7408e2047b499de9b1f625acefc89649387210dd8aa96813e19513d43ef3f2f4ea8972d40d8139cbd34c716c607a356f08ffee08d2d907f78d26ea5916c69d04558b58cc6663464e5b4a8cbeae22b05e8c81c486d43f896eb1762e11e0eb0799bd62687f11e98fa68d616c11f0ad69f3bd8d7f10bfefbc153f64c6a6f9548e11472e650649b6aa8ca437cb9b76f27d7e0f6df561db11661899c287b6429dd35393915d92bd7059a730dcca0e16948f6b6cc06f4fcea32653e88b7f7ba14732ebde082a8e02c8b0496cc7a7c9f1d4dc12c9b0a6c793e1a124eba4990ea63f2e6c121891ada1c7c455fa1ec2f02622761b8747d412619851af567c91a43333616e01165bc9b0e9751ea4f36fe264cddf296328491f8ea382c09523402b5e318d2af8aed68206627a580dc6e5d04f54df6cf17a75223612960cb0efb39c80b72e5557014b9e6a37a02ce8c05e6d79d97faa540c83e1c7c1d52296cc263b5ee75f4a76724da7926c6560ebcde61216407e5af14787523254581d358957448f9406a555fac9d1f4b99ade2eb7931982eb0ab852a13063b7efcb76cfbdea452ded11bd3617950736fef05e684c6e7ddb0a395c0db80c5a8e2b568c49d3af847bbc88fb2a2a38996e55662b487679ef49ff54effc6a1012173f3d0444bba24317c7f7bab2e6a097c3fef689bea75bc268e62328ff2824f4ae3bbd15f5cf3ae7e34f651494dd6bbaae6b0337b93046161b7c2f4a6085793c9e7536d40575b5cdc7e1f7a65acf408c46f9e89f26f35540616d01b10f5d90427a2e8631a90f5f3a7dc7a354fdb7b0a85a74adbc820ea9e33e208de2495260b46f82cbc82aa8de9d0c600a5618e9e51cee8ada6f20f8939f00ff27627fbbb17cdf5b15f16bdf976125a64be5beafa46542a091598c9171fa9a6b0ad37839c51efb1d49c929f81498c2a9706fff988c15c134c918031d48763a399dcbdc8433e1c029ac3bc45495a6dab10211fe59bcd3411a50a46d0de5d1f435a99f2ced0b7091ba29a9fbe45a0c2c4ad6e3d70ba88fd841c6fe904eae6c81938817c139970d1a2d9c3d2e9d42eea1695e5c207b1adf58167f6aa5987d01d81c0239ad6ecfea5993ae24efd35830a598c44ee5f662e47688cc1d21ac241b75d1521786d3a1c376ebb7a04f2c5253017a93815a808cf0424bc837c4a975b30d12d51a611045e1d61d26f2afb4625f42786f5bcbfd4fc58d24db78fa869452c42c909a5ade3958b44406e057cf90ff49bde70be3808f5dcf0db25907ac7d5dbd001740736cd7eec35075cef64f439493c77141e08422df8abaa94726316f058cd4979cde96ae3d980e2e697ae2ab27ffd8bcc3850643cad181e35ee5691b1e50e751e0802fc60c122e50cb46ae1869683e1f3e60a885c4a54ececd9083e21901a938f5042692addfd3799d1834601b72a5729b7f620fcd86680c7bbad7c7115a2099f71a47a8db0f2b9482fdfdc0d3d6a44f64773e033e3f6369f8deae10b41a8715b4a6f9453a6d3db64021d1e617f9e173e1c6e95b6f5fd54bcfd1fcbcc02364e91e242f8fcd335d803d20a1d3db535133a83b2302bd8b44dfcb7ef3354204c2bc5dbccd05cba0189251ae8e84762e61e0d3956b45e51d39085ae63917f9e5fe8836f81f512741314acfa766cf21d51beba4fa1630501479c65debce709abf50c81eeee2de4e00605a071769805b8e2581be09cf840703386efe89c8cbb7bcfe3699304002395cad2e9de66df84a02b26980d82666c0dd5457a8cccc4c28ab88ff0ec9ad6b3c963ed1d6135c2774db0cd861775222c1e5b44a40c64151bcdfd971df05b7e2441555a0b9a09119cb3061bf34eb724b58b4d522ca5422ff0b55520011474362f542ba65d4e365641400b47dec7e6ac363d966c6a7de1f7204d271e0535624d3f16d9b2ba8dba218a4232d295add17b45c2723d09cef6e3225019e8bee4bbd642d04cdacc81a60ac47e0d95db8f6a66618c8e4a06ce4c84d57c137de5884fa322e0e2ab6471bf39ec2b22d8d2a81959d9000597fb16c212ae2603d7412cfd039fa7ccfc7d9207c8f5039b234842792736618e66a0b09115c0926fa09ccf063bd05e896cd55eb8f9b2ba5bd961549300c24dd6285e29aa8d2164a73bbc6c041938957bf72560dfd77150eda4934cd9130b386eb44af3b3882a8ec4a8ae013dac03e9184e3c6c851c4722d3a4833518487233c6eaa01913439f603d5f626568cb5606aa079fbfaa3f8588b7890a772ccd012382db3a221060d81850fc4bbba807a47158f4951dd4590e8b3c4a4d8fe77d84f60ed822eae635ccc83a3dc0936d23dc68ee4aa0902dbdbf80d3cb08c549b208c29f9239d4e5807b989527c1f51b135ae941a5e144d6b4392e166cbd5bac7c4227e0254a7af79afc433089d57cfc1bef8f56b403dcc28d6b0c0d56a044ee6aed730faecee0c115524e1e2cf322980b72cdf5155c56627f9dd3d1e3052125f24e6ca2238b4cb668ae82d2909c1d043c72bfbe1dc1844a7fadb9fa2fcea3aa9b47784d460e1f411ee95dfa73f617c243e45e3d8e0d1719b13220394c806aedcd384c9d3f80f1218cf1bd52435e6be0b90e3d83510b736a38edb42ef89847df99bcec8e9849fd67251b6e66680ff0b4bce3aabfa529a7055e111aad5ed7f4aa1dc1b71415e77422f4468310f2864af8bd2a8b35545165d0c44304d9ea5ed0724015df0e00525546180598e2c30020bb79199a933da29e5737303187d47528ad76e9b577ed13f0611c159e30d2bed0fd8dc9f91a0f00853856da62330ddc45c01969f6df14b1762df0ec2980a0c2ab118de0f9673f9d28031d6f4a6d2ba16344a613820e93d132c1ecaed26f3c6229f518326d34051349789ee8d028ef66806037044ecd28c2aaa0b142cc1dd48a0a2cb9ff22f881dda73b10c89e7c9a2b6fe567412549529e6af19e641b6e3556d5d964d7d6aaf6bc843a179b34b2424619e16372d31a0b2e0f486c1a23431397ac20c02f11ef5ed468ef12f16e4ba92b99bf28e029953e19c7864cc90835d0b802a5e1261d0fe15c7a3a683f50bec72cd9ee4c3a5970acdb09194f4e3a912116167f1404d833944247b44ed863d3d6c7988b4158c68fb68db87774de1bf6d4cd0335ed5a64d005ea40c8c829afa8214251806b023b4863466c980c7d4e664f802c0a53badeea3777278054933b51a2d070bdd93f4d1ca9801cfddbf402efde3de6de175c6f06fe41d28659588a3c4ced994dde075f0d36bbe8e9f681a1a8c8c21240c10201ce052a87c488c0ba552015d5de33f4dca4db4a7a636a5a667a380afab98b0092e4dee52f8e9148a9bef873b704b98ee09463ed5ea52e46f40ca9a7e475a974a7b690cc08d081bed99d0a715f1f5d7b50604d1d420e2433e7ea15647d5d623d6eb194094517a0d056f9c9067f591c5eee5fa0295ef8b8680a6d77fb5cb3284d2e669eedb3aa105ffad86b10c3c0bc8c6e6e06d11f6ecd1752468d6fa16214c8480e746183413e62feff402bf6e443f6ff3825294a9b35acef54e7fee1c7bc07d9c881a585dcc4da53f19805d260f4160f99665645d7c892944ad25039f53c90e4b982308099cfe4831ce4e0e8468c1406c3dacecef79cf994d712846162eb75d1b548907c9ee5f57be83ab39dd022a9904da689e75be7fb080a50ff750c0d5771d9a5a8a993fcd60102c49edb87c3576fc89310213de499606a181e1e9b4da6d923768713e93a0d6efdab3fee982240b710a8e3c89c944d0ee1b06e6f332947d9f442a2571d5a743d9e336b21ebbec5b40619adc2be20cca99aeb468cd31033334c1a47f70e54c54d0ca507300b6fa4ea5db36048d6934325da8947bb6563874e2fe2948cde05c3f9281bb006df167caf6a3a4f576f336528639c35f40d3e5be9d869689723e740095ab0effe6a1799e958a523daf33aeaed05a22acc73629986e5d13546675d93477fa33e14afb5c2599b54c4550e1d57fdd4792a8f5a1da5a249ea8a501b02413d346c17a44827bfbbace15b1d3707152fcbb606abc597b58da4ba948b088ca6dee3c1114cf151ba8582b50483f712dd1ac0de2fce2262f9d984a212e85ecd47d5d5f6012eddccd304ad77315d1b3d588e81a453ae7b9e1056955f78174d7777a3cd366b68533dffc82b29faa47b11e25c787799c46c666b7c0135c80793582e48bce66cdbd8a53a349bf0ae21c789c74066838d3b1267fb6fcf3c0b14bfbbc5220f3cc078779f7140e6729a6662ceed2edba89b24d4fd944e8a47115ccdf54e593b12e5bb4114cbf1df2e4ca41b5d795f9c8aaa408975f60ad4a91b0313bc41e5cabb2d4d46f3be5c6b3e8faeba6b648cd2dd47a8dba1d7b0e61c08c7705fc8d9a6bf4a58de53294fa90276c2e43808321badbaa0b74970e9231cfc1f359c165dfa37684abcbc21c2c2488d14403c54b93b0d35b5eb7596db900e4f3f74b4e9135980ef0b4454edd9ae689c9580afa39861a2fd24870c6c78da2fbee4e7af6d19f35b0d78e0ebe8b3343c0d5f935a36a227a9fe4589891af39646bd1ac3a85c84baf8515fb8b54ae2e2c4dbfa136cb9e55f6075d4fa5e3203f59d0b66eeb5530425249a8e8dd288dcf3c60020bbb4b11629e441b8c458ad606e207df425a0fc312716b11b67def82ba818d37dbf4b874a07aa6c39c483ed8b29cc80487032b9214cbb9892479f7936e6d67ce79816487cd1ee3c8d2d542072ce03711fce740454cd01b2fa3a302a62bc2898b455e0796aa88ab271e8ebea74fc84f2710518e0391a922917bee05aa89649d7f30bb1a470a5a6290ad0810428d90fc2bd647e65e6004b6a1ec009b895bb1a418814ee3ea1db5b2bc36d9ad281320252a2388bb2724a9afc22867c7d8cacddeb200511bcd8e997b4a9600c4706737763b858813b5cfa885b3ca891fb4123c46abaae3eb59d65e58b607f60b785a351b8854b0fdb945cf627f9be28a897b136428c5dc7740778c7d3a570f64ec8c360d13ad42e489df6184e4c24c1fd68584d92ee6b04e789678b185ee9c2aacd5edf2a0fe68946185ea218d05030167520a2e0280c92f38c07cc3b964601070925c9d31ca76e82a2163bb799be7e2d4143a4d6e3f50a3a2245a5842a326277d6c70d90d22460ad2b48e4f4f6a309a1594ec6eb087c8980225d6ce8c1dc07679aa420dfaf072ebf5077ae3811957f740baf1a9ef8bb2384de5dc09df702128e3e9687427f6e3fa136b4a4401adb010c49dae8089384226e53f42bc05a23cc0f0646758aae5dd044909a7c12f8e54dae8013212609906df64117cbccf6340679a237691116d430358b596701f28afa0b2d6dc9584e6e241ff54c8493a7bbfd621dad50ee1f8ed4ae6379841738cd4861778384b86a1d2edd3cef535b3939395ea7bee05c345d351aec2c36e4d7b4b1749c45e4b0991e89707f18b1c9c2787b9c96ea60c7072c87f85f1c51eca72ee6d0d16baa8074e8431edbe829c802541041ad439ed2003b091d21b26c46fea000bbe0711a3ee29d3554b5d5e8f80b62f2522ff6ce0cbe46597fed9f662a3c4265c4ba848d64563e39df79916a6d0739d9b26cb16de58b12658f19faf02f73f9f851d36c60fcedfe99c58e9a9eb50f6efcfd605c77c41e2e84bfdc8a3cba5901cc09dc6c49eaa49c6925c45cdad57cd82295566aa39783365025c27766e9b1359de7e7c0e0610a56a905c68c5c8fcc095058228f39bd508d5c4642a67333a9736d65e7aa781440d2b5e2e25ff018a9dc8f68063a24b143533d80f9b80efd1b41902fbc4d61b1726325f58dd5515a98db07990dd765b19aee7198fc1bea2f80fc15e62898169d9df130cd5bc53b76369acfc6ea40ba3085648234dbec48371653c1dc3a8ea2f62a2ad8609edc373d813ba91178f2f38301185c40aa3728ed82496d01179062fc657ec241dca102619c63b2675aee076fa30a05269a0512402ec9c319fead6b80d8d14dc66f69fa157d064afa9224d111a44193852215eb803db33eeea1810c532d749e81238f094f09dd1fc6ff18b2b2eac72d550c834d38d5ae98845fb7288b8b24561cc7bfe8d9fc40f4e5210a5cd326c81a9ade7e9e2d99192f2b00d5a603013c7472d1c844760731b852118d9a041d1d41f88ab73479b99fc040c2b0bb5c301aa47bea6297e67e0774e72113edbb2a4cbf9f78721982cd7edfd2b010f3b8cda691e939d59ebcb03c2035d11f41e48a66ae3c486110846c864f3d572a48fd687242060322965e0759619b10a4f7c64c13eeec8bacc08c4a0787799b6c5adccac59bfc005cc6084e95816af7e50d1edb74ae53049393a548636c81e045cf2e8d5e7eb363f364edaacbc0ce6a50950b8d2382a9c0d69c11b440a28ac519c3c521fa22c78338ae77427026c71ef40b7f47530c1f5df980333f3b661dadfb9e97f36752db2e2b92896c091d124886b3e8337840397d9a701f387235f3357389422d9395695e2b6330e51d812750b9966b8becc9491fc8e6a73ca01d8ba1946ee40b6cb5f71014889c43813e974f2e353afd9fa8ab11b77cf75ebd995d77b2c5191210021346e7943098e31cdd7dff5becae46366763d5a7cc4350d206261c36c0b8011a193a49da841381a11ba76cd0a914d3336f3d788cbbaa2459a5127e3f9502c4803c0bf1b5741bd3c14088d4c63e32d51d0f5a8b58861156114c81dad8e5adf274c46d6ca16ced8552e4cff3a4f5ceba9006d1a02cae6c0304ef743bd68bb1ed1319284fe8158d4fa66144464eab60aa3886c99c155e6e8ad148abeb315c3ad28af938097083f1bd635fb53041f57e31b25c1189f8386a8d0f3fb6325c5d48483706978cf09fea40d083f88ec0fd71f10a350f0cdd70833a2ed71fc0d686e98a3a8b097459c65b4b20e0c54a82a45f2be850f288bb3a8158d909e98c44eec8ab73fb444512b32804b594fe92114055389e06a91f604e88a2d0e708e630ce4dc8e1b4c78eb40f1bb7b52019c0672ce4b31d14b01e1649839b14fec9ba483dd421beb27f0f9898314d0bf5691a4dd73a605b5ab8fedea9e991a780525eabae1cbbbf182a877a32185af1e864c7e3f5101f1396fa3020015d0f07ca4f30f17ad39469cf4c01b10aecdbd8168b0f6293e0ac66cb01d0082dfe77215f9c5bf5db63cf3907c1ce76154f13ec8d06adff687c19ebf5a1e885c24f3e1baff2cd25569c7d5a1f01704bd2a2dcd32953bc7b3703b2c26b9cf0c8400a2e8f5683d3ab933c4d5126611c72982d81ee1ad474a59cdedc07d42597e05db887f2759f8411fc73bae83c865a55d75c34002e53a20ac8d6ca98e3c064678e5036db699e760024c0ae87f709c2aee93d947019260f3c0a7749e896154d28f017c0a5c6c0927460a014afce47a8b338288c295bf94d4aa9eec3d349b8c5e21780db499d5644b5581f5105ab9fc05f114e3b0c9bcfc99a136b84d8fa08cef2cb223ad8d6af8883fd2d1b293c6fb8c711078695af200830e21d1db8e253ae8665c16fbf7482b58dc9d33a5931eb2fcb001e2d48e2baca865c9518a4cae65c792c6207895648015d0fb1dc4bba326dc608350209a69eb648ce30f89ef32986736b3e4b74bd43db53fb90412a7e053c2ff1715b82d452fa36a2609db78981a552ecdb69bca17a6f4615543dd946af4490068085b0c88f7a54c71fb99369f18c3b77c6099b5782c1a0a99aa7b6bbdadbd8d522115fce6de07531e3f77d3d0f8a780c6c4362aaabe56dabc0ac48108dfdd3061be88b7ab6f89e1f91ab0287a5cb86b59e67025c1334902d9bdd4f785a28bee4b351011038f8810d1b611dd3033f2ec648d86889b10e3c433e66235fe90a69927bac63a2224712fbd50968ed0ca9a45ca2e3f6a2d02aebf8c1a4772f7818ca79e52ef1ec487bc7973e1bbc3789a492f8ff665b378c94cff4a973a191ec11d4819d553c1a2686bd52d678668995a7492e887fbbc12c5e10337d603c1c90878185dc3884c51fbd8e4c09583b8cbeac68c42f74be2b7dfffa2b217d13ce20d2229ae0b452f3e1a45967fe384f794b0912d46829a8d42813274c842e6f8e68b164d40116e774fe36e46779a7d8da1a52d9c3a8d7ca459bfbb2a05b0ecaeaf1fb636cabdf23a40769154d06e6198a3c637d07f9d149067298fcbeac9ce88d8c3639ccee81b2f6499f347d22c36602372c1ed36256a6356cc0391ac9ed7e2bfcb738322c07818315db9f61a3db340f6989a738e7b6390c0347233431de2964e3bc944e3621b08a8b6bc44b9379c1b994334c8131dc7ed096671e950ff90c435e2a962f04b44eac54e8b1ccfdb02d87c5a08cf4688f7217639e772975a3ce9db169d221cf89b3650391dc11857450276ccaf9cf54cb84ac4895fe68e4812141897f2ea075d14ad404e516a7e5371074ee75dcfd4f21d1a65e8724153206e0550c3137f8d6c127cb8920f323e23a5310828dd5eb89c434e50c0f46918ef4b8b0488009f53e713b8bf9b6b3babe20064e26b18a0a9594bf87301721cfa051d30e8e3004fa40a7cb359388f20f6c74309666d5f5abec838d193c98a92db36cb02b31fa39e89c8aec64f67fab1052a9be667f64e9d87862ab3437d2b3c1f31d2d2974a9bc3c71c0938db3e150a6f7cfa0164ce597a27e3e9f48ec9fd826ececf026dce8913af69127705f8d7293b3828001535a24837c38e51c39ace2885678139d35a2470df16e6cc931cd1f1d31e7b889624c6690a56208da5afe799409b54473ce5d9aa5568eb5953ac305592b757e80504d9f24b81b2f8a9696b6e812faf1eefcca5975181bb77bddae5be9755b3f2ecde750750fa33a25d697be72e96b55f0674f4fbd6711ba34f8359f45b860056727923777e54208eb71bd6195802c257a45fb973f3a775c817424ca7c64b23514f3c365ac8e45948f594dfbb37f4355230fd7a3d1b6301a51d5961452c895e2a3ceeaf2914c230f61ccb8f5f4443be32d8f1428ed928c3330e9852867f94116e1920b8f985d0b409ed447d40542c0da572a34763ff6f9daf00fff35338a64e51f929d8248ccd23bf17ca8f7fedbcae9ec452c9f447cd1a6971f35b04fcf7f8a54743596da1411f660c5074812bc1faccab89e7a066cd6fa08374e87f96cf1eb64a56f87495c24bb5d03c4e87f69fab9a50d56110199df5daf47ea2cf3c884da8f6796eb82e82e405e41b32bcfec5c93fc535aa3ca8cc43320bb37a960323539acf418831bf7aec91887a20a5aa7e4fb83f75196fbd98e0d3f94ccd9ee6eaddcd1263addafcb81a5e8c9f4abba44f8f281c77e7a7db35fb1caa55bc604e1751c050a1198232ef98c3d260610e31a95de5a4e0d0803aa141e3b8f607410ccd920886824d10a63b94453bb1033233a5f36981e744c18f7dfeef266b31175aa028499d38eb7391b2a029592ff4dc116832ed78d4afdc63ec302beb9431d534887af1b931bd5e7b6afcdc337e0c1fba377adcda5b0e0c8c1909711836ea6ebca97884d019cfa06a99e18707cc85fa96050107239bea442a248fa45954f305a688b800355910a814aa7e03208f05c4d5f2d9879bf9e3ea01de08d14b56e3ddad4ba3d1d974968de4c0eea7411840c760bec3ea75b526bfae5c8838486027f2fa1d05d2ba302ad75713d298cdb6371ab902d108e164e4c46f86bc6a465b09731f5d174e7ecc4df3a1d936c6c242ac07bb784acc4fe3d5aa6f9a2d741c158c4d063f7465ded55fbb6e7155032bdae673f6bc56686229be1bb26d86cf98f49c845db3fab18203a2493f1fb9a150d6278e025379dad240f4f4e4d3acfc4aec029649223a8348068ee40cf809a316976440f7a607a77ef4d0ff52d7005e888f8c489d487fd129a308e047b133a46da98e0d0c4c2824783fc4831a705a28d07592b228a6f71a51599b350fac68d913519f6d9d6ce44b8e03d030587a6e2d710524ba76a0c9a82294e49d252742b23666ae5f199a034f983494230e7be7502ed50f42bbab28a1e87fb2432b781ac3c25395a6578c0d46a7b0558736d2a81d93cef43c448c51983505e3f1d54c2fe905c1220034d35343a285c856a32c7675be6e409de78b0a783db881c7913077546c8d8624ceb031f9935976581df1a42452ad1bf72ae10dd0407036416689b04f01318f821f57b0ba498eff089bad77d82068b409efd4c8009eecc4b0e1d04861db4f2f0d0df81c43a5861def3c727773fa2fab4dd53720bb3b319c4bc6246a38926f5d0713c3311fd12134a96c8d9c22441f8688a71b436644e4578dca0901ac586f4f41e3f64f72885017a6d19aec2a0013ff77b0ebd6a63bb50145b06b727afce48f83a2df9843acffcbd1a498414a247f3e544e530f453c9ac2e61f06d4fc900c7ade859868875c209c1e2d1994c40f6aabdeced7430c766c90f1ca9c5b1be7a3c0e7a95c19128cd1c404606326ba742d1bb03fbd1fb2a149096fd90fe67b3c55aa73b02a9f972c5a8be90a7a0c68eb89c33a999160e498aa5788aa54d991869c7367ba3f29a1f3d7616bb36cfefc5ea6ae03ff85d758bf9a3da9ef21a7bf813673a99ec72af0c84b60690e9c63299770514db7d9403fb351fb127aee082f4b75ab9656592a63cf110985a39bf07f448c6f5f81a5a8f98c7907687718bc47a8f35c67a914157a84bdcf52e3c48661e27c0c9d4ae85d88ef297410b0f04f6b08115a068a0421e79e3047de12b3296e186776ceb7514c4564001dbda03aa5bc3bd12d84564bd77c7546e88bf7519f444fbfa5002894106cad10a413c66ac43feee7885e8e10fe1b37717237a403fdce3d16bd7677be3c96d073462a10835016fb0a6f189f66b727b9c53475e402f2491ea54a9fee32a9b59fdaef50192e8794c01fc4650fb57a4d0b46dfcf4814293c59fff99ee64ca86dbaccfaa661083dc78c2d246613f13b74d1a154ecc17ffae8ef4b4ca67bd14fb5af73be1e0fd46e48731da8c62ccf9d3b28611adc5bb2e31721f20e7019ebfcb299cfe20f0283a8b384a7736d07f38fac3843ba1db06f93635fa4110992eb445b8a30f6137bbaf2e93b876fc70a5b3005d79e963ce1ac0349c735e180accc9623911fcea422c42e47c540f58abc76a1af5818a2a1c26f02c73e352a773ff032946caaa31766e5f7d5dea909d36992c0a9772b8807cdf519b73125ad4288bf8c233174c6a85e06f433cf7a603ac1ae70cba78ab57fe6be6446b18164ed7ae4b3c29929c9b3822c0890abd4cb2a9870cc7fa173b4b8a119d5fa4595543af65fa896307902ba501a923c674cc2cd13d9067cc9a80d40e9e158e4fad882ff67a7858508a2020dc2677b87e4cbb625ba028c474e71acad69d2295d04f339da3cafd1edfa64121b2b9a5fd509081d18eeec8d4738971ad32dc96a8707f594b0b1e7e08f1e99192b594ce9593091c28b71b946b7c1ca0e6bc8a83d8c63ae5c989a096e02208ffb15d896b091cfd3b4b892740e9da7d3c30d00eb86dd808fcd0d3e7b389e8f799b14493364fffa24f86cba161c7ad8a2666289d8850516224090e5df6cadb0e5c58b9ed0273fdfd1378c0f82ceb26202701b20d2d97f01d24017a7d808f261b04c855f2131025bda47b0256c8f25061b37505c7bda4bef955c5f3b391a2c89e7f2125dc51f7a4b5505729ba6babc64c9087905315f9a0f5ff6a15a1eb16be08db1d5d68e534e02136b96a08b03eaacc48a1a344c838f9ec6155b9e0350a7cc5360b9b77153ab1ab48118e4f6527ffa711d26b104700836a0f4ab69ffb298fdc250657825e4727c86d49eef827aa1cef8483126c743730ccb6ca1717d7c82a0ddf544d9eb6f2a1a981f7a95b0e5a7de3f3b5837d05fad753eb0f6ae4f88c0234228c74b57f28b73f22bcc049ff4e7fed71f319cf34316a18e59a9caa298e10d0df1fe387f07b71703da7a46df5a8d538ce4798ed353a05db3bd81e435c56f0096432cad1da052d16c2e0b9fbf88209cc4a819fbd3e5d2e0c08238d42aafb4f414764c01be329711118632e8c23bc85f3e56ce299d4dba0d95eb07da5e54ad6f2c332c4032776fbeee9ea215b35b45443b24a67fb31ba6414fe085082872ac9ef41bb11e802718cbdb02e8995d4e386e538481822f2eff1295f8c8904f4d2529ff55fd7e39ae9eaaa17794f5474c00b614edec32c65027fcd7e6e8ace322c4f09484373c39ed46a6e5ba631d6d42315041a001c919ca0c9460158a005151fefacb7a2639d60c815de8239f76285d4be00c8e29c3ab8c1c547344ada81b60ab282212ae83966e0a4e14eedfd2542020e0ecac783728d072a95eec10c5d06052d6b24657a6fac4599ae961a0f30284f9c2620d274db3b3397e53957c5237bcf3f901d7557791dcc06b132b9f7943500b332b0bdf5eba35f0dea7bcd5fbba84d1fea3e964d7008f8116a131c680a63bcfb5465d8f8a222acd950ea3d6efec76f57535857fc6415fc7817fdf7cd35e37ceb3eaf735c6df80df2876bf20f8eb6048a9027351548b248c1774030d95323dd740f67b5b78795c10d1dd335f10114203eb0ba4ca960e6ef93f56609b583d72c253f4c3ad59c4f42871fbe1475a238e3673916b9ef9aecb5e8a445f2cc7c389fcb08f08813fa8829702bcfe47ba5dc4a03d6424ec52494e37b9a53ac8f3480cf520899b90d3b3b4c00633eba6b4a851b0640fc80454d9ffc55d306935e6b10382f0e76784813153c86e005896378e03c55103169fb94a93c37f7ebec3944cca7fcd41abe28127eef1bb0ff1459deb8998702b690731d6816c1ac4d0ee8a22a5861f047cee9c7c91b52e3875db85cf670346b6dfea9537fe6bbb2edc09c2bad35a06f4a90797b92bb614490b7c278aff1e08294bba62e9596f079036299f9c6124c4c7359fd8d6f53ba49a7128991417ac3fa36d94845fcb2effa3a255b306447ede4d90a33b1c183a8ba44d8607a7c35142fe39ca90e585f8bf5242acc14036b2e7eb314af0207bf6049c9fca22741b776bb570d8475c90d28579c87325f93d47e8e9e0bed15675e7558498f3d53ec74d6f20a6bf8949506ecaec7b108a540905b50c1a4d4b0a9f744d8aaea39ed44055f6ada1fbff0047db67e980694bc05bf375640a891cf2d8691049610d137ccdd7bd2dbd0468518b0d219bd1430225298f5a12e520d8da1220d9a56056230cd5d87d88cc7f4378c519308dc32459c87cf10988b7f0d173549045afbe7316f991e19c40bcb63118967db4ace0d2713839e299e155fe29645a4036291a448e2a296428651e76b8917aa80f0035bfe4cde994c2531e43b8f95ff7c659991e942a0e84cb9953ba5c692fdc204fbb071746399297388070aa9a38029d770791eb2ea7247bc50c7edaf747a6fcdbaf99be2e124c1c7ff588763c4b9ddb4a823231aff1ae1a1701c0ffd5431f9b197bdcbd6110bc584e995dbf2a3de6485d57c93e5783d13f0eb4a170f77bcb727bb6c24788e78f434a953c6ee1c66048851a4e23351d544eea8509850a58e1268474ad8e4a9ad7a76f3b580b4e2e9621a2eb027a52050a432ebb2c7e146d974277c97755b873bde786b28f82cae3b4315d62162a6dd0853a844c55d7bb556e31b5d8dc3af7583448542c95823f2420b73da7cdf1315a29d08669eb55ab60bd3debf545a76a9af21e60e71ccd2909cb5636ac9e183e44ea9cb285aa36791eeac5cc2715febb458e6d4760a73c89c64b6c72dde937577e8db1c1bd7b33fa65652267507f21cec45580789d1e844aafb9769a47c9096a573a586a77a93f291351ecb1290024aa1b8707bf8ce3967e6d88aa28b1a59f7a50a595cc4878c14fdfe6215276313fc0b39bd9c353a8e78edb2eb38d9dc999bf00b0f3107003df723c27656f850b441ea195c1b86b1bfd5cae5271d2c52016e2e48b919ddacf099b3ac8a04a50a96bf52878d9b62d770c61cfe0d9924481cf50a5dc9c141d7ac4c06c2b30830c331af236eac8f8694228be79e16ba1d848a89cc268e824264c54c4c224af51d94bf22bd99d3c9a2f493551457948298a528758a2c4a5f5452eade6bdc865874934797b0cba892927125e9a22a064dff6f60fcc8572fb8bb28ddb708bf86a2941b5e684949317ef57b8c39fa9d2fcf4b7e55166e23924c0069983fe045a9668a922f14ed9ee2a8fc6c1ef127834a9ccc6395a36e109dcd0ea45c037a60be7c5e40103a52074533bf136b7f8978c5634883d0aa92f485d8c58844c095b2a72bfbda1ece0e29bfa2855fa60fbea6bf6c241357cb5dcb03f4c81439d3129f1d22ea8085405f30337a666761d5d1ece52fd232f07154f964ef12eeb6a54c49ca93079f079d07e1890aa6f99ef8722e99fe4785ba1af649913b84352c46c37e9c61249b77466a584d16c6be862199917233ac8c7a3522135265b2930c1d40084f5566843efbd123168a3d1536a3940184ed00a333457046a206f0d03d60859f1640105900024008a155a1cb1df5c6cd4dc691c24ad44123fc59e53b5bcd58a5affa41d8398927d8ec2921b83e48233c55c135e14e36efac6568186d18a8ebc6623aa7ee540ca4dc8d794c0431c757a5cbfe7223b0421942180cd4f5e5429d1ccb3344bedcd733193a004708533998157e08f3764298bbee9ddd19ce28f18418f9d260c0f585d8733ab16a748d00d4009010eef0cd680ed415c2603de486c9d001a61447054365233b5033058b75d648284ea372805328f45b3275ff859e9d665da3f1cf3a77f959a55bb667ac9eb17ac6ea196bc69ab943e9d2fd5a969619ad71ebac59f636f2a70caeed9a29b83e6debd7ff85108943070ad59fd64b9e10caf5ebd77cbbc367a91c0890fe056aa66fe3c50df00d4b4bae37d6f2e0330223404a635adfb9f7f04162d2ae1a6403b2a5eed0ea4148727400531f5df6a83a5f75c76aa9bee940ee729d03e5fe6ad25dd5b9ab5fa82c3bb9b3e41e7e5385e5534ae9ca84d26fba3329ddc12e937e1c2dc20ffe77f0cd8e813eeee881791c0d9e0092e667f03d514a24a2df3ba4b6dda0f4b79476d520646dc467a64444ed016aae362635259576037cbf2f8f6eede83246136c55e0d1b1f07bd1939e60b363b0f01355da8b8c0ed8d665adb76ed9db47b774f8b94844368c923528861ae42e99982791255286347d5f0c093eee3bd23a36aab0c3866c08f490935549af9abe30265ff8e0ef99eae4b85c1f3cede0991d5b9d73efb4cc92554923a1c51481ddb5c20c2130fd195260fa95ba781c0d7668a5cb5a77aa2eb703d8ef851deb1a04eb1227921ead06d5a02d3467565aacbf6556baa43810b424c0d682a3093386c0167c4a71267db5e0581a2b2c859ca0fe1ad4adcf842e73682fd23ea4d14824b2c660540a2a0b6c760cc73c5b73df279226cea290344f60f820d9315a135a2d442da425e214a41deead39785e4b91c1019bf063c5073f14493056695d6b389a8e6e81a40935d7ff7db8c272b93f249e60513b585211effa7d3444b21fda9181645329d9846e5d2b3eda1f47d38fd565ac63373a76d365531f7ba757fdf4752fd9b556695d928860d7755969a0b0b4ec8fc2013669d77fc7b8694a80dce540bef2f77e9d2e97c3e1cef3a467937e85e63880edf7b97b9fb8ead3e5d9a5b7290aac0307a9083e75c86b5c9ff59571e8a89982bbad37ee5465774b132d61832d1506d90ace17100d34f107a28126f6473e3ef55d0e8d3e6cf4aa5f1c819f892cb2c82db3e30c1eb0efba551fbcc1ee4c2580be3e5f752a01f4f5beea7fe1f5c24b487d8de80b487d8dc81951e096b593f506b2dc4997bdb3347c57965666b1a861cd14ec24265228bc903b0753ef5ab26bcc7c21c42ab5c862a7c7f3be660a76d1c616f8849e94933d7cf4aaff850f7e13ef70d78aaefa6b44c9fd3434a1dafd7e72218879381ab16804528100bae17c7d38c040386e7f1f0b2d744bd5e507fc1be0853ef287bb60230e1d5a4e0f48f5be0fdf5aeb8f2e6134c8fe0072bfc2bed65c758a5dcd9192ef8dddb75e6d1185ce22991954017bb568809a451b5be0cf2ed4ec42cd3868cdfd0c501a843543be4fe9bd7f2b49860aa4cb1f4cb0a95275ab8e8038f3055f0c9ff4d4bdd2c63af3d57d5215b81ae971d3f72bed15e66f0482d282edd35cb3bb30cca9f2d3091c3b09cf0eec35a307dc9f0a3dcddf0d8a4c126c3ff7806f47b2855edd0743213856134c1183bd484f70e35359dff348b385308610d8fb9d7c59f8f0cd29743d928528d7bbf7698466b7d66cb0babc2c1772541dadb1ef7dc80b897576d3e57def7a649d75498a01f78f1074bfea40ebd92d8fe28890ef57247dfbf67d0f9fa31c48694c97cf36698640c277795064e222e503c93f9d5c4e17dc126cba9cd95f1c8134911b72385fa2a8850c22274f45b0e972ba9c80884f7a1cdd12bd08d9df3f140abdcbf8a1b2108d96ba70b3d76f9bfc5ad45709979ffcf23ef2fd9711888b7f791f4117632f718509d86b060ef8c67f0cfd539c2338fcea792f8eaad30c29a1afe34d97a12f8d38ba0cbd3805364f39f4aa6e89f5455f4953fcd187fee462ac29a01274be484c60f33f150a816f431fe660938e108457b8a13822e4d0dfc0a4793ab99026c624f2c51187bfb8703d700c8946b37e95ecd9ffc694016abedff9fe252570e9cbe507eceb02f0de6b2ba983f82c895dab03b0865e3dd93f21816bc52fe4f453670c816f37a55f76794f395491ae6013e31e92cbb686589cb51bdc703402a92e30028af33502810d7a603386c026dd926d55e29b92e9586355f603362910902e4957b05973b2b50fa45b395565ada8002c5abe7034d21928d172deba6323652ba55d350b5b35d22dea53fbc91648492d5b28b7764eb76c4e0bddf272c8220e5a63adbd48f00c1c708db98b852f02b4e534fc902497edb3608fe0b63350d7c72a0f47b2ad43b2fdfe3edcd657f68e355665329064c0a62afff7dd6fa14b5b67a02bfb4370476cd718adb14ff660a14b91096949b7388501bc842580385ff7745e710a598d7569493b60b3c6beaaaa39971d80fd16a08f82f7236a81cd9002200f32775723b007748b06359a67bd9c873b6fb69aa7a3d56cb7d3c379394fe7b9bd7ebd6bad5f1228578f8d4a6068f1cc7a568667b29faf5d5fcd9ebc6f7dfb859c66439ef5665ec8561c51549385358a53fdeb9576793a5fcd284e2814331282ed047939bb2d40edfddc2c9ece5de0965ef5e7fcec0019d92109caad24046312cb7d2e1ba3e00b0675d9f6fb5341c4642a9e60cad6f4d32d99dc3f52c1f74d97c9644beadc25f4d968f499afea0887df4bd8a58971ee9fc41c56464ce18511fe1105d8c44f93095d26b3a920b089ad0d8f9e7e59bfa6128d4618443577b9cc572daa8d58d63433d44cbe230e472ad814d532e8b5a95b4b8ec62c1abf178daab65d2e1ba960d3d60f6d00b0024cd9ea9b9d8371f152c2f4e7c7c5649132fd94ad73dd1233fdf002b64a6debd7696db75eedd7cf4d9a36df07ed583e8d254b776b9d88776db56d59ee7d7509dc4ba63e7ba469bfcb9697345fc94b96ff659b69ecffbd392bd5ad67fa30d5ed25dd90d7d6ae7cc0e6d7e077eb1373b8ad559429c5b16428d3b71ffeecd7f2b2bbc85a15cc25b19326bea098e3da2fb4ddb25dd66c0588bdeeeeeeeaef757fb506207069af64cbfd868ffb5e1cf611a0b5e3e8c4e30dd83cb9d98267cb354471680d40efedbdd7f3bcdac701dc7549eb8e0020cdd4fa90e33911152a4958c9272f532a4964a135069260432dd19ade22c4b4464b3655a80960ea33822bd93ca94e14a7e6fce12a485eb4cb4efafa3199529c7641715ebe7edd519c92f8f55d46717e288ecbd74b9bc8f6bd24d97ea85e91ed7f0d25db17e964fb238f22db071fb5245b32bc49d0266c48e261a957849c341418744c110f4b60fe6574f120581a5f1e043d2c8d2f2f8ea5076f4882791771c47fbdd0271a816128248df66913d9dfbf5e91fd1b4af6779decef51647fbb24bbf7a60dcafeaad09b3789ec9ffadef46cc8fe3714c7d2934694e84d0f4bf6f742d2f862f466c849f61785a4f104bef9c190fd5dc8846f7e4e647fd268cae29b221eb27fca0030d9fe97614617e30e5a53ff65ac345a53bf34d61dada98fc73e694d7d97d165b4a63e69f41fb39ad5a453b0303b4af621b98a6c7fc831a21dd80478bdd027fa767dbaecc7daecf5425fe80b79a7cbfcc75e2fe4edfa74d9f5eeaecf6b693bef5c0835d41e787878787878787878787878787878787878787878787878787878787878787878787878443133e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8e8f4c36451dbedf5429f68048622c905975e5cc0c498644e2f5029d50f0d666d29d48b938ce9c29889a17219ede67e4c31302e5e4a313e452b6117d28fa82af37662087abbdc3f1ac917b2dd28447e70aa9fec031a996c13045b5bfec9a6c8f613934521d04063ca364130a5b426041a64843139b6049a3b739001142749b0084192173cb0858807748c18b18490d7d521dfc729c822887c7578ddcf33f511414e36f1e3e04da9ed1dd8ea44104129a5f6f36a2d2c168bc562b15a63fe361b2c21ac1b37426e685ec8d3288594305808569d849cba14c2d2a8656983c5aaed2a3f9d68fe63b07d2f6900b4a67f0003f01d44f5eb907bf65e4b29a52010f1f5175a2bf2788810a1a71e77a7b1a136aabd2b4d190095fd3b9b10c84eda20404a8393a29416615194624add9eac0ca59e774d21198d81a13404a188eae75fc13457bfc9a0e1fad6dddd2d08455c2f54c40bf56a1f382a8560682f4da4945a4cf24477775b23d5bc59a63276c0f5afe8b5da1084223cf710cf1801297d118140847fd6412022145620108aa89e4c06bc1411cf74b2eeeef6ce18c1f5698de9326badb5d61d8422704d0d01a188eb9882a8179d425577550824e7b6ec2f83961273d077eaae52914b62a3b3a2521f9492e89ec8b9ec5c76ba24ba9c2e279259c1b11003f2d123b6f3742b23a714e7e9a91a6872628801879033051d4270b7369be1505d210c36dbe9c013f6da6b6978b906aaf554c65dcac080e6595f5de177fb62d7ebf314c9ced30b75ad694dbbb58d86b6792d43a152aa53ef74ac63304c9dd3b099986ba5455ae0ba2548243b897061db796405da01729179e03cbdd0e770b8243fba8a4a7d504aa2a3c1de5391ec565912dd29ba41241315a1aece89723873f5eab448a2cbe972b22f949d52ced8e9224b729e3a990eca2d76d39d5f2d89eef44263a5cd62aaad46434d27925131e414d51c186c2756635556eb08a4cb1f600837f48015680b2cc4807cf488ed4e17e8eaea8da2bac2d357fde628f4a13537f0d86100cf5e4532dd13b9a6425d7db614b943297d8e357091f5d9525cb4b8ec5c766178dec2538708628e1ecf6597c4890475b9ec5c762ad07db51999cbce454bbb3cb2ab744e24eb9611370147ecf442f72c9f863fdd7575f7d49d3f3af886c562d568d5e954230015464502151911c9c2337778764b4abbae95abbb5d5d4c05fb40043a50ea314a3b5701af5f600d53f4d5af7ec100a650a8d67649718c6200438aab2a5789516762c4f0f7d50d54769a22b866950d1a68f4aa7f8403b634c6f5aed6ab70b9b19d1b6bb75fee44057ba211188a24175c7a7101630a29c5499d30d08b1c3df52768f722448555577328544a754ac9c030c1988949cd800393692a86cd2f77897061c3f9ea92f54cc9806d26193d9cc817afe63d95263be510900ea618b1a7da50a90f4aaaf05405064d37ce94ce66887c10d5d67a81c066fdf9a135ed35af31b9df5feeba65fe1341cbfd343ff54ad50252150d7dfa73e5a4729b87c51391836168a85b7caa2798b6b49a3f6013d75aebedafa4115e1bc09c267e2d3eed601930e0fed7d15a66a32971125a81cda6d1dcd54d8bc9ac4d169b65295dca880114484430c3112e08dab16cacc082077eb4d8e554987f3f155b0718889f1d3cdaa69f4609c64fb878de985396ac5a56160d16f5cab6e9b2bc2969dcb04d6d48a34ba7f900c6b8cc5dc2c801bb3ebaf2f206597ede14b6963b9c216926305eae621360efd62dda320fca77ebd29eb8dc350ba55c01367b76b396b433b36731d8273b5722c0f696fba9f5722e50925361a99efb22f6dd60a73a65da4200800a7cc10f07d83e4c101826532636a0259b3813f9e911f4e34aee07b2c203b4e84841051e2348e1c0b983c71052727f03709850c5c94a6de8344e36c61b183c9620bc3c40271eb6dcdf802f54d9a6d4c230cd298c50f0cd0dba8ba10999e526066c7e5f2d811424f79b608899fb2ad7da03ae6db79b96a6f5aba574ee3afdfcf390cc48a5a93c24a71a2f0873de0ddd5f73d71080394d449f0752d09226c5ddd8187d699d344334fb884f378abb203cc126cefe9ee3f22a06dc4fa42c858092fb69d8f87efc1c0a91acb266ef56d657d2a8fd3236700211ae78e1b3812d98f5d9a75eb26e32405dde1d24e794beff07c5a1df45e8aa3f041248a4894b3821f12ac826ddb132dddde4fae9aace92317e54a06e9974d743085aeef7a1b392650bb522d7aadb0175ade84a67b262e8421040f63749c866d5517fb304259098a20228a8642a4536ab6ea436fe7894416d7c01b9d2953f7693010ec8f52925698e53d444dd22e57b7796fd58edb9bb7b3774effb685a807a30ac6f14f2af9b1bb0c9baf1cf9b65034503fe6cb260904d7ab2be18f600c64eb6e47e98a7b1a1b2ff654983bff29f06e64422a2fedb2aa721d83ce5b6d1029ba79920566e4e9c843cfb611a1a5129c0eebd7d5bc9d34b6503fe68116c966f04e839a1e5d0b6e9b6e9ef210216dc5fe9fbe8c356d27ed48e34c8b1f83881e57e20d4c2d41c1b37366e9434fe4785b54d3f49086cd220ef0710b10a4c6929a3027e4e5e25d96f8d341b979d7a5bc9f63d5c975e5bc9de83d56c5cf6baf4ac47d21bc213dc4fd3038c7de820b2e4fecea2c5615570b9ab941bad9f0f6b3f7ccb4ddd4f265ddaba744aaf3b69260de48d42fed53b19361b68e73550b7b2d41a47604a4beb301b4e5272bf8a5a181aabcaa1df7769a9d7f1c4031c30a1a73fa53159df04d70f820986a1c1f5a98f3590d0e1aed1f7519cf9d9e2faa2effb300e91b46993954c610424be90669f582188ea7804b193fb1b7085c70a326c52dd0a3c1a90834daaab05a0c1a2856fb2e4fe1bd4c248a96f6f84fc0b47dbf4e319366f6e6ec88801d3a7b4f4ef5c9fb4b4c6c9134a00861e48956c9900f991fdfb0525d9690bce247b0837dc2f03863194efdddddd3f0bf816f7daef5f80cd8f660b560c894b4e13bf65dbf4bbec807b62ffba64ca2d798a823f871ee660f33b6300027793bd1cbdb9417dc29c26d6dba954d79dd24b29beee273f1dd736fde0073d1504d8f433e3bae567b7a4541721d8f472397739edc3de12baeaff21f7132f0a0dc8bcf16ab4a62603089b2cb7e1edbe10d8d87480cd4a0b6380ab0cd7ae75a539c64018c9fd3034254e9ac91218d6ff857e05cc69725fc8bfbca7342ab8d75a2b49df02e56ad35f83065c491e3b4c36e0930ed83c79df1e89c36f4ad616d06403aeee262b3bc0d4016c9e9e52911d407168e6a1420e3f13ab80619600739a5898edee211a7f68c12e39b81fb603e6dca734e6775e5ddbfcb44dbf8c0c38083edd65ffea7637e80275cbec5defb45cddb572b3f49629d8b45aba77f671b4ebdc65bfafceecb6a477b27218c37ca745019863af4dff6f81ddffebaed276e0725b51426972ccafb23a9351b2ce8c5459cb6739b8caaaac6b6eb0ca3c7c4fa71d32bfb2938c94e5643959ae73b20ab05961a45c5f0a5ca2900b05619fd298f52cbbc6da0646049bdf59820a039d2929b8e2d55f5980bf0fe3d3e9ffe62687525447c18f2ebbd65a6b85b1f75e1f405c60b8878f1f40bae57f7f6092fb617ab8fad5392a6badb5d6de5abdea55afc2e4fab7f62581f4187f903ebaec37ebcfcf95763dacff0bbf1080f54569ccde027fb32ddf0f3bb2182ebb151f5b6d876c5623486498c0fd0da3df4e80394dfc85fceb3e8b060dbd6dfa4d58bc68b45ed11ab69d6e7f96b85ed1172dd72baa002c5abaf5c427fbe87c019b45250560f101410560d93958c3f6c9926956800b72dda2516290cb0ac0b2eb562ae76400ad8377a451b0e47e5e764c41f1022b0b746038ab1025370479d911e78617a52228cb0c2f3bd2279a7881d609273a45d015148102f4b263093878c1004a620722535e1ae8132079612c3ae05e97fc7cd529285e96c4a10e975d521b4f9ec07510f65f78d1785f7bb26389e2d01b5a63bbf4f1618bd34ef87aad31db03e2d8da6e2f3d7585c1b87a2175d1f88b9f87dc695acce1df47ad7d82660ba6dfa9c238823f6fc1f697d4d05631ea64af09055e0c0a60fce62ebf9d67a62ef399db3c5d0fc99e14dd355fe9bae5436829056db9115a761ea360d38d982ebb478ef0c0435eb2c4fa91233ec4fa90aed967eef242a4fb34d74b86320806752b26f78f51b05fbf3aafe60533a728138d88b2dc5f45b8918f54417038ba8d6c99fea8e6aed40849a63f3a425ba72e69ee523dfdd18ce2949e8e532420f2c9f4454ad0160b5de6280e7efa221cc579794a7774e6e9dfd35d309efec5b9eb9fd66009755920bb83bb936d50975dc385c1b4c082ba2eeccaeea5b92bc6bbb03b1f807015504ca1ae3b3382aefa4d8bcbf46d14eaba5705164aa66f9fd0d6c57599b3f4ed6de48205ea16d90b9f5293cca35e9c4221538c2a08feec158d3da9d40e6cd0ce0a1004c51c3d29f1851643a33598741d29691465629150175221d2c41e8066b013f9f44a1486632ded4ab4971a5e62eec188582e238c7cf2cf6452d236dde508b992261a152f347761db8bb194115d5c280e0b25e6e899f1f1ba3065c6d4ad6dfabfd27e9e2ce62b180a282708ca0abaa2dd6c4a9c4fe8ca49fe8196504cb9e59ed16a3652ca26d6f0ccf8a2a45777acb9aac0989898ef1466d1d833339392d5e0c3cc0b0d9602675e8846172a8c680a0bf8dfa43bdc79f3956966a2996a26db12baea87915f48148e069b8981f9c9e13069a27cb2c80a8f747064bb9db84a9ac41abe7db31831c41c234f15049b299b0792225c97fddec8c5222115261e4e10e15236116ec6466ba466620f64b87b214d941451861239138534256d8304365f6831b66ed9a77da310d7ecbf98a3fe8fa38fa571fc53aa448bb50468eb458796fda55d2907344725d4853bf1065126d2c41e68d92fd6c694adcb940846ef25254a3ab16ea1a2b0f27933cd4c345ad35fca0136f14086aa0d6018618c972c1a7b62fc288608370253a53115a335b3d44e6a86140d1505f532a2240005f58496fde78fa61b8c99d154ab8169663a4257342e48d3ec881128c2c58021d6702815337e1fa44470265405c122488ab52e41b04313ea237b6248eca2b12786fc3cefdad148248a628e1725f7a5460bc71bbc6a432484e0832384ef228bc61e95ea63c69c9817f2bd7284fc2b47087e913ffebf3762e0cbf66d50b7425ddb1dd05628052d61ee2ad152365f5d23a82bcc015ddd5b69d75705b455ca829617267367e428fa406bf48fa3d88492d0ffa3b884daf4a746d1368a37d1d640c401b94b8c42578d80d02b86146bb4463f0942b844381394dc26272f6f9a98646ccaa1df748496f012ab23501cf067b426940249ee56ea082d5341e8ca49d32535c34f8ed6f4a76cee4255415739d0e52974d52d9412b42c65e1938364b299b26191b25991b2e54c3313ad4b2535dbedc4f9aa2f89c291300436c5da8747da2528c221c9d549ae3fb99d097625b9fe0b697e455e68c8fd33a3c318411b365e0240820d1b3636620eff5a475fc1a738ac02c0c89844e17a4c4f020da71a431cad51a2893750d74b0d2f315da82bc96433dc615aa9542a1161c3a6d51a39add56a591648bed0a698b94b94b5280b73dd2a01754885b64a33a0e5ce5de1ae44739708e735505748057d89b92bd4f98ad6ad97590fb4f592032dfbc39d4b364b3b97fcb2cb3225d294119568255acc984a8d299aa75c4654d0e8820f5c9a41ca4809a85ba921b40c77ee42694157a958b8452a48ee1f513a5ad32f8e281c4a8473170a0abaa222a773174a09baca0125e565d62d54145af68e0a2b70a82a7041d934e142a32907d3116a4262a29950a3c966ba995aa659143c933303ebd6f78d64c788e7ece46aa66c9e93eba76c5dcd94ad6bca56df9cd951e59ab2e5fe94ad5b4e5237d39872d2ab7e97ed264cd9c41c29275da67c48d9523ed890f5e1fb811165dee2cc471109a18f1f68231cc72f6c855666b430d8cb472f87a6f1348a79d1d81343d25efdc7b8211cba1ecc49a4116b34620e91c907628e944daca56c291bad9c1142080078a1bdd48839441274804dd38c96fb4db56e99622df70c89896652d22db305b7f58bb54a615cbc94b00b490c618023d18fe40737563327e90517edc306174f60dd0b8de5d553b5d62651258a0d86a8c284861a1747aa28994195232fb52a3ba51360520f5c1c81c12c5cf060910c604a40a5054b5061e2a990a008cd0b162a3d180b951c4a4fa8c868c0305b4a3c60100b1d0eb12089620a2ccad4c78929d9fc378248aa88133e3821821438c10376e2066bad9581133b3a4ce1c14fd9f1c0b8b0e24a0904539e78e100c699fa4c49e2862936173698d2838b9d29b2124cc9290dc160a63e392d72c06296cf55f1e5d394b9267250723d44c9e570839c0c380a2cea00e6078b57bc5cd1c41332c03199fa3471440e8b99fa3421c4973605baa769a2872642e0328227525ad862ace4498d9658f0aa927d451794cb758bfa3c01cab2c5ad5c0bda4b530220c7f96cc9d55da16f2fe7e016cf018dbb5c835ef020920053d29230dd7605b89bdbaea47123e5d5c91eaf7a63e982b22c7d681bd36f38dfd9912b8be15805c26605fadb4d97fb1d8a149c6fb802ddd8cdbcb1bb135e9a0cc09c7be6b66199acfeef298e5b99afdace727fe85f7899a71c1a2d2cd7fffe85978da52a994240e8edab107afb1fb9732041d4572127ef25af8dbcf515eab0c9325d87a266c74cd7b9ee96fbdd8a5fe9c15e5914ecc194a435974dd765d735c1fda52d69dc1306375a13fff691d2b2000d858e154e1cb79cdc6fc20e15aef834cca9cbbe0c2738a5c27dfb975cc157adc35d29157cc0377a4e26cdb17cb553dedcdc701ae46a2b1001b443852be7ed04017691015787e2a7df680d0d09f66e4f684d7b365ff57b37a7a585badc2d7bb42e691477cbfd3a52f08a78329f39ad07dc58075c9f3563b1623888f061d990626135ae60b3cc250d59c38288b8d55a7dd411c326d551ddff90ea726d39dedfc73096da7a81daa67fccc166fd01ba3ff5a75bee359f56a8e46cb7263d0c0d8d0000000800f314000020100a08c582e18030cc0345550f14800c7b924272589d0bc4490ee330ca20430c21841000080106189899192902003785e9c5854614280c374fc0c372a733ea5d31214daa140a65a8db3c8ef3f165d8fbebaa82c88e2d80dee085a218ebf4ef8c626a7bfbc47ff5a359e402a0a53c5eca43119a1fffdf1840b80f13fa552b3875d5bc7276fb1ddebaa266a389ac23915075e94d542ba95ad6f1fecd19e6a1de6ca5d20ffc5e2784fbb66386512261b5370844ad7facc07f55e16d24d2e1b03d626cf7a2b14384cca659bce1b19c59e9ad1060384dc3474a9ab6e6bfda666d145e89da85d470614e564b989adf9f456431acc54ad398894c5fd49b07a381ee3d11bdd69008aad52ea247eadb946603e50a4c69c485f8f06550eeca89f0c30d5993f1b7f036b011fb3a896cb93ab0e0351a4a4d6b30825e3946c368548e453cbf543a2a8b5a35bb2c2c1d19a043e4d53bf89b9ac57052d1fe4527592f98e00d09d5da9a0d3848db67026335303313d4d95179bd1bdbd5644cf7beafe7ba046bab5c4781b7222eaad0d6672b99ff1842d65de11c365d7b78abcc4ee6abea7f9d5248aade9c682816be1500ab303bc58be62f2d81d11ba6f1290318e91d00c73b98b9da745d354d4a637f2c078dacf78cd222d27fecef534db3e88cf933a11e0a4cb0114d539118f1a2b1cb4f282f0f3827717b93470d6c7844e2b91e8a8921d8c435aea0a68fbe6b36f04c34e9bb592fbd216cc2f25de031204cd0d789ac7b989715c311ca848f996688075a6ce1d5319457c65e10e824317ba1855d0c99b6faa68bdd62e366dee1f42b97fbc422cfdfc23446b5494402032bb14d62ae2b8cb6f9a482dc032535f6eeaab1d04c803e655993b6533b43ddd1f2490ba8940df82599d6f61bfbe54a03c131910ac65bb7428392b7673dafcb8885e585b84498a2e7d64c3a8fec88808b9d7dea5d328b33ab43a7a2a1012ddd99b14382c399d5807a2f55176cc4fabf52359690e7be5041c6e5277cc92a11158c88ed9c48c7fdd9afb078aac4c826004916f2c58336e192a14d59e2941d8883975045beb1f75fe33402a6bd99effe0eaf5a80907bd909e8fde64ed07530bfb0fd3cf778b508ded21f27018a4c67b3519dbe2c89a231cbaac37d8b12d50c64ed701219e539128ec27649ac6191156761c8354fb4e5795065799d8a3a4de43b0be3eb090d8d31a23ced5813bd9fa93bc5d194cfaf63f7ebe19f31f2a52896026d77fdf7e3705dd12b238164898455887826364440a2a60198fd85e802166fe5e331770d464f25f33a3d75c5f434d31f939112d4f738b8e363c3756f822843d4fff03f87c86e626b33cccc9dc120a462c76ba391a6af2d7c656195245cd9e9832f984b83ef2fe5ced89f5fb15539894796b3b9b98c669ce9e0b4206efa6c6387b5d144b2882e76d7f0148db818415dee683eec8bf24e3edb5a512c86ded4b366c4bd90bbe4dc2e8df1324bd07024e277ae6bf7823b5c8f6fe47381af3f1cf2c26019d4f45516bd1be6660487ca330c438ed350de74fa75b281574b9104bd21af70cbda1a125487749f62d885c20872050b98a6efc2cf2a0ec494a66540d4156f2ab4543506161cf39d7cd382d8de143aebee686a28aeed1697e9f7676c840626efcdb699296ea04f7128114c9d7fad739a83982092b3b0912fbf390a374fcf3ad31c57adb5ef1f306a7ba34e25a729c7d1f1d894b10372fa9a711b330652579b0d246ba1786194b56000b105e7d3c427657b10d89636718cd0f5c39e806db149aad4ed1b701009775bebf6b28338b2d93cfb23b50a558ebe41623dca1b53c9bf666ffad4350b09c191ba980ec6780053b3be17efa12dec25b97f041feef1a0e6a2721d627d911e2489248a3256c319976ed5b5d551e96cf348c35fa61063cae8a3a929277e6fb9ef9c518878cda2b1529cd36d07dabc9218ff431faef7719d76557c135eeb98a211c753618f80e74d49f658b23baa87e8fe52081885eb53fa98a1e9e1348019587251a54df3947ade5e40a0f173cee27ffe9462d58a5d086208950c801732a460cd9da202a7507a08ec5838c2b9d985afe809c3f1abaddeb4b999e971e1ce3a931346d7848aab27b6fbacd591ab6e1d0c8815c52b198a4eff7c84e78f31015226cad651eb601cc9f06465db7550345dca3a18b25e91a79052e6113e6a9d5d00ffd8493ef549a958370ad607ecee378848b0e77090506a77f041b25bb21ab4d2a57256684c3a44518680f17927eddf06928385228612e472e13ab74eaf38533803de6c99cd5e57ba828592995e3d18bfcda49be54e1b89841b7fa03dc0100dd59a65743175b2e0e49e9fecc4973807826b1479a7d30727d02eed00123d0438d8d6479ca6e88e6f7807f714701a2b6864d7af2c9193f499295becf6029efed5ac1658200a305fbae74ec1bb0f2b55b3f1f8dfa6ddfe3f8150876e92947850082c806c4a2cf9c9af519624ab08096c105041fd69ce63e31c6a55df234618e874e0f2f975f7f435db8f4fa4d8a8c177e8acdb1c6a0bd0aed07db1ddcb9e30b3d15359473ad0ed979666a0690e76887ea1f30fa0ebbcdee1a4e1681bc4526979ad92a732e822138cb2c93b4c4c63cbf75f999390ada7c1359be00186929b17c9959092e9ba76a02e2529f4c330355c2a694da2e3b4326c9092945026de4e681341dd997d94340cafc9ebbc1d3bd822624ced2051c998cadd87250692d0a9d1029d77133aa1b06e66d99d4ce6051c19bf8134a01f80ee94796f8082b6a4052effd0da2ead3bd450cf467becb3b65258c67458ff17f2446238eb70b13c72e3eae96637695da7879eafb0c3818e868f23f47d0e143ef3fc778e0ae8d7e94e8171911dd07114897dd3f3c31be6059458887be37bee6c7d270da68bb7b5dfb6a4f7961b12c7db2a53932aa7db110d8d8bc2296a2ffcef7d689082bec549d732025a6d2f2f44b849f602e538647240278dc779b757601222adda73c123cd902a234f9672d44d4cb0495d2e64d9b02d30ea569f3498163f139ef20f4998d89785df54750e6732138d01d9f250ea8f59994c7d21b6151c84d72c88ff752237e9167096aa6c3eb0ab993abd873981d2a404482bb94597a826015778a6ac057f888cd79d29c3a00dfc2fef49282ed2a6266abf456b3854998e0a584f050f78833a885d73eaae359830b80e4afa987c511de0b0cba37c3f8b63b5c6ada30a26aed62437a303b8e62b24da4056b6c0706719454062e3f786fa46158da9274f098ab040677ad2dc0c7919a1f8cfd9860954b93a10c6cf49463a610137c9257c13bae84eab191951044930ec13c378faacbf0594b2260176e01ffc827fa954a914f92e9232a32a419ef8728600d23a160f76420369f227637cf672db2ffd28693734c5c5d2b289c578d3fa0928241c9e163d6ab17ac3b3ca9ec155adbcc090496375b82d6cc5b588e35ebe453b07021eabfb0a942f3ffb378495e61a1d78cba7c425e8c661293aca950eea7d5c1c4afce4883931dd76d2974caccb262e386ce21f4d0b3f737e9a1c9ba23c4cde11bb1747a22bb7c90f9b3922faf9b7d28b46c39de3ca52b49efcfb5757310674689c605a80efcea79bf2acf0751c348326f6599d6b468d9e5568b39fd49e773199f7d84f186967210c134690a6f3356b8d266174e9d6ab9a3e4280a78940c3f4318411e911a9fb00c268d84026b1820304150fc4fa7be227d03992905f6830f2f0e713a638e00e8c013a4ac4159ff0652187bb02058f8d5934570a330ad89acb494b244bbf14fe03a3485b1c18794fc9c0680b083cf0c2421ce65ddcc504462c1767ff2341724d53c088f11f29562a3b14b813dfdf98a1856eff03303a66dabb9c1cc665e32d2c61daa34aea3afafc8e76d4b02248a8c40c765c2fa80901d28a4908ffd750673697d65ea23a6e35e376de81096526b578d188fce5a2d26d316f6e42e4710fca1392ae81b4ff2e740551ca5bad15d04f914200e85d762febf3c92024e440087bbe5d210e573c4cb401ef70fe2f6014f2a7209dc4f15cea393d57b8a97be3794ba0d894aaa83dc7543ef800104f27df09b9027fc27239cd4b3ca6cd0796cc2dd1d06974fc8328013c933a4477dbfcc530ace5e3541c3b2bd85aa4745ac96d37bc9fc0f032718dbfd306f4b68c21a1a80ceb8aa025a940ce6218d3cd6f894f858f78b0b6ff31451ae5acdd47a56546a838b022d69c6e04908a6472d6537673508b35c06eab7b4984bf18a3ff8fd6dc0e9be5fbb4ea6b5bdb423e69d8513dcc60f2e38bdbf843d77644265bed89379461183764c508bc71ca6da83ef059fe83eff967f3cc7ad53e727510b7911bdc8fd6f60a32e346a722596865d2ad6e733d4c9cf7b0decbb8dc1d4eab8d6c68baab08dae24233c4423145cc89fd5e59e2b8ff2af6a4c5aa6e6a00a0c8d448587d4d2edf36271360b74b3d9badce38cfecf52bc96e3a87ee05f38bee7014c2db4fb0d1028c9f0f268b0758e45eadd5b883f9cc3bc0c27ca4a48d39e7f546e6ddbcb203d603f52727097ba64c4ecf0d641ae9ca18a2a09782a5807147878af8c4ac19e73593d0f27bb070fe965ce4d0b25ae3402bbed728e9e1995aea2c60834b4db5afa729e1e100565636afb523df61c8aefd14e3b232b0167268c5ff0abf539c19dad74aafe59d27e6fb024603827678d0e4e134dcfcc0da78d98327e6f1f51eab115d81f1cbcbc5704756eba77cfd09adba1a83a7a95a128abf32c74b0b07585df4b88d735022f8f5e7d291de91661616971cd908e6659e27218dc5fef6e4c82fec6e29d9054deb0bad1246e40a0952b8f8331123e7c38c388ad7d20eb41046385007baaac781461e644a0e3444d5f75943677832983d2da785c6618f3f151486de79a4e24536fe47f9d7c08e631be9084d437ae32ef69a94b1a131aa0c764bcad508fbcb44a31d5b3e20692e7aad3082f838699e45e4b35026d32e1a2af11f11b9885505cb502606a0334d6fbaa6190708389b95d30e636abfe370df90c12e4cde7bb03e58b2268de156591e66c6b0b56ef038b7df11db96969f42e33770d3a6d48e060f76795c7014c9df2ffa934a4ea8622c1cf8c6c661c12158f2a66fa63a26051fb4ec1b4e13c221955a711544c975290cc74e95dfd63c0563e359a81e2ec46ec31b1cc37a5745b294ea6b2f046f4b575783ceb26a18b90170fa96100904c00391b761768bccaa6e20fc8cce9554ae24a06fb2af242f00a2dff5ebbb1a39e4d1eb8ef2059f1a4989bb1d443e43a4c8862b3ffcfbc596542ea9d62e4c9e1999a1bdd194d665522825b870a0d45bb2d15388966e38e4299e39d1a167fe1c222af15bad1f0210d2eaa0bea1d2bf8feaa4650c5aa849b2f9ca8033ab47264aad5c6f9d492c0e11eb23d502c97c32120c6eac4170ddd40de8b48808291c0887cb7c81ba8e8402ddcd824c29d267ec669a30f75fcc7cf5daf744a282b238d3ec29aefb2c4302c2078c15e7a114ee774627421e8510574234ffb4aa2169ef554f8cf98dce22c21a08995db4be16daf63f7c5b63bd562e57115a5879c62356366a6d31b81343a8fe94e55979c1ef1b8bbabe4d29a72df86ecce58baf078116b9f55135384d2f21f1aad51fad6d96ad1cc0c9e9e6ba71e9351974ffef4941ebbad658c2bf1a880ce7abd545b7f71823249b02ee6043b475a939bafc723fd99d4957d0d4ee6da0d22692d83a0e972792ff57ffd811fcd5d6cefa89846f39821807e2960250d117dc55af96c8381a94a95bb9cc6f0d68b0a8dd64a084c1adffdb6f64882b97a140bd0599c67d84b6db3d059dd9ba8bf630533cdcf5a575cd696991a578c4de8e0b265ae33474dd4f35eeb6a4e85565895a946ef1d7ba91eb3c839a0b1a7081800ebf4c695f9ce3cb0acb96d7675cf177ed4ecc914ff7ac017f282c4cdb787bdd72f04ee1086377823c51833c795ab3e61d4e3c6a97b0925180bb78a4764180b29517b40bd12e7f9502bd442ce3e363006e28743a9f9d400a0e06aca09a9568aaed3126855d85e20927af35d8af150c07b390350b7a45a04fb1d1f0b62ed8e59980d544ef2445ca50b4d8184173527c5a3791e1e7907288d334751df5a94f1392234b08af1cc38f09fa963067c9e3ae9ff45d7ebaeee5a35e8e853aeb8aa1341b231539bf4415b3c3e5d125f139dfed0b1e7d0ab6a9657634f8ab9120fe46e7c6992fdf1c9d66b196898c01766cf908c7dbea1506b8a5326ecbfa05aa44113c1a2460963a82edb608d0f05eac4d889abe6d3a0d214be5e9c17f3367e2a9319df1663d84aa187fad452a38adac4d93305e439f5fa6c0cc84399f0e076b87a0940213c1d74d58befac94dbf9bec47984de8d7597d212d48d2e4493d22299fd6cd46e3df091f0217ed0c452a454b0f0a7de412300c0c5ebd40548494d6986ec84d007bd603d85cbedcd8392f2ba6360e89c682180103a15f55132f9bb4ff1c42cf7627b56b7992348843be94c6905247924aff08480ad485a479032059268ccce2c772310c4afa9028dd1b539871a3d91e206a1767fe587eb3b6c1d1dfa88505f757c50b8b444ee14dadf8bc2942f6f4be2f2d6f5914f890091f0e74bbbcd359c10f1a17027473ae6ade582950ba30cdf75d4cf2bca3b29d4976f06da1226a2be40565256648b30ef98709663c5d51ab33628745a004dea0bacc5074ba0c8846d2125b24253043cb4a2b413f19e84e965609b45012772b468ae8c5ae6ec8d45c308186104744f747beab7d40e048d2ed5b00076e68ad7eb6a7d368a91ed5f8a0179e6c5f370011f84d0d96a8f9e5d0992e27e857f94cac80b1e1b2ecccb8ebcfeb3db674d9d139c2406279645e97c8e61745f24ed84426c0d9a4cca3d9a70f479e02e97f8870e13671597d6396a74bf8ebf0dc3c2bdc165dcf30faa4a7fc8ebff9ddc7ef30dc3b21a4328b453245a97722d0bf9e782835b00d86de7ac8f19ea4d9016fd7fa7c24ba1f13148f893a5200ca57595151cfd531fabc78919d192fe076cbc90a4aeb44fef43a405772a6d32bd90718dd6715dc1f3d77e9c3c2445bccb83b8c21c2d12b296423a292703906165757f254a727aa79e6ca317090ab5ef8ad615863c7236369ae6f62cbe1701a2eb491f108fa60cb88c45b7612147c14426d3b1845dcaf654b905c2cc76a1593b269916814b5517ff12d915aed7520275b2cd58f19ba76e9aa415df5a0a701b122f4b036fac4878ded1e98d3dbfb6846cfb382dc903c139135206ca146d96a9aac5634391c473021d68b8e5992fbb7e78f6927c9976aad788d01f351f8fec5c7b3885e5eaffe99562e113f2b74335734b544ca998a37145e9d21bf37872a8b9622244ed4b0aff631efb6f1897f1c3e991ba016b3b4c906a2e00d80ca37417464b95b16fbb1685deead4b5ed146854f702f0452a0e9e71c89f11093cc42b5f091f689e329936b5e110fd54a22829e988369025003cbf5cd80eea5cd16d2c1acd4aabe1065c889ec7b4094713904973feec14570da958a9d39422ee7181dc275c9752574633f786882560194d41ab20550ba4614f311c2375b367695ec11a4a895e96ccd91a9af80c04ad39d3216521cab34272e4331792f61ea4310d9896964865a02866646bf60d710d06960b826323171ccf1a8ec8dab68d861346b054c0bb65d27b0ba93d06a448df7c55e6005efa2f992f9cb561c2396de3ccb4f37d95e23605407b3ab9bc14156b80d02120575b23e208e015151c5b96c40ce48210e185b8291fb6b3d38dcf10f4d3aaf906ebe3e747a8f76bd967fffec37d3bf12a608822d8592db7eb0e4d716871bdd2084e75d1e516c45bdf0008bfd1bec9c220808da493218b2add20ae1349e6fe2435dad86df1a54963e6be2b2120372464c9d1737da475485811edaf53741cd904d692dc03bff926e5a2a58485777e5bce67ddbe93027da8e1b933d3cc7224d30b07d133b49d95cbd1ef8be823c325429ea733f6ddd5ff85e75726d492000f429ce268336342e9c45f7eed1de0b546ca46a761582af681456d41612472e55f158008eadf6489dd45db5e723e9479aa10e5b0956f10c3c33751a99639f44401b0f741cb84fce33accd2a79c46363455fbd97fccffeffaf07b89ea947004c6a6fd34a81221342b8a889aba2fc8426e868bd520736dd71568c7f213bc6909b42802957618654c85d5c22d4f67f09cd7428fb6a99062f67eabd0dfb57f63d9bf6b5414e8bea770cc63fbe1690dcf295fe35637e40917225b2e61083d71f4a214dfb218c7866b274c366c10d051232660e92f795aacd1c4d1a9d2bd62633166bc5fe62256fef493a86ab15f30b4f54f797a4f5c29011bdafd281126cde266747fc823be87e2c181b81f20022aab95142113aea228acf8c1b5de5b9d7ffa8083b91d0f1bd7b7a89b155d403efd49cf6b887493330ac1f5d46f5eedaf40248dbacaf40ea86296885da2d36a1a4a185799124a0677901a867f7d4e9249a92c8db69dd3adc889a47174aca0e4052164d423e8c2242c69a46439d569b6e3dbd66b1499c859b71aaa9ab240dce7601323e7f821a0edc859b97c20c5bd1664484ec2955894074e1330e259b8b4a207f9bf62bc8d027108660c914e4f4196f06ad7a203510ccb5795fe328711d49e9a330c08651c9de00995efd35efed0993a27dec350786563960843a11fb8be9751c6c4aa168031a0a9dff4ce04c0a3cf3a3f9259557a3814602b72cdac51976607a98b5169b3f33fb19fdde818a31a1bea268cb970ccd7ba043a13d8eb7bf2979eec28a03373137ded94963ff0248f69e8b2facbe4f1cef16b5468ef942549fcb4e75c9f56221cfe22952c9f367551ebcb032586871eaa89a833ef5852a7628aa74e51ffe426b6f1fc82b503f1494ed7f519f3a6f138688ffb4ea83a10c8c783d1aced63e3ac964ab5519fca6137707febb881ed6ae553468954ccafbe86c5804d65a5fac98889f67c0d4cf33b6bd4db19409c9049665ea13e8526f9e82f2e8960d8a4f4c3dbd8b8a5457334f922aaa92794d490ec1859b46260948f4e0ecb620546d66af41efde01b8c01380c337345d65c4f878bb253b9140bc3b281cdd078859415840217336dee8be3f53fa4a4dcae768fae88aa85a58e25fa82f86f521383675fdecbfe1dbf9d501a1ead03611ed0f57fb3162ef1ba69d8bb82b2d118ea5395a7bb49f2dc98e0b8a6757db57aef90201f74b948d4af693fa8327004d027f4e8970f987a5539699b742d09dba0d2f628aa05bd922168af21e690c6a1b7afa598490ec538d925971386a66c422bb6432e043d6783de94875ca8ba830cbb90993822e51dfbdc3bdcd87e30d5d45bf49c3d3e8d5d3cd05a8e1febbe96c0b3a6ef20f758a9b89bd7e13ca0d6e5eb03df79299f5935477f6920a7a920cbe8d2c4bf736ab4a6c1c9354a7c71f058537a86d9d76c61a8e1e10de7c8ffb3d566922f4b64f7ba2d5b1c528db5e1b8b3c75739623d4fbb9f580f9d034ce1718ccf4a5094cbe21d589be0e94107c56db4e495474ac8e305091a60a99a81dc2a8dc437ab2278edf4ec80b97a67f6afaa7a6fdaebc794f1b27c449ffbc9cbb997d413aed9f84c5c2df9153c907bb9a95fa3dad358000735857b722b08de3d60138f80deb2129a2ecd47e9e88977148166ce7f85f1ae4fdd4921a541d3a83bebbb8d4cbb75d6cbd86f0ff67029abb506ce4c6f61fb6325d62e002c16686cd3dd330c694054d7023674a5ea56b1d19cafa92b3cbb8e0ed47e656d0dd6e5855fff01b27f4e62fadf84da4b0af8abc583db43e24fe8091a98a95bd9f41082e982de3e4ebed784ceafbc1ac6d7ea0f4cdb41fdef97e210dee561128ecfc0063e46f0bdb4b7ced57273335a91f5985204266790ac9f59fbc161b4de2bcede896ccab90a93e7613a280a10e4433b5aa3f08e8cfa9be9fb2780608bbc376f0f0bbe3e4137430994d3cae90274a80f37c9dc6a670b670d60da5dd6aee52677aaa2bcbb2011ed40785be1e5e03a6520583a09b542374141399814f67085ea702ab4fbd0b74e2cc9068b0a1296fed47811039117a094c9113d873a534fbaf110e3808bd3f5897ed58358773b820e3be1939b5792dc68591fe1ac49a5ed19c2c01c8bdbb40bac3cc0577d655cc47a56765cb84e5045101b6b92a298899edda5dea35aea5f2e912df72aae292436f5b6565c2dcc7eba47c64e83e1e9adeddfef06a5f1f44c3259bb1453d4e1c443a73134b2d95fc9d7a6001e4d41f72bf5ae44d2f4a5f08277e36011d9997b408e1bc3090d2c269fb73df499a8f80f6e666ab4e1dd3a9db7dc18b4a048f754a9a4f42c0c6f3f7c20456e973bb3714d768018142bc3866ec3702504447002f85b4a6eff3ee6c8d574371672a15bb42deef1ebd5725eaddd5fd4651d8d31d6c74cf10602f0dd7290b78abcb39afbe967f3fb244f549c5f80c80e2f6a516e95a1801c0eb1a6f98eb6ab7d37b37624281a39985fc34849223c2eca64d6f2a0748925bcf7620c07a9778603a1ebdd3db433e5d01e6853eb18a1cd74f2d318ea1b63588e3eea3039212b78dba7c85ef0900a8cfb7fd2b8a9d86a908a36cb7b0eb6bba8c6a787d334177f85de93a8268358b7043166e9f9442f08c426330a0948fbf6065781a1fc3a5907a74e9e308c420735d77fb5e12fa3acfdae5ee7a798bea1295d2907a1714328849f767e8b09fe0532731af798074420d91d4c3513a0483b0f4f9b1c834fb3de15de6a9c5017800bc2a79bc0efb954fca0f716a4abaf0a2415682b946f9816dfa861c15f0e7ff6d726fed29998e0e91e9b688442977a19722b1356d817a616a299acaedab5452c9747474376b899390caa7f962615ebfef12d84fc96304a8702fd9b5853a52fdf6e27efa4c679a7985aaf9fc215a0a556a230e8c85b3ba225234bd3b468ff3db649df5df4606ec90f1dd8d233067a112f36f1a24a5cf52253057c9b840fdf11c30135ccb4a6c000b05075c103a9aa23ff08003de9a38f15d4b15d026ff4fd0873fd755aef41abae64cd37c43037811a26962f517b399a625cd4f911494cd85177ff89e844946777b8388dd1fcd00df1efe9fd0ee6da0de8c0616bd360e580592f6076c969f4762a9bfc03fc0f22a1e2da3492485b98d4f4747c0d857598e84f0e010aa5116c29878cca6a335ae9a0d28f757b6b9ae813053b2f8e504a3960119617476875db735459251741e3b1ccc79726bdb2509d54485366488e45c12507b5b3c08658786c61081a17d992f5cb05da1aceedcd4fb5a6896fdb6b9c393075aba19739c91725aafc612620f6d3a6cbf0c4be029cf66e9641ee10d08f11a3d1f3cc11265dd1a19a792970f4d6e48cef91acf8ae0fffd4fbbb07d383fd3f1313dcb28d1814b7e2b5c6adb011c467697a070b2d87ebf758284d7c1ac4cf43210c8e3db4557e30c2479c9cbc5164346b9235bf8177265d5ee73ff6c1606702e56b0aed5776f9715bb3faef7fede1ce2f34351f93f68efc5d3333d840c1a475e9fe9648cdbd0ea459d30c55d229c69f70de3ce8c65cdedb86e2152cd6dbc2c9f033e10120f662c964858bf11d49e1a4e1e0b767a83516b15e7f127f7a0091a8c37d7bcebd5d577e64a3df6608d13d596fd2c0bf4d23e3e0a4a58bde0b5d230bbe6285b139452c81de28fbfa2b089687aefc2bf7e2549cc73cabcdd31e7101d6a93d5ec6ed151ea5d43ca6874300534315baf462c6fe73ed9d26655f5df0a2d959ab7d8208fd52e343d106cac15824948412b112efb41926fcb264df3d69a005df0fa15f5264e80bae42abf43a95b3b14366098805dba3877b86269ceea948e94529d5745b33910f72d2c42f69e42cc39bd68cc26b71533f191bc3accaaffecc8576c8578c96ae94c0c2df6c77fde879a738b92ab771599dd6ad7250169a5d85710ae4ae07360fc16b978e898962666d8873c1d395ec89ab7f3fbcc8a9f11f760f0f0f06c0bb3cbcd5cebcc2602a41f2ecdaf89d0fe971edfb01f42f35510a7a8ff59c33a3ce3a65b55442cfd3e32aa1c0532f0c6358e9e18fa30b8dbea43c02c4265055317046cf05dafcbb93f2f783df4c1286a247e89e39a97d7feead71d1fc8787cc7784c03b6a445e22b590d1bc9cdb753a9e96528d597be848f2293590233e9ad75696c10133ac226d50ba7c4f24ceb42d648177ecd6448400d5327e1f1226f6d2b67d641734ab6a19d41937e9f62e6c58890574c6519b750d3daaa2a37332a3fd6b418d1ce59c8e221c29e0172fa3e3e38db31df7e5c27b0f9109c930d4b435c2db02b89c24d4c18c777c13ea544b9b39c3704d40a67d959da44a69818455d6cdefd81e2a96d1ac1ff9273ca816ffd40e6f7ed7fcae7c01666a4e84bad372e89be07243757dac2045024d53f67a8e2c8c5f21249b800a4a2dc94030c76da3d5e5230cc7ed85a62d32ca9059d1c8ab631d65c8ceed9f82e50651eea96595c989f3b5c0a590cdbfe7070b6ba45877effbf55601deae5e74a17771193691a45cb6d0ef9c585e560954126a58089a17a9d948c059cb1f3f401c25d85170fd5340d45f0c3454f98866ea6f6c51ba9193d306da27ac01a16cf7d65db31ee97356da2a443e820cd8d21077723dce0703f366f87c3dc48ba7cd74e8f8485dc5d639bf43af23f0c1453448079bdce6d4fd310f52ceb9cc99bb6af821fe46f23648d2ed002ae1a175ddb77bb4197a713d9a2457cbaf4bc55e59bac8a7e30256693d02f8deba06fb0899f8b38783d24e99c9dd37cad4c943be73e74976a27ecbeace08e5df25c8aa329359ea810780fafc61aaa29fd0a2eb88647b121beab9f8a87db6c17036a8da67ced175590df54a0cbde86a9fad33392f41050c588972bf87d6f929e09d19b1763b9ca643afcf164d22358d624dd174ed83309df0c7733c8d2ae120a7d9f95eba0c1070a0e8d78ced74075e230c9c10b6676f3975bade8314e84449bb614b335386a413f1b256ccee631b24354947d198b3db6ce63d750abddb0189711236b54a0925cbe284dde377ec713b77a47424f37e90140ee4d16fe2daf2ad34c0f36806fed13b4c5036d5202ff573052267e3605fd0c5c8b7718c45a51a43f844cf2715a7081a1f31ca57e972db46190ce1a460c539b9a990c8dbf10da7ca21d1deca717147a5e00e09a6281db6e67a5456724cf09faaa580e9447c44c0b0516a2b6342a10af1ebbc303899a63268694ea78588acf623925cd5ab1847ae7ce40256280221b9ffcc6ea8d7d5322b2e05055187efafa34d418a79e34d4dbc166fefb32b5579ecb95f009e49f138793a3770ab11a450187b3a921fede13940335f33078f4c78c0e1df9170e2d47c669c2112e319672f5ecd6a3f76e7ebb635bc9114412172e0eacad0f82d5e59d0fbb52b984fc6878b486022f1ff3a2e750647f8a56ca0786a6716775febc434080d31647719833c0ddf24d1af2f2c10e4e1bb23324c3a7bb872e1d62eeae5043c6b888346347d05af68066e914d2b95d062ff17f981532606d3d58a02921bb6bd113548f20c273eebe8b3ecfd52907d37a2e4cf4b5a88b7ee614a6aeb5b3bcdd9a97881f00e13bd90e57958e975851b5115e9fc2ff020d23b204c20e0e53fe7021254f4234dfba033a382ab275e551ed23bae1fb6e9c394154cc2f15c049061ea519b9f271cffdf1e042075821b41175cad34b73c5acd2403fd93c95936e50bfee1b19aaa7420822f31bb04949a9e5275e51d196b89fb4081fc058daa70343ad5e5d1a48b679b5af06a340743d8d3893403a25f7cc0084e3e51fdab5be0f3c95d5c2b6638c5041ea6d91461b51843445fee04b0cdeab7ce47f7590436c6bb54f0e038228c5d14c904aa74f25b561bc98cb706289e355fa107bd65154f0389eafed7a8e3b03f59ebaeaf79d5ac4b15df9478b15dcd25f5257d9f809b2ac6bd9dc63a4900965a69f8395c08be5c5df61d4155c6ab015161779b418cb6a07766f06f21cead971ea3c1384de3d23c0073fa514b9490f9a743c2d34a92756564786f920e21247a9cdaa71271191e24e3505802636e518df2b478e4b53468ba20ee98d961c0bad501096a567daa74d31600a136ce0af8fa845f538a7e28356bcfdd0afda6552ed9b86965f9e3624fd26f05bda58357d480bf6304aaa88e7287af3865edaa79f7e80031eefa4cf3ea858193c56552e3c07aa35e145022c057c8056d1f01404d1464ff0e1526aeabaf0eea805d03c16a996b1a3e3a96061dfdbd5a045eeedd4dec8d6b5ff4e85190664bd36a94a17fb213d5978fbe49b35ab047c1d095ad6e0d230c40be1ddef54602b467676c4f0d4c6fe8b99d0025f3b7e4c20633d16c99d9ae9322963ca548f28b1486c2d0012df3947cfa5557e8401d516c98c206591e3cf80c6bfc82adc4251df6a32fe5379d73e289e4e8f3c85f8ca836919155e3ea4cb0500bb8880616046eeb987ca46d26fea85c1d7af1b1d4365d3412d7909ba473f2e01c8cb097c542fd78e79b4d8c906bf86d38c858a094cd79d329de47ac2218fbfc8928d30e7cf5922aaff429b7e2b831b7282bb0c542944a221b888375722efdeb7568f0462db846219acd3a664e946074ca485a86b8c2fa91dd4d7973840bcd4410f08d3b48d5852fdf37a5bc207ca5b88ad8094121c0f36afe0c272ad136600b2634a6f6f0d536657819c3e64854664c4b48305d8929ac9a27ec573a5970cc9478d18f5a4470603c32e19d2c697ab0d48bdd82a11c885daa7345639de560135fef034b2ee1135c03e44373e27509ca7ec2730a34625f4b334636c1b956b9bbd43b25c8074bb358e0f968c474f7609f83a25275b37544629a30a3980d896356ea0754a14010c3cea65d1ef63a6929cbf87bf5b8d24655e00ad191235da6183b59410fde12cc5a3f3493f2c5be9918650edd71564d24c880d4ed501c42c753f2c6068013573f004a927a6631d38b213e42137e5500b18d590767b07ec26b5d7b7f2cd6743bb25c8ca7ec2cc6b55a398e502e0d73c219dd87e1af968058a288face77e64c2a1c29c8f59cd9ed7c4189694cb4be2772c378907bc111b505288b1d60005ffa0ec2ffc38df58b81200680136639ec5106ec82cbd06668bcccbe5aa5f0a189773685e8ee7f341e834337d67c91444c3a4041c67ff1e8ca2dce1c890e31403aba71faaecc4a13aec17a533369f5a9d5c7f96ae467cadf5da62cc767bb061391328aeb4f9cf93bd756416f8b147fb0f929bfe0f39873787ca09e5e6898a6042ec6e7f29502a9aca6a7b6d45e18a73cb3c61910c6519514b821603e7a9196931f52024056f49ce6a736c287b10ca4d3846f1a0799ad3e859ca369e331a2a5ce3f227cc15e897ef1857740b6b5bd841595f02c1be3ed19ebd5011dce8698435d29369a73b13be78c4878944c79c08d6736ab32ab93074fd7ab6d3534c5bcad82d26d1b6498f79eb286d9759998dd40cc6afcbb98e40ed6b1ba17ddb64751ddfd2ae73eaffd49521e92eabde9a9ba31520c3d4aedcf14e019e1f6614eec622753ca829e5d3ccf19a0702d671a71bda12d4261862505b6fd511ee06c8e287c9d22fd0cbffb5a3cc77af8be89c3c77feb65c0999e713bc17d5c6f7c36546c1ba22120253f5e3cb577c91221fad4131d94be7913f124568a52862e275ac9d3e4ccef35e22d32d550e2545e34c4126346c31185beee26f3a232214b742e0989991179a8d5099a9e95b46f5244e1f1e75b8ddc3ee73e4b075b1ef9176f3b3408ab3cc5c06c5aeff11d789e3cc054ceec2c0c627f4cbca3e4d8138f7f5aa654ed3030d6199fbda0ddc9370980da0d5c31b368a648aec51aa71247ed1ceaaa70b2af6313e0140dafcbadff3dcca92ca02dc62225654e3675f39573bb1ad0701c83ba28c16fa4adccaaa9bf8d3d0720dac23a5168d21d4ed5a1918c1563d93d773871f9cb3b6790019c68c61e3fb7d9850b31f9db695ce5a05b1c92b3114305f26de01a52ff66bf88fcc252e596fc6b0e1e3b3c20dc07244dac4b70275c6b0f1fdfe94e7d0cd2371b509c8d674b18fda97d47f8f9c6e47b8659862b2028d213da97aec2a26596553146af8ae3066b66c09272f82dbb44f4c9bf7fa06d6241e2be2189eed52f1ef59333fc0b1bc7a11dbe17b3b6eff47edf7d2735f7b77fc9e0edbffac2ffff6fdd0fe1d32eed5717b3f6e3f47ffc7f6efd0ec56c0888dd1462c65f54061a78ff4c71693ffb1eeaf9e3329434145b6479efe11f7f8bd1e76efc3eef7d4dfaffb3d7aafc7ddffd4577ff73eee7e0f33f6f6b8fb1f752f4bff61f77ad8743750898de84b2c6e75f0d43d0d3189bcaa17631f0610896273856a42938bba91afbfd3082340e6cc9a380665e7acc4635076664f1c07b3e7b660c19e73503d5daa4ae776a1e2bd20ae11fbbb8125eb91f032f6a63cfeeefbd0ed1d67774b41d9466a01a7ef18d212c50c0537ab4c815e937d02092af0caeaebfe7a98f33ed7dc513b9888d3367a13a4ad6faa738e3d39b14fae203f6d276bccd1b517cc8134673026432895f8469e358650be8dd89f58f5b1c5e67fc3e290e47dcc3a231b91b03f1f05fe9fd892a75a3545d71dbab56f0d03158166fd8fb5b242a64b63e6f44fc9092e69eb10ca2d3b0b2a4ea23fddd40c1327eaaa55ffac7e1c0c175f406be1cf5333a40757e71d50b8b12aa965305ba0f7490c0b8727464e14c9668ab1016a228a37f1dba7d2acfcfb36dda06a7f1785711ca444e5b36534528c7a0c73e20024b65977faf2db57007c2bb2c70fb939723f9130e27e63b2353b598c1ea9751313f609bd537b65407bc35a0b67be458b8bed69d95ceffe79fd5609c2b801f5b30671d46f7de16a501aa75f5a401fc888b5e23308d0790d2bd61e176f6d9592e13d7956e5008b01273b05223e5afa905f2cf60affbec51f340fda1970ae50795d5f3176b856017c96a722a283a3dc1a5053daa206696238a08693b926a45237113ec8e4bb4f81c9da1a18f69cfa19d2d2176c851264b831798895b7f10f632c39d086e1ac2a7a91fa3f79ea8e2498c7833218ee62eef3ef6fd905893ef8485426ea672d0c08bf1e3f823873165487e2c5ea851c42af6cb01cb881046bdf9c0d5a93c95aaf471688fcf2dc2ccc02562e0ff012981a72036e34fa0be194e5b1e467f0eadae83997b6b3c3fb3f5a73a4304333da585154ff63d054e60ff9c835cb5c2c63476669d6f780b3221f16c32bfbc93131b8734f97b530fcf91d9c307b8d9454468b507bde9ea0e37b5aaec885dd9b5f0e9ffc01c0894fd4e785c298cd5ef32589b9fdfb23fb1618ec1774f85535a2f800450bc2209f82de7892b0a9d39f630f1665ba056a3754199b4238f67a874281a9ac8e21f802878e97c3ff482fb978ea2c5be1f38e8a3bfd092ef5cef7a972e01ee31bbfd62f7e89a1f0cf0a9cc4e9de107672521798789a13f7215d0654058007ad62cf692fdb9cdadc2af24b2bab0aec98803509e077cfe40b2c2c754d5d86e3de655d31a1df2a3ae8fbfab52aaa79be4b6f646428b6c1fd3a457433512ce0178429d8af4a0213d55a11750931f4410c87659ab22a0102499afbe529c5e0a2b2b14f2a99343ce4ba39d7ce64370974cfae6f2f06c227d11f49fbc32c2631a4082e8dd12aebdac8a70afdd7448c833b3bb0506082423530af88b7d46842157ecf560c772eb1b51bdf1b5da777afa660c2c444c7459b28738a9894d6578d29aba146f552c260291f241fae56b4035e8cae26993784aad1de9be750f43b18aa9d80311a879e0f7f6b3fdfde854816302b3613bb008bfcfff5f5704713145c742b9330d59506235c36934471b4a9c94b12524d6a971bc2c0b64d60b942f3ade7a089854028916a8d2c5c599d7df5ab48b4999e005b1f520b85e8486013a761d84a2cfbdf5d9d4a338f83fd66df292aa2a8dfd6a0b7425bda060fd11b13fc7d68c80a3177439bbd04d7a9c571dec07def4143509fa06351480425e8a2ef171638943b4b23cedc9624e20c5829b9e30b2e37337be212fb40b0db2b6d5c35733582d304faaa14efd971add0cba1dcb58c3c8d51513049d3168c43923f79dfc3d26c5c04360abb096c010672a6d4d3a1cf78375ea791d9700225603d8789c46cb12f7f2327886e34f888f1c2373ff48f1faadc28330767fbb019fff4d203063b94f49ce07486f5019acf6887ba9d529acf5d57b4fa8d5d27abcdd01e2b5fff007a13bcc9ef6df22ac558988c55a65089d99e476fbfdef45a4ee9d0852702e5cc5df283ad7efabdcfdf6d99ef93cb22aa1f015af1ae916d72fedafe97891e6a56415792bce8acbcc18a1edbf1e24afb1e130e51faaf481faceb3b8d73869e5dae08ae75bc9de06bf3615cdadf58c2eb9bf23030418f26f1869c51ffdfedb57ffe4d6461d777173952108b984cc8a73e3d7ecc4d5e53f10d2841b035f122f16da1e8438994a4c06e9179afe44fa8bbd6cd0128e1b7debc31626782fbd4852fd5f862cef2996c666867535adf5bd482832f47a2da34eef4dc4ed4913609d2b9331ccb9bf1028b5093815711bba33c364263e8e4ff3fc8680a4bc68153976e49ebd17b34516134c128ea8ba1357d88c91da2f67bb1a0e5901be444b74e38d9a77041a303a2d54fd0e58d1e4dd4d4e4fc063b62dd7b4d4b6edf3d89c838bf945a009910e5600ebeb13572cc0c98bd8ab5af9baa339d490fd5c6c15de46a2771f46cc9f0366e719d911e57a358826412b4fabf0864bb9d25517dccbb36c07b572fc81b3b5a52e73a33e25b3deb908bc6dfc1996434c3650d40e068d16ba1608cfca57ad614013a77cdc24a33f2a1a62e0b88a562e6e1090b34f445985da48ef65cdb255f69e866aed60bd133cd129d874acbf2352a19c61a7c2b0d81d831f0cef6c2a5d2acf4c283c63ec5ab274c94fe4db62957c745b021d9919739d9481c7022e56af24d3636aa9cf0a4b0cfe233b1ca9c5e204959e6d48e13a6344de3b33d8a158175e14d263d981da7643b19ece08b962f3ee097a4ef0d6681b48d7b3815b7bfb58e73728114e5179f01f18fc54ccecef11f587cd7ee460c68e8920b3099c8f2503324b74b4678f8ee4aaed721d16cbf64233dff433d555b1efc426064c40442ab313e48660583be12e8fb6cdc04015ab99c8691abdb6a4dd14fc29b5e848c7bf789455e69c96e028ff9fa2a38e4a4e3f42c2bc80200459c89559fc51061960779a632c3f633fece7150fbc826b4eb301b1e5f6838fb142580956a20abdc681b25829058b5c8cdbbabbbda26585f24c28b3bc7adb243b609fcbfd76d09b11c6f705f9eeadeff866bccbe347389ad29be2fe5c797721c1a073198bb26cf7b99e407d146d508ae275036b0c69507f7ffb0b028bcb3b9f28f558c27bb16d6f088f629cf387581c3dab679065d4b4b8b7598bfa8dab796b6d39aab61d1550b54b0b734e3969753178d479604100109996972de361b64991a49b08b79b1cd248f0784c5873c0218e4afa9cf2f43e7e05545546ab6647caba3b06e3055f665756d114f43a2f6cccb3600da6dc3b2c25ce1bcb8bfa5a752a45ebbe0e9acdc6029366620d77bc3eae5c05fd495d72abb6424b9466658d1b6777050be21d119149f8d8fd6c1249189780ec55e2e5bdfe8c7fb58fa2358864729f46ef9a46166881bad1cc2a46df50c9e043cc93baf442b3bc75f0a1e96db3c7e3bd1dc28873b271aaa4914ee9cc4ab1f400b9c801a430dbb8b240f80d82f6c98becd844640e8554359653d2d42c41dbd930f302fc524b7928e13511f3a135b01cefd9a55424396fd36d228a4686f87f69a161085de34d071c201f3b3ba80a1eaa7cc918488d337fda443135ac8ea84c347d1bfd22206b96084a2a4a756d378085f7733f83450333693bcfdf838c62054ffd32c21c79beb678286d0b51574def42003b6ca583f58d5cb95437a0fc2c41d1c3d69a9ee0296b8b12844211828a9e9026f5536e413fabef906fe8182af1c5c811fbdeabe300d6f2358c0bd95a99ad0f7435bb5d59c7792b46aa77c10e5e016670ef4eeee5f37d102bbd764a77179e061d317d7080d626a0aad29f53b8ebaf375933f1b403831d87ad272720c33580ab174de6c961cb644a03f5c22c7a43b13decf8583373ef12ae8a70c40ca0190cf99d077fe09f0452ebe55426792c8201479c8826971ef0bea342e5371612a678dded6a918cc7bd5a0b9a5e6fd6f3e39e0c3b0ea2ca0d8d42004bf6319b02452148c0c22131ad76c26743bab6a5795eeab94fe1d9056c404bdc76d14780d428ce558b97f8228235577bd181a2dc3dc71141bf089d1b8e786213de70a80e5bd0d420faf5f6bf7704b61ba97164e1a4bcded88e2fd28674008cb1356b892e45d402bbad7012915bf76f1a98ce802f8966e74629629a575928d5ae412de5d41ced84ad18bf4eb51c0f017b6c3177678ef9ebcd15ce616bca0ee12a8ae8f599caea89d2eef0b453685e629a488449f0f65be50a454f8ad50c32989d540256300f4b6e580e1854b880c9b137bbdaad06f3464e2bf6f513dce03fd0510715ebc046a8e5777b8a695ba9bad6d6633a21b36b4b0eeb22af91ce04a9dc0d51557d2191f12ff34cf93ea87cd47d756c37db2a81ec4ce307e49dc123aa1f4f741078f6f2aeb43de00adbe2b5d44d0acfbe75a1e76583a0c5c7e365e2d160602ed2316a4070a88c4161fb28b5516059d6aa6a22b9c59c4f3e8c6acfe2e52eaf46317fae1b623425974f7e85414d3a0ea46c41b263af5b22264e19b93b5b7b163085ca418123a2c3f6461a1f3b4a4386ed5a7216cea36b844bbcb7b6ee251c0c930010fa65a6a9073e818c7e41bfbe0e391559f61e1f6e22b87268b0db8dcec5198ab377e5884dfc37156721f92128ec27308f8a0908fa07e823fde2c1dd16af053a1d112a08c565d5dd7b327540d393572d5ad81917ae51b39f1bece4fd01009badefdefc6a8e585083bdb9db266cd89b9abda94aa2bf23e3ac1a8be7c8a2852a33d8bb7c030427a983c8bc8bd8b5d068e4d388e881e59c0356b99e2503452d2b746b73e90f348302d442d45d8880eb95aaa6b9352ac017807247bc9b1a8c50b165d4215c7a37e2b7f3ccf56657eee9ae67dc29631cf22c68a623ec567d0e5367334217d88d8a55040c6efd0991d7c879c20f82e6aae7a843f7146dafe4843a378d06899875514aaa832f6b1010b4bbdda6bb1bb009ac885b1d2015e82d2dc789e8e138c06ececef52748214fa74dad2c9ab24c55e36b32601f0148028cd5df91fc00451201ced4c08c6eb19993a283e636b2a38b49278d866ae920e9c4f16fe7e1df53c27bc23f3d9cf9070fd1ebe56a7bf88ffc38f8749f48d403790785924d6b7f1b048384e5ab4b9d3ca9119ea26a02109e2efd84abec599932d917c5dd98dc0ae5dd552883e8c6e077009b7203dba00a53ad2d8703eae5016a5d901d9ee1f588a827d9e4eb5e241235f8ce57d60a38c2bb0188efce5ef99d3fcc01b107dd40ff4193f82847766bb85b130108866420a54c3386739b34cf9c8a17fc020f61ce8106fff68db26c03330b356bd55ffd62a6fae11c1ba2b9ae984ad3f442cc3a50236786ce28df9ba4cd5d83f106fab5205106a1a395e054d7bf228149a140e71a8f44d5adf6a72f413cefacbfaa7d7d595e400fbb504a505a42041c48a13b85eb4e3278deb36536e32c0f754cb9faba6a16d076176fb11317e8077e361e97ddc6a9687e34d20decb900772d7ca1eb8715c4dd6569f009cfaedf3b810f3dd07400ab03dc69431f2d48c37655f00742d8e1b959f9972fd37e8615c059a315606e8c07495765f6d4bafe8d956fdf6023ce6f3fbebf289ceb9ce40064d78503bc9d26014cc25f43c461857521a695becd8eedb30c9b06cb248cbfe4bafbdb8e879a092932913adee89811103ee65bf36650a5468e0f3b2d504f1bd38744238bda47497b5350a7349b7ac7124ca7a75e165e3edc7f61c8a7b870ea841d1d1baccb90a4a0f50c6169901bae0fb0b112c5594822af8a20a5637eac0513e1ed07ce595c2a1386977a4e4ad207e1f1c0b2bb026699116b1778c837826673e39e11c7a44d9d1814c43abd23c968044d4324e6df216110c932bedfe9ada727e6f862d12b6f06f42a0cc8759408e3488b0831861c5bd33d82e71ac8fab886ee9c5081d1275b1bd6ef8708d587ec29f1a8da6782120c302c6aecdb81d22b0300adfb4d4a625d818c738c29679b384afa926e5ec687fe721682ddb2d2d8b8bbe59c1e163cf1262d976d6690dd1febcbfa9d021010407014adb061a5c6d86c2532f8ef69bfe79ca88ae41a57a8072056182a749726eb75d09c70b7768956bce57b4adcc2ab80efe4a2332f8b314605d531480b9bc51a9487e432576ff8d8650ced370d68c5255285a9a676b8cc10e7842c2efb07fb2b4d7067ec404ca76abbda7717c9db9501284f1a49b158106c99836d4adc48c046e28647f08a0f8cb4221232c1e230437a166ceb21350cae41959014de91274d92b002d2bf889a608ca8fbd5af0ae6ef5e6d5d135900ba4fc0c2f95363e97226202697c3f1e2e16fdb7e384444beb28303c1c291413a43643b1560cfa4be2f7a2262a557458c52033bb6202bb40c8d5fff41e2147515240e6d75f3d1cb1613f80cfd7bf08efd87709537ca7bff4f725424e825633a007a33c8d72d2c3c9e7ea3ce9cae849736ce6468bbeba45238394586779177c7ed39c42f29ca6ed639d24cf8db322a392090a919b76b8ad22757c07bba299712be6248a09c176ef84adfff6c7ee3ff832c9cdfd893838b58baeed7e762da42acea787d7d5e48de889ca8145187f0a8e96dc0a411f8897fbab1dc6d0f8eb9660cea256e61e02f18223e5089745d36f915de2fcdbb53554b4ea8fe1e6f672efef7639100bb71d670b9bd9bc5ea5ec506359197768b01438d43b82435f985da2cdc090cdf46ce477191a48e0da8a730c22a9ca82b6020cd6c0d6d09886a7138a0a3c874f8e4a066ff9bf1c5c8b40a5ef66d1c016c9fee06781e7e78456a7404a40d317fded50d120d6f2ae7b762736608b7573d692d42daf0ccbf14128836fc6be15355a65d4b00730f8d36af26c76d7087fe915ce63857ad1dd5bfe4ac474499ebf5c77b42d83a955714b95ca266511c4a919ede1e4c92ce99d3cae40ee7ef43e56793afb58b5f6b97cbeb1211e63e5f525a1b6f62d9d7568e8c4e5396b1f19bc07179e15e4750380985411f376b3dbc078d9efd89f7181d42f6b02234b4de0f279c3a3ac65f172c204a6bc666324e3485398d8da4e5bdae6790efae72f891730ceaccd73bb17d6fae63fba9d052b6270ed9b6656f0a4a965e38255c447047f40c2bfe488c1a6ce6c60fbfdd47029f64c3cda3367a288cb292ba374a2229d4e04daccf04b43fa9ad6db5677f69dfb111db405d05de7cea443b12bd61077b1d609f305dee7139c06e4d8e3a95d7a74e7051e039f55efb25c20a56d188a427df7aae7c117b900b65ab1def5667a7a0a7f2bc457fd21ebee29f09056bac5d8331d70f97df48af3f3ad627e8933fa3d845800892f41e685f1983d289d407d01ede813f1ad7cc7c8f4142be8b6106874035f7114806b938417d0deaf7d112d4511ce1fb194eac1531331bc06ac3df18e8c7a61abe266a9892bc4c2a8cd1225ea867b5ac14987043a2906c4f3c72499e8b05b767db9741dcf079d60dba789442eba2ee276c6fadcdd9b54330e1c23f91b3a90c193e9c130c9713534a44ff0b00d90c8e094bb2887206408dc61a5549c60e81e62d76878c50360620bbfccab2d3f718dc20a7b43ae445647aacab43bba855c8609e9df3b02c765650db29f1095f69cea93b102e97709d11b465f5f163bd5efa96422ddf3739c15d6b02001670ab94b45ed2077e3355e652a133b01bf8b9ee05ed8a3e43454e1b0964781fd01b541c106f234038471246e9bbb112d26faf02b8a3e0f8ab285fa841375887c7a2a4aa406e18294a84883013e7b3f11fd65aa48e2b80662e87f3cbfa7d85cd3a1e113b840a2bbd7696807ec3db07ead9430989b7da1d39b7046e2ca156b79666382cfebe577f15949ab98434695ba8fbef87a8fc3391e49972466bcf46eabd8423b13320ee5a775a31587a5e41a5a447c0350134b4d7902f10d1d172cd928e1d7b8c16ab99aa470d118b2e3c4369b8aad2c7bdb61cb095a026a7ceb4045cec46f3a82c09108568680c0c594eb83252518ae625f34eac77767fb86bfe86faf8af2aeb3dfaf0aa4743edbc04bd43f480212b5e8c06d616d89d749ad0818bf2a04f9e1aa14a8a718efcc66a5b04934017b112a4bef30eae5f729f6968ba10e68cb11f4a40adc120fccf304849d8d1ef8ad9612dceb12068e4f49267db115c10773ccb2b26e45d04dea31742e23c8b8a200a73082fe7e0746953f9c5c3186b46bacf66641bffc9eca06fa41eb01bea40ad1a4dfd17aa510ecd3571ba26841b069ff34af224700ce7b150409153116b68f789589d409dec1cd98192fd6a0af48f9ac6ce2ec3a4de26ee75893a2f46930e7f07b03235d2c234a185d7b9c58fe58d13e83e6752675a1e3a3c2da9132b5f7e55a593af69b6301cea52bf7d6f008fe769dba07fac9e808d108c2ba752f4116c09fb166c02fa3d0fba63644cff82e58381cf547e703343e14a9680a2aad15a2e1e66c1582b045a317347afa81467e659bdc517863eac777f044b1ea63b2cae433c48cfe49498e989ac9679721e63327d816845bb0bb7f664b7903dab503526f6d24e18646385b785889c0c61787104c21ba18d3342a64d1074d3ae240eeb4bcd517f8235973fad20a64a387bcedc29dd83f502accb831341812a51e62012d4ff3d460f03f07145099396ee6606950e91a09e5a7faa590bbac57104facdf2d5848fce0a06f84c4a9af0ceeffcb28a4e66144bc12171cb66d62a4139321eff9b30da104a1c85538cd838a691f5d9edb9be71cadc69fe3c6d3198346222c0805ee34c7293102dfe88288170cd1efae85e4aac8c858f7c64093228eb67574f0acc13ffeb9029d1deb37e7501400410189d3a4c67d70425e005cf1685b0b69d152bfa9af894f9ab7c15e60b2537f864b37aeb03f9b3f2f79a353f55029a6d9b1a66039ab53d53fd814d21b43b42f7e36a7ca5e3dfb0f31dc64eca037ad53c091d65ef52bb391c31d5c53f7a73af98cc3753b90b0f1e5274d91029c00cf0f1d0def063be2bfc4854ce33be0fad071dfb6c4f4ff67e372dca1af78d013a909949f9ca9aa069a542a8979f25d4a115d7f82c5b9977e5a135bfb1fca5c97badc0562346e9d269c50545bb3166f526a9f1c160956b61797ca9d2dc3261d063ddf66aa8368086dcbdf4c59cd0ed778eeae4dfbaf6a545cecd22f849d89ea144673b1abd2bfd81c8fa77ed962a51a980ec63fabb68b4d7e94ba2ef8474ff93d45b431035efaa9049927c4942d4f69f777e1402c54df2a4531d52da29aa63a6e5bcc7cd1ddba773954ee727105f6154198410f17699af6c4b079d59ef300d810fd90b6ef986e7bf61eccc79c593702e480004fde06fac26297ac2de1e16992dbfe2dff1a8e1d5d0e3ef416a07f898af15f189459692c3e127a694cb21b9db05980028b90b3c2cd16e8ea64fea6d667adbe8dfc323609d18d7bfaefd8a538439d71e68fd486489748d6075f88591ce4225bac8907bcb750942503d9350d4faa4103fdd1cfd9f39f4473887637a577d1854c9178ba30c8b4c49854c7459aad663bd05d3770f5c33c886f9a395bb71ba01d1eec2495cae8f01d9d6879ec471254821e173d2b193a4f1321f3af2c47b5b206ba5ace0360057f06a5ce252ab1480ad9035f5d58ed257bed9972fb20a92f4568b05066c1ee149500323798a26f3132ea5b1f20f76191161f0a18d7c5e9c5534604622e03f955e97bf447fdd9522668a988b10e37ced23597d5e1a1db78045baeafacf6aa42f224317a859bf366198c84d351fa4ceea3fb01bf5139e01c3a51fccafa0f0223c30d18ee2dbab4a6ad60723ef61ff2d1362999e04ef6b2d0eac53bb86e3858e81b9511fc26ac4090a5e0f3991807344ee8c076b25f7706077ed846c08cee490f02b74c3e1db3bfb0bd0514c761e30264746973477abd44e7566412b2b5736d5134483ba6fec687fe258e1f5b33a0886e6917d5cf96ed1aa3f879ba04700d204c90e99c1e1a790134bffd32d3ecaf686dc878b8e716beda618807472251f135123bdbedabdcf8562536fc1febebcbb29ab7263041aadfa510b4fb7b4b567ca1d3e86ec871410c5053e775f35b7442615e4d79681f1fd48928a7760b18a77372957010adb751b8c3522609862e6ff1746252c2b630bd79ff4a15c3507d50239f9e3f9a0a7f47032b50d52bad4f81ec0a517c528b2d4ff5772e70d0eddb24ab4d6789d734e64df70ba97b4f0950a98f8d83c129f1f6e3f8f238aa48a5261253aaa20ba0e184e95074347796eb87e9150089e3fdf2061a209449e5ce5fd476f98f68bdee78281a24fc0e6bc42d04fa3c9d793dbeb34be44752711b0e8d9f57877be8fa08cf9ebdd07c1d799a10d01e58fa9890e1089cf8323842ba0cc6f14c6ed111d2954e722c31d12e170181f6231033acc44d35546b5cefd4bc950ab68aad07166d41d22908fb8545c3600ae26d4e41aae7b7da8b5a228acc858330425ae4a8c5a17ab55f08d80ac63d5334d2e84ef3716210b3f1157108057354db868345b6a4f648de524cf444f192b58009a1e8ae4e69eceaaa01f60cb83bcc109905d619f8ff52ba83f9b527c83a7d9e2bcfc61b0840198e45175d5f17925c9449cf19d42864e4839bdf683a11f1f5452415f78ab151e412911e6ad4ac96a08473b1517bff763815b3b1684bb3c8ec4e65a63587ee50cb8492b67f7dfa3259d8e18b4008563c0f31a0c9065b12091576fd7f1a18a52b62d6ab4d9e1c3bff10dcf822ddb0f85268b66e67abd079c190e2f4cb3a0fdb0c2826102de806b33fae2027f2f697b064b594165b3909deadc2545c0b710b985640adff85c96ea25a13ebcf751825500cba7740f35c128faf7c2944190831a36a5439f0330b6e3b25622c4110570a2387a09c3a540e53410c3eaa8d3a8189477b75259fb66cb4bceadc8231214d36e7ade98d972c401731c932b6cec9b999874cdfb30e647748a7400919a542c1ca8ffb97489f20ef5011d81842db6b0f2081d41b8e74584555b255edbdaed78e0b6284b0be10b48048a27f187e574538cbb588b31d6b3bfde32aa96b4c13c9945cdeb04b339ff836e8e2689e5f44b52c6263f78f987537262691bca385f161493a3738b6850a342852517e2b90dc337cb871bea077839ff63a6d6bec7114f2c3de0a46425c3e22837895ddd230d8c1781a4c64aec51bcc510b2789dfcb9a96f078a45c84b8f53a0c39fb54da4216f60ce70d65c0d065fa8e28ca87f46b1b9ac4e41cfb5e535fb1dc5df7085b1332d3ac0aa244411b14ca75f5e0ef10107183052feacbc5cd500d59fac2a24d04416390470c5d8b4d3b22c7355b4a76cd206954ab94755a6757d143cd3ebe2d2db85b6cb1633492ad8e1ffa3c5c1b409a9cad893ad01ba58ce1001aa4882353709851377fb7d6ca63f4d5f8ea166fd222f2af9a78192b89b52f4b5d4d84d360c9f5bd43a13e487450db116c9fc5c5c4e3624da965e6b5ef90b59504f15560d9f10a6c8a6b5ddfd7edf706b564fd624b9949a60d0215024702660e7feefcd598daac56a156f4d9685f7d8eae0a5fef49141786b94fc5bd9f63ad47e28f7c42edaaf75bfd8afa5dbbc8751cd79cefd7f67b56b7fbbdb7ab6775bb3507c5f7b5874d3b7d6f57cfea76ab668da94d2ac5798bb3cef524d2bf99c3acd13d3d45d7b9318adc003067a5e4903b00e6a894eca4d791351ab9eeacb350fb84d784d52541720b2871e00b7f1261d573c53428920b437ff43ea4a33568ede719bac28de54845b9303c05bd7db4868f7e53ede74be9306cd7e6d879fadfea57ddfadab6f441c55c850a60faef6f70ffffff7fceffbc1eef7f1e8fff2d8f67753b1edd6afdfb5eb73746d973cce6ce4c1f379667e6ad574396643f4b9c49439944efe7eabfbfc1fdffffff39fff37abcff793cfeb73c9ed5ed7874ab5d66f7dde71969b3f98f69cc1a4d5c1a1305b326cfc85acfb350ebe3ce4a21250e8769cc15c8a5318988cc9a9159d3cb5ef6bee699ee9dab47751dbda146c85a9ea138ac248e1f640dadf1f3b57986da2885a0b5129767a928447a564c93aa02b55181ee68d115da5f4f726790dc17be5e8eb1ba1c3bdb1cc3e707f9ef6f70ffffff7fceffbc1eef7f1e8fff2d8f67753b1edb4d8f5a8f205c3b53d80c705569668761d34e7ffa512fcf4e3a6c3e1583fff42ae6a19efbbeb7dfb3badd5fd79cefd7f67b56b7fbbde756dfdbd5b3baddda73abefedea59dd6eedb9d5f776f5ac6eb7fad4dbf2810661843770a20a810757e6e67c65319f988abef7debc0681ad20d01a0466cd3914857428abd920175f39efdb65385e46977b75cb07abb85c977afb6431cd19ab2eb228430ce32628bba5d2ae490acb5c91462adabdf796f4c5c149e5fcc24199c4f0645269f7de9b429d26a472cea8a6dd7baf5649e16d50dc4146a07d237e3ee24dbd2d56c95b3b6471a539e7d0b662dba8edf27db3411e8a3a720e6d3ab076195f34edde7b5f21189d412f214284f85e381bbc38b2abda89094599e6622886a18c3649d9200f6932543636c83ffc859355461733f8850b181c883bc8e52f48042ecf3767182f5cccc8c862623098178c02984c5199b033d639e7101f6185c0b1b91dce0d2677099d0ab24cdc54d095415663f86c3d6cadd6add62915ca42ad465348aba88cb931b7daa050a228fe3c8669d46ff57ded3746ce981b7363ae45da481ee6cdd4e15c4f9d524889d3bd5093518752d0ac29bbe9c3bc8d3bef75ddf7ae33699556999c66da3d5808fa84bce7d89a63381d373f76dc9828d5fba9283cd5c98599e5d9fb3ec77edfafab74afaad4cc954aa55ff77d35a6362a9cea475785fcaffb8efaa326b56808682dcacfd7d3b55f89dfeafffaef8c2ec748bf29ead89a6a598bfceafdfab5fe5a6b57e8234a5571ea9c3bbfd6ff94f56f0c4fd6c81c7e0ce9767880d3fbee755dff31b569b56e3af4733d897433c76fa247d66c6c3820bd1eb9963894a75de81765dd75c8dd300d6a248a8a7da7aff77501a653e98422a152a3146aa2aa52b5da2b164bf681d997ead435ba5a442d2e219717d0cb4be505f3818189b058188bc931320c82604a8a11948138c7e4307641d005de19118b1f988fca4b05f4020ab984442da2d135ea54939c5c69891d842b2cac1283cdb257e28d8925067b97aad244cd516a4442ed08545036482a9d4aa7e9349da653e98422a152a3146aa2aa52b5da2b160babb542da2df26f9eead435ba5a442d2e219717d0cb4be505f3818189b058188bc931322c930965643232d90c8c730670cb28c2c3086b56f49c332a4db73b54915f2446f6052e24d103880a282021c287871432a8e28a2a8aa2288a4cb40144e0d022c2fb19863cf1392011410d613886800200e8068c4f6787e8e160000bdc3eb1a27ad92438294ef8f3f99472e00029b5d82eea65718c18b580738508fb44c28ebd92c1b4b15fea6589e094b71d532f4be48f46b041fa61a7ea65737ee0728e309bd830ea6573a48c96ec560d5b14e925198a30b1a7280285a4c446dd28d1b06136438030a2bc0108294639e8944012a2c3c3c94ea997d5c921b1a0c3c45ca2630549ca669550e6d8a41e7e972b147b46bd6c477244c7c23cb2cd1aa58f8dbe3052b24f41f66fb3d4cb1a516246d92bf5b246a628996c558d12093da8388243c49125371ce19940ec52bdec911e9b204820adb055ea65839881c4ee967ad92070600e24b9350140bd6cce0635542f5b441bf238e710c45ac414a8721bbc3c8738a4c959bc6208de9c2fda006c02d00b22fdc40669a09c75688b6660917a00e6613449d92a291b7ca1e61cdeeb420d739e516f3d3d6aec744dda1476685c27072cc0c42f67dda1061c2106176a3c089c3c4901c4d598f2fb0ebb53819311857db9cf3a74c1b379088e2e1aa8cae0a9b4f06601d8535b3eec0f5669a1005b6cf07f605369993320f29b13c85cc502b0a77e5c32421e866b786bd721320fdd120fe6074035db50a3a447c5393004b30dd3d0c29a1e98e6d3230c6fe10e3f15f31087694e15f3b00d797806d610de609acbb23ed1c62ab9a1d2429d8a9bd0c29c8a790866916400ab68906c005433c7a4022c1238d1539367618d4c80450d6bd85653b55051592cb1a24795f1edf886695e9cb069b78f07e459ca315f8086067926e223c724c72b9c85630edef26c735c72ccc135cf4c8e39d849257e726c3aa1f22c85573ce42c8e790579d6e29ca73c6da5ac749566ae4a3347334fa14ea5f4e61829f39199779a394bda2353519a412eda073a545ae616803d8d336f5b9dcefbded715c4e19a8c39d67109b898e3da0ee43d017bf04cf75aad56c20cccc129bf3be3b2b91c0cdee01d7abc9de112590cc3dce672638364089a815c5846945bb8863715f64981f0c1a51d19508663722c8489309f97ca0bc825d422728da9e6646b655f57be2c96d55695686a84229d4aa6f334954e24d42865a22caa1532ebd6c84569c8056a5171f9bc88af1026c3702c0463ae6c8506822a130228cb31398c81a2f85379a9805e40219790a84534ba469d6a92932badd083708585b569ec4d63ef52559aa8394a89e2af742a9da6d3740689bca804cb75ca96d188200003190000c23014c59128c9d11ce894071400144a60505c54309c47a481582408e23808a11806401886010000821800aaa8625204f073b99f25f659e99ff5feacabff2c6b41efb31443e3feac82e1d47e634d3e4157188fce5c0a6a87c2e4935b61f7d820f73a40b91b76f559585be0c6ca1afb2cf4cf7297b3e83f6befb36ecfa2c7286e8691955b819225b751ec8067d83ef7e9b81b965a3883b10229ebaeb3ea3f4b8f65f90df24c3f2bddb3dc9e15546b35fb049d61c8722b3e9fa87b61e6b23d011f4b69911e791852457cb296bb064746562899f4ae2fc4a7cb3724b664c87755b44b37937bb67eed99fb6c0f4fa0b929e4c90a49ef610afa0e858ec10ab7d1ec0970005c792ae9717a39d154b22e5639129c797139f44bc987eff6e3e6faa848043d909df57ee3bda299990b8a13a89758f6add6b6d4847341c809721052b5410102e49c31a8c279ed209ae90eb0744d0c8f3649c659541519cdb1ab85c2a37a907bf6758a1370507162ee6b52df2adda593f5a47147d8b5a4faa741407e674eae16522444cb8ab88e6e4b92bba65d206895d8d48c4db0ab13e61ba543981d360e18ef3624630566fc3da50e58bd704bbaa88b900d20e1ad8ddc424411726e49ff0da50c170df0a34bcf4d4ef699ce91f67867df31aac00df7514f5a330e708919c9737e500f412cd60d312b5eb11055d0b611ed5c6e0d026d89f2447abdfe44480e8eaf252b7adab16ac10866567d03a1183aaffa1eeecdbb19df785f95280f58bebf4f7b2439fa89cc3d498703f61d33fdb3dbc735d0e34017b1f9ba8001715947d1f07810d8ce0911dc9cdb40b9f3aef732caa3d2951d496abae9179755483f0a9f518207ea7cec31ddfd55a2e18f2827a076f2680a8d3fdc7009bbec40d7abefe7e91e9cf730bf96698723014b33fa7068773630113720f651ff385b15fae75e8f25e2ab811c8447cee128c4b69a47ccc8fa47164f9ad99d51ca1a4a83ef5c1fdc17460076643dd230ba4814cc9f2f71980a2b20049158aa9b6c268ddebb51512509121e9eec274001b5cf557a6f533af6ce213c084af1c5a87dbecc9773ec7693d3e78820daa40dcfc2cc10a9b54a905bc5a7ab2906200d09b12c4f206a491bf84d3068228db2bd09ddf90884ab413d624b88b459a3f3188abbe04d7ebb70b3c6f0eb31fb30e02ded55f8ac96ebf4eaa8f76e603d5419fb92ce670cce2ddd38529f16a728da8331388da67aa39d1b794108248670ace17d9455ec8014741b9a9f27ca8e8a96cd6c31412b087b5bf9d76dbab519e47c57987087510080e1df2baee809e2ebdf659912fc455c7ced439663c051769f237538166259bef75b49bac1d731ac8fb550223e9bb237318d11c3b875ec114ee4266de1171ccb4d8cb414e6d7ded92c77e0b229be3e42164198da8426adf0f2882c8230d5362a663267c9e9c714aabec7492067d4f3a895232454c0cfc547cd623e1c26e3b841d4dcbfbb1d39c52c8238771ba121c11eeba306420fceec5e2b875925079a2b300ad3d4fca846125c49c1d416a1e462ca263469859747641184299bc00d6a3536ea2117fa3ae19818c4cb3e899720aee5905d3087df33e415c6b99bd8d68ebfcf9857107336a14d2bfcc4c75448f82d96d48cc6add6e6a460c25282a5f6ccd2ba63ee450a16e0ec415d30db22c56ce1998c7e1f30a2d1c40103bfb53f52caf2cf0d7d3b585d9df589c900d3b5032a0309d544bf8b502d99ea927e932d19d9d80dfa1c25d85339d7038b671a64c8f3fffbad2a3ecfa89fd8f8b4a57da6a577653c81b1ab19c1cac63385bc5d88ffcf129495fef7b46cf81f23a4e635fb83b840147397fff4ed7daf8bcf33a38ee5f1391e26862320479e7fefeb75f138a3dec4c6a797f6322dfd959ddf7fefb76a16373b9b517a88502f5bb483c925b6bbb2da1326e001e571f3bcae94c23194f2038d4e199a4b547247723a7b5e574bb8704d66ad9901fa8e6a91c2d49912cfa8919d4ce6adcd955a5354113fddcc89618c8c90006f9f4cbc88662db718d13c403fa9618f189da1c57b984bd97ae8fee01639fab814baa6ea01a41492664ee3586faba53355014000f00400eaf0500e0762305ccb0e57169fe279c5142cb5666e4d37e3402ca18e8253cfc5c8650a73849f9fac9779581aeadadaa419ded0682a6a00e60d4539cc732a5e30942caf6472b29c1efb76484d96ad0c10d68a4012641a008a21bfc80092ee17161e3b6137723085ad97086d0bcdbf18050396475201983c15f9482a2c643a15adfa68492a81a93150644038028000e00900d4e1a11c0ec460b8960186f033de5ce12e27fab0b51607d2895a407b903646b5eb388a65d1cf4f2d14e4b5844ed73418af6eacc7fa56f277a040cea06921deb4954d5cb45df152698a7d2be1a542c710557f85a6ad79fc521dbbd39aeec024f655f6b9d45408cc632ec9b7ed08194ab12820f2deadc10f5decca8482549961ed65b251cdc95704fcbebbe8ca875878a95bcd7db0a5cab940a111a8d8ced2931279b04a8a13082d27962a35f3304d97be057835157a3fd92c104f13f300654bf066c61bb3eb92df08a3e43b4de79211b0f01e14bea4e9a421ce4909a00f2f0fb329db19a85235e6e4fd25b55ccf0826e8d8cc7386613715830cdf6b517c6f1d066aa0e51d58e06440736dc87a62ead5058b16cc37a62dd0638aa315e25ece9ebd1e54d7746b00aca9f1a0d478a3a263fd2152d862c228fe0bee0f2af6b953e1b9dba8baaf93122ea6339c7b1b710bec055620d26cb1c8c6e01a0eb000a10f361f74e3bd0adbf060c101d8df84c67d3002406cfe93add5024194014efa20001ba688fd566ac4bf154280e27fa7c38b4424c59f9495bb7e37175cffb671aa9e0f16eb53704a0035f129190cc1c9e9f8e050dda4d01cdf8cad4be4e8f442406237bd676a6ec41d1128da561dc28fb3a272f26671ad888ec451c0676417e0e57e04bc9cb9bae1802740a370063ba09fdf321eb2d1594902f6802aa88792647b8d249d8dfbc0cd00d7b16e3ccf9f583c391c393e60b0646c7c61cebe7012bdab8cf73bde8cd24024d625a46a3c50b7143ae1c158bb8a3f4ff3bfa802ea2e67243749b612da2a13a0d5aa08ab095b1526439bdcde6435147bbf7e8b4894b89f1cd4e233944e20e6c4f15a425ec05f2cfd9b276440941fdd8f10dd1b2e4339d9403593db61500dfe6e1f23a16a204c186fcaef47d38e60c0a0b53411311e7a3d450bb9cff6bceeea0ac35e63d04b4cc14fd4b09f21eb7383e9f34a2d568d5e08c2cfe8194dabd06911537d0777987dda7e2c10ea497c221a7f03d733866b3fa98a5701b1e6105dd7e78e019a3f9328f98298f4972106b88f519c488aeb390011085ef2281d16a65e248c288417b3fc03929301359ea22101a6651ee0d2a4ff37d2ccf00d885b17673199d6df2883d521e5aa9824a726c76899d8c1805df0c53f79fe375d205bf9273326211352aa2d7d9f44e89a84d77419d0f02ba7df69ba57342887ad129e7ede51d32eba5fd2ff0f5e00975958fca5136d0e80236fe2e53185faec9797445ac8255ba4b4e7775e18835fa4c85426311c645a831a4de9baec4f9af240e39a03726f605bed660c0d485b9d8fbfb14496f2d3c1f6f88f54eb5ddd112f47c09235ce7620900325f94a369a4be51837c8f12fe6388aaf438e668168b60a803a019c46b1300afe7d35e69370c8960fa302468b9310a257d51d17d02cc7b444793db54290ff4dda2cbd2e75a51f80d2283529ffeede9a2be23fbbc3873887b1d319872b0c2dc04fc3fb3e867186d5b813447b22ce74cad0dcd23749d742b66fb64ea3a02b6614ab79e3a1f50dd425e94e3385106621d43b378ba161a9d10ab30aeb65fdaf4063efc3a150005afaf8335b5a5628b40c59bdf1e07be612de1efcae842e1356f8713424c412a5b7cfdc644c361e6dbc97ff612866d28a93bc6fe7f8c5d183de1e3300d36fdc35332d73174d007f6e99df3e2d57c85da6bb98630234156d6f71d65b4de7741fb720661eab47a1ceaa0d8e41496278065aa010d53f65f40fb382d028fe6e886d561cc613fae6bd25f3c9770e503732bd26fe3d4dcfe0f5c560bc0d5e6c03b1cf802cb1e6606dff0854ba441634d5c52222c261120b79c85b149767128564600702af15d2d26dfd427d8e3b86d726501d3b51dca405eff10fa68820c8bbdc7e6865527b9a52a656179701cd20436631ba3c2d586ed6e9ba3d197f93fb9675112b88367128ba72b3011254eefb44e85d2bb7e9d789990593c65b3712a88c9faba86df71921490f54b9596fbf2d13da30eec83da707c7a534665fe6acf0015f4a1e75085708628ca72d2f626729d8db9c9de6616d6188e66b3933347d740516306d25b908a93d850005dc46c5adb75281c9634da958c96cdcb275bc0ba34ee6901bd49dd33735be09ccf6131cc352f293c67af564cae86e6f61c4dc4aa06c0171588ac62311743b2e7412495e5cff92bb214b79a29eab1012b3598da1883b225077e9b15033dd854dd659d9e7a56d3a9a842214f01cea8517e6af79316b20fdea939aad24638dd20f959f8c8f5220b780699faa61b15401202a562577dae8ad3885e84f8d64997142f53d59b34b0053b9180d4cdb91d7f692eb585a758aec6990d711ff31dd459d723ce2c2bd1b822de3730ce7d32911471dd892f2a19918a92c19ffe38fe2a54e2da9d0a1e6b2651511d49a602acf2310f66caabacf9fac0f5124b6c638c9a4944d39262169df4564998943842983e9f02f047d34f1dfe2189ea8782e09e2ab451247b594a4f9ef8826d2a837d207590924d72c4d1d0e25f6372e2630dace566e75bf0a919738e324a4b6e3a0ec19989480350da41b954a12921fc184e1b28fb027411bcbf3e000ec68ae4ed7f5664948c914f28c465ea6165f7c58183c9a9a1ee03edcb4bf1f0a3d24b6e1460ae2ed58bf22e3768c66917a465de49e4f9422e273dea03ea6ed06193f2605a6f95d343dc0d47d186e237348bee22fe0caeaa50b1437a1688477018abca869d6ff4933cadc22a2d869d624ae0cdc6712d34d2765c93768ada51ff9def9826d7cf123ffa83b1df6dd114525147307cf0b99f42cf8286a6fd33d951051b75f62c1699e454706466d88caa8f0e21c16dd747a0b0cd894287efd1c7a200a477951a507df43743f59ea1cd7a167baefce5c780899fb657cfe9cb53edb8543e20b05ea151fced431ef3fc79bd58164030935d85b4f778eed3a9f64d623176654ca6acb8eca10115da0befef1686133c7299e9f3cddcaa28e159e892c50352fe31d4fe2acb09cc80c01ca9c6c814a5498d0c681835ae33ccb02553bb8f9d3aa8069997e1ae9cb397fbad08005ca5cc7f5f4bcc8febb6be24ab8b98d6f1e37e2c505d80e576635f0eb4f854735facbdc1b3a9cd54db525ef9477b7c875c07a77222774683213ea4f3260b9c696566cb7788344fda9e21185a3353a9bdbe644722a1b338ce685fe245d47323a90f2bfcec6ac3fb9837a36f8dd7f1fe3cf2bf021fda97e0c5ca3ab65bbb6eb8e64ddb1dd7a53004d8bad4d108c7479b462ec3227a6b49ef924cfbd11550f102b116f0893410203ae04f81ba4ee8e5230067908119ede282d723145a4d481852aacc9fe1987ff01e61a98224af8d011131614c595e839259401954d619546899aef6c3da75af2df94db59659a26823135ef4d9e53fd3dc3e663e42bba19869caec9c8d05132adf4c873da8104de1ae07f05fb4b2cdabb9789a782ac01de833ad061feb31ba555bcc84ea251cf69c777f15475c19782e484cd7b1a5fb5070ade3c76bafd6753e0b4d35fb4c19a1b527dd81bd24f1b0151728153f0bb71bb8611b201c3070ecd54133fb149e08d44553d2963ba1331cea40f096b32e70095dc4001d68c97f46c63aa5e1b56fedf2db182923906ec4c0ab42fc191030e2361cc2a4cc89ecc0796c55185118a3cc9bb8d8a8f1be34d8121eb58f3a5e6e2fdac780eb4974f983bec3302884fd632207fb7096bbb0d170c527f1f3d9ff043404d4aa5f17fdcea644df84d21990d2746950522b94d8c4b68031f4e18d276185c7d4d9e666153b9bd0c82802b3c9a08753279706509f2409e5effc6d114546a8ac3019cbba46bc4366060b91b8fbdd22661537acee98df14753d50e5b8f973a2fc5eca63c1ef4c108198290c2d578c6238fa6a78907c00d9164e8755b7fd4ab2c7e9b0c4cc5e4049176e7272b0796c10cf89c4341d628ecc0fc3bb27b5d7955793b8311458a33930531b652701d24dba22fce50a8915a33a5c643288c671b5184c616e686c6e9a04e80a6782a65f84bbbbf7b39cf08a6eba1257da6e2185efa0041aef0e499ece72246705f89bf2d71108ff98f397a2a4d227f29509fc69a253fd74a76979597c4cea9dad6fcc99fbb81fb35700fabddd55438addedca1ae20b2fe6bcf089c2966f21267b81ecd46156969fc5fa46dbe5b9eb6c494fadd46d4a4836b5844f69d0c398ba15023a546aa868750986733b20ccd2ccc09ccd1419d00cdc88c8948d9c52a96cde412f95431d4071a3be526322210f59cea70bd9a206190b1ec6d6b335922cfe4081c8f3f4bbef06057a02a559e824e99d8378d21b578a392d1156b7f41bf6b335588aaa5e4298a12919f8dd123f5b1561e612841e4cc8e2441c87d531f9524b53b7b88590cee5589ca9393527d1d99cea25325550a0cfcf43683fd748ec8bcc8bc90cd3d0c584120194e30622883719396a3f0902403209140527a00250b7102b15f01a703e6dfb815fab06d8573f43bda38969560beda3df42d29248ac7ee18a49864de6ffe81c0d3f83eedabb6bec87a3ae80be2d01452d86d547d5c886a12512a6b5ce88ea58ca41141296e310e2508a291512967310e2e69ed492429f5ba866f56354bd27323094aec9b010a0a053a6050ca41e3069ae9b91f0d2df454b9cac393b35fcf12a408d7c30b6ec8e95eb450bb8e93c6e28e59acd003c277f44e7f309200089270751600476002618ae11ce7386bd37305085a96f954135dca1ea1768981590ae05146a614d9253ba594520a6d0394039f032e5cb08cb8dfdc8bfe467990d5d3888b08263059ddefd0ce53710fcf50615f8a7bae2bbdd535dcc3bdb6e7e3a3e1c4fe8665124c9027a0005340ab00fbc0bd1bcb98c7adf5b6b72dfcdc9e462ae8b49f998fac87e60224f39092a4a4a41c3a6ad4a88123870de61e8b1eaff40f6cbc297aaafee767ee2387dc877d57e896beacf4f4e451281ae5103a9208b66c2107044def6dc3a336d0d96c46e3a298c4933c0dfbead8b95e8f61d0e9743a2174ba5c2e97cbe5f6de3939688b2466198dad7387e97558d1630a685f84ed28515040fb1b96c362599dc3ccd19c73be330f9645010318f7d8dd238a4a38c618176157e210048c3590c35803b9f36c85409b6d869996dd174eddc7dcd8b33d7aee53d78888a036bc6d5796718f4a64e3e0b4d96c428e64e2dcb3aa75ad25c4f9356cdf4b81994f5156653831ce332dbb50a7d6b0565667bb6717e95805f9c985b2813a553e137950d08062a04150b481731c677befa1cf078d1a47435608cb830a25dc6acc1d44004ee9f1c4023d2a500505128ef06eae3f4f14f5616518e3dbc379c4d84a1d7f3e520787a2349acd66e6741ecbe575ac9563b0117ed4372eec4b8dcc0ccaa233342550c772ea3b6f31b8322907dd64e0628e62d81c84358998bddafe9b58e1d4a004fe0cb44e0a67f6a6cee665715e025f386f31b8affdadbcc5e052d038f3eac66130dfe23f5de34060d3c7d777796f7cb9dc9cbe35d3defb8816d6e2745e0e4e6747c551ff168393096619a89f5534c5260ff7fcf41748d331ecc92bcb3e39e80618c341d30fc6679691ccf05fdcc2fa3724ab19037fdf47c979c3bf8ea79a88e4a0191c8585b80903f3f8b14fc7b43f6b60372c2401fbd1a0b01b96fa9b48fe3330bc94550d83f1327e9966c6df348f8606f59a978374c8fc1a1e41a8978eec3450376928edd3437ef634e8ccbd4138f7c9c740ad8f7e89a3ae90e8d5248f8fd02c27d59d62fb61202e2ffdc6087f5b4e7fd9cb5ef6b2972dd2341b4cf752bd94d5ec6552ad43f3b26a82c7a9613c8b97cf1e06366e2c17274b99eea95d756559eae79674031991eedf1e92ee977437a53bb8851b6a47a5fb49ba7159cd4739967dd2a874de4075fcec759416ea981eea589594d4389e278a7aafe2df6f99e64fa6f88fe98df257a9e8d39b54bdab6ab3d96c36d5a32766a5f24765987a797c62aa1cd33c170fd5335c19ad4056c2bba676c7c344f211901b361bf96fb0c9d28719a24248858a5e433f2f301e355141684888e5cda18ed3eb2f8b5f59be3227449c70d0644a93274f1ffff18421a2a1a12541fd6f7049d3fe371855e58956101129e9059b44406cda28c678c50a9611bfb22b53b20b3a71e167dfa37ea58fe684e7644742c67983514affdf6054d2e757e8a22cfad0d0d0100b16324c56ac58b1a2458b162ca3162d584657967d0b960bfc8b9864f99bbc237abd007242a118dcfc07df42a4cd7ff0cd37d2e63fa0726cddd6e9b4d66dddd6e9469861efbda9dcc06e1a8c7d1fffd81ffb637feccf0985241b48f64a1cc531971bc5205641ecdc46b28398a103549c9cb0d8b0b1d9ede4e474c3af0792edc4ee1edb89dd3dc4511c5722942dc289fde8139db638ecb19dd8dd636f91dd620f2428e472b95c2e972301cb0dbe9d58be9d38df2cdf4e54b0006d383939e11eeefdb0f9e69b6fbe3710bb0812eea9e963784f4b4d608c9198909890989098b416e680c007507c8b5bd4e9c421f6105cb73787da7c081970002218ac4a4ada9b236d1e3c72a408d30f28be85489bffe05b88b4f90f51e41b76c5e0e63ff816226dfe836fbe45a4cdc51f5039b66eeb745aebb66eeb74bb2adde642a4cd837b73a4cd834054c590140c06b11831826ab3b7b84700d7706f2c815c5909443830a6025c72de7a8bb3de7b73ceb917592ef68ae562244bb3b346b49c2e2f30b48ef6b697706be270c7cf3d0717872fac01e4b5c9d55f20f8b0af9b1e96bf9da6a7a9981ac07b5a6a2285f1c0706238396a4e89203b3e76a6848e8e521f518faad7f65d46706f66a86b781ccf13457bbd9b382c3fee85a0b37399f47627b60387c7b31135df2bd5680108207b592d62a4d98001553c3c26521e9a166102073949df5b5acda4f93d12fbb8b5de9a30f4e6df70ef9421c8cf7d97d5191d643e20bc58f63543e533b399d15cb49a9f13246e1a43efb0206ad435337d110110100af406458a2099a05a8c2b58b3a90802e30336f556c75c4dbed577d9055121b4e385d7db2bf3f1704e0011ad70419162058b73d758d05ab46c1cb457a4ef6d8611870220b708c5a6a217b5d8039c746b788795c42166fff52e7708ebf02ce35e0ff7b08e07cb8205cb887b165e489f47ad217178336d8e7c595d1ae221bcc29df1b8b20c05f74e5f8ba21d9dc7732529a27d8ef46fb887f381abc1d1fe954441a311d96c2c584500a041d0a39a10f4d5e96259de1bd10260e21e8a7b29f6f95c919d70626f4260d425e849ae5d7619e92dd083aed477596d03ae1a9b6b5323012a1cbcd5b4b171bdeeab063bf999c05bcd57cfe98c55a73356f3e6e6e5f2d79fd9041286b0abe97d2b75d9a042b0b79a69d7298ec23264b7ea1a1e885a4d9caed39c0353d36ae6749d92547a54ad668912d909d207bf1c1d1daccb409454899d1d221fe8c0a783d551c8841b7a40dc8e4e714e31c75dd9f65d598c65b47ac07084d5c0d01bd488fed6a08303c375c6aa733a963e72580323b320c214e0e2fe98effbd817694e444eefaab92f01f86bc07d9fc36e0e107e195c651971d8c5b979d9b86a4cd3e45bf3b486e4d0ae39bdeb8cfd009dbd2f6fde5db9d572cd9e844fc271244b9e1e63a93b9cff76bbf9af6cafad6c75ed5cc14ade2e5b9beaf282736e13a68219a2dfbb057fbe5b9dc74bb7e7de7c6119f193f7983e8e322f21426c5097111a12352ed4e62573b37fcadb1defb539845204ae34b639845204ecb3afe4b910ff86711e5f812f711f5fe22b7c8c2b7d62d9964a7c4984f11ec771c9394b6071b5d2e93c31af5c5a1e6db978746c8db07375dbff9b3b2cf29a1a6ffc79ba47acfc981a5989e98dabbd6d794cf4c87cb637c132e23c983c73ad6c5b947bdeb6c0f376661a5bb642eca97f79abf27634213ef6b7b2d5b0a95fa666b9f4cf1c9f9f3dbf91674fe7cd8fb29f7d8ac379737ddcf6fc7c23d7c61cc4f333d7f1b38bef72508c9fc840d8c879dbdf47d66362d6d2ae720a0e0883688050f455117dbd1288b106e7c5000a3f19c01a267c54e322c29b99862461f2fd9ba485debf8d49987aff2661dafddbfe99e983eff26f920b64f998b3b013524ef262a8e158c53c01e5c4300a8a45479ce9ca0167bdb9b81ac9d2ecac11f8babcb8bcec92fa0b0b63fc0273009309066db1f6dead9818991819254d323332334ab2cca03328e7600411280d4a23228d66076848d09058f281922823891a1235bf254b4b6e2c1901edbdf71ad79227238679a1a5a5a5c5e635be6e5e372d31e41cb5e0cd5e8b89d2185c92e5c6df78263b26bd8dc2c0c0c0f8f4c96e658989898949614ca69842ccccccccc070c62e858686860627c7494d4d4d4d4e09f209239141674767274ac798349e3e76facdcdcdcd8e3a6e1e6a4c8d19d929c43a4e4bf8685671707070784c942851a284899ee06e1902b3a6643e321fa82c50533f2553a2a28c3d8acfcc67368589d3c86232a3cd68bbeacc00ed87f613958577fe9cf839a1046a65036977703e9d003a61026dde09840208484a6c42b33a9bcd6628502c9932fefcfcfca448b1e437b2a66073879aad5623973a8e97233615013b58bf76cf8379736e5ab8a471fa460ebae529dd3bd2383607c9689f06a293744b964d992a6799fa4b1ad74f8dcb41471aa793344e0bb1f8eed0dc00b318c4c841b855ba21030116f45ec0b8a0c895836e77a86e1444fd244b1e0383de61318632eef0ef715fdfea07f3055996649973ce3973929324274b7e018c171d8605305ee420b62f0ee43ed3e45244383007e12fc3a73815cf926bd70a8f07b9902c7f40f8901ce4f3730fbf6ffad29bb963d6b87f5786661567507ad3df4a6f6eee6f63c9819cd6c753b5115d2a5f8b2c39300711d9ae2bc35ef4636ac276745f96b9ec300e1cd23def7ed5d3ce474ec2ceacf6d5b87b99c70fcc6bde2e05f84bd22c49d324733b944265966404158ce379a2e8d5365acee86fa447b3ca928084ddbb5d0810650839f6ab5dc61a190c8021833bc220e07af0fdec6394e408c1a8a63bab3b58bfb2fc985778454b8f585ee757168c05d2934841631c61991c4958ec0a5dd2b35218a351697ad284e528c1d89561df32f388e5f5f47a7a3dbd9e5e4fafa7d7d3ebe9f5f47a7a3dbd9eb6dff7defbc3d5576bacf1355d449cdbdff80eb68d805c38d92bdb5d21f3afa47e96f9f966cfdb2b74c52d8a9cf3587be894638174ca1d11f9dee5a09cb50fbfe48940ec763b24392a41296c304a8f223b1f8218af5761c34652528dbd7a0ccc7b6f947f7d06ce5839f1c537aa2e141fb5d67bdb08b94d7b1477705929809973367767f638c689cfe2dfd4ecc7eccfec3d8df6e457986fce7750a4a10617e201e7ad53d7aecf037d470e538173ce5b3eaee4f8d89fc12b3ba4f36c5961e10a082ef01882340941b72e56723bcb4fe8851d4a3624f9546822c62004288aa2288a220c4520e0ab4cfd9ba7a28948d9061c130ece3358e58795950ebef62d94562549950f14c15db82c11e67b56833c3cf144241981ae1de561ceee67ef8b5e1c75281ef8d95f906b98062e188525c520ddc3f731e238cd40f43dab22cc8be6e83b89a288b3f4254c2557beff7437c159025438b26ed5acf98722bc75c69ad3192b962a52ab39769d6e283c44ad26e9036f35cbaed3adc394a8d534bb4e3194232b00d77d8294e16ab2ba4e310e138032b59a23ba4ef31086dd6ab6749de61d4ca85acdf3cc51ae00757ad7dc825d46fd82aeea0452c2436a3561ba4ef3ae06a7a83537d9416abd35744038b5e6274fb8354749a169cd1b80f25b3307a89a569344d769d68146d48a9d503549ada62b9038a854ec9c8aa963030000802200e316000020100a864442498cc228946c730f14800d597440685a3692c943a13820863110033114c3500c08500c8331cc38a39052790b06ef7603c01189de3639f212fdb5dc99e0418fba4407b7b7da5f49f0ad1c3216c30ca8372cfcc5293f042cf120ecafd1298e0c37e38be34b145e988f1a261dfde866cbce9d510ef9944592345140e2c2b2d67882ffed0871468ebc3f1d4e52ebe59e1155df5495e284a8104f74975fc0a1c3ff5363facb2b48814e9e0265ce73267a61383036da3097386e4cf603fe9a8426c620f88bfcef64c038e0ed0c10ca4da507da3eb5055dab9565b2d06eb55bd072bb8a3164ea073a1459a96d957e1aaa4ec39a3c3136db725bab9e15233f79d1f6cd1a84d6019b4ad7626ed377830228626403184df78d591d18c3d630fe456284e2ed64eb42a0416a598d9e1043c80d75933e8e0127ca19a13fc2c49bdfb134ae52508eb1b3259db0cd0b68b5e10c07814f2e0f35a7d495a5ba0504b2ec4db0c06889281550f98b54e8572041ee1674b800a40fa81510a82c0537b7a60040d731165398a0653f5b39a2112524e8992276107486fd383ad377711e71ba5f26cf0c378e024a6786cc3ae0c2003f78c055bab0e77fd577f27a0b5be62d266b5f1dbb2533eeb82ae63ae6b4045e1aeaf36bdbf2acd6968749cf127a640d110422e145a9f8567f87ddf0b3dc9af5da6335754a5a7d10702865e21aceb07c44a6359629fbd079cf12070b632d10947f73f33b40688b47889049c6597004961af2c4fbc4e5190d490ff4b39dad438a50d13df70ae9d611236b9135b87a24e0de549fc21b9170583ab628e03c6b04b9aac3b683f85542128fc733f78a30d37e855d61c652cf46c5c738af38e7d52d05caaa66cda3a4241b12d4b47a743e3c53568ba83e5f11de6476d3f3cb51bd441703310efde96eebe2883f2046eda54d0757abd1f5110bd241401822175aee07188a25a58bec87427b01c49a0e7c350d88b715661b2a1a5ca34036642d4334478963538fd2eb741d30d6391807ad894a6e15b6085f74bb0173222c7fe5dd28a2714b31ecda409b85f05de20baeaf699bca83365b90b65b8e06c62c01ba02a1900897cbd335f7441fd66e70397af49cccc2ab4f2ad8f3aaf9260cece89f54a08be006aa23b8c6b1f1f2df343508e5645f2c03918cb378a2ba25fc6b6b2fecd0752b77d41b7b65c5be11eeed424e2a52a99cfef79f7b105a63d573e1615d0ca3ab03dab0a11a97c5e31bd0c08e068944e8c3047bad12e47992b540a22ee240ea8de994bd3e3924d35ba8358a529211abbd468633dc67fb908d7fe939e7998f73acd84106136f0b7d2c7340b04f198677a3fbed8f0ea8dc5a4caca1cf08698b89c905daaa711bee8873649e4cee4fdc0ab1293a64b5e04374effd29205209fb24cf411b0d6f1ad0b51c0283c230a2704ed3d1f8fb1239349c5f9ef676d0c8498d2a9e05645880b1efddb0bdadaa247e3b8dcc98999c8aa0f666cf76de890481e69c985de28dd555509d9442136caa14f189beb91a37a71411ee4d7a3dd1050a369b1ad08cd0405890a63dabfc29717cf4c035e1b28cdd2ccd3fbcd9d49eb4cb850d673f8da36e55ba3be954968d31cc1441b5319b1654a3e6438c6077fe19defc2c041d9a9645317defe1ad867a4818e98305cb34b4ab05e94c99a55f4ed084ece3a32ee938f762fd96bdc15623798927b588243600b8f312baf02b2c59ade03a0bbcd98f2f71ba61cd5a922719cc29db93217fec9ea820bd999cd48ecb4880353b2d0f981f72daa7e81e8a91e464e2b75ccfb5255104447401063c5769df2defb646cfbc48b652c8d1a2ce9ea7a20cdf11d334b6a8b8ee96d12c39a7e01be18036a7666e3459cd7704f40c0a1847efc5cc7e4e797d9393e2c4bf186bb8451c40804555d985d29c188f4284770845da1521f8573c6f2e01ebd0ef640e3183bde11cf186c786d3760e650d07c0af7c438976f377446344e7d8861b90c188dbe6522dc3e4066224029eab3dd6e5cb4880fbdbbd981c9e4b3289bd1fe9540ab0fa92be9f668c49c8e4540eaa71ca3a13c15872ab5474361168cf7eb1c6740b008ccbeaf8ca1a003e484539a50a8e93f4deb95722dd7e097ac3b23c5a7f5dbcc3ad1851b286d50c19f05e2cb81ec6ba545f5456a03b8c91bd3884ca5414919a4463270f264700ac496731aae2884dc858f96441b2a0830d2a6891127a3847436c9c711420af1160868a48143d5c6c8574467eb61e6aebc9281cda3d60400be2df462bee755581f7ace1376009ff3e0944d6e8c3ab4533040a08521a1ea8f05d63f6464ee397281179bac42088fd2870ddda680bb49feb0f366c3e40bac715e30370072b8bb9abc4997cda8cbce00ec6a8d4e290852fb872e156950592bcc018c63166a25f4e13c7b2b012fd7471819715309173592ded240f4e1fcb3f81c0d7704258cae3847e64ae6755fd4475f5e2125559399959ef9f05a70879cb3feb36ff91ce9b94fb09510e59953397d7eca689e7c2caa068d42525cb4b99d81f530bde6c723fbdc6d5460dbe769ef863abff0883a04444fc103626559785513e74daa99efe444bf8afd19046002b9dfe8459a955ab1d6de82cd170572bb95d48827a4db3986d4ade42899851834d889901351039a64bf15e13f7d3697ac1ea4294a52bcfe659fb46afac3cd90b96d31caad4af927095f249c533901dda18f50207c5a1102412b36398e5c44f00758915732916cffa8289a6956ee0ff6cc040f5034b71ec1b15858d0f2433df36e9ad95486e6eec0586db75d76d4035d61a51d9d9872c5a5ec6ab103f9e95448790368bc9fe0dec075e7685df800f21612d137378baf47c1d0a875d28c43c1808d98a99c62291c6e0369358f867782e8d13cd322331a7459e0eb4808ae5daaa40295f9ce09f3dd7e890b38c887c037bd09c1657018b03e01165528b1ecadfc8d5d8c5cf6b44d5a272a4499a02523dabc1c37fe4bdefe6b3dc8dd00d4bbfad5cff58a31c86a5d8eed537885666cc7d1efaea7b07145b3eca0a1aede8a8285535ec50d5e6393f4fcbbd45061a8b8a97e008a804bab46d8ab9b6a1a713160ad11d4c36e612996cd86debbdc7d985d7a3b564b34ba991d7c66fa40af45c68eda570c4a9763a36498a00a1d20ad8ab69b549751c5de9328bad724a11d01af899a529b4b6523ae2543b0d9b1444243c30fe9a7521e512fd2fed35291438d7928e2d09b13c0a8fb3fdeb93ac14c78803f542a56da406e7fbcba242935a1a11297af8fc4acea70815fbaabd94f288a4aa9b9f3629ee8f1eb5fc8c56983c73c0cf45ea2f21639220363b1bdff0b2a09a11da681e90e149fd74fd4e64257f39e03712c6312e9915cf71097d4277ac8197896446ce1bbc01f3b152c5705c2f36ede3899aad292e73d907e110c7f9d28af43751dd6a713f6746111e4afdf483568b86390e108b0b455852cac457d8dd2eb4fae943ce6a29b0aad0a05e78e51b7e94842fae3d5fb71f3bc14ddad31301b471f3372f0618aa8642025d136e8036495f4aa40c7133bc1e82b26790bf5cc9ab4e338cd23accc0b40c144d29a342f68d337fed661118c42238495644b67afa3048e19630281974655109f14c107099877be7da103c6680f41847487f4f102f8c7a1b506164677dd5126855128855c5c1a3a9ba2ac9b7b19540b537d751d97b6aaf6de20e9395f5ab502d5900b4b9bef97f0ecddb2f90063ae85fad578bd31dfa01a0e9aa55111b88fc70f300358356d39c47c166ec9f00cd6c3dabca188f39c60e9c0fae8e7577a73459349d21cf4a4317398314e618de945f78865b6e080db6661c2982dba9e40cfc8b0e678fe3ece8863f9b76f5c13886224278fefa81e320cd4df62f436af885dcbbb85bb7d05a64bf1f4cbfd3c4ae9815ef6c23ec75551652e31285c1dafd02a9f9318eaf656785e37d8b704d7dc9b8e410ef0cb6eb14401f0d0f9e04757175a7e5900a4d9f60a3800631774f9a4140183ace0111f87daf2afc2c1fb5aefd461828e5c44add667eb423a843d276770ec4cf540939a08a9d1cc10da9aa5579937117acae73f8884547c888b64021dbd879bf69a6b131db28217b44a06345f45b4fb7bd2798594e359e0e6c9ab58417a8b4843f2ed5d9b33efec45aedab8f9c389ded7c83a8db127aa432ffeb4917cd0cb753eca9b556991655a044f3213a0e982d59c918460e8e3f63fdec6e1654c666eeb95fccf16befe3cd35494546fd25cd9307ea92829a215d22260d3b4674fa82ec121c42ec5a26da4bae266b8a8ad0fdc19a7b436ee4377d689db1bd62ba76a130c65b6f30a3da8cfb6cca4881343457f245aa460d9e9d4e507ed37216ffae2c99310ba467c9be26216afa5e72708b07fd6cc52a21b19c3b6c3b57f8afc19ed021a37f02ebc8acfa5520a29f2213718f87e26eb88f6d3075644c368365cc3cd2a1f132ac369da44d806b61d76167a883292b8ab781144fe68881ebe3cae0dd4b1798695ea1edc8af02c85583be0672e078073ccc0c0e40f2188990566e4436ba7ddda43fb3a556254bfae1cebb9412525a52a35ae24fb702c5c3c04f2f779ced70e904940ad74d8a671f3f59787d5cf23e8d3a06ddd418a25549beb327faddcd843bd2e877a9299755e9718c4cb128d79ad41eee003ed147f658ed3609a03722d13205a5a8a808d46b8cbca88528d403b010a3979099e5fc4b2e73e9d75f290f97199c94adc83f49c709618619ae409d54675875b2d6192b1266c9b6cdb498759a7032595a2eb325fc1f6a85895c6493471559285d5627776d97380d24cd0d2278eac4ab146700fc96a062277c4d47c31fb16e12cee4f1397ad1b01fdee3e9c56c1fbe3a3a3433f8fb27346d95a163bc7cb6a01314f53efbfed9386251db06b5ff6ce46468469b3f14932fd96a571d25d1bd6282692488f57878b545aac98fdf649b0fd622bbc2412b29feb91e67f605121dd70b668c304fbb2eff2c401dabff6289fba7dbcc7a717263657a26f348fb8535143122e2b356f0c1a03236e0ad7c3951ec273c90811ee79d49e131052c29838a2b4219020cfbf779e4734e04d5dab73a2d517417a4659a140bae010030fc5099bd38785a47a7d3c94a34560ad46a155f0f993eb783764e15a106ac06f75b95e7bd507a149361a3cb9db8cb376516a94214e5e1f0f08e2dd179ca6ae998be6e74065c0f240d8754d792cf93b60c249a9f9b1a9090af19487c821358d2e61745a7899fcc0386abfc9d49b5d3296900363891971d7f240b3e19e98bc4e4abc9febdfae996c3a5f4bb6eeeca7881e7a7ef196db941da0e63941df5218d0c46455ea32d9b0fd745c8eace3c4270318a967cdb673d2ec2b9467d386765f3bb3e479cc234ffd75b3b0e28f8a8edfcee25ca8ac41beb461b84a395f1390fab48b3957f5453d58f5e0f34ea90ea6a87a07e87e9918f60b8a55f7b26e9a611ef69195a6585aef990177c3ae4174c11c67885e987c9043b9ef3cbcbc40b911a66ab700da64042fca38a5ef822d3d743738d95d5ab37d2fd7fae491ed30f2097e7a58d0a1288635669e569afe98d017245bba24e0c906b85868016fae30e332f5e5ab1fbb9da5940a0d2fbf37c709a5233b0e778b29a39bf1bb5068c3c904a9cb4ef9355f72ea6cecf7cc3298b5773d7fc4129b029440fb97525b0c0c8ca77946f0661302e41dc3980d498f5c4a209fcb2024d72d8b9e67b0751a801da389f3e512186446baa0234a1dea8e7d8a188e52e57031a39de9756b1a358880108aeff696c0816e115c073c9ca5b3f5920438c55fc48652930912d8c48f4b262d41d49b35101ddb001d147a7ebbf53abbf1490e9d454af6faa95d9bd8ee814046d6b172c919bdd434b7cbc7d4966acc95547a446b575c31da3ef3e20c6d754cd3a3c7ce2f6c899b11f4f621c69a036c1bdf8385fd14fe98b11ea6b30004b56e9305edfc10d061ee9d2c60a773acf85374a47e624967adbb92ffac7d66dadde91b41a4f469786a65394754c3613dbc4b4139f3eab7de0e9150461d1aacdc5aae71f1b7e9d15adaec458ae181f7dee38752d8f91a6657a5f24cf8a86f87bc3a36abd4085a5155769367f6df0ea5f635757f91afc4675402c135594bdec4aec163f9ab26634a58cf475066625474af6e6738f409924d966d9e095cd58ad4819469a2cb2fc6258dbba630a9d7ca597ca03775ab2c114204c02eaefb6370fdb55276ed86daf6ca6587befcbcb0cbbb631c2f2d5f07c1929c6e4f81cc20d3e9c3d7277ecab4588ce7712b1b02722052668dd9d7fda67fb19e67f16b28ecec9c9cd7d712c7a8b483eab5bc7b4a32c71de778e5f1c786d1e8d7e91d8fac5d6dd2bcf3e206d5a3a2b7d947d5510246a22283ae3466a3cb095ea2c8e1891680d198866947c6516d5ef2e2cb75261b282637e338a1fb899752dc88a7acf8affe0c586987a3e570c8007bb7c31e89863ad576756470ea23d8593b46c12e5c03cfe1f8f99e0c8378fe64c35c676739369e5851f6ea768a88f53a355b58e5124ef3b4e03387834812c6de99058b589c85c0143ac7689c0e0d744d32d859bad781f00ee5a929576a9282949e8669121a0c5718d1dc17b05760049428feb359fc1a0cc5786d3013712edc991bb512fc4b33756ae06673278894d2eb7371114eba9a710b9151b567d586fc91805521b9e5b6c88da11d8bf082488b049bd5eae46a6b47000fd546a22861faecaee776d6e2aa9b839ce94237b67a44f424ae1581b29824ab12d757b546d9df77a4dffa3b88842a7488efc4941ea834dd96ad7aed4d91b8dd628038e06602c06ffd56438928f27c654500df180f15a5d07d6bb27e7a04d676b34dd92ac5541f2dc7035644222563de2a7b4fec251439c0bca10cd0a9185ea003372c023cd5cfcf769520333d964b66e02077d650a5da27821468c4b59d15c684727d2497f9109cad73f4b03e15f35f8bbd081905e09d9a673b5c045a7c2b61f43087343c32183ad79bc3fa646008ae17c2b1ad804c58cdc3f3206f9d9083c77a66cbafec2a8654c7b24e3ed00ad002b44c055fde4118849d2b1c84a949d58e2fead659347fa66fdb4103425653f8837d37c2c9df451fc57be161c5c3821878d93c462178d178b8e104ff2f92704756284076c0c21e75413e49ab5f64ccd820e22a77b0f38b14db5adfa63b4c3e1a0f23340433cd09a3d01e8cbb310014a45f94d420ae680080beb76598aa9e26cc5e6746ed98866cde4183063c80c1925f0f11ca33742f1be3627c3e4812b1b08bd390ceeea18fc1bb3cb204e11c7df6b82c2381b112db7ffb5ff6ca3c0b6f5c893e8d5090def747dc1eb7a41219b8ca3e4ea1f7fceb2648c628a68be780fa8ec76a5a26c75dab720c80572d97bf2e16bf73481af76229674e0c4d0a592236cb2c61c451c61e12367346150679692875841f00ee377589f22f7d6aab65769ba6bf6c5c0197372aee1bd0510eafddb36a95f1930c6341962f06cf34e786d8a4699c04a38746a0980c8b017a71cfd9341773a382ef7b32f3e93c62f8b128fc72ab03c70a219b0211e60ad3dc2f128e5e5738b7120a36416dc54be5fd8931bd28c671e5b2a1a53885947c98b26b3268b818a4171502e44156617d398994ec18ba6b18ed607c59b030df119d5a711a01c69f9ec3288a711f05cb3b2e9ea45c76e475646787e1fb79a2d9b0e83789e01cd2d2b9fae9fe1ea18d7d21639541c08c00ff0031168a94fb92822527a0e9292c9f93aed1b256538df35a3be10382533c113bdd4668833431a567c7dc367c81fb4ce9fbaa0fa47b0a5cebbf5f0fe181b253913dfb6df1bce060fa741b3aab0ca78cc028466a55d8290af101cd516ab5f33a35c2cfaedec43714138bb93967dfc33add774687c189ac5a365ea356aa5096a91f035d9b1fd446b563c88138447a1f3c803ee81e9eac8d7da3b0d5c9bbadecd13fad75dcad055a10862a91fd4c60dcd0bdd2f8f756c2ec2a423e1ae59039dcc62aade18431125447af59b50f38b4c249243deb1cbcf73520a299eb07a25a13796c568988e56901bfb8f4dc967e7410ea310db6d89e059bc7f37b37e125475e052db88dd0952971fae45c33b7d58875a15d2f3810549600b2f027e1cd95a51f80a56dfa4c02936edb3548c9c3721019ea63578a1b762912893c19c7583c204ee73f45764e2f9859c78ca970e898a3405da4a09e97e4311a1319442aa0c78c220f985edf9a42bb33e0a42921e3e5c176038cce86cd496d4067c2af9c72d8370b8740befb5d58e2cd6f164c289e9fefe4cb918d5f2199f3a3ea05f033a3f5d943cccbce368ec0e2adb42f1086a8303e2dbf2565593320d88307c29dfb89d459ab1cbcaa328a37f7647b1b18aefc74d5b657a4cc73ce100d5e203682fce4134e1158e3d4d31d452c83aae9eef0ecab1bd17d0257157cd24bc1234b833a78a418a36b804ea86adcd50cb2342e3f351c1cb7bcf8a4a730ed13b08b0154d577b5da8e61038e629fe43a3c8f4254cbee923b056da040469476a02154e278dd7f96c175411f5e46368a4d981ff80c8665f167a310207a72112433b59766bf9081861ee4f373403e9020a201ef8211821c8a4d49aa2432d76b15a024038854d9620ddb944b822a031dca72baa244c7d62acbeac6b86f835673936312e94e634881c98c28821a28365e1d68180a4291d8219f3399e993dd0c2e7334d5770c5fa5c91d3d4e2cfcf25ef49c5f4951a1c39f7525e9042789848ca98dedd8dbe1fac51683d5c12b528287bbd4fe1777923f310f0d5cda469902aba7b570f88f1a29e6cd995ad8f0122358795032df7c22e1e57e4af13fed5f7c47d92c9d565accdd6a20a040dad5485475e251d9cdc6fee1c75fb3d7efed89619753ec3b330a27d98c13b61d2c2d5c10e35bcb14cc9c890104458a07933c1c421542d5f0f34b81e958b4ff4d89c4855ab44846bd7f3c65bbaaa8833da18007ba323564a9f25f4f907597317542d6dc4b1bef6f40c0fc76562707623fdfa4408f57108383fe381e7c557cccb807a054daf76f14a284d03e912973847ac5ad6e2b17336b75290dadcb7060982eb081861a0a56e71cc747ca883fb776be2c33f7bf14eae6fc2f6c84eafff77c0a4844abf7000336708bbc9d56201f74637ebb6c64d82747f7720d342a65c7a27719941a8c76f62487fe356f7511d6367b8bc40c5eaf58018e1266038c6704a0f4f05fbc5b2c2a5334083712c29e8c670d9f1fe5b88afedcb298e5b11b2054e72a8413c934170b8d852b4027bc9594a10893f248bf18d0872e12a7341c5bdec5c502122edf1201074019815ff4cc922a44a3339a7441c38a641ff717d3260f27a2556b4ff39e5ffb080ff503a91832c03f57023382840d08b1ad007a3815b384e2991d9853d060950e45b3e085542e91c060ec4467d2b8eb6ce0b463b40b04313a98cab4b35c46074e77dc031d1f0be4903ca3497c515630ce2954cf2bcb6d96c234e8b1f7e4d54b3681263ce023c27c31645056b5cf554c127ccc7a67a13e78ce2c8c4e3b812d02640b5abaee2479cacbc8e49346bab600c57f5787e4c65195096f53f380e3c4cac3c86bcc41c03fb69915f226eaf9285d4e20d54652cbd317afd2fcc9fd2ae951c54d787b23db52fa599a089a35c6ebff455e66f97460fb1eff24fba4e4dcf21d66e5355702e1c5cef443815643a294498b36aaea5c4d74c1f4735e9712c6087a1ba840e2acc90ce53cc50a722bcb7e8ac0a317f5786f1911810e116a890f733fe4b1b1a6fe5288c1ea00b432053a5086b254e24e4123b055c15bddcd9c10e1bef4a17fc5a523e96ca2e5e9aa2cf609cfcddaf2a3dd21da014c9383b763d233c5e918ca53afcfdddfa0b4f64923f005bdbec8915add863820a3526c2608fd78737145281e32f7bc3ba8b3fcbcdadc587fae3d6c3f3d8f342e0706fe1b223cb4a2c11fe0cb708c4530ab8898ca95ac4019a09904bf38e546b00fe3ce8297441da600f72983e82dcd6481a12b4ec1b9555b8d713b7402b1dd21a92fd3d1e5f86e325658196dca06287bbbe3afbfc77cd495e33e016f1edf7c0513bbe525cf5e3aabf2a68f252b23844dee24bef730bd3e9e20d29bf687ff4e55ba1b95eafe032340340dbae86dd3d4c252bde881a9600678c8bbbc6ee3cc03a974d870358a9dbee7d5c8f947404f673d226b462900dae53a3982c5a036da11422ea637990f79ebb59f9e14cec5c0e50496c58b323ece403e2ae8f7d4aa9c4ad1ce38470654c7c9b6e289d546000298d974b4cf53d457aeb4e77d1a19be3c2496a1d3f83113389241d1df62c3aca340eac2c755a644e9299c5a24272a2091ce00c1bf75c80e8a0b783f0ce4b88297b3644daf8fb6c40706572a1e20cb12ec7fc836fcdf51791876e19b555b849f03f8da07953c6aad1daa4389388f7d9561cb8ed8997398aa69851d932f791cf7355e65024d4ebb68d71be2f07b9de234ea467269276e20873b42c3fd184cd10051bca36c6f4d0e135e75223614688c519192b32ebc04c0a628fbd6c392826a4d5cffbec36bf34b4f99f64722a686b7a26507781c13bbca21a0b06971e0ce4e933372b1bfbc64a3971a9edc1441f00bf9a63fe22e88eec90fb4077035ee0b90028ea5be380552f44244419de250dc14677a5ec79bb013d848f2365105a94a8b0bb4423244e86091ec9f11e3becc0781ccbc6824d378f15b001578d6ab5a81ae32f0495b3d34276a92b040c1e26e7162d7a96cd1a3b3b5c108df8f71ff71a71bfd4ab412d4798930ba85ef03f0f51dabcbc72a6a0193cd85b372bf250cafad866591f8e9d5cf364b450a0c728a420ea1dae231bd7dbc7ebe2fb48dcb1f16a51e652649faf17417ff57ddfc1be04117a89d87a92a35c63a10ba56020bd5fd2a4b89945507f6c947450244ab9c31864c3aa16e04a2b6c8d04abba3891e5f4c55d3c567e83d13e01d4afe8c731e9ae1a8dc802fdff75f274f51696573b00ba1c58cf31db41d6af7f2894f1529e800cfda9adc538c7671131809590acca53c909285f43d7503b1c35448dda743554d0c2f838812aedd16ec57070b36bc920523b49df50c309c526e2f2c552674a1146159c48d8dc9895030565384138c607feddddab9fd30cda96cdd557864bbc787b534e58c865a42d47dc8dc4e3555b6166f0c3d8ad9e3e7b75c6158267921be7f936b2326eef45bd36f50a5b4c43673de92ffd438492962a22071c73bbe98702dc14eb6695b7332032b70b879c81b41724e986067daf86401113985c8e81587965bc711e46ea20de702959f4b24a60f2886f3f0422773f545541493cf2a071d11b2ea6d47597a5a30bb0e0d8611ec6e86428af6fb06d5c02ec4411f5eec443391c55659fd2118f99b735a4dd9e6fd8350719e9a06ad4592c0b45e4e87b4f4a8ffeaccf393a36dc906dbdcfc501acb9d877bbfcf661fc8dd305407c9b95259c877123fd1b5d779812c6a3e26ea22b1791f2be18cc1e5f4eedadd548280c9d20556f9e91f2642031b33094c5952ede49a262cf1e909169763a39015024c40039ab0340d2c4b0d887ab54547909f0f84186470d57b765db22856bc1f6f3f54fdfb12597c9924080d6a07fe6bcc8931365858165fcd80b804a6ec07f7de0b3ed30ab6d9ac37edb242afa77f2766082c4470d2475401a7ea0636cb635c5db8988a8dd3457f756304d50b67b883ef85b2a0230d2e396220d289e741e69feb9d2de89c6d3afc64767104588f128aa3001db7d6d89ab5fd74ea15028f731b48985adb0e43bbb9c72c4046a606ba4cdcfc493302d1e12c06761376fbbbb9833f13a167e43a972ec09e9c58f83063c366e8611c380460f49c0bd417bb58576547b6020a1c8c416f181037d16cf78fdea557df686496c4a6b25b70ee151762eb6a68587769dfbc3870c58820585093ff769ff325c1c41105051d1f37c70a7a796a7b6b69734fed5f876bf64ccdcc8731c1dff8ab96941a16518332dd89bbf0038b3c10c09788ec39270baee9f0daa256271c158ac251fdd386220380efbb3f9790754eb8fe06e406936a8680ed48749068f2fd9f62c80e858de56a756451017bc8c6dd503197e96c932b1bece4c08737952f14ee0a1f72ca74fd5bbf8ef239e0c7f5bc5fed4b5c67bac47c8128a975f23ab0740b2556e704429dcc6c86db15952dc442a556f60d4bd5dbbfda072e307b66c3997744923a182b73bdcd9b67833305aabe53bf4e10682e92ad9745083d02eaae8a24daa9f4e0d0d60c7570d2b002c4385c275a1e6eec2c9d339e20e806f71ffaf045d88fca113e40bce4ae8c822193a6da803a6d04961e09dda2074387ef89e884304da32983264fefed83a18d4da39ac3b9c23f8d2e0bae7e89c5907b3e701fe490fa903d8355503c847a9b8ff6b5207053c074a60ee5f6bddb94fcc7450263e2cb48570e6c7d56ae13e14f83746176c133ad4765ca58afb2c0ae7931785bc49f727ef411bb3d14a1116c10d9bbd8ad5a997463e622bfdc96b1a09d24fc4227461c96412715812a08b8b8511792c87d8740ac970796e070e3514a3643b0685bdac05531f4395c38755e7b6f0178e604132bcc73cd84147c1a2fd1dff083450c060b58cbe65247879168a886323ebca3d74d3c9a1b3dd69d6c5cb9a4d0ee2d0ae49a57d8b81d660720a2d9dcdc22a3958f0f29ee1f3547b61bc77924acacec3de0b317024c48b8d9ed33568fbe59f812e4432098e505dacd31aa8a32c562e0cf2829eb1eb2f180fa80199ba6dd05eb63efb8e0d61730b18424d8db3f395dd96cba7f85830e56ec24c4bb39dd5b9931110306259ad161362fbde21b4bde781cc1853c59ce4e2d95849b0852a6c391c7c219763653a12ca701a8dadd01a0861e001748d3e6d72b40da6b78ea70bbd8dc4da93a75a493d85b5aded9fa19430b653bc2d12f4fe89f21d11767f9a228b06381e8e240d62eb9aee33d79249b5592774e70ab93d88845d5a0a102b619940a9285606709bb3e603b5d511648042f3359a52ad24e11ccf0970e1175b6d25156f3ac1053c3e32b2f7fbe27334ac20b561d6d08414ded0d9b33615e8036feebbbb13bb374bf9ed2ea0cf1adcbca023d2f511bf5ee4ac21f687e8b21cb0b20cbeefc74b04861b326deba64e5400490b0bf0ac88bdb42bc410e8da3b4f3419b13f34d5776d675b2e1a0d4a50f0f34219bcb72cc617e62fbb1e33b73544d6820c823335b3754a4cf0560e3513212678a741a46c1e368378189239e948dbeca3c03b0374209892f02d8c3f9dc56b30918994b5d7b3e0decfe2032fbe32f8298bde9d95de3b8b9e67d51b2bff7b8c038c0f04fa5b63a958305c554d63991148ae5fc76ebd7cbd2f157b5b3d1245acb403d3331159e94314fff28fb89d5ab31670fed31d43b0660004b349f606bca974783586a9c1a680491ad9abfaab542c6d326ab4d42428a4edbdbbc9bdb79452caa00aae0a490a28f7b0d4dd5bb0aac474a12d5c6fa60b3d22c6a0df58031106fd66a1a3ca4c01411531d0335c2ab8dba5e9cd0c294eac3611460874f7b4d1255c350a8e32474b3cca524a29f3a669c93c143c85cc9d2f5ca9eff7dcd931efab0d2dcd0d841e1de57394bbb93385d0c7a9a2bd93f63cedbd4e58b5a12ef49ee7551b53a6a5fc791fe1d13d1c67389af93abcbf4ce3d22315cc1a7d27cc2a3d6ad339ccba8f1aa575528b4aba6bce8d1eadab64568f95b7deca3f5a5f794dcc877ba85c25b37ab0fc5039cb6b62a287c4dd309a75ed87bad0b360200a6365ad4766ade7cae0e2af7c6b439a528fb3992f0d67be52a7d794982ff0f45ace7ca14eafd1d3e9b520d776342143a84d8a2a25653569104d9fb252a5703d22d60dc4da81583f10ab08625d2286f41fbda43652485231437a143d09cb25272c9960d9044b27339457b0c031e638c6a88c46dff7893eda36d2e54758be9b43f3f57df48d46fff21c9ae168f4296638121a2519c9233c464eaacffaa8d5de3885cc7024f1f79dbe9feae974fa4e790a99e1e8f5fb88e8d149df3c009ce04ebdafa70d31724650834cb1935300a93f1ff0593d58ce3a2bff609d25b3c846e4abc4af8795b37ab06091593d5a677116f9c7df9ada90b624d69841f487c2b2219422b1999990c983c371ce45b658f419e53da347fff0e99399d1f2f2a7fce111de215dfafb27ef8d5670c598daec90c30c29ed41676e6ef7ff2bf1931919c1825932ab07cb57bec2f295d7c4b0302bb37ab08e8f59972bf2fbbcb3708c6191a34fe63da3695c2c38c6a0e01fbeef525e05b37aa8ac5ce535312dccead162796b8545b2ace0a88410bc20c607ad8263cc87496fe118a3b5708c51c1318685630ca95ee5736b8ea6530ac5a61085d523a20b7ded800834fd0934bd14a2361106a59741e8a8dacc57d5f4f50667be589abef2d42313f6a22a315f5189088e68aaf5ec6a736a44d36aa3e9479fd6335f7beef8ccd7d69cfcccd79e5b76a7da0f3427f3b55d4372d27a343dea8abb23130fab38dca267e8d52d473563b0d0c5962d492fe13da34b29f5abaccad553d5b15dfad65a6bcdfbdef418bdb81404e9f2a278adc78942e594bc6d2bef7bbdcccafb379fb22c7b2ce1a84d78d39cf4ecf4ebde451c3dba7e3544d7a7de75d49330a9b3dc5580956a835f79cd7b74d70c294c10f7a7df67ef2ed6aa8987d3ef0ef944977e9f91325246ca48198965ca3ae4135dca9794593b48f9e491504898446a995e3a09e524d69de1dd575fd3f7bd47b9a49b300b7b58a504bbd1a572a43cc37a9f82776907f0a6fbecdae56f0e74f4bdea5d74c08d4a7280a3eb572a3ffde23da3ef4f988572d24fa66bbaa67b4ddfa1be2c946c3ae9a5df77f13365160f9329d727a8a7bc46cb6f070fd6516ec2f289969f77d3c73aaa54ba572add74d687ad174bc9fb6ad229e95e269d23dd848267f46997be5df0b179c29b74954ce3884bca1f0fe06f0e02bc2907a1fa7d09d3b84899c6a541958a65b592eb28fba03af54ca71e9b29528aa479d701da54805d3ae937d7196e1f54a7f22e427f3c6801482593eb7b75c1f8dcba63068c4cc27b7727917e3c70fafbc5dd5178cf68d4a9e5b26b3063e55da359bfd6de5beb492927bda33944cd5d85a4a34693328b07e9adef20e596d7e8d2e387f2127ecaf74f8fd4f4583a0a0e5bf8250df743a8e41f5d7fcadbe67d5167e1d153706c86547f3f25954c8ff3f4385f5779db53de375295ea27817987df0e97aeb9bbf7d89c1f8f2eef1a7d5138769dbca7c4c890f66af48cebe5250c5b5aae33155d7fca5b65c2aa9f8e9255149329effb9b4cb9f4e3385d4a281590da74ef79f7de8c3efd94e3b312de529b4ec27b46d79cbd62d24db854c25393f046c9342eedddbe9bde872fdede2750b3bf1df7155fdc8204b77ebb74a5716d23b4f7a40509eea67169eff171149b5fb78d60a2e3ce8c8ed7aa56a74b57406af9f8f140e9d664b99941180391c8d2217b7d1629508c5aa5caa89655b85e85c50cf733ebea27933d93d1826a1c2ac2bd163a5dfd0493d1b77fcf322dcb3222e293212dd2b493888aa8888a44930a3b3f459a26d2ac280301811e339c9a46339bf4a8e1b1922602e530bf03cc18b0db2acdec335d7125e1aaadb522c96222c48896a40b4490553483286148880c3f9a977d386a510e85694056742fd0c33045fbae3a39ecd0c3871f1c0081194e306b402d125ca977d5a9475c393fb749932baeb8b95162c9122aa898620a29a4883fbbea4424376ee85d7566cc78c2dd2a1512eef6f48e3f780a77c71f70897df709443b275708e1d241d86f42f6c72601a230dbd3730d4b4dd33491a88b9ad470cddba5331df27b46cb6bf45adef276d36cb729852572727aa838426e0eab075064932b8e6562839ae879fb4361762ee9a1301b346d108f0ddad6c80e8e90f9da556708939e263f499c00cdd79e427a8a88ccd7f779d19177df22237a5a23f3657166b839a130ae676b325f5294a30189723420518e0624cad18044391a90284713e57044001244935f01a49e1a67e4071a9026a462df89724440443a221f5192098b45101205011224e211f5889088764444f4bc48933aeceb0e91084c5d95f21dba52709c2bacc2291c2788e3d42eca3e84163d36e96c8de04a4d67bee2ce7c09d186cc97e8f31a118d4733325ff7289fd78ecc57e9f39a8ff6a3e7536638b9d34647bd2bca84429d640978a058a2077532f19827882a88b505918918c620d622d1063107319cd76989e05e4728800ce95d75e8123a44a998a1d00ca7a0415200e5f0e8e9845e31614eaa8d0a0875889437b409984540689329ca594191238625b47cd14224ee0e592e3d63eab864de754885a93a570051583d4174996f818e819eaf36d0f341146848eb44185394b3440abdaf96b10e6187043d7ae618a17588d6a4284714b4335ff3558368103d29093781a34a1dbc4a486b820ce7352548ad09b18613220ed500c0ef2ede487d6b52d0b31e51e1aa8248a30a1942846786291ca38cdde95d75620cc0ae2d10551d51d509d205223bf3c5fa9162c2a21080a2921134e9c978443085ded5670b63d0bb261102d2bb6a4014e6d2010a9470c203450802932d579d19e2dc3d8574e46bb4053c3ce3c9b55a7b543202241badd112fba07acb320919835ec319a61c93d39c61022e20710288121eadbd0b5d9f6298c14ea4d24774cdfe419ac5a26fd8be8b32463a6a228bd9708c11590c435db416ed9aa196e590baa498d00e01950f3f4cd8d6694d7e8a61063b31f50e91df7c992eda8b2b9c2104300d6e0864fb5462e2d870640e04628da837eca22e9ad4a1301b254eac11436b3446c5a3356d9e0c97ca4f4cc3f9cc98a1f6d8c42f3374cd50fb9d5c0954bd43fdc9842f132695d0244e8c9dbbe390d6b44360beb44b9b6d2f8f9ca2336801888807a210715c0c871d54aa3f0c5daed30c7f00e2871e333b5ef8ef49c5fee6d0f23036d3e38717d73dbd7859e5b6842dff9998c1cef4f8615b9dc30c5b5c9ebd21cc0d1c4eaa9367d1d0c59d23393f427686f800493105119e9d0de5000992a3b213d668ef9a71c3bb3b42bc1a77763222d94ecc986c67a86f79b9d6dbc187192e9819201c407323766386cbc692c0e6e472b976e0ba8e9b9d887bcb8b8a9e5c3bcc970f335c3033403880e646ecc60cd70c98192e97cb4604303652971dcb849c965863c63a918beb3a6eee300383e39a7163fe25c258c2b510c001f4f16387991d7088e190030e3eb11c0b05755d3a63a9cb0b17dc6d339128933f0061bd1f7acc582dd7db3317239a6b107947d471d3292a82134e54e184134e38e104e7012456a88ebf51c4591b2a924e5d69b6e1aa6d38d3d18b611655a48d39b5efc96dfb2c08fb7a297af6f1b0226bb126424e5a33695d8cb6bc1d9152564943459c66b78e74bdd187623aad5097b36a96f370628de94d15441b5ffc5850e3e48a3566c0f4f0e1070bfcf882c41a25d3c927d640325fabc7cb9ff94a79bc4c3261f2474a0184684352017e4b2874fcc489b0f82796d0f172c88449cb132f55106d48224458a0e3e5cd840d415de6ad123afe02d1865442c638831d8a4f40b441b3243ac17563ee00e87819d1c60e32c654d97879b14be2e78d8e72c87e3a349db2faa142f5f303e63de737941c923c435bf24c9daa825c9243e466ce67a56f3404138972493334a30894b7bc02887a9b75ede072752d235232994da68bb421b71063cccf1b3d6fdef28a2e4839d404ab65e4ca25d365680b57d2bc9af70b2e4dd3ba00024dd3344d4819e896820edc0a28e81d6afa42e955ae4f89d682ae8bb18696553a638c519331b6e0665b8c1693c5c4d0982ef3342fc332a65ec3b5661f8f1843841798e146d3344d13ca2c0082279c30022f6ce10c4bd0a0488274821c22594f8d01bdd94076c3031b6c47dc64200c1e38010a88e808610a5a1038214784d8ba4f9a42e1e998c48a1698a08bb1463667cda69453b3973ea3534eb905e982a9f552d66b236cd63cb740e3e7084a3ee0640a3f3c409041568324341d0d892ccbb26c05160615891f114c4dd382d0c48a9d26430f9b0831d1fb2e209db5314e997dd68c6619cd599665d18859934d2a24e5eaa10b2674659206755d8caff83d679d93c658278b2a98b833c638c3205a9519d56a9609a95a2624d32a95a7995629955a568508c9b4d065f4b2cec70afb1e819830d2631cd26268c355b5742ed1060e32c6fc765bb31612bed1a5eb3eb98eb3dde43a2eef2134518843186e39871764d5b66839db16ad5298ab3497c37c6597deac56c6980f6f74b197d102f1610fcb8fc7b543e8ec32cb75668719f6982e93478c311fc61a3ad81ca206e405090de59043fc91999631e97c6081b41c820b871362122d5fe3e34b45d75a230c4ad029a402c31531d65a7318431164a024890baea0424cd57c741dc90c0c216001030d74f609c4e4092f4a066bb76ddb6e96183a818e4c1a8630b14107e6197a2a131e2c21abcd9141c3b6370913242421738621d590187c443b505911cdb4acd4048e1217a56312211374408808aac8e5744c22d4832b849b6c43a209614990ce3e3f996c0731f4240943152d55084318b8508528f59411c35883859e77f900043d05a0a77c78d3dde32e923afb24961975e18e8ec8abcc97ea93ba44179ac30863867a5291d5726c8a7013dfed773b5ff865bacc7b18266cada0de52cb3d7e228e8a28bdb62aad18633ec32c114675852120016d2e8872f2882eb3a582fb19d2e80aba72db9f1c228c5a3f10dc6d6b08408479618cf89a32946136271d11b155ce14615e8c315fdf45527c65af755b293b49e98888add61861ccc3b0e26699969fcccc0d975577c6e6a87bb43ec004901d9b982d47ea427514ca9a20a4e95542d65e88c2264f37c2ac79d4f7d17b7c1f7d7e947f1499b9c7e828d67c69f41f2ccdcecc3a0078d47b38bd948b28fd54ca3782df6b62507a54a7df872c50dc7a233d33a4983583ca31ea623a6bc6741602b4c7a0ceea41a2324bcb2c05988e7a0f282fe5228af4301d7594bc7a0fa8a31c251761ca45b6ccd261fb3cf77954661d20f5d5595aee21f515ab07d559579df51803669676f03531a78c02f38f22de7fb0ec59d94fa8ccaa67694779b9878965b3047a947e8f801803fef41ec09f72fee1a22ef4a50cd4c3a908943c73326556cd1240408c291df51e4a47e5fb2250f28fe71e6e06a22666471fd4b74b65fb7cd41425e531c6948bb0749841709f2ffd84ef5118e526ee1e16a58e8018937a0fadab1e3f96762dcfacee432b1799675df59a9854ebaafc43f5562eb23df59a1895eaa71701be08551ee2f4d45ba7918116455de5e04fdfd2063cea0a385d25b36650a8cb1893e932c5d25698a565d64cea51b3ae927facceca45b8a7e653f847911ea9aff2eaf745e414b1ca32e73e75d6696480b52377a80b3d0d9b8bf294977e3fd6014a47b902ee53326b06e52c04c41814560f32867419437a6caeb08c516119a3616964863c33e43992f5f44c9b119e3cd36687080f4fcc24e283c427cb49eacfcfce8ea5dd41d4e69d4cdbebbb8cc36f9961f68b49f852173ba70d75c146ee9e3e538af9da936706ed699364be3692f9d27c7ee6ab9edaccbc270e4b02492926909ce23368f250589c757bf66e66d56aaf557bd56e758561c5ad7ad78f87f62ddb196612a5869ba728ba2e723252bba0707564a1b7c7628d987dfbb615416fdb5d3c5793c741149498e0054aa2b022667bfc666ee6b35117ee568d8edc1dea6d7be89a2fd145f6f122014497edd166980863fb86d11bd7d222da04bd869bc0b13174cb700ed485baec8e7a30acb853d348b71bd365bb8c485a2bb8e145d7aeb2df1e3faea31cb53a7ed6ce70b3dbb7db5b9b374d186e505cfb6db5c7d276f3605871331db75f1bde5881e1da0c33c3ed5f08666eb224d58be55c397461528855a31015f72e9cb9597a63bee86dc6d932101656b8da3c0ec1ddd24726caa26bd7524c20ed12775b3d69de524745d5811825121a4851bd9a5d4a29a5d462ac5ee6a9722e0b2cdcebadd230d4855ec57387c8fc87a14b661655b8a2580f341cebc18e7624f395d97c04109c416f79ab8e645ab63da6014161dde976859c17af0a86745da3dcf359ebe5e82273943d4d709738cb26d385498a09ee691888a0776452bd252efd86e51433a417e18e7ab1a094100124e152fa23d227cb9ecf0ad7011098af5fca79d901b3cb71baf468203c70e7c3a0efad91de6a43e242175bba986d67590b7343a80225a902289caf0b540513edf3850fe81d97e87aab6da1eba53e8937a64b85717267cd3e5fb3d7f9f99acd2c7b3d27fa107afe2df335b36a86f599add5060a95eade189ea68b4be4444e93a647a9cf267d49085d9f692831a4476573ce7c230cfa08505a4f831024489021e044a10a258ec00132ac2071b72bdb7b2a98152656986829a1a584182874f1b1a5b5843c809c4e24d04edd7234cdbeef8ba3efebbe6ff47dd4c5388aa3388aa3910fa9a5e7718fcd1396babbf7799ed779ffba4ccfae93ba9bdedc11b5cc02138fe5313e70a5ca61ad4fa59589e8afe33c0e732132197da3d368341ae5694344c49100e93e6c6cd680862b0309f7fb0b2e5c16ee7387c25876a6102714c6922791397764f8e06eadc783b1e400992f9d1deee3885c16967bf9f47a4d0a59efe3f28a07f79a0c4fe82fdfcfab6424e172dfd566c89371840bdee0ee6a0364f475124f2173880c1edc967ac251c7f8c08d12d727b9fbde7f08a3b8dc4faf36347a1fbd68c2c3342d5a9e3e77bee32460cde707587b22c6a02761ed488441b51e1947ee3c85694141228bf2d8ec3a2700f92e83b4204d2f6308b7d69bea12831bc40352bf8eeff686f3c9a4ba579bbddde89a335f52ab5e36b019432b104d2711ed83884d7f973a4618f7376f0a50fde56dfa5780efa3a1f9ba99afefa44f14d67ab4a10a50ed08fd64525785e09a2e35ea5d17f3befe24cc0d15d70c55f8727acb55a978f7f459ed7da31178d463b36657fd5dca572f4689d834782f89a0e025fe1e3ff9819fe0e7a743045f750ae78a33437a13ae3755460fee9e3b2e98dc4dd3a2ef4b2f7dcf1db0ea6b844bfad67a6e2dae7d32f34984215fc39282bbe7936ab372f97a53e5e713d4593e1e1364c1d448d7cdb0eafb15def7a9cb0f9575dc8394c7c7d4b42786ebe5000000086ef7fa31267533eb00381e7b0f39ae7311fa391ecb4514e9a19fe345c48ee331a606d963034f0f8f919ed7aed12efe02fc8d1dc77b88e51a7ad079f6e4cf68172e729ce18b6cc365dc701b601cb4010000c0317e830c182f311e3f19178e811f3f19182fee22efaa5dbceba153bfefb42fce50b31cf5ee395e1373c1cc3a008ee7780f1ccf917f1401ffe3f6c0f11ccf917fcc9e5c1303e67d7d4130b5fa05ef7d6ca2f07ed137a3c2aff006c0e3c7830d076b780abb5cfadccce23175ca593c465de097db80e510b9b3ad0eff02bfc0c02fd848cf0ce29e6a1004c120eea5eea4b78dd020b5a138d486de4c406a30752f792e963df75bf218c9b2678672025483990819040787e2f4e0ca203654f6641becf404cdd79641b444f2e2c5bdbcfca989a9899136d4e002b5ba8bc2a4cfbdf449ddafee512e6cc8353cd2ec22dbccddfb7b1c38034d34cb490fd29dc8b3f32575f613478f3103328d32a1e803e352b17c7b7fa1be4fa3b7c0516bd28694dac6d7ca47ef364f7bf1fb22f52e7e5267be5232f66df5f78da1301cdfa1067f0acb71f03138521716d73886237569f149fdc5bb94fc0b2c7352974f3d3673e048a50f6d61f14e7e291cf52abeb8bc043261f3052c761cdf56a73c46588e14954e790cd31c1807ee3a4f7e3a6696385907575efef824992fb9c1cbd5ea5dfc529e3a885779bf6c981efabefb645cce82b74ba679d12c0f0fe2dd4387e7be1d3395f78c4e1dc41bfcea1777abbb9af1e49e82342e0da29e8277ea3ff7c98039ced045de56a3f22e3dcc3cb0749d67e74bbe1be1fb1678c57a9536c0b3be7dcc21e05509dd200d3e4630fbc974eaf63bfa6c9817df2e17dfe1caf735c802a24030f5fbecd381d3a9acc918f7f5db01be45de52b7b897a3576923ead1bd266d447d6f87ccd7e8066916964940242b5db87bf6f0d01c7be543bd6d7786bac86f382e735c9ef2fc32e5f239e47160e9435d5e64177925b364e93de58f9fcc0adee035f87bcf4ae17d9dfa0a6fa957ef40bc236a10af1e3f03b0ce81df113598673cb9acbcefff1a7dcf721466adb2219a856b58b00f4da7644dc6f8102dbfd110bd82a50f964f3243f91969bfca3b4ce57d5606f3cddbea15dce2c7a34b1f0aa3ac15c7b558165488a2f2b67695f7bd5b254f7d6cf649e5d659795b0be67d75ebfbaaba3074b95adf302acfb87e32ac633c8f7c3b52cef215bc6bf44a4bb3acf2aed1ab83785f83acbca566fd9786a1eb3e5ed655deb1f0f4c1b3070797756486d2874a8e4bfd79db548a5b39885b4fe1ed23d32c3ca49c25df8ba35ec1296fe17dad52b9042f3f7de62b46fd4e05b3de494f85c5e397957d68f7b70252df4c93f22d75ca5578b8f4ea60ded247da0c71b2a3c10bde1c21219fa11f26404e34784110fc8ee0370c0b6fd4538f1f0f99a357acbc81d0ac8378bb34f88bf74110bc8f5116f69169162b250be1d2abbc67342af58b55aad4e3e91195695cfaf44f86e65098175deee5bd776fdea54cf3a24947c93cdc4c22e1a8e956f9f8ec0c604a1034d1494969b59b96554a27a53347461f4dbd69b32dcbb250c7586b16c30da67e32f14b60e20c6fe838916434a3b9d67a15fb9249bb5197add2cd87c4057b6b085d30330870c1d80c8380197bc31aec4d7265b541304d1f83a4cd4deb8787bba136524a23a5477411565d79b7e8998d10933786dea9c49e418a2cc48082115d5f6b199c98a109339441d7672ead033838c117862021899e2a888081347c810a66b809038ece10860072416751e80c064e74a426b327c86c739be1ec2c6745d6e63d71f8f9968e1385d5d62da35678cb9c487432f3b185270b4fff1bf3154f1fd68a5be4f78ba62e40f252cb24b2546bedb4ce098e931ceb834854451c57ad5725d775a2ee15e54d986e65edbe75dfba0ee528ef5070ad175dab55d41de507944e7a9ee72181132541c5894c2825530945b4719c674772249de4889ce49fbb5511a5643afda084f6aa3e9a26287ef241bd984e27ef74328519e5a9984c97524a29a577530666f40411367ba80e127a680c7a680b7a1061f26742f163842568bba14820f9237f64920d054802c91ff9237f807c482d530f3efbe9643aa1502693c96432994ce0515906fe844fa719339c59169b20aeba931eca83c00c29159ae9a182e791e9d2a3e46eaa33031481a80e153ff494baa378c7994a94b0d4e012a80e854d1dea426feda53a54676849d0143487e2cc70882ed97a50a8959fac3eedab4fa6bce5c1afe0185d4c6fe118554c288a02df81f87bfc3cefdd77c1eda7479a32d5993a5487ead02054c7c87c39892e518f9cd84497a869eadb82df1765fae99d09d31daa43754ca74152795b304754de2a2de9ce7c99323565ba93a90ea529df5693489f38f3c53abdfcb9aa873fa64b6c329d4e4741994e28479d50defd84c2cab1199a1e9b2816309d5ee2984c4f894e56a654361dcc1b954d3f491c5346b99438f69784f75442d38ff0f6e83faf53511961862f137663862a9fd55c9dc174797a2c5de2929452966e32992e4d2553b6a57cea58a5d2a594524ad9bd843aca095d325f92c2a20fa5d435831b757c76d4bb9bb2c4bb9a2ca04fd57af7a43aa150264cc4a651a6c74f9a72407da28e7a099770133646609e1ed8c4942e4b37954a97ba54ba7c290b313f1de44d9986ea8dfa046ab4e9258c797a60a3e3c7032a9bb2109c96a72ed3ba8ed52541f9fdf6edd4a328586a104805b56da753ebac6fabf218b74a9bf29647bd8555708c2e2c5cca5bfe74c2db3f19d43b14eebc2f87a8bb771f09b5c9922c459f39c4847e6418a22e517fabd128459502512753c974f912962559f229994cbfa79fcce93ba66b3afd74dc7337612122900ee2a6e4d8c55bca952a6f9bda2a54de0f4d32df97280a8efa6e1fe1cff391e9ed9c3ddd22dcadb255ace4d6bcad6aa29ef006dc8884224ef44ac72398014813410a6d6f458f40a54c8a264a8fcd1d1a5d1fa5a089425af439b485089b38d16528d650d174b260e89641531c307820c2a4cef72481a629f88e4e901952d54ecd724747ea5cd70caed440d06abd7b526d95fa18ad98bb868960f5607a13a76f5ce5b07cfcaad444d73e1de493274f9e70b8ea13b6c946986e7a67b22922847cbd114584903ad4cb1c048dcc42d46f99866ad11d806344a5c78e5219847384bbe790c8e62477fbc8ea4707957087e8adb599f684446648a708a1b8532868863df3e51da13e2938dd25674da27cc2265cc231ba6c79edf693e93e7ba9f1b8bd28d38145eae08c1e9b232673e889fb2adc3d876ea41077200313a24bd428585e7e2e2961157591b9f42df36442edd01d9adb521739850fdbaa3ea98342736c863950180ed3075a3fca41416197f7b91c14459d150887c24a0f5d30580837cb7b0ec1cca12115ada51cd20441a00981090d54269068c1151b0d133b5dc0c2133d3a68424332841b021337f841fc028dd48a2be81566846d769b73e69d5dcbac2ac67735467a2db764af59a5f1f392c9a6cda0a7270c3d3d3d3d3d49c0d1b21ab716d52acaac4d7bb769ddccb20df1456411c31923baccc718f32c303d75b63d36ed76b91f1f3d7e3277341a4d3cfa25652323f91d2140749498574c2755b89175f549e5a3126356cd1f0aa3534497782a8096e8f8f9a3256da2e32792f9ca320d9a619c4ae079933343392d3ee53a5bb26f5038821315bcd010895bd2c4008624f474d529a64b10159c0469a9679e3034b8f80af17b0ed15730a1b0ba2397ccd7bcac416628a7132de58f8e653c77b2b0a0b22a251e30c2a3c4031990a1b36f314802063a9b223b4326850c67093acb70aed059078aa033559665d911c4e08328b4e88343025deda3a86208a719051b9470800aedf20125480ca938b00da159544d6a2fb3aaa94e5ae57470a710264c6ce68b35e3c3aa0bf7ba4908c270b2e076aaa6549943e1cc3b0a01d52a536515eaec7c49e98289dac36dcb3bcb4851bb8db0792d6f5d8d68d9b7565a552a6baf5d6a3eb22ce480d614b73eaaa86879d904152b6aa522dbb56c70a9ddaaea12a1cee738435ae5a659ea92595c29d5e8f4b137945cfa184b79e2d2571f9ace68165ba816bacece17959e66338b6326a7d452ea99c919f442ba982d626cd19b524aa96591650d6fb72ca215aed5a978ac2f65b422a96e2ac6186946a9e97432a14a204aeaaa48ab51cac7f254ba16b72262b1dfb0963316b585b6982ee40b17a72b5851e59e6951c52dda8ace25214aa26294b658034364d1257bcc2680aaba6b4175e7e245c5f2059d3286e128bbf6849db09bed1a2079226b5fe88ebad05d6dd1729166358d85eeb6ac3b8b7527baee3816dd752bbaf35abafb547437225d9492e9b4610d0c112d80fa78584dc1544977aad5d55d0acbb32a9fee5add0a0ba7bb8b7487adee328bae25d35d0b4b75f7c2250c4734c708a35ed66453bc085b842dfada98f17564e156ba96a7f2b14629a4d555a1a44aa00965ed7c9de27c99c0520a457557a494519c2f8fabf15a465dc418bad808633ed688cfa690ba236559969dc25c97c26274c0051c10da4015a4f08498ac083ad3c117862459f244154ec4643f4a6ea84045a184bbb31d3ddf52c2ddaafa1361d4fa136bace879fa196b4c4d35c784b336365f328bb3db9a45d1e767651c71b73c95a24cf3a2b363215e7410f4128b5c226b39eedb6645798bce3d362ddef27ed1f219d621faeea1ad102f7af7d041886e5fb4e8f7ca2be5e595a181bba30ff7d97215d5e95a2b3abd04ea8bd64e3524d45a2ba694525a69ed6a27e23c6fce395fa3299df1e4f3bc53cfeaae761c3ecdb0562c825aebeb8b6bb69c46336ba2748e7b57c291bac48f873843940ec8683442c1bb6a94df4b7afc64f78b6bb4244dbc67e8ee31ca75254e8477d59604a4990de9624ba7da26de2ff3a6c8943e127b323270630ce9f6db7624dc75d2a7ebdec9fa1a3d31f6f0b65ace78c27da34c7f79015e9ca1a7ade844c231467e3ab65bb9695eb496af92c1dd61cba6a92d276f6647001909d236e8a804075168baa3dd256d88ae69a2efaab78f88e446ce9b06ebeda21cb77cc3b763bb2b461a81b48667cc9967282c6e3493d99be18a16ee0c9df1aaeb5d631891e83a43fe066943ea7a4da1e8e45523b89bdacc781a986437e16dfad5947ee061aff07ac109f52e26423ed1241074b95cb0d761e7e22743e3b159430035cec54f06e6b1d9ad1899a14cada456a8d4bd20085ebcad0653e0bd57fa701cc7711c7765dcdc1d817c64dcdc2d7d3477f999f9ba0765b8d541bc3a0a53cde58a936b37777884681a466e348dd300d2699eccecb6515b636c6ef2d3913a8dc7288cc6258dc7e6e452a9542a954a499e498586f9963a75449323906898c3fc0829524f3987edbdfb6eb55aad56abab7d9cfd643af9ada4cfaa5a9b7d3a52efacbdf4d3913a4c8da7602e35cc53f0aed130d73e1d52c37cfb74b8f1011c85f75530d7e5135a7b1f61d447287e3b508e1f9b99a77df7306cc3868d6bdf3de9dab88da75ed8d1cdbb76351f79f3c5a15071be502b142aef1a99558c4d993b91770f8220088259eed44f060473769cc87162078912aac0d171093b377acb1c1634197d3a467ff10ebff8bd0b2a8c08d1a37752dce8d1bb0c00516283448f5e83129b2646f4e83084e89177b19da18bfcfc1a5e830a8cabcc9717f9f2f2f2f252447c797979f9510323b3c0951aee8289d021b50d7fa92136b5eec5bbf8edf86dde2fdad65af3ae3615c7e7de1b10d3af5ebff8f8b9e8583d3be951b79e92e32d381ccff1d8ec3a19f39ac380917be4784cfe117b8effd0c7f19a98f8b53c0766c138011e637060168c981802e42262cff19898965fcbe3d7227399e3525cab95e30c53f2b6dbd3f6da57386a174c848c0d7fc93af0af76f114de57e7b3c04448dde5d39ce30cbd5c430ddd47effeb9c85bbe902e729c6198bb987918bd7b0b2642ea01e46dc371b5a1b01a037e325cde3f340782e0ca39ec63ead1519fcce89dfc88909ad4a285c5ea16af8076f4e897c7468f6e933cc9d151c90d80b44a472537e8d1499ef8e8d1ef3bcdb30147dd227d361500b46deb34c6f118ce7116586a1296ba05961a63fb162cb50d586a2a44e5673a2af47d715cdf071c59df871c43e8d463efe2e79af1e47e06c417d3b8748a3b88531c88bf5f7cbaf401802a8bf6332fb28b94b972faf130facd2c1dec511ef5ead546d5caa8bc02f3ca47b78f4d8d6b622c8e9a058e2d70d42d38ea18ae8941c1bb468fa4d05147fd7d29af174bedcdd7aaf5aac177ad56eb2d14eaf16bb5f2aed1a82ca37c32f771957a07e20d7e7e05e85e81a98300bff21d2b0753e7704cc12cf045ec2e707c849bc09159e0713cc757f0b639959b886516987580398de7c8374560afe3c837456a9c038f292280cf4fe666160f98d338cc69bc033d2aa0d031c91321dab3826996c1bdafd1570798dff88d1cc4ca611e593ad0f8fdcd41ac9cc6a3ae91f34e798dc3c2bc5d1c76f96e05bff80f9dba5dd101b6de516f05db7b100461a030b802ef2a5b1d20f7ee377ff4d88c510ea73c855dbcc05b6a22288dafc0d4f808ef1f1ab642c305f631358da7601f53c39c08f904bc75fddedb38875d07b18defab5d366e6ddcce97eba28f87ed49b633743d7e3a6c64e9534300303c2e1896485e34b04cb281bbe54e077ade7c814fa59ee252a9bc6b34f74e469bf271f776be6af4bd277d321c2777be94c76fe53cf375b3367b5aa36ef6485db22cb3a71bcd60b97da9c4dd960e82208759403c010982602aef7bfb2d7d58306ac5826b3487a35ec568c94aa158436a397b5400c8f2a24f06cc1b3c98bb8b5b49eefd59dcdb098b315707c026c6900f40d42a291cdf2ad5e384e9ab3e43613ae71c19474e459dc255efe220c0a79e4a5d45e59de6a9a8c408630740effb14c7711c77f1c63f3478ae9b1e6bc7bd8d16d360bdca37c818a9c7a814923e2a2c75d749cfb26ebfc2bb46af568f4d2e5fbcb1be07f1668006cfc21d8727103f8efb8ea839207a58200bd768f05a955b9c7ab7b27a27bd152c35c86265560e51b3be236a56667d5f106fcc007dc14b83352adf206304405b954c6d52b96706c51ab2cbdb6e1a572b6f95765d1967f122df701739c6e5c7438c9b4c38ea19784b9dc5788ccb8871518cbc695e7496675cfb0d8fd11932f00d78ab740054c7fb94695e74dd3db4466f34ac0272e5bb4a52e153a1ef49077fcf7a17bbcc8bdf8efc56eb5dcce97684fce81b6ec33510a46d38d855251ae8d14a34c0a3e525120974df22ef1adde2f7663b6486a3679f4ca355a8742c3775514c1dab11081000002315002028140e868342c160280bb31cdd7d14800f84a04c6e541889a320876198428610620c30000010000110a899d90000eabf0d84608d5ac7964f775033ba8f6c277d1dcdecdf172299baa2042d9c30339ae6b09060c04581df86fb93bb50f438a49f81cc7caa8dc7ede65e4e82d856e0add177ca0423226adad00edd23c9fa5f248843d893b6b2f0a010835df8d94f0d053d06eff1c42d56eec92e1d68279f27928652a62a378653bc850defe6979b8313adf53c4442ae6aa04be0b6445b7edffcad9924f362f44d52ab8687feaa6525009d4b7638b214b05dfe047e9b1b52bd14c8e4dbb044ae9e599e1576047cb0f82746e10b10fe169ccd54254f7718a2ef36d9b615ea8ac2fc73658cbfbccabe2065cdd5a3531ccc5decb56883c9bd0472619980320663848de8cc061560c62f40ec8f3cba6fa3654256ed8ae6ebb2ffca3db30f82cea5aef07e9f3ab1cabf7abf94a60662f1061a162b0141e746494b12a8c5d824053acb5b3d75c3eb37d98e9517c2542cb01950552140e637299c68a9e0bf09cf8870caa114973fe645201545801647f6e3163c76a8c1d480097c261d814506ffae6aa12adec5bd29003022250e0068640b6a628560c3c255e58e6894f799aa86dfe1460cf72c3216ef82e85d6439ba943c2b48f92a76d4b0436a7f062e3498a6e958314d6c80d6dea3b4bc7f70c1b373f9288763970081eed6f4235da91da8bb75f67f923ac9f2d183cd35f695047a3d26a8bd26f64b4880873635e27b684b9db80d4318b71fabbeb8244aebe7d6c90aa5699a934cbc3e4c6c45c9c9050933c7aa0f3061f5ec4c555f1b63a8a42c48118b0ac54405a4013d5032e03a4beb26e5a49064336f7d88e4d6c4f42ddafb23d58a9a47eaa0ee938c75ace53cf9c9a678a1dc004b9d73d912f9cd6b74ebec01b93add9ea057041835b09ff55c3801f26f51722ddb8d7235276fc3676beacaa18fa03cc94b758d03b59e67f2ccb2279733131efbba1433cdaf0abae6f86c0b7c386039c4f3aa1d5d9de99fec1619d519593a656b59c609ed65eb1abf10e51e28f39b3f0f434f5f77f1c4b2f9a467c75e2f73e844f109285995712891b1e40f338836bcd88c01ea43471cee6e1940d3a7c46ff754289606c17dfa9b31a6cdfee2eeb0710c0c2f79f101f3feacaa37b605cf339f5f224914ba0f12de6463c9cf30990ac5fe616e5ebfca919908a86d6120820253b2387d8a628ac0e2cd64183ce9b74a57ff244edefbdf62891334896a19cb3fefff177f46780be06a788d3164a362e255d75a1bf1f09b9ed27cb840d83956784b190365fdb8728e392d044e38d3b760c7b706960f1647d5247470a5bf33f9dd5ffd144c4f374fb970f2b7e136e72be28d2321875491bcca6c41290e68f74b4d182451afa09f7dc155b901ae568d67e1e5c0be5b7c10171a1825ff31a358ce20a17dac13f312d48a13dae162f7c3dbab7152e3c27c911a08343adf64410d324dd81948af66e867bb107c30e084339a231cd4cc3a38f5286558ae503ed0ea4e4c3ab51799636eb6a9d093710f92994477158246e7e034e6ae1accd55ce3cd1783d243fdc63e17a3aefae93cf669ef3df4b2782f070c8e45a17a1ba81f2c71b5e4f6d2c9aeb10002d689c1e01916e01cc1c93412798ed68b0ec9cfe506655bbe1fc85a5a710971a011dbee2d3a44c3f12095f33906a62fea8e4d8739425e106778d4315d387169233154dccc92d64a18d476937b39f1b3301e40d25b4cc4405e347054f1508955fb9780c92873c2f104b3ffc1741766c6b4ca28df042abe8421a0f9836a50118797a6535281e5165c4681c5145cdc02c32db89cc28b2b588c85c35bb83c058b53b818afc0efd5d64b508a976ab9706baddee362df93520a04641a6fe605f96cf9f646dd83533818dd3f128530451b637a4504da8fcf69bc935138d98583af705805265778f28507abd0f00a4ca6e0640b0f56c1b0154e5ec164170cae82e12b9cac82c92f18ac2e28bff68caefcdd0cc08f67eac24690ef9971234385c0ce8822890ad94f92dab4263b5184922a4531919567e279dac37df0ec4a842a1ff885065c49d00fb9586ab1ea4c6e7aaff94d0bd0eb42e145735ad486cc04027794fcc14baf76604f84a00923570ce98a96c87699736c63fda28eccf42e7b5e6cf67a0ef678c0246ac88b8adcb6f499d8d02eb6718ded95803a6b2a252f6b03aa8d8f3cd597d5593c075ae7cd7e5daae35515f6e469dfea83bb6dd4224a9dcd4b97e907b4c3f7e8fd5881624703d9d111ccde91ca9b4079c93d59efb020d672081d58afbfaa99d33ae57dd7a7cc25262de657066759d637c350415c52c76d5f2d749b02f9639642ef4c0b3af3784c99d966e41e570f1fd852ea2af29309b279d445b65fcac6ab09770ac8601b63949be2a0ac009be718135ccef19a7ec643c08f505b8e37f79d7945449f8721244e0fc382374fe0f68c88c2bc70ffc29686f5a7374dc8206056104aade846cd89d45e4caab8b62358f2c9919291c3f3600e00dcbdaf4cb56ed6e1b6c817c77171127e59983d31e77c952ef4e51a18536fc7e01a7afc7c3c0154dee18a011e5d4036ca4148e5ffd62884823976dfd8ef62b7f9f8e0e76de032956a99e55a040e017b5ec6b0f8cb158be7fce8b3b78c4bc234232895f5096078af868fc3522e306d6ba2a0c1183d5d5368354de2723766c25397db5b6759cb2e9fb074a5db11245b43d4efa3a8eefc192d2a9e71ddbe00cb594a918c0b834a8af903c377009d020105ca61a72964433ad99405960e19d001d63eed0b81c8dd3ccdf903d93e0e5e0ed5c0271ca527be5c59c2b860eaaeae2a9192941d467d96a700da808d8a3e2319504881ef548d8772e3509460a0477370670b9ed353df6d5f64a194045dfe3947528564c124d477018950226b788ea125fa573cc630a249839a4c40863cbdba48306f1e4adf7d1f63789bc71732f257fea37236da1992f026d2dafdc86595f4ca883826e1d3b8bcbbcfe894945e7108fb028cb02cfd73c5b8306cd62034ef25ae9dbda19da7b9fb8cfe6b25fad0388e99a89b1d3ddd459207cdd09ad4d1f8e00b85516da2c31028a46a695ffee1ca379b7ad3d2e92f4a5a0bc89edf1fdacfa1144d046b403cd2f915a553df420e41eb653d99516f92d7a2dcea6c2bdd84f16e2f9cd27f7706e05cf49442dba291671cf4fa66384c8dfeb452505bd2ff76a931277588802e6b4ef4548d638169ad917605132d6eb25ef6eea538aab61d63b12139ff020c2aae17914118c6ec6e54f7b77df69d58032b66f284ac64f161fcf7b808ad0b5ee5898010f8e309475e362a13bf52381c69664e9450dd66d7dc1b525a011b10b889f20f8d57f5324cd0f0b3b969a103696197f5c69a191c819761f9fd7415c42e5ec8adf7dffe9631946cb2c4554b2b2a8503ea54c425347184acd2198c9abb663bdde78c3dd31c2469f09fb6b360cc8b71862612daec322861719865a4f506d424fe51786a82d0711649993962f9d664b462084816068b0e3e0c1d02b1ed8900b001ef8301cc21cf7d2449d764d03d311c039e52404e97a4f0c42475aaa095a9e4d47e1a394b71abb1344d04bb467a9642ee45aedfecf027be36a611f9f1070e96659ab704c0b036e45d00390d15cd1a98ef43b25bbc260378bc3bfd666c27bc7b0aad2ce391c2b8214180925593e669889e486da8009c58ab5d677f920f791a56585424d8c835f2792b78e4f53055994769020ea1b132a3ed99c5924400daedb9df97c7957accf31641200d040e035615a2ef812b4817440e01fde026babdcf2e19be236ccb2d44b14968b5ee0e464f80ef2329b27f4e132615bfe48b3af6d5c0fcec3d647426b65cca180302662c9481cce19e4ebd9c3c5b3ba2b4bc1697bc38ba4248f1f0b81d47fa62122beeb3ec962e98b4266cf8cc0e7d678d2be296567bb7a2af1536383fd89b0314058a6d7b8eaa6cefc87dbfce5245639653ec5db264eb5e3534f7c1e3b9092677943b8f4b19001a7d0cdda68518824fcedd85197b677483fd68c898ca5df5d051948ddf83b258a12bc9ea803c1c8dba2d8c4f40d9c4319d9fb2ba03f1584c40e43e39d218f1adb9c2897cd16ac96202b50e4fa97c18c06175bb680b2a9182cc0e0f363ff4aa73fe883bf2df8c2c1a3ab50f44a56edbbdeb8ea1d300d911f38e55bfe2b35ec842a1a3292e13a1d60d0280ef760ba19078dead2fa9e700a57c556046fc7153e516365a85a6453504767723f06891f2cda940ba4d11ba97795a746f946ec4b2ea265032abb866dfef9db8206d63f4897ddf0a2e43111c0860d2cb6d74ed86b1400b80582049f2d10f19188f4746b278a8089e365f2fff068ceaf019ba006a4c69950fb8e24607f2a843f0b3cd3ae121631bbaa355edc1080d8671f3dd9ba8822d4ae3412ceddba504d87e000d505660513b07f03a00a2ac469bbb38e4191b3b83e0f9b0320bde701d1ce05da875e9e70a0dbd4585087145906a05f68018a2e84375755c9d98f612b2ee18792ac2529034b9a055c025c819e490ca0a989afb0caf6d1f9c18573996dcaf50d620a8d7bc3d7c20e639faa6a826e16ae312ab05e407b9bdffabbc5eb0b70d5e6f4b56c2ba27775a7090db623d674c9843dda9c6d9c1ca8d77a02392be373be9c5c1fc73b0fea84f4a65e90da3d852e09447ad1e44dded3bd38fe1434fb8e9158776ed14ab6d7dfb1f18c5bd6564f78453a6ab2cf2aa3eec2d946cb79937ee7b757fb39ff172f578590d9d9da5fa8ad09acd4195688d78be9465b156cab88b24800d59b2bf0b95031b525c5638be1e723c624d37b5b8d6d3c628c0289d41cfab5cf01e06c4e0b44e3296e7c2ca9f02596a4b38c50bc78610eb607c431d2343191c4bd88ca65985fa007c09872a6744936d3620c430f583473139be0929303af06b937bf1977b556c81a3ae3187227606f2b0811ee4eb74bd23c4dfea329434f9f909630eaa11c3cbfe65b9c41f39d9becf9924284face44e392577bb40ba7c3d13a8dfa1ef665ba663e26a48783e388851003445f2330ecdc5039ca6f909d286ee03c2fe5d923bec3a3c31294ff2ba4bb1103a00bfa3001a49fe4e42b26de928d76c86bf7ba8332039da7bdde103cb7331740c51e3ed5be1c0426779f68367afdf2986222bc1d3123cae8680fb78dc88bd4fd2ad3bd923c4267b4d0a516315ab7ab661586c46684751b9a36fe8b0efe7ad92d75b9018cac0a829fc7bf18838410d3852c20161ac83f5a70eb1eb4f61ff22564d5eb28b3c28b3a1ad79b0705cc5118516e15ce045070a871df102ad456cbc70bb6283f406d2b0ade04d0ef62bca8db5fc32ae9d2c5e4de6af257e6698b77212cee17704f947109151320989a9910621019448d68a80ecb11e6c239eba404b79820c0379fdae2c46f4d1eef6e67fdcf04461e720c509353ff8057616494e02d254e444fbf8dd662978e5c283b165715b617e2a948db84bad6537c7e551a489243c848185e4d12859f817dc5cc25d5b6d2e0209c99d45444210ed99a7bec4ec5276a12751efc5fa500e5afea445ff68d374210d40215cd6480350b1f60f99eb4fd49e068288b62781395291c0b59c247de60455fd90c8b89061dc5e5b8d4cfd965a2e5b6214fad6819ce9a6c82e1d12926cd78bdd1c5e81400aa608bf2a9d297a2f82f055080e3064fc2a6ed7bf8e648cf7bac947e9e32f8a3a6cdf8efd3616afe6d65b4a09883933f20f23ed03f574ceaa68a8e55a58d535f60006e8b819a73b5e2331cedafa83340bb3e988bfd0d9b0843cefdb5141be6db89f03d42d891a353cb6035865ac924ee1a32ed2c94f11349d9cc8ca28e3cf13a021d8de0ae55a172e9c90eaecd2b8fd702bff22864d4c8048e4667ec5f2aa9031b8cc4027c37709e3ad592a0fa16d5de61222f8145c09d9a4b0f5de193095ff3467d03b28bd871df9c5f45e54ccf99261d980d4f3f31f7421c8eba6d6af3ce2a45b6169caf3d3dce7119785eb998032dd5db6a684ef9cf01462c7e6be5cd638941966cc0dd46252c48fd169df5ab3391a31c3bc7cadca0f34df1bcab34e3a7ca2eb016169219b8d253e2ce00a56fac9f29685e8823f54df12b1f754d3ee65ace0884137cbb1c65df6e8a4010f454cc732d32dddcdb5e96ea0b3e5efe0c6f0c7a7b705d4e15322aec0cd58384fc8046b925b3feb3ffd7601023c7abb6802246c19838ee2a6d608e2df5f3b82a23cb8fd378b2164574945c08b6fecd19dad9777a26fe385a1ba8d8cc3f0031934802c1ce833939719848380772045005e253864fb44d5a6a2e92e70393633959ef0a41c161a56734ca2f9f018252c1b7987240ddc8b6ccdda4dc7a3a40cf10cbf96e4a7aacdf2575f85aed526852e92511a0182e295efa668ee939dbdc4bb761bf95f0509914eab73a065e0cb1c4ff314e573f3cafa67cc3637fb5699194f1eb3f44ab088dcbdd5c446bc954eb20589c80289e25ce7672d217345c4897771fbb9cbaa10ca5a385c9e781f1bceae67c408cc76b307fdf5cbf984977c2fa4290e0d7792043dc5435de893cd52ef619282fa1ee08e7082c2ae181063c8810c29d68c4e48b2cfdc590d990e1944feb0d18a7f3804058d3cbe703a4ed6941f11567616c8f773eb79417a242c879280a7a08809ad71fa98fb46ed88d93c82b227eac990b19cb7a3e5547a9e5d6912160958ce83f5ba7aaa16659db47ca60751174c1190fa21ec29a3e4f6040fd56dc8b2f6f7241cc268538c22003b5018b0a6c37069a647654254a0c0e55078409740c1b05eab2d630c757853a76a108176ec2fa8c18e6e2a8571228f341c9083050b5ad93abd465d92a42e1b0e5b8d18233c59a7678c3ed026235009557c2b5d28835bfba5ea70e1ee640b275bad8201465cfaf67c302bb459c0c015a14f834c16e7d248d0c9a3844c22c81d97195e08492999da947568ab1099ab74b19d6a9f7a3df8ce97ff45114080f390e016395c00f2a703628da9de9b331e1cf6962c0e4e246a5dc60f01f81f19c33b266a80de13d44b23150b753c7fd447dc01cb5896648236cc50ad20e585ee5712ff61f7b3bba75d9752ee3b7fef42f377dab4fd132bd6ffa425963e3680b814b07b80735e626cb1798a4698a456c5642a73993645f40819c03a6ea32cd35817360eb88d7ad1183f318b48f37c3dcef7cf9366081c07265daf28d4b1991b995d15d474d3ae9db8ccd3bdbfb585769f670b9e1a40d748fcce11252e1a1410bfbdb00358cf997b0f4e176bab642de513e2ee9bd2b3e67f3976a5c6e5d8d15683b9f72b0eae996ce03aa337a983bb00e5e1ce534d074f2d9babeda674dd8d85eacd7679e409ec3b5becceb790d3717c1ada7900baa17bb5de8165752936079b2b3de650122c21dfff9963553872dfa894280ff734f00eb84648c823c28301bf754651d9d2dfe77c868804ac24ee3e14541cde65ae0a7d3cd9f6a4b6753161ebc527aef59625e716633e643cf66a5a76e1aa7f14a3e4b880c435475a4f864b61e13d8ce14899e7f7cb7424d585374cc65533598df71c243f4fe95fde2632340931fd07aa158d5dd09e7d38fbea2a0ce023956db175956ffce88318396ef3966967ffafe522ac55306610f3fdde3e6a2e587f9442b6f0594aed38d19ae6496161fa270615c6a81c08949fabaa352e568036b13f3aaaa3e48b8715e494ad456ea1c63f51d02d9760fce38309bd5bb9b169e0e72bd5987ceb3e16836dae54208154e01f0084ce97970f2eaf8e1322ac891f50c88afe2b2771cfe2287fd35820c647140fd45a41dbe88ef3eb564b098ec45c432f7889613dafe571b4f51118a8a86083bf364c24e5f602069173afdd3c3032a5fb4a249a13d1332264b6b8c52b4017c423a17b2d1394e25bbeba7fda1ca85d4cdf6043e86c6eb67b5c658cc3ddc635b95a61ef62ae89f6849b3b939eede1080d28a6df1fb60260448778efc4a002a28cbb002cc212d11f21b59686a2697561c87de63a752a260ab8298ad9e6d1e1afcffa504e43dd037857f9fbaf9605b0b0f7f7360d2e2f4f9d5c6050e71aa028584d7c632f5abc391b595c57d0006bb3467d1b87f722c27064ac24860579443df61c16654dc0af949c1b41c339736fd6d988834473e7c24ed4f6ea9bd8c3a7a2752dd86f57e98010b691ab247fabe5652b82fd328a55600954335130f756bb002f09555fd0192e4cd8dcbba4a0d3035ce0d42ac055ad6f3c31d9615513fb18a89506ffe6972efb9423f6bae3ee075275968bdc82793beab1d9f0af63da829520d21e992091df1b3b9c40c3eade108ad88ab815cee264603d40b5752e1e4cccf3b98516c5e281c974fe9a51ba906a570f93c0f21e26494f3fe8b24380da8c86ce38107bdf6cecf9fc7d71faa2e6d873513998b24a9d452fb46f95edb724e08df2d3cc801173a00e2361f6c51efb67d4845c997aecda81bca85ae65a44e413c3f1175d7e9a4fbd73b04f5fea47daa40f00ec64e95cf27d3c39a5baf45e336aab283b8f0b2fac96fbce34bb702ce2204921e1a3c7368f632b6c461de9fa5e524d3609b13f8538fdfab3b1c47acced0e29d80ac0b84cb4f33cbe80a1a3146a1822be734d7b8edee2afe1c54d9e1cc9cc1462259fe66a01bec026a39a4ef079ec27cc025e39aea2ad8c15a063b3ed8f25af47c94d3dc6bb8469e9fdfd492b288192613662bd8023780e6a88dfd93f047bf885b54c17e3b974ecfd19cab37458b214904937a68d1976e50af9482871e97e97f4155d7b20abfb97afa32cdb66a88caf716ba04eb1ca044de6fbe8c4607ee396315e1a5c1e1bdc40faa99891e9b3cc708d15c1affc1c827c7f0bf28c819ad45255b0272a8cf1f78321dda886085d958bb08845529e0cda7c563c5f6acf106e982407e6eac31a6366d83596f8bc61792bb0a9ad0dcdfb8ef21063ee017d9f30fd440bfe699a64e1958af259b5e30ff9f15a6fcb75ef7d1142d56c5209befff4d9a44a2cd9fae95f8241efba54b44e966678925fd6872532deeaa531c6163639a9a2bd0d4f9182c09ebf9f5d71e18027f57ac086b352601eece31bb41e3266e5d51fd8af998a8eed9f4e88119b010734ec8920dd66d88fdb39cae2fe4760ceb3990ad7ac3c4a7f388231ef888fa721fa75beff8355b900511120a4d7ab0e51ed48d3d24a5bf81faa59ce50d55e2151d5e77f4f2f3391552777602b438a04e9cd15210b1f4c9c7e53d48d2504e3bef8fd10714f13cc089e4a5157132c7a821c0840aaa51175c9f7cba0b7f331f16b268805d232885873c020fd041379cd3ab02c2413e7477f59f43e7b0175bc643403c24e7bdb67843d69773972a73b01f07234fe050728e979bad273f0e7c75a53fa02ff52184f8785f0fc77dc4d3dcac5094de6a2924bf13737d81996edb5c59bb2af2ad2db85201f08507f40061b0385fb580e1fe8c3692677fcd0594ca9f837243fc1549ae731133b0e920160b88601c8cfb6dcc1580a608e6ee58a0c28c33103443c9ca203de01e3e4d691f98119f90b5692af0becf8586acb38ee9d8572485888e22d2018318ac4b438ca9c5ee1622434b5e13d43fc874b72e58d47344d3918c11965df210275e0a7fa2ba0e3385cb00ae836d9259378feb67d8c37ac91f2cfb068f29fc5504cdb470cd12fe6237de31fb6b9800d357ecf59fb5656e2b58d8f548c579816f0c120a34b1f964e688935be94b90efe0038943f014df94bf021a350485e7747ee725f7b95b300df6b4a3a86e44db6002a83b24e661a5ee14fdb7f92505054bac1259828de9f9e58a10446c472dba4d341a1751df7d307d997857e9c6c9a328dcc2f40f63a5ee0dda372d9b163105798f2472b7d5cbdd27da952490e2b4551de821d68ca8205107974d4e60d946d68a9f7e65d6919f3c6b845e3244426cedbe0aeb3259d6c4a9d5b3008b000c2341670fab29b669ee436ab70b9259b97da87a320f7e349c88fdca9b1b7a78444432a2825797e37285481c6a59f6a7f7c52f6ab4bea00d7bbcef4e4f6bdd7537f841e531c894f90e6c360cd02ede301a3b4461ef3e838b7e7dc6335c87661312809dfef1479a35ab989ae0d0654a8ccd68b8b2d62aca65071675128afec0684913712b1773b800795cfa28d55960b0bacc874ead99453f0ca7e68519008e68100563f681f0235fc910cc0c957c5666d14a7046914dfd13f440a1519c02b3e03575b3beb63904efa1854db459766a84fcfafe611b16dbf78bbe81b3e97c1921057b010ac14eea2cb8356bef0066fbbef12a357c70b416c62f46271968e13d8f99728971b98bf9fdb45f7b7bb35f0ef44d776d1a5dbaf978313a76c7bae5fd75ef79363e12dbd6f2e4f2eba6a135fc8baba2263738a8227184829ae772d1a1ed07a8717d58b0729bde6b73f670511a31690fcd2cf534d7e1c6c663e4ce7579ede364cdf63084ed4390149018c2f867903bf67a7e79391ee95c534ca6d3b961ccfe2d7b8eb474f3116fd99f4e8c49b5118e7b0dc63cc2bc59a521f2c2e656c2f634ba01e6cfb9826d16e6a633135b13c9a6f81b651fa7cedc53e4ba3cfb2e21a95be59376bc6e16f69f70bf9b5f2603a98b181e0c569d479510ea08a6c4c43793646eda580e69fa20c2cccc5e60b00f1d3178003ffe842f06b8f57d2c67967e3d4c2317347a440e76dd9f8a6b50c4ec4eb4e518abad7dcdf1e77406fbd710f86a0b730c063ee9d2efe1b41bdf4bd21da8269dc30aa0499bd19c778eef77f5e6aebfbf3a5d3894fa6de962ddcc4bd398693e5ecb737cdb762759463301ee4e74e0d0224c7b6476d83002888359fdba2c721b70fdcf71564a291bbf58c411acb9ade0a06cb82e494bbdb4ae0c1bb270b108e18d55081f7b37316e3ea6f0e0b285ddfc951518e103e045abb10e2c86ec6bfb66d34c88d4bf1e3edff9bf9be0ab07bc4e5c632a7cd8dab1d24f94795f8591e1deff5d4d7a721c7af7e540e8297a30879cc6060745c5e65c11f9a2fa3c22be5a21782aab203160cec52a48b0f3a4679844661ec7a43d34e9a08af3d4061772aa460bf9657d5c064ab712d2fad2b0af887f7090f3da1237d3bc7748444afc63618fae3806e08b3a3e086f386d1c390b197c7c02505514542e560cf74cfc6d5e3396266784489901284c3a2fc4e102b829362aec7af79b68ad99f957611c6d1895962eed65e83936b83df5a9e2a2dcb2473afe7f37a531b16a8468419ea7e2e78f9ca42062649b6d8d1a8e9a3a92428ed26a140bc98e64a67d469b328bfc541147b382ada34aa575948f8eeec71ba0bcdd08d808fc937993d8c9da698c9af976f66922a045a3dfee3dce5a5d82d149995c05acec8227dfda8c1f8e99e2d14985b1b5ee26506a31739ba80f37916956263380c9a38a12843a1f9ad95b5e85472fc662e70246032da9be6ec6ce126e2d63e3229531be477df7521a3bb8ff6202195ee0443a008b6de142053708bb207c601ca2579a178bbdb19f7998ed86500946bea597a613c751de216f5ba35e823172124b4cf165604a9c89afcb98bc5a17ce10d22c6a7c983fe2e8a3e5a17a62513562cc660885481f905d330d51ea43b3900bd81b101aec55df07c54caa9aa409e652e875551f1a0edf6230ab7fc1a937f2ed4bde598a29fc3d26f62e7f0cc81f1868182f089d3e0e794657591bcbf43f03f77524a97f3b4e927eaa06bdcb04b1db4ac3ac410a81a363ac3afbf4f324af2c25bc9b934ab0e785051a2ac895e6bddfc75f73ed36f23e682066ccf583fa2a60cedb94973c5d87c33f16ebdf5c5bbb86c30eeafc3b76c276f7391de7553376f74f03a000914ad41adeafddea589153b4c89404b9d6c5f1c05879d5ac6691411a7673528a3685118e4d43449189a10d711a0b335701f528a031597641e2f8aebeb00b91a0aab6e6b6b1dc79b81b8bd70a05316baa15076fb3a26f8f68d530d6dacd9e8e76f43792ea1df7c3ef3eed9447464aa01325fbb596c12aadd0b688f3c76b345a94d083773cfc482f5dbcd86c40e09db94e0a070f0dd02a843d6153c96e1962ff03923e5be09d412dc50663256a8ad74092ac12b49b8e0f52bd0c12723e439103848119871380a61a531e45749c2358b42203938f2aefaa338ca5f1ce42b6a963cc72b3cef7be1712f83a5c75ec43401fb57c106bb194b8f36fb94cfcde7d51c8e925a514d3b36d4f54d1c7b0fb7a62f63632b869325bcddceee48e7bc03675e446335ac874c555715bb1fd15305499e23c511f106e7c02e257c70de997eed5a918040a911781dd304d28ee10ad4318af93a9602d9106ff3c9e6f74c76a74914b408909d9ccbe945d4123bff791903e900505e63417134e87f74193828d659ae0b35758acbe73e5a7631c9c72b4d538631c0d886960da2f60efdf0402993e186b0be88cb3a1aa3595b18ce51261a24dae766dcbab4e57ec190228db74c3f3456f495abcab449a106dd17b7c42d234e4508d4745b32c880bd6499c84f3e46f994616d644f4a3c8906de4d555332b6bf8652dcb0fef2289b1e4120efab8b780bcc90e896b0d62d46b0298f2a8866490436dfb5d1de01e7b3c3362780dc9427d4484b86776ee00612a3dfafd5969c315e53425fcd770fc2c07eaa4c98c06e3c9c4461e85148ba293713d764af5fb403067ce587e883c422ef24eccb1aeca560367d5ef4201ccb8c20f239d9043fc5a33c6d5d8ef9d3c8abce045ba08cf0e8e66862c119aeb380ca8b87b4a45bcc4841ea0cbaa0f5218b861e80f71fb91686886d4e2d2d9f154568e9d264ef015dfc3fa061358a53b815affc139b77e5d5fe4c6f1b6d7fc8ba9f31279619a097f1f544871a8e9dbe9e3cd0abef161203b1bccc36d1013167e327c8962f28591bde1290a2d4b4e667aca5c96cdc520dc14a4fa510ad6ae2cc6e917c3551dd268f1c7451cc0e30bac9899ac417bef95cb453d61114f7439aff16a078b386ad9ebfb60437dc0a17004d62f10837f0d62c8dbe53a4e95eb59878f52f42cf76fdbbed6aaf58fd73d31524e69a508161243102fd19e1f136bc196c75d7be357096a0b528e88bfbc62d3a9b0288f9718c32c59e4f947f78dd8a0267570abc58a7f8eaae7b0269d5b466ae4eadf0451ab36a83db8c2d06670db9468663aad0c3589aa0cf94d6b29e74e36b998337b04c9dc673be2abd59e42eea680bc119bb281f084f1c7eddc6c9917a527756a0b82b82695b7b147abf6b0a30208cf8e104d5a1a3f282a54d248c01a63b9dc7a76e9aa4dc984140d0797912522ada42bc1402834e86b9101a18de38e15bbf221a9f318670cba47d5c4b3539c59d743bdcba68bf21824c6839665c995f3eecc3271b2395281ef0c07f803b27a62b3bf573da8eed0beb9761a511cc5b1cd01301de621f1ab280c059070be9206d810610fbca5cf4f03c84f453e94ab14425da72371fdd3cf8e6aa06e908a46c68c2754aa6d6b084a48e46e9b94c9e7a2e7c759c389927967ec2b5b834e0695e70c77b0c620a5f7e25910095d631194366a8f4f87c106f60403a0fb43e03eea59e052036fe7720ef863cd52e63c51b4eeb072ce8b5d0ae9749532a543109f1503c6742ba7c600bd87d532d8d3d45612706050b852677c200ed123f8eb58178757ab85bc04ca5f859d14689c202ec3c3ab5b4312f58f606430b8ad506c72d6a0c83a4d739de4bfb736cff4520a8b6b1efa1e0ed09eee56c4610a8b0384b282fac8f997fcdd4aefd120114d4f5c4ab969a15bb13104d035610f33fd07f7110097d34f3cb31c6a84840d77516c07bc567f24dece5e12cd53d104ce412a3306b0ac12604e8c2bb97a5c686716548bb5c98af61685c8aeedf7b96a9694bd7dacaa1a5694e21be422be132a91963e3fed03e5f179603407926bbc0311b765ec22afe9d6b1900a9a622196a099d89ff5d7df9df1cda22adf21d6fb28978e874a3d6430c19578aad9fb2c0d43cf1c0241ef71e8bce834e8a59d736c1b81a5ebed419d1e5cdca74123c50ad95376bf60987b1633f379bc8755041cfe03c0f6a12c175538f5525e00b8f8ed2b29c7f9d805c95db2cf1dab9ef4a71f183c1c1da91dd14137e0e52f426be503bc781170e67db00f983381c953b8e874987023c03b17153b88338f08d9a87c1bbb6093b0d8eabcc47f13a7227499890550ad4791edaea905ccfa63895e6540754a3e5d3ddde05811c6752b65fdcb55f537e4884ce6f98eca2e43f41b7bfeab44c44ca1881143ee26451f3d43af7f2a51b680100ca5ef7c04ea57cc23db699b8feb4e7413f285762b71297a25f1ebb14179c734008d7bfd9aed7765b4ef940c1bf0e912b5fe5821e7137b93466244e5ac308bdb8c3ca9395df43190f2c619aa1a774f8cd3b2115d44736d66ee402c20c5370d8e4f9a14fd7f44fe0c2b6bb37fad43870984abfc3e7bafd4907ca5e6648fcb2f0abef6b3ca2c25dc3a6c37772a2374b79435155773a25d5026886ec6cd0d8996f96e9433018f771da17b45bfb709f540104e6006233b9b64f827fb00b785efe3eeb641d4a2b3845ffb34912eb85939ea6ccd72d089f4cc0126b41c18678caa80efcf667d88bc5f52543d95bed461638569e4f0098f29c133638c91b00e6743579a89e7ae13be0bd02035497b4471e9867a796bb49fe1e8b760ff1b8c307918288c16d1cf635a824fb8dd364eef559abf1b6d629d18a6c537dc413a0c363c7e543cd86d65000bda0ff2b2720c318b5c48f1589da2a02a4134befdf688cc847a66db508c3ad722cb1ffdfb2255f6f9e6779ae423fcf3dc660f4ae885a9d3c176429e242442f4324d77c33467345f066fc4f1c2df629aaad786d948c97b9d8ccf966fccda172300500d180e95533ee9c59af9a94ad95dfeb0e691c367e7266cf3b84bd81f63c92faee9afb1280d63bc448f61657fff1a18761cdbc3ccde2242253ee12f47565bf62196a91d292f4c22d814e98e7f3e9f92b57f41f37ea6e303713ea457f35b1fe14e80edc32efb3974f033b8f9bb3dcf743b5aeca05837a76b9165268ddddeff51f9914a9aa75b92661ee8a178639c465a422baff88533275aaaee54005c6951923400cbf79ae59a502afab0106d9757adf0a75a35aee9bb77449768ff695bcad682291b1ee99648dd9108351d5f2a19c4a9a100472d81b09f2f402d6797e23c1348aaad7ccb0230baa28e7bbe0bb1aa0a166f0314ce6fc554ce62237e26f4ddf5eb68f7a1bd051ae025ec866ee8099c8256bb60c7aadcd713642f28751d2f8995ab3bf905fa8e086ca008f0576dc0f50998014c6f91ebdceca1a3dcf4ddd8dcc9b04bde7c14ea93234442c3ae0b224bbb3e37290af11f36131c75c6e9bd9b3835442092d565ef6275c48c788bab26181f6cff0dcd3c45ad61cc16fa5687b472ee9ffdd0d4870e30b5cbab039bc9036f2f9905c6375627e9029bf0f441e7468f008fb76e81f8b1aa65e49df9b3bd7b921dad9992c34d5e1db2ccfaf140d8b18fd7128c74f175fc248647708b49ede524c0917a78580ad85e20722e5d466f4148c505c8fbf600700bb94cc4c8adacf03424192567418c61acf45e03c5e5e8ba0f26f129400c44b1ae339f11e3a93ae199735920c1c63a96c9ecc36f033011ee04123ad0e4a948f6742a33a9e124c1a06adb9c7bdb525037e2d68064f351f98652e4c2ca1cb3dec4825dd48ac4b02ec263172dd55fd594123a84c6126b1155bcdb1dd03f5325a7b6e0aae2c9a2f8094964acc260844567d0a04acb30b365be788775f9a73a54c89b586a1af797e4a212585c2be291156aa1b43536f2945e194d29c3ce1332f265ddcff2d4bbf9d2f6a5dba49b405bd05397f440f6826039aae370461617cc4b6f01ef93cc16990673d2b6af2c45d6de88d306a407836a9a0c502e588d0d8de0b7aef80a1a84060821a8c49e75c54215fa9096a12c089808d2841ba865458584bc5e751b0bd003ce692c979bc6ca82d8ab588f6b47c61039a43685c13eae6b8980208781eb145923a3586a1c9d18659bb6efa3078b4fe817182420a1a987ec64fa257b5a9f859c4031021c3a251b7b42c8b772c125e2233b5701dea1db15669126d61fa27fd652b1f8ef2f68bed2f32083901e5161fb8ce9001e069e745089cb056813a9d68a2ae40be437f021341926e597361edd46e8371b78e12095c6653f34e32737dcb9fa7ff887708314b4756a78be91935948a9d3fb25767336e077e99a8856eee956775bb78767896a3fc7a49834fbbd018eb02b6f5da9e67bb9a3cd9fc47ad45e22ed60c1b433f513f352e002c096abcd2f70ceab802d55a99af115faea472258fa7727073f266b5f51e09e282dbc93e87adec84a942c1c921300acb229ed21225215b2377db715c5c1401150106bb798c0bde5f868ea93fcee61b8116183799e2a7046035a1a4b012d9727fece2f93165df497cda2e2af581c7177b8a6c123a9ac7f92036acac3f8d153f49448cfa01cbd1a2d87c92896d493b487552c3cdd66b1b80887b7a48fefda1e1bb32d5d5dfec93089949c69fd5231feccb3c21969f50cbf36419d6576d3f0464e19a77b14cd4461e87b46006cf52d08d04ed35d862d23276718b90a3f696293d0d2f3e2cc9537fcfca09f4fee8150beb6944dd9a138a1ca3d760b3b41de093d50f311de38244a9a65e9cad5f058e77cb1ff78510bae6ae90a6ce2dddeb8d2a26e231a2c9181c044708d0a7a1f1e05d09e24d1165b1674cfadea2c4e79e95a93ab4b15eaa52524ba439af421bb3c9e586eea0848e5b5c3c33766975b2f43b60c1ff368a6152df0cf3f9868a43260e851c8132708170d3abf286c3e6032a086e9c3e32f4eebb0a703c39548230d0415d78f178a05ced8e56a2e506f1b98e4dd65b990086d923691ffb0b184091f00e1f236171f636821a70b6a0210e494fd8424c26cffc3346d88b417b8a389f3fa041b28aab92464cf279b84e58084b4e421b8770236743df1c8f2dd8ddd5c7afdd96e4d50e23d766553521e8bcfdb65661c9d6d595767d7846d3f0021c797981da37deb06dcf5de78ad6a9666d182ba1d37e42e2df5745faef7592f6f4eca8e1ab252585d761d64939889af92e789a8279697cdc5e77016e788fa26bd6349ead490deaf6eac687b330297759139c91207c245ef7dec1e64e1b504920593b9c3570d911376343574d266dbe92b85faab5bcd4579915b7f734dafb6c32498aacc6ded10d3c2ec7d8d4719146781b313d411042bc2ec54df032a929b711e8f59aaa987d678b9d9d3dc0b77bfc22a743f04a0ccb4e9e88a9afad39446bd21de91e53907a70948ccb7991ccb01202610fe14c6fc6976ce63a21643c2d536bd31bd42eba848bfb4a6683b5a9cae5291a35fd0c2a728a350bb639ce09832ca5bea781fdb74005549b5d838af5bd199f3e65ec89f56e7fe090575765ee2a92db30347e571555507df82f78a1aad66962b54fcf9b9cbb788030ca7761b54e7e0512ab16c044d6f9d6540bf00a59c7c13b81e154ea3ec960ad24edc73a3ec83a1f104ed535a32b060ac0bab1d50c0f596b88f8f1dd0e533d609aa44a2428adb0549f20e36cbbb5a9d78b0574dad38b2edd6a2b2f4f155eee59e4cdf578bf00662967e5dfeedd80941be83cf6f4dfe4a19e1ac9fceeda87e0604a8ad677363fd261645e4e44df3bf5fe22a81cad9a2c04a28aa70a217f12cc867b0e458e3e286365d3ffd8fd349b7040b9c02b849924cb1e2ccfbbe2ce81b92b969d17015b017545d7dd35f9a1c80f131b51fbff2076b4c802e59abbd0f1630c8d67abf190ac0e64fb0bfa9017b5379f185096c6acf4f340dd2bc672b51709d78972581de129d847dcb5d67623e3ec20023350cb7d1c0ed120035a79007f2112de0cd4f8aed861b530e3fea630c25901045eb3bbba2ab06dadc237ecf7feb12a52f48028b66329862343d1b054b648ab1cb0c9f179a9f16373e55fa2627ea9e0b8f5c797c861d9863678e6458299cbb22655606bc109b3609cd7c03ba0c739515defe3d5b78053ee117843c93b23daa7191a448860c7d066ca17a4a702c5153c81d84f60bde9e2299327a17301df0d65650e514bd836680042701138a5f77ae44a90f88ccf47bb55313b619e1723537915f3f04d363a8e5738285b2ee85bff92166beb329ece20fe6699b3f03aeb85b13ecef64a0f14ce5a09078f84ab8c80ec56fc23f2e1444a6186e35198d1d8e52d58e0e32a34b83b8a65489387f613681e5e383d88c329ae080d270cca47e307c86978cf2c0d4c13c6a2adfb797f8b99c16fcc0bdb4074bdb148f612df181aae16184358a850052b5de4e57894faad3c131b17386c0e793a42b593e82dc75a2a044ba05b0eef757a3a0be45c92560280499f5b14ae62380a9d2a23c449f3e4dd1becf84dbb4f369d3c1d26d7876937839664439741930db1ecd77b6fc2366ce9bad0724ba2a007875b99a7a4ccd4c5785fee4b15179dc30dfb69b1b16079cb6beae37ae639dc1a8330ce862764668abf1123e34692d8a18663499544614c154753ab42f897324575ff786c1dd3c6511c9b8b57c8745fb3032186cd505b67abad1866b9b87e742bc0df940e287769234aac4c043a2615c33b74a003a90bd62bb8fe934fef2aee954c38be61df7757c1432787ac5efbb752629798dbd662b48241a66ea1d839e5c2abc8d3a101001686832c47174b5202cd73166e5fe87b5b63622ace49a9585ec11eabff50289457d012863dcea9cabd1aefb93c6759b939d926a7dc5220ac8dfc7c67b80c670ed1786ba08c7af2d4ae938e503f4a32f06dba2d691f954c6d4d2b08225d2662c5e8f842ebd87c117e2626fc54312272707073fb16b4b009507f07c14cd59b2a0ae3f96ef8036d681abda3d4e5b6523287675a997745597d514df1731d256988a9423eb896611bdfc6aa08f271c654419e5b11524b2dad1a155d2f8fcea1c8bab0a3a99810c15c92071ca1689ba2a3c75f7aa26378f1e3c596a6ba3c0081b74e6c2fb9f804429172a70dcaf38a104ae8e1a29a4bcebe89c0970947d278508e19c787c07d0524e02a9007cf793db53b263379ba675706006591a154d08db1f210e0e0d48e4b9979d88599b9cb36191b5444a5e7b2eb8ee89f5b847a847d8fb2703cf0047c1df1fa50c938c4403aa8851299c30f5bf809e6521c7d58701f6ec9297e1d477483b5690c1946a9949406fa1df4dd3995280e8859d63fb008ad11089f4311b2eb07c45a82939430a6e0acd86f096a4c89d0df5e75fbea80d0a3b24d234dc2b3296c182c6d14c26e5091647e6635f3f7056d57513dc161c8d9868081cd92f894152a8fda6d90d7969a4ee786b523c240b0a60b97d906504d5840a1a0af8552085a81a29e980a37523a5ad25c0fdc12a231e56f71a572f2c6ffbf8413ddfd7211a2a5d9fac0a1b5242ff45cc30920b65e8db5945295649550892d4c3609a122903ac1cf62cfba1f50a7abf63aae2696472a2180e5902e3bc0010d5757865ecca31190882a02ed626176e1717b40bf1f91f2c2eece43e565fd0a8df7e08f3849ea23f490bca9eb2865fd1b37da2f3a958cdfc72304ba11236b1b399e070194fb2cc8f13a579ba8047a779886f345aa166a978283d0dbb65f0f114cac58d244f3a09ff9613481f05b910649b7b31695bcd3df9b099f422c825a0836b20d47eeda034f668167077ffa89e15db2fb46a9b6fa8918d6da4dc8a302639fb79f945c977f3dac11fc7efab9a45397bd16a7421664ad21140c109e4859122d963d0bdcf12fdeebf53a66e965224e69fb4a1f63a281403ee8ffed384ba3ad7014dc5466226ae5e8b376a515439a8258b636d7243790fecd946c009748e73e7d348eadb412b65818e8a8d101a8d2b32f888a6bd63cf88fb729bb7c868c63a67916fa803e1d2249617a81abb457f882d561853c38f09f28a3eb54accf9f797e23de509a41ca890b22f6efa421e817055d2df9838fc228d60d3b4e3f961622f78bdd52ac232b5b35b83b114c9203b8592769b704bd5f5e7ed5a3d97269ae8aff99341b4cd8827d3925d6714ebd7c044aaad172e433cd83301694e93532af341617714cd6a8101b394f227462c34c1ef65a7f634ca33f3fdea16629ebe154d090e1e84414de7500abbed835fdce108e606bdfe0940da74def081bf69f2ee9c41852696bbb8410a08c7763757d35d5ea6f83b157f22f6be803735a9c9392bc1232182025b417cbda5b27f5409c468177346012fe76caaf2dac5a551831eb0093b88bce8ada67bf7d738b721d99b2f271ba9d99d9dd15527bff7137806840edbb6afd78256913c350326a1c3481c2abbf260a619e03b08b835306639b1911aad689f794bdc489064829f51beaa7d6e2947e01e1ae9a64aee283729754768d6772462aa0a3dd70d341af5fe51ef321b78f652a0ff0310c0486bcbd09d9fa9ad00b1a21f9501bf9c58316added8b2bbc93b4a06da9fa5c720fb87633d0295a3a2cb2901ba9f91a96c8193814d637fb877ed620d414403a8548a9c63aff47db75628c660a72ef44e306d4eba348c4e71c7c025c49cf81ad5095f4f9b86fe0e7d43477115d0b0a599968a76714b8e55814920dbacbe9944d154ac75eca9ff6f523117e9547cebe98c6369edd3addd3d8b8d0d5351fc8552266b4a54ee7055a4ea981e30b5ac54d849a4a4728dd2459af28ea5f8e9acee0e60faf4caa13e12ccda61e740908a926c62cab00132eda366c9a62e15ab983377787e56f306444f34b0c94200f5a9c05d43e129434c07fd8c1fc66df6d192454ead4c3ae53778c71e0d919f4ae7d9f0748c63adb80094ba99113a1017d7aed0807a072e8b1a71b5d915efe7478de22d90f097662bd9a614269295233d3c8ad26ea33a0df37c8de331467edee87360fd4cd5f1d0f6f54902b3e7a875f6a04fb46820c59f680d5b2032258692d97165d18deb22e1245602ef9b156a09aba19ad133e51c028788e87a57d00a2f9664ff5f56fc7fc90848a1e5086b7aa3e1c4186a762e299c2456caec5b062e064d49526a14f1eae45d2e2ca96667b1ee01116ad1a93272a3776e535a5440551c10556b9a6fc120ec5d9a6591d6ef3820303ddb65dc9f2d660e1bf58bb5d8a81e91a3469fdbdbf5cd2b7040c206fc7b790514730bf3e0aa5e67ec37985a7ce84fcaa39554ad29b5472dcf23d207c17964d7a236b0d8326f4482f45d077e9b162e299b0bbfb3b21679094d6ebc545d67bcf109568496d6da06ed8dc6c5ef358252a4a1840a5ad5f0c4d7ba74eaaddc2c6a17c085c266ec4eb0840441c57d9278f92008875313b0f9c04b3149ba2ecc586423ac70835f8d59aba4f9c989032d027f9d615032cc47387129b3081681f4091bc6a1b3f364faebe9d14a61bd99e8804bfd6bc4b3b9b9730ee0db7ec0ff1d8a22fa5f2fd2eb6b7da7b032de38ce1cb03863374d3218bf7ecedd77f1b7bf73daa10eff791c2fdbf8b22b37d3ab5167e0286f75f1521be6febd4ce92ccbfa687542d482fdf23251a19798a474f23930bc52261948204b2d41a27cbda83454b5dae6d490fb60306b5d20e82c0ecc75b98c4240f11f0f759a745b8b262fa6bbf8eb7d1d52864ccdf77594610a572630d9e0ed9f871c5c36f76180d5a5778c8141fda976506991d2587a1029c830858c6d97ad2442947112a1dbf401ae435a81446c4055dcdca12b3ac08b9b72479ca4c4e8668716b1f77a35512bb4ee98657138927425815e9fadacf63a44a7f7ced7e87340ec8ff9dd1efedf7c9881c192a1359c8f41ff9e5eec32eb7de080756b5bde44f17e9f66de8e63416ea6cdb22ec722d2158f512f060032ed8b0d8f4ebe64fbc7112ab1692663ca37559c05c17a6fe3fbe201c2a1c3cd7108a6c715e8d8ef1c5771a023e088a8ced037a168f8bab7ce6b48b61d1aa05e2bc5801e31afd3ed5f9a70bd3fd4c8278d25e6ddf559a015caff8eaec2475040307a8c7c3888af8d03420ce5d71e4ad8d43103879f0041dca8832e6d067bec8ac3103ee20a5ccce39ab6b546e1fe7115f7bbf285a57d21a5d5ae408ed8372afa720fb50b04f47f7644e3058b6802fded8d18778a89db4020a7b9cc192cde6044d2bd5e363693f47f79e638b76075a0cd7b25eab66ef4e7b6f5aada2eb9fd860ccb1ff10766eea351145a9071f35d421f6d06e4673d23556a2e943b54811451b36b8209fafc81d908b44fdaa6000ff35b45438987c46f853215cdbde5b74a2743c1b82649491cf2a6885fd2e76b1f69f3973b06d24cb3b140c6ff62ddd4f466d9e394309642db6dad8cd313f708f018881b53ae2f57f202bb2d70cab654630b1acfc966a3cb87a5346df5415dbd968eca78a355363edc503dff0c1229b8a1318755e122a3ac84bc273da1ed33171c8e78b3f8cdbc42be982c6036ed63401b8e21cedb6199c1bfc5d20511830eef57b636493b78c81425a85ea985be7b584cc914a5c11e4a92dea29a2db922edbb4fddd8160d60a0ecc3f4f31e9e393f18710f05c272697905f00b429e2b369ff2d15344c6a1e02442ac583c0d2d1e04e52697f3d59952d39c0342fd09d7536bdd42df2112c5f4e661ee5af31432ea12bc73f3e36301f11a6cfe80ea3782fa988ede35c1a88869564970b972e2a003bf2077eabe33b28c37865bf323fb02bcaf6e7e20d58b3df0e96e38cace6e79dc0786dee70e200ef7fbf8ae171c6587537b72b16993c29d35f28f24269b46e083f8206d4d6986623a7a26a36f29a3e115067a5030218c3066839491fcb015cffabbb09fb505f9067057f7bff7d1332220644a6f14b7d6df1b56138d714ec1263f4029cd4253b0559792da586c9675b31a02b6a5b15a4bf4e955e552f01a377832cd2c56b7a8937426569a9fdc2076e707cce33282149faee8df2dfaebbd5786ae3e769ae8e4bfe8834393d586a0cf3e608551ff051ffcbf28526f5fb6c67b2ffa1c7bfb1343eadd97930a5485321025c9db16d13e1521f4661b0e2b7892b9670e960d7886a6c829792e3b19742fa1ee61ab1c38310aa4171aa99a1c05ff33e14d423e0a0f754fe2425285345a32907450495388047fdcc5a6141c32067d5f39c93596f08efccb48b6c5c07942432223fa289ad9871884a9974e6b405783a0f05392e008d0eb66f6106db45441561df11d12ac9fd095d446afcb977d664352c73390beea618cbf0a86d7b2de2e90d5d19e6f59aa3fd9baebb495c3b7d93fa876aaa0a41136511682a41f0dd38ade123846aa099429d1cb53c7bbde95543bfe321c346ea2581f9d51700cbee9d54e611ba985b3b5a598f43ffadd5b8ecec0701912e97290869c67c515103f370e83b365250def0ada58ef6993f3154330f269341a60a168255d70aba3b1e0e2cddf93f33861760aff0ee2f2e20f169f5e3f7f0b7a6b29234d7de4c513427042db2006ca74518fa2a0b42d4a24051270381072527804ecf964122e5946865061299c91f1d46301fc6eef16facc9ea6f092c951bf48cb936c4c0f5ed219949203dbd956338e42c669934400042078188c40e23957bb62ed3ea331bb0e47cd209054c4c2dcad672def4807009969de12083910a8baea698319c98bd8b60b76d49de5b6852cc2421b0cfd32dc16a4d66004382ce171908a088d1055d13c6502d08b271cfca2ccac54d9237722cc33298acd557404957467fd5d8af9e6b1a3bc783ee4de908ff7e51fd350a9eab6ee0c0a5a361a008e016316c9cacfa2a20ab363bb4b7959ddaa5f124285c91b1929349672f09ff381017db232b6b0953346b79436b0d5424ee46b4fb276a6561e8fd1eba36da9a5ef1da9afb9a59d8c28adaa5dcccf1d285c10571bb51a00cc8232ec4949e324a0a32d82c299af7a267ca35d69cc1368565071097bb02ae2589c6a4479d92769957e0b7f95d1134e171df55823d0c76e90acef6d2887c201fba7414f0fa624d520a1f854d4b6495f8ca5be04ac7711fbf7e096edadff6d99fcc254401cf84db603b36204a27a06fe41a9961e1d5dfbafb322b5e2f2ee9b2e44ae7aeabb40c7e7bea9415754acbdccba3577400ebb7413f2009903acef1b54c940def66b7786c55dbee7abce22c75f2689780e5edd420a2397e95fb63cf30d1276de24a3dcc91219650822b92187effe31056f9e54e71b2ca0ab27d5dca6d7a1dc6618753d1193bc1de8b5c8c50af580d122b91f41e21d8e0bb6a9d002eb049d4fd774c021680ada83783d4eac09c6abc3a4753c6f804e85ae832c12fc789e5f3ff031c18fabd908c86508a11502fb4a0e904fc1d4c337b999fa6b715a6a60ef5f3062b8c09442ab1336b07c52e7abe1d279bba2dcb71c70849adeecb37a5859cbbbdeaa144854e0f2332711142a81cb17e636af5c456a57f49802c6ea78038f326b506c116f971553db0af7d62380ac7b4629646a89c1743f62aedfbd27212831ac8d756819c3941ffc21c59ec639a75d41840a2d55d808b75917f65c4dcef87bb0d2bb3aff62c2d758cb958924976288d44930eb0bfa51c146b3356533bab23ac960aaa4ef52deea04a2358e9f81defe5213909d05e4293da2c5b5e211721b1bd47fa370fe7786270a07c3c069a9e98bf20e5a318848e527b6d6511981d19d60f8810fc85a70876e6991196328b54a4574d27d0cb4d16d12176f603b70c46d5d33bd6e0e6682f79ad09193229fcf9c1747c16e0041d45d77d2bbf35a49775481d4cbce302f80f4cd4508b6a466e0d13ef386263bd4197a6defbcb34c5245576edbeda1f77c05aa07e68fa3fc8f0d68c50c65ef0a952a15ba5e4fc0e20a6a96a85669a4e86400ffbf1f3a3af525c9d59e98e8952783f0d30d3a55e64730019c5d1c154cc97a8fd0eae9d047c547e054a84ff8fccac345961fc3407afe5526ebcee2777f166f6518536d264765c38f12757ee4c5caeef632edbc7aac4b0ae21a10a7f4b36e443ac4a95f223eeb9a3f15a85ae80ad23b18cfd0e9cbaec1f812df7d13383e048ddccb6834fb177c72974048d6977b4ec03482d2dc1f721642031f230fe8442017101626d84ba1477cbaa3698eae40709ce2fd79c9beed74084c99020b4bde94a868094419328a04e3d294fc5112d6a44f4c929e1a69408f56341b321c2e839e2e1d42f3ad713822e27ff27041bc45be05043f3264ae4472e973c0f01d5e2133aa02776584f2cb0edf152df5ba39e39ab900306742c42ea7fe7f3692a5d8b06f1c9c59f0f677d52c3e55f6661f2cc6d308e47e7a007ef9739132eb4a0afb60bfdde35d7c67087a87677d5d568120437a0f29994b79c75a22a752542db469bb1c4c9a0de0e3749e042ae36d5fbb5196538700d1f4884d83d6bf9b250adcd7bf0e89c02057e656154f0a3070c85db69c3d1dee29fcb198726e54e2a58faad9afe02e8dc5774fd614a0761f13c89d7f3875ebd4895c72386abf3e883c8ad0b2bf0a0a648a1bf3b7f0e20645e95829f2213781ee0766ae6c7d6586b8540ee4f99c8cd655a673d36304c59b7794317948a9af2deedcc66b87042140ac0fb33b47ba95f78a4a147e679f38203a4764264c0cbef7b07967d50090c2de6f9de9d39a9b3820adc7c059945d3775e90aaea6340dd5e5e444caeebe572f25ef0b3eba292335c0757e1745749cf24f1dc23e4ea117596bb6676c6a0859c670319a94bbab076577700bd042ca316d25645f8849957bf4c664968a0995449eb735d7ce1bf9cd852e45f196824f6670bad517f3d1efd2b8e800cb1207a5f8702072994a504a9832126b450c251db7a0c69ee054aa406aa143f9c467e872e751744bd72eb9e6bb5972185eb9930c4ca4e8bc7ce2b39f6c92d1104cf9857c2c0762a81c4f363dc5d16ff23993a4d448fe4c2f0b0d3352de4d1e74b5bb3b36d989ef6cdb8920b3cae4995537721616aacac9bc2223c698373843350249c0660e176f0d4eeda1875b249033d4f27584ba557097d092d8fd3711fb60d764529a92587e89aeccaca41fa86433891f0aac95b22e99a3ba34c5bfb051f0ee019cf6c3f0559b62cf88528a80ffef640a9ad737974afc013e140941930bb4aa0b7afc1a3e6bb016c1902a06a616be7a2ebcb73672ae44b82c71e76785ee4f5fef5ba61b612590ace7b7a1f5a6b6eb0c19cf910f3a7f1ebc75834275711a14119473d9f2445971df5f849780091d62b24f360e968d0cde95be78b47402004ab02cc9e64c2cf0910bb4d1669e7cb8a2591f0ebe23c1cf8074f0cdd9c39b19355d6771a42e591f1426dbdfc5def188cf931421886087218266318582566d9027e7e4a3ffc928754ae147f26cc23d6828207aa033b43c33342460444dc68a34d92764e3a761819e11e83810e5e8c4a7d8f53173f86a0f34112212e11a9d57cdc51965324da0652bc456964d260242938c0c58db7fc38714044a59b3d4b4b1a41029be1164436fce4040a846bb8e4686a84dbbf1ab26b7c43930d80a6b3e34e461a670fe8970abb80c9198b0f0ff5eb10f60572944a5a20a1583448adbe90ca05391385d09627975e6d3636fbda76519c647547b12079e8e5890a1a5e5466d220fb6670863b8b804fbbc154857b9ac5eb4b5f8b7ce57271bc0becd0706b8e381ac1b25dadc4da8d348dbe1c29a10291688cfd89284e55a957d6ea4d4440be63982120b85898aca798553b00c50d5cd69bc512ea4064a2c45af190cacb6f8c7ea6fc2242d47234adb7861696a2c6dfca688125b033acccbbf15b2b665211389c373d921d3398f09b01dceb039e3f221018320ffd3c1a9b183f1f2ab88e804e0b8781a3d1b12278114e58d744b96dd9c54a9f42dc6e6af397a8c7edde98ea0344646adfb3bd2071989cdbdcbf018f2eac62f47d900aa4b0c3dde406f5bc1879363cb5ba592004fca1adcec3b239106d8eaccde125ff937d2288df7d8a95f075a7264838565eea004022c99bae261e47bc40b3b5eb83c4a0a75e5a37e478ae9eabc307e40d234e9fdb3ea932869e80c9b9a2a0cbd12b8b720acd86a512505676627210d242ac8347d8bf50c7a558ecbf7472e4a9eb2a67c1cbf533ee81892ef0022f2d2126d6b5a42d0152478b172e42344b1ee55da21f4fd82ac9beb66ee264ffb82acd835c598e8b9be24edc482c1d19c1b9860546c532ecd9252bca20012e77b0d0edd5fafbc4bffb4aa738e36fc2040628367d0a1b03088320614535e074d3a69d089567485b92b79eb50597d3b76ceeac071b10c2bbf999d31a31133534d3e4c5f1d204003254b51b161a1cd13cfc094201dc9d74977146f2676f68d6aa6270da4fa4cdf4a95d6c64a91ae8ed9132bba58f8303dbbbd54183c8f5691a502e9f49c55d7113b48db972dd4d99b46e845fdbf8ea8f1c9b82e4af6761cb1cfd4cfe8aa8a441b4988777f30ba1fa7dcb12b48041cdbe2b7e378d1c2307b01678eec11f2cae287b6e4e0c8f72ed094763251ed35ac903fc14253f63f344b1d4a31a5bfcce3f11307e1c5128c23bed3632da95f879abdd066ca7b3d7719c8b47f445980a6b546bc29c219507b9a0daf8e6e1f8333ca733c0c99b1e5ea48090bcc40328e526ece835add38ed077ee518f3932d10984e36ded2e646f947232ce73003e892220af241e3984175158114132468d5a360b534c5a69e503efde54a3684a2cfac9596d69562220723acea5ba39547e66d3a91aba498c38f2e6397b716455541ad0dc754e147135e238419858826bc8e5c61914815edd1880b23386e619daa85c3ce7d3703c32f45ea0242fbe1d01239391153a418894fda3f4a05eaa0004124da06c19657f18678d63d28e6ed807655b42c495249d0e748f2f80238e8fca6687b4413e6941212d1b001dfd6397c8bfbdf2be85a1adb1f8cdf71ac8dee0f189f33f59d44117d09d85f8a018894332677aa8599fb17c8f690ede161010ac49271e16179074c440615cbacca31c0023b481ec5ee4f844778534adfa851254d0b158a3245562bbb0520ff33c3c19ea3bef2122bbc4abeab0cc3794f93a1d69b10041a514b40534b705611617ca1143afb75de9d8d68fe73284ba29c5e154442173a977ee380edc32c83742f3a3fca861cff9d474806a29cd5ff61bf60c33c42f1b5914c06e8c3a6f202fc196f75c5f2ec6bbac9848b728e730f5b58f6a7ce9bea71e90f721e3fcc26026b34cbe032211236d1fabb29ce1d89b35f3bc655155e4587e6f04ce540cbb97cb8d94814d17ebf7b065eea08125a35352aac884c60be1015fee6f001fd57985be1459f08314fe1f875660b6ff096a28cd45cc93eaa9b3fad91d718512958788fddf6624483cdad7248f8e8008abaeb9731a1ca66304824b69ed02a11ddeba860d08d2cfb825f94b4772da9488e247ca523ba2e5be43c2809deb8c4f082e5184d6d0382ef2e36a8f3ee9e7a3823480553317c3809bf011fd533297770e856c4fa4c8e6c582ea605caea30a7cfe5105f7cbdf310f83dc6cdbf8cac876f74b73288e81ab2a34ee50baf65806de08d05aeb0edfca43ae8a88e4b34795d8dedd5fdc845b1817e88c802d0ddc8c92d0145c8b7090f7fa1d04c75572bd817add98a99170da53bc8bd1a8f223c83ce14c671956ce4615736bf246193eba43291b5574dc2e4327b9504a5eb66c557677909c0af9e0960e7d7b5cc7472f26c8bb9f6618ce5a870c7bf73298df4de28b3db38ab07cd4da56267097cded3c0f55a8a3ea6aea128cd14cf3c457a34f5a05b0078a03170157f4ed97c18615a6240ce3f650f40cf3cce84d24e5423f5c508beeecaea3f2679d53ae6e9449cc731f5a5b0b295fb8dddd6ac86535f1e52b6e855c7056338e9dc9d907d904621c269931b59a3b26529fd7e7f3482f84082d10fc5739d3d1d16a1e465998fa3b64f67b95abb9f222f722a2ef28c1f139e12f6265c809c3d14400f503a524bb89ba01daa174b59d79faa7d4e809b7aa4fea9cc0527e610c13e84ce5380059c64796d70c0c7f859461ac1b0d55b464f969fe3f11aac8dd2daf909643802d9902f20ece249a34cc82542afe6cec71a325d334981a4e9922f743a53331d8e520634f1f6cf2234338487e9beec3343242150dec47d9bde477d6a8d26229af131f93e8af22cceb26626bf1e1f597a2642e9e89c76806e0768c36fad86f7f1370d4b84967fbc85d0aa696c07cf2f2a704070c834414a4c38e8c9af9674066961039d49d528251d33f74966e990260670ea0f1d63322bb833106b1676898940e9a47aa85a707a288ae6b714ec92140ce35987050744c4da9b31e6692726ad27f2498e33d5548805e9966cba26993978e900424a44127faefe34a7a7c8ab2382f3b293558a2d13fc733d242beff18c1aff096732a95296225a8abaa54741450f05c3ed182b16aaf1f5336908f66b797fc7d66c2bbba60e37173c68492e67e9e066f3e30f3667d506271334d52f143180ad186be6d5bd667b6efcd9c140290f5a837a3e7c76a061e6c67f302df2125d868f5d9b36f33d58137843e58cb2c29e3170ffe0e77618b1dfc2e1f1b7a887ed5280e6b12c7133d0d0205b1c9c1bc68b89c0a104499440ff5acc4e89ad83730690e38cc74c6a692c46cbe4579f2398dd77816a0bf78363202ee9dd96db880b4986048351476794c29d60a1312247119a3c31ab1226bc865864e01191e4b99fef7c088ac14af5af64b2c18fc868ad279752689fb71ac63936f12bba685e4b71c7e5218b153316f0d7c265114cd618da57b3b288801521a38b26b4ea4f4a9fcf07261b1bf8b6ef2bce37c1fc3a0b4d7bfa5794e8ff3174626ffe3ed87116072227b8bc707a0500d26338543d562f74235fa19a098baf41f45a747842fad7dc14dd5c8416917d71fc737d16ddabb3c65ec7093707155e1ffa90cc8928e5f410ebcbf79cf49b2e468a16119a0af3799ec8b899224b45ed52921be44d01767dd22b27ffea362e6eb850f1dd8c495309361ce4a67d1d8e718a0183f52430688c3829f26314d178a9dca21490d141df3e9423956bdac30c370f436b00488c12cd31c4ba9f9c781400ac2d992862a421c26b29521f92b5ef90f6c16ff340d79a17fc8d3d23d44d03e821162c416f9dd469d20ce2b9ab57a72b6570b0c6706481ca33645cac71889f895e7ee77cf3f248c9804eebda606b1cf51a27432390047d747b2a70956811d3943718b7d38fa9f8eb3f6ffe923fa8710140b58def944237115d66f361ebe2eb1e5643738bcf689f0ace66ee584ba5c2df54a2108f457198ba0b25e9df96697a691cc7e996a4128cb5dbdfee7f83ba0fe965432d7014cdd8eb78bdb59857a33ce00b9381e9beea4a245d00005248dbd037e45f0d81c0d967b703f7a7316fea3d097b395ab894ab7db1326a32ebc06d85fb83351113232ccaf79fa6b51005c22a2fc497a1abad27e1b29b25c309920abff357404913b3fe150429c20e703580c61af7d2d9245cf722987493ba9030139286f7c23e7b03e1fa36028c1181d5df446061ebd1d7e7496b7a3369d8a2f6c9115802a84368dc46e0d17dea7750d6d588f118f2b2a44e730f9bc191af7a133a969b656cb9eb57bee54f41bff4c3f723267d392495764b146b31df5f43ad625ac25188f8b73521ab07b3d33abd6fd04261cbe110ac52b7bed057ab063e7bd83c33b8b4cb37397153a4e8ecf39d3444cd99632f33215c42741b03b23ee4f5d8191503d42d70f3f64005b88e530aad170dbc649d3782bbec4f1eb44d08645302e4b50fdd8f0e48206b91ce7b4069f715576f64401a18b66f9301f6cb2fa7fa6eaa803914ffe563f58824d43d7274ad4ca93f0c09d815687ab8063704744426dd0a6928c5bd4fb5a62cfaa95144b618e33ee1d39f4cd4b1fd66f8509949c0a5759d00f00f05fdff0354b52cf4157e44afc916912bc90a41dc1800b8b6ab7428be7a62506d27190d4c00e7af8994b9c59546100021a894a9431f09d135e0479ec24506b48284150ecd160d84bc4934e25330c125445e92eab7fdd9f8e90a8d2efc7d3e2b26e11f4a45282bd2fa92ab87808e017069ec0f57dc0a6edea0005c506a0820a2ea8436886cbb6e44036c7bc9c4d64fc9e4b8b20c5de14d6ef76d8b56fedc82444930f42776a8b6911b912849cad96a1c8b49bf7a65152ad0ca947c5fa2731677140415fad330dd3110e0c06c1121017a97ad0a9f462bd6d8078045273e08f5aef85d40c397365af87f7aac4c921f0a58de95330b50fa5b830942e847dadf0def84a85527483fffcc0e07fb6a0d6433a05e69dd6271412832a8f6cb7ff2b126711be20d37338ec2f730ac17fc507a1710e5d0804e1637dfd3ea3b334cabf7ef73ff92ac06d25a79ff7c568c621e1ce5397040ac5f271336db3ae10146e6092802d1b4fa44afef373d71166c9761be273ae375e469aa1fce49a9b127a187bb7b1a2c291ba020319855068cfdc8f61ae96ea746800dc184cb4a3e5d8e12661707c4671da1081e22b150c09943846337c90f656ca95c11fe34c52f1723eccbfe2d2a329dce9e3e341974d781fd327b3c7e061a6034ceca28ce8781c695c724e1b15d2be44f28527c340b6999950354ad62dbc189b20ee290dc9c133b09e89938c6da876924f14a22452901c96a28c9e93b9aa4de4fddcd6f30f1814638cf026b258862c997de8481f6b56913381a9410dc28f416ef7d3ac2521a6d802c17a53fc24801933957015cdf030af802955c30da15a70365509f835539fe1c56cc348760c19dca557aa499a25dc5aef1b507a31c165d01515d169a070a2f7cf1777a5f8d0a82b480a0bec85061cc06d7ae801f048f3887efd746a9c451542b3e35215bee2d775bdb7bcb94a494019509510941092fc82692e578ae56a2b0b285e5cf04ed7745d850fef8f70bdf3f957021c24e2673156fb84818faf1cf7819cfd223a3cc1897ef16228dcc2b34c504764b0c182f002b6c287f461777d86a9ab7ed60effb1b6919d048cbc41a6de886172fb1f3352ffcbfcb0d65beefb27dcfc0e1ccdbe37be55f09f6f36819f9d3327088cadcb7448e43a9e0d0e213c66109879f3f1c82d95f905ec815ea85abcd97e937b47962d1e3687b29e05be4fe7a2516e611a28bbd0b37d638d6a266f38cf92591d267e718a359ffec8632e7597b68189c207d1b13a4efb58786694c706682b4878661b216658835281d226482f4b5b0f4c3948df6fe3b728843db07a43c7ab025ce0f7ff79eded2fb3f37363241f789e35fc469b47f76ebda436689634cd0bd719dc286f1f52f08c1869fdd7d74e7f42013f47ff93ddf85724175727339fe96e363a376e227cb1cce57047282a5d349723f86bd7c0eb9cf2813f4e2f57a45d15c264865bf1c9aa03f99607b90b75c0431066682aa48d3459499e957a429405c92fb073b3f3a6c9a9c32882fb3098c15d6c86c39aa5b2d335ff1a55fb356661fb368de48e9d887fc35c1f6974b94e9afea437e4acb342e857dcc3e84e7ab02d9d005e3c1862e573e99600320e3c89739d61e34cb973fa3c8216f656fcd1839755ac67bfc15f40a7a05bd825e41afa057902ff1d6cb5ddeafea5f805e02d332b38b1d1d66155a256482ddfdb58b201a2e3346ea783c9dcbc627828d1f270d70c8c687a9c28a7ed3bc0a3b7aeea58e639a1252a765408a4154ee9b39fd3fbb642257ae448cc13ec0031cbcf2f429c13bd32f30db948de54ed5c2c60fa58ed466c6648b514a29a38c314a39250d369d4cb160e9c71c819a10ca320335e1522dc9f4a5a494650a560033490f99bee90524acf4628220fd6e07762e99313dd388192355ab48a3d332dad39f3b9d096c28b3fcd024caf1b31cb51a4c58ac0613b60613d6b3be22bed00cb72bd6a00f638515610d83fd4263c786a64c53305ed6b4458eaf2c71cd225555363465ba837e6d820de5d05cc51af4a1ac70615ba85d13ac5dd8500e652a87e6d31a4cd86e26925254a63468465daf4c3f6c57a6b40613364872780126ac9c53ebb29735e6ecde20bfc81946575c963e465128f926d7114161931f5dc276e51ec518e7d08e0f14534632f1992978cd95aa09259db962d0d388dc1fa7c44db0e1943f5ffdd233c99c3b139c497a10c01136c98c9152636526fdd2dfddddadc404dbceef7fa108cbcd2431471c1ce1caf27a2b4ab07347c70b1b6a53673ed165b942045bb5883f63d5115fba444a669179c1fa850d6d1f8947221588c042a786fb4d24128944a2c7ee0d11940016713e4e0c0be95a368c544c234526e893b3d90db321332694a3d16b5366fb919021121852832962d80d45f2e845d394270e8be4110e8b88706875cc0f3263b4ec3d62df3f6446968e8e0e8f9829c6f1fcc5175f642143ea4b9c09766a6221352b5f582345ea900d63cb86203f80d07003a805ac9a79b958b51d2c0d338686fc39310a0bdbdae4806039973d6773de724e1be71c5d21673bc5324de44d45a3ad1ddb26d7b433dab5734e33c7a8538eb39cd63393dcfcadbb6763c7664fdaee73ce894d6c3ac5de139373cec9f59c73ce196bcf66674c15551c328da07f46330ca3ae65ed3346d20cc48822e81f9d8a2c4045d5c6b3760446318ccec0a6e4089482259cb03547a01410c1450a3ae0852de508c444145315d694231013ae570b66060503c4448b89010040e3929dc61242466082032657408109508084ec0f323183ecffd51c0ee34e5d88d215a250032b308187043b1810147777b735877b3507e532f6114a0e40c65e5bc2878c7d577360d6b11c6ca0042a95ab3930093ef6a819234190310ccb820f1943650cc3300cdb6a0e8cd29f2822f7a42508398c4f5850489082127420fb5b54097ac8fe5f8227d91f842922fbcf2c91fd71287185eccf6388ecffc3045b64ff203c64073a410fb2bfa8e670af08552491448d24a6c8fe1a129cb32287a655100258e520fb674f00410c8c09f227875c76530c171a3646d005101240d4b3c21184600416d9818eb8c1088cc8de041f021152c85e8422a6c8fed60825b23baa066c9182096040850d92980213352e45f62851c89ecaeeeeeeeeb9e4c3c4ed0739a4310414300ca14511449c0066094cca4a3bf5f440eaf9312981c45784ab9403226c0fa98a247a34a020b280447744cb1e51441d22c86b620427c450f764045b10ab0a240414921811b1c30161842808d7b6022334136a14797c80443683112b11104f138cc06658f2a3ed70023a0311aeac8911ccd033d48312cc20440f508f138a98a1889d1d245c1b8249bf446d8825829881a7498c1cb06009ae172c810adf137ce08155c9510aa1254a2210aa014948680a1311845c53080d49c18410bcaad0d1b23fbd37f3cefe98fd8ec6e1a48fe50cc58a5348c18bec2698d47cd75e5ec186363f08bee6380517565cc186a8dc42f1580c6bacbbfb318f31a91ed8d3a738e61845f7c70d62041b462755b041f08f09562eac24c2e54843c4eecc04a58cb586886598a07ca98019034e503e8d1eacfc68e7ff8c4945ec59735531b79850e4cd1bbddc36f95b0e5dd366b2864393267a0c6322ec699c4de48d8f58ccd86f91373947d786126c187ff2e441c38c315868238f64c8a3d168f4a39f339037641efdac394650e4589dbee7d16fdb633735fa98318ec70f2d32232c511fbb4b70dcced77078747958c15a6d82950b7b337a77f9dbef90bf7d4e1e92472fda760cc9e1e8b5215984ca199e339030f86337f4dc4f33293cd0b3459770fa44187146e923818001f221e8913822091bf0a0822b86bac07cd045169cbbbb5309848cf9902463184a72808b216858cc188661188d34c570a171030428c8fe280e64ff0743d082ec1f7b7802cc0e6dc26a5042405bd907a06082211f9e1f865030844d1598e000882636566001f52084216c865ea81a54413f5a820b2ccd510a2dac909b48a145143a4fbc78820b0b7242e17d8f630a6d31c16e62c618a7478abb893987bc8802806273d7840da713aa84747950f782d8f1d2d5a54ca693551333864231632a17b3bdfcfe6929668ce8255dcd6eb5ccfc892f437a263f4159fe860561589053e12eba439738141fa23ab40717f228593ee6930906c2861e4485bb668cf7f21dcaf7f261646127abc92a95bde7ec4b37957dac29bdc328c2b6ce1c9aa0d074e2dd94bf4cf9462ff56629cb6f26329b4f2791dd93653791652fc9f23b8f521df33d3c5f1394f37112369c4338334f8c53d8c71ad2c79711a7b0f78c7d8cc5a9f832c747402a620f722ae60b4fcc82b0f23fd38f38ec1d0eab3922d668134eba276ce8411e3463a28f99ea111fa77ad09b7efa3edecfeb79d60b2d42582f4f4a5be04cab65680bb75a7485698bae5a7445e94a47cdb4158495ff0f8233082b7fb644a20edb640d3db9f9ad9353ab5320477f86fd98e0122b7ff32bca5ace329637da77667a65a8332ecc64dd79dba8b3ba556dc33f5e82ac6c1970fbafda8f58438e46598cc924d270185ddba6b5ccf6117b94e5b84a811cd9b7671f6b46388c41221c46bfdd5c6717c80483ea94d1bd73acfd8834b1e3dceb8fd8fa1169a2686e5d6cd125d4e46ca759cc32393b6ba758268a22919c2dc2324d34e222c7c9d9dc881b6d5ced6cb456ceb6d2b31fa9748aa7939c7d8a27ee942251f4b542a150572aa65272768aba9458f52c51a9b02758ebc7098b9544071bc2a2602fecf5840f1325562b29650625736541d993ac85450c93b3b1ac25676bc69c66b73ba558e659d65366ad438c114570bef427530645c54301b7c852ce7891258e2c9f2694f5435b412c168bc562a9542a954a455dda1393ba5c2e970a0acd899502f5244f2a1c5b148a3ac5324da552a95422eaa22eeaa22eeadab85abbcef3ece7dfd7537ed74475e88eaa07a44c5a412ea1178bc562b158aa7e51a9542a5513d64f8b0671b5f3582c168b65552a954af5a492c9743aa5a4a894bce5412ea1d7d06ab55aad56d88bd52f2c168bc5a23b54457be88a32299956abd56a754ac158180b63612c8c85b1f2fc8b5a810123958a1183a5c55b5a7aca16525e694cac0faa09e83faf219dd56ab55aadb097b7b0d72bc895e70bbd865660ac56abd52a85bd5ed80b7b6196161932feefc5337cc68c9e72c6f7f21defc95a596be52b10fc47a19c89fb781367f94f8b8cd56ab55aadf2fc1917cf98e1e2d2420b2ebce02fbcd053bec0ea20974ed67a81e03f0a65add64356c766d4ceabf2f4d1d1741e672d2d6b65590bcb5a346b7908ba6c2db8e0c2923cff05d50b9cbc1470b0ee903b79fe4bdd21b3962402c00100809e12009ace04e77bb9559a4ebfb0c0ef9f0ecab35d51a76534cd8a7088426538fcf7d174f2fc16341f9fdb651c2dd39a662dca85aaa3e66ef1a1455dd7ccd2aa56b54ae50a7510638cd17964ff7e183598992bea82125f0dd298b9414accbeaca0cb7be085d83830cfc810696417a394b2a38dec3264883494668961620d6d003e32f6f145fb7ab51f19dba4282e21fabed8345f1c0bdb8db9093aebad5017590882e0fae2871d747cd82104408882083f580f4480b558902487200d212674a0092198780089a01a2a601886f90083128228428b2754403802f603ed89122770028d6c61aa0be34094d2e5c7dea40f92b0c5c4a6df5e8c7d044a6218cdc10d44c0012c8a19e0805601045368a14541870718e10a203cf04512be18029b02c807095b8e403e4fe437a635172347a01598404a391b680537a094522c5b41502a47a015088d389148241a6d3d260e7cedaefd357eed6a778c78023602f938819123900f93ac32442bc2081727251e582d47a0152c891e821de4073800b4020fe4ce5c7204520116402a70bd400ac92679f3bca5bd7c42dea0af790e71325186290e1b4b1850f9848481bcd164c6b4765d1e035b5e56c6097a8481c90e13250c9ae4bed67740b3df60b46cc04ed1f7f35131de72cd35a73d372dc78d6493fe518ecdfe0eed6d906cb9db3794a1fcdabd9793e58dd91b7de56ee892478fa3b7d148f4ddcfc67c59f962c86a3fdf84f3bd4f99d82989616a6cd40fd890e3b09e27624bcc124d1126ce25306c63be440bb34245cc718a278020c792c89a28d8a2cb125d73b32ed1bd00b2b09f9b9b55474e761ce6dc24dd7fa2efeef0354ec4efbac781672688d339f64f93b540b17eac23292b8ed2860d15b47234428e404e44c9404e40c9a2f72158ecbb2c2ca6058e96f95e7e101b84cc188ef4b2fa40a2811c5ea0636b5dfc5863c631637c19565c1647c53355902aeed2f083f4ddae39e2cb1a24d6901fa5ec9120385fc61616a17cd88fd339a7c37249cdd15886f1c765e657758e90c082126e3ac0ce8b04a7035c4185236a8e9c1ec9b44211a200c4e4a1428b13d0d0a2e688094720f0a0e688e991481f9c8024015cd4943ea7267e8b8e65f9c2ca23999e6e0ac849eb17ff139023f6736a60a0c2a6503946f655652776bff260e763c1ce230850810e4f6a901ca087269050537ad33d728a410d1213133525ec446f224c44aab0c7308d097a868b0c913e3eda95401596f4a50fa310672dc7711298a0c354614d7ffa212d235599f5fe8909fa0f892ffede7f38d4349cb9cd307b4329c6b289cb27a40fa5da67f471f47c7a3b7f1c93fa907ef137dd30522c77628dcc3fba8488de47df5d9c39dab2107d0684fb915d9c2297c804fd4777c8f522004d58a992467cf60830e114fd9e1993e1147dcf144b95e9ca2554d8cfaa54c6b00d1e8348ac2e075b74991f310b156c4b1b13941fdd7718c99afc6e68247fbf611f6db00f8d3ce971b4bfcd7cb7e9fbd1d7fcdd66621bcc9de23007c72469da26658c9f12dfbeb46f7aadd690f21f4bdf7dc4a1ca6b3e22b622edbbff143fc5e6fb88f9e89f3848c7704a077dec6d2816b1ff6e486928f190b9f47d63d041147b785f837fc4a9efe37f8fa53e9cd241faef6d481fb6c168487f84f50de77bd8c71761f8a6f41fbe393d4ee789713a97b09f3efb534ad86157c1389dedcf141c4a7b43247d9b768ed58763efdf16871ac8f1b99aa37ef4d139e2748eb37e042d47bffe50acefddd048f6bea3db2ffd56baa1567a1bff12d6f1e130277fa4c6a47e1bffb6b11f27488ada7ce9ef940effef6ddcc6e2fa19866fea539b4a6b1065acde2983ea10879c1b9ccea50f4d9fbd3faaff86996ffa63d69ed29fedbd5fd20d8be48ff4a88f5306f5fe3deac6497a1ceddd9b1bb21c643e7dccad43e612ce4166ccabcdcc18be993db4a7f4eba7bc4ac9ded048f657b936d8a75c9beffbebd5f1e5b4f75eb297844313c6e9d29d39a48f434e9639457aef4bdff77b2c9446f2fcd2f5d1f8bdebe3fb7ed2d5f1e178a9fd1ae2b4bd2192948efef9368da30d86dbc321924cc13093f4d67ab58f43c2225a96a2288a53478bf80623196766ed238c8f0d3570e51b012b180d1b4ba01ebb21f6f3b795be9e576eac89b5510f030496ba086cb471b9f9225137d6cc19980fc000d9c8596d0a1b5f65aa2ce18dc94c349710fdb6d139e79cb2b3996533d61e37f3a5fc82a66cfab1dfd1d8d532e9fe2b5158f0a9d0eda37750ec3ac8658719810b73ceff17390e8be4c737a2cfb2cd0517eefbdffbf7defb3f995c29fe0ab3aef2bcf5e31c3d7ed964822c8742b2e47f9ce0a581fdbf1feb0eccdd1bfa8e51aa480efd715c3691424231655e68123999bba167aede50e6fad90d8364aeab37274f0848186864d1d55e74fdb19889ae6cecebefc0bee29c3cbaa18747f20c83e4d1b66108481868e44cc331fa7c79129342fbb7c8c0cea7617c22334a9edbfb861f9565192ac60a4bcba7607cfdeeebabfc56b7cf483ebaafd8077dfffa2a246c43b1e3fad9ab546b5352eaa59f4243cb932856a1f459b25f51b9998cef5ed61a543ec329ffeced7737e59ff25d949c726c93f2f6b7edbf3f9d4e26933be7decdc95e229948cf7da954a29444a2a45b499596ee09c709fe73f74bc1a1067ac8dd5bec13fc7fda12facbc031e860b1efeaa3e529be697912be6179fadba51f5b54300b658991c20e03e37446bdafe05066d4874872467ad275ca51096453e63de9292a7bef6a8ed1671909bb09879ed1ecdd3dcbb26fd26f9bac36231ffe248c63b6c8c0caccd13b7a8df61065ee23776f46efe3fbbe52e9db9ae3eef6ddb6fde8bdea387d09873297fefbde64fa28d971c8dd27f9bd71be5092bfe9fb6cba61ca6b7fba39c8cc7ddf8c7eb319fdf636f4fb52e94fa7938a4aa974baf64b4e38ce3dcff338ee8ebaff2e7d1c9db23de9c9670a737269fa73bfc39fc339d9bba167efe93599bcdf2667ba27d3cdc9270c0109c3f7d9ff6e7d8fef040b261c27bb87f7a6dfe1bde97332e9869e49ef373c92dd74c32039d92fcecc250c010903f7a41bd2c8dce3e8ef5a1c6794ee8648f2e613a4388ef008033d1ae881b2827a9851720e92b2823e90a5fc6e9930b0f01fef11652f1265da6b38c47118c0407b427415800384918107f704ebb2dd9452ea43a95319f88ff7685ac470285518d644a3997bcf4fa6578699214238846c1883e61c22e453fb91b225594da28c8d30e8c98d4d41286f1efde8b28d5eba46a38e4f2441dec8300ccb24883e932e7923fa2401ebc9a3ebf25a67e004bb250916a6a37c82d224d0c8f2a1f59efd0d0d07c31cfb9684816b82b51286a8b5953060d3c94bd334acb3189dc88043539eb4bbbb656b77c6860c4eb0ac1fceb9ab602e812277b20c0a0f3c603b3cc81b31c625398ba1f58bbb6461c308822e7b883276bef0e07d5b3de89feec99b977d74c11efb8dfb56715cd4b450a469b87fd85e345dad923762d6defb879e19a3fd64eedab8a31b51fde2a2eb13c466b6b0fe4d1f07f5ec2794ecb3b72de3fa41de9039ebc958cb7f6c6c30988d4c29b5a15d14762d9d58d8f82f2701e40d39613a8a542bb5a23e42a91e79034bad72fc1925cf0f89c0d8024b1191a57a6008cd182252adacddf964822d0c8a4c01b73f8298605d30a66bbae28d41073b9bc0d82245040ca11913532beac392dfb3dbbddb1bc4dc79d0f61f1b5078d09fc6a19d99914b6815349dac95378f453fcc5a389db3f72c9b42c2807df63363e2679f49216fc49cb5a64ea6573ee14264932b6c286513a48cd692099126fbf99207a2b9813cad9027145057d822e4f9314a20e4b964f6c4e8c20a4584fd414a1e505580e9226a4cc8f1e506a48cd62f3a4420cac0f4cbfc20d94f36452bc74a5b46b25a7228592d92c59a3071de0bc41a1303f265fe7440ecb1e207140f7986720357684c5085a8204df0f4996067032bc23edc0463648dac70b2246f5e7f74b994d225995b273284363286b9e63e97b8934c2f0c0d307acb1fd902c546c73f12956764c011a558228718a23f79f3644bd2eca9b7b7f74b663db39030f4d3ba237bece3744d28f246c7dc4f7f8632bd34f0903b303fb8b052933b52d5435ad3a86bb375a6504d7c942b0b7943fee4585db63016f759867d183feb8fd1e550debcd8b13b76c7d838667c6d46ac175b86bebfed97020c20ccc9618c2186f0480ee34b1c16117d67b1af07546a9420714a29a594fe0e3335f4951ce917614dd3344dd3348a95b8bbbbfbef3053e358498c2fd5e6cb12c73880f85366f917490c628205254fa008210b4ed41c71427e9448b2b91d812588b9c990116964c8686989342d2d2c2c91868525d6983162a452912695820123d2c080b1b21269565650a8488342a9a8441a15959494489392723a459ad3c9648a342653a914694a251229d29048b1c6a4f93e6b238db5b1c6a4f1bcae8b345d572bc7451a8e8b3526cdb68d469166341289228d48a4699146d3b22cd2641986451a0ca334d2501a6b4cf7ee48d33de79db146a491b1868c3572a4c4926cb2013644651c844089dc35d3022187a60c3393984768e1587801b5c0a549e16a893aca90625c402fca7c1f55b28c0c441ce2cb8773228e2f951b45220cfd52c62fd23216cf9e38412ebef6578a56a18b9410319931dc733ffa30befc85727737fdf94d8909b688896835c19ee9eef872d5ec61ee789209eab4173d34c1fed15ab98372531c3eeeeec99d021b8a56a295c8a74ecd082c438831c6e6dcdd29cadda7f8e6c18325083f208e1999a6114579c41af387879c9d82144f0a082bdf3553ce6274ac9b0631c618bbbd5b7a9bba7b668c5aaac7bac7a875db25b8da9dd22c882ccbb22ccbb2ba43d609c1cb3e6b8a655ab71034d10b5c7e1c6d94528db32622a66d1361de1c47bf526abda986ddce3277e642c05eebdea1b5c518e36a934d5d084a29a594fab643fd0855b6534c243a029689462391e43cd2c8ec5d5ae3ac8988c9e4894622ea2da234bb31e7706e4a99b351cd91592c8bb267b5a1b7f3ccdb5731fce3e508d1378ed3382ab99ecd299669224da4b1e66ab69c62999669994ab25e7345b10c0b61a24baa582f8cce09135d52c572ea214c185d52e5ed6ae9b1f2e79c302d3d46f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f04001084c27cf97f2c7893f6939cb7fdc09ab9b62be72efc9f3355f227291a8a714b90ac35c1a942879bee825b44366d768e4c33de124cfafacae898fc7792dfbebd9a4ee2e799bfae4a7534f796a1d9f76a95842d8d05f292aed982683fbd699abc964facc26f3e7c5fa6905b9da4767b6747474747466904be8e5e3e3e3e3e3a3a3a3a3a3a3b35992c9f41ad2993b53c5fa6905b9582c168bc552a9542a95aa5d3e73e5e3e3e3e3c3c467366161f4f57abd5e2c168bc552a9542a958f8f8f8f8fcf674a419558f247b664904baa582c168ba552a9542a55bb5eaea1a93377a66ab2582c168ba552a9542a95cbd52e57bb5254b895d425693d2bc944c8ebb0582c168ba5ea97a952a9542af9235b412e6f168bc562b1542a954aa582c1c2fdfd8444a1f88a43fe62491508fea350d6ca1eb962d278fa4bb2582c168bc5c268339685fa01c17f14cada9726645fa838d4a29a662df517f597bf02e191fcfd2c79f6491328c913af1bb5e9b0e77ddf1dde32ae7a6fbdcfde1049a6587a1dc5b3727e84fa9f20487b90567737088220182448101004c120dddd0db648adee6e10043d779325994c2a29a3d37f1030081804044170c727481452675bd3502821b971387acf4731964a38d446d6dd296d11572aa9d4c0f529961ec71c7dff361a8ddec4b9b7fd0887377cce0146c621277b5fbb76f5b0f7e8ad37dabe9ff6f7db8f6e28248fbadb6eaa8bd186a83c4a759847f4defbfa42f2e6617d6cb4dd70fb0fc7a083dd300ea5237c437a0fdf987ef438e668c338948efc4729a712572a6d5f1a71236ffb51a9866df4d51b89b6d18bb6f75048eebe35126aab3a606c7dcb6d28cf7e8c8d4b3844e5fa1f0e51f55137c697da1bbe11fd48348aa24d341abd77fd9612d8fafd38da3ef673c337fea3d196536f2864fbbe75e67ac30e67a30f478f836fdf3714527168bd38346f384492471f3fc4a1991bc92c123d0e2136912524938036d20d7964d217f298c95908c2c0f0c8dfc7094eafa3f4b3e748d997655ed7759d97e1194d9ad1b8d1a83b954a9a3591345bb2ddbbf75d7dd89fc9bebbfede0d6772963d8c03898159f0f74bf62894bd4a626096ecb91b7634909e7b99d12c7bd3e937cad9db3dbdde63eb3ebb210fea655ee6655ee665dee5bebbf6fd726ea4eb2ecbc5dc0361c1dc7f5e101be3595e09875970c823dbcfc9dd6bd9bbdd489fe11bd273f8c6f4d97797c80c35652657c19e722a7925afb3dd7b25afb359c66519b7753cf2f7526b99fbf4f1c3d8689941bd0692f7dff2d8fb183827bb8d1b613c6b5b6c7654f61a60262865c878fc40f08c182fe381b4fcc790d1f29847bf389521e381b07c0c252c38069ee9179f71ff8239ebbaeede70bf7de7e1306726e491297dd4a7fce84b3daa65ee372a6554c29fcae9c10cc2c0dc3be3751b0ee5bdff326ecbb35cfc31ee8c1e94e5f12b89f133be6b8a012c8f1f488c9f21e3ef0391f157c6fdbf0fa4e565fc7d252d3266601ccddd99258f5a83109e81f1b33c9019b4857751d20276c1f4ca887167b0844466f2f6a28e1bcd2c6bf79bac3d602648bff86779252d1fe3654d31e09fe5813c06d2823fc6b7b4cc78dc82523203db7ef1c7d8f60b4d31e0fe3f1019dff217c77e512203b76022333919c764b931ee13994112c42373e1c10f279871e1c10f26c8b2b5325bb02248de3c2fb9c94fee20983b6b290ebb1f4e9d3a757a32953c9008584f7ee248a693fd5a494ebda79608e8370471caebbe74c36afacd5a1bc4b337e5fd576b4d7941ba6ab21613014d26121110cc26128943a99c524e277bb25dd79dac7b75e7ac77c320d90b5d323d511a82a56fe9b01f8c3663593fdf8f09fa7f5cfda71ae964729f2f2590080882415a06353a95503f3ae1520ae964f2489fd9d377d7f4a76b632a0529913011300811900898b9caedf868b600434821041660082996b0c5b6ddd086bc9d2ce9a3c1a953a76f43e666d8ba926934c2b649f8a394528f888ba771294e4db51d5bfba8771caaf4f6de6f1da5b4faf07ecb4146c6212773bf7de79d77de7178a3efdd7ff6b9efaef41ec529d2d314e9bff73e6e76db708a84b9fffe7bee3b1bb24737af846fec73f8e6f49d4bee9eba648bfd54fd3b1c46ec2a299476b4e328ed28a51c0e9d76de945a8d5e4b3fd432473dafb58d06f76864b79131a97bd22dfd772baa65564829b1512a38e58432e110f5d9ee576eac33e4e4ee1d872eb9c32111978df36cb0b6b3b6b3b63375ddfbaf986cd7ad907ee5bafdecbf9b83cc24cfb32197bee47ddc0d6df070f77eb927dd6f66ee86161371e1b6581710b3f77e431bb2bfd775dd739d0b1712710989b8d09c25394d6cc8f1353bd385127e5c66ba50421429f3b484add6ae7e5bddbacd643a9548a65a6bfd5357bfdfbebefdb6fafeb6be57aad61ac9d56edfd36efb6fabe1564b58ada5533d5592c964aaa6fa5553ddbeae437de9b7d2f7599f31f8972aa5dfd7fde96facc561fdadbb371dedbef4f686362c92bd0f55327dccdd09e72073fdeec6ec75f4f59e7e746d4ef5bd5bbaa111efc32109e3b47767bd9fcd8763bddb7bb5ab9cecd3b4497ae348f7c3a1e7ee4998f3bebb5be9fbcee29bfecf07673b27976e7824379db3fb4ffda62d4ed3a33ed61a4edf3d7bfa7b977aded7fe537fdf4fab0f7f1ff66feadb70dc3e5af7b8a74d7a7faf716afbfeeefda6366c637ffb2fd5c37e383c921df34838061dacc537f5bdbea163c7154714c6e97c7a7f0f872a610ac6e96c7a3f61537b5c73b6db7bced4efdd1ede6c733d5bc3e1ec9f3d7d64bffbad2bbd0ffbdd7fd7c3dd95550709bb91fc751de626e8f5936ee5bebba5effec3da043defbb1bba8f0ffb16e2b8c77c6fa79df1bd9bef63f60f8748f2f79d96bd95b7deafdc385fbcc7d11de963fe4cafbd75ff8d9b6e8f64af7bef7e4fbab6bbf5bf1be24cebeedfb5f19e7bf7ce439cd971b3431c23dc118d366df71b8e641cd9b60b2379ebbcee43237682b6dab7f61dd7ca71ddd3efba8eeb7c6c5f5fcbd666abb6ab5b67ad114b6feafbed8d64fab5bb61ed3ad26ff8c6f41d4ee70ea73bfa1d67bbbab9577777df6c465e69dbac7b6fb9d2f527e138419cb6f4763734923b124d09875ec3c3a11bc1e9dae17487e304b98f951b52c44853e9f20b8f89adb9df36fbfebddb580f31f0face6e9ce738a4f4a39652ccc51be660b544dd4b2ad544fa9453e9e9db6baadefbe783bef5d1fdf6f6b90fdb749bbf7d7fcebbe14603e9bb6f8bb9c7b8eb947bc7a9ee3dd5fdf6f4bf54876db6df30f0cafedf467a4a3111aab2f886f41dbe31bd254255d992b09b4c2a35e5846bc9b92f71d66dc7b96fcfbdc525ce9ddb3a7777f711f7f48efefbbee9ce8c213d2d3dc5de7b2fab0e8b6987bbc7d1248f49367d77bfb7b73ee7e190aab2dda13df82061fb3dd9e2d1c7d1477bd0a71f0e73baeeededde5a4a4dcfddd29bae4d2927bff7756fb570e36ec8ddeeed0d31f0eab88dc31d56e5fa31cc197d05822a808197dbb40f53ec5055fb304507b27c7a92f6035b74d9606cdbf7f37e4f6f276374c2d59a452e8eea8d13ec7048c4fe37730c3a58ef9543cfb1ce2ccb7e07f6190ea54ba884ccd8e98256aaa20100000103160020200c0a078462b1581685a920741f14800d79a23e68529acc634916c4308c53c818640c10101110012019492300405760c1a75e65406bab5607f8b8903e4b9754f369aa78cd6a6526e41aee82ee4e6269bdea235dbe7b9207134899c4e47f8bf0928dd96704bf9a9000260d98d345a495d0d4661fdc45cb75f6b8a3d54c00791ed896121b8c13bd4b943f14158a805f7c4f7975cd69acfedad2aa54bd7e52e36b42852747bf240b29d80b0596a7a3a3e4fa59c1d641d55ca6e43da90b04e084d2f4165ab72e8b15554706e5944332075ce5feee98863afdfb0c136f3ee10dfb1fbd73d3705ccf9f47239dff3d07de5974bbdd74a9227d1216f2ce54d01bf6687c8c1247d2965d98e17ef5373cd7d7cb7c75ffcdbbcac8b57f82531e9e359f40dab190b8b080d3da6d211fa1e78b1cd173e0c2d51157e20d7cff036de747a76150c5aed31d69e215f2fe09a76ca3be96b2dd751e3c97c71137cf81b4c9fc658e6bac342ea79b0356261c3f82334710b24d406e391962bb4c29d96b77234cffd8eb9b3f41b24d07e4985cfe199720b5435c00c917179b49321a9fa3930d67c3c55576caf6f7da19664169361260bccf49d79f0070806b9934da22d36ada9efb2ae824bb428eaa379c45d1ced85d37743859f743026d13d18fcde50fe65752cbb437850cd0b263d3472e9f2680bb1bf3ee17b51b9eb9e598962f7483732d4570d906b8d94e89b8cb8cc29951893463d2bc46fc5d86538b708df1f2125a97fbdcf8cb3f57560388c006fb2e45f0d0c097fd54ea2cf1027763beae953b69a3862e05854ab478dbbe18b5b80d3376e0d83d7e015eb38c62cf9adbf83feeb178f719498909dce41bbc1361ec2a104b47cbfd82884e6ed3cb340906ca8e4a35098d2965466d73d25fbfadfa5130ebb606c20ef254c80a1a638346b572372478ee57fd9b56cd7bb74a43c98a9a92eb9c3072cac6733927dc8651b1174c32838a50dd8fef9a24ab20721a26d95a0c3e12a5f2979aaed63bd5020a37719ecf304ccc060ab302ad1e6700600ac5919c3a52ff0479db42637b9ddd3168b7b4ae31799938cce18f593a0bfdfbb3993edb7cd1d993048c889d2cee39a30d0ce816a7a68953688ee519299e917f99103181b68b93bdd0c0bb5a5c9f48c9eab9a963dbb93c8910c151712fb0cb3c848df91528e14c2f31d5ebed3d52c114efc386f3653cc35f0b6fceeb1bbfde27c15e2823119d0b63f012b5a3450ca67c7329950fb9cf971efec45e2274c691d5de24e9c8c18a9d53efd60709be4d61d757d657b080f1b06644083c21b6c51fa4966ae4d787e488dea4d4dfe7d85dd1c3d1158942e4751d11834f4e16f7d4f0a94b67c723f18808dee5d8479711a57404c450ff002a38a2c0246c50056b490c5dc0221f0294d06d60766ac9f353843d3e2e4cbef2f19292b850c9e3d929a18bfa78aba7682ec2c553faabb18d099643f7f4fc03e0365bf4b6e42f0e98c1abd52318bdc274c2f8bb59e8a26a1af2cb793da68cc884c9ebcdd63dd4f44da0933450ea370a79198d6f3cf8990af1a742c2bc12d1203f904edcf9ca52d39475f337f98fa7441c1d63af6253876c1bc697bc0f03c30c4a89996b98070a02e349a16471f7f228a1696bb4cb7c41dbdd226920c9c3e9ef5e8dc5294b5e99b1c3d35bea4d2c8159151aef21b6efd50cd4c6a2ea949bb7a26314b34a9063c7102ec18bfd65cbc3d04e8ca51c51f4fc00b68abd3457f02c7ebd4e10eac99555c6b72783fc6be383169cd1d5ff6c8beb1370055573c1e5ef3463da04d17f75172df1393b7372708193f9192f62dc76dcbf9207552cd0b2caba0f853c8fecc37048795dabd81d01e27a8f91bcb4ec121d0823222d0f31373464f079ec83852ace8b9187ef234feb6b144d7b4729d42846bce9e6d90823ae763f847a772090e12480ecf0821b927a249705aabc64df3c729fbfab6e7b36d06c42797dd342f5924222ea9055a80fe52dbfca67b5d1ddb99a546f651584ed1e445c00135c97b7e1ab456b8a67ddaf2947022d995f92efbe243a7aa0e2b10a5188d2bd84a0e4d5df06f46ef2a87fc0c7eff1b52e7cebfd77bda55c751dce63481cf93809fd8110e1dcb4888d1b9ca47ea11791463d384b99ac6b43ce5fc0ea8138dc17988da215eed6c0382e203e5524aa2ac6223684d0266656e8d059d0528e544781755d63f76f563c0502de9c154cb4b97a8010725e92546cfbc4c6d2b7abd8015998f72c569e2ba45faec919d4027eed4de6c7c8d4433557edfaaf21741732dfc5ca3346ebc04838dc290bb924e65f095241504b21929a86024dfff090ce9da43796c47aa922aa62b2501def9e2b1c01a01c09493d9cc828a4b5bb8879905fde74c67152b624b8d0c27206caf3924d82946d94db8fae1649279280bb7d186dbf8538f0d5bbc1b636116d10e2908db5ec0ec2533876fc13894c269c1d572280ed49097dbb04595c03e87c598cb34ac81d3be358456825c966cdb1604fd0f0b28cf738646de8da5e9eb7447757a563a2beeb38900b9a3d746a7da3733d19479169d912d2243030e764cf7e8470c1be71493d005377e6c320857010a84571808f9842bb338c30788a25fd139c8be6cb81a0b83e62b4a2cd513e7641025a02601bb01531bf42077769166ceab6bd4f6034764d875e344a904a2e3b56df6b601729a0c7e26510ada085a1682a828b9426c34a9b39bb90008ef19021151f1fa481db56737824cea9c9a85209fbb968a37f5030eb19c0f1dd187d620d93a5e57c416c903c1477f9288870841024f08475783a92f6304c80479047a89d62c5c1593ba173cf429f5ca2603a18c26f0556e1714ace4d18ab9923936e68ade840a246b9fe27d6959778bbfa890abc5e301ed1bb22b41175a8cceb304f18f5461c3f5e531a2993e6b72e0af74ba4066175d59891d82d4149190df1da7a9547ddd8aa0f5979652a2a0f5cd131f73fa63b135f7623ab5dfcdf77f1203e62d8a392d4b0824032c2e03cf1f265b0c36e1abdc604ae4bd621cf8a265bf820c5948f36c2488565f15eee144926af7a6f0d14f1c7e4183cdd0b8293c28905f5a5274ec298f198ecb2ab3f627480f2aad12fbb680fa30b8991ec3d28f642f2d08f0f0173fc0d3fe8ebc49b4a55386291be267333f87b6fbcfc2ba1ed8279a12f279b6d552c8788da077b37688f3fff3a772d1523ec76b870414c341c7603d527018bc2676f6e70a146eee2daff12194798b022f793cc5200cb6922a1c424a074b0086bed5ff092756b633809260341c83c75fc2f196f40675dcbf8f4501730ef381d213508386777d358121709eb826fd9a69fd48ba508f1d0677098d999a4addbf431d05eba19b29495765864c04c2d5e1d0c6f046e38f46d7d41bbb2978408f4fa1fe3186330833f49044fd16fda4049c60411370ccc0b9f981e2c634b51d8a72a1d7d8e1d97a6646e3b66985701855154c5402628dfa72a9527ef3218ff32adf584d934d643a8552ba6dc5a08b83aaeb39554b00a5179a159dd3d66bc48932e2a5b60c2aa7e179b7c1499e595fc77b429ff4de3c9fb879806973f8477d79eba9cc20245a404e25631836268e438d0519b3c5f4b542ec14ba5276c10e58a3e56c254191ad9b58b4e3827d07309f53462085a88fd78d1b6d25a9861b3440b15d63cc91611e07fcaa8c645c4cf7d6ed7bd2ea799578d050344ad9feba4cba28a457c8145be1e8a2d440469815ffb7f84457564ef8041fcdb8d308dca759a18216cdd8558c14ea988e68fe785531102e42a01959133b722ba4469376642772eac1652c749f88bfb15d1c912644853aee90470c44958e24137d6427c1369e9904a8d2ae7830c9171c15be022044a661a773f09b14ce16f72e43e5e78996cef13e2731b48c2ce52414c3fe03df40d7db0c50307912466e7c431b39985b0e5852887fac2b317096d3893917b585dca0e2e44bd8eb9d423626ab1a0e4633d89f928aca9395b59b522a7053504d05f48774561028650fe3e0d6d1b6c5f6b5748d52a16956ee4740fced6dc58284d31a8e9b64decfe27a938172fc7c5a19191115248ec2569b11643de148515364194c2bf03d21d63212b7687d0941011c33d0b85219e671b5e3232d591296587e3509a626380f74811b8c7f0a41e08db44b884507a0ac0fddab5ba34e2031426a463960a6db504cb1ca5e8ee19efad621b62a2914a0415100fbc7ec13a0fec97e13d85cd805c6e8c2a607153c9cfcd050aacea4cfbcb7bbceda8934e52017a0e3733e4da238892718578d9f0c4b9d6fe6e8c70695181dba7bb292a38bee99fd5a5d2de270281480aa597ff5b426cc14fae509225dd6d7f3986f8178bf788079ca1aa822b31967b6d78185ee7edcec36a9101380221faaffc7561783da6ddf4d3055092216fd3ea5811c0127bdb449498e2c64ea4f01e324d5a4a0dc2f92fd92e1705e8de6fa1d53aaf387cdfc83bd35b04188211b5cef012ac42415ff39c4bab5a40cab006dc026007f93441156e5a040c01007b8877ea0dd07c14303aa42a9bb10ef5cb21470aef8eb73000b87da01b1c84d1e541fef7470841c21a59152a47801cc7cdf6a79fa39932ac07fe9c2c74e7891e42f8467255eaef57c25745fbb201ea4c75fb85ffb6f76448a040dd348d6ecbd0bb01b27f4bda2b25142704079a9c92e78c1382486fe2af0d82394efdb40a41e7537fac87b161bf5113906d93ff75e87f881524798f1ea72bdbb091009710c41ae51f1682e7ba6b8ec91602da40b6742e4b46c08ff989459b1eba5654acd7fa937cfb9a3b2233f7187a73c86743ce417b8b7955c6ce8468ce79dc9cf661da474c778d2a12c049cc6c1b80a9dc911bb8c5c610ca0ceb979c850c4c17bb86011fd79bb3ba9e2328cc73721e1fe826ec2420c1fa23d3d925b8f87e352df303106f08b5903753434cd7f90a44baa5a3306a73128f6b8d5f61601b6041abb2e7139000565fcf431ae608780b02ffd841c9cd43e6461200722493d96153b2d0bda15b7a23b8bb820ce6e63a2ec98d8c458160ec730b253dabdc6538354245240adcde762b40baf396ab1651da451208151dade01f236a650afe14560e265d0542c85f3449d08b6dc8a2148e9a94e2826104cb4cc83ee2cb607a6135ff4e280706d4ef1c04dba2e2f4a811e1f2630d31b739e91d57de529558508be1253f93799fb9b2b3aaf46fb816eaf0ccbf59d70d31e64a9504c8408c7b23cb11550f43daeac96854975a96e6fd268df29398414c53714e7324201689dc5a25e0c33a43804d8ad9938bbc803037cb91b16c2d9ffe43e713f3df782e17e98a6b616879e4a5afef025441893dac9c95fd14f871cec5e4a57f5d814d8285a052889e23eb8bf0f818ed177a29cbe70d699a4f0628c86dd5b3b4ac82c3ce314080e333a2d1269816a077f9a8a129679a26e94e0b88836a8c6b8dcf5f92fc9d013717dabe2308f42776004139711782afc112106e2b1ae39724266d05d851e1c77a75febe6ef489d7a9006d858f7e3488f40dce4a9032673d61c941f39738427fe8039a873ac0622b2c53564d7e3b075602c00b200b96ddac1f2bb280d59c9bc11c3b300194e091c0cf93c31a8a094faf5e456624f5504c90d8612187fb2a693e6f28463172e759585fb7381493a785b78f872c6acf2c135f75641a92aaff1513d99e388015f30ccc2b4e8ef06c4c51e58e0cabac58448b58f72fd72fee8dd3eba5dead0a74786f572e26e281fb3de162bef2fe60c19093802da7984ec00fbd36b698479a0a768681208be00e9c5adba51b05c78b826e7645bbb17977b7f8749aeec266c832f59ac4be77146698b8f740e782055e6337be26186a37d8aed69c96339399fe4de90fe0fb5daab9bcdb62e516132eb8e305c3f5d1f4c7748e67a8282ff2646c4e4cc33cd9626118b81989164ff64f9a4cd1d62b295d99d75ec661c38e5fec26daa78345cff6b55f4266b6348fae940411d3a67f053064a631fcebf1c9ecca6ddaf4e302b372a4596ffa78ec92bbd53d10f70bfc465c8ce34f87ec1f85776b7ce5c77f7eb9c80a134a08629f511021da839546ac90d3ce6722fda4f4e837c0297bc76ae98856ab95b1c8be542634da04ae355707c6a9b41fd26790c4e26ffa97b9d2e4f927a99fc18ed81f2cb14fde921614980c00332c6972056cf223bd46e0b58bc89090b6610798d312e2fbf79c5a10a19378c15c0fb4804ebf9596c80a10aef8ee24b7055ccfc781049f6ecae385ae42c5771d10f4d003709dfe4e4f0a43d59511e0f86901347b270915e09dd51223c221eee8ba01d0be23d5033a4ec7c0cf733c6fd724b059774be2a7301e0f2276ca5c604767d804c14f0828e2045090d8ba38362ab218b9cb80ef50c508104e3b5e723c38c4dae08cbe603207f894fa63123fad713fc8b002d7332d442e4951c3c01924322f2c80d9ab5872e326f341d7012f781b7963eb1cc67a3b4260a30d38d2aee9b65b7475b801469cf951c5edf79408f61ba03a097c909a0cd06e029bbb26e433387da9e0b155bdeea55b7c6b2a29b46adc84ca2eaeb3ad91c9bd4108404d44de4202f34a5251c529b5c45a5b464e5eb96e4aacfae9b9f80555a3d93adaede0568a905f0455d1df6e04bfb9b0fca7d3c36cb504bd311a8dab59ca9ea1ff54c1c623da21dc0742945de7e9b6c59f835eec50d59986580b710a3a5b6246b7b5c858aac419e551b787ff07965315d08d0d142c19dd3688b5b487e6fb664c84a8c4d46fa05e9aa79ebe893df2672fed1ee53e7231e0cb4ee5a91f685d1960715c0544527342967e06a1439a4f2c7930a1e1667673183d1cb3486236480340c6423cad0680afb38c848c4ec7c0e99db76c2d67c7da9ad38f492424c88341e45ce13024d9bcce6c03fff8ed10d2835f298b13c870f82069f7630513b0804210c63e7ff5d18942a85bafb7339ca3037a3013a71e98ec72d3edfa7c97428ca5a8f34348e307abe50d09d55c679e3607dbfafc8bd601ebde2c1056c461779f8806cba172220f331807712d00f133f024abcccd06477701508c1ca2fca9f980b6823c3815075f520b6e58f1e050edca798bec4a13c5182a4b0bfb66b435b72ff608e238cc25ab0e07c007e811443fe5499789992883cd4ba7cf838f04f863ea66ac8f07042dcc081f205df4841c31c2cb3f9b47d617d3615cc06072e00eccbcb055577527e7d36f25403096e60d7673450f924a71a6bdab4eaa222a18dd7c0dbef054c082f9d9c2c039a43d449da1ea70f9046b3f12e0892abb6dbe77ad239660b88c95ecd6779db4172abbc5c9440fcc863c54889aa80d0ea75e9e533f40b8faf71cf1cc265cb8e5d25de54e3fd47b9178a77fd949ce7b665c02a7617221acb41b903dff88f1f26a9114a4f54dc66cc3651f36859e8aa971409e49041c2d16f3ce76379b09b709754ffe69dbe5653f35bf515b0feed52e46f5f34e8f27e70268ebffbffadb55f46645e7b7d407685cac116c146a80a8079a73e592b672740a1e0542f1279586ad149efb3c74b9bea20a8affab6ee260b4a9df824cf63e5c53f41eb2079691b12ecac1e17a00a8bfb34c64751f456d94b4b977e7fce578cb55519a6a28aabc366d8e4dd5cc9ad0ce3e4c3218080b2a1201887d12ddb1b0d1a572f2246e2f52d2a674d4c783e1f5f059c41a9f57f69f83467bd86f46af2d6704fc31c2baa6e75a93042e49750e88470088ab2d1b38a48ad18cf598ac09895a8b8ccebc9ec89a107e6670471b60b681adce6f31a2c868b1f78ca181ddee20357a4e31802b75dd01aeb72e239a8dd6ee6b9dd20ab2594ae211984e6a00fbf4d3e88c6f6e1f94997e9df69a115335646a01a5597f9edbb220d3731bc48cb55a4994482494decd5161c3ab562dea4791454d96feeabc8b92911e7a8609cc6f8dd2ae8546a424626d5d78ed561e32282300f9f9e337c166446a6ffd6ff5d8690d2eaafc07928a2c28aa3fbdd394be4e7e560a66307ea8baa56060e2e0971c583a97c083049e2856143d0a3a9afcd7bfad75a12a3486281b4693f778a187acaa2df992ba5e456f54d42f91b4ae699208f521a2015bde0cc562e236e071f70d06c89ad39c06a094e449ee799a6e6d8f7d9f5fbd4c40975781292ab2cf8f398d70176a99782acadb10dd40401dc10097b5c9595e17e91daf667e463461f220df470fb18f143b7f658813329dffb20db68dc2b52e30e13d9428403b2acaa60d58dca0b1b41361ba62ee669a23a1708d411e3673018da2e2d638e925c9f45b5838713c385428bd73fc3569ccb821fb047c942d6347df7e7c916b6b20ba8708acfe3baf5b6d27e6dcfc1f62cc462b4db53ce5c5f0a495f89a5f9338773dad09dc4eb292d305bd3d636bf4d6b53e81c220fecd301496537556ed3e191931f4b705721d73909fe674bded724bff659d8708daf2a671ac4b8abce6002f5ce8066b49f8d61d9c5b9174ae0608933f9c0c5cd890820e70498aafe81702c4e1b9a57991c82eb47789a797cd9d43d19ff873f9bd67e31ad35178f1d22a25e3725eddaea6739f25082892d0bfbc35c28857ec1a96b71e2a40828044e81fdd7b91282e2c1f16d264ac300b87c3893b923b3ac56cf01fb36d5f68987f2e3505a24a3fa929c0499d5cace0278ddd807c51b855e3f26c29de58cbcee9ee8b00a21fe255fa023e578e5c2699cd94b7dbef28af4b1c8946312a661e1650025a7efcde04f7eb0b5a543c14aeb7aca9a9cad633553b05081425304e1a931cc14b5e34763b809d4a52df1cc6eee1598354791e894cafc42e76dcf279c91d4931d6a9814f7094a5e6bd5080442c24deb76fb50acf1b568b4c69ab1b959a8b42ecaf5cc8a7cc74c37762ba71096c0793e1a4201c91c66120083c45a8b5cd5b8175bcdc2e932d1828c9a70ab899f6cb38d6a958955e22d0be1e34edbda9b08ef5400a49bde54743938a688d7c26175faaa4f84995c95e063a4300b076faf618b6e6bf07838fd305e83a7f02add93fabf6005079b090944e05e14310ab2cedd8d2af726e3dcf408b5c25b6c80c658498fcf0b9db82c4325e4181c2179acc4e85c75726cb093b4c4514a693b606848b5ec20f07db1fdae1ba818b1b0a6d70d1fe6f1165a5849a79154243ecf22eb4890a65c10fdad6570b9614a5e033225154337771808aabfa368de88c95b4574c9e8128fa3a82297c9d5989c62be37aa45ad08b5c2b84cc24358f56fe3313a5e539f49d3377be96ad92eb298db52cd84e7ec6c8e70ace8392fc96f3bcc127adc39145b12c27bdc3b996d90f87e6fd24619ca6bdbf0f2a8feba940bb963733763b6ce220bc7484d295f51ad772090566f40c923177574eb565d24a61bc19b02975b3824bc76ab9e25eb56c7280bf1adea882ce1d8142497831470cac04dbc4ee3b1c2d08a52c4240dc078b407b2578b01242ebe06c5de14cf803110c6b84170b42b865f0130829a647c211fb4f3f7d661eb2b1d5379c9fb638a3d63ec6fe2b67155ea1d6b4b080787dddbe172fea9b2935847cfbc1dea83ba84aa1e07eb36184e7a96047e74846293e00920c492c43aa0dc0312e6569df70c12880ba7ae38da4a285d6d31fef2e0be3c0965ba90a8a63877c78e2695dd83390bfa4ed9d9f9ead293102eb5f74efaf962fef1e4169c845473266a6dfbffa4d7586ab3130d5d8c39d2cd521b7497d574c7d3da15e52013af435c1d838e094ac4ecd30aab9699ec7a9b5124db87aa0504d1a28f389c24f56490c7e71dec9ed345a25355efdf2ee53e9c8e89ac379571c124a06d903a1df626dabccb2e61da7888842ddca8360c7440275d253a8ee67f2ed3fec42e3659efd3a37b45a7687aa91eb62c542cc0683c4d30ffc1d7d6a9661c8ec5a6951f8fb623fd00ed8b9ee30b9cd5f1c3422e6625b35f092566ffbea3fc942c5535baa4c0aca0645f7035f18d89017562faaeca24bb1039ffff6ba960f17084fae298692ad72ec3a1e955d2613efc62e70de4eb6029b360daf6206145e987572a86f07f21d6a661ee15c2a2df234f3fecbc74c7b475c977ad0eb389c24b588d6273df71aefc3e1a8f01b2907f0ff94c3fb5e24c8fb0203240ace2fe64e5e15ce020473f8a6680524f7ff5b0de36f4644870d03eae14daa13d3645e87c7ede5020f6b118ef78221b09e09ee079bdc04c8ad03a867955053254e1bea64ed732abb146ce9c902e547bcd26d0447bad2ef4a0bbe2aa50f5a10a3f67553f0ba29b09face8756d09048097301a8e06212ec462629ca0450011a584d5eb2ea9875da0de8194b4c0014a635af516e596dbb5c816c7f46e21f601baa1f852c96ee263e88529f616909db310d559a240dd565d962a225d652dca9f83f48473107749c41a376899ddc66e257940477db488d15e9330bfbd7ccb3ac088790d7d4ece94de090652e0f31974ee46c436e476580092ea34bb63443715aae71b89202b35aaea372d7846613eec5b304fa03e4a8d4de2b7f90222298383172833bdb7540893b788f4857b695f5527157277627610734f75b7d1b31ce90074c20140e7499467438120a6dd653404d988f3b0b702ae448089b655be805cbe8f5e47e0a254de51374126bf991178394d8896149de08bee05746463ec98038cd4462fc0a7e8390fd8979951f82e53a35d3c65d684156ec364dbebc356cad299c3d89fb537f05b7dc2398844ce6763178814d84d48c3f6b88da9f3daa8dbb31d9bdafad77549a0a5968ec5894727caa6f194cd26fa2a8d61d8e9ac5274000d5650512215b1a4861bf740b4d92c646901ec7642ecfacc0220a82ffece4b4abb218d66597daedc72905c7aa3c12b6b6fc7cfa37c22b1ff31e8729e6b618cdf1a83f1060b26b238f16c6e84a1e60e266abfcbc3e122103b7040b9270214a5a7c29e3b586a28f1d7443f3b5c91664556c982ee982066182f98f2e43ebf99a9dde64180569087a2023317fe2ab06d5e3f631100ee344e158e2788673c978033f4172f956dc716072b7405fc2facb0f6428d75fe588cacf418298bf159b0fb803a1a254d19a8885e52bede96f29d78a816dbdf1be24c4d9b2288bcf6ababd0d9df86486b83de6032e52a944e64c493a3ba3c653f8a9539764b1bb0f787b0ee31bbfc3130f7f977e2867073779ea14490297ef7237e24a2c25f1bd006b12a04cbafd8769c71dbb64d501a6e5bc4806c5d07150da4fe61d68034730dd8a05c47bcb8860238942827d9d54ef083a2b406740f59be5648e229d37baae03b7c2456a9cbb5f1d4ede703e12537cc6f51e5bbb478b1a2c10426d6af225d8e2356eefac526b1f760416fadba7f92aefb8018defaddea8eae968254d9927baf087d3db9eb6b911359ea4ed4a701218e3f476a235468e8883253b05cceb4a923cbdce35606316798314083d1215e060fb7cbfc4e88f815e7f39e61ef476a469e7047ee6b39de100b83bd69a7ea98c8757b029b34a0632181304fa50cade7990b62864a18382517bb11a9af4c4bba0120c4700bae15051400004281debbb4d09c8bcf39795ff8b41376a7cf06e89da3a262a3c3d84304ab7866c679d10c5cac97a86c2c232e064df89ff00e846c28b077d775483569e050ea7a8b48182bc73769fbf52bb7af6615f20b2fde2e74e61cbc33ead473eb47ca0a0d7398ce6c54bd10c1d822c94280a0bbe58f1aa3c2996ec09ccecd9bfebd16be130243e7598d5288cc8d7b5b77348dc94138433c6c36b289001470548bed68f8fa0dc7a4f03206ae64d1b1ce24423a6a6a4dd73da94c8a3eb0de493464c9746ef8133a1078179535666cb7a52f3c347c880ed55539bff157debdf1d152a902e6a43c60d0bc9a23603d5b43e050db5616aaaa2ff24c88ba16100a4ed7efad9aaca3fe385bdd31776e66e97e255f047a6051e243cf15a2ee81e46aad9637aa014caad61e4aa26b7cab66f5d7f8346a5e90b7b982ca94144d96b1e7153b040e53ef6abc71a30e749a2c338af64e4c4089389640bb1b6a5f795e0322f86f17d96255c1ee671f67453875b4f650fa922265eb16cef72a947a20d325c34d0d19670a3c801b63b8f06f49298da17f666fe833c285173f294f2d547a5fec8a856d0d5339c2c4ce7c01e6fdb11c33f2abf7d617840a871e9320df81682fd27c41cb463d823ceb0088f949e25568fa0498527596e01075a9c294195d695fbae2755046ee5bd91f1c200b04159a3ece2efa73dd79567de02b3cb281ef91f159ef934f5187162c3a10e19a394e62d1ae3e46974c76dfcaa880b017360a1bcb9faf6c08f73342a0700c2d6ad6ad071ac808146e622877e73a2e1a225c83516584489b012331395dcdd3206478e59aa553d1b3508e56cbc66c5a5f46166bbbce1315ce1d4fb32afbf9363dd0ac9b5d413abd5b127bc4d325e38398a189045efe53708ff35a703f60f08f73927f802762e2c1ac512db1f5acf9d68a27757b585f87f50c98b7f237cedbbf9d03b1eed7d5f914a016a981d33d7204c9af2b2d8d306420dc4ca04f96e5be9c2636f5f9a85703fe6f4adb42921744cc93e60cf1a1753e538342b020c49d85bd3afe4c2909163948f382b37d36feec7110f15aa26076a893041eb22dcb31656f638941d400a48670c4a16b49c89cfb76f402214c978e73a6fb2d5f03cc6c937d19545825bba0b7204ea730833557993ec87aaeda443ff6a14b61d6f7f773c6a1371134ebc1925aa9a208c7867a5bfb9081b4234366899019acafe1647f05e18165f1654acacf3425838ccfc9faee4ce3bb97d2b8acbc9a604084ee14baf7808364d4427524df9c2057e6dcf2ecddcc1848cf5c71e39a6841c9a675ff8f32feae7b09ed342df2f46ebb18678e4d742f2d63ed48bafebf92fecd20238793bf6caad08bfaee7e66ac5c208267729f1201f76ed3cfbbfb3f106c82feeaeb9c905f960827499f851d83a17824c500d1c256d0740a4dc47ba41b525f4a340d991a11558c0160077a725f9d532eec5b50fd5ef3cb5c768586e9f42aba2d83309bbb91760bc0d89da8575af011cdf262d02a0d7b4e26d916ee2cd105a81a20d1cb8f5827ef4e2936ef45e5963a5bf86bb5f333ba7c5f003040ed3809319b52293415111c3949c8244d7063f986d1c399cbd9790ede1567a7cf27503c677d15266322cad1a6ceb61d1dcac33d7da90c36f81a5debc4540c61801b34bfdb1af505148c37cac65ebf7b92080f1b8698efcea1d9b8e215c39968d713743a88a1dc9f616c2574352895d50ab52f8972eab35d21fca110e3f52c43bb1d024db288dd75a8931bd688320bed130b8d31198368f0e8d2d2145b45c4980bb6f2eae2df5eec6e01276f6269e7c94978c3e71537c586b90abdbca281a9ba4053faec7819f89b40ac880cb010d72b317e22c735cc88bd24e001d150d451eb77ffa5d4fd91322d4cbe7426971baa2cf417100455fc88f95e5939ab71cbdf26adb1d13d385ee8a9746ce8d7e1762d1a920b78b330c117fb8a6efa327423d327c5a0fabc715d262d855158d92306dba45348496721c868efe9cc6f32e064ed12d401f751acd863085d70443365ebfa8b9fc7634da656857de1401411a20d9c6b5f99b6ef3b882c1ef45609e492261eb0ae54947c2619e2774fac151eadc1af845c0c6a22154a092d018fa325e845384c6614f8ea66420be00aab30d626c81fe85d916720ab8b1823531a6cbec5d0b5b5d1c29d87b0d1cee85a0eba8d98f0924c8b5666cd962dce234817d4418b8ee7525107bb78119624e4ff84d02e4b9547544c81f9ededa75996e366562abccb5670f313966acc48d551fec41d093e0039b479004b76176206a2c921e61e01612d7fa12e6aa48f84b8f4464d8ad42577b17d3a43dcd273fa4d1da242e6028d90ddf79b6822f9aba501264e6e4132076f5f9e3245b7934e303daf40f16e649791045a23a2dea75e188bfe62223cbed9f6f4485bc0cadeebe913513fcee98ad27dd994097a1539d19181f39be402e8df3ce5b81130440b297177bf0180250b164e4a872d576754c37f8f340b9b5a2d8c21fade3daffeb045845732e867d4636403405452c6f81bf20a2c4b79cdcbccb47aad4cff4d3c0666705bea4f1511f6f1c47eb03f51cd6dce3abdd63d68ff4bb4306df9e35779f344075a8f2936c88d193d58bd619f6f8a15e4c68c1e54cf796c971b7e935fd58d993e68bd536c961b952adf1c2be81b139d8adebfd3af7a734e07452f4dfa6eb180de5eefa5a267a06fe83b86977eb35f71cd6f7a13bab0f21a0aeffc01bb3583ba03003a771ec9b368e28c4f03386563af0b5536ea2ed0c7de39c9b63b93d2f5f750f538e2b5dd26d293bc276825e19e74144b01c6b308c5510e575782f140c12e0c1ca86cd719d9af0806d373fba7dc049cc6548aa7123814e7361eaab930609ea69ceb070cc0c7126112c7165753f7ac61f54ba150da9d0789d6540d04a55581d4c352c0ef0eac4b07bcb46c6fc170653ca9633130fd6f411564d59e06cb3050fb483eae3dc27caa7203707beb1c7122d694fd9bd5798c90201ffbf9ea543abeeb2e30b70e41a018f374d692f663d218c97bdab3baa7aa76a4f2affae830170f18bf802ec6800f13a41c0d13dc3d368a5a5f20541a8707cee62c169886bc73f8a0124e488440b00f7f0ee03c4ff335e228b6c06b665b63a419f3a72240b14eb5318228923beeb6618424eb20d81bf6c77428a95b63e38e527593b96ecbc238d57352e5d07f4063c30fcc85bb65f60580a73e01fefd85e8c00bf33b8f8c6cbf984766ecca3c493ce1cfd2efe7ebd6c3f2588a08522c48d6037c021713aa880d7ffd302bd8e6261fee75e6004a4361007b55eeb3ba8d6678dee2fc9dd0c61b3547cc33dadbcecba6f78c4d972ba9be8cb7cea3cd6878939b0d9f70cb58b855f27a32d5649fdbf0279bf48f7cb5659b0bfae822a4485c693fa2887b25d42563dd2a831d6a01f22bc858156630be840a2cf792e15086982aa86adcdc0f8c4ae0c181c3224b7b50fd6f87888f4a5e326d0433386773536d8bfce21c87149d91896b4975fe2357415498c353ca263fed9ad6fc1b8a43cb89ea10092767b7e57fd303a3f1c7f6a944f564529fccb83502c01846dd8aa8c6a60da62728d9a0faa3e365bd82d2bd9c812cdc910c8a0a51748d0427b36de5c261bbf1316bb4a981c0413b1ea5b281a2b4737da003091004f1ed1239e2ebac17445e40584078043b6a0781665637b707a47a6c6610e55501260182f374110aede099dd12b340d79fad918009f5001ccbaf1c7b6aa4dd05f3c290c8247337dbbfa92109778d851ba5a82763dd2acffd7d2b6f972f823c66d63c7da6af0fedca244d9777ce2f550e9c22ae3e496ae2a42991980e8c07091aeea791df2f9d72dedf3c568f0d156d0bc9a8a7f92c638160b1aa0fac018eaf9fd15a534eadc4e6681e960eb3356848568fe5d787e4c4748c83adbf1ed69b723bbfbe3f19a91fa11c68305a8350307627b1e23d66e7a4e79f4a575f265d8f4c354958fea6da0348048a815d8a1bddedc8504b56ea234c4d633721f0b3cf72bada25532eed18f3e1379c2814b906a55c68e23213db54ef8154ff5a3a7c6c94a56249cfe03040893f39e5491e5bd1bfea20e1ad2eaffb73e0b3091120e9913338618f93e6ef2182e9f42e451d43a085683853c25917cc539d52776a5a224cd873782d794f921ad20c64ee2b9496cd443a05809b2c0fa6e24a983e74219cf1b3773f48e72835ae1acc00de47da586e2738c7e1882aec4e415e77560668d9d1e619a8291123effe0bee6b5aff05a0ed7cf61dcf5fdfa9c8341387bad5ab88714ef3140aaa416646084e3ecc4cd5a8a02dde9aa6adcf23f0da912a6e56f8996cef7e9bf3152c142835987aef421458f2ee6fbfadccf0861903db5c7c372a52c86c964721e2ea1899e91c83fe27f0f7586210f78ef0037dee70f72a1c9e604e712e34ebbb4aa504e3ba5141f1036f77ec4a6b7c136bf28af0d7cdd947207c7d563285f573523cc0511f9d6b096bb602957589f9dc8ed8264e68ca20340652fee6fa3487c98f5b44a7c5d1991c06203b6c90fab30bad414dcaaa6ecdb35a5af1d4cabe400834692240b45a0c85eeec8ffe0e7071c5dbe13424cd4bc8ba0777ccadbfaf4b26e5414ddc21b82f7cf3da2eb2fe5ca384e152800785f0dba4dbce0824b06f43c109730a20456c8db01ffaaae2091af81b1ec8ddd95af26747791c8fefe0ed2a0fd1d4defd29a98fc8324f65699c9b1bb51acd05543bc55134519ddd66ceaf77f43644a4fa0a5bbe64070735b658dad268d0ba5efc6927f9e098db68bcea94f1f456b4f087a5087e0b6302062ed980ce00a602194da1b5c830280dcddd9726c9c56aa6682b87444682dadef4bc5f4f9f8608c6e3f8e7ca44c2b921443eea6704b6e88165becdb150947c219646e76c6c167d2a1a190210b741d790bf426ee30b7e8b919f91e33b2ebd9418bc9136418649f7b41afd02a01e0179bb8a53e79d84a6c81f9a98e5672ab63f015a04b60315f7732f0ab60c6b01a35090418bb0ad13ff701fe4c41e3b3b3543364250b30c83ff9655f9c25a083dca079ce5486c9073a8b235faa96f4682d3ecbabe9025ffd82aadad1c1caed5c0df094d70a7b511652ced3f729b3d3944d3c341fa8d29b7be476b84a3d1ac66a92ee79cce469464baaf1889d58fb765ac54e020f8fb34682b92e9034b43fb85160a8cdf522c2a7170da3e7059f03265c269d980c74d593d548d042ec904bc53a3abc71d2caa9e089ff0b517d7ce11f6927c044ce8f7369802d1cae9137886147e0842599648d7ec8bfc461f6783dbae5dfe8fc2cb250d68fd9fce081813c79a37b1414895c459b28e8a1e057234a7b7615434e82e6c1e71f1d43ce350dd91e9d1b9c2d6546e7db11848ea941b44859e9fc7f4256ff708bd80d6f481c498df58794b228eb2c2dc939419692ef4ca92788b7e936129e4b011bfc6a3ba35a3ae7b57460addd408a432827fc4b576f5a818a7f720ee587b324f59e78052287aaa0a432afc72010494670301876589700728a5860237ffac34a4411c4b31828a0a83b409227e01b504fd50a41e680d689aac73e4c914339a07dcef2101fb4f2eb6b7f7ff86e1262c3982371ec6780f4167ccc62f6685b3be66ab87253de0484c90183d769c60344d452c510d653bd1831b9d4d9234fea688ee262e6c37ec5d1f6146e8c3becee841f54c1ddb80d3ee0c6a1e6e341c05dc185b8bfe28f5f53de0582f6b601da68a7a0da1a1c1834f0757b9d4bec8e4df3d9a87e5b57e03ed5985b01c583f6f3193b3a5ed43078a5750613fb3410936983b387644f7512936987738cd9a390d62580b0958d442f47520a49bbb1c6282094c68deedc8ed07375e8b5cd64176b5978b057ad3dc74834bd60763a9ecd9a579c34f74d10b90b459011a4ad623b33a93d8348ccc9eeaba1a92abab53ef7b7f4a0277379b579a656ff994a221df34dac4a0ecd367433d8c7286202a97fbcd23642215f50ac50de9ca2b637e2eb571e09f090e94dc75a8c750f7386c1293d5047798b4fb5a8a0b8c5358bcf14b2a1f657d07ae1125a92f63d747d5d68790c324fe71052eb3dda03d952514f135aa0feba7a4071d2b6615ac7bacc1232e9fb1bb21f045747a973296486f44635f083fe612af13edd514ef08d75abf80e2e3f31104c906f06c440f1f74fb096c2ea9d1fe186f415fc885b084c18b476d5ba70fdef549bb9f20f769839522b04a02c16b895090ed08f8ce977ed008d271bb52696e134141f62e9b1afc440ade304e19e26b2cc9945a92c5bef0229f5043d65053f491a1afbc5a86a4f5ea4611429c9c57a96572a3ba5f0a5912494e112d4ba95889be5e567d7a8b8c0e135adfc23b5409ea22aff04973a702b46c86ea733a824752838792ea0e7f9eeda375e439a8fdbb33de8935da62e40951d42b3e3c13c49837025c9d2adc3b9b4ee717c6ed67b44695529f8ceb6519f56adbfd484e25de812dc494a3b70f3def9043a50b02f3f857b57e2f8e8bdf1e4d93f707de17c109e09936d144f4b6159d2191e4a52fc9f050afeef0b8e42aff3e95a7b19879c6b7c27eb51fc1cf6f4bc2890f84209266d21fa76f1403495d3d108acd29cb4f56f78c851b8b3975cc896ca518ca7b908086a99b4738f047f1ee01bba97220aabc3648c4c5aae46905900892bf8a33ef61d010f5cd87c2a527aa40b71263eba965dbfe2bb985bbdc4bcfad42739619031a5da332c568478cebe30c62d3140603da2c4d22926ad7d448201618ca676e21c4f60bd9013609e515f7bff885e030f1a4b2ca346754729c62e8d3998aba6f638a350c62aebbafb30fabf5821e6a3c8a690ee0a7a0f8791256c4d5f431a684a1a59f292cb01cdc95b7c2c07f888f0efa3806b498bbb64c170a5057e00d38d3695b7080dc405c5eaf8f68ae2666447af30a6cd482664d3c182f885d8f18619737439c5e96593f269e50e2157cbec8b459e861b72bd4b63deb2b7b8fce0eb6f5c1c2c192acd58c166588c28d27c2d2a72c5c8e7cd87e4319022fd5cb1dabf868bec6640b1fb00659e227845d6d743cd511d93a336681b5013ff4f14451bb3986c2e422da8767bc4319c0a2427f22b6b1bfdb6e16931ffd012474a9ccc7112b76305d856180044a213e7840fa1eb4824ad7c3f68e17df9ab3bd8c33dba08b9689fbbecfeee38ac0b54e8bb7ab035ae14178d3061ff49b0fb24d0214fdb582342c08042db0e20a563353f618094005a4fcdf4a4e49fb1e3b217a4764becd2f7a2d8392907298cd33938318d35529577801725f660c0a88beb06dfd2adf471c9349d4df1fa9c16ce51595038794fa7511d1378662aa95df405173fd4c6c32d2e397fdb8bab2d7d2aacc6f4750ef786b6a8f1b41ae10671c464516b8167d1ce3992ac8a7828546a38517c01014c98e0db637a9c581675f4ed835d766e5fa12542c6c6fe7da3d2db436cd7d53c9d3735c7be313957e2924760b4a29feca253582e1e78705a3d7098e56aac78b47b896fd9083c64bb736b6716fa6b4906e650551b531b6247be7b50d152a59a79a56bdb7eea876123978f26d8e18870e665c8af5eeae32293193d2dae6b4765a7383210cee84576e6f6965827bd445e8768d96d8dc72fd9e48ee23c3bfe4c856258ca6356ef1ee8ed0102aaf7191001b13a4de583c7c84d110364afe28aa4993d0fee8c5545adf288771e4ca263b9aaa24eafac76eeb501c6c95c73e9383dae7cf6ba86b51989fbc3ec0192083c7ceb5927b59076a3d62ce661fb1fb3f0b1ae6150a15fada5ac2759c2b8a09d3a08385b236c7d188f87c6aab59d46ee4243f15c422bd740ef08e45f6b32fbbcb62ff6a410d5bf2dd6ce47f73da6794c38c73394890cdf5feb58b3d18f255336477f870ab659096c35ecb7d4d576682cc1937c2b20f8eac0309d497d4f7af519294ec01c40e5095658c3d72ad69f69f3cc5d551e4b97ef8d707d8b411dca793a1cf8ec80da172f5ea4b70c4eacf3c4c9d5e6997a29c776a04a0a20929290a3aa0da98eb69a5f6e939b32c557fe1422c8142d93e0d2707ec4d0647e17b5b9f41c944c9c34de5c35133eb3e734d2359558c633c819bca284091cf5cc1783687d6e9aa5a148d0200b7dca5308e4b0fa4abba9f35984060d65db23061ae9061ddf52ed16d97af437d2811a323905085db0d6fc949a7163a2dd03a5c076fbe616d86847edfe4fa3b8cf39d61875daa1b794f9b88f9a03afbfe8391907566fd2e20c79bd03a9ec956dbdddc263a893d9ea39f65a79a803c4a14084ed281e49941cfb215fe9743b4a13b92f2d4b701cee43b770a8710ab6883c0b3166c736291c050bbf70d0280188e0c0dc6189aaff09987b3be3ce8181c0de2ee164b3751496c83b04c3cf654b008a2f66dc4351975d607395a0c98ed6ac9c2d6a5105f4d490bd711ebe4202e84249130f88512d673e049ec025390ceeb443a160d90a12e548ab693df150813dbbb60c3888857af233d687a35692c4d7aea0a4b78352f5b98c3865abf28268d89bd62ddcea7786aeeca31edd6688df26373a140980ff817088f4e05443747a40a9bebafb99c9e7dd2dedda2a89148f95ad376d9ed3f1ec6e329680f7881574ed71d3a20944a4b2fb1b95b443d2402afa1eb4e7f0f85c6c371a4856be53c77331df4c84571949a5296d77bb106b4eee9ef8c4abcf5961f8f67a396bba5f0d98931c76596aefe379e69f61a706ba4132ec2c89370cc7f12366c2ecd5d62f1b6af16de01333c02d0b84738cbdd26c9393de5106acbc02330ad033619d8a5fe060412d648c8e9312fc25b9338272943ac1a524e8ce697a9a61a2b1a4c2aff66c693652f3d81c70783999784c9a2bac2bd0c3017e4e3e74c41cc019e36fd18ae750b92177e70a62fe239d46712c5f384a281902cc18a7c06c5aca3fc144ecf893651f7d8eeb9dc6214982b5170f1fc26f21363baeaed873490bda3b031e59599e03374e33a3dcb14f29d6fd9253fff92280d6a886f954ae501e6f5f6827831c96e2d04dd8fda042c1b8a47e145e8627c79bdc04e567d32b64725345179e52796eb00dd79981e583922a109e005e20b1f9580afff01a9862c4ce5c9b8e776cd22ad4fa659e58a0038a61648f35512383a2cf0a1f07babb039d832e1ac25efcdfeb10ceb602efff594c74bc63fa6652edbe0944186e32164e003e65e171bfcb4f3244b0c61d43fd8030a781ea77e91715e52ad46bb7b12de2be5cc38f114df0eac9a88dfe18cacd3aa968141ab7c648380703545ca9bb0e3400c9820f4e0f7b57b00487fd0447f18435a9a1327a8cae06e43d527679dccaa1264c88b5500ba32b81c5fc4b5d0fa10832ecf596c7d10559db5154a327317688e33b47c05ed8b49828080598a7734e3116474fc9b98b438486fb6a307eff5429c211ff33729d3db5d9498daea99233e984e0b6391b90101ceeba3b60af265338bcb66357972adfdb6a14bfa5000a19ea1e4378b900d75ed8f584c58b19efc7ffd35a408556b2b798e7f50dd13c207a20e468a58ae90155a18cbd10ef365dd154e562506b742b4926a3fd01611971ea0080458e8939b65db0c0c2115c2f86fc5ddcaf4e5322fb80ed613c99901dcd00c28e73a0770721103cc0e601c6482af5dce0e3c18a0fc1ca1392673c94570d0f3906b92b6a523eaa546702fc3aed4b1d6ba5da998e56d9ee9d02a1c4166e1f2ba67f841b16604d3710db944227c1954fc26f38063176b4cc7a681bcc3a33aa81ae7107a6148206cb37bfb0e30feb436c5ec8dfbdff738438d0f7fac0141cda486450121411c5199119c707a794744706f1f798b73792d446ec8cd14151cc9cb4564007e074512c3a7994486542fe0c4cfb7a91ed32f460d60200f131b8cd2344f86d1ee83279b893f7a2b379bbf74b45caa18b9afacc07cb28e62f4d1f9b0baab8d416756c23185a35e2fbe73000576677ac2b73fa48654c83d4b3c5691d1eedd8b121b143dd84bed6a59b3204a41524e6b2a3aed69e960051dc0813060d849a07308e9d4f16e166991d1aa83c85fb9533be10d6e3ad26e1abff2d57dda724a1039cc19b83fdb0db15d058a5b8cda4f6fa48e64468938fa0a338d6b67cfa4946e5c8a16568600a6a33ebe2251be49d4b0f3dea3fcfd5f20b02165b2784bf630bb0c10aec157a36e96c9a5bb5418888c123b4af00e77fbb1e0da196c3e29323a6ccb8a25507224ef9d22dd78647fce0521a8034674e201110f127928573f2666ef0e12d6ab545477b0135167d387a6168d89370e14849285647ee42cb30ba8ed3de798304ca0d8ddc3fc71168c40d29707a8c6dc306c595e75f733a87579e2541fdb74732daa80921393d0db753bd1527acec21b889906230ef681505ea1a24a88016b1ed7a0694c578041e021653a4f2110a371ca53055c288d4d208549abfa093bd5cd0a5a846ac1e4ce53a93565d2026ea5bab6bebc759831715203e417b00e684fb4f3861ac40e7bd30d5bea172377961b603846c0e5dc66ddd0c789ec3399f1c06f0480cceaceababfdc7679705ad5b4f3addae42834171697f2d9cc1705bd66148ed5463c69a195d478f749e00c274fd64fd20ac14eb7d9f3f2d69537a7f0e719421f91290dfb83b4b600c7064312b80b1b1d1dadb8ec6dc8ddfef4adce74cd467d862a4b81fe3dfec469358ce7824092b4f1110ec84124d3f83c2a44c9e938bd6643ea3f90c8a1407e28038532067059425dca205e014e1ed14a6a4dfc0a29382987b5687baeff3885c314ddc515ccdc4e0c0141adf28dcb9acd0aa5cdd18c7aad6587e483dfad0cf21702fed9e6125a3ce982197dd3332471fee64901ae93c59cc9ee1f55355f1c0e540593a21cf2b663a1b35a27c25568d05f73e51da21af59ec3c938a3c842daa0ed3176ea0682c8ae2e26ba96bcae4ec23cf217d0e294a72b091d39937cfc80cbdbfa71f5184f65b3c308c81d5f48117b23413b983f7cad29b1e2956ec16247235967fff838363f4ca7a563c744ddd170d5c232fc96b8e98d798293b2a81014cbbd836a9c651d2ae6d487cec298007e3292c74641271c92e4ac5c6dad1174cfc52da4bf2d107178b050b5231e1c3bf4f25017e3622bb922dee5aed86ce426c3989cc7807510f53b614726ba4c50493c1ba91d28b9bbf8aab9db433877ac3281be12949f6e3e473a50a851dea4f2589c80798c75c6788201387bc0f0d54815d8766ea2494c19dd2e280d6aa36d9583065a06faf386cca4348770594dd6d2a81eac2190f5a85f5c8b6906a1545f10d617bbe30631cde2a1df3ce5036d8d2e60a916498eb4d31267c564a087adb6942391c373d1d9b371614349cd7a1e19e35e79aca64284ee87e25b89de8fec17180a6bcb76c3ad5aaa1a8cff5420cd83acc4a53940db41ed2d8d2d85a98a963a6333456d01b9a018a7a57638596598baa0dc695ccce18754e45ab37768b95390c975ec166b6eac70d72bfc0c0544762775e763d8da2daf2e0357db6005d66dfc03be771022bcf7bb804c088a753c0ed23b3981686c6f8892cd759338f351e51bbaed4389e044bd1cda2b8586a989e6c5af6ac4cccbfac8109ebf5bc3b2c5be181e3b0bab9795c481a609007efa17d2810c96ec629321cbd11d19e016ffd1c67ce6b741c78898f017506e6ac6508db53f20071b3ec4c1703b3bb9ade0d4ae753bc0a8b69c2329db8b739c6257b059e160f12f881f0913ccecf18d9c88656a80fcba824c8c6a6666b22ab1516ffacc2414f73fecb20496d9a3272326f631ecdc657a59591dd35d8f2f1c0cbdc391a60b8a607262d0102e1900eea884c3c0c294cd5c47205fe2735a2517c6360ca4b37da2ffb7cd81d37f1844dd822a2cf03afe842941a6dcc49833164a051f0c5c058744dc9e8df3ac9f65b828f169f256f630a47eb8c578ffeb61a91d750eee4be03a3f4c7c6e837d1583d18e9d3f2e9ed5a2d80003c02744a21899296fa940a518094b168e0379db323fca36e637ce1290be68d5e6fdf80d5f8b5e9d6652a37223e42d4f1f24ee954392dd6345baed2b6de110586519a7e501c0075dab882898d30fd2d105b54cb4816d5e572c0f568b0986e133b988a3944fe320c0d97f8cbc524286a7ca5abc8894220f35aa272193ca0cd2dadd01f2795b110c4dc5f83a5bdcf6ab7a35bde1a3aa92314977884240685aaf1e0201790de5dcd735de1fc68dbad7cdb6e0fd34090ab3ae4cb8bf2c65218cf520d8096cc01d1114be822fa39bdbd1dcc1a209d709d9582e27c8eae9d3fa0c9332f3d20a30ae2afea4007607fa8fdca46c786d82a126f62c8f326480110d4ac20fa24b57e36bbe661090337052931f57bd73d8a70a119c4d555b1269dac5a58c8a9b26e6e6d00b2c19a01a9b508b9a32f3541381073051dd09413304f61894c3046dcb919f440fcd20b9c2873796904c6d20087edcc097dc960c8c0b16ac292a1530f014d8b35d86bcbb333d87380ae6350c6d99f424beee3a17a9502a617d9905d099c2ffb80811461fafed82c56d05b4cd9cdccacba916c07817f4a2575d4ab6a75722817966baac508dade1e6b8639a8f8d8eaa382956bac929b64d8390f549aabf971a4bda2ae39ec8ee842eb35995115862c36eb9e26c2803f7505c84318cdad2ba4c8e605e87b5bda35b565876315b006b1e7cb9776846c79e067043b56fb324ed41496c95f328882e75e3f2e96cae3f416f604123b9a65ddffe799ed4992377707d3a158dd76cb0622f98947d61dd5ee99ceee096a90d3fb61c73e93e5389590ba57df48da2380428ccc45632488707eb69a35a8536f8768f3452b2952b31a6423ec61be4590cb169e6904f9c5ce258ba63220da0c0fb4c80687731d2706b2778ac14733911ebadb0a68f6f02adbb22e1f383238f4fb793bcd08a71a921a5c1047dd3f67504238a60d77b5e747c62360554a24aa45a83df26dab07d097b0fdfb48539ce5dc470f4ee63fa1ad98c16470eb44069162b1141202e10b22d89067401cd7c54bac942f38e81a8bed5910c57721d0019f9c715be670b2c0a496af1ef9489ab0cd2263a3c5e99437735cc43213eae77e72d11afdd2c751dc42f1f952bfe64609adc998fda890ba769c5ab4c49759d540ed5ea901be116bdfe11888ba1f65e6004673cd5429e2834b840608c9f43d03deec8356e8d5ec24c855b5243af3c2ac10ee3c32a7329b99171fe49c44286141dd975ea480227143c817a9a67f1e6137acf0ce807a1a71855a300a447f996ea92bf0deac15d4cdaaafdf19f63cbb8883cbe92cda2e16fd4fec42cef6c0ab176fb6e35d3a1b1904107c1a1ce4116ba4aedd1a25a7a3dd0d6d631a250ace02b4840a23c6ac73cee6fa8c8613d46a61ee15e5194b42efd83fc30162574378cbcbb67e20b39a51a23ccbb86114926aeefb835098c1b9b2fccc51ba267885c50ac5c26dd980a540e0868937882172a9066ce102856ea47d305fa2bd37429ec0cdaba3652ddce47fede58814d112f1f6e4a0ff70f6e3fcbd2be8f1f2ddaca6facc6232fa5688a9ee5c5a1483c0677e368ee3407ceb34957a5dba428b11123f64465215e6a3f4ca33341491fae1ec00651ccce2d575d2e09157aa060d29d924307a4de2bcd35921ee88d8e14e5a78f8aa8177a896fe247b00fb68f30f5f3b92fb7240d4615a1f54c80f9f4d25451df61ed60721ec677f417aa7b49d9bfdcf7acb9fbca2a54940ff768c0401f81f1508a4cd6d3b2ed0b6aabe874f0293f5b60b9e685bbb82a3efdab4ba7ce3f407b41d5a04f0eb04a11e1afb8a6138c1e8e46f4f2b1a7556c43124d1eb3f3dd816dea9109cbd4308d0adbcd945fd83920b2fa53969f84ac677b40fd6a3b31cad2cf5cc9a0b2a87b4e69fe16e312df6985f0aaef9ba84b9aec1ba0de6c599999202564c22cdbd898b27d6dd38d3bd0f1892ef61c7e00e42eb9716c45575256678a164a62550fbb023d6be8e6dec00f711ed76a277e0512844b74befb77f0317644c7c0e6a6fff6af57eeb640bf6fdeddf5438df9d755b6d609657a485e2a07d52093843be3619ccef602b765a04a4f10c7c8a0e5bfd00d7463dea4d3d5d7adbf2944a146784c059be71a274422b6f3c2301b0148c081e4899338874c9692f72b052d96c4d93e1390b9cc7456fb1c4daa2788875865adf460031b50b0fcc11c22989cc192b23b2e3709c83c0422a5d9e7202c346bf01d95656eb30c274fe258b579a4bb9dadc631f4516e660973d6cc1d8161409f81f1887d5770c461e3495a0a46a55e120bac1ccfc21aad0c4ace2fdbd399410fc7af3871ff1a97a76da23781e2e6fe9ea2a02440bf70ede82569e8c7a1ab04735bffe7042ec839a59e59d530d3e97a8f04c7a44cc461c41aed6960147a599192cac7c96fc33324a30c5b909b894eba4486ffeb143b7ba548b8b0497f68c1bf13f6bdde8d96234c409f84d4288f3b57b930571dad601e204f7b34668e9e26362de50f6b2c5c9fafde1ce5c5914071ed4d613f30c5148ea4bfff27490c9bfe07bbeade50d115264464628583e105f785f0a776c7b803fce92741b321ae96f0f07bf41a505f8207d7d0d7cffe042d0504bdd786e3bbb15a1d6ad65202895c93da9c5aa3f1ba3a2a50252c2eaa7513601e9c9c10dc06d34a156642e922545218c4089073573275ad39c28c5b9e6512b43906c9950d528f1a06de3569e565b0e101fb22a4e37b8c3a577e1ec129f22495a81d26cf49a3b0f64c08983dabca5a01acfab05bfa9e24b22d41991c3dca043cf26578db1e504f77a6a6b80468cb63620b0dab2b598b16c2fbb84470cbcb4db236b8085416361ce07d52b80e0000ba655aad5bf850502d156d6f97ad800af44f01284a17cb2c6277fe93700714b1576ff02231c2d614665bf99ed5b2c1a29c2250d31ea1e52ca51a3d593217e130d37632abdfbd40cffe452ad561f7920940f2ed6dcaeda64cd857d3567f35d1f45d9e0b49758061be39a93877e15aa39c79ada1fea5104bc3ff3a23482beba3f59bfdb5edeb01a50336971fd518fdc88b59868b97c2e6c06fbf9d07d351bfeb5b3c18055281db5df404c1c17995888fbd4dce09822c40ffd5f0e588a598d070c834a673263c7bce922e6227c266e5761fb205909168bd09f436ada1a3a1dd171e828ae2fb2afd22e15805f9fd5e072edde6208afce066a642a0b4e9620a7b548d8ac70711ba5da86e341ae9a30d56443527f420990198ce87daa0ae674489c753f1eae7526a0e008ab7ffbc062424ace4cc24990518835b73aed071bcc48d1068c80d8dc04b66f1746402e0ee46eab251a1fb82df96908cc2d9a171368d851e5c2d9a5eaf829e3960c787b42573c0ebb20523ac51b982ea832f7d2a46a9eef3dd2330d56ae49062d49616cadc8f26b0005191e5459623caf1d57b04224cfb8134333c898f06a1fe992ed9c937c1202399838ff80d148a534fb4e381b4cef44c9d8ecf7a08ba5f4f7b798fb6acf6474d8ed1393d3acb1feb0441f11d8daf7c14150886634468ee6d619281d036c11eb437282be10ec3fe35a15f270a84ccdb305830b3afea3ef8194389469f5e18032c5fbfeed844b2f844a5411aae8c91663c6156e3aa7eebbc5d69cb7c415465f0f9d32f05fc936a35d0d7e4b82e7e3b18aaee0f1e60651936c78a9d2310f691d41b86e1855bba726d55e9960f141f859386853affd07072d3e7eb740bda16322df09badcd992e8617ff69a896fc4de9e83cc9f099d99b9bd5ea8957f1eb8c9bea08b42464e2da27e2bc6d2c282b80c5d08e195e921f89fee2429afb18415fd8286c499f3b2e0ede440772c80273d6b8ec998c76331367054a1114d933ba96db6994c51c19cb06433dbda51d741bd13aa92f24f20b38e892c8d15c62b4e2791436e403f082c81a6b8c0d558b57aa53793492ce77aec5a118dde8607cab614fa9547ddfd28ce7949672bc808a0b743a0b5b8a0ef1eec90bd7110ec87506e75f332dd29cec5c7f6b2da8f2986da8f2b1d936acc0c39d4aec269250ab4e4b424d456c91762c2ce720a8ba1c70d5b4815729d8d59e4834828742ef8c4edb20d5793ee0a41f6918f9b96f8012115af661a833cf1c4ae954e56c95b191228bc61d9f7a18cf41b3bc1710886c13ce731c4e9cafe0cbe3597fc6dad2293b4fbfe1fdeee34e60aa99864f02e3c5470ae3caa1374fcd01f06de438327054258dc2c6c2f59f9665f060621dc9dc20449a5dde95435aad88a7447d01fd136271ffdce167adc86ca67945dfba5aeadff05f2b9234e52b989afccad703da8f7e64666de178cc27c0a57bb5e2ee6e3e88371304c00d97f952fb251a99b192aa58052fecd569d8d9510a2c247e8c634a99410ff77ba090e53a8f0d1d712a1be38230d7471788d0a6f749c56b4bb8170bcad854c99475045adffa396893019318b13f5b3811248465b77e3faf51d4cbe2742b71561c7a7688a72be6fb48be0b41f37a92634e00fb091216bdc10f63f6292b0f6a4bca8e268909372f3592a8978e1d624c0f89a8e9bb4625aec131bfd9f2c644c6f88f081981c68af5d1279469c1802f110a2e1bdf760722f6c9b696621916cf13d50ee85b051753fe194278578c8f2a141ca4fcf843cf2e1c20921a8ab10cac21712a6c8072575ea7627b7f67f397b91c17ea4f08f6eb6982aa64eb3246b86eb1543ceec1dec2cca229688e49e74fb560f04e7524bb617e87e6569c7753d83dac080062bd46eec830bbe3ecef358a507907b8c3fe0278ffd28c4586491239a827728bc35932af688a4761bd1c18d0cc7d9d6b1a060e0116d41ff24d745fa629575a0fde62801cae27d48e34d2e3e924c7f0227ba3f7e7d25fdeb312e7bbca6183789101b4ae7c40bf18d695b1073247d571a8110b10f43435ad4b64a58eb3d8d8c41dadd459f131dcd611c9e7ce4949a49427f8ba60837735b852c3f5fd6a9230b4ce7d3132c6ffc16fcc92ed3b331e3b84cc14aa2460b77cd75393f7452a12b8b8ecacce5adf11856713d17cb7305f50c0308d8c6ce5d4d44c028641d8b15a8a3a2c7528a98fb56b9baa0066b7a095afb6e48bb8ae504ecb96d582001f05aaa6f53c0ca687a8285b91df987cb4f1aea87e47d57773cbc13dce3a31acf94e998cd8392e0cb23fbe2d8aecbd89d0a6353adc7d63fa1227a16d78d2e77335e51c4555229aa8272562a77257962a10b52205515ff2ca0b54ca1fa429f8d8fb8b9d5c95c114c22709d0443f3e10f963012812f9fad93b9b2f79f28a05116c21981ff0c56dfdcb35849e1cd624bd81c35c687db1cd6eaf5e1364018f48ee309b93cdfec9f23da5b84fc8b8524b44551a271a0f69fe838c6511bd0fbe0047be91118f45688f88112b52c4b6abf71a79565a5f46b29ada1d3cffc745be5a810b2e4e27410770a09029c91d65a43cf8dd35ee55499a3d56f858a46c554d3a2c18adbd3b6aa54fbac15d39a929fab5c4b9fd969ab7aaacfd0e2b7928aa62aa962c302cb4873228052193f3bf98c511a329f9c6f8c101fd7ba3bc54cce3e704734374d6a6e4e772ba43aed6b15622914a73e4e100d957e55b9e8848a7db2ab5a19fd407e9b7ee824162bb46d55e85c994dddb23ae1ac53ece249125f7ac98e03bd3ee32985c63f427998d39e58a57dabb7ed6bf3c293f9efd0a4a3ece2979c04dc7aa7c7d89dfd8c647855c21a6837b1d6c2b3aacfbf37bd672c4e35333766180c50ae4210b2b069c764a0019e0174eb7ebdbdada91880bd8ef613516d41267219b7c67e0be9fdcc69e8600a590ba3580e6eb65ebb38605e5f7aecf0dfe679e80f0d578b95fba35658134253d93e337e8cb30432c4b1410817805aa3906c6fab7bda302ef00ed66a79ada4c3568092d50c0f9c79654074846fb4e363d4bbf8f2085ac4dffd80ae0d98a4f8a3f5da67b9c1c5fba4ecbf13e0c6ba08e871346cb981d078a34e55175c844d78ebc486daec0190c45a43922c75122686de5928f8d3fef60e941e16dee6ebbc055a97a0b8fe159726c916c198628b714f5afcc492c0380d57508eb7e5cf8b9531808ac9ed053ee176a00d4d6b678f8e0c052116e4639c8ee7eaeb347200edb1d431e46fa85b438bddf756659f49ad25297bc567dd7ac8c48f35e5c613a2d4765794a9daf8daf40e4b4e8669b66294b62e6cae63e97dfcc25143c18fd02edfbd833e44f45c35816a21694ccaaca9277dd2655c8670c89ecfa61043fee73a6cdc411123de06968233c7468269ce29f937a0bc56dc7dd72945e2e873577c3d091e25a1d7de3406b2506b2466a1ad01e6826700608545ff16d99aaf8f9761a2c8c0c3f8a267f862e420fd64561761f1562fd9eea78c8a08876ab761f9d9d2b89abbf22c20b7f74f114ab4f6f01a92965cbbd65971063be820238b2c6dd137403b8db6061afee943331eb7c91afe354bd0a2aafcf2e1b0e4c7827cc9cba67afb20831dac63c34d9fd5fb209fe6c628f3c45b654f62773bcd2c56b5fd29a48a6d60b682f00692c3ad47c719462afa6f0879b667e6be3fdc71adcb240c1fede0c2a1a633c439c971f37c045ea70b21a8742c5234d2d7af1f6b4a7afbc139899190bef1eeccf50a82cf425376a6c9ad91d8915a41badb33fb04e42322a4b6ef815ee716672a51f6f2212130114fb5c1bf5c33d39cf90a6a9a0d3cb7e1a244ec3904d6ccbc16b4d8836c5bfaa42a81c3711e739bb2c4a1f78edc00aef5c86a25c20f1e0f31a106d75e6300f3237a3733f8282819f5a832359ffb1ee90b25321ae41a6c37f5ce3542121f8367d4dadfa7550aeee9bc416d3e4c1a745fd7ef5e31d0b220f515e4decad23c63a0af2dc397513d7fdd49cf75bc38280d456ff4f44a9a50e43f67de8f1e98f8215deae4e1ff0991cc18aa9e8624e916e593ffc9dc50d76758f44e1545fd4a39f5a0512827d2ca4b9dcb604481c264c5949352f94b79d2578d15d7f79352b1b950d90b438f5eeb5798fe30630d8fcdd2e9eb543c2f457308123d6acb82ca9508a77010e650576bdfbaa16a15fede3494777ecd5c7309c120441ff9e095c8e71121401f8aa2855f35a34476e0f8c6494eb058aa32319d292958422799792a100d13aac30436437773646036d79ac61d5c21c3c60afd37b5eeb7107a9eea44712a242132d3550fde04ca6eb9864485f4ae8dd85afd8eef28b2e823b18aa7dbeb6f8d8f593b28676495f3e76cc5449837ff2e7cc38623118b4731795a5c3e80a4d924b05cfba59f7deb85b98cdcaa2f7592f6e0b0a803a10a23dc2f400a53828a0cbd1a1555416982fd27bf59998465ad42770d8578ae2bfc0de6fabc754dfa69a8dfd747861338e3d821f12936a73ecb4c7b3a435086c34be6b0354f69db26c184090ee31c96c78ac682e3f9d542e572eb3e7801359889071f1080bebd162cf36a075fb52e2d56b1abf62ed4250dea898ad8667659ba21e51c754968208986dd05ae1924fc752aef93c2f19e3394a59fa6be4f90bae1a3393e5b92129118b87c4e9a85d91ad68aa2a6d8e1af13f25192c1b6c6405369e54002d0d404bd7775f3981f889ded5ac71229169d288a34d60574bbc0e02d3fd8661862b324a92f88ad74ee3c2516156f64178c9eb704def822f35296a36505c204c1d6f8d7ec1671e385106fa62cb47101d65884be5d1f8472ca073ce6b742d98e2086ff7cf38bd0abfb1982fa82d78075f94b9b7b049818b86cef0accf1e9c00277bea42e3e13febefd08b21967aafdd9b12edec9bac11fe158931850a756df515b381f7ca488ea11e7f5192aba45261374a21ef44bd42867d48b4d343404caf9d68b56609ad1a4c57bc2664fd0a02322619f61778d150cd3eed563dc441c07ae42728e62836b3657a09b43e73b9bd886bf69a39b499af07048f6d033c78319f59f49934f616c1357f4fd2d69ad91464468652fadeceeeede24b708a9088c08d1895aafd2e084736a3ead5869a873d29b74483a966e1f8c76177dbd3dcf9f8b58cf8d40c8455e456e449535f69e88f5d0a821edde88daf3e89c1363bdd9e1d9f8369e8d3fc46efb4afa130683c6d8343e65430e54062c5a9eb8c15a17d6fe8dd05ba3429f4d0634f23f0d706185bc86172397e343aff8eaab4500822008822091d37bc3e24944cf7bc35622d56d65ade66a0eafa91810f2cc057ac4f8cf82eee2355ac8ba220d807ef506fe3ef38bb581a77e89a228da404de9eb877d79465f3fecfb485f3fec48de1b78b391e2bd81355823b15b63f3ea309ebe991e187295761181f746c8a1ee843ca33bd6e1230b86e867597751837e2f348bdb237f77a12fb64746a04c06a23010f5cce108f4976f8d7a08cae887d1d783e083a00a21089a1795a1b0c8dcca3f797be8816e586f7f704d922ed3659a2a8becebad3850626bfe66cbcefc704309c97e133561a653c7500f83b1a68bdad3a537dd06ccb365c331d3062ae4f22297ba536f0fdfe5a1deeadb70683debfa614faf36c4cbab86f786a63aab2f57691b692345bfdcaaef27eb5dc48257885eb921de08e8dbf06ac3dbbda1a9acb1fbc706eba171ab66f786463f5d99d5d643a3b234567dec447dfa10d7db985356c6ca14a6655ff409831163b2f61569abeb197de287fdfc99052842902bdc50802204b1c26635342d023c337eb395644c0673a16abcbc171931b7054676055af695206bb1dde447df647d2fbe40970c44d509334dd374c46b32a66c1d8ac65d19632c1db125cde911fba2affcfbe91aab882de92b5f4cb13877048447384744a65a0682ebebcc141545105f26298aa21d614ce13c73443daa56fc6aa50aa5c8da48b78f26bc9174bdbd7d3d5ed9cf566ad7bfaa3bf912b5236a67aa8a34190cc691c516576bad5dd9d3a5b105cce9185f2e49d4e5a22f8a5aa16cb4b231cc1386d4ca86908aa295186988a2285aa1e6be56282a01fbf9ca7e3ef3c3851ca040092bd4b600e3420e5070856b0144d18b14e51aef5d1bd121d42f65dfc887b736f0e1a1beeeeb144dd4bdf4decbbdf74a39ca51144539cad34a0a5483de63a46521ed36004355eeb97aa35f2bfabb518f0fefbdef46118efe0e5957049d3dfcdeab5674685d2bfa7bf72a6dce9cabeac715d75f0b7aac286b8e754613e5e30ce96b877d1fe96b875d1f5dbe2ae9a73bd321dda156522e8c5fc883ef5e08ba40b7468fd61d76e654d31f8522026f4c928ef4c539bc4858b202ea771567e3d9aad157c5e164f4954b301fd9c0539688f59ac98d94766d5cfe5edbe5d3fbc4a00dfcc9b2ad04fe62e556026985d7dd8b2fc5d830068773c30d25252424231b56138522f9324953f4e7d2459e1df64a4ab62cc076fd730f1d7aa742edf27031be3c5c0cdbaed85e0bb76c23b2554376a3b17c6d447fda06fcabfae9abaf95941c51d841d36c9802e746172a07b1c3830f3ef82009492b21b1765a12129220820882848484a4b29a8c7de67ce69b1466ca2455483be42963320909094926d9308a6014e1eaa236c4402a8a22385d4882200982848424088e092e04e5b792cadadc4af2e5424d988b84796825d125ebba798af2df26ffde4259f3104553343d4f14e672b95ca2e812e53c5d951e456f25b97a522bc914f5dee572c138e72c49b922025fa877b9e561824548cf738d2278b8137aadc487476a4204ddc8da5b0b41d646519499264c86925e69a6c343b73193a1fbe8d0adbdfa797088b48da45f09b2361f1e826c741f1c8e80a40c49d26f04492c0ec2409566ca4cd31445534445fe81d308b9e6d53753f891241262d5203f38dcbf0701387abe77faf3589ca3287de5d8d4318fac6c5d4520403ace607db16cfc7bc97a1e1c6e11f455a5af233492be706cacafe9f9d2a9f53c3848fa62991e61a43f9bbab03823581af27d849f63c8deb0475c7b0821f809ed07879523d80e1f7695dee561de7b1c4e890f30537963658cd117096208018e33e1709e879998903f73a29e8989a2094a87d1c61e029bbb38045e7ce4514949553d496fac76a18178a1477474f867a55a7dc8d5dae44baf39cfb9b98b03b101e271263eec7aab2f1f36b4f822ad70a6290483c16030cf9ccf7c3e7c5fd57671fc8c39bb469e59e76ff487b09b67acc91b4baaa64cbdcd21e0423f6ea31f67028111cde1707cd8186b449e1d8a8b3b4d48863097902a6b32199a3226bb7879431df38b643194e5801117bf5840bc58e16c32a7c6c6bab046beb15e5c3e00317217b7960346746401f1426f32276f1ce0e22307c2c5880662a357381c1f5cd52a2a6422767d55ce595f44705eced54a553d192a1f1fbe622b3ee7e9d74a85af54ef27ebaad2c5990898731411b1f3afbe88d86faaec73b533d62bd5be54396b321486a2288a882bef693a94908a83ff4a3859644289aaaaaa88d838e45316b11e6712cd103c41b89a88a888a8aa8a0a1f88789c30032740b1526d0b3027ccc00934c834e905d5bdf6d67cb3c615254939acd000bf2a5babaf226007babd7d641f67f234a4af96675feb6279d0f334744e7f347f7a662af567da4387af90b5cf68eca10884bc3ab421befa87904ac54191b52e28c2223614fd1ddf5a9be8f736437a13e91faed610b6d6652f59cdf236c6ba73c9dcbe6dff1eccf090d18fe6f0b6521a0c74fb6a3190b5d02d86421a5f4b2d8df2eb0f5509d4f711a87edffde39e0854fa71265757db4294de8b1f59d3a14c96773fbdc3f2f6f44bfa73fcca9ace04df5fab7381a08bbe720cb1f31f4789d8d111fb0e9129625fcd331a7d15b1a3634ef535c4be47ec485fd2f331af2c22f6d59774fc9c7af665d21660791bfa83204892ac1f42aa2236b6c756f46cdde717b29515726b5d45fc10a22be8fe50696bf276fd43353db5d8df058122f6f36732e6304d1a038e5d715cefb806bc37a4771cedab52ce2ced62e47b15e6c9488755b2e225e91643e9bd012fdde34bbff7d2ef7bd2b3bc0cb8fc5e5ea468da68c211d57ae990875c2ffd1e9fde09b17499da962ebfba632f5da5499195ec8397de838f922829ba38a2b0141ddfc84ed685634fd29fe45e7d56bad3b1f56ee4c7d2ee851046d0eae03fbbbe2c495092aee2327c1046af6ff5f0127389a82f0664b718af95ebed76b91d5f7c9ec91c1301c7a13c5003643c8be7a129312f8a9beeb4cf5ffadb167f996c945edf8a7d53bb04dd1ab435f7b6b35a9b8d29912d7acac25cc5b1789b7e1e5bc26acca6eeb4dfb9049b0167d3f05ab1f4ac3dc6467d36a637f2741eae582b52e9e3e5b8bfabedf39854cd9638a57fb7068dd603b7b49eb85b7b6b5b46cd966030606b972654aac978767d6ab51042f820445b8baf51dd81ee8dabfdc563acaf18fb9d46fdc96e8deaf4d582c33d1cc7e8736c675d0f87cd604fd957742821dd69f7047297c22bd22caddd31add2e6cf0ecfd12ec6bef0dfaf187bda90779a3aace5c45a5ec65b63d606378dcd35cb3906e35515c7e0ab3d61331e7bbb561bad67b36b9b734e32bd79f315d2177327f4734ee8a273ceb9f85ccb65378be688809f921b1eb69f95524ebb9a1aa2b99a934cbbadd254ce89cd1ea22f9676216c510b8ec66997e3d15a6b1c36a3b5abb41336433ae7c48ebf6750b3b8e79e7bb45def7958b3f2d380ab4f1a0bdcdc3b14953cb5d63857c8a3bc734d9f3018b2fa45fa49fb15321232d2a08dbea68eb1e32bddf455017d72ef3de1b43b8d053d6349e7eee2c56d0dd735e817da857e11b593d65aab3d8901f51b848cc11873e65cabae2731de4ff0af07e13b848b7172e2c44948d3fc6077af6f24ef3ed61f6c2ba594b234ab134d4a6bd59cd1c92e964f7db51d1d6a3dd801a22bd5b552d58bde50ab6cc1c15c8467ee6a5574a873d25db61eacd23b8c9cbfa233dd4462a0816997999a055e914b59a918659b36bd834379a009d99d86d6a5d17a13550e85233907d91b158c52cde3afd6832db1ee30f9093af6104d65af0df70ebb61b7fb0e2f64eaca696af4ec5a6bd4a8b0e160c6bac758f22aceb1f6e0cd4734c799bc53fd38112dbd5cedf98bb36bd5d74abddeae3bf8c349818f2b1567d7da5ea52c6d53bd99978fe738949caba0d5aebf56aa1d1d5fbfde96f59d08aadfc1559b3ebeb72b246b48d676f0f8c8348c0fa4fdf36a2d92fd3894475e1aa590b22d1ad552321f4da2b6658b1b838c697a41d8b130b22dda9b2c0ae6836531dbd9ebafc982ec78e8979a55f96b6acbf25a8334fb21311fad5d120b82af0dd97e259592a69204a9add0ad01556bad6dcebafc59d3a515551c932c0ac62e96c7de8123ec4714e98be559db6458f683c1609fecf1ecc7150fb1b48b49b1218ce9c5a4d8f1d1ea8b41f683be6af68345d1643c35204929a5ec478ed6729b0402176cbba567b173d8cf153d9062f7c0895d37fbf33c43208826234ee8d27c749193ce492b9cbcac420e2925fc95bfd0592d95c066b8c3ce7d6557dbf592bedabe97c46243c6e09d639a39ddb9af87fb829ab2082f59dcb20afb72cfb1a1d5e2293b954d9037ae66236569fb4a7d492c76fc331f04e4cb4b2da56459d8bf1e1ff14ed2065478a92f06f5a69e3e36801dea8b077678a30a69054bdbf092586c9aaf0de95047f70685129558d25f292548edad01d50be3aed6b32f7c65d7821bde311897b462cbc76b837d3e5af062ad4adfac4956d14ae2f520be9e24ecf7c862534a2defa51224162231d090af950e650d90bf64677a335f1f9f7c5c59b155e7c0817cc543ef5c7d31796fd8cde8beef1e5bf3c1e16aabaf270a9bc5492554e0d06515f1d680a8f5c03dad67c73d31b0e1a5810d0f377c7bf250a36e3c70bb78a156c6d82184ce08b79f531f44b10fb09f2b7a60861ff0903e08b205b09f2b7cd0434a8b6a25cf74cc297dd9b7ab7eca4f9694bfb85356b5a53cc6cace44e247a7ac9c237cf5b3fa8251eb0e14a966697be62aaa200822d803d8cf153d64ccce15ef9ee3c557df6b94d7dbf86d5ea5b9264e5d546b542bbdd581a228a2b7d12d3d4bdbb6630f45573ea3b0b1cb19c330911a9d9e1d932f4cd3c8306b92bea05f19b76df5a4ae0906836aa9af9d9b648175b1f758f02cedf56a1affb1aedcb6657bb647f8c836b63a46e0d82aad19e17694aff562fa7a9b5d79b7e0c8b1d9b18ef8dac066f1ce059df76733eb723bd61acfaccb47fce554b0af7696b68d709bb9b7f159dae5746cf8cbe9e881077850851f00d927fbb9e207516c287c40865dddc507820a76c97eaef841bc35f0d9b51615030d99056ec9d2f03d7c74fc8ba5bd6ba313f5753b49d4638b97acb9a54f9fbf58d48c348687e227eb71f16a16b86d03b2f594bac31e0fdfd963dd4f5fecaee5802db84d1454f78784caccc7bc942fb090af9496e2aaaab61757c89d77b82fb62fd7048321ab91476af878a0a32485074cec761d74d084dd1ec4153bd8e2ba26180cf876a57e188ccb31f1341f3dbcfdb46b82c160577167a88f436102095a40c3a1d4c00a1e8481c6f3c7aa8f43693934341a6304a820904f2247122dcf92521ac08727a594524a29a58cfa790c20e57befbdf75e7cefbdf7de8b524a29a594504a29a594f24929a594523e8774524a29a5942f3713c69a4d41653c986c7b111854c8cfa53f7fc04303de1afa9a6dfae403467700731c2d3430aff12ac01d7f13fdeacd7ddc44ba87921d3dd2efa164db5bfd120675c708faeb61feec791f309827d14203a393a03e696d043dbc845eb428498300f3247224d1323bc0d240a306cf3d576c768c85c1606ae01e2b089083ec5040a0a191040ecc344dd3344d13354dd3344dd33f904263d2496800093f38010f7e74610551d0a07e79123992b840902040f1851518010662a0313d074627216130180c0683f9075268607412d35b3b65e5c7847d32610db6444dbac18811f1f6f62a8d06c4aebc7db8ba03f7385a68dcd7f65ee32f790bb81d830cdccfbf7b9f440b8dab93886ee5e7c397961131c01a04f749586badb5d6dadf7bff81141af739aeb6d6da4f67f20eedbdf7de6badb58f36c9c301f5712835a000102c0d349ee6616e074465a72a68d58343bb880e9e984e5c618311582e04f57165789812d94a40091d3ad0b19f2b70f0c4cefbb902073a2a00b6c85749c00e4dc653ff62bca83d623deccdd74a6685e8d34a281d99d6f55a762b919ba82d7c2e08d15d4692a43f4daadeacea92f55a6badfd10019187bc86483967c8a4555629a7a5b9b46293b90d8f0d8f7b777bdaa868f37ad2d94b248b77c7dc8e1d9b1d328afdd8d082191c4383f1bdf7627c30be182ec66e31468b6a25f1b3de5a2fbe93939393ca5e1020942c0894b24909250be258107dc5c8e29c9914d75a9149d171ef312976fbc17ee416352885375d7c76b2d93102c7332334e7d9b5542b11f9ac7ee5adb97cbdee45b48a33697a565a37898a9eb98a6e8f157b1ed31e22ec791da4cf5bfda479acf1237d553970204b1de33eda79fa3147dd4fd88ca93becf9e91306c3619ac422c8d3a4a394d24e34297511931263d3c449b19363196ac1c1880031881d623d905482a474ba2325c4a49b2e526fa2438f18929747790b2fcea66c959c0b1445517b8c9205c906630666a68820ce3a6caa297d8ab516a210f422cda6801e0f3128d21ccbe4d42e3d5ad54193801d18d064d0c738bbe35c28875b70341f0d086c02760f1eb7632ba0c48d0b6c467478db94f713c32a361c41614c38f767eac8b1161c2d36d8844ed4646bcd873b83563419c12a5a6badbde98bb55766736b21228f2dba9387bf26f7cc999dc3bf77bfa61eae6e5c70d625350bdc38087b3c47e5d2a34909ab6887d1bdc1a6cc45c3cbc17d71afac075f1b0d724c384ab3200dd6a015638c23ddb8e0a08b589a8758156b3eb2435169d9e5ccf1a1c9b0d087782ab2aa1c94d1af79f9cb5e628c71548f7f59cd85399db3f8f571ce9cabaa52cd02370c8231c658be05d9928917455571815e046b7ac8caad04bfd254e8b2617ddd33f15a901d1b17d88c0ac5d3a706658d0b97e6420b21259b51e82fa82673ad145248d1a9d59c4d0a1b6765a7a8187e0d790bc14f476bba62ddc1af6f315a70c478d6b1cfb163c3734a5b491c999610426831c3f8e921de36ebb629a6ded4cfcb181fe35914f12c6e1be53ca5218fba136f4366c83117295e7e362632676350244443d87a768c3b622bc66a65a4972ffe2c1767967c6541545e938117c24f081d840fc26b5e77e2b1958f7b12eb4efcc4f336626dadb511cf472af6d41b7a7b090f21bcbcb572e00004fd85f538937a17d6e3743c1c021f628835b4faaa1014638c31d288040f1cc96e1817b9e9dc2664081d88f0504d4604e39c73ce39e79c0b71cd3df7dc8b21f25841041d4486b09048e4369aa5bdc839b769cdb9fc13e74264e336ce422ee6759b288a44acfb900635194c8ff738a6f3d0848fb16b8dde498c288aa24863039a12633f0e45537203079f59984a2aa9a492a5b51c9452f946df2e97f5d2ab34395188460d7a24cf9e759597519df274cad359e59cf2866da7fa0b9fce5bca208d29a59432a919bde82af5067afd94f252bed13b267493d467c597d64ae90ba594ca8bad15ba356cbd1024a5945242f8d392ceaafe2ccda19579b430a7d6fc64d9ab384671f3d14a66130caad71d7908dfe09a6033a624fd7128313b147849cb4b5fa56ba25a40d867fd3cb32cab3456c6cacee446f3d135716fdf7cd8bf5bc33a1d1246292d69bd0dd1295f0b6e130ad87cc2f160b136685547efbd17df4b2ffd84f78c7eb6cb13b8b1df7a35fdd65a6badb516c1065f83afc1d7a6141d093a0827149149d2e17c225e389fd81182208869e79873cc39e61c738e39c79c6357771ac4601458648c31c61893e06d3c703567ce55f53bce6e53477d1d846f8fdd3b9fb8f3092641f9c6c3dd550f8a4bd957e3d178341e9a8bc6da35b6b95cec9070e190d88868f7215cd6b8c33653b08e524eda5a9b928e0c467cb065f8f4787ab81adf8d2e342fa594524a29a43bf075361b9fd67ceca6ab889b96947038292917c60dff92120e278525561d198c3bf76d3c7c38d6b468415252389c9292bfaa328ffd1e2184556cc91277fdc512e70361153bdecf997355fdb7474a4c89913911a66b50a926c3be98d98cfae7f8514d869d10c28e7c1a84f36f9240c9e65fd31d76f887bdf7debbe13512285e88cd807eb130c6589ceff88ee2c8604c078f1dacb1ea88457cf39055232a32c6586433186b2ccec8d8646133c647cbae16f2eff5f90ead472342ab027a43e2d55369c54785cbce5a9120f61b1d760385642d74d4a195a4c3cb9974619031c618638c3128b95f1b375058271264a363e30267ddb4d9016fcfd236b41b1e3b3e449833e7aafa4b52645c2012cee45d5afa66252b9205122e2585c32929f9ab2a67b6d9416996b61dd49b7bfaf8a81009b2d121adbd461e7f6d786c9a232a3243e66c727eb3e36c44531d26a594253f7b5962b4a46475ce39ab373b248c3e59b75ab43524f6fb15b71009d28810b74062072c2288c47e2f6ec1e6a59472b363a5511145b2909708174402e551e14cdeb5a822888f942870b028a9625fafc77e32070ee4954645a302ba10936c8b2dcda04285434949e1704a4a7ef7a8707abee3ab2f912c76b49b1d2241a894526e763018f185b01abe30f29e9287e4fae73aa834abfe09a9208d6bc1c1a4e8dce9dc64536cdcc81cd157db8c0978dd1309a99c4a0b0e169f0b1c93e2a9c03d1db23d1d3b9ea56977d9cd1e4a9d66021209a9d814d0a26288179f6a3885c930299e0ef95a4746e419132e6c0f5b837ea1617b3132d90b179a83a591cbd91453b329aa73ceb129a4a89bf60a2347445f7387e82b431acd615394945c241c5d2cef416c0a1910427db1bcf71e156c0a46c5100ee54ad8f0ebd6afac6dd0acc7f59c967edc7bfa711763e23dc97a5c46059b824d81c548db64c1ec2b01aafc8cc760bc0959ee8fcdc0e181f1fe8ec37ebfdaa69c85025b7ba178feb23ca28b852ec820841042811b752e6014e337c783feb23c76bc8b287596b633c626c614fe41c0fd84a0852e1f317ad25775511e193fa234465f34d5994b06535d44c368d1f465d2273524044108eb130623d6960fb9d94a529a0ca99ee3507ca8a8beaa063992be28a594626b4b76c55ab11863b794520a4f9816586881851658d8c8daf6d78a75c57834af0dfb0e96f64568a1c58ab5e9af16b6461e1b6ab930912148af8e6414cc3db3aa9b734a684ee7e284626b9074403873c5b6895b6bc1d11e617b645aec0bcee7d88d3d4ab8165df02221d6f398549a1b643fa7a6870cfbd19988afc707fbd3f18f9e1782cda8ba033d4a794877d8744250c79eb1180d4623e4b3d2588f73191b92fa903953c239e7524a7674cec9471da295c29c73ce092184eb214414b1e5d22e5b8041b019d6ea1b0f4a286b406b454c08f6f8604108f1219a0cf827a17b0f5f88a763201d5b3190a88e16dbd9f2400d64cb01be46106ef1b47059b4206c3f0d83d043b41278d1c740c3d3d7e3435ef1ede1b8a721485f9c16ffb6d31d88deea2684106cc6a33bf6f48c6a21180cd689510bc160a8b4272b449fcdae8d79f80a2d895d05cc98a145afe22cd54c741482c18012c2e7ac0a9a0f1d3798155d134c321d55b826628cb001714d5016a37199a47c7db826d8a18746c458b399c46bacaa99c467d82b2b5f634dcf5ca8338a1323458756d2242bbb2668cb6dd5033822c394520a5d46b642b1da48b7203af67369c52763902643aab8776be043169641a87cf12d089494c669e311cec4c57ba3eea88f8034d552b3fd768abbbada353f0860db49f3929533d6b32b041c4ae62e67493f4fccfa796246b3f380667864705b342de283ba05692551fe6a41e02fd9824c52fb110e25332532ec2a13615ee133d6f39840cad291a49fc704ebc3f66c93ba63b57cd3b107a9238301e908a9858043799ee789c2f344e1791ef634878d6069d8f2d19a56a20073b105893c6e9b967082a345f7de1af70f8e9131ce5674316e325e8cf85e1786dc8170c6d873ba19e7e5a15646d9b4d86632da687b4acbd25986fad40707902522204b30c6d8c49f40b0be31adf82c01c409bd049b0cc8648c2d719790d82d2a9f1dcac489168464785b382d5a166c47cd80b412c880c44778a13f57fef47bf3ef2f93cef70fd2d78a95f44f3e9a7f1bd21d0afdd123b8e1d51d7c08929dc980445be7e12b5ca1f67c8c314e80da9d78faea6c965ef545ed782df9fc80cba5cb64d96612e5ebb317ebcec48441871ead8bda7643d0dcf135f2f3a66d258cb5b3035902c81240965882735b4642764e504ae9bd114f9c134d06cba756668c9d3827d88915f5614840aeea2be31ab996e82c7ce2b9c0f1682a607b72229ef8535fce0905b0fa36e79c1b3d33733ec4821a8c9da7d6753fbfb14442a8beb20e1b5e74b372e0c0253dd94607fe69ac599e1d7587bef6d0e076f364b2fd7ccf6f3e43ae6acfca7a9a4926d9ce461b7488e983bd29d1aa9649767c55e5ac8402e82b4ac54d6bce997355b5b9dbd4272c8a0b149e27b216b7650d7916c58cf48d69451f3f823419f351c5b95b033fb230842cc8b41ec84395f6712893743129d88f1a103e2ae09e5d5aecd18274b6188debdc5f5f802177e6e176a76287ece78a20a860d766739371a799a51c94872cfa6c834e6b5aec2a803e3a1c832c258d7ccbdd470bbad63c49c90dec2e424b4bf683c18087134232c85555fd55538a5c55f92f4f28aaf9448cd2ab9cab5c5dc555f792d5c1555549d5a52b495596aa1b27ea124d32579f1ef52e6fba8f5e0c799a0c86ba4c5148d657052afd342ff3308f7a97373de93ed231c6c860401fd0071c13d1a96062d2ab939dec64273be569724c4439a2f2af8b0e18197b76289ab3a9d2643091c4281cb14b39724db8265c134f6af207b6d64ed05a8ca79d62ecf72b468d3e59576ec1f1709e1e519ea2e951c639eb2bc6b6f9e1931329638bc4e2115a706c74c88d0b2468312d3844826c7460f2e51e7339e662aed272267afe453dba179198e8517425912ca20c864539badfecd8ecd8ecd8ec683da412248557472d38ee2f9773ee2f3c3a39f68d978bbcd6e574cc0b853250dafb9b7fb1aebc5b70449728bacf17e972c997e76b8493f2f12f18e91775a3e685541a195dae7921af7a1a7dc5d8f7534663f649ca913e6133a01306e3da0ae92b9ecef9326c32d1038bcd4ab09f2b80d003e87aacc693fd344dd334d94f9d1cdb426661ac555c94d3cc2f567beba6099ff9b84e599dfb678a5ea7c99e9a4e594c5da545f77ec25c97639bd11ceb48fd627938c32272618c66699b62f99215614bd90f06c3da1eeaa6fa829f9b76a9d98fa9c91e77ceb90b39f9724e3827e86dc161cf713c2ece37ff5e7cf12fe931a8278389a87c2a83a1f415634397c7267b6f84efc9c9c989bcc239e72628a185b779b363b3637ace50863294a1cd64756abed63e67e853fe045d667f7f49b7d045e2f4cb5a0d45f632d55f52b6d7eacd8ecd8ecd8ecd8e9689c91090bcce25ff9e6333eb82f05eccbc480e1c880c06740883811806621888612086b98ac340c756a7622c06031d638e217cef3157699833e8416111e6193f826e65e66114bbb089492cb3885996b9ea9f465df4c45cd691be38186aeed58a0c0644d9e9105a6b4d6af7ecc70fa905078b82f9906c442f4597ec542bbd48ab9f0e857ad5178b88149dbe9efa45dfbb899efd603fd80ff6436af10cb0b5d63827272d381eced323e23089d5fc5e959865d9c9c949d339b3e801179d73ce59f9502925a5929e4379484872d80ce974cc7925b489b1dd4624e45265268c464a8d7c06237f99e474f9262965e89e9c5439d3a8102ebcf7b228ee998fcbb68835c676efbdf7be77edbbb3fe41d1e373c41a3ecee45688eaf8a3cab7c927b887bad347e543e97b2d389e674a4129a58e4e289ee7a18726fbff6bfd9f688d32d2bd6032bef47dca44174cbeb4a272959172fea45fc344652a91911201040000243668cbd2afe1858b918d4848a5c960a8cb24e5085fab211a6395dfae14ae8bce39e9de9a6c8f31e6d8068a0efcb3d9d39a48908d0ef72494325eda4711f9daf4c5e875f5deb7d786df6ef41ce176ada690aeb2dca2b6d6ece4d0161c94439f1e10a52da6504a29a5a716b255b3b4194f4eaa1c73501f92e7714f8e51c6bf28677ca27c424a8919425fd1a13f525ff7b447f3c190a0b2be4ab0be38565f291a2ba18f2d8fd1178b028c02c4624bea972a6cb8fef3a09000e09a3f0f4a001ef2e741114089c96bb06e623d8f4989f53c2602b09ec7240016002c12cb06eb792243426b4b5f4f8f2d7f7da5bcd01787b3a588fe969a8ca42e52923247158a5bd65921c8c51823b35a0d22a3d8f26d78d8ac84a8442dda67357468040000009315000030100a858342f1784498e4dadd01140012829a4a6e549608d4280a620a21638c010246440000000064340100212dd91f2871efb40445a5a50e7d40ab9f9c3a9621a5dc0d18b915a418a7e35b30409a17004c36b880ff37a612f9fe95aa9704470a5afcad7dadb9ce4dd7f3bf93a43027689bdaf0f94de5947e8d2f1e4c60753e77c507cdd9cba66ea0f7829a1fe588123ea597b40d352b01a01378725f0998321c34f41b384743675e39f4b62d7715e0fbe6e1826275ee4d913de234690522234e712b86b570f85c9838ae4dad6ed9e22ca49538ed87954428ea875a2b7947fd01e5cf12f7b81b847ddaa8698ae29490faae8cab026ac75bc48ad34132b8c1cabb562f71ea4d896f2a8862f28d6b4a03b3162c88c65e9e89a9bfffd2bd5d7d8290198cc7ce6d64798e6cdca03aba779365897245d8578b8ab4e717e96e7c324d4c163865a069e4afa8e357c1af98eed5a4590cdbc41bd24514d203ea2cc0fbaa0d41179fe02174e929d75b2f22e03962d0e994b7b7904136a01574530a191cc00fe611638d0bd9a96fe1d3ec2f929b36135cbc61a3bcc77c3ed0f96cc5f9c380c77c8edfd6ab81c037cf37272ec68d90d2974c7711ec5ad3c5e8c9f0a98b2a496484008c967b9df52eb08555fc62503fc4282ed66544f03a02a2d90f5b064335d2386e026820e8340925e5ebe4d48e0a34f936ea09bc7579ae61635ae3d2274ac8274a61a62814747cccf8e094fb0d90e06c821820b0a7acc4c811a603339ae5a52b420a2e1fb917822a94919c0cbc13041c5e60db6fb24fb4ab5a339ec84ae8eb8c913595eb8b3cd1d4e206fe2e0d04f93ff0b95308bcd9137cf29ad736e8d1db7390b323d0d2134d08d181f1a2ed7023c74c71f07ebf9cac6a07fdcb88430dd1775698ec940a6c75671a7819c85d6d47417bb5fe7421d737da1dab09d8d809015849ea87273fa475e599f38b01be9323b1b888b836df938c9eeab0a0cface8b3ae546951f4fbadbd3ab6c53feac931d3b70c6f495a4f1248a6e881e2b399c5bfd83e7d3a3d73d1ff95b0735c61d1bc4f8cd675cb2e929ddcb711127f9d50587635fae128e83a9ab780c4d566b3562dd461229d4e3aabeb54544ee0189472f02c985d59a7768801c7ea3ac99b8e9b71075c3e19b9916f15f6060897b94214cde3c7a154548a708a7a12e9f3c157a127b0e6c9585459ae3c842141400e33cb455c3c9a90501afbe1a614e554573534a85f5eb4831c10bfce6a63e89cd3e9d604cf3419fb0c4fc704b481237ad24af5529fccb369143f8a7f2e5853bac1f26fe71e686888e2d4e8222eedd0b93c17d4bc77782e709fced9d6aa0a4ff7ee7e5230ed6e6a4b95d838ccc354d62ad334289522c6d776931d3954604f9d429597a2d13d75bd8abfbba39f5774525bf9d606bf3119b416a8662055917bb20b4032895f0685c1e7c09455871d852b9a7b79504f0864024d5beb3608eeb90b7b27c28b5307e9974c7e04430b837bdb56b8c915d87b255d0cebcde5b8560f1e7af8f722099f337b27b74160beafa7f32bb352c2063bd19bb9698b779439c4dea63510f8986528bf14f12665b6d63d88832600b117615fd132a806e59ea6bf55b40537478871b7f82cc62c84bb25601a901adf6e537b3efa2a1ae96c74036a915600d6ba8d4267ec0c00d17db048b01c913d0b557d37ff8685489924c059d05f7e3345814ca8f447e1d1f60028d653dd6e45f3a70c200b68bc06776e9641ce3ef7a0a158d90b167784427313781e956bd5c35feee82222c3ef49dc566b34853f16912aef380ae406fcf4d1cc41e412934c3dd426ac958ccff108c7b3d328301fc1118d1975bce4aa7f710a6e013cb32e02e2061d9b656d992408c1f93760f33149c89c60743e641300344e7eceb86a8b7c4c061a7192c7efcec644c0cea969209492db322d8c27f4d5da07cb95f72b0e5701719fc7039ca462c19d8bd5f41cd3294ba70abef429e992b0cb8558ac92ec7203adb7dd9eb11d54c0637c6bfddeec9430a4406847f63b8e4fcdd2e49ee9a89624c7b822a5d6890da80fb3635262738b83a7be594a70dd484ac12a809960bcb130f354145c62db955f57111c8d2082794db9e8e87df3165b89e77b0b9258ca30f7eb6f6ace7140b554dabcd8edca58bb47e49b361f222df628cdb25f9a0b35ad103a6d4ca384805a7c1f726155b9a5950eabb451c4cedf512b7db6c8f7a3865446170eee47571f45b4efeadda281774bc54da540734cb24c46f7efcce25926c36b76b35ad214a8dac3d9a1437453aac881580711ba0f70ae93681cd83c03254725c26061d30dff3783657f4e7abe4275c8f97335fe615ff236d0ea892430ec22646af2925e3962a55116fa922ead79e6576a77e14dc86c7fcf7af8d4aebb8eebd68121e095a1b3eb40ba96ffe02829238458111bd593f13a5eda5b8e80d1ddc1ce6ab654bb64db26a23c4049059b3142a066d15ffaf1ec96fb2674e42fdad3a7debf820100a18627138dd52328dc85e16773e32cdfaf306194e55c8f6b4008a70e3d94365fe4fd10d83be46c6b12843424d50b9c0e6eff241f1f32b8429d70b30a6361df388f88177e4fe4b97217f3fde1fb8a4209b59ddd8878242ac63dd2c99a6cad44ff2fdcbf4b7dda6e272e409e79678eb99d317023a487eda09b43f358d871b1da41448380e76a88e07fae1069c6de95e70e000336880df405399f1a7c10beb75e7103901772d4052c551a7ee9326fb541fe2206e9605546671e627727add9c7dd7cfd87ed7d00a1afc8397afa9aaa2594fc787ad3a503e48d44d0074a0b277068184645aa544a105be7866c9a23f73b33f949704b106b2266012252bc197fba74c61bdab140203d5c85207d3355e71971f941453aff6cbfc4ce1c0b288277709eac6b7a6e7c605c3445d7ec0ae7673cd1a5989848a023191bf4d5686754a1c1d7b2ec68d08cc97516d13aa00db84845bfc48e8b05e2da1bae4a0c8b12f69347c64b21477782b3a03191a5563647509612998dea7f8bf98c0904c464111a0a6258c93a5f2ad53128023136fff830695bbaeb6454047687fe834c68ce43a7e14ae93443b3082f9888c182797439079c468fab565da236d4589e18531798a778f031734a208a19271d4dd3599c951fb7e8ea88cea31c8713d861d4f69ab69a28683ff057b9297cb9fbe0225dfa59184960c7366bd74ba1eef1ca027c9f63087588fe308598d203f80178fbf2415720368299ffed94899871b4618eb2c181cb69bd8e0ac5657a7bb8251d1db420b1d28cbe08c7ba1c9fdfed9f856e737e5d038433154ba94a2fd91df0d36f74be6bfa9df8ed1d1c1060172f7712218cb1616e27e678e7dcd92b55717e670457c1b9c143b866885fe1091051e3bd6c391360b655111023f8ad154a395ee4de906a7a88a7623730b475ba8bf9a6701aa56738a24e625c16c5355e98ee076c100e1555444586d62318659367e4200eb8684bb064510161206b4a300ea53709390c4a90b2c9318f72b87257a8c7254474de6033f646ecb3367441929ced57bf4789cd5053db486388d2d0c4e9fdcd3eca2941c4369d4a5012e706940b3db66fd6d51b88fe671d03063e14d895aa7959731cdd9ceddafbb58a3dd32d16e1f9026aa02dd23b53fc7d2eaf57bb4a7817d203c66a69473a2a69fd27062eae68ac4040920756fe68baae622eb038cdbe93ca5c48346fac22c43980088103f9ef45a976520e2a8e4c66ddbf3dd08e172c016ac5650d5db05ca7554a6b5ce92287a0d702b971b9bc6bcdbbd679d70764233161a7d026afed9ad4b79992f550be69b0d8e2e46f7333f3dd28924f373f81e8420de1ac27e330e62000300a55c6b7b5c8bbec682bbcdcb8dc12a0c8e7b9431f6908c64b6b2377bd311ae274ce54ee22f596c33c34f3c49db8bec07fdb090993d8338496fbef7f843c0538c5ed724ff6c4b227e83a7e5611121d80380a4bbbb469f654149d384d5174a9b53940bb1a2572737f6b87f900d33c70f149790a0846633d4d9a704cd0c497b26ca935394a79ef87f46ebba7c7e208432e82449bd60f1e4589a814353ed046571ba774fd041369ad0eef92c138a02d36c56de78d8d923e524c0133e9ffed9757f4a25606cd51ce54e67c0b0b41a26612898e38af9c9c517fa4bcc5a2eb4c892b623ab3a05b6dbdd4aca5f40a89ea408f8ceb45322bd1b126255b68fc8c9a3f5252f239f205730839a3e904f1fc92e21a3f82d21cc852e307a3f66b169bad118a59d752b85ffc85b7cb3d4973d9da1c84cb31771409bba0e42c7710a9849ab010ad37e23bce2c9726d02547e1f69b205f729e0886494142159f8148e3dcc2a3f4fb082a6d04172f77a7cb9ac9653a08acae43acbef92d0cff5b1e10d38c54bb589b7ba37529515a7c2aeb32507e19fd3ac67fdf9eaff0420d83d51bae150bee0eeac2bdfe06bd586060212cc3bf6b23e505f399380fc2f1181e9783f2f6ec1c030dbfdb6a878752b9b68816e99c88119f1aaa3b36fbb4092facaf9c7d5985a64700b00c9d067fc937d967465e3b5c47430dfd1cfca8bc3e12be1330c8974902f64b498bcdc688f2622a3e36f6cbe291cec393b0afa4802b8af920e491010e9a0126fc42b45e199be63c70b627dcc60c3dfa9f3c144a9748fc4630121aaa0bce818a178f2f6d8d2538681aaf382f8b9bb31589f25a88b5f4c54d3938f57bfe196ea99a631613abdb784aa24d1a996603f148078c4c2a62f12aca529518687a074a342a20161e86e89fcf2a84a3c4df302d6e492453016c77c765828dac36a7a26df925c1f48770a7249bb1568b3da1d8c40a2603f253f2f17b8f7aab515cd9b58448bed3dcf6d670b28e5a2eaee2688fe840ae59e6a4a96d61402dc63825c63741242d870654c45d450dfe1887751713602f002f9761116582248c9fff057e3f6cad673d92ad038090593a00657b344565acdbe7491d4eb9400090bbe42da30936209c3035339987e3e5163cd7c748886f6a1a27af116a6bd58b55154200a296ea7b670b25edf3cb7de32580eb9db5511b1ffaf72b2478e3f58f4dd1985a6b63d2fc4bd22cd24e886ff6846bc724803cd876f3767bab01f155e7d85e3d78e77de3c6a4aa5f85eea76824b6aba27276c38e73633df2280cc497087a85a686ca8bc29b7e8d8bfb4bd6f0af20790f21df5746e2fa6a1fc5001be6e1e8cdbf2f7c6800512c3772ebf025be77ab8bbb13569eda77f17e0fdc11d81dedc03a819ace8aad3bfbd03f2dbf5b0dc0824e9f8b752e7a7acf48a14b5a25abb94fcc783da012e76c19711dcfbd106f0ead63aed77e6a1ff0813314cca4c616f4fa7e0fd2e0b98cf6ff1ee8861223bc4f739d0366198887f4c600b099f4ade1fd9cfad18ce23d921ea8077459f70211b314cca3782698ac6bbb8fd658a4fcc6653359a86e16381d1336f1bd95bffa65499073de28671588bef6ee4caa62f58c25cae42ee25d89559edbbe18538646cd17f5adc201d8a2390b942ca53ca75c533b52205457208d1de14ca81fc4f8cfcd618c110c07749c42412d3ab96c742d04958f7b0abad2d622c92d8dd3a1953d78c1d2216aea0adde641cadc097399c771e6be7c904d1c0723b2724522c2e1f2919d4c1620573a397d8e128d2bfcec57e7dbc4ae3d0e1c782b7fafae0f2ac123dfeb8b75fd086535dd1ede96ecdae77462e89f81cb631a3a2f758fed4ccab444813f65c7e93071d7739ae615668683e5435ae258db20a6923007b4465875ba6766e0f8d918dcb55d8024160c529bfe63b854e0b6e05069346877240cc070a0fb4ad47168138628b7dd5dc480b460e460220f94db4c29ef649675929a5a118dd85a40b9c08936ad8674f111e1ac86a9dcfa5d2c89e340baea475c22a3468b3223f527bfaea7a5066b656b4a7a00e3b0900708516bd0f0737ed857e9901e57c66eb04e1e92e2da5127a8183ce33335547e70a4945e97549ccdf25f09afa3f9a7ff6e61d7e0d7bbc13837d58a1d8fd17e728062fb843963df924c2656338923997c1dc1c97664a2d5a1efd19426b27e8ad0dfbdc49cb91a2d653e6dcc57ffb856ff66ef4349da5530fc3ad8701e4fd45f6829fdb29ad2ee7fab72cb877afe72f519f8fdff0c3e4819e5fdc0c69b4ef55ffb3ec643c891cd052bd1e7227d6b5d8afba31598e1e1002b7f46fa1e6090190b67238556c6a00365690c836b52c4225f4692c2afc1ef9a9a79a5729df72adb9a8d8d360a1173a238f0b81f0cee0bed55bde85acec05b42740c687dcf3a509f4c78be689aaa6118a7f5f83d5ccd81237e3f7fa64cc4ed9110e6be5db605f10916cdd36921d1e8581ea16fafa33e376dcfbe0f0b2dfe36dda2fd92338367f18fe27b5ca708752897a1fb0d3d65e6fb8b0e7472639b704815430767aae22bee4e065365801b3ef3c6bf5b46e0538abd0f4da1c30e4208b9a940ebbe4352a2065084b4d517aa329674aca15749bf4be902369db5571c1b27576c129ced957ac235257d129bde471f98ccaa6f85e41944d9be3e710ba573d776e79c10a87f14eceb619ebce7ecd8a04099a742e1f79f7b9abc1922a83e67b75c5e6cb4c49ace1133e7dfdf35f6f40d6212aa35687d0dcae93f67f85a30fbc650090bb6c700707c7c61db6d2b5df67776e2c863bcb1b20b1c2055bf1af0713503109f1d90986fc6d218d11a14abca1267bc3abd68afb831accb63fc456a9c3339567bcc8903f9fcab8063fc700c890df20f16938f666e330ba33c47cc3490dbf611f2911b3f53e92df41f6cf85bf09e8bf9efc3c496410c7118d910f44bb6e485473701247cae0c77e18c11872e0dc2f014cdf08892288ac7f866c82ee37e045e1b6953ebab4bd6af615325050c5d85aaaf131257385141f609bf8a1704f5027319ebe044bbd1288043dc381fe876d09fa36f42f8e6d9e30e11e0e5512f725f936bd99a2846c935843040207299c80c94d1994b662d329de56033e6886e5bebccad7c23d862082b91a9e98213911d0b4c29aed3c959564af0f8e8f45cc613cd01451729a3979d067a2c5476ca22d9bb81c41a3a00ca2b97016ed0f052f28ff085a62c42e3ca325a8648d603374c6f826a9e9da88794780d43ab1ca467e74883e099d27d752a38550be2c002809dd38c6c0c71e063024d7ae904e13683577ff082e356a61f6fa4eb97e86442fe03c0192feb63300b79c08132145e85e165f60b9a4e288c7868ff64d0befd82ac7cc4e10444d279bd508ea38fcd19ec7708bfe5c6620cf2f39d430c21b31d5de761f3165fe74173231d282bde9f06f7375510cf682e4435258580a9c7c0010f46efea29e09a4a7e9a0570e3424bd4fccb738032cbc3c6e6e2afd92e6346c472636c9c81a162a68a4b896f1858759eefa9194ef62d9f697de5c39cd028b800a8cbc0200fb3c693f7dde5d4e8c56c08661f62f8e0cc6be6304a670a7a79c34435bc70d14268d0bb9659782853d7e67a911661aec89bfdc67d9fecbac7c1b56d2ddbd5f54025785cbb7eb1b47fd9d5a089b73ab4a97d57e4b9283062cd6e8c1c8c70266bdacf665db6fda79645fea384fe74e754548b12bbaef3f6614d9dcf9849c15a0dc3408420c502934378221a8a8ca196def96b211710519636c5ae3cdd4afefefbdca456afd590fdc0af6cd7fe1774e0c97ba72556b7fe103b8065187becd103cb862f9db90d969b09836d61b9e67fc70fcb1b333872987b919b83caa1543a6063f93921356f8e65eb63d91d0d6360b27d4196756d6f1125d348fd4a0473b6047318b74ee1959e1d7dd24b5ed52898491edaa99ca369a53e4529984d48301383b95a69307bee60869a9a132cb558207b1f9f6818aec4a7634a42da8133b00d5a929c4d544ac81ba05992adea2e42443e05f691dbd5c1e9eb81af1734e8d3566650e96767d190e162266c50600aee7899ec4fe0139d69624e39fe0e3ecca637a597211fae73d806dd79928df4ac53448c59ee2d6a425dccee9cba7b413316deb5c74f84d9860aacb05803ec58b98fc64fb3aad7ab10fd27733032892452a97766674b234862e6e16425048df6832918928335bdefc783a55f1a2f82426ad39b44f77be47d68a0c9ca0a5e4adc589b686cd31ca8c56425b6d18fb3158b280da591766cd56b32978d8366cd0532b1cf70e84c5e5c5fce0b417af7e1a6e3a8ff7106c237755499923806c56a53586835ded30df2773fd682bac9d21416c5fd0898df5b2cbde8042bdc4d0f1b047a5a7c0c2f75099003d7146ef37ba9501acece34c376541f31cf15eac8bcc0c02bac434be1f1f436198c453d3171e569a2d6fe04fc95f377c81700e321c3df76cbf5aa7da108cb97a37238d844ffa635ab865a05fe94cedbd59546bc6bb816dc3ca1609059cce555739090b19532c118d34f9477df572d02dda2c405832cc710c823cf7eb33cd90cb226fb19fcef0b0d8a320c2f48b06e473e40b6c49665de8f7480d9f51e2c796fad1c1191227f7c672e92bc7743b80ac71d4fb91e029d71bf50e931402feda29868a072c3049ef6ce5e154ba312059389c5e578d0ce0e53fa47ca1f71b93ea10798e99eb423be3e92ada7af73cc72ab506cfa6d949d999b30ace5ee9d38f2ac0e7c8b0500132cb99d3d6d5ccc556e5328d8b815e4b25a37d95e5876c0e9fb422a8552afbc501ea3eea2286049d6ee49ef1b4e4a1e7a3b4fecda930bb5091aa546228160c3d045b3a9bc6b6c800ae5b197249c9429428ae56708349422301825bb3140fd3426603346bd3d25ad423ed083a04d201697d581f6184787f03b1d138c66e6b688d3069f7a6395ca060c9aef326b6a2669f5261e33893f29c355fefe110a3888fe3b2ed16e2a0017b7454e106edc624d2d9c6e4b6f596485e36c35aa77c084c523ba1fcd25d6f870f8c6a093f6ba476fcedb0d30ee797f326f8d43f80e08d973f11357ebcda3a6799b742f3405673f1fd752706f6d180b66a2ea9c6304381fad4cba629bff9d982dc609850a190f51253dc0b19812d051191e20a9ec76220e76c90b4c4ffcf17036e0895aea405c9860d03778e2f9cbf7c68a53360477103728d0536944566e7ad65ba2e86f3cdec444da6c89395af660ba6018a553da67afd294f21ad851624521cc6476ad346b709e76acd78abd95c4ad14a59e793e29e73c860fa8bad28663c6be6ca03e713aaf9410580b811a5abaef2723759bc2c0804b4b9109be703af3333006af20c16f3ca88727bcce1ae0f206912b896e70e0f3f95a9cd2562e2923e09dc6a322ea2c4e0e9fe01edd26c07483e8c67e2dbdbadefeef089b9ae1a69b370a703002508025817fe30e0ef332820436335e4ed0853f2472b9d9cb025cb135a03c7ea384da3c34611e396411909e9d50fe0959ffd03ef1d5fca6173c1fc2159ac1a97c80b1f1cb36cf53f297e8b9afc505531be4e2088f8f9c8385b78d850d492c642eebf309f53b9030e5bbe710b95ba483ed81ad543e57cb5ac92863e56f895bd6623373de04a3b97ac046d444dc8bda03791b4f4be707d9f8142a49d1f9e28f08710ed6881ac86d2d22becec5f6e5e82ff49b4ca0603d699d62e85d690dddfa286dc7626cf57694e5595d83724935789877dcce0cf2b4445601c941970c2212377a66c62f4df1525763c30aca30b266cb160e3b6a117f10ae52598e7b697b1f843508534fa775e8c940963de5cf35292dd9c131e08d3dc560dd058cca898db6807266b76f6651a86d0f075547b4c2937871602691bcefcb8313e47b2471c92d43c6715d525d8c5bb16cfdfa4cbd0be58fa5dbd7c7c0ae557e093313a04ec706f685107ed044fd44a9fed4a76078f2e0316ae020af8cdfc76f31406e1ec5029ba4b4070a34056757aa14a32501e80b8b9e067f0981ecd1ffbd07cf0119d17f85604f512a06c702f9842783990fde268636f7dcbcf4fd592f9b8375e89fb5c13cbc6cc808c0ed738b46d78c40b8355111bf6c260c511a590a5959aac9e9c1a91211653f8fa0959023c80cbd670faae3c668074ae3c1d0420de651476a11c8dfc9e34b258c87ffdf8805bd9b3b1a31427a82e3375314565d02a6330625cd98fad738d5b98cf158695b2a950a65ff7214e331cee8a6aac692d23cb1c791474ae5944e0391dbaf02ca6a37257d98804b4cb7d624cd3565e1e01d05ee2c6d2ded6dbfc42de3c13d8b8dc99864aa9da03105119b208cdf676b6f2d3a50dc3a4b1e43669571495960fe1352eced63ea66ef32c63176787b0d457c1737f7828a78b46cf8f9a3823a37f7786be1d59c8786edbd18ff28c9d454e1a8607b6cb1f0fa3680b5b9971e6c85753f9bbc81c53f013c4c2cc2835a195e2e40173b46c4581c66748480a340451dd70226472349d5c10946d58213c94b4d6617f66ca2497fb29cc1b4564458796aeee4694570f433d7f8d1aa52158937516e0ef9fb02d4a8238a81dbb513d9249cd00681908c656275070cec5c1b0a42c67feb05d9bfb364c643cdf96709567a3bd2bcacbb2b8300b2a45d9403c120e8724d24e4a786390fb8277de4ec58af842050ed85d07308dee097320ea1f009c0a659464333bdc1d270772dd57d821838acf23b869d5458f3a016eb28c4e98b0bbad7dfcff576ff5051f84f6f01c6aceb03e90b4ff4439d699fad4a15bed7551e5174f1c04cf9f49e4f2af4f3a7d79c99da122953812e9000992a99e867c176818f7b8ea4fe23bbbdacac3060b4cc41173adaaa29fec1d3c970c40270f0d5229c09dcd0a09d63f7128798baaa38145347e252e9cbc784ae9130e80d25ad7dab38529bc96bbe200f5123d5993d28e33543bb4562ab37718a1f28b512af02a1b5dafb3ecd1405323f9adce14cfef055421a27e1ad4a23b779184bd6193fbe2c4da78434e30c0fecaedf65e76648fb10cfb02b4d3f1fe69f02c082113bce24a6ae996289903cc20eac2aae2f506888d11950abb77ebde98d50bf349c183f93a6e9137fb5cf99964e1dec6c2a92b7f4695aeb92767b6510bd7612950653136805d9719db6a9248afb79830f83c0d9f5d4bc9c12a669fac18df63d801bf42d36c8875a839592d3b4635285673004bee48d0c8356a02f3c276c9e3e3b0b69b8b4734db490cf5057b43e593f96bbc563df5c5426267836533b13a0c7f73caddc6f051b1efac8f1bede171a53399599d0322d741590279ac4bd15d2ce7ca8ea65cfa4f0494c3b80ec82666fe6e799e369011799647e7e9efc52b3e4a9aed04e0e40d2d6037a18af319ebfd322264b6a9b88d81dc72bfd69cdfc66cb4edb12599cf48b78bc9e9ef8ce1e0ff44836833ff093c6af3f1981442e1a7a6fa62b43d25588ede8aa1a0ad3906fa0aff43e5a4561fc83f7989c06bb8cc14672e36cf7394ad9766514460c1b09f3962bc8698e3fb734c1057dab5b6a209df6825eef645992767c025595353eb481de1e51a36da05c8a1acff36a744fcd21de716fdbf09f2f1167bebecfa9bd27a0925d20b865c6f4e7cb9f48e0d85d9b89a3ffa70fd09d3838be4d90238c0f8f7f027474a2d7483b9a3c4fdadf52333b75fc9cc48d3dcb15809ae97c910f259d7c3420128c7c45f4ee999a963bf59d8b532544135f71860c41e32b76028448bf7d54352d5624a309a2f03ef02db5676d5ea76ab63eed65c07df53da33d9a7c604dd15e2cb43ff1f880480261b87c79c55c5689ac762048230bf11f9e2450ccf01b87e5e52498446cdf5b22b5c57ce676e86b64618325636bd283ad5b553d827d9d19e980b0d6bef752050106f46663fb6b76cb6b79a9ca5cd5785988d08ecef6a8139956f16c29bda7443a1719918d3f5be2e23c80256f5a24f540cae906ebdba5aba843007b7d11c5e053bdfa118a8daebfb336e14d91ead334139cfcfafef94e466952bc0b59ca4e396f57e6b9bab00786d2e0ee9df1ae96e113de2f6c7d0effca529da6b0997b0f340897f316d943047373040240e1caa70d3406d4be0d8719a2cfdc76c5e928ff6c845d33d16b1d1d05408721d5ec58449a9c1da28f06dd74ba0d863e24ba6aa0fe0b6730ecdd3ed590301351fe0150f160125f803efd6aba3a9553dbdcfe40ad6ad247bd0c42632e9937d5e7ab233ef7b6ee8555c894aff251f304cc8b3c9670f5a9ca79526f45f6184eb8ce30a03a9b78477903600a9382a172c9dcd70d48ba54dc3f13fbc035cc4b5d86f15aa5753b29ab18575b0a35b1a3b8ca3107ac5e9ad2b15b0d5234a5aeaacc1a954cbbd09c629f34bd5db1a01587712b40ecc619ea4ac600a3ec173980344349087c32f1dae7a0e202c042815c3ce3572a1c76de70ef3269b9879411893cd5e90fd53d94a61d85325729117c9278982e7a09edc621ce97d0d16bd29ba2e887959a414521de0b5e3309cf106b250983598da50729523effc2b8cd01ec8dd846f03212b8a5613896a5821791ca6614c6a5346f467053f88c509a0a1e77457185e9555bc5a8b3360cb6d96868ed4916e45a23e5f42334801ee484820200f1ba89d1b6d9f6c71b6ebf15346591a882744074ee88c7f9b46886bc8585956595332bbeb9eef8b0775cae08e0f90a9e93de3fab7c06d6e22a89ede2edac8331ff4470aed3d80a2b3747260ec7e8c9b4d7c75e46d72e8e14bbcef8ae7a4d2022526ecaad30973cd221ce87632972939ef3f0cf17e547f66548e6dbe80dae37e42ad4f08660d5c62d0d11b3a636620158aa73c8782a6b2aeb36a5a67aff75625d33b26d6947b61d53b7df289124ec6ccdcc9ce40648e218b3d89ba42583d52bd67f512b4a84a95330ec0abfbb5f7cb75c1e4075e0f7cf155c1549e2b298b1364f14370a7d7dd6ea5bc8ea68c5388d12f2d4fd24c2a12497bd3316011964bc6431c89c00e6821c0ea121fcb0208d0bcb18df21223eaa051f0027a297ceccef0b3970edcf4b934a622bdaf7b6514be115a47f5a70b36010808cf92933c635ffb1015c5a2a48d568459f637408498cc8c77a289d413cbbda45143db64b044c21e5f7c292fc4ea2cbad45cc94aa9079831da807e3b50c9744eec26106162602839885c961c0b4b95c4788bfb64ef9d93b6ea1c4edff05f9b49e09cdadd6c8217e2932adc31d83f9ba8dec5cc9795b5f5ac495c09fb459d16b6610483f402b08f028fc1420760190785b4200c4d81f2ad6dd2b7108042f9640acf5c4082d6e265eb34747d2db2e43289c51394d4a5591d4fa773767a0603af2af7134ff540cbd8e454ca0d6949292324900dd54292f25f3717a4937e93a5d427d7a2b459f7be5758e90d8f3a581fc9b5f93a5fea089d2393de1b43653ed19ecbf3c799d691a9ba118d8b4c51910e55c79da601a8b3b3d272e69002d54ce16ec5c99f2e6ebd082f31aa3ce9a0690fc21d71f83ce8088de89b7c5092623bd6ca3f5a1c68addccdbbf3840331bf3b5f64e66274dbfebee1701d6c91f8559d73b266729f643335d18b845968c0b0db0a5cbda4c2fc36ac826da38f7f66adfde65a6f7667aa2e2a83da3b050117c9c44054821378fb2c2a962995ea85d4eb0f5d8ff4ecaf2913671bd94e9ecfc096e9761219211c00e31f390353887c1424033fd3c4cca2052e7249c8a10ec35e358f0ce7197197962c469927c2033fe7d7459e7599ab0686721c8f7fd0e842ad3c606acd3253203d2190cc83553b19cbe91740f399365afd1563465d6a5a9345f961518fcaeb2bcb3941958009990111ac7494359005b1225535979db57a7a9b4bfc3b0481cceb5a0e8f83bacf9407f0492a4df064a206af93da215bbcf5645a939533177e82d0fa7eabd37f2814ca8d9a48e8bccd06d6fc2f4c72d68a3f671b23dc31d2b60bb58da65302c6d84a635f5da68ce9c7487c7d25a09baa5b4ebb8f2feb4c9526188a194215ce31f0c453a9d2e591b25ac98aa819b954ee4e00a5be9afae51f049d3b8896bcb40344c2590211e6d729fb4db0fcb71f968248d58962ba5ab7f940d84864ada1146fa85e325cfacb6a2dda44c9acf785ccf42d3465a21926ed23fb7a21cb5d158c83819f2e6c8282bd13b61c6f1166997db26d2eddc7b3fd5576b9934d8393710265b843a9fa4a2705f3ddafff9a5817ed6890a34ad0ad57372157d32cc54746e3de4c99fd10c05ac834e38452a3aeb9ec4452bcda2c7345a1f15736021bc09461b760a4218746673342651baf26739831b4a1c7651f7b9dc49bd8bc2a48f2d3a683f119d2fff47dda4a27e14339d68776c757af0f5e16309eebf4b81bee1b7a6883eeabc8b3a51e24ff43f87c668aea5cff7f820f90eef546569d1b458942c2a99cd687f7a9c9a6603ada53811d153512c1feb55bca9417d6e6421ea0a12bdf920ee4509fe34312f6fa81c0a5346eb4c2f72e2a7a99f8314409a717ecae4efa766522513a94339af067b216d3291891bd34f63938b8b130250dbf3164309b37fb70e0ee848973b9e01953dc3722da482d2a498c0eda179bedac053b9fe1ca6bce5bb928bc741d75246012c91132767b14579d1cfdf14a04cc24ddaf44e086f45013df4e04380b84b9247d1b3ab9b7235facb9372072fcc243b711e2c4851a7f67cc11ce3ea6595007e2b3b616465e78f3b96bed3646795f44d96e9cf3352e5266f3d9dd372a0418b9d514f29aa383b863fc517e95056820f84e2616691219d7a01509e930de717ba3049c16105f0810403c6e21e99e1011f53c3384158d1a4eafc0916effbe23261d4f2c9e021726b142edac2bbbeb891f86dd88bef569d91bd378c45031dd28da415df61e660cada264e85f5c30758309b8041b93b87c85795e8acbe9cbe32254578fec35baed2c735be00278a183c691f4a1c56afeedc7aff9581794dc4eb999600887d43bbdb7cbb1b87d777d12ee2aa8c5b7bff066629757fde2a531912dfe6f7c9f8b765212b239889202ced7c2db3f91e3f955764a0d8d18f64b414d7541f22622ba971af4fad271280ea5b6b42095a17583b959d13e7def7957fc1846424f2f9ac90decd13c978c2962f3668b090c70e7460980340d376a8835cd0e75e214ceb99a15fe35b4ac74c3bc2b2c9ecb079cdf4ef35c860dec5469883c1a44cef62261bd9550bd81d738551de2b07c1a0b9567051bccaf32ca6f11aeccde2618cb65a6b43c2f9fa454f84dea40d6d296a25483d907bdea5bb2342c4f5ec8a8e28f3815580654f4337e3fe82e5a2519702528f60c62a10f230c2075418aa0e5ed5a4074146b00ac1559a74b073024c3342517f1f3aa6e9346c7f8cf9fbd13705ecf8f68ad86ed2c5f7533ec806d74353ce652aee1c35913fb864b7ce3377cbdce88a8855787393eb02758420c1fe332c4ad70496c8e3a02f259092cf54e8a77ec8e259479b6def35c77ae60b9b334e6e642cc4809a05bd6b0a0db4cd615a3b992c039a94c8a43c46136d7f0e955ed9c009bae9c2dd39d9349a448768fbe813f4844e24ca7cab47f8373b6160cf230ffb6aba179f111e8e14b8cf0160b2bde2c0310af550a147e24e51bce86ddfda9c849941a671e2fb27d7373316816bba800fad607f79f54ac0464246d28c8032cc1ab4cc137422ba85ab316993f1fbac610e4c8cb00abe726bd44cbc738503799b5699070b88d5152495f0c2a114c55ce9795009554d107484aeb6db15cc51f7f08bef78d99a327cd01339c6c61dbe0794e6c59b903949735aebfc09808d1acb99b9fbee63baf699a881b81bf32e889a37af3edbe624c40c09ad71b4778fc1ae2e8030d6b9145170d98a079ea3ebbd183830ca9fffd7ec4bf1b31c63370dd0f8cd690a0a6aed98466faeb55bf9d7fd0340315f6947ba7d3288e6172551308e226aee472018d2dbb53ef9e2f440185d0f0481a46db819087c611c66be67ed1948e59b752867444886700d0664f06fde271133f35976294fafcd275e92e6e3e664bed08da5221f0b9adea8d5fb68a056fcd30b0f6dab4ad8655334d2641f84c71790116b0077c979f33083c316dd8c5aa2402467ad179ef00da599934b8235fb1989bed229cc55754d47bbd3e7ffa820a0fa5455de9f1e3206aa45b1fdbaacdd59bf23ef47c46c4b68904116799f5f6890bba07e4203214c4dfe80073870b3c16ab217a15c524e29e5c70b03f7888e4b3b4fa8118ee49765e507a47ac71033a2e6ba5589be25edfafbd0f0a7678eed8c99819a90cd0554365821b0b23070c66979a777c8f80d502011c689307364344e58b828184da20ef2f92f64467d742ad2b5badbe66ea52def35ee3222e69d2335259e57926dc5138e02e83bdf29c722801389c44b4613244f68e0aa055cf04245bccb4111394377869cb744c2844e3b41414d62a8d6f1be3b79209f13ae41f9d43bdb38287d8269f62059089e2c3a9817b3246f67492c4de39d476acb926070d56589b550c09a381c4995f388cf45817bb1b4db1124c10516d089939b2b81fc9ce4f802649070d377affd2fbe8bb4634b67bdc4947fad4a48a8253d0d34dac7e58ba492fc630605347ca86b7f2a8586cd84400075a80d5613fa222bb9df5234e6b2cbe524c9512a5409b9049ef5cb06a326389cecd3e7e7b70e7664374d2ec86c36b10c85a8f455b9c15fd194e836cdf4149c4cf5945c7dab22b7160b7546133ece7574c4c2b9d9ba852b161ad1def6ef53a8e3beb091e184dde87ac7c43e24c6cdedb7f5276cf33ced77335bf78dd842c1cfdd5a917044458945dd47551b56d0a0ba1d0af8c4ba81be5c805aaffbb1275289c9b45e2ef41fead48ff596a31de3995611cc9446d8acfb26b47a56dff71c78f05be27e98b6b0ac283410be5077ed7bc8d2707cda9cf0fc64cbb0fbdfb7a70b2677d2b8eacfb270d9f704eef33ad4822b1d31485922b9800d138e7c26ad18775a648055f48cd37da7960bbbcebecb3383364f4c4d7f34b0eaf26d10ec3c8a27489aff3e5bcb9e7a57524dd634f43b811fbf4ffaceb1a87d43ff90d2556a5adf8cd1b53df29e655ff4fe366d91210fab0b45dbf5211b978c000d039a4c62c60c096afe8ce4ae95a1ee06520ada6289286c3ad31a60ffe5d7caa8cb807214d8396b60d1082460066370fe0df489285b81abfe3d5cbeba391f88166e9148a3a4d710f2fe49f70795445a843e39edb842865eef9a4a82f0df7fe0284df565bcaecceb977985d7ea594aaa871dec1320d540f799d1fa22c1ce12f008c18f7384146aa8a57206afbb3375e37d1d24205542051f754c10f120ca23d633339b7a9e46e06809c6cdd3dace0c7bda10dddb190a48240904f3aee8dbbf40669152a8066fb175518133823f44f7d90fb5c0eb829a67fd459af8800fece42a4a75a6c736597e15070effc244e56402bea1f977340d53e15f610913165a12db993bfefaed605dfe29cbbab10edcce171a07d6ea5f456ff69c1485be64a446cc082bfd3ca55000cc47c307876bf02ddd59bc4886d5f5899b8fddbee557994a05f3e287bb8e966217adb517037d5ef3f22a2e26c0ac8fcc7e63e9a14d020d1eeca25ef6be705e0aeca04ba3291097bdb04428a6d05971ec972270a4e7e46ef795d920c0f0696f8a128048103bb64817fc2bd420265cd11d4fff2e50ca162c0476e068592a946828bf4faa86f2384bffc9d59ac2dbc4ed121a8a0de51bef578455ff9f4d699514a6202cdd82404935ab65fd636aac12430b9bbd94d0035db4aa08a34f6ba68ba986d850b1e0cbc4b79b55bd087eabb1df647d676f4a549c8a54fe7be1f0510109b4f6220bd8e46944220b863d3a894fae17899c2ccd56b8d89aaaa7d66c88afb90370294ed24048e28df1bae82cdc02bb717ff9d304bcc07138cdc8abecb346df8392313f86aec7e1375ee15b0c5e32c9d2866334cb032073ae5951017d6319fff072e558335a200894a9a50d099d914c541fc9d6a0a618c392f618f63b04835434eedd00bc6c4222d8b5e5c27c863b89e5f28395542608daad51c1a2f157ef8178c91498aeedefd98a6cb57c5c053f05af72c3468b56f749eb00686a1668592ca53c7751dbac176475ed978c2925b66a232e2a0b995752b53538b1ac2efc3ec6803d20dc37e66b0690880e7c0898cd9f3681feaa05e3efbe3028416b2fd80a68d69e2208245ff0a5bdfa7b6b3352ccc7bc7e992778b524ac2ad9a39ef327e903288c82b9212a73ae4c952096c71a9795266051c463e985606adc8d5307bd3adf13287fc4a46bef2d5659ec9c09c83add7a00d56d405e2f1cc07d87e9f0f1f10a81b9278ba107dce20270c51d50a0865c1c5ffeef887062c56396788c863d33139673233d17e58f4a9dab32198e9aedee39e9a6c36ed007f0c3d65cf389037b0c98a02c24738dacb4295f2315cad40435c408d57b1bf87895463c8014c4698b99a1331b3132f44b7055fe532126c3ce670ec7ef4812028340bdc4327a88531b154f0ebf78c94ff8ae1097fe9cdd146058925766d940b59c3d5b991e9a321aecf86a0f52eb5b173d6be2e8b931dbd6d68616ac65ea52e69ccdc2fd6185a73b11d6c9d995029194595fc390d3899b1cd51c7a9352ffe63de24d76a012a96bf9f37c9ea978d2c770592bec379f5a7bf33f597ff5fc54d1eec322249b3fccda8439e1d2529c02104233f984d04c44d1eda324debcdaaca742c2f5158ca3d9741d691e1c012a2e5ffdcf054065bc572650db16631d1d6c42005f6fca545c96c343687b8800fa21504dd9b84549ed3563af6a3dc71199fb7615475b77ac762fc613f28c6d56157ad1c3741feb84d0ab5081db807a19db564b5ab3549145c040df2bc45a0b3705c5c427fe72daa67490847dc304556aaee5734693b0335e3f039703a2892233c02d366524f80d9ebaa65c514df97da4aafbea4e180ed3b56f7a4196dc8f4a59a09d56e03bb00a04635afd31c5265a3bd0a964a58b9f554d029a76dfc50b7d6c2065407d5ee194302954d82d9a5e53e87db713681ff1b97db315f4541f09171dec898a103e55df286fa9ea947685af54bb3f755dc1893a378af6e013a07ed850bbd2d3e444ead867a569f8a493f34d1de5e4dd48ce967310ca6ff5e1c331073015d7decd8f22c809a10ae97a53320562a9dcff173300a32ca3b328a573f74a87bad76cc91d65c0f59de7445f568b75d53f4677f5e92ff9ead426630726a87d5df9274431e14ac429fddeabfd0ae7360a74aa39c1bed63095584754d9f67a279664c0ee78f31e98982a0502c86a9cefdaf475377a26a4c01d6b581080b5664d162f6e83668ef73a6453b624d762c6927ed730cc07d35522f9121fe4bb45b7f974ad26ae52933659eb1ace4c8c55e227ccb61f9d564152e61b08bf463ab0f866a49151357d16561b2979571cc97ff7ec911a9131f2f4b35eae2e6eec34a338f55e6727d8e912c8a959d4e54eead6d3e5e0ac6f48f5ae8e8140fad1f5daab839186d9e48aea2887e01c32e48681734b51bc3856d547468456f03f947f0dcb424d3943c55da3465b07347f5456c61ce13b0f6e04a975ea07acbc0a687e60132ec6755bcb2d9eb8a9504097485b7ff214b67f0a52543007aa2988e8ffd0866323030e95026e2c2585ad9fab2481496a0350d9c8e8c5eac3806af044a21c543342bf28491beaf5f63cc2366741611c4cf13a415cee019e39223b067cb70ca6b5c950f549c844b6e67a8338e0dbacf931dc2f30f0fded2d27765fb5380be10b55094d713bb29059f3a126ec4bce59ff7926dc3388069beb1231ac79c862bff82988983fe846f9bf8e33ace9e03a50841396cf996f7a0559045f08fb0ca1ee66545ccd234e8712120343d232eb62e5d53c3eddf424be17c4c4ed7e7e9c5cf309f62a4bab41c1dad99c0be19878a1946405c38a409af8c40ec95bd9f4923ce3db4637b2703e5874f90d9a11f2d76987bbf54d57452d0f344056a861e459e58de599e636ccb60707debfbf082a48fe400d37fdb69c7e44e4d0a8e6ecff9e4f0ce44009c3681b43cccc7eb824e7d507a241ce02c98279526b264e82ae3eec19643f9dc98baa2cb1d4b0d4a906a229a85c9a80751d3965a059e348d1a14b8e233ea98504318295e75f1a5b1a6ada4b5b0ced697c2685e8c1cb0c4dc367c50ee36e2ffd8e25f5e39a93aff9c779d2adb53a9799abbdb23d9f48ffef37e7582d1de8bd2b198b7f8cd111b450836f402f377c93a33b10f97fac0d5fd869cfeb8d793ac2b85cb302528dc31571cc488271fd91857d176a52290b8509eb7c8df25678d03f71ab6291b2b34d2249682c54dde54e0189a86b2f7b0f0f175144f5876644dba0c25f1f16fe88959cfa2bad3d4487fb669cab18cfbe5e969120551c40a1c4950b0ebc1e1179326ea37cdfc70c001a075fcf9b0cf4f11d49c05a58c1d39768dbe19f8c70937c2fb17445f8073ce2551c44e0fc36be79bf528d29614d00af094afc2b10ec628ab71bc312884740c75e6e322dc3f69e6a23c8ab8a3ef7b8858f4173305443521816feae31528024dc955dafa74b5d35dd8c678fdb3ef9592f5eac3d10b08799104833e1bc7c57976e46673bc28872a8ff08f3691a6944e607f6ff498bdc6454a86a568df7a0ed15b7c494a117c2eead4173ca7f4430166dfd7892f294c18d19bf9f6a16ff7c6e41fc143d50534689c243ba973e33cd1410e071a759b05aed2aac6b04e52b708d33075dc86877c204f2bdc02350013ea54d1fbf392c501b52465db4e845a812d8b7b0d0d16b153df66a02c1434294308c2c33b9ec679a92e0ccbcfd85d0de0172f881fbbad0147716890534ae48e0a90be8a871fb26513bec76970ebd11bdb6f5273a21209f8e9df9b19b68a1015f4d360a43befdd312dbea12ca6a76733568a5d582bc184da966e4f59408d8e06721ac6e9ae2bb146a1533453b011355729d0981d2c883c52dfc31863c65db896b7857c2c681bbbde75d8739f06622866b36fa0703bfb466c102b0a688834de3b85a2859d2b190ff1a452d8f924d869b4561c0c718e4d5b6b35fb39d664886bca19aeee8e1cf5d2c59608d253de0133ec8a549b8f24173e1c69f399104ee8a6927f8eb1b22edd444de5fc17b76238cf0b21b308cf185f753ccf5b23e70722ed70654a768dd72585b81d4482f918fd394b08d91d4d376823be6cdb109133123afb81eb76a4af9f35f811b3d1034d60f46e1b0f996d3d7786a4bebb7f246485688620afb19e087a428769301098e02d36a6b93271822125032589506a22c0c1f32f71da06f82ab32ebdc5e2c087970c647dceab51ba6b0a4ac47fa97126a37cdb3b5bbd3eab8343f6d798c39681abcc312a32d2c0f42bda613f1159da7b8c8f2969e0b3721cc0eddce774fe43a11f1f876f1127b23af4493f619fef24b43085acf7f04260fd53029d6ea7c71a295ad31e6be64595f645f7c76ef229066e0430659fe64320660aa8a5e9c1cf1a3daa16cbbef177196a918e239959f2447be8425019290f48a031ae479327919833b1c2e5c502806a53e9bd7051653e4705f1a683012c05f8a5fa09df38e21ab8229be06506eca1dffc0104b7362884ef1a6dc106f221408f32871765d21998ce67362961f3ca7c00f070f9112741eab69714343cf122920d65b9f1cf5ff1c4ca4e0756f8051b1711a0361e6db83e045c3cd9cefac5369bb6850389ccf04acf57ea47631b5b19e454c63f5f0ea34510265b5b4afa00565875268a1f386c5b4272dc8c122d5ff11b9b8263a2ca31bb8e776533b26633407583e6406e6723cef5e9cb9da31a8b7e3f0087f52af1c88e7d92606f6d860ffaa507857b24775eaa7e1d90bb0804078bf0091a2126bf2fd0ea9655a7a3ca4f46273483d1eef4bf8af1bbbe1ebabca1043504f57ece37fccc59bee3e4fd4e3e9fb08e785c8451c9e2de77dc265a388e47436f849b431481e14db432e72233270aaf8d528c8adcdfce7746bad1073044a79787d8130492b4cc7244ac5590947b98355ca703eac5a699b9bbd4bb771dd06f02567498f70bbf222d35cde3183bb1f3b8e0dfc9c44ae03089ee58fc38e8e78248fba3cf94da55c683073a411b7e90b969b50ed1b3c785678c637f438299b6f6e098f897f53196461c4bb6afb52099c9dba4a5d29f45ee4cf1569549c33c133586e4d84ba4342c9bb1d2c642371630816f2ccc0e70b76285016f2c59010c90db83a318df2748b2ebf630a4a3d6263d3c1c3e94c9c21a20e006a52d8735401f4a8a381900d7945c8169480a9ab167f08ca473a6ed127a869459bc9af178ad808a8b4665634f9bc6127f0241627ece8ff6161cece7e5c4c887ba0194d151e3e77b3ab3ee5c8f1848494f5b0cae58e4c49116c0c7edabe114075c8e336af6eb648ae6aa718e2baeb12c98eb6bbecd4c69ae3c99f75c9595319648df0c3d3b91f97c8b87b7050516509597ecb73c99a1d94b9eab36bc8332f6d39eb1c75c5c5b4748d5a923a55f55d9a93d1664a403e656307431ac7e37451ce07089ab3b14c111e53e703265113caec363c5850a3e577b070d3ca00c81d15784042f1cba18ab4ec32552698664716eba09aae43040796a065759194541facb9d1d5cc593ff3d2701da857d338dcabfbac799d3ea6b0c6c6e595befd3a81521700b9e305cacb342266d4e5b232fb3c211644498728ad1028b0a9393e341c62749501103723ff25f27378fc932af1c809285ed4918b1fb5ecd8366876ef4c3b6d9ed006f57336e7f5a6cf5c988f06b34d69d413133af4025e3e2f394835d36dddaea233fab61440df58e5c8422f050bddf80b7d5435c2b1a80967ac088e92a87558a966dd94cd56ff82275bfbc2eb7214132eaf68b3742534518b685912649b020395e3127a3c1709d7ad9a89888dfd41814273c8ebf0c51eb76fd96ca3185d478c0b7216236bd0a394ac869bd9b403b6f91abf29db087668b3a9b5aae6bad6976b048eae7b264029c8a4832f2f5ec98ba5a4bf95045a5de0aa5cd5531e5d872a0f397bbbe88710c90096304ace22dda8b08074e5a1723a87caaaa38236be99c7f5f4d0296f81fc441cd9b22c9aea39da6aac2a5dbc066e1116dfa691d814e89385d248e0215653faafe3f47e994365e0acabf532202ff058493497de9ef3c6519e770af7f09cc928a65241b749c1e0a55eee50164cba724f795c3a2fdedf7426ea003699f8293855153cb7062ad74ee9f114a7dece7b4ca724c80cdaaa4e46b549321c2aba86228e0582ccbeb65f2bc3eacc03aebdffd997cad3b6b3981f9bd63099d84759b734ee22697ceb0e03e1d96e585b3c7065a4b15ef6f29e6774d35291d413640747261fcf9c0d7bcae1c15f78c2e23242d7856f6beeaa9d9915e6174dd9630288bd7325a6e89aa5f9e2476a1ae7306d119869ba823c2327d6be40f70ba0032d6ebdfc1649013217a79004a24de2a9042b749280f00c4885b6a051eba0656675b4a3d96f2dc57775ba6fa4320e2a9f18e1135e49fecf703c085daf8c91341c2f8fe2ddda0cb0c37133cbf21857dd18727fa33d8ab250e38d76af85658ee81e9e16487985419b77515f2b36275eb19f611de820175ac93584f5eb9890cb5374318bd19a68aea7c70136f22a0e10439933e565b8b32a5d6287efac688dfa958cb66e745a1ea35363c25b6ea7fec95370db100550693a62aebf8214ed7f6e49dc8896209e6fabe34b70d3c41f4212aaa628a40317af227d4369272aec452322e226235ec73398c349c6ea7f108a8d030a1ca02f1564a158e6e1392dc0a8f1d0838321e94986eb2af8ed0ed3e11907db528bd98c99bc18704f194a214c857f1ca3e2163008600a10d7f014b5166f6b39054ea0acd88e7b385132f79d7d1fe3ddce707cc247b42ba787f44a2361da04898210e3e7effa7585f5c9390d230c49cae5452e2ada75f17b56e559781ed92ba438562076b5f90f8521f93550a43aa6c82af3ff3210f0d83759058fdf3ebbcb29adc28e55c5181ec1d6cce41409f743df30b7a80285256da24dfd8c6eb29087a7a3baeb017dfb2177a0e5266f475703c236be20848d8624c59452187f19d81855a33b31ed6062a928ccdbef93b159a9dfcf89912b9a679cde60eec35073f699981b6c508eb9730b71f79174ded861a1ab37c7ce91af51afad09a669e9863e261d9e0999708a6b4d9c336aae553c12a17f6eef5e17f5a20a8ea164ac2d5ed55d7e1b28002d9d557e8eb847692487198fef522f763eff00861578d14e87d170385d0f37cba2af0b181b61d7cf52c209e39155d551143cfc93a08201e0aec096c44ff6552e425a27063732e95f12508d01f63ef340a67a7b9b41473fcd730b5bb1a879003ff7db2547b66232868113eb2e3e4d05d21fc50dffa49ce4361d03a429aed57bdcbf0a71e398d028b68fe4b0895f0474fc19aef9bce1dc373251a97ed1ce9a914639031a64c153dd883ad9be982c1ba818c0319990893381786ea47c45217cd41b0197e9cb205821085fde01a677e74d7c184a76b49418453be0edc6e3e4ed7421c0c9104e5de9bd153c22666434e13c754d2c523c8c873cbffb6a2d75b518c40cc72f3dd36514bba36a32ac561bc4faf1a5ec024ab91b2dc1ae63d32a72d35c690d5a5ba24e9c8a92ba781e0961ec806f815f83a25602735d99fb42c8b4759202dcaa6627804bee3713d8c3744f15cfc8fd65d3f66e505e578b9f19a960841285792732cf49a41cdce682fe087323966b5348bde8934586d3119b946af9261ce248094e60408b28a3c3d4b11fc297456ceea3bf1918127da86eb527faeff59f86a093a68cb6737ed6c15822f20bef01b1c6b2a80d5614f3640e8554ab23df1e0ad9994331ad3c89abade2749458d62be912f98fa9bfeb8d7c5525d29b34b3c89c5f4d401567c36962e391d763192839f21af7c5b8ecde6a2b0b4f383ed2f9c1d6042cb5eb00c40ac9855a2a2259e7dca7d97f9dec0d222caf78e316554a05bca0d9a4d2fd48e83d29df7e50e80651d3b593409aa2c31d3a0c4b5d42ecb299997893b29018f7b7b0abf815d6667dc7caecd9f60fa300e03544d151352b4a2afb00d6f95196a4a614f18a031ae7bbdef11ff2a6123ac0f833a1bfc559995a582658dcdfc2ebf0ec351c852dc0453e2cfb384d277a2a01a45847c32806180542e0fd932b9329c59a4824e36e55250c43382b57586ce688ddc381fdc62c3f3ade1201e04292ca0a8544df456759dd2b6a2606f8bb0625fff9065df2e4c683584e1aa98edca9ad6889869672253dc72c2a0a99e006bf1c8cd1039a5cd1b2ef3a55a5f93723c474463455fa66f5ee44123118c08e0105857a8e03d3c8ce2b68a236fbd1d139489108e904c8a9da687d88c8bcae557e427318028bd1c000c1728a92d923a274101304fdb4a8b5cab5f5c01a95c6a788331744b2cd4816d491b0a839672f47d727104bb8b951ddbda5e13b2e6235fdf79ee7bb4a6e0e4d3ab11e085bbe5f6590a5193992e91e46326be6944737edca20c8f05f7d3926319c6a3b39275863dbdef6262bbcfb92e9f7c28f2ed730efa65fa549e821f7ec06a9b909bbf47af7c5f3acf31ec96a859d1d887771fdda4648abd5a636cc47a97e0cd5ffdd324e109f8b5930fc328ed84de88db398c151626115364a633e5fac8cf0c03d5e9cf13ddb6986a359b4c07b257aa6fd238d166b655ba4c7770c18abf5a6de9050535c4de63be976bf8ccb11bf1f5897c834d5b95e4f79068ada74651cfe0b97dcb1ebf928e9460166ff71b8656726ac2eb7e319e5d3358cdc0d3af046005aaf11239fc820c435e70f398efc103b31fb11cc359d5613ef11a8233c0331b58fe3425479dca0ccf1e1938968b3ace920273aaa4fdcd295c6b30d12dc62216a11506dee5d42dc781427d98340e96c9b0886855634481dcda6a9a69d33ae51742e244e76c4e73aa2ba595a2c5bf0b04df5eb6be7e0cb1d1c27e8358f2e237dbb077fd166e5431e1fb9122746af47b41ff630618d525bcf93fe68e148d2efe7ee8fadf62240fe828c40aeace8b196a0ed80c59cfd0aa8e082978a8a08bf061d7ae3d89fa324e1dda0785602595947e28329707b063426e880bb158a1100198ddc3ce0bb8ee81262b3c37645ec2650bcff1537ba516126b5919be596e85885011a4afc60b18530da5db27aa7b52863f84c35f90611da51698fc2dd2dc8b4d060ce807943887868796c0d47d7b8d8fa0a5a5b22031470d1dec1ca9a575d05f5c2042fbe0ae93adf12f9317e48406f69a7add64e16562bf48a201cf12011697e314ed914da30c16e68e37a98fb73b8baa9d7c7dc24284c1cc283faf4ea271ed2fee77750eb1267388648dc6489352bd61e941a07513c56b0bf48cfe181765d4dc5c749c600f4d10b396a69c9375496563c2d62011f0044d6182a91a0aa648c26f7191ddf159a878f53754c2d988004d11903be7dc82cff833790520cf7861289fb625e89a5b44448caf31420eaaa50dc592e080b1f5c496f2002b1c373110c3b38b91917a6354d0fe93386648c15242421062596ca40501b151e9fa4d0dd06d2f572c4f5fddbea3a00c9f9b0672f746473772e05be012328ee1e8060709f108f1877052c071738c3f03b6e553c7caecbe182ae1270ae4c14abb547e0fde87383bd6e68d2112adf473e365fca59ee51a1a442f1abc99b46995f6cc1289062e1297630b54a60eece1d1b246582d26c8d75628068ce041540175d17389ee1553aeaeb9d70e785c97aeaf2dcc2f2edc04bfdb8f3c384ae0097a47c106d0b5636f27a90268860b3b6ee8c4b593123c69b13b9e472cb91b21035d780469dee7418500385322a4f9a80e82eed844b133375b93546ed4fc19044af7a0fdd0b9351edd396f0ac2238d5b2a997620c4dc635faf5e258a24c3d99b11e25811b0f7b8b2dcba685bb59cc600b3c2f440984288f692a2d035a84e011c40c1c791425b4c592b1be5e94b968a81c42085181aa3a429b2b742b20b4a2a310b627e84d5040ad9ea4c5815a6c80f9d8021603150e369221725a0f7ecd5c0b89d456d60ab640c09727d35eba899b8dfd14a8480d00ebc46fac63ec5fe50dc14bd483d3a60dc78d1a12330900b66a650efe7e9f853b9f3a53088009ed49a84fbca3e3ca66597a06853e8af562107da9eec4208e74e7fd085be54c92d1cdab154decc2d350df2220465df743e3821d1aa85ff7471a6187e4aab6c5a5a6c06960006e846db4d5705260771601c48872c5220532d4a03b7a5fd4587b793e50affb2cebacf3d51251eb8c69f931d6e159c2723a4591f2addc9769beee50fcc1921f40d2260a108c8be3c522eaef6c38a9a0cab2eecca7596f5f245d18a9a2d0c2704445b22f2a86ef86b056ae1ddfa197aecce4b772e55e7c8d871e66964c2b17c6aab56312b7ae1a5474a57c245c545263757ac8f8c79afea74d7f52790ac7daa002b15eb94b11aeb56b587eb9ef17249b4b4843845e2ede491bdff5985e405e791d02659de1928e941c204ac0b8b3add73f73a98eaf732c738982d5d7a90bfae1c8630e4ce3435960c9b1343ebd67f6a1d1779ffe6ee1d08554f70ad6f8546fa8850ba3e28437846fa857dedf26b25b8f09f995c9bd0b2e4a52090d82acc18e1889e2cbfe9bae2e52e2259f58c9e2dfeda8f1f5627cf4dd08a0bda1cc1e9de9c29257266d5d0344b89f58dac00fce230df2d585c5b07fe8d08993bd611a8888e0f46aeee4c0ae494f39f82469be7713ac8cd8a9c3d73cae11de62364e08987345b29402a1f474fe104b4bf7f16914f84392635d1a477a3d5a36727e6a362dfaeef7f3fd7a467b2a7569a94739a6e69cdb31bcfeba8853a4de2dac712fd7d7b235b28a850d0199f158a33ef05428a93c580fc64b92e0c691fa1bd3ec514f91d24349987215a51dab0b98ddfb4f05e30b304b58d080299b92e31a7bb76c842523229e157589a7bb9eb266f39228797126f2949158e672649064086d3c26828c080bf21684d5e59fade81afd64da3656c4db47793976edccf2573e1eebe34cd8eae97144e284edcd5e6e41f73288ed8ee233adf51cbdc17e6df5895cbcb7c71b05e58e048c42d3594b5d1ab10d6a3569536ea346a46dfc0db27a8d117ed793c8f54b407011b34787a75ac278868600baf803e60761f7b4241ed88f2779206db70bc3b7d3305f0f2aafb3bdea9be36cfa70aaf26f6b12be12b80bac67635e47eec8ecf5b5dd3cf75f823e968009fc6c8c446478ecebc30d25045fb9c7208e171c451c97df97cecd2e9600b8abed86da240da11df30fb8af183bec6f76de7e624305d2215ee319654c601a2f1e3b23db7b1dd34108dc6f2887383512a8e468c8d621a159560cabcae47f577ea9c1b53680cdecca2f4b64ebd4e00b35230b34a254574657f41b95a4485702cfdb21dff3c6e9ef4d99ba75590b9aacfbe8cec03e0676769f50256c471d576425e184d3e3e66a38170447855253a0eda6695a40a4f11894fc43b6966e6caad4e8df6374c511aec2d9b1605503821a3d6078a66a1d9507012f35354ef8c853422ef953ff8b702a4e0f2f2a5d2723840dfed5aec990d61f8521b48341d21a5e847e54699d8361f95ee2bb99015f424461acbe286dc1673f508b20e09428acaad6af093b4586717d896190424571fdb70aca8e263e6b7d26fc3cf9b61ab360aa090ca1a4538da3ea32594c556132cae0c295433897f54cd0313a321956cbafeb1970f0c42c1a542d549fd2468efda835f579c8c07efe2d599c832b6a7cdb3db767c90005567a231f5c81a66a0255efde002e56c39eedba79e656ab6a27f5bf10df4127c01df57d048acc03763ab97fad006f00065cc48e3fc3161929ddbb379283ab11c52493fb43f6cfd07b8146f6df970e8e171516a4659604d3727c4922478c8cf97bda65de91bd4c08511df0919efcf5a9eec0bb380d77091bb0770d7ee772290130d4a74ec3149c26cbf2194429343ee98ea69a27fc946bd13c572d9b2b47b4d37fe3b314cd7e34ffbd858f968cd74d49b5aa83239fc709203b2dac6e0aa71fb28b91bb30f2e2e46ea0c9933b60bd70474985213fa35289ed83a434046b123c156595d717f49f010b6c95902a970e55421467767f5d05d35a13f26de7eaebd39113bdaff98f953e4aa7a24221c3fc4140887ed54d574d0450a030e1bf0cf5ec4ca70ffa18e0fb664797e1922c2e4343873497a933a055ba0f0b5764577400c6bbb61c8df34666ba577d84e67138df98e4115915d52adf68aeda71231bedbb54eca82a5920f264fddaa0bddb223af28d4a29407427b2bb7eb39e568d86a4098feecbe5041e1866991378288bc107fdca7c0311ce457ac299f9138a4423d8ce14aa06f04e11ce1e015e6b0760bb75c2e91faa0839c564be1bbdc16085defbe4ac43f04be70941e8ed10f02e426880d4f32fb4700e96c4a2229fa5f7091d07ef744377e3e2f4d6ea8a2d3658d41786cf737e3d2838fdc1731060d60a8c168d9352866839f1b966d2f49e5192f4fdd40cd952f942aab7de3d72cde299c7460b533d922702b44d3f83075bd67eea47de0e5f9b33fe2c6c523d9fda2b5e11aaf533eb8c21518a286d67b4f1ae0b192dfee6c8e08f776adce38efc9d00a1b68285252eb91b4861b10a70e73dd7658013b08e4621bbaa6ee24400bc45aa000eab79458af2ba0bd408d21bfae34d7b607c004a06a3a98097e7d72774701d2abf921cc06e060058d7837cfd15bc351a073c3980a1adfcdc9ab391909e5df1522c3ff391d4461469c2a4f3bea65af0d69fca969d1efec2ed05e0fa73a1f76010929920ea8e8d8a6f85df983e3ae476c32d80a3a756a062dd4ef3c503407f77b5ffe50209ee6e1c68d964da5a9dc2ad34ce3db4c485ca6dacdc5a490ba9f3b88dd9bb681c71919714c0e4f260d14302fc50d8f204985313935c4efd36f33dd5b196c79f764f19ff40fb24ac019b83e109924b21691eef25c2a56f7535b81e7f80f3ad3706f0b3364e2a0e4c474836d72ebe770403822f35381af9969adb35ae06df776b63ff2e602f5a238c127c3635d44156d708635cb8a70cff74caf8874f192340a21e18e6365b0041b89a2c6abe846b71e27ed472506c8b834a198f162d43b9aed0882b25cf27bc3d7b01bc2b07f93b8419d3136d96331ee1862a78f15933e4ee7cb8b81ee36fb26bf823351daa31d803dd31971b8fc628218e8f142658a60aa9cede7cc44c1951ef98eea66e0f74c7c0663e127080368954e25a4499e685ef98f4d35303e05c05da245e240ca4748489a2c78a261b7a1890088e35decb0d1cc92ec798ad632db85e16cd956a5e922a75c03314300ca516ee3bb83956b0dc38738e3572ef3a792ee66ae38b05c419ed3a311413ce0898228ece19d45f71725a33807f6d3b47c4a69f3981ada0838a5ae79d4f6e9e1f07fbc431e007ba2810ef5c2d0f20820f911e085158482d651de746bca6c6878f07e43cbfbde52d85e50f5954379fe5488e4b81739c45123cd9487f93ae2c8e4ae59ebf3e3ab5489aa7a5831b55ba5c01273d68223bb88a7f86cbad335c7aca48ac961494a00f915118382f1a17ef34fe0803aeb778333f68a25f50d2bd290e1d9987262c8d6abe8db255c4f0b0acb2f9c43a0b878dcbbef742f182503fab150197e35b51fb18e551d14175f86e6219f67b4d20162b8bf9b4ad6d5258854037f063fd61c5fdc8a25e913115f499af968aa4014098ee0804a13c55e85c7b01628eb5614fd935ed0af1392ae6ceb289efd715473e5b423ec56d1afe85acd2e76065a4a6d35cbf7359b76c6962866ddc3dfff33aeb5345ad859c5ec47f451f5663b0a26d73060cf781015335f7c4ac76aa3a1fb68d8b8d39cdf28e96f5131cf45b18700ac5736b57a551099683edc385808728b0d9617ddfe141652c00918f69d274883045e90c963ac0bb428bfcc3b8d7b29ef2cdc199cf199ac32e30cd85f8299773d00476210e020f49da73d8348c62e92292e61c7cac2d0f9fba5366605d8d2533f313077f70f325805561cc73b653a7acc7998ed37f6602e0b4a50eedcdd5da00b45972fb133031a63e385f7fd28ae5d1039cae9556a2970e18aee8c17a21dcd36b7fa904115b56974e60d78684904778c6fcbd4ffa43c8bfaee8f9ec8db29a60427e266fe24fe0af9c9836f495849f4710f21e27c80c483869925103a6252dba89b725a1d6659bad1935b0cb6bcff1a0e059c06f9e8a6017272ea36c1d2cb52a4b3c4b5ecd5464e747768549dfc7d91634d1895a4dae36668b4450184b825fd4a9ca61d03add78dd57b47907ca2e1e23b0648c225fbce9b0ac49067fc8fb27d2a6028e5d715d41f7c2b76676ce9d475931d4b80080434b4e582ce0e207e281edbec8811e793c8a786c151bf21023ad85bd92a3a5e3d5639ef53f01597ff30fa31d73a71d1faeb42c9f245b18151a884de5e6fffcb30fd42622d7b1707d6981128cd6560a15bbaf795e14fbfebb9145ebd9a2172db8402fb3b2a73f6b66e94414e0fe1a6ed3b6ea8d345b396cfeee0f4f58766df749727096c1754cec27f28ca0fafa4a170dcf1a7e0b6a3ce6764026d81592a9bd73a0bd35161487f310f0003e47a5cfa2b919c1a24d129bc43f9ea12dcf7a4d0a85b98a448c368382872c0d646890a1811c0de4b03a665406a0a3cb19def25d8f927daa51e37b947af342a507ef28a5c7179782084830390273a0d5c5a2f08adc01b50782ca00c44322b4548ecc790c6fca705e7dba1de07612cba9787a857633bf5733ae5263e29e33434b60c0856664b1d7ffef5383d164c99933d1f65fdd5f0b66322b135fc8453e7b2f49867f9af013c996e23798af8a1fd5b052a42cbf912e135afdea31beffe1da2f0489159c1c41f061efa387dc9efa66028ade130528a927b1aa4d21a7c942d35c08625d3741f65381a66e6105750d2c6d3b6d76b5a3a335b6682b072eb23d6ab114ec85c5fcd5f79c392588b3ade826a2be4de62b4b944ea35434ec09ef2c33e7d6bebd17b10603d153514aeff1706a302db44a4af1fd4e3da0531fde58d1cfa350210903f7e77d6dced6081d09fa10809fdfa6302c6b47e218551c04e6644124e8a4beb43115845ca1613af476cac1becd36667807f7cd693fa12f61eab7276690fac0b8a9b835f7694ce2e7ebf9042d4d69f9af3aa10d14ea91b91d360d99f9d245c2e8c53df59d4caca1c8d28c869cbfefd7c30fb6af9029981d44a150d744f4f9b9c5647c428f66d6422af461d113efcccea1ad9d7e4ac96e687b9e79e597ee3bc652a72b1a4ca5671e95d9875cbc8343b71c1e2e20497a25dca6f6b443d79a68cf3f000cfbb718a2ff05315868afd459015b3ea5357bd02e7abff469ea6ec8a0a23625d0a6cb8b9122fad5147eafd7e306845f289a25c181801a05d16f5f74cb81f4aff6cb9e0a54972cdaec467fcd39ee8c122fa1ff6e7cdeb69e86d2d9286fb65c0ca2109c98ba7f988c81d8c938755be02b3e4a56d12df9e29e998e781531f2049a4eaf7a635f056994a004641263b7d5f988e7799a0181afa3e5c5f8a9c5a4fbac6b84bbc40bd27cb3ce57bb0d412ee39a7c003cb9e0e8753986fc38430d1dfb19ba1c36379162a72b01e0ef933699eb1c6d6090e4fa6f3d605f01437be65c6794944cd48227063c61e435f28b60716b8139a6b702251082ed6d2639c7375fb70276ae1560779cae025d7c96892fd46509648c881c8a4e6c88c0ee22178f76809dbac3af51dcdb601aeaee910972c94557044d76b19c0d68493d062626f58a8b3b1b20034c7c9c982689f54c8c253241fbf41b312cb6e19271c2d43a3729d9e92bf1a0832ea44d5cff20c91c775ac4a4ddb18d5e628c9772418c46c928e6a4ab10fbd398e26b95d328a5637937ac86d3229eca5e5ec90830628a9f84f80bb3769dcf36cef1d2007d9c8115de09238dbfcc7c6376e57e76cbea3d9a6a0261a27edf4f20e9ad1cd1ca081ea4d6e77d6461e54b6547a2d8a1e8dc5f8aa010a3172cb048b993958a9d8e0462fc7a1006c5a87df697cf73e393289ee30fcf624251021f9cc185a4c8d9d08f7588096504d0067b1b0a378ada94337af5f0fac87663722aa764e0554c7b3811853e957edaf4d7a0ce9d75dc3086b02e23a89881af2dc22052d9d31f672a72a7ed5a8ce4ff8849a9d8e9c1b80b552aec7abbac928ab15c08af0b30778520d5341693b3def3e273a92b0515d3e373bd51c610f0994ac8077832698d55fabeb19a7382facacd92bbae4d116bb582c501eec2a43ff10c3c861270715de32c77687884fccb633af262ffb76931ee1aad21de625803da455d2cf30c8adb5f9fa50785fc4217252f3568bef3bdccaa1acebaab7457e6f048ebd0d57e0c87ae11717510c994c5cf27d275b76091cc77c51b15b0870bb6353f329ec69dfc2f48e70c638d3d4488e50aa3b41f73085e49b3ad4bda3572dee29c9d6a6a7357aac6c948303ad93f1d60b3dbbf779d07bf9c8df15dfc05e842860144a8622e491b770a95696f386d0f9c5eca6f3fb3f08a5cf81c9cc64ae45d38cf2cc5c8390c0d6606a1d99c97e3c58f84bf01ff77c9e6128697d889b6843ce2ee6f4b17b8e35f92965007f9231b842f1574ad77a44b15f313ceddf483f093e125aaebbb8267692ff0f0c1d41164e734d5d5e53f801865a9c3d15ff963c9601d3023b222272bcccd74633eb7c8c6a044d92cd801823351b3788c13822832a097e9782c763ec2a5d57b00d008e65d8977029a47efabd81603934868981b2f2708864d3f6e3711518eec2c0ce9757ee829b5138ef68586df391e338be81c45dc0688d392412abd8c00a61ed81650abd334ba6c312c9bc217c0d2e70cd5bb8dab1c060fa2c901cdc73f77214b16e1aac5f2a06883d253d9053fa8befa6dafcffffa5f36948ee037bf904af8d7efd1e1badf4ab8a887dbdf3f9a4138fe2d4447525e3fda2a400c268a4481b5f5f1dc769bc7e0f87489c9f695109d6ed5fcbaca22ba65984d87c20f1a753cf2e226e33528227ab308a592113490202498f363cb4e8ad9504b666b27e4f26647c900e23d02aef39939fba3f44fcad0cfbb3153f734027d06134725d46518a1832e0a6dbab071f2ece65fbcaefad2fc68bf9f1165e1079e7dfb3b97119369a6301d81ce4e10752a08fc031c88aa218f81d24933a40d9918423cf582bfc2310129cc787d492a415023c44c85f517b2a898eb14d90d34a63cd0fdad2d06a5839ecac7c76abc63f0a8be765808682cb36c5a528522fc4ba4de7afeed472f766f317c5240a5d9bf1c3b4c4181a6e9d2fac526676bdb9f6b53e5c60985c49e746483cb7e71ae61cb5721f247c20dc115e7a0d6c83699dff836c8e6cbab924617768119ceab0691f13d3756d40a7f83742957ec306e3bbc23218469e9a9f81266c16e93ea528380f54c1cf9fff002c6bb18f8f2d532aa019f7f5045d6e742e7d7fee747546ea1577369c16e0e41ef242d017ac43dcecd465404482dbdf9432ae11da22291c6be4346cb1cc4a7c50ac39ccd354b8f1b38dba7f62a4edd9037065c0ef4b0c4505a8b6f2c294d0996d28c5154f5c6a374da83f83f698cca182f5521ecc2941ec61cfea73226e98d8b181313d76782683cba7c312e2729e86085f9f4001743469e935afb92dff309176bc1219dd44ab74616b5580737a98e58455d31443bd3f449e184af11c88c7bc5d031bb5b27566c218d2870bd01b042a0e8868329e6d45f84d9e1ba2a72ddd82d42d3156c1cb946fd5144bb382a1eeb1c2122a849cac6ebab9389b58e14543ab9d4e8f26b41cd3d03a74dec64563bbc2bc974ee418feeb5271a73c92e616e27e670d8db3abaf38a3297533866772a14a40f7f5e0986f820a4125466e99d25e744211d7b26937f57e3bbf0e581ebad763a0206e02083559fd8bc7b273bfc419eb7ecbfcf791dabc804f146773c2c61fe8e58552e6616a00b9eeec1a81384dc73a09811bd5f504407e44cf8241849054555653aa1c84745551418543539445075c0f7781a61ab31cadc949d2830da1831d3b9e83782e1b837bbdc13e811f42b97bd2ac40beb3bdb58f45832b5b26f2c9a71e84278684a1aefe16983105f479ab70f9d527fe1d751e9acf33c35a8dcba9ecedea27c97e8c63f1d946080796bf3697e123c77813c4719d50ba35c7985029811f7dbf301033e5200eb3b4fbbe875f1a6e3197b5fbb3b89c417175415e86d8a00ad768a077ef2026742104b2901ba22406776c832fd42f5f7b01b01e2e3fea8fea94d9685dc45924ac5c141e68cda6467f6596721ce32e5aaf2ff104b56077edd8dbf8ae3ba7c4c0c5ce2eb667d781ed95bd41966638bcf7cbc8de2fbc4478250ea4ef459f61df26a1711f15918d5ebdd942e17ac8faa6913a04a8f0bc0c00680f5b9409ec3c1edfdfeed46e7776c0ead78fe07ce91c5af42ad6595dd636dd25a2cb0890ef47009d01c83ed54d3d837b9f5e01dca3b6f7817895488bc8714116ed8e8f80d250cf95f544768b766ce1f5a659d11083f516207e394479feaf29efa6df2bdc07545de1190baf49c18cbcdadd401d8dddbbc4ebc1e6ed9d76c61b3cff961b91075d200964dd5a2eaf1923d28d2ac0c1962d17d81b46991fca6a53c99143e8b6e205a7cdfbd1df5fea86cbdd55b7b4a469f0ae66f810940073b45e839da504f25ec7b8158acc5f0306a2a76920bfdd7441250be90cb5cb24fdbf4073adab293d61a7dfab3b464e4291b3ea6ecc6e7742d1f1699a397a81f59eda805829f18b5197a5c49af0ffdaa2b31ffd01e6a21d766ce8f77db34a3979affea4cddbcd82e1e35a3d9041b759432f23454e363b5a34ac1b4a00328eac0d45b0819c12f9f1b03b122fd6662b8b6747a344655e8fb639239e092a930e861988669d050c1bba6fa807a81eeb370e5a4142f7e54361d66c469a84e8ef2438bdc60f48a5d279ed1b2ec69393320053a7b03cb0f35c9a575839b58676566d4a48c79bfad7474e431f3a2c7794e690815c9776923853f5c347e303b3e94067f6a41976c0f63640128fbb9c4535192375d59df22e588d3b4344b06ae8377982f9de295d1cb246b012b1cb7445619d44e036a17366d5b3090ba4a07593a4d1e9f8a47dc4be0d8e28c1aa5ad9b1855ab88745859792efad76484fb5c489374c01b0e69d4578165078ef55ce12a949c9acef73a851e55b3167a03ca3e63899c5c37499b4465434412b2b7dc5b6e29a54c4906be067f073b06d12396d8d1db3bc618638ced8e1ddba0d027f87f8dd22f65aa91e94b0c090ff8973692c57470d4469a98803a265b9043111d6b39860e34e8ae0d831a9bdc690b0d4ce47eba446904b99b92a090228adc0f97ec152840824bae143d80a4075722c2a1328a42048e232abc3072d4742913f6ce277870c3912838e7e649172d394cadda9a4e9db4430cd3a9294aeac8145b44698a1dafb85c2b2f563b3342f065891d229f99a5176421f26172bf7293d3821c8ab8616ad1a0d2859316549250094886490b742002628a49be84131d62521347c45dd9605a4c7124f757a197d2a09da4133154da49c629a81f9e8831a589885533118b498a542c0a18a4b03264763ee1270d86c839445ef1871fbbd341e4f57a15c910432847e06f2f24824e2c6d8b114d1041279987748ef89b6cd7e528eabe80ed3ac698713543ffeefabd935846ff31a48f53f7e971cd23be1a5b64fd2aa5cf8fd467ccda61350b189312f7a0c157ef3c31852dc295dec24a124a69adb516e5cccbdee5c3a23cb3e859f2acbba23c9f7e9017e5e8c13c3f28ca28ed1691acfdf91b7d8ecee9311f2017e7d92d87a01272a053da256ed5da819f13936449322a29d532f92a440ca368738b544ac8719df83872f4f9ee0e0e0f57851584220fd7fffbcf69654d589b7536b36c9bf3db49c772cf2d72be7a9acbe50324292cca20b8196c5251391f6f653e3e3d2ed85357ac9e1e9f1e1f1dae3f94f567d03eb4e0da64b3dc43b8444eb11b854b5465b90e757fc66ac6f3a48430202017aa7b165552ca949a7adeb445a058fe9418c6226d8274fd3f9859e082f21a266bf729364b7c22d59035b6c8fc556b8354c3c946498b2091cca369e4ade853925cb75192e47a9c4ad337969494661e37f91acbbe7ccebb514766aec5da16c15f7af188baeca6b5da050c674bf942a65fd1dce13a9c753aa5c17e50cb05637f3bbab48cfbb1883cb19e584faca73b94fddc88f84fbd305324dbfdf8ee7e3759e9ed27bcf504d64f26cc7fb4867900a6ce8aa90c577bf8e4e936fc9193562432ed274f5837ad2788b8c0a22d02ad784a3a979096e2572f2bc6a50f28d3fe7e1231ed2712519d7d7ad280f2079f644449b1dc6dede4dc2edd7363ee0704146fb0e004049d808072708732271688363084880b5c1bb5512399dbcc361e42d6fa288223a804135250c147171c41259890820a45808070049560420a2ae4e076fe80725682ff682fb588f4c125201c26f0608108083ab1523d116793f3c192d09932c1e5e65949ed945d31b8b9e9808c3b946573db88b86deba4971856da171929a8b082100f1faddea2b7901255656fe1c47ab130e7cb349f92a1cc96ab5f380977e0b1a813bfde3077c8fee4625afc677ec996b2a58c29e3b61a4e16db28a9e1e42d89bd8a922fb992ff5459ea15ebe6735abef4c54a8b61b8f4e15db16e3ea715e6765eb16e3ea765a3c486892b29ddd5dbb896eb311b25359c7e7862fe406339da28a9b12566b3589843abd66d8d57f7ba97ee39aefbc6d30331f783534c88375a2dc9c50ee631f2d7ca5c6bc7357f3816a01351c661d822401464de70cfbc613debe63b05155610e2e1e3bdf45b6963b8f44d484185158478f818e3b60929a8b082100f1f3d402c96092908ddb4763e38a5d5e3ead99e3c613a4195c85556b4311c911ae7d8707b70e5f637cef9d6e7b4fc87b6952d0f62fd56dac63172e9c3a6db397efcfed8f381c4316380e2c3f8f2c6c711ffe3e7c468b17c281b30339038664cb612e5712c4ab5205968e14da5505d0ad5f5e8133498e59c734e39256a7ea89fb2bfc26d6e0f7fbe6fa977fcb9f20845eebd78c853af75b8e21ef27ba452b8478b4031ea35199b19a7699efc6a9edbfc20b7a8ce9b1eadb09b34d623d623d623d623d6638919fcb990677e7aac5a6766eacc8c8ac6ab54f3695495a752d5aafa5a594fc363cda854aa1955ad5555e1cc4ccfad3275557dac64eef7d4998a7b3ede089a41f3af2e1f8cf56c800522492e4034c4074df577b723fb0cb52da35ef75c576fe57cc4a4ebd08fb1187def74745c0a453b8ec5da66743783ae83f5c07a603db09e0bebe9baaea3f4530de002cbd49bb427e55d4a611d75f504d119a59424a0e6cb9eaef64f6fc3b5db55c5a5e4a2e29ae29a38887b7a1d96699fca3c087924feeca185d627e571592a7b992b1e8258cb7efbaffe76f110ff1ca77a7a2a1eca7a64578f663bb4ac8168eea8ef855c7f6a9007d603eb81f5c07a603d45a8e69c74423cfab51e5c605c847808f58075af799d500f9810a52f04e322d4033e650ab9640a63419e37c3eb21d4a3c6eb57d4d1b8a4a22ac42356c9f4857808f18854327d211e714aa62fc4234aa62fe43f144798b7e806cb54fb524f69b066b4116b35a306cf80319a19d57c1b0f0613b647191dc3c9828739373c20f7eb976708fbc094dcb98b6488bf7e75f2a1d7828742aa88844fbecd091b7c3883ecca1f1c93bff8de395c1f017e77403ec717105720414c8585101e605e1d3217b2f61fb57267f601940b33f919fcac89b81cf1941dadacd5aa79304a29e5e3104d19e3cc44ad0c6f11b24605d73db674e9f187a4bb7728a4725de518b190f33f29a55c4d6ece395b06f6930f3b06c43c045f42af422ebeec2d291b2eec2ccbb2ee96347a4321a394f1e1c76c764f59dd4b438ae18c734e192b919a8fe828a9a474526eca0aa108527a9379e385fb7abd8af4d77e6f8422777ed6b13bebc6d2e6a0924ecc79cb5f7627a03f5c79283ec755d7de56af7af199bd36a085ce8d25fee1cab59d066b650823b83047a20d86b3c5fdb1c132c54313d7a146e2f261076a57552aec4678764210804e003c0c801c0f70dee6c6c60c168d1a3534ab1919d50078764210804e00720080bdc7f1c0c68d4d0d1aac193534ab1919952b0de07a43fdf27b870afb174ed590c771007cb8fdf73ffabafef2d643103e5072256fbdfc490457e6dd8da490ee9c93356302a02cecfa5aff8183e0ad17ce7b37ac771a5b8dcd667b6d336c8da5b14ba28e733219ec25d2fd9cc984f523f92a0fcc7fc8fd3bb12db93f04ecfd02c0fd3aaf16fe2a08f8bb1fe08f1500faeacfa1af2ab91f00f873e58fbe98723fa62f0f27c1c12ff7007f2c1bf8bb373446a54aeeaf91bdfa69bce0929c0cc682658739c5ca9e247faccf9970fef4e544d1628489162339c779da46092b1f4a081f627782104209258452ca78bb2184b13f5696527e5cc4cea4bb48b68c755fb2f69fc5ad9b7f91b6fa972c7e16f723f22f31d65a3ffe8e5a63ec62abff507cfb9af656dbb4cf5f7ee60dc5f7f78fdde590de6a4dda2c8bbf23239ab033f49fed354d6e5e670fa2a0fdf6d11bf2686d7668df42675f94e96b4d61d1d6f3c8c29c123cc61863b5495ce787eccfa5d67b59ac7f586bc6d918331a792009de5ce28d5e12bf02693fbb57d56015685678067f2be3a4144e8a37765ca7b9f8d05b5bd9d6b67500b9ff27f74704e4fe09a5e4fe8d8707f248ff10aeb85f432ad9493fe9770e92e0b95b4cee079554780ebf6d2e4e6323770072ffe402b3c41ce449c18f50336824b8820b17b12f4ec09298600a30be88410a1c98ba643a0869a2a20c1f7670c28909b8c8721012657081254a64612204114c1491e1700497314950c044f1c28823213aa6e062c911182b7a8022bb21c8045070440a131643ac6088cc06aa2444033c7851c5952852c00394d89481269abc1c1501430737d410441a0589824b145a74b9f28351093224428a928011b3041035c0f00512599420b208d3d4440d98b20f0851e22206263f0cc1d445936c86299cdc2005521457f8942058204182234a629e9e803012928015901103199ed4c0c49523416820020642281991850a80c83c10c1100242192490e289873161bc640802c58a952426f04288271e3223428a7e10b32504626021a2091d64317cc04a0e947c50f2e203530683101e2a478e5001156378e08bacc803aea0400a2f5e638ef840f69a4004897569428a284370798d1122450b7a300289d3135d8469268448303d2801032563ae98610733a06011e3022a62208687322a500328548e8cac60410a74102448154a65c8b083172b53c40491f1218c327008c3c3ab8c1c0419120302cc17d891172041060452011aaca060891094a08a12f42948982527b61c016182299c082384014ac038c9628b2e4e98c608228b1072440507225022850b198e5030420060c4e94a1024703a32a585083283912f8878419519a4f8b2839019d0508694232d596c58e245080c579ea822cc0ec0204911420c136e6025071e9488a99243972008a862cb6bcc92151469226d90250c2d4250e408930e5ca6911bc298000c16287ae861a99708a192444597264937d030b21e94cc0086a631ae608283a2d7eb0a1a8c481241920d2818454bc610a206482c512287a42df48b294d9260624b1450a26c7103211640f2822dc0e0220c185ca80d82c42c940c299696805902860ceaa405089a7859818509ba40d2346419420c097658c28b2bbcf002032988e28a0c61d45082221a8820900a580b580003244fe010a50b0ae4a00b2f72a8d2258a105c4030aa68e294c5abe989305a8670a2871c40a9e2431522b22c608715188591021b94a8c116418a44602446162550810e3cf8a045103244e902851196d7103121d6c88820b86802050a2c289620b20b27312f38cac2440916599ae0181bbc404a11466c5802832b454a926220e60a11351809c104b7dc8083123d7079ca418a95a21a3ca0850d488800065dd8500328e5cb13276cf0a50b2d49d040480198280204465f54318514ba04b11062c41364852a8e8001858b112cb1830ca2c21a2612b761fd5c52014228d257a5ff7ceb5a9e1ec59fcc40f42f0310f2c4eaf56d7b190062c4866bd4a9ab0cc430b1638c317a2c364c628931c6189bc3e28d05684a8d4dedde349b628c31c6f62b31c618637b538c31c6fe18db9ba2a4f2f57abd86b45c39d313164e38538c31c618db63d2616c8bc5628c31c68e58628c31c6d834c618636c6faab16927c618636c77dc3e31c6183dd6ee4d31c6181d4b8c31c618db9b628c31c6d8d34a8c31065f23b5d1079ff20fbdc47ecb3c8c0ee4e3adf942f1068e9a69acee041df3c182a7aeea6b79296d032e6b3d1f9deb056ace55bd7398cb867d3afe8bc29e33755c208956b6fff1060abb90c46704ea23d0382841152f0574e005fc423d0abf70bf0341b1c3aea8d9a31f0186d477ff41d8c549f4a7f008af0b1500952ccaeb3c9696f399140b23ad9fccdc4de6be9ccced648ec35ffdecad77b3e2eacbe9ffc3270fc9fac22cb2ee402881aa5db5b5e664edb9306e670dd5d9ae9e567326b9f7976e37ed7277c3f8d3a46b16995a361f66d97c4dd3bca9699a96414de62abffe50f654010db90f4270f335c242a0ebb98db24d55fb5766d50650e17c2b0e6ee7fb30cbf0d73fed0fb894bfa22679a8fb21ab83fe7deb55fa5f873fb8a4699aca43691b57513242ae7130763007c5eb75de388b53efcf35ec54ea61a78c32cb1f8805c4cab2efbaaeeb5c447049c77cfa032ee5a159bdeeadb5288f7b2020200e8350c6d5991fe44273d3aa0b66d72d15b01c51f8eb8ca2f11f50eeefb7f16a78349e2533b3fa7b83db1935935633322a9bfaba69b0e358ef9bd618ead88a53fed2efbd25f84fe7b8b09ca4fdb75adc67d787d570adae00d8b89774d2ab933ac96b9e183be67cc6b9a5549665339b2964fa538a52e67ef39c6559f6506e8f4ab9dc362ffb5a2ddc887cf27ce80dcd9773ce29b506cccd9b1e8b4654e5f9b3429ee96e2bb7756e4a3deb80de8ad95076429665866b1d6361ce107df9b66e77abadfadb50cab3cfb6cafd0e2dd3be7bce5ff33cb56d9bb6695ced8af2fac8e557efdbc9157e287843f5b9b795db7e4756bffb8da39d07398e7bcb59bcd5cf6a26e914f2efa350ff595cd4a3aef70d15d9984251879afcecbd6671d2b7d49b165ae97d19b723be26b7bfbf63fb9bf23a9437c4ad7deb65ae39aa270e52ce1f921f5fc628fd395fd8262a6a9223a543fedd1977f47d1a893a31562c44454f64f971fbfedeb40c12e1ee840d0f416fc51cce5badb56be1dbb7b6efeeeeeeee2eda71221ecb1b5c3292d44c4679dbbe17b20624f3bea2fc6ddeb7f3acabf2946797fe8351705cfc290cbdabb2ed6414deb687b2027921dbef85ec01e91752545b23dac9b5e264b9da90fcfe21f9ac2a71b55e61b05ddc5d0ef5c703dcf8fdf11b322d0e5307e1b2f0a65ad0e54a74534a2985f31b52a1177929a55d67cda66c30aa84d9779c55ca38247e6123a636a3d977cd3268210a53bafb20a594b2e99c61fe9c90ce49a76c17f49c5576cb870ca831ce8fb2bb7b4a28a07c6be1436f4d29e94b2f6440e77c2c373efca0285b05012e9e80324bd84a923ec4524a292184524ae9020b21fc0cc287199dff01941ab38c62222e4f1ca5d8dbfd4fb7b18ddca494524a29a594669ca49452ca715c4ccba59452fa284e72f25e95aa29fd996512627f9a84b39e4922056fc05997936661a2ac358ca66d36725d8c31462e072a8cdb9fea74b420bcb1ca7033ddddddeddd3eb35ad1d034cdcc8aa686a6a6a66635235353a3ba353535a91a545753538382dc0ce0fbcbdad4ed76093fc6087f29c3ff31ee1791be989256b924fb31ee776be56a13d68f716b95dfdc17f726f539a96ec7cd55c940293f76cfd9dddd447146664675676666666668a06690b02f24b55218ad24810fe3421add61e23f5dc748b47be22f26b9538afdbfb834f8932956afa2dce436a594514a2923b5d65a2ba594524a29abd69aa6d5aa4929a394524a29a394d55fc6eaba816372aebb94ee70db2cd77528940f90ebaeb87ba94aa59a2a95b55beeed562e3d02c1815b3a4529ee72583756142a956aede4b82d958acb215353934a7de62c9c91a87b210f0b8845e33432332b9a9999d58a86a6a666068bf55e6ad4b059ad68686a6ae08c1929b8b3c3730e0d1ab7c6eabb2192bbe849eea2278a9ce4c60eb7103de48151b27b3794524a2965ff00792411b8b4820f904b72dd10df74396e6c441b366cd8a014d7a803ff8b972ff7e3decbaa8675938366b5aaa1c9e13424abcbc1ea723496dea2717363c3bd3de6b87278b033717070240e4ec4c1c1c1c1711c9cc6c1c1c18135356ad8dcdcd8f0c027070e84ff9e777360586d6e6cb40d285f0c1b37371e743a6c7439a68d9b07e3e234740f705c7a6cc8827b442b0f032027009da1bea2dce57e97b3a9e772aff75fdc7e10e416bdb59ff1aca751c3a6e6ffffbd4140411d472c7417fad546ecf4397dfa9c1e03df4db6393b3b3785ea38d7e63ec3ecee293b72dc5fff9179ffee96f9eb759723c8bbcefad4e70f714fffb397d511b0faac5ab99d65feab3b647a676766932effd9deb929e3755679df7b76a772a9bfabbf7767a73f76ac9b958e0ef773656f1407e76fb0f338cf7a4164fe5cb766da0eaff591d7524a2041997e7fc9fd02026119e22f2853fc05598b9be3fe8358be1da1c8851f04a142f49f0e8726a18f1d12f309d4891ea84891e76f1a26824a993ad10315589e953ad7d3881f1bac7e30c4f5b795660f2109ae8abf6f83dda4e0d6aff1d1bc72c52314b98e03eb31f87677ffc531c4316350e83163f21011fed198a8df883163babb718bf0e488266238a289185c3ed37b2dd618238b89751304cbe1036a9f6f20a534081683c99923e58f9c3c1471ed2e0275fc67a83864ffee819575bc204f11176e48aad70f97b5c1f2806ee68424ec40123a432823646fbc368a3a6ea4b299d15ffc67e52d9b195887e719f67bc97f62f66f261d64a779f257bc612426e170c388b5820548e41b38b8fc402ba268c95101fe3352b69160fe6353b98c87ecdf51fc27db2103415641208b91a51c16733fdcef8280e57ebd94594ef1462beaf8bbac5c1b7ff31f5cb2331e136f2179cb3a4743f3b2cb51f31676333ee57dae9c7a9ab71e912bdbf75e8a3afe4b4ffc07cf97d0604782e17e8dc4a2c19df9af9174ac7ee68322f4166e231b42f186cdcdbb8c0a5ffcb5eca73c20ef5cd962fa7dd45a64a7aa578ddb2346308225ea95999935c571dc0fd5d457cb719cd534ab751b0862542fd36d322a0ee66eab28eff79f0e853ae2388ee338c975208849b985d25a42832691416388fb51188541125c1bcc065d6283e119492c2cee672396fdbf1949d946cc95290cf23885cd486a2d59d2ea4ce49b36b89d65d5b2b72cc418ab53e7e9b972f4be4e5282cb45f1ac7ec30449976413e20d162a0bfe4efe4112f7c65b2148a5b46c4ba552196abb5acd34140a85aa194dea6b261daad3bada659dedb8ee76a9aeebbeeb6a0b7fae5433711d7fd4c6ca70cd6ab693d36add14aadbb1ee33448165688594a79ca1155262b905b75936c4730b9e87b6af70abb16e36c397fecd727cc9dbb6e1fa1a867562b9757402f3c18143c6f316e8e6dec453d5221c92a39fb296afe1f37461940c210bee47dfbec32b6f7f2e99276e21e6f9d6bbab86b15b9879e221892be6fcb654413c722347e23f44bc355532332b9a9aacc6a3f1bc19194f055b4eff217253a88eb35b24d22feb5de6f278c3919090be46ea23f7ea48d1880b1bf89c969da432ca967c12e492d2156ff41497abf5f13a2ceaf803b95c2c893fd675d8945c595dc5f195c4fddc916abd978524002897be53d506a04e7361059146b2bf5455553c4af94d02a3ccfce78323730fdb0038b2c3285991756f412693fedd310e6fd5c870b8dcce997b0d0a04e43fdec499e07026aea8f3465e3948e7f7bed83b6f5283fbc9238f78e52dff20f78aa30e6cf59f16661e923f1fbe852dff4a03fed4bf2c4882f673beddb6ef7edb220bf26c18d2802dea3900429d8b6fd4a1af23660db3200f5de5c65cbb3774dd8a97c3a0bbbce5ff320dabccac5c33bc1a8fc65b79339dc672ba1de79c71f6fcfef98d7dbce553c78db75c32aa9bea38bbcd1db3979a09ccb04f33f19fda4ac91b514a1fbf1124e52b07d55607611cacf5ac1b6347c8a5b54304445b3b40d403d2637e00e521f9dd9262114a703f376a02e94eadf7b2589f3bc9feb39b70b8df751ca6f28b452b272785eab8d6e60d26b693fb06f5df8ddc3fc28d99effe194fc6defe0a26a5a558d9bfd64eeebaefbaf78124d4ef7ee5d77fb4ef62ce7d4ecb1575baf65fda9d8e1c8ae405bf1cfbd5fb727245fdd7e52ce3fef32cf310fea8fe23f273ff73216732f8e340ceb0ed9850a97e2e4e2a39f5b0cb91a29fa5fe2b7a9287ea0fcda72a9584adafe614fe50ded7e5efd610fc25ec66ea7f7ee346f8b37df71984d0003b2dc29d6e23fbb733e7fc8c665996d1f923a7b5adeb4bd89aadf95aae18429e1c556b4096b39d45d994bd2aebe393adeaa6501d07b4b90381e3dbf10102721d1cb4c8baef24598bb5b7da16b7f31639ef0c76969aa62a124293fb8326cdfa41d2fd362548c24d769ab4830051e4fa9faa88f7b972631b18e479ddef031b58fee0a5e3266f4a902728561bd84e9297a4a42c27b7bc596adcbc1f309679dfb4f883b1a9ba1bdeeab6cdbc84526d3f7b98bb4fa13a1aabdc0de73758cf714999dd1a89ebf49cd67e7b5996b93c22b8043463326665d758cb8c8ebca31ba0b4a834ee3884da319a1200280043150000200c0a078542a168308d3351531f14000c7ca2466e509a08644190a330088220438c3104004000200000631063640402046bfe893123e32a9c2fb4a74f2eb2769b351aa1f27b2a01abf765c94066222f6aa0922a7a2a11c524af0c4b4a9da9c27156cb3410324db4ee3b9b52e09a667a929b92eaf886fe950c550d36f82aa2ffc5034e304070ec7798ea24ce3796bc7d404efff58be84bcbd040a6ac5b6deec077d63f882a869507249930435fb6068af8e3d8cb821b07180be490dff80845b1c6028916897623a883124ec6c871b562484fccf57717aeb317c0521df88d7b29cd3ffd8a19b6a8228a13eaa05668a8bbb42e680b0d0c6958e18408d9c40cd015746d3c423dfacfe2881431b800c722933027efabfbc03ea32c8e30e032ae21bd8b218d6459da154d66d0895558092e4beb036cde196848b9afef59c43e4630b190601b431cde1a1838abe21d731a2ed8e3f1babcb0ec9b91bcbacc6a555f420acd1f97bc752d7b8461a8817168d04b3e62657f70b3fe73a58acfc981669c22155fb323e8c5c22f7f1ebc42a622456940ed726c629650a6ee919112a449df2fdd1a9bff24fa3f80992917937a9f1ddc45279a7d6284cf190a208380943bab64001b4d9f4e0180aa189ecbe5c8b706f729116bf543f55c00d6d3479f635917b2487d3c66b4e419395ab17785cf9b049c481ca77259ca1758b9e30339ac39d65241050668b8a3778c2ab5d327d9a7ce313a9e2cf062e42c55c8162a6767a98e0aa5c5c79657a4733c7a4b6aa008917856dc9c5c28ff30f708d5c115378fe908e2a96e12935a57cca5218d0415de0af56456fdb8dafc5fe6f612a6f27c2a4dc106348a04fcd2bb03a03c99006562b7de007e322430f17a7efe0956052a41a8a60c3a20cc876f642bf6db6fbdc87ee8225ee2f00fcbc1a2b317a3911490e2853c9b5d1c7bde11204aabe77792eb42ea737de51b6009ff30fd4e269a309b9290bf6312e13fff2e99246f1c463e3a1475da3683001e0314f68c654d62a3443dbc312a01de80b0380e781d8f1578a6057be8f99b11572bfdc02b70eba3c0556fa01b1f1fb80d54091a8c91d005428a9ea8796a26b157eca38d3191f7686236d1db0075e83b3c93310177f58a02e5b8d8ca8aaa0c140ab4f5798710856b3644c42959c62a1a8b34cb806cd868da76dcf047c24106bcfbbae385ae640b15e69e012020b244fe8f07393adeb431a9c013d90c4954775effc45be8c86d8a8cb700c83bf7ef7229af3244fe41b9b16151df0638af39661c339c3ca448cd30969a752b043150ba58d07235413c8efc9df3dc1b045c8837a599c31098fe1a92b8fa8f014c95243ba9aa352f67a0b54f0f8907ec0e986db4b6d2891be7313154c8e5c96bf1ac2d8e84b2a835d5f594113b00b706b282ef94adc4a5c57feb41fed5e96919edb9483a0494fd94e4b2ac14ef9e738eae402202c174329b18614962f9f112d55b22237a7afa97771757afe41e7a7091edcc1ca04ecd1b7aebb623aff462d6e4f850fc595423761268aa21e16201e1d1a2a0ee4dcf67f2f93c5672e23ada29338c5dca9ffc7fdb82e72865d7e699636a6aa57aea55e918b1bf79462297829d4df1ff0f7cc787493286ae0bce7bc70af020f0f52d616e5eb5ac3ba0228e413a12778dc210098c9d5bae0446b58e30c0dca470c7333ebcdd4157d97f1665e0b0ee0ab5ad016c3e1491b9421a098388265292071008fed2280884a963a8319cdfdfa3f13819722a927a4390b3114eefacd000b4095b39233ba0c8f3f65f133607c84e40302a3e47b785a1c8e3fbcec9ba0c60ea52245ca07b01accd312501e75fb8aef166492089f40b0330383d2e287a12de2237f85984a8611ab03d4281e386e5c16ca3b13cb11c6a5a2df5f77ec531a5e0e9d3641965a8c96ee1dbc24d73e77435a4411022af1d02faf6f18184926f35dbca2c044759ecd4f3d74ed531c107500403081d11e185c5e0323ab5f7914919e2071ed32ba1e0072e2ddf8def33df6854ea38cc88ee01b3c4efca3b20fdece5792552e4a96103f3e0f8c53ad18ae23435a0107c7efd10cefb3a016ff4d65ae3df82f68f4bc4cc7ccff54133f86c900df6771fb4a7e91a04062b8fc1c6c892be0d56804f7d08e2687f4fb22fc072c1fdf5ee75a2595c005ecf6f0d3b2a554c92513d44c50bdedb2c2279dba1c0f65e8fed0d670bb7bf1acc9f4f57b4462823af917d8a2ae736a761989e01c5b20e29a5ff8880e7f55c538a78e8f5b001f359b5e52e3fc6054796e4c59e3cd8d95697bd9ab2953dcd8a44865d191c2b32e9f88ba889654f8bdd824e297fc42e6025d22adb6ff105d17e54b8caacded6610e989ee0ba8fc19f224ad9c39f3788a0594bb6a713194cd2762494f8e15903ebde6a63150aabe63954105a667d5bd97bde6eac1ee4a783952d2d457174041c9a85d2e95e0ea5b8c9479afe0203a0371bf4735820cbe09d0ac7120df94c2ea32287f2dd31fef596bd6b407517cacc1cca8f2c2c2aeb0dc66e71e650e21ea2a69f8409930d69a23c5880a44b278984c0a027770e0ce1289da1f552064211e6fe2f019d32610f08c40361917ff00eaf447cde5891083ae6f143578f6ae6616f43489c6e41c47e82b0259a774ca76e156b573a04e77ba3d8cd41f31aba06d38cc95a667c025cf4811905b68b5193ef3b534d6eba667f93d7f17393045b256a4e6297bc166f2807c426a528a3a73d13ff3ec449361d3bb6a4ecd7115df505cea1a93901aa08a34e90d19c1db5c56f1c2b6698a5921d3655aa10f17594310c456a19f8c93cf4addd02bf6ceee61028a7482164085685467da6d1e1ec2ad53ca5f30c1cef07f797f5bb2a855912b16926883837b448523d203f32a525a38c257ed4590495198706155bb09ec28a8c33d934820bad116009a0349a91928244b6f245c9b49ceb0bbed528a5731ac1bca2cdebc05788690cb4cfad6f1a39844c40fabdd0f1fa8c7485e770a606e91eec8162b5f63e69d2e8bf619e42dc0ee5f687e74e234d499d4a7ab52958ca90d7bf8518d2a947c6ce40bd5353debf8c28d1815e2f3ea3ef083f72e3bef62022d805c27e22dc1816bab144e337399fc8ed6b92627708f0749054facd2007516da4fd44a44d330c3ed710e35f8686922ffe600d5242df7581a5cd491ae981b990672c47e052ef1367aa867a74c6a699083271a108b90dd79730007492e6e92a9e4f97b3a1f03d66a49e8b5de36f43b7fd087ac50ae2525bb1a1868543dfca54eca25986a8177aa69dee721d5266d1ea3e204774adbf6cb6060bfa572151df852844999991aa8ae4bfb8ae9c19c1714177d82dbdc40bdb90766f9194f6fefda468b8e45175a53b3fc573acb341c374d02c6d71207d350a71a06402a6c2936261a192927d9e7f61c15989641997f68548b8a9a5cf86c5646567ee16a96144b5be763294ead165a3b029cdc35abc23798c44d78a30d9d3d74eaf4d7bb6ee0e24653780d3c42feb10e1ee6b4925ed543d74c6afac73f5811be0c1880897ba44bc46bfcf03cabdafd5c031f858e3048ad3d392ef41b371ff5e218a5d9e4e20756b7286735e00488169e067836d56e233a2986bb0c985e363cfce76e8ee653f6d962c514aba1edc0fbc46926834c2896f12fb4d03328e950ca553a5148c0c05c44cbaed167a740d2be76c86db04fb3a0c81273d401bebde71086257230111e7f3b3d05e4ed0cace565c11aef8d173822c863f863f47f4e8e9132eeea174bbe57486e73c699d84be524d152c10c8289c2368d6218dc9d68df6593ee185bf65d32b11d07a715f24c7cb201d2df32d49ebddb81908bfe0d2b139d24c7806bd48b79b6aaa5fd5b3cab46d262c2be82e041e123b49f7d593cc14a55086724aa164587e38ee373fe028b6773cc02f5ba24f13f89d2481067b4416d0ae2f2df61443de44f13e06ae85f07722cb2353db1dea23110e67440144927acd030462a5b5abbe1ee01c3700aac9606177a2fc0832a28683ef2de9386d89d208ac8b608bf3093b09f332fb2749bf6e5bf1173f4ea4bf898a60e7d5cd12708eb480fdbb4391b79127e26b08ceaaf29e055eaaae84b5444f9a51f22da6ba784d0064bced24d903cd2b29a47025febd76acd82cd484c3c8955780b7a3456de15a465319751a9e7311e95d1f6acbd568b0610b44d4e68a45ca434a2abd80f41ebd992a6df2a77d05e5d891b245c7a32012c039fc1c93e7680083296ee32c5cc0887e9c4fa2670d007ea98f24c3835e487172636ae4eaef6b1270176dc2c2378137eecaf8fdfcac72ddac615b815ab6115779e579bf69e7f53665abdaa75385dc53cf734399e53ea1d8a50bb8dd756d2874b2b117b84d1360cf3e1468b229c333607347a50a1907d82032398218448b7c657e6146aca52a4b6e3f10db8e432c2dc7e8f95e288174a2ba2ed69a96238c1675cb14745323f021a1211f68df31da7d6fe69f4d498f6149a355713e0abdf438c4a7ac47b28cbb85366be8c41960f5292c148566ee5b22eeabc53d04db4cc019da80e4de588e2b1b94135bc0a4479a97cacc8f00051a395966e27a205446d91f913e678791bc1ab9b9ba2b5186bd52214a0006f719575aedd6da89f2e17d21706b84f0c0f4fc1d69c574b3887a68855440a048613a28760fb17d558dfb21a76ff066dc4baa5b4a196953368faf73374017aaff1f8ad9a5611050b9ddf8d5a5dfabb4cfe70eb3aec89b0c9f505c3d3d97a421243d3a86a618b9791616d2ab2c58303e017b6e5e0902ecf010e795093a02b1e4bcc2b2531c3c56ead68575e705ba5a6b38e66753e46c8af4677036fafa514e88cfedd8060ae28cfb8d347046d6bbf929f91251d416cdfd6b64d9aa7add94179c5f914c3113136b6495a53cac780e59f0efb9eaad0b7d93214327f93620150a6085c474fb6e648223dfe3644446522fcdf08037e9bdbf5406ac4f7ffca8089d6a605c3d863f3ab99e993b828b881941201c170fca60da2c7064fe57bd3666cad6f49a11718b6c3ebfe4dd6253787bc696d33b448a93c69bf7d132e138ec9b62e0673e718230d54a29cd2f6decfc8417add8b88153938eb872a10340cb4ba415876de1d82e678633e8306bd745d767fca63cbd6a07ef39714bf96203295056c868260773f571d9eea7bf2070ef226f846fc5acffd464e7656921dac84432b5c3b353104b0fd733971fbf982e26e365af8e650921492036504aa18cd29401ca2fe3b9c8eaba7d9d6560998a2c89427f89c13ef30f1321d8176c3fbf65f087dd4c3d2af92a4107e64e2805c8df8ef55a101d174334662329eac55e8a8dacc4aa3442ba63ba008e87000db0000b8f7f117825d6ade3a3080dfe052994010859d4df6bd3cbd3be646fadc72837be8d04fc6a29104f70b7ba633c74fa00a660350d1271d8bae84f4ca55dc50637c71caed4b6c4d7854402da3260e9aec5927b45c3dcac30e9466d05a441bdbd26de337c50abd7b0bde221deeb30bd306d9ec5e51e7689b95fc5c6b0ae5cc29579deaffbf6496245752a827eceebe4a2a9faf3e68507e8d8a51a90ac6dc5966ad0c75d5d8317255f4874531486c791bcbd601953e53d7f5d0bfa44902e1d45e6acaf76ffa77a4b5dc863e807f17f120680913acd0a1471bf3a29c45134a4094b3bbfa1f9f1d5cd4908135e5b1f93a671ec23e7b84597f4dd381e5c5f1f6f220e79b140fe127c552bc9f1514f6f46113e9be7bc161650c41fac794caa609c0f1c3030d12b0cdc4043b9008a1ca27a8f60834f604485219eccd973d069ba368c77f5b6641667176912175b055664b4de527ad732ddfa191e8893772088e61c0492113b23fab1a92afff811a0554b86c984cf09fbbdf820cd1b5072b68433d4703e15fb33256c63aeb16ae88745fd034667cd6d53041a2c205deb1355ccbb0b6497f4936bb11d1ae7c8fff38a1eb995607c02c30a20ac8daf8ec999a387f7177e4a005d28bc7474ada3b4b4762d4cebd2c6572eb816a7bd01b329b56991d97de01cc4987a7c1aa683d11af35dccfccac1740442210d701792ddbe7dc6aa949d714183324d0d9084cc2cfca74afe412cc486161bdb0e873746ccdffd634b352ed45edf5d9efbd6d008467e0c20778bbf0d484dacab2ae406a57b80657ed30d63c3c381d8bac1f0c87848405d0382606451d9254594a1ed7c546adc82117b766b0f2f40b151d943f22246d78a43cbc824631964360155bf42b2d114d763c8ba5d5186bd288bc82a7e9fd6963444e2a1b8474579ab463e560803079d8d20f88f09184cb9110708ebdea25d824d5cfe45d1a1d227e7ec272d582b6af28ecd4654ee09eba8bcaedba99ccbf2b659044a235e7b754254f09f51b92504e050aa03236c4db0f97f9860764096487deefc7900598e67799df3d3d49fff78e3069c789d8eb7b9016cab8936a341c7c32ae7aab6e78734dc0a814fd4823cca0dba96c564db1827e30709941dd3022c8b8aa7915a612e9f0528533d6c9e3ec0a6ee94fb6035c7ac672916e29da853d66a9480694702563498beb5cb622eb681b67b272083761528b6ac2276681f9476d10b049c924f069a356e77dde68ddf86a7a45571085305e6aad607bfcc6db6a0fe732f9fe8012e3c01555bdafbaba247a6aeb78118c284370ceae08f10826cb16d7f55d8ae450597438eb70fbea50200f70baa6b7b8f100494da10ced4572f8fad69cfd8686fa2f7e47e617d3d13c6e03d81d985fef0625f77872db1a921004059e2886a3bd50d63c05a6d9c60feb50eb9fffa9b48db80cd0767c238150e8274f3f35d2d875073a7fbef524219868d29a8c70797a16773716962832c8127f061d233bc4cda01b356e0b4d40073605100c9abcfb403823bce6ce8f0f0bee5eca727da268d44609534872872a33fdb7d0a0400b1c88e5b05201ac8fb4e32a25db0291626eae68716a52fcd396c84b8e6197a27d5236a85e9751ee59156461bdfbf4ac41a264f643b7f2b036f361ae983996cd6759c4efb11d193d56b7965e09a030b01d04e1f72652811bc7e3f9421a2437488948141c398cbbd067fa65212cdb43235f19279c6cd6c399624b9faf45205722e4cdaa61f289a79f3dfef286232d004e752a54e07ebb573cab46507615f54396a3837d0a84a2169037e4a2e83691fd8f5d63396dca30e85dde67b02f39d1335b7fc1f6666c95f73c3f1867c55cf34ec8334189cdfd8e947e5bcc56124f9b4c28fe78c3c05ef1dcc6547889d4947e4721d6041ee6e81d3191ee8f169fe4be04306c564521d1d8b692e2d77cb6b45f0bc1df676cbb620f5c465a59530e5adac77e5d569e36855e0a00101cdafdc69fd78cac42b682756cc2df7eaf35404d50572c5eeee7e0330f0758f8d6e6cb17ef30217187732c694e31e3f58ae66732ce30d621cb117067230c5db923484a192647533add8e1d962d08b36bf5a4128d05aff8e57abf05ea7ec3b611d023604b19aa65cfdab53bab284de18cb184d90945952e2b6f56d9e81e5ea46526458e12352d52a12208405b27afb5c7b38ceab1de8bd86bac46b9cb23c8636b2b04c640954a41a7866cbf4e748c48bb4761c952c9e5d474388f21698042798b3bbf0198d51866087b5e6f895b0e17465f9ce7618049e4a6011a47f792cee7a3d6ca8f2cff800fbab4fb91d536b8c8c0c35f7e3ce99885cb8745b574d00b1dca3e4b856d847c9f830e89764181387fbc76f90bb529ecbc5f4cc851109d28b137b95b3a6b18dabb209488dc3b71dad9da463b7d9d6b7d2086cac17ff68e074b313b42ce09a966bd0fe745fc5c186be092d229f8e4278242c999c9a4282bb5e74939dd384f926db13761e2daf4bb32cd13cdc5d962d1db86f091bf393e8911a9d21e845dda99a00bb287785280dbbdf90cf32a5c3031bfbeb7f8941ac14740d188ce988348644ad2a43c0b557e54935ac7a3f73ee0547db9aa73edeeb1524678b45eaba3c29a56d441514dfa959b310b5f124dc4880bd16965f041874df1e60a39e2172d642d3ec63d3bb45df557821af7939df57f6399528dea98a84a6aac5b715ca57473130374ad8f5b0727939116253ec570a6684963fade08608714e67c373124f84e9de01ce2bd3604c44821db1bde4d62a70a33b36bebe1bbafcf7d73540f95d0a2d34ac39dd647969d63061f04bc777c663571971b3ab6f51c88e83fc5219f3628a073bc39d87a51b4874d616a41e93054671c01d9c372f91e8a4db40333f9f645c0529ba975e094b04ae448f3aeb90f093304537a84393ed1915dda0558def96badb283af479464ebb8ae549a5280bca38e652c711356b131830ed15ed67cd763f77cf13bd43ec855e4e0ce1577db6fd4a426bcd23963ecec90984e49e21be4f2f58e48215804f6dd92529c7c68d4769b19bc93fd462927f1753ca8f6a65f2872908899d4f131d060baab92a16cf311b0fbb8dba224c9ca9049f9d6506b8bae59338c87808f6ce88a9904f0458507ea6a33437274b075e508782f300a9270f08340adc1a3e91cf15f66758accdee91cee5822441d7f98eba72dd53a80cd616e44fd64e47a3972660e31432f35365b6919297d9715193d25c3b301f39cf979257a1209ddf4de2802d3b129da1142d228afa5cda021c36e49e3e560efc42071f0c9039bbc4f81aa4144e97f7cb6fbd219f1f6ec50824d4d870535330064f9810e060a13c07b54d82c0302351155c8458b67848a9c1b91a00e51a3e7790ec102f1b7adf7cb923398761947ac629154fe3db45768d60e90c0cfc6725489591fedfb0c8b12c36eb64b2de909e3115f9f2d1199469bd4b237ebfe0aa984533a4800e78154fb067dfdd4f6eb451f07905d64db88c8e9912316930491345b2e8f301f791d37e95699b4fd3f47f4ef448e5021369348054a4ad0045c788fadb39b3d919880466a0d482c56b98faabefcc90409cd58a7b86115d22d3d0361199897fc501d36c1f82c388a38382e612774e44b3c4bc166d6164f4ba3cb74f70e05742cee89141ca2177dc824d8d5e2224e7cdd73ce06f463c0b01a435fe8de18f3374f0fae1425282eec6f03776481a6102e904d4ce2a4a79a6e2f67a81d1305f4710fe389c4ea4e78edaee6be679eeefd8897787de295d1b150ebfa91227afc8811d2c67b8ee40f8c70be09f6862a9f966bbd517e8416c00ec22f660d6860fd8a68cc01a4ea9805c121b55354617022a8658fb85e651509c1c6dd9cf400e997738666c13640ae21fc661506c58045561f30cf091cdbd0d41b5b7cb2cfc4ed8c810928d0405a71ba4112d510120e058f717c386e40482829dc4ee2473b79094177765b7230113001d43567da9c83a860795b41eb7ec45c3a639405a70c47a52e56df074b40f35b4c0c357de9343eb67ce5e5d4a836d981fb780661b9a2e0ff1ac33d6edb4642336f32c6567206402fcca2f33f454e2465fc25e86522d7f7eb6861f942c57b397b7d5832ad296e9ed82e3fbee22c37832fc3730e16521684f655e440f19bfbca313f5c44159208bac5937a5bceba2658f9761ea811d02e8036d0241a64c6a24b6f8661213ba6edd0cd329bb8a58f267a912b337e6d9d7c7d2ce61821c05faf0bb30016e05532bf62bd2cadaf4ebccac78e3f96e9675ae99d47d91496267fb78c23fc0da7a05401133efb7c4e8ddeb7b4de4908c135e1c42acd502da1ea951cdad5844841d3298fd054a3808852874da6416aa0ca493b3368cb25d15a4d2b9975d40d7db40c94048deb9ee544ce810cb622eba0d36dc5abd164312ce5a19e17cf1a27d428b7036b1414acf0254943792bd2c6204c77cf20121abca192a33d2009575bca3d327ec1e310610a6d4a01871779c31a05a9cba8d41f35f217b1d0bf7e825b95c571be03023b340476ce101b5a00aff7c24bb372bcd308fabeef56a0b511defc0dd9d7408f2e947eb65556d8a0ecaa045a341f0c64e7bb70ade975766b7706b8e5e7c0098abb367c3d16d21fc6739dbe5924ad2d6f2928749c7099c61703ab1512c4ee732e522dbc413170988b2353e3c76e809ec60c428330cd2b49257b811e940979f77c72a316c890678c2f6f220268b75be4bea46a86fd9bfb956a1076056fec12f72b770fe315ec3e0a6d00c9f08d1ab519d0f8799d11050cdc4d4fc091a422537504d452e01678e81e29eb84e90e813eadc56aa4b2b52d2860f71bb6523b6f21b62355d7564cbe0ac8ec11370543cf55361b79f7ef7810f57064424dd4662315ce1460cea3dcd1faa323a09ac14432bcf23a9588230c04dc436d4687bf18b3ca80e6fd31c9a5f151f99b6799c55a6c0bf5c6218d531bd94e138d083098d1f4d0b3e9c56c4c52c97dae1c1b07b2a0b1cd917a34127b006712550cc62631aed5406bd607f7bc8e62d6d47285faa5cb4fcc747d298fce9ebbc524e4647da5e8f048bfc40da5310173f9c1bed06349e881c2b51e82a0b4552a7eec189cbab6fca3338b4c92c185cbb379603d77a6d07c90cb0f661aeac456f234a449e31e9edd673d620bf1d4bb3319bcf4480b511aeb9840c14e79f21bc4b572201e3f61525c29c2da87d0e93d7fa2423af48080b7b89c3c90c07c88b2ec8c0a227e2d8ae1a3b50e20cfb5ef54fb6077bb46981c97fb0770d8520751edfd26b28e348751669e6a2c8e53b41ccb5ecbe8080efc882505a55d49f3c58a95893b2b49238e4fb38c15fab09a4300978d62ea6b1dfdedfcca4c92e6c552eaf1ef776e50f1cd264479e1e38d019da2b44deb34d869b872d6344698806cc8f71d324d8024494a74c5c269acb5531665c048bdabf525d1538f9299057b5fba04e4a8d32ab4a51b3d1532be439449343a35545aca8d3ccf637115c29d9818646f989212cf741ca4da6d1060aca7803381324d60d302fde0c43bb4afefaedafbca097e0dd498ce4c32ab4688895a6b0e8204fe4da7cc6d267cdbf25e2b0b311b25ad25280a0fa57dae5815deef70e9bad88c4377f3afc6ec07a12eca7c73204d351bf65bd67b52280f20606e320f8f4cc3709448832936e09ef7cb2124dcf2829e2c2418e0e004ccd3022888f574f21eb33e379d15c56f317df1f209116076c98d6d9b475a151eda87df73d5aa1db0304a405b50bf6a493c8a8183b28efc586371005d11b1eb6ea06d89f7a53e818207fc03051edf76f203771f27565346131ecf1cce5855d1d7ef89bec973e6e3ba1928f776bc01ee362872dd6d18b27a580bbf5b2e801818c1f91f8ef7a8e66ea151a4fe8df8f9026df95b956eba1c4ffc38d9bf0019a7c0105de53383cafd7d9fd370cba7df64a280df72c76e870eaac1fd7791b080d043a33f731081ffa25a4c10735ec993e0dc15e7f2dab136fc7e05cf220e76934755a4958089417b258f35d1d41124d0f7dda9b9628c8c31e8e9e4fbcb5a372439bb5a2893304b6c0a7118e36cb4fee0b94ede4703e0975fd2ad0956981fb92323f3fc439415b1e463acc00ccb2d189eb34e4b914844e2e46c3b3758a7546514a18b08d2a6571e295ed96caeb89b4607b0cc9b75ba418729e11257a0c3165a34cb31765bbf81d3ea5827f25473c0217ba396c53064d654b2c80958ebd563294768d30cc27690888725684f6dfb9f3910c6f91dd11a97472f05b2ad2bd3b10f3dee802b458bb3f5e3d29a924ddcb927d83add34fb63f4df39dd9b00007595fb7c33acc4b503d7ffa2ebeabc5f9c0b68f0901e79985c13e54b5349c9d0c6cc47ba90c5220af2a713e74e1adb097d8131c264fec3a7b209bb96f45bbe02e74c3fb3ff262ba852ca2dff943745a3ce2951795d2b0350419f070248b63cbf3fdd921144d9afe9644ff63c3aae3c73f6e3eff9e58720b8b07b74215531dc3f917e65a3c8fba48dade45dc3c92adc97ef326e3dccd91cd9c4824ff5baf4901ce12307c2b6f12a005869a8f522ade63d04432f99714ab03a883d6005d07b8144aafe4bfc5901d29d697134ae5007175d75466a6ce5df8217841e863007439fcda359df4fde36ffa412af7b32875cb2476fbcf42ab21faee57802bb59aab5ad5b9075e49e0325cb200090a422f185bfd1d532c2f79dde7f8ef5bc9bd1f0192e870c86d8ad266ff57e1366fedcaa80f01a243d48b5409a2085b1d6d6e40200c960e9a33ec7946182982b85a944319f978b590618b90287a9705da6e745488b04a7ba4a5f83b31cc2725bab763e832550a40d20006df0300001802009c5b3f9e746809ea9d5b08b95428fdbf89804ef085c1bf7196c1bc6d44b2b27afa5efecb102ef21579f90997e1ae262b60a7123de9f0c11baa64242e5d8ea5ecd83323eabb1a5e0e1ec60a7c39b0af6693732028c5a9fae25bf37fc351af7fedf096e9e035391eae1e0484c6a14e5db1e2b9f8da71bad6d8f8663a23163e0f31128ba15e7cd391e08b2ea37dbb520752f2951a56e81ccefb02801b40b80d99bb60439be15a4f7d468e4177d1b8a5d7b54cff24a12d39ff2b911196218b5cd29eb379d0b1592082f2037b62222e2f2cb400397a10c7c8f683e0def6bba3d5b4b43f5e1f6cb5c7e55f6a8774b8a208528b45e760ff8fd5e0103e2042261a2f92233234ada07c27111975bd9fd71d6c483d9eb5f270f0ff1c8362aeac0a4ee12d2e209a83a978afc9931f38a554a8faa7ee2e82df8fbd14a80d926c0fc4cf49fdc45a0467d652a4d547bf6381df3a761f77ada35e1ced07ef8b3c127863c26a0c5ef1e84970c11ed7a894e2ae2963e49148edf972f19e3fb5572417c8221edf3d57d10121c8dde94de26bd19e98c2d4c635a56ec6357fb3862f71856094863089c4d1234ed400fb7dd1aa12925b0e68bf847f804da8dc830571090577020e5a55e04ef7181547c530038043e1c01c37c3c407183caafbd69860f6b589ba6254db8177608f122e7bce1540d30e24e856b45aeaec50d769205b59214a814103cc5485e5b45c44509a4d91b4e39e9cf8a5e45081c94f36b517ce33f42792af9db968cb8438322e31caa0874f3731dfd34bd38ae9c14036c9d7aad342465c91b5c011a45c4e242c9348cb8e99704c8f3451f7d5cf4ae7ad07783e7ace6ffbb2a0cd7c29f163537f288a45c59e349b33d1358ab8d490b062cef81ef1119df73a3de3c97b55973a453f5b4e3b811f5a317aad4b38f5653938f4acf54b40fb34ce8f72aa22339915b0f5b3ca4f17650b1e80e8261304a062271612bb61a2fdb04cd40fbc736ba8e0ea674a3c13eee12a8c2c1d80138468a45b58833d815d4a6d6d5065daff69578923463859c571034b6e92ccafea6289611d2cf78dd16df58f828f0ace4b068d82a08cf717704257fb0bb63335738d9c11c04a1239e32af3bd25441b8038443d95fc3ebccc59fd8893a220d2b6570ce3498575e1a03478eddabf63e90e0bd18f4b3d0d4083735b91189b111faa936f1289840e8ec531c0b406a627cd8943e4fc0843713fb5ca183b323d8b5009875f06d35e3796d348c34258ad217c96018538d326d01764061b135fb2357f92cc08ca27210d33c89dfd62699c597a0d308b65f661a05081cc43aec6b4aac764049dcbc19801fe3a2b0253442200e81bd249c205d0cee81306c0f49a34eeabe798238af425116a5d47e6e0fabf8c2bc1f48a98d6f7c6db0e4d5944cdd0c683cc2d0c093a382c6fe5173d88729e299dc2f21a30c8fce6ea67f2958d223df78780f885a45f697489f214c4af5d4838c3ff2e16d2acb9f7a9ff27880f1f4f7ad8b2001c173954f6e2b09981a2e1934d842de62c947e185e1dca414912a41d1e90e1b091cf995f025427553528ed868a542072a8040fa76eaff12d6c2e349e3059525cb883c554f1a1594ae7d5d6bc712fdcc210c8fd8eba8aa9135ad2ec506dc955ca08b7687b606cfc5ac98f8df990b131916766ebb00a2e7694e90472591627407439912a2392d95c9ded261442a2a264c4a22db0d8bf423e3accde97ea751d0404a25f742e221cf3befa54c6c186c66a1addc05b2bfe045c169b4c63f3fbc80948abeb8e8f413b6df78d134131e710d3c41b00f6ac56f6e24b1e0451e0e1f4e7dc0ce837f200f543441fcd151f871c3b0ae92475af0cd5fdae2860ec096d6a2c6e0e6999a960db1873a3bda775c2f568ff6b9f27e43ae83aefa6bc9aff26dac3b3ec765beb1735b20053fb0004d8c94e058661f4dd58cc903c4858ad113b227e651fec20c5fe6b08ebbb3523ebe0cc91302ca929c05b6c84c13afe3dbb0a7a2d61657f9c26de8a0c6acf9bf1229503a49d305ef44788ecf4f18d9f94a5ee5ef7696287e76b16b9df1b42c95777159c1e112d1040692b00826885d56643a868ee59ee258e0a7a4b125b5cb79a82791d23bd71216d2fd2bd8444f49e5fb174d639e0f6386999f2c2fe878e3a204ca11f9d33eb9e89745077c585eb6f4b5ae110caa8954fb48c09ea30903ee4b35b8e5789bc8eacf8fcd8d83f8830aace73e78a1b2c3279d0beccc6506fb92e7c0ff40f4c50bc766401a575eb16b7dae80e26ee01d0782073c9679bb2a15ab7b4017c0cb0b3a261aeac73e8162f0ee82681da8fa2f068fdf529fed2987151a99342118301ac0065934095fc04217075ad3c1e1b2d03197623d0aa742e305907a21667c6aae99e66ee2a713481bb04aa5605ab5ea92d89ef7885c3f9361103bb4d1826e77e819e3db654da41d5ac908a9030cbc0e7005c0cff5105bd066c40e4b3953025561244f3ce1c87301c4fa437bdb62bb7732ea1d25c665691e7da44c5d3904194ddb9eaff4a66fb9e197d210a9ce3308c76a694d3312245458970e53e7006c8ea7b095c28155c88fec5c65793e02610ead4f3eb4d0f0aefdc5f8f545b760def6e9ce0015c7170275301a8e0c97002101e7f9455fa61e442d10db68a73ef87e0cca377a92f945ed0884d2ee02e18dc82cc59c9da1f718975c93812cfefa4c8af8c3250532021b75ffb666ea560d12a8d4fb7b15607938018d13e72f12f5cf1ff17ec72d40594cba5a0e204f414d4156661f9701f4b4286f63f84dd5321d0189cfca8e71789b6b816ae8ed4a1098c701e40644548857deabfa5b9a6e5396a0fb33ae18e9373400fe2557a89cbbb6ca6afb601be5e013ebeaec19e16b7d50c04fea88e51d3868c5ddda5dde33328f47596669f6d6acb80f7eaad67650fba1dc90a8850e6ce8e38b2b81f2f45fa24ae95972a425626fb76a5a25cc21eba375d085f3ef8cd1bb0b73cb3b6a538a20db77dcffc57282e9abd75cdb9db7d361e878cad92691b0d1f4e6733fc02e4f48408ba1038f449394af64e9674be81632cdc1d2327176b0ee1eebfc32b04404285e2c8fbe6ca50f931ec8d953d60d34eb50bdad7b3886dacb2ac19859b4d579c11b2c2ba8c727357e525ff428f70dbc76bb182e13961675061001a7634a02a90266cd162b0b3cdf9e854e0c20774316c503a284212e351deda620d6a24992527899f4a05c2c46f6ed9684bb65da1c52f4a899cac7fe913a32c0581160f4fd0bc3eb9a0079c1b99ae694bc637917f56c15e28c00d6dd8b590baf00512a6f2a4069043669afba91d518562a594bd8acea37c3d042680bb352823a67931533919124dce9c5b8c61b458f6919c22c438fd98d5c3bed55736be4bc44df32f6a12be668e0865692245b29d52ddae7803b0ace59148a95af7480ba0b953619e3504996ea4e10031c685583d7c68f7183648eaa6c8d8d0327849545102198fdcc11a0218fb7b57760b885fabd287855c87eecc8452cb6ecdcfc641e2b867360b68b766c679b76678ee17879cdd55a10d13970c12ceed50e01b0c5c334b4613aae69a2ef728352254dc69c434b81d43a8fc59cadb55f9a74fc66dd68dcb1ceb5888264c1b79469f3bab5a702a1b68c2d857d9bdc22d51f73a2d68c4581f462dc16a5c5a5aa41b64f489b196ad76daa41a6701cc3d4ea2410c2c9ce5ac731aaa6d904efc9b397d10283956ebf0efe95ebeb1ba306b18c1f9d513495107636583b8ac06cf2251295a1f444d3daba2dbf2c0c62988242a246c73b43608281e2f019907f10508821e8441ab33f60b83c0006a5640246b44a433d601135bc8e1f40e1e434cc95358e720b5bea8c641985692a297c483d12d809976b1816fc0cf4ff05a487bd868671b65d2e450b21e2c111481a60df339695f0d929e6a42c856e822c577d71a74f8086e7ba81f65a2e070962e627e850d04e11610a2ec9c5066387a97550488033e20467acd79061745d90496f2609546c52ceeeba7fcf97cb03609d381c6c74908f2d2f4c227d4afcf532d91bee1159a505777098fc8be5a83f2ce04a9df03542c2665c479aaaff4ae2a584c0da01f0027ce89006fea8efdf88144400095563ce1e451b9d8cd074196a55157456517b710a9cdaa6619a3e44cb13583ec9fc4425aad59b3a30510af4a23260b4c54808cf87a608d5146fc1d9c7c03885ce24e03986228a65b411a91c493bbf468eb1172968de63f2c54bb6236519cb0cebb072615d8ce098c18dbeb03c114fc2f3f959829d76fe33f355ce630bcfb9ee0bd0806e723d0356230a867772b16e64e26f8035fbd3c8c2b08937d4149326bf94c49ecef2e550de6987099e91c69cb95d76f5e7b54c896c5f46ad8819bb6558148e61618dc14ec7ab7a197cc6090a2cd16a4aa8ea3f3aaa9191871e9b01ce6fb67332c6f4e92430d663c6d07274446f7f6b6c51b0f0149bdc822a5e41598f142412cd7d41ca2bcd614aef8c760ed1453fb9216ac2e3bec6255540d4f7304969052d45ea6ffbf8b869a4cde7ab422af845a0f4eacca4bb6a587103b6cd3c63abe6544e9ddb4a6df143c746602bbe779a3f6734da2441d38842a552cb2872b25b186afbb15801003d72638f534d0e15584d220bea96e21c272a4d8467753927cd8feb72f93650c6eb0c1792a8457ad1f9fb84fd0af4154f1c8517be2c9b758e7d9765ac82e16a80544088285244f5bdd0535de1ec80421313fd183c33f0c2c5b5c183aa8745e53b5ed3b218ce1ae44c35a594f4f43fe8dde58206194ff519498967780d96bf82ede6705cb44bb980044f80e914315ffdda8927e1df68b309db627786fd7d2852453c7c26d790cfc8939bda982b097de9c373266b252541c5b2bf68077990fd1e59ada4ba431fc71c94dd202a91b7ebb81f68c107646f0499f518c3b1ddeb10f0934d4d8b2e0818d224cf19d262db2b2b74e00746425d32bb90afaf36d69752f8cb0f2ffe2a2c04b6d133e5c6ce7f2e98023aaf5959f0b10f253e37ac6fd6e11d6a7288207bdbf5c4ca0d0a74801b22f811427d0a245cae47d7cce9c137e346f7d3b3b8ba0503d0a71eb0a165f393279b914ef6a79b723cbf13b79e4a0cbe5d99644d748c0719fcef0efff594c6e074d45ad6e8cb422db4e0ade446539973f421117bb1eb7cb8b4e8897a46871923a0f39f1090a543b82533f17355390262e0fa4d179b879294d1ce32a83e215c6c0e70b7cc0b142de00429d272613427634ef88244ceae8adf5f4de8ee1739a91173a97c0ad8bf24242e7b14f08040dd7c80b3b4f7d205d49945e182951806471c5500c3f242c27a5b36a757c87c40590c138bcfadd3eec4ac3725afa4ced9d1d30a7cd5bef0bc08996c0022a00f5be25b7554bd35e4dc67ff1d26c328fa9e921b95988847a1b84d7f3be2921237f7a5ee51c6f0d4e61af3a316f206c062667a3a5fa28b0e8d332f622f36eba28cdd60704a308ca336390ff0bbfd06ec89d8b8f8695b8465519af1050834bc60b0f28089c6fcce51d7fae3ffcb1f145c58731928826b108b34306353b3306f3097666d46bc84aee8dd03aa581c0f2bf76c1e4132bbffdd75aa79df01509ce8c44544325cad4cd8c01fd0b08d5522fa32f7f01143e0014906556bf809ba509cc2e35a827360c924d7ee888ad66c6716fecf923a8a45433632bb8d68c48033c4aacaf4ebb73f0cc6000d67201e0d56522144687c10bf24440e9a738203f96c735ff97380cab1f399a13100d71184e3f72be4d4084d969142771249f587dda1127719e4f029fd6cd8f9ce9c7e5d00a6cd7ebfea5708684461c40f2ca14e1d92302e3761384d07e06647b2c3b331d8ee8283f3f8ca71f87f3f7d5473fa93337b224e5aee8d9bb1a10212316a187e181658c4f61e9da0468a4b3634e80902fdfd9ec6de2040f5c8f299a2f7ebe997f0e2f6606e61d20afd5b997883ee8fe6d28b745e45c6e2834303a877cfa4e7a8d03ece6a679950fa5e56b538f8cd758ae8b023d8afcfdcfbf2a195c2c89369232003338ba82f3e3f49d97a37066b4d8db8a5ba32fa36f3a88d461ebc4e49473c5605e729e70737e4188fd39779c949621b35bff92c316e083c8fd2f22320f0517e26588178fe16ce181fbb068e5bf8515e3e00437e820c84a336a2387ba900d9f7abf888e8e1197829707ff8068ab0060da2a2d4430d07cb100bcfc547b52d0b72925dd33e9ef402dfec2817fc3a53c260421babccaea051f1716c82486bceb98759bd37fd134bc30602238ae109038005b19af9043e5bc6218d63818d4527a3e22ab6b030271b630223e097e08de88203f8e16b25318cb3da2da10c938a70366d4b45517191f2e88ed254673dea67848bc2ff873b78f57ad296831caf6dfcdfd875bcab36e81214899875941b2f7bf9d6d6330b910501e687a834efb70c3715d332c1779fc0520cf20fd311d9656b7e27e24cacccc201613b759522be981e3bebb21fa310e2fa4a884351b7a580364702d958376d8ca837348171bba8fc2e13c9069d84da8d63831a8c6017b2e636b562bdcd4d293f6c271f8595fff0c79889e349f2e4180c9599c6574e1551ad4ff81079c5aac7055a92dfb03fb0e362f33502db2ec8b5767449034eb63ebf72652298e0987c232d38bcab0b95fcc06c481f7c6c1593841736b840dcfa599a2994e012404d313da97810d858225d152f51db76fb3704b4356c3b15c5af8154231edc04f31f7867d989cbff3dcb02d56722a53053b2c7b34955a845e6fd74d2c051b99c932d5610cc9bb5a22cc40fcbfe0a9e46295ed6fc7422b4a843fb4555b2274df6ea90f73f754617e0d91512a7a94dc0d7492e4ebb2eb9bbabcd321952db99154c41913643c57a86500f1e994244946b626468d99a3aaa517d5339e681d71c1dfed6104a3073a4c8006dff672f519ae6a0192656eff591b7e2a8ba0c10845c34a8d8974ba08ddbe43ab31fe86be60214778a53e8b69f929e278653987b65f544db5a08f5334eab7e5be619dcb6bcf6b7539a0858f6d21c22f0d92dd890c67488dada2d868ab1d172261f4dc704ee70960b2dbea56103d0827332ef1581ecbf216180b3eb387cec4532ded0e541256c7800b4e1761e6b84485cb64abefe3e5e05937e3f28d42a6f8db1eaecc265a02dd06945be38d0bbf3d28cb2d2f3b38048587c91d8b4317e4e09216c23ba93047ebcaad31008eb9245ba39a4f3446c1e57dfb9f373a435dccb8535cebaaac4cc86f394bcc649af5bc74407543df598bb88383eb398c960d81f8b0e7866931032e3feb81be9971090ef05bc65b53ee46e5f37287df797b2e3621b9cd193d1f68638b780c67813bd7e83efbb15c873984bf7557efc02103d7db929b1b035c92ad51cd71724d295b97dc4c89e5c45c1fb94bec4ea67623aebc99c4d3af1f8cbdd6727d90409c5cad272246000c47b8f6cd92eef6071093547e17e95b8edb983ae65d000d3db99948376b575f6d03bc4a64f309434821b090a2dfefc6cde3df6ae97a3fb7063ff9f542d5220db09c92c49b45b23970c839f35e04a88ddec42bc5750755b3dbc4780a28c31f7d8f86c94c238f091ee94d98f77105e00d0084dfebc7c54c48db53170023623c999a34eca65cf34c34c23b9338791610a853fe1f6ec1efe516fc3f6ec1cf1bdc82fff671656622b4d7aed45f9af465c4e0a13fc7987ebeb1e133d5ae471af8e0601eb7d7a17a5c42180b8ec1d03e2200fcb7e395752a458900d0288ff183f779e4109bb7cf1c44babca6d802cbceaeaf1451f3e4f5a715f6e9f79f6472ab7c0ac1d1b78dd833ae7cf04db1a0599d199096bfbf432c51e81c98ba8a7f54f3c78b6b1dc04e8cea31a92e89434184623b17fba507d2d3681c21bedb977772d8d99e2606cdbb9521d319f9af920f3575b568791b92ad81aece5912e89da4eae04c4e57d9e4a89774a5c4aafae53f923d0260a921524748e43a6598db89a5950b008f541efe55e81ce5f29497002b6c87628000729a47067c8f13f5c5b56ce34197a53ac90f4e4ddf07c752f8196bc29f06ea19ed3e62d531e09418c957ec34dc586f24cbc050c0599b2ed391e84e6ce3ee06e25c2f6b86e64830330787e2d7a3a4580fd30fa3a7be8b3175a899937f32f17b9307645445ea302db19729d62bdad0007fefe6ba18d90dd1d39513c596d31905b8b93da631f669f892262f1c949f382ee6aed52ddd59a919e7470659e0ee896fcc9c191ae81bc1426bb8202af1138b0bcfe30d26f731dd0ada8f94df8ce501a2354e5397e7781f15a2ac68b47dfd848eb27f77d05d383001010cf7d22302c268f4ec4bb3dd90048515d656e7a0ddfa68344f57e214671cb06103c030d8eaea3ce51b3ae0c4fa6e2836ac04b49922bd14b6554db6454df0383ab299ffd829eb4073a5ee6cab03843dc491e88db118538f7a07121820527b909423c21c2431ca8ec4bd2d0b37d56d9c0f8065d1ded90f3ab19043711f641898ed3f261b861b01e80b13c5f4cf9c39e2b1aa47d96598a0f7802c9da208e9547b21dd0d80a970a218fdd1e7465403e377feda0f777c03bdc49e40c5d87b5ce6038e6c1e63966e0afdcbb421d539e784439172d4e0c6ecdcd240de1017bb91c4b34918109b6f3c3033f334902f8487432057578da466da361c5923ff76384fcd066eef48aa699491bbecede64c5860612cb3a9f578cecc49f007b8edf3635d507147074d06684e5fb658c5146ad188cc20c73557627142113b9afbec446a1ff76380e71cbcd637aac71e6ec214ac84b8e72e51009ac850aaed727a34d3ee713a4df49e8d51134c4154fb81bb25bdd1e9039ca9b1e606f8ee804540e3c6c82ce192f98d683792c97932f190e7a3d15a1fb62ba90242ed2601e968912c5a8e7727a5f3d57b9a27d6385706053e9ed2d89b04da1f914f773449ef657c3fd46d53d650ad9b63f63b59167557c753186b850a7dca431b0f7a531c6b3966412f068f95d7d0ebe1b045141785af02028ef557888f1f53e11a869796e66e224fa8c00723228ad398718aad5c6e5ad543e774613b51cec77a2c0461f5dd5943dacdecb5d08d0fd4d8b76d4420e29d861e563c5198da34f406a45c33a8e786a1ed921299805e2fd14c87efe9df489cbdca020a4495687a79f693c14494e206aac142f370278b66601240d24aaf05cfbacb44a2cecd980babf1c164c4a978b89dc2d3cd847e22cfa194d6c74811c331be6478d1cf176d5ceafb56e282639cab315418bb6531a1a0a544b4aff5c21a583e7c371d0bda431eb00927be6999e8edee83691eca86aac97283bec07442cc48a4d96b0cbe4f03ef4308022221eeee877a2e6a7b90e8d5632c6494812a887b3ac77ab2a1a5016e6ae060da6bfb2593ef77aa146cb59c4878d86b5a4393f322b03b79483683a32724f13c99c214a98e8e9f308701db62800df7acba61999bbc78f100d7096bdc189844f2e13cd1be641730ab5685515890a6ddf6c5ec7da01ae1d07c73789b8e1e896bd726d31cbc3b7b6bee590249a79bf55f6b919a06799c4ee60a49328529c0ddd07fbdbdbd80793c6235fb07436334d11101cf67fe54c5b1af1a5dc17a00b29402d396286d8395bce34f4805dca5a49713deca5526255a520d438df16c90b78badf6a8d051f342c2de508dbe2aacf8773f4ff1c20a303e5b37afbf7940c43ffe3ad0371e097e993ec6e519949b92138c10de0e258048105323bb188a2a3ff948ac5da778f3e459e0ebe70c42be5d52f07e0a8322173e6e84d02b468deed2c3f2fcb2620238b90c258ee0875a0008c00435c9e4ea6d57799c3bac4dd163d78ff8515f7b9143adf5ab2843108606de97ccdf3cc68ffc46247b6f16d9ec91416ed00bf3a69fdcf9b15407bbaaada981eddf94f712a18d3686c06ada8d628041c7d4eb3e93466a7361d18d7a6fea21480aaa5b5c6f6f374b8e42c45eb605666479a0091c5ead8c1b3633dc65ae67e6c1b22567ef6bffbe7a50dde4c87d106db4d073d96f990939a72f77cfaa18dbed1a9a514d2f99f136d7d2f71e0253f6f102a32d92d61fa10d8b3cb6566b06354227c94087237dab0528f8abec1af90b4603e1415fd50e5e2e8ec2f69bd17df0606140ca9e3e06004c8c7efae791ec7e75732e1b55f7b7dbc2a9ee584dd19bc68d68820526014d937fbceef8d937817f133febbebe03d92ffbe32931cafdf37e0bda34aaec7cc961661301e42de9760d2174d17e1b07aab90f33ffd031564a1d081ee606df80da811a969b46f2eff3b63691f80a595e7c22a166173e40581f31f9291c9cda93d3b13c5b3c1d006a3ffabc5f4b40a5d00448a170a78727a8c584ab0856f8500a50c486eefb1f03017a8060785e7c3d0821d142b7a962a60d6fab0835cc7ebfd49f82cd156b9ff275d5f65d665e6a57287c0c87c5a1ff1e5ab11480694a5d6583f53d2269c6f27321f9389db4b1275795d15e475bf5c81bcec2e600c27d5009ea07a1cf62ab784ce1d8e697c4a816c76d14ede9b68404ef697ea3807f91f9f28f9629438b594a9b48e50cd81923d34762dc206d19dccd62224ec6179b5e9476db6f521c8b0d9818b12cbf6d808e8270976458e782a178ae822bf4b05125f38f7cdeec44c328f7497c58f97d49a598819bf1eedc86e71e34c92340088828b9d978ae721e71cf30faf6255058b12db72b0f3fb4c378800573271fce2777e1dc5739c7142653abe4ae0ee916ad887919fdbba0fca2859e52aaef6c4d35dc3d1a43888a34149c79f688e15cab819be2f18031381f2b159a821148e0cbbe28b4b11a4b522b98a8595f7c70ffa305810f7a382c601a084d10f4c67ca9ffa2a51490f421e18de27299907d144750c03fbec141667d4573e23098cb21766e90145ed9ba51b4e7634bf74203e53dfcdf9019f5bad21188768850dbd153e011a8d0a3348373ac9c652415b6b673586fc34ef7a06d2095748dde4043a6ec6cc30a8688a44adb5fa7d01d3af8deea7027f64a7f1e5185f549257dec5413a1a7af83e80a00105e2b35c630f170f111a2d10ff9c0ef1787b7e3c2ef37823b4a26b58f368000009d67e828038beb1dd9f54294455058b909e84206423d75474cf911db2a118d72c04ff520a5d860a00449088111aace0984246e6f483aca0734d37a906dd0d1c76c406121ac5c1ea2adc7ebb31043e8ddb291698e81f12c60d1a5e96de0bd2f30268456f35e1b89025abcf42c391f7735121bdd5042bee59193ba428ba524afdcbdde69455f11e6bd765fbca828b16955b800d8b8037e3ccbadc960cfb1f36ce9723cb068a056baf62dcd7898eacc4dee2d1efec537b79408e4bf5c42398656da4d725f3b4fe36e6b3ecae3858176574305b3bb1c0b4558ded2ba78b0353fc13924b4a126e498c82df3e50bb6d54c8b18686ad90e9bd785645afca4977697f356595748185752d1d631cb79594ecc013cbcc96b9687926008b1fec4e6690932d654408b1730a390c835aa9f64912a326d5764dafcf76b5edfdffc9b6ca91626049ad8e5861e5e92fd1cf5524e1c66ae243dc8233c59858de6a7091118f6cd9d17ba3dd2de5c9b707eeccf089b3e0e1eeb0865e15586e774d0b9ed30a430b68706a29fc80c70f234cb2190770a968a23ace08602088a1162c8e24348043fe8695511a15312e52d76c475d87ec127ec4f17154e878821588371e886656ef2a83cef50b66b4c4981c32a879e7a4b9d04a9761ce53f798af68f0f5cc54409dd7da936ff226adf5556844c8ff1f434f09a31e10a34a396199c670364ae30e719f29716c8b0adb91fa0bbf8272a405aca99460205f01e6c89b3ec5886f1fb403628ac2a711fc86f6fd9e748e8ba29c1b581bf26f022a4fe2c9246a01ff94ea4d56a2d4d7ca2308ece96192402b43d8ed3b7aa0fc974e49c6905e17ab6be776671146aba8aafc6dfb35ad067c7e7457c93c275d31e78dd87dd9990121615146296075d8b5bf55784d498780cf9c096757ef445d62fe2e15890a6a665f36fd1386c84918c6e417f52a07797a01008838b3aa2c9c48590d1987beccc4a669c1eb0ca0e272a1ac53c52fc2565092ccb38d377c6d7baad01e3b019c6f5b797ac88c1b976bdcd1ccbe21c6a16ab08bd6cb02c50b9c6b6433d3b8abce66bf9887f992cfc106fe0a176e4b221414855c71c718165e6a51f1113f9beb2a09dfda7f05feaae3bc3c979673f1de585649f3953dac28b865b00aef36b0ac155d6bf8b8c37ee86c464a75ab7551b8f83c867ec429151a8f8268adfc12755680018f0b990e0821d9bb1bfd08ecc2f465ce3aa8f0e356148fe736053f132ab114c37f13db79ae8d761bf69a0f0522cb1ca7ebf9c10e40422b6d12f3805de7c40554779ea1d62926f4c860a2d999ebadb36bc851f1806b180cb957cf3e4102718782a829fe920d382ba4e3f603b11680e4ba82e187eb393f2793bc7d18b8d998b162b63eef6567cf32e333e3df5e825a6188fdbd7ab1da82551f0dfda9f574d4fa4f32a25eb5324d4d5d42215e07e5044d553c91f185ea4a7276764fe3c4fd245d00ddda565cf749a20229389e65e003c54efbd55de81db224eb916406d066b9f82072747767e3248df91873d42911b4527174edfedcdf5b24a621a43ae2f06f3db316f7ba9d321d2324b45b8279671492499217319690a509accf2de828d25fb2d932bef9318f5344db826398ff58f1a248728f3eef2429e4003fdae4f9c691736e261242f3de77062b1872e0ce3f748c4eac8be874093085987f363846cd99e348aaa8b190e024cb05c258b4bebf839e772e2a83c3e113c3ab8484f44e66ac3762b4cb9274fb80d4a4aec69627df79b313a84b39493be8ab12058e9b3ac39fa33586494eda340e9869a919dc3c5fe02d9ea54c04742efa6dfd8e96dcec1d30d75ea69e7b7b37a7cc37c8f1e9d4766be8579a09a713b9d121bf7d29bab707e0c2806ea798483084b17fee6c3cd327f483ba24bc9cef2b516b2036f2eeb7d633c1b9ee16b2b915a2683160c426b1b17af515be1a195a67ddc4d5149b1542fd7edd62f02025348f091d409b3870fcf50626b198e92be7ce18755099ae3b429231631dad024ad0c32b4dd38006954ea3e817436c68daf344cf88692d9788810eccaf67ecc860a207d172f25b64245344f60aeb604ab65820e6c8c5f53190d221265b23b4221af0d942dab0b53609bd7cb44fa9baaa4e25a27710c0c41b6c5913f425319b1e7acba3c9fab9a45e4f5a5ea894c21d9130f5f8333a809c177a54972a1e81347fa26dc28ece2cf0059783cdde0addd2b617986341db6b9ca1c330db8a1eea85cc4408d9e6ac9099c686f0e26502fe4cac3afb330c816b8547808e6d6c726880e1effcddc1e24c961573ff3be3a0f072822172970b533c03714dad7885287b260314cb8a99319c2a595b8a6a831bd4fa18a94be76dbb375e3e7b4dcbc0f0324bb19d1578c1021901d28c52b5b6891dd01610c4d807d44f48fed640ce9f4487df09f810b45befdb660a3dde25ccf4dfd53774575051b4fab0dcb95f53161dfb1ed1336defe35af78b6240ccc44afd46bafe390ffb0fdcb1698cb4167433fb433b5210a4d4ead02f1a13b677c13dd69d438d3b2a69cf98d555f9ccf7654eceef736e0e625b3442aae859177a09a7aec800a503955e55b9d8922dbc91966a946c24a7c8ada938096e41839cc71669cec204267635cb9b5eb26885357e601a040b2ba04ef4268ebb31638a6bf101cb403442366a596c541372bc5970e1afe72a4692a41c9be434b5ea3505ed0c393cd3a3d40f846583b811b3ff732eb1d1fddba5ea777ebafd9773ca1945fbc4c95bde6e59bc999d8a7380fd1bb07f90e3dae2288b28890a638260c12a647b68e3ca28fe5e84bc25f13dd07918c74f7071179141fab1231e26bcd8e4b9b1bb6f2753b00b7d80cb196b3a4ca1a92025c08c076f40829f99b86d90b74c3c5952b6d12aaf12509ab2b3b86a252b2284644c8bd9035d36855d0c4dbc453be38f27cc38fca8b0a61abcccda586d654cd502573ea5d5a15c67dc0e13abd2ed37f6c40905186d0686e908bccd8ac21e4e6a42a7d72141261d526a99d12d761a693af5d47a5583655a92e3784d64b3cc436b0de3c6a9f8bf30df4665b4d5454ff2684866393208851249334fc11dce5263e006d770fc2e5c0a90fe3602063375fbbfb596141cbd40c0710334753b1139a6201e05a62c5f94d8568700852961a6956e105678c1160f65afab02f1c80f3b94b7b260878d9f26eb0bf39bc6e2083ac49f51fb5cabb49e7e111f667fe7a3629b2778b784932373f411b62ef4635dfcdc003e4706413eaef5f73faf02cd21ea3574db5c456d5cac6004e7abc0d06ffa89c3e32e712c02c5d3a26b9e3e07b84b99a936dc82c8c1089ba7996af052a0f214e73dd6df3ee7a49dd90a55910d1b7dbedbba64c2d80813d1e7b2730de4d46786bd2122b2aa7e1f4cdd008b9bf1fee4c46bd881da6d048799e2726ddcdc772a158f9acb701ef9fe5b9ee699a26a8555280833fb2a7b730519f559cd89e23e82bc9d4c4258ed9c70f0a22e73099162f89a96b6903358f5563139a31d77657bad8e328b3bf601540b6b8ccf8719c9d99e91077fa95d29ef284d037a15011ce309430888175d4765014df89c6518f32ad85f102f646df376d0234272a7e8bc9c5579e8cb95b9a1a9645ef2abb4099205d50d3dac0c235c06af174e2a01a561d66767d1851da4213c914fddf16e7a1bca26dae153aad8416540d2f19705de15ac54c40188d7bd733e915a507f560db112bb1ea9bad2cb8818f10a469122c7f0546919328506ae1be4afc173fbdf7d82db13d0372bc991cf08a81c03111df3421a88381c05a21a16b33d6106ce879bd03accc41e14fbb6e575140b4c7349498c06de5920f07d66ebdd5736aa77807d158cb22cc9acf5d61d161cfce9d07f46781089c37cb7c5de8d6c118b950a8029c3cc102ab143835afd13b4f6664ac458a3d99275dc4f5ddaed9e6012d73e114d5d84f8fae8ef50a7fc8d412c61139104533d4928a1acb7f8c4084e3d98d6dc91be39ab82ccbdd53d2343d322fa764bb5cd56b0050fc22f5287f19dbcbafdb05a543c46f5fcfbc342bffeb9fa0992b01ff8c30786f5f3124e64d414517a7198ecf1c92794bf5672308a090547723f7ebf62a9b6e62006916b6fe59aa2ff6c6b4ba973095afe5df0cc31c9ce1eaf0f172c819764f3e1e2149baa168c5d9794461414d5cb1ce2c2c0cf8079d04476ea26bafb6c0cf73aa4d8be622eb085a031f2ad86e45a85091f9de7cd9d623289e46b7392e6275c528be87036036e8e7d880ea1a04aac30df90266e56fed5cdafb67b993701799fa00ed18a8ae002ef4e8907b903bc44c74b913c70235b307fc035423de63bef6779b237ab22da57ad063d80610fd0f20ae69c0f1b4e8c619d85c01ed39afe388d859da1bf0160fe863d544dcdcb7ceac619200bd9836deb4b2a27a1e202b56720bfe881dcbec096ca1b5b2c85851134ccef51471c5fada903173c20990d9cc10ff5c8e83a0ce08ad0c9d0ba9f4dee063221152adb2941f2b63123c9edf1d860a09df4c80779fbff949ca1e8fc1032a7fca107ce59fd7b209c6dda334628e3cc535bafdbf3c1fc84ddaa5fafb8800aceae416ea3ebf080482f35a478666734cb07ca9e00681784f85affd07224674fa26d291fd8a1bfd41cc165636aae1770b9709458a0117b2f5b5b2ef2a19d801d46a8fbf5e35b3535c75885d54b68cdb8b023c8614ba08cf5e812c72b901c0fd230059b7e22e407d74b9f29b01a09d0cc09b06683bc0103c84c4a86a488750d487e673fd569868ec575a748ab0fdf7b93f3d9111d303ff34ecdd0dd48c962d56fc6dd94af21fc56a8ac4317f09ed4a14c0feccbbbf09f8bff312208d8f84d7bae1f44ea4cada8faeffa27befca17105e7ed30ac46dd9f8619cb4c22845f729ecff0f603bc70f2c65d32b4c98d9154d2a11a00bc01df0c7090748e2e4951ce03f58c661c5b92b95bcd13cedb69f5ffd84abd9f72338ac0da677be9b801cee8cbc3bfb05f0ef0a24294062a59aa90ffeca768af31b73a6cd3e4210689d714222acbf4566a01ae03f9501d4504423a46a4cc5b2fa3749d3d2757307d45e08c4d803fac9ea8e5820da59a503d58d23d2cc8d3208e47738e08f35e329cf511e6b5e8d43cf2332a9839f684e4821ea3f646e0d431c3e00703000439b243dbdb756b41770b0987a7688ffbed0914b210319201d1a5949c8de7b6fb9b794322519ec086808a908b3f4052b453bbb065383a23981d63b540de763ae7da191ae02c09cfd4612c9b02fab14a3184fc7667d6e328527887836288ec898b1ccf3119f5e29a794f2f29060cbc2115a1778b0708476a5e9e4a9c287c74e3aad1c25e141b219a16539820532e0f1c1114daa2001cfb6e4080d0c9e2488a00b7153128fb8e198639c33c61899a1e0628c31c628654f39e5945386a7e6c110f0e3053ec68e3176ec18638c5ec418638c912ff37031c61863646e792347e1b8cf021c23f9e81c77cd5d923c24bbccb7ac9991729774c419950dbc1e383cf3903746238cbb249d877c796be20cbb8e0679ce928a077d67243f45a0e3a5a88a2df884430bcf93266ce71cd6b5a739fd4e2e2f17ebe2625d3c7771f18eba8bcbf86c94a142350dd278b4ccf989e3ae8fee3b79f46e1a6c1dc2f88af1f1e7088971aacf79e5fce49c9f381932fc85c89225329ce3eee56547e98b6fb21f91929b6a57faa6c9adb34f97968f33994c764e51da9cb39fe92b62dd887c1c7b8964b6d4994c44c8df7cc60f6d249a150b20ede6cc64cce9651603d39887c3692e9d9b1e8ea473e254ac3d03a9a4b2194c41e94207938f742db9c05e3e1e73665925cdd78459e55753e3f2041527a8af1fd48a612048515516912d7b3266511fa911facd92dae8d9dd440c8ceb0b29c8d7344261fce4d8cbe58647d843c9f3d2e7c5438944122d1e4a2443c422607aca73d8516278287764b07c710df21bd66ae386d5aa56162656f94e7d2b4ff9fd904851840867791857d57019245bf255e383711a1ff60228c2c2f88baf56156605733f9a5a25912fa09f5f23d6104a1f154ccfec54f261563736a8fae2f7afbe2432891ca144e253fc35aeea2302829d87b94beee5b294abbe94d3a0f165ff7d3ecf9f3ab98c2fc6c95f1c85ba27c73c1e8efc09757ab991b55afbd23c8c55e44b3e9142323eec0b827df1cd4ffd23e37bb1e2f292f1b5708f8ccfc623199fe9bf20d89046c657fa2f08afaafad1fdc9eb8718f893f731764e97621e8e8bf419c62b8434613cea79b1951fa20fe5ab8bf2a194ccd2a994413ffa064c4e205f2d2f3872fee877c427223dd6260f273fe1d94bec1e7bc7ec9c009e7d63bf1165d85b6dba33ceb0df7456fac29aa7f92f447df5ad9f91a8748e485a95253898269e48d0801f16369c4f5b867a4f156cb5c6bbf9e6739bdb746a641a99dfdd4f30cd002427c7437620ce695d7b9e77936681aed36280ebd0006506d7b1a1a85901306a96cc51025c0788eb28c075a6ebcca28ee279f0b099bc4ebb3ac9ebe8b49229ddea22aef23a7ce57518cbeb741247f13acce475b8c9eb78ec27cfe96c3a3ace48ba255d2b1d5ee27558c9ebf804ba25533af1caeb442cafa3334347c775e8964cd2d1a1e331dd9a3e3a56c7a4a3a3e3b3a85d3508701c3f9c8703b80c3b780c3efc460f1e387e87b80ce0da8d6fefdc0eef72701b3ab803c03f1c1c86005ea300bebac153364e6300aee2229f59e3a8164b87005c6aa0f11c6eeac117d0c39d3f0df6d78303f916e0d15bc037952cc07b78356b88b773433efee96a16106f9f43beb8808f081b8f8123f57bf0fa3d5cd58f1e7c01de832fe01ae11e6ec83d7ef8c17df8e2e7fcc01e4ece5df28387fc413ce78b712688fbf08547de078f1e8e0f7ed34484e4e4f8f0c5ffe18b3b847cf183e47c4484788c33391ebd20395f904ffaf0c91f3e29e46b2c0dc6da12c4739c7d7a0faef385421c734ab9203348909c20df9ce2a337857c4370395f909caf484e4e8e0bc9b942b0d717a200bfe99c8f9d931e0e900be4e3204e84fc2037e44b247b05b8904b847c05d01e68901b1ef920ceec395f189d7cce0f1e0ea0011ed6e0000f651ee0e107010f5311f0b0e5a7879a043ce49f392ee312f838cab003f1c52813812f4619087c0ff8d81d20f3ec0df861003c721c88dfc8205f023c0747c639990f8873dcc9cc04387f464f81dc21a2934fc091108af80478f470124027026e589f871bda1fa803ec70c37d74510f1ed771ee10d9ea240078943ae4b0e3febd31c00d6ba4ab003e04f0c1e1b2eb866be31ac0953537acad1b5ad69d3e3302b8a1d57143d4db10e5a907e0a3de3eb2355db348b63849cab4d770696e8e0b8019c671c34ac3278022ec0cdc0c3ec3a52f439d63c087e4073fc277fc70a560d0b9ccc30125085222fb0981ba287519da1543bba8df7015c9164f89e9a2481d862e8ad4ef2da2feb5df48ddc60d51d43bea9c9174c916238932d4a9af5cd46bb8943c7518976c4d20ca24d9d221ca50c7f2d45545d469145589a8a419322952977193a68f4bb66694394d9f97e9e3e2d372a74b7ac9338f475692204d4df7e1a4dc475188e0e5a4410be8951598a6d620a09708b65324de431ad21e1d5fb09427822f914543044b1e0aa421b26264072a51ae4ec734ea73081ac42c9dd2200e829320d04c1f220c03bf226c514a49697c45a2ae0b1db0a0ca24474720f839fa16aa44cf45cf2e54d0333bf541f5d86a45e322149115da6a5031c6183967d97d32be8e8e303e7a49c5099e7819a91370cc68e28a0de473962c59b2c0a0c41cb7d0e8a86996e7ece273f20d4ddef98c4fc60b8e2d796ec22995e62c793e9f4acce32179644e6fe4a4ccb2a913cfe5ac61f7d64326c27a9fe6f593ef79c939cdc329d512b7e679e92b62ea36cfb3a68efb4d16e99c080876be8811fb1e8e7679e83e2dc619ae1e4e268738f1e9bb0b2c283e318d80085178011684056d80080bc282544cb0202c887f8880b020c98caa162599a5947d8511cc94254b1698182a4ef084e49e341f038a2540f13c27b30b58ba6c16c2e7f6fafe3e0c06c9d2c9587b38937fc42810e108b9bdbc4033af956bbbfc86e8be3d7a3c44f70dc5778c5eb7115a1b07e331180fdc4773c331c618976c38e8f0f968502ed99cd2d9517a6b4a60431be33b96dea03b5aa963dcbdd8b50d86da576fc49c5e1a3a92329f3ee263172322e5111ddf7fe002210fcc177410a822d44d7c01212187c6054843d0500184bf80e7c3ee9b8a21809639ea31b4c5a9caf3173fb2a3f3285b277f71294aee01955755de5505b1fee23e587fb91f90e2032f6edd07970f9c62dc233bba17b73ee474ad94e922424efe723d70baadca3199543ef08e16e71d2d1e77bc78683bf71c1577986a831d8f79f298065b3e6b4d9ff685309f61eef5c4018d07438634c8ce116d44af7d61c4c251c11d3d3b0d1f3ce4000d712226f9768a4464f18fec8b75d3d97788d97ee45bb543fb918f1e0f39bdb1ef3e4e8848898d699048163dfb10d9e28ea40c378ba322b2139183f2eccc2131bfbc9c900c13d8f6107bd59867c9845dfd6685c732f36dcecae6b3937d2e37a94954ada15a168b86c49976cc4310acd5ce595353c343e24c0c38b0d2e38e11e6ec39b1efb5782d8d246cb684e5399d9bb3622ebb99c0c5189ada20a845086638a48723c39a9b18d8e9e9c022b66d45429acd8861529a24365dca7989c88b83f4c1831004c0a1e646d64829312a65110cc3b08ca5ccb2eb9f3d350883a39ed8c3b9c1031bd6f4a959b2b31255efe9da0675342b8479a20a06e6959b5dacd5f9bb946b7f67d90dfb8a8c4cc298c7e66caf7443ec0a524a29598b4f9ecbb42cab9f47b0a22a26817020dd350de2fafa6c4ea22554f97845143c8ffa78450dac3c877549963f936e6f6457314cabdcf479d96fa47482469a2c867da59b851abf18f9350df45cd3bc4e4a89554a51b0c55002cb4bc4bf809431b2c33b4949373538344bfad15151111191942d5bb66c59eb0e93524a6f104334382f8d8e06d97f4c6069567d461be9f54e41d28f694691b0196da8532e5e52a4973dcc1d51ca481e54e2d144cdd9712e35f0f286754af74d2ecbfc374ed3ba6f729db4c26645ab7102483942b0287c7414ce33e6c9b62c337a7ae3450f1d543b78b65d8d47fb3424118b22ec278f45d12ccc5a14ca1d13ea568e949895cf91ad7aa5b1181969485aa331b120189f8d05f580e7467accd3ddeeacf55423300fefa878c8cfbac83b8ca432136e525df3e3260d528ed2511ae4cb4ca28836fd3d4bd853f5d01a19211d191d7190110caa5e157bc83d288e22ceb4d7f00e23c19cca4863ec248f4f3ef56963890d1d300166198f3eca127ba059e1118caf031a14126dfabb41182fac2c55c1867cf43e366260419c2147cde206bdb0f2aa3c2171a65de899ad743ee03cbb4cb043d07ce630adce9e6a9605cb79f6855ce4a657e764cd6ac66dded9e6bdd5e7b6af0234e1e615a099be7d15a0096b7d3ae5d6f2089cc9bd6e6a1a4776adb23705ebec9ce90b4dd154f24c1e3dcfe4cd909d8826a25f08ad8b1ed7d9130ac6634a3c8bd0b9f655544b7943ed0a534a9965db067ec76d58456d1703a78dcf805027ba7b8a860041c38718912e2fa7407ad83cf206314427e17100d11007c8d82c229ce5c3138f16409c698faf62150fbeb5c12457820d2b0d59448315b639dfbc9b56df343ff298d76ddb36c77cdb5cfae6db17b9f6a847e6b68dd3368d931d6b1eaaa4c7c79c1deb3a6e6e1e55ed20fdce29deacaee3648742a1b480d134f6a8ddd9a0d49c72d56e9839f3c5b6af61109e4b0fa72439f6887096dfbc7e4210e12c4f44fdea4114e99ddf2e917a39d6f1d508311367da8360be447080d5b9566d4e518b689ae69b7685c8bcfe569d08b95d22e4638e82e1381b6180d90c2c2a1144b2e70cc8e71b6a4e247b26423ef70ca7b363db86615fa43f030b8bddd9bdb22d7e6cfdaad7b9945e8378997131254f29354dca1b5fbfcd2cf32a65cbe45966fa4e51a67ae9ab0e8875d6fac3f4591de23167b0661806645e21c93c626a7144c334d89ce4081a8e87061b88065b4a9a1e38be80c0f80bab6cd5faaaaffaa2d1612bca3a0af4394f35082436ac60373737d71f8c05db96d92cbbb5634dd3b4b885f53594f4aed65a6b2a865f0d2f3b26862536f31b8cd2a22320983caf66cc7c3dcf6f9aab37ac2e1c766b8648992eb10744880ac857fd60cf3cbb324dd8ce659ab02123dd3881e52b48482f247e1935d85ca5c1b6820aa309d2b39fbc35a0d5ce7c489129e42b45f8b7ad7ddb980aaa8bb060fc17efc5b0c4462b5135bb606cb0cad6acb0eff14acd23df9079dd82e5df3e22ec17d1dc88fdc83942670da641f64dd3aec43e7a3ceecbe61b88b05f84dd88e51bd8b3cf39876caeddcac04a1e4cc0a6672ebf6cd6ce9e347031cdab67f2b30cfb2cfbcc43982ccbbe5e21b82fc440d5b4b05df7a97e749e771e1f094c64d779a7b9d61e4e473d1ceade37bdfb24b779f4b44de3e87daa1fec9a6b57084df54362af7dec51d7ac14b02fe37a1e9920a81fe83c603b70e2c0cb70032f3d84a1189093084fdee8770c61ca37c75ca59442ad7ccf2b563e7e1a9d442304de166c48abd02acd8ab7062c2c7badf3a5735256cc6586b94480eac7a456489039e6ee730616a17415f5234f6d8441937d34fb28cf9f5f7fb77bf51830cb7a5ed58f9f5735fdc8d38461f91621a28117c288acd90d896433b0b02c1b055c1c80edd8025b3947fbfc36ced12e23091bc6a250ba8f2a580d08f1e0c239daca48c2d66a2dc6629772eed0e01cedcd7ee4f986dc021bfa77a338477b12a8ee6e77fbdcec22174b5a4ceafc555ae2f764d7f1e07c5679a57420d14a1e70dc5d66e666173bdf261099dd70469f5be4da6298662b9739f6f1cdbe4e7ec1ab8732f222cc45f8ab11fa582ac61aa2ccc7990b22d13727bfd0c84f0f703e6f58ab58ee68c3da7537b2987ffd84903e437e99b536cf3cf3ae5b9c67dc17c3d78d2c76bfaec1da8de57ef5187e6c8db3f4d0b93aca0a28989b4d73e941b0732824edf687dcf3e3ea81618addd0fd86f2fc8d7ca1f886569f8065da5b509b6028be7d720ebe917a3847ff58e9b15f190b6abcb1b6c56587a9e401f1a61b6e6e830babaa7ee46b8feea633ccde48a1cf3ea42ccbb41d5af4b28a6518a6c2fcc807215be8b548437410b27583c4af20b5c42a5b3c4b8293387b685cf942c1f2336f5edd1bb32f7bd33c34775bde1d6905d14fe7da5508689f57955d8e986a76c106fdf49f9f1e1ef9a6e2f5f179cc2246aac7384344e6edd2434023203c72e38c8a1d731c155f22d95722d97740543fc06f965ae8ae6b87d5a9f10daa1d5c66c9f292db0bb604d3a1b653b558372b77e41c59f3c490e0d89c59d716d5d9aa6955b5c3129510af1d17980f01a259f231cf91647d441b97c79c871cd9c2d1329863e08a091bd63c56834367d9678e6a168ecf9ca6665a8936353efbacfa6810335981020a0a965d06e162ecfc748eb1182936f98b6a92fc740a466cd12248892d948d8c283c45f849a93c8d82508c51b628400a4a787adfd434d825c6a1f9e6d66a2d9d124a4ab169d4e09c39a2e09a9b1b0f6f1a9c5e5353235bbc23368bb358ead428dae0054b3dac5952fdd6cc5963438f0d6b242dea61bfc8fc9016fdfcaab0edf416d999dd65819b1e63c2d58b088f1a8f09bdb4616dee1211f93403ab37b27aea3f5d36bf986576c71ad11234b79f3ef587b9ddb146643d5de3e7ad81d413eb15dd89331d54e351477146daf0856d42ca155dfef0587dbc25a238237d7efcece1dc2c6c0f5fb9a2cd74e9ab2922cb04c432d560d5e46b20459bcc615cd1a67a4b50caf5692620530da613a9844679be06151cbc84996207c6156764ca15f432bb3590e28c741b7e6cd0cbecbe2add7e5e3a37397689fa4d67b7fe4c356950a65e2917162c7b9872ad5e1a17b86b64ab9c13667e21cc1751cd3d9d30b19c52ca29a594936edbb66d524a29a59432ab5c6bcdb22aa59c524a29a59c52ca29a594534aa9691bd7759e572a994c16b3d6526bb7ad6a5d27a594f1155a186c606383f3969a4b9dc9eb6cad3162944adeb9984ca89a1baf539f4c2dd6a5e5e5e4e2f2f2723ac5882163c68c548ac6cbcbe91423860c193366a0502924cb37b4919999999999999999999999f9aa54303012060606e6240305822026ba0213dd78c590524e29a59c56c6a965cc191e0e4aa582e9a2468d155dad5673b592bd5af16ab55aa55234542a18981a35562b1b36dcbf8f860a86615452ca29a59493e33e2ad8be3ff86b4829a794529e561e0e1796af0dff2e0c9c755c9052761d6f80080bd202c652daeef47961fbb2bd46b166580c2b19ab192b546ab55aad563462ac56abd5aa5986920e214cd63230270c001fbdf37030c99894fcd8bcddcc47ff9c605959d7f50c1ffdabc2865d8d3e93c81c33b0ecdd737277cb898532edf9d5bfbee608b2eccd51ce2c37a8dca07283ca0d2a37a8dca07283ca0d2a37a8dca07283ca0d2a351c7db55fdcd14636a441e03db29a735146ee59aa95b9a5accec59e9327c7f94df764f639e7dc9e0c0142e1275428dc84befa06e56b6f4f1ac318db5e0d5669b3da1ad6f5a7626f51f15d42ddba8b7398cb7779a44c75ecbb3d52a6c61d160a76fad5c252ebd52f916cb578f55b245bd4abdf23d9c27c7ef53b45b4e97c106d34a7dfe569015477e9f9ead8f5f9ea7d77a4d89daf3e47b0e18d9e0f980fd4edbdae6ef9ee4bca54ef8a6ca8f22955b14df4614a887a3cc04f09355861786c98f249f9a47ea24de7d5533188369a574f01a57c6ccaf5291f276c37e7d52f4f9794a9d795c30b7b85640b0649ca54975ffdbe6090eed15718a45bf4f50996739626291134199990f0a4988ae24c957e5dd7c4e315c5996b64c3ad88475503125fbd069e68331d47514b8de7da36417aa8f2994171464a0f4d47decdc2d29d94129175771aacac6b4404ab87a925be7a4a68aa7c4cbe7da5bbd338b8466c4cb428541c94b6a018a87cf53025f437a6f8eaa1cae7862bceb4c97dab415fddf4853448de97f7d56f9366957cc22035abe4d7755159b0e1f6e175511c3bd1a6c6d71a5f7ac286d7354d53a287735aa2c17af269b0faa9a7c17a9d60c353cfc9e7d4235bbca3fafc4c470d56e7cf84d4a0e9e84dd07c4317f1752bb2c257f7b2930c44f56661397a3d523d71a64a71f2d551af6863f22a69f0d5c3194a7cf5193dd1463a47bbe9f558fdbcd5390d86af2158f4d53757add66e2ed4ab7aaaa74e1c7c78eaf9ea3206a43853dd861f8bd4a3c69b6ed157975ff559fabcefab735a9723c9ca20e430485fbd08ff75459bfe0a7385af4478f06fd7e34c751e389ebb4baccf5a6f93d415f6beee7535585d730f0bb63dbcaeaf1e63ea15a286a315155c8c0963c850c2dcb46f4799a03fbd4ab3306a2562f9b9332952124cc94fc790882dba844825b6402983146db89f537c7ed22528f1132b020cfa45516ca1b80fe9127e9e1a9c3c3438316f55fd90bf43bd2c7673fafa68705699b64a0e27aa1f1b52a756ac5869109c2145a23b718679c7746ae5c443b3a6db00045b647e88922d1f2145fae93aaed8902251a46675156aa55949d5a7532ccdca7c3ab6d32c9e66519f588f9266613fd813cd6a9f8e45d12c55378b60b79dde7a8ad1539ba0a03091846699364cd3b4397976a7780a5db638cf328e6298e79dfbe05d1fb84b43edd47a6231a30d4bbf6949e34cbc553ebaf671a88aa31fc2c6a12a88fee350154ebca12aa4a8b28661bbf90b398cb3145b09b7013b63948f5af838e48413f4e468c21076708037ca1749f8ae82434456868852f01c77ddd4070f509e653cf3511c1a8ae24347d23f5b7cd63374e577b4d3299da659d1083cf8067e761ccd9246cfae03df205d070b3ec421c5c412d960caf73d31d1ed71088a0d629aa5ea1be36198b021aae70a17352ec65894736c551cf16b8880c6886597f27962d89c92cb32c7bef8cc4b66b21dfc11911ee3ccac12063952867d48b3721ae41ffc40a826f0fded3d8434c8b3e7c7e0850de311941c211c8317164a100d6494f444a90c54ea26f5a1288661ecd2624b5ec76d5a8d1813593299aa093485356f9a6e3259d962264d13462bb2b3d5a2dc411a1ada1c94aa42dad6924cb1d6a90516e7d72c8be09d532408aac08635341d73bc31f304bbb0431ac421e52bacf91a59e3f46f831fa5c49e5d05b66b4f7777ff708cf970b15926cee74be6d133dac4af75db9c9ddbeae4e6dc6657b5ba75edc9d5fb2362d6ce9e369e3f5c1c806547a5c006c1b0393195f4232f6fc80f848e1e78477c551d4f29a5d479363798028b84dd31813a08d5e040035eb18c43e8a3c7a3a6d60ae2f8f913aa6b90c08615359fb0cdca32ac72b37628cf47837d136b8742a150d8ad19977d45707ac4bfc1e14e1ce617382bcfde9ec33f413aa0c0531a21078ebe6f163664250d6a40c543c9100ff4a01bb36b21f613549d9d75c03f54f340834302b7bb572c0c914a8ce7cd82e52eba99941dcf8d1b9d754951bad1d1d9adacf370b848b6ba242dd361c7931dc9d0511a7bf4cbdbf13831c337e63482514457e18c5a5e7a799e42f1ede10c4fc1686f20d9ca80a44c7bb5a83003faf606ca8abac84e41a1302141c130f19488aebc82b06bbb1a9f01c956694a5015d795522664ca883a9eaca8d4f168dbc6b1a5876b1de8ce53e7e88a4ec38a2922c380b977d09d162ebc401af2e2c85ab1a88f435e0865f12207368b172f80822d7d1cf2a2c7a5898d11c60b126c6a8b5311eca90a172a76460f5ca4b0319a7092022e5081a7050b3be38b29ac6582152e46d8978f43549ab434c1da8f4354a278c2d68f43549e38a9c07a1f87a8acc06504544410830995225a9ab0dac721a424242b521869e7055c8c094f3fdf1e637c4286f4e78957422953ca93ba83289f4fdbdb81775cd4f6837d5ed8902ae901c377f6c8d6e6431bf5d3db8fe4d8a51004cf3dbd1e359e9aa09f6f8c3392d927da60de252abebd24146da89bbe60c1b75a7ea4e7136de46c115ae295c4e52109c2f2dd02d45d6921ea9d4fa88a0ba8c6b7fcc8564769997623a0294155aebc5ee8e7ed68533d7ac71b3496327336b2d431af470d9f92509ca1eefd90458cd4ef3883b926330601c7dd25e6cd87878da73e630a3473fac553ea3328da48a72d444fa977946e997e76a20d911096d7155715ea26a0a774f399e28b6f24be3d6c21e28933edd82774c505a4b9b21a6ffa91adcc688a09a88a29e88ac985c5f4aa484c423c311ebbd94a09cb1ed24f7ea059468e33537294a79f13144c68beecc0d28f435388de5fae98e26489293e9805b8c14b8c7b020b28b6ce5396b8420a46358f79a9c61552f8f13c1cacc62eb408810b98c8a2840a7e3226be4882ed64d8028c9fce61188669e00a12a88024084646c8206b411694f0188e0843146220250a5dd882093f7df370260d26dc38fa313ac282d15802141e7382d130828213383ce65914c2bc5842e9bb222da23c01cb4fd3132c62f1081fc23ce631083430b7458f3d61076f8a6243eb34782cc663180a75c5886ec76cd6351ac157263c2baaf55aa38c8c6699141688e0850aa218525e90c4c5083f272924688152f42285090aec932217294748624242508b142590a0f464c74a7942128f8a2493142a4a744525295d3001d7e365c193c47642550154455067b340010934a1242e0b1794a0e630e4dab280a204590e46d0b2e88109b01c8ee0aa5914410439100108093e395491b4c5097280b27385278722f00c65812589263924e1c990134690c4939f1c84802c6a0a495d64f9d0fa0a49f7d1823a62c066611e62d46aa10b242cac8d8f435d50d1a204eb1f87baa0811576f571a88b244e4dd8d4c7212eb0f0d2635b3e0e71110597cd3e0e7191454b09ec8c8f435c10c1250c6bfa38c4051330ecfc38c44510c8059094893f87a64879978f43435bfcfc383465094fd3022f4dc1863434a52d6c91f91d4ecb10c7c7cfb1b7432de2611a94492cff08a2c1269a828b31e125fae925e762d5762247980f3b6ef1687764abe5b600d5fec8f3b3e5e3a582ddb8ee44245ba61e7982d22ce9af183bae2453901514923d329d8a505344d6468208a25cd1266e2568f2339c41e5a7cf403ab22f34882dbb135f80a24d8c9f76043fdd88d8320925f1d3811a9c517c55d8d02454f2e92628cd32f9e4d126212933dd411abb63bf979fef45c98bcfcb122f3d2f495e788464cb85c8a5c8e5c805c98abb243df8b2f3d3d924f473ba40e969708906a794d2e463ea6970baa9c7d4235bb14353cfcf17a09f2f40cd9a3ffd258a66c52129497efa4b50b3bc9ffe52f432a55b1cd4f3c2a45971a8080bd04f0f5f9e08fd642548f9f085e8e78bd1cf170ad4acd02414d4acd0da1d9350b3a6b744d12c39859f411fb630f9393ddce6d1bf00fdf60ab7d777b4b1058df0e506370b1b879480f4357ee72f91d7768a182949604e948f606a666666250d36fd69b0a9e9b9ee981ad1a34b8b4edf4e8de8916cd1262e2a44a1a89eab945912a5cc08ac8db12351c0c5983075f4ed5c9c3489cf8ff634d8b29b1c6dca914e9a95a8e9b9597ac2869b4fea492a4aaaa841b05345cd8aa9574aa8c1a61ea65edf45fac3cd876f30c1b74f1ed9a29bcff69323c902bd7cfba664fb912dda14a8c14e117da78852518ab0a1f173f391410a1bbd99fda6a4c1ed67f339b2edf2c32d65032ec6843658f98c062cec26bb6b64db654bd9b17331521a9d8b71869d9f9d166d5aa3010b5b791a8c49d260e63c3d3024c180a5c1cc638c31d280859d3142315424815f7c46e5b39828842d1fc608c55cf199a7aca84db050404dc1aff0598a0b9ff98c19d8167771f94499ccabb57c5db215c3e3aecfc0a46853dd940473848d0d720c4f8ccfc71059e6e16956928c5af199c7564aa8e5a987db934d28dc889ed29e5412620b06189294f099570f879e4ea7d3c9c5c52485063d3b058aad139094c9fc449588ac938bba247d5121d93a39fbb66da6a28f36a6d872716a9db918dfe9b35d47031636a3010b8b752f1fefe06294507a637e3ac61743748a29ca8911923299a3aeb0618c4f8c8f928c8968f4bc4961df9af8cc431924de43199ee75006299e8732143d773f529e69043d0b4919a01fc4259e5d349478761baf68e3bd0da1670f6d40d13c8c2912a2e17aa6f17aa6d1f31cd2f0790e69fc8c200612cfbebda2cdf6ec3176a2cd4b0c9e672b3ef3d88a118a32314988b1c118257c0643d2b6f32921d98a118a71356b9514f383c85a8541533142b275025a2535ebe4ea55189175fa410433530fbde3e5da000418923e73976f552465b213906cad90a48cab59ab2be2e90727a0a72348d92f251467b237dd15519cc9dc8629ec2a29da9c3e731b3bd1667ee63000451b199fb90c51b4317906942483f4314c2489f16930f350e68a50a6e8b3166e95e4d348c43091510f6decb498e855fda04e839e3a024a4b5adc48fd252e3f9fc5a3efee4dbb7c3c750712294a9d6b1e4ecb9782d232996f1e0e5f2e25e4e1a4a0349839b1a10b3145cd12821243141325f3939368133f9ba5cda759262622cbd4c4f6c587ddcf67ce715f6732492999062cece66974e3ed6a1fe7b4477b451bce33df9488aceec7b79e68d379e74404330f2912da13ca226a4fb4d13c3c39f98cf67ce69cf66ddefd348b16113b27907c7b5644527872b281607ce6a129e93319a8f8ccc355d267ae7d3208c59922fc27273142dc0593e24c961212caf29a17e19450b461cfb83bb54ffb2cab91146732c7a1c466ec618cd0676e83159782c9ca63abce7b4e76d957faceb3cf3688991efc25618df5215b2d3da2c6a8f4ed9495450b5591000000005314002028140c884402915838249635517d14000c89a2486c589f4ac3208829658c318000000000080080c8cc0c012001573354200a96e330070e3e4e609e1debf746848aad11d53085029a9606485cf099bea0eba609fb91637a0ea70b5bef55d5c3c8f49a83e0172d3997e222e8b418470c393836269d31ad974f01315e3d5ebba8e2c22b13bfa914f062208a692ff142731a56b03f597cb42f1c8bb3438c58d335d7c18e073689b641c6bb309323f092b83b57a9f12b38465c65d8d6084e2cc910c9fbc3877459814afc0faf6264fd99867d23d5e4978d6562ab50266ed4929bfe872afcc1c3d42510ebf39f79f8bda03fdeeb476501e8cf18ac6b31a21c7478ea8cb76975533810551ea71f404d648afb0a565e409282ee5b0aada09fabd0a2e4bc44427faa9affa867470deec993a99ac1011caa5d71072ab0f7cbc6ceb74bb9995f65b13332fc13e0e5959671488300ce489ec1477eec56754098eb86d5e1ad08e0d2df9ab2ff07e00fc053807f2b23f02f74207e80a050dd7503e746ed6bc9dacbcedae4422afce1b89f41e82b595669afaeff25da15a93f8877362ffb4a81a7a8a27737b9e40f9ed7e38a14813ee38a3b6f5d03c8b32e637984b5673dc3508b3758bc259eaf4f5b8c26669060231ea18650581b673316e4147ccdd16c70165722077e0ac326c74b527c563614dc069ac15ae10abc2380d10bd9ee73f3d1d46b7651b1e4868738a343b6f47a8a559767af3216dbe308fbd7bf1542e00884c1a9258e6e1d7469c5ecc107725ca49e04abbf37f330a98e2ad01f77c0b414c5f1a651f4f4559b3330a678e2c20752da9cb95fedc3840c706a67c22d29faf136320054ff56090480e4b3c17abb7d0999b8a9df5b867c50df2af56ebba7f6bb1793aedf53ca71d372613b7d494f6626227595fcf3c9843a3fe19c10d6f1c249c788b51098862f33abc01d87597fd049d3d16bfc8fc69fb819f484bc7562524806e0939f72970b941900356fe74ccce5f39366db5d8b9a13f79a0474952cba7d2e4c57b1c315aae8368ba2e04f270d383b65174a2155b283793cc1aae0430aea83bf3321b2bf1855772593e76a1bbad4b25ce0c4b64146a64657c46fd8d27c7b25549c549c8910e065d078e7c6664cad75c8667b8a737f921d51aaa4baa834f7df5f48a52e4b1e149a5e091f1e77e7cf4ab13aaaa462f1cd3f5757ed6ccbc6ac20d05e224f537ce1b5f3ea38b1da442e983562e862926189d0cbcab2dde692388fd66b457bcd6d33ebde1bbde7fa7eaeef0fb4af7e63cd84a71e7d80426cf53485244d58aff448f7db44cb4b7b2d2d9f300a5625b1d5d22d54bfa0849d99a44fbb4c03bdf9c32f35e7de73275cf2eabbcdda14518cb4170e91d5ecabaa1199559a01de3919c5071c05f1ce142f54924a96fd9e9dd090c1974c77a24dc9ce3c4f07238dcc7037c91d77ed4c2500bc68e228d48c7e692f549c22194b1811bc106efc634fa9d44f9e9bb536daa2ef62f33d4d295cb6823b085bab2380ab50993b98aa91527ea20b4d2e4f676a8d78324f2a666d5ee390d9e0189cbf63c2eb373543a5b7531206409cc5359a9857525a6b589a57b24b8e28c34171761849c2c3ef80da60bf6d7ffc7611f6f9b72c776c00c9cb51f572e76a14a2317cd350ba6cd03f9daaf599f96fd895f4680d672912b265658bb406810bfe4b4363f4b76e704125854c245ab7af1b46c4c63f92e2bdc11539507ed97c50ca4879a67be56a525973ef4e4ade2299a948183180bed50d995b5846d23aacf9101a06f823050968c6990fef8628117bf31ba6eff5a07a08146edc78e8514c767272874790e86fe9c61df381e254b4753c2978b5b2bff1bff04db74cff17dcd5b0fad4d27666235814780f86e330aabee8e37d24e443525ab510992226069d9a8d79c777db8d1423e3e2206fe6617d74e2056df0d689cea2f6d1b0f317099be84455fe93b833542cdfe169a371bcf7777bdcec82094e38a037bb75f5d3ead0ce8db0a4634132a0b1bf925c9684677a7b53a95c8266546e1da48a96b1c22606a7b78453ac42d8c7cd3b8afc7412fa9d3720809664020e8092241e25ea55422f04cabc0ceac69bd7b17f0f9caebac4ccd96f9a5639e3074ad870c400186df64b5f071c0e6154a4feca8065281dbce4d2d93b1d7af522c178d35c816c5cc20409208e7c35444a31f320860d208cecc52741f34f2c6fd6cde3cd876c649706df046e11655f741f850aafcbed80fb8c95768dc1dfb1ec2395707e256f46c18eed810624cf081f8db9e82d8c04359fd20c35a3b04941fb9151076809a6790203f6fb4c9f42d33ad5342c292487ea7d26155e5b831add2c2c482047eb074b9bfa96c634aaa95892680e530ecb37752d8d6994538365890ae020fd6ec526854960ffce9f5949871b9e6c8fed9b9dde708997365aea130acdac0c8f06d2ac462a8a71e8f7563665ec01d63405ab48adce59a732c1da199323d8b04b1de4eb4bc6f712fcd8192e3ea157e59d973cb152d173e2e265f1d8f6ae2a3377c8b92178dacb34f670eab0e204252f486ee0532b21dfb58c2357808388322e422c109a08e624f1b6195647f25195e6671ffbdb93314147d5223a094873ad0f31ef29431e19e063534897d966eae87c5802980afa5619fc9fb76302b0342f18d599138641c646cc8937b9e5dbc89739c4aab23cea83e3b61d735fee205d26f7d031326f6fefcc1f1b9adbae7037f4f2f5f5b143b1db1b001dd0f253c66b4722b40837fc9afe750f1bc4e9bd4d223787ad5c04339008ab99089fed25783262ce8ac35058b0b2f9fe17b86f4214842d5230e837694e123dafddda4198f9f0cb6593ecbd42f3d6e73b4e074bd37c055fbd5d624334f542e738f2cbf7dff0af61a467034ea62a748643b121a73cb46296c580ed55d9419113d18345938692450a7e2ceb05bf7415d4d3c80e5ccf3e99ef16ed45eb431ca90b59cbae63bd354dc2eaf820cc62af95a338f9c72badf7f0da2c46c14ddd8ebedbe510328a12abf21d6a764becf6487a90670a12078dc3e620aef0648da42a80a9d95d04909f41102eca55217530214fc51a8eb61090c0804faaebcea6ea5023c1119e8ff619ac8b083cd7f57e49f5b7a2918145ef10102bdd36ed87981cd25463a29cc59028c1f19440814d739cecef6a24a83e8d6fc6406a01a5bea47771a38a13243c97b9ca21765884ab88e98eea66f251c4d39ba5dfae290b3762b4280f44c30f24b37b997a34d59b9d03ec063bbc55df6f6c981d5b0a667b52e44e064ce4cf8f30f1c74c2a146c2f74197d8937ef59d9da9dbbad932b3f34a68538f1adc96730e4f03d459c4f46242b247cb3322e6c2538db50390dc9e672ac0250b09f5a3de086d81290eeda6f769c440aa0bbcd00fa5e50703880e44eed5ac248a643d05cb624a870068053679b0c72e09ba6dec1cf20bc6e97acb261338ae66a88dfd1721dbe830ccad71878556c3d5c6c077c88d8c33544147c1c021fa21d09de1bc393896fa23a8380b587b9bcc39a32bcd155570737e140a815bf27ee24ad9e0603802c2cb65cc49b137c393140b5d9b900349dab62da9f797e78bf2ff39e6cde8f811d8ce768a35d5f2cec310a9ac24cf18efff8da4b2db35f822f92d4ca95c1884ab140338cb1d25cd446f20ec58dfd704c60d7b38cc44612f08d0630ee2d70943495a8a48690428081f9e05051323c2c016e64a02828f77e5558edf69a742bb9e7f612b645baf1ade07d212be13422d1d3789aac812a75dc1a0462073989ddb491d6351ae8206828fbfd154588ec7926290080bf4b2d89aebacab03f21eb39100f7b48334adbaa3d703041a61b304c224101b1169d2fed4e4b3c051bf5c93d3f25af7153dd08bda667e8385f8f04bc32a7c00701d442b97dd5c79ed58417b6ef5d1b33194874e27dbd8b86a9a65ae67ff5f4f4d6d7610ca18bea119d2c2876598869bf4e3bc27d3b443222ff2870cec71da0745fb700ff277f34c2553020eacb755f64b8df5bc0a1c5bd182d46ee4e78ba026e9975fa9976d185b3b0e7495243d62827405b402694e3cebc74f2cb41b139484f71c56858cb2a256b878aca18fb90b01b7d7bbadc13d464afae185a967ca7614a1a12f3bff6c0cb8d256446ca9c81b0d76b1630a6e20f948d2b4185a7437efe088a284426264238b125a559ce375c7aceb2cc6d06bcc51c0924835331258b131440cac2468c78399ccc086879fc84ca85559f1f0cb6213b8eb18c4ad824090084a8088be72c0832abbdb3c9576744ed633c62f90d3953cea592e0e5ca7978c920a07596ce2583cf6345abc57ecf4c8168eb97cafd96d84fb5f9125996072c64b98eaac754fe675a2a35da288caca743d4e942a9fadb3a3d34a959083942157261848f5790b03deb6919a6cd11de8134e345432fb2049b06126b05169152fa9e3462b1687997f4bd5c970d4683bfbb4d8014f9f0385da4b86315eb4ef9b396e00dbbac7bd268c9b5137b348ea8ce6fac06516d2018fa487d588aba6dc8026c482521e397a341b4db073c74175a2cee19f2368c58455d70d5ffecbfeb84e0bd31fac5dab052ecae70046695ac6850d6dcb0d854c336dc4256d440401e45ec4c63e51e7b5d53088dbfae8a032c58bc363b4ac65c06d2fd2224332dd188f73f7d15a71539fe2cd049c9aa4b5c2502c99be086079ade0590993ff90343ca45bb987e8557067ea886b1b8bec2165bc31769c025fcecf5765cc39f8ab164cac05cb8bdb4b68a58cef2199c17b7709f89fcb52e94dc9462cadeb7ec7639c2975c91b1d2f3fd488e8130373736d09515c621c31b5661030ab1a123ebdfb28024e95a62cdbd13ec2cd69ad445e9e8c012b546d63088e95cad1feeac41b671da4f1c80614aab20b0e7a2edac87d9bf1735bf09ba7ef32a54cf1a3577afbda5686662a168e31426020c371164726ae4593b639bedaa9c5ee92294fe2ed051eb3e3561ade66b35cdb2d363b17447772d67a8a092c1176bca7c5ce1d0a220e0651cd64d765c499e185a8d80c107b7b02434e36e2f394344172298dcdaa31a6336f82acee40a2fdb3376f661707704044d2707b46a1744c038b825e67e94d88bc49e0f103c8172a01e07d7cbb29d336d5b6c3166ce04c7038df965616393b17672a3de11376ff9934d28ce287fbd68508db8a958fde157065cba0e4f7d9bf4547f9c4a306858ad437d3f3638c5f7adc0fe92a7886aeae0882ba6f4917ad2c790bb58172c484b034339c2c9cb07b376b3be379064b5e28e98bc4b2b56da5746ab327c7513ecce4fc2f32814f5e7aae8d9f557b4f71c499b75b3afa2242435bd2872d52461972a35e3b039f536d49cf69e27b9ebf5ebd5b0ef26dfa948bbd3967495c0ac5cb186bd85c9acfb53a5dbca64ad998c42a3f4a364f64fa37b743629900186dfcdb91bef7226012dbdd8934666f8e4d88b980f7e51c5f69da86e8047a1bd9eaaf6852bf83b9f9e766998689ec215df1ceb62325c201c737bad8d1e8cbbf74441731a8a4104c1a4edd31c7abdd94cba07b824ae7c824e6c4988925136ad6599454ce73f81d84c72149ed1369717bccd9e65c9d43bba6fc84618e77a8bed7ea817a537bf63a767c801345245bbfb393288b058dfaa75882cd726f000587fad6546bf66b1139113ab1960d6fecc145862e938457208852ab22b723790a868961fcb07eea2208395f0c413640809d3885fdf382b01fbafe6b8ee0ec9d4a0de6eb3e609590166d09244db4f95b259ce10faa4356d41823d5fb47adb669a9f10777caccd3887da901ef405ba92262795176c0865e10c5c9a99a637d55a14ea807a671d551945d8c3ff53fb16838482ae8a597b96eedb631dda6f06bce448b11afb30c6b23cbc0f380868bbd34d0d5cca335f77cc77f74a68f92f21accacab12811376e75aebe82cba1ebe3df7c6e627837acf45887ce9d0a273835d28308a8c77bd59b5089130bd40ecf24265efba7c7edd95e5cf6ef45ccf51ea847e2ea75e46583e6d7ab3bbd13d16feb3096ebd988f90f7d37833ab1c431bd1ef7efd3e12555a2b339908b05ab83fcc8e0273c91cacd1e2ecf4f0c78fa8bddf228a9e7da823418f883538329ca37f5d8658f4d356fa38dcc19611c91226620403e9d4d805844c04eec14d52af77e80332cbe525fbbbe266acbd6d831660f0ce4d06e10c7030f4117fd8aea78fd4635658136958c7b1a10724aa95a513188708a4eb58da7a46150d4b5ed5924b807b0b3a654c6b4fef8b4c9c1ca5b123dfa6554aa6c29c7b55399558ac651b95d63540ca0ca551316019e872c5b7be4f84c52f4b42b0c954e196bb38d0933fab92b8c2ed03aeff63c7f171b128fa6d2c019c46a52a329bab741d80d2e9425175f6bb7c58332c6c6fc5e5ab5c2c9cfee811e29725ad4aded731404e66913a244f262e301e4206a8156f13600dad87ee058a94261dc6430a90212e4c8b829ec95eacd02ec185d807d1d2aa4c499d0f1e337e8bc0061608e0f6f42d28af8396f658b70eb0628221dca21b4e86c338598c9fdc1dd2255f7ebdc30e2d941eadbd7a6f278b04a33d98c02b842efa2637a23815f1251dc8dba11cf7e17798165bd724727be4bbb4b5d197e61cf0bcd3c5688e3eb140f94b734e3db223dfbb5829dfcc81a12b8bcc45857d76f6bb5599cc1a526972e9d1770157ec2cb0838a476a54171b1028b5af5b5b74e85e15931a1a42073f25edf8000f85983d9251e72558f2cb2b9f95f1198f1733dbb7d5dab7f10dbe7c00a80b522872b21af4799279518b4f5ae7212a50332ac9a05456aee085f101dd9ba384bdd7966a3ec0f8b6aff7fc901ae4c288d2b4b5a23461a042a73904fe9d56c227a3ff738d0e5471657c83a3fef16f16248ed7086e3c64f08aecddbb826e2f1b503264bae148f06154dd1f96a9c01c15259c1de5cc54bb8e0fa0c9051ea9cd3b34dc03a122232fc874c883d318011f7504f1542cb20605fa0e167edd705ca18dcfd472515a0e86c4edbdc408ddb24654d8e4b0ef1ac07263c063ef16d53ba74c47f4de83c73e6cc7a21500c2410083fe4118aa7df06c9a074e27c591fc80d1126afeec24571a90243f7972b1a7e6c5c31c84c1cd94d0a9157e2db5366ab960b30eb01b9d40bcc7d95905d3f8b70186df067c62e54294ea3dc571fb1ba7b59a5bc2ea8bfb51382e9f34d2b426613997ff15f969178192f4fc286ecb79c1147268bc7d3312db2240056ce8e0859b9e2cb8498964c42bc128c274316e576680fd6ba59fc1251cd6402080a029a6312eb60a328688701cacf528caf239afbcb2a46264faf7009028c2fc9c4a1e483a2d1855c79ea0a8cc9a9c3d78a4aa775119cd798595716419e0831dc9eb649f9bfb4aa45aeda0b2aed2809267cc29b0193821cb46df2346f7343366b572d38d13324466c23044de8aec3f5828c3f6b933ed01ee81769cca6f4ae8c4c426353c1d1a9efa74a2640c0855c3ca195561d4fdb9a642372b2199162797defa3e83c276f5154223d81367a72a6b929ee4de0b8beb2e5be9209de131331182315f30d57b6466ab2bae33c947ddabae4fe270f6881af04170237ed807e319d221272a90a4c7a86099a8492053892b24280880b111f4432f9c3a3d49b8e0ec8201bfae8901ce424c02358846602991a8a4c18eb9c4db82725b036df851aecfa0c5e5e58e7ba1f8fe2d78e224c46b9a9ad584f2c7a2ad511f1fcd3c4cc94e013369bb769331bb5a3969db799994d8da6f28d89f5049e1339d917c8419dcb2aca1541bdb7d6fcc8f67644a9221cf18f7222c25ff48d81a9237ec46654515aebbfe3b9d682c5a49c6a8ca726722ed2aec40901419146192b7441159427c3110951f0ff402ba557b2ab18172c6919932f68ae1c78f3677e9f1f1c50260829e4fb3a4598e3f87a86793339248ec1a431e7d9937c0a1210314a805b8e3057df4f67c38b2e7e36be5cef8d6fc0451fb9fbe0bfa6d8f90c9b3375e64b71682f6ae50bd84a10618912e44e65e00b008870f9d92ebe620506bb60f1828e20358502c7a92f9402691fb1c77fd46e6c62a610a607413cc6d4ef1e1fc98157a835f0ff997826704af0408fb8cc5f4910a20f0abc1f80f909e33a8a3915e1ac0939d476e5a199cd4c9b11708162a668e9191524408d4e572ded8c3ee386df86fe0379fce6dc52a62ea32ca78a41adaa7ba4d9380ed73bcfa80895c12002cfb09fdc0d6a3d4dcca8f11109a10209575312689a5803fd7b5106b4baa7fa4b165a8ab589374f8690c61078fe14f4f22e21fcf7351707b18f60b7131bce1a2efb71b192d752bc4d30d567f5238a24e675b84ccf44ad1c23edb9ae3e8f722e02f2dd5c54725750741eef02b46ee410a17ac32081d9bf1cc572d748731cb2412a966afc08d951cb5602080485b672a27de8f30090d684a06887c92bc2400072e9d6f470c50140c399d7f31bb757f78190353c08d4eee8bd56ca7fd1e2f1b079e6aabab0af4a180832777e8303829d8ba2cd14bc40af1bf97de08273a6b00522cbafdd18ffb5437b292cee41fcf60114bb1d40aa26dbf1e1d4bbab201d85d705ba171d7e139f65288d3cdebeae745d41ab0af345f33d406e0de5378b92b4a3fc75c9a4bc18fcae09a10aae06a47acb120b209ba5ecae162d4314ed0c82ab408e5e493f5d26c8070acda5fc9dd022609536ce2bf77cec9df5032e376c39730ad6beb2b979747dba3554db17cc5257db49c77da6021a0bb157860287b3857cbf39ff7980d2f60ae184d18f65534f0ba7a3272c9f681f62c5e236de6421cd1b583f0562cb95d6151631529895188969cebec2f7600a17db7bb2e108bfce5c5ae803c3b5cfa1fb7c29b39b5ab2d3250b823a732d6a3565607406696570a1919749a3a13f9c8e77d74d2f3f9c36fd5fb5b18ca39566cffa908942eb70174d8edd603ce3335664c5fa997625896a392579b4129be65ea75f056d465d1c6be34002dd02e4ca0b39b4b8cccbc5f6d6c7558b9a65fbb1adb5e6c9e1ec05952fcde1f886acf97027fde52dd8beb664ceb4bc0a707f5c8e729fa054ec96a5ec83154694183e989576f0b505735840e1bc1e01c461612ca92d9fe4535e6f86fb5d7ec20e6f6f0bbf99a49a7d07958e7f70e465d57826527b578233614d6359151b991fbfca9b6a126eb5c723d9b565a258ea5fe9e2c002dcaf8aa6609f0bab7bc4008773a3ea41d5caa86a794a959c253448ae669862712a816c66d353050599b3d14d8310166e1b774b29b6c49290e790e65afa5b52326ae2a8da7bc91318ac7d624d015f108912a2be1f9f8ecb881d9b535e16ac3ad0681725ab07759dbbbfc83497c8712443e455520a9209ed0a383b0354cfa0e0021307d26a2efdfea7cfc812b5f7d0a76d2c3f7dd0ecb2ea66a5214cb9913e835a9e5d706e77c9de31207bcb2c1913a16fa2740ec8c71b884b69dcfa65b878c212dc96f1abab2379b8380d12803717416a4750803015b670377a1a18c1b26a91a40d41adb2187a16d75ef5a9c9fd7b25b0e34afed06dc092719dd75e4459561788d475261a46b765c2c2ad7c12446c7b70e44f307f7987f09fc8982417a4b38aa441c23e1d3385f9c48995dfd88467001401ce4119dbcbfb745a98a14bed76865baa18a724e1b56b764c8b91115d800b00fddf1a01949be723d9f1eaf6c214fcc1483a59ac1b89732f46d343612309e32e294e00e8f57b5813145f409c31e980ca1c9e9a2457e945956a58b70e230e5db6dcbe9459226215cd205b5ce1021fc8ee97ae999842daff6538bf01183fdd58b20f1d02a3b0a950c8e1c4112b96136be8ed381f9c3c8b6ee16dbd781174f642f26945f92f2799016837f4c4ba011f8f82143397664ba310777d759c5f6e169747e7c5db557a171f48f7864906866f54111845e7e98c5008ae08cef0ec96e4958b123f905f4a8959fe3f0f65cf068e2997b9b115a030b268efa6be0e741066ee05c6aa44c015602ef038cd62a698fac3653bb1270705fca687fa3317b011b886588515fcb382d6820d819f5e0a29053277cbf2b98669187341988fb14a07a66eb94f051b746ce9735014b818b4a0b465a0ad82c25dce94596fac7250296d554a94fab54ca967497e490babba7d6ca48d7091e81007e508bf179a166c32149422bef70aecf31bf7279eb98d797b52bc09585c34c3b5bca296e3666f367e1eafc714c05110644e2f6c41a24ffc98683ad7797e714799ba7a54d28dafb2010cda1b5559bacfabab8a91358f33fc511642c7cd403a449a95a7bbe8e40ee80e4cebe39f1af111c2ee3f350a574844d3dd72e42478ebe261dfee1f8889e21888d92e5b99c55d69c02ae143270f05aa844860f7f52889fa0f306fc2580f545dfbba9e229fa0fbf9aad089292cccd29b974d85051bfaeac61e8e17f7c20549d61343b1109757ee996e4ad0951ac51241aed803cfdced22f28667faeead3c59469168233766f02b4b5aba3f9b642eca59d1b18dd9d9f1c3ed901e5d26c6bf044c379a0e7ad3eb23eda18aa38f30d078b3d5260cf49b9b6b14ff19b702d180ebb90ab73e32e12897c8d229acf47f266c9c7fff03389813eefd7b5feec0bdbda25e13ea72f38f87876054150796319f683616a364abb4fa2bb17c4fb507cbedf81784c13ec5310c1ef8ba8d3963eac7891efb906f857fc63ceb555eee457b855639c39f2df54377d44879eef0287c1e936670dba20a25f6063a38c6fa392d0b285e278799e4abdcd4b725452f12d71073778903d8f11f33c0ec5613a57dad1c4f4f9bfec3a4f5e700dd3325bd7a49fca389f3d74fe7867bf33a0369f767124af7bed6ee1061e12cdc7e82b9a74a5c8de3f65584c1c65137e68873c72790757331db91cd80681c043b62acfff3192f13cf9c0c9bfae65c8200089f7b8392c086a3cacd6d8ed2c22af82af33203eda35a08193604d10adc0f8abec788c61d8b7f5f9ec67e46a5c7e49dabca1b774314c799e3b5baeeddda2769229fb45fc3bcd5f51b3d246909cc10c1e0a67e2e8844d61c17333ae1b4094a228fef8d973186669d1597de0c5d58035109d2a9cb8042d1175884412912d63c1b9bc98626664cae7a85eaa154d48b4c96ea73dab87dea77d093d989a5a5841a564a2af06cf1728ed5df3ca6eaa902203193ff26326eaa959218527cdf15d7a0ffea920e7f21edc14063195de3538f4522e05d86c57c6460fb91adf2cf348e3408563fe53f0a53a6325be4e93530c867aa4dc79f435fa9f5c789562a958c96ba53c073487eb0283bc715a9638a263e633ee91f98e7141d5b4d08823ee535227855b0be0c99addbe8879f2892fa3e56e50bed0cc4f7a1c87c6fb00dcf93ff631e37104fd5c26f9927c9f7b799d8c21858463f1fc83b19a5f255c23ad6c407e2551236aa715e8883bf099d700bff9cc7de02d4d242efa5af92813c7ea38b2732378ebcbd2544e807eb52dceaa2d62430b68fe883708b0b4f36dcc2337995d89d7521110c036f8d7c20a0451da2687513168b80aa81c4152b6d688515cdb27b4b7c1f06661d1a408e5f77a5ade2d17f9a46cd7b5ad60d6239b7e548dea8cacbb26ee76ed289b067cfb22ef74a15ebd7aa0d1f3b05dc8e33c22d698c401048ed32edfe29828ea6ddba06dda113ba434fe8873e062579eebc22792df8703053c1821108d3fb20a4d057dc1419c6845402c27c9993777ad62d60ee0250403af1e77e6d2065a9858985694b70c3f1af00b09182bdba7c41ff0ba54bec584aa41d5cfa9c0bdf91bb6a7a5244bb31b05e68bb0582993637a2af5874f014959d29f1942b29fea84947ed01f5600dcb7b1b39cda9c616505240eac88abd2201ad4ad1507349b829ea969064d0aa09e8771729250c59b6c6a3b296628c7f0028a0937a23911e60c3c3373a37a5cdd8b157c1aa4c69c8b40996353f54283f8b86a8c8312007ea4b379daa0b7709ad25d30886e8150a934167dff3847e9824c82c03a8dbeef3e729ae8d9b500459070c8a79a6b33b9519a437ea7e15102caf5a3656c8e9563bc1bc4edce21c01010f28037ef9a62f9dca9dbcfbd8ba28ea644a59a8a56fa28dc2b7c1d5bfaa94de30e17c054ec1554785f093bd1e3587bb7cd0e20562a7a8fc3cdf291a2c50fbdc4ca35441d58e07cbb29ea2aff1e6c199f9594ab728895bdc73d4d0573d0104072bc06e071501c1f474003fbda0e395a6448b50ce9c9091b5ce863d1dec1a55cd793612e3902aaa5297d5e0ed06ccc6fd53889fd435068ab2e6bd336f3478275e3d0af10be3509a3a0d2a3d5380dd0e7a9c41308f064834165df1c1b8011995537fa7ce97644c3f5c5c310b26468dcb90bccfc2dcaeb7c0627458a8ce7dcdb1f7740e4c3e2f094067be444f114340ef346c0bc1f6c96afe5b4c34811c76d18794eb28b37c8885db80eb4379880029e6a80a73a42ca13359b434de86ff28e026d8fd81221bb851a192920c708387d412f5bb1569ee42f85a11ca7a7addd541d1b087d9380f57dce6638a0f7d1672fa2bec93a213f2d3488827b0cc24a1effe10e2622617cca83cfbcc5923a5fb12ef5b5cc446ecd05a47412471175fa546632247ecb1097b0c83575c61b7604ad18787f6ab771b65d9a0811628e05f7e03262e47f22c1b422ca00525250f9cf518dc85d94be56c33b430cb2dedf87246c33e28b60c993b84a9b47711b1895e8fbc16b40d331d9ba75bea327f6c35c39ac75fc47dabbd7ee14b7285a8637bfd47afd68a6c24426f35e02c835f79783882d130abc6b40ef6237b002a47c46867dfcbbf30ecd1e4309a236330f70d11e66af451a5d6312d3dcae9fb098e189222559c00a85e2876b6a77ab5a7df34ac5574d5b17ee693fcdb9523dd1d5208a4672ce419215d3bf2a2fc8fa38d64c7b0de239566c8fcd14235764eb696b4d50c45b394a01d052ebb4b9b6cf8b272a8cbf30632d436c32d0f1187171c7ea6ebf520644609f3b09e424a36afdf661ae818abc993d72be18afea381a1a468c1f470a8a344d697da9954a2bd543ffb9001b4c5bef1d307cb409c6719bfa4433dd2d362b3d3cbb21195d163ffbe0f4a324e3c9ea6f8c13e54bb78d0e774c22006b3e62d69e8eb387e7815acaf2015f010daa4c0146294e9029cd4202469ba88266220dd523bdf50f7f4a7d3919d9d8379a26591309672bad29cd21413a4d442f39d2b9d8018eb931837b2e43cc7adb53e480b5535c28a74341c0c2d918c49fb55873b673842c2298dde6f8b9575112925b0ccdb0f2b74bfb08ccd6656d299bb61e51d3c6eaa51781ebc2d0caf8669148133fd6a652862591e73e861476db04f802fe94394791572433f5d53828262819eb4966f7785cc12f8321b8c95988c17353c6bcc456dd9e77c4b499443bf05a905ace783810a60f5b30af2a150496f85ae26ba2f7da1e399c05780c1a8d0829dc3ef5bbaec472f5db5f6cbf205e35b19dc5b52c3b375b21444648a0aa38572f261e5c099b1166e0f4e232534babcb0588c0361b6a9e2ccc3a0b7e0440796b67df93549fdd4f99ea5a557de0de1d2c303e6dc524220a67265c18619a89cf229d8c176ab111cfb4affb555557c63ea39e0d5c15463dca3b73b374ee143c9857fb6c378673c2bf12e987e42ab396078f16841795475e7ff7ab84a4f1aad0d3c13cb463b4cf3c8529ef7a80dfc538398f9326a84bfca54fdc2880d527769c5f37c9b3317613f48939468f397456f5dd694726f221e544bd69e44f3ee2d1c58bac765af4cfb88bc235f31b48bac05ac981b62156e94d059df188654f264aec0a3fe654e08f046d08df523c0622142b871b08052e42180bfa837abf67078b9644fc955738c487e500a959e6f179a959a8c08b1c5eae3fe6800e616157695c04296da4f1f065279721e92d569fde2443f784b9c603553bd80cdb412d88c581113430336d369fea435b292737a4e04c9f0e10a7e44cae99b86f23f984102b5535c88900c66cfb557cc3d935e394394f78ab3f5a222be79e035e2f00cb09336288f27f0b349f73ccff526b0a299c1f49d0af9be3d97a9273330aa05bd943747bcf91501000d675ef0d7c340b471876a2e8e1422c89ea157128a7e4f6a439ddc9623973ef64471fd241dac44b5bf461089d1b08ebd028e73720e3a3455217ec4add21565a8b6607d09ac1786fad02e974b7075958792a9da266b6cc1e8dd568b997410a9eb79d2b508b8b6f9c1a70837eff04e900daadea3f78bd73768ec06628fad90a55b5d4c012fd5cba3b9e48be7f7db004478ed819bc76a79602a0d66202aa23d19188800a64a4c6d7a9a29b05d9d625eaa7e7d293e0e376ce3ba625e2a3d184b374c575a0d0342b2081f6fc44b699951695950844c324e065e2adc2a6bd481234eed94ef920ac5a4188c1251efab4a432e33913bcb4b096290ed8daabe617c7cea1ebeeb3d2f5598a6a351589f71b9bf7d8e4f5eaa74a07e2c97ff9ecca6cc8ce488cef9bbed1087f791d64cc16540211294e24c0019f2a34e7ba4a4891f347a6d216bcc67d5ae0f19407c3e52c13d8cd6282d3abf37d15a2ca2bfbde2a466b51ede19a17c6bd2e95797e2c93694b0f94b0cf015ed612512189cbebec76ed220b43bc3762bc2dad6b2d30b683c64078958a1f4c8ec881bc3f8a85e91834165310fe4c099e16e87682dfe80f3a67580fd6ca326b4aa23a519c63815ca5ab509923ec10eedd7736933e088b0d426d5d75bb4cb31ad6aa345f8f5bcf79c8537dd3cd6dd41199161e44a8f7e58bccb2f3f1407d8e8aaba16f8cb9ca788a85c8a2beb9b27ce534d859527f043b4f09bf77b0b2c45ba5aad4ed17e24a98c8c57f19f08bdadcdde950382faf08d448ef6e58873a5e03ce6c9613c946320c501bb4994c581d4a2bf231cccff2dca67d2241ba0471328d4edf966b72541fccc09c8c774b03e0e5553b907e257b3a19c56b8d2acaeae4eab2e502b774b9cc0de81b20d5f46cef5d07adb16ae3a1976c0d2c7521f57921cdf6182bbe84cacce045affb8927476afacb340e255b7a6ec0225dd62953ffd4c833b9ea12b0104b4999e54d17ae0fea37efba6386fd1b11338e2b1201508925434de3573a24c1771b846b10435266ae9c2704d81aaebc05fb84535a6e278699abc24e13922b955c52c3b49a252daaed2d2fca970ae5c0a2dff344f15588188d1a7104240dbf3e1911bcde618181f00a4fb3b57450452d3b5f4f6c087466f2db7e33f714887f014d6d6190a8fb6acb347104d132c971a9aa86e0a4130c8902b5ffe7b76529d4328c8b385c9ae54ae13530207eb30133b9fca05e748e1876ec7d8e332b8b048b6715751a8a75f885914573259ac90e6d1abbc4f4086b3139aef8a9008f5730c566f58a1f536072fad4a919598a8a48c12abcf5a3eac7eca751f2e4d84c458804be3364515a9e72bbbddbbc1fc59964d2c691876e61c2ae073c15472832927ab00f107e722f621db0f436b3b944f5b5ee940752b75c8debaefed89f2a8ff90fe2a647586b2b6475fdd66a8e7c997c58116c0c00651aa2ef301c23b6f845c93360382611594c38e4ed6feb79198c20d31c8fb58ab9b9a8a5885dd776647110e80ef01f8cc63e0af56e483831fbba468a92188e5f7bf988fa0385f29f0ee58c836b0409de16db6654e98971cc24c78229f8ece46e16e39003dcfc0f708b0bd7c0a818ecc837945d1e3d94951f764e84dded151154b8719d8c971f9106f487002d124a793356a96198eb6b32c03b4604a531f10bbedabbc6e3d7c9e71e89fd14315dc3b72c5b94e16bcd59349dbf12ab27cbe7208b4305554e2464918728082f9904ef8263e10092dfc2eee2071cd6766ad63dcd7b2052f81a9e75e9679828ac45b7622022f3108ab9f2e949f730701a4009a0ab1f1899bd78e880a94d238516f5419b3b037a0be592ae101c193228f61baea6996c9c967c6163137e052a7cf8fa9eadd04c912b33eff3df5b0fa089b8f02e6568d305c7a3ef2c7d9781228b63853cad4ccd52facbfa6137580b6801467491f20935a6c211229c1a2739eaceae49a6b342141f83465a6c9bc5c2a94ba3ec164fd69692a9c1eede9f54d872081c735bec8f6fa07034ef53568897eb04a590407163040022381d45b8d5e165afa573943a0baedcc4f1b0cec213142ed7195a20ff74abde5dba222238e79ca3e1cb87a85b286b8d43deb0bcc03506aacd0704b756f3ed3424e42d093de055dfba8fd07eda14073c10c16bdca6cd26d87cc24ba18d4a7ee3d46ba597a6999dce4f17467106b6a305801016ba60b6761b1edc22f9169ddd961a92864b979f4b26322c1953c34cf6d76d2ea6935df905875776207a462aa1d939b0b5e6c39547f7a3b210b54e96a9d42c13c7a49579211c7d622dc9d8d153983136e797c65f717d475471c560232c9d0d68f517bb941bd47c19a945a5212e071908bae6030c7d958234ed7db6bad3a910b6c5de5d28160faef55f6daa9e05346f19dd2733e0c2524c53b659156ca7e70f1979b44e10461649068d49de37acad24d09a5710ee9eb648a5adc8563f3594e40280857f1de1369d86de3883dd9bc60095c190aa6b0098d3aad8039792995cd58d9b6e001d2b85cb883c7b83ad14242cb1721a05cf5a8827f17fa8743179b1876b2e7e3b88a359e8180adeb05e45c6370915040993b0746bf78297a1ca045460440557382c27a05347c2828835c7c2dbc5d8e4092793109c2ba9b558bd163888f024dbbad9835ffaac0c4091e146424f99a0a1d2bac397464e55ab9d2ca8801704c5569b573888ed35bad27a29776989c558ce5699e4e0f39d50f53f5560e07fe4965aeef5334da1f6f695e586597b7f9a955b74e3307ab92561a8524737a1297d463a43fb8e0a1663b054c313900d40037d7789dfff0c40fe5854f3a927ba09d2060a27d5b4818e1c361d7fe69bc95d069889cb80289414b1565db155133fd7e871c1d8575622d46d79f7b09254778eee0f80a685e5af861afd4a3d0cc1881cec70e52e86e90734ba515d51d6123e72d8b5431ccf9a7d9c9503ed4fcd6613ee012ead7a78de0cbb83008b9536505d3b8032cf9bc2d6b86994dc70aebf3943b4365fcc0339ee6abf55eb081c150e18d58dd73a64c235fac9164dc5ffce8025439dd9c39259c80eb1d8ed67f89dc936b888fd64d3f089efedcbab7e663681b40dea308fd75e964e681b1ea7927317f1e2b5397de05632253583ce4e01f4c3c599740701c82eae080d668383ba74f777fc742ba0825a8c7dee01bc5c68e47230e0f42ecc4d1759cf1458f31de333be15177fd1f884143839fe1de30fbbf294f5963e1a1b021f2b2c76f4f50a27be138247cc2c7d47ab826fd7b3c269479ac64c84f0df345a88c73eae1d297b85574c0389a765c73b7da39c97cb39afed0c694009391e6c7f2b0b0894727a1b1d90d7b05ee5b8024a3a642d726a163a391fa02a25ed180659f79f4747bee448b4d08a42378eb2a7943a6ede66e148aba1b4130f9eeaf078aa318d95faf9a3d087f905c7aa3686b6371ad3c48a033d126b894fc5a60d0744afc553ae0c826e6fbb4172bab747bc56ca4d66fb55782b18a4e147f6fbccb71c21990d2d4997b46695bf948acf95bd6c831cf80c3e9ba774bbd89e8284ecec3e961739fc99c0ee2e112ebbf5dc43c023fdf9aab87a3aab3af85671db7870a4d72fdd081297673dccb0a1da99c97296874bfdb5b2abb073d4dceab39a3a7060e9a130aa9e3f70bd8c86fe6260fdc6be88b923553d94783475424b035135bb543fa330c610c21f0bbb747e8fcf3b346a622e7850f9719e0dfafeffffc6b9f1a12ff26d91b280cceaba8d28bb31cead50c83bc9589f13251cd87bdfa6a1db5cbe509ddf01d125835efcb65156220128a3caefe5292f1928ceba1c69aeddc846952adc62b940543a1113f281c24bb894e332b93a588e47a8d66b03c1a91d583e3da0393041c8a5038715f632894b34dec5f63b61a71997fd33bda08aa95b8d7672b52b930473f648d1576dd985a50f075c42d24cd39d9b0912532f4e01b885ee00e7a4e379754817e5a13d7643f29a2d58a0119797e3c7db39c474a8c2201e81d584fe7ea3702b4c64d1859ba1b0540abbd3dce58c020a2e419afdf8c7604ce27e5d6ace3786eee88ac3e834910cdcd23759f7fa57b98d20e1f1f961a1ac26a53e8035e25b7ee4466a186a415432ff46e244a1130bedd422c2a40d202631a5e81e33150e7d530bd1a6206019a746959aa444d51559aaae3a81cf566928d85ae22d1ee1942ae55cdd5a20105edff1f2c2935200b1c2e53952a992cd9d6c4133f9f7ee798d49029ca54c1f4c0546899189bcc4bcd0d74204d2c2639062efe142fcca34bfd2495f217a3ee2815dfcdaae17fa39d73166cd66dfc89be144fc2ab1c1ca9589011839d3cef2d744b43dadb493585ebb3ee160b7798197a30649388db0d2c6fc474024e52595297f72a4b76a9429e1964590634d442acff2683f5f54a9b83a0c81c8f861838e3088c7918e05ba027c61ec579e084b550c7a0c0f5de01268d7d7c2ebdeec9075370a1fe2629694fe7c0573a7c93b9b8fed6f34e2a20d8af1c22d378ecfd650aa2830bfe0f337bbc865e43632e4c43f4ae6c99b71053bcedf274bf900382818829b6ce86bbe1485a4b201b1adee2fb4d3e6f94960c385e3312b9cf4dc5e7f77e398d850ddabd76be2d0baa5c3baf608f165ec070ee6f29d438d3b359611f482eca35667771e420d8c104a3672b8f706b8e81a6a2822921ec9e16cabcd164fab451ce92bb5e6b0d6548b34697014ad8605dffc86dafb1d81bf392c1627f3714d8500ba6c7fea7e901a034be957fa061e31ddf76e4bc7c98e584bf0fb3e7d10be6f0c35efb938d0136085cbdbba8d6d25cc554b1a1c409983581c545006863620f3d7fe5fab54ba858613b067d14f307fddc89f12f86b7a71f4748063d151431e6d71782a8200121e4237c0de11b884855f943fa2a58673c874370ab5120156b63575796afccbc9204708bd5e3d1602bef771605ec788d24607872aa9826e281db13dd19a4e3616578c19e38cafd137f8ae45596d411010d238a610e616a322c2c00c5bbaa769be6b2a8fa00cfcce171117034480a413e851ef3aaf3d99b35ef6b7e7e28085d7d844f9ce016bb2a8c4baedc8d92007a6cc0821603a50fa7aa558300b8d6345e6e24f37c449da52ed8dcf9d78d0aee143f4b00ca959ae095f8ed8cc304704601377464125078893488f4c94bbcdeaac3b81ff77dc921653c05e7810ad05aa595934eda2affcd442733b4be76bcf5171883109ccc51d11a8d354b1c1384380aa88062595cbff8970b884de2cd8600fe18b33780b4a0c54f466ae441d97675326a47b8764dda6b0b66712a144118d5531bf6f89dec49f54145ecc428da6dcc0d0e295564fd3fabaf65dc8e3e6fd30174b240e84a28746ef070539e1344a66f9759a34b10d53d0f0a7780fe9f372bf0637966baeb6e0996353914e01dd3391ddff56a48ee2c323ff439c64c5482cc5eb367fa811f7373311a64ae5b3fe2085b8466aee195dbcbe1fd95e8d386e6537a1ddecc537b47ff4b65f274cce73aa67e24c5a0c4eae83ac06795ae3bfc6c393e7d1403330c0d48ddb6ba58157665375e37110f3160924e50f28e0520b078506456628ee1bc1c5417f88394312e53d165ff54c3555cc454f56b72b9e43657322ffeb7608b8832db5db0c8832523b1c67aade6cbb43c150e0bed5ca6b003c113bd723346572559c07fa5475dc2295d3dcf01a914588731f9c1dacffd8f5e267acd7758d6f6d59f51dfdb9635075ad64eef8e4369fff1c35362643e0fbcfd98a0e3d508598d6b9d2c1e23e958a2016993607c8db6e3a4098ce5aa50e5600eb7339630c370540de1255378a87903bb4d5287610db0725d822d3c64b495c8af369eb68b1b248a65a11d0dde54ef4bcdcc05b4a3f1a2a9cbf49bbdeba85e66bfbd93b5b4657065f9f6dd8cacae22b55de95220cc6d494e5db4f9422139ccc61d9639508764c0f1da40e84337cbe0174e19230a0f0a89ba0c2d739fae070c651db144bd7a3696a2db67244b7c70ccae73173664c8e6d32de60ddfca48d0b2e4dcaaaa00d2f58af2a98fa33b3c8a8f59e256af880d78a0e5302eec2756c29e2b7ef49e562ba3ff8a936475b5cf88138313be800b5038e8b957ea40d30f0c93d011fb3f51eb0f4128ac2c6f9e063407d69e159d462e1c26e814f8232add8ed28f2134cfde9826382638e41bb2bd15fb3413bd0e9f5e877d4dec0b38fafe2ccc0a878633cde468bb964869d32ff2e5e1444c6f195d123ce642273dd453685dcd38a928c10d38846853fa799639a40d8a3039da5899ad8cbb040d5d3e7a367e62c4873ad4eb015645a3298111403515f044a78c5236d70983d70efb0465c4e00d4d0368e926b2f61cce10a200fdc1e401b1509a103152312ef9a815afe21a931f9c8d3455c957a6ad6f629f152e49c68c7c923b66a692e7ed39f87887cc3a7a474c31f4c38af0346988d01fef73568848bcefa4267bdd3e2571e1a85ab47c7a28ccaf1840ef3cea8898331cd24538dd68ff604a427f540752a548c0fff5ea6647165d748e72388b78db6f91f4155c5551527cc700a0ea52269b2acec74a53c499318427dc898afbbaaeb21a4d972089536f6da650caed00cd2d93658c7a9e5e141c5243d88bd781e5afa982f3f0b6bfc0f68175f89c31875e7970d43511d3b034188d1461228609e23b50763b87f7bbca5079cc5e9bb60b44f5d85186a8909e02427dba609e296fb01d2934879cde4d27fea1d4141b1598d3388775a4643f8a50909b0026b875911e5311cb19eafdf141c05a7e6a6a302ddbfc7c2ab8a40c3d3818a519b2fa69f266d76b97e737480bcdc66ab73d5061197275e14c350b9c59e3cc0b62c0f323759b16443ac5f6f59002807e2df36e13eb21b985369670792a9c508d4d3fe4f7ecc5e1ee4cc4d301fa02b54911e99fa7f9f5a926af563940fee5034b3bb5f0c119aa3921b56be25c1d0ec83390a570150319ccc1b00623574723adefba7609ed0a2f01244fc7c489395c67033a447a4bf816378724df91d42f2a62346add80a2c263729f2f5b043275825eab4869e0925b778d71246b431e32b45ab40bcc0e3925b7bdba2abe339e146875298ea83d21d76feb034dbe2f63e880d5cad0581be4925b170dae1f732376466409ce88acf36e3b5113d609f2ad31be99ddfc23607a45b9eae65b69a7f806409fb4fc42228153c3bdaa351aadfc2c9e4f145858a05e61e2d3024e2062a1dc0181e9b7ae7e433202cef4276d75c4d798cf04b1a793678df3622b690b0bd45bcb60bda22caeae9614abf736b5b9a7455127e1e219a403eca741af523ee67a7a19285002035094693d06d5dfe3409b4588740675e084c13aff151fbc9ccebf455b97b0b52e65621d22523763c7fd8591c862412084c06930cff13b230742f683c69e7434ac856c58fa9f0f1645f74cce9e1760ef0202f69d89d39535cfec4b21bdda931f8ffe807f99d0fe2f4b23b3002f635af480f1ac664778c5e1d91f1b281fa74b871a5fe426cd401bf658e85e2ab4be24c8939c220a796170933116407fe5279c67edf4bf13edeba41ff64fb717afa51284ae716f69844afb75448e5bc586fd40b52aa75e8d351f60d87968c71089c2976903fc47d32301cfc416fd359ded58f64311e1b16764d876719146adc200228d8f36093bf4ce74d66e686ab712de9fa6584017981cf16480104bd4e50d5980f405f4bc47c946a282056e7795ce46c8a4909777845270d98865588dfc84855440d0a7c0c126c807a15c0c2c7155d27311d21f45d2496bd0f9bac785c90d3debb5388c804b37f3c54a0b426bec337163c5442124f9ad38fb408cd1e953b022be3052c5fae0f227c504a43c378d4fcbbe05210f94ba717981f61b7f547d7d0a342eec40476abdd66778238bebd1038af2c6d68e3c33cee4b1628962b5f13f9c6d1e1992c3c78887c56474dca7e241c787203f0b375d200edf9656e79e86d2e1eee20b6715bdd95f459c4922dd071d4f0d477c6a30a629a272c9b805db9170f3d5dcf94e1346d1ca6f1a449f0484dfb7009ff46836c622e67e5cc41d0ec619932141a977aabd5ea20745caa7dbb9a1e20a55f9bdfd0613b66e0873d9ac2b4984065f300bd7e27ce7a5371f50ca8f8acc9a0f307b4e576573a37e2936f6013eec4bc343502c125db29d142f25264879c88c0106d682c2e45a554fad3b12ab5bfa285221ea1c6f33a4e2825c3ae9707fdb309db964ae68067dafd468a81e9aaaf633fe0d8d06415bcb566674ac6d6dad59130b4900ed510089c95204a3480be51ddbbc286de7339e3be2e9e64d517324d8530639c5686b8c06c92946523885f6bdc732c56dd018971460c0da33708a501601484bc1b0acf6205b0e93d66b08fe207fe98379956bb0bde029b313302ac7f73190ff87363c0b793aac57357648a2d40d93b36117c47e2f8de5e9ee4a5d6c875ab2208c74eefe280308ca66f18acb2b38e29592a5ecd5308db1c58568063f27d19e0124f805880f6c558362b27b39072ae28d62d8ad7d7102964b0cbf2ab1c4de234b3c2a1358db6f6885eb9d8ca2cd8b13fe2ec989602adcd7f0d64010c2b067839be21b03ba57bfd754f88e675a7c641ef2b8a2fd6c97b9c43683ce82fac49e915a22c8c6befe91def503248f5301111aeaf64b9c33f14d58230060edf888113b48598a83ca51d0d1544787c5f41c63417868d1bde72e62aa0bbf6c12d3e13359bd89097a8d92b5c490804e7bfb226bbc5a0f907321ef430eca93fd56c0e1fb99e0cd72be82a639e90ce4fa02298bb99a811f759f5624e5a891988b14899a39a42f968e64dad025b42252dda81d51aae4665574c6ed30f33083f2d30738e486528d4610ccd583c614485f51c7cf3e264804329c87ab497d31fff8c08ad9976f501382f7a3b08fc8c6b7220e4fc84e8fb10eea11807f400d6226182cc516b873b20a91848f242b9b40e9dd7110f1f738876b0bd7ee85e751af82d13490562fe1746e35337b680f820d60c90873d5ecbec393dfd53477cc1e8ae04ff4c44bececfccdf94c823955acd3553bcb0dafb8c1ca8f23ee77f3f841c8e6e3d2b907efee4b70443ff912b317210bfd824b29ad4c447e1751d6e2a1892f010d3a14c939d68d90f7e270d3c3931a52702ef01a500ca9047d26383a69e1f29884540a90970846b15031217762f87150e4d983f7c5cdf9c95c32f8cc283799305596c2aade9bfe958835e79bca506a538c86ebb7436dd5d55dedf208ce456d0e000cdd3c9b06927607d1693eb14f1f8871e17f9bccf926588b920e64662a580d613454872c9a338ee7ad83bc5dae85fb8389f3a7ec982084fb7c4d7290705db20254c9e18924e2fe0e6cbf7c6eee183308021e0eea18f09109fd0e00f029eaada757ec03dd93a198a7c18f0c58a48926696ddee3dcd5af39911c9636529d87d179f9e1a0bfbd9539c22bd1628ff78d3d1745ee121e87fdb1e808d9983b4cd8aaf02358c5ca143ad7a6eed6c80e26f544025648ffb20d8426de3b89d0fd9d7e8e388ff912f1718e00809a0ded0b553b803ff091c1c4f26ae3b0f88f67fc3d46f18662ea38f4cff7b70d4a23b0ae198e3b64cd07a33ad55030ce82e97b9f13eab26d50bb79a646b0bcb950adc0856cf6ea8102c2036368608205a5b37ab42141778dad7bba2eff293ee7d04a9928d42a522cc1580367f60cbea560a8381a8c3893ff10c795850248b4c7ed417dc0f20c6b1a14f8de7fff197a66b161d1359b16b0824e973048a1512e5881fb8a5f80a7c41542895c603ebb23956ea652ffb1e468f4fd4ddad58744b9fde965f9d5b06ae96ab19f6167847e2e0e579bbe87fbd1dfd6c7b773871eb5e3da731eb6fc9f8f3b07e71d02e866799b7571ffa96d8231f659cb4d051fecf38d7c2b75a3c80e1094a5dd1a6b0698a793c0739af2407ce59bfdd0e648df58a696970c5c8ae98ea0000e274921fb58227d6f416085569bb91b16200fef07ebbe5bbf5408db8a70adf0f9e73cdaef46aad5af31c181fa448daa3eb0b67f0a2a725fa73422510037e41d5d4ef4444d6cb1622d4adaec65fb83521b88e743dac8283d31269dd4db018403b049ad50342be5aec080697598ab386b1f00394a590fd78fcc21ae922e6ac6c258cc8e1d8378d469599f8adb1a45e678ac2c36172ba531538d7da52013a539538bb5c596d2d44a1be556d12832ad746966897874296e7225566b48d904f26c58d56640291d7d4ed5a62d12d6292d4c920025b1a66e5196ba4304aeda7b30a0e57ace963375f978b64d589cf95facec0fc97c6dfb2285cd0c7c349ac96dbc3cba93c36ca00ef486458431a5d330c2c718ee42c4b415882af666ee938f10988d00f148d01fc688f01f4bfaceec6c020cdb8c87066e7f9112377d0cd48692277e24570be28a89a7a245875249838dd76c506ddcafc77032e7260ef8baa4cef392bb9f5e13dd3980099c1ab5e93aa007ddd7a80220b0febaa6691aef116f34b47f92f5f5ec7277f661e43a9c04d643d1a3caf59df355f25c6d8b865b9a29e10b842fcf858ff908bf8ca23f6cd2883b35ed8c73a2e1f321740a1699636c1d543bf793e0c7ebf0b249a5f488efe8a6dd82882187e7852ec142ff380c9ff9014b9cf560ca9f958a9fb5d39b9346b6cb3aa75076391c9fea249071d04cbca4e260bbbafc2ff79707dcb845a65e64478ec592912b48250ad179f072778ae318d82d4737a8e51e6fd132542909e92404b44e6772824e8f17f12181ceaf6d4ede4a608bfc2c231d10f661bb5cdf8a1d59cb3c0e4f10873c5490feeae709e8da47c0dc990c8698056c3b1690c70c403f7290ba7fdc619ade70ec0c67076f4ec26cac26ba69c8443d4cc6c72434662d5c415b1b0dfe4ab4d6eb29f6b3551cb4c7a9cb92f4eb9acd410cec0563cfa7ea30fd70d3f7e50772584a9b15c9fd78b4a7e53e473d62e903631607bfd8efd60026f5688965ea863b968359b6d4a34039276125673ccef6524103cbc850caa00e1fa3065cddcaf1726addf7e39c648facd483819dac8ea47e6daafaf462935c69d2033e6a13bff4ea8304f9c5b8c7a84a7d2d789fa0710b2296b3d07f386bd46cbd4e2decb5ea7717695cd48a55eb22f82769f96aa9a840655beffab5e5ad06dca26a613f40f3fb29fa0ea666bdc335cb7427cbfabc71bc8495c56256d21400665195fc56e63272259ae65cdcb11cb2ac26eca579b73f4b9b172f8fb2b3c8e0fed0f699e88d7b88d9bced31b5709c1de8fe6dfe4382106b894bc20d8a1f8ae9414026573e60c4c1c910ee291d611a2adb9be36d38185c0f7ab7f2eb95a92de70d2777d895df67fc02678b0f8ac58f616c7abed0c4afef46770d2d75978a8ccafca56c3d4671d92ac63a83ab845997b63b7c872026e9397e6f59398deb7e4ab816e9d6df9f0b6039ee3ba894320e8edce1b1496a731fa2ebcbcfd1afbcb1033212758a39f405e8af2651fa77b674ff992ba164ec5e7c2c702931fb5515abb0ac1b4259f99f7076dba01d25dc0a1441626c78e227aa4cc6790a0f0e464d6cbb2752d5029ccaac69885ccd2370a517ab4715af57de3abf0ee225698ba9064548c65b937ae798b6cdeb2ef4f49f0ae7cffb01c9d42fad9c46f9e288bf7c8c2b5a436d77537aac7783900f33b5eecefe6c512fd48c37ca977cb5c4286ebcc0b534f9f7c283eb305bf481df6f0f57856835067d9bbbe787332783b4d55be5e18599bafadd48ef6c362b0bfc34020918880bb21fe99572f06b3a293d608ea05fd736f1b6d07c874fc1ac18969459fca06ae2bbb5e462507f7f5c6c0c065d4a3e3a9630548e8cffcf8ac25c85d2d282324724290b74f9fc1ea4121235e611e3bcf60c4b320b5f8ac9d8a36bb24acaad56723acbd5bf00a42f800f24a73520bc5b3951d0be910bf11d18dc9ccf3c65fc955f99780e395f2f205c52a83de0f09bb892f327019d4d8589e5abccc6d0db8cd24fe1f0488bf18212b952f7211729bd131a87c610bd840a764ac05b1b3cfa464dda0e786bc7a5e588f74a9b86faddcd68bd8735b32b5a00cdbbf8112d355bd456696c1c85d6222b17ca58c7992760787be0af5de4f1233eeb6e5389c0803e7327156f60cda8d8ee2492b35bc5971a91b5b26b672d8039ed4406785972a8d5857981e537d40fe23226ba7206db13e426cc41cf4e35c8fc64cdae05607a6448009137f17a41a550f2e4dcff28375bb91182ff944b313fc0d7f29db53a0cf841c82109411d1b71474795d0ebd5ad7f28b8429b1efb137521e6159b489589a01dea988e2c895c7202f58fe307daa09a702e43350a1a9c01f9e318abde69f426e5272228495be7da83b9d25a45d9c195d5d0c86c1932155f2ff0036a3256059f2142e64087852fb3781ab69ba395203da12c5e3eb2a3cff697b1643f90d7f1050e138ee7f4dcc384fd4b1e1f42af514c428c3fd97b830e348d80dce0987ec4745a1bfcb1d53a791b80e416232c497e77c98a0494c2512a91afba6029d6d3cb5a901138115ba1c2cb1a5911f74c97368a47bf989f0f0501485fda589c76660cebe61c558aaa1a742a4539a47fcafbc2e3603d9bb68c8229c141d368d67b79358721bbc7ce011f0a094debabe3c7efeb6a9ea081c021784a4874823154d390876d78ded7c6368fe52e0b066fceb83da54e3993eda3df1757a17f23b43a0bb04ab533b0ad81f1a88acf7154dc8d6f7a56c7003b27cc1c32842008dd516b37841e6ef719feed7834c55fb513e2452af5320075fc35f064e7003144e1b3e0ae9d19c6716c2ed54ef770f3264c1cad1ba237daee33d27d077cc7cc28e91ee1143ea02b06b59ae29a884a6355d4de34ff239b0969c180937e7467dbc3767285064bc715a559acef04e5e6a70c59aa2acf3b6876b534fa2fb1e539207e797f2d8eb3fcfbbbf657da41ca11fdbf4dba3f00393fc3c184c76252ef0d3506432dfc70ae8539088ff98c9a5113d1633eba06a29fa3fbfd365120d450e49efc069ce8d4063f4293a20718a9ee4c9b49a3075fb01677d585e2e76e0dc62476a7e1bf965b6410d634f5cfa626f251f07051aadf472934b79e53452a6daff67b9b9fed9f1fc4f8216cafcec13070437c151ab7c37494c63f8308b96e8976256b3e98a046b8d2e1ad637f74135a29b377f2f202caef85c4ce0dc76717dd3a1ce727fbd29a54d3652dac10be44c3985df8efc2b18fdd17d30aab84642c28aece0799d24e2ff00377841753f45ac6f22934f7ae19893a0ad9d37aa80a45a8ee9d6f29b93f9a38974136bd9ca6dac2a3e9560c3445e953d8d404f4b8997ab953d3b53bd334b9214fe1c83b93f90dbf80e1ec9334220ba297c38931650aa9f87534e9001568aa379815f36ffffa31df45d3e500664a4e3421601bca9eb698296bd95d329dad918e181e68421eafd63b6b5dbbf4fb65554495c745e86628817d1514e0e949730249aec7b54dbc96a6182fa54ccab9969277aec66fe606cdc34b78cf1b3103976ca77c1ce57f98be9814c7645537df8098d2f5681936919c555ec0c767ab1482472e1e80e0a06ae8e600958625dcc028d5241375bfaa808a4eab16dcb212f3cf994a971fefa16b2a4780c6576906c64538711a710030b3740d85ce2f679cecc652cac4546db72d0c32d11bc3ade5f519ddbb01b1fd220c7f26ba7f53fdcbeb334aa3f601bc75ba7d565b670269629a0516fa1215761f5a0f2b9b11997b230a94489a911fff2332f8c5689a876e24a8bc0bc19a7d4d6daad04b1b74c3782d31c7fd155b5683ea37ee5abc007032190d626adfd1377c0135fa58b74d3268dea4340fb5790f8f04f6fc97762044b049c9a28f23622e482cb19650e1f7b5af645941623e0caa09c3451850af213fda1c4c0eaab0d9f5b55bba345f1dd16691c18ea564336c6165b316bdf0c0aee0f2a2bddb043cd8807640195fb91b4d6daa16363a04b3e9dfb3113b0344f52220b3816b1d6b28e545c8fa461bd5b3528f361a25e08d0ea1f945626cbc0dfe7c11688ac1a5cfa46613c3355ccda643c9f4c103b030344467b34600ef64ebfec870b16e61341664bc5a5dc567d19bc885c35df925c6092123be236de696f79268e1195511022501a21a6a12f022064d9358cd72a5e4262f0ed99988551ca2321184220d3a43f03720bbb8c73c8eab0acb9897ce0652cfdcc38337e1264ff8685a501ff4a9485abcad723af5a81a0fa0e95d6071d50d51d055daf433583df61513f9c2e399d53194d601e8866654c5561e6f109b69c94d72a0da6f090ee53ac00274bcde1edaa5b1428433db059265729115425bf9c56a4c223dbdd27e8467d9e3e35d02455ca51ee9f8e5391d3509a221fc814bce2f0bde2aa9020b491430b77fcef47a8fae8dae92f9885da01d496a3a6aeaa830210c3f61d9fcb2a343d851a57b7b95ec258d92bbbd4a9680c64a1244aba1ee561941cc3ec895ee8e326cc15d3c3d98a34fbe2374266f2091dde17db4f4f6ca2e7625441138c5b8373f3f5cda4bedb17410daf835d28419e9f0057eceae14ff4bc97cc42c58898c19c96e1cba836169ca114ee41fe41c4545cf83fee8dda225b04eb45fa7f68cbe21021c2b7debaf679c416a142df1d12471360db069d88a528c6691834602ef342cade1b054451e9652b9869afe26d0e83226f0378507a991b9a0a63e4b48da84933155b19c1239ee3413e68125b136ce12a01dcc626d5d4fc3d0c6aa1c423d8f2e7971f501d4eb189a7a25f370ea2eb9210fc5d097d7e88f83203a5e7b32a021dbb36cfbe3a1cd69154e6773c4c59cf7a163ce9b28a76d3124eae3d5a8d060da2d8a6b5692181fa76bd2a7704170ecf447e17e7b7064921de0a1327ce63e38c0b47d0a67d7f8f3a346669ef6900e79b8a0e05c3693915693fa4ad67741a96ab9185728840ccb447fcc0a2aa02588c419b85ef1087022efa2d3c9abfadc970e653b23531ba7baf2146d96a0c57c3f705d2987e2e015e2fde291e17b0e953c32e04ab84b85fa3be589e77d8b16e78d1215d8b927a51c2555caa5c4e0986052181b59715f14394ab996218c5620288b6339031f1568682cb2e68683092ce124e5a131c7bed06e99c9e84ef34ca87da5496a22c4b604b6448041cd5721f75b0301b6aa26bf912f60ebc2cc077b59fac0c187c611ad9eeebcc529340a21d6f70cc1656f16540e0068f7bd564991fa7291e5bb7085a2b12149c25367bc0e71867be1d3cea22e2651bd35501f10050dea81f7d490c6a42f45919b84a32fcb6eddbae834a70dea2b06896aecf812e0df163d505a327e73832d6e138eb70e0de88aaff542846f132668dc878ea27d3baa860908883af4435892da467f7812e8a690e7d11a094e96f8c84c8f66c8282bad18c17a610e2aa6e73bb39f26fb76024f56d58cba5c09342664825f653405a2de257c0a775cecd05cdfb6d270e12c50fc781aa76e0a8a83cef18bff34111aede5ff155e1a69298e935e15d43e4768dd5599ddd909d2de61a1be60040f00bea18dfe6b0f7984aa92aaefb55e90aee036d71d4a50b611b0041c55ac805e77dfcf3e10a028a4b58c5b280e62839dcdf1069aa81b7143a42cdccf66b46f0a013d4f393b5a744c4669f7b2c0e3054100b0bb0ee7b01381192c60194db1b3f594261fcbcebb485707726ec12e391754ae2b9da486b6da60afb5d9fb34e32af6a8e8e6d930fb8a47efc456537ff9fd163bc32ee0a4c64f7e4c3015287c1570b9ecf2d17631ae44e07a3d0172625cb2bd8f4e1135dbd6831a562f755fd251eb5260d49aa158b175fca07cc19cc671a8d58d9c40809638e7f662fbaf38832ffcae4f0ffee62988c76435b820daeff3f3a60714e95ea04ca5415c435fd5c86bad21027a46fb67a7e160bd3da10b24bb9def223b62577c57c037afdfe5c02e9a18bcd8fe9f8330d53dd58b962b615ebde5f359b3880856b82597ca311dd6364f947840eecbba9ec0333b3828c04510f89470678199207316eeb74c2d4c86e2cde91e4ec5ff1960b25f2b830f4efe81e743ba25c2169a8e66eae8ca8484e06a3c69ec67e6d836373048c4995868483f39ba2ea311f3bd3477115a7541b372390c8b59f1ded4e78feb5622bfb1eb4c44adbb40ca3a985830ebb001d5a00bb1647cd639464cdb228e73cab5bc61874b99d758ced895eda19d8bf9e95c15a9580ae57239cd4ce3cd4d694dc8bad6b7beab126b3f4123fe3465cba0be979f4ca55cccf5d7d7c9cecea2022264b00e5ddb613a16b7ef10eb87fa58da18eb152376ff3412f952136ace0f524160d05dab881c2ad4fb092c82828aec5a7ecbde5a150fd8468e7f9caa726b086cd339635aefb3a4e2bd71b949e7ffb04df477be201d1b2160eb606f1f17cbcdb4406f8bb37f0fdb3d109d54da98753f8202b113c51db7b77c66d527b397da4fade4926721e34bd609f4cfee6a09c8b2da2d1e6dcf9964179c9b1b415e2634a817ef59c55db439705a2dd2a0a203cd9c5490eb6c9b0b6c90563c681827d8937549ba374bb0db2d6ea030c96e8f38f65bbf702f0b2dd0a430722ed8f7e7f74e26b26a3c5b0a06866740ddc3c95c8e16555d0dff51037127e8d6eb7eec2a20ce709cf366f4e79aa7f897d4f97ea5013e51fb1f66c53b0295cb08a44f7e4ee115ef0df9b8a9fa3257e8617edcb270137a10ce5c34f3e2338733f65810cbc2e8c6f038b1b44ccd588f8e46a99c552c3c070d7696fb11497097e2c9460e937a727fe0ced8083296e332bd8ebd35203e083f765b24a759d35ce0f6943910859a770daf21ee2ab41a9bcea5fe8035a47fe9fb756c513d98d5fbc9b6d2bc32be4cb361cc5e82dd8f87ddaecc505ad831564c2de31d37bbc060cba80741cd3217945f596e4b38ca517656316ad5dd237f0dc3e42b00a24cc986ed0564b5a3101abf4eb00cad77aeae11a6e3d99ce43653cf8989f6a0f2714bec9bbcf4e67bbb33ee6259c76d14d409ce6414b0d3473e818a79b2cc5e8f7f815e73f7983d8725a9db633940b73fa99aa5aa3b30d75c4ae7d30d9a5a5c6601930713f7ad8ed88dd74947dc8afeb1c25e91068aec5f1e19ec78082def51c38f5e2c38c943c809fea071559266cce384581148993d909c66072cf3d033a7033e8a6e42d3f36b0cbf8648396d3ef9f2c4e8877b9dde88af45174a517da687a0f052fe092cb6dcba6fb774302908088fdc804fb16b05c54f285078bad653cdaf23fdc75bbad4ae283f3e8eae366dbd6b7183236aaf1f3347dad3ab262bfda3ead201989f7b57feb442fbb869efbec9a55a560046ae586f2a97444082671525d1ba066f735da5b9b63d0ea360fe7faf9316af87920fb5f70323dae78537f854f4ad1fcaa03081d0c4d1b44eedbee6e1652cb8053a2d4ca0f5635595502e2a46b136038429b8c5c2aa9977443e4870e03bad4d2d5d630a85ab55a3a88bb268d6b7432e11b146c7a5f96a7dd728cd5f89d14633dcbf07ec9204eaa8cbbe572056aa9a0ef1b3b2742fb0fa03f603a4aee5adca5f20e386fd68cd55b17abe11f18fa08560425bae68cebea85efdcfb3e52bb025fd04a9dadd9c29efe7bbdf78a5727b6c442a32534b1ddbd6d496ecb6b6f79632252903e80ba50ba40bac06cc473d50ab70109163a0f9281c34457194b68a59f56766cd40bffe0f88593fdeb380bef7a6e82920f43b658314bfffe8fda694d3597c70356cdb62b1dc4848a222963fee3f2a2c0e22d851de28117f71468e4c40f674c012993e1c43513df714903021d94a543d376330c85665fc90f188e08ff28cccfd77ba53fcee1cbab329035ff52324f47dea8550cff22ad52b1141107cfaa00a07b1e069f317f7a80f4a6125e287badfa5207d90fbeffb1ef59482283c8738ee9bb253873d3c655ee4adf1c907c24bcafdf376c0cb3e746d4c2196fbc743d9537382795f29a5b41be39882fd1e7c0e85598e59eef5533888c8ecfca12e4b7e2a892583240af5f2513888486220d4a7503888a280fc84f36590f98795dc7102a5bffc355940d8bb2c20d49f4ef886e6b174e5de59a66e6891c33afe92af4aeaae449f747db11c7a779ae2e95a9d2facccac1fa1fef92d796616fdfef414037941a8f75e892874fa0f4b17f21ee5ddd3a58f7a25220f8b62960da7f71ee8e4e120228a81bc4779d8fa8bfba06f829c689dd816b9837ebfa84c7225d068b4293722f44e0f7329177989e3d6c4b4a4947464f361c6e4d8f39bca2073ca7628fd0ab068ced90d468a0aa5b4d6a62b559aac745dd7791e1ab52a683099b70a1a4679d5e144238bbc9ab70a1a43c8ab9e5e0b9a867af04d010d9d1eb4e84329bf062177a40791e75ccaf648da5cc8f2795a00c19427258fd4cb39e79c9c0c603efd696c61657754c8f2bdda837baf07eae5f7791fee8cc2630b4086fd9cd7df63fae8e91f7247ffb8935b82c153b993d761bf3d64389f4b43f638ca25cbc791db479d11969b4a39f13893472bdddd5d762c6350f6e126fbcb00e6eaf2345a1d323b82b9ed977d986d54ec4310994c81d498dc31bd096708b98009317c6085c8082dacbbbb53ea5426512ae7eabaa420e7d456895a81f528df184c4a605049b24d9162548be28436d4640a4dd9ed8a95a6a531ba503aa2e2e4eb3ea20dccecf22451b293d2bdff1e7c4ec88c4d190b45b0e38c4d59cc1d96b2f63f0c27b6a1d502eb39ac13e54b4f01f150a81490796a54ab05f6f45ffbec54ea7d1ae57f721781ed4e4c6121fef2e731023bdae730a59c13e44b8b3ffd938fc35e87a77778747a74d83c1da2f0e8cfe2461ea9c362c141e0a75e89f881d2e67938b03ccba5f22543fa635046bdc4216d4900124e16bf6469490012a2742833776d872b5b126d54d71c7c9c33a196fa5622d2eb5e71507dfa41fdfe4ac4cf41bfac795913b36cf0ef1f42bf622418091251a63680fa1ae67b414440feaa77fce32feeb90fb31a50df1f087c1a44f4e1a0987f12fa4874de5f1cebc33f00d507ff0629aefcc53d888394884a4415264afafaaa1f755e8a2aec538435c37bcfa261be27566c63442c1ab2e7bd878b78ffe18c840888beea91b0bec748286675cffa5498d5e1131e5239141e42bf9fc8c3720901dd7b78034ab217440444dfddfd1d2761797feea5bfdc41ee8fe49312960d14a83efd1810a5943ec549589e7ee59e62d92f8c412087640ef9c4f28525a9499b347f71dcbf10ab3496f7f56df030507d6701d197a27798c34566d1894895a3089eb52b1ecf3be7b0876587eedf94045de6dcdd391f478ea3dc7b1dd2aee3bee3be4827a9e7755d877bec5ed2ee69f7947b493b0584cbf3698df2499774e952ba5c1dba6060fb471b9a1d6d7bf7c83e856d9d9e8de4dd537af744e5cfc13e79f9ab20953be47760e5f2d7815c3d819ee70f059e3e1005821feac422a9120d29a5f4a314b79c5d37e7a4a0e7469f748d769416e6854e9f4e29a5547e9613bbcb59b914cc3961f29cb5dd51681031e79c52da6491ecb4b6bbd396d6d199754533b650297be8083ee91a53d46335362876f4d85196f43da9e6a3c76c465ee4d9d5d7d86c79ec9a3cc6c5fc45ff34cbf444cbf454cbf46bbc3c7e37141032fdd1f3787a41a63f764d3fdfcd5f4fecc8c56e993e17a3b645b32347cbf4a9c768a72c73401bcaa3c792523432be3997d8cfd21b57597665d0ac2021d3ef9875fab30d2b60e439a717df51763cd6ecd45b4e1a0aec286dd30476a443cee4477ee4477e94fb670aecd8b159023b97965869ab62050879bef4ec2ad48181ed38aa845a2bc5deec6ab2446a4112f2ea8ba349619e28796459e5c624bb6459850968d8b98507f64e07682e32bd6cc45ff36f44987e947ca80d48acb061821898808818088914ebf82b05a47b927552905190c7f0491e794e9047796482dc95208f92899647792b628333aa88918510a2388138491000368a88410c84c858c2429cff0e53628411b880c20a95279ac4f93a0eeb418d1c58a1c610cc407a82e8042a7ad0c5121334390115e2fc1f8749329a78c2065c1c618829ec409c4fc461048862850645008293245811e71b719812d9154a4235228258029338bd69133e155ab044138804ca14faa0f62e2fa69022828b0244820825513441d1148232ccb0c2065e283141954220d4595cf19674162c682a05c9892cb809cc94208115319011c500c90918e4962c919c78b2c6f785c005267840b931840763dfc24061888e895d59186bb358630913bb9ac91289b67402a3ec0418ec8e1d3c9a60e5cb8e0a1624640a4e45e8808956c4fc25a6b0c9126989a2fc6589b4040ab6d08101820d6c10cc80414bcc7a9655cc78419319443142d8ceb28a192c9842984102ceca14ac34a18a130e898984094e2c109ad189c40f28480399d4220a149c617482275a5c912236454ec0cce70aad0a3676e0848b32446e3291b993109a9854a86ca004c735814ae6baccfda0886e04527cdd0890684e48339086c0c44509aa18a20ad1756eb24422811a48244042ed62e49e8a8a44adb5561a861494133630c2892c3c1a46955b12e428a75431e3097f1d30cb2ab72cb22acb2a372f3822609840f07e06d41e440181365c4006164458e1822a3a2773befd2c53538a4f8e3a2218537c411b01911511884090374cc1b96e2b462a8861a568c5030bcbf25c5d0df34ccb00c27c11e0f0cbcdecef9282937368d8c4c2abfc204af65af61f7fc8a3ec5de864afb5de196d6ab57175e816c666c35fa5f1b5883342cbf48cf186a13ef4622b75a9554ad488a2b9b7789c759fee2a0481e594fa2c0c6ad1f70c04794461d1660fa594274b592bed6696f573f77a07e55e4f3351f0549d949c7bb89a415377af776453fa02da18e1f9cb613cd877eb90bf64ee2ef39cbb3be5a60c78430a29675618c26ca795ebbc13ea03532c2adbe2f202132333b3a2a961d9c8ccc8a87023e6c60dcccdbffce5a0b864f9dc0924ac26712ca84933f36254d2ac491c0de5058a2653936270cbcad96a499b2a4b99c5f460643c5ae0c2619939ccc747066726079524032325894a9233871ec91e3a933d2e05460b30721ff9f8f8501c21286d920849f74b9a12c6d1381a6744a3525229a9943ae4c10218194773588c4ac96152f4acabc2977ccf7be538e558c1934d72c7cc19332b742d843a3a01087978421ddccdf1af1c619863070bd57b28e7b0ee24ffe423e4a680fcf840c1ce6f99b13432ab554ccb9ef974ca53ca8799bda11d3c74e4d14a4a2136994fa70590725610c1c7932d0000f4c2ab49f5071206b354875087381a0eb27c6a83598259ca5dc5aa524154c82bc8d0c8fd234793a14d53c8c81e090017409df0f5d7769241c2544adc19b9a5125644b05e644f6ee12a25152a49a574230a3b7b662513c3cdbcec91304db479ccbe530f3c8f761ccdd569763e7deaee3c50e0ee1e95d246b1f3c1c9e3899def7528dd4fa31214119cbabbd3155849e70bdc9d52eaee945277a7947e2c2e30333537626456352dd4cae5e5e5592adce0d8504a9dd65a5b75add6b4e8ba4ed6994a5da80b6e79ee920242a54b9f76e1d49a29086887e339eed4678d6d515bb6703929b9b83c0ef7aa91776b51adddaaad2db496962b2787bfb0a854392056c3be56705a650d3fc1ceaf2d95a668ea05d2861d713005c48f38acd6662cc70a94aa202baeb5140d4f29a5b516e446767c52a2c29e50b2e8a3cce44f5082524e4f0556fe689bf8a46b6c69da7d580d6b5d4029cb5f4d8b0bcc0d944d4cc73975ca751c751b99191a970e3077837de240d98332d0e6a895ec8d1aea5cd7c2754ebde36edc7837f2b99f9d57abf3439dbcaefa043947a2422eb2626473cc02d69b69cbb03e373b0e578f06d52d6addc2da5fc38ead44b30567a90b0e81b25a55a92026f86e1ec7595c58f5011ddafcbc2d36d6ab1a1df64c923d5df48e634ea8c3e664398fe31fe7c6dfd8bc0af5e55df2c45c0c498958964fc1af7504ea4e59589ec7206e052a368f5c14991a5899e78c5c1373461df68f5c11d76d45c5c432466a099c3e5d7eceffdf781b30f2f731416676fdbc302f5ddc930edb276571c5648febfbb9aa9483c715cee3d1dee0d1e354c03678ecfcc2bd74f91717aeb58b1dd8512e4de1847aa7251634a5dc6ff3fd944aefcc0fbf9b26b35afde8e5d5cbb4301eedc5e36ae6c73efa990222e38468a6584e86b95887fd29336c4ff9f01ed1bc47f337f068696853ba6db0ec108f358f625d996baecc2395d1d51d5d7986ca643f50983bba5eee0f93e362b9dfe5fe305b92925c79ac49ce543beaf78b831a0899ec99474e448719e548d34eca33099446e4b6c2284bc95c520ad480e91db7604ee390c2b338e30ba9f1f9de61125b8b1b9452be66f7dc73a0a738e7e26b296f10767e83f1497715b8953bfaadec91f3069f9cd327ed39c715a51e766125974610754adb29472bad5cad7808ce29a5b48a2a3cb9e3e4814cb9231ec8e43450d94e57dd3dd751a74eb90e01d4adf4ab9dc909767aad778ab329cfdb0d527429e67881339de40ef9aa270f7872e9eb814e0f5884789280228fd22693a592a4c2832aa93cea38e20ba45ca1209106931a247144ae3050a4de4cf623a464973b5c12b4dcd4cfa048473c5141c18e56a747c3266de61184f94196a38e5c7be4fae38f5c59c82ac83508b9be47441bb9be5d45912b5211644824590d8c5022d7e71123d7f7a94846a49154eb1a4db9d65a6bad2d7891e97bb7214a90e9775656272c753252106283abb59ed184aa3c90327d0a849332ae54b1a40512142b70c20f52b5d65a2b151a41a631c8242d84600291104738c208b1aa20d733cac8b5e65a6bad398460471d1d28b83c1b988293ec0929304d3193c22c06579a908aa00121891878c06404264b3168c184240413c088a107638049b4ec80074ae8c2da6459850769bc44c1be6459a5074b7455b8a0659a65953180e04ad467438d366cb57a66418aa55d75926308169c43b3c99c4d5aad774ea793f7420c50ffa777ba5cff88cc507da0de915b3431c9f54aae5e5791962891845c3f86de7130726a062e8912e4893df9198809c3599ba2817b9b0e576734b93a94471d7e23ecf8b9b2c2aca3c3faed841ffca83c1dd637c28e3cb928096e297b77677f1ac54af6a74a6334ec469323c5c6c86eb3bb2d76052c420a6296470ac648a764ffa61dcb9ffba0bf435920437fc91d5aebd05f9e8a44f961eb724354c82e539f9c144e4a2d940203ebf22317c50573459c94919341f6cf61043bea14392c7cb7ae1f57383f7ece8fe18f3a21c681c39cdbe334ad5c98a37135ae8833923db6de9148414821fb73537ae7c5614a44179f5ecf491d7a171d5e156c767243d347cbfb73495c17fd5c1313e6329f957b393d9697d33e4debfdbbc8612eae8b7ee186260fae89f99a346ff1e836c8aec2238745f6ef58f0c8cd20fba73c3c722fc8fe2087476e05d9ffab78e44c40f1c84991fd4f5c920a52d891362773d573df511a569bfce55c1a438ca184a529b4d6b4e6d19aa7c2f706760429cd2cd7ebb0654c798ef396615d9b4579ce245833cd39abf9ffe68f86798f3c75d834cc8ffce53f5b38effaf9abde51fdc478f4ee2dd37f712e068f56068fab0f1f8f3a3778e4c9ce84b1cb8e1c4665fef25fbdce0d976557018f9e0d1eed51d0903b93124fd2a87314cae0f1e9c7e0715564b9219937c44471aeeaba2ead39ec878d7cd157438752b15e8f4c7558972cfbb76279faa061e619b8a5ef192b1d764fe9ee12a4d4bdfbd1e3569472553a953d2567c5275d172757079c3a7c7dca79ba79391e8dad5c666005cc1317c09061b92cabb4c1022f63d50612b9cbb24a1b429d46d10d2d82f388095be1d4e471caa6cb7c5465c1c1fc71d56ea443ff1d3a6cad6177e82e918b4387926987a321ff59e4b0ef57df14692acf5976d83442be441e972e53b9c353a6238605fffba09e14d8a288c544107b33651421264a9168761e69ff47c1bef33f26297aaafff3c0914eda2c5052dfa921534ce1a0242288a7ec4e5b91bf7ca89643874e24a5043b4ea9e4596f167d5b8422e3932e2c869d7406fc31a67a3f7259d61610f3e01eb9a3ff43e56fa67ab46151dfedb444addcab9cf4214169650fb8f37d67d4ed809751bf1a808421000332033d6840f238ad010539c3514621f70b9153c8331c2711479e0a82f2062064be3a4806e48efeefe4729e4ea73e9d288a85be4ff32077340b363b73066e0f9347ab7113324a36727fcb3672efe0030b43eafb7320f2de9db9937962eaeb8522b3628a6228b21753d89bd9d1cb766826552a79a4b9e7f79dbf39c1965c0a08573393a67475383bd3940c61763c931a4af760129cd63b4f7aa762ec4ffad5b30b999d4addb22c9b054a37648a1d0e4a22cee94fbce6b40edbf138bda896215bec993029a70f8a82950f240f72bf9c120b1e37c2d6efdea75563a86e4d1d766b0d3baa9a72ab6eaa2667ea37d23bfd401cc912e675dfef237b288fdcb25b7e919b0b2dba67e6b0910e1b081fb983059be5b26c31f308f3171de6f1974a0d27aceaa66a6259d264631e934f3e4bce2cb14aee98df796620aa3c5fbeec9107f86cdee6a394521e404941eb29f8a46ba4dd6afae87058237b26ce217754d4444954f7a7793a9d7c708ec6a60f8e2ef942eef4ada520c3fa304f8b9452fd5405b2cab0fea8c33b7d7ddaa47766bde384d27ae749ef784f8b60f0a8a357351566c134208d4d500c3b8eb4c8003e1dd6f72b2486fba3796c9061e8857dbba16e1cc5dd9f5cc99572c89ef9f543577221704727afe35027af7bd4c9eb38d4c9eb38d4c9eb38d4e7ad2a618e0a02a95fa77458dfbbe24ed9cdf7a4e77d373937923deda37bd9b7e9a3c3b468f2a85fbfa3207b26a62f903bead7ff3850ce3f15853d5b38b0f406f3e2d2dd644216eef4a3471386322f1f58fade4731302f2edd51d782c75fa9f0682d883f8e16d14e0713cbd3332f65c115f75fc76ab3acfa99af4f552077e81732ac5f67302df257fdefbcd3a38a74e491c66a3c8fc6dad56a3543bf62aa2477d4262c7d4ff25a7dcfdad57f65323232323232329a320f654f2befbbfa1c0efeaaef79ab955452caf514851d69514cc9c87694a4e4032696a5d7728dc6640e5322d6a7430ea3a2b4d5a7b4a735d93373a54b2ebdc21a272c860fcef3ac5dadfe431d1f4e5bfc51fd7c2e15a465b34eeb34baa9d1f05ad8caddd44dddd44d2f2eece8198da7d8cc3e3d931c760209f364b2a704d28792c3589ee2d1230af1e8d55a3496377b9179d2546f241b86991d32dac1b32baefee7f9e880976b7d69247b529e67ed8aca78704e31ebddd0e20e5fd86f8a1d3d996784849d62fe92c99ef9ab12c853cc8be2146322d3ff62a75867cfb376b5c2c9e3c4c9238f27f3177d4f265bdd161b0cc3ceeb357fd14f1565fa9ecc613bd01cd669c817fdd5ca5a4fd652f084b0485027e88f530799fe97b2a14515769abf287dee361a9207fdd60dac7f9f5e49b6621d489c52364851f532f503be4faf6cf6a9c7386c9dd80f04b98bcaf57e4bd8b19bbaa97746c9a4aad23699243ed15e9c4c165017c4ba418a5e8759f3adbfa618d462f7b39b7fa518bb32f4e4c67ad7e4e27584ddd3c791c9a3878e136c2d1604351c84a1480a53fa0acf8f5a1e67139e187c6c35b4ac490806981fd43bd2b674458dd93f404939e0d0dd6f8d269bc85d297e484936242a61e40f4c1ef3fb06a1f9c8e4317fd6666d4619234f9a3c7f2a09606842818a6c4ea14b5060238f33291585136459a9cfd8d06dd63ba38c429ecf22a24333e99d0e4a935a631e4027362700096accfc81e9c3318d14fb79be910ee71f993e68536d8bc6952b576a000a0186ab97747bfe373aba8774c997fc76eab32758d1c117052bfd5fa7804c1957df3d074f32ccec79728794a1ab184a477192ec180a8765dfce65ac21250b7068a98694832679a38229d3645985093639012b9164d0946db24492c111f953b17e3e25be42cd07fa1e07115116fd9f1fd48dfa5e89f83aa8079fc3a365f951a78a524c3d37bbfff117f7c30d521482837c1e95d49805f4c5c0ff7e62a21e4496e3ab9dbb7ae1ae7adc950b97060097a6854ba37369785c1a162ecd8e4ba3e3d2ac70698e2ecdebd2285d1a1c9726e7d2e05c1ad7ad89f9abff6f4deb7b295d007f65847ca11f5f21225e1422c28a52b630522ba40b2385411e636864205fe89734376ebdb716f9abffe656a32aabb93792582d911b06d48a3ce2d90f13c715388e6ebc4cc9a042cc8e36339b273587a9f0364f3a6c9bda4ac97a1e6d6e5c29d2cc2214010a34a2ccd270c2d6e0a0f98b16c1ca6e32ebf0bed7dcbfb176e6261d768cacc366d2613780f534ffa51a60f337300be8c67c420a2488d15c1610cdd77c0d0e92413843a47925e247c384f5fc34c90525ace7b11e359ee1a0d1e41cdd50c1083bc6c8b0cc61377fe3476fb4313187dd603cb3ab235879f2bf52bc71a5582fcca5b952b4b93194886b319438622a6c970a426bae1469ae14698eece359ee161ea064a681a6e8620a4f701c31dbbba5aca5cb889c3099ec40643e8e22664e67944e2793368fba984fe6d094328da6add2dea9484449e4fa3af48e5c82e319ebb01ef1577ddc8495484d5cd19202322d0e26769c33224b188a95484dd032a76261826d422805e6b0c2327d28700ddbbd4462824ae65efe89e34e2f330abc6008381a0642045340a008621c575896b872054965225fcb0b9bbdb0dccfecfd111dee0e1d562234652ce9e0423cc54a24268a32e74d2772c97b22bdc342bdcca7399b349a654149bd14c11fe7d5e9e1fd389d304f08ecc8e3e3affae015e2affa3432fbb9660f03d59fa4da6589e484a55a1f07c9c35ccacd71f3a58a4f051e589ffd2de50dc2938f844fba3c1c52d8511eadc0882558e4495d4b3c161c52582135485800e40c72870a41064f7690a7b4fd90302138dc0191fcd93ee02ac7d59713d82e4b242666797c1db848b1354b24269c50a24a29c7d95b7c2de7e468e6169e5d652ae58e96fec4e7b3a5d3e9a392ec1d31a94f7f222f69138124e78dc04b29695359a7a4799e770513249aaa3882e94876c42c2909264c61306152431a5a021148ccfc253d940d74565d7395e32a8c1ad625cb2a48576092b650c2e5b6c514b22d8866c040d1f2046b38fb746aa951c8d7ac331e4cb033093bd43bf5bbce7e00c2cbb30e1109e5117491de0e78d96f8b75e63039c6e4b1cebe539e31b96d268a469b605b5bd82977b060b34ea71fe9d0833af42347e6dde11ae990498adee9bd3924f36982ec538a268cb0de4f267348270c2b8f7ccaba6790b0d085c81e3a80ec63cb78caa33c62c166a93b0b94ef3b35a4c5ef51771ecd29d3d6e190dce19f0243874d26e4cbdf07904bc0f3e129f31735c08f900e5996588f05df0c93f93fdcdddd79dce93b1edd3df497f4bcd5aabb714b7fb5926ebf7d3c3f7ca44ecb0fab0cb99fb3625a41d0e5a04cbf1bcb577d548e5cff7f04c0016c9e9d6b12d5af5a90617d8186ecaf7365fd16103046e055d2615e651169e3aad0e12aad95b634d95396484355bc0c61bf2c91866a5a7479d471e29086a21862c2042dcfff78dcec0766a3a08923f27c3997e4c9c3937d78faee60a443c924a5fe047ffe1187713f6bf303f1e779286b4fab95f7dff1641e87799eb5ab556834a54c91de398bb899397c64faf074389f6589953ff2d4ae4a1023ca9cab2558886003e248ef8c3af2fc69d4e1acf96b823de7120f3af43b66f5cfdc78d65ef36ba08099b5595212d16187de1972d2301b1e6a57f2945dd43bb336a5e4d9ffd323cfafb7c7d5e970b60e1dce1da6d831cc93e52f73c3ac96a66c72c9a5ff0e05df0cc2ce972d492d989244e464b504cb12ac0e111d7e6a1df69cf98b07a72c9196402553b03d296c0e1346206a7d182a66c9773c9df4abbf060a4bb19cac391da8cb2d6d96729809e5f69913f93ebd23918a64b93f86dee9e1ea577f436171c02c5360b8167cf23bb42a6995cc24ddf3f6e958816d4979d2a54b141e95784e054901691f927483cfeadc81ce6350eec2702faef08a00c294ae880e69092294b84289f8a4cb660973b5f37d3108f109c2ce9f5eab4f6125d62177b8661f8196abc702c5ea903d33cf20c741f4413c83ec3b8883589ece5bccadbfeadb771ce48f047c8ac22a1cc48291a4debf533dcbd777dbf22c3fa4e559548fc4beea87a8dee55d3012969f16acf32ae92f1f9d1e6cd0af5f7f84a86c8a7449128a9118f11726e22fb94463acce31ab1be24f3112222096a78fc4bebf86d0f7778c8405c9a4f9abbe7fea413c87fc555f8ae38ca570d82fcc077f0988299e2fc4ac14fd476808fae00fe19fa20f3e907fea7d9ac96129ccea5ef54d0e0331abfbd44bb1b26056f72c2fc5caeaf08f7df0a5d8a4c3cae4b3c95ff5596ec768b6b03dc33dd4617d9620ec387b6809fcd14b4d5bea7e32f57ddfddd3a3504afa4fb748f73e7e5157a66ae8efb8a67d4bdc1d03d1d9ddddbdead4653fe1654f90f668f87e82299a5345be57f1c0a6f84a5685e791bf5a6ecffcd53fd97bbfb389d290079d7aadcca60e5b825c7dfad1ffc0d3f5282cee2e923aec9e32da5a6458966ff9ee19f5ea79b999624c4fbce63427eea49ba4e84c3e2b4db8993af41f9ba9873a9475485dc84614c4f2acefdbc86116b33e0ce5e5a568bf9fca3aac42fcf5e3af6e91220bcbdb1fd2f22a8c04232102527dcb23092202b2af52c5543889cbabde6220966fc141442a8c24b4cf823d7f893431db36dc46ab36accf2bfd427b2ee36a090be609632a234dc588a83e0f3ab985b2145b2896376958eea5147b268af3e6d883e95713d963237730cd261c37b0e3bc19cd9bec9141661bb963b6cab0631b11fd2083cc3d86dcd14f03fdb6b5cddfebbadb543ae49a8a47d15432876ba0184686d6a1432264d8969f4794eb3a1504fc540ddfa3fe43a540b05335744f67911477e7d70f36537f1b7553d923b327c53c3b67decc5b68ce79f39a6a0dae6c1aecd6129a699442b21e6aafaf20c3b60db75187a9302c87dbc8ae96b0bd6373184b101150cbbf4dd55031eba78d6c344256aaeeed88bf7a08244432c8ecaf219010391ea1b4b4b47c0b4e8264d65a5ec6922099b26f1925d312173c8dfc155361d98269bf30dfbeea47795ba2c273e62feb2fc7de6cc96711d8363f58ca1cc7f1b8591c18c91e96ece9ccadbeb05c646e6a91b991875e3153033b6d144fa31af73a45f626f3705fc510aa3c31842198d210b947dd9fd3fde89f7ec8f7278c840889f71f1e82e4f4282c45f7fef43edd61960da8ff1e08f51f0e22ea3e48ba0784faef3f91be8e1756149a18bf4c0e6c7d29e2d0a8388a89fd53a943eea3d058b1b3884ba9c08e3a3a0eb381e37e091dabeb8c7a6766eee7154c999b6a348cb534a78cb30ba5cccda5cc4d2b99ebe4acf58eec0194a5ccfd8cf2d371dca7626064973c243e1d3a1dca23a1d3a37e1c76fa7e210e43b5bc12f1047e0b0e6a791023493dea835cfec3488880528f7a242c7f7a2522121824dfb7e0088285f2f2484022a0ef5b5e88c35e30cb9f882912b1bc077a79f0bb9f22cb1f09cc7fdf1eb601fc970702ffe5fd91103906fa1ee69180fff248883a0c0483bf47f282756416c42eff61960daa7751bd0b0bc87ecbdb6f79caf22d37a574755c206aa644f45930cbfff4e0a7c06739063a3dc80242fd8f2b2110f3501ec29612fc25797440255d7347f8d0cfe775783ccf5623febab349bfeacb211dd85132e5c8ecc9f3c2fb52ac91fa3bf4ce4824d35fadac752cbdfa54ca71400031d261fd1b3eb023cf9c1cce40189962479ea1f6e1f9019322153068b33b29b24723b90810347bdff2bf2bc4f7e0682417f1613665206686f2814fcaeffb79fd8b65eadffbf4d712871dd607e2e14aa50e6a69c751a9434aeff6a043071e75c8eeee80f2093b28bd7b1e74d8de819977c54308963ea177b4c9f527ad093072e81db0e688880e4cf5757a38c9f57fb4011a36c5fa524789a23c8a15268f1614e39bad23d8feafdb9b5229dd55a094e4795426eb29bd473d520e98e4f930405645a024914922d138b3cb73e11522fcd77f453ae019ca07c27fdd202562587f421cfebc145fe92f10c4b287dc8777082522bdb3681675d82efd3ddf3f074e722bcb2a3c9892270f47ee182bf4c09e7cce29353ff22093327d943b2dcb241f64cdd71e64521e9514e522353f47254579e2c63535ef1d75d854024853dc72bf8d6b67be3f8142b69325d213b6ec42cb54bea44b6374481f7cb94134df3fd3b86dfd02fd84709648505cc9df7f94c72d0809eb21f9a24f3dd38622d36f27246c2ef98b3ea5f4712c81cd247f7d3b6097c424d3efa9d43b63fdd3d351498c39bbe890a63ea5ba2f0461bd9729ee02d1347866cd504f782a29c99f0c80fd50e0cb0da2799987b932d93e8512f33efdd337d9a323ab5439f52925f9a29f7a29c1e6543695ed599ab0b0f8cc69517c144521cb2ed2776961515263a9995a8dde615930c6e89dee894cbfadf44ed702fbd9b0ac5699ba8ab0375922cda86499fa11d209c3f6c3bc8e133bf62dd3d5ed5b3d85f9197fa12b4c9bb07498dba83cb692a525c8148a0c96bd18e329ef5373a943ead5facdc486a52fb344826229d3a6dd6e6d73286c9952b15e1972a1be79131e655899aac15ba9773a04481ce40efc6e14991518621ef56d8bb1d23b5792d6580ac0d21335f7a5c9d421d5e94194c77ef283a70667ea9d3a46a7807ce083ef799e973d7cfaaa045ed59faeea53aa996a52e990aa700fb1dc6e2202bbf33d95b948f7a7a71c1e93644fa66800bdf7e91df08b00d17972b7480dc2fda9bbe32cd27da521e57dd2384fefd3f344435287347c5fbfe2a9d4b1e81394b210a4d91559223d71bb9125d26c8a8cf2d8185d64511b838d2ed868425a820ad8a329044c63df6a6da559138d4aad77c699948b8c6090bd18d34af49d64fa72ec279946c9a34d96634bc9f457365a83734fbddea9315788c87b225eeca7b94930112ae676937e39a1f5930ee967c1ea3dab7634ef48a410c4328dc9544ac374245293a64c7fa849a6454df2e8b44c5f5639838a3c7a944ceb779cc792b49b5097d9d40cf4e5b68ac0854dfc5a5a5240bcef547d96140d3deb268d69d667bdd3b7bed24234168bc568227d1fea9d8e0599be37913d3353cffb540a88e779b2dee48b7ead3908828decf54d878fc84ca178a87887162964237207fd97cbc30b2c62344aa04e7822e8c8137694b721feac212fdfff8283e60870202699469021be7ce3a0191c3491a02226e981428cf924d208e2cbcbd490fe2056fd242f2f45d690d5cffc0a07cd22ae10418498a4b5d0028933c4979fc14149a614b0183a81f88289b897c1418ec5172b281293482a2898c10fc4184ce47595f6e976779b3563ac19a42d732f6d99c353a843da432b1b3563089949f72eab1982229571835c9b7873e8e6a443ba8652aef8c9a47548270bf80253dfa72795dea998356b1d46f9dc0426744ab9d9711665da4f5340fd30578a2f578a2e341d50ac2dcfff1a9c9ed7e0c4416776dfcf86d09cee75e6fd2840c274a40df35d90b01f1fbd435b06f91d86f27d7fff5559e7cf7781fa359fe606b6e671d66c7098b3e633d97363d2eeb8a5378285c91269891a799cb37abd3c67b26766f92350879349e69eabdd7f9d9c3fd09973b4ebfc027538b9d994cd3267b32124cc07f99ab227083003216133169bb33a82747acff29d7778f4feafc743bd3878995e201d3a9c32c887f2fd8fc33eaca393672a48e71892605fc72c0c6d315034b560cb2d25cb7f1f703fc9587a87e370119bef7310c4f47e4749b0239ee110819472e766f6b19c23d993fac7a9eff7fb9b59079145d031b247758f3b2577a4f09f5477ac4174a80f34651eea5011ff99a1dc789bcb02aa799bb7c1413eaabcc076630676b4999dfebb712b957ef54bf174bd2c53275c8f686af0833ce21a07c471ff87a3096b63836f6a374572c6cc723fbe211b65a50965a543555387aa25d518df04ddc6608a6ea2e4be29ca3db39283306af3088d9bd5dbef6666756f68374e6e6635b11a19985fe65be69663de490d93cdcc867663646363f39382dc9c6194306e393803470dcf648f2ad7dc09c50ba4c024831005d7cdec5744b03730c652e8d7c8644feadb0919762fe54ecdd05833a331923dfe2cbf92c91eef6d661fcc8f354cf5c82626e684eafb6b8654df2f3fd6782d3fd6cc5cdebb3833b9a3fd6f6237b36c632f31b9c3314c91dc814a4229a196504c1765a5c33e3add544baa2587a96caa25956a49a50243f6ccdcbf52b2a81f5536148e1b237f51d9d80fd3a505cf626435883cc6c83c39852e38909b75d83635342b50616d9e7438de70e01a91a906d87c0d6601d57409b07872136b5e8978e36fe0a06902216eb09a59bffabb9a59ee77d23b9e7d30a2811e32c0439111033b5cc00215d08102139000910840e0013938a0010cc0610143140094801b6cf841c0016a30000d059841880c4180c44000b1957d060083007ef8e809000f6ce7851e2e00a0051d1e2cecc03757c70a395ee18c56c351e4b01fbe1f87119ea9967ca896248f7eefbf9ceb7a9cfb1fde9cc771713ec70dff7571bc8e9be357b8afbf7785bfb93ade2f4bfee10addb0fc77736f88df046f2e287e0ddedc94f839a8ba5676edcd65116dac439578e3e486866f663733235768032f8491582c161339f03e5c205e03d787cfc0d5c0f7708d7c919b81e7e1f6f018b8457ebc3cfc052e067e873b7e05ee05de027787a7c0adc0eb702df012b814f8095c1d3e0257024fe44ee01f7023f010b844de01f7019fc385c033e03ae01b7073f8055c063c0eb701af80bb801f7271f8045c053cd01df236dc04fc8debfa1b2ed023e0daf03ff786afe122e00f707f9e865bc31be01ee067b8347c01ae015e863bc30bb905782057860f72853c012e90ffe1fec770837ceb12e0c51bc3fbdcd6e72b3e0cd7e70770f3ffb830bc00ee00bee7fe781f5700cf737b3e00d7c7ef5c9e87dd007c8fbbf32f5cd803e0f67817ee0baf7301f02d5c179e85abf33c6e0b8f2f0bbfe3f2f87bf1dfdc1def17cc35563a8462299ef5ce7833cb5dd3746b989ab0239e8d354cf9867653bb2902e2da0d5c5beb179a7633bb99dd38c13387f9f0fd98866b0ed3c0f7e32287f5f0fdd8c86119f8e6e1bbc8f7f88d81efc74b0edbe1fb3193c32ef0fdb8c96116f87e7c735805bebf1573980edfdf92398c02dfdf1a72d804bebf35739804bebf45731891ef6fd51c1681ef6f15390c02dfdf3272d803bebf6573580edfdf3a729803bebf95d4526a2db5985a4dad9b2be692b9865c3317cd557315b98c5c36d7912bc9a5e45a7231b99a5c379c188e0c67c861e2f7e3cc1cd6c24242cc3644a2d413e189adefc7a1e1d4708a708c706c383849384a384b384c384d38b79c584ece50ce2c879653cb29ca3172180bdf9f63cb397218c69e88bf3f27c9613abe3f47c9612b7c7fce92c3727c7f0e93c35edf9fd3947373188eefc7117358cef7e390390ce7fb710c39ccf5fd38660efb6fbff1eefe3a3ceef4b2e8dff8df7825e287c1b03446724703d5fc0d0e9253848074136bde2f10cddfc041928c9a48e3d9ff4b5d283fbc0f17cf300dd7701136c2367c8493b0125ec24cb809df5ab196ac35d49ab568ad5aaba865d4b239a095d4526a2db5985a4dad5b4c3634a3d58a8c6c47494aae251793abc975c389e1c87086fc8543c3a9e114e118e1d8708e7092709470967098709a706e39b11c59ce50ce2c879653cb29ca31cab1e524e528e52ce530e534e5dc70c470c8700ce1d34be902ea73b4902ff4ff1572c00b912426feb7aecc137fc038b3a37a64e4777cb3c0e35be7fb6b93c35af8fe7a731800de85eff1fddc90c35ef87e6ee6b09d877df37c3f57e4b0007c3f67e4b09eefe76c0ef3f1fddc91c37e384c00dfcf29390c861fc0b7cff7734d0ecbdfcfdd1c2612e0fb3b99c362f8fe6ec86140bebf9b392cc8f7773487c9f0fd5dcd6142bebf2b72d80cdfdf1939ac00dfdfd91c46c3f777470e33c0f777490eabe1fb3b25871de0fbbb258721e0fb3b2687fd7c7fd7e4301bbebfbb39ec864fc037d0f77b430e53c0f77b33870df97e8fe6b0057cbf5773180edfef15398c01dfef1939ac01dfefd91c868323c389b96eae2617936bc9a5e44a721db96c2e235791abe6a2b966ae2197cc156bdd5a4d2da6d6524ba995d43af257cbd6326a15b55ab4d6ac35d492b562f8869b305ec24a38091f611b36c24518d3f04ce680bb92c9167cb831466e8c066eccac871b43cbc08da9f170638a8adc18a3f1c6d83070638e76b8314917b8314a16b8314b15b8314c3adc98260adc98db04ae4c4c02574646e4ca0c45e0cacc207065680fb832b51cae4c9103ae8c5103ae0c03ae0c0e5766015766c89559ba324c324d09b832b71bee4ccc863b23fbb9334308b833b303dc195a0d77a666803b5344c39d312ac09d99e1ce08b93332dc99207706c89d89e1ce10e0ce887795baab7c57433e77351bc05dd160b8ab9a00eeaae8c75d19f9b8ab9ebb0ac05df1dc15ec06a71ea8146db486510d115224020000000001a314002028140c084542a1482c9e69c29e7b14800a86aa50705496cab22448621432c81062080080001918111899a16d00e3a27020421000ebea78bc1894cc21a6cf3eebbe01aab0b2992d6fd09561a3f1de133a9935ce6c1ec054b6f795f941d6912d8da016431dfc2632dd19b0390c5e72c34e59f295ce1a16365d3a2a65269901867639924c2bec378637b15042c64a7daf713a0361f46120408c45a4566660afd4756dcf84c862cfb784cecf71d350b20913ec9c3e83390a2f976bec8351fd06451920747715480249ab61db31b5f264806cdf0aa5014b767ace1c103a7dcab2d993423b6fd5deb7a2ff79cd187cf343240ce18f3068683090e1c93041d44661e616d9c371256dd95ad71db513baf5e4db7fa1d07d774b11e2b80e1ddf2babbb7213edeb1034d98e8c9c7d6dc6a3cf2879c85ae3cabd3cd289eaa3a5380bc40406cf0b05da10c0508d81051b2255ada0f11f302026791bc44fc8e9e19e4887ff73044a844a3dae4fe7696a7c41a186c019f1eddd057056eda8bd165d7c65afe644a0a2f3f15dbafdfb2c2c508e9e60f2941180c7a869e654cec4633073d4dfff2c4b0036d48ef2163d50978e10588c5aac7e603b28d7fd544495c28a29a36b08e01026bc7e139521d1bf7d8fab668bf0a4a4425fa4206c4b4f071ad8c1d2d804e33ef15230bceeb5086cab314f049511cbee070674ee96df525cd9dab1303b203beb01ba979d36ed400f48c0c35bff9c53966ed8f57ed2375342f6895a23537533d1ae179820f685632f206baf399b7010c8344be448f21c72d739d885e1f777602406e41acbf4003d431e48b1204e02849ec8f7dc3f5297606d68e6a7bd72930611ba14385d6c72f25e486504c2f52aa00704c1b5eba4020208f2976468b5577624cc85d35792c5a4a6daa0b8800630f8bb2c5d6b948e230f09f1619b826314763fceae9205c220e682cafaffa9f1b2da4829d469b670121c47c5f97d8bc1e02cfe948123576c5f13a61d3522b8c91b4f4a3b3c1d2d386a7d40a39cc56fdbae79eeefe9beb08c27ac78b51482572d643782cdd4dc11f6cd3cb11264097823e148f6b5eb2290a54d9a5a042e676621d90e390510576e0bba440bf64948a1b66949e60cd058e3ba37df8d7007a89b14979f69875ce5a65fcb11060e8aae9f1096aa00b11c4b5547483558d0fe90af27a643a6fe93832f7618f172b7519eedc96fa6b8879c28b4d5cac8dc3611835f817419f854b4ba39bad7ca9ea9f1219ae9d64d47b26ac58cec4216cffaa8e5393242d54b318b81cb85f7c2c183e743d5b55597179c8b5539332b98a03a603969e0e748a276701c764c3b5735291a4750fad9022e512de626bf376cc38b999eb6c09bafc97343955ed3fab8109ff8a4093ef590f2c77ca7fddad4c3cb2a03fdf18c3b10b7c550ba9aa9c7a5ae81989ea1d031e8c84e9d02434c05291644e49ce6cb34f66f9eb12341500815390445388983e72c5c7abe91eb1fd3940a6f65a0f2fc090d0ba0e045f34a273ca53f029aa6fcf536f95e580a55a36d2dc3b7a363c248770ce6bfcad111415f6ce1b99ee179b17fa2b6666f533b7e559a686535514d4f7230185dd0841fa14d2c7b9cf01272eda06a878b9578c37a00a3cd784172f7a01993a88368b996cb51e4cd98927ad38a81ab03b480c98cf7b37e68333de1ed019de302a31e7ebd122bf06f35275ce5981107c7044c79d317350255e484793e3d0839c66bbd2b0bfd571745165d0477add144307d268a4f56f74f9ca1f25c8bdb20c5760f2858d1d60069f383b8b3b58b7600d611c0491a64071282032611de34194b435a88c51ff576e09799143f200544dbb09221bca6e0e8e8f24cac782b263ef399a42e06ffd429b92e4054a82bc10305c217c3ee4944b42235b20f67c3139f1f0ec43bf690f8c94c50ffb9168e36d568c7dd96f7a7ffdc2c9c04348817c5686196ec78ab4e23c06e12bfe45ed9e98c10ebf67816ccc030ad2912a405794f21f48b6e8f4cc20a091666e9d7d7142177d99429407944858c7ec4f92ef261611d2a2d610c5d743b61602d4f5b8ceb4fe79455bfb80f9c8ae060fd9ae2e22a66b08c00397df7e6335769757ef8980c82425309fcd167c91db1d5b7b1c6dcdb57ce3dc048af46567b0efec453ee0fbe1a235c857cbf8efa740d25d112752b9018a1664dfd1ad49fc42065bc79a047a0243915e5d45544f46139b2cf4379568cc7b023fc07e3fd970d52119b655258c2bdc8c54a0f10842c558728800ce146256812f49ad3072c38b5f8b3d88996bccfd360e205a40f5ba8e861a5a6b54ccad40d790feb321e2ece247d15a92c48eb10fd055593f8b9c24deee61414555d2e7eb731c1745549a32baa998d1d7095572acddce2047635670809a53e00347e3f955ed9416fef6bd3589ab9228c8cd59ca4fd9a46bc01dfb385f3056e5a087dde148635e5da1471d843abf4c903fb17667619e16786022abc89425c189a221680c66e2d0914dbb3c410201e30369e1c01cbd7345104b8888bbf2b019ba4dda45ada0d8ebfe4503eff97743955cbb4775840feb0eed06b308d4c1dbd19a84532fedf86b7b068f480c4fafa277fe92da155ead48d2cd732baec6d314237df03863c8f32bb650171f037f44c2016c4e7057372adaad2db9f99d5c8a0f7f70f6ba83f4c79281d449f4ef79caa769227233fc5aa7b1f0598639b9451dfdca4f8cce42acb838fff867d35f8d75f45b2b7cdc7092ab6aebff75e76dd53f2bd48e437c3d0b5da4d194bcf6c8ad3d8d7d17a321b9975987d517dac4c96df7e81a711ce49f82f3f986bdc9bbdbe29645d2ee6607898dbbfbe0f2240a13b8f9a82002e18f278ffcbf120b8d9151b849e9e947e37f188eabc67c77b2d6cf7ed6aa2bc095b87eddbce521167f57a413666a86278e86c28752187a767dc45da999571645e96323137ffec3b6cbc85b9bdd17a32ecab44f3ee2e54e82279f0ee6d14adddb3036dd8856e42afda55f581ea7bcb2f6b8f8a82c4f25dbc9652e0eeedf3c3b5f27e574e82077d5f2fc50569c58c1e34fd00e9db45fb2bcc85a1a8f2498d063b4f0c2435de8405c1c21052d1c5851ada90a416c88731d3bcb0a8ca609aee4d0e0e88a414bd16c9b50ef486403704b870afeca00037f5f585b17206b11553b92477849f625da15f913a5886262151b7d74994ef5480e88a19245a7b1d186b7ef317e3c6850b110ed05a87217bb7b84d091cb0ebbbb94b3dfe36b36c581c80a039c2b7a96a7d9e6a8e01e42d10104a7fb126a73d788b0c223c41c82da42606959f4645909344a29d9ac38ca6b1c34417fd61b09bbbf634f5a034b3271f6d8a8a5b7467be936ebfae354663d3fe0edfbc93763a9873f4261767b07bb11e2ad7470a5b69b3acd1dcd1c756080fb79a07118b0fb19b4ad78f9cde0dad55541e3ae6dd051113e83bd3cebf1d733c09d49641836f9d4bcaf4572a3c656dbc0cf5ae080297df8699f0c1d4260c543a438c556b5d78911cf44140ad60d2e4d298075c9b33677db63cb62f7f63850e5c561f665d4ff7dea13952d5ffc2fa2e8f0d9c34fd50154971a38bb871b06ab6e84b3017c73d3d89136bc6a212951e80a8084df018e1f1e5f4dbc6414482a9af062a9dfd46cb38a505f4d843f76f7e9650027bd9dc9764a58565f6c357c86b8a8477d9abcde4471a3adc92a208cc7e335df7c5569fda8c4869bbe493597c290f1b6d3f7896331fbffc84d31f52b689ff94ab5a5169c8ec2d089e6fc66ca88b2bbb00d70b1146d0f5660eea36d28ebc37fd4db4f71dec453e280059c522c610e727be41108d5ce1d302a9c534ecfedc08d7861c238ddb8b538e9b794d1696f25ab792d0cd8ca72724d8aae924d115286ada288739b6ec572d42967b963b8eb181d60c1c035d91f6af97dd86563e3ac5206eeb4bdd57cbf632642aa0e64e0b00d5383afc15ed5864dcfb18038b0c084380086faaece46e203e01aa120258dc9b096c128b3f903c86ef2fc7ba8957ef564e55273aba93cc31d78643d0b190877525c61ca702ec54828025f53c9507ec05187c7f94f7566d43807c62a9a5a054f1bfb70295ab3e353a7570e6cfcb5e32368f600bb02b1920005d7c4dd79807b1616f2f1a0b4d2ff4f94d1a4c4da1d22903856d8d5c84b5777caf41cce3910d1ae9bd164cb5d9daf7f4a1758a60452935be84da4ac5ed577b9b00627ec0e006a1c35b9204710afb47cdd51a4bf69eaa4753a4ba75d45d8db16ae7b56a37458adb47cdd908af365eeb4b4bb4ae7dbcf29a7303566cbcd787967855f7a83b3711a5ed2b358337ecb1a2ee55736d928b5b33aad91a842017427522567e0329e511d21a629a354f45fd4dd0a7654571ee59597a8767ceace115650e8de124195b6613d0c421b0eafe7ecf4e2fedfdc96272755ea68b64a61611d39299df971b39d4e0e1c36abc06f518b05138b90eb59854c20c167997fe90cf9494c5eb289e27358aab6b317be8ca276f1121277111b5fac5e38eb77203f78d0c460e653737d90e8290c3ecb778859ed5ace654344645cea7f0b1292297426152601e8588456171280883c2c59f60ec09823b61302766dec4c29a189c891a63c2e24b24b6842fce95f04e12d245a21f24d2f7083f4764af11dd31e2b845fc5304e912810e11c21dc29e21b22b84fd08116f10cc0982be40447a80e07d3ee4030d87e0d67f40220de0602fa11565a9edd74e0d62a115250ba64a5b66a38588b1222d1aed42ad0c595c32ce191b39691d6abc542cf02b00e249e1d670bb3acf4f5a4869a7aaa750389e6898ec3ab5af2a1211cd7bbff5ce9eab5623a2be3fd4dcadd0969ce22059958da7a772e0be49d817bd1cd267097d23ad45b9cd60bfa82450be17e80b0dea3b0c0c87e4bca90c412f9021974257de6bccfd8a72586c989a6466b0783db51284288789be2523e7518ec6940eb6e22255573ebe42673fe272a6deda27df7529cb6bf2d705d049ce5e875cba12342ee7345400f7cf7e5fb1a356749ae8b22d048a7504db2229fde7b86cf24f69e36d3657f45927a94cd33a55cd96fdba6adaaa54aca955a896d984c82bf192591990a2725dc9e04dd82a913b7c0f8392738d0f30ae1a2eb81c6e54e072d7c06de391f7340870b233d738e05792811c6e246b2650f9d56461ceabb912b73b71bb82951f65687f24b98040c56e1c7d00665e8a8c2e8d25bd4ccb657ddf6e0cf100ebed9292d5982eac645e47931e974d5ba6639c9c9697e819ec3c609328195fb18332f1d78ecaafcc89ab0ebfdfabf7b19bd2729321408d2a006bcf79651e62eb93258e5c6bc99860afa460a5f981e37c4375dfdee90fda7d8999eb566d424bc4384b9075ff0ecb14a1140a17145846b23b8a07086a76a5e955bca75c5e9d3b12e389cc042d7fbb1a220560e67e9aebcd422f0b7cb8494fc9e92d3041535702a97a6bfd25c222084324286d21fb72d4314760bd265355d4076bd2fcb2bd0b732bf11e37877e14d10613aba06cbe95f9d1cab393eda9735930073320adadb2f8ec769c16dd9904d9e83d31bef9d5c47794855bbfd25333c7d0ab89dcbd21af479a15ed59cbcd61dfb2a939f6c058fc39e3f5ffdeb555a1c3637c3195eb7930d6badf77205b4bebee20427682dbd74dd161f4b9e4e27c48268ef1ae437240c22ce5d16e8160c68c48358f75889fcf9be083d4cec0d5944c3f1b991f9ba06f7ee3b83f8fe78ae414935b5962b537e00d9b9f7c827571ba2e5a0452d1414731c3d628ae09888f062486fdd5abd438142fd02afd2a6ef5c0caaa4973e231260e299a7f58614b5b72e0ad2ee06bac3c350eb71d872efeb8f90d99dc902bdea47fc3b7ca35164a0224fb95fda4ef5fdda39732bedd5839eb4b0adb8daea334327d9df635d0d814885a4197daf76b7f3af504c2f2349409c353e369c2bcd38862a7b9cd719dc60eb2873986eba6d398e39211578a40dc800ecf993788f6f109f6bbad4d36cd0915d169be892f04670f5262aaf7b73512c0c677b26007f869eff9eca4fbc838bcf41233bf6f26fcc48d3223dce6320e7ca8c77a992f2be24a659f4d1bf401c4565b1af1887fa100235cc5b9eb9850e82b42363ef4ab3d3186c2be86f61041c78ebc19dba7cc708f728284f851f2d5057e02b2795ad682e7f20b112fc1011a617933c181bee1d865c651dde0ba171b621b24aa624634f3068e062730fe2ec3e41130368f23bcc8decba6dff746969d3097f62486051df98e641fbad99887e1ea8ea268c2531909a858ad034c0d78aa0c5c36c36c2397fae594113043c281b231975fb301ca41379df3b438d56da317b74202f132b5296b04353d038fa0c2242ef6ece7d0260ff0bda32de3e67a0fdff58085800ae820845243b972560e0a40c9cadb6c76f9514db9c12b310936c0646cc7c2446196c32a1f63553d88c9e01ae03eaf0f7118b66b13b3499483f4e67b112823a27327483d52a28b17b815f6038657fab887395ee89ec5230d5790e77683171650cfc370e4f10461d5241cbad65979d8657b359d0523907e994931d3d7639fcbbb283b5534b7bc2b51b948bd9e5bbda34205c88f2b3da8a1478d359987233fdf112378cf117d4e0f1d0a6db93740d2a1bdfc06a9305daa30e226c0e2a876d6faf30937811d7986ddcc4175915c35182197549edacf40454f66e98d022412cdf68a3ac2027ffaf0f72df74e88b79b26672753367a655526b1c7cc81b16e318ac0ac910494b722a45a9a9b7a0b0c590cf7390c92c6cd2eec8a042551382317b6f05706e04e2b36f9581e3fcdcc563ce8c566134518d486f25112b31274e45ea29bc520d28c26fa0923bf131ad6fcd4c3885a8ec14970c3cf53f99498a04959d07ad25be3b68ffaeb3528970fc45fab86c40e790eaf436e52815bb7084deb17109aa4851f492ff1b40b45d6f85000e98a54260f8dd063aafb9c225471094f976051486106cf8e8aa2c961c06745259e68256c24f9a8cd38c9baaf75010aec59391b3abdb4feb692f809542a1922d31e4bf06f4a7633d689be76a9009f67fe01072b758f2c1c89458fa2e7b91fb46a14f178450d435ac89f40ece8ade4205b82e82d4ec043205cef359db064508fa2349d34f5e0bcbd34be6ea28762aca471fea39650a5cc558dbd17a0bb903eb5e6649bb5638b6217906022fa5dedbc8ae1f32fb7cd209df25a0199fb9657ad9df9b12738d0cdad503f3b8d897affa4bb3e2401b2303f1db9704f1f2ff4eac5dca2a9ee747678c0587839656b7fa4ff942d86cb8a2ba478ae581be02862b7574c243eb2f7ebb118fe86aa42f530447753adbcca6b9932423ed9a8f5f2219e1b55beb22b33323f1d84bcfe319a1b15ce85014a677013da29942e966ae18c68a186495c41a0a0ecc7367d4e03f103c6e3ffae56a86d3f52f72ddea99afff85b2889ade978ad111445dfdb30141ba66be45bec1d224221653e3db7c57e062a4f5e8483c430bafa8552f52ec73ec364aacf6e1fc2fa07740743028f71c93c0516dc72c4a23faceb3c38952ed39c601d05b0ecef8eb0ff69dfccad296049e6ace7e0e00eb46b7b5b23ea7986610d151b3441ea1b57430b30e71cfc106371e94381f948c1ff3989e2b58376c0ecb320bcf28450c181858ac39e4ca151ee974f4a288df38217c86cd364005043e07a1ecdc2fadefa3939164a007f905d07682af9074d0dd3e6aea464a960d2e78729aa8ad90984b5d0a1138b527626b47c710206fa2603b58f5f701b4d4de2da80036bcc547700408c22f6bc408575060b71443e7aa8585cd789c4a2fa7e9fcdda061d439c76fba9be0d9cd0b6fc8731986cc8ae8146ba044c04d943af11817834c318df0c23714cf2b111099ce40b8084f79578d17cabac8d8468cae4ebca601f1a2eacd1fa3c85a3155b63f92cf319e14a5e6b0c078e373936a77013804f7e76391294524a65cc9394c32ba3dc4c971a8fc7e5bc00aa32fb0b623606f77e0b83415087baf4414925d9d8d68e4c1dccfe3a68d74836acee586adc70b47ff3594b08b8e792d9bbb6388c5d3bc513ccf9b6b406dd98a95d1697df4b6db83d487d067a3b6559b11d497dc8976001c44c83ec55c8f6e59202c57e33a2e27f40fee8b660e04c589bc189f7c8b57e01e89e3f7044f3855b830ce252c7a02384092a4f782b5c407a111c67471f8b47fc4e1b0d5aeb58c3fe8e7889f8f84fac97d12ea61e61b34dc65b953931d328549cea98fe0f1a88bd7ea9dac0b5ad7ef121956115382ace743121fd96add0cdf1b4ae92ab005af06715a177a2f2e2f9a7d63d399454e1d852110a73effdff4f42d14afabf653185d2f64efc6083076fd489bdf9844720bf2bbb38b2fb84482d7a04928ecfad5070bd2c0e6d9a1ee7511a235e4196686b5a7ee9e3dee593af8296156e3b3c56883a909fef755664960788b7e0b642444d7ef18f25626bb298dca447556732dbca645332c10366d456eced4b433b51e46642054f12f23a0e780900cd22083ad4fb7444540c17c5a077323625f090808c02a8d6df1c1a64b236aaeb03f8f8dfa73a18e1183d38aaef72b0185daea25cddf3945a4b898ab335f3d267af5a6b5841434b2780d48145de482b059825b53d7bf033fd60494029c9c4561ad536aaa9bd907abcd6712150e7e9195f6f97b863b91ea191ba58114485b86ce2e66f87136035b2590e223d75d7aa2545d860b01f3c6e87dc0d2a611ebc9b4b11b65edf028eed0cf390130ee89c7f9472dd206983c1a99c955d4139102d15d39fb6a10d29b3c15ab628177c2cdc96d2b812c93e383fb76752b179cd0804b1e4c12f0bf39c9dc032c3420c9651e85a05fc5dbf299d9ecb150030be739e68675dab9341de3311bab7ef78b31a264cc95348637b5b2d4a4e965621f86e41d2c33f829378ab1453f94d54d908c6cb4eb9a4297a20964774e8ff1becafd75cf6d42d2c63b806d2f95d0d091f727e41889935863d017839605d494324fb8b63ad6603946601621916903a706b5f6f81bf2f5c4fff6cae22c43fcb79288925965a23b963086798db71c458f4a80a3e0c5686d5bcc71c328116242b7ccf82abf74753526ad21514a7698b46bd6f8ae1de968f8cfb04785e84392b7004df54e94c4ce00aa60921ba56b50bd2a78a62ef8fc3ecaacf98c9196d8f8e24d56479fffa425e029edbc60340627999c4d121fbcdb4b36a286b2bd79db8a7c6aafdd92983f59b48f6c78fbc496e94a593bb44f52fe97e7fa1832351d8a8d7c5095c4a1852ebc9d505df4b080ab48761989b7591ebe42161d3e5efb6548b421b79de85387f9945533d5cbe6b0fc1ad89d4ca214c308b73ed1dd4ac3ec79d23ffec511438c2884e95b10507de6e094e411ad162ad66b2ea21cd383296ccbc8ad6ce83f174dc7fa0e552ee0a03b4fe336d496482f68bbce96cbd9fd612215fd452c636d94b631da5fb9806087c6394e2fd63b80853b419e30a0c872759341c27d5b25969941e7b2fbb840e987aa5a78ffbbc38c5713562fe2b431ef38dc7d3175b01a9524dc8163cd30eff66caa1dc7a13f4c5c95ace03b6cc5426183ed6ee34da4bf4851bbba4dfcd85a4b4a2387564d6225b7c15b8d5ba3623f0b3c9ff7f95f19fa9a2b22872f341b86d5ed0f21769e6925c542693945a2327baba42bc0aaef5da406b9fb7f79935c858832dcece1f89d6fc56d10874feaf46ac973443054e3a3fca9e7cb3b9dafb5df13f1d9e1fdbef48a13a8b2474e83c892cfe73c330d9a2ef630df7c70f949b4282962cbc5f0efcc88bbdf3bf2af5a0adebfe8063abcede4bbc18dccce1430269603a31d5c82b906a0bace1959210c01a28b2538a3286bb25362dd5a7be17fcf72a47eeafc650061118cc2e1bdbee2cc856d46913a85a5067abb8540a08ccc9b8d88f4745bc7449c24a6cb9945b77c64c0a60027a7ac6ddab7513641aa81f119d048a992d23c128dfadcffac1c49ee354608f5e497c7d894d593780c6a31e4b8e6bec2c13df824eca1482bd529f2b6a7c884b9e3e32e2656d79d5324abefb105e931e94ab15b603fd1da1069de8c087fe0e3184de879e4f80bb7b3aa837b0421aba668952558301de807b46943b2014499d41f97c9a3aaf1e64d66fea00ed4f4c60cb437ce7132a9d493fc3ba8b130c2bc974b8a65c3d38f85b0178f71493dd86c3a229ae46deb293dd736dee1a40e5bf95c15ea00eb57d46b4d25f0af1885ea9a688a517a204a74d9c088b169147e7fe1ef59d57274d1a13f352e18af99e0c26ad9e3105c42e86c385f5ea038c8cf1579607d447410c17bf5cf30cd324eccd1258e7b1ca3f7dffe4d764dc72024a78849cb41d1cd1dd7edd4b0a972c338b66941167a1e00a3438ef6771fc7f695dfebf2056bfd6d50cc1e4da5831d522149d6246c156f2169023de4dd919896196537a5eb124cefb6c6ac5bfabe77425d6e8e798649d1fd8a0e7b0d36bbe326a6699c4fbae07ac82226272b1018ce490d14748feb664cb0e5e0f8d52ca854aacd042523ab973b6d4d3a5a6a115d78cb747a7109de1e3d3d663b2cba664adc12cde7efb1c16b1f506269a6bb47b4e0ed22a66453fbc12ac5e289790874fe496b5903e84eb93da7c71667291dcd9aa194f83c43e30d29cb9097702f3f842cf3eed8527f01bd09609743528f82e4aab4333e5515443582b82cdd8ee3fc89f61635e54cd1d8789c0663d9b41dd900bfe7fe251e40d54941c28856563b2866ef222599342f4cd3ebe157d0314378070cf29f2e1ae7112d765ce09b8cf5a767b1a8dd7d9cd13365a6c7b890394645f0b685287e884e2abd1c7b06145971ce7b2a9adae89aa8870193c5a379d0ed9a630605746304731cd3c952c5acba8717bcc2ec64e40bea6ea53c291b62ad3f6ea0900613731e8e2af0d814041e905921b4180098b17ab3ed28f4b29a5b7bd88c0b0f218fda82284dc6d70d68641f0dc437bc770a234bb86e369e7f7447b1fb330ebf727cfa88d89960674935d204d7c203878a15d8c760d152e0cb524d0faf1b09e9022430fa8d53fb4a058e3eb2f111b5478a650b83788effc04dbe6f931f74906dd7b6eb2335383aa787b57525c96b1e8cc1843d0af4dc5688ccf643cb007e4c7b7eed39c93eab68b261a728e6b4ef1da3ba5328995f569e8a99a62b98614b1265a273e0a03a6893c9af16a76959841c82a3ac1002f209f4d0603896f327330cd337a8e1033c9b3b38565251317eaccde59d682906cd615d8d6aebf4ab33cb58b86a8fc64c90358d4137bc49c54007da1b45b19ba5938dc21ad7b59e8e8111a4f2df29821a2c1db491ae666cff52147fc48e4d35a66d05a6714fa001d69da3c15245d1cd2d464f2681440f153d4dcf293271d1ea33be28c1b2c8f177f6871d7a95adbabb4e5a155b61261e354f0571c8ac96f2db520869a68e6fac715cc297720bd3adf0689ee8f181563d7a38682b1698258c940a2ea920222504bd2fc1df04cf82520488b734f0419aebf46a6eeed221be05ab2013e21e5cebd99b185b9c2b8be72efcb9b1038593fe06e03a1b604253f7673f4f48ddda216f8055727b91fd9f57b3b078d422daf058b9d4676ee216efdd9299e41660b00e6e5d1b82145b1b0f30f6453dae25a3c77553ecdb0d3ab1b79425c395d54baf47b5d7dfa3837e5d4a231ea25adcad0c6b4d55bfaa31119d83f060a4325ce78f454657845cb6b94363d18e3bdf10954eedf18478580b465e4f811ced7684b6cae21859270b26754909518cbeae497699c4fc8f42bba8f0f4afb7e3c370f1fb3175da9069675ba61ac872c8066d8ee45f3a6d0c95556dafe398994946fa7728894cf79c80c4460aad07406acc37783bf6f39944f28abf37558fdd053e9c8cd4b20a521cd350923162137e71bd18b44f126bef96baf849cffe28c867860c7838594162cb2a37b661884f65325a40880857f171652049f9e90d6ff84ebf3633e390aedf2c9eecbec0ef40f4e4a197dd0fd88485ee1808dbe96920d51b08f4a95787a790efe986100088118a9ceee84ad7c9f17d541317b5d79006545e5d1ea698c020fc5c26fc54848537fdfd2ba66a30d17b65e54a55e8072a63de1dba00c63bcc2dccfdfaa357adda62ee6d42b9b8972a1a8d522cdf33a0fcaa55e374fc2aa6cc0f79fd1efd4304b7eb581d40a4154202b26a92578ef2329b908004f78aeb534323e5ac921609983d4a9c7eade2ee8c818081b78b53d6e48a11f6d6bf36bc466688da900adfb75418cb2acbb32f5c1e668ff871619b06d000a7349b99df526b1f31dd6e1011d61235bedd294b6344f239f5ba789cf05f439647c3a733b739e96cd8efd42f6785362e6f73bf03f6f5cebc54807f57d8c6b667689d367bfc121b4fbb7af90772867f17983680a50f50a214b2a58edc24be6c9e99f13f2c44259e09ebb9ca2b9f67193120360f78895aaf29fe61c6c21855e370938b07f163f566f934800ad8e1e945d0863670d35f2e6bd678667dfa082a2dd4455b7dc79b4d546aaa14105de80630bc9d754d02ad769e68e9338d3538c14c2ae555c8d6d8cd0499bc0bef1c78548e54f5428199e50a9ac6fe86c50090d9ba46c020f85a849639607bb74b895964afcde622c0901320466ba2483205960f49f8c6567a7330e9d909094be64622fa1a64e06c3699074a92614ac247a409b08a8efa3d7a22edc3ebf7af67526a9c8f7e10534c5a33d2e6dc3217981de4460c8e4be8758dad1592ee00d84a37ba5018e77b10e2a2c2e4b33ce0dd7dda6df318c0a72085e49ba071748cb5ded0cafc8a4031d0b96b7aa5fdc74b61cbe9d45ea98ee47cc500ea23087d492b0e7fc273de35f1e982789902d2f6cdaadc87b015d32ac29b5af5c3853bcd8ecc804b6985fc62bced70740719720eae3fe22faba5042fa2abcd914882ac8cdb29516916870bbefd799110a365fde34c0ec03332a0eb68f92eba1a10857b1e2a8517a191b354af3d2b802094df462c135891f378e33732c2d37dcae6c96e0293b3457546b4aa5c692ecc71e9f257ea86117b2233bb9979edecdae79bc6002b6e6f0cc2151e75f11dcc148581040a5208cc21c7a71b00fdf70565010807d81fe80cdc77aea5a1c3c68d1cc6a8f974c7a8a34c666769fd4c797152caa503e61f17dd0b31aa1a62e4382c1b2e1788754022968d4bd7fc165c76dc2daade7828b1c90ce8c21155a7b301cddc7a7f6425942af93aafd0d9c6860edd8446fd0fef38d4e465df128d4862986f4b99357eef86d4400fcba9d04949602a1043d940d76e4ece86ccd83d1f826fdea0efa8c0966c7fe7075ce7c022dffba217570e20324fc7be6d7639b53ae41e4725a22a4781c8c0cdb6b352dac342ead5e2714c426606879dbea5c283f85033704c6471282a64a6a6f62a46143376e24d4361dddffeec5a86803b259f048ddd69d76750689ff6380557d12e5fc24dd1e6aebd9836dda5e6cc5a604497c6b413aa0e04691e8d4ea474ddfa90396b225070a299c3b912668338a509840ec1e14a5cf0314e19e859d4fc449490231d8bb7538f2b3098b335578c630fa7c44b785b6b98d5964bd3f711e2b9efa8220a1a3e68106477877c3766eb0e077460fd038944a7e02eb778cac877b42d18b38b3af98706e741e829601b0eac2470d155ce9dcf6e262034b52d364ea0d68c6e14fae982d5d683bacff5b6628163f345b5b50dffbf0869721d1c7802cfa9a2c01fb06654bcf1459f5f557a8382f05209d314d06ae41a32012219af16442b702bd2994a04677ac2cf7fc0cca401c44df685a193126cdb1388de287de05f32d0d2dacdb8336e36fc2a0631c0159ec99f1859a4e934ba9cb84c2305657893170107b905bf3f8f4e8824184d380a03a5d7af529491597c5d85dd59d5cada6b7d4e879caa6e4792b3074be86574af8f9d8937fdb45d0ef56bb10da75451581f1873f84df207a416127919e228b38b00b56f0f98f55ca89794562f86dbb7e5ec4f8e8e9b71ad72768465f7db18f88e56315ecf69e6b3f39972b2e89832e58fb8cef48138b23e09da0fc185acc1db0778a9b24ce674b9c1bc4738c35fe24c1cfd1a95f4ec0d1dadead6b5316e72ddc8ed5fd31c16ae4cb67e9b7fb35d5c63b906d540afee3ba58134b3437f94514cbaa4e492e9dbb56548e668be224db545a0b9be4bc6c0263483fe56921e8e94586bcd8fdd6727bb28117fe892d048dcc9ba1fbcd5a4280d7b45f1b6e17e255b216a403e0f47ff3683556a82b438bc5b3071dbf4cbfce8dc3f1d5db4b87f169021389c32a1c05166f307f3629220423729b637f4169b4dfce16043d1bbb490d20e62b3bd0b34f990a2e36dfdea130f277a0acf08f7668afc920958ad4c18e07f83f83d12a28ab0c14e82dbb66030b9d4140933d7c55b7588b263a545df5983e334509f0a766061d77f67ae93f8e18d9ee83e5aef564b4a39f6957f337f4694418c5808b3835e6616008dd0545eaa61cd063f30a013aa9e16af98b1678bee4dfdfa1804703a7c8c5920fef4cd121221ed7368e389b3334688aee410d30485a8a4db929712ae65e2286c643dd2e87acf2850e5def513a9c166283b00cca4832ba59b867e1947a7c01c17fe0155d19894a1cfd10eb6959f3581fb32f01b569ff89a5d4a7fa508dc67b740455b5c98bd633d20ce8fcb9e3f51a8152c8dceeae670e3c847b24af50a934b1611fa1cb9b5f829081aa7b13d0988c6970982296ae661e0ec74f3b3252ef6df05a5fdb0b5bba8420e08304339ebbc7084c8cb70e11fe19d7540e1fdbba44891b3be4ee42e74d284e5f87c76f93851343bc62f6a62eb47ff1263c8a6f1ddeed6e99b07524100077efe146006eded90c1231434251001fc1d9488ebe8d017c50ec7a6205afc15f7b4a021a995dd95056e47622e653e4f3ec71df090a834a0a8f0424085c065afbcf6f9ca4bab0361d276f1735b999b9ed3066c0a0fa87acd91935270bc3207c4e59abe4aaf0dbf6f3686fe5a16d1b3cf854a30ce3ec14e9905dac0a3f1a06830ec1348d8e1ac9db4f05ccd1349e367211f3e8f21d539df08102a550f6837a8b0aa267527f95e893b28e2c7327d0614fe045fad4dbe3e708058c5675c4e740a883985157c618ead001985f6085babf244c28fb7a705efd7c3954a3abffbf70fb90d82bf982925703e7b21f38c80b98490b88f7854e2c1c13e060ce069efc258cac96c50f853aa2c46bb6099a3b42de255b067cb7979ef844a6a551158ade7bbcf522cdc8ad6a7f79b83339646362c021360a52cdfb4bc5c6431d950c932f7bb46eb31ddb54c485f0ccf7f8df58a67b614d77eace47c658fd18dc76cf165634f4a25cf395416e8f3c70758698b71b07853bc76e3b920b8f1377969fee9e1d43cd8251535c22f683c3c2bfcdc255495fda79143d0b7aa61cacf6b0804c4926fe1e0c6961ef251ef776208b20193b43edba7ab8842e055bf43a398fd87ba3f0a2c4e19501a7f7f4213321929bac4781ce9e204237cfc6e2589a5040d5b5b4f5941ccb3c0548c4564f7d69ba6181a0aaf2721a83b8647176304670a029cf06b376703a44937cd8a6324140c558ffa0dfcd0236eae6fac1650c299f9cb8eb73e2c333848ee228c9c52674a7aeb5c9d491c6a3ccf9d843a60d96e6e1ca8caf524abfd5ad7a0777f4955ce0cf4d019f1eef3d941486e06d60e7889d490366a552714844f1543a0ab01b261b38ac1d1439fc6540c99fb23d72d7fb7b1322a54cdc11ec6eb72b758ae862955481974647adb60cc399279446663925b8a49f38219aaeb4181a6b3adb3bcbfe1e6fb98101823f9246f688f0c40317f728266121ee865b2e0a4632aca78c2bb5a6c10a2deafd1a4124d252908086ae74b35564ecb7ecbc2999196ced3271334d58aca54ee4cca08a8f72200adf09b538d56610ce8d74ae655e7c996defa7607d202c26db404c4a4a4529de5e1cd05a799a3c82e11d0432577ffa3af3dfe3bf277af879660b411681068a18365fb46d361bcc3f4b2c6df8bbb40599d67fa68f27b145011b529ec085b043ce86bde429a989ded1375c2144aaa6bad75a352fdd7a062568be8fb6c3977e8e551fe7961ca4d1fb614f512213b5e8a683a808cdff534f5440bb11c1daac4b4e17b47b1dbbb7478562a68e15ca8f8a5a99f89f65fb9976d3f9a763e61cdc486062ea24826a3aec0d0dce041f61032468cb87af110891c7434fc8f2853ee2a30843409b85f11fc4760a1d3fb2a1e42342ef68ca1aff51aab189a2cd68058346199f36fa5d4331c5d6419b53e97e4815dbb7a53b7022d217dcb6612299eb81124a072fd1cd6cd469f023e1c05d4f3855e21b933d255f2a2908f230959f9be711960a63c5fd6c3aa22ce931c0923d911bcf2b51ecd421e0fbc88d4c2657c8735cd61657d851291459fd840c9aaeb0daf544f401ba4f809af43b4dc66c6278007eeb42182d41e872ad1e0f45228bc345fbff47d92a7e47462c038d7ecb505ab823dca76728d64ed81d21260986f7480ad58864ebf884a243ab64f294661c48be2cb0a05f3e923cf7e58ca062ef6eef72403693bbbd4751ee614f5642d7f5713ed85ceaf3d8ecf6c55277d0cf1649cc4a4c50ab193923fbe67c418270afdb349880948f148f3e7068064f30f18cdf162bf19bc0549e6af387a7f8838b29f0771dd3c086f16725675dc78af8473ad5891cb71ccc22a5f45ec15da090e337bdfde393652bcddf50ea9386bd775b17f8cd9d07c0f185439ccc139ebd85f0c349b222b40a0fe5d374bf5e0a4b8652d65d424b63e42356130c15bd62c379913afdf4c1ebb77f31e7f0d870202456d8ba4dfb131005ebdd12e24c3568fd651ad926558e2031aeab13a9932dac51f0d8222e1ea48d9ef951310c1a85725755757d7f246cb38b1ea8e49d0a14268417795d724540253d19947de37fb6e7a18d209382b1205b25ddac4287823f9658509ee3a7a0ab8cabcc21a5984fc09b91628c302659ec11914dae321acc1409a747a6a169aba6981fc4c2d5c7a362b87e6eab10bbe169f6fb937a7717c6ce75779c8eb7742c09f547e29ac809385220425066e3075adc28cc0c53302c87ca4fb8d39cd32b51c5845fcd821d8555949656286a1adfe1dd55877edee1b53b4df0c3a589083950ad25d8adb84f1a554c66972e1af8f296e141eb22cbed9283358e68a3ff682cc4c52c37194f83fc73cb442a2555afea3be50c903820a4a342102bec93b42d92b2b0ca43bff550e98bc96987b9020766f6648293d6e269cff8501dbea752a2cece0b475ca55c6f31f2b9df72f9ade4c31153d37c061ab88396793ff33a873a1ac43c25df59a0395821ab49287a97ac4afcc3aa766a0d57c667722a0072dac7186e54f9ccaec8c8e47410f27d9e2a61436baa24f3e28989c9145628f219d8579a857ae9a8cf6f726f17564a131a5a2c89334936d9ff1eb7d2e92ebba9306b2c8a5f2b89e7e2684ba854463856c436ea3a34e4a6d29160ad18cffdd341f5773f789788a4950237c47ea074f96e4a038da775b214efe6339b37b3ed60fbc2ae2915d0a2838972569d51e67c653b307acb6a789ff90edb7fb855ad024eae0d69432ef1fe069aa07d198934d66d8292e01f6b21be80346c7999fe6b476df7078a30f185d15d612a0bc89182df530d6cc57d1b1b847f34613bdd08d8f17b4f932f7c610e140b1daff00144c959995f2f7eb79319549556d420914d7588c15d6e913074dc77fa42065ddc4f6e1a977fabb288743c4fa820b6fe03b5b9fbcb6a618806965a2b1052e12be0184abe3a444e88353ec8b39e38b2f0b7f896a7018fe1737d922801d1c3f0c0954f160101dc96d5659c785e20281d3649fc2ef831eaecc7eb4e2cd787c87237e96d93a529f1957ce607711401d315a46e15f207dda1c533f032371c77ea2f8c6127312616bb04461c459bfa63c6f732f37f74e5cc47c9538b9822f4b3689e821acd7074e6d4f2f5c44015d5fbc15374f60b11c59f6e2f2520ca0a3ba1bdd5b898ea65942b035406881da9f9723b560020067fa21e3e9a821531cf19c1350b3ed089ba298dcc1a18f598764349f2e35e0ad85601be70d2ac723944a5b9703948a42834702c7f118adef7c5b54c90d8fd94ae53ea11dee70d0f82fdd9153123f708845c15257a4053927125141332f5e57578a69fb9a506afb61d18d2e33250d5f75942d65d56ed35e82a368e735f839084869fd8f1fd9d4622477e6cc9c108a9861d21bdcb912aac874c223150eb4ea68e3a55d2c6854339c2ec226afea43aad98bac79a19fc3053b6fcd056b3b1cf160f0dc3ec7158eab05f0d3d67e9b064387006c4e86b51ae88f8e265f6eb920e8669e547534965261ad0a9bebb81d1289aa131f486e89c9a3d2642ed4bff43f7a588f5389ff20e32b1e39ee169443190da33a86a4147870995bf6c36c9002915d94446c038d74ca900d1cdc1bc84c73bcbc2f765bdc976d895c6442e14957e69467dfd890254ce36257981d477ba8bb2a9a34d439769acd21b5c4eaf33c4ee6620b44db2555cd3e4af18d7f7700a701e737eee25fa2274b2400a8fdfd38378bd8dc41f8f82c71f3a702433776de27a99fd2b93d4cdd5a0100a24ceba43717c60ad0fec4df56a66e3c10789597493a27226cfe3ae0ac09cec4845b85abe5e65172ba67d7e427749c1cf6900aa93c198be2cc24b6ddaba97dd6cba39bf537daf2123f6c888c1d779e8caafa52a71f70c565f3f9ae212d9359c5a4ba7e0ec1ad0eb2856303d95483a664ecf781671d4a2d8f2231702fa63d3e719094ffcb17db62f8c564cc26d82a6a6067cfbdc23c2c1bb09085ce1e606fc182760b6138c9fe48c4eb31d22b2c1075491a2b0389be94b5094aa356ff2b11de4fd04e1cd0314a3347f859a0e126b44e57bf2ae714965ba198474c6a28fc2aaf9389eaa5dd6bbe088c7c5104e1582093dfd021a4140e784e1bf8b88604ace0533c8a9b48c1105d1a35a11cc5254906c289a5e429db54c1dc7645d874a0809f68c1266cb08422911064150fd444bd522547d46a0b69089c8662f39d369c40d861d127932c33b04fec86b6cc03e973b20af238ac368fe85cb2939ae1e4892cfb58d4d4fac6eb14c0de4f5387138b11469d6007556adab75102b2a6bc69fef3240172f55d2060a014eef5a449d025b05efcd69b161a8b10ca96f3c575d8d7860a060d950b7e6e4f802582af28a8463745649c89ef54f037228418559599dbcd61e37d140c2bb5abb470b4138d28b7d3ae6d65ab6b9068a7b88d3bb58c7cdd879e9a818262e2b2df93a8dd44da88103b87753ff99ac4cc8f8392d0f333e9f652cb83bd16af08c74bfeae6f9f36fc51b1f23672301c882a600429e7a55e193be5d6042b995bd5f05c486d40f80ad5e53be4efdf935ab1fae4cb0f9fd3e35d2e8a448da0b412fa0493714bffc56a40ad790d3fa8c9ab37f17330d116dbc5f248fc54a84a2028d4463b125b7df7410db77bf78b709775e1b27e0ff753bfd5bfa4b0f86d63808316469086acd30c823baab811427e22fcd2efbde447983536ded47f548c28f9a99b53c20f5ca6426249ea89077bf7f138211857f139f6fecc345c91c5dd77be219c021a1f90d7fe7c089666716c99e50574242bd11e808e185f4b87f8b0f406a45f0073fb4b0a3aa58975f333cbc75d510512bdea9cab9189cb40166aa727aa88d4647a56edb033bcbfa4f39ccdf16ff2536aef9be46d517d0f92b5a11a36b72c8c36adc6e14cbcd1ce05635f42afc257c3e4045a15a46331cdc308762d76387faa570e921c208f2311d32b8d3901c32cb8b9e0124c866bdab4be0aabbe833fbec2e2b0b8a6f6229d74a8a835fc28164e513ab4b7f461849abe0a55f67c0216aec32473c999cf2a9ef1f0a41029a560b004ef5f5a285753796956aec0976e4869543a59a91e9c01a2a18104f4e764d9d79bb6f3c750db3ac9102dcb6a4b5689e0a3e7b99c79c1d238fa52cdf4f39a9daa284b20efa838fd373f87cdad9671b7e3ecae839dafc950c94ca19abd209e208902c803799a9eb1a1c26142f63304e3dbb209f8b85138de597a4bee98ae70005e098bca4439382e3428e25c544ef607bfd9cc9fc72b452c2b1a8ad25dcf7e2fc272c584ef57ad126dbe1a43588394ace5ebd87accbf3f268a705d8e77994b8478812451111880ac90afb64b4bcd51ef7efcff3dda319da44ad8bad8f54e1e0643a5762c3c9be5383d85b6b469ad26b872ee7999742e20b02844777ed403802b7a6e589e3f2b9bf2146317d48f43945665a79ef912763019ce5bb47770808b65472cc02dce0d574e7287500c3bb5c2089a64593d6e332e88fd03e0e68c5a835eb8130885d4e1f08f70bdc87b6027fa6bb80778cd1faa8f3c43906b795d4473c0630c70b586076c04eb4840e7c3c3215f60dc8de743ac8f64d003cc89b0cd8062398c794441ffc18aace5b6433e33f80cab63ede2647c3a4f3a9ab204705ea7e16eafce9be62e311be983da96941e13a6df018a0ea1089a332de9237241e2118d6f34bd40bf5a32cd046ec93bc15c8daac03165ab23b318b4446787e17d2ceae7dae98737ecfd12342495325f86b64a02722ce41d42e4bb5a201c4edc44d9f25334bb581336fd9c22a43eb6acdbc4ab18d3139dd4495bdf19f9b62e0767298f45c8f448501e5d9d39f78c44f347644939bcb3b0ad481c015beb190dd0f92832d8c083635de5a7cbf75b987cc6160ca46fd03466204c3fb5d2e4062489f3b6b6e2f310b9789e495454cee3fdf6b0c94a45ca96f4e4bc1435b0188165f10813c9f60ee4142bb8617a92ec1d8ed335a4f8e1e8ee4fa3137347551222a8a6302a4ea700dbc18c57cf6ddc541a1394aadc48f374ea94f9413cd321c957ac5da01905a4a5f3b687a3d5a01fe605fa4c58b2768c00e2e0e54ffeab63bf844b2b374881d5a8e413571a094b4fa4b9fa3f21ba666d2109f00ba1750ddc4851f9ac4f0c5e96abcd06501df5504c093272f9e51b144466f5739f5f88de432c4666e98673baeb13906d7671e72c42b6bfbe4f9bac64ccfd9721363ca0ed31858e20c51dd131b04c84d5ea80145ddf3fe32e6be3da4c5b0416a701c5eb24009e18fe7ab23b16d552f56708bc916a3ef2d032b98950427fefdcc4c9b3a49a643395e5ceeaeb0e01a47b59e77ce212fbb31a9ca46d0bb76bde975d0b69f76152b90c2456905abf81976599e5ec9a16fbe2e4d1c465f8482fe725b7a1c1fd7d35dce3feddda94000d253efbda7f0d817b70fcea19983cacc256591e3638f0aae8902151b4021d3227ee12e5188ff74f87b27388ed1645d337c58d21c3161309204dc54cc1c8cafcf654608fe74fd85de3f9b0a9e842328a60735f85fa99ff4fa0e569b2e73192fb0e2a96cf0ec0c918978ee0405f5426b41115e0c2d80c5ca29b4b1602c96eeb3ecbe6ae0863a9d2d3430885da8b69b0d7a2991b6f579afb8d427cd042b0259933a4d1147afaf945ccea741060a05f61cbada96f256140a455c56da999def374916c97cc92ca1bb6be1e8f8e99ad77473d786da30d033c5409c84560f28cd396ea402592b12c9e722fe412bbe3a2560ada8584c69c22182a1d717d4cfbc0e3e47d8c722fa9a41eef2286177676ddd511688cea7968f9eaf459e881ae43a94062e9132228e4641ba80670029c689197968933ffb4c176797615493c57c3fdd1a9c768240f612df1a94b26045d7e21060c58916aa733027e527f66179efa706555e03a1ddf40cd580de1338b61971643921ba24e1cfacad92e9622a97a516934c2c5b70b444030e83e27eec13eb640143b26cc9f86b9d3b516e0b591135a196671668b4fd195c22756f856561d969542762247cab7e965a6fc29614e3414b0b0f88391aa0789c9ded0de82d824dbf1214937361cf96b715863757566fe2c08c7f4036a3328efe4d2589347748a54588b917bc084e086a642191d50dd1ac3c645989486c6cba42e464ee4d4f0fe5dd1ebd16db13a33a0d35f758ad9cae7af8b0ce8f65a5cfabb5a5f19d365b696f797863fbb66db614debc8cbdffae7ff7de02a561c3506e147c7b41e19a3a12eaba7c6d2ad88f6d360054a72dce5422c8d1d542acd5117ef6760c3c631a073c48332189400e3b2e372d80ebc152c06e9e3ef7919dc034460a76b6e8dd448e3edd247a90babcf6a472f374a495823caabaa9e1111e12a9defc5a6ad24fd4cc0ea229b4b4344b30c23f8cac8a91f531465b7c8c24bbd0ea3e5829b9d06ae9c1b2d3fc543b84771e6983f8ff189aaef718e0b40f06e720bdb1344759b8bb54a8ca630af8056687bfd42666f9f5e4aea6a9193c375253e647bc3bc3f81ecc7f0fbe4390ec9febb20e803f289fae6ccf019e32ef36d6fd82a1a099935bb701fe0e83c11b7405345b354926f603319e888966aee5475875d9253677381332560db1d24e9eed0c241080035d7724f758641877897f256d6ea65b31c2378cdcd546f06f01ad6bfe46cd8ae6cccc6096979b845cd785b0665d65f94946e9384bcd343c733a883a09aeba05bac843644efdb5ac229e20639fad7d9f75b11947c44925bd9787b7ecd571273aab3794a997c1515964a774e7bf1252617924f3ff86f7d753a6c60238df23cf8ec556829b8f40997d04be983372937a985759c4ed62fe67e47c173c753be6c6f9f9279054a4f886195bec986131c613d77d4bb16e2db74cc337226794bef78010e8fb27cdd4125a2b2d4200dd79bf6011f3c8d5d9a031016aaafd36fa8454fa284bb6383977df766d7256ecfa012158e2aeaa28d19485bd23e8edbf5867fec0544e1b49e1c06aee3ce530b5808fa01b9d6342aa0799b5253b4e38eeb43c383d3426e4ae779dc0a1a11d87af5aadfefca10c30c0a79fa50c3e5e516ea9e4073f170c1edb4ff22a7132202e187c6c5983f7552bd5713b1232a9ca431564df80f21b7c5db39570cb959a3c64a103379c01c63e97320778cac143c3aec21f9d632e86bb6a5555b1b5dfe2058022ae3c31a8c5818385390ad84c7317b6ee2fcdd34e3b4e886e0e09cad6abc93c3155c123153b2f262750c715067dc4729acc9bb3a1110013dc64308ce3bfc70ca253bf80400e061ac562b465216c2b8c5617f66d4794e34d51e0e7100d5f0356969e78531fc8f7e59ab131e83fe1ae3515d524a8070ea765a55786f83254939da5a3c1a13598ed88915c30935a5c5b3598195b5cde665e377c2609a4d7f3c7d03364a86f87301c784a278a4b6bd9964e33dc8bb6c5d84368888ac0859f12e229e9787f599cab2b3f97b6d24327bd1fe004fdf2dafdb9af4bf31269c95726abf11f477f6718e2b26940a32440db46b4f9c4271d8495d42ba39e9ff188984654ede58acf8147dbfb0687a438525d11af4c1b1ae4ee8d0d7b5856f26502fcba8163a49b0d0c69f94cca1f6981612ed472559d2b44263024398d30b9df35f996342484a33a2cdae2414a63abfbe7ce85deee71d6e157408cce123dd73432a27795a089adc37868c33976539be0cf80889b44a41f271b88d38767b7543ed9a28ae924ed075a43b9815e7aa574065bce49197c39bb0caad4860bd55877b4aad538a385d7ca9a50c8c3fcc380bfb0a264c1f120f659daa9a36efd06a7d834579c6d58559ef52b09da0609bc6a50dd80a4571c61aabf99b4380d5e1641ff0b68656c9f54d967f95d0593be81652a1156ef34f9bd236b306cc5430d6f91ad7b81b4bc9a5e41fdad5342f6a917aba749e11f5d4103863be2028f52ddcc7d22ac02a8409c10e71e98cda1b7d0cca1e1297297c9581c7495ceb8bfb08f592aa5492d9885caffec394b7fd767b5d3262b0b262c9274a430ab18b0c33ebcf4f9196a43885da6cd0ffb04ba3b9fd9e7217ae356f2681d2efd1e1e4caa8642731de09497b4b72963224f5a83cd7120d33ba9c6714548f04aac7040d2562939ae1186586a57f22234ff4e48a2b443b9a09989a5b63c2287963353782d1ca14ce6af314444b44e2ab9d956a8345b48448b689a299f12757ccae8befa018420116e121c9052dc64b30d5f81686a16df5968da2ebdf351e3f39437ab7a4aabdeeaa380a229130b26d6040d5fbf78d7a00818dca4e3db6556bf183ae5293d9e6abdb7ecf5cd67de70d98226e7e3e67576b2fc94f18599a95d6db21c66cdb3e17ca9eb8ee04799c6e9b25bf426f76b2985ed615c1e55c92802bdfc94d2c9e45a29990fca52387372c94a6ff8b464dc95b58b4368ab82665f61727cdc9f4edf4cce065bb7da7367d21527b1a922b4211433d6743f51e206dd18f15b912aab7d0af342284c89f2ec28309c4778bb776cfcf9767d403852a9634bd7155323e09277ee3ca9e030b1b820f1a85325b2a61c7145f28337094e096a9da9b0a91a0c26b9d1692f2ee749dcd25612226c5673c78d690a04a3af4d8959c38e205ea1c54be0685935d4bc606cb33cb1f90e907b22ef2115f6606a577d7e6609e2a51a9a27959a2331face552a0635bdd07626d55b62c8db129789d50e5d3624adcba08e1b26ad8b8b46f4387dc4828f8de720d1401c2f754ea45e9e98e59d816ea33b93b56ad78f62ecdc844949b638aa39e83403e8e54f6dbe7daa5f4d353188c150eda4b8106e084154d8f794036d43f31345c7e1d59405f460f045efd88e99d962c5b12215e699c0f92a3fc26a9c04a8ab390122ac468a6aade00e1efe8710fb13179f8177b02d5c9cb6106956cdb7d2a8c07af174fe24f6441d9c4efa1f98d7bad7d3c206f86d582f819ae988917edb29446575100d90915f5cd43f6498c61df45a2c1ada548629d06f3cf9bb49d4fc1794c5c70155071acc026de88ab9d82a8ccb735e4270c269709c0453de0fe8e4780ca876412b8460ff42171989236936f4fb718613d5008df7e44f9a6b72584a21154e09e412e64c4218e52766c80ac4e39a04f854fcbb302813044f4a9c93f6dbc41a65f9af04e39674cebc23cda9185dcba29527647d24903b97db32a176724e8036d4f39079a6cb5b15ed9df6462362b94b0ddd9b89b21386a19bccce0ec47c0ccc9f62f58ba54764d9bd94bb3025700ecc6fad91c6bec4017700a0592714d08c8dba6c7aebc1167aad23fef8485712dba4ba926eed54af93eaa85f908a84691f6340cf72a77363788e935b1314d5fe823e87e9c1a80c8e691d4aa5aae5163fbc6c7bcea37b59288c76cc528df69c032545e7420a84f5599e4dbee05058ed605904e25c6b00dfad95d208def8e52d76baacd64848c96cdec469a633109ba376020739b8bbb1ca3f723df6f4e4922fc9a45d3339dcecd679f0d6aa1b493aac40691bcf6d2e3a6bc1d6f9b4b5db860f7857a0729d1524cf8119cc591fd59eef10fd2229a919bfabd680caf5764741889158903c91ebf366272f44a3d6fef86e6849e0f171289b78c9468c3d5df2703b5c637f0bbef2a097f24aa5b4f5ab5136ce9843c08996551399eb759a8936f249612b03aded3330293721a07994bd9bdac5b067357a46fb5a28bc6606e4c9ba6f28ab066e197e785ef8416208efc49872a89d5f30633ca68db0dc223062884566df8c5a6a04a4c9e5a19376a447f21d62580b37695742c280aff3692a26f2d587b06063d73df891fc813963dffea49a4db5a90a6f35b5994554fc53a74d3bbad2288a1f930e85bbfe48b0f2ccb8f955fb34a63da9c77486b3172c219d77a2c57d02bc75e0d45f43ef0682c108cd576678452d686d1fa06367b205f7c15b2e4850dde79b04cf0b3a9fb54dcf40e72211beb44a543f5c3664aeaa8147dc2217e03c674ae038d4a8f22a0e97c5ef407967e444de3361f08fc9319ac1be4380c95e744ded40f8c8da44700d9f86813ad2bdd7084e361088cee6756ae35b9d10f205ce4b17a06cb5262be08bb1070652f91b519a7d03cff4aa61f040ea37a8fbc64f4bc4c5a52e64affcdd993fed4b3134389b9916231c12202e4c0e0ffe88f88f09140e42a99b6c0c89f3c8a4dd47143ae61aa376614bf66adeb27232b01f63515b4c841189d43777333f8a1104a6e3c462a27919a73cceccc9cd271bef1761e9ba943ae9963d5047673183a0fa957c9199cb4d48eb72602ca76530511b5e177afde840ba1ad6a1719853168c538057909430189518d55a8dad35222174e119421e259ee1331640c49863cc83e14085a2ac8478a14a49ff790cfc7a382b8113fb64b16384ba721d06da22f61184b9cf4ed7e37745f9138649df108eef25f4f40a21fee276204f8a312e1da8f9d2872dd6ac3604123c209a09901e5078be04bc1042d6b5886cddc276730de0ee22ce8f353509c433c7e88a560e68aed1e891c3363cbae14bf47217aa1493c168deb4016458fca9bd59d243b9dfc80c29213bfb722cbd7e19ef7771c0d3be21d602f279536f70f5e939cafe3919f324e0a435e2e5b44118bc47c0a787c4e1538f7bb593723785185614cbc48d2461dd0ae25a8a98179d8a8723b4940e6a40a9c3bdc83064bf0b73db2fa7a1e56c878fbd3c04ac3e453d43c41d65fc307e9540674d124f6b06588e3ffe31e4d4f3540d0673dc98952baeb92bc194aacb4bdfe67a861b61e5e3da15942553d28dc4a515c8a515e753956710f135b156d118875d10deea12bf520de5e6971d2c77d1c06e9948a4f0572a85fb0e036e6d07f3e2acfe379f41df7088e6b312933ba35e8b4a62843cd29453ff3461c98072ee05f7f2943154cfd7e3eeb74848a4fa7a6701123c4e33745b94b95b1c03f9f5c02a64b9d4ebf2310c135966f0d7cd737aa210420a95f72651f8873d168c0eb2d20a5f0151b31023e69dd8936b07a65f0f17753938993de58ccc1554e57d65b49af37eaa2210f72daa25bfce3ceae7a9335fed79d3e75163de26ddde2e2fb7f1dacaabed80329546541e039036886b0ba936fdccd2b64bb401c363a0d3a4dee4b443be3a8f108ef22b5e8643250001bc99846dd261a5c73c844a3f4109da13063d96af54534c7a3075b40475ff9457a726c934ce4c8d9a7e9c7f40c631c5c369c50020d8478a3b99d67706f236e1b63d70627c23570b554631453b69ca249f91ec3d44fcfb2fd0285aea385cdceef0709c54a0823b4ce24d538f989cb0236376ff1cf446381a6b32e9efe01f99d9db1f6720b80346b99be39f99877c19df549c16daee34780e78840d2eb90c2277a519ffeb850b37518c3a8b507170c6dc44d047e923e5a592c01d1c6783f87ea129c9f81aeda0c1272fad0cee6439e16b889a03721d5a8cc7a97fc8c125b034d75c961040b03ac241a99f900e8b8fec1b43ffba0461ff9bb5ce0a3f4cc709ae56246fd84402494100d051091545c23dc5a685b5c5bd5e730230db88986a882bf9238ad597a11270541113c17925b0d3afd6ebca56072a8a220659a47c5483d5c7093a7f5ef555d61c5d68db7330ea3a278c121aaf32ac18ebb869fafe3efd58056c32df06c5a25a760b73066d291976e0dc3b04b2f5cf55fd00ee6ca34f8e112d6c5d2c9603efd7bea54cdefbd2fcd349df2b2c14631ede55e759913f5ffe0240923a8ca66d3e962d42379230421d600ae69f564175d21b27bf335c97311399be4a89d88ee8fce8403b7a012cdf97bca0477268644a3af6eeaa270d77250933afbd4558e90cb958f534d47231d520ed9566b3a07ef3f4d5b09fc4b02dc1fe1dd0ebf693ee07ac4ce8e18edb367dfb21d9ee5ab74dbba5419aade8ab4bd339b034a960dab7cefdc265c575a37e4e5b45bd6345f063ba8d1f372317ea4f9a1cd471d243502868193ce1a3492f02ebcbe0cc95e779eb3eb87e9e5e4d0541f9284a1dac1e1da55aa348fd24b7a5d0af7252222a425c1b54acddcc12dff9b492fdd37ef73d003d0ef834845f63cd500ba41d9a46fd8f52edd1e3cd32e6f039e5e9c9891271495ba161c984cd81ad520f036731ba83e3be4105dd568345514071d7ec4add8e252e4211258b0031d01610e1bf77ee19f52d65565b0ad45df739d136e7f2a37acc9a50ceb322b7af45c0b09d514ae7055cd822b0c0407533d2007c46501044ea02bd103568edca0352a2aa3b3904b7120e9967bde4b42be7987ed3c18e90a6ec9568ca5452294f3219cba15a476186322f053b95a75bbfa401233bb1d0905399402e0cb47c464470f438fc6d00469401110a683107f2f7bba0eca4610af5d4f701b2e46494d04d2b102b858654c4e7199ba8b3006fb8123562a800e80c902b975fd8264b128c5172119e8662ec1450179afe5e9fc8b13239c73221776e3a291cd786b99e27e36cea9390746da78cf8715640da3cb62dfc1071380825b2e72a7155372f8fead1d3f4fd698eb8684a1a899c0ad4562b5879f643dc0449eb0cf28412cb5619bbaf3c3ab2a1f94c00fb0f760494343ff6201ec29caa8732a43461a1d501dd81537d71960ceaf80463449282e282ce99171f0ce9eda6772fe5eee3481521e4cb680602ec8f03c12f46ee83dd578df0342fc0ca885b8d016a3377a7d0ec6c325a76b39c4eef5305091cfc4766302f366d2e0533511cd4ff7863de662452cbb1cb561af7700d4417891204304604d8da32c43cc2214d2e3ea47ec7411a6368d607e1f2f1c0b63c0e1fe3c828dce05a77a0e1afad0505214d0502871e8f99884aca5862afc5f39ebabf477124fd9f1a74ab44fcd12d9c1277965312af1ec215ebe1fa2c9e3dd2b38385a0df7fad73ae8d143a18272df288f67df3403745139b232829083a9bc9e316d34707b9a720c1512622cf961e8bd45ce569794fb081a4aa1d13f7ce7021639a9b507c029fb7fc0bba3579fcd941d20f737e938b5196cbd172d3aa0c015de7bd43c45c697bcf16adf125f22ecb933cd8c84b801b2e9d9973a00271e93fc5469f7927999174728851eead693020f469a8d011b16f0426652c1b1b3424344d49526924e73fbe02b93e7e83588fed24ea32eae500e20843b150435d9767ecc759d13d3826e53f604625bbcbede5ef9b949b0b583e450cd39c6687fa81960a7bc01306b2a2eaa3b16a1ff097e696054e247edcdc45527a9339a6d8a8373f5afee248aec8fa72582ede5b741111382c9d0450f18d533520b72d22367e193e6ae3a258087c765d3ceaa82f153b40110c020ec5f4a2d270b82418c2391319239c9943631fc66f8263eca6dd06a54f6691a1ca3be65b6d07121373441339062491cf10519ffead58909d47f2dfea57a997cc6e31b36e1231ff18750c484de7ed6a2b8fb42a8ef90fda59b405d1e020ca88c101df8699ab9549497bb96bf432bc6ba562d1ff738f2d31643a4e2f0ccda51bc6ad3024f79c342df39ba200981100b5bcbd98d84ebfc5dc519827357abbc4912cb9d8d77634d00375e08ee5c3eba32f3c62146d9b4549270f0115a454b68c386d929f80fde8721275fea18bf8c226395ff14126216162e3f14458c57a5901160f72477502878c2b7b5ed12671d14ffc8a088e4bf9befd0bbb1c9dbb6275f67a8ad0d604ef3f3c7489e8c07817cc4df98315f27668901f2d779a7c34b7ab612712291437ee4a8336107ee6cca424ca764fc25974c92ddf4e680c09fc40554657ca639830c5e6ca4c5af85e41affb9b67c43057325db0aeebf6856822c63f731afccd0ca7744b5766b1c99dc97ec629c45d2b68479852db75a35125878b12a188e31f36d266f083da1dc1ee6c23b21c45aff2de412409bbeb9e8294667cd9935420de172974660c99a7eabde36dc6dc29e03728ef0f8a9694ba2b50339205f528fa3fe3382cbea433abe34998ef70d50710ff8e24934a8c35811f3f73ec373fab472eb32bcf2cc7a501a66798226fa86859642a6d35665d0e68b99273ea80e88a09973c21062882df29b32eaf9f5ca3f2ca93c55b06ece69999e3185566e891667cb5cd3050b806ca67891c94a30cd174628a45dce7b4183ea1479bae330de56ca2735b35dacad8ec1ad20ededbee7d9aa8f192722717d90a14433ec80d33d02173cda513b8d2636a4d8342f04909345697ddfb22bf40a332dd74654ee818d840cceb400d8af430bb31a8183522e5ce4e8198d82e29b13345fd9c84bdf1e6d226254b180ae88a849a6d89e51e98391e0a32f6a26374af28c66ddc44b5a1c37fd9585d6a75675a5b4bc1c26befd6b4900d259d394e0bca5ec3b37a2b301e748c0cc1fdacbc8bf8df17b792b37dfdda8fe01ad8ca0999bb74226a3a565c98e5d0f595f0c0f842129c2bceb70f3b004836f2fb09d57d3f49c6300e3eb1b5388f8af236801049659b1dfab00c03cce03b1a715e373f58966eb2a510187baf4f051dc30e270907225433a45542590b63e27340557c292f798e0c85532b79a1c6089dfc9a37d912d2d7efeba9cd8a1304f93df0b69904fe07bac6c6ee70306865d0880357d117b624271fb18496f98b9ebcab6ca7115ae010488a3ed4453a2fc26c23c9ccdab2cdb3ce6e59038cd46b13414cbbc3403304fa281a147ebc3945fc81241f276fafe8f1f96afc074d3b09f38d90c3eeea744a90b911b39fb8bf8d7006ee47079aa31cebda10ccd78ec166cc1175632651bb55c9a2ad6e774673661029eb986115cb39a4bda9708776180efa317a928d299f91ee387e9565790b6a00430c61484b654459e120701f60a03211579dc4fbd1f2f851faefa4ae3751e0bf84bbbd4d8993e9d9a644628f3d81a9ab31de9b22215078648490e266164d11be72909f9ab345e9e5b3fd02539c648fbe618ae70b4237502200c876a275aa96c098205cb4fa84b5514be63cec66550358bb62d3bac5af7e3544edbac8d6185f40a4a5535d940339255ee3c35b7f78b68f5e0099d37e3eda13eaef17b4984f611c1836f0cbde495b8d0f22514c6da47486cfa4270472a12e3acd1e1959b3c99fe28ee7b1ef3c1968be0d5dca964331604a8510558aedf6e63f845faf8da2e0f2a44f6659be4f3685657d5fac8295a52e74c44260763b92c3486fd942bd3ee628c56717b3c096e6b6098aad14a558e70687cb37309f7a47f8bff8c202108a0bfa0abca6cc660d5d9abf21466b449288afa7049d73056371fab93e27558c095f75a040f49e187832b59a9f5300e39dc7955c72b831bfc85012ed77974f300f77ab699f8f7cbbbe7e356e5b56f393ddafa3780d83fbbff2555cef3d17377f8d3f07d3584217817955a11938f8b8ffd20440ce09e0ed746901377e53d918f185be7b9c171438c3360f925f877ffc5ab46cac5ecd3ac8e82914a5fa45e1c9e06dda09dbc1f5ce1de6f52aeb5f92b0730b4c0325c1b02df088bfa77ee55e9d078ab7324167b18f70b72fb7fa61de070fee220bdc4716b7fdc46d3d749cb525dd33f81543031118384293f142901251444e37f4bea2457dbbf916c15914fdde879035c012204ebc4b6f4e75855c42c4a0292eaecaf142a349e42f76e1d71a1487385e135b0fb94bdde05e4ef43520d746aa4f2e49a20178b2fbcdb2e174ecb433252fd8d48ae07544341899b17694e1148237aa1005494388a926bc8b0c828fcab67c5a7c361b615af2917187572b48ed8100136000c9946c2def8232ff73729137652adcdd5445b38543ccea8078d3915a567b9a39993e30ea89298fe331d6bb1f4ffba2c2b56d19b1b091f38dd98380b456e40b9acf9bbe7c57b69eb05227f67b4373f781ef0d92fbe3406194a64b018dcfbef1a2ec01781f29ddf3f6430336c6541423cd74990c76f2699f4b3cf3885753773861e002a42d0d74cf5e108d2efedcf09fc65121d095040d7d7786044c539002a4553c650916ef76dcbf2752a93a43e28400012cbd53509869e83f25fa2389b4195388612459be202525f75da4d8a5bd414e35c67a3b3f1f8a0d4e515c66ce1e4cfaba6f178379b9e695945023ada2ec81abddde807c510e3c337a0e518c97cd6c862f22f826620cd863f949d6020054c394f88e985fbc33659ea396c3d3f49acab3802d146aa79b6256e9b0b75fe1379048ce49deedbf7bc254b42fd9fdba40ea375d858c8e5cbc44d3fd404ad6a659b36c9e66a0dad757c9e4fa3bf0026ce7593bb7311ea973bcb0c23ea4566aa0be1362fc8b713d083588d3228ee5a71131bd2dcc4111a9aff1ecd96ed88b9545a6132bdbbfd23abd11d4e38058b70f503d18d53dac4ae9dfb9cf4d012553a63e81540f4dbef27451124da3e70cb585a6dbbde08f1531c78ff1faa35a9be629c665ef28bcb5dff727ee388a9f625990ac78f7de31e5dbbe708b2cce5280b23be0f36106b7e04047b7b8371e34231ed57dddd958cb37ebf4bc8ede64cd43f77533e27b0c684c94a11546246d5f3d50c1a7b33f2fbaa6b27e23d402b8559797f787e98d58807204a1ce95fc5dd5cfe92149a14e1e32a77b7ad2bdf36e763e79e327425f6a47d0d14b6ef8b11e259e379f6e7f8cc6f68583615b136784af024d815cd58615906d722260d8700781465223595bf6d269d43165a339c53865eaeba72f640c315ef758addf1d4cc4304230bd0b2e9a63ec33b11f2f5ae25c6fb217be1aeab09bf9fe3697a34756d9bae0944863ba5cbab718b7a75eff41a88ca49c2862bff2fd19b44f7963867abfeec535ff758c131a95b2cf2453a1e812f2bb5a5a53a32dc265d47542ada9e528b9f0c7926487928830777848e42ea0afa8b799bd52d008ea096f8333c08873d83ac71e22e2beaaecfc986f8b51a9ba44c4c8b883fca7f7c366a28c140e407a44c58c57e99a5c68fe8107745212882d285f0cf21c460e5988eebe3570e3e450a427f38efb8e1cb5c3f687af92591644fd66f76640d28c26d87f2ee163d6d0291c6cce42aebae2967223eb70cd4005d2dda39f960f5e6a31db929ca3e197eb04c5371f7c3ffe4a1ad5b19b7ce492c438811ae9abf330c00462c4cfcb361957de73a8a9e1c3a05ddeb4c2ee88e6320c1e3a3b9daffe79d9603b83defffb84e94d2058b1a4a431caa3be318bd2950229d4490f7dc08e841c470749144637f36fb934df21418ab621ef53a29ddd13d227245ba8b78a6998d6d321f72109fe50922e47ce260807b44294571ad21a3904da0d16cb06feea6b7f0e207b8607615038003ca34eb7135c14ea03106ffdba6ec630e73ca5a2e146175409715deac4da64d1142b3b3d02dc195f57425784b2f2792b04f6d3adf83d616612bab58b1b2b413c81e11fb0c25c47009e8407c03faf27c8a802958227cb1fe833afe625797e425238f071411bb19bbc212244dd79445f3035111ec0d2f897f4a284da63661527e7d87114f9d0829851b861d2caa55e225c4a163b913bd9bd7a021cfae16873cb22cf47f93660b2c980463817069de15e6becf3228fcae6f386081470e1ed8467319c2bf78ca2fe947dda014c185b56228f019a4107b72c721ff1daf7c13dd501bc32ebe9fc1f029dbbb441adf29fd4914b98ad84b6f5f0332aa61b769962149ea61381bbf1a082e1adabe66395994c80acdc22c54c40eae11125491f7eb0b82309e2e96ae7a8b1d306b12884c7517edf20b471b12e1e03f9e313cc14c011d067a32a2953da5b02a6ec370c39b5e93dab223a1b72b64dd93a08cb8532ff77ed028650c1c188b7f88710e230686eb3a5af354ce3971ae18aaafce001610dd737ca5161d27c38f10030093e835b9288abe07de26d7b8af3460bcd868030735e1cbb8e0ff587dc4a80973b0492c35e184d1cf7c43c845e9c8ac7db306217cde1e72fa84c76bca8c2b778c9b750641475cb4aaaa4fbda023ec8cb1045d85715cc5b0cefb4489764ad2419a33b5d3c61b0c970338f7415f0d1de2b1c800b8d716e40e0934f1c1213844be8d657b8f8c757c0b38385708bf22c1a9c4d215a89901ba26577efd0cc18c2867f5272723ca679eec58a4e2b098300d32a92171f0fc1a46e8b48bb675bf7253b2977d7da5d49e76986ca8d89a4f7d0cb204c582726dd6440ccdd3aea76830ab359a22596848fc482db8b516050db2d445d24ab991e9ab0f2d9e6f70182eceb9eac360b6b4270377ac8eb5691a446d5e6f41194ebdd964aa829c950fd333ef0da4ecaacf0597e0c30b0461ffd3eeab422b8b8ed538009c5e62fe7c5acba9b9ab16767c91e8c0b1353f0a39d49f8c71e83695ddacfb2fc95c5c6b3b96a22d99300dfd84a6c96b238b6d2bd014268170cf4c18f34d3e6d04759ebf59c09c1c712a4f093f1f9c441786963e7470030148242dc2babdae12a5f3cae393fdcf3d44185fcef878c924978570de6d7d0bccd1cee977c4ad2cf7543de52c4990c28e354eaf8207d421a409384895b39ff87a26efb2ce156d03e8d8914951cbda75530d1d6f7162cd9e26983209101ef308a94cf79dd111dae7a31d4fb3397f315f559512d35b3c0426a541d22f41bb45432e622c4b903e054e998ac0c773d7deb2ac07da78053fdcaa8eafe733c6bc4e952b7691c6e14b538f9cfcb27937b0279cd859b2934433f41c479728016dadb85ba720e307cfd12f6b4e2f93882b137ed16cb25e9258b8cfe4836f313435a6a373be781e9ab11b390198ead97c983e663094492eb3c7872950cc1c66b2f2ed4f7be73a503d2b4e1e66aaac0a24109b7d33bbbe190f36e8e331e6d78f4d2ab4ededa2f72365e72eb06ca0629505e158294f3b9c38fa5e33e94f203c632cd6a9027515b0dd3eaf06cb4066b1b15845052aa3d5c886c0d1911bdd94341ea55a8f7cdec482bbeef41e0fb7d185505fa54a201f9aa10e0fbb6f081175da07662dc836979a89183e6e1a017cbbf2b6f2cbd0b0b1d49f13237698eaa5ec0818b74898f073a594f7120a876b49a854ee234f21b76078491a745591d64ae71f6a280e125f4201d0ec485d4e3306b6b227fafb1fa4d8b5a99171fc50b6d5a42c652167d4f691b172dc27c3d2e612b3d37b595182d2ba0b4a7484b398c340458bb9dd9d2333f43b49f68e98f0e3e4c364aa31e0b482ead8f0b422e53e5ef384d2e5b0251aecf2e42f0eecf8827706535bf1d2c2ad1c4189859abf9a767cf01988102e0109be6d75317897298a62f3da8d8483d62501c2e1b0d868435695e61f92c3993cf249312bda3438e9bd024585a64621d4162e3234a75d2665ff49e3e6add0159c17d2ec33bdb17761f4c498aa2dc3f390d88e7386b551dd253a6e158ca8399149f789993c439359c8544508f88759f9f6e0a18001d509b6e00bcb8314121fd95549737736a9378bcc8648c226b25897c8130592c5856849f268118efcba78be481578baa83959883a726589b7d0e497cf004541f11401e65ef1831852e8a9ff4a032a6c966eddbab1b4e708f0271bf97de1028f25ad46730bcda765ca28b2106b2a7d76590d4c7c15a096db8b2eb5bb2341d35e375ff7d4737f1b3006024444fc4731916016759050ebab457fc8eef7ff7bb61312b59c301d7ac41f51561d28fe110f6e7f89abb5fadd2ce696fdde9028bceb9ca5c5a1063eddce0601af5a720979e19ac82732316415143a95fc6d1b28d6668c92632cfafdd25d0960ad04605fc875f8fa8359393ead3c7bd994326908e52cacf54aa32dfd3db443061d250eb39569400482fd8ad1e2c6e87389fdb195576e6932f38d6ade7591d66bfae89d11a61f4bc579eb498e418c1918745bfa9abb072eccf88e5a38bd3c622e529762d3e4833abca98b2d65f3a8378775f70566da09e28fca970afcef9d54d062c5304ea363ba5592010b34a0756c79e4fb4bf5fa9a2fcce53415dc71e4ce73312afc656b43630a736dd4d429e9033a11febe533086cb510ee9950010c0244728e3c9b51ea32091b60ab8f3dff9550b9d59c2822dfdf4a42f6de7b4b29b79449a6030a900a150a1f468f8529831aec64d8de282972d84ab303e2862b165a510d3572d84a393b208805d7adb08bf96b7e68af006cb0d97fd8b0cafe61cdf66b21e223ad433f07e9ba8ba76708cdcb4d3fcc327d9d256e1863148bbbc286a24afd4366daab306e09b638922553fa44a694894c8fc8f43ba443642ab55c1cfab592318629fd21d4726c2f63b97ded7fec6befaf75d83e1087697cb00576e3b6ef6b12c6b8217dcaf4e993663da73b3c5ccfabf9f2594fc4e8d7d8c5dc2d1b5cb7c26efa4827a5d90a0a48769acd2eb2c9899bca394e5c9b23f967835989931d09ca30cf18375cb19eb8f21b0d29a64451a306328a91e3ef64c9d96071e53b95440e3a0db5d23c71cb5df26f8cee2f9d70cd80db59b610cab284c597dcd559b6386549b964f96b44b5505f7bd66421b11b6b6224f5b5af3fb7f81c06026ab2c485188a2c3db593cc6f3ff10f90eab9a82ca7f669bf3d92f81c66c27d7c1c9f098fb73d10d24ae2c81fef3b0ce4616bc12cb555fc8964533df74c647e7b24dc77df6126b0900701de778fb9effef6794ca211aac140f18828e94888868826dd8f2e7dfe6124c2acec9bc06c8e302bc347826e7cc3529f7131f3314ae2c87f2020a4ede3d20c068a4f1828ca442d6d4b9b131755f2531f5dd23e56f695d5427d7f568691d47716122f625409a346512c064bfdcc23fddcd75ed33ef53fdaa7847eb49fc1402e2471e46bd88f88b40f5d48732216c5d991147a8a127aa2383eba64b33d7914f70de33e944235ef4e1247fe0321fd687f1f08e987e6352102c0666a3050cda7fe6220a41aec4b180379127612613358e6434f9281b56cca52aa58141f096a02a34b12474a169208d33ec234560baa97f91fd5cba8927e547f319024c23229858fb6efa961db879268c34c907eb8df8e3c2824145051c510130eb37ebcef36cc42e27df71e0642621dd9fe000d4342a3843083031c588ac56040420ee3fe86ed3bccd2bec3ac23de772fdf470e6ec39ce492c4d243144c4c5f623158c338cce4860dc7b4d730ebc84f2dee00829472739143f9946912d521e57e3e2329873596a51423a31c94322acbe7be59e494e56bd34b967368c6248e9c5a6ec3365894334da6db94e19a40d411ff88832eb86bfe1117d8b8fef31dc7e0a00b2fc0e0608c21babbe330fb171c8c31c0907dce18668ee185e8b027475cc00d3564a5cc19d7cbcd6484d30d6ec7856211c51ffc1668861789d33545189194c37bc3b836379311560c60c43c0137677737cda45dcd39e39c394e6efcf9b1bbbbbbbb632bab32e0b2d933b7a4d0af6f2e6870e70e3766198d3b3cf4bb329b2fb3496b27ff5d07078f7e591cd93fe6ecd093ff65e6452f6eac5d8fb876574f77f7e8ee45425cbb6bd22c739732d5314f77c91885c8fb17ee48ec9f750ee6ccc1a96387fb39fc9df9918d1d700a9739e77c1feea2c9f379821c99734e7c67099d829b1ce67c50841239fbd51791829c3d38a5899c7d179143ce5eea68baa10573fcd54d4c3e72d8ca5953ce888811c194b3ecde5eed7c91830678c0a20921d6a856ccc062da9b2324bbd1c61da26827cf4b71b002e34316ab41b0d1c32442461395b2030f120649990f3e786c4e891289c0004a52294c3c0e6568512d652495a154c6d2aa0b4fae7632716bee2e4a20c5a5ab12588181a8a5c971dac97ab94f2ba8ef12e538bd8298e3344fbef2f5b28b126cd1c0d3a1dc5bc620cab60b1a48a1444ca8d9947bba7422cbbf915966b5888d91e5f53580e29821b45082dd10a1d8c18c2658f7db071473f8027643434181750f4696e16576d1934f42d45dd23f4cc84eb367df4389bb69cf72f221675dad363bb1a0b84be4abbf4cc1812a650c61850da060fef58b58e29598f4c52a0a78725f70c1416f8b4b7103197558018ee33aa2308519414d8c3adc109ec444233433d4e409051639e208481fc96d2e3868c6e57233d9a004398c42371db5eac00d57158aae931dbb63c76e4a69ec7e3e757b0caaa3648cd925b667cf09950667ddd51d637b0f5cf76b4aef965fcb2876f498024e7677c7efeeeeee2902ae55689dd5cada6e9cf3d9d6e8f20bae5bd8ce9e1de377f7b74eec627f6c01275fae6acd3e1c6e7fb893af9452ba8cb30352cadb3a2f5b254e667708d2e32010eb2efbcdccb9673e1cec7f50c68cbe3277a7594e507c8aa175e6ef906ec9f0252d53ba92835784b8f2350d87d9ef0023777ffd92fb29762e73665a5a594669e65870d65d518cd6a1220e91fb7144b9f1c38e8a31fa55cd1f07fb718cb938dab87115bbf13d3029a53d3b3c4fb166a96635db866c1b11dc397138b3cc7e37c392beed577d2ba3b2f78fdd9d7ddd19c5386e70e5873e767a66ade99a0e4e1274dfaca894598d83f3a994f2c61ff15be70ca1186bd9ffe4c6ff40891b9f8873f9317cd6ea1fdcf7c720d4cfe3e6d5f9c78f609ee1da285a0e7e8c44526e96bc7d1657e4ead359a27b77848767672704b70fbfb7adb36091ab4f2b65cbe16e1ded35da4462f0032a566a8ccb11571287fc6cb635aba13475c6ca68775371a9cef3ba14a7daae2663672a0dadc96ce60d8923e6c8b1d2919a53c626d2b92f585a6f92dd10dd8fe0acbbbaef748f71b675e4c82b1c9ee763bb9a35ceb49e4fb5dac675292f73aaee76f2e33227d3d17495a6939fad996699c3d1c96f666e9583bbc1c1d2919278b6ce7cff28dd250bb86e8150c514367eb7003cd6906466a3180b4984651f611916ea60d9b37c5459be2a1b5920c356e2f48fce52760ec0cca928a5945a6b6d5118ab1cbfda23bcc8a2c4e5f8d4c6bf3a50d972fc2c892326951cffc61eb82871452ac7f7b6d67e36fe4521c7a60e3491dd5a2b03982bb67807199d61891d873f932398ad8d292e624c4a897d3a6223ade31f8ae05662b12d9a80f56bfb10486e1f5dcd4d2b77d8a7717cd222377eb83809285f3e8de3be93798ab48e2f99c14bba9dc3869a4170cde393db5ef02537930f5af2f6adfcc6fd01f07463535c5a2de5248ee3efef33643a806019894d72f418e68a1ba31c840293fdbd31ae7f04b3d4b494a397ecbf7ac10d1b8a7bff25ee9a5ac5a12be51a73a1288f41453dd5da54bfd65a3fe4d9a0b2dd70f842debe7e5995bf49a09bb2c561132b59866eaa1427c9f28c77c72804336e3863f689cbbe5b524a29a58c5c8d35d6586394517e11d3cec12cd7e0524ecf468c92f6d97dc7fb5ebbb88883ee60961b74d91e676ae61e9249f9d3c1a74eb3643dbb7b76cb4c6632935996cd0cd7c8960fb7b117391889da3bc0048a4f3f2f8ad3bd03489867606e187d082a8cbbbac1d09bdf5fe7a08f31433662ae8c6f23e67a7c0aa5907cff6c6e57d4c8c8fea57d6bf3abb3ce39ada5f4ad90dad50c71e7afa0298935cbcf9a04eb2eeb27b1396b1df934b4806c3b5b47be9d0fca973d1ccb47e67e2905c0148414333c4073300111c5b5a1250d252d917afbcc6636b339e77c8f39f6db2b1dd710f3ecd8c3874b7128434dce60411c87e53fb3e39e1c64dccf67a89143b0cb53ee6a95a371e277ebc45f6d5132c30339ec2625ae8d1b5e2f950a70e7dd4a293b32191113c10a1307a0ba4bc76164be7e7c925fdf872022bebc7188fa47ea7ffc28a1041144c058878e999c7d3893b79c7db8e5eb0d913985fdc8c1fa32f5bbaf56c9f555f55951dc306e5fbff386c8ec3da8dc2341405c161477abef44db97c433228383f525b0628a650db36ecdbdc9562b165e70b03eeb1dac5ffd48fbd089b4291389ea911c9138f52fab059957fd8f8cf640f3b7fadaab708fc4a9bf03038f13b54efd1efdf2211aa77eddc1c1f9be1c3964647672cd163b1707abadf56dadef6d71fdc3e8b18ecceffc235f46c9f342dbb1737a95524e3ab36c4a49a5ac3ea79d2d07e79452caed3a4597539b19b5e03783297fab9ba59dcadf3a4e6efc69b54cdbe6c649aef36ef3eeeaeffcb7eeffef6da94e6ddc96fa7f25ce899c2771da29abcf29a59cd99c524e97f289ad22ceb0b5e40445adb3ee9add3a339b825651edfbd32f04734eeed6545458e024c697f1cbc1049a990a9c644ea693289c48e9444a27d4099d73cec982289ccc4c054e3227d349144e3c21b8e87266b45a6de33a959674c54ab47265ba96894a490e7e63549ecf0c0d0552794ba262508c45285188c8280e5589473435599219a06cbae92e191c8ca12561782126c9170e57147f377004299245cc314879463d0a70a163ce0e8f9292b6149bbedc1f1b4797a4cef36ce7dd7bc3792b377aa909adb20793c6cc1432a0e172e997a62a27d052850b1b596ac6b832b999aa58996983a9cad1115538d0441521eeb57168a78730d9204c9511786006636031c9034a96e70358e4b095b43497179eaa3cc91f8af90053ae3fdd7542ae2e19468c0f24e181a53b27135f260c261360ecd818b0e155119830ca99053383eeae6ecdea68051953182b02232d72f693e9e805464ce8d0a146110336987e28d2c1da1c5944b93182a1951740d8641185c3053fd42859b941c506506846906443a58da1191124d5f80084cc1651344519b85928cd38a15292a962289525e972d183b744a44201944e8ba754144ec98ba7c40b84d84440d42911d583a6c511a74314ab14db86a4d42dda125484a8905da2ca0f3e24b0b2841519f0e16268092e443e5abc2cf1a5089f2c96183384cf164346443ff86c5992386dff83c14cd24de5ee220d2d425fcc4041814cd29d2c90697a8106d2908109aecddd451a5044dc2d77176944615123872ed6c8329df87097dc715766e377dca7defba6bd94c18803e8a5bb2410e8171843ff986d976cd6f399d90269d41b22b3c4ad33eed76a1cfaaa8ffa0855c8f31ba49f793eb7a580d4771b87bef7f9cc7fa1bbf9ce90e7b5f6887c59cb2d91feaf85155f9c519d45ceaec8a87f596e77d169e56aa53947c54e13471b143c6ce19aa8a22bea21851da23040c490962d6650a7405a434688034861a412b2872fe893115011539f504a69105ad5d24d54a6c8613b752942c5095550ac526998a83041e56ab999a814514ca5881db4cc47c1092e891be49b9b2989189c80f3a2559a4de9b1535ec76d9aada19991b9aa1c2b1c376c3ab861e9f81d1ee02ff7f78f0f3ef088d42c9f6b79f414c7836653a63810b84db333154296e2c0158e1b3635343415de90e5733835c5d9947c6e8408a8b2f0c0273e0d43ee7c4b098ad30a0a940d94282558501efcd60f357181a21daea0c1c61a691851a558a305a935ce489ae2660d2f86a050ba0692132a56fed6e4008b1f96bc7832c61731a2e062c150baab5b736fc64508281651300a6c4d02881568994ac8a4216b54208db29965138a932ccbb21920aecccd94040f39fe9dab9c25b143ce8260adac65469b8325a6bb26b6310bb17d03d7ee6ab0ed1230cba694598c38acfed650d17ac8b22ccb683044520dae88b28124bc6831489d08b0a840a2e004776b9068c10e52ca237106dce7fea17d7f03fa07fd950aee1724c8fdb07efd093dbad1c80ee857cf9c734abb49ab24bf29a5940bc8f4231572affc9e9e9da5091659feff02b27c2f5aac4cd13df775d755c15da9ef3fe22ed5f7ff44317470028314d12187f1a8c582786ba66753caacfa521c973598694a66373516369a5139a546633c8a4772b5e291002338e5964bd480b7a7e2900fce72f8b7dc1d37407077647f9e1dfda38dfc57d3385926674f19da5b4195a7ccc13dda7bb37597f4183f5b2ba394f2043fbc6374777737826bf9a25974f90d2342034ea69456b0289639e6216e4e99e16e9d397b882e5be62634c6a4212a08b41f660dd2289a6908fd30822e9a0d8ae0414341160fc801cacb165ec2a0c19509823574f0d61812a2b57811228c249650e3a9897a450d2a3835445085460927a2f801075fa021544150031926033862c4a658e2891c9acec87c50434a55a3082388a04fec7c2b8bb28217f0f0e0b7fe0df0841529c2a062832435a0c8928d6003501a04291d1efcd6df3f410bbc6861811754a640a33e11c68c6d4b9834a2fc4724b65412acdece39e7444229cff93593c60b1251542d371312557278bf09aeb9dede1f89f61cf614b516b35ae83a8ee39e89fcee1b56412f1747eddecca318d4f65c69938b3b5f22fd70aff9036918c862d0579ae6619e0df3d0d80ddd3329d261a4ecb91c38bc6117240e7dabe1ed91582648b40d5ffb4d7a7eb3517b24f637ed2d66b98659ee340ac5a11c6ddcf884a31707bd222eeb89eb422d04e55e85e0e27f38ad937d905bbe7c736751595954e29f1efc30243c8a9cd83206261f89cb77cc9a482410025ad094148349cc9af8c8f65afc52b9e58bf523df3110527c20895bf60fc7c94c82606b29066d1f98bdcdb22ccb223824d5b0b9e2e6f48760d64de3937b36bd5ffa10f2e582c4993f52b98b70bf2371e63f10d28ffff62effc74e8b813090c4402de50c6fb4b8e5c7ca7efb0cb35a906f1f89ff862d66c271b5165161e6f94b6290bf56503f73ced96268cffc2093c9c6847b560bf6e5236043fa79ed6362711cca8a38fb4de86bff43b5fa1603d9af0fa4bdcd961bae5831c60814bf6bb3e57af69cbb3ce79b554ef6195bc0d5ff205bf96282649f893fc784a5693c40e8f7c490c45fbd642508fda6944279295a23870d26d39a5124a864ea23d3ef03441c23b875ce973f1d90fc0e378165f4332e73fe117cdc72907a19e6d991c40d5b9982556b7fee7ffc39fb13dbcb2d776531363d8b712c1fcc92df3956703f3f0adadb39e2bad533c6d7bfcbeb7845bf73322b479611fbf52b66dd9a2c2d5ead7270e5115d72d84a3df283c822a72cff88fc9f2f593a9076d0478e5f9f7e37f9674ca54f643ec5ac9eb93d21501de0bac501e9951228db23216a47bea6affac70879feb7e6e7b84bcaf0b374c9a738e6c41c75e4ce71307e7c95120c2c2c6e2f1f89f68e993813a41f7fed99c8dfec67a586edd76a1b56a547363887c9a798097da41fcaa4bec4ac888f64b056021d742b7172b4e181607422e6835eae7c6f1e0727eb899b7d679ef9d917bd4cc1752b74a8fee1dd3841981c32b96315395291e37334c789ebc9a7de011a967a4e7e4462fed9a189504f7bce6bf454d8c463b5e0bdea7fb2bfcf65a00b6e7d96fc86ad58125f07eb372c47ec7e971cde5c7fd6af47527807fadeef90fd8d2d777b4ef535ec765eae6a86a3f95ad67cb5a1721caa9d64751df771a87e94523f12d58f4af52397fa714a18ab58c9554bae1d2767a89fa47ef48478e6eacf7c7148e2d497a99fe388bb04cfe060adef55716511f952611657592d78af7a24deab52cf84bef7489864f58fc8d7fd5abf688add93cb7dcbc1c9fd77bfb0bf686fdda1a86b5a8250a02505545233c7895b13aaf9342ad7986797da86cd98bbe8539d4ffa4567064069f4af4d4c9f5ac7dfeb77a514377e68677c9252fc2597e437c929d24952915e6415f924af4828894546492d336693674cbee8d3d3139025f9d2b0388ebf96262e4e6078e9a27dc92ea39edc1b62e3810ff4893ed1a76d481b13ce39673f14dadd3db3c63d250f735a1e1ac75669250f0df64fe92054916328876a4a8250454bec2e305268667366d14a916d93e7901b39fbc8f99c33da39e7c491336c3324eac718638c31c618638c71d639c7cca1d6914ce88d4ca3b531c624219b82ce9b84fa077df90ec6aacb7f01c178982cbfddc58432284b6cedbdab1598ec4fb4e4531cf450fa78a6324a30fea24512e7c95dd91f85490a5282929d2e49a14d53a813d16793a9937c699a53d68ebe1c6847de109b9c61ce03208ee28dfc6a72170edac571a80f0cdc5012492277c97f69551cc7dfb5a38d88db3991d13b1c705ca5b97f4636ee963bef40ccb51fbfcc58ebe77dfc648ede0a137b2b4cdcd52f02d9779824f47e7646e811f975ace79efbee6b39c8fdfc4007b9cf61c6bd0e729f61eb207793b967a1fec43f0edec820a46cfecc382e7b40dcd066eeb95fa1c7411d6d5cff18c4c1c8e108ec1059c9f58d849c48581c7213e87b4e92c02149a9033ec06892529ed18abbc24825270dc5e02e2a3153a629b864fa0af09784d17825d32af251d6d58f48e7faf2bb9187e46b091d52338f2937298b5f6e70f81ec4cadf3f2213ad439ffed7afe88188439f66e1a122d30f7b442832fd10271eb50efdd41a77be90a04cc5263b147f7950e3640f058c94303e454c04e32f183a7271faf1887e5c72d77c311e14464c98d8a54e995cbf9829d5b2a74f57ab7f90ca78d44edf24874d5c90d6ae9c3a0729a516d7d0eff17be3aee956a2b86e85b528bba432b3477ee4477ee455dc8afb15776549585c8b2fb92bce6ec995ba580123771726e1d22fb7d2715dec9e9b7ee447d2332233f7dd713804a2d34e31592c6a88ca8c9a510efa9d56dc8a9596026a51183b3bdf6a28177089424b0684c6c8c10343784b60400b2b2e0e476ca1c1215689b47832438464690a33a0cc08a20a2129c61942db96338010221a89314980051351a2165a589924d0e20a0f28b028c41ec2ac76be75e394c3dfe1c8c8220c0e95034e9604597891c224450a2208b999a47822ebc8cd24c506a4fdfe8ab3f851f3a153331b64cee69c73ce39a70757eead59dd3ca77d604d0866076dd6d262d6acad1f8b7efc4c8bede0f7d1f3e7a6fb470391ce42ee11777ee49ae370e84f43cd99866d90d9e2e960c52c8a7da257275cb7a05c9e22ee8aef60e7803b3038f8a402184d5c7a3a36eec9c96915f1978f9ffe41c3049a34cfddb9ab96410ccbf5c789ad96bbc2beab8937b0e360ccf1a666b5521e4d06541447d99bc26e8ac28a2d8ae20439ec2efe956691931d66e2866076db394e6cf99ab0f668f03c310f1e6eebc40d881b72e390027185f8dd5176c4b1c58d1fb6f26c1d1a94dc905be290066f8519ce1d77ff9cebee3e8c644f6d90597ee733c7305921d43343203f3f0896a23cbfc65f0e739bdaeed7b9c8fd707b99ef87c15f77e67b6436d79da15f4dc3924c7d4ca1eb7db7baf936995a6badb5dad8d4c84c192c53f336d806996b70f7057170ceedc356221244666666e66564645432aaaff38c6a66e65bdd3838ffc6f79b6a7b990fefa652cd5cd536f3a966be1a666666becee008dcb7b9d2fb3d418a6cdbc515dc7170c7d155cd5fdd5c99fbf970f0feb6cd601aaacccac17977dc35b9577d354c21def6d3fbf91fb3102fe696bbbaf7f0fceeebcf7ecc3c9fed81b86bc349e4b49827d3b781663a79f070e78ca764c0f5fbf4d727d27876eceef86dbfc7e717de1cb5f73b5ffbdac1ae8d7b7f627772177035c4afa1ce582c16443f0829be1310a6431cd32487f1fd06274f3d462838db044740fef47800cebaab49466f9226b93d21637293181fc05d7f05052185fef19decc09a64270f439a40939c84869ae737993ba06e88b101dcc775075cd7df9e53b17ce26b5fc364f9441c81afc173fd8a8dc4f9f1230e9be469e50f89d9f200e27adf7df6f100e2f200e2cab71e0d42bc1f12f3f63d8ec304b752916b08b2f7db6fdddddd5db7b76d9bf78d6d90d9fb3a1b9f4b7d3acc108b6d347c4c6dddf6c1e847037d6df52db0d2af94d24a354dcbbe523a3dd788b86e4597d3878ffee1d5cadebcef36cee6cd05488e3e9afb362d3ec5d341708867b075fc71bce03638ef0c5626c972366897c40934b3219e2b5ffc5f5725c66ce5b0c6831cdefcc8612bcf9c6c420e7d405194e71679cebf50c420cf5f45c9f3ff03b9994040c615a4a982c113607c706c48a1b7594b3077176a082dc1c92e4e6078131729a5635f72294472e825142864dcf05f5ef96a49293f172dc1c9cf98e0223f04929bc7afaffc411f3d67927c293408b195d376e46b2a81522639287766d28cd9d4f5ba0f1f9cb199e4cd988332cfa424f9ba32b4da27b138a8543f29971c94bf7d928b83586613cb549a611c9a312fc344524ae9711511378c43b19964eb9d1f7e12986d1cd241c60d67529634324fe5677188064729984a9e1f0f1ce44fa8ce0a2ec5d5d8f80b39c3a1f649b29cfa98ad96edf7b80759aefdf63ee599bba7b294a73219999ab9297b7f4797ab00fb4554f87e5cf85e80418619400ef3782eb89ef5bec73d96fccef339d5ab986231d567efaa2c3bee72556fbfb94db571aa8faa8faaaca3891907587237f485336fbf7d13185cc0a8f16dfe857fe353e1cda9d4dfb0a909fdb5cf3c219ef76d5df6edf9bce3bad1e078c569341cad70116300825c93dd13e2ab2bb2671f9ddcf073401ed0b18f9d940f32aeb6a49edcb093413cd12537d3135c320072333d31e5e626e3d577c9e1ca762b5b7304d7ad702ae5f846a92f03aa4fb86350f9e2e9092879d3bae811d1de71e8233b8f0e6c72bfd7f1bbfee142b70ba10cb24aee6ae49e14df521cda6cba93b41687da5bdb3a6e9ffb5a061fd5b1384e7ceb09b1d8937250113b0781e8869e1495c0b82be4f12b397e0c67929391f7d1dd9fc218c62f79ce8e01124e56e4ec33196415231d03249cb0e4ccaf441972b2c446def7d872e5f768ba12b3e474a71e4c777e354ef146c6a49393939393939314e3d47a1fae0a8e139f47be26ac888e28f2bb1c6e08aa50448bfb1287fee4c349a973cfa889e5df63cb65cd8f39ec5a9f4305f7731407a2cdd13d361991461306c18d36bbf2dfe3e1da1e8772224b6c1d0c27b944ec5aa46391d8931c941fa51492314f8d1bba8b7157d44183fb3d926ecb212fc2765f19c376c51d6cdc29b31ed7f27c032041699dcea135005250e374ce7088b55c8652ae1ea713c4a509e2de08e272b95f2788bbe57edbe90471ab4e1057cbad13c4b542b823baba09b9be17f58f25f9921f027fc299c8a9a31bee7030c410c21077887d2ed5e9047155a9ef4e27884b939b88f63138587f7a444240e37a433cfb3c4b7143277222a129ee0a1d4a51fd1abdb890f7f55d8abb3a56f6f79bc02a2bc39f65f84746e681e6abbe09ac7e084fdcd089f2fc0cfb8ed3a51f950010c6f5af1f0360674ac541498fb22c6a1d599f0ef9530e35a1226da7e9867428473a44a550220e6a7e6145088abfb8583f90bb681687669466c475778cb11ccaa22f541c477e8c922f8fdd33d51bb7d18d6e74a3945afad172eeeeeebec59f1ba7699ab669b2c885a6b85771f0e893521c24a2e260ebe8862ee45086a615ebde946e6aa595fd1b1b0c7772c8d311132047207a8cdf0eda18b1f5ef5086dbb49303b6be045ba49452fe4beab3a3cfd1f7239be6b5713b6e2e89ba94810b6550393ea7434ea12cbff93487a2a6946f0e3928a1244e7ca11c632cc7289dfa294a71304ea21cff93c1ad61e62cc866cc6d1cd085ecdf59be848ad1f1cca07010a3680cca56ed3b2a47cf23962c633b0dcedebe6f0f9edc9d23f9d6d50bd9bff154e2a6984a3426ade0babbcb88424d383621ddfe303615750160433a387792bcb0e24b96fff1b37c598953c695efd92b454024022aae1436931630d97112cf1458e5242b1abc498c35140dc5ec0f5c7d8fd52fa7880cb02a29801942a5e5aefadde3dbc1faae307e7157c53ec5c8e7b56fa3225fbf773c0aa1074f80ef9df72b0e766814e4b56f23d8d76f2321af7d1ba5f0d50b91d7b013190df98abd6800df3f817cbf15c0f7773fbeffe6f8fe9ad5f7af707cffcd8defef39e1fb83f07c7f91d7f7abe0fafe235ef82eb82bb40aa8007812be3f89bbc29cd7f9fe25237c3f90083113827c0805004a094332522e91ea9b7eea1b7c9cef10840f21890796d677e8dff23b9cdfd987dddb7c87dbd77cbf7d9aef8f5ddc1586f83ff80effbfeff0e63bf8fe28c65da18e677d034d9891ef27c087c2e747311c5f8e03bcf679475ef5c918e0693e9b4f4955e157df1759fd4e111c03008243ad88cc0a87401e47919da7c14a6e911d34322da88afc8d03ac7c7010920d65be870702c0218e5ffdb8e1015672af4f8f0f42c281430f2a101cfef81e45766c911d1e3c8e223870e030c7df2882e3c60721fdc0a15191efe1b353e477f8f4d8f920240f7088e30590038737fec7af5af091b13e342aef73f8acb092ce27c7cac8e7695a90f179550b3b3cf820240f87397e001a0e570fe4b98f838910d23c09588985c97c10d209301e1c72afc13ccd0676c2cbc044e091798f050e87de6bb0af47b82038082924e175b0121bdafc082368cfb96ad5f911b0921be48390341c92f0152ba95a7dfd0858893d01872358988b84d7609a8643d55798563f08e9854323d8bb828c007b11b0923b8208dabfeabb9e6341a58343129e27888d0da24323130487aae78278dc0721918043a320afc3824d90a76181049d0f4292c1a1f727a870c83dcfdfefa68083904214c2d6e3602536059b0f4232c1070eaf8c0a2785160e09f03629b47cd8bccc0a178732af4ae15306b84270105268421882c509000e557f4b48a5707088f33c42f82024150e4ba8283c0facc41200873c6c0a0128e15529a87048f3a914f00e4148aa202414706894c20740088f14be258447eb83904ac0a1ea0390fa12feae60c2fb10826385f8102283439abf4264ee07219980432321ef63051c211fc20a38217c10920d0e65de041cdef7f1350518c2c24aac45e1831a9a2136343d1f6025774846c1062ba91987364f33e4673e25351ba95043040721850408bfef002bb11f745093cdcc7cf0e1f083ef002bb9443e1a1ccedaf3d910d667acc40e0942a219424333338466e683907a706834e43b20c21af219910e581f84347148f373e6b3afc14a6a362a802480cd46443eb0445090446c7028bf062be932de2108c9a6e6839008804323228f42013ec0a191d0c388fc8795dcbc4310d207df0721390e6dde250e6b5e7e8f1c001001fc3881e7e532c147004ae8f1ddfccea7e349f800a0f3e54498911fe1bb79113e1d8ff381217c2038ccc8f3f86ebef5e9f80f3efc7d0f2461467010d20eec01f62adf0d362ac0b33e1d05b092fb737cddafbeed717cf66f7cf46dbeee6bbeed693efb331f7d99affb6b3fd56117fa36ec501cecd73e8b87b04b71b0dfe70bf2453ed813f982fc900ff642be2044b93f850f8669183890204c9e5fe54248055064f9c92170589a41f68ff690058a8cdc117b4ca649f66f0559b8e4cea225f7df3497dc3fdf00317e47a12b9fc715195042ba7b1fd2f59c88bc20620b1ba3c549dc1004631673ce2862929558e4d44bade452cabc33e79cfd146fc26e7e8f37895e629ed96c2263c4128944f91dec70e3f748970017bd64d9fc08703b38205c3b6601b71abafddde2bac3e48672b0bf894b95a3293483be7851c222a710458501a3c94a1587e2424f5fb428c5a238458c938f9dd8534b6e2507fba34a7a42765a47c56ae2f6e3e4ee584ddcfe2cf69c724a2ed2965eb318f184926901d7b3684e1113e504c6152b72484201f3b4a4858a17794c4c17a7a42b514a8692a1088f2b2e985b3caeb8337694a9f895098ea39f0ef4eb9cb4d277a7f4e7277168e3a4f1eba7dd38eb9c9cce5a3070c192b59f5900d1a58bf267cea2537dea2b6945e2b810a5e804f238e39a80c38d4e398c354b2a23b8563a499cf97311eaabf458d07e3acdfed146eafc6c88d9e2b01dec2a965ea8703caab8f1edeaa1b4326ef4da9b9f3db63f3d06a18c32c6490217d73f8773b266985e65e1845a5ab98b7e26ffb3644d2daba9e460248104f779405d12bcb8fe9fa7ddf9c0fe4143cc12e7c448532c2331bca1e599ca4a966fc541575de124109baf7c97b775e4ec8fd2d9abae75e473734e2febb24b69adb55aabdd6debb8ee76359e97dad9c97150e2165c55d79d7d7f326c4af2de3bef957ee3ed1ba99acd2abdc65a6bad9f6219b91142207b97ac93e59185e285b46c7ce7c4a1fc96f1a1e24728b799aea892b77fa8acbd3ff7db16c31c396a1fca845a8e1fb5c8233d9e9067fb22d752a673d07ad65e01eeeaacbdf627687fb3acb6d0344e0bfb4bd6721cd43e7e3ba083da673cf2a57958d336acadb2f4887cdeb88f316e5bdc7ad3b22eb86ecd077dc997c3c30d8150098ab2c7b2ff1298ff47e988c5ebd5fd095918a5f3e7c268964d6c44e9d712477ee12a703d3753121adc969b090934f2eac6a3bb096074bf5ef367bf7c2e48c8c2ec6b5f3f210babdf5f78c38fc760f6b5cf09cf8fd08699b367f9c4a29c6189c31b283e52bff3cf85d91f217d96cf9629a64195336c6463b13cc3ac82eb2ad3395823e5ab5be270befc6c9879e296fdfe3db25ba77b9c808b38f40d6ecea00277e6568a22a50237cbad1485284710624c54589971d594fd6fdcffe61a0763962944598a20f2a297f7e85e022ebe0dac786c451b84f9907c7c1eef028da6ec9fe32f09f32e6cf9526e610c702320dd6e565a690e8c085535166396f99dc12e91efb2664fa270da73ab819320ae73536274d39ac45872da3e39467bb2e4e42e192546bb240e96e498faa4ead02f0a45a36a0f146a0c85aa1b6823ec87aa29a3662490b31a255fde38f3fd6726a3dce50dcef7997dac724cbfb427d95fbb42716c9df97966356f9a8dfd23fba6294e54bc5479ba02854546c928f9aab1985097a62f4e60bc84791203156bf2e0871af31b3ab60d65ffd84a376e64a1fe313f3e8dd8041cae14ca472e3a4683feb449f2d02eeac5419f4f1ac7719aa4bb66ccc131da357568502e353da10135a35f5b6c134243c8169bc18d1f6e313aa6eb93ec1fa740a834ed56553d2b99a21900000002c314002020140c8844027150301e1637c13d14000e88963e7c54160cc320ca410a21630c2184106008316460406686b6011f8deb80cafd2f2b5ca4e439c16314d9fc011747c2b2ba0e11fca35ab938ad4cf3ee0b0c0742f380a1701c0c66f6cfe310fd813059532e59a12640bddfdf244164b82d5fafe8c107fc84ae051ba86f952a75b692a07914447b182dc892d00caa35b8d7737ec0fc179a8651c161314d6e87e9cfa586a7dc456e650ec400dcf85b9b95ff3d62cd708eac948d3ab660be82ea529de872b823bf41e382846828dcd014e4e38d8ce16c49ecf387c5b6bcaef2f144e35dacc8bb92c68066e6a47ff8324b6b978d35cbf01605cb335b0b7538b892b0dfde4c328155fecc5971eaa20728afaf92c2710816b4068fe4c1be834eb7b90d25bc2b838b9765273362d337a011e73ee3ee91fab4f781b7ca6e04393341798b430e26c2122d9c03efd554534d9afaf03cbeb69e7aa32c6a9956f294ec83f70ae9dd3c1b57932e5d811a4155c777d05710c7e9b714eb6b0543c2dbe7ff72f36728a7db3a527c4c2b568fd4a5a60c16a4ed5d7fb21c396a8048640fa623bc9ee28bfeb7537c188204582a290cc647e6b2b6bb858d46c3c5f82528402bd08ac9ad99d7928a66fb1719597ce4a81df8de204282040805af07a62edf2d1c78a8a5c061889d0f277599dcc29618d38cdbf15587f1a0f3cfc9824c210699f8b4b9cfffa482a474840a8159e16f9172a5c4cf5e41d488d681ef8a2e062a2a7d9952f088a019118684ae1dbe3a5dd596242dde499dfbfb79bd1eb194797c80ff5d18c65c416fc61725bcb232c7b1e5032ae1d66ec70b128c6caee4d3a828bbc231c5ae243be86b7dcd881dac0efed42fc854918f1d1f7ca8ab9e4fecbf871f5e0042917dad898a224ae55dde60c890c6d60b6e57940fbc78b12d0982976d05cdd6f1c00d166c21aecb549f855ee4b11c4c30ac78762397cb8bf78c6939a20d2f9bdf87e21e6a9b7bcf0e2e7d4f2f7b7b42ae0c28e485ed97c6ad7776c3a67ff2de9ddca809324c4731d89bce4fe53129820fd309b163b3b528d64eda38a29240b2cf6fe1b011ef94256c45ddc036a2c741b53ce6cfa16cebceebf8a3374c7f853d6edfae08f1219c50be1d6f46a9c1fd87506a3080c3b113492b0b932cb10aa580da02682a69a49c7898870732c9b3805558f81a21d9910fc1d7f9a3d10875bf4f4a0a923728572042c728fcfa2ee29cfd713fdd1aafd59afe5ffcd9d37a663aafeed4769ccdb3d5592aef263d4a9a5ba5ab9129433b4391b136c65844259ef6673d6757f18132aa6eb2ab0b7581d621d42505ef612892cfa08ea20c04ad1bba1c4e7bdf58ba8e6b1f929189e0eb7baad7e5d910e767048762bab637d77935810093c2cd6e51a40cb878408297e225789bb8f9b39ed5607b8929ac2b8652360c8ad9600bdf5eda2a7507f3806d73ad0893a5372290bac027cf009d9efdcabb138e4d2ac2ce9201867ef446cabfc81912feddbadceb56c524e81855531a7a9804b8b060ea68a5f437c1ec627ea38376f607372aaaac27f5cac02df9ce068c984cbcb96bac10e341be7888d5de483dd102bd1b7b3c51201334849d28c56aa2411eb9945bc2f9e090297a5044e0ed71420aa9d487bb212029251953bfad6c12f1851a7b8a144ef48316d8d939cd8cb27f629e3f068b871f140fbafa269012b169bed6ffdf11104c5bc45b728518d8b39945e8a148d7e541896ac0a7f966c1a869b165905ab1239701319b869866450ccc882112a7860bad65e3f3376fa0b16b42d3f3f4adbfab5097cf18760e46c5b2aeabfa1afea2d09b00c634703d5917c7c48f289acb059c21eafd65b4e16fb4505c86c7b6192096cb555d145d450e2cfaba1a07479f2696cd1fc7515ab7935e7eb4690b0706bc2ddff79886c8b972cf39b03c6dccdae29214982762fb4ee50edc6f62500716688e2e07ef86222c6c4053e2b00f49d6f537b30a5a6d8fbe92a5071d34037722b52f67727f5b5036ca2e98c4cb6c5fc4e2c805ddb6752c04286aba52e9651e8305d286cd504e8be4a91bdba09f91d7f8af432c9a951055aa890084bc753185ebaf3074921bda71644eeacb9bf53622f8711ebb13c172d6ad589214e040b4cd5fc4246c64102498d734c080456740b755029dfbddcf6d2a1d66a3ffa5000b38a0c5eb5621bcad127b0e0383e8d48262e6d1923e14db32ab665014bab2f420f4c3f3b4cc60316926adc1a411edb72b2a6fc48a0cc3934ee0a38d054206b47fc2bb1a507e985b25209a4d354de42d0d18e86b4ee73678eee2f7799b72d096c153cac872391c4d2bc509d50815652a858557e4d65a42b55edb65df0dad3c865841540787474dc77ce5bb80613841ac6f81b43377db125bda46cd7e3618e099b8ee6e2e7df015bfc048db755203735a747528d771a8c8664f241fa8a0168924a987a715a799c4e671665fe1671359d3a06c1005ef497985a7dd1ca5ad5845f972381010e40dd0f493654ef41624a27a689743d936a6415f657dd7954c8eeee7046f505a4a51f1ef2b5af20812926b92a01b0a5c3c03d2384a7cf9dd31dc180e967973148f0d72f1e4804a6110400ac91d0069a91ed6c0486b4042d82338525c75a0df841764da1db4e5b86110034a74d8951091d00205c8adac323a35f7c5bac92d45ee27287c82efa8ac3cf9d1d1c4442addf8885e365d491ed59c83e9bea3d522879beb1d271665262b9574341cf5f0a0f7629e7587dc7bd09078e39061e1ca86c82e0a7f45d8d04551d963586a3b6dc666fff5c01b1facbd6a43acefd8685263667556ee0e345b23fcb72aee6db482d20e62f5d14a72e274e0c069983e0a24cd885d28ca80c6348df799edeafaac31683ce7828d3bce38a983b5c1814e54efa6f90ef72c4fa4914fdec6e4be85cc0bbb707a80f706b65e4a7bdf61c9bb35cbd8b3df628a6bed40b3deed85b6e74f7db521a75ed12e8d66dddea2f2b525fc4d60bd03eb05c4bdeb78b450538f9122175ece8455a1a00da529a79b2cc4169a3464429ef9fd1209344603ce0d03b726fca8d9ad2e5e73b54a2af52f01a5eeacffe9fe440e85825d476cc12b4dee9140a01a9303bdd98d50eaf06d965d1810a8ef48f1d5aed585a1c076c2ccafa804c66ebc5c03d94462884a4dd4fc5862d61e5fa8f442ab68fa9297518365aca2c5712bd4010eb8d58a94263c6ce76b642a5c485458167be4a7c18a52d187837d3ddc386a067fc62bc4cf88f049df985e4f5164c8642f1c7fe9f49a2d77f635ae65a7ccd1ddadbc6b345df0dbad9787ed29435a929e210e93cd9f526cc121b86d2cc6a3dd35b648e441c8044d2c6a3a0f4c46a74269f62ffa69a185d0ea6f3649cdd0c32d0e360cbfca0375b4ff4995052fd58e796688687d1958c18f8cd604333a15b929d83e6d4374aed197d445f44880743da184ca3bea89e9debd6e51cf5a83c7608ac0cb48d0872cf158b90f0a6697078884a241a9e52a56e1683034b10941074d240dfb38adc73d4dc6c7d2b64f6953dc4ab879caa93e4c937d4adbbea53d71a326f9c034edbbb482db34d9f81414ed5126924182c3b5b07991295a81dbc1381c977901917602cc126d61840f983ef3d074c649042b639f984537c30d64deff0e37b1af00de497eb7d1457728d91ab796f64bc6127ea7b01f20ec5fb9abf0cb50c00256274d65d9eed4783072b18ee4ed6116d425bb1223114d959b3ac519b59c120452e305a23103a7e1ed0ba50c94460a442306a66b6e1f5d18388d1418d3d8deee97bd9a8cf261030faeeb16bc55aaa21c66d776b0c9910ece0ae435db96c78a002f8fa23c65f89cf3796c7f7dba617de357dbfac519a8984fe850e6d548952b3f2ecea83dfc6e3b119a02bcdf787d84e565c3cdc8d4c8c5e9c5c5195582ffd770b4b57f5deee21c70d8c0898c222bace671c98e4f04ad70b150a3083d87e4b82e77de58fa394365f31f25a2e51f999465eea1862e747ee224e92a55d986f4139712aab2b64dc48a02c130b248015a027dd30fbe62972580b0a6d8401b40667e68327a84a0e0e8c9f374ae83867e021bcc3255b927d4524cf31cd98f549ae34805ecc1a8c76c1cb32c9a7b770784979383ff9add91eca753da072fc2a7a989d20f46ad9a15d51271919c31cf4ee42072d7124d02b65e04e900323a8b1a092ff82ea46f44703565596543dc4024889ffaea20acf9c404c2dc8d1612dd276b38f37c9e23cefd95aad19b51f4af100f85883f3fe7339260ba34bd35c7f3014655e6d6178c54f0acb9c8ea2813eb71391d091b57dc5370e039609e69819aae4e9009587a180b418fc9b983997ef45ed824b9811e8ab2e29a3c2c513bc501db432584bc5f00292e2b5c05c601bce72cc0219b8cd8690e4d706181169d3d2f6d48bfddf1dc0fe8155cefff2bced8482a9fbd8245ef602ac638aa30cee4f85a8169adf1fce349500277b7eda5342d750feb8c9f644ad33afd42cb73df68b89bfb8928946d36c933057069553d8f9bac04a7fed716bfb899c51dedd760d1cf8836a206c013d8707e2ca7356c968248cbaa14daa56e97f22f8f46dfbd52fc613ae9ed1077b923ddb308b91049753a0f29c55356a049939a8308ef74636effaf250b5df14896632893684fae089e7ca9c3d98288ebeaa2da876a25c9d2778f5c1e8ee62a021f73263c117f459cd67120d13fbe5eae05c5ce2c4a55dd6fea30204c661d37dac55f2eab9dae39a85144dac1f295e8c8c4c5d94cb6985d23b650dec63b43cd5da22994cf0d4d865b8e332f138482ace00ed062ac2ae541753fc2dc19610259f57e2f945a9be47bcba3efb014e3143a8fc424177e4a8c493824c048e8e7ba7f539acd6d19206939caa18f369258644c145aef2433340f726810e948e53eae8f1830feea522dc522e1f31190aa97cb82449e24c34447919c8da6aea9ae36a2ed665d6d6129f071663821ee9d21ee699a9f98dab8c530c367ab0f5d8f2bf6e0d2132c9326008398465021f29b54dc3e9909ba179ed45cca1878d411b5f67e903f59fd96cdc3f19af0eed487ed21a4b0850c2f4b4c5a414b002077f1730e5516010f12124e719dfe66e08da3640c39241e88c92eb7a080a0875385f12270d55ffcc261449e6c81f8ae0e83cf1f731f2d2b0d4547adaaf2f00ca4578bc1e4605abcd49cb1fac4a7785762a6bf478f0ea1161afc3934d3161b5c52ee2fe342c5e3a2d0e2bec0705d6cc76d760bafa32902022dd20784f7f34d37f23ed0c4c65f8f2ce91b6f2cdfd20ce7bdac9fbfd0a97339db5cb954cb92d37da588c211d4e990b1039a6d8f190676c340a893e43ce7b5a3bb5ec7044d91e6a7beed263c50650a07b76490c67994ccc5ba221858e45544315b3d6f5be2583efaf22df6ff978aaebbc87e9643c5be8358a0b0de8231e807d7526110c24c9255d612228a8666c2effbd945d550891b0a8d40e0016eee80e3a8c03abff0ce34b5e49f4b3aece14c14e5cc1c14dea12b8bfc835835e0e6b3bab129341792710a5110b101e5682ba1b92f1217df8993bed21191ad03fd3d63e59fe2be51d02b53a95e43e82182b425e32c7529e3168cc7055e82c60dfea844634eff60e45f1b6d7127cdbaa989a47edc0a7f5f1e2c7eec440ae32bd55e5c202ded5554dd85d62236420e1818cddb296be330828350becd1c85a621eae2071609fab7df6f3b2645cfd596848362ef6ed054aa194f05e9c74d5be2cc81dd1f32b9194f97511523137940bfbb11d0504da29f4fad5465e28e3913147eac0aecb9413c81a040406b1f8ad5ef2a2d50a8d9a164a2cb3241f35f7b82599fd1f995cf39d67fe30114a68d155547ab68bf8b6164e8c10e19830065c163a85527a6958657206116cef344b3ecd0942cd0f33f18bbbe3f0dab92097855a0edeb2a7d107f98f582b9c0aa8a1275cdf706cece0ad094cf79a13c71aaee10f406c7a62ae1fff716c2651def6688a53f2ca20faf6ea0476fc750a534f58a1a662905df7bd5c9b333544581b4a284127c2ad4b20ac23f209d8a4449e8f955373c6c718f63d6f398e097242263a1fa14c7f542468b16b771fcae81a62ea103cdc23337729ecf770778cd524d7a1ad6e3fa3edb8aaae77388a87a0c43321a646ad239d89dcd1c613f104d12591f1669e07b61868daef17a93a20a2dad379890b77d8c00ca6225bee289f31b8824386b4c9c18ec8276fb067368cace84d605c8b5f2be5318c8c975bce771d39525178360446ea7497d6a3b0a0ca4ef8bac50e876cc2e011a546e9854f1496d7cf8fdc7370947ff81b1783f3c767752c3f45f09bd83d1d6216cf6ec138ba7b6e1ed47608a4cb5a99f26fdef009544781d8e937c2c0ec7b514f84bc8e95f5b9b76976e936ff19d1d1533545f336d0bd6fc0b613a897366baad6841c3961da216447812b736b0e9d7fa4f12cdb4abff3e4b5b41e0f37b2b0f416f6870fa1fad8818b3d0e82bf24dbe37b3e460a69a4c1121feb5f656e8005419f61b683042adad4131230253803c7182b442d7b5caef72c4b2e3213de4b7da704f50165ff050dbc71680c5e11b7eab82378d745cd24dd5f2279fdbe68e2ad0df3cdf3545b81f703f785666f9b69465c953b9f6da76c53bfbfd1db9f93b07c2d16eac37f11b4cc0385efc41d6ffec8528f991d35c4af2feb84b7f3abad14ba9c425958890ce5144ff07454dcc771d8683df02f468957b41ffa8b47a67ada5a72843fd83e275879ae58593b869923de235274a30c23959faf07343bb096b722d71b9a7c7c9b5a4f4924b8e73d5f1089bd18c6f7876e84f9e2b8f4d5968b713f728e8d7109ce74e52814cfb0fa73fbe2c92c57f153ba9310727710bfa9b8aabec793f4431746bf4b3c1de9048905b837cacd37a53b119704dcf840bd864953a0b72c850075694a8c56e211212223da7b2f34e0b78b2621f65513accafa5cc425f12767478a06896d6471648d3dce6c496489aac784cb6441aedaa398b47368a898b15c3f703e631b8e6370a9aeecb4890240f92c3e708026f0170709e9f77c8dfd2ebd2e9eefa6272b42046966dea5c9f3959888ad832e018b31ed0cca6c57fafbcfd206348a72fe35ad39a595cabd45b7b8cf10b1e0f7c16d200ed042b8bd915377cfabd641a89b46822846bf77482fef009736615913a7955741c61cce24c8d297d4c1af13eb01a18799120391e3162f0a6344aea9e54cef15050f8bb83b3d4234c0285018f125579905895abdfd87984fb541b5d21b5aa96c642578e599ae4450485aa3ec39513b5b8ce730bc3abb5487d4ba4eeed88736d69c5a2bed59368da7a825ae579cc4711aa26113939c5905d2363258503c6b5166ea326742f119b6f58a1855697009bfb8c6d48ef844f7096898d0bbf9fddc46b3a09aa9d4747437a1fed9f8d147ed0b209c6981974686e173491c57b07a884d57104258ee06806a7a27068286cef87701b6e7367039c45d021fe8e0fdfa9e5b594c6654be05d7c96e93876c383a3162b6a1846fe7e184c85cf1197e77b930b21cf93b796a2dd53c24c21384023271b0d4f5c9a2a1ba8280a15df9f40c9b653d189e3e9e8bfd1424cb6fa29013871f48064eebdfa1531b5229e422f11ecee3c5c60ab0bb226236a6151b32e6f4ab9918fa16b3de19dffd7d7cb6b85448248901dc44c94526c4ba879d99c9763b68ef407afc615c61253b110b2f0bb0e50d7bd02926765246a8ea282026f2e4d0bdf2f2456362cf0b859a20ecae53a17a905a239b26cb505440af683ace6b6f138e8ce447fde12dc702ac0e95c476c9313be4ded43e9e72a71e48b0224e5fd914893a0bca02c040d53bb3c5b504c4001716261a30e6f200a2eccea93eff9f4c245fcaf7f840a767ffbcd5904e18ec0b2c8ef03843f492bcd2c68ee83742d4fa8d9129617422454a294fec3ba38730fe4423a94c1330d0cdc1419294c0866561b294bcc5870ab1afcca990d26a9f1e9a1da36ec556dec945782c92d7c708303175b858b44db2b530a107456ea60040d905e4d94511a220c5e46b6749f18d797b3d0c64511e618fe1525a0510fd56e7cd57e3f7c8b26a6dda68941ef03e0bdbcad0d60bb4c80fc24ffc54e892401665fe19ecd9128d1d6af3aee77a52af51ba4cbc3eb03c25d1fc73ae20478c6a7760100da002bb055de2057cf0538ff5e2c19999c207296ac88c82648fa405515ea3a57f32761f84de7e59e9031d81996c3d55b8ad8a0b841b68da03f9bf7421d359762eab36db4e7dc4d9e77c12d81a91a2d1b8095385d0ad784001a04f3e958115089a95c6bb33b5ac3a0ce039634be223ac473392772a44cad698d2199fa53b5a4962529904342acc98fc0eef25e24463874f17a6e4573375e67a99c921f12ebe296920a608c2837691ae4d1876febcf0eaa740bfac5fd2d789a97d6a9c68a402a36dc17fb30a4b05a22464d08a25b84bc8e4ac9024827e965be8dc178f0d8b7b0fa59921f8e1660fda1f9efebf29d81c889e2091468396ee909046f78c45d7c1c24bfe6acdfe47c7a702101de8a5ed3fa96c0514ce16cfb4f4924c3902deaca64c026a9864e7fa66f140b960299156ce4619b837447be72a68c19f7d6f8dd29958cc3c8366c5c343b6ff38be69b841f77a4f9b5901e90c56743a2cccbcb39a8d920eca1225e846e613bdcadf99cfba65f0fb87adad9515de8d96c483f2c5ecb143fb12d179461ebee56683070b72c16feea4e3a6130e040f145dcd6899a8e61be7ace84bf405e03a5549f3724dccd089e6892962e89d326976231cd34ef7e33c83f46a7453f4c2cba65b2859662e62201a2c52c0cf028af03985ec5e15f17dd505c04dd143512c83d88e0d6d21cae007c2057bcbb06e61836da1a7d28ae2f67433b7809ae0c2dc73eaa9b38dee20382bdb48f821d36c2e8950b019ef73581e805c5405315585ac32ab601fdc20bcea04136bf71b1d94bf61c42a0e14fc00c38fddeadaa8d65902a28be57c50fa99d62dcd814c524498017d2919d52ee4e82ae0dcdd054efb37a86409ee5d7d296f65ed51ae1faa6c252da7c6171f44ddcc65647b6e0244e1a3ee0a3cbce9e0e1ef9e8d06f93fe12b5a730f0c0c168eb9461e173465c082e314e3210beac0c188914dd506cc0eae22800c5e68ab0a8bd38bfe803b291e4131f4e05ff0988e01390017a77e7354aa3a0ab61c0369be56c8efb86e64997b5048705e69bbb92513694b8484d067bf621039dfd350ee35209e475d4cd869f33ba65c014a796b6ae4890b4be2e7208f3a1232e5007cbcdad25669f5e9d2d03086a09e533400402e44912c9376a28992d68abea97186299160418e6dd714a3843e3881770e9c81c5536ccafd4a333acfdbbfb54615bed7d1f8044e26dfa25c50b5712223b27410182de62d3c4075e0aa0737f642b29127de086a0c25bf3294877a21c4d0f45686ee4d9481f2af7b36ce34590c9e1e6274a580f0bbc2f4d67c7e57db3286fe6edc1bd130f16a0f199a466f0efd779a60fa82cd2fb4cf5b6cf981a2a10e016ec03d67ca758c81f87f4e4683c4377e6bbd005b50512c3d36be6e3edae099228affe2fd205ab2c3ace097125374d9b26eec49ad68e948720e2399c48331adc0feae28bfd4020b4ec78db14126d248caec2ba9dc93c033e56bd95a2d632468b1d92a76ebcab8b1f8a92a9e375f9f7e43d40979ad0757478ac1d0d6def5a91cc08de37db330cf24e725e4e189b03e9fff9007297aa975b8d1389ef8ee0ab2daf2d524c3a104fe9bfcca2f88776b8b9e4aa59a28bb0c1c79b0bc837bb2dc4b66121facddcbc502e93b392c603710bb64c274179c5607765e20f9a27f3ff44d982351ae9f1944c1785b5d44ee46e917c55683f1ef781ed786139b2f2edba6ea9843c4d033d12de250a7abee201f8cf3dd364b8c9541a5d2494d8a1bbc6a591498b02b43bece59465d0873e8a64ed8a24d0448905559c0d3cbf31d2b292e8179f054ff5e175ca54358876b7abb125f4997a59cea9a009ce38cea75420f2aa37ef9b4fc1d3ca9492e3f551e744d73b874f6327e6ce0e3af5aed43f2a0a65cdb0856ed15d99160f9a8723f7dc4f9335578bbde0311bc48782d4d26fd6b692d1dd01c2490d193645f3516ac92ad6025a0e83361eb70c9ab368aebae20abadc05de21141b8fbae547953f2ecef6186401adba0766708302a08e7c4d24ef021b65f38583d2fc94d7573956f4d9e6486c8cfa68b9903d062bbde16c2feb5cddd39184855a0bca5bd274664d7e0b1b227a2ee9dee68e5246eb1066494cb4250054f59f81356e8ede2f5ca8bebdf1cce52710c5abe86c950c7f1a6e286fcef92b78617ea75f0631735274d7eb83ede365002b0b92f2de1a055e1ee7fe750b368eaa3fafae05355d525e1ebbca35b22e4a90a8f41e155d5a7d7f45c98b9ef5282b69b9797891445377c2d35f9556d2c2e2784586b8ec26e1be7085397690f856040facac1b6c28ebe75879fe8a1b539c6061ae413f30f5ae4538dbf56f6baeb4bd99c17b5810aed5c8ff97bdadae1a3917e14099475866634d82a360f6202efd24a9565b14b09704f492b318f9cdfea8bface30ae10e7c11fa8b49c71c87b9bc8e57433688974b70cdc9482c5dcc2609384995fd62102cffa4497f37f6b0b10f6f64fc86da61f5c3240fbbdae361d29b99eefa26647cee1906e8be5db03788de527bdafb5d6e20f6f4d3a0849c2319b55fcac00fe87dc481a9d4d77e9049f143351e5851a3d2650285f704d70319b223cb6ae5b20bc3342aeea4be93996ec5f9e069d36eb57fd4857bfb586a35763059a47da181890da13c82b66d68dcfe7ff4c9e3229bd63bfa509d028eacf99fb94faae9b1295bd101c111254b3ff39ba81c4c032a60e95c59bcaa23e929f5bcac4352f618cf3efe9dc96f70406cff4298cc862dfc54acd98197d4c0ded317fcd694f184957b43b48ca76889cceeafbf328a4c49ec78c2a414d8f6bd8fad63beafa951f539401e658b3bb8f0e74e9a1eecf29ec4c47548b4d9dfc4b56aa3050b9fa12112407f018e211479087f0c4d3632b1954218d5627cccc312be8af286dc3dbea501e8f5f9edf13ef87189485b7e09b4af2f2e05f947c1e25a4937dc22289a37aa19a04ff10ef398af886b2f05c3cd4b55027b278d925a3fad635bab34caa722d9de7500502cb3affca5fd7d1341a9a325f0ffd24ad42df161a8dbc1ce029d64ddfe0963d805b210371170abbcd01f1e5acce13ad3616a6ff6a7de3f5b33a1b8f100d3c9082cfa3c89c9b2160d55c93919b2967a329c56f3b378559390e0607b71ef4a4ccb82d1b05bc197bd53c8c55dc19823cf034c6e497685620388fa402fb9209579721fc8becc8d82ee3e8f911594b2ce26e835bea02228dd85179bccc59bb6f62075ecc98899eea35a90abc5da9baf904904539b3d7c76243ce3ac5ba6199fd34aa677b81983d8bf75ad443b20da408826e4889bdf8ab03e066ffc56a4a806a3b0d2bf33e706553455699f43b3b83c67b53ed8af4f76d4318b661705cce297b877db475eabba93ebf342978304e3767e878b0ec6784df83d326861fd7ee09f4fef2ae5dd521b00674e02cb5b209e5cec8b0ff9810a02f39553d6559550258a07ac75ab04e78356714e6a659ead2b68ff33b69e6725ec44518f420e7e16e615833518420290f7e346f7e76c5239d211fe70681d7d81426f9ba84e14ae5f0d75c5ef79af02a9135f4504d5f0ce569688b588431ee84f586f1866fa06da0008f0b74f089d4c7d49d158ffea2b2c412faf671ce9ba3165226087fe34bbe27b4c413ba304a9477ccaa3a8113587591f98a26cfb468262e362358e515e484ab336a444ef60ac42b1a98907c1ceb56c8a1f12abdd06723925ca5daa5229925110f5d17d58898b6a3f1b038e92b748bc4e6b6cb6883dd4429f29ab6452821814b90fc7917566ac2faad273e2fcc853f457429f57a23bab7c8c539e0518ada96192a5ea043978851c63d3e9a87585dcb5e4a4239d2798b7f286470905448338dd1903cd896a1559013a2dc5ff8b61ad1a0b4308569b05b48f99c731c1698372b4ea4086e70ba07a5f44e30db410fdfcf4698e110066a93c2ce9e9d2075fdd1fab25dfb019188244b0a0641a3e8d66aad2757cd92a93c50d0f9ace4c484c39a74d20e74f617d02440b1c6f10654aeb6a83b2ce1e6bcb88380c3c2f6a81b7761d07a5ad6931242f054173a10a67ded6953d24b7b4bcb12e933803aab6628ee27532730a49cccd017ce6ed0ed001e309c1941071c91ca2ce2f35da0944ab7f027a5ac14384b3aae43a0054e9c32057a3e922c5ffb0de6e856fd032fe2339b735c3b863172816cfa3e86f08de5057d49b4caf155bb6efcfd50a26bb4e56498a98d3bbbc8f7bbd366a8eaf49dbf089525efdc616cf7fa708569aa4a9b355760c5198fc7fadeeaeba1c30dc44bacea2aeba71ea216d97c8dec995ad86c91ee814a85867bd42b6b90b250b290b15164bd294c707f99f0b2930650ae8daa5dad3a73de14785f4f4149b2259c0631b25a11f683b238f9ff827c410f5f1883ef3c55fea8f0ae49d9e4cf1ac47a310f7e98d322570e2851779633ca38f338dc48b00e1d373edad5446019b716c5758c094d64c414e519888f6225707943e574687f64959fec49d50dab95d365692ddd6c76c85961d042cecd2bb658369774ea735481e8f26d598c867f8f93226321b327f7fcbd23e6909c6dba8ee079adc03a5abf9abb2fa4e302795403543e61a18c92363d53eb47de65454a0e9c90b84e1ce40feee220c3417276381f963429266f1da1d211723b30b17fa087d37af35b13814e08e645ca5e33317e445dc7a8f75fadc33b8f09d30676ec0bc5fa1e162b71480afc62d34b24f1e6f69578a233b233e63524dd0eb723eb85ca9f20ff6162f20703f5602caedf532668c2c53afab79a73ab93da7215ed144b84738d19b27e57beb642f97477a944e1e03230704e0f8eb978ab7c1052af265aedca95d153da565c904a20bc2a9b41ac668f5ce750b33e072e7c4b30ad753a352f790245ead043ba3899ebfb627054fbb3c4e785d24418ab6a37541577a4462506276683b35878d908d93e36b54298140fb5c3c3d383fa804cea811145ca9d3284b8f038a5ce01ca7888ff0c20fc344f41e46d511333871c37cec7475e37f01fa6eb30413ad719c04df1bb8cc7343c53087b027c734962de7f2ed6fac94802c77a9284c517a59ced1301e3d94feb0e00d8addbd7399f94eae49467aecdc6d2b9c489f9e2be174ec2a9aeef1aa46541c2e5ca985fe9d53fb5ccddaf61d8942e113368dbb30344bc9060cb53244e8f2f1854f0b7e55accce6c0871884aac85ca20a984b0c38e1124cf448eb5a511936c04475b6bb464624863e2a72368c268f7c01d5b1d2e0e01a115fac79f73877ca1439548448afe39a7a4e312c9f5b8005de4f8373df0771d4109856cfc4cf6e7587ae6cf8447adf594a21cd07706e8cb6f3be73606bebe041ed946a7b8c1425255357bd9042afc01259e31f1594c225d4f90d5d0c2d65dde7d88b2499653fc5aacda382217fd80d2baf1a18c50ba4a8738514dadbd452313528e08095c2401ccd33d51e81f5bb3930fd66a6c283fe8216d6669e476fd52b6a3cd205b6d67695055eb9d716d828dfddb27514dbe2bedd0fecd21f551f4411e20debdb74a577570c522161332ff80f115d1afaeef36ca9ed6bd6b5c161d7aaa075970e80b29848557056d3fd186d2ce37c97223da069077a14756d2989e7151cc4143d2b9117d0fcf25c1e1400810a4a54377505887d521e15aa5884c4ea38681c6217ef6c3ac091f2731e1a027c623806681ec50a1e35aad4638050194f33a999d138d79d4613a427e5b013a1e1093ab43c5671ffc0f67931e95f9b9147357ec29e266487b5e42571804910c50c7c41fd5c24c5069931f81a4cf9a1d732a3c601cfc6aa9698a56be036f787e4869fcda1ae25f04c166d2fd141da998d37723c05abe7f1b315bdda403b068932dc070823f7b272158eed6ba89c410ee22c243dd60d9399908e75fd0a7b483f05ea6e12998a513d3e57b7280056f1a98a92985daa1f77b760ec14b067bf910ad9667535cc0c57b6be402d9b55d905ecdb22eb7b0cf2a640e237b5af396fcd3d9c1b21c7e744d3d05bdf002089a0f6b0f7157731a1198e999cf092e7afd568ba1b05243a09c5518d61a8e2373f4853b644e8758a29abfe06595b06e5872f0450fccdcd052d9a1559d187c8440b5df06234744a5d3a4715943c74a733e88d99340ab9a774a7e7f157124f5f13ed8bdc9dd6de6ef98484876057ac221dd15b23ffb8338f1bf7be4f5a835405245c109863912a67b54c7d9f7a7e5183abcd0f2fc1466866aee8f911838a4fdc41bb3c5df16bdc44a587e8eef2be53feb77a58236010096b4b0e7b9b952d822824be471ba605ec4f914bc536ad9a9c8238839491ebe5bf42f9313f71a81ade08293f127573dbaf58e184cddfa9a4adc66c83e4c94335740b40f13352690a6ea43d9fd196c79fc28d4ec05bb25caf319d0db611825309e09ca2f8246fb1275a26fe8d8ce77099378b72616394e5333551ad39649d044785a551dcb851b3f5a23dc4962af506481c1d7b8b0012bbb82c7a47f853a7a49f34d36a14972bb94396360fffe29bf39fbe0e01f0386662fe3612133c48a2ca0aba55060b43825d53377ff0bd91097629792472db9f0fdcac1e515e9a045721531d5783abcf99ce0a585b01a010752e89896a6002f5e56c4525b7c8039e55c053f6ab257b2db89b254726b87646f539e2de632e11c7180773f8a89963a55de06f7792d3a75bbfcef8e52e91f1e5a14616e6db16e65ce0a3ab0e8dcbcf3a2dfd2f9c46c582b9823f8e53ca6e79e3ecd8bbd6fa141982d9dba3d046e12197b153d75c8d9e8f1f09d970e43fa57cc666210fd0ddd5e2cf90d2e5c07c67490f36a56c55126271b1eb8e92bff348fcd04d942c7de68b55010be4cec13ba80369105b3c5a963914f62234a8d1eacdbb8330aee36e9cc665bc949a5a69d39cec5047cdea6c5b23c79743e7dcb3f9808b4241ea14f7a001448c51c5e51f9e5abc928e35a58836bcf79787089881dfcab5a6031758efd68f76ddb2a1330449dc565e9c42ecfe22332d5c0ca1cbd0317b0971bbcc6c2b93999634b5fe97bdd1b893d3b38cd73242c462d364e23c1fa488a7b1249525ae60e870ea9e703fbbc0e001eeb5b5b24dbf3588c58743eb45a9dc1aada15dffe18a99bcd62a79901319f94e7ead2082597b27965167d7fbc73e4832c4cd920cb882abadfbc016e02d9c014092e109e4fcfbcd850a10a9d938691795fcd1b82a20df4558c0abd47bd3b63376fad2c0951b8366d05858fd0c49e85642579b0ec27591c384e3f0892e16748ddeba3eb97d40932dac22b5515978e92081f6ddd4833d20a82264bd147f415c1c2d39f8ca00d5876ea0b439f48861104a0fe8826f4b26f4069350c61ad35a99a54a74c262c2931938e8ee980cf0375836a32e862103564424755ae7ce9c06d25b36a428235440a707ce355d4c005e3772cda02097df8c6c22c4f7b0697d14674ee104714cf068c87982fd7fd8e335f755d202a42568b5d3924ead02b9fabe8b53f64d62490731fb81349394e37a26eff433d74169731b97eebfc3f3e7703d6d67de385872540aaf5bc58529ae8ac625fe9fc7e70bc3f14d149a5add23b2685a3f22503525c6e3e6f5650d40832600cb1a094e074a304ac62d9d33eb0fd24106bf7e02005c27422210d51cf2e5445df9e2d62b06af91580fe7938d02783ef6f4b72799406cea679e640a8f96b6c816519b890a18aa6eee8a404fa62a083d337b93fb011c4053fce627b895212a7b5d37bfce2104302206e87b3b0abdf47e4a9dce478cc8192077f76c84808425b8bf21b48094962c49df84b39d3fd1df0bc7d54811ccc6c0229bcb366daf840f9b4a8dd99f591bf494665024b3d8e78935db2ce8b0124e42c29e4ba75247e67128ef6251f25702d462970c1ab89dc3866861ef67d9fdcf274754cf8192efd7954e8cc54a48c268bdc5c9223c15ecfe39b5a4838ae57fa585c03bc8022a87c0d9b4ff1bfefc98445c66c0c9e87c7b72622bd953abd283214e812f6a898aed0ec677d8ec841279b9201e6b070ce2ee2da4bc525ac2d605bde8e2f9fa1bcfd78a3b449a458babab5059e341a16627ad30a88019846c7c13bfb228542ba01329571432ebb3af0d51d59196cc1c2e58a3b6084cad51405b6528ded5b5f922ef306d9173c1c7d535984f85487b3396d84f2e5014ccffb131267281e9a078a23ad80abda35a227a9486cd049991c67972470c2cd13ac6156384e8a0591bbb0841e2b8c17ceaef50501516cdbdb332b683a35ac9b765c603b8a3aea105a77c4d9fe9b186f9664c9aa3f90b3665d0d6567c68fc0e2b328f5b2c2eecd644936a469778e0a6408b1429142070bc6b2aa9cab41a873884b854a2c0f07c532de1a9137dfe361dfd95fe72ac615edfb06b03d9fdcaad117a30a9f277863c2745d2d6c2755cc8c3f59069fb0ed6abc5a5171f6fb7b154284d0f35e805209e709277cf1d08dce3232fa00f93a18343508c18b42a914e6b4e9446fdcb11639b5955f44548d463f4af6692dc4c1e3f1319df90c3690ca56f921d95c0058bb392c65b18bade3865f044d99fe76b93e438bb46327ebb73962745ac168ee0598225bfbf31f9b844ee114deba85c2693b64f741f2f4ab4e7b9a231a7f036df1684fa99b11854ab65a7f8b1d27c68ab3ead757dd7c7a0beec22ab6c525d6507e95a5b4a70c38b96acf5c47d6674c173bd65598b5c488a75354d4f239e02d677ad5d6e03005a0d8ad2ada19e71ad88a29d96c0b1a097c29bdd8c859cb3968a77034df40b6266691ac758e097e3425088d3eee0971218a1583837fa283a2b13e2630cf7a2f38326f478ffb5d4fcb4e2c5994101ffc678c88dd68e8c9cc10d77a94de2d09b74e75832cff256dc802fb75a28e532e95dea01b842069a145c603c48ccaa1508159f21a89e3387c88a625dde0a355c6411d515c57caa3bf652588a7f484715aedb0a812028e1d00590e3a690c3d4c13557d7e27be0490cf0afb90a214a4956e1b3ecc317c51e3a043fb85de41c821a53b3bed4eb6de2a61315bdd46ffa522cb674958083b8a4194dccc07720efceec93c73f87da2b22e5ac0861bb618065ce1abdcbff9ad8a8a49038965888cb5c420d330e81987ca8d3e7374c165c456d772fba10132849af596f00741e47455403695a37b984b943d36575dad22fa9cdd4a03808776604b1ae64dbb538ebbcc1e3ab07223fb2c87597d1a66ebc52f9ab5444ceb7e1720df60e04f2ae6543bb64ec6b13282abdc003c845735facabd4394bb5c9745c4691ed2500b30ff6b64dd07b1e7e9a4b80d0a52d1789e8332014fdef6866eed806218d0caec8a9ae6eca0ac134ad8b6f53a23883d722619c057c20d69e05020cac447e2ff32a7849a9811ca372a30ce566ef795ac7c13520590df9c63412d5fb3471ca3defe18344e99f6eebd16777e92b7e7403076625768be9851d5a4d858181c0a8dff246646fe034ae156044f61c215d91896f34fa0a7cdc82aa53bc43a540e8997ac72ad00055dd4c5f1783f8b33cfea4740e3ec4512b00c5cc4c3527aa89f92b358c797f11c7d294b21d94b1f7060e5fc318ee15e12eea1492c82cc541cdd469a4709d76442b85458ce0f89e92a0c9c422061c10ec6297aca9165f99e6560865503cb332b740fcc346cb0ed0d426ed393f089c2aa50f1f3c59a0f543889a1d7b966759c25b3b75084bd4584239096eb551e66d4c207e664ae946c63152e90a5d473f5ac7529842f3867c8f96a8dcbc6a6a4088470beb090a572230d765cebfde684d9ab5cde541a1f1695bd450f02d5928f12b9552987c282f83c12d2c686d1aa5266fd0e1324f97c2c43566f50ce0ca8c3178d5d8ec1f2fb93c0bc811aba529f28277d5440195749e24097c487bbd29598dd548de8eaeb9aae3cf5ae134cfc053227a8482dd458dde3d3aeb24e395ddfdbf25949a4f21128769b747f457a9bdc2a92fcd859e6130f515d0bcf7d568638651ed8eb9f4f2e550c67c05f0dab80bf963e48e9eb2259481031568ccf4f5a86c32f31eda920138bbce589bcd6fb9591ec1eaaa13773f1c5aa72a3ca462a953e453d3fa975ec926aa9e69dafa20481caf58e076142ce9bbdda21795d4c6af5b54c64e8be275628995d0e301a738a42eaf759da06dbf851e3917baf202bcb7a1cece07c26f4e095094330e74d722c988c0392ba0e974e8bad17146eca46a5c3c7ef374073d20abf434f1fd175179b3d215d285fc1b409f4e5b5546b533a96a43abc73232ab9ae4c768d0a94e350d8ad3bc049b74911cec4cfaf426d8f4a6b9593d6b3e1876bc6544acc2aae2ab486b04ac4be28e2ec90ad56abc14b32601b425d1235551c5abc89322cf105857891da5042b32e8ed1a84006515ad223f4552dc9d5a68f2ef58c8865982b785a0a391694502bad0180bcff3f5ed4e54912211a8a4eeabad881efd6d271622720452d4fdba4c4c47ecf4fc746a892745c0b07cdc515e4709ba2d173226a65124d2dc8f8d5c6d93c418468be4fb60e1d8a64cec678a4b56de075688ca042ee70cc4ac5187cd72e91aae0548f22d6a0af4fbc5a58ca001c9bb546ffc271d2a66cb3e80f328f04d77e47c9ad09550b28025132705751b4a1781358fd24c28588b38d9630ebd0e6569d76d699da2600bf81e4f25cf5e8a1d1b865b3abcbd724a859bccce97ec170241db9f128b97fdc7359f3cdebdebe2750b5b67d827d263016970aae77133b3505616d3af60ea72a97d04413f2536d231612eb7837c97aa3a62319e04ee8eb6d938dd347a283fc0f4341626a63c71c2d03ca6b05022d17ba16a7acf298365f07ba6d071da7f9ea1b267a7026026c84e553bb0c271fb3dfebbe13877e789ba81dd7211724c12f665ab005e97876b54162a23a2d3dee0d2f6fca6030a73da1aefae2e1da3a4d057ada5ec7c82eb322b061e240ada2aa42b92f167cb5bfb550af0b02aaeb832023bd921a52b8649922ac94c664d7f9483b813de1a4fda0fc0bf94d257d778bb10879eb38eba2d217ca42c4450c5b298b8fc7fc07b9a1f7fb157a5add4ab12da56757ee9242e67c404e29dce7326c7d59bda7a780961039fcd3e6bafdb44faffb2bca79d808d84c01a8ddd2992405c470ae98c2cd1cda0694d0e66eb8b8a2d05f08658f1f31a1822db29f861890620cd7671aeb115253a30ba6ca9fbb549b1ab43105a55d59c4aaf3a4e2c4e2d8b93c9ca2b79ce84060092eec4d461a9bb5d2eee4c87916817b050cb1af9c593560a55e3e899217cc3eee82cc4bf6a2f7e982a659adcca130c1a0fc303c57799a869168d069f819f4ef5bcad42a12068d0714411d191c6397deac0536d4ec7bf86529b36877bb41aea33d3e650fb38da7010bac97c6d794498141f4b587e02718497890a7b788b24b4f3d86a3989bfb419c85f5c8dbaac9d5c98975e33c4b8647ca89d47b093d083202af02279dbf713c2d82285e4c0edbfab24a4d145deb5015fbc7134ad0cf5a08b0687a5b434c9740d1936e4c00143071b3464e070c3060d1c6ad0b081430d1b3470b84143860e1b6a60c83ab4b9118a981231288f32fd58cdda9345bff7932365b44269bcf3d7407a7def657cd0b456772d70ec537a1010a964817f7f5e44b56aa1dbbfa0cde82e1731d73afebe2949a76693bd2645e377a5e841b04c83d448fe650157c048a1df6beee2628383d8c08b2e81bd734ab31551eb30058d581912ad09a4332ae4d14d4211fbe73b1d2699418f72818b123a00cd542f4e9852bcb831e00aa3051b27cbb4526b12beead53b793715cc781951b46d29d6d2cc1954582cb33b45bf735e2969dec600d2eb998eeaff590e7d32faf8d3c2d9a67358a48a70112b205ad62ca3716664c5fe21c6238a510ca651e0a915020667464cabd8093c54628843287e85cf68577a2e86e92f8d6d20f367ac2774ba047f9fe6efc0821e7f830d8ace153e36c627e9fcf3dd92785ce87466f094c80f169d7803673d51f7d2151ab2e3a8d398d6a622b97ae69aeb05ce48a7ec22b5916fc5db7149211df96e58d5c6f5f10d5a4c0faa1154004953814bc0162f9884215529bb838aba1b44546d96713f2495ddd222da26bda1ad896c970f9462c5080d57d46847fbd17281cf0f36fb1d251a05d0de33b4732424362510f1a4342ce6ff9c68dd314a65d44ac078ab87d10ad5607ff215c156eac01ab145b3f8063457b8841f91083cdcd46f2c023bd34540e859be1534b33d462f89d6b4315e86c224e290887630e9889d1dff65bf73d2cd6012edec237fdda5dd9a5fffbb750fc238973cb2c1edf262898e4017902fe0c2090c8cf9bb49ee22641e99433f351d1421d79fdd1b098fe295f17a5f8fb6e8f4aacd926935eb587f7c83c3595c71c94014086248128046fd7116e6d7dafd27e00336ad5706bcfa2533c5ac97f0b9123d08fd4e43910de6ca089834c6fcda72597b89054b0e5cb347abf6290e5f5860a19ea0a9c1a92168d18265cce1e997e7e13b9e00994f1bb975e468fbe702af435c4d3710354354abb46347362481b8c6b7b5ce292753bd5a359a5653df42602688b3ec99e4f5e72f24f1a0503dfcf5976947665989e812908cb6efc495feb1efaf19736ac9add1a2e19ddf8f36e9f8a0e5f7a73747fe878f29722c5f86094b8852050d2f1ba7ad25dcc9f74a958d7f89c6c6f88fbcb669830013dfcdfd895abe2f4ba9b5880a062cfbd6a94276eb2be64d81afb86e7136be0301aecc52502d57c97d68a1c7dbd76320ec41c80d3b241b77b59c417f190b31b6b72ce54b117f1828b825564252573f39a3f28c54b62e41ae1e652980f40a6af99f0531f6cbdab57c7e6bbf96fbeeeca596beb14d8f15731d84e257422458be2c2434c06e56fcb52e8b1e19804bb72119570afc29deac2ee074a4de71a37e1be7272e8243ab141e5e820249a5652319d00aa90ac99bd1ce15157589027cec452182650419ce5c2b99e01f6b604fcc09458a6f2a986c8d32ad69b3c45833e275826e5d389d2c250769a2bfa9cc1e4a8cad40826a5aa59020c6a9110d862eb78c670abf16eda5c971bda714a81f922b29fa8a24cb73a0be27fb12cc5442f8f516c9d3bcc91b73568f2e87ed7e5506b18c1800e6fe58eae1de022e564d9cbe25d3adfa6755a683a9219f20865014c35bae6bed2451a990cb7de2f2816ebc7477f6d2785677d552dc922aff84591631d36cf120ca245cc1ff11d81ed6d57d8ac487c78fba5096663c80ba7f7d5a3d8c6235e839b94e76c3e6062aa0d73a27bfd5df44e7f7d08d4ab587c193e74e720347af5a571fd10f024d364a48115413c25206283e5ef377855a20cf8ffa01aa0882a01853e019c5f663a3c5029dded948848398db60acf9f02fca6696788609ad96df0cee43e5c96f0a52f2b8314353240a7b09d400602b04d3f06e868155f357ee0f058b43e732632d20053d418ca2084b8433e2704e9201162be0f3517e2365e3084ca47b631ce0ef3e8e48f1da8370875c1355a3a20a798772ac908cda1a3ea5c2fa6e92ee67c9bbb616e1801ba5e9527ee396fd9fca12613f08679d42a2562e20d2843173b34d2b318e440639f6c3edfa052d01d148428430ea7fab8ca5218ae94995505364a0a00bbae083234e7954f5a64c634e4904bccbd6e449797659bdb49ffb184d076357252fff6154158deaf4ebc55de270543d1dd1257432404efc3b1aacb4bfb10c97d7406a83377658d28911c6c4f6f6af48fd87168ecc0616ed3a3cd1f1d42e9b9ad88ea7f88a8b0e489ac640b2c8977770b059174c733b4a9a316f3a576283ce6b398ddb1280032cb3b4a9d6362adcce6188b438cf079eee93fd0a460aef8ca7489d6f8d5874017a7e11fe9b250ad3044b1392b085d37468c4d418640781e57ad6a442611c3bfc28580ad6540a3676e4b4efbf7cef78b43a33ac5653bc638701f3f9215424c63ec800a5074f46840efdc0d5226a0920cb9eccef87426993b8818402379bf12ae1982d0cbcf45020e9a5a42a5c358e48c4ebc141991538201b73519510114729863c3554cb28719d9202564f2a2cee0ae17167c2d8ab0097294bce0fdb75f429367863c74af7da8e6607a7c03d36d2e561728f42143b345b969c655b906464cfee6c9c4dd9849dc51d05ca2c037b529796e2fcf7f5641f37a90651f11b84c3f930f3f80355d1b4e436c520fa85d19785b247c5615b268f51e593f504ffc21f40b1e8fa5dfa1086b267335a09cf42ae367ceddca88252a096085b5800e2b453d295d8905d4da9b52fc51456ae336df35a8e821df14eb32ab9bc6917a712c8ff809d235b4ec9b5d4a5a075728620ef57aa91e0f1a9dd2ef656fb6b6af300b7c3543ef24cd59d6b7d1478ee64d1a62f60740aa5c534f6caffdc0041ed2e71aae5a32e4dace2c87e3128114549912bf9ac4a1d775643cdd2d8509882a304796966aa78958ba106235e62c4715fd6eb6706301d5495b7eb2315b4144723c79982637098a77c96da21602b100c1b99b3fb804f07224beab1847fd36f32b30e9f8b08f3d9d80549fe2218dda3000e2d0c21e0cfab100b33bc01befa6d989a43382608d89c6e0069b61647eb985ef738848e5ad928bf750cf7016d06fdcd6aaa2816f3c5a29fd519ab31e8640e673c9982070b4957e33c7db1376334db16e1fd08b3396afda5e337c8c60a9634b38c58de06451b997fbbb6b93c6864b42869578abf27ba01f27a274515dea6f59dbbe441cfaffe91f2ed41c64de69a9cb46364a0fe58e033919376445fa500640999ace6e3d2bd0f290aec7cc949ba7b881a0a15e44c080f77463c226b8652e49ebeb9654a062ab05ad2e7577a7cc259bacef5ca5439730415bab336f4853558b293b3fbc8bd7c43b7109f20af3abaebd2d0da45779972e397ba5b0ca9bfec7ebee0b0fb0c5e438033695e4f690029c24d041f9101a3c3dcb5feb02b9ecc015c4b13ad71dae63b5614bf69ee61b2950ef1dbe0f20ba6ce7588880a0339d38fcc3d449e319249ccc7de2f4df4d0a3831817a28ad6526a9bebdc44e6e8bebef8661fc22484e51d91bb2385ac528c192ce356c43774b44acace77e6f62564ff3b15b9150b9cde87c36c00ceb45805ccfda320b72668ab4597088efdc87bb7baf4aa71947cab0846bee4614f749e1f6c220e5b6a68a7c9747b5451af74f7ce8838f025023c48cd13697e65122fbe04bed5473e06007904745ba317ec05e64cba5086284ac3faf458ac89ae41fd9482f636821b4f3082b053eba39e0a6d216acaececd6bfff041dd5826d16ee3919b9a1fb026b51b7cb25f6e234449c013da48c34b48ac55911d10c1a3b9a7c0b581252ea99629a7ff9e4cc60be2f80871c063da2b57a12631e5cb40e943aff0da999f489205fc780e60c8f9724bd21ec1a22aec7df6b508c01087af63c870496302bbaed39a1aa7a09451a168c0bcaf557e37671849afa1a36cc6589490f03300d8f0c7b185033be874193edfc193cbdc95107bb7d6d9b5ba7a4ccea7aeaa17a295551efecb4e32f7a30cee0b9dc1a3b2dfa68b7c685dfaad4b2f078a377c0faf55c553895b4c57a136f55321f414f974fead2560b2c312baa116baaa61484a4856483ce23bdcf2a91eab801dece8d4330f55e17b5d43ab85863809b841817188c24f6527c6218c0ac7d548b34c9337a7671f7f796d1f57ebf0b1d0fada7f19b4c5c59507c8dfbf83ca65eea33224e40630da157b42dd1b565c3f962489f276a5a41c46f931c8ceb984098d46457425a68c5cd05219d4a78088ea6fefcfb6defab221a89b3a8f6a48918d5aad851f9846cb9eb7b1d31f4159cb7bb13511e1173d503adc6a8e13f02c2aaf72015c6c864398db807c928eda12f9de887b75a58a543ee438cb6448ab7bfcf75534219ab6a6140c937e4142aa6ec0000e27ce8eba6ec38fefec92fa7dfbb7b8d0b43939e9e7bc51eed9e06496e1546c5bc7527946884b42468132e2e90fcf614faec5200168d0c6ddd75714389963b150174d19f6caf2e67bda707530ea86c9b10e39ed9e908b68e7c1b84465a1f82e65fb106be0a6b4898a83ad93a11510c6c73b0708c319281a9b0afbd16f47841883698494a79df141c9f2e81af1e5b42f2f37b5d5c1053812bac735d7598b486294aeee1cbf11d38a2dda30f37f8c0706db52ff71e02c9f3ce603164fbd8d6f0076b34a88df94b2ffc1e4244509b69ab6cec3ed8bdc8367c0171bcddc204dcedb7ad510c7a346abe9a3e7b5fb7b73c5a34ce79c01997de386e8aa4ff521cbee15f234c4ef6acb659f0cd555eeb5d23840347aeabcdeaea36c8c0cdc705e5266e033040a1ed571d59b15815db244e20f10f3fd1db137955d32d2d238c6c1b863a28c75c7035db2720a7ee5dcc8eb07797593b3cc50144888456f7f6f6989fd06a63e6acc0d04312c7dae1c2fe62bb62b12ba9dab2b09bdece0903ecbd2e9e23983b130a5cafdfe332488bf212233daf270e0141a966922341cc87e82af4e592312cfff432ff79f17c7ef0ebdee1fe313035e9ba76f745c7093a1ef27d3f461974ae886be551f35324e70cf35ed7ca6019bd6e3a576071afbe17a3b2faaf35cc7eccc734a144cfddba1cebfe3c035184a83b0bfa13ecca3a5aac3c959d04de09b5543d7b44ecc3da164bf44c7e3369040dcc42d7e9e0735f21fabf0e37b782c75ab92b4e360f938c79f4e750bef4a697a892cd81a01765d6e8251ff03f7c488e9c25ade6ea1ea2f730ab05188a2719d0ec1e6d8338d1367350f0ff8609acc6f8fe3e672c28a823a03ec69d834942970e26dc21c8b3053787842990b038330337fa5e22ce7c596064cd3454cdc420e7e0a15b0cc2ce4524f6f94cc47a936b398947b05743f89f6baa8f4d3086aad595f48afb8f3bcbff3168b4345229e04834e308ab7d3468e60ddf6b396e7e1e68c04b4c588d2fac9d1db30772e01a02b383c3d1aca03a112f3f13c4726d895590b009d79d61ececc403cc38bd7b488a005d27b1dadea5bd1d2411039f64895534a26e13471fd4ff5fa9c3d5c817c3f304ac19a2d4f4dd58ec5bfc299db42922955d19f1bc8abbc51dd67f151bf7f37a16a59b9279f88ca18fe80bcfbf05a31abced37f3d0a80f2bca996b21f240ebf8e08f883189ca65342360ff115e20f06ff16b1049453fdfd640b6eecfba9052789ab9a500c7121cf708b77342e2a740a6458fecc34b1dc144f0a7b310c15d37348ce35dd7fadd79c976c8b675c3a88eccbe11a7a9368f15399077a81b942b481b253b7324d6db6c4057242afb5f0c37cf2f899d392a20f13bd54d4056c47df29d0559f7e4eae533a6a35a787192db66712c2d3baccb04355a6daa421988692a878d55c363e31bdbd014fa7f61a6388ff7c394366f2c19dc403e3d7d7c9169ddc36c5d6dcc4f62cb1249fd184977aa4bfc756de8248b077a39ba41dd51643b9e60f919444dbcbad87beffca7df2782fe77b56163c38305a676d9fe317724c414506e5404db15dc1381473e7ad11f8cce6819371985c72e5c6f49282007e869e3b1e5356eebab892e85782c5654c6c2fb5cd8ddb68280944d747addbd1155af1fd953e354f9314a955e7fd5cf324681d39a5b963e6fd2cd17499bc71228680ad074f08d989e63937f387b08d3048b206917159ca71d68a63ff92fc8e2d478aa65841ce48b2471b30999f2bcfba624f6ed33a2ef18550276e36323b72427c52c6cf2373a4d358e43720009d28867c2e9d7b7032a2187d053637e9dab200f0954d3458ca2425bd59cd2969015e2e22a82f0759953ce6e118c4969a2b5c83b35ecb20d92c33ffa9b394d2f425fdf669d90d13c320ed6e712e4ab670d933cc26a91dfc2709b4eb2f8e976703453a0af924240fc526277b0317365fe3d1ff568a1d58ec013c99f87e5d5ea7e26428320354723674f27e362f96c133904a89761a8c19ad5adb9b35fb10637aa5cf126eb4298bbd28ef9c7cf05d245141e14e01e9e4d05dcbb54d94c127bafbe375f96eeae7b330f9f3d45b1fc140f8b4a5dbdb1a3c6e1da5f61d1fd4f409f78f70b5361e45732e5eb2dc80726de91970be39a4c9d0a2fbf2e21b23e51c550b4ae79844ae66766c1c402ab4aa0c18246dd1dc3de0efa1be25bc66504d32dff9f01d221dfbb2f03ba3f8daccd75e42b48f92228882d63cb3fb2ddeadb3337e462b93e183d9070a1593a7c68cccb8d530b4bb1a78b9a34c40c543da2c8f35c86d1bf5f3eab0b2e9a974d310c775f6efef1f0cba103f56ffa3f8be572835a2c72fea07af1e17add8cf9e8ec52b2eb06dffc0553cac8aa65ff61fbcd06c1aa7e47443565c784125c90754f3dd1cf18b94cdd6e622ac95036d54c590133c6704c482a6895dbce5b3089a6d81e02eb1ad1a987c44c5e08e8e31cd80f80e50334f04844c1da98d8b753b6285737c54da38a1fd1278ca44d8383e62ec480501bc15306ddc9a86ef33e4fa047c5fc83034ee5a1567dd40c653397da852db80e9734df0c912784dfe516f7ad43082b84e8d653b63d35e26b01a7190e7354014fbade4935adb24ff22b487fb394cdab9f9e82d642c448ec6865d93b4c7f8462d320f04b1a72cad011029d26d7d89126582878ee6c1577de348f772b94edf9afeeb282d091c8c5dce01ba1e7c26d0b04d90ece231f78a62da17d763cb9fad152468dcc8a5ca8057cfd6ecf08e68b5b142d059bcfb2ca9347c889d0c2a20f08cccd39aeb516d79731a4f628a2284bca93875581c0d49bd5e3a7e205341ccb8679ffdac9e3474132b62d351097e5c6ab1bf6d6f4212238d4798e166aadbb6c0391f10ddd7a228eb511adf26a2567fc6202f38065459a608bce65789f01d2a14dd3d66c14d7ef4af540a1d776aabb6a864269969b6059bfcc715748da418e955d0f975e707367d79c26886391572d3ad9c6c6269d4fd72f48bfeb2cb4d0b43d8c7a4149c4931128e4e658bd4e49553f95db6e12aff278f8d4fa7adeaced202ae1cab2961f0b6605084cd816dda4ee5771c6d6957a0ed7aeacc0a95b90f95d055bcb24c0d71dd693f661ce3492fc9c73c615a67b535f57b6d505ed8dc0e8ece8ded3236800e2553b162dad06de90db3a78c37d182232f9968676868f8a4c8d4ce3c5ae628a2c86a797feaffc3f2af0fce7bf7e2980b2ad45a83ff899f713e83d6e2d5630560103fd75eab67964a65b038b1b5a74fd6952fc34065bb133dc75f82231d4810f4e91a8e2eb7b081b48effde17dc79de67b71febef134961ffb25a88614f3ae19282c20b83f9ff224cb4dfdf9f95e2a2e6ca5eeb7c6ca2a0b64fc74684af442bcf7d6874ce8d51e3f4612f9b91abfa0aae092f8bef03b0bce633f22fe90f882ba8dabc124129f3cc4fdb11a1b5c46cb88535bf1c7b991e1f596cc188d8f0219e1770f66556e3c48a4e6f8c12f3a07fe1f02a441b240261a7292f0787208c000a1b52b4a9aa85de9ac19019bb11be9e805ebdf6b967a5ef7cc20a4098711f13723ef251237f2cc6c9746d1c6241e425076a3586568e1895f94dc2961fcd88ae4908d263210073d36ba8b5f1a09e0b48b6db1565c0371068ecd40f650db9952694d301a08f1459e5c6fee5cf8eaccdb6167939f8a580939293cf2da5707ea73e572f244b1d88f6e3a31caaa9c96ac9098102432eb2e7d46a780c629c4a08cdf770f88d7390beb803d6cf033b0da60e32a6a33b87cbc88d913ec338237caf291c128c8bfb8fe18d7168d84294ebd755ff5406916ee038d8b292724b307a21dbe7f706ff6540a072d4e248e0cc123c96b9add46fa43295f359869cb7e73d3d2c5c679ee5ddba03259e2d609a3a212fe67c0feb2103f38be9d89ee7c99693081b29366056a132d63fa515829af32e196fd87b44988764c385968093d0813132235e1e5f8aa86713a79542427764e3540f31d9bacd8bb8b76764585a7bf1ca8971ac16825bca58316130e6f9fd5f25c09064fc30b09e1c9c2b25fbec4c0a57cfedf96c787dc9e0ea52527fd6c0af59c08cdd7d907cfcd55eb67876f51af37334d1b224f2242fadc87cdeed24513e5cd15734063b5440d85a7ad23d95d796373b5d81b00aa3bc021fd3871b906880db6828bde9dd5dd92711e94f0a427010be8d4ee56029454efef13f10667ea918a102585e4ffd80cc338151574e7f2081c33efa3cd185a0b0f97006ad0db631095694988dd621ca0038a9a8c9de47ccbee50d7997ecd50104732e8b63079a2cdfab5031ebef3ccc3914d7011f0a0594cd3d605f30af7a7b17232bb765d3244edb89b128679f4e34458814d38348e2a20fecaedec04d6618788ad74026252015dadc450a205ebcd908a682b1f9dc9cab64ee33aa11cc0ffa8137a351be2dd01989a46b3ae2ef197e8cbaf3bb7de29d700bc28b817da80d55299afff36d909c9e93ddd41b10f2e543bbca872f8624d1c9a3737119b09199575f5413732e8db876346c1c5e6705deec4f4671a4816435588a3d5b54a947327c29425d099a88ac456836ca73f1c3f8fe58cc74493805f0ec531f6610d8c5d86d8b7cb14ca40880ace9779186ac533fd4ce3bab963c079c63c9cd338ec71f1e160676f98af699b52fa690639b7ceea417a192346d602029234eaa6784cbb7fbe9b6a0baaff6bcf3e2369e107a7e0a515f01caa0117867a4c1db38db9e4373918e1e5dbec4c38eab67ca8d1f7945e9d60c5b67caa2ac5045bff230442db1a9c81867ba219b5853c545556a9ab6a01c53cb7804ce54968aab6ac6483879d46513cfda1302c647f79126cbcb85d000252cf65dd4e0a915f7962e8a910bd1b4b880bfba697e3f792dee898120a5f6775e9fe581059f7ca6289031f2d62d4d89fa6b817c62e43ee11f4354834ae68d5dbb7e665851e0aad8712dbea68453da6bacf47ff38e56be3c74cd6a6753ae78d75207bf72d50856a44e356614034c8b7d587da0d7e82d34dbb39b927a782593fb7f6ae93b30fc6f59ac31a69498cab5fbe9c5d04a4febf95c6ba0675c852ef2ab6e2b5051da2caeaaa70cecaab4a9c62f1b81b9f7ebd354f02c690053baccb15d92fd3636375eea5ab4e99b013766834270b5effedc84b220639caf9f513e9a3ab8dd640d1f9e93db2ba44e02f33e7cd93b43bf9efeaf647148b6fe9973276f6e249501502769c4cca0025f6496b19dcf4fb0b0ba57742cf0f01630bc436c3c2236d01deab9ab29f834962ead8d7a4a19ee28b1208770c892b0878e753f8084fd125ba7e1672d936eb7a29ac7a6cf3e1c82836777cdd74cb915ac0fd125a143b7bef75fa2cf35474951c1ee9115a10d564c8752befd19421e138315003afaef9a92381aa3f73bfec854516fd311ee25fbc20f3b448c0562c16f9cd291534713ded166a0b688d83f11c19be1ea558b828fa511ca5dc9f59c5f2d025cae5afdfb99ad5ef54fb3c56bad6fae04c7dccd09a7f2834e3b7745ee6675c9ddf2b4a2b05d4cc6801ef000f6882c0ede2676a3cc036c3fad94c53419de784a5ca3e1dc11ddb7628bbf3dc24491f2f26d22bc262f4e5c4b008e4f28dc985c5299abc0e2f6ca2d0b0c1dbb1a4ba9c7680e6fd540a43c1ab20b94d3687e32d317f10a372be9950146e5fde19bdcd16bb31155d428264859e55efee77edbf59fa87a52e63bc7e738af4f167e22b7d3ddd25180cf579249166019326c6bd3cb5485c1ada50d0e0e4b381356c45fcf8e18eda90971d4e79051d6cb79b2a7175aa9eda1283db7349d3027720614558f0ae72db9cacecf1ba3901da224a166b8c6f984bcef8c8312adab7f35cb5f329429d1e38bedd4735203b9a82473394596875bb75d0df7b0fee2309f72793d46fab4627b7b0535e7fead3b37cf71fa81321a4f3d6bd74f7052b5cfe14af5956a80b3af23f1b5203dc8eec32b85f8750eedf01fb4ded9c6fb2c6b5bc8b8ceb5f49823c40d92b1830f61d9bc1f473325d8374b6b270da10419dcd10861847253a5a38b9199976788b8e06d1b8b585914ef37e334ddbea05e2b77334dca464a280af1ae31a3a55293ad7cb5dd90a1b02851817c32f2a595d5af0dd68d277cb82d0927901e53e196297a6b9c037efa9c7986d1aafcb166525fb94aec0cd3e80b9d5034d873482d64e78ffcc84b53e02a809231b168746067d862c99f41ef2518de479b442a21814bff60d9d49d56bea6cef6ce95704496f7689d29e56e61ab7c38f1ea020577d7c95cfcb2f3206b05839dc194b53a9f6227d4608835a27171cae57b0f84869ba5351e53b0940ea5de66308a12c4e3d949e2b390f1a664ceba555f0630d6d4cea585d6d7e294359287985d0db717391ad76e3df68fa09f71e0b54f1643ebead915956c160c22649592d0675927cb0b3b975ffa86a709081df45d16c274d47ebb6309a41e5b0a880a14d72cb688e534cc8a0f42db33bcf83b7be99df28cca1bf077921f601a184b42a52a37aad4c8979c2f3293c463a1f32b4c8da71d6b064dfd71f4659cf7472bbf5c4579625674ed51218028f9aea2abc2ed7a5ae9cbd33139ea4b8912ff640cce7b3f59c276df3c88d7d8be4d59c3ff38ce8ce7fa31c74647988bf276cc4ad465f0f2828bc89663f2e7286ce34c2974d30eb9751c9233374e92ae76a2014dcb1eab293b8c8566554bd9ef812feb126c7241749f194fad7b6b3a0dd75df534c89ab51d1ce2a81aedce2c82671d48f16c2e204abb10840da053bdf2e0cd069851166d42188829f9205b7ddc109d179e4fc463ad5da7a1087044aba25fdc73715f41a12c13039ff7712320cb93fd460255cd1418851c5110abeb2e56c38c9adc0f9d570a656c2d3f403260b696264599a19ec234ff5eed3249f89b485cdbb9cde35842c4c0d365f2559f6a62e13fabd8943ad4bfd062f73761cee515770cc238f3a83012bf9405b26abca1fc22015891ae141662de2a6d334b9e3e06c28442ceafd13f2eb7b598ee06eedfeb2593e154ae00e0eb8ad10a3f1c6531668f0f7fbcd1d7ae0812e31eaf0198976c2667c6cb7f8096c29da99a718df07b37e86dab16af4baa39b58c8e3c20dd54ee8a4edc9371ece6a3b81be366d547c39102aa81fc9481190c3a72e1ef1fe000cdd0d9c573c49eb8bd863f65afa6174a0ff57935b3d4ac50425418af48e3ec1c2df998df9f3b421676cf63554840e301125cf42fd0b22a769dfb7868b739537723b8f86ce8ba3d531554a78c869d21db89e5d5e922d6bc418400db931cf57e0038fa738f443c68d0618947bf74a3445e0f8d476d9db2c2d3ad58368648a725139b861c6a17f1c52b0fe2dbb36c0f134e4dd4885e7f7b70f5048fa93fcdf99d38f4c4cd67aefd1729d59d9b1c35df793bcf29e176105331bd8f48fd16eeba6089969ce7163f66090d0e6883a68aac1c09dc70f907232e694b6d8971e22299df6355eee76357228da3525f0a8125d8047c1c6dcc1882e4bac948b9ed041f35dc706809ec6b1d4fe8723107580ee39846af61d0743bad6d0013f79456e8a0456880b4faa99dc96f1160ed80c8983944c1c85e609d20e585cff84afecfa6c348673afb7c1c1e230d05db8d0ea9939bb66d8f590ee2bd581592a564b3258a1d0edbfd7ef2bdf5fefdd89ec6ed16d9ff1af160f9b0cf48c5b61d5fb6e88b1b6264d67c2e58ed38139a5896e0e43d29ddf436d77f51782b68cfbafcbfa941d09ca15909171a3d18aeb0b437515e8509fa50200e010f604dff297da946042c5a11ba7e28ee101dd3d8cbf80f3578e381434806075e457f836d346b24c6f0f929e90264d213e5f435b3bc242ea4667093f97f0e1654481b8c3f5d2e7412168968426ebe4ab9cc3d5c6ed09c5122a3f541c6f42222617a5a238fd1e565b1f9eaf5424e6586e2a887b37767e2862215bd852486d4c796784381417052e84c09a9bb9a8d48787663869e15017beb470a80a474a3854852b255caac291123e75e1490b87ba70a5844755f852c2a36e029cf80d4b4323f0eb6b4f386a85c24207100e8c581afc692f3445b9d1d475fb96ccf46543c700107f7365bb3e1782fd17fa15229412414029ee3274b45231792151a099d96fcc0fab001a13e0c9f4cf03ce189d43d26c111a00cc68a9fd26575c569533fa4c6f95af3b6d7a81146655f40e341f7aa51f9174652747f30294bec5b22955dc8be4e71848eb6963642d8b3e0d49eab6cd1e7e47df7cd43658cee935ee12253e9b3d08dd11455a62ee2b8379320ce5b1c9a931d70dde220974ea771efa8f26703bce46b01569b0fef5854593d5444dd4c4fc45ca2b4c83dd3d6b31b7990aeecf3b8ea28eda5bbeeba4726d5381540f3b96f1d7ba71bb840f64d7d9bafe71020a232b5d06e45002d77d2e80b384c5868d23618a6b2b6624f829322e874c87eee564bd41d198ae5d93f18b8a9d892446e739926ee067096c9fbe566f5227993e0d61389181f12a936014ad9b42236a7721cc8371b585700eea18d16cf0b6149b7a2e922926882ccacf2a2afa096563715d3cfca31d9aff49b8cabb72c4a1cf0efa820cd4bc19f85c782c5fb6e45f9cf1bafd9f3366427160822394487b70a2397c82987e2fddb4f2ae6fbd27a991d4e35c03f13c5a52bd78181c1bec843741ed14a16b3887f2fe541cd59da844915bfe5c2355750c7095e2a4e964542fa7fc94f59d581652fc8a7f264e2444c3a21600ce6b3cd1f122d3491f1374ef1a415f7a237b992fcacbdf8d6611fbb36011fcc105cac619e1c07396525b4befa466477de3fe4bed8fe68b40389b312c0775fbf8252a9dd5f53d9e726d5b2466d3800e5cbca2d1e7582a6c9c66d7eccd643207b17285c41f3955ec1b1da52ff2809a582c3385d01c6f9ee4a4e844f223dab60bd1e03d06a82105775f467c137a9f11cc0848fe91c90f78028fb9ddc16584229c75f5e5ebbe75edacfb1a9fce2340d0dc58e184cca6a15a9f89bbdd869c6679ca9a7a877eab8b09cca99a9d142f143700eca6243a776e34217437eb3450c810cdd6658ddae97fa5efaec3f5a0c30a615dbc62586daa1809529993a344ec788d934bca7cc132d5413b4b8273815ef374ce34aa670c71093ae7e099e19861671a98e23ca1da097acb526e9dc53b2ce738798697a167689614648da8dd847bd00ab37bcab6cd1544a6e2e1e9a414d77d4186e79705c71b2a4953f07349cf840af366c9cee48a429fba8f25b827ef23a4264a8f980df1a8ffec828535cd9ccc57a31554899d65332e16744ae25ecc18ec2fea1192281acf8f9b2e74a6674281e6193a2ef1117187f9478a33e1ebd22737d1bc6cb1f738e2b6da2d4438f3a7c5c8e67e4c6b1ec900d6f970165118e6c200628fe2f87f57e7c2f97d3681c1cf1e5b6ed75968ce3ad9edec0153dbf903b917c6f3dd1aeff81c77fefc04e3ab8ecc4863fdc82fa2cb82b5688290d81326ef716bced01d318a4f83498dcac0063561ddb963e4d0fe9394e69c8e283212c2b55251fb0609d10848e528562c9b87aaa2b71700db64bd09c54b1e4c6afc560cc3dcef764724bd0cd294bc5d5fce31926330900994000b7bb10c9c5819b4e414f233687b4d2dec4c0197872e99e9a420a5030fb5abbca72d368c476b0ab8c7cc3a55d54f2b333ee56d90780f6415227b0860b760c9ce60c61daefe6461b7b70b74f10add57c5183868f4b60f4b2f31bfb31cfdcff64cb0672a651fac98b0bbbd369b6a309289a3d354968dbb76a3a35bbe9ddfae82a21fd12db76e24a16ad24aeabb24f163caf5f4eddda9002e24ec3f505a18dc474a22a66028998c257715697ab78c97aa5cad70beaa715b271daa7fdb6fb7b4aa8363dd0ad7549f9456162dda5ac8f96aed8f925f2c9a8c4a27c10ef7ddc0c58397783f45575bb664e5f4dbfc7690a42d596764e985e4d580c0326ba7d1b5573c9069bbaca4611da989f96660ba00085522fdfe597c8a3ed124b65f1f535edabb99834e13547a25531ecfd08591847bf5e69519617b3f8ec344bf5fc13508984864ab95e634d81712a00cfdfdb41a27684440592f3b7b6841ce47047be9a0441564aabfff07811a6b281511b5d13713ee2019df77a3cf7473a9141077f0c9e110833253909e76dc5094b522c384a767eac9d2090fd6d48248078532efa0b01c49a6757385c0b0981de33e304927c34f5da2aeab3c78ac6b6ca59f950ff1aa068da4d1b17e37030ab2c9414fa2a4d8313bd89016734b489b48f0465fab75f4295e613f072d58d364a34d0610a1622ee25e40e85161168de6112a61f4d8d5c69d11c1a06d9ef21a54805e0df03603b38cd450dfbee60cdb3f1a5cbf4d4ee6c1548a92a3cb2e0b364292dde6051bebcec7b50ea7a339e21fa344ff54b125959062501b3a0caa534c2b35edea28e7e3a836c016fcd75d3927971d1bdb540d334e01332b9d8e0ba57ef9108aaf8d9caf196f2ec31349b50159069a15de9f165fa74237c8a68798913966c2bf35a1f8c8b951391d8846f56ec66bd087fd0d47d8aea174ed55c689accf593c0e19d6a57ea60e6723a74cc4af3f92b4c51590a8447a05c271149db0c20e22fd9598611d70fef8337821bd1bae8e184eb139936ad4fe295bfef5434bb9c1d77793270d67e295dd376aa6265b834e5eb7389bb4fcb7e3ad2b73c3c0d467a3ac86cf3fc3d7d0b0ff829d1f916c666bb6525c9ab2479c03940a8d4c5d11fe35008a40493740050fa9c1e103f59a1d1876c714576b0d9e325895abd6c16fba1c3448013f1d8144c5b730c42ade7ca7ad16210688f22d88bbf8ef4f40fb926cc7457a795cb7eb7109300550f7bea94c0354427fb4669b03aa925803bc92d4f54687ac01403d5e49dc05de362057048babe1d30ea014255ea0f0e738432d805933192d17b59dc1466b1ef1aea14b8dee76e32503a923a2fd07d6e0c3fc5c5ce1e657b76cc17ac2a0651b93f7b70bc5470cc5ab350b5f562900ff0074209d0e28351c042d81e87214cb5d1c0394d1034aae72895c3052b29a0ea5f16852a53ac96d48aaf458324b0b1aa515d5e8d1644661a93f04bfad4661c4394587d40632804c7db7331e020000c41de60883e543ee7412d4be2f7d6abe68e1d38f3fc8eb898e0d953631696def6e5bee2da54c32052f086908ca081d8c0a46a55a7974b6a66cb2a1c7c55bfeab998c3773d17321333c227f094999199aa1d2746688a6e0835b7f9c11a293869ec7853c31fbd122343bb8334213d64e67846684fc353f945d1a3e71e9cf34eba6891e86bac6b19170a6f9eb0af0ef4ad38e64b8e05ddd1b012c82b081952a9cf0f112d392b2f617d45ef457e719d8306e90e2879ea32f68082336af6469c20626bee4f14aa5147539b55a467fc73cf1e1e606d88dcb87036c1d8e3f16c9f26db86d1b4f9645793a113367c22412d7a43fedcfef518f038677b63cfc1de6accbd3e9743adda7dac693378dce39e54febb389ce46082ab83308ea3bdb7efa3f61a9bf4f71c0d9a228fcf3c33da5920374ae587beb96e338cfc39ee78df2ede93b9edc85520593a394cafaeda207baaef139e50136ffd3cb203cd9bf1d3ab2299fbe7b9e2cc3f1c722d925b53cd9432535dbfa320c47253ea95333e82cd7ef388dd2a159346da556638910c67045f88e45c41521ac12f314c73cfd98ef2f084f8ef998a7e1f44e1ef557fb4b7a545c3cc9a7396ee910b54f433ae462b56f3195dccb900e512a9e8286dd8f09ef50c574686ca61d17ebc3e0e2fca0229da3334c762be66b7357627e5ce5981ffdc84527dab88ff91ac27b0ac0af6e91b84c3814994bae32b43a403ec7e098af7131e6650ff994c76b5c5b5ce322d7929ba86e1c31d98942b7e262fd11c6b827a69f18dc75be7bcb89aa30d74526b986f021fc30f1d77c1898ee0541a6ea8d7a7905f5d25f2719f3527e07c213912b685fbf019d837e7d07f4ebf455841f2dec7fbc3954dff2557f0a678bf2b5d086f23f7c11421913d63f85de10b7b3e534db594f7e3deccbe7a89c8886864627724ff22b7ee45abc737415e2623542451bca7568dbf2a1529b081bca65ccfb15191627a24642f824326f3288bf6c96258e320a8a53a15c69d06cd5efa0118eb8346cfc7ca7434314f65feb53246ac55f1f965c51f54aae5aead2213a44a9f4f0231e7df04727b24ff1128b83b818026e1743f88d09e66870b9f8abcb8489f0633351fa33612e74aaff21edf9e8c7437b8e06d7881017eb2b913988110ac5c5a009732194d775524dfb2517eb8b104e2fdeaa4339e6c766722c2ef32b2ed677a11ac2098f36e74c0dcf2f4f5cf9344fe367de893a87a4d962b3cc95f96e1891cf7110c21d196a9f1359228a6170b17e8db7e148c8972da05efe24f2d7f7f5dd8a17758e06827ab944668a47efb97c6b84ab708a083f13d20865c224d28b0989926c442a0cbed5fa983011707b8b7ea55dabcb86dff0a1db280c9daf7da7751c0e6ed17d19caa2f9d45fac8979ccbf7f310f9e3c8bfcb55d915a340ce4e2c3c85a19417832ddb64f851d526beffc8eba8864c2643ee6bdeef432a1ecd6fc55b8d556c1f810f817548514e62668ca84a6cbc5ed4fa71accf942d775322be5f9f7bb6d3b55cac5e8886aa15b2897941116190a25efc54b649640fe1ab797402e6aaf6d7894f9be7ced99d892e7abbeb3b6f354a16b6aff20a8ed18218cebfde83f4ee5e62e132683fc67c2625e7b6f22c55fdb7dd56b4059fbe94259d33e26dce42ce8843f1c94c230780473d7b309fb92b7f7e9c2a43661cadadf2f084fbeaf62bab85d4c1da9c92c1d99617e09cdf3755279aabe880a2f9119068f92c7c546247ec145ed95c8acfdc75971b71f21e976288f66cdbe869ab4f69cdbc3f8f86bfbe6c40ff0cf869e85417d675942298fb2887ed1161916d9246baf21f1b44e6be2afd4172691a0a7755a91d7a42e8a9f87d082eebbbe7de2de47e7f0dce5ee61f0d7fcee7f74df7dd775636b91bb2fb693e11257722be5cea20452eee467bdc850baa84bad35cd5a4c975cec3c17bb6f0bd35994b892479caf38feeac01c1f1d9841f99d676fd364f92c22ba771f2e76b65bf2b5203cf983f84bc3f47df8cb7ed7fdaa6b3a0d89ae25703b4b1256b28ddc59920872dab00b936d38101172c77e84a24b5d941c0753a386ece10454be00033593f96bfbf974896271a4a3242db32d79725db24f2ce38ca6b5f782366e6d9d4960c9f3df4952d6bc2d3f5a9926b9c87dd93826cd880423eec819811c53c51c1314d989cb0f15a4ce4bd0156fe63374d4391cd5a473f80849dcf9a8a2d9f2b7f4cbf50199e426b9dfc8c8c8a8685a7b2f088ea8a22d4ebd50254ab9647feeebf139a9bec5b5bef69d731cf3f0dc54964750725efcd59c1109439763f2d7882ae2e2af11ece2af9133cafe1abd2df228cffcd5a08e223e434772a949916fe991623495803a8795cee1aece31abb5f782e0ff28725f5cf44702ef19297065f4097804a54b937cb20a325cba04724cb3e5ff43a0d00d02adbd1704ff93b27f47e337ab3c821af8155f8fbbe2b296d0bcbd4e2a6f98a905fa1b5e32ab91d996633a49a14bfef24959409c037962d48c86930a257f4b927ec9f2a91787cda2252879164dd887c55bfef4cb94f94c232679b4481329d72679b44833492927a1934bb648935a248b346176ce26ac63e08b364ffcc946f0e2dab0ade589db628c5258c7a40879ce74deba357fb638e777a8820c52d2d9dfd28682ae6b58dacfe789d1d05f7e95a93dcbdaadd65a6badb5d64debfa3d6466b9e04f7f883fc53b55b43fe11dfafe1a1e229fc33bf3e5fb966ecab26cead559fe36bc8683ee345cc6555ec47dc75fabf7f692dd3dffbcb1340dcd3b0831ef337ab364e111741b78b435f078f10882781465f0e852e1114726e5f5998747b0c3e38b9c9442ddd3cfc2a3edb781c7db5f038f603f88c7ef9fc1a3d84fa3a75fa627cb5f853b2ef6c7842e9bb309d3d1dd7fb12ccb0f8fe0f8a378c2a3ab9fc3234e082108218d9cb5eca6339ab03f97b1dc93d2d16e1cf4850994e9bf30619c73d1b0493d8c32a60c4c94e21f7b890bb79fd99a9a509e3f81ea17c159dc712bcad303ad127e14b34c5842d8b3d50a7bb6c4701576e388e15eb525730f9394b9bf5a32f729a4cc3d2ae4fe33ca9c2c737f83044ee47e04ee6bb80700f798fb30ecc9fd3365ee45087bb642087b723421f7ac1a2118f66ccd843d5b343c9f308747fbf6a70c0f8c6b5020e5fa36d5eb9c3fb355dfda10057714732dba5fbdaf47708679efebcb21493461c22244c207b8584f5f4fa8aebf16dac52640f207887b12bffa9e475dfc70bbd8758c88bfbea7f1323fda55ccab7efccc61ea2defabe7791eb636d9c3dacb1b26a1e1e821d52ae4bb3a20b05ca13e98690d4cc32cd730fb2ed249808e8d9c8e8e8d5d9edf5d808ec9157cebd68b9dc31b871c696ef58bca19abfd6c6aca1b1e2b6e79c2284fd87ec32da911d714996c45536373a3434777e2eca655776985342a325b17e6479cb961ee53a954cc4e4c77614296e32130af7a7fd57d19bcb3fafb3b310ff32fb837ddf178c495353b018b8158a7ff989075c24986c4fcea9324a063497454bfc23b3b313c3124d62ebd0ceed8eae7b384ac9e75c209e8d8ca355b138fdbd3c913ebe93ae2ca6e3f6df3979e8a1599c00b8eadbdb7730b850f7f5d98efef98d5fc2f325bfe9fb4d2a54229259443928a8b3d61a7d3cbd0e6d3490834e3ca221496444caeccfb87471b33ebf008cae018acc2b3392b65b50997cb86b39b56dde511b343ea62e3e81922ae4f952432ebcc1ff4e4daefb8438bc79adc3c342037cf57628fd4e4f97476937f1a1abbc4c4616013704201a528390c07c7cb977e3f721891d99a6fb55caf4495c89b38944a4425c9add4599e0dc36ccdb75ebee496cd25c3a4b50293b6c985922405943e471c2699883cc0b77f24d0e8bacc83666bca26a5d4b3d69b220a954cbf7e942517f060250f2077135e88b2d1f4dfb64f6747e77d280f9a306b641464146414646485666bbeb5f782a0906cbeb544266c1255a2099b48d6de6bedbd20f8a25889802811459aadf9404c40444144414441484548b402292d2d252d25310149a6f9dd655dccc3f395f94ae42f2b4df2fc5ae4af1a797e9df94bc9619d504f21c44403aa323924a12cf258b954d90bbce4b11ee5f957a6fee8bc7271a210c5bd2e7371ca7a3816ef68d0f84b83c60d479e2c3bd3083b2623f3dd382a51bd61bd5265c26ae5be7ffd4ac44afdea65bebbf7fafd917a995f85acef3c5cb9fbc7780cca8d52a111d58fa9f78709815c6c04e6efcb5049e56a85fa18bc6466954b9810097d1690fbf52b368282919175d14514a010da7aec4f9e0f94e707e5e95db62de1367371e3b275d9945cf4e2e2dc64409b11d086b4056942db2422caf367b6cb5d02917a987ec6b9e164ad68b6b4a0ca0464042403220287ae10518ffdc91329572b2ecea74b1356936ad16ccdaf4b382ebaf4207881f2dc925ae82980e8c902c83d45942b5b928bf3b5242155226b94e75ba3cf2ec5388c05d466f3e1934a5641863ba96491841daeedf1978fbfe87727cebeecc2f147b07b361ffe9adeb474d59266d536df93cf2d332f37d5ec8dc83a611e9e4f20cdfcc7c999ef23080da01a2679be384fdced2c5d86721979bee7f9c7c605fd766c5f109973a6369b434831a349ee2988c83d051143b94b75727b4bf326a56cef73fc6befeec4bdf597f75d3f1ededb16b6a6a6a6a6f0148ed762af3e0c44b1c66e5a7597526a6afe795cca1c6e6e5caeca335d3e81e3ad686a6c6e6e4e9cddb42a9fe81a4b63d191d3ad8d67baeca2dd7d864edcc61a672b6d2459868d8d28529ee9f2884e870e9806db6016c69ddedfc66138cd85ddf2fe18349ee992065dd78cb2dedc2c17ee7fdf80d4a35ebeec1cf2ded44d75ee7521cb05d57fbf80d5a34216cb05d57f3f64f5a8b033cb0598ff7e88cca31ee6bff780cca39e27b35c8079d52f0006b33c1566751ff33cb105c8609607f30bb80f8339c001d5df5f40ea655e06730066756ff73baabfdfe121a91d984f09f151e19d2a43540ff33d5b30309f80be31afc23d5b31b85d85ed550fa38209427da72fe24aa87475118ea7f32a8593a94d04c8267982942b781df5a4b5feaa1a7d1dd9e4a3cdb78d82ff9474881d42b17515fca9f50f0131b3ca94527a4555bcc4b54d4e147d2a7bc2aa6c43a80a94fe10d9c361d92d0e03b6e3c22a9452492925f2534507271b11334f8cfbaebf1ff3756453f5e19e862a3a3859c944a16ab4074ff62d4663c84062e4d7c2ccf3b7f9cddfb8b0ca12dfe69cb6a22c5ee2f4a9bb667df313348b5bd8a1f5070780d49fdd040e49f9ebc1b3fdc4a3670f3b5beb6dafbd9c8f80ba8467843ecd9d47aad9a01eb55a9dac1f599bded9b861baa36723f29bfe463f5441864b718f3975e417fbadb3f50c9d9474c3b2c55a37eadffcba6d8fa5496ad9bf73c8157ae62432dbce41ff07edd931e7a472a226ae357b2d4236752e5790525be23fbc274bac339b9ab2ff5ce25d53531e777a7ab29f50e9562595eed3718991e10303a4583b414495a4d84ef74006455d6231a4aac4da5518bd3398c861281683941440c5e08e9e8792e2d575cd18ceb273d67d3c61c9a7a37cb23f9eb46c9227d675fbd7a3be5b5b6b3d9db2d082699c11aa52b2fc1aa55fb60a758e4a6390e553a4ce315ffe14ea1cda4b1f9a2a25bbdcb64d7e3dac37c5bee58975dfc7fdc006494141de2468ca265064172e59aeb4c852fe49d63960f278c2b29ab515415e01e59916f947d52ccb5adffa9df9c88a41141b428dc3855848de6c4668f684de4cca19a114cc8852b3cea1bd7c4d52a26e18986f87c7c545f766de10fb27303ac0139356145102a41887677862fd25a063331ef2c4c0292e9759b3ff8c942efbcf20cd6c71183743e58a2c3b910ef238b321c1c00666e47146cb0c51f6a7530a551b64197a5d661e974942943bba5075e5fa1718bd596ec18c902bbb50e37017921370111f79a1dbec66eda93b755de5427fc24b12b3980da593a15827e371e1ecc0123ff889d950ee50450c852761748975339ee542d60682621cb6012e1cd1e5547c1a5c1a93299ef2f331ed6538457b239876e3ad223e985e7459713ff7c0885c71107704b3db2a32d002f3a1e989d1f0b12afe3a685efed49b653d1a1962a0ec7e1e69b234238f3634d77590c2ca9dc5cb184d3a202b340ef903e813e47b9578002dcaafee5867e68a71469eccaad9b1f46014b0c551ae79c40171fcd55947962b2777fe54a18402af872da8d88244e7032ec468e2c606f9d53d8b0c4e18752773ce3947b1fe9c5f23a5ac61084c5cfa3ee9fce1fa4b3266378836ae9b895303d230e1c36c045db25de170697e65bd2e3904185cfbb26eafd97049cd46ead3e734f91d17befd06274cc6b81696c825356fd888f6f3250f6d07ba7271d27c8dbfe68b2b2b43b872e96b3f565c5ffe58a9fb20536c44becf12482672b0c2bb97f2bb29a7a39af5e3f4f47b9c70779e5d4ac6e8565cebeca1bde4c9947eb51cad9f3337b16767ff1ccb18b952d7b22954902445d16f6fb7ed7bdb9408a2cb170d824a6a4ee2ca9be3aff9f4a47d75593b9148244b394876f89fc209788bc3b2490e08fa920472e27a766bad3692b934979e6ee19a618cc18473f2014dd3344ddb6eb02e18c3e7e7863cfe910c6cf2fc9e5e4891e7afc07957598e587044258ff73ba059a0a1982189d6a59c7adf3c6d16c569a0ff560d683ad30b47b100e8cb195b986cc1c5f6e5851eacf4e0e0065a7ab8c424524e72461ec1ad0ba333907c9a6c30860d2cf86781197904b38b3bbed8420697232766eca00af01f893290760045892b663060420a2d4c3f5292c0011659be3401022d3d304203104114e144172642c003095c61c696258abac842872ac820b2830f6e40060e3d686146155e784ef08359d11832083241146330110228a6b86188288c88811631da8c1b9481c5d21363006111c6931d3871344490121fd86249e767072678a0b2431541558081840880609a155d79e2072d5f6c33339e10c3878619962abce041d00c335cd1248355ca5b17d979aa5cd154250b2a64800446cca9a0810bb21811021a388122e6ef5ac0baed20d75a8fb832e8a2943d1c9d2083598e8270824a0d6658c83043fe80c309baf44cca0a5214216332814c16933908811355a6608ad1e020ca0f320cc56e00828889580c9a0962ed8414cda5c90ba4ded28109c58a1f9c88c5e01921e110f3df711b40108b212629e6b85d056bc30c475d624e8ae074c002054cb1183e15c4445741fe1423ca8e3c6206298e88c560030431eb2ac8974cc0d89e34b121686699e2402c7d199250a824811485c88633264cc32208273db11e8c88c9a0469e2cab0d5c40208d68a302a23c825108e5d18234a28dd613e3fe6e36f4a10127a6fd8f8d711cb6af4d2429e4fe80b40e72e3292cfa3b2d8b6540fb0c6cf445a7ffd3673516b23dc509e8d8868fe8ba060aa11c3463e57696287ab2404194050a267f9a21de13dbbe67ff940d87469478a61f93fb037223379e9201faa2d3675393777753534cfb29daf7b70003c4347ac59ceeeeee3ebd8694d78860c3952ee9d3d0bb72e763185c1174b33b89e7d9322b71cfb9dd7b8ec0353799bdca12fff92c17b8b74f84b35bf5d93ef4b1dfb3a5c5be51f81fc16a715f6a639df56cd8b1b9e17715fc2b0252c8937e9bfdef1ced1243d6754d15fbdd65af4adb7088acf5d6ae569bbdb063b6c3b255a81ba03624f261ef89f4ab308311253373df5d324f8c27e6dbdfd9f2f7421fef6f7a70759a292b8975a3a0d58e7561c74ee108e64a43ed039242ee34af7ef46d175659e2daac734efaa138bcc4eb7f0b94648b879fae6be82561ca9daa30157447d197666be2b009005702d7e2549cbbbbfb295c0202e1e64ef4578d9f363c9647e31179e037f3c97c4817b5f434e88e2df3251c78b43678290078a904dcc2209188477b038ff749c023a8fa11f0f835aa07001e5d2a3ce6e0cc103fe611caf569e0252211804200e2e9c9f541c04f835944e0ac460c50727d8a349f2ea91e44a2f1334834f018832cd797c1aa25d5920a8f31086189fa42afa3228ff27cce86a353c9f3372e3c2a506e00f004407a53baee860f4032340565ab5d72ff0d1f6e4d514a29bde1c3b65acdaeb59e1da2a101bbbee1c375efad77bfd5fd1b3edcf1e61dde61175762947c9a2c310d23206badb5d67e3be7e48ecdd45d60d881f9fad247e661befe0b1356e3eb2391097374b858bfaba19ab299577d4c38f2ec8801bf0331cb4767f07b74069f27cb84e3afc2d1e6d5cf84a3cc330f8633218defeffe4cc8936fa8a4661a3802f204d5cb8463cf4618b2ea73e6bd38c76b841dc3f117ccfdd4fdeffb7e07732fd652a8cfc3c9381668e5558819d4cef68a263f9560ee429fee69f898f75d373d89bb8ecea7df0f1432c79dbe1d9be7c95c3dff80b832fd3fbdccf2e3fedb5183cc340af4bb9046a3405f0b57f204fa12bc69badc9fb0e722a6177b348aa0a12f4818820421481042fbaed14299bb236188ab699aa67918c43b6aafcddf8f9ee9ce0a35f284f9148f19c89af630dfa99e04216ebba83222285f973e51aa972adc8d03068f30644dac912bb0204f9873a2be1a1e33888bf345eee7b370fa098ed67353478d31641f8d63fe084a977ebbd85ea6328f6d644316909bb7bf79c356bb52fbe9e4acfd3c640bf4ed7f3a3bb6e721f30839dcfe896f441b978ec6389d87101122fa8f3535d2a517f1fd5d2a95ea537f3dbed7c2ef6d28afa436d4b49fd33e554d4d75dfde8ed2d1a652a86f14aef6c465f976fbb2c451714a5223baaea95ca6ffa3611f9640a8948d01ea5ad15a340cf5f3350b340c85e508ba4571b738c6c47cb8bb357679945deece6688bbca49a854e222a55f43ca8501c90bee2881beebfa5a58b5222f79681944a62f9bc81596581d46d03948d02f20b942f7f4650e9d637bfa9a6c16e40a1d967d82f6b446d6fe84471532d5281efb894c93c8209d4366fa547bab7926d29ea073de7b6f27bd54ca4314cae7d4e409a9f79c09f3f7dec94326d1d9f2c9e549763c793cfd0ed477fded40e928b92f33cc4f981b8e4b66d6914c19c5e37b1dd9e4fd9c3adb9289ed0c15d7b60b0997df69e128bb64ee3be98d168f721b2ff8234ede369aad977e933d789341236c72e8f4a3a49237497463fbdfe451deb66ddb7e943331469e6c3c06b9c9f2bb55d6b41737980ffc9d16baa0b8da23b1f86d095989f632f707a466adf3d9cd69a5233e8c2090e5737824f2f1f0ac3d80ca1cc7a9c1022e0910877652f63f39b1f4e4c96c5642f61f4579827f5777d15f88cc05da883728a46082f6f2ebf165894f5952496d962fa467ab62ed3b36c45b2ced6dd6b0102bee23c9eab5425ffef7f3fdf8175f1c659b9f67d8ac308d8e1a9b77490610100f8038633652fb3634b2d55abf47e78a6f9aee122a8f5c53babb697777d31674519a491a57dc98cc6bb26709dce18e6de485343e702f8d37018bbba2f7d280790bf064d5c7b49156ad54abd4f750a9fe7eea79728ec3bc2a8481c198f6773fb0032c68c014134340c903c8cd841042b9d66f87a4e2a29443515cb1116535f37f0a8dcf712983e49085d198016b884866ebc80c8db0674b0ac92028ee945090cc1f654e6129c545d941fe6a8ee6584c0ef9dcef6e643a52f644a5a87f5e2a3c62935be7c7f6fd279bbbf014f6689ca12cdf6e61eb681cf23f7059f569aeddf3e5038abc20537b89e2f1b2e0d570c796c9957f4470e9987c7c9e3c99410e3572670943280725a52698b80e59b858810e6570e14206113740ea9a7af0a56ba21b6b7ead62e3f772b550c99cded5704fa7762aa778dfd9b861828b80fe958b4e021977bc2e216efb448d3c99c5832ed1f83805857b628855e1fe48c7a0061ff464c97da59d4347369d944c22b04071d1c621f16b5fbf1d3cea6fdf199172d2efefd1dda9f614ef6f9abe398c59f0965b9c43821a27778af7d5fb1b87791a0bde72178e8673644a66b82f7145d82cc445224dc45f441a6663ab4b46d074d9affffdd51888ffa4df16b77f7475d760d60f2c5d676cc963cb68240e77043d2093fddcae4f709470d597ff4566e3e607775432c7895d3caa914a2b0c6017f08b2bbf7357adebaf05c7aeb1a9a9c9662533f787808a1b07e36c13a75d134fb97198fd66c15b92ba701ae7d428ba9fc9c8411e7b66236e3cfc408a8cedc8d87c1bc858b2c1e7cb131ea4e0c90c9ae4a0b4440e1e10128a128573373a1d21b928dffd64c4bd6f27a3bcbdfc93d13c21f9ab57f7e61a1e3851ac3ffe92f9645481b2f82fb8f373154b1c653177154a70c9dd746510723f4f6e3ccafa93b7bfe1c31d6b510f1032d7a571c83fc9fc257f6a11027a8b5cdfd5699f820ddbef480187bb11350ef9dbd78f070899b3df0384cc613a6b1cf27980902ddef0d83f8f54a0194e39fde974e42df936bb4e462ecaaf27a36a548bc014d295a3a32e88f2d8327a44a783253f9b9ede869b9c271bb612cf1ad66a38cec72c67f9d31a4d7c07a62c2d3d19e30915b3289dc50b1744912f316bbecc3ef8e0031f00f5d3e789b11ab35cf88977aa341e329f62567fc7b4df995f31abf194ed3b569f27e60e86357aa2e4c6ed35f06f411f21cd6f877c723366b9e03150de1cc5fd8cb4427a92822d4b67702183337abe10bd904964c2b6777db9a30d796276c23cc0130b7962da6f3f44fb0def5499bfd3b3d53d4a3f79bcdd973b8ad37d0b2b42686c62d614ca13f31f45e7019c2dd1cb0c59f63f121319e4e0458b1c668e9b8005ed1d243d3d237d0bf0e4ed6dbfd6daa6d5efa161ed6787ef9273b595cd2150b8c1fd221bcaf5dff1578e8f09b3f782e08b3e84526c87d4a75f3b771ffe37c74693dbd856213066a9f67e5072325e26294dc0a2bb3b4362d1a37d008c2cf2d848dd1952be7cf9a251eb6a212cf8984d6a50c592a963719136d5e939b68c05a3bbba77f6c3c2e96f6ca4041b773f29a5b47fa3dbcfee42d126bce170cde9bbb79ba6f3f45ca8d3a390dc1570e551483642bff11157b6989b78a41cd6347cc312057fee087a9eec6230f3b94e3c27f36b64b85a7ffd5abf7e1657e66a84cfeca6e71f8ffa40da48bfffb4daf7d870bbb8f1e4da93be4825172ea2e4b1919c5425bcca4a5d2db5d780747f15e3cb161a91fd833ef73de8733377e778879a36e5f4ab7bda68d65cef140922222f8a17c584d9fd5c57b7913ceaeeeef3c760b2fdd4ec9cdfa3f3c4f3ebf63e85fb1a87712fffb9964dfa3dc796798da3fb79290499621a70a6e5804b3f0b8864cda72f99ae07ca687abcb93d6044248692093aa09e7780fbd0c87ccd5b9efe5f14ff6598e343883bd2d038c7854ae68fef3620fdfed46bc8828b32a439359ab80f860a5637cbaa0319479f8b4c189d2fbd115c5aa382cb922c896bf4dcf7624a763cdedc8fe38de08e384b4552a46cd92dbb3b8f0cc860205da02c652eca1416b07148f93d6606677bd848724569569ab66d9bb51c783a79377c30f2408fe6fb746489936ff470c7f752d2fdc8a9bbf1ed492165f9b767c2524b28c81f53b3942cf75f204e082b30f25d3fdaee777588d37f435fee9487ae5b1626a13e3beccf917147dcb191840cf197b74a923ec45f49641e2d1128d406180f15b04513173bfbdf19e40a4850038d2b6af862a93ba3c9eabe0e9bec230d0f77b44c50b2801283834f6a87181c7cbe7ca9a1434abdbafbd71c7f1f5cafa768300dcba68c070f74f1622df779c8578288586eb2f428a5476eb2fc19d4704304355001e4e960421732318a9051990e17045f74b516af76eed9645a6badf5ce70e7538aad50a103a5ff1a563740f0178c1df2e8caf261d46ff7954258b0d09653e69730dfc7c7d6e656fbbc20c9dd4958c1d5e19a38603c917d0736d9cb52d248ef59ea760d2ce5fa1d9a50451fa940d9ff79f01a4871450e4053cc40ca144f40d11804b7afd875e3a2cb4529494042c725c11d6d3b095e60d4dddd2d739c0342122a043adcd1cad972b69c2d67cbd97e97727006d18dcbc58b83e3a274c9581734e4f177808124a51402018a3b4aa1217ff5500266cc761ee3863c4a2026222a5e0959b4cd2269c9070c21264a59284def9f3df7730f94f278ffe80b0846e9c205445166abc6cffd2f50d0c417b3268cb2007fb823c884c90b2a84a22c315d0165aadc597af0441e9f0a298edc7ba28154775d9d1445ff1918dc51fe94b155bd52a4ccb193e88f1dc41d6dfd765897f3f8b2cb04f7cba3abc6d539beec7f2306a1bda8844e1475450c15a21900000000f313002030100c8643229150382215cbab7d1400098d9e4086501648b320c96118849031c41800000140001991119a992608973f31f399d7afd1177f736610b44c9dac9fc2fef589614e9146bd6cccad9e2dda689b3d12a949783cc042495026bfe114031899ac033f8c497e3270f8454604da32586981da396319c8043120108a12a6939ce3b16518bce02f4e107c67fea8beee22b260a52e37f0a05d90605d459c2e031d36fbb32e2bdc2d3cc053e924b0cf7bb81c9d1319d83d42087d117f3033540a32eccd702d426f28bb28efe290899c3e4f5c75f7c10d1d2ba4721c83214720051993b6cb52c363e92924306a7d727cac8c70281224639d09550d851bd07d0274f579c117640b60dbbf05349cdcd87d71f3c080a24cbcf8049a24ee3112900e88048f77ca100515fcad10f7b9ca1b789b2f3cd0840add371af23150feaf52576bb23177059762fd521f6cadcf628f41777f375394c0e27b592a68f9f7b04c431717c144971aefc879a2b69955324d0ce1c1c5c53d43fa7c03acc3d93c7280382dde9cff116fadff723507452044a42f825026eb8d5dc037a75fa6f366081138e717053dbf1ab13a4b39abd33bb9a829802683f58efab217ea0536f1c6c4f0c1affc537e1f1613c870fd805751e98790e80432deee0c323c3aaa3219ea12fe5fe4575650516bee442273a2b31905b463d1164b482ff8e6aea13bedf2b2d6045190030217ea964bb0f3c74f5642c9567e08228613d6920b3dae5090ea90cbbfae601b0bf9b3f28d5eb2a1e72ea83304f4ec6194a252f3da2baa2d82e4b04000a9a77c500a62d1d35b15a5e781aa6357290a02b31c703a59a2cac0b8ec888117124b92eb8754ff6cb3bffac2a58a4a4094e5b481db23ecb86769566422e1c784f6ac056b621002226664681268ea41fd19326e7070d5febce3652b67c6c7f1e2e70bccc68a24178870f4f829023e47884fc56e653ed20c3502fcbbd44d553a82421f46eff0da03178265a34a4bcca71be167060427a1ae806b46d845dc825bb2d2894f659f4ea926099dd26e57404f82c9332bdebca30e6c9cc65d770cd88171658e1a9745934b4b37b0638719bd43af362b228564e5e768e4432e0b88a6c2d0cf29ec0908b94aa20261d1879f2352e3ae927bc70d72061a7b5b9dca1425a3e6ad68a31df72e31f5a4f1b2ed1345ab398796b0a84153275f02ced716b37d06693eae93a0d41312ae044ca00787bd7dacc2166ee83ed0f3cc27a16415f07fe52d427ee78eed95594d2b8bf75e9fcfe150e36605d9bc2bbfd59bd737fe022ecd7107abe70ad44ecc3c0f77736ce84d30a50530121f877110dc8a3206706d38bd69660a0eebad91312a1a4c8f7d986d2641a8d0c81644931378aa4aaead1aee80e44a21bb31262a46c00d218422b02d1066e21a91e85219449e8352121e1346e1fb6e2f3c5c00527ba9f63c8a529c75d8dea9ef6b0583692b0e1c641f138507cda24e0fad80b88cb3e76752ce0ef620e1485f23deee88ed8b302e6ad53d34258094ea08b0303fc09b55315632e54993fe35767376a510d1514b3ed253994bdbba53decd876169372f2e543cc871030711285a74dd3070bd440e6c05fa03842216add6a4d6a9e84900f000c709473b11f98bdbc6ded3c1a43abc3c6f049a3311019d351d8943a57ee27f4e123b76497e6850c3780c829e5490315980074531a6350120d6a7b6b6b00e8d45bae72c570089f95b01df7ec64e1b9aad9af5d54b74919a93a6bbe7896802d26519fc00ab9f57f174dfda0fe31f0380bce32bc94635c90b666d1bf4b1698127442847dc4dd57028529e12b63df80e35b8c53e6f5446177616b17e4c7a112514cb955fcacebe7c03b441efe44994bd0f6fd096a3bdc0a0ab4e94647c5a79d57aad6bc95ca425c8fcfbf9222e7a74c281e9557d442986312b7245deec90c1df9aabd5b6c3b51ae89e8995e37d94fddeca22e413854a4cd9441285b70ee3942962b18a769fd746bc137b29b24afa1994abab7c1359ef3600853cfc8c0609d57ce270a9810595248cdb7761cd7ce0dad78a7ed9f827b2f53c4de994a4b12ec5e46bd86ef6bb9a58c033d9c7d040c24b951b9bdfda37f329a3c69980ce1850f04cc600ccaa51808009f09cfca768c2b451be50b3a07c2f57d2d44494c6eeef4d9ea083afc5d8bf38a1d43d5fc53fa8b29ef19ea3086c8ed10fd82023b18f7b04962bb5b14cca40d320f739975b172a982030e19521c722b5b3f8fa06d1965bd55dbc3ab03e3f819d4dcb6dd360ec10e675812085c6316473f93ebf5281952ab6d49c34608e5dd430678d6f98df47d0ada531722a996d18c27114a7f7522220996b549cc8c4db5801b90cdbfc640ac4f75aa71c7527f120ca65baf25310152b672ae7446bde25471aecc0a79c4591c00f44d6b9bb32e53c294e3346614899bb55ebf2ae0d4402a830529158ab31fbee580236e9a0ffa20e7a4328cf0aed3fa0f9b55f97bf357a0b0fac238e098858112d1de994e27e41320d4400a09bde1ff59c8aad08e51baf1d607b9665c43ee125b668a5fa612007bc048a5affbc64cdf118d4f5b608bd12204f4fb48bfed47b3bf47c9413eb6f5d4309ab6daad3acfed9f99d8328629434fcaf7c9feb9e232ea0833e0aac78e9dd8f85dc3cfc9781f65f517ae247a4a43150ac3711ed9be7c1dc0f888a5971e5c4881a88a05921aef3470b48444f9fe0d70e1270e7fea98ce217ac4680e89fe91c864534cd30a0a08858cb4da4d18a81a23590bbf52595acb6a739d5a5b6a6b109d202c8cad68c07852bdb9615175fb80b80cc41970a069db8adf5bf1c5b81724cd33b82de62d9d7843c0574d4e9cc1e35d5da0ae79d21f176f50ae3e4dc868c5338ab9a00649c17a8dd50daf7646ccd142e123302457b78c85964129772288b67f5ea6881c59868785e24cd7e2da54d35a007edf48cb17a7b405f732b5728d647600da92bbd1c6ea289d65ec5c670ac933981970ba16f79ab5f3a0ad55666338e82ca5f80ee09445a3282510ee20c906761291f7add6f8d69a4c34d407cce462d8e3429204c2917a642860c9c34631fa209396a8bb4d192d00fa4166fec8b6b069848a8cb451b09f6672c637d26156716755ba22b89b33a2b8dcc2a55d6259aede558d306c81e75ea95d87d9692ea567bc6177767bddf629989af979910f35201fcda8345ad03b74fa931b521981e770d66811c68c1de9611ca809c4117d0873d105bf4c5a842cb691904ea58a469d8e97b09ef000e243dc78a4ae6829d8c753996f4fe5a310d218a53897be3cc2801d8500c1c1762516b87062acebd23c683729df6c773a8498dfc9241a04f53860b47d416b535c6fcba4404f772506fab89032e6b692be7fba05aad9cf0b784c60cc6cdf94112e1dea024c2d7699e5e6e252a394a307fb98fbae66b89a504ba024f647f43b6c37980654429f6aff33179c06f1963d0e09b8e5a2277c964c4ca791fa516f562bf06da4830114d1616fdfd4e5ce9257d5d5c9f8fbc930922cc8b9b86fd13acf04905362bd5ccb590f058eaf7fc250a81d82003621b4470f6c4b6370488481e6238093395bf465acdf3431133c514bc2f0a769cf92529fb0ca5de868ee3b0678e22922454b172e1ec5c76c528fe802e7908945773219b328e6251982116b41f72042be8e581f8a6536c50d4f934b40d01a13b118ea7fcde3cd52ee80b442b1542d96fb67574f4049ebb3595906856eab2450287e3400a12f2b8fdbbf26bfc4e700b19ec67ce357c2a3d0bcb513c4e9e03883b43fbf1eb96c78aedf5512d70e3fc4cea45519bc37577fff8f439de72814156c3839fc37b3f7242d7ea50a9e7ef799396631dff0948ad2ece2b764168f5ee3f16eecba0e61af09ef9bac64601667fd5ef6fdd7fbc0226b825d10aef7dfe9034aac7d443ce77d18d188280debe035f0fcc190440e2bd32dedb93e4878806ab707601765c870161e66ceaf25f7aa25b0ac9aab38ff191581b2bcf8bd34f3cad6a4661e1b9c4b9110aa53fb7ed12c2f040672bc6e0a76adbd01a8883c9b63de5a22ebf566f8888a852be7bec2ed50887d5208869b3182ae291ebd374b19d2e44da8488246c256871438ea54ed450fe62c39d8f92afbb0a9b79d57f82862691b5aa23525d8aa5c02406bbd8f6cd1d2947267dd01b1188e81265baf2a3376881f7403632976db1f87d5ff127d34d3dff046b62117048e35030900a6648a107eca027f1962e76f03fb9332778b4859e2d7fd763d84dbd9b43d9bccdb720902f69525e36283819ec4ab50be0c853e801159e59d3617c40e7a6f8c01a8867bff93180f65f7cedfe1d7c3e2b3b451cf7012f886b170896bdcdd1b8ac8ff95d308b318989d0baf0da22343b04253fc3e37f262594d7ef7e941713494c0cc1d9844267c46a92697d9c9b47ef637cd85b423ced047644b81fee61cc5d220b88761cda20a0a859eee6f938b40222ca962c30a83f9256d4d0e6afe98da0a80658f6dd470acd0356d53ff1eb6613803ba53124e184c520ffc883b7d96d71db9b01e76b9846ff41539151220c0b123fa23932012b9627c424ed5e04ca148b4a2070f28c50a4132d00e9e06d89441aed8640c5832f67b74d7ec4f1a8ca34160a3f4db68b8d5cd9aab32e802b4e22c9594ad55bd102a07e25dca11b1f3052193c5a80c6f482e5d9128ee11ab92ca17b308b04e186930c375f7a35cf61cb3dd6cce9a3735351fe15fe5b7526573e00a35c7137fe11f076007f2c1c5a186117a6b9d35cc062b08a753f3ba1179af1344a97621c47f9b5da00b2f562b0dfefa157c2ee0843f891c3b788e624dc92d6d0db34c1cb58e2c453c6438d68c8c630515840a453082b283d5c315172608077427e2028f7fa9917259206d992d4ff5400aa634fa75302ff0354a81301be53c10a5a25630fbe42701b43d758eab9df8ab41720b64f2b723e0b5515d1f1a3fb59e6e31ecd671eff90d74fecb54d1bc2c9ec81f1f8669228de5855810f920e7a5185769bcb5bf5a180706aed8a6894a4b94abe6c2a9f32090658d2ebe035088957e50f26d29f3abb24b67a9eb9d5cba49958dd79a014076f7867e4eccdc5d108c98a5f2079b855ed4fbf8074b252af1bba71047d9c5ed55ab82fa571ffeae144815518464f404d44f50480eee8bf50e84d3f5a008f3eca0b1be179b139bcae52ff43121e4d72fc24b12fff08d95be6615744cd73219098b3367632bb942a321479c819ad06dbcd208398ecb96c113e18022c1f9b0f67f2318e7619a551b2a0d7eacf8e2e292a4f40ce82405ce6e76b55af4535ace95939e4c332d452a064a29c90a3b126bbaed214934208aad343e5fac06894de47809006656edab29792a843b2c4af89ffaec58403506b57d525d26b78a0b4447230dbf0bca2f7d680f19f5061768eeee1d204c861778a3125815426d360a8502ee649e7ada94a71376686cf3404a4b89175ec02fa8848fc3fcc19c5a29b3ecc8560c207c13f3941749a8a4a62e3a935ec1bbbb1f6c41d00fbd37bdb80d861f468e78a05e08328c1585a3625fbb5c0b88ede9a2ae0ed8a042694b5e451d938440a12839e381bdc8d3ba015569f420416d4dfe9554c56c167c4f3d11a0040389b67229ce416da8f117b1b43278d1cc306011fe8faf7ce385150a2daee21047d94fb6de5042a62f56667bf6c7d936c7c133bb5b6c1b61ab2c08176271f395fdd2fc09ef93888c2d6cb2d9cb096e7ebb8dd9e499bee7baccc74711cc15e6ded023ccfa8e530c8652e2d7a98e148f8e8c0adf629c4558f842ac07b122d1e731d9317a068a1f3333b2bb356de457b3243229e468adc169610fc1fcc1a6cd8f0f8dff47b3b307871041b39ddb068811e4e0f217f565680d7069bb430fe5eb0e0e67fb17c306bac70386c9b5ff51309b1041fad634a098f9e9aa33c64815ca43114e21d306e4a7b3daf9b6273c4689b58507ecd21c3c1a16d849a8eb04e6f4056375697c8aa0dff3d26b88e4aaeceec56f9cb9a0942f0ac222dab143cb91a56840de0e5b1886489b5c17ccb62083aa17069d953afc3050e9ef4e87e5c908c4dccc2f8c37541d908d532b5bdce095e32c870184e317031a4386f4dcfe8c2f43ccee34106170cb8ad0e6900ccee55734f669a2cb6b9b5aa739e36e4311d1af630298829f23857075701a8699e751c1a610a6bab69f5819cacaa56375224d1ab67d7f2f1a917ce510a92012a041791495cddd1e7f9e6c6efd8f7b1a81213fca253bd03064707a44a4a206fd4eb34c028dbfc14155c614bde9dc3c5f8dfe3588881068ed97cb39e97b38308e1138f65d616301cd5fbf053bafa17440a7829279ca127b666c227ad69336cdfae1015dd7c9756e10af4bcae165b52b784b8e3c217fdf600738ebf0a02d694bceeb0b4879f8d81907e114ddbcb37cf6275e742bd8700e31c4de05e920a2ba18e90e350ebb6e12905504ab17e8d3e5a1df9d0de52d0e590d9d3ed3d4e0e364ad213bd2a4c618144e5e0ac83684cb23321c93feae26d1236b28603e46f20fa370736e8f7852805c19ef31c4ee44fde53ec03b5c404c7fec220cfc7e266581a61f7f504de2ff32df6a6ca274df78531976479c2b36f803405468aacc2dcdc902531fb0bbed69d656db2a532209dbb55256017dcba36e76c6233511776f815808d4b94bc8b8f1d6622314a06d39943b535b1e6e635b1c33bcc42272de7c548abc113ee46cb1ca10c3d4510ea6887d7134297d51c667d087d5e215ed10d4679d060e79a81b14fce999165589030fb3074c89e89cdb072d34ed2f1d0fa5df95669a7aed194ba255240266f3fd63e01705b19fdcae01ae241390e2c0951b0b1fd1adc4ce79ad1ef69890754eb7ea391d691d880eec3a7c1c4c087feb7653107bcf4a495a809460ebb100a9ed05af4c430c0755047627d4ec85188b80c5d318a52581b45375b6e001fe8daaaf3002fe60c97356042761b576dfe0d81a7163671010c9781acb3a7b9ea9427d7b12c558eb4d58cc619142202ac776d81ab401c15bebe1657e059dd0e7f5c6b249722270a7397cefcb8f010406a1eaacf849e2c4ca162db1ff3c088a05eb925ab8115ec38e119ba2e00ef34e77cad7918c611a145b3843543d1597bde7b25242653b4cf18fbabdb5e119642e7f0c81e15ff83f3ad78cc21bcfafc486f46cdc44b6d66f37568580f44a24fd55659a04d7451164708647c6f4686e79095b9f954293fc619b5c683de549de51a231e9d4a530d66aeb192d36246603954ae8b30019b50c683c2bbdd32374ac1932a468e9c8f0c3eee25d0c4adcc9748f9c56403c3c60547bd91a9d455306ea59114cd98514e8100360392720d1884a9d77448b21cef2c85e44c0721dedf4f41161afe5e9b2cb94bc760659e05739c6d212ea4542638596c686588be5612ff7d69915824392d3b01399fe93dcb97fea012b0aaa04b00a4a253c5bb2ffbc741f9d28a79236de0edffc045edb93387078ac77e0a7be936b64fe440527f7c97bda9c0b3c6d09578059553cc3196b09b3d1b30469c4b3eabfa1172f2c34d7338e837faa0e70b6e72bd70568f8a3bec615fd7aa553ff083d47555a40485746d7b5e3ea5c1a7e7da04eb9150c19b7a6903b7e095b00ed83a2b947c5ec02f08ca24d53a7088d87b13f9af97466e2d50b53d26c515387a8a7c852968d4ffd486199297486ec6e6185cef24e52ab4c2ad44a65f4db7971e733c262ebbcd10de25288504e121d7be2f3a5406ecbb56336be878e40e8e49e55391d8edacb325297f73529456d74cf99b416f87a1f92fab82c4536634daa1aa7a08702082e4681939af4428bbcdea84309e3f88dd02562e16d249fc49fbff267181f4f6d8053c579c5897065decce608f146327eb7427074184553176b5dc352e51d0027b36938a356b0324e4ae184e61d85338cda3c77165183ba72a0f66050bead6df3d2f7c5e0d3cd212bef7b3f24054341d2f74641a464e446746ef47f48d31e70cc427e6b69e37dafd000dfa4045fefcf23e1e7c6ba875ff70519ec1d70830a07d943089d414df54611182c35791ca236961b4eb5e52a3b17fb5c96b9fed07b2fcf3cd78e96139399b096d1f16ad2c71957645b0e94e8d9b87182f16c7f927534e70105338a521427486d0b25f251e5796607a0172e91a5196bf3c44274e20d5bf4226b54e5ba4b6c4e30d7062d27fb9baa4f432857ec1a490e84ad36f75caf8cdf7f0c81f394732e6935126f955c9de3cd86f2619a938aed2b42325dca63b8a38b702d3cfd768117b2c2a6300c437777558b0873f5799673404aefc503de01afaadfc9dfd87645bef7990381c6b545b7d236c43580a21680895822628db0e4229c2c922a2b613508e7414f3770e693435b253fcc4b3e14a76d13fe97d062edfd138449598a6949b88b414f391218417ca12ce42d730c6fb61a0088945b12039686c8eaeefe810e98685cf89b59aec5983b9c3b717589d1ab54b4787a1291c6435f07ec769501bda72d588b93f6c2507e5d88b280944d8fe5fdf0b1cf1943113c058416e72dd7764a35666ac96c7ec7f6578bf7c78a0091bc37d4d12c3d9dd36bfc38dfbdefdc4e3577ea8aa08a22519c5eb4ef674fecd2be50843ff4bd421a592c9e978400e39ac34b724a3644c4c39ce14b6cee209f14e45299fb0bdd29c0ff7a24b6d7579ad2104818973d27a5fcc9c708d1e62b37fc0f26d7772645618c2454b300eff86fb8e709f4f331ca69d186ef3d2ce025d2ba6075897ed74799a219d41a3d610ccdcb42043b37fdbe424103c66237490c57e851816bfbf1502e63c2113f401305b924c88f328eb28abd4bc33eb83c5975367167110c83544915124895a4f888709854156606b36d42418840c2a69f7159d0b40d7edee30bf49f10fdee62062e8586d7a133305359b15f1063cf98e0701e14cce0ef0535ce556161ba5ca68d4e51cc4fd0f441926843ab9ce5937377da89c4bb90650e2835211dfa8ecbef5b397f312eac18353106d4a2e6092e8a131685026f4d295f1a0ef219e00bb9e85f6246e34d0266f8df35ba7d3c80c55a3172b1949638a0c7500d6c3a6d6b08d23e11fb81b551fc69a24498f8c18ea17e9bd91c8a1ca26235e94c11681b54dda7358c14e48af74af447bcef11adca939755ba9ce6047878af72b77884fe3dd670af8ceb8fc0182ad6bd3c424d797967c26477cd2898ee67ffb174ed475c84819e83b5e0f3d514932bf67eeb85f7fe2359d6cb213c37a71274eb770af392b16359170e82717ba328f2e225c0df246ac4ce1c25ce792a0a29d908d6a4116c240e78f35c3903fb71688b64f68cc27d976a37954fd2ce91febeb0780f376fa85437a0993a4698ea448404422935fff5f84a339c9455bb02d3c7b43d69889ed9cd82df29305466ef6dade3663fa957b0ff071baec0910f678ef338090472c3002687cf22ab5aaede5268926145f8843bc2da89559822cf988edc8cf9463770293d618d9f95708b0c64873ab69441b835688bbba822e6ea8c3d99a7035a7e57cee8a9c132da0871544b5af5b16390ad8484356eac2dd2c3288abdc5adcc4d24dc0f5a8b504c57a01a4ebaad8ab0c1ce4e16c5f64a5010f31b5f915a41e8a0f065031ee2af75de130f9423553c7ee482273c3c14187fecf0590342976daa522b6c60158a737093754917a0ab56beed57112533152a7cb757fd67ed62c011569c584a4f72282a13a4a04e7e94010b1acfa167ca8ec859da271a96653c53044dbe65238b7f6fdca4df5fbc798d0c076e86542bc46a5db7522e8274523afc29689d48f1161a7d7b7345561aaf6863f6416acde2c3859690b70c45445e93e3d54efb74768533af2821af1df05c63620b07bec492cca29d7d5aabce008c777b8545038302a65cbf09d9985201a73c4966540a4aebf7c6dcacfa89611cdbd8dcb0966ea9d30b03e2f486dc59be198bee293f8a6361a51ee3fcdd4855fc462e25263ea61d623e5fe544617c12604e757f48318b954880b9e29440967dc85c40824550cfd739a463b1d75ac24ef4a8a4d898834cab4a03c2074d5e4e9d116da1672482a92e9a3606f240f73efbd58f909ca2cee76ed09c7a062fa81de24cf61ab38a632cdb48c9e00e843df25c9203af2cb417aa1bd0e95b7303e4d0ea96778484dcc070abc230a6369223954c20d10188ff367568650665f0ec2749b2584993cccf14d6ba8b6550268d46d9a95fa72c791a928904bd018ce27745d4c397ae4231b2d691f3df526b72b8103310428202816b7d5a63072fbdd0452cbe17d1985db5cc2de2e869da7d06e16a208ac34c616a4589487676e7ddf71fc54e28f0e2b9f2200ca889adcf2211d1407c4e1b8159ecf1f32d4e50bdc923ee5dbfbc91385c778e93d83ad4896163e5b9844a54757101f15ab2403648d22651a40a2cd9b26ed1b30b07214c03a99aed0f117f01838464520f4de57f37be852d210db4b83c13098b8f73a67f9c6c14099209b11ce2e30f2281c89d5df1053428a97784cfe4d59f15d34387407e68f84c36955b6e4c28a44fca6f07060b97f74c37b3e36a0b80fb5b921e84d860aaacf347663d588328a1def31f2dc94f4d08328b7beb096da2d78b112f7b3699401e94406f880abb7ddb00124ad3f54d6ce5e8d3dac7bb732f6bc114295fc56493fbd35c2404b045a14dbc7da441dbe5cb9dc8bedc44653d6ac6728fe80e8e98f99003cc384a57c2c1ac1e573ffe8ebf7d589dd77575c47f363d485198682e274bd468c0186ccb4e3c2d6e297f7a2857bf55aa3e846e146c5348f84e5a4cd490d2e0a09bfb829a746ecb3fcdf6e86678cb14e8d2ffa39736709765ee65f9f75c90a6b33558003b50549a9db7a9e7b02f6225e683c297d3cceabfe4ec2af0a5b4fc826130c847c8aab55572cf11fd7afd786046a871e32bd42b864b76286da6bd454d9bdb7ee84af7f39850228d3953e17821ac5720a8810d799042535bebbe763bf706954696af8bc77bce571c2414c0ad3a62b27fd59685f429e509ba9acd360dfc5657d01cb2b3989a304a16977f4ddcf96aaf12521c904754199231bc0b42acccb88eaa0d8b04ec9e6c49838e39ab93f36673a96fb4897cc90f0ba74ff5fb5ed55db247f346e61fefd982ac32103e6fc86887787603f542085e93c083704e2bc0982301e65e6120d347b0e4da19656778895be4d2b36a44cfa940abe70cb43691a6beb33512c6152c1ba5d912168a0c1d5599b2d06178f5ba6e6b7b01721598c4f94e6ec4a4ccf6b5e2603cb2106cb73819d084ab6d9817b1c11888a5d310e8e658d68489c1efd42b3afbafc379eae812cdcabf51629457f691011331a2930c3defb608ddbea2a3b0c7d56b0ecaa1998c26f67f18aae477d368867f0c40ad85c9dba023c8d262203955d606d38d2af62159acee5a8f579dd617c08a003a142838305e91157ce962051b8d10bb13221d69f4445d0afa6a5e4a482a132748982ca9626d3e9d16bb5f7d2e07a0d416ddb2b42c56ed405b526776277d31cd0919c6289d8a351abb04eea2d5a22203ff0959e82c60bffd51362129023aa883d7ac959ea6cc4ed2601629f2460b73a7d6661f2ea722e3a48893c7ec8709d97a90b1a0cfd42f51daca500e3ceedf19b1cb87c646953531149e781378a81d60f2cff01cedc95ff0215afdf940e4fc038b05297f1c14c9423bfeb06d80f9089bc0e43104540516e51f21cf799a1f71d615bf90dfaf895b6846388bc9b5506343fb2de1b5e0cd0c90c82a05c5f4f8875364a3cc249c83864f9708c283fdac413b91b00605ce8da06eaeda981b37f5a4209c4d8bd0291a9dc005840f28548f243d82b1201bb46feea2cd23a8520f66b205ba864848fb24ed7f22d648f29947393379387ffb34ce9d11399c170072b4ad288e6c3540c5b80a8b11312f384633f190ac158a7aef65a7124a959260db9ff0f1ceb30007b89e58ce0faac3008ec9476a331d8f945fd54d243784e7c0a915ec5c6f3acefa80d96cb87d05a78dd6813dd7c20fd19a680340c38aa3f1f65df495331a1638421557e1966472bce569993e3ad7d9cd6350ac146ad923eaf26983644968b7215e1dab99a03f4cbfc186f09fa60c5240a2e4a7cef4430017c9481ea26289b089f3cd6ca06a926ea2ccec756e3d11044b5f47a9586052eec4c3441d79bedc1f42bd1c49705769e4c53883f8614065c4f170d61c04181f38ceb2e97e334c92684895c815647a5889cc1aa19d3480765fb6b809036b7f236e24acf959e577a5ee9bdd2eb4a8f2b3d577a5fe979a5e74a7a5e1f7a386d6d718159038267ac6ab5dc18633bcfafc3e9181f840606337ac2fcd1cc06a9ef04a80ef59ff84f841e575ee099537049531d442ea54f0a9e75ce6d87dd2cd9fed4eb2909a403020b7b1a2fd15433fec110cb5a0e4168942aa636d3a0d16a2fb7c22c28c0a615d2e2b25143bcb14df79f4c58fc04b3f3e07214baa8d2f59de2a08fae8cfd81203e1f6ebbddf0c00ad7c96c8f6db0562ce246f558ad0e778bdc18ac75abc3dde2c660acb0a0b72bb271bf99b6d8f0670595beb925883b4bba81de556b979bb5ee2608c9fd65da3636fc58ac2e779b1b854ed956bc1381ecabcb137fb4d316baf243b362e35c64108bd16aecfef00b4029fc9d01f85e11d26781517fffd79de89b0496cb8cadaa36a16341533e035e97d04a4e635c5404ca971c5286091a9b8b97f4f834248930b9ab388a3600e0d4b4fa65d0278bc6a96bcd071352c071be8cb51683453bbd48c364e8a57c2fd679ad708d191ed0b17205f8c9a34052b7180761c155e6ac7f0ed2d29efbb27c5ff0df2e48c91d519c85f8e17bbd6b1698644ff2e210ac37bae4e0fecc1268136011307e7b68da2a42947954a843e69e5585e986ce85902c0a24709b289aa815516f5e8cc84eb338f390239e12c0be03a6002b27c0d345240217a92b32145012d1e538a2a4de72ccf50da0e64446cb5431428ef24cc0a02a2029638f04feea44cbf8212b62e0f772aa18f7d108dcc49099112dcf9a05a1a4d713afd77618755a87ba84ceaff15f8a64d2badf750e66b9018eeb45040905e4ce65553a42b8c73902520b607639e0618f842a9f77107465a8449530b7471a87feda3e10fcbf32c836fc28f8aa8a8d69b0c574b8c7acf8a9eeafc80f320260292d7bc0ce86b9ec81fbf537e93dfa513deb06a6f73b057735792353575a15fbeda7e4fe01ccaf107c4af6cae8645c7356a85d36b557ba317cb6359e50f76389117240fb696e7ca8c411038dc3149ff0532904e5853655deab8a3edc289463506ae0a3f99d68ad2f11d45dd0676e5ae9004499a980f04080e73cc93fe7f814c45033ad5192e7f1f25bf8278640389e7da261a683b2be03d32dad0a4ae6a0549649a8cec7b02c80ea16930842e0c167c9740a4b82a168c0bb6a6e27a9bcbc3a514edb7fe799fe9f95d033d466c54674fa0ce92702b2fbd86a2e3607948557b061cea3dc8ae75e98f2b2d5679c1083ce8278f1a343c799f7c8ba2fe1c7170818c88503cceb988f3217c968f7361f6d669e4b4a1b0af29995f6638db0283f81a91e3126178d32f2a318cb1b53dfc3da335744d471c27e4fb05fc35ab70f3ca5efa08f09e6335da4d8ba4d30f26379e2e47072515c3863a4632df4f8412d2441ac82c05a71cb2b9a09a03ecac9b07a5cc448735a934e86652b2136c73f61c8874d236952c5b28a9e1b3355a4f8c15ebc99dab1ca62b49f886dcf1e002c8c1eeb9caff07ef65642fe1f0a5bda422b5d1c35ae002b1d5efa12345c157a681ae758f5a4f3c87106946bb4e46bba353ad7c448de02d821d27910d214bbc9eb7316c926415760078899f1ed3bf4c703c5a53dc3e6e008f97fe9169d05fae3830e80832222152919d387f692ef7e0588e5c62266c0078d431867fd9951710b0caea668dc33a4174cc915eca79d0f965a9d3cdbe88e510b0670a1039c2a24514a50f00b0d25e51df134ef7046a0fcf4075fd32f3f7309b930739212ae6bc2505125a5f6286c8fe7990f6c29b605d435eba46984cdf213502d0a070d14f0aa68761625604aef788edce95add0aae7ae120d5be1dcbd77dae86e6ffcf52328b58f50cd0f464004821644c91a7e4638ca9d5cb1a3971534575bf0b99582305d8a9046f2200cca10ce14777ebe60362c62e0a65e0617fc25c0681bfa9a0e2a1f13fb521cf6ae3463be2d023e0720305a42712e53ecb3d45506bf6498d3e4a4874e6b612d83161af87dcd66929ee7886997f8233843e4048b707450c6c1656a24ef24cdb12704680c06c8d5628516c036d26baad78a36713d003531b36b998dc78125554c9990a472ca7139d4bad352468bcc0927fd0871cbba9cd6a977aa16325a364d1ed59c25b8e2afb45911ef663cc78cfe2856239bfb485a839de4724451a8e3a9394d78daeea1a9306d2c251eab473cd4c0bba8c884da352bb7b061c192f74c527b1a17bb88711b7256a1aa79ab699694b135563786dd8020206d4b244d5b155e8c15234a7f544346055b943024356d4634eb7b4feec613f7e6d9d2c1a1189a943aa251191734d91c98e888427a57d077fd6e1e5c3a83baf7ffba375fa6a9247f015bc16477e42244d43c07611476dd05bb3fb3f3ed98ceba6a17e07e9bdf845e552d8a631ab48536060cb7dd48280812d33a0b46051b06507d656186220191aa75a91aec2d2171d442ee48c4cf5e72bf524b96997e64bbef5adb6e9d44683d580448782d2cc61540e800187993e99ef48f4fa756f111b3292865e1e01a32d5ef862064a9c571a16df3fc67d7c562b51532a03bb67390923a364ec92c8b6c2d04b940c07097feead2e8271eb2cd313ee7c581d5ea493881e7dbb899e371abf405c10242bb242721b945a1abe3041617937f7d78e1a27de81ae46ea3dff4b446afefa41e835cd2fcf8138f6c64983c031f5bb7fab077da8343c005859c234c88f77cd8c250726bdc77bf24ff5849e79702103093905bddf36e44a3c349028865dd50aad4aa61bebed8fb23160a34b567cde7687009ceb067db719723d4975698fdd637d74ffb0323aa2b9dfd2e76fef9c7f9a392b14474e12d922e66cbc230f31f038072d01e856cec0b08b0c401208564e24c46c39524e9de39d18fcbbdafde5ec6a9ba3b98bec8e147bc25f22cbd508483ceb8a58c8340193328e51195471e57a0d5717993ce8137b4270f974a3306188fe86ce26aef57d2c6569c21c6a8c9e91e5ad8572a1081000f764bedd877e49def87c1149c7d49df0ac614270e808a2de337c995d6a346057cee0505d47fd4829f6691b91646f7b21f1b3704aef3667222462c8469b424064d1c627ff6f2eb5fa6ed900bd373eef8fe9ac0bdef6abf7f883779dbf405aa68bc586ed8b58ed9078d9cd5673b0276a164608314c8db416913c2acbb87521730b69cf091d10598e2424b103e5d85691a8474b6ebff63d7e0f00754b0614801aeb0f1b7bb98884d779b417a73b5594c6ecba221576925887f31e112bd4f8e485e65932a7ea624ae81863d615426bce8529105342e7cd10f1024d06bae2abaf1ad54af10466d184ae9693c9204f66aa3d67126b58034d62123495dbd329ca01064507225164856dd2ea956ec3f49a44af58442f4526bd01a8d4b7a92c3dc9342789c93a0fc89a0764cd03b2e64159e74159f380ac7940d63c50d63c206b1e94350fca2a0fc88a3c18c0aa74c2c1ac567af119aede0b77ef87abf787abf7c3d5fbe1eafd70f7fe70f77eb87a3f5cbd1fe2ea7f5f5cbeefdedf79cffa818459acdab8fa627194d9f2a78f6713b757fca271521acb273ef76cef3d0b284f328886e4b1f5baa7cf400b44eb01f9a0b583a18c8bba20d8c0e013b2471545cd82f1a1fae4d6787911c43b7800f7675a3208131ae4651a2dc1f0e4b686c5a06ae2d08883909332f64a8c0e3b21bafb73a8c177c7ea764b39296a1dce64eaa3d2cc2b3023539761342985b7e152fdb187ac7069ffdffb9733dfa555cafdc91f805014abeeef8e87fa84f4b875ff540177f53eab2eea0b015ee9ab54aec0f8977d7e0e0f882478e1e32d9333921ed112698cd1936767165288513a54d1fae358a02c98496232492103e742aa7a792da14feee90d94ef78a26833a8f91a55b8f0328f650170ab0eff4f5780d557b8e287147d5619cabd95733a8c671ed58cc0d0d106ccc5529fce6361e379e79f1ef28913b7047275a3c0bf69233b7514204227314f1b3b726b45cfb2421bb8f5fd277e9b240a4544aaf2fa1d227e7d2101369a90df8cbb10ff83d024bd4731072831356c2116554e34de69342760194213a2b10580bc66501d79a81662cec48ebd8e5096c7fa3863d01c4225a95dc63d72b5faa1b9643990741484ade64b8ad2e81123f593f70d1738f7f46b6f922fb9c66c9b34bf38826476272a0cb2a19e7fa8404ea2643cf09d353c21759f02bc7c1fae07c563c06fa3c99640ebddbf44763c0a84f01932cb4e99578cc4c469c8fd598a42d7b4c4b3dba2c4635f07f16fabfed90f7ea8858c3bd89146947ac962112c364e90508b103d4769a636701716193a6d1b7c7e87bf648b167b3a86dc14a8bbafd7108c3210f76c33256d056af790d86233943189cf5e3fa170f708b9a057cdff0eda542d1060d724ee6407947341197d81d033cc0653932ff84d32dd9c51ce729d852eef7f32f79c5c2066aa68af2985934255e1507cdd25d449ed3e8f2930086b2e530e96bea4c3cd4f7c31a0e3b806f4ac0753a96dd3ef66ce3dc8257517ff836ad21fc827028bdd9a1d7cbd1a04b5ca401ddd225cbafc17ac75a0711471c103a28f1f26e9bb32e44412d86f9487c154f3f57ec9b907ea0a2b2b6e6950b98030e248e532cc2a11a4229187aea5e81a9bcb4b9f024e9aeeb006af73083226e84bf0d094c2ee04cf9c5483049e9792dd00df903bc1dff3cd9a3c1a24560528aaa3167691493399f818de6a5089ed1e5f81cdeb8117b1dcba725c308d3433014ddaf10ddf4c4372b9c5c29883f643133c49292f1e4c51837830030fe24038fb602054cc69a9d0942b2c323f1c0dea23e13036aefc6070279e238cc1e035ffe098bfd6898c8ad297e83901e18c598e6483bd305448a93c7c786e01650947c84d1784641ab57fe4ac50f31e18a81de89d9b20bd2b9502fc3a57c633a2b717cec4ea933deddaa8a5a9523cd492126aa79819e61042a821132856ae4e32d3841783856c766f79aafd4d871399c7725a4729116db4ea5035ec0161d9640c53658cefe2e75f523b1c1152a58d8c6e92edae878a13b17af3acec268c7b5a31e5ad66079815a773169f3d8408e3ea5ec34a500377370284434fe2a73d916141c2c478d4dd7c8c976fc29f26e6e7875a80346dd630f1bf1008db5c8c59b786fbd3c4c84f38f237f8698938b61504af1fb60d5a31620e2dcf3562e41335c1da254634c22e2e6035d61aee2c8f091039c9e853dc85ac6d201e03274d21f6525cc30259d5f9a53044b496168802aded96ee2867a244d39a2f22cc3f5a35785548e41d3e11413ce791ed2390d105175d34ab176451e74f9d1f1c79f7062422ad1f9d7af62333fa0ff65c4e33bef56b811f05cb1ff0028a6b39fd94598f4b8fe2581e4516854c70f8bd4391e68d354814e8f2a32ba88072fe6e6822a625c33a7e3b3aa2dea61174e9ca95061d80b60dfd785ea6c188b0cf65ca58840e083c3d547aede6243a1780903fd6b80cc4aded69ae7618a58e8f770499589199b7346be6d235c91a3e89eed8529d4dbc528f490cf4c82a7f4037050d22c1ba4e87d47c9f686f3df69c82c9f1309b264d98e494c7e13bb6abbc4f3e2131c6855285179b82e0237e785e9c0d5674e9a97cf3a0d5cf54324d164519e24c86d46f2e69d5a04ffd2138042e7765cd677596ae16d5c9a47b1ec07b847740f279ce81d72feed92215af141dbf5f0eed6d79266d561bc608d03c5b9ae156d4284b3ef198da83e69d774392e59b1e96f5687cb43487d19c55e9dc9de2abcf1d47f45e83ed8db5f0e167534d9dad4e60ea863b0f4ed5084ae09397ea6adf9bf621cbce2f46e8b402506d25013ad465d56e0fc40a933fc68aebea2d2d13ef9173b2d35f5f7573cbb5a57cfe5a26d278a032e72e782723d64c951a91aa7bebd9a6badd848526107539acc87d8cdb17b00c35d82c6d1001a40ddb34682bd5727a8b85fa030ba3fffc0417e90fa4b20b6b06eb60d4d71f89637e4ad0d3a943dd5a0db7ab935c3a758ebbdf94f20ce676172707eb386d17f70b70285f0ef4c3a457c6cc6c563180c63b0d4e274ca29a7121d8be8cbbba6e3bc4bcaddc5c5a39f0a68eb96b4aebd2079662c337f69c09913d141a0d19235f0119b6066c975714406e23004119b075bf1323fa5122479c0590804c1981ce0ea3df65deb86e305792c2b85f81936ad322daed83a1609730a44bfee79bcbe672cb4cd3709a8083ba0b1c520745b45ed806b0fe17b68c13bf63aa128febcaccd9f4073367871afd1357d394b2a1403496c096daf8aa5e1b05d3cc3a2001c2150a74540d0d963e65c9c3f49bd39f2d12f4baa976c898d39921de7dbeba178147d656f273d1ca9d35e64072d48a15904801afb85e63d3a7dc18e728309e3e1da6770d16d7cd67623a1000c3eade88e67bb019595f3b83ac33efd5ec31765f5ca9f2e8fe16f9b9d26aaa73340c4998431d1d973cb94929c88114f3c4ed686915b4add03ffb74e4ce26ee6ef6070c5343900e0e859920d9d9981fadd3fc2ee30763a8713cb8b9fa2ee747f20c7e5016703351672138b2ac14175000b9d88ae3b49d0b8c2115c0ca6016245683323c36135e13611f3bc88428a2b81da263efdbd8d9db4aa3de2d07cd9453dcce1302f2ae0d39c620a888bd830b3fbca1fdaae5bd15fa8d36efd4ee0ffe41ee4068694ad32339f48c78fbdd0ececf7830066f0c3f02c2b70742f9ba3cf3f609b76831b91db1412ff496f6bdc1b07d3f40ba829bc2a74a7fb026893b8cb9b68f6cc66d5b1eaea6ca4ae18f3a66284658999d8f188071cc7091b40127d7aaef880197367c144154ab6309e24e9b7597704cf1628d2a47d2a57cf4797db049e3b9a01bf5bc60a25fe6897d668bbd205d3b3e9ac4387d8773aa299bf12bf4d1e8c1bc84643e2118cc4e71d36911fd85dca8a258e4cb35f753b5b33564fd0c01007886e98eadd70eb1299cfbc14f7e60b2e47a60846a6b11c639b78b1b0a06a95e48aa8e71f58b34363032ae1cbcdc00486862e9a101fdb3cd18d93d34199cc053d161016af742b57e1aa0c502006227209e639a8786bc86de35bb1e95993fe8996ebb1fedcbd9083890af4d9e9d376734251caa3991c6774113858043989270f08d499385dc9c3f036750bfc95efabaad9535daac52b935f91bf203e1f6c8741d82fc9878874629ce703cc95a13d6721016f0090df771ce678c03930172f4036196ca09af213ff742e77311961a19c532a7117409f13660da2f3f3449283c0361c209b1e7113717a80e77ed6434ca72f7990ad1c43e61180c32686694e072b7c2ddd248bb6f65c9c85cedad5fc275b689458893e40e5f4c9b1f7d14142a97e6fb90568c261f70c348a2d731579130755382b5113ab2369977cbbb642f561e2bb16cfe240ced2e282f7ec7c3471d9e7d04da0cc10c6952784c490349c8efeddd4e52c3a8c9cd25c4f03ded3086efa94afd83537763c2416547d57f429af2c1841d11ee0d6319656d0a21ebd484225382268f28deb6e375929c1f1d6bf8eec4efe96d7672972f533caa5902cb4ca41b8fabd9a4e3c5f4b28dac1cfd37b6d372f7e324036e45fe76033aef2fe613bae432b077efe3f5f8e9d46ce7caa95ae464acd0280f7c3cc20a1e6a8a25b417b881d76e47d1a319c273c21079d2bc914f6b967cea2735916dacb2dec6b048333fb6f57b913daa226649ef756bf58f940c70a92bdbd795c4fe925ab6c21c0e5775827a815c46915bb0add8e03c33ea472c5707cf76f1e5c729a29c493d1bdfc7a9402389d12386381d86fe3228cee0a26c3761fe184114cc23e101479dad3965602e6596d1b8bf1783d032c2e75c7f5ce191802693c5ec8e0cf721291b95d258b12f84db549a71275a58a09e294239c0280cbef7d9c61a1139707c1b122de53e7987d9b7f2dc2e31b512cde74efdd60e94c81263347afb3eea2d9505f874897aade9592727aa20104026407e3f57d7cf1d8daea6aedd47192427b2bebac8b80c4c708db47870e3bbd9ebf8bc14b01cad21db592205216dc199b3064cdb6a988be6e78877abda8a2ffd9d2aa707c79ae952635f7caadad709d27563f41f3b6b7eb097253e2d38eaa9cf9df80c82f5331df54ba28ef2438f3fe2d5d31df86881677ee488cdf8b8545aa63be51f31000b4e987a12d9ecfa17e625d0d7f215ad2d0c54274f802e48a71132a2d374b2caf8ec06a4939f816c96164daadc0cbd9c81b7e716ba7fa4ec77810bfa418f30702bc3c1d4853e96649977ed27ec4ff35aaf97fa32e32d0439dae3089a3977cd27868d27341316c6297618513980861a55cc3132bf456596422a129dc2ce2ae56872cb8c7519c4ddab5d6c17dd7bc2ab49810288a1c257bb6bbad781036603e6e692966477e485e42e61856839c1538500f6d123f6ab8646ae3e502f80b7acfcca2c93c690c6fdbf8d49cd51835b82ab162dafd9a1be94afef409cea1d274f2a4d223155a105a5092a69f89028ee5fc739c92952dbbe7e5be7c69dbca5122971b4e8fdaae24b4c19abaf8a629589d6e07a54484531d67e5d3d45436ebce32621a7f068f530f903bd2afb031bbe5b85e17385b7e86f22b97dd79f49753deb827593732470d05b42a769dab2c271b2c22a5c6193ea2b943039b573d484b8f8d4f089b30d50983826710434907dde7b6b93ab113020d7e6e8945c7f772013218c2e275eb2637acac706ba02857411c161c5fd21c7fdec8842e2f6adbe40f623d82d3f1c2a86a9b4341664ee8cf7a2e31fb9efe5b372fd3463a58ac5f7de99385733e6d5c61d7a52c8ed9aa2e9404fac005b472fbd2f6c31c476359292e29508b355509b9f06a55a5d4c10015c8a653f1e5409b209237ee3b9cf797cb5bef9f36bf0b97b24b659bee7a49c7800884a180b6003ff7e07920222a9d2a311494422d314000c32dcce4151e94b01309ec9e56311047a1e248d86e384389354029eef12175cd27dca133a4bd3cb0581916cc9907a7aeda63ac3c683bb7d41ca69abb304536e9b10a20051f4e91f2ba94edb6d9f44b9f3598194e8862cc3afa374cee84e5e216196274de5bb63ca2167ccaf1fa2e6272d5631e469e25f2364b547f7996febd8b1ee3a767ba77b1ae55a98902a0388edf5e1281536b5706c7efd8006d9c764bcc64729d8f0f34f2da3dabd4ec2c328d7a98179163ca21a349cb03aaae11916c08098a694412d4124d85b7088ebda9daa7958669b105fdadba74bce1ccec1cd156809ff84124f291652d0ca0d33c690a40c0163ac6e7e5d066c342fd66241d2ebb37daf46fe63d74ba438e7c929c880a2772eba68d92b5cdc986d161588214409569c75f6fbf4b1ab6d9b10ee6c6d2d300996ec4552937f6730b514be2d09e5200694cba830aa99c007d8ded9d3073f705ec5ce25ecc839c05b2b160e29d8ef5671b54a81ecf6f5a5a88af8824a47a43dab66694c8ac9b5ff426393f926ec9b13913527470085e4b7f042f612527e8f103b4c6347a395eb1c40517b21a455a4a488dd1290f878f3baf75e9c91eac7792d1996ab2e72df636fa41cda449da4d9a00483d135112a8fb7751675d19c0295e821bf3409d4f5695790a972e227839594dfc27ce662712648a014945113c8f34985750eaf1e24994da7f2676194c91fa755d2cc6111bfc08e8d904b934568b414b9a7535b33df1c18373e87154b7b6a706b9714120d37508c40069d1ec8dadc89117fda4daacc95a4eefd81265031330ada549efb2c0aee5121dcc31fcc003bb45b9d82d23b7d54ecd5c4f2537fe34b4573f021357052352862cdc91955e820ea1a514d483c299e80d06827b6aeb473339265a311b002ea91ea0e32637b858a2b116acc56064f60202c7a67e242c1d224f8aa2c39d9ea59b8e6b4ff6a3090eac2393e4102e9599df2f4ed4f03714f305c455593ffa970be306cfa2a7cd2aa08b6206254d0e678a75584a08c31fd1d437100b847e0f70fbcff4e6df3c0cb9ac4f987f04a0572421fe8946447a275aa363082446c120068d802daa436f287ca329c08deb13400a2b35a2300a5041c59824583546669703f7e2f71c1b5cd0f8036ffc4e44030d2f8a5db927b78b955d0f80a25999cd5bc86e3366bcd5fb2b15a5849a692d3f4e05cf07ab7cb7ddd559cdabf8ce590473dd9b5665c619e1c954e8691cec616ad2c71c8e340cecaa944c9e7437c7245f3ed9d50130b70aac5beb1e03f604f952449144f09ed8bfc7cb0516afb47476b3c35c8d5dfe60cb5c209e3a67b35160181fda6a4c34419b3d5a4648ca0366ca5aad15605c5d1682c9f28fc6a4d5c45d374c656b46b7665a66c51761cdd1b223b5ed0a84d1b9bd37fbf83a429fbf846e0d22e350e18815a95de013d67d87c611eaba6ecee849d97af0ceb9738973feb8b82f17ccefe00362d849a170ade0545201c0accbd5937bfe5e1067d6eb96cd32cf9b2d62c7598f389feaa561af02fc6c49f9947a15dd7d4560d5bdb0f279ab1c619b7b59f14590ec2cc4dd52bcfb658c620b23cdd98e1b95b5c7e9df184201b7b54e763900224bda97e141b13191b8e96a76638d5b8d9a6f9a72e08f3d697fc37654d22eca311caaeb22f33614b88e795f91c721500a922d8d370bebfc66094f2844b1ee03a6f1e8ee76dde266843cd5911670fee20d8c4a5a380554efe2fb51b27380ad7ca4146c03d90d57ede9c811ade0e314039eaf6d7fccb460c7cf9daf9ac9b97a74904e0ef6a697c31ec5efb8878adff3968f401fbef879ce2dcad20411804e09801011cb65bdb5faa047823172f7aaa805c1bc5df704d49c4f6eed7aba5a087869a62a49f432f8d9b433d9ac7a3263c165d105a567d87eb8d48d6e76de2fcf64b1829c5b8720c000c8420f638ccf33a843017ff4152f474e2ce8a7f52999b664a80e081618ac20307ffdeace50a242866ad5df5f838c41f5b3d8816f8fb744126200bc383f7c8988e9ef2a1dfc9bbfb035e798420520159bfb5a97eba6e0c80225a0df7b764b8792d19c162be09b22b093e3f19797b681281642aa64194ba3ec41b838dcfa5c77fd9e9821a72a132297fc70039691c1762ad373fd6779d0649d9631fb6030765068ec7ad4f1c21b1669177cde3c3446973f1e700c0afd7e27b0f0d8155bd983aa3255c299c73aed8de1f14a8bef9d2747652a10bb4889e607331ee06db04d82cabd81114310e9aca5c7882c6c80cf7078f05a949a618b3c9abc20d764c917cf29e6857451a4498a4856acaaaeeb302978c19e1318cfa099c8376d0e17d22f7a21f446f586c3e7450c69c80dda80188d59b4cb31e89ded101c3ea152b2dc1e4646263de5293613551a83c9863e4b6742537a648deb2436c263932b25077f38924afb4a6e5d2c41ae09d0d4c200dd3f5166b41e6d1a30b51c0074256a70076e7514972a8a9c487fce3c586c8e06dd590e9e982110929238607e32738830ce271c1400e93013fcc6ec4b8fc88b0f20ca021310646d0db47dc66e453a8ecb7a8c1d91c49b8608dbb9184a48c929d44b5ee3871a1adb11c7e778383a1dd7ae87018c643402601a643ebe5c268f773032cac33540332a2dee276a2afbe4769ceda4806843bf75a6420d2113e1d01e009b847f60fdd385e8397f9fe5e6146054cb0ebc13c614338886345749419cddefc18d262d32de37000876cf0fe986df392477030b6556e206530095ea14eda1bd223844f08a45c4b6e2d361b4f3d8c4ab25fdc16ce6b6c4e5fb66a1eeff3a80eaa06302a2bfb826ee23091baa11965380505792e2adcca2a05f5143de8dab2a5fbc60626dcb22b418ab7702bc22d758282ba47a6aedcd2110200692fe4d04b73115d60a7dc17d1fa04c5e92e94edb8bdeda2453a596c0e48eeea7d5a1ba6c91e8dcfd692bfbe81822096dd8c6ece35a3cc286f5b73ffc20125693b70a171965568b8c93adaef04dfb8667b2700fd3d5d6f44a69b0ed4e01ca0b703833bca003de6083a1b718a513b57ac37926080157b10c0d588dc84f22d9dce3225a03e14f66f9aa0c662602fa31730fbdee868a838abbae2c466cb14cfafcc81b18a4d711a07dbf391c025a9927766df7eb2022cd6b4814322507c3c70fd8b94fdff5573bd33a696f62fb8da6899b9fe45c50dc819fd90f0dc5a8d48ac9e09fd1d60f8cbc77719a8963c1d69b39e2557eaaf165ed10da60dbff697609e8ae4fdf66eb6c064f9d9a740d9bfa8a59136dfd79febfc6912ec2f5ccf7359461154889d908106b21c42e4ec23394a22a6af954460f0325a3d14369b21e1aae26160e177e2a7ce241b984e70bc85db565f3d88b123cc5880563fbd3f3f55557fd13dd04487ace35f5337b6cfe5e4531a74c67774cb9ad34646503123e1e036d26f6ec97559100911b7b0ec7fd4519b7ee74778b7344af96848c2e45d8b470fae2adc467d2751293cdc6cc775e02b093d267fb89f52de48628b75b864a97da136bb4ca8f76c72cbc44f72e4763cd49fd9fb3e2c605ebfa229191bbe067ac4aa7fb3a2950aa602a7cd9be927430732ec8ab2b438784cc7fb59ee46f3d50324b52f3d61950716ebe6e735cd11b977e69612d84b45456e3cea2e835bd283b9d3cf7039c02f7c395a2c01bdd3119e19bd96bd37e5818e2b2ebd091b71a89ecbab95f4ebddc77bb31cfa51a33efb4115a1c048a3110dc0839be7b961bafd05042142742f0c0dee004d749ac19c233727de7138542eeeb34ba5d5dd809fe586ff3a412e8c7a9785c87c7fda720ee11f8b85a80a4d20ce06d2165e5c2c836d413af174d1c28b5936e60265215f01e7e249307d545875434b1602dbfee2832538e993ccf0f8c4e1bf5accd08ef28227c59c7ff298afac999e0683b13b9995c4f078cc8f80dce518821eb58f5ee64f02de36e99cf68fd027dde032c1a3a7e8213aee99e59cd765e98891f0b154896070894d42275bb14489222e7a24dd7b77ede2bb07e92b94529aaf29648d40063f7ee4dadb99cd0d071939550cd3203091468571e00decfdbcc6f3050dcefa33c2bd153fd9cb78c718b9d943028ab490fba408d7fc10871bd3fdafcd4b3f66ac97bf872ef59bf5cc5645984c85dcc2ff268bb90ea61909341420a14e22da69145ec6b1654ded3d0dea7de148b662ed601c169067f083c05602aa54bdcc224818a33d5bfbb493087660f34fdf5cdd7a8b4945881e781208b2cec1b2a21a4a8f504b5e529d514cd187f0f0b9228d70c8ffaf7501188677f11b0e4531860434644040e4464b29788c86d3f1058c57a8ccaf845429b5900f69e5ada3f3269bbb4acdff6766066be386559d7c835367dbb670356c6e8fa304c711abefa1ae8dd7ccaaab807f268af3298ea86387ce2aa80f2fe95c623a1cc1c5065fdbebcdb433ca1dece1c8ee70904c2e1c7afb4a53a1856557fcba2e5262a02fded1313a44e7254733fca078777ca0401ad8dbac0ca75c71d73d49025536793b92d353cc3d13facba68f9c6378bf6db5f38b63f23a2d393f9ab78d62bb3497b444eeeb705d53b600e590c46ee55f4f554b69c132ca6a6d88702c1ea737eea3bcb09694f2a4a494bbc36d8903969dcc1b63831047a6b0ec9b40bf0d7c197977b41aa056936b6664164df15ca44bfa3e54781f56e4384fb65f087e8d0484eaf7fc6bbcfbddc53e55e8300cb8d422b5e2a2c6d4ff817853fc828faeab4933025f634ace1104cff99b6045e36cc31698e18bd29b17c4827d4d8412e6c10b1eff49e5a66ea55c30346176726a0eb78c0a460d671d086a054ce00181bb30d1d83339148efc78701566a710d79776dd634e21c816a15f7ced515c793133e5e9d2758d15c59e71bab8ad2e06b2f2584bc48727bba30db95a4369ec158a3dd96368a60d906a66f971c4e441ac8828cea7706b519718b26c0801f13a4f8ea1f6193d5db621d00f3d4b769db7b025e0184b8111ac75bf4d76fb90a10474cb7acf7bcf47630bd6d654ae07b059d5c832cd84d6bd3f6e8312083115e1607358b148152dcdbef29e87b769df46d2aefb2c63dce2aacb7f8b2f1d1a552ce2f98958d12d3d31943707b986d46348b3c3ada822d0518a03b329af3bc2b7ba8ba3e9f0e54926cf8736e87268499d30cd7febdf11958cc45f1ad7bac1c363b39b93568de5c58a8ffdf3129066451629aa8514451ffc370995bd781982f5e994e0bb62644742808cce5bc073e3ca85fc557d5052311b9924fbe74b76d71ce5835dac8a548bcbaf35d4a6ec3fc1a35b7d908290354838bd02264ab73bfd534bdb036cd7640e4340ba05454789952fdf4542bd6cc115005c2fcd2b97707b7caabda6237b23527305ff7bd65f304d85a31c2d717b8b071dd22cee6347a1e89138967552ea27955b58a4c68abaa9ad04892a81b10f3cf993e470e7510aceb307a4dcc5acbd33a3ba3904f5340976af1d7db438d988dd610a7c9e4b63c27088e5c2fb6a93cf01a098fddce243d309eadcac1a7ad7d4b1a69bf8be07d3f29333cae5262d245158e9ebf6215edc96e9d36a45e5343845b30afd106a73f3af0d9592f7e19a7027627b4864d2ca17827d9cfc5e1e40cb8467ed0ea2f04ec34fdf9dd73d0c01b684ff9cacf935a4efff28374d152c2c73130583cc6c88fc3391da78bcd3941ea200ce95252c7f3e7c363710cad250e68c8b273b812cf60ed3fee8151676810994229a53f696ca75b8c58db065120b86cdc537259431c9d7fe33652a63078bc5904c39fc5bb48dcdee7c3b8e324d2f6d8555458341104a14184e99855cb77a1b0a1d3565e5579ae72c36365f19691d10be00838659202084ba42246ddb80302cb5228c1149c5414a5dff688828b41597cf809afbef3ad2cd75578605b60d564ef955dc87d76bc39abdccb1e3b4a8cc7b5b6e2cfb6a751d6157dd58d7b7d584074615e174b5d2764deb87a062756c71cd66d09c016b9464ebba735a2b39deb2d5f384bef12a5c386f0d6de696163b7001eceb85a78a312f9870eebe18ea4d9e4c9a23ad4c6e5eafab08b91cb47bdf4c50d4a0c4331b134a9448d9f32858b4900bed55730d01ea0c03e25216c2be843ac327b3b8b0a4ced81fc20532ca9f694013dfd2a393935b5dedaa6d6a5235a7ccc0fc0b2c33a990fa70a304b813fb78007177e3200eaf2ea92a0b0e8585c133d12fe37262df58febd184b59b00452ffa0e0b469cdf425f036d7d68e2846177a8ab9e56f7695a86f014bbd40a551a2cd73d4f1cc94a1f439aeb0f140d2fb29066a36ddbd12aa92befa14600c654cde8ef1cb4c52be85e93160caaab0ee78e1076cfe3dfc73fec4771dec200b47de0c44ee85ce2bf170397680249b844dfd86558bd1ead0d9587e5b65123cfaf73d1ec25c67ad1b3c61f4f38fb6d960bcb482c9c514531f3adcb2f5f0cc91280fd920090a36ea7e526a038c866aafb163399e7b90cbbddb07b9a16897ca3440e04d789d1003dd8e093bfdefae836a0502d1a6a2367ff8a496687eae4160f64bdfaa02bb2eeb5ee627f11ea360fd14ac4dbce3fe4d9d1b492caacbcccdeca6d2574b06626c013f57374b314d96746d2e20d17e85a56e211ef90b1b3c139879252b69dca557c6c2ff93691afeb4576f0f821233916a5bf4416e027aacceba10bee95690222c0acd5b0a936778b257103165202d259889cd9d90116057e96450b4ae356a65ad6941e92d133cb5c63170731414dd65f6f4b78ad04346c25bf88cc2cc3e7e0086cf8ed0e355623cd5872a5c2f0c039071049aa85f551cba45bf542c039b322ccaf42ebf850fd28fca1263763ebfe53663a3f749f8295df1db4bf7956a9ecbaf16fa6a0b3e37096f12f118b5cc465b5581757b2722681ccd46175aa2a47cde469144a7389b05190b51f641445ba7a3024a8ab24b7f2766d179529260d22f1ebfd1a9c2c8d0e01a4550892748f349389b069846eff1daa9910fb1910f7c4768bd040026e5e3fc78b2607a2435e3239a969b94925e5a36f8915b0eea1fab53124afdccfb0478fac3c778ac83369271b245eb3e5fdd2538b6b6a0fa6121b0de85805ff35c656efd5136033c58d12dc0151db5475eb85e857840b090ff99b898c03f368ecc0a7e16f7cf91a6c48619d5033a0cbb56f748755c802363561bc6d7e9271c9a179a0fb3fd823d7f8902972eb2a84941318b6efe00614cc123457f01d4cee96c0881e83dd866d809e36401e503cd25b9c1e84afa371a0151777e79ec8f0b7cbc49f2f322bcf04435e7dde7e325757838cd60b15a67b0c8152a1ee33e19efd64e4281e2a98a53bb4317b7b0e200f78f100e724a878b202f40ea720f6c8612986c3338ab3388412cb3e46e953bc7f5fd6acfd0aa395e5dce83a37ce7eef015c0f961fdd429f2fccfab59086a5f467ab236f92aebbc1c2c86b361ec1dd6960ed6ef435fd65abb398345acd5db80ac766bbf9a4ac1230d1cb73da482cf6c41c703cc776cee281c5d0b1d473821737b7137981de3f9909b9694630afca1366907fb4098185c75abf63716f73b7a63951a8b3b3fcb1a5bf1326a721bb2bcb3bbd8b3b71ac2ad475a843667ad7483f4cc78827783544e63d8fb615daba56cf1caf86745001de0718cc1d5cc87538d96f0df4f7939a693a875b4a84f11ec2652fe9d13ef379a933258a8cfc4b1168b01732271fb0dde330a1e3ede4fb8952e9756a0b3c5f933607e6fb44283018d609b1a2fdc034bea98dba435aa6e93daa0345fbb29a65640916726c5765a2d1a5696967800b5f2605ac0c865e7f3b3d3a67f47b2a5b182ee86bbcf16c7127c4daea165c5f728be8fd9b769f8991e5643433a48fec75a96ed93e136fdbdd0d9bb44b11b5eb1a2921c48ffc90022718c6e69609f95c8a19a0b5c0c41ac24975bac83879a20d592308c6b4b1439b235c302a27f31591f4187dea036cdd0c465da043ac6a587f54a23e978912ec6320ecf620e8cf9b25ee09f3b88b92d98825485d4121ce7c45e441c468b75abd2964607fe2088763a123b766ccb19811c488c3d9f6e832ac068f48b0f00c6ebe1a521276bf3b674a8722982d6d6fd1377270e9d5357b44d11fe28aee789e16cd6c0a6cca854bed278950d0d4a1e318782d926b36d825460a158c7f6ec7d4787d39bf1821b21e9440c212cce280fcb8dc188759ea5e6b48b450d53fe8e2eda8528cbd8555cad6f0eccf9bb6e7eb5ef65a48b9f0a974df47b7d92cd94d0317aa30b9cf850f0a69e4375301542ca5600f25a873dd0d9268b8984f8b37baff3da852a727c7c97eb555145ab507aea91d17a9462a1ce1e9508c9b15029edd16e8fa9625626a4235ef733706d883c110f49e4dce2d7071a50e884278ce2d9ff03037f00aa21140ad8b7cb3804bc458afc82fb6071810b3fa0c0c6cf71a38a16e129eefcee5005ef98df5d50bda36ec82cfa4d16ffe119a8d61cad760143514d5565437781e5d33ff6c9ee43d704760009cd3ae6dc7c931940b1d850c9220a5c446ae97a5d6a1c36b84c4446b651e6cce3abe45c48199dceb241d0cd035dd024289c009fcfb04986671d4a8db99de2eb01b712afc900882e4809831c9f0707f2972a26c1444c02362623ec72fe7ca632f126cf31a676c6566a4594c397a3f447ac8c55089533cf0f0e8d8220d8228cfaf811fd0439ed5f65c1810ec53149173312e07f45e4ebc4e4e9967b3948a41692649a42164381a73f9939eb61bad6d7524ef8ce178848c46de58771ac17b5f42395484b632aaf4e3d20b4370ffdb4b15278f834ffa3a0e384f7ea9d089e5ccbe574201b44ac40ea36a4ef5294327001ff9780854a82e7bf64d0d6e196f2b5fd4e7a0f4ce30be5fc99c622c0c4c0110767d78704b61758820a703dc0ff96998849d31e08b45bb6230f745fbdbc6496679bb7474dcf69cd249e8f4037d0a277a7d856ad7477ed06853aab269a303a723ff1e3f24e3e252d37868f0a504da616553d82d3bcb73b467d648b7087dc8b3d3a90eae60e3b40e8d1efd55bc9f9a5fae3995e2b6d108947e5c5845bd801f97ca522464cb5dc6e6da6d134d4a281a63101f77d8cc40390b765e12422496550a592a3521750cd2b06e3c76ce8a6499b54efb32839a87274406b32bfdea8c20282f8e0d9831c957e21d1d9fadfdb8e342f2906512fc942b5b5ce54ee4b9dc52ce2f586967c6549cfd07bdbc3dc7ad4c3188d8c5d9552211847265c50a869303a5727aa888e7381c97402fef5d786f1c23490447111a685e4dbdc6f17396dceef76cd8fac1f1c933d098b094d694655e11e4fcb4e82efdc443fe5045c5a4aa06be6cd84e7a8c90346568d756b37a76deb61c0e58f672db5775a2ee24c1cdcfe08d4fa985cfb6e346869ded1b55dbddb9df3232d86a17d42e9606345d6a5943d10a0350984525b9af684f252d55a6fdc7411ebb2010eee8fceaef4520f6d0d080e6c8e6391a632c0e6ca8a2acbf6f841b1f2564c51cdf543ccbdc0e5137ab528a143f7857bb781f1cf002aaa0f5dac192c44c57040a7236cd3eaae1eacc5a94c88a7fce5175cb213d80074c882f12267cf864cc5b2cd594524a90caf59d841341cfea653ec7f41de1c798921ae152ea5b218958f61babaf9ff6bf09ea3fc992c26d7e24ad1993503e6af2ad7f4e8194ca501d8f129a4fbdff4c5210d02a6b48c40fe8058646431a429a84259729c9f311c39bcacb96ecd51931b9daa25e79739f4e3e6727eb299b1bb1addde9ecd3c9255a2949b362c007382097c9e9f10e5347cd1e9ac322857b0b428b0f73c3845a424010ee17a766cfc1c47daacc2825829040bbf15042a4833a5df744f84e14458b4d01302ef8abdce1de1ed9e3fd5776a5e3be79da1831c46d098dea12cf672d1f8c10afa151d29918bd2c415f6652807e2e5a7f76e80bf0bb81091dac329f4b4423f566f482b6dcad07559f1c0eea0551400a17c09c811a48d7e7bc8eb1fb6b2eba77e03199872f847764a9e6733534ef690d9080ff408f0ebe19e2fed193fa46ba49aa7f05d2e146a55f9737ff45f48bfed122062e46095f88bbe8887ef90d49f4e1a9cc5c2f8b4f7ac4f7d1c907e642527cfa0f5f8a189f94d40c187b340ccbcb7c2cf3ea60f809443d9f10a121443c182b09e5f837452a8fbb81a49a853a0d15d7d57a922bf942054f01297f6121602c0425b7f5481aa43219bf4dbcb30250a8efff1f92d3f32ceecd06d29d79af70cf96e4f1d8511499e23cc6894ebaf26e6a5452df9e4f9a9be55e8d1a93d4a83dea5e4788bb354b6cf0fc1a9ddf0842f23dfdd13d8a30af198f7fee6cc796969285a5dd815030a8ca48d053151afb9e0ca8f9b492ddb21f13cfa0ce55cc44684bb9b918dc872332d1924893d9e2549646396e1ccbc8ebfb3dde16f195e205a4c5a845d7cb00bb40781259b288174442fc1c774b1bba2ffaab2cac18648992f1ccd119496df951c88f012397cec0598dde7615871cc6c0fe8840aad050a221768bca7a232b9fe80f02bb90f6982743afbdac1e35365fa98e51eaf44496a4d33049c86031a9dea875d30d6594d0789d965f86e0a2e61c18d036c3bd19ba5eea09ea50e04d432953762fea15531d3559d823336e482798b70c68b03300880000886e2b81f6cc624a831ffbad315746a2af3dfe05e3a868d5ddeb558896defb626b794322529034e08bb085208ee9209b1bb6e0c2855e1489353cf72479a179496bf8fd32de0f843226d1144d336b9d573e02a957a97aefbc9f2f8fda57a168861fe7b79172f61313f615ec24f01decb7c8f9877110e617dcccb84439c0cf9de9b38a7521f036277a59e056277a9de0355f8471c7976e00f79a4523d4ebba8c2fb181ce5133925a9e4542af51324a20269a783451576bfb1805fea59bed4b77c0cf8a53ee665de03bfd47befe23ff04bfdf72f9e057ea970c7d401663d0c2af3d4c5d39f46fe7af1d4fb8979daf294e5e9f7f461bc702133ff5520cd1f987a1698fa18507aaa7b9cf6d45c81e3cc1c0e478994f16f1b903ccaa9bf5dc3f25ff7314f04e67dcb637f7d2ca18eec7bd67f5df829c0fb98e7e17d4cb8e384e577bef0eb9e08cc6b097978acf0eb421dd924f242ec2e26b08b9779182fc45df47fc7098f98ff7ec7090fef637ec7098f17ef3d2bdc71c283f530c21d1feea2cffa2fdc71c2e37b56b84343b873b493e32efa2f92887e944594154aa7312176177e09c354c9850c11229926e357813fe411d6eeaf80dab6ddd46f620cebe70b65d9840a7cf238899a50c12c6f93f3e6cc5df43f90f5de138111818144605b731f4804c60289c062c009f374e8c858a1174e2a79ce30c55df9b5507f2ead1aa605a7ef9efbd27117fd19c629eb190fe051ccd4a9f6f4677840d7847e7ad9f5a976ad375b6abb3d48dbfe4d7adbfb227a3fa59003a663873f68e41bfad0f1002e004a22e51733c035cc097198e0512eed7c7701b60d0cd233e62efa960bd22e0aa4451ac3a3b83d45f96b0b71347d54289e5e5c304387a0086248b6da1f3659037fc0a35cca408208d9e99a188f06afb4280e6c37742ccb97394614d71ff5327cc0a2bf869cde1ff58f1aa2fdfd9126a3c24f01f6ef7ff279d4f7af5af8c99087fdfbf62fea3709db9c8bc103ec5d0c13a6bd043b7ff283ccfc71cf43fbd3773ff3053ff9439c6c3fe4f4da0f71d2fd10ed4fefe027c38f0b799c5e0b3ff9b02de4719ffe101a7e32fc16512fba0b45b302fc6dafbd847d9ba6d13f7d8f21fef7254ca2502d5493229444a0fe0faf5225fb77a7a3864d9ac6623077f72a55605da54a952a28008a4093fa367895a6fc434ec94de403cdcec76440f798728a9c32e50894e6d07fa16b5499feb6529bc49ca7bfbdd3f1e98457f6c720611d7ae8b9cbfe0d3f1dfb5f0c1266c31d273c7ec2ee7f3d26ecfe84ddfbfd4386dc50f48a68a10df59fdfa35f767bd0d6609398930874bb30bfc3cf85dc61045c6822734aa008264e98b4306a82053e593621e49391b26c8288a17cbb4636c102992af7e326b1fa9201588631daa386311a7e3d268cfe84d170c7490c72f6983af3a7165bcb1a2c6c521299f300483e6c4747464645454423067226610072c0934936f27964239720e2414f6c12f95432974c2642fde2e49c48a6aca9a9b492f89e1719c1e40c3853a8c5b9b443f7186511bb72729efcd9833ce2e9031e1fea989126b79216fb451b50f40cc0f7dbf80bc703e0fb6900d23535be3f48d7d098f132bec6f535e2c7f89ef9fed9d335287cb74e08c1ff86f1fde2dbc5f74fa13914f3cdfafef904e6fb2794ae79f9fe69349f98472ddf2cdffd33a96bf0f74fa5b934a970df1baa67f2e67e3f8e8ebf68fe868db70100690000aa00d2e0aefe1a201030488bfd3340212df6cb007740119c3270ce66c089046c8153497f08ce252df683e0fc797032e97f01ce206690cc07cea17904383d703e01671138a1b8807305cea32985059c485392fa53e0a4024e267036750cec13d8b34602e2e884a32c92479ea50ce713368c704f2bc91136b1f1b5da08bba79774d3e853948db331051ebd08cca45c037d6ea604f4479b15ba66fc319372d8e47ed750fa14b4c9b1044cdf05aac36316dd8a430783bc41775ab8d5bf470b4ce99eb23a355ad8b255b745eaa0a5395aec1bea84325c7184878508f2287a7987ba4550502c8845c4f2de6af7f4be62f5b07ec5f5b0582e2d2fffc2f22d2c2d302c600b4cf8b900f3aa6701e6a545c502ba7c0be8e2c20a776866ad42215c8f6a47480f12ae67944c3d5c0feb715a88bf58210dac984f4685c3f2b205af6c2c20101a587e94492c2190205d0384e5c79955214b28694875a9ef680022a487eb51b13c4ee3e095969045055259c3512f43a93d06c714934c62c1fb13386ae1ec219a3d4439886c6c609a9b22060ff8f348696b62e0c11df00a8e93b3c9508964c5d20b15f86b05c5162738c3a3249a4d450a031cd279657ce2f80944a1266b06d2e8074efcf8e0c39c53ccc9c1c9215a2127076705fa72e6f9ab21f74d6e9b44a1b64749140ab5a15e6e1bcadd7d3ad52c0de5db0751eeee1beaef76effb751ba44883c3266ff3044416b1ed01d95fd6777094c93f64b20b2af057aec73ba93c01fed38f58c391c9f51d861198d6170e6d95453b6593fb1594714dff293201bf880506f2288d5644983b011eb1d7a24dd23489c043041e2210414af9389f71c09c16e5afd0a2cc6951d67cfd14fce8cb5c6905390aded5e32538074708f86964def3686c69a971401e3cdad87072bcb98804b84915fd5543cf06a1a21058768dbc225f91373902c941e892e53ce78527b9bbdc2f0965a9a3e02088201c346a290a0ea4b49c3638c8fd384f7267af762cc82b9ad4f7ce0579459ef567c7c3090da5ccbb6c76400417e4511ead3ca86200fb807d489244d6b7dfc38738e1314476b36e46c58e1e7ae83144f61822bdf69a284f20ea9cb5d21f5fa7d6b9c2f5561f252528509c10c97b3a695af855a4f0bdf3745a2541c315818194268090650164d904103f36aac04e64fd390ac4d24e870d5bbc1ac0e3e7ae79d189a445d944d3b4f6511a116120043a902571916594a522923c7992244937eb66386de307742ac1329e2b3b88672d1c89f4df7075294b8a944de41f984be015c65cbdb749f7feea42b16eb683c17f9c99d3341947475568f6d46251e19554c7c170880e905314838e11037c1c396006a41fb3a21f1a0fe6c565d5c2a2c22ba98edb282084a9482c7664364bd2d3b3c48708cc3c05a1d9d3e39554c76d2718ce01728a62d03192c1875684c846e68b6179302f2eab1616155e4975dca6a16e9d470c191922fa268a08a9564b354954799e0706cf0b1e173c323c1f4f0c0f8bc7e381e179e171e159f1b4f0b0f0a87830cf0a4f8aa7e3e178361e14cfe5d178a638e239426d8eda5c5aebd6de6b51d46b7b3d692fdd9eee448231bba453d5c4550b8b0aafa43a2e061d2306f83872c00c48230d49370059daf1919a3dc9a43a6e3bd1d0dcd8d8c070885ec83922a6d9935865ab16198b4c25c3b215594ad6c938d9263bc950b22bb33b42669229d632ef0e9a3d55994c2693c96432994c2693c96432994c26939d64329995a14e1435edcf1345518afa79d2aea596d2d3b5d49e50a8d3adb3d812a59adb7a51307eccf13f1600fc5112853fca24e44f592803652f83217b21732193917db218194be6c960642f3217d94ad6226391f5e0e3f3c3cf0f104040430405193134940411d11245454e18194d7174d40324a48945922cc9518f43e7d75a47f9add5a2b45ac31b50da4f79834ed76a45698e428552d6d0bc56a73bd94ffeede10db72d509ffac956a04b00cdf7f457b321385328d85a2c2abc92eab84d43dd2a917ed0a039b1c9d61cc0e9c74b7f44d51fb9fb632a4bacfdc8b2fdb8e27e7ce97ef4523fc6acfc28837f7ca1faf1597e0c5b7e6cad7e9c71f9517cf95106cc8f34bc1f6db07ea489f95185ef471c323fd6b8f8d1e6c58f3793b67c01a2ae0b9005cb80319e177e0c284364812ad0d0dcd8d8c0705ec003e414c5a063c4001f2da003666001471a926e98372820049c45624766497a7af0d9c0f9c3cfcf04026888a02023868692983788e68dfe191eac6d54dba8a6c979baf7e5a4278a43e713ea711a154a59e3d61923d8c5dc8eb4e7a0d2aeb45b7936b79291eeee757a1136ea2da56c49e70df9efeeb4a607e09cb4361ffd68d8637bd4b6811fedba97b0f7b96d8fd3d73b70f31f361cf8d1104715d8fbeb4a577df7478193ebd1b02d94a826a8afe037ffe6f928f09ba19430da2eff1823df8100cf1f5f6b3ac552ee95262a19aeb744e6ee53e00117718ffa1388fa2d852458b678aaf659a8f5bb7aaaa7adfb2d051edcb5eadbcfae037dccb0812f8ec03e68a64184a860f8371a5a14faea9aa1c5f631830c92a60a3cc449f743563ef54358be0b53a10c79b084aa504c82ef49cce32c4a3d4e7748781a85b3e8ed7720c0b509f8874db6ef33bfc5cf7f6d38672df6b448916400d3f0a38308f19b83d4fc629c8b66d19c4191227976510e13b08f195c3e1ac0331ce7516e59246f0090fba791bc915ec30f2f4a2c7b3897b84e1db1252108543869821415fc800537960508565e78a4b9f3e88f5bf4b0d773494a2b6e307483288c28e900a50a169c0d2870ff88fb67d29190cc4ce693208db3842de916718f782eb916db251282a016142105500e3f27d09a3084a1cd69b5da0b9e8b99c6c63b80f30a776620bbd213d9dd7d09ec7def0d470de6ae4483bdff9648238724a400b34c51e980f113ab18d440f582232c8ef02acb284018228f9f04849fdce203202419025ec9320a107880c05b96517ec094c77ff1074b3f88096d7e9a94d28bb3bb7b8ebbbb534a414aa9e6d4bad35a29cdeede6ab1bdbbb57ed9dadd3853da27cec1cf7386dd7d726942a2f5e4d56a577e8e0052c8127bfe21c5f98b3ad913aaa236ba71957aa5cea1babedad53a54ea6a2c1c8c57389745d2289f50f385699b7901d52ee7f461b8bbbb1002cf977f8209f03c82e7d3ff29d8f3fc14d76d1bc7d116a5fbb6752869aba6d55a6b3d597094395d14aad65aebc59b8ad3b854b7b2625964cda3bbfb76e486565569e1b60ccc01dc307390f6db35eea194215d71bebd103922cb9823e413d93249c0d35d7a2b9a16ba1031b9665269a542b432a9b452215a9930a1b5aea032a19a11288c30b9468a30328b3082aac288bbf59e591ad6212298acb80c517fb20bacda95b556bb2d940526ebe9e6a0e162a8d2d183b4f09e542714b699403f9364f92ee400668f0c8e7ca55edb50e0b66d0ad060a71088bb82f0047dc8855a6c3fc2859037faa110d1774371d75f2b30f9277086ed45147876d2c671d25f29981c5a111565a3dc1c8f99596743d3d1d0bc90d3713087c947819e8bfe42c1a4bf4e303984839280ef55b170d2dba779c8f35b07f99a3dee9afd4a7541f390470f9a3eb9df87041e54875cb48065c8f320d183824e288107f9eb05af5423ad5747c0d49b57ce1d0c81eb1e1e3ce1ac684235673d3d28416a0e11155d91441ea7d17c22cfa32925cfb93499a614b52c4f6ebe1c1b499eb37d60642872f7b4fb3b0505b97baed3d1ad32f75ba783e3f2b65d71246f3d10226f8fea746c18f5a74e076a06f9f41249c7494ec9f7b54ec7a5da2a6b52640d090559b3a2080f8c34295f373d2c0144148359ccc40e96208bac586204a300ec6028fbab4b203bc212443158ffe46e9eac10bd1d007d03968842871448017485104c50021128ecc13081c7cfefaf29834a41caf429fd5b0511993e8e5245159952249490695121041b524090e97bef625e91c17c228fdc1432a0e203995222f08869f2b89242897ca7d880677dee4a074f78c04707588800e90803b3d9d1068c1875e0e7a8043c1009cd8e90d000d25114244753f4301d61b1c30e28988e9836302405068eec78e2480a1e8eec7082488a101cd9818323294c30db110592144e663b72002445114976e820e62e1f5c1fc4be24a2fd89c562476ac0c32c656bf00449aeef2c328c020111185502171460cdc910b8135211611512ab2d30ca899512523c80352c5445389565941a14a1c5881a54911329168bed5095e8c9b5d65a7fca1ab0a028d7ef95104a8ca04509e6b28ca2c4095ea0c4101e02a630317124d32ca34c81228ff8b50fc452b0c407cf902c65ba7518c7a42a55ea7ec7f278a6361b51f07dfae011cc3255aadf897955c883f5de7be10e4b158e9228c78072d6cf29d516031281792011588c0e958de8ddeb85a3c71ac5d4d591b9086537dc1d478b6e83365b1dd4b5c2164201ecec02656ea47e42e42f3a2bea1a7a744467ee4f8fe69c3de5be2739c1b6bf85fa25611de4af460ae90c860eb8f36dcd7a0aa5f48909a545a3301c6f8c70c4628c979d8e99c7e99628b6c496d8125bad274459e0d6d324a54973eb717a6b8132cfcead704eb9c18447aa01792381995bf22685dc4f95e48dc458d6a59f99096992143ccea5bc8409d7e9983f4b7aa6cfec49bab33be1e752f81d7e0dc3a7e1883becbf94e6a44b2f0d1b690a55127190d4e212131ac95f74e62ece9b61fff97dc4141a82617e7611c953c9cc4ccb5a3bd36ad518f367c9d77781482cf494166f6ea4ac71f3dbe4acb5744a18bd34e952902acdf76ffdccdf3933a7b7e6ccf48ff1b283c1c31a5a7f730c14c2166e166b27d59999f938b4c48f21de9f9969cdb45a4b4e1c94274541080505f103c4e4c795f812f771251e124fea9aced9912435556a0f5dd662bbcf94a82c29b9775223f98fd265178324e2310052ecc689f8389d927a8a26791e82acd1f4eb7f2d740d3f1ab240f30da9ace1de7a6fb57ef2e6e0d8ba69d99f748277e786d3dddd9f823678be2db0c9cd6f960e6000214d7257e77b0352267735046ca04af4ef537a9dd67ac3bdf7ed0d6bf0bfd9521664c6c16948937aa874e00f998482127c69849f3f8d772199a144972815ca449bba2656652d9a44a9d0251748959a70f82880f74570268c01ce8fc1c184e74b14c0fb159c5904658e01ca3c03cace9fda16fc290d8378ee991307a7fe74d635a75367838e195b6388bfe3d6905b3f3b1d4954892eb5488532b5d8546375764228fbeecb3c694f69b1931aa945edb5ca842a5126dad462accaeaacf65425d5bb8104770713d2a4169b26d1a872d0a4252f3efc85dba57d1fb5842c4c4937d44c9350f7dbd153b2a6d91f8bc4735e586a49d463d33db448f2e9fee9e7240c2df4cb0428e1210441fef8e1b763669186474405288fd20807cd8f3377f8ede83ca750b1b97f3a28c78f8dcd516e221fb46813e4bd187bde3f150a72f98e754dfdd46f96bbbfb2b5d6ba62b195e59d856543d5253a93a4203de121a1d135763ec99129d1148af1622693bf3c8f0906fbf565aae5eddb5066179766b15cba533039c09727df22d95fe6bd4f3d0c389b2693164d2d3ec803e4ffffb7c9ad56acfca0847d16b4e17bd9adc4d58336345aa42d936936c552bf4d2e054e1d303030dfafbebe7d99cf7edfea03a90bb20cfd6d057e37ac56ab4fad522bb0be05bf0f07cfa3b5fed6596f572b6b57a9effb0aa6acfdefb3df0ab4c1f3f7bfb14008d820658d15183601b3b57117d501014aedd7ef77f918975adbe5c11b6aad35aca1bd7701dbf3c2c98452c94308350135210494dc4bb31f265d3381a864fa4d044dc9f4675323c934888c84ad72b25b8523119fbc7a0b8e739412850ee0ff2a784421d78ff98ff5328f41aad8f254a6e5472f3f28765e03850fe0cfe5bdff5ae8ec859f4bc802cd1d4a592346e6efffbfdf58e083de129845c36f91fe17ca8e15baf0a556f62b0a4ab08541c5c5d3174f9f3e8dae89f9fa2cef61fe65f5f473bac6e5e9378c17a06cd105285b94f19a70cbcfadbe07c684413ca75832bf80d90365667de0ec5232b3be5f8132d7ae85d4af566110cfa9ff6aa7be97ba26c582f17ec7ccac2fe677ccfc3d4e4fa6ae49c0e782fd76f90f1469d0b0401c1ecc8b0b98d3225d852bb4b86a6a91766c32b548bd2d704b38e2c9941f40c3a645fa2b600e9c15727478b4482965123b2bb078a958a9c7647a668a0e946c317ab0e907658d1f1162044620c0a38de7f9396e30611b7993429e9f43de749e8ff32f577c8722c0adef981d64918c8d2702a424db9dbf6366293281fb4f7f92b9431c3ccf4721099ea14d8843a44193638524601d37729f46f37568a460ffb195bd65826d9360a5c161038e136549943d1c71b27d99c7dbe4032804fdf1622ab16cc31a6ad84e501b1a3e8c5a6b9552ca3ba994524aa9a3ce916628b64929fd0ee9fc16999c63f256bd0c93b7eb925779db38bc92eab8bce5ad65c5b9bcc078ac986f7321e3e2850b34cf5fe571677e7b0bb6eddeeeee7697d9a9c03377774bf795379552dea6f2e640732771ef59f764f92f66d86ad77f2e908f74853d84ed768dd3d098a72cb3fc9ef402b256292badb45229a594a07b75f7bc5a64d581160c442570f880060e722c4106051e097006be1271a9126cb2e06a0e383970581eea3d00da9336cdbc216988ad97f15698133b40f326658d53a794527797f54777f7eaeeeed49dce4ac5a96a345e5c562d2c2abc92eab84d43dd22b118921e9caae6719b8692218a2ad0d0e4306263a78a2dcfe5a958c6086a5226ac24ea5e168c633c2ffc3f699a466356836ab5547b12820fe3850b992f86e5c1bcb8ac5a92f4f4f4e0e3f3c3cf0f104040430405193134940411d11245454e18194d7174d40324242c9292844e557bbc92eab84d43dd18748c64308244b3278fdb4ea86b4f1475a2284a51274dd372d8d824e154359954c76d324451051a9a1b1b1b180ed10b466ab0d250b7d210ab11b6ce39e79c73ce69ad0d6fd828b5d66ef752bb6df4743a713325cd9e70c4b03c981797550b8b0aafa43aae482c7664364bd2d3d3838fcf0f3f3f41cc947a347ba2f1e2b26a6151e19554c76d27d42d128b2199b9cc7ba4d9938dcc17c3f2605e5c562d2c2abc92eab8edf4c3cf0f1040404304051d316341108e189607f3e2b26a6151e19554c71589c58ecc66497a7a7af0f1f9e1e727082020d63c2541b3271a0fe6c565d5c2a2c22ba98edb4e4562b123b359929e9e25b31f70cd0d3678109cb93ce79cf3decbddbbc5265be3f74b6604d3971979188f57a9027362df080dccc9fdf1e2da12752f0bc632de1f8152cdd6396532994c2693c96432994c2613c25424163b329b25e9e9e9c1c7e7879f1f20808086080a326268280922a2258a8a9c30329a22631305b50d6491ace1326b5f63b9c6fcfdc707f9724997bf24f20420441e4fef9d8e4c0b831a885acfb4dd5b17ac457632d97e9985ace11fa532ff3aab415d7344bf662c55245e9764af42d969ad196916d9fd2915da949d66216f6691bbbcce6acc5f4e1de4cdcf25957c69eff74756f6d145f6fb238cecdeaa505abca006ca8cd8c0eecf2eec54a5e45ae42eaf46d98f5a74a32e6ad1fdbb17e0feb18b564bb451596cb235d29e6c276764c10b4cd82c9229f4b76880a791bba49277a76316c91a4d3ff9f9bff653c3711ed19f0ea2323aa3b116279306ea9f5934c326d6b3a1c450a651b70596fd4339100513283aa9d47f3d1e859f1514c5601aea3ffb55fbe8d7630b3f1bf6e0be86b247f879d8847b0943bd167e1d3639bd8469d75dd30852727bd95d733e0a14c215b973d8d8e0b8ab43197cc8a3d8fdd9366e0b400cd3f7ffad4122b00912816df2c8870c33cc943c804652914c3124a8d335a2c191236b3a3c1af4de5d9a0cfb988186d9af3d8efdfae34dda5f22b00a1281dd17dda53d119805bf1bdec0a3bebfbb34ec2eed6d8841c2ec7bb8b3e3b94b23021b456dbc19e5839a3e4b807e8a9ee8d78b1e8944111f26a1a11564247896c8a8d3d590e0f9c9daef74cd14ca1a11799c3289c4054c90b597a16b50c8dafc7197f65593cd2077b978f06cedefc5d8a6ca70fdf1970512425f8369ef5a58c344aa5336d97a5102f76c8d603281fb471b04d09c42d97dd65649a96bfadda9a5d2a25b26bbd462a705a63fdaa56c7dac528bfeb3f6182fc09b4fab94fdad120b08fc1e64e393e74c0a9eb327d9df89ba86be5542ba5c5e7933ad0c40d6c9a964771742bafc4f2aec41a30dcaee4176488aecd6c76d516e22bb2fb5e81e246bf88b54b4d03ca9fb9007b5e85aecfeb0c9d61cc164c2af5fbf7e5d8925e4d3a61dce252d70ff38978ca6d20b80f0389594bae65940e0f1668ad41d53c2d946deccc8f57168a8f5a5ec17eae45a773bbadc343ae0cedc6fb40a40d6a84f63051895bdabd3abdabfbf3ebbc3fd29b4db9fc2a7271d19b7d100a3c2938dac51bf5584bf16b4b7af556b6bad154bf0f42b48b42d115b0f8dbca99f43a6205fb700f64701106024408e190dccfe68802c3fc6da8cf3a204deec072c9005b241d8207b64a75821eb639fd8226b64a5d821fbd335a3fd406ebbc432b11fe82e06090bc20659202db0ff68817237929cc91a1fa54b41424348af194b474031ca4da94f23796ca53c93377366da447bab3d0902434ae4030defcdb0f9da423ae4ae7efba30d2d07eaa738794e5c4c67f2d84836b44183dcc55a82bba7674ce0f963cfecd29602fbdb8b1278ab49a7296753b10a3c7aac3bc8e2f76a117890374a6a92bc9991edd7257933fd45ad0ed9da1cea12b2b53feff96be5bbaeebde67e89f0a3d6f0d6107eb528734ac4beeb2efcf5495b4ca94eddb9611b82849c77f7635490a1e3ba8a8593821b794c05f0be1775bb4ff692ff39dac2af0d7a4d38f35e974c1693f05e6ccb183b2fd27b27d1f39feaa3a907286e3b5cf92af0ae4c99b599b00f3e8b1f2e8716fadfd0ae4af1a04e9b27f526d1528a912d5a4f179c8f64771ac47d9fecf5879a08516a826c91af6452a5ec2ac80091b926d5daa4944c06ddfa5871b42ca175c21d42d451042cc59f344022285f8ebce1990eea734f4668f4713059630091b6974c0d23e4e07b13dee9aac2660212dce9f34b93b083428420b17002159324bc2405a8c718465a7a30bc2a35c02d23512c95b4382fee6ed80e5bfd00a01d60973e64c6a4fefd39f41f7ce592c460fb0ecba22622777709be519f206757a0e941caea1122e84f183e5dfd79c7e8e8f1774649881864b374a25534c43bd5c9ff4eb4362c209ee07c8672cc75d54b24a20bb2060fbe39c4d24ad2e09cb1fe70c075d1e6cfdb2b5cd396d10a3c0f7afbba6b4321c25150d14a3c03794ee9a3d9bfa257b3271799c4cb8918cbd24cf20f2e6fb537ba894d922d7cfe1d1af9aa0284c0822e3c815db645913753d4c10b22debd70be4fa5276aa055c516548816b7d4ff417fd205cce13df08db94319168685e14268b9ac6ce4a6b0b06f029cb284d4668d2248456130f9ad0d86a6d9540f841e203265600844fcf95298153e2083c4924144650b246b8006eda415315344d36681a8a59a28ba54b111e3d4f94791a3436fe55cedba20c8d30b4ead1d17171e75e7c84634e8bfd04bb3ce1695eb839e151a82c5fb2e49e2f0a4c21b246ff09e0042414a3272dce237ac88eddd354722f99f9a4add3e1b9bb5ff05993e52cf071da41d64f10fc625cc8c078d9e978f1308ed4624f29477302f2e684ef17b2894c60a5cbd12529d80678fed216b4c7e889e6868284baa889fac9921f5607669e4eb9f9eee15e7af7d2e94de8492f42e091cea8129fade7bbbbbb5f7aef0deb92caa4474995d51953938b18c81b9f39ca7d247231b8907b7ae414a92269f1a8c53e9292023cd2d918e49b2a29c2d3018f74e64ca9263cf3a333cdfce7c9b4d8dd1bb5d82b9ff21fe99d4f99744d53241a100d6a9245eea74347f4d327fd5409f5b9d32952d7487121e870147820f77b53d7c840b202cffcd8487d14dec00805570aaf82cc00c081a46b68bac695744d006abebffe30e99ad7f757a0aeb1e91a017cffe6027164ca7948eebd41422dd280f37180361e00e08c5701b4f1298033de410180f36d401bff02677c0d68e30300ce781870a099c685036c3d0040fb2a80ad4f01b42f3b1770a079865d14f6d0dc71bf7eede83bf8d170077d193fdf3f01379c1fa4738dc76918648be10d19329ed2194f6584367805676c978349028b2acc1b369e8236fe82366c7c77337e763a549837ee6ff7de2082a3c58be3b2d33163c65fd0c6df00472279c6cb4ec78cb08974d808fb498d508579e386e34e38ddb65e76b6f5136c6d276e762acca0b7a8748c196a92d4211a1101000020009315000028100c0643028158240d6361780f14800b79a046744e970a63518ec3308c8218cb1103880106008800c8d0d04403e1a4b7c526eb722558ba2e62efda67a563cf65a89dfa358934ee27a84f0bea3e46d05e37fe21b4962b3e359f5665127c65f92b8794f20e42a4cf3abafcf07587011b4f507765ad2cc166037cf89c0c04f2b47ce904f79d2652fb2391a9ac6a4140cc0374d70fc87e8f1d9fda0a1467deafba2fba6b7de5be086cffea4e7378873dc4ca80b0c886e3bc751f69b35a7769d926cd9be8c3bca3821e83bbf70f56e2c4cbc3f3db6e6941761081ba3f1dcca92c7fc3624115e604a6b08fd506f437052fc83e4ac61816ab6f3e56bb7813f21caad608267c1595907bdeb87508f5453f1fa305f740af64fbdd0301badfdee7657e4d5ad764a40aae06b0f79858d61edb8f10068e060ac827f7deda1c123e08eb13a96aa2ddab5077aa16f4a1c36a94fdb6d02c1241da2874bfd0710663696dce262e4aba9e2e5792872bca6fbf154ebae30462d11caaf431865410a18b9163c1bfe717775eabb86d1f8b1da29f96e96f561cbb3816c295b9d64f81170f176c916492192536249c4421c3fc94b2bc6a896f43a5a8a8410287e169070f232290af1f1c2676aa946f869c7350bf4a0ca2747323186ca913b4461831300d68e3843393897a75fb436f16699b003c4cd55e1ce8ef2d1393a7e79d97d3e820f8e012bbc30b89dfde941cab6e778b78c72cb35a01c47ebdfbf4add652770dcc2da9eafb713c275b2e1bcde330bd7c7b24102e252036ddcb834e7d876f154826c77e26478102b7cd35381d3cc2a940f0ed9eca96718bc5fadc25db1cbebfeb1500ffd84888ed8ad7ca82ffedf31a1da877993b3fba0810c5adc8bbde205756e233ba7242906f0ab9768b2cec1dad488216735184a8298db86b1fd182551e45bedeaf19e4ee3a3baabfa0cc75bbb9daaa8e80b1e7620468ab7a1d2c35a0620d0e2c0686d5572ba16a5ab103d8ff2fc55ab7e7f87fc809cc04cb894b09ac65aff91311eb359dacd45c6e816e177fbee9c42f1f17bf3a22871ace5ebbcc5f6aaad2d59790249bff3cf150012549d82aa2abf00b0e793951e538b95e05bfe861308dd85211760cc36ee5aa6438ecd9c92e654e75001cdae40d8be13866b6a4dfdb4b88d20c903b9754d02eb76e5cd70fe60727d3472f33919909cffcdcc140a3fa69842a612686a3e68318ff34267579afe11acd14ed0b6bb28e0241436abe9e219fbbce1a9b964d7ce3b1142b407befb7791501afe578adc61c605bb65734b242069bb41c61614bef453cf3c2f3b95e20e014d7a55644d78f9cff2e805af9396d2acc4695df0a6dd3fd89d27c6dd48bfc6ed5bbdaedc87e44e443e3dd5f8c5a67f384b571fa0c5458a162109cd62f0fce96db4f58d6a09970397dd537cd454949b169c9844b9ae25be2386b57916e2e159f2369f0e1d7833e9236016c6d7c8b0116deaf59a25b250ed4f7ff71ec3410ae353c9412e2f51fae5a491a9a5b4e2fc013937f6867d473f1fc2b46cdbb8a69224833c5eba31a2b3ac911efe8093fae2283a79a2b8b9bc8cdcfcc782720470f616cd60094295b9409a227253d2c99fc12b3001651e689b4e845ef204ecdba4629253d6184fe1b3d97b008d2791627e587dff48a399b0f2778a056f6296179f4fd942a5ee5d28213b8840bd4682e01477c3dc2c200b10743b4a552a461474a004fc00ea8ca3a27d064ad68fe495107a092b7bfd74153e1aa104e1e1ac9404e81fbca6b7f4ef4a019c806c682c9349d17a155394fe804e827d7fd17f9c44f9e8ecb616c059843f4861e44e5bf44e216bbb52db995e0ce52312b53270a292cfbbbe65575c4055ab78a446f032ac7e8a6eba63c8d6874ff5705b8bdb06c00a89a3cff011258facb3a49e0c8b57c3af04457cbb8a407b81a8a86461bec40a62eabd58441196c6e45af41b0379d1890dc065e0520eae6362834f4299b46745abe606dfa30472a463b55b7251a02ab7e4c93f24d93cc02ae6a804466243a201e67bc44c3f02c20f90e20dc21e0638f593340af13e5219c1a2a9480d1b31cb1dc14b21ad7f57aee928d1c6f61b2e1cbf01cc19913de7e4bf96ba17dd6473be1eb9cd32e4eedd0469653245f11a9c057d8f00c99922e7526e15a3e54112e579dd2b4feb36bd290599b362891d3d9d02e0e95d179dca672f212b128fc3f98ca392ac62d3fb59aa6a0c899f18c6b43cdc341479ca008992892f621931acfda271cd3e16fd4ea249cd854291edab523665776b459788ef4061124d83a1205d906d7a077b1acb8f5b38805450e323f6714f7039d8366c8ed06d45e5cebed3adbf86656e0abce3d47837ae367906c86d82a739363713d0b5e5df3b4e5c0870e4be68a71177f39571e78bacfea53e6e042f47146058434d970381f2fb48428837a464cd0de45174e6d88f80e4eae4a21dd0856e00718f5c440bd3c7a66971154587df5ada008b7dea33ddddebdf49f6d1f8fbed5d0f988ba429c8e5274ce0f4c115ce51e524213e982b8e179950d456cc50e31d8582e95b2b9b41ebd81c5a50080562b24bb96b52d34cfc595fca119f21a2b4d44efdf966a8e6114ece1a600aa5c5690fc7a1344d006589119a91b085301e60b928e75e9f13b86c6175679c2517dd5033c687c6ffac82a0f1434559fbd4f2fb4a303652f9b22b88fbbb33671a7c2aea1dde870ad48bd89a1996f1f47ad1e2d4533c375a4203248eaebaf890c7d4cc7a115313075533a7114902b279afcbccec10ef32a2de5877aed0fe676bd436e6fdac55c19714cfc0cf2b23939e54645b133bb4d644720a10670275948a1594b7ce0b3c6882f27cafc4b0714a44364c63cc7ac9fc3bc503661710700df7f7215d9dbcd1dc350da64e576c4096b8f8e7ca0507e1cd82d1bfc337c06e9ee154aaaf299e97d86311a899d47f09528d6ed205a3b9b31ce4e39b1c80b8cb1675748cb99340d732348f891cba326e0c467688e7a5882b937928b8e333d2f24d49f902e17ac10ea14ca75969dcd8a8ae1ae18065ef2093e4632dadbed3e259f9236bcdbff983f2b3f37202705118c636027c65d04f42644df98272855f6ab24777d329615522caa03a048fa7bb0ece945562c80ff29fa4b4aaaf3cc18ca62e3a436b83120a8e2c4b3332c65911d7050ac1e81d1a7971634aa7e2eb81bad7c41c3e61da694856ac2260dd3d0959337499c523c24fd29ad2b12421d857798c204d02d593657c4b57ab61f488ca4b3987f212e02f1fe13c6eae3d4907e1ef91afbc9c9d3d39c14852327e6cf74e0fab969a5b2a53afaf8b3154402e98454ea80b7280d21102eced0facb1cd06cc37334ee99f910930c8114caaadfdb80d5baafa94710d15f002444a794a76cea52893c0c4a0e9d6510ca92204bf0168ab557d612db22ea65c489f852ce924f870cb16409971b3778de7ab29808841c5a0c781233cf63b131a5d01752879f61a639f2dd94b351e5a3b63d47ff89490bd7c280861a27b97fd58103399921bd55295c3207835cd72e57b294adcfc98e9faa156b914f7fdfcb871fac40e22af018da5b84a6461b586bb7ad6c7e675f85f523bfb771f3bd7132dc6526d9f3f881bb54b0354a342dcd4f34c8b245838f47625ad4585a80f5d4d541c9f75e2a14cb42f3722c97ad5d43391787a166eeffb449735c3b586396cdcdf8ab64cd3ca56350735cdd63585d2fd830cfe4c7e2d1e5750fa528011c570ca5a40747e4cba0e0b05202d80130c302179bc9e4455a3b1126e264c2263e4567e07fcaaa8d0b70040f17c68997ba012872f072654b41c91b04becb438ab22a181b9447b741c893b67270378982a265fface043e86ea37a28aca1583fe06f6d4c789701fd7c90e0448bc9ae1da46b2a2a076c873a154f67f5d511dc77b10e1b818672db773159b370acb4ea4efe97c90cc299afa9d3d6a0b844c83c11e79e2103ffe887214453c8fdca296d43c8fb8a7e8977b681a10899b5dd50c7d789a3e0d6a314ad777b57549b4b1ac2282d5c606c8e7187e3b4fe641faf6fe6fad08460b57fcfb9e2956d0ab12f8df6755024f036ce3a960f630705e7e0888e78695ad0b0e4d0c462ad512e1c46fc5bc0864f2a501a56bbb1eaa6f4ba146677524f8bf8e43912ae4989e48da91b0fc08bfad9f120682998b5ce6f820d7528f3d0d59bcfb55aab6d904776f8a71be720da6b97713b6675967d231c531069b42ddcc03dd81786a1c1ab90c32777c85f35fe1acb274d9f7e6cbde1076ec12190b7d8014aff263f7aa28a565f6432a59dc098e177b291da23bada2eb1be068a8d3a065bc40e1c7f0f3ef0f36f94e35d01e2077ca614976af6c0a4f9600b172e146efadb631454a1ba5d8c338e9acf56c0e8d0736d7e3171fbdead3ea9a0ae95252857c289c26d86cf6ed10191862613833443b722d3f528499621aa7ad68a0438416e19947382a01a58f45f281f65599a993f8ec2cafa4ce4df6729711fa043ae8c766081d35e41edca0c9e01aa3640dff1ae67c4a2167f9e0c11744339723d4727b6c344b3c360c7a74064c297d68bde75d8a397730d990023323fe2969038d141ea80049e9e0d627aba6a6a8760e7a6cdde0c3b6c8be5bb89d9acc01a7d719256178352a0955b3e8afe44efe85ebd272905685b426ba87089f7368bef12159fa18d15e519ca639e697c055aab864dd0a802b35bb7b837fb28669220c0e05fa8e86f51fd5ab188ea7a65650b151820c6e10401f9309f7beb201255280bc16f6908cdf091577b6a62b4e5ee69f71a086934906f9d036acd6b7693421f86f39aadbd000273810bca5da56731b2ebd9a12337d7688d10f121f14803d01adb431cadb5178b5e09a8e821af5446dccc455cad6b72699cce56dd9c3791ddb26c02acda6951d49645bce6a936c21b7d6824def2ab719e007307363dcbe39932499fcce2f4d0102220f57ecbd6ef34a930717a7cbf47f9be4c2e854eff53b867b54e8eebc9e8933d50f75a02b43558f8120b90cbaf4b428e035a35b81c44bbcd93e316d5803122f10139ee3fa13c59c7ef37403aeda6b3b3bca2448124a7f80220a11c6f15660fac6a7db7fccc5d6352c969e8a756e97a8dfc8a928bb5e52c709519f1eb4484a81973e1102158d95158859bd0ffb09d3f6f79a6bcec70f497012c52aedd0c14623174fc827a3093cf856611492c52f602cd3695bb9dd911d5a07655e43be73bb5b6a2f076e5d4fd294827831b42d40aed36b13b1c0bec3967b2a1202aba7ba50b3491a18b8b747de28bcbc328ac8c71a33f6e087d9e1b2c08adf084c111bb34dd6d72f2d9442c2a150e6f497929d99f0c83a493c654e4230a5fe14aaaa990e01e58d013cfec7ee73073ccc16d6749263c0497ef467b7b7845c2314e5e8cd8f8457ba7940593021acbac0140bc4cd9a5db6e405167c7139046c43163f706796d75d2541f0dee762271432a33a80375fa06a8ab3a457b16698eb00a7af1c79964a1e8ccc3232e9535b1ff158b04df43bbbdbe72c4f4ac99c9e1ea589ac3f64ff8ce0c484c46fa30cb2e53f3b782eb0e292e384d20ca0659d160270bc2b7110561fea8c55d31d46aa1cdd8944e5629a9c15c77306b9dac12e2d009b6d8816a25d3f491852a10bb740cd93e279535ccd1e8980a0fb9eb1e82e8bb6a049c7d625320d533100fe4004ea4e40196c3aa36ce7e04de55995542bdc7c9d29b41cccdb0092896e716d6148ab913d99c8954b3fd967bd417416858918e3fe306a638f4ba4a7eb9696937af444b7b18f387db6c89d0d0d68aad3466d236c96b04b001152f63ca467f26b84e717819e340aadeaeeda561c17b901f301fdac366beac9ca5b69685c478e85d5a932de9de1a14fe67f03672244c5c466edeaaa11c9b1aaf476617d22a235fbce1244f207196e972dc9ebcc98a49d89441511094630839612485cfb1112803deb35c39816bf521fa8077a39b7d066a42dcc28290646d4afddef69cdfa22ffd7162cf7880b23549c03e7705b9094f98b8504ad09be76d6ef47140ad92d4c0219114682905e4827d922cf9a0cf3d8c2f0b87e6e8b4f18b4781e5cf00158e45db244f6d64fe900dc544527f3e2a9730082fe8a1f157e568e0dd9bb89463b2b35cb2fc48c950d4950c87696af7940f42e4799ac93c0ff6e510b5273af1cf75569295303a177bedb63985d440da3fb866b1a8d1fd483baf786a1eb548ad996d0d4055940fff39765916c3d94d81914ca68474bc3885db4788b81082a330496a3d31ceb19026346cb6b614efd663698ba51c27f303b62580c201dfb6942ff5931cc0fb88a95a3fe6f00bad0fa1bce7a022106902fe34a70404f6e979699f88f845319f221d06c36b7e9c7e0e5246cd7024b68be0089c9e508abd68756fa2bd604279be10a9a5d696b3ce201a16f25ad4009b9e6abc140c4a1c1e74902d61821f0ae3a1d5302d820b7883475661693ab5782645fd910588abe7239ab32b29787a3f6aa0499b2c1f6267a72c2c39395bc05369fd680c4e574bdccf46ff91e838e814561ecdb193662bc9411feb6d1cfb2437f8a83281e8f33a5bb34e5197fc9af9e8bcec9a0bb6588e3789d65e2e948f344f258f4723a601208519a4d5a16e598eafcb54c4bcd602c3425e13895fa7bd95e8e6a48a98b8244a9963bb0b2c6b957509d2532cb919d09dc82a29ecca9d3241e42fa20e9794c944e24b931711e32fcb6f8d323601daa01b9d02faaa048bb721563d72004f8b44af35ca5ab5e6cfe18456a4281d4aaf5990ee5f6f93f5245d263eeb0ff632f5d8b2e036615cdd64ecff9dab65428e8a9086ccff70c4dcb36a0c194d4f2202e1840095ac20d6ddc932f4323ac32af6efacc956464afb05cc735e9d749f7994d3ddaabe0243c09dec75b623c150c17a6f1b017b71350639210745f5f3349efa23b58f064a971950cc6633564d4a08a93a579fd157131f01f2c217d78efad748313de5a424c643f36122e03aaa2db54893d9a37ac665be651f4573fe1af37316df8b5aea0a1fbd95d10b54a11809a4b64de1af7dc1dd19682f2b9bc943b2c9b63c73120396d54c7d97160c9c2ed3b7872cc863be7a08ae3fb10857652dfed85349dd792ab1a29a5002abe29d7821b1e053bcad9d334038adb27310ccee408095b27f42c92bb7265756dd933b937d32bfb27c53c2d96ef686210043c08010fe75b42ab90593002b782df0ec8d6e30d407c4eaa2527f9b41c3a4b2c525834f0816fbff6da9907b9bdfd1c3bb8713e6ed905870454719897a9790d9886fceeac3a394daa6a108e303f172912b69d707c430e8342c26199fb7bfb4ff80d1770407700397d0135c61bc796c8d5fdc3c351c0adca8f012f4ce284bd3c89ec47c3adf113ef765f1ffa0031dd73f0a9712dfb0fae1b8008de6268afa13c035a1d26fb7a5225f98b8ec77c856eaf10f98feab2720513762b756f6cc467f28188abf0d03d9cc9d2ac2b8c853c5930d83a8987558b927f5aabd86cec310732292b96c070de9987804cb8d0ec3112f85b3d136c85a7382d24a6611d921a6831363163ea2477a7919ae1d8be216b39cf0fe852925ebb5d7952aeb0f7938f95123bb9236b01eb6fe255ebae52a11b2e9d7dab9aba9d275fac1ede44ccb8e5498a6f16a729b235d980329dabc0db34537cada7ea9eda38b6f89a651b24c54489b265ca64594e69a698263bb92af5901434e720072803278bd3f18a12b01d5f5d86f0c482523547193474f7ded087c95a83075a5bf4c34d28ceebb074bfe09e1943279d9a06273f8e0dc5346f92757d02173bd99021e79976cb023dfa70b72dc92297a1dbb6b936c50d74ce2511c2a52d1ee74c84e36981aafd307fbe35b11c21a65299c40bb2dc7900bd3fbc5cc96fb147e02850c89c369d6ba615af8f7ba41319760b73084f781f553658ff2c3283a303fc551e43e96d14fd21fcce51ae5dea934a3d782b72fdf6b99f87289beb65ac918119857abc4dcd61a851f64cc86d358fcb1054e3daf8b2be1407222b5595d1cfbd567472b205e820f4b4fc0dabf1ed5fed33598f8136fcbff67bbae9b210124610f632d2a3bca5c63af2cf6ac9bdef68121b2270b5ac71834d598a7130cd64d6c562c9d32d4927196c1ff9ee4d107141f5992041970f49439e364c48cf120ab23cbfcff39f1af97a2a955643fc189a70eeb24521beb029a3688cac646b1d1e769e047fc4d4ace673e1872499648176d0d1dfda638834bc2b977d6b1c7f1170afb99349b6b15100547272a47f45726e2936dd233da4304b0e74f0cc6ccaa400783858c5ff7d7d32729c48523efb58e19ccc36718ced40c8010a2e3dff29db2c18a64dec018c31b11f41a2654743328e78b4544c2c26a24be192844763f0c9f37720c7bc2887e95838c68c838d0b69866bbe14c0f157aa193ced4a337d67c980b9a655af80f2c58da85ee33ab69e1cca75a31b35171566ec35f44701cdbe6ee17d484652266bfe0c2289f5cea4f0e4f832807f3841c6c24e6d561a78b0dfbdbb52b0f99559eaeb003c9e091392a4ea6d76d5d351b7284000e2961e2f534f0ac0f19f858a15e8db7eac6338099d7e49db44bb9b34843f82bb4031b27171642400d46c7e2ce3716ee8d38669c5cfd788c5b7a72280c8124392cb7b124cbb1fa4140bf1e4ae617b88d05ef8dfcba8616171dcf12bfdc1a5dfaaeafe801bdb5f9132f4cb089dd32e20202ab8cdc4d9268ccc2d3bc6c535478068843345ffe3eef2090ff2b8e59be9ae45eb93df55329ef6e39a67b013ae0041db3251833d103c3587cd2c200b7d328c324913820054c3e37a8c1659f3040ae8dcd4ccd031960cc54661f2c2a2b28826f8f079125207252c5e9316b1ecd3b1afbc0660667c648d8d8df649991d0004f7f224e8cb8295eda85703497e1640d3a1279df64d53b924472b2819dfb0408c3f94b4e39b661987eaa95cf6da367ed5d9c1643ca3f15c90a0eb092eb94c404b21772faba447d1ce4fd553c255ea501be6cbf25da5d347e371c6e98a2fe46be87d5897bafe4662e746f0a4afcd7f8ffc2a4aede72abea31b4433c356a6d40012b698d9c3979aad091ce8223424c80edf88850dddde2278e623668bb7a42eacaf5bfc5956ffcde8762664c2d813c6421bf1796c08cf538fe076ba10f5b642b3810561d6001cbd9623ad78452caed5a5b73883d4a22f4ecc41c02d150d714cfb784f633720d21ed79805a458bf327dfdc5c2ab66a35f4cdd6887f73fd8528489b16550390755c37cb058c689457c51b4c35cc9c2585d8602ea7145b074703f5ea92e1970d3ccfae4e14dcb8622cc84c440c0175914110d29f7a9228ebad2deadc6e51ceadda5f22f6a352b075d1bf6902abeffce2f31bcd469c12531e921a486d49a93651e9d729a811a52de0c9b65e7804befa154af575c3f5025d51c499dc935fba6e2d55a02692abe369863265374a1d02d9edd0b55651fef608034ef7b09b0e90ad839289a7a5587623f791dac19610274e50efdbad45bf02883a9a2ecd468031294fe25df008612825c9b1ac66d6e75ebbe543696fd9d4f1c2c03c02b51ef80365716d04df6ed9eda8cdbd89265430a5ebfad086813d82c63bb41c39e9a15deb3ba65b64c520a1f035a25b1a27c75f0610f5ed2ff416ce77616029d8ba6f73bda522ed0c05ab94370812a9eb0d23b8014057e1f0d69d4c10596da613bbaeb47c86ab7b5e1619fc0e128d2ee385253206e8bf7371a0beddf50afdefd05a7e8f81247c32b1e1b160e0c7f926ad886826f3ead1784fbc03d239ac1becb22179babaf71752ed7cb46b00dc4cb388cd159a7b086d5e3da333382b9c3ebc89aee174be7df20e0fcac85a02e1683976eb62bbaed44e6564701aa3177c4ea090efb929880aebbe2f088af7d23a2eb9652b97fc46c9ba8584418df89aee77d83a18fb1ee171ba5c72185505e0385dce0fcc542c3f0029e16a101316916fe8984a5304d78ed30f738a496cc04366250fc958203196e18a445bf596da399e304bb8835a2cca5a57b8bb1f22217013196d899b3d018f7b6aad52bdd4ae839dd1a398f2f943cd2d07d87d1b7cd2d089af3eb2334d31871965baf7d49767f2b9e7654bffc16c1e2934328984fd96162f0089daec00556c7fc7008b16710b329196801dfa3ab2e48f2d0b0e4f8972958d788c1a703764f885152de48e0ea16872516c00a81e79a24b555f217a24912e711bcd69c489ab8ec43ab6c6ca53c38f7a6e655cfb32897d65af07a3753e081885a9a64cb86a2cc3f9386bd370169ca5bf8ef2366fc27dbb8cd4733c4c8908b2f5310096a78baa81a1818aaf1ca11995964454cceab65e7108426e89a8909558d971cca625a72b258a82d5e78abf89d633b7ba1174f7fd87f5b625b7242d213cb9c5bf8445ace0266ed1823d4b47199aa37331362ccc42410e97ec28056bb4b8f97c52470d3e25930300b1189dcc94d6a0ced707e2b36ae49d72f5cbc050908d26a073fce2a423199e05095448c2b5c278ee30f1fb03a35d5ed21170024ddcb9b5fc67c1d09193e32f71353f5f38dcfa82a02f0c59508f01548b5ac067de7e8b21d30deae233acaaa885392c6572a2f97c85bf24a6ba092bb6f0ed053568c293cc4abf32dadf7a6ccc79b7989ebe4005c763f9df3f9e369a2ba66ab0aa52be5120593263e6738053b81418135aedf1f82d53ce19aa8c47ade590dfc8ab48f48959c045f7d8d97ed64b29662401c15d782bcd22399b590cbb88214565b02f0c3d07d4191dbc2d112a16ee959c38082ffcaf468698a22686564b2cec815b6daec485c79c471755bc431a9a84ef170530ca99317affb2f235e218f8afe23d41ea60b3d270b28a9c8bb6fd9a9571a8d69b803c90fb4b5477836eeb726d04d8f9d43127c498ddeecf0e30b3e947c530e01cb022eaab03ab0cb6f4427d9f9b9818561381ab7c47135361232a8e75b14cc166fd449c80f811b6df8815ff478346552e7e2281ed87d0915f387854b680aca2dbb682a28c3ab9a3e565f439e649a0f1cf051fe8d5d7892b236d8e890e7e3faa330696be297fef87947c9f6cb671261766eaeaae63770f67270cfbc92e7277db8d7be2d04e806f09ce8cc712b568a3a743bf9aa76c7078badc79bc43a2dee5864258e47097a3d7fafe60babfebac688e9b4b86c63b288ccaf7703f8d3a11a77b0016e7d1c434d3b7da539d49dc1a72367837987a41639d10daa54fdea9d8df70115c54d8a4d23841cacc329b10604d2773b29131f1ae176d565096def96c863b20a728f12839cd62626dcc681679f9359297a825cea4575856b5bbc4335515f43f2a53fd8e2a4ccbdbb954613b574dcbb7764d50113a6509e79f5645a79ad125aab3964b127fc2645134cda0da0d7effffead94a4229631fd7359c88e7d525f1043000688d3ef853bfdddcd09339e42cc64eda212e08da5ddd96e0fa6221062ab0ba67e70abeb7ee71bb1f575c1b2984555d25e127b507ac9eef5d570beeaaf207c03698266857b1156ce36f03d2b25dc50d3cdca82a598092a09b87f93a6a57d40cdcb62de1a02838bba2b96ff0f6a2207a445020dbbbcc5dc9cf1d8d3349a43e5b15121786d2a52c7573257631847e5600232f60cbcf48d1e1f74478708931c13843f523243235f1e9319f7a6c9d6432d9e061b346207c822a4175ce244edb5c2d6646e57d706dbb27dadc356dafb15a96c2a7e729266e566fdac8768dc534bd60830f601c76a3e3b3bed6678d8eca4ddab49a6ac3b3e3a21258d681ece8ba9ea90cd8f9a3bfa5e687324cc85f131e2a801689bc914e09ec4fd105f33389b755760dd208fcef3ec92957220d2fabd5e7b941fc382ab678445e731d1fe8ca112d8c18650f65e110a310254645195ba6f18a5c2863f908007d301950f0a9b4d59ac471734baf11e469216353d35ac8ba27ff506de9ed1879524c434ec664e8cc61ee43a8f417683e0b299df998ad91db25e67b52f116a71f242560cc7e62bfdf132323124b9a18ba258d97e7970f249191ba5b1839588d6d073b13456d4cb7bda6e0d4d5ffdf29c8f261288a1b9a06e0d537dba5cde85ee4af8e20ca9607f598d4a3e749bb604ed6532d3c0e9f764805ea2612ae1c87054afacb98e03c28f5731535659952cf9c476159e4d533e79159168df5ce7950d7ace868e3e2e042eb359fd19a96d07bcd65f067ed60ed86fb4f2107434a50bb3187e42adfda0a9de7bd731048a9258a995c51ef9c8790b250d43be711ae6621d2cdca757be638e683c5757bce71a4c7592cb6c83e34280144cfdc184368fb4baf397084d339b112048e64a2e9e93b4f64efd9e06c7f8c63ebfe206b882adb6c69044966eb873252f2d5c7331e6497efc3f7e465184577ec7ce3f8f4c15b67a8607cb48605914cac5eea5d182cca396e5932a220472b219d2ce41a2b45c48e899ebadf5b8d8c8e0b960e39d00fc393dc6ca4aec6995de364eac0d25f30587d0858fee61d3cac5e706e93e60105576fae985dbb1fcddec4de211956209ae5ae47af4cd806bd9bc25ec92f013c3bf2f868e84453074dba58237cbc737c06e4fa4845fd832d2ee7b1200476f3c8e4fa12f703fbca7f578081e962f8cdf170b5fadea02c2401e1a516f60579df6e1f0aaa8e34e8912a2b27bb95dcee1ac4a68fb7b729e60e66b3f4ea9dc41b0dd4c4129b13bbcd592eeffe960632df7281544bfb60adf1f2b15610c2f01cd47f13326cba3cfe8a8f010cb926cf8879405ebeddb9fc3673efd47ca7e69d35eed4e8a6e7890350a6cdf19aecc5637e8b3fd227664ffbc399bf45cfe91bb7e63df1c83f77c04130175f0909ee1d1e031909c6a707c24388c7461e8e2db9d685c3ec4c7ffbd67b1b5248a96bc5d919b04c745c81ab35529b147084e4d9cc653e584690439c85e30f63d8f379472ce2e0f8af64db727ad46a93bdfe60d71aed71393bb26579a4e467075b3980418329568875843441b8729fc20f059c106f13bca5b93922ae84ed27fc918d746b3075bbda21ae5e3339a30d1756c5e26178bd47e18f82e9bd1ba2b5ccf0ad996d55eac75b4c686d0c8b96b6ef5d69587e38a7dfcae1848df16a3bd02acee0e79fe5255689f33a20b4ea6accbd171c84d16036d35c8346eee85d4c56a5e4077c2a6033a6c0135e5e6fcf614cad85a3bce6b66b05db719c3b0407101cabddb80a771d68d0917db153f04f00cf961c1e9a74d1d089862ea651322be707245c0e32430e1821f3009c6ab4ca7801cf8d6e5ce8be62d589272717a6de29f82790cf661ebf1a3a6ad65543a7d4186a93c90b98badeb5ec84fa0047251e18c896eba45bf5349293a87d2ce89ec2efc25c3672f269b44bc36e1a7668d805d6b232f62e4a73df72df7c83c27453cbf90c56807539afeb2f0728f908d857f82724c76e0ebe1abad5d055a38ed7609a52860f94b96dfc483ef175de0bd8753d0557a96cbd49c4cefe6bc4b4ea33846922fb287cbf821fe1b8f6f3f2d6dcb1e6ce9a77aec62a1d993e68e275b083339a6a56fb7cc0acc260a6fee131003fb487092e53637a0b6970ab8a22f869bbfd13453f661c587e498a0c374aa2adde37f1c62f8f5b49f44b2ff63f4b4adf3c8c1e5b8b0a8febded67e1c4e3cb21c7bc31c553da9584e16cace8d6eebc3d3faac44e4cb6614e5fe12bb0b5b67ec571d1ed4e8bbf01c68dc466c88ea8e6755d58fc87ffcc0600503d4db7e413c66bbb8ef82967e15e0b595974f935d1a76d2f03d08aaeaf7e126e78d633c133724470c9bf805299f89cc922b8ecc3ca290cfc446c91147c56a1edf0a8263974740460082d14be023c0612b0f67ec9c8151cc70cf72cf3c3ba8cfd61251574f7ee2272226892a41631bc4179c6b3b27bf6dee3b35efae71a734cea1d763a4367b5fdfc080bb317bda1bd0753d0526193a193b7e8e883b2a8bf2d928d2405d72aee6f4f008e2b1c98137fbdc796e26328752cb04b284bdf51b3f435d7f7187c33e39d51d10c1903ec53c0642ead3aef2efc2dc36f3f36bb85be3ce9a776ab84bd6b39af5acb27e592ce83bac155b7c7d8435b8ecdf4967bc91bbd8630bbf3ee94c0f5c5db9fb24be12df844fe22bf14d7806ee922dbf57b787d7d3f1f8de74fc3c61f1ffdc6bdcf49b71bd6c9eb8f877ee356ebe6ffb115d4e24c1fa116c372d0e09502233f85b8501381f993e01250a45b150b7ab9aa51b8263a6353ac9de72e2a1c1c124617b5f9dd78dce05e0ee686c9c3db9017d04ab1e10c3a1b90460a28664c423e404126aeeef2f45c8c50b3413901880d1644ac6bee7ddc0175625704168d316aea746f4b90d3e6ef92a212b1161608c83011a63455e07d9da8269bb0bff0971b4cbc96b1aa1b82ca656eecf9199e739f699935af76ebb6f3e6a6d5554c0e26546fad05e61afd4bff0f2f6fd48f75717355fa57755026c5cd79a0e3d51dd61d909d61c538bf5b852952d7cc80355e03a114a7ab5c2f3b7efa5cfc437d19bf04c7813bd89cf807db2e5f772f3f8323bafa5f8c460a10e261e6131bd1f1b1d4b202c5b92a0a8a27558f41db4d529ea52c91fa13c34edd06c87a69d3498465aa695c654c7f2d232ebca222134400b7eff624d081c3ee455d5e3ebfdd9bfbec282a944781c7529fa6bb3ef2661b82d427fb597d5dbef99bd8617cbeb22ced5d58b891112aa2f81198920f5eb34183e6947182c97fd83f4f25f9ace29b05147b8f2a8d86f46f774d3cc14456e73941fe7c872651c32ae2c57c62db310e9918dc4f564e3223db991589f88d9075316761992d33c2be3f18b31d18f2da365ea4694a54c4485f12813109b4aca54f0624f99c29731061414443c002552a64a4005a4e06b0b4c99b2596380066710330aad4333abbf49268b0f2b97c37a8801395faf08dadb8d922cedd7b4bf743675519e4cfe8f5803b0b21f02af7a9a4ea063d736ce8409f3c412ff2de0d4cdb95a865c9c4c10fae1df737106f2191681e8fedc85824553015f13fe782095958375e60eda942543c88e0c9f930d2c5c130fefa907e0ae2ae3d90f51535739b05c89bb4720713424051234f19a827eb9831902bf8ef9e7c08141d1fde86bd127a9e94ffdee1b033ef6c0509c6474437e7490fcd8d03040850cb11709f957624c409219aa5c1fbc114e019c76b9f26ce6d65143c72b4f503964b536e66e1ca3551f5bfb48db6b44a4d0b1a4eb5a8c45d4a08e26b574662934fa65b2193b74777506da7a9bf1b91704bdb4f1f48dbdce06bdfe66fcaeb7fed82c75e13e78769cff99da11bdb57839ad730e8dad7d3f3a374d582063b41ff17772698181295ac527b00d4912d9b8677abc886cb056a9e94692025e5a40d651c2410f201be31c8f668082d70d78799768ec9706062f77e5c247e0c1fc5a771669369e6968b08a8ef95ad01af8f523f138779c2e00f143630a0542b3c88c7d9026a768b2a59220ee5dd9a7e60995262aad86d18c54d3be61d03524bb07e0bace6745ebf38d8720b0d89ad0e94e06888c766a01c4dfc1acd74c34c6595757aacb448e06ff9b13519e834371608e095ca97c00fa9070f9a3a2656c60de04d9e5160d322cb09f61a601af03e88c116fdf89932de89aa81e4c4f6bfd4c7b35d8b448a1a6509ccc07aa0c8f3feac50d16bee3d8356012e332136e3602d1b0bdba2c476a95de13c55a0e456708c466446ffc246650d0bf7975f1e25ef182c17c21b68dafbac7b5f350723867c68742283cabfda53645220285e7993cb5d42be15ebeb44fb9e20098a940a5e5ba97b88068bf31d21c937228021dd83ddf72806f4dafada517d80cbb2a1ad616a0c8c34c8dcf43b874a6529b8a59b352305d7ba5904cac922438eae232ff51005d5b51feae1da666800ac486a30149daa42be6ff4c67adfa15d4f36951991bdeb543a955502f73415560d2d4656c90585abe3d2e8f5f5087f47ef6f26d841a3923c9394275b8702182aade207e31754c714875c40e000be0410d8bb2b6ef278027c6667f914140c440b2f171208dd46fea3b0bf61484e845a6ae778c34a49cad5a857c371d46c296dd6a1fa088261d2d72ed386a6487229386cf4b766d6547a40993c5e889e498fb6420225e023e70b087bb257dc3f88825c527e43b961c566fef1162186b04e2034ddfe6c46cc94b56786f23268a277e387faf3a1437e7a0e6e9aa89b0e02211d8eb4ed8841871d0dd6bb4b95f2a53cebc8454a60d661e945e7b0eaf4b12e4f72e11e1ca000aec951d39dc192cc0bd10aaea3eed2c8de0e279be0e6806099f63af1cf65815c7eeb0cbc4f0135e5aceea48d7673c7c9230d13a7b63c917a81491aba6c6a95deb6612d1ba4518ea1d192f19d856b7730eafd2233d585cf50c9008af9eaa0438a76f33be977736610262c6c7b92b80b0b79d69313d50bcb128c8c3c006afafae125a0d2e7324eac164b15a7114b50b45256cfb9c9ddb05682352156039170f30275ac54b8a9c7d57d1026b1467286aef638ee62962a953f764f35217bf1959fbf8de20bda8464abe2a1b1fb443a5dd8ac976725cf5f46d610cbd169b5520c5e7e39e35612fe26b51f62dc74e8c4af1700249727356c7a35b98f1819ea6290605df832459761d87900414346c73b1317a0182083d402b3427945cbb70a6fd175c553fff527780b3540f0862d470f08ba0ff0b996df435829a85cb4d88a209aeb211ae51310823be275e782a059dae0490276ec90851815ab2e154f8f4d040d88f00be474ec989bfe5b5646dbf0e9ed6d5adf508d28952fd8709b56ff8b9918c7193c65f4c3a7830c282e8970e39607576edb8269a125b553f20e6228287d43ab777014f916166da2d30f9fade050b3337da80dbe26d78e90c57f1ce6cd1be22146cf8635f27cb36b79ece5c0e1488ad849c475d1e59032a91b7fcb9cf8270be7fcaf6cf547d193e79f0e8e0a53dd62fdc1c2de186b990950cc56364f3fb41387914ea13306f20ebec0e435a080de480f59309e555d629bcdb88731391e901a3c6f89bfd6219bafd83fb93b462a3f8e083b9f4c4e2f099310305b695d07b2beb1488905fa0e7d7f9bed84bdb5fa1ae61a593fc2407d5ab360b80c0d2726452118ad5df256a52f89a121f1a4b21ea7d9126d580cf21ed579cd50462d190f7f1190800534e342e2bcf751d9fce487c31f6a73d801ab2643ac264afcb4193d4c1ce4493aff4ba9cdc09a901552d5cbe1bbd2143e09621cb9e010642eab986dd1119d6ace80a01514e806cf78755a387f329e65f58b9a96b6f58811d4158d443ae722621f50b06cc17fb90402a47231c7743da495d7c6146781bf72741742c9f11a39792bc99236bbb23e56bd624c52e02f93d4d668200349a516afdc3a236fbf6fa2709f371c05e5ca19ed40fc30607aeea624e94500ec5deb793b3a1e6023e39be2bf4902b14a354d45c8c1f90e4b2ba511b8aa37c507fe4dbb6b51b439df3b96f433784cae19acb6dfa58c5ddc5e84c7a16b525293f8334cd59445a0df25542b3c19de38d090db860191e3b403e6fd2d198b1ef205a982ae69407c72a2d6269e8449f0ab005a0cd6e30a362e24ab209802d4227181311ca95c65365811902518046540e9228d0426ee0cb6016906e7d517bf2d291c8d9deb735530cc3858621c07af1d090fd43dc6da8ef32024f350bfc4c066985f490715c44e5ce0dc6c1f2d919630b0a0211cf4dbdfeb50dbe75a9a7a3fb2a8f8bedd073b7e948299cd107d34655c1518c3d68315ee688aceacb0cdf4719b994d61fa26d9f8725bdb8a1e5387ca649262201de892103e2d3a38e930dbc8e9653f6891e5b5a3a5c145c4f9c12fbb433502aaa921f5434526a7ba9ecf1c7d88c70dcb3873bb9048e381af96d8a5d54e101438339673ae82dbf31797881c6826d9cbd986ac74f7f2d76f4913291c6ffe4b5106f1c34d740da01a348faf744afa65c826cf5fc23bd82f570ea0a4aa8656adcee40ac53afd9380c399f8341815789201bc97a89b911a31545c854bd5f4207da1d421135e5efaa5fa65e5e44228e660908577dcb47592f5ba90bc39a8e702851799995c3d1669e06b8efbd205b7e88fe6537cee1d26824ec23ad6a233fc12b6851cb41c832dc38968805a8cbdeb182f886c3b6b0e9fa5bc1fe93ca8b2517c73a32137029c04577b13dcd7687cc7e494caf56eb19e18d6d4c47f991407f021ccfe642aa1b8d5c4fc60213ceac231ede9a69570d986d61ee0919f72199606b3b9b1f3ea9fb83f5fa246063e47154fa243d02099d35a01535d51c0a27fe83bda56bab302fe26daf77966d723b8066232e475227ab8018ae24d387b12782491d82f00432f3135733451a8852b2337e8535f95a0bebf2a81c7b28e22fb6c3a2783c9068681da6e27184d33d1cd7398002fad3a793cf4575ef41b8f924617e2d7a4b92a60f460337d19138a24164abaa4d9a3b05b030616d32371f100c8f388233f81f5d06b48e2354307f25b2eac2693729e36b717d0779501c55f5e671326f084140f2898eaa7dd20efb270f4df36a75ad0a1da25b4dc48f09bcfbf60fca8404be6cdcad4d2e51c707ea673b8c430a1bf7ba569ba28c8021ae89c8bf13185381f11c4e07f75aedd58b0efbbf580ce0bc9e67763a345754806951fd1d9b644c2694eb25ee26a7953e6fb0859a206d5256b318b4de2330c5af8cc7faa28e004e6c8b62e7b18d16d0ac7c206b7fe8d956893973d1c3add8e3572fef0fc4d7b9ec62f4cfeff6e742645605026a18071ab74ac41c86756f818fbc15aebd952a92901f6fe11a85be5e2c39ba4af4d339f2e72d5da3d4f70e666b9efbcdc8c7c9696bc32b32763fb992bc91ebdcde3bda46d61085a65ddbdba91abf2ca13bd9d9e84f0135f107dbf02c8825a23273f29e74bb012e974e5734640a10c56e591295e285cd8ef2db158fb11b9db701ba09e6fbb79328748066dd381e44ba155fbf58f1874444beb241f223f2eaa8a5e0e9e7473692423e49d57d134c5d805ffedeb79079b76f9dcbaf7fa7924bf723ec3d920bf72db9441b09fab8ba402cc38018e79685f78f08c57530f359e796c9623a593217742503d4bfe85291fe3710b955a058f2aecb63d5e617dd3a098f1e19812e94bb692561ff28e32c90e815635a09d06d33ae181b77af95767c941c85fd6b37cfd3b415beef5f4da61fd1bbfe0babf907e5d7f3aa0c6514509b1bfe0b7db0f1a1da1d3b7927bf2a45e9f9d649a954e59307f28c3e997a51e707524ac78a28c3e20d592640f88929584cadd8d3e07267f07fae4ab38ff245789a9315ea54fbfe38be41e22b53ef6a4c1ec048f83d71d000c90f9d5813a0b68dee17493f81e1f0ce88a4511b9dc81042beaf60df6a8c14f53e7414acbe7459458d01fd2494c6d4dd62fe32c0648d94df7038ed48877bcb00134e1daf0c27314d9f63e9f3c062ddb51dcf09d820cfe0fe21bf347f973416f31c1b305a5a22319e57c94dcd2d2e47533cb41cde4ad4cd0de37ee124f0bb48be2eccab57bb39a5a6ce558a965e9da6e1209269494dada75e848c57865f48881782aef44d24c4ca45c23ccc35fc8bd76f4baec8c113e52a858cb8edc96234447ced1bf808d8b4e6d4fa9139ba9ebd7685ca5fa05604101c55dcdde43df3fa89bab1be1e9d8710e65c5197bca642094cf5f909746fee8a5a1079942aca42522bce84755b53e6e38dc8af5083c42ed5c4f0f30ac9f0ffec1efe21b3d437415998d7dd99a6bad0966343b882d87b3a03d65093bbc6d0face1bcf00de70eb9779db84f0450fcceb32ab3aeaa74971833a4376f66435f32f85fa5b3c0d933f8adb03ad333fafafbfbddeb9000a8fc34f949e19e74de33f856c6bdec55ff42264b169d790131d3795e935c3d093a3fb04d7339cf8f88d0384632421461dcb12ac29ba98fed26f3843ebeae5ea3ec26393c05b98cc01e4deb2abd325acd56d3300e05e7f14e1fac0bbfd8d068778c58664ec493e6c28e3fdbbd54026f00b341d55e1e8fc36224217e41c41f7124c68ff296583994b1115019817a6c101aea9a79eaccfb0f53ce50933f1c3037ddcdf9df88277422c088bf787eca8d1c529666ecaf950501a8da4d4077bd2073eb053801da60ca5c0f4e605dfc863abcf85758fcb3707a2a806b15ff7b124b8714260968e43fa5980825c4d4ae0c6ceac494c8f75ec131f10e1ba54098c37f2ae57443a2699ecafee9257e1af7e0dfcc86f226e284cd2d95fef3e1af985f36a355797df2678c600104f6c9572a3b03d2f5bcdf5d8e7233f9469ce76e6f6ac3740b22e4d668daab1064b4727aca5c4866845e590737d217fe414be75a90c275eeb4824c7f9581cd6021d23b4c4434256363beaf0d6cf5e69bd4a83a545fe746940795429369f46df062f9091cb15a0645fc7cdf35f2c5ffa96c66e4e4df3cd4e379cc804d48dca506efe11e1bd1fa083dbdf0814c1e04db0280165589944fed6dc9602d1757c7db0cae629019945f6efbd5117be0517d7a6d32abc182989446278e27dc61f2f15be5daa4d186eeac717cc7c59b991a292e428ce89b54d8ec2dbba933020eeb4691ae16da9e8c8f41131d774200d0412e416e5941d044b86e66a9f91c6263c9c5b047ec7192d2c7e4e4fc5a80b08cd1d2a90b9e2266e45d1d226b7c89b7c83edcccd040492f9e43efaebe36d60cd1f106b92bdd64cc278f7c5f633a3638b4a278fc1d0267d7ff51080b3081a894cc04357ae1a9af24a44e93ad3debf87a33adbe72278d7ddcfb7ec0b0af15b7040981eeb3f4de95197352aeeb5d4d43f31b7c5293356cc2ec9ea6c9d61160a546ce7f2874128501d9b0015b6a888aac12c4f5869e35cdeda204f23c71285b13b3d698880ee047f322df4dc0851892a83f944d8860295d919d061908b549fdd9c6ed458a6c2d82ae3a26adfd349d8c5051541ad3814aa9cb36258a212a9554359953eab0b0b2a965a73711e5b820d383b7191e3cf9f2206cdfb036f0e74e27ff72f166dfc023139db8382e96cfbb7c6bae85714ed525ed7b5e9063f39593d6aa1ac4cdfaceae88e46267855656e5dfa80f02a4a7855d7dcdaba1c4b17389969a91c16f9f7d164200a0492051e0f124b43497a7501bc848f064a3a5bba89b55877abc95d12f955471bdcfe2f8e8868996d85046ef59cf9f7a2499efb359e00988b13540dd05bfab12a82dcc71f6c94e4d2dbb5023466bfa969d2c8d6311c376da973724fe2e5e2a022abb213defb4f5badf49438b2b72ccab7e1741d3d3ff64f684b4f32144e90ac106e9d9eee0b5a1b3f55d5d2f86bf9358986910e9e52b4455502ccf98b3e84ed4f507b10823c250397626601c5e7ef10a6102e2e69c865631757e6ff042e6bd33c817487d14062e8c2fb3ff33b433e81c11eb45d841e8b7f3210f7f401baebb097f167c8cb0f19b3399e1bd16961946cc600b4027094fc5918fc022464de3c6a9f63d8a8d008ce85c3643588d5ddc0a7a9e4251e5c0965f78de5c2af2a1d630a2feebbd2a2c56c743dbaa14623669e4bd84aac10765a0920a0e8e24a0783165f3d7a4dfeeb9c118331548cd6085dd6a1657f914b673a43d382a5c94a1533100c969833211b2cce2f7d4c0e8a2b6ee43e48d7ebde490fa558268c32350b3f37d879e4df06280e1e5209dd02d6228ae1aea0b6a2ba1be722a5b87e54e8e040716c8acb74a05cd0fd828591d64cc8a212222bb48cbb33287d61859900038e28aba3aefa8127d37b331e230c89e950724a320a41d57473ac560ceca8be6d860eb3847570bb218fa4832b8383f1d07c6185cffdf4fbd050cc5bc3772627aa0c6c41dab08aa0d0e6606795c0f9312f8a3454ec4174b923aa4806453b5ba290516b975354f0f7b028fbc1837d4b112aca56a0ef542537e27a097388f30c19e73e0fa5fb5a7d4fc442e37ac9fc100f2c69202e8b0761a81ce2663b996f6537bfd80db0f1def2f6e53cc108a93a878012c09d22e99bfb6e8d6c6014e73bb5a0355255d69157168e366ff6f9dd84a3f91211bbc43578054f8d06aa242e00ebb4ef82810dd9f9f035525e62a06a0f455669a50cb20aa648a0a0a193a64281e0cdcec8e1bf508a5150e8c151876dc17ed5cfde5be063a408588ce1b234cde7e1c70cea13f3a9e91b0244dd6a07566b216101e78fd5d4e2f12e9a25d24c292311f001a348c5499ac580f765a158dc9ccde2b6ec9c2652ba639a7ee2239871e58c823f091b79a35fa9c7507bd62958388e10dc034d8a0aff79bdf919148efd6a943e37af41d02b77d6878120a5407d20ac5f564d3bd56b4b424379570b30c67b9bc76c0dbafa38e0c9dad206ba459710a77d939ad932c89bd9ada06a659b2ddeccabf256411d2201bcf18fc70f6bb7086eee165938051474c0add2e2a7ca88d09322f89dd192d10a9e3812e1b4520aa531abf09a9dd70cd45ce25ed875d875dd7c57fdf601bc9995aa874837b6e362b06ed6a451ecbc7c4e2153315d1b7e8ab006b63b625bf07d3d61e542c1d8d93a1e29f59eb779842fe0f8d53ba9f2050adbf83f55d4a8a2afc2bec688af909d3be772ecac5d7def4db22d562754957bcefe38374333fcca04001d4643a8de12952cc63118ed831af16c5302a8ab1ba86d6a50df16db9bbaef1c9acec01aecea33edcb3935d44ef725d36215acbbfefee97589f24e885746fc17c30823df55662e0b8a8aa5cf7b61a50d4c2d4a01de0b64fb861f5f25c7e6f650dd7594ae53261d5fca1dd0c3697eea9c17169600caa1a4f4720890c99bcb0c881a3914568814794e35ba664d406b1ca5a98482a9636ac5f87a48f8275a582814c580fa7de9196b85d04f99b88f6973f5444ee47426e9f43f7b039cbac09a562c2164d781443dcbc12abc25ef8cf9720199a543940b26f252cc24080edf93d2b9ad0b6946d23beb2c2c4aec216eae43972d4281a903ed104bcd4d329565f33c5b4394cbb05798003a042f92a5614d9c88c6312c2ec9f9191984cffd259aa02fa7514221eae4b4cdd99df5bc65d28e427c822c53ea9124a8632c294a68894b8f9997f1a659a11add9f28f4a067aabebb2b2f6155924ec76e4002f48879390a1bbe4097e639dceb78584dde6c7a1c6e2273bc45385373af6a407c5aa38854ac4dabc52c1ec31cef84ed9b9b9f78a0e72417d433386ad13b54e513c74a2d7c03a536abe3e0d60e0a36bed58a0c57beca67455b21f23d6fa6eabe63d742a39b8db660c02a4ffd2109f9deadc315d2f46ed6947e7a77783c6a9f1e96f4fd17904b8adcee813c2edcfd46baff928d13a26d0d6e70f012fb6c2c558f7b75498b19258b5a54895ed89ef5b0952132a5ede6ef052a0c39d332a3feba6881ebdab30b14646638c944f10b4a8a23fc2acca560eaf703a8be92aab7a374ad7a20493a559ee033e5d7179a3420ab667c23b92e090946356e54413d8a3f9f994d4951664902f087a7289a6526cccc3427d25a329223b7ef7cb5396146589679f0b8b0f9995420d86e42e1be8ab86b5542fda258a22112c38386ece17dff317f24dfcef2391f6fbacdb7eed273bf5eba5078f1adc3cc217213f9f8fbb44be1f7b76807d2fc356a8f12a3af3b4840f82e90f955b6ebd0ba01dfe48fe93182cf46b5a49a8319ae2a1e3d2f976544ca9e49904786e083557c3fe746744a55168afe2b995307b9f3a959cf67aef865143f5ebfe92529fbbb13ba7e4c62df270744817b8dd421bdefb22ccdc022caf0b3e623c0ddb3f26d2540fab3960b928c1dee616aa0943a661d0a00c0d617e829ca59274176ba3b03e376093d4779a3f5e31510f21b22f42e0a78584ab30ff9f46209a7e12ac47365a20e32b3bfb7ffc3021102cec3da550c45cfc3eab4dd773a75f6776fd784dc7c7a3d429c530752ec8665a440c484e5c1006173d9206fe3ced1f346176b0a96471c8f37dac4d9003fcb276e847edee027e111cc48cccb170ca3180eaae9eb064c16cfaf8b95c60688856c923a5fdfdbefa2a36091efc7389c874386fdf96cf074c0a219df3c8c2ee4b7dbbef903c812284a8c1def0e0cd0217a02e7d090a303d7a5b90e60fbd02075997c215d9120a01d96617a41789bc9d444b2ca31f7c02115e3c07d64bbfa66c31ffbf03d87b01d808b6c4aac10ac4144633f0c127254e09314c72b70e591a6bfb3fae21bf1398e2460846e693e940ff6e955fc81c995fbf7dc44024396a20bf9456db6b7178a73e7d6b517a76126a315adedf207f48c3f23c87f715a4774dcb888518cb737328bee0029630b4c2221641a88ecab53c13d53e4a49cd99a523cf084a39c44718a9c39e77abc75cc52518e258000908b4140d1e95155572f9fd10e4da92bfb20fcd5f05b1da861a0ed2d4d8db360064cfac216d9f6c3e852c8445889b7c0c75baad55da3d0bbc6bab11c864a4bd861ac1b2ce33b60a1297901c8e320c7065d915214dc0dbfa353ccf8c9079d627cbff24acd9d606c5a083d99bb4297ce9c8ac03b6702f6336acbcc78229d4e6b8ebf970445b6f13770f67ea19e1e331652135ea579fa83c0d19310a8f1c56410d86270b3c3f34e3d56d6f1b0e729d777719fd100970bc5aca1739e2fe874338448da3ed8ec3b420232e5bbb7e2047af4a1fd2c9a784ccc3bf9efed071d620a73f642e2c10a100cf2fd7a95cabb30683c3d35f01eede3f664be3f233cdb5f9c9ba4532a76ff9c116bc739697b59be0de5d853d373f6abbe6693f6cbe8a3c585663630933bab2c9cb62d1990791a73e9c930a8bcdcd964afd4a8070101ce5036e5c51015f37e763f4fe054f519d52b3af08939a0e1737eb8d1bd0430d64697e8e9eaa766a64176ad72d9c368cd9e43bbf5413b962827988180f7d1d7eaee639f025c6d90c9d38e9a8984edb54f0db9cd130cd04d8e8cad9501b337eb06af41e8f1cf8dca1c6cdaa51e4899483b2d540020a840aef48abb28f921b5fd0a8cc5a7a22705086d2801dbb142c341db6525d9883f0b29a9ec79e25e3f4a91320dafc1c8a89482f14882978dfea24f9a704b90745149931708339d30bacef9dc424315219ebb52473ba00cbb4a2cc3cbbf740bb26eb769b098841f2fa01c12e7ee19fc6bafbba694b5174fa1b158d773f7d3fc43371f40f35926267208d9f358a88f713ef006ec416f56cb48f8d8188ef2482bae7c70b714e67f9f68ea11181a5030eabf0f89076870baef388a7114a4ef1d8e9f6888e1bffecf83c58b8ddfe7f1fb5f4b5b598898affa272e74e756b1d5131cddff09e4c2156d636821abc50228b70e50fc8949de795717c6ad8e32f3666d2d0594c1028be824bf9480438a807266120e81e2f677e16588ba225742039163b980d7068a2319bc84f99e4a5aea44dfb6708016660d4b081fdca35e50aef2023e0d8a377650d676b567f0da3bf88f85b00911076559dd6363b52950ee26ff84e024c4bbf008d85420a60d1d0c072666d15280a29f61860ef73b191d1b9dc353d7da79da1b63763a9684d340a16f816b17fd27e8a6afccd8d9a83629f99f6fdebf92d2bec7429aa5da89b964627271891f98fbc60e6f935ff871ee2d3a691dd96c231130a15e448c34474c0fb22984cc09e95d857e417407b613d713551277c1c2b946e2fe8b49a0ec7bb7722cadd239f3ed34ef3ecefe9d6d1f0e5ff772f762bc7d766fcd5d3eb3f1dd8ca01b0a280470b6932ccde6630e2f9dd3d212a7cda07e1ab8f63218f4422c717bd26b945add588c9944804f4309ea331f0c2a4340cfc462e3e921913d3c30b2634cd845d09a2201e23b8408676af8d8c9e266a7c42d6d262d1e200442211b6876d4b9ef7efb0ae2ce18eb50522ebda62b10e76e8c59a8e549a5d89ff9f3d526354a27186f92828d830a6280739eca68b99421c7c69b041ec415724f940c8fcbdbc0d6964c9b4e24d353685c2fb1bfbd60d8638f8e37591d7ab3a723c7f04b2300a3aa968137a00e8cd4e9a73aa086d2a71ee6c17572bb66cce65d77968037077999338c56ece3f3b1f9d37b27a4109b89771ba8b22694817fba7d3589ae022b51da7dc814475d50d2f25db0b183d77cad673415467f5ae84b5dd488923483d7fed4fc27c6528ad1aadb30a6e5741604adda09e0bb17c9b9c5f2aa694a489f8f5ddd65fbb5a9b5a19eb90bf5fb42bc82d2e58253f4782e5240e7bd21f85b2bc8b082e94e88d7aa17fc488dfdd74f17bcbf3bd1ee77bf900f6ad306bd471318b240ffe8ab8b8de8c63c7c4d0ca54b585c06885973c1579a78e0af4c4b2d1f3a5170cf2ff88a3c528f182a6a4e4d70f109aceda3703ea2d0480f5b4621e6962bd11b92280f4513bf1b8421d77279b1f699b00b9d4cbcbd339394e78558a678ebce52e973180e0cb5f69e49055fca9d348d517963f062c2847c992566b0e258152b0f7660331a5b5539f201ca8400e14fa3c606bcc6b17cfa3b8235d99e81488eb80d7d693eec6a1650de61da495bc6677710bd88ed397fff89df8019e824f311cc46f1b563b24dedf6f9904652b3c036cb8aca9e50aa0b069adc24a819ae7b9ff3919fae778c1209dd9cf033a3856fb247b58fa7290134a70cf347befd96592005b30742d5d6da30220cfd9ef302a9edec22bd2c6108c66ddd5332ac241e895e6da402bbae0793acc3ffe8836e488ae41d4026c5e84fe89b30d48410ddec5208f5163d193d3f53567e0c970d29fddbe8c0f5dc6b5889dc64950062c8d6121ef77a8df466bd0744328ad684af186efc6b503740638dde679ad9075a888e82ba319389396f153c7a06d3e40228ec3edc8829368801892f7c8a4a4fcb64a6838b3eef293b6b93044388c36519903d1585ca869e2698883dcd7e0e736b82503674a41a4db114a29159d2a969c6c4960d5d4968f35056497825fc0b62fe386ff41df154ccde7e9f1608deef5eae44f92d6c0653bd02157f01dc92b3e263989c973076c62eabedf5482de9b6894e07343a5504b43c0a714183603f9a772681691ca06177c4858f0364112aa0202cd0686608f6ef6c2317c71ecb9420c14ce9b613ef37737c38498582c9096e678a6931b63f221ac51a88151049989cfc5e26cf5ff5a985da4765eb9b9aba0935b9aeaa111bf0c0fab80197143fea65fc72b8a20c92ef3e1e95f2f113964c62045d927ef5f8e6d6ecdfe1c1a61d76594b733aaa0d2aa5faf37d34b5419614747d3331019919ad44cb61e9249a64f1963a31961eb73f3fa241dd0b6458efc32ed027ad32001af542f88bbab901090bb050ff3209ae60261800af87a2b48781f1be9e217e73b312f65330199c986f0b410c96084e649927277a5821ca4fc0331d35e5e01cd2f9571e01be71f6e139ccf2955b7022e40aaa0b41231ecb04990b9faa8130f98b85fddf9d0104135d1404d345600c2a957224f54597bf6204f1c1c21ace37f53610a894f7d31b6157a926032ba6f10f196fb234ec92f83c9cd4cbf6564fb87a25373110262e8b1e1f0668039e15d3b87daaf56fffb89d8818e510ceaa04544f699ca41269f05f390dffc5a35bfaa793e1c855ab26e9ee94142d177b21907f16f1aca278622b8ea5cb3ef17e54581ae544affbe98657c34527a33593ccf329a87cccc376934032f810123119b9614706a022ca15c9e123ab099bf403d4360b851d9a1c9934e0d0e036623bf58c84ab038aea1a0f0d7b7a35eb1443d85bbde344d60673d47586833a43049d7936aca593c56912f442743ce9ba38c3f9edb0beabc760e53016774506254fc9066e1d806bf571b59e717df00b1ee9bd68f91ceda0f5e5e545055fc8230389403da48c1917014673d5003702619021c2081b164935cefafd5047804e60881b7f80e53feabb962d78fb45a987f49e78095bf405962e43a480f41fb99e1b5f011bf083c0aeb0c15f0f601104dbe20e704e82fcdfad678f62f63a6e6361ccf9fbf958af7bff86d3836b969e4b698c2b17ac5af258779ba0eb3471df7bf1ed86bc1dbafdd0e14e90b34d350cd01c9756cdb02e2678329ac523bf59aab524921ca61b583d5326c1d6be6866cd1ea0deced545f4483e5fd25cedc7a1e3d6d9c25c9419b52912d525d1c7a59e86dee1e6005727e8ccc3978cf9273f636c57ce75f014ffa255c29f68c2adc6b7d653986b064e5a7e9465e948d732a3d74204f3b5aae9c1814ceb47b15acb23e18aa8d6988fefe35a7e4cfc59e7b2d2de629f88a5eb3e603d2af9710711245d87e6a8da59f5dce253bc5e32db106e94a2d52d1b7b484aa9d4f4a602322a3462d11cd901ebf187b29b08cb62c603de9485b035a7b7cc88538408646033505409f3dea700264ea5c95cd20bdfb0e5f068ec36048f207c39e20c5a15f80e01b646e49299f186c2f3f17887911b72b338c07e6624754e7e03a1bbe95c6b627da6418a4869d3bc07c090dab8d810fb844114eea05d018380a33efbc47ea4fe2e60af20d909fdd3f47f1c6733ed55a14fa1c7ab05c6a5dde27880610484178df3bf7303b8d853e422c01a063613fc2f9d0be43f03ea428e765d3050ba9a0e453711f16fb08caec595276a9f8736024819a0896e708dbc4c207de2da0baf7d146f735f29db8a73098ea78b195740d82a541017424438c8c8586a40170d7e6bbc39bc1da0b0d785e753e5f6adc9bdf74a6b726f2965923268074d07dc0655c4d440777bd666b8d98c72066badd5fdabb5566f159b7ae5d81d8577ec2986911846621899734eeb3fc3e674ee5cadb6d6397b6cad3fb5be7aea9cfee274e95ac75add69adb5babbbb0c30540ca18e90a9577b39b0c3a7af029e7305e76514d622cc79de9c9ca2cb28d445a1bcd3e9240ed5564d6bfb753edb00bbb451f9e4d1b5e53f34c4e1d13ff03d345dfe3160a0a91e3377ede9b96b336a5207eb3884e9f49960d8d50c2de190d3a10b869cb461ea0ea554d6f6cc5431af9f3c545b617d592c23e638ea5f7b264489437ae64f3471c849bb87cad7eb872acf84551f9aae72de86a6cfbc6941a6d618b7d65ad52a96aa74ea5a6f686d4e159a7e053bcf7e39b7db4dd3e766063c3a1e61adcd51410e143950e440a1e9779f1385a68f3f278a4c766269bdea3b73ce69abb5d6666bad2dadb5f6f3e657476bad9d9352fae3ce9f1a7f3d9c9cdf75e56c02394e2c2db927165bafc5be3329a5b8524aadb5d65a4b5a6b73aab0d64e4a29b555acb5768635c55e7be9f50077ba270e45e97827796f8c17642e256a4da7cbedb5578a6b9f68b1578bbd5abe6b6d5bec96bb858ba53366559341183415b798e40dedc5f2e4c9b54fa8d8fbe4c9b54fa8d86befb54fecb597cab54f7cb6eeab505bb5016b474be5b68a70dbf649f1cc9e6f299571299e63052a66cf27e90ed2ca57ef3b061639a5fa2f4fa9554a7c127ec74c195da98ccc0c4da855af12a913d1488fd4c88bd17c6b65e5b30d40803d7fc4279daa117113fa893d1f8b3d9f01f3a8d41efbf2433ff2a39b1dc1ef83ba739cf86278ef3ba71e1fef8627e6533319a023094f68fa25ecf8d123c8f741dd7504529ba9ad984f840a8b19694e0a34fd92c6448765ea6991de7b67be204da757d88df970d4641b80351eb501a1c6a0e9d713123e12bf58ad3e1ce0af3e107c9fbec663793266602034e6cd21d47c08d0db08420f983ea7ce66a3351c23212161a135fcc3307cfa35043f2e1e6af413d7dd6cb7b761242c1d12878445e806e4b13e1cddb33e107c733266743d6c388fe31bb1d6f48022d11a8ec9e9c3d11b175ac33117fd00e7f1a3dd61a47fcad11b173c72e9093f1e5e19070747c60c8e3cfd3c9dec3e7991cbd8f6f30c6bf30cef677c38eccff840f039edabdbf3f5e4f1d89d1ed01bad91125faf568ee454bce5d4038f326bf85fd9fe788c6d2762bbcc7bb8f9d174f91f559fcaa3fa72b5752aa5e2c0a6634ac4540024d000a09919dd063a016c40b1f547c2b5b9a8369d95f376674471ef00ee9d5c76bcc89065635da464df5f15b560df7f12896cdf7f21b162dfeff19d594b22c4beff23c3be0f746b1f1062df9a12d9a6624d0628d87af15aafa8eea1351994844d47b86cee2df7331f0e2e0b9702ce88118f91dae67e7504cae65ee635c77d4f03388ee3381b45be6cfbaa0f8775a24896cd3df7a91a13319c2089224236f75a0b07030c9b9b6273351858b0b90f3f1c9ccd131cd3e66c645e90a25f206235c330758999a58cccc9b6af652d7021896d3fafbae8620645009b0b4d889c404c630b111c5ac0b2add5984b6d3b6b2d54196285b6d6be008bcf5a6b6d7953e674d9bf4b1b9bdcdc630d6673bf426273ff5c4d080b6a438cd8dc95cdf5ccc9c9c04ba61f8e3b806d6fc049382a0306d698c41a5b3ce3860fe03471938164e4260b0de70431b09028baa1d1608345c6ba01151fa8c9d26473832d70586999d5c850438ca4d591110dd013b318b325334036231a2d61a880071999154d754518377061865b93198c8040226b12e208d3172fc880ae2c5971a1698919806a342a8a002531c32e40edaeebba6e89db5d4249d7625e1401a2156121483abc05a9db92d46d99755b68dd161ba9044907c4c5c96907241c9012332cc4916b719622599474576ab047281db1a4a728026262068324404d14d556082309500a906a2c202902a485a90035cc5e74d5552ee6882cb427596eaa1db2c840054683436246a055496656d032505253689d84027d693345b250a1250a2f5abe38a18549860a8df7d4a2e50b15171db382ea07cd29494dd12926334d34cd9e5a6a3d245133e26b4a1449bae2ad890573d15e565f1e0cc985b78092c2786b6e9f6d1517b52764b468bba796da14648e19906c4e9a286dfca5e755b418e33fedf93154ac983e74fbe3afd1a48d98fea500338f62632736ce63e94b6cfc355274f7a527e59fbbf4a2a25c83a4bbb7b1d1b46ba2e8249f394d69e322cc8d45f7bbeecb196591cc162e9a2efca5e36701a11dc991307e95e8b3dac29f124f9f2739893fc7047a6efc81f06d3b7ad274e1cfa9a249d8f103bf0b993e73e327a913d4e3931148cc9deff1d325e68ef7f8e915d3670574077cfcd405d465bed33dd6f869acc680f24c8a45c514d760e32eb2d8f869166a453fd621fc2e5e0a34fe86d8185bfcdd57c344d3cfdd9723fc9a10e850f49cc4f88b1736d64e62cd12a17eea75d44f8db3b674f8afacd0397b93b3a2f728f1fb2cd29dedb4b482747fa215b19317754a297d5764fb389f5055e8fafe27db4befd74be6e7556b74d05f152f12924bc0b4e7d78468da73fce1f36376e9813d573ff5b3ce0f7ac69e32eccf7b69d3a700bbfeb571b935489a367952e561ddfa7e54ff3e0a3f6af4a4ee4f01618411c60db68f285018e43cb37572de68d9303d5f9b1238188d134bbe5a72a8a9638b6badd5d65aabb5a7d3e974aab5d65a6bad5c47bbaee3b8aed66a6badb5d66a6badb6d65a6dad15e3132a67cffbbe39e7e994ed0cf79611fd39fd72ce9e73e5b462cffb3ef0e569ec692c23f37defa54070d5d3d201d4614aab625229952a26464666868666b5aa51a9626264646666686862c458d9d8b05895c562b1626662b474909999a1a189b1aab1b161dddce05c1c1c1c8b835371707070701c0787e2e0e0e0ac563536362cd6cd0d0e8e0c193366fcafbc9a1acf864559363636ac1b1c19335e1c3525bade002679e6284dfadee64197da53aa23559aa2cb8a54912a15af94d699906e97fa8427593c1962852a3fc460d7caf665620643f6bd47c840b6ef5dd5a6ccb0bf3d6b5364bbd4ff84c8a949d6440bb8fe1379d1175ae4a636e7d1de06b2fd6cdd392de32d8b231c6fd0e1b66fff73e8bbcf9cf6c9ef41a0ad632af2ccc9f39df49cb49131455f9bef70f19deeebf7f56dcb484d72b2dab14c81b64bfba8cf4eb6683f1c1cf7dc13ed24ce23dab6044fda9e0d988dfa9ffacd3d3fd4153d19336b5b4774e94df46314e6e57ab46ba542a3093d77e94d4d1837616f2c57388f25e9348c6db575c4f867c516e3b2849e8d31f658f5ebc52dd05f7da0086442db2b2412fad2eecc494a6f598d68910bbafcfdca216556ab22f41f200404837e2773cb88b6329a2e7f7b978608ae46bee3458a9af88e13968fbbca76b5a3cc9539496b1105da97860ab4ff4ff59e2aabb2ca4361f46bd1bc6d7a336934d86beb9ad866f8bd89bdfad2374b1dcb39bb79ad6898b2c5b6654693d5aa43de38496b1de78d93eec5a0cb2e7bac9dfee49e5a605064ef388e409724ebfe6c40d5f9f11dfcc276a11148d0d55e72b6ac84610399e32bb0f316a959d2b7e8ca9cb4b66d1f8441df2fafcc075d5e59d155a2a534ed59eb810b1b7bd67a986da7718fb1d6abd57f75dab65dc7793f1c1e89b6ffa97bee7fdc45a24dfd943fd35a4716d176b1b4412a4739dfdee83f358ba8718aa7fff94ee38d104d975eaef5ddb7687f1ac20c63fbf56cee3bc98d7faf134e697bcb8876d924b368e3c6ae2ba4a379655722f69d3cb8b61ccaab0e7defefd36695a028bd26596decfa8050fc6965b8a05f42fb6a6f4567508f7def75e2b904fa31f9129aab15a774c1a0b100bb70398ea3180083065e7459420a2921c0b22c4ee0c9408b196ce7c21516b25420382dbbece92169977336afd47a38aaffaa349d3d6b2208b3f59e351180e9626ef2c67b745c39e94d1f3f4203bd933aafd94d8ce9f29fb1a2636caf3192b0112dbb437dc8e99a6f9374f6398e83cdddf8ad97bb95b363ce74dd59b99c6e5a1a32396ff634c2b6e612442598ad6d25507737e64c97a5404e05e6b4651372627b8a7373b13d45d67cdf73dbb838e93856f47c9a9a3409e5d1b5528e7a3f290f18bee6e2af1a4bacf558d2b19c496ca756e6cc1b4b6a821ed458d2116cff1315c1f6770a82ed762c2993ed5fc7d94465bea39d1451a05bb335b91896b0c23427075e94ec1054c62466a52e6cfa3ad3676e2c2e74b1eb780314995aafeed4ad739c2d57ea4e6b9dd9d2f1da7a6db52b983912a528e54394584ceb3d6b474c2e30fe48c9061183289cb5d67659acdc5ce1a18887298e72080116cea60b143bece0c40e5d6ceeef15008022c500766061736fa980c2a4622e8e52736ef766505a7882c4b637744670ee6ed71525c14728107ca02b3a9140062e86af24b90e280153074512eb80216cdc5251754092edd640d054833ba00a927d826409d293a31b1c6082251718e0926f017364a557ae3db56c01e3ade451095d4e4a77788f93f9655ef54332e3508c2b5af5310f941de527b746a9cfa9d4833077ea897615cb27418ba930f4be8aa058f6d85ecf78a347c67ae3d3c844d64f48d5a31a9fbe7dd5abde3a8b8e3d603fbce56f43440b01d570a38863c1abbbbbbb1299560e77139fdeffb1f8ddfd27ad9def5f79266c45ddef7ceb3f7de6757b44ced6add320bb79f85b51c7dddd4927dddd6bcd9917076bbd5aeb75de79113049fbf3a9f5a739d5565bed77b6daea95029cadd756af34c8d5c3397d68d7838049de9a0430a0038b807d41388901c0ae7ddf76106ecea7cf320014b8fb5614f49043d1161adcb396030b4a30c5a104d90b8a83950e2c0f0eb19d9596d8b6b5051abb81e9a502af94b9b1cb9b1c1d1b37ecb4d3cb6d97f38b0ab8e0d9e50cb324896ddfdac7da28866d7f65b4c5b6ff640d53b6fd179316b6fd9e1f26406cfb4036bcb0ed0b0dd920c4b64f020cdbd69a5cb1edf798b51b86d8f669cc06366697f400439051d1121220095aa274995c61b31dd9aa4811b169f1395b82f8573db2ff19e9b2bc61e3e6857ca75c8d30c43df7372c9d69fae59c511b2fce9f7b72e67041501eba771c268410f439e88b404bf0a79dd8c9f0986fbf136d882f3bb242b03ff7fd6d4344afcad79e7f455b5fdba0c9121a6692e8195e18e955152a21f40c134bb48c10315c74ee41a64a0e2926fadbb34643125510dadbb34603119514fa6403992ffac445ea0b8dc12cc9228ae6f6accd109e67c52002e8c2760b02a6c20d2fa4b001cc7e158378932e3015646e80d9717a07a5b6e2ace249132dc0aa3853500398165a1349db5fa767fb2b0186e2a9c17bad30214416581565acc0ea15491c6de2529bfb1c72380885617ffb29cc5a3f051f4f8f7a6c471d24e9a7f7510885a1de8e43882c00767a1985a17eb5eaa9ad11a8b63811260cf51db08043c87eae41464b3f8514f038545bdcd3ef8005fcfe3af0e8409af0773f02f6a71df51d321c42a7cfa820534640a13ea16c94476ad4010b2535f2e8375a1d4938b2fdfa320ac39fc711ea1864089105c0f0cb28ac7b3b0aa130ee6dd840e3efac5bd0070d83d26a8bc3df8d2c218c290c857a0a43a1be7e0a29a0467aab2dee6be5e8526dd9aff6fd75d8771c14e631eaa74e69578ff910bceb05e3adbab4851600115d527a99ee526dd5efee7b07367d6f8d13081d6d9898efd057aa3fd43a6badb5d62a525b6bb56e5d48bd077e9e6116b50fbab32bffec44716b71f6a8f9bea6e6cb5fc5ee5b51a268fb397ff9e9e7ba79d8f0e08c43a674a7cf3f2a8893bf10e704a24db4c30743ef432f7c4f7f5f8f301cbfb0c7076483ef7963f9a386dff77d1feb83f03dd0f3f2dbe9c37ad5835eae15bcf1bc5a6b8fd8fe51c11b96e8836ece7bf0f573a29daeea7df8856108e4531fd630280cc3f07f6a48c2063d30f4beef77ea3f71f5e5f8beeffbbeef0bdffbaa9681361fc883e66bde86e6c3ef6b6a80d488e08fe3cf9815f43dcd7f5e0d9fc8c38450d814d5377635fc4e04c72ff5def7e1b07ea29d2ebc81ec39bdefc3e158e295e8e3f41f0fceb73c6f87f204a2ed3dfd1c3e6843714ed737e6ffc459fea8294f83558bdd839ef760f54016a86b0ccf53e52c53bff27bf00b6bf83131c499a711651e0465de9b91a9aa30fc7e3e183e1886ddfe38d8f49f8860e5365f38eeadd2a6cf7d0ef3e6b86efc218edd98837bee6dd771dfcd6ed2d8a67f9936fd0f47bd9fa31bbf7e39e87341d6ef5b13e8ae220a74d3fa459e39397722d106bf70ecfe134b1bf48da9fff19fda89de875c97c227aa3e71be6a2cb9f1870affe3aa3135faf6c409c3ea696a484eb6f72ba48d2d04687ef59c98c3fbd4672a762d1e4ea76ff1a06d97f1a7445650f7f4bb9196348f826f1e359f1f87f3033f1e60a6d413c1cfe20c1f0cc33c3f4f85a0d453d04bfd7cf0a70a1bc8ce4fbf0f78783f774a836349b43d8f077d2f259e40b4e98763e6a727f3f3591f6c1e313f770cd57f9fe97485ff4d577e1abeab38ee0422d558e69fbeb3536399df0420b1fdc3f7f73fd5870a5b3f08beb30fba733e8168a7c6395d610c911594fafca991c7c883be170404cb203bf5a907c56a1d0c02c11efb8b09c792c6be9807c792c6760cf8e1ffb8c5a13f977aa7de13bd8add049aa37b4f25fa08b2657e7e4132ef8974bc5af451b7cc7be3a5cf4366cc2cfd319f5f4664e9cf2f6342d018e49544b19dc7203c64e791c7fcafe665441adb74ee70c78834b63f1e34bffa1a9a077ff5fe05d1fcea734ee54f89d9bd95f8fdfc42a0f9d55812edd5aa0c82fff49fc80af29ee6bda7412adaf8c1cf9312d1b3f6836dcf6c3af2e866f7aa0c7e27e6487562e8d92050e79448412d8a65903dbbe93dcd58d24d73bf1cdd4f27333896767b793c7d27d62f077ef04f621e41f06b8540d30e14cb13f2ce0f4f7df83cbeee274d8da5efd47b9f59ffc2c3a6b7bacfcf12a7b7f2a780ecefc3fdcd2f47dedfff388eef4191d5bdeaf3b3ba4f7d58766350eac3eeb518860f82af43b14c7da95363508c67b1b42a0c3f3f28b2c04e64c97ccc779f5722cdc71067fefbb248f32b317f8c995c8a253806d13c0bfcd47f5f821fbe1659e01894faefe7c7f8b24af4667ee66388ded3cc783f4da0dbfb502c65c620d5b3bef21b83523f3ffc1c23ea30257edf89fa63c4ee5562eae717942a89be39370886c0c1a6df0f5a42dddd8882ef16144d7f72ad23eda37bee4fe27c2cd2ed311a67c5f207a753d0e9e41b2596f81bed09c45ee7a1c43c96166fd4177efd94c8e3f4fede7fe38f7ff9515fcae6407d238f53cefaf4e91cf9bff7443d9641f6d30f47aa0c73e41e1bf5df6b31f55a9c5e4e8d650af5c391bdb75f8ed40fffdea242efb388fa4e1fa0442fc7f7de784205d9de7fe374d21bcb3cce47a14e38c82ee7fff04d4bd813a7a043fe8096e107d483a86f3c620884de6fee33fe1ca0881f25e2c86349048447f7fab593f9b10fba518f12ed74e507c512e7387d414e85ccd0ff7dfe3aa44d3f3f04c03f3d16bfb1044271798200b80307ea830038f2a0ff870abb0b72e7d1e3f456fe50fc9147baf307dd6711e7c8df61b13c05a13e9fc61f75773f9f5e3adf004ef4f9bdc2babbe377d25f50fbc1c90ee7a4d45213e8f6afcffd8f6f73f462cb0aa27f9ffae8461434501271e309f77fdc7dc713eea390da773c81fe8f6f53fa76f4d10538c8b0e08ce86084d8440b530b921b1607f0423667aeacebfe0fe48eb1d8da11b3edfe5e90b8c71bb702bf502fea9a812e5fb4ea4c78d54197af6bbb515c31a0ae7b34c75d71d204d63110caea54c1dd17670de7460d00cdcdaeae81567233c4bb615c4b682049ca9d4b0a0da8ebe8ed761bd2faa66faf5bcf50e559e13a6ffa48c764394597acad936d86903c7328b7e793b13dcbd59e74eaf8744cd1de5508f7fdba73234bc6ceaa0ed9f7ccc9039842d317a18bc0e9710a275c7952e8fe747afca711d716f7a7116bea34062f9ac090628217dbdcfbe6c0056d67d5d22a0f8971a5d1e8d7d1a3d526dc908e0902ddda49f23e698dbab1d4c9e5bc716379e346e378937376498ba0c6a9b34b5a44474699a08374a2c326d9a3daf2ff466b4404d3317508899e886bcbfbec8d137ccf7a6310cfbe7f23809fc720f9934a7b64f445808a4061df48d6d6f46acb3e46fd69d6166754de995d122bc65a1bd1d992ff4a2fd9a6a5ca33619549c78a36cdc8fafb0ffac783eed3bfe36a466b0111bbd4fbd6198201d483d2287aacf13f16ea2e2c5cab6a1626fc28fbd2d1429793e9252ba2956861b48303d3e7ce806837a521b0d81fafeb05d7437a022f2029542f0ea88aac88efec983ef54ab99673a27dc84719c976abe9f2de6c379b4de9968ff2d1cd9691bc59ea6857cf28739683ed7946d4833b7a48668dfaf5bd59e5398d5e6cfc00935db1e7cdbcd89193d593b2ebe56e77470f69d7fff1264ed6e99a4197de2cb6eba76e9e51ca8bef5ccfa8f26427db7372b4eb9167b46b4eda3569d7e7625cec72322ee6cdbc594a49ffa82810d447e0954bb5ae2cae8bc8e5a4e0ba77a9409773f6e58dd207ca2ee7cc877a508f76eef017616e4d941419b25f1ccc1a7f803fe95cd137a525a6db74a235e8cf60eef0252aa34ec307127a2ee0535d50743997fcebd2d2d28e1d4b4b4b3b969696260b3a06a5e8d485047c016e14c24226e444975466c354663ff85f99baa850b1357591e32daa230505ea41e56a6cdef333d21ad469d8809464a3224566b9f71f02425f745a837e156f48994c2693bd349661990c17a14b2a7352df3b9a16ac825198d220425d87065e996acf0e0460d203179096fc8147c75b14572f5cfc0616b73a449049f70b11b32f576e72746cdcc8c08e1e95a77bfdd3e904d1d1e081081decc3690b9c51b7722e35d12b1d285e0c9f0cf4684ce845c6481a2377d09c91af8e928e40da2519db3446871479a40e8d91218d22b8cb5deaa2015e4decd88f74396f5c12e92d262a7326a507ca8bfe12937397bb55270cfae22e77ad6b4893e52e772f8d1866d3bc5e93906d0695ba94e68fcfaa92caf3c2c36e65c2da6c3621219bcd2664b3d958a0cb695baaff433d705ac366b30909d96c36219bcd966ba5b46225277439673f0df039539100b58494a4842e6f12521212d22c09b5845a4a424231e11e540f75118131751a514a1e9ee933ab349834a9d6b50217b6db55e22e77af8e0bf4abe7a266f0638552a16f982fb41f4a63051a0d088846a301d16834265d4eda17279b56a4cbc551ed72e5ca152656c8c20a152a4b9ee05643362f4a230722ac12959b141b94ed94ba16af4ec8d9c2ab02f80adbd594d58b882b58b878d161d38f02c4a67fa7f077626ed92244807a60af5c8ec6142e5cf8cef4a93fc265b229d7e94cd1619d27f8e44ac2bfce3aee07eff1358f784d970e0eba9cb7cbd4642bf19d3a7dec439172a95c228ab6cfdbad61b6af110b0a961fc0ec89c5072e587c30228a21372eb2d2ae444ca5ddf75acf77885a46e8f232fd709256d1205c71fa0e91fdf995f452995f50f73297a9b6301499ded366a48bdd45c99eb62348bbccb75d7fb5a7ed88d12ee9b6df75dd13594c6467ea322d55dcd9ac04025718aa83c5adad77ec7175a93b767d1c25ac7a681cb1ae2357e709cf658356f29db2a78746a371401d108d4603a2d1689dc35c55f46a4f5c238411484f14a171b7309f437556e035914eaeaabd7af6b33b3acc858326ad40d9faa74ad1f66f805093ed7f630825dbdffacc06d9758c792cd03da99f1933a3f30637aab4e4fac267b3d9cf9cfd6ce2d9cf260d1cb4175aff7ed94c78490705141c3c50404701a79f4f5aa0f29cc6a0d9aa3f0d007b0044d1f6b9b7b0fa3d80d058fd21bc69b2b0df510f401417bb63100817e778ab7e0eaba608fddbbb37b7b9746b5d11a08ab6631109ba9f39e54b9cd355835edbe1dbdd7b7dd43ac5ce3b4a5b55f4fcf998d617cc18ccdad47e1478da1a1248ecbc67cd8899d1e98b4a290a2c60f062430d4b47b81778b102a7b9219ab20984ac5093c20a2ab07851f1c4eef6ac5181250c6c64841630e182054c2538e20517b980d2161958b182165808f12b2de04064d6a808e342e2059bbe02b0674d0b1f36b8674d0b27572cd02483152cb684e9f203cc1ffbebff2420129850a2331a107597124de8e564dbbdba90d4a12e96860cd5fe58b94de8a1cbd15882398f924056122a4c078c2ea75218dff19dfab585756a804f349e547a803d39703b3462561754f9d8d5a4ef5fa35d4e25eb2d27334ad4664cb599129b65072e6c464db61a8e86044103145b11b04ca17802a916050cacc0aa38b7e8024667e8e1871a868065eb5971002000a20a0fb02ad2102801cbd70bd9134e7041e4600258eea64081049bb3208a4802cba72850fc80f2ac38c17811032b60559c2e38012c67cf8a02f8e22507236055a4301401cb019ea9a804cd1865358568060000002001a315000020100c088522915014a689268c0f14800c7188426e52381a8623418ec33008821806328618048c014401828c52366403980969f055d0e3f422f42027216e65593d900d1915e9498e863093c76fb43146057df32006757c3fe2ff1780ad5c2cec58f95f59ea5030d6caf9759a8085d1c4671d21c36be5a5ab08616eedbf1f0ebf082508fa549c527e03b9010799b61a9b8bc8ce0b4a1f0a9675cd8b113f42518d27081c91ad4795676894cab8ba98ab11bcd650c82fd9828efb263bade1ae1167f423ebba0a72cac5b67a90e4ef32a4318c05592298751d232e58594073a25e80db4bdda5b64bf834ab20d900a6fef8664112201f9fb80e183dbc9651beb414dd5b59ce37b1dc6ef754c2ad9bf01ef2dadfaaabfa8e6fc7d406bd3468bee0f617b7f6310418443cf654d88c058f3edc657feb309d8d1e11eddd1d12f514bc165a0e58646fd21e9d201bce90ab0d6f9e0268493636d8b1573a559d379a89f851cd2f9a6646b3cef9e482d4834ab2aa7c008f359dc71ffcb8218562cc5bfa437eae15b48013d93a7ef95672d921c7822f89bd2315d21bc9ee5655d68254b1fb1301936373697003c0113a975efde615b434545552bb6fa1ab1dbd3cad9366554d32155ac3bbbfde0a3d9f0add7275c10d2fc1916c2f1e9d3f4876377e15788c9d8179852a2996adb0750e8b4bb861dd276bfddb58d1427f4dc5dfc8d8d0719dbdf7b8d2096f3f2476c8b40aea8eeeed7ae909008c6c7a42609945be9198c7a3471751302a6cad801303d23f26fd3b2436b9a7b239a4917193b4120493f04a295ab351f16b7c7183c40a94084195bf24094594bda3a11f2b3edef197117f1603fd0cebe12346806fc26641588de045d06dec943cb898b432d5d0fceee54d7ce52c1d24cd90fda14654c4d57a03b27a352f5d185794531d98fcc129574c486a1031c86cbf58ae399596702bcec955507d722dc54645481a28341d2415588dc15d70bf5a6c74ff224f913f8ee6bbc82d10947e573daff92765aaad4dddccdc880849bdfd7921a33f26250d9a85a471b3d5eb1f4b4ac92890db32daf8abb565e56beea71af348c1f8febe3a68af5a350d534d8e109b007d58150018f33c1ead6ebc325882d0128cd07054f8183f1ae0e940011ff3fd2df43fda418881dda91009133d912f24cb617c33fa89c87dafb584484950bed81e7d903d4e6c5ca4a324c217e7aa42e9ba848dd386dd87fddaa9c4445954db003081e1bdbb55fff201d030b5a19a7d68c8322c16e768d8564fcd66a74861c31574b4206c9be4be638dab6695184dc4253fba4a756b26bb9f16f9b3acd3b52431978cee9c0a29896d1e26428f5bd6761e18a5e90ac6661af50beb98fde4909e15a1d8f6aa41722c8b69b597ad75ba3ddb0b2314c16801b19336255870827f523bb2e4e823539dd12ada6443e95f63179eaa0f5e44156b2d1153e7b1e9b9ff835d3ddb8949ae7c388a0414862c3fc1bcf9eb1398a7060eed99bc85b685615fb668b4f120eff5ee3a045d2bc4e5ee3c921180b20579029056ff2b57a4287a8433226939a75e8a1364ec822f5dd37d1f8982d67a61d212c9082b4ea0606bc7fb780b92cf7065340040330bc4f031be3ca8f0caf139e0b8208c227d4df909bde7612020095d528b6c13ab238c85ffb3c72e0d89a8fff4631772743f1c1dc06a0ce62fd0b99c7561f95efd7e5d12d170ba45740398ae575247393ef30e8d4299bfe146e2bac74e8b15f8414bdb494312b021de76b8a6da88573b91bcaa09912c6e6420cc09b08289096d1c1f268e30d642f38dd56b3739cdbc606fd263e87d0543302454d7910df1c64efcf05278127b24ed63ae7a53de9134c71aac276c844052922001b60b2ac488eff304e3e551576b8d50763522e3517c7559ea99bac638c03efc4e234b258f985263be6299af4b14e777a61e4b714b3d7cdac4091affb2c08238471a0ce3401500216a28e72dc014f9285292931940013e0fc51eb9aa48848e647d17d949571242673b7ec4447d467fc48c04bb9885e3db3e3a49659123c32a3e277d2e60f19bb2626f8a3c701f65aa4db48778d991997545ba8144a050350d9f650731b30003a218a9089c19772b69a9318dcb15819e405ae46940751cd22355e6d830390249cafc32d699cf11ca7c5af334ab6ffa1f92a2c696dd8760cf5e2b37f02249001d89a4104c52c5f499ef9642336c22f12e697b2d202e415cb25b47b8faa371eb1e76a7c9820c3e4c8506429a72d4dbb5ae795b932cf334dfcc6caf7cf0cc2a4c74ccd53665fa98e1d0b5821d7565f6375d9b01125d774232f31a9f3aa349433ba234a6f067e161ae10f5c5cbc3d6acf115306c4edff1872fd4e233465ca0d3b6ce003d1c53b78352f29cf3a7814ccbf07e1c01edf76d7ac0fe508d8b514d14929751088b3e4096a4b15b58fa35d6fbfe45f1ecf69993b2afdea93c04ecd8292e8c4fca72645f1e956b8cff5ce47408c146f1aed80afbbb8be67d4c5d9e5f90956e965f73dfd49dd3a8736a9c4c8b90b832d44e1eb9d3eeed6d424f9b787e5dfc4bc2383b47d24e1728657941ed793f96c440a357e2fa2eebe9fdedd247f60c8179c3060d49c89fdcb3b6d240ca2d10a5d4473d30b13e4e8d720c5f03385a0cf9174c2e458339dd9058613773dd06b8f885b76bf7c9102fae825bd85da27ec85054a2bd30784177d83916bb807ed5a03c59873f01532e30a5ad4739f44dace4a3a6a1aebc24fe0678940c54b62bf46053bb83b3264c0c2c5b4e9c79b6d06ddbfb3d87bcd91647295a912cd78b1d89800add38954b53652b9e5054796564d9a213b24df92e80cbc4ab4aed8b6d25eefa085687f13663a347a7ea8169034c6b4c953f110614408f725bb90ffa7458ba0d06a39880f001c6aba0ed41b5877fee1e8a41748bebfa3bfa88aceb7138c587aad5dd140a806436ac5c0e1ce808c5a33bf2230a9b501472f0224fa083411b44e024b9308e5882bf1b0ec7d186025691c9c9130728002bd1524331893bc141ace38c1b7d04d17e095da4fbc182068bba071e20a0996fd8f9a1bb85d45412e7a072379384fd6c0813a5f80ba4ce67c02a61e7ced18230d5ed9b373c804244d7cfc7adf53f0de84e18fefba302716e097d0dee686252353fd01421a0d4987e2e3f5cf1b886b06e26c20ac94b2404eb1cdbfa5d7df5707c7324c54f1a1a7a0d01958a50464d86452b11f171ab80f7142db587d7b6052e53f56f1f3d3aaf45eddf00f0d4614e64f20db8808d5e3e8a1b2ed266b4c25889d3b75d2c4a428a41200d603ae53d170c289c028b2d85e2ea77ec8cc33d5e61b72b3891f78aa6b8e9ba1e3982449e7d2966987622339f65ea181b81986dc257c3543a7d6aca873e44625c52676dde01924642e27b3b9316695db14dda187c8c3ba3dd7cc6b7df175333ebbcaab53c42e06319883b91e4aed098e0e26678b3767b7563b7c03daf057ca5d51ee2e9a67dff2579cf0ebaec6c6b9da524328f1cee6ada08dca8176fc81f2ebdff308ed5b7fa47cf80de727ff6598ae2ac6298bd6d0e51706a0f3c1708c355f3d66d94c3d6146d84eaa2a3e850c59a663336d42961b0b0181017ff2280ba38655785a8d0306e4ff870c6f2c5cd7a9f8a68f4acd5805bec0d7809bdfb2383945c2f43f650e8014abdcf2b3f85720cecefd60264c81b4a821914a160bba1166b4ee6b82c4ceddd02fd08037bda34923c62901353c22cfdf74273173bd138c6f837d12e4e58457813732ae6bdb2438978c56a74b55be760c590d1a8a87484f89666a72db50d8b37608c9baac43e3824f9305e6e620da604342ce4ebd98cd6d2e03269997b7189d35983e7e4b02edbe510184d543a9dce5293157d8393ceb7071a8b4ae4bb0e60b56e92ac25da2b0d676d5a274df5b94c6423d202dd8f6e333abd08925c64f8da3b920a2b7c8b1a7c54daf77223cb0797ceda0052d7dcfe00b26d63de70155f2548c44f779c1e953d28bd821ada6bd42e7b133b23bbd0cf7dce2291c41fdc68819e4858861ca6646f98fd539d9886292f6c983d4c7de96404235ad9d9ecde46f6a998f0177ba86afe347a40cdba05120d63b4adcf9e0dc7a99f33b6302b7f212fce10e212a65e8985107635bd3f38bf2af198ae225fc415d2d62abe46446fa76ff8677886738430b305bbc9ed2a6b07875d1c919812da8235d54b5d187be660809ec661e0038b476c25ee3e06c28983f5338304cc40a0e434205407181450829d666fe68cfeed17f438ef64b08cb65a68fb179918096e3677ce3c4fa768b28ea931c1ee95563f13ae56b1f2c2dab378e2382824962c4e82ea239ee08b163d6b8c46ea04977a5ff1c80552cf944c760ff979310fe482cfafa7d35eaf264b0b03d45ff8c8dcdfdceb878153d4d8a956d126903541638f925dda36420a085dd4a2e5401965762dd6da93d91572fee97510b1b6d0f99a72ec00d18fcd07e1202e0b235d9445e4401964742d56db9329bbde2e18e2b88ecbeab8dd3405b3844fe4feb84abb4db739a08237d70e5fedba3221a441cd523f9e8469ca5821258d2aaa15c675045045d9b62b30f13abceea92145add5e88223f2f5a2523e7867214c8cf59168bc9e66928414d941acb370ec4efc5f5f6d06486edd11c2cc6970eafaf334e1051466701c22268cec002f9d85c25520903fbe5a1af9078f06ff30bab46fb94338a265685da5c25521a045d4c5e02b147b2ff47df4b7bc0ae0218c883efb2c6f2c4d88167779f6c3ed3068b53fe7d69d3de52083871fd42c092bbde6b8f4a325b1f4e1fd6a8f1a977891b7e7507f6196b34faf9832bf68952e81dfb9c6e877f47260dde0767569cf1eb21f959c16042716f89fdd52905745f5daca78489875da103d5444e2083262723dacd88b816b5abda6f02c2f6a52ba6a7e8ec376ac239196e0ceafc8a614691538d65abbf7d0b5f81cf4af960420d4daed16d3bb2b3a1f28452835bc74977ad3fdaaf73593ce0cd49803a7ee0c920716b3ccdf665f2390d1d6a9d081a52e18800570c8ed10e198fbac1b31c96cb59899e9a5f6a0cee5faa1f70a1e6edc0b5ad8850c043ce2b5d3a40be8a719ec5a20e6bbd2e12949bafc9732a0702909e3862dde6d8c8a868ebc3b56721d3105af497870971804b40dc7d2a1a4dbfc32406be5dc0cd4982ca014d5da611aba279d649260e602bf1158685944409dc46e8c50a53042edc7995470844f16c459a4796272433e5ebb48820be8ef02ba7f066e43fb82cc7a42910bb927afeac9d5ff1b25a067714a88756e7262acbf4e850dd083ea1fb67de2133613791ac4c6ab9974066ee3f528ed821172927141a1a8f961da67398e1dd2cd59dee2ad6cfa49e5209cf06448c920840ad15777b35382dffa41f6add15929e2e0044c3e7fa8e0e00b4e70cb1141f16cad6dcdc4b02ba969dea89771252acb6afec939f9266d1812d774ab7adf9dbf045b34dc422a048279d8e697d9327c813407d3309c0bf77439b286f4b1b23400a5ccd767430e369900a4b8de8724122b912e751bb93da902cd061effbd5fd4e2db5025d6865acfef8a9f1a9a8d41e52c328c7c9e24d619b58938c775315f20268cc4a31b586fe1588d42a09adf1368cb5cec1043a982b6404538ba78c796ebdea65e0d4f9b661377d8422ab0eaf45e6e3880fd1e2cb2a561dc0044502c0245c34efaa5eb567b64418743b83b348b9ff6e4ff46002f850f14216c311d2bf750b1b2618ac7e794e07f9ce52567c80fb88b9b40b7bca5a40c3aca5d11d8981ec354c4afc15f581051e076f1cdb8f701cfa9513f38d7515e83fc94dac25d3f0b9fc0b0628b758cef05f9a44bae129ef47ae6bb0ce13a3e070e3816629329416c3144cb342292926b81191d4206470d43f2df6c29deda31866abe35055cbca3a09a4693de4b896a00891e3650b7456a661472f503d222fa178b80fd676c8502dbc6ccc089dbc9ec79db5158f8c627a9b7192a9c8858550c604af7d4e8072d1b96c80ec1860f5050aaa5bbb51d95a92eb58d5168a0fbbdec5de552333628366424006cd4db75bd813ad7a10883c8988a135725b8a928e04649f68d2aedd080a01a5e36808341ab7348aa5de1c6d84f8f8647011e8b1e4a5845e25a2067300f1b23a6b64da8ecbba5ca8bf68eab24d67b3f130edbd000a2e39c7dfadb8edd6fd5ad7015691eb12ea5ae97ee526fb8dfac2525c4d30cc58dee79ce897133c4c7f85002b7c1f7cdb9f4231e9b25b9cc6b7e63dbd77d91fc0a879341fcda266f49f8a2c90d95d5b316ab96fb284d85de1e0c3f9627fbf389a49ebc1bb2f5713540ce711253dd0f8e72115d6ba09907d2dbe4d5895a1df1a0e491b96249093339e8858a2c56955df82eda7672b20c85c3d76b3dc4cc693195a11cdd6b676dfa28a26a20fe2d9ef28b9c3bfc383cc055a6cd8a2e863aff8f2ecd051973fcd28a5f484065b23f98b3f0035af38fef141aec70b7ee98fd6b63f52c5fdb02e9a8af5dc172ead926deef8bcfd519df415b3b198682d4dc077249b5905775e6d6c89c64d9e90f31ca7195727c8ed370dd3b68e78eb72e18d6a3837413c0117f3757ef47072c4f653d50a20a1ab489385b3ca5769864517b59516bcd3a0a15cbc2e49ea0b8f02e5d501e3acfa79ac1de86b1539235e395ce3f1446602307087f9286e5c10c8a7bd81b3638bef098cec5de1b4c7b10d1a196d14e28ddeac47aa2ccf8e172d4f580d27b96782cf31ed10b255e301026466c4b7dd3c87bc77c905d2de4cb502669ca4b3bb4e9f4361fa07fc90f123f51ae2b68bcecc75b6a14dccf141fc12958611d501da28f727f6984086c7eb2fa9e2edd6f3508a889112d96c172454744cef7a42f60f34d1f210f08b90c117a8ffa82fb48e7632045f93c422f751904895dc4f635114022b79c32d01947452ce29b56fbc1ffd1af8cf106b38631a36d10be8536e8065ebb242699fb24d4924e6916e0b8067a7c83e3504bf736825ab0c824ffd6d5d0fd5962ade8cd66ce818db9af643c3878a1825234f7161988c421857f26b22eb60a7e56f126bdf9b34d7f1e2f2956fc39c0c6e73e816b589ec00b4b3f5b2a13960ee6aec8d67135946a0434890b434541527776149b13bc68027c7ac87e450e3ce5f9b2ecf7cf6e4957f48279da3c60da8bcab90b7e2be3f20884fff04bc48bcfbfa50ccf275531f23da082efcc799ff3376d08703dff5ab3a45303d7ba1d87e6d0edbe1b022a9e9ba1ce6643942b8ebcfed50ad733c5e4b3faae8050cbc957029a75f2c8222b46d4c7643a77a8427ad24495296a9801ef7f90fb28080063391296ec18df4324412a1f932672b10a3430ae5b258b2245478f4cf405ca4056145f8e1132f92099c0f0136856a150841ad9cdbdc0381da5642e812c9842bc502c8f2c3330e19e33b0007208a7fa56e7726e5028ab3613b913ef03ba21badb89cf3e50d4cb474eef76749676ad8fa7e53bf582eaf9b54b408bd7a0497fe80ebb8f55b2aa8bf8433ac90f1f5d893b1382555d567eff657a91853b18b7c8a0984897bbd46a0a5af70742ef92d3ae5aaf27eea05e58d5c98dd10e31254938911ecc53e0693cc2040544e2b108399454e7af29d539af0078aed7c74e3cf7332e74c008a91725a92dd60e3a7ddb23930a077439f066c445802cd93463b6f7b4e9beef5350b92cb76d25f47ab9329aebb6e5a9cdf34f5504b3fecdbf90ac894bcb11a82fcf10fbfd85cfa43e658bb7e4c7835bb20bfc3ab09a04274408ccaf1ed56e687f4ffdfbc955bd722635caae581a1f47de28a95d5b91c34284c6cbaad1bc4605240749c8f1bc0b024743e393173fc4fc311c4c9306503bd6b5affffb0dfe0ea4a573a749fa5d944d92ddcdb113b6210b27adaf8006761d2f43935ddcb4958f34b6018a42ee01e4c6bfc91ec302fe861711a3a1e55e5554ad1aad8e7e1622f3dca9a85a2800f18f3ff51cba2b1bf92bf07ad54902230b5d513a5f98fde1c418bc0716437189a052b4c068aa7191552eb097b304fac080e29426f9bec0701760d40e6b57bebcc3a31e5f345f3d766f83076e3c6e87ec4e3581010e086866f56d8210a05e780b48b494b1db3159c0133c8ec9d406188abff2e4a7b9ff7ae9af4d2ec9b828a8ef0cfe5e187564adf205540c6720274ea721093bed859bb7b7f04ecf5a2028ae7730828b14711b6c212ba96d6f7c4d6aecda5e4ff3ce769be849f226ece115fba7fca60e73f802b52a46df1149936269527c398d5ae940cdaf66bc24eacfbcf6954d2a87bb472a18e8fe337b2715518f0f64e66e27c2c10e2a9784fd1ab0129640e984cd011b9559504f834b8dd0003a018b050e44026ed2b2cc83302c7cd74fae859cf7b6e950982df05d022a8c4e8cfc9d0b8e5e7ebd61973ff4a09b625a3597328176168ce7874af8ad49711dba1bdabfe1d76a5690ae1032d1f8080c3b65dcbce7e678c034542491b4cb1084e15123b4303bbaaa60c24aaf171d5075bfe12386018f6bdb45679c3e24a14907b382877f47d15ef6ef55b4f270c9bf7e823787b70d5691ad0eb88bef5079a6391344d897a0291bedbda21596d432fb82d16cb612c59cfeb16c831f10fc53e3ce6d4e2c078dcfb374a54918eeb252cabc3da3d4d702767de163e8f84b7708c5bb2c7c6567c07d8a95f97d7f9c39ef5fe7cc498a4e19337a5a470e56855d935ab83993abfcaa8e6c3739d06f73eadac6b0b65e0d0fb9008db2d62058f2b20e6c283ceffc4beef2e980f801f84e1ea154a736ff73f75e4c4d8e64c269fe03b86aba4fe37cfca6b5e09785c386ddf055bc35f99e7c1aa75da0918e1074f1ceb684d5d291bcf7d3344c93a5c1d680980a861525f74713714d3a2cef488a6855eae983513e356c66935c0a55f197ed52ef5c9333b0216f92236c27cafd48bb164d781883e240271581aabddc36298bd1c3ec98057c622680ec7b545a43e68b0801eadf0324192af2ea89591c9c2d4c2be3450483a51a18a0380269cd84621244aa437c76c94b71502a75f460e496a13a55408fafb77abb6d27ec12db8153406d897ddff2a519bed9ccd99de38097da82f996f4d8862ad368f91adea11120a1c1a9582d048009c34bda798d443edee9a3e191851752eb17f730a0c51c0e6f370aabf11dbf05b8e66e4e095a66f9f96e77f0f657d04d8f247c97e868b027d6b62d117838ef89fa31281cfaadc319097c0f4573206c20c8d22ddfbd24666022f3cafb9381c04e609924be3f6af4197c62d377222b2542858d8f674c457086d4ff1526a1afdccf38be631cf5fdb92fda83368bd6dddc039280fa173cc934a79b57ad1cd1f0d878d54b082a05e83477127f206074017a1e4ddb36f7bf48b20a7eb223e57febb57671417b14b0f42e205a705ec9a47b57656f0e71170099c0dcc177b1f09f58c062567536627e8d356b65a0f276a7a016cb3af88e1f070854765243631ea2c0ce2f5f48b16209544625602e1dc47b1d164d90acea281e0127c497fdc1b03f29fba3f3c889b1415ddfe74e2afb0ab44b14a20c7986de7f7eb71672d7df0232b5ece43bdba349b6d6497adee9ce64e658401b1c27dcaa2f1d4dabe152d4609397d4aa91b36174e3aa63532f668b734be5f430b9e9dd8d1e8611a01f213b5e41221bb8ed6e4a4bc752cf5af3418f2ff798d5cc595782395477d0ab303b91ceb4f6d0770a8a228089bb72be6878a9883adea4b5eb3788bc6b124fc9134e19c7cf6e04bea32929cb2be7f2f95d7a1289e4ed1c82a698777fc0b00fa012142c05e1dd09044027137c99915b6319a01bf5b1131e6e83df3d00e94c4ee1e82f775743067d05cd3cc6173497eba57e6ff88b1c1d6eda7a7b77f2ac551fffec5477d3895956870c3a18952db35f9b5d05787dbdf22160564035f996829b879fea8fc9151f18e70b02eb4254be8382ee845b73b4ff618f004c5ab3f711bdab619cffae9b911a2ebcde9761d802462a0597653d0d3661267e3cf70d80d255a18ea8a5d751f7327ea162b52712a785ba51bb41288735e243f12013fbf49dc71ab10a6f3bf449f36c09e6986e08532dde1cada150bebed0edf39bd5f35436eed9a54311850bbcc346cfcb6d192c8f10599e445f3ad859c3e6031acc025c9b4211d61963de5ac558b699acdee43af6cebad9b0af031e4ab923f202fcd145856e5d4faa023c599ceee0f94953811cb7ff6e010d62a92388810379803b0b417709c968e720dfaafd05b04afbd599476fecfcb3732b1140af6f5bd182d24720f39cf9174fcf9f91552fb0a091d197f425fc51cf60b9b8c4263c526c209b46031f31c9d2f391669285f6c7ec23caf7da04ccc9e1bde038fc80cb7a4a6079c3cdd35f9ba91acd0cbbe4cbb070532633b6275ed42e8ec71eb61c9a4c0e77ffeeeb98bdde5fcdc62a35e00102dddf16696db0fedaf7731197e3473bfedbda2c10c89840d84a3b566095e36854a740db09905afcca5aa37a81eaf9f4ce259159381c7235c3583397a6621e27d8c5ce62dc8a43ba641da02d1b750f39e7484af0e1a79a4bb45a88feb4a51199726ee14fe99a2b0a899bbf66b36502a3179cd292b87b07be2aa791120e69604e831c97c33dfc62cc360a2e4fcf443508e44703d1647314bc92faf81871ac5751daa48a0fd7c5dd8125eb7cbb3224c3cdaec8ec3b976b27d4b86f00eaf006dd1e57124a0fbaab37b8332b9f0654bccd1549f7834dd4716bafb5bb7a91da039d68dcab5bfb242a982a5dcbab5da23beb0c98d5c5881ab413543953c47086e032f42c20e6ef66c686c5e0ab1ba7706c085a0860b62c70b7c0ea41fc80c9b70ad2b992da10fa112bb094296b5c44945ed0c187d8b058d9d1e7c41583acd62801c607cbecdd1b0d2bbd978dfb3dd5a608d07ec41728bc8ed571e9897bcd97166719976c6cd6bcb3b8d609caee9073203970a9b218575f8b41da548241abe1a324fa05db08779a1b9b42158642673f54a05fd31e5c00ac5734933ee730e866f95f6c7146871a69a9e92b04211f706f3a8c57cf25335ca5bb8336a885af3c0b3e76b91184b890febfdcc584217e5fe432dd0b4ad090729374df0e4ee3faa508c5842e76c0759c54848020144c72a5d55439b2bf3ecb01c14b4e670f072bacb5c70c690fb374f625e1e2e02eaf7333bb1fcd30cbc42417098dfaabfef599526e5cb40ef22c998b52b158182b99a9d0183b080fa63c5177f7d62c2ad6b2591bf5d84577db205dd1a8202fe2e9d44dd70ba4d05c8ee2b81ccae3aea04cc527d87ad03707412ad2a18cca742c0577c328e4171ce32c581df50c76c7da1b094841b9325f17ab552cb3c0b67c19c7612ea428d76acb3d08e66931433f585ed36f1e232945f50e02808a44bfb1406ff772774d465135c2adf28cc245fc9c48ddba57f573cf1f3231e506b0f6e91fb4c3a58c62f8f930e3835aab242091cda1cdcde64b0a79d25b8dde1ea4483f8c0d3ea517c438220d918d4d9f809a3f70efedb02ffdc741c4e80ed03424bd5ba30b8e68014dfa682da16e70b130f0d223020f0c0e7145785b8427c9e897429d8d9f816896f6c087416dfa1a9a1cbee520437d582dc0c27b452dd5b936f0d96bdcceff821c947719e68731bd25d8dab5de6c7ce961a0a4fb35c53a6a4fb2597ff32bd8420a433895f4638163f0e5a53131248ee3d29b2fc0963572710d947f927c17f1e4c47a9331d646ae86eb66d325eda50bee13df2e315b677e1ed2f3fe642e7924c20f4517832339fe0b02bf13b4cf72a2bce346bdcf561584dfcd4b576fd256c605ae2dc254f78c7af183f8a5783ee63c769c6a93da401fd831ada4479abd0b6de8d55cc0a355eaa7fb363ca32cf6f5d3080cb4c77519a4321205bddb2f1144ea7acd07aa7aa8a52a13796ecd49f9726ea48f2baa6da420160bd48a0701a3193b93d048cff93c4cedd134f6ed29098d2de3b9fe7e4335ed34c03ac3b798851c14ec2a27c0ead9dde7fb37bb2d88a17c287998351f23ede626db5c9fec4e4068d5970be07dbaa2ef71b54a39ff16cfd040d7cc178b6f111d051c03fe2f96f354d3096ed5000cef038da09a5caf03b50411cd6b3e5780f2cf28f23ce0c5680fda19b18a71593a72ed81c2c0a84a0ea3feec2afa20e1b65265ad9a3dafb9dd15a6b3c3b8b669fc8b2e99d55a6a90674060f02613eeb2c0a96f51bee40526a90cef2c70f0194a8a524923e702d1ac5a595f1c7f2585f1cb40faefdebe3759add38f36889c93a2bacb1c0f4bbc0338e73427d1269533e0716a6f6bb13387f395ae85561ce7a8292bcb36f8001a65c4e5f7398c901e7b7256db787af8aec80caa5b24211ff9ace03d07e92a3e83f07b1b6755faf26626c4b64cc63215a81906a948f33d5646d655ea8a62caad80f5ccdb0c505aa81026dc00bb0c0817c9208b7cfb50b89cc7147a2fe8bb71ef3785499632dfb083cb631f49c6ba0351c79b90fe0dd7978e425adc47e60590f2607093f1181684887d37d1630f3574c9c8cacd6d9a2da36998db0f2f4ad63cb175a607e9e0f73f085468a3aeb18817b64d3c702fcb80a063f1ea6a8c4c3d408504b5e7a1a215b8d66edcf4bd3bac290661a8ab3c074d0954df10e81dc00c272ffcfd75005543670dba305286c27c4beaa6c7ba94276a73b140b4862997fe136d9452c3f16a5932d9e0f50398f9f8e51e5dcb6d7d82ca2640f7570419ebb3d1fb5a1e4a191905e110b9be7ec148b0a115cc0b85c5ea5f94e801a8e189caa022bb3234c096e106c5a940846134110822c645ee99615c9893140769f4e58a6d648e3144437167e83786c9c4fb11d00f8c18888c7161dae411985688180d4416c9e74106f9433f0c5eae93b359df1e02723016849728e0ae0ba6652e0f85e15c0b21c619ece3023e3ed27ca9c1e95294280a4cc6467dc6c9e376ec9738042ca29706d35fbe821730f9440ee6b593d812eb963c7b6e261a9915a64904153bf708f63b36c466b2c3a2cc08918078fa40f47a45ee3cc377708809280917071ca6f31db41e0475f03e4674c6ccc0dfdcccf22159ac9e9f259ed924e897a92f774027b59a6c1872ba605b146ffc602850b605ddabac97800451b22059fae3549e8d10929ec8eefc87572f97d2265f342c7e77c96cb4d541da4e9c375859b2e5dd4d5a6f4b5fd9ca9596cc84f38d1eda0d4d8eb5b8fe1525d35cce75bb38384b09045af27592dd52e840585b563dfeac96420402f03048da46107c49bd2d6fe6d30deba74802143b92b05444945e36ccd48a6a612b1528efa3dfab05c5a2ce95b4801b6379e36f6f4e6bba406b2b8a775d780da3065d04b2cb1f7a041d7e104c973c1ef14cae8bd5bd79cf114fab77331a98ef61f01cf12314b81020ecfbca45af2949cf275d26359f752b85240895f61b623f8c4455e97fa04a8e7ab07ad17753bcb28b89f11572c7799698a3a9b2fb27c022fe501007385ec1c02d1360dce9c86682553887ddfd1422403fb4e36415054ffff22d5b99359e72550e82fbc6fab6a7ecfde6561f5910357e72fd31ab5e427cdb1fbd158d2bdb5873803bcaa1f252df5e6f153fc639730c7a79e23e4d685bf0d48483427c18a2554a4e773c6aa32663711ec1ac057050388c3adb446794b6ab989245ac0bd532f9839c41d4ccde94d4a631492596bd2c5b05a00161c7c0f1864bb7f68d9a06e705019cd7975374bbd1c82a29976f322f68fc5b90a210682edfe59f77ba53d6d0d8e6a464e3097966cf480dbc6dbc74d72665a8e3b6d4e3f49a6d334634a30e1041bc6fbe76437b03201e696075e54afd505d3e08107329e3cc55361d1e904aee2c4110dca31f87d026df9937c559bb2246b5e7b2e4b945e1cac4e4d19a05821d4924f7315c4a8abe685c98d633078b97c7f6d2157554620b9720c16c8ddd7f6aba042193e514209ac2a2ce933ed91f17588e29890165005dbed91ccc001451ae29118d08551fbccb883a6a388581f4b381e238c097aee4b8eac3fff80de561ff995b4c2bda127726376cdfd04778cb6840c9ca004558559039eb44cc2ed4689ae8354309591ca8f3dd6af59998458ae9c6f8b1a4447533801b9f55de366e6d4a3051406200fe9d7bc3236784404b5f387dd100e4ca653e848302c64e8e87cce6fdd6ee2d85e515f415672d1504cb86f5d3b7fbbeddcce4099f98497dfd446024f3891841d3fa1e656933847a545e48b153c2029c7c11d3f9fe49f4bf0972c176bfa29629de9562e385ae2ac0b61b561df3f82d15ffec4a9c310c01e333bb606d013ca3dac8b58af69240bf882b56d9fa33e7f965ba4c0e7b04af87087012d1e39bcf9ab84ed71deaf0aeb2ed270a2a36805c768e81f06863816105701f41f1aa3af61f93b46c26e82debd8d35fab3c58dbe705f7feb571f613a63bdd8e0e3cd399207f74c3761f3aedc8f000aafa557530f427f16413f510212a7647621e071ebcb09920caffa8c05208f0cf76bc711caf0fe0de8896a29a6632c998061776da4f65636cf65b51742020d043bc15240a0e359d588b0186d47813f04ffb5951a62010b662f9ecf72fc3b5dc8341930bd4fdd573e2f01e3248bef1783891d3509a6e8aca660c7699f2fba430988b09ff76506a18854d4593b152b7ad3bda530339ebf9cd5915c82c8fa662279701993762f639149013b04fea4ab06b50e894dc47b7a1aeb867e69251b1b81d56a4890aadfbcc84aed1d02f12b4c0bc0cfa14180b974e88eb4e64530bdee451ebebf5c3f2dc93b5e888d6469b64361106a01c32cf93c0aaf68d10e6a01c8da065cf2c56002e19b60be86b100f45ea3cf43f6e43f1c21db26d0859807675b483567c0fa037bb3d42f052e730a0b0c990b47e34a6f53d92e4f32903ffd4b126da3c315f15e9542f1a4d2851f6e1a7b99d37499f0d186685b51abc4cfdcb9be8d15b4a102c7f423d1e696a6e0e49b85e3349b2166d1451aa9a590288b0a003bb29c9409580fb0363a34ccf15e1e254c9240392a6c4e7d820be8e2420ed7dbed25287dc131a21191e339b1cdac307a0d41017331a6f2b4a9943682a0da0990c730ea377cb8fdb5ae5c905b6da29eb64860808b5ba6977a40573990377577bf1d8cefa50327c9b1f3d58a6c51ad4eb893cc9c9870a82808e37ed90fde433821447b1e9b9492c01f2c308b76df9401cf3c217d4ddef7faa9148af9fec08a0326e67e44cdc4c195ed4045b1b40a5aa2170065af523bc0cd8408495255b9fde213e64350604d39590123034686ac22ad6723680fe245f5db1a00d7558f3ec729c286be212a97a6cc96da27e435168a6e9d7bc950071735f46f1f59075c812fbe0fd9324cac2c1328fdac61fcb7b3dae51162df2edc32c59a4c9f40c3ec11048d64addedb1bcedcbd1e2843091c43a049d51dc8cbbc64be0148daddb7b6d154bca4898cd401a45822c842d7c7c76c81923196b2302fe53f8b54a4103c2d342bdb5470edf66a7e8198724abb9ba27d078d703b3e6d22c55e75ecc884d6d4edcd070ab180b0817f0860202fe88438516a774415213c4736e48f5dbcb328e4f3a574bd15ae9497c67405e52354d0be18be9b61d20f52aa462a2e50d3d3f7e018bf20183c70b8601bb434c456c397d2543f512b879acf655adf6f19833f2a4961f310385af9078fc9edcc9ff999f483a8a39007b2e21aa2355bd4c65902e500fadeac94bb5fa350ca41d700e3350895281619765ba7bde20410cafc62a37d10bea8efc32da07f08dfe78e7cd8099e3425b48a1366cec7fef1271a7af4bc211b3861313043b284c24bac96d5ca864d2fadf7d2578811291971376801dd31d4a1a5f9b11a315bf45a2aee7d1e3354f6d9134b9fd13b17ebdf0dcf559474d1bfc6c1fd4e0bcc03a42369d7842767071b596c77e2a0b2eed9d6ff82f0412729164e76da3369ef79adb8e397d39952070e742b219a37e072b13f117c00ec8bdae242585044d548a4baa84369601ef1a21a96207056911753f33160ebe2e6aa41409d7a55aaf04b69681bc06e12e11d35dfc6533e4eba3745b52d1c66ebceba74d7d417069dfffc4e14058000718b42b291fea420829571a2c831c26625e36aeaf6dc071a2643e7ce87b566fc30c1735b80a4e764e0d780688c9de6ca8e76fb4010fc67c1deddc8d80d3be1a18a063a93636a87f9e8b1d651ab06df8b98bd4549d38e099d1735b2839e5834d25f12a55a49dcfb83bca4a05b14fbda35782ae42af1c346125abb6c38c06c4551d0c5d9e38d539242892de0e450aa5edfe3662f61fd459cfd2e52883420fd0cfea8de54f2441ad94271269ce10ec7c2d5e0f3674f4ef8faf97d7412032b96329423fd79a21066d95fc47e78b584d7de89ad97590f838609330a4d6c6403747e930a7ec7053c6a7831268eb31ba4d01ab3cd5583d46c91457032577d7b64583fe9d555506c45ae2fa6332f58e386353a7922d1c28602f4c7b1a8b445d860187608cd635d95cb068adf8ac30e4b2681eb3017d2425bd7f3ed680b54508e4a79351362b7c83d1fa148f4f8aedd8da82079c03125bdc5d390183cce7f52f9260936c646450ef0f444d97e3f5c38d353852a8161d86571f6f51e42054afbe759f6c2605a1685906224b89e7d5484afeb247a2ec790665a0ae381eb5c8d8031818918702f14d924a01a9a21ab81b649482e1d17c0beb447084856018daeb60bd293c4ab17b2b489d6d970391d75b7e96c1d3d4d37cf1380c80c3032e34271a35bd83a237c8e9d64eb94944b8fe2579b8862a1a5069f6d1da3d2f7b0aa21408f53e440708dd6d71d6fea69af8636910a1ba0d290f506eb33bf281dd03ca3ee9d7d7613d2418499310b2240e7d11826e6d9a8ebdaa43518a38e375aa162b48036d1525c3ea63441f4d489191b4f503f41e08e970b8bde000ed10e44c2a749b1cdffa91942113f5a1f069ae2fe53f2006bc8ce17afd47ff6fe5fe1f1fa4af5f012cb1e858d71b465751afe7123fa02485036cc8e9522165a402de274b8d6a2294dab816f5da981b421484be77c07c8c02282c9ad29542d41b329fa41910f5aa0a9a09dbe037acc2c316910970b3438f2710758de2e0436e0f8cb1af0fef2d1d38da6598a390cdd062f5e30e9c64cc2f3bcb013603e230b5425c323790a3c9e1311a9bc67be2015a235524c86cae76111ef33e7f8e74b5efd0c03747ba6532dfcd1ad16f691972c19fb93e7112c3edbc7e975e60d4e4ae82e0393f711d0e3f73c82c20e44da291c81ae64c3a4700c2edc0ae7850bb41b4de670c9f9e7f798620f6a87c1bd4e506cad93c87c4c673755a99f44d6419daccb33baa9ecd3a5072213d4b13aa5abce5ba59b4c71b63f2ae5333707f8c755900daad2e6654c69a4c676a2ba0310e63e745dd4c7a8e4e39fc9ab31accd2ed1418da3dce711ac60f4ce5d0b0dbd71002a325f9422637711c7c424448d7e8e56a2986feb11ae03b914bae975e6e1866840282e330169351032d0815fb982294bc84c5df2fa065a067aa012f341be15e29d9658eaacfac2d698073bb62978a6947dd016a0bf250626fa578d9fcb4d605fbbf9aa1c029a3c174cae34b7978e786a73b2a14eb8206117c4c2a1bbb64c505e323f3ba39401122f3aa4400388fc1add056f07266c6c4c04c4241392951841252f06979c781f8937f2eff0f2060e4d4cd833b5e4680deb032082f91e20dccf22205949fb20cc7163f0efc91702f39004c0fc0c6180e7220f034a9fce6c0f3ac5ab1bd27c24c43c387a3d8229cac53ee723c07304c00988cdaa5687e2f11b2dbee7ee9bcc6e5e67705edc6d6abdd84c85dd3d96c48153a360c99ea49f4f065edc4f5b3e9ddd5ff994b58abf07cd9e4d93d1b9d96344ea3b37949f4825226545c3f36ccebb62acdc9b8fc3c68750173b33b3f11aef81fbb6942ff1e24c1d22976bf5792fbe8a14d07d9ad8d8e7484aa66c3030b5db02d82ae043d1201dabae4cd4546c1d1899473990129e409b44ab31cfbd8317810def864d12a96f9aac5ccf3dd91d76d2de557cb3200388e3a687bf8eb1885324732b914c786cc1ab0cb61e4ef3bc22c1eec1009eaca1b325599458e2c26a29d77328d046e0014e6a3632c949948af3e2d25a59543071081fce973684c37ca302f960905876ec7140d2c2150fd41681be7629340ecd320400511e9158a89543966ff9f0e54877d63c72051983d4aa015a3cc3195830585bf759f0a5596600cc437682c1fe378df1a830311da8b6a66a7f8091452ef4ae5fa054bc35b038e1e2dc8397e7bcde6e733bbf387f9ebf22e4bee8cd4e19f49937be1303dfae259c8745a09b8f7951cca167dae375a01742b0dad87b1882cf9d3eda0de5daaed7c3c81df7a44e2dbda14ca1c8791c60314f4eea6f1d7b51df6234d60a6208186d586d5788832e29b7a6f247f6b47d87bec4f45bc2102f9018e08cef493036174b62f07d82974585a54771f973f0faf8ce55ba4d5072787e1c5a2692ffcfaa1bdf1d3c75f816c07150fcf8561660262766811f95da9dd3e07c69baf18bf49871b5f8b720a968644fffa30a9173fc01596b99da2834c79ccd1248ba5c551164344f454c8654acc45ceb70bef05e425eb210055d89555d2d7128d83bdd30e96aabc04474fe4cbfc0dacabe2d81e8ea3b023ad268872bda7b3db8494c2b9428143e86e3521a0019258b3b09559ee1c6dbe645a0ff786707be61b933026d461cdcc1acf162ffe2adc116ad6106d2a8aeda500a54ba3ce9459d15c8ad76ca4cf12b3305833760914f13e323e7495eee2405c908c658f03c0eb8091d61238202fb8e3125bd69321001ee14811d1af65ecc3d32e569dc02892f9ec7bb04531a6801846b60631b050a5ba29db9cbbef1991a2cf367baf979557780ff60df1f1bba2d3aae49f09c71212d5f0711f4858161d003d0ebe34581dc8125326c5796971bcacaa82801e3ec1cd88497dbb2241d02fc6c7d664f7dd3f26f8dd27a67b98d5dbd9eb00d69bc7a921be8ba311534bc39195a12b0ccfa9934616c1ec143af875bb186c5c0b8ffdb03c29ec18d356f73dd4d236cf61eb826b627a3c6074e1669f9349776e3ce7365aa4ab62f1e9a61e5326a17fa707c5daa13092624bfd4b8e4c6e77f5ff2cd8f4ed88c3eeef04b8358e4c0bbe895ac7ec8f037293445a5b13a9d65c47b35e0e92aba3c391aec96edd63efffb5e1412aafa5d78de7f925a994e4335b9bae0a62498b9349cfd9f26a9519f13eaa2dfe698e3265a8283754e516f75e05bcec45dcc32d32ca62fe6f8b5bef4c8d03088f1625bde0289294ed8ce1b1846e4ee5f1c1a8f0b82b69e4fc837e94a807bed68f6d66d9c85aabcd10847c02c373195bdea9000e21ee9c938bd74c28144fda619a96b06a45bca0773bc4b43b43731cf7ff72bf5ef7b8060df70dfebb469494b7e0b5cc999f00adc23bce913098636055ebca232fa85e7553894bad84e891218f06f60c2b3507cbc9a5dea28e28110bd8466ecbd17e40fe1e08117733ea35b59e86ff592116eb16d8aa2a38f48f994b187027d1c52a90708d3a8c49777e49258ccbb07f0b656d80feec8ac8eb9e6383a2dbb7412ae928e19980c3e1a4313682a722c28cb87ba5e0160136cfe8ba082e1e621379b5f14a0857349950325e0f530caecb314595eacdf1ea4f55a91eb0cd95d76015f8c1396fd0abaf2b5e2f37b86d5589f3b2df604d61bc5507f329fa89377a497141df362669afba960e370ddaf5ba686b57ff6ca490c9fa281a0021419fe17fea5e23814687adfe32b305176f77d2e7b0f852e7d2ed87d36f41e7f6f31c011a0a490de60740759067ffe04c0548b1d7554a5922e3e629802f27b933a233fe481d889edf3441fb6dfac3ec53eed64f5556f647f0e7693a31b0d978ba0d5a8ad41f1d0a3e2f0ae8f8eafbcdf8fa7e80a2e567b3fe13d05c1ca4e94ee6f1b6314e4d972611f2588215425e1831440f8567e2103da97329058014621639964e258cf57893889ef11402e89555a39f7f1affc0c79282f25134012d2e1ba6bb009749fc6b8b703a5331c623fdf4284bc48ca92d603f9ff2e70e72a8e83fe893a4c38c3b1608006f1443faa82b75ec27511471a581841fb49807e3dcf43ef815ca57ad9a606e5875e9aea59c8f69999501ab956edc7f9e2c20bf0bd142ff7c091f6f8a7bd2875ce26b431b61cfd0c2357655e8b405f6e0a4c2cc94feb1c44c4378d55ce53ac09fff5c8c0f3601424809b196cb1e64868ef68c04594892c93e1120893de22b62f88dd833941928d2de61c0c9b82753fea1afea14ce373bb14212c7d258dd29d59f80edefd8481e44c8873ab8b1f5ca29a395ca3c1c2b1e8da8c536dc1c52d23ffbcdcacd23b08fb75281630ce926fcfc91dbc12910d0c0d48585bc951b8e81cb6ceb31fd51b3978d8211916eb0f78c17df5f35edcf5aa759a72df326f1e0b205d40ba58cf0abfa3608810bb464d23c0c0bdc93ea97d5d41358106618fb736594fa27210d63da45396b1cf887722be7a94718e2ac0071551351548ba25427f31916e6d1bb63b3f72163887f11e1c65bb951553da5b52fc6add6e62902e3a519e86898230d74749a50d7ee441a334f888feec49354014956e90488d93d83323d977066881094bc89702727c87c7fb451ca7fa3d5df0e7571c6185ef0a9ff09684062847ba1179491871dec80971f4763f51297f0b462942827a5deb80fe06e9d74c50771b9855a4ac73973f6da51d84e3f295fe283ce4f4de7c4de782b3f0ba0203d2fa8a75b5937b3415449c99bc0ab44e381c2c4edccc04089b1f7280707549ff4144a00dff86df0321e5421cc30c575f02359398efc9234959d812143df5856ebbf93f34e20fe0eba1963a592948d9caa7b491fd9c81040649cc068d880c11b00711f105b5b9c50d7f2eea5fa2b42a16dd94e810437408ced686940ee5b23450c19ed46db11cbdc5dda3776300d729913224946cee72949b8b76ee59b8512e9c9ab505c532c949268d194c9d2a9888a4f9a92484fccad7123fea76087b1a58a781bb0b469385d5a6a611d2fe8b03e0316c492748a225c5dbf24b6760113da3d6d6b18bd3ff2b85dcb23c5c88b495bdf0c117699535b06fe9506f432628d7b2e7b08fd4522d35577c9eadc639b56766843645f2a66c05942b930c75720e10c0b925bb2f7904a387a33a8b274ce7c58a2e656bb02b12320efad4fdfd16491654817f3b7c8ded29b2aff985896431657a8e9c7ce832422501b60bcb98baae363d7017c1ba8184e5d48ef2db5aea99c10c052f7d23ff7d742b52d41ec74891944d0dd34b6d61a14f61fb2323827ec6045957f1eaef86713b06b6b44016bbf6da03ef71cb08e5fe96b01655b7e168e721396b26b369707f8f5700c619245fa60167d42e4f830310edf67c859b8712325a0a08500200b9abaf5f3105bb1e496c00e13b50b44f0716631af6d70bd6c865350a4bb9209ae2a685bad195906f6f2a7558ad06144f38a90d8a9de976df74378efb5c349810ad18cb9c7c5df3a2c162c68881e3201016588d68a6aaad5a7eba87a7a35f8845b67bebc6444b282f11f64c70c8e24da6284340c4cda52645b05628781a8df575b06795bcf23222f1bc2962a149f4b0092409133bc1cb365fa1a911ef819f547798be6997c7ca1a9990b27b30203f5e6b91c0b38be2e5e7f0e795a7eefd0cb67761b52a2220cbda019129877f5602f1fb5c6181f7fd39fd5885dec90716277ad3d8c84b8f92367d63251a7b8899faccc7e4f207fc54b5da60d55aac197a8806c833376491f7ceedcd2a4af6de4a639691c0968388dd78af42e43eeb3c52f2cca8ca7989b05d1d1107ac68c2fec6f39c1d2e188ad3877226668900b25e771781d89a79d7cbeeb2c399ea74b37a3cb60a9d89d939822ebac810796729d8cca51235c4873288f2e246f28f41f3cf33d027d403964969f1aa55acbb77fb1351a4739d90887e798af1882580f39b8e72a09f7b1ffa59d3a1dafa10972c0c9cbed3a45ea1b4feb4f5a8e5e4c25eeb24f49ada306af971430ac84026486893da58305c449d34e24cc0d1da7242a6fe0f4be8d912059af724577ceddc99d149b8762776a284f2ed5d608830829fd0aa9f76e10e6a8da6bb987fe353045cbcaac4db1c6c812637ba699dd1e348f2b6d9796b109c7b9e2b9370573daac45b49ced941849a0c5ae9d00ae75ff4c3cc811728b0d95b4537e6beabec228ccfad92389d48ac1a0a964f0d3ff678c179ef58bbcb1fc275d365d7bccdd212c80e542195fddf219ecaf6a3eaa9ec1b523d6fc2cdd7796a265198042c7324896529f4cdb8c2008b68953cac1e220c913241a8258676b63ebc48b8f26b8a3ea4fb3fa899e828fb8bda032f081d83d2a4b028ff09b99827b7f548d65e82135bf8c2c965286c704377ba058614bb814a56868c0e18430958a516ec25d159f57d8bec85447b1faaa968aaab1a364ffed6fe6db48bd55183c9fddcef83ec9e46c40ae32b5404362eab455f6e7e17c2dfc714c4ed098bc9eb1ad8ee2d43016d86002f4d830f98ac1320346b4019d34fa46b96a5dfc28239bb86832c32dbee252088b61e47402ab39df2ddf45c3d00c339852810a967faffe9c4e2f34703fb24e8673c2c3ab80b258eaf983b4f7f440e39e921b1db012775a7c128e7a0a849affd9db7877c0278a6cd333907ae4cd449d192d2ffaa6a40c5584ebf939e41dc0c895259c543f04c1d9d4d7f2396c05136cdab03080ccd15b4a3d9d5fd6d0c0f0101d7d5deb6f7966f56cefe15fc722003a90b9121b54ef9163dd1a13c6dff0553f4f72cd2adc547391344ad358530b48160e540ba7fd713bea404d7139b7086040566ef5e341ccf299e9611600e1575e151b2acc5631f8812d9419ed57ff9443b30380ce26f30dc6b0019616766cd21fd6b97812086111c1711f850c0b149d9ebff607864f7f9696566e5bb4a74a5a41fca9355d7f1c14f4d423e58dd10747696562ac2457b8b400f6cf0f7d68519e7250e3ad523fa42d445e5b2377ceae92766b65015846c569d94dd1f546c8c35715d76dd4b06c3af71b129c1793c925c3e841e988b9f455afd535d001e208e92f2485b5edd4097308ec60f2c90d69ff563f94f9a7c700c69f6623aa28e8aa4e5c9d814d506407d88040a08097d8657da94442fc00896044b6750395dac08fcc836fd7805187030e0737dd63b7bb009a98927654186cfbfe0327a43c983070f0bde0fb0ed993fa5f20667e77407239d4e6717da75cceb12a169bb228024d6cba1d2b6c7f07f70264e936ec8b286e543f0d02b65c7253db755346881db600908c1cdb74b5307379eca4c4b659a02916f16ccacf6960cf8ad8aab9ccd08869d9ccadc9a7996c79abe2f69b70dcf3ad3f077b95aab0b5d5e69e235160671474f5c05126ca5ba6246071bfaaecc0cbcc48f6b52e493f63a982b67c882adef506541b9b9f1a0c3f7e5d6671139ad265b88d9dae569305e55e1edb31bfb9b2050e02ca9a6d9935f68b1ab0d5781a0acc1256d2653164ccd74db5318ceaa0a13b5d1c43f11534e4e6e59044755089d1a8d62774c1a3b70ca66ee5c38c6ac2168925caff92a6d6ae7bbdf73e91194880e71013273433303c05ba724167155c21587f2567e3e6754e93d2b0830afaf78fc755f8da2b07677ed32a8ef6fae5bde53e93fecc61ab4e6e89cc2619a7b0dd9db7eaf8dbc8f2dce0cc90aad3878293834f1645e0004d2e0c59c1e3272fa0d14b5cc8eceacad07c8af460d5d973a286114fea5caf7a1e28a69005d3d06d843e19d4d2733ceb4e58cdf1dec8d6ea133627cdaa417ff03251be926763a296c6f6b25a11e49f7a2be3f4e5b011e4fcc35ec274bccb37d325ff4245c6e6d6ec107a6d4ca391fd484030844c2570e3e3a41d832181eafcfb6079537f419fd9d7ba21b8e74e042c8c5d77098c387b7b9c7d47595dbd68bb42911652dcbc2266f6ae69d245eae7998082a0238888dbff2350871bcaff2a48ee5aa1f39ebe0f7bc3c81150e507ee329084928fc74d14cbb8f7f1a0f73c366e050010af682de815283cc246b191052ea49ba656f03e4df37a5fe420653048b2408fc5a343eb524c65095a6c9c689aec20c8ab95de4baeafd780261d67a748efeb32eb2e4053a7360009c9190e388e1e59f4118a4ec610ca02840fcae9a9200a3e2cc1588c67a4b582aa8e015bfb522ca216d4197170519264bd6d25946ff8b792db5a1725dbbe24e9525dd0c0c73996939292e7be2b74074a89fd37a78677af59167f612c5de4f4fc86a9c384ddcd49ddbb0aaef7454765070661ba3d1d93741423efcc6bdb1a3ed2b89454838bb5a9a3bb7359e866046f34319d3cdbee2d33665e0f2bd9cff09bfae98ea5facf8fab02097207a7e4a919318d2f56ad11931907366a2e565b936a15c2ae5c99c21f1b15269d831052d9ce3feaa47780c63ccd5e273ee8389fce31b0065fa9dd0e0b328e5b55acf308a04797df7a29f302e19033b44143164848283ca35244f2380ce67ad25ee9f0533a1022067311f7a17c76f8f56b7f2234fa63c5e658833e09ba95210ba6a851311c03e4b12ff91df1cceec66cc625798f8a90451ba5f0debaa4e6dfab16ff4b8bfbc978dad0af896e1067e40c8361d7ee57306572bcccf3bf4ad85349bb20129d3579ce6a6bfa878e0576fd7285c94e06278d200eeb985447ba259216417ecf8b811da2dcd162cb4b3cf5dac7ee0da829e7cafd3bff2435cc697a3045c40c6b9586895a38fdc52cdd4fc842120ab8698e3d3f2371cfb9dbf374db8abf236b1c6b8eb4ae5bb91f1eda41e5b23f8e0833011343dec3ea345ba066ae2e9b9cc5226994b4d188c83dc15e02aeb05de90dad035b13ed7b0a58b7924974d245043a1a3f4679613583c08dd6983f4280887a71d0c7d75f79f0e24504a376b8abed0ee46ead8d085479129b238c3201a02c991bd0452ef2b04571cdd5de96796d3d4757a93aad4a080cc81274cbaa7a6ee8e11794727fc1afda4049516ff7db5de64a2b14580f3e1eeec4b8006c031681a4c4e78e49c860024b84ef8c1542ec62b88f3ead38e80da1812e2c846011a94d7641ea95313f750477fab771906b85e2eacc4ad5fe393254ebf3f3acec8c283bd3c64b929db34157e3bb82ab83ae4df0586a9e0e541426584db7b85a1df32948711bf40abb490baba937478514ab0d3a8575bac555574ff391134891dcc493de679bff7e285773292b95be5f1b8c6d4b92c66974362f895e506a329499f4e0041335041ea590a6765f4d9a29c1a1770cbacce0a62ae3a3e2f4615ad45e2a73ff69e7ab46402fd665f950dff9615d78488963d634762013b8101993760121b89e88642c7950b78aa9abeafcc92762947d5297b9e4f5342921bf801f9897bb4736c03976ff36ca2f9146b47a39557435bd8774f568d202736a397e91f19cb96b339ea65e1400ad8d73a79efdb9e59a3b94137c6b26a9e996a24f387f36df8feebfa04a8c50d5852944c2cad6fd4f9be6f10f0c1adee03ea89c2e059bf2c546c98d114b15ac9d32b0d9c052c5b2f8af935199e407f27daa723fed13137cbd0113bf6ad76bbc8eaf52c36259000b9c811f5e87c0ff924a837e00375301009c2d26a44ae70b7f8bc03f30abfe23d190e777e2c822f26aead3f838ce36d576291964ed648af2c59cc1a12b64a73c7205cac69290f4992ed6af159338bec9a13a0a86eec5ea99298105bca465a16447563ada474a03825861aed434c3bb3f770837e205663a6b2bfb3d34131b36a9ec9df2511efcbc412d892b11a43100b780951fbed464a39d1fee1a55c52deab8c2a4f1f7c4f6949381552568e84911931aa8b28f351fd2cbd7deacbbaa99018f82af15ae3d384ba03776c88b41d45189e58085a867f19ffec1e733d4f3074010db9931c86a0e9667c2014aaf1965fae75667e4776eff551cc9899a9560221ff3a7ced61b03d71b26d211dde0614bee19f69b85217faf3870c5d7d11af1c7c09b23d14dbad9250ad12d7300e97c50e70d357b5ea0c82ba87e18fd9ab69da17d878b61b644e870b35ae8452f628013cc197c5542510e278b1a532cb56cb48c13e94644e036dfe138b38ac414158a91c8ad88ab3365a743be8922f229e74076690acd58598a5e254cb2665755bd503e4132d60743bece57eef2fb4df9bf23c080aa0cb9a8b25a14b4213295a6db0b1945814c76ad356d84067a8f263f54341d898292e9046deaee4d3adc5da4eabe092955be6ac206a89eff4b06d635dfc1a78fb175eb7323f86f43d63f272fec48df3b8353176064cd44004bd2fa37cdc78be2f4f47160c7109cf15ca9ec621da51c93cf144d48492ceeed98b9ac9404d0140839f186eab17020fd94ea6d4cb975b13c95f56d0680ce35e415d2422503523a332087989d3e38cd710e3dca1552a1f825b884ca2076c07b47c1e4277f7251de5f5e77d92ad97182a7bd8acb0436bf9bd081dc4eb28b361575e39377df9b0974cc3e298a6c8fbd7bbf8ab0e72689a31ca6d7d82905c35c1ceb6a9f73a11410ca4473c84fcf084a74b5e29d056d1a679aa3996a292ec08afc6ddef7f9df328d33c5162cec36281c467e60b247a1b478cfad789c07ce6fa0661c67051b349aa83e0242c1ae81682271b00ce8c0d7027cac6aaf7161a8521cf8529db33beb6e0adb916d5939b842b523d04de00914b6b8eedcf9949f4c1fba87054bb964ad04cb685e7c481cdb2f7061b7877854c56e0e057f622294fdc89e3412f7d6b1023ba802a9ce7dca9a30e11a098da8a5ada873dbf7256064a42fbb7d15a7eb5fe88f15ab0a38400c7a1cbb6284f04996f21392a554b0198d0a504184b718b1c5b840804a0e842e02ba64094a5e408cc25107b9321708807f14c49900df8cd5193ba838fa5863869ae0694daef1e535c04aab4088243a65d176f4039b91cbed57e79d11fbf56eceb0bd82c811e4eaf5a46bfa11e66a40dd33b49f9dcea0369d735ca6f72e21522629a59432bf044a04a3043fbe5f307b3daee5baaee3eab594fcc49cf373af661a42eef75e7b35ddc17cf28edad89447e5a27beec2f300c460899d3b6934e23af759776c09358c4035d11d0d9839951739e023c1e3482b1b2c7e76d76790900e345436a9cf20a11b4e2034d620f4424d6b7b7d0609b142a19597561779aae4aec573ceafb8de3a81b0b5fad09cc9fb44d57b4bf75e5bf18b2d68b5585f8cf125d99d5b77b4c604104037cd2d130c4f8f35f5ccabc1efe1244976dd87eea00498a2a9cf9e6a6553ce4992c4d3c39387f330c7ebd8563af90ec337dffa869c0826f64d68040a938b1125e9081c486490181a41488c353c9aeedde85e9099ee795ef9a47ba516bcab4186c2caa7e3683a77a373fc725cd0099d0bf21274c40ea451180e828c00e2fd31bed10b80711163c74548d131172d4450c1f34bca9c606f746db7ccba25c2b505a85b6b8106c8987971346cf9a9224b4247bfbcbe28e276435c4142d642bf9cd66083d69aa4e50c0ba50a2cf0e8e1b544496c86243c62b4272c54718d80355661f1a0220b12028b0a3caad43e2f415d5a1e0ff4cbf6ffb55ff41944e506a3852d4305184bb68c0e98d93a4a4d0c3b78a0ca95cd7f22f9a02a5bfaffdf649955d3a4d56c3c9adc783859c5385325091951aa90a1b16ddc675015a22e2c7e7345887efb0c42824a1779ea476ede8833ca6e79ce6d67299307e3e89667287303d887c1fcaaa0a85fbc2027ca622070c943b75be6684d5eefc06c31bff4ab5b5e397765df4cd4ccb2c5fcca37ccfcca4074bb33956ef99c59ca8cd2fed06c04b145ce893ae637989f30d7a13bac0dfec8bdfb44420c0b7ddf120dbef3879b37dcdcc08a387ace8e8ee65c3e39bd5cf39b130cdb5a6a1f1449e8cf69a9a33b309839945fbe2f8e4eb9e8e2820b48244ee2aaaf7a1de48ec19b89a223fe2513420ecc250a500aaa7a4f9157c37e2fa3904fd12adf47c21726f5d5144a4a4a571df5d3f613fa845233222026944e61ea46b5012daf1cb238822462801c82b8f8182165f11971229cccc708e733a27d3ec68ff9bdf7de7b6de9f21f81b636b179cad633b05b90c7a246515f7ab0d41395d2e228b1d7c5812ea6628bb346472cdbc2bfc5e7130d356bd40e7a74a209417910304d94177184972f6294e8649ce8354c1e70d239b168d9c087a9c10e3347940890707e2acfadecca23902671ddcbf278377ba39a684fa82271382050c2e2ba21b6386bab1fdb795a7eb6921ecfc58987d2da99a5d99a4dccaf1f28cfe292a5aaacd4d494178dab1332c49ae8ea85125c84848686ca94e944445de6840990929b9017abba13c278628bb3b6caaf1e185862e4b0c559fbdb8ad572e1189d087feb7293812a818ccc9a280be6247fcb2c60f9dbdf7030f037cc697a44c05223822dcedaea5f7ad6645b75585b0543d3a2ada21535542d4e0a2b7a420942680a616857c8075e75477c5b5ef529248eeeb01d2f914a235de2f92f46c580511d9836212a95ea75c8538b2d5296aa42a953aa957ea3471980a2ed1e91ca6c91b27c7ca02a8253a17c50f5ca334befaf3b05d17951782ea0d82e5edcf0629fbe6c18526c91b26825c088815221868c106c91b24652060d8e934d5333660b5199998192691a6634423e5ff86a9ca28c3d5c8dae0421738ccd06ca862d52169d26ca6b4ffb592fb39033558f8f59e3a331c3466ed94a80334c04632c368e39a074498001138602797053eb8fcb31c7609d3d2a506da593ce496ba5738a34d5da2375da39e79c74560a060c1820272ca06a3b166f09479f1e08a48e8f74cbafd799a877c55bedec740ab5fc5a9a79e42b50f5c557d4c02eb09956b045528dcb86498b19326cb106d64965b7fc966a5a35f420ec97d7b82c4fcd946ab2dc8a353563b734af6eea17ac81d5d074664f2f4d08914a928c34239535b01a18a924c92eb0919ae01709d380710c8f980ac62fdcc30bbf26ca72540a5bc424695677f05877a68cc42ffcc2240d0cb58f5374877daa01a6ab14ad283016670925e1d4c5616310609d22a5fea4a5f23ce5f1638dc31627397b263ad5b462b538bee921e1d46868d7c61826d8aa182a8ab305ad29eccb6f89ab0320616e7350d8d6c692c8f2c5062b769018f4856db92dd518b6d5258cb1aeadabd6b9049d336bb6da6aabbd3a4f5d33ce696dabc2dd11d20fd5e683ca33afd805d467e9fae93afa2c619875ddd53aefb374c93a7739eb619c6f028e748c17307b55c011ca475c7b21983aa695eb0a8ab4db7c507be5bda786f0bc8262fda072093c68f31cf3077f841df3b0637072295db10ea3cfd2e5a47331f37bf3bc36f76d2e0ffbf30c5a2e5e9ee90d41bc3619fc11f60731382f684ac19600e57a3be1489224f72637b949156979be4d52b2dc222567435cb4d01efaca70a2b0e84cd75a16ba686d628b94bc0da1d22d0acbcc09948b0305bbf012f84f32d4a674ca7d641406b413164db2875016f490894ab2adf46abfdc44bac92c9587d20c2142abc663b715e527339692c2785419aa55a1a8b6ed35433464238b846eb31a462d51e1b22c4510a12c4b11cab224dae22c6be4e7efc1f264b6618bb354e9a0dde910d1d0fbe051c3fc5b05233f39cab2c559bed0cf7e888915aa3bb31faa3baaafb182d32a928a9249e954d40d3a3c5f6dcdde53988bb5d06182f3e77fd415afca9f3f93408749ce9f5f477112aa3b624ae785103d22581d25c5825a3ad2746475c5e1404ad4e995abc8f272f059d397bada593ad214348dc0cfea20e9cf7e27d91667f971e0058fad7b31c658ebd288a7527d869607cba660fcb226cb37b68d403c569f130e5bc436cc9a714aea8e75619ae51971cb71cdf251495b13e6fa73fe9c3fffbf77b9c52e171ef188f1bd185f57cb9b2244922550001e61ca75cddd7d6cefbdf6fe4d063cdc7b6d77efbd95e6d86bedb573d6f0de7b278a8e68071ee46e414a929144df7cb1fe8bf5d37299d7fa9be0abbfc9bdf84718e3cffa7ed64dfefecdba23715c898431c6e0bd9f7513fcfae2c78f39e5f93f5fdde47fe6e0fb1dd3fba0a594ebba8eab99d2129da1d69c3e1ef139c2df64641fd3c7968218d04660ee1abf6da2abcd0f2551ae1275e8602034a7f211ff74680e5733af2312d8c4c62a209306c0c9fe4f079c443af6de8b7f8431feacffff34779ecfd4e451e1e89363e0f1519fd7746fc660fe7c69ad2a6bea46259a9d63444feafda07d7473ce5e8facb1e53994721b3ecfff20d8fe01413f38f9e89783b6d767d010abe3a0211490f05c9f9a85e68c182bc498f9c972c59c600a1a9aba532d4ddda93cdc577774d7397fd6af75d6f9b91e7844346788f59039aa778c05ac189ff882c40b171974cba2c0b50cfd95314920e0c54993da0a5d56d0c26d67f981e5011744804fc057ba13c48cc162bc74197d068921a180d9229dcd59c991bb729b8f30b6d793d9ed71817a410a5c6ea22c1fcd1ccb2d1d4d94e53d3eb8abd5687e40bd5bea317b2d5da0e6ea8160710fdaa7772fc7b487eeb60ba573de209603a13e74f2226fc1112ec71cc8e5984f5e24ca0481fce59817895231e52916a594524a29e5947ff4f27fd066f2cc6daae51981fa7cdca68236235cfe1cc8e54f244a0589649008066d2a3802f599d3e71ef1a1b65a202ee76a87e3cbbed5c59320960709f58962833990a73e369717b9a00d0647a0fc3910caa35c10c8e49917a1fc799128160492c1220fd214cb47e5262d805d790f3e51ac2df23e39e5bd52be2a0189a5a29ad0c6c8483c9b283033470c1699ccca9a6c11d348376ec5b1b856b722e7ea565f7effd69086ad7585e326a353a4144571a96117ad34805cf6087b4f602e46b560afbdf5f59f5080a7743155a17431e524855dfd82784aef7858c5c81c336c11933132169391646c450515afd70bd672c9b6f8ae96abf56a8defea5eddeb5ddfea605dd775ff26d8e2ff7ff7ff5df7df79f1b21a1a8ac562e48c46db22a6cd68b3d8ac468bc56833920b975aad6683c57ed8228ec162b01a8c8cd56a3198cd246412ea5cdd58c5169fd562b15c2d97abf5ac6ec4b4532c45ab996a6ff69e6017a35af849f0f99435137a744a62443af940e24e63b8eef4a4f3504c3c17a7d2c50b94132f44488df0f578d1e0db3dfc3496700b06ca081831502bc4d05a06ce2b85391934a820686aaed4ccc0c9c00c1a58d0f84e4f7c354e45356c9cbad8b099c2e6064e0d372cc071c10200a06a0098f5027d01a7c24b283125f0073000a71d027073821b0cb66090011019e0403dc111e20085262fa61ca82ed3e6d07162c2e630853832d00182113996e45862b3b158ac16292b628b5846ca481659ca582c19d99acd66b49a4d055bc4b69aad36abdd6cb399ad46fb988c12df7bef78eff5c6dbd5bcd6f546cbd3d9ba9a3776356ff458ded8d5acc9fae0b8b6e88d5d0da88bd8257aa337c2620ff35ede18fb98373e4c4699851429441061abd1acb062f67acd4a18e7e24659a9658bb8949532d9ace45c9cab9471e32a4666d9222663642c2623c9d88a6391321fb68865a48c244b19c7e2583252bfc5165b3cb2246eb1ded692401f140f5b0c7b99ba63ed996e75517eadb3d6f973fefb209ed2a3f5ed80f65f793ffccda3652da33b309893cc1ccbed25a2db1bbdc5b6a8656f9b28cb7f467760f0a998395f45981a8d365155b6a86396eb98b6527934f9379bf3e7fcffffb5d7a596fded6f5a6631936af2682e58b7dbad5b6dd9e2af447de36edc8dbbdd3a994c46be8090c18208014c46be8090c18278c16418865a814b368e1acbb08c8e32d46a359bed66668bf866bbd96cab1b57e36a379b4d269391caf175db227e8daf5136c25e32d96b2495a4db2a465ad9222663642c26234937d28d8cadc67184c5a48c3a541947584ccaa8436c1cc7d3150122ef948ba97ec3ebf104730cda549bca69afa00d18c8949d81fb5ca24d28a9e1ec34357cfed5f0f9d79a2d11555bddb1b61d8e8bd556c3f0a9cf7fa75e0f0b5ed89613d526ea6d694dbf9a140665dd952d2d4ff5796ee3fef4e7369db31d474bd883dc29cfa5dc391c442bd36dff17b55dd51d91c3ea8e586b3b1a6806d1a6f4f7f9b116017591c6852eda1f1042983b1d7ffe63eebce0cf4fe10d67c0e4d9a17f16bc8a2f8afe64fa3fc75c9c43501b2da2674a94b462add1b02bbaa332a139cf2f286e0b82f92d0afd3945fd3f7f4177d42766cef34731e9cf2b288640fd957c3fd5d4710b8aba47018a7586fedcf6f0eb4fff5c57acfebca716d5f0e96da8865f1950c6c97317609dd5b00a1fc23cd16924d922b5cd94b42a10b5d59da26f135513cdf26cb01655d3f37aa60654aa630d9f73b97b8ff4b93a9911c57e5e892a0fb7a6af45fd791deb8e138e7a3f2e176dd7e09d61e67386790244bad66058c3e7357c4ebbc847fc39cd472ad5b9236ab0dac07a0116fb769b9e61b5b613c21257cc707691866dd7a669f61096a04dd3ec39dbe4e86153dee13286084a1ecc5ee384ce4dfb29b1c5ef069762ec935f4e85b2e0ee01352432030603c60cd570f61428ee13cb0a4b7418cf5ff4896585327d7a13a0bdeb13cb0a5e3a2ebdd741ed14b4c087cda965711fcd8308a93b934891c913640e99a24f2e7612983c434a46ec123e27f4a6d937be0f8af0f49121d6b1a91208f6cf93378006f5f3f9a00de59cb282d88001734029a87a61e79209d534f92d05a97165de7a6050800f569f93d3c967b9c720c4b4906c550f57551cf404a915e03167fde79653e48033ad622aa5c524d3313fe107f9d7c3ae9cf2ae411735e8996326fd45551f81306ccc7549e752a7d20fe2d52d97205980971eb28c1cd822881c9668a0c8038f04f390dff03f3202590c4950117249c184de4095167e01c923e1824e028521aafc2869a5a09564a19a422ab03c65f99cb2aecf2025a4b0c235be66a86a757b00136a38b915359da4d67b739e4aa95407b83b98db7b2f78cbabafe08a5444a932e11017fab8540eb8ce77da3737288dd6a84d9c37bdda2cdafaffffffc7506688396729cc48391a11e2565ba54aa5c2f0b9783167f1fdc6c75346fb7d7b8f3d96c34cefe36b2d27859b96c7476767f9b870a1702855868846dfd837e289d26c37ba624d2e6e55999285248f51187dd171dafab7fa85d2c13a50345252284684a892a2ee6386cfa7f7c1e432a55fd9e534ec4f822d4d4d7d8e8c8cd4fa31e06b2b9db3d65aebbc5ad49f13d72885dff7fded777e9efbfb3ac0c0fefefbe606f3fe709cabbb9773756336e5f65a6b2de7dad45a7be91b81f5e9c2d6dac93f042bacb0e9c5cf7aad2b196d3b4de9ec9cb0188f48a32b58a4c7d75a5dfb9a6ccdbb4fa5e3898e273a6c408019aee256e76a677340d99667def34c5953684d4a2ec634f772f9d61fd6f611aecf83b82cf3d9769aeea89d7ab8c4202ea3ec5b8d548dbf685c52dc8586e9158a7da76cd21d9f9f96c5500d4a7ad45c3450c4a07169e2c4e6fa0cb23206c60956a4d8c28a153296f89042d82595f5a8840d9af5a444331300100083160000200c0a060502711c88d26096e40314000d59723a6c503e2e8e0542c1381c46511044411c82300cc2300882338421869451f60c5432b44a52010004d5a5a99a47120d6b26d859bc974829dae373c394e11bbb227d1edc0a3b569664840a5967f64a3119466f83a469794528258e2c60492f431b1fae3a7369693178f75f085196852d3ea0779fe6e22eeac563ce10cba943026252b4eb2cbea4444f234a92ea1125716502864ac3b1deea7edb80c876b8e87f269606671e465a6d938843bc65b417cbeff0594303c63945d8ff564e470aa358b0e28d360bc108c88bf1bf73c0fd6c24b4840315f7beedaefe0ebccff50234d9ac9a6432289446b6cef06385b7f3721efc2dd2b88e449e937fc59ecd977c6375f1b46ff4a54bf69f6710769e26d74900f6c339f4e86a6d30986396c30a5062f757f4daaed15890d21fb7782d04b218dc1f96606d7245a195200a9ff0d3a277d5ee41b60798f973ca3162e3802b4b784af104c5c0be47bd1c8c0dbad3ba4cedd378c8c2e7ae07a3a7c33c9779eb0f3499bf14c7700bc14da007eb701b2a178be0ceb28b4530bf8731763b8615ff1434c349962831be724fd2a81390fbcf4a5589f0f617fe35daa74ec97429b1870c5b13bb6ded713a32502913afc9cb19912a3a2d55bd84ed4e067412c1b57545209e21f58afc204437d0644432c7454d6262fd9748310527a659ce1a04b16d0f3fab40e4aa75483c8c638052ad4a051ad474ed90039c34373bef12a8164a6a765b5df47a077349671ac271bc76a0c088424d7f10c518a1022d9802dba3bc93880c6861cc1c3e70b9b8b752d9970c511a6f91cff5b347d11f1fced1190606633563858c836511229d7515cba5137cb02462d43793fc191cd62a102446905f311b6eb6369000cf1abcbbd4c425608d0ac888b993d7c1422f5fe7fca2e5b5bcbd1343106ccd18f0f5bd9f8d8830ee3495674058f380ecb897bdeaaa8f451af54d168074754b8f03d21dfecaa4689630cf6673f1107e9a8ea3ce0f904e3439ed82e40229060a1537b0b94af14c8e686d5b08d93cb95ffdca619910c948aa68983e548d2d98d9f6a4b8d5bca27bc90bb621cc1610150205dd36974114f59b230d298678c8aebf9b1c8b40a9e12b37a825957ce889c143454d7f45042e2c1dda91fbb3872d5675fb5ae50e491e57448c5d0edb191d4db14c70294372170b1d748e1f476ad9894a43b7ddfc6bc4e48a6061981be515972ae865f1ee803128235262701a1c0f181c14967182c50afc4d4d2b289bc586b0b6758a22cec72d9d3670557507e20943d3ccdaa666c04cda9d876391270ad79501dc5e7c72d58580bb184649b045394d3e93baa82f26860ce8404cd387b2b741a0f985270a13ededa39dfd67ae40fd12bc6e1460a019266ebcd5f78d771650de38f4fa74c617bfc5afc181bef862e891c89e4d23fc52fd8e5d34087ff4d80744c32dbf5cd0b75b61463485a2d1727db799867dc9782dbf870c6d134dc4563a38418f7088f9928711e983ccc4db5f8c20abf03c4706fe6613d31ac4095dcf9f7bb8b9489eba82493a5bc7e750f529654b82b5535918be80e4d0c603de5a6373adbed34e877ea96213d168d1abf585cd11030c81b4b6d70b03d8cb7c26029ad55901d700ea8d6de73ac24cd281f0c2b0031d93629d43b8b0c59e98100db075263e9296db4a2a0b35a44308d6d2292da9fe5c156f0b3b1223b380a04d2630bb249192d02e94948abe163455f302595ad034c3c28b14159edb443038d0949aee49be837566087f0ccc6d82be66597b351a886e2823485df346f7e393015b560cacde6a2952a557f28f8d08e6de06f4b807b684a90451ac27ce4bd607b61039d4562c4df912e6c1730117102a2b3e0ea1d081f45563c2ac81edcf791758d0691e3c36097a9ce45db644de6b3e466856925fcb07b033e85fa51734352671c413d0eab49f6544aabd2232ed2bc830cc7036a5ab31bfab16d416838d7925ab16be191d741274b71410d94480a8aa93205efe189f2519364572ef4cf36ba2d22daea51fc307124758ba4f9d4ccfe11619ea9ec0fd2df3a649c27d81d9592755dc64054e5355cf2b740b250d0b7d99cf1a7e015b79ed2c0b35683f50d949260716bf8c8bb181729f5a99ece47bc50e12d5d83f0305d9e9656adf8eb570b1f438842a736b5478e99b51da90a3f1318f36a4421c2140f5db1f867d046a50a6696e5019c40fa11d5b0080cad0838ea511ab3d0b4d066c2d928ed6334a41f4fe2ee014e9f6bbeb0292b01a47bae99e38eaea3c6606680386e3c8c16cbce5cba8c9e431fd4f0090a93e226b41da638ae380c44abbc7a9729f5dc20e4b5d166e3d9600ea54dc67b234ad66cb976987d22c04dbb41d747ea8a2f670170073daa4d12986563d06b18a1d8218cb797407a4e3fe47c11e0b81d226b606e592b5b098736be2a97383e076cd5cf63011823b72f49cc934432364ab95ffe20ca424139f6b9a7949d7906fcf59e874f5a524abd9c855a6b9303e0a250481765e4af907992c0523df3eab85d647b3c123602bf63a2cf13396fafb530ab7ba9e42b501f5b95b451044ee79aa835a4ee140b4337ea647a48f721b82b86628a902e88fdfa022e043df56332443ac6fda14e421809ad8fb425e7dabf2b504b4f045ed841b983a0390b78944bb650d92aa8187b2ed0197c4d0e2f29822411b7a13fb2e8e1e3c3b2da4dc9cd6bc461feb8ef83471f06bc4d42aafbc85b8ad27e798111f6728d98ce3a4768c6a4e786dff6cab084172b068c9a814f6c8790c8517be09b46f64ea7c4abecade6caf5ab18ec02936f060ae81752dc9c9c06103e483dfc64216c10aa8f6d943c080c78c2690837cc0722ece95422558c8069de45cbeb93a660b88e271e5f9c5a2c933bcc2c458386bcb1eac0b6496b6b6484a1cfd52db03f860a857a27813834d0248c77a9cd964a5ea83849a7c2ef236722ec40059c88904564ff708c52b9a0ac62b115654b577b70499bc26de6cce447b0dbad17a80948829730d916559ea240c131ae990014a983ad037966ca94c1f3c4d1be95a117941e1b124be5b9fd68bc281b3495e8126580dd8d274bb0ae4b71709d3e799b8b59fa758e4ae2a71b9e39a2ceb39802a20c0bd798153fdc418230b01b3355064da4e55b70717e8f179747a04a33c52ac3eff8450946a92a2c88b48aca024e6179b3d5825a82f9a0639665680449dfb123ad047d1d98361e45628805623e92d3c24e1f14f078bedc340c482f54d753bb9968447d90cbaa0bc5397711634a21b57eeeb411305b518a1b66e3fa8078dc458bd48d81844f24e99f79f56577849f99e6eb1dc1a8f2236e5750cdaf11b01f5a1451f7527ecc513e498a467d771cf993ff9c65addf2afe22e5e3e8d269b055ad43662853f2a0e09824264d40f1b2b968b32135733be559f2838161af794746cbf7495b2b753b4b819e8df4b16952d881ddfcc507f7217d228e28796fe95e82ac14f88f0e0a1846e36f630ab40afec592574493c929c30af449ebfb3cada7da22adc19e12a4ce074e2314415ade5a435610040326021378257de660492f77d3c0e1e567f0732d987f77e0f333b93828da46b769ff4627144388e2c3d97754f03102aab43d19215f7a9a7b000a3d8ead62614292c0cc3e274e110d33991aecb3f81042e4da67de76ce387e5a0f1d6115ed8221c4b8843064fcb255147028f148f68ceb5f5df06468ca3244ae25bb097d7a0eb9e5e3e05f53d109032b937ebcc191f6e9d95410bf13e00a51de6e9a5543b628dac003d95448a4233cc38f35dd15e96517072da8d199ff68cef852621b3b36b3884081770b9c3359ddac94776d150ef8ba28bea4114d3b87441cc60a2d746c0165d544a5b6ac830ed61e618174a79d9d078e3bd73e2b8d61879b16c344563e07b739b05f431de024ce14ef985e21f4445c5d449fda328bc2a691abbf8bc8995dc0eb398b09376c5b9bae80dad6425c6b2313a92359f36c319936c6dd672da2829599a5d3fa29fbcaa2899331f3cb7ce2cbac53b389960317576755693aef3598f7032d3895e776335027fe5716a64a601fe65e6703135674e0bd328a4c0cb7dfdf181e9a857374a151036c6253ff082a7c78b1513b48a929137cdd2a0ef7d8e131ac7e3b84aefd60b733604bad136d32117427b5d6c29dbcf893d980c37b559083c824c43756419e83136a96a4b08bc8c3f02d97af2eb15cda2a6d209f91c8f2dd2b65fa0eecf7fe57a1010dd75d984392f094ec6b667cdc94ed27ac9b40f5bf8076c7279bc66a7d30d467557fd06ed6a20d61d16187afdc0fca57d2c662bf7da6371b9224a158841567dfbf3d88299808a9115d4b288424b72fa7f64e43a609f0b8d4232afb5385ca0f5e6ba188040f99d00350fd0d9fdfdba55e876940767b6f5be507667d58331c6c33d6e3ec218219e2252c715782b785401068f0a766fdceef191fb73a7da355121b5b1033e6de8a4c0b3a6606cb16b4d5af5dd4c51f0ffcb1a11cfb478648b3e6d3eec0b318e669e6fb769438dee20f0d71d1883e369a251bd3ae57b0f06f8f75cb5d7d59492ac72577408d8a19e13e85a99058b1e39a45ae95bf65a455c21dab92bb45358c29bfdb09c87240e8b2b27832e3bfff1de482b24284a61b80871d9b9206b1940161644f722ca4386cb4030d0868f4a2dc89e5859793d75521b482002cb08479975c1a312aa6670f19dc29d848b7091cec865d89c90da38017c9c3232013ecfa954203a6dca00c9cf9d9d2ddf3de1a17b99d5a7bf0ae77ee7ce2915c7bdce6b5f206038377bb20600cbb161c00c15415366a8751076130a166198d9900908bffca0068d52576469b9facbd1b364c3f5aa5a3e2753f8723c691f72ab31110d20de0e0f5a1b654f7605a221383aef8c827ae5a43422689336e201238506f1943a2e1bd2706d05ad6908798e26dce988b8a5b183d3eec3141289a3c665e0d2b0205f59b66b79b15cc2a16181d14bd2d0f85b576296f3ef852c9f561a4c28583b7502f72844696de010cb7914ac1dda7a9e930cef0a1fd59a8235ef09bfc7d90859e9aa018a6b536bf20c163096066b9dd16a2830cdf2ac0f4b8e5659bbbd3a68a9914be5c295c74ec8158a220ef40a9c07184518e3189820524e599b79439d3cd88a58f3883adc6dbcc2aa3fb0a0e70381145b0cbb26268e56249aece38eb3e675edd5e6e54e83fcc7f6d6f9f09b650f981801d3fa97918ff11fc73f60dd6a5912c2e7dfb1ac67ad72ef16bc98616bda13600b107c6d8c9d15e8a16720d3317c4bf48fe9d6e6cff5fdeb22756a8f8b36a98a0a25fef131f9aedfa87dd940cfc80dfc23df540f8f73c92d15db4e92e79cccd23e7d2a46f3a5f0bcb15cbd9aa689be0a4bf1478c23baa67620cc194b3409cbc3c34d3a9c7f8e84fba13848c308c657c1438268d42091d8f860d5022aa97d8c97da6ada3ec9d94cd5719a71b1ba6184a6a01a25a9536851e3790e679bf8a2980c383bef4f2267e0574be9fad3e7106901fa51b0a5090b2386cc01610e29d9a28a2710b45a6e486b476c01aa2795603df27e7a92ee020050f7147293194981d46b36f4e731e6e47712f6f4e14d5f093c4835b31ba2b504ad8637ff4defb33247bbbc349db6bae23e723b6a07bd8684e8cb628ca3462df9cf1ce2b5b679f656195666d3992d3b0d0c280e9d91246b4e31088446e5d5f5f22cf2380d2160d12794f61580ff150854a636b96110a90e6eb97e7d99f0aed4239d1ab060899e1be8c172c0dc3fb3816522299f13c07cf3d05666ba00e42a0774a43c687b66de87972f3c98582c290f8b60056f5815c0f3fb4b2380aba142019c9db1f4eca7a91d5bb185fb73fddb12ade8de6065ee00ebc441b0350ab4b78345f77bafd51a28498ac8c494b78bb725c7bc0337939c3f378091cb9a853c0b6ac3625ed077d2d7ef40b57f78f11338684591e60809ebb1a57575641802d0d6d75492d9983fe01c38d811fa02d120248e0980dd8445da35e17ba62f4cca830d4c028a3d0f955049fb86e641ba19b421a7e5bd7139eb9c65ff7e16707bcad13993d5f8168992d67c2a42ce8b85d2f042ce09bf2878c6c121052b505e66db01a366b5fe72109e488b7e5165a071921ec6185e961042f4ca47f56d77d03bbbd8da52ffc39600eb080db81f64354cb2b1e6a9ecc355e0d2b157744205b052d6bf47a097ce67f4f8a2d48b89fd9e7cbb681f311c1086d38b872953a0538365541dc7d9f8fb37af08016e4e0e40f08b09f759a3afdb67943ae82ff5029ffd950e0f34a109e33d1c7eb1a343163ceb7491013126fae524b38765ecddaf7ad8b6e9d2c415c2b3398eba5d9625e318ad19d336b72c430fe7c3e837f1c7c15e6d170be7e53e8cfea00e9fdef1d1b772b845d3ba3cba83f1171f3d7c294b8223da334cdb1c5976d51ffae12027602ff8dc5771e840139a1adae1e8171f1d662953d2115b32a69e5cd96476ee794629076938daa75bae345a1f9d45165ee0958031b19d0e87f137b8bb3699c61177cfff08ba77ddbfd01ddacc99ea92b4db35d57c632849bc902be751f80954a12a089ee1764120a6b10b82c8a48a502cd95278ce317ef7f50a9c0d8c5bf06110e8c2b55ecf0ab8f33099027e1f365bc8cbe36505f8f1f0bc2077e3715d9515e0a13fba9dbee0143078f340ef4d1ddb5741d629c0caba006b69908a851f18469fbede83c5980031f4ca0db5732e6441e97105ff5183620d28d061111a3d526a771431f00b7b960f00ac15b869956596086e01173f3c2be0f4785901171f372fe4f5b059215f1e972dc0cfe37305797dbcac80cfc3b2851c7cf8ac803bfd981d0ec4421b28e9ca300799b6c2fc51306803818ade8f96c03bfc8e192596ee8ad9a9912f704bb86981a389772a744bd879a123093617704bf4b9a07bc226054e12362d7463e227054e249ea9c03dd14e850e6c22f1db9f4a85abbcd77cd5e44a5ec7c8b75653676b9b98d6dc414b06d579421ef3f0032160fa26e21b9b4e8e75eb6cf05ccaa0bd57ed033f1c6417ec0d5f7d2986293451d1e33f0c7ea3a3439767c81ca34dcedccda1b1a79301427fea611d9baac2800fe2c7e8f8c0922c12c76c993337b9a5874493a4e44d459ce23c93e57c05d087a9a084be41c66d6d725f85bb2b5538be10847b5b53d83390eb5477ec38c570e83ffc02628bb90f9a9e275d040c696664fbaa50137c5695bf1816988e59ad6a7520dac572eb2a15b70a42cc3a2c35fab17815579f309d7346e308fefed00182204c230f180e2d2c68a9cdee244d07eb85cfa777fb50ea457adeea231fc58db9be4c5164b2e65de09fee03f4424888ea42606b86699b23cbc54e291f981310c6472c8b267a797487f13f3e3e7beecf2493dcb1108f32e55714c931a40856ddc7c82ec28dbc736ac2d5607fb85db6239a923f1a0d1f63edc8dd692eba98f91fd2f134d1af72e5235380c291677f3b93dbd4cebcf0a05c36c7ab1d7f18ccaba16cb047a6d4937ccb603722bb338c735bac5899dec2f5c67a4250104789ee61531508951c144703fad0b2ef1bd64a1fba7827d135da59de7188a0b54d8fa3a51f5be9a75286c66596602b17f66d9ce7189138c5543f9560e02b322c62daedf3aa5ec90de0e3fd4dee0e12b0342497fc61ce7acc8ea40a1a8e4a98b5ee756b62be512b882b087c4b28cbd941b2ef6345f233988d7c12b2e8e79c6bda78a82a6a8d13b734be368ba59c304473ff98bcb11b71d11f664e08d842d75eac8c626ba5d9be6a54c959ff3163e99d5806b8d585de0cb901e8065568692794db49494ab575cf14d527a3880b5ae96de57db32d3821a1c115ca10a1670402321d46feb8a9d728be712b55ba1bc61a5b5e18c77626581469cb39f6852262ee70eb8d7109736b45bb3033a41640645f12bddb58dada14ee3365d1ed7587d08268c3e8ec1a7925031526e354930cba87e743addd7b2c12db91297d101bfd32ddf323287c66c8dddb54dfecbcf3eb8ef539d51531273031043da9fc1499a585189845cb785c4cc716da011b9c1b7df8c7c98732d4f35162716d48d6a02860672a867633d5c1c0390a6b8f99b8d45c453277c286fda485f18eaf4644c7fcb9e64b410d15ea3b808dad73a5f14fbffb5716d57a9a9ee7212773a450447af359be47c542066bfbd02049f3f8859cca7418ccfb2b7e5a77020012985568394001cfab5b676fc6a77e75646b2540c0785611c208d34961854c3d05b98f3a427d74deaecfe0c974571293abd3c664bca25b468933cd6c911bc74fa941cbbd61dfb3fda41a7c185ea2a9ae0ced20fa8d8fcfb6fb3165480427a041beb12713cd09ad4d0d0aed8efb290e9abb89c082d3c3673b1db9b39055d2b12d79a646eec3f774724ab1f591b327614a0cf134652bb43f58a3da71dcc6df9fc94a081af4c994f22447df8b450dd6b7625f99073f6956d2df96523946e25dc73337dc73df38384a7a18d6ec1d4e7e80d097a6aec0da1b937ff45a0192b1dea662c840863d18b50fa12baca18ec9de0af07a11ff5095c22f85d64789004c1002a36487992e9aa0fcbf96123e91bdba7961d9a4c7d94b5ed53e198a514492ffe6d70e5e4f0d2162c1bcd8db7777e1d94a5dc1c69b88df85b9098607d8be341e81bf34004190ad03c72e5d71bc2531965e7a118e50f7d7d7bf2a28eb3f57eefc30fec447e195f2fd064ba19d477ed311bfed41c6d602dbf87a284109c7327f0571c811805a1685464433a512d01f7d1cd03b88f839fcf75d1b6c68ec407176370ff7516ebb1cdc7680c488dc9da51c73bd28706e2dd961f3b518c48fba22f833ca66febec093383a92e3ea68eb262dcf9b28a3965e47d62a601d0312a17b6b1b930c1449e623582e502bbb35742a3046379a56ee9801853e9d7d22c3e4231b5d1396024f987f8f1aab62d15ca784fb3be9c20b9d8581399873360657e38d096c6c17eb3c60b6a32c959b4243bbfc8d1a6a23f91d5b0874d94c00034901b8b6cc7b34b510ebb1c06dde6e7930086120fe5ff631503b725e94ea6904512f22b54b10d90cc605ba71d9427e4a5545b44fa829b84498507c37f147361580b06c7a2dc4db54f33a2a81df17a21d4ac03d1b83935170665f295a6e7f303d90b123e40ff948dadcf4a650cc06b4b7c1abcacbecf984b520971130370dd3a2ee9a15b885821e012647757165138f999ba428a83c0bdd96273404c6924e6257e3c4ad9074506b38e3780dbf7fe88100c31fbfa4fee412115d0477063fc3841f2a860ff7734504dc8fc23c51e7eb0c12e312493eb0c157e98aa2d6bc908865b80970f1d1236eebab4fc6aa7ca95ae65a4b8e35d069a2ab60734b24147f350c3e99b36c90f1a55027f07a12ddd3443ca6d8d6d5083fe00e4699183482a84b30ec6bce0759c02aa247945424fe9e92f494aada27b53e768bd6357d5364ebc5e63312ecd442742942e0790d5efc3f13eb84270e996d9e046085627a15cc09368fcf7805b75d09a9ccac6ccbca7359bce9cbc982b4c5bf3290283865dc8b846d03041f01d82139b577d71bffcf5d405e867235d148a14c515ef09fe31b63628cb3726a3089983685dcbf50d676fe388355e1149db754106a7a607775548fd4453e4868c81be0a0db001920a8f30274524b030c65336d80c0f2a189f6f01040205b59fb6d1919669b919c565aa67dc34d3f0697643868188d50d544c93761b47844455715cf2a71e343380d6ab14f26eeee7411bb9a33b9e00947994aaca5bda2a044818613e59dc0c736a117486d50b4820542db60ee14af25742a5b189d853cd2177d08784b0d4955089be5e948f123ec3b644a19a8a44ec37cdfc1868aa144173f0d4977b99e3bc65a5ba4dbcda8159a1b2f7182676a0b1521deebf0a6bad3bff3e1f5bbd87a318d2e9e04f6c5b82daa5c75134c18d7d1a7a2ea72e0ee3094c60597620c3f5abcd14339cc977df4fe140e8d358403f22384a4b42d7cae70b8cc7d4de217696683450a4794047a226aa35b7189503c57432959015d4bb037a086edc15ab436e4b91e7bcf2cd939a34811c7954d9592f9b559cc245268b818b4d0be34e132bdd0204bb433b19769421a33da0cfc128c3a24c9ae1a9822281748fd8cbef769c51d1314e8ff2741079b2071109c459f248ed963dfa936ea91f2df35bc50bf706ea6f0ecc7f5dd40de220a1bdf61de4a2c50fee4bdafd18be2d6f2737ee6b52240304d54443dea93a65c270cfe8644b23f27a95ddc3a7acefb9a739f304195b29416df7339bbf27c38bcfdd5a3687d0c2322e77889d0115f59a5f07eb6cc564b59e1447f2b51947d2d617226c17db21d3f62753556c02f07dd70bb387c44e0714ff39780a007ea4130ae15884995228410d1ec5a0c832f17ec4aeb822e45317ec239e22389cd26ee4eb06b28ff749dbe524d5c723675c39de37e70e4cfc16a11ba4fa07b1b4c72ec5f29afcbdfab2d7a60608c634521937479eaefb44d790383ab7cf4c01fd00152234a2c6b617c347f8e88ed33e3938c4c3af3a38340adb2c0bdaa136e66ef971a1c5130873845c5bea0aaecc2f5df4809da0ed81e8fe7169f728dafcce8fb13dd87373e281537eaf5907d60d3efed9bd41cea8f42fcddea97016aa728355e6a13cf16e18c033f3b62144d19e1f54c9389dc745fdad0de857a7e52fee7e395afa165b0557fe086e699f82ae677e7aedae872f3c9a151ec8696db992c5b47f4cc7b8c35ebe9346a6d06a2eb517ce6c138c383d5c0e220c5d0325b72498c5084a8f800aee28dc796c921b767b52a8a6ff1b6af4edd6f642396488dc80ad8f8f18f1d94858d23a62de18b1d458a5fc0e096c03ca9c6e7f61b05819d2912295108ee339563b64ba74c9da0146df8c9529763b0e56339272393b37fe2b85138b4f7bd45ca4dbc32e02d1fb9c40a25350d4c27d424e01544d7bc8ffff116e699987d1109bd9d5bad51c5ffcc0ba20a7b9fa1d7cb32a422175dc6d11250cc5df35d4bca2946a8914175e5ede89fa2587d6e28fa34ccdef308beeddc275fb76bbd1ebcfcf9dc45d4c6302b7829e4786b33ae2a6c6dd1c2ecf0d4b17ab99d220c4e04d03c3e5a6fd347fb56b1ee492047c2b4ece1b93d351a12813c84990fdf7e728c9719f86c9b5658f8e505b93c4dd935267f39564b353957ffdd6a2c8478c9b4ac2916fa9a7faf83a59eb8864f200cf56d022e8907ca61a8273d580ec67e070823ce250668a11529d9617ccacb082b5dd4ff04dba28270222beca58405fc8f808600834b8c09a975662daf0531cb504d85ddf7217d3f6f694d104547292a92917b5ed76baa4517369950efa15efc1c5e06433cf0f44dfe105f8c80304097250c7b80a8d4085d67df1fca07fd6c469e572aedd2e83db7114559e9eeaccf12558801be1770057f90ca46af1a8cc21a760cc65b0845b4835248502781e1237fc3a0e12cb85ca757fc3f00ed11c7729fca6ee0dcd8b08e9ab8dddbc370b821eb5819156da44802223814448d8fc1cb82d090c9a03078c540376d2da4c7ff7af92ab9d6b253686e44e82bd8a8066e5697f61ae79a04c43dd9de4510e850238d1d15f7331ee25ecbd1b2d0a5dc3e9561b8eee12cb051d2956cdac188b44ded4efbd6ce027b50eadc148a82b6ec05e724a84dccf6057473aa18d58744ded2095f29df1125ac8c6c0cd5884a11f6faf01cf7616029b98d52e5fec5b23bcdea6150f96350d67c6e5ba7bea65ce719cb8b510751658f336c58012f50d6d80366c56fcd1b6050c7c24b9818e6570dc12bb96350ac2982fb16126912d37847d00dc6e92a02627b0ca8e4a5f6bc14e9f380287080d0de28311d647dfaf3716677dc09979eab1601d33ef90e2810c9652c58be515714ef6b0c6c8ab4fa9ce7bde3217f8e09a37bb2502f1415aeabb7d2d67be5a8cdd73bfc2a528de71dd19a31e38ca5144eb17c02faab909dfa968fd08125d638f340e8bf022cf4c000d163ace5c93e34f84f8800573eec5db3f364a497261be45614c409620a6a60ac6326a9239189b00589de08109630de3bff70111c5bdfb6fee5469028fe168d4c587af6326159f156ed5b8d85395a5be15fedff8088c572a1bc066188771edbb03ea4935e64d0a924986e1f81e5ca358419464112a0321000dfa41c74ad8fdb2f03e8f4de3ad2756e4eb508ceb1d1065971fded747896b3535d317a79a60f049a848ab8f12fd28bea3b2c6b87da832761f3cd1b52bc97f1f0d6985e7fc3b69153109e74e66f4a19a6c58608003109283289278e1f38a0498cf3872e8c72f7673815a7c0d48218e0a51873ca55e434915be3dc3a1241c449c2c589d498189c93f561353e33b5c5ef99acb48268b2af16858a1854eb4e92ec6abe9536ce05130bc0687c30bd02c6127308b76362f48105874d0633f47b5f4d728d6ecc2411da64012576d63adc72e84d906384aa76207f01bfd5ae83d062f4c62df8f4197f2fb4860550af1b88753c32139cf7ccf2b40cfd750b2f92a1e6897e8a45cf50eb1d326cd72dd4ae20eafe344c5209ac7c4847b541f45b190e3110bc89fa2412d7a75327ebfee611fc71781c08469ee0b47db161b8b066a4500d2454eb888b43fca8e89d9ce0368fb08c427534b652f6672df636d8ede10efb7c17ebb203f92c04e206187395a198ff04c5f1e2229427e365bd8da7986aa82db5d60ada27c8096e0fb6bf1e734226c17134d1f95b18f2ab1b110821420fa15a58b729d383d4e2d006b5d1d48a7a4d6c7b3e76c006001c9cc571dd84091c7dc6c17d5bfda754dffcc456f982ca80403c4e767b1a2ecb4473fc93f5c825af0f6db85f47090b6fb28e9aff60b4ca4e5c306727c1ec03e02dab69ef760ee08f4b7ac45061fa9a7377d67c99de6c236aec7514ec85cb9b5d19544b43d01f8fc2c9a759b176df04ea1cdce14e681c3b45f65ac2885811a9da8d36ead0f196c01a577ba58220c354d897dca64df74e604a4bf539e3bc952b07d683b94148ff924dc06553136ab2fccefaaec382e462cf18c9c57519b900d57b1c2211a80b45ed3eaaa71093f160b80dab7d5e5bd3f77def393854800476b096462dc2ab523dc8009f2563b061db5589058bcd0e7558508246f92b9a48c5f796cc7f293004682175379331a23686f2d7218043f648ac412bdbb6b21692aa13bce3789c6a1b2bcbf1582accc822c489fc33613319745226085d8f45e08bfa7956d362dce8c49de01590cfe0e98758d9fc703bf5813031dc56ea12aef5c0fc0d7320213aafcc8f90a1ba478f0dad4d912fadba5ee42be8f5f01551d3daeba55b85e59216d53c47f943d4690fdde0351e9ffa362072cb5e9e178aa359fb3d49ab315e793dbe01cda341fcd545b36cc259c82e15018b89d7fd130da50f5daca11e2f373071d79ecda85b37b8ab000420fabfe089bb3bb5c921f28bf43707fc47396aaa631e5c92f7771e76df3806331444a5bd0de59435348df44033b0dc1a65a12bb63da79ebbc2ecb610b37dfe54c53aa961368356e1fdd94007670fccb07d36e20d3cb594b4011da1a930eb699bb35ee14993ea2abbd48191aecb188cee065f6565a83689a361f6fafb1f0ac299fa38e264d489b0abb83d4859ddc796d18be15cf7ab1858fac442ec12527e8ad5c0ae809f47c523c79b83fdb462424b03811cc639cf7cf61cdda0b53c85273a52d5f5de5ab30ad309139027e9adc4e1b504c4365780aaf5a1fe1f5ac8bc16f6506a0e1788e009a0ce44dac66a05f159c19a850669f9f4f69614172f4092d0355183014bd4fafd270b91546dd710cef167011a15cea157e1b70c50e2713861f67d0456765b26644e408b87eb900be827bb9435013f2aa0bc82bfcb933cdb8279570ad8824bf696492d2b6acb744a5476f35082a1c8874be923550d47342ffa8621020eeb445f53814b4cb41230b4a5f3fae7a17ac6b45f1703ea0119ec909c673285774d809e43233f604e44e4cef5eb4283e581d3318779ddc9fc004d68c7d85b893dc0e13066b871658cc8318e27ab95d4fe8314efcf803fcf4353238b155c32008a41ad590b89aaa3c8668d1ac44eec5bedd9388e198bc842f78dd3def36f59364c79c5f449b7e09efe6f9b118023a5ce7fa419eff46bf8700a54b73d3e084ed2ca1bc49a3d72c5722a1601ad453a77ee1a2d4b80764d6b163d41855f6c90b12b87c4863ce0cc0b4a2974f493d32a7978bbd6f378b4ae529300a550de2df3eee87cae633ab084f6c50b2232339d37ec8dfb73f3f9cdccb13101b7bac739b6f06d83faa111a56b57efe543814a5f1a5ac7f1ab68bf5365b6f62f582ac1cc5517d8cc5810b6d4e278a19008358f04ddc3895a5f0545a16e40cb401ded72fb8c636457123a73b27112e8b1458bbc19506608c967c1f5457f85efff5dedfc87fd08c9c3b56e19d0bf3bb0080fdb27997f116979d7c13b808a664f77921fb2d3fb644e1be04504be85ae8ac5c6cc1a46c8536b62aa9a1874f4f768c5b1048115b5482a606100f7903714191408f995d38296a74dde3b94a5dc4dae57c0708eef38ce68e23c5fa3c7cbefa3d7dd43ee5bf388b26bf76708c6d3d42ac35721cbe32a88d00fdfee73f0ec422c9c754e177382007cdaf92687777da00098185ea655dd67d753f3ef793bd559b5a7e6d4df53a3674bad9deeb83a29cf996b98156ca5f64c430d82ea4c13da8aa5bd8fc4f60ec2dbfbf86eba7f019bdd74efbf6f8a723eca6c4eed15ad9d931ed991134d1023cd0738c3fe29cfcbe2cbab5f5f6ea5921a6c1ab57f6f86728fd35653c1fbe84eee13a2bb7a94d83fc3dd9d4a3270d01d1bd98727e6bfc39beb14a30e762e6233c3878f5cd9aa3481e87a5812f343b9e8b09386410832b2bb028d21b6a281e271ccdee5d126ccdc5b24d8d6c8fecd19073ddd2071870a33b2ab5c578091fd9f705f8fe27feda5cdb0872eb2e70e926eb6c8ae69854413965676e8d26539ed8321b12708bead3b76875406d1c6b193a149470826218e0c2237e292f02131ab417262d0c57e13299fbdafd8e1fd10f951faee815fb1373fdd1d2c760d2b4f789bc836f65b1935f0d32f898e53033b78a2d933bfc31e0ed8e03087c6e6d0fe59629488e178634424875eabd8c8111448c0c615e56f502885aa47c75414ce85ed82f04354a7143c818c51a3f7c0976d22e093bd7503e217e5abec14e016808da0268b5ad88f39849f36c63e938f0a15a961778621fce9b57f95c9f94200e21ec23d823cd78026aab75f301c1e473716cedc684232c84b520c3877035ed1fa302d3225a62ee07527361b219c03fed9df58631d8113e813a473cbb8af822fdea10a0d7cb96ed6eb27b7ed0b970aa678875568f0f0ba59af3fb9b7c581760a3178990a15bcc1e5f4317b94d0ab9d120da286e78a46a387cd8b3f97664ab0442d274dac649caa0e0ea9469d391d87d8dfb788efe810914a25d972a8831962ea3d47f8cac206ba8821a3d6f469efef8179e3c187c2d23c563a1becc2183944c9dbefe1ad55f653854cd308605538284d9b0f37b9bf05db5d3edd4a560d340c691e54702302351a4174f9844c014e020de8722f379e8f9d2bbbe6b50e73985fa06f27deec5d3c0d0e1db2c33decbc08c6f62fe3d27fba56825019c5771b39d1134235215cf4aa12f2c63ab46d93a115958dd4efd14622e01677431fddbb811118a80258414d712bce4f15688737ee43f188e85fff6dc50fbf235f5b75bf295a606c1e5c5c1a27238e2ec47a9176bd224307f5f83ad0b7656702526b31b5b0b53f80386dba0d9752daad9c9463b879ccd95d5c9805348096e71c8380a3bb8c752f3cc018f3fc514b2733c8c42a4d10c31daab39f2299cc5ab2eccee352c2e2219313d635de6ca097e55abac101f5c837ea35afc14be0a2ba8147d6a020a46064b62ba1e71ae4cfdcc6241e584cca15be7d3de6900c9d33c0886363e23398bea6baf811e5a4a3265cbb2a420a19e84cb6965c8a86cfde1edaa3be46f2cd8a6919cdd3ce41b1b0cdbfdd0ec011e0f8e9106ed91182b0de76a3f1e927b25d2af2db80a7f903861f8ea4720e5caf8acd433b4da6a0bcabde2e0035ece75366020dce04b242c7a938ad28c86a4df64383b5d416c07ca796d8486275fde3f6d5f43e08462966cbb5f6149f551f8ea4d5424226cfbf39a971abad5db2ddeb7045b8acec8b2fd09161780accb6e1b493cc2273b4ae1575dc0737cdbb7f088d94ee646d0575da0f58bcccccc4d48e2f955d2c22e335873900c30a25102462e75f31ee1ae0e9d9ba5b3a0b19bbb4a1c97d19ec92128f535ee9701622a3feb6f9ebc3cba32f8568bff1566fc5c30f9c234a3a2796baae0bc07cf15ee4c59f1cf8216983b89cf181da34dcc259c52691e9bc5f4f5980b41cde45217cdfad365f467d8239ac9fed6dfe272274aa1ff7232501f365d27cc969829aaaaf9d7d6d069d971e8bb59438be2a11f8cb549531a85eacc0fe86fa262b912a9887d2d706946168323a9b55a759813a0548d61c570e7c5c1e3dacbbba9e0ed59de3515db708c1a77e4155a571d803a5df0d4a11d8b2af4d40311e67c125aca1674674d989aa180d6a9dd893408d181450709b648902afc72942418794d2a8de30c95c8e0254903b72d5c19d2f645341bec4c321454c961e695c90e932e92ff2006a596e8cc6f93688b2cec34f351649599633460554d237488c3d0e990b1dac2eb867cf019859c3b5a71609fab6cf0a518ad323e3bf8360238a4f468a8b0a18c296b822ef6457e363c2167ad10266d5f43019351f4a0a940095af37ea484b933880c9c5466ec56f42b3f0476bbd2a13c88418ea5415f2fab9935911535f099b202acbd8f18d7865f0479d9cae9b49dec7fd9d14f0ed778c7182f7e48cdc78303b41b6de9b8d41e42c66fef9c5114bc8ae8131119cdecae67a14a7b8bc07f30e3a2fa3c1c1b6dfc57af48f475782828f4721957c2ece8f36577711e414531f0e85589095f96e52bd4fa05c1b01e916c8ce13e7c1005920f47962894b280901c053f9cdf651f9a8406c552cdd4336fd3f13dbbb08be326945909750218b8a5eb0e52a661d0834096280bd6cac20b9316584882eaecc519a2f3144b18667ce1c781ceb7787738718ae318822707e549342b400485249ac643d89ddefcc7b274408ead4e7ec414016b8976e98c20ed3370c4569a606a01bba7b789091d767c5cff85b7330589ef06c6afaf145d8f711fa247b61baa8c9beebffb183ad07e395c656ebfddf6a21c26adfa9c5f70bf95f87e2f00796512aba8d8fb606eb27c72e60057c04242b069c4f6be8dc8ba594a415f8f99fc49eac49a27a3039699afff0492cd61c29fd7dfa2dff317d3d2297796ee81e00a1b318b235561ba7285b26e92aef878bcbf2210e01652cb4d3b8f59104bbc2ea59ac3a06f72457d8e4958af0948bd2acf72e34453d1af57f0fcb63cbe323d850582c19b4097d62e6a142a5819de40a505dec4ad96f39cf5538114fc8498b087ea11b47a4161633207428ef71591228ae7bfc582bd2b82477574cef99576f9f6764f02119d4454ce73ce0ed0f744d89bc4c1e13a1c5cd3fcac8fae4f96f9c01313e0fd73435808778905491161311429f681164d8a1ee4c9008f42fb251112b4da69946d5101616f0584a93c5df5d11c247d6a06012a3a329023d313050223010693e6a2885c878e284260c16c7543639da98c22614d9beccaea5c3fcd0f36b0b403bf7fcadc222017afd7b2a370138a097c6d5c625c541338cb0387ddb7def6da841cf8bfc630638f240add3ed1e9ed9414eaac7288200b18a91f2f02fd128dd00c3c88c1c2123dd296bd0f8bf165f8d2d2630bf0dcf87dad2032111c626fa5be91bdf2775dd0577bb76f29e7ee48e76e7b4055322bfa96ce90f7ccf70425be306913c80c264a98147a1000601486595917dd73d55e48e93bd54337adcca48b586bdefec81bb2c29acfd4a35b9e1aa9dcbc99424d2b964d1d0010a72e39fdf04be1be4da33b23514076fa793e2f38045a4eee06aab94b67f0c407f643d0b83edf4244020ce33e9391832327d2003cc7150a1d5301a6caa2df3c32ddb0a4333d607f8eb5549e9af950c4ae31b485dc162c082a9476651bf77e3bd5eb867b5b1145a8dd7bce7591de455f97fdb856b82e5feb1a1930174bf9e67eaf3d7d58fcfae8729662100dd240ee26c149969500c6f0491f38925b61e86367091db9e02cb25b09f5efdeac98cfd8406dbce4796d06342e52b36753483cd9bd80e049aeac45816d9c82598d566bedf3d848353a9e69f69947f193c7182f6e1c6943927bf57ac89fdfd89340b1c0894045fd43e21551a24419263c8227fec85ba24587d0103752903883600547e15a0cdb980a32aa21bd3e76f7bf961d1a35ded09333865c0d42abec804dd5b0897239efd9c5e35f7e7673586c8307332935b6497e6658fa8850921b844ef16a274841ebadd02866e353146e0c2046ca0e92dee1794eb035a276ba3541058c96a3aa836e327e31ef19c000c842612956a9caeca95c1a3ba5bec5ce91e951f21b8a0c518d17e50e7330ca59b537bc8b18bcae6de513666a39eca7ffce8c7afb7e2191e32e3a916eb467637b9a5942949193b0a490af70953f52fb70a8e5f5d1c1e8e577934f223cdf610f7f3c0c2765e44f262ac09c78d51ba1575e82035bfcafc6081ad89b15e7a3adfa74af20311221996cfa48776b5478364c21f14e1f951355fde0c449c83cd114f48391a12c2f155723c112219c6e17d00c7e3f86e262142248b112192e1d85e9521224432a10fe0f0a2e88f62be131c378aee9777e21ae003e92fc69863128ed1c7077b127a441303e851c210ee18d3b0f051300568dad21fc432b40bbed34cdb1ce83805793dfcee85e66ff3c47a4538fa1c9726498ef7cf81a4718ea7343b7e3e0d12faf3e94f1d4035524aa943870e1d34d26d64fdada2b0d9e605f434407c1faa76d87451e5f578e8af9f977f737df01e6277293feecd11df9f2b85583747ccd2e28469fee63b4f75e7c2435591167a76dc1cf10ea61ba6d0cff3fccfa548de52eaaf9bdd7c77736fbc1d4dfdeda81991ab7761f52d3c843d3c2bee7730c19daee197cf33b41ba4d0cb8f99cd3648e2e77c8e97733ebe134c919c74e236559f6d649d0ceea858dffdb062f36ac8710311dbc03adfc954576b174c12b18ed739dd6e8b119e276b53b3d962e3647306fcd1813f38f0a759888f65de052f3f46c97c0b5e666194ccf778d9f278328f7a185faa5ad7d343d3f3307cd0bf5ec807f9165a787d0eaed7cf07f91eafca9027f2425e55dbf15435165435dcdf05dd183ee7d22c5d9a21c01d8bad8de1875c211f746972ae0a0ff16892845c1a19cdcc5b6d234bc2fd42a3d96226889c17a2629d1712c39018bc26307836b3215e131a1c7e7ec80ff19a10f17e84d0cc10714e846216138a5084f124e44428c8e7958d2cb51272a3200014fa79221a4dea4fc875219d9b818a732e9017725b6886e62f1b99b7fa6bb533b49c1b31908be3290e204fbf8d0cceccd8d024b8937321fef9c6f903b8ca8f4791bcd5412e4dceffe47841e4e0f3423e07d7ffbc907f09f19ab07ebc26b6ab71f99ccf969632c2fd3af7464a7f38c7bb29a2d91b39399e8dac0636e6b38dec850fea8e0bfcc9f9feaea9abb54be7fbbb2dfd1af2fd9d52bb5cf8fe6ed6c9e04fcfcf7cbec1313e62be98564cccc35ea1e214cee7c62a2a91a75ff53c37c8133b619e221179f87a225e93efa12a080b5bd81922d6792310bf90f33ccfc2bb70e7903babe896fc162eecefc7773c77e742dce3cd22b8c3738910c9300b37e29d3ba5e84fbe8efc1cf93f2e0ffe9a5ac09694f2bbc0f25b5eae41c0f23f8f490c2cdf870767e4afe0c957c1938f4305770f2fc6b694e7e588bdf79f9742f27f6e5ec7df7870061eef5d1f6e3ee220f76bf3f742fcf7e63ac13caecd07b934f2857c907f5d1ae90501431a53c840a84990ffc04e13570845e1fff3afe731b359a78600cf9bc2661b998d52bb6a683c9b59bb20c4d24609e8d2b8f7427b0123096b33b391bd2c61e9671b590e3efff3adcac1f542be5538bcfec76bd25c5421f4fa56e110e485784d20ad8b22b02114e4839c7521ce719d601c37d31ce0fe999b6f646e9e4a31377768e09651a44c4304dcfff242cb53497525db3c612a81f38c0d520a671b5990fbba9d17425055437cead14809a43f9b9e179c6d68b86d643e38745e08f978af0b85ba987a2921a245924cc8e505792bc885421d928ed30b7da18021a309331823bbc2104b13a840a209303041139c3041134e7046138a9ad0cdee96ffb9777bb7e73802767777d30e04b15d4e3aa5a45b9515e53b6ee08f2d69fb8e1bf067fe905750d057eb3dad1b9d5ed08cf0474a2e764141fdc9a0a89242d7b9fb6c772925908bd3dee7eedeeedddd32fdc1efce818694dd4dd978a1aa54f73c3c86991caa43715d979a2877771e5c92e145664db6c7a4a4a464d409bfe9a81b37dfe09c54feaa4b171ba22007bbd50b55a5bacbc14c0ed5a1b8ae4b71aa22b30328187883c65c9cf84eb81ecf7186bdf09b77491793d200f6ef4e46a29efbcac16f150485dfe432505130f6aa7a13eecc2252a5d4d3cd0423b44c7f7f4e928accf0011667a4b164021770bf450277cf6e26a400bbbbf0f98be55b94b0f4c10a54d8ccfa7a581d5291f6347e8b1433ce39ad8f81e7ff97051b44a03d52a6e41294c012062cb12c010b962d4f60f93e83a8041de00904d63c7a7919da25f17c52c6a684212846b01829010a099e94c004133f58827581a4841814fde088050423d40b7a2ceb1fe7d3d9605c40042e3a68821374d085e90a98cc93a51862b9c20433505c31c588a6a837af73aab130b3dd49c1f2dbc848b705fe44f88383e5774eede2e203db4edeacd16cee6a5d4d0b2cbf0ba72060293b31b0944a70a707169b3b25b0fcae08eec82b3514e6af49a32f9f45f3d7ac39ccf60ace35357f754ede922f7dd66e9842d4eb6ade5249b1fdb9ab61d915b54bbe7c9aa259a5abdbb6d55a2b7c1666367271f35abf9b5bacf56badb5d6ca7973bb74a8d6aff5bdd65ae753ad0e63c5fcfa3048b5bf46982040982e7085d102d75ae9cf59ddea56b7ba552965e52a57396ee3b6cd6fd7c56b12eeb977ae56ce721fd4b30b4787faab8ff2e6537ff55535b030b5d675b973776f776f2f6360087b3724a57cd91788385d6615c52bbee58011d705a3ba218ce29e300a95ba51a0bebbddf7f5817b0e1861bf999b8ff23ad4fbe5bccc0123ec5fb33f7dcf1c30c29b97e9f464a511da9184657956b584e57a3ab151d8650db8b3a586bcb57da706e4d99afae412792e25ead6f6a3c23d9e6059f389e5dea4970ef5b77ddfd9854b049a6a409eedb735e0cef6d5cb330a787b2afd6db1fe8ee0ce369ffaebd2049042b4c85b3f6636774f30480d2345bbb8df1e2609a60af803f1f63062c01ff95bf75484e7cfd94637bad1cd09104620e63e49c4156256add6426751dab7ebd2dfd65ec7c2ccfaf6dd97a6df09ae1b85e16d8361da845084fd530f85e00f0ef667f28310dd6a0536f53eb58802c367fd64c22895ea55aa5984550f3fa82deb27cf12e0f9530908f480c8e33f7f4a9946aa9fb5d54f2f6761b7cf73ca349a526611dce97f40049a4a409e7e9f25804840ad3e75395cbbcf1d0da77ededcd1f06c32049e1c908227078cf0e440119e292f636008cfdc0de149239e4537cf1aa6f3d24f5d20e27cee53577583cacbf3299e9cc764d6f0f674fba0f62a2fbfbd7caa5f2fef5f5f6e4db7bce27a2166ed48c2fee0f5d09fab96b0fef24e25b8d3bf2aaa3ca8d5d3d0d284b58881297d99a794522333a61943b3301862d17205670bf8ee04eec8018cee113fae95c5eaa494124277e936a0bd70f7c056ff0bf0f5403480f23d42b31eb8d3dfe31ea54b9772a27ca2ea265da2ea466710a4141b74d46f70db36d443196bba72357a4c4bb499cce7bb40faab3a38c090fe82d742031cb5a8a91161afc9b03f4b0b142742dd23e8a9a284a71b68e932c61353aa0988e8d233bb94042e3bc470610d2d9220c3f2e78e21481d240c614102166c6580661cad1185065c1841250742b22e81a594584a29e511ae602035220d0d0d8d60095356a81e74c1831f3f805cc8ca500196f26b194d58be6595c1042cff8d60032cff332304587e4f0fb07c1f690614b0c4d2840596478882e512135a24131c5ccb182a41ac8c121861648b190b082bb082cb7f5f6031d433d4458f920b2c5ab2701a184af33bcf4200f1f17ac6b001ab219b83eb3ec7f5211f32b034a2261c5b80212d04329cc5494585cd3e84c3f371c5c61d57768be7c94ef8c38323158aef317fe1f8f88ee449ac8f3336922a08245b0d17b1fd45fbaccf01e675bc5c1a1c5e7ec7eff09a746838c9845ede89104be6469ba7e3b693b7e2b36e3fbdec17144abdeacafe5232edcab5bf94ccdb76e5f8b9939abc7cd39aacbe97bc157b668384cde1d174ef81d5df7899c7e1d1749e0d44ab7f790fbc7ccccf3c93144e3db4fd759e4d122ce76521228781886d2060f537be550878f9980ff255ed58b638bb912be1f833dfcb5c9af843b049a8678b30a024110323569045e8c6e71e1c619310148af18e780bc6c68742f276acbfe83592d75254d12f282464a3c5e68e61d91637823338732338732338732338732338cb700667b20a37824b1d7443e544d52f4bc8b0d3a0c6844c88e7c9b2e00f0fde84fc3f9d54cc7e61b3ccca0c9b927921f0cd4ea86009853ad8752a4b2b4e9264b0610138c67fc2f2e38560e0b96199c2d3cb426026292ce58b8c0854bcea06ade839b70937a89af18ba6d0880a8d8842512669646df506074e683dba7b7577f76fffa0943c5070d323a59c1142086972680fb46a4a17dbe5a45bb52c944fcf0a23a028aeab3a33540daa74ca82dc721c97a2421bf7af88d4d64776a4421b84843455b4ffc18b8a6a4542faf00d2e1491789c202255a488b47a912f2e6459d2b94ab72026151a92153f5a0890ea4cca28b0e0454a2951aa2254ce10c440f0033c777c11046799274b5880e00458fec69a73eec093fe9c73ce392995a9c1218388f664092c69434f60f9f3fbe69c733a610c3c5578ce39e79c32ae2964c192076db0004b1b4e60421ce23346e7851490bc58e3c91a56ac81461720b03183290c4d6104587ebf38c51fc346e749066a8c00cb67a9a105cbff4f0a44a4bc783a2209246dcc9ea69400c9149c60a6d81b1862d9010f3e0cb1ec60c99d707c2ed0a9084e70867f01275129c95f6ed4bfb444a3cd663219ce363ad96ca3936dcfa5f4179f690519e89048ef804f1a4f32504a297d02d11a4db03104050cc410a2750598521c98524a29a552862155520241430a2144c1882894118526a431c352fac4109c31851ed4e09081b30e102c873c418a27b0018530b8d8000d29676c8182881b4e58158658b448eac1104b10acf8d052b380fe1f4d10dbe0af9e9e207f4def0aef0afbd463720a834527a5132585227891c41152c00222cc30966ab02d514125890b8ab0851345465f84515530c676041b582c677c71861216ddc42d65ad1e4d12fffa46fc6b93592375da1f79c0fd17461d7410a7fa8b52244b7fd67659191655cd57fdbc56e565d5d75a3bbeeab95a3fc851b5d2f9716e8442a15e5e5ede487737cb2658f52f2a959320f27413e6eaa36eedefd7e8204e5ec90b8576f098c2ca7719967ff794d28eb60a21298d51a8d6dfb64df59dcaa349d2af7a23fdaa7782519daaeb54ea72ef04735e3442e4a952dc7c952d2060411337d8c108a2d862cae4428d2352be002307568a38821735054f2011e1193b8867a800bf6088e50c249e20194722902541892c9eb002055c9c306a82043ca8520411b21350349e0793ce4921f0831e5c71c414626461c3a88b0dcc202376840b981082f9c5925ff23bbc921d1c0d61253f86152946b0fe3cca0e576ca66075f81d7cfcc0660906f6f7010327104182d1aef85d13bc82828d4a98947872a9043606f915a2b10e0f554574f0246d872b673fa0606bb0d89481450b5cec58431e35e01df0eec25be0fd7b4abb5a78ff366a57cffbb79476f1bcb3f0fe1da55d3bef3a9ff33fde5bef1f9fdaf5bdfb785fe15d85f78fb5a676f578ffc8d42eeffdb6ebdf6fde3fd2dac5e3fde39576d9bc7f9cb5ab86e677bceb78ff98d42ed67b8e771cef3331ef37de61a4c422d5a7de25f0fe43f82b02ef6f83bf20f0fe47fcf580e7e1336462c067e8d4c3e7964de07327e5cf4df3e173cf10f0590e1de0b377c9e1b33f19e0b373c1e1b33b15e0b36f21c067afddf0d99b6cf8ec4c03f8ec5904f0d9976af8ec60d0f0d96909f8ec57927cf659003ebb1292cf2e3bf2d9ab30f2d99366f8ec5214f9ec48327c762b00f8ec31a1cf4e057ff6a3a0cf3e2586cf6e04c3679742e4b3170df9ec51803e3bece7b31309f9ec433e9fbbcbeb733fb93e3797209fdb0988eb85cf5dabc0e766a2c0e75e62f2b9a5f40b4a2aed0474f9b84b2bd8b3945260ff2ab0cb5e8044593e71f5809ffb021eaa8a28e083da879425eff02ab99907ace4e30de27f0022880bc485b0f5c3dde1a3ef7097bc922bc4c44b962c5125bfc34395921d963cbc3e4a96fc5c1297f830cad22db94b68962cd9c1dddddddd5d72c1fe4b76804b2e845ed0921bdfa362659676d5f04a9e0689005ec90be095bc0eef2f97daa5c3bb92f7974ced5ac0fb775dfc1f6e1327423f2cd1e177f82517f6b783a7c34f550d40bc9297aa0128f9580508ef0351a83004fb831012800fbd2a3f7c90ff70a350f24a76f0b213bcc3c79be30e4b3e46d930c60dc7254a94e8b0c30562c34abe554574f84e87abc385f00854f2539544c9435511251fd43d6b1794755c6769577dff66eaa6aef516275fd2e14a2c97325cc24e64e302ae02ae925b7bdaf5bd005d39f0f347c075e10f705bf81c6ecf1be0f23c0e97852fc0dd79025c9dbfe1e6bc0df7c70fe0b65e00f77b1aee0a9fe4e27c006e8f4772bd3f72ef1bb9ff33dc9b2f7279bc0cd7e601706b5ee8d23cbe3b3ee8eaf8182eeb61b8399ec8c5f143eecc035d99ffb9312fe4de789f0bf3af6bdf755f3ec85d3d90abfa176eea2b7025f014b811f87c19f03e5c077c0f97879fc06dc033b910780bdc077c02ae118855f81aae11887d7c025e3ec9914416b809b882fd112087b0ff01ba60ff1c0c808313f62fc016ec4f801b9ab0bf0d03c882fd05e05fc3f5a7e1c2fe925cff005cd81f12ff2355607f23d77f86eb5f44062bd81f0017f62774fdf185fd055dff18609082fd890c018261ff1f22ec2f6408fbfb5cd8dfebc2fe5c17f617e4fa03b9b0bf172eecaf024cd89f024bd89fc9f521d3b0ff0492b07f0fee04ecd1545cb87d0477fc5bb8dd739be7360bb7776eebdcceb9fde3f6507ffead1b3f2e373add887363ad3fff1e3736f5e7efddfb372ef1b89116afd4dc4873e38e1b65feac1b73dc88e3c6197f19ff981ba9f4e7374ee9cfdffabfdc28a5bf5814a3dc28811b87bce51f813b84b7fc21701f708f78cbdf01b7076ff937e032e0d6506173cd91fe6840c0027878407ffe36633cc13e10e34487fe238c11c509433acc38630a38435995d9ef97490d864dd6fffde503e1f432931aec1e1b2f83b21ec0581dca291386b4584af9d0a753ff5cfda7bf0fd3691482393e5c5ff573d70bbb61adacfecd9393c9d7b021841feeb71d04f9794ecf87e941b1fe5169a33438c1d40b42cab6022a204714eb7f9f587f19973c76951e31ece8b2ba5debad1add7dc28d763115bb63bbfb3c72ff1b176225398bb42c5814cd700b15d52a13387e74f5cb22f61d7aaff206ec85d82b8e2a7f4e62f9830a9bbaf17126e68ff84b87c762b172588b63f55dd7415512e983a45988c9753f6f1763335eae3962bccc822d988f1e0e0f6605f3376e76883b3ae5ecb974238b232c627471c538d4c972cc82634b98141cf10b7a8dc0e8f9f4272511b83387c09d2938572c7728110567ab040c67c0b13fe1fc71d9b033b19056d42431a41531e1ecf33e43e08fff7c22f0073a0ea6e460b30fc647da952da415c9f0fc21787ecfef3d290d3c3d4b121a78c28c43f32750ba6d946e1ba5ae2024a6af78446f10154f8f68d0707fcd67895d538dc4120e9c65a211dd10f605faab7a2bd2873edf7a2bd29eb4bbbdfc03f71baa7e906f57043984a07ce0a134d99ef3aab7e2530f0a842d87d65b30d383b00528342f14eaa7f1cff227a594524a9f081f21ea7dc049953040200518a4e0054fbe10f2a0482f8af668dc4be2a98800618c4334000c5a124a4680886d6cdf3737c1f32bdcd9c93deec19638de44b8c75f40071960e37b96f77798020fca1b1e3635343b74b072e0989189b901635f56aa54c7a1ea46a7f46e29a3d04929259d28cb92927b29b3521a597deadd3dd81fef95fd79db07797785682fc592ef24e83ce5533ef52cd3524cf26805478f5e66126bfd1991d5ff8606367eab8cc878ac88a44a515495f865e5452bfdd1fcf5641feccfdd0c6570162dab57519611ffc9ba177f58b1eed1daa0f39ba5aa489681fdf99d926ed56f9e568aa88c483c63708793aa549752a954125bb8e337a78a58231257b8f30293f22ba5941d8451c5a8607f7332f9b09433ef373f8e9a1c39628e39938ac19192c9919a51b166582c964ccc0d160bc6b258ac17d64ac562b17c70324ec671d1598fb13b469793a6aa1bf951fc1c28ec9c54d22a534738fe262363594cb6d69aaab19a1ad6d758395074100a5bbfeb4ed5982b67735445dcddfe2a950385952f352fef2f2a2335d85a18981beedbe6eefe5ea6cfc4a3478a84a3076fa2f0c30aecaecba162a30d30e2f41775308c1e9216a6898185dfb90f841042086184d055333894a24ab9f22dba6ae507b5138f5104394d74394d44f76eaf3a55d98588284a141ca54c29383ae1259030cc02439a942db8cb69c2e6b88494b3029beb15dc5fafb4cb91ba1e51919fc23de4ad4e7995d65b521f531f531fe9775b58dab4297dd95fa4aa14379fd2344d7b493e1cbfaa284d511a3b1447fbe977ddb4e3a7babbcf123792f849beaef374fa6b8fbb352d65a3c8b090ce2ab290b284bb772933dcbd4ba9e1ee71ba2d6cfc5afd5f1585ca62e9c7cfd1c2e60f6f342a1a9597e4c35ebf6bedbc0d5e096f85c1d91ea5d3037fb8df9c30f7b905bcfdd72ecea349f261550dfe1d7769b897df79349c97e4c3dc739ca75373dd838e2203679b27e836601b43da115ca20f6d818ec4239431acc2f17bda055f3045b4238e9ebee888295243518c700662717487d5231c83ba6d96b01d63ecc15b311a4518f8fde4f16b357e0f317f35cc5bf01b478f4849b0a2d905edd8ddb5c6eebb7d74824c8704b675486023091a771bbc8e6daeb02e858a1fb5aba778015f92c95bfe4d833ff47d32012bf2273035e6d0194f5aca98b11b3fc6dc47d113621eb52b6257ad9ea4f9cba374cbfdd53d9042833ec4841a4567c0b40c95819d69084ed8db0b3f9acdae4c5aa57254abf8d41a76083609d1e4e0011ad701b38f9d988067d1594dd8ccc239c2f6ac6b27e02ba2503030b98f706036f711dc890d9382fbb728dd43a8c934842e889643f21b534ae79431d76ed29f4f9f3eddbd5d763b8c31ca15843bddb0a18c4f9f3e5d464229e58aaa8a00113755912e821042082774afa3f417bb1be6c4c5060ba408649d9c4bbffac869105f8de471c64ef530fecbf791bf9c4bb7e2df88f63a52e489df48fe721ac496d73012545e76233453e76527028e4b282ffb174ddbbcec3ec03d9b5ef62cb0752f3b1548eed45f7c1b14dc2b6c10d2a8615cfa156bdea23010411646e8a1284f44a9f80df357c38a1afe10863d9cdc88312de85cc0e202172f38c1c697170cb11082d2b619a103666b1da0e33814c775b0e3d68010c215a8d8a89c1042082184f5f316747777dfa6808ab25dc64a1b61f74d16856393addf64b76fb2f49becfc262b5337e8a44c94843bf02b8410be854d57c8c184104a192b13e32367e7104208218412fa48296b0f8639451173184a5fe10690260987fd23ce18c0eeb565819d334aa3e6bc1dc7d5212ac7753a6038f98473ef5dc721319f882ac449a74c35c7f4e260836f44d02b43100d47e4101f227c2447040c32bd19638c1d0a725d773fee7f8a875d6a25654febea40c9309141d58d4e8e8b52373a259cc90d1523aa6e7422019d1491decb4c118e27505ce54620a7dc2a8aa342deeaca71dd7316eeb435a2680e015bfd5feb2f4b878571025f91297ab10916133016a1fa47e27064ca8962e3fb1351855254e2094542713ca14828f4369e502494882514ea0111dbc013500111710f70a7ffc50429217e80324407e9df246ef7a0d0bc318382e16eec18c25b1f8b86803b9d52a95236f81902eec42eb5f291b1332a1f7fa56074dc56cf2b22d98a0473311ce23b2f57cecb1615999022135264426262f281734462f2d70660abff494d04b85f095cc40c5c4e14db0dc161d410f0074219e287803fb068e6a8917ae00bf51f0bf690bf545e0402fcfa51d01569dc1de207181dadfb2307eccf65000504c7db370cfcb6f9dd94b2a5945246c8ad24852fa228e8135185502e23ef0210f0001e1ccb4bc3111c36950d3e4486a07981f4f47073e55e9444b084a260d243c3209372407684cdada8176fc8b933bf4325b9698ec5e2e04f9c7066557d6450a5892d2621c34466c6c75fa89eaff597a5c3c2e038045bfdb108f88ab49804134de08e553027035b372aa723d1fca34d8bb448eb700f6d99919dec0fce20cdd84005d6c90afa7bce21f8e32f918688e28c5ebf44823f36516018d290680143da08a6604be384edfa1c2d6e9fb9272f34b8e3f3c9cb10dce15e30b2f3890c8d76648fb29cc18b1741c4f9047b86b48a6990c4974970f601474f3ac1433d8720163cbd2c672077cc1c4915c406cac0472365346ad7942bd80643ec5dc89c260225ec3e9d6822d0824202838663d81fcad8aa1aa2c71444231a9b88eed65de2e84c61a7f7e9d86f667334c2d148290819f4807eb5a00cfd925d5ca7a6464626c3ff7a7c20cd0818604833c2087b7c181c83fd6bf42011364bdc9149081dc49191bec929e7f4640f0fe0e10436d62aadf55714016c350f4c3c4c96c93259261f261f261f2658ab081bbbb819116511ae5c2583ce85606f013b6dc1d7c32b38aafc0a7e7fc513c02370160316193a7db52ca7680477fa5b300b270e2a8ccb1740c0f225134c0638a92a36d7236ab5c2c4c402b6d51d18c92c68b488222ce159c002904551b720ced5d28a70929244548200c88a6830268c02804512978419236c0d8658c288bd30c4124693b5b422a6501dc4705ae38c229e30858bda441a2388a143d8a8448881e54f4b2995c21946a4a0249105142f2c1a48c444170d11975a8960f0b05a2bc3aa99330a99832116252b6ec870b4a919f9ab93926450b320867d8f756b98c0726da5bf08838558c86086fd1b897f23f11abaef006a7fdcdbfe389ea78a94c47d9c538e585082f522cf61fdc50f57b08c8c97650c4b22fc74e386979d09cf92c0b444ab025beb6537c25cf06a15db4296846405a71a8697d270aa3135618ef37294e1380557f88493c2a0cd64944ea31edcc3e9581c0ebb2bf278ed2417f0c302bf2881005b2e99d0904588aa0038c1532ac9198e8ea14a05f0e55380cff209027c9651dcf0594e6143dff87e5703be7818c067f944009fa5086af82c95a0a16382005f1196e4b38b1180cf7e04249f9d0947dace00be229291cf8e83193e3b16453e7b0f646898eff723e02b2e01e0b32f21f4d95590fd89a05f6981af1e8ae1739f01c3e75683c8677f32a45fb480af8ee5eee2e7730721b7183e9f5b09fea4be9bf6fadc2e707dee19e4c6019056b1015ffdf4c2e786d247b4f0b997e8e921c0971f79cb732c8385cf51cbcee77806d6e9eeebd845d422e773b402f7c729e0cb67de729ce802dcd109dc5109f872a7fa8deaf139468182211b100ddc4f01e835b00c1e48e04bca98c01ff8b33dcd67a84424c80e96d101831b85fb55802f89037fe00b55fbf6f1572d80972b01bc1bbc7c231b8097ab00bc6c6bf068804c28a3245eae01f0b245e2a18cb0ff112fdf5427235eae3378d9164172c2fe3278f9c6eb0c005eae425eb6d80bf2f28dd7a318bc5c61f0b225e265d6102fdf6c4f405eae3f5eb642bccc7ac2fe3e319abf36dacbcbd5e5651b840684e65f5ff072b52e782df478f9066f433c5eae76e74867e64efea248def2cff172fde165dbf2326b09fb7fb3eac3cbd5aee065ab028e976f30854999bf26530f2fdf785e665da337baf172e5216536522665d86792a36afe9a345ebe61b1ac95358797ab9df164bc7c8333ea868f675939454e8941c9c858a2a1664f4f31b7f10d9411ea062824540c75e4603818304ea8249e9090e04e6c6c6fe36e5567350995a92e559a47f128f5e88a24a458ed76977aaa4cd4a20aab434a4a3427d49896faa88f54b73b2eb66db1c9b6a40da94b17b813b7a1ad89cd682bda604b4bb7715d4ac3a9c624851428242c3359522c8a4570a77147298c56a147b4680b13b8c3d4c693530dce8ec09dc69d4c0a833693651c8c037722aa0677505a38980cb82731355067e45c61fbe56dfc42d586c047bd30fc944c0d0e104a16791c48f42a18367ed7549397990c407a1d7560fb6bd86b3e2899d3b037eae9051c3fa3b2e8419961670a08fc69225ac02e30cc41308c28336cfc1be20298682460c2b6bdbddd614e0eac0d3dce62c1242fb87fd63d7cc14ec9cf8ea5c36fc26fbee0f9451a1349b8b62b3b1810621d2ce34b272ccd0c930837104e30ec0ff6e761875970ae38eb60f974e2e9e550613d3ab984b1bb5dd5f352150d4e66f8566d2528c2f33b2881f820a05f4260ded2aab5acfc5fcfcb8bbc35ffe53dd62e27dd2a8aeb52aad58b8591e12e466606470e968e1d3435363c6efe6effb8eb918a323cbf870a490bc72afa9b1d4ec44979acd6580c09a993a2bb1552426e47f3d67c98db2d49918484b452410c9b3b58076b57947e09f989047f1c1be998dab5f2aac4264aa90a4fe98fa79452fa4ee93fa594de3ca5de534ae97d4a6b9e524a699e521e4f29a5364f29eb29a534c753bae329a554c7538ae329a554e629a594c62c34e629a5947e4ca2f129a594caa794524a29f7f4c6d3d4534a29a59452fbaba794524ab7a7f4e529a52fa32a427156f87abc0a3ff3c38ad6e7630515703ca41e5eccdfc4bcbfe1ddbf81a949d1cc9a6635339a99e561a35443f3c2cac1cab1da61850e225a63d572d45438aaccac89ce66b3d4ccd631a596a15d8c157588058371d10a3b51ac5ae5b85a6dd65467747603954aa51a2b35ee6c5dd9dac16c1ba54adb6d6c6bcb15ed7a4b3bf9cbe7e7d3da42aec3bcd5317d7c49a55fbeaa49b17a79d42e9c5fbd5401049244adcfb209bc7a3905fe7cbf7a39d42f0983c164d1ca871a104852717df6359ee0cf4d967ec958ac29b625c665a95d3c820081a45290cf1e0618f0e726f54bce66b2d96c350308249b807cf61ae0d53b12fca1f9556d55732aabf7a276edf8d5fb11106812bdf0d993c0abf728f0c7e65f13067b82f910cc615bda55a305024d2a2e7cee25d4e04f8e2bfd9ab11818b12cb1a659bb70680181a6520b9f7b0b25f8a323d6af399b21cd9256df54dac5fad5b713106836f57cee16e055ccafbe89fa356bb58e526b293d05afbe87da55d980409488e7736ca30bfc9961ea1785c16a30a795cc102010a5c2c2e75804bcfab8047fe8af682ca614bb120303affc571fa780405429f2cc9dcff10678f5510af873e3571f8dfa456747b3d8aa7b9dcfb10478f5510908449b84e817ad5d8870149cb37a0a40a08d28feea7f6817f7ab67027fb69a65b2a15f1bcc5bf3c7ea9140a08d4ae4991f1b9281e0d5ebf46b8bd1d02ed4affe08fc91bffaaf5d2fbfc2671f78f52befb3e3d5ab008136251cf8d3bffadaaf6df6b25d30bffa0881b6a6c833edaf7e055591950c4b98bf3a246fcdef21612a4849250275565c52c6fcd575b2939d944a11a88b059172e62f8e939ce4a46c8a405d0744ca9abfb85a67b2461481b8a61788f0e46231580c16835189409c920b54f0e460b1584c290271545a509af90b55abcd6a73367f3645208ea86736e1899a796b7eadb359238a40a8261e2298bf50b1182c068bc1a8442094120b54f044c16031582ca6148150547694f0acb5daac36abcdf07cda148150443ab409cfa7357fd5d98cd666b436a335a208549b7288f0acb1182c068bc1a844a0aab4c5fc556b6cfea614812a95b882129ebfcdfcb5d56ab7da36c3f3716ed7d414812a51e49992c8db9af06796d73c4984e7fbf7e203a9b3b282a78287d3c3f3565e6705cf57e166c50316eb60f371aeea6b1dd14d8d47add611e1f93d68523b664d34b31db359139eefd974355c4c89868bede0625cece6e07070308e4a0e0e868383ad38184705cf7f1d28568d23ca51c3515bd538223cff26a6d65953cc6c35abb3263c9fc7cc26838a29c5a0622b54ac7a31253cdf865247c1a8a06028180a4605cfafb931bb5a4311a5862acbd61a8a08cfa7a9c24a9c7da9ce9aea6ce6b3263cbfe368b61853aa3556635e63782ae1f91d6a87f49f1f69fdcdc61546e5330b8627153c7f63b16c57a4a35b69ab55a208c4cd22cf7c16cb6eb54a84a712cced9a6adc2c027565409ef97388e51d9319706772333c9fa59aa1b1f5727260656398c4e459da156d4c6a17ea5faf9f1f95e22c5ef95212e6adf9b26330d854cdd01d537ff3eded9a3a98bfba2ddd9adfc5765cf084754c70677ee39c1cd81457c3f3b91ab785736ad7f6f33b24871d12ec9090f0fc98d430c8ae95f25891bf3a26e845b55acb62fd841b0c22629efe8ec95f1d6cf5cf8e09311d9391c7dbcb95372621c16edf3f57af9f8f62b2b9ca2b7a41c858454e4a76ccb63ba62e477ac79cb95279fdd4df7c9fdb5dba31e7a1e6bf6eaca25bf3ebfc9ebfcdce8929b3de65c76464c33edfbf65aac8858e45f0c003543a8b0a3a4b672122e285e6d38f41e2cf5b3b48fc0e8cec5670ff4b0a6c841746e9cec4ad6088a5eb58a4310e4e843bf1a5089036ac7faefdd50a1d62271d03a2c6a8b4cc76554d512a433300200082028315000028100e0704e2904824ced34c9a3e14800d779248725c1a0b646990e420c48c41c810400801002000223233430300447929521f7f27b62e95cbc23d10808e96da37eadfff254b85e6c8881868b72b352108cef9e0430bfa35f15529cd0bedc00162a45470e37f2266518a1da101933a57083c29fbd1b89a837fb5c00f885993da36e08b0d96ee0f9b355e525721719e0397b6f81f105f926a82d01e2a20c648911bf7f77f37a4c2cc1adc640edc9b0d907f540c0138cc85b39f196691d58dd8e04b8e5a5ecc5dac0ce1324a9a3ae2cdb81c6b495914c102b57dc5e8928616516ed198f6ef69c2b03f227a10d328e1e54ecf786ae08c93c0096f12584861b62474bae4b86459c42b77748ec474d15af93638391a93c6394862a1491d456602e2d334ec51613daf555ddcb02ecab44436e56e0ac291c8ddef2277657c3d9b23f9cff8e29e38564220ba6a0a882eaf5ec7fda44b1e2d68e00f79eaa9a7b63d63d740593ef0fbbce3fdbbde8f7e80a08c12097e343678fd9aeecf8807a20cae2c05a520b8e790bbee01900a36744137c0afffd17d89d8f537ba0f1f9f602b1142e98db0f6ad2ecf6a90eef3f6c99106edc6819713aabaff5b9969d2fed3d41c20bc0725869a2848aed29e7b71ada6030826425269c510fa1edd5f8b960b398aff5d3647119b73ac2f3c3db4a51e9ca75ebf89d9e9c88d550eea9eac45a1fd41a359104e1b093ee65b6d22c3b728f33192eeddafa4311a9451d052fbaa4bf1cb2e1ab8037ba2b9fa8c7bae8ee12aac05c2e03840fc00ea68f280bcee2cedb2bdd3e602409fa4d042b024e23ccaa207fd6645a0df15b95614944b542843ea89a190b67d0905c30683d5cf0039c8ab5b6a009f4a503ab7b177fd4e0b738bc6080cb4b3f71aba8aa2aba2d5d0f6a0747183b04631ad60222daed93c927f3eea8450573dca223c2cb706d64bd9f550767e81a12c58817a1e2a32e6c6be1cc8657b28edd5dd275ecbc28f5a120bcaed84eb0dba87fa5ee7478d9abf025a7f4ea68ce674a5ce4d99ea487b915edcc268dc0eb5337e043f5130f713d020abb7f3bef0c7c586f91e1cd21754a06cd396f26acdb1347ff9472dcad96e582e4332a008c7111c0e6e832c18d27337a6f8b94528431378dbddcfe7680f184de73510ee0c938ee62817a1a859464d1e5e98cd973fd881c2bb2351260aa7beb11730d54bb3d69a75fe6a339c8eb49dc7a4e6d2ee09c641cee9bbb96bec40064bd92500747db9750dbf341ee8b96dc5d8425146a6331dbb0c6debb75f8795e3d5e09a31875e4b4bc2db2c165a6ebd81cf392052479714e4256db8ee05f23270a4abba8bd823230a4f9fa6c3b4cec57660a392043a84a009f4f039400e7269faadb09e5e76e3e5358f3d4ee831de461f9779f0c1cf6023010707cffe3291720cc5164daf13e01d4570f6b02a78f0acd20daa196d56ddb0a8afd402eb21a500a6588fc0fcf45876f12700803a39b7d5cfda5019131e09cfc2e47898a19d26250cc60497667c1848fa3228ea73dbaae4d3513754e46201f5f00feb777bc5cbbc00d800cf1c89c17778a91779cb1b789319241e9698ac6ac9dda63eab7dc3f695ca94b5b5aa635f8b01af6de65fb5d024b80ed8798768ffe5f728d9a0bea15054e9b88c9655ecaeb05548f8f596d58fc634a9b6325b5799ebbcb13ad7134ffadef6f1445f7196906e7fcd4b8eb1aa2ed036ee704b2ef065e8e22733b1179b55b59c78906a921250c08af0623880d7ee62f1a7466b0134502a9c1c97216bd09e1e124640b7ed881f993954402fcc98a5608c59cf0795a165976749759e6625b57d2c4f5d8b35d7ef163566be4f35d0a556afd354df6534ac82ced5bb23263c088be9675aadd5b07fb72bba10d6c83425c15274ac219b5bca74eaa55515a220240f7f83b3ee0b2db4edfb590ddbf454709fd96931b5bbd635d718b477b453d25b8a2cb4baa80e61b90efd830e883f9703b1b1563b4be51012d79eaea03352074633ef34c3e1363bd7c121d3f9462a06343c01b37beefe8738b6628cf315ca89b48f2391226ae5d95345d9d879645143971e9feef12a73ee12b41ac22f96d9abde959a36e1b5020c3db78a472d28e8ce9295739ec2eda7ef1e2e7444a3363b5944cf09bcc3785c86cb4f93827f95f3af728d6c0f7da15ea2f11ad3f0a9c61221349dcdd903c4e6090f40cbdb09ba3b3a1fda0f02b01b8302a3cfc4fc0cf75b0b3f4dcfe350617b8844cba399b0a345a759145030f45a6433e62938e5917cd4661d485dac55a644421e25004975c4e2c1acd132ee382057cb204ee9e824ac7ce4bd0c3868e1936e9528f4d19b38d4b3b43bac5340327755ddbbab49749db97f7c59252221bb3a0c823b9682074c446773d8752bfb44bb10d977b452018ef7451bd1ec879e40f6ddf2672d07cc87aaba06615a41a55fb95a5de6270a021154f8840e647064a69f02977599a660003e7c9a702c118ad5ace0d5718e68c597e0bc3b9ee9fa1ce634bf7d397ee92e57bae504ffbc698c4c46cb03479469d86832e7e8eec860861a02e0bb1fb33b2180cc887a4b02b05fb201a7a609ea2ff3fca5813293602ac33fce79c57393d8f0a38caedf63ad84d5b44ec5eb82b6c883e344ffd7f0d27a2f35c262fa6197f6951d3a6f985fb2a2fc98fdc5912e281be77998ecd8f7dcdd7902b18f77bd098059a4fb1ef9cdc09bda7c1c20c4d42d83c68d166f3336335aea0a535ce41670e69569a2f5a675f06c7a4e7698ff9c0af32428ae65dc39b6202f47407838912ccdd213327b0b4be4a194c2a9f514ce9b9edb099c4125f83dbe1c39d433affe12cf2dbfb3865553dc0702f583c192591113a09ce4219990ae23337565b6be0cd695c9ba325a57a6aea3e6cb2c31838820221d99d629d37a655ab70ceb9769dd32f4faec64c8437d062935179e8e9967d205bf688f949618d70e49b11ca41c8e007e6cd12c842b0b6255b25103f252b06516e71a161bc479cec759e7f19d566ae42c8bb71f81fad738fd2e91177a300004c21f7f4d2d33de9ded19676d9ea626f4a8160f03444d146018a21f4d9cc34d4d17279f74806adee168687ddf3908fe2951cd301086e1dca383ce07d178fe41e71dfc7bd40ed504ad86a7a4735fd7700eee3fd9d9d1988bb76dd150ec67569be5fc8f193b8672eaf6aad328f9e74e3309ff1e5f872a8774c353d2b1af2b3307f79f6ceb68ccc5dbb66828f6335bcc72fec75c1d4339757bd56994fc737d99847f8fa9439543bae129e9d8d7f59683fb4ff6743486f2a7d011967750ea0c461da24723792295fc172cefe4efb974f85cbcf95e1f8d4e65e23e33bf53195b73b2d1b1d1ab0e719d26c344597e7768eb18da9c57d3d4943739f00126dee1c47759f939a73946bd44c94104e06e3b5cc060512f4eab910bfec66978a524a699360e922999d9b16110e251cc904fe29e433caef3348b8975198b3f3e28f5ab84c05e1eeffde3c3531a2c0044def4bd5fdb292e50e49ab28333fdc5058c8c51f674c847b8c09103ca1c9f000cdc0ac99b0e90e41ded9dbf201501941c4473cc81308a544bdeb10026ef7bef820f490ad0e4e0de93d00493023899dc7b17964952802707f79ec4ad989400cae46e58a3bbdfe8740351de8033c36a390829efffe822d5ebac932371fde3fee2ee9abc4fb0363dc48118f726fc93bd0e507d31d998c34bd9f4698eadc84959a47bc128776546469d9b960c19f04ae82a0f2c2ebbea7b3571e6cf7dd04ebe239f906d9f4699ceb1a11e26847f89aaf4e357c9758ddcb7934fc0008f55da8f72320120a9f728d0998e32e916223d7658255fce347772d06930a18c38d8615fc3d08c40b836d643049a86181c18021e3c722c92ae68d083eb6a85c1c8d4091b21da879af72e4c689477c011bc138747e5825a575360b9f797e9ab3e485968d0baabe891a9013a18fc667a51750a86e9c2cc26f1357041c9dba172df91536405018094251a37db2d6a81b790062e8a3396fd43b9230c42947cb966c186aeb8f30158845be7ca32a22521b86163e980aeef4550ccbfce7c2a1d725b112c91c0d0b8143e0eeb6e169a9167dcc365a50a042feef1ebda2f4d614740ae5fa503067e3197150120796e0bc9b8732814a2d47d82cf72d5651cf01f1da0c5a6f183315716e6b625b4eda0127debca257605dbfb128b84aef7e8a4aff80471ec830d2d9a6a0cd502900622f9fdacea7543977e1c1dc121e77cd2ee78e297cce9a17444d38b58fe90d77010dab24d1b79f51cfda30f2a81dd6cbe2791e555f58ca0de6ea3b1f83548e94f6f5c936e83af0f13909b6355028c126e6763b05b9b5cdf4e2b03061e264f4b5d31a5e222a19481886e2f31dde144348307cfdae847283f58e497a6f5d9b415416149226faa597333ec6a2c7a708de30da89aef5846affdb49ae240454ee05058cb1b280863cc607be510916ab6dcf316d6666e77db32ed1b5c5d23dfe078aa73aee3290e37c3ef5a73bf161cfcd5d136f9c756c25ca36ae4f3262f1845126a988a23f2dc09decd3e72a8f4f0496333814e1e434f1c69a579b179d0459ece56beadc25dcecc98b4321e884a69c0bbd4611ea8c7e7a32cff59abdaf6409ff14c1bc9b637c6b42d393842ef62d39d01a5e38b19879a689410af1860d018cf61d7842ef8e8e1ff13ff873843686f4121dc4ab1fbbb87c7ca3893162c3120e4c525247584c2ff2c600b335b8bfc0cce086179b042fe87a8c7b121a7ffa6d11547ebb530d6a2f4ade20060c5814c48364dd389fa114eaf2f0c32543044a7abdcc36e08e96a8157e80e9541b8dde76148fcf17110bb513ea09b67b0ef0f3c9dc9c374ff2ce23ae21478805c9014cd1002103a801e9c15f3d882e71677ac34319809dcfbdffa5c616d9280fa33c3c514ea723e02a7bd1ad27daf24975ee5779f99f561f69d3116dbd41884bb32ee9f8331ea21ba049078e5394576688ebb29219c3ae91eb59b3cebc408ed6f223d7bc59a0aabab79e2936eee84a7d7ba35f613f52695efd8bb0cdfbcc5a02b4b566be8e5fb0c42d4bf656ba9376bfdac366dbb8af9d4a97e4422f9e9285a3ce35bf45889b16394c0ba321588c35991b5ebf7182618d9e9326a42247a463c238fc471270a3c49e237272dafa765d54bd162e0973229fa3f44a0a5cd8b52719ad4d926c8e2ce68c0b7fb5a786cb2d980c0bdcee2e1feebcfa2696a98428333308cb74f8427c4e64bf7903cd4beac08fe245ead3dfc5d7ba67832da6dff2b97f9c810ddea13191bbbedd5f3b9a2c4a1bc105f12ef520ab5ba74229edaf9307d065a5e77f60cf65e15b16628c9d6552c10c319ddacbbe1ce47b36f3e0b244aac7b3e21c195b4f838d9a003ec4576c381da2a9d3204fa5ea7eb449ec2a2c990b6fa709006138cde7a7bc5a14fafeb7af40cef19c6f3f06cd90d409b800c59976e080b3954681a4a977c395bc7ec9099efd0aa3dbd153e77fc85b7f117ab1e0f859368dd59b27e07a867ccad1eab16fe292726461fee293cc7129ea6f3d267d7d0b34a60f20dd153555de45279a42786960ab89e488359933cf2b50602164f8bc2606c7af3a59348730b319ab04d59b6d986f70e51d099b0401adc954aea8424f065ec951f97ad216b5695a382f670955351090b1c6661c7b32f63130f3e4d9b51232e258778e98fb7813fb79d17945cd8cf45119328b414a66f1332672e27bc7fc1922102e00da7b507daa71c2f2e2ca41a652117993e2373bca933677fe540a08bde23b81f995436ab2b0ce92d75849170274e317b01bcb1b0ee1ef0e47251c6929b15812eb654694cd139f0e949348400f5372c073d91c35abf96868e686efb68f0b59c881d5bbf155daad5923e67c4fe2005ddaf20cdc3bc4b026a789a9cef8b0281ff01f3e3428998609cc8f07ddd772058da115f9a1d4994fc3307bb37eeeae47622df88fd7f7e6023f79462dfe864cb3ad7b56648c0c3a0f61d70b5493c0afd1c70f413d4bf4a3b30282d84d8a8120cbe7c3569d62109aa4ef6be30ee61e7dbc71bd79437092c99b640f117cb839f5bc2ce5c19841a09dae03f637fb1dca612af8e3743a03d061721501e8485ad9195203c1ac96ef611b265742313508a209e1148104104398c2f86b2b523fc911f6a714c2b6c30250c7fc25706b5c139c006d1836b709d7377997d50828c7520ea93c82f5789014b29a11c28a9f09e7959f168b94d0b42a200d3f496884d33514aaa4f793f831e0b9be92ff8d6cc7faa0a0f1c314aa6c4d2cd376c724f0aae2495859cbc1db93f78ebb2dab1ccf9d7f7e04e2fe6b47e562729423281279e259b12d42fd4c22ff28554398b57fd78ecc74c5aa9aacec82c6548a2e7b596533bfb57b36750a1aaaac0375d7527913a2151b63dd47408b669b2270d6c0964ead2e4eca3ff6940137081a1c8b80abe4034bdb994e34f0a24944e12328dc0e7efe2d936ade32dda2427b9f4fb644899c21514b516ddf9965a945b316505766c356e4dfc43bc0d408d6f4d8dd94030e5979797a2e183ddafcce9512ea553760238c614ddc5d581ae2555a1ac5cba07d77371d9950c590b21883eb76764ac2c909d3471bfc8eb4bf4f681c0ae671d09122fc9755bfd7c397fd75b4a60bd88b67af2fdcd1849655aab4d47d9f6dc808ca302e7d160e47577e6ec396b861fb9982adb679264c6b70de038e4b5c87004d88fd59b336e70e5ed533b5f485186ee13311436b521604f231c242fd6d4de001d85dcfa61a711eec5a19e4ac6f363a15156c1e2e0e38b5e590776658b97459c5c77b7395fb6578723999a26f53c3d0588ac363e6074f08279702915711f117fdf5b4951ed7bce3c16c401b00a991ce13f4fb152d781e1a11c3ff1c47947d50ed731881e5485cadf2a14683c2bb7142e876cbf72d449b028d566fa14911acb4f1f2038128ca29c243293447bcf2b11848e904b8a8ca9d966216a37228950485cb2e428182be048ca6eec6ebbf25d145b7ab2190dda64330dc3420bb7466e65b36846dd1572fd26390f343899b0e69e29e7f94724f6ac1cf8e5fed3816239b00f62fb7a20a4cf2be292609e0a929cf45a6dc971b98ffb89e641ba93200a534003a5880668c6f6cf1755518f31435886f548f5437ed11f23486c9707382d4988e16050a3267dd58f73edde690915b970da8a25dca7ed9dd60828824156e7075351c13fe5e093f1682aaf92d27cacdbfaf7930837b36ea1f6defb121d583ab2ff6c8e0537cfdb1d14095dceb732f446ee17b48805b338e639afb48832f3688e184f9c181ef3c8c6b138c45d069050ddad80c2f11e874fa5e64fe5d803207addc5adf8308f7d2859eec69aea0d7fa87c4513345134a7886b65408740e33981905577d5e202dad4e546a077c8b5377944a7a74825fbe20a8a3439f1957696dec7cabb59781fcbde67f57bac7d97a5efb2f25d96becbc2f759fa2e0bdf67e9bbacf567fd3e903962137c94b404933a9c2e411bbf0e7347a71207272a316e45530160ed985ea60b43f6c3e756a87fe73472a0e034b74e5cda45954872fbdcd4b4fd012c473958fc182b03f43c60273ba7b7137122361d7c6f6fd16a22d176c94a416a2f8cf66a42bef945ff9f42a73d7d05d00f0998c5d1d6ebeec506f3bd34acd9443db81ee0690b49a79874ad70accece50e1a252ec2f0cb797e14f84d3215a1b1d4d22966a6aaa282b4b357caab901180424c522632a216d727835dd420e43a263084e9c3230368a1755090f1c52389bcd46fdd448117a1bf7edc2e05d4f1d6a89432d7a15dc13febc8cb419459696cc829682168396a4960f77540cd3cc09cf495e7adc69acf950c069fa3a2c753cd529b15b1fcf253298ddb7836389d77601d4d64b835aba3f8bcbe00896268111c33bc23d6b8567f50549007fb59c6872b3d68846a7910ac27e9c12c54493b68476fa3bec344bc6754e35dffb639256cfd84ea46b4e0c4223323a0842917f0fb9022d37ea97d6af849f4020d77fa3f0e2ca9e574e484061b551155884a2c3c6aa6e71abb75495a7e7481cb3b5d970186665cd2bfa8fcc5afc005a293637fec4908a5850dd4f831ca244790002928484246ad5259ddad0f2c6c447f0628e06e6f5f83896e4a9cb07799d6c5001f2492c295c1fc9f6cf06eeb75063351cc5ead4927474ba6a07e852b2fbad9c478a2a4cb00e420dd38a97d816b14e28aa77a766bd3270cb3bbfd394d3baf62bb60776404a04f4a900ab353e8be294d6a9fd6c4e3dcebb0ac8dfdd009141802e6289aaebcdde61cca6918d7b4cca64d1c7b77390568a2e30025b03beb82a1461e1808a5048e5aa1622de71daa9f31768106feceaf1f00bd205d80f1e24a79ea5dc4bd0da17ef129ecde24ab85f1b708ab5bd54e3b1fd1cb3560a2030f7a7c08926ed9fc5cd106e6b5715083b1c48f28af5131116dd4ae46c8ecc12b19953f3a835129deb96fe61302b976832cb02d6b8dc71be556b0f86ed27aecb4ab7d19b105e6c666ed3f7c3707a581152a773cc31c6ed86aa30a80b8ef39a38160c58b34df427c0fdcb2d2ddf61fa9cc52fa0566c821c903839d11dd36df67e4f1b57f44f64516d5376442b904f7e2b3317ebee7ee06bbcb21f61886a38dd512030c4aff30c8a9160439168cdb1a358c155178580cd6ef4335c142dd8fa88c892fd116015c09ea031306c9821f62aafaae96a7fabbbd8600a17c2814b67bc01fa1ac50d4767ce290cfcdfd713111c414078b7526f5993a3cafdf66453680fd8cb4f393f32f8a1e7d33a0c3ec657ca5862a5badf9c925b9bada08f81f4b1bdbb792b29fb3ec3e239cb959a42140750ff064385ada9da70513a3b005d84c5bfe004c961a881a28a9c32ddb1a4c0df1ac67581f4b2992a615f819ea3b5828ff9a5dee9a0230cab6c967a4f0088e9ae5b72c2b203ba75ce1ca7e95ca7749c8fcee050f4a8ca6e6cb8d453cb68626a0665867811d3376b623a6f45743cd9f1c55e8d9b934af202ffadeb17389e2252b0f82406cbed18a138b150b2cbf1d7f6f6b66f4c1f02b6d9f6b60597ed90f676db066cd423e4f111dc03b764867e6f3b28189c094bae9b533f67e22e958b51078d7071808abe2d1cbe79f80057528ecbd0f3856c4ab5933ee243a4d328fc8906dff4dd42d0eb85c7eac78d1c7cebd88997e1b1a67d392f94665968d8f7f04bad88abb52330cbf5eab44529ae58055dcd6fef82d7ab124dfcddd2da7c805927a48e73732863a05d9f2cd8078e1adfca11f93b53562296ea67aa420235940e008da02c77d83802fb9f11cba499114f1fcf5de9d720b6f1b0123d1c9ac24c78d1d906b76049e8306bf500133d3567136049e9913ebc4892c35024e47588156b0ae429da2da846a40b65123be1482a8ca9f89067f5b5b34894f8edea425924b0dbc7c263ab5ce2190554cb822b76a6dbc963ff06cbd072ec62b888206bfe617d44b5c18c5d569e2c2140b9cdbd9fc858aabbf446c0d58a682d6bed6095170ebe9cde1a2dfc8dc6c809aff550ab107411a9b0d0730c435f7094ed5dc8fb83bc27a1b901d4941524054bd801d28eb3aa992c750226ca2b4f53dba10fec8295273fddd966221853bcbe708bab255882ec3769e85685f81295b4094d1c2d31c45c582da5af1d4bd90723d6f93473552e19c16bc1f7fe27963953739d88cd6998c9c71c519c8971a737427c06f3f94956d78b882333ba8680b4f2580230fc092520d7832b3d23113329829b82891b15543126829e2a322243e756e18632aeaae2327970d07acc3600e8b9fa2b38a241210d0c1f2b7563983ffbb754361078adefd2773a0520b5032abbc56851e8f587b36e9f3198aba8d03c51ee48cef544363394050afdc2b53fe7d6755170bc4b86caf45f462024e6493eef1947a7420c5cce593a45c8fff3300c4f7cf876688a7967356c6c4f0d1f4f12fae5212eca4c742ea3bbb5297a894458c222047014bc8640d6f7ceafeba977b5a1c28b50c4e6f1943ac253e7615f89be934719f66129f7c3d5042dcc38c989c7469eee0477a0dff55f0a833764e5f722eec1f40e45445fa477194e01644b5fe15bd4ac59981fea4813468b025e516d541e3c48c5cfa36bef4a6de498adfca0363175f63bcb8fdd713e4236bd8f5f16f5075ad82dbff6f73ede5f6e355437e4b99717e58021b34989b86a65c10a1eb24f0fc89eaf733e77ef24f80c1827a92b72652966c3cf6c95884e5039d2c26fd2b069c905c362e2ddd4e2f6adbbc99ba7a024e34ca1c25f141ce20a3f846dc0c3f07ae7e13ca9305f7fddb5c50684eab03e930fd9ce35464bf468e086865a51b0bd36f545e3487cc9602b69da7b2c26dda052847937aaa53d552a318734c88fc5d4b70a13d52c653dcdd28b5c02f1454a3d6b6e04606150ed77bca8614c80c8e933c2cf4d52e8690d5664155cc147cf3dca49bfad8a0ca10ae969b720439732784257089ebda73979c03356b36e0f26d872f1c16cf2b82ded0b7ca23c52c00f61a5f650df4188fad2f2abe1972ed6492fc7edf935c311f9962ad4e1f31384d495ea9072ef86307003c0502357f95b39fb3398d9c962f50053e4c32a9f950b035ee5d206231e0183a415b424596846480d4ce72339205224b25e25a558235ee86887866805c2f48b5de450eae680a7a47d167895a0c84a5510dd68312a1270395263faed76a3149c6fd66a36b870e94f6ae0d5be3afe884e8537f044a74a3c8750f5cbeead4bd550be86ec887b27298bc02914ee8755dd334ee5b65524f95817a9b15b7e7d2f4efc7ccecb61649738dfb0e7a837916996af01420e0094e971f1f7f2ee9e326037ba5a10edd2e886839a2b984631aaff8a5a344ed46ef48f5f93d30eeb6336d0a673290b5e8a907c9274ae55dfe6d6bbe4d804a098a9d30389a824e18ca6db729107275e6b51ab16dac451c7b9f699a203c6d055d138312e20be1baf021375deeacf7248bf34b57803dcd8022480d5841ebd3d1bf3c086153d6ea9248944f199fdc6e24cf923570df05452c7bb66dbe7afb67a38b9e3ece5d3abcf0e3088478f631cfd94dc783471202577019361aec8180e1ae821ab6c23ccada2139d787b9e620900829287d9ade7960196318143e11a44ef4ddbde0f88b96bebdd77edfa81bc8cc77104b8c4cc069d2e0db9a1bcd24d5405cf5de7f74e29128217ff5c20ec06a7eb5cd7e9ede30f9cd40e656e159fef2b502270590c6a49a3e75c6914f6c0b647f8514827e6229fca02ed5d8e857e9ac5db74e92c3e777214512a0945b9665a29e937d4bfaa8d312046e733345c88217247aa21d3291f169e2adb2f2543772ca79a275263497aeb07a37aefcd339f48f7c33c4a37dc25a830e050c16f131d7b2641cf0cd70e0abb4e359b740ceffaf1b202f5eb2d49e7178f8e0e61e9a64825e2dac5a1a0ed333073a99b9613305a8f456ec41780f4d5021db01d52a9a7254f81cd00a3cc8694c367c0052c981744e26a13770db82b906103d79f7be8535a57412555914c188b0f2f828f4f5e40b1a8d618b37f3034fbd4f2998bad8b0190aa5191da84a58b1d5c30688bf797c6cceb4145eb0d358d29cdf4af616f8900d3ff2deac9dea2604a5ad20686ace4294ecef0f9ab47863a51ca7503e3c5cb880d21c54c1fe3c917e10d39733ef02373aa44259bee775de0d42639390ec298dbb97ce5015330c070d2b0c69f49390173b4483f6661696ed53884ad91c5faf1e894cff19ea6849be1df0336559704598e89282d7b28e8eb10fbff8e73a78817ebee5fa3169e9efaf02840cc9df0de1786a52ab778d66ed3eac92c4319dec4ecac6ab7a28eaec6fd82a750c1ee2cd9047987d43536282f27a2272507009904c99d83977824d3f07ff448d15cb7f707a8d8ef3c6610b33e8a380a5ea718138974ae80485218e754a21f34e9dc977c7cbabb28e243e1bf957bca2334278a68f06ccdb1043c99965f26691a8c8ecc98f25e50ab9399ebfdc3716840e036ce027cc3e9685c9cdf2c9ee51de72aafaf513631eb98b50f8063a36f60cff1c5e1387be53d17894c5351ebdea86af28954a50d8bf59ebfca75825a594f031168efc0afed18e19c85ad81e588b9799fafe904d1356026bbbd59f56ee00dc6842e362cad2d27e1bbc956f747cfa01bbc36f8bec609b178aa962d86b7c54455a3c4e65ad8d52aa45d06c41329f8d082349e088eebfef028d7205ba08c5233c32ad66823c339c7532fc487ccf229b4df3f79c870c6b9fae56d583e7a9ef213bb06b531d8a5f9a86eb4dab4bd911fe805a2b9552d15953bb6bedc43dde253282ff7781bf030863ead0fa2a3ed54b96d317ae44949efb03e8e33f82a19b6b5d3c91a8f9aaef3336af892c312abbbb73469c67b161e7292c5978948f84a4f20d1e42a19960b30c3cc1eaf1d691867772987370d987a46236206da0e6f497a935d205fb4a1d41ba07fdf0fd58fe0ea9360bdccb84858186b1482fe2217a6680a45373845af1be69ee2c86d0b62ee9491abc5cf5ca62bd365bb86fd12fc4cfeff7df7c987f6c1276d2fd81fbe26439fb9203dbf1611f7bf7dfbc047f7e98b307b17b311cc42f26b9ec0d8c548cf0f8de04590948c6ebf301af01ccfe5c0d1c5fe40eb603422133af4fe6178f8476e8cc8720e5829e33ff6e9339ff9e8e9dcadc3b6b099fc38e7f168677f94f4851212c7b7f3e03511d353d2abd88a515d9167019573e84abbddc804dad78582d760c9cb208871dd1ced7392dce3fc5c978a5c3bed683bd76848677643201233110c09c3be38e0cba435c215c2878f13b45dcf282c5c63ad91c8a965a87c2f17ea077f59330ea1ca456250750f896894b0b441bc2a1aad0170af4e984fc79f8b14e830e4a618f80632c262b2b744201ebcee0fb8c8ff6d1447a90c0cfe8ef97f48d035a1abf58cba7cae71afc712f74d5f4c5826b17489713fc4b21844147282c61eb12e6609603d7b26efffdb4134505a707c23cc1e064a432242cf34184a73519e222aac47425bd79a3bd934339736ad59c7455d9673ff8e7b28519bf9332e054e42e7fbc7aa66f6ae8dd39cbdf015b6ede186a76d3c9f86716a283506393275f4512e9fb15443f70d37fd1e7f0b3660517027c152590921a7ed9b8671322b102ee19e6256db2a22a5acc0b83e946e4ef6a007f570970048c717546ec8a751efa61ad66693f208f932f48279440650021ecf1f04913fdcf88a20ca25c3cf17edb7adcf79a512fc2af74aecd8ea7bd03cb788e41b86a4e7d7c10ea40021eaa6be8c512fe13f26623735430bccfbb7e0bc98c5481078cdc6b73bd72e8c3d7fd26fed2c61a6c47b923df00c66a23e0faa3d49e88580eec8a5d4fc34772468903cb8786776850ad020805571b3a8b3ca371a3c5c12f8a059880219391f5742c2c0ff7c13fae74ef3ecfd5f1dae6dde5175a00e157cb14f1259bfcb466d5e979fcb3527cab04aea88148044e75e07b78c18689e81a7cf2dd2caf878c02a4be02280fa8c8d61d0e1f2401595662556e99148f1d9a57a96477ff8aa6a685aa51d27350cf4ac39d7e40748152c9340d53dd75e4420a6bb399da81dce0e08dd4e91c698044d5cac1faf2e06571a605998b7df3af0d5fd842f792f817eb8c60cb573def5c1dee760eea0138152724e7f9e373d3a592cd3a4ec0d8a1c6333ba8da2f2d4fdf40b7e5c689e09142eb8662ed3479a8ee20c4580f85eaa1aa9ae538529b3dc95ea7bc0ce66679b2bcf921912e8c95ce56db759c29a3cb758320c299f86f74e30336dd3a617ca441b567405e39e19e7f985b08b8581f7946a63341c33d78b459a014e443c0a718d5859bd51f7387399d70c03dd9a30df9a8a5ba960d81b54be24831ed71059728b810cbdb8f90a024877dac226888f430abb2a59637be1202be834f14ca9e3c339a9c277d6af09471382f6708153a4eeed1f2c821c287ca702ce61473619752cc772be0dfe14f703dce621d5e479284b114afd4bf15f4a746a7a8c669008c0fb38a1b3f3aba46d532595061510016c912c3828f060b5808d4cff583484af6f534a0fadc656d54389bc6843b1345a20c8aec6686b36df2ff87e51e127f3fd3ab7e4aa50809825298b9fa3e06ce4e4c9a21f5207259ee29d9045250dbd07dbf4e5af9122490fd5a130dc4cf78463c6f315a84f2786cb5530ebf02102fb0bb30103d49f38bfa40fce497b3c08bdb5b44c6073b25ea61ed8a8467b6ea385e6a7e90a695d55967ea4acc3a8eb405cad7224406731c361a2d1b3ffb1afcffaec637f901864a9923fee4877e466915e87bc505633c1692948385f0059bd290f2c785c5e0bb1a8009d507365eb5e1b2a219bb109a59af833c9a009621d174c9b6229d2a06d5a43088a182120026539ec986950fa53b4ebe090247c2ab1ccae74739a7d9ecadb675bebbd4ffe8b781ee4beaf41eac7d8b072e38efb010172187eb1f483378720c1d82564fb322634b23d35798874ec10988e7851f6fd8dbd45c9f5114b1edae0bf6f0b88cde1475e8877c4e4894c8526b64617dc1162a135a08019fa00ffed1fdca347b9a6da90b99da0079bed41a883272a8c0abaf4ef988bbf2347ae6b823a6d03d65a54d0e3555e0a134c6e499d71cfcbf630ff4419872b685cf7f657680efd10582c751f3a1e1f270873e8177217490fddc4e69910c71b17c64f0976aed206a68e595adb5d7810db0c2252c6b1810000681d9059be4a8896e392e922f7cba7d270b9ef05f8a30633b70a834d8cb9b6860110641ff06065af4e70e490b209da80d7366b5f999f49ec6558010165b7127a85f2edfe33e5cd814e4823903be2475d489c56f87fd7c53d59e211c8d8a3010f823e400cda642123118cbfd8a2f3b0b650671287029684051d28527346086d2d072e8ca5f6b14dbeb9f9c4f80f66875db8a467d6824e1f0557e01cf0b0313b6657474f12af743bc0cfc776162a4d3433e67cfced89b897bda0f233f26c4276c0735745dd03fb847abcd079c7cac4cd873b724408c0216359f292280155c1b5709b49689731d1d895aad28c8a18fb1c857a86c65b8ce77ee6b99030e1ff88c1290c9faaabc870e330e11def1f2f33e3c862c3d3240fe56d1647706b3c7d903b1a10a83724f1bc7105c44002dcec783d6c7151611406929b551c9177c27efe178551788c5de29d33ee0c6edf37752dc12da05a48a20bb226d121c514279de45add3c151bbd04192db74884a9ab48a9b1791a02ebac02f0703fe80f6e065253a1ed43b7d2686cdb626796605c9fc0961718e8cfac2e612d5d0a0bb0e4294f9918fddcc25225b24a6477630ac4a6adb06c2a659c17e40f5a0902e3036977ca800f3c95462de81284ca4ea3de78beda931d21abc61ad86d53c9c442c5cbfe39da2d37bb3841204f030ad834edaa7f53945340d8bd947e558113d7eec970d76ee5a752e87aae594e9702ea64d390a739a33fd5e9b0264250b396da6f853b41197940d5d308db7984db9283f1671d334e2b84a6c5c59a6b0f3ce48b9cc13217bc7b4ef2836fd5c2a727877785e37b14d8c5a2d1938dfe9f56eec04751c9223ca0b5cb4bf4b14d7b4006c9f889e54896282c2d21ec40e840ecfdec458835f8bd9f42a2b181b356580dec7c385667130aa0928f07ce70a03efb0f7ea68654698a05d3a7fce1a38a92714f2bb7f40f80c73aef96c09fcc2fb1589eb9a250cb7054c4d0bb6dbb13080a7c1bd106af8042dda52c651fe314fab1dbb00b57a5719f90c0f3cd00b82fd0c36a823912d0ceca41a0a87761ca6d2e4ccc01d0ad324dc2e7df0cffc74d85276b2ace8c12342d8b942434b7839862b0b240c74fd7642bb0bc02a5bd887af78914acd07a52cc5bae8757c6657949cd7d3aa8ac45d35d306c482fc54b375b6d293046391dab7a30ec446c69309c68f4b7a708c520f2c5478cb7a734d496bbc242a547969e2fe5df8661e604ac4c6e43f0fe7ffae186abd2d8793203fca7f555348b47333b731d9e5f700204fa2ad2cada192d142cff6f77d37367b801183537ea065847420fa80e6b14050df2a87bbeb10b119d30cc87134edb89a13a9b200a05dcecc351e0b049b862490b845fb0d14cad0837d40347a3b2808a3ec1b6f93d0870d47f76a83b7dda7c9ca3d825c461e7fdf068d8bd2a5d7a759fca1ef30c06293664a73a48e2a0ca82867c18349475e679efe0c9dc1bfdfc99cb8a58e8cfa6e4130957edcd89107959f995929864811dea36ae6772e34a61346695cecad7ea371f37c0290ced62c62a4a3918e0ff0a9c2e140ef566be2103d4953a5228818871107ba2cc5a4437cd254938c0c410f129516deae3b03df04d3e60a1e86887031ff42c9c090d478a812c5148c054ef8aab9d34f558264848a7bd2f7796a3cc0d7f04d851c3bffd0acf10a4a0b853e73a3d5509fc3822067742a26a86f2c9e7aed7092cdf74c8d2cb2abb13e3c72f4dc6911b596604887ff689e671b0e6d887a80a0002ada40a62e6b49246fd548e1bc8ee9f5d4d00ae602998eefb71d6ed72178b08c8f3d897dfa4ecd7505f6cd1970b29a0f2a4af3073b10a0b9a6543059fa180b6f91e05e8d413a0f6257d24a255acfe1d955e18f35b1722ae951b9528959fa386fc35af67032652bf0ca0e788877f422306deb687a1a4877da9544c41343004d40a9d422c0b2cc7101ba1b0e3adbd0a8a6227de26bb9210c126c43bdda2edb480ebcbd4186c4976ad4e90011877be0435870a757703deb1caa3b4ddfd783377ac50f8594ae7af3942419501364b9182e640dfcdf577b74e499a1d11c5fffe376b033dc4dd22b03b34601c42b6c253d873396d9c421134701350be45363002cbecc1b7ffeab911211e5092c1082efc824b51b2a1a1a7b1260d44f59a9ba05ed6d39d883f2043ef15413c7cf58844b60ce94409816367b540f0ee4f656a94e666d63b3417d72836576f671f427a4f867ee8cd115b9f770288cfbc832d6f3cf882ff0cc9bb4e85cc40c26d4478e34d500fba9554b82e2351200b362509bfa8eaedaaf03a8236cb1f6648301bebaa430a90121b4cee88570838d2b9cda10b425179c4ac12435f1533c2db071472566d09b88c473b33bb9da65bd777738adc03b81a0d49798e773bdf03b1251802457b5625886bb292e2eab56582bc37aa503057746fd4bb3459f889bcf03313855d0367f95ff445fc07fa669f4b30ea66713077b10292e6a67b03dbef099a8aee53dd056cb62c76550e9b70110790651aa1b0b5297b5feb35cf38c3126b317c98d17031606fef1a1d9e8e117f2549e99a78677268b49c592b03c298c376705a5207ab4094afc44e6ef6036a1588bb593fb7f00de2d308002ae6447713d2693b9dfad5b8296802181a864f14ebe4ddb622373169d373bac601652ada8544a40be0c9ba37af1daf10a47459249c587eda54e22f8a0a4791c1bfe80fbc92d50d5941a38a19ed1e24fc2b56196c2466fe0ae8d2f0c1790a509a21019da3497b9ea518e05e1bd796d0dd2b95d2d2d28d37482cd0f5709507016035554d2d2394732a14e2e444dcf00ec968bdee5b9a4ea2ccb24ca051262ea65ecb9ab36b9bba1ebf3ee99070074f3fadc0f234faaeeab49af5ef48ff743daf30eeb58dd6297d82db734ab4ac460986015b6eac5616681ac9c15ef527e74ab294c0fa921cffd0b3ae004772523303d22fa433cde708a07200c466d7932af550dbe01794daf2075b0e931d7b94d552500415361b41e602c20a00051b27183f43fad79fa3454eedaaf213e18e0d60f5ae1c0c774fc0085cc9597ee03a4538fcc0fe23af43c836b2bd69583f3badd99d9684d63ea38d24c37e862d57830ff7c655d544dc40fa155a01cef294ccd4186ac986a9351f8a13fbeb2308e8407b50e49e14a11dd211852bb823773f77ed595c660883898ad87f194f0541125ad59281cce757775dac1c5810478071766decf58302369c320da8f612572f1b74780c6b6ea6401660bf1b091e89bfa0a3b1cbda740fb4d8e8586030f20f1d208f37d103688f4ae672b9e255e95c16906a0a7261f47632b7254991df1b3f46293cf2ca1f19609db578942c1935309ad9b7af388558a1cf85aec93e1fb6e67d1dd1ee0400bf6f708378d149faebb74ccdfa95e9fee0c17bf24cea5ff57af112af9a2e3ca44b0d1a8722b42c886a7f06d5aed343fc0b275c0e6aef3b0b296f2f4a00e22357c6c1078770fd1498db930d1c18a0e7e46eb23d8148c05a68f36f739cb263a5f1daa0161feeb87a03bea9c9d72de5b6a4435ca8c7e0b591532b8c6300abeb927b9d2a91ab4686aa6f5a072a0858a575aa5285430473462808e0146c6d2081a7a0d9c46d8f4b4be14ae701a9b8923f1ea6320f9396a350b07ec405dcdba2119c310528bdeef162dc1e7c58cb5688c778cc01c76f7f94ea5936f3606ad2e5d2f8a640b89d684c520724e9d8290537b59471b3e02b0d887ce7864c94fe7ff32205588b7cc611d1410511f87b3e85ee315515448e75f3002ac93cb765f6611c4507795e59f666106e1ba7da4419e5a4a7e4ab21dc94282c036a1473e526bcd913bc400b1faa9af4f70af1951c19a81650a727e24c66af06a53a4abd6cbc05706b50046c5075064a5fefee33b4d638c9faddc22bcc9c4c43e80d8a4fe7ef92362f46e650e739c6afcb29b0a5d11d203e224625ce2353ea48a76a842e12dfe5150ef678da9cd22d6c2443a25c9b0781ae10fb7fd187ae65891eb9fe8917063e0f4f0f96dd7aeb14b1834e077ab3a1c15c7966abf8505ee78c526ea68cd05b2d52c1fb39b46875947a026b1a89cce6953d2f60370f6285bbaf775949075d01b8b1f05d0054384bf9e85d4a305293a610a2a345e95dacad1782f9465c5f5b6b7589a8619348a5cc5cc7772432aa79abe8a9b8caee515b4837e75f8724e0706a658a38390027e5500fc60c2f1ef884f77208b3a19a9b47c16e21ad7d922dfee062be5044336871de4c985a943dc2085b2ebef9453ee91738247aaa4c2e2c3081f0398b88b57ae7b6fae4c8a71e21b7fe6b75ed5803b339a8c5477f952d046222e08bc2855d911eba73620d1775a327fd1498e0de1f6f81bb892f0fd16a10c578bf8547c17ac7300d4d73a8715e70b9c5fc87a8f604a54e0cee58cd5168ac7fb0575c44d75706b922740095d1dae1164ee799529a232ebb98772643a0b559dffe3a75200abaeaad936f54fff8650b711f5b1e14ffc1d06dcca2c70cbbc26404acccf153f53d335603f87c99013f7bf1879dd6ce30f83d39917526d79b79bb6c47346a604f850fa201233bcac232575ffa5a91cbb68d9db1bc15d7f60c30782e87d10d60cec840080c7a85816f08d1354fb264a98864e5240b9c1982a830835f4c17bd1f7fa5ddd772ab9821cf192431b79579a6bd33efe612d5300670d27c12863b9fbe17d9afb58bb79a71f3b010c30f57c5549df74186345be1f6e95f55b41ae1dfeb663e56c2eb81f908c7f812dc3fd1e3da7a358a42710c300810cf71465e9d03e2524c9ec418b2fb71a36c0301c6b8aa1980084ce9a21f747f5668d069cf0bcd7f3f7ba5546865db599d5ece889f4ad453ba0efea6faf9ec59f66f46a40e0b6d2cc4637bca5ef2f9547ecf2dd2988bea43b3628cc4fabb196193e80c696227b554244400c843e0d7ce986f8c7bc08108dccba03b581924406bcace1500229abe52395dca8d6379274dbe0fbe765207d9a4da6351fdfa5677996ab1ecf7ad18e6dfd5afc39899317d76f26aa7f31c9ebd8d15f2792cb72c44e85f2e8b43b64098a78ed399d1880ef32b88e5be629de0b3079e5f331193413d6f39cf00842f57810f34e4e42e4919290a58a29b34cf73f559614cee23a7b41d56fc77e7f1dc82d65b38676eff03a5e51970637e4f6c258069a8dd9029b7b6ce73e71a31e53ffd51b8f5e896ba3bb706605d7981485984aaea9f358452209b109663824a4e785c60285493f9fd1b134275a7b8ee3459e1fb70404af731fc9f1d63e00de31c1677b28ead6229ae72c04977af6af4a49e21c07c83a4a8c0a939872ca846b149a2fbc494f9abd82fb9ff68e27f69b9b8b939f819f613dc1b8b6ebae864381573ca0afa1d8dc0d4f71b3c6efb3048dd6b14e99253079b9e0892741531993e2e34a8b1e93f50d4b5fba3601ce9c1ea3a8bead477a77366ff03a0e9b2bb994ab70e36faddd3edd6ef02bc8fbcce4d16c6bcca063152814f2ea4365e8c46876791b2104d9de964e18c7be25cd572a4315504d8cd9b1f5e986ad9e2eb059169ce0402e0af316cc4fd6caf322401f0b8396928866bbd13750362194cc7d659a312695057bda66019b60f872752b99387647376e9d368060cb0ce8ce1cfb0ffcb88f9a15fca45d7d31ae15279163513de85d1d724c716196fa561de9a7ae22953f49876311234c15e6904c4af0687a9192270211e4367c27d5551c0b2f2f51a2a64294d8998f36f84f6417541b72626615e1b159c714541078081fbe2fcb87d156be6ddd45d9d227c9d4b52a31995e4265a8337e547af430081f74f6dbd549928f36bc59756fa0a8d35568b6fab4933ca9a6c19a08c87713eaf2fd3cbf7a49f31fcd1d9f9d19b2fdf7efefac95b4f5f7ffdf5ad674fbf7ffeeac9974fbf7ffee6a9b7cfbf7ffaeab9d7cfbf3ff50eb89d84a4843059c2b0d78ea2dad6aab556f34fb03d5641673d2708a9bc916edd8d122ff2a39662943f2f8a24fda3471372785778b910b27f86837d7bd9aab555d88c38d5429a511a5b33398ac8c5a72082dec3103141d6af797711c23ba44a2359fdf86ac9478456f273b4fc7edf495e7510941dd8879474193c84e5982b9fbec1952eee33e585c26003d5f54256271f728fd8d86f321b53568830fcf298ca9872770d87f4660893ceb6ee069337903f8c5b8cbd51b78f4500cb8b2995795ef0744ddede846edc0b5277e3f65863125297e93e895f76beffe29ad745c215a3f27eb7707ddbeb00f8399da1faf168c2e124d97a03260ed63475f1d220a216d73a56d58e3db9dad0ea19af42a4b2add9bc8f16f96567feecba01774bad856fb2e027d7f5a11d3f04dd50f46614ec02978eb0afe35f10c3a9895a9844c1505264a0a0917fc1036933d4383966232aec8604b87945d8fda8d221403bbc21c589923fd53240f5f9bb0f09a370d5fb5088c761c701bc818ba5a77adedbbe5c4673cbb47a67bd1d45bb6fabad644253167311653468a7b341830e096ab010750a3f7acb2cb814286243eb389ad272d205710f85a1901d9a50c92d2b582d1ec47dcd4af7f4756832e34676c69e52c20fb62c0db6b2ef516d6adc8b871020423eba3853ec7a58a385cb51dd7e1b52528bbb509ba112eb03bf8bac4ce7fb22b20e9d61973c8170797d7b48a1ab73647593b4ce06e42be7ec72cd020e8f5405290c7a3fc9e4c023e04feaf7f0b0b570cd2e08a604159e0da83ca10a8ce5ffbfd5958f7542c57ace6e87e339fbb2eb1e96f1a64df20c9021f9f040fe5101121610be13c8fb7b5213a47adc887aabba27fbfbc2630639a1d55912642e6ce64ddfa74592cf32f7f100695941c8e214853a5b85a60f38c74e483d0f1a280b531c48cafbf712c1cbf954277026a52d9041371e3063da71bb4c483641dd7764c1e4bd2010e44e5eda836949782e559d6b86e79a6067278e1f960fe9fd1389c901e9c992d2ef6bbc735ae30b3d95a91759efb156c83725b7fb54eb972b677781a850e31a43bfcd037080ef0aac175d50aafdaac5c5177d27b7be32965aa80493f593c448695356a3f49c2cc649f18d3b8ee2ea5a71df60376fe615fbe91222e762292508b98f5fa32c1789aad4fa6d0b112ce1b22629f47c10ec11aaa8a72c190c36aa46a50f7353c4c194d18d4a4a09a927c022e7e9be763d8730a93ab73901ce1bcc381b1b047946ca28e7dd9e1a81fe60e32c1a5af45c8244770afcfd0a7ef4074bade1cb2f73ebaf58271d0b6128274b4d92cdfb6a1c28cb3a20d4726c458176d3523c7d6fd3f47ced0db8e5da370616050f6291b9cc1e928c97968f4c66e6531ab89a94688df6c9503d8f960f7f80bdeb107e114aa8e09a8f99c7e58a748d0959f2d10df7df0426c124de734f0ce9b72e91d0dc265fee3c17f88d4e350668a841ce51043fd39f860088e9047e3f1622f9000ea1f72b465adfe6b3bcff8e10ae54b8a4e2aaee0c42802c5e875900b0f9887f4503175607b51471816bf3f4636e1eede6077061ec57543e1a0227c9e62ee2c5cf5ccc201afdf15214187084308dc0992c37bc680ddb083159ddf37161a175d285d0107aa378ba84460cae3e88866634109db3e82442dc7ed5f38f37c8e680a5dec6575de0341a7cadfe9bef33b9bd6e4e70d08c34d8a6edc452d4019b00bd118a56e9d55fa650834f6a9e83502b88d9184053ed7bcbcf436332025ee00120ab3e3c2f317cb02654abb7817f16f0aaf7df6edb5c7b39b93b1f32c19192d61f2daea4c59fa15483f143467a9b5c907434bf177d0649ad8b1369dc8b12f9290aa26ac8944024b52c38f377ac207f702c1b955a6c933fa54dbef5d609a181ed91c4d91bc00af598fc45492cf8ce7e94f790647501730fe6f2842e7b637df61865f08d926be7a95c93d778502a705abf9e474e9967d59074c92e9a5855941d7b91e88d1921c100256ccc3a7e01fd06c35556eaed5aedc544fde5d9532184d11919a8c149c25fd37a54ec808f6c30b6ef3a067efd6076d8ff0bcf7b2b385277119e0e64cf8d92970f8964e36e7caf1b1721cbf09c61cb4364f559582ed162d684e8f2d6a23b68146aa0bdc0038f89b6c05dc604547b527530bce3731a4587803f77daacecca574ebf59a2a45e8623fd55efc920ab93356a83c5eeb0add0925b405c3faff045af70e3d635fa86bb3bf8820e653254ca12009976d36d99fe2a1e6bd09930e040a49beb41e6f93e157f4e32a63e95741a262892be9cac7d9dd98d0c18d89541cae5e2d49efb083802a568c337345888f05cb2cedf61cdbcaf947e5f75caa9159bb14eb23ec9af1f2e6cd31eb33e4fd6cb40f1cab32383c0020a8875a12cf7a14165f9d26b72ca37b30b329aed9ac6a6c113071cc3b554964a90f51147ff99bd0f9ad7e2733556bffcbce549f9b61487d50a037eb0525dc79880ce62760ce9c04d8818530a21b66de3adf4cead08105dcc240e3d8177de4f2f3de529c011cc1009dda8da100fea22121e1cedb67a529c6ce9e622d09f5a57f21827e2d11a9a867338a89290fb7920f5a1c6b74689100a72a7041f70b908f2b710f91d8c51d10c2c32f618b29add0633b1ce1df9ccb68f96bbe7a165117062059aab5952149ed5d761f19a49e042cde7e1c5c463f4207c59923883d3da4f6c54e157a3e2a726408a879d8e55cb6d98866abad44ae46537f054806f37f9f9c9e52a182a840e963545a58c73af0d448a751a70a35d55a768c62abc547cfad18dfe5a308717d5395c111df3bbb801c304817fa84005b4a8892691bdabbb6398e23d7aaa55ab5a075eabfadd4c6d496558e074cdd8287a05386c1749168efa3635ac18e425923593eece5c682cb8443e36c2f9bb5b1e725801803ec047313585f852d90ca56e64a10602b615f130c6e742dedf2143907b8c2307a04dc209745e06043ea4e75bb579cfee16cfc33c08d8055f3f17422e6043ac447183e185080426e60a62da5daf6952b7ecf543ea7ce80353161204d316e62d84192c0b891e883c11e8e7b5a4bbb3d413cd834814f448daea0cb52c00b62ce0b0e46455b2b988e5ab8c3ee9aa407f26e52d2ce1d54806cecbac63ec1d581a2bae749426665292a4f9d53800ff36ec2f666e65136250d3f3fa4d660b03d407e37e13ab743ebcf86b9092323ba166549af3831312a0fd00d4e3e2f83ea90ff058e117987342f04320cc214608b7388f87747d9404bf444f05e2e2c5d498e68720bffa60d37358f42b4d854e7ebc473012f9fe0a19a41c2fb044a22693c7fea0f8cdd293cc63688cf0c1514d18e80ec0f53519ef68ba6076419a91613e00a19acaf9df9645da054393604c5d59b63da98e6277c8334fe8217b8048043a09aabd0be35a08be89306fda4063f728fe7006373cfedc4a5b8a614d24841d1c93d430d8b24ee870b2978f136672d727b00c3ef7a05f820491185ad04ebbf821aeb462e13a44a7a9ca6c393c4ed974156f5ed96d16ef5b2e79d91fbbeff1079be77108b80e0b1e31b0740dbfb2bcc1411400e1b8b700de76fc254d428103b98fd735fe6f4a6f3bf3611afd04efcaef00be5eb588def6900f9e483e44e2dafd47ae708917b7583727ee7c342dc676e9e67934b59f73eabfc7366055e1b5a527a9e7990858297fe55cdfc7e9eaa9e4b8ed4eedcb3aa136e6dabeb48512b92dcf1e6e0e06683bc5d4e416a46cbebb4c74101116b758865cc3eb3219012b5cd4215392684e6641e6e762ca927713aa1bfd436067c86cad18aa58f1e9e44668de47cd79fd50ef642548d747c0a79aa7e3113ed0ad8be2bf42dc6d233634c6d441ab18a917036e27b1429e29d00a76da945dd3900c31f2e4652d6a51165852e73662291117dcf036f50d1cce5f82beea3b80105c65537beb6b0f834c64c865b0cbaaf01f8802434779f79d84560c644630948dec8364725fbb63102128df2dba9558562b30f79e46416c54dc93d9a6415f9fab5907093b2bbccfea6fe1862f7c9e940d246bd8548b93ffb46e7de30d53c1fe50864ffd896d909083176852c4f1c0099c476cf89aee3e88fae4b3fa69bf777c4bd0605ee919408eae02fe8c6c3efc053c615542a6fb5616d18f3cf4896d30d45b25f7124d0f74cbf779eac403f641b410d3f0b9198363e70c4aad5f1af783224da30e3eea2da2f3b960a2863214cbf153ac2231f4aebe8318be1018149182f8f7005cf605eed0112141deef6818308c6ac919185c27a7f45e8ab42ac4afcb6455a5c22cd81b56e5ba88ec869de9a077690928ddfc56f14f2e68a96b173c45cd8d046d3e811eeadfa7dc72fbf35cf918ee9a6c4485a1e1d92feada9ab9fb4c6efac9e4aef6a78ea6865f5d40eae70604289ab4c0e3f143b8d41d7d2447ec6e5577c9c8b95d3a77a7b8cb4943a06bdd79fc620c3aaf98b55fd2409fde2e8021bada2cbbfcc2168da135628ad5ec0a3c3b76acea8581a6424824c0a2925f26e3d1d5db183794fd1198087651af2021b4f3614cf33b59c94bfb5cc4263eb3317e683e3231a534bd8aa53b66f3134df5e94dcf2f0bd80d65f7fcdda6ee70765f9703b9d2b0963cdd5dc0c01483c4d4a3e82e46e904ea1c70715380904dc34a13fa7ae3aa552f84121bcc86bf3afda8a96291788676c70b05340eeccc07bbac466e85808f9a9f4ae05fefe96baeb378a72d30678ab91c770371ba0681ce04724b955ae91e489cfbecdbaac35171091c5de3a40178148c0feaacb77b5b5abf0d9b74a6237df56c08a8d3c1869a3aeaf5272ac6207c00f1db896fca4e9ca71b4f68a231b3a574f3813581188070cd5e8ef59ae404915a7c1cac34ad09b9ea2504011472224e14cfff1b9b370ec5206e366c0b058d775167dfaed0f0968c56dd0041502525c8f4481470c20379c853974ca6d27f70d53906268c3a18dd02ecb2a61ca84bd66dec431a0a7f40460e3ec33fe341e25307abeac09bde500c34c09996f7800c5d69db11f3c199da0097f9fcc41b0b54a0f1db3996b7baa01b6a6db5a9bcd08b5bd46a185a27e01ec0456db6b78439fdf6a079593ec7deac894bdfd15b17aa24ede2b7ef6b7f94b7fad9e9d443649f7c5313f40215026debdcea02a0770d0b1eba148dc68a3eacfe9627b369666284e3753e34ffba6148b538a768c8bce6deff039058c4b780718d9b0751efe8d69813c5203273a7a8a71cd7500e90cdecb951c18f6704eeb78306db3ed9671513a7f97b5932b98c5579c35e059f2552c26196dd29eb820fbd2b6b82a0771c5e78db6f4c1e64df47a42bba135812f89a41414cbdde04984c6ca7c04fca517f934db422b0576c3c390fced62c5bc4d1040b54d9d6907a8136c47884df89ae7730eb52d839206dbc00416a089be98ddb4b091c1117bc83c5f299adf5bff6156b2077b24f6cb0812d19775b68703fc50bc2684a08bdd21056d21fd4cfabd9ad627af37e7c547179226c1b34d871538d98f04023ff7101c0aa463bfa5dd7189467a480b069e016fc25a407ced5e4de819fbf075824754ad966241742b82a2d242140e1a7b86a847b916d0707bcf077b2ccf784f3e7c91d80bcdddb4223663702269bf70a761afe7f97f267ae67dde60a470dcab61bc1f74aa9d10c528df1593ce139970160ea05d07f4d487364460c10e4c0e3fad55fb178d236f8e1b4a4b22bd181d8415b78bce9770e0c313c2bbbc51090c46d158b85412b83b704581a0bef6f5cb49978c155fb08a3589f68328d3a4164ac1d61c4d1e85e4f5fdd05d6dc31490c13f01bb8fce72502f5ab4b18d25ab5fcbc7662a8ce19bf101c19aff7fe8be562f2e526543173b60554394bd38c02597f4645504c5b2ae33edcc2bb5e7a5c6b2822767fe1397408bfbb92687e04daf8983efe6ffac060c37c195ed46c780312dcf9ecc0d07bc162702a9a7502a6c097cb8d142115bdcaa8b3c917e89ab6a11903714e9c85821e6310b8fafa990a2c60d7baec57e73a95061d1c9b4b40d0ba5f9d12c628a9e597ee02551d63ce70481aa0c11ad2be2f53a84a4bd0ff9d13d65ec256bc477305f3a80f9112dd962cc6b14c2a502373ab02efa11961018a23a78d08a9170be4c7f7acdcae0373eb3da43f9b10511090e51194d066901288b7893eee3ae1774b845d3696f48fe82309f633b0722827d0161ea96559364fe7a2771fc893f1b089238b58f2c1aebdfa5f27cdf014ad089775c0d1ca96fd8ea98007a74c8a6d65600a628de4aa9a44806a750a681194ac0b19f3fb9c0d289d64f0f4cb44ef6c1596a3e50d28ae0867b19eadc545dec5d27c3029b3e7d5ded7712d3171282dc2800f27bd00208782516064b467aa0b70be80119e33491b16883b5d28414de6a5c9e2bbc3842b8135247347d7cbdd9decb2c649e896701d2aac742829c4dca12cb6ae35100e265579f926f92298212f3de820f9100b0c1ad67ef6000486c11447411ee1606f947c2788cb813a1f215f264f74ee5767bcb72de8c34cbc82ee19f552f0c13f189ffff63e18b9c9772a38c9fde04b8a3dc3cc11f51912671d06e50356b98488716f9f104632de5cb9a5fefd597de6ff9c9209266033f1c5c4a9d6a0311d2f28ce29a9cc9791af062c6eed17e9fd0e6a66261e6e7538eda6688e7a162b45dcfa4bc8b83337581db8d4459897f5c12ff2d61478fda498bd8f9ba35c926c79129b2329421ea098974efb35dcb76b8ed687a9653b7482c7efb0918c998e41818250b31650836950a6a38c83305a4590ac83aeb1b30fe109502738d31afc8c7250f8a908c9166cc000f2469559548a2a2801845c8e4c1fd0f83d3236d3f6bb209ab5297ba3de59e83e429709862e9947824dee24a88317934b7cffb232a34df9f47eddf68336c037d7255497191b232e5fd00f07e382c7b9fe127c5a9502a812c6454257e491d505aaa916d228f1b2179f85ed2cb91b759d50de3aee59c76b3bbac2da26cdfa35676538b49948da2122a3ff95fbe1671b29dc90e94b40fd732d74f04a2aa1f1061d5058cdedb74a92544fb708fd96f87c83b13be20ff95a1b27ef2c8c9893c10c76ec730f3e3f5699604483d10f64700d92580e64e1c67411db0c73e2f3d242a708fd860808d5940178ba9938c86e184a4e33d3eb5a73dc5272de8d2c2d25a1406964e969bb1cda417671a9b7dcc0f9933b41e2703bdfa018b3b882a0499cf8af620e9bf369f05aff1f76191c3518832ce7a9993e96febd2ed07c91b4d0717aa11d4b5d673f180a8e68596ccd7e3061f92e0ac60e1eb923c6f254aabda92f89c73b612f296359769c75692647ba4dd51465e29c55f655cfa628d27a99c332cd049f072fd8288f218f4ace7727302a36a9be6036110ec2d818748e2be60b34a5294e33f31cbff4448c577c5ba9aaa42674f3c6622f2acf5f6c95333f154b72c828b42281094a282fd526f9b7135cf46563d80ebc6f82eececde787bd7f0ec4a89d0ac406b6f711302f47306fdf073466d6070a37fd469eda76f408f269e1e7ae4089801042f4f936483e08c6ef8e5d2841811626386a18de7cecd95f0fe3b87c00ebd0ce9b0fee891ee9a2901ee27559af687b7ee59a1a30bcdfbc203a0311db8fb715829f7c58e55062f3a30f5e7c4656560feec83fc20b411fda1247e4b59ec6c1494094d85ac19c85689307cd79e35a554ff9ca824d2e938e076c3831a8119e0fba4f1cdfe50effb9ebd1c5462f467d02222fb439d8993408a936df018c2b123be8486e209c43c5038253cc8c7a94d63a6a7a24f9d88655c368f50a2cda8147002757e010b0c9b33291d8742e1925cd0887b0d695b4af7083239734f9cb1e04f033607f3476c11e20b182d5cbc349690d84773c0bc5421f1a5482502ad89a3606ee5f025a50493917673b0d30892c933458d725e89339fc18d463712c7c54252748880fd47637d65851a8c782e23634ca10b0e080901b70a9dc81fb4b6c7154af8ae450269cf96295375c2988f4bc425f8683b4cd7f07939d2adc5e3b9fe686f3d104bfb38f1eea9bd0048f16cd7ab5f97d3ba0969d3d5d70baea9c9561f0c1f37fab02ab0ab5441d82a19c30e853ac971d590328d1f2754e5ea30c703d1f68cec40853f6321887fda5c53f90a551cd41644d1daf2a6b5a2ae46b38d8ee2a735e740fd983410717f67f6251d0512afa4be51a05c49d8377cd0b33fdfe799a4dc13010fc795ee0c3b153aaf10a7a55917e4a29dace858d5d3e8dea32676900135fe2971924f0768ee509fc8dab5a812c0e77c8072f6e01d7d20cc2638da1bb02fabbc7c13e47cd5453612163a14c34c186a22520e6771ca0111e462173eb2ab4e24d592e2e60b04a34f55d9d20122e885df83ac3b711f7742db72103c6c8b0fac5ab04b76259025618fb2ac754d3f7c9ce9b894c591822b87b76246e8b7619ca039443a741ddb06ce07dab0e09cc8cd2a2461e42633f5127526a94f47c13e547cd24453a32d44d103f097a603d642011394e75adb4962b05104d230c3295c021644db6d1b950652103d9f34a670a7ea89c634b77764f33527a67fee52b8cde45145ede39e2a5bd983c26d04b390b97cd586f0840c80445cbd6aede0e022d5e0490b97effe21c51eb5ca0439a98eb76fd6d8d80008ab805fb798682f412d940ba865b4428cce5990a33c389651a2fc702b47475ab81590323f7f57ad9780401b68371388503ee31d5675f92a0dce7333a5f5fb7bcfa4177bf8e8094121825b65f8d564c9fb18dab1f9e29cd8110e0a40b2eb7874d3f8a732bb1edbe42d44c848458c1386f6a3eeb7848f38ab606ec09f7c545d6d4641c1bcaa8531983952be6bd92eaa15c6df44d8f72cc25efb3306cad65aed98c7fa399f8d84b1770958422e241fe4b87c83934dcb21df0a4198678c02967f114b433ec9903cb728946a0cabaf8df0552982ed022a6a3cf3f5df233c1d8c574181d752ce295ad05a7cf93113c84e38c698b60e438f4dfc3c29ffa171e65fa7455533966f24af9fbc238d7e6d4f9cfcdcefc3596738f4ae47c8077d3c4411eaada747c08220bd3e3d7243b65758b4f7786c9938358c4e594d9292331ca90a1c385bd7d1c03250b44e9825fb6c969f0d2cc064aa1cffa6584e034fb3df279a360a0b352ab1622744cfb7fbd819851241df2fc6b3e59eaf07f1f6729660da49de3cb6c93f4a7d7c91cca883d47dac072f7579125756c026731dd7777fbc3485e51477944ddf581e59d896d252547269ca72d490260e7cc24e0393caebc2a5897b000df1366db7e51e152cfd5cdb8666630c3ba055804e2f2fc09cb1e3a521cd19c97d21bf7f3e10abebb73c2077910dd913736fc916725e4d12f2e8425be0c9483c9bfe28de951445fb3f6b5d1ed0f74e4e22c7396b98468379e12e4c67cf10b3b620f82e5d27aa6c90a580e729174df8bcfcbd24c5d62005b85874df179dc98a4bf80e65dd708f9dbc99367c0ceda0f5f600e005b6a3923e81f2a2f6bf02f389a6e6e9ab2a4131c5294706fe2d5aecb0a0a9234f8859143eb3f0a900fc2804cf6e6b80be17a86ea366a571c337facec17a57ab3764f90b50b3fd6ae7fc5aac4ee7e9aad4808faf8117f0e59c5ac27d8795a89fd0a25b8d2d9ef2fc06c9f8e773a2d09bdb39a85966d2037ae37165af1b21d8e831049c03cfe659c05116d458991cbbda61bcfae8c22f14aee7445a7504fc2afdf55dc4d13bd5a6fa5f47eb487358f1d1e16005ef43771ec35f982b7ecbd80075b1a16523ccb30047400f4ed00ec064ae2560a1a067c6564c95f4ec56e05c27ee3b1b0ba8d3465f9065a650470b8f95b9bd8f92a4355e48e3587588c2eb3d61900ebc2515daad207c7d1ec1a22d59ab20ba423bcd5031ade32945c30903a4e072a04cccf4a6966c3b818a3e8f92178c3f5f88fde680c75d4ed499390a4d9747286b761b541205580aca20f210fdc3f296aae4188a21c82a6344f41ef11e364f3e61a981df13edc32daf993bdb4b677b72de596522699029d08cb091709f6e518ad53dbc67c2e1ed9af45b62319c8617b42ea7ba750eb9ddf9c331082ec7340ba5f70c15734beddda240bc826348e7c05740fa7d9e505a1e19e6bcdf47796ef7b279369e3e8e8339f510ecccfe8b3d6cc425d6f646b74e4984553fc8f0bc7cf74431db733bdff78df8b7841ba373d67ea28e54e3f3ee7b98db77389dea7f1a3f832ff5b388a33e19509430ff371618bfbf16e9bf74750d97bef2ebef7de3bbbdfbdf773eebdab7bf11d69beddb790dbdddb9dbef3be0babb49e901bbec03d6d4f883f3741fa1c583729da97b2481acd3c6f71de333a0e9913627af7259d82e9efc5f8fbb6edbb79e98e27f0386341b4753a7b8f8a014296bd7720609900b96540fc64eafd49a3941ee5edb96dfbae28df9ff34ddf2f64b1d24397fb1e8226f93b11bc1f1e1ae94218b890c7b66dbf85b248c6e312e12e3705e8347012f9744d1afbaf2944dfd8afe08c02ce20179fb48dfd0d9c407ee44844640be647693665ad33f3cfbcfd75fbdb6f3179d33add6fa73f82e23a2e94de8f24e4f6bc97de4b0fd5469ef724b88a7baf47f63e01ed7d4eeb74ef799ee779de7b9e870a3d211ecaf3501e0abf45fd18f32811bc203161129951efcd66cc84a7a3dcdddddddddd3d8777829f40103c21defd94f7a3001bd879babb7bcb7d82e009f1e9be6d81fd29e84706e85c829e4de00972d61b16c9e105a16112996b08c30b48d36960dfbd70dd6c7d983b40e747b3185db2bd7dda7215f73dc13fd97e3b6d92edcf32dafe0cd33addafa46c9ee12ab73209cc778467976cbb233fc3e3e9af6d2fc8294c22332a1cef9ffe9e401964f6c217b62d781c612421fb17d95e0a8db7ff82ab52f7fe0d65942018bc841a6fbf0379b44dce5cd50869844132432f0420a1b2a552b6efade4a2ed0e1160023be36cdb9663db36d376c3f41b104bb2aa93e0bcf733819d73a45276366788c31342dfe70d2f051a524aa54ccaa44c26bb187fb325655bc8e574ed16a98647c6914dbaf9b66df79adec324f2c76692f9f722e5d1d9e7e105a1c9b268471198e3d169a0ec6981147c018401890c3857a06dec53a06facfce62a069ff9ecfb680d2fc80c2590fc71bfb247539f3992ec415fc479117f339fdd997b7dc685a31f696192f007a5bcea4cdad3009b35c19975aec9b4e53101734ed98c39c6a921f3e3cf7cf0f313d03d3acf1e79fe07e08c398d7d1b60bbd310f136b37533e66d3f7fec661657713f697841ba3089cc5e3876329e90edb93089f4998b76f4996cdbe286a3bf29dcb62d09cdf78fa0f27dcd14dea2a3eff215cd2011e7c5ef71bbfdf93da7e95bc80c4d53f2e4d9e9001283f4914d7810912335192a9a4bae5dd0077b426698444aa02019248364d0fc51fbf948a8ed6ced7b5e10ade372ba695ffc8f7d311cdbc1027c39e96a1d9974f284dcf7205745912ecf4be1beffe8cd7b319eb9cfe40f2881c06ec662b1fbdd8ffe5d287d8270a004923f3b9ec045bcd53addd99754fb9cd691607f469494a595edcb9e23587fcea68527bf5ba786334bdbd89fe08cb9687f071669dfbdb4ce7dfb7fe3464cccec1b8e31e8c8a92434fb1f4165bf7fffe6f1feec467feca2e987116c0a8d70a10472d1ca9f6d0b1ea54fb6d2c755a9973fd6ca5cb4394ee30fbb312c9bd9d98c878b5606e7f874bc2cdbe77874a6fa13a44f039c42df2f8833577ee434f6c1b4b5d66e333c4efbf6fd680b32431c76a0cc5d4f57e3e1fc08131c7dcff37ee6297a7892e57b2ccfdf01058fb8b725b249a632783f5cc8c56ec714d85b481f7daf4ee42ad3d3f9ba361c3176c105eb2e17bb1fe70bd63a528a2c3dcf01f3bd97ab529a17a634ed354d0b3b300728c3db2b7f350d7dd8161b6f18f1ffdc79f497d4431fe2da6facc0e39cf9d2cc5547bec2ae1a292c6baf7de758ab5bd23ade075ae784fad3e93b70449d3c5066d3c934875c149a2f2b4ef3b233a96da8b5324cba17e3f9cd7ff1e8bb7c45ee599ca80a3cce574efa15fe99e4af23f28c2c05ff6bfa6bbed83758f038936490793e99b309f4e3aa7102654a8196260d7dbb19e17102a5fa490a1de44bf3d6d01be605a1c96e25b5044642b39c3f99bed31f17e9bc021b992fc37cb9329d3323fe2f2bae226a9d2badd3bdf75df71a387ae128a7cb45dad98efed315c4a7509221181e3d2953fa54c85529772b43ae5292afbd9c497226c99924a71557cda3d7f1e57021777927b87daa94c5c5271268f3975b71988b94c869e8d3a3eff2156569c5002bb96a26b54e7dfa138cd6f137325fd2e71c3c82caaf65d7a6e84128cbf7973f933c0153f5e7a76a485f3a7d8e3a954047aeaa99e2fff7614ce7cbd7c2d4a43f93647772f7ed86456865f92fc9ee0ef09fe13ca23d063f6001b6468e68a1911962f7ef6850e7dfc3f71787d4c51bb8c65ff1fd48a881d6a00af41b04e2620d7fd4a74feb0f9e5ce9bcd19a6680a6d24aafa952a6948e3899e2b848bfbbe9534a29ad956a9aec075806a2c237efc5b8418bb72eb4222e760dc32f6e1da9d3fdd7fbe509b8d6c13940cc946bd34ffbdcc86530a6a7a690bae83c441d8ed38231e4640ce4e4114836d2effd08247b395c8d1fdb48c7f4352600593eea246b745f5328c3b1bf7b1f33061c0790ed6310059eda28869cff72b858bfa6b22080205a0787d669227d6a1359e629bde7fcceb2894a9396b88a888b55fcff3e1a253ca6fae5cf9f61aa654f520040c872264b1e59de64f9ea9bfaa34d96a3b7bdc9e459869f04457822877c49f99aa0b4d2f31b94aff9f425ef9523d8804d9f9a8f846e1ea6e60c4517ebd70dac71b1ca7cf59e769a6bbfc11107c7c3cc998512650b33759c17842653ef046badb5d3a5363529ad0ccef151510b7fc8dcf3ebdb2afb31caa33862166a6d3035bfbb3376953fca637ca89aa66955abf5ab875a0d02d75a6bad55d3ea089472cb7c00e3d455e34f2cb7ec0796dd9354bac4f12cdb666b1afa94be53fab76de8ef7882e9370f1d3934d32742e53cd51a36d09d5382c1f58e2570cb7c78e596f9309439efbe2e9d85f636458fdb61991cefc323a775c838a345a9a46966f26492e5f454505a4a72f1032f8d0c220c1811292101164354a03c41bdc0c1dfbf0eb1c66a55d32ad601fe20b7cc6565071847164b18476e99eb0b17ce14b547d3344d6b2da66c4ef444f1f38dc48fd6aac2897c004193b70205b74a4c192e28c10e540c5d21c309ede8c3628a165f5c451031744ff0840c3045e84006463011c62a2140513e4551ab10496c096201d29208907e68c2fa40850939c45e375072420c1098200c9103b020b9b0c860882d624c68b3245a0879a14589a12ead12ece089ecab0b0e40af1a80c0041bc85e5f4ca8c1d26b4904b12a3c3431a10b2015b84c6085167826b7ac8b5717433580e5f1717eee66abb52e6b65aaed2285b55d5ed0035017303c78f1ea42860f4b5cec00e342081d8020c1b8484207203700e2e2091e807831a406af9bdc3221a0d30d335bb55a654e6639c8da444749333ff8e69639b9411e711054e0ff2101891e234cd025064d58a94225ac0007ca0f0a8ea0444b8af8699915556a706ce49661e1419eb9655638218301e49621312577b9654364f9b4aa69758b171df4ecf045139f9f7ac596987605148a3f2c8331920fb58a2d39e061cba38c4c0b594c6e99162ac836b74c8b57163159708ddc32295d84b0965b262507d80b0621b74c8a183486c0a9dc32570f3584302ab7cc356548144b34b72c0ad7c52eef4b0fca09265d17b293143b705e2c7958ec6002ea94b80062eb6288530a4304174966ca8107fbe5b539f141b3c1eb0afd541b20591810465bf0d0801b18d5c049036cd092896146100df0c225db819311340069e95bc1494b1605073215b4668a789c80f2e5cb95227ee84189a1d90315cd022524b01265298c1e88a8cc18100991456c054147566810c612da92971f986859e10227ba68c2e4656700861158e48004508aa67841c4a30409bef8c20352bef0008cd0c745c933d1344dd3b67c69c2e384043d3003882f5410450a585a8b0b914c9433961c600b12378a40c0858c2f8b3058491633c0b10515980b0ebc2d53d0303112e3f4431326272646583ea8c203415c8664946cf183238ba01b4c5c00c6c7c40634b2a8828d66334c8ac4004149092bd011022545430050b265875416586ebcc0071b379051e38612b6d82200215062e444c701b450e22b0281163ddc506294824ec9164b7c4cb41823c5a4288bb0a8898e2c70f840c90b90985112562e4636946c198386122c5c8cf05620450894e412645faa907d11e24b131e3954ad56adf24cb9011058ec20c6183ae8c1fca26ae18982871e0cf1a089104956d01e33b898d9b0c5880c2aa828217b410f13498684908c8b0eb229b78c0bd2152c332aacc822092996701ddd24aafcbf9488ee8f1f07470bb667f8ab04a9835c727da6c48a1b6411c4911322aa70dd028fdcb227b1217e72cb8488e516e4963d09937f89a5ac7d6ba112cb5a2883e70d7c799ca1d56a65193e55b747b5afe1a8d5d0487dcf9daf7deda9083dc0f6b5d048fd998d6832aed2b42c61943580f31111b2fcb1861f76d1592dc0e3f5d1315ffe93d73d4ed06627cdfdd3d4e48fd3ccf9a6cf3873bce1bb4743e913058f3208f7e7dd90c35de8004a337d39ca1bd2cdb523fa6340ac6db5de9f2bc0f0d98119b4522c4843d75a0d8c102c80d24312d554820e4b62ac2dbc74dbbc13e6735cdb7cf9077d1b8332b260ed98be06ef0104605853e6f3b0b80d3481ed9d70ad168e35e0a48898c094691e915afd4dc897e597e5d3af616894b2d91961edc77ba4edac317ca6bb793ae09a43f54873ad3b591a91c185f4d370d4004f6b61df79ab944b604ebaa00c1e72e82fa6a8e04c44703497dc300450ac052c8eca1f58e0828245c1fe620a8bab578e382288c5695984a088c5d98e080c122c6171b7932209252cee76154c11a93b8dc516222d7674cc8055abd8e24b128b823a66e0ee617060f2f439732b432e36a17d7ee9c5fd72b9bb7cadb5d0a384ee4a1870a56cc465c8a3c9ea0412da3252f270dc365a8bdfb7064ff185b6d1de876bbf030b1e71d6dee7476a6f240316e81e2ec89bd6b9af3dd6341f382ed064f9bd2306523ed5ea532c83680feacfa7df55ce39e72cc27386dd0bbe6aef1d50707b42eaec4ebaee50962f19e434f2fdc845293f01b97f34803c81decdee9a34f2b57fd93a6e18ea70b1861368fab89834573ea090500485e3cd419bf664c1e34c8acd2557554b655a51eb6c5ab48e897b93e93570e4c251d2d7465fd7c2acb8982dc541e6ae1dd2176c4efcbd58f3e590c9b267ae682cb6430adc547ef773d58577bc4628cc456985c6e8ab87be640e998ebeb27cfaa2548af752ba972b2fac9994f6b48d34e234e6aa2cae9ad6483f7df9340c2da375b637fdd6bffd05475318769e03faa9d63f97bc20fdf4fd9358f0a5a54d5c94613e572438b44e0e72459328ed610459d222b2b768d25c512c4d235f4b96cfc54bedc9f23b8fc6da46fe8e20ea4fd2532117a5ec3f32f3fca51aa6ba73b1d5e4757c39b04cc7e375fc742f6539fa2c4b2995602e4a1924024df9da6d3571556f30c03d85d436d2affd0591d06cffe650128529177255bba4f384222e1ed1dc4ddf01f4bda9f7fc59ad911ab16d3acc7131c8cdfd31d89c64661c3c96f019356296f33bd0ebeebedf55d30b9574bfc3c3eade87746183dd8156a6dfbd0fbfe08d0bb0f41153e3e2fd9aa2afbd092eca57a5683846eb5ca06d965aa7d61e792363681dfa36749730774918ed992f6b4f960d933ac090d0fe22cb26372ec0e31d3b4bee95cfee5c29e169c1827c7a9678c08616eb033c32727e07f6a459752fbf2bd8b97b09990a4ed3df320f470723270fe73bbae05a87959a6c39e94b972ee7eae3708460846516d9633ea53fc12b6fe6d350b682be1c8c93e928664a5d9cb2556ba52edbc6fd65b565670839be9f93a1af92dcddddddddddddddddddddddddfd5f58c9a449635fce4eea694d1c37be0fdec6cb1999af41e3e5e3b82a06a3fef4f27d9800448521445c75eb4a04151512827be79d8b3269aec2b7612887c070c8e7430bc23b08b405dc3211b8f2975b26029fccd16e0343780a6e2f02f85f412922fc05eb6be07d13a83d079abe034fa79898af51e3674099b761e33ff083bf017e8f03bcf113c4f129707e0eb07308efc3656e5339ec3f28959cc6e6105ecaa6086f5fe608672a1cf1f470bcb44b8121bccc384230c2a3944bdbe7f8711281f0e3bc9253360728330829104000e173a400428ecff11e662ef1f98384665fc2730543d3f8272db55260d3ab751b58730ef004ff1428955cc401ca1ba07ff63fb06f03f419d07d6440af013a903f71d17e0ce841a04701dde542a00fb968bf03bd097fb915d0612e5a0b7a16a729babe348d5cb57da6b7a39986b47e6fa61a1a714adddda9d322bf5df091fb92085a3220926aed524b60eba1e012944a760b93e4a2955fe73571b2b3a560eade0de491e3628cdc1105965fed731dd3c9a49cd43a3f128c5ee14983c7c8d6866cedb59e8381c13d0f71680cf732c9554a4badb37db3591193a9b559a1f9f40c524ab9c477a494d765fbbd57debf2ede1f5ebe2f1bfcda467c01a699cf01a9a467e8004fabe8fd2b99649fabef62143c7bf779a59a77399917aed034fe1d172fd987f4d2b5bd34c3b65dab3d09b2a2f96cb37abbbabbbbbbbb57a9c574940face00ac6656d1d1964fee10968551df297095af4c7df73725bdbf85713e070e83557f762fc852fdef08269585d33ac411e15dc2ebafc5ae5c72b08df577ee22aea9a567d7ee69d330026f86a6bc9489c2c25095f96defdb28b5cec0c4628f7cbed8cec46dcf470d34387f2bcd309851231bedf7d3937558eb8a9226537c7c90dc04c301e9860b3c33e31aac12fd8c391d684c1212c008ca4de62aef26dc9b4642bda9236a42dcc66b41d6dce0975ee9aabc65e16a7f12da6d51081e96fdbb66dd2b308b0cd374b388b965e7103681df99b7dbb34575cb8c5b67044e52d3657d68b4dda62bdc8fe1636697c8b5998bb62631b2d657f2e0abc116d587a8bb58efcbc64dfb8e46c5aa8fc61f3166e60c02de6a23f8d173c755a8701dbfbe7c8b0472fa055d5cb5b38d62859fa3cd9b972249ac6bf04d9bf4a769762dc622723579dbab8ea6eb12d6632559ffa5381dac60a2cc9cba153dd01c8feeef2267cb5b57c0950f6865109ca0ee4c16054aee4d185bca7ade4e164bb9f2467414f28df2ce102380e1ee0f1cb2e9764186f59d85ccd206965c95a6b6d6e0976163428cadcec245212102329b4922ca20ee632cbe4ac5933c828d967481ececf8e9f76f3051ee5926de2256cef6f7b5a8b81000de4d2bb19f986520bae911bb6842b6f60fd719a272e06d528ae98201a7cb2d397fe6a43ab4e482d361625c8fd74288333d93b41fe0e26f0789ad500e17133ca8e82f7a3db663c1965d736fbd44361bef65c6b9b918bcef9c625fb5329e9a5f43473d1a987c266349bb3a1142edc64e1464329db09e9843457a6b7ada3790d41ab6a00a96a04d1a2d780229babef5e8c371990ab2a0e2dcaf7af1144952c7fac0125fb9694fd6de4f1840425fbd75a6be5218f35924e48d9bf46d25c7d509ac6fffffb30ae31d43592b28703c8e307e58365ff5ed99df5b5e6bd187fadec47e419b2e7490af73ebcbd08388b0b776a606d4f5fb582d507ac3f3e82a454320dc74d36c1fbc950660c4086471757a05f3f02f33da421a4610a117f1ae6d330d5375adfe1f7e5662d9961d294262a80f202a19e18105a6eaedc5cb9b97273e5e6cacd959b2b37576eaedc5cb9b97273a505259686904ad09382a0ac819b8fa0945a5062c94bf6d3f3a5880f287846a6333703f6b08209188b93dd0c2867008b818b25033a97315832e04e6f118225f333e04e0d2f66603163d9d8a941ce58325f430844b066de06b85383f7704613ac29618d91c6d7789e1cf33ca8e7c9a7e7c9def3e4ee7932f73cd9f43c797b9e7c9f27dbe7c9daf3e4fa3c993e4fae610b438935f31c0ab0ff0cd8f908f269c4c8e609f43ace1425cfdface4f9162ca2a00c48bbdab011f60ca6e15507ae5b9092454ea72de032ab2fbd39ebd349bfd6494323f43d07f10f6b5fb391fa32557efb701a7ed2a50c63045cb74082a321a02117093d20982c259635450334cbf716acd5fa020b4e83c00cb6afe1ed7e5a3ae989527a9af629c8bdfcc1c9aebd13acac3fe98972940af9e7e67dcf4b00ae18d5b8b53f85e3f6d745cdc8f6dd778a09719fb8af6f7aeeaf7782f71ceda414ffeb5f9fd340fb0e12711acd6d38c4458d07f8cad0878bdac90793d0d413727f8e32597b0fccd17daf4374713e76d5164a79b37c9b8dc8af32d42ed5feb3a67daee12866196aae9decb0d0217fcc2cbfc1115ab543bc616fc49d2bcab0d34a33ecd890e77338e011e33c9f85b94a11b17fff863b6dc3d410fb3cac5b64ae7858468c913929b6cd7c4eb60c7f784ea279be0b45797e1157e1e859c91f925e7055cba210e5f93dc24ead2346905babd487abc62e02e2aa51cc33d5f44d70d5b592672ccb503e1131c66d53b303f6f062cfb21b1eb0e7fe5815af2a5c373ce099db4e1f2ee79c523b2242015a8043982248b62e6cce39430664d8b951057f9ee1bd28d09f4052f45180471c7c0293c3bfef86072c6f78c03777928bf2539f75d488d9e70c533f349cb6f1f7ecc37df80d1b3410b31b034eca218c86d841fe523f4c228644c82d23424683981091831a542528080dca120ac82d0bd262976419941d48c82d8312ebdb397143888d466e5911b310a698d36b1b7f2260d9cb2d33a24977113ac89fcc08275266842b7f2eca546e991144f973518232236410e343a769ad1cdf99ee6f17ecee77b793b2bbdd6f9dea7ed7c9ea9dd009917fdf878fdb731d785db4767bbbbd0fffbe2edcc2eb5e90fb32ec17524386e41b666018c2f17af58143d22fc3cdf2ed7b9eb90dd0d3b2a75e2073f5cd19e6ea7ebd3ff762fc7d5bb5328a05a5cfac3ff87eb57ef52b4feb9bab66d5ce224e4eae0dcb15c8a4a9ac1b6660e992412ed6f782c0f2471924879ec89ebc64417441e28723f99cf7dd3df71130bd17d2e0bd8906d477e17d2ea4a1fbfba690862944babf4f83e9f274ef3d91eebda7ef853b5368e8bd09f55dd8754fbfebfebe27d336da775df75d58030d3e7026cdfc147d1e160a4cd1100991ee51f7e3bc47f1b01e9f42ec2368dfbdf7238e07ba70c8a499f34768716f7a9087650279582fc1146696ad9d229366be299c33c0f0806671a36c99b8076590f409020af201bb37819e7c09d630893ce2128664a7fb2e945ed879ef7db3ba1fe5fc0e6cc96a4f86336da37db3c618b61ad222b2ea7789db3aaae37cf4471c1e4b3895820846e67fee3015244b198a4ff3f85987bfabe61652e4fa63bb14b91b968df453f7ae942ee05e8cbfef5f1467c3165087e8e64cdddb7597eed65dabddd46bb1ff7abbbbec3893778f70e771759359862814aa6ad7b30c4fa793e6597bb30c3d2ffb6bd5d4d96b157591e6d6e91144c9ed9d3acee49d382efbcbe7a6181ca577ce09e6f9d9c89c94522ae794f539da9586b4a911355a82454f006ec8a628409001050f4c808458020b1ca0d0c2a0a2c68c8c97e82229bc145df1822e3aa031d07870c585590e5a98002305e80a14d810104de0882c443f44f1812853dc2a34b832c3206a01b6b9b5384901137c736b7172827facc58994ac25293520294c03c058e235788063726b71028412f8945b8b939e2270aa56aba64505528089a208d7171ea051e61500182919028a15656c112233779a4bc86a2ed9a39337b5d6aa2d691bffad49d67ab29492d33acf3544e0da84d7a12a247bd4da5557db60c163956d5f65d548f3d1a27b6c699d1a46f6a0a1f681bed1d22acd8616fd5b1e6a37b4cdd45a5af07cbfffb1f0fc5ae7a6a04647f61bd9eb8f29570593dc7cb9efb6a15f61d361d9c3d1c1bee6f2ffee7bef2d73b7249b7ed45c1ee82ccd3557f762cde5a61f67a4f73c719d94ee276becb2dc2e787da2b828b921ec054629a59cbb908bad8129cc293e6839234b694dc100fdfa354cc1004d210599e9a3d039c4400af5ab04533845b8befc1645988c6b1d630d1890ab9cc668118d42612f9a25bb8b36a1c96478881005a241340a75513af3d122c610fcb58e4b693df99af7c3cb9fbcd12baf62a9601046eab23605ede5ff6490f23803bfbf8ce53ca475ecd00abdba256c5c64df7e6c19bc8e34da448ae9b76dfb9ecb32bd1005da803617f5a13d2e7a0d9bf60ca1409b6b13a240148802d58069de41518730fe54c8e13235b55699c74aa552691df936725fa103a53cbebb1b49af86b76d3ce31a140563ac6943459a0c75840292fae165dc5d4305835a14551f8e42a15028d4a3c42ef058674452f022cbaf1d53ea58134a5c24aeb49aab75ae4be6d294f86b3670a1e93794d69289a9b3b9ba17e33a73c0e93b14ea04b68b1e15fc79c4a8130a0814b85df434ad045a15cda5b950272018a34e60fd012b507d02561358a3b888da26e66216a4b60193e4a20ce5de4fcbee4a24b6972b8e4b49d334fe202ce1ee3ce3297814efcb8a288aa81ca618818915d59c7f4ee8e7eade278252daf70d50444e8ea6c9b42e5a6b9ad46477b78efc0640ee17c1eed15d3c573b0b6802ca10ac1a342118b0ee4f7141177c047f8e52da69dd3d651fc0111e71708e56adfd017a62a1e0ba852a805e3e2fd913495e603e806c2d135aa965ddc55621598daa91ac6182ce770f8513173c7e96262071a3eee1cf0013dcfed85cacfd6a02101f52e0f1c1b13a89926feb483a6be552bd542f2a18d5c86a30988f7bedcf932017371c9ca04b4fa55a152414cc320d65f09caa91c70e641a4eadc52ab3a6695f3b5b0b8edad7fab48646e8d36c84be0c7dece2e7a258051e51f3042ed81fd53af2270e3664d6e52ab746f6c836e16f856ccc76b12f4b743bae0a3c4aa2eccf7d3b60f93554f0edb82ef4442ee64bca826e50c1575b9a34fef762fc7daf2dfdcd122eb246ae2a41af646b47f6b7437696345734fec382a5a86291b25b97a624fdea5801d6945c74ef7958f7f444f09f5efb53b833450b89a0de0b77683cea7762b42d4cad703abdf7db1612f1be46b8d3bdf73bdc9f9e87459f06d8a20c70880a4fa117f6a4b921126d33030596990060a8b5b6860aa64040eae33dc059b4e70398005f70b3b40fa4c0a3a6942d50f6d7f10496da52cf5c591feb7a6b447be6aa5941403e990a65b7ae49e3456009735105772b645f3554b07c93c9ba800469da130b694f0d46eb4a9500dfef3c6a43d675b10e156029d3945c950a22ff6619e2048179accb457fb10b1ee72b48fbfb5a98d2e1e2e5bee3c2ba46fb7a3f72713687402993a10e2b5806f5ac28bf8ab29c6932d024945e694341ad23b52de00d0bc66e79b4aed1bab016cbae25bb36c4c5ceb2dbe087e71b5a24eb6a1b7f1106587a80c99537c8960f38730564c62a2d32573404d709a6507aac2bfb77afce8aabac7559976bb321db3c55064e9231d9922f294a9252ca2abb674584faa6b2bfd4d22b2dfb7de9454b2e791699ab796735496099c77b5bc7efbd354960c7315305a75670968c65291bc23847349149e09b455ac1e34b59ec35cb4358846c7ff36f2f35c4fbce4402104425d6629960982b1bee4c21727ffb1dfbdd7bb8b3fd7ddfd9e9c254fd49d34ba670e786a9154eef7daa86444e210d532891ae69d8def45c6a05fbf789d8b0befd66d190c816160953351cb2d54d5683c0e317699dea2af9b1b691609c02bd92588a8ab264212281041e35353266050c96b01712786c1896cfbd922c90342ebd18bd20fbbb20d636fed26128e2a2e704a640d3f87b21823146111a8bc5700db86e01074529ed5b0b1f956b641d14ae78424b699a88f3028f9a58971c4d76b7b33850b2b40e4cd5bfcfc3ea9e87c5b50fbf59c2a348845392830c8c58dcfb982b8ec8fd2edc11abb0ee0399ab7b939de59fe31f1698f36e1cd99ad65af5ba4d60cea409d2463542d833f53c1460f710e7457923087c6ae10d6c96067a6eef041c1d707db94ab3e2aa2a8aa2b5da0fd01354e5d17cfb028331213341134c0cdd60d63120436658424405a40e63d4f5e38a640fefc95e46124eebf837573813d724813fc823cebd17e7a35afb4b2f058b1464c4401fe523f38c33720cf48dc4d047b9befc18be8618e8a3d815c3288f6de4375f60a7b118903abb54dcbe970557f5bce0c2926c82a494fd6fb380e4480dadbc99befbee46abb6f6eedd3b81666e33853c5cc4c10177366aa1022c486002f70ba55a6b723340d3f8ff35326241e6202b5756659d93e30306194c20a1c1c46a8eacd7d61c51f0fcf1e79cab6b6ff8f35bc7c32ff09813cb929393a3c93423b86e61054a278039d1738220a4eeeeeeee1988f0c8c1e9dcdddddda7114769350a40d723ad4b5dd29a54a4aa94fd6957a32d2d0332697ce6fbbfb9b2f1fdcf2a9a9c8d4ce995f2658f2d7f36c04ac1bad436fe3360459a34b34953c7689a2411341b6a4880671eeb120dd05931a064d9a06003992bdc348e42e5b1633bf203365c318535f35ccd1158fe0cb863e367be8f6a40fd6004ab7d84b1c16437daa94176d1c39a62fa1a709cdc3003d614fbd54bcffc08e66ad43a60f6b7015630b2572fb2e370816dfccc8f45e6cc88082cb5a7a00c355b1be0ce14223131bf63e377a61091f9987027e6657e87c6d7f829a7e4d9b10156d971a76fd6cece1422367e26dc99791b610a7fb3766c7c0a03a1e4a74ee10a92e7e5a363810b53355c41ce30c1237dc61972db5ec8cc47669ee19105c8b000f6a47130ade35ff46af6acc4f03226114bc67944f64722b3d72cb367ae6c194de3ff011f1db2df1f228cc848e4388f30b26170fc8067586535f6041ec5ec3eff82154c4daa4693c69f0628632a128e16a6e110202eba37041ec5202d6f7080c76a6442328171d5ac46d5a86aa0ccb5fafcccb4504e2387d6ac080c3e4f62f07fa1f5d3491d669b15c9c9992bba75dc166e81c79ebd00c3f6feb2a7752619d9c3c8eee406f96b1857e5cc55e768b55babf61380256796b3dda206a8742d5586452b15d50000009000b3140000301008074462b1683c98679aa63e14800a85a2466e4c1d8bd32487711032c818020c01801002000010012222a30477a81c02289dc2c21340938b65c1c8513a0ab36633fdcd2eacd4ed8a14049942bc417836b9cb2ebefdae51d58aedc14fee08d04028b42f8920e247559246d425512767c73f9ab4ec0f1d6d0c9c112ccbc835cbe46818c7603ed2d60856c288a8cc91d0c754c07b7ec405dae1703e965760ffe64111cdde3577b21be48945f9f1208884ec84a20b1d242a902e6231cfafc0639481f3ea30e440f016f5ba80826fd01b4316289c0ab7ffeda3fa26de71cae6ebdac627ae980038343a7936f53a5f178780c2051fc2c77774668f86ecc2bdac394d8003379358804d4502f2d8cd47c325029df2c89bc7e2063c6d250e60292db7ebb3b41a752cb993c72e07f808bda210705a8059ef5375bbfd2d2250bf2662b07b526436ec668cae820d6603dc5fbd69d8e8b548cfa259cd15bc9712be3fdf91570234d6de2377fc56cb107acd55afe4cdafd79179898d9ec43bb1f5ca42f7dee5687750cb47b2cd3c68e878fdac94ac1dbfb1494155fe1f837bc1fc5914f53b6e16fb71f3268a1561c6c59609920cebb22b051efdb6a827076d83cfab7f173619118e192d5d3316f84d83ffe5fe9e99fa4bba3741f7b0f48fb9965dac39cc08b6b72653a1fd610d62442cb1b294719f3d4332b030fdd12eaf0c0308ecc2ce6fc8d24c5a3b7554ba95625b3583deeaef4653051c73fa9ce6145006445eac5ed31092cd88dca22528ed0ac96aa8fb18e1956054dfae8629bf8797057a37ba4d606eda92d14d2d088b4da1588d3e781b9bdccf4491702bf57934d767313874f415d38771453cc207f4d975ca62e4f7b7452487b8422f4267baacad9ccee75a3a956311bed3a6c6101c6895d75d6bbfec9bb075a32ebcb6980cac33c02d9cdf2f3362f62f55e75074e523fd7609a77749483b2f99a352ddcbbea4f7fc1e2e3f983921677d17eaceff09a2f79376e9c3635c180020f7e937c67526e8477ad491b6f0a85e36abec7c8981760e7c4988b184713ba3e3c63e2a9d806b9f761d53c7dd12930ac0b3e6885c172f971231bbe823b9684d3ab183bea5c07f31c7f43bae1bd1a2e65e8d9ec47fd1ef25e2c5eeaa359cb46dcd81ca85e312cb11b1e88262cbd19e637b6e29801b4c9ddff035b27116350aa5e88a0dcb5d657c0aef59f04a7d4068afc6f718d469b022e3b3696508398274c17be9370f4dc24dbfc173e8cf2e643af888ee20bbf694977e7a094db64b3f060216b083bba5dec948844ca98e40fb2ec70ccd8a6ee761a40744efabaf0590c875d9330b031a16589f54ac974b10491b6d0ac6cb07e386c0d925b52521dc9bdd458cc3f2780ab56792983b98213ceb4ad8d8feeee7cf2a1c161d6ceb155b948cbbf69ae2973953df9cb71c4513e84739446e934d225781b2ca4a84468a0f5fc2f042a7af4c3795e2309be58d710df69bc17df3ff6b6ba0f0d176c40a1db2319ba09b4c0cb4c34585c454b96a53291357802c487707f9373db26498d598698b998e4b98459e5c3578ace592301290e411823e0b3ba4e5dd37c192ac447ad8aec7534ffcab8926554b15d71f076fcd38e6b0e28ef468ff9706ba0ab0cf16af4dfd4a431eebf37c9959da5ac69b140594678021641d2e86c00ca406f608f57314b98646f8f65a71b1bf9e1cb60a588f627ca5c5698dc212f118879629698d1a702b8bb823e16300b30d8fd3e587fe207c127b8e10519f8849a51daf6bcee26bef4741517c0075fe39a5b479855fcd251d6b2ef6f0b4c8f367edc4ec260e1907430b5c91fd424b2b3de536e61c7c7b6e2c9f9328f06cd93105ef50200624e3ed2353b69de34ea89d4d4996a77a85174c6afa46e085ba3d8662408ad717cd19812f35e2bcf1d2148cd39ad53c1e573c0af8b65d3ad4d32af4acc51242ffeca5c35c53a4bfbe1832d92709004094182b090ee02b3b95ea8be22a28c824147cb6088cba3cc6d5c9d665b6a6d50d980866067b25c08c70fc2bc8b0acf660ad62e01c3dd328bd365a4529286d10e4795b20a0f72301f1d4129ad2de1580fc9be08b93cbcc8663dd14d6e8fdce93fad0d794eb019522b559306bd873d53283246a3ec594a6a50c62179bda52930ba537d834ca2df7f5a93789b80f5438553b68959e638c72c821843665959c5fe375dc2fa698c8831c8a94e66297679bc97932827a76bdc22e053303be19161a2468ef45c950a984eabdd87d74e975fa79d7bd53616082e05247c46ff8a8f81a8bb4d6fbd79d742a2cec02ea3270e2e3a169143b275887a61b12b0f88c857c2e71ec8c8a5d2c2253339bcd6c9481fa4613646e4a304f24838d1f91beffd1448ac58d00594fbaf24f9501e59b5a5b877b0cce5e567b13c46fd21b2f687b9b34678e081102751d7abb81c781f463e60c03885092946880e2f3ea7c60f440a997296b0fd30a79e7c9da912087f1ab330c92a479ab920c5ce3df35169108e4e810fd680804b9160f64d5d43a9555928640efb44c4e4b166a2f329cbcd11930593f0e4416dae72a7ac3c04f2c8d5c75904906abcf5d99a158ca82bab9298260c381e9a54d239f97f2b1fcc93cd404c35f74167cc06f277a48aa99997c4b6b2632093546ffaece213492408f28b3ad3a0072d443d4adde8e491aa4a591278c17fba36b12ef39dba8d333ea62af41e7a8cbeb78c9eeca1d5253706f3e0d404ec1b917fc8d6605789d4fbf1046bd5646a601e1204d5d19e8963dc04a8bc62b0a055268da983945005cdad4bdb123ca2891d60e84de085392d6b8e81a43261bdab170e21a1c3b71d277d2a2a4deb9cc68903ff24b7e1f2300e091325e5f27244ca719c47aa0131b5ca51517fbde1dee3ca31f3e5e68a5c1af03198693271d4881aeddec7d588eecf6520a79b1fa42c3bba5efe8966c52842bbec5e3be9a0156c8860e70c72d0b0fff3aa5c89049c88deb9f2429b608497668015bc6e018008fe2901daaeb651e0953c9a6bb21a9db9d114b865afb6399501f90ee885772f829cc1e3b257044e26950932166c994155e3876ea1e9e066c3cb4446786261698370df3b6eaf40b1f23fb04b3ba906726cfee1c0dcd12a94d2eb8f3477709b5391598bbacbff24f1db5f192b1e1c26a705cebc317709a6a3e83931826cd15d33f6daa70fed407e9bc450e30580117dc27f9ef66c1610bc879753119f49ffed43e501498bbe3179372dacb73b6e560663aecd84fc1b9614a7ae62d95e230e05b8e118658ce53449cbbadf7820e08520e82fa7338ba036509853342dcc6ae49ada822673dad5edadbef0d2ceb671f1e3856fd641cb3f8481acbd147743d97131f10af14c7729713715171ede75886037933f7de6560814448bd7b16ea53c1dc7bc01a5c6cfe80a9c9673656d0c106da6f36319436d339af17168f883a47238168d9dd1219301e5fd54c5b257b9c98fc20c61467a51f0f0592ed03ae857c7fcef7aef7ea57efc5b56fe6ac211c282bea9edc07c3c0560d6daab3e2b8d4707ce5907234de7b041b11f2fe45e1d25d304a233f2971f0a35c7d5f108961acc09eba64b740e4833d34c5065b84dd71545213bb1fe6c541dacc70f5022d06b6b12e0c4f9b5f7b21242b38813f355042a6b4a6a91f59d6f94f8a4f31561646522fbffcbf599b9f6a44c38d5315b84ce9cc6ed5e729b37dec39800b4bb89476a87e3e3b4587258107081e0473511a3665cf97c6cebdb761ea803a44940428f68b90ad3b2491132a8519281eda997c63751369db05309ee792335222df662feff5014edde5b018c02b19649c038331f6802a267c73df309251d87b901fe03e446b3a642156791a0684b42dc0826280eafbb4c280be12717c1c8344491f394e2e85111e666c86a815536c9eb9a7c45c5082a1abae5a69046724cb74f3533ab71434d682648e390a99022424c8af05c13612c7a613d812e9851295f6d2b93a073e9fc0bf224f053e888f510a8a51c4b1e1764da09fc63bcfbefbe45fe6839e7b1227b25a12b6a2ac94fb4b59fbd9b61d9c6af1e952265d1b3d9f45b6bd3e041c4e195c9295591444c6c88001afb8db547fd07e46fb70d0e6c3c290d628f3def35529515e0d4d0035508a08d2eb057aa61e497aa868f0ed26e2f71f37c15f5c6eb08ff70cf2a6db0b8f467ba402755d757b86385a0245c1683273ee75d7c675a3666da51a52879e581a3e067b48148b3ec1880852995e7e0ff8ffc9f4c0e4ded58b0a846ee57c0af6c4b6bdef33b629c7fc310ddb286825544f07c44f4e2bab4ce4aed7703314d2380f6a340a877213a51a7d0d6f72f416107797f07c981054ff33a0ea7320b210f9cbc0647aecff2542977873f44cad258e7709fcc05c1264a94bbe48a77e066a00355c5ecd27ea7449361c1460862b708214309068da836afd61ac811b7e1e1be2e3447cef4f35b41103144440c6dcd30094c0dabd61b863b4aae7a4d25a5aab0806f40798aada7bad09ff7b4a3b015214c72c4802849c01c6bab3ff303a97505dcb4101f19bf7db83b7770f319a171a4f58c597e9167f03bbb8604d370b32a36f12af8d2b8d13e53fcc98fd7fcdb02a98a5f6451b39e0dd2035dabf0eccbc03d660aa1e8ac085e5f2014dfa14d94bbb2c2339c15fd25130cd633893d6975b0cfb4ef32b95e2c57be0af4b9bea5960cf81882dd1d2a6a8d1b2b6962f5cc9541d3c6715b501c6401082278742fe106e468d96e7fcae039c778fe6553f52e3c54cdd9a0daa504ee170550caa53e9defd1b640268d822b891f048a4acd57aa13264b137d92f487e711c57e45a286304d2fc155a17e36cd9ec22b98364a27b2ae1a88d0a786b376ccb4cff14e0ae280a2c55e7232b74294f896db7a8b1fd15839f1a46458ced836ef8fafc90abc47ff571b9b92f68b80a2cc3905b13ceaa5fa17ce0d86cb33bdde1aa336db9e36b8c86f735f5574347c3a4c75f86b24520dce5b9c2df9f3b56bea99ad2bb8449aae782b025947f52548eabc02f0010fd69c23eac8302057d8f217f6d3942dfb81713f0fb70e93ca1517692e421230562e02c2c32d932ed7007a0046757d070ee50168d0e4af096e1d01ff9f2939d3eead6d84bdbecda5d37ca1b1c76c2e7388521f1801e1dd6985b876e99592398686b0fba22dad5078f4dfe00ede07e4a0c58d1cc3b82c9f41234a70d1f9a957053c1eabd0af06ec8fa0848f17582feb3737ad27f8a7593421ee9d0bb2aede4bb603c138107407f8b458fd1d0a503718d6d3559c59c77ec224df53fa7e9bd512640df750c583b6a73b77b8efe088ecc1ed064aa8c5db0a445f010c20d42bd0f544d712e550112e99640e2d697d6299c1943163e3276ff27c878c89768fec34e96863092e3ed797fdd5977fea236003fd52848c211242c71f2fac1542c0f49e980e30f1fe74d4576d627a7aab4edd333b5b45c56943fb69f8c277f52cfa351ee1702cc7549f1d21b0df2a283dcaffa2f3aa69645499a76c036ab51c35024ae839f848c927e91c0d9f67f1f0c77c1b9986619fc52d8a6c9812d7430c5a0bd3163383f48ba9c79969a29581a7e60c658d5a32a3b34c9ec4224cf6cc28346ea420234920a5e064a628e9f67ae25825e2ee304f0c6ff818324c2c1e274072b8948a843262c2efa6a1a9a1ffaed2b119af8f1dfafb700853ae3ab9e54fbab2ff79e0707e8a0a72deca34570b0a7f7a38e16022785a24aaa6ccf99dfb25f28b5bdf6489c79c2c413fb805818124d5382cca1cce2be47a6deb13ec947a382b2ad18e08a6544efb1132c309d239ab73618ce7862e73de06d8ff1af02603f700f216f5267e6eeb6df670ed5d2a4f86a5defd053932078c8bb2f278080b8128a01c7dd0136cd26433e26d19e5cfdfb984ad26ba6bdf0f14e13128ba53b6ac54d94e2e0a67386158962b21270fa4a4574567482eca61a6215803dcf4b8605a0b3ee36436e09b563f5bb65f3578828540fedc837cacc354315078199e7869d214fa66e32b25476fcd7aa667195186b2602ad6c5b807c1fcd6ca3ea16a9991f9fb0b429a01f6b5f2e2d42ea8441c384c82e08fd3a271fab6471e9b0a04a6bd969fe7222cb1a2f512cac4a7a1eea9e594c2f94642ea06c7c4c17d10e44d82d4a66fa6bb39e5c5d1c9335d55d60c115d398e91f6c8f149510014cdf6c5d2da8169eadfd6fd15e72ae902769e9d3d7218fc3a7e47ea85f6792d0965a8b17f784e24df7b3d501c99186e1063a14df7561f9eb3813d14ca21a07714e32915347d635e6d7c34bdaf2bbd604e3eec5b431b06c6969cffa5d00fad51ca3c6240d3ad97d3fd8db09ee466d1d809768b98bda39377f0131887c9d439cf196408f5066cd0329fd822a19c16432e2222ae144b76e33d0335082c147566966e5c4e8d62d08e760dbc8808665ad275f9ff2042ca21bde98cb4f815f9c0f644b8219cb9bdf6e2ae6811805a548e65644025885773aa783a861ab7ec761cd112051d1a68c0bcf9aba5b908fc947d64151baad001a72e7c39078272d8b6ab0ef2c8d0309e56ec101fc4db0a25b67bb0f57a9c6515a0f8679dcbf30e25c6f48e0c0c9f6bc9c7f04e5b764609396a1677d5847a422f1dcc6214f72a45d2d10726744e568cbe44a8713ac12df123f4fbca2fd62a781a9e5c941fb42857db45955ea3ed7bf739b408d97271d23fc462e15d73aa73231b382b339cf838606df8dd3662a067d5dc011fc2da95f4dedecfe06b5c0c48cad1d5c8a804b37969b979e6d6d3b847dc8573bb43ad67c1d9848a8e2f1362b9635d7a945e91bdf5eb3c0e88cf794367969da579099a13cde543ab3dc7e0667d1dd05570fcea0906efbe6af40446e2a19011063cfec211ff67e66957b13fcc45818572263006bb6fee47e1e24b418bf7be446a28a8c9e85c1659bb3590719f24d574ac3a02604f214d03fcb828856deb051b980c7dfab1d31d52aeb33b3b002f5ab0f2f68fff746093ce2187734d70a81629358628551d9dc99c323670c17f6656201ec8a8343f072d4d5a58253622fc7d61625bce644912aefcd56d1e0683cb9f5992e907fc0b836d41a78a8d37cb708510a4d11026db6815991d7416f172bdefe88f231485c2f58cacda2324d9e8d3a6a508849688b8f5d6ac6f449aa397c13e63cff40732d61b9397f0ac2ee030705c26b6ac5b27c707c059b3c1d2b934f4aa61cae8306e788015cc6a908561436aa58615330d2e07c0573e3d9f5470fbcd879322114f1fdf21fcaaf258b4800f02f8cedfe3a4fe3be2a95fb6b3ffe60617f89779e1660abcd171c0bf1e019341655bcebc7959d266af11a03045ec871a29debec967ccf23dbb2a3491bdc436fb358b334dd1deefd349bcd028e696a5b9d2a894f134205da346784b9fcb0a881442cc51e4d06b01d92ce1cfa57d106ceaf877b84d8f713b7caa0eb0e273ef755c36789c0d10e2a42d419c807941c74cafecfae17c6675df1ce1cf3569e954eb1cc9cbcc45d3bea49c8b0586157748d04e8c6c138f82465b4a733885bf1e81a8d35fd58ba8ccd1e68d0e6ce65cb55de00892ac14efadd415b50564c9f2e1268667abcf5cfd582e9e4ce923dac1a16854ee2dbada72da3a2440bc494158eecbd52aa57aa573995b2a3013c13b40742e051055dbe48c2e0ede899b7c402e59013dcf1c7001baaf2e6904ccedb063d9e7fba096701459f8326089eead8b9c3943dffa008b624b691f2eb360ab7bfa9eaf3e9a3f7fed8ed592a1be6d0c0034a10149c4416ea066b787e91f7e80235d25b3ef3967b60b584c67933b858c999c98c9a1fc30dcec7f846c3d36346e3b7caacc18677419c19613a076d5331b2f3130a9f4d2aff612e904571e042743ed964fef1ed8cad3c13380601f69d1da3d32d33f10430f34999896a343b40caac604213d18025b31f5ab68d35a980b72f226593f85bf466c9fae612f0d8c0bcceebe1d14a780946ebe7115d04e3a0018c456ef8c9f9e99fbae35fe71884e3425cb7c83bfb004f42843c484a52e892e2694428d4c1c57d3f6ca6e329ce6a62a03ecc46c72bc7269b7a39549bc2e8281fa677eeb0a3608437f6a071c3869837d85899b86c0a89f69c19ee02f45bbac0e5a6f644c81529776900b610b078e8621198087a42008d3afcbf35a6de13b56b7677bcfc42e9ee5895568db84744229cbc01fc2e84144cf7eb71ce36a7d458946b003b1f19824e841beaaf35581070c0a106395782b711469abb3c166a94a63ec3654ed673723a1bf3d406e53df787392985f4ee1ed5966611e0ca3c4d59029a6222f3977f8b3c30475a51fe7fc4245d5ba057f379bcbbf709d7f3e7cb116ea722669abee0b822dfedd05c6552b265a7a2a6f57e9e97797e4727adcc54d0a8bf90d1ced33476020441e2eeb1e2ddba413d1e7b526a0563bc04792a7de82755f6f9bffed1a9966f465701988134189ffe13e6fc58daed97205e23015a3f0218638eb824d7fc0a020b05ad63fb418dff931b0f156003d45b386291d1cdb60ef4b3d2d000bdd0609741bee945925508499b894ba6a6418804774966a1f03494a0f7ec9e1edf1d21865d2f25d3d1d841bfc66bac5d568cf5c8b411e87309de56be08fade1fff95f41f98d78798e3b5728db5617dba7f7378ffb1e053c5929e192e9a5ab703b482a26908aa76b1e4b159f64e8dddcbfd43773fe3d52d4732aa50768070d16966276ea1b95a4eb49e6a1169af5aeb9c1f6d9a5dd97e787f7ae3a5aa83bb97de5de643f6af3493bd0f89e01aff995e4c2a98c8c9a6dffd138a31945618caa5d20107426eb8e3c2c2ad331dd81af212790e7a2f4a2f90ae01752592457872387b702d0593c38b531bf0eae6cd72af1cc6f4befbaebc86e0cc0b0d4aef148f6cbf93df0a7e53fdb6f190a2e9b69f08fb8251f99a5894cfb22dbf8be6511104dc16b44e953bf384210cc0be85a2c74ffaf03c988dcefcaf943265425940d6e722dd235c8543bffee0ac3b09b59241f5e0be019253dee8099350ed93550407f9fea247046b70d748df5da8d6f6c0ca8838584d7a5e885c890049d08ac95df13b2087e7ff0c0f19c13c2c42cce4b0e5ed3229471562809a63a2c0099e48d62532a69b2c0d34b8d748f1477c3a321ca2accad291e07227378160fda0624bbbd48f97411ec49a107aad88d159abfac1880615c365905edd26529ac89dd50b744d5767abb254808be809adb66f38472876f4a060c563f0d4603dd882405cd5ae4e7d0611f737817b8c83874ab6c5177e641b149d61700bf1859b5825d7bb320177d2d8f36fad8e287b3f66189ec006d0fe19b59d3d7a945d1680e423556eb490becc354643be52aac3a5a88c202632f5cc1fd00661289438a6bcbc58842daf60b837f3901a86caa61f5af5be7ae6b8db5ecadd40787cf66d1d2a45523f01a3c2af085dbb2a3f9dd97a93329ac5bcea595b75fd9b4ddf75de9816f311d99cd166db42246afdd29c7f77c3e3d0d1dc0e91fd76cce51fbe499b4a933c21e882b32765e8ffc87158a277138eca73a213d1820f5ac7b7264696c06cd941ceeba21bbb547c7ddd8e3c313d396403a650c4d17b3853e6befbf61d79aecbfe7720692e75daa67ca7daedea95d96ecdf16ad351c7d37e04e36b893ea40a35dbbf08217acb2aa831d4a1658fa8652414b5059c6223df8c0f0f3bf650f91d3d73268101e0fcfbed7292a40a80b13768c14952443538944a70888b6d085e08c2b68991c8f0ef2091c815bc9b055d17880489912e41176415106a41cec9b8332537b9f4223f7b9ad8a937c4cedba8c6a9318cae7b5a1cc0ed6f06385d51750e78f2c7a9f8afd944b14d63aec3d9177f9e28028562e09a31551d2386b5e782861951280814984bb0549a2285e89558d844764317531495b261a2684f77a717a01a7b8048974546c4d1cabacca30a7bb27961ad977dd46a713da3f969b54ae75e6832b1a5590ad32e52c6ad2d6a8613d8c6d8c35f33f3df66389741f2db4cecf50c121173f084e651ebdd5679dc06b2c69000d7b183fe26439e117804b289ff081a37306690beb955ddcb6c6547cc3b4fbc790d152c07408767bb8cc0ca65ee1f74cf33bea57b9ed0c42bf13753408efdd6be2a5f3ab08ac3119751889fa0f77ca7a4898d5d84c928984c24bb95ca05b8a0cfc8392ace8875ea343b903e99716dc9ceb6bc036550988581828a2272adc6a1cc3562dff671f7b3fb8754ce818439e61eeac9d3b7ee85b9c616656b03cd08c87812ca0c4b0dcd0a14bad61dcbc27e157d015a1443f2970e0bdf2189bb2c0a8b95b8807544b5976770d42fa306b1efddd238fe4e92f80c1d234a7aa9fafcab0d31cbcca5cd08f89dbf29d336d77e9fe7d20b4a69ce3ab1aa5c0f1f49d408d328157ac0811881937c46e45641ee18e62e1d9a47507d7dc382408237a2866d601adfe75e9806565e98f9bc8b9e0aac97044c448035441ececd2315787107b8536aa4cbdb3156b080c1efe3731b02a6420739480a8463a9eb0d041399d40d3751f6ea40c484700c5635da2cfdac77a792d31f1f45036e198284e787125c17c720c557fd97fb26d015270b95a593e7e3b4d97cfece714a90e3ceb01b1f856fda6df419cf9070c1e62ad3a7d4bbf4cecd50f0ad531519a6ba21dc3cad65575ed6881b66a2ebc90261c82eb72e031b430b6fbdc9636cea7a4f500cbfd760c1d11b6af7850a9a3fa2c5c71979325bcb4e390e2dca889126c20ad508652c851f83fd4927acc365bdb5850080fd57ae1d4395b63cc69584f5faeeadd5b1c1049159a03b1636166422acd6b7c5588cb1cb4491f16eba5709270ac7dc7961c92105bbc183ebe9feab7833f6856208dfa22ab8bcd2309932f9f3b542558e7fc65703435136766d63893e34036b083be5c1e87f65b6eb3d8488579540af29f4c798d7e4af71109a41b1a097203491931283dd81b881b569702d809ef13066fd8cd9936d96bbedffc242b8f1f190f51a3ba205c1fdf670877d39b1ba50438536fc66d44b9fc98aa8f342991b959079caecec1f8521d97f2a2acc6bec08697842dba4f2c4554091d6c4a3b332ee042c8971020fce78f52680b1db09a971a780a9869a6ebb639d9f5f2fa4443e6a0e424320ba338436734930723e8051728a69c4aa530e4f6cedcda806e906a9e4597a33a34f9a988fa082fa807629b4a6f2535ccac5a5b0d560ec05344c75563ba7739325771c910ce3391ca6fa10a90524976a9a68c598cc94dfbc217550bfd3d45dac34b2920655217a42f66ba12c8e9cdc3402aef7ded87f744a8cbdd24d5699c5d346a42900e4196434b292a3787d6ae0897f75b9c1e1dd11054a515e68064831d0f389e2b2b8755219563f1e24a284a4d939cc704f34f5dd1af86d9a8d3ef52f8f22c38879070ff9252c7eae8c40f68b6aec61176226590a626e27c57e8f211de83d5c8e12bb6e57e8ddf81647571729b15577c1552940113741993ff32b880a9c50495f54109ab1125fbb7774e5a9d675e91fca57db6a2590e90b5a0036d9e129a33e7121509806b6bf9ccabe2c358ae714dd43b1e122ae2b6aefbced5390bed58f8ea18bef081386f68e85d55081c0c8b1ac81bafa9352097d5b1abfe6c04b9bc81a33c66b7b78b43d5307938447fb9553105f9ee29149b5ed534afd558ed51ddbb02cc6bd3decbd996b465ae2106ff5ed33547c4dc8b553b42ccbe3d86f41d988a73b2ab25bce244e59d45cc47938e7131134b08568aac6e2b6064d2ff2eb4330be5c20431c934c1f0a34a12ad5c3096cc42ab3c9a8ac03539246c28c50c7db7535935f2b0f20fcf4d327126290a289bc0cd0d33eaa7dba05aa86cb81884fa8fdf8a28dd250782434a23855e97a35474020d349a36774ae7e4f5d9e50ac4316978186e1a8a26c514eefa6405d30356ca514c91e98b67021850ecd645522e514ed15db612284b8587306c589d50866bb31dde524fd118154f5c49d6443ea08b21897d8d09301cef498618b078f39ae6c6fb580e6b88e404d851e57bcf9b97ee2e34a8c00c895f495de100e26337d5a92895ea729668f01c60cd2eb44ae048b0224576c12c1e5a863524ed53e9bd8e7240a55efc5faf0ce98cb855edcf27ce375f1970ee777929a9f27c35d8057c0a9dc89afe654f7aba951f1cb4ab805eb82d0ec1094a5b0864f411b0a987955e0325e2ac9480c212da8ed7cf899f32a155e284d3966c7a82499c1736619c4fde1a8c1b38112f872020cb282d637ad328624cdf56e2cb052c57fa4711674b12323a34c2fd816e9fcc819a41519ef755e87af0ec481cec63730dc8be3842f60caa9b046bef4157ccb2dff1c36185b464821ea266afa38721eaf4c0395b1c252ccc30270ce5e75b36237494b31492b5041e0f9089bb0ed49412797539f28c5dd4ea5c7694dc0027069d05ad3ffc450aa148f7849d62abd32170536ed0ace24d1baec1c34ba58827e959c64df2c7cc4d9b21c7e27a9175ce07664475a5a4d8895a2b5a422608f20b2f2d36db78f254bf02b479d207deec039f963f7716609f25eab97ed914358d07cb90192c30437e4b0d2f22407a766faf256011a944f35355d4a78086b35785e466cf16191852e587ba70103ea48a8096dd138d34a1cb6e96912db1c84e223e2948e69701ff0ec2c0b632541dbf0f14603f44127aeea05b84ef1a3d9e791deec4b587dee064cefbe532d82d1a409f33d218742a1bf75ab5df32512ce076bd399c216573e4465f2a815986fe42c755ba398d15317e9aef989ee65ca0d8bb5bea41ff88fb690632d6abfd8869a1237d4c8504e16b05655719fb414045c99754383038b926f02d840807a41a5373bcdb3958014c9b6395457fa203ac1482ee2d826fc5f9685aa135e087e8d57c7de749fefcf2070ca9a6d8da057df11dc65fa18bccf0ea908bbc4b0ee75c63c1af54814a07812bce6d8920be8050f1a543c6ef50c27fa68756f3fed970c2a6be397f87a08bc0a42ef564754af6f7dfe250613cbe444d3631c65819edb75c10f402bdbc91aa2d1e1a6ef3a834292c9455f650968c1e2af68718ff31c2e60b3e27c35c997fbfd89fcb04afb6562ab9199abb7f0b11b5a11a5b322ca083edb682fd4d5cf2ce9671c0bfad1751b0951bd6be2f2655fb1525c9cf2c973c254af2d9a5438a9076057540a6dda45932c3b383a17382658cc54a3cf911d179fd7c18adc092ca5dbfdff30268712af7a232b611a73c2178bbbe9bd305c1c0db107638d7bbaec0f0c537277164dc254fc0e7ca01b986ce011919cfb744e094c6de61f1ca8019c30e41ba8afe07a34c3c848114bafd89ab9b5b408097a8255f6cf32b9d2bc4e82312a1005145b0550ee08a27ca456bb933d88e9e31e6b7481d19f5b515d7ca916930b705db0d142056ceb9b6a61ecdb0ab770aa705f9fd1fc01ab936b210c045a8cd581151b94a05c00955f67219f96d24a21a5cf867a325c80fc6a3c522d12ddd417df57464c6929999e8ae71de8a4d73ff7464acaf94a34462cdc3235b67de0fa1659c6f97c943cfa04349c5f01cca4242d2b88206d087df0d484da0c66a6158f411cda80957925b2a02212f274a92cd1297b563f1606ef05d171f572ad3b21fdc4e68aaf2b0fd146655dec7cb4b6c73b2fe9a0d40364584c26c9f146108d526142caec7f9a8229aa42a246995f17bd30ab6130464719513ef7c0d38371d140bc2b75f6de7a2b176efaa1faca6208adb3adccebd1703da5666af23390216aeecf0b451f5845de51db600781a5a62523912d903e55bc36b0e10445664187f0833f6b45044ac3535dfd553342f49a4e31751413e58e9b205583365a2bb34453c2f0d70f9f844389786474d7c90e5f0220b48783198eb4748958460f97d45e5ed55500d99c3a214e5f985ad429c9681407c60606a536c802b83021ab380c50e68a61a2a6f6aa646e96948700072755041394c5cd41398f7550aaaeb2169edb934782f9531084fd93556e81b41f2e5ea4c31600a8e0c49c3a899541961e646640a2ca7aa79d2ccd2f13015ce3923e0f1749c6200f6ea28285e779aa77932b9f2e1964c22f66bf81cea3f68f138ab058a056e056dafdac2d87ad4f0daf33acf0b7ea02a90250c572485c3ef050ad8c2ec60ee1d32b56db80b896711bd2ee0db08a8e8260282efdd042e9a8505b6560da57f89d0693411006b8b773bd43ae11b12f750b7ecfbeef782e50a59c9401966ce035650ef9c0e2f858dd33cd344ce1e226733ea63afa949d871292049ace2c59abc1fb0ca58d5a3ce66d4299eb689172c89b28043652d680a0beaa516cbba864c7de0954008e358b7cb0f099124ff6af14c0f515cb8fcd0eb919fcc40d0054648c0c0ccdf324db24015b70063b3979b2fccd2ad9e32ea8b2af0936c21e5d44c7a164e7440ef5e03f2412eec5218ae1a269b74b8ef99cb8dcc75e4235a1442368caa86bcb0b1cfdba3932258e5ac4e8457c7de5d727c6596786d5a0bb8dbd45fec6c3b06023c3ebc1bcdc6ccb667250a9af030097a7c389debc45cb7f6e6a7970ae39be3b60df6cfcc79308d2c0209fb78936f79f9d7280562640170d62073d3fbff81ccdf18501ef0b89bf12bb9a1f6e70a05e4cc05a08900ce3d1583cbf821f03e0dd37236d5c9bf2977fdff17eb1e1447b1558e24e42480e668d8ae03b0ee4c335cb65fbb102d506af29a915cfa694c33b9b187254e520eccbab3768c771bb5f6a8f3a730209f53d5cbc91b9bf803574f0694740a148c1847a54c7b0a8d1352a645e11f22034561ba5aab7903c26e22d99fb0510916f232c62e9b3fbff444d3cf36e4901660e0647d14404ceed354d7ad48d4df57aa4229afe8342bf512440057fa304a1c695c4eb16017f94184225daef07b9771433f6fa5bcb48d82e5ad899dc6a1d39dd4a0732f4503a61240dc6dab69663ecbe6a8ad12ce0996947fd25a5e5a42673a2a36525b1cde6dcf4756b638cb6cf2e2b8aef1fa71ca33c410926f0f2071185e6642e7970353f0257d91cb16d546dfdcbe7de680b4e5a92fda68c6fda8a785211e905dc80fc7612e83d0d6215406ffd25e5f242bf25b202be96e05f728fdde40d32b4dd91fce291c50e6d0311fe45130851010f9a6220d8235605168c98f0b55e080c4dbc314e3b78ebed0ed029d375506ae0296ab4c95d6c1ab366bf05d305def6953efd40a3284fe692632745247095cd62db28b7296744c24912bb395afeb9edfca043cd71b0808eec10644423e9b3fad08aec6029ac13d00ea90a7ea493e06e234b0941b502baa6c6e256ebe24487debf14c61971a46fe7fdf61305dce3e019c7a7d975ddfed913b75a8a145aa5aa1c3d318dfe837035e84faafe53dd68858289b9661156add0648b45a2784a474094c818e19821ffc9f3d459953fb9364d548a005c656c771cab979da89a27c717374a92f7d5aa72628ce813f9db783cd9f81a4a6e6e74bab281d12e24f48b0d5bfa3a65aa483823dddfa95891cf49caab1252b253066e808904d53ce752a215ecd92583f246469a72cf3f9a680a4b72cac0491092b06eaef6e87019519550f1ecfaf239467af62ac1fd528271bb4b912534a3db5669b93cd0592b7979ddd317187f3c28351688bdcdca904335982c557ab714fe7860602f7882cc8e095728ebbd556be9555d5e5f0a07233fb4a5170136f58744998f61a2f9d506e5e7720e86e17123c5e37e8c5312a0e7d8f643377d2dfa736722387abfb7f92f32f448eb99f8722075dfa3f14437f51c07ae9caa66b9aa43f494072fa785ec95827b3a7b2e64e47b3ea5d9ee1f899b53810f1f3d0e1ed4075dcca1c668cc093181d892369c3a38e4aae2a304e1e3a159836b062c213000f701c964dec9fcb6327d031ccd0a16c8c59ce3c67114a2be6e03bc438f81886af8afbe9fb8137278958738200c667a240adb8bf720d4e776ab523942c4882dd576654ce816e16441134d213eb5a04789f8fcbd5bd4829b91bf0b222e15d5db9d047d69d551a4a8685837da044ea0f05b1952d8f8b0a2b3aac6a95cc2f857b843d110cfcd91394d8f17995da66e94b3cbc4b084e42053229fc4a7f375935bd499bf110a4c8400fbf1317617ba1c946825943ddde66f340032549fdf12074b134ea82b4565d23ac743feade49c9628544bde2779e59cc1ac27259f6e7b485d757876965a930113dac77ea3eb41b7d38fe82786c4688b8ea64fafbacfad97d912d7756d50638f0d277317a50235d2cde6ebabb4b8e73ff61ab9581632a57064b6a93a8834cf488ba1d0b4c1ca5e996980f87b8e489914338da064b7299a106bce888badd8a985206399d08298bb64249d621faaf2ff3509e5838d19d813ee7f63d0620eac9afb0f0fb482178f640da3e6602d185893a7649a2a64f7eda434f8ac76f6e56860ea43094989a34f69a0c3eeda01c1814f35123db05c88d6d427b70c0adefd084f10959df9e7241a35c9b1bba2349fca2be4c58add76721b24b0d3972a88d61715974ac4e0a0533708c72e0612d4e56ac4931b9ec640191d1e9bb780effa2a78be6b5f8e367ffa674e2c3a1be4ce7dfeddb2a33470fe1c8448cee7ba9d67aff9b784dc91dd44fd2cbd9a09139cdfa0ffce18e521aca3ca0e56576d472214a30d6d7f0d94cd366d66fa2ba269a024e28f908d86694db4704049ff0d1055a831a24260ac8ea98839d59961ff8939803d824c1136b9050a5b92a3796188429fc65109c7292a023748989f043b2abfd137c68d50d027b1ad0ac56e053fe8ed550c6e57c7a7f9a7a165c41e9d7efcda8e2ae8103bcaf73359a2baa8267969d30146067172b3497d09b151470bbd5951616336a71bba795432e9b6f074983e9808dc8af5bf4ac6d2a83d3d41a7ae3af78f1fdfe280085cfa5746dbed508c13cff71bf2776b1b9432127a19d6552c6e50e12fb16575287614f865b450b5b81522afd379d8a9f844de57a0b4d1d5d98d56fe655857b1b8958a1f49ab5495ce214a13a4f3053245c79fd1a2dae21684f81c2d55694d7f8861417a1a7e1ebc8118f7ead11e5018a0dc616795792b1a1d5013e0d5ddb45f0a1fd785e328fa8789386050044ba30ac3a0a8249b02fdb97e6e7e6c87f8c5b77cd1428c1b20d947b812ae8749217d2ea9c4e45210ff67305bb9eea1017482113dcc62d37516ae40b10e5d25361597831dc60b6af6d93713ab12a6cb4b105c692ac85a1187e85aa172d8750933d9fc294bfad541cb897b2ae90d22157b17737c3f9a24b5cd1e86482ddc24c050e87d3dcf1141e900556ecbc34723c6d3bd2a951528f60168a1fe6ecfeeed4cf35cc00dc3aaa72b15cba2dcdebb05751a05fa122b61c29c4d8cd7ba841e42203d52af93426eddee45ec4a2b242ec19f39b5828bd7701390cfeb63dabe300688993b6733e4b9d43c203f08548ac641ae2b6b00ea9e4cbb318b37dece5f9b8906c2cd16d7f7ba868042c193ebc72a108cd8b46b2ba6b6730112cf7b245e04d714a378975ff6c8f1929c89629ba27b81955d520c740110ed130a2cb88e2c15bfcb286f38f9ca6e4cae2bce083ca04d225b20fc26047730f7105ede3b7dbb9e445457e2387441ca68bce565e9db4068e7a22eff3e8e25ed52ff75c4afb3473c90ef616dfbb2372077c6a4882291d75f3d0a317dc837d50122c9a34877a1c914e28709d6817e0fb51771e1319301cd43b7574e9c9f73abefa7748a77012bdb893f0a37e268e2fd0dac77bd4eb203217554e8478b59f3a2f031432573c0cb6e1dcf43c5bef015fae73511e6a16e88b80b87f58d32ca5e3187931618cf7d59847a6aa1291c9cdda238f223a79c7e7b9047790b27e2fae2b8b39706fc84f2ffff1e05de980d40568b345daa1b3b00ad4f28a241e20d2fa93293a1f9a3a9d46470daf18e23668f4fdd78326928a196d78c444bde020d1743143cb19430ea71fc3947e957d81620ccb6eeb117933077c20668119a35fad369158ceb0d08295ea3c25b62d1a12383b5967f3849fce9e14e9095cd4281dbfb534a806ab9a16e7b410a1a0a9d3f9701262e305df99d05637a586a5d97533a62605a9e8b0cc1ea0d66c74e4a1f423ade640423bd9a8241a5003646fb584a34a48a59111c6f12a336db6914e0a2e4dc1f87d7399eddee3cab54055c84aafbec284c330cc15c1aae1406828c55047d5e5fba4f6a86e0aff9ecffaec57be51673030156b90f191d4c776610de82af0c5edfbdd925894ab1249344a92a83f93f78c1324cab8cf665325d5e2a3181eeae3c6cf9c0d6f0cb6c7b2a396753634eeb1c567787e554043c16fe2189b54ca7cc1baabe6e3ab1a5abdd5dc9be15ff08288911976d4a5bbb2407304910e9d01bb277489f7eeca0810481e6feba81ec6ec4ce2b4ed6ef32de104324302b063dc9337794915f6a1f9ed051873d04c436d642843b2bc901a8cf151f09d4162c672618bc5d88ef62b2301568d5293048b7a23e6b7bea33789dca604503d07266db3d63f193b3cd13b39c95c37db9e721c55c22adda0a98b2fe5f7533d7e40bce3eec7cdd3301a6ccc587523cdf2fa0d94c9c549bea3067ebfb2101422d928ef5eb23f109ae1ff4e380ad3b4acb6fa24195237a7a4b6c39ccbfe3922c73dca5adc602a95fc8ce3102e0378c32b1e0e163249a14bcc290933685ea8f0c3cb97ecd8370ca5fcb2850f6a9a29577ab5a5cf624fdc9b38162cc9c4529106a6ea2cbee5c27a3ae2b07c37c20b47cc3ba9f7caf91edb62f28b172875d5f05dfb6d417a936078cb46998f848f3885df5052698087b7911729e2e1ecda98df600d9761006ac6323e0238d6727e9cd7adb5a0c519405e9f48aab1259fff10a2408b381aa0902a5f2f9969dbec3e1c0c4b70435863d51a1edad606c655bdd545cdd4d65236283c4e57288e785b6086f2a917759d87ab12dfdc96a02a1bd5599f78768b45549ec09c4ccc570fa72027fef4c1197e34cfa0eb6955cf9e193d67a24cc808530ca860be391c406d9115c07178c979596038295bb8b61dcec2413a7e261cec89b4469feaa4c6a032d79b66f9a7e75f07946963a9ea36df4264cafc9174ca713a4db0d7610a16e75751d756dd86e10588124be023c80050727b8aaea87e16b0bde7154c8c39006d5f89d6620ad0225c25835bb8542941cddd8665cf6d7e26430fcacdff7cd299b5ca1fcc5a09129fafdcaf4538460b806925af4f100820f3a0d87d126ab188b70f540d7ae19f44689c7aaf0205718cd69c0b4c4e515f89efbe1aa22b32c409a832082af46f5bce56fbc48dd6338b85824530c1c0c04f86404bcb33f9337a9fe6a3da6500d51b504aa9e1cc8fdaee169176c30ba00b98e853ce8a971204cc85bf84cc21ad9392a3788cd5c83c2ca53b036a3cdfbbe6798b030ad490cc998b3913789e43ec0463b53a8436d47731cb02051daf53344c12232bed1fee7f48f877616b4ed3c3b9e9df41acea1a8b80811530ac031ad051f15d951c065402ad58b12ed8e4becb0640caa9c4dd37e3bed0b05481820aebe08e6157f89d4b5b42ab15b58de6c61050991d6b4c6071cf1452dbb14481e462554d08d4d010b192c0f6997f7f57bc1eaaae7ae4aba69bd4e232af66cd2769781cfee3dc6e2e74dc41cb91f03f93e161bac773ff5561b67fabb1fbb0db2a5fd8cef7d0ff1d56c5f4670b262f2105e6ce23a8813c1fbcc23fa8b4560aec8cfcd284e30fa9f76a96ea0c60633e04c84a9e1f3014e28b24da02c949cd4137c071666484c859610cf43199224012afbb6509bd4e7008ad10ce0f43484a93abf8081930ecc74ad05987a990f439d5f22777a77855c4244aca314653c016753d001955eac58c0b2e515812710873fc1f57df167b44ff3c24c95dfe69141fe8e24ff8b87ef629d4d99897de88efd7e2e669f43efcd5bd2c4c94368d5901ff9b8e4e45dbc315ece378bd4511c80702ba8da1728b7b5d8b81e4d552b4e6ff50e5cc75bdfeee51677eb7a93cab9a82ebb36e38a56895c5e36296f03fbee35810f05eebd5f8c996179e798f4fe2953b1e64599e0be846c96a98da0a5fc3fafc9cd3e991bf86c327cae3067223860ce4ccc7c3ccb1cd79c4228a2b283813b184fc1c32ba889c92e001f197fbcf166eb736f14a26e9c6074ac33920d538c30aa6fe8c16491d2ec2208016550c392a2d0df2673c9438a7f7ba4058c3fd34da7c026b92569f202e01cc7236bbc8ad9424ca3e196cf326c8db44902a5ea60434f16c80006572283c02f29ade7176a2d48e7eca860152fa29afd3427e7051ff88f7cd1383e448ea332f362fd5a17cc9f31d0e206a70f3357e5d591b66b2f04e34e5524135794eb3846a9921dbdf256d17fc9cc156689f78b1e8a24e36c216c3108bded63bd3aae37ee61ee6b2f72f0a1fd3e609a73575469d5321a34d49c9fc9079209af4e30c36a19472f6c0ea018828db75133d7c5294d12902f8ce313658806c2f334c7696d1ad5c7c3f3f4829636c1f574c673d8a64577f8dbf54e880f230b0c291b94a84f4061c3c97654a75c89134745aa94e62c8d87daf5c41fc981cec4f4807f96da9b8a222f25fc2ef766526f053b986aaf3e3d6e6ef955ef26c35389e04444ee956b6cc5d91e54536b75685db1bdae4b8f13daf7408b6e6c5df39a10c879396b95c66e0b1c4b825b42a16e47a0925d8401b1327c3436ab24265e33ba4e8addb5469d38b24045266f7fdea62d6579e4325aba3e82187d704f7c3b436635a87f8184b90d6263d5ee0709278734451d40f886c8d6342464eb9fa3df8326447ea5348ae8957ac6f706757803842fbd7d2e04be539811f00ab52f6a3ae662682d57f9163c05abcd0fdc8c3542fc931fc91f55530a75db1bc528357b82e682670ccfb7f1f001933d0870407ddfe9e70de13e40076d2fb6631448a58afacfbdabf244151b95a5d681f0aae1323e8eb750410b1ca2f3f970b6b2f068e0cc9652b4e1f3b68ffe7c484f9a9d2b9ce4c2a8d74734df800d95c0dda2f739add32b886efd59ab3d2961833b63a292bcc24669b39a2d47c2f119d12485ba9bf7e2baf2360c58dca10db214249b8cbb4fd430fd8bf808ec8bc92be945633a278301d0cc8e505b7eacdec1994e1d8e1ad529ed48e0331937bd635430d8fa2e2863539eb0b8c05e0ccb22d3570c72465b1f3eb44764ee0f14c057ef09f47c255494c693d663410a006cafd2800d2ee8bdc4aca745eb88428a78a0308afe2168aa5744479495ce9151e5756b62228965a707958d9cd6d4511a095c6d0095e60c84894ce9d0f05e81955d9bb0b64ab1cfe0fb0a446405efe244d6066baa8e340d55e818e53dce9693367ddab88bd48a704e4169e2cf78747b61ee784284749755c75886f7abb3d412382fbc1cf7e3a76ce713e5dd5947717e0bdb8946a15751bae729bfcac102037a19943965cd56cacc3d22415a9bc1222265f8d2dda9b2047d2e82bc664bfa257fd5c328782dbd0a6a60e988c332f7c440a649ab820c3d3ff1f1113090ec5eb30b9117d45b52e211a1f2b0edc8474d0248603cd8f96a018b5465b67db28b2d7ede5799cc534cd498a29a2d0e6cdc49646da5454cf7500dcb6355bb2d710b997bca1c403408a0ee255c80500e195da2f2a5255a998b1b6036c036a4dc3bcd367abd1550d2934cbe75c597bab1cf00cbcffa85e77548d7289de50db88b3f349c3cadce0fdb966ad7394b3593eab3486e5e50868eed4eaa636d42b3152d3040f3ff4205b0d603b5628f7219d5330ace211d8f7239da6d441c25fed0143a99c941f3af4c693090a2add1a3bd40358ebef5d0612ad9135592eeb8ec6ae567a08943cf1257397f1d4c363b56a4b66d2e9953a22e63f5adbcac15ab73a09eb2f3f4aea93e7b7cd644b0a97e3808bf9b83a8d0a7f39087ae01c23f18a03430e32186792ff6788791b7c7d361c6ef3e9e8b31ebccd6ce86306544066d888565eb2ac82bd7e38650712199e9237b062e92c8b67dba904f48c27617c4b1aa6191288d5567bb880017d5d9bc57f555cc0400549c565264df8a419e979ff041bdad00cbebaef1a8bb0b50098fa7a59def8d92675fb4f8ec09855ca5208ed6b2a49eb995b2899307c8e17b9667e007454701b2e3b2bd03979dbff8fa47440b74d25bfd4240ece1e34e32519a54a0083b57920a5900a72028a798c02835edcf698e311a67b033a79d50d20a6e2117dfbc08657eff9926f669f72aa85221f749dbc92967c7ca3a3838dcb42a6db97f28a755c93a5fd906f308088e8140883cb543a2670c46731e32133c5ec47eb4013e9f83873e7f4fdc87aad7b8fea307252ad424c2969c67ace27cc702babe0175b4ec50ca4c648d7b4b77541471ca82775a1b384f9800e55a60ce21ccd111b9739648d436655ddee32f041901cd7265df9004f33274b5bc8e9e08738c2329dc2f27a133015988c1e9f987cbc7b9c750be730df5f883ed6182eae0ecf372a5804a5071289829e97ac6a2f570859cc72187e0ec0d15a713e61097701da86449f7ace1e5308d2b2de3b8d1d542faf310e89afddf1f4ed1a937f338a1ced3c4ff747efc648c1272dd45fe6ee1eb130c609fe0fc9d7ad1d07a3dbdb1811bcfdfaffc7cce4cbc8f1a973958b22ed088221be2e30db12c8decd927848d212e12bdcc3a7c69b460396441d2712f60bd3e93a0e937a3cdb933de889e717b87d186254feedc7ec26e4282441095847f258f7932740d89acbbead72222c8ad05397ceb9c672933be35292c5a8e1c060b83097a601411c0a7b85d1f95f09ea1fa150855036f40d2504550d9151aceaeaf7bb92f38a7a87945d258def95535d1a2a43ecaadfb9abe0745c39a10b12215d7efd5d44f87a77132a513dc786bd703a34bd4537388f8575339ef0ff96546336a37b35505f59acd592f334368a45b70c22650af19d122002cea2f9024729c302cea08e1ac348ce2f4e23159b7bbd5dbac67d4945990d01bd1c716d0b4b76dcbbff8348a9041da312d0b3b56126e852f5ed85e753af80da31bfa44ad582e77c720d0c5bb5c05d97d9a6da81fe66a292ed4b7d5a9f4645512dd19e90d12d89d19fc8be1198b1cacf86193fd225b3f8b5d51980f9d1532e2ace1baad7b7690e99ce378c80873b8ee015e70ab2310c8ef61671661000b8e302b613b5c0f67213209c53af708532301b623864c4ddae168613480b94fb44be6e21158c86d064bac1d0dc9d8abb0e1434bc6c3f194971160344e8b6725d9ad2f1be20ee231f20ad9253865f468d13b280f341929738184070c993b14d60fba13ca7837c2e3ae107559a522e50dc00f7af8d7910264f67ca980779397f30be224a350fa49a13d4835e738164c2f6ed6c5d412c09cd62a0e8a96f344c4d183a8dc992871c34cc495aeee23602da6cdc18d297b4f62b8133b40aa7185854a6015f0cdeaffeb9c4b39c5f4a1ec73990f9eacdaeda935ea024c6f7b69039c1d6856ec7a51fef29f3a54f8cc52e9a2da55a9e9658c6614154152ed981a06cc57750a2c368ca1e97e2a1e002d30c2a7a757d0f8223395a870f002fd0326fc271ca0b4d15d6cd173a80d63e6e185c28151783cde227c2c787962699082ed184def0f3d2ee8b84a2449e922856700a65cd9178b605c9b24e501b88e64a0fe45cc8ee1259f606f20a04bc4dcc5b8560356400961b1e2ea4b48ecebfcf469ab71064e7098f843fd9d5692543e6d25adbc3515e93512a750afccf5654043d9ca3f927e3d1417a6fe584744044307d22292ceb8a571ca3484713bbb20efec17552605877885d8101f0b618989db59b03611be30ba555315165580b63f46d4fae3b0d92004b68d9cadd4c440fc898adca2421ef617bfbbb7e2f697a8310a31a711358afadac360fc601c48a58ed41eea0e059862b73f685a900bac7a0dc7818d02e9e4cacd4d6577b28af21451d961fba4d3c50891ac5ec5ed864bc63fef4a898b529238e01d5728dd5f144c728020a49e3fca31e4c6f93a52e619dcd0bc48a99ea3a3985f2352152bc09409308bd2fc9452cda2320a3a2eb42b17db8841bc4068386712e132658aa863d3dd5036c60458194042fba25cb4eaf0490d357f49b8b612117f4a7e5099eca480876080fb34dd481aa174133e459bd3640da3d209d79dadb1e16bca87cc2c30a966bded620f8f50564cb13b22fb49a63554c73df985e639ef5edda5b522a354eb87bac9493bc6925b702e4194f73090d12bd80a324e69437e4dfaac86703e71d63adf8604135b8875689bf8e62c23f510f1b84193069b7a7fa72bb8a908f2d0ddf653046f957ca9d42809f1dfc9405f2699b77e0579019af04be69003f13ae1d0f217e8dd96c576c35b31903e7df190e2fd12ee1718031e289ed741608231b3535793e6f268c552c298f75aaf56a9eb30597e8a3b50d455d0ed23c1c218a3618ce425c4e1f13ca09600e28afa43ed684a2b1531bc15305155ae344a6b15321fa38c87a764995f64fef7e9f54f1b06d9d909006c9bab3b64cf9a9cfab43c07a54cdc1355b1f3b727a59ce60f5eff1aa90e50e4d0c7c5f26b6b88d79beba9514a1c3b27934517e1e87e02bd101f136fc4b05c81f4b137210f10e3240e872ab9223c6948bf55a4f30450f3a0f3107ac6da2d6fa42155998234fad2b1427721a82044625f4d9575ba8585c57a190a6e2cc5ca4509a0080228e01323cad4d396f5aa635203162341854b3f651edd4e2639fd81baedcfdc5673a605553902a233c3387a1772dba60120b9f48fe6e530c94da062b7513f96388957ac0911b66b815aec711997c30d0024d9cced1f0ea5c4bf90e8b51c65ee9598c43624c375364684ad69946869da2b265acf5f80229ee6c21f77053cf2b2bf9bd353ee174e4bf4418505c30d30e292b3f397f45f3826680a9a7f7bef2051ae0b3864e05177b43a8015fafcdca811d2bb7f950851ec3af56750e5a0c38cc10c4c78751759c07e6346e16bfc1cfcdd86734f284a5a90832b351c2ddbd2395213d43fa312d551931d8dcdb4d8339df158ca650e45e6e907bf4c1a1d08199f83ae59c609a0047467b22706a9a3a9255630fdc1c8d351bd296642832d4b097b2d0b020d33ef5094fbd762700f8a2ae23991be6251b84de697a2c905f066581d781ed2cd4749dc31554a47fda0f93a289af10f35e652e87fe1163c2990f7fa3197505913459d95606ce11b4cb000b28c4214a0441f3710a516cb5032883157c1fc3941b81bed4a72602106118e8a75541ffc8c19abef1f89af29a0367a55481c76aad695463d8eaa92b9420da86206810967309198b9ab31ff900d3b49d0c1cd00e6ee261a65386ccba94b00425349b67c7cae63a6c75b9b09e0d23afcb80840966b1ef4b9e61b26b5442803523c0473799253888517ac24cbec497849be0c81cf08298ec7b8648acdb4a8190a5838e2305398d5d1ceceda7724e5e3e56f745b34470eb82ba988f9884267dc2072726c0e84029bcaf922007358d002d498a35852479aaf411e005bac6218fc2f4232384686fbc6bd76f97f62ee2d75a08128014028a22480ff2f0b40f42b9395fd2161149cc433aff79195d83e343bbee01f5a31c8eda51f2d0f48ad873d3895a91ba0dc510a4b27cb05e92de87b16a8a42ec0b22e1777c448442466f162e9da4c9f97cb03fbf7d16b411aad565258741ae49c5172d600cfd660987e0b651ce92ffc0df8bc25290d1fa64373dce021f49ed07dd0cc86e0f1fede0ec6d43432064af5ef2fa1853eaadfb20203d43b9f5e7a67f1a2a816bb3cdc62279e13bf0077ac5f0414a7d1140b900666bde6a77cc15d191dbcb7147778dd4073ef8abbe0209955676908a17d34395f0ce9690c9533929efa6aff70c83cbbe0e965f2e60a10d8d9cd8481563200d9ec6e03320839eb8194b65c637c3a590025147d1de26b22f44bd7d3f15770eb76fdb7edfb3a789094039ef383153b5ccc8d1e6691419c63931e3ece1f24d27bd8307084da24ee3390d80f7689ebc7abc4c4bfc898dba89133b32a3f63ca79a92878196ac30cf0114b46399ac3436e2032710aa3c25d3a4981122072c9ba92c2830768ee42897576e90c2e294f2c53d36390e5d3d9a52ddc39b98e6135dc1186731926552928be66896506db80258e09cb1e0fafb420b8342dbff64973767bd90b6bb3c38d855cfe6b3ae07ba04cb216c55787899c8a6d8213a82741c52474a24e40ddcbff4957d54c3d7116d3221bf0e863209e6d512547ecd7959d19b62329576873128c849cb9b3a1061f0ec448689bed43605789d4632e422bab784a097ad0b420b42a7c0df72f1034896d2265d7573c9ef7fc34c8711d920a24d2abcd99295748258cd1238278d9c487887459ad5241f3878bfe20eb6ec430dc5909c082482765b48f36000895cc5c2647896ffe5d965979766f576844cd6f3d281a0a5844c21bd875d63d7caf050369fd7a267233e706da976fb749518cfcdda598df90118bb2f3c8e80fe04332d6e8ccf88098835aa5060600a1c2cf53f1861edf98f7a9f1c5cfc4c44fb154e05b14487f9b72a790946d53579b61f94831ad848fc99a8551971fd3793cf50640e2e6a07726fea9d04a817b3a2d1c1a305678f69eaae6df246b06a2291eff857028c42b1a1a1acf2f626b0a862d2172b7767012a19689e8e6400ff7df4ae484915e6d8a5cec5dfdfd4718d1ae74cd614649edf74027b776583330e38dab308fa714c0fc57baf757eccc45ba99a88ee54067a41a4a9a0d0cf0c3e0648d5a3e46194f1ab83a4733fa3aa4594d55e3021d3d0b80e64852cee7dfdc868d4d4b5a6fc34a15edfdafac7bd63f765ab7d331c194934052fd4c5d41358a786d90a039564c041b72c4824220938e50610f540880cb6d40ae54482918a87bbaf1f02bc8f314cc242530048225a9e70009f21b33b411d4af8a2a9843ad708ad0ebc8461c8bbaf175d187c4673249e5a84b74945298e72780ce08548a3c1dd1154a167c2422a6d9ee5997f8f021933feaf87fb9ae1de42edd79a94f2df54b96227d763984723902ab65e7255e46a576b7cb0b6db105fe2d817b6a3138a29748570bedc7f524bde2143b49a29f08e567bc541b20f849608aa20081a67a568cbc6e0eb6c821fe44de8b9e76282ec83a8d0eb8c60ea4ad2de521b45cf0cc9e0f1ba1b083d935b3be0238beeb48c574f8024003badabf008c116e8d3a1e61920d38bc6276d0449575df05cdba3009d56c0254ec39639c68afbe0d2684646cda5c6bfc8eb8e4f300bcd119dc8dcc2e44e2b7402b07c33edc0d8043ccae8bc277fe95f65ecbc4ecede2eb215d51264c8073560667264c198802867b814cb8bab9a88d4b14e62756d94bd12d5a41b7488dc64f337be2b4ef49810a5509b9a3faecde68e1e4f6ad680233cd219fd303cbe33018f0d41c1bb344ec3b8b991f2581e38fa21ef4314d4ae7f0d4a1253d20cfd394419453065bec9d42823dd8239d93a33203f3135229472e359e0f14d9a5502f593cda5b59aedbee9126fb756d3353ef593966c40902e2525181d2ab858c66130963d8c5ca7ffc02f44bdc0e33f10161e285333d9cc5fdf6689dba8bb477ecb2ade55c28e4c4a976b1ee15c9bb00cc850ef4dfd5ae52af83497ed3bbe20230814afea61d61794cb2385ed55773f838be1c504b7738610d8228e6913dfd7b2b05033ce3bf54972d0560ef3cc1ee1df8f75e1111f367f6a7b965390c23efef874dfd935ec6ca240a0bbc6c527dc5693ae8f7c12405b88281b78c899355f2e61963aa9ba9d23b84dc6d80bee6483fd7c86c3d50b72098a5f66b623015904eb9da051ec87023d58351cfc8e06dac3333c510458b241989545b985fc75e6186ab2245e05ce22dcbd2fad62ae1e558c10a43d2f304f740dd44f76714a0941ae0582680293cde36f33579caaec218bc155b1ab598f437a0fb378b787691ad4045197dc240f7d7f1235484a4e8d5181489193a21fe5b208ba4ad9fe6c2d824b2c669e17fab3dbf15ca3b3a59e72382877eeeb8b5358044d1873c1a969620b1226b6df8b80855db63c108519077ff79bf7baf35818872816300b742881dc323f87e9bf9151c0dacf44abae5a6a56616ff9f7ca8654d53d31974cd682608438fdb48a9662406106fe0a769d238f9d0c824a5774560aaff126b133f4a357cc9231ff9c0e85f824f5cde24f2309e0190692c4035625afa504f5cc2f5c816cef2b9e8e911ce37600b668ae8dd97b4fbf842a7a33f30b6f7a02294cffcb08eee356ad84346f94077b5aaaabbe448b6e90291cff4d8a5ae79294228df3de416c0102883404cf81f9d63c51dd7f5a223b4f31e5cf148ca795cfe2b9eff3e6715cb887edcd2e8b06507f833babd845d3356eb460c634acef09aa31ed476505a022205a4a0f7aa770affdee047cc24d151e5c091564aa48456f6d8f21f5a91b087079d6abd260449ab13b8fd8042cd4c4cbe86058175c28b1e77aedbce2ce0d26fa6fc9fea0e2a4b4b09850b8080e679ac5110b5250d8b4cb273babc0b78360142edbf621455a7f9903a23fb33754e8c4528bc7e6d7488c03c7c7a658e34be1ed4ad81b0d07f728027ed205253384cf5576752046a63594640e90b19a054e8d772a77e310ed4561e938c6423c705175f5302284ba9ba59f93481b14bda5208ef5628afe5b7e8d7d7b96e28d9be4652cb2f433d44aa05d80699791ba057d141300476f1b54e60db105a0ecae1580a38628b2ad681907b3df955ec2778f932aca95b21c00398508702905b07038f981251b08812827ea8d6aabfbb1916f6c253e91581068369c91880dd52fb643394dbdd637a7baf68652f4d9cd5d0d535b7b43a7a1b7b888394ebfa5f4c97b01ef1bc6b8f7274c3a174dd9679c1025b08b057659bf6a66d8d0babb1563d00e7e980602526f52a145fffc6d7de8190fb68b25a00dfe8fd85b90a60f88347ed24a0fa45a2a23bdd8a68c51123429457d27f638cbb786cb0c267e665d4394cda117d13ed834c8ce2be439f8bcfc520778cc8614b69328f2f86869817fb43cf4c4efae2ddb565156ae26cdce72fcdfd620163c05042750b1937996bcbb5acbe1001215670b2f2b5176a602867d834650894c620c77198feb37e2767852578cd35471bb0e01459be2844c58ec9fee50df28fb250bf73798f341d090ada43bcd892da8d804011be2327ff579f2f4d0e0be5143913a83827a293f011c16e17150aa1aa5d8fb9036d09ea674374eb86e7ccdf28348dff28cee47bd07a5ad9540b19279879ab07ca8d21428b27b880c587bd3190d17854598c3618e7abeb1e4c1cbd1a456bfd7028da41b3b3f986ec871d86f1020c46bc0af0e0240dbb6c3c6eff190b333f58ef1512c8c76b6cf34abdc79d477ce30fe9d11783d656c212d84f4cf81213cbae413dc9ddc6d65990236e2890b290114c3d129272fce5e42c333045bc83c08551b18c88aa9c6d40c667443f77d6595777e59b7f7c3995453b3fffbba07287011338543cb92c17f3d10f9e7b022b7843a3cf7853e96a91b4fabdbaa304e0cb34398dba7f0ba1ac211b24ba03a0f95f8e8f388ff1c109a6588f9a4ff7715f9b17e18ee0111426cc85f7d877822c3ce0778e6104ca7513b4c044136a84f68957bfb1b2d07f2f6eb72e820d0bc134cb4c6767ac7d0030ab4eb12cd9ba447aa7ca0cceea0c62bd0698e2f3599d770903d8a38ce72ba20c3cba504081a11bcc5e62efd610ad18ee6675429a64f331ee7153291bb9034f2a870da93fa819a8a88db618c3b52f8b91282369315d48a703eb4be6dd9fc45534633e2745f085508d60ca27b6668129932046d93707b59114236128e835c78d39526c838122683f677b353cddfd22dc09b6b307a68452074db7d32db3815422ba5f8bb9773166c8803eb00ffcffba1a1080e57df2b12d056784e8869a7094f967d129e4394cb5a378baf7e8a910002061822e7269c772a35d39486f04fc2e20c2570a82d5166c43ff614cc8033106355c8cff7b343d1829b050b04a277b82e88d14decc6420489dcfb414c654e0bea9e7dd904ce491750b769b7bd271c94a21ea55031592564279dfc0329418ab7b0303576f310741994d433e614199c6543e7f63acf35d6d5098b22eb3336394f326b67dddc1bded7c452119deccdb99916197f2377523f00ea0eb33f7291a0c9d0cedc851466f65b0a36b66c6d13cd812a684f780d54fe43a4e4c575c6415ba2b5cb0a5eab207c53768d521aa8f99221b41097f0b498a3b004bf46bdb0e2df08573352859d81c7443467df67ceb99e847e34e5573d6c565c713e21279361f74ce436a31737b0649aa6821b9fa88fdb34e80544e65333a41637703f24140e3e82dad8486b30cb4b84322d0e4ceebe3d06ca726281ca81472739f65417d03012f6f1bf4b463822a185200aaf55f6ed5a30bd9c429b5b2051ffba7aba44de0f39f1f31872d8272e08be4d54bc86a347f594e7f0e959d22100e7276a94a18e0f6abef0da308cd78171a18e42784ce5f3296e9d3332382ef70e9d4230d5d36e60c44704f2e4a728932e171ac3e5c83b45942d75748849d29a01877bec756e4b55d3200ffba262f9fe8e6435fcad532ec7d1e254b37093d91b0858266a3c631979277caee42c396a46ac485f4c172287bbcbad5e6b270b95aa47c25ee36578a1f3da9c23cbedf7fd9d504fd27d09aa7113ed97993c4a7ddc0e769451478a79b5ae614280184bafa60fb1624553cad08b0bdac40cbe38a309602a533dfca2258a5a9a8354161df316a644ef395a30679bc9e14b7ddcc4edab072f75e47e646d3b37d4b7624072d2b542eada8908207b62e47c56a77e50b4a57278a6eaf87e92b8b6aaaaab195e5977a73c17e051018b2684cbea30bf1305012861a3827c876ab6e7155fb2351115cf7c301d448929553025d8a57da748d034d9eabc57b61c82d42dd33ac27848c4e267fce2e58d0aa4aa79eedd60ff3a88b00da972e167c3a031a1c066c5c30542a520730327d79eacfa1c1627f5d5324c6b21cb3220c49738e953617e9750262a53182e45006dfd1092918320cf442a6d6c40f00287a1fe5140fa47975d520eee10b6a0a32e583f7b51783fbc03fa234b4f7de5b4a29b74c4906af06ae06a10659a3af49929aa669da67051e4158ff0d7d0607730e9641b0044e127dcd7efa7af5197996c0bcf291f66af1061e4c99be7bb7d91fe9cb4bf4354920f8025f207d81d68216b420bd44b65902411b5e540a4eab28a592ca7b5ff831dbbdc87151ee5a554de8e40c4a50deab864fd7f29177b20e4ac7d3f974b1ee49f7ea7aeabd1883e0bf486369ac7b3106c199ae1bc7fa33040dcb778797f7d1229aa087128d77791aef2d1f4a9236d2cc3b3556cbbbbc8be8c3e55b78f0214314193517eb8edaab003ab57ef7350c41c3320dfdb5be1270bfcd6cebc92f4767bbd6fd97d0c70e4108e307a59796acd9f1d184d9e1723f0a7809fc96106647cbc33c8ce803e65bbe875247239c3e21cc8e1a4fe36b88d307667b1a5fe36142981d007898078038614498ed6b88da093563ba04b3893278097c509c3444cdd4795b6ca0ef5c35954aa5ba5497ea525d4a0bacb1ba96a3ba2478d45c3eda5e6ba97c0e37afbcbfc6f2d2472ce2d820f82b2adeabccd28a0a187aa96b4dd2f6ea56421c72c09bbc517f7bb5b460ecbd5440d05192c751a29625979790044b800529e1b06b8dde178e221e58a3f736a8c0a3c82594a50ee9b758d10745f2bc118676e3097ef9a83b978f70c8e176ad496aa1a89696bf96354b3724c1cd56bceeb5845ed25893d4dddbb57437c62dd7ef5a35ac227bfd118f9d2bfb6d6911bb56f66f75d7f059f11a2d21b5d6edd67b5b7062ceed6e97a6d280753aa15a3c37ac20ab9d54cee9e472d9f4b4cd24dd3bbd5b6bfdfa6914a9a7134a13c205766aa7161ea5eb09653c14d94577819469c93631a8f2145558a1e37446c1d1399d52a6393bd539cb3627570ae7743ab138279d9c41c6da61edc87698d4aa7365cdd7e33ac0aeb530e40796f4a3df614aa6610ecfed4deb575aa9ad1f133a6bdfd2b8a8fe48f335406a1f13ea770853c506d8dcdfdfb976a569edc58486862685d345717da66aae266c36993a33c7357b266beedce9dd56ebb66e6b92bc87817bd05f0c762a90d8aa944c66e3083c5bad4e4dd56d5d28401a38d4b26104f71c22657c22d131ae028dbc6691a9ba05388088851ba28b80db9235dd57c8187f2d2ee8a461ac7bc44776aaa66aaab64db5737dae7b5b98a1525570857a6badb5d6f9b5860bf06722f7b5251c218fe0976f8481c75be9b5563563544ee8e40c3dc071cdb5d95076b2c4deddddb5697f7748290c8f3707a1f30ca6f0d8280976dd4d7c622e7a0902fba85f86d314ce5312bc655973bf1f9c29a40082feb3bec4e18a0e8594e997a819d3e30d732b19e592dc4272479192322b6894aae74daa57a12765a35c5405961f8eaf089e736a5a6be22891905bfbc096a59439f9e96364cd69e209ea28408c94916f001e3c8229c8008f379ffca673eb90358d6a01ecbf176310fc51348174355ae858ffbd18779fa4b740159e27938bda0b321d75dac1f28774563649d8ed87b00daf94711b4b70ff783315af6c802c6154a472473dbac926e9ce100e891fc6e29743cb37f419eed119e7e373412064eb472bd62f8ab96cb656dd64773e286e32d0e6141ce051bac6de9ed3a67d074892941f008720aff8809419fbc4fde0832c432ea142c121d1ba668cfde1ee0fe7334916f620882f0d2638233dda4c9ef2a0ef219a747d668c3f3602442256e40649da6432c61f1c5d3636c81afb791db73de733492cbff2e3e57c5a93b4695b0b4f15b11512b756f6df4c3e6a232df2078963db203b90eca314633bdd8b41f1b49d681879c918ff2a6fbdad49aaa619139ba40ade96e9b6fe417c63637dd91fab44922ccabae47d293529779053c4d18a91dd2a713b457671b4575894d502b443c8fed5a2462bb34fd81f29e34282c74d969a651b8cd468b1010f929095e0f179cc2481479a041ebf7e1400b2f22c8f452098ce7c648720456e8bf09a311b0862fc32ddab526d55e53b2ef2f0875b72f9966779ebf21772a7bf10b2bf4b0bcb4a68235bf01ba46c0201be5eff2088b1b441caf8bb5abfb5f2f6c4456e834a98e50bfea110873c803f0e73c816fc4115de7e36998b9cc6b6a05e482ee44808723441303627bfc936d9ed4c29be8212458cb8b1d65ad97d31f8abd9c454f9160abdd4127649c525f4d14bc6407286c6793d4dbe25fcf8028c262526bee761c60853102526ba779796169a19d1ab84b2f4b343a12c6da173afb2b9f8a86613f9c78a0042c0238d01097d4b4b48728155dee5c7b796529a3b1595775151117da87ce87dac3c8bb5945a4ae7addb76eba4d4f32ceddafb44e9221b2f8c81c5f5052d82244d93290c54138af0282a97359d5045f8536affd5719dcaca4a284b5ad82a9a1575d8bce8ff019023edfd092047d3fa8763aac8dbb3149a09c2d62decac5a2941672db601b5a594524a298397baef3e1a1206eeb91f51e07e542177ab8ed53dd185b274044ea9613d855d6a295b18eb090e305613e417fc3b19c891944dc80a44ea89ec5dea9048ca73e1e99652b89217c2ece8de7baffb1e4a5d1752d80eefbbf7440a83e98749113f11a6df1367316335e5e69e13a9ac13e90fdee1defefc7bef953de0968bdcebb8b05bcd98aaea56432489b2644d8334aa8a5563072b22b27fc7a411605f761d4fee1bda53147522a90c456528944c65bfbbf73b6e53adbad5dcbad5f696e33e9c25392f765d074109996cccda8ef9c84f37fd45939907691994ec6fa5fcfff7bf17e37fed27c94b3333221108c6bec5d1fe4ab6df59399a6fa9385221538e6aadd4cecf7af4deef98ac198002c490ff019097057c00c97a2905b803dc2cdb185b1e72c6c3061db449bfbb630f86ff321fd9273eaab158ec5e1c95096406a5dddd578aafd2f6b49af2039e4fefbdb576d1692b685f5e02cffce1b837f75e792578ef8c66c3ed0d354d6b10cc013601d7096edb0d0a92508152a0948f1cf402f580724038a016880968053a72ed0c4b094a6126c8513db9280b89b10832060a0c9417988bec8f8d341642622730c803bc240a70093ce40aa950be3c8252a0d4174eb2312f64cd4cb1fc0882921df424fb83a490a025b286be3f088996352cc89a9bfd4143648df62a3f82b8c80eca42e21f415480a2001919414540a96f05b68823c822c662208843e288b1385e90088252a8140a94b29ded6c922a8bc562d9d9f79aa40a83853277ae28d4a366adac49b271b15c2c174b7b99bb864d924f37edecde7bef97e376db6802d390e6eed6530dc2bab7da6f8585c02e19949235dffb83563e9a818448d28bcb8fa02149b8fc0822f2bd403adb77837c2f3bbba70f257e27177da76cc99031fe3f806865213e979d81522c2cedf2dbd7938f3e938bb43c7ea63cd653febed58cf94ea813ea8402418c572fd8f7827d2f98679b602c4222e0bbb8fc8bcb9f6e09fccfe423cc04293a4d12ce42c6e031b2fff80101e3e4c5898b93132146ad26091be998d724611e2c59e128564b804330fe5ed91fa4034abd80ac8f27da18a813471be3c41b616096958fae9de5647f906a03a526e9e539ee3b97d04b7636492050caceec2c75efc41894da5c5cb67f0967e927890a41c634c541c7f4fb0b644cff185409b98ff003b0073ac84d93c84d99c85d83dce2e83510500a94e23889236590489920489914587c851ffa8a5cb8207867ba006b8030520539d2be2f5716dc6fd85903af054170db2a1555989153051743d4efca51fd76cffdb50604f6a761bd955a9bc20142d378b8fb4c1723ee5ca021067af0808235916646268147dc5a4ce341e9cd0f16f7f6b8f7e2173c6d60803ba37ca4390cdcdb4ae4f4a5ee7b7c2031cb184f112f0cdded7054392b1d17b1668cead640d6c3479e05d03939d4d02d5b5a1daf8d6c92f40129cbb751d0a49f3163936c668c8348602386c83ec83268a800ebe043ca1b60e04dec11042c4b2dc412288aa03295c6bf60172e59adc1dad0a304019b05e4b0596852b3917d95c91e382a94a70448d3eef546e10c3c52d56b6a1f8bc160af97cbd56addabfaa9335923ab4f3d52772a4f65527b6a131aab4054d5447572706a9057ab57b29fd6c4d6a1aa16a9aaa736e98d356d35b0b9c6194d55502ef3512ac7a1a0e669e2f86c02c9fe5776aa533eadfbe3edd033ed54a7f2155d0c49e264cd00b2bf3ff11f5953ef8fa093c1892e4b79a74cb2468d915d96923e353807686749c697a54309411b2cc0a348e44e5679fe9065d903274ef24b13f6b759a29d8875ca65b3283eb22e7399cbb60d47b5a302224203e9a299442767701293561451032e879c3cb16d3adde303ecdad4444c8899decb1aa7d92ec75955ceaa1aa176adb2caee9eb5e5cf5a6bad32c65ff492fd09a0657f9ae5155c08017402ae2291fbe04a070441902b882260ab152bf6c51198ceab498b67b53255934e7ba111fcee3ad4b6b7f1ed2f0e3dcb3b0c2bdd4ef69fb3399bb31933eba8d75ad01497ed9df5aac9544dd5544d9aa7759e5c752b59f33e9a14f0d2ca8742981d21960f7d0f25951066878a0a8b0b0bcbb788d307e63ecbb7bcbccbbfb4dc955f61f1b6b829a0f756563e659640292ba7d3e904da4edd296565c5bbb6a442ff0bc72e77fdea7ba3a732ce1b61e0ae43a15ee5968f6a351d61ad2629f4db4651a10e85422f55d3247577655a55d3ed561d925eb13a14ead5aa6129f00ce1e48404090c491794de7b7bfefe7d59e37792feefdf1c5f7e2b287d5993614c5d9bf6a47931a1a1a1b13e742e41f075ec580100344c442eb406829aa65120648765a7af19e35d4f53da1fa5d40919e3ef2ceaf5cf0fc747a58f68f80529630ff973a034f46bb7e7b6cd6da3c17e3fed6e59a9b672515b7777597be5a2dc9ac872571e672b259425d32479a20f26baf7d7c1fb5b6a94ea8636b9383588c0579572912c7122133c2669422163fc954c71c56cddd4a7e323eda66eeaa66abd49bdb0cc7e64139baa299dd49c335553aea5288147e98ae5da12028f34250aecdfac19a0c3c64574564609664f386396822293c6644d96325a4852a963fcb58861217930041b5b71aaaaa65c24a40ea94ba46cee55fd7442482939c975af7ad5dce77144bcb76104d3a7d408ae79bcf47ede275e2ee546381279f422d9473792fdbb8c266560c66cd1249ba921010e815190fd65bb0f4b68243411a4cfcacab9faf007fc63efc46cc7ea43e0e6fb34d472573d1b46f046432ff70753047bcf7d0d24f00d977be59a244f5c62b5f5138e0910b8619cd82f93ace99894b9f92149adc59bfa898bba73809be51ba04166c0037234e5ece5d3ab496a6d5eeedacab95c6eeb9dc91de3b64eb5e3e2e17c050910abd6da5d43cfee55af3d18eebdd7b282d8d817f6a5439bd45a6b2db7fd9d28a8b015227d7c92eefc8f3579bd74509fdb03ade59d4980d79aa4dd9412c008dca94e512134459b7e539474a29333b44c4ef83801e504847b657cc05aa61a27371b69064704ffa5dabd54abd7aa76b856add80d206b6a5702fc294760cf2161b82b1f5510b4b6de2477d68ebb1d87c2113ca6cfe9022192d61feb91ab9349df4823b47d6215e2559a9aaaa99a8ac5786c9b8b5342698f4e8e21b0d6841d14b400e3278f334fa790a3f94b3089c17e47edd30fc77daafd536d25656c1228a5140533f0fcceddbb56cda773f9d3c77b3cd633baa0d16aaf76eff4bed5dead7af26e5ce7699e37bd3dc975de97a2a5a44cef14e9c92f4c01cd78292947b27c102bcb108721cf51d15454a6b78aab5c247f06c581b809ca0ccacf8ba707c6f3e271758eaa6fb27c2dd5289f3f997e9101e982e4718166c645f2db7d4e4da355ab757ad7f639358dd26a356ba7b7d568add6debb711ac74d6fcede6de3b8aef33eedfba6f7c7759ef77d2929a00681bcc6d8eb50c86b95156d65657aafc870bcb2a5c5932e2fa00682d31b0c752a2b2b5e87234b96cfc292a3c5e5457b7999de2f3705a66f0a0c04f22882dca2c35c249f6500d66dd7eefdda2d657777df1a262b6bde276d44c1f46d44c1f54519aeefa591fddf3658154f4c1a0d4dd32ce10a9a28b79bfb70f48703d348f1831779942f005cb0898f8b288cf6e088a107fdf9913f343fe091c2261259d395e298344d03d2c8fae1d0969cf144ee1918606dd2507a53bb15c77192933dba677a1cc7719c362ff5b8b045c6f8b7cc961a462041206f90a38a0006f48deb131ba2a360a67285be95a3fa34d39792fe9423fb74863d421b943ca0023a1ac904e468be832fca89b238d29cebb6deb7716eeb3a6ebb3b52c6c5c3b5e70312b01878988260604703913e92c6a07282898c9b5a2b16a62b664ba4c05922c5cd9224b18f022603fc94eebb1f81bb57a07fbf451b9a48b4c3c74bab64ff8a520358c2ae486518ec48f6df9101ffa2739166c6f8cc09ff4c184130a0da20010711d091834397301f1fd1d760b0186afde1ca784175612530a8b3a104c679bc35769a3d40154e99527eb0ab72a12df7081bc5891fd844f944cd2df649cad088e1b19a7ca829a827b09505d995c0f5d61e2eb2b1f55e1c5575794c306255f444294afa8dbf07f195ef788aca6e3f39ea4f334564949c31de163c279a948f288e8fb4d3e954ab555516149aa6c3db2a0a02d6a1672d6734756d9541da3aa7ad72c62065fcb5a903a5379adb19c7d1d0bc94526edbb66d311cb771db0df38cbe0206832169edfce83c26ea449240ef1b48a44e404a06587fd0c8b64bf3dea554393a9c7739b07bef6bb3df4be7be5e3d701cc7711dd61cbb4ae2b31b1578a43fd4c7b5ca5ba54d9008a0ef4fc790355c23808a350931e4a80e51fd7062255271aaeaa57a7dddb66d5dbc602f8e7b75ddab7b752f6ef3ac8f0f75b95cf9be70a77cdd7ba9be2609bff0ebbbee3df1fb52c259e23e54070bd980fe63c0c60aae9e9904dc6fb55aad56ab455b2dcfe3d568ab0c4ae2e4f7ac230e43f7ffd64927571871f63ec1ec864161ffeef66e17afc43c9d4451144d51176542716e288bf25015d591f7de7b294a24ea165194524a29a5946a934e22b659c002cf3c8ab26bef798cbfc6b9c6e05c98b3229cc1c859915d83c1a23c6585ac91d9da0803cf1fb926b2b7a40c0e1e298a537139148542dda4382f05d65a2b6d576aadb5d63640646d15dd0bab3b94760f4a9ff69035607633b27f9aa6dd39653d54789432d167517ac420958209ffa093ae2a6bed63e86005ef9fd2047034345a9f5ce0666a04ae8e1703ae8dcb5a8b011eb31db318ae9c715bd7e5ac7454a128405452dab4a5943e8f704da31a95966a56a3fef36597c9a61aea6399a49454d29e99e9992470c65ec85bf6ef80f410a56105bc68db614bfe06f4dbb799daccc133112a655e09f088b3e7509e89c578d48a4ddc12275494527abdb384c9e0264b496aff6aa54d6055d6dab5259df5dc2e8fa2a6b3d96c8643e63a9ba1b3d99c5571047d76a5bc9f8c91a4dc429ed9026b333a58fb6062d8fed2ee400d36af9c52061992742b10f5072543caf8156919ed43458110540999ce9e80671a4b6369300dd3f7c2f426c274157774cf953a11a6c518bc1e4a363a668c57139d69b4d20aead134cd6a76feedd6640d2bace0b1262e72edcb028f7ff38fb74fd514914dac381ef30595c55ce42f6b5a2b82dbab358994f10f8d186b92ecaf4d2d89ac9199c6480ca0504852f8b4353e6d3d6d3d6dbd0d100c856cfa5dc99de28afc55faaa148e0b54c5cfeb059b79407a7e98c8a2c434914847d439bdf7e290247553742fdcbdb0acf962af0e266bbaecdff5f848eb66dd4ff7aa28fbd3bd94e01647ca438385b56e11a6473beb623547cbe37d614e0952c67f9a7ce436cb2e08f7d3e174aa6ed51de9b4e6663e1a3925f873ce45e194d05aa7c2dda93375dd8f05a2a2640dfdf691105e8564af2fc85e8fd85435e7327191d3bb754d54dd6bc67817bbb0fbea5ed4755fd9ab10427e86984e1585638e9bf86876af4c531ed3afcd77b95a7914f528caafecff0a1dc167b0e224ad18020b56329705e8a7d6978eca6d9576208d206ccc8cd72586b51f6724a082944590228c03faedf8e5086c9c4c0bb0cbb40077c581c3043617c4fece2fbf6211d8bf2350e78f366cf8ab521d291cd00fe753dda66c4e85529fd893c5a9337fadde98613124e9beacf94cb37ffdb1a64a46f62abb95de999469327efc746cc6f897ab2cef00cf6ed645a93299b52ea82a3a390312a2e0e095240707ab262196bbbbbbbbbb53f7588c878ef3a0f46b800c0bb6dc55ef4fb2e60594aca1ed271eef446c522341258f9f47cebf6552060b7c8231827b868de322203f31384ca04f32e3a0e2d8aa5025832e8c3dc543d6041965cc4f17902407622626260c654cfa29e627dfa97102dc2df32978f829c4f2ace828a593ce8f8227a59452ba5d90eb4e978b8697052c7097c7cb02161866cb5e8b209778044c5b6e9fdec09338fda99235da5b24dc8e8b6e20475c1229724e8a24dd102ac8a3a70449766ec79f4be2b31b420935499959af9062c810d9a50c0e9dc757f25206854c45ed002a3c82fe8cac3d0eed92359d03854ce787539b09e2ff6bbd49a9b838d94acb356654abb5d65ae5bdb36728bff6c497c8955f4d514a2bad3417e6cac9f7df46114cbb6b58838cd93c3efd701009d56a43ce81731102a7d150e8c386908c651abc1fef836cccd42063b99f7bfa4de0b6387ae26b3de41a4a71d4be1373e01250f28294006f3fd2a484561cb53c1209556a6d288503f37470ee409a66adb5b4d2f95aa85d0d671befb1ae6aaab54d02e89d20ab56f59146552b93c9643299cecc8c480482a2998e0111478e50f2c14302c6e0c28cd2cbf330938202468989ee5f4426ac7d2213c4be7c4d39f8aaaaa2dddddedb30049287a7274b180fcf8d2c613c37b95f777adf6255c99ba969c6e4405da40213b83ecedbb8ac6255b1ac5c7bc44542f0d82dd1b25cf402fda842b660e83a06abacbf43322cba4615f28b8ae3adf9135fcaac5253f59a6cde8bb14c5465a2faa3a8fdde0fc708001d7ad8c9ddc391dca2fd6a5fab9aa67d875d6badf5d6dfe1e55d7e07f05bbe869f45526e6d6a79f07770f997dfa1e5c1af219853fc83e9b7c0cbbbbc05c06ff9fe605a94e1e55dbe8a3bc06fa93c1f7595947117cec055664f40fad4a6da377c096b903c3546f060e5b25f9ff48d8b5226df5a50f5a7ca5c247dbea840dae4222732c6bf8a51c9f8b13f6655d6a62aabd464325daaba49e1d8155781081bc09ad2eea63db5d6eaa294525a2ba594525a002623d8b5e3ee57d16e1dadf53bee7620052948c17bc10b5eb06e6205c16b2f8afba67871a56eeaaaeeebf6dc9c8b735b97c95ddd9652ce56ab355b2d516bb674b00f39058c08224a3e78f02024297dcf030c114bf8e009253a445e95ac91d9bb295913622796c8fe294de0f11ed1c973c7455be0e992b317c646cdd624dd8b3108fe8b44ad992e70f73b789ff23b7cdf3d8c0cdea7bc05be0e7287ac6e6a871d52defb1dbaff9e4a29a54d1258ca929761644879ef2dd0fda7438a7853239dd94802b738de237446837dedfd79c8d7d53d671569a0e298812c5b4a29bb069f97a8e44d77e6bc54440200000553150000200c0a86c30181583c2ed8f5561f14000d6a7a4e7a543c9a08c4418ec3280819648c31060063000122404244580dd11854192e065812155c86e2898cf2be5eb7a861768fca1b921183262839a67f06ed84b55bba4c20ded11a4daf6915b3445f91d245332dedf8d9493a83b74192da0ceeef6f8c2e0e40018993c695061d05ee1878ac108aaccea168f9fe238a4ea040eae9589c700d94b50e074ada848ca330aab7548905f2c22a166cc728b43fd05c8c5549771ade9f25dc2adb7f3326784d2baf77e71415afe5da8f71bb023284fe716a7f66d2697edee2a33822559b3776d4f1a2314dc6d0db3f1b85b2dc5dcc8a750a0daec1b5c0101de58fbc7d5e5466d615cfb2082f2adad8458c685416dbf685d1e55376ed5d7313fcf0a1466559d9d05adfaf6352d94675c959149509b00e2515c6404dcb00ebbd2fabaf474663866ed1cc2fbb2b1a77879dcec73afacba6053575defdaaa03badfe5f13e0864bb06190b5f58c1850dc1109abe87f7808f78f048527879025a49e9aecd812c0fcebe8b7a1645529071792024a50373b00b438d60395fa2418ab4544911a099acae2f489223a8a10e784407822290e0a02460b671c61a23c9e0655922e86f59d51c66e87d46864f5c3946cd529ff5d64b02c719adeaef807097556fce86a0391d5d37729a6afd0f00705e8025a5bfb3ff8ee1c3a8afe6685b4b4a8c1277bd3bdf7993a488cf1edd22f7ce700ca5706e2ed4bec8445377954a459ed82516cb3c927d439c28dacc02b0003d0ffaa1597e4cfb11b2cd22a3061274689bbd6311783a0ad87653082bb5a61b2ca489ca719104aa37ce83e734fe56ef022e84177135aed2f571e13d545cd8dbd13633d8da4e143a027a20f05487300a92619e2aba581ccaef2a32efb1801940759bf37d0a59b873b36eddde748d17b4bcac58c99ccd33caa951efb09c43418486546e27b613a8f81ca161f4544b94cb9e0eb51e13c0b492afe20c9ae1788ffe4ba00cbce52544b5e8a40b42ab7682a1eba60497b2d60fd39c275bf4351c85f251c049300715935dbaf6020f7c34b54f5f6a69fc4bb487a3cad46ff6edadb6551bf158e014049ba60fb41c2ed43c8a23a00a0f51eafa742386513a5406f0661aba0701e445276aca3dcc1c8909c3d5f45ace69742c7e63dae687cb70a77b987448809ebc81532ca02c13b3dbfcdf0f06b1edd6f74bc38a5108820db3889ea97df0a944d47fcc9de2e1de092e1596540cda9d82321baa465ccc8c59ae3e31ac198cc70728fa6a3677935af05d5b52a1e16d6dc6a75d4d0f9b931b24669670f0ae584ae4ec22271c6580d750a753c872bca436286d6c4dabd1829671985467a40e95a8bef86297a212a200f5df2c2c4632e603d63e22308c96c80946186ec17895c6211ec2889aa3264b28ec2f901069dcd5144c102a0e607cd2453acac5c60caac4c872c74ca26a7e3111b7e0adcd91271270f6380be9317d76fa0e79ef125d938c64a51de532efb3d67b05278dc6472b3a66c262ee9aab3163827ae7a8cd43c5e8d0680fee026878cbe0786f1fb27fcd1a0a34ccc19454be78eac2f9695bc44ff44caf9a7a5aa4d4be062a0a04cc6daec271eedd40e2fedfa91f23fb8bb6d7a9bb7d12a3875833c4c3dbdc3c58e8a279d186c18e36e24ec2eb756e6c92eb771338624688cc66ae541d2b5f0bed208d2070e0bacf3c296a50e923cc8fd5e0b4d0724a4d00a879b890fd4ac1baac59d583d9925bbcec3dada29c965be0a3e7dca6a853ff98abfe933dd524d20bec2a6763dc875fe44dd1a4b5cdadfa0344c8047cfc0bfa8daee5de6a4359742000733c01e92a070504b2414e2e60d8b9c76dd968056e0d011c0b6cdd37bef8fdb5dee15b4edc008fdb800203cb1889069e3a121707eadccc97b511ca68c1125ad31622adac513c5b899721b234e62c631828fc33b468cbd028f1183f414b5bac97ae8a6ffbfb494022537f529f0e48db53646848a5dc0458e11c02fbd1e39aef1eb1988bee33ade4c13e98aaf2e227eb60143111be4e0907d4b0eb14841cc601d02dd2fcca2cc4b20071406ad5c40847e14ea860420f8394c1bdbbbfd87cc06d27fd1ff272c8b9e8ccd078dfe24b67852f0973d49c01e5647d0e0b46d35ae9ca28a0455fe2112045b0dc5d3ee2db748e40c415f3cd6796a78e8708b49dc391230301fe1c1832cbbc60fb6ae18b294172f3fecefca7502e41d0b9c78ac2a762c7e9ce134c7e92e5791a6d2e966f971cf966a141aa30cc726339e4032584af567458d0c7a8d4fe7712031387ff4456fd1f1cd2e11f94fedfaa3101037bda7ef93b92a21bc852a436c3457caeb14f496535a5db91db2e0ea404d210505bb849b9de5b17709a0a6851e40190145f55ce8de443277322be4e974eb29418dce240b29a1789dbc2d860d037ee4714c2b5e8720b7327a781dfa9c10f6c434850488474f156c82ce6d01b5369d3a8df03af9b32ab058aa0bf4f3cd3246f1cd8c9a636eb8be87df066df4318803e9c49e15ecb6d6b114e1752cb2dd0ad809258329105e47ec119ddf4ff6eeaba503862c9fdac105d5f850b939e62e92defe69439eecba01883076094bd65490f84cee4e7cbdeb987cf3ae4360bcebf0a93b0997e420394ea1e075cea90afd3266a84f9776a2678cb0bec0f1191505aaf549a09f76f7ac7b3f94dafcfa9910b4309b3be4dc31c36e9de0bd76cedd690196ee7e80bb7ed10182a7dc2cba36fbe134923e2bbf20b92a2a1228b7adec47e9d3c7acc9d5d8284ab191af961cb45dee2edb8e94c951c179831a57e86fcbf5ea17da32f319002843644bc904032085d0824d995ff6ee0462e6734768fde2e3ce806cd2542f4e914d6d81fb83fa0e9db38ba4c39e57e3bca8b7a8d30b7906e658f5f4c4d0eb99d04c0c7522df2d6d16a9f8d59fa7f883ff0998ee903f4a8b01cea1a68e5c6435ba5098b7a7320404b9cbfb62d365a7021b50e5f28499ee111bba9d4d463c792b2eab1c756757761f7bddee0e28db85fd1f8ef6ce17a21f6075ce673f33c38ec3a0673c612b1640d06825335963961654873415bcb59c513d4d9ce43570127675720147781592351b58ff23970fd83b08277905aa28578206070e63c58d48092564f9e40cc662f8b59b8261c22c47a7113119a00cd572900e98ab40252fc1c138f638ed207d449a849c71369ce3dcfe3266cf9e319506e947bb07b933feab710eb38e0f648e82e6250efe7306fae682dac33d0fa8141636031110580bdd94a4be6d12d3284e42208694af78df07a03e44d91626d99d44d9c40515ab8115838f03690949812194d9bf1a527882c741160da055456dc7ad0c1ca724b3ac96a605b9b74069006a168198ac0d917c84231e3f9bb82f108ad9e1a1188f0a8d275b18207de7f68a4e5b2e31436c00318a392ab2091c2046cd9c33e79456d4e107c53f19bb2579f806c6c1567e6f2fc43ecbe51422730562803b2598194518fa5887209d0245e94ecbd25f48c0f87c336f932f90908722e1d77462a3e06d6d87efabd0a3cdb047287be7b16cbbfb1b7aa4b012199b7dbcda0b69057e276898b358cb951d66bd20660824f0891301a0c5745a0f055abfc0ed4507ae07be98fe11972d51d8a84bd5fecac087ec0c1150b61dd2735fcc0d63e1c1357b0797a4a121c809d4cec23f4c306ac1960939a0f0bd3c05c053bea40ad9783f315806b64f14aebe356a20345b8d40bab234a39fbd78e1ea21ebb0ead0a34b1ba3499c6eafdd674e17e4db55c0f6378f11707975163904226c127602c23ea039dac4ed7fb04af0e1cb2ad15acd43e5d9939b098f06932efc583e87befb47f40f1d790aea4cdca5c3a27b0ac848fc414966ea51188b484dd86bd7c30ffc6a5d5bf2107332d4b67ac8657ad4c1e349838a318986d6d814954ead3926ed584edd09ac1bbbcc2340cf76c565796458a955c29539bfd380a5fda0efac3120a769ec38352a0c0075ffbe9b76319d8278e5e1ecd80689950471e00be029f39a5d790ab082b3fecefba30c483f8844cf799539df4ca97cb82a0544c5de42e647bd30ee4605be9cca88a1b0bc02885d5e29f05057e6eb5aae98c07b14195fb606ab5d1cb02b92e187c8adcf83eca710cfe8bceadec5bdb23159d744dda2644d549a57242ed112d5db15d28c3e36262ad4be1e574a0ffe8da5335fc04ba100865293405e640bb75d7b712eca2ed1f9e3a4aef662fa204afd533e33eaf1ef0152b43a2145299852dd7a878fa0e048369c16f28ce35d2b301295000d26415d550e2a49ddd6796a5876b3c30735022f0adb42a67bfc397deb62304488e3b7dd78258ee1e7dd3ad2b689467c19d2acf0b20fa8975f1bbfea28af6a38d04997fc1e0f2d72e6d37f609532ceb74ba1ce0dbb47602ff6d687e19a642bd45c5800253322500b66794f7cb5fda4143e743e6577ab15f7ab0f2b511229ccb37612f9e56b4b19e1f2a1b3f57e288700942eb75b21d6e8d3fd8ece3845bbbb65d911da1f7bd5e3c8ebd5f11540bbfd5f145fb93d7afec53c5c3b60d1d8dc37e84a2fc8bde68b96d05a0a87c00c5fe784bd14d7269ef2e4eedcebe5160d15990de0a9e4d2df62ddf476596a4d2a81035d1b712883ef80bc2854df6f9454eac87e477fb03d7e39ce29005553ad85a6dfa5d940853f5376c16fc07c05a1f502124f5ad446d84b73715982516d0f1c99742ada41531fd3a0423f22b8884babc6cd45087264e0c6af3b0f8601dad4a772e97d1095951e1f7f18a1fab4de84657e18e432ff4af13a3957ebbe693327c10de0c21320ea17dab109cbd421028f6110140ca75f2830349fa809c1c1b1d2c89f9fa55e9a8961ddb7e1a3e83a62630203f7282897f35e895cb9cc147b6eb6a944d7f7431795db8579a9a089b5b264d9819b22727c6f26062322735b0b45f5b9668b5c09c915da4b529bf0881c281bb998eca05af6397a42306228dc8c394c2087568e54a9e001f5417cdf6abd6d8605d097a9b13feee2d8c5433318072d4a37ad2630f22644f2b47ac2ef370f5a044f4e5992a9228f378cd7b7e389d395033a4417403461410f738d91144df98272766536b868d7f9c160c163e5d2b13d7f58318d1eace18733a15b173c56183c7f6c54af96b3dcb43a33f43b9f83ccfb1807ba7c9a4cf2c9255f02f58433a40f11b8d8d2954cdca2708b2913e380a6e52fbabad94d11d657fbbc2961eddf29f3925cf0474bd596bc13795244030a5f83abc3e83fc93ac3fc3fa049359735aa5432996cd6f7df5cb241f4711c7a671a2978ad411dc5e6c9ce4d20595f59f72dfc4aa293c0f3831ec448140583caada00f0cb10411840a673ebc846c16ad78bc86b40640fb12d03b43a088a2105ca9dba1c40c17fd78012ff35990fd53966b1d56d6f1cdfe9bb548614e2c51a5eaca7afe603a95bd8ce572722f231741b75fd025b53746f7574cad687a3368f619a1f542c412303320f28f203ada00e72a4f66e760a1a8a9cc6356dec10960dd0bcf1dc57059bf2d06b4f866a9625d903d40e01ca2655ca6c3c71272dff6eb8c33de79c389eb6c1269ceea770fb11a769483d58d9d84bed749d7720f4ad128f2f52ba4966b77114daed9b9f82fec6321c010059b3215c4e7e2b02cf9fabca74c5c484e111c4adda63b59762804b3f8a4a8a9f500d295729a56444219da83b2b4dbeb7c744f3a88d0c931ef2142bf2b98920869718e50f69921aa49501eb547766483c21f98eff135a8780d62d4acc8bb1ca9ff343fd3d1cae03042736f8107ec4270fb87e0c65d2670308a648614c2e618b930cb8ff7ca7de4bd0db22186787e6a2d26a91c344883330a26d0c7cde771bf26505f8548a4ef6ed713310e7e058f28d19ec8c5087c9de3fed29ce8ec248d902355e2d30dc52235a2c298fc6e6f9006f72f0e988b7b94f5801e89e8d8c8272285553fc64f09293500c25dcf71e58f04d7bc4ebd74d4603dcdfb0b5e75f68fa03ef3766290929436130e34d2e0831087e17fbd49e6b534e17f3522c394e88b4583b391ac0b5d49f75823be4868531e0dbe73d00810d6497d8a6ae6e8dcba84147d4920dfa9382bb0d6cfe6e66c164300bc39adc8aa110fe318d305124489d2d13d85c44aad90d85960d9a52671058da088cbbfbbc92921a0fd1fe98c091ab1fb8fb684b04208715a1e2bfbbcd24ad45b2507c676a72bf33443ab6e3ec8fc430f2b61eb115f0999cec92fc1808918f52b1925c72c6fa2714f684be8d518b47fe18f0260721c4a2370d66a86b4887f2d3885ccca3ca38f984c14de32c0454ce63561e327911c232695b8527a94e40c268e88e911680763f4f8188433b1487614a6cfaf491379bf2955493f394555676e8354a3e580bb997c5787813000fc6f218312726d3f661d2b8384ca9d2318a1b23f8aa8838daa1e3b24157133564f1693edb591fc87624d5944238ea00dcf34973f52e4a81a326a6f3dd3ca675c3ce33043a3c9940553eb0a460aa0b8e82c1b2c367553595447393a8d8bf6a4b26063c6c41dc4548c685cebcd0f33bfa92c4b479700b794651a435cf47bfe884bbe2c30075cefb8309b3c3beed3986357cf227bda18ded69accdc0d876bb42fb8f5d397035a2cda5b81d95546bbb0556a26b137102ecb025a409267b1cfdacb9a490d0b3326ee4793e3deb9f3ad41c96a3e33d9e4d03980021e39df42e3fb42d5ec5a37f9889424944f0f36026cae6a979099500f5840716bec771b5f7c3db33f7bb9ab22db33c20f524555327cd3ff909d290d4151037bd69f43bd9aef1587206b125c8da143a850df22c7448a81bb19fee69cdd746d0ae2174d11d43a60960d3cd37a6ec60e208fabef7068007e5387433215ec979d8b14b62828ca34ae667d4d603406a9f008ad9ea0c43e2422b2a77e75a9a9def30f1ea248cba57029346999cf524d153efb79f3fed3493ca81a741ef72b918b2b089e97177670338df8c397226fa04c6994f05e327efb7368e4277572bbf21d595dca851736222cc6300745f0229a650a634a779060ee711035fc558c2cfb95b22ac9fca7845cd3518b8d2206bbff04940ca1d3a8666a55cdcfa0badec4843fafb99c67bb9449a5e5da51634d3fa695770b71274301013cc4f7c3a0101dd2ea993199fb8ad16d881817c54abb60757e2a4430858666cbbb944ed093be87aea4c8fe5af8d105993ed0156e4e4e3829e59130337842a8d53f60ba2a07b29a69225a72a28a95109fcf85b4274a126f3d8718557da6fc216079a2c48b261a03df6a8391220b64cdf2c4c12c868c1ab9cd604f723b6da80f1581b710dec06c8cf4d09fa421a4215f9c3af3a5546276a8e3e7806613b913d57afa1ba9663778af9007c6105e3b09736c42d7e362c053f0063a04e84f01be6c068cea958119b0e2c24806b8310da8afd5330d6499fc6c7c9a458b24225fb7cac2532c04855b4fd57373adc72025961e4aeb0c1ae39c1d1b6c3b640a22a85126547e981006d77d7901f64a996a91984d60ec27ec667b19cc8d6def8730df384c5103bad2b33db5012692a18fa28df52365b5423e499f0fbd991886a03a6705d8970b623a93d969721ad5f38594941e8c80cdbefb62a2f7202274ad6514f223e6322d19c8ef0fce6f8af3c723e3afbc15d2dccb396d3c533bf746229b7239295d898f59791855fb570247cdf63800a9389a1b7939cb3281c0355aeac26c8e878da19cb534db3d095c16befd4d752f16101bea2081d2bd8f24f6082b23a69822d424be2b450bbd25b005d65a82279ed69b5d0991edae15979232ff277fcaa1911a31fc1c9e5810a8d0bf935915473795b8e4d00ceadbf74725f6c8944ea37de630e7488889d9e49aa23228a4bd5ee0a8197c2be3165f0c81b1e856df32338ef9c6cafb28877229b88edf166302dd5c838fbc5eb5a96df3cc636fc5473b3bc1f3071d93e070b6454a221a6acffc955cfd647ea288bb68d0303d1bf0a13ad149d8426528c2d16f59012414c1538f14214b2ca90f92493f59b877e60d4cda032d8005032dffeb9f6e14e75571e4736eca3da1eead67f1072a9caecc86224aa7356c0e500b6dc80b1560088339f1b2b9ed6e77e0926310239f32d0839613bdb0c58df6794e8b7ddd5d234cf6badafbcfa84f45686531734058f5578c8e1978823da195361a521af561ce7b4a30a8c1a8ccbe31c77e17e90710acc4fc1aa2f04094ff1bcac2842cac70568c41cd86f6f39e8a1b17342cda0c54525a530eec471f9985e58343c33249398f59364827e3a07686f4323c453382ec12a3129d4268a6bc0de30a55665c43656d8242211c11a45e124afe712be862463ba194e49d5cfe26e9b286fdb2d4988254d2a08d2c68ab4ae21cdfb28559f84a429dcfc40f9e65a2e896f93e8b23b371ecb1f499fe237041c615ec84a8425a2ea304b737697c8bbf338c799bafa0950f6b9f139441198a5ea8bbe5427bab2b5b8a2cd7746cfe038d61ff047cc19e803b72239434a5fdce9d8b8e93e183694587f31176d554e07a1e2fbbac1279524e349b4f82fad43647f03238c2d241babbb4fcd2a008a11d6acc5594fa0127947a92bbba510e34a6f38798eb7d5c6c88df7b35bf34429d7aadfc50643e2b0cd2ac7b9e89ec78d32a0496628747adc871611ce460a247145750adc6409ccfc438a41aa13b4b6b374c75b1c4493071ccb3768e23f15816e523e29f225bb178a5933525ce7c1cef306528b09cdc5fc5a9393a16d84702c301b85030201d64dba859f1aec68c34614fb0c0dec0b744ff284e41c514db02c728d052f1fdda8792f9bdb8f6efec31a43753011fb8f8920e4f2b372d5ed0aa7b9a9262df40ffe1095b662a08ab95df0d8d9beaa01152233276d419c37ba8ff521ae1bf2a854fb834d5b8f7352ac4b73c632f457dad6edd4eb5d90e1eb0fe9e6b01221daa16440860054732c1c052035b0388606f6270a1d4bef140113c5c4318ad09d8dc0cfcc4446225e5b795b3adde3b20164f253c74a2d978b773ca4ced6161c5d69b03826e1ce89df84b20e3e32cdd13a4821d878367fc8557db1f0086792a0297a46e7ea6f3586be1a9530b4f462f406df4e9a1324cbbf1024045c7a8fced8249bb9a7b63f4e9a95ec3538e408a74b636be6b9c52b0d982de74c3f417fd065f5c705b30715c042d220e815ecfa06f354fbe931f3454d8affe75c50d77e9e3844733e9dd8d734956f9b47dbaeea509082e395a32d739a287798959fbb796b8ae26585bf62f5ce5ec750508367b780498b4f3e13df38ba15f9c38e77acffe4755a1a4fc0ad8e6a95b4b3bacc69b7b2e3a84b738060a5be9efd65080722dcd20c17eb83e112b449ea7747b3fffa85ea3209fc27601bf856734e1c337f2034e057c72ea6df929eb8982c724155b700d3ef50f5fbd3c2f7f68f21f827ab95847506d65786e211781ad689caf25ac22baa045faa833100f5b8855f30f0d6926a8ffcbe920e2e63280db8448fd0af1a09f1dbbe4533b8763c5ccfa9e9d6d4ddbd3e476e79e0fb2f805848fb9d847d87a1d9dc56206264fd723ffd31c47ad29f2d06fa19d02aa65a32a44a7ee814b41368d49a1a422ee5b6c3a1c8733a101f9c5e6309ca5f36470e94d3253c9abb473362900e656114650d9b8abef5d9f8eb110a991261385a0b031eb1eee5f24da6a0396a4aa59a126406ce917da3f1d12cea13a14eeffc1bb7f81a02c0991172b2e9f78c966f9c45621187b304a5f2305707a34440a7d25c6e8e173e87729c4d01dfae91ac9a1c63f2c769a297fa732c88dcb10344b39e07099aa96fac061636033422568f4cf7cd8ba1d2636a4b3d7ad8071fc9838456bd66065904c5f46372cdc7f628593c5c6a080e320b43dc0cb1142779fbed0ff0595b161ca03c8067912f009ef8b7a7ec38653420e729d8e66343588a0abed2b895b055ad663aba6c2f7b9cb617a70138b8e251173521ebeef7cf43bd04e5479b645f6b5890dbfd27a7a726405a622c7fd01e601292931230d4f2bdfe4ba1d9818bb05f9f7b2b17a9126139bc82cf8b1f92bcb387f1e7dfbd7bf49e0becb263b0f9c0d7ad60057c260a2e058dd52b05e5396b3e4f5e223d2ac9c461810d8ba1f58f0c2324668139a030d75ac4c0a52115111979620252c6c4c2b3c72f0325a8a4ca41128f144dcea183ff2393fccfb20cb012b2990f6d68e42590bb8569d8c1b971aec1110b030465bbe090a365281f5dc542552d117f03c51c072b4a8325662b3f40ce5006e52c8140030f4ddfc1e8b0e5a09d87d60e81599d0b737176b3b5afba144c808472f6eb45037f7e7686d1b72167acf74d9738efbaff8b60a2151f2792368969ee54558263027c0bbeb0b8a1ee85fcf1ea06803ae389eac1249cab2bffc459b4ea206e6b72015c59daf0180187a2321c0b1b6ede650b5668aa922c52488cbc9c823cdb4eedeb446e82d961745b9e4b34cbe287d11ffad66f25f566cb98d53d9ff1701e452fdf081f92a3d57222506740f9ce2322459afec26f265b11ed3612000f75638633fa873902e6eb1ce4157c0247d350a37b0604a5a6a2e80bd3a0eaa1b05128455c9b4b3aa36383700dccd6702e6c3dd8773ba4497359e4cffe915c7416bd13f3f863ccaa48d73e0132cd6a48059d84374792628dc37164396e775876d1e812726cbe2791c2b2c9b803046181ecf1df559146567ea04533e47715d83bf45803091d096a1b65628cbb0f6891e47a003aadb52766b0bfa37fa28f74aed14c0bdb2543c57222150db0287e3687f5d1d127169104b11b862c329ae44289e6e38cb996c2f3eb3316c80ed66d96a95fb0c831abb2504ee221d9e25a8be02d8f799a72896ac0098d892ecc698f75619eff77854a48099084bedffcd6d48a210ded20c743512ad033b46ad38a33a47e104f314f36a2436703f20d95a73c0c8e04bc2caed8ac068b5865cb65047caa127c67934b0003a79748ac8074249ee9d56ae7c12dcde0200a28107a08cd52f68c9ebc8dad4d8c22a1f5624f46537c7c3702dd6d821a6392b74892ff7d41e0743cd98c7484d6fe79ecb79f98827d873e06a928fe064717fb434c791e5b71e01895509a8458e13ff779334ff45b0de52d1865d091abca1f198bf9ad91adccdac70ea51db7bad5707073d4ebde87919ad32092d866d141c2e616943063e02443163806b45e06bae9d369a53cce10838213ad8921cbb29744996a33c12271ea4c7de9df81e5504e4cf65dd9fd10835534467e4de8f2e4759421bf12981272676ebb521c94d41fc5bc4a4b0891de0ac26e578285f64c21f79c35f6d152dd361d8deb098d8a8a9c5c80c3c1d40a6b760e2bac0a170a0a0c24abb6886add8cb11954d89b97ac6bd29b8287fc2677d71fd020e8aa20729a7fea5ef792c65cb624376638a5ad17c420f7a1d012ba5293016c69df989f45ac4656387fa177f83b69c56a4ddb6288415dc18c1052a7b933c644e1949e1cdbfa12d36a10f32b95e9e016588263ac5d104f4f814b3c32387b0f8f9532ee4e9ba8972180f8dd101bc79984245c9e70e305ad80d6b673802812cc733885363c8855f8c6fef576a0c6c02eb3706f711abef2131bb152151bc94839259f15abfa285da4470346058f3d12a206bf1db2a00f105160b57e132d5d6d39631e1610b5bc438aec2923078e5e40063ec73e0cb9ab63cf84cdbf8e54a314cae08f9db0a6e46b17d3fa7bbcb0e09433b122e8d2b64c67315014395c86159b133c5642a22b27a9e4ae902828e1037bde26888cf2f2c79126e5adc4300173c45a886ea72c856e465172689322cdcea2e26a41858c558aa4f11125feaa03e4b8784f1ba86ad375f9dad605d180c20a238ac8471a1e924d47737887e4ff96b6ae3a0250d0e59a5c46ef85852c9b07925013b46186780a650438f1d2924dff3d00d0025bf1e308d22a21740adaee6f310888abe663efa54966c73f5d453c5651a0909fde6051caee34ec235b0f2ef8fedbec5470c23c1d28b77caf928ef260309d3b637c1628ad7daa380413cbeca90cbf9d80cde80fa0763dbaa91f0329f2d3cf8377b26cbbafb404ff75cac79364488c1fb9a7c77de8be18ca797cb49952c0feb693ea1a625e3997a1352375ede97e74a756a47b37f957f3641d00f71377de8b8a715b001db20210eebb97f11a5e430f130761d65ef02f9d893325426213121eba871d0c124368a9bf784688966c1384ea38557c2d265401a09f78afadebe6dc93be54f5cd41c959fe9242fa1c14aa28e8ca82ef2440758152701b46746090c5476dbae33f43d87381b975ff3bad4b0f05d187f3fbf7e25e00576c46efd3aa2c3923afa0a20da1125f1924f01609dbf4f4ed4304d714531cdf0569c5766b604e86dafccdcc2b8318b805cb52851113345fc582aa777eb6111a1340aea2f5dd885bbfa58181520f5e2bc8594fb43d42d635c2a5c8d31b049507db14583aeffc0ad3bba67cd003b093bc91b2f41198c601496ed4721cd1f595c9bf15061614d4e0e3d68aec51115170966d56cf0a7f92adb2a725de541b35f18b77e8f073ea2b0bb94c99e2e29834f4ca6cbfac02f14f3f6a1b02aff861dd4af1b68c56ef2378a39fdd45d025849893604fb58470507f7ed66f7d795f0137553abb10d1705d6b734dd85504faf9d96ea04c48af631e1357dc56be490e0dd00f6157ba3b823a0437924e34ae1c2bf81a62a619bce860984aa64458c1e8a9953506966c83059ac5f29451380753c2e9fe3b7029f58a56b25698d5db089e189a56fcf19f157dd9bb328bc7a29bbf200287474db6c957d2442865e6d01b8f4513442e12706de8a8910b1f9009a17e7792ef70a695f5b08b0b229ea8e4a0c4ed0daff006fc3893293cfb48aa87a6b177aec21020c247d46cd8b4a8c37b930bba23cb410b5527bcc6b38dd3681ef26b15619c849bdf3342bf1934ac1e99a39395851be6d9dbfe867fe7a7e5f3ac5ce79544cc57a8fdf674e9bc5f59b1f85247d2ec06a12c5def23fcd99629a55c3992fad2f3ed7ac33f8059378e949a66c56008551e4e9830e50efebe4b4dcee95dacb3630824b2daa92173b8d53e0a8422cef7267df3a2c1270b2e8317553768d8b2011041ae23276b146eb1f09781e942c1fb8204b2722633b0f60878c4c745b204a52802af754c1a218fea2a9f962d98d300d1be7a9b3aca6deac92da5fc01cdad056bfaa8a337672f6fdb9b3237aba8d2dd5762a797d69197752078984fdd8c7fd904183c44cc6ee1fe0906b495de59072f902c8eab58c29b1a7df8da2eeef5dfdfb3446e8af7bab6148e2ef48b56db9ceb1b4e50df762f3e86305a468ef2639df8daf03677fa0f4256c3943fcd1e79ff81ab22bfa10d492355fe16dcda9ae2e482c1625bba09a02c10dd8056dbca529642de4c2d0fcf3403b1cd06e8ab23496d05c04667850658cab20f6186916f4ae306be0f1720df4fa7ee577adb58703885a06cc50e42902ebe223e6a757674c16f1e0cabcb0f8b263f45458f41a645ead985574b45ca3760b4a416bb8984794aafadf70915e0259b7838b5bca47409968da640db43e2454728e1d38b023cdaa0f5a1e020b167549427603188cbc273daf57497ac40c51b17d881172fd24382394583974b264a22dda0d479b061eb1826da8f97385905263469f1ad86d52f6e8b18201f6e1238f050338a4d9330ca4ec7bc834df6eeff83de48d7ef2987a7d1fe6563a6a2b86fba9261285baccbe3fee51e7308e307dfb85c7e910d08dccf8a797459f8d95a0ef2115ab11fe49f5a55f812e96e38338d8518a8f97e82647167c70c0c59457ff8952f05da6adc887d8428e9a6d85e277a0a14d32ce10fe44789af2c7d42ab1a9054a9c7009d22b344e5a3f79d52eda1ec9741968b67ece52acc8cfc872ea719def49c98066c4adb80eb36dd9f18cd72809e1016bb37554f7440a873ad34fdae50b971e79e80ee82f3574ff2093cdd40c0d214ab8b9233600253b4665ac969e9a9515db952d657d427778795f21b7e761b3162c7d1852ca5ed7e8159910eb5217648ac6da4e4fa9540652df52c3c8bfad80b06625b6229f682f03c4050b5021809f11af1584b4424935b112dcbd63ad092d2b07ed4b3b0e1a65050291278d14629ee98641e4b6611067e3e74980963435071cb1636e28c6a34258e211368db7458ea724027c65510d3ba8caa0bb686398e974d0b69ecb266b15b30795227c0c832e659e2fff3ade844eac1c96311b42ca6a58d6d65206951ed7c7d9d16ca3a023dbfb1af1c3aff0119d759674356156c8728f2bea9f18d803aed69f4c05f6428a397b9a0a5124c48c3a90283ea5983ab2f1d09400c50ea72dc3aae6891208c5a399566bd0126cf984427900f61ab85d552837aec72ff74c48adae454a21f7891a889b7cf4a594c09f31f66123265e54ce90cfc1e7612d4c84a74200979083c78f656cd86b3b97b9bbeb4e4a688afc997ff30844d0d43549f11caf68db999f9107dc42f79d3fbe9a5153ef941781a1ba5d44e189b4d14ad083f1d09089f39ca8c472df1e2286add6a06cb426cbd38a50a219c9f5af57a0f3b835de6d7323beec522e315e005316004bb45345dd2d6251ccdd441be8478a802c5881dbe9256179fc6831f9807baaaeda15132d6b97da68b4e8b95215e8b5321c1ee2379f0ab9409b21bfbfc5a5bdb4bf35d0397a55707d87d634f26cda178202d9cc24992502d18bfc359cc1e459ae44c2444cc4fda283f0c84406e23c0bb6019378e54a019a97046e2f20ff2788f4114a7134cc464e1c60429e4cfc0d95f5e578685e21c38a321e1c1b62d5914cfb07b8136d2e61a022abb2ea93675516ba82c1890c86a61d85e427ff29d3f2643d5044781e54aa051e6ec3befbdf83ba550b241830c2440bdfe5f7314fba541ea5a5bba2f2ad9d8e9b1e9b97029a218c46738798a2b7260d3f8f3903f0bde0401943b28418a2106636b0aefde864f1b52bcc095d9517cfab77285f83e515f34673987b3050e17c3d88c228ba901fdc986c7123983ea6a5b9accc0515975b8aa1c565b011942f70062c1c0016f07c1673bf8138048133febb58eb6a36a7b78769cbb84edacdc9118122241241245c4c71955ee2738dc457d13d380b24f2e1064cb090c414ae343d0f23c835517c25714b0bc29c076affbf7a9250bd48b9dcc36e0e87e2ecae5006753c6106c630eb94f4c91037a833b31a020aad472ead40521474952404e962ac426393a538aeaeb8f70878bd74de715c2fa304e230cf0b8e2d019130c3a7ce59f4f07d2b54a87edb484a922899fa0c2671cdd1d33c4ce95c931f35e667d498ca6868d916a0105d505656c81b204bd05faa3adb4bfadca01de2464f2790438c950f99ca8d4db3f297f9fdd74f77f49964151d54b3ef3f84fd6197b07d26f5dd9663c9fc4f9f49e92e08102e965d5ee8c2af544c3285e3397891187a7f1f285f4be82d34b43f7f59808fae53cfeea077dbfafa03690825799f5665e2b5a6639c0debec3d472b1a3ca12165e729d4b1de835a5896440d3366a549bc0876e3e5b478313e81f381d4c26834221d5875f53264b7d8921efe5e930192e8f5d7e62d095b20241716f0785b433adc84d8f3abe02a333274f1b8071d5fae9cde078de76b27f0ad0984554bc8f814821efacd8a49db0bcb51e1de495f1a5cce76c0b580b1d5499dd1057c55270ee2f10584d3e6c0fe65736af4140ffe0d2b557681a32172e36ba27821a6b3e215164383d5aab81e2463ce1f42ff0bd17ded8ca22f8721603c4c0b18e92b906c0612bd68a8929c556804915289b1f22642fca26a44386dbc5c4e98fa4593db0ae1f9827c9b91bde77d1b459045d1dd4b58eec510b76aa5c8df7d56568022b6d6eea4937d229cce6a14c2c5d3d88d190ff2c8caf766b63f3284853177e5322b2d73d82d49235c5e0640bb95090acc15c4539d3dad4193211a21b3bbae7b682869ca07b855c3639b1d63f857370cb11c3b381cccd027c165bd972f787da50aa2c020e0f52ebd10f66274769c880ce0243bf113cb45111273a9086b06ac311cf650dc824104685799a0390085db8380da6b8417030938760701a028e238917e40e1f546b43c8fd45f906838c3c3d240f17147f6f7d1b083b7df5fa0e4510d27eee25e0d69c0f7aa0a45b3122141818b54f43c16de2904064e76e41df5fc3c76ee926aa80b8cf3e63b38b24b60628a558a4374ad7f6284247153da6ae7d11a0fe6b321f7729feffab455003b20d808c76abb0919dfe02114949480bd98b3fc88e0b55ed6ab5901688704108a7b9f4eddb0f3fde570601af781833ea0ea07163e04dfb07f58c84079511744387b4c3a2bc78f9b74241efd1ea7999f16de4e4a2edd6bdd6c1d80a82d1617c27204a09557d7c31c13f086bf08f22bf3f01546fa5016776cb5702c20b3a36e2b7d279269d770471134b60a3845608d4e86d3b0a0a58e298a9b1da3f0f90cce87495feb23b74cf42d5355aa5ece936ba1d9383970e632e7682630d1f2358cd274b4d1f6262281fa527c2fa363ab415d56e44a438a8b4d89c1e226e49b6e7ff1fdfafc83cd50407c08ef9632312db6a42aadf2616a6594756854d7c38e887b8b8a9e3bc34d204c2e71e39593191a68e0fdcbc66d524316919ec27bc8a72a213bbfd09ce5e1552c53121e740bcbc8429430b9275cd5c81875435b8cf57434b9e8413a930222d84cf9288c3c622c4ffe0245ff868078170969faf7a7a6889b001ade13d70a14dc3122a50615a70b457f00d2206bef5a6c37106cbdb6e014f02bcb380ecf602dfb7ee4c1e0df1b5950b5cd6ec59bba7a9cce23b1d59099daeedfce37c55105c948975a036c5aff42ed2c04b991f45198de1d507dc3df99edbb6c693ffb43aa3f050118c8d878d686cc607be75c10f02cba2b77e8a4b13dff3500a158eda48ce5fa9e9948e35b048c37ecd89211c71f6d492b4b2f9a9c4befac0cc03d6cc6fa67e4a704790d8948a17b710ee85ce85eb5397227909fb27df3ea9af00f59237cab8c656865804d9b52f344bc5f4777eb0e9170a6a0fb390093baa0e96241bf5011487b66efc5498b6e2454b1f58c0e206eec4e098428b8987ea4eb1096141eb961818f716ce955ba53d3f8b57aa2f9e5d90a839cc9aaa57d9aedfd62aad7f662373cdc33648151873ece8df0b7e8b726cdc8b11f687041003f4e82aef2f28d4804ed097f37432e5346b32c5871c6fb31357d0c96b11362ea35db73e4204c541d73f51e85d38e404ba646648d976ea26374beb7fa3faccac86d6033a1c50816af238c84cc571ca5594475932ac8618f1596116e2e7e3e127329878a25cf8b44cbf005c203782c239e6fac4080022291e122cfe178ce8434fcd3ac14ee8949d0e223ad1cef8a6dda2ee788460422a63baaddfe950638051a3d9b92772bdd1db101d0eff330291a68a278224ac93a545b4b846d529b49495837ce2d48540e3549223594033c4be592924d9ca318d4cd5026803d1d7eb65f95a33528842564309883d85f82dbf83097b58a57512c500a90ae2396344c2e7d3c77fa461f34158a79ae8678ab443791cfb793b67694005bdd7159ca6fbeb84b43b7e2023143b2bc3cdb401252466d50b1522ef92fb7197b6cb1c771cf3d9ba71ffae3c679a2129d82d2b611589f27ec36bf0d3a516e972910a89e5ab9d13f8d2a3b182df152ed0b2a6152e0a7bae0c7829b8c4398109e12e65407b1b6a0e0537fe00fbf052a1c11f002116ba82823865136901df2b7340363cf5cccc2632b7647c53aa474557cb64afa76f96a684eab4bce356ab7a46f0626226da8bc46ae0db1130edb4c1d7f6b13f0150650f1f543b9b84a294e9b4b6ba674401907f69c8364e8a9fd418f89d10d53d2ce5b409bf556a3e49f43b10f28e196bb9245158eef8f1220abb059c8c566c5f8dd89d49d9ae1fb435134280990720de1e9866fa39321eff354dc1ad1a9ecf5773640628c390d775482d5cde2818e77d2e1ee9056e00f72f26363a3d0e2ab8ed3879d29e52150b31361e0d3833ad9ae60cf08865face30dde73d2a0035ca8edf5a1d334a7b7cbac2985206d6a1ad296ad8dace65baf8069f3dab2f2692825a6cd4f52a82a3558fe8d7219ff607e887c3e8fc20d9c7e85effa38fa2179e11074df17c8fb8e2b5813fe38cf8b6078575b51263cdd1ddf102726e531696e7fc08023c8f7c712a8dd286c1d303592c1fd6a7593c3a7ce1a787c045b00a7262c686dc2ef9f60093492a7523d5cfc1c07acb5a771f9997972b1bc86851e1e419b9ddd06ac746fb94f51fa56cefb0ec5874bdb93302dd0ede7b91a640f3483c70eb4320edae09409c5331d34a22b78e1a47eb38d77e119a9c7a5d3adc185ead6c8096ac9899f23f1411a0b53ba393156db157c3f27b88511dda9acd811fc75851c4e2aa00e14544c55e0d581de74e8b575a0414c21c944e9381d9049a0e831c065fcb3f84790d09b111598838d9770047b03a6edd27464f6430c3d1d6619415a801facc6ad3b149061582102f570018195c6c39e4a9c9bd3619cb3f230894a5d28bac23104b7092e8e74e99aa99e1fc3c9a15d216a682925d0cc266d6fbe018284b288df27e888b554fedc7f10c8177f7c0bf0023678386f5ce97343e4f1e15e3ac21e3a86bd81e2f865e2469f38a32d2e31011c0aa4d78434ebbb3e0724f846bd5787d98d3bb6046491ed518d9b331a3a2ccca4de4a68b25ef9f73f5617e9fc2e723f8efb66836a893cd53f2dd129e43a268e404518402679eea779b5599e549ebfc8a9abe1d51c653663d7361a10f4602876c97f1ce99ed3a6df9db039e5d284f7b08d9da26db8d1840a2c52cf74bbf45e82752eb926ff3f8041438ad6bf196c9bef2b70091d7e04f193c84a4d8987ba5fcad8f14840e10768f62e5eb3af38c564d0c48befc7d2e6f14a4ba0fb307e9b76f7f2a35049349282ebd7475588c2d96d231b8efd01785f646faa50765eed27d6e38b4a2fd9592a5a7add68d1b3c2baff2b13ab40af698707709b4fde083dd7c38fc70bee15a1086e94f8716f4d032d87c1f6da0c7fd92f1ed205fc5ee40fdd569ee1977ffb8a081a76b78283ac716b691cb8381ae49a97b067359b6f019a4fd53bd04e541379b02b43a3360157e3615e031ab915d1be38817389d376eadd7e52a6562b5c301eb609b59ff55983386ef1536906a5552ff3bf0de0c364a8fbf26f494387af142d2f6e256a0b5cf993759fd1141f649a0586696703f16837fc530017f967d0fdf1e3f00bfb5c82661dff24340786285c896b618a316f2f740a2d0b0b9da15a3918e9e735ee651f5ed814c40332e2823f1916dbc236ba76b4d0ff1fa05fccd902ff48f0aa8111f807155723477fabb7578ad3e85ff8ac018831039249e433c4d06c9c2f45933960fb7d24987b97cba4a3862baf98481efa7beea19c96d0de80dbc5cbd9a87100581b54405f6f53f5da9b254bca8bf1a4bd2b12502b2c91ec01000748102c021a1050c043a10b48781b289834bce6703ca95b7ebe5449c0f1c47547ab79d212e901032adb6eb83a894d98e37158571dc0d614099397c223407fee07b0e76970a01274a8ecb97830c2ed83241f6077b72a8a5ba9854b31390479d73b4ebb4aa8a0c439e686036074b87f6329290b4df0d1e434abb22306a963a31ffa63551e1324ba90739034a3fc39c7d748c451bfbc5107bd97d144d255abf79207572ee6b3e1433195936286a10d1e11ec80381701b7a282674bd66a50d1d283331a27802bdd57e17382866e4c7a7c3e58d212f8529e9f46209573f75fa5cf4e6dd35907f53ab5b21b1ddb208c84107b4ee40005c1cbe28c183fe894c68112dacebe47d325042099eb05453ad6a8e599342944a8f508dea18e3e55ca8c18095596ad82e9451a4170cc8cff887b03dbcb18ca6877a6de60a37f5560788e978099d24672192fba8038269eaa3253e4d70db6a44484b6817b76193b01e6e371439d76d116095a104563adae18e001e86be4980a3bfa0354dc6bf7ffd76b383e77913f00e0bb84cfa71da11545f33f23b9d97e138d6e65e2bd7d3bbaa7a87baa1c05e05816210252ea7240e858b5de33140279d9bf024d099cf2579727afda8c9a2343fc4ac3f56a737d8f076c70b9733f7e1b91980474b03cba91bc7a60d7c05dc4fedd5aaca7507092bd206d57fc97231a2c7a9b019851bebc4032062b1b5dffe29cc6db9b145f5701ad439d3dbc801f13bc0603101e34644abf16ec80479c638e77968e6418edec371932e153ecb6bd7cece0c901b36a9d792799f4425f192a09da8e1e19215d76671bfbcad556dd7c726ea78f7c44908a3a030968e749a51a3d2dacc3b5eea44124b398a5863cab73969ae3a9588db6418f3c6c4d76a166bd76cdf37a059ff4bac3f87cb6ddbbfc231cc5017101bb0024a27afd992652bf059f33bf2f3037acfc206c88721b9dddf3181190c3ac812567c107eef18afe71fedb1c508911a9994a791156ce161721a1837eec75661f21bb2484686b19991b46845fdd73b7bce70ae30a463ff58c989200dbbae1f5fad014a54cc109bf58f42267551a1f695e56c6997f058dfa0b495483ee723e01159c0b3a46d1c219286e66add52e22bbd506c75881676fa8cdb3d7322dd7b9e84d93dd7025e535eec3410b1dec4081cc7cd3cb9174d18a5d415d9f9991396f2fb1493e951ff5fca0bf8a718b1500d14e6c3670413e0ea21841682934702f4ddacbe402cb99b63da8f7cc387d47ecf8c35e3239cca022f9e80c22119979de0e6066dec1a33dddcfebd439b337b66b70c016d54c318b7211949bc77fe212b237c324e53d73a1faf76862818e7cc089d6fa9cb71c13ce7bfa48706a8e1054efa38cbafb7c392dca69fe3ed39aeca2f08f1aaf5d6f09bf093439803ea5aa6c8b0105a7aeaf507707992560b570d2cc9d102667397ba95662e976cf06e694bd5ae70d96159b51ccad0225e9aa46fc37d028eea7232ca21bdef4c7849db546799ffa1f2f58d33088d2e9a7176d4589746865541206864309d4e090ee14b533d2250b2a7fd9d84f9b184e16a653cf93ff028f2ce805822f0863a191122d5488912bd026d4b72db630305906b2ff0b734e35a724b9a2cade11196f03b610b0fe9227864805ccb7cc50d3dfda4591092ce1b205c5496a58ab6d933dabb6cddad9cd0ca848ba681849b7670b01f0225cdb36d10a8b05d8721ab44ed4e89d67b0f965d8aaf843952381de82d8b2e2c86d5fbafadbf6164065d9a9edc2cfca84c6bd3cc16182045493072c06c7228b90bbd4b453a22df9a6cbc1ca27e1bc4a59c1163d921f604017bc24db500a05b6ae801595f776a11f67ffeff2aa206a28ff673510e1aafcf19cffaf5c56c35e4745a807ead146313cf15b694a06c66e8fc139b1acfd3fcbb87d3e9fcf0dff959d9da6331ad6854f7f85622cc6a6e8cc4c9436ae8b1ad9151520351b51f1e36abd864995264acbbe008b580424150cad6f96770f3889386ad32515ef592a1eeb5aafa3688bc386672314e341e4ccb932a9806db33ad5a1227f86e0ebfe02ad3310cb31efa66a0f65649e47a6f7a337965178c0baacf6d01f0b93697bf4e6354569eb77e7d57cfc3e980bc35bd7b6447e4da09289fd5fd7e0b84147e5436b05d82e03edb3d69e5da6a4842f7739e76197bea9ed1638155b8120d50d5bbbef6b53fdf855aab51748586a1ff3ad0a569c699147b8c1b86ccbba510873b179ac7de9544db382c48e2a462b56080da9cd9b58241b23dbd7c1eceada3c539b35fb42c5e26f7ec0aca91bdac522af7befe090b77d3966be3551e3b20ec02235970413698a51fdb20e68a86882746b8cf69e8c08cabf9d4471e06c7e10df808768b64c45972ed623196c0144348fbdc6178a3a04a5e25e23a2a7523aa143236c1428fabdced1c5856e9a2ba97fa408c3ba88b3158f2669c23fa6a5d679d4b2c3177502c189ddeca20c28c15bb3c3ce3bb35255f3b4dce981f47254680d1b5e4eb20f83c1dd605ccce8188dfa24bb9c2e477df4eb99394afd2a13c194213e04952c9995475300d90d973d215be11650e90e0083d78f6fbdd641b48e731f8e14e6d1efef19be7eb8d0648a9cb8ce543920ec9803bfc73ed522509d224d14a380e04e4d6930a91f03e05be548c8ab993f596a358553670550ec2d0b2e5ed0d3be32bc21b4d4ae5d2c79d21ef9c02ef1371737991d1631e417d133efc8e77ac6ae52a9f3ee2713fe428dc412682c081de0d28417e4544ba214395330c70fffe10db494148198b2989fbd5c446be9e9a20a6382c0709cc30ded770ae60053cca092d7849380c241248df3f18d8fdf16b039b4da5c51d2049a3f24c6e294192fc8e8223a8c47bda9a3c2fa82f1a91b7b8eafb2167fd72c60ad6b4e4cab354467bdec2fc8fd68d9c8c3bd6b1f4b1b616166f75e843f7ce4603066fc47d0f857a6bffb5d50ce0c87ca7f240e7fe0a07d2b9fde735a0315165bd30b7234646fb70e1083a2ad44d2421c89f5bc0962133a20dfa7a284054fce7ae90f0e1caa7a72794fe3d66f974b884f7cec4355eb6a45e0873a81598a135c76965fbdc3dca786c13f09c7e37b883e6af2913595a7de62be1f2b7c158a71910a3928d49343d73659602d7228f90329f05483f70e662ad8b570b40f3e689fce7a5041197e6a9289931dd8187ddb39aaf28616f1fd12f040730635a17257537f01efd23e58cd66c5dce2ee1210b408af507b6fff26fdd94b39f01606b9ab98447fbae447bd7e79850b8ef79a323ee52e91d9d156da52f7a71cd369171b86556f2803636c7465110390f732d05f0cf95a241ca69b7b5009ff8587912cda3278513dd0e1ba50d9192e564bb174ccf3fa750c6bca63fd5cafc73ec1c0173e4c330409ac20fee7163694553686b6e5b6959fbb546bd2e031a7a42ea8bceb5eb35889b98cbaa0a4bc0159f65c2faaa1b9ca50f9420a3574085cc800c99b6b18a8969e53e25c22f39b0fa5af7dd7e0c5c9cf6414c73d2f99c08cde61e608fa3834a7fd02c9fb90c501792faeed5e4a3451efc66e4eefd1010e620644a1fec0a8e8db653d714292e55d3f95b08da2bd491efa61dee3217aa9cdf761593a7fbed3bdfd9b22ac7f4a2f8b773ab168cda079cf9dd59446cde1471334a69eb5b2bfdb4fe451381757f4d9f94485ee72b22caca81fdd800bd8be9bdc0ecd93f0e2f0eb574217b11933102b38808729045fc49149054870db8aec1eba49284a5074100d6d368e00eaac315438374c8344dcea87f5eff4b39c33900baf8357252825a8aa8c5ef9e8819ff7e98cee1bc4484197532306d7a9b93fc1561a6a5c103d586935c34396b53987cf20c11dd53796a33b8348aaf13733a9896a9fc95edb7909bf35c8f17fc64268d6200fff085defecb7aecea8ebccea14d5765141d607536f83aa21c52d018dd6335c6fd097e66610baf6bd4cc0cdcc636d697d7256cfc00ec492823c427ba8811ea858722592df5504a972fadab716206abb2ca84c760dcf8b09000ee9288e452989ee2c81baa9d8111976b149d8a5a0cdadc7b2e3433ea881b2010176a23c825d98b4f6a8a7eb91d79285ba1cca826afe8788bc0539c5e205a17fc167743787d242d7ab94b7b5b86bd7b5221abe9fd3576a3792b32a8cd601af4ed1fddd5838be36c04c105d896b5c4812ac29b67abddab5861ec581bba146d581e812161bdeb80842bd29431d3165d41153454cf7d0bdff9a2b384e916856ae62e888df06b953ef7e1de0a9281e0d8431cfef4ac4607c33b065eeb28d186d736b61e5892d1814eeae0aecd8fc8fb13acba860fe99aa2a6619f804f4bbb0e457647b5e0378bf481d84840f3d1838a18b1f8c32637114c612876a52ec13c376a8972c966a37436832b5de134544a0cbdd9a53f980e3a937a9ceedd93e3f27497d1c7f3ec150d43bf2f9e92e105fa791447944de02d23976907e1cf1dab5c4e8e4616a17b6362b731aa857e4fd86b17367a11a37e30839a90513e51228ebcd350cd4dc166f96a58fe0f7d5d30d395c23e279f52fefc49e8c260566ea772025a1822951de00478adaaa4c888e79f4f7de646d8969d635bab9b070c2ac151c7f4d2583457e347e8448052775a25558d94035af8337932a17c1994e42262dfb27c8fbb8a4b74a0eadd60f4a5985f77f4f785ed86506ae720ed2d7ee6a489bda47a93d233ef4b5c4fa33926e185139f98bbd3c458d0c1efe1ed92e756d9f56d78c73593e6200a5fd2e5597373f3b2b501dae3d1fbfd5f679dff9d06dc31dd0c50fc2707316d94713be63536b0f790c176e535982cfb827f0748f722b5e9645f0a92fe86078c55356a65cb17c6e62fca189589d929e226dd7f94245e7dc655c7575e231bd812b2f2bda0ed976006b161a07905e0498484ac96e5351d12b91087c2e88906e6a8f887359356fcdf973b567e74156de347694bdcfc49ed9a6e9994e3ae781d74fd8d63b79304d63bcef33f0d0a33e7e02cac014c932f43f4eed26cd1aa80ffd4c039a13f3998e8e957fa69b1742dfdc3fc95ccd7a0228d4e10fa62a079431c1304a889ec8fedc4298494667789e44c65e7f982501ee35ea2e58c069badcdc6c16cf924fc8eb89b4d3d62bb2f02f8261cdae6c305b39480f9aa9f12fe7d6a62996af1ad532ad52508bd75e1e3085aea2751a08ea28aefb5af9e8b2584ffcf36fe1787da95c814389e17976e3124118a11599a77c70609470de56b3f56e14522ca2befcbe1d439d094b886fc1f5798b5b8817cdbc14b89bf8ee9f5552e1585463db320567e41349cb7ae4f196a88f997a5aa86000cdca9f5cecde1b6d7205b350217acb33c1bcce62327b58e68d850e7ae43616e018fb66cd2d63e66e26f82f11b53ae10dff27d2f29eff7a5d04b2dc7f9cc3030da91c39ae2764078ff5dbe221a8d6e2bdcf60d619c05701f9dc9f5fa8f62299251a11a2853790d7e1cfb452edff732ad00f923cfa84034c9614294111aa3b5e602dc05227fd2b553340117663792dee3ee603664e9eca631c6610fad3910e87c488a41f27e704895047292d8952a8d725c0b6010f936cf493d6be002997cb0c99cd2cb23f73d31f3e991a611fbabb7019c7b1fd61bdb68b5b18fbfafedb1818377c37ee9f984ba5b20653454dccffd78ec70bc27afd70c27a2dd52b854fcb794f11263ae1208d4163c03c08298d3e454fc161336bf50bdddd593750731fdb111c556d055f598923fd45737de6dbc32366a85082c33c339974a994138d8ee9e22945a6d01d4ff36ba275439bfc75c530cd9427affdb7f88f9a358ea9af1d8001586b5ca500f39b48dcc2809cbd281fccc804ba23e319fafa76b23aaaee0e3de7c64219027e0a2508a257d27b3032cbe3141e086a96e3df950b8ef032c322b343905d39eb49cad6022767904f920dd4ab42dbd587de305c56485e00f57bb0828e80f12296860139074e20d5cebd69c58fb3872c5634c7f3fce6064074425ddca5ea2928beaa3e37a1fd7a465b4cc2630ad78c65c09f6515a23017d25809230b21390e1cb8a2043ea240d2f0b2a33e7fbc4a7df8f294f81c31a50927c889b02167b35e372ab49c00026e62bae049150cf216180a18ad05a3a0a1d943073b72793264c937d01bc31ed961007e4ddcb38e1c947c4827795d2b3d2cce731395c66699abc829b15952ee0e558479ddfc761bc99331c28a8ea8a2e3a167020240a73310628c7168fc327c7f0f0444345b2190f662729f2a385608bbd72b752f636ee3b75a9498fb8d58abc6eeddfa81029111b056284287cf897c038f53ac5b5e129c8dd734f6a174adc4f81f0c7ed6894f00bba4189ced47f111451ecd1b66fff3bfa31a91d9953bc9fa70e8656176cdeee30d36e0de408a3280270d42f410d16a160fa8e48a79895624f29dfece2ee6ae1fe5c0f04c63c0322706905d43ae7fd5cbaa85db946e074f27f6f5dc095a8eb16a975262e6ce0221569d0ac54c09a692275c8a6c8f05db52a574f4e1f8aa28c7c3b22228a5b7f46b86da89512a337ff9041f1f50f49ea1ac41a687598532630bb2cfc9c71ff141e09ec2fd66d5aa60628afba6361a375cb2a5758acd8fdec892b1b9657bf627ce9efefa3f55761d6a429ef0b1efacdc06a3027d1aa082e8c3b9fed27c44803dc5abae1b962eaa1e92267fc4a86604e97da56649a8e05e7f53f770ed5d9d58f47ffd32a15907573e4442d49bcd99375267eb38d00deeef8a40223cc991e4cfdf9c456affcd49c4aa87cee39e4738f7cdf77ccdd4c71bc9267562f96489dcf5f86480176ef536c2750400508e3d8c6eed97079ade0ed269a79ef64c2f86d07c92245e4808b344c47976798faa3dfd9cd4f6010d51ac979f63cf36f5c2c7efd3d17883e8d09c00e933e3a60d0e09e34477fe5a13ea9f523c3380f2af1feb3da7be6b0f1a2152999592a2b54670be03f4f2cb26be1bbdfe30ce0b90f11652ba7803fcde7f611f2dcda813edcdc2b4dd5e1fe9f2bea0078bb074bece6e238c46b5464775792680b42913d74e893278a304f54d743e8bb4b2b76d020a6d35d18d40691fbc37d5a292208d87244b93475529dcfa4f32090384e1534935889050bbe93adf17fa04d420219d0aefd7211fc353d88b5c349f100b1f74772ae248e2352339f96007693d4bb09eba6fb972965e24dac95d6ec39e379a338fb1335a55d022358b55da75a6f34c319476c2d1de53e220c3f68c4474ebacaa506b54cc817905285c992309bcd922af8f0259e660e6cf2e3516216ce0deb900c3485d3a309d193ae8b218bc363179a4c9ea971404b0ba2a0bcfddeab4d34b8518c44f8c274bae5bef670d0f8f63921a18c03bf89e66b212623932235f8a15247c24154b1092aa0aa466aaf634ea4533a9a4dbb7083d33a1a2598ca0d7919fcd3ddd5907ebab98c02e0de75ab43139b80b4c4009bd4061647f6ebd4099505a5308f742cd358c6fa40cb55e42b6f9ed50ba45b53d7617abfe1824d99260afad00b62fe2fd080266dc7fb2d5d3035e605177202fcd3959018458d89fd50274552a3fcbf7519f6b496a0ee79b127e965634686014736883914ba039004ed014d30b96f62b4f80d35b77af9e6d7d53e9342293ad6f06b77d674db6bb408dc53bc94d6f600c2aa2de52b93066769cfae7e4dd86a4e7168002eb98d6ac2a5a55abe4a25443915531bbfe2bfaa682552355b96d5faeb9cdff21b81a5124d73bc7f315f0218cfdb181062064d3e4ec2a4012f2dd659c9c6f15cc863da4eb1698c18b61a61a36e47292a4e673f95868d2a21d3f0236b767d725ac4c66186fb896082bccc3ebdaefb8beb157d72f68b8b297348f799a3c8c2b6b9db39e4076d9c4fb819cf3aec84147b32bc312aad2c3cbdfb4e768f03c71bb6ea0bb8ce606f30aa7b436f37b5205f6f7ebba02990c6fe36f9eee50c70bcf463e27345b06bb36251e34f961b29b01552075f497e7165d6693440bd948630c2815b71069337dddba19955bf08bb19c4275c71da9c8ed21eaab3d1bd1e86b45ca30d8efeb83028635bc2f374ec6c68534e5c069cb38f00c0410033ae7c5635c301816a7036902b06c327b48b2adfd54d2124995e030aaaa252c33661150b117f7744f3263896aeaf441c3ce6f8f11c579f5c3003800eb0709e0081e88729994dffd066331e4b97c9ae5ae784c401af11f85b4bdf7de524a29654a322b062f061506b8f678141c9a5e3ee37d6732994623ea52f1ac1cec61b57e8e247141824b43c51829a5af97bfa28d9b96c0a155c5bb24fbbb929c6f0b91e14ab13ed97fe6e09055cd6f287b12584811159d60ad1aca42d1569ab60a40f679f5b89ab462731f39f09aa2e02b63563e037afb78ff781fc9fe55a8d6ae5181bc1f7d5a9cbd9466527a3754f048e499543e7cef08631189e4fdc797e9dac0d1c35dd596cf683370ab55afb64d63f9b47e801c6ccd3930622ad5ead5a4c7c503e44c9ce53fddddddfde33e8f1852c28bd30ed7428b9311181cba022df43513a638b54bd28060830d36d860837de3dd8819041d741074d0c18ed17a314ed59c2a9fe9d7c7eaf19948452b4af69703b9cb99385581f94ca82285ca4b85c91439546992fda98a14d1a66b989faf5c45a9ab5ce52a3a677bf47956ef2b57a9bc84545e2bcff2fd85352ca576c99856791291a6877ce52f49b3f2282fd23321b9a67a37b4aef3de8677147f425bd648224db7b8771faa29d9af94ae5d4ec41887999f237a96cf19b13c2ead744bcbef741fe3459df7ed78bff23bddb3fc5df996d7c1f2e93092837ff43a545ef4315ec7caa703ffe85bbe3f7a30f3d341f42c8f4394d3f22bbfa3f231708c7ee5dbc1dfa2f22b25fc54657b992387f57d20e5edb992ab9c2563dc5d0efacb93f81127fc4793f68ab81a492be91b5891dba562f90cfd99a97295ab6a55896d3c36279d0003cdf9d3b139a76c9229d5316c2f12f448d59cb4afee4e030a51aed9bdfeb9d3b77f1c20ec12c4f842d848e4ee915fa3741cf428707fddb30208701863a42f6253a628c5409b169492dcbdbd2448fd99b6b8f7436c495c6f5ff7cb0753ee9fd4e551a033934422d5cab3a26e7f50aa5d4dbbda9d01064c7f381bfd2534c741d769d40c078ea99b6775a748a5542e263c403e5a49563e5b2ad53454e0ee05c1f175c40c5904310619ba86471bda29120cbfb2e328b4f950a560904a6202f38b1e52339b966a3a8358a33f884a915b86548af3a2055274e0b4a3b680e7c9edeebe30d88d93ee271a484a89b1e72288b7043888a720fbf711220d5845a4f921dab8106d3cba07402830813404dc5bc4d06b2013e0b061edde23fb93dea6f661c3e4508461dbd140024bd06130873dccd6b7216f29661f4098fe59e7d7b0172918e7c6c1380404077ec080068688c0b06b5bc352344d8b5adc9e466ee9ae2b6ddc9783f49938c345f03aa812417f98d479c92fd9df036317d2051e8c3aba79d6a1a37bef75887ef430fd3930fded30fa445f8dbc8182c31a124cc3f40783d37929905a80018056b71bf4edc3b47b9393bc4030d475dd48d48d4428c0318754e814d6c8bff6b59a58d3755dd775df8d442351c7d5785ec76d9acf0fd091ce2f165ce421093eaf98929e17501537b0f686442299482692c94432914c4d60961c9aacb5d69a5e883437c04c2653f69c83e326ca3c014b0f0701340187b7051bc1414f60b01b9e550fcb1a818b317291abe1441e27f26a644d4d0d1874d619d74277f09a7d8da331ea4363523ac7717f1de444decb18bfd633b7755d0febc54468e37102c762ab5b4041508ec47e604f5c1d2f89445ac9349ac09734e7e448349ac04e1c0c7210d6249b9ec061b7aeab8344d067b19e28e3da13970ee090348a02eeffc9dd32c61fdbafb57d303a5818ef5b4f3450b45f8e50f6686a255e572a9976801d7461082c5a62f296d4beee569cb57a6070a2777f2e502bce3640844ee5008f565d7bad09c7b65a2d4deb612589f9b06d6d8ca0f6349c66fba8440752849c7654d511a7ad946b0b0c734ea939e8312a9145fb0430c321680740801a2f4bc11b84527a2dbdb6852608a133bb331db41833dd18b3314629a5f4da6b5b70029d3a3c2bbbe40704417009fe21ca3808fa100cd32fa819b2e7a69c70b0b1001b82a24dcb6439ee6d7191071f4841e24212e301c2fce15a6608963924a5d0341b20c5d9263304d3214370cb0cc13537d93a924824e284883316cc70648cffbd18af208214f0b050a7ad0614cdb484d521020e63cc9bc1021cc69857039c68234494f10dfc9019c145cc4227080e4df2fa0c73319be9509ed91e0954f7de78a397db5ddb3c66c30a1c7e88811c15b080ec82e1324aa9d52b0428d6a48a24539a44616d5bcf74bab76ddbb66d3b821409c40edf2b0509f66e6c52aa2022917a96450e3b7563f349a303035d43fbdceb1d94ce6c06eeefb5b84382527a2dbd5608b34d9bdd999d6ddab5d75edb02eddaaa5d5b6db5754a4aed16d6ce74a6a4d65a6bdd6a9dd564d74af406ba63a8439a04451343486d449b9ee098bb90546323a0d32a21b821b2ffe66510647f8e7e397a70b0861485ec94d6f6e03535b6dedbc3b2ee3d018323499829992df951222382508db576ed28fa38c22a2b2c2da2afc5646201c1957f151209637c6f1439e91314a2789d424c8704e1244272d3c9faf3831ead8b2a2c7824ba9134f1848275b9bfae8bb1f362f47bebe671310526e4189282bf8611b00b4cc02e5081ef8b9480ef5baf06cf75094c818851667e1017b0b9d6bf80cdf3b5978105ce80acef7d5f0e1fccfcb62fc7c18dcb61b338d4cdf5b3396c96a8e6e0e4207b256305d63e6cd6f65a69cb5be902bd654d86105cf34d926740a4e919c418ff1933565821460caf07be5fa8b98262f303386cd79c0ece6863a7124a3ec083ecdf4a228de66ad76c97d7002afafa4d1ca87703fd60401a204b4640bb60fa4b22932907bf5152bfb06132ccae87ca45838df86a57a53cab1ea1ce4944d4994e8d398c33edab76b94dbbdca6dd5a6baddad56ea53ad6ae7aaadb2438c16145c9862c0124afd5349f578c91467a2975a104783a28e3e28cb0c65ced7ac95a0a13a124411d05d64ea6cba552a97e3cd9a9240d0e1587a3d61abc8c23a6458fccc5c47466826404ae7949010edbe592342e6f060b707b37bc1ae0b05533238932fe341d83b6a28583259d842bca9882e017cec1f94148774b97cb45e90605888a4ad6b21e5af9b4948ee229ef99798f8a423941499a9b9be8d3fdb07c6efa8b680333bde845441f22f613b2bfa905d886985330b900d79f72136d7cdbb6267003e8bfb4709764645aeaee6da151865a3605ae5fd8ae8cc37c151c2491b620cd66783b68df0ead92311ebd1b20aa652d6b998fd3b80fef42d62859a3648d6a59a35ad62859a35a26539179ea895050cb82a4ac51b23ac567a84c26b376a5aa421663d4a286425d7c3baec348e0fbf23dafc92e1f3f02c2a83d5aa59a16a4ddcd49adb3e9cbc4c2e11d1aba52eecc67e45b296bb52a70860b8220cbe72ed134dc4e648060db40702703046b39c440300622030453192078ca00c12e0304cb0e63af1fabe00ec7190cf18523b00b45e0fba2170ee3ac57ae7ac4d2936481f2b3ec965d188e05cdcde5074f10d1050a750ac11444b299f6611cfaa1f36edc194ac09c77e305223822208c9b1b84b2b0424785a383d383e1e8dc6bcf893a1920b8e6106b0f53011f483940e56d0b796cdf7d1b5e3d0670dff6f7a77783f6db17daacbdf470b8dfcc04d36e8b35fac08fabba510013188e1081ab4b04034c85603958a96d5f03d7a520055fd22b684684fd07791f14148bc160af5705aa401186baa96813ed1013a7c14d9ca64ff1898d526596c781ac4ad2c45392233f3ed9f6c07275d519cafb3a4a059a5f585f7504d8052af0cca1f6a829077d5455e5a92b1f075b0ea2fae505ed011c5221cab3528d820819c275b9f0053ae24a12052ef25083d70b62304821e1c2ee7598c77c267bb8131f72f7208792fd6f6cef1d068339cc610e3bd15802cb68733fec1229d31cba4c460afc0e138a3631dfa7e91e1ec569763cc66310820346b0d6bbf0295e90a4e1429f7dd15fe36c2bc5ce7b0d3c9d3c2669bc177259a93deebd6f8716e18828a71dd2c9c9487d1e27ae3bef064ee77d366e704a385e39dab0026ce231073d96c2121c7abc42688819271d43e71d07dd648497c36036dc6b408492e7bb77438818e34fcad1d381dd273e63613098a6f95821511615440089547d80e7d740226512c9da554f125c05b13bc618e34f4e46598a3f6b2c0104414a691114cacde39fee99b058d45a25bd21de4a5ff8811373b0fda6f667dc3808a3f3e69ea0043c28c1870634088a45931780ec830c0888b10825be3c9349e4d2f200001de4bae770e6646812ea183dcff33cdb719c271279224fe495228053b2d152fa90e4397c97926b1d26c00d1134c9b870cda21b654cde47ef6588bef0738ca7a228a3c9f8e8674ac918d1674add307284f550cc97482f58854a9a96efef5836fd8f2909f8c7c736bfe87d22d19c9d272a5d4086217a1bbec2f23ed8a021079c9c128e120422e0a083dcfbb79474827821cac2e0c214b3c8563c6c05256aaa4ed1cb1a821b2c19caa94f60b01bad879544f30d0a43b44bd06a0105f94c3cf2e3307fe22e2af2be2ba5eec9fb767ac96947cfe0347a5169a7837e0005d869470f81450874701acd562bdac000146da4057f060b87de72a0d38b46eeba0f01d01fb6803f4efa5ed725072ab94bc6f8cfcea7f01a647f571261f0ef1215d9df6f106bc418e3edac3f91524e9cecda579b776354dae9d3e839973430ddde779f8eeebdc79f0e2339dd7b3abcffa0f4cfc8456d9672b8c0a1ab248df7ddcfcf7954de771ff610ab87f7dd0deaad2fbc5bcb6136a4262573b2f34acdc4633ca69b0651a6c6e8ba0a61c066cc67fa836e141d83a37e601802f7d3067270c614dcdf2fca030833bffb78e2e1650c8e88964699ba8c7157cf869ac5801ce6375bad1cc7b96b611a5a51c68bc418534c4ca9f4f2a282bdc504f66a796b8626f199d96ab56adddc0509edb56227eeb1bb3f76b479f1a649814472130a70d028b70a382f4248d6ae7aee084ef0d30314638c96dbc028e39cc45e0e41b063d034ed8216a40105c639043b6e0329d844d3f470879096740ca0e81612c9c07beae170c3bdbdea540d411a50e051ae5ad594acbac7b768b590702a0a6ca7b4b6c129a990adf7b270939521989ccd1ed2891ccafeb28994c92932688bdd9d4aa552a9d44f2a95ea940edcaa87498f4cff0a1d3c0972dad9212385c8a9fb1dd2074a9c3c98142b62b4a1d94bb06853e2220b98ac53cd72181c06aebbeb7354cba189e3b86de3b66dd356600e46e9803e5dca6d2ab904026ce4be8bde7bc992e9d712bd6f83d5fe76af46dd080683c136587bf4a352052660ee0bdba753d166fb311269e811609d82750ad629584ac26c1421bc75ed03a6ffc2ee07d3a14f396c04236f24ee46d204a5242cdfa0fbc4673409933009e338d68bc9ca90e4b1b98c1ecd9aa939532a17131e201fad242b8b73a37bb469cbe331eec3c16863550f8831d81fb1460cb68858c36d6c08a28c7f68b91cc65813075f4c665370a0c030f7086b5529985e604282a7b525203a57cb93ad8f9bad0592fded8f58c30370050e3b35e59c499a4ecd24ca6762af82606abf4b2c39e3441bd7aa774375e9263c4167bc839e5ad1982058eb124cbfb0066daffd0e9b66aa4035a654a5e99f2e225559a9ca4a5556aab2529595aaac542a657d58954d15b1299a5aa4d27b6308118931ca285128140a85aaa8966779966f87e55bbeaaaaab1437dab6e7a44ba7a9acacc450c11cc7719aa6715a0d365c4ab96d52cadb45cf86edebc75282516929c168a352e799455224ba176312298785e5b5524e4bcb732e31845c5ec6c728c19062c888f1315c3a203ec6afaca8689ca6a2c550c11cc7715a8c185ebd7f6d48fad8ebb652c86d5d4b299e58fcb2b0b0b0b0b05816161616db29541e2a0e0020b58260ad344c297c8161eac75b4b24156a6654f73a89cfa0b94010d4583ed5075d17a39472f42a4f430c098843c83dbf26dad09aa19a4e89adb7ae9ab4f8d32504a152e88c0e757428a42d158c9fc6682c4692c1ab71022679dfaa063f2e511e96cf650283126564515edc0c5e1c277aefc3aaed3898e25e3433578ad9d3e13e93cf399170534c1054dd1fbb86fc2e9140d527e0804424e28ce59e2392fdca6b356e9be9749d83b01713e674423239a594e46181c3f4b2c59d5f88e79cd286b1027aefa41f4be1cd34663c09bc55e6f95f8c4f6be5590dd518638cb55d860c982170f859fecf70bfd6d4d4b07cba5891524a29a59452ca8e31ca643227a61c584692bd0c63197369a400733a58f8586ba544a204c684f7981479e06348c86967870a5f18e124fa1d9dc5134ea30f71f66206a79004452a892557b429612b5880612f94c3e02ff2915dbaa28ce148f4bbeeb1a4197d47ca368726ecb59452761804e5b65a02010ea54bd218a11286034bdebebeadd3d2b741d2ed6d69fbd671d0419a439309cfdc5ff8ee6ddf4854ca116dea37dd22c6f81b31e2021724f124398c32e992ae1f078160303a8c5ef439a22f27ca18ed83a91f5eaf7e3841d45c1bc044ea4fdee783c77c3988e0f0660ac418ff1cd275a9cbe5b2b6674588f31838c04d030a2ca1c00e05b6392469a4196966fa5e46dc0e50f175e5ffdab7eceedb311265ccb7d37d221b5c8103d5fcf0d2800253ef26fe56ba9ffd6c485b92f5068dde0d5b9e6fc303f7f6edaf3398050e6dca89546aa65ce5a0bda92a84043b2b6a96d692ab9ec0617b81c38e75a59da9c409ac9872dad152b84ed16190ffb2021cda94bc76fe8b1338b43345a23685c304873d6453d18600d1664a1a5ca4635648cc26615f36e62a0e8542a15028144ad2dc3b438160afb489642a99b0e972e190a24430fde588bea3288ac225d28c2870e82c1084e9c7cfe3d495ba177d4ef7a2ef17a93cfe7644aff23b31462598f64a30fd2dcfe3c4cd145679eff23b8c1ebbb0bc37572f1f4f2ee349bf83cbbf7c3a44eff2a4cfe575c478191f4f261850d88bb161c23c4e3c529c0f9f894a3c9002ab9234555687648c75e16779d77c491a19afb13cf67e144386cb37bd29f0fc4d54c2997103ccf2f8abe58931ab7210002cdcfa71d075f0bee573bc6f61f1be7e39a3b721bdae144fe164e11c010755463d5054385134d79f434e57794ad9aa0ded405312b41143b82e87bd4a22d2d81f76e5c53cb3a4434419fffad1e99a61030c633f0e0d8536d55af8402691431e5982114b4dd54ccd5414d3355d93073307d306b55f887481ef8755166de644f9ccf53a7727b23fea0898aaa95a53d68725c090e5a128eb635b16c826b137e533b407f5315d9c3321faaee4759fba27d1f7d8543c797655efe72a077db0a9a020fe07959e85f855d0342a9f7596b3f04731fa5e20fab0b320bb00724851dd57801c52148e4dc9989e3d78bebc63d3758516b11dc4991e744c08143543a166a83b9bd15981240d2de2fe480295a2a8554f2a956225710112f1d8dc003d34d513673da82c8793fb736b0e2fa5d40996ffff4f3b0715387c49678e5a8d18cd7be7fce8de5ee700094582608f535e4a59140a8d947647fbd6ebb84dbbd6ebb80d04afe908a694526a499f23edcd64d2e847ba74d6cab35251d75c40298d34ded46e19340ef1848f5fc42e602aa5979f4974de5856ad3880e812105e0ee266ebb7f4cac0cdddf5ef6b4166aba5c9081c73fd82e81ca30c13a93f9966b831e260f9485164c85aab594db3f1b5c8452e7231c678638c97e39ee32217b9c8c518e3b5deb9f65dd234ab69d63ea769d6daf0db5ab7a6b5d67db5bff2ca2bafbcf7729f6d2002ac70488201b17c5a3f40a91c49ad1f1289f4d3020628a57c69f98cbf04bd407939f2f2f3027b79f2e27a6192fde57469b9b45c5a2ead9683fee3a0d7dad2fa5a801cbc02c3b8fce41597560b4a5a60f27d91fdbfa192121694b08024ce5c165e5c92ec2b74116dfa5f90bc148934541563fc1b89172091a6a5155b5adcd7052ebd70d8d262a1489c19f5b0d08a36dc6809167ef288c80a41d146fb91128a449bed5f5ad1c6a240db8e90bdc5489c21755b5a3e431590024fdd872d4f64af39751f722d3f5186ee7d4e2fe69c73ce39e79c734ec1f3399756e8d2a2cfd9aef3eac5f6726921f1e2f299d0a5f57284fef80c5deb05c8a545bb518fcfb4b0464bc49916222dad119196d948092e2d15215be97e0bab85c86ccd0f5b6653cba14b2bfb5d218b96960a45662ab45c5a2f2ded5b2148f5d2a24f55d1469b6f4bb724512b28c81eb938828ae3d97e442540740ea94a7bbdb4b23f0b2e672189cfd097d64beba505c65a888c846a6d82d29a6cca72ae2005cb196b2ab576d53312ea828b3c2899726475e4075584bafa49f1d499cecfbd37e6164449fc28c204846bf65ef43a4810a902074d3889b8799dde6bbd0bc4f641dccc44f7d867362a4a8267ae76bd1a649a803d0371810e23d715b2fd98483d2d31d17d0e91d77d3b1ed39f0e0d3ef3836d2082c0dcb5dc0d2f4d887024f7dbd96fe7a5e146ace17f4b364419b7b1f3f2056e948e83de11f455e94cc7ae7a443a3031791a18fff4bf97698c9146dac4490d3243709dd1bf6b6a35011763d46452b4201c9aa6699aed1b2da84f2b2fdaaa86bb07470f39248d8b8ca0580b4ad69552ccd12a0747a4767db8d539e0dc3818a4dd6df369a9386784524a614ba802c86967870a3c5c9cbcdfe1413c3819e9c774721c95b1ce9bfd0b826a7fb7edbb12a6947a05faa536df86aad99ff7524a67ad3c2b152542dbd0944da88738e7947405388c423dc8198890b27dc41864e81aa85e55179d6d11c8d1c34b68b3abd5a609f5c071429e1426b8f75e6de33aaed336aeeb388ff3bece9837d1ebe0bef35e94237a8f13792621745cf7c94be7bddaac019d8aa8a48dd8f5346404000000000153150000180c060482c1804834269aad637b14000c6382487258381a49844910c43808a218638c32001003000106102022212b00f8db66f517e275de0fa85bb501ababf2bf914dc96a985aa021a7f1f1773ae5f5b44ee3cc4fbbca2bb3ac5218c6c5a2e5b7c0f3387a0e61046969588408ec2ccf244a3d08ef5604a6607153fec40e09fc441c8cbe66d44c4aa8169a134a6608f72a4da0834cd6ecead735a951038200eff1bae794b652e54efc0093619a8e5f9cf9599702d5e5a884dff8ab7a726d709e8e062c6ecd2964fbcab98b061927900ad8b4b73df82719247e41a19b87bbad6b7e1d6ea8ce61a140766811aba6c1df25f4eae688a6a78d7490a260b4f233812512a2ba939d3798b9fcc9b98f6a731d33558953505dda82266d237d12e33e5ef06ac1c1d07ae2d34971d3d77c9c62dbff74c5a1162596cf52334432c4f0080557a1a51aa233433e8b07194e584589568203c027aa2183b767dfd8ab41271a24aa06734e34bc17245938d18112b15ea7fce7563c0009a058b674c28cde843511a25f5759008292fa5024180a7e7e626bce7f640cdbe0611ddb4fed141e3b71250adb2689a2f2f8e498c00729fa019df1bcd8b5ad50245d46fe38f63160a2ff3efbb1cf82cebf15d11a7d1716df020394a3f07561ddc3f36ee6997b661a1e7079adfc0b8aef01c77d70df4fdd1651040f1e4c80db5e6fa323d56b494d45031c99a7d45b80ec310e970606df99c42ade7b4c9b7601b8ca0614f6a743795ada26b22ec2b1700bc7340698b7554e4262900a7565bfe8ee9a2cbec9910d2487494a9f9d16075666f2687d193ef5853a484ebd22a30cd2325ad7145e095e30853b0499f5d1c54760d6e4b16d1f3583f2b52e03d361bfc1539128719fb379b715c5747ea35213d986d224e6cc96655bc0d18a3b8975635d9cf34227eec70c553a4cf870ac9763a897e95446e5b33f9751b5f63240c6d8943cd3671ac11f654ce490f2fbb16370fed3bdaf2cd44036ccaae75a4017389ff4550439273dac59ff4bff3ed1cbbc87b6a82d09b3a4fd53d1f7f1ef2424eba3d06112409ae68cb03c43bcd961af3aebd2b87c74760e2563e6375e87a0267bd9b22ae2a1012b4cb07c1243411989f2ccc2563dc9a871489a6812e30e78310b50414211c51f9f59c178e9894ba3551d18b2481dbfd40cea30dbb374ff1b120c50c15c511c6528db4f3c499bd0a6561129abc0d6712b7c52d1c406efdd223c8c5111014016a64bfa858e8ed3a93e2d1fc48b62c5c1b19a16fa329e622e2143d6f1b3907f7f280662dd9d53de8268a229c436dcc748962c7556e71461768f945594a5358d14787d2e766a0f83f5b3015d28802e60c9017e1a58c9e741601949692c45fba41811b1f4058d202ab7f33907231c7d434c94f1728793854b5ba348eb49142f0494191992789304dcf6cfeb2ba8cc334cb43a6eba47e67121155c9817fbade0cd21896ec920a137b2194874024e824fa122416bbdb53163b0f4749c42c49d52a9c99d9c04264f4e49d6da8848f8ff14985ab02099131253cefa908355c26ff022c06d2e503cd79101acac70815c3145c3c96de0c4695c0598e2f0cc611b8e7e7a7b7da8d7c77abd289cda7250cf4e65eb41b9a730a94a4f94e361962f3a7b54bbe5622ef1adbee4de2b818056c6ae3282ef48d921bb0403192adcf0bb657febca626129ab5c16440753129f45176659e0c6e626a9edcf5706c4e38493c4109504fb1edc2963979952fe746dcdfa9b74af9c598d572f5ed070fd94934650402ba6b06901a8d60a4284294a8f00a1d687153a396bdfbe1a4ef51e864a232dcc60c7504aa8017bedc8dd48e01f88db8f5a55454702626aab3deaf14d8283f5075c01ff0ca84844a873ce9588010e8f46470ceca4051465b560444a68984a84b94ec4f42bed39ae68127cf74f3bdcff22282dbf25cc18a1f4d0596cb0116f8206905916ca8159719b5a7ab4a170eeee387cba37af6686c91845a35bcd72c2fb6ef80b47de2821bdce5a33b174fd5afc75c611093bcf6f1a838869d06af7129ab28646cd3ff95590e12bf0809bd35cbc6d284988046848eb902c18f2ea6be567167f3c372e05013a6b184fb9763d4d2d8ebe825dd65f2d52847179618a14a9288b8b0308eb49ed996ccc1835bd9e9ae588282fc369ac23733587c232ad1c5280a822df94719d5c139c1b4a2dc4fb4dfd93e2e1fbd11366cd8892108eba2c79c057e454823df1d4ee60c16230f20f7082016e778f05c6e33580a66265277e0bcee17696881c748383b1b7126483c373b4da5ffef28f853c662f8e6aed2313efe334777a1f2125690c38d1b289b5e4035a995c92f228ba9fa994f78e8d4351ab6a6cba9062b952992b5d09c3996c661cedba4baaa4bb977bf7569720aca4d3474346bd335adecd993cfc389e5a85b776076164fc0f5948d3720f97be0ae81c24f163e51121fd3ed9f75c16453ac2391f104a30b536085d1e852d12f465811a832d32877e9d1a41047b7dfad91e412f85f1503b0c161bbc63d804406315292e5eb1a136adcdd6fd146262e4b8d9bd337e70803e1cb16cfefcb5682420ab940b0e97131ed8d0289ac5e8fe34fe238902deda4011a8c995ea54c328f21040d7d5d2484d5e3aede24d336ea0a44f09546f94d693e3df91662cf03f6d083b2a36401b75571cd70d548230c274aab6f16adfb0ddacd29f24ef8aff70cb087fe03c29a4609b21a8db022aed55201b72a562f0c8702d61d597dddda25d38c2bc920534f5099c35a854fcc3e70882ccb80026cde794b78daef72bb3ccdec1806c2e86e010227cd67388f142d8ec6bc1aa6506956f6b8beb9df63c8d8b6baeacb9f20885da7f811247d11923ab1304f5b404d8b9591693aea9e3ca7d555bc62fdd8e7098f19b6fde2883f6b1610ca351a4a33e31c4f1ff0ac28c4a5088a6f8d90ce1385cbd44666d946426fd9c36486437b1a3f2c65ee69edb8aa9232ca0008cfd3e4c3cd5b1e7a5a4fa85cb029e17da3e89af16b5ac52184d6f834f52f79f4e6ce4e820d6f57465a5d4e7e69708c1f0f4cf3d36274827c1a4ec316838305644594440b8c48a3ec820a645ac8483feb9c3b8c8ffd5d8a9724a46a1b5518f846f9880565b7e06bbd2ca84e24f3d8719e2db14e4a9a8dc222ed0c342b75f3a1ad0ea58bd081d29d7f3860bcc846e85ac13dbd22c04bd7a978327461c8ee19fb3ac58f51ea88e05c25444f3e8dc9a083dde4e33265bf0a82f967f596cf410f3a7d5f828bc03222d5305f1f4c5254ba83036f5410b175f4dd4dead643daf4838311601fc42b6138fe7d7c63966faeb9865504823b4068e4311d34c9bd1941424052b50192888fe761019933d85b9c0cb0d76e4f1978c204a750ef40aea9c06de2441dc9f8baea3e7b353b3853f003973571ebacac136e2b6f0072c94f220266faccd1fcb942638a7e2a04174c77352e12b90b762d89fd164c6210c27dc18b6c5fa23beec364a74f876207088e0e9d33ab45da61faf8ef1a2c7424ebbe84a889b74f79a741020254511db2f494e343e758d6501025c7a473cbd794320cc4b12a30051cc43db3cc136f0c1d81fe8745260078447a2dad8ba6454234230ea3bd83991a1cf82437321955b4acd4d964fd7235a51bae5e9115db53916d3ac3c6c49678e6c30a11b762e6d114306adbd692b6fcdb2d79b14547f50fc813e056fac38170dffa1696705e0d980c7d9cef8ce6e28892672eab810eadbe2678da5bcb7e4c95b032315750c230ac56f8b358940228e5f47db34b9e25b458b10e8d56b15c688b433d5d1e861fc0237a18e766a46531ac8cecc1f9ad502832ed4d1c04a44262b04c940c91a3ec20bdc2a91cab45f051d8341bac453521b663840e8b04914dff0729ebcc0148369524b735bcc1824f800b7cfa20974f82b45d8bc1f4807fc70c1e0cd0904394fc838c600e173573cbbf165ba56b2e4079168cf86a1a16c4f9bc9b8706ffbdcd6c7794bb93264b179cc8bfb7a1e03a4be79cb8602755bf63a8b1809dacb43190f48dafdb3815733d368e9242958a40b05ed424c9f56b8490300c960daea976092bddfc14a0ba0b76b429f9fd5aaa70835b10ee2b67064f8a1ecfa70f296e27252bfba5cf7ce7c56fdd27d179edc1ea9133d7238ef3658b679cfe548dcefb9c60c0d1164d01e9c3fe8540b7a0d4a4c746ab70a7662caac1b155ac9be195bd7d4befbe377d2aa4aa16dc69006472dd54e2e0518e5fa13e7d0d22281db0722b1a7ff7825f442d7eacd4023acc8d2a3c41c6406e05d96d440dac2f37e71b8604d336a93b78da71cdbfe332333ad6cf787201a992d1652c6829d73e7dc2ed8b64829343d010437e9a8d77b09d964006074d05091b9d00c9ec88d1e76655261923c360a38352b1e2201b01c051aa396601846c2dedf75b81087c5f931629cdb30827df3cb37dd5a82a61702dbf6a369f60877f4a0412a4a65d9fed683aec87d648065df1edd3a1637f4f3a77b6cf55702cab2095d43d5aba9811f85a87b2c2861ef57cc1296914c4b8857fc272e053d170f2a7a18b7692cec7bc30a73eba8d4885253d651ad7035c05db9cbe591b58285b5245546909c6f44ffd1e9c5a0edf55a512c7b9e6d9ae878263046d10e4006c9b7f052cde72aec7a7cfce951bb246e94113a99730238ab39771ce0b10f1cd90c5e03ee8eb1873b7491a78893231e531c5097eb0d28657d36c4c0e306d9755ca910d914143af090145dc18b36adc58e665619195a2bf1e0080e17148871fa197edd54caebb7a890dc38508d256e846b4850a3af575e3637b4123f75ad1cd73cabb4c316e08bc54d3f44b6c0269b3da7f2c803a03ea495b8b152bee0f64261e42bec02884d691cb3ab71fcce489736e0a3a6a5fea1d81bed35a07b01a3713320abbd6da22fc14e05d8085e08f67c0b200db8ca1a879f06b2af3771c1f3182e745d687ef01538c00ff67cc95f097a6f6def45120cdf1d8e0c2623b54220a3037974236ce1a2801862ea3560e4efd8b9e7ad6b80208d7690721a7577fb0e7c8c15d17e576d3c483662b884039d2b33f69e69be2c09da1b63ef4a514bb61ecbaa3b855fdd40ad9bdd4782c048b84163ba6487df6213225fd281443dfc90b5814966a1e0ef37a859a36f57bac006396b698d39283f1acd46bc1c0e2076fd7e17d49acee585bf66e6a59485bb13935d52b66590c8d90aa91014ea0b3b10bdb74996833b8d3c6daea5e8850f96c088b1794aea42256669457b9de71e7ba93eb48e56fcf14068cd71d2e99f9134826f0e704bb72ab9f7f7925cb6f902cad25e1c7dcb01b0329f0b5ca3d3d37cdb37654e39256a0d4bee0691e60762e00f638a86c2c71f0df949b0aa085eefd5f63c6b43a412c972a0bc81aa6ce2153a1047f6e7820dca1ac2215048c79f55d990eb6111a970c800a6d3ee2e5abf3ad38f79dede029154047ecdb3a9a6248b04b54919785dd0f817154e682e7ac2569eeac23258aec681946b90aa5abd92d25bdf0bce9f4371e1d03e53aec2b7dc8f9507e42a6ee7939e9bacb654b972ddf3831d7d9bd7d10dae1a098721701e90c66fc1368015683658706f241663390499bfa39d00e481a1ed9787601b464049f1c184000fa9ca38d26c47f92ec9110b1fa22ee648156782ee236cc961d239f2c85277310c91734a2315356fe8600a95b68e44ffc926b3f5d2fb75938077bbdce4dd15bc8afa00a7331f61f50fd7b3290290b826d97a02ea8fa06e8008cd8c9e6c7d354b0b0895809be6f9f5bd622687c633001eb5e25eaf6c7c56d9b5147522fa99a92fd04d636b334fa24f799108a04fc95ecc9c82919799741fd7811427484d2aeb295a4aa9aa13caeb632a379153e01c065368abe87db73e007a4988862402cf5866261130505244a00374f1e445ba7edea980c686c2acc2127f03393da3893e2005de8bfce2a196421ee43b88a2c43b515e420b97de14718277724229921003669eb297f92dd619f94b741eb057fb4afc325fccfcbb13631fa30ad10778695dedc548bec6e4ee441235d1b393037ac70925355ad5d8deb24aa79d938b10e4f058f336ff55806a72d2b1f0324b01003953382d053deeb3429ed24077721cd0602f782e108ed89d0aa23d28e606c3a0cae7bf2a71f0b40afb0183fe57a0446e968d47c822dc051ba24c046ae5fb5fe1e151f61700f502fa15f948a55d7e860e0e907046d70db062cbed9a12114d6d7007150cff9ac0f624c740bcd7d94789df5281ba9a5e215e83d08a790bb7e5bfba9109c387ebe0b1d1ed9e3f018d533064b0dae350dcb6c63fe13d770cf43a5d87bfdb1d3742d2236a7122f3708edd578b338885b00e7fdca039b046782bd5d790aed9d3a6d70476a3a91eaacdf7488e630081728b257ad89f5643d0e505daf59750e8d520524c9625851f3ddeb65205914754db9239427a4298de2092a432322090b2fc0d140c2b8e6e3fb5655450e9cdef6b140d6eacac1d16160d32897489f2c1bb1f24fb8082c88105a523e0b0532279aff4b1cd16b3e12c877a7e612a55019ebda6d0936794da5c1fa044c5e4bd908d64c2153f36a16ecd99debd4c419c5b979db19fe751fd17a2f3c25496c5e722da074144a7f7ae782a3d2811c83835ac5f1f3f88cba80f84389a93e26f40796e2cd7e597f8c78fba710c5c57110b103e074fd430a075e3268482e84c04f3d608cfe5ef70b73a5855eb085a89f8466969ac21a67a24f933d9ca83a7eeb60ec52b95e33ef875efac605cbd21fdcd95c43068acdb12846aad52e3fd641d89e0cd65cdb5858be74860c9c13a1c99ec1223ee2ec685f2b52f43388936508897422c08653f9dbe41d4e8a03068902a132cf0ba7bc33b4813e10d9c38e54e3f08d79386bf66704363c8604b23c82a9367630602916fc9bd448a76d2a9af1769ebf50d0deae613a3c2ed98221da945d2e9864b43efa54b5751780d678896bd04893ecc59112686791dcc8f444e58333e84f1821905880b3dc3cda28209846b90e959c09932017595711848c8751ac16a607c4e679b30c10d1559cfa4242d0ba7085c21a1b49e8056fc2a815cccdd39f20a8ad8d97a091fa0c39f35243bf2be3e46ee0326e208677048af5c39b68bb344533208bbd0768c3060cb9568825cbb11f1b510525eb80c1d2d5ed997dbfa2d236efe51b1de7a40f5396f8f1e65b7024f161efbbad25ef3a39e613c863ec321db0c634954851c135626d033ff997fe5a50b1d3be8de36669d6232865f3bfbe32e3d49eb8bd0643cab4d543787c55a63a84851550e8fc130ff41f77b6866c2e8a13e8d0701829c2e143845659c8ade5c1328b75058c6420d4c15c6e6d9d2e84441a88d04d6ca48c77d332feabb87dac70be96340887a904caef261dc10af17a20bfa21f540a4b3b23a26c93b9711ccf02f2760886d4d0483235161b563ee0c505dbd49ab55bf3340016f4df921153f39bb9bdfe8ebf5a300148fa008e8a4b4fcaf85b2786e736d1cc6a8c7330fa6a6c7bf30fe4546791d46cd53a16cd93abcc74bd99c4dd9c62d1ff9306f693e932fecf7dd1f883c2ae876535a2b359f7945c8afd8cadb09d5d1718539479b89920e0fd2831bbb0ea8053fdc44887cbcdcbf75aec1b6bef5594fb8a28f8e8a745812ac56feb13572fee5511fc8708d3ae431e19aea9ae30902abc60355bfb143f906eadfdacd4adea2faf69e45929ba538274b74d8de9ea240a499db28a309a575a9ad7c0f300c661d096a1ecc13af40bc6bc946881368c161b0cf981a007a30ba42a7c284c8ebe6f0dac298315a0f7fdf32c19651c2f51081e841e79b8b73a0f5a9e70aa235302a1fe15f9bf244b0534cecdc8f32849e2ec49d4e736118860b849de499004e6f3763ad6e1320047cc356770cc0dbee805442bc8fa842391521221db5453a63f681a04dae1787060a88b2a2ddb83d60c9cc121541e483df0ba8fe7ea4d7e32ab7da20313a77c4537a64f3d055cb1df6c22d602eb7b95c61e5c1a3f238873e63206715be3b336e29a05aff00aa16cab88087fc754a44c68ffaedb9e55ba605ad0eb0d7d217eee1b164e68cc7745415430463389bf8ded6818b0825c89c206295d281025c7fd689fc066c5ae927c3093a3f659bd00fafbf9acbec3e4cc2fc9af6896e74052d354f924b3c395ecc8aea596c569c54ef37b500e4cad4448042ae521427f9021a8724e719adc1f100e917ae0af25c6f5b2bbbd762523b47acefd00afbf6b59d4af65baed563e3040d48fd804b5d20c27f0fa2b482de4972b4511d9f6565720a8890e2ff2d3b162b253c0203d84fd2896eacc4a8228ac68df89e472b517410cf3320aa3c2eb82a43fc1c0658a2fd5970730d47dce2d8f1f703041e52e88f4b4863b719932bc9de5385920c60e519cfde5c0ae2a83f9799cbac4aaf0e3ed277519605647187aab9ea0562a93a6b52c4e5b1c70d9d546a3880d05fdf18125c660e81ac524afe3a7b900360cc0d88a5a0278704f2bf67f0242843819e089b903a72f74f4816b357525ec4352c7d876620141d3c51df926b7234eecd6cc1d4d94e9aa82382d1c2bff801d216481e375f803ecb44129b17711feae76491227f02f14495d70e91f42051c79a804c83e14ed3c8a3cdcd055db24e304d8525301c6c310b6a0d063775653e9ff6db306b0f22ac50f72ed81b32e4db0aaf933a6bb6d06b92f76c59d249d783086b3d5346680d9f240d44f6b6f5b57be63b7b118ec62c3ecc6cc2ce311c41493753928b115505fbc51ad958f2fa5406301f0103c834b821ae0b7e439ffe2ae2285c3eda8e25adea25c337a3ce86428189df40f08d1fb0f3a4edd15cbdf51aca859030d368f836e123d496261667c31587981c93f6230c8148e3088b13232d8d9311c41b2c0451c6a905e1ac3e2bd3bac0c1e3da31962a0ea82356a8070c450830d2c847f7a0c3572ce34dde872cdf0f3163f35e4193818b5b174de618ec26bb621c9b2f2b95bf873cee97840ad30e7cc23207d59a866c8aabfed617ea753cc448ab9b598c2a592671bfe16859c3170b8c45c9e78a7796cb0e0f600404b8d160befa94a2e27aa082559a5e46a53a9407da5870070db0a37557e9e9a7c17dfc21789b6e00f1ded2c0198012add2ca69dab5ce91cd1beb4eb6c2221c650578a2dc205ef6f78133bbfb88f6d8a811dbba1e329dc06696a8437375ed8ee242b402e5e3f30167463f80e54a5dc1be3641af95b055975bdc843c8137a75ac42098caf236e0d72433d9009b6794c48cddd7c7b8685a444043acb2a6c2e3e76510ee9f92235de43e7523e80a2ecd2819d77d0d75cf5a9b2c0a484a9c361b72c5bd6730d53f0b3b1462f75b90f59009855bb52d13d75923330c6b6290c891b5f7a758c2afa6dd93a74b28a0b99c4e24a990e4e47ae6a532cb173af7312b063a915248ad09ea9bbf84f33a16e929323c11b91bec202e36d386f82d2b87d6da1dd42ba9ccfc775004d7f12efcb2ec9894be3bd51ea3a693883e94ec844e8b9e1b98540f37d489e49ae22589f33eb856f7776e700f6fe85377ffa7cafe15932a6758d9827b10b98912c397c9b89ca79d192dfeac8b2da954aa51084b37700f9c7a782df7abf2d82953b3c059e1194df19c9193f7f6d25652e8cf2cf70079129e00a73acd2d5ff41eb2badeccf31e5ce794e1a3c0cff568311077f153451f4832345b24e2b527789337619fd40f0c6a750e2bd5b9c715d73d6666b37fe06309560fdb37279a1346903ea1cfd6f804146c10870a5c386a7af93490e9acd5cf17d322004c240fd5e4c65256a833275289946f1d28144a3cfb183e69760cadc8c45cb100449a1ddd92633af45e4c9321f38bfa41931c25657681860e0b463e864bba7b675b9ffb852cfda7c4d627f7f9d0de29b805c7ca891c64c8fd21c568a78c48179ea0d6fdfe139e250674ad49ece5709993857a78c86db2ef615e6aab5423730e0d1135d8809c3cde7b84a3e648fe68f2913d8860182363a38cedcc382a572159a64d3d8af4271a9907ff2bd0ded025f9a1f3dc90d826b1493a519037eca4a5c838079fe1fc3dee6e66b72649a763ddb0d8a676d7c13995b80ba97e26eaddb07968b9520038eca2e0b07e596083ab2de21657f2c1fc6374c709dabdf67eac2377424076871ebd46f058dfbbd0fb317ba46cf50ff1170b4e7e14a545549db8029b99a29d4a3e51e045bb5f7179d739c37628e664713e5bc8ff7eac18880185efc40c600ccc15462e2e5a22d405e9c2fd7e93c847671f9eb71f1340942267ac2dba3bffec83c58fc19ffdb9f4d7e1f0133c1aa39ad26dd27ee081f758145e4209e6a3bcea2c1844e28598cef15fa6f37e16960f601d1fd3256c013116bfa061e7b43447c99aa0442d96416b7755d249a4dc71540f1c3b85c2982b6445c567e579175dc0fb57bfc8ff3f8d20103418d840184f37e978276f12a24816a007c02a7e319b59717d7899ff2dc9a2e5401a89828da32222cec7a57aea1bf39c702ffba1feb14e40dd6d8a82fc1fa2c0785134aca93bbda13b4fb256929417002f460252e1b2f4bd0eb96245175f365d5095e5a3a362a00f8ff5bd89b24c299a63467a493192f24ef4ac3af87c79916c5154b0f572a2d3b6e0c2b77d6bbd456185e2205ce7f4a120ab1510cbceb614b00605e2d28e0d3fa09865dcd5e54eb411d3344c6db63470be653d3f156e3786d0b2692c84788b52a566d06b8400438e58c94e0685ba13650b4e020481e396cb6f58047ed9998650ec8f6fe8a97ba82c0d11d13ae20e7af01f6397acced2a1d9786d223a2b010e080b6307fbb2617824fba9ce83da9eccf9756cd6e0dd12f21e7c05f3479721947dc5ae4dcb07c68ed51e7061fc64c986db9b99773011aade0cc38695bbdf008509fe76b6009e298a9fc758639fc5311bd6538c5613018a0c84a9953d67158e64449b5c466269129adac176e964070dfb619807e0610087c2d486448078e648c9c9b91e6b29adc11699bf5fd626b618d76481de787f62497d7cae8fb2a016ec46039667cd194cb7cbf4355961e1b52e9401b0308c7f547eaa33d06364e53070d108a2664e4d664c63ff23ffa3cec049ce8f45864cf50d80e0610221e16570e55641806f2ce3218df6ea3ecb216830f367861aa73a6c58ffa986a4d59e05292310423a63ffbaba6b8a066e57b96da86c089794b661da777297b5ef531a15338e7c712eed920687ea7a9a9506d65f7940c0e4861369d67a418bec68b2fd14386cdba522152030af3335c3022ff4e49943bdb1dcf3161c929c610e62523377eef338cd0c20973842a91189c2e08780578224fef7637235d3469671d121439001dc7239a11055f4ed62d2d1bb44912c61c17d225e9ef26fc5a37d1f0b96ede60289a716709680780a5012b79fb5f83b26990e23487f84db12eab607fd0a832d0ac757ed0c61099b85d28a2af18a779f98fa87a20911ed753cd20ccc30c0d56307722f5d2ee0b3b9fd8b3cb5ab4852fc20498d5cbd6ac13b3df4b68b4e378ec5965a445c0c8d240a3a7d33461701511c98f6fd770371d40d0302ae70ded9e2ee7ac7a880c1adeb26be1ab8c8d380b355978fa9207eb0793d2306f1feba0f3857752142f69609aaa944eabba4ee10a47c24403e6cc482d71b78a027879ff5061eff7cd2628f0fbace12989cd8b156163a775153caf124f40d4249dffcace3bb2f501ce333c94d8964af0bf6cc9b23e2d4bdfc9a26f6986d639b3991ed2536060d3c96b25e4188cef8f7dae6c0459242f8afcb4068fc227b0f7265dacc7378f2fd9515b040cb2a86d7b7b7149d2a06ef2dd010a244290b8e877499d05656fdb45e4108be6ec9555b5d37221f70ccb9340266433eab91e3c791a32470715e508fa29eec7feb00145477a9a3d28d773daf3c5a14ce00e351af50ca4a135db0faff082fe4b05864c1c4665639236bf4c9204aa83855f8f65717c2020043655e84ed373e0903046acb3df7fabf5ed4f4164dd523b7da0f64e5bde8bba38ed94bed492f060fad25b65b9de8b874ad1fb1640d8db7c37a5bd0a91664525fd55d7470306e355aacba7477335f3b0597cc61dc8d30221860516fae9c81c2d2d18a590e493246e636ed21f51aa54b5ecf2feb8d8c52577172dfac5e3ad943e0042bb6f81f67e24e5c4ab5e6ee9932cb976c1f7bd081a13bdfd9a5c2136bdc16e448e483d42c0bea896d4e543375a6144863f0184d0ff7b6b735277ada1a1f22b66a33c793c6dc98abdfdfdd2429e9ae0eea616c9670f4de0d4d45ad52aedbdbb4f12b99c70f31d3d5a7b0158087aa5b9976541d3a32d3b6e311f37aea4417a97610aee8e0be9edaf46cdb0e716284123ed0eec435adbf911a6c3323d5cb0ce05fd679a435d7444ce24b0657817c17548bc540f6a425a8a98753df559738b204ae10177cefaead21ddcf78b666885cae10b54808e59f61eff806680b327a9663dc1208b67d5440c05eb95c513af42e117a1b72f60231f4be5d2e648017b407872cdac22ee49a02b7cc42b6619085f8c23e80a33b92976c6c39321c621a9e7e6c1a0c190d8712200672bdf9bfd05d5c87784e9fb0d7388736d7b69ba6c357dab6865b0882bbe1fbd035d99196640f5bb9a9bab08a240aae6114c678eecbda0ab51845d0e7c3eea5998bd090e74f4e3435e750b7a4bdcc03969bc8dfe633c7da268c895706fd0d272cec0af072b4fe16040ad7b96d72c597240813c111aed4cd5e7c746044bde83738c374c8c3334b6bd6d56369ae4b892276a25645c24cad62f2102ec92100f1c3a8ab28a8a4df05937c308a4ee198c0259fa13f4ba70ecfd4486c984bbed89c7ca688d7e41258b0bd6b8cb7ed62b302a705d9e0777f138717a18484f1a04d8de201e245785400a2821a66e9c09e40970b7c3d71b5395dc1c79a73cce75bd1b902ae220b2e3c13f9464d605c1f676412ec4de8e19f12cb63856504a1eee0f05e135a719e84858ce522aecf98121c89d502abbbd69ea749f2f1f17bf51bcb8d61909448198455c8a4de8f7e25d5d48311a4a073c587097c6fea734d53d8ee2a2f51fd8ca2c21bbc2603a33eebc0e144fa1409aae58b25d0ab751a48b909924b24d4b9ea5b0430999065625de1745e98b228fe40829a72ac21182f67a8c3455c856af2e6e98bc8c89790d0ad0694cc14a70278fc3b6e8cbe05743625a3dd6136dcdb78a765a34ed7d9c3130df6f8af1ebfdf53cef22e050287cc902aa066c033abf3a0aad92480f90da344f312ae7597240d71caa8e7ca758ef25213a31692413928cd7956a7b2d6480e4f6db33d8d6e0181f4b93f9b7b62797bc957f8cca6231ef8408134c1b6056421a032cf108c8995fad5289b2512a7326ae2cf0b6cdaeaceb2322a4b50dbfc50270800d224fb89c3f4d1b68065a20c5d725c3683aa1b3d9f895011c0ad249948ad74153f036deec843111f6e8882cfdb95da6a1f6ee8549d81b3dd75013b283283946040d9514d705fc83cdc22c488a9f9295eb2b5de5cc38958e7fcc267c5f40916949356a804858107f3a951c4cd2471734c78171e92e5229200fe14081291dc5539c010413fe4e59b7d33062a5e0a6b6121aad3d9fd29f4a04a4fdee94baae9a4145eb05291406f109a87e558c07a995e8a0b7766f88e615e597c9f0a25f72846ed28026491c751931675f359ed1ac338583dcdde04a7134609545cb4dacd1ba24d66b0f146018ec989a3459e0b516e3a35970c2831cdd4419040a77b9046a3be3f711fb5d6bea1f912f30112030483b323b1a010e1d06f723b9a2784575bfc0515fa2c1b35a0c768fe8564ed523180705b3b3c84484f3291a0b10b4edcbf632ee09cf873574ec39a8b0eaf6c7bc80e8fc8963693b62ef3856003414b532accee84f739d0324b058cdb4f6e9820139147b2165882d90feebe3d8dcf5f09d68d2bcc14f4b45f30e32100276438b8fc2d0e67f4870742092ef6028d35a7a35704be93af56c96434ca49f276ef87f211762ec00e62216136c4a98f922c898dcdf8798fb3a205338492dbce32f4801521a30867f4fdab33b2f448adbf02b31e31bd44cfcb68e677385477ad8f57a0cfa4a3b22489df3f12a6d90bd14baf8cca415015cbf8e9522a99132f5d243f1dbc0748acf6f1e95b3f649cc6bf16217813f42e1ecef0f193ab2b00868ad4ab4286902bd9812a686124c838cc63f70e7474f814c3024ca80d90bce29187d8f39fee56bb153e083541593f601261aafe81a404a17e95fc5eb9119c3de1d013fd6baf85cd0e2235651e9e1ec4c8017fe482287132343d78bd334f18294e26043b772d70a205b6ecee377b4dfe6f0c18466f1458df11f270697ffc490f88442a42241a8ea760624e858b28df513d5d9349f75efe227f87c2e8b9c6a5a61dd8e88c0cf123be50893bc87060ffbdd7a06ae711c94484deabb0ddea99e24c233b7e86ba832f872ae4564d26bce524364e16b9ff060a8818bbe799f6dfe025c1aa3eb4e255f06b233ed39038105e47e163d2c3c270a448942496e2fee29363eabb1e1cc8ef16c0b7b226472e6c8101a66e922296a90c235d4a8f83b5f02c91abbd2d19f9ffc10a0aab19b47c39e5d94a5b20422bb84272caaf000161b837650bc99d1f45ef9f235218911105807dc5d679cdd0b2fd24c5e320778bf9d087ffe5da6c2607ad16a5445030405edb5be0304c2fa89e4982f04712b506aa2ae8f1cc4b5a653891b176fa4792b8c85e81b4764606078577085ed5b18f9e97a48808e915214232321ad53dddf1f2ef9801920e394581977be4de63ad5d9b401078255b012dd84f1047aa299a07155d8934f633f7578ff79988fd550ff9d9a50605df42da5fe9456dcf1e2a3bbd2105157093a6fe3e9859410db65ff81112f517f68ae0f93f451cc02bc932d6d80bf343d29a098c507aa16c0002496c966615dc4f5558d764c1c04aed62726db50269240d5e1d023ccbcfaa1905d10d48e32507104dee0b3bcc37ca155669fb1dd18c351be270bbc5aa0583affd6509e0c7f472f371315786aa887ed8240995c404d500f60934af82fa65cf441fc85fb02c8ab486370d71a2c1550f9f4a772923532d4381e181e29da02c5a0f35f804de6718ebe717c3e5b38189c60e22eb531ce01e010b0276832de96d40c38985754cd6195e10a2a20bf4239ade85616cf49c0ce280f907a748b028e933549615d5b02c690372c8baa97f461b8b06e7f7ebfd5eb1b780df5ac3ec26b6038e452907d696caf621512596f402c9621812caf3307d1c48b95696248b44b39024f42d504d3022456ea120bc5d95441a9f951af873093248cfb46119cac967b45b11ced2d98acbd9cad87f93080b50f55a0f7bef4b9f59ce935b5521b902276494fcf4afe532a67902124849b51f9e552bceb4cd52089d43b50cc9305180c427c6ac7b0435e765b8d65401a46cb0ae98cb335bd6145ec2aecfc7148e132aa88b6e42b14acacc4ec8cb65431f951a930614b884fba2d0c3a88b2cf6902830242dc7c466ac367629965014fe3f10897b0628630b0133f84d5edcc03f1fb4415a7d9ebd0607a674d18a3b0118d0874d4e0e15c54274363cab0a13604291bf3cb4d1ffbe08f2ab0cf706f7ee8af5b66b4cf19801dc66a6f471ac72ec59747ee6daacd1e61d4014d4fbeda2aa00941daeb1d4892450b18cc76f302fec0d4dac79a82372d8e82fb551e7c9c908dae2726ccd851c530b81ac1bdd5fb8239428e56e40734fadf033f1f48f49545d6c6e448075f58f0381dc01158ac2279db4bda7b748662285836561833137318ceb319af41e3a9b49fff59549971c1512684c3a6409e5c4d525860d0b4a3b46e16616a12df47c94d64c8ec8c29925b49da50c79e022d7c87f6695c1cf507d9e35e7f12ca84c7c8292da8f10e5ac4d8825066a3ed09f3e99e28f5282f0d86f060c78fd3c1870f0f00e23b60d4c2510a94bb528dec8263cdca1cf38e4e410a31af1c207f682ebe8a635777e379f2971aab71a9a0a09c1636ca3c9595e93a2273893f7154567ef974260b0184a7ceb5c947a8f677487aaddad5fb034fc1d1b12462c907f1ee2399723598186ea688169a6059b0f298b1ee79a1237022e19f315492266828f4ccdabc351133ea89ed23cc627c50bcb294f01e9f81f2c544476f32ca9804811cbe107125b841993d6743a003c218794abd85a1b8da7218303ba62fb3d6e97d89914db6bf05d2e2b3a98c0f19edc09fc0251eb484ac99ce1ed7e140320f586a1dd4e0fb1fe02e66a5866f2e5848da7281e1eb8a7c34c649356240fad58c0d0c882f3ef15bb72123b1deb3b5a0f3bd417ff672b5bfaca0effccfb152bf6ba861ddeb0092a820063ccfcba60a7c874f552e0ac260ecc11aaf2d26159117c19cb02b1de14fe31a67b1eb422cd81b2d4b4e01303196750730d835bac6e2e95188d3bc5e4d07f6e47a08981dc144f4b8101eec8a91892e2bbebcba9b6498d24065e12e4c0556ff3f4102dab231bdc097b2540b626dce1068094568ba1647576584f1528716fab1e73015c5cc289ca09d95ef819bbaae3d6eeec73ca3c0c04f6477e515d7e36dee90c1af688f9d4ed80fbf076e988748f7d257f487991eac5bea6a906a6d556b6aaf8283b8f4f2e72a7994e7cd8f8bfaec649916b34d8e3c04cbaf49d719e85fa294b9350db941e9baff3474a26ae1e33eeb8b6855730a1c8c46d438dc57b618aa9279266488e0f0a7d757c7e5c52e8e1890119825ea33842aaef2ceb78538cc26f918a89243f4aba14974016932c21ab39a73af668d1fc79d31415828550e896ef3b52e69be04ee46ab75fe052509eab769b4bed361c070cba0f6fb0087f3ed74049ab8894dd4aa7f883fc5bdc564d48b8563efc2f460ad112987daf98f4391779f68e85c63e1c63475ed4a9775e9beb6d2b6cc281bad2b13b961ab3fc7f58bc890d0c4cebbc0e44776eaa4f1fc0b64f35a71260ca892bb35430c8c476572913d7261edb64435c599ea3447a7f5b42de6b5070f611562dbb23b1a2ef8dcb75c68f768581dd334251f4b6803dc5fb6c4c28632586d47cf58cdc87377c4488838094085ba2392b74229bc1f25c4e46441eda020b4ba290bbe2320d40a880470f2e0ba29203f0f3bbeec855555e4b990482e03306bf1e213c3d6a9d911313d45f9d44502178f9691e27c081b4ce3841f5f56d6ad01897ec28488baca7b4a320f8aa4402b9d9a2f3dcf65529b39da9893b0a54520258145a0a4f9088b56d722bf057a64bcbda610f0a569b3f6ea2c0bad29372422915fb6b2bd258989f20604a2bc09aa44522a59cca1b05cf517868da2880f723e21c4dd85b73449ccf61200bb8d9bc4b1afc0c233179af5076349183403ac2ca1a8a3b1fe926faa93bca4b67f037eaad9e819e362b5966b7a51a0998a1318962e92b4d5404946460c42cf5c88a05f3898569d14a94a13c9157ded21876ce5a09fc028883c97d8e738a0a5aca51a9b79d7cab978062121667f0d820ebef562e12b4f494224f77b13c3706b69c7fae241c05ba99c473f152bc202b2522998b9ea1b48eafb5e8c57eb4211a428e1f9e3cbc8f0d0cc876ac08016cd2838e3601e4237b43aef964543b9066a103310db7534a4dc0049b644810769be2d9044bc3cc40dd303eaed46626bf786181454a79a81b54e561992fa264626996b1e4b04247219abb540cc76e1ac90810aff4f8b8272ca1b5877c594396855a6f0fdc6366d223f32e73627707c1d8e3e165a26d3d01cf0d084056c7b4ea7eac822e8d47826842463811ebe3ec3dcabff9bc79c5c2ef61e06176d8808843126928af2360dc4a1db153d0c693922ada0bf2cacf225ae12094fa3fb435e5ee6b7a974e08e1b7bae08bd0ecb1ddedbf6483912721285f8df93746affda5eff5cd4f0ef334887350de08158fca1a2ab036cac7212170e8348033086394a25a3db6e7a44f5946d9bf2dee258c5375d742c59ef37904300636580d0599934d9b8c08b81640e4acc12270c4d001f18a70d0901dce1110c9347b3b81099cc742a09a106c859ab47edd281b937bc7b6e84e6b45bca7d511f365149a583c256f12719be12c6c6620ae77977d260081b48e3cdf8cadf1ca58ce88f48468f1256031a806ce003322a77e76d1dcb29c03572c3c71db33bbfbe5fc583f41c64db13e0d6e4d9d54c48a60cf1c36a12dce38c91f8a32701b926c6dfc944ddb262a7a03b7ff4914577dad6cf64b30d9786068ea510a38f66efbf55e11cb3056f41dd7dd8e8f4d96c61332ebce71cef167a6d7d432e53a7c248f89055bbf2a54f1e710d9aaad8a08c941240726ffd365b3d0034e4a09b0b5e52ef4a35c2206e603a0f4ec2c59a0305aaff84a58d89fb485da8d48498ea960cb9e54b6aa35d921ca5c3077babb0e2ec4a3858aaaff76ee08daa408ba4bf3c463cf6650c1078ab7953c83323258bdacd4e14ab408d7dfa9cba997988508748fa544bf55605e89abe672f0138ba29ed8453bec120163df7b80f265d3ebd0a195ca8f0f3dc0095c2d5124a4e68bf53bdd60db04d1938cc0af00b2cb0848f3caaceea3afa94afd591f7f11a3646ac212ab339e0aad29df3809cf53c3623b49114a6f6235120a1bf2bf7f7a0559204df388a2b7c2405389191b0b202f80b48020b3a5360d1dcdaf8023877ac87e87beedf4799ff293d1952196406dfa786980c6d43ef00bcccf0ae85e633db1899f3c1bf136c32f50c7deaec1d2eee1213a28b3d716e893a7d08c20a863a1407b7bb452fcedea64801a513d7637710205f27f267aae27620c0f2a471b1ae2f8c145250c855e829d231a3db441c4212772d8136600b550c200c258882da9ee7f7ed5f1619600a9bd65dd51d042b02e796390e942d3b18dc2851c0468a403deeda06b0f1485b9d55856072ba1aa7ca8f3ef901160a9bb7fa0c8d08c7d6c663625392ddc8b2bf11f4f9e130e70e0e1d51fdb6da9f4d11e761d45f824bb0e807ce6224a1ac3a16a68801dfebae6d1cbf3208d2a83c1f677e4bbae0b719b3f5043ed4bbdb45af86717d5739b018aae00ee631b579cf89ac2143ef64f471b482669036bbd135b5d3a8ad6ec74407dd3656e03f93ea1a7e88f23bc0448150d9040208dd54704a79fd0353fe21090e3699bdac3afcef823b900ae3d9705696c001b31069cd2860057882798259c18d0e7ae54c81f844bc358aaf6d9aae77708659254d1edf3423391413048438e8b2d21a182d2006fc17c6a9a06e8742e9c9b5b5a0f4cd7607d80d9d46edeafd2bbcecf9337510806571ea1600bc0a3b1db2a8a3f1a67688ab9aeb4befde1eae12057992d228051a470e37b42352f35d756108d5d41704daed98a3d98ccb56eb1955153aeb28df462853ce36da7ac2d75c13ad5f67d00b41419d119a079cfd0c9df968cfe15d81a8bcc0912a5e30e97e6ab8bacdfc45375cc547588237885f4c129459db0839b6804e531d1bacb7610879d5dcd96057d857f47972c664fb6de2a0382b47fa93d2c7ed410493c84d1dab25d6bc0aaafb7cb795fd12caf91f828dac68418350091ca7187c7202223ca03ff70a843e77c22932c5299a8d7921f326682c3edfc10b367c5bca4044a282c705bab4598e3917753b2374787125a7c5fd28223ef617ae4435813da50b3db1072b0f937862202b1b7437fc236a766dd14cb503a409bed1b2d489eae1f29949fe784a356af9d4b638f9057a703ffc94bc9a15906a1c08af8a6095459e44623b24509c1d2880ad3eac8f1b5397003adc56d0c41c176f82dd185fb80969e8b977fa686c6331099f043ce9b13ae6a725adedc4a22ee8e67a18514341d9c5619b2c985ba73cbf97bc9059c56024e13e8db0020ac2caa014e152c3bd7aa01146399a4eec568c23807241be6822db2dabe9b90138244cd187223e464277624fe354ee487b8ecb6818a3ed75af04a7b3a970803dbf7903c911324c9e97b394f896e4ff48ee75d48a3c982d485c3b233a431cddd9f1cf8815632c9b6c675d10018a4dc19d5efd805de23408390c20b8948d7986e18f84cb7003eb98920eaecd1e4be6ced486717fb9d6a1465cfc786b985030d5247905449f25c2b1925e1267bf6f75d03b777ae6f5c446d37d12229996a86ecafece98692401d080aa10a2a14b0d150eb8f05e0142612c7ba92fb51487b608ffb9fb34d66340a8f3254e38155a279b7db1903182c8d68fbbb682de90d1a04dca16f10b830800e82d10f7112fd2bd3bd0a182c019b34e1f72fcae4e5703528be92f1275032e4fe56c58ff56cec3fbaf31ae1c707a888482b42b1c9f89f8c8137409c80277e7ba896d76c21991657eca19d4336a2998915a0b8303ae51c5eaa5cf7c3083b80aa70d0663e79765216ae5f985cc56046dfbe3811c7190cb816f7e31460cf249db5536cd946c45980ff045974a71a0967f70f842a3fc76134f86a12107ba3c186d94d808a8261ec434ede20ca560d8811341c148f0dc7cbee6b7a7db7f7c1c341b1ac3829eca9ad4b969414cacc09a822f568bf79e11c6c32a4216a54ae21e0c8c46a78d13747ffc933271a7cc17e5ca963d533a5dd672be8190d2db39ba8465e142c265756bcb52896e53fafee52e12f043ce19b109754e3138808aedac1e3805d491b1c46c025a14f0e7a2cbcdce4824c377d80164b7c69c4c9c820b026e1d1e553f43e9ff134ae114c79a9c3f83e59c037c31724dcc64584326a8469be890253223a9b52e43c6de4780902b8f4bdea829e6605fc460ee7de840e86afe8e38cd3ec6c228b0f55f9e25ab7d5f26bb36e7985986d4e3e16c09a8af955a94971432b41bdbe96c92281e46ad991012aa7d0fa5494b971f0dd1137ae83bec44c39b361290ac54c3d479210cb33a312c54c797ee64daecadc97a9bf6f3c74b09c0366d01a738f4ae8089e7e6338c28a1df3fd5f6e8c13263027ccc6c6a339f110443820560c3463ef1ac3eb80c881a3ae4bbe0c16eba3e57d94dbd2fea6f94f9a09214323103e55d70234825539dbce7d67f4e90a026f982b82ab3f5c72d3e8a62453a5bbebbcce79288cb086b3ceedcf0a0cd412d189ca4dca3c604ff014a6d362dc64637727a6fdf3a4708c8dcb8293b30005e103ce7680625ef1c8a2d19f9318f5294b16e667401735ff3bd21c6df7abc6ec93756bb977ce45453fcb526ea0b5e6bc0c3a8e0c43b5125bf2475caf82a1c4e92b39e5977a74c38c5e1ff37c66219ca9084b2a6ec835150bb0106b8d6e03ae0b840ea9b6c895fab9a31562abff90154f1a46edfb106855950a0f2a5552e3173a3efb5772f95ff13921ddda3b744a4e6746945d399134ff6f8b0fd7bab8f6d32cf8766decd9dd7a6a6d653e08a385a96f089eb200eeacda4c2e28ca76d12438332f406cc93361f9e504c0f8683d67e28c05791322479c8f53b4b19129d6cc3cdcd4968304af4fa0bdb92c8c18d93ab605b43886cc32187383c9404e4bfd8133971ca46d32fc5e251071b6b4e06e4aeb7a650bb2682b2b9384127848ce5911a14cdf71742c3b1c4968e6b31983a85d6fcee7e119ddb894ce673d45781da98db924a09141696222f57859c2f300f7a0f316771cd84a5420c786cadef25ee6df3371b6762d0a99e7cadcdf39eb23e8727928fed976b2294c9f3107e76bdaa785daffc97736d5d6ad83a7104609c4efbde479f2db3e53c238aa42fbfbbef0fde7db904691aea2289989a982c53b6bdd78a15b0159480abb207ce0c70bb55ca428d62321e4b78d5a7b82a85ae6f26c46ba13d160187b09ed8ae0821a6ea29eb021a226b93a0b264f2bcfa9f608fc2827ba0a43993c0bbd754e8f856b85ee14079d151909b2e900b49d25198d2af95bfc825f03ee1052ecdf381d39ea917b8c1d519bc3ba5b3c1fafb7a69d2b5663e2ebf0c4a9497fca7595ae97303ae051987d152c47a98c8975eb1eb7dff4cdce52bba8ec5eb68aecfeb946369df14cc807405d2e369bbc9a872ddb612b5baeefb8e34ce99af87fa51c7d2c33de8d6e9997375e88743c133eded419326237549794b547c4a5a22d776765adc4f49501d06d60a779f6507a3ee358d2650ad3b22b9f08ee149303038c6caa6225c322312c00ced250f8bf908335cb099c3f4d45fbd007807583b3b06352c54d86dd060530841014e572d80bc3f2fac4d867aaf892bb30b460ab0263d85e5663645dd6b1b47dac151cfffc4efbb08fa5150bc1bc80159fd0af9db5b6d98fdafd859c24d9809640d02b393e8e892d2025f2d6418c7d1630bfe3380dab7d016739607882b903c21717bed143f6f9aeb8d55d63c1b8a790dccd83b7e79cca96840facf2ab5655e35387b8a89180d90ed6625bd6bcdea75bdc381d36864dbccf7c62422d76e24a96dd43640597500da9922de3a4699a4ca25c12c0a9b9c4cd0fd47bb582876744dbba633528536ed68affa96d5647f744c5cdc592e893a784e83cded0422c7a3ff4d58473f4dc4a2283129958383a28c8d115d70e99380842f0e3ea1ad8f7688e99e0682349370c5535f030e33a3a43acd8d97419e5480d244c032c450d9d35c5f479e42de53c32802965fb21530a1b1066936a4a8d246cf1e430bc292029e0dce5af22c822c9f4a0241c60760645180eede7c9044010fa50f792466658fab98d4aafcb41a7e640276acd01c01e09962a6d3c61b27edbd84bc1a15e99630e987031a10c29d29da2468f2dd4bf255c088bcd055d31d98248fea314807b5e2629e1b39c874b0b3f3f4e2b69292b3da6fc2d7b090e4ff9fa7170ac6406c57f14e408826a0f0668d0edc87c95d2490833d839d7ab4353c63d13e05d30c4535df5c057d1286be5768eef903a2a77626d5f1d2ec61d5df32393b395aa437c887a7f68baef2289b5ea2165c9fe8aa768a8af2a380c30795613e0d4c7ca6f3cd5c5304405fa9131cf56e7033b5570356f5da0b964d15e5168870ece30c2e744c92227099c99e190ba0953952fd6f133ec00a5732e3ee06f2027699ecdf265594495c0e37b7a49878cd6a137be32e93502c4e36fbde42fc10fd6164464a8ba7317eae118e5c8994ab4c30d350341bc16c67d42ab2a5efc5a00da5a0f2e2f370132289efc906586648a2ec86568423c67f5d3d20ccc5268c8fe2fdef594bb3f283e3586c36e48eb0ca1751eae000d6a9bdad099f0bbae0349c3f0c6e7b6f5374ac2f5857374c0a531c98c85bb6275c4d7830dacaba15027112187624882fea46837f257d93038b266a0f4cb920e9e04aeb43ed65535a994aea39c6ff6b0d632436af283ba21c7b02d1f117ce6ae48d73645a1a19662bd69e57da869a2207c42f14c129bc39427e0e2ac7744d9040fbba4f9194e734d6f1cba556622bfd3c5207ab2dbe11d94cc15ebe8689e8fba9aa5a86a8e113ced3204ede87d737cf3c2b37cff0380db96ebc5b513df158fcabeab3007ccf395e17a21949a10ac1177b3b51c09ee3a926ccf772d385c47556b088b46428e30551199817505bfb31fe1916a672b9bf63dd83c1e67f31a768dc238eeda74d60337a91c6623bd93525d7e3c483f1bca991bde297cf475c22e22c828aa25e70f85027213c9fe112eb71199b8c8d72298caca5308b063e62c62f63b5c09acee5a7a38278566bda35ebf304264eea8c0100841170728aaffbb9898976a1d5b4acbb4c3bd1b752dbf274d7d0f90523fe559f1d10fadfc890794142412631bdd046a52db9eeea3ff624e7c1c0138b81996b2695fb8caacb8f88aba245619060eaea06f6bb65434e765a036ccf046e6c76cf206f135a8a94b1324584b116d04ff049dd68e50a34f80c788b59dc6b1a8da80c3148919c1d04f577a8f9d5a337edd5dc6632bf159e1556c838c1b686ecca0c99a698d5b04077cef7880809e3ba740e5e4e609dbb64211ce70c03a85369d552e3cf4c05d3dac3eb409774188f67457d71d56cbc41a5e8288a5279034d9420a2a63ec6eb9836d979e7cb0f290bae74817a9310cfe5cd62084228b85653678408a697884ca97c713beaa78a96b7a3e7805f4160646fa95e092e048f7a1ad2d6c4f34763cd2cbf647330e3979cfe70498cf5aab2f700d7dfb8267c65cc6f9478a7781a436dfa3bb0602eec3b9a40d520c71354733e0e1092b3b5c74f57db3f2e2fbc73bd9700e08d3b2ce2914435fc3ba50a157eb22b8c2a43a0ddcbe2217265ac4b5889194c51fc4ab6e6b1da5eee1a644e49a85b0e0bb6a805373aedf6e56230e6bc4cf381396a2c01e75462be4c9a4a4a9439d371ad5ff8d151972266b75cef037208bbdad4e74e72455ecf2d1d9d6c150c208ad557a868f99c7c1bf782c6cdefa80190066198bb6c37858338754bad9aa9f589ddf3f640860594e479d9b76d0b3177c22d0405c524c694a397e02dec86b4976d0c0ab00b97513afd251fca8860b8efd3ec504f52308d83e169a413d664ddb4c40bc0ab5b1669ace816dafc64b7211f3ade0404c99ee6c752d688867e4ed31c53078c19174bab653fb84f30edc4668c90f352989cc521ef219636adf6a36b3904284e85589e292ff84764aec745be6f7d8042d011616a76a22bbca3feaa0234b45816e3e25c8bd05c319471d231a84f631639060aea43f63a658eb61271c352f2ac0a869513fc38762c0566c0bd4c3b16aa02063f2e52010968d7628fd320a96747386aaffd35d6ea3ef5971bc2113683d36a3534719585e4c913c2a589fd4491f49f20b8a84f2c63b5d746a733bc0263dc9f7df2387ee4ff680a93952dd0f7b4bb1d414423bba70183982b09d1f9d9a075a56974b7a2234212c17e56455e6f242304b214d8f59d83b35f257d40a7b094a8835f3e0d3ede43aee96b9668db33948f737191740a820ca6aa4a9cb322e1d995e219f257d2197f5e19db4489b3279e360026ca8d8487dbe72021d64d707c05795ebbfd7babd5ebdb29c098a38d28b06555d7bc7383e4334df80c231a6654cfdf97ef573a96fb86a374d4d64504830699b2d1dcd15d97e880c5ab42b65fb397d4603f9bdf365234869f5171da5153b9e57d975989e9cf94c1f2b3cb2b0a75573b43d3787115014c668c8e6e9f931884966108aed3982bcd31944bf398318a8f00609246026d48474ec75ed4d90e7610d5d00ecab8ede9d17bf8415a0bd01a21b2b04c1052edbc7b1a49faed38f8a834070c3b96e87a6c2c801e9fb82d46da2caf01cc173e4f6d87d81eb6f2e4cf5ed9d33a635eb328cce89f2832d1f4d432746c692f852a91727a220701f5c2c53dc29ceecb812ab02abb7362d8f09c30545e0535fa9a8d5cdef9a591b61dd233415d2df3032ff7a13d95d4db030d9633f96ff8e1b3784a86fb554f2033fbc084e3f394a91dc7da6cee70e075195195e60c4058bbe435e48e4ad3eb5dd26a118f4aa82d109554894c5894c9e1f9672cb0f6b1f3b85fbc9776b0510188c86ae33738b523dcac7c1c822acc04bb0b4b184637136596938ef5341c843b3da3ba1984a1524069c0561f08aa1669aea55748a867445a496e7b02759cacafefa62a0aaf58a2e4e721e0ab701ec3eaa9b06d69a0dc30f84c2cf60e203e0c19f82bdd8213eb982ef380f1ce982e7f247b241121638f3fc81d30d3963dd90b6f3b91fd9cda0b1ebbcf76a01fd5189b38a9bb4a380dd935494a2267f8243abcf106076a3c0a1fd348466b9687e2d10a51aebdfbc182be1e441d1ff7072cf8c6524e8d86e3ebae237e70e05d75f7eb1de242c34394d64838ab098f5e4ac630ae54f34a8e1c646a42dc3ddb3b96550eb913c4d2f4e0c8aa558d5813d68b0352635fc3bd75f7aea65a21bacecfb440ffe18f88be2a288d02fe3b4fad230d33f40a56c76bd20a37f796166e9a19989177715ebad5e1122fe66dd6319aec725857b69b6ca946fd8445aecb339a97afa1324b0c19ab8c1608e695892898891d135d49eff013a6093139e3d861d4b39e046650665a6e29b5433905eb1a95966982c88d0e5c17efa0bc61e4b7b24c8ceb27a20bfe93de263bdaca34de80a7dd717eb871d805f7c9eeac1867df96fe17984279df50b5f9fdc50abff5581021ca9234b9f3eaf9f63fd3e092f83bb79a874e2550470df977089a51267ef5a7d7ec0c2f4eba251d26abc03df26e60bc25a968357e672fe5e84c9f56da8a68e4ec9e752a9cc41311142033ec36343ef43573e675f16009a4a1ff695d0a4a68a2a617f81debcd2dda17e49fbd48f98a68a4300339d5401980cc570bd1eb845fb09e1f5ff3cf95a3054ea4c160c5ecbc157e35139713d5aa1d41e225f1acc2d67a81340923e93ab49452316287a19ca510017d9ce02dd9cc8d38d161fd8ef8bc61760a5ad43db2d88ae13ed22ac3726a517972c40031557e93945d75d6ed4bc291ca7c55574ae035f127d305c1067501e8128fdf13bddd96d1883b83504e4030aabfe885d30145651071934dbdc5660d192412e4326ca329d41600842843330a27ee794a04e7f060d00e080c7363e078f574c2e90676b4346bacff3be5ee26e9b50f15ebe4f3fa4318d5ce7e1e6fdb117530192f5faff8bdab8dbde524a29934c01890891087908b6c48196dd94d2bef1dd784f8df28652ea39b8d15e31f82002d310e67e89966166e026387291ab22dbf0be300a45878676c07142e371e9c1a395d91d1b9b01dee9ee9ef5062a93d5d4eaeda0ebbe99c6d1349d9b065e059e2f5ae1a457ea54e5481926fbed40cf92769c287af5c8ae122ce024c735d752c4c576706c78a847e0818de7813b1c00fede6c0edcb15aa175f84f51885a921ab16c20046108a85a57bb1004cdbaefcc537e87b82217e8fedc7b6f53a92381e445725fafaf69dcf3bc9776a1025ca63415f832b535fb2db9429ea29776b9c8223bcb9bfdccee8ce6a97e5d988b2f8eebec77f6bbd0b2ee7361dbd090cefbf39776672e524aa9e5b9eff6feccfab2483e8adcb7b77699647b6f0e9d3fd99f5a520c24fb0a50806571122ce51e177d362fedca6297756356a7da5ae79df1b8389add19bdb31a34eb993b05ea7402c1973bab41f33e29726f2eebce66ac1a7467a3d19dd1f928140a359bd5eac2528215c828052ae2a2c7b58670f0536e59add55acb707cad67fca94c56f3648b96b22577b97fe1fefd1185dc37c4337c504a69e02183572a83b5b62374adee6efb7a5d9dd75471afea2e9754c3df1748909f5402a82be2e2e501ba3bdd4dc77291e404e6fce77b0cef215f254426ee7dd97a6fd7fd00dbba9b6b4eba5cd2e549d7cc13f8092cb374591715dd859a4d939245ffddcca118177b21c1fbcf3c8117e027ff1f7e72176a681d43340d027ac6df398a5ba8cb4d8aa1498d73a0977d340d273fd63352c668315a8c16a3d16292268447e972b9a44bba7ca40bf25d8216fce122872a822b168bdd6a802975483c5535f4f4111380e8b9582cd675a21c980eb6a960341a39761d2cdb4514ac384a80efd02908235a1d727144e3388c69d9abcd933fd7bda82785f50c169ecb8b8d23561ee57835cf95733ca5a308d83f46088f7568f4a4696a9e13da05ab82d6019b2a94d0b246ef7936ac75a157ab61ed46f66a23186c041bd99c9ef15c31af8919c4ac70a253f6894ed5982d6682148cc2b12a9187e8223ac549cfd593dd7379c78946b051cbc3f1945767e3576979fc72cdf19312ed4215a275c8a6b9a3f79a46f4f509f97d758821f2f8e5effb48a49127eab8eb636b320a1a79ca0c9a6bafbdf6babbb9aeebbaeededbdd4efaecbae62637b9c9711ce7b9cc67f643bb59ad569ed7f28425b8bbbb3b08dcfddddd8d236bd96ddbda8eb338aac033e3900898082cdea6add568b4d94c261bab4cac32b1755d419705c4a48913a1274339fee3d3c3936f5f9bf666da962bbcaffb1add1787e7a9695c560596b29b43c9356e71bcd8709589f7d24076efeddbdc8bddcfd3cecefd170b44374c15caa3845c7801c60d57001dc79de4ebec884a506badb56f59080a6e5ca5d66ae1b5028c802363c95c383cf03cafe49556565ebe182e2d2c2b2f5f0c9716161446803bdb2469e4893a6971ed2888b035a9147237f809cecb7f31c64f44e597f0e3b818e1b842fbb2572a954a5ecad312f5a8473d4a690a9d29b7f4122cc9929412fff5bac6650e8d336024975e827f05167d090ce242991b79e14864277bfd3ca4cca590f41e18a469d9eba629fd984ba003699afeb28f1c426099695d5c9147e94229a1dc3829a1a8a8cce4c37678643eaf148f0103965a6badb5d65a6bb5d2bdba6eea917a0427571cff02e7b1ba6875c13c65753c555d2ed7bd2c3210745dd775316a54806f28a4918712f6144bde3b4e24daf16ad72aabec6e8ec3f8fbfe51536745eb9e880d07c2fce05c47872a59c10ecd86035d47c7a6ae56ad556bd55ab556add56a9efc653b3cb207f930ee423810d9fd03be23bbe60b704fc9272eba48d42d2275db74f62167bd0881e5a394c03119a34f6938daf7e84e12928734c38c2b026b140193defb497950b98347cf2ca2f72a09a606942ffd0f94ff517af92a811fca7f220a4a7c7161f94d9a9625876438ca990f94529801510692fc10bdf7ab2e8fbf5a0da1e4d00a0f3989878f22a370f4a210a60612291c85de8bfe734caafc889fc0186a0db5865a43ada1d6504ba6a4744e826e3767cd93dfc82194921b17bd888b44e8c1db23fef21c1761eec271b58c68c9161d1a1ab236e5f562c509766060c89e519063f33cafbdc62824af5b44aa5efd7171865560b05ce9544d51bc92ebed2b278a7d99eb112ef0601d129de292e8d4f560de4a1e2b2cbbccdced3cd168d431912421d45abbf667bf4c6be7206bb5b59816ecdcdcb4623e383b46603dae1c6badb530503b72794adef48cec46ba546bab937068686805b22e6a58d6ddb6ad57a34ffe337ea4693ae798ae395d413fd951b2fb162f0ff2b9c945ea2b68077994326e87d605cfb4b2081da28e4c48c0f3e504f1ea9349588cebfbb8b7b74e97db968b3748d774855a4c176eb084ccc68fbc248a07b074d954bd7714031a55ecb05aade46aaa1acf8c80254552dbdc07b88c127fc0630f098d6d1b22c76f75b9d50e352808813fcbfbe3ea9b17943d2ece2c755e98a2cef0993474af47c50ea5a53c7256e0b16f403821af9dac97742117238ff6a9cde919087c8dc50c2dccbe5e73926ae8ac15c7ee54516be56ee5aea8e32e8d465b828f90501073c6a07c9f1294c08282310d02064104118495374104216f826012044f50ad3a32cc64e8992b49303578dffd0fa747e02478b4b223b0748c318e23704b1e7bf6d3c6130cf002e3483c5060e01195472067230c3c72f98505789c8185f9f5c7194aa09b04991f8120f583cc90ab618c8b1f13f0f849d28b2b079957390040f8f3005835b2b6b18ad42627c0f6666db248bd91ac2336476675649647967374765aaea9923c7ef2efe17c5c40319f99cc459211d8ff063b645d955a8be30a6282b5b62d103bdfce1c649e80fc69c10f023de3417ac69f24e1ab1100f736cb642f353d436309b602b9f7d6dd2291a8bbebbaae13891cc7c075e49503637d9e2742e2b2c3dd7befbd3b17767bae8b6b39fadab6472894f83f84c31ff048472494124e7109598e93ddfb7ec0a2910665b7213d1292d88cb2255d94eb3a3172d4ee73f290649c6f5311e8f99deb9c3d6648694f40e699c7e32939a5a3cc966fe1b5cc2862655ae316c6daa694524a29a594b65c517bbbc8945edb3c51a0ba240b6b9baa2e51fa5ea54d15cbd3b746a48a257cc14ff4e98f8dd2cfa104cf5c7328c19ec77a47a423789583cc01e8190a455e794774349aad1c87f14d56b0a375b5db01b948bb5ad8d15c84c13a9d6ec7f3fa2b7f2b2e91dea3a31557590153feda3e7b17f444df81dc7b7574c18ee2043d9e9360903fda57969214030c2b2101ec171c6822842cc3285e41d93e90ac726d63d743a68fc191d362e4a0c81449a63d8cc2f1caeeebb2accd5a9a67e977344a613d43bfc63b2117693714e462470bcaf4bb9aa73ed3ef803c35da8e46dfe7c663023d70b65f9f926ae883e56f9322f456c36b1b028f1f174d9f529817f92ee08238804084f40ccdc12ac9742753fa4dbfc665a7e322ed763a981178ec6099feb54d558ca75ffea62a4678b5e8137d172eb8162f32a52c178c4cffda7a8652fa75e6a91f7a6d15b1b0c7b0442ab10c5cb2256200946b7dafd483519d24d7ca515a7532a52a99524ae987c1d255bce451c6892b3ed7e7ea6325e44aeba141ae31c0c955acabe6810f7260c51362202832034ef605cfaa892a327d4a9f73e20499fe652121c9d4298f231c34b1824cbf99a87db5562f903092c1441399fee450f2bdf81d9e12e54a05b5914c0c31c308dd8b52dab46535b688ec6d5b93a3add654d52cb4c0b71c4a30cd028f6f032088a0051142d0e2eedc16a56f83b2ac914fcb40e35f1a10f07fc1812643182f0dc7457f224fc0f3d8b21cd6f48c0f9e61e76ab958835a5ed81ec0c8deb2ef1969eda565a7130cb243cf5ce00e215fdbf50b746b97766936b440f4dbb72ddbea5e18c76b05c47eaa5de2668923d33eb56eed48a4090c5c50647ee739a7f7e8af1f437f0de75740e6ca83c54f92e226f8331748f2881a8d5c762358269db36980c711b8028c4346fee3d363d4f82d9b4994285102a684cfce14d5f33cdac8f26d48176a963ffa01cbf7e68be746839ddc59e4fef101cade1c89349ea0ec92e5db8083ab56827678aa6930d8c9b2c8ed4016b55ef0441e9b4996924e9fa41e5e128264335410cf937c9c024c5f78c65596a3e83f50af336453456ddae59962a698a9679657f27cd3cd24e4aa2fc8e4e3829809c854a32c17f0208f265bcb054dc8a3c989497a8bab6b4bce0b4df6b837cfc481a61e1937af37b4de5423b55563d5c755a29d8a7345939a536175a7f650e92c432d2c96272d45443725f247538e0cc7194c642a838b252fb469cb23cc4d509e2d489a467ebda91f68152ea24ff3a51224490891270b80c873e4514ec6cd142b0599389065e885a5039c9165a81aa9384d9a8166046c21e4d5d634fe2d2f6a53037c7f6c71b5bc9a864bcd60a2c5f9a309499e3d392d3979bed0f234bdf2cb120acba3490673c1c444eb983fb620c926277a66fed892823cbd1c834b966fbaa0a9079c11eb99f91e9d2f4119b7a0525049a834845f58c75578a7f4e40a1dd10d1bc12decc2397962569e5f6f63bd1139110981fe32e65b5006175dab37d36341c2f2ea99590a6a4d95e85b7e579b0834c16aa0361d65228f2dae175acfb4b83ab0c5354fd3143331d1aad1cf37c59a46e6695a92a7690a1314793ecbd0548d4293f77d228c396ebee7a39b0c2ea68c1b0d1e3cb6b8627996825c123429e999f9b5a5d61697a76a9edf72c4534dd3414e9edff2f2944b9edf326b0172556dc9c9a296a729c613cb73da9ac8638b2ccf8e45d3412d8f2d3f79b6c0f234c53c359682649e1a4d4a728fa7ea2dcf27f268f291602928cf3729691aff9f3f4316038c1c082168ce39e79c734e1a3ef8fd4022c02a34bec67be2c9e32ac7fff980c709731ae2b13649993070ba4023789c309724780cb283c6cb7f2cf0386192f3c13ffe3fd69c193f561d193f569ea9ba81d61e3a25873cf5f2fef409ccfbd3db54c95a8df6d0d48c4681688d324179ff5e25391c7ce4cbc9eecef2fe5196cb356d5355e3639f8bd3358f782afc70e4b819e188b18cd087680ed221fa8406d11e90caa8cf8cc6002910486b2065426db409bd71911af1933f0e7704e77c3a3c620d70dac0599ba76f0873dcf73d4c84013b9b40cf2fa0e70f943906d8d945661228730d5006046d4601bb499635796b9bb6a989ff61f1bf1a7309e98f8b9e6b181bc53acb15702442e39dc403d527945f6514945946791aa7d84b134b8841ae1ec02b2cc1348491af5785c94c980e3e718fac098cc3452caef0235dad186009fa008f9225c15601ee1c83c1ae10547dba420df03861a695774aebcaca9f8cc01178c0caca977ec2563ec43f775c36346343fec47bda063f40b3277b1732251c2930337d97239eb2dfb943f92579735705660e37cb503ad1818e84601bdc154b572fc4a0767c220e9697c15fcc08b3a46ab52a7f33cbd738a5206699241e520757c932942a34afa8847367eacc159cc063d36c20c12612d9e8028f1336064165fa5e8d0c9ec77a06e646a0c1340e6846980df9ccea8e118a90c749eb9ccca8f42a6f7f934ea4bcd1f06dc66a1c2381eb73f314a33114b0e685d51783c34fd25a3b613b3595164fad694ad8e66c090ee4713299b6d2099bb039832a91197efab1c562b29b904f4f75526715c8e24802773892c0a46c859364600c0a159a46d62cea14e08b1178acb1779bcb6253c57155d6759d4c8f8b5e67abca841330c84481270964978b9e99b71efc52048e3d177df29f7feb19953cce5b9d5cb4aad679abf316ab6517f48cbf0d4062222d6a4398372713c7fbae7b51e7813526aab3e99a2d17672bbbad3d555663b19a006e9e3ac606518dd5d8bd2c36951778b5d64a0309586ca1790d4bb34c6cccfa74eb58231c41ba708356555992bed134f2db02f7c08a8f0631e8191424f846aa706caa6aadd51ad127ff0ed3d0c250c051c21546b06c60a3d9f28235c6e3a2cc2693559bdd81a9006661f5c72abba93b2e6ad127ff0a86adc276e8ac2f18ac569c16da880755dcf17db53e0ef07c19c2c8279245492af2d9f57b8c2828f30465e64a8047549ed4a5b52112ef3ee7a9ae3b5cecd0da19aa8bb4d6703a48a4f2e03e51e0392c10bde760cf5d3df3028cbb7abf96f27c0e5317c366c15de0f9f247cc926768c30358fa0ee71e4503d1244dad6756fdfe33f391f5c4785cd4c9af232e9c96919b22923564071d5cfc796a4ae9575048734070b8610136fcf041830c037091ae34617aed0ec776bf73d639a7955e84d7cfc91b98577f0e65e060f93d7fb22411978ec51319b96f2a4bd21d29df815c755b2c5a288e4643f268546f9ac67e0d82562db23371d5bca9ddd893bb230473f20a47eeca50a008223b105a905aa3d813980b45468495241e148551133ff93b7109bd464f48454846442d190c2db986231b10a2969c3deb975af747faa4d55eae137923124a09a7a8acb0b4b8c4f85e4c303128c898f1604843a6868d1be26906470b2c80334415be5338e9c8b1024a85d38b27f124de10df460aa793d8020b366a7c31e00a281d396670a4e02b3f782d237dd26a2fd789bc1109a584535456585a5c627c2f2698181464cc7830a42153c3c60d31f77b298c7aaa72ccec68c15e4eb4801b70001264e5fb77f0144bcbb7cb778cefeffbe5fb657fc77c97be5fbef0370adffddf34be656a7cbf9479cac6f78d6ff11bfc9ef1fd12c853a7c7f1fd9249d3a8f0dde5142c807bfc58f8151e07585b4ce14fa06c3185ef1aef143020927ad07cfa1b2403785621ec144ee14824872f7f470b3c421b33c09816c3f00610fc6ac4e020822c321f901b20a6c112c406380ab1901a20078e749001e9873bd0087f061882e13824cf78f90f8e483d689e11521921c7b160db8f16712d635809f40103a41303d260a2edc08032bcfcf098c0017cb3d80b5813c38748cf07bee0d2b29a18e0aae58501b8803b585632b480a8951d34b0803854503e5640b145fc29387eb0007e7dc2bf02881f937a50d10614c8f509bf0e107fe903a202d216f1a3907ae05cfac6f5257e12a907cda56f5cca01ce80a41e34d7909278f8885982d862c591ebf8234f9168439edf62fd8ed483cae4ba803c63b8bf61047e3706070f64b11f105c593a157c450adb1dba9d1d8ea2a493524a6bfd72adb5d6da1ed670a444aea44d30c9bd04095b1ec52548d0f21371091241795a8f919fe4720d452359fa1ff84be19024f287e0b0f48fc321d8238d5042981a563ee513b0f229610632b012262025032a610a2e55127d4982a10b850c7069c8a1ee771f137e3507b8c318aee1fc8942919c52e1719eea2641e3d29d5ed31ad2affb39c37136f68027bf651a061946ce2d734f1cc2008f1f65d9cc97379df33755ddd39f2fae7ccc1ba68af4f3854c15ca4f14f049a296a0f488489f48bc9609a9c08f9fe59311519e82f1bff43fb1746f885dfcaec0d741cea2a8fccaff50f9957048929b128e62ee5ee587cacf53f72a617b28c3081ce3291f51e07c8f65e4f3df53a59f3f5ff4d47d1470d4c14be0488447c9a3218c0c9de9c7d099863bc2c04ffd51704a0aa843cd387421481d28254f35e9470e65721cae99a2fb5dd8e3287b88237b28c72038b2676abb3e78f4b024ae101d5cdc00de41880b05e9bd341dc15224027ff0d84142380e245204860960f42e240c16578448d3c4d019c654826f04e22023023c3aea083c7f8632f37d5ac0b38490917ad3040715c31ca413b27dd31078070a35c3f1b2f2fcd8d04e10ec565f36996c36ab65db8fe2fc1135ae7ad457167d8ddbb8593373f04209485b1685230fafccbd046fcd5d1069cb5d28e5cb13fa825cad00cbcff1022cc31462d8822f4dc0341c256c0052c2c8aa83035b2c4762698bf5782f4927936c240523030d2ec3d1179884652a3e78ad802a8498683191c3dae2eb0f4121f183974d0d61e47b1078f0b219225958c05a363c7441d8d41fb2aa814d0d93f8f7f320a5007cba0fbc69cb3403816683dacd0658c0666dda9a6492a322ca846ae37c4beb8e1be17ab23f1312e451e6c4e451b6382846d993fde69c03e130f08861be985b6d4e97ad295bad9a8bf23520550d90277f1a2d7a4543c3020b2b59ab4da0860c086ba494b77ef946344dcb2156be5030c0d342da7ac66b562ea2bc3b2f0523304318fbf343182a67795226b61edce254c977b72989714048d945fe7ae897cbe572c997add46fbf84628a46f54ccba03ec9e74490e58fdd857416165d72c1715f2c265f9d831a5096c0f308996a9f20902ac99a27f95c10d804597e4b160ab2fcf981a6e142723d64c96529e7cbf7987c8ec3f8fb384e4a2992d207a692c562f5cbfefefe1a7aa6dd45254d72371c39fcfd6b14a74b97a7e61152942f5b90a55c21c762afd82bf68abd62af19fa0dcb15503dd3bfb312f35a669c3b79ba3739ccb9cb5fde8fee9254c8d3b43fa511decff7d9aca3c851d0d0b0c00208bebca4641bca294209f3724481e9fbcff74cd472743a9d1e93455eaea7317cc0fef254db4c070214568ba689b98cc9fa98809140843cb3c873499e3e459e13e8fe5e6b6d0eb2fc1d008108d77acccaf92ef3d4cdf3fdd682cc7de69cee24cf6ae96492e74bd88f2b4fa993e74b3945d37473d2f7989c727a73c43d9d241e720ab0f31d2515397cb07ccb1991a7e8e79b5e5ea74321fb90608af20416fdc8e599250a65093c256b4ec99a74720710bdf7354ea5c820111baf49338011a06ffda34062cb3acc5cbfca59aea09c657f397754c0a094caa0db57d068b323d9dd36a2c2873cce232d3f27fbcbd0a6b815218f382a05739f52c8cd426e1ae9cd1dc89474b9e8fd6c427251602ae4cc41f69f4c4c215a255f7df2ff94804262bf89b83b9ba1cc48e16c14beca7c9ff9ebc661d7cdf554facc537307529c3ef89942b8380ee3ef5f14a7ab675cc25096c0a3dffc66bdfa0d28709348323cbacb5d5385e264b31a9aa6bf297043310600d534f4e5fb8ddea8dfe8ec2a719fe4fbf7a967fa6d25245a0135d05122535263f96006373c349e211e19904f3a435905a612881cfb29a534e43c176029291de50d546b80f9b75f50a711cf0349b0b5379db4b968e5d49c23d0e931d48e19aa5fe80e5714c83cc9973f5f2f4fd52c7fe64853963f6912c6d271d293a54bf96d2b75dad840f235c39802d01d9a667ecfc8f72c7f88a7645e8680e7ce14451c6ea0a183c7961d79bd64f93e7cb234c2666c201aa402172fafdc7fe3881aab1711383468ca9fd406796af498ec22b7a746c7e1845a8a3cd227b96b114e1660043158d00d9dc512245493435d841c21998dcc13b1d11104f647f5008bbffac0516698f768d0e96982e8d0549d441a5084f91a5f811ebb3093e9f1f7347d7d1f8a79d1cb214fad56289428fe7f5f100d476ec8535d0cdddbba33c3a30b50ee7f79a198af3b1cfe5e44cd157dc171b18572ca0d47ee0b470e7f4b38bec8128ee28a4a38aeeecdc59ee18b2b7c695d1060f92e409e92306067af3f05bcb0b17d7c4ce0e82e0747dc85f2898bfd366481f832a8ff453c89005f89fdaba1e3788acb4de50c7ea081980fdcf8c10f563c58519aefd573df3220cc0fb195d004209a8da8c4a6c613b189593983ba85d6cce5937bbcb4dcdf3da90512a475904282dce572c7919baed297d64bcb5330362cc08f788aeba15da7eca269beaf58bdccc3a64ae6fbefce54ad421970871b0c237ff5446c14e0c2cbfc8f00fc2a002fc31f2ebccccb84435c7822363db47a9a1f6550eea053ee6f0a0cc57899c8fd7d83032e1c87f1f7fd8bd3a5068b81d3330dc2fc9019c283fcf971c22609f8375ee689d8d400617ed478f1c570888daff1446c740081e5b5798abef8fdd7c9e9fbefd07de2aa14be9f2bc2dd4c950adfcfb5381c57e1f87eee08f79aaa99efe7609c8ef3e8f87e4ec6f938f7c3d1a66a85efe76a1c1357b1f0fd5c13ee36552d7c3f17e42921e79e74aca902c0f777379d1157a5bebfc3e95c53a5fa8ff67d6133e569844f83c6cbdb9573c7062ce8c224a3117ebf0b932649573f08d60ea7a8acb0b4b8c4f85e4ce0871f8623cc83214c0ffae083e118f3f43f942f17403b344ffd34200d00b80a9a33c291938142387efd3160f571b1c16a022b1317fb5fc07a73b1ff03ab106859a035025a57ff0a6855409b02da998bfd18b4401d686dd6898bfd2ad006cd537f0ab44dfcd40f00d0d6e6a97f07687ffcd4df026865f3d4cf026879fcd4bf026861f3d48f02ed113ff5ebe8cfd13f03d6a17972e2a77e15c06a9ba7fe14c00ae4a7fe135867f3d42f82b5c74ffd1f6daa48e1f8bdf7d1326a446598eefa786a74a9e5fed6e9bf3b9e32cd8a54d9ad5d26ae2a82b2c404b4dc7f9bb80ac5ea5e620223b9ffc6ba4a5d6a9e1abfff689e829130a9f32e4cfa5d6c2e4dfa5d6e2e4e3cc5d520f77fb2963c72c7c5fee9b11ae3b5e5fe0b8e9795fb27385e2572ff0d7008fec18a1bd06c784021811036326f031cb2c28dcd900e5c9b24309487941c1b9930090cfdd15d432ef69f7ec044b2ecfe0bab01b64d05a9100d72b17f82413564286732e08b15f8db4358c3648c04fdb28b530b8f52f6f21191711c607828608147eca212e3239ea2410a699a53f6df6148d3c0c060730e320ccf1386e39a05d3f081312e7e1d6444880e269544a2d54b88f831326d645f08e54953633bc9d8955d9e82f9d124a3562f04ad5805f07ff9e025e94cd48ac07195eb7b600e328a2376d443dc0b251891d99070f080bdb8810d69e4bd68eca02c1289bc1f8d462ff246a1e8a2f45049ee4b295f061789208548be0c1fb027459ee807f03a92a910197cbc8cd0201ac07c51cda29f4e7dca905779a443cd1e38ce6491f722703c65912702c714b2c8f346f53930c80ae63ecdd51649e2df81b749425ffee7975ec8dd088157c42c4f51fc5e5244cc6d70481ae47147963b320736ed0b237986fb1e7845e03b018bbe732f394150f6bcb2dd300322c4534b70c880839cd2a6a30878bee86b5c34c3bd65510883334bd08f4c806f1c816f982af940a6aa699c03719005904934c9f72f6986194618797ed74b8870922f08040996493491d25129c0338c30b2cc63db240b73c0935becd47830cb27a51457b8bc1c5f60520c28e42fb07c9973086159259d6ea3f16041674e8ecf48ca230590364cd50e7d030f2071b3e9c0182bb0c9f105f69fb94931a080043cf610a987e9258f0ec8d64933bc1460b67414981964a643d8810f43361dd85f38b1a152d4a48055b0c22a07f3540e90a97dc08305ac6bb0fadcb52dae6706633b89225b813f57196bc387e92cc51d1255001f4d534318186cae5fc355f6ffe1a9175c1c025ec9180d33c847e560f92e65400d40e5945286a30e0481d2a7f427a53fe9c8458f420af1079cb5b6732e7477ef6e5b2bf5e958605b7b62b087460d6a26a5b49df69440f05ac676d75a6b7d3ae75bfcd55a29f6276af704e9b44332fdc9e3fa9c554ce7b8a7949278d0c939adb4abd4d24b3beeda3a7dee8cd4452291e845a14824128563c7514ae9a493930e044a2947a90cb9abc3a44b3c5ba7bbec999e9452aaba1c9d5eaad5fbeac0e6d802d3efa7593e9550e03ce7945765bfc3915e6b030d29f07c1a44cc95629b89b10866d311e730c70f96ffe10eff678c3ad8dc4fdf29a534c70d30a507681b4ae988fda98c1b2c69add888ad2f69d737e45ca422d971e1f851120f393f5029a596d24a29ad96da5a69a993dddfb03bfa33385b67d7fd7daf03ddbb900b4759be75ca04a5744896df9daad54afa94524b47e0b5fdb17e05b9907371ce9ea7fe183ee09ee2f798c37dea7062295078fc2c235f288479d5c9d177772abba02ececfde610e2bf09c7376cb29e79cf296e5fc415669109e488ec3736887a9aa61ce6fcd99d9c4888b9d47d488cad203f3d8b439e54c99defd716f6dbdf37279ca26a532ee08af5f360c976d86c1b9e69aec4f697f0484a0f2e823cf9f6110549e00c8bd426e39471672ff4a079be77ba0db5cb39cdfe09c303eecb3903dcf1f69f7cf0e1b00204c0fca62d54c73937a48162b07a402a8640dd7553de910c9000000004000c314000028100a86432291502820d15461f70114800c788c48825c1dcbb33088719442c8186088210000000000048646e300638405be2940a1ee31b8c1c48c19156a1e356979ddcc63dcc5681fd1b5bc1d52a9c504741784ef63f6a08c32d038896d122c56fce36af4f92b59dab03bba317d89ad11438f0efc9a852b450a72069b6ca0bdcaafbb2bb20195f3eb8844ead74ccc15194641e29c7006dd5fe02a0d3b2366eec1b8a6c4fa173ebd61b3eae360dcfd06b2f0bb731f1a6bbb60eafa641cde77c167aab1eabe420a31e6daaad5dd26de00e593752a9ea91387280cfd2db6c5b452b127a2f0c595b335e8944fcba5acb48beea289e30855577e5a09ca7733f881501b714dce4856d34cd191b2151546000345bb2f6bdf00b98de8d04b60f7d37014cd4d20530a1376d3334a392151f5d592e4c29762a81e208f1c4181253490ca9a91688e2037b2b10306ddb91ceeafe2ef336ffbdb4cb850219cb8fa17c4e025f9d888711b618426ff307b4f7eec8a1cf0b19d9d94bec091fd10892ee41eb641956737652786432fad9044b78a0d0157d1ed5a10844e9fe043dfb47dd2c69315120b6807841d9e00400946115a0a057307443dad9d845921378d4b423a6f677672ab4cd3b827de78b950601a93c818025d01ae4e90ccf83134e89670589cc893aa4696345b47dd954042d38bec3a007cce0e63f3a9c6bc7f12623346863bfb3badd6ff1ebc7d63a9614657f2a7bda0d3e6cef9ff466c0882aba412e3fc0486301191a86620a895f56361efb431c1a6bbe69961bd68d622aeccba7d94d17cf067148d0e39fb1ed1dbe65c3e99d74cf74c18c4e80089b327e530f483883de20da09577b7300c325ad3ff50140bad12fdd09a78ec81538b59b0dfc28a8e97f02c5257e5a4cd09f4a9fdbfeaaf4450efc450004c6220b25f8256797bb8d97690b01eb222d0bcc058ac0f5f5cd564853c85dc8b93dd944153be0cf2fdae68ffcb40f2a4a691229d2df47f3a40cb3adb4dfac0d3b7bcbf45d8a107c0a55a12690767b7caac237f10e5763fdbcfb3e63c29f06413be089221da79d5c411fd19d4450f724834e9e8796d7ddd89f90622db88c6b403732f057e610bf4abf750e7755ae1936bb32b042930f5528e638651bdb3b01af1fc0aae345f53a1d92c69f9f6623e90e041e5c23a0ce1b51580270538f00607a87c3bc304cc7b8499709880260cc1859880c2345949db94ffc9c9a0a404d7a04067485b8dd655c3a941125f30ba8b10a88438d98a5365a55e951fcea30a43b69cb9a618901f3ea0d7301e4db6dd265bdd12d7e96ea92cdc16202cea790190ca73dec0deeb11bda0da6638eba7cfa154fc472cb3910c14f3fad56810e0a8158ceb425d2628c5815030df20fd13a6922526e36559ae14f057f969fda6833ef07e65c63ffeb5913097c47f386b3bf877179a9b4353ba9ee0d5bf5d4537fc1b942ed27cdd788d7062258a87e730d57aae28f78c3e158ac040fe50838914dce2fc0613bd7a80035145d6271adb50132a14a8316cb2501f9bb4830a16b062bcc6b1d983e79b6372c6a4f49cbd3e81c76f424b866c61d3c9a5a3bf11e736866b0eaf1c38f98d3af5c031b9f9a40b98d8d3f54408d924512e2626aaf594c4889e8c98e86988302d202297857feaa145d74621342e1db62d15c910bb21578f341cea6d0ca7338fd7c744d860970ea97a1e21b7bed1974facca1e391d21cba5a7cb25e9a1cbadb6bdff0226111f1f191d463c9cf311b8064788c6da7b93ca10e8dae4137a7b6a04fd2826b530d1de995fef7062b2577f8fc240842cad7b09e7a790c6cc8f38d90b7d64f820dd42e471fb23c3bf73dc923431c266486a2ad6696d445bb2c9860780aa4afb7db8e3543832451de844eea124f3dba2c6e79706bfb2f56a602021e09e43ea24e3a286344651267ad7a53f812133dcd4ec504aff9bbdbbf56a8bcf04c508fa8c45679d3c51c1889c51a7d31f14351fa9ea90da1b7fdde5705dcb904e1318057c9453bbc99a577fd102dcfbd661c726c28cd7d6a5f36288c2d99119d6e5a12e59aa911f8caf1d00a11c58c74d46549c36fc59e01178a9b444bbb9637b687f9d7e36afd4f6ab60331b7286c040069a0d82d6e9db4bc107fe1fb3b4915cafa9b855d3b7642a6031d1756c7199c020072f4f9319a15a8423ea93372d0c9e71b1936c0cd98abf661559067a091453e6e83c1bf8cad8ddfed9abc62518e6c37110a01cd67075de4346e795461b3e1575069f7fe1df9d401f83c9587b6dd4db2352dfa1d3e78ec5e48496e94b2aa66c2d36b88593ad3b5dec01a0b3c16e223cd8bfb7496c4967796ffea5e537fe407427fb378f70894300ef0d6f58ce83562570842a0d02ca3fdfa168eed06ce7e9c3be06ea8aabc0f57dd70f761fa199134210fa95832ab3b2ceeaac1fc88d6d874916ed3b332c34717c9494be84a1061b454bdc74858e5f4f4086b3fb7d35db8dcf80ae4c4e7c236f9a0fa3491a0b060a05bae67d52c764b856a0491714f07c981956f26c4447cdd6c1b00139d927fb77bb774e14dbde5bf0c24a01c020a0aa1158b05c6a71a9e624ea46e213578cd34fa702f31a8b35a8dee879cb17b5acc0e1168f5d237d3ddd3ea59524ee5910628bf8f83cf54674a50663d58f8b3a5785876c61c9a8cbe4fc2a9c24bfb63a626b59644bc134bc851980108d70ae05f23237f70ed3f03a452a77ab00006a86c6f76f1a593471f3a88b981759d9681f127dc92c3b33db01ea0feacc7f9be296fd4a212ae68a9a4f095f90486d1d11949b046ed98069757c7f36bff6ee3ba19fb380d714c05a0b8f3c66482f30b272456c51c39de1286b043d501c16b42283f16a7d29246b093ba98ae78a146ace4bce173a91222a3990245c62cc00ac82185bd979239aa81c0ea36a3b32147ee0deb7aa26b657e7296da922ffc0661c26c1d1f334006e486ca50e9585297fa9937a3e5ba51d11ea29de1d009c0218f2505640d28ef389973b5d22cb47bf3a543ad650c7c0689c9ba79cd52e6b09c8e23300e879ddca61e142dd51bd15aad68199719bf233859fc40391d38de5d41a07ed891009382312633e77c83a2437c6ba1da2ac17871ac1b7215ae6fe85d2f2d18013db928131fc77892f9ba726599859d4c0ce128a93b01cc0f5300d112b122e375d6d9d228dd45988f763e38a4ffb7291e0e85e5700a6351c825253c4da021ebeba5433a0080d21c85b41e4d65d150b2f8a952bdb1959b2818ed9286c8a9743e88eb40250282bc4b49456b8619a570c9826553b78efde736e9fb69418ccce5529df63079f4d1c4c796868545a699150ece5e92da9c4c47f63a3e741828fb0d8edd2748b205b36bf0bb580b370ce93e69499210adabf04b37447490890fc47f0053668536642c80f9b9a07e01488ab9acc8fc6ab817da9acc1beb36bc3a84e31d2fcb48a0dae3956255566ef3e8426fa3002623e1f3f69a1bd34ff4537be2d7aa218a5f71c19c74342ba8eb76aa5525353803c849ffe823df93ae352d8c29c15e687f9e280a47cf442e4de46e0f036f01f3f81d688a67dbcc6777f1cdfdebbe9436504a49c3c500ea01430a10c5e5cbf4568e2d7e27166188477a0f7f334a4356c78d702ef09da87253018fa140b83c6e02110a44569d786a605138019d55db4b315335aab8005fab427b4e27207f8179fd7cfd90db03f1cd6b74fd8369b05b2a48857a3c5ed99011f957a6b9ca35803151587b07ad80c338ab9a496b9a833d022432e3be890bd4e6de2117bf61426d5d8bc2ce97d7e4fbd5945e2318657f7ed3cfcc254348b0d2b75abbb55f5f3f79062b88739b90dbf24eccab32997e8167785f161fe51dc58240b83ddad9880662ff2f4e5e7e4ff8e2c3c23694a42603fa5e0764c3f8ef894abce88eaaeb25c09a606d6191db39fd320f7d3f3a2be3162f83beaf24641144a0a539187d63e727bbdb607fdf2f2485dfb4317d0b6b60bd41a335a9c824c348ad8443865ee2c47b698ae18054d9da01bc5194fa81d5f0d705df2d679a718315078ee7761229c7e48710554b360eaed716e019f1b36035153060dc84957eb775004333f4561fe48d9630c0ba0bd099ea1e7a9ed29fb736bfaff4c76cda00bb5ba5f6ad4e208f35f30212ea5d475937d3bcf9c40cd570331755c05666f28b7cf774115bce403ad6b1c9ee684b5b870ef4755b0d3152253c66942ac711c3b3a1edb1cec4106d0c7ac654b00b8ba4f7450e8ca4c07f027695b82954e9460c1b9d3326c234ba592c2d131347e603fccc3f296e491c570f61c3a757c22ffe8e827ce88c767e4b0ad7a74c0c67bccb64639a70ad241655473bb78dff6180846fd9fd3c7828612591ae18f0ae501a9009ae227ef1b1a07ccc8ae3bc8dd26f5294f6fd8514c8a0e832056ea4a81eb69b0a0ddf30fdc6468139906c5923e3063aa14f42056271d02bc914c22c1871771b409783d89404dab2694b9fa7019b27d30dc7db39d827edc1e04ea5dbef17117b59e857230b2741aceedaf4d6e9aa2743ea71fe066ab07aee5c011388d651126c2627ac3aa38e3755cbf0614e5ce437812684cbf7f95504dc1568fefe15a2fd08628247c26e714ad90c529b4bfe0f12b22ba34e7ceb2eaa0eacceb0a9348e7501c7b2ed10815a5cce2eeee69607f50f048d7a50a470fd5571790d6aadfd30d3132335fac27774b2b0173d39e998f4b67958ab0502f6909032a33e2f9d1a935206d07397427909b21467312cee66cf4d7d9b7b1e5b96b825064b30aa890c6c0cb77dd3f1644b8a9cb6d1630ab6aebf6b06b13cad46d5e80d8ed85f077ba0ee7eb94cfbbc45b9c773ebf7d1f4db1267f37158c8ddb1e5e7c4785d07a180da99af34382288436bd29bdb48ca4caadc7847997cc59a32f11bf5e235102a4c251be5a36b925216e1155378626327255498df14807f7e432772d1d724173c87932c20388d3536e5539bb02f2b06a4aa9ceba754bbc4091e3c5b89791b1fe18611a358b50714a7eec37fe08c9237ac439896429e9af4e97707a594b6170a9527fd3b815b30658a6f05e257ea695739eb36608b140dabe8fb3df203a00d286b2aa174aa24ba22e6d0a071a232d8e9eeb1c461437e649b9b43f7287da09e8d3d9451608e7261614ba0fecf512f08936023af31dd7c5406079a7bf29c60203af6b85201d84723b782e603667571aa67123ce3bec25a8dcc98b99e54b604e9bd959510ac6004ba4b814a32557e19aabee14f9413707093d1498e7c53b64ba9ee306467e4a4c2eac5177b56486a7549fcd2971296aafb5a4ffc5db1fdad010b183dc855403559bd71ffaa205c15a0363bd35966747bef2aad4924425030e9046df31b738f567f1f3038c8ee75828e8c77251f014794e80f2227f9e256261a113ac6e597bab14e72f7ce217e3dd7c423d5efbeb80444e9416a7c0f2a08aae0526324d14cf7c65adc7db0764a1be785c3151f2031626440e8bb1a31b15ee9cca466085a88ae083f0429c291ff4dc46519f84714427c009e76af5fc6bf47005f50efcc2eac0ead918e75931472f4c11d402ae909d54a1ad713be532f8851b340c26976c9be1f60c2d26926cbf22f79eb94594219f44b4bc2fd26308d6608176422c5268185137391e3e0515db9e9227d3517907338abb42ed551480db5d04eb6cae7932e6b5f93a00b07640b9abb421b2d2626cea30549579433816d7814790f40d5a12d9609db1be8224b2073aedcef986c0f5a039dade364e4acb4c08d484484d8eb531bfbfa7f0113d1e7f18fa5a345e6358183c08511a8a1ad6068a8da10759607c75b8617c3a1630c25579292487b19420e92c744c4032f9e8a0e3e0b608a257520ed574a03a7e07b1205c7109186cca8dc3f4b3be8279da30b51308a9a003c976bb916a48b2f8f9e6ea1cdd88504c7418c8f00ff4ad0678acdd15e39a9bc8e5b68fcca2da478771a94d207051d25dcffee2afaa87d958db50c3ba1b645ad64feba53c79f40db6dc6ce42a435ebda309b37aef0878e65bec9130c8a6d63278a3d0105da19400942ee669054c003cb22cb76c1227c252bb89f14552b6caa3087e3ce24ed578b4410abbbeb1f546c7fb711a4484f286f0b5bbb36efec503b85737832fdb6eaffe361f208df26d951c0f706350dd90baf77b426eabdb8f1e9d26580b08548d0e58bf9b106fdaccdbd5aaf6ae6a084bdbd13c35a42cc9d613f867425ff7c99b1aca2183486e4f8d3b362d7cad2811ab0de5f473d48c1b700ed76401ed5e628fcaf7e02147a8a53f5f2b9121e3df84dec01e942ddecaab18cd181f160963e8d593c6b6300e43dd5d188a2779fc18302750594c01b3c26e4beb3da3986a8db35c5cb932726497eb93479c2ae29e41831f888d36e738346ddc548b8e5e6d540aa587b2c2f43fcff2b421924eeeb2766cdbe37117396e528613ba17b7cd5956a7f14195cf0e7634580a7bec350d5ef8967bdb8b8970cc75db6a3844988079a5a8122bb5c6d81b74921f6c67217ab6134c4f4d377da58bda1839c97de3935dc999ef67c28d48fcc9c174eab0a17867ae5ed0e92e618b81007f02a13a2aab76daa48466a216809a6f3b4d3bb2c85ff02107c4b5c102589b2457cc8a9598ad73611d836a64446700e47b8cf9301e710dfb6dfb1c6584dd0b558792f19b002ed8e3680d6bbfa66f863d05deabb98880f28d06d054fb46fff6753abfd2703d2331a9ff39adb2b8523124179515f2120fcf17222d405d62240ccff2310f46c4a68779862e46862cadb069a8c726fe7dd3a27348e281f2975dd4fb721c3b698368512d26a6c1fa7b4d197ed103dbf0332f79c327ac3b808f89350282db7b511d3f46ed5bf4a42cdd1bdbd43dacda11dadc2f6b946fdc4f68fc67f0a22901cba66388707fcc38c4553c4a607e53f610886e9358d69ad1bdba985a39ebc1e37cfa7e8b309d695364be425d4b305637599b705b4039e865eb4b7fe62c4f381b32ff0db64725455ee1bb21231ba060046cf685b4f5ea3b7d10c22d629ab8859d29e293b560aa2144b150d1e484f009a09319fefa53d057f38e3e3ad64441dd4b4d6ec9b3d2d6d298e4f858d88ebb46ca320564b569d0bc1b4c01a553f226611c1335133b84a41adbcae70ebfb237b6b87df042cf1cf0e3d2dd38c345b6f36fb32f383368e855b3addfb6c42ea00a0efb3df0e98b54bfef1ce1cf50c0528552013d31e116fdee9c6016b24e8f9b9cd2474a1839f7556ed911d956e0de183f096d5cc67ffaa3077f34771b179bd6d2efa3687fc7ab42c534f801f5a340985a44b9648c7eff11bf4b154563b7e019c845a9a11cfaf4ecfd7b569b098e4e14c4185b3291a09308a96080cd0d46a2ede6342672f6c45d1127b7390aaa943c681acb84e4e330471c9910cfbbf957dde3ce3694386aebbbe98cab83f7d5cfca5d2c9312ffa31a51cce4173acd6a9e0f09aafd36771bbcbd2d74472d90997bfa47e3da32d7c7cadd26d312fcc724e2c232f37e38a39bdc652cab46f7555765fb508f7e0393d233d51527afcbc0e6fd0da198167c76bdfb82dcb40aede9362f449f06e14337ea9d2ab08ba0f33a37790cff8b9db51b1ffac1b8b2ccf49172b34cd907316ec31fd75681e90d15a6a0120ede08552848a14a0218a42055fa463fdc6bba6f060b04a529c8187c3e02100a6b461f381e2fef625e06a92d40fdda7372fb4bc0b41835afe9942b624ea7a442c5c5659c5355cab5b1a11697b751f8ee5763d374f2b5d0bf57144b08107f5185ba9cbaa0c3ce2d4d7ab52a082bb18017ea25330045270da1f5cdbc11625854e51301fe4a9f455b829a64552888080cf3c975a6ba342168ea8c3c77428c02afd71df9da7eff37484c5f3b8a4a27c8f4ab85a02322c215976dcaf6ba13c92d00ed022d8afc3ae415a23bce67e139c8a1059aff28afa3a03eac90457780434615e0f9571c7ce95d21026d7ea1533a4e427305d293e68c2996b806605e806cc5a6970a6d5e0f34626c1a9dc9b2195f748e659537d50017d122fb200552bbfe8e643a9d7808b094052f022c41d52e4ece91c24a9f8f3ac48966b1404d2fb21c10d4c0cdb530c1a52c08060086caf8341b8ca195b2b45beb03aa927e2337a87559f51955c13b01f9949e90ef3fe781fded90813a34740a2ad7402a4658efc4e6a2230e991a5a7fb8dc892d12b4cf1e211007ddcb1f0b7bec10776b61e864210acdaaa8c513c94c132b3c1e12b3f7a43fc0008eb3435880a714893a47e9003519103e475180b3a48a649f6c14d1b497892a2cf5b29289258f363a41eacb8a109a7bb34885d23ea36c1a5a12a8f71268cfa048bdf44f47ab92a350a0ad2a587f0c570252c29856ccae89d334c2a09ce628ba5ed16093d8e72a07f55a5fe67c04589727b7425910d3a28a4bbdac4442a9a71d4d20f9672308e6bd2c4ab1accf90262a7b35918918611f945285ca590c4bbf9a26a4fcace788a862dc7d90a228c507d3a020611a0415b8a8b087bbbf2c96777819931c77ef093e1e22f75f1a54fa24e5585446a3ce2bc5aab84b2b23422bf07b00d243c90d0185ab899145e421a529dd51c23605e614748b72679886f7fffcc102c4fcda1a38f4cabb52ff34930e247d0969956e0375ce70ac0256c04d7cbe2d5a0720b0e15c1727c0c65fce7b367a48f8e92928fc6b693620fec84f1817cac87f2d1c1a8cb2777bf329e4d16603a965b725c1b0b4b5c40f54a6cc24b3ae7f24db8562aaf407b7aef81268900004ee353194bcac075487d85f0c079ceb607bce9f8cd23ffce599f0493494d1162708f0b40fafc1e5ced662256810530b74d9d14e7f5c5a5a9278e97a016a73db12b038da1a5fb3a1ed497459bd129b6e973e50a74e165b6ee64bda9ad45356f1ea813c63e2a3366613452962efc3c512e8f3715e1db324ccfd425980baac216fdf56642c8b4d27d0d41d680b88eecbba15ce208d418077074e82fc924eb7a18dd8308caaa4800340558c299845836ac0b3670257da1cb96e1c5a2cf16ac3ddafb16280ad0c40a6c9d05ef982b48289f3411209b280fd73c44a0b102265b987bd8a684bdbb4e6a26772106b3be3f644c6890dbadb9c45c85f24842222f451b570fa870a0af92daff7344a7c773af4db4538a03a2dbe26772652a914c4bc1dbbddd63dcd6e921fcb704488665205d4ef9005ff40cfac60026f3407bc672d356502a55d53fabd7036a9a154e69c52d8a5ad4b81d3a07652861db033dedb81cb74a3f675e0ee49f9298a20a55d2d332526d2541c740122b7710e162d490f8561db7a5bb6566990932292b5f6cc08eb92a11992c682aa037aef631d1870a9552c6e4bce9604aa410cbd3df58d5bf65308e5d25bee97737b7eafcae301e3e464bba3461eb0d2646992d96da3af6386186b79f33148274b279cb71b1bc55f207ce0ad1c2e8ff52bedddfcb01591fa414eb94d67b16140708aebe2fbec07195ece25a891d23b32f550901b367cca9a861aa374fc8fb8b80a8fa1a30dc5196e37dfe5e0bf91f39902cbab60db767420cdc040188c30bcd31c20d3e9bb3036a5c05d08a4f11fca3862be708e15113b82d52e6998fbf087196e79c4967ad97be2b8131cce5724559751c29d2ba0d744de3a597e25f7827b5b537135a7830ab4e9b910a848b1d1ff573b5aa371c4206c1e0e47a9784117cd790e0dcfe5c0db803e270bd199af3be5b73c61b7c041376cf4c67377a870231e3e7baeaca9fee0d85424af057623bf0084154c8f22c84d89d7607a1a8acca27b6252c6c5deed8ceedb5d5d4a684da4c24f7af40d772ce9be1472bc12754bc5915a016cf002020769e1d7d09b4e9bf8650b3a3158760e7da4b90d8b0195d8f383d3fbfd1940512e410f212221cb4bd8d024a2010c9405b78b7f73c202c872c8d32c1863614707741d27525d630da503ced56b591a7c6ef2c3a2a5b49a8686fa712df0dbda603f4807c9a997df102638c0d7a5daabbc6e6da0b36ed9d95059994509656b0109b109b3ac2b57c178ce3e2c034203964c697607f110f070b54e4a9a557b192078739a5a25ed7c5aa490c7439590c3242e0de1a24b01c1836c89d3cb2746dfb2020ac7fa5eaed6150efddd537591a01b9b0619c019d4fbabf09e4f4ad376b657052e3e6fd0695176b5c45d0be0ea67ddd01c2b087fe497737852fb88face464bc29a56914b1e7def6b7a828752fba244749cfa2ca4fd65348acef86215491cddca9858b44119e84949652512cb8c6dc4f4dd140378ce25863b83f1c9f3aaca6ac06cd8d1640bacd371416b1bee971d96649c509a4d8a3a999d29c989ba173953fd6f6176567f3137a3610b88b80db0b0d909e3caae405e5613be0d8ea3d3a5cc67aed517a37d8fd70b3a0204223970b1fead6b41830c556e4a9a1166a18eddeade8971beed0a08a9efbc753c323dbc9f596068960670257f95a30413474574a5f702df5683d7ecfa03e88b44395b14ed04488c205b7d7e245b1f38cd5aaae711bce435311ff08750c709e2ab0367846db3e2f0acae30d1720c4a71612146e225ac0de8b26f898c784095387695daa45911041e67f0869259afaf227e98599c382bd45b8018ef97442154d456f8d171f84b132dc99899cb85ba865356a36ba1c7c8f89783494b012c2a77812006c2342dedd1187c92c6d2ad46aca13d5271b234727f82893b6ae30bbcac1e7d95c01f727102f345056c5084cc6a09d1f8b4c492486f32549519c0fd6e1b21432649fe5c2701c6ecf1f72259239087f8d74e18571adc562393ffdd215510ff9564c2bda7cbc41796c5f728de86bed70feb7ac2992142219b72de49dbfa7899c81fb819ba1db30c16a61b897a29578b7cd41d389442c854b99e215cac9b8c812bd605459befd8b9eaf1772def3be835524b7d29a6758cfe0e8b1dabe2d0cb7c6239273df64b2fdc183707f9c154992c6b20c2080d0e7186c868041f71b1aff13a4783ab47db5db976b4bc4c1c4ed9ada04efb300fc9a021f690ea73d59794685b2cf7edeb6cc64745536450a7fc56747c991550a876d7c858bb31318dad14cee42ff9a826ba0ad92d9db4ff3a46c2ce53db00a45c01c93917750e54030d701b7613c5a7802bf993b716360b8447646a805384e05624214e2ea61d452e027d8c47cadb5efcf6b551b29c4e61490f2468e5683b5c3522f4465b2fe6639e7abfb0cc6a6789b9dff84b20d20cef687001d5194da45e5f8607ff9a31b70c17cc9bedfd6e5cbdf9230892cd6adc9d402198c25d503be2fdadcdcaed5c78fd4adce8b794f9004f3cfad7d7179e3f2ee938e831710004671aa62dea5dc8fc5124c18107413d31b5e28befb9388f532d435369cd1b5043465c388c33ead692e205b5c4c523e5c48efb8dfdf510aafeea96049b839a5a291c4301df5efac8895d2ec3a0d452b84f685d5a207d0c78638d2302296b005e64a101cca57db8ea9bfcdc1fcf036a73c5113142c64266e3d1fd760e30d27fccb763c958eb963df5271327327d6abb867a4a372fc5ff272a6c7dd6f20a205a3c5e06a85af30915ac22aad03b6495511a22f3c5286f16d6b79239e2433aa0e3d824b443bcf42f08606d8bf6194005ff1c37cc0275826e8019bc3a752a99cd6931d15c4ac69069a383fc4bcb34a431666092646960d17201432e94e1c9c760b43853fff61d3f86ef6548070bf8f3751b5e6b1d0984b1ae13fcf67708208a0dc8b7e2135dbd0010d4975f9a309307ac901fa475efeeddf4fd381debb656883e97515e21fa395aec1637fb1b4ce20841d6ade28863da672bbd15a5cef9e8b2504a7aae939e96abd80aefea2124dac15c255be7fd430946f7b5c375913f8574b721fb6fe415700e335e1112a74a25a5036882a97cdc12970d359a3436a5bef7f924c32dc50703aaa5d1a5fccebe8d07a0b7b46f09455dea72af2122d692c13faf2062a577bddc72b36d360750f141fc7aa709185142fdf7d06dca39a5497313a758d3aa84f6db12bb83c9c60d6a33a85c80e04dc0804125499db9c1e10e2b9ca46716c2087c2bdfa3a04aa739954480da2095d7b6b8e4dedec9a01ee1aa06a89faff6395cf58675498ba7a0e85c292399da259614090916a6761f04c52f0507a59d605ba54b05cc19bbb42e8ccf9bd0162958d941f10f295a92c3942d9ac989a4577247969736383429a4a0c2ce15993559e4c32fdecca60f96cde775b3a83bf43233e7ebe6d2f896b11426370718815e90b3b4fb386ac2749b70ffe53ddaea4214d34708574efbfd411d3391d8fe64d6c551ae474e9326c6af10fd9138a1cb35193ebc8622570e41990067950f0de4556044ce9b1c4d90ac04cad799d204558654ed1a57d33496ac2d45388f3916cb2bcde8d243c806be53aa5f35fe57f485822256ff122b0912c2c824483884192ccdb9ed9b058788f7dcfd1bdfdf9b63dda3899bcc3f01ee3b25503b2685da0bf7e4dd82eaa93bd5da08a34fe033e4a47a826bb0bb47263a6ffe48c56b21836da64ac9ccbafce7a6b0bbee1ffb1457c7c4d9a66254aa99fd76425c42805c327ce6f76925e8f5d1e7ac41989e9a6a80311b5c9673a65cb10bc6339491939406ed004a49164adb56c0d0533cdcac03b08d849a8be35f178358576c3c8d40bbc412a66b65caee2ef7f9330f135e149f42ff1af50bb89aa38a51040049d02a933932d1d7ee19c821dda844c79ef6a10855144f5193102709f651d8756f9bf21f267d5d730ad73ff3a3cad5be0629e04b815f8baa4b132043c3425cdf7db6aab9df61edabe48f17f53a27b4b5d00b3e5fae524021e63a56531bc4d1384d2840b896688095d517895886a6dc0c4dbc718fe830f31cf8437fe9a63426a9d3c4a081ce3bc63aaf57884f7642135ba40de1c7ead84ae262a5e708f61d826c6b090006853b3c79c48b4f0dcddcb129547dc78430225b1206d2264dcc4d14eef59e927f6ffda3baa912d631720a47001c0f8469f27205e4252c41778e8836b6102352a7e012a19033179be720e88bb6044a0e416e46447e74c31131aa7fe58ca1507b3407723a6a3ee57f349d24c30199c6d11da60b7c34448eee3be9747ac74e53a13ea386e504cf2aa4b32252c6675a4941cf33fb1c6376d50c3943619293eda0d7cce543a6275b3367d6c2c6a42b364e363a121dd998df19e470e02b725fb430b04d8742ed2e6ded5054ebcca810153b08c6f33fda508884e52e98df56c7d63cab0b142a5b527c339cf5d15330d2eb58a5c034440d4d47d9cde98d08fc60cdadf6e40898150a28c90021d0adbe9be394cbcb34234b751a105bb8c766d9de2d7ee8df06c0e455dd1f4b0d5fbe88ff13654b3e235116c730fac7d92bf85f8422198e348230690abb33ffbb7d5d0dfd2371cdf78861767c6bcc9665b59e8861209d96e240a2ac9d0b7e4d2d9cbb7ce9d62c0768889d9ac47cb24fbf4a13d5087d9df2fe1aebf65511eae29c8ca18f050853af294fef6d07042750cf158f73f3885e9397bf3e219abb61376506e733a77378e4de8b531696b941f43317eb362b8d13844c6337eaa31c2bc1a0fa7d998335c919925ac4db95b836a1006bba453422c341c9d4194450d2a593557e0d554ae7258df17bb55b9c762a3136a329cac2244e48e66e47f35636965c2ded5480a0f258ba3bc1bd6c8c260c88b8211b0502fef1cb61d1a04a845141c82e5802d08bc67bd45b5bc2795fc63b764bb8731ba0a018eff70eb5ef20118264afd64728f611df8517dfe322738e820fb655eccbea4c470a839922cf2913783e8eb2d0c1709b2e40d79191272f7fef02e2f113ac0f888bf03f8e30355d6894aca48cba0ff4972e105a2f5dd8e19fc025c54d2f97d3656a0c5086fed3ab8cc8e1af0e669fecd1afa00124745fc931259f22bedeabf5602848fe7142c7f064813d162f3e1f02c7c992939d4f6ee0f30a593b554b765d58bf8919594b0e4dd82579db2624a0e2e6b8012d414a1052a0bab973fb8b84911fc6d13a9a6db871fd9c7f3622ab811d343bb0628205191e013b3a40915b0c7e871a720cf53a6082d93e4d8810ec5bd8b115ba4e245038f6204f1455a2dba173809a5a34f5bd2db5a0f451d309211588409c45fee7426dedaa2b98c8994bf984a8f663973b40b5d94feb4007670b21c5a40932349b300df0db3c697c31774119ea29d665ec31157d6a5847f1618e4171014046efc2ec5caaa2a4004bcfebe73d7428d2d888691e244de2df5aed7a5da82cd10019494b53ee8ab7d48a60b83a8661208afc80960e2d6e9141d6a9b4fac460fbb5cc182ad40f2e90bdae1ebbb05df3c15412ef56730c401ee38b5a6c8b6ae6aafcd7f9aef4f3e370e6d5f0d294a4810608f5c41e3c557fb735ad7a532e588c4ff04f24648850d9eb14da2aa2f836faa0bd5c479cb45a1f9e22d66a8231fd8e216f4a83a039eb0195d26b90bc338335d9ec56719066770bbc5f9526f33f5ac6029a1491ff1c64cf18a8a2609e881780562ff622f2b7e89665a9e4aa2f087ada6f59fe7aa0bc3b731cb2f6c386b352c94621b9781c016826941d0b0931d4a3b70f5be96e68675aee91d32c6b9aaec5dafd2386f4f8ebf3fca456401cbc13c4e3bc840b750483fbd6065a512fa20f1b09fba8724c3b7b012d41bd43c5ba54e1235842b0d76ca822ab66f8d3edc99507809b2e8ceb465e179ca46104fde0e28453765864202b735166cde58255905c03ba5687388818cf76c5c8fbf31251cd2e67242967d9b35e20f09289c0550f956d4e21f523fc2e109623c71e6fb0318290e100bf0316e348e0bdf4149bd8a277a661122cac82706df9b1a7cd8e9d84efd54d6e4654c1f8636a67d6b178e0c06642a8a511db4d460ec89b76de62a5b914d75f85c7819ac1a466be6a480516bd844400147b701f93ea17bb627a2e3f42a7bfe7ea76c7f5463691d901003ec0f4a5f82774aa2e0b87e23531d5defd209a0fc155816dcd41995d0cf0d982719b1088898c42c52a2a9c118994790583290595a01c40cbb4f5c0d9437dbf22f7a61d8a22306a8a072950d3feb3128792811dc31e27d8854e7dd54d02479553163b6fea32851a9626626b55aaed8abd4e5f084269a8d228384099dc038d8cb024f890a4c54416512591f9c6808c682258def30352f7a889365c8d161269d3f9791df0494c345eff4d0d3abc20d1ef52476afc682f5839cf6386a81daaf6471d57a79525dc08b03fe82c7e3e7f957687f0bb2c5becf185b6e50d0b9dcbbca303124111e590779d43c8cb046211fcadf5f7957e2bb6ac8444c61da195d8aaa37bf916fb5f02a4b1ac0556f0af078104830e66de1d06c5e08c792c60eae2ae88c9901d8ed170fe3778a038ce11f68d11a9d1428bbed2180aa73a5755444231358055d9cd006572f31cb1d9be329046e38d28b0cfb7390a2c5bebe60fff4ed61e39d584e0ce8cff9dcaf711b67ddd95c0083440ed25da74cbe51a427799c48e90f45924a18e9df4f0bcd0a0d71b789268a84f9e8f5fd0010fe3a68a8ec303c40d7bd5d13906d460de30d49f01a670eba30a5578db870762bf6752febb1625a02f0c15615ad828d33ffc93160658a08a17ebc67fe54318bd48ce5e77d9801b8c525f734d765eee897f08992d8703695d9783e5a24f4bef45fe53a81a9da347fb1dc7093ecea6b4ba01093e228db4d0daf0a851cdf4d92d23f34fddf6bfdd07657910c39fc357d8593c2941542b8ef6b64bf62863b32897c9df26a35cbb51a5e1d517249d683a91c9b60150f2b2890573598669cc614e83b93460c26e3f001598416c56a9baf359758514e52eafab3710b513133872c18f148961179c28155df3bf68140d3d0a501d38df95e93a157353bda84dd9604810d1a09f5a7c5a558a46457a4119785be9f9e180da843747266bf46b199d97bbff93945ea2b3bd6a4465a073a8026b3ddd703ec7de066753e9d22a0889924cf8916c88ebcce12550501ffac0cec2ec8c012dc05546075cba05ef79116023df3185e9e76d15318519461b7a42ac5766c84942f47c9aff97905019a175268273fe80bd64b21417f48b6492f6a0240c8ede951193cedee0e9c21a79ad2f066b25e2317655e812082173bd572010c884a481a7904e11cdd1f6dc821890dd963facacff07efce5ced67dd25a54ab43808d0bcc493ad41d0bd1105dc6d785d4b7b6aa40ca16cd9ac78814a52e711554aa078ec078ccd9980bd84a1c2fe01442dce046412ba020443112bbd67f5ed6063f3935df7c8ea24d746bcee3ed8433893fbc2f6088100725d75f8365aff40cfa8a24e0dafe5ccfb1df186a922fc305c059c34a24739bf00b8000bbd706a8ce9b56a83655a5a50459a872a20b2e9c86bf795f46143a9a5a5cfd40b4c90fc02af7be1c05d1f0e6c714439e3f5a1b193c1b7ae0f065f3155bcf0819170a26e44c37c67d2875f2f9eeccc1ccee68ae468b4ed47743c36580492ec0b0b273fc8e6cc339ec2f2ead20bdcd68aa9d33c44f1beacbe661956546e7ff97690e3824cac5f0d0e61acfc90c3f0f35c3a387bca9558c9e94fb05709a528647790454226a5ec65c7a6c7a50d6bf204af0ce463b5198784a580fffd1f20eed9035008625519198733c2b7709560b1dd967a8211280bde8e83ca7b1a2f298699049485594dda878da701d0787cd788494338d7b040b30a41c6571750ae4b0bae959b011462d54eeec3d70abaa5bb5d69613fdb6451322b84f73e818a14d8e90af632ffc7d55295e594e6daf98592f437e1d981f035dc76593eb904d357582bd585e866127d27c4a1ba82be8fd9603dfb53e40a0e026f2d8b6a44126d972bfc9f823e2ef0285f6390e19e36c60e571d1b5c29f7e154413d31ec7a32f7001c95a5b9e280a78250ed71f6cd0024263029b93e27594fa4f8a6589a9a518a35c13e15f3432d9e2d023b1899f2ebbfc09158613db7bfa4805de1c616c61331fe4088616db28fcfcba31055854d120f2c192290846cf6198826f01577f90c8672fea01d6f43af22b7941d98da7f4dd4816e6156af7b2f171bcebec41b2ca10508dfd8802a48aca93f120722b08c0a5f09a9e75ee2dd9dba2cd0c84251f231661540afa64c0415f6c4a4e1c85ebc7f1a2dab020561cf44250b45416331e07e57860a3023f6943f7087726b6e9bb9c44ef243af021f035fc0851d74f677bea4163167be986372ec7d09d50a94666ee08f8715cb15776abb57ac507b265273ffa858c7bbd467feae79ac6d97640b1235d10dbca9e2145abd2b1564c1da17f382654bda569f731b93b8c4029233e4424a936acc797c39032098a12d0250bdcd2c962358671a0190cad2bb69f564f5d357cbd1864ee3c51e33d4e5d2860e560c3b8a4864b81792c388b2a0808c330c0ac089d0f2f916959b32657d2db17698f01efc57bc0abd69992736a0a9e980557d365a5ebad73b08c3469b0e95708c0f33d6801e5787c6546cdb156bfbe78f0ddc32e10e061480c0241b2ab4c16b74f51b7fd609ed90bd5b80d9e85751036d44545974917f59f604a7ea2c6c39a5058c30a25248cc4c6ca905e2c4b684df4d0564a89e3a37256a73969170875b6fcb1a4f3e53a3dc2550cf1f7529f897d2632e528e10915ef78f5345b4f686881e4ba1c0dee5bb3b87213aaedae21f8a3de02c49a504d1bde2be54c153166c3541a0910ce9ff102e145b2d9e5296640fb3a784798da00070be69a113800f1dc2892964e5df46c7c8e09bdca66074a0bf99b7ceed49c850a81b428254218e79d342bafe40487d21056aa556955a5901329d354b92406d5c0b8469f523ffe66ad0e17a0e2084bbaec6d6a0cedcc963e4d5e66622a74f30a94a15e8e1a0f78b44097deeaebb3faf86e3eca131856029aee07c1b9d31c6c076343c3994766eaa4739ac68bc21f942846315700d1688df26b3c9a68ec301ca001ba56d05f401c9a859fd42aa0da1400cb9056d9d60aee4384dc0fc69e49e9f8d5ce09f57d6a0fa893a7a783059de0cb3ca7294ec6a55cf30ece969ca765435ea6770fa87ded971125abe15234bca4c0389d0824adc8d627b5bf4072b6fb08c1005d4acd946c0f315bb49dbc34922ae1fb741ad024e6a17146a0aeb04a0aa2223072d218081ae14c8b64ac9d8f122c4455475b8bd224c8bfe2d2bfd022436863a01824947fc6f1d8abf1c64e8bef2e469cea7e05012780c9515fb6e4e50c7c7bb7193066741d4cc13414d07a7af4f6e546697129f3fb6b48b34066d1a709ff2d9a6dd66956d38dee648b903bc884f0397141ab41a8d4d10ee02bf4b89bfe263c6115a65fdf19e822ee9ff0f1aacb2bc190330104a425873b7434f4356d372aff070630c3788da38837cc84db9236e54f4f092b3192492678d4e3dbf677ce46bf73777b1dc684dca9dce69a4e91973e483f74750750cfb06dc65e142a6e33ab1636481d87b60f068c0ac5481ab2fde8c051b1e4034e05044813ae9f4ad1b6ef240a80a6dee611462c47c2a0277c8726dc65abbb95c0bd88c43ba10a86605783620b58cb04fc4d1cc740a398415e6de4f4d5b6dd375fdc85d29efe35af4fba5d59e61a8d4176ef3e48aeb71a6de21ed14e9d0bf40d7a519becf145edcee28a3bcb0ffec0dc3607844db7e83d86aa15b8174c4e2aeede525b6864446a1a50f24285c77efd9e6e8b3e5ba78003fe44003caf2b5d1e2222a565884ddb616e2e2df0dc24cf21fcfb2d2152c0c621399d99d1052716beb51617e350c66ccb9ebc864275687028f70847e1f024dbc252555028322e6a077b31d1e5cee5d81e20885249dc00a63d8bc08396c6e1e700a20724a0dc1733250741952617e68ac9722b054c4707639417e19925a1d3935f75c432754e511a2045fb537d23e94d20032945dd25512b7f4005c8f201c79949443a9802e3dc43f04cccebb0747a00a88a6a936c131c98e879b9781b24bc579eb5874b8c2a920258bcd8c367a486f16bacb53f50f9402814afef52ea5b4894b18a220e812cf4226bbc7ef4d5d22261b36c269eef404825fdd20384653d61b98cd5ad9220cd4263c376b50a8f6caf5acf84781e10d5053ab65de06e398692cc836e292b5864e12ad4c6cdb25a6eb9f89e514c13c6039e44b9a5412f5440d5d5e59605fb51fd8745bde512b14b5f465b7e0380cea0eb646a29242d5db4dcdbc8322971bc290fc4c6878f92cc8100d1f4b21c9ab22345b54bed3309f2dc2587b22600b925deb2ea54992dac76cee3640f322959dc3676c6eb907e2770708bfadf86350cf89ecdc56ee2873096c16a5de49fd08c8b9b4ce607220f3eb6f1fad8495da0b2758240baecca8d1690f5013395be115ac4c52461484ccdc0214e970682db908c67f0a54808aa0421dd5b54c70c5e0bcd21f82ead93dbddefc7b5f2a7e3a034ae3cbc21d9aaaae5afba54e2046d7b440e6df7f01fc012a65d2ad5923944203b2f1c686b20680e2a10c32dd504027a11680940383fed4564eea6c8edd988724392828831ff8655ab928c4455f802b7831d2498fc55a04d411c11789271434d8853ada5f662aa0f017e258646a925b98ffc4d304695076f69e8875ff88c735e259d0e92f58d94a7af33326caadf7ead1db90fe10260127e9323785ca3183680c916e28f9ec14d304760f1a6c4eb715e01b8e7867403859e8c6245da1f929bd2370850a08a1e841ba0bb7b762f621826974279d915ff56a064bcc7ae5bd76348383df19b61308a7d0fa3611f3244ffc7fda9920c921ef5fa123798319112ce3b21b269b6aed6bef63d3a6fcc5a34201cfad6673ecac0c0c3272ccc714ecc4d0d1faad58174af1b90722784b6441a14916dac92aaa441639dc1dce4685e22e6a71078510d87037530680f035f8e3323857555690fa68b3106079917771bedfb515725bad50686c142f3233ff19a8c020aada3178cd07e2d824d9897ac743a3de5fc64626e3490d241b50e1651409e6d7a1a1bb9047ad5fe8d7b0dc7831f023cc085af6f07e4007f4dabd97900c3ae328134a527602d3cc7ee3d1c405deec6981ae46511dd73997b1a2e21aab9704166ac684d773475c855404525638fdd7bc9f6ccbc2d01e86012b817abba60f0ee8a607165636903bed7be8fce32b2cea3bf1571305dad3cebf4a3d567b19980f093a6538285d56049a709db1ad3d29184962fe5d045f37e704c8f75a331a544dd9b06aae12093041ea302e2e7b504c8b88d521618881c58c9150c87c2794d7962279223e1c1bc828ca2b0fcbf92a0afa62ed68b98f80c5e9aeb7936aab445b795e1c7cb129d06ac012bc3b475d755bb369149b6cf1f3a59dbc791632cd7ae1478497be3b0482877d11c69ec81bec07a962a4a23d265a55d6bad7e214a7b48375c63210067a6a2c67ccfa2c2fd7712a4070cfc50729a5003e854ce993489c54dd0ba367550555462613a177921417972cd143c016ff5648222df2e18ea4a74612775dd4060dc2d8c36814c262eefe82428c15f2ce33f8d31594d1ab3d64eb55a28c6162994e3418fadeb6548ea77dce1083bb4b5a6146b2b76df3c7e7271515d512311c3626f40abd5736b22f3ede4e91dc19023f3d2b6f649598aeb87c9afd86eb51c084a9e19d4d7a5b80bb7041ccb38b27b4e7db5e65e5a3d2d28c34f03f7edcd97cab503e524888a410d3a4f6e33bb27d9135d0fbe7f28a20b17c03ba55d043c057a4101dd79565d9169487743d9d681870df742d1532a538a5293c98d121842961e286471185ade9268dcdc6ebf7e2013717f37d286f3e02cf1b82c9a3794f932ee93184c80f9e00bc4364b9deed645675f6b903cf2f4211502d0a2f67c915c91dd5beeb41c99694332be3cc49f76c74b477ea3b7e39c899fce682eef99d3668276fee85c113123eb607d4c183876b36c8ab77600c1a858295e5bc44f463ffb354e463473db73626644a20e97ee09dc5a860247ede93034aa1a8a6f13d746840257e80b37128e2b2677267e2dd68f2f3a1c66b6e5bd0d97df2e1db84d2f72cd158dc009466dddbc45291c5117e6a739eb09f348304907fbd0d577663f76b427ab79e23e051bcf42584eb24358a84af78b22098b9ae4f4b0879e82f966b1a4177763ce0c46f919b4b13bf33a5367489ca7fb460a1aefe2e8f68e9cde0628dcd50139f39f914a501c595099aecccc4e967c7217510b6580d50afcfa0ae75f9a211ff7adb861990c9c7f1ad995cc5e3091fa54aa788e32d37132028e4390d2d6ec8548f3b53ed6a239008a94eb0630917a9aa58e2dae3a03ab5d84ef81388a14031fa8493b53a30141f2f0e71f2015bceb846cd2bc235f2939e86edd290676951de775c32390269fb26d2f5de71da70da57ff2a1641fe28d9d2e3fc7d437ad14d6f5a078192aa23a729f23fb3cd560267ef40a0805996414b015efb94784e91879642141c9863762a08243a5e10e3b08a3f9fafb7824049ae0033bf8cf8af7b00e1210288cd902b0134cc1edca2e1d37fb462665bfecb7fb75f7d8f5d232474459e085a4005a28d66b9ff3b9e6885f1c59b18c256d5e5d9bc8b0be60e1226f3823de446f84c9ec43e14272313b8c353b42a0b4c64d4feee1d2e0f4af0e7c1920ecf3cb491c20168b10936758b54e019bd61e8096eb45c928d46984908220d7feb50ec2c92d819dce80e730dda5470c90f1e7fb2f36dc4060dd16978c06da10ac847ca8fc91eb122ba8543638894a88cbcccda5d11b27c6bc45836db7f2e84627e96c577dc1f049e9dbc15324eb03cab178467aabb779ad7180818033a38d9a77f867e4286de0629204af4330dd89841385678002094efb3139d3a3532b401416b210fa46a7925bdfa3b3293f7424f37848922513cd169adc32dd5d6dc9cc386d1d231056812d809f846e30383533ab306f5491d7bee821f8ebd91802724d85f545e024df308e1cca27a2ce7b0d3f93c8d9c2cbfa3ce4b4210f320db58b411c05484f6c481373f46c24740b06b9e132d523f7004af81c89f838619c848d2007bea0d96f03a9d6fc84079356a9b468043315c9bf70f61d59b87ea819d97a537bd9b2d7dfe499cd18ddef0fe299bc55b311691378fdc86b148eeb32cf09c38a45c4df5c8599bc08add4e764ecb36a1c9389fc294747f9f91fd255180b31a38545558221d1653f2453a0af8aa5fc9230a728509a2dda2c783c9dfae5788df5cbb8fe4a8b0611097a60519abf19420006e1e493c81a6be9a5f042eeaeb711a442169135c74cb0c2323252668965925868150ab807ba25d9c612e404ab775f079c913bf99267c764abf0e15893468fc43b48f632a9f54a47674de8936c92a892ac1a985651f7086e63f0a1cbd467cff8b43ac0c1ac5b4b2dd52f87a356e492083409cb94357e8f8de15cd3181377259c0cff976c8302fd879cb81ec98476f0a7b84b791108510ac7ef5c54edf678f3e8062b6d831bed6c3151c5820b0a52ce28854260ada5bb2f07fa1783d1b126f00ed223eb03a72c3edf40fa6f5033da1c13cbdb34002027ca3b8faa4a4ae9611ce958ac0a6e6c0425559c69ff18a448dd5842d764ee856171bd30f2bd7a4ec4a5e9d3b5412fdef2fa6d040f698e71a74dd9aed635034b537300705e0d14cc586d3cf12f4981724c8ec86f69b576a7b1ddd6dbae87c247e32ce880076f55bac86ba66265b4519056538e5e67da507829cb2b0a1301d533ccf8a4c0296489d14d1b5c2d5097f385e282773d124efcd35edd579b5dfc932eda3da8459c226eda59c2d70aed02b2654beb735cb5883b489198d6f94594bc0bf00e823f4407569772327dccabe2a132834995fc86f0980b3eabcd12ba23b55f4b8d66d3313751e15b8be13f56e719bcfa34aac5f1176b11fe92da451cd75c063bad783064db0adc96adee0bd94dfd71039289a540c47baf8f74f3b49d978ededed86dec87f9b396804d626f92596a6ea150d074d8ca566307ad0dc8fd9a18876e09840ac2b7cb29e97fbaa60f1e90a8cf4fa9e58cf57faf863a69da09ade76ce41afa9934e473abc7435eaf4b3b7f89139bf00750f41b716bd5df27a99791479402f6fad4356e60bd0900a65d4a885ac1c188002f1d0f861d5a5646a468d7b626069b551656ee46b134445234d88c63d8be945f851ddf2cca405166d5d40940a098ea900e51283f370afd049fbba90f514a41c74a59969f6349a49136e98f3aa2d0b808d4a09943d2cfc9f8692519b0cae0ea79fa158070863473f691bbdf16d6d52f04af8fbcd9c6cdee746ecfa31246211dba8cf9809602b6f8d2fb91e90051e81b211f0cc2cf923cfc0d33ae0fda2a7db94c2b22955510183515c8a314ad743aad3bdc8e00439db2e521dae3ce9f0f98bc4e5e5b03e84392fa5362ac1bcecf83ac8120942e557a08efe410efa18caab41011917313b90c08690cd24126f66d51d10ac4263ea1cdbc0adc0826b4ffc06510fd7403b54f5127457c9b1b97df0591c6286ef941b346051e7620c9420c2393de07c2c4271dd507b57d395ed3c649c14fc57908aa10a7dd19a810112ee0ba4519dd6d2c97233638699ea02c1dde3847e338e80fb823997420c7341174fae0a4c8cc35288c29739ece8d67c5a2a5088ecd7e358c86823caa7687c744264b942222c820e728743e9a3b78db07cef8dd1a130292403cf1d1e442dba8d332ac1108d545e901e44e245ca10d6277f35062ed5ede106b0d02fce4cbe85ae5e64578f0017ff9a0258d5a9041e798e6ad5afa2ff3f7bd447b2c301af7b407d68f6db885600055a65492cb64f2a71f2f72d8352973a962b30ceb184b75a23d3494e3573885126d68a22fb48edaf628264bb9ac86c580e956397bf22e2425b8b3b4e4b25a3e85520835413fdc7be6e403d405613a9d3a8893648e26fcb794d74a2fe40ce7e1d5b00945a84b8565fda904f681f7fbd19139ee36922df86ae689e5f8d35f8203d5a1687e28056433ccf147fd04d959fd144f704c1dba28d5ba73c1345d5078ab1461a6613f4b6709a6372e697a10a3c75dba924134d73721f3da674b49507b915271dea61683817e4bbfb535f5ec6728309b779024e11aab0aa2750701d133e1e9c9733efc90d69c0ce3f12b20e9f31b78b38fdda51b0a7c48738711cd57adbb182d67460cfc137510deb88e2249d9f04b09e59c2eac8a59f3743a7889df9fd5ff5e9d543e3b5b27c03060e4aa01edddb96dcabf0331f0942931c33a2bd06a8497d2bd28dca5092cfad3ea14bca0c941bb448073e5157a85a9d928ff27cb1c2f422f9450aa56b2ab39ba1a8404c7c05a8c4857f99d12265ebfe660ad727d7ae92943ebb0869004f2c4b52d61bced52119456d7c9aaecea0c37493dcaec3912b860b4f0da8349a08ad1030e651b60dbe3ff94ec0618c1db2b1028f51c735b84161449467f1cc20df208717e8cc26a2d93837da1ebb10e0ed754823300b823589709406c42d2c10b7775f8dee84baba9513dc16955efe5b9ab3ba8751f308bd5e459b0a36923ff0567ea19602e24cf598051002f33a12925e66947129d9fb029a3c1bb27d34495825135cd242448f8869adc5336ba6d2c8c1b26cd485528538345bf731a275d052d475fc3ec50652172f834fdae4a3d17c557c21e8805b89ed370193df438a989b23098d2333ff8a28b4241f56098aa9d3f703d3c429dfd02db18dfea39eaca772c9e404b50cf725c18f9aa5369bb75de6e0c6db431709a2239aee3b99ff4b21ad5bfae72d7b1113728e8cbf7a8ae17c57757dc86a80f840f2011c3c8d91408c350919caf2196459b35c161bca746a65999005310ce1285459753f034c5e6fb75112c48ff811cb0c9759715f6cbfcd876f7bc68fc84a6982a3ae7ff9f55e21a4e55b7b6e4a2b38e5a07112b64cdb18cdb50d2e82ccc06dce9d052b3079fa0a81c5f9efd71ae9fe1b2b19fd949382ae5ac659c31bcced304ddd1e87722668a17a536fd92e820053f6d14639331276ad286b942e72eae5db05a45e1154b5b159f8d75fc50ed4728fecb8764e591de14492b04fef8360c4f4867640990e716949121b08f439dac2f3100b6a026826f458841cc69ecada981d9eeead87e21d7580466b6866cc2b39e9a7f470224ef02436cb6d2dc65cb6e57104840973967540518c3bbe143307c39c6ed25d0e2c4c5e9959d9cd3a35ce216f0b84476b65b98697208d4abcdb2c00a8a34463408105d206c3932e8a81462625944b29e2a83a4eb5033b0163223d8a73753558e966cebb6ee858c40863250e7136b4beaf6809cc500133462ebe3c1b8a7e880b0f0bb7946835d412770dc07779e14789a1239738c56557e6a976a73d7104ac3e394307ef600aac74cc61da1dc62b682caf418da65a11c196201a580324ba21ff91e178759f8628b65ab328a266f2eee67638d0effaf6dba8d919a01071eb6e23ba5f79d50d30a9be18b9e25bade2e11f4a1564f488a92c29fdd6345c2e2913ec4e54b04558244f7c06d4178ce6d0c6af88b3b1dafab9ab5a64498990d58cb51901ab5d738a0764d423963378ae26b6f7ef3d2eccaff234f62f3df0f40b9f056d13d3317f4c991a0700dea40b1e3cec27555b60c04719e0c01e99558001a3bd335981935da61373eb721307e88f924e16b29bf2d823d111f1c49917ded8a426afa85002742ffc73777761d9ebbdb2ae19ff973eb7a3f93bc5c4b239e626d4d8e8625f2d2819fe15ed43397134dffe00fd11020409b8100ec542aafc63422e790f140db218bcf32765e4da4defacb91a39cef728c3236c85c877389697d9b6fc7eb9c54e6c30f1bb143be5dc74ab644a4617d0351b600e94dc7fca3896654ea19d5f740892a2ed8c3aed99cdd069d4c5356412200e48b21b5433e043d4ff60907ee809c73d147c0f46ecf5b076080c137ba8fe3b18da144e26f367a9e757750e462b2848fff4c2f65edc0a7a07e530e0e6088fbfd2139db7e1dd3605b4357691e9a01e1d85f3acee18e5e5f659776acee832970ff9af99ab62cff4c19e616b580481238eb1c3788232acf18ab01a43ec50dcff0e07f2c886025a79a419ba3903a7160cc033db68e1b3fe8165b69977e5950cfb9f3826caef7e8ab810614a11fbba2215f25176a02474d08bd7308eb4d634f3cdba53a25993ddeec35cf484fe5c39b936c16db708cb3a2e3a62b05705223928d9254788ec866b63370a463c0f4e20df69fb4511cd42c9c039a6d8eaca7637d9ec649a4ca6350479a8cf6400d54dfd71fa8dac405fbed05e12828b0af1d921de4b12c8128c36cbd98c158c5ec54975f12b7aa27c21598c00286137110dc526fbf51de19d2c9b370f83f552dff8fc10acedeb81a30d27f3842c33a381a041d2516d500b59dd1f53632ce4f94419523be5a5db0b1b6a21038ad5595d2c03acc8d6b437ade943c4ce92a4822d65cf4099f35e6b00b60ab13318c3501f36c426202b4bb8f8a6e0af03a9f62f4703d123248e5468395b92e9e29e0ac54bc1a6f0a5134db4f92119226bac8f7639e0a3048503efa796d48de53f211416e0afdff9ab57a5a58bd36c44ac07ee17961baae861a089f5f95b75ecc96cecd1216f0fccb8c15353d5bf9ac3d317355bb70b1f9efe497fc9bcbc0a2861b76097110b4f1f1f31fdb5f3f3e74c8217045ffa857606363051a6ee113264e88972f60de97fb2778d86c9c91371a22a221d2c0ac54989035c5dfa3a7465ed15704207668eec2789bb65045649f46bce65764612a6e5a15f770b0d501703d113f5e243cbb68fb632ec968059e1c0b05ac393a4c4c772840c153212af59b7a14f320534edf53f1e8e1c3a4510e5c228ba1bcc9072592a4360d9d442f30bbde1cb21b6c73313ee8837dfb5cc7aa69e21544ce4b9f05b0d50b2fbc42ea5e08aed77ae5b9066e0de150702574e5b8c36b0ad6d864d65e5ba8f8de1e96967541ba76a8ea362477a7a6364535c39974b2470a2a558ac5da20168e4918757a769403e21a3737379d384ea64864cf018533648dda2f4742e0f922a421119c4cc0be1ece7ca845673d81b9d62fc781ed621c695aa4c78091f7a080c79293ea1186857d0bd65bee2c7b929c71f8ee77a3e879f2086e447b2089c6ef9080b61cc4db2ada8b1abb01a11d54c772058f1eee730d3934b32a80f3e2c5e4a5d6bda063020e1f8ed65fb103749fc8ed5fe380f82786e1af1d6996e0703bc093249a9b3e65e37dfa2458b25a9dd5a2ce61afd088209390e82e46628c46bcd400935ff5d7fc9b8bc1ea830389c06ce12a02dd233ffc0427e5910e7b0e4b68ce302a582f735de1ddacfa05742f0a022c3aabe8d1eb17a58df4e15fddffffb6fffe37fe82531cb1415519e24cbdd0f0b61c8cc389d104ac0f56d5c39d10c2939a81a58d60ae981b56ecfd70f7b74febd0a8cfcc02d4c62e510059513796fd423402694b32b6d0a361858ffca24af8c1718a51a6e9aa46d44bfc64966e57ea02a1ba4d408cda90390f1908e028d3ab70240e9e8b511c1cd46d1d8bed14217d23e1b7c564bb50e32a20025640298aae230a40b16a71620fc22abd80812025b8070838df69cebd02af60430163d4a3bbe1e3feb0de92b6602b9d948eee3003329ab154bd56f1a826c267db9eddfed9244538b852547665b21626cbea5955d0b8eeff81da122e42723309cb62b01df4de3def404564d95bb5eecd46428913978cd407b2d173b5dbc940829a187d7888267a85921b66bfec16b36dce04af950b8a3fe1232db04e6e1e823a8b213d27c66bddfe2c2b5896f4bdbdbdcd64f9a6c54ea02b92695178f661d5b9c4a65657a075d9f0268191af4e64871763cf963713f3cdb6fef16a868d43a5a3b129516c4694d9c80840bb11822fa63c10c33b0c6347c3f2654a1390011d65498b5034956bb8d2bfd8b85883a46ba6069d5bda803803a34b3510d7bb50e4ba6aa654f1708e8b96fb06a3f6f1f60a92028e738772939185bf956bb0e6ac2a8c22c987cec42c3bf2c5bc33fb31ce2ab3b40868d89ac91316c8f7fdda9b332ff6c164f9bb59a3de2f442f6494e720d95b730afdb0b3c9c05663d3300e2c9334498e530bebcd315e1f06d6c41c296601fe40da9ed31da3b1c53bdb484f9d34943bc2fd4ea8a4a6997ae0a1b7b922c889363fd90683ab5dba62168842dec7a99464ad7b7e9023cd9b072be9399cbe604e9e5aac635ac6ecad69e1783b9cdc951d9a8a89d4a80a399b451c76b1be34e6973a8a4bdc4c92ba7b1d0070c0783cc76211591a7e21ac9f0edef5b578ae41fbbf963f12955626c8ec13b60bf31c3ca36b16da0607bced89c8c448158b0457f69612a5180de6b83a4a8fdd7aa9da832ad75efda8db7bb0c780af87eba0309ac698010127ae82d02c7b0a123ce8053bc6527130430926e84edf5472958ee475bd3958f6508f54491d4eaf1452ed8c69e34302b255264d08fcff497fd74e8d507d61984b05af278bfbe0ae0512dc9fbe41b5de20910ba38e90160e7aa9ac1a793951b2fa8e03b7933e0e58210f4c02438484f3fa2476fe47044311d2f827ca6b10aa2c5088de1761c4d6cd021349412386a2748c379256c689ccaa69dbd90045036c35d2257468f50ae25137be7d90df1e14e18e3d83e5c6b8fefd990b52bb073cbf93cf726fa33c3c2e88938e02af3c6cedaaf3cd70218e836e7f9d16eb3a14cfd28c2183e85a70bc23d347c1d190cb7cd60bd1e6dc202b590b2f38d061f50cd20696bed47395ae9d0594bec192366cdbce64a2246ea7bd1ccb6702d872c57c2c5a40122ad780d720c67c294ec01b2517f233b8e640abd596df631ade72fa4afb086cebac0eac7fd0fb90453ac80ba68c58731b8b1404a83aa4408f407c825f93382d9cb9362d886373c2e1b2533b1877f58c8301855800f8ff6b13a1a4f25e5cfe75ca3889692f0d508ab56862ef1e2a475ee52b064b0a88818c9add319ec5f9235f42eb25814ce3ca657c8b5e76a291ca9909bacbd1ef4d29b9e4ed8b5b2604946aa9ae1207ad410ba231089be4e4badbe0a798d301596905777f535a86b1afd8e71df4053c211aeead9b40deac70ef801ff8aedf77085a6992809c8e37f02c9b52e389cef3505789b26c22397c24160771f77c9a0cbe17bb99114208e2de5ce4015130711e58090cb27e7eeef1cd70b679ed04aea7867c2020386665fe5f7e6955f8373920926fa1c78945e4996955c42ed19a411e356461a420d1b7892f839cf2bbf3ec55b9e2d661301a74e8af69c24a2a2de7628ef1d357bdba136f58ef13a1ac8770b4edfee5e98ea68cc0bcea8ba9a0191afcd5e1a5e3112f82b8cb1442f46878721a1077fe56704ef118d55d19b11c42b76b18b6578ebe74557be5b7f7ff7626714149ced3052fdb9a4c653326c772fc42880aaf7de0effcd893494bef258abdeb1e1aa729c851d93512e4d44bd6e2b6c00b65c3869f1b1bb68326f858eb62810a3ac0e35d829f1c742652c41450234ad0047a26256f55ce663be21785797a7e4457e52cf434818a3a1c8f79b180dc1e0e8341714a9cea8ea281cae15205ddaf7586470262e3f067050938f99f3effe764c2435778e0b280420b2fc09fb93dc9b958d3f7faf707824ccc79b077171cf54fa8d0e00a0f05a31f4b1028ad3f56b95f233a2f02f162685fbb6d0dc36c235d8085e2223b62514ecff898ed16d07946b44b53c64f25d02c197657a3cbd27eb50bd405f49348593ab7af4e76315f66b0d45a65596da4abc29b509878e0129713d6cb69b64ca60292ddf8975fcf4886e7999162299012a03eb379fb9d0fce0d0c4377994181c0e1e270fb8dcbf0d7a7e053773ecaf3c04321feb2be88c63d852e1f44d597f0a736c68004db8027e37dd6170c030fa57ae139358552b7ca1ecdf37341ad1b39f5602e6c19bcc6a2c8cbbd8e994b39fa5eecd3efb12bd721f1c38101e4ecf7e71870b66495dcd65eb7c01586c2a8820f4582cf9e872ced4849ef15282f244e17b7b533f3bcb39f61d84535f07a78b43e45879c0fee99cd211d980875be35532f67bf419e8bf45c6999349141451e2e6602c3965289920e7e106b20cf0a874790e56a153c057c7d5768cce4f2bd298f2af304d7b100e9365ba77361021459dcd7115c2ecaf643e0379530c3db4a30d9344b28a8cbb9cb1b76bb3c209f5672a0d1a438224f711f277e38824e7ea6ccb6143800ec8cdf590d2252a76657cff040e3a128ecb8de4ce4604159f4551f469444beb3ce127ebb9f3d8b4a65a1a5100e910b1558890bb76c36e48673696b31a6a6f5beab3f4ac032dc8b2ec5de94fe2c3708a97ec3cf2714a46ce13efa6409d9a48c7787c50d93d9be33c066d84fe562d4d624bdf5447a309494d0da2b4f006024f46d3089a74ec72a16d5d2417cb571b8323cb012cea44d708cd52e21f8edaa0387083bc2f1f30869bcd6af4e855e304f978cf91284387bb8099295b7275d8a04ea99ead5a2fdaa7e845e646287af229e1c4081dbc50263643a2c42a5553fe12aefa258332136e177beb281b6ec42a2699c00ee798bdef3c30021bcabac4728a5ef2bba081815c7b4429b2a6976efa4e82198fd7d576d7c7038166f7838010973fbd118bf6ae02004393b21339800d131e81e4acf362abebf8c140d077ccfa7b3b37f8c309b4be40bb0b288b0112dcdea31726954b6215979881d29e821b5a8b565aac629b8ddb48c5b78b96e4fc4fd86928bc41f0648c1562a9e3450a14ba44af748465de74256d1dcd6477e91a474b5eb7f4453902114c548ebab60f665c86029dc76f534c40fcb95c6c45562a88452f174f81d4d81a2fc8027e58a0ff3c04c80b26c30702ee838c9397f987a069e9045c272a201139ece1c19d3d48f0c89702bd66a2396c0ad91ee4dfcc51e1db513ae874ae3f20dc900aafbdd36cfac6075839f9105bbab4ba325f1e1ccfb867bb4209e39aa9355f02309708155ecece0b2106e8e10813dece80dad53add212dee8c90435287e8e9af03130b1bc529a752354c3aee5ad4200d017311f70c53a1dca2fd0088d485423f69616d42ac7b3379f2d751535ce3a2126176f87c05e809af00295a3288910a040a5bdb42621b12c2cd552894d515215e951a7fed2d365b26c543c88db7a266eaeaf07ab8a3da6ba43144b079a4c8217da587fc2029fe9a335c4646ceb7c10e822ec11bfd1ec5dda4407ef897ce5994242af0188ce1374cf6e28acf0fe5c39c4e21509471d086bda4852bd4ad45fcce40702e3a9e9688b78285e997b88427533b3e2bde67966c06dd7eb0cfa3229efa643d0816446c7d061267eb9a0b13fb43238c3771c4cdec9e9de32bcd44a255a5f7680438832fda41d58fd89364f8bad6d7458f8658d63feb692b381fb15e9fa1b9db748dfc376e02dd874cbc84d022f6d0e367c8d8e3421b730586cf71e3f27e27ddd1387c34d000ec6758c396ed33eeacbebac6fdcf3e4b4f899bb1645f2ff7b389274a1b1de3402d6e282d31b91d97ce01163b6c5c1431951c349bb994923f7aaf264e89caa6bb50095f0b67186e30047b22137cbe25d8243e8b0a627d85d90ec6bb5d0763692ccdb7b04439cf714238774ec8b785434a2928797ece3570c43927dec523d38e16e003f792ca3ff583baedf2fddfe55ab51ed2a8cea5b6782ec7e1910cb1c93de0aea7a6fcb2ea9500c63835a3c8426d7e93098b0dbd1f9571c2ac5f820e149051f1b076150f01fd225aac3b6e1d66fb2e55532b40505d5afc6f842a04875d2d0c0cbbfb070b0a9761b1d17de4f20d39a5d1241f18e1bbeb87cf9b6a202f272aa489083a2e7d95a0d9f37ee0c452ac4207bb38984456bdbab6544805ba5465817c028112ca63c0538588532d248b8c566139d0448a1129320ea65163a8d42a8c8a28817dd293ca9f0c22e0f4aa6fe2992c7586de4864f771a3b624b68cddbf24c64fc56e258d4cb8862763e80f751ee3c213c9536ba37f38923ff5a719f22768b94fbc6e9216ac42e70ceafdbab6a8e0e022706c2862eb57aa8e16c8a3c727498fe1eb680c2d9bc7355f0ee193451fc53d98902650993921b190ad131dfa48dae085ff3f15a0a99e7bf402bf1a751095c4ec81c82ec6c0be37cf234211e321c19ab1241c651167b0bebf04eb2a971787cda2bad6ad3e6694aa01aeb392b05c101db3ad30f76cf33d77e120a4f3058299731e0607eb34e35bc953d953ce2f99ffe93b94e67af632a094b0867dc4dc796e901b26870fbc41705f4f11c61f7db023b4e3fa5f322dba5d69a92c05ea7376c52a5e06e30dae80d71b04ac50d9d68f02b159f48a2efebf53bf4628ca25809ef426de28cdf8cb138127fc95f2a445b491c2be193b7e11e4c29b50e1eb0a54a45b598ccf909f21c327bf7847392bdb5604c0b85c2f948a5701cc3b2024d6721d77b9f515c83b493e7bb40613375bb52ab1d9389b03dfbc1ee651a7edc5899ea6d06865ae7ae7c36ed05768e8dc5bb5c37929712b7a106ff32af77b8b6328df7541b45dec767c4e1d243a62941e45c1d6d358736ce22c3018bd1d23ca4cd969a2e8a3ee5ef31d3072a4b1e94bc844aba4298648824f2d897b63f8e124e0c29615a0242bda36860d125c2a0b48ab708bb1fbc2efda455c4a98cd6ec4b5631ef96c4ec681db19666aa5b530e1540de25f0acf64f646ed4309fc81e1169bde24b4ac04eaa5dbbd592050ab4a0712100b881da80d8dec03a8036aeac12382cad968adab1f416538f6dfb42f024692019d28a314fb103d630880505630e44a4f3c3c8c768175eff5b5e42edd2b4231be1ff5d4205159d444ecde9b6cb9a594322519b80b770be90b5f9d6b883d44c49e9855a7d5add723e2549f004e14ba475a4748d6f4d4ab03b1d31081f0178311c740b7aa872c6481e8a37ab651a05b75ab9665b5ea4075c757e7a321a71a95865cb55a2d6b6dc9a95edd48ebb02cd7a35ef1ab97fdaa5b97d5392757037287027d53bd86d189fbd8fdb0d0342eb8ace9ac1464972eac1478892c2f9d97c81284fe2ae2d45abd723ed5a76badb56ad7e8858af3e444d88a57bc62a51baae454266ab060a6d65a2b0c6a840f6db4b8c1871b845022e5a75f17dcd04627e654403eb4e1d1e3870d6b7840a424544612152825e9f2d353f7b66ac540124538a140871e72b802562bcc20d2b1fae0439b1eae37b8b0a244831a4a35dce0a70d49fcf497ee67e610b95c2e1cced8a2a6eb225ee1b6c802011fc6297250f1d3577318f1d3ddf5d35b394b7e7611e3a7924b8a1c39fc74aefb991176861a4e949841125c84910411684871b70064f9ea2832b4bc68022800971870b9e1abdb2530de281283054f6b68a154c61436e3b4b0f95afd22c5d1e4ebbd2d686163044e90800438ac01ced8cf49fd87d61a7cf55989e44088d8531b6d1c518209c6cf39e79cd3032d5670bce0ebd77bc98001add5b9ef76c48215aff8b087bd4f6bfcf415eca7fb8cbd11c613ece7057518a104a5c8491209585c96e6cc94236fa45b7bef6ae539595aa7bae45c7a3bd548a1060b3e7321944fe99a67b9d52bfb2417e9923743f246f670d96d3fd53cad7eb82e9b647cead1d49295868d76774629a594524a29f5ce689671dc09c143784a6f9e3ac718c8743d75b622f6c4a7ce6b8890e4f26ae54e73d8f99b30aa054b95dfa20f1f6e8cb921e5439ea7a47703cac7981b4ec878862d35ca470fb7336aab7c4a298d6cb868ece9e829a594da9a4d79ea94b2105dbd969e5aca807eb9c32e7b57deca799d409fa5441c5abb20d38782b4a8ab5b34bcdfd4b91fae2be250ef3182db460b9e7a09ad13c9f0a1e5664ebd62a1306ab3ea943263cb961a384971a4e404c6157b3c78ce43eee38b9655b32ff5d7fd2244714540e2024d284638090204423253c50940184762bf40028c7106e21a9c4020243a2e10c691c826c0982f0a07e34591a1f442a0a16f9f12e8e59ae1e542f20a72c5220ae8d2e5e9e5d3bfbcb87440f65d04040e86f34ea2cf5330c5d6c86239ebe4c789d8f3827fe12912263d869de0c1f7c79cc753f8d550bc88182aea22a32353d8734af058ffe2759e7f13d1871311873de4173cb309dde217372d40a2006bd673bc01171a3ee3bae50e3f1163a5144879f6b8854ec949adc32cc6c1873ce5999b28f0d39c82ccba13f831f0e342b722d3120c4b1a884dcf5c7ae74837c99cc98840b809fb70e22dad93f29077f07cf3eccc147bbe90b18719083371bf70f5946ad243ddea254dc44d9c8599584b33130c84afb4d0b357e6c25c449ce613e8f7d74d224e13d78d709207ba35c2961b79f06d1d4b6cb10535b84c199ac2258a2630d28041e11445132898c2d0e22455458aa62c5aa77b6e436956665de94beaa34720ad13c2ae87c1126197ebfb63a11322895cdfdf906ef14bb722a431d0ad6842b7f8e572fdfc52a9e8b263294e3e2e922bd8620b651cc9c069064b9070c0d17b087e1cdc2ce2b4f767dfce28d85ace5939ca3498a022d852a9d8c3a91422ceac2188ad18979873ce39e79c73cea239e706654e9db711c1e9bebce07294b8e3c2cf2750788a0c5ce0e1f511e0b87404386e7fe8d68e00c7b491e3ce2c50be3f6457686384e588c8c9f45896263b129cd34a9937f850f55950ecb1225871e9c7cf40441c20c18e18c201f44568e3669d741a4ae79137d3ad9d3c3a7e04382e557d00e4b8d4d33ef673f614681d9edc916ade2694b8dd74b2d1647a1eb9c347c4f8c241132b80459c39e7f4d93a506693beaf5492c83176089a4b52404a293d529652423961a33a2f9d022e8890745f6077c753df01b604220bb1672a808c1880382e7bf6b96ba971e93759a02eb0d01511c01b619a3dd7305d173e1650d040c4d940a88097d2c31c1eaaf9e20ee996f46e89c84d548bac954e1714a7df52707cc0f345161fc6579cf20c8b559ead4001830d18289a87cc04bf1250c5078ce5999b3e0c25bfd500e55af7838a81210315cf675b32fad56902be287aca3f259394975167c7b7d3076d9c1da194c40d647777774ba74fd2ab9015299d56915c5e6679e933b6ec0d4a27c7954c46df617bcc8ba797a0745aa57598062f6d48fb6111473acb85ea6fde6852fa0870682268a91927420baeed7ea68bf0e4d6da4456b3ea5389e905f164985fb4f23d715670514cad13d2296d511486f289aff8a2309f884556c374b337ae4e13998d5158b7a4774adc2b29ec975a67ba944e63ad1383740a9bdd8fb559ad12ccaa8fdca1b0992da3302969172f6d60b232fd3e096b9d70a29c84f0428a1951acac02b8ec208aca63e9a9d3367230839f3ea79d73ce27339cc78439e79c92841cecf094a6b07421c5cf2986a89cd560a3b1b91392bda41f479cd93f917c3b5b0d04d236cfd951fa40a923e07a68848280c56aab9a1462969f41cdacc607b6d802962227969ce0b205d28b47796842061198f23a8830c0eaec3dc4931cb73d7e8c8d51e5f96d7cda4a898dd1e4db8db88f00c7a5fe43bf90a723c28fc08050f8e94616d02d9f0faadcafbe00177c546e399ea72e4150e3f2f8f8fc4079d8c3722f65e79ccb2f8481e7a5f374cb0706577ac853427742a4b352984ed9833e64560aecd469d04b675a42eca87ba05bec42a1a23ccd0baf0aa85b4b2e91a6800b3048293d106fda99a3504282979fea4ed086913818b06f3eebfde4379f1445b9c377b5726f310f3f692c4d36127b33b1e3e37fd052b23c5779d65c569db0593e7d589f3cb333d12df611beb848da17f64b6306481ee96342f3d4274deb01d3344d73556b9ab3a6694f3fa5f44e85214d283389232210cdc53e8e624f7b0f1e363cf54973319086a27d3094368b241406329fb00ffab93694d6509ea7bce661236547dd2a92ecf249ee644b38ac4ff249d6279bf9d45f0c3c8be4cebd5f2d2ad2be4de37cf470a73791e4cd1306328f487ae624220e7bd8ecdddf3ca21f958a40fab03ed9a6d661a59c1fe5ec9aa73565475ce3c89cbdbe1181d426ec834beb30aa09b3d3a655136dca9abcfdacaf56df64b514f117aea4bcf685199467afb04f437d30fbc1da7b79cddbd35aebeeaab9ac527ab7578bea16f6c1cef2cb8ebaf51471b884f6eb160652df883ed8398e6fcbb39390c59dcc9a4b13d286acd396d689c1ba11fb9bb35b5fbdb2a11ef5290623175563b54ab55297ba85c5ab36f02a0e220e5758cd53853de5748b3d4723aab1c1e685b6bbbbe9eccffae8e1dae6192773b3c0e9a7af3ed2ea49666ee93954b65704047e4da7514e09f3d639fbc99764da4e2a589231da52cb129396d661c529ad482cb68a0f6516e6983f6be5ebf5cf3e78b83d9dbac572ca297d04015bbdfc588838d3656cbaf4e267b33aab3277fc7416ea1d8f282a15513494256422a269bec4949efcf02173f999552a5f2e5f13cb9c4b3fa7cfe95c6bde6777276e87d99ba4f308a3219ed0295d497152c14566e624b9238fd86804376e1371470ea171c7ee4aca253965b7ab635f1076f190642747ec62d71dc26908262a3e6c2cb263809412958e865e3ab3a41fe0630cd74d3ce1c9a3239e7d05322929f6b03c6872579ffa1839a577e40a585679d9c4b37cfddd54b0e4675212114b568a9d31ce3eca4b29c94972875db632e521768a1ebfb0b57c1d931d1b923b72886834b4faf849a388c3eed3245c71637207e5ec7d25ee6cce30bd147be49194d237bc7df2881f3d7a843c2ccb119e6e2865962daf29723c3f094b776324a620c104e57a485a9b4a35974493a7490875c7002133047a9610eea7cb0f3ff0f32bc25d62e01f9243a96f2d7d25deb04ba129dbe8490e35c92126a87cd8589a883b6d246f38f644efa327be978cd89bbe70e386d2c848ee7413f186fd8967ef254e588dd0c6b51f958e60e2e5d1a6daacbd77b5726fb53a86fa3a46821637ec981130239236e6588ecb4714c5a2d211439289678f0c6829331296aeed7ea20cccf4298de44ec75a1a65e1d256bef8e8c53c7729440f6b8c3748c2f2d1a3cf1d03a2d32fc6d674b9d42d661d7c543222cbf3770e88de2d7639e75724530aaf18f8bb8fabdb372377e66177bfd059e64d5a9b9b9b066e39a54fec912fb34c8b1127b35e91d47711873df342cb12d22f586fa79c750bc7e5b7ae79e6bd60dbadc78e8b381c7d18083f7513acb5591814838375a904d117a2ac4b940cf68bc818da088d2f996f94528f3146ea557b0a53f3b439ead6b3d0fa0cd132eb2e7762bcbe7095ab2f9bdcf9429b7d75fb7cba453f14b42f84a47b42bf4f53fac588c33a96dd5acb6ef905db5ed8ce705c7f815b87ce9871942f5964c6c145390af531370dfde970a30f915e3bb64a72a30f6120fcd58954cd6a5606fef630e8b36e054ab85673ce39e7b4c08d4a515eef324aef30289d8775f2525aa02df208291157699dece318b79d6d0cb347ce8fde41b9ec844cdfdc6efec21d03505f6823bb158d49c9596f3ee719917254caa7570489eb3319737541eedb6f6ed5a3417c36ea63a19c7e1ceab3321449bdf5ce65ec5fc6b0c826b9c5b5a4e80992149815a6a9a5539e50146ebaac3ebff0fbed6528720e372a45717a4eeb84c829dd524958b75eeb0280c30de5ab6308121fe541b85feb7eba2f461fe1e62d6486df1ce6dc373b21f59353ba25037f683d7ea5284cdf9e3120e5ecb68b70a61471a46b5f114fc268e4c894becce999b4e28533fc9c9f8c451cb912baa17cbda6444a64a310bda494520d3523c739e79c9c119caaf3e83cad83dab49ddb791e601790d090cfeb486a871be648d775a175e2e7bc6ee7e83051060314b7a9563eed8b7391e338cea35724d28eddcd71721cbd229267ebc4c8c35dd5caa675506da757424e8f1f3c9e4fb74c584086a5b5e486abd96c5369d8e4a4def526bbdf267797a022717d23d9a70743fd6ee61d652f431850af0450cf62cf0fa5a8571995d9b831368585805e17482963945f08147b89f4d14330baec5122bd9432c618e5d702768fbb1dadcc6136628c73b6a668fd10e38c31c648468c71c618e78c1e00a4b8d2639c3263032157338c255cb7e67767337731639c33c618e79c734629a78c5372b105895f84bbbc92367ed5ada25f752b469888d345b8cb73ddba11c7265c294131fa5065d33ae18f57c1d8d6e1209efc2a4a0f14c4deb8296de58bf64acdb758c4f3b2392b6395d8f215f823eeac644eeb8240c565e7eee7e85f5e74f8aa73fe88cccc7c91bf30e7bbae63c762e8bbee8bdd7af9c2cfa753b2498ca7fc7acd9d17ba0bf3655ebc1f5dae7f07e3b1e394c77841cf301f013a2ffc715fbcf3c2b8f49dbf78e18fef8e7ca4e6f1dda28fd4bcead60b8df4907e555ee42fc69795c116dd0bc1857943fbf844184e1f9f0883e9aff8eee31361b8e0d97e32f80a37b4effd42e369b0814d43528ae203cb88caeeeed84c50e092524a29257f2dc50986469006757db4b160c992454bf767001a6ec7be63f203ea922aa04840320423c9cccc352461669e41921ce6ae819452e64089945206a16469632ec00ca8e40c7132fec8e186bef32329674806bdae808103868c279aa8f24452969d094658e51943a58a0c162afed2e057f2a35212529492406a32361b1c248b870f6266a31b88628c3256a48fcef62a3187f606b356c610f36b48ba6c170d49220f66392e676dc71d55a384b8b143243f63926d9b51fa074a2efbf4b0bbbbc339a56ce570cf39a5742965c7c8ad1c2abbbbbb011071a2ebd861767faca818489fb187569f6e35f5e49c9339763f6fd2a3ef33a5fc8d4e3aabd4acc344495dd2593b63cb3b9a5df1ce86f21647cef191373fdb8d5c63ec618fcefa28f351c69ec99b0f6d335bbf6f66d587638fe69d0df265adceacd1aaf564fe4207435f4a004f8006c4743be20d453d8de9c04be7491b091da2435fd01bb0adfc744ed6eaa7b1a593e5e4a2dca151c9b5e956fbaaee6c5d0ad502afe7c54942e880170fa6abf17e5680f338de4cdfbc899a41cfec3e7ab8d275a6c7fb8510c665df6c56a76ca6b6ebd3167934d7caf1d5472b412befca9b6d052d189d3dc9cccccc2cd9b3ddf2a85cea4550763f43a86f96e37a87eb1be6a7d661276bedbd52ba7aa8eed4b79494cc65d24b985a6fea8628be786629191348508e52d7e57219a9a92e5dba201d3d31faf8f2849b7c7426ea629e50f18127e609951e8a960c7d949cccd20dc058c242ec3ab2e5cc208105124f5ba2c380d291822d4bf4d091822d4a6cd1d2e4820643ab89094b742296874d521a615889a1903905a14b972eb129d14ba83ca8f4a0021b1e547a7852024f0e150016486401c34a00582081054f4e8f968e9caa020051458c1e3c32195f42145065c402092c92f8cc2f0cdc677eb140e2b38c7d6ed672e6f766d39b2f73b4451ea10ea697d4526a9bec163b4532bd742b452ebdd4f292bbe5cec69c0f2657e30f636c29e32cb75a32454a151b93af973edc259b248dac94d6797d124965249fc8251f4c2e1d6293c2883d51c41d0dc81b695f0cc442c1c5cb2b5e56f1d26f78b8d248de48b7f6ded5cac8470ff7f5d26d122a2661d40b129fbf199372727075b8cac3d8b425b54ef4c1e44e8ef3c1e4661fc658520f37ac2e1e625569f4b2d68f080dd0ca673c080c2d51c8472abf21921aa0359e759237d2571e8d37e3d17c2cea2b0f0281663e16fd582acc388d53a7a1f1d50744f3d9d74c1038f333c426c91be9e4caa588235d5e8938d22318a5f76872c32a61232c5d0a4afe0c40c3e527471dd9a4db3e82b8b4e9a5ebf080a2109971d50734e33a9ceb7e588737e3ade48df4408c2b345e0463f02ac1a51edaa41662d7028d977193a4d0ccea35f34c730de5a8cd37ceb9cebb177f4979eafa857198188ff9c25026a659a6634d2fae22295cbb0ab501a4abea5075754b9620797882c8f78938d2262d8065a521de48c741ba74451c09ebaab4ceb44949493a986a84d8220f6631a330e488109105c825db3014ba7bb55a4191567a3beca8d6eeee9c1c1192dc2340d6e54b47a1cb4b9f2102e94f86583339a1107b6e5efa1006625d2ffd011f903dadb767bbbbd93aa5ce5e11eb3e6de352e7c0962a0c8642a79c5e7e90cdea96524a29a594527a4bc9e486d64a2ba594b6d229b570dbab7b2fcfb4d66ff662ea1816a6a2a20f6bddf279589f96644545513ecc8cb2273c3ccc8e3229d54ae5229441c960daa54b0ea5e04349d4e45b16c978289f2025f560a55d4ef150c25c32c9a6a10fa593dc42e3a17cd2e1e114222af2e1890fa7d17cb26a0f2713e184f9c0e5c3199b56be77783897be3d9c59e61309ba782a64d31ed2261dfb901efda0c45326be3da453e8921a1f52a60f6916f790367d7b48b7d4a11270f9b012e900a042a94945397c585f35ec27e9e4a88a5c925c86a0c47062994db4884aa1302d140c6b029056dd435cf4d6b4ab0bb109072d663e3e090d71c96149eb68ad1bd5dd3a50e997deba398b53f3d312a30fdb15f692976ea33e6202c6878dd44c744bf9dbb05ee2c106cfc3bfee87c7fdcfbdeee7a380bd56270c8087e0a11101f85c60081f12300a0fff1c0619c5072b5ccfe3ebc0e70070ef7e00f0c5d6b99e67e5439bf77e78e23d1bbc578211bce7f9aa042778cf41e87ebcace9dd3fe87e1c04129cf120b807dd0f084064972eff81db743f1f3cf71ea8de039f1eb86d22c67be0970452de038f4d98bc07ceea7e3c582d91e56d7c47f763c3f2c18a67794df7c3dae1abee6747eb6b7c00e26b5c47f75323c61570b5729aee67c5e37564791d3ed3fde8a0a17155f743f3fd4c0f2cf81997e97e66546ee34e04551ed3fda8ae142fe311cbcb384cf72313e3b7fb8969c1680183031818bf26781822351e8687271e86491b0f13c2c3c078aafb81e169f1f87065dc8bc5bd08b8f7c75f8f4bfc3dc0dfeb7749d35f5fed2083bfee3ffc1dc1157f9914f1d75fba9fcbe3fa9477dd4fea45072dfec5b9eee765a7f3adfbe93895f7a1cd7338cf717e63cfe970f45c0e44449dfa9b6bddcfe628949647a1dc763fa80fa0307acdb3ee47e3defab43834f1560c9b0dc980521f22fa396b5ecace5ecfa33d12d45a6badb5d65aed915a2b94ea13712acc0793bbbda6691d7b8f8853399fd8d37d7511925cf9d5394ad461a15bd52b7b75867244ee44b07a8c3a1388ad8c281e893d370ca4ba02df81f6f9b1a67f94899c741113464f1a0a1ff1111212130da575589c64619c74798a85b1dc5edf1b4cf860e3c6c931fa6a85c6d14b4ecafe6eab802557e1838d6b421f691dfe5837e4575dd791248bc3e561098831da27deb44760c7e34df431de8b6f498162dfa9232858a89b95b600a33722a52a73f4943e26b48e65fa4ec1f37832d23ad183e0e03b6af1edb12748fc185611673a4cc4c924bb05b241e08d38ec4b5896c62262bf299d253f8d045be41182f07a761f4e570427374c3dbd4090f2ec2084776836a5b4748bdd87d30d79562fa972c23a417e7b7b3f7baa294c6549393d47f76c562e901f0fe6d4d3502a078497194f436e24b111638f41cf512471e2396b9fa0748cab1863f783edf1c3ed4e48a4a2c457ef1f5d6ef6118a13487996f69e8da7651ef5a6b7d271456a81c126bd394e4a2d9d2c841b4f6ec05e6f3c312369d6287f74ff748ec79374c3a08ffe69b1f293eb135cd594527a4eebb0717d8d225e7a98e34e6a0d9899e79c331a41997e404840398508e640c30b3884d4182aaa5214d51328a9b5d65a93284193b4808618861671ac0145ca0d484460f522c9932447b00e5ce450c31363cc20a6851012708032075ce0c0731051bb4882c34cb2830eb5d65a85b6d88658c88d98c4a5e960e89a4185d448d2c51a9bd21667bc0c12a2061c8c5032c404920b94dc47a52dc0f8eda3d2165a7ce839168b6d4b45fb36e274958f1ee3ba20f22d3333f394733ab78c38f6a79bddb235cbac86ea7e48f0e28696e3ba971eb1e311b65e3c322e7fa18d8ddf1b616018863915cb68dec0f36761f0c151ebc88f4e3775943a4a41699de9fca55edfd15348bd934a92a924286eeae8773e951471da39a6cbfea9a46eb5f74c25c92f95944afaf65452ec891f304161660eeaa4b454850956a9b56c628b21488c21486fdc718cd1e3ff61b6521ae1c58fdd0a0dce0f0809c81e7db2e5f847ce89f5eadc5db5b22cd3e249a63a69b1345f4b3a2c2d916161a24d3bbe48023e469c2cb525cbb200c4ae4cc9686f4c2b2243acbca13e7e8b2be2d0317e768bd278292d1fc49ea6c468c518589ebaf54d2e1d79cab47d28267953bd3b22a80f75e40151c601d6a35ba75e887a05413d7f494ff9a917dea114faa78875b96e7823d4f9b913b2fa220a88d4e953dfa897da12bd9453b72cb5366a446e14cdd8486762ad13a6b47c656a6a9d30c565c6cacc4c0af4ada7b4d894536a0b0ac5a57534af9ec292626a9d8e5e3d95a575a8dc614a35b58ef62da05bd5ab4fcfc7e371fafdf861b79efd76b71b8dc59e17a2b384a89ebafd9077f0d4a9971a8a3835f3504311a716c0c90d67e84cac0027b899d3020871a387286e39690da9d55e5842549fb9fdf085cfbef791d18b8f628a3df3aba396628feaaba75043b18786e64ff0e0554811a7fa0094dceb727d686341b61342f8f8593fc1befd2d7a3dbc1cef47b7329a657106c98a31a46491f6e089557ae4fce0f15940f77d71592778309d3ecb3c3e4fb72a6a0985a55b00208ac3c56ebdce50be79f7cd2cc52eca1bbae4cd68d7f5d5599a765d7d85b67cf53bd43add57bf48574aef54a3bba475a292152b5f3d86d715a3e1c37bf4d5098b1f3ebc4c7cbd445f5db3196a26f6d52b5dfaea758caf583e8c58bec62c5f61f0a10dca93ce835a42619989cd2cc99da55675eeaa5aa777c4667b951f2e399840249589a770411c715c110391a4a000b1010b98891cb029354c1da4b8c205b6d739a001f6087e584204b8554e7a3bb43c110613d81e3bf103b86595ce4cdba1250a2c9ec0f6f8091a4024cd8cc576638f0c45b22e5d9efe7545114bcf9f11194de042c4e3d96b9adc302747ca3047f6aa7372ec16575eafd52d5ed550c19ca39232466f1dd5770c8b074450284992eb3cb475ec067d96629e8028a7abd0a04f8f40821bd6a20da975c23af4d389e48ef41a04d7a20a44ecd17c562022ceac41f0cde41bfb8535053f2b123fe717d615e8f869e48807ba35a7d3e62407d73e74706d181ed8228f4deed895f3e821ab479bbcd011b9f3a3b9a87762f740e276c79fd36071e061f57324e2b8c0c2131bcd214888c203930dd6d0c205b627c20d201430a062086c8f751004d843d440e83539e901d524456106884401474e590680048844c715507e740d293fbc0122c911020543544105d1143c5001b6c76c4c81061450bc200bb0bdf8c49318b859aebd49040c40e90149287220b40444d24a5c9b06850d182a0c162891034492e3a48a1b5430068f8d6b20129a78c90122895d9400e48c784152c749cf004ab8f1c2498f84225e8004b617c12dc5498f6590032423b0bdc8850ee07639e94528a6fc7004b607802ae00653e4644611142700b7184945164f4280483a295d885c678048649640f9c536c026c3494fee40448411d81e6b3902dc549cf480e81c538e7e0091e40831841ca0f4f6805a8b1f40250dca6fb601a44723031f8a9480ed512128c08d86939eb47284182fb03dbe320370b33a76d4b0c40e8ec0f6a2530e2092e6c9c60686170a2f7c48aa428714c076804151953988729898e24617af2ab814f104dae000c68ffd84b502154656d3340f126bb535b359952cd8582b0071194820ca3537c2df028b5d471208a42309dc220febd50c5d0f73be9fdc7075135b687d54a2f2a444a5e9a31295a5c7f9a8442589f7e24e4e5291125398c005566c01db256799735a6b3d487ceb417fe499fee87295a810f12cbf7e9c03fb901e8fbc7cc190530a40245d022c3b28a2c70e40240a40430008f8c20d2140240dc795357c005b890a8884999801f617857b6c51ee00d12fb4f80003a5032161264aa47081d38190d4b8202908503a929a28446c014ea058831e4024035002049a5f1476d9dc80cd0621bdfdacc79f4b2ed8ecfcf17443eda773979fecd4b3817a9d935267a694764b8f338e395177c2782af6a4522f2fb1e7e5a5eb624fd7715cece1b86d8b3ddb8642c51e144ad3628fa6451ccd469ce99a5bcf461ccd33a7b1c7faf41a7b5e5cf3197bb6cea7e69d5723901a7d683efdc5ab11673ae7651167fa8c4066f4e1598f461cad4b6864a23814f7c950b3a1b60d8592416d329ba3b6af08376b3532ff3a2ae5851e789491f931f3aa62fc42233334326564647090f1242a954aa552a9542a97919171253ca08c2391f9542a95caadbce90f8ab8ed7647e54241433a78b9646464645cc806948cdbd03292b1511ccdf10454a954ae8407547d4978a0600ba5a1284b78b8028c62bf178c043d11ba81500aaa70092306da12cce08a1180d1c4151cc0760fa05028948c0c0a15136364fe7419e755dda619c166afbfbcf895e9ba3c8c6f7c278c6f9afce9d6519e7c6bfbe787c2b1284ff3170f42fae99d6b5e10d237aaf32254861acd9bde7911ea1f7841f3eb2f681dedac779a6bde695f11548cb35319ef7ae731def5f829d7c788333b4f75be35f78211d539df64f743dfa76f5ec82750df620f438cfd07827eba66352f829af6c5c3e99a6f539b5f11948756e51a6a7aa18f9c2afb1579f98cf8e0cadd3c7ee7eca8187b849b735b1884f4dc97d5ea9d87f63bdf32ae7ae7fc51ee0009c52e34f0020d37e290638e2ea0ca6d60702803930481d63b4dfb52a81e5a0754b76ebf30fb19dfce99a0a73ee3094579413a2b05fb2887217b9474cdfbf17451ce5d3ed47cdbde4801f585d60895cbce882107551f921803a3ccf95bb4c08d2f294ebc5e4e3cf9ee4016f45de6c712627d3a0364e0cf3e5ae717d31c6cb3ed81b7df0b46e6db906d9d5e847a78e4ed27438d94524af915a93b7c5cb9d2a32dc25f8c3d42fb15619f43a8f542fb36b3cf5f8c3761f615a99f11ecf48bdf135be401c8094e19a4b94fd86a3df2edecf347822f1891ff81ed63c92f85969f0cf25f88dd9aec41cc40b605c49edef1638e5b3de86da80e14045667e7e82702d773b27e916176ce3967c489cc5d3e469cf8bd24076e545202c9a23ec6ae3409b9e449a533cb6fce965372d9e201ae538f1b7d814a66fa02a519cda8675ebd17a8db6e359d3f2ba5b65b967a946b56e90b95d6acbe5033cec69efe5969a53483924aa552a9542ae58483f117bf305dd7f9ed522fdded18e6297366470d19bd7f53940bc99c9979c4507dbaf48cf04be99b6bee5a4e7bd66a2f5fa86953d366d4bcc709f2b5cf461cea0330c1cd9c5f18680d6c20f664edd4230820ac56d1da18ef1cc6a9ff681d56cc27a4c5758b73ea9a07e3d96e715dbda3fceb85f3535f0c3fd367e4a2cef4483dcc3edeb8637978393d240f0672137db4f7003e1e2d003c8996b333dc6619cdb2d61c2e1cb034cd81830e5c14cdd124896af5246fa29d0388212e62f226da3986d001cb91bc597571ca1a060cd8132060489ce0ce8f4ab0a42930294a6053946cb0454e8c8955779006d3a450482e34484d96f1618c71c9e1c388258a6183105098e0e00b2a5b4c31e280e3a5ab56414b94288922040e3118c2054a4741ee504009071dae3851451a5d8057d5faa81487151ff351298ed787d79dd8b68f918a94b495736fcb9d2727078500e4705918226f180c400e316e7ef2ca74525a02a1bbbaaa951070f000c70e53261c422aeda3d21b713cb1b28146c3135bcda20a0d4c80d51b59fe7e547ac30a4d638b1e79482965a444b4c91ce3c39b8f1ede3cbbc6ec8535cff49b91267d137187164947523aa2f2fcc473772bcaa64572478b37d13da49aa3901a51a62e44c8e2b66f2a4406e38e0d0d8d873034adc33b236c78888ea77b001e179ef899d34525adda50af9e2377187cf1e94a2dc99be96174babec3c3b8c4aa5965a925b973c4f5d3c314d312538ebc99f4f3d5ca7d9a520f5c87f496fee275d7b5772ebbce3cf88460fc3acbeaf022d825406888076c0fbb47c0d00a6c0f614a186a817dfb05f5d3b7972b9769ce0f1e176028215689b1b814b3d09a7a6a9d30b594724a6d497159923b2b79333db5b45ad53859f6a34e820f0158488983910b1026e0a7473640d8b37d39d5ad57b7df4fc61a2265dbd05496c3b8d00ebfbe49aff3f65ea68f40832b3fcca1711b5f81c66d3e56751b8fe00a3a9c556d7c85ce6d5e7c06e99daff0e2366ef3cd00fa74caafc739cb53f90e4fc6575e8cd778339ea93ce54232ce39f55e585e04777811acf122487fb4189f71212195908c0b71fee23a3c56a5f158d5af47d0b2aa531e79236fa6cb782cc89be9339e06e4cd7ca9bc2e2647decc155e1ce69b81f317a7de0a9d5faf9e0a29efecc60de16804332e4bfda4b0bc78acea3cf266d66fc81c37c5945aca31416a2926c8768c962d82517e2c1532df7c85eaa8ea5bf5193cd6906d73d60a29f4b33777fd3591661e629d3d661a22947564f9d26e3d96f4cd355f6173fbcdf0a17c062d82d77332cd8b20b526608a4edd33055be4e17147ce0574ab4acf16893b31aa1077621c226badf1cad70e85ea1d191eb2518e0e97c663bc3ba7f1249cc7d07c2c1af3b12891ce69649665b47b98e00e913b5ce7dc57bd1b226f6a189750c8d1e1ce1085fa0c9c773e838cc7387bd9c7ce89701f2b731a9fde39fd88c87c2c15689c08cd379d73299dfb62ea8f188f95655a48f339dcfd70db47a4732094cb7804fb867ecdcbbebb1fd610cee31391ddf4ceb78f08e7349fe6d9b71e7fe631e7b1503e04ec3c16ea1b124199989a396eea29e59472ea32efdef09be566eba06e98add343a8d93af6069ad91754f61bcacb7ce3ae0518ef3e966de13acb7e51ac03a5b817e73c4808bff50744fe21348ef2eaa368328b7a4004bb6f8628d66798de71df0cd239a77122d3693e16ca693c8244a4b35034be828cd37c33442142e3313e830e97f115625ce5aa6f061a8ff108661efd8dc66315892185fecc87a8bc4890f82aa771d6101dce7a400475386b051ad7541ecae326d535198f719fa6f15899ab3c823a3c563633a3fa6650398dcfa862543432333a62dc7e44a4731e3fab433c173c0fc89b5a613c14e44dcde956f5ce894cef3e5646443a2bfb2eb802613d5a5fa74bbfae8f0040c205d58679b2c50bdc680517af8f5d7cb4620ba6e7828454e3d137116257eeb0d87778e47cf31536dff1cdc0f9e6fdcd603f167f608debfa5c71b9e1eab98fa5398b08ff10e95bdcc1712c9a83c5cd7c8273f39c970e0f1929c699888bd888c6371d313972875f21cfcfecd3800bed3e9db57744de4ca71ec3ba353d532182ed1b73d28bf280080ab17c876fcd711ecb376f4710c8f9038240ee030a023967399116bc8825d100721f500b5ec4925ce08e181e10c1fe84542ee32c0ddc9813218bfb93b1b20c88991032fae9213789b333caf7a875a65fa3fbe442f9e9829dd48acbced2be21ac1d9ef97624e24cef9c5c76ea9a5f8981baf6fdd897a6cb3e020deefc18266b088bb5c3bbcb9cd2b8ca85665cc65b72a7c6a7bbdc59f9f48de579e03b3c1baff1a4afbc8e33933b717a58f347624fcd4f5f792c1538f7c08970eec10714853a9074cee94764739b0fa8591ee73bbccd6bbc08aebc086e59045943643b17e3a15c8707e334def5991797f13ab7de0322282474fdc58552de79e66d424249500ee34242d7855e9c73a1940b75beb94fc778412ed063188f91268a937e822f1cca0b721da999e3f2746bce9963658890f4be481f01804415541ba6872d9b53ce3967ad52d618c2c0359d1a70a6d5c728e794934e293929a594524a8fdd629fb151682899ec514e568204154a9458c96928c978d8228f58024f474951e8d66742b79a7326ad40dc1ead16ad1495e5f2f09a4d9ba1cc4ad58d51dbf1f179c5d6b19a7de10a8794d9620d25992b6ef751698d29313b5cd447a53562b0c6123af0f0246f64d6b8a98f4a6b18ade0de8f4a6b10ad31e43c983ef41c6a438c52cee9d37bc9544e29254ffe7cce9f53c678d3f21e73ce39e9ca63cd07200673360a06955aedc2d4d81b125607f8e81e6572b95c74d25aa5741e62a2e7a26672d986b88342eb10b20fdfb575e3820b39ad960f0fcf09ddbb1099fcae6a5e7eb1c7e58d0eb4f2174b498c541499743c5d1d4f97cf68b5513b45a698258d2c50a85ed224da8e636c9184890cbcb0010a2532d040230bf98891e8196dbcd4ec758042082c48d810bbd2f42117a12145c84f648c6d1187154c50bc40075b803dc6193fac3260c30e2fb08113521c15812dc6b75fa66f57b50ef7cda9aa7c6863f3210f34da10809391d31969c40088001ee559f783fad5ea06afbdf62aa1c5c3a65b69308146467d138ffa26fe446a25e5bc78607d1341a358dfc4d8174343e8adff586f1dcfc65b677e1b1b4e2f309c9fdb6f15413e6388cfb0c85cfdb266681100af71c38e31cd96cbe5aae1e57259b9d34ccd640694fff13287069ecf6935d3b3af9ad8e8fb0505cc31cb638613ebc51a45bc44d6f7f4d477d8377858d5743f35e643ee29752b8616264f7dd5fdd0cb2e36a298611d57ec40ca53a7e97ee86a3527124f8c9852c692132de0d4011a37cc39277f3468dcb035c6539fd4675aac430a4a64d1061a390421871b20f556ebd82c51247162a3aaee87ca8430e7013eecf1a38418c62a62b8808a18738c4184d2186e2835c16820c3ca4f47a175a2521946fcf498181414cc0862dcf0436f2ba805366ca14214050e2c5a60c3705aa2d254f743a7f8518502c2d8a295a5862c5494a68065914307b09ffe72698e00b03009a1a407208a4800ce2b66b431e79c5a10376ccd137c094f9d6bed10460d3fa76f4f6354d6414d28c078499146ca065f54f1f3675a32a4dc4a63713c75da1a01d3959f3e271a472fd15ecbdd1e1e418929892d37b43d94bc48a3c7dab06075af1d5a424d58b294356132912a113e48137678a22f10a2552b2218518c68e95e1104334962f2ea9bf8a1bd4a393083890923e8d512fda8a446d287d7b7263c25eb4a6ba5334a2ecc4725299862ce90228d1c48c14555c4dd3e2a4d31a43ae3eaf8a834850f5e4c81848c94fbf251690a16c09ce0d68f4a53bc5a2aa881246fe24f964a55caf8f951290da6b9a48ba78f4a5d34b1f7f8a8d48594d7334bfa7ce92c19da55ebfa537cf1708c4c4dec162687c41dca246fd8ab5898dc8931f6c7b02f067b523906eb1657a00bcc6b80698f30b98372728241200b16195c16f50f51b4bdb97a7173d5a3344bdfe8e0f617daa5e727b963955c579efd8b67179185d9f0e0562ba73f1e8e634d94136a0b3beaa97552cfbe19b10a9c505cb058b10143e71f1d4a36ac755827ec6ee2b975c28ec173d84e3c4b7163e809f5c22ef9d609ed14760acb6485b1304c0b6ff9f121c384963401e3c376f2c587fd0485b2302713361fbba4752c119125b24496c812d9224b648f2c924d6247512f32573644999888f437843e691d7a44918ee8113d62a424a6310a48f9b1e046ec1181cb65c56eb18658d7b625625e7f2175c2407f2e48699db05fff923b36266fd857d757fd62eea6670b93370c037bd54093131e3072a463107bda3b10c3f80e48206cf0f2e5d3edc52cbf630ab996cca16e22f648e7796461ecb64aebc03c3b770c680774400ae12e4fbf0e4819b304a8eaa8546dd575490c19aa190100002000e314003028140c88842291482c1e09631e7e14800b859e44804e18cad328c87118420819420801220000002232b409003ccdafc4219f02b14d1a0f36d4410edf7983068824213ca2d100413cfcef8e31097632895c7edb6e627d04f13b4d637bef62e521e01c821f516394898a94d04c6b3a70eb0aba6be0dda8db612d9837ed1096477bd86303318ac65ad9df4e90a17e7a2c94ace5a2b27c62f6e313aada64ac153b2b841e1af8e3094f2603357c7732a61d33a170efbb473231d73ba5e249e57fd60c5adcc4a4fa9c10d09bb047689d4e203ad5552dd176b9df2f9576274874505b859010ac8477fdd93a73fa18a27a54835a0451b529f3cf5f39cd0857d46462030604ed86b8a9defffef3cd8888bc8fce1e1ff64a7412ed012fc46275d40c5919b7c008983be74db20eb6e51fdd2e9df1f146389babbc61a7cf481e33e0eb8f0da7c1e640322e0e753eaa3ade005d322482aa22d8ee732ca63d9492467763c2f1d69d853a57c448f6a6ef740db619964bc2f5c2d3aa9303e84e4600ef67a1daa4057046beb50d69e3a52998ff989f6049063503a6e5cd1bd08e353edc6bf2972e421ec34c1131b7efdefc879d27f6c1a010c77a80e8f871bf49ce649c64cb0cab3e7752d70b1562ce6f35b7a6ab178c7dbf868c05c2ff6700353ee8436b418fd9818b2e39fda06a5386e70822258142d8548e994f72ab407157a2003aca1c87a50c104585a8e1859782f5fe8a3a332fc98f53dc23335be17cfd984558b74d7e96890e31284df59e5eb9b3bf2e19d2de4bb18fba40417a007532fa30e3b448510c229d21be9a2f31907cfa3075d3b82a580d96c41ab1ac55d7b7d8119265ef12b04bfb55dd1d973f05f9d54d10bff6781ca3e50dadfb7a51737fe762ec75bf57590904db495e676b134e9d2e08b08c6244455342ab4837520ab3d9da77e659fdf68bbb0257cd5d21f8cb954b27f8aea07bc9f2aa6a872fbbf0ba1479f528616b1185ddc52b11bc2c5ff898412427010c4a03bf25c668e443a8fdb9a0699fba06464d92f240fc3ee05b1eb36053080ec1a2170852e6f8da17abee0848295a28ef7d0e25753dbf13e6fdaafd226d78530dd98ae7af0eddfa15d261ceb59f69fdab170201796e88d23e4dac002b50a2743e76d419c96ef98af3801a5aed68b689d7e83d49a307abec4a0c6279902eb20602674874a0eb6bf49b2c9a0a036a2cb848f9db9e901df289a1213ff80de9927d56185f9d391993a1b8247495a6eb77e6e1cc900f6174456f55c377b6a533da5a25d3fbd3dab769a091fecee0402c31a1d2263b520612c699b3289053bd407f616e837b4c83e4b53840208dac4b933be7b5cf6392949e5cee4dfd9e6ccabcc50b9ae2fbaed7d37012e06e7729f2a1b38c1b4e78d993ba898eb84ba649ee37a304025ca555ee759c0caa1b74bc709ce664370e262aed4c4d09d8fb8784644a564a6ca50b2c3a621d5fcb6d6123052b118097cbad255d7097c4ca9948e99d54b7fe8176be4969f9a8307b6117c6167120e9a42435aae279417e34f29dc4c5ceacdd7b59f498ff10293987cd7a70555e1ff19f0a039b5373d9915cbc01cf32e21f99a26947ec0aa5137a02d94885d66f88350e3198434cea9026a7a4c1e6e9be9c77daa15702f40a314d60d9f350946a606587d8c0fe0086cf806961dd6ee73d43f4c4c9fb81aad30e3dd3a19705e874a5286cf5ed40d874eeba21d1d52b2a31d1124aae0bfb6772c5b070fc738d4c417e347d8581e4fa2b8d3550206f0793a8809e6f238fa03849cc0f418aa4e317097da2e47faf279009efa2cb84b3e5d4e87fa31fa09344b57bd1b4935683409ef97453db0151cd208aa68ea075079accf6c68166380aaa9c441b3ce48afd9d38276f3eb18b09a0c15e0652a4bcdc4949772661b8c0190e896b20a1e28f154bb0deb1d8d940504546196762e79d087ff69b4abda56abc084f4ec2bad4968be2ac74195e7bf6c56c43cde4223d51eb1fd3250aa617f42e3c6631602e97390a0c20d6b09972cd5a006911ecb64d7ddb2b012ab0c74a8883ab706b53b15d15a02e6b31678089ea1314162788014a73b0cc40cdb2358594ded3d0f845ee30e4616f382c8f9e6cf14a760e9f889eacceee17a91e6ebfe026c8161d2d929e28db6841bb5cd93ac11c5d9e814a2e434d5674a790b29234f192ccf15765f4fafd0cccab0fb0e6ac29dcff74c1d7c5042f85459306505896e0cec17a8d1b57f72de94ffb065a0696c88040d349fc789f394eb6b6049cce4e2df1e136fccc59c21b505bd053642cc6251aefa9ef8ac97789c685579f3c35c29c3e3483a0f18a049e81860d56bd239fd40303e5d0a1e48e3f0646f18045dc41e403a7c562b9d5cd6eea69852fe079ab042ea9fc8bd69696352c3128ca2612814e1f765a4ca4e69cbee7a13201f87dfc6ca6003a9241cdc97be6466f8d51878cdfef5f7ebc197001cf0efe09ab3d5b84026f1e512eec2987a25ff909f11dd1369a35eba5baaaadc352efabda52a59857a9d460319d0b40fe6f1f2806c50f92cf5384fb8b57587d944d58dda839fdbce65079648bf4bb729dd7a49658cc37065e04fa7a9d25ca0eb0bb5cdbcae2b092fc7c299451d5423c67a56091932abfaa0e7e10d9c002be33fe41b0b210e7d3f9fc91b3497acf841cffbe21216a01673a494def49f6b9e186825658a273d68a3f4d9ca2a5fa621d0454d850a6d134173dcb8d6b564d3bdf2c7450da834503dd868a74230b1b54d8fa0d585fa50a69f1a039905670c3beffc144bfb8bddf0622e7d90ebb9f1596126670a4f72e4d97d5188eae38370fbb98b8255d25e2275c030d32ccac467ee4d2410249d7ae368c17ab1ef5f6f30368ff94b961700d533dca69ffa16499d737d51857bc07dd4941e1752d3640d811e784f6c1ac5d5881a08f7357c16006afc3e75ef084c9c9f67986d469368580ed728b64c20d18f1e215e075fda1cb35bf14d2ea8e5ad896731366cec648c8602b1d259fdbcf396114911d764a86658805ea5d2921f0a95aa826fde659b5b9f6e941bb8b77458bdeaf40e090df24c92762433245f594d6890a4de3a0240dc5b2104288e368de53761e5142c37749062953b51a18a6bb3753b6b377d79384e08b746d54926506cac8bab2fbe4be7255212f7e8483920d43d78aea12c3d6c3fedd1f5102360b7cf5c92db9038ba4a35456f45685520c80d27e45b076352ff706da7ccac9fbd9be1a990b81b9c9e8cce1893eb9ef1ffee2124d5db9626589f03b6483cac1e4d1d229dbc506a88fadb6625f71f6d7f7dabe3a300c50ffeeff936a17d42eadd586ad416369b0585abb16c2f71b8fa3e14ce8a9304faa251aafb257d11f9024814f8d15f384d8d881050eee1eedf57e9ecdb1ed50eab8a27dc088c234bfb06d010d7b2ce488fec22635bd32f40545ff8990097748320946a9d4b7819642c05ee980340d98c421d00a53b0c38b85f3e0fc97cc88c00534b809ddc2cd0e1ac6bce56b2618ae9ccf7869577a8e8eb90ed7f4ede01ff3f28e087a17f5db76a87e6ce05ad0c83fd2fc2f60bfa9afefa7521d8b669cb0c4d0cbe674a8134030cbaaa1761ab3184b6ebe91177d894b3c73ef4f22c548bd6350410c22ab3d5d2bd44834c093b0048ad736342564873ed728230400f6746b6dc77defad3a4ab3f28f6869c80bc830daa763097bb5a68b88e026aff64972aa3fbc590f98d33370e144a161404d7da924f6b19b42f70013ca092896de21e77daa6bffed565bbbfc8cee1254fb967028d4cd2646ccc903ff3846d38bbcb754991b982471f8c432938591808efbfbe885322a8977a5ed448d02c261e02233819dbab7ce020c5002965527007de7b2529925e015be0035e967cfd60657d4dbd8472c5f9343ca63ca0896a67dba36b466d2f65a4607aa62372be24288eb32bc694b50dc4f4ad420c2cff850f27c5c291008ab358e0ae06c9b455ddf4dcd48aa9bdfcdedaea86501cc5f3f209750c37a248a74f5843fa339fb39bf8fd5d337dc0b5619771d04ae157b43b788924d8a4c87346c4377d3dcbb0b59269b1fbb9bfb859651e157e85b29e4bf1dea03ae05fd36f3b5ac7e2b46d9005ed57a3312dfc7069b4cad91cabd814e2afb82bf4eb58ed5e2ac2c25cf10594f7712a908070d207b3a7cd190f58306bc92874c907b7360cd925f8eff95e85cbe661cd436d326597918a9bf1460fee3c0ecef96b798feabcd7e72d41159566d88fc91cd0f49c93f1c33ae15334158a1fd03ef29bd93f90ef84a3d95d9791059ff04e1209ca3489c73f0c1ded7decc98e64dd812c1847294591c50305941382cb91d7f8f34e301e55fbdf4f398b542e4ea0e2e2f7a890abbed703281620d0592dcaca6753e78980ab10f21338c2b7ccffd724da2462c1073fc189f1fae6af7f9fb9f749f60d8f585f7fc5f74e2cc9ce1a724e6199d487143eaac40cd0d2f3cefb9f3748ec7bba6f1dabac3e4faad03f200ae1d9ef924dcef8081cdf8905e30e7f42be24ccd8118a780d731148d41b86f10623a87cf15e4db2a234245b2dd40bd12b4aa6e17a8828bcb923f8d8ae56abd65516e0a4a5e48040e6ee5ca848edfbf20ac0fba732c6a3b4ff0c3cd7faafbb36804a515db48735ddc9af4505e4f3198dd4636a895b050311756792b07f608db6d74fd5bb814e8a49c1a3117d2cbaca052e46f032fe09d2553494c9802b22e110965539a8baff54b93bcc303916808d19abe0424a29273b14148059ce0c7bc837b36e2c080d63c20065e954bff001a62b86c5f661b0fc83dbd00a249216a2e0ecfb9a98a9c6a263677eea7418698360aa974eecb10502ee098b078ed22474d7c3a4009a71d545b03ec4b55538819d126a6508de96e545854fc27e5d4ffaf6668921dab7f9ea603c03b182bd64b8af86f018e0587d4aa1ffa1eebf42e4f5c3c74ab13b4c8ea1b7a82941aebdfdf8d5128934e39993b55fdd6de9abacc9b5e078e74cca9e07efec4091ba332565afb41b7a655c9cbeeb89ba0606d41e00943a7030870c3a2867fc02740d1a875eceb35ee6c870a9fe82958a67c46b9a12d6d476f29bdd37467d65e6de79c49b48c7df41222d79a4d5767c9128935e792f30d2cb7626dc477d9fa25c6aa826d6cec88463891a8dd8e74307b298dd4b863c25741bee433e19de8e6928c6e83ff72b7d230276dd79d74d7e1199b5987170faf4a27d4263e4ebc825b727255365dfe9559d137aa1b6ca75c82482e1ccf67cd45dd8cf4b58fa604bfb2035e609d8237b45013171dc0b3ad620316048016268bf62b49a0b810045a2e820f3196b8f562b107f6b0dff19bca89fd89f965875ff08c6c2f86d806d65b8d51b10168ffaa98cc5f862cb56dde864a36646d805ca11fed931b82497038ee77739e664a433fe8ca791828fc11367ce203c703854596be703152c40135e0f945c14eada1a655749c5f61cdf08f326c50c469be98e4a14cc4669db10babb25e392f9d9adad613ee0efdbaed9da61995c230c0d4b75f8e9edece2aa14b1f23382148939f93a670cdfacf1b4148ff3ff03f565d1a7a38db2a19891c65f5c7286d2daefa78007ee07f2620cc4a679aa3105f77a107bc227c6b987b847b3bb6d8e7f0dea3a099fcec70a00fc65af610f494fe3282886268c7feab5b9411436b193193fc1edc9b0b8feb829fb39872bb4b9f93d0ef45ebb36f76ade22afbc638e28112ca743036393633651957fee9b280a1ce1c60d5a2ea2ee9428c8e042f33916afa497d8fbc5109d9574358c8a73613798009bae3130dafa0a2dc49828a9f870ffdf6815cb34117fd034389c856ffcd69d76f919b0f371b1fb288165cc608a9ccc1232c71668f1a5f43cd8dbf0eac54113226ec28d807592bc54a8fa477d58e6c591fc80cb0b0e1cc560f49aaca8f4f81fb475ba6079666a51bccb87c71681c12333fefbeee1684c38be0412eb4b9870d6c59a3a1f1e963bf461ad024eab876683f6880a8a521ed085e3e842506d11be5850e144497ee5d7e33051381275b2771d360cf6e6f597f1c7269051d1463f28671a333a5418e8822b6da03dce8b932ce09f6b265515952d1a2f424c00bbd3baa9f0cc7f8dbafd67b75cd432d667033569f2c1d24fd26d8537619a5c4a18f0da0b5d91d353e44085cace1367fc78f6d0b85d6a69e61f60293f94775d544e9832b77619f08c104606abd32b26dd3bf1b02adc0cce117b9bff0eb9de1136adfcbf84dcfdedc1f685b63d45f31999e00742d47dd2b30edb312318c11e2ad0b92beb2dfaecf9b0f86a189788fe34b208d874579b6339a800e3ceb3cbd40e509ae5b12701984f9a59a5d64a4d67f14a9f6b640640c8d4a2836d3a0584e5743a07a482d008bdd761ffc3d5817afd8ede6a0c30eab56803a1ea002976253500407204f06b4e70bac88b958cf933ec048f496757b5bf2ac9e78535a01a4b286e977f5fc25811e122cf2dafaf611b3ae56a7eb549e8c05a77bb374a3986c16db412f5939f46857e14927014f620c3be98058b9f0e56bad9a741ccd143f7b344b454f05cc534b4be23a638f33c2404f3b3c0698e72fb193a0787822e69d6cd0b56d8e3780c2e42c9692b311c47d23215d71f95c1913f244ccb11d34ac69d2592eca1481e838bebe9b873ac8c15bef26c9673bfa4319be356334601ad69fa69775dda99330e38f51a0c28e73b60d3635cb32de90578ee0ddb37aec2207367ca6d91138087691a340fc4918325bc28b29635a2c0d5e5388afda4aaee4aaee7da7489aac7d12630dac18dc71ea697b5b443344d6f7aad9c8a039ae244aeb4cdcfa73ff5f133933851c159a19ac76ad4abff8fb7d588688cdc97e6753e18d17451f50c5777c4ae073ba2bf79162c318a83ca99cb1c23be3cfc58a07f47232489c06f0b205d5318572a9e8d68a0d7796abeb5e2b8ae59ad00ea1c4ec030c3ed928a342e1d213b668ca4bab545b5b49e9a893d645d0a289513f2f96189ab528a5afbded4de998dbe53c8f7f853fcecf45e910bd3b6241c37b3c02d05b68a4d7b9afe7aa6ff3edab969baa14085aae8a920d661da6ceefe38ff6d1479bcbbded3bebf5856989caec88b125692d84160028e592d5961e96abdf57ed2d78c5c143aad13a0aa032f2f9cc74accea45690482044a3d0a8ce16e42124ad8eed95285d1b6af460c4c5204b07df1dc79fc9e65ea5e3009f5ebb26019c11d127b380534ab50a035647dc19ca70a70284db077796dee450570977b223b0118c4b962f40c22f819d0b5cbb7434252aa7b28f0d54da5b1182c0d97d6b8e211c1672ab2444420643d19eeef35351f408ff34d5c0f18ba89c01fcf26fb57963c4fa70168d88a687ae41e4db5d4fe548046184cc2a1f1c0814b02032ca5e522e9c0b2b1e339453b6b83578b8dd15434ba6c8823d805641874bbbcf857d922abaf85a6219c4f207218e369a56270cc205974890e435075dbf68ee36c464232b8d2bd07aa23cd9cf3f791bdec75c28fdd3728f17d346dfb478908d67515772c9c885bb51142c9b697164d764a8b31cc2b180623ae3f3a506d1417aa14943750449a8c8bbb13b9af5629e772a0273e4cac737cbf2a5e1458e437a07d1c54920d470d63e00ae6f1d0f1c2d8d4cb18ef12fa0a35c9aa940eb525bbf7281fed42e9137cd43beaaaecda197c88442fabc93e5497d14d5b1590b4370e310e2d666974fb94c684ed07873d572639a48a1968daa6f6ad7824de26e555c2d1bee1d75cf4e9192f5dd6da38397545814081704e8b452d52a57b99b63721f37346144005ef2aebf00a3b347248e02b7c7e5c368afad75826ccadda52054a68e8ae882f94e1330f50b98096342aabc0d276e4a8edf523f7cf269a3226ffbee48ba9491f361c658693c6ca9d3086cd98cea6abe027a011fbd7612d795b28531bf874f74e035c6b71713cec8ebb2dabb3a4fcd3e5abf0fe32c8c7270e7c0c51358f3c1fb8dd377cc2d9e970e9fbfe89361593450089f62e406b116ac88cf815cd1393d8a894f899f9cebcbab3afaf38b9486617ad97ceaa77aad6e8234b6a295b8f67cc0754374b2b1c17f6042c4cfcd27c4e47d70b9625c2713f1f140d673bc93eb878262a148db4510b180fe994cc6ef3702da9403d3afa29eee51e7121d39354f6b95f38e913aa1e7541e0c294781b1d6678ad054b06de4c16a0813b43487b0b3e0360926065c552339ac2436fd834fd90efcf2b3ea30128733c32a03263186b827c0ac155f0b35a107cc5a9457418133f7802b21e51ac376c31a93f9d9f461f629cdfbb1b5409b73567fbd3a3e4908f0aa0811867ee922e813ed5a063b19138a9c8ea203cb229b27295e143925877899e9db99aff7f61eead1f68496b53d51adb29a3109e46d523907faf778ef3891a27a4c7ce7d23f32cdc77b32567591cffd74521b36e926ff2e2d3d802fa5eb9209ed8978f6f8e84c479879217fb14ac95e290e4c405166e9e6ce368ea79e68ca7a68d58565dc06ab8a43905fde3d2610605899481cc1ab662a202148ac591c117d732aac6689f71f36f07a6c6e53fb41797a8788f7fa43c7109a41d96b68deda7f999088eafb0e3f60b25ae6dce8b985a065ca2db71864eca1d95e6bb947771b8bfb9c821fc1cc0358c0d6f078830430747037a0a4b58c5dcf98c5cfcce0b964ec1ecda65b87230f8277e7b4d71d0162e0032602f6da0aff663e5cf72c0e46645099e6741523b0c8fad3e6d9ed04b49d29be092285f5ecc6bc9015b25522c2f942b6254d4d91920daf6631b797993d03095958223f6d95c121fae61bf88f055e6a7408a012efd7c731c0c2831e7ba6ca4e952a7780ddf05234477037e288881f1ea149c9d097d930879b325fcecd97cef85b8521bcf432672906ce58bd41d045a8529d99b8e5b772d5c38664422b706c003b9d8e978ca01aec69a9bfac44967a23cf3c45d9a154fd3980f00e1a6738b1ff4eaa524f300377fc30e73a4d8a3e17bcf6f5453d002e8391d13050b44305d520bcf7cb7a2f1d8f7ef2084104bf02271a3c4f35c8c56197edb85a61d00932595f2f80952242665b5a4b0a674949169a8cfbd553433ec8b84c87774cda7e5ce1a7e73de34cd772841e765680593b3ce25ff44bd96dca9cac29d8f4ad0bd667e4651d0b4da90ad53766d47248a0e2c551187a4e0baf8a5166eb4237ab01f4bd622c6a6710fda808445a1d73ac4e4e87b2a92a7028b82fa6177722f6a4dbf704ffe3b422cb4e90c25eae43060b639b2980b2d0cb0afa84a010cab80da34874089b51d44f84e78f8edfd7107517b80dd41f04dd81287773ed45feb1540d2e57228b640676b74636bad47c3a9ace751bbc437874a258b4368c8750701d987006b71544f38795bb55499458eb33b23597ad8ec114092cb167378288584b4047a833e1df168560e7bd0bced35be5a69fc9ca508edd26efd390993524a6e8013d435b99ed56c3213c2dc217268557b69182aa571df04ea9d1f1cbc6dd446c2f27ecba2e42f601aa2433901f4d18bc140495a2182d6b0f4acda769cf7f02f3c5e3e2b05026701f620eb0b594dfb4f941e68c3039693843b3e25e2536bd012b1bae142bdf9a839f6cd6df0b3ef8e3787d420155557def6889a0842ba3c8de26a205f74f9cfc7cb69f21bf48a00628b55e1dc90ddd597a96168ceaecf170103a0c9ffa8b41d5fe04f34479746f492b2bc59aff50371181d0685858a141d560c7b73561396eef8b5a84d12a1e8c01ed84d81932d5668232f31683db3c9810516650dccb10f61aa8064901cfb4d71e700aa884b28a9c3aa85f4892f5be2c2a6983cf86573f07c4464c798a0fb176c94a72c12a6e3a1da2760d2bef5751dec3ebaf7a187195725bd98137a974865f60bd37dca69a3c415508a4d031492c8af0d38a5dcdea2d53d0adcd4e531e0cc7304a5b817e993f8ed1af22435c7220f407d6c07dffab085dec9fcc1031089a9cecf8b81a633860cc40fb5e57908b7e95fb86518452a6ad52cb1913cd0f0684ef8087dc5b28956e6d8678ec144a7ff27a2f89cbac95456ffc7952cc476311c8a7386215aa9c2a00b8017ab8019686ef1199658c2043a77d9e8306699d808089a7e559fdfd774e69f5252f92a25eeb589eb5a776bcd570a9da75ff6821d3af23e7cd00d11ec1cd2aaadc01533ce90f1b9edfc7a117d3b3de69bad67f897ef629ef4949b5657fabebfaf5960cf8e8911451b2249b7721cd082a62d4ac4052d4314d97579b79f7b7c620ee8e9a761e63037ffed606b7409abb81f5dc54a0bd3d4a7bba9e75f9fa6cfb44e13b29a72c81bbb792fa8cf025f989ea847c94a3486bfd39893d34ad6557a8557db49dbfb52b4ac797dd45d7ff297bdbea8e7f4f128c186cdac8d5f7cc91969e0cf4be6468f76dacd611d6ec69e082c1f363a85556aef586f4272a57642fe6d68287729509e56a20f5e05da529228ca40eb2cd2e3a21e210ff4ae7eea4ebfb84be4e71f2f2d82f2cda8273b0ccff732b57f6ce486c8ada3918c2b2d257f6a2ef306669ee92d8620845dacc5eeb480a97b004cbf687da4744a448b821f102d854b342aeeacad9f53cc7e4b1f849adf2c22f81616e6567097eda3212b95f6f2862002c0695e092d47db57515f1370c63f4e8590e0b4a19f82f23f29379b06dff24c9b06ec524e97d0efd4812c2dc3a92e848e6e60d9f295bfbd73b5206286d937783807d0def12e8cdfccb44a173423f312b29e4aacc08d4ce3191806cf29f44c56b45ec0c9cf4e2ff6f40368db3372586eda91a0f388774892912b68309fd91cb7a71645e236ba01233c4610d8650543e46a0c08a57e07fb4d0271f427f1d3fcdd34f1c35dc71ae60d1f360f0c081c5dc69d8cfa77c92e6c2085b3babbefa4b90d661ee9ce316ad42098fa2595b44093351866ea2b05ee5c43ed5820e2398c7f6f9bdf1b9a33cd9503584362285ec2ef3d629bec2ec68e51a99733b6da759aee50e751725689adea4cf1d0a048df97ae847e7b7a797e03eb5492190ee94aad8d3caf912ff4422e72347f62e8a9e61a8eb50ae3719532b918a0a7f9caca0460e2ca6fa7f54dd36d52ab02d21e5ee081de184080ec4f7c52ff28312e840764bc2cf15806b0632e325266952351590c014d3d942221e23db88d788e75842a279cc794adf39df3b7a202955e799f1614d1b2d8445f57d8de53a108a7679f90d3a32200fd8f0ae0b2def41eccc4ed7a1ac75a96369c9dcfba34ddcc60a46fd3839ce0a95e1c630cadbfd574e4cb47f9384743f86a96fba4a798c34b9c5b669cd56d609218864093ac06e2f2a1400c0c0c32a97947f460882a75e863c6c6c0a22971010ff023b90a655a770f24c9f170952a613a7a5a0a04549543629cc687f8a75467bc80803075b757a76c32bbc454a293a9cd393f2ef394cd0f94203cd639182d0645069b418c9c09373099631d4eb4624885dfc4077d68076078cadd48652b8248a8c27ab2ee90f446f5bd1af6619ea70edf5d0289ab39e29091cf25f48815a8b5dec2e71b2a9c9ee3ef136fbcdcfbdbba602cb8146597ed940a904f5a0d7e485bb374754d7ce8515e949a15304d09d6c3038f35839f6271839985fc462bfe776478307b5525a4c45e4dbf3a049b81380bc14e9c0a019d6ac2c91b33f2f9a5294d35f991da19efd9546fb3aaf5a0c289e4ce711ceb96ebc3d131b4afb9b7a2beb8ec13f1c96845f5730db75f02a0119c222cadb4ea41557e1210d1fd4d16100054717bdecb0f1fda006c6c90a17554633b4316929a20e079d344749b0a26095eeb84a293d3441228436a13ca655b470601065caa44977e926adb270da146bdc92407364de277070b070f5f50f11ca4e12ff479ab540b3650a95579951335b9fb3c409d44eb409a2d6c659a38d1054190c52e0cb10feac4f9fbe41c332844f3d61ec5a662acc051036988763d71b9e223fbc5a1df1319182b8935299cf53e97be074194091331340bd90f7b98a957b213d731d0649a09c11150d882870706bf0c447c167c71360745755990c7339a7960d735d6369a6db0de157df5fe2019bb43e076cc5285caf2b02810408d205692701304674d0eebce835302e0563d5bd5f9978e9e794b585f708aef2bdf8dd2f3f8d911246f4249c9a14b24e0355551a60e04d74c91589dba72de2b4aa9ad0d409411617db9985e1f504569885fd7307948ef7f51fa4689ea3bbfc8d6d7cdf1ce0e08aceb5a28bc69fc5cffb85f8451ebecd379b113ff6866c6ef77c3b97c2bda6652d07904095b0baa1453b7f41383b07b92c22b7ba194d5efcc3097ba47f388cb51c58feff61a485f6a83ca99d3a4d3ed854fb01ec84a5bda15b5bd7059ec0252a8a5c1a4499df7785ab296ea2e2caaa0259055cdbfdffb607e0b9fc9ffe6033cac71410734b659dccb0966536dab7554d131b19a0d4656020266f554c8571d305b5187beac947f16af4cbbb44348b82cf433d4f3b41795e400119ff5172c27fa5e6552e6dd30a54bbeca7c93f47f0527d219896df772f1cc0026e20b5ecff3b2de49700da8a0bb4224ab9058c1585bb219632e55bbe099ac05389c7b855a84203ad7261c60b82aa8169e1d6ac15cb25ab4268e88b96159c9f53afe2f47d56a16dfd4f7b9a1121d8306ad7dcfe25fe0371856dd225c5f8b58bd9d38913b688b79ff3f120401cefe66d21004dfc98fcb197e84e69c2b38a82d6a4ed051b767e701d31ebb7b66ae5cdbf7836b6e7fbd10650a4881776402244a4395693170820e20228d5f9775fdd3873ce7fc002b7ab838c8f3f364b9c2021df114017691fe895bd336d4b7d68b37bb00371224ba206f2d4924b0900a3d65cd049eef9a9dc45aaa938e0f64a102d535f9c6a2c29299e86920d2ee9bb454cf084115589aa20b7e580fb288de84b60550dd3939da5695c9f393ddc54d3667661127a58729adf68381bb8a40c1fae7a194635e9be39c9e9df712d979c9c3d0eafc1c3b525092a16fab21b0eb75928123464e00851476264a89897a029d1077de3f39f6f9d8d1b4aa0246dc598fdd45c861d1ab4dabf22083bf8aab844c0232eb0020a1234160dc6a3ccb285ee8b8435dc8ae9e94176a94119226a111f17e9833d6b3bd697d398431fb0cde5022a2974f17f9b384ae6a5d02e22055c384251d8bb55d61e9e26a8f1aca5e092f0404b3c74a4f40027a48495637c1c113dcd0542c8716e5f8d06b2ef38372b9098aedc55d382f449613be2fabd10ec1c34c44b4050de1c265af460bd7319631dca0c0deeaf0cd8e1ee91deebe88ff09b60a437895d789d580a8399cb4cc8a081e3d836a1bde3735e8f1e417db1160b1dc2571dd264f5fe46e77b913e82a90fb80661364182520bcbff2bbf00f7f38799f6228a48a31f8bc6a431e07f40adc616a0e3d1975bb6deebaa560e5f44d89378588ead1f726bf403812a143d0d9a9ce58a8b22ed1be57cf56fb3fab11db9d16efccc0a6c24c01f57ff7e17bbc4df7d051c1f7567d2d3700f685326feeb3138ada41e3debe58d3344a134e3f5a6953ebb32a87942e33b689aa86cb86ddf1ae784b0c405c621fbe37420eaa8f9acbc7aa032c9c3c43097876a0d5dfb523e2422a25bd2cd5801f7eb192d77f589046605a549849cd8d7f2ca4b3be16860d317ebaed97c54b822d4394c37d6777f42f88bfca93d34a95eea4d06c4c966824d43a2ffc74ff4e4042089991f4744554c026e93237f8e82472b62ae7de720e4ffbf017b7155bfd38b1eef2b3126df50fd0aa30139d24bb66a7f98b9a13dae403b7bf86694c2fd037690cfdb803266fa267c7add2950a9bbef00ba0968c96b1fcad1ad7aad31675725107102740f8c0e4e7c20def20ee14042006cb6ab5e2773d5c0c41585712777a0cf460139b1cb3776fbef0d256f671fb3d9621fcb0bfd952da8c065e78ba8ef02b2effca13bfca47b7d59757eceb0cde99c2fa6b2fe25e0f1dac97788f4935951f24d7bdacb1c35e186517e2eb53636eabe19dd2e0c28ca786f545699e0e1f7bfef01c4d7fda121d2d2b3a2c0ab53ea8379f7d56a110cb3fc7422b38102051083860460acb290868b73ae5dd6d2bb0dd40972405a69d6e12ae914423931523727ed7b80a59d0151a97d6bb8c1606bc996d55f85e3c6d420f32bb5018719f2de79926d5ac1e6e5bad2151065e78b79f019294fb9ffc5d0e0a969ecc359013860b28d7c82d66fdfdbff3c596bad9d7925ae6c134ddc6523226c93a7c7c04c5b532d1453921b83875db21b50e1389529d9017a5677d80afd35474a6fb43e6f8574c96af92a62a02402786348bdc99bee2611bfa72605fd943e9a5d190d9816eba95ae39b3014165b468e24ee2cf7a64f10682093bf80724d7c89e9e032df096b29b314257643bee3fc16b1bdafedc3954b6470b9a9bf78920f086dba2dbb7ba0fdf36def4c6c661010fe69c0d4b3dea39697a2d235adfd7766c98c575cd35e4c3d2835443c568e92e2e41d17a7ba894a3d7cf3fa151dd1bd315e4009573b3dc88df60d12f0dd242bc5f808c0ed98b61ab090ffb4756b1fd5e4050b2a8f4ff544dc58c482630d06d41d37dfca3ea623ae7648fc9bf12b2fc515a7dd6d6c1cdfb89e4dff567d1dde92117310897479b460754c6e10c8d6cb4263ab7525e8d61faf2bbae03f7de742e76ed07e66678c242ada085e8321c6c6e39e6f5be2c37a54f449afd47cfe61ba131061e558c35c1981cd69b602663a835a8a50ab7c96b72e8fcd1888aced770bb9b7806b5e1cb64a4ee778d9f9d406aeb9f857b5b6365637b89c44e4bf51d4621947819f9cc8918f2bb821522b4ee239fd7b6ca76050305b28499415a997ae550e840672a4c423613e21c028606da059c75e23c95ebd8d0bde0926b4ab5e8bed57634401bdc9823f480017a54580876f7fb6ed58dd24dd7ca7494c01a9143de1ad6e644674905869cd7488bc28f7f7025feb2a42c02a331c9bdad0f25c7902a0225324b996c47138f7e2a4bc9ef8785202e6d1d0062afa9384ddda16295baaa6c841dbc18bdac15292c709db5bc566d7edfb671d9af6dcdb6dee1907377e4511c5e20c352a19999d04128065c45c2eaac909afa12a1f67b462e363fe1b804cff5d00076ccc3fffd33fc5f340819176c5759e748c717f64fc52638f10681ec285fed13d0ddb23d9b069814d2ff713660e588e6d5ea8b41014d179e81c1475dca0021482d1fc5afd9befeb007a9604be53b284b7ea157ae9d428be2a78c5d9945a047be4b92b8826ac9807f284684bda545209055cbd1fe0f88545771bbacd69e6bcc4d6b813575b15174bad32d676c80d34713204fe06b0066004a414345f88bb6f1d1dac3d9e7028d060ce7765be9388a966a9a1b996b93bb8081ab629553852e1e14ff611ae4e9b4c25b02e9c6b2ad823160f5f73c257330e7cc10b34ce3dc53c5d355632e55bdd1e81959f726cb225b61736555e059cd6b192164e9403ae277410ee5954b38e825bec398ca2cad6a9553b0237e1f25cc03ff7143db1ac64a320fdc9ab4323cc93a49fd2f79c23fc5b9e1dcf98255fd18728812b8428551baae5b96b322c8555db40361c2187b3354efe35996fb45e29ec91f6522c81b5ca4a637fd717e88aa66325c51fa33fcd7216045a1e3a997233d60e0eeae555642731d95e203fbcd22b7644cc49252b8d4f8a588c13cd8a2d1889196ab96b97eb2c9376540fa936a965d9c591a3d87309e59507fdc0607759a94be9cd2dcea2792fd18f9a73b737e93eeaeda4322277ed8b07253b228b7ec857c93c1d0e8fd002fa51a978a6d80b3fbc44da125322da9cc10af5ac4cf01c00a77d476b94498c163bb4b9c37141bf6f15e4839d106f3fee4c204b234d787d53cb6e264f428a41bd21bf228388e6a9061ca3df217754848e2889cf03c4641af379b0680a312a56f8c1c2cde43cc22f7cd0ca0f1a21b01ca73d525ec6b64d806b919f96d7b9244f89de500532f6f19c2b4268cf06355acd210e516bee43007394f4a7d50b8fda591fa2837086fee765079b4889cc9525847dcf8ae10790e7bf76f2794ea8bd0e7349b47e69afd02a46c940d0e686020480526d828225f17a4ab4810cfb8259978968d0fc77450f025ef864ba8910fcbd6e57010009e384c44e6a008429bfe55808a7eb1d533aba44e829681e97ebb3677ce42d81183b3e1e8f449c2da1a3d63ad74856f42786bf29f3194b92a2ab56f99f830abd788de15927e630821d2bfdf950a219252cffdd4d63878313779fc8c5bda8d36b0257ac7a73ec4d07650163bd61a0fd6b560a2af5f40cf9b831612c348ac23487d03609cd02f068a573910308734a811b8347e899959a81b56b83f9ded77b24a657d526832b252911718fc4dffebbbd7ed9db85a9a6b555220ce35470a3ebf5d34bfa999a3ff7317913e7c5d7734d931b28b358a9eae679bc084f5142426da75cf5c0cbd7f3a46362b8b8ea385cd10b2b915de2f5b382c3849355a17ec4d2b5c5af38565502d8802aa886279915bc19211cc51f3e67140c61ca97bbb27041b49355ca7c0c13d50ef232f666578d1430a467f81d5d33f83c8af845889d9547184e88ec575dd572377052c4b666ceda4ad82f69526b99020bf9c73be24c8fc7f31dbf6c309c3a840367c0336688ec9cd802baa88cf2261c6e373a4657a4160987b31cd22c547a235fab325f6737f24efad1c3b514c61806f30951f3e3fead506908574aaa0da4b3721093a66d87c1e539c52fa4f764c0d7db40d71b77e0b28b6bac488ccd936c82088a83865c71b975bd66d89073243334d1731079fe6c9cc26dac8928dfc5034b8ece5424f39670c0617a253555ea61739ad238e0765ac0f0e8a487f5aea5470afcad91b89f02770b195e4115d86583805ae119fa50326dbbe0c29698d948fef38b648f6016d6180ce22d85234a7f388d7a7291031a3fbf7183801d52fa1867064bd84763344ca01771bc99ec1492f774be359da2a51de95cb2821aeba8edd342c06beca3cf5c00b448f95deea16928ae7fcec9d4c6de7dd6978cb0a96a98e27492160d49c68364ee2a8c23269ac81c835ae7a4b3928ee50131331a501c1e6bd21ec8bf67dc02652909023f4e89a12db466050150b569e7609d20129d7322d8d03f6ab1f5e4e78f1049f20ad9f83d789c2ef75ba4801cdb13811ecf3d7c958da6c43f01b302f2fee4f524341cd48ca4c229f9a64019397fc4b7c96ea636af3385b985aa760444e1f881ef0fd4671edd538c42fa4e598fdd30277943677798c66680664619e8a7409d5f6a9a5ea30b20eee7011437063a3a6873cc22dfa8c5c50c8139f0147d805192cc83ccabd9b11f31fef820c270eeee9d14cbbe35aa9ef55887767f4ab0b7c82e3307917cb594f05149979ed289acedd2b01e9aa10ddb503c1cb5465562418099402763c6de2798c5828a523826b13713e014471ae9245c72fe40deec0a0e9c031afc947363de3d872962423c42a915923539dda4cc99370b1af066752a24379df8444c1eab5842c5687b93ab1bb687f8f31b2b7ad24cf9ae0959915036c8b3a25446c575ba384714c1481cefca4e1f79d1fe274bbeb46bbc904529acc19182de472ae5263d0fa20589ac4777b775a4a8bd37b03b2dfdfbd4cc87eb03921fdcabaf54c53c4a672e6b63cf4d711b1b8173a348b4aa118c53749bfd8a207752bfe353b7c1d59434c39f08ef473235c1d50389965b757237558bc823e910903f758fdbc6fed08d5d3f1788cbd272dbb172715c0a332c0a3b0ff1b6094e1d15462bf0293709f7fdc5cf21e16980027d285e63a1de9842a07c0811d19248920ffc6a66a0675513686526b645972d71235e1611d92355d00911e28450a5e2e519cd7e0960b5236cbc65615b8367409b26565714ab4bcda6c9230e1b7d93f37812d2160f114aea3038fc3bb37a6b2f21d1da5a5ffe11531c414ab1aae17c07f2395f4eaa12726e4d24090b5ea8d5bfc17cd7921d29071f8e86770c13b9d21aac447505c9102a675f9736dc9104268776589919aac2ad2c516ec2bbc029107940eb6cde51c654d0fa21d7d41052c182e966b46cb2fe00988d03e8b0043f2a22d2edd0c894300e8a5638c85dddd90db317187a2c21424f3c796a1d6ae0f6b9ef5576af0ed5663c5f32cb8784403dc5e042948ef870dfe81470b0d9eebd2ba6e1e67f2740fbd7cdff84eda151d09110f1821026b6d09727e8ee9e5e87e645a0dee9f056fd0082372ae83c914f57fef820067935150ec28802f43513880ff008f589d015e0fcad58227996a99347b4aca2cd0b8bba4bf7dcf1a8ec394ae99fbc661477de6c7a9fb133e3d7899454d3d7877a6d6086e6b5b1f3c7ebdc0cefa0b9215dfe1af6056171d1075b04147912c77be618efce9404696fa6181e0181f88582e0e979986591fcde6723e1fbc20d213a18e6286e429213220c1a64fa451f545510b31f5b38c5bc4d4f8bf578b95ef1e7db2e5d8a1aa780a2db988a3550e8dd0fee2b51121469a4006badf8a7ec465bb564e8a05de8d656903dea4d321b61277f288d846af9efcf6c3c76140e4591eefc934aa1b48a89e69e959440eb32e88bedc03293cc92e9dd5f4af491c5367a7bd57c56b26faf81b51a999ecb5d76eda16dbdaf2506101687191af888bd91291052e5aa7dd328c1d41e6a3d463079455a916598e09de0f71b89991de0a80d130e7e034738f9537a49f7c5074cebd5e74237082675cf68a6c5a0876d234dcab4202a8e108b82aa28e3ae14fd0a3f880b9643cbb07ae504da7acc246aa54ea442137b9a8a58107fe688c94f12509816093873d697879abaeadf88803873d044bc7d22f0dca59c460a9e70fda88a9482a1c9dd4a8212e1e2940d19217ee65b5f7f99d71147675eb8e9a12bb14dc4d4483b9c87f3e2f47b4c989e89f00b6688de97911204b05d86cd211f09230ae7f0447ad737381fa44d6bec3329a1f95c9bc713e610456d2a7e9ace49a2a1ea35efc1f7ae1314eb5f12ad1d6449994da29f07bf95d86c907f0a71e0aa0633b2218a856c459c478379aabcf900e257a5e00c26b80a320669223863a7a9882a2cb7f555edcb9436159e905c7b95c3311f695bdec1c14c6571e0619d4ccb2a91a1bb436fcd60369b1a15b5b46f7b18930e67feb904e8d393a6fef2fc555dbcb205ae39c07b655191730e939f9d540cab8e1cee72654c1de093d8c7a3da5e69de6fbd7598d9ae70b8924b5b04fa01f24c0bf2cb70fd35191017d41fe907e5446e817dc6dd91e05bcabb0b4c0197272fa0afb120b5b1e139a456c19615fed77ec91e36a8dccd014f581c2068c18d22705471fffb7859c8d29095afd40895d6c0ea1605532db814533d0a9c4d1cce454babf0fae4152b4d50d1c351673bce95c8bacd9c411d597fc21699f3386ef94e8d949cf2dbb69a54d06ac89859fc2019e59ff264b4e17f6ca410a10345b25f4099261295aa1ea5099aed44a485b9587c20466ea4037f6e56db3e4983320cc6a4ffaf3fc13fdcfcc55712645cef0834c77524d2164287c9916b23f1438ae6a93d11887c0cd64d5a675355693fbaec490b79555f10922c786264b030daaa0ff0a7f6f396f38ab34de6944846016d6f3a4f6d05dc1a216e36a3785e2680d50f50b108765d461004ec113284578c4144904db45e999c9b1a13f3ced2fb4d412fc1284f40d4e7be206a6764c31f94dd106922cfa07a421babe2f514b0a96195b2f0e44b62028ef114498aa74ec08d62bc01ae226e896922c0986e82e04bc821a6a39e7cfdc1c0cafeed2896e0058f7204dd4e9f52daac0b39258c6f284f551d4da346f402f74f2133e79d2f3a0f8131bb9f80825cce900070d73bbf15a9225e1ad8b4ca82480be9b1993100d34ed8576d193be3fcfc520032f3f9005a9cb63a12776970d50ffa48fa8ffbba0e39d3b2e5052875fdcf9c0b33d6664003e12f9a804cd59185057591ee91a428bb74445328569cd73e0ee516092d6a2e6a92d6892b5ef496ac76b2b9aaa66c37bf2b0522bbd6e5fdc7c014d0afc85df48743469e5d38b1583100237f5d2efce1c26b027c68f98a9930b66306f5febb17b7dacc1b254c977df2913aaf54b268d94b6c264aa69b45b5d0cbc9eab0853f7c45115206a317b430fcf52b7f0117b2f82a1fc24d308dd34b3e1602f2f18a81b5d44d87de42570904bb2e53c3db6e925c2872fe3c6f7db0f7146e60085508e7dbb10ed74bfcf340933bfe203513942f8e3f1a0c8db0171c7f5a2e2129e94fb55695457fb1e401f2b45ae25ef267102ffeb868fe81d49c145e6d572f87f1cef894a60fff6a1f10e448c6f3b29eb2a9e93c1acee48ff4c0a334830d038605ea4df5c6208150dd72e9109076d1b4b43060a2f471a361901395b926a1a00c61a18f544a6a621d33fbc1b692b3d2a4185793bc7b2ffea5f4a7423d377662eb7b58633486dcbdc0546c5e1d2f664391de59cb413ffae420069c4fdfa73ad924a6d22a20991532c1bc2c4a33a362422cb0a59cf6ab4e3eb1c575eafe689229c47645697e9a8f1b967fec08baf1b9a676c368b6c2c0f7b21d2e21e33c20b69ae1c52a1226216cec41138c513296a366caea6931278aa4b3fab2812fcafc0185b6cfe0fb7d671ff5eeb182801bc7acca5d0420bb182b0a21670d42d2e4de16cfe94dbc071d67b365d8792c85532becf6c773b72929c5dd6bb9168e6fb91b050d10a7393c8a35dd6bd98fc3793673c3e520ee98e29d038f3537cfe696694cdd1baf92f31ca7fac40aec3ec3cc77860a1e21f603b154c19afec0ccf20c61dc0dadc4ebacf16c2842b08b3806bd2fd409269d0c11f5f6bbf169648a94907f960125ee1038cb308e9561ba9756207e4edca298c0cbf9d5900d1c06c3184c79106c115b0c07411821d82b1fef15532138face1e70461aefbdfa07b448c3f655d48a1c0032399ba6cce3e41413861a96b1d9083a1857d6c973dda4d2e1af9037c0e1c6d70550bc0c030f30caa5f1710101969a26634761ecc59e447129965f92b7351d56a1ca957d43357423500d8a2d1fb4889af8de60fd294368101fae2d073049f141c607180fa13d428a4156a230632025264f800680da6237aa20b2c9c01d4b56ce335cb20a3bc822d3ecd0e8bd1aeb0028ad6defa59d9ade4bb35ecc05c6f790d67b79cd5f19a28ee4a91daeb820bbaa2fdfdf2d1f4c5bfe9da1bfadd864098abf095326d039b0894686c920e8f9043682d3cb2bce4546dbe15d4691686044cf56b597726ff4ecaca4ba6314118c43628646489c28ef835aaf468cff8abd0b901860fe1985f389a00fb497411d222d378c77bbc078b4791aa0713050fab7d3ccd81342ca6a0df247c17d58d23cf28ae8159304eb869371aa050d812e6960736048b83ec07a914d7718cf278b7c068a66d0129e263059f4b328966f539a81dd0135c423ae7cdf0b7ba1d938bf28a30633a19cf9cf78e746a1dd9cef4cb1ca9a1d3727c4c8e10376aadde6b89b1691cfbf08df1836a4bdd3ffdb0f37f9e43e784005261118722c58bc27da509db205871d2ce4ebcfc85b4e65c09b0c0fe85a4b6a44efc042b479b4b35e36154bc2260063b20683bb1650eeddbccc16ad504e60bad5d9c92d4edc8fa0fd8ec97d88872ff05a095c98e3c1b09e56032bc70ce03c9d43d4029721aebb8ebe7e3709a444df7354e245250ac15947eaa6e4a37497a3557c28d17b8055649fa0e697ce362d7c25b77c555823cfd752d1fc7d7e00b28be2b8180db588934981cb2b38a24868c935f20cc9a756c99812741386c128e90838ad450a4fad607fd8f20247f948d27d7a4aeb1a14a846d5a71c58c3de65bb1c742028a11a625266681239435e5343912ab0fb0bc681004a2dff0484b5e12fafab0ba1f232e792d80cf547212ee73a26507baf6428ddaf965739c659509e6bb5033deaa5215619d859abedb1e5f950f3f175f459f89966e4932af25991428984d65a019cd5804e6a5fc78eee5d1b3642c02720f5e63f5cbf862199470cbd337b184745f0952b897ffa2a13aebca9670346101aef83208a9dc78507e1e384f819942c2b52d9b666fffa0cd9fe3932d9321a8212d13a477d15a8f626506f389581dec688f253241152e3419b6addc8b71e740b88d16efd5110d49c6d3e10137fd29ac09fcc9c4bcfaad4d21d3eb79b627783e0974b60c6b596155c23dd0ec5f8f460b3aca2cd0a06f1a55d35c8de17283109662a95519ccaa8025dafe66cc8c7f49b8fee8cecf0b391ef5e3479cd78475864e20b4404a4391fad20964ff3d1ea8d71ba54088eae9a8d8fd039af57b822babb57aada52d1082742cdb4737631bb1ca82a9b94a7a178000fc69993bc5986c261cc8e807e959c0c7eab83aa40fdfc5fbefae0d88e548c3ef2865c85da3c66215fae3505b7d2687d41d8508b6abc427405a6c07048b35b5a9ca84b6b6e517eb69b0771afef1799869228bf5cdb9282baf4a360578696c1ee346fc6c0c2ae81670813370ae7799e8c9d49ace6f16324048c744cba0b7c9c464f41a79c6b4a24b7dcbadd149890faa1c5873a04f41a808835851d4793eebdb063089a6bf4e199f513d09c9df6c0794f6b1b21e766d3901b3d20e479bbad39813560f46d04d02815d4878f223558df0d5424bb24c3d53a0734d9422c43b9b8376d8a034c2d4fadfd40923106d2a5c36830ddd8a0ab1fef23b2395661a819c6e7516de828b65a4fa35c44dc4effdcf2ce1b9a0a51ffc0fba4fac38df64340249f3f1143c043434adda06b2d28b7ab7caae591e1627e15dd1146ad823443e26dba753aca6a337db493a2ed4213897844af4c32fcbe43eecab0e48c30f8112ef40e3fc6ce02f4449b19e00965425901b3f37b7fb86379e5696adebdeb281500cbd6d9a2b829199fd1a122811e2debc7db72e6f1daa78436d3f835b8354abc6b61b071ac8855c931e81e294a776000c92ab2b33d444f2e4eb73cc4b3a66529b6dec7330e3b21595c731effee27f52554321aeb655c425955a73bcc8d8bfa1d07fd4c8fefef4282ddd0a31143fd3e585fc2e236413cd0d1348c1990b3434e7701b5cc7dcab996641a61e7792e1aa06d20d7bbdc80f56c5793375425e3883886a3b03adccc30a9ec3e790d39c51b546852df7e574bf6246743061920a58cdd236cd66e9692c1b6b7a75365f9941a595c82e7caf1723f4230ea5a9fc68fb2a3b363b3959dca91e5b6ccbe7acc5a903d59fa8315992ef1950e8a30eef7e6f2a25c686dc4da30cf594d6e0df93a7268cc6aa0c8b72891def188323ca19c49ccd4127012ec13f4b7609bfd058481f10a80783b8adf0672a70e88270ce4ac15fe4f5ef1ca21c3620a21ac3c6b182094f3a0cf0589cfceea8d7a0bd686efb16d447f02f0b0d03f410d80b8c804223a2ca8898e71be342ecb150bd192f94291cea2094b8ea94aae3d09df2caa02c1bbe0f45133a92f56d0c76fd3e4121f208a96f224d7881c8fb35f3eb1cad5c7d3c7090a36b67bba9e1e45ff6a8a931408ea5c3c3e03bb10e2c7edae30736d32f0e61c9a707c448cb001e3cf7348cf365d75ea11143d7ae2383b743bd5cd928a15eacc77ec1d38865d9911e051361185b29634648ecfddef365a17b887417fb8df6ef08dba119558bacfecdfa187f156a15b305cc0ed57a35f539d2a4217b72caa071a6b7b86b9da44a7cbe63ccc5f1689ac242e808a33647a1b88835c888388a75522b9b19c935285ebcab2fc51662044c7b35bed43232ae81d24c0422c345ed2138d28d13d15526ebdc72d40185d7ffead962123319cd2fb8f8178bf2dbe8f5bd57c538fb75ae559aa1b3c3d00c33cfa2a1380f5aab76aee0d3fd7b22a68ac99c036680f9eeb49f4cc55b73b266f15233f309a4b3da474e8e6f3c2b69953e805efd1c00614d1715a6483e29cdceb49ace23348fd9d069b9eb8624d28fa35ad36ab66acce3485acadbf561d6587957f9ec67351444bbf631855471168d16ac50a7505d418f0bba74257c933a5e2c596705698eb2db321ef0bc72936802a16dbe828651d30887f41fba99081b1e008b9a4d7445762174128f6a249688b3a6a740097eb085101b1ea9201aee4782fb4cf19c0a19442715208508000c57662846233ef21002788e51b32c42c14db9c9ed8fbca513fdb7e0c3db195255f707a3a5712ce280a6cb34847f4c46e6bcae017104e8c9295e7fafe514fec82e0525d71c6fbcb8d4958b050ec1d2703558708a3bc8100cd541678ed5d7b3198bcfd848b084d17f02176771a31586aee3e71e233d64b683d3d309998587bb18b222cd5c2264a5f64b2776fc94e8050c383d67fc88139b71f8411fae930848e4d4c36137f765e184179016801ba4200d025d4c774fbd0f1b471615096158d2489a35f1b3d2088811a2778da9c1d254cbad9ed1aa7df2f2307f093e245995f134c24f87fd77ba7f753951ba29d7ad619e928a9ad88cc735eb45c9eeaf847a154dd20522497e5222cf0a401f1a05ae76bc67ab8c1ce4ae9b8ddbf1d3dac7eb640f614591d651ce3bb728c8950b47b881e724fb7f87366dad872e27621955d54b187132cc126a4b2bd9f3e80240bf2b1ab61dccc6810010c4cf806e454c1c97b49e69148968c39949930f9d7b75b97f082afb5d10ef661b635f86c3a1fa9feac439b43812f587714aa837320eb17368fab1f2bc1279d324e1f1035fa5d27dc7797b70f0ca99af853b92507d2eec74a93755b4260bd54057e56eeae2dd85777058010c8b5551828dbd4d91da9809f7a27a7a913097dc0799e7f21d07c440cb5e8f9bae2a3bf69faae66d33a91a33e976bf09d99a5f49cced374fc23d66177f8f2d2fbfa26f6e6cd5d72a2cd236f7d1f8220779635e0c5e430cc3f3d23b9bb6598045c1b80b4906780ea9ea0f7e5c02f76757972b01bf50cbc12b1e3eafd7abc0c8290e6b7a40a495ecb49f84a1357f6f5890ca3fc076f4d78eea8b9c72c4dff2ca3ad1940efac082d66d896bfd83697d000f9fc3112aa2cfc1f7bb4ba1526a52e9a494cd1f3bb39f6a93110a802a939f35249ebef67ad0bdeadb065b5f78d7b7f2572b01d7a96a2d456360f629d07978cef05e927e415319287aa278f584afb4f4a93df21b4289e6ae63ee87c364fdbd16cc7f15d0ccb90260f1177825b18046c6f6e07c0023751022879e58eac4d63937c0f61729c69163d46817907b1389dc50adef6a116b0780780b0b2c4ae304f41b5d57b44aa2cbbeae29ee4203369bae657ce5b309d097fd99ea707ae1244463684050d1da578a9f18a0f81260c738026b97de8040d229466e74b6d36d0ec350b3bcd9356406433f775e6179301e0c09bb375dcfd0c82114186c2a25b8006428421240295b829c403804db08a39b63e07e075d160405310e2e334a7ff40ca532a0f9402842c8478ee891b6e00355c962662bb74e610514f49bf1a81922a008552603d56fdbb84113c4cdfd5af59e4d3b1f03043146e352ebe9a337b8d220d54244cef0fe16e0c44041547547c45068055906b0e7f93704b0d11aeeb34e841fb9a2be65f14ca7a041c9e5646cacea8f57b646b3284f9dd7decef05f13ca3165d581105cf00aae58388b47c385845aab128decb90920ba0a9261cf36f843a14a188954e9badab7a44482c8fcef2253cb0ebb12b5fb27ddc8ab4f67510096a2ff9f9e39a3daa92f10b82f125e7b4260aafc7e9b70c253d8e7f9c913fa3773dda362f358bdb27efb6646be3b98ce499e868f77e37a8e3d73c92828743ae50ed8418e603777f29581e54e1d94d77fea7166891d15962ac6541f2edc022e065bc48912ffe0af884bdd58a8a728edf9320cacae852f3e09813d17eab3ddcbe52074132497c7b53e97f7bedcd6be29553a1e0e100a2ea20526fbd73c77885889415b1ed87b600705a732785d32716a37475a0f44dbebc62a2ccccadf55045aad6ce89d4c39f1a82549dcf18ef3d4d746bfaf4df5e68a5d1ba191e295efadbeed2bf3ae40c1b95d52d75f1c020db847dd5913b72c27a39cf9a5270158b9e8505d827d89eadb697c0a6c30655b7ccf717affc7f28771a33fee3bdd7827f810cd33defcfd34398d8f1b617074c5fe28653541d23c71351a0c34957fd2db64b7c4f61a7d849e729d8ba1af9e3a4bab4832b066c2709bea0dfd787aa9c8ca31ccf4b12b2f12d037575cf998805428f7e4f87d76355c0ebf0dab85ae103f6bb3cb72e5542a94ddc308d8be13abaf0a94d999d231de1f7ebf9e0c00c82e252223456b1efb7df10e5790c0a55f6eacb9ae74b6c75c82ba0b11f4064a2d846ff9c12447908a27ca2151693568b85a160b95a1f18806a2456bc2cc5c8956059f1cb099618c2a993c8c03299ca5ff9ccb223661356a1322608c1328db7d163fd18160fb0da171220072513e70587d4fc43b4fc010700e0568bec4802ae885c483dbe50ec7d765139d8c708e91d97455ddc59025baa5c5d100ed5bba9ea645208b8296633b2e9ffa0630a5bdf4203ee17d4a8ec2fde6aa2446514a91842e164fd64ade9cab81e122b6714d100619039cb0869fef9eef8b40b2425d22272bd67d1b66e8f2aee30a7520c24c31a42a6a1eb0628c3b9f8ca67819251e336f75dbddfa9cc763c5d21ed8f2c46cd57955a432aa15b3003c246b8d18d54592c91f107b936970542183e8b5150df7c7dedee1a92185d09f9c943cd34698b5f5a1a3c8be6e3d5df58eca1184cf96922403aca94f6a279d5a6e433a494747e5ef35ea2e9d84b5c4ead8441f99f2313ce13c360c78896965f9b211c8e118f3dd88c8ac69b3281724564537aac335cfe516c1ce68d4de2a00bc63de83cf81e563e90f5a3ef4e386efbbb55c5330559ff90f137350557d2a9559ef1649dc247088e897080041df087c74ac3a07c3a21fd55bd338f32512a15fe8f4fe5a38cf2287a1556212ad86968e99b7ca86b245f5a3bb24a8159ba024df9e0b761947039cfe7e272fad25a8b70875287a5c82e9271bd6b65dd79281f8699bb3ef07a6073a727f79293bbd9b8486b44242fd79ffe8d6d27fc556dfc2e7f6dfb5b70d8296be2418f999a92f1f16420dcffe1d71dbb5f80296de96073e12744471c300c6b418e0eb550f775d9360d45f7866521e9d1527df0d32a483cadd490bf3a290055ae7c62acb1dc441a4df8a9d1059d53dad215e109053747702b67fb7a22570f05c8f09c35983dea1387b8b413b900e49799102497ad7a377399132060bb59b5e05630b55def81638e6fa7054e0e5c371d4142cd884ec3c0d47016de0d9454ec53b20029c49f1b594cd75a52c5b7d57ddf6c0321fc27872847e66409d39c541fc012e0dfbc4c1374d2b2fe3a9b577d9010e65523ffc17cf654f34b6d5272e2e4637bf89742f97d6bd4901e5058ae91bc44359a3d4e01f8bc22257d6968bc346fdaf590dbaf4747983cc191219bed9ffc8e155184c66fa14753c8328c2f40f575767289067a1837a144adac2a6d3049759a5dbe11f94a809d7479a40d69884a327d999c17756326e7f60d2914f1206835fe5aa21f71d5e3915f77a4e741e1e43e7e6b9d9cfc6eb5293909040d73ad9fe8f6ffb3b883b64342a2f393d9c7f0bf01bfb5a50c1708dab6a1738ac6d3867a1b8289621b18a4e9a550ea4c03e0c570a4c74d2bdca5391dac4e8422535ba777682999572216867496f0a188f393ad408988c854d371f491e6820e9cff1e885ea9662954cd695c740572d4d27447072ef6e6d5774b58c6224f8ece8870c6d8bc54438889812ae4bd07af3202f748238c80df6829f6da7fa0ed746a142db0580a5222335da9dbc567bd705f59f312fc29bfc9e89e0c926e07bf2bf6f18867c5b7ae73a6b4d4d16b88ace5594f6ae32339c392d975a43f9c57e09159a8ef08e7ba00d47f9d043f658dce271603e623906679f907cc490dc7e9fcc017aa6114d7efbb4f38f6c567c416b0eb16be01db0b81fd7d2a40a972680a6fc1a887db77a42ccb9bc36302818d1f46bb69e4842aed1f5f00cfb37716ddbf1fb4508f155fe4c7e962af1bbff4eb5cc9746eebfc8fc2e27dce54490438ea53df536a5451f0864f4d1682e13d8c27c77a240f2746613de3ac297cb7639b5e980c534e24a8de52ca60d4a2a02465c74b5a88bc4b23d2ace3be8b2db87d40101bedba9c21d8a49f35d47d226c6a0bbdecf3f18ca6ab50160344fa06dd3002b3e8bb7929e83da8a8e3f0160dcdd77cd3213d657c9ca42d894521c9685f773f36d1f1b1ddf6cd5bf8b1d13260667c6cba237c6c1f1ba274c3f497fedd849c0997bd78c170348783a3e8eaa6184881143a6132ac3ef75480c15ecd31b828e901de2d9e8f4503ad0cd22d5f9198f523eee7c8fc112c7b7b64dbfcf9429148ecb0d0bf7a7c8081397eb15a5c47e17d1133ccd0d8c24fe636d461d46b9017912153e5c13787dc310d797ee55867da71ec970729ef73149bc496d317179c18c781ef35a47190b8833246e4ce30005846ba21e6f9629a772f42d4a6b8ee7806d314b247a8b2bc38e411d6a5ced764c3343b289eb51fd98f2314ce6b5991029b2045e024f2ca5bff24cbc1a59189277ec0c3f1e0e06325cc84b652ff206876fd73744e2267410c3ca2e2cb747d6a0806faf3fc5268a884c018471e64fee3d9945f1fd0026b922c88bf7574a20f60457e07027feb2947f7216d8b2652bf537be5a628f76b3ba723c2d563008c8db713488415eec5c0c968425aa6c31a8496aa4f2b5eb721f9f3e7e3d9c736bc8dfe7cf1bdd102ee62ecdd105f2000f273d8071e2d02fc00a3c01ecacdddaa833dc16e206e806c7435a03ab28df29163421bb1226e645ded38f1b973335b39672b1d02c4943963daaaf24a5a168d0504c96b75140ce9d5dbfea21b6c55b16ec9172afa9f228ac253e81f7f32cfdc7997598d00a30e0d804a46b343b83a9b78693f69695b47a54524656d0e0482dbad0f75abf237de11be9349ee626a92b324426de5eeed69c205b0764aa0961efc5b2169d351069c252f0e9b390b1334f9fd74bc64556a6ae4090826ba4d13d4ce7120495cfb2506d5a2ab74161eccc97aba68520268c955713440271342a098cf2b720b850aad483eb5610e3962bb35d8b04b55cc5152d2e9fbc346645fdcc9da8a03f439ba4b6adf3ddf41af6483ed363f0b31e7ce0503d80e53cd1514811aab81b19ed2c576082745a884784581747a71ac04bb7b54f11c5b5f6c67623a41f4bbc1517fb255fc6651c961685cfbecdc38c7317cc286701db71ce3acd28c3e63c359623a841973f94d7e7d85888d0ab69f09a1c344760199ccf82fef3e97d1d50f74240767696c0e883d31b634de78a9758c682e37cf1102573fa32a47797e1a8759745f6e168805b44da0e57e0f305cad801e450ea5ea484a5b87ce0021f2e67c8e4a387b0b19a6ad605a7704faf6dfd12d23ab071c4c6359860d3a34d5301dc0ed9bdb22ce71595874f74414f46d502da49797bdfdb731da300a37836515651b90a54607d032929f7cc4294284131eab49a7db55df83a4ca71734e23b1985e9ee85629ed602776aaa6a116586ca7ec90693a1cb4de4dc2b96115dc3117ab73cdfb04ff6ea45109edc5d4f3f861c54b09a79bc0fc1ec0de28559c2b7912628fadd493846eed593a412d30ed074b3c11646cb0f5045eb5b038cc96120cd8deaa33771c732b87fa7856e875abff240f3dbee77ecd24356cccc75c79c265441ad8e4017d90469e1730c8b880c2becf77db454220d6c8440966a1c57a0f9c4260153050a2eb43695cc5be92aa210996f3c020e31d17d258b1bd742cd08671962a0de48d0d0445c83882c725ad8bd56b37c45887b9805c25cf4aac93e44cefcf3c60d21c2cb9c935267250be9103ded41f9cc38845639f87583a06d2462fe603a9c2c81f835f1bfeb130456e8c72e87ce4eb943a464c5ecb5f9dc58655c574e65cc64f7284c7503e3c1871e65c48e5f2259543f42da9ec60562b7d1ddc3d573fb607d5309cb8eeeecbaeb6f26b3fd2737082d57567875027e6d16c7704a58704126ae7f20f4ae28e3637f05a5d1fa0032dccee27a1d920bbba3f31fe21783511455cd49b44281272bbe30d30e72b3dfd5f1a7756c6c0fc0315fad96d48353330e0e92abc77d26b16e6d255f51b566927720686b205fed2c80637c4a5178003d2f8e5dc53ec938d052bedb09dd60d7b051aa0d6810c884921c45788d94cc5bad9f4b6d8a45fe09678053903e267db3b0a73d90bc4514875a9469d621d14488db6448b3af704221198d8103984d855882129d5e02508697c97aae477055ab6796e7dfaaab4b05857dae58c4af80020e47a7b95df6ee7e2635cb764dd90ab1d6610e789db977ecf81bfec1cfcef0d7ca8da6c246634b30702e036b3961bed41bce25026a18e98c00b0e83925c02111d32cd5d2cebcb9f5daa58266ff651382e1f469046e99f4b8a2549820cf51917bdc09dbafa4a6640f6b220eff10ca240a25f0813721b5518a14800b5786bd33cf8e994b9284497453a90df4b4612bd455309418f7035cb3702b0e7d4b06c8a35bdbf8881c609c05da32dc7706a2286d76a64b26a514267beb8ce5b0daea7763b0f28711c8e103b7417148c711212f9d5ed4206898b3da36bfc985ea20c6b223eaca4c221a44aadf5e5bd0cc4de21faad94b26e953db8327276211d4cf806879c1dec0a6bc23e9ce05011c632acdc40276e3abb92b4bc8d86a37933f40889310cc528e87a599c69af31ceb54550c6ec8da65353b77738f570d49ced7a18d1eb61013e5fcb890cc3d8df2d8c02742985075635e30181c571570c4f076e571bc56a3adc95f894b03ae2a6007f31320d712fad3be69de100a5bdb9268143877b0865429f1325b95c94ab15b0b36db40afd0f67d1d977d0f4bd886b9d063dc1b1c984898e4a5f7d5d4428326aa143c63189d93ad1c1ebaf99fb4ee754ee8ca6bc61012f9d6a35f6070d471a027e2b2368648d60120d8fe09fd0413ca168b8574159c777b1ae16c3b4e98c04c390198d5f19a4a0393cefa6a3916d1000a4cd821ee9166b7909f26e285bc5fe1c031e1b919c3f9cfa39d2fa3b8b53565cd3a331b04417c6920c0ab123c90752b5686215e0208a3f6b8127882c612c05e7fe74582ceeb150f6072559a34e8a5fd0b5b118ce7893fd5a2c4ac4826f61e71c763f44720e6829cdbea97190b1b934a24497d7eb37cff6338c2c8db35b1f65a720674f0fdd738c1ed2468d32640530f4dae13a64fc6291f03da9f9033c64a462371f005dd75ac5f5e1123f2f6b009ae00fc33279b0557d8412ff90888e9fc50b09847d600dd2a91b0322792716d7977945857886ca1f76e284b6e78418f1d5ee02b465dfa6d7b7ebd8bd75e430fb56cb81bb9872f3147ce8c25dbbfc0582cc5d75b07f87f92dc6b70695dce6528a03ade3c25958ccd60aecb6b312675bcbe340bf7e109e9ca41e91c00437117c76b92d3b90f9af24b63d66e79e44d0ce2bd4157ff62248c4c26cf84260583e9d355dfcfbe5289244fc64355fce3132ea38e46ad382edfd7a0f13a2e11dda736dca61443f4096bd0ed6990783b782524798da98be52fd6f38a1bdc1c3b0c50d0068ec68dc572478715eefc8a5f802b99401b74d95d74ae19d785ce6daa39559e091568abf41a194c19de035c7335561facc1d0a40938aa84efee824371a5485409da1a9fc9e4be995335ef3fba52ba4cafd1faa505714f5a5c88eae509392ad04b039fdc4d3ec932cdbdc578dfad831b2083b69c595cd26b7aeb12c02a1c660b8605865b99728e6a858e8d5a4ecfdcdbce122862fdd7c411ddcd79ee9dc889ebd3f428bb0a29928e7040aeaae8650ed8f5b6003d6f797eef2167d42e10809184ccf0994a5b2e5886867655e72114f779262cd753c04b482a03b7a76f06c93fa78f3b0472287283efc453b8bf637a142b31c64b292868ffa4b7eca40101b41a7dd6a4bdbf520e8652180634b5c0ed22c0b826ba3311407f6b39332c8210893eddf6b199b8e6c90c3f0e8db2c164a7dca81eaa6c74891a0cfee165e4ead22b3fa89684572af4c739fcc16dff4d18b73ae507dad2429e12d5434e9cabd7f81dd2d48772a2cec0d420eb9cf198105e64d6cc90f42dd581d162273048d2a3ab2ceb8fd937dae37d2cb8c0adefb4780639eaff76a6b85904b09f9a311aaf257e63ef08585ef820ef7c7fe8acab272efd5f4b64a192b5d393054a351f3b0eefb894924a7523f9aa633c959a1f6a7f0d6abc9d487f9b8bdd3886f3377e418c6af6bb1a7de009bf77ea14d280a4c390e01a1d58ec1b9dfc049befe0a1c257af52a7a05cac6bb782323800be0e5cd670d13a07b2fb7c601451ded018072f85c6fc75f77270fd6c6819430025c3e2fa696b072b410027f090823821feb4f168e2e85976851e7e1ffb6aab156b429eefd8c788f8f078fd517084c694cb93b8ec72678ea147f979deada2866d5e7c0c53477733e710c9deed068f8a60c658dc5873bd7d24cd70b8f601920c423dba0193d2e5ed8c69919ed9fef399e41716744cb157d940d07186da87bfc05fa8a2f1c02d5af3d68cd1161ef65449eecf3e38666d03eab9112664e897e64b966e053acac8c1336667d02c0e0e66abb7b9ad09ea7468e0031365cf5cd220d254ce3bdac45317adad99ada7482ae0eaaefc633fbe608e61ae6dfe6d6b57ec645eeed44bb8d9c4a73938fbf480fcdd73ec56ba0776463367ae5bf32542ad8d8da148954b6953715c60ae8662624ff1f9bfcb8c40015c7b12bacbac6044220c61b9edcd249e542612acbc41d72e5a0fcbc67ae797eac80a5d73efed6f9174b87728fc8af01d079068aea4d4708ed2d63bdf95bc198c50e15815da3d533ba9dea1e0c9e2b6e0946a77184fb43cc67627891d70da3d95dc1073022c78ca3622b7245b1974be3218bfd76483e08bd70760f09d6886bbb28aee0e7a82e94ee4755e08f6d19d905d787dc1dc23e28e1ea7bd40b1a02c70669c004018242fa206b19dd7d8a628920fd71b047ad8f3e3150a72c6bd1a6699615219170618e473d4613a32234df9e41338d619eb02b43543ae739f39a7365b8c302b7ce1a98473ee76eeb839f65cce15549c35e587497650555a0a028c80fd24585bd66a7c12de4f6171d872163dc1a5af64e1acf354ce4a0edbf7e94ce5b4a0e931e3917d0d537a2ed90c4b5adab896b566dab288e45c2bd910455d3e5658feb23724e4e0c0985e1235bcc8674ec8a753d2ab969d0991e0b8a60013b78a2715f14dca92626588510167eb71db6f4715ccf534207a6b4cd59b217787c5c4e3f67a884c171529fb37b14f698af9213453b2d5de507e818ecbc9abbfda3fbcfad0d089373e3f063686826dbb40b4c9b7669105ae5f7d63838904f5b8cad77f9733fd19fad268529e3776b65cd9a153ffff6e82e07fa87a2535630a7a4b905ddc521ed9b87b3186b972e4c2447921c6b44be0ac05eae854a82a1bb2e24f68f8ed01a93583dfb6edf6e4f31baf4f46ff8795cfc1e97cdd7cf52397225b31076bac2285eb9cce4664775e8feb1162493b5a463172fd40471e41d39756e2df836ea7130d47f0f1823e8092febcd82371247efc4dee8bb0c20021bd1b92fa4bc25d11fa55d0602d140e3b7975a74840e833780ce11cf40e735bc22b3e3ecf2342027b880911c5a80fc301ef16d965be0a15534baaf34a2076b7640ff45bb3f0d7d8851e0942cfb5dece82e080ac2ab0df7cdda8b727ed7de85d82ff87075efcee7aafc22c3ce185ed17ad8ece773953d9957851ac63ffc212e2ae42eb5a40cd760e27a9b82b7488094b0a641bdfa6bc5b0b2607c9eb3e9c46e2c10bb08e71a4487d45286654a0dbe90bdbf169f3a101da6bb097b047788d7ef41f8419db77351eb6bdf1343bf095bc260ff4d31d0e882fa87a62e3b74f1f73813d9087a72521949d64ba379f80d75b39413684d2b3306ad5c13649254228be124f16e92baa98d30730d57c70716caca574b9db532a8a596f77ce0f2c22bbbe8535b1e291754dc385025f1a7bc2abc791b120ae1ce438db5fdc3189e9fc0e754f9bd3dcdf45fad56cfe233e6008ef9433c8fb924c4623e04b3392005c62a120840204453809f7850b46f83144710c75417d18b742c54cea80c60d8323dfd16ce1905da0154842bb34270d9ced711a5a8e8b86bc2ad648aef6c8b264bd790f42a40927fa4ff45ce7f16e1f290f82aa5113ca9c0ed354db5c85ab5d13905806ee455208ab4bbe57b6398804428d3f30615ded9f6580c71066df57ca8d581cce0849e3d067816322c0be4ca44e5ca5ff1094bb4eb08468738cda036a68b49127380528c229347ae23620b0623ebf4b638919550fa5a4a42774840656841ef47ec3c3b5d3e193e70cb35e6fa2445409baff1fba4154df9363959870429054f612668da4bf67f5f0308aebb39fc3ea3aa6a4e1325a4f7ca6218039bb269fe15c9a133cfd12165db35ee5132ea9f72427cf136a3b55288d44a8371b56efbb01c782b528ae755f324ad713dca7913b81b12e74dd8f6f11dc35e66c22f71e802f422d7cc81dc64d1dbf957c10797e8e38f587d22e92ef848c87083db281518b529061232e97c14cb3bfd584eff7d9182176d9462358c53d0a3c0bce4f91b77caedb5aa098f784a2c145074a18386d36bd288b2fd44d3cd35807addaf8524f3b3a3a2d655b125a2b9fae01711d4ff099251b176a19b45133ce1be9a7cc7e4a591d05569dd04c14b7df13d96163f85f041b94f6f4acecfb95dabd657cd99eb318d540c3aca809ad3e4c2847506d82eb5611d7b0dcee0da3f2270e4203fc7637b8a4a9f125ea4f7354e417845287b63f7bc1e63bc2f133ab28d1e4a54a35bcc1eba9ea867db79b396404d80fb249bcb8619a4bd46b3b7530dd03b5c1e24487f7a58314fbf5a5035276b113b7053be4a12b0aa7f0e1f78417ca63e48e4e68d874c5b0c9bbbb6979358dff7a834adebb2f346e22b43388af6073427baef804c27131fc9f5de5c27a1775c57054537ac30964d177c0902502707f3c7870c47a42078f5ffeaade4773103665aad344f13dcf5d4a9ba053ad1dc4612c83a8b03d056b1942ef192a0dbf318cfad31b41213d9a2dc889f0a64148574457c1378e26d74076b0f73f12b533cf55c4a3e711bd6a8cc6530d14a3f5b95a9f79c221d605452e7449a830260e9542f2a0828607524442f272bb51c239e8f08acb4469ba5af6a49f413517f39e14f869376f2ddd786d57f71fc4a787fce6b943708e3756e7a5e45a1005aa5220b8051744480d564f92ed62c5fb440f205ad875084e18dbe34166cdce5ebb66d04504d87833fe01cd7884b88ad52393c65ad1fab6fe11b9ad2066ab828a805117f4445358b4cfaa8f5b38ab6c67afff9d06d8fb79e28901effbf01cc54856d4b4e23b50eec0f74a9e14ecea2a7ae8b335aee1558de4f54c183a959441b79a5c8900d5ef00998700dac6b8b8a6d941219fd4d1feef0fe8148d5ea523bdcd175d1bcefd8097356f07684cda649ce99939f44baf50ffccd42a7afbd22f68ff932aa45af25701c561ee3e4752dcfc95512568a70642fbd44e047ae43b0a01c6c4c16bf31d702da45ffa324ac215add645fb3dd81cb3026d9584026f0774482a16cad2a1abf7c02c572a0865b6e3c60df5b8e25f063103446847cb37a0fd60550b83ebe0fc8cf34b2c759d6dc8f6186c8b710b0b542f6a8ea5b5dbcec6cbb3514571e3c36e79eaf5b4461b11ceea90ae94c3f2e94e6aefb5a47ebb1f596b5fbdb52f938579898cbec3d3f7308226374d6b1be22d7ebfa4d8107652cbb02e8eed9151f6891cf409fcc2d18f87994edb3fc423bc6a30bd3b5ee37f552f76b189ce944c6dcda316e46e945fea0c965d4b9d2281cf4b2fb68b16111c34ae919b711d62d103b00ba7961019095e88655df625458f2eb46a7cc727235173fb1b2995702c93389109cd45b50ff994051993eda5c48d6c0130c34475e4c3a15443aca8f8526877e9ae2f3ad5764a18e248ba57754c305d99f8b7be4dd11fbdeac99c01233fc72699f81765e1c57f1a28fc0eb220104d008b30d9cc917f05da7ac3fe4c28be73e117809524d26f54bb361969fb93258860d56501da2fff10c15a156a3dc4559865b1b6ec79a25c263e714fb5b764e136b8eb45b70bb2a16a2f2051dde59fe6fad6d12977548cae4ce191635f8e9e4a408cd51f9102e348094418d44f0304356529f66c4366d19189aba9f9df064ca865919d51709f7f055d27443a1e87f86ecfef4c4ce5462117a7315f1c9ac2656bc7e6f62db696b4b8f134184e75bef330b0811b202b937308794d1540757b954ecf6184ce8ad55205cfbabd13d86cee2d035de872f0428274be937233f01addd713293dfbbc10c87194f97269cc04f73051c926a51adbf8b0fb761b611041638898b6399a6a6ea4d335acdc1cc39b88510a91ad63bf71c77f11e18bf1a12389a56a83e84c341b354102ced767d6fbbeaffa96a947ca946872de0fdcbb889dc36f2ea8ee6a2376d8374d919786be7c95a851e09c5e807eaad5d3b4f169e4bd8822c3b7a53e811730f3b65bb89b03248d8dbad99bba1834bca10a113ffab4ceba25e8c5ca3a84cf3777245f4d4e728cfca0a11707ace9dc5b928459b6dd3eec1102550889a75072eb8e1a8aaf09dcf369d71a5468112a2577e80674421cd5f7656d37e0d176e7747e63c130707021581ae2d570edc81a800fd9a5b1784af2056005b10789f23a7ed39bfb160d19db235a15f2cbf688a852877474819b6fbe40db33ef381018ab92d724a0214e192accc0d1e0a13ecf9ec29b57a25aa485c7ceb4a121a2c04d7070c6955319810857050c35041b4231f7c94f386e6c172f0f9f78b0b9aa540fdaaf6a11f10106df41e880eeb13f7c860c7ca66871ec5edcbcb23542704fa30dba45d3012b2d27455f35ac953f0bd3885c5b86bc579ae6571aa745943ac60720c803be3bf61bca3d311c0d0a62c468858379b322987611e036085616731b23835c4f502a4d0071c75bd22f3a311e23148b88ab4d1da6ea346468decbde5de3b2e0a3e0a6d0a193b75d236d6855d06dc264f959ea39f24193b36d2ac33b7d09a2c29c3e27304090666ee2bc23c1586c58454882ea144abd08aca337bc2f9226acc07f74f1c3f18f165121d8638fec31806d22adb314d0b75280be34159d84f50c2944808d3a12c27b4e674ac85d4b1532852c73d46b7ed077e16babc86a30c3229673c688d49a4ef63c7693a522232764e5a196fb24b28c43e1582da7350c721987de6ec324230e6041eb6c50865163178f1b874684d76ec5b8a7e96544e898cd92991f118a10ef66d13c721797b168e43b670cc44212d4304b34b170c94063b2782d96bce441f4e66b24cfc1d60dffd14820dc8be7d935976db71e812166561181115a22cec272e70f616684d2602a12c2c4628bb17302ccbb1cd2e676ba5a0adaec0b2d82067e2489d640c7b86e15016f622d40bc55fd41b634308ec801a5de0294a89430ae92c9570220c9466faa0aca2d9c31591524a21596a405ac931c85351e8841f60b001fdfb2b8e45804c9ab499a134f234cb78d4b135b2c689c43e0b9570c74219fad62a6f90e413d4b7f612902a548461628905cb29e70ea5997f96b921313e988a3f7c80008fb20a0f5ad302652d818744d9a179be055a638308cfef68658974c3924cbb07c815e467a63b9367c837203ea4955681b2e625ad6df39c73ce12f04c1020c9f372ce399b66f921048629e54d5561a3de112868c1375207984f336cbcf00c89635edec89b14708008a1363207413c3c3c36b824d20d47f29c128b6c3ae698916326db228f37f254dde429e7a4333c2544509425d20d577a92b2666a2c4499fef6bd7706f905679d581a414fa6f39c3d4af12ca1b6c860185034f033cf58602b478b1ea580dddcd093133cce293a409225468f6aadd92e7b0a1c7eba514ab406a585d68c73cb92b28ca82d3e7a85039e61e63eb802cdf632cf73507e5c40e2a05f25c15c17059e3d436d9b4513a66d5e504a216a490a3cce284a17ab7d1bce20bf0835208f720c0d1382f5ab1771bd84603dcc8bb86698eaa12cea03aa0ee338850489319524d3a792a48052419f17630a28d3a77a523ea9d4115ae3a1504a3c5e0e7355e8c2cb61bed55016651951e03125949dc8d525a447bc902209f252e28851346807e61f0a0b4c3884451e305f893babc3fc0b77bebf1c86098c5f3fd231058443d4920f1ee78852caf429205a1365a9697e26a5999fd827b1bd8fd991287ecd62b55a73bedcc3c8208fe8910eef614c9b885a0a51584294d20f1e69910c45236a295394120a0bada9b4467639b3452136d719654e2e8880e79b42a12cda222dd2019e3f1501cf7f3ef8b6f88080c5b1c80b6e90a7787282a90d2c30fd8462333879e64b0b943c7b664f46ea39ca12a9a7084a964821d8926951dbcc2c94865e9c4b9445cf92021fd128f7e57d05bc9c9e76104aa96d2650d32ccd1fca5af1d0a229f412d2ae41a9c394e9375a44b1b49145740456327d1055a2596a5394d2114d4297645a44a7138a524229a194e692c4418f820e789c4b2922153de104f668d648810c407d25d8697f146269bddc0f64f0439e6f79c4fd40063ee4215f1137e70ea5a1435a42787e8852cb0558ae30730e102153c7c2cd55e3baf6b53500452f2da6ad20eb860cac0b849e1c0e688e7274f6bbb79a2c915e3fb9863ea7e2ec3971816f5a850aa4c50bccd933f1dc2109e9035932a5b6b6165087870cb387d20bd09af9a31f90cc6f5894907fb091451698b89427b501033c522525bad461cfb8ed33a5b4d4365aea2705a4034c3fa67ef2e444b0277650ea90f9a2c9949d138960cfb06727a2ddb43dcbb2ec994ed34cdc3498b833342ac18e61c7c41ab213695d4ba2ac632de947d3f0ec0cf1d06efad2ced0885d03a6ac04138904691a14ac78c233ca2593f8337f9a669c3f9938d4e76ec2699a394f7801d6ba63a79b0ed6edf20991511e67900d2fb0ec228a2d8cf0b88864077576867860f7aebd88cb137786fad84fe17412ce2ee421ca7346692399d434ad855666871a48c0ab2807912101afa2ac84480d98924b3bf6158f9c3f4981a98829b9a44b13793025172682530be5699a55cff4a13d9435690f769a643f459a65130bfda147e8924895286b9cf98ad488b26814ea6406214a1ea9162414a8ed5203d11a394b5094c5c92bcfd9482813900651569239d2209ca9fc4895a810157200939456e4525c84addf0a02833cf8a713c91288a2802cc8cf4f71045998a012935883d4c23544c106c4203f652e92e58be4221964e1c6404550bbccd9a90862cf36cb7a0257a8d9deae96666de540029e3932eee6c405c658495041a676868aa32caa4f6c1b0e86925b966072c541cbbc9dfb3bd84662217a6991bb832ead3eb208a1353b788019d7aadb3980da186248dbecc8252684805c35745ff4200b97f79d02bc3c71e8b2a03d60479fb6214dc3da318455d831a46d743871cc382df3529e213a3b86481c8d323dfb28b5cc3c431aa629d4c26f6608acc29c2c9ca77e66e6b7ccf4871c94d56f221c218fb3270579631ac206ead01771cdd9f3a0ce9c2e7ab0878b8ab8699aca16745a61df4ecea07ebf650b75bf3322281711e10038bb427fac28c1d8b76a5a6a2024856049eecb51468e734beed79b26fd69892508adf921bb8544ae5e08c5c511b94ea19d69640748488e5c3b350cc00443585ca9d7900021d8e00b176e9b1d19176071edd42075f0852bf51a6411ac70e137cdfd54280335401f8740a8017ab2907da2c04d0b5ad35322d960945ba96da8ab5f7da4a53fb7509b1787644317b97d50d44846aa6ca629d46037d643ee6b937267810201f2fcb54d4ae885b94fa13e89e3274ac971dcbbcbe14e5dd789d3288aad72a810e4813a9681d6c8f0e347f7f146eb348d9aa6efe307129e67000c3f8cda2688e689e39771d80a02cf9f792488eb79d43dc141ba3f203096516111579d464266b6455cb2b36fa9a3331625286338140641b9e250198080555492ba74a17e6f2a4485ada6e9158f0a2d8beafb30fca8b5ed29b5a736ccb2ecac08b2504f5f4f4570be8ae08e16fa7d1dcafa028ff288fe7414c69553130e1e6079d311adc94c55729bace4eeb648cc3e42eaa8ef29b9a7c8bdd93bb336c504180047a697238d4cbbe3e63754a65aa6b4ad139cd64e1f5739fb88ca59f6296d50cf2e51210ea5a4f1c210d3c21916309b76cd143b42e240620acc144f72bfbb1bf3410049f0b31324a68d668fb0f758688f4062d2d04f9a2b8ef649a6760a6aa7644a6758a7461c51a04dce8cdb8d213095925b1c6dfcab80152b56945fbfc7469e52c7066696f43ab9442ec063e6a36982c046b466bc4b72bfef1228f812212f91d431e525d232a9e3122171f4fb9ab4b94588e32a8f97283712d97d422471f4690978fef4cf77c46493333786c033cb0a8bd460a03ea492ece60acbbcd22667702c6185d6d09baed09a9a6e39e52c3aea166d15caa279de04c40f2e40e02d4b249e2f6cc0a62c9178ba40e2517a8127a925b46d54de194a6b95f6d45ab1ed9d7dad95d7562bc46c4a35d4aac353569d4dbb67779dff2b10db56e9a4947653ca9293d2b1d23925a5f607d3de9add5a250e0cb39f2c2c93f576ed6aabcdb06b6b865d16587bad9269ebb4d9e7b4199dac5befebad99ed1a463c04c1091eb39c437691efebbd3c34c9f7bbf7b22eebde7befa512803caa7e56906b15b922fd2421d7e31da6c8f5f6d30205c6d1945cefbdb70b2ba77befbd36721de2071d57329c7da08f93117c4dc4f83cf10363b4a2b2c38bea93a2480aa30ffb68b1030c279c385104837dbaf8514d21f47283085ca02cc1d041879416550e487a504f04b9e490a407fcc42895031226f0682084ca418a0ea7221e9cc3153c74357bf2e3653914e107ee09a3930878d89828ea506062828753a235f1b3e9c0c4275ba2c8549461af9911124a2393e4182dd1bea31d6e1151b6031d2c143d58117c72a00021e9b0841c729c50eac921c804394c242191200539e440b1741a488c9694aebdd65ed5119cca72ca94571038a607940e78234219815d9268c2141b2c3105c9862957b64ce14110a62ce11b8ee0b33ec332ca128a166891edad51462921f9b0039210187f061dfeb0ea5bca128a2125b27d5dca473c3c3c392041c98153ca120aa256cab80a8691e514a429aa2df097e514a41f20815db29c82d404972ff029cb2954764001d6b29c4205084b45285bfb3b23a1804116141070361404952621a0b2440ea8d840b5032a55523d54b09091e5941b28b5b8116013c36e137890a06077fe708a02abb0e3aa40593d77e01431753c16a47c912d75ac72bf0be50e60b66e194fd5324915c25c267c59c9f428354ed3748bc592390e950971fa14babc0b531ecc5f3ebb17a44be6b353a95eae3a8cea45467c818f3978bd49396c62d89d6210e6b9b307f3e057639fdca74a6dc3ca581809cb4bf08a3a300ce87748b0fcfc95f357e6c8ee74f0afee3145372dd64f17d36eb96f1b86d93b83b4a1f63c657e7a17822ec8fc74f08a3d64c4d3bd77077b78efee89c7e953285d1b18c2784ca8fa17a2be0ab1cb61fc95baeaa610d4818179f9364d1beaf8af97cb5f300ef357ea2fd55f2e5ddff5b0bc843b9aa6af0a7d8440f0910baa5161111e1e1e1e170e254ed3b4b7e429515687022c2fdf5da1b202ec170a4a7a41843445094997a650e1c14634650aa23661d7049a4c2a60d2e6e547ca924f673161d79348474ae4be8785d6c0e88e850264aafd8658786a9bee26d387bd62ec975a7b85743e3dfec1454c745545e36c132282cf4d22fa9348eac8b813f1be7d9c493d4e4891dbfbf61e9ed8038b6fa112d14d2772b4591e51d1044a965430b192475c832ca96032828c8fb095e652de514abce3d096131c83e9f6da8be46cdebe578c61be50356b1aef024e6b33945a064e111fb970154ad35f2591158147a965b6966021b9f4c4950a77e6910d920882ab067965896ba889263ec247f8dead507f863294d53add09a76d5e43b5a7f74c94fd806b8306be9c8931d467daa738b6506186698de9591682a6a74cefe13d251249dd3b2a854d229e73d458f8b2e95b168e1f7ead6076efd2854330134117b6e3f7e0ee8944bc73c7221122b86bc07d26620f6be0cb267104923551860f0b55e816284dfffb9aab59729fe18ed6cc842ac63eb4bc85248efe8c124a9be98229f429f42994420a3972dcf83e146a7a8147199c15c968aa8928a80c45f1c97c078f9939a350496b468c9b12933aa4a43219656559cafc9346fce4fe7604d66a9839f0f9c10957f79ddee1c85583dc2284ab1387b0b77c30f7d375723dcdba6f93032f1782f7bef37eface26bdf7e789df3e54d6345feeeef2d4f15883721fe3a28632b432ed23ce461598680b652d515673a7709b6db3fd1916a4a43b0ea544452db660807786768676bcc3f8b6f16c620d2f479deb56c2e96084cd85b491b25f8ff492d4c199c42a82dc36e4ceda8bec43594336968055a2500b354dea188b3a4dc34364888727ee0cf1f0688e128904c1f7c41f4dd3ef3eca232c4e2bd4007def039e289b8613274fd374dd7b10a9e19d58039119e47d8b09f2f1c4211b4a983f1f206a1aeee32492ae367a39026bb8ab304f607a4db412b6952c4e43e0af7b7c7aa339067aed55d3b4f19da5aab3d05eca91e58d9ee931e3b211579eca23754825c9f5a9a544ada5df4add4b6dc511779276abfe5471c338259af4d043ef70e4e5f12ba5c6d24b156826a9b308e5da537f2a92d6d244b466a4442dd4577a90c76642446b324e7bd631403b8fa492b56ff4f51bad956abfa1467d5eb4461363b8c7de35e4ec63cd3108a159ac3108a1e3cc4469c318462134c770df008d3ecb9901a35b288b1efbcc1bc54e296bcb0de511bd92c4d1a759a84df5a1748ab4e920548922a1a4d04a396e7c1f4a6909657513095156772ee8d39f4ea453244dff48e2e86e2c94d549fd6da9975a89b2fa9d0ef0487d727f4915e716ca6a2dddaf56a23c99ba64f4459c8876d86082a534dad157de5bbbbbbbbbbbbbda2872bfbb9b01567bcb561018ccba31acb1eebe5dbbda1d3f29d8e48c7cb98277d0d0060db0ec3a2878945054a035f2d5ee68010b7978504a29edfa197a23d34f15aa00a0c0d9c528bde2ddb6bcbbfbe7fec0657983e70d5b4ecb09aedf61efbd14716a380307b89e012aeca02c6b3371c4d6da7fa10af0787bfb1b3d4315d0b7ffed67b26ced574960d629ab2b02cf7f5207b8c2ccf7e00c33d7cc562d7e36da01d96e7a8fd4b9eda673a9a4a4de44109b79db502e48978b4d01fbe47aec93f40348db98ae7d944b3ca74ddbd13653e868c7d11571ac7873a33a0e6de1c7ed5c902ed55347a56e0a51db86faf6d4460388893aa914ca45569ad7d01469a04108367257bf9ed536af9ebbfa46eec2c20a481cf537b4c044a17e86412e40253580157f7420eb00ce566c01cb34d00ed449a16e3bd05e661ea914eab203ada8b3f5b8c141410bc60010a9e3878becf271957fb84c1b5a9808a03db9bab03d751edb53dbadc8c37494b8436fea74b463ef27b9ddf41628cbc49dc2d9134ea0a6a9dfbc1af443674792d18fa55d159b9c193b28d7f8cc695cce84d3b5d10871d19ba6b67a709fd21f0a34438be63462ab1c8d901a596e26bc61baea52d5420bcaaa4a33a991386924b4a6daf8cc4c4aa206a8a7515f236cc500f7cc6d883b433c689c86b8d397353ef39d3e8d197187bec6e93470542fdf258d012ff3d324fce964cceaf80d39e19c7853786dc665783c278863268a230ec5f1bb387e8638b26488632bc710c79b8cd336540b4ac3d332e248b1e47a501cb31871a45946fc8923dd92eb61c4f17b11c77ee57a18a2aade451c5947723d4a1c5bf5f3c4f10677224fe5aa98f42cd27beb3c42d2d43ba12445ae753a9138eaa5b77646e07b6742e9a22fec6f1bea84a4a997a24a4ca4451247cdab2160da437928abd6a0d3939339afc94cead8f23c2acf303ff188c05ae72b26721ed19c392a6d2f06797ede239af7984c4f893c2f63d0f23874b64744b9dae5f49f60d90de1d123caf31e11ad9151e022206c72663be100cf274860d9e57450f0c862d514ea93cddea4806521d4460c52a12fdb56daa235a38dfe8dce91a50efaa6379cc093b228cb0615bc357763082c0fd00dd1d714706e4e4fe0d98dd319814f1802a63f80c4d1363aa6c8277da3c5626959b018786b6e760c40853b540539f8f0b8627c9b5c8c706712a1c9143cae9d1a86b2c7f8890a6661bbbd2d92e951ccb1d5319817ef230265c0a925cbc86ca742740936a247d8e9156c0e51449928055bfdc87159fd8bcc397f3689b9b0bf857409b4dae93de83d91c876fa93484f847b5fb60d68ef326402a77bef817211679cee89a04589a05d5ab22711d4660e8f433d20dbe6b7e174da61c6c729647d2c0519d23628998f536812f1cc9e9f18323e4e19d4ea6d339d14b1ce0a62b199204d836d930bc321d0057cef3dba9fee12ce382ad46607ba80efdd47f7d3c34c9cc18a3a261b592c0511322468c98ecf0f50128b81dac6070602f26165069338e341964ce28c19bfec641cfc2bc663fe10b4ffa56b46e87dc67b9c7e9148f7d36788b8d53633ced1cf108974a77dd004f2d86e0f6adfe8e989601134893c3ad08a34ccd08099ed5f90aeee34e498aed31dd444b08777fc1ea76f27effdbe868b280b0761202c2384798cf0e5abef5ee8f253887a8685a08e8b0b4a46285d3142e992f1f2e97e7fbd605e2f7fa98e0a37942a9c3d13e80ba7900b8c54285d41fee2be1da5836f677018241ce29d564dc07289ebc314c1a8aa88a20c3e46d2f77b702791087dbf139b9b54044db37b931c37a3dd3e08ade16eacd42223a02021a2ed73c16eda661e5929ba29d244d67f3a0e4d61f658a1ac7a4d86e3388e8371d54153cb84d2e58ac902cfa96113c3660fadf1f97102e50851122122253427b466bc2162a24490a59ba59b204b9a0f6ac27ab49bb49b6ebaa90673187fdb80e2908d11417b22f4dcc5211edce98974ef7327826b671f561f57b967e502276d83b96054dbbf3085ba77ec6e4ffdf542cd9fa04914cea2a6a9ef3c14970aa50ba32825363933e2184b70bf851dddad42db608b401197fda461491da73c579fcfe60d703dfde8256523a52765408ca677946715b397d5e95e2ba5fdfe0c4b07861b4979ce4a958c92b4981e963c2f8db2393750073bc8e39e061670ae6f9dee38b4bbf0a10c94354ffbb55dfbcbf40c02d2658f4369949075b3c3c77cd3cc23cfc833cade52a55a157a812cc4407ea02069d2698352ad7104ee72ea7ccff99e99a335737e9b019a2f2054c9459572bf302cd334d3c6715d773a79dec5185b5c9b4e2cb9d3b8934da60c732a4a9bbe6df70c33f000aae0b1955918a350a95476eebb1940d2aacb0995f09c73ce39e79c73ce39e79c73ce100878004903c8620059b8a2d8e4cc5893329d5c03691bed2888d4c2d3b2c52160fa4c14b0eb027569df6c6b0a1e67bbecc106d43c8b68a8ac9c89fd339465199e3fd92cf29908984a4c14e8e948a96bcb38203ff43d403f414239a89164a03e42593f4a4c04749780095ae94989e9b2eb315d2671a7069776023ccf812f0bf9727f06f945ee3bbb9c9a74ab64350a151f8c7ac2449426584481018ee283094c677d8655c5a8512c88528226b0962552141c8ac0599648513ee08204df2c91a8d8f27ba92042bef7de7bfc41c1aacf06569a26c5041c53052be12e8a5411453f60274f309625121544ccb4302bbabbfb24a594b259df97659dad95ce70dd2dbbbb9aa4b46196dacd302cbbb55a294db27677d76e8e76ac96386bad73ce6f62ef86b2bbbb7b95c5a35e7bf5346d2775cc30f3e48aa8ed6abb7531796ddf1475b57da379269b0164d9926fdbd576356d19aeb65f6d6f1cc675f7e479adeacdd0d9759da4b66b77db15a328ca4bb15a28d6aad5c2975adf6861ab696816b62a76b5509b8b87bd9384f9805c593bc7b6ddfd7d184b29254c3757391b49b0d786163a250ecce1506f284bdee75ae029a7ada3b5d6aabaaf0b96b2dd19ad197bced91565ad6926cbbecfb31c67e5ef002123d775d65a6b378fab310353c55c8d1968594d612e9cb5d65a183064791b9ed0022c431966b2bcca5a185c8d19e4d15a6badb5d65a6badb596d64862662f4ad44842cec4c4a081ad590c4fdda9a6d59c73ce3967b5b79b0adc53e0be569c3d754a81db0877304e4d5c70a88446a5f09592355db806b4916d2fba452971ccd96da4db48779224c22cdd4ecc264d6c4da249b5496240a5adaf6c71c406d6cf26a50e7b9005e9832c4e89a3bef3cc23b8b5d2ce569c4636ac5ddbe46677db1f8aae9de2942c9b71d2b4327d9c9625176ef23bc1e8c0b2dfdfb44d77eef2386de35d5e0b77286b488b06786add0a9db11614784e9f157a3ab7387fa0e0f9d3edc40904349db8d02e93d87a02cf8deb5e3a18a793a702f2c30563d4d134125f7643a1527895511acbd2a0407699465713331113ab8bca033abdc07030df06838f6fc555a9b38a01c25152d3b6f87af0712ed1982cd3ac8420273799189c944cd2502ae4a492291065891fa0403132a9638616248e2752869c31e37dd36ab5b089c9c31366b819a9a3e78db9a36db69b6c686bda50a0a69108984b1305aa63b491a7112acb24a9348da61112782a914cf03cbd0dab2c4d044c29240af45a64fa2b990a234c2331065c7d31b42886090f528ad4154da89ca85614bdc008aa0bdc5922512194046fc9b244a202c9eb6bcd82e811112724ee89124e4f38e14101948a0287cf6ece8944050e33354f737a737227cf9bc9de8d1cd94bc109aff32e87c8deab8714c516d9331aca9e679444f68cbcc89e1447640f490a25646f0a25b2370513b2f75397e33d9fde7539a7aeeb3a2894724703257207c510b228d727b60dca4fdea050c9dbd1e701909ee8a199cc132c32f67bafb497e34cb637b2cd630e7b00ab007b59e58a4580cd22b7bc6af2387da0b0493491ad7d8693e041b6ff9064fb2b8145b6672d0144b66f2d3145b6bf59628b6cbf838924d95e87091e647b1f3f4a902d52135664fb20f64378e029b2a20705d922393185d648a4273d0455c18194c40b1f656f7a5bcc8af1c7b2d29af327ab1ffe9090c82200150441ca0e47d0a1892dae6a85161c9ceebdf716a08a29aa201d41050917e47ae9e48b5c4f802ea77ead5a0700040eba10c1132c28d2c1553322e48a4509b9d65a6bad03e872aae9ce5c9142be509844c94113219a10198183113f988113272670c245be6f753937092a8081429763391d32908111b95e005d4ef581008a38428a0c7af23d0e298ae8e1847c7fc30a114c04a0cbb959104d412222887c0f802ee762acc3aac75dfca0d65a2b4d9753ab0a853ccac44049be3158220a22dfb3ba9c7b0512f2fdbd8d2ee71a0108971a5d8ee56090c41012723d8d2ea7e2eb92efbdf7d6cc54551d5a22d7cb255fe4fa13ba9cfaa58084a22d8284b061881d5cd7ee90ef6d5d9125592d21e4fa2aee208a17282160090bf27d780437449600bc00887c7f6fcba87281109e0cb124dfcfe872ae0e5c2044bebf8c2ee7c65851854d140948018a8c22ab080154430826941c514285100ff9be75232425dfe3ecd089d1e55c2b39660756646e2411ca5746be484968d00215b4c028dfcb7439d7638295148230ca970547588025df8337075b9c085d71040727515cd91082104583795521b3821d6a561045beff824841be8fa9b5d6245831d55a6b5dc9c000e5fb8f8b201bf2fdd7e5dc252d304034c9f52f5d4e8da18206f1f0f0f0f0726566f2bd916f8e146e952bf962d141965be66bfa9cc008f9bede674052f23dfe807c90efef830cf23d4b07a41f809025120a9ec8f7382ac8f73b74906091ef7dd01a89940223f2fd8f1df23d1024152cc917098810cc9e9f24d02075efbd5755eb0998e8c108b9c644e96105a9272650cad75b629ae00453f23dee726e9623bafa3caa7424e1c812b9fef4717144aa83e245aee7928065c346252022d79bb01458b0c0f7de7b65b6b6872b46b57d3d0a95a25d25fe6c269e364e7baf6d532ed305a5927feb0607e76d83f3bf08a7a84816a95029d449ca191e6cd9c46aadb5564beb6d5c6dadb5565b6bad95752d65d548c2ce9b1a4948b9699a1559cd6a56b16b9bd40cbb364956b38a5ddba466d8b549406024c3b29b558c6b865d9b24ab59ad5992ac6615bbb649cdb06b935c8b65f55aac89bdd762496a766d92ac66b549939a25c96a56b16b9bd40cbb36490f3f584629edaa050101013596654744b367f250a2a9a424e716f40839261cf0ced1907b2f965d4d0b92350d3ba6596c5af98ac874ce9a94659966aa5cd63180e6fb8d6b9d1cd4661e1d8d01b8d1a2b92732da421d6a8fa21c1dcd4b6464c52a8e734b3632d1a28ee3ba9cec5c8e92af69e895b26f5c37b16cfbad8e1193b74b746699419028d0df2dd34aa65b481c944849931247bfe92a04154607c30367adb5d66abfafd60af3711c0cedd32e853ab9a85258adb5d6aeb5d2e66aadb59abefa4e21ccbbf0e338ee30dc878116e6dbea0d169ddbeb5bdb8ddcc5b54b4785286dad6ddb4dada803f3f108e1b6d03e7d9f8a39190c8cecbe10260cb17cc3cb6f90efbcbb84a7a342eda9109fce6d9be9f5321d3564f60009350dcf4f1051103b532d45c5a0f310d335ed58bba789e0ecd9aeeeee3689206632756b5a6babeed349a34d3b88f7eeeeeec60dd35ff7edeeee1fdd4d6df76dccc36ec8a4dd0b4da793e9a76b27d38dd156d3a4dda03426f13594fd6504bb4c6fd38d6097f6ce3aae6e6a2dedeeeeeeee6edadddddddd1747e2e8a9996e6790384c7dad3beba6f4989873358d5efb55dadddddddddddd4597a27c70ea8a17d915503613645d98b04841deacd0e00a29523e71850d04b0a9b42601d93e7b72e5064b0003e8e028b70d8da01818612af02c42cac1d192d1927c7f6f7a22073b80f95e1bca8103a57c9390c30a1702c00110f91efbbee6e1e1e101aa8debbffad72b9e34e10a0c7f35c615786cb57eb4ac8c52c9fe7639764a93ec6e4c2379cc916f9550983ab92546cee33c726792c9642a4185c9932a47dc8006f9524142159e7cabe4906f1523c8f7064de47b8327414248556cc95722596145be5656f07d2bc01f567df58911727d7f587a3afc61d5476b20451133146459d6a22d4e0a121db4a44dca103ed90a3f0099a4184102ac6627006a1a29058a11acd08394a3134801420e4ea464e1e1c8480956f0e1c80713ac00a4e508063aac700223cca4455b18553191a2c413aa1f609ce51429354082942b4220054baa0a295a9c404d391ac1eb6805c7e28b1b2a5a3333151e54262aed16c2b6daeaaa75a956d36af57df5ae13c2e180887a400cd436d3495110060ac24e9877f08bf92ae65cb85abd7bcc2a833978d014b3fa74489b979196ab7b0f76719fa292d71c3b4b9afa56df087675c7b28ecb06536859966119a6cd98d5b1cf307968904d904ab0b7624e1613b302bf556e86180bb1508785c81507912b069238ea05d004b631ffee637599db90e6d9e9c4f82a2624b27acc6d0d22f3c3879521ed31e176b999e5ef30e7f11de6bb1579c01c1477e8618e43bf83dd57a126e60ccbb0cb9d70aaf3509b2a05f28888cce99b9e488cb78d21f3930f7c14ea2791083eea1d3e8a3b3ac222a8cd2ce312f02177a083b9f8918e8fb6416901fa49924a7249cbe441819e96b69940415a308f0e7683e960a6cbe0de7147851dc6f81ceeae0a890cf190f9e94462dcbb4b4844e627d3410d87ca9814ffbc8e80b4e01f7c0423c9f5544bdbdcdc68b9d1727363758e348eeb4c22a89dbe752168df59f1d61e75192fe2dab6a34d8707e60383d4f2da4cb6af802ee073e781cf893b43a6cb10776288def14d220fd43b714746043511b4228fbe07f2a03f9dfeb479a1eaa797c78430609e618c5ac1fc85ff82f197cb513e800ce9c1aa9714d639795b747c00e178b450567da5411955015d05d42b4369aef802c1a4bf3d2d57bd11ecea5fef357c1969b94eefc1ae97270ed1809d0621591682737d873dd8f53a893d77d51bb9ab6966391cdc7c3fbd387111849c4a79f726ec060a522911ec64971d87d2199a4a51fac944c134c651347e61fcc2fc161d2d612a1e2a2d549d46e87299ef338f910abfa3c299546ae6a97fa999c708a76b9bb2034d220ef541e8072182a0266a42c2f4f416316926131309fa827481e22be634ae9d5e763498aef352dd45073c3dfdbe99cb0edc449d54ea0b4d31e20bc66988add7ccbf59e33468d8d0a1f942a2239c38f111117dd8957c8fafdce9badfbdbf918c78c2c799742d3cf97e0211614433c7a1da0c16521ecabad7b86f93a3b1f11a31a18d7f618deffb6ee3ab71302472facc65c29913f14e833bd885d265c3077e5e3e1b5126da24263b51c7468d6b349c44481cf7369c454c14ee64a20411d176ecdb313107e3b09087c4714fc308481cf735ec3169ee5bf220dfcb69805162916f9fbcf7a8f7fa5e9f88f77aaa3389e6119d1374a1d67e4a24e2bd3d3123e26a5d81ebfbd6868d1aef4efb76c2c57322b8bd473d8df7e8cf3c6b1b1ad6b16f5907baa052a95c5c8e851a973acd79a44e23ee0ca5ceb130ecf5347e0ac14d74a19e463d0d90477fe6fd996f36c298d708bfd308653e13823f219471318cf187ab87e18c9b64fe8a713026e6b3114a578d50ba6884d235134ad709a17489e1ea33fe7ac9f84be6317fc5f80bfcf710fbc01833626464ac5633680201a95c52a8ebbc6e38cccb61c80e877ea1c47850d6bd7709a7118c705a8109a7922a944df312624c74a94c918cc61862cbf0860aa56babd8f3b048843bbdc7759e37c34b5dc67be0cfc09781539e086e3264789e0c4fba304e81312a182f3231c0548c8631d6d96f93f3665c4638e3a950c6679703eae0bf205d58c6f16734c185c59d222e19f742e98281a5de033fa54a9d66b022a8dd471fdf07bd77da64c8a0e105e97ac5b8cc410dbfd536dc4fa857b1cfbd07fde93911d44417f03deff41e4a04adc803bf8f6784aacb0853c7e1cbbd10c66384df654218305c7d7ff90be63054aad48c50ba64c4c0aecb577fbdbe544c0a06cc4af5f2b9bcf0bda750c7a12714f63aee5404a348465d78b01af6fbdea494d8eb0b610cf517c3c6bb60ba9434d5625a835594ae4a69e85749e00f1771dac5a5f8b23bf71eddb97bdd390cded17581e6bd9d0862e071e826734cd7ad26d00cbaf77e9c49aa7b552e40da665e252077f64c1ea07b6d035f589d0b633ebbd9e9bc6ee877bf819e337d87398881a1746d5401dd5d9a7b56dbb488d3ad6b230b8c2375683aa60d12c7fdbd6bdacc0f4c9afb9b4a4d1e937582c70964354cd459695207f6fb2c6da60f92e6fe62e20492382e1026e69854a0f73250d6fd15370134812d0dd5ae56b6d33e1f3f50d08257407fb3fb19247564190402ef910c199036d3064973efbdbd17401398bab03a781f3197b9ec74624089114e2019d0081715e50beaac565d4cb80a890c61b2c3441e74fb42ef30e1e92f21ea30427c9770bb2a4cdda47d3064568552861934899aa6681e4da12d9c404d738300a1ac234b5d70d8e44ca62da874cc18aa8a542a4423000000006315002020100a874462a1582c0ba551691f14800f6fa04282509aca63599003310a2165083184004080001181991ada0601fd82634adc2824281203f473de42304f27d11339012eacda6bda324f075527db854560cd2a2dafd6ace87109a59fbc5d4644c52b48f0b9ebce3b084059fe1288dfda16b8b1e8d8267c4a0dc133135ff4abb014e23c32e9d45ff23fa2640984400bee8a8d9128a6cc1d82caf4ce3417545e2218fc336ae83a81188c6d94ce4e0dc1c279edcbb3e92c5618edaac168af66c644283548aa99c838aabed494cebc5f5540782f2707f1928eb3fc54744fb0b57c4e7faca1d6b72c86e4656c892019a8a38cf884415589ec814a06cf0a0d382bcc013752ff51c64ebe01cab45c3f8292154fe191ab0b94605c72adc1f08139bbc166d961e2bd6a5b4aa47a774f94f0dd4408b6bd595a29b68a30ca9eb51e8739667f81f2bf67f5617633dae1f3afaf4b871efddf351b20b578cad1eda0b933965a915d86c620d87d3c27c63aa7f06a1c0939d70428a358bb251832fe6acf840d47d56933019c0a21177a1cde1568ead435a2de0ebf8f6811afa61b28ade96fd4256e2ced26918f4bcb4b7a150c85a4f96815dcaff0a1626f4c547226131ebf6493554e9cf09ae507ac54c3bf53a7e33f54740d4b42d030cca261919468fc7b658fdde789209e8b2bd1913774feeadcc9fb51ed6362b9a3320d33b91ecd29603688994b3be4648c728f8007b948be7a66a06b3bf34f8b1a5ad5be075e86e670abf38fce4ebf8e681f2b891b8777069ad4471224663aa0bf1df263e4a9187c5df5b964a49bd43a4888ee7a70cc2c1d9132decc2e4ef97f04dac47eefa582452f575f1581b64bf048ea766e04d246340b32ec81c91b32d20478f1c5681951dd320d3d51f1cf3e416951453c6c40eee16220b49b3d9177fd292b94772f6504cf4d7c01e33b557229dec5ad4b517b7af946d2ee0e0681d91c799a91b815495597dfed5dfc1cd568f925ccaf0a33acbba12d1fda020d555248c090214c050229ef137189822c6cf2c8c9c612388a477c1df0e3450254694e8fc1dee0df771945c397bd7bc9a4590334f266ef45070a2bc4799c7484d8750cc7f82158ee9727b2a768f83ea2f45114bc82f422722bfff6bb3673477ddbd5d704edcd1cd42624b40e697c1b4b3a3adabe3ceb89e16358d8536204716e62daf3c2110f53b3fee5b33a46c91212813f96f75b6c05c7bde29068e3a5f28ee9ca4215d2dfa1a96f900a8d5b15a6a1ee834632ccfc2c9116764d70988ebf49c65d271af59b2d5971e75ae9cb796fd240061cb7c1fb21f09ed595ecef54dca0d29441732b7b64c1cd989bc1b1c148da8d9102cf6c9dd1835f4eed130cd573d56f2e4c34bd2ccecd37b8f32b0fc497d23ed200c30373b98e6a4d1f7b4fea77c28354d19bd8722af74e8df654173f7583a8ad011dd873e763d9a6bbe35696f50d9eab7e3e13c8bec6ecf4cac3bbac32ad96c6e54a4f542f5669b8927574e28cef24eb4b3cb1d5ca907ddee314a6a10b45ff1e7de2ef0b408dce0ec1d37d14b37c9f8ba36d2d62d70a8f62a420ad12e2aa3f7e0f50167001cbc536b9f7da5a06b093f89196b40085d5a432fb7fbc0e0852a259b20322ecad870095da9602f54d0475aea449442b8a7540f59803ee68880aeecf026927ae861628775f2342f2bfa6449d8d3bbef9f33d7a881d411445524397914a95c0f24d60be552265ef2b76b9b8d085d2421a0c78673d92414a0f75fc8128b7a5a0459de5ee38cfff42d7264a34dc1e260691c4fd3349a98043b62cac9c6e88d928c7680102105371e92165c0cb21caa201c46e90eab6a2194e2076e3f76e92d9cb33b99893586dbdaa7916f7dd167ac45b1a7fab370e1ad2c5f528331f1c775162084cc0a87ddfec7cd982215a6b26804365b067a9ea57466b988c358052357d1659cdbfde2410d36105643e6abba3d094abcae8421181bf92831028c50cca4b334667b08055af137f48c1c037078caa1f78e1bce7f1887fe64ac1dace0efc6d52f8130145cae140394648c1f659828ca9b02320fe6caa1a912391b635605c45225400b42a5ef72e279ed93284e0db4188d035dc1dbd0ccd000a07a5975d7f6dfffdf6453e0990693ee1ec91e4fbc59047c2d8a8af5a373dfe0058131d222c690ab0868d4a6f7495e4a133382d8f3e3014d24229cb45fb84238a2df2c811e6b7622ff615acf0f8c63297ec3b738104831462d497d3cbc0465f8fbcdd88827df6e25bc6393ca6b8df87c223e8c8a763b4fe49996367d495ba31868652b2ffb9f691b7afdbc5a8bb935f99bb8eb3bbd336b84a05fa8ba1446e98bd75ed0095abcd90fd95c75e906e9c6aed8e6e1080f5c2c603ea2b31abb49872f57dfb4dec30e48b9197833a6940135a2661d209d0e0e24f69457b507200bb06c4dc1be04a53f52e34cdd42267931647bbca22a40dc227ed7e42a98aea07fc213f64481df03a848d6065041ff2956feeda2d4be27f25ad5231f0622633e48a8ce7cd2ad4e20aec657e75091febef9f4594a52bd76b462b73e9c27e6e6c1f372fa5e6ac7605c00610bf4b607f55c8c8e59d97cdbbf73310ae897d89bff334fb63c55142b6728a7b8ed09c4c5f490f93f786e922df93b93b9a453eacc0b76c1323a3660d91b1fa10f096325cec6bc0c273361820517a0404803d7a98cfcb0e9dbc2d46961263c99e7e8ef37a6f23a71a3cc7ff3d4317e0802ef43bc7e2dcf7775c8154c180c795330f2f601a6e8bf9f430c61e389d36db628b829a860aa457f0b0e7193cdf5c44acba9b1ed4089557fc8b70c18bec098192252b2ced2f195904b14a121f4447a83c98614dd2202e2d2c4e58a10ce06b0f181dc80842ced673ea4878bc4b793fb6f953750bdda4591c1fc4e479cdfa33f94b4ecb622e3a24941dcc5931b64025f2e9523d926bd2146ba40213f98e0888e0e94998ad6360b7d4127d878d1cd01872fa448dd9466a303ac71472ae170b2d1c28e12fb07deb46c2cf46d2da822d616ab8dcb253efd62f2e97d88ccb95d13c1593b7b0bd1b2d37bfe88860f4d0fa92a762c57faf4ea3a17de0edfd73e799d0cd26d0f4fa6eb15d12a0f392689bac1b8f9338e6be46e9b02acd6d48424298736fe255daad5d2dfde3765c30d1a09ffbdde2a466fd2a05d83b3d5ce97afc3577354dd31714d8cb2b5a9bb98bee65d69ac1a9d13fd240935e42d48a57aa8a214bd2984e6d7440046627aced83d0601767d799b7476824118b9be3454a3f863db8fa252ab87859fca89a23018ad2b8ffb18dbd68d6aee574bd721f129b31feecf810ebe9d453ca54fe14c69dd4452c11481cb0626da7ea018035585fd51eb11391ffe679154925fcdbf639f9cf153cb6a6f3aae714fdb67d622544fe27fde8bac0a88c1bc305e400b8326f23af6159862470647e7ff0e755acbf2211929b7be8326a1d0cf5d01337e93d22aef00bd63da977b7a905650e43f815066f411088f7234d5e0cdb397f99778a5147fd405787bf8a3787dc5f71328dcc29aa1d84c3c27fccc110992201078264ac00e650feaabb52cf6ca22045425ee4a6cb284d0c422ab4ebe3873e535f290c94aa2d61d25b8637b5828a7f4479bfe07139c391196815632baa2a5c99f097160ec07e3b97dc312adc4bf9d2a619340baa0f1b9958bf20ed2ca8ea63135e3077ea171f681fa1c80fb2d7ad9f706948b22caf19281b7b999d3e5b29e17e608c6819d876885b00859fd81ee885b2d172f277edded648e22361a77411c7a211f1e660cd5ac40c2a7cc84f97e0c13da92b88b1ab8cadbca65c5e4bc478790c416a0159c15ee86a62747f4126f632db1a2f71f42dfed8429f02e9581e20dba38280a9a5d402cbd139b63aa5b124abdbfb041614ed6ad9bd5fe3fea28bc8337e7b7fa60b864f9c49e567a53359b172e8ef409b4ed0787891602818c81405bde68fbbb0a0c95bb5ac22efbf14d897891fe472ecc5098cb83c796d4f02a3d95b2a63ba2ba035a807f963418e1ca3e3a117707926fb579ee71ad942415e6d24570730c3e058f60879d99a47d0d6d4f6b04f9421282bf1e41cb6953d0a838370ba42e14559f32ddaf30a828db94bd9956b160e98af56aebdb02d5f6c84180a31a524a6d31dfe83bedada17bd0590e70df31f97bf572ba17e0fc650971ce86bdee28de19181ef3a3ea8ec288f74e10c2048cf18214e18d30c81829e0d243e8b9532ff38b3c5f5d2e35e82fd4bb22e9c5f234c53ded9014a1b09b75549b9fdb1a86c21bf5d1830a7c5dc851337def32153af699b38d48024e912c969782f530bd3296538f4ddec4bd0703573aa0f2671c365de12f97b4cec4a4b29793c7be99038df64cd6370d045efed2807c7a075747a84adbbf7b233683dfa900959805a1da6fe1fa4396cb864fc4e37fa8f62da5c8a0e33188e1f6093bdeb83c223d1debe91bd6b10f2aaf4c08af09647638b130b719340595e06c3541f6ad1f172931855b2a7cd84b0304c93effe1d9e014063c00c809089f31a90d7961ce422191a534e0d371e264f5e4b6bd295503ce5fbf6025357898efff21ca739dae1aef29e0b1c732b4946e94d4c57db1d0024e0815094e67f7732460d4a5ece0674960f2b3e529d50370a0c10f808100ff10823b06c1c8d2085f745ebdec7cb4c2858d02107c7425c28dff607d8d1965460b54b8d6f0472522c854153ae784451c67eccec0aefef0d6f81b52408d63202ff81261a8eb420ffe8c365f6573155669faee76b964065edb1570300a203ca1fc541a81c18c9ae97f8c190e0683611cedf632fc69c3b545b0320b82a1087140715c8415d0d4803115ee823ac205ccae1985e557031c087c4e183d08ce819072e16da8d33189c6b25842d68691061193c2f5c8e8bf5cb40383cbec5f441237815711771f34b07f590512dba74c310eec8687c79f6ce99c3b43a3278e6168c0eb69274ef8539f290a2ebb9faa2c5c0d5bd07ad9862edfd1042e844e84bafb8c3bece908592d4089aa365381c8825d176c2088da7e88d6bfee49ae73c0ae63daf2bb6b341230f64aea787c2c0fc01e97eef6b7090e0312ab59b4ef7618720dc5266dad0b7fb709fa20efaba616006080635f732bedd7ed0351abe15c19515b012b6c7f4e3fc4bed3872a17fe5874cadba4807004c577cb6374cc683a0404f2ab08d14cf24522b18e48cadf09766b1a7d69c120c37da772812f78dd57b45fb2beb470bbd2012d2e23031d4e81a2c8fa278381ed54a062f2aabea86ca3672632323e81cf6ec0e08ad0db115293dee081c0508f784f4ae2f4e7763b27c53312d03f8412eb4ffb6c9c1ef441d9e8d0aca2a4d022daf369c3a53e045a27fd1eb33557dce3874b917ae16a6559f63bdf2ea186c1a91de975aadcbb1251f1f4ab0b732a23e679375dd8f398c286fae1cdf61a02d7de1a00da5c940f35244710ca70c86582a8ed9f37f1d756784c8188477f20005363e10080a0c7590bb91aa3db5856b1b3ca33efacb48e9739c66506dcbf315f3c9877aa6f33e94dab09ce20e55b40e899fcf41c795236c3f0c86c7fa4c439d525aef85cb1489a2fad2faa5ef4741ccf5eb61ae43b3e470ef9258c613511e2dc41aa4bb85a027addf106a13a8241abfb0490e81a44199aa9352568017dca71df1986512be286b46e32b7cc0ce601dbcf3106a625f4a1df467fdbd52cbbb71b5d47d859ee403739938f5da80f42d45842d382352d85f2529860aeab45aa5235cf7eea910e586458e645cf97f834af6fd021883d62bec600f72ed6ad7c3909cc9f2cb2d016e256c8bba6cad365e8ba5a926b3690a61bfcb2005eac33a61fcdd0a47d69834870620db92f8528247ef39b0368ddbac509ac725ed1bdb5f801e73855b4342b27fbad3971851312176815481ae499e348a88690b595156f31e8ffea4c8539b404de85028aa814963985072034627698fa3b87b1975bc893eba49440e52208069bf613450dbbc610f253fdd1a63839c506d3f49aff0d66f1a7375c8531616e0954050ccdeb98e092c2d916a1b44dab82f62dc205717c288583ab40efc71959b9d095c0a93e85a2cd1821645245c60d93a3e1d0ab4e2416daa904a49c1fbf983eaea916eb3d3075e2a3efbe9571efcc6da265759a8b866a76ccd1da370f72c78e0536b0de3dd7b9122f477c6382b90ec37ea4740c5161cff3ec99f6facf5b2196959b67c7deabc4946bef553a317c92ed24b0bb76f146da23ac83fde5ab4ba35d73785b55100b39aa2b4b8d92229da926c02dc45c9caa2ee98eb911655a1b6d98e6cd4e483b60030795ff48664e9222440637ae06c55c14ba6f3426434ee276761945a77254af51badc37a19fb9b1ac0442dc756be51b354dd6e52613e646ac75ef7cac456a51182e9cf8ec55c1493bf3f4ec52792040dc246af54b8524f5c24a4b6c40a9f15e268672e9b6531ef726495b355ba35104fe804a6447d2f55ce89c45c24a9e851cca5ee93454b3434584dad10376c682e19a87a499483022dd8fede9330b1c17d04e228be075d6d69f80e1b0f04104a34e8e8958e1b88df0580df1af1b0dfbf5748681e6ce861940e63ca063cec7a4fd1133e2e9e841a6245e0681e466102785fbc372894bb03b51ddcacbfdb971ae806574bf7855f64b46a4515227f72a18b615d86f03d77c782872700f667071bfb221c52ef0fd04e032355ecde2a30222716272bdd0f63cbbc126fd0a2283ac8e5063df6a18eb198ab71f31430438b760c12400a36957fd6410eb2464607ce6079a5a6e68ab53085059a86078d81d0c02124f05948449ae5e081964675f16996e49d832ca4c4ab8ba984d36215cd4979e4789a7f35fcb3e8496158eb615564a5d7fc25466063b6cd232c88d3c502515479c9877bf1bbac02afb351e86c4a58a283e0926866249755a6fb43168dba1ac8f48b3e07c5d562c3e466bfdeb3d8a73668639d1315d99a8d4bbb50cbf802a5b929745144249ee0ca8f40ed469db8021f05c8528634f20aef442f812b196c811a117a7959a88ec8d698a787308e8abacdf81a5491fc439854cd54ff2452e576cc3166baab65887e3cd8fc9b231299f088daf2994b1529a502bb85370641d3f3967784a7e70506c2227c7159aa06aec3e8eb33d0f2db9f985f409e2578e0e1d3d7b11eaee9529e8e5d1d03d61eb9a3e8098484d543b554895046aff22c2cf177153006a98c8dd86becedc904c90e3c4435f7c40209a55eb0263c6db41b59619da67e5ca0e7bc030681cdd11b51d14b9b004cef65bbc7c43ff01ac6f5e6cb58e7094ad3dd750f9412285e593e8c997642dd4664403605ea60053d1597546c63922ae4130f738f31f5c500f583d26a86d6e28c9199b0b443e384b16c2e5b6c170a12a8f369a12e8a2e773c45b14a752d74e35613496b1b92425c396854d79878b249b63b9e067eab1b0da87be0849852ab9c405f92baced4bb97c00bb3807a509251bead6467afe018bc65d7beff41904c7b1ec98141742655a289044d2a551152a9c305dd9e44207a1eee534a02a7017565ca15ca69029abe066ce045c7db8861c16da434a088453414263631e58e527f07a94e22bd19124868f7ab6969b075389d7ededd54226765e739cece81379412d342673b105a8fbd2f9316d55de431197094d589ab908cc11114d06369689c1aac718a280508fd007f2de5a4247b998598f894567c3fbcda8751b97dc1945a7dfa29ab0d217efb55e4bbe581c3d7ba8ace3c11cb7fcdfee29deb705795c7cc23c78f44446488cd94ad923cbda241ab23409ae6559e7abb98d828a037f55d6f024e5e33237b1fd62918dfaf461c98fde26467be9d1f659d2f3fb5117ca971ec4d479a2d554cc8676a826481433c2e7e72cf8506374daf91e28e953fad9e16181f1d040042597220a07d41d241b2f56d920953f76397a7d1833b760acc1a442d6d0ae88c25958e083d86c737416b7465035b232546ae119689550fceb0902fb9bdb3d3919eebfaf3c5159fb30f37ff8f4a8a9125e04d6cbb05f7b3786f778afed1daefd9ba8ae175df0790ce911210ce283679c3c1c08a3594705544724161e23c00508ee21c8e0c9c2e8a3600ecd0458ba5c47eacc35416209b0fd5ac607f71a486fdd13a0a3beef801a6a458e7398a77355c33df48df0a037a541b69f0327a938300c93566ee88643d6e3acd018aa1fc117cbf3a5eb5e43d9dfaf4fe5b5348d8bcedd7720613380c8a58b14360e00d4790ae316f7e59ae45893a1140c8f45f9ad6f75890a9a9503795ae77c51674ffdcf823506b2c48cd4a2141a6b300a569b1ea9a47f563b52676d1c176e840dfc9a9d9219c10b952e8ac00e49a54905645f0128266c5489fc447686f2a3a0205c2246168fe7dd232eb971cd9b7677f554de4995c17647e649e3e6f6b44522366498fe32bf251a038db83255ccc61ab9e0004db90a6b78b7ecdaa317e1200b24200c1ad23cce28b0064685d5d3390e8d927d9a7041bb98f587a58b506c35440d77c613135321986fceb92b566d806e3bd79bdfd5de1c26945d97c39f0458d1cb1b6090977f36f632cbc5a187a5ca396cd6fe1681f8ab22e6d4094fa68dbea28d7ce3d21578ca0ae4bdd359167d2d7b4f43af95bfbf6b1f87815b8086dc606ba158f47463a9fa6935fa324a9bfdbcd961c122d744d0350f9ba824eb72675484de81c01ee84f2561759690fe5fe7d61954f219dbc2832ad1fdab300773d27ff6d4fa6a0b018bd0f9c3cbde52a0273316c4eeafa4f1f033d2c9a6767d8e60588004563bd8be14d4e0ee9edf5ebed5d67288258d6a4484b174af1dd2c311ced6dabf900e58abc0cd9337d994385f9ec1ba98b488194a534aec155993d5287c61d639235271dd50e8465f394eab49a7aeee0a3751d2861f0199e659d519e2e06e30b683185f221a4cc6a4ac6482270d584c5a0fb1f95d60a04f56e4537c1dfdaf04587893dd7307dfa4db2e8a7088c18c362539cd18e79782663dd849a9b40809f0f6ee6a8acfb03f8f77bc1916c5a0e01c6f0386f65e9675f35db96afdedd554d05e4474e5435572c62e823afc894d5850c894f352780fa75f161eeba5a12a2e6abad56a4e3bda768573a2e44e4d4bc6d584db1ca4407acac2a3c54d3c95ae8e05159f32e862bdd11ffd6d1e46004ae9e67c419466186dcb431d4093b31fcf677de1151fdb4d0f397a20dd7182b39f4b7a47c6ea0f3580fad3d67f0e7b38d93d285dc9d4b856ca4739e196d844298f3310e594479a95fb401d3a38fe61bf9dd206a303cf6af7a8c0e55fbd302ff1125b41be4bf50789a500698e23fb0afcf898d5d4066a0c786cc301f82586d1a73bc09bd089ab3dde2fc2f7fd24c2c97b5a707eef90042417c3fabbcad05ec42f9143e1c5225172b775aa2a84def827f0cd8fe3702ebf9b35278065837caea1ede4c46fdffb9808c8cfa9fd3489d6c8ad91061182baff03787a116f40ee87ece79d8721c25040a905a3d9b4e70fbaee914df7276c8be7c1c3167629a909436bd717cb9bfce11382e1512e8eda9ac53ecb3700bf3082cb736405c1074350c795ebd2979dc92371015e402df2656bbb003458162db40ee4533f3dd93a65777ae6c50edae9456b51c0d6842ed11ab6f05c12c43900e83ba959f2ddc97f1a352c26ea38ec9769f2f1373a4abd44a2c948f5c941d6b9d4a2c0ca9d59667291b8c18fd3918111ac6a92d54ea4eda7cffa0b4e6bc13adb04da33407f53281b443e0b6f048a0068ce669641a01f0bc31368fe864e985d76a124b032286293b21622722850c7ca49149989d0f0dd748c1a86bd3188d123be5cf781a3a567a822c7d7ea9895149fae27f846a862bac9a7221ea970476e69c5e2d0ab2aedd07079dda75c968d535db44e614adecbbc617ae6411c52c660a21a81861d44b5b982a7ac9d961496004a743b7db26a051b541f3b11a510af184240020bff7495adcfa239df36b28da5805510e20f5977fe0fecf1e19c5e8c3ed1368d4057171eb85318dbd1e2662538ba24845d889b65ba132fff166c95caac0a580102a7ccc05d99f87680ea8334352055741022d6ca21de5c7bbefb7694b5f39cd07714b8e079728be1dadd50ec56e33abeb94c0f3c0c7227583011ca09ad9995be8a86893e84fbfc2d0bbdf73f3a447a06762ce91ced3fbe3552a53f4a89a0655e018fd06315632d64540e9e8d99b8c02fd28ab51bc4833f19a3c7e36e5171e798d80d0aef70a84bdc4bd6fee6ee5dabe572e5def264d78f86f55d5681bd183705aae738554efd5a6eac73b82e95f8860dfa579babd7e5921f0e6258362edcbb263e1f67ea370e2db296958d1a9fb77c665a28c2e100be7e71aca40b3424cfb54d6ab00ddcc7acfb0f12d68050cc596a915ab0563b13d76105f55b3261c3058729b0871ef4a3a65636549918fb8631f13de9fe78a00e9c50c01c1c6097af56b6193c1bdcf62361746c9914475d92221f13ea0e74c4398042740470cb9cd67f5b56315bb0794059858233af823bf6222e1de3ef77187fb00410055c4f18cc719250381885bfa95184e2a6cf7c529452ead01bb8892fe85e9c32193a11a30ea2685b3add7c6b605432fdf222d25f00ff05fab676b2bd837f1bd47705045020277ccbd4e877f0ac62b96d8839bb49dc697aef148de76fa21109175b6d6904a5c04778cfbaee74f8651c10d4c62b3f612a67eb27e6c75e822d7a87d6aca06d3ab54b8c22e1864722e12630fb5f00c7cc2cbe53e88f66c83bf6a0b23bd9ddce15d46995e51476d2df587ecfb72aa571c949a153874848502a3b79e047deb52b113fa3d38b0c603dde66c33870a3930bd5a4ff1dcbbfa6242dfee2bda3f286623216cd866295939ee2cf26a76650742e8ae3b435644a9b90fb6f461f903ce4a5294111fcb3baef7d86423964e53ecd8b6e7688ac390176ee73111895e16c1535595e70667c7686ae80e76ab31fdb1dc5cd01f2d3059a731e4b33a9902a1fa32a646cd1d9f2e2fe00f2dba588c7c32b3400509a80ca5388fc308feb1e5ccefccbb513e093e7198fe02c6cd468797caed74cf9c3a78ebab3fe8896d40e0dafc818ea703dc31f5206e4cda8bfe46ff3ffbd79c813cf8dd67c6e1dfc5fcbd83bc586448d8bd1c20a3639e3b23de64034cbdb83909d1ff513c762c81427b34ffbb88c5bb855698f4027710f170702c33b5242ccedffa3d7f5dad702d8b7df84d57dcfa72f36035389769515bbb0b5add5e1733b3a549b0d0458a85cd880883990398676b557ad190c40c5d09b553b3b165a9635867ff309b9a582083e6ae013bf14f029add51926f9f5d512c448f82ce207789a3c5bb12d666218224ae9eebcb4ca2af59d5cd15a673634f2726c20a8d663a9ae08a8b6cea5be96c1e3c8f04805313b2e0eb4b54fb86b9578ff8a3148652952924082fed2f172da1d848ce500914c6aa768d86403c1d48b48a7948215db87ea3c2da7463a69268a6cff945a5850570530aefc0ed6131f96302f94d03e9b4255f73e1e95bc1f0905a7218c0315242394e6a2347b8c7f636cb7813efbb3fdad4adb0be902a09ee618f7d524843dd6e98efd92f0e6df4f0c1dd9affa89915ba2028abc9e9fa3f1f58737846b11b6c55582b35d63cfb689f20135a20cc887ded373fb187d502a2aed8c71dc4f7ecdb026a591ac1a87a1093838c9951682419425d2221373a162c60f07d20e6b78a5fd1f669025f217272fd1042f0045f9684d8ac15088908fd890db5ea96fb00c4368949385f1392acc18dac4beb83e32e06ab8dd455838ededa0313a6013ebb9ded9cdc32891a8bbc4707c1c3b380e6f235c79cd1d2dc3f09401720420bbe84694c13290db4341de54c68dad05814b7ba96f11e6585aeae59bb7a949009295631efe3e2d162016435e3e32c04c1ad1dad1b8e8eabcec260a7d0865fbab7c2fcd28b173e6d83e80b92f8db7de02448634bed61b34e07574649e8c6cc81cb6bca4b42e07c62d17fe568cc742ae2cb85d013839857346c46686da435a8fccb5afa63f1313fa25326a3b2a39635f1a410294797f45306058964654d0801a79eedc64c1cabadb54cc844c8b4af50cfec5922c3bbb7fc0e91adaf042d167d6f021b7a1e8335a1e9763f814217cc42933460d178526de09b6f459c13cb1105626b20f7d5a81596d51b1a703a31df3616acc9b51e48779d1fceb29cae003e0626d8533cbcfb56024bcdcce656774212b0e968328c88125dd0593b0d9aa1ebc76606fa78ccb8569bfd43d1e7e31e82bb3f755ac8e4dd27c4db0d2b45607881feebddbc6b87b160c057371a34763190acbd42e68ccd374d1e16e06f472bf940b990147a2a973139a9329d19f19ff7ed094727b3b49e5a656204dd2d2cd7088f97835d47853569161ae0246fdb592eeaae22af2d035d5e884f515f560afb860c6da17d1702be3704895394b6515a4ece2eee862d76bd38484c96f218b89ac907292e342737c7a5d79ae5d0709549286b277d13a1d12b9c39f6f04178ed488a25a674fb0b12921d4a46266152bc53cfbf59508d713b59d0711752f64ed0a28919a4e24840d90eb65d2bbad32dcfc0b475fd2236bcc24253856798b5caa257c13c1bf14fa0f83bfaa28ecaaece37ae341568493786dd4eb8d037db3dedb02df86c66e6775d301f5ed061f482eccae39aea2ddcaea380c58a5685e6fe0ae2f042103ffbc0b470b54e2ae441c4c0806d55be5346f48a438706960103c128f4c42c43c008ad115fc29bf050b494806d815e7f60a3851940d953787fe9fe214d4ad3605d52b3455288eeaf0c408d85ff93582692bbe87f7d8e2d5a633598d4fbb4107f6aa415bb1d1486ce011d88d6c647b092f7c31d21717f40941e7c2e43bb70d2040d734925f00bb05f929141e9dc53c2936af79d51d0aca82cb7ff097d953dd412ae5fd60c32030ce18a16e7110b3906bd883e159b9d5679897a26040714036ac2e3b746e931283df9171b4f66f3e52c9f4093a14fd0b3efd1baf9372b704292c64d18a0875dea3e3537c0dcd83accc22cc6db7f0d04890ecf6673010174655ae219a7867aa1d48032fbc67d4700b4ad77c2fe40be8f5821303a145e61f6598c2b181ed74bc8905e6e3d8540993c640c123fbbd273d8f81949b787f1988b3cf996ef6288786f86f60c0a888fa14413718e2dd9a760fe0668c668ae337c08c1e20019da1148a801fa36d324f8689f38926132cd2a1f08ea0fc224b3381ff02b25229725d41676f29d28e77d290f8d590d9ac8e64207c2339a8a6cccd497e25d7f67b64e0da69d61a737654099e09673d6c7f45e330dc063686a9b24cf44ef3ced2bb82f001263a0044d4643e82b3daf6ac02e7a3c88712bc3b7c3928cfbfea74ff2891a3a04c62c67c8d944bbedb5081b01c04f2010a9b6b5e74c6af0a108c7731e5405de87f76868d587f09ad179414bca77044921a03a283ce2cf412ee7d228c812fad7248990cbcff59ce1dbfa3b8cd2415a8ba35b1270603d9fff2c6801ad9ad98842b3871357168b16c264069a9fc912d3dfc11e1bfcde4bea5de357f551ce7329004bb9c1613e9a10659765cb40661ac7a5bc618d02935c675572c3b5ce39f9caf87f9d600d5dc950c799226f5c24a059c0740bd6daf395b07e30e51b4160e284382704871468ded74ac00a94cc5ff5bf456693da604cf2eab0ebd59cb3df1ac204be84d0f07375609d4a1f96c39b4a49098bc384a3358a2d9845ac7ba029dcd362c7d62fd5743c7dfbbba7b0ae6e2d258ca0ac1016ebf3b8c0a9f75dffb06d3709f64fe1da3f2f497224c4676e84b45c7db5fd8bdc41f0892e73ae790cc99c7d38b2fd27d6f04a8463fd8b4e739ca0c5a969a541aa2205f4341452e325b27f3a869e419c7c7749b33820366d2fee339e1d84bf47472802eedbb605867a9aa17af7881c6259d7b9bffb0f5f4f419b59c2bfe16829c1ad92274b5e1d4afc7896f5bca176a2caa4ddbfa42db5f1c548d0d45fe57d1b35790ccc66a19f18ab08853bf6faf81136914141278231660d2db216dd0338f18e0eb0c9774677c8bfddb34e68cdb0605ae604afdff8469d1e41370f066d2d151cff29c4e11a10f9c947222185c17aab7ea432c2b2e2f428c5913fc4b20523f81ff8812a7cc8ed6538700a439679f5978170b96c1fbf9f8a277bb76f77201a9d39a99cc3d3cf49e9a3d69333bda6ba51aa6c2c44440069994cbdb03efbeb28ef74132b6768741282c167f46ac2bbbf7db823f6659a08890ee87130e2d8290eabc84a8b46eda49523c5583d9c41bb088b7378192db1ea7b32cf10badd52dfe2ad5805459a3d73d6d945560f7050cc7e01e2f73e143ff45e898e0999073845d2a731edfdf90d88378e7e8b21ae672f904631b6dd3cfd9a225917a5cb035a8ce8560cbbc717e38988a1168ecbedbef7a11992d51ff32c12eb0cc6ad583d5ce1bec47e3bc8f78ee9022b1d75bcd228847e81b91d5924b870705f38a1f309ea4ee477f567ab13e3a2a9fffe619fc005dfc424b08e3edb0da028bd2c4c030104ad4f80b2a229bb460c82da2c0d39591357efc1e58891217d33dbcd8936be2b74e3da283091e2c691bc64224578a125a96b2c43a368425125aa011f8fbd89a08642b5a079b1cb1f59c2284011ebc497208bda0512c83867ce3e9f2d4e6085398d164d4aa01fbd8ec4427adc54ea153758effb7a1b462ca4e7805e5232b601b90be90671f874218d78b33adbcbab5680d9757756392035a0f62c2d790ce996a8af3df91c4e0cf94ccc2dac38418307610bf7d9eeb98afd7320168b90218dce9dea615469c2b06d70879745967cf3c904799b991f7f8fdede8b9ae250ac2c9188740ab73174c3386c352688ad96550b1280020d8f7395dacfb98e84b3ee343cfdf81bd840aa96034157b264cb5b6135d347ae036dee257e9147f608b8fcb041599387dae52eabe2836d91c2f2137c45005925d0e64431957932fca927cf5e9d8c25f12384ef5f2c320176bbe0fa5a8da580b48f265ad9062a3cef66e606dc9b85c9be367506d4214ec231669e0c56689f6f300245fc86b7ac3723e111328d6188252a33e21fd7e00506a42a8654752125b445fe0185b6575bb9a5cd0e336429a8e68f284f06291bda852425ed9d53a7ab7d4123d6f9211afea2709d67b94cc93de84273b090901ea7007693425f1ce634e25039e46632241366cd9468502136f307d337749972423f801bda7a5b44a1895d10b361eb162e83b0958bacacb22894412dc3d2fa60d93a37307f27d8a0f823eacf7ab7ef8009b98fb2f9d90a71e81354bba058a32e844187bd4fd3e40c40942d8eeef3ea2e79a86174cc339f9cb84473229d20b32cbecf6389c349a1e60e20da9c52de1d58ca2b9895c6009d470a4013464a460a36de00321c28276f4d69445688c3c6ad1de9906735c52b33c54646acbbb604413d13d30b7b55a299ce9913de96be23d96437cdf6658aaff78968a41c3be0ad196924b4dfb4e44b5591a58467bd1c6ac4d89c288b7ab0b37e7610db464a26c154ed6cfad8bfc691eb6501355f3400b61ce9774540414be58a90787fc2a5aa9a746f684967c18bffd9d6a9ea3ca4f68c23bda359af240e4650e8c1a13bd2198ea162dc1d747e6e3329b9a9a59186763ad99e32c4f1e83bb53d0f7f73067f839c3e48ad66b27950669698dd01090a26fd2dc2ce416224dc7349b0f71ca05778cb44d02b44c310f9985d3a03361abf03e485505455940fa9455e1b47bea217cf62654a127ab9e29febc14696b805aeab0af58aa29bb1de05b144ea96108763e712c5ab1607c7a7803393bbae1517dd67ab2039b0b4e34777c4ee8d58b6e96c52f60892f477c21e287c3a899524c7aa5b78ffe0bd892f364d285c869928f82ec28718cbf264f46ec0b8c962800bb976f864921b3e1c0692e2bb938a7057df4964290ae1198572ba9d43b782c88b83d6e3fa1fa79fcf2a06752ba524bbe5577e2324efb70a26175710506e9c72c4cde18626a1b1fbe33ea809a28a30e79baf17001b3cb93b9ac63db0d0b1f8fa6acc18f8acd66b2b4218738fed7e9eafa43c52a5c299f15a8ebc61882e9397966f12beb1f17aff21eb23e75683cdf204a648e780ef276cc2614e38e7913452b944109844fdd6187e83421fe3d8f8427356efafd8f02a0f82f6839b6903ea8a6342c6a27a3f49596d3547e4fc3e67b015f9acbff5404fa6a504cb45a702210bd0114b436d4fe89af3204750547d2949c1f1e9d9cdb321bdd0f6b1d4df37c3842855380d638a1b0aebcf405e8274bb40c9b01c0f09d6b4ae1857d69757523c0b8e10b1dfa1ac978c35c7e3558183a034b7bd2c48a142300fabd5a84ff222e97866e38f49619bfa4a48d64fa232d5bb8c12f1ff73a3b0eca4f9e39484f396c764b9e0a84b411f7d9314fd2a013b22dad01f09cd0a1382524fa2fe4c0023e341b31668c4cb842a0a8794e2308b1aa3aa3f48cbafa08b21f989f515da64751222e38940464188f7784fae83938d9b639045b17de563119cb65a568e22ac4d30246b3340b4dab44c0957bab5b0e485b073f9a77224881cb6df160adaf6c0310fc64373778858a891e82d0350ec7333a0433286a1522c6a770942fa7678f308c04cbd2dd6c6fed921d674a92bec4d00f111ba6995cebd0b33fb90443c35018c756d7c9adf5d7ee169382547be84f211c4c991f02072859fefaa0d5dab88c2ef0e395ccbaafcec794f658191e0b741565f62414891baac1694fdfe88c3aa4295fe94f98e39fce973c12c79e3437e4399d155494c91e3552db8423aad2bd809e20da4b592e996eb6e5fc93418e4306aa9ca9f7af26e05a8033a8db440c8cb1d45a262e4384e8a4e19d26c47daf376a949f02f154e6895d0a5e54e633253f0a72a0892ebb4d6b112641a85a8133e50e54618381f059cb697c4449a486527bcab39c91b92f9d0fd41d14b2b506dc80acc6eed00741459a96f39fc3e1530642e22e741180449998824092f150efc06a117ec3fa48ee68e9a6e8a04da730622acd3e10ae83dfbacdbcf2ed82298e2420f789a173bb3e864362ce29e68a8ebe682ac1819e24fabb4442b09570b9bd4e622330e4b1d120b8494d4f679af1e9274e508d24cc832ba451f5d46bca5260b2b0425e77381c8e2eda117eb43dc925b8e45a973280d79bf03e64395e960ec013a312ab059686141c0856e8cfa6503c036a7845fa68a2b5c67dc480a72183ca97434dbf908694ab84bf8353691aab9ac1589746afdce1c972de03b13c1052fb1baf35e3fd8c0cc137a4c0c21f77f92ac60c93c1ba60cc334b70b32a4cce9f07c255ffb2531c318d69fd722ede9a262aad8307166a4285e97b3d4d0fc347f3d080f09ebdaf7f234d3772c2da8f526b58bae240bd4f55e140e1fc6b73305bc7c0e57336b784da66ced8361814d768085d2668012bc886029980ac2f3989d7b63add697c8ca255e41dc3f3bb5090cbc4fb85239560d19ef01c8b81d1f8bd5c6791c8e0a21512c5ae2d19c768a1d7a3124016fd62e6d27f7f0ed5c3388ef5e41e0e1c4a82860f09f7dc1cf17b83298a09aa6dd1b329a0aedc8a6def5edadb808ce8ed27c0b4f0d84994408daa4b37d00d01ec531fc404a9cc44f674b49bcbc02361e53a1af0eb805efa02c006991515eecb0c2f9f9420a41f5740856670396e3f1db539cfa6d56f9ffe6dcdd588d7f6f724a2b706def2813a154c00880bab704e8e09dae68e7a08c8f5408f4b70e541748805e9aa83f277a050057fff12964fdf9a2da62f0e179b062469ce179caf0945bb101f92b5d175851d7a505fb9d34e3f91f709b51788dd9c426bcc58f3562a20bfa67783a87ff6fdaa4b19d1408f7860e6598fbe6dcb7e05dfa10c4fa74393926ac0ecbd0b16bcf40ae5358203eeb5870581bc9e37a051d8423d95459488966a9f27c09005ea1788608e0b5e854e004fd96a418b84f9961c0860e01c00339527614d099f493112211fdc421135d7780f6fb10cc3e5b3b309d52b4df365adbae018e011f0ab714313d4e52bc19f913977e3192da8ddf058722ec8e4b86f71221ec0920d38eec4318d918182184cce9366b2bfc287e5fb26e75a55541c4e1e05d178545d7a6ad67af288dcae4a621df1861b9e56c18948dfe7531ac117c7d29064385f2151cba9a3f90f5ff66dc4a4e64a8d877c124adca04f73f56dbed33b610a122a379cd07d856a955c1d3e0aa6faa913662a0ce22446eb5801283fc6dd74c18381a217c8799556a7b2ecee63ee4e37b9a10e0625c34b855879c5c8e24f07854b41878ca8c50ddec38361880d908d3cac62e2aa7e131c8612746f12e92d7eefcc2d3edd172eec9d35b7f411ae5e2a7765d3ac4f0b44e16570d4a916b9d66459b09a89b7aaa2027b95f6e1a11b3d7bd7d4e38c708f87d476dfdb934a8f8f5a99c224b238ced17cdd95ff50d21f9800e832a1f76d9f9fff7ecec940cbaec2494a33c32ea52fed172974158019f433776f97775bedbddf70c37c8d8cb6c8fa741aa0c13a52a2a946587435e4e6b3596f326f86d58e5cba94c3d66328c07fd0064506148dbfe8f62086cd9391c08240742c7116b65188884624fd806d648af82a4d180c3f545e53cb2300bd529a2dc0e78a5f5692c65607e2fbe5332146430c65a42079eb862726af92c85c16a59e61d4ba86a7c7d1791708c0b1b9d5f76a63d1893f16afdd959e6c4ba70307d078dcdecdc6746cf298e452c49a16c1beecce7879a5568256c2f86caa900c7d549ee98ad3d55a79891881915dc49d86760799b680a057082189d2583e9f5766cbb4fa7f85490d6e4d3609448617e6e2be3a9a7fae74b24f913f94835bb368b231fe39caf22d0c51527c123f78df37a96e2e1bf363221778bce916a3115cb94eb81b8003ff23efe347c1820b417ec494a16ca327d52a7ad2415bb650e7e11312cb3f0a273a78a5ccc978a7d7a0030a7d29eb2efd932bdeaa56c22312da8b23357be23ddd3251ab8098cc1f3829bbc15f71f81b03167e3585d274f4b870295e72b3a67befa8471c06d259636057a7fd21fd26b413f4bd076ffe3c0dffef1deb5555fe0b6b9dc01866e66b2ac4a119a02684474bbc65ccb1ddc5b82bba30dc8be9b854a7ac793d5e0e3651962f44da81ddae1bb4573a49cc0385aa56753ad61ba5a61eea9f2d2bd620273be68da02c6b8a8ce027ae4cd245e3df7bc84f7d4c1dad1112992fda2107ea68c81d4ae1a581852b22b8ca08dc6623c605f23032a4842af7c4996450ab2d698dda2d317461dcdc95c902758b63bf8bbadd2f7e9741b91f90a3ac6762eb3fffbcf59d1e3bccb528cd4477d6dd8c7222fb98f0b3ee2475271a13152b52e30c9c1a1438b464c5455ea1df8797575dc081c55b9653c244ce77d485af19d4ea5e341c75488bed5dae052bb19ee49be0d82ee6a74fb2d3211577eed127150a4c2257687a2de6347da9301919249232a6a0d0a0d20e5e73f08873faddd807c100ad45bcaa5016215f98fdc2137f54755282792de45b37f77d421a138c17a74600638539772fcbda017499673a06af6ccc0462978639c4d08d59f2654af1b7721887dd4b50dcc9384d3bc738b34b0ef4eaffa38cfed10c5fe8a647068c59fc3fcf65afa076fcf66f7640e7490b59375823e9aa45a041f6dc1ea1407eec8afb6fdc5428916720f360d7cfab1707260db006c0b9edda7a89c1dc02e0a26fc771b041e8308f61ec27e28272cc9de72303837d0e0655830b637f45df93dea25d2145961fd8012482d32d4e27d45ed5cdc9750c7f0f35705c63e4c5405910c3d1ac07e408c9e688024252226bd3e69debb05aed6ebcf681853835c859b745880c04cb6ec3adb29e7b1c93aa11904e88023c46992816cf9b73e8e4a97e72aff45573adab0ca90a937e7b67766890facd520b50d5c17a5b7ad4b61a8c5ea7d88ffe3294f10f24355c9ca73b2cc0c8e2e31b03e1480739b7d9f38750cd263a94415fa78d07539faf862522bb2b9c6ba8386b3b16e8fe1dcbdf578f6c15d116c39b18703650a3ef3194617dbc08205178e3927431b9b075deb907ae8b6dee5dd60f7cf3f1daaed72246f69c002eb6674b585394c8443a5ea25074d8b45dcf9b31ff6264ffeb8b017b58973e50ca93c8e2d32e0a405a03734d439e3fdc6b6eec8a30427fe13b8bc8a9bebb220af97a21ec8a3a3200419058a759596424ec473b1056f275339a837342f6754e2673f316f3ecfe74bcbccfb2dc2378e4bd98dae033683419ee53163d1c4913aaeccd2619f39966725c249bf3c3c771b1f4deaf6c31a2abe31feb203c2791731f6e2622cda8efa573ade394ab147e207b3666d123de74267d0227dd6f247886c6592d640432d683d7d30435ef8690ae7cce5431659a50d3e223de61f67a7d584cf41600f75aac1e1e23a81342ed061a6e4b25e260d9dae38693ac72694424c2a9a57b6b39516de0fbe06179562cbd362e78c3a39dea3856b58c728f05a3b2f6b8f4969810375210783e3da1598d7281156f7dd8c889bfe974bf0f6fa6a63ac84d69f8605dc6659ce0ace41a056c91f192c984b845719442534d1dc9401e1df10a3924c62affd09d890865ba48f28cb1b305e7c62a2c35e74dfe2d51b38d9a0e61e5fc795351749c1471dc853d744d766e01217e40ccb6e558f005a357507d0e2adc37aa4efc1c19bca040711e1b61c93a56563cb6e38967a23460b7044e2f20fe48a8fc23c2595ed1cdc59a3531a0349114c81501e1988b9c62aae564f8282bca07c45d9f2cbcea0a6f6cd36c6b13742d44f0254bba8e48f6338629b1adb87a1b6a54b7da1516850d183086ef24854d6cb337742eb1304cd20a0333eb02649c85de28acd904a65754214095721e19e4dd222a865ad62aba48aa31e62067e051fb8f4bb42b320b1725a94a699e08295574d11972324779605a1d03d98258a959dd32f318eed3b74e92a709539f1af4088052b80e922c021f09fb32bc42cc8e3747e2e21b1ac2977101f80e5219cf5ffff17a1bcbd38e41a8076924654dad44acb3d91122cb39ef28dd4407b2befe4332341be4354473cac902b3d69416fa3f53c34b12016690a91df54329d9a873129a691a275933f1afc1f3fe7a3ff9f4278c18c81ba6cd690b7b55cea40f3837ae03ef936d2b5792b1d47e52507deb780b5a0d303f009f05e3e8565b4234875c014fe4032d78d7cb0205e18b55645367ccf0d9a999aca766f8d768714ea1b36f936ba4adb54dd3256d0dff2ef0561c549180c63cf0d506b13b9d89f33a9cf042c04b5a184c9268b99583f785448a7d8fc9a490a3dc38147bc16d8d18797f1e40b48a41904b75d5dfc233e068c8d389aef42a6cf5f311d3829a2e4154f58f611dbd7faee6920be7efcb54063c33f7ecff15c259eb9c0db3d23b069a5292d1f60655c482a8d199354c81a18e94a9f2e5ff723caabbb120f249c36336f3fa0a5787c1c0b170867283ca6892228306f6ac7af173eb32a7dfceafdb252114f809ceb8bdfea492803d7fe62a5a8cc3d7c1069fb971ab4142d5bad0af3f94f96238e26d158400afb4caaa1fffd338cb3a0f4864e92b9851827fa4a6ad0b49776dece3049f6623ed37ced2b5d90d62e49f5ba2bcd744e3ccfd0088df3edeaf557433dbd0d799163b4381324cf34c6bdc46cfbcc75c369780848f0d1d03a1459c15e45b41a38fd3eca3afeed13416f45bf839ed0ce6600a21e858ac9d1c4b841229645bf860525a24fa6fb1b1c99e7e64c3b8012a1ce68f2e380c866886b857a2fc7720c61d81ea7cc09d198c047a2d0e51e0aa1ef83a4215194e6d05c83201807a9351629903f4998c15a29d1c9d454fb75342db3ebdd62a6a8e0ca73858672ec1f2829a088247cfa4be11b203be54ed61ee0c551098897ea54e19bdc19976972f96279eb9abb58d524572d6e836a04c721765b6c7c1b0e54dbc4d5658889bdf645db76ddf36a0940a09b4478bb0bb9bb70704cc392f5415291feffbe9ec86f8740c57eaf7f8b24fc3a673d83611aab129df57120aa5a67f250ff0571da7f1e1a90009ebd758b768a7c682c0c9d36d50573b2333f84a30a2079c052598584c07238f0322dc3134b5f36bd4fa141b48114fc7edaa4e267055070829c25ee87b735a16766ee66fe522750dae0eee91a08174b427a769350b9b59d2ae57928180698e03fd9b2ae96692e90490832f12a1ad27707c071d4531a02b824224fdb1306468c4a94103d33d23ea3d0d2ec5c6c07a7cd508159cab06978d386605b9fb63d7a28e32553bdf891a17f841a880d1bc850f5250622edc525d50bb101cf4221e8dae4578e1227fc6be09ed166c806e4b5f53b57f478841f175606d4c3f70c4ec67871c06dea0cd40c81e1908a90fdbcae19222d026d0461c80ac9215767b4943d7503d188554f1f8c3af6186b100d6e11cf868589e45a2e52513f730df59c9afd154dfcce1d4a72144a2915a853664b75e210eeedea77931144dc7254dd1619585f8f76de7b8e805021426f7162646b38fb86fa1ff45504827c978eefcd4c068f9d38c92722030674d0ca17f6e53ef90def4a5a82848d1200d5d8c42e5389cab9830dcb3936cf564add54ce47bc0373f863e1dc85b556a998733aa1aeb8d0ab92e8d8cea406dbb505128752b9dc5a4062baf0fe787d24f2797f0224f052b1041ce4caf44cd446cecd9c68e6111b43afd081c6f5fb71d34e8d36f2a8f91dfd127c9df514d681ed7a9e6989110f115d471d05019e27919b7e172f2e803abef38c1acd73c406331d602e1231146cb723eef322ce89171997bb3428ba7a37ae72e8807d9782647487a7ceb8f4edfcba4156e584b9ee40c04e23fee8190f6389d4233d3ad120a736ec3b53d508225911f3cd431f0699af00a79c3bf55119e4fa139f02133e9a8e0640b4258724f96bc8d23308a3d0626677d13b33da258906dc65c4192de0c13f3f48d0408eddbae4816b1dd60281f04f3d983706d6dc89475a145ed791db41bfb5e538778209e3e0716e97984dd0d551c6c19a5dbf4f861c75ca32335efc508f52e659e2ac6bc9fed345c493d3537e090b866fe1d2cbceb7e581c5fe478843ca19e45e8c1f359b6aadd715a8f5eae2e03a844229b107ce1a3ff621c82568e857c215e24c1685faa4cc8c4d1381b6846cbdbfe325c69f118d0377be13a5caffdeeb53ffc5ce2a5bded5c511e49f1b9b4566971ee4383642f844433ea0df00f53425cce70eef3a0fa61720ced3180d0fa41332d7032266e8e14dc403e007a394495c376b303cf7d7d8696d210db2d1f1cf8841ea15d4fb9941bd26d48a0b5904825a1f2fe37fbf4e21dfb053c3e0b21faf4af31a4e5072851405c50f7bd2f063867dc4eb92c79c87c1dfc30080ee2b2e92ba4ee1ada072e3dfb24875b4b983881ff0309db854cdd804529cc7836ab5f9ce39696c9bfcf714d5554d54b406500a997a55f1af7944e12061f2df401bd39d9e6d53c178e2a3f075214d2b98d695052e2142583ac62dca944ea0a74a08d701e374aaa7d8e48420b17e44c6221aafe60085cd4c17cb32e65099cda205ac53c110f847dcd2f327d0b158322cc5af8e0961149c397b9e73b4d1709cafd4401895a4f3779094d3ec6df84cff5042313ad759dccfee5ba6520aac6eacdc3fa2b9880d937e9e98b68cdfd9ec685dfe0d6277b3ba0a5d5e8d2b6122113bef2af0d92f18ab3d0fe882f1c015cd456ceaaadb459b0c16667f240afc16eaebdd8afdcfa72ef35e9f28bb0960143c86d81c320f54d0981f9013898d3ef85c3216cdd1ec5dcd89d611557f3ef0189c2a8adecc1ba492067161bf3abf9a64dd77a2ce468a6fedbf56fba4be4f746fda7efb8a96eb731e9d8be65415cf353936a3d7e244bb4ce7e0086989596447b54c879afadc88c5118ce3ad20c6334f58a184f620e9ede9d8b734f4902ca01454b36fc79df9092da18087fc0c1f40ec469d2e5bd31e4c360ae26aa2ee2bda9311a067dac299efe3777e93ec1ba1c8c45c5acdf1ae36b3b0cb98808f39548c7ab52ff2cdd65702bdb0f8c4529869ed642940ad0912c984065e1d0d69d7430f3a6683a7f78b057e01967ee0486d348945140d81f4b77c61c2c393d4a202b89603aaef32e08321c1cc0d6d75d8a17cc738eb80cce382278a169374f0e716337df38c1f69dbda2530e75a520a3ec60826d40364fc8c84ffeb7858a18874dd0bb6978681fbd14ec98ce247d1eeb536a75c09cc2d800b0761b6dbb5b4db6b973d6bbcfaa06fbb6b2e03c51f2a54e134665fc3e8c1c6a539476313487a96060184b428cdbb6f5b8bd83fc34043b799ad1a0d1dc9baf175b30768254b52a6b461fe5f640b685eae121f887c114a13e6afd78b7de3ce9436df70f654756b4fa32d50835e0e425de3ca18cb88144aaff308e09f57ab076880783baef055adb8c1a167782e28532735df38c92de259a6f7ae863926a56904e7ff6df2544ddaf1a853a338a8f41dc8ae500cbdb541ed950f2aaf672931b50531a8639672782832ab52aff6e1b892e1a44f8f653a301562f32cbc7ce65c6eacc9fb14e9e35f811e9f06d91eb0900cfe849579773c6e880adc5d91f963c06e0b2f2e8adb3558a6b289f235b1135bcb69cf3461d5f4cd0d7a58a39efd0b318427200e231da14acea0126b48390928292566c40432de6437aac3985cabcc9b4c0100bfca7dc4e560bb981cefc9a329a2c9e8af143ac58e7da723b1ae1671f6243f159c9e51dae8d3c4b9931b7426143e30e60385951bba573f15b0bf593050c671d206a10871d8272d38eba0cb1e3c40c10a1b54b060010d491555208a6003fa60a9ce587cf233da463709693fb96d5a5b5560e208acc966173d45c445c801f1860152bfe12d5cc44143d7d63ce5e79f0020031502dbccf473c2d62101780e974359c0d560b0d52640b1fbf86c5b6f608d274ce2ac97eeb456aeac23282f82e1358760d7750ee6f62c15db16ecaa0e5f52db3fd0248e2a7add542099c6c340f928903fd673bcdfdd07a567df9063446ea4b28f909dd6206d13927e515ef03a11f01d69f5c7c90b76f327f0b2879130723fb01523ca15b2265286cac7792d74d5ca0901a2f09ed1838d5ef732a3af6f4c2f3b7406c581121ebc5c50deb39eed19978bafc066418dca855e879d720c567c9eb7aa3aac26037a72e9b6a36cff13465891f7d9af8281fd9c45bd080bcdaa92e68a5e1db84063c36d1d503992a280e95d5795a07c9dd84401f19310362d0368a809629cf10864b887296813501a17f895cae235cc091e936e8fd594e4499ee3422323fd00fc9ef6e49d687d614efd909485c0a07c98c87128c463113a7fc8a06170482bbe25f27ab2429718f16e05d6729371f1626c8c9d34dca3ef73d889d574a19cddb6eaf7b9cbb2883d89194011149bd54ec65556c56f5bc6d2fa9c36372e6e68b352a822e150baf497d3273d6921ccc7af6b2080e4ca106ca839d3e2c76d05705880ff920f08830b435fa36613d4649a7721f57a0239dff5b35df9f5973f84ada3d8a3758729a44486acdc27f55d53e76384946439bd7574731e0894ea0391b0a6fb430bc130cb594662ca831be459e4c41ab8d1e2a32640fa881c4070e4a9fed4b6b105ff6942d4219e9555d164f660572f611dae10668b53fed97536b319d67566e43f81d73fd1751d0a4479ead63fbf489772eae8017e4ab365744efd038ffb0571a11063d6bf85a41ba11401ea3da21baa2254fce4a075c13ecf45295b1e1e1853c2ad0ca90c57495fed144a2b28413acb91a0774be6764410ad17efd01fdad4ddd98850271110390046a5f77556f6a64afd4ee6df1577ae51e1623345dba957ecb5ba63454a07fb6f38069def8e89fa9c478830fd08547fd544058c9142820524004660f04b2ee646e3a2aa8adfed8fd0f19587b80b8ccca8383dffe072935d3874e7e639d12fc594075bfcdd87898025646a9b9cb5b8481bffc08d894593b02b79639c0a8924ff7c744e4b872c6bc289cb18c9b3116aa6e9bad9dffa65f255aeedde90afc226e0a64ffb261cc8135308b60969373877aa9c9481f4384967c275beea2fa9ea786b23cd72386384aae326ab1ac11450c0b3460d7d0c85148abdc591b32ee84fba78486c57abda9e000e283047562b9adc50245ccecf8cf5191cbe97931011bcd025430f49d7fbfd6204fa42660d0d2d1adee701e81ff5a6ef46b7cc1e96fae9309bb0c10fe6e4bf206e3944fd85c90a71529d43cb6acea5643815c2bfa8347d6148e435570bfc83d754b5fcd32cbdbf33a2a0ad434fde62b09b71716d1d1564f6f6038bfde758d9344a5a01f149d605d2659f8ca37c7dfd036166fd344fbd460064caf33cb69947e7dfb7611b1b199b3217ffd1322cad73a7e0550e44934f2dc890826afd6611f8ada97158e06a7e66cc79bba8cfbc7cee65164d6d3fdf7824690b401ef5ed8a1fc865e002851820dab950e85bf26955ae671673af4c8d2942721503d566988fe8ee229b5377df4e463485b5a0220ccfc5d6186ec4c5ec778eb9d1b0ad8d0b89d5a84ab4e70f270b67b792cf0b0d4f5afc2e474fe283bfc8f84b1bc3a2daefec77b7a063dbc10bdf1949b09d5fe21156cc8a5c69b10b217437a86d31320ead7c4278559cf615f74d8e7cb71474f1aff696587b7407dd1af2ab0b8b263a7c694fae8e6fa6e3606c036abd621b2c90f6bf69c1582753c845055c171b8749bde56f6515219d76d17d73dd6a31a7354dd106056aae65dec90fb944500b58c8d115bb48052f3ef9f59a2304a3dcbd30f3ad41917ebac44d4555261ecb9bf2e6c0eda6bf2b390b120a8bb54568c2aedab1357b8af14ed37f1ef723ce331aea43a62f4907ccbb372751bd92854c4197129b381e7d9005e6eed85f343450fbd38ac01f30bf7e1b2f6672ea97be9311a7ca2481393a64a945096df928e8f899fffdf36de8990433145f3ac3bb5b909b7ae4e432fc02966cc2b0186d37d407d8b37cd6c838853fce51e12805df55766d81716e60ee8f679baab061b43961a40390805e67cd68e8f7078f90ef4712f5f1aec0249151fad89933676a729d5d710981dc0998fbeaf07e2d21b4b84800d484239af10965ee79d9557714b11585fb528caee4e4d21446a986a67dad8df725445e155ef8a652c71e5ae6f857b6692777ca44678b007bfdebcab8d264365b41174bd4b0071016e02d7e44d88abda4d741724bc30beaad26f470ae48684268e02abcb5efe428400080e160445dda883fdca5291d4d94bb8cb9c13f112dba99bc4c694612e09f81268fbb9e6afb18ddd16dd767f72a9a4b7feb8b9449254aad4c1aa8468b42f793e702433b86b1aeaaa7e2db647a69e45fa0dfb81882f6cd1887d53642e70686190b10581b55353f165b8c25a4545467f3cb64e0966ba292b14c4c19fe18e31a240441eeada3da227c30a7220bec0241f8b707d390c3990e95be3c58ecb05261db3f5ea3e5d30d408be36a8d964afd62b9d94eabd74e04eba1bf231ac1ddcbe6c36972c113962b537542e4b51628d5f8623750df22fc8b57348e741757011b3f27bada84c1bd1117be6ead55e9d210d8a0d3d40cd80304e434670710476e8cfe5db12212508d58821ea4335ad38f71e2e391c8b9374615c64c3820fa8fa33b0a8e0c84a68acfb842cb892f7f284b8081f023d93cff7111f5c5fc507543475739317a91e01434b590383179a1b951148ad004797dc4972f39e679498f626317a4853d0342d9c72faa2f54e6f88e2e399398bf026838835cf3db49118a2f4ca133fdf8a4e58d8ad49ad651b416239869f23ca326ac4c30617bd16177fc7f8ba816124247592074ac095b36fe252770f2145e3238d4288e4388b2e1ab3540788f27716881e4e80f1e97c659d1ba4a988cab6ba30fde028510b60a81899757c07bf70c467b02c22af1e271b6e36d2fe83447290ba36c0859e2fb846d8a828e5ece9209bd3f0d39e36c1bb153345999b3750d539a3c833978c90573b0f103daab471dcae8c5ee659a9b637a12813530fd091851f2b39e4bac7b361d93c9ec857266c2e3cdcd2602040f06193b6b56a4f06e955c1790fd44cacade5af946f561ca0fc81df40764b47348ad14f005ac53f48c64b1c10cf68fc2bc421290ca5c0ca51a55dfc69a59f5a16a2e745f6c85ab9a48f84ca2d096dfdb862f69cdc7e6c6f29b8f5d2451d889bcd846bb98113bc6486fcb7b396c1d347b0865dc397948b4ed16b8aef9bde2260bfa3d0190a32d4cfe998054da9f717e85712861c851d41b0916b5acd9891e411e2d2233ba22a8f13b20c41a188515dd5d7b4b27de1369569628268e363f139035ab2f78f777556aa89d30876810521769b76a4cd4e943a1877ea84da434f23b45b73033080614cd4a17a07a539a8b5c100649c70c260ac86351b2db24d900baceaf75ceae506a8a0baae081f865690098e82bf9b6a6947aa8bb0432616c9eea6ca0fbb4c4ace0e29f8a32d311914949dbf4ad844b68c662eba41514f0ac6763491b3423f099552e037c143ba25117434057d00e686f588f58bdb1f0cfc9d59a19270dc9783827842744aaf4400a8eb8a9a275642f281400ecb2a060efb11a57694b870b73090e254af73e627db5064e6cdaac8cf9198e3ba962aef89dc30268a5d4198343c84df57bfdd006310e8c642ee39ced6a370ed5b45165c4ace0b01c26e7fb106d282f3729075a101074d7aa014b625027db1765a1cd7716d1097a88c320f5c4940b787a7263048ef443c43d422ead99ab4178a85159e628da6e80459dd5d6550cb0a6a55752fab18146444be08e2d11a8061936477bee1b5432bc84ab18eabd1e78d8240818255e4e6f7eb10589644e25a8eb10182108eb6af16db440e72f1b1e34c6d74290baa557798c1b92dfaf8580f12d915248f0b8cc589e31804d1403858b9108bec9cd0c50f1407580b12f91ba10d9edf495f586443148765a940cbf3ff0d81f6f54e53292dc740023d40fbd779a145179db6f754ce9ee6246f9d292b97eca8c19a71426565522afbc709452af98bc57fc2e0b930079d1c0096781f0919265bf8b1f7f76ad957d3abc6a2564f43a74cf7d4801f4b8848458ab659451116d3a3a08c1e0371d25b8bf45a42182e7703a580df91075d30764d9839225e871d0fa3c5811f68af9710f4b0acedc9d75cb1da7660d3e2ef14ac9ab246bbe8f0c5391e7a16630938c82898caab2c235ecfde3b86e8df047456f2b5db3832e473ec37da351c69c987c19d1b8810bdd037d5980dd705327c44d4c3505fa261fe60aba8e03c1b8b2e9d5cf13dd8a77d1b273d1c58d09f0d991666ca8fbfc09efac037bb72805f1d8b90582e4ae54d146a26c826f7b1d97d96740fc0b28db8fc96317262b570fbf8ef0a49cc7e98b45be9aa0505391da73d3ef609659d351a9ef7575d13bab893051988accb4d7abee8d864576c576c3cc1b7397979464b07f6d18098cb22e387777c762521cb1d1328ab53810bc5998727ca9a65aa1aad7e94e5624b885032e6846d9786f4720ee5e1ab444d70c230f0091b55661b1d83224b2604acb712134e4222e599fe487381ed2041959c929b5a10d606b8339c3a145d2c336908eb16ac01c2cf5407ad0412e0c529d3e7ef3b40eaf031a4389fb33de4dfe0b75dc61bc3de89916c9b5bac6b3b2a14c4cabd243b428cfaecc2b389f9b210647e75ac84f86cd88c975a7b503cced62df6a0965f0334d6b0766f7d0996d46e1d6513783f33135d4ce423b7a59909bc3b885e0cc3ddde731418220856401ec7afadf2790295f97fd85a43be3861800397c5bab0876efd42eaffb30db404b90547b7a6376a1d095fa8f8a4be6aa960e22d1de7432634e4e897c9e0431981099df2cd24b427a590727e4169a0555a4b359edf549eb29550a4ec9c59476e5e5a065a5efdc8482aa5a9a0300255581ebcc48e01ef515675b8a7cedf446cb11cdb6eaf5d02e4d27df6c5be27c63a74d6069d7d9fee467f7571e62e93ccc6757d2c4c5f67716b309072868a7a458a323330ecf55d2802aed31b31ed47bb01b06738543d4ae927917747896f01f12a68de6ad72e2fb983a2651d433e8e62c93c8a88cda8ddc12f2f0934909a2656bde57e833a758a09eeb82454b2fb2b8008d3c79c06e63ba624ac4fab06e96ad46c27a61e84f92b5db0ae83ef0056b4a7b69e89a87f8e4b627e082a92aa7d471996b0385e2a54b0a9591ed4066b90459d0bd112baa07aca0f31ad0c4373f742a1c2dbe8053792a45b7a5a696631255efb25ce9c1e258d3c62af0a87d7167ab040294466618668236de1161f3c142799fcbde1f4c3908fecd21c3877d4741aea3dcaa83bf1cb1320935d48b427f932662219b6432d3992d903aba33241344cae7ccadf375e34ca9325e95f610ea17a4d29e46712dcd469f1f32cc4dd105652c0ecfc7b11177550a90c6c8518d486ec341b5e84936d24e0e4a7fb7e5b2e79dc91a4ec2d339393811647140c8e2e457461c298b99e170ad2a48e6a01a583c6ba80eb1d316a4037b026e598d5e50312d9432fd2e0389176ad399900009eb01246773a0049aa13d08e77f51263f313ef00b63079f4e998a8f31f66e4cc00aaca00934f15d578b72984254b707d48e5529671f6448cbd78f99a04edfef914ce0e3973907190a98d1d2cf74b6651f8a2142880e1ad13d0f7977fd465aeb26c8002756905a1fc9a52856a8d3e93c604f019f563c5d9ca1d8a7271a6e234783309cb2f5387a3e7a906b115f994b8a720a681a589354b969dcf5addec70e22740070a53c9844b64e31043babf7b58492744b37b7a084238e7819d081188aa4d95d52d4d04d47ed5fd81fef0502c0492d1514a2fe1e23a6557ca44e4a505cde5fe64b32d5072178fe8d8c36674becf90039215f958d1979477876322cae8281f777a9ce0c24494f0a9cd9210feed6bceb245688323fc43cb8e17084425ba470ed86d654d9beebc490ab5d59855dc1c7466175b27c1763bb49a0e9e3f8132c86f6ac58e214da2581185bcb0527e2ea592fecba56373023e585c33518e138d2e00e4bf2337562988e5a0d4c43187de7b06a0b55c1fc45c4f3828670317f8502070aec499a73e8b3569796470402c57e1eac8d5678b119c42aee3023add69a511d4f1c2296b44c70da027bfe1f11bf48efec3be3a9f454bde1aa9db52de4c608c2775b1f549f237a51aefaeeadff7cd6ac2e43360a7f500788310980bcf04974063a122cdb09d70fef772e57328b882cb71573a0223a6cd0d64e652d97465dbe1a185fbf42cc7d5a9391727c6a9f330e019d9563a83ded0f67b989e95b2d269734c8abebf383d7e4cee44a6c23bf234854afec3c6993595e0c7eda62eda537428426a165a3adeb378770d139c7abb50d8dcaecbb346f22e48113c35900d49396d0f467dda8beed6b1fc0b71a1442aab111e8b051e4dcc27d0340e0337636266da05ae6269dda97acad6162cce6b691b8c15f27657341c828a4df49aac0c5dbd170601b6987cb424496d329c64771938f309f2230291bb19f618684ba9d36e382f67458c7c1c9ad3542be1c0af5327688ebef0be37de469d454cb043c977e48be1ea78094e6f044de3aebbe21cae43e764c6daec42c3146adc8f0171e823c99366abe14b4ab1c543025856b483e43a230ba3e59ab7a74c9d651a8a916c72e6cc1d5289759bd618275acba0e815ff8ebe375a53abe69da34820de21270a2f5309f45e118c17abd33c33c49250834a1e432d62e54b4f8d366167ff8790eec86dfd25df9b8045c09ae429290cef010e31ecaa25f18a690328a7b0888a339d3e24086440e7595b93f11e8a2cc98cdf039c76c4dc9018e9199c87eccf94b5f60dda4fdd6136d8796adf8cff26e5300da93fb6ed3445165bd7c42a422718020a2fe782c08c496e86ade4596ed74e271ec946bea80a379f82de8b606a27722b7af3366ee5276d5336d2e6d8dcea639142547676cb4c74b1d41c96b6b7904fd876845203109c5899c26555a8909d29d7cebe32b0f49db60d98813803776e89944e5545fe6baf425544a66d50a24c8152c8e6641c5f04cc6313f75439e8faca1f321ebc8d1ba4992829a104e95327e47d168d501a21cdb7987862f49c84f4660b4d30de36cb75623b7a3b9fcbe61ca403ec1681f1fcb52ff527cd5c93fdc3ea328a35b170ff09690b9aeffe49a29c5ce11edbd287890f0c274dcf3efd4c38798ecb8efb1731a07a4e3224fdd597108eec59ecb2f71e6a97326ef52687d89f63f38a421db1dd0f4a3f8b52cf27759c78e56ffabb5343034e4d25617960bbaf93359f64d84947ff9511ee8e7fcc51b97d9a02289becf7c51adaf0ceade5ebfd211527da8f989ab683d24f4fe0850a0a653185260840a85e1f696ade945023657653524a196b0db8e696f77a2859ecc45d7aaf7bb41eca10ea61813da8b70447492c26f0456636572d96e9e5e993e3c87c1ddb92dc540695940800eec9ad87da402681b31fa99c5529f52268a48f7d6148d20f5316b7438bba6add866e05573c74eae24692d267a79b007f0e892352fca82b1dd214c4add11504686ba1da2b41f958a616ced43dcff65e8bcada86eb74fd3b06019f443c30ad27b67507fe059db8b9caae52840927580585d0292efd8d1b504ba7a41ed6dbb2dc2d2f818b519f6996657af0c73c2419fa3d84eded75cc918923405921dadcad4a6bccbc607cc73d2f899dadafc10a6e9266b911c093b9ae02aa0a7101283486990690c94e68f5e86d7bcca63fb4c2326fccb860bdc62c38ab561c0340d2b2ae1fc9d955cfb06086b0c7a3fc611635c8d4d8b17a1c4a105f2fd604ccd9558d7149eccea3387ce917c4cc2e3eea0653723e128875929b284975cfc78fff1936eb3009a570aeed03c337b36c6995abb7e5cbd5070f7cf065b2095afe4bbf0a8723d257b751c768add73826fab2c1ce559fc0138a4969db6cd6ffc26072094260cbdf5d00a65afda5fb4d8c664080bbfee92e5eb744ae802c8cfeaf9a839b20de91e13021b9e4f4d74e830d9c2be8c36968478356973930de5c10e7a662d1349d1b40b34812049d06ddb49ba1a685707f0221007a1a3b72d350ccebe1c9217e36bae0949042f9c77040a7efbb2592056aa9a0ef1ebd9dbbcb5bd69319f42be06956a18d430f945a0d3fc25aa06bfbf48843a6a19776f22fd7812843ab41b00f8410ffa50b35b97a4e16e60dfd813ad9557f0159fc945fc2c86466351486b7b77db724b29659232510b2c0bec0a9df7f9fd4d078e873c625885e8094658fdcd79c0a0e74b8c31ee3e1eef7319cb677552560b006578282eb583972484b0a7e39433c040e30c200c5d7c46106754a177348a5294ce28018f9831bad89e0e33cc6032a352f8004611343c6320cdf0595a220616a95611c4d015b76a6c59b9248726482c61a2082d5870822240e1f3537388e1a764bae249d7279c6c500413e88a45195c68197c690d2f5912e0a21f3e1e9682f0d0e4b0a8f7c564e4c0872132aa10c111193df8e1898ca5253e4b440822480f4d646001fa2943c9921f2382f80054860a8096caa08192203f04fd04d9a18c278408f253c69425417c6a5edc596dadb60b2daebcc400bff8bc2c31226f81821eea511194747d77e1010fb5a8b1c50c30d3164a84b1c5133c6c81c5cd220da0283a1d52604e47eba2b9872fa542505742a5f421fe2ad495aeca5bfa7fdc5797026f3a4a81513afe4c164cc1251cc310f934484a5ba9ccad3939c7dd1f0698469348772298904a5ca6232dca97394459cb43570ce5a73a6eabf146be2b95b7cc2186f287b46edeadbc3f227581270c80a611dd0ba4b8d44e7e7e67933e0e9b9f7d7c3e055b1ece1d9a29f096b4ee477599fdf9d267be05b5fc5af078c3d2f20750ade33e7c42d327347542d39796ded794e60968fa15d4d5daa7bf7913a4924a5a3f219bb6b45221c49c5a2df7af353a0f1dcd131c5f468f32bafb8cbe030e419a3669696dbc1ea760f9b1c79bb4bdb1e3e2666b541569e97181e3cbce658c51f544cba91af2503e5e3245f82dfc25dc00cfdf9e9e5207b3521a220531b702bc690af0befaad4c212328ecbaf8d55a6bad9e87b5ce3969cb43242708e1edc92b4f10c2f4e357df652710e1f7d0dfcb93c769fe6f7debf5d28f385e027b78b62edeba704a42c1d2142234e998547ba2f74daa31d19daa82467ec8b7cf43935c1bd391cefa43c6998d50bfb9bf26d7bdcd32caeda50a3d596f51e0ed69ccb106fedefbc76e37eae3b71d913a888d207a90a269166223881ea0d0f487c4aeceec89e98b446f6fc12d8dc00f242af2b20bf5a94fb2832413f13e9591c409f31ec9f7497674a605e71b8959b264c1c2f95ff9c120818c4cbdc5b4cd7b88155dcca1288ffb0b76e0e680ee62f776a8efc023545f0f39b027a637eae1143cbfebf29646fac68a7288fedeff6e076e0ba4391c7417d357fe95ff815d3632750d31cde53d44f7c4f446f5d685dbfb52e61ff0cc9205c875adbf5312f098402529c17db23da051747d100c0144266303d9754b9680eec9d2956a9c76f1b37feff6123ce2faeeefa9d194661ff0c6baeb6e8dea970cad22561226d8c9b3e20ee9fa9b6a09021f5d5f7a939e1a8945db0ee85b6b0fa76badd9c8a6b7d45baea146dbbc65d03d359a3e96351f714dfde3477f8b6a6d552277628d77a08b35744269617e73c7dd86973cb0f2c4a7e30cf57e89119424c61863e440cf6f5931621653b4738190578c9fb7d64a9a1838e0a8bcd1425f1e1061c9b4d6da786bc2a0c1a551b4640be80a1fe8961593262b50f4316b90cbeacbeee557266a95127d6c5f48fca489cf7ec2e45721e4d72862bd42cb8fb1f240cbd9519f5f02e88ee785942e2790771d77f87b640a0b30004d054b304e1d5a91d278922f6778c24eb8656cb1b40406238c8146136a383181113bd60b1d10218504155c27213a850eaad45a6bad37b5a12150984209255e40831e04618929042a6e70a7a022074aae9309ba32f48e48610ce95845cfd8b4a3d395296118419584a029091f5031440c72d8991f4bd2440e317842c887a53296eccc2f329ff494307cd09c8e53c2a07147f8e847972ad07c7fe40e2aa20f99ef0ff1664679d4ca914f2f9f681469c2e6cba7f9ffad16c6ad16c646e0ed4b1469ceeed723daa64af7e74380efdc9fd95ead53da5eadf36a73d6cdb781eadd29e95816f8fe48153c14c41df3e7df1fa20f2f8978337f7ab578038477e70dcd599c537edeb14987f395a28f31e2cc8bb025a9828c3bbc880e4694d197d1cfd0330b3d77bc46ef00714a7411b736b7d5daeab2036ed171ca107620021cac5c80b18e5386f0823586904437e7acbace5ce5ae10dddd1d67fad74c7dce293deac0dddddd6194d2c8e9e812f2691bb4e7db0285f449abdd2e87ea5a38aed2d9792e9b57acc840658557acd181638b1489373c70465ca545ecddb6b854a488fd547a6edfb2420aeb75ab60262b3a3e115b296e15a1da978ad425ba34976ef4e172a38fd41301b8b0380375d4227e90388bb4c8b55fc4e92c527f698916f92257b26e30e79c94524aeb56e7cc31aba3661ed94d474d4cc7ec612b0458fe7515e85f70631d5dcf9772477c39bb395b975a4a2d05adb594ceb89368ffac545ae9bdf7a2bc70c7c055ea5dcd790005c6489174af56abe36ca5df8652e3769cd35ba78be234e7c9ceb9ef3e4cadb5956ea8ce7ba9e171dc4bee7297bb4f1ed2fac34ffd4a6594de1030fde1e7ab62cab4c8188d21ea86a63786281492a757abc5cdd4b748a79a50470c27e79f665a5998a2bc581698be4b15e6c77fa56af7f1fbf834443a3d611b2eb044a19e6e4f4314e5b6a71c0a95e482f2895a6f87d3f73cefe3b1efa1cceea748fab72c9de4952727ea14bf3a5d52a39494560c330975f243f9b12faef8865084be62e5175ba8b0b1bef06182c18c8273bef4a4f3af0ff49cdf7ad2d38b223d997c8490839eef31ce70fda2255b588825df1182544804e165214a4121a24302d1b7640404aac95bda810838a00ecbcf92163ff466719ab0b8d405113fd6305aba52c48f233475e1c3103f8c00d4c5114224e1a88b27421475d144103fb038756105d08f24c436b7d5da5a8508a8545102a32a5a80c9a84206483460a2abf3e512354a21d10bcd7d273d6f21d4f8bf2e765e3f1ed577b12ca820c19511147d61c586465ca2efdf1df4ddd6d03c88a978458c2236d12242c45f4420c4cd0abfbf1db94c6a4b34a3882ac4bd31e9bb55a1a2efdda6d0f76344c0f7abd2bdb8a3d3a7dcec0e0cccc36424310ba11d9b5df363be164dd8fd243b1be8220283c4357ffb985c8990c81e7080050d235ad4b40385fb243bddf4bc4041183b4840c0f9b003a5e541308300c50e14aec7113bbba59f566f90d1924adfdf8a5ce631e1b2d4f6fb5b4f7b1bda9af47d19a0f9e32e153563e7c5b2c05fdca11fcf10d7eaed6fb9ee78c2a1be7f7f2e90be41fade9abebf35cd59ecfede9ef475d2f7b7a38d0671b6fd7def6feaef6f51a28f7a37257d59bf5f716b62cbdbd00b2b6f95aef58908bb7f2b92bebf3725f4bdab5a9bb0ab05be3514c459acd6a20fe99277cb0638062cd07722c58080e7cf84ddfb3224b833ef8b7dfb8de86380fd6d68c2ee4f24a48ef3008005af7ecfda6465979c5134df5816786f433074bfa9cba37e841ae5a02bf4f07ed441ba6c64ba5a80e5d35c0bef8d13f847ea661ad4e98e7a7f7fc3742cd2970511c67dd3efeb782c0878cb3623a131810f9078a2ed6cf94ed87df9f5084f35da4edcd16166d9f7874469f9cd6c37fad157c9c3fbad2b31371ae202da40ef7360c8bc7fbdd93267d461f53d257deb7d35bdad4c0ebbbf75d42a0ebb1fa30a558bb8e3fe20dedcdf386e9cc055ff8d1358ea6dc8c35b9526ec7eab85f13de2e1cd1ef0f03e073cec82f08e4efadedfdbd08f50e31c431d9bb36d28c2eefffd991ce0aae4b2386529077dbfbf5f99a40afeb756f1f0be0adc55a9854f7fb9c6c6c07b2229cd1b276a1bd2f727d29421e9fbcebdf4bf990618249a26e9d9a72fa5a455e6df387137d473206a1e406ad06af99c8ea3c0faf648b54e3a87e5d9648d271e9891055f31f47efc4408ab202eb43042524b08b0bde287d50fa200230946605d815d66e05285052d2740c14a072e481083205acee0a2872fb8a005a1ebb06ace9f33ce393f77f73a77477177d3f1c6dd5677a713c884c5b7f129a5b5d64a2975e9ee94babbbb7b4b4b2a0b41fac4b8ce1695c6b5c5a6e8ac484a76fbb6eb5daee350a84a27aae33aef7adfa68144a400f0f828936ac1b1032c3d3a6b4a5577f56dfdd613f875ddf28e4fb6b62c147e39d4cb54b7a926b5bfcd6ddbecf6133412e7a493c6a9e39108065978614807ce0062c0438f33a2b1d554fc19c543772b1e3a5df170f3593489d29844f3b274c4de4a13535caa1273556a62aa4ab54aae4a72ce7927510bb730ab65873cacdd5801deb6668528562cdaa9118d0e78ffd7b87f8eff0ab445279e7352774fa292a9114cb182f442d3d35b624a85df7e47f3baf1b4a2bea35dd7a1baa72890ab1cc7715f6374f73699e8c4d414638cf708a51733452b4a5568a55fb95a6b76252373dee8e97ad6976f79f97d75cb04a24118a686fefc9fef565c86baf1f3fdc965367ebe637119cdcf9f3497bd7e5eed2b6e536dad78b8e4e17c10ac55c0cae4e1fc076b93874e60b501d627b0be404b3b72f991e6321ad747c66bc5b07ed754250fe7a5d13c83629e404a6f27100bb4817e5569ebd0db9584f47c0cee542bd5a4e6e19cb3daff21298abaac5b02775df7f8035b4be06fc6da72ffd66a150fe78355e9fe5c2517e832f130c8c3c9ba3e3ae03d81805c56997893599bf78c5aebad55894241434257af2ae9495f6ec8d515d48b93b69dcb9922e0f89b4a461f37da7a4a55b6a58d292ef5c8c1f33c506a1a24b4aabc3069fb97e60c9cfae8a10958f0ae3f3b47db971b04fccda8f1d76b79fb174711f0be61eafbdddbaf45441f46367df3be7fc3ac40d1c7cdb4cb3622cd99ed5e490909e9e8c8c8a8a8a8cbf6898776d71f6defa7e47fd14315287f932e84eade997cc672293e63b992fcdb99781369455ed9124bfd613949f1d90b90ac22a95821a56cc9848c229fc8265b32914a5a7e472bf1ca8e58a490cf5e8826ccc7672f4833f86c0e1571d9f7b14aa412adc079b13c1a84b70b69c9229a33f77198fc4c041269fb2ca439934c0e93ff79df1b79631b48da0ad1d49f57fd71d59f99fc6385962f937725a2a2e5b7f2ae45317957a739933e3ee50bcb89c572d2f65f80e66c8617a2695779b7ae60f92d40da5e55de3845843467353e87e47b2f48dd0b927cd40b92b6bb85875e9c6c4817a5afa565e512638cf3e557be5a61bd7a59bd8346e2cbc78fe7e575dc63cdf7cec19e8fd1fb086e4ffb4fd0c8f4283d1e36c0f5a9fd6ae4b228e548be4ba9cd995fa14f2e63bd7c8a65f5d2e5e5cbcb96c7aad4cbbe2f921eb771f133c2d3fd0fa9e37c019dc99540a7027a15d097406f92afbaf2e4a16371987c2f3b928c10b04f34bc4af150522c95567d3cfc01ab1220216d03f51c29d3270f6596ffa581f422af181406974a94524a69a4946ac74344b7429548fa9cfe6a4d4929ad2c8cad92cb24923755ea56dcc97a5315d86b92a26da0da9bb010b8736f8a37ee4dde54e526821e18ad6ab845c7241f18ac9cc02a1d937c6a493e403133ac98463a9c40534ac7d022054068e11b6b4839e2c56a5d81e4b0a8e4c2154b363e9eba0617402e29462e4839a2c16b9461c48c144aaf1f2264a278721d11d4aac269660645c420c924e1a8069345532b094d2578d1c1514c0884602139c11001c42a8a171410e182458d154588961d00ada238024751e4926529081515472d53b294c12435c51106faac50e94084a703a7d4089674597c49d45055d43c289870540c75341f045d298250b4328cd88e8cb89f262eecc04908c8852940518470c18aa5288a70018ba72d9270e1282829873556e0c214b5a4102491840b3af831a18a0a001db338430b37c2d1733e1197d5a74fa34c6657907bb3cb7ed4db27917d3c947af7228141169e4aaf385bad1c32c09df476f880eb539eaff1704e1d9186391e4e3d3fa62755a393da484ed8d4b186ae7377f769757818abf1b04ef759dda5f4a2fb74f74d5503ff6dab74c64963a5b3d2b9d969b76d6edb0d8d38fcee4f279d17b5dd2df5f146be51758f8ac7b80455c26e72b32528a1448c314e3c77a0010f3cf0c0030f5262dcbcd6fc56ebcbf1d09fce1fff807897673ed27462d5f4440b16586a6005bbe838058bd0128c62411130c042829714e0948e53b0f8f0d4323a02171e12aa784868f251828434f49635a1212de5132d65142d6f94d568fb95f65801094e8e30064b4f7184202a03234d8d9890e1117eacbdd3b2304509b6583212c2c10f3bd60c6da1e0c10b6dadb5d6c264f19daaeb6f53584f4c949eac683ac50838d0f4edc743554ae0786adce089076dbfb6a6176664d1f9b0b6660068e040db3482d0360d2fb44583a6ad0dc7002245715c01820b9117f772dbb69d7106d0d3151d94105d09e28726239c145d6981104857961022c80a7eae5821441027419e0fad6d5a6bb3e8410f5cca11400e8b41418ea8bd8ca0074c2e69f4000cdcc22c988e592861c16f3473d2f7890d91cb681497d5affabe4dd19c591b237d3f35038cb2c921c2eedff83b7cd8e1c3109650de0e1ff0d4d3c68855c6ad09c345e055cd65332b1edebfbfa2cdd9ece8dea37cb4a2f120c27b6645dfdfb3231b9acbb6b4f171d97deee3f17e66c567477336bb17e32304c49d166e36d4fa6a70eaa5b9d990bef357204b73dc77e075013d87719c8d0fd186167de0e8fb363fd187ebfb364473f6f2f76d8ce68cf5d70605fada18a1efdb08a1af4d91be3647fa7eaa09ecf2ace76c68f1e67e2c0878957180825f320e2fcf7ab97a9727b2caaece25bb6626f2925d5d0e3dbcb0fbacec9a9901dbbbd8c761f5db33c0babcfdb8a3e3df1a78469bb3dabdf89bd17426ec864360f9de751f8f0b01dbbb3c91ed5d32f744ec0f69c947ace674fce23c61179a8e7a4b1a6dc2ee77333d72c02eb40eeff001db1d3ee0aa2313de49f4fc12e03b36347025f303bcfa02a3541ff7137471d9c6c627dedcaf19a3fbd4179a51034ba37e7e305019186954a6613ef7f1f37290d58f2b6a8922c27d1f0f978780324c30868bca33a0eecac7c3558f63a069be8b03473cbcdb0648dffb289487c4fd48451f41598d7a897a14ea6d7c6c7e3cbccf651b9a877745d3f7b70d4ddf5fd15ce67f7fe6c4b94b0ab018c5eb321a7a585a7eaee10a233d5f06467a661ae60eccc842efd84f24f0befef286f9918a6e61d3f363fc8c98a08fcc97fa1352f5fce8d3f3a4e8624de451c3fef3754881b9df576ad7d3a7f6ef3e07769a02f339aea545460604c330cba378e3e12b8376a28f1bb08e54a1bef7f30b107dd8772a9d9775b81c3d44fdec5eb9a16891f85469913993ad960c9ad346d3044df9436a8a4259a2cb835416785f3d93c54573e193a00e29f0d4b1f3cdb31fcff7d9edbd6e5c272d18258d33d582bfe7218682519bb4b5da3a346773a80ee1218b6df06cd57ce38da439a2886a382aa1a0fd65883ea4f62fe2b2d777067ed5b72f73548a4aa911e0fd9a798a724bed2432148941e9459b53b8d03447733ce43efe046313c63dd7e990026fbf43bb75d4f3a226220a9a7b6722fa58fab65fe13cd0dccf1c0157fbdce732efb977292eeb9ebbcfa190305724c7e0a173f4b9a8b9f95ce6a292e6b62e06048c031422f35d1e07fa2d8fc37c9797cf753e36b74184711f5f7a51bce13e16048c0394d4e3d0f2f471706979fa445a9e66d7f648a010593deb3311979fd9b56527feac8c6495f184713fa1105941f17e95a1703f3f21b28987dc7bbf8155cf4f880cfa0da4baa3de067e5aa808bca352c8b52ced1627cdb52c698efb8f20f5c06e7b14783ddc507fef67041c83cbea73a8f7746c01e38e8b174d18f72d46ded469f94ded457316c384717faf126eb5fec370c7f40f8a73230fb947652ff290e3b88f355ca6c185668675bf5c84d98f37fa4041dbf762575b6ba3edaba20401ab8a54441eaa88b4fdd6cc893e6238df7ce38da5d9756776ddecc47fb6b0e9fb564554377c61a05ad275b2d5fabf51a7cb3965b531462a91d23ba78c74733be7a4f5ce39e79c736e2be0c4429d3a29a5f3e59cf34529a59346d50ba8a44e38a448aadd620c299596da1ac3c999b158744a29fd226fa9ad2c0f5b0070c2941a7564dc7bf1666fa45c8d28d4c7433f4a524073e6a3832a4b962c597666b811e432541397792d460ff6f2625410ba4abef40549e1fd5d2e213838f9c8d4373eea1b7fe35d46db17a484eff1f6e3e991b7119c2f618946a3699cec6a025d4ba08b6907f82acdd98b16809c8fb7e5fb1eef8ff3b2df2fda87f37d3da80d74fc707a805f0fd0861e3d7a7c0a3d5240e175bc07e88ff37d287c0af986a951c84e6610a279667b1cdb9f90f79b90776893774c15845f35fdff9f23478e1c05e058e078b81f5c0b5c0e1700ee72ad56ab058220f85d4d4d4d0d0c0c0c4c4c4c4c0c013ef63b1e007ff33afe84bf1f00fa39f75bb8ffe33ecf7d16ee17e0be096ff3dfa7f0381f0df03dbe84bff128bcbfea530f7b1c3ff3f9773c55a19f127259ced0931491cb5478faa9282ef3f1f42d007e0e98f316f8ce7e3c167821890540499403de210f29ad25d6b2a305002d35971b171d2e27b8e4dc045c2297013786fb803bbbf7c357af56ac8b93c25542e1e5c64b092f2f2dedfae8aeab5daed7ebf57a1a84b7d77917adfb0ae47d2f05f2c6b848de2d174dfe04f24dde57025947de3802f9849a0c790681fc80bcb103720c79b71a901990f72f2013c93b54404e0002728ecb88e6876413f2be30e48d35cddb1c20ef96a6f94fe60d90f7d532df23effb42de58cb3c8e90bc5b5ae653b0f12ee47db58d2f21ef1b246fac6dfc0d2079b7b48d470187df4256e5ddfa915379639e0c7bb190774b8705c81beb3000795f1d827509e709f3f8a877be93de0e28f5f7d5ef60a89f733e32358fbac38347adb356cf75c9e6a9eae9094fff1e5d2b5c967afa17c9653d9efef5b93f2ec379fa570990cb6e3cfdcbc465293cfd1be4321c4fff367119ece9dfda1572998ea77f875c66c2d3bf4f5c8682fe485fcf2247bab4be0ae00ce075587e1f20f6307f97f24af8d4c7d3e3539f119ed4ff90ba84b751998002ece3c7037b1defe2c793028ebf616fdcb881e3c65bd048c4f1f1e3c1f13adee16cb5d66dc6ced499b7a091994596a987f927107d1da04bf1b0fe09a033795899d0f7271ed6c7017a9187f571401ff2b01279583f85fa30d09970230feb9b00fa9187f55100dd0a0febdb805ec5c3fa2ad0973cac5f02e84df57bd4ff3e9e99ec421e56ba5d83db91c21a1be08e5264c01d9968c02d7da4ce0537d5fbbaeecb65ddd5bdd7e5b6cc400280db856a769402823b326de9238572805b32f9744a29214de713ad3f4a5c969f724f7f329941b31b00b8a5c6f1b92a79c9364b5724bc42954af4cc072a585f676e604fd5db1bd9740d2c3d93778fee61e9155ec7ad00de3f1e01acf09df40600462d8015e693ddc3d22be449445fd0f7b98d93dab62d561a6ceec1d157e808cb3570d20e489aeeb8b4c38f137a572b0698ba6bb9f12d1f8f8d6ff98cf0d0fc0fa96f7c47a30feed322368939ffc4fbbe1fdeff77e0ff0c2875e7f29944e0f6379e6369fb736812e100cf279368db483d8ea4ed7b933be9c09bdc8a3b79485d2d574dd3d606ee1774cddba8e28aa2fda2e921976d7f3a7299ec845c56447f3241add0b44be2a189bea163d20e58747e0ec7db9f020616172f69072bdafe4d4a42c99eb4298acb62520a8434fdaecaeeac686ac5fef6d6cefcccdf7818b8e3131a86fa0c609fe65f42af9acba2cb665c4302e871631369b47d899fb64a55dbb74fa30f1c6ff376d53c740d1161fbdb557309b9864e00a387337be65d340fe90decb98fc7e620ae9fef94604f618fc247d8a7007b1cd8f780bd0bf631b07fbdf7fd30e161df75294f7e2d84cfbd05bb1970533df319dc52e71b703cc73d8723db23aef3ebcc0c46dd81fb866902b87be2133a3fec3beffb113e178246b86c64d3f6dd8a87ddc3aae8ee33d85d1fbfb14e05e0774ba73efaccb5efec376e69150abf7352f81dc3f91dbec62e1c835f5869c7ef56ec37d62d3c7e5f4dfbe8b357eddefcc600a84b2e0b9fb6f4ca84d5534bb3b0667df4aef6d15f8aba87799751f72ae47dbbee03e032d2f45d4bdde7e47dbb9fe58dbb97b996ba7f751fd3bdabfb1e797ff7387987dda790774c778f42de39fa45eb9e47de9789ee3e9637ee7ec78ba6e9bf6a733683c33a16ba0740dead2bbafb9bbc71f73af2bedd9f90f7edde84ee6179b74230d6e6ac6616754fbbc79177abfb99bc71f7b9ab69da759dabe612720d751b973f7e5c4e3529320348d45cee894742524d8a8aa0adcd3c8c70f7dee48af9785cf537d52b2d3f185c415cdb776db3eb47c665a6d33c9cc02c3d3f9e7804de2e9aa65fc2effbf45d3dec1055c8f1f45d3497cd3c7d974ff451c2d377fdb8ac84cf33709bb55dd4f1cce5fc16dc9eceb99bc901de70750933dfa93e9e99ef66408be3e367710089257cf8099125cc94d0e369eef3c70f866d86ccbdcb3ed5325b3c9940c778f6f680f7d5d4266f24ba86562c4fd769abb5d6ed6ef7627d37d048bc52b76babadb55efbdbdd365b374b8d669187f43f34f0be5452340f993ca4b529572a35bafbbd005d4344d77c2de0f84bc5433ab3715ed0f6bb984e89fb1d4bf0378323effcdb77ad1d4b304ae7cf600f4e0f8eb60f8247a6a6f9ef5e06dc52cbbc7f41eedbf8a86f483df3d1fcf4e40703cd5b9b8f4c6de3e9773597d13cfdefe3b961e3e3c76383e66f989a06064df3b3c8653439864bc565f4633e23525b8de30dfd967843dfe608dcbdcc77b4538a69d5a5392bb2b4346566f4dd2e25067ca94bdb0a6d2bc5326d3e7b93a2e9a7c0bd3169fadfaba6e97bf53bbf9dcae3c0a8955ce6aaf1afe24d4cd88aa6572a952d0af882090f59ba36d5ed6e979b3c28310248d437f7389290c98392206f9a33ba43a92fb96c63ea7c68ce3eda14a2377b583c74e2775d726d1fb91c7a48439c0d8cad60738acc59a74584d1ef4287a1e97745d094764af186b25097b62144e8d7a54ee985df9dd296817848e391109b5f4645fc0259d82b9337cc4b31d22e2eafe32e2e2f2e2e79d3df60c08f79ba7d4c0e7ef9eda36c75528529a51466f5aa17954ab57a1d5fbd8eb35230fff2147cf98e7afae5592c168bf530a09129bffa947a9ad2a7f629a55230a536407f7afa66def8ab51e6c753899ed4e8908756c8439b6bcde8c9c3bf4dafd737e91998bf4d6ecd65a9b77f85eed07d72eddf28452eb37f8d5cd67afb578acb3a9a26d7effa548b244c858179aa585c16937608d2f62dcd652edabe0db2b5a41d5aa0eddb21fbc4673ef74a0fdabe8de2331e40d6c76531e94748dbb73f9609cc0b959f01e4f4e457bf36cdd955b2d7ca0ab44a3cb4ff02a640156831687f3cb47682b605da261ed694ae92b62ff93add260f3f346ed4712c1edab761c296b66f93b67ee536b98c7b1e4618e65f6a2e7b79fb55c865306fbf0ecdd98db75f89e6ecdf862ed8e5a3cf9ef5f6c861f495345d5259a7771fd2db9fa81b398cfe0dd08b1c461f86b610f3929dc846df7ec503b715d2f6695ee0f621176803d52ee0ae45dafe0cb8eb935da5d0e0f27303efcb802c0fedc7d06ce3cbc76f7b91ef9b7ca7da05ac616afa14e5f23477543ae902ee9eee45bee4e861f73a4ebbee5db6eeb9dfbae77af0d1a97f79241128d127e888c51652bad845988769bd914dc37cccc7cf00ad5c6f981a264a86790a6e30f48321f52fdf6d9e7f2d709f8aa23e69d5db772c93367d56eff214dcb617704bfdf23030ef9f11a96f887917d0c8a65df60d53bbe42d754ca6af3361c0dde357f4cb7fab3722b36897a7affa17306a16b86f989abeea572ed9c8a65bfe86a95bbe3eb9ccfb161c752605efa7c016f670d2ed4fd908bcfdc9eefba4ed5b2c9c8ccf20a1be13d474827a1e4d60a9fdab06a24c07030588617d21ded42f800162589f0598be3f06eaad403586f9f56bfd5a2b06e24d05e236d0b53de8b22f5df6e30e2ad6bf1b788dea56ffbef4c1b08edd0446444d44434254bfbd7f2d7423c0db6bf265766def2f85a83ea949153ddf41dac4438a33654283785091d28904401e2e81fdbbf77c83d4dbfef49464fdeab713d64abecb5c433741c9013ddd3b1afc08d5f3e74f8984124d754dd288686d4a97c52413306169aa895ce6123293c4b07a56468203116856ecb090ac9884c082c90e9296fcf831e0e56364124d64f5503c6fe90f78f91821defb7befd23e0c08c55f0506a13f1ca4c1be7c18bcf79f5f10fbf283c17e313060f530445e1eb002810f9125ca0eccdf20f5263d8fd5ca301f034249c16428deafc078278c6a4f0c4c3f050e017528106542833cbcba9bf6270d720229908774cbb2099401de5e7322fa74c7265de432fff94d13ac0979489fc8557621cf34365b7d5c812ee4301a242c89a6dbc002d7e40c4d15d885bce621dd01d6e11e40e2b29d030303bcbd76a4d2a1195c0664888714889e3151d0e964f513ecc991c181bc3024c77334ebe9a424883745c41df42f4899c41b4a832605aa0e4ae9ee534e8f3f4123128c33d6c7b0b2d722acf35aadb94c88be0f39124e12124c103161a429752a9a3a91a65fed247219bd46d0b269ce281387d1a74039b2e0491fdc024bfaa00fb0ff964d15290710467afb2e7a1cc7d1ee5bdfe9ce2913ee7950c15d0462326bb5408fe2b0ed25e85d91342d7158bfa2abd56af5d45b21faa8addb42a124b554825b87f6bca72b441ffead998f1f6a1cb439c3912913876dbf01fd50200f73c0db7b149f4d276f0798b7f13bc83c4dccffef30d37af07770fd4b47531074d5073fff0dd075ff1fc713f9c7f1f7716424506e2672e36b32121c7fe391e4ff4fb2f3025d08003f839f5d445e8fe35f8fe3694057b501da789a2762e369be3e0dcdd76424aefa4976681e89ab661b88d4bccd2720eef8e009db3ebf4d4682c4e66d724d4eb263e393ec7cdcd970e4b893330826d979b156df490f0493ec3c1877e6648147ac9e7902800a6cf3f6deb6d160816b4c6890f72ddf5d4f829d6e8150e8779cd742e9ef07ebef5370f512ccfaaec02355f7642ddfe5250caa9741542f3fea1c5793c9fdd5b3587f3f1e56fd249a82fb8b6829f57d59fd7dc928c81daba7e0c6d1abd7992de0d6a15d5c72cbebcc6e7a4e35d65a6b964e404c521f8f534f8ea61f432969dcb6ff74fc15a28fda02728f41e99402bdf6f17cdb7be0eed131699320ca84021d81b75a63a2c0f4b7dfa1136d3a93eebbc9270f85bcf34d81e60cdf16fe9675a2707b0a3467f762dc6afd53201de97c0aaa340df2507737c03ba6b7ed3e6dce3cfae00c2803b6c01830468d54fe51ba2845434f9a44263e1e460f60e9712ac244440948fc18c389384e2174b1a6db3746a37ce9b663dbce966313f6a2632c9c301c5076a8bd490cb4ff6b8657b47fcc65333a0594540226ed4b4078d2114ce81dab54992bd2574e389d72a0958252cf120869fad2c97d4a7376d110e028ed6694840efc2de724ff9763099682ca01f4ca1b88069252c1f40465b8598d0f97cfd13d389a86faa99fbf71f44cfd487dfdd4d7d7e9024b9d62216ffadb7cfab564666e747c97ea2718a9c3a24bf6e24da4f916b81d54d2fe2e70fbd27630b43fcdd178083804d0f531b80cc3d8e84883e3bf3d1df3eec9d1f187443006257024e2a1a7dc68de60bdfccba773ef5502263a0641c7242384b4fc2e15583e114d43fcd76f1d3af5a9c7a9a76091974e3d98772bf59f37be915f3b95777cee57af33c1a85f608f0e8d5afdb4016e3fe6bfde0648f311747d17bf20f35f397aa84a8136c0ed552a30be0cf87a1a50e6fdfbe1f2f15ba0d433a98fff02772ab7e0f2f165523f03c609b63e82331fe3ca5b878e9fa23f2a8df9969fe04ea263bc9f01edcbe898ed5cec96de6e6494df7b1770f7e0b40c8901ab5235aa4fa5521f53aad44f559ec161fef7e349e5225bb0bec701e278aae367303fc67a061003608f870e468ecb455ed749cd6f35cf82ebd48033e800292273034ed7cce0b019ee7006b0c8cc65482bdafd67ce66d37c252524a3b86414978ce292119347a7159672726aef30424b394880637386739081770c6b8fd86533bf447a8a9f834a8cdf05c92831c618638c31c618639431c628a32f75f3bb09c220df2524fac7dceae40783ccd83df9059199e5617c1d49a4f480114a74fc17930e808e4941444eaecbb6fbd4f34bc70f86f9546fd3695e8142d26d3b7a9790aa3f1ecf528aacb1641115078a3950cc81620e1473a09803c51c28168b12c3ee40d40039900e070ab71d74a476fcb1072cdfbb7109a9498e25610e2de27fdda33ef5405c76b78de36aadb5561b36ed5ffdeb7d47dddd7dcff6a9afdf970ab271ef8146b6efc09efbdcd76ffbbaa968e07e7e37f30a5d4755debb4f9f3e7dfaf4e9f3f7abfbd9bd2a4533108ac1aff324f53b3d8a2bcbb66cd8a6ce5455b0e77eeab78f479532e2017d3b2051a3f21117728100a13b79f778e10d1a60ff5a6081a3a1c7dabfa09dd11debe52002ef88447756c84104bc57d02e21f5e9cf9ff8143cd2f1adb4bcb764161c266796bc4f2f04b8d3e12e9359c743b95483f4da09bb8b922ed66c4a73929a03f7adfc1ae8d360dfbf6e94dedfe8b66ddbd39b74022a5a46c7a42027ed1f9d37e7c9e4b0e9a24f35cd73690b4ae3b4d981680f52e614f270cee9445b94668d40b76ddb362ae596f7945b8b556bc68f6328167eec5deae3a46b5a42b1340a45350a0586152f84aaf7d489f71da5d1317ae8a8bc7b74783250fc8e46dc8ffba8bce76f514f1d34cc9796becf8e46da3f9efab3cb350ef3f7f0298bded128d6b2484c6972026514da14a27dadb416ed34c7418e32f0964ef1a594f82f928e3892b89c3bd0374a0a6a12694e6282249f357ef0850e5828dd27359ae0501f4fcdd2d25b471146c819410c48e013a483a6cfb5eac75a2b11b050aa447b40c320c204449891c4848a228688a2e96f313180c0b2375c004dd15488214d85e081a65f5b39b1488589213879328430c228821a6714d1423f9e8a02928c0e1c4d5758020446d21235806041121046086288a420928072d0f4670844a378898048d3a7224843d324254b68fafe35acb5b29a88f2040c4ad08225493bf5a6a16b55e95a6bad49482d6d1d3f4f7ad0f4b110344df2c129e907a4181ea29394527ab1175991fa9c53ceec60f09082abbb688f3e8b4a4b3189872b4556b4fbc73d7db457badd0a378a4be8ed357fffb1699b2618c743f9b14573998f3c9ab3f9e432fa4a4a48484747464645458ef4f30a7d979dfe6ad935ae2b21399150ae551ce6cfa4dd8af62b61c512d36e7d72642e54ddc9d375d26a37299549939a37f9927b9746650a194393e64f579c3c97a1ea85213a2cfce0fd3a2cbc30e4a2a1e5cbe050f830ddebd9ade8c0c2524a1672c0fb75d75344862adddddda3c7211e4a201e4a777777f7173c942cd0e480a50e79456a3967f5e96e4347287628434fd99aa913743403465ec68fc752b0e60c4c97f186fece408c7adbe466b7ed7e17c10c1871c2e53b612e3360c48b37d7437c5be46f4fffda6da3d606f947a6e691d9c8a669903f330df4af9e92be05f396b38baef3284c448fe2611c7299fc1865f6210fe3cb9f9791a63828d1f64addde82d56bade9fa75bbdb864423ede9eed7a11e569dd49ba6003e7efcf8548987d482483ca06b8fae18d0d5cea06bb6bfbfe7e366e9fa5b0d2c4d43cd13689e70058d3eb6576d89c75fa5ed327afdb86cbb969a5e3e5789d015fdd23149484927b1a4635212483a051d939268a26f159ff940b9a1e457e956b94b9587272d4c1fd9c71950f81f52cb5ec72fd2b5e21e85f41a35c154ba9a053ece07c4f07132e0e3249200261ed20752e221ada67e3ca4291f0f698af6aa39017efdbc6869bc682edb79fa291f971d99a91f97f178faa9a73da804cdb5a5494b95a21900000000a314002030140c07c422716030a087d2247b14000d83964e72521bccc32c49610c1963080104000000010100191a9a46010751aa955ee08f71cf558d18a41b68d123bdc808553a6fc108e42d4cb2b90c891b926198631668706e09ee5c5863284f281c125c424b93f0d34371a06652a2c485e8965b3cb9190656972485a2cc75fa4b560358a533eaa22307b33f8e3b9ef301668acb60516c68765c3ef9657d4f12071e556a48136ea20299b5feaf9cfe6ebf4442ba0a19d4589dab8462a5f6e68c2e7312e638d756e13a0b0cc789a93b53b85a80f1293bc67ee9046e66b11dd1e4cd695518fe4334250998f0b7be080a8f0cc8e894b0e88db2eb2bd660ddc1b6a05ae393a513e708f60edd58c10d68da577ace99950c36c015f83da600a92b505361930d4107197f84bb6674acde6b720ec51dd79b792cd73922364016acb793efa4e8510f1fe90a4a4f54c248e3ccccadf82fdf0b8bdcde5cd05e7a06b01bcfe51ee4711d588d6517e52ed1844a98dd377a27a05a9500439b3000dbdee3fccff79fae360f5e7921b0c2adcea17cfe34d00827e77ec938cc446f2c3a9cec29a72588e8f0e12bf84323f03bd65584fbf70f10f74543653e39b41c9338a816151c54e44b64f95e54aab92d24ac57842a3654f65e29386b5f26a9a046f7f5d6efb254e18438da757d96a05e6b52b7dd2e438bf6768f3700bdad054f3920a82d111a20cd7f4344e33ad0720d85b707a14d4c351e942e4a6fd4c64a062f8a847370332eed8e7d2d6fa6216b28e62eafb6001c1279f02f23a1558c232711b98e2ee2a509c3612a4297f8f4f0bcb644b99e5f82ddd7d23577cfd6e86254b13b7ec04ef95304adbb86022114e22767bab5aa548366fc384c5c5f51bce7931a81967eea48f35c9d89e8342f07a02971b68376d7db110151d27a5f6e9747973527952bd37e1517d73778f22e23d0ca5194c0ca51eb2d5db22fdbb81cb18639a09fd9426b9aa3a21bc2e0a8bd985dbb26e7a24c1e0954371f1801359b375f879d730d85fae09870a6420fc8876162b4052515f57367caf0c562c7c5c6f5608cb43fe7cbd02d5e9ccaf3a55da9cb973932e024661eef8fb1c66b623412a06ed753a4d33ab194e7312064035199f5e49f7a18f71291fb006013f3a78c3615a6952c391bfeb23308b4fdd9d74c23ba26b2a9d8c7c4734e4e895eed6809d15164954ed6b7535d3f3b2c8d81032bfd2edfe05345b6691b2a8a2dd7e05d274bf1b3b01d8a2c1893f2dcf5f2608847e6e73a0390da3a29061c929e65701b9bcb95fdc00baa78c28d9c67b489593024924adcd2c9a0870cc046811ec8de7419d5f6bff35712e244c881d925c01860ea731d4ca09ddc1cf4007f689f690c4dfe5dc416bf397ea5580f361845ff2eb52e4558582eab255a980cd9b3bc75308f13b8fa08a99ae975b6988ee6a1ebb7a988c7c6cf248b39a8ac6bab54bd779546141d4c4786d0091f8b81d86a7b2aaaf5413d0c1ea6859e3bf177c9182858e012c504e8c0dc48d6abf6b5de15c7a3ee04e2788542a754235fefa3cef293e21c8995cd6e82b436daf7f9ecaee43a54f403f49b548566d34c5044c711183fad28f549692e5e1a8dabdfc8adccba7b88eaf1b0dedc084ac620eddbbb3e152a61b68573874f8ca9413d9ad3743720c94634d8ae57ab3438a4e87198542d723a09d71f5452370527ab76c9d4fcb23c5fe4ef87002ae00b6eb814dcdaa4dfccd83772238a9669a8f4b83882a7fc8dc6b702dab0bebc03fc388bea7842cf5c28c1cfc9dbff7e19e89a3fb33afdee323815535224e46feada84fc2db8cfffd4a70a7de0132bd45825a08e6c3fd2ab4603b263b098d854283f8916e62b95c7d50653fc36cef17091665695b662a1719e0765583b82ee2b51c5ecf1ea1cbd6896c75e32c0d04d72da33afbfeca8cb8190e6647f2a470661c210e6f2b90cc64c46aad6cad4d21638312554bb3595c44397d849b8fae80710a06e675972d82b5647f061c7256a9c20ab8e4251908718a0f26bfaa6a588084b83ca63ed5ef7d7792e502df66283f426588984fb0a5b1e750facf4b79852d5dcc58c5d159971fe15d9af76fef1df51303006c2f78e1a4d8a1b9b6d186e2b2ad070ba06a66b21e792221dc8a147ba0c05c0860570a5290ce05d51bfaf55814185999e92e3a5abf2d236dda4c66ee41c88b35083880cd6f151284371fa306db4e43cca99d286c7d05ea55a49e156b09140ca37b597758f5db9a6f953a5230ce1d776fde04968711bea54018fd564ca7e64b99761ccc7b7a9d447c5d01d965b38ac76b1e9c8e936e3b6e363d0b25e29562a15ad6a535ebdda34113afcf4d71604949a25048c15f5011e7a86c3c968a3663d1d9a882134c721c310dc764cc155cde785712ca09c3c87b7b92737a59e0d9efbe25f06c2b822968430f88b5a91cf2cc3c7beea3a828760b1439e877c6793cf46116f105677bdd22572fc17204a2ad0bfa5c5f6848541698d5870d4cc164ebfc0826f5e585e55c93d2ff14d87edc0d8c2f524714c9a3161bdec850325c9195896b33f7a961da65c005e1a711d42d75f0b8c442cdbbbee41b849dc12e4cb13479b59518c41fb899ecdf76262670fadb2daba0eeaa6987b92d2c53a548e4042a58ae70b963798ce0f056f66f194997379e1eab7622b6319069ee6aa01846a95579e71d56752feaccee50f18d9c4c7149898a768b9ee755ba86c439a336a176599b501bc0488731f12457fd7a93168854544f4936ecc37c4bb24434f30467f7a2024c97634920dff8d1a76a445440a199778ec71f7e7cc34ca9479641de293df917b3245b5b85d88cc3176ebce4ac1c75d67527c482ca5e9b5cee6f4cf5b7dc6235e497c7c34f4df4c2fb8bd4747ec7b2502e9176316ff2c3ed324d1dc7872d719947ce8ce9fcafa7381a569cfac98174b17e2d25dd5c15e98c13f998f4ec3e4aa5bb3606a6e722c9ccc0288b8833e3a5152176519253c5a27acf670ab160fc0e117b0df0ddf81e02ec1a6c8d529fcf65f0d8106d0a497dcaa729a74681b130a35dc73379f6d2e8a73d415462ce400f130d5a1c07212156d942bfd1fa1050b0086bbe994f4b85b0c01796aa11d1453d64c312fcdde9ebfbdca615eabb3ba2aad3bad9b3a864243550771d66d879c5ba359eb72a123e7c50f97e1d0d0f9fd52e6a84d525b2f92f311b213e75bba699a9b6afc985cf867c30b6a77b40b16fab0e09f6e68ef098cd1f2215e839454d80be7b1a11140fdc7d27ac475981da850bcc3f435781ac321fe2dab2d729fe53c740e6c765c9acccb81e3c0288aebe197b7967f9117478285e2b387c3daae361d1692b92be3ea42dd3ad235c485fe307f5191f437eca6e82d83d9160f7cd63707c3778f7c6ae581d6b04044e3310a1fb923ad2bc24e6374867ab2ba73e1a0e31ae45e2df8b162a69840cbaeaecea4bd4ca6b8e5b86312e1095c64bac9d01842691e51b085b218d09a996c170f40b35c70c87c3aea29e731b6a97c719175e4b7d6078a935478cb170dd7bd007db40cde7a429d58419c65056b22bedfeeb058e7aebf179908ad5fdb94855c61cca4ea2416f5db87609c022378296fcc335a1b10fca502c1f1b3fb3385ea8f99a6af73277cbd1250fb1d1b3e529e02a4c504717ddc0aafd6ca0a51b9cd1feb9cc9660bf5da407a5b4b8bbbe4952f840f610aed0a3f4ceb024b32f4d39bc7145d12687d3f54d9fd35987ce6695361b229f77540453d42d1210998740be6d62c5f2c9ee15ddbe261ba377ce807eeccec33d11c1e9cb3f799185f872569eb7532d3e366d551a7c6b51c324010d367cc8879d0e8356239be8540bbe8c2d27b6d3939088cbc502d15f5097bf8fa91ee091b6e44728ffc6a9797f2f1b58daa01cfbaddbc1c7286831654bb5e760c2eae4b537c32f8979f7c59ad5470187184fed792a0484ff5828e0288f9965ad1047025257731c190035f89ac0e8dbeb9372d4bf89a11cd8f47634e41b2795ae2fabb4a1e129921852353e39a4e3a58e5d63bf2b6d6ce222c692e1e1c9dc413d3af7cf44806baee5e6ebed812504e0091cc550ee8289046240f613fccf94ebccf38b074d8cc6b9b75ecac2b201fc404d64501f4ed61d76e49fe543b8c7e82d9bd6a32d850f8981fed6e271453367624ea51a52b0f6731ca8a4a3996f17022bb16afd0b0b81da412a6709f0d1031cc4e200eb403e77647b6fead27aab84206a0f6730140468efcff2ca4ff39627e58d102ef1f7749ed41f857fbb712e3b57fe623dd10d7945aa36d98039cfefb3a60325cf4d1256953a88b0eee05843e10d69acbe43ca0bd066b6fb524a2b9c6346b164a9472fb6dc27e490e68c1d70b50d31321811b1217e175e5519c8dd852f2a265eebcfcd59f939241851ad7cf162e4841012f6d43f11531b571650e4283bf9e5add7b25f7dea27d41dfec74261b4ad961e8aec822a5411f16eee561fd9e3ad10023e7eb8949cc1686ac6b36cbbbe6998b06d91d0480f00e533b0e84c4b85e98c0982cfb18ca77e511aeff3d8d52ba1b192e841c57d0c7826d9e5636dc83b36d734d28a6b595c8aa4161ccb21571eb9d31cda2e83fc29fff6e1b768787c62c717b2b9453cc9c5d64b5106e72219f30df4e3d58704b5cbde1a9143535a6e2670506c732f302f34c7b811f60af3bfcdc413d190edb1af73b23671ef082d7474f2d5aa567915566a723c769b080042b0b8972a9a3291a744dc959a32ca7f61e325dfb581fb9189acb3ae981619b5d8b9e55b3c9522bf6e27c28978948814096f117a9015a990442903fbf0d3adb9a5eae01d598a58da0d4dc2ebf8894933d870edccea7e63f3f6d16bae229f592fc78741c6b57372652f35b5ce20041d16c077788edad2978f99bbaec1a3ec73672b5cc0e8bc1c1c06b819c834183cea2c7b13b9ad7d5109fda1d42e2baf397dcc427b711fba1ac6fda7043f69e6bd55d925303657bcf249674f636ea554a0a49463e7fbc5925004f7db0763e79a6483269193969795e66591ac1f2fe9a655423cb10d0fc6f52febda579fbd8972f624b374ef284392620f011adc19b78e21a4e1b6952d38b58c6cea6b5bf942b6086171bb889cda4ac78de03e09b2ad58e987c768ec71526eeea3b9077001fbd29e6da913025d84dffdc2b5a355bccce52c11ffa5e83d67d0a8100a703a3878c497b8b83a05ca17f73ca68d878694bd0f05434684d5044b64bda90d84b47ea37539b8cf20f12e90c031fcb2a3095abda3152abf69a594207d8e4a5c7397822154a3fb5cb22a70f32dff97c3e56e9aac233354103759ae0b3a9ae6d3d16a96343defff56e2100eb15b01422aaebad77d96aab923d1217c6d61dcfce8f6ed1ac8f7d62d91746f6f444fbb68f234ce27969d27dfb8991f6228d467c1f1b2b25836b26b7262d265114cdb803e243a078420ba798c511da6745dfbdb87299503bf6e0752cc1eab6322685e9b82a13b43e700c66d3c97bcbffda844e69fc2f9c4750b95259fd33420bc32e4c1b8573c75997ddd03f502dcc741d2ad22e511d89daa59cfa14b2eb2837d4aae537016081dd076193a8874f8951c764961e6e6437b24bf60581d12e6c8dc71564bf67566904d291c10576d24e9e5baf84e7e597003a18171463320c10f9909705ca5da6a6ddd5bbe5e1c0293d9430434258f3a6be563c7735b7aeb0568a80618ce35b43a8f8be104375b1c3b4c3cebcd06c72601032bc3f4710bd523cc6de830b475da15fbd5203f4b3c4787d5d14d91745e40c9c1e55e217cf5058ee037ebadd1dc84c3014f1b962bd3f3843d0b7a45cee88e667415139503652b0d7dc540236a598d667e360b659dcbbc6f8721a7bc711a5dbab08a8b2647a19df039ea8761ee3465483feb39228ad113ac5dbba415803fdc1440d13511fcceb12efcec516f4fef6974062c9f067835a1718c1ff19996c74126dce9d630a821e9ac3d51ed7759f2da643197e8ef1bb197265409be51b931857de13c7af1b4e82237061fe0685239ed9a0fe3d9d1fd5207bf9e336d56fde9890913fe9666d148cfc1c6c63459a30f111ad4cb9529555b2255eb84f7dbad42b0cd242e7377e5a0bee37a20053568d361cca640af5d038e4e931bbb3ad1acd0cbb4368e621fa4217cd0dd179a9e8e781d836fbb91d489266654b9b7cf236d9c85920f05733443e27b4e1b0710b534f05a3abab89458633148388b3cb1586a483999078f60d69b0dbe23e1e9b961a9e54752a9db5f9716d5cda804361467ca9b50d1b989f6ad110254c318a2d36fbbdba287078edce923f4b866692ffb53bc12bd7a0c3b1ac54f00b50d5b28d5475f4e9357a48f165900b302a0de88afecd1b6e203c69c660b9ea40d5458102a0ca2019fbf5516f1d266ef4b9445934c131e336a4108f8f4b16307594077848e678dfaa95617ac4ca0a56c169620e1e321fea9888b3cc555623a785c277346d1eb51d37ad247c97f59bf20d4aaa8a564cf4842904337871598eebf55a3415c6dc683e805e66c0badeb3b85bc9b0a26fd65ebd6aaa3e7df7ba7e72eb8e87d8785dc83370d5b9caddfcd47f53b801f70c7c90302ad984fabce8daf3ac8da70d7bebc61e32a0756319809445bfd477cbaaadb23790f3cae31bf0b695657531f2b1042b771b8fa079ef625c7b0c114a5c02a4f0785f55593ea2579b0dd25b78985290aab18386dfe0190972aebd8f9ecee957079bf1b92b2341073e1179e3224ca5a5369aff130755314c66722ad068b0410f3bc977941f9f33acbb5decfd2a6ce9d3777cb68a5864bb8d61765057ad2be2eda03dd2532c58b946eaed3d5a325efcd83bda36f895121c68048d4ce91c8dc161ad83d638d41ee02737003a05a01bcbc037003c21e774b80604776f2864c57b8b5b60aa39eb10c760648937ee508d34956bd82f6c9d49764a93b240633a5a3a6251038035e23ad29d33ffc2675fc08dca6ccc96db5794ef8eccc68ac5d882c94334d8703a2c77c32f8cc7191c4880e0a5edad5885dc88450ae84cfbfe04353282ba13b1187a6aa12997fdd1b96f3c1cab2939723e751e6e2b8a28f118b372251649daddd2f6a38cff038845d26277e7dddb3a1c46e4d22069983fce80df93eb0f3a05fed1d6a3ea37a113596c4af33a1f93ffce0cbc41aea8ca15c76ea62790fdc9e3711da43325a69c83df2df4d783ed22152c404eb5afcf51e5d96a9eb5e9527de995b03ada53720f1f5e5cd4a8189d2bfaf088d1389c9540141356a9e2afd552b7297f5c4ec67df2a69fb44001488745532cc7d35816dd6d36e0e81de8e16dd25deb72e0f688b651a2963d6e90b0be88192fb8e4adf5ab2a6e87a6264fd2d6b9a365731a86b29223f77a7bb98cbd2222d34c4538b5f5da7c9a40b68a50701f02b4cd36938737f45a3b936f7c88568570fb1aeaeba538b4fed368871c586b436cd782a82f2578efd1e0aabfe1ba50702cbec0cdeb671d18dd12ff24675acff41d4b757af1264febced42e877d2cc80ef3011bd7c3f5af7b3ae7e4fa310a41cd9af55cff97a36460fa7e1cd6a954a614e71ae603e5ea0a5103c3d5c663ea2d39f7c9b416789e141d8520b4cfd0a749d4185221ca5b8c020ff8948d87c1dbf08c25cc81d3cb7bb625f9f01944917905ac147a479141e02319a893c46d7082bd6bfd7d6ed6984520817e5df7216b4d4cee42d6948607cf62b6ce0ee430e06db679c1081a1922e807b7c03c05355a16ad59196570b0dce89d5374055954240127ca94685da9a4af6ba17237326282c1c0b1652dfa1122c101a5dc1bc5f495f8585b2d15e81b96db144310f45098cbeab25d046550873455852a219375b31466c95320c64b3253bbc87e540aec5b03c64bd224cc3cd50f37bde14b506dfffd4d707c93256c563a08c224093a3c8477d2119f78ce82ec466805bb3e601162a392776ba544ce3c004b34d10ae4a899220fdd8a797c5c55b6773a788d22f61914a9a30ebf28759cb565beebf995f16becca94d408d3730608526a5700a188231db51d30fbbfa35bcf521801c3b067e3b13e9694d68baf75315f2a37afe951b838cd34e96392df041e5173bb2c489bed745a576597e00edd72899f67d34138cbc28a2f87d480fabf017890ad9cde9521f4bb971954e1fe684b1361706a1a3482230c2a3e9b67e05464911534c915a2145393e98a7886e4c02e3e4914ac92c05bc5934af383543e4dfc15530a7b95a7e303bdf17917a1d198dc1553f6ec29a01fd1acfd06d8a4ceb650927ffb335ab5c64cb0423a7dddf6d26aff4b18e59637a2f5fd1c57ddce1f641aa0af290c190fd4a7d94873be9926b6de8675c0e26204a17400a3c88caab926d1d754db0eab1f6d6728d36ee36f5ff34fe9ccceb45a1c331d98f0dd95bf98a40e185818392b3f832b7aab63b624d106a122ae6982339d56544601faf0c593ebd28f1d002197c613f9e5850372a454bad8dd6bfac4ba3cb378852451775e384e372920278f004de0639e4b4c49380c8a6d73088ffaee25dab598e59d0a9fc953bde2b08d30852c834d5f6211b9ce11a8cfe2c91fa48d22376d8fac9b3f40328cc6b09364e8f0be24f3d83ac37e51456bec8d8c9aee06f1afd0b14eafe457b9512c8317524028cef918086be53a641b227acde538952727bad3f456ee16798d867e9618be36fa095381d390989621e871acbb7c3fc9f69ae6b4fdd462b1ca658187afa2e312a9611819bbd74f51eab2c50d50791c140a4e4a4a7cc148c44fb359693b244aa1ad442a7b2d2a72553a8b76a5f3b46e851af20dbdfd29dcfc91a5a14bd912f5091f06331f767844bb740d32281732540c4b6d033767c5d25b5597e2b2c6bc08dc8f464e4affbeac3d5bf7146d92b99bbda21ae8b72799e0ab2be635b8d9c998ddb95d69cc4d10b9b68c39a3a809d8f6e89a126a687b73d9a6b89645d23fc230485055ed3dd794e855c508d2c7d468ec2cf81dd87f1bcf49b26ec64cb05609d7db4bf4d1316468f069cedf74a68a28b40c1c44cfdd0daf3ac2873e707267a958fcd27bff5a19d07bd65293e43f31005d920fb4612a1fac6e6c9011d390f049ebdeebc79f1c4015650974e7954da66fdd03df0777b2c6f8189a8622be6f2051220c745d27abc32da5b12aeb619fb7279d54f04ca7f86216b582511afcb10c15a808b55f031cb20c130ac208321a6b9b24de2aa79b7becec07378ca44a68fbeba8596111d53452116847a7ec434b12441dd90bf89cc710c2067451dfee042afb8f3684241f8d31c380004d04fa40d988681f817906c0f0af28b0c35dc145e6f22b10dc2d1806b93fe991e87190b0269ee6d45432848729e37b2d19d7bf62285e3b2701e8f5d4d5a37f9b4aed4325590b3832a590cf1a62004e380da0c8aea95c7c98983371bb7e03c20dd89252cc216edf43aa8dfe46baad3ca6825885d189b3ac502c6e9cec45dd5c40cb48c1fdd14da411f26ed9735646e6b241dbd50c1250dc1f934019029e8c65aeafbcdbd6f819996ddfedcd5a2ad70d5d8ac614539bcb724944c497a35d96b6f088794fd308d4695d2ad0ec50cea8e639fd8cbd8fd98246e1fa2ba8ffa83615d6dfb77939044d6cbd8bf7bc36516936dc8e1dfc40385ac8e40e597849e4e88a8cbf8c5c6f8e0c0eee40bc8186281dcd26cee3a1793f00671a04df50442e2a84469ab1491ba7d2d62d8df14fcbb8690075c9b5fa70fef4ce5fede7c578c83f3390d58bc87a1fd95a4b56dbc9a64aca9ec81c4b8aaf7949807084db3d44934de8afc48730949435f47114d4512cd89c9a2b2d7c756acb1e40d9d0f26fed3d4f6249f3f3d869bcee987d8ddf636df16660ed293fdb6df287b5472bafc9a1bfcd235e9f548d54d2971715f5f3a832a99dbb748886104193cf8505a631482fd74144c87c1719fedb02aac8bbd93020cfe8d0ee9c7bbb970014d78d972e5b4fddd83b9a8cca4beae91eecdd741a80711d85d357d63318eb9487c58e61d9318e87e5ef569624744dd78f0277cd5ca7cddb95729dd9b230b7ebfbf382f3dd58a2b9c9ab19ed8df5b82002aba907ddc97ba3a7136094750e91ab787e764164e445ff13b0b74a7e883e9eb7d1430c123602a5f3ee40bf4abe8abe4bb4d8558cc5bb3195e1766fed21501f5dddf3493e9ac81ef91e9de5d7b5ca0ba3177fc31346685e6a1eb64407838819c38dc6f7ac69cdb5534c78de2ee646503e0c0c24f3b0f054dc04b24d9b3e6e02634a6c01841b141237ef79d1b71d357aa9d982a57e0bb9284f47c23748e4a8ee0587484d4aabb56d29e9833db0a964c832e8de3dad4638c04582e832866035e79dfde84565d8be58a68dec80d30f87a1ad8ac3d3081f6dd52dd35247e3a8489843a4506a1bb3d99858f845abec920cc31360c537ab5174204dcce06324f8419c187313403e734e83aed819a293a837525f7b4a8e06bf0543a9e6924ec3147b131294130b777e3abb3c819eaa665401f0855c97446726dd41f0d4f544a83b6f9b6d210f8db7d961e608e7cdfe2449c5459527ba876e76e72d5f2bdc558f3f3fab7e1beb9a4bcb9ba612791b403c8be7122a07757c630bb163175862d458a7fe868be1d0f434881d6c5339c7fccb90623584025b8c623fdc8b729e7972297353e8b32995c4699ccda9721295e1608041b723231a985ffff4bfccda49cec39b62f544737100e78033128e6108ff78fd259d331e8a3f49356cbe6503ba061e475acb9dad3c300701c9acfdf03b7350e68ab465467ff7d1d9c04071fd8143ba112aee2f0ffae9cefd77ebedce20b7d3f83b9afeb4fb771c17f31918fdf0ccabdb0abf42a4c5bef158b4c1e77a746a121facf288fe53de432de99bcb7e1636e2be25efa187e6d024b95eeeb76a1822c87c8b029fea4382b53e5e7e4bdce04032419dd782fa0a1278edd46698522228a0c75d8cb9a54ee2915df7e05d030f5ffa2025e7277e659cb880a2c7ee1d9dac38b6969f4726619bf8727512f33842c55c9ab4725fc188fc788f71f0a8302e346b29c20e6703d5ccfd473cacf737885ac5dd304301223183e9fd1704fce2b991075ee32d80563652971bee02b82d59ddc875aa20e39ae19194fe933ea316478c5fd976db9b2eb8a811df787d024ed42bb9e6c7f148a27ab64c1b5ec1d707b6e7f05c3527f945dbf3a17e39d0f5eca4846fe9c1d7726c233fb940ecd0060cbc87e149f3b9f6b105ff5ca06ac981b8084a1a13f1e986ca2754ef096dfacfac80abf67ca848e2951b7d6f77b7a56266b63880378991eb39b4731fdc7b13110d7450b3d8ac9479692e7e52887db42d2adb765b7d0edb1264c39bb3c10561b3199528617d8e81c422c07b5d7df3a423bb1c85e6e07a24d6fb84f8b606d5f1c5ef69ee437a52469fe74aa4dc2005b14ef4647a962f0709bbe6cfc41f3469cd0e1fe7131678beb530d79966e004d4164ee4005c57d5573414824ed8567e89cb241af5f50fec4f755e02d35878226aa0c17e6a6eeaa3e9fdd24e7b53b3714b979cc91662489977fa28110bd5a81a40ba0f91b0e71620697fdf9b81906fa1f6e9ae7eff2c8b70cd92b0147bf7a3d8ae61c3111640208fba9af54fe3e0c45fbf7386730f4eb4e69550a407ad1247fb6dcd6454fb7fc2a819cbad59917a9c9935f35ddc20eaf78ba8584b22a95d88ada05b04788b7e393662d4396c7ba12d41c187850357f51db61cd636621ad0d4835889b1562754623c2fc4b669b4138db649094d54e29779aac498508fadc4d86146f50b68ba42f3aac424eb89a1c1a77885c3e24d630b2c26d7c0fdad782a95ce571507b3246e912772758a97899c55013fc54b859033a17353b954abb053bcad2c5155dd53bc49581c5d4ef1b606e0a778c061531174a7587dd06aaac996f1b2f5fa45798a4503d229feccdce47e3cc59e255500488f4f00f030a30af3142fd192332e8aebc012188423bb816531c9a0ae42f86125452b5444c18bf32d417f852a68f0a1c7bd69c97cf79758a4643b4e152e9f9ce45a11caaaf69af203107f87609a23a77cfa8a14dfbda08651ad244021a7c1c0f6ba95a64504616343dbf207fe4e3660a84dc2454d15d10fd6ec1ceb6c0587c71dbb960193ec93a6da664b1f2cd9cf70f86366046c1af40462cc0640193cb7e89422368705fd45d22f48cd2235e0b998e4b8df2909cfb481f3219f9e377323c930bc300a68e8abc46b511dcad4bccadafb20fbed0e371117c1fff1e675c0848256e70b6ae129af4e3957505edebdb0604c750c262e23f9f3bb5f2b0dd6b2b2253d99b38406814497d3ff54ce736e1b3a67e57466a4eaf24b619e49b5a6eea1a1af0dabe3f7d6833c61d35716e7094805d471441d964134da542f3d3047a9468211d834b5dd806aac98f86e2dde4970edde4e2a8907b85e9bfe77ccf0ed555b95e28ea21a0d359bf6b6f8b47a9dc7075f050de596f4acb537e50bccbb7376bb2bf18a75d05d3bb29bb0f21404f5e469da2684de10149f3646c80be0ca6989859e9e915d3d602be796fe6060f52cd29ae2e7b57b314fb54eea06b38045d3ee3fdad38bd8e140fe47604ccae6d4b604f25d25ad96229429059813a42cc46df39807231c98f3ceb9e722526c6933d7c503011d42717de83b12077d6f49de501cb23f93c37c1da8ad9ebab4534933ef33bf44bca3c02b73883e7970d87819c86f9b5582771a3bd75bf65e2f57c3fb45c8f13eff293367e3c051fa23e1212b320b8dde051bcd40d428ef4c0e2085e74571c395ad1d785258891c28146170c9b80ebec734029b63e8dc98f936e7264a23ee961e859d44b449a26e567b617e0ee55dba02cecab913957ec2a4c6ca73c421230680739a13d1f32107816a8ec7b1de8ff473c808b6d9140787d8cc4765b626c4fce7662bb3a8054cd7eefb40da1efbedca7ecc1d16b45603e7e20c55b04bb06cfa503d4dc0559eae40a0dbc568909c6016aa9d5f9a489e59d9eca498b8777a12945e52a3ec244d4d95c2aa0bfbe7486069bebda379449700753812bb157902be93fcbe55d417fec8b3911155d72d532c1ad382027c8e7c0b666421e0594177773fcbef964c1c59bd76712f4e845c91dbf57269c14b8e78dd89cb5a70d65be3432beb79ba3c0fd9a18d503d3c6fa461369b2eb63dc6be7427fa4217d95a398167bf913031a2910b6436831c64c5388c36037e1af905bbfc80e9ec1d26a763703a5d227b7782bfc300b61d8cf04765f2ed1ca55f4f546513004794e17f68207244b291cd0dc98137a074fd0eb7b50577415b9e15c2d8c7d1b34a38f2f36d51e2f1d322e50cb79a986f0817c3bdf475448c799f401416907980bac66e514c45485499992f2a1ca4cd6f6aa1e38a878a0aba8d29c52d8794bede7547c04f8addf1fc55c49a664e9e1006ba22fb6fbe7c13b0006f46891b96932d7a3f5b1911940e3cd05e34adf4aa3b2d51fdc89378d665515078ab8e931d9c1e9b8cddd8abe4c5d438031f300a47c54b2c1d4583f7caf874ee9e61a22e98132162f2a4a9c4b95301e631ef05db441274365937fa38f1a41467e9ec1fe8ca19265979d440bb5d9e27eb1f4b676c84d157e185ce9e8c4f39cb46efe85b3e0329f3d3825ea0dbb4139f0ce0f13c3dbd77e9e7e0e9ad47fd37a466014dffbcdcd300ae5f45db2b13c3cc8944cac9ef6a3456cc7a054a053240f92715d66e0b5cfdc5557cc436195b4ffdca14e2ef83d38c02c620a97d241442e30c8b35e70963fc4e93af4dd6b231ece5a6cb40f0cdc97ca9b58bc7cc66a89401106505a9570eaf869eba125892cb472f781970c9df024497a69cb5db162eb9e6c5faf16b31c06a3711a05660ac4f98fa87de1dc1ecddc3caf7f414b891061e0c003be97f7e4bc976f7453a526e3e5dcffcd5c0e79ba17a97e7df5a93afeceab22d29461fc06a78a015649da9451507f1c6d35de89e7250d492af745fc0d4a79b30533de177d7db12f0dc7292170b98956dedee1244acc614ce0ac75bc9269433787f442122e402d800e2d2a0a4663f36fa17ea1df47d041f4dcff25c57bed031b73c11b013695bd28ced4943a66b5b27776c2dfbcf1d1d2a5ceb28a5dd52bafcc07f06468bb1faf31113983fc72ed061478c03c433982ec9734eff022155d643604a1c4f1c988e147493f9967582eb0727f4c33d2a85eade01bd28f04401dcc4518c0c57d8c45f7b6baade5aa9cecb276e46d399b5a2b34e2c17d001e28a7636d9c960a4cfa64274d93c0d52aa1f8f6bb7b799183e485413792ca982ba05fd969ad88e6a27ec13efc6c65147c888cb47414d98308593d0175e6604ea8c668c833515b503dbe15738c7e00ba9c02ffa3da11c4f35905723629eb2317c2fbbcc5299467c9fd68991be1b90612dc98e896a9552f1cfbbf8c7cb47a411df5b84ac2f77148433df6c314151e8d4e0a226150001047fa3c9f6c22cd49ad8dd28fc9ac59c9becd2c611c28da19d732f57fafc2bcecc1c2226134c33b8bf78a3f7767223e5615564b6dfd86988eaf541b1e9a7c10a163827988cd741d8321947c140013fc3e5ba017db6137a44daf4d9eb98c3121d39597a17e74327b6edd3c90923bdca3c657d12f0411f7bffde108c9a3735e4e58bf71e7ba82d4f5eb27d04427e5cc8eee4c0e4ea9d3986a299622fea24fd75cf7eca500be99b1574fc5b488e4ed897c6b80f33cd3956d7225947ad4397d7df06ae685ba690a15424f1cb8d0cd3a7b3674de6e40aec8895dcf388c6d006eb14b407369c321cc450700e0f254cb9946c058e6b4463d980bd957a4525f45c151c57131544752d8533874bc41c790591792cc7370f5c2e86ef0cb7d2cd5e0f1b174320e427cfc542983bec7c12f1a6796dd03a32680a596d41adf7654a98e5ca53c17463f741d6b06365acef864186a2b319eee88681568fd00776ef0dcefb5d1015c1f785c999109ab9c6172e3e210cb05436b7dd9f41db9a52651c5bee5f360d61557e0619230c0732d6d4f95880309c1ac5255ba0c01496af72dc022e3e1dd4d1c21607de91215b5253bde7909a575ef09028f59afacf29d509130a8d3d076264323a74cf585a2c69cdf1afb37696d2f955641a330ea3185621c45abc6c32d775d2c5460a813a8e0e63418a7a2c40528d6c27f082096c05a76141eee6d3a101603cf1a581bc9229acf619a85ada69434ee2927e416189b58647e2f2d0b7a56a9c6e7bd71ca30c5207fbf03e289f87aee2fe6f6d2c7626457fcac2a2c1d62715e0ba1609c0ca05abf4ce1bd39e0e0a40757141900a6c5bb4bcc3c3e3549c870f9e1549fb00006168032b36b9e4b7162a99bed16613e980c6ace5f700cacad0978091b3efe209ddea2a6f20b66bbdc6bdf9a827d236df9479a1a4708ae7d442345ff0d9743730f0f2ac2e75b3412074785767ccf331dede0d4c7cecfec249b6995fa12f407c03d3c48e3b7e64a788fe653fa9640af0bb632c750092beb4317297ee0496e069a4477c441d4cbc7410715ba02a5f3342cc0e6531d0cfa2f68362f7dc696b2740e57268031e8d87edcb9daff067ea25f1fc20f7c04720644f482698a994702a70f933711d7399b1350c48ec4f18ff89388acd0f9b828fe0e479fbcdcff23fdb650d3ff2122e34781217041bb4a2d5674416c2244dc0ae5beb10c072e23ffb194cdda2c045dd65392698a0ce958a568d9344239e901b5e2e8569d178a8a7bd631ea6db40ab43dc204798b45d34076fca301633905ffd408b24d3a304cea3aea7bbb3af0fa615e32bbc596dcd125d08b3ea20f7150ea552f1a6b5041aa22bfe9c23601e4a91beead48dc22fb9976da8c9582e214269ced43f4b95cf85e0327abe67d8e98db4889a50b23c7cd63c4f3bae7d684b9865e24b00522acf372dcc0f4ab388862b96dc1ad66387a6100c0949e8f788cc6b233ead658fc60c18f5f5d9800f243e777c89987e428d39173ef24327ad007e721704b4be26ceec77da4eebb17743aedbfd0e959f143f851c0972294771439b1a9d3aa543421208cb73d0737082a54a9255406c4e243ca75f095c5e8b839ae2ac2ec086030b4d84b352c4bf221c20f6e0885be3932605398a07d1854c3bbb704c9426ffbae0e9f68c7f61c68e4b8d9a6b63c2e79d23c82e1572318ec1fafe4c7ade93e1b7e90a03048f09dc5311c863381fca03d6dcf2e612dcc4205d97218c3f8244e7e6fe37ca8afa63b72697694cd29b9e085858ccc59dcc246e89667c29bfced600ba734732e0616bd9e09ab12c8eb6481330af2ee0e3460b15ac97cfcc990db329ee609ae784090905dfd1bb13b742742547f52fc18d916666f4217daacb1214b71801a01c683cd1d7e2c249b1244374d45520c0a503d8f06a569e246b24f3d90f47f008594a68811611cafbd33482eb2ff3d1abbef66d98070e87e78abc86bf53bb416b94654cf74bf0273d778b6792da2ba20680c43426b16d4857c0e69296248a4584b5f2b8a350f7dc087e283cc111418a5ed2d91c76dd72cf0d4ca4218ca9dbffa8c85767a2148ee095564e8d0d55fc3c676dc479345f7b165b3f57d704ca6e4ab95d7dc3d606ef0c2b97bfa4c2bc236128c1ac2a1ea991c28d3307931b0ae1858c46108c9546895d4db3bd53cff5e2992e3cfcae078a0960e2ca6467172cc577a95909e9aac96d2811d6a2951d7a047d4fcd2779673c664b726e591e4eb239187cb77b2acde664d53c17488f81698e35e2ed705d01b492d62643771c9947f76fbbab78559be55c05c5ca314a1ea7c629f9c67bb6966daf764c13ceba15143ad7977ad17da6bb936f550d7e91d237725765f2a129b8ad6bff4d3d0c9bb3768dbe06aa9a6f93be7f859ae129882f343fd0c36cd713ea3a1d786e2415ec6cb3066e96d76986361d1ab6198eb3bba1dd66e015b6ba82e01d5ad87cbe619273da145447904843fdb92383d5a4e034a999ba256f11ea2211198c8329fd545c69939a196544fa09678c327229a6d358982a426aece22f377e9232d8735d428ab5fd4a1f5fed88820ef968a5ba66a0bce61a5015d5950bc0adc2a93410572473df28ceaf3874dc4ad1089c17aea169bd22ab02f86badfe287766bd9c041491d1efba90c1cafccda7968d98ec7575f30486ab03e125131b6b164591ca2fc3d0977b8906e7911aa3e5b6a15cba92da255044344472019003d58ce9c760866936629d307a3350c05fc8f88ff04d70e54fd6f08e76a073a8949c569863bb14b73538d41761ada121bc7b8f458b6c3b13185ed31b81a8b919087ce0e9aece8aa0e5c82cea89853ef705aa6140a51eebdc15ed281d444da84f945b3b4c6ad6898313f9c9c05104480f9570f911cc79e5fbae4cd5e3caafbeea706970414fc2b73238e013a55591e29197112d96ca82cdd5d71e57ee766b2bf70ae60f01971827b1a30f6832e6aa2ca551944e0f0da9d43dc1b9e2c6e0c3181380c1e7059577aa1663929a846b1e1e18ed127e18e809932a6f6931db5d37d1fc0850636b9d0ef0ef90c9bc9a83190c378b567dc32ebf019a384e1f8cc322037d0c4fe0675631eab1bb2fdbb8d24843e5ce486d898a85e285a79fa2ad13d02e638c4c9db106006fe48752aa49e1763328c94709353ea5b64a16882f790c3280009a4b107ae9ba8fa652f382386e4b34c7e6df77f55dc35c4b221ab48cae8bf70fe6649374d956187ae5c29834222807600eed5cc0fae86cce3b51dcd2c6b9dd6df00d06cff4f4e3c57ee1263b1d0354afb32724948fc2f82a61b1a638fec4980b70a9b6d90f178ac47b251c3955752c13df5ab2a610cd435468a8802d43b4cb31e31f40cfaf57706d9f1d8437c0011ace60430c49580db38f11a901a13dad5e7398d8b1dc68cd80b48760e3377c5d08ec24574cbb7372c20056961db5cf4f7bccb124d464ad76e033b72b8f9b6d5ca69aa1f17a4605edf7378c5e2a1093fdd85221629c5f3ce95addd159c3629e0b9f629aa8415a116ff3c649d0aaaca45c91e162abe25b70802fc36f0e6401ef769881d1052a583da84468796069f169f934f04d830aa2cd51af608664eb3511f166bf6957c61f2fa8d9403eeb48c465c2adf9f79c8d44167f94e35301e4438447c8b5f0d6e65015423fe16852f7082b5231962ac093d3cdb1d735a9e47b1443017dbc9a16cabd1e06814680c9247efc8f899e9dea248f95c9aabd78d23227c02438b0b7b43ae56254b360731d10fe6a11364b193695dad8219aae904ba813f638639f4007373cdac4167ef60ed76705bf62716ee83a3044e153547de134db670b8a3a1fd15dc5dbe00ab28a5728d58286bb6df63bd73165bef87f20b1ec53474998cc8b5e70225f22a61cdafbf59205a925b0b21c6fdcafc6403ba38bafe0d3a474b32453bac1722b297803cff6dfc66510f5110236307901fa63d910d25deb3cc9b6542b070c975fb232cd568adb0ba0b2ad8d617343aab703750195ce0a29c1785e1772317deb1954442afa5aa5b36c48700ad5561d60f66ed817bd2dc5a6ba0e74f99bd6a78d37f1d29e2fa6adda6e9dc990c3ddcf5154d615b82fc57e41cea237af93a2d6cf5dedea54d43ae230ed7554f4de0b5817457f416d51abafe3a26ee4be7a3b13bda61cae6ee7a2b6ae807d49f40b721595ee7456b4eb1750b62cf8e5728b66424f6b0607a1dccc48dcc810cbab3fd1dbd5a9e8ef735f7d9d8b58458e57afd3a2bf53c0eab2a8afe82b7ad5db51f4d68d0074d2a057ada005bf4474e6a79468392b89c9bc6a252d794b93337f52ad757969cccc55546afd29bd20c542e752a9486192cb8c4ee34187bf645369982712b3d416c169b0b5edbfac27c8506854ccbb2b78175288f397a704d01ce38ec7e0eb8b58c134cb123502a41c596823123aa668c185f48c1592b382966483e158f32f7894971da91e607807c845f5347a1c0cc5a261622595c6c6f631e359914ab9a8c642ef44b0a14a21bea75964e841a063887447291af279c5b98493e32acdf398fe5dabfb07355e1a2f2db587093f9607f68242e0d9af308a1fd507215194a1ca63acba83a5aefb7d654e6994fea561c5c6b36b61c7a724729cf928e5dcb364590945ab491c61e8328ed5ab2c6c85b3418e3eaf3eb9d689c4b282dab93f5a117a8b7ec1451370f9af1dcf5506676adfdcff3099d200fd1c67d32c3e2c85547580d956b9195d1f09ef7ef078a3fc9ff807ee18de89cb422f28734df487e0c7cf2dc6c49dd00c1783147c2d2a58c8ee824d0c28ef5b9f84accc3bdd0d84a39f2b68d8c06452e39e24d47f034c460c98dfc51dcdd1f34b36a01bbe6f0877270abb4bf463bba8bd920d4ae2cf3460c2e9198dd0ad795f83b7962192ed93447664810cabfe24ce7708d237c50af49ce68746231ffe6f79d82be0388a6f801a2addc3005d87468b3cfc90b0cea943b46a764a197c13dbb6b432d3df112fa788f5525fe2a3f9f6363cff56c026e1c5d4ccfec5d5a3102fea0fe2034d21e86cf0adf289e17f9b3fabdbe2ca533786c6e4609bf404d2a2f108586af9ae7d949ab60e4e3992045ae41d067fc7f39e9a904f2c74df3fe5f093fd3aa8a4f071c09d456037eb3d62cba79d28f0baaa7c7860648d9aa93f908c540c81729722f542d38dbc15101a22c59b586bbf62620b6fb60eaaeddd95831d9654a6979e30c01f0f8c9d32c56df7918ddbb1231b02735cf4de5fa4b68d16a1964cb53399088e41cd548da08731eabbf3d8e6e9fd478ee9faff472b46333489e7621212689fcf7a7d1fbd0866bf1080f3709246e59c97859fcc2530a8de500e11b8497c15149ab1a95235c7ad38aa8a5510085b6b1d5f3f1a81ee07b798bb4eba9aa071029fcf383ce01f98faa9cbad00725eea4b8d5385c6aae9a30fe33249f3b0cf919d3474e855811b988197784e69c9adad9496fdbcc96eee9c6ed20482907b6dc4c463449ded32fb2f9e541c75b09b89e064585f93ee0b74c5e70bfebe53c4590d2f8113a8542eb3d3a3f7fe9df36bebf8f3afdd2d8ac775a2a6c46d38885988a23988958892f195bfc80a14d37566d2407e8e8cfecf25e1582d2e7c5545796d5b00ccacae90e96f92c9ffd935b5970b2a357eb6436cfedabd3fd3b4ee32510a99178b75f9558721e14ab6f0b317392ab68dedf123d673ba64697c77b73d2ccfdc312da0ed11a0a5f3819ce557c41c81d649b601ecb04a4bd7622028aa10fe8a0dfd283f79599fc892cd722ab3e5eb1815771f5acc83f6415bb679a45fe63538de12ae5a846c8bdb65fe661909fa1a318bcbab25d80c9fed6b17d8a0d13092821a54b987680c2f55833b96b4ec3b4b1b940b57357fbb841de46c2ddb33f784d51b2ca5b5140ba083e31c349d4955812686b86512e02f8a406cc1cd57b67ab3ccaea410d3ca4b3003594ba1393a3276b0b7ff52c5df6c6cd44da1a1ff26dea3e7969a797779418dad10bee01a267ef4e5a026484692282d2884ec022f43dc4c2d9498e60544a265b832d81fa283918d2d008908424082e3a700a091e6dca1361040270781105847c02d8236031640a85ac8c41243f3e9bdc0b3531f0617401ef6dfe0b52c736da281e28459ed06a5c86dc1177f282c171a6238d16a9764fa229aa4e2f5db1df2eea474d0926cdbcc7d7f1748da8e98c4bbeaa06658ebbc3c790a692e2cf32ad911a3474ce539c915b32e588674efc44a21fd450ff6147b827891474bb911612c9639b8320e7dcdb0ffc716a5d22be269439fbfc1f1609d6be069ba4bea6ba2f24d47aa3e7bcabfe57a8d51e2b737497e5c55d92908bc848fa3c43f737f31fa91e040ffbf81ff543e78e8e88c276e8dda32b4426981f0c390655928499502d4f777bc1e058083fbbdb9caf1169c4d29f8ceb33a4e24dbc052c69bbb922b1597abe87f88556d7480796f986087b9f634405dc2e713ecd21fb2940b1da90562928ba81bd93dca411fc1c7b0cf220a0c015e656aa1a8a050c7e5575b7d5851d5456f0c8051d52ba8319bed957a8574ac38ddeeb1172ecd44f87020d535ad4ac7075089bda86b9d5193c5cc4ee8fc9b5a327c3bca5f88c6fd96e6890ee9703a4dbcde9dec02014a8c6a041af4f803ae321bf6a420ff4b1c6242d44e75fdd3b0b64e30b3d73004d4b925442dee2c12103f2a72366ce22a98ca9ceee9421135080c0b9774793e2514874b2237d5771c7c4ed8d8ae41b9f3fcb5da972bc817f1f45c2b90f25c5640fb4f4195807ab63620315be4602ad9ddf410be8d8d8e00b75c9d6d0d47da5498568ca1a2f6c814b7a15777264a3d168e71d60e7009bd54910adef79c367a7eb39a67fc1beb990755ad804c67fc7d79e88e544f3228f1e4a6223f425fe87a8e5108b9b5ef81c762259ac3f1bf592f5e6d44f10f3dcd8298f6a5390fe1d7c1893e3f75445044966611169365c878c7fe6be8a24e111ddb4abbc8168837944a7f17a23d6c420b6c74b83b810308d7599bd53a98406a0449eb875f4f2263f60e4323b8ae1b795fc761a53f3c7c717eda41ba8e9d8d58c17b66b9acded34371e7775d353cdaf5975cdbc31b151a87565daf264cc8943a8577554c24792304d9ea42587131eb139fe371c3b602ce4ad3e38edfeaaecb7b248285ffc5ac5ef3c240c77ebca9a00fcc676e3b900425eff372f734e61ede7c11bba2b8173a24cb50c6ff95ff9576f9f8d98c75f40032777333e70876afb5c590ffa471d7e32f795615005e8e2bec1b1b46977062c0597fdaf1bfeeaa2b46022929a3224cbe1634ff27ab4fd1c6e21e152271f5355fa2d950b7c72c4cc08fbc46f1b7e1e73d828845bb934d57a13ce68cc22053f2cd14710fb3f729835b25774bcfe162e291ba2b8e1b4caab7137676e2fb60921d9ece6561e530a8d2c238611cc3369ba8602a9796b565f35e33ce65e9762fd402f008389cf284030b5f000ebb867e497f8fdcb9a4877ec9070b02405692ebea015a97c517b91df09fe6e8531dff0b3f0e0e4192f3f4f4cce00880c457e9e39e5406c8f4a529aac4145c77f72e4344f6e8de7b12cf5a23a029fb98509cc4839eeb31d7edfeac891e8b8eef1f327d4d0b921ebe28623cfe838f4c3494535158a524fda55db99f88ea31a51f7eece94713f844854e981a9160dc3a8bfe804fc0c8dacf2a385eec727be38fdc8f8b2c93edd4d1efc45c15e8dfc5765e23e723e098100c2ac6f377af122cb658af4538a0769b91925bc0350c042e02a0951d3707d40bcc794ba7b42c02b2e3ab8df04d2b8e405c9d3689e12cdb2a4b65228d25214e298f1bc3c7ed41970b661de2929f9e9d6e71b1e0b82b10857c891ffb64e268a699caf039a7215774a47b829c44575a923856040e4a3128dd15ba38d5566497040607a97e44044f01618e8c5cfa1bee7818f1daa9d29acc7f8ad405acb2cbe735ffbdfc385111db1df2df56e0cb097b99ac7782cca64908bc8a6db6da56f338e244e93c80a81561b46870f9951312b6ed74763bd01fda9123b09c10c11f67ac4f13e0dd13b6321693e584f1f19e547a81fb74b39c38bc32a036bdcc11676d39492593edd45934a715de5b1090ace223c64b4d3dfb7f4569e2112b57e347d08f3c04a90cfe27efb80c3b18b7b27cad068c0307133a11bd00fbd886747188edd43d246e10b0ae019bd27d70818aee4f29f7838d5c734a671191ee7ae0ba1af29f12a174c5ceda33b7dcb3dfb636d224a808f67fee633331d7f589e261df889599be33618ca106ccf964bc0ba2b7909df7098f86a04699166ff2dbc95b9576ded9e44ce6a0d9f4a6ac75a73f4b271f06af6fc946d8d3e08b588c79192466770645a40c553ecbcbdd02a423aadd343a328be142c24b990e239496bd2ba4fa79a4def82b01062901761c035d1f0fa0fbce725e6fd4017f4eb7bebf6409e0c47ee7203243460722419e0d3b32395d98958684118c072db6608fad188b41b17b3b17c7ae3239d2e11a36db716e15bbc1973397edd7459ebf0751a109a838909295f911e41891db3142e72d946f664b4cddb61eff0da7136e001ee102f135fa7850edf417ca95a0b4dcea6905c1fc38d0b6480f42391861701803b1c9453eb0cd63321b4317c6efbb812a7b2ddff72d97d084dfefa52ae015a7413ee8f0e07b96748ba4259edffceb1b4e232a6e801cf71843c640df22d57dd60b54fb3b4727575d73d86c650e57bef796b1698f858aa1863cf7566d998d1a6930127fea9a2216741482ecbed6ec3bd7b55772166ddeb54dfa04267b0ee965d9a55160798ba7d0b6d140e74c76bb8914a9d39499780a5f76ed1e161cc33f05b45ebb8c6749a46f0db15a53a1cea9c25149d5cf0092c1e359a5c7d3fe1fefb9c8b13b37804628939b29b95de6a608c62181d3f7f78979c7be722abb65618e9e17790dcacdce999499204b26350535fe7ab340f62c09d00815a99fa4df36d31a2c1b2bec5db47726a3329094cd2be9c3b24d4a35251d5471454479cc44f273173f4a0875cc4827513c61f355cd11f4260c215461e10fe203b3bef2cc98a2e853e1d6b12bb6be39f782f7d30e8a37fa128d72b3e881fce14d7dedf51b11092f4c5c74b0e60a6aef23afbd64851a2d86ed25be6cb1eb2fee5f955d3fafcd4d518816d94daebbb681f4ca85b19957a86af0920c5bf16acf938bf8ba4a0abb111abb1fec47dc56276e7142742c7d831e7b16b9d4c78e18081bcf2ffacbf1cea66b0101b39c7cab16c7e40eb38217222d9536e606eb2e4dc5c03f0eabfad0c320831bfbd60701ed1e37af4b310556142bf6f6ca0937092ab2f4c88e0f21ffdbf2d5498cd553af48fa4aea17beef970c2ddf650ad25f28296a19f8395d248c63c862dcec5b8eb1a1fb8d2fd3d1ded2266da4aac881b9ac507de45e859d41dfd97449050abaec2718da52f5637f8ca6e15891eca1ca83370f59017b67578cccd60267d9fa4fe360edf7bd46afb172bc985266d04d7985b337de1d4129a549edeeb2360eab0e375d3ff9952ad3e6e3c4a6b88eb45658ab4e826642b594262f792e074ca72cb6dc5f667c70a30088ec551e56acbd71b37f0315e25b55156a9bce1abd8c3956b35ab677aaa505486b7704683f6b7db8ca66e72ef44aa11ddafe2c93fa615a6851c7701b4db301635d571c5b4d8d24456ddff792e9aa5b05cde2b51d639935837105d97e01b3780e2c71240c63886010237015bedc39e77bb4fcfe4f3c703dd65f2fcdca1393e35ca2a224e8cdaa3d97b112591dba9775089f875fa832fe92f1c0eddddf9c7dd0818b2a33c0e01c5731a5bdaf6ba3574302faa18b6c5b7820f5c117403b875e9247efe2e224ecbebe35ffafe5ddaa7349c70a695f9a52b68641ef8dfbef0b73e9f27fc9373262b5aa85c3c4dc12b9a3bdd4f20d68ca35db04c70ce84aaef55dfb289ca5bf0873768adf8cd9b557c270f5a362b6e2f6177e3f90dc8dd105baeae4f5d5b1e4713e599ec9c90360324a0c3a5fb90352163dc7d4b584d0bc323d89e2308712995ba35ac7a0cdfc9a3baa7c5e7d691434665f4a98d3ac493b23ad67a92d28618b6605910c30a68785ae184baa750153741f2d40d989af951c089a9820a0ee82405c777bee186b7ba7d62de4f46be94651cdad3c7c548dc122a6c99fe59fcd48a3bda7634b7dc37b282954996fbf29795915463ad9183c056e3c752f0b5edb91f5175fb82bf0b243f41fbce38b05c95ff17979da0446d5875cf7a573ca620d408f7d7a1afc5668a0640effd0ddc43ba4edaa502a751eb2e853e5be53ccebdd0bed293c27de6c5ae765b8eb4fba22b1866c7fd6c3636dd42b7979bec475beaac10ae2b1afb2ad570eadfe98b5a774882fd72d700f7fdc0e29d3c9ddb7da568b30acfc853edecad5c0baaa0f5e75143d20107368b5032492fa26602eb29dab260aac6bb30e87fcf93e3e77793d56e9100e598be80ec21586c463c8b490ae9b5790c1fdc349c642f7dff4411f318f75833934a31f9cf996e4c222630b3b799ec02cc1d286574c60ed211c3c94a5e906fe3bc37c5b74c1b619df5b2792b865192e8ea20530d5e868f7b247b67ed374eafb8fe62837141e728ae8641628369abb31e80e69b32526d6c70da4fb5d85b4a9b90f0dfb3b75c0d7182083dd5fcba8de558eeb65d4e82528056fcbe44706746b8315997c544cb1d89ef5c40e7144c47c0ed531a9dc50a5a0c55ee942ea45610df27e24a05956ace6f43464710c7e528a9172adb1cc890f082917185735ccfcab754278a525d22c2c97c2a28469cefc923a65246af70bfa0e4a1fd5f8ed2efb32d1953f14ffd6a5c9c8d76f350076d16826b7822ac2606cc3bcc3e134b16552a1b9f220a9cb63d7cf16e651d334ff4fcbb66b219ec20a01ba1ff1f70efbc2ee6661ed8ebec2cfea809b74fb6b45edd28724c0f916f25a013410c45fc4b87e794acb0324d89fafe6060fed547f0e75e0c7c49510c1ea6ad71323558a17f9e4d1c110ef2bb3155c54065729a1e7720f45381a95a774855ec9d530d86d242fb5ed182bf32a25db9519b24a5ffd8ac3bf9770a75788a462117761092b55c99db18608ccaeb56a859850250afaa0e2f5d24b99e59b6a23bc588548964f65bcf8bc03965620000e23e814b83859e40c1eaa47481775921419c6bd7d073203d1b31c575a3bea34843a42700e965a58dd39485c72fc8285b2cda97bf588e9b3febf75cbb090ae35f9240fd7306d1e2d0a3d4b9335c1781533cd39da2eab044f8333792d1a502a86bde45558ed9f3bdecf497bae78036c33db2aed59ffdfb17468e6f86516ee9f7e15a708397effb4a67c1156a70ff6c008a1ad13fe0e5cdb8866a43762055f98bce3f7f6c5d667ecfbe3cab342fe91e5de91fce5f3e6e24787142e42e6260353301c7baa1e62dca52db8239e30e0f0481477104102536448639c901ed550e44732bbd3dc6912dd4f9a8b2df93557d805b1c461ad21297f5ccdb8bd950b887d444c0bb8ef57c72cde09a7a12ee646f93c3df32f50275249cf00bc068614c1c477e10c0ef2126404cb4100502764c0ee764158984f1650f1374a71220e180ae65d45c2b58dec38b804320d449e12e9bb38f7c7524ffcf4c1613d465263ccf95d4e23978ba1e1497df3c5ebfafb88353fb568bbbaf23fa6bfa344f2f8ca9e8fd23d92486c9b17d278e9fc71460a9bbee350a87f6317941b04158aa46ad646f31b5e64cbca1fb5926a5825ec44bbafb0d75fd761a807cdc37574b7efdd692020c9cd69fb9c3a8d38cf9a76990a22a0dc9b6c224c77475daf95150a9b1ebcd745bebea5c55d44f8527a5b240d4c38cd0a545359266742db3496ef48e0bc71e5bec406ef689c1502125bc3923de7d0e55924b7f059753e10299e95f6f9c3cb4122c3b8faf141b520b10199196dde4df32dfd9c760375b3ca939481102c228bd39368b9af0e379d952438ac8e20e74cc1c090b459d641e88cf5e4fd37fb37afa893a297415b913256fd661f3c9d44c3f908d1be4317777acd6b79a504de73d421a1ed10094bb6e9e56810af962ee8c60991fb7c275b2cf8b758c15202e13a31714d7a348651f228266be537bbb09eeef1a0d3e58c77d2cb67b9c44d7a32676cec063e0f3860e95d8c5eb90490171c1fb6698b2816aaafed10083a20520f4d3f74517700b3c31d592c109dba97c99e50e4bda35b31e4e63781f28950570162a184380c280c0c9810bf7c387bcdc8ca40aea0856cdff91e02c8ed8b4638d88baa9429575762d8c1357ddddad98d7bb7f7302c289e4642c387310e98be81b067fd088d9f992f8f14ca6b788979cf3062e5b9819a9d0edd21387306beca24e9dfabf58861e2ffe5b1432716f32e0f698961a543dc89e2f85a058408b88037ca42790d81aeb338e9be331c2017c935af22bb4d75522120f07c1672450da5d97f68065c1e9e7d28e64d46a3fc8262d8e413e3d01d54c8c04e879e5b2d399ab002229d48cd8acb03a1d6162bac2e5ee1bacac8cd484421ee1a9093986f9bd6821c8c426d82e8bc76b66df2d22e96200db2b9754be9d4e5485a67659ac3f40e88e491b89d6d5160a5712f6df0c691a28a0a004de098ae74961926d1a90e8fec64f685de380205621dfa2da5e9602a2251fa17fd968ade41685a40e16705a0e3df42f38daac2685be940909147399fd7b051327be64124daca7f9aae3000387cfebf3106f3688da870db57d561ae01c8ff8ef49f4141378b18072b9ee991c7a594854e4280a0c11e48302bb5edcf4538c9e3ff66be0afd85449c8259d048a90d52f24d905498c5b11e507bbc598a26901d13fd33670a71355e9067b9d08cbd64f7c70e1af666f7d17fbf22e9cd5fdd4bb1d977c95054be7a73c1532b9b53bdbd98eb16b9472153bf367b0a0c44fa57eb1b3f60a8c5c8a8d623680affc71e79b289310ba392d32712d731e89d3c6ef0e1b5ff9446e4ccaefb15b43baa1815f43582b199c59bf3f9a36d64bf453e04ce8ba83ab0c97d44948108f51da882381e85abde7ff26ab0bc7d0d3de7ca0a86d411b04f0ad27338e854ddd7c405e86fa8793e81e89c74cf61b2a3c0944cc9ba26832323b35a33f765316308670b70c236ef764f4962f93c74fd7f501293bed0041efc870a4d225c426d10f571fdfebf26c7f61fa57b5073006446669eca4cb39a61ab92c767c8069909def8390397e4f1910a06eb4b34ccc31bfa2e39db04ca859c59446f9db7b3e58973e86e795ff92537b0199c170a81b326f0bd88c8ac4b213f8cf1046fe6d0785b38e043f4048621b0d6b849461a83c51c98cae0d5a1ae855015d44f57d58712a61e071e46e2ea10c4a914e7950314b3309939aa2c7417b3d9ee523cb3c8720959d1f1fb9030b6c9e2be5d522e3d42522ee964689a4ce6ef97681e8ad7e714f534770a3f28afd002d5123358b0e0b9230276b3c9e74f71e2fa2403953eaed16fbe8c82e8e3721df479af948cccd4ff2a2a817faacf2d876a2d493181c286d963915d08d6e7dfd4e6a3b2b54806c7ca6299df9e28c2e01bfa745fec0d20787bcdcf2dfa2dfb9693256d96d178ed1a6d02431673eb5948cb7c34bbc1bdd0064670317f35d179538cfc3828462cf08b6cde7ab477e1f582df88221db1626ab1774ddc560725f867fbea1b0f3e6dd1e1e81a357be9276885a604bd43eb486fbfdf60099aaf10d050b2fbba2cb175570f22ce4c8228b685889adbd5148daafefcf996d7215ef10f7f11289c08de8b0d6b123d1b0b69f3d4b81cd3a971a5e43b9b1173d1709e35a1c04dae47d6578f5c15a91adaec852848990e47f3ef8dbf9819104a60ee44bfb4e14697154718c6d125fca2891ff110f1e2621c002208bc0b14f9ba985f54f3e5dde41df5453b4c3a06fe979fab73e4c26f98fc4ac4cd8d8c788cf2e57b0da45ffadd1045826d114f5fa4722d079e86277ca348f65ab1e74cf4b597819d78fccc3362d4a83f421df6338537ee96e919dbc61bb3fe0bda48c75a182fb48d2d666d66ba47ebae232cf461083d3ed2e74f996b77ccdebf7dd1320cff0312eda9edc5b238af3edfe7fc603afe2bcc6ae64d2327eea87187b5cab36f00f25c7e02392796cba22eb99b25bb2dd846a04c18a5454dbf08b9f6abfeb0835dc33257b980d9c38c06dd71ea416b19d5021e07b688a1c1623a005056f9936f925025b4b98a3f1c7333806cf6d744f78663bcd734a96cbc0a924d0328334ee35a5d0bf787f0e29819cad42414f8883ee0f747951055bd59a8eb06269b0c65b359f6cb8b740725d69ad8dbf3b24590adf21b7867101e97ca787f5e99ddcda2cbe926c39e956b05a08e6c8db0c79cef15d9e3e5d9f9eb18fa005c3b6b47eda20fba9ce46cca837ccdf54a5315ec18aae654d26a8d84c4688ec226115ed6e53bde8a1160e3711d5fb488f2022d55c0a4b45e19d43fe55391b9f57addfe69e2d6829a9c0612c89a6cb2e7e535171a2daf7c9c698234a264c4d8f0207bede3c0ba0d27027427a93fb69a320590a3eba0d34cfb177196e6863285f83c4b0f13d1b4cf297c4611ee60daaa013340d2f822b9db44990d1d1b94855add207204931c37827b3cd96d68cc14ddeaa25d6b6230b039e660be623559d657de1223b0a387b80ba082e6ac703927e74f419ea94778f7592ee3f4367a51d34c16105ac01e826ac4cf6dacf1086eacfb72399a92c33e2bc1ac421b5a742808c993995432725c8ef3c7315f8357389979182b46fd4b4b2b9bd872efdb5802164c2b97a8b77959b1823ebd4c155508ee5a136d287355cf45655f4a880669c6ae98a52c080de924f59969f1104e7cd99e010755034761e6396231625f54c790c9bd01bf1737e363ccd765098a94fc77e97130f4ce9b1c2e86be87173feffef41d919c7f6e2f0ab4b82b39b7e4c4be376917ed5448c79cf5ed7bd58166ebae189cdb2b255cf0f900a44d2a3180150e0d73158b77d8d96a3fa64bcbc346b78bcbd7cc0b3e7c4454d6366905182fde27a523f2da85e5e5489ed66405085087bca4cda09df6a8a53171fd3f5b0132057986642ecc5c0aeeae51e16c265cd24e3bd81e55dcfc81aeaf3e03fd41664be8705be655f1ceac66e867200a861d949cdce43c8d469bf39467539fddb794310f6b16a7c723e70cd198072fffa33d34c8eaf9b32ab87953e80cbff2f3d6a13c220146ea0c1404a97c0d441231d1a79396c76c672b2caca3153e2a4e1a4c1288122eb548dd876771077c787ffd26b7d9ac1097420cd1c7a30c70cd80e37e076e4d6f97d799e738c68aeafb3ec38fc12e40fb3400447217f12de765ea9a0e8c6f83d4e45960b505f0a6b1c368ba0a69f37276d05c822bf6c4dee66422ab272407abe8b3ae4e57f33c42503df376964410e93eac374ab3fe3bd92c5c8da23a4f79c2f5e70dc7d66147fe1b60976fde84b885f5d8aaab166aa42dfec536621f9cee76c60b0eaf70629393c77dc52c7ae480cd82f4538c22b242f99b04d15694fc2e33ef3bb3c15a5c5cd20d1175c71cd2c474b4252b5b0db9e5a29d5a23031f95c4407f7b5f84e2efeced098daa348048ba3301496481e1eb0bf32e9c2ba1ff35e333f2a455072c439a6a01fc250c3b8196c700cdc89647a35dbd6d01af0b452039ee502946e369cf16853d3b24d01d20ada0f65b21a805432b0320ed0e0a60e9d6f4de54b1591bfb0f7b3e10b6046b145e28160246f27c2fcaed7002b39750abebf6abf2878b804f1d411cf73c329fe5c3edf53ce70bbbcdddaad56f67ef03c29962e5030a0e6579ad56e397e57e5c528d258097b4a99630e770493f80d8856b9b007823967ca2d3068db3d4f4253cbfc93fdd5c7bd42e9510e396b2fd60a5a4eba6be1959618eea012e696a775054ecb948cb31066dedcbb210b153f1ebdba4a70abb795a842b324137918e5ef411d41200d7f1fd58bcf1d4ed796d3d0003b9245117c80cb1af84f83ce15477dba983f38ecc976f7d7a095ce9bfd279559ae57a4b3a5b498384de22c6b7057b0970249c479a5c003052fd40ed4778f6f0881b987e0a5c3486b0212039df8f522a8dc5228687978108241d6cdbbe83ae84a825bfed95234a84c30b076448e0e11224f2accf1f49a4992b15271698cd237566fbaf2061fadd729bd5e3d86af352a3b73d58dccd8171296c78cb26916f5ea232da438cccf7672a4a920bf179f45b3a934313446119ef286b8eb4873932d545ab97453292fc1f72cf9f360dbd3838c056a096aaaa75a16505f52a23127de6fb3134554785ce0b23f186c9b50920037dae68d9e816a01e117b7f950b45c2e1730c1272ab32df13c532fc4e91b1bba28e28f85dd026ab52b4447e0fd20010531c490f2568837e0ca164f90488369d06d0058f8842c57ba3e763d06fd14205f98e9e12ff209ee0aae9ae60c6ea43fc2b6c3e3472c927e8796620825a3551b1cc07ad8f96e25c2e70ca806c6ee7e6894b741fb5380a492809dbbac36d4614f4679e023c5918f393787d2d6f75ec5537f4473b57f878da2b2e9a0981f91d7e8c7b57ad6197df2986441256946e0b454ce59dea22cd8fb9700ef03b697dd17a8b6e042164434e4b4624d35da96e2938c0b84507e40490f30a93361533a3b9808c4ff618ed38baecd00ada596e77d1ad215d72745c2ba30179502e8818a66f2923ce3bf51bf6f5c4cd771c714d08c440949129b18d7bd830b2282d45e5074c9aaa36c8e92493408fcfebc5c689d80b37c41e55915f6616ad996c061b08f7c83b5fc70986bf1887cb47626acbde7418bc03e74f6502c162158b85f960998c273219516aa5794f21c91c35b1e01f6bcfffedb96bcb4cae01e880a77fd47ff0c890d8b0ede60c6dff49acdfb7108ef64aa0173e77bcaea6acd8bef3fe6931e1275efe3494706bf8b390e023d7f6870c7748599c20806440d89f1b1e5611d36aa5d1a2564d19238a0e455e4c9da70ea7f324a8d24cd11e8e92c3b160a942239a1f050ae833acd9ffae9b29c0d636d7e7d0904149f8e8e95d94f1ed621ad7a70a605adb45ab363a273113197884da6e928f43aae85654d255a402e36334d7861d64e9386845773fb338d03ce02fc3ab0ccae66c7bb85ab1036f66ce9c29510610bf47728cd9be306152abea4fe173ac9630888d57d4fc77267ecfe42857b6e66a8373f177212d2b1ad87ad825b1a2681c1a2e9a2134a3f260365f50d784f1d9f3afdf9c39d363731ea0b06a49afaddcbc8819875f6b832afb34270c8b7eed73fd2cd38ea9c962e2d7b66d51cdc6f0bd70a424866e191751245c380eb2cdd88ff89a4fd0bd8f0cb7cf6e73565335e22fbfbfd780d19edcf432de058fa152b6668b09338eb8cd9864cf855b0c9f0232b492fad8184fd83244424ff33d489ff371cb6683e9803814e60062e2dd9fd10a14331b2bf209d2c3ec5a93496f60c151a4c0fd8767be078a2418be9b35c5f49156e40e5db8b70118950425f270a1dac3aee53193968d06cfb11378552840f30849ec2359680891d575e7a9a8e213a69f8599e7ae950d6c5b1d660eb519144988f6ad56da47861c2526526dad7491f8303624d44318c7d1b0a742fe57fbc1906d741958d64c24a578464de6c845bb5c9bf8155dd34e2fa362011ba3d3dba6234368d97635c005361824cee0721990c0ff17a426839e25fb6c650622f548103d8ced1ae7d00000afffc3966c9501ea8d1958c1064f6b99f191dfa1b81b7488d52ceaafb41dd2e056b87c4634fe3b097c591db45fc500a567f0644e3b4b4fb5d66eaad2075d0d640118eb8a449973183b50a046a3dca9ecbdea895091970de2f6d89c05442ce345046078ff48480dfc2ad05e072603623be9b77d198f628ab1bde2fa66250ad1f85ee781210c4bdc48aa2027e014b457ebbf5c0a008865b50148c781d75f3cfe38070a06a1478938c7fe381ea71737cb57e593b11370787a87ab50e53db40989c4c43bd327116323c7724577ffb42ceb337d32d37c37d70def2e60b551bee367334c0bb72e8fe58da5b212d9b23e0cfdd2610fff07c27f9e20b931d7bdde2c8b5baf8b9981018e39d3f4580fee817cac3f58dd6a4fa8a53440a7bbe963ced6a073ff2bb613b6363dfd8add7063e2c94576a09faa9ba98931a7e7399a0d8be33f392b76d816d6a2b2f1eb4a95d8573fffd6c2dedf2f5bd3bfc3e3a9d3d060b7f61010b456bb697113cfc729dd125c47b793ae9495342eaa7a9deaefd7876abd2c8ea389fa9d8ea1cc16cd6ddfa6eb8ed5f9c8487df8f94180f537d6170ef297981e7dc92d3552001949191ecb0fde20afb00d860dfc14bc61e6bafc4bd0e94dd95a9865cbd5732230b1abb8d2dda71efa977a4eb872fb7872450f2d177945dd5dce45b14641f445915fe62f5acdedf4a240fe1cc744c31be8397b84c3517045616c2215bfdf8966974ad9f3d9cff2ce7e62116323052d6d4cbf50b73443fa2562f54e4e208c8db09f39c97b48612168e916344ce399bbd8c0e2e6b68b349dc1c10239323381b4217ff4ac45f9c08fc6fcb3a3bbbefbb2523919207e3166f56aef1bfc93f97da7e4d67824c5c150fd57ec6a25f25c6ba711be130588b8af6c9c77ee6ac5ae34945119b37bc698b2bf568a5d87bd98a6f955d46620a71e1a7d545518cf633413104acaed84dc5b3ab54e044e561ccc5da1bbcee71b2172763eb70f7a482facd2c0177181077b1186aea412642c292264b36a497ad9683c86ae6cb127dbc8c587400d6efa3d76dd237a285f1429b4b7dda9e88682908f911ed9e4bb8052711a146c5d7a0efacbebddf540f3b0fdf876dfa3cb78411f1421b6cdb03c928712d41ebd1b651f9b83794130862c1e0a0ea7dd2a3bdcd62be6135a79109c284c2d76419a2c35ca2338f267b62f42644a0d9676481e46f349f899e6805df7d95af1c21493fb5c9e511583747e123151d54179e77e8dea31576372c679abc89b400848b05ba86afb06b3cc3d022ebfe486a6cfc209e93454f7a8cb9236aabcb4ef7818624638d12b207d9aa4267645b382584a22bbfd9df157cd89fc6349608f3a4d874f6ccc32c0370e311bd9afd17b003db0fd70f923c9f4f559e056f6e24f8ff3d3c12970b949a4dbc9244f83c27c1f5f31c35f63ede2fd4f8bd32401a40101093fc3c3823fb4ff2fde7657aa563f1e07d309167612b0a09c1ce4742b3a433f7744e5e3c7a85e1166b8de10a77201122e1313359bf01764f5fcdb02113aac27f0c86498d7f2d267f350b69309bf9a0b46f2ba90e1f0878dc06b7f830cf12198660d699a2920d66f852d04815574aa46e126a0dd0a7cc14c95f4b631406faf01891ea2c907ff999fd6e10c3301e62ac08bba8cea4310b47835e294ae7e542a9bd1b5d71fc88fb1db197a7acf475f0490e280f4b0c9f89bfc59c55e573582cde2b14382775ce2e884db596f11693d6c852e91dbfe9dbc9274689d570742677239b6e8a1fbd0dad270e526535254117122143db4695b89f952c8e42ff9e6ca702f04f81ec5d9f801394b2e62fae16dd9940dcc28c50f7a13b8b8521f589215d555e4ee3488919d0287ca041fe293c904f3c34d21000f9dab14ee562677661934a43dd16ab898c2c78874d0d55ba654ec98080f0c058e9da5d0b99ee663614184ac2d5d14647974bd6fb69cabbcba6c30315ae0fd9c04fa40cd245539b598ae00e69b2410bd5923874aed4cdc4326d3dd2b3e6d3f28cdfef0c0be3937f9636cf722afd20ada3858f447a77b46e5ba3356faf83e58df63c17443720ba8a6b01ffff2d27929316f71d8a8ad14280b195b8d37503c1571ef31b18908e320b538ab89e57ede22af5aa840d4c36357dd28d8bbe9e7b83e40613502ba4c1819eb182305b23484ddaf046ca2528b26bf6ca749d21565b6a1f8aa190769288f0534255d264632877de6e37c4c81c5ce001682bcb3034d7e048f4961e05400221a35f8b06a9262a86fdf4da9e91d437291702abe4a0edc5fac8477e664a3ad6f8af492eec211a0546686f4758b34e0fe7eb775d54208ed5475f8ff59ec32c706aa74301b9fd3d3dabccb6ec4048f33713e5bdedf12e9f5d33e224ea96bcdfbbadeb6ea4c3877a1126d722a65025daea274a6d13c72a0fe597c27c061cab70279f1f7e992380e9ce95f7c4d1e50ab7c2bb3a854eae72eabadbfbe02bc87614cb6abbefd906113d47a9db14f6920408361ff480dc3fb7c4916be26e37a9796e7d4fb53ac521636958dd18fb2c1fab2707ce245c80ceb12e27f69027f675f9341126c937eaf81a7d429c74be437a53e120b96b3e422392ff80c9b1b392f0d5cbc5956913237d171ce429a35941cf093708eccb5c0af53bebb6e749418d0f9c3237b56c6859ce51ad79d20660802b3fc343c014907fa4669129818f8f4aee3a389922df60277015abe9720ed1dcaeec12d6e9a04faa3ed85ddb4b86584f2f738d8f762332fb920666135c792b38490f424c698c560ca53d064f061abbf78d0b1b7076efc45fc78d6cc38da952c4ac8eab7b18941b844864a20b2a75076a7c78843a7f0ee7d76bd9f0c74ad7c9988e8c8a7e53c5ee4060c162fa9eb11592c5e311ddea9b5a9b734017a92343cefbfd14b8a6c9ada2420afbf7afdd7fb1ff54698fcb0982d839bdf1c6c362fe86b0c5641aa7a647a7fa8b7b490f4f25478deffd42b7fc8073c3df88598151905a0307a9bdb2cfed2257fa22e870dbed16bbddeee42b01a5f565d53ff575e132c121b47cd7fe81918b9e37582cbd188fd32f5d8314264f8bbdf387ff309e643adefd990b5697b80841bd811fce8c68368c77ce73783934fbdf438d59be63f4319b3b624c9f80d3f48b7ae227ead9ee4082d20df6def1cadf04d48e6450056a5e795046819b83f9321b6a1643a9806dc838d6002d75e06ccb0722fe88074b2f00da49286373095aa709745d568701ea29eeccf0389a4e10d4ca72a9c9848b35e8279e0b3a58a5d20e1985598861060700f6cadd90a46d309499d642bfb8d9038c5ad9f2764a6713e46360a5478db1ad8c6c2ce78f8d8aa6c9b813e06fafbdef543cccf5f0f3d30bbca8af65c00d50d3d96013c31026aad6d5d5d40cac9db0699a3c2f9e90835cc10252e11e011e96b7dcbe0ccb81a7113f824a0fd814cbede70f3f60b7c1b2e13776888f2db8d30456bd507b4ba52d434c73aeb24dfd233427d8459978b6ac594bc08d40ac3478924b2dd642699524a29c105be05c40541aafebefd5d5a5f0a411f2c41b8fdeb71142e5c3e74f5c4a8bd2f2dba2c5b3d2e5f58d615a72c2b595f9cd11b63ee31f716c07a83dcdc8222a9a3773d6115811e89f4118290b643bae8573ada47283979388163d6a63a5a2b4917de5f75d4260190f38b47ce0d9e184eb0d0d1bbf2f8d0d1bbd6b698b040e7b6a5a3b716a40bd05cb18200a40b0cc4b5a356cd29a1a377955acae53ef73707b0215d84a6064b403301d80601d28507a20c1db55b3c38e0c818e174e2f4aa51a140eae85d498c205d84e607484817b6eb5faf4b1ae9020411878e5a9eb406e4c4119e283840d4a64e1b789e9c88c203e5045447ef8a824647ef9a5303274cc40fe922344538d2510b164493bbb922d2c5d5893774f4ea4e24e9e85d49a08ede75c668b6cbeae8dd299147d8768f96b0edf2b43a7a79a2938cc949542cc5b69b4e61db9512b774f44a61bd6360c863e5adc2b67b55281dbdd74a0bdb6e6f876e41cfb9f69c9b77fd7a51fbdabc60602c88bea8bdd0efd7a10d73ce69fb6e3571fdbcbab0ed7a303776050083784d2c7d753a0a55a716fa8814cb8715bed61ace08d4d15ad656d891dff1794dab40593932820d0552476de1ee8784af57bedc2c20d3d19bd813b3eb69d961458b1517e4f6ba852b966af53020c028a4a356bd60057b587e08793e211a1cc04747ad1557379832a1579a000e6674d4f67276e0ce061bfcb7c403088c461db55b57a26c55e53e9080084447ed2fb603736274bc2726adc00bf1878edaae9dcbe2d4cbe20584108274d4ae2bf0aac460830b0d117e2c9808f5cb4af815960bbab971a7605a88a936f4a02bd275f4ea46fc7e3c70d9198d2874f4eec05d155558d5758faed23daa2a62a15e55056dde55150a2b13af285c784b97478489080f24f224cc11b161881826a71b1dbd4ce29a83919bdea89bde26b9c71baba85253574a5c7b5aaeae7aabc4321dbdaa9572adee158f8e5eab9ea48a949e9638a6a3b737f2b0fa444aee68cb4b0a1dbd5bb31f942c59eeef72e53a7a7fb29c972b4d6ed7f5c2d1d1db453b72b2def57edd35c4efeacb0ebfde05bb61471dbd604e36bd2a5996d62a5b4669152da52a5a3ee482687414e7be462b54bcac54a161a5852f2b54545d11908e625d2ca7c2124f85263ba3a28ee29d4eb178e8faa271a4b4eb283e4acfde95274c57a8c8f0964ae828e6853f1eaf8a1693d338d451cc94a6507b3d987a3da4f492967a4941a4513b3a8a539eabc16aecd57083d4148aa5bc80bfab2f5aba2b197e5c7d21a2568d323a8a559eb3748d3bacd5eaca0a0beb4af7b0b28e7658593cf4b0b014615d15e96989417414f77652cd530187f1a7eeb6bc8c3a3a8ab74aec7e5cf807a6f887e502cf6a4a97578d8ee2ae995cef4a6dc16afd5abdc81e142aae9404d90ae5c90e285452180c87fde8e2513eca4a5a5ad8a7f6cbe57223e07a6cd6d5d54773941446b39aaf32d3bf5e679c75dfe86a5dd6d5091ffb7b83cd9cfb3928e77ea8966877d070fdd7e27bb5bf6097a96f593908dbb22ee7b2fe3a7bb00b34772ff3dc7a1dc56bd7c7182cecf18073b847e62d99c357778bee4ec643f27aa1f64b47619ecc39e731ae4999a9d3738647afd7cf3e368618631cc2d65aeb7bb9d7df26aaabaab4aad3cc933d9829a8d1d1fbd329eec1d7875824eaddb22cce3edf1da2ddb93febc3b0f7ecc5cb536f8efce9fbfbe5aaaa9eadae99d5303d7b9c73d641c43d2ca66100d7d7bdb93a5b6b2d8d6a4df8fad65a6badce78e7db1b6b57d0aeb579cd40a2ddb139e3eca3811afe7bb77a71d6f65cf9d74ac4b75e5c00c7c526f0d1510b26c20feeb9f1fcfbd1db0db1d72d34607dccdf9bcd15d8767508fdcbbc1629d0eae9f5ba5d29935eabd145f266f18aa298019bef8a7bbe70cfcce3f5e6fc8cb7a9598730694cd4fbaefba6d97644985d5e6e575247ad550b1dbd5151551dbd4c4c3174f42a297de9e8dded64e8e80d82d2510b0656a5a3d6cbeb858edadf4f4b47ad96965647ad55948eb668b1d5d1dbafa33b3b593a5afb5e3af7db97543a36d33f63e2a56b625ef6a2cf013582c8489974560d1f20e79c73bef7de7b771d11c5a0b1c5d543121f4e5048d891975448da7285049e1030beaca4ec42071b392260bd1aa68c98c0641c74b128243be8c06146d8900ea629bc37945f8059124358991a3fa6c472241142aa91c439e79cf3bdf7de7bd7c8c2a30a051b5855b250b8348654a9e1e35240861d9e74f1da0191f57b827203496b26312420d5d82c4c5d40487900646c1ce96cb234a16106930f6572803990680ea808856142c310233c700c99d2ddb4dfd1799bdff11b7c41a74b726daf06165ce8bd1074e403b1dd90ad1a600c221b92f4b69aa8a028d15d4e5c36921040820b419c00c583093f70fb0653188f6f70efbdf74512c3bdf7de7b6b9d35c3b4a192c79a0b04eab54eeb7b6b1b9ffbfee567262940bd779f5bd09cfb685c5801108f6d9a73ce39df7befddedde5be7b1cdc63dea77b04dfbec13f3da83be679f98e9350b45c2acc8504fd06104c76b7ceebb8fc894cfb9dfc12f6e7f57b0d4ed477d88d33759d32e2fe881cb3f760a1034b2703074d10bb87f410fdc3631d8553f7459010723ff82c0817e9b3f76ca932b39e060e4325c3810c50db7992706ce679e0e40cf3db86f3ad8a0e7e61e3b4ecda6b8e1000cf38f5d210a8a130e46d6c2813e066ec7862fb0fae6435c7d428e70fab16691bdf534e54fde62040c0743cc8185c248e160b42832a2c2815e973fd6061c0c9b89aa1ce1604cd0c355164da3041507e396f36a61d77e2e90d28a838175c0591bced018df862932b585d3a58885c3295645bb83ae5075bc8ef9837353c293f039668d1741c220c4c389f0dec7c0993e062ec79bf026cc9f9c1c9f63fee4d8d446f810e60d073f341fc2c7c099f03170a58f818b81b3de2c6d50e9cb1e8031ddb633a45f1c96d707722b7ee39853d67a705139d51fb20a8d9e971c0ee7de56fc4efa6cea8ffde9857bb48ecc8e56a4f1d6fae0dda9c2d0b5140c6c0aec41cd42474f23ff346259c4bc6e3475ca9cf29205d8f931d3029b22fb53977d683bcf789a125d71ea74e83965460adbf01975963d7a7aaa4a3dbbf5aba79546e55d365abf7a5a38ca68e39df39acd98176358c830fdf0c73c9923dbca754e5de6c1397e7bd1669f333d75fc4c79794a5de9dca3677a4ad98cfe4ccf28dcc33d1e63e38d024c781ddf81091df3e7e987a7831cf34783cc83bd8e8943fd774e595e3042e79ef4b319e79cf440c7b49927c7f4c0669ed0661e6ea2a71a9ea9d726de8961bf538725cccacf3d6714b6e99f6b3a3e8700fe98f7a0b499473f6d9fe3752ca931c0bbd4523a7aea6ce6c90961ff6c5964f38cb229b03fd31d303d66e633fd18efb2cfc5f5b2cfdda5bd3563a9ad23a9ad0c56bbe19c8ec7a45ae51f6d977d72fc69741e9dbab3e85c330fc6d69e60ff544fdda9c33dbb081be11e7df2704f48f5b13f972c8bfbf1aefdbd77ecd4fae714c10cca85613fd5ab3b75463b1ab08f9e5616470396639e2a9e00ac9faa6561c1c7feb43aaf70cfcdf6feece19e6c6280f641f047e555c2b6b3b774f2782ab69dbf1c18c8487df454cfa29b0db23f771fdf7fea9c984c28b22d440192c3d146bcd069b4ec51daee638f77a79a7930c6477877d2d0d118bb53876d98249b3a7aea3ef638e5a9c33d18a07dd200fa880a98dc209b47621e7170f6e8698254796d38fad521889f4df4ecddab730cd2d17b7bb5f26ed98cb9bf11e5edd2a1dff54ab0a5e3106500a6f4eb27f8c0b982e5c17eca51d6c985e95477741d3dd58ffdf8d5af5f4113a3e3087260cdd0c29a7175f5eb89c96191a9c2d2a57605e1bb33fad78f319260866e3de9a2c40cfafa1d19dd7a71c40d5d4920641fed411f03079a3f4fd78b907db4df668e77e140f3c697d0790bc0db0799e77a4b7280713f317009c02d92c010f9d8240006d81601af5fd205f6d704a2fb7f7707b8390d6686bae565cc9744bb1382a31fb558de7020fe883e06ce8a343705d8fea6832cfaec2deea603ec473f9a1e9079ec2d2e041c6e0f5e323437a0e06683db07fded83de02310ffad0ef9879b301e8430ffad0e480f5053ad8fc22f74772ccaf41c9d03c06510516d625a09666bef541e5e0505a50bd0fa57e348c1aa1b88eec72fb5b1f940f3ea830586bad41f008cf28cc4772e978a42b7feb3bc2353e218b5881dffa90cc3802f66bd8b6c2a6a0bde8d667e4087feb83a2fa2fbaf51dd1fa68f8f1112a1fedb41acb0209d128ce469224c9d90c090f9a27514595eb33b0f9eab00a38f36dfe85875da1b8c68c0051c6bef5a541bf3672d205e79ccce092d66723b0868c7471656406f79319b8652eeddaf202ddfa52a74fb32cecaf5916fc5b5fba74bffed6974efd4d24aa9802824e1df5f6e62ef8d451df5fecfc10db280803a402880c153884a20cf540a462478d8f76ff758382321d7feb2b8203d45afb8ae8f85a7bebfd4eec5b5f91123eea8dc4f1a32dbef5b121ce32a59fe65b9f10ab5f8118edc78c1983c48625ba1b9a70a0905448441dcae68b1b085a505f102402f5411004419d6ff63d85f9e4b7bea71bb016e6c2187f7d1bf6adc73dbc8443a71e85a76eb8ea663de6dd2fecf341d80f07e1226c64fd5d77bbab9dd6cecb8ecbfa6bafaa5e25f52ea9d7498d9abaa1d71a66f9f65e30e6a1f03b359c70ec659e8b838c3ef679a775195c2c1555a54a45711e46c5541999c1fde2388ee348e6bccef4cc45a3696832be3432a3259e3e32ea9dc68827826654a36b6a32be35b158896aab2a15555d1421825655a37b23b495aec2362c8637c4da821a0433be6038bbb9bf461c01067dec49e4b00de75197a806fbd897d05f36dac626e36b338204893197b38f7b780bff700d477dec4ba4d806824c1ffb9b251c100727e38b0382be44897befbd9783b1906f9df50de6f1782b57ffebbac575fd5ad7755dc11de6e48cb9a4f961188661a8aa5895a93b16aeebd7baaeebaaaa55aaaaaa6a18134913b90cf163b1582c16eb71d9fab5aeab6c5d63aa5aa5aaaa0a8ee40c8d88b21c7329e2afaa4c2693c9641f849d1cc331af5febb8e6755dd52a7554b3aaaae2efc7f5fbfd7e3f9a10b411359b1327c69b97b047fb60582c5cd7755dd52a5555d5bddbed76bbdf8febf7fbfd7e691a95a6699a92185554f59a0d8e8e37710ff7d4dc6eb71bc8fbe0f75b7fbbdd6eb75377aaaaaaaadead775db1f9e38de3e8476cf3be56cb341eedd9f3ac5399c71e5ca201791de4cd80bc19c823b7ec17fb5ad7758de59daaab66b43ad32aa9d5ac55598855bd33f25eeff42ef3f5877b3617f9cb3fd92ff60bf11ed3cb4b718f1895a6699a8a26d8d380ceb91c847d4099898e63cc4469b4d04471704c746707c54741141fac80848eee9ced893af6e2acc1cd756233f2f72b8155b4d6da12c4368b79e0de7bef309c73cef9de7befcd39d745d121394971d1e0025219127834d9157828eae255828fa0212249d6236916111dba7a880d01622349a737972b84748d9444b912a602094c09e0e23292831399a12121424f503892b21710c8f2bdf7de5b6806a10b04096f19e1e64092201d990a0253ca41170b92e302f99286f6511317dd45c79b7c5b0c095884291794642889da21089cf1a42b3ae282bbe870e42c05e84784a463e8898703ff9801ec02c2718f9a52d9e73ace973e1f3f070af2913719a2cde39c73cef9de7befcdfd2d66b4b7bff12028e0f101294d84b840c3470a462466201d75d1e90848195a61f5e168ca0fdc5efadbe94910240b8240218265481057b480d41cd112662a6a8c132b28e02e040cd756102849a89ce0d40308520640983140a464a1e2c40510c9935111d2e6555d8ddb38f8dd0af361e9924349d68fa6266157d8802129a5261e32b67a260c41410f0982a2a949892ac817103f7c70c1439466e82f259099c19744244aa9090a8ecc39e79cefbdf7de527c443ec0a0240ce689c90f214d6c20e941c406a3a4bd83eede5efe0602a28477f8f0d970e2a540442a694811a1a4985d53179ab8462852069cea0dedec19d80610d245dad163462a65c9863486c40416748f98bae8a00c39c1a205081c36869430c46be886fd9d00b55445d483912f1e5cfe101a84a65c0ba65aa937b482f0f1648b0c9e3523c61226526608b75ef3de06e69c7d50f53e1597252a19a8bca8c046783283c8931ce913de93a627534fa2829e420d8837bc1e2cf5d7e5f8c732c8aa4fa1176fd093de1a9c7173dc7600e125c39c679c9ba610d1d438df6ce07fe8fd0f65216cc23226fab0142296e1bf1e946d6baf99f9e7e50a6cabfa6199bf181363368ccd50187fffb15c218aa21df10c85f1f7ce40f6b70fcb9b2ca64bfdc1320330723f9bdae21e329cf1bd4df1fb8da52b00cb2f729acb90e4158ce1dd7baf55f3d38e08553a64a96460db10a49c054910cd411054816ac86b193e67aaa09f814c05a1054cd285a668c8a1e7c0bff54df980a7448bc53b42b725f0c559d66a9db34d6129c862b7fcdb47637ceb31c8f687206827571fc5416b61cdb7640a1f99d0c9c1b9b129512331a2862622044d9f9991a3288b6d3254f96a9d5f506948fd9bfb3edf8c330f571219df555512d62fe86d97785912462a9773ce5a4b298d229cc8990a3319d6ccb8a5c766a091794989112115461369d4d0bef531d93142c4b73e2643484cd598589560a2a566a4d168b49a1a265e374cc27066ba9ccee3964d8298a88db789aa33e6e4e4e4e8e834a1628ef8d6d784eb44931f7642dc80e00408c69d9d9d1d32831202084817b989561a01c9826d060b8f932f12d47ceb73720300c65b3a2983a2c4b7be29a214534b01207f6d82f14e4d89e08460e784597a133a39383736256a2446d4d04484b0cd6874882ac02cf18223822561749c523921088aa484ac938e132ad830b168945b8afc0c4326bc68e848899991231566038706d1cd0e239b213a4a30992aaa994cac6c9060a265a7b5d69a82315d7feb63520393309ace86081ebb10416cd04415f5262a8d99265486664db878904d7ed831dec8213a39e186cc49ba23e684851aa1132c37b8932f43dbc90d3b4027658af41411529e5a3ac2535335eed4145defb4292d1ffcd63795f5d1ee23d8023e59e25be2b464e95bdf12a325ba6f7d4ac094e8a0e4031f64b21efb0dac5d896f48fcd6a7c40bf641c99492ababc487858060d207c119200882e08f26a25087900677a8b114d284e11dba091dace7e8503dc91a94e42b4c122466bcf762cc138db4d6201855c453ce79185acd2c91c964a298e497646b4cb2823706b039e0e7d817f176154a5d498ffa2234fbd617d545c443823f01a933f7db8bbc040201f4e2b618e31133cc736dff9219d8b818b18ddb14d857f043476b3c7bf4454ebfe696851d710f8fcd047e36730aa2c5a2f56507fa46e2e5fa10a32d6aaaafb259dd30ba33624f00dc83e260d082a6f4511c9c9da8a28f5a8083a0d8d8826754f75e8ca3aea2bc447dd13db2d805586b1570ab751085e7a1bdcdef78100790531190d308a2f6fa014d4254469078b5d0e584a61774d3179ef7575fee2f3741109402b414ee28255ff6ad2fca298c41b4f65e33ebecbdf7de7befbdf7de7befbdf7de7befbdf7de7befbdf7de7b2fba818fbd05bef501c8e106669d55d4e8257428ae216ea4eb30a2e087944767ea4ffd460791fcd04d80e84e1d878efa5d87922123fcd60745a34a67ad7315adb5d63e1be11721dea5db5a6badb5d65aeb6c0408adb5d65a67adb5a761afb5d62a88ba8a25fdf6740a88dedffa527507df7b8d4714cbba89283cea5b1b06904b48f79acd209819d9863a67af71f634ecb3efb55c5321a4ffe8469a7c281e62987d829e62a1b7d6ca96430d84107eed67e4e86b6258da0f96f6675d0a217dac14a2abe1483f2bc30bf8482396b73b01f6b3d25e1e74001ff75c1eec555c1bf6b5ec53002b1fdb5800d62dc0bdfff6a3dca3376ec6caedc972460df7c4bd088e3e635b08e619c83fea01720485903e24fb17652338f379a96d8ad9ec87a017b1b517eb99ec8f250df3e0fc18085a52cfb62eb729fbb924ff588699272c6d987df815b198afc559cfb6977d3fe652fcbae4403813ee6d86f8321c16112dc6222f8b4d3a7c122a01b76028c205a6880ef95a2344bf48994fab293226c43db1582c261399b81451c59510522ecd0fdb9c6ddae5a75b61956aa824ecd80e5a2ad1d400000000b317000020100806c4912c0992344f7b7a14800a5d72545a462a1e0705b160288e6320866328864100046000844100c42006a1e47410006e8ffb422d49fc08312637e2f9ef1fc0b097c67243cd98517bdb757979380488d44fbbf2bfac67a49e2fd61c73c4f096281ef7e695377fa4502d8c90d91af4f16175627f59503ee554afdc088604a277fd4231aba136b6f69637d4817448e83360478e2681230eb51ff3d06bda109646a40ff044464e099225e80e5efba5e6b0e246c4204dc9b65ae99f1bbd2a268adc7fc1dc7394229717a940b2a944a917d6167b05dbeacb04a91603e49a6e44994c7f55c12837fbc94db18909cbcc5df348d64800fd7469e84af47d0e4b265b15aee96dbdf65106fd470bdb0aa8f537aa839eb7a9843be249d55f3588058f951aff61295f6527fc2fa2aff035885538e4cc491640fcc1dfcb376a73adfb1b30ffe5b2e675b86f830915313c1a2886fb0a1308cfafccff2b30e216372bfd475aa2c94c119cf64bf526615e83ebea53ebd40cfd609c9027d517b4a8a5e6b03e905a2af1511ed63cadee9ddba9f1cb6219bce23de497d3c447416002b438e32d0ac577daf2dacd63e3eb06ff1f7db3d2fa0a300be94bb95aa6e43d21791a438682ed65de976238454bc4b79521b7604bef3850d6c476c16d33edc24ac6784d300fb32342ff55297c9127f563007304f3efc57a180d853f46a7d12b8815e56ea80c095abc6ca08bf07eea123e261379e2e004e0af3a0673dd1ffe9bbfc793ec118d7b51f00790562ea69a474564e6a740dbd1763f608c70b8469ed074eeeee58d3a086f6317871d7ec1db6359a2dbd9461cf62b5fb87f09782308674d94a6e1f13d468fc1f449187c1c51a61e50e711bee1030b27fe322bd347070fc223582793f6a3a3fe07c446201ec1f43fdf4baedcfe1711cf0483218a803787e832123c39df2110db41cf49a81c62d9ee17546e83ac78958dc53b7bb46665315ee6ee73edaba69c84a46dcb18011e9f9018db036645e878c71fbc37c05f947909930f254320d1419d4d5ce38154171bd962910b481f2ed00fdde73920de0a2bbab775df212716a947f55c061cb08bca3272177493d3f558fc150a17a297cb4050c1a0b91d152894b909e6d54f9ee7ad5095eb373ca385cf4b1d0a20afcf5bb81e7944802a383c2d90a7209e846802f224c813104c409a066122e429084f009c454c70acd66d663202815e85c84cdee4a26d9926e5226b0f8bcedbf5e47762b8440ccdb4281c374d665125f8d5440c1187875089661238e33ee86c0665cf67be6ba2a7ea571cdce008a1743e70550beca003863934374ddf502b729eae08013ace2b009e1d29662fb60366c0555236416538a200d0b28086a8cae3844e09cbba78a2f4bce73b1ad156d96606d7478f77c22db57bb8a6d17ba5796ee7bfd4787f6c16e53add3f58442de85efc03a898a29928e26b6c54d5d1bfaddde8100d7ab93a99fba78d03b4b2448dd3cbed30bcbdeabd5efeaf3606ba0d4717bb353211a6e5c6417e0b6ce5dfaffcdb9d7fbff36fd7c2c5057ba5406633dba0695ad2835c4b42c34cb3c872761e213874cce033ae3998618712dc76bf02b956e657b530b58b1cfe395d247973b2c681c353be2088c42a1b4ad7c6cefccf8bb139538818a9661cddd7bca1bb1387fcd9df423bbc710eda7ba05effeac78e44cd8515b9eca9ac171e8494fe32a9f1c1fc162397b9a8dfc300039770d996bf595e1680fbef71084d3c3eff28f34fa2f4d498b18becd03338f7a98bb1138a8e31102d78166d0da3f0c1390307953ffe5bf2d952e1f62dd4f3d035b1db51aef4010b2cbba8f314ecee43a5710069d32585a9616e98c82a8e80e1e1509ab0bfa2a970c9b41626a6362e59ed416a6ce2b3dd1e8adadb78b0691da4e6263e9bed416a6c164e0376483485da727f994bba04223bd4a7052cc4a6202292f4dd3e8d10065a1bae7b3ec215e1512c0e2731c80129911ffa47da7326ab56cc79dcc7644e4d9ccf7d9becdce4e6729f4be6d4cc66b91f4b7ed6cc59fe7adfff710e4735da82404391dc115e39b0605f4b07ba60c4664b0c6f2d925b422b07312f60c74d8c98bd2b23b9eadb1d0c036ffe09561b0824ccdcdc35bc5b2e39d6a7b2d923e04f25802256f6617c71d492ac5cacf1c2e2dab3f29ea645ae3eb985432bc599ca1936d9e9d71b07714a83161737c1c13e8293c7b7a1b5282f062a97621cf52a39fa61a623ed41eb17ada6a13e21fca1530822cf174cc7707aa7ad8adb34ede3db96a8c7c9c3a27e254da4cb3a59014239f008485563fe4acf47f99b55a0afb902dc366651b411301a400562e022c22cc41a507fb30918c75a1eb44b32f5edb47990d9f52a07e6d1e47975b1a32ac7d1a726e3605f21cd82aea302dd37ee70f66b24453597d948131b9ab84ed27934c871c9597681f4221b89e16129182dd16d26f1b55cc230c209ee5b3659e915936713c333d06d38ba385a7472c9556581063b8cf88625932bd5bd73557cc8b4c211dc32c1148323fdaadc0f59e5c257bc305b7d6c7355756676b2ccfd8b2009fd5e6e5293ad84aefc319f991861c74ad4462efd3fb688538fd57093a2c10f68a54d2f1aacd1c7ee4c4787f603edba71d1fcd2ce47e52196cbe3a00e6687635997d78908f52a4e5093a1d2ac2e30d2a30c177dbd561f9b4db804fc43d645491c960de58048f035b28cf07b0717e830f956029f6aca1084f189b1963f8ac8d9d3ec780b17aee82c95c57a560e41083520c9b4ace80e535ed07bbe59bc05043d696e24a68c4d5f61544dbb256c347e979eee10d613fcf4ce10f69bbe83d4e1d79e6274481a21822b8ee24fd4bf722e685f2891e4581d0dbda8947cfe1e036b04e04b77f1e17edcac63607b075f94154d876f112ec59a3ba8ee33e6f5ad5924506c1373964cf91c106d08ebeed1891f81cd4700c2c5b5d7570caa9551c237b7d7a6dcb04a0426418ca169cfb39ecc16d56f8e8406165d1e553c2e6761a0efafd422166cee91e508d50e655afa575b43c0418995a8b9d038abf0d7f46c086f6580d6d93491fb096bdba802a10a2b5ea820f1215219b8dcd9c60a795a2cc0a968e84dc79e60e92d3484fe9c08176b10ac6d2916fac7cf9a59992c343424d13e190635c951319eacf8f8adbb07154bd28f437569ea4ab73a4f732e7877d482405d61d6e549677512626bc257a67ea7b512750898ec9f8388edbed13e37c3650889918bbdd7181bd25fef6241032ecd42c9fd77a536306b586113175b1f47082c1d2a8032caf53241c54756e599355f7ffcbb8c9aad8ffcc6b6ec9a39ce2ffcbfe3f9e5f77fadfb6be498b3f02db722fffaf3df09ef45fce5f7bf67addb96ff5e61e10b134b1188a95a583ff0e1014b99b58d6ca98cea207aca264fcfb6f39144a71b5bb20a916bba5661deede8d5918fc137743fbc1600af0b9e624af47eb737b83e4a24812dce01f519d4eb76c3de085a1ac1dc731f53adf344298bcc50fecae6baf5522903b5c98af35dfd6fbb903123dc28e52103b6129daaa4610b2155f10c7a1dbd56d193ee13313fe68ee30638081c2a863233f6d34802bac0eec83d7c1819c471e0029da0860727603f779ae15f6ee3b04df90202441f3405b051f4dd3026e4bf9582997cbe39eb6c875c7b69ad065ea3ea45803cf1cc16e52b2273c7e3421703f3284d2375831b9d0427941c7fda5fdbd17fb7aed64a549ff2a5437de9323dbf4391b43e178b6c4e03f053787c31dedde486f3ced8e34f77688e86fe9fb059ffa57cc8f84404cce6b712fe4cc5cb838feea377b16a522503311324bdb7013752311eecfb7640e97e406b824a0b4cbd2ed1f70f90c034ae2c37a5561b70dc742f74a6ed2d730933c64fdf7e73ec5c55aa3f79c738c822ef6e4c4a9c15ffab0ca9dd3c55fea3dc78a32f55460ebde5bdf60ebc4ba4bcfeba8e3128f50e6d894e0e52a1e155cad209426bb8abe2262c92d97baf3228342a0365e8f7ff6a23a4f112bdb57f87e2e0f0a88dde70d636203d1cb25e0e5827955f6482abe6263a08ba5a847a346054fb021eaf924795ceb71c3a3c8f2374b7ff2e6ab5520f1abce059dfdd750d2dddef7cd1f120f6dc86a690d23360cb37b559bfed680cf001992321008fa3a84924785f3b643ac2d84626361674f3ff3a09aa5b1c1848c4f711d65a5cd16cf21ed0c2570c59bd8e2b51c8e26abd03a3582a7994ae7c604bfb987edb35d93a8d771e651ea1b211e087def4b9a5213155e0644a3a3c27e36ae324a75d0d604958e4f09aeaf997e09c98bebdcfce32d99f07f69dab13f663cd9cb37a3f948bf4caa38b343566adb6a139661d14323dff528128dcbf735a6deb3036ae1467b69a0f9ae1b7093508c274d506ff5be92ca174b0b79d53b97dc413c9da2d3d2baad3688f2b55a1a3dab33ffbffee94da063bfa05020847a610d49bb05507c096f449d22d7d704c0dd8d271c10af2216a54c44c0d7f3b50c65dddecca13cb7c2b38b2b629d5ffeec4c6c2cc5fd05964707c2dcb81a53c309d42faaa20886117cced9eb237ba2f84540146048e05777ffe1261914def07f9dff33c1fde8d1fbfa561597fef2d6cb537c140cdce2178106a96f2cce732247c2a868baee75eca8a1570d3f68831672934008975aedd6535e299420d25bf618351d2fa307c4330a3c3f632e9c1d1f08d2023b9950c3682e8164791f8668c22e94d66d8647ddefd9eadc487eb34c3a77b990ad5b3e13b0da18308eb68e231d77606b7faf1fa5b6ec309f18e859ca6a59533677706d96a21bc6b3501d9fbefc55c467b679dfda25f2a676fa7ebeaf073cbf6abfae09dcb8e0dbd7c9fca7b658d4d1c653b14733f2bb84c1d292e0f1d801a82e2e1d9298fb02e366e3a18910b4c8163daa1c333527f1018ef7b1816cc2bffac0548c84de58c9f0f081c36abc14cb903d180a3b323b9c7d1f2ee828074fbe9dc0ce37a3f186d16baf45f4e29d9fdfe8d598538538b5a3994f33e95f3ef19367c423bffb17d5f584e562d425de5f1b87429cc6d2dd810681a0ffb4fd9a6d4f8a9fc024c5d6f180d83f3f2b4dd67128df7dae2bd73bd206544ec19bd854b87fa997087287917e638773be80a5a23fc62d16ff81d397180f58c665bbb424a3295b7756a13bf0c12d2ccd14cce58671f37275d56e7f83aa01d73bb67d6fb844e684d9b76725afd9af2baa5705ab390dd95bbf87a1c1515e2351bf564bb4753a080fa69f631b763407e5688f5aa33f754ef7bedfa49d02b6a65fc8890fd9cd3b65bfb65dfb4d8885291af121c9dc489e8e7398666f566395223d372cb08675e7a6e1cf1409f65f2b9b971eb5cc85b052fc93533bf2ff0b14c766be355ff9f05558bae41ed5f82ae74bf8391863e7432cdc9785623fe32fb8e680b4592678715e9af9c1bd97b33b5ab4313f60285e9c273904d620259cdaa836a59900217dcb22aff5b9182a1911a1bd6a5f9383be5f6f11f8273667063bfe078135f9c4e151cb6a5d63d08ede11ae38077c61464af840aaa51985b83acd3194456b29cd8584768a424b694ef60c5580da07f5fc1b557eb70d852e70e46a7ec2fdff5b9277f9d5b3d859e713b52f39956824edaf48f82a1a7fe21069d64e13821fc1243e6ef79d3541983aa9cfd844cd49c965ddec90acb424c88495d88fb259eda191a2359dbdf889cc3187fdce02f3ca86804ee8ab5acf7173099d6b02c842abda5eae394ca34587095aaf1c6034b537085abcbec716197fdc12b2d50ec889fc78ac06f0ee9171d5901166db205fe2f13606136d75c8fb0bd68521cae36c539dbed354c901c48d1a4e6b9ec99f02bde1b8396f144ba16d6ee65e0dcb6dffc4e3c157ad401424d1f669060757b096ed8a6b46766e1ed6750cbfb69b9f90a013561470052f27f032e4cdeb34805ce484cad5e7a2a80549d236677d0907cc8e0764b9c962523f74fbe02804d6e03f51f247136122a17a7596484a75d048e268a31d0cb5dadbbfb8b4cd2f1ac0056d31fddf5bb6e224229491de389c4bb92d57a6c18f956afedb33c967d3ef2579f32757536ca8333c4eb1f7a2748f40881b2e5d10c1d0176ba0857aebf1b97db941e6afa914422c526767c98fb0a60329d2bba62e24d0366bbe4e37fdb13aa0c6a8ad0c237f5038ae3c34256e57ea4f404efb6dab8df55eb99f62d88b91044f1ce7897505070335890e65703f3ea8c973144f92fb5b7167cc772c04ab6eb5a3854ab8778cca87c4b1c4b39a622e642e48ddc7557198b5aad176a3ddbbea021d9fd23c563278443636cb7a642b4fc40f3f9e8071b8364d7f37757f368a490383d903be7d672db021538a44860f064bae91f00d43f14eec002621ce617c178321a7ba967d33424fc201cdec2a5a3303f6bd8e5ba32201c2bc0c7abd6d9c08ec1e2ad0876420228e2653d1d58cc46bd37c2341ed3c41dd85c294d682e00cef89ddda072e1c2f75bd607d57e06dbabc5e68e04cc88f54cb3be648b4443fdd2f47d1a78e69dafd5161a6e4081013abc020b39e610d9ad455ea056ab9c234103c1e7708be0765772d82e67c6fb54b0803a379af00ea5c7169bcc2b1db25b1074f6529c8a92f2e531697ca00a35751a07c0f81c5df7ccffd4e64793c6f057e88616331d91560547641e2916cc703794aabdd67065c2de9ff8cc64f681cb1334d4231ddc41441721fac510d2d949e7017c4a00c04de734536311032d579eca03c487c795c60ae0df45e2840ff7743bb05d474a12e2fc2030ed7ea663b4d05a85e8f92cac732556bc0f4f4d552b0801062f6f3dcd27cb691051a24458e10bf381d23074fd80f18a8dd60226b20187cdcf14f3e32ab9e4b8522f29d03686e1c5acc51f2c4ae82d12fa8684df9f347c98731b4c326472ea6c9ce5b5d40b1990514279598a15f8ad155dccf96091458a2e3164e69779c90843f551681a79183529e2ca7b6ba17fe82c3ed65f29e646770a8c4ba95621be454d65c0b9cb56054eb95e5118d49cf44d0d5b7d08df9c57ab6051ced0acde3e388c066705fd474b25efc2aa6ee816e942c69d034494a6c397bf492fe7cc5457c69bb4854484e21a7e86accdc2597a98092313aa5115bb0a28727d1ce71ed4c583b40e2abf6f560dfd51d64f51e55f19496d538aa6c9f9a9892b3f7929a6ff7cd464974ee2d0ef2587b22cd68a39e1da7d6c5e8335e891627223208401107e0ef377ce94fce3ed253abf13fae146bc51c6c4bd884e31b2278c5886e154331b3b9f51981d4dc1126a70208a3ca781a289145de2f9cda337f14f993db17afd5909d6e53f2608ac1e7e080b2d30fdd59cc391032c6a83f2ce413a265403db96ce68ad3515c2a9f8ff94fbb694c34d54a0714a7e42ccfa0c12a86246e176b816a8418c21083f1bf6355d9496da06881045a42876e44fda61f7746cb79b3a300b19ec06ac043b005bb0eb6222ec641c80dd8d6522e7645755e26f57e462ce838b162d7ac586c8f9db8730b749039b2231c25d0edb336ace2d600decf40d72a2f6787903b4f0973c4dd37e4bf5530629cbccbc8cb4b0ff918dc752d2aa8006e669b5bc080e60fdd591746310e0f5d723d3ecbd7df2d36164ea30eada813762a1c6e385582b6743b937dd558cfc3d1d5a7e30e62c48e8c4e26438e09c9e32b1d790b01370afb9953c87cf9acc0d3b6678cdaf323cedb63153cb2896775a44336580b8a8e05d6b5500e673fd5ca445f8980250ed2dc64414d1991ab4944470193455ead75755a292f919a556456d3c70977fffa95157af631be78d94852a296206d03cc2784013078333c6488e2299ffdd66ff37aa6223c19da462a2b5ff858d83c6cfc1bb092778c6248014fe58171d1531be4278c0f9821603cb8f48e50d9e82046e24fea979df8d4c3e168f91e49f85f15c4b0a1236085ebfffa767672507b663f23de57e92778b7359323393e55fed368f1db819a3ca195f24aa9430b51ff522600667f0184c7f4129f59411f001409144448c3da41b2c3ff8e9982cb57a68b7d0ae45325fe01ab3314e7eaedd41d24a357559908aaa578b191975f7828cbec87839a9222d411c06a10a51157410e12ae42288f22720d3e11e48a74c65a9b81ca72778c23c5fe7d7fc494cf4f51561da494e5efa6e7d4e0089a6fdd8c4450e046145b4738314277b4e69524a46ebf2d5346297ab0588a04a4cd647224aa45cef2669ca1cf1cf234e446254a9ad00d49ee193df4bbabfd7a585e7c63e20fb0a8aef5bb17551b1749dc1c9bfb66f9ee1274b58ec8265e2cd288fb486bbf405a5a2ae2207b81af4772749a5bb2422b12de828e1f9abafa80e2d55492b630acfb76f3f6c610a2d3e7a9565b227df0277d853a4656a4570a1c7035647d0e512968e9e7b88333a1b60037d1adc0d0397aee6ad8f0aecef717f53c03b661d6e12775f16add8ada4d37b9e94f88a07cb726603d691819dfe7eafd050bb5295d330ae7b324bc5965074696f7c1bee4709d623a448d3d517ed15a7600034adc86a32e9dbc2f7a1f9e88527baabb0fbc019dec498808bed2e0e216c1b5151ee5c5bf0e94994a419742f038b39773a214aabe9b90620f90f87f2ba105d51f29d48530f750e29026418fae038c24cb7e129d2bf8d79998f0b4b70048b3b6c5e610356c7356744e5dc4c3fe67a3b19dc5cdf57a0b77de7aca6ad4d11e212489162a44039c40ae97798a0e170be3476e8dac599e8f1f1ff8a3a81bc7435702d7779bb439586b1581319b1d0574c70ccba8689175b714dfc959eed1a86613dbf07c71c5694d6cbe369e667b6f720c8c99dc8d1b1c460f2a68e2824dcc6e26deb1eb5c9d8aacaaf5c0e2a44283d8bdba2e5336973e0ddda6969c05a6bb45a4517aa7dd1c242bdfb06a3dddc254058fe68437f0008b65cbdf9c3ad46817b1b3fa63d4a4f534743d7d65d7d244aa69e79f842e4c728aa3ad5da317a84da03b251a1183d9d7f478bad46c147cf5d8e3eb46eed49eaa76c91484f6b13e1affe0968b1805a17d8335816d455cd6e9980d1a388350797ce662c190d89bf495a116b6b226461f5db21a03d461b424bad123b5a7cc03e7e86893e2022b43284676b7d131755496d41fbb2687b90b9a8459a4b8eb6b8a1f053ec31bf9e11d55d273fcfddfe680b477739b078c0d03e58d04985a6d579016c572ee147642c8439b6434553f284abf0e9366bfdf1543387d87246d233c76f092087b0d90c55c07293928a373392be273713073892efb7b9b212611cd6e663b2127bce39fafccd662ff640ed44e7a1d61b4e3a344a5ccc34b1651874c4dc3b96bf343118b044e7173741357c5a43c141f1d73611cdb7e1c6de6e4e9443d1105fd3b69a4296aba2f2e8c78c93f3c16c1e2dc965798a7243849b4e969303ea2344fb01551a15986e5b662a32f25b022ee72bb4f5b03525bf2671cede714ad62d64963a2eb099cbee5bc24d22560b3c6fff87c9b1ffe39797ae23b0d7288a036275585b887f58e62a3677802fc493a203165c17e8935babdc3ecab7093ae576ce7af805616b0972ccaeb78389663a9568733ca9a84a8a789371e9bf33dc3c3b66a15a988a441f9a893f1ef373cdba8f62e381f1aee775e5d1b1829afdbed6e15c093114a334428be656271514a2675367bfb33801929a9867c9fbaa56a16b22addbb3b5113f3ca2faec193f4d521155665bc3e63a6d8bac229666c50d3b5a4fd74a9d5572d98c982a07a96be110396cd1611001652bb9b62616ebf50fb10628fd91732a3720e83322000f10cf8eeae77a1211255b7c134412d454004fff1cfeeb204cffb20dda4236ec1708edeada2af7ff860e025d43c4940defe22079b0516213bac8cc3015521e8f3eca68819e2338e0bea797890702175d86754a332112b6b97ea80adeb7fcd8ee4ee64d3e6a912def9e70c279abc7da97a7a6a61c0157808b5e6d7cc51482f10508c543c4b062681c4689fa4922803abdacbaa8b1b6256aa9e56c81a18819289cd3be95bce0baa9c878031a94f1b907da908a646c498bdcb75c307f3a465fa010f75eeae118ab5c9485b5519cc8e57e66ca17ac24c539f7836f1c0de0f6b670187cec19d99098dc4c48f6d9d4610a1dbe1c08bb293a51141421cf7af2389d8e716dc034e450602a5b3ab02906ef8cfacb5967d29d9f3d990722091616f4c5195075b74dbe883261b99f8369de27789c2410fa41978c84b5ad86faf66e7da3395e83966877d4030496ca26868ab761252228757ae69e396644581cebcbc6f308c5806e6f058a126620929089c0169168d12a9e6ec9daa5f1bb9c99c1f01d621bb9ce1b8c5d25f05fb65c295e1ef62cf1152e41a7958e953916c0cbd0729afc496ce34373b6143ae771a4ec20e7d4e47bda12bf5586b80f6f2fb18faf644bc85a70e1b21b8795a194cd84d1b8ce4368b5a7223c7496b730b0ab411c04b21b543950e4b8e40b52e42bed8376e33adacd304537a21b55c2db0dc2f5ed86b8ef3528e06be81cbc404f6447528766e3499941c5c3e44ad5398dcc2d6646ac43dc4151cda488f91bdf5a2ded4064811b345d603a88cd04855a73b89b77a025d987d9ccd47c4f7ff8eb5bba1397eb0da658fe7ac7f652e83871730755b9ac42d5506152886132f2e1b1b948a41975948d8377d539f9f692c55f5158a9ee0308e656c331cb0b20b3cfbaa36ee470f7d67381233d94f193c626dfe1bc3e535e5064703906370b143c19c98f73229964fda7200a60df73cf5c4286be8cc471a1dd3b96e38d868d03da97d6f3b60f43aaeaf54b813e2682ad77f53a012ece273980c68ceb7ef33e5b28fe1fe3e10188049e51906d7d8a52fe01ee46b01768aeb3bf4235b55a58f92050a8aa9dd0707516dd1bfa32528b8e297387eaf98289d61120ea6f7114d44ee61ef4a0f45948f75ddd1348164333f3d048c8fa193004758f3c025599729ba9846a4e6d30be8b7b2a4b28928022f24f50bdb6a78278e85455ab614d0cc66e4432f12ec64abec544df43458de14a49a8c818524a296e7955a5e868cc880ad5e0e27ea081fac8a024268aee4d22b16b6ce33280a57652b9bbd7207c946f8267074880f0f408de55192d36cd90fc0807e59184c208cb7f9530745d2b2136adb366fc6019a3c16aee302aabe81f137a9431385e050a24916b4960ac98356b4cd27a3dccb1ca0cec35095532fd843a2f6e22929da897f2c8e7783bc1987ede1c7e9af039652b154d1269396e6ce931c1079a1bcdcd8fc3b36239efa42798dcfba6523086a0dda2911f45595ae6bb43e41ca6cb93d35ce65f1320b2b810483c29e3a3ca5f19ce49c6d708345d85b51bd69020652c66215ddb420dbd0d5fe9aea72e13754d76280f5414dad6db57b972079b93f9d44e59ff16676d66ec182b8db41c08f501327ca02ebcfc86540a99cd24f6d9d1416a863545e421e204049ad500ff3a422012a5f4bd8fa3b6c4a8be864aa803b3cc8eeb6bc4e6a4690b28433456b7f4af32b680e573c9bbffc198e021234b4d1364c482b270194aa9c829ca740e4d81845b57b5d96d4cebb6b7a84c60c214c0429d7fd51090884bfd81bce65233fad1239fe4ea8f7656311b23ebc67b074f83433065c968618638635548e8c0c2cbe12dd3590b1a614d9eebbd47dfea0b5cf8afc2102dfd879d15a150b3742a54666da94c3313298bec36bc9f17f504b0e6c4aefbf2d52965b96babecc9bf7de1fda17639da36115c4e49b9e7040449b450630b7af68d4edb83e6b3fed20f74373af5f46a284c4ae7ad9b0b36367d98a5144eebd74fa556e4c2576e2a6671b790845c335429fb8c3a921cfa7ff185cb02579ac583bd540b38f0bb6f9c4c3c812c604fdd8a29db41ee74fe326cb2e1faabc6857f453b6d63a47626df3ac9be96861b3c0369b8ddcb053a06b28b1a527c3003bd9874d0d30eda80490771af423b838f750d28a055565e53caac817771a6ae4bbc915ae3cc2d0a229895e4da723ccbbfe35e219dc98e86c5572fe90b96f3793814819a7d6e535f51dc11c49fc89161eb5d4197a4cf8c5a2bec838217ce813402e155b2b260880c6dfae570b45042425e093088d3a53ba2b8f658ce30b2833c1bb1ec38a5b4d3f28d8ebb50e21f817215c7b3f8d03cf6d35a4c02bb321c431516419a8018f29e448ed61c26d21f69ed57a2ffdf40ac8f81232775ea41a19e1dd5fc2585b0b41de66cfe55fde106a0c71f827f140eb5d9019ed8d5b261182670605753536cd5db6a411c210147a82416d6e4679cd822561a5942563349a23804840e04b98428ba6a811d931e0a330b1f1ceb949bc5bcce03c5c2136c5b55f26df9652d2519cda952ba878e484860a973e362dfba9050581461a18246e76ace57a1f128ec7198418b37df1d975655d4c37b8485c564b4bf435c84b5f0f3f6a3a2c3ef23d8f6f232afea000d4962443aebd4ba75b6508042c24fffd599056a95964aef3eb455a2ab2ef59128c925b3228ef2729ad4614c73e1e4f1d2ac163cc39ec16289506e079ac9241c00f317b9e5fdbdba10ae93aad6c7d1f3ab15365f7ff22c980bac0d154e9b8d1fe14607eb789f7d7dfa0adefb7a414633bf3e15ad4bede022e0693c5c180abe41b4fd3afef4e96e0570d7d0c791102005f0b1279771fc8878154d639c49cb09373b8733f7c4385939d4d17c0e68c19ba83a702212b4847c1b918fa1cd3eaaeb8475125d212d9b74b938bcd1849e02fc0f2c698c721d54f2a21fed88685f9f737de5e6e0b12d264ef08745e4e6ac22114e90f7d221007a8be2b1af9114a47cb1fd4ad0966c2aa3007108de68946129c92ec1be8bc7de5ad819e1714112797ac15a4b93b869134d3c959e44ed82239e01d4885641900f43c44ead74cc98ddc528a7b8497cfc439db413178ada18f53107bb28702d1378bb0e6435e4f908ea3f0ea338511a88e2c8da015bd772ad1364310a6326d1b181be477cfbf3c69580712385b5caa7c386b9b54601cd6f5fc9c4d19a3719623f3eaca041e8cc6cba0fada6a708c03be4719eabef29fdf83715cfcf2840b633f771d48ec824cd0dfc1a5a5681b47237a8ce384722703387781c60bd40887494785b5054a841f603c2c5bd1550779015127f1f39a8157cd1c315b75343f1dc1b9d982b55f4dd2d2b31c809e366e242f17774412aca3e233781d1f0adb7205840ac90e26c9530307687641a6bdb27133635a3de863f8db1c278e14cfcf9dd9aad3697fcf3a41746150edd7ea4728c52da708599d7dda72ac79cdaa6ebcf558e31b16d77cb93bfa8a431be6cdd6ac79af420d11fc466e2d3302109a5d8484f5d46da134ffe9db3c7ce438d443fc0aea6918fc33743ffb83b0d3ac6a84bd74ed89975499fd4175fd3d0203cb719faedffe9767dc836828dd7787dff24ed9fbffc7e6cc4e2bd429cbc17d6a4f83ae15617d19d8ae6ff90e799be8332c7d310acc9f2b3a45b87bcbad015dbb141f589cdf0ef02de9dd2c384f7055824f3f1ff14adc25a03e2823b91b5dd005ae53ae46b31a691a89aca3ca89ebcdfcca33cee09cad5eb6aaf4978c6ebedf06454a6b5641dc15ca8fbe8662a3ea518ab6286a40483d8210af0bcb88228be070aea2751928926a3fcefedd7ac2bdbfd75d9dd24b788fbfc2ed6f923fe03bd379b056cb2bf093762655e55326e9e10bb12ebe90c1003d1fa101d7f82b5c6f97583139b3f7d5cb8d79681542e6e12c0ac5159527d19eed2967a9fa54d378eea17b188015d9f51731ea7465c4ced306d394e7f75bfa22a6c1cbbd743de4aa9db0735e2bf2f9f7cd05f97d655a9df117aa3af3094d8a193f7eddc39172abc75b6ada8570d2a41ead81888ee706563023d083b310692bc37fe1c334f99737eb40b4d1cf350d7cfc001e9ec7810b3d1dc19369d3b63c06e6cdc0f094d3caf26d9380269d22add88b4677360dc6506af88324c29b15b26b8bbc472e1b44b8f398682460646c03f5280370c0440a382e0236a948a5801a9bb9ab109008185786dff678c6cda7010a919cf6079f2ea6ddb3a5f4dc10a41f5e9cf00deefaf9a2389171db4eedcce667941c8b3d7439b0b37dbb9edbcd8373eb1bd5df4658432ac0445f9642352afae189351197928148d4a02cfdd5f27d0813e2b09195068d38289ac87e951bebf0148042b1d3a8884cd814abc8d4be25cb07525850b92391673b0edf5e87d8b762a4b5a534a0cbbd28ea4603fd0341f30f1732cc20e80232a159d440242e46d53a328f7e3e6460e0761663f2441a06de99bd9635ba6c47a2c0bc5e9dfc91de1dc409712af638638b27a6a08a13d6d1a48421d9e2e682c7c807d2a8b96a666392cab9c19120ed1186624a19afb7542adc35b4884913dca231ca8fadb554df94b528b1b00aa461e2209cf67cd46a366bf5a9e479386e5e705d268ec2387246102e9a0095b0bdd1fa1a773781266ad75ca2894ced15da322d443032886dff68944db2d6a6e593255fbfeb00e2866afd66a9a09b02309d6acfd6145a48b82b4cdd395085b8d3d1586227669ea92ca202c1b5e2b1b5bda4bee51cfd66c0138d062d70390911bb02cfacf0f14b3f7c84919eb6d30fe3a932530eb9f1754c159d37247724a6a7a8608106b76bc784631183bd67a8cfa8f22ef85c79e484346bef320906cedebdb5242c99e30a8f1eadf18117b6d1f1183391d142c8baddaeeda2231b1b083e1196c14e42e6a59d198b6cc40975e0bf0453e0733755d62d967042e82d90cac6d6cd1b728df6bb9a7bd844ccc8165d4a3f97bbc8fcf36e0e1ac55b1cff11e795b3b9656dbd070225e3df0331e405e0382a16673835f0c2a8a75e8361a0b58c7607c4855cc0b2f70e7a61eb35453467f6ee329496911ac00c0226b08ca4625e99a7d22f2ec804794db70d342f975472aa4d015b986a7713e99d44ac2ef876dfc9398487eef0e9dd8da84113e4318590374c2c5dc60e2e767c88b3de91cfd4e2511529bd4c7634956349a550305bb1e65ac4184b7e68caf9ee83a574c0d34b5aeb168799b14e5a5c539b36bf0b694c5b1668f553d3a2b635274ec069a52ebf10b1217b1ff22f8be516628c2985264c852bc7416ac2ab06bac8c1adc026109a91d338d0db4b5c085cff666628278041b1854a9d15f1e245e470a75d0ac64cf54fe8a1fafea14465eb2dfd83eb674a3e9411ef17793adab3b5988f5bd0ff73ee29ab0cc9a1e753d152b5a83633554238457f0ee5b53722033dec41c7f7d3892312f6e10be07ebacab4c9fbab58d6735355344a5a46c5b1bf0b83f4abbd9a5fe6e019881a40ed71402de7d320403ec713141709b970a6885ec7d38358df9d69c096b4c6e79cc59d681d0ccea2328bd199b1e83e7aa208103b1ee4e7e359463e0027fac323332a32cbed6a14cba610e0480385147cd59a64bb0824dc7c1ee0270112aade3760e5b2218ac60bcab7b27485ca4180b32caa1ec350e38da396490c5f8390b7a9a7b8fdc20aada574808e7df0a5d109645542373c03075dd3e449e6b2a4e85130035524c0a500e9e23f5dd2b3049db73392b78c58f156f2b88844d0c8310b1a242732dd58109215ae4d1d0465d4636f928904151ece1531446b08a8abf9a11c416eb745e086796bb925cf00e438a1ce07bd1f1d1c80377a45f0e063e7c05c0e2ae199b49961eef270e9c5f1309c1e66ca7c4172ebb2c9cfabab0c1b8ed4e204416667acbd067364931d04bf63afb44531c7ef5709493fe709e331f668420700c4463cbad318caac7c37f05595edcd196e99d46db361048584f1d48f9601e23609e25831e1b9908a21ea7d14bc33da2e0082cf956e0a591fd95fef3db1dc74df026089a979399969bdfe6fabf09a4a7ff49cbd7ae06eeb182e01341452c883294ddee5a4531ca0497470c43c71658d16e1cbaae7f4cc573f1f585566bdcc98ee47cc40bef2e56b42b3e9874ed8629e83946d749745a8053be1117debde8d94197aa78afd5e820f072c2c650a380b38db98700c2ce3737afc93ef8d39f13bc5570e248a8f14595dd902576daba310c85296a4773bb5d3757be046da5b723c6e359209c13d76beec64edf3a7d44f3d19965784fb0a6a0e7f751bd559b8b54dd9bfa54f28022df43b2083e0762431d757362461b2218ea1d76600a4290394aa5f2499c5c62152d548a59949780680ba7cdb3679b4a7153ba17b5f3b62f71252844d96a0dbc980d8c3b164b2301a30438ff42fda8ff871c0dab451f10052e120856104b0dd3cef3ad2cca4ccdb653b7fd6edddaade8d7c26a88956461477326ba0ed5d85fd8904062c7c3369c4a4135b69528f53a2c87ca67eecabaa035672a6d36410842af8f9177d98edc10c913952671d42660a17c7635dc3ac33ed6cf1f96a0d68d4fa70ac88d01a27124bcda088eb4dbbc5d704443cac00651ea1841fb0d2f158b6a3e1e8b752b981826d83b653ceda04ec35086f65d73a98f4ddb16a4a55e55fdc664e1b4c9553582858ea15b8a7c3fad7b588c32d9719c8d30eec94d55710b1b6cd6418af91b822cd9f47a131097686a9ce335164671879d0f67ffb135e7a1c0b97f1651d16172d741aa82446e4f795f4dbe4ae184ea3fde038927f719bc6b32bc0b2d97806c6fb8791304c76471974a75c8402bf207ee7a6cee4159c7a5a11f7db4df4794f221ec888eb0ce6fc08919d23465799d850e6cfe1faa4f124b6e6087977570b7c55f5758e695eaa45e5b053431a0bf4fcbecd9b175455e4b2333340122c2a2ddd7a21b1bc4f78c198c44816188a106dd44abab91319ca8be7cce96ca8f5b5faf16b44343a4a8ae1a26ba7f9bf7398b76ac19f232c68538a9c8b416e13913f2be6306a3e614ae8cb3a7e7559773ffd74006652f727ede8245de34e25c8268e8555408b176ba37942c038a4556725b409819a7036bc54010534b2f57cb56c8b1321ba08f0af47bdb7bf80848ace1e7810d467412f2a2a4dec6e9e850abb559d80e701fec9ca1233d89a81a1dc2e535ea8006f786e3634b2e191be16724cda2bdf7de726f29a594494a193e07ec061b07326b6aa5472dbad4fa06bc82cf4b1fa01e444c3e403da84fa443344551d4084d022529350511297232051131a554434e5629d550aa1dc3864140c2430c5eb7c21139046b10903a8c01cec02e2f9f945569144b5b974a415954c71444a416a9a76aaa41954835615c5377a83a79e9575d61aa3a5453d6f6b03eb555a7a8536a0bbb0d7c825996655996651984f8de135604a332a122724666599665599665539b10420821c45886d955265db3ac8d732267a45dc919e94237898b3a0915c92084104288337c5bdae6c3dd29ee94ab95467f3986979397ded7aa2fd53574652bbea3883673b118be455efae82467a40dd3050bc28860221666c258188b85b13016c6c258988905bd52980933bd3c66c24c3ef311635d128391432fb5d56ad556a457ea5ea92b75a5703405b54e2da116aa65a4b55aad56ab183361ec3dcdd3e9745bb7d538b6eb5e5edc67663e567abbeee5c59d622cbbb0dbf7744ff7744fa7d36c8fd48a464c1c4ba3bff65a3bed3d65ddcb8b7bbc27acdaae5fe2ad5476dd4bbc5237c6d876b55aad56ad28ec285b61478f6131c66b57766557766557ad9eb627567bd6cc52ecf6ac2dda954e7cad3dd9138bc562b158180583c032e2adf032d50ae2e53d45f1b23d0813a9073dd822fee87bd332ef58b16c95ad62b68ad92acad3eaa563f76ead75e630631c669ad65adf34ebd8957ae95d6f96ad765b96ca9a6134db7b7ae911637cb15bec15679a6d88ff653eab9757ce10f044f76154678ca2a8c6b9b7eb5e5e4ed99ee449a8856a1969a55aaa56f438c59540a6940c4abd8c295535ad9e5413ab9aaa299a9a267ad01562a158a8c691e2b6ba171f0742c1689ae8f2a63a958bcbb5ddd16b3e38a8684da23b0015254e90f2b104027230b4448785ee4887640912212059c1d529b664caf4358b8463f4f0bf8962d1811695cede3e1c5c60ecba73fb3ce02b1db76974fb72f0eaf67d20dbedd30100394fd48b2d7a4f8cf308994862c99886992fad0fc60067c0c019311e3db6e00c924797293843c6a3b709ce60e1d19b0567b4f0783d7618ceb48dbbae118ff9d759e1db5b78cd6ae14d67e1893a2bc860ff5686be9d85375dc61bad0c9132ff5882f8f6e924cf258818cd3f9628be9de44d5fc11205cce630de8bc7b4c0e08573187c5a71ad53ef7a2effe2c5006ba2aff0e209d64477f1620bd6441f7932056ba28bbc36c19ad18a7ff4075bc19a66f12f623eb0069f5a2c0b5d614f4c186c710a1f3df33e79e4eb2197c441e90a9fe88a5bc119179f7a7e13064d45321127c1f0c5477d7c1ab6bec86a31992e3f1d52389a8d848fde2c5813659ef45ecc7b30efbdbcf4563c757cb759848bd63775cdb5a865ac23cb5ffcec8752b7fed19f0d056b46cff9d810d17d22d10aced09c5ecaf2977f31ad9813ace9d1c926a8fb625aa3131317a798d6b747a751e403675087abd5f7e8b9554c2bc604a2d5b75bcf67445db41e02a007c7090463998e24968ce986e9f9d274c5bbf0d3e5eaf2304314f599a8ba045600c21cc09051e3460c0e58e204ca4489baecce18a3944a4c18326adc88618913d669ce0a4c4a274001154cc98061810ea67ce8f19f4fa00211a0404ade4cf472a3009f0fbd8ca8cbaed7f3225a42a6645e449e0e2f432d99970fc830114f32d0cb4185310dceb4e830f366901cf182c66790f02002d043b2e476672ad84688140f41c0a486e8614ed1cb29754ac5208854925413292852494855e1c8cf111f8e88e0c8e9080d8e3871a40847a42cf1b3c40f4b9060092388582235648927967002921d900081a40824228091e252f51c710414522498a2c7116a606487035021a2424b9b8319e347f7751da414c25a2184a3cf1f85d06db00217282cf4075a8fd7f7f4c803fec01be983a24268ca498aece8edd1db07ce8899c5d320a889b2465f9d06619294c562511605920d6fe82579c01b1bc4024909d438d6d434edf776ddcb8b5b09f4ed314d7f200dd23f70264a69dbd45a104b33c19af6ea65ac201a91079237da1038d3de6e4d8d9361d68459933561d6f46d6d4eddca0ac7711c9727ea5e28374a27e5c5a998e9ae79852567da1190a4fb38d3f787a5e00cebfd6143a6b767514c5913f9a6c2a7bc48e9a260a6f7d17458bcad9e5cb50fac914efac7a64717bd4e149cd1423a8b09c8085ea044143bb8410a94e84113258ef0ddc3264a30196203c406880d101b2036406c80d800b1016203c40648b7a94d2b205216c1d231a713652667a04e741833461ae34cd3484d062f612f4306adf693a1c9d664885a294a4d06d9b0bbbbb16f1b3794b0a7b9847d8c1ffdd34a11d6e870f0af0b8335ed989b0186569241839aa6695a94776bef7c610d8c18dba6d36b65c3c33499682a55351b363c70363cd8f0d06aa552363c74d16f1502dbf8e83eb912c9530b4b2ab5d241168bdb1eba8d8f2ecad595e574124b3a25598245609d2c93a145221999ae13fd849cce8ca1870f1f97b351b55266d34307a3a63321bcd7365d27c39e5244ae3d36952fad0d94ce8679611b8ed89df19ab0263a9481a2dbddd938f7fb9a5346447367b3fb32932965c09433b6ce799b200351caee39298d40db79e955313c316e1931bd2a66f1cd2cbed9a561dbbc346cc31de6b24e5bd958288c6c850555048ae49429a6b454434e5643aaa1542c728a4488c8292d18854620468c18a5944db349ab4ebcd7bdae96f1b2f7c2328c319c655ab6711bc7b58cdc96699acec6719a4e97adb0acb0b0b48c2c2e5aa965c58b561a65302e2b9a0ef45a7462369a18ba8c5c5c5a4697bbbd74cffb34f6f6ed4487734e9c2f36e7f4e637edd67456bcbdd865adb598b5d35a6bed75edf4eb4aaae998f9b6e946c843092990844f3a6ae393975716e8cf6c8fc55fded65235ce3645d3480e48b5b5b6d6d6ea161364e1f2b656d3c89693cb907449c99bea2245ba44912e50a48b93974e3efae7b2848a96bca153e4cd9c42de74a576fee5614b248dc4542a39832d59c11a2d74dfd6f29137ad29db141b15f2e65bf1755e9756d5814b0a08bfa4c17f7008d4f412dbcbe23153e36ca92d65dab6ead7bf2d55ab7f5baa4ee1c8cb2d15595ab046b66c445c4cf2a65b522da996544baa25d5927ae92d2d432d2a79533b4eaf81608dcbb74b8afec0d39b529bd81f3555df54adb219a28bdda8875b13df4e297702426219329a26ca905b89239164b86e9d86ead46fce35dfdb349dcc3147aa95566c94d424dd37bfe5a7cd5027fae9525e2ddb24d1c52bca0b5e6c6b27dd90de5e923d5f431281319761fc51d4b7a653dfc87f14e86d6ad055bf016b885570cc3c29b1d7ddd8f1cc326fce39b1639a651ea59452ecb86699576badb5629b1d7498dbcbc4baa936b5de9e5aab78faaa8fcd0ebaead22f4dbb41d2720ed1e38b23f3cb4b198682b08694b9e6a4cb7b5ecb37645987c5e37cb17458fccd14251de766f19ac128de8f919a1a678547fa03def847857c747aca31c688b1fce1b07acc514d2353724652247086b653148433b5d2f8613b284a9ea09b2e47269733487ec09919e9338c3821409aea9c569d73711f2b1cd3918f1c7e3b962b3c52fb8b8baff0f615390717f44b0e2feee23d2fc4c0886ed0d152fdf651ae21561901c119edb2c5041f9dc5e1ca908ff407a489dc133883d5382b5c6699f4ce21bcf1cd6732051279df28e873b132faf1f573f9e384c0b546a7978e791f0eabdf415114f5d6e9e9079cb12e1d00f046c85b97426ffd02a2264863ddc50bd2b1d666085dbbcd50d6da3b28ea5b89234a7c8f50228991c819e19c46584c2f81e04b0cce64cd3f2af4d0e9095221909a204ee6d0e90f48233a0df2d03953e36c99b23267b2e1728af1cc32d8278cfdbad8832f5cd7b30cfef51e76d043037cfde3a3d7201f9d0e5961c1dc4040d663f114d248bf1733cd39e4a5694b99b0282c2aa64c912225caf871a697ce9938225c90bcb93850a9542a954aa552a9542a954aa552a9542a954aa552a9542a954aa552a9542a1b51d3a13eb0a6064e1d162f7bfac5c79d80e00c4b516f13854e7af42b0585eebb36159cc18241789abfedfaf9c1cd66884efa47b1a09f6ee24e47800143768c4d23290db64ae9356469ba9c5396f07575c38011a76629a494522aafe82713dd97f54caae190d7a7cb3c610dac69995a09879c5a69c57a751f975fa71a4906ebd569b8f2a55aa9ab1a8e98a356e2ee35fd0686b51968b075bb1a0d36cbc8329ae6d2269c1eb506c09f594e6d06ebf501366b250be5dda64f69b51b4ad84b2f613f1d7311d640ae143de64b2be19f4e6dc520b6b5b75779a83580ce9921f61a983d536a3f983aa61e9cb7e34837e0432fc187f9c78f87def398d6607f3a8e1a62154ef3cc7d60c73c063d741ab0e9a197ea4f2f553c1dca58a5045fca1ca34ae7f2d6932bde76976646bd3927cc538f524a63ded65a6b2d91de5a6badb5326f276aa258ac562bdb18b9b41ca2b78eb1d8da8d9bbde65a1d73975fbf32bdb0461d166f5d87c5575bbd89d2aa4baf7ab5cacf4c81600da440f575983d57e220501f09838892787a2c3e86c6a13ed2dbdd690effce375e980ff5c180c01be81e5ec7dc6db07156c7560558272fbf74f0e111abbc8039aeb5daad066880e8b3eb63b67b60a8759e99691a48a2e1baf5197a5e6a25fbb3345d7acf4f97de9944bd3aa9bde76bbe81e612f633c312f6325681a184dd90c87f33d35eaac00b9872799004ca0f5050f0ac1d61443205c913628cb285d81e349b734e5a8b1461adbd300735090cc3301e5a3214e57202b641428330312609c23e4018879c2411926d045c82285cc40a18e200e5b3874d98487df42ec24026a230310542d8b08658053ad4463032b1840913133e49aa60820aed874d94f09894076cd30208081121042554474032c40bd489a7bd022904e9eea513751da552093d14b9b5c990169254a1bbbba377476904dab165eceeee467df4ee289148228897fe329372441cb1238ba7294f1701c6880550b400c68bf9024ad474269c26e8be6e0745bdf4e3884a1cd9c1479fde0e8a9a319372cccc13bf3d1a01437903034480e108521c210ad091204e48084267544191cb24c9ca87cbefa52d3252538e41a5a34070c65b4e2f9d005148527cbfe9d52fefebf9cb2795316239837c40858c8bdca757963ca7b7788b7f1de45776f4cfcbc41825144fbd78fc781bd5349ebffb2e72c7227f1da945279361bc160ee3d9ebe1021927b1f046354ea7babb512c3c198ff1eac3c8788bb7707c69365ac8f895692193294c0b219d6a9cd3c7168af1e6b38007f83aa85fc683b006a645867286e4c197dfc283b0a6253e0bcf23c96415e46ced06e330319efdecc1acf044eee28d44dee22f8ea966e3258bbc6a0ce8799128cb1a30055397f417af532df25ae5551395aec53117c9938bd7e22e1e4bca5b791b2adde62e5e07ddc5e3de864ad7b98bb7bd0d952eba48e42e9ef6239f8fa29c6db058afd12c5efbfca014604096e9bffe3ab6feebafbf4ea53a55e3acb19d362a87442209107cca855c2981037ea6c8ccb737118756f8bcbc6aa517ad0e21a53644ae2b7a1768d4ef5c5e1d230008dd28f5d5e565be7ee5cdc65ddd855df8baa85f9b6b2ae8e26ff7621d47e59527aed975e9bd1effe6afe9903b4a7d0d5943de8b3b17ff7557d0bdadf67bbbae5d7cf4cfc5760afa728b100ebaaf65757ae92d2b97bfa6467d2d2b58e193a5404b71dec91b2e7ff139ef3ace37c79b778de8e2733524f54af1a593cba5fc442fafe8d7a6a57e689e4a2b3e5e595bf3646300751f5685e08c485da39e51c7d431ea1716a9d768cdfb5cfce59987bdaffbee5ff9e356f057ce6c9139a7166312d1db415194ce1c9fb031a8b4770118bfd39e75bc3efddb01e3af5f36429d75f8d2e97de9f7c63cf3ce741a0402e106091c618911a440048f253441c50638e4e4678810471821c4112f4022c4c4494930bb9f48c1c10f8050727a2283090516fc9873cee983227e099b223acc67a2b4d284f1b4566d8699a699569b814e194d331d576b6fa51a37356d6a37caecd266909c6bce695e43562e97b0a799bd36bbb4e916d64cc737c3305cca6694d8cc72a695209ca170063ad430ad3427acc159a665da0c3498e658cbb026036c1a1ae8582bd9d71c6730cbb22c8bf26e9a6bf96230629b73dcf44dd3328435990d09ba1dec9232a80fb6baaac0f045931eb01e3659e2e4000f9b2c996243fc0f5b714fd8684344f7333ac119d6e5d55dde44c96ae90fa5d88a7be2db6d88d4c351e56dfeaa471df27348b72e337c8ec33a4cb482336677badde9dbafd5b7cd1ffdf908a5cf7fd54939ac5f7ee59dcbadc3875a8efb241cf723e5b876ec95e1f7bc9452b66a152ca5c71863f476cc442062c7d93901534ba2441f213e10e2831ebf43f6a0072d275017bc410240c56f2728f4a0892d0c010b21b84110a2a0248806551c11e485064217657ca5940aa59e523a638cd1af135ba869e28416a43f6ce2c4109c587d742aa2d9f98baef9db011249fa4e74e8241c19f6c4f802862f3e9a7ae98eb1ce1793bf891d6a38e6f4ce19cb5f8f63ded750011d6ce284e9db599cf0c139e2b767e079fa77361f39d46060f1ce5ce49dbf16bf5e43c6b8f0d3ed603e1d73cd31e6d1d663eec203d6b7b3388ece3b7f3bdaa9a6633a56c25cc3b9310f730664ce7963d9859fceeb1c2b8ec30a06cd3b93386fc77c7a24ceb14f12977530c78e1df3ce31f661afd867d357b20b3f1d752cef64cee51d17cfd9254774970c4799a79fe513e596ccd3bf394bfe74f8c6d88b1a8ec626f09c570dc784e1d31c3b96a79cf978fab7fc7de0bb1fe7296730d73297bfe93c8d7d3d507ecffcf1f477a7a0eb5eadbe351dd8e5b3c35da7d3e5afe7356fef38ceb9cc798dee569cf3a66b5e863bd734cd3bed72f838ef5c8ee1b832066b4818ae761e34e141ea31ef9ed3a7c7791bd8bc3ace3bed18e698e3b0fa155fc91ee77df13bd726f6e969de799cd768cdfbb66c31cc6fe879eced7d38783635e8daa76b7e617e5df3341d9c3f1d1e73e899c3ebf21a7d79186869e084c3aa694f59c50e543ef606e2cb2a76a8828e22e704013118c223e1077ed8a4092700d5296260828eb3410bbaaaf2418f1fa8aad0848f268468a2044da4a00916a84ea06281ca886a072a25aa1fa888a08aa26a820a0a2a1e3cb4ea07909c826a884a081eaa21feeb5c0955c98a472b69f24309149312293ca0602aa14209159ec0bdba9a40a952a28f2ceb1cf01c78e8d3db31f310b6d765305adbdba7c3d301c07ba96ca1caf34c8fdf499a51ad5de746bd36ce6df1d583d5afa633809f2e1ec6fc0cbc5efce9beee657bad1de19c1bcd73e64bfa10d05447a4539252a28488129492391fc21a2154235d900ea853c283c7f6b089121e1a35e99c740a12302822074cf08962c90b73c9cfb9022dfc9cfe4276fd3adf01027e74970707a8e20756caec3993f810248990887bd824090ea0a055e88ce8681294900eba2b74b6874ff743571f36194a02483714e587fb8b21283ce12627fbdbef953ebd24f39cdf2e4d704eccc52865293accd78b55beb394b38894733ae6e69c9392a4973a2e51eda48db5135a25ebce0e1b87738c31ce1fcf8c894125efa0409a9661ce838d659ef957b6393fbc745788e9718ee9e600e508b939262cc72465feac5f380361e7fc7ae779e62b39f3986dcb5f96b98b67becdf28783f30e0af4169b7e5dddfee5fc90f343ce0fd5846d9ced3cf223959f75d7e8b853430e2fbd6be89719cee7915fcc3cf2a311f4ed50a4dee66113288400010504a0c7ad4987628a17c0c32650ac1ecbac6a36a4472d13c919e8c20f457d96ca0e8ac2bebca396be9e9d2b7ff1e69de86ef1d3fc459fcd9a59c0f005d67c3a9d4e93a046680e68ad34549846d063ecd65aa9f3c81d1959eb6dec513a751ee97df265bc52a15a1dc25aab8ccccd304c97f11a32dab81e3d948bc8214b27351d8a92f9bb5dccdfcb4f8a9af9ebc9414a49a308f67630d7e16794893470744ca3082c9377b0633234848821c9e44f3ee6a4fcc9c73482be7693658aa6cb74fa0308ce20f9cc1f861df3afe6c06a26617e9d62cf367f71181cd3699868108934a6d739e7c7233f1a417ff3ce7419c7ea5d317a81f195e9d46f95a5ea3b325f4d47f6d53b13cccb96cd3afd5ad5634cf1f4e69c984c0d396910f93a499ee6311ef6f8e2992c0d939ca1186b451e6551fe5e5e56f2e7c205ce28104d515a69cc5fe45c6aa5aa39c66a9cced4188b3ee130ea773c4f1d91cb24ebd86967ba335f574ddf9d91ead4b1e7c24f47fd72cda340b006fb4e36351dd9639f6921259f8ccec8b7d31022d2c07e390d93bc817fd108fa69e79cd36dcd34848806a077141357482189cf9ec55354bc0b0f9b38197a27449a487927451e7fcc31bde8f4740ba24554a7452a35d5cb57bccd390fbb9ea53f1ac7acc91ca0e892476ade4ee63a7ce4a4ccd1ae6b9a57c9e958c9f921d2905e7734cf78e4b3e858c99ffccc59f2275ff31cd3578f315797de173f8b3546997734cfbcf67f357fb327071deef7819c22feb3ce2377a4ebf0d5fbfa5fbb3958742ce710f9cf5e1d9f7ce91673abddfce598defabd7eaf7fd36fdf7baf432d477579657c123518b2ea377fb16652e6985ba73f60c011bdea885e3d07284748a451fdd6979e0b3f1d8ffcfaf1c81c53a79558bce61d16acb26017c358b69bbfa85dffb821eeadd5b12cf558a39f55f85a9daf79f4abcb68802f47c85fbf6af48ab759bf3ccc5b54730e1036e4296dc10d31e4a9144fa9c778f9878323c5cba85d9a7f393f441a5f6ceff287f30487f535db8f67c6bc53fd7a74ccad0643fcfaed008a997455f86488a752f0f0ccd79cf30fe7c967d9859f6e0705fae89a5bc72ecaf2c7333f9c27a5e83b5afea2d574641f04cdbf4dd3f2b7c352cff921d288f9cb1c7b0e90bcc139a6c768fdab0351ca8dc69b737e8806b099e61dd1693485122b253d564e744dea0d563058d180c7ca064ca4c0440bab134c3a27d531411227f811a404422042142b1128c1a3c35230420bab1d280e9ef0c08445a52082891026262622605202264598b0800912ee2f98189112634720386336160593824dc1a8c03db0104c04c635bd942b79b3e2a1632c39231d07991ac39e1b8435d15dfe8404a694ce19a448d475d396e6bdfc3a0d97d72bdb3a49ed3bd3a9cf09c4bd5d6a2abb679c93b697689632574aab5f6b31b6d6da1d8d6a77e121468fee9238dfd91c3b976354e9362350ce582d6a526adedd9b37e79c9a639a6d1ea594d2cdabb5d65a372f46902ef36b254ff4d46aa5520f59d6ed966304e92ee718c3242ee7c85ed31c670cf39ec7b139f6d29621acf92a0a3bd4b64cda9c7312f69ee7f20d5bd6197dcd50ce5cf9932bd4f42f87d5ef683cc427b4f989f0c58753734e890238331d7a9f244e3535cd0f78534f72c624712eaf48409a693ac99b2a5451006f6a0be0ccf4e9989e705a20343d01428dd3404d93552179d3404854a19f1dc4e6afbfe6e90d04c4b96e03d9a7d7899c0e054a942852a44c99f36ba09fb3337d126387eeab425f157a896b0c1fdae18be8ab183fdd77353a29a5a91435996aad3595b2d65a9bb577efbdedc5e8a1fbe42a460fddfd562b958aa668fa20eb8391758c1e3a68234695ae14db0748a37e83cee849f4e40aca77efbdf7bafccc7265c2a680259d33607e499128765d15895a4a0d0795f7a9637eb98febd6a7469201f3cb69c0ae0b7b1ae3072294daa95f1a8ea6ad95b2a78eb9dc7544c071b5127d4ae3855e43ea307ba8a43ee8eeeeeeeeee26755718bbbbadb5d6ee54976eab8ce163e3ba9b738552ca526bad2dd65a6b45ab953cc953ab954ac5f091e1c86ec86ee81e8d46236bdb664a60d8372f7246877743ce90e04d0e38836550ffb8bfd137e48deb803802f8b89f75abc17e3bf497f6ad777720ab9968b97cbf48e9f68133ba00b1d69c77daddbff367637ad32950a10a53ac70052c4c91052d6c818a2aa8d02a3e3f3bf0e8e183871e807e000922c40758236dc45c7f8035d26d44875acc15084a5b90360e1d9234d297bcb81459808f32d3562b9eb2a8646e543639ea98220100000000531540202818100a0563812448533952dc0314800a8194406854194ac4519423290aa3203084106208000022203023344400bc079fab15c1b8190d47f2efa9d1c9a4b66535c1727dc7b89aba75eadd449990a1590a8447a12eff6c341dc78fa15da0b70c6404e1641f62970fa40081a04aa427462bfa5494886e3305faf8618ac21c4f20bdfed506a76df753fa18009554e93922716c2da9cf3077392b02918dc7408490ef953dce5cb12d64319c31e96c949eae05d4e582c2390ca53364a27b072f1173a695a61bb134be112d7f42086fb8c24ce4c9eac10f1955620045d393f80bb9c45fc65cd69b57676509ead9fd19390b9007592d0d598ce7b98b3a5a83dc3b2cb654fb3bf030ad1b5a052154e932ad7bcd732b377ff0f7d389a9da373ea1d36166356a21ee4b72a53f5b85a06a78bebeb299428b3357070575ff4066db980dab4e278578edbac95e442daeaa3b639cb7d50487e6ee9fc3bd16bad08dc504f5cc973148323d168d2a080ce363d02ae153695a05904375b9b6b61dda26d5b8812674825c944ab1fcf4164a712fad8f78c08f4792eec2ef3fb164d8d54eba26cfbfcb2823aa542723b8e530e22d8fae12bbe282286c86d2423054697842ae92b61a6bfcd7d8dbf0d85c000fd23f9cc5e9e1ab5c82b2186011ddaf77250cf2a3b69ee363d0b329c1a73e4ce86482c6e2f26edcf024f132220d78d9aa1f6f062d06d6418648c2a5653750ac58f0f7304cc4bf8e855f66542d5a70d8cdab3443b5426d86e17e6aa6e89b765b1b5480a619a1f647950bf77560fdd6ce57cdd4f8d66f95ef5b2fb4597103a4482006833bdc9364dca389936b4cc16a173d8a7020122aec89f7ceca002e668a657ce8b877c217332b10d8b4e5d76ee4d5ecf791c0c81a35916d91dc507d6a698020dc54b062e16e874a8b726dd0e4b30346c1ac2511b7ecc2b5d920f7d9318263b20e0fbed6674de9d4c8e7963e2d19d2eb6d26e19ac2a0ac836f4a7eb041c95619b3594f35698139bbcc13a4a5394499967944c16588680a8b16f2c20bedf15ce3839663c5e7aaeae29a52ac5e8e9f318906825f3c364a112570d38835fba95214815a795021b1d87b0d8548fe3ced4b3479f1ba6e36b2b1523b11493673d9213cd04ab6d32e736ddacc69cea32b999b52fe65146ef01bcf86f567ad095be65ad638852c3cd928ca9bf3b46634035e401929bdcce11e19b581b8070f0a25725b8ddd26f13b9ec261f369bfa86a5fdce87bd4fc582e017f88c259f17b1b34bfbd5b44d778123283d58ebdf50ea8a039b83bdfdae18233bc2e3e5c2aa8f7dd7012d6242a254ce620c26e68ddba5b8fef8e05682b48b15756d51fde8f95af43329120f01a070d76b5cff3836aa5d9566e561731c774967d075a4bcb5c89b50ae591a9eb04dc137e88219821d4875bd5009918870fdd5018d7bd9f9323de148e70500306371c865665b9e1506550b4c454d66706a12224946a5398d234fcba1f616acf2dd2cd42b3a9943a24991f7c0730dd224a4cd2fcf28a6343125d2cbd49350ceb7255df9a0b422347fd3cf680a5fd691032d70b5c23fac4394583b6d66f2a677a1845b5a02a3f2da3ec46ad48371b51dda8f7a502b16e21309831b430ad0d080e2c0ffb8a0d400283425d0350cc3cd89ecf0cc04c7048e4043e73df59683f3d54b0ac7c4dc699652158763cbe8dbb2605d7c6b3245f0a42eb44a620f2d5001bff64309ee3f1957c6519580dc6be4f3b9a32f102b80b51ddcd44d5ad06d090e2e08a7ce3e5c2bb1f16fa0f57a1e3574b1c551632ac5983b22c105bdafefff861f2134e001cbd5bb17db6a3ad5ee9a00dac236982ed8b0d09328b82fd0786e686d6d0b1147c6a22eee11b8ea36333c88096384c154542000bec4c5e5a66c72edc8f5a9b77f0be03547dc2041512c64d24ead65787564b6136addfc72ebe163e05b04cbb73788a2e0045f6ee56edf1a13ed2c22ad95bc5a2308f11054605903b91cff3aa303323f82c2792b5f00170535a93d0b3474c16dea028330ad7b1a7e2e982f4b2fa13ba37dc806ab300eac910b81a2ddc30f755b5170be86e1e065a30ef061cc40019d0abc34557c7d43e440350e5f9b8910fa699d45904c5424693227128f0b674fec66459f8dd7d1d7df915de2931af0f0bb8b39e84bb3c389e4a88206f4de4053b241698bd8982b4835f15699e148f98593af81d5e4f85db193589197503ae4fd38589f1c757e5313c062b445009f723d6357f392cbb52818047e7fef0d514e1119166423522805ad0131f89024ac67194cff2698aa36353aac0343ccf56fa3f5ce12f741cb236a60a682840c8fb457804d95422e45540cd825d2861f9ff508785bbc761a8a967e0e095caa65915de6060a88e36490aa5f4eb25af49a57ea153fda646dd1ba13c52f1013b1ef45a67236d8c4c3655269531d46656ef7df469188c2cd4f37e56b31f29f3ffe66554c7a09d1a4dfbd9ff2d5034eeb782646484bf24d94a697fa11b98c762dc5fd74e21368e11e8a6e5bef5a9e71d2489aa734e9325e49f5e833ec8ec67494119232439fa02e4a65647ff436eaa0b512956f8848d72e52ea5a92346bf8ed0312a5b40964b0b3a8a7a1a223307310515ff65c900f575bd7ec10e999d6baa1a8ec46130524f0a0e149768adc132ff7b3645a6c69cb4aea2bb9f9c9da99f1637a03062b8010d9f43c0d5a5fb8a60c22d00f4f40387a7ef0d1b2620b5981d23fe018a0629fd8d6e43442a512336de51b7b69499186453c87dc3edfcdd61cd00158f9ff56510770e478729a0c2b9d4710618ec04fcf0cfb27198493465d9132c5b70927c2b7c421cb0e513cfe77572aec65d2162e2a6d153574fd88ae34e7f8b85c09d734d786dc91b11f12c82bc86f50d1f3a694543c2a6d772a5bd3b3dddb3fca0d3b0a8c75ee72307432bea04dfcffb28f155e200a49680ae43cbcc65e3afabf937b1cf2f05dc6ea3543c043c3687965de42b9ea8faaa5a07de9686722520061b4aa11e128d0fb7db9c5cf2ffe3c02639f16fcb6486d2357e777d7f73f2cb8e08bb757fcec6ef55224ca8c2dba8620c05d43716acf2c77926f5cc23299d3c60d739954bef45028cdd3965ea3279d9f5fe5753c4475c036a4e4353e0004381dba3f7fdb0c82f535753b79adfc24fc8a9f262f46dd26bf668d79ff0bc64f6aa060b090edbe315ea1204046b707930f3e1b1c4136375673a9458a83e2717882a4b4f675f5d75331086e832d7ac1c9441ce7f8207d65603c9f2b622e82e6f63f983494119dba6c36db731065cd1e15280334a48974d2bfac8addb20a4ee5f4256bc88b3d7c4201cb7e23558b9cef0a3ca021cb1bcd0e4539a2a96957ca63229350ad5a5a80ded3831f50907442204aa038356c8749497239d34de3e114d6a88a24cd8bbf708b4349580eb93c4bc9de425e8e6bc601438760038ea77460375b0a783102ba2197763f9861a764d702bc0db53b7b48f7d2d2120dbeb43ec18b5225ad0351d73f408d8e671d25224746b29aab7601d787a9c5d2b6fad73c8a844dc7e06b206338cc0ca073d5379bdc1cbb4d6dd15195c18cc0b8fc2253789a8093f943b69b3f26e363706f6324133f1da439129059c6fc9112080e85d42166d04594b37f39c67910ee97bed58d81bc31086849cc18fad518e45036621951a820e87580d778d931192ab03921296186d40290ab10f0709dda88368b2ab713e5e0469f367880a94d5bc8b116968716d0512326dac13b3501570659427fe29d22cf38a831a0332fe4672a36efdd274673efc690642815fde5f735fb0b826a05ee8449442d175d7c47575e5c6af10a0241edc5e5fd59f9e8001efb777ab91645626baeb36695271568cb0e8090ddee0feb3565113cc33528fa36f5db78b997aee0c4e30e43fdbb382ca160ebc55000ee98d0c17e4bacf82da2719d160e354ca86b283c259c5196d6c9809be4ba07472e2263a92cad16695473562add723a220c178a4740e251ef5671f66f141e1f0a536133f31c4ded8761ebcf7ff9f59cfe316b2c0053c740443d20ae1043d624bee0a1ae4dfc046f963b2ed38cabb68546e6bc4ceafacaf28a11c634eed60149628938e4b1daf025e01eda10db573d56223b8be4af69b3ec47ad2cbab4a1cc6602bafe4154ae5b80768ca1acfcc4d715bf189792b5a68d596ec0ffa30147561e4b036069d41a9153a859887fcd8e1ab79dc956654812b247139456a7cbf995c2c37d1955d4a9642bffa3387af0c5efd57527d39e8dd868466db38c1ab726a9dde42d0561e859e338b6191f0cb6c50ec5dd950cd3a53197574a8c494d618d8fcfd702a4d0b6fa9fd90a40673d2cb00202cff66130cf42a5d6e93cd5b6820251960e7bac0476ffb54c907b9831d81e4430c60a48e1d7f604688ee535d616cd035ffb09af84c0092e67db3be23c3570e8b91ad78f4b60e8fb12ffbcabad5d59fe7b94fecdc97d5bc461011140b7f7adff6615fa07e0569f49e3efa761628d6500026fc021092656e0cfed1b0fd2fc6d8a8ea0962a35e054b1c7cc95a723828d6c0831a19dae0255e7ad9acb160e2f12a4643d8965c06c19877248d875ee87810ed38a4adc953491964acbd02ed0568468106058f7713bcfd842328ead15de3f66d8ae0bcd3bbbcdb093f1fc482a6d7949868f2ab2ac067dd1b3b040fbc531be81623ca763c6b98e459282acfe287cb9104e7d916134de4d75ae5733a26ae8db95e1b8c50d0882489feb5bdc801352c0e092ea7e136d3f75374c44962c067163699b1a08070c8dbc1d597222bfb2ac978b22a64b915081efcc2f18d7bdfc2078c80498b3c5d295b7bc259f1d8fda4119108d8f8708c1be92365d90ad329f0e18176f07148f7000c7e0a6ea636fdf2fc875a49e2a562ea30ea35b1c746ac1c9ea3f13848c5499e568785429055f4c328d3824c6321ee4046e35a81ba8e6aa5fdf6aa27640ccd9a6d7ff953ae474b542961ae0709e903ba7cb12400c00b888ab6450eca3adab2b0c52155222d4918e8ec923eae22fac5c773410152aba671a3bce1cb444643b679752a2fae328458af8af0e14353567382a79c39c72e1c24765a686a039484d71ae29364715852f9c32bd5e69f1aa08e100f87dd87c3715dcc14abcb37c13672d5ea6533ec192025cc177586112ef1249e7d9f9f6157a103ff9802ef3b42c340c748f5b237ecf08f1c0dbb8a069426bb33233df69dd2f05d179bd83d66d235f1ed6550e5343cf6e0cb1ba622e7b07af86f92960a7376338523c2dfe69b5cc7306779c8bce05b77a57c86d54c74c99b00f9910a9d1b56a7d710b1a6860f58f3686f08a34d5b60d015d179a1f1180aeb3c7047e2e687b7a34683da07e0b5176209fccdbd9633cabedb810aa595d7183d63b2f351c26b6c8c8505aaf1a907f06cc27732741eb3ea4b9d81766b73568350c87637004455facc4e2be39c194e62d18171231333ce78339f72fe99e478ce549a99ea4ebf3b1bf52fe3604b062a110e43511334a2ecb21a8fbdf2c635546bcc6240bd9d56dee811cd415d29ec69004128d3021b17343cc39ac2d2f549b21022e9164d2701f962b9bf9a1ae57512e13e71d0dfd72c2223ea187e4b35fdccf4ecebb5c56c783ea46b495916597131e42ddcf61de068966bd4b9147802f3c5ada04295eaaaababaeb2c2ea6aab564387adad366fdbbce9c6ed9b6e6eb0096ea8ea90331c14f6a89a7d3d7c8eee0b1e2101c0b6b4652ebd3a8c1993db12f07f9c2739a18cb2f28ea91167add6f845bf3a7e49729927579130324fa159e897e7cb4599f1889139bd83d83223be707dd1f275299ce86a8a067bda38b5617972460c8e2dfc34ffe38ee42c277ace545795e8afc28e87d5dbc167906fe0e99fe207a67f35f3e67a8e5ffed60ccd844c09fff25e7310f5c269c6a70f490c644a86756544115ae2c2d2e2a15b42cbcdd3970df57cde793c257f456b7181c213783ff04f04295e5984b094427e9892d3c10df65194bae88caca5216b8842da104230c1bfb4e721d54ff0fb9e6ff409425abc01ea2a83beb70b12558ce2a01dc4608ee92ee0d505ad913750a851a714d06064a87700d1e8ea4558bac9092fa5b8b95b6ac88411cd43b66fad766a420ff9cb2a1829a173984a8e73112cfa1f5766d0680b7c7f67124cfb05fb362f7d200ee7939d031e00f28e69950f0012105252cbfc780c73b8858e2c0069b2f0fed2d2efe957464cbb5d3dadc855f67d0168d497f7cd3ac74a64f013d95ebf4570aacb6782eb836db7510bb27d1f46146fb12ac1423bdf02f3030221e002e72a16e46e6afe630d9cb70bf570a088f09b7e9a21d247cac2c85e919bcf9b18d2dff384e80db1f6c827ca1ebc3164a75fbf7e27756de41ab596685d770a139fdf76022b268e5572c9260868da0166999979001d43356177d5f8a165a3f4caf3b82acfb14f67ffd7b1018ea6bb598e5426bf30fca4e4f9593fc395c67cf646655af291ea0ef73f07735852801edbd7b25792775f7257d2c9f681319704beb53de785b085b3041d543a3a1781d4c9c83be47449bf904e91f811820c732158937fc6d47a398ec1d7245e84ce0286522e3e89c6d987983247e0cd11cef499442b0dbab6f529781cfbd08d4bab826947b9080e2679a4b56a3a676353d9a991464a2c674915ff601dda04e74bc9a087640f9b6b34997de65bb270d6089f8cb711cef9a1080c51840479ddf761b21632d2b3f44ed13f393088704cdbcdefb30ef3163154db488f3c3a80bef789d469db92d820344d896470945c80cbe0b90ef51ac4bdfd9b6151bbfde41e3e99d12275701671c8f1a5f2a08cc514356649f6f964270782743258d4133efcb071698d84e1d15097df0aa4edf708be6361b207cc4905315bcaf8d8f59c6d11d93abf28c1baf9e99f50d481070e985876a065e0bae8254d92b515f28b6519408b1f3bc800d4c91677c944f3bbcb23372cc47679e70954205ff2d9c3818cc92b7d62b2a3953b4571c7cd14be18b81d865352aa4911a2110a85fa395d8dcc4641234371e65792b7b630a2d088dcf1a0e7dda004fd5fd0eeedefacf7065ae18bc3f0796d2a47398078c2779676c37047bcba4f852320e68167323773839e58024421d4b721c4e61e7c49c6fca4ff6c1652ea0e46f3b4c116839b6caaa3ccdd485e063b184d0abf028267640d985fd12092cb842fa09a895f14ea8a5809372828fa0100fd6f076e5de7bafc611b3126bd54bf869c4cf6f69f6f8db376c7aeefd34fc18dcee0007ddbc95a1604c99dc8dcc18bae079b0bb1962801141100b4481c3dbc5c030720864c4f504f1e879f82b28f450f38d2c02b0d22e0d321edb84af4a972ee1568936827dd2e614d683031469ab3d1f49b07d29d6c6a6105173c7aeb764e72f21a1abeffdeab28897604317882964ca5f2f7402fd4ad21a0f9a096214884a50a698ea18ac3c32ee9fc9ac3281117652a06f26c0a1dadb87b5e2a30f160e2176358beb8a396693296c29fc85aac5a3cf8b0a80325e2313c8f732a9693f43f2fce3d71944b6d239b22d0ad9cf61974b96e8efb98eb716a8141c182fdc79746bc915bf704702cbf7a655d4c76f48064f0a420d8d913987b53359ffc046d01b7eca485b540ff47e4dac6e1fcbac219008d4f847994b69e0702e93250b535e1c32982a8501aaa014e0f4789c26054ce5213a41ebe4414e91ae2b39d44bca25b736dc0a6a5c007a2bc18a784198559a2a6f0a38e3fd6d0d54385e63c1d44d7c99d9007411ea47aedce6080d86a1d8071066407ef87c0364004fdbe837ea5eef216b148dabeee06ba9863b2025105b21c8135db92fad77e8814094d72437a7c6244c5042469a6b25ea40d5c6ec945944cdcc03f8fc1afc583fd0c49877c3d1a34ab5a3af1d0c2e69435300137583be092536ca998cded924d19505e793934d5381d3a042921103c5e74faf93e236e70de478e6cab0d21462fb18ed171eea2abb07a18bd03d10e21aebc788eef30ef6bbe3d65603bb2675ce8a536f4cffd3715c86a5f35ebfa59f976d61ff0e7b811ce1c5c40adf42df3aa01ec04f6a32b9ad391fdde06ebfd6ee6b0e455fa5a6ffeac9fd27a8c7a94cdc4b4638998ab0faf12d7662b2b1f59a3e937100aafbb121ebe5bcbb2170f08e8ca92e6d7d1b65ea93dce01ace0b049f71a13bd9c8098f1a8416f8483830f8524f6da1cfd9ee480a84348abed8065cc8199468845c07d83e4fe7e073006b5f38d841e5792961fb9498207f045e87e091ed03b9435db7aaa6e0b39d2c3cfb2e6127305f5817357b9e83764f6dd2766abc702d503a1d2e5a28f7fb904a75c9d909a229b5c23e94a5567cc26cdcf1247ee10f891dfd1abe0b0202148df3d650852da3cf061c48b1a175b71bfd2a0dad29d4dce4763e149a380dac8746db84af3369923fd8e419b201f91952d6e967383d86f89cf6ec6297d4cdb3be6e36bf9ef117f261592cd80c57d6d14ac162c98d886ccaa75d5e56a00bcbc866d231aa7493bf3111f0535e720c96d309aee3d1a66ccd5975299ffbd345f0cc97c9dde99620882adf2bfd15d44b32f8a18de521d9d3d6676f8bf667e9328c17e27e8af49f7f6f513b40c0bfe6b1a20c75ec7350bd62ebb1edf398684bbaef6ff98e6d2483f0b26a703b967596e297c0f3329560f74c226c26fcd202ae5e08837d994515b84d4291a126505c319f1d516b1de70950ba98dd0914e9f6b7e5c97da88e036a279f19eb93b7c41bd7f8c6eb743cc71f9024a9537829d01ad5ccb182159ccb76313631090196e4f137826ec9a2a6491e87603c16d4fe8a44f3b54a4a001c6d1147084e5c44ae51018dd0e2739b0cf5eeb9fb65d82507bcfcf368794959a8a46cfc96f0e873086640dc2e96f6df65a6ab120001540e5737470c50dcdc732e673343636dd85b550bed736b66b50cd710866201d7ab91c48eadb5cd1ccb6063d90e22042f789b3d6cca8e61ef99c449e78ffe452a34c2ff2c788b3d6b88c5f94685d62b1e5b01f92258f35d367f325e1ad5d75b297bdd3daba40733ebc360d4ec549dfcf3a26b5eb70b8e653bc56642222d09008e8309501d64a096831d59e4ded63ca49c82bd5bb21bdcb9ee9d9c63a7807efb5e83a9440ffbbaffbf3045c49d88129e3c1813d25cd034385fe7c0406d09f7884557c6fc933dcb4911e42cdfcf08ab9cb21c0b41cc8469412c12084de7a40e82bd809f0ae35d7821d60fdb5db0218f8d99d800586415839892ec06a6a67031b1a7927e0bf4f7745bbfb04e27ab89ffa05ac32f2f8d244fe3d24da11f09163ba05ee0a5ba4635850cf340a451d65f8b7fbb008396bb2a39d5600b6d1e06a488035065f7cd712259a5e885d3a9c95cf052b422f2c5d1d9acdbd578472645c99fa6fcd682f7f347b944e8c1b5c3d8ed6f8150de0b8e906b898c26fe0a42243a0fc1ec023b480162fe318c5361dfd1bf62e233a3640bc163d39e066aa4017bad0d8f7a0e1cd688a9c588d76ac16f716d07fdf0b7f1973f18b841d3ffb53a05039c206410fa75342e9bb4a361d15e00746468eef74af89df1abeb54d6daa709ae44f514d481b78b8c680ad96d579a1982511851f2b181c0deb20ac442bb9005e31aed3765494ad36ab06f02f2bca6fc5dd19f999350a8328cfd55272362c31938d03d9714f0dc38a8135f594efc1ad6d1191f7859b51c6e494953a0e290eef0c4673f2317a6f42415d7504efbe0c360459c3e8a7de9ea30dbd66fba2c9ae230be746165cb111a2d1303added306320e1bb047e5da80b4def5164fe56da12315e7f670961c41c69efa59e161afabbf4bdb066e38f5ae857c1ad3e095d5b2c5bd0368251c6a19041426db9b2401b4a5c0c9a45686d7ecf35413abf2ad62a7d6e3b08d5dcd15570cd755df7ba5b19a3d807727e5f58d7cf198c4c040d2041f225a561304bc52bd53c73a737602052b215788ca3f0a6ba70111faedf85daa987efda5950d38bc47c80465d91a9f8ad4092b899048b88b92629b2fcd5afd1aab98acccd05e0af7cd0f47289f2bbd589b7846d172147a697d46b795040c302f0471498a84f91d0eb11b1e1be50916de373676f1c06d12bd6a719c54cbdc1aebab25841c425d5255857f55f3da31856249ef4d22ac40a0e519d8e94c871225459d16e8994fec04e9196d81f3f058097392aff2f1fbfb0d13cdf7cb89799af05b02760c2eb06f96b402dd1cdc806af3389134da5fc0546883d48cce4a361997c9404a30ad919900f71ebdfe96466c202affaa06c655c3948ac748cedb90007bae6b9da1d622454c410fd3e78eb2f17c09684b89bde4700977d9f672cfa2b0d01997815592cd037f02fd1b7c8c0290d3521b11867bc08e8c91516d04321b59580b386f9bd0637941172336ce028d14f597f48ac6d5a246dcbf7398db8c10bab5c3cb8fbd40a1704ef2c35b71a1f115bb62d6ecce63909958084db749aa31eaceae3159c58416f2c32869de5368471755d689c1b8d4b145f52e8bda8845f2d4a33cf13631a7960f575e7769b81f3c69d7adca2715792ed9a7904c5a04bca71b24ea57c2c15f7703809fb9bede9ac63f3715b4dd72f166a37d912ef3b59142cabd1f2354bd7afddb5ac7d8361f9a736d7c6e1765764548e67e5d22b95023b0e39ceaf566c7698d95acb773a366b676cf4b9bbcb879c83f0505b2ce44e1ea6241db0d5b8bc98f30e0791d0f671290f9d00bf3f2393ab5a288a177b7d706f6e157dafae907841c0e2b5a17d39943cec9463a987e7ccc1b08905075e5198b28822cbf0cf40b4bd0c523155a8ab6210a595d96ce280b07df58e169d5894d6d9196500520f321942c058e9250430f2afca22f31e9217f076087ae483d81252f0c6cbc5a3e0279907142fb30c6a4a35a92733a5cfe71bb4ecc8a773e76600be459441e428e0235230e2ca1d2f3edf7b0e899b9b7a8606db7ef6161199ee822b87242ba603d6563362516ca9e893fa5effc4daa88589cdada56e05b23d454ddbca3cee56018c38116bd395225072c49617d45f07048890a8e8fa8d91cfe247143fa9eca024c3733f41c13e7a55947a448f63b54f2bc4467b8163aac428d07ddf6005c38d708aea6d02772fe1e0ff29b26de989dd014b23ebb2b2d3a83e72099d6bb4b70f46a27ce3bdf8cae50bb481614e532deb77c66e3991080528de336eb845631df172bf0708203892447a13964aa1c9e0ac9bbeb548e64d59fda3259a189dcd35c7429b012f3f762a464315abd380f6e1af4e784a4f041b6fe2e3cdee87b42c4f4d59b705bf9a1293cbe63d683cd29d3eb267965aecdc65db9ef892f6e940cf5bc146cc0675b5f94669473c44d16d08cd936e5bf7bdb1a7005001357d71b7dd1bb7a53a4ae7e5762f26d31f4b77c0c03d8ecad2647929dd7438642aa68ef5521582bbb1e3564aa01df49fbce18ae504090f977da606a04a855dcb190444b7e73f07eb2abc5e1e455defffe063bb882a0938528c8d5d3c2c150ba50236a05031d610583b5bb1d6a95fa8007954dac81a322931c8b559c0b750511966b82c549c008948aaa2d60657807587dce303d0e5d19bf95f01f202fae8e3dbf6385b985b65dd9d07f9e8e1bca17bdf12fc444892674181ec483f9741de1507c3f4645043f921550948275137332262c3a31627d81bc0fb8323c8c7ba536ff5911bc4065a038e66ff909886dd5030ccc2635078ec030640a8c81a0ad69a4fa2e72145ba203820101b8a55d0a76964195ef7b293558f13752f6299a5b7f30133aa96cac547bea1766c6200c28d864ef6e81d516584ef257470ebf8fa65108e20951d50c2cae40fa85822f2b79a15ab4ca2a23a1292f0615d519b370ece57ab9ed9a0dc02287755caf6511f7ed219f2c9fb02b88867218e20aa205e35ba25475388b52258cf5e1c34bad8ba9cf404b300d0058faf58e528fc6b30d0ce7b92e09642bda4140685dc626c0fb209f5b271b100549748d188d52af8f2653395982cbe69be862cee15543d6385165f95330991361f7b1505ba2f36052ad809f30492351c5dbf97e5ef527ad956d3805cb61830318f7db866876dbe9402c0e01f3c3807141013d40edd998e3c295ae88fdcf2862e0bdeccdf3aa27c132c17d3bb124eab242d498354a35534a68009c87ab03e5cccf6631db98f135cfeaec3c9046238b28f9b005692b0e6687c71a2738ab1506be946e6c5f0285c0e1f5622ef502b5dccfba1f523f0f8ca157c6c2a3bb54542ac8afacbb7e1bb15b253f93185d8267dd32c7790191e12c196bedcf476d32ddfd9e67b366692ac6ab5f6dbbf770b02d6df4eab6c923419fa89db94f3f9db13e6b69f8af334537d69c41ae846cf946b41444f50c04ed9fd599d85160aa059bf128e99277c4e4b00ec3deb87fe6d7a7897508cc7a36d01e64727eae42c58cb4c409795e69ec97acb72cc80451d90e2222e868a640d15b38e2c2638d7006799643f319c77c8723afcd9844ad235b2e311d613c48ce3de3d29adb67320d7cb79ba34dc7ac8265b0da041f1bd4c49dc6888d1db667a68e1760996c24c3edec4170c96396c3cb2ada5c8a1f8b64e6954da7a8fedc4021f05d2962d3a464d3a1b6ae80513ed6cc332c80c454076fee644aef142f1ee0c51d59c1b72d60f1e8ec18a2fca0cf2cd1f9f6faba0360163b492658ec7fff6dd7c780e9b8843f3c4e3ccc11d2ae67a6ec812e9172e3e9e5c5ba4dd9442029156dfbb78d9c0f2ee140653586b3ad6cb9f2860d2a2415f1e36035ca19058d530757c805f4443988df4a4f606706ec58389e42936ecbd15a12e49122ba59a2709ddca9a675ab499ce47f4baf674be6b3dae9f8e260eeeee4da2b8531a477b52ac49d2f36d389a637171e851d5d08ac10742dc973c2dc52d30c2ab27d10eba3d88fdf5a6cc774724d8e32a700bd7dad312780c7c61aff7f320d13b4632b9a66b8c1559ac75d32bfb71c4cfacc51e5795bce9518343b920a8903f69578fdeff76752bdd745731bf85de5531682af5ec789f64bbaa0a4b050381ce416326b5483ff49f12ceb5ed24f9724dad173dc59ab793176d29ced170ca06a1fe6b3a5a6ce49dfe323f65c81d8f629c6378760a8877467fe414b79b015ed3aa0bf0291c2d0aa462952b52109970cb2983d2c35f6b3b9786e85cc64f8cb7ec5c9ad241cffff9e24fc8e6794b6beb80b68a3e287346dbb7c05fb184266756bb1cff654071d461107f9fd78e1c8df4558a755677dff1aa2d27e53161f84a932c2527efcaef6e40c996703e2a0cff9de5af052994b7c0ecf9f32bafca0a9f822165401056a078f8a31388bbf253399693078a14be2be529d33003b00e7272ab8b71314a3fc9dc06a4fe575010116a62261baab44160472a7f0bc058dab679f246b2b53739e2becc2e81ffa2517ba20346c138bf031476ffe5c000d1ba0aa7da6ddd7e55d7c17c0e8608102cadd72e7d0bb0400146337b2ddb12ce5c8afedc00a0d94cde77732e141a77789cb334af156a9418f4eda816ffab7459c8318ab704937c8bfc8689e00abcd71d8762d1eca61e11d873f94d49a1ebea922d60e08279d4fece43b5fc27807ee0efc94833a00aeb6c674b89c7f7890f35a8c35ae7c5e59be8171040e94c8832450bb0218ead74eedc67f55da84587d838c3aa22910595aa9a8cb819ec965e7168eb54c50da92a9c09fc572a5057ab8a51c3fea870c085008dd316e785b86da84aadadcbd70e219a10e502a0aa7b9c7a5d0bced6284f1badb4846cd1464f62535fa991bb8233ad73b7eb54f124ab51d45a099b3181f08700abb5a5438b61a127f096466b1daf1fab5fae49869cf269ad2839741cf9e94498a0b5f54001a1a99d1c40b203ad7dc4acb4ae35d5b9c657e85a5ba39a5cc69ff62cf36a388af605b43cbc1aa0a0c7b426bb80a2ac931e2417315ab67ebf272b349ec727f43ae8548a33852d0b0b7a96e7fa0649dd50ffccd5aa6234ac47b626090184ffbd1bd1ae8ca3c8e540cccce36ce7eb9a62d977eb361d6af592cbe319d1fb29575eb379e8557805f5cf76e2c96ab4787324217dd50faf88f1e59efac53002845d799fbd20e6946049f8c8aa99aaba17b6e13bb8a2d6cf60a566c13871a5561c0d91fcc3f19f3c2e9e47d416dae1963f50671d67a4a0403c5d8f710436939282c396ce57f3eb8f94175dde98068b6ea566c5dda3f930793b5d5c3333c45ee5d2273db417be90c49ac74bc754fd066767cd1e5d296c054c6581201de6ca94c11eb66583f8a51aff25f5fd6d0bb5a1f06e42aa9efddf78515876754743b2f49540d79ec9d2a7d2bc5b72aed96814447db7a41d682dab4067aab1f1f82a3a60d32b72238ca6052c2d66d693104f60a47a30a4437da21834d54d24c354066fb8fc25a7eb304c7fdd5bfd91d4cfd4ad845c7873c04e3d149906502ddec80a77d5973851e996a38cf6428b8c6c4bd99b351f0382f47c19bc790484b062eb0e3eb8eef7626d47be3f6c1bcf95a0be4432fc1c80290f55a89c060fe577a59831a12b35358325c0a85650c77f988fede5adda0726a4340072ac99b1bae5519994c4795ce2e35a48a8e02b201acba68b4e5f6d9820c9d06b7858c696f75d98f7d786039b1ca2dd94955abb40dd6b2c3bea5661c4b8c948bec9e5974133a55c0620280ca6798980c6b0f8b6babdd163a635ea49746450267c817db7cf3fa6e727d8f38c03647a504fc8d3e107f88402e3a19bd9d7272a480e5ef4c6ba9b10fa7e1cc28337992f86b22e44f310918280ac4d2aa80bc390233d4439459982c4c1db5b47196fcfb5a5ea7fcb41982fee2ddb8e068ebf6ec96587f634a3b56d763bbca2b3d136e0fc8dde4f0bc7255f90557e18563e3896a35ed55d5aebf6d3018cd13b0c0f494043c54aec9f809595d39d673da7367d556d52a326f0a9e1f1f92293956fca4c224b3066784bb78f99910cfb4267979106e40a5056385c952c40b1d71a90ad954ac44ce6633c1c50c2b927296121b6e2880e1623ab2322776ed89b24f398d824f71e9710690090ccae9cd6baa26698e044b90d3881f6ab81142c7f25c28c42b6c707b24560b879df0f72de9561084cf28a3b21ec1175fa80cb5f13c28550a7d9359f4c2a3514c9a87098220383592f39a82bb2d714fb22f4c0ca3f1cacfe02bd89694da2bc42da0b0990813bea1b6d6e2a23dfb82ae4a9604c213c9ee32a3d6c96100033a567fab677d44bb5b42d107dd661269f6f9bb5cee8d494942b629ac64acbbe078bf0fcee787b53cfd1be14bce7e9dbe6d9d3075991ac5a02be600a76da40b7599546b6da4169de5146026f33db6d7c8a5f9752d072605c2a40058d2e7d00c292faf244b3fc59bc307660e5cd1e56109cea8aa28d1dbae4216b727619bd3a507f076f9294f38a0d545daceb75531629c5adea8ff2762ba2f3832326878a53e29fc7b5438a731601cb3aed7c68326195efdfa6dc34b109fb3516b8b9eac6363218f0771163a8708a18fd606809d7fb4e5106eed5b966847874dd16aae7bd34e1b078867aeb52a6dd38f5c0062e9cb5be5224fef4853054f732640783422473360228a5725fc870e2f43cd76dba33788d931f87ec3852185d50ac551f4932e835f2ac6bb351e8c6c49da2a313deddc0a3a68b142166993df9158361a750c23e3e6cd0b3200bac3648a0d7ccad9bc55ca2b006c28875124fd4324ea8c0b9fd70890b0b46528a2bb9ba2909a8197fbd5d8d4c18050c126f0d74d93a08a778e86510ec2ef419e208cd8778b64ed09ed86b3cd368250da7a15d50b84b230b2212277a9a8e4e16362d7e712fdfe2f983948b44d3899ad75b8d237864da3d6118279f8de9d84418414f056a20e0962e331fe7406c4c459c8ee0b46885377d87fb17dfef83c207f31e344031cd393bf5f143341b2cee717864c8eef604adaa5f885f418bd58942b22dc8406834f8f158f42016fb7a3deee1655019f68d5918c0f07d9fbdb10b5543c08fbf99d499a0217c7c70b2a7509aac8da6799da68cba00dc833330b43e2a6355b5e93942c62f658276e5f99e2e22261755b7faaab9bbffd53b86964f5269290cd2b374f671fc6ffca5871b07466379fc6bbac221006400a127e8cd942a7333066bfe73fe0317a83f11c20a7647abdfaf08d8bdcbef5cf6b73620083af294c60be617f9e04400a73458605802a6f02764af042a61a8ebbf5b2ead95b04a66af0e983e6d710813726488d1324538f2e1e0c66b60198b3a1dea39a2b3dc42f529b3556336953f831b526c13eb695c9ad7ad690255ce39a9f223840faf36d101062a608368bb8fe82394b29876363ee5ae1bc12e454ea6b27d8e5e8057593a1e334d6eea59b5cd9edd265aeee92246fa98c3c99dba9d37dbcdb913e3619da8a3e8e36711b98d3a4f348925fdfee73f92af5293513ef0bb710e42ffa2ea03fecac194395b84b73a5eb908b3402b5961652851b20ee32756cc4c6a82bd8170c8846b4421374b13bb51c3d964faba2b7109a4a9be35b7691c51b4427da620885d225210ab5281e4c4dc8e1f4a35f186a3eb95bb5d4e594ed6914cf152a774451ea032548f3bbfe29fd1af8d9da5996e25680990dceebcfb4d2110b56c870177b64b755f7be45d561d2365c90ff828e2e403fc20f137b2ab063cd0e203ef64f64c1725d2a8b25516adc07cbfc5aaa7a81c7d596f6a94abfeb52fbd651fe750a09a9d828084a195bb6d6d7113e04a2e3a9246803ba81351c62222bea116e4950365e4323436787fca7c168c22b9301d90912c7a8bcc5791cd25fb90f5d3740518f8bb031e38a3c0d1f6aba5702465107b8b2ae144e69cca1b8fbf0d85601f0e2e3470dd210e9df1c8ddca63147c712b6891ce9fb15d8e0ddc55bf4b2f633a4b64591b33ee31e99197eadfc593f244e760ad59966ccf170b8388128f7f6dce89da4a520aedeab88e6ace55a416deaab377b78d0921b351f415b34dc0d973abffa9ab2566fb0a1065ee7bf68558daf636f20ed53f369784b174573a4df931c53a8a0388b1e8e263778e7088167156808c6e025eef6d19811bfcd735ec335fd69c18f7ff79b97f313291dc13d86493571c2ed41fd9b9f7e4336d4b6fda127768aec4adaa46a2a1c0addc0662d2a19ff35924b16bf4de7437cd90950e644b9a6d18586aca6de7b61aed1798fc689c2f900c093ec293d23512ffac7e6232e70cf35ffd61f86bf525beb40a4a431bda0d681b18b698f6dd2ffa3051bd9a367244c670e0c1fa11e3cea68ec7cbfd11d8ab90fd44ac80c3d68519ee5199b1f600eaee6660843b76b86514baf62d6f3de271a39152b7bc043e20913e89e5896fe74309ad4bc1c12e749aa74e71be706a1f9667dc92bad6ee7ccd785e4c0e37d7177e783cd6fcdd5bcc7f2dc45118e1dd6c2951edb4ca597dab966e31da593645ad34bbf3ab2470efa12bca79ff987aa80ca5a2b2724ab517dba568d8b05f8886e9ed7a1027b08c3b6526e9acdbbba6f1bf7078ac3c59a4ca6843accdd14be17bb1dab646f9d585f23aa4c5b123d8f81e5e86b05a0ffade82bb9486db653865495a076cdfb842901cbd5415223a352fadae356e3373ca738ca30dc0eacce09a64efa5fecafebd61e1133b32000831ceefdce1d4091f143e27b12ce2ec8be640dfd30362f2cafd8c228a16816bcfc4f897bae75610c65f19d670c53f27aacfee30b7f0c1d2709c18ae27dcfda41852f483f2a5d7f0ff8d77f54f5468a45ec7056820c69936f4c370e0cc88f5eb0a03e7f18c85e102ac48940a834275397571360d78bbff4a051eff64c919871b0defd81a386c8ad0c29fd2508505f85a4c9cc471f103a37d64aff9ddd42716e210675bad9235698a0a17aa17f5844d4e9aa7db7b152509e682c2117b282dd11ecdb9efcf6c9dbc0cb3e58ac24b57a3a14c09b0f8fdf7d14800096cd0727efc4a7156672d38ff59046d72e1b0d06ee5a4ab0a96c0aa7dbc60ed192420f735ca9b014b2b96549ac0d806eb834e508bacb3eb9684a6e3e45e1c19b455662da03f0af1523578f3ea6307288349078c6ea74da3c586b2438778925a3a0de58021e20d1406ae61848d829790e8dcb64f6a9b939c26681d3fa6b4dfd623e59125302833137e986c1a9151754d00fe24569309294ccaa4115e0689fe4184280d64291151187d623a3ab154ea1b9b47d473da4d60121fb1e0dfc511bab19fbc71665880963a5e5dd77e97a52716c170f1c985fa79f70d5c3718c05d1c2be16f4788737ddc50f92d9128f784a2ab6db8ebccaa07a63d38c276064f16050e11a7def15cff9520801047efab28ca51bfc15dcc96158dc2ca6950c7415623ba5cc7c88a493ca57eaa5174ced1c861d8dbace6af6fef7ae2b829f78b37633966d1d91f45f4369019933a580ad8443225c2484f22c26324e942e05d9466221e495f2fe1492d25bc84ab37fc7f913737463b72b88e9e98982c5abab91e35bb3395b5bf57044eb22e11f8dd0853d352a0ebd3e0e6394096645d7fecdb3d127e3204a60226c38599ad35df3db76812b59817ec74b641322081897eb2701a27bff389a9d7b90b4284e8d008a7d63769eb3494c488987300281915ca5e83e249049334c9b8d759a08180ca2b3d10d61fc1210ea8b689e8f08d3612d0707e8b37e630883f7c6d83d66d81c95a496e412f5c3caccbc4dcbb4c7924b277516dad0ed67f6a9ba92c2468a1678b9c4a2d32214f049b9434d6e3540d8d840e9e13a1e2e0a832082756f011f0d1c211772eedb68d33fb33e3fa39cc6842c30ed425e6ebea8bc60a186273d6a011cf34dfc17e54857a795b3d821e5cc9e6b5acc3120b32a74116e9a2cbab1e8147380cccb62ad30106659b8cb2b316572ed112e03b388e41fdf44f470f9d6c7ddd866661be46d02158c7b38711c05d697261a763094dadcca2c99bf97a6fc31963283aa3b6c58cd02b2a01b3860d7eb0f3f5b7094b9e00634f3dd8151c5dff29c233c15277143a2672d0493589e57e4f6f74ec20f261fe9d0b72ec53839663ae6cbadefe7d0ff4a480ddcf3f9a872646f923d3fc64850f874ca6bb0e89687f5c5a24768518ee24d2f7ba9726ba10e99350e12d7750aeea1d812c0ffb9d10889487788f738b1208dd1ed620530d6e9a3ac44ee377410a5321bb435ba33e331442006cb2a2538d70fb32c968f748af150afe4316b0e926e2f720db6eb823e4f8c28a2417818cff3dfa2e580909dbc4d54479cd9aefff33744f0cb4ee79c1d5d427d1ea97da155e00c3fced8d3d9fc2be9569164fb8c4f66a3256f771ed8a5eab9f03096fe9f2155333a7efb2379bfbf354427375c8405f0d27ee115a8b283e82569f7055ccd4d7c77b073a599382ca94844f3f1db601ab2e9414d725f342af881cfeabda3726386359f1efcd177d1034ce37e450a327aaf840327b0909edc4fe07ab22c87a6633f060196c026ec9ffea085da1eaf8894415822b016a171f1d5bd7db48bc0048468835a38e4fd7d90b50e9d87686ea9a411f9bb0667b5c3e8f7c3b37046c1545f34e2d00c9353be360a9fb91cf8837fe8fd04506c297a4f0046ed08ffab561a583320bf960acb263190cb25b7ad702ed624012525e191f36ef0fdea4f458ec70b1620f45a9a303298b080c271784e6d9ddec71bc22bc0f3284eda955e7c46a3068345a02ed250caaa45337d9de03f05b7a7678addbaf9748979b2f29e225d96bbc0b5067fb918ad8e664e5a4d28719c7a9de7f1c42304784a2c340c93af14e0fc746af1dc34620b5cc389bdb26ed5a232c405d0683f7bdc291b4e4c6ed7fa885c15626e2cd4326b316910525bd987ec65b379733433cd223d7e16c96048e689d3a801a27a431a26e304997e10b30e5c36667d5a4a7c603ae296bb2e289e0d3345affd176dbeab9655a3acdbe225a127e6418c1695967378d8a2ac2fc08ca630465e5f4bf22a16f42420419c533c91648b0a37c12b2972f46f9595cceb857661a33ca1ab45edf37666ac62328e034d624bf45573228567c2f305114deaf9aa62e47ebf9c97987aed0478bf1c3bdf9c727cc45cf6879a353645a8bda67e384eeb7b71c6a043e8dfa3521e2d77f3a5ff1531ec874fe722feb5ba4f83874aae6405a53d42e4821600be6bcddc291442198b44d46399d1a2f9aee3968c1a9d4ea6a0a6ef698bde19bba547be431d969784524fd9d69bf137ebc5b24caedcaf2b4c4220d711deb5ec99e57c6b5d26a0056805c6353fc3dab83a99e0c1b63be602f0ab17a6588eb7aa5a8c49735224e231dd981719730480c847106e1e340c4bc0f251c6a6a0391e9f4f127da470c1a4bfcc350b70043e3123c4ffd3ba0780602b621a82ce9762431aafca6ec6124bd3667667fa07c5fce73ed5b4b7874a2f82934eb137315a2cdcd6f0d1d80f2772b4a3bca0ea2ba79550a4b58850f577afff946d6ee56048ec6d0ff65b7ab8f4576466fa0896ffc2999b50d95e8b2cae1ac7249abe7c474d3e3f0ae1fa2ebefa0275f2b44ee6c40e30c760ebedb5620e096262f3f639e2e85d303821f6765c589457521f3655d98ed8f113e314f96e4bfb65f4b802c2f66c68be34cb9fce5cfc54081997c2cda8b963d200ed672b52fc40058e51b3e366aade56c1fc95a7fd18e2d9f4361d0250ceb8b3c21c967a533f838393f18370bd519368c344e175fed147d052502a530e1b206a31e9df48bdc4b77bd1eaab26e27f3280a1e0df371390f7aeaf68b8f50ccb9377d040689b68494e7255a603041239e494db7492728584c78c7f6307520d64c67d47884497984f652477f16a72e9e2a76061124be6e2a5a1426e42f5c9c63906be7e76a134af2045979fe31449bcc1b46e6187ca6d502bcd7193a1d8025de582c820b60d4382b7c4998952d28efd97fa7aef6626f5369b63f939f395b0c60e9b1fdb209e9cb1f0959b0b394e5d36a23844cfa0ba3052b2255c740271d1513b1ed484d9fe17c2149e9958125e288a76f2b3f99a5b0bc8951a14f477e67a082186749275dc8118c7742a66b380e07e7126311f3af49d8b5810a42ce640d8d1bd458fb1bc72c030cc7f7a62a18b418de4ae9e9b13d79cadee9f3fd8f5438f5a2aa3494835f572947ee71002c732118dcb7f831cc9a2c661e911866763b03fa869b99352ef48ea2fd8359ffe803b6565142acda226f5bfc83887b226ee86945a3271ac6e4319eaedcd16d7abac2aedee2a9c5266bdb231517d5831803f604cefa1a2bc62a06df9f7943e593a74295d43da83e4fe2de36099bc62ae17b92108c6ad8c7ee56775429e7a7aba74fe0f1df084b604d4cf8f6440eb788a14342abba2205e6c8b1caa005f830e7ceecdbe1e108329cdc402ef108e8240b6e7e87d80ce7ec8d0da0cd3c95e9be70594e308acf9de0118e7be863247d42e7155af04a55d8435774164d1c8ab4037b88f6b8fae07d48dae3af4784daa63262d6b69d3bf05c6bd1087ac444f684faf55fec1cde0d764c185c21ae4078e6a7321fa2394b04bb0f2434e7a08b89a79015d21dae244e9d2c19dd61aacd8eb8d61d9df5b39aa27d428ff7b66f66ccbffd6a701fa2551881fbfba403bc6480247959f704c4010bd61f12d5906de87b25942782aee2f0ce5cd848dd8f6fc1b43560efc9941c8d78eff78441c07ebfab7841362f259f3dbe926cef50d64925fbe138c720a1e52f2cf00954d5cb89e9467feb956647a30b4cf0b53d514518c766bfae170af218ab449c15850bb7d4b36b404d2b156a9fe033ce727420e8d53467da936662e851a54b0cd3dfed32e8f3ca62d2007dd8bf09dc13dc656c88293704456938d5260a0221ea6c0e55ac16271f7eb786a708e42af57506856b2f65c5a3305e702e7cde49967a8a9fbd04760c0e5ca294ba679954d7df3ff6122b0eb6ed351b2c73fa1d0fc3b69ac574b3f1673e86c145f8f0f306c6950730fe1116ccd86d7cc534850f19e62e2c64f136e8aa1c1bd5ddadce6f71508a067069dd3a793c282ccfbad2852c781405338a0b45657141040994c0723fcdf6473d1f08ee9b7814152441f7f2c9d92b676e84d4ce8780b1f11fb0b4e771833ad32f5b9a78a1a160ecf9b588a60a074849097527989efd7f8e09fb36d38fc7a59cd86b3b881864454e163b8333d44f68e6e64ffcdcad46fddababa56046587d4d0bdac108ae4c238ab77c695f559af54da3faac0d30bbd4068054ba0514dd28e62795cf9e030be5f8e7d8b6fc2af5836a8e7e704c0bbcd092c4b96cfcc02352db2fa05cd628b9b9275740729e48cdf2758399173fdd2ef47d4631de8022f87106d73809eb5d7dc17cea0395893d5dfae6d5064cf640aebd3471854efd9f6318e36fc948c75d5062a9abe3e7d2541d2adbe59ed13fc6a36441885d342a635e2c825158f5f17d11682b9ab51d887261b84ed55510577584ceed16e09a23bf09e23fc4540774854eccc603deb9a9f1aee80bb6dd2ca801f086c14cf414c2ad456e06a1a5bce391abb0dde1df68da733e08430f5544caa8bfa38ae8178ebb60fc9822e43bf4dd4224f69c3657c41ce604ee98d1395669b109017bb90bb8295ee63a7722eeed855b3ad683e807231751abaed9b4424add97a02c80b4484bf11f748373ca59ced343f0d047fc5821063f3f38e599122754ac51e310022e4903adf91128a4f16785f1c9ac2d203a41e6eb2996267bd955b01ad494854bd5452ec1d30984ba0e2fe40fff7522c1f82511511edbdee55f1b39015152bd74cb4f2df02a48977826e9a80cd77775a4a8d9293bc8fa048aa7c7e55e2d97b374a5a5c7564c298721a656d195a2863f6a91a27ed47b73705ba252af06e794e47309545d750ed67f87a319812de21fe8f7c200bb3e02b9099c08811d3912802e396cb6cbfe28559a98854504e2f37b45d8ba64004ea5aff2715c7b42ca7f33e929b151980717192371ec72f29b0f4a2b2f267abab45c6813ca6472fdb0d4b0bacaaa326c0d2ac90f5a00954997042c287233724b3cb0bccf44482f96f5b8f1893e3c471c763dd21334b14eae1f8e64ea199053c0c4670d92067002773f40c93c11d2a5b52d4e6dd2b20e1b3aa5bc031086159332335f39be9ceccebcfcd269a58f5aa36560944508236590c5a42e9ee8af502ac3e5ae9d03d900da262ae0a4a7237b003c8014e96be6dd8e904c75c4cdb825d031c79044e87a61562878affa2a63a40b0926de5fc83627ae8739790fdde0e7d5505a361134e7a15272ef0271db331bbffe6b9e724a294ef67123f8b023bc78d81f857932dcf3589c0295c907b46cb9f0f706bb5d8eebeb8b8edb31c6476c224080e70cd7fec4be0eab2389be3b0676968de55b2364e50f83239bb39ee23b9dc011610ba7f3747b2a01204e5db83478a00a681db369989cb9f7d253673135ba6a747206080812860dc4ff85bb6907e2e203758aa0d71b75fcae04b444dfe111e4dd1d6867a5c00d178370f5b76b02f1f2196bc392efd96bd9685fd1f63a3ec9a9045f9bc5a2be24ff93d12cdff333271b51a0fe7ae08b10fb50650ade9d0164c41816e7e400505d8ce795a438032b8a5aa4a887bfede9da114802fc6835e68390cd5452a4de5987a1af9f6751b6186f7c5f272407cbaf1d5fd790817c70cbd8b60b0861e30ccf38443c487e5b607a9dc43e5c6c4470f9c7da67f643174c324378644bfd6f775dd1d999a2286a63689d85d9519b21b8d321b38ac0da5d6dfb8072733b576836e74183f209656c7e2ebee9aae4f2c54dcfce8aac5daef5e8d9e3fb6abee7ce956c7f2eb4e4d05f0498cc7526effe9abc562e0cdcc23e8f249cd4a7c43f8535a10fe061f7d8edfed51950a325983184b35b2d0db3f47366733a15b660dc9ac458ed712545965f6e5be5d41e57a277c383a2b1f6d01d43b5c806ddc173f7a112fb920c43867b35801ab6f1d4257410286b102c2880babb66cd82bdf4e23cc72ddd325f5bdbcd2d5e7dd3811d4b4c22138ecb28979f94ef6f33ec381fcf61416dc55994fa11a9b594d5af99b4c18330fdda7cf5d955515369984515246f02b10edd052f2da37df8c9b44e919e92e34a57e4ee6c31d11a596667541daa7f0849bf9915e48949fbea660bd5596d565c3b537879c972a1a455fedbda149cc8e1547f05595d6859125662b412217bc2a1a110063375b4a7dd3d496ca4150b4a50620f9bcb8acc3174da990da40799cf4d948d6c7293f45e62aff96d1af064e91b115e9e9cc935b319b7448ba06e989a4e7cf542ad76cfe40f51190c4d44f9b8cf932372bed1f7fcbff50ce0852211bca2d6d1e2a08b04629bc822e6230e8dc55cf72fc9028fe3892e5304215a4f02482c8e08bea9b3ad1145e236b74f4d26aed3bc149616d4d31416e498d1492467c02577b5c938e76fa1c8b38f248fb856c73a3ff439be19bb1abee98408b48b8a9c684628b50f3ffb967bb76ccac57fba9da16db7efbabddd2056973814b54cedab52dd3b7b31edd4dc4bc14ccecf6b54ec81d50259fbe202361fde38c04ab860d89ecd2b4066f4a9870e2de8afff57688fc7e2a3039e8c919313054dbbf3b7edd4ecdd5d8632e6088715e74a41299f88df1eb7ccf086e9e31469bb4dea7f4572b017129f54d3a2031f72bb53527bc490f3c239c2cf3b496008b6764f47ef661013a62396ba128ee90f5644b65256a6cd97e1c1a0e6c023256e06c668b5109656dd10258a79e989f4cd1d045d0e27e2a7039f698bb1927b1435a0b4cdd0c463a4e1d0db150dfbb61cd4e2b1d9ce996b54f45a55b5a5c42100beef40e62928f1c152b53ea5560b5515a84614133770b1835166d64b248f0f0068bc6168decf3f81a2d2de7c57823950135e9ea19be4de80cee17ebcf9abd1dacedcf7983f35e15d0357c1ac4cdf55e0d97434084ee6f399dda053929cf11297237775190e9a080a83d97b58c4e59f32c6dd4be94850510613292dd9b4bbfe4956cdfdb4e819fb3d7dce263a2d69ad73c88b278f0080b36a48666aba18350f447ec9f11ce02beafe4fd4986aa97bf450914bea0f9c36e37dde23a97142850e7c398f0aa08d52e15a6ce138ad354978294af22535da6833d4e4e60225a07bd078e23f611b054790fd62bca32ef286c0ad648924d589605ce516c48611c66a90ccb2a1c0c60a1d79bb91f4b3f5effe5370bda651b7219504f4f8a983c9c965ba034d2ec8111e3c1924305e010bdb93d926c21b01e6a48ae80ce3267e19d8691fd99adbe3c3108482a97004020b051b62151a7f4bfc6a2bbd0301eb43340cb1b90c80152af0f87c78e8e23b1b82695c35d96ee2c8475508347eedfcc83321fa43792974b9aca09ce123ae80ac96345ac04ac649263ab93f02058307df22f5cec806ea3781b7f732507c970dc9425107c87d67420776f556597fc9a83d98e998f4a890107e8bc9895adf8c1bdea195aaec70c235321b044442cc3cd9aa30156595b61df7a3aa281b83771631c4c139706544712a381bba1092d3aa8159aec5b5a04bdf575b24e19ca5fc9ca86734175c2c859121a3afed18be3a5fd58ca86b3437da2cf23461c6e38a5b14e2d42b181eb2af0a39349cab12ec2b79f25f48963d30a4112c2c60e75e3134ea8f53b3a35e81ba0116be1ba2a342e09dd672ac96ef6618d684667ad0c9582bd041e5227558c70c8b761cad196ea7079e37f62eff7405c4ce94adce06ad25a096e6630d9680069a4518fac54865d4c7715fd64d61d7564e1f8a2ce5d540c52d14f376ff9f564b16c17850feb8e31bd0caa4c5f98177f0fe894c1ac362e84564d11ee28d644928eecdde3de0bca531ee5336da7be280f602978499687081b9b31530c4c12654aab09754d6a08510c34110283a9e1bf33327ef919426fda0d7d5071575ffb1a9066d01f9f91da40ea44dad1a0a55b9b2fab4a075b620fc95e177531cccf569d1cbab8552e56484fd7379685f4beef9faf872abc19238e0e8e3fbe2f2fb73a96e4969680210213f430c29e7d0e07a5010d4f2675c697330224734e4baee276279bccbc1ce8af080261a543ab633121345ed84c0f3c2e9b0d6841b27c3c91d8db0d0076a0408bf09bb2318dc691846e9b2aac0910388f825fb7640fdb408db50dec72de0de58ebf1034a8cca074d226f49b32282c4239905afad8158e11085ae6cc6d68ac60e42074ccbdbbb2278ebe50412a9199b5765b9d060f2802ddb07074ca6409311f953483c25582ab1cab19d6f4d002040d76804d2cd6b6612d4e8d20d79ed359a75df13763856071577c904008b45bf1b3bff9f7479e35797f4ab5d23638544311e4ad0c7b2e2981b71af83d758e87886df2195229947ff8dfb48728f57ab572c6328d90e1cadcbc92bb1e7a6f201cdc9e38deda5b2e3ddaad4db7655f1f694b3c60055eb585ae13581038ca8c7301e5459ab781ea06f1d31cae7e672dae663633b83c8c3ea09e8c15c552f52886969f5aed4e601374dbed4ef9b685cd422c8102601314081fb5f0f7a5725b8a8f943654da366f939fd30236da6ffbbfbbb79429b713dc13a512387c7e4565c3071b55d9a6c19341d4b8e2b7fca417732adb643e7c53876cb3f1e19b54a60f3d04718625e9e50cc7cf31ce72e4c8f13894661ec7e39841c1f133a3cc467e5fd9438d2b8e1376b12133759099543ee49a0cd320c4329afc38643424e499528e9f79259ac7f1348fe3593964387c5c60c9c8dc908def31191b366cf8f2b37e0619e5cc339c84b3d18be3849f434646791793ca9c2ac2f47997f171bcaf958346e63864647e868d9ff13468d020c999548d08737c1916eb6dd8b021ab31ca66bc8d1a339e354366d6f28d52e30c55e10c635559a30267d86ab5c2903513dd731661c60f92c9d1073b7d7ef5e34361d8438ae7c7b08f791862e10fec639e8c3dcc93b08f7925d8c7cc94620f73baf86cbdd83265352bcc714ad80a67be1a11e6eb57f0e212df258b72b658e293e20709a7b0161106a573e0a3d972f5aa37aedcd022deb0cab63cf3feb0fc43f3fe268d0c96675a2d1b573646d80d992a2c9f7b91a9225345a68a4c15992a376c5cd9b8b2c1858d2d36c2b071021b5d6c78f12c343e9a2b54983846d41671c7c9bed699b1e36452d6b322f3d28d276e64c933942432bf9cf9ca99a7c18167687ee695687e66e66974d0bc8e70cc356a68f0bef0b46143ecf13c689ec836f169aa641bcd956ccb31e367b6c854b921fe0d256e54b961c5f4e214bd904ff35186669ee695669ea6c7cfcc946678fccc2cca1059ba64e18cf7d9b89ad9e238228df7b9971ba1ec861237aae41af15fb21b56728d986139427c24a5c7f3f8b27685293a99f91def84e675b0e000251eafe359e831a3217fc7cffc8e6781c78c269c91b063a6b46336f33a9e86e65def72c9c8f7182c0cc3d82bca99d5a55c23ba66689e95568e233e8dac0cad3065beb4f25b95f087e6459235e53734f8902c4b3164c588625235224cf27de49415bc98a70be6a39c19c6052baf5c9e617c2b9c7946565e9dbef0bc316391536e58ddb86135e3c529be4c0c29152323a3a2728d2825d78819071c7ae821889c677e02139351590ae665c437ac68aaf88dfc10263f39a5bcf2d6ec35f3f5b85a829cd15491c2f4b997272852d916d6906d53d94605fb5056a3a645ad0a73e669de474ed1b19a62d47adf9b6bc4a7a912da883f23f3d086e6ca29ce6ca94d71c3ea14bfbccab6ccc5966c0b23dbf209b2ad4be92544d27a5f9eb548cf2ec2907eb664a23bc6220c3ec9190ca5d97223ff07a6a8aa7c264bbdcf908d53b2d28962b122aff75749e3956828cd988d53a1cdf81edac0c0601f939131a298f9a5697e96d58830f3afe0e5c43031a22cca8963600f23f3fd643961e5c364aed16aac325a1561e656cb3c5b3568c8f0cc17241ca560a439db02935d5e4c2b1798e5c34ca91acc295387d7c7589551d92625dba4ca1aa20ce12fcb8729c51e36f3f0431989ff35f3c53c20c6ca71b26be62ba7caa8524a2955d610c2caa8192de5eb0ae72e33df28e525145badd6fbcaa80f65e39351ce59695ab9f2288567317d9e05e31cd63850d36262588b158629be3eca50cbf5af5772fdab3563cd945cfffa976b16656804a31685e9f32c3aa2307b45478a8edc3fdbf299ff6b322b8f2f28336cac828981c744853faecf2e9fab8b6fa4fad64719a2717f28ad77cd7c3f5b945eae7fcd7cc871cd0566eb5def7379097f7c287f8c1498aa2ed92686cb8b8b8c18e02ad6cc0713c499df27c600a6ca71b2ab8bab8b4b0c9797ec8aa91213508e8ff18d1c76e9c245e4c265e4c2850bb9650b172e5cb870d1718a5cb818a9111685e1c8c240ed8bda17b52f6a5fd4bea87d51fba2f645ed8bda17b52f6a5f88400421f0620422f05ca35685493eeb7d315558e496181a61f84d7c1a2420e20c636884e138614c9533c42116b5384ef82e15d698a93af1971d809df95f5562aebcaabcaabcaabcaab43e8797f067940a6df04f4d5151cd58c184e138f87b5060922047d5951c4190e0c435ba9c384795e3e0578d2e27165f2e3c9ba9122550db62a4c21848a20523556d8b0f04490549054d95a5931f0a4d953887e4287e90fc640ec9f0431c230a3f8fe3c8cae3487e903c86e42883e51a1765d8c3700c43320cc5d0c92a56ae963862253131b2fc3f574136c45cae876999af9898d9973fd3325b31b39898b14a88714a16e3cf9598ffd57a568cc8253361ada91c236ab5605998415338f664064ae780035e3a50e5d439bd8a0e489d5d58b1603eb2624aca13632cc3e23f09bf8c38483612da01e7c85e7cc13c767d28b4c3933123af333613da2156e41c634478bc926bc227724d386629f3b3624418872216a610158e8d303c82e131ef5f3aa0088fb32c314bac324e8536ac93f538637c25941253c439f09910d57b8ca887e3e4b1c600d3d703d6c36fde22cf5a1167172ee3c3d45c608a1ffe2bea25e535feab866cc33fbe6b8adff2fbfc4af42292916daea8161ef2f047fc79bd6633d7bf64e5e7d8cce722e21cdf875d531c67ac3a6133df28354ac935e3b3645e922c9fe885152b82bf9c6559be4ff4929f7ce5972cca9959a4e8e51c5f53e10ccaa8da0bccd712fee3e16bcb8bcb2b8cd7095ef9eac58133bf34f0aa408d395659952cd94b0c17e345c638a54b11a66fb43a5f5dc29fd7550f0ee0d0c0ab022d2fa7cfac19ad548951a30248fc240e42684a68871194cec1cc0627c014df5773b2484c7e7e1f346476b5b0cbd59279aec91fa8828b53767a155554394b0cf3571431db5eb320724a6d8ae98b316be0f818bff919fe383e4b168631a21a1126ecf3bf64bed78f1e2bf27ad797b228e78b9cbdb46431b20e2c84a8c56f3daa58b9f2045512260b462d6154d9fa9c6731a295df780449054d9d415782a482a6baa8994b28233fcbc41cc2c2587e51145b201fc7c89cf13986a310e1f865cea218be280bf30b51e550263415231263392b6185e113d699a388d8439830939874c203529ef0fd5c9dbe573c499f3a4a89a2288aa3388a631e49f1b32c7c310749651028f101aab3cce5d3196631cb82a642317b08e38b0281d27194e263ec18635c53a3943f876198652de42861ce0728c5c7f9c59c737e31677214c95114b318e65ccb398759cc39ccf9c59cc31fc91f5f891c5b2c31bf98b39859f945f2c76fc594c819105068d38ad5b298f9c59cc5fca2288a39b38298c9383849e220b0d8827df9394643028c4aa908c6a1582467b155240c479345ca8ab05a2ed68b9f63462c3ce4b1da1326f9aae23839b4b26a71612585e91babb45a5bc629b060c182050b162c58b060c182050b162c58b060c182050b162c58b060c182050b162c58b060c182c5799ce4bb58c56fa34f5ce2c4f959e450e938cc304f98ae2c8e934306b06a5398bef18913e7af4d61b64ecc92592d517a2e7ba630f1c3724d01e314bfb1cefca3162bc6ab6ce3228b32f101b51698becf9ffff38f5bb8f098c0c5390cc3aa2a5114c7711c499224c99a132c168be544cd892e5d5a4e98f8bd9533911866d613a57350fe9114186030c07e9c0a6dca1811f79a9a324682bbcd3883db8826ec1de7702c129be5588d091336a32142be8761187e089bc13cec4b180c068395ef30b01f65e43956c936df68459eb0d2719ce4150993953f5a85ae16cbaafc5cfeab7c57f9adf259ef1baf6225ac24227e391babe41afce528f3f5387d64fe71b472e20f65314cce604a092a54a850a142850a152a54a850a142850a152a54a850a142850a152a54a850a142850a152a54a85079184c9c99f9c6872962fec8549ae2cc57c2647ec2509561f8129f46cc8be3cc77e35b486888b1b7f1e2cc57e35bb9268c297ffc524696e56b20f3a2a964fcb208fe022396b2f2636f7e58ce609e1467fcf83232df0a612081797146638e321a1a7346a47cd8c3be7c998795a20ff6ac3236fe8c59eccb1953eccd1993063f9b6960a4c1cc6fccdef0a4f1e397339f8d995863f68667cc8f3466325f0ba708fbf2cb52062bc5d214611ef6658cf8e3fb6f788ae5986de6eb612f8a62cd03a61896ff82bd287bfd18cec87c292323f33846447c19d37c7366ce7853363e8c2cf6309987f9191f0e989799f946aa1366f682cd985e5fbe663ed84b2c5ffc51e61ba9ced1876394c1fc48d5844f9967c1664ce297e50a619cea884f998719613f9aa62c9f30325fcc4c1da960b2d257be1be55c218c1a044cf17d231591509495ef7a18590d0226aca43a63b117b04a50cb0a6198612800118ce0c454a1004420822c422eacb8a8e2628a8ba898d2c5e5ac76444ced889a07ba78a04b4c8c28c666b1982ce6455124aa1d618a628c07b6d48e20aa1d513b02a68c9a046a11a82d51ab42047f396994ca7f3d0c58ccb9159a188fe2935f449c8d52a314c639144792f5047f1965352b337fe8aa59bd8ac617bfc838463973ebc72fd29ad1b4def534e347395d33b73523b283fc714664478873188aa2388ee348922449b2582c168b5543c2cc1f6ed9d2a50b1266b9e32467a2954fb4f29948d48cd8428c3384d3abd0e2ea2c637c7c1b165b4224995b38f3fba29ce318922fcac62789c65164e11c819c31ce3197cc375a953099ccc33c0ce6c77c08f34a32af877925f3f5315f6251cc632b24cd227ec2602c18f263f80c6346b1d9ab4684f99af95c9f5dfffa20a13a5ae528e1c7c860c219cef05b10a3bc72f84519c6d41c108ae2388e2449922c168bc5aa39a0e60031c78a8c9f3f5634ce32ce312372cc62cea12cca88595aaca87c787dd054d0944bf6b3e51459ac99efe74a4a4a4a2aa88620a9201b849852f59a7a519de302a4826c588094540d5356e30a4a2b2cce9e84a8728d1055ae61b130cec92fca847438c52745a1b0c4302c13da01e7885ccef1b525d78ca11825fc590b676d0833bfcfcf51fc560fa595951255ac7a2881307d6316a9522a4b2995258b0fa56daad421db481fcaaa6c2bcb29a5114253423b084d91e1a58cf24246195595c54b1629b45871c5c596322adbc2aff5e01aabb278c92285162baeb8d8e243962c5268b1e28a8b2d423b08f9504a79c9525279c922c51519a554594396524a6807211db25859596511daa1b42aad942355b6893ffa706298c731570ccf6a9866364089cb6f85e1d77e307d6355f8f3aad20aab54bdaad40e6032b97e2cdff541f2abcacbcaebcaeb896c235f52bcb4645bd9faf0afaeb868952f29d70709493c7b19916ba6e41aabd79497112fab6c63e19755cd00f85de3cc17a5860093f5fe9a7200139fbeb16a0c7f9c321a61a544b655c936d8e9c3a74f8793fc2aa6bca664db2b4bb6f95e53c6aaaa33fc5188f05f46bcaa649b5751859433fc9795fc83877caf2aaed993f0cb97aa707cb95e7166e6737de3ac45fa6b0b4c06160b06cb31180c46041b9f050323638e3131b35a1964d4192a21e28499f9a29c30cf9285368461ec6164b120a9201b60415261d038b24211060bb78c5fd60c60326133dbde173425c26a44f1566ba4f2e1243f48c6679054cca83cc3998c2ca64a6883799cad87d9e2384435264c9c051127b68ae271c668e0c4b3128cd317a301cce3f458915188718bdf6a65980ec689df655a599d6489652f12cb44d3eaf48d5467eb4921666355aee971b6bec7497e8b8cb9621542998db2f1c72749724b2cc35c50925fd67a3099583f9ee478b29efc56141cd9360a5189b01a51ce512cadc8c7ae28a3d014eb3f9c290967be28e3b803d518ca5c98c56279eb85a646511cbfc4e2cc952e2789c571d67a65711cf283e4da044c92bc726228b3202129cac417838451ced1ab5a639864d0948c4c9054900d4153e6b364e6cc1725c88620293f71d054900d3466c47c6b562bc314adce201b4a2282a438e86280992b335a66b2cc5c054dcd3c3123c58c153357826cd0c2847d4d0bf13dc67c808c14f695449ce28da9280eb6788c088f13bbde6763090ea41c479cea9125b4117f86cc439b58f93ef3013cba388e7845ea14bf7601d337ce5c39451f07be1e5a4e51ca297e79a5c715073348a941071f84b072e54ad054900d545553acaa9ce273d0053603cfb60e6439fff42ab49071965e6618141c251361a24cb2be1563cacc60cd94cc9031637c51f0b75a3b50655beb7190308c11c13c4b06d32a3ddb84a6dc4ff285a85a32cf3966549e61c982b5320b8606e3194d97f0a76c955b68baf87a1091e4630fb49caf45162d8c384b0cabf56032b57e1c4f1d514fe325dbc83c13838c6cc3345d6a5726ec6b57a6af9499c2adcc92a932e3cb2de1cf8d2b260e5f8fd3576ef1c1a44e71c6cc83298e23fe159999af8739f3e17039cc8d2ba7e8bb11c67b711cf165a6ca17cb67cd7c3df2cc87c365a61ecfa64e91a64b9553fc1a064cdfb8a5cb2996563e06a7f82f9a2e1e10718a5f5ac962294569c5297261c5e96b85259499b34821aa8fc2f27156a57565cc82c5f7408b79658ab1582c2692b198e8fa58cc28238a315148089919a2187b99989711678832339f1015cbb432655656e20bed20b483d00e423b88e418575b4e8cc3e955642185cf63333326f631313131b18f89897d0c938ffcd6b770c6c89818f18cb162b1568c8b1c59b0d8c7624c33c634633e4818137b1913cc7b8c4c4c4cec67c4fc8c98697e902c0303f331e68c19b1f17d3364bec532636acc781a3364622cd18489f99818a9188c2cc8069c139b8932871929cfd7cc47be2bff381ba7c008c3308419c7cf423bc0e4fcca303139bf1e06f63039c30851598556d92a26b3b2ca2fb483d00e423b08ed305a9155b4f0e104e1f42aaeba903132261febc56f6164c166e3181b3f263e095b3fe3e382eb15c26231582c06fb2021ecf532a612060383bd3e06f631af272113fef23da6a48c817dcccc1734357e0c8cccc3c4c4bc8c2ce6cd570cdfe7c21ee6535be197b299d89af958a718cea658429464283425a4839010423a08f92044256b912fabf2359bf9a2b058423be0305f987c01eccb320cc9307c0fc370c60ac330c427ab2566162b7f9014cb17e403d3f89edf95737e312462cd9e84277e7f676121c6c9737a15585cc9c20a2b0b23b290c262b16a659833f94b9827dfc794673eec7a6101ee4ddcccc1aa6930c743dba1f1e0b0bb35c5d9aad6b92b2f75dddeab8fd8dd6a04d5b2af46578d44d5ed062a51f5af6593b8ae56850ce9e95e0d7453d485d247ee2e814de2b63474f75cdd5b83fb97be6bb0c561020e273886f8d2df96fed5bf5ffdba8fee17186c5b5688bbefe8a85ad53714dcd440c86934da07ef566f5ebd5bdebf6c92a7b9af6aad0675aad67def4d9d9eb7a6e81afcddeadf4d6eea6eda2a4ebbab6edf9be300601ebcc3e38e61f0e8ee3e376ffcdc6d697ab7af9bb379ba655fd7a666dd2a6da76ef77ff87834fdb92dade7ea5e4e0e90ce27a86797cbd9e1d13a3f3dba1adad35303d2d93f38fbd5edebe6826e8efb065926ddeee972de94d77375ef767b5b16080cbab8fdd3edce8611ee6fcbf6dc67d9b7e7eadedfb6dbeea6dd3e9aaaba6935fa717725376d14b92d0d5df7fbb45dc8dd5570b3c695efd7dd2baedd6f8afbb1ed0ea7db403747b79b727a76280f90deedfcf0f4689f5d6ec74717f463dba9f5fcf0e476745ab7fbd139a09d8e8eced1bd6eb0cda961e5c6dd954d5fdd56895c1698c4dd4300c1bddd68dac4b647fad543dc76af6bda046ad5485856c9c3a61c685850a5e6221316102da054cecaa2c80b9c6802721c00f6c503121d70d60baa8c0040a3f9e25f4ee0e30e34fc20b1b380e31f624d7920c2f34f088911a06a7cdc21bc408f073e3e9a50c410142079771b1608348400c49d490a2896a4a00bc7178832950429c559391a908120c850e2a2ab023ae02ad0e4ac18b24ca120832f4e9250ea1f59beb8b3747ead38f16c82225a932a82dc675044540a414a30be6d035f44e08bb38232a0abf2c1848f602460095fb1713ca546c8c6da848748a0a051c293023c07f9fd8081df1727dd1ab0048172f2908a2157c228240f8f8e9a40f8c00a4e1e40070f925841099eabf0148964ec70160c051822ea0810ce52810a3e34015b72bf620164dc80e30727693e1801a6cacac6575eaaeabd42eabe41164a1f11c18cd171ef12b5e4ac1fcb45177f606755617494c12c8fc1e30d0c835b3ce28f873a883c58b9d51ac51063d720d33c3b264114013b4b68f418123bc6781c6bb9cc8e310e7311c62c9c310ec91532ce98956f20614c6296671ca38599246b5e8fc59cc5292c629c5fd80519bb7cc4620e37c6be8c716e2dc934196752ccd8041963326312b0061887b975813164c1e01b18db6885f8079c319931ce210e67f1e5aa651806d2c22307e10fccca59dc095f39639b181b0680b85312098fb28b9e1780c5b0461c330e7d2c00fe027b76d3341d3b1671c629c0ad0c02c679cc39c4b807e7e01686e59c3329047f90b398b14e482b73b43cc0b1193399073ce61c58c421f67c94ff8545cf29e9bf840710baec02d88364208798c4220bc770489573eb1662a010e72c7e86b96af088314b47dce9a183f38b6c658c3166617cc3397b2024b12b8b61139ee520c6210e769519b7583807c93c328fbc23f4d0710c2673c631d10cc59c23e78c492ceeb08b035c8e198f18e607638c314d366295ae8c732d182b6312700be330631117e11d3928ebc86566e5118738e35c669688c331c4f80787b806bb300c632c8479e457c8c22d11678c6f189337720d2c663c8a38289738cc3c7018e62c661107e58c67f20bbb704bcc18e31bde915fac108b2d1163fcf31807082d1f6108230eb10b8b38b0cb752b4fa0e181371071ce64666d6cdad0298b30ce38638c719ce54037210aee52420afc4b08220c2d25c8b89ca089fee288255e6c7125d9169e1404077692a6c29182b0f203928c55424210be2e47ba16e448103c5a50a475e8040581232748c334e0c78b18073fb217b6798167605bfa0284edcb70dad2183c7096a6e49b2d43b037af03420855372ae8b1f4b01eafc10cafa291822f8d38f88b01700fddddddbdc66d69fad5288e94f2ea208a28968be512615a36962bdc01537221c9ac5543be5a40222c068b3012273a85b15046bc0a8001a24898cc728937b11d404744bd98c050f106c6855ca319978898f46181a81f4786c804208b2ff1880d0ca246f002085a5cc0e34da6471017b23813e200b10cc818c2155124d9e3488a8d982118c2222ec81095c3d50456035663052236802df7f582281fafabc812014c962b8c8d4ce20c35b8d01261c81d38a6c7053012e002010b292d2f3cc0e4720c22c30a128dec13ac5ea031d6bc88bc3c205110416005bdb04410455e28e2861ba68e9498ee88009e882a83bb030420c6138399e8088558396c2ebc5841e4ab0513fe18150977bc88bc20eac5328a25b58a688888bc5c45b024d4c712511a8837b61779a311235f25d14c8521a25ead221e391aa2c6d01c314902f91a854810800c9541d707ad22f2c5ca111be2e2404ce2d2a0860e0f666e80d00ac10892072ebc5a34564face7c7e88805135933e32db4b960e2071f84e562bdc49cd1880814048f34a16cbca1e36ae9c22022211cadd70dd78f0b429294b5568dc881c8015944140830e290318491878b035147cc4eb8e385285a0e0e77218e188e0098a9908313ec8ac4115aae58215184100288c2c293cbb4dbba25155030c10993254947474628ba01f5d478d0c1062f6600035f547002304400d2c16c2607ab6a0a29183004094422dc76d88095e4135626e080290c1042014154fdb0a4e6831cda010ca094f4850c317226a8200514c0b13204b821dd01117ab1a6e030f5e3d2e28a8829b7209b0635ca578ba5834602114061a34a928c60448408081b669061c6169f269038a288284d98fcd870d41039a0a5054c80fcb0b958e4036298401209d821071a0080002080b841491220421fc0f018a10cb217b1cba72087218291bd18b7e02d7216190bd715302b32073215d94a7e40884466127d9803dca3b563d411cb9135c836700d191ae38c2c834d112697e32bbb5aadcc628d59c421c6a4c762429ad08928710051e2111284c72c17b8600e11358e3096075bb82006b1236a0013a201a400a2c423ae1b2f1d380210e52a413421e451be24ac45a40544be42211caf318aa85695a81a28b8e0fa097f6001ac8ba8f14bd4089bc1220af6ce9c8872e180c92ca13167d441ca4699838717c41aa2626431b2104726a78543e6cb0b63082d20968f3026f4d112222a44b29343be4823a2c2929c116fca9d108b30f1e645640c8155023943be481fac06ac860b87eb06ab8470062f9033a1d50b6396a80e7ce2ef711dec106fb0185246c4214e28443c826940665613160d2bc96803069365388ab0300c73c80a5ba1eba5430c594b5833628e5e322c9285439658137344dcca11d2b8e0ea3136200ac60817644891a635e405b18b1766b8f72f6580a1c51507b468204b909784c314d190083f7ed8550529c8f9c08c69b14e304149922f1bb0a2033d6ed0a1e2218801bac8820a2c149000120cc8a179b043f0bdc16d5db0822e5c5c610506a844694105144c70a2244911223d786870c30a13519038a20516703b74b06b0f982e40f0e417f5a50c18bc00851334b8219305960c5480021288c0036eb061069c0a25345192c4888a0d64608a26a88a3cb005155830400127861082061802b0822e595c410127ac2421256aa3464432b12e22e0d2850630c0c40494200287016c14a7020a2734312212bad9c8c4a8d880067e38000e5236aac208464488846e3031d145c0858a0d4091012626a0c4038820800d525218c1e887d0eda7b663334346f42f22e00202283490010c303181071041001c6c1880942f7029a020420e8d8c318e188981f9808ea91a6870d244270103a001eac901ae2f61197906e3185906ad06884564223203304fde097530adc4094308ff468fac03d3b066c21c1887a801bee1a2316346688a313018333603cb51ea78c9b8582d929549721cc31a779f717f992e75ab39fdae690bccd928ab4bd7e00e77cc720521dd74cd305d2fb3c5c5e66bfe379aba6bfa6efa6ffa4250ad6e754ff73afd5612ad23cc5695fbd2f3d674f79cdee67ff8f89a1f3e7e4d793bd7029aadedbef43bf6ddf45fa85c0a341aed04a322276774dc47a1d9f881bbf77093b5c5dd96b6b6fb7d3530a77d437093f583c9925ad3d7dde8ffcbaeef6e167d9b9aad6b83ac6bb27c2c2547d7fdea774d560d5db7c9ca6497efbdbc75abbf63ff5b76f7b6fa757ff356ddf6c82b6e4b6b7bbadffee56c5daabaee728187bb6b05f7edaa7ab783edebee33ad168d74e21fb8bb07eedec1631104ed3c906fdba00e84a020a0a09f205b904f502da82788276827482728080808e807c806e4035403ea01e201da01d2010afa01faf9f9b1fdf8fcd47e7a7e787e767e747e826c40b61f9bcde663abd97a6c3cb61d9b8e2dc807c8e7c7c7e6e3e353f3e9f1e1f1d9f1d1f109aa01d57e6ab69a4fad56eba9f1d4766a3ab5a01ea09e9f1e5b8f4f4fada7a787a767a747a727880788e787c7c6e3c353e3e9e1e1e1d9e1d1e109da01daf9d9b1edf8ecd4767a76787676767476827480747e746c3a3e3a359d1e1d1e9d1d1d1d9d9cce93ce76771a37471deeb6b45f70cd797fbbddb2ba144e78ddd4bc6a5878161e00ff37af9b1700feffdf3770f799bb8b2f5efd4d89251b4cf10511e8ee39dc149bb8fbdf9696fef6ba595afadbbbdbeaff6bc9e6edf1d2f6ffdd6db566e96fe85653bd73f58f1f3f64eeeee95efd93bd29cac4ff9b0f3ef8573fba9974e9aa815edc6fe115eefe6e8654fcddf40de6fedd74f7de3788a465db96c8896d5b76c80ca7dc69b4b0c9dd596e86ac190e719bf7e1e3776a7eaf6c92a55fd9f4052a71ddfdc8cdec85bbbb2d2d97aa6fcbe6b4bbdb70a7e1ee1cb88b326238630755ddf44b6d4bb4f4abfe95fd259b1aa06e9dd6e0edf6aa4177232d3dba5555ebdcdd74f71877877198bb97d807774772136b31b11479e6fe37175d836cee77ecbf41f6d917f7a62ad0755b9a0ead46dbc171f70b95cbe9e101d2eda01c1a14c463d3e9f60ece8fd5d172c1de9bf2a0dad74d79bbcd6179add6e5a85ac7aa39ad1bccf91f3ededd5fde9ae126d6c15dd50bd0c04dace4ee35dcc441fc47bbdd3575f798fb0805d7705b1acafe7274bbc9742f5fb8fb0d375d0a775fb7fa3e7ee71e55836ccf7d9b77d39a7fdae89afe6e627fbbc501b593ebee2ef78cba3b0e375d08b7a5bdbf1de9eed83d7bcbb6edfe553fbad736f8eef657367df5bbeedf5681bff4df54b7eff3d6f47df5af6577af33e9ee3adc741cee2ee3a6d7dcdd895577ed6e621fea4d751aa8756e4bd3ed269c936e7374ad9ba3635555e740b5bacda5aabb8fa1e8ee99c61756a55f898a3a3da431021dca982c7f89f1508c8516f2b766514330d8bb582ff15f315996223eecb18c05d7e3ec8abd4b16830843e1bf6452a4f050f831883024e252e643a52c16fb57f95278e8250546820fb9b08c85d763177e16cacf43af5216a321c2ba7232b1660c80ca4fce180015be08a7096b7dd92a6552ca97faa1d7b76452621fc30fbd1ec7665133292cb410fe6b16154a89e187621fc64c30a3a26232165a08bf9c45859f3f540a3fbf645278e8f52e99141e727d299312830843af97c243e59759167b2c837d1823a22141fcd89b103eec5b3229ae26518662f85978bd8c85f225231f0fd560603ef12f2739636200547e0640892f7e7ea5f0287624bec78ec20f923fcce412594a4a8a94388ba115fe4081d242fef05bc02f3e1407409122f543e3c7f0430e5072fdf82dcca0c4f043e30c4a0be4bf66ae590bad99d40fe11f9f356b81c43fcec2f76f81c46b598b41cb6b64d46430beb7ccd0667c1f29a6f8ef83697cd117651625c4464a7f12aa2d292fb880f367d1fd86a988a2283ec69809fba0f8f08f10857c114a53fef10d7ffc20e1188e50468872b6583351c634ce9e40395d2439be380b7df9314bc6d482228a61188aa1288a62188e327f1c3312937f24a2748c7128cbb227a1fb38f389ed2b3e396bca4ffe28ca9ee03899f2ec0d4ff2fd7ccd9e4029c267eb5db327504ed68c89244999387b129e4cfe6e24e6cc515a383751d6c630f397652bfc19cab218700ca21429073c11e1648a419c39e0890867f81837091f972c6f9dd845a129a11dc4f109d97865aa4665e21fb5843fa315ae727ace213ec32c1badf84f852cf8a2ca0b1d4e17eb5def9fbde5ac9993ad6705d56043d0944b361a916ba6e49a307b8c4814ab38ce68956bc2aff160e6c73e4a651bff70ea8a289ee2ff5c853ff83dfb6c1c75c83557ba1c651baeb28280d7e0f7a567fef15b331ff0ccefebadb0e5cc335f58fb80e9c33ee49a271a22e1493e945c73e4858b5cd82ae3c710c0b86a744171e2e4ea74926b70a9e5a5e574c97c4ec6596ae02cb79c384bd191a36cc3277612da601b5680d7d870551ea5c6fc231599b3f8ae8e62fe28594663943ffb13e2670eca2c5a3207b906565e9df89d54655ba901c70a28a538f1e3328c135f29b3380ece1c7070e2137f59d3c27c75711cfcb5294cfc3ef2ca8967f8cb2e2faa98ab0f428eacb135bac6a7711c635fc66440b50f00f97872b997967b61b917d2bd54490102d308d2ca8ab4b2ca02e363245ba4d52885ab306915b658e28fa4d599b7545db5b21906084c9fccd49633ff0d2abf85a37bf9537455e4af99f7f0f59099bac23253e596d90d2a2964a6cefc4f3001d4d8b20508a8a685e9218be55381b830f1493aa903e959c65951ab659a3870f808f1873371cb1983336b9167315bba307d6616922a4b8c17afda1437ad56abd53a811752b6b400b3a08a2d5c6230519ec1a65aae1a9886cce73f9af13ed7629a2d9f49a335c3868dd1c66863b421835d993e73cab49265732adbb23a434d21ce70ca19be87e6d454f8a655b6b96361ba125d5c215931221b33d894158df7f0c7ccdfca3fa30b519eb51a60cabcafd525fcc143648c23b6311b471bb327ac28a518a5171fb187306597a96c0b6b59982fb66032397094256ec95ed83467cc623464a6cc679e38fe2467bed1cb19be4cd9c5c638e6318f7926838de1933125acf7a955e490796833d674720d14262c4a8c6cf302930293cab6a96ca319c32791b0de97dfc68cfc8cc7c7f1396e601c391ec72be5781c383e470e73eaa4b2e16b9d30d87b4c2ce66338727c3c3c3c3c3c3c3c3c3b3b3b3b3b3b3b3b3a3a3a3a3a3a3a3a3a3a3b41414141414141414141404040404040404040403f3f3f3f3f3f3f3f3f3f369bcd66b3d96c369b8f8f8f8f8f8f8f8f8f4fad56abd56ab55aadd6d3d3d3d3d3d3d3d3d3c3c3c3c3c3c3c3c3c3c3b3b3b3b3b3b3b3b3b3a3b31304f463f3a9f5f0ec2051f5dbb2bf9f91bbdfb8f3dc5ca14ab73b4797b67bdd3c287555f20bfed23545e2c4aa7be8ddae7b124155b648c856731a5d37f089e86d77ef55724409aa87dcb110129bc4bdb9e320770cb4b229d29bfed223ed86d2477edcb1cdc7ddb776511d5112919047f59010b7fd05dd95d5b92f30b8919c76c15fd3575af70a6cbb7b83b927f26ed7d5a8caf67e65bfddadee776ea728fb3efa6e8aeed549035da855ff9e6595da0da5d557f5b9d9774d1f18646259f5d774f72fbb0a599dd895695d62e3c4aab9d74fe3d176cdbb7befa034f0d9f757a3dd06dfe04ee7bef7b669eeb5eeb93ff675833adaaf5aef9c5669e87e35bbba2ff46efacf5bd39597baee09dc718f3be631dd2774dc5f76c5b4fd6393dc318ee31b771c823b06c1c695522032c12809378468881221498870484a909088704447960c518204e7e444a25d54b7d7cdc42a21010a02f9edd768088f5551a3bda6bc9548484be38e1ff7705d16b8e2802eba5b1d7ce2e27e4177136d55ffd235fd3d71d9d438cdf114d68b7b0ee7ba1a886360de55afe92f6d756e8afe2fb86ed7dd634c6eb2402af097eaf40e27e62aba7fae7672d922de9a3e6dffefd72ceeeeeba64f44fad543de75b7bbb71ab93b09c20083b7a628abdb43d08da4ea571371f71188c0ddd19465a25d54d70271dddda2a8c63d6dd4a8ddfb084d71eddec0146a3eb69e9eda8f87bb6f209412d436c2be40a856c7d3831ae9ce1645f56ec7de6ebb6d59a77727a9d982aa07eee866aac10786077b3a1648b4737a88081213743d9dd228a877efb4db7375abdb4ebf6bb6e0efd21762d2b1aaee55553b3dfb3e9476fafd63ddd7ea6e6bb6e0bbe9e7b8ee5ebfa763815bf7b2aa4b34740ebd4ffb5d59216f50c96a440489c9cee9a11d262dfb02d356e7ee21bc74b7b242dea79d8408121317755f564d3a9d5855d536355bf06f6ab6608d6e4db57a04d5ead7dd3ca856ffd2f6880812931dcbb640dcae6d52420489c91b04be4116b76b9b5e564d7a59d5bdddda0d0cba3c293ba7733837e8aedb5d59dd0e04ee0e04eadb0d8703ba1804ee0c90a1c9dc851ee4a5b97309db6e13a086700e9818ee341d8bfe568328bba68ffe8e65db2330dc3de7265ac692d2d2afe9bfe9eedf20704d7fc7fe2fe8ae671bd4e9d8f51c02c4b3b304dd4f2991d60fba2b7774c8593d774fddd4b9bbdb7696b4fbe876c301dd77ddba761fe96a70f70e306f4d7b2faeddc09c18ee4ecb9dc0dddd7f6ee66e3ccd01f1ece0dc7603d5dde3e909da76824041209e9da05e62890c2542dc9d8a0db8ab6d4ba46355f52cc0520a1bb4b82a1775f8007035d94835d6a00204dc75a788c2084a051f29d4e07a978296deab813950af14ee2e46f1af1b44fa1f6fbbdf7b35f055f5bcdddc5d27e71ec141775f72330596bb2d0daa7dd79d03d43f1482af7ce48410bc9a9736e9d0881d4426a415af8bfe8f1faf6b5d1a643041f59dc7f9f13ddae6a17ba3ec9ab377fbe67254565782929190f3e814f23efe094d4bf840093edcdde6c35354c28d0f11f585b71c9f8073a2e364097fd259d9d44d9b52946787a68383a36a1d7bc4dd3b70cf276822e5c05fb0491026633009c3dbcd6bb5faff84a6cf64eab7df94499049ebee44dc6472e34ffaf7bbf7ae4e6ccb03fe82bf7b2f13236ccbb67b8554bddd703821e86ef76e171c7247a2a485dbd2da9c9c9c34c7ddb1dfb2ae6e37ba91ceb73dd1fdb24950bd8b9c76922454efa2251b65852405a15b0d04feda9ebb834f369290750395007f6d115218ee5ef3bc87ca7dbb812dfb43a272f7740dd6b848004072e2ee4070de75bf6efab47f65d7d7eb76df4d1f299b248451f30bfed227fd63797b2541879aff27a1258135490042820eb779205ff33a1ebb57277d8404a9c815220e893e70b88b402ee68832f308e8eea31dcbb647afbba69a77b2445c346925427275ef89682f79f5af6589286139f0177479ed5944b7fa68b753b23ab143786b8ab69acdad4a5cdd6e5507a5dbbbf4886ef511922dee3aefa6502ff0b74940320449049050b99be29efcd0fff12eda6aa7d58945712612134c244b9084ee29a07073020aaa0ebe3abd7baf92233c1c79724487bb7b10378d70e17f83a64b4bbfd59c5e6a77138bdbbab4a9ddee1294aaeae0aa7fdfee57abbf73bf6a1d4dd5c135fd55eb9ef6bb796830674409234d9e020abf5748ddbff91bdd6aa0eb6e1ddb027fe7d0a674eb76bb7f6c92bbef70d3c8691a61ed360d3ed9eddfa0db0da2abee7d4f49c9085d8c6095020a7fb37facee0db2233c71dfb1ffee1a448d908c90c41c41c73d05141e4dff041468488438f9475bed045c82a638744d8dec967dda2b10127ce8369377bbbb1d6ba4e4dbad11ada8044edb2fdbf438bb05ee47f7bbdaa9c801454e965056b7f4b48db2ba27c2e4e8752e6d756e2ee87e9b7ebb7b6fba95cc22d35d37f0f7b3efeb560373dc2c72c5ae4e7bfdd32c42a506d1ddd3b9c1d309aa770f35d26d8f9b456096d074e969bad547af350a0ca2ac0e5d53236bca84d3ad06ea704d6eeaee75f3d01ddcc1274050203d5717a17af770ba27ef1a6475389efbc33de91f4f4f70af90bab8cdd3aebb7fb827fdc36d9ec6fdda74b7b23a20a8910fa046b277ab34e4426d26144dd7d408baa64ceefea5efd34687c4a0e54e669cc7511445310cc330c4243992238b1c4516c96291ac18864eb0a62c1087eea774a74bdffdebbd69ab7386a070a8dc6f346d4a51e06fbfaf06e2d9093efbbeaed6b59bb7df35454237ba1241a17ab7eac926799f761274afecefc7ea706fabdfa4a3edea7de465d524b7a5e9dcf497a373d3df939b678dbb83ae9be6f474fbfd17f842e86e378f97b6ef6e83e8ebb3c659c3fd6f40a006023510a871badb6ddd47d03535b26b3a62774c8cfc8cdcfdbe27d49bee24de9a9eba9dc45b53269d1e7a535daa029f88de96cd9da8debd932df2aedbdded51dabeee463a42770a0cea744a76cb0a11f2b451216f3a94618038d9e90e0808407600d101c486bbaf6ccadbedbf690ee7f5ffd876f7bb655f17d56c8672f724377fd47077276efef0c15d53fd63d1dda47baf5f5553a77751bd7b37ee8ddbee77ff74ab81aa0e3ed92ece9be6cc1fbc8db23d9ddeed1a7c74b7fb5df7df54bdb6fb5d53b7a56d5daaeee0b8bf7dbbd59a6e3777f3f4d19346a26a5dca638f3c6924bb297d7512269d7e93a05af6b7913c6924bc35dded11909f6ef551cbbe41dd7ed2ed27a25dd35190ddbf5409b8dba35dd351cd167cdae8faeab62f17745596cdbdc0add36957d54d6c0b046a1cbad1bd57f7655517e7c4f65c1cbbbaabbb55e04fbb38560da2ec0fb76b9bdade8ba64eb8ddd3416975a3b8decbb67b057705020cb26d1160906d793820a8d1bbee1f10d4680814d466c241b5bb89d5b9290a043542b78bb269bb813834059e1e746f17f763d155b740b62e45d714d784d34098f8d06d26406cfea6c6876e3371dd1e4ed77375516ae40d02dd740854fbae44edbb5bbddbdeab5bad438d5af6d5aaca0a418d80e8e4dc23b75bbbd196bddd74bbe94d737ff3a6433c3d412eeb4e81a96eb7ed46d7eda2463c3dc19eab8b8090a046ea5e57dd1302fcb545a851cfd5451b6585ac6c7abbada9eee974ab81a8de453f5adcdddd4de99bfed21688db2dabc3bd2caa995416d87375d17e359aa2ab16d27375d1cf0f1f4c9b154773073627eeb6d3b4bdbbff0f1fffb725de9aaea9feed76e95f57037feb56dd84ae5aa7db282b44000150e1879b3e522edbee159eb7a650eaca3eaab7faecfbee9be63edded82bbb4e73a6ee2eeda4d9f96ae0707c7e6660d8bbba3fbc90be9f4a8c0f3abeebdefba5b855af5bbfbd76a37c8a64dbb3d02020428e843b799f87083ed66d2b1aa8e3d92be6a1009badbbd3ab1403c3bc1770db23f5d939192210677dfeeca02dd8df4d33959535eda2a519540edd213ca6d77ba4b5f3609ba93f6e6e93789972261f2d33da12dabdb485bcda5bc3548e4c87ed9df46da61a2c384d7d4b6444c4a8894dc13ddbffd1afdf66be4be691321fb5d8d7872fc0db63b5b5cedf4aaaa757f9a3b53eeee34732788ebdeeb5fd3df7ed3df2a6f4ddd3fdd1dc7cd9d96bbd3dc60ced4d900bba23c3d411d1cdc7d899b3a3e9ca6aadbc9d57fc35bd3d76dd3ddefd87f1a94aa0677bfdfad027fac0e4dd177f7efd8efe95e3dc4c3e45d77aa5bcf1d26efba7f501a88dbaedeea4672a1b4937aee9575da49b6ae6589f0d654d7b244dcdd6e8f5255336177ab917e75a7bb6a60126f4d6f37de9a32e9d7c5a92c9b43b7aaa6b9761ffd581d909a2de803880fdd66d2b2690bc4b1ed5e616557dceb6a55035ddd12bdad7e5d0d4ca2e5406b3d6d74354ac2f9c1c451427bddcde305dd7f7bbcf4f71b08f5ea6f77ee175c7ff7de9bdd7b7f415eab7befef77da4994e0f0b8d33610ea7df765d5a4fd4b9576f089062a41d7d408baa64ce68d14e64d949b109c96020a2fabba37e89a329d8002cddd3d57abeea3e87e5397056ef4ddb4a7f4b49755dddfbff47d1b5dba4b751be8e2a06bca5483aefa9770db5dda40a0eefd12baa64c4bbfeea694b7631fdd6fcb0277fb5bb7eedd8efd55bf9bfe6e774f094afdedf608ddaa9a1ae9b9fa4d4237bab243aecab247b96012da6aa78da4b2ec91cab247e8cae6d625abd1d66960528f176457a2974db29b5277ddbb3d84b7a6506cfbba7b08bad70d54b25ffdba2acb02713f76fda55a15826e740db2c01f2bc449b768ef4d9ba8eae9ba5b6d370e08d4b7db5e53756571bf959726e95235173cbadd82767c7c785a170411bcddef9b3a296d9efe19b59bb7a64480bc2335d53fa2974d9172bb89aa79fb089456816e3a44e94d8770fad5436c3e3c7bb73d2526add36d23361f1edd4bb2f9f0b04e4a9b49ab433c3d4e1a69a7c74923e9f43869a4201e278d04c4e3a4917e789c34928dc74923f9f03869a41a8f9346eae171d2483c3c4e1a4987c7492305ed386924a01d278df4b3e3a4916c3b4e1ac967c74923d5769c3452cf8e9346e2d971d2483b3b4e1a29c84923013969a41f278d6473d2483e4e1aa9e6a4917a9c34128f9346da71d2483a4e1a69af3629b8594395d6d43e78e20322dc5175a744a0def45d376af441cd918edc9d3aed24a60739b85cae170d2ae772b95ee87edff4b7df26c7c571735c1d8be2aca9fee5b0298de6ea583427e7e602dfb75793c2bbeea67dc2ef9e92cbe57add6e1a88aebae5bdeb6e22323d28721aba7f4177b71eccd0d0ed0635f0df75b76d50c8eba647ce77bb38b3832adc69e84e552050ffba77ee5dddfb77bb0ff5a62ddb7b83fa9d7692770db242782bdb36d1eb12774f82ae4116c9893dc2b24abb657549e87edd60fbae4b94d0dda6ee1eb2b242d08dae4176c8dd4970df2ba449ad121c0e88db6f10f86385aca9ee095995242d61d2e99caa6a2250ba75f3dafd2372dfcd6bf5cbd3136ce26087bb27d96a4eaba96e3ad7252fdb73817a4d5ad9d475d35f2e98a4b22c129749b77bbb3d3a02f5a66a9a4b5dbd89b8bb91119c49c71e4193a8aa161254d9a4ddb26f12ab44c46df7cb32d92d8b844dd2ee26954dbadddabda64836ce1ac4d9aeee0171d2570dfe72a0deb4d54097a75522ba7d9f8854f5d4b92992bd89b81b08f5de6eaebbb2aede48403c3b415917af9baab7dbeba62acee5e91c0ee8a647f6ab75a90a0c0e6977daa477d1cb26e1e9a1fdd349abd1cb2641d7204be465936c944de2ee45457000e2a66c87bf1facee665137edbddfd3a53da7bf5142b71b940a43ff057c0dfeecfb2e4fabbb47376fd53d1d90fd1d5cd3776575cfbe8feeb47d3fc89600a58753a10717771e9a0e6da7896848099252d212763c05bb2d6de7d8f67577683a341e9c9f0e6da7e9d7546d371212c8dd95b8d9e3dd7db7c157efdd2fb96b10d7c4b4f4bbe7061fdd6a4eaffb77ee5f37f87b74d5afa6ede3406da69f1d5a8da683c3635522771fe2ee42dce4e16528aa85a3a25c887a45b94745798ef230ca6788721a68707fb9cbdda5dc0510e5aea82817a26888728f8a128047bde0ee6e82bb97e0e68e2cee4ebaedd9a1e9e0ac4e6c9bebb9bab74388ff9eab8bdcdd77ece0be7f6cd25ed9244aec6e35daa86e79c025afab8fa46fba1aad90aa7a4d891041a940e0b95ddd3b52e2ad69fb2621e180eefee9f5d569e08f1572bbe936caea9a787a824070ed063ee91f938e5573adaa5ff6c53de91f101f4ffaa74bdd356ddfa78ddbaece01e1e909fa68f7d193fefd58a59526096ff7917bbb1d61d2b1ea101074038169fbbab79fab9d7c283153c3abdb6dcbeafe6557f77f973eba5fdd063eed77d3df3da5175ac2b52c6e09dd3d375dd3ddb71b55d3e090dbd2dc37fda56a8eae75737efb75a1dcfd87bb631f8eeea676bb1b69ef9688ce4d7fb79bbb6e26f6bddddce0abdfa4ad5bb5aa8750a377abaa3e5ad9d46d37932477074a01e885808227b850fa68ef1dce85d240d7d5aaaec9dbe3a5dba9090feb49bb41f78daa7f7b600c0f4c79e088d3760ec943e9d4adb4c50ab648c01604d82288d35c28b5d52e12214e1e6ad5ed46d2220a538b02985ac4a045cd69eeebee57ab4b8f4343770e6dd7e0efc7ea7ee774a95655f67d22ba62e2ca862b2077a7f1d6f4a77b5a7a1c9acd0bdc5af7effabaec2f874488939abdd36e52164bb24882c51858a0008b1ab070b190b982892b9c5c017305698595154eac10abe8a28a1adc69dbd53d5d1b04fedebbdd7b57fdbbf46f705a1cda6fbf29fbae290e6df75e77a3ebc6a1edd83fffb604d5ea5497eef6ba734b8f43abd97172636343a3d5fc4d0d8f93a5df395daaa64d9e36e46f4bafbbd1a5c7e1adbf63815a476372d3f65fbd73e8badd5f77464fdbb1bf84bb59faed37c5edbd5bdab1bfe4a2ff7b13d12dbb5b79e96e7713ebaa5ac7baedde3171b30a1b1d20a3036474c008a7b94e4b4b8f437b591609c9df96961ec79df6a6501a891027dfa6ade6edf6dde03fabbe7e26f774df76ab2c9bc3b929101ba0e0df00056b7cac1a48fb0487db3928fd73b3e90b379d70b8e924829b4e25b8e904e5a61301dc74d2805309dc6c9280bbdb663c87cc4608bacdc43940012d5b3c05ea1c257727c14d2d50dcbdc7972f5fb4e4b40c71f707f27f6bd957b79b70de34876ed43d2b41371a54754f44e85e973001717e2bceae6d72f719496e5261c493edfad080683a38e8aa5b2a8e72922224478c8c6054542413d94000dc9636c513ee7f7bd35f2ee87e56624eb181ac4d8d294516f7efed6fd99d7800d100a3894b9089dc4587c203505c91a2c85d0a9b28c800f25b44914514556ef33ebe46f6b7d7d5ea1a857a7377cbea3e85288ea2088a02e87fc8fe6f299c1005e9eeee9be6703f649fc3a1fb0dde8a2c19c28142cadd715c1c746f1727bcb9fb1137a18069c007775b5aceed968500349fa6675fadfe5a76d76e20dbb63b88a6fa686f22596068ae0b4c53a85daa027f7a3b2d2d017fc1dceb7f37ef6fd8a4a72d01d3977d9f7555fd6efaf69cdca5a5a517b209e185369107e143f8bd77b89afff1c0f4c5bd5b15b201a66f8d4ed53adc8fff77ab3939bf5b76e5a537af1b6c9796969ef650b9bfb101a66fcda37b85d4c581525bada6bfd47dfd6bb0c57957b6ddfdaa754baafeb5eecaa65a0df276fbebca02d3f7758e7df6fda5bd77b82515b804f5a64bdfa6bbc7e69e7d7f064cdf366d9afd92aa9776aa02df540dfe7eefdd9fef7803176948917ef5903789bb5f960950b7baa41758546bbaddd0cda4d343bc34f7a6ae6e899a007f6d91d1bb935c9749c71e71d3df8f15e2ea5220abb4429aa4d58da4badb6555d44865d92324214f1b855a3530c96d5997a7875e373dc2a4df2455bfac92ab5b22d7656af5afddaf6e02fcb5453d571725ad4bdc55ffda7d34c4dd6d242217a891ec9765b26bda4112dc8dbaef4e7281da09ea896d5d95dde913db1eb52c91bdc2de2d1157bf7a48cb127181ba557237943eda297173c12425ed060693dc1fab032e69370fdd4f3b897e3712571fb9ba35c8aeebe9be6beaea96e8d4af46f5bb91003512d7dd2971df55a3ebe69d282b84888bea5de4baee6e79ab11f0d716a92c7bd4737511d4d0465921aeeb426d23aefbb62c503b01c5dd9d38c18924276aecfb377fbbf95bbb774ec0dcdda909319ad8e27f637b4e7f836ba20977a3ff06d99feea989013cddfc4d6736b1a38916cdd5e8aadd149501b6c28a112f8595279a3ec225b012c49d96eed276373dceb422d252309978826dbf0913528664254ce0d84d13e0c29d862659da124386bb2f2180256ceebe832a0bd4bfdbadca167787da4cfbd5aa5fc0dd5537aba06e4b03ea5f4ecbbebaddebe655d1f91ba685e15c70907bc12cc700ae818209f700cee11198f5100130fcc726bdcb4b7dbb7d219d07f23d3708fcd70d8e10819ebb19811abdd11c95a007d1ddfe9afeba4409224c25aa9490622a01b451f5cbd6fc6f94d56df4d9f76f4bd8a6ca74b7a5e1fc744f393fdd53bb5fa046350e4a77bbb51bf7d33d991030c21f4addaf4ed1fdfba5bfb483edbbb4b4a638dcaa754b10b881000e045cb9ff2d09205c2ed7cb3d4188cbe57ae156ad0271b82468c07f579db6bae9f7ca0a5152552dc4dde99346f2ee4e77ec9346f2fb972a11d16c760eea05eef697748ff33b4b35bfa45b7a777d59957d74bb3ab79f7d5fd56953dabebaf475736c0b7c37758986ce219e6e77931e42439974699b63dd67d1674f57f7f6bb4379eb5673a9ebb24028f575b5dad3e97db3fbd19eb6d3a3ab661f6a33edd5897db5fe1b77ebd2cd63dfdfe9ab1fdd2d8b03b5995ebfbb9ebcb56d757476cea7d96c57ebf47edd35fda55d9085aa496f762ee969a8ba53281dca5b53a876074978daca3e30f8e85ef556d15543b5efbaee377df64ddf892d7a9a0b0cfe5e53f786c95dd3dd46939e66e3b639f6d9f75d4ddbb4b4e6a1806cfbae2acbea975dd75f53269d6edfdf4d9eb69464e97770922c3d94ba9bd257b781ee6eff06dde8aadddd7bd39ba58d5bd9259b2782c444bf1fac2c5ab3a65a05be1b44d5209005fece7dcbeeda0dfc5dfa4bfbc7262dbd9bdaec5abd555dcd43b5ba6581bfadf43428cdc4beabd7a5a4a5bf1129294982e3444913a51dbba4a3aafadfedee76afecbf4f7bfdedf4376eaa7feb56254f5b2a522a9284e8084e29091192224449b8244a8c94842c41524a4aa244080e8968489225c0e0ef589c7fdd547dd4757fdddbe9ddb9dfed589c8deaf67dfd9b49ff7e3779dacaa68f9444a7d7fd6efaf43477c7f2d0ad3ab12b13ce9ab23a1cfd3d5dd07d77bb2cb00d026fa05aedb6bb09d5bfeaedb23d9d9b6aa79ba7fd2d4be469401b9c95fdedaafba1daddb47f33a56acdbbe96fb7bf57f65dfdbc95559f75ffa6dd4ddb89edfd8dabb23af6655be0ebd21e50b7bc352de144f2afd1d37eed7e5f97aafaf75ab7eea0ba5bd3dfb94fdfd57fc35b5335f7d3bc6fd9ddcebd929224af94b4044950b7937e83a781f0ae5b4ddf35f83aefa6e886527fbffa5f56a5b93b7dda4f5b92e982edebaeac6e0945b5767a77d5fbe70665bd974db23a2981da46c2ed42ba067bafde68cbee76ee6b3615785e55774e012a4df7bc356dd99567949dc857e92fa96acab4f42dfb4b9b49bf4bdfeea6bdfe767aa19c81956d756beaa6b4dfb987d2bfd70dfa507d3eedc65bd3b5d54d6008c2e7ee4b2fab262db5b4aa26771ace9ae6a85af74d69f0c97ede9ab6389b690db2bb7f7645800d775f5ada6e50eb76ee6d35f0ddf4770e078829dc7fcfae0f830f5f00d93fbdbe8f1fe51426eeeea40c0257dcdd6d70e001512468b09a7b0a016a50ef36faaaaad19465d26e5545d23aed8463d1a08b03ba2dce4ddb5e10f843535ceaea58dc667a5dbde3a5ee13db02d120b06d6a7bfacdfd744e56cdaaa813db0a71db0d04eab6098b065b8dc4ee96007f43daedea56eb561fb94155b71ab5ba97e4ea561f6d26fdbaeb92d7d54492bc6e7aa4dd2fcb8497ba2c1a4cda3cfd4b777bd432d948ef12253fa322aad6a52dfbba69910b4c7bee9111f0a75f37a7877efb75a192ac70c75574c01d73c01d6ba16203ee780a29dc711459a070c71ac8e2eec113ea896d8fd4ad5bb5101e1a1cc11d62d160126f4d99f49bd4ee9dbbea5669659340ade7064229413db1edd1e8022fdcdd3b709387c72d14a0276400281cb7f0039050d4113ddc8207aadc1a80c5e3283657411cb09982a3c8400514032a3d1c858c2c403a3a2085a30670f403645605bbf003876dc90257f8050dae7ca25c55c101903dd5aa66d0054b49a97aae3001c2308cd185a70b271ecb10c6ef7c51400b0be0b4daf92fc203f8608b8e083c41f054045a392a34b9820b1073446b2196051b601785f3c36f0bae6241d18d151400e129646c09810b182d3889ab2310c6489ac24eacc00b08333f27780a28aed8043945e12eca08a3c6495518f8054ba67ce094c4962cd34491073b3c71957b4cb8d201952daa64140a00e4c00a2fbd7c030853361003a6284f11b4b4018d0f12e62861ca8c8707286ca2801619093e964212245d3d90889418e402d4e38623ab71a67485c711265c8d2ef0c2774cb11db3f014c4ddfdcb972f5fbe7cf9f2450431a0b9e000363ddf000f576ef8420557bec40e585cc1c1f73e44951cb8c0adc08b170003a8de20862a1e030d270c5d11aae24f1f00820b0644b1e46a0e5cb06082091dd7338cf1147cbd3741000e6601299c7892086ca1c3005ef8e0442290b3e3600a2d2e020c52e450c3011e789029058a1b2a50e53d4290907298529c16e3010315bf731b156e7861053a7b07365b7461920d7159ee87a55a1033df31032a1c100108513eb3020e4a3086891d478f0aa418d90003dc8613a24f1732cc380da90d723812250597a1018a0ee4c004041e738107c200b92a51303521e0220a1f550eab82420f8d2b2b882a7f475e8916047f09e1121546039a7017d01248407c114454ab480242d48ae845b19ee880210626253889842a8221acd8e0245e871855c0c8c7fdb213ba8809225e454083272e1c5c3481003718112587202109ce2f32e0b057c20034250058021251618d9880076ce0e54abe02044308b92180a85cc30c2ac0273257b2119676871119546598201e62285a1f5f2dc1c48d1460d1c1538a28b20495cc16cc020b0e38620c2e8e3013252ab0830f0f8f7b3e40a4050d25bae01a5306c059aa31e55eda011821638a28ef420789ee354017cf12e5f5600322a85c891d212c80e551e3414c91be3664a0e73898f0830a1890227f2187da04608cd0e2c123588e44b1c0114f711e8022628a2a578188232e0d5022ca97b87a48a50829e1475014406801d07d48d58c866aa506ff31c4ab0a9b1c56ffd133b4f08362f39d2b35e30b525dfce6014756cc9e90c26b3cd8e165032a1dce810c8e08511490f2df3d490143110f7c074d4f035c4063023ed3411122183d78e11ab0c08114040425e136726c20891c017ce033c4400008922a9084cbb08830c5608391c71cb1b1a3c444178f35c18227702c8139ccc9082c1713a07979a38c09e0ace003ee7a410a426a844006de6a010d2f6ae0217bebe581075270a206670185413355840b9c84a2022439d470021fad9881012b1690fae843cf50b0010c2e2a41a3430f3500e06290950482f880021e46210118e070457bd843414f081260f1d0a4c586e000099eafbc2d6ce1ea3c3f5d1106f602e719288ad2113b30c7654060c88b2a40388602cb0b02146c8e7d988d0181275870dcfa78b3b07085e32354c19c1a193806210b8f1e51d43886f1b0d8ada081fb0a78743042d9c1fdca004414718102b85ba000395da098b81f21c5164828d9e2fe030bedb2e3e63e00b3690491877b0b4bb42000040bee4fb00001168f70df0d099baac4dc4f00412eaf000c7724194ab062a689fb081bf438508014f7a11eb0e0e1018abb9015c01704d2dd8702443c21d8c25da72895420336f710701848415b86bb072fe0020211a1fb068e45a7c506dc7b3c7962863204e0ae4384251f371ddc732ce58431c60ef71b5138213384cbbdc60a4f963ce8e13e63370de94285bb1943111ee00106ee3057356ce10013b8c798d8948005e85e8e01f3438b07eeaf0bfcf80a50717735a0870d2114e1de4202ca13113cc09d35c5da43141770676514680328813b694405af608cfb382596450dd97dac71c5163086dcc5a90248b9a2ca5dcc81e5e70729dc432462ad1b43b8874a6ea84610847b8e41f9820d38eeb90146d0288012ee7907c24672c33d7fb084950050b9631524801625bbe3268004e084803bbe410649b8b0dc31efc807af07773c94450a1955dcb10c0637f80871c72294246c34e1ee25c038701ab87b076c57a0c0c1ddad64414544c9dd8910a2013688ee4eb57f1420c1dda5c090c99273f715c61003034feebe02408302b8dc5d27c210377cee5e428d009030e2ee4738605737b87b911640e590ba7b900458f1040adcfd661260aae7ee359b265b9eb83bcd0315d035e1ee20e0d059a20177ef408b0f50a2dc5de6c557c509eece434a91cfe6ee343ed7cb0577c7513543101bdcfd468f1c804cb83b8d2eb01051e3ee325bc010c606dcdd746d710030dc1da6f7ab71ba3b6c05ac06a870f7b28a003ea6bbbf9e8891c3cadd5db9199a30dcbdf50b410b65b83b8b0051298880bb9353a84033b83ba963890b22ee3eb2b0440520771753102c42e3eee24a7365c8dd43196cc04ae8ee610e371f3e70f7d04633d2c1ddf3173c3c608abb671ea2806881bb67a5928b6de7d5691698c485da465234a8579eab75ab812bfb4b774ee756ddf268dca0c4c111ee9e6f10e2ee7e830f2003001001053851010e77c7103822e7312b4368e0ee610940a4065c51e34b0bdc3d9c9200228e683091e5c7ddb108043841c9d40c3f5871774c83097ad8b4a38f06b83bb64018a58a11ac58a1e7ee59860d6a2020041d401185bb872e40810a491881811e50e0eed909151db0c2d1c51538b87bb68209408906891218b9bbf8e30724013ce41b24dc3d1f21124104347c40030cdc3db471839614f04065a503ee4e1aa0005eb015b73282b87be6e2021ca090c143087edc5d3cc012ab875e14be2edc1d5df7eb6e271bb60cb9b720e5516c1882515073c729c05b602bb8890154895bcce0ee466e0ea0a65ba15c4c440419cc1aa09451032c9402e4815a8773daeb7801ece3ee98080d1ce8ecd0767074bb4955f50f13e12138c61d014004b9bb0fee329cee0e030c2d90d73d15c1f7bfae56ff8578be03dd9abaaff33f64bf6ed56706284d58468c1f2f70246cdcdd013320867af0a91bdc8f9c8908ae434a03df6a2e97ae3f3c341d9c1c8ab3d3f6cd0dd96fda3aa17ab7355b500627779e26dcede6e280ae0c1bc8604306d1e66f7ff3b8dd6e6b9a2839b142802e5050b799b829f07453a0e6ad2af097c6e02ae2ae731306d7711b65d7b47d812e30edb9edcefd36928db22b6ea7ed2ba506b64d9b562255efa4f648b7fb76bbdd744be4e3e3e3e3e3e353abd56ab55aad56abf5f4f4f4f4f4f4f4f4f4f0f0f0f0f0f0f0f0f0f0ecececececececececece8f0e8f0e8f0e8f0e8f0e8f0e8f0e8f0e8f0e8f00405050505050505050501010101010101010101fdfcfcfcfcfcfcfcfcfcd86c369bcd66b3d96c3e3e3e3e3e3e3e3e3e3eb55aad56abd56ab55a4f4f4f4f4f4f4f4f4f0f0f4fa5f3a8b46db0c6a11ee598526806600400000000d3130030381c140b86c3f1805898d46ced14000787b06a7a441708b32cc861ca18c3003100000000000000603411003bb009f881cdf5c9f9cc01e584428b6dc4a868b92c785e5d0b7d03c9d36afe363b0ef41b93f7f97d7edc28ce6504cea222ea5587a4d67d098d44ba0467a98507382852b74bd386dde2fec3f01470cb9e5b0e2e3fbb6a095fb5563c0042915d82fc1c3da803f77bccc5f9974431dda69e11728d024af61e7ee079076fd04b3b3dee4248ac20bd350a49710f6170807f3e24d626c3642deebfb3bde19a84027fba0335001ee14e046adc8b15bba3ec419df51de8f72ed3f10024fb0d432bfdde748bcbbf3f07cf79588b7d1b0ef06a9d7fbeffa6c2bac88f6fedc5a2bb5baa3b865393a34e6f00d8737a033714a5a3360c4a2c8642b792e3eac76c167070df9e4159af1a40918db014f52ce10c72f67d14a7c4ab734b2719e81efbfa7f467627b37e68322122e291011ff6e4168e0de9f42d2b8ac566287778c2ed2230e7de863e628a559f7aae7eea2348c4219cd34bbe917aeb44cab8798b4d60792828b32eb88a0d88c6fa9a83d9c4db972dbd1d8a32589b0c43b5b4b47a26145e3a07223f2bbf7afdd5744c1b6f686f7f80784c86c478757c49c6fb74b364ea3a9fae43853ae2b7ac0309e40d42d093c6a806c6aaa2d1bbfdcbd238333f89049844e56cc150aa8d275f3fe87e8be50a38b5dc76ff62019d1291e0bec06dfcd7d0d04b54d573db14e44aad3d4f4b66acde7731229e486edd830114a20a80cd485fd8ee73e3bc5f3a4272838be327120a4c5fa8a520defa11918dcb2a49d92c22c8d2f36febf1e100a9db2e05332b88494a7410a7c0520c769ff2bfb9b144a662015c0d5912c4d074169e54a0e1b48483c8b00e958f1154a35a5729cce94568c1a23c0099d468de0052208944d5b75ebc8b7a58a4d342b0b680a5564b4a2c6e52843a1f684f51cb0a3d0a423f9b7c8e5424528a8b53484ab1eb66f9010afc9171915cc30c9d4c03859839620383f6e08d10390ff7c41f20003e3e5003f53916f3cc91bab34d3826855fb566039e049a1e97c1e0d7c513f511b4ec70b4d62134252c322dc24d7ff95f7b561232eb7afcbc6557306afe61e3962f4ce8be12ccc1b04f32d219813c867153e7031ff94453436fa0f3442240d3a7081da26f0ff64923c04fb9fb310a5809a3ee15b7d163a67fc48a2c28a4080109cca3cb3f320a2dce019458ddaff6c2f0acd0b90440481133ace034c219a01ed1ccce00d9cebd3865b8e7a0dc1218dd3ec703781d6a61ea6466695045d0cc245e07863211c8d15b0161de1ee0b23f2e85f14bbc8e03e8a659cd22b71aced200861d723173315636712240ce1941bfe07bff0af7475ac6530f004edc98ee932fc57bc06d74f337c4d38ffd6e27c809401323f2e72026e779c4d265b6aae7f30afebe1facf0d5be5e8975316428e273e504e457f6ed82900fb840924ecb126d47fba8b2d7a28897e3b9ab94fe93b8da704602c9d74525cae2bf0b470894cbc0b7638bb198ce8767354aad04a790bb1e450de7a723eb5dc40c71a61c9e80d11b98e99726283d4a73dfcee2a88fe084c3363a02662c16c00d32cd9ae7b07747a4a835b2243eda76b8741c803e7b8606ca4ca6c160911d949e501dfdffdb5462e354576a5230aef66cc3e6ac50ffbff1699cebc5c44e01c5343cd82965835e3850f9a43628902c58c5c0c9aad5c52726f23f965ca39deac0d17b518d578c056a3383491d6992434d011e22e94e27b78a4f668a9f54c5443a98c32855b20c330f2a2251cf1c422ce4404414c0bfb8964f3771d3a8ba5910937b692fbe1071d1ff180df23eaddfbb97e1af4d35859f06826ee10c54aa7144c70a8a4c06b45e5bb5d2b2ad654db163e3b058cb80afc9b8636d17f6dd059f8b708331ecc17cdc3d8f42604571c5a04c724e6f27490f214ddca0970c9b0aa6d31005decd17f8adfcfc8171fef8e5cca92a916404d68c458d1742a5d28ae6b28adb852612a83d8814e94adbb9dbf8fe896390401468c6bc5fd375e474c075271f8ce6f023be3213a0de1011f8bb141b27dfa9c218be24b653ea13fb575b86a94568ce14d2dd2ba4c4bd3ecc25188b93b714c12db924becca202ce648773752a9c7305159cd208c85c86f7985d2d63707d9de4978c1d7aac38cb8340e28400d1d4004d5aeaa7e884a8db2e2360090e8d036810bd9abbaef47d1ea5c24ec2859b41b0e100a642362c3e0361f847c15bda016ba91eb6b172c0a372194ebe752410bb8a4f20327336312791a57df001edc452ffbdb99ad55abbb794f00ea8a60bff38181a5d54668ca2a9f3e243c2b385f30512b2fd7b0aca8d4a3ce787d802f827458450e7906d370896ee11ae4dc86c64d670306f0976224dbadb3435621e1f53930eb1beba4b2df6da8b0b236c3d696ee74577f22fb07b14d0f0dfd72b510c20ea62dfcf04cbe8b5d5dd740cd54fbe5d0024c0f4f8a82434fc26345e13050e20d431ff791941d1fe96583750e1c1c856920418c8e476e3d21dcb134449de9b3c3843a91be24b4567b352da5da9829b16f6479ac0b51312479bce5a735da236b51223bdc50740e9390c862537c000a4b3e43daa09ee8931a0158ca747b6b370da3b2ab0e4f1d0808f56953ee33464485e923adef02347e910a3620d808a4160fdd30ee35df6a04c53d460db975133dcc64155906a1b0ab139a79f15959fb97f8202de9deba1f32c59b64d9eddf84805f168127631044b23be11b6beef4e131793d53bf4f8fc395bdf5950b77254c37a370aed8eb01f29afda0d53fc2df8f5ffacfb901a516ce2733139fb9119d8854eba549c301439b2fcd1c1aeff2f612c07e77dc481010737840c2a603ac01d025d90764fb8d65bca64353434f7791f5ad8d055037a8386323a1427fe0554ae7118316fc158b73afb8402d5d2d136b4eccb1c2112016e55f810c6ec37b3849ad3f89370ce929bd535a57d03a2e5932562235f99e8f1de4afb23f5d25ec612969c50d3b366acaee7429b24bbade6d92bd8368af90db9495cbe13c2293f558bce95042ec047d7252bfa1cc47078be86b68439228b87c247386f8584b0c24ea756a9993b8fc8eb9a9b51179e723c996d9a5f85e6da008fc1cca0d8eb6381f3c2cd8bb30411b4da07efae024f9c5ddc87e94f509f6064475cf6509bad91d4379f8ed99836da4057ecf8f16f659132fd5f145e017cd4fab094b30272f200d48d02071c15c69716ea3168a2f9b333bfa854a522a68e277678c6897c402b4c1ed23a19c97702cedb55e5c92d4eeafe6358eccd4035c81458e87de100b9495a33a020dbf18bf944d4f0f10dc3d77bbd81ccb1cb6df26fac0a20107e4a886b348369e30d555a8852cd1870ed0319fd66beea5501d84d30c2221194181b8c18226d164d205138d70a35fbf55cc2728510906f83b5f72c1d6387c927e754754053a2c506bf62e572398df2a43bc7999728badae3c461b69b2508d95d285709132d1904e8a2ad83ccffc2d1253e2e69f13b6136b240dc55f3ed5c5377862a4070dca253fb1901cca9e4693817ba5aa3914d149f6d9ba662bec68fdb7b928d13b5c80ea573aad31e3674320d829c000bacae1230b1073d7a6134de672742732099ddbd26336ce10cc69487c5974d96c98d4522923260a4640415a58e39a9030d8e407ad15bc0a68f4b1428428beeb2b8f9c2e18e1d4ecd8e0ddf24ce3999e254a304f88154ba028175448523014793a67a9a7245f42e6b8cdb1d32481d9f172e9d73e21425caffa0db4dd18c4934617e9d795248f8ce4ebd560b6e95fb79ed39a964c0cfa35ed1b717e810c1dd206da5b8492c5b976b22e8732644c36b0c66ab684da48346f2e2ee83d29182bc3019c06be10cb9078718ca738a9d24b85be1d1abc36bc45f24743e0cbd8fa48c4988202216f9bd06af4714e1e79021895f8d509c4d47758a30404d30c2f2bddb63f8c82255cc9470d17f0eef0029400e003bbac196a6e3991918e658465b2333f918a9bb0a0a14491b96a802f077ca16d3092e84fd1fc4ccf433d20feb005ab12bfa8dfeb113531da026eceaec80420af96cb0b876e6206289a336a9c8fb37d63861aef7bc08586bd8ee48e4ba187bc74cf6c5aff28d182054259d09f017fb28dc6481e83fdd871591b5c67e3470381870348ef4f596774701eebfaad2442ff5b6a9f871a5b5838b4c003ad9992142808b6b251356ece725481fe642024360027043c21241ee05dc44d64442c85391bbb2f1819869eba06ba6466e466ae689bdcc560a4807f34fc1f62ffda5bc5a5f299b33ecd600b06d9fba785b37a73b9a82da1e00d27b976c9c6b878c43189a20604fa9529af5363e2110fcf03097661d3bf7d9d0ff47ab190188767187160643fd7eea63bcbac8bf1c1e60a819a5089a98294752cf4e01121103f51415d0e93ca360c055cfff2a3e248f45dacb3a91641e923f0337d4c2a0d4c034b635336ef0add826f161af8ee20b437d55feb063df4e89d828dab8c90053d3645725903dca86019517a992c1f57d9f1cc5237adac4ad9a2cb99d8625d5ab1b94fd85429ce494268227f92f111e6f3264aae486a6befb2c90f696baea55d42456a17a92b486293519929f66a4f825d8e0e420a5afcd336932826c0443357090984cdca7f11c56a207ec5e16b6e75711eb3f1d8cb8ee738fe77b23c193c5d97abfc59d0500657a8a8ba648dc96af3586e2144977dec32fd4e3fb98f4d8860f9221b5d7a1fb31513ba208fc75658f4151411cce58b2411c8de49bb9eb1085c9e86fdbd8fcfe3d73ca7139447671a6389567c51ad600bef826e8ebc1caaaedd69dd11e8abd97c6d2dac5cc177c53df8923c76271160d5be18755db41b9c0d4e90cc3ed40aaf7abf92407d73c5c1babea6efbf1a37e84746f1d787503308bd3af9b2cec96d4587d65f0f5e44fbaf5dcf612673c103f14e5bfa90d8f4967510c1dac67e9c8725acc94030c07261968b31585c6e46a451a484c4be6b8063648e396fe4105022c8f88ca6269b49b473524bc2f465f5bc8f2acac57e3c6b27ba6693a4e8b3ec28aa20119ed7883cd81a36b271c0bccdd99f7d37a0e2f4b6dcbbe261bd4727b592ac268085d1760154db473335430f5c552d03b6c6ccee0da6fd37e59269396b60df7fb54fc3fe17bb0287eff84ff0d532d52c6f93f703edb7ca192d40f2ec2826633db1ce95e62655f9a33d93980a3066f05492997d8dc127604ceea03d8b659a9ec48148d707da7be2b2a9daae37fd48d9e223a3f9600d31793c97f2288aaeae17248431368f460aa1ea0eb3fc16935d430aa02b20bd2fb54b67de60dff556550d1b062b00a1a3933e4e8183bdd0e9b5f9862651185bb7eddc63e804301432da5e8bbdc3e7ee8dbf4c32d1cac8707c839272be7c22535fe4cceca1469b0daf46db23dce6532dd14a45e4e21e1f90f55175d89f37275c3aa904425bc3b6337fa3dfedd63df8b67c8e0350ac847f081382b75f09ef812d08119dcc6549b5ed6a919546f781fd5f05b96e78c1a4296b82105e430cbc23260727788eaa22bf7ffc16ae5d1c51a065f1556963e52088627ae05c7be19c5056eedf1d30a101649cc929ff0675210e75d1b6e1c31e68d9d42071d5125ee6cf7938d53fb1e716428416f189d1c3357beb9fd55616383d2ab09338b2e53c421c22d4176ba9796afb1a6615f2411944908e6528d9c5be19369eeadd0730a9211ab55bb7992835126a6ee3f840b57fea32114a81d151388a410d808a67cc90732bdcdb1c1baadfd03ea6df4f2760afc0fb6e3c79fb1fd0ef3ff3c27db98d8fb46713d7c49d7b56339be68ca8918b2063f9fd31a9986afae62bc4a130d1a5b9a6f103f3bf1f3e2fc932084be3e760729c37be4c0b1bcb9f0c5f440618a5edf00b83e6f2536865e56589e3a46d89be3c0f17054287bd70c20ac9be2dcdf53ba15fac1d476ac2440a6cec0b8e9fe7779bd0f809949f19e3c9b70794f9b9f910395278fc8bff0570b32395464d849f983f1df6319ae2b6ac70cf9111ed8694f3266f7759c323b53713af4181e7eca9e294ee5025c7f60693733513cd8c00db3a55877c8f6b4e9ad37cc1043446a4cbef4aab596ef105972d5f1f1ba9ef8e085cc9d158ecc7c6f0ab7d1781b8d277998edc8c73bbddd1c36359abfa679e205d6a0a026c8c79419655d8c668f600c651a30f58ec18825f3f3a1819ec409ea80bb5afeb701e2e4215d537efdbb2f2a11ca6b575db33f8e51351f3421ee85e76ab88d5174d3c7e7a862f23ab916b9d91cab30315d0813fd45fd95fca9b6c4161d49a9fe16e96b01ec7772aeb69638e8116d4d45a4baaec1de94a723bd6bbe075f38d80958b3ee50bde9be96c2c2b1bb62775aca64011ecb00e5589804e114850f606dbb4e29474e7f9a3a839ba9987929a0301d2afd995f053077842d64fcbf40ed0649adf7756c9e9651a7d6e294b756c163270f208322074ca25617aa8268b9da27a3f285b2be42cd639a4102d4e16f85f7cf49b43074f2a5255c1177a4ab7178066442b1bb4b07a4088544e2aaf880a1ec9891864f05f7d90f48e1f349b11f3af073969d75641576399dec0a647b956ca4da28a6539de15cb79e8bd61ba564ba23ccf56ab958ad514ea73b43f2b404c4d452d23f4e49a1ba97efd573d17aa3944c7705f39d5a365e694ba9545728d7a9e7e3d5562199ea0866ba956cbcd62ca792dda16cbf928bd61b652ad515caf52af978bd594a24bb02d94e3513adb78ae954673857d785ee327acb53dcc8b32daeb673d9c8c716edda796b84558b8edaeba68d04a253f5e9daa9c07aa257db4e05d613bdda7622584bf5ea5aa9807aba5fdb4a04d612dd9a6622b09eead6b792c1b564bfa6950caea4bdba562aa896e8d7b793419564afa659620aa0344bd424e4ff819da366433463a1e5f290ad38227857cf0a5234b6c2e9878ee23c86af97a177c1119eeb581b51d323a528f72945e916370df9b7d70618eb8655a2d2c0e52df33d57926f61fe56d9c377f8fc2c474c28b1d022974a6d717e20a5c7d67c78b7087cbd47b746e404717381d826d744d84eca09c95932096eb5f59bd75dcf5fc59d9de7ea159e40b68ac2788c0c69748ebec261369a5ab55babcc287bd79a404a5a54812347269492276e7f434497dcb5a654b4e113edaaa564b9441fae503d8a8c13ec8130ce77939f153ef8f947daab051dba9e172aeeed1046c30dd02bbc257a87124b4a359a7c9c02ff60396e3e1ab1c4cf20ef51c8ecc1349cc151144b6aeceaedb6799cb28379aae9ee4eae524026ec7e1e52dbf45300103be6b84b1836872834312aa24afe45e8a4c06301070700709089deaedc00d4461cfa490b9f624e84d2c05b94dede8af0b596b6e2dab444ebb635e905636d70a1d7ac9a44dc558d54bd40a1804129f98f1a2230ebd9044a1ecfe1ef85ffe45549b0575ea3ea3b9bd2f3b9ba55cfe4ebaa49bee2b2dc5b9403097530eedb24aacb59824bd4498b7c661300a7ea6a335051da4b0654d8f9c8b9a05988b9e1fa463ec1193da13da1e928e4a617aa70e9847eaa82956243a56039412c4cfc0bbef6604f8b02f148b8e439e627793ccea5f6933d1fbd935ddd09abe1aa82e6ed9344e21ac5cb7ed385b1593746cd68857e710f52b1529e880ca8788cf3a289a5dcfaade3b0d31bebc512229cea5d078481573dd9e1debed283b0c89f4c30f8e7421c80e89d2acf8bc89b849ff36f2a9bfb994489f1f167d0d800841ea4e06a947485b56fb6e01f58a5d4da049bd5eb7d898dab8757a8c4096e8714a582603f96b6cc73fb2d6042b088cb30ee98b1911363c44961493e273db6ca7b88956fa42972709c77d0ddc0876808bf06ba6b99fedbd34d9a799b71053fd78682727488af049f975e240f65510745d63fe2f7f23793cd7ed292733f945f7e9596b22c825363b1b47b3260bd0280d54d76c0bd90387e842043b73ecde1d1c107c0cb3733717841ebde0b87b18cb6a26164474343b4871aee50d34da36ba84c80a9e0f6e6c14f8bb7d20d9015677f98a0199e218083aaa90ca1fae40dd36115b54c15ed6deb1eb280549a58b0bf55289613064882a982a493ce8b6e77424af73039de9dcc15d8ae5b030fb5a0cde110fb4dc39fd26b6edc2733248be7c3583398c1f2148ba58840af06c51f3d90aa6f9c34c400a3060384e28b90e215a5ff287125ad803d1b3b0bb4ea30d3202f4dbdbbf501303f53d16d45703d06cfcf680d1b3b79e6ea1570d08e623146517bbf15bf16378986bb32f1d729f3e7062920965472675f2a5543879d3d95d6b395fade2598ff66423d7d4f16052535bd2b302d01040ef36da10b02dee9409372944ddfd10f486731f6718900748d8cece73156846c614ecb71a772f9d6f5b36947caccbc433aec66a3e997d56a5e5050a074dd69046073efe83280f363db98cbaab0199be0c741a620be46df1fc56192ce04662aa6008dc280933fc8bec74591ca57df01f00ec4b7c4bf8bf61bd5c582a5f36f3e0fb331092377faf1ceebf2de00449f44c64312f219479d2332376a8a6f0b45a0d183a9a1ffad34c4d132b0f0f6793cdab694a36ca8fa9aa5828c53375d1f0195ecb2c213e6a8ed97c494dcd5174f88969cec7ea3fe70f1630d87e86353e1595326413178fb9233f2bd5f9d70b9b5a213efeaeb68308d3c75ec5a40de13ddb43f15b166eaf560f6f36b6b705572c4be615f075efc2ceffbaf8de4ad92992fb9e8c3c1f79e4aeac1e6caa22c9badc9670117e059e6360b80887be63a2723fac0d22fe83d94541a753ee17331e3fbbf1ce24b0d22d409c888c933ba00e2e4f4b099115785289bf06d39d593ebd27cac1466b9382c83e8815ebcc33a646b600c995de658856893fd9777d56b06c025db7ab3c090956422213d6b6d4cf513990e7eae89821089c890ec0c2880441d4d187f62caff93d505c496c4376b6e9473623d19c74d27cc7ed20f4966b7917fe4e6e55819c1ad2e2591367fb6bcf4339a791103cfae2c922b7ae72b7755e52365c12c5df19f92866c87933baa197da2204a392efc8b9e90b1dfa72520ab6924401fb185792676180f5116415b861ee4d19dc4f7a04513e79bbaddb6e28cda1044a5dec14d856e661e2cfb056fe2c4c3ae73b1b68ecd30e8af80dd425390f80748c5150b15d51c91d45f4a006a00c7c3df4bc2b4267fa208a20455c8c9979a1a9cae890435cd429dc72732776ede3fce299c27fa31078a8292c275ca5ffddb49e2837d1b2b6d395ee06cd453cf214c3a93af855b82fc88c28f8f7edc2dbab4b18d68f52067879b69281a64b24e4e25227cd2f40a31542ab770a86c9abc2c275b00d1af956e02f53e4cc647d1597e23d3c98ec89994c12662bb9d1d028c1a570ea42b6ff1f73d50f74ee1a2b0cf83974f52c7573d3ad15a34415b4b378e0193a0a5336fe86e8acc3839175a2659675e0e9769f47fc93fa399e40a2e7e7489f36f0a200f165ca90bae606cf9487f4343f21ad70c05a0f901cc861ac935b69a6a43b9b3ac2872c19dbd2c9996731cbbb8ad82ee82a47e14139b6f3f04f27af9be9c21d9a9a31ffa742c60ddcd9fdd3725e779fc9756a25ac18a0141fccaaeef2a04cfc05ef76886fc5523fdc9cc8a0213ac12dc17c37e2a09626eb5b24442adb3790843f9aaa4d23ae24bc1e310434c776689c2b0bf9a82e46f5ebedb2c8845209ccc7727ea4cc84de6ea630069860db0f983c02435971587fc8151ceb9b82a91604228b0ccad02ff23d3920dec8d1494858dbd635528b0ec5e98ec9dd3071ad5c5a80c1d7ba28d8d6c7cbafba1cc93d59586d19ecd6c141bdabaf9c2ea3853264416379de653d05d42df906e9677aa618d10d3bcad1f740b3ecd34f3c042fb494766832008e69bf18ad5aa27bf4427ce99595d62eaaabed829cb26b4933ab7f716be6e60c5e13251303faa01ccc18b3496d631055d98530a172991c3befd5c6a2d9606d5d2636d1a70e6549511dcb703f12f486151de2f8377cb41233bf07199aa3e4381ca1764f76bdb50fd0c8359d72ab19c94856e88907ebb98665850b9d0c85ae6636a2c2b3907e45c41222810d47782d69dd9013dc52214e461ef6ff0cab0abeca3a7cd64a99934ecb33140deb87e45d63e15121b4e42554b80a43375361060b92ebdeb2596abe5b4561c065c7cbba891f9f48e243e883b1691bd1eed8ad621657f25aa74b3cd9750cd09424bf148a8753ac6c94771c19b5101c834f36737c3d1d461d54c0e413097ed16501c4cb021c80585ff394bd39599e640b4193c4ca25f05365e6ece0246e25fe83751fe876816e57c4316b2e88026826b4c0da5f6b6a77e69e629d515ef029341bf69fe57bff65bd6f64a6fbe1a134a33c8ccb9f0a526d44520ce2316738e7f2206daaf27b01c71dd08015b0a9991c6b5cebb6b4ec53b9235acead35c1c82248c6a84ccbc62d021a84decad265e52da5c3aafa6fb1bf69da8622a254ef2e595bb47930fb8be3df0bff9f8e12181671fa8ff40559c119219ecd4de25706c60b4880d7092c3444da6cb10b83a2b0490d13c37881deaee23d8d7ca27b1a639d627e19b7cbc34ad26699e5f62c31501a64eba4fbcb41d5105da929a137a767f90c2d808d8bd7e83784caff6411b952e562c91cad256a905b5358fa7782fe28035094b5857d6ec6c539274fe6e525057b81a2585e7e3ef505ac90c7924da81b3515f5e2633b9d6968161daa225a45f74429722767797d9a5121af3f3c4f780cb49918ce690ce0b5adb17e5905e4ca09fe81378fdc8d349d35320dca366a8a3531fbccd6af4033241e5065fa60b845231f4dfabeb1d02bf153cf64fe9861274ce133141e9aef0742e6b692e6b3287be47ff18d45ec91aae5e78a8cac169560ccc4242c764122aec98575efe2621ffc341cf681c9d74fa6880fae782776a7e97ad2718e9ae0631c4768cff17b19eaed9eea522f25eee719b9b00cd5102808b61e509cd3c24b303395cf4f77b37ba56eb334db2de23d503bc75cc40082023f1941cd894ba08d9294fa99ad9d077a431c9e3d4dab310e9abd865d741276d364376e34cddcb8ffd60f4cd07167f28ed996d053892cecf1ceb8b6ad48c0cb8f5dd271bf1d79b91437b1cfe816cc16c45051545100b54a68d34d21fc4ff829dade58b4dbab336eb5c878b01ff86cf1d3bc60a1f2a57944405cc65070341ec1521c9337357b1100f7b53e4880bcbe1c2f11ddada23e1302ad6b899db03bb32291766274fcdac9be96e9302351e84bba7805541e5d93231f47d7459c25ed670aaef4bc4bf00040fbc77f432f8cfde28ada07a0092fd6b16753bacbb05f97f8ef6728cd2048bf4b865e7466eb8311fb6fb6f0f32e761b6ad6a5697c0e21fefc1dd0e353b0beb69e72fe336f6403b2293c7f274512357dfae6d3971472b80683ea439b943b8d1fd45969b83f35a2f7f6fec92a23c7ba58123b13182919110a88839115bc990ea5201dd9ff48e8abdf67bcb4757e8385383c8840adf2bef866a9a3729bf92b247385fc83d150dcf1c8f3d230388dc57c3e87f6f67b5652046df4175bfabc59a6d992ada91820d1a9dc0404faa365304a62fad00c7067bd9c75741a9f22544fa1fbeec6fc23f40c2e11bcb3d16f4114f64930d3680ea15d80259284d22fdf6b35d5f83347264176742e31248e3af5c1dee1b48b8b218a7cda2124e486ea2a6c594cc1ca6ea5d0a0f1fb0ffcd0cd6869695e8c112e3c818f202a0283aae71299fd81d5e61deb5de3bcb470ed0a65d099f3e083c0b6e6ded5689a6ff0e0445b3667db15c8e62b896a177e6e915fe065205702dd20b6216ae203c75ae88df41f5b9f5b0e0fd25fb11da7c6b1f74d0a566dfd76e1e1ff0e0370e32c43e97e47580fb2b8fbd7ed941635fd70decf276ad74518ae4f2136d7d5b7d1db95fbb106ae4ffa174a2987b0a423de4391332f362f738b5180c8fff79ab133990e07f3346227049f7127b8db22ae831f8685275f6cb2b13d5ea629496a2f4eb865db29227eba31f25802776ec18a8709da680baa502d9438286dfb48be22a037ad6edbd80c902fec198ad91d9fd43b299320ea39b6c82646425fc74e302eebebeb2388ed88d22bd7df960ee9b311c0effae65780c168c8e8221eb4826c30777e9b4300faedfe86dbccbeae3fb839d36ce538b465c5ca4c0b43700a04951cd9f4b931e699ba349c61f1527187a43af52b0a79f3e745b172d7edc51ac54479a961ddf91656be5f7612c4207421ea70a678d7726deeb2e42e4836d6960358480edfe554862027d5faa19ee8041efb89094258f031b741d825540e12a40d1a4ef30fa6a41a18e633e0f55dd01f6e5aa5430c40a73ff3578382841e276cc68abb371aad8eedfea425d5652de42e72251d1374124b9a48480e6d8b136b267a46389e0d4adaa1d086b71e6f23c7632d770b7a6e0f4f8f2f7e053b084df03944f4f581a9c8433877ec2551742eb740f059f0d5011db31dadd675d3330db1fe5a9cb94bc461c35f9c0a8aeee811f7c4b51473f028030a91e6fb0e2ce0a0ffae393b2679bfd6c5a45103f936c744ae8591df524bfc41eeae01857ca55bafc087966849e5e8b9759a3dfcd70bb9b0b413c743572c3b105f2b997a003275966c9a8df8248687f193c67a4dfa55789cae11da6bbd76ec71511e0b0278075d7ed11d9ddfbeecfc04b14bbfd0183a4a9642a2e7e1ee362e57ee6fac3a4618f08364200a511fdc46a3c2ab56f1673fec009ae2e4873cee80155f3f93b8f9a4bf20d2552bc602c1161d34a07ed9fe56429e906da20c5fc64486d38342e64d8da93d4ea337347e32afa2b4a24400772ae453fa2588c917c4f3bbe50d4d46aeea4a553c1a574f6d6b4fd21333e9b90ff482e3641b8d43ae274f0f54d94db59eba4aca07c7404920bdc79d6c6e724a3d891ae9f61605ee91ed4b2ef35a6c16ca7e18b089d35708439c9b1c9ef5493e8b9fc74eed47e80fca078b191b1967f14434fa29e8aa52ac5859ef3332e2aeee4599da63a63e76da6abfb1f2854edf94be556d24816c58b64769ce037959a5a32761de1c8eb6b991f7b0bdc4cb8dffd289691cb80fc41daffe79b41f80c482d1af7bf0ac4634720e9fa1cb8cc0873922c30d8be3f62dcde5b12e945b5447f47230ae2dcba2cca5e0aef617b9e22516079f58465910a976402bb0cac7a15a34f88360a8d4ecfead96dffb62bd959f963af91cb5b0fc2d5056f31fbc3eab05f6ba79f60f7bac1cb5fd795d77730d6af9712f57a6416dd5d16ec4630b05b8f93676193f930e7178244305f13d81a6220c7a0a750f7f4d0794c97a05fc9c758077ac7e4719f1abebde85a8e49fc0ae954bdf4fdae88a3bb8f0393ed2f5ad88f2971051896dcade57edd480133ea98fc4bbadc6ba27426889b33029f6a026398e635753c32649c429e7b90d53d603b4fac5f8fd86d2bffee25b5f8f377004c3107b5777f730fc7c7aadb94f8628a56e60e3f78d1861ad3b6c5366ab2907e6d1e99f741f45432b70d06473bdcf73236c915b4fcb81ba5123f27547d0d29cf78e886fd13b831818bf5cd99778b58ac2cf0dcdfd86e5244a618685cfeeb7bf6ec66f0e81228b82fa45ec441be46c25b66f212122720395860dc85ffd43d389d97589a55a4d1929bad9b7cbab1e030e4c57479d0c3fdd9646ee93a9722342d13e42f9f7a47d19b384b79676c4f8b07bee8bbb2bfaf3cd1cbc33be0af0fca39fd287f9bfc394ee47f61a1afe2f3f8332a6b5cb31c9b1b6efbb36b38d1929a7eec70fe48ddc17cedc2cace3eba3f44560509e5e47d63b1d9d100f7ff3663235447233f981e3bf5db346b6bf666ce5e0608f51ec7875cd9808499eb388c2a913c010df79d6455308c7c6a19af5e0f54d766ccfecebdcac54efb4748f335a41226656591ddd51eab63b18ed0c4e9586c046bdce91110c574053a4cb039cfff55dc2dd1fedf9598dabdc5e8dc92efa72f7aaab93860547727948372d17ed389e3cc893934f528d00a4567533f7541bde75d51374f1de6c878e86ac06631802a5b2ae1a58e2e1bd5468f922cf63638a1921b1f54f4bf01a15ad27948a91233f76231eb1a7b811751536c0680dbd0fc6ee61924648d0b2bc5b704a1376242111ee4973c57af61ca5eba0479a11263164673af979394662542d11fa6e3a62153b90851988cae16bd57cfa13ddf1a0fbd03b033c3c698e71615704ed7e233450a4e48ce4b386d965312512f54238a5c5264230bd0a9cdca0a864bd3d3bf4637dbf34dc29e53ba58e630c7f5a641cf003d6c0c85f78eb84b01de0b3225eec450698cb3d24eb5276853fe87d069fc2270b6452f0cfeae1998ac6bef93070f30179270e24a67436bc60f17211579c62ceb0933806959b9a8eb77aa07205da4483b96592480340e010f78f3a0ea34d09506e8099fd4b959c8bbaf638cb6fdb84600982e20d2832c0368650d9a6c0a8a3c1b1e8fe8704cb4e906b450d903e11baf2b421d6114f3203c446e5afb68e261e0e36604b1b5b48c712e2dd70b0c2be087bb6efc758a78f05961ac49e697aef1e811e780302198e1cad6d288ca196617f07a666d9b4ac1b86aacb272c54b14859e4dd584cf0d04386d484ebb394017a087587100665be201df52d1b0af6c19e11b9f1035ab52db8e0f32e418feadf6cd818419148c38268c3195c7a94b11075f806907b35d54596989dc829934373fb98123d108c9e1e04def5e3fa079ac71db3fd8632d7e90c46a4d95875c71e2a869b51fcaf73a0ef668a2d7413bc0af48f392b43c0cc688d60e421052461e3b49b78706c5e4a26230cfbbc3e15185a0a000507abb6b1a6a5250df97cfd6d3861c09276285be945c8e544a38027c5d9c34e55650cb1eae0c84aae8480257c784ae4aca58a7c4fc646b77aef6128fcf9b9208d7230bccc666ef24a3fb68f04f2f66c0d82c50a2d6dcc5923fd92bc2c7b2a6889ce86f7e477f0487cc6e73f390310f4c561014090fabc74c8c7ef11b6d3bc04bb1f5a5b7b62679057f8f855cf40f07d786a40438ce702ce649f8feb683abb02689fdaec22689db13f615c83d99a27aad0f1c3f2d5d3d3727ee5e3f2aa3f838241ebdab722b8a04119bf5dfb3abb3596d60b8d189af750cf5644bcb5e6edbba5716ee45415bb202ed0c9c4e09d316a0848325d3190ed99b420cf66bd9ea413143cf0d273e5c63c0d337286ed0a760e99b803679c63ae6b725f8b054a108bab184c0b6b00591c6c3d74d1295a961a77d432eea40347ebd0ca4ee3c185b00d509a60ee53db10f3a54562639ca38082698afcfb9e3486e9c0940c14f6fe69a17d72ac4dabc530badacb505edcc430358f09e8687ddb3404897f8fbaaa81c9175259fd4861d04ea4db0fc4e3c68ca86f425bbd6ea1cc422feb491a3d570604080174984260ae0414441952ba118d794aca2e4fb5a5c08e75866a5a23b9802c2ab5fe4159ed493f23ce3a0d96b29641d2791ce4b58040fd6a3b16aff23df2caa00d1808325a4a8b16d296cfd874ea6499d57842a503c7441fd7907cfe37291aba53619840f669dc875160ffb54676999c8aa6640858670227abefbdccc0ce28eba73aa954df8992656e2b3fab92aa3d17bcf08475242c77a287ab93a791dca35c6cefb1f443fd5264ec941959e8ec97201e6963cbc89403ca5d3e8e11d29ab8c2fe78a29c27f314b35f21397943c1400eac9d4a52c1a54349f6d57e5ccf60fc08ff281778b9f24fd776ed835d1e1124b9a18b487baccc9beb9fb4f7371945d5251357cc38a01ab55948d4c35208a20f24d9471dfe6bee83eea7490d5588a3bacf95b15fbec5288a7db7e70c12bcd7965871b8606a93bb67c84bab7cab455e0d2e33c0d97da497c49331ab98e0a6ab1a909169531ba00360b701403598e79d1f057934b2e62ef64efe38bb8580d779cdee738ffd9ebd8857700e0f88ff90214e0ee581ccd9cdcf8e1b7ab290331c74da9739b510342305eb83c13b9ed67f2f6cd913b68e6cf5478414038051267e2957845711945d9603addc4be182999ce82c149da8150d1557e4dccfed7d80a761ec03fac105f4052a34e3a289fa454f24687eeb7f3abdc3d4bfa0ab5174f5c14638ef5a2cb26f0ea797fb3dc16e734e5fbdea286c37a995d6266c8613d329524d782510a26792218e19caba00e6da5ed0d55362efc800e77c69ceacd4b89cefeceb34cf88f02cb8d3ef1a0b93990faedb582c6457215d83dcea692074c14c10d847f6a3a13567886b372b61e0679a9827d9923cafa4bee3e9872de0b27d03073c5a5fd788a43d968ee639eb1794dea3072c185214d34ab58ffd9574734da5440b1ee596611ab307131e5e8870c18065f25beb8f1486382646ada7c4661d4952f31b664249a51b59fa174c50d2e8c3bc7200df3ca47fdec0baf0dd6de7d282dac24b9c42d7042a9e07b0840a8676a2e7132669c674d9b6bb1c72ceaaa7a776877b1fda9873e150ac5b035e456f5882cb7931d439352e6ca61a20c3d0e63a39c01bae0a8786baece1d8d90a0b6b6834a6af4751b53c8ba592ee4aad93fcb2d16b066961aff5df75f7d1b48f9c7d28a5c50f9813f801c0f3161ecba2a6612f8a31ba45e4e6726954a196c60b05a4cccdfba0000815c2dc59e198e484f9e2beb0acf1c9169f39d5d628350eaae33bf2f0c4f342b01962c4bf9891d97df2bdbb016252a1499d50313f5df0b7e7e7b41b6da477517d81b9cddee9098607631bc0f553f2f77d1bd9e6300f28294e75caeca1a1f7fe860868b52ca864e2bc071114dcf84722edd43e4d600fdd54d029ae1c3353f8ed6b4e288d0fce1c12350100b420160982d89cb81486895161d94603f395a6a23ca0b16280408d7271169b8a7f548e0aace3229d4f63b9b551cd2b1ebb345398b09f77b52070c0e635b39661bc8fdfda998f4498b840471717550d92c447d54269dc41ef6de8da4a3e8fe0f19099a6eeb2986d1c5a748f969cc57829056f7723d03bf73159d4b0d25d0bfcba1a9bca3f08f5776549fda10f99468d9d7ffc531afca15168f8ea41d52229fd07b687fc603247b2b4f97ff51d33ca0cbaa75ecdc1cf0989a60029c142f23fa0fb6d2ada45df77d50d26fa52dd21d6f9d1a5b4629cb8a94b05d2222443b93b4c37e4bb91631c50a85336f5001ffbba5f91d28948e581270f540ef00f9e25f68f4b881cac3590dec4ee289f28f04857fda19973678739e5a51b3d83e01fe44893c3f8565598ab19869e6de533107e6c9deaaa1925490e8b51acd86f4d0ce2cf9938e6af8639685b726ebd6cf6f7d7f8a636915eaeced305b2d39cfd7fe532b714493b84fbd2d3c081173dfd423721cc3094cc47c4a7aa4b1840ff5b214f178d565061e1bc2aca86622d3dc686c839a395c33ffa83e74268b6f7bd34a303b5441d0b912a6f03fbae282623554d43499352a1d8fa0b5cd663d8aa90ef4de1dd5bc4c03a5a23a3d4acdafab732e79a78407fb9932ec464cd69a61ef94086c90d93e8f949a6fe48723b0872386dde8226264fce0cbd47bbc2dca190ae28661b4712125f1a0c05ef3dc107861d5a1bb8c6870fcc3711bda5207d533d5c4c81fa1038abb841609f676b86f7256133e71426f75def8f86c0da66220e2887c07c68407bdf9833221d419bfd3f03827243451f792b03365e24c61c0fea660b2b0a373c67fd48ebc1a7088da04d37460325182fb61a7b9ea5e1f26b66fb8739cee6136b138b2d4aadb294089bdfcc6ca1a3467b1f7bd2fbea506198ad01a46d3c6f62255ea2243bffbda21724c7b46ac50c21bfb160052c0bd403a2c82b969a048771c6b405afc5e96fc2855aa17ed3027225dec33d9256b4de23c5641d564508176651a89309a3433d8e267ec77e25d668f98444e49ce37e229c81e9453dc3ccca2e32e974213c82cd33f0b0f451002281d86157dd22beb5a414828858df46f22d88e28a2d1c5bdc47d94a17da36c302161c3ee549ed0e18ee106e0b4469cc926b92048421bea3b0e8ede51e1c6f26ec46b8289537fdbe8d22a68fd2d09902c4a02f2af68c4e66be4bcdea1262aa62ae0f89b0db734b00441a7600a380ea9820b0a01871c1b287b2f3acbd0f4330203975283ecf30035c4167eaa3f70601c49f5d87c83c29183bd2d49de08323ba6be36e26abc3927721c3f61e2f090dbcc446f9f658b78b97827384835143821b0b69098b520e24038a65eb30678b9ae3acceb268d684be855eff5b426b1a641c582067255fb75209b2646f7f9cc85e180dab9a176d4854af27211507135bc109e8613b0856fd0502ee2636783c4e500a81b737440000e910a052df96d66f67e152d1cc4bbcd09c83dd05a623830f4dc6d780a7d65ec980ab85e2da8d3055dcb77266123d974a665f9b6ba1d5afd34c50e5bce850a4c280ccea0358f34762af5c6f1d055b34406bbe511ae3cdb55ea384adbc0672a0031cc2bd734d27cc0eba53c9e8227a151588ee49474356b8e80788f46146345a96686bc0c1ab086e2dd60dba4c7e5a56b1f7b4763383ea2fb36c740bcd6806e145fa4d603ee4d4de189c3ba71ef3d933ccdd738a9aab868039525e49bee5de95e04d7f8d6a20b20f039eaf03c9066898f18c8db84f2ccdae10932a02711572ce6bf0e794897504297289eab2839c3132a320c392e8a0c10b3c316e6551e09e5f7d5c15d76666023f12f4eef75ae6e372d6ab77171a7acd5f2204b086a3d693fbd39d34dfc353e4c38c212402dfdaba0dd1f7f32df842439f5cc57c9ffbaac1f33e8b936bf4a8a2665035f488fd3db1c032b6412978c3fc408aad8d43b1a8dd2e6cf1efd0c6ea3080b9a8e81a66f5378ccffb4e571093d37da71ed687615d3cbd29e9a7714e47f97c48326796677de894f719dca88a2f84ad9fcd0218592e6b89e520bff803837a4a669c8f9b906562815935ff2050910a21b1cd502b6f22b46da1d4d8c292d32eab2017291ce6fb9888a62ab8a047cf1514cb987a48c3af48ebcd302fac09d429988d7f8a828514ac2bf477f8bea6aa56e32ce6c64f818aa2a96f6f22e7460a5477e6961a10214a0e98f308e61f433e65e952e779b678f2c02ce0146126d9bf8611025dbbae07064e4c75057f1c77c57bf13b5652e480a2b4867c4df0a2b29230a356df3116a2977df4e6b2b9ad656566f69d177c9982b06274098bd66b971a16f4d89e37dadce93e0e8337418ac4766cab5ed06cb17c3ee38f73c354937ef61fad1c985c182726e4a297d93ba14f86dc4fe2eb5175a9479826d4aecd6a2f20a9d2cbf659b17ca3bcdb368e91c9580cdbd2fa0d3eb9fb4076f3ea6780497d48016411df4337cb59ca85e902944c12f83a65c159c66770c673f3a170cf4c7aa33010fbd9fe19d038881ab38f78eecda047103f2f17b6725649fd951cc73ad4d663500029bd7bb2c5ac649713d6d12d20fe6c9e4d66b95c0653c8b14d2224d09ab8ef907d607306c394656d26586db416ca3073bd00689a75701658ce2a77223dc9bafb8f2269a462340717ea25e0810c615ad4e2ca802ec546b6c85aec6ad14042ce52653c03ed7996c2e3c24e7a6a8214657ddb22626e1545bc0902fcc0dde0a810a0eaf279a033e676352e8a9eddfbb5c045c26ca049bf6e36f416b5e225cf3ccac4c7cf8e0de6e08deef47afe8d5aeb82f1dc2d045f17c2fea156189a2ce569e11a16faf623e0353fb551ad0bd3dead7145547fb9d5eb95909e116c07fa59e802f31c1a0cca44cef6239d6fea4d9812ed4d2c5ef901f3930fb321c66a0db4b20c71ff47c3ad4ffd731bdbef8483fef9614a2ba2c96fa12980aef29ed7e0627fc5ed9175217241e555c0404913c8412644b994e53ae0e36efb1b3ad83c8dca478d5929475b52a16b356e481913018f489c4188db0b22e5729f95bd284efc974369ec094ae0958161d4fcaecd9bfd51ebcfd3f79a9ebca4f629e41e89e69240829288e8f10fe63ff77cf805f42a3cab35c7d4cb68a93eacc9a7b728769f290294b73724be9361bc697ffa3414ff5e5ffa8d2c98c4ebfa6f5cc7dcfa037de4921b215c065feaab2cb7988a8d69a9cdfdb79bbd66087d043693385b25557985a1cdccc258bc1bde77e8d3eea07b5617b84bfa6659724fa9d92b8b8ef149684fc900aa78d791f52e2d4edc4d2b9b7b82a6278705a7611b8ba5c0228ea721259185c021cade2fb766609f2afbd27462c312de60b5bbae44299d062c444fc4beb4e68ac8112d75240f47327ab9e65b1a2b79457e9534d77904dbddff65ef3d24297a2b5cba6f9a7ed7af39f807e4e1e557f2792f1168c64348197df735a62bf8e5b5b77293bca9a82fd1d359bbec961d97179eeed3c0785ff27632c3f9124f6c2085b1864065732711cd42853849701d00eafe97c2f44d632534c4728e85b2bd61e55568217318e99d853459d445aea770e323d9959d0a168a868815dd6eb1bf32bd6816b8b818b1a7ef93a03834e51eea1b71442ce8594bca22b4656965aa0609a37ab8b1411c184105a9815f0a87ef7a325167d047f0ad15f06386a3f590061806242b680c2d098321e6e97433125279a77daadcec353fe6657d4ce6c00712faf14d8851f9f5ba7130aa91cbbe05eb33469d18177dfb50d87365c2a420df0067e3375eef9cdc280a92fe20c16cb5f5d5e4d52ed6b448ec300ae54b589d5785382a74bc82cf932678da949e06ca80cc50f31b7afa9af5fb36add06492c433b1a9ea6aae3e6b832cdda243e485c27611b0cee6f9c2a3a3fa0449f8062e84ee4762f4b22dded84dde8735cec93ad14dfa374c1d41e12e0cbcfa2e25ad0165ee2141c088378f426f39d3f3524de114bfdee3f2897307bda74eff8881b18ac60dc1bb9e5b4bc7abf04541e682ccd52829ef098cdcd4a8c168649581d7c9b4a3c1f5041df1cfbbc6943a69d36bcacba09bb0a023809e69c309103aaa0768498461ed694b4f02a9954fee6e00bb10c9249878fb509aa9825342aef59ad461753067c960d4873498566c4efbd67ba7dd29d6e87f00c87374ad6d7e6825c8f4df8b2f4dd6f23d8cf14809faf0ae6866cd948989f5b435fe2f974b12416d086b10f5b43625ae56afc32eb549e8d77afc27988788401a14eae6315cf1b212b85f44518b8abd496d40920404914791461cc1449e977ad01038055bd1111c643a853bcce2cf49e82002251af6084f1fca8f4a9ebd03a28348500204455c708634b8754bf63c32c81ca44aa03001ac3d760648cc45053e44cdb665d6456006ca8193f7402740f18d1db031130412880389e2b0cc6ef408f28c13754c04231ad003f1989ed9308b0ebb7a54153135459b5e8b5ef959c94166aa7aed9384fe58e929ad0fe2be4e06957257abe6a5110f3321a251e7dc04a3e2f837128d38b46e769d6492e4b1d28a694878bbddf07ce9774478ad5a2d7c6bb04166ecca5d7eb85de1ebaa171ef99e300d9d1f754bfab1b96bec6e6b68866e714a7442cb34860e2ddc3ba71016756d3001e8e5c94318753f1c022c4695e6638ad0ae4051a172ec7e2d14b2c7242206cf99cb4132376bc5b281a394578433eef96f4ac100e3552f6246f64addc3aea3278234b6f70b9bc2753a565a03b46ff674c4f50e0f4aa41167d045e604fe9b64f244be88eee4781279078b829f1f84444ff1387863f0dc0e948f6310f5e8c82ec0b776cb1567447f08d1584b702d03b445a5ff4c03feb58fcbe6096900ebf4d665632ec361e1fae1d7957b82e0402bfb84da61bc16f1aca2e23817b19b7153ac24902bf5951fd86675010e3847ef186a110a9f2cf1d70f81396857b4938d9c14b45bfcbd4b811f18185caf165dc4c97f702fd7f79393c8c77fa0180d87159797d5700ef3bfe39df18d8f19fc17dd897981596fe76bc1c110fad6451be6ff824267d2cab87703bdd28019df4321ff99dfe67a1a79d17c90905ca79ae93da162b381580d074cb7f5e160cc42f7ff2e1b76e2460f374054a42e02d9c37a373c70bd87386ed6856277b8455dcfa02c756c8cb957a94f6e031a0ddb568a184b9c92d0dfa122ae3a69d43681b27a1f64a6fad9ff0b7fe5d9d7fe6000301c0a970f428623673d5cceb0b9b031d9f7d531131a2a5ca3a55f64ad94119d7d201fc83d76539428a2fdab897641d593772ea01724134c9cf310baa7b01397511285b8fd433069dcb7adba9db5fe506cf3ace6c8f9386f30829d3e2a650280befc2be5f82606681712f1da8be34aad8a7ea52df44b02eddbeb8cf8d0e9b709b93db97755fb57b813815959641f1b3a9e5ef007da51c7cd81f4497b3c5857ed5b7aa1a7752404c2715cca976f1d0d488938f19a78fb30d0ce2175f86f4e1d26b521b7929e63c253457445b53c529c3934d509e1a9a72715064bfb6e2b36c8af905c4241a819cceb16b98b60023d104303811b1c2740970a84495a896fe4ec5a380d1a2d2b1774b84528584b0ffad06deb46694ad7864f3b372a4f4f7b646436545eef012901f129c07635038aa56d70737f9f413d89d97fb52924a9444d68124baf791180b818814ee235e0b7be5a51d69f75ce20264b9b0f78e99e36b62966cd4d67b6264767b1cb51b56496dbbcc48195952ae23a367e1e77de92ba291e9e36e16c150062b1682ce454e86a47b755ab3c1f60e471835a83ef621e62cb8eda28c34dcdb11ae959a3a8bf00d058553829885517ab4b16b14c4645b14c69e5c827428150666a4f7c6393cb3d115c89e3af23361d586c654a41113c00805ab6f74fc1e232c5f9cca6fb62848b140a842d20974c67e41e14eea2097504fff9259b8522c109bd46d83b84c2ad668cb7296475baa0d624d24a14498fb08d1d6c7c77abe602e701815782d90888f89fa914fa6f7024da75afe468871102f75d85b211c36b48d60e85c41b8990c6cbbc113918b3435f367567c3d566671f90c7e0deb0afc0e8eeacb90e11a73dc6707ac6dd73ba70de6909d81c24f58392a2c960d27568cd67da3fb01a2fa0d3869d27b51ebfc0a40f598cd9c58b9720cb5e6b58303dc2845e2d7af7646315df0466636a756af3333c85924d42d7d7796acad9a3dcc7af16901da104c2c80c29d69ca5a0452287aba4a742b067340d737cbcc59c750ef32c8eaa9e2b42dea321533de695e1c1bfca426bc1e0b66da87680270c90a7102281740404c723a13d4b044b265292a4db82358ed136931d3fd2fef4085ddd0b3e1fb8357595c93d447922f43073c0d39f2dc4a6f5f74ba2b17c492f93162c8092c6c52df48c4468210dd0900c2179f105168e651b495f1c7d21049eaff4201c3d266c280ea5c65583bf0eaad920c342a92b6f4052607fefcfa92e059647cb790842a23b25757d1624b71f4d55523b8ff7c6b1b41bac79ab4ed6a4090f46d06f09c99c53d96216facf16adaa51143d62b496290583e8327fe2ae51ae2beffc0260488d97b46ce6abdb43f4e1e766245b4cfc2373329e3e2c05fc7e0d1843eb6374680857b080a261659e8bc23b63c7cadf97334e8c9374c774799d1cf8d0c6c02d4a8eee140de3b9a15dba4b18ece753b8e8592aa4d9e216145bbc6dfb7391d298652836a875517528705443329793c2ea1300692582b291d97692466e5a7755904befc967618d7569a098a5bc41499b2da2b87700e8b51d1206b6b05791c070a591af98a03e88cf9d0926a617f8fdfefb654ff02aa5916c976d59004619c1cd0df09ab4b3f78ac8ab18cf3ad7b0601f6095c501c43cd23ff967951a2a9cc3a78b7632982335776b71a0677fb9987a01026dc44cfc6241c6f4c36fde3e403b3286e0ced744842a2e743bc6e6cdac9d3c321502112e0d5a4f34347f10c74a774155a22b126600c9a0407d7905d80078fb42b43ad40fc84caef9c0da3dd2c343d6e6897d43588dd3a8ce5f09ae28859d63057f9b8ef9e39ea464cbf571255eecc157700ad2614ea8f4e45d6f679aab5bae34e376c1547f956705e091abaab233e5926c402c1786e86fc1d5221a02234e42e6cd4575d571b359f918e62dd67d8db0fd2ecc1c332fbb2c01678a0f0856173915ad45150e0b62e434d8174ec839077d7528d3352a60b6e41d407fbd3b63bdb420955ca148c550304faf626bd482d26b070d0106e82b49dafe9b7e1d2c47589c265bcf605a70532bbbfa7dce51af921e7f27bf23835a0fa8e78b44e4838f3933756afb696ad3f37bccc69ba8f73a9f40492e1665802d20d88503694cc464957aa123b2be9b592ea81386ee080f9aa620e17f16d7c16e5316b7facc91c6a4c5eb1e5f4f47a5fbd12fb9ad84b3d2c1aaa1dbb9d0be73fa63e299af3895d2af92a23881431ea4a7e9fe07cb76ab60cfcd9de86c36e2b0521b46beb02d5b2ce43cefe1339991ade949e9872b66455482ec278cafba5a5a2e8937147552b406c2da258ccc534560e4f7ad6a65bbcf03d91414e7fb13baef66ab583b16d91190d2aaa6e32c2547b855ff546b8601769f121f569aaa52e2e341ad8081ef616e1989ca019eaa9402c2d514a070f8236cc6b5189d2840e063008303cf73d529b40db8ace45670572cfe7309e2de6fa7610580ede5052a379178e54285932bcf28bd13c86cbd866bfdc56a15f21f91d1cfd5c2af7b738f2de4055a4020f4f603e6f76f3e8cee07b08c217bffa8c90b4b2949f297860450a9a86507f7ad7ad44ddd4fbe3ff7e2be2f52723fae0aa308146a04dfeabb1b3586bda1b5511aaf77da4ed414901c83f53a7bf1ad209c96c28c71a22fa4a4c951342d500a1bf5a32c46c44004b66ccd529e57fc42dbb920cce8853960e40a05cf94c9566c251e69a43a648922c304c8156647ae3212ff36b14c03cfc20abccc6555ba22c8db2bf96f34734e4ec73d18d0402a37bfb1b9247bcdbf6cafc7b1acff21d485bf5443f000eacebbe8a8986b29f329dab4e00fd486f80f39d84e8a373a7bbf3c4b530b7893197dbea98c5323cca6d058948e188a415b8ed5af6cad0a79c8522d17eac5b784892082e02888e27906efc0ca3fd42147c81d8c6b996895fc6d7ecae7c88d31a55e2b48b29a61a1a36d9d9f225aa24bbb1c4ca0b6eab44f3bf1466852cb3c9c902b8ad0cb7bdc7467823a4d55bc355d48282438f283e705bd5d9c223afbc93e90146af53dcb75a33d77b0f681e4b29a3f0a28179532c86031903133dab0039b0670a171b46ccc3fb6a53c3268c12b3dcdef1a6944bac1295b072f1c1647661a54815fb5389c3fa33886de6bdd254df8261756f6b563eb67c95221b541adbbca9a7e9e99c5ac492e6fe82460526204c412a29814acdd71d099b0a676a5bb531559f065058081f6fa84f5c7c4346dac08a45c9d9c125ef5c55a051dc5cb0d98f009b80a87433b5820c120037b1cc36ccb38a6d13440643e64c4f90d4979d947da628d881fc1ef14e5c00da6c927b6d2017145ad034a7046e83a8052db7304a2740041ad4dbb8326299237c2d8796905fc8e6413adf816861b1bf2123a94e8540a708a89c0e11136b9c5533b30e4a936a4c700db206ad493525a8465905a5c935ceba995905a58935ca22a89dc867c2bc7ffbffe06614d6da03c9d37be067883b32a3e1d29945cc37e272f84ae1343283038a5a1d5b20ef255302d199606edca097471a3c876d0fb6779857f7540890965247a4654382d5df5fbb98d94098480f3bc0f235d2120f51cb9d867197fc8e21087f9547ad3b1cd21c2e5f520fea9154388008fa83cb1245a5d5dda05e8211db0ed9b1936f123e8138b563510e776d6db5ee55f1d11814127288e59dd2ee29c0830c6a31ee43c656d848300ae882d15faa09713d6666a243e020194cc48a8d6db7c978681cfda4c3d73ca3622a525dd66aa1fbacd5b9fc9b33bdf907e3855faf9277204b7b996710d963a7eb0d57c271862ea94ca401faddf417c74e838535429d37f3146cdbffad64e82550b794f96377646ec899a9666b666b7faecc8e03d329ddf80c731b2626c54636d6c09a97d59cc9d1a02f3fe023be594f14d78a4ebaa1a1e474efcb113bb110938983a40df70ea6814e4624a10cdbee158547b33064a385d40fa7de158d40b62f128d6c2c54f94e0e574041fa10ad329c2c3ce74ad5cec93359a7aed43913ba1e961b7e96ce29bf1652efca3ee4dbbca929f6c0360c3336f1ac5258976a71ada10ea94182f16d4eee0089b6491c90228f0911eb54993ac1be681ad5da2369c89be7389d9d9177204f3dbd4fea1bc8eb9885690168a88ac29fea012db7a211478a1f8fd8e29f378fcce386fe51ddd1faca20cc5f7a746ed302e22e907efa712f8d060d54fdbb7a4292dec6f1ea5a2919702d8e1267fa328e59d8e93cf17134212f2e1c7b0cc27f0e905ed8b20229e3c0e325fc60ac97798259678866a0d552f821a42e600170641282937f1efcffc3715a2b15d1449e02c8752960d02005ec7efc31d68a3d841093af836d00f6675e615938304e4bd9146ee69df9ee6d42124f5e82486389c930fbe8cf521986e9ae92f55f43cf936920dc0cacadc4cb046830be82091e87f1fbf8f6a8e93d6b53171738043a717dd37efd302b0126a06a6dc9e7bcbe1108694f30fb04fb55d742a05200744e87880935ceb2195906a5893527a8865907ad893527a8865907a54935ccba195983d6a41a6515b44eec26d1c85315a24c44f56cbd005426375168c09bc99c42c9c01e9f8d14ae2a26d41b4356a431ee7b94acf15bac49748539c685c3e0900d53719110ccb6bcfb4945f26c033e8e015ba7ecc907bfaca903a58dd734458d8ea31a2a120aaa90eccf9e705424e5c79340dec247cbaf0394bbf502332fc89a2d154979df2396b016e37b8cacff2e1d1615099d19183142bdc7c122b3266e9df4dbb00654af1223f32e1a5e2915493521c082dfe5d73585e0687f2a9244098757ca89cd8c1cdb7dcb9c4b6f1142ff4f5ecb668466e89226127e584ff1b7da2eb00ab0c7411027ff291733cf4193e7d3ce9270a94812c04ae85c1f79ae3fad6a80811bbd7a6a2f2e47da1b84158012495511759ad254757505da85a54845a273964b1c19d798891084fa11cfa8b080442ae2563d444592942f97c1911d2b46a9c48bb25f0c25481cd8e4ec965f6875f31c4e9e00ecf22ad8eb73d75114c995d3d789761ca7820c97a4d57e6808fdd149b759222c76791945a28148b62e7d7d4dd72fcb2c11580115a69d31deaddebc2540e3e66cfe1e45f23658c27e2ac0339632201f1dcf25229ea628125179dc438d12e30edc34d74a7228c58061c1405246befc305f7c44ad1870d1ebae7c90c4c0f558b913452286abc0689e624e3f6236277bb33472c48c2ca75520c517a035052ee0256d2d4044e525a4a9cd7499ea855a6abb0f86bbb8e7697f7061edf0e09546eaada8252905fa66348140255633440bbc601791e55124339ac4004b258505b47ca6415eef4a723cb79054720b94cc007917da41bcda9b47bbf406947f042e20048922293ded7108b5a3b0e120074b2f6953e4605db61e41e372c91d01cd43f8892e30523622397492e47849f5e04b172f2747f4caba1b1e48e9770a2cbd8d9483458d32f334b272701a7a7f472b60dff5f09bdbdc27bf3acb31969e46df08e2b626f2d5e5e87a1d618eaf2b4a27735c048951b43d8ce6f07d6256cf600f96a85c6a7d4ffbc2ff5be85f2633bd71d0e8e73caf51b08b98af3669c9e70c635a07ad756f1600cf4fb7ac134a91d05c498e1a96e7a03d2c1fdb627e4e9777751c1fb80d11f72ada180c5773629b42b7f5ebe9ba116caab88ea8cbb7598fb24d060d0787aa000efdc958ca6d456e1cf1101ba37b92cab2613cf6117edbb100a2b0580dd7cc86860143a4b4b37dbb206984232ed3725ca5f0ad1686eb4554ea8c2a15d7bd06d7df01eecf737e3ce797e7d9eaa9dd6ecf3b4958ff3dea45cbd780c3ad81093243c6b26994ae2e29d732013e7af861196519d23f076049e3ad6a3b3d394103d4f28fe8832119f5b6fcfffe30f2e0fa13d40d89454a9230227b4a0f7594017209941e50eed5298cfcc971b08bce77b2453df1f2725426b16b73de3f8bac88243e374d041b17d6db40a2933ea2c76cba324c4a401f2481750292b1cc768dc273d247fc98cd4b5717a1c2e6a1cde9bfd7b4aa853379ed40482b556e5f2d7b45471aa0a1ed1d89cf360471217a6c04795742c87160a6eb68f5eb8161e31dcb37f4f22ce965cb652d09a6be47158b204ee2dcf6f2c37f90f6b9006803f68f70c2b1c772d263eb0e5c3008e6ca8b8657861842c31ca7caa8066cd1740fef2864d870386190e1cd5487d9290fb31abd913688cba94b0a75e543a0f6cb4ea77d54419017d0bbd250ce6f44a373a01c941f4cc25cb5929002a20091fd79ba791bfa0a212050b7a1ee705fbe45131caa3503df284593fc988a3ea122acceead9d412bcb185c2b6022d441d89fb9edf2194a8f60804b928109464f3dfd3557b42d6eeb59ab5ca36d0fec8ea59a76278b95ea8211a173114a32699539c66d2211444d92a01301b746e4f25a7e3a8b5e9e5f1129eecb6c61f05c33ff48c4144ba45e00393e2b4e23ad9ffe67c634a5bf6e9c48de5a022899f9b948460a991a87a189da526a30e1f4b904b4d23507cbe81ad2fb5bb1886ff6a229d2331b5ea0b587980dee45ae1656a3a06e0e003ea936fa4598ca676b3933c2999059020cd90b062d319fa58338be25853bb05e5fe2d22cddba013999560218c82d4e16e6aa620468495d4252bb8a93d0fc3131fd8a7c6de155107192676011fac646597f4d53f2c739053a35e05240d3bd8537bb6860b81d515a89d49488dafbc6dc65eed9d7d09f05d09ca402c483a00eb5a34ad939f7ff66f0ad30d366e1bb4962cca5ae7b83434d878fbad95eea6ce7cd405a174bfab39e61b69d582f85ff70f6b15dc8e59dcb003bf27e5523909fddf7320b1b200ff132707a450215591493d922aa404a07cd8b92bcfe3bd054acdae6e41f61f1e8b032ef4c604ea444c3e45f4e7a3e7bb606e27116c0df35a9f3f8b1a4458a4f04ddb3624358460085c355e9a26310e11c5e4d682e9c1e75247e742d7c5306eb23b48541942b14800e3553121bc201fb504b9f613aa1214095077d61de83bf147a7593b4edd5824059bd89b5567a22a7e6884d9bad88ba67c6c258602b632c896d2f9858f394a127288daa4fc82037141d2df83728b537a43a4e4ab6091375f96b98bd6880434064400b0540683f7368840ac78e19cccca8bf756b502796a0f7b64b58f9f7190c169e8ad5554ae01f3015ec27ad3a97ce91cca170de75e4740e16d36474ea198453f0947d7a6ae9339e5f0c0a943b740288790055ee9c3cc9fb5300e7683a6dcce047563814999bb01f804f51d56b34fd401adb4c3020003cbb291aa299e2d643692c1d5853a5de52ffc7bbc38458b21e7274e78e1b5e2526b6e0dc1a7e594502c8ba7c263e5d20497aba625349aa491821daac5a39f9b52c76beaa36f81065f043c8c2a748c6ef5c28893a0822f5d615750b2cb18da82d8c05adb4b83227ef874989cb3cc1e2fc2638b1daa7d2b77d7e20c2d2e8f2f8264c9e0967009bb927a227a114b9aad22af9232403cc1dda1defa8a21da5107390a551df9f19ee2e0791e18b47430b716deaecf107030bcabbcd42df09fc89003f4422c9eb7d00cf44b51b70dd3da1f3e6a9696688939d822138b900b399d39a49182515f7dc195e8492b1f982680dd63f69bdd51a93dfbd836c2ba7a05fef5c4ef078a993e9f5506798dd8edb5742a1c79a8bc9076f19d36cb7b862f842102db2aa12b3c42145179ee59c456dc18eef679f28adff289e31fd89d6c9f2386dfe12d1e13e56d4f34cc0c0869eec1c01e3063ed243e7c6b1b118553c01eef8507d3950a23b56242c45a86f2a6eb7e3b49a40fe39b777fbccfe85c63569b790c2642af9858bd4c119deae86dbc1e4efbce1b933fc96adfcb007cacdb6a954d7e318bb6554a1d8bd7609964d554b21848b8cad06d488a19304cd025b2c6f25d01803204ee719ea7d37b70c3f918a23cb0c8d71c8838826badff2b8f5d8c96ec43861067ff1cdc125a8243093558ee959f1dca4392170f86781bef902423887ae9d663b957fb8392ba755373b194a04384812708c3abbe1dc092317939227b89223a210ab38d3bc881a0067056a2847657f2cd0135bfa8aa8a22c39394e7d74b5a55fbd7f3d05d314fb761f867408aaa3162fc3197ae28dfdd5fd750cc84088fee5c8ab29520607e844377c49381ac0f120342be2bca6a485bd2fa339c3c5e86cba387c2fe688214d156a60d679ee04b6f7c0efa060a30541b07685973df3bbc84db0a8fef3f785f57205e4e196503ee81e41b1e931b43a30578b3fa5bdb0d11e95b8c96a0ac6562f1c5adb59cc6d30b33496ceb4281fb132732a9f16f4be10f151364d31398bcdbc5df948554e5e01f4ea0b476fa6caa7382785b2f0dcadac164870bbca55947f382d3b2420137f0910cdd1c9b7442b7ac80938a7c8f79ac6a41bf074c0982cb74e37dfc98c866785516cd58047204b6ef854dc2b56cb19bafd382ccaae5e2d224467f092145b5136be2c1ea1208925a2f65cb0a86d1431c8a3cd9f40c534494b3af8ac54305c8b661ddcc446f7dffb5fbc4cfe3e8af9c82bc89d84906bcd140de491d1a24eb138a3b331438f030c9082f2e6723a6764f496b5c2620d97e818969a651333a24ac1781e582ff185d9067b61c2a64f1eaceb6c8988569432c862dc32c5d210e542ba8b531882bb5ca5656e8e0c344a9e4248bcb26568f3dadb58cb8cb020ceac40e857b589314243e5761cc5ffb1d4ea8e3433d2b1c2c4d7b66239107a00d2ac8d13d1fcc412576d84244d3207df63b7f7982d55eac514663310213e3e2f5c89c9896054959a8ed6390daf762e0f720be89e13fbf019566698bd20f9672e7744fc142e108844153d928f81c4dd4efa90bc2460573781c95a3664047173eaa5ff4bfe462f6056d17ea797656eb21fe6613a2fd2f16f9bdb5b43458f2a24f81517079e0379dc49456b499be24fd6eaf01a5841142aa21868ff3ac48bc197830b15cd94c1f446da199a479543c802f08fa2100301b32e398f09e55fa95444cbe26c754643cf5443eeddd0e7642563f47bdc2068fc5dec009b84dd2bbd23fe8bfbd4b3743eb95cf800847b1450fb694c05d8aea41f6eadafa157c794f9658cd136ab9f48991c243dcda9a9a3f60beef2b38716ffa71a70cad1c2fd73fd7509664efb0cdfead0938301d2d4aa660a4daba9aefc17bd2beb5925f8805e1e107cb16ad0fdc39c97fc21f8ef32945ea9943eac7783f89319fa00bc52645b24ea583d8ed72fa2c1bb69ed860b6fe36276a6f60b0fae282c4784e04e8caa4822fb10b043c835415950bcf13bbe34af5e713661d695642ccdf2d5c595351c8115ff06f7487e9511b4abc44d99029ef60cfa04cf1f3a7222671b0687d127a43f3482ee9232ba9b08ad4be5f152174a617c38a34dd39487086467358686541072f1cf6c3e8a1a4dd20499f3c5612c01fae01148978d83fc5482c12e27b2a80d7c2d0a578725c797565a19a0187bef5062c86473fe783c54a45ec1914150f389910ccf2bd4b62655a9d68dfa40986fab217bd1bfcf6daffbddd1183cf3a30e2fb2430c539d1c7eee38c69e0101319e48d20c7c0038e3107a6fa0ded221cea0267a781a445ff8c89b1dd6b16988ae3c34245929c40fa16a7a23d3015317122b79ede077d270fd6fc35996b6680240dfd0f3a159f5d3adfa9b8b2e7ff54a1979b3b1e193d3a07b7168054b849d1508221ebf653dee3b845441343c271c811093f16342b5c608b5828844aeb699fef7230edb9b72ef00fe99936172375dacca97dda668320bfe122eaa2e6489536901c7664d4dcc4633ece5ff054c26b12b9bd06d2f15a888d8a0cc060420c2a8db30df24745e334962d79e62913adff036d36e3a4438a649c562938631eda2e3dbfb7f84813a75311e02cd61b2b35efa310371495205f76349ef2c890f2f509485481879e346653074995f139934357497f70eac5462506349521fec789dfdce40eef567a1dd79bc796c0ee4c7f7046cbba717798a9ce0632984423976e2c6d989ec04f0f65b8b5015117e6ea9a46638f224991320ccdcb87d1c35a3194d600951ac508a53da6882f0bf6a7bd666c83322e3e0f88c1b552a98cb03f11d14857639890f69866311e6f0e4c42d5652525c528a7d909c75a950358b983d450ae251f14958ae12f9e8dfdea3a14ff9dae7844c5009cdfe78280e88d2602e29c849c5a653c4d7fcf90c361f21993a02d0ff126661d8e41f77054c4bed052aa0bdbccb5080369e17254fbca854297a6372feca95aab05c0d654f9f4bdf0ca233404d4e4830e09037a86867ed522ad773e95375fd815a27e52d9e49290623479ceb618b39de0df0b7bb4b89cd10993a98b0f6eee6795d42bdbce9e714303ea9a3745e1886505c539a7a6dab1fd283784e284c96c8eb4c38514dc1a459cdcc7cfb36f32a79265026cfe081a68d7dbc47a3b3f6df15e0fe97491bebdf0a6b9874465d9e7393ff98b10a7e934fb3a07fe0fe96b74b72e778a1633ea975d2cd0d1710be10e2a6699dfbafc3d98c653efb322034c274bbe007cfb02636b47ad8bdf83d9fa8bd8c97b3af97b0cfd83e45c09feee739c8c985422fe3a82b0abddd278054d925323cf12a7ccb0cdeff710c9159538e39e56e3e5ba81a15b44419fdbe32b49885b293234f7270b05ffb32f81c77fccbf19f7535ecfeb7a9153a220143033498dc0ab1c0278d02874cd3bca658cdc5cdd2cb06fc825e16133847036476f9cb173b383ac80fe8c983bf9082471deb127cfe134688ba2ed791557a58ee1f0887406cc6995c683f05ea4a38cdef8c5e8690084a77d4625fad604c3d8f91e0aeefc3de70ea40b36e13f515710cad4ccb07a6fa6cffd22699eaf99cdfadd377812118ddb315cfffece6020618eaea66c5a9d8bc100f485a88fec0bc86b4176d63e686a1621d6d66bed35c160c4f60ce97512d4550e299be3927caf295f8be2069586d14ffefe83b2a0bcae88a7d9ae1b5df655cc0a6f2b1c3955a162530842c92a8d1e5ee99f10e4ed3d28be3d968bda2e5942bcb84432198eb0c3562dde58a13ac3294106109697f02225d4342d0728ed28bc94e0d3c61d318aea4b29409e554fb15bdb6924c212cc3de7c4189dae5646b0797d7114e14fa5144dd1c56d7f1463d5e36f7270fa66451399ceb7baf56b8b3f06900637554daada54db947cb6bc2421fa461b5e8645b782ef10828e33c362c9d6bdafde7a6a9c4a35f16d584adb423506e0567aef067b77d669340718b05059cbb30bc568d9991a6a254b34a980213587cdd4bbd2dc038a91492132f1fcf48c998e400ca303601cbe44171168337449dcba4e33d4c8ff88cd25b70a6de3bbdb15817b312b91393b6f50b7dd3ef2a568bcb7e7a0cb6fe4c58767379b9b006bd802d8fa7ef1474a9571f43a21af5bc460eb6c90d7479f1b31daae8a35cd8ce4257f6647f7002eb66cfa8a49b3909762eec5ea06aaeb5d3937e544d3116075a52b62420f6422b824d46ec2feb00567e24e64e2aba14d14b73a2035f1e683d8883d2fb9198c342b8a2f135376681bb64763bbbcc3488dc6a4ed2ef24e316527e243962dcf67e731043c6205da58dbae531048cd361d18e46b2683f0daba910b20117195bfa60cf7c410dcb139327312d954607e4dc46ea9145bcafd1fd9d6d2ee265d3f149c216dfe7fdcded8ec1f8bb66ad4c13f42abf53083ce32017739c08e843505930ada0a0e0bde7c8e12a0474bbe2506b05941c76ba7fb7b9ea7cd4a64a004a6a453c202ca04a827503839e491c314a31c463940c98127490f928c91a495a4851103e06040968e8f31cd137bb6b57b15d9afa616752f6c81de77d5b2dcf37f9e6d8de1fba0e34ab96a6f2acd2f87cd9e787a7c1f87ff727cad6387cdefb1f5367fd9ce31e7d90effed569e473b1ce92aa741dd1fd37bacc9d9cd762fb71e0d2aff47b96a37cfb32dcf9572d2f368b749fc45f56fd89a3cf1ab8dcdfbd9fb964eb4788274a3a0cd33870100c0c10e1c9c18e1c08343dff0811b88483f59e5a7d8a26eaa738b7268ded79474197c4e8bf9c9e77d8d8a9c9725e77de9a7781f88fbea976ad24f71deef9ee5f83e516c02a5e6fd5497c1cf8961eeced75fed53184aca86a8861d0e149beda3b82a4d61d8ec41a1566e02435ca98653a18d4db0944ab9c9e66f882d08d3e1a92f5b834f0d40dd11c79ec83fea9848a65f44bd77d2dd447a548307e9510d1d918ce946b2c391211c49e30811478ad4a431aae9007e3056a9973a3c33f6f2f69796ec9d99e4eeaa1413c9e1f1bc3d4ba826c8881f2323604646b48c8c38c04890ee48c21cd5624f844261f039cfd86e2a8fb27484f413afcdf359194789634f24dd664c8a3d915084a36389f4514b770e4f04bb5b156bbabb8d70cfc234f6498ce7d7694b371e9d667b7333513132615302ba4f7f5bad774c47458628d2a48877e895ca1ad6e9344d8c68724a7894565062a2c443c904eeafc9e61675946c614a1db4274c517e8aa5d35f9296ad0dc237647db47adfddedda11c94a911e91a0905044e22032860812ddf581b0f4546d9d168f88c43022d2349880868e86d10c777447eeff36918e33fd74feb650b1beec7430f4ffdb64062f6600bb6389fb22ea8d66207577835d96a14c576bb15b2c431832dcee58fa22ea3d49954a0df16234c4ca90537743e991103142ae0839c5c0c6046228e2633ac658eed59f683d0f7fe7a21173fefaaa71193f0bb4d9abb545fefa8aaded36af5f9fe5aad4e59adeacf56539ff3cafd7d4d41c71ee5dd79eaa8b62ff2ff4be3571e7a29d94dc6fee79d3e5b1ac02caf15105e93072e9421620c702ace8eeefb2dfcfb6286593317da2f2c953e3523e2b6f7ea55ee5a9ef5dfb37043505b44001593a661a63a9460a00522920484718fa18c120064f150c5dba391c18402f576bb3c9f360707ced2801613091f75834579a002e3e4a4047614209604211a0c7bbdea345f4828ef3dcf0e3e07024ecf0dcf1bc899342a15628d46a740034b01c40c9e8051ebc1046f7c2014641f80832c52808064641988c8204796cbb5796d647cbb0c753fa49d648208f364fd0e62bfd644dcff2be8b5595df1074ec02132e30e9ee58c2a45cffc340b420460b75d4424e470e4f7f03cc61802c2303e4e63e68c482162316aeb050c382afe08215c2d10a52563061947519654e645132201d2bc5a66f6213a64da2ac8979a18df95f22a18d41f15892dd96274bfe3771a56e9aa18bb2be892927fd1461efb56cf697d2bf085b6f7e919d8e831ed3d7e73aef0c5d1dfedbf2e9f53541a1d14802a323a391094d431333b69e7b9e8a86c6e36fdbacb4865f2de72deaf26f084a8fb11ca5830f8f4f904a4aac50bafb841ecd8831c3cdcc50001c8c0a90c5e32cbd0ffa046d96f7146dd088006610c00204c021c0080330c100f26800308c0430a66dbd78de389e2eafcddb6c9223bd65e7579ba784cd1e7b1f0890763118dd2cc6d3253e4d3c12400fddbda44702806114800008310a005077473cbbf9f258494a12ae76fa17d912f714662f4872ef893e83543863a48210231572e8ee00f44885385241480a3488dcfc4e91ab336f13f6428e92da6fd7b6acb7bcd93dcbab8dc1ecf5e65fe9271450941c3725a6d2f3e626f374bdf7dc83b1d583b1ac79dedcbc695b9507cf1d146ad5e1d9692978f728055005040e9404e2a51bcfd70848fd190191ddddaa119012460000d3f25aff6b71a437379d262300748fe7dfef562300e400a063defebbd508052f1dffb31b9e1d47371a0a8d5090ae1b82f63e10a76aab8f50f02ef64e9eb39b0d3884a90fbd1925f64e6cb68f928abd9313c6e88e2dfbd3a3137630c18f91095eba3bfe0db7adc8ded813b1421cbacdd9daa098474343431361b4f517c42313b27477f43cea6464426b64c2936e593a3232018551095fba5bb67e5402964cbf27ba4f347b4625d87483f33bc744de631eeb7b8c55ac97f2ae0976f7931e91208311096074b7cc8f6152a865258e9425212fe238a49fd7d717d2793c3b30b5b2d93e4a9e79e6cc3c398cb76a6beb83f0bc3a28d42a8542ad34ceb3a311c87437952a1e89accdaad10859ba23473d4c39cf2a71eebb2dd317f68c431f7ca8ca7dcb85984a15ff6e351ac1d5eddf65a1d7d7d4caa6f563bb17ccde78dedc46cdc6a8b17434a1478d803f56d031f644afaf25f9fa2a49fe87107fd83f6cfe98e96e273d5384328a00eb583a42faf1532c53980f1912350dd398dbec960b854c9e373799ad0d925c9d960b71aedfe5b0082a229469226ce9ee48842771a2502b2df644a9d47d6efe0e0ab5b2b181d91b3f5e7e20e96e9d9e19021e5a0c418a215019c20166842026ce6e0b7149be2479a631af5a96e7d157972deb66d8cf3a63d7d2a2d93d0bd3cf484c085608a1270841084215317fccebcfaed6e981eeaaf4afedf27f1e18ab959a26dde66a9dbb76f38052f7ff3e779fc3d9da9b43b0c37367a80609ecb9da87148d427ddb94548964f36d535238dc8064274908041600010442023aca929b381e922c9a9dd7b015724aa4e74d1ce9b3863f30e30742443cbb1f0c60868f33f8b8c287a987aab8c994bd1063ba031fc4a087aa987c80419bf7e8c11e507437cef4fb2eab62a6cefdb5d576afb0db03883d76b8b9070b3d00d343554c25f96d53b8fa42f273cb92eabcff72fcdfa40747f4209b4cb93e0fcee86e1e40c18327188738cffb52787042191994b93254c533b69b9bb217e2afd7b2489e298e553553c6a63bea01043daad0e349c71c5ae7fea3395feba6f9cda9c70a79cc9147961eaae2393cde8333e55aebd3b9d9a9f298c9838487197844000f23778cb903cb5015b7d6e531afde2fb22eeff1c83d08dacbc5becb38b4f75d7572259b7dfe25c598076ed3037de68e1a76e0c60eb0f4509589b38318ec88419bbeeb329db18365870e75ec5107143d54c54d60e8cfb2d964bab8d2f9e51fbc8ea23a9e74cbead411840c196ca252059c377b9ddc0b91f9820c13646c3c6f6ed8562dc6cdbf8ea9d351043a66408795ee1eaa62a25225564b73fd22df689e9fcde1accfa22349be5f54292765909ea163668e2fb104c27e0e2dddf1dad6cc1cf27e6b0e20ddfd1f472728470c2afdeee7e7301139b2c891a49bb54d104fcf270667771fc863c972b65a3c5f337274c4b38b434c8cc38a7b1ecdd8ff4eeec39d9e89a326729fff827215870b3af8d2f67acbdaead984e7ebbb950ebaee9e5eb7d579faab03520ee0e8ee38f3e43c0759704873203bdecf1e6dad7200e4da56c5419758aded307d79ace47993e4f5655738984077f7c5a9548994fab629a994e74d9c148e09399ebeb2b1f9b629291b98bd4965fc5ca61f7d2205490d610adbc0eccd1b366ec4d1717a7da2993d6f9ab8af6188ff5b336e4419421b73b491a58d1b66da283246cccc980e7477a4f9cf621a25d5d2fc5ecc8bd1645b69bcb0156257c5e7e6572dad4433ff77b9daaf5483cd4f5a9f18f3bc79adc7bccda50b7fb27b6d015b88f16228200c3fc20813657def04eba187fae37913c78b780f5ec485a4c9f3a824faf9f1288f488f79d4b317be378b68f843bc26ed2514116811818e0800600618140003e80b3fbeb8e28b27bed821047f84808c1078dd4ee35ec41fcf9b96fd16f5ae6db1c2f0f323252197f5483f92e4db9d8f3d7667a594c751f25ac7b2099638f44037c9237ef2169d5e70f1a2025e04e1c5932e43e8c245975817b0cb922e0b00011810740182211000f9801a1f20227e9f29ca4ff18bace988a37e8cd49f96a5c13f0b45173299ea8f9fe2b5a76aa108917e4a24cfd24f25923fbd366bf7bb2cfd14f34ed5bae99452c1664fcae6bbd7b55d88e9ee2eb874778ce1f9eaa2eb22081761ba3d2f5f2e94e06227d3f96d2a2e82fcdd824c473c555b80516d8145b545d7718b9d2d62757a8f1664a2165cb4b092c323b560d2ddd6470b8f116d340b6521a63b5edbcaa24b776791a5b3e8ba3d8b9def5659d434c962860b1c2dc405061d75fe5b3636307bc30a31476285788405998e1e163b60d1e522eff187afe8b962872b1270c58c074ae081ec81ea81177c1024a5fc6fc55822e577c51209bf47c1cf6eb64a2951279b431fe804bfb56a51ef40131f585185153d5811ad28a23a0c49dbaa3c54726859d3a59f72ace2882aaa74cce1c1a1020c152f2a3a2a945011e4546da538cca758ba96e4718bddb26d61c014774ca18129f289f3ac4b20a0d2eb2bc9311156f87da6d7b242213959d7e59a580a3ca44881143f483124c54c146644e125a84271c5e9312f0a20509001451728948082080a295090c0012f58060579112732c58bf894fc42b6f5fa0ada0b821c10c2811736e0c606b244956d557ae77b381b3035c7a99e70c113603cf17ae2478b10b480d11d652988f4f3adfffcdf62cdfb2d2daf65001af843035c340093deb2ac10737fffe609fe6585d83fc6c24432302603626420890cf864a0a69be354ac3b2fc7a99c90e2849026f468e28d2648d044144dec34a102137630f104132a0cf0a09fb3dbc9e594137767278562e9443a5d19747297a5295ec485bc880739a69e51a895c6bde7fd56a378941d9e9e90e4ea949815624c248561b3c74da5d40e6e22f99052c1668f6d55fa2dcc794f9bb8a934f3cc71d3cc3387942dbd9c47e7f7ac7fa55a1ae802bde97a6fe69993b1f6d9dbb279092cb1b4444d37ebb9e7b2f4d11db3b4200b0c5bcf73584d3a3964659912b3d4e42cb9d2ef025ffa025b2eb0d34db9bf9b941e637933db0bb0d0dd4ac040095847256abadbe624cac412479a2fa124b6742c250176ac376425e1dc5f4ac2214682f3ec0ee7d90e092e4858e997f56e9060d2b14c919831724418d5115b3a5a9b8fe8baa3fc663d224977944d8e00124f7fc19bffdbd25e5f51a895c679d608cf88231618d39d1f3f868229114cbb6c01222c80044b1b584680050a2c56ea0dbbcda31efd2e17cdf7fca590dcd61cf1bcd9a24574bec20ab851012c15b8a188378a10a3880a14f12a82060ad080022f0ac470058e0e6f26b9dbec25d2dcdc8467e79e87e57ccfda18b7fc6ec2267c3f56678c05fe05431b33cdfb2c3795be887a5303ff89a4578cb5f75813e77a858b2b563aae7e7e827e635d216102694c000313d099c04cc76b89dcbf4d2447c31fa847c41d4434d1ddd1e4784e980e112409e42181342460250ef1bedcc588ca75ce90430e91680e51f1efb2044856c644dce56a3fafe1a3b0187274562a1c9d20209d9cd37fb37ad524354d4eeaa9ac3861c587ee8e325b7ba563ca43b4d9271c0dbaffb71501383a0e55a152c5ab2a02572250c33da9863942a04c571504b66c10c8618832dd1d71381c623cbb21be0cf18ad3b62a8f10550826dd33082382000a2249f705020a10088895111b2246145340ac04981d300cc06e6026bc82f0aae2f5a40808455b90bceb3e3d229114f112294f2d1e414924250d09678a474853543dd251f273c8a237e7e93d5c9d9bab52d7fd4f2239c23d6d51ce7e353471fefa9a316dcd2f9a9b12aefefd22ebd884ed2bfbbbeef71409294a210c4178a53b4a2e8f19e532b2057294bca423965ccef384e3aaf43e38c242e84ea1502b1b98bd99db47b944b8605e585eae3bce7bc20f67749c3f0c01c974e4eab49eed5edf77f9b379aed02350c7f6c046611de047055393a849469f1d1f139febdb91d23defb9f999a434d13addb4f298f1176e9712fd48c7c1919e37711ecf1b140a8592138cb11c63daad481eedb59f9334ee51d956d8c7eac42caf8a913701cf08911a444510492122c107187494ac106bdce329dd84e4088d03c9231a9ef854a70782f37aaef315da18d136330e6d2cdb7a0a717d9e3aa3ab5a6f3689b16ab9f031e8dcbf10f739b41a472738ef6bda9d9cfd6ecb87208da9fb3885a369968c69476bbaa3cbff4e22a30e8f4e4b63ea2725f97ddeaea8abe94ce7866955b9c694542357182e697aea9aa0ca55e3b9ba3b7e2b8d96958e527a97af7db57628d1bff148fc948e3153cc63cd6c7d7cd2a2d6501513952a1ebfa6fb0babed569c05381bba7d43632b62abe98e46a663225f6db5947ee7aab4e48ab14cefd9ebd7e2b0fa7056185696282bed9111531c162ce6b0bc239e2f156b86e9ee38b98c265077fccf626fd61964ab3cb24cfcf0075a43e7eae491602e9da0e3c8236492881dfc2772554ac4fd571d3cae24900e4f4ff3d28da996ef3f2ba475f16a3b3e1aa93b6a40a2d003c0349edd0336d01debc449e1ea8545956ab0f9a552b9fe96425243eb2f9842524308fe68da17d6541530ddb14472eea9fc41850b2a4c50d1a8b8d0430c463d70d1c3aa3b66ecf95d9a0c35ad24ff63137493e45e92ec6b859fdee4fc7dcef6482965ccd4710cc170c5431f3cac80870bf030a53bc658eea727a6d213d28fa3fc143f68ca988e539648d143ca0ae2571e8fae6afd59ddca562943524c33bead51b888124594a2283274a34ed6c74ff186969648ee363fcb84a9ca23141a408941a9e98ef8feab5bad8258e9ac8aac5e103a432805424542a6ee8ed7d23beb6fd83d8f12e5ce4541ec422521d24fac79762f3b3b5c1fe3bfa10d3ffcc1a58cd52032826c5029c81d0047b439cefbd887c498f799565a5fef802bddd1c43dd108e80fa0138c8030508dbfec8d9f6209574b49bee2e9e1798242e1bccd3ce756f221b5ac37899c2496fe3fdc8f0b3e73f82ce19343cf1e3d51f4ecf4087922832b4f943c998926ec81f64127da226db5b0cd917b1d8ff23d524c74add6f2676934b6bac9eb77523cfee6b67bc1e6b553d32afda4d344c7f4ce22271e70929dfca0d023273c3bf0b10398ee538c3d91143f45cccdbf7e8aa598472dc9635eae33e34a4ba70f22edb0ea6e1e9e3178409eb873831d27563b2be83046c76aab05c30f2ab2ac29254f941c0a8529f761cb9bf8feb78a57fab51e91446fd297f59ee598ca7804f577bacc38e4a4737f6fb646a6ff56ede6f86fe89ed784084dee68724593294d00a023860e918e4dce0e72acc8e17266bae30b45282d69ca3c359cdee289a5161d42a1a8fc47333ed99294fe8f498e896ad86dcefd9c757e45f6e35e936efa1a3d2f6c7125120a15db50a8156bd6f91ee6ea7f0e2df716f4e9231c2eba3be3f8e014b9211387647e2ca9084589a53c9e37b265c1d05beecd4de806bc41806a072a2daa1c9500ba23aed666c72dea8f9f687e3d8efa6c7d220bdbae32e911132b980cc1644a47cfa3446e739ef3be57fa712a146a8513b9bff75b0df8c0a8015334006c000252605239d5a5663ac63285551e8ff8b9fae029ca589d5faaa1a4c255cb42a15ade0b918624572d4b52a95022572d2bb4b11bda9857ea4d6e42891d9e190cb3d4407072aa253758e2654913dd5d3a42fac10173738bfdbff961c9f17c779ac0f93906e70bb3b2c9c1f902e74b48c90c194a8f0c654486428dd0dd4e3acb218c1c8ac872d8e98ed26355e5dcfcdb65232efd14a9f453960488243f242965495e7840670c28010340203b63c04f191ca2c00196d3b298baf42143e2bc13487acbe2ff2646f090213187c75f5f8ddcffecf6377e1a12a1b834c27d7dc50c87ce6e40c1bcf2ad0d8a6136713c3eaddcb0d39dad876776833f774367367c89d7663658e96e1b76ba3b5e0b640358830fbaaa348e67d6008b355c3b1d8a0d28808401f78160b347c6bc96a5d25b99e2a73767bf29eef3cc47b868cfdaec88921a32354cd4f4504363e40646ae18c1c1c84cecb68c7dd210e313f7a5134f67d14bb7472cdd1d2bdd9e157722906e999d64707a65272327201d8f609650916731a6dca5262fd26d6ed9cce4848949777c7d35cda88ac451a4a80850772c559a6be8d9a25984d4ddaa8ca68c8a8605dd3dbb154d161af939a3210dc9fa4f60b3a7a704a63ecba7640536bfac34a5bbdbe66c2bc98d8c1405c9878ce4117f5a687df8ff3222615c9512f1ac053322b08ea5d2d421b2c3512f915c45a423f7190d61a2ad3440d11d1aa141a361c6e6589d9eb56036031cd8facca065869de8e1b9f1b82a9bc19b4c77c479863f3c3765c042063b54a9673204e9f8b215281b026608ac3feacdbf4376fa5acf8674770b8943889688ef739b15c251214cba1d16c30d71b63e31cc208620babb5aebc5e6a7bdbe62edf535f5faba803da05880ce0b9d2d204a8eba02b0c814102a60860c063d3218c6c860a0000c3634f7955a1fea833f2894d3445ac4a59bb86ceb741a1c3d6b13204702509025e04a4757493fb9e4a8749a9675291d4f8ef62043c00910e0650880e100651c60b236217f29087b211ebfc89f68e679fdce77cf2bf9a5955a1f827e48dc5fea590b86aa17f878e18aec8508bc700a32a6e3f43aed4d1c92544c5fb86dd314b96a6fb2204fb2202b642ed891b9e082ee3675e64214990ba10b60e682c721099b3d3a68de6459cfe5590b741fc8b316d460133635d81caad4ee50698fa4e2f985fce4955a1f5ab8226b61b630d3420a0610c3005e18a04a779458cb8fc3967569924b62f0968d72c912e722b52c259db15044c6c2938c051ab2157490ada0816c0528d90a455678215b4177e75aa9ad5976253365a33b3ab2aef50944447e76f4c3e8003365cc70d1ec497a6098656cce028c29c095ac003a590148c8082003024441001e022c19801d03706200b028bd498bf8555279e290749a388442492a8e6962d87ae227a789dcbbabd29f799b2eaba599004001bc9005808c007859005a5021052a0491a910aae0590a45c852b8234b810b003a4b818a149e74f792ce52284096420940b8c88048200302cb80cc90015161041900ba8e4f44bdcdb4e3b1143e2579ec4e8c7ffbea2dea9e37877880a0370f0d31a14a7f39a28d12dd6f6d96d2441c1f12b937553af3fd0d4ae43ed36f5ddb9aff596ceb574bb7cce344a494190a6664288091a190050a2b1400704208b21336d0dd419d9db0d3fd513762c4a39fa4d3c4eff1138dca87486bb1e3f73a37ea811f95a69b88f17b769a90850941990908c84ad84156821b59091628c1ebe85977aed607adf62ccd668dc8e6ff7cf5e3f3a08d484cf1088a4ed7e74cab4b9e8c043b3212329091d075f74f6724bc30827bd616651afef09ebd3c505a34f344d3b5b037b5bcc7999a6836821ad90856b211e40fa0b3114859b391751259ffcb7aa7785f5ad8fcfc9475e98f35fee8d21da7fd32cb8b9eb53efa83e88f27dd1d7dfe38a1085e14818722a4400430e27759feb53dd647fee3fb3874551a63f97f164bcf5a9008980831f811043fb8f881449b86240a25a998b2b5d7b316f4ac05b9d752f3be761f855a713c54f3ac053f7b5bda7b39dbdb65d8fc529f67d0d55225522ab5b281e2263765fa4aad6ce67dcd560d363fadd22f5b7b2f2b65935ad9e0f76cd07bf6de57c17481dc94f271d38e0d47b5fc18889bd68b4db042c1a95450ce8ecd6405e5ecdce7e6e7a97176bbb6a5e197067eb7c33bdeccd5a69eb338afafdcfc0e0c532a94522537a5766c3248b2d93e8a86af65e517caf53f7c8b2c38f3e4b46a29f719537c1ffc1be2799fa3dcfc8edbb22dd26299eed83c1014a7e67d3e5eb63ac787956e3e1ccffb3e08d320ecb147bb97fb20fb60017bf4e191ab4f74e7e7262c577b7c19ed8145665bf700ea3d50e88198eed8032cdcfc1daff454c31edc406dd6f0bccf0322784053c606655e50268832347aa4a147187a687a8cf2f8230f2df2c012f1bdd46326ae7a74b662a64a27f5fe3f5abf7eb7f2d8e1168f87b66269b3e9da3c96e0a1071e4f8cf050e111a4a31462c996f51f1e531cb94abf4ce72bf6f894f16cb5bcc75fad7fce1d5feee0401c9254520f0415eab63c4b19367bb84f457193939dfba952aeffd91e146af5b2750705f8c30e2ceca062070d76b450070bea58a20e9b3a8844991f6bf73daf1485a239d25b96e4712379b5f4889f4ad89b3f92e452c6580e7e33b34c8f6707fe83dc13d9a24a534478ae88f0cc64b6b0e693b1d24d264977d33a373ae0989ee7afaf7f9d08cf3ca2e30b1d5b383a649feae3900e524f90d2318717fa41732481f3dff421c273959aa3660e20728891834b9503ec9e33e6e1d07eb16ae5f021c2337beabf49532894e74d1c2e955ad9bc07862b9beda3c4d14529e320d9aa8330d46bb56cb5261d7489b127721f1d28e1dc4e6a0341154f0edec8810972b0440e94e4e0d42d758ce8389128597242fa9151ba4eccf359f9ceef482e71ec9db8131d2fe24e50f53d0d7739546935a582ca4d97e354a624a18e9b928444f3a568afaf389871f5c05103389270151c40ded0c11b69bcf18137a6bc218334b96697e98bb3f5d4a28e89ae7db5ac733cfe5ddeeee7ce453d49391ec7446e8f1b52b8a1841b366df0d1060fda88a20d1d3a5e696a592ecc16f4589daaf8d5ba262be6dd8f796ec24fb337eb837e2df79872f2afdd70867d45a156f74130d45c9355f417e4e6771e9db924e4a62824ae86b6d3b48cad37264b8f61d29163038eee188b8d2d6c4c894fd8b8b6b58697e69e35bb35ac346c7e6b00ad01a4f37fa31b7ce96e2837c0d2dd7d839d1bccb4983062b2e09615c3a43be674be46628274c7fa44f6b21c5335c474776335b8740c0c3d3f56037777b785b62863ebc191c617691091462b0def8e428468ab9f9fa0d5cf4f101a4ea0a183469033c29c61c41940feac7f218facb701183688d9c0c60c3ecc186386968e9946e96f3261951908a8411ca18de1d42056832361d80883459823c2dc8429d100b33ebb85dbcd365644b310213400a2c1cc0cce98010866e09a010d32c8810c9088a51229c66e3c3a5bd6b1f5361914033131a0c0280641c48006188481c1153058c1808617a0f102235e60039ea03f0bdb98d4a4e7692dab0d711a975e44e22772c11c2eb8800b72c014010c18606031b431f718cb7a72bedc84bfdb425be4d772ef2821427c7eb8e1bf2df8410b3ed082b005475a904277b7ece954edaaa809e6ead3db62c1976e16687916809505350d44197d7497b1c56d2d0374dd598677cf8ca76a0568e4d50aee0a90a8600f158c11ffafcdf7c1f9dde6dd167e3e3de92d9e50053d7da4804b47ccd5d9d109ce2f56a7f55280848c36c8f8d211086a7255ca714f460f6414d1a4fba876562ea4d3c3b3729da09f1ee93e3f9ea3f3e4890ac7756e847876b814921a522592ab5257a55fb47487ae2f5d7f4982823ebadaff2c56a1c04b4714c05000d4f15a47828220fdfad609c0589f13c0589e89545f9de004331d71e9affd481eabd3045e9c621380b67afe989b5426f031cac499e7185a7abe5463482f65a395a0a7040b20c11b24c842029b8e383d907ee2fdd3742f7578a1c24b125ea27819418cdc8f698dc9898e8a81de3b6fc6d8e0a83140d82042b7a34c4d2a459d3eca06096bfc608d3cd690630d34d638a37d899b7cde772f1898a28c0f51e911ea58a3238107dd6d020965b8ffc123debe68e27975f0901b8ca0699af66d30ad6bd0a06a68694705fd0405e9780c31c4a086901a6a2451a3a61d755f33e2282338f4c01b62cd44b54c0d01f892254bba4780401a5ebadbf3bcf747a8693c208da0349274b7d5be0d9629f7dab7c1b4cfd230401a24a0010434cce82e69247794c951953a08cebbfa50285c2dc528d48d191a0100eac9d9a6077a87e70e0ab5d158a6deccd7f6dcab43f4a393d9a0cb6cf024b3c1936e47e10409dd1d2839d872a1d07dd6bc49996cae6de279130707855281a3360a0a854269f5398e761a05a70662ace16c3d7c3bf00bb523bff1582ec43785c39123478e1c3952732487240cc0e1061b6a4072047fb64536363636cf9a3736cf9a2cbb42a164703cdda664425243b803c773ff3ee52c0e2b367bb84a89aef561e63a5fb655796cabd2ff66fd6f56edd332f5c19b1f85d14ffb3cbf6d0af7efb1429bc355eae4c158d62a75d94fcb53fbd617511786cd8fa35aec7ef8c3b5f489369a533514d97cdb14140a491197fa6f69457f535ec05cea05092f3578f17e8e4edc6d3eb1aac488414b250611621809638e309608634916c64cfc6a3f6b2f4bc6587ead945fe9e726495289e04b77144196ee6b5b52707eba9b486722902d826ac31618707483d1a5bb27088615ec604cb9f3c1f02fca74c72fbe48f9024bb7b55f4cb976feeb8b245908f8e8965a2a95ba5f69cf8fcd6b06d9c0ec8df69a17a7f0fd6c8b3498176e78c1c50b21aa6db5a417345dc474f1d21d87e46bf9b1cddef421144a52597519ea920208bc00810441ea03643a9630c96dde2a8dd5196b79ac4e99250a2533ec2bf5b6d999843ec0c30748e8228f2e34d0c5d6854d7724da26eba76732dd78546d1c174b70e103172e6c4146b685175bf4b0c5095a84916971450b2add1dadf50941536cbe3ce679f4958dfc47f37c51bb8a2592635ce77f3ad569686868a8fd6b7b3cc6bc96a67db555d36c4b2885a5601c215caa376ef2ac6591565960e9ce02288b202d87dc245dc5a54cc45cba74472e30e70214c50271e98eb3da0c0b2e58c0b008d21d63e12bc874bce2045764b9a2bbd6845557d4747ba08f1d0f70e9fa5f7829e701a04c410fd4bcebce0ef491435607b80e64e900ce3ae0568421dd58c105c4b14276c796752bdc8a2abe54a1255601547213a98a1a322a64d0b1ab54e3709e1a15413e2a7acb97ee8e5bb27cb7dac2a43bdb12a4a7d081b539d5e1b933853685499a384aa58abc2f90c2082974900288775ff4f7c6a3f062eaf0eca854f11805d85124e98e02484321a6e385424b08423125629cadf581a2a62307fac88fbd42e180976e8aad7300e4400db701325f932840d906bafc06acd81d6f5edbdac0cc743cbb27c4f4135c9e98d2fd04490b192d30d012765ce52f632d41320d1069c0851364e03390394102275a4ec426c4644d7439599c635ea5afa93d910531d17ccf396a8ba6db8cf3bbf2c7f07dbccd56cd7376ab31cf23c7a99ae861a28fee6b7d985fd1d36ecb5e88395b646262cb646295315104037960a04b77c7186fb5167b8c88949843200cc88ef3315064093696a0c012361eed5ececaf5392ec4cfd9ed5d33e767d5782bf5389c38f7b9fb93e98d965d334f2d4f8dfb1a5e30e56383ffa3ab6d7a5982b20089b17c275844ff0260fc0248342d72eef17c6517b0e102415a0e51914a88698e6aa618a7c4968e4ac0942075c44924912589ae23a659123348c0814497e61edb0c092bed4800c51ac71409b7f7e598fa115ffa082bf608efee58dd0832d1082ed10820234e8d391e8e5ac0cb2c50d3dd5185e50d2c23c0c2b9b74d5a432c2e54808cac025d2ac043055628628c589219d327327ad866dc8ab1b62258451020a3800fa0a0404ee4ac7579b5d3e48f69e61e130992527a2a97d2a7f49f2b3bb8a281ec8ad015201308c104b098c02a53c7dfb5dbfb804f2e311124c888b8828816110a908018aece98ad0db2d8c7a3047a90c00b999532566c66c52602428840188cbf66fa723cbd0d63ebcd08c022a04343008c2e20c082401108c8900dd1c610560c8187d8e9f8e32819a5c461d18f14e9a7183a0a4a8ccdcfad1ce2248498385d882e42c084482284b782f0a2bbdbce3c73701049bcea00d107105bba2b10b1d81ab13262e0bcbf4d2f5613e507c8616436181698fbe97587d707ed8b05af2311bf5ea4ee58e9dda46d12144572b8284cc710f45994a53b16d5cc504c777c3cbb96c5212cf4eca5331677cf9f43b065c262c2cd72ce795f2d8e478fa583b974c4df6d186c5cd371e220f74b7c90a345795ebf497e20f303978c2de83f4cf9210489e6839e33704b83a0db2d0f5aeb96d411575afbe80a66c2e657b574f4e64633bd5b56995416a2fbb7c7b725ce0ddfcff9f1160a7da9ae2dfb4050ac69ada24964ada771b6dabf7fed566473d6b45611b8d569c31cdafab29c67eda669e0173e101463aa7d61d5346dab2dcd5e9b3530a4453a353a0b74c49e3759f42b75d5771e90e64ec84584ee186399fe5b26e9c25f9e5aae8f534950a8ed8b50282e630dc42edc247381dd4db977316957092d2fd1f3288e3d91731eedb6dc7aaf85a5e3acd37aee79aad6948ed77e6ba6bbe33f98f87df65a549fa4ffbb3ee6b44c208fdce476bac31a32cef3c7b22dcc86e9c6a45a6afa6c0bd2f15d777ea9a6fc31158bd565ac195cc32cd31d6797ee38ad6473a7bbdf6702e9eea6587e79223bd7b54e045399a4bbb34a33cd8eee8e29fbfda779337b4099077079002867f8caa953f5001928a7930d4161871850c58fee2854e7b45eab9051c5872a33dd314f93cd5e5d7482dfa44206950ec450483ea633e8f53e92c802f570460f5a7a58a2071c321e76c0c3183c8080872a3cdc300508dd4dd4d91424aa4c3175479bb363225c0d5bd7ba12c9d597277794128de52d7b5272423d764daff53495d2b49a78bc34ff7553d89ad7b6400aee1a62eb596f62f799bacf3da6f3864dfe098b82738b9265888af418654a77e45850ca7c129c5fcca0bc000aac3b7a9cf79b4011b20ad3917b0f0c2f37c31ffc399b9d02a9564d74c7975356b61aeaeea1ce56dd910b5974a3af5c6d26f4a53be696d096f6110285a674cc8492740bcd04cde1003c1cc001073871400a4062004501b40350fcb9c18f113f36643f343e623a5ace7bfa728eb2becbf324fd14dd9443cf62d6fc2edf8c2f55e56a6d967e2ab562ac073fbb9972784eac10731cbdf158fa2258f8f9df094eef7e91bd1c655196e3d07e9dd90b3f8aad073e572251964f0f3ea31e13643d5c22f737b42d29e5b3a85722b5c7cb7a7cbaa3bde0a952af5af6c48f3844453e09e3c93f09d21d31917927085a4c9be09f2f27649c84619d34c976b8a33b7e987eee519b5de6d06ad2f3f6b5dacde70e11d881dba1059e327884e88e7fbffbbc979b541ee79dd5ae329e998ed89b96e5d8f376c84430cc76b6f40e9608a4b39d6f8785a639ae4a7ddb1414cadac0eccdb7c1740875f026707447f0b76d7ead0f5a0dfcee8ef43abdaf33e36fd2244bd6447677931a9d385a678aeee6a1339d263ade1d256c7e513e107f41c714f6994e8e96ee48ebfc7260310728cb99c970ca74cf3bc10c0707ecee327de130b921d3dd38eeb991ece64b0341f14d968e1c8f63dadd905af6e684ee1537bfbb13d4325511aa9cc8e48e8cc9144caa749c4c64e8ee9835a08bac014870f3bb06ac90a564909a22d5f9df99c3736285d897ec60490696e8605326b3d980cd8d0d094a62405f6e2a5d22b1efb26d0911622b6d7df7f3c955ad5703b1b2a8f453f6f3a6758a660000280053100000203858301c924a66f301d17d1400005dc49c54cd4696c789cc29648c21c60000000000000000c000287b4bbbf646a6a0db77e8ac574fb741fb4c581aadb6453d9f7dd35a3445814188d4fd87309763c28467ae107a8e6910039e25835cb72ac6fc3cfcbc28bf0b400beb2005cc7afa1fb52db99fb706ea7cc0c3958e61ecc31c08f746b5ffa18c439cd8540799cf07e1042d0eeaef5e23f9a12b1beba05b8f169d6089931c1a5eb6f639b3e11c6df33372ca3cf053bac7e084c609db5802a120e7b4625d38b1acf7ad74047537fe3cfa14ac04eddeff2ae8323125ad4f9c3ce97a7f76c3c6dfca060ae601714900fdaa77a0caad0089927af59442129f412b53b5dfedf275be7a0c75699b0d613810565c6b69ab506e35637dd8aa98e2c54180bafa91184b4e0a90aadae9bf09f65d20d04ee886d4bc515e6db6de97ecd0156989fe4f2f282567d1307dd0b9d66a11e7f5a435d20fb524908a9e5f97d8440980e885a8640d0db39c14a82c372812145f4daca50e2593ef1e9e4f3868bdf3b03d24e12ef02321f7449dc3514764370ccdd1428cd4c04a7c172d85dbe9c4151376c4f556eb88c733e0ba3576791d7d47b8f70399e5f714f0ffadfde4bfeef8452bff5ef88eb2e1627a824592882e769657882b4a5a362f01ef1f050cb7dd7812c599a1d0bc450c0fcec18082691a1f0daa58f77a77a481743d4fcab8d4a4902952b19f00fb39b849c1769d203c846442407b4e9d7418e7f7035dfbf1c7c6b5df201b8fc37f469003f2e55a6c863436013742d741dce05b6d8253744c2b4694760eb489cd8f5ac4a6f34755e70da9ba3a244957e69327435403225d1c37f1c241c98b3aebf36f5cfcf0ba8fe3f2c45082fddbbf51052ef4ca362eb068a9d0ea3a13f157b149da0940ef51e4d44efde96d6af48a10567a9facdd0b2233ec2de6f6d7e8042ddadf6b68f530d021544f29a181d3cc76af22a313885ae8b64f1c5631f31a2e06552ceea2326359b31485447c6853188d23046b0f82a171d6b5ea416d01abe013f004d15e96ac260c05cbf50af80427609c23625665fc89e2fdeebed34609fa79ee2608f85be1d113c53b755a163a8a805fdcac13c474df7c51020d3b7478bcd32c2b7827e0a3e955f409f10afd51c5451131bb8c4d6a49b0a037d1d54ef3fd9f9a017ab4f56ccf2ddac4ea215a8c77dde9d0d1d34a5b0cd954e773fb57f24d7f858ad1a603d361de91be987b24cdd7f65bfb482c0546a2e0cf7df62b2f53d5081ac5a05413987434e2b4625e3399a49bc0d8c6f3157764cc47a927a78a0be9908905dbd68402dc60274979292c1c7c1a53a20a1d2c7fa1feab644888ecc9fc799014378272dd3d96b82662dde3758197fd7c4fff304ea113a73f37a2eee1b1a70eca70aae4c17dfb4f1320aa93187bba2456a7442dde5c569dd8c68c39858f4cd92d82cee834489d3dcb011bc345f4898175794a296d0ff3464c05563152041216713d8327f0579b9d87389b2c0b3ea9fcc040f15b42c0d05e019040a53506002e508017500001cc8002a03f1e8f2a1bfa46f4fc320cd8c64a33051b78cb11e0bf11f1c153dc2d93e951810885109810156a522080ac222ea5037173db868d436c26e587159c070e798d830b12c1303988d97e1ce97dc088cf8bb4fedac31b1a5bd9b88bb84eca8ac6c66afb5265273cfa22e8f82c4c3b50c09c29b6e957975a6e52fc84c2701a17de2beaa8f88510d5da025c3769f2682d1340ec42b33a81d962e60e7cd21244637390c0faa3b6f9cc85b02fa96b8c05d06f842753bf1027dae5adf1fd3488705400a883857497ec6889ba67b02109918ab32d9fac2a58863b67fcf41efc504dc47d9f366dd8786e03844d2cb5477e35cbf082c3ed6d29f868842f4710957a066cf4ce4484b7d22c65208d5938a869f561a17deabbff9b0be5b8e6c0596a6016f9bd8b158532dda9feb460fece624b76fe8e577d4aade2fc4696338dfc80431cade9b88c9134fe115da9e597b92e50268b55248f3c711a5289badaaf583778c7383ae40e894695f7577a76d5d0bfb5d1bfa5cdef93fe88028f0137679a86609b8be4b67f19d337f2197d042fc7b2f0c5c7321449b6bae003d0e635092e190ca29c61836c15bf72c93986afb6968561dc0816809367843a6b17873d83ae959c9e4fd8c49cae84dadcc9888b2ff20e51209d1d63346c24dfdc998f9db487108d60fbbed4ba1c37c083645e0e0879cdb1428c7e8187bc464bb98b05d90c675ebf19349315f1dc6d91dfb7429a98e0b7bc9765181d198c5059677f75d8e229fc0c73ef5345f97f883e6931b8f615c34f04d5d705a26ccf5a8d75941d4005f277affd11f5a7e4df621ed8d115213e0b1a690068bec2090017d221def378537a577f896453901e32b08cf906c5c164062d1fefdc9edc38538143da37bc52fc98d018274277a8c977f1e8c539264bcd526f47646e8194c95c063927369e0bd39da75e5c9c93913b7f276d11981fd9620c1e2aaec6d925e13f1b4232bff62b75e36a756911f88a6b5b80f4b777d4b71e583c6fae9f3bd646dd6526a78944e8280ceb103dc99a944092a4e5928ba1ce3902c7c3246ae7a09d4e34f97d1547363c304671dc01298c582059493fbf1a60b93030e71264094b37694b57747b5a50af1377cfc448df774cb49c5da009d783fbb95c032fd9c1173be315ddc01f3a672b23c29c09c867185742c6c4cf3c16e7682d75b09525cad50a260ea55a67ef74c80056f3b7c84e4ecf10228f22c2612cd796e565d3ee169fd520b3896e30080cd2818d114df7d313c0f600562f32ac2578ad3c941bbf322ecf4d2581b07a53d433436e92e645555471f54bbdcc40b5011dbe848cda144adb9d08b88f3a14aa62d189bcef218dc45eb5d5aee888360891a3723aa961300d3d9e402a5fe8da7ada2c2d07f67729722660ed8d7f4c0f41d77a07e9c4247c9c468c7211d75170a11aaa255df63e2e588f49650b8249f0a73c84c4a5da0c8f853de17c761d85f366776e44fca06dfb0206b5337120a04a805462bbdb99aca3067fb715cccb3962a2fbbe1c585c5cd6e5f1f43b7687cc572e316cd408e7498e07a1f1e9aa7641eab9c945dc29b1e2da3d72569e822c9e7e93d700faa12c38c15a750eac5f21c6739d5c6f7a35f793456f8028405ebde0b76f996cc2ec0a3b6b4f86d737afc11239c4dde06ef61623fbdf9d1e2c81b018eb2eef01e250a5116e55376610e9a8f1c09e3a0008fde113d20ac6c3d2925bd042d77d57897e466f0e9532f05e34ea2c5dc17c15e1e02c942061a70a685c16a4ca1c052106d4218e33f25ec58fcc8443fbcdfda4981eec9c1ba694be4332c87eae674d004fc1267f97e24a073c6a379504b4500562b8f695017577699fdc9ca273b2cfdc85166a236d86752dea452c5ec48680f274a5cb50c6e3c2b0fa7c5d1c8cfab2c5d80ea9e342b029dc96c2c07db7ca3175cb03b4d9c879261620140e357f1c1601c91453091b85d7cff17f8fce48b94dd09a2b3adcb5fdd5c1881dde1c030544421dd75c8bf1c8bdd7b8b66eb98b684b179da1d2e8ecf8a079a38d488aac6207236cf8240ed1858f5c36e418cf949fc70918c7182d4e31628ae7971a8c61c545828923f55afab25a2d6631a3b56a8615174c7d749a54b56defd69479d58f4c0646757be8b87c76fb59154e9f9aa3c7b5e8fe706c8948cbc3ef599d58f3ace5022d9ae6cb40204a4842181f163f8f3b828be161e2019da7b635348f1c13a41ccacc9ccf993508133ae8f9e414ddde7025d572bde692e7c98c1a39acc94014ffb8b08b226801a52a1564a8463bb66f30a115844759fc0ad91eb45018e83e8e02c7038bdcda21fcdc2adb347c97c634c6ef9bfa156004317638b961dac77ca40ee3bc6f5ab85618e2f887393cb266cb8f95dda59f3cb03ab7cbe45dc84506e5105708206ec417ade4efef46129ad481f0d77eec59bea68652f7d5cd73555efe46cfa879781c1d68d198967d043c43ba399a9afac1efa26702e6363606e60b7453c08b0c86ade99cc11682f98400d4b9d81cc3bb2ab400145f863d7a315db40cebaceceffb98ec0fe85b55c670985d5a1a862e5c1bd81d39e1f4cee51ec1e5e81620e8ade4b5c54e662f1e789663bce3108dd1cbdb18648944b4f2a893078a3d7c6b76dedf193e8439eb9ffad62b48941925d578dad68a68dd11af3065bd40a7c02820287f113488d62d4fcb714218d5911453fd1bfcbb1f5376c075eda9c53d2294b58467ae779c8953db32bb797d37d03c7e5386a00a70eacc6d250e346191bcb6b3ffc14a7902586f7b4800320ef7cae5ab624e40c9b551a93441cc9b85d82202688891841a66a13666267ca5438dbb587794865b79e9b129619d97ec21429fbf8774854e1301d3bad4e5586f3ebf768e20e3dcf6ab4eb4f277ba76a1a286b3c081b65ab00164108512a6a913d777734eae84ec13f58df9060fd3681ae36f3245513b8064d1d4d4b4af1a7e44f0e5945c884728bf193a7e29093b09591e6dbb80bea877b4368297495f4f4e8f3d736cd4253bee267f58bee6b008bfea1dd964125f0e1ffe70fa166669bda2dfb080ff2a2c18052030b96293f2e9723f7e022255832ff2ef3bca53d461b17fc89a2f5c7589b2fa1a34b6457bc98ce1829cc2e0ee546873f0cf6fbaab55d1c414d4b582acac502857438d951bf6a30276238815fca3d2cd209d8a5fbb55ebd89205256895b935277a1d4a505869750fc1c5667324b77489811dbffd7d4c391cf2c09e49978e26fb1018d0c54019d33a70fa83463fbb8c9fffaaf136b62cdc80e7ab55d1071753e9bb152942e4a3d068329b3e1be8e7c05b11e4fd37d4e07f8f932e095de0faaa4a49727ae705720da68567b9286e8bd5548a3499d0197215bf927135ef1b0a3c518e93ba712837f44ee538fa8bcfc7cf4618da8be92a6b7aa5156320c6d3a49301b7d09c68736dd7b9e80d4ac0bbc25b6db21c5b8fce67ebd08caf43a11003fc127ab01a18a06e177a0e409377cb85adf0bd1835657af5e26a3ade958bda6c1b4156a4b357f3d3b0fa09226b13154bcf0178f74d8c9267d1a8ee1373c6968bf5176347896a052821dddc27e66e1549d99e1e59cf78c4c0dba3b7e0ae741aa14ee1b278d8628b1fbb7772e2e147674796b3f5da7f1b98c16e135b8d855a311008b354664e07f457ae63f2c973e42758da51eaa79712990c045e75fc8ce82df3c62979534db22eb4fc1979fed33d27b6859b7b41bb8a365f4254434cda5e20f3944ffd55187a74d338bfdf775e2a3a6cbdf0eaee88adb2c45ca13312f9db8f7ce0b07a4236b3591af3cf9743c43caca33a5caa1ab2304966e4a361a1428c4ae6c33dabaad85b9b486c8dd8d397a3b14d818cef2899d4e3cc142d35596bf31d1686642d9d3a946b3905418c397545db2b05886dad491bc1920bbc1428135f1721a50cdc2843444e8cfc0b69fac46c6761f548cbc98f749c1a4584e58899cbf9301b20ae1b67589949a944e006e95a12744df0147ca2cf1539381baeb41cdfebe2880521b9cb6afa82f34690071db4004fbc32f7077c0d975dcaecbe227c0b445692e4b95449659eaef4da711fb46c265832cc450561dd8a0cb494e5ba87de22509c28b5aa426daf66d9760eab81fb2d058d3a7c6b26c4e55e46b251e3db0d28c8715c4c698546545bb91429eca6cf6f53a74fe1dcc505312ba3314e149597e57272b82ade62bebcb1bd691aa7c2a5d9ac014b225c404df58216b3227511061214a07718b836e0ddbbcb2883728f151bbbafb76b5d21acf7ec88173ebcc68eb241ea85cda9e0a1812d2fa7df2dc9e9efe1fb9cf3f0407de1a6e921d7cc7dced0c0c1ee90def96f6bfb2407f6a0bafa4d8f1672e78bd9c4b3e8a18908392d740f9e6cd2d3549a1650fe017789a6440ea81d219edec28554514649539bb310924fe0e3d75b3330bf414b8fe4d177d8a25ae5fcbb22ecd464410fbeffd5e8f9c1ec37ff66cd33a3bdcc6076d1b29a25df640e5200ffbea8f72de7660cfc156dfe1a2616601c2df992c2e4afcd6f5333444b9e16207f0602cdefc667cb2578e88cda8f6e1cdebf76c8a793c3ac0ff93a31a4bb640e1956446f72399f93036daf3160f5aa50ce23e775f6b85a026470c1b9917989c528d8959bf60a598f0a57ae85779f8aadbdddc4cdd8a2d170a46bafbb650eb50cd98157c43e715a8bdb097c031592c10de033944c191277b7488cd130f3b25c75df178be2d3589c3dcec6134ba6944e3d521c74bd31440ba7b1db2b2e42a7935fe6061dbfa07af573356aa6db2c6a8ab8d9468e26d9d86cc08ac1ea3350e6232d6185472b191dbf126f601ee57d84b045e8182c11e08879741137028aaa6df376b601d03288b69929fcfdb091890b3e4e3b9b4403aad2e6f5c33cb138779de711764ac4b085ece66c3ee55e7f35e5179ab1b06625a878a02f0a2860406d81808696bdd40a3b39c6eae514be5e5887b0878a2962e10190b1b330598570fb5c361c5c75a5f60997e30e1ff70bb6376c4c769393479283540501f476f459a5912308920391797db5b43fa317329b636d8f89fd4c0a0fb8474e2afeb6103767f8ca72090c71abb77fe0c76fa36870b82b6f58407cbea1ba2eabe66c8c7c0c6610ad58dcab4e9e822e9be3105fbbd72169f86a407c7b4e81e0fb20f69421ccca3abc53697086171f59a71e2ab899facaa636a407ba997b3cde12e1ea11a9a200a3c2e581ddcda562224b034dce52a23e0a541de8d4e237118e9d75b3dd03dc4d150b4f37d864ec00c26d7f8390d4dc2866f2525c00bb56db00899e771e101dde498c15d44fe9e1c364cfb71bbb7d82761468842b9298fe92f31a795357b543d1aa4007e079a4d63bda794c4b84e7eb58f4d196f0a78dbeb11f2dedbacfca1e7efa224844cd376f9335de3642486d792bb20ddd52ec6e428006d60283c1ba936303c5602687451757bbe1f24675530f654d3db5c07a5b120a736d25fcf365cc0db3bdcfbd336dc6a2f7865a2f88a82bb2e6830858ee0d55956c860db08605a292f8fe37ab7e365d0df07823edd935efc5bfadfecfeeb174b37e36bb60e6090bc85452ac06ba21849405080756272244f5884f5874b2086e2a7afcad5e12d5a41bb9f03b94d5a7414dac9c04c5cfb81b994b46b29790d1a27b5c99ce257bf5bd76bbaa5f38622ee6b1a75f8012a27d7458cfb3ea48737fb61e1256c189dc2693b633e1fd2e360110bd8de7f8a6fde5e025ea4a29e2f3b2242f77d6f6503078ee48c0e0b70c8f0dc3a6561870b86c72e49aeb39c995404f823fa9b6f22dfe1ff321d459bfe4b7b781ce41c7e0c9b3c172748c2cd6094d9297a5e013b54ff4247e73ce51975edd5e4829e8c83dae3a3d01f5b2883186ad02c5fad8e2437157cb24bc74ee70e5eeb84388d5f452446cbf3a5e6c449355fde317fbd8f83daf8a9474d335b12f1ae8bf36699c684241c4bb4aafa2b3aed0d7b1baa886d5fdc1cd1bd931b20bec6ce98264a7baa3e616b3892f304e20625e3e275677e5177f0aec3cc63904bb53a841146947723aa5918ce4ff34fc1cd9f8160ba3132ee020d079419af94f30502a1cd21b53029baaf84151d423faaf83cc78aac3b1329e0a35cd6dfa6e16c01199c00a6a08de2ec86213f8388a3c860571f02c3d42d269ac4616931e15b88a55e2f108fe0dccdaea60b9d45b0fe81997f26be0411480f1444597f4612485bf02305ea0d575b0c84553bb522645e1f2a9b563bef632ce8f9c7587842806a430f1801f6ea386554f46ee03acac45c10bd8b3892b5e601fd0209bdf782e594a966790869676f7952d3843789f57128a8a174c22054820541a3573c03a711e7f4069d240c482224a81e031daecc3fe259063516b6b78bede3f1cda33f8fea95fc3e0835025f47a1032625a2dec60e22340d804167f4be6edcd68817102f0ca9cd87e24f631af887e3a99226fb2a526fb740d54e7e9518155372dca7f8db31828bc29381eecda0107072fc3cbcfbc56c773ca31f0f4821298be704d4fa2da64255689cdc415be86ea326735bd8b8d852dc911a31ff690b09295e7a6e250d8aaf29125ddbbc8060f38b81ac714a090b8a1061c223aed506cf48586335877f0a477a897ee48b7de59449e50157150420a07c0824c1dc8b49bb757627fb6c6c2e408e21c3fa17d88341cc6e1b92c90b7f9bab2b37071ba57ec4d121d9e010f5fce992bfa065b0d75a3cb6f85c204735007978a96f0d5b796eb0230a0f6feb191117bc911c25f8bbd5db928715d53844360663ac56a2e6de98618d31de5f37bd426ab9fa4346d44058088cb8dd4d9bf01971a73580c4c0ea3dd4783172746f403fb90216408566c72d4effab13e481b77e506173a67cd10fe288083b18f9374c14c0c0946bed69164bb963a60f0c079c7c4b4a1babf36d30213096c5ca7919ee6cc4ec0e307b0efa8666821aba1b5c32975559ebc63e1b665fd3c753b247ddc860bdd06e6537b50bd88a0c62234c0dd22b5b01218bc5641d9a992a378be15da51e18a4e77fb877042729575a8beec5a7ed31df2139a9db4d7aa8e32405d30dfc9760483cd1a55a8bcad3845c21aa4298b07057d4f086ddcffb254c4f42e86da704dac56a5031800fb89543d116c25b2ac4f42a5385898d4d5a6f256280608fe3b9e2375ce5167c138b3b71cb85a4547cc6dec8ecfb84e143210e8b06cc324c2d973bf9a2575ff3b3af90b7012c6ce1db2969b40768ea915815565faf033ca4c9166adea763649b0dca1ab76599bd006c2aec3caf998eb507bd46f5b1f1c36ef7aee90ff8b22daf6b645762add6250aaaf3a6b345a3ebb2930723684373f153b1c4cefea9aa03b676413eac30ee38d4c134d36a8fdbf5d7ad9e11a35f57299942f5453ffa6fbfbc7ad2420f89a809201546e43c4ffcffc6104cf5f2449873c8ca4ba22b10b7a8b45ddcc7970c29631b31420b9647f60a0520cd9cb111e218b1be827847053c1222c87598ed149fb8e1636b917e884b75b3cda613e86de86b253d03d99d26558ac11751e03e41bb72939497e65f65f726c63a8004f18a769eba47b61a739d3a1095bd354c586cd3f6453658da2b911b431cebc890a26b2745ebaca92720de18c6bf9070b3d9afdf98d6337e10d81ae99742c36c191a9f7afb5c4ee4187de12fb0a7826821297ec3dc843675d41832da87a924730d9694029b345a7748f779e15aef478cac6af737921824dcb012b6f9ed67e7aae49e838610774d33f4422112a6df4f3cff403493a1f1e487434f61b8b83baf6cfea7470a2188bd01a1541c5dcc0ad5d888ac0100ceacad159c6ca6a7f486915e3ba4262dc686d15c85d3e6b75be2a65cc3cc27a3e741d0fdd448527c9cb60fc6644e8e2c156c45f204b0ef8e975449f5b1a4983cc05f55fbc1309c238ccad80f1292de853361bba539004b3de706f73c30f6946d6b4e03f8c73018d7e3696573c2f29416dc83e1155828e76db4b20b6f462892f2875e2071833e34959dd507d469b2492168d62d0e8d2ff82dee2dd8c449094ecf926cc8346993bf9bc61f67240117829485c8971ef45ecabb7eac6cd26daaa37b4cac58141e38ab8b8705fb978dfd1c1d41664b4b81c1fcf4ed068477cf17bc182bc2b8de3f1a16f38e6fb76d92461695a5fd67ff581f06995a1e9f5a2eb2846673d6626601cdb46c0b541e9fa151b4493e4d74583126ddaf49eaddb4c1308a4e73cdec928bee94c1f889a20e9ef5aee141b89c0efda5a3f75c3b598f43893357c0dd6df18d4e62e6a04f77328e96d313a9868c8dadfe2ddf5413b9088527b491c4b782f02d73ac21fbbc62f9331d5b4f02f9d80f64432e331634b5df5028f3787b881d708bdd4703efdc810a1a08b2f7c8a85b099d1ce7de686a3741ac7f6dbc596e06ff288b95d2166eb4a334266edd8bc16eaae8964b249deeb1fef33ca78d5d0d59ddc9cd7bd99b6ccbf12f317ffd0a22ab91df977e555679f7ca48488cdc0fa71921ffb63e2ccf36908ee3f124c056d5fd6f4c4328fb152a480964c3a483f8b0ad3d8a738917004c1d10a85137709440b1e4aad05659872a6665491c811b0cff94c9c8ab4ff449649190256ddd9ba7ebb3b48d6a97ee5a84b4e172642e505d16e6ac81f29241a1eb353c07cbf353fd96bf656af5af0829aa19242102f4417add93705b734b6466c5d4c187dffa705597e3cfe62b1c6af3dd122306fd40256685f7933b40e3428b6433a0863cdda79badd241d1f5131f359a01c02b6df6ed166c3b2ceb298c3e21e17fed932678a4796d1111b39f96cd0b551ecd14fe6123252f7d4ed7fbe37886df674f7d772d138e0a26b979f83b91d9a59da2b44c45e69cb8f907daa71727c072eb0625e1d8cc6c47bde824c9d725bf0420b46eb9976476ffe45ee06e3f09ce949c3322989138e21ccd3dc7984a752cdedbbed02b465d3ba17b725752c9e3e86b9b94aaf93d873bb778f6829f4a23ac4690078cf8b368ff874c05b69b6a58d9d75b987cdb77c617b67ffc3bd36900e3c5aae3a168e64422c59f4e2206d00b851821bd98b40bbb9927607007c5e039ed3313643b27633349e05386ad7326975cdfc1da0eeb5aecf038975592655eb49ba4257c96a0527cf930dbcee9e78931d387a5437e8c4d4ff0e04b4aee891183ce2112a50afc81eceb31a5c7eb25d76945e23103ac369a40614cbb3a43995a956cd68dc584b44ab83c89b1220585ed86d27d53e15d2afb3e6658a2a05b36b97da99962141ef01d9ac503b9c69484227a8cd80cd6cbfb9cea9fa3294f9775e2cad63a75a5c0c24f0522085b14d6a620c8b63562c5d83c0cd4d087cc9f045d3b4db1e6e79ac9344de48a54763e0883a18d157a67b2bbb0c0ee5dd1d79ada0a74e7a153cfa0a381cb7545cd40b4bd1ed93e90421bab28f93ca5a45f7b23670342588372151b92fc657657f32e90ef77ea93d7801057fec4b481f807a4474320cb36605cf2a2eb78b9a68b4b4dc330bb9cd0a58657e5214cb59c1435712ec836a83236f85588f44602f89c4c11feee3c279b284dc03c925c2ecf5270e3b37c27ff56dd8535f008186f05aa843230ccb794ec430701bd33bcc9a30a59f192244c92af1e82e6bf22153a0641b73708f17fbe1ad24b39a9499d166ea658f57c10f075570df14c251aebb7b838835b0918e139904940d869279db68b65f54640e362254f3e33f00ebb03bc547955556ad74832e6649edaaa5033cc19d1148cf36cbc6362050ae01d6707f20e96ae53ca1c27fd4c310450d25d05549959806db0cc2172ce4a104e76063fa1c08d56d7d2449e37d52afe0f917c6e08d73153f6c3cd33bc0753564ec2d9481e6fc579c915841754b1eea700a2722271e48aec2427791605ebf55606e55362b3a683c1ca6cd9628f4c614e9fb319d634af569ae96882857bb9ebd8b4115dadf1117b4ed9d2c59ecc478f2526570db5efab59320433a3ca25016fc028de681b60108f3464f86f5d9f6b9381fa851f1c423e403457a01a7372c8c49c1f8076b6df0fde364cd4b018b1eef648be14e2b94fc22ce89b64e2d25ede5ca682db9b6349bd64fd87d11034fe419af0586ccbb384bbe58749a277bd4438817914529a0b402e19efc8685be154f5215838270ef989f64dba8d6710c7e7304afd7500fa13f1453982039c0569bcb080d395b76824f58c69c516a13772e989443d524ddee5d5dcf78dd17319207dc0cc7f64417f4f2558d4773d656a933fac4b2b1950bb32d91794093c9457bfbf1e591c3ba2409f0e10a220811e65cf96c39d8de891f9dd545cd7be1c5173a6f2ff431b6de8bd95390303d150a515cfe9ed9f6d1ca3e364e8db059a7e28391e8058c26e88d6a7966d4f52de52327785ab31a8d6843ec0111b8abc5cdd558838223c85c8267d9c0590c96a7e54d65a1b0d4c87f07d41fde8cf8dbb4343a674c222baee81f25f69eb1aa2abc5701d686e0a664f1c6b2fe85cdfaf1334317520ff18268cacc536f94240bbb70c2730d34a29c305172c4eb13525809441bae32123b90cf62ce8d4e926528dbeb46ae031772499c377a96782b58d023bcc53e66efd2c2f388cfb19c3e034083653e63d80285b46c991596675307bc5cb7706cfd51ca4fa423e052e5918880ca6609c5211b6bfa3e181e69aa3e5db954cb8018d6f096831e48760c108c2720657c14f74bf1c5782534045f96be8c8a8e4c7f56b74ba6c6df926e5abff63f9a4434fdbbd77a989d05e0662f60a6d981e262e2cb398fe246149e9dd5a94e4b180b6f75cc4a77a575f4002b80543f7f7fb86e431c14cc1f95bc6f42ba0beccec5eef92b2dd9dbeaa4c0becc9fb8e7cdd177e23d21d987201615df6b306d01a0ca90690e19bd559c2b4e30f0b9a182065fc71e5dbe1f8542ac4a7bd0375210ccffef34e23e7ee1797e742489b1e2873d89fe4d66d0d76c4b7ff4d4418a1fef36e730fa21e76d99504c3adf0c5ec0d7cacdf1ab84d41575477d4e923e2c96215a6d85c77707c2206450970fedd0b0a17ca06c211eab266132083b8c43ad03933f210499438e45d8454b1fdc4b854eb5894fee5faac63604c07280aeb872b4f0ec664d592050774c0353dc93707967310de28193b68bb1154799eb37f28d199505af3e959162255a6481278aa9383f6940cbaa6f4fd2bb0d6e06230f2207a1eb7d5f91c43824e99bb92018f3fe56a7e1e53981e2173dcc93f3d8401581a0594b1284938ec4ead61165c52967e9c80f6c1e2d4bc997565e2d9e249cfcb785a8dca77909db6e2e231ea27fd94d512cdedfa1066001f07cc4bd22caea4d6ae633113b3961761092878e35bf9209605ee6d0d6852b23b717ea1436db8d93afec11056134cdb83ebb109e9cce98f42eb690e6aa8ebb23cc2d9e64481ae3900ef19ac21208dfa3f6419768cf535490b36b0c713d040d96e1fc9e2368390a34baaae333f94e90e0ff7c7ba4e3ddf2534f61fa8af1e845935738bd6095a8803ff75580caaff5c8cf1e540b41af369131006f5f48b1013a5dd206e860e6537bbc35fc6ab827c000e46fe2cf5c6af5f4eda9a85cf772057baeec2e2aca16785850ed0e359512aa1e25fa3cd026b5c3eef1a89110a980aa5708f42e72c13903f278c3143a2d7f87f567ca1e7fb40b0a8aa68fbb7e184116d9053f483445c56221a9be17f73f501fec3785e86c8c75b677d483c613b370a459ac11829066d09ece0c22c3287a381f7b9abafd1c018afa361eb61a6b1ac1b21b229b2b01a2cf90a3c7a65ba726ccb207e20d9610320011d1b997f18dc63bc0281bf11e4dc3573510edf900f14eee1892b8f589adb71288f22be880501c2a5d0f185252bf0aec59b87a4438d4cddf350c5b16475ef82734b6a03ac3902dfb9c79e07c8f3bec53ce2acf73a566e739ceaddf0196b2458617543a0c99980dcd8c19ed49e07c36c639ad618b8b3d3f44634e964c978af285df8c912d909984b827297571f6937a1623c6d83f8f7cc7cf6490dd823a02bdf3593a0b6a587c469b1e7f6a4c296392f278632b54b1cb6de909f15f7e45da1866a28e5392542d9ce59b9374ff553fd7af5776b3ea0bcff35b2d65a9510bd91269ad38851b5bce6ea7a38d3fb0db944664292515282e85b05fdcabf0fa4849f878fcfe9be77fc65862bd0b04587483b38521256a7060f44cf75eacd01f377fc3250c38216714e24ebf03dc43bc04ebd5999a91808fcd9f21d6b34865e01c1b35dc2e0339d574670e4a9c9873aa1c28bd894af9b00b165257ca4178b796731b3c3c8163152ced0b7e885d3f87283ad0284611c9b60d731ab5a8b99bf7555317abf1becb5d03e498f90b41d50c1b1ce7ce7ecd971fe8554678bbf7008bb4ead6b4bdba9856f921438a454726d21c01a3fc86ecdd316a854a15bdf0834b1407362021cf941d8167f8654e7a9432ea272c009c3c76c5101186a7662f16a3724c868ba6692e016666c83af8fc2d423a0370f16c6c426f4f37fcbfa7cab1fcca20006d9a982f6cd449db555bb066b2a785c0f8478be62f94d38df7f01de34abf0a3eb208d6ed71c2e1a62ca37470289a2d54a8419827d5e7477bfe5b83d809be18a3529116d337efdb1cd1e89638c3de35b0efee2ae0957a072bb6bc4db8e1f6e39b84cc52b9d8ca646a69c42474c475793d49f2d4b932411dedff0b25aa02c10d5720f4e34eefd348fba02e2536a071d4cba1805dfd37f0d229fe0726d75d96ff47e4f4009f67d2c363e9138685e436e8514ee0f9f661871bc3f52686d55179ca417d36e69693a4dd1a701881bab4edd79ce1c51763285864d00b730474f880b1f642c2c93b582461c668493017a881ec120b6922009eb15c52fe65677ee3d5110d2e98596175727d427be9d6e6b63b4bbf3db2cabf6afe8023415a3d988715d8deb4bc4f32130ead91bbc6d0eb7e4d5882b9fc1d07bdf6f4fc46aff44743c7d45bff46c6668fecd996b52870bda0a47adadcfd57311568512972830b2a7763af3b4e8e9f0c5aca1063348bd59ee79f4009de46e75281437a4832744f2802fb94e462b9130a9315b70315228503388dc904976b0b7ada0d2f4e1a87e81713dd722e0c0a02bc82df5156a485bfe468dce9e7cf429ff1d37daf841282915fda248ebecc84e0904f45f179731a0e4a128b754f49f07973ca22003b32e8140513f63f87bb07392b66c4a3ab7fe96ae9844994f5f6217a586c7bae1c05376abb8f01e9ddedf4bd60a4a2a8005233d6cabde6b151e641873bc0165e1bc8e0ae8015a822fedbb5d0a81b2f0b92b8337b0c3477dad510df72459fc9e5acfbd0fcbd299dd31cef01ee35fc46bf42b75b66a4c9893f254d17db2ba6113e089278e4c05d60a2cb7352143a3b33b6f2562b30276d4457b0f08245c4381884be8f73db855b521f09b49663d9ecf891be393c72dbf34fae698a6e094070d266b6da594f88ffdcec1df478066a6155b08ea4a3631029fdfed8a5ac7bb878af868242282058b100c93c3b2ca6f83edd412ff9370beab5f2b34d53415b8086d6b96b6a9f0ff78445f05e072204b718111b3cbfe2c937782106fa71ba25125506420e1720f3e3a2313ca2a171001a94b8803eaed5e91e92e650b2058b5635bd5885efad62b6755f7686ebcecc811c090d7fa1e7ae72001bcbef0be7cbf50496bf475e9b0fe3ea9b421e95a25f91d41356b4179b195c7ae3e2ade650b644ccedd1444ee36d208050215e7bb24725ce82f417d829690a3351f44e8e6a8199a1cedfe1a2fafb437ee68aa8f3fcbfa2d08708bf1d0e80118c951c2dba8607d949c48288586fc4e0a436130084d6f97d7c6d22b70be013c8d17ee7835351202ac8cea7ae4c78d2096ba01be5ace292c61bdbe46d544cbfd499458156e0ebeebcb60acafc36a0ba80c04a301bc46fe0d3361f693d49137bad3a2ea72d246bd3f1d220f2865badb1d847de521e9e31d043c836a1e4612e45f146be8f20c42aa0deb766b2677152dc170962dc2e009c3464bf8f69d4dc7f21e50077959d3497b9d0f7fd2d692aa40eba1b63cef7ff71810fc8f79fc6236395b36f4de8a15d22efa74e492bd5dd66c01e8ecff7c7134c0fc120b1324f23446a3b83bcf1086680f43ac6f827a66562b7cccd93cfc68668fafe400ab6338e59bc0b8dc3b8788629dc703e1a19bcbc0ed1acbbf3882e4573b807ab559ba215996e047e6c3e6d1126fe38569081660ec0023c63b07d7c4897191a529fdf2c5d41f5b3053d094dfb80aa0b93792903234f4c46373be30137f03aadd888bbbd605dd5403514020dc3700ef3df39e291c9fe2422301cd01c3037d2577a7456ae4a546afa5eebebad2d7f8e606cd58373e483d1be21d48e4803e8eea7a9166f4a46329757c0e9a4021fe2fd0902c396abffa545a09fc68d7d5d8e798dec4e5e8013fee09ea98fcdf3c92c0283f14ef63f5ff23f426173d49c2e2330684e3f2da87584157b1b6e0203e29b7cd9fbd926a81c684fae20051c9db3dd669f291ac0bfe5ec760315acb2d55dbb87289117b9a95a038c549078f91752067c9bd928b44337b12d04f016c66affcb09b2fdddfc21744da654ed08a829f6a7a60b686a0237e40dec9384ad7ef18a31957e3183b7bdb305b5f7498ada400d0b80a2a3519ca3840aa69547ce78ca28637e82843c9ee43cef6cd5aeb789080871e7757f63a6bcc03e1a0fece844300df834dffa0de4bf99765fc4e1ebda91352e4888d218120fb7c700146d9de99b0352d4bbf3e3f739da1f7420bd95d70731141bab7179c7929bdc78d08cdfc9f60f16bb6d63d62f95c174908033e059895adfaae65380ba38f12e954e7d7c1ac4acd4f7a1f038f5502ddd806293fa96aebcf51b9701b45b664f185e014964c4c004085f8109971664e2a7a4a730854d0cc8cce163b7d50cf12453c49a86b845efeda4621ff63851582ebcbb7def1b78adc5773df09dc23e7fd73f093c257bb0af1ecabfd7b02edaa45b4e8d21ce14238146a46a9e6e139f67d8eb01bd4722a3c3b02c583e5c1e01f2b166eb1ff72ed166fff83873cf08fdc6aa5ac75e95949eb7fa45052e56e1cd49fd5cea78685c068c62e199bf56a4c34f0615e4fefc016e396d37d0fedb6889c21190fa9a92b8a48ac14592b9da00ae7a109299b04d3f8d54641d82951c913d93ff6c8c1d423088a8e42aff1a3d83f6683d07ad3470a29d0d9a896e6808bd68a04625bc0142233b43ce0fb4aaee0a6cccfbe2de12f60d1f3b8ce3ee70cccd29a980cac04ceaef119c12e79fdbd63a7e9022988c1a7948b707c399bcc8e4c9b9a8b46ba0cb0bb94675096c3d6f6cca0a8d301653eac68c8a8d8217ba67cd8d293bc686aba53606ca971edcb23ebfe61696210b27ead5a5fa2f991a9082bd8ddaa1a87007c954a9a5d5151e85fa7da2bfc577b12744165484a32c2824dd011797bbe85d19202655bc303e659a15c26c506d639e949f92a6dd47046b7a783e020f373ff3d61e1a6457c759cbb70e3b206b44a9501bc8a1a428b3128d729c1549e72fd5bff36f7a49eda42d92bb5feae3bec9b508e1d739d8efd6c13486d08703b05f6c30db754a66b4a45e2c3e2fd40b73c569f2979c3dfb971fae08fa14e2b1cf3dbc47a83cddc0aea77f2b2c4dcc3c4f99af2bd100e43e67a4fd4b719eb656c25ea1496e8854beffa97122cd3c69d930cf33c8e5665157ab1520b8e8e17e71adf8df55b60fa9f8880fb299d1dea26edb82295a7cae4bd5c724855dc8dc93fa4f00e6f8e7b0d02c802505780725bc4dce1100deefcfca883a8651534b4728fa347004991efa86495b6f8c1528aa910570c51756b9e1fc54c9598cd2190774e892c9d3f1b703ad40024f833f5319a5eda11f62948c0f0f9383394acec44d818ed59ad64cfc62e17de70b85fdf84775d47fb70424848b34e2bbf6593f3e6e321f87626dedcff01833c7c95b3f27b0425249f5a98c6dd597cf9bfd5ab6f6ef4b87de2e986fe49cb27f4e4f06fa3156f824fc274fefac3590cbe4bacfc65eab1167d506f4a24a8723873bd8b2be2ac0f17b601067567ad4bf23a67e700efcf5fc19875b14c78b0e8ba5695b8a761359217c67cc6d90273df0c70688bb27eb0ad79af947fb868a57b108cf1097e3d2231095de7c65c3ea7fb4aa5442d3524b568029b2cc52e884a9f52b1fe88c365b31815f443fcf76a481db304018d6b3e472f53d33f5bbd2dfb3c47e661fe774ae4d0a05c13821056f6c80aaf3d162755c707952d8763564f120d2a2de3e211aebcf8ccf0ce4c2ccb9dea0bb0b5835982a24b618229b5977404f88377ff8b35231ab5878d40f0c1854538929def8003d1cb617f5e69da7bba85d0efffc4b7f86db1313d2f1637c39b397f078f9c0f1b36ae290515aa56b94d94bf766e886aedb7131f991640d99fbc05fe6e94e2d6997ff7a68b73d662ef9b2ad34e17bdfa4ff00f7cf43d9bea33d07c2634f4d01316fda0e9450f159c0c42dc2bc58c9334af021a03a9f74a66e4dfd2ffd8f39353ce5028d2b396220054a208addeb6547460d69058c71a5a89431ab2e9056113e401a7565cba3557e2801aba216ae6c79a499383e2adf4c1a96e20869b87b21673e987bc33f18dd130972787cca9c4eaabd6d14aaf261e85470b5bf13885e55018784382f270175e6e3ae12060d633ab9922515ef1a2667a83fc14f897b63d847664fe596d4e55c9f7960283cec0ed35162163d8b9a5e4a8ba9a4f6c46178131d44cd1a9a1135a70331ab9369a1002a99d5ac01313bc0ecb39e85e759fe82cc632a262ff2e1194b2993be8875fca36d0716892f86c08ed5587682d056f9bdd8a4b25350c53969185a8113150e16b87ac375bbad83e4af2c0aa82b2e22d4f5c902cdc46c1ded7403506f34a54a13dfb95670087d01a14d10466b6d2bb7bb00a24ce0e0eeca962a210471804c2ba3891b2ae88d36dea5ef9bc37f15e9d91d26adf470624901c0e66484e158c2a34f126e7bf0eb51b82f49ba0d6620b05688903f383ee8c37bcdc51962eb6f4724bfb592988179525732f3b02a60c1da48baaae3b2c702f2efa531d5eca2ac3641d54495d53f2399fc7043f12ecea2ee433a3ea9930406a69731070d18bbb9b98f92587d34643ad46c7284e8607ad1b06e6a0fcc7b9ebfc3f1a3a6e1fd3be3810584656a277d1de47a180e66ebf77080cbe448fc7cec0aa7b9ecc79370faf21ec4cddbf63ead031b0ab6966b9640d8188bc27355c3a941ebbdb94079bd709e149bfac6f3de89398ab76515d5b63ba25348fb4b06e4378a11cbaa4e0ccd811dde97fb8accdf9ea40377fa1542a7768a0515bd4afe0be8c6de0c1b54d215851f14aa4c38d304c9a5ded5a7a394650e37050cb0fd26382686ff61496e919dd17072f177588eded98049cce47c7230a87ff5b94e063387caa82be58f994d1621fe902c04af19d056aeb078f59c53c515980e474811a94a51629ea1c448022906a395f80d3af32820d0d1bf741c3dd53ef67d3a8bf39ef63c65730998efd912a6900585ad6b5e0da43bcda8e184ba527388c2b0ece6e2fb7fef8d13c36c3fdcb954a8d339d308d9aee42bf57258259fcdec81973004b7a63dedcc123464df297570698a0b3bcde030a5ab17f4771e5e0b125d0e7ebf33a1ee7d7c0a824c0d1ab9fa3a63312192bcda6b466bea85554c70dfe718a03e128b8a6c55e0b2420a0238a08f698ebf4ab2d2c8d2ac85f68fdc6c3719e8071847bdc15c6f97d886ffe1438b689febe2bb2a60b932b76534c5ff7fec9f285b5d352c1860a959ac8255f03614d629d1c76cef31ef80a3f48bd636b18eb0e671a86afda40c1ba7a8558e7f3d11f204ea7e4246ef584cd7337fde0e3e4a2f08d82cd41d1e2bf853ecd2ac77e2ae88489df5f860b0a4b41aeb9034c3cb7b0495ab15741849f06548d5d5bdefaf2629c3f4abdded3ff2f4f1d77426dc522fcf7b7aafafc02239361d896625155b87461ba572c6432f98a6dd813c03ff685432567e0865bec92059a57cc8e5beca32ee62354f0794288a89c6abc81f787a77a7faef0ddd88ca4ccc840ac1a843cf5846b3a589c788190fb1f7e44c748aef8182ddf63c4d750f8125a48d41e108cf03f5f6f4e567b367ca2d22ed02e2b347c535fcfdbf5ec775400606760b0b6f74f7c2492eb0388be4caf5be336032ae9d0120793a6fff6eab157fd9a42241be67a634956ef79c676dd3d4fdf4ca4fc88c3d1c7920be8f6781c1a987d0fa69b98ca0c9ed1adc8af9b5ced4e89261fa30f9c9dba1de3e5ceab13c070e4beafb268c16a3a95c9dd8a3b30ed902669bb483c6e6671285e4c44a4a74d765cc9f28951bd62a831d0511d173744f296e652414ab858c467c5fb3a42cd4b3cc0c386d06ae004ae5ed2e41e34840b3ba51933051a3579baa7c5512f5c881c52ace6d1371b7951ae07be075777b760f62cc83d52e16474cbcff08c9e9276f18e15423005536f130079028429b2d0f1253314972c9ac6924b27b000b1a9779e86f8cc8674466a58360b4a2947edf4182fe43b091c7571df4c518b68417e4f154e957913f5a3d3c97fe8551f4cbba9452d790c77a02c0856eb9126c94f99309e4fd248c5d8b88f407c313129f94f9c5dd3bf6f2e4099e079599239693697a8a4f1c78e8194d946cf8e8c8862c046738acea1b8c2470eced5d5f06a23d2da6c8eb8e59658bfb1d46623b3e87d508684759126d428a939c5e7446bdbf865aed029df164b43c4dcb9ae48bc89bcf01bf82eb4f88590e7427a5a8b006d482804cb304c5600a46222303996993ed36ac7360122d0538e86d8a3156d0d7442e5817eae3a72fecf4f7a20089ebedb47d6e29bbbdf1064537829f2573427dfab98d8eaa161f5d3994ef938262a968df82bb1d1c139172af91dd25046091793bf1796a498ac3904f56dd0e33c8bdb2b8c4eac7686ae35aa9afac62dbc8a32ad47f32733a219e2a7aa8ac786e930619745ac125e53dd55c33c979dc24903e4bdf599e59eb606512ee4fd49d3eb39745e5212709966ad6cb69c57796f261b333e054016ee735390b839e6a57a649a36ba988bffcb8881c9e4a4c8d272673a4f4d41903328e05767c8dd2fbd5f7d840a8f30d9760737943b759f18230cdb569a95143ed88bb6a59f277beb726a746d407f84d51cdf7cdc8bf6aac1f1a41c6a3977c0b059593d6c8d11c7217efc7feb56d2849ab2aecf3639fde46a4b3fb1daae25ef2d84c72f997945aef4d113d62e319148f1554770a8b2aa8556f178a782b0e1455b0e69f088a226d83bdbe6a6bc36b8f08dadb328d191c326f79f24a5c979122f81fa4db7589e7ef2a5b37dc197443d90f3cbac851d03ac5b34a03c5963b99b51ee7ad282e129db390d449d06f95d99e26538fa68c8b98a1cd9b69dbecbc40cfdacb3f0cca29b6d5edc95dfd2ccc1e318f91d7af11cd35010d91bf8d1f314ff2ff64b957695a5e74126d09a46a25366b3300ce983bb373934557edc8fd4d45714f089a130208221993647df10830b4bf76c38ac049be218916567a88d452fdae54ffbc733bea4b42d0864de3e87c11cd8d047aefb0f3293c1207ca2fc9c016227fda11c4aa86c8d81474915f2a67efb1172446f8c4f9d1aa1b3d7c293192604e7a49c3ef5e977570e280ccd106672c2c7aa5abc1d2b15b26581510864f94e2e0fcb7dd866a42363511d32319cd1e383c0be55c82b72600a8c369f2da87e8238ac4f4c8186418d4eb6166b10668670bbcdd743d1e810882184442b9c8d38dda6e6fd852532b6849c4d42b1b32d88d403f17a54383cfcd6e65eab87f6373907d53e0f73eaaca3809d5f3215db09298a9aa823e16eed2e16eb196a04d5a789663aa5bc9ed602833c1a13a3d06969a659773e4cae1705d45299957b401aaa65ecb9a8cb79267a5ab2256d0d667747872edc57ccdac2891489fe75b930d602d8788d5c3b4fdedfcb227c3a2d4fe36a0b39fe603df1e3a3e3aacb057b212940635ce1660b1b3a26054a96b3e6bc142c92468d8f41ef138f5bbdf167cde3cfa21286a810a5887343b192a1f7364f582133fbee2bc386b5556f1f42d691986837c79f27415e1ac36cd19aa8584129824146c5d7c041b8ce091d2648a87c7572ddbbe55610544a82c6e2844d54ee7bacdc59b2fa7d3dc3d9c1fcb81dd4c73e73f5a5c483143ea0e87c03e391a9ff2ffd901626a2aa6356728d9b2719f65866485d03d56457fcdec5ef393e7d8f16b3b9212fb024bd55b6d1b644f6b3168512908e1b50c075a149110c5ff5e6500d25d5f64512f6f9d3186809594f08bbd560702b7a8c2cc74be59d5932d4f8d865d904b3d9239f4fba35441042a6f6e978e633a1500f8ceb801065225e4da52c85e84a91fa4adb3d8c672f3f8306026cb9d72ed2a7f201fde9cf8b9555875582f2e7d5ef28f37c56110cddc7e9bab307ae0661febece51655b8f6612027a0db10a50fc39d090889a038d394cae6fef4243693e9353df726f51c1da37cb3bebd7e6f5858437f66df31ca3042da1aefbeea6e331130ebddb9435188ea522311b85e6635b287875566be55574a0245293ee2b1f55a36cb206b19f5866933d26a7f3b68ba2fe8435e1993489b355662faa67c1e49b57ce5e371ea312631311d9e51be339850d5a2355011cd9fbe5935ce6742a930cbb507a6fcf9b5b2e2e1bf7f0684dc0a2b88bcc52f72a1418e307dbf5722d7494516bac66dd88d304ac1fe39e7f621790636961b2cb35c0882c0c514b96ab1373a9f2dfded895510f243fd2f9ad5199beddccc6d1adb9c49ccf4bc72685c65eaf883133302d7692391aa255b0832f9fa288f639909424c59c3c1979c61cf8bc5dfb03efaf821b29377bbdb0b70fc63a6bd988df5001915f2f145a1c630de88444e5c12fe073f7aee34427ed5e3be9be703f5d890cb9beeac504e9efa9212d97d9018e7358c17ea7bc3031288667681547ce996775eb5503d32edf62cd4f56e3d658ea170f7e97bf08584345f064439122fb8b201fd7e6db7be9e43a7b3b8efbb3cb5502cc7de6860adec4e1c15bd02050bd9307b848006bee3f9e27edf711b4036439635b19cf10325646e3472d67836430515be5e967201725e00b902a7c93921a65a806e64137e8a3b100b928156d341a18de3451534a6b7637129fbbb077066fb455b74a569f23b222f4950961ff1ad7b9825276f4af9022ce32070224b23eafb60d0d494ef628a9db74e2ee41f9fe464dfaf2916331990917381fd168dc2dcc04d839ef323e8a700eb621862532d3b81d535babd6c4bae23dae0d6f412e5e9765324b0416d6b73f5909111e0d3edf86422b7a51e5c709b02adef36ca50b9d5dee3d21354bc11febb448d9d02038acfb22add53507685542810621a5ce877b76956546d16ddd814604c2dc6bcaccff186a6a7acf50421b1336c4ed8db254b1d8b051b2cae50833823f5893ef3bd82f74596a68e484eb4fc903a949f59047404334771961a7a8549e361059e03449e759144509fec5cb9014ce2d2b92e90676eac5a3e8cf7663554e829b5b21878c6125213d19b733cca501771a3b2ddd0673870a882e3f835588bedfd8befcc0782f8bc88ab502c3428c6214210cc2976c62d28f95233f9c056f628f39b8238fb7b92afe9fbb68485f701e16559d9a31849f9b9eb8f399c0a34f1b010e1b105b02151f780d2b846732d65a7230333885a1e95308363743a2a5bf234f9a47a2a67a218f0da723c1b981c1569f737fdb5a0bd3442fe53f2fecebf9f145688e57a74417da40af87c2d452e37ecb3e883774fb30870ffdd0d6bd47014b4a0195fda91a44e21b2cca6765f78d2e528553831baa0e03bdaab7b3aca91cbeb562ef7de30e195d9d8b701786cbb0c2f3aceaaa78ac89a46b5c3ab91a91a0a0698a521d60ed09130426af810d389b3a77918d60dfed650bc98a37d48cef73288b75118e887e700818ca8d3bd920057dd1bb3937c433801ffb02e28459a44ba8787d39648c7aebf13260b118e7e2516192404757403b41d2732969ec51500032aa35dcc2d1634d104a471d18961af42a27ce32cf1e22bf04b015caca42ab066d955f7785d864128b95420b47a6833869ecfe8bee64481de508a4198dc0be6bdefe61af52c3c3c1cd8df0d52a9a44d533ba9d4551c00ccfb56300c206fb3912b60b573d6f4eee919494dcee36c7b6911e4f9993ca0e3298facf8af2ff5ff24c4c25e71f3faa2dfe4c850e40b831b221a2fa8e8799d04e74bd687225a437bfa409cd29614b59331b11a3f53cd23a5ea7d53bb9230c6c5932ce4f93d50be5fe414b54d07c38f2d0ec693d076137b8631695ccd9540b698993fe018d55e7f44ebb74f6f93626ac3d09d4c87d5e578ddddc23dfd537858a71426ddfc7dfa8b797b9bb39d0886bb12fd8f4dc8d499dac1cde7fbcc502d76bd7bfaff82ee4b2669150f12763fe3d53e38d0abc3826a92ca19bee9c2b1409d6e53f12b39d8c830540a704112374f94d9913ea4cbf0ffdec9bff9c5e98ee7ce03805ccf3f4fd315863c187fff496c219f9f665d7bb3886577a8b1901435028acedf72d6f5f21ff2333861af36a591bc34f444725c8e739d919b59b2a4f2256ed0626e3b058f23eba20a31f7adc557323e8a63787c457bb3c67b8e94c5ea3cfadf36fe6cb16eeba6e340b1d49def2c1278db820c2089dc1c98303be9d3ef5313ba274987dc4fcfef0666573d0d28336573a206a01c8eabec7524716acad60feed746e2bbe18b7f32e8cde249c76c115e24ed186c957cb452d4c68ae462b8b9b6a9e9441d2d5af033ef2f61a3d6471c06c1dd06723af7284b80985cf0b2ef2cf9742844fb84a5ff787487c91afe7f767bbe7c18a5182ef4f99784eea6e4b3291ebc4e104a8ca71a09e6e297d04d0208dc953008d743cece7121b60d63f15815ac7fab2dda6170c5784be28e93da6770b8e28c483794d6537cb586680cd91e646447972381b60d12b8d924133d21eeb9ffbfb5f7ad489113c3e0759aeb21c34bf370f3f034b5cff953cbbe533d3d5b780a35cc4dd1d53855f4cb68ef174113a4ae85bf69e1246ebae79fa9fc8fd33443b5bd09b2b6623fb4f27c52e7841c2aff86defb3f41aef7ccc48ed334999071047e080372f3844a680497448c5833aa69ea6e55bb8dd8d3ad7b55cc282fcda1e847483235494ebb099ee5d92dfac2dcab2865a6d49b61215b416c5c814ce4d481044b4eea47e5a0a56edac696c46b31fc08ac58e12556f43b779af83bf690f06e4f026a0533412417e241aa3dcc86f202131b679b188a51cecd18b78ed16604114ea8ca056331f7f96556d40cac94928bf47a20800d85218072d83d8fef8acf3edc8d68acf8d9b59aadae4a8ce2369c00c9a86f342a87b8d26195e73a30684d68e9c25da4bade565808ae06c73bdb551ef0c4cf932fe1833dd6a3fc5fb67619727a81db88f24633921a5a5895ae786e495f6c0769262fb98f9b6bda626688230fdfe2a2a85fcdf91c1d4710f06beca78462c3417f1999cd7b536cc724ca482fa42bdc0d6a5a55c8755f5b367914e61a73dbe966c94f9debcd31b39673f6106fb0b5d012d2ed0eda893d2d628ceda2c14ccd2e38e9d898e0037db928697a3169e8dd057188aebaa89a5b498b523ffdbaafb995eecde49d5866d708b1f785ce9e048ba2188c1ffdb67bf44337332d9c4373e55200eba2b5a59948127f250047e2f6d1c3dcbd2d15631a79057b650452c7c9744afb85ff539c011ec4bde030be29922dabe596880bce8fdae453e2ca7a256d95d602cc18bd32def8c8689a48294605a2c1767c20f8332fca9f15a7f635cd001e505176b81aa28bdc16e65910854177b0cef3aa8b5b77a8d3b0968b1b16ace08c3963106d036c01c241b0f70d07c2742f2ed88f0c4a01f01650221aa93c63084a9d88a2f36aed1b58e3169253a9b84ad7ca96f43189accb811b8aafb15dfd14def96f14bc98831cf7dc03e441dab8d7c4f16fa16807ddd06a31af28af6fc5b18355781375c6ccd1bf55b5335778d534229520be1a297f10c27f6ff1db50f4a1a45fd3be69ed0a6cab7ced89f42529bda1037858cdfd6f532e5fc08d8c26385e0da8452a7d815bb401a1a7f506e119b551491f5d9ef337def14e8a5dc4f034dde31d12acf7c637eb63f845467f428de28c99225aeab6159cb9f886471e656ab6ede01ad6857916093c988bbc7c7c91a15d9219fa2feb3c77ad3122495e2eaed34a73f092d7f4ba5da427930fa5cb10dee54494abdd3fafbea4d9201cf8e91cf87ed398e104d26f8c57e7af1b90f9cbee1d3b3946d7497286a0c29ffd5b32bcbf14d4918765c629823c54020e8cb28c2126ac28d99421d8eb0fff75eb8e995b7f78127111988314150102fb89f9d29a5ebe0c52ab629b71eddacc24e5044f869c01938a3729f762258f69a800e75ec68911407ee2469b4dd385c9942f35d1209ccbf083e1c5fe61cf3ada7a8f072e82b9b4b2a91624dbbd005d6454d7fb887b57c3bbe2bd400b9f63e3a70ddef8b86ab5354384739296ca3d04eff42de759006c2f476909ba9a31ae9a10adf1c9e86828b98bba0e60d2e98a287c2053c25f399e2291886219391f895001e5d0b8faba481ab8fd55cd6ef9477efaa30d2c9c82a6eacd23bbd9d348d210db680babb5965f46eaa92fd91b123a441e81510846938440b3f043fd5c59b47e3f0973b7d16fcfcd1f52fe4da420a75aeb96bdeba770a409f25a20a8df6bd3b75387e9530f3d16ad1f68cbdb3bbd609801662af8fed0a9534eb6931c20f6650c4d027d1df2be166d76c97dc287afdd7277b8bf4f4db7a9cf63ad73275e40516464f97707405c003ad6b3e8f9a822a333afbbf7bb079dd22a0d62bf35f33418aed1d44774241fe0b00dd7f7b95cd96655a5bcbfcfaa4ad0847391c49f424c03ee70da2d825442219a0c6f4f5ec1b19ced768f6bad1816787f7e7d9df33903f18ee0dd379afe61e7829a03ee227d136b9b34d73d791c8c2b18745ccceace1ef2fb33925df74cf0c35a01a805e1da0849f39ce0be9875a2716b74c24e8c4f9083ce2e40d6a8c79fc744c5854ef1a61cb92d10ecf6fb46c983d83d48a3836a0d006c5c1d94bb580230d6fb0059c9e0c597857729895a15ebe63d134bba8a9b2a30c46a49d68c2a8bda1492000a4c94ad8593029bb2316b495fa5aae169183a6c03929afcf0bf05b5fc1ea133cc2dfb60bb40bbc2e77fcd5f1dc138540ff76cd474ab617f98c4b906bee3723bf578df26cdfbde641d4be3ae7bdca2c8764a98b1cd6e25a3e0891782412ebbcd53619281596aced082811e33aaeff613f4b495fcd9e9c1e74c26694c0060f03494b9183e51f12a4464097af3b3e07e958159a50b7a0af8e2caf67b7021ce968bdfd120b42e781314ef2b804d051e9ba77aa7399ad6c9403127e4c78ce362532a76b850810c997537b2965ff775d742f8be3825a95655f5b06a3b3361e4e5b49030400ae6fa0565bf2db0e60165fc11d5b827ab85f385889774e23d8860ca171f4366d92f33ae2a62e536553743e5569d8771e4d53170402dd3c5b2e6a5cd313fda0cfaee08d34dfeea1cbfff22b5f097d4d377ef5fff55b8694a33af0498fdf49feb04ebf7b803df2b56f0f2fe8e2cf15e53b713a55e0be75944f13be1b0045a2049089c088e572cad060b8a82e6f6e6027c846a47e273d86d46f8ada053da611577c5c1ae340a4cc605d404fe6c0a92a6552458946597c6c1785d50bf0690af422c77c31ff18254ce4220317952ea0aae7465fe4f39709f8559b52df8b55be8064566a3b4a31e6bbefa29c1b5db825f4eecd45cf48490252c4d09dc1e7e09a1dd314860a71b7988b200cc6f798ac64caffc6cc814a78077b5f925e4141bb1a96622a944f50c8882e4c045d453c06eb1115576e6af8c16c6ef430e2d9872b37a7cae8b2ebcc37b62ad313765c5307e34fb98049e1aade16160933703402ee59a92e45713069f3ab9a25725fa4cc39ad90cd0d5d8e370d65ece03ce7f90f28232e06fcbfa804343c7780860421e2031509ac4f3b022a11b5b80cf9075a3c61be445a11a7dfe0c92bbf341295975f3ff6e330b4c89be1b82a88a3430a49465e07b14a9a2202fc5a8859b4bb05320fabbd039397f52cf361073d7ede594ec06cc5e22e5092d66a242e7bf9668d785fcf26a34706753825918e979cbbacc5aeba2ebbb64ff4067510ae1941e74f5be91bf37d51d7f9702440cfef9ef8a63424660fe399f96cd0dfb3590b2049b579901da763d1f46bb1896abd32ce06a031b19d2cf6b8ccebfbcf3800aff4120630796ad6939e47797cc200f694f8ef564df5f3a7f04404e9fab3c5aeb4ebe8b76938039c88d7de7185be33b0bf9c69e15b251d890376e521bfefee9bf7d980f56a56ab741b1c4fde33eedf83037523400a4de62a2645fe369a32e35067928539c91fbda4ef5d2b3840d45c0987920f1b85aeb25a47c27e04ebe833dde3a16c86f3ef95ec5aa11f2f9067748e563fbda078f2b22483e6e322df80634dd5905beffb8420f0b1cbe384a8e984439313cc75d6b9f4df37219d987d16562cfd549cd69608175088c9fc59ffd62667b28279688c16ecb0f5297a65deede595ae1fd68e1da6f8d27c765091e56741cc407a49ca802fd2237b7232500c806f50f941d61721a015858be1bd0d7afe7457f03f91166f64ef7a79af6269be9ea366c014e64a70e6ffe3e5ed5b8bc339f6f65cc410043ad35b88203f68e2e09e7527ed1898e45a71e9b1fd22d6ce0a0916924e8c51c4070fd2e503966b02c03cd13e08e19aac17758e145aea83257bf68bcdb994ce8948c0bb8a9eafa1c6e8c757e8f085bdebbc28d1ad083f546df4a6d54762ee69b77bfae6c2577f2b93aced1d5a3a867de497c984968c812f8fa8635068fe072ce0b1c41814cb2cb780a8d3c19d322fa2e11295920f1e620a1f9dec75f79966ad1b18dc58533e1d991e20d533caca2a7d40bc16c11e9a43b1fb13f49e05a98ee276d996be432b3b51cae3614af8632c818bb81889992e4e7f74dca46583d8874167e674d6e1fb6b3d3d430d18f66b95920447e7ff336d5d3ed80b8ffa8f7f502c097304914b39bdd00b759564a720e3162217c1c3771127d582c0b97439fc6ea2b9d6265e8677e12e42930e7fb7b92cd686ef3e2f94a1a4c84322764c494b396e8b608ba6b0377a6e0d6504dc4e0bc90d959dba6f9012d7e8e83a94c6257c199e67e5b6f9de0bc97fea8b671e93ae83aaa3088afb035ebc4f7a7def83fcb69de3f9add8b62e115204ccc2bb303af36be86fd1c050fc10ec17f1cbfdea9d0ee7502cf668e55403fe9c57de2b7920769f80fa48dfadb7c3e3784b8737b39801b743aa26c408d533048a608c90e8519399105062914e35446626ca188ef62ef650aa0f10cd7efc94854e2a205e55877b1f862c3cf6753e164a73417f7086a2e81e6c5fb1dcd5b080f22b4a58f7eb7ef10bcebe4a084afc210a7ed693bab77aa2be3aca5af77b44b84bfff1c81dcfcb2139b66d3890e60c03dd23e2fabb46c3f612b0bf91f2861f87504660ef746e862ffa2ed91fec685c56c89ea9c521f1c42aec5faff2ef7a871e50d913996b75118876565c71b6a48d9b835ffa5e5db0a9c57cbec0f48babb661bf4d599d31b46a39e443be1e9cc0dfb15bdd16122f4276aa01cf59be55ce65c97454334104988ec47334a880730ce4dcfc849cf6c15e33e97033c158724dcbb0fbbf24b60e721aea3926ab00d0320f69218ba32fb5243c2ac70e760f4740d7e09b34196c9291dcb6dfae22175dd4bf1e8b79df72db3b9d7fb263917bc9c4103dd80303f57c971168ae23a5ee2d48c6efadfc329c045520b63cc9d226928de03d61d7448293978c1d05f6491a5598a1a28edbcd11e473e44202b0c33f309418c7165ee57adebe0b295de8e362f313f58ffc996fcaa06b0582800349e552e774a4952ac3f13c9dce08de915f2ea08457b5dcb31cc64d2969555de0ef80989badd60ef7176513166cfdb646649714dacbcd6f2c462c54c36521f330fb92873aca87710a71c8e64e04a2798505eedaffb2866dd999c85c52aa0c88ec568bea512523841760e8195e09621186ddf83c6ff3f4e88db8dc74730d1033d8fe090c3b35d54389bc83f7a899121dd27409d621864a6ad9cbfd8e38ea9d4cd4713ac473896235e9aae5e4db787c566c9b62c2c2fd11ae6d655a7991ab5436afe2da336c45a8ea4117a8b19d8edee3612d2f5d9728aa199b630aa5f9fd73b6075db3fc70ad8e47780cb56a46c405ae41f73723fcb4a511ad095433ff02f4f3b1d257a24313a79272055e95f983245a0bf3080cf8789e893c83eae0596ad724cc7a5e1a0f9ee31135ff60588fed9c9d667915d5482d53bbab1df2c8c136853e01120f7d0667f9e289ac99d5f5d8d4dd0e9c94ad9fdf5cf9bccff7d49d0b36327c464fa3ac89ae29f63d6247100cdc6d8f3584a1165419fea726520008a1041cb7214f03223031d99a82039221ef8fdb0f03bfc2f9bf297b6c3f9b621fb763b4541628df17a1beba218a1986f5a59c2531ef8c3a837b67df1300f4331e39b26eb75662632999eb9e45cdbf3159f794405a97883404e1a7c095486652e545c7542d7f948a3e6ce75f17ec6a76be330b27dc6ef85acc378f2fb5f064b7717d7268c40c9a285276deff54339db1303ac5ae40756cae2a4fb05a999388209b2b0c0fef2c06290f6b14554a2c1a805e9a81aeb8ca8095045d7494bb1864b86205485a387a8e2f273a99f8a9e0b30938f3743329dd20c12e8d4751ec8192b567c7a47a62cc87b38176a22bf60c126c6b2872de4c5a6f2b3bce61baf7f8197e0598b0c331a69f32874b94d85f25582c7f909959b1ace6cabc35ad459e241d86e389e7b71cf4e97358c81fa3a40d79266006e7c4807749b4a6088e2d7a3203df39a679b6ea1d46ed530d5e482bac38c2e36f4d4055014106cbbe0a766456b973defb51968ccac69924b383c07f8490c0b0299dacf54efad1fe20f9a7e417967640fa6d61a33ae3b9c7c92baa79d573ef045122214638b6dd5edbb751f551f5141be6b8978bf8f80cc05606ea9e2fe5321474106a3b5cb8d9385cbe2484b100e6eb08c1160c2d962b68218b861d08f009114d7e5f120fd1d5c9197ffe97a41f822a4599d79fa9cf5deaf250aca38c44efa5ea6b91598c2d92e3fb171a0fad61025dd3c9a9332b35759dca7c56162e5b31840a255820d793ac0181fe5568d6a45498ef410548b9cb92a202bd310158c7c73f09711b24d4296c5cbc8ee078b775c2ea92b9b3d58c147a27b9b693ff8c970114b4aa86dd182e9dcadd60806af31337afcdbf389519da5186138b719f9134e073412d39d6fca82831a93aea31f540d767b5c5dcab80ca402b659d8e300c4414ea80fe265bc83868dce3964945e70b6b600b142cf4d2c46c156dfed1da6644b139e5b59418e6629a0565affe3b207b4b9002756744095ff421d7dfadc0b301ee706a71e6e0890b1f4886c87609d8794c6501fb5fc1b3e3acacf7f4ebf50836d2e154e56e81f0de851fbc240b0d8e013518c20dc485b1cb339a844c249fa363e1c6a04301f7e474cc2468ef5f9a9dbc67ebfaa4473fcab5832f341443ab6e1e42cd6526408eb3ba7887c3edc0818cce9b86728fee316662088acc1f35af8fdf3a0480c8222f5c738a897480ab7fdaec306e6c3a44cc8027923beec21134b5bcdd9c38828afd94f933fe1faa951e5c86a2a6f6e47e908cbda213f07fd12bb22136a8a2bdaadc96e3aead047a30250f646ee291ece405e20b850303900267c9543cfea91a6f18fc3d461aea9661535d9bc43801ef5feef85894f017c4d567521508704c18c4a9e2eca4f7162298ff2dbf70263158db93a31171e852996fafb3a52b2b211db6ec177bf196489704a0b3380aa5be3a12f5d65702f577f60b300571430a3b3f93fb3e62b457bab04d7d15aa8e5ef900362bbba4a3168de33f0972e0d0ce3650b9625c1e5adfd4ea790c06d2ed46b43e289f20fe1e6944b5af9df8c09c43d95677388459453e0bbc4bf5dbcb3f7d52ca61eb5a83254ec28119e19bd0ae8cdb0cc8f0369a9f69da99b08d8549a77c4233e2dda0ba73b8b628d1dfb7b65dafe727571c63a0bd9dcf940270add89051e76c63feae840ca8adba770a7713100d70584462e42cd65e5e283e4ddb65a81028d3e56970e2e0f4adc621774a13dc2138153fdb66dd66d853c223bc2bbe07d3908faf04f1f20a6fbd3c7b21eabc2f8a3771c481f16a8a530f6ede23542ec9391c71a106b8b2371eef86cd2f4070bc62994dc5ab96e833e624639c0b82612617ccd91a0bd13c0dddef0c432ed9040007a0c0a717fabbd4c8ba483efa98841b1d89ff13d3f9edf08e64dc3bc8617a025e8ff2da514b49200cf4258cb0670421ef5bce0afdda797bce532ef04bdec98dd9c0d6975a28d00b37a6e864e2afc8a954a8c8ecee51d41e0d08b6fecb6dfe76d22394ed129c61cef996e2aad661e1369c0d84dab2a279289d680305c9fab29e447a33fe57b7104d40a772d2acb69b54295e36bcb28a463babee3c837043d7d18f22c275d4fffb2b0b2e92ea2704bdd3a69f237b8fd4439a9b5709125735f863ce885fa05662a8296e2bb7d0986a5dd3bb8ec67f6c4f09a4745eb49e0e82eedda41e96bb071cdcbca420844d2ca840f1056581bfc55e6c05457194f1041faa35c64ae90e8394cfba6e10c71377c03d9183c1d6d5dbb5418d84c208387ea72575341faf139cf6e955d6d37c799bda88ee871b90a3fb21880cd6fa5686f9790238fe6ffc166eb487bbe90fd7011ba56223883dae9b6d1a8eea8dc533f182470d2c5c156e99c0804e4a3c935872822731a18a34e1fc7072fa11a1f09d88283bae2603e7991075820a5d4f7c22160732b7626aeee5f30afc730076aa0b2f38e53f6c328e98c1a947d9f293c756e1cc58b04742c740a90e12fd86f147ea1ef1c3b8eb74f054ade4aee461ef1d0e2fbaee60ed592987fd6120cd418bd24e165107e919b9067322d33d6a0d9afa0d6835c2c4831c0bd88c0e241b10ce266108b91db5a6a6f9ec1ebbdeb2c9dfb6c73aae3071071f2821067018ee00692782ae8de1f51073b7a6190828edf0446644ec42d72dcce4ae041aafccb75b61b53beedc2e5c2b9ab4dfa5cb22ff9bf4fb435c65af5e2909149e8f61f1599535e68dde7f05bfbc654347ad8993f62f404f77dd9a307f8acfd422f6e59fb8ec0b13fe93f1ed3dc2a945d39d30e6be0eacbc5f33ccb7561dede3706f799b197da4bdd1f61fca77b7855c114f34c3274ce994effd6167248754781de02e25e1efe1dc5810837734a1d508c9e352afa07a0fbfbdf73373822031ba4f12934f8e826bce83c1c9aaafc1e4fb9d3f1d11df8f77a7c34251a0f51bd916c7582994f601a38f6f5c2f22cd0c04029d91c50052ee19e9255c49614e7809e4176728739cf9498681ebff95f538b3fcb643a689e84dcb54261af33148657a18280214f7adc57ad9c7e02d9b61b5c2f2aa9430e670275b5490acdbc20aaabe088a480276a84150bc731a8a63727d0173a58a85c11edd88fa7b75832f85be829b26616c8c2f4b0327e5409ba4a8d689bb23b06280f66585ae7eccf26f1a2644f90b26fb4706e9909cb57295884fc233d187b795a4f3338e1b289bd23196006a7e4dd06eb4d49d2be8053aa9a458f1540d50f002d43e62dc3251e709afbc36b18943d71f6d966a3a6d3013a96f38b30d994f601484a5944e42451c7744b1fd167eb1241ee83a55ae38751bb7a19a84a841d263d4ce76b098c34de6469a75dc0ef2c37214689b6825eac4b598820f6546ea4174381187e3cb5afda660196a11bf002626d7e97bbdfc2e4b8231aebd4aa5d9142f82bcc94eadd2fc74d53a2e78e02583c656e59b46387f24b1d8807e8f1cee5b22d4d4dc404121646d474d5e01711ba051ccc2de28e70188bc760b718c4bbc90b74a100da3c8e0dcb4e7fbd2234564a360ccdf73478eb5f5adeb2c51c0554039c8eb31011b8a3b1afe3583857ee0b534be2fb2063f9a3712bc063228a821919b4ce6bc55b1966b0f7fde83b77f7d7899d820642306b00b1831c4fe0186f462768437f97d4fa3c70e4b1fb834ac6188947e96e519a171f14af7a876281ecc33b12df61ebff86ead196c37043115986d328206723df419f77057972785c2fef110c5d0c5d8d642e6c34cd0601a3a3ec262809839063648eef80badd190db47048ba905d6b2bd2572983afc043e2f86401e537751d8081b2a97056d7087af81ed6e1b0b080fe401566ba7ffc393cb1c8d06177f9a4d5b495c5226b5866042c8eb13dc6fa00156c9dd52ec1ae2432e00b9dbe605612c2bd962067e2d803256726ed1ded0607123d5a7e66701601f7a9e1e6cac1bbf57e3a5905e1c7b90bddead7bbbcb3e15b219be5dc0cf644bed62247d8ea208e90f27a012a2f87449eb98c36de47b2ec6e2971598cceab04220a601496db59cc222efbe4016ef43e4e5a8a581cc469194d357045a9adc4cc0384b738eaacb18100e420e230ec02a8e23d0ef53a9979f64f0ff273b62c4abf1d9f4fc6493ada9104b7d79063b3569126ac7d2a0ac3048dc9b08bed1012e0f7b68719c11bff233d7acedb885a304790433d032e675125615396de5d8b20a191a673f3673c06f786666a1e52d8a880c168e4be1b97243272b6f430879f9dd875aae4e7edf57706b79a53bc346300f61c5ae37f78564bd63be795f1a8fb4fab91a71b2d66f1d07680fcfc98d40585e8e323463b0cb182f07939c7272c836b229cadf1a7d212df9496abe409013efe2bf3a16fe7d7ccd36af9651f0cc000dd079eb984ec8009a6804e11fb17be55bff3ba53bff3dc91afe6345fff03f52569a791c01023b4314995bb3c4cdf678e5b497775d1fca5b81e54ee5123669a11ed0be43b0d07f2a9d805e68f83884484ab70617bc999d29781c3bb289e9b9d28e903480cab0452b009dbd79643271b3cafd3a2b109803ed23d2042dfe42a49c58bc1304af06e0c9187e998939c3d0e92ea15264477f5c6ccc66d990f8d74face478ddc1e22b63244e8a1bae160a1ce01d010e7ef5fb9319e60b6d5ca82555db966a0d0edd9864ad19caf3f96f65a00e74942c291edc947575c1eaeb02517d872827c7c8027d3663dc0905983462096b7f82dacc7519e98869f0baf71800919de328ef4de4b02c7f5186c508d1afca3c1f5b65d3bdb034298d9a239912c9df052659dad509e07624259a917b21bd1312ebebbd2595e01841e68c0330d8db914ef2233dd0f49fa037d70df0380dd6146b7b326428a70594a10f988c9685c2c6fd7aed1ca22aecea35a13ae1024c20d5a69e077b8a7df3c5c2dab4c548fd935c580af108dadb7f88747f5f903cabf8267718ed75b74e76569bac7932174457468ca4d9043a74599abba75d0481e0f888dde6beb0f6bd41a15a2384f9a724cab61e342414e9314264be643a00abb606471c0091365794dbbecd2272fa66ce0bf38246a760caa7c93d3b4f731dac4bcd35e8f4674336abaade333d162bc29e2f3f2519807f8ec2ad88c4844f484ca3ba016dc1e383c18381b7c3c3a5df29e6b71c372daf7cadd59301badf1f7cc48c8a8325eeb51d3546de6d396b51c850601d4e1a9d8616f6e526a2f0bf36da5a9b23b68689d5433f7eca94c336b71b22329df54bbc99af5643f1df1b7374d2f4ceab37cbbceda4602a83d6bb29ef1abe9125384ad9899d7de4c7d5bb840c471a9c1824174cdd5c0cb000dc53aa4721159424eba4c9a5ac9511fb3a719e37711f6902871f62ec51c2dc41214c1d0c04f0b6d0de117480b7fec66f55f4a9bf9f8dd24b3a90f17b1e3c7bf71ff461a8c16dcb96c05462e88b8d9f76daa290da09c54962b29b6151fb443658310569c5aa64728fecbf95e244c9f86a77b45d5ac67ea3fefea98a3d29562d5ae172da373d298746ab8bfab0af62c43b93f88a806ac715dfb72d0364c6c63a37d97ab6c42c6d20834c4b318c67bb56ebb2f55f8cb335fb9724f48332f97db7f2598500a02f0aa52662d65896460fe0ea7d766698734852fbef581e88122258f696890728729da935414710a9d0a7855ed9d068cfac25c912a405043f1c8a517de02207f22974eaab2ff006c5e217ed1353fcab65a848819804622783737c91ee1f37a2f9dd467ef5f6387fd513d397d3c0ecc5317da42b76077ca573229568eccfb150dc2cba060ac88bb8b6ff65c4ab7a43978c5ba01160c585840d34c17b2bb300068a1c8408780a301efa7f8bd192160fe8c908b3162235ca26a071d910489be48c5bc7cc7272f5a9f7761f4cef03f06e091d66b60e2d6828327d0c2384c603e8f247b07361ea10f9b6ec29ffa8bffbc4627c941b898d32f9ea11de2d99ff9242d5c885e76cdf6c09e452cbacd1ff62f648dbcfcf4fce29b6705a466fbe11b1b71b21272452b2b9488a4ba762b76764d1e61500e89e54218b7d43543a554b788600200f802c2d9400a23e3850f4e7b7fcd898be197af4df34bff35325ab74bbbc2009e61a1e3d0e05c6634ba744655ba0bfa09c91669fafe00e5df43c3c7fe8837a73848a827a1bf16abac68bb46301d1b17be8c152948d42e425221a84b63d1910e3e58f24a69b39350ad84c4e3e8e979c0ecc4f08afe1d350d2a8e8c4b11ec0a13191afe287d6cc591ae44071759b8bac06212d9fd6f303ff7c40aae7a2a78a2692f477169a652a0311c0678dcfb0186743b0c69e3b637f44c14b5e8978982a2583c39bdbb852364e3d3a23652920a65ca368600781b3dc30813ab3b0ed49aa5f11face91c08d58bf32d69a502294da5a071fc95ab8199873a2aeba39e43823f134e388209ae4e31ba371e79e93fa4dd768e15c59b4d390e798ed643e405edbe020edfb03c5e541949a0176f14b2d6c519beb22411f4cad5669723196368edca3cc7009224a0ed420242fef631dd5fd54fd9117832a37a95ac2791835ea5e7c210fe7580fe200f5c6b81620e70aecb7cac5d51badd6a810a77d45726788f902631991b97448e55639514bbce489135359460d4efd7491ef3d7c31cfef9361a0c17592c8c0bb64eeb7b0773bb1f49ee7acde52973cd57893b12318220a943330f2cb28003e58248802a5589756e18850e053cd67121e48b3bb334a11369d84960b3f7fab6b584895ef3763630feb2e481d946c631ffae89c3c54f25d73de8087bea896530a1d44f974a2411bf0b3a4809e49257b760081bc82e49bfd3aa1bb67160f4832bec30cb0cdb9ab115b90063f999783b8a7bc9ba5be973923c24557207df26709eac9f1b6a3ed452a96c5fe5c5561f1d8c786ea60a0f5b706fd1af7f03d5d5bd0aaf3860c1a7de7fce35106e94c5b38b3ac4c1967d3135a260de07839bb320210bffe0ada0c0a066ac0bf391181dd405fa813430d2cbfbee3830194855ccd3ad5a1f9c36615185a341801df021be7d0986c75e508443c46516e1257f4f368d26de760690898885d00ed0f71777b309cb2ee3ba79f2a30b085a63ee6b328e7645eabad7dbd3959c775c91d0fbcd5268fd80cae0a6710a8226dc90cc847c66f9e81880df2c389f179ba21baf5081e1017a6f72cb43610d25f36ad8d32dfe297a533bdc966e74d880049211a038ccc6474a99f1fe333f28df2ce4f259ffa6e3aa84f3c34295d2d51a41180cbd682db640b99bc49a8fb65204c3afa02de9744e796d484e6e95ce768a0134c6e336a08958024540c3ac767c2a9ba35f17482641990ebf228d6ef4a40017c275577dec7da01d696ea89fc2711b7bb7be1f71f1dd542297b238dc6e6217d30bb5314a6097ca52524a9a900715d760ddd8410b4ff2495c6fa4963c91c7564c01e78169d221cf952c64b1653ae5a46d4ee97a73e977a76801fab1fb17dba6db4146d806add212b87f2b8867f5a881c65242ad450611b39d48ee64c732cfcfed3cf3897409087f3f348c76bb61768f3c13a1f96cb5053e69dad9297fdd959c297df8002a0e021ff5799f24ac2f7a7c5a7ae0de0324878ad774ca1858a886e974ca6188435532e8978d044c669a2b965781e62f6b5994df51875a3a8a386d434c6894334186364ea2a4bf2c95601a659188dc292efd3055be5f2060e1065fee1320ad39f9dcf7f803f4a2875ffdce85a62826c5e3c4459ae355b28a328777e31d78f1d0b654ce033a5649e412a6a515deb4a19f43e7ff5cf29abe0f3350942a8ca9cc58cea208db18e48a07e900f68d747d688c065ca3364c6dd6ffc6a704e26c987bc2dca16956e59878722ac3a3f53e1dedb1cdee4ffe7369533109838cb32e9a701b99d1dae412782790baed9831a7412ecb6472c3ccc002ec75082a0e22a612abd7dbbe1c133d53d6bacaa0a7b81333591f3faf5cd20ec96feb3a0cd591291b9f0cd6d5e5b81780f2866bd78272a8fe7d3a8f166d40c097365af760d183ae8e4a7621ca6006803fae06bdc81a52d0e70abba313b1a5d40d692471b45b21125732498cd36efe7e8f8b1391538cf3258d6eaa9120baffca76d8b2c460969763b57674e110fbaf4856f7791d7c78e3131ecff67aa64e60ad94404084e4ad95c4d71de8b7fabf1b389381a250d7b99f29af5bf2727aebd31e2be1f0b1c2462dd0db3a20b1998f1d409ce1a15334cfced132be0a5a73a8e08f35d43752efb21072d6720af7b8e2cb8c64620852e1a31b2fafa2c2b3964c31344bc94e7bb23239b42d4cea514bd028d4248eb5f8c2e5621f263b08e75b62680225c4a5f032f857fa1807c5db90fd0a71ff2311c78683df6ff6fefd34040f317af0a16ace124bbb61be9d49648af37aacb9da3c2af852a90bcb4d72c383b1d8eb02b901369f77dd97b19b6c7cafdd0488ed19cf537b79a0b078f9ca5b9baa8c6d29ffaacbe65e1d439893d02e640482b0901c1afc48393b9b1e581d444330ca2893028db489c0edb8fe564417283859122b7d20b8dfc3faa7f1fee80d3cba49c7d2b09592ea5d112db36ae1d4e6d8abdffcf7e304047b89d0e951a5e595d6065ac427452b02c5a3518dc52ed9268fd5580f67596bd2c3512075badc168014aec086d6d38f8e6f300330cfb34bfb9f54fa85d631c1f6b3dede8230f70655434dd880f990a9d2a4c5851c26bebca8847f88b013ccd68c6e40bf8c62a67c599a106bf075b7e4f525238b447437194b8bf06d2814618c305a71ce5c29982da709c3a48e489f06484688cab0fee17cfbfebee8dbdfaeac9ae55f2d6d6fe242cb7df78da1500d8d9f99c1f769f6fe9a99d6adf20d5efe3925357cc9c3cf2b04530d35a25fa65e9586090f43e92bd5441b765d1914aca7b833b2d4da5f62bd88e9ed393a88378d2833f6f224f057040c3e37ba611c6784ec9154204544fa33dad097cc5e748c221b9f7ff9f6edbfde6b3ed22d4bc8c13d5575cfeb624ed0db4deed8878dfd72b55213bb8bf3c3823295faeedecee512a2cee2160c3be7ddf3f9ea04d01f096acb29de9b8ace90e8c8932afe2d0ebe97e341bd2161b23b4b8d2bf2b14c136f54d20c0e168159e3190462c1bc82cda740a2cbcf13641617713748223e0349f554acb3723bed0c70fab319c0232ec768947114265cb9318f1387e158d6e844be22136479e76f569903cf33ca79a2b719bd669ec235d6c2035ce89c82cd32341c3a3629e781d290ad71299244e1a3b4feb5c917aa788735a2e30e282cf1dd5acded54f092217f89decb9bf94b1e84cf19d30d98f39ac82baab7c825f7000db4f7dc8a482fe28413e753e6d88d7afd481218f8e57df81013b749aad946d055e815a78a2ed5e8f6b19e04fcaf6358f1398ee298ec3cb5c649a663e6970515ac626b16a3d329d00f3348781b8668b2ed506ff42dd2d2b7a4290d84d39f91c45a31de1b68068df42136007d200db9c991be0ef70f930c6b2e34b795d4b72a9c41927e4816171627162fd8e97e23e0bb375c1ffc86471b0db081ef4ea3d9b32752267ab6b8c25d0e6bacb2ddda76005345baaf3e93a053ba3dd5dfff423a1072ba3f9703b525f384ee24f5b19caf672d18ccd19cba25526818209e725b446571394ce77d30ad9f93f7871dbdfd7a08b1672277fdbf616de9cb73b458bda1b5133294b7805213d6bdc119aa7b732d3c9b9ecc0d4a68ca1d061eb02f2634f7afa7b05751af3eb056b1992ababd75ed9bbb04bd31b22222398f5a8944779113e20deb9c2253ed78aeac187f7de5f3f429dfcbb2a70de4fc007dc5900a9cc5b3b0032e01dd7288bc2247962f9a3065bc88f44ba3e3164959f6f576a3722ac68a9fdccc1697f25031298c5a08ea469d7730f03d3665a77dc432831146de3de052417df3bf08291c1b5dfbc100102eb7a13f5c00e0ec4e2e4b4d5dd0de7ff5c30ac1c83ab8a20442ae5db75dcdd41e84de2511cef75a8716f29de0f91f088d28ee0c708213cecbdc7254cf1ffaffbf1b54726c235017c5dfdd5968299dd570d3c67088b696d039a3ffbad8853d35cd5245552cd1e8a9851fdbe019ac81b9313de7c7e15cf85bd8d385f75f425d1b014cc213ac677b4c6f74620353cbd2f7ab9e60e3e2b3f9a1e19ff5869898128b639e10115e9dd219f032126fa30d11211a930587f52ec9748528da208df3b58807bf1022fb2f8004f8bd3196dc1f312c9d21132d5ac73fbed09d198d83b989361113f00172ac9a77cb029b94cb5596bdcef87234a62fc0dec4f789df3c41a744d6c723872b025c54c313430713b1fd70a15d679db85944f182629a67fab933864c9d7784260e57808edfeb8e9ef30f1c8437ff8d4e49131613e2f05e9a6aebdd7927d2b133ad5fc38b1741bfdd5c027f90f850569ed1fbe35873d00ccf8ebc4e026dc7beae6102af57ca0433300b45e84cacd7f705ce12f6a5baf8968566b52e95e0b1c6c6654b7a068c86aeda552bed86147aa90ff3aba67e813537b770b471c49b29d2dae67675046e08d212f6b889039180522bfe7a96be8bff0273eb15d4b85b104d17b24c40197355b99e0665efc23a4662d5745cbcf2e90fd439b749b111af54241f45ae374590f0b6184ee104f3569be268277d847fbead83fdc973f4313180894d2dd43431e9a08979c25f185b753ca7fa5d4d2ea8118f83e584ccfd677019f8dab0cd8e629da573c7b631ab12e1f842932d6cbb9a474154800decab19886eb2ae93177d1f870cdb3f7f631e8b1d4a830e136f610ba1422f37d364fe6ce4e288396cc7fe350713f27fa6cdb1cc7c874c3e8ab9198c0da4af8887f62f33933969754b03c5d9a706368a67de1d13c7279750f413c02884349e44d9b05e907ee982e5c5e362b8bbe661cded781cda9b89e90ab1f6cd348d113b5be591ef46eb1d876999e770cf5d0769f449ac687f7d0c9b91d6eaa4a17ec36935bdafb8a57184b4c0d0627811d077135b918e60969b75e6008827b0416388da43d47c6286318fa55e36a12d405532d994f3ea14287399b954a3bb941f5c8f02bf876de5db870588223d18647fc3143d4b381bf98258483c4f9fe39d658a1b5f502eea69dae2fa06916994320d4b562450b233103708bca124065c9feb98c066e3f2426d20b137a0ea0e181a2a5d553ecbac1d448ac9e9e7bfdc655c6f09ab545d35f222d0b26931747d4197ff50f5967f6617949958d9c3a69257e3a7a19c61954569e02451e91dd34a4688291e1bd2bac9217d702d966bf5433d6f95a7f85f810ed044d32585c43e226381a07d4b7a2cff468641fd4dd2cd0bd1b7301709873027f3c243bce2be152033832178897443a476a0cad92337c8b711201cb289724995cf3070000aed9c47352e2b00d4d1190b4d4205b8ce6670cfdc8c4be75bae778e58c9bc0173af3bc458321c5571f70cdcaac409bced61a3372a370df9828530223a7fa27fa823dd239ef04e3b4a1cdef8de9f67c18abe486983f91bced84156e60a44271c2eb3c79524d4611d8e0a2a5f0c38495deb7d61aab87d6191bc6146ef710d5cb9b69e9c937e74eae2ec3c1cd83429c655d3a5e7b64e1f928283f00f13bc773c7807889323a1833b2c888072c6e075c21bc4f9a3b1c6c6ece7845d73518b6b88662b70cf545476616e930bfe2be2be7389432af407fbcdc7b8a9758ae0fdba1f48e9956638b7445ef3a10375cee2b177f982564656962476dcc1c45dd3efff860d08be31c5b627b05f4538ea1458bd07f83e9e9dbec70deca7b8beffa440911ce91c6470981219c250e5d23c94812a869812bf5f24d45980108b79b504949999e99d9b1d79ef286e8766ca4f0a63d866f7dd0646fc0843ffb5d6f5a44eafb8f013df8501821d27db4f9b7257f072f161ff93c6455842ef1624b233f3b247fb7ae2349ff368d2e50eb50060ae08cc48206ed8a31a4035c9530cfcf451407902d499eb144c09005212af88e8dc1a0ced24eec1b5cbe7ef8f2b725e65507182fb01a6f338fb568050adb282873fc6d21b930f1057e6108bd0599d7fca0ee21af4ee2f93a62e42c79ec714851320c0213225b09b157d8392c5b4422418a048378b36cd63fbb1e578c71719885a2ca8fa086914317ea287cd69e6f13a32f52fc59f1df707771ebee460fb24634d2e4a511d81992fc112cf2e1fba79695d27d634640b90c2943d424179cd2481263addcd9ca32aac03390ced9df6b6d97da398bfb76f635552c24de1a51c21b5334b5365f6feec4aafc786c035e2225db6f40415d6cff3e6ed62ba36dd57b7e3c4c0f80f9925ce838157d037a7b47a53befbcebca1973562ed16d634f8e4f9b975eae7fff0b68850c37d8453f0c2994fc4efd82edad2fbe86da68b50d463dea26fb5b4840d8ac40b73cb13dcbd0dad481a607360b3d31d9e29b3fa732416a244753837f1061e042e4c341437b04fcedfd021f7f595034672920b892dd0178503523603774871729f8f8dcbee81e9085eeca8144e97a64d14ccec63e6c0c954303b821e6f8d0385cc00f0b635e468ab4008caa531060f8b11b850633fb1786d6f7bfb13ebcab0ea8b9ea4807d522bf558b84ebd55e179e33e7fca5dcd4b84a97ee8bfc648373a279a9c8d61b3620eff368fd2afda40347e4f6ead0065e0d46d7c6a55eae8f7d649fa965420ddf1d852633ebefafdd5cfceac2e486b2acafa30290a3fca8c51ee06573e7a0ef87a62d544601bee8b4b73467486f3671392b26c2154a2c681c44f00371cad0ccfc72742afb42ac2fa599f8e7bc62043e63af80d886d802c96a98a05563993da32fa643db532f9d6aa06b1cd45effe3fff3c2861306525cb17dad2b40060ac8c5e351abe7d8fc176ad1c7278afa9aeb393afe8485bc55bd1babd767f1b222e2e6470bafc57dfb14e9fede623aab15210e1ef24cceca6fce66735c2520e86f91cd060df5b84be20c9f90ab687461b96d471ca7a84ffc9bbb989c4dbad560367b53c6a6addf69163e24bbb281027c7d53a0c7a9566f970e090e15247edb693d326c85566a285faa0333027afc2694fd7231a7dc0f94dfda1edd790dddd42736ff958f7bd8bf527f541ec393c5a64fc946cdc2f5a7c746b893e8f698323d56b43bbc1ad60cd4b5897e161f4fcb7ff944c6a056710e4cb5b7c435d1abecb9b992affc46a7da01a6ea4b9bf1bd983e689d699b48d3e91060fbd73ff69e2738a431fd4c7dbeb81392756f34e91e672e62a848e5ef6d5bbcf18e753c336c013c4a7293216f3e3905527f3b00a70c46380ebd307b74d1791bc4319b5d30f46df41ab2a2c64afcc8474359f7f71fad85b31e3b7abd7e1f1726f3e8cc05aa9114f5aded3adb8646b71bb7cc4d57d589ae12762472139620098f365d09d49a7ba9859afe78dfc2633c8f3ef45dd0765b015b46fdcd347394be71a566f4a31cda52e8a7ca4816c22ab41156855ec1375b0f41860c876b492d9f948840fe0e31dc262081c6d3b5c1a1f0981bb22c29ba364f7d60c6c38db2beaf1c828dc0875c31aed30f75be8448dedb6384ae836dc1baa9d2a6814280dd41b8b0850a35ca229ed898f794d79f18696f8e1fbcee021d28ee4b439dac9e2b1d3973bc72cf242b75f1b63eb36e5b3125d7d27ac1a6f0fc3cff9a3eda9f9a1f3b57cdcbd3be51e47d20e5db2bb40e12da77bd261bf348fe584c8c2821e1e51e40e325696f7be6b20a4b8cf5000bcea0748507c27ab2f32d4f2ca942935fbbf9f91cb94d00824b909177391e8678958f6e47b3d1fdea6aa4c476d150367e207791137a43151acd69e329fee979247c637be493e66bb702e48a89bfdcc6921376f68bec654101296d0c5075666e06b4dcbb0821f133045b2eb80ca637f7ab7d0a4021c0d7aadc27732bb3a250ef18ee5138467f94343d931a268d3a0bef72846572b1a33d90fe37c3eb9e4af4523005114ad8949423892eb35ee800c13e89f9323caf024fd6452310913b2dd8b202e4ba47521675669149e02298c295f45f5e0e7779333bf5db3a44e96f9caf4e6c7063e73c417fc349f39e12e99c2b29fb3f44afcdfa312bba2ca096c4599de99f5e5ad2a474d4945415db70f506f39c581e09a1ff4dccea008bd4f80807d0539cd697fcaeaeb22d6a0b78182619e2a68df15008a74c61381bcce0bea0b3da332c480404d5b45187538d8015a8d11f5e5be36585a860903153d9f01dc4f028a56d431c0f0ff719b9aef76851c254b1edd8c4c2512ec1f92cac3e7c0a6595dba2a4f3f0b4cee1d24590fabfd9488fb6468443d053b1d15c1ae35f6a948fd26e3e0550f1c6d3a733469f080dbe8e3bd7218137bf6fa1f315800eb308d3f1dbec7a3d73ddced8ac393130daa514de948a799ebbe21a61b39d45d96c744d1a29521d9af10ca5668ffe640767a5b73a91b7a243bd7dddf062b75764bdde084de3f64f9728f658a3914f50b29bfdbe67abfc3c42f297e0ffe7fabc5af21258ea04c5b3668c7362ccad052e150678c584013b8d274278f9d917262496cdb0f03a5abdc6eeaedfb9eab432c8d9c354fbaaee60c0b9ca3eaa05ce2facf73d584bae89c2647deaf309e92f61fc9e07e6dbb0125b45fa871ac74f772a066bf26f8e4a662a810c5f0a0f0029071593eccae35ec2ebf77ed65dcbefbe95f721b3f2a9129adc84d44017f86ee12f6b9817af355d4b3bcc238a4249252e1ff4c780cffc0deb9c5224fbf3f3cd5700362db57f75e1faf9e9c986f235eae737ddfd385060b12af32d42b8f35daf44532407950605caec7c8ff40fe58dc360f37dcd84a8f455896cee7a3a4104891408310be000f8efe23fdb9647082f1cdebb864cba982cd7e33c6f44848ca2a4eacdc2aa519721eca79d701082f8cf0883ce3d644a8417c061067957acdfd4f6539214f2bc2ce3baddc7e1b9f41d97f4e07a3ac00b364beb2a68f6221e0f5c347296da8687f94fa9d4eb0dd0f77cfe0c6ca1fad0664e5b1165962263c9b0bc3d16c09bee04f7a200b2dbd8a7ac2aed9c4f35494e7a8a9eed9b007600fc78261ab018383b535dc7f31ee1ff83c1d5742685044ed81df9f627effb2704022a7a5f2c2ca51bf7d7b6ffbc81ea4bb8b1d0bc7fdddf79ff75fc11245b3032dda40cdfd56df70349b1ae64f4a74aea2dad5c3843eb1a5ec48aad8b393f82b9398f28898d4dd1b507b46e6a0da41b38a6fcfcef45b819495d570f96f20c9ee30322547449e6990054d71bea4fbf11bdd220a18faaab215096d476238afcbbd945835451a7811417a8c2d567cff7c390b90cd5f7e619f561f6f7a0d4f587afe07e78b81f50c44c6c212ce379f1ce7663a4130b8d1fd3a45bbf964b99f57d463cbfa70fc064c964dbac1c9bf5c6d4f7895faab47cfbaaee3ad582296ac5ad454a6311e463298075552c1ae28cde35229c306c21cad1b104ad9f23977dae5a58ea5c6bdd5ede96e97cf8d51c70ce2837503f092b1234767a855ae117461a0d058740af9a9c04e0bba1a03b58a563e8d65bfade3f24cbc8b774b5677fcab7ba15b89545956221f2618760cac89935f604f6d04c87d7c5d0cf508fe270d824cdfc5f229bb46cffb318e8e88143fbf6dd4d59b67ecec0a82801abf1de456e7eca679c2f735ec8ffc4524080fd6315ad75fc884af2d3cbcf92e1e0c77655c9b8fb4e6dedbe00f2ace6eead70c1e88ec41c2b692809510409b10ab2d0affd56abb151c9e7d31fbed3b0fdbd12a5b960073441039ebcbbf6c29b008c1f90ced7eb4e3cb50ae1a4f38a7369b0e5c8d931527f1d5e9040f88233edfc901bba5c5e63fc055bae27662b62f617fe5f11b2e764c99542d0ee0284601db30f79fec23e4f4767cdcb725deaeb93009c61dbbbd952a73fa2666237a51d86d0233d5190b0a408bc2034b070582658d1041f0f99ff33b978850db5aade7a0d94c44e5e387162d219ee34a16070bc757bdbcb598720633efb236a7f251a7e3db05f127b57a8b1b88913c00ac3bfde07e7dba210b79c706e0651e86290577a468eb007638922c5a12bdaba5c66c7d07183b8de0ef59f3ce97425996238438d98893b5bac550ecd9bba63d6a3b7728bcfe3147e652f51a5a7fa593cbff24878b25d1dbf9c2bb2b956b83e4318ee71e330cc0f954d8c3750ab1c70fa3bbaf75c1fea47c1d5624b84172e57ee9a3182c47406d2f123081f4f127928b18ef03d46084179072552ceffbddb9fdf4a0b77e67b6418d0f7e727cd696fd3682788f6e8da46b43538187453dfaa8e6609579a20b9f184f456332faa84c3e290f1835ed460189b31dcf064fdafb0fd5e92734731ae318a43f27464af8b9323ffdf22ec8055d7343e94211f9e71c352236dd7974d8a2403b2a530bc55f3be5e098a2eeb9e378db4a312120fb0aaf6d08362c04be3e17da3b89373ee2161c9ca8994b5acc4615138855010e27b17d2148af37db0ea1d67651670957f64e4ad7d3ba8a8e3f0287d0850f0e92b308be4338bf51081ceb046aeac69a561040cc481db8d531d450e45ad7ad9eb13a96a55f30d2b8bcb2a8fe9731bf82f82314fe5dbf8c246ea9145bca1d292169594b649ad61db0b40591a727e01f71a716b814f8af453ab81d47f9c9cb112b5e7a191d6b9fa45b097809eb094038b1c6110b980f01cada7a86629c50385032c3157668412b63d2b8b8139164d23c983370d6c2ec4577334ac3ffe2546a17b386b56882579c66f7459adcdf1c4a345c1856ab27509e501c5d6855bbf6472c293969d7fe88524a2f0c33505d68656f0b5f86a3d54c832aa8c8c1840e4fa0d45e948522ce91c3132714057a5f44d2a1505225b092c53fc4775a2972ef61cb0ecd99c102830fbe43ac1287bfcdb138e270d414f732ee3498557488a496982f5ca1f3278a4f9b2ed8305d70c31db53453845212677597a394d317ee5efaa462809c9c9c5d585f0acc1d159bd181bba36052b08bc582d56a49170825e42b0d1524e5c6920eee2928967228bd31978eb83b39e69b52143732164b76133e1a1fa57fdbf97789bffc77dfafb729547f4edf6a2b12cdb9f87ed78ab65bc321ba7a0d7d20ce8bae5a2a90b6c09c43599ae2cc54f4bb96e25415fdfe6bd1ef439b3fc9675f2a6d592c8d035f20cda15f7d4b957eca4c417025538139900a08e2c8e88a8a0ab4b792a3fd9af8301c0bc2f95fd0bb9abb4ae2d36ed07d32290ae8dfd6f815e504d7fb35bda591cfd616fe63bd6d3d5b49b4b2b8d32ab375e4423af746e3f1d9dae1ee1328fa61166529029dae284b3fa15664555820e3eeb5ef33ad5e4ba96ebd7e6e86907ea4106d5b29141cb04ea1ba15949394f44e694ae977ad98f14e887ee093ef830d81f4e670786d0e6718fdac7e2be6fa2048f7acc421bdfa6da5377f71ce6e9653abe11b9c7f57269b5baf1faa2d05415010adf32703da016817a4ddfdc6dd63983f647eb4d57c23fd063a8efce890b18ae61edcf7ca7d661465c812f7195a24b2806361a6fa0c3803ce20994112471c271d9c74f0d9ca19b68995824347403f45413f43525c4a54a8e0a729869ca4f0936b0e20e5ee65f85963f226898184618af89ac2836d01e1e5ca103f2041d3df27d6f2620d8254dbb186c3af637987e887db3d8eea3063dacedd71ce43650b397cf4bb0ad59276991462ccc2cde16b84757d29b5db6a09b570347c74da2955419a2ab8a1820754c04bd7227d2002fccbb977d16fbf2862dadad8b57f72f8e815c34c012985957b129bf7b57e652a7183894ed00774fe70edda9cb98456863893315022c63ddf9ec4afb1a8f5d356983d57582cd405664f6af7389e2ddc1d67f738550a07f79eb96382bb8bf0824f9dd7e449eda8e14e5974d70f778f4ba1e60e169d31fa9998f49739dc7081eb200011ee272e2610857a2a0b4f61e00b8f0418c0031411e804d584e58e5241acfbd6dc33599b8ffeafb9cf84a153709f6923b428264b94b8a37a7eacd77da6c81dc583dad119693a77541277d4974f647ca372dc51abd30b50402141e1dcb8a35437a1ade455a259123fec438ca4ff89f6c37e63178e868f76c6625582e512a867debcdcb7ae64f822495a1cec081cee6ebb36fca7e1fca2f3881394f5c4e7111d771f02348d68601ab172ea22635d41961e7f5bca53b5fdd1b6ae72ef82a30669783185a83187c860bf96edd75ab65fcbf66bd97e2d93edd7b2fdfab56cbf4c9651eea930ee5e372e65906921dc5d86b74c88cedd41d7425610a212f2011bfe5f93e12d0380cf205db8bb166ddd1fcafe6b3348933baedd205fdc5d16c4871964f7b819e4c85deb1765417c76ee1e82cf20d47d028183b4372d9b40ac7077205f6ebade26101ddc43dfcd64409cb80351e97d5f86310442e37a9c3fdac0b56b7f60e1de847f8869f387107afed85e770de78f97bbfb787e5cc639d9fc21e447ca3519d7d3c7163e7d34e1bbcadcbdc6a70f2372d04c1fafe9c3c7dda78f0f9ce21d5620ef429b2508a1e4dbf97672c48a223273841a82a238aaab042375e4cf7e58d1c360bb12a84837f4422f0605dd27938272ef22c75c14fe33d997d2e2a1e2ee477c8e1073a7ac1a133947a8f1215bdb23dadde9e961e1ee1fd6e919c0c9727a37d7b5cfd383e2d3ebe134e3da9c47645c0b45f8c02a56c02a746505bce95ab4adfdbe5dcdd516fd9ec9962bd5566b4b3f5ad534db21fae9b2d2cf385575ff733ff4ab75ccb8a6a988cb3feaa15892ab5ce99b9f1b6ddb5cd694ee32ac54db5d65207d0245a8557325c39aeb7dfa55ca64e9ae74b5ba856526a9a6d9fcb666ab5ff41bb75d5901c12a4c6ff30ea23961d5422d51ac766705fc1bad0669b0cab79b519a4ea21f08562b5a5df9536996e95ad66dd14f147f6852ddb05ad26fbc0413c2413347cdfdd3f913ed2e45bb4b164b27f19982c21f8bd5388c63b715b6c8311725ed8b83f44d02fab75ad73ebfc20f75785b2e3148e7c7edc83afee72cc2b7d9eaeca5b4c03f02e9ae53e8f7391431b9d2b408dde159e9505b9d512a8a3b3463aa63e9b5f27d1f5df5d0150f5ded5401a9f651c2f3ede8e8f0f0e432a4e1834a98d8ea4c14411c954cdb0f47b5dfc662695b05022da86d7596a345bbcb24607e1087b34351d0d5f1c39121a156705554f4c9136a6587a2407155569ad26cde3fe2b765bce93862dac5368816a1df4ec4b98d2f5e699cdb7477c35dc35b3f3b448bd0fc4fd25dfeae61962cc78eaf6554afc2b7f452bd6d9de5aa6f424bef8fce366b5b9de11db634d5b2af26be68ebdeb43257209056aa7fe8a76d754635ee5a91bae867abb3fb43b7b6474d69dc400dbfc1163700e394aee8ae9cb16e0572175fdc90e081004cac11866f10e1fe4611a12f8684c6280a14ef8c37add6d54eb4e4f7ed6a6e776b8977b45620fa51f94162b198ec94f533939d92ead725d5761ceb57c3303ff98138aa1a4681f28078479b9de0b36445a29ffe6cf81bbb70fe17b40eef5bd8c6ae8d5d1bbb76557ca1704914ed86851548015e5cb0b3010e3068000ab761e3071b367cb06143179474ba325382cedf1a4eb85316aedd96ec37beb230ac32d9877fb190fec161090b776f14dab084d9c860c86520c4dd7595e1b07c5de2b0d4315000d387c3128622418d2eee78c976edc3e0e88b3484b8adce3ed7b04c76ad6c97e496344eb0b51573b4adce60b0f2f0752993e1300d1fdc1d8d34c2d7e19f0470033265d4914cd3174300992ceedf14fad15dc9bc408692d12153e34eab2f20e3ee37dafeda0bac98d9c18c0ee0c881cd19709c71858e9d33c23380ce706263c6171b33846ccc406263c607333898b9c11ba717d8a006346494e1eece43918422262b4d467ba6219e20a306f719378a66dac051e9fc25e961a2e9f4b63d4c234d271b23021f886fb486a9ad89658de24db5ed56102477fb54820bb8b86aae2f1b3186701b317c44b106edab1f0bfd60b1b0a1a07d377609e1da9d016d5ab0450e0ddc9d66a64cf8abfd5a0fd980d102f7274e4aaaebb6b3276b7807e50b8d21d018814c143e4c4010a42bf0c361b2a3aa5fce8f76d75d71541f4581f2f480babcc52858bfdbecc3d93d4e4577ba71a5773a9cc559bd4ae15572c96432d98e14433cc6543086ebfc859feb4d872e88b95f000c369acc2f8c98628cc0fd6fae309ec8373088705918868dbb0b71c1670bb8ec7294e92a8a55a6ab0c0c19dcbf9f8dbf5b23deb7de5e32d94e7f2ec97d7f0c655fdc402041003e788c0080106a6cc604c0e7181d9f639ef81c53e4734c0c3ec7c8e0730c103ec77cf139a6c9e79814f81cb3039f4d3b7c3609f1d9b4e3130a263ea1e0c1671390cfa696cfa6187c365df1d994f3d99483cf26217c3625e1b369033e9bacf0d90486cfa618f86c8ac3e7140020724388101682d078b042510da8ac30a6e0756bc54092e08e282b50f90906dadeb6ceb43ad226a0ae8e275027144757c71392c8a012edd368122a03b802322a109a5e7c31bdd04d2f62985eace033406c4e6546e023f80205028a87bb0352f072d739096a48aa0719147cf150169a315190729dbf94073eeea91e3f5b8dbf4f49eef964d4459328da2ae5b4c46e46f7ebd56a0afd7e76ed0f507ea6d7b17ddfd26e68613024fd1b7371f176658b189430b1583c4c2c96256bce240102dc6fcebd2b6937a39fdeba8ab39f2f6fd1ae722e0e3399b36b2f5a24fb774868ae35aa35cead2a4d443f7a6f7b77c55ae2ec549adaae75d55c5f22c62fa550e8ee3229b4f5250227864450c331bdaffd8ce8a8402b61f4db61e9ecd01adec938477f97227e9d9d15de9666f75710d4da664c8ef606526c77cd3978e77ca1a537394cf091b86e6bf38774278ad5eaa7d9f2f58f28d6fc4c43b352ff8daec812671bfdb4d5235e812085329be527f1d656d7dcbe25fd44223f56dbb5384d84d630255fb45f921889e2189092ae22edee4f7831104e5b291bbb3676e5a4fc389a35dad8855dbf3776dd1ac4548bb0d0fda39d3896a38d61d77eec9a52f4e0ee40dbbe5c452176817897528e7415c92300822770dc5d026e801b54b041318117499b6338166211469638b350d63c14be766f84a4df6eddbb60b76da7ec5cf7d6bdabe6219e1e251c0bdfa63326aa9968ebdea5776f145e6c330e0a6ae19a7ebd70ac08696351ebbfbfeb91bead8dc5f0df157eb875effa5ad55749efde48877f1f0bce445bdba31c76e99bae452fbd75efaab7d512ebc6b1af555858bfe8957fd77e6a1ed2adcfb5bca4f5d6bdeb8d3226ca5ff3d01f6951fcd9bd91b6a28b59096322033bb8fbcc800beefee92ad2a7a9edda550dd3515791e877b3d91bddedfd994c4ad272d14fa8457e3c3d54972249b350eb66fc6d2f9e95faa3595d8168e0c619a96869b7c434b1da19ddadec8feef5b64466a52632840d6350a3a4ddde76ebb1ba3676856f7b22ecd27da877b722cd4ad8c6ae8d5d4219138971051419e084c82a2ae8244b518cbc42990e25561c01468a390125dcfd96434ab8c0fd4b05befcf005cb97c341a258653b07184934f9c6a2b6f84a6865bfeb9689a2bdd1747594f902582c520bc5f6c366120f9849284d249c8040988904f83a851081363c0263dc3d0cab9e95ff352bdbaf65fbb54c142d2eacb36b4b197e4a0c784db985d7300180c8dd842325a8a0dbf09aed81d7ec16bc66fbe035bb025eb34fe0353b075e5302f19a72c76b4a2a5e531e6004252e80281ec2f600f090e10c77285bdc6336b812b2478a841e59683443c06ac414f9707713aa38a104cfdd5d1566053ab846e5ee0e8405108ab8d3079ca065b66b334ddbb101272b7eb89fbca8c2e711eebb5bb1f8d5ddcc1d85863b8a8ce78e8ae26846061cedb258e1df5cd2873477d40bdc516744b14203ba107d8b6b86d1fdc5f0de6b6703741ae0ee930146306005f79c19375066cc14c5608404dc5d57c7eb53e2a8bef0c3655c7347e5a0881a14b1338b28c3bd88298ac0c02ca2745ae4d2f963b1f402b6dbca996ee120a98a409a43bff081409a93310b04690e888383a42aa22ba09b0aa4ac8abb560c6a01896a4a5dcc47ee8afccb24c2892b614a2292a39559b2ca6429984141026c70af371cc3e32385bf6d38b4450b148ae24ff8afdc87ff8962fd4050ac3844c25bd668497624911912d5fd0199c831fae55aa358539a6dc617db67ca960868eb7ab4757ddd5678876e2b57228c63e11d4a12c53ac2308e85ad4ad6a0fc4c493929b44044fa628b5d4238b60b2b1e1fe9b65eb755cb4baeda10d3bbea6c8bf86124c6aefcf7b60cf0863b5947bcdd6740300d90330008840d063022b3627d2944e14f20b6f804c2e70f6ab8bb53d67731dd1ad3eccde7f4eba32f865676f14aa746bf21a21f18186af2dfc8e6ea48e4cb27e2c30c3ee0e8c9cba8ff14474e081b660f1b50a20722f0877fb201aa0c1419b689d62ff650420f352c1cedbb98a04b08669724ba0cf164459facf4776122b3baa7bb2f3b512c893676a1c67047b9c01d25863b2a0cbdb1a88dbc92a3c0f882052b5081172940c109ba4099c01d5502771417eea82d5051e820c86681308e61c1ae3768404602b79230ff727679538a22813b4a0b774f392a0b771416eea811bccdee2811b8a342e08ebac21d050277d4077c6a81626a0983f2803bca8a14aa0a771fd255a40fe7c77269ad453568e97d5d524b75158968e3dbdaa1a5fbb5de160912a1d60ffdf66b2238fa2dcd8ef862dae70fc7fc9b5eabaad9efc379dbae2acaa21886714cbfb5d919c56f6da8f17172c373cad9d1aaed8f74f84042103ac011941e05e861c01044271bf8cca44e3704508534b841c31734a4618a49830ffe51bcf7c374fe922861cad234b3dc90c506a717d324540a05c289357050c01805b0618c2e409c727071ed85763a7cf1c542cea0e361b86df878fc11874951acb2574d2c3d7276dbee7cf07027c3dcddb95b21a7526d7571e860e022dd37f76db9863828f72e771415fae58e9ac21dd5e48e1a935bc28a4ffb81fb687bc271fe172e76bd2dd75b904df5c904029dbf67ca252d092d6b1d1e9e9e5c9512b6741f5ead7fd4fa4b9c53cb4cd7e6d432139194a59bae454452966ace956e9035e728de41dad697fe27b295483faec65e8798f6bbf05dbbb02aedfbb09f9d43ebe0a5dee17d9d5fc86f7ff82afd76b7daeab695a7a70473f8e272f4ab613afe6de7a8a67dd6397c71f48f740d53a4202a42f4c311c5baa3a2e1b65f665b498a033259c243791e578de8a79588c2fb5bb44457e9a504e90a74145620187685fbb5cee123d8c6aefd481bbbf43f9156baad91a69385f7f514afbbebf029dedc7d846975a0ac1b6da4e992ec92be0b7717f1cd067740ad0dbfa53b4a0a1a77941251b8fbb562585fe8471b0bef4f4e6d02b51e662dcaac05b983201305c124fae120d9379b1d91684d03d30b0abc8ce1d3cb1b3e8340f90ca2c6671027f80c62e53388273e8338f21944e833881a7c0641c408deb401408dc7011ab8f704cabd274470ef891fee3d81c4bd279ab8f7c491bb8b1006146e13c608dc260c2fdc268c32dc268c19b84d1871b88d189edb886164078f0f0020c6c73d3140ee8931724fcc927b6240f7c48cee89c9e29e181fdc13a300f7c424e19e180d8899c23d312570f71f36227c2af7be1ff7be17dcfb44f7be19dcfb7e70ef63807b1f05dcfbc44c1ed4f0c9030e7c76c9e1b34b083ebb08f1d905c786c60df7e9460e9f6e94e0c6e7ee3421f400610665b8cd0cd4709b19bce13665506e53e603b72903c46dca18719b329fdb94f1719b32446e53868adb94a9b94d19ec3665766e538607b72983800fb838f1c9a5c72797229f5c5e3eb958f1c9c546843000702f8c00dc0b93e35e9815dc0be30ae3827b61aa7b61b67b6178702f4c11ee8501e35e9828dc0b8385bb934013020822f49815e8c26705d2f00966874f3022f80433824f30457c8251e213cc8f4f302e9f605ef009e68a4f303a9f60b6f80473009f608af00926099f602ce0138c066a4410a1049b119430c23d2528e09e121b704f090fb8a7c416ee29f102f79468c3bd2f3adcfbf2c3bd2f1f0f9a1d3e46f049f9f4f9e1d367c7a70fcba74f524d4d08248400a406041a2d3eee6909724f0bcc3d2da17b5a4af7b4ece09e961fdcd362847b5a90704fcb13ee6921817b5ac0704fcb1aee6de1e1de9620ee6db9716f8b12f7b6ace0de96977b5baa7b5bb07b5b66706f0b17f7b60ce1de1606f8288184113c1d250881c13d21ef9e109c7b4274ee0901c2039a1adcbd1a78b85783e75e0d3fdcab61c88e1bb8f8bca1013e6fd880cf1bb4f079c3097cde3086cf1b64e0ee1ed0cc31e0f049c60e9f64d8f82443003ec9b8f149068f4f32583ec90072f70f26104ce31ef6dcc345dcc34cdcc330f7f0e8ee9e8f1a24525e83840faf41e2f31a2488dc3dc7ec1182f700c187a8009f62037c8a14f02936e15304814fd1043e45307c8a68f81471e073a4f1394e9f63007c8e487c8e29f81c877c8e517c8e339fe3f63966f1396ef16903801a11524e5016a8923a7970022c3230e08b251d6f0902ae1794947a967896469aceddb55002af256dce034ade77ed48450c0a6f22f68363692a3a0b6dceb90096e583b9005b6247296ce47c26a56421e50bcdb896034f0a096474fe5a20a27a2dc4e8f7b9d7c2072dbc9a786561792f9f27f40b99bca432c4241f7214a1421b9e4d2c0577b7712fc98897f4010d0aa52cd7085c55782e301fb55debdac145a5d206b072f9a82155f1ad90721c9d80b2c28fc1883ee30d3b72e29fbe7628ff4b57913e1047c562c540f0c559cdfbdaa7ad3466a2b6bb7739f95ff4f3d7e867164b4575ad456ba5b2adcb51464bbc2bf16ea5ab2eaf84551793f2e91bb28abf6409d5f6c9f07fef07fa604488505df558c34234e80b160b4a3eb05aa620fabdb8ebcd4d0edefb521dcec5e8774b0dc6e8a7e9f875d7d0e67edb52065dc16b55e0ea87e67258242b92de55d39d488e56eb6df5cdaeb7fdbaa49fce2a897eb326957e5640b00a58056f4abfd56a068274ac9fb726cbcf3fd2ecd6f8daaa0dc39bf314d500af091c9fb1452191325282c003500b98b922a5f431d94c7e48c39d98eb10aefe14512c89eaeb462b91308ed53c248a3528474b4ae1a04213ebf71dfa64ee850a4a8cdcf3f1c2f3d1c187c667865268e2f42385d07d8414487026485096ce794c8a685fab91e12d29012e0ae22df1f19490f12e9e12225cc90a3a7f40783d6466e68d7b3d48f4f4e0f5cc9cb26a1e8f073c9ea2130b3b68b83bfd700d7fe3a7b5fb298b47820f4fa7c63d491a49b070775ae9d1a7f78793e9c6226c63d7c6224c27e907e820e3e54440e77839d31d467b266fd5c451b54bde6aa4daaec2cf388ca36131498eb74aa1e01e0a573c895158808742170f854d592b0f05276409f350f840b4b7a053171c0a30c38435b3e321a1320f877477e91f9e1e21422801881a565a78aa2fee1a8a138b85ca89a74ae11a22f28900372b0f8177440a0fb1ab65ab40de91afe21d49f28e0c1d7972c4c98a866fa50a35e2002917dc5354dc5353dc534bee4fdc33e285bbbfad02d126b63aa3f543ec3aa561040419b4b6e209605cb495e59db0f24ef0e1ee4e593988e8b0d3c10b6a30c60949112759886ce15110094f174021c0dd4f29253d2b35ca03c7828893903764b5460a8cd33cc2dd08aac47334b185674218cf841d3c1356ee620882382dbb18a476938f7ba61bfdd6f6336abb36e32f73ac86716efd60d7ee8dc2dd1b6197eb8827a4c6dd91703f8110c4c7dd0b52e3bec40322e4ee3b71c9128e7dfe92d0bc1f4b783f8470ca5ab14498399dacb857c2ce5ddf4a75497f57db0ac783078f1e9546e3c183470f9dfbcb92c95c492d9894a125d9100b3f52926230998c95031ddecc0f7f7924b0e03a7f399678360b50792334c0fd6d9524ebdf5837f04640a2dbb1a78df94972fc7d4bd96947e913f0660ff76c3cb0e1e1ee94890438800d6aa5489524229cff059cff851cbec1b00be77fe1435d45cab588e915bbf516d3fa8f3416ab7515c97da648c9c7f28ea58b1c7391ae22e96238dad39e843d2d042fdcfd948a3916ab7fa6757f1b3a951e0827782004e17d5046ef1e67cb25c944990414dea90810d8e49b131bd8e632011198c0db5186fb6968e6ce5454149ffefde2872d01a06c5244b491a281edda21a83894524329a470dc532a9a1d4719e710a76edc5347c0783d52ee35f72e07783caeb8f4cb277890dfcf09068f460dd7f9f368a6f0689a60c2a301e39e3292f274ea8453aa486a480ec30ac5a371e2d134f1687c1c0a5d39d916c8db91c5dd3d45c4dd695243860cf17468e19e0e9dce9f9f705e8e2c74fe92f430c15c49ad58904b298a8cca0f12beb2d38d97c389ebfc9523a62df97472b0ec725e4a872f1f05332ed21629c4f94090ea5aa90e2bceb3d6cc1190eaf2b69b80335b13dc3f09ea71dfb1fc70b6fe1c06afa5598360cd9554fd88615be7fdb6b7c128bd7607d61a66851b5b5d3116ff374babc0926afa6918fd92885a44f45afa7db66f887e5ad4f4d35f2b69346c0b1f87b9d6f1b7fda19ff831fa695beab1ac5d6cf34841ba754f411cd57e0deac76247bbc94ca4adcdfbd6f161a1115947198b95bf9d4f2727c70636b08109e89398a6e9a63d930c573fc762c9c2efe200434d449a15c51a147e0d6ae03e96a37d7156c324ac12269a036477a212260a2587f630d5a3550bbb62f0d78ab55ad28f181662cc8228fe847abffea14b3e2831272108c509d8aae15ae99ebdc6e0d6bd0bdcfa2bcd367f6168c79badc4b5cffde01917b011f3828d8f8d22930dd41a39a02a4a59d40a65e93ebcb64a921cd852d8da6d254b80b64c19a4f1c9e003320853a485272723f74f8b62a5d5bfc5eaacd421933d7231c08c038411c18d7ca6f1725591216a34f138995869b8022e811fd408e247338d2fc41aa03161a004015074fe92e4cc316e1e863fe1e755b89335c7867eacae1743b1c4537443627d21ecc2d1f0d1557a71569bfcc559dd25398e56bba7ac58a20af71415ee9eba406a8a914625fcab14be7baa293506d76e4b144b977b4a0af7541429283a907a22fc18ae7120b5040ab8c0420553782a8842054ef88ff5a62ce084f3f4844a98a4c4ec1ee79eda800ecfee8d68ee290dd45d43f75413bb376221c5c4ce95744f6520b4b9145fee290c3ccde225bd7f5eb7de629f3152d8b257c93d15263fce5e8ce49e5a6248ac347b6fb48f89dadafe48ac9666c332caef72a9ebe7d8951d907bea028ecb98680754c7aa4ba32952300dd3f014f79405c0b88fe5d0677cd335e85a4cdb16487ffea21d2a3c547aa828a1b2840a132a2950f1a1c2c3c4628d349de6e96162b1787a98582c1e2616ab8709d76e4be3da6d41b97f94f1953a42b97ff46375e92ad28ff5d65d4328badec2168b753f1c6919e73ca435a943d14e81e284f64bb7ac855698ecf8ec5c5fbb1003ed5cc9b0b50b311014283c3d4e787a94f6caa774e2c3b353fa94bbc72961525a9e9ed2042a488183a0054d1a1ed01a189268683c4081236ab6446183660341506923c601f757c35d02ee2eeee0e9710387cc09777711926802072e5c76d061071fdc533db8a7baf080030f5b78704f71d9a265071ddc5339e090cac13d8583c7051bde82d3193738087a5cf8785c08c0e3c2b720c2dbc209162c1e0974208190bb7f2450799eb15fb8bbcf08fd90c5d6c28b164c5a88b45be64d577ae6260b28b2609285123d03448333c297e1677ae36b837baa861401dcdd8824add70feb67bb9ce5e45656979b5655398ae9077e2045422965e91afe740e6ddff6cd4eb4584767097d4275965024d482785f3cda2afed00fa7b3437765e97d431d9d1daaf3eb34eb553fed5521840f40ffb8a2dd9de6d12388a5c12a6c5538719f2100ed6686042a28400511546c2a5a70f78b29155a7ad11f6d6c032b6bf3ea69f6b15898c6f95f10c59fab9493ae527d6dddc5565ba48b6dfda28c8366b4cce010be0c3b14057a05a44d404b9dd02be00c0d20ecf53aa24ea805430ba4f3bff4c6224cd7302df28482492808d2af866fb1c7797fae4c3b3487823a545b0d83d1d77596a343ffb6f50d597576324eceacd42a22e12562a9d6252e6d765ffc2becda6552f87b0794ffb5abd077cb4cf1b6f2e17cab1f15fdc2bfb9af2bf9059135073bc106d126f336608303b9e26482fba7b1fd59cde50fcd98887efa3e2ee3d7d805fae972578a0449cd3d10fdb46e00e18fd5c5455314619af8c06316d000165710e03171c4ef72db291818c38230e18b48b9cf4ff6e028a919d31a0e1fbb724f84712c27b5b04b29fcf05a29b0f06f2e81c2dfd72249510a353edaba140a3f87c33bd4d2b550fc7415e9bbd85a6008cd9285864f9f40a159b2501c95b6df7fae85807e9ad2cf453f5b85edc49bc90ad2aaad0641aaf54ad76af8c39a1f888260895da08152ba62b1e8cac9686f30b2223da194d21928a540f4c31ad6dbded2b17b5f4ef07daddefca50577a754eb8bedd16e5bd1daaead2fa49de04097999c191e68ccb0b400c192253d064c1b3b39fb61e1dbaec5d1ac51161293c20f6d7dd53c2463d1b29e00eafcb517da6d7b4bbcd2a178af32ae7dcd43f95f5fcdffe5c832cfaa4c66bb9656864f2b052d0d06ce40d0666b170a053f16b8ba6df2858a36b9bbf6cbf8c9261f0e88445791401588246322504575c6b8f62a5d2bb502e6feb25860158af7b5bace72f856491de6da47412bb489cc766d1590b26afe9c12e7b37dafa2bb5c6bde3aad6df8d56a483ab5d6ee9986603889c509cb9bc320d55640b08aa674bf6eb5284e2c67d44acd432b9a43ab80f45ab028f61a1292b9202529066b158156c02a19e7f06d55f3d3f0f75f6c05fcd9d6f5887ef9c78c592c903ea9fa70547af738160bbcd8e63ee733ddad36be7855da15ceee713290e96dded9ea6c05fcdb26ebb81357165fc991383fabf7d69cea679908c509553ae02642e4efd6bf2fcda9a8586fba3eed975af41bed156f3adbbac97148f7a1885d443856732da994c15ea5f0feb4745881f40e6eec40e65a1ad21dc26427bc783becb003b9830a876abb7a1d66a0c3163ea384869fcb2b36b8e17e820116b2e672e822872372e821071a7210355d694c5e4ac31c82e0a0867b0e5faa290b0487965a30d710d190508a862c3f3878d91f0e44353f2be39c87bc1bc6e8e2860fdc0006875e6b84d6f00d3adc40a58a24395a1b1ee0440d6fd46083bb7f7963d7c9fb6206a8c989d28470e14e5866ace0308648030ceeae077073fa8b5d184b0973558a1201c002811d26b664f1e1ee3f8486cba71c50966620fd253ed31f91388602962c4f60d9c1001b9fa4209dbfc7e53ae6de55c2bcddef9ee8caf097cf1218ecb3e58c7ebb4d84c86789d644accf12188c86bf3ffc58a0dfe33013eda66bd18722567d381a16e911fa81dbe7dbde382afa5aac44f403797a4a1004b7c622c5207865a5026b58bfcd8ab41c27383115a559126f5a9128387efdac2bad86737418887e39d7d2ba845fb56bf5bef957f4fb4090ee661fce0d594715d5f4bb21ad7649522dd4fab1ba684fea8a63434117bbc2cf91fdc372d3f5665bb84dbebbba3fee07378737c231be6034632cc3494c718ca868128a6384d29511ca22315d19a1a28a5216b552657c623c42e52e63c586eaae42b876c99ad3381a1665615897703ec424288b48bf0c27c6ddedecabb1e17eb2d1713dbb127465c9952b1fd055d0e36a4c01febfaba46cbfc6bae697c96a7e59eeafecf34dd7cf389ac5e9ff0052d892c944d15623c06bafc6648c376857b8a76670f713161db26e3ddafdb92623eb6b9dad7d0ea1048fa5728fc5c43dd68f7bac24f75856dc6369f7585ddc6329c03d1618f7584deeb150e01ecb0cf7583b70afc90f770f32029019c49bd48790118e4861857b5284e19e146bb83786c6bd3141dc1bd3e3de9822f7c6dcdc1b83837b6382706fcc03dc1bd3847b633ce0de1831dc1bb34613cabd2612dc6b2ae25e53907b4d53dc6bc2ee357171af0909f79a9a70afc903ee35adc0bd261db8374511214180fcf0e1a1c0b887aac23d140bdc43b1e15e2ae55eaa0477b7a929818b1a9f5c10f1c9c5129f5c08f9e462c92717379f5ce87c7271009f5c7ca1d96133840410721ce13307067ce698c2678e14f8cc81864f1d279f3a88f8d4a1824f1d493e75c4e05307cea78e9d4f1d5a4c181244002ec48423454c884284cf2848f88c5285cf2860f88cb2039f4601f069e4e3d328e6d328fb340ac2a7d1123e8d46e0d3280d9f473a7c1ead7c1e45f17934fa3ce2e2f34889106ce61c2ac3e750199f4425f824c2f14904e49348e903113c200104a7f1f1c30b904f2f493ebd549f5eb24f2f04f0e9e5079f5e8ef0e965099f5e3ae0d3cb083cac6ba8a49478d2a2648806040000000000d31000304020160ac562b180583c29f01b1480015b9264b268461aa95118530819628c01002000020000001811038326cf4a8963671d8f61047dd8931adcdcca1d39038d160ec8ee2cfa12e3031b5d8c426fafe237d620a13a521e824cbc6159218dbd21fb32c9c49babe63bf8f1e1cac5d0e7cab9fcfe8774ccec79e4f76b3ee90ff732aa1ba8e76020e7ff5b4d386cc0dd79907f62746abbfc776c4ab946fbd5cf40fad7655b5bc23eb09919f9e355251bf1f4c429b3a3177f81059bdc0184e285bd505084081e2884f67affa15236ac49a8f3cb44f21e405c06817cc25e730a2705aef24e75ff8cc25fd63e169f8af6c63bff763f62c1cc5fe5faeadb6638fc7e5cefff006e116d2917de96daa4d0e7a9b39ea78e6e02af4b9a20a787155cec1675b43e8c885f77b5c4ef719f9cf9c2b9d7d68e2f1b61010ff18a672ee8395b7a80a8201552158a36febcfe932cb586c48607aeb9a5375de91b8b99fbf75e6754a23f07fa57631e48a3a71c74ffeb5c49f38bf4ed24120c7479a35e322e9cfe13c401987221abe16936716f9bb85b02bffb4a8e23cf5e3cbae1d006122583fb7cf42f9ad532520f6f6062ea3ed2baa3a8018a848212acdc6da613e430ccca7de62fce60aa181b024f145ca6eb98e830f7c546377d4d345158336b40c1e752ed9353802523c9fc28c5fc3cccd2303d082f046b6243c727317333d56c7d85c198602a0d30bb1157d3b9ced084dcd95cd9bdf476a6143b79b61942329f4bc03d0cc84c02c686a30b90d6ce9d91d01417c6a1f441134d215e3273d2ab01807197d427b7576edb43cea8ed3333f0f737f771a3848ec4a59ace76161b1c83aa347ac86bba487b064e76f1d99e7a9dd95178674bb78e6048da901c433286a471f2ee690e8d9452c7cd600c3f63f46472e6417007cdfb6267f54fba225b71ec0d24ad6fdeeff6878ebec73a3b129cfae41ff164f74eb9cb123beefda7b7981f0fc33300f283e4a1e7f6b22ce28acdbd03e8b6309114a5d727f5098cc3e071100d7998c67762133c56b59c1d3b8caf7b7b1c856af9482acee7c97504e4966dbff1923077476bac48ac7ea277654600fd513e5e7fe3b5cc0b48dac6014d98e0346a74fa05b586850285edb02a8b8447c8d22e6894bc1948953c2df8c36648fa7f9e82fac0bf68d477af7e059866aced377e9c4c38f2b2d128b9d23ce4865e5f24e9cafc436b77424cd8c6d83cafd316cbe1fdbd0a750fe043b50f94ba038efe5f9e25a0def07ccfc74f55cb22f92c4c150c1e764d56cfb8ec8afe5ec33dd80133cc18a797581256a55fb724c5a465aba58b4c6e5f2622f7501b0c717cdb0bbd9fdb1fffab48ca4c5540e568b73d7bc94cdc09fea139f45f6fa0ba684a47fdb6550b0d1def0d06467cb2f7afa3330c9f32ad5a1b396c0e3363816db87cd3372d34f431b8764dc3aea17e3bcc46706da0fbfb32fac890634abc2f912217c817cb35b70dcf6a562b807f01862bb3cc4597e43a73e32cac8b5c28b1fb2398023ed03f169219ab34684af28d04fbe7417d9a3555f49c2b2b18f18438c4ee14eb595604d4e57c8f79f66e8c5ba3fbb606d4d2e152189fb7475ad85e3466354f29f598e23507bddc710db9d36be40a7755844794265cf1267189cabcc16f2fa8cbc42d3e3fc17c1c37bdcbcaa92b45844352eb2af763524dabc188496b52f59f916fe333726d7d79cb5166aa7c96dd9bc16657eab67c801850ddc6788d7e042a22ca02b3a4fe9ea79b1dd36b7d6d23b115d6f57167c7588b62095e7cd41a62254138bb8a3e573b7b332a1648763faeeb39dbca49c9002211e8b07476d4cb7c479e36906a44cd2104cca48024585df2e32a157c5500b34f04c362428f35914b64715603b05cec24d6658d1fd1f3980339d51a0314407cc144889ee297c0cce7e4af9b0046145836e14616e57ab20c63a62d6bbd01df045c69bf173a4e658c20bf430544ceed86f2920e3a22ddebcaa4dcb8850dc4eb263c56daa000884b492b04f1c9daed1470655bd912130c8826cabb08bc610c79c0af957a6704797ac6e9b4579c74156cc37f98d0a82ed0c1a132f028d9be144c5482d94041d55bb67dbf0c786d2667bdf3eb0f2ac5046608db4f0f56da8cd3451aecb4e76e87ac6876077af68d2084eab291ffa1c0cce9c286cc2f14d0e00ae61f9ffe2ba4d28dbc4ce46e271e42e687c40b9ff02002ec8c93f829c87a2e80aeb13c17b2333b7ddb9cb1331b291760defcf94aa49edc9ff2490bc9ecf068c1fb10bac3ac989e30afd9b799c366d2cea9706ffbe282e024f5d3e9d71d5eb6b9d9dea4fa0b61b0f308992159e6cd544e1360ac3fd690bed1858f43495966e2c3311385f391285308f10fffa0df2335d9ebe2f508651abacaeee1b101712d43778ea7567473b2e1b9b91eedaa748a84306057b80d2416498f56104f1287f93cd1a3e03bbe069846f8fe48492819fb88bd4bdcaff733015996da7a3e0814c5c09aba0937b47f0a49dfb17f8217994c7a0c88befbe22038a00934f91df9b1aa930fcf7cd8f0025166f1648586808c5cf621419eafe1eec5ac1ca9ae0d805e3001e493fa8cdef5303c68c5f51f5d7a9e41503b2427007f222bd0af5775f77c24085cb27f858e007748b9f8356a1189b1975ef9b7fa430b707c59dac851dc68ec1eb5f5e8aadf73b16360d2016bbe7cee9f2049470c8e8cc804703f9e450fb26df38d6c615819d605889f0d684b803f9ad767b7da010d38aa687430ace6044a651b0e7e7d468462d8870587ccc68735dffd44d05003c03d2b0b9eca35f29dc27f633692febd06a0929205f748f2f2727536efcfdd23fe2cce9fb5b2b56175baba519b26e40a649e3bb5062894f1afcb7631c1bee5462909a9c0af433e978c0805c2862bf6971208388643918973314675555b2cf2a0b79e2cdb722bd5a99b7ca137af52f0f78822591eaffad96d2f08f176b970d3070d6c1c28660a92274cac83993dea895066c2bb6185b4eb5825a64e09cffd5b002d037b4ebe59774ba660a50459d0ffb13399546c562fa4b54f6f8c23a59937b930af83d8cd29b2d18dbd7d42c5c7b6149ec767072ce8e16d2b147572cb8a5e0b33efa84b940416a25e984ae1e6cae73d81efd59bc80c7a9652f2fbe1c7b9f236dceb736fe79531c8a3828dbdff13cc1fc01452a4d53f797f7978ee640ffb919fbbacc231ecd5c98ad602481a09aa9cb486a6a18d01a1bf40f69914721d2107ee1cf9d2a5c4e0936e375992ec354fba04cdd7fa2386d3dead855d29ae90e2773d736b1cbd3d1780e9d73e6ff3fe479b5bd862ee00fa89e263ba348b08d4f1937263b1ca579d5c94e4724d2ab23a2f1a3b02cd210474dd96e2df88440482e89f79b914e310548f1f84934dc848b5afd978b508b2dbb01bd1a8b6485f5f7dcdcc1e84346cfb6ad8f84cc0daa4a32bae41fa14fb661f54d5d78afb7d683a25eb9889dd98a4be7204c93890321447bcc1bc1eb45c9f87df10ec92c5b8121559bfdf18ceead18ecb26c5b4f07674d7e8307c44d13f8055a4ba143dc6804f8143f68e95fb98466ccc0ef689fd1e5a980d97b69f06881cfa6c36256c1abe18b3c8c1a721b6409ebebc9139d44b21737b18637d22a86dc4da9e51c5ecfca901e538fb197203b90e15d50d4088160c749789021404e85491f9739b92cf21d7d4104bb7dd7891d77bbbf8a0401a98c55bc9777957b424c19a0f7da93edd65c5300694d90d9fa12594e9b29c1dcc8aa720befcaca965fb83a8a8a59baeb91e0e3e8c7513e77b80874e4f23d2eb75d60f0263c0485c609067d272dec54b980309e33fd39184e2e07fe53f36ef259437c8eebf6844199407a4d3cd0376396a2cea1dc145c4aff369403cd38d27b93efc8bc6de19ece67a4636bc7f116072d04413139ba4d70a5065df01571074d7055b6ff57366987df88735d90fec45afb4100e1bbd82abdf3c5b9b891a88bd57e7d9277bd959c1cc5d46d7e9a3de348c7a11e651660c55d1d4a98eccd85771f0e1f9b8dd53cb6916c9001c13747eca48c133725d887eec5142b1d18fb2a795977bf55f2c47a08d4182f2beb951fb25d375c20c838061314ec2398e1269d2fa98287474ea0a2e35950ac7ba1352820cbaedca904beb7bf062afc36c473a95ba149022eb37ac2233355940c917ab17243159faf399e8f46c6a8421b4e564d9d8381315e0a2813c65478a4e8337913eb2cae2ab28321ed1d41ed9fa8cccf8859c96f82e65a488fa418266344d78ca041ee9bc45b3815d4de036b88a2ae814c0e603b2f02ceb61c39a81f0d274d14366b25f0b017b5cfc062f62fcfc2ec2ae0bcd703ce24ad119fddecd900e0e5531c91727d2934896df6fdf13801b90f8b6f08d8510eb2afa77f9c9aae26c915ed3c1d20bd934b90feee037582be90e6c647df08a018fa390524652ac525360b3686bba0c6376bc2106647b8a944077e5001edb23db51a1fefa94df2a0b0011fdbaade0fa0cc961742594e6fa05db85d88200e2a642746ecdea2c52cd1f14e24976bcada97b8c6114e8a728925057724110f9024f1c01138fb60077f455a6dd440e1682b09dad9026aa263ca238631cd2981a5a40db9c4a67c1e063aedaf4f16aaf7683c48b88f9b88fd9821380041f7ccce832cae80b074d392248fcdd0a484e73418d4b5a5036b976e8d5da8e917456033872dd10d20fb4b5a21a0103214931d2eeed5c27aeae410231d412d9216f1673b86176b931a043eeb82849e4c649e58583be9547d4322ac889bcdaad704b179f61eeb095cdb31a23c475645145f2bbea31063b9147193758d7c37cee7bff4f287d21eeb97144c9066b03abe78423b008bd4ad43212b84395cb45f2a96d44cb1e2cb40ff546750c18583230136392f8ecb7052df99c32d496d3feedcafcd446cbfd4dd5a867f4511cb3b57d4937a7ebaf9149b0fc5e4f090d51020b0b350a44adeb0f573419ece4b6a0b535efc3211698632c093733d318fc77eecf2e9c7564060d1f0bbfd85dd6244c1a0ced80ed433bbe2c4e92cc0f676c55902d98c18a44afb4d7855db836059a02865c42b4b68e573651a8c08908856b5082b877a8dd67e5d1bc2d6c8b69d82d6ca1adc102065cbc5a64f00d022935cc9e44f6b17c73abf7c35523489b61a8b9a015c019ea238bcfc1b7908e42dffbe4d5fe62b26f0035a0834a4c8cc6f803bc3750a97c3ec7953e2265a5effea0aaeda01100e3ce2b415bfa24fe9755860a89f1f1c1bd563ce7e18152bb3b4e76f44c3651768ef1ee8610e6dec7a9809a5b0bc4085e01bf8f177ac0f2a6ea66b35852febb7d6c68498403e789d97bed21c0823ce1823dcbfc234e84e328ac0d1d93d217e89efc68ec2c782072d56ec9ced64e83a4d074674ce3fcb0b50cd8654ffaaef12c2bfaeaef00f48620ad8d3f99fbdc67d6aa95abef6af4ea206d9721b920ffceae710df940e7e842e0f4cef1ddaa50ae1934e66f43dca3236fe2e116c01f17d3ad41f7c06c2567558d3c9b63e7f2531ce3ca853495592d105e15092076a06de8e29962c0c704371baf8fd2026760642459d7d8e49cdccf3b463153c52bc0fdb8601e728773575ad8501998411bd380258748f8d106d09deca6d8b5dca4365c0e308352e63f6159036d42a4d6731e38ea005b437e1adf314cbab326ee9d76799d18102f54b031db8369513cf73aa2b28a139d761d9563445a7bd6564d5f6bb592563ffbbcc0b1170337bf88a3c36a0c12ead9075e19871359b06b5e7c0eab43a334b4a07255850082304198dd301ac31f9656b39959d936657cf6cc9f0082e3549f679cc6c669ef6b8434b0075b0477e829d0bf34cf494925c5f0c91b8763a6098051ae1b0bc1a23665e848a1cd7a73384bca6654e5a753635d427e11de36f721f2f79c56d7b4fc4db1257e127c6f035bc983e115eda5616b95e85059828fc37cfc0e1849f9fd3ea6c7768aa7564389d4858a5648c265f3b874aad032465f30079548662f7914a072f2b195981f6473d7cb32300917d7f33df04f3e6c63467fb9c02818995f8c1b78234e2dcdf86517db96e98998fc7b364953c0f248cce38d344030ebb1fd7f51b6d9f8909448814891b409b58df7b804d1a9ea297a985e5a3dccfa9c97f97c0bb4d4c252c5e858c830da1f0259b8114c6c6c70b2a7e44c40742e9b9e2d312a1403528211747099d8ceedabdedf2dd1eb3601cd46f78db649b0237cef7b6fdea9c157f06b1028e92f64a99b94ca193a3b874d90ea30a34faf11b42d45db58b22e463e06b20982febd616f6fc84c9581db82c60e2dfd3fcd9f2a5e8a17ee435ef8c2dcbc12bc32989166364ef5ac3b698a7e4ff340fa08024eb412c2a02503cb73ef853a25852f6e080b2094a08c6f7a1b1c00b4cb42613170eba8b5a5d1e9b7d378b5218e88b119d6c0442196a981dc41ca90a315484a4a41a7f28fe6c12a50a7b2a3b89ceeae0dd412dfa55227c351182c73bbcb2bce88d4aaebe14082c1ef4e967b70b331eeea88679d9d01e54d43bd2e80640be120fd5f73a09652c533cf0d7454a0cc272bbaa67676749a741d31e30815430116bc9947c2b680d2e9cd5258503d6c1ead6ead820ba5946180761ab112fbcd58de4e0b68062e03b776a78f288d0972b5921ff1c26a37d02d9ef41952c80319312a337bfc81a63166cee040e501c84eb6966ac29df8b56ddf3d3a3e09cbae377b87d21b798eadaee6c32c36e915272e160b6ff3d8d77419fccc3e65cdc7bcfe86155c59e116517ce2ae93f5f0a32429936a03c9952ae68d16200ac779e04837e814ba59b97c41663fbf11f0916e03c50123d82b8a410f365d5f02abc0f5b5dca21a4dac25fbfa96b5a1574191dae80fe654b1a6da037c3b01098ba100c4c232c689479c0f9ea0622340912c9bb8d627bf600ad10d10b30e54401d1786d32a9de5fcec10168ca8ea64141086185f9ad0181f8feeb630c52c40c2bba5fa09c02fcbc0467239c05711311e18709017e69c9ebc630848e5a94b24261b9248475b140b950ac435f8be44a80de4f63be7e53f493eb8debf844e595d9530168436971c22f19a94210abcebcd17c4ae2d115150df61c4da1be26d39f2eae16bdcec59de4cef65f0722fd467a8452789e68e2fba421c05b4d9a00e7d416bdb0814753b873356d388ca7f4cb7f01d9699e5b4a6c2d9c8688805384c4be659740eee6613f67006054b6dfc019a142760e79fa1a73cea278281f67e1097b0a2bfbac7df6269237cbfb61055313bf0d78cca237eef26b30f14525c8642a3e07eeb8ca3f6e1686caa302b54f5d4af4b0aee084cd0561513dd73642e67cd2c61b209309e67c8b5b38d4d05327b0bcf06c33f094fcf8d79b2166e367692ef94d5a18da3a6dc9c185ec55336a0e1b70e7c30cd1de83ee92d488f1c9c5d0bd627c3242c2a8358f830b5943f82c395dfd4498bd9919f7092e97eb42672e8576abafe3d0e28004fc88e3a9be820d914fd31569ba5a4c7de820abee48faf25381bbe5df56960384b248748c1502e4caee6c9c5278990865d33176729560b283c2df36496af4714079d69e370d4e07b480ea8d1fd62f917ac2eaa45761dc5342470dc14a957345bee9cc20708ad4486be81446f0d69d72efcb3f726c563349251d75659f238e7572396a2a6185baf7aba55f3497d876a244961cc4794515f0e656396ee39ae03623ffd7289e4a3cef8d9404f41705966c81297f84f9e7c879af9b48caf665c04d918c1308d9ec014d20128fd363e22568834b1b61d3ed6638a3cf2179ec5fe43850dadf28cdc0a8897b72bd3522a79373a241e353453177e2eb4e203a18133c32393eed24c8abcb60703dbcff6af12a019bfd7c5440c30b9189e1f4aad6338f712fc05f31732aa60827a24696c7ab249c17fed3f66649c7e8973119242803af58d12a4f1b6030695829a3c244bcadef5776a95052bf3136f7d48b232f9c4d496915bdcb70633f39b6934501b64881a5c27b5f583699be0624cd38dc55b10a5750b7a4dc80befd3a30cb357eb1d342a5b9a798cebfb029f6b6da95d4a6cd0a6157e80dc733f4b942ad9e59c59b22d19f9b3d3900b1375d857cb3afb022690efb1df0d173637cfac7ac8187207a78d6b2014f8bede6062494a26fc3cbb470479ab20364b940fd701e7be6dde2d8285689adcb89147609e3dc404fded2313ce354dae199a0d8edb771e9d95ab6cbec3d320da7cb797b9886a6807e1909da0e86586aed5c1de7be0e89d60d419cbf9876de6074cf96305eb674e2017ac587a6ef0d6e3db850d097d6f0ad240845d7be1f50ef1cb4134eec1f6f98807e6ab7f6186ddd17ae7472befcb4be2a1800359c20c0f9ce9ed15c52e6a12e88c579ac9bf554ac6ca91c74c5f4a3036da0518cafc7920dc06059b7695d7287cbd814a1b318637d3b36818a755fd286e3e083316ede9d76cab0308c46d030b21932415e5bbccafab8649fd95aab3c98d2d4974514e5a99498d03e598f27f7b05d5110684e617c5776989df89521a5fc0e9e39cd0d519f34aaaa03c608f2eba8e3e3ace83cb1489ad22aaeed2e5157a863a3cd2c369b26f42b057f4abd914cd92ee7a7956f945edc8db7ec085865e6acb2e6b7a4ff73346a634508ccdebcd1c18e87cc18d406fa49081f002e17a335ffcf212d817a57f489c33413e4253063b9f439f8dfd69eaa1aa2c56a24940d7cb1897355a343476c777a6716a69bf7db93b8d4928821d4ac991545d50daf1294bb305d0fd34cd6502318e094f8ec4bd737e142dd4554c87d4bf5b818beecb0b2e8046bc5870b0f3f55426b9046e3c8c23dad4c11f519a4c93418fd858df045650b91235765f79b6f4b736ff1c5c308cd9dc530148eacad50150164c9ff743e9e47fd3d83ff8bf1c0cbc35328d674ddaa0cdd1c7c30cfe58bc7c238549d90f4a9c2e04e93e82dada2bba1ff8a61d7fa18bb1d1f002030d86511ea14b9b51ff1ec60c506ec6c728655ffabf3a1b063c99f3a878ccf1d05f6dcf775a083823a26cf780cad0dda46836ad0d6ca6d4b5cbdf43b3b036016a4f1482b32d603611bfd043a65de5213e0e088ea41e7ee6a5edb648aef94154236d1091676a5c16e0fd0436cb684edce4d824e837d75375c9b206dc59093ef2265b6ef75b5639afac7a5de080b716a35d1f5f40238e3800dd4e2a4775041829142fde376c0e782117a2e006e14c743e473f0e43633538550b77b3ffb30a64bd4ab1f1855f3b0a90a3dbc76defae00a4456d24a1923f52438026ced0060331c80d1bcf2cd0f6cb7414e6715c932d814d49020a90f00c61e8b16c0035388fdd66c2605de5fa5400968b5274bd568f23249ee279144238887b37e70a5453ddf7bc1359eed056e824b25b9b8315addec775fa1a98cbce35bac0557d9ab30425a7d60be1b3319fa19e0cd6435c90ec1695cb930ba4fc6f705d09d884671526f921b1f36ec97d46e2eef73e0d41c34d07e6ae01a0a7e70c6d1675dc3758effddaafc9de566b899b13ec164b478fed86a20e0b9f0bb7a2596160ba260ac7ac14ffe685f84af6c5233db0738e898f71ae28cff11954cb487dacee8d6abc2f32c41109542c3af13bee61f5ba9173d0acb22a665baa4823e7d5d7fd89d9d172319a37b9562bc64d6f754413036b2df982c69e479e5c5a198fa9f483b1c872653cf33975d7a2990da37d7bf2b89cb91115ed12a267ca53fbeb155098efdbaf546a63fce58993e2a779f4dfd42854e9bd1246f1428a1356e7d8edfaf2c2b755f3a1fb1cb6e124438508022062f338ac053e5775c20f5fb7366a07c7c8f23d5871ab1e9c481bf78b9822a6037cb557ca2b2637113f2922a0a9104dcf5dfd588394836b32a58500e46b3f8be861615521940491d6179b37464b925f75ee4af972c1c7b7fa9df1a70cfaa7278068e93216eedd59d5f9a65ba6b3ea4f15978ba29016ce44d113273361bf5e41c68ecf2c27e342fc73e8cc15b578d8d64a9fd3b0f34285019aec878114ec55b1f05f449ad1121f05195809f30ab9bf7280c871626a967d2ffd0ca3829e1c357710afc7acbab76396691655277e652c3fe09345263d2f2fd1d8d396faf5587fe7dffe6806b28bfae1b01f628ac122a974de12a8a56057d54a8e849cc8e26a62e6d781f4c7a0a98f08f6c4be2620e343cb56e2f895ae3cb2809e38c98788ed372d8e36c2c04a014a49350d15144ae47a29c9410dd767481fc891d6589992c9b561b42bcfc584a264c774b58d8019c0d0c3e27d9a0b7a06125a3cb200187db27b86de012880cd9f6222f269295a48fea712e3db33dd80ddf865f4e21cf9be25edff5e50183eae2a9e0279be1c3720f4ad5087cb187d0350bf8d6899fb54091b459473233c82c1e84e5d46c1add869e665669b4c03830a174d040165915b2c1bb8482e9629f0a9738f3d752ca4b0ae8eedd7aa75083db8bc66b7a4f40ad6aa5b74c77ffb1a8a02a93b17ad00b4761f4150d5343324ec4f8c91b2e66557c4363ef382e8bcbefe69ca113858ac7dfbbf1910486c40e9d83ffea0374ef47d5b6ddfc66029a400a569881b892ae72f030ca56332cf48d8c9a36f3d3a661c8ec64fb3a648e09cf46f4f348ed07ada78653f3a6a238d650a8765876950dc8a4166aef7513047ec73182a46b893296b8996d11b5146edcc4c422efea80e06e6c0b2a842385206b6e238bee21363ce9657f327fcb6fff7af68fa382e2af4a004bd4e154c12a3ba3104c7ff0d70665ecbfa17d9312de8d89a3919281308d309a407980851e713b5e25da6ddc3e55b5aee08fd0eeef85196b7c791b3a4f246847b042f555aa09bd08340f5357ef97bdfe85eb0e08fc6d6365ce5c4264694b98b76be0af36a12580237a271a710398a89876f6aac7a2346416179eb35509c6cd29939303767608ec6f541be6e741f291deaffab839b715fcfb9a60c035644502076adae9b2a06ddc2cf324992d4b74099f22d5d8f1ee818afe928c7477844b9b122694c04287afca10373adced8064975bdc83eec2a6296daf964f716913a697f9c1c3e5f36449fca8c3acae70a767caabe05c6892b0d7e21ab0362072e35dd6b24df13a089813c446442fd6f980f5fdfeb1f3e4824d6662a46fb89493423b88566233862c093848ac47d114e624e8470deaed0e20cddf2cceacc8f7ddc9ad14a254e7b4a547427d88a8651cc2c82ae20a9c5f706cfa4beeb5cfafc180cf2e94e7c77c37595ddd3a547dd7f8c006ef2db6f3c3c0ce98d2c3ac163289cccfae91e03b1e0a2647cd746731ba5e3dcfb3f0bc3e8fc1cf902d2774eca97ff4b9463efa21da3cd7ef0457f8e0f8bd3389e2db0f5efded200e1d2b008bf885ceda22feee1d44d92bd98a77ff28587dde6ab7f7c92f371c4c0cf6896d162e083af1fc3e340ffbb20acf70d90321770f0d20c60b920fad0b182059708ced77779f88c48e7072c7e36d613bee1683c2304992b1cbb3da2b8eac8bf355fdfd74eff78e217a7e683e651f0c79eed40ea7f7b1702f2effeb77b19ed1c9ef7aa7574d5717fda53cd7fe8f0d431bfa459d32d2ff36591562c4db6ad9bc7ebf0145b6e7fb8054faf39467b2ea060bdff461bfda2eb7767f4f89abd376cc57f0509b4a285c633f4f8dba031bca039eb5994427c7c0e8ea666d4fd7172b8b15efce2aeead6bb24835a746e6dff06de60849139582c1c797edff9f588ca79ceda10693322da9a7eccdd7fbe3fe77bbcc741b19776447f59808546bc86ed57f359d40f9f31e825542f5d10daa335b70bf1e4bbcedd8d033e355d0ff61673fe71fc0bc37b7ff1babb427f9dbfaea9e8d1cd804cbc86f82566b32d80e58c1f3153eef49bfd068e7c0bb61cfb6befabea2dcfc8e1dfc7a79c2fcef029f36367fc9ddbce6b6763dbeb6c543cb96a649fd896136352eb3bb1d77f4c474f69787ad8417cefd2e95e63c4193c8f712870fe50195b57729cb9b9df038e08d4d576380e608989ee0e87a92f9fafe9ce00679995a1edc6b7dc2e1a784b17df486bc616503ce075bd0cc0c3dd5c04183acc097676c80ba077cc08fe47456107b7eda81e773b28a301ea5dc80d6076bc870138514d9d0d1eb4cc01f03191198fca07fc0df1f81260a07a6f80d30c1cb140373d15e6d9c24416960666a89282ed3f4f3e247c8326d84fe32041254fb10114b9174ed1d01d48c4f4c6ca9f8c67dd2470cfdc418e66464fa8ff947afa4a28e3361a7fdfc4dd4fc3d4b4b393c89ef38faacdb383b84ff7a07645ab563e01edb49afe0e601bf3fdf0eda75f9d4cc7f9bc8ea74af146fd5b507d06983c737e2312a18e2f094c54cea7b7e8d0275a5de64b7d4a447c0e6ba6f124235b426bff98e7f851141fdfb3d7956a995184929e78f0d89a1e47ecbfd1e3f1522f299a4853408cb8d83db81171b506c54c70c8787ba256ca8c3ed4731ee183ffd73aae3ac24fa2165e47c9b3369a9b5e863fea7dd450f55fc838893b4e73cec6b051fac69614f02e843602c3649cd6d71f2f9789ff8ca52be64e0a8ef3298bb9b3b364bb4c2fdb89a70294eb9a1c859632385d94f505e5b137d5dbcd398b84ddbbbd314d7a2f22df811c306d06375b59f08711d1194edaa77291b103e372fa36c94261e23904dcd0fab01b5eeea0450975e019dba65dd2ce05c763e2de293ef10d94e438418ac7105b862f6b195ffd310338fdcc4b82e79adc107112153914ec0de3bda9e39da3644e5dd1c143a0d52809a1088ce2f0a7db760ed3ad176c6d559ac7eaedaa9e19dd5344c9c7892fce813a18f4b03177a6a6af5c9f41f62424f8f1810ba5be1912d721a4a945ee2e32531095940ed60154f4d61edcd6e299b4af8d112699d0c293797c442dd145dc64ed437d38ad87d0bc6e1a8b015064b09b3074dcede94002d35ac99474cf91203fc9a010608221b9e9b4b478dac3d3963aa76743f92f87705dc1a83d0a0ffbb2a5b1b282d6938e2b350564975f2c26958af8d78f4c916b692af38a8ae35045de1824c57a637240ac6a79ba879f792f15a281995a4476e1f50aa1b8a02bf118e87f3125cef75d52d9561632bd728c650381922519648ad2910e3d554d1ea6b79fb16989c5cbdcb61726321edbc613440fa2a559a93ec2266ecd20e10c9eb580d03e4091e373923d68c4ad37a995fb670e2b19d221dee5f048341c64d636a18d206e5b12094024e970533db5492e95712dd10d9670a6c85b7267f010417e1874106e0a590c415f593747deb9d4148959ba7dd7357370199ec5a2ca5b49ef80b5ca206b7431f1c8aba874902d372a4ef8017c6a02451c7ef717e1bd5b76027a840a547f155a1db6c426da1a1197b01f77831b14b9f286ef6b101c6d38b7829246d3b9f2897c9f45c6c06e68cdcff467918e7afe799d3de8feebaff7678d1975b74db4fbb55c065dd3a003fe2ad62c8eed6a1f2f4852656fc060b2149f1c4ac86644decc05cee1a22cc2dd8dbef4cdfc2b0ea55714e19e799d8b2fe192c8b99b5b30eba6e999262f2e3c09f21b4a87df4aba3babe7df73087fe27ba310ee17ee4c4aa1469e207a56bfba7ae6ee8c9706b9c0ccddce7e749da445112a46feae412b4b2b63a06835fb96b420bde827cfef221f23395cf9ac8403e5545e23d63233ea30ec311821af2816ffeba29ca0c1c02d1a021f30778b3300f7ca46a89963e3034a1e821e6cd82a40eee317f7041360979b9fefcf28163311683951080643848e93ef76fbe093bdea21bb8145a0ea0ad9fdbc299ba2a365f4330a3eac0c7fb7566edf01b073c67d2807852fa1f20700fe392598e6166710d56223f564d28c50ccf780acc9106889573734162624815e16debc24a2b7671220b6741eee74c276cbd938914c3b14e8617012724c00ee666741767c33e571e0d1754d50cfea33399977375b0a4ab95842561b19755919dc80f802a996e0c670844dc66dbf0d50dc806daf2da28411107864e636fd39014113c54245882c9b27bc3b705987fa64c2987a057b264b3663f9e3f9b00f135f0d21b651d88b141b0c89ac0c5dbfaad0d9f4649e69e3a6809ef5899ceb841fba0d62e2c4dd5a72c2b27d3f0f898d241edadc1c273efdf529302b961fcc24a66f411403081301ec7fa240980fd50f1431800a11d780b2aad635a03eba6b7c4b7445547f402eb8169db2e7f1380220468e0f18b253914459dff13066ea646405606c104152700e7bbda3bd8ae9006d6e2bcef7b911d2ed3638c396b6c6a7d4f1cdd317eddd727c22e6cb75a174418650c00b3cae44d933ce2b0ed862ae802d600940ea20dee03f8403330ee887fa595870d94a3da51a6b9a97b0e00671ccacf2c3d8c6f0a9a1ca97729fc88b9b497e24f06d2e342399fb8929fc009f68e4b0f4dfe1ae29e7cf3706fe5547203c9ff04587deb0d5b8c0a3a655c58ec4213f5b4e55df54ab74be0b7b1c2168213c6d9a2249f508e00fb0baa19c7186cb807fd45a102b375ace99023b2d69c692f3a7f8a5fcee93fe91e59dffdaa82a803d7c16fb010c1d6a0fd80e9fe431f95646824ae5b7da206bf04dbae101c5d2825aea36b20ebd00039eacff44811efe7ae1306b2c2160d3fdacc3fe38da91c8b5c1c2172d41b67186fa5789b42f21cbec462a8b4792fbd150f92ec7eff11188104170a2d276409460f8dc9b2727268cd7f40c28a982eeb83d3f0d3dccb15da096f577d9115b05db61bb6bf21b7ac1925b1bc8e9a5f5dda0c2ff5e6fe8d7a660a04a630cadc4fa38e6b25dcc60cc6338e9c41a6c6e17553e63b7849676cb30af4f3c701dbe919ced1fce84cf12112db393d256fd97c2ba697ef29681ef347bcdf527b55fb51b4b79585a0961f303e85cc86cd19909798dae3e98d54401cb1d77a240c66d6d4ebe5400acb271a5f97ecd258e247f7d0436af91803d097f6acddb1cc8d9c49f0958810cb40f1e9faffd9f5033aa8a894747cf494063040dff02c6f9cd96ad1e9755fb59d60f0dd9fb89d7a6e08898d8466c4e7c3202709216ef564f773a5bda2320d710a8de256db11d3d4af74ed55680731a9b074ff2e68f797480321db9795f68be48d5b62255f7d8abd8bf235b0a4b21833d1dbb23a7062075187e9bfa016ebc2ea36163f65b522af49655c65a16471bc85c16f0bf21948724631c9555d25e6449d1d08902f8dbf17a281ebba14292667e6d14f76f1218c6cdbc37603acf744750e2cbabc332a50f63ab630b02f1743050d2be0dfb52cbb4bc3175d27ba0b93e5003b3de5996e2baa2d8bc0b723421018008daecff5b9b5ee03a32e3b4db3e612bf9c10cf8a078bfbb0e4ab51fea8ee4c08653c79e7187f27525f6ffd1b2a1408140e834a876a709f3e37d34b805217e38c7e8e3c03300fbbde3923bfac1cbb475f95989fce9a06366763adfab1fa74b2f9392ce66df309c6ded4a7e995a3cc2b899c900de99e5086c402f657858b0af879f7896b7574ef0afc3267b7d0eda5fc330b30d862a9b138a0c8ea1f7d5ce2eb6f02b1d2e4cc7765f3c4cd12d94bafca388f8954e29939d104f08e5b04db34de0edad07c6be180fb517d74cdf94876ac76cc6a136c7ddabb29faa2d7e177ebe7d007751206f8accdea026b8612784f66221652f22dd8d51b548ad7569b3894ce2a8fe8c79eeee8bb3ff21d236ce0bf5867ae7ff6c7c88da6aa6fa1b16adecc666e92058d50759a13c7fc71cfe94c2a1740ded97fd10ad743de3b3ee07c33fc81dd8046fd6897c64cfa83653a56d9ae2fde0c4b7d77c37e536fcf8f8eb618fb30c4495f2f2cb2c8bd84ebcbecb7db8623c5bbaef835e61b1d56dbeb55f5f8e2ea385cdcf4d6eaf1f58e0ac864b166f6b4d6fb6e5bb6a31936f97b30b1769170700b9bd4278709ef19e64f4147f6881b87e5dbfadd7c75abeff58642d1bf9b6ae572294c9702e4a396e4b025888f39ff93e356ab87d1f3eed062ff37f6ac2c2899e6207142e80360f0fc2787ebd3dcaf6af84a198850214599bf51142b37046a43b48b023b9ac577fe8fa808e0169915c3d336f4c3b718f48b42c353b0916c79a90f836987696054fbd08345ddcdd77f19f6b5d323383d054df554c7c556fcadeb7d1df58e2e9a8f9318789f582a619b786687ba3f174df2c1d8437b4db23979a94ee1462761584f9cb4bbe78468c2b38fd0d18091f932371e1cf879cf89bba1a5b83c4effc6507ab8ca0e10146240915de6d55fdfaea794a556c9c160db8c1642bdfa78d177d1e404152de1631d18eff38fde80514339396d191b1083fc0f28a3867409115a0473d467d3fd91b855ed6714793dded1966b0de620f58ac917395dbe197f937ecb941a879aa5f2ade3ae8958f89ca31fe777eb5c1a138280ca669b08f5028903df33f169ba9d30ca6cffb765f73d0da4aa6bd73f8186b3c984caef09832cdce24f90e93c33c5d673169c304411a1374a388441c1bfa40c9d46f501c01e0b0de64d79fd6bbe2c33bcd88a0f6149b4f83810e363fc07b0d3705affb54b02753f60bf73612f7db983c0ceb20e717b94e4b466df48e42ba1eec6453968a32413d6004c3869b630e9701c19c6d8f4ba67a9bce6b3c1b47c28edf6d33df288d70fcd8d95cc26aaf7a5ebbd8708bc333b75fc3b3ec9aa688b57b568e7d1b041712b866f507bd8a59eff609be5057ece2ec9162432f8d8114bfa1bd42426325c959f929e2f79894bbe16ab133379252f51956d105d09907ffffda274adf1af809c23acbc7ec2e547758a03fa50e4d8eb64f404be8a3a369df9dd1507fc21a7b52c13deb7ec3ad52ab2986c7660f40c9bf73a8c42e6007ffdf8806c7f8151a4632c940f705cd5dc68c75774a65490b349a5e4563c53af52b34f3c9cb1335d78c38081fb667d9748839c50a58b5b30ee4f56f0bed9aeed6e012be160fd5750009ccaacfba58c78485e171c09d46f2d0218731019db0d6b9cf85bba83eb6ee0b8f536a2c70811d297d7622692b21d082e462fa8cb23bad8034d5ec151778cc991464c5555af2aa64087428b3da64bf94e96fa53480198746a337bdb057ef08d71d3e19803dce0d50b2b531e98b7feb5d8c3d20321bb104059e0c055010dc087dd9ee53c345f62357de12649f77feb2054cc82aae062734fe74ac20ce21c3ea24211690410994b022f9e8cc5177e87ff8d43489727f65e5aa04183e48b77d1cfe942bc4fea32996ba296496fa0fd3b547902df175ed81437d84020a28ac7d6c632145b0842ec1e9c1b1268a82ff79c90a1c26d322806f4ca4fb7b7e997dc2093cb34e73092bfd450ab6ecc136283a0b227b5b4f1bb93e3c51e5753bbb9480f9355e12ba2a8d06f5bb6d8edadf123ca1fa0b04c3e595c2ef086c687e43cfb9aa5f23f7da4a96ca0fc3ef086647c3891652f1a840643ce544b861d505b948220d8c127463fbcbfb8a4d617f91b737c69ac6efda71ab7c392d771efb0e49a928d0574fd3c499a143c4981110d8a00b32c491c942165dd04c66ebb9db51f0a435ca7544bacf93b30ca79137c93342acc6dd32ee0340993da5b43b6066def01f4261e63df6ae959c5ee483a1231348be80d3ca7aab849121023e43b485db30e5f849bbd2f683592711b3617367a7f77f8e2060772e3df683bfefbf1c4869d5ad4d88face17702404054cd37d4a59079aadbeebee659753fc849c7bc70b361fbea73353408df0798126f46b377fb10274d1970b37262ad4a5de70daf18a39af9be155509f5b6a3fc13f189af5eecff6a286a113cc355c757efa7f9c8ee27a7c4dbe73edb557a7682bda86524d48c06efbe41d909385e13450a37a584019edd54190eb9e813fe2f799ddaedd2fae11c73d6d563d5d8f3f083d4aa3b6b8cead5327bb3137425162e9943c9e873735f5ca8eaa94c9c21a08ca06800b00677c53558e1a9941ceac37c0e5ddb0b3da749f802b3f6abb7e9680dea5efb847630ee35edfef54cf7217618b18bb535a203593309fea86909f25e7fb52a657174fd887082d24c5891b9de5abc466a1867fd2576ba3c3345ff4c97341b743d2c170780f7b5609ac54c9842744feb487f296c73729a1b0e25aaf8698b1cdfb78f0d783cfc21fb9fde52a174d39963545d1529b6b2833f0ab0602e664b6cad6ddccdc5d9848fe84cee36e46650eadc2c7102a6b322332cc546d4beb770cbb3f854bad1ba8b1da8be1f1dd5c6a4ccc01edddf737055d2a4fc8a3fc6ecbec835fb59a6887917e0d731e59e441c63dff51af2c08bfa6f2e5d049ffd7875ac3ff4678fa7ca9fc603ad01721748dc786aca7da9267bd2de830dfe87fd81998c8bc6579b95f20bd37bc610a9a23d773ef26686d37eeedd778721a9e4a12f1cd3fd4e3bead359d44950691c8b8a87c730c26ce3b8d98e12dceb0634d7b126f022ff4fe7489805065575fd7bed6c07b6a1675a5c8bad8a23d580ca7625ddb826ec487a3e39ac0982c9f65b422f0c1e1f6045acb912f22573d6db9b16967549b7f8c90b50f485bcc463ad6d2fb6ad9a152f58f95ca9e8ab89999975e499a557b47c8e4202079cec9ab11ba71e8535710285e6f80448f05df304d3c44f6afd50f07c437dc32c4fdffb928aacbbc8255cab3a28887765698de058c0396bb23309cb1447bc576525cfaa1fd2025957fd09a2e67379f31952c75e4dd3b255ff878063de5665b54bd52304500450bee84412f8440aa0779b9d42d1e8439cff0bf7a6bcb790befa720c7562655194384bc505acc57e6dce379db50e4f7f1bac693eb415434c2f2bfff87bbec59d370ac0a20225afd3d8b1ec84013f7238d3780f94e0a68fa7a225b6aad2ce2b5cab79e0597aea9ad7028df8d2292ef333d0b1a5f996a43338e6a850d857048aaf9d25a10b65968713fa91602369fb627f6b9a7754e52aae3b73b523eb9d4bddc576aab02707f0016efa3bd098242db2e1e02a7bd45c985aaaa9a49f9939236fa98ee2f07f4fce901ee6ff44d35d3fdffde7eb2412bc5fd41c1ea8149967ee1a5f893ce7a11996fa767c948ddc258b5f0a2631e1051092bd053d5224655270899829b2b3d8257e94a53f259dcdd2cf3505f9a0a704ad5e020651cdff04e48d5a9b9188a533e8ef52f80d0002ae38c9a8dc8465eead50e512a1604b492eb05e63d04b6af08243e5670c12de673d1468b68e97949dfee7a5fd923d8a4241f7942ccca534ffa5cbb23fff44d107f6a2b02e27297be6fdd642a1ca4e9ac01c4e04fdba6c1e6238137fc037d8ae13e7661f5dde6c0435438720b5f2a672086104e7048ac21dcc41eb49bf7adde08501fb0b1fe8f545a11e97b24ec4742ce79eddb802c29a6eacd29a94dd775a90afe39f732fd146659e4a23eafcea5a8f34778650603723f1af12f6d64c998420164ad4d639aa8c03dc0196ad2b3b3a032ec7c18c5f78156fba0eee50105681f60237b200f40cffd015df7375dde7c9a94817b7d53d68ceab5f4e7da8b30ecdc569a42944633bbfca65ec3c754efe565729ca88996c81f6d938fa7ce2dfd799958e466f0dc6194c6bcda42b42e5083c192c9a97bb66a8f60b8d5259a4eecf71a19f8cb214ab105f6b80f9d23678a35a867e22bb4f96bed6cfef82fcf26db48e90b5700e42f78c16770a47d9abfeeeb793a87a05bf45c465539e3fe648b60d153a4d281117fd3d2bdb975a17d9af59b9c6b4ebfe82b99978528ce916838eef16b599101d6126e63ffc7d2016a43d967a129df2595b8e6b4a4ecef545526c97654777bb2821e20658e328d4ad4b506be0fcb5ca2113b086d3a5af666bb8923b2b4983cb37e91328b0fd447580303f6e72071a4cd89317700928872a1650a8195e6050a8fbd9f4e84be8bf6aa0dbd2d34c50af432b91ec41fb80369e15604f35b672d746e96d3fb010b02178c683ec0779829e83174832d4805b1defab92f9449aa963ce5fb9170f8feaeb1da45f4b11487f9adda5dc03d75e1e2f30ca817c0e07e9e0cdba9e14dd4afba7189ffcfd385e9242212823e0e4506acd1bc604a5a73eb15def23e15e96c688e008803fd4124fe499af3e1a3b918e9a135d5a8c62e62b7a3198b70293780d3be1f3d1cd8e791480fd67a79223445edc1f4f24e4aa254be0776dcf3679781140d14ce6a3b457a5af4c18a2db76c840ab3b096f401629843627a6964428f368672f06e216b0f9edca5a75696f8fe4f70961a63497815d2b9b1f56cd451fb401792e6a2f3add102e0be772328374b018e3823cd1285cf7f7e0f6a3c8c81220eca3297734a86880ac8d8a0a9e17f66c8c153eef8a595cdf738c8380e44008102c36e53856e35c20352bee4dfd8427fb1244d1f22d175809ed878ba35afadf45fc0334d306ae38c840df8352504fb32b30b87183b9519309eee053552a1914e77915885dd35823dc1ae26dfeeb6b43bbc7c52134fd8a588b56b5a5a45d576ad45848257fa70fa009442b38078142c378632a823b1f3d55829e8b6ea495cb5898441af7ee4f19979ed1c5dc1026e8b045a090cd1c8e2bc1fe15301481cdee0d5bc068f4c2298055ebab7f7fc9971ca4ad053c1482b2de87090a33da7293bfa1cdb8eb6fdc67954216333ab57db906e349439fcb8e4a36695feb09c92b2dd90e77fe8b6f9c5d1094cafb0a064061a53d474763d97a61e8f71b9494d6b8c34a213ba8edff9afe3885727c62ff2cadfce8f9263a6c31aadaea81e3551ed2601ba23cf609a7cc60dd18e7909246a90886b507ea7231cf983b58f47c4c17ae8c984987bb21991c352707f95c13c30b37e530deba5bb4c4c81ae0bf90adc015f7ed9d0b10fd9fe3cb63f9ec5bc1af233c78e23061b433e1865fde5f2b2d5b80035b3cace68d0c317ee64f308ffc88f337074db1dcec1322a84612f8024c1f68f293144721295a369dbd26ab91b574b7380f3c739ec232af3056b0c8de2fcf9e5177fa48a5a998b741e5ef599730e8ba3ed472534b518ee60f942a839f8bf173ffdd834bdf232c28f0fce7cc8e573bcae2bb93ed29e8ad4ef5bd0516c1b7878e4e47617a9efd44f9d7f89be391370b1646a28942d991c06d2ec4741be470a56fd8308e335616872eb9bc87ce68768b36136bc03472ffac34855123950bec0deb00ddbbec496ac009f5fce0f728276ff808f896576e46f8e9e81fc0e7243a2079331c6a7efd1ad77ae1e9cb4d73cf5fa8e11118850800e2402ffccd10d93a8f79c291e30f63de55ab6a99f9d23b2145df5c15e4ab1bb7b8d76d4843239ba1af706217e24ceea5a89d35265f0ec79718425b5ab97a95a132c8cdc6ea3a8e86df83eb6f9e314cefd5836b1f109d6848714b6d42da057aa451318202a2ec1e4c6645209b68a1a126b2b4ce5728bfc62365076bdf1f6463239dd5bef385e690ef5c66fa3e7d3a89041812c495ac10a2b5811001b838918104fb30c63cd36c66a1815ae4a97de64ac0eb41308cb4282fab0a773265c5b2f25f976a6780a11c37b3d6b90f10576277010357cdea65059d15e206d511be1842b626db23285d3a455f3f6a7c21fb309ebf07c0bbf4b9785807341ae3fb5e0997f71cd5eab81d6f3660f2b94c5505a0bb5ba362d0d94144ec514aeac49afe106e1b49cda109bd6a99ea242379be096176a9ce89ea02c2057b7fe82b4a78e22a67f41dafdee9c17d80944c6a1efd04f93c2499609b445cc2f71cc47c3948bc54bd81aba3f655931db7d113dc7b543dbcdd3a0d23dc5aecfa166e597dc17b8068404197d25847467ad86b1eeb5e7aa23b74a3130956e9379e9767c23f4ae24dfecb28a975f2fbe956b3134d5e48d2075297e7b996ae971c3c04e1b0041bd4d02448cf41df5ee10a955a26ec671b9c915321a3b5bee0a4244a61107638c893a8bc0d739f06291f5107b356f3d12a992a66d45811b18f79bf73e80f3a795d86b673a90de14d3ad01eec951d87d834dd63349f5e21c321a7cc091f349876356bd0cfa0e8edf7d9541944f545b6f5a93112fdf317d2efd7cd38df345d63e43546b0d4d53e0622a6f1d4b0b8eaf40816b8440734a01372863fd9ac9ea73fc5c7d09f5d219acd83105fcabf32ac68db1626e9abce608f35cc3d247e6e7dc7e55f8bc54727af9b498b7d9e769578d69797e897b4c5a1eedaf0c3f24568c3934420a8b31443ddacbf2783d36a75e0e17f760374f156178620917137cef7b0e70f9c668edc564db954f8519d6f0fd6e8b9c9ee0f23e97d6223e79424222e17cb7000a47af7267aca7b272aaeb88ab18c3a560dfc69a56f1dfb5aeb53bb798d317b88bbdf4a128754153c27a8d8ec07e33673a8734168f719a103b009f371ae27f987eb38de869e2fb3c5a2a777580ff896fd64e137e98c3e83fd49325734f5842a157e896c2a5e67c4f5407ee9efc56fe6956e7036dd2eafd1c374a682dd0a5a91e5600ca338f2fb40603e379da30bb80af11438bfb89c8ee7a3fa09ac7387596dfd51c378bee544288c8c444844b3085de144f02ad5ee5407e4a4c935cb7fb8788309845a42d6c10635a900f497bf76bae709e0f160add86771030373ee4f97062903b0ab6ea90e91b96fbdda3f4b2d1d8b8b147c6fb956538c21c2ed8382e92657754ec322b9504580e256825710fcdffe762770aa0183bade97a3c562a32166ec7d22e2df6873582ee275173871bafb40325455df7f2a264d61e01638a622e2d1572a59bccf8d2aad1bbb683ee89404d0095ec081ac96491b88bad80a1de34a5bd5ccc2e9c412d2f4e5046844bd3c0f710c65a416fe4f77a4ab95812699c5896743bf0345226c1a232978560f6f92a4d8cd04fea39bd22180f261a71ee4a1cfb9db72bc47eaadcc309814d2c213c484a8ae4a1a5ef008abe68113fcd453fb2bbc90aad9408c2cf928e408c3fb9ef2092a582e884a7635e7cda592e96bb7a86545800e176aa780324ed5cc73291610aa0764fc059f2a21f5cb91508aed58a26f08656566891291b3d97aaaddca8f91ae8417502778fd3139cf1480cea826ab43ebf2a71437b2a2307f85d8ec308c62cc19bed9806a5ae095afb5293b25c70b307d7a84c0d9a338ae3d4014f3b1d61f6e630a8237ae7bf4601d930d5f3a07a71194b9e326a2f7813b947a2c2384fa714455c4dd24c171f89d19c6fe1bb0f7d3c3214cc0ec71674c8673192971872df4400f71a1b9e1d6a792658c453c8d8cb5fef776c5181e665972f0bdbceea35dad503cc832d0d3cd451e3ed61359ee211af7e095dacfe723fa89808c0ca39bfa21adf87d0831102b04fe1d04f9af69b899e0032c4cb11209513aa565ce64a5e7f82c6cd641130feb830bd4674de33d8d43ad891a90afce85779916117ca548f6d0005b1ed834d11835f3ebe2f7e1835b17879cc07594e65ff75ce9a3494c88a83a7d4200d1b4c304c32358b8a66c6ab35f964a4f2246cfdf2cb88d70a2a318bcfc358ad7d402723e5d273a33cdef113bff309bed509fedb06ae8143b592bf43a0c982f007c9dcae326402d8ec8636fef138abaa78557b69520dd589a70b38c1bfedf06396adb1e435c688a2432981c19129cd9c882950f1c0beb5715ce1c74a5760e055f385ff6e334d67e945c85277d0818debb1f9ac4a6d2e9dc0869664391898cf792d9ac77408e645e9927fc0d69914f7bcab27abf75c5516cca66101ebe562d4e28f5838b373098e6f4411f6b850686664b8c16035b6529a4aaf130bba3af7b6af05da187c4ffcbc4690b634386124cf1c0b374ea4e6580a9cddcb5033d5203c4707f82379b582b51b4fb219a43d9929c09956eb058306bf23a98c4f53b3945ce114a0dba842e2c2053b544ae6525432c395c9dbe9962550eb18e191cc752090c26631b06ce69e5bc575ac38e76b470dbd36390cf6fec7193f7c7a28efa5fd706819a2d41d2589f2627beb4ae0ff22b2ad75349c62d93004b1b84c903bf0d00aff29ed9d6046e21220095613a70c1c4fcd9f5fcf20c2898d88a70126a872139755c38fa7e45a76019a250595378d1e779eb21aad174ee2ca642915b56657bc2b96ead4ef2d62b40b1a643a88fc4a9d42a826c686693cc6b4d064953f034a277d04f01fb430222ea6f1c49b482adf67916a8c94c4e198c0fb925868313c34403a9ec22f5faffc8e0df52ea01c9b343c1a8960ebc8359bf9dd823ae28541faf145976ded17b8d75f8d2b493632433260e72c74cbcc79cafc5b323b35499ae3d537c8b66ebc75a41e8ba598a3b98cf621547d5b331d25d0c7582c17778586bdbbd8557334620f0b01877b20e49f7e19e870a58295f2e8cb48e35efc9caf81e3ec0989b62f7cbbfef87d979ab39e9b8940153aab52695d578229f8e61cd7a03e3b81f313fd931229002320b44a75445ff960ed69f07570fb960e1cdb00c7f34189890f1da1410bf715fd2e4965fef5c3d2a183edee5deca37c97edbb6a213d99a8610d6c112d26338550a789c16069dd1831e23786cf66e2a4a0f1ebaae916001186bc658ba43a2693897f15e08989c0e67dbb2920a6c19be7991a09de668e24ead41a55c1d7ab02827c2b04c6f6c5b951a88b7093316737f21b6b52ec9a7abf0cb9f681486a4e4fe82cbbf18e61e68548a8a7a624b07cf9c51ead2ed072709d0801134b2f25a762ed1041bbfe65e92c19b70276d27bcaf3595844b54d924dc42267ec3d75d26a2c1e9feabb10a255c32cd80ea5644c88bea97ae82cc102c7e1592adfb96eda06597da65652e57da5d44a44a49764543585a322184fa743db2f6d564adf430f6e22599875128558623d00fc36047653e770b685ad52fa73c6b305865ddd7f77e89bc6ca6361a6aac50116e67689bc36fe0a73fbff52193da8bad338593602d31423a17f722b71dd446d806c4ce0926e9fa23ea609560d287244a5c62130c77145bcfafc5811eae476f2dc4bdf98dca7d8e68b72bf8287d602e40fd6230f4f9b683078705d7a59e6becd0943f0efbb9f15f1069b0e5b3dcab0ee23b6c605d45e1fcf78b8434f548afad8d017c97ab599739989c21fa6ce9dd8b882d8068df8af6297c36a5823abdade8889f2317764d9b78d735c2c2c3e0036fc225e9bcc490bd49c0e5cc29f5c2345e20bfd316a100445a377b921a9a2393a941b13ebbec2b729cad1ca67dd92bcf686ca40748c3392398e677102a614ab1d648ce98dfb00baa34bae02258bb8e1b2b47921819f211321b35a8d8258bb6b7fdf517ee37686c9d7a9a08604cf781a085481691e08835734ccd9505cb3186371d194a2dbcdf7b5901d04b16042503422b2545cc2b1f947074258f8923a8502b552e2ccdb7cc5073afd196a7b371f857734e1a6bb160d42871e2334eba8d30fa407a91d8d20b9148d8ed15da63951eab36a5e07f52881fc394bd79dd333e01c1e708a8552177def64f9cac1285439360e4fee7dfeb91685518be968cef8d1c1f045fcfcfe6922893d18eb42c910d642894ae2fd659f2db25373908af79f4976b6302c4c057d7da6fb3b8f7d31b2d8c84d1d1875c197bb4b48b358ec688384fb57483334c3dac7b017a0b93a4dcec967329393fd7158aeb5deb1e7373dcc48b29f5c5b4103914c4af662f45c4cc562b6ed079f13060164a2c9e61eb2ee8c5b6d74794510df1e74b0e10c14189a1524f233fadc336d160be3495e46570a41cb9fbc5637fe0ceb84b089220cade5416862fda4c5d324f1a8c1888722cfba155d218544a4b940b51f7b7bea6464d7df96f6e0fec147a6e714195cecbe7cd45b639f3307ac522615a9ba2bea1faaea58e73753d1fb2b8b9ebbc0a2ebe3d50503c8b12b0f4f90b5321b3d3d0c71a151175977310e53aef4defdbe26d7b7d67456a6d338f8116653ca1fada1f58e4b9348a4e042875096ebc062b4ad67259ba83d5c09c85e6dcf443acb2c52b159203af0a5b781aa6bb95504fb77948530230f7439ddd01d774a990e925c7f76de800baf6c685a219836ef8a1bc4abea0a218301af899a84172f601f49b61118677a5b07a4f79e58020374bf25fd571e6d71b1090544ffb1aac1bdc005766f7da02454d71888a28dc5a30a94d0afa5a16f6898b81d93ce01c88a2b2892886b823f16c4e8ca1de315696330d1eb7101a6bc527724e6ff2f6fc0df957a36739a1663b984f52092a150391c8b58e20a3164343830ab0f8e843f1861e337dc7f5040bbbe052d7dc67d6cd62d8a759275ef00616d3142ea3a90f6496d0702d82078396157b9a8b3e74aaf53fe13873c61d9f8dd7d73b371848134b41a6d6c50c0f0db485fd3d971ee99c5c9402041278433e3b03a094bed28575f92c1443590bd835052fcb1f56b2a49d4a662dc4516ac5f83177ece521dbee3b30c2c117ed00751d3a14c1a165667eb0841fe576b69497a9a1f2d7d40818f0ad1ef2401b82c16c874190f596a12c9b743df1523d4b62dc5f0334391fe03774371d7066bddfd4304c477d046a2ef05a4645fa4801fbb52016a2820a8edd4bbedbba36c7afa2be2e0a60ac8e79ca89f8b7550248e4e1133904bd050167740b12bd957e7c8fab15dea86bbb1e9c02d01a5533196f2581f50fc6b612aefed82593bde3e6c479b6865180fbf47622c9faf041976ca291c76ead7bbc34c8d9292d5f58b04ff14e64081314a3b68bfe16aa649d7d315c244ff604092d93647ce7517446e2b1879a2c83246e13b480c159b193f9a8b79f513935cfe7360948f1433adb6e9839d33f93702a7d9ff22add00ab41a0ff4f35827df22c3ed28ef98f45ccc189aac72c2fd45345ce817999e3f48defb81b267f769fe5e1e401b481f6ab21a65c1c80bcc8bf68bc9891c5bf86782762ea5d948ef007af3eec26df7ced5158722b7e1732c96f19cae559bc07d967868e1bc854920e76470e6945b99812b1944ed5173651b82ac2ea413a80e6f1d7899ce05a8e1f3137b200260c80a6a3c682b6495782c32f5546e1a24a7e6382aab8209ba9e60d3f3ddd835c5924bbe919ad5279537d4823ac5cc5c7e9e68364ff2a846450d53ad1fea9d8e37783a2b3791c4826c04f8160d1ebae25b043aa2807da63063cf26c8cebcbdfbe66dafbd56d9c7428381f3ed293060bfec782a62c49371217546b7233ef4827812f0156f150e0438bba0021ccd940e8236fdfee6d9421974499f03709937b7e97f5f93687d2965911f3f32d75a3600f230b69e2c62060b78b6da16c357139dd87fa7f804d26f9822ff9571ccb758c0edc6bb6600a92e405c822e5c61dfabfd9a825387240225a1bfb002e004462fc6ae686bc6e55136aeee7ac3987fb265bf7ccfbaf82ce2cce0decb7c1f03ef753bf4a407e52f60a15303797481013946b41a199c702cee4182c065ec1c7309856a031c462d02d2c21a2ab45b58fe711eaa024ff61b53f7bb6ee05141c03aa02a5f952e2f8b96c33149effbe0ab06070cb8dd959a03e7f0cf49b48e7f119ad2cc6e7ecd81ff2362c964d169c160c5a1d1b278456d3d299c451e9b8105b948a050240f6534a2e1689ead03d93dd50603716f1fcf292b733ed5334aeae27480813f05387edc9f51631b537ccaa3bd1432b3f2606593c80838d50c34cfb762c245d1cfea9c22af7976b3718f5bbbc2a0f966f69f8c28749492e676f38ad7e141e9611b025206ed908cbedad75d8f4e83211c1ea4016cf25df47a28e98afe8b75c2fd7dd65ead208fdd97e00bf9f367c3024d14988d4161302a499217d33c0b787fc31147879f8b276597b7e454d93f098f772048b05c1a257be12d964885e1e693781439b330cc68db6c994a6a3e53eba570ee3af10236ebeaf465e1f8d874fdaa1a0da49b12e5ac2abcaf0b2bda2546a9ed343662595f5c5a4630bab88368b2c03f680b8b6150fca38135bd2c08727295c1751fc3bce2f0eec8f43ccc000a111b652d3137245e8e4d4f1af5f86103e940b2b23616415af198987f8c5f37bd19075c5454282e4a2772e7082b84e87822c0866e5061c7a836ba8240652312a5d3e9971d1c01eb90edd10cfed13382486c96e738719bc604da0b944c3eb479b87e4fc4042b54b7a6719b9b89b0380e6014ff64efc0a74ea453484a53719ac90997cbb623ea6aa1171c19f92bfbce6b1abcacc071fd563277cfc8d4efc2c5706ef8f0bbff27a7776e647f1f8535b446ce46e7f8c316aa30c43d82e58c81bf0a12b1ff4683b149eb456f83cb7e68b7c71afdbc7e5d1e847aedfb1f431c8775ba99749b116623625c38ec05b97a0c0826ff362057b72c192caf4f60d8bae3085e676b74d4098267889864f0858722dcb8852b9117fc6f243a0fcd329a806d9084959c91c07871f29034b9e4ca91d5ab86450bd6091d9b46bcd5d827b077ccadc900215a0dfa1aea7051e0af341c046f10315c09359a9ef06f3c22a2f05db12c4cad1c987f52c6f01e282053dcb47899c309ea60a53bba1967268ffc519c2734a5d45a64f0cece29972bbc8eeb99c5e8d426104cc50d7e4bd4e445ba1a9d86165a0a2d6cb926989bc4fadfd36b1db3b90841cc0018e5f19706d9310c05cc38c96c6c5fe542b365062abe98c4cdba97a5caedae8c54890dc9c07d9a7858a6972699d89170c4058dcd0e285c80b81a3fb501ec0095132df80c347c87da3158cf581c813c721d74d8bb9cf9d00d2beebad590375b4eb237c25169e0fba5115aab3e051054e2e04f6f0e801a8e455704c330a571443747e706d41238f06f2df9a423dd72ee88d8bc00c9db68aac589ccbd94dfb18d05afe5860dbb753568446054ab8662996623e99153bd9594c820095a56726ea5ef524a267833862dcd29eec93195df3d9ad8506bb725b0f074731d5dd3633808f86a023917817681b56d4ec4b8422c5c41a997babde560b70415989ae9eda62f1e16db2f14a773bb4f794011e5703a7119904ad626ca7d0a00b2edb32f13ef5e841f18fc2bf12481bbdbdac4750383a7fd9e6f25d77e4124c980f16fa7a16d1a090e3c650052d093cc083d36ed6bdd422318bcfc800411cc49bffbd1fd31e370fbf2f8fe1ed5b4f04fdfe30c7a7739a488c2337166855cab9dbee0d60fa1dbd18a55a3d6e4f782c88735a5304b85b33063ca6a8a50365c676ed8e3f32e7d0db3fdd61bc8e521d7ba53822b8021a32305de1d191aceddb8ae35baa86cccfc9e975bb35e92d20c7ad12d93b71258644d88a8702ef46019663c1a1d8f45f134e448166a4920d7454ea81691e8a0ea963bb07d06a77edfb930ee3ab9e54ebe55718dcc9723fc2b656e98d0375b6e61a82920a185fd65d0ca3243b853a66a2436e765352a79043a07507cdf1ad5861cdc848190375f607748b6f49727cb6fe22c085fdc39d16c0df1cdabc2f648d6759b006f8812e44f54605636172bfe7c332f036bb94826e639bad09317a5f4950d3bffc28e05ce5630511e92ef15c550b25732286c339f5cd4b339251f94b4c7d6140e9ae9bac0b75b9c58e7686bc38459dc1b842f8f9adb46e52000cbe778695a8c763b764c093084ac41ff3a43507ceb6cc2752b0c10e158cc400b41cb1dabdeebf167bf6afbb8addb5154488c935c460a90aef7fe5e84d7d300e99bd3512cf193c41eef6756ee4f6ec0fd9de4b3924c20a655cfbabd5c5a3cab1f5875b8121edf3441eb184f231b7c5303c1d6f44dc1b0652d9ece5559127eeb896a6589cf37370ae1c66e28e7f494af3e7d2e3ecbff0df6a97e701ae9c381e28e009f342d76db3b18a5f653c176b3ece6800e65f5773da8649425279a3dab06a98557ce4835d3de4ac17ca4f0a2b02cbe387ef38ec86404030f83de4c0750c56c8a4402702431dee3a64871bbe7e4db4f581ad8abd7d436ad51ae49a473452b8c7c11b929ed3efbe6b1392159fe0833c3a641a2f7f0b373d4569893f3ade7612824f27320b8e323ad48f3cff46d982d552dde12bfe377554d99fe92f6b2aa6a810e2cc45337791a256b2ff5e7c1eefaa67ab72afd2209665b3e4ee849e818628796985e7194b7f8b66fb9e3ad23be316683768105c237f6d915534b7fdbb439844ed71740d85d4cf1e7c0fceb01fefd81e95059fb486f225966897b18d02cba011970a0a2e60032ede86be3657cceff49042211bccab7c9d53eef3cd7033ada5615cb9dd51f7b4ca8fcdcd63aed66f264ad6d489f0122c95eecc605125212429345cf758b2b2b442d6b340e94a703ffa80339d16df1c340c46c4ce6220389f2d9e15572e735b2276bc24d72c2efcb7269da624ccdac8446e737137f9bc8198cea3d5ffa413f0a41645786678a984cf3c0ec85cdfdee49d9764d602d3f0af780c27a4a7a9486939961083b181f442677f01d134daf431f9bc8286d74abe9d63f702cc5a6e820edcfb9515b5655c067607b0a366ad53a8264324a4ece5e45d00ce2f8a81ea3d55f490f1c411184e72ccd81bc8763450726e159714ad205a2c3bc8db08f7f5d9504951f29696855c8a1ba35cb38a807247215a4fe97113aef7b4db73941703a76070704da5d53346d41e26c57fe2f1de1ba7a55a3ceb1e65b06a171acc524f6b133d619c58b6d805a10054371b52ee8da5d33dda6e1ec850da70b95c29d2d3313fb5598f9c5e159c0dc5fa5e923e918ed452e992742b7ab310473e5e2ccfe3dc35a673ec3dd7891a78871e9ed2d80073c4000b44c14baf4e29a8ae21d33d9db969bba8228cb0dc985aefe76d7bf81aa10fb6aeb61042720105fc71bfb7f241eb4c8a63744aa9f4d52d1860120f42f38b4537b1e372cd36c728e7cee9f7f9184acbd74e69a9c3d3fc4b1f0dfeb50efbccd9572c25a0a040a36d744f860922c8b8b1032355bb71b0f741d307a497260b94c95eb655383f803842a44106b95677b8963671230c2876879c1b6287e0786ebd9f49ee1b86e4e8abde24658836271c35ddbbefe11ba3969afb890789b2dd146f91cc5ec1c3c6fdd31efd341be639fe8da13ca81fb766292fc9533555b1d835fbb051c5813d236863cbaf1ce8cf5df1cda3ed63b2840f41ce4c04342ddc5120e3b2440e949102d2ad227816b0a50d3e0badb39159ece46177b1be034de05385b803f690dad27351635857599e1a7e771bdd2b9b006b9b8e130b21946aa183bd3871486976010c3108e76dbd36e9528d884daf923d31ccb3b953a8625331cd7759676d6d25e8e7d8c3987b65fc50ce20ce5a6a74de8f48e2eb65579c9e87eeac58f8d4c7a065c1ac87e055cf75a140775cc1455f9e6d539d8a84d37f77591912c7a3dd88c61a923aa021b2543fc7fa4b876a935f3d8675123ad3b6eea7c0a85bb55dfc8182fdbbd28125d22481e3323a769ddb8e398feca7f4f6d8062eeec6edf047756eff6573ba7f4a6e0783e952640bcc129419665e345dc27b9d4b93de978855055220da55bf6a8431e10f852e2ee41daac2709965a83c589c33feaf2bbefe071ac7ea368370b89c1881898593a89c09c7454d9b415f608dbeeb20bb4553b88bac0a7a2e41c93f61150813c4bbdcb397e2def90020a08daa1c5e696146831afeaa7287fa15d75a90049d2090d478da473013e907d11d0b77e436625efc4284c69fec0e7a41f858a0fd850014ee1aa06ca4b5ad2405ae680cb7e6fe1f3327a5c82cc8b9c498f9ad052655224bccfae591ec615f48029102d1ab8a18278d761d6f27a00af85f932ba758a9919b664c757b0dad18f15cc66bc3977271b92a04252819c691578fe0186bb1f5d090baf4f21e013918f4835399616293feeb41760faf7c4b2e5d5a89cddd48d49ad941796ea0e0d796992fc88781f31fdcd89aafe402888cabcb30b9987d44829d41f29751af233b6ae54a0d5719d1c31041fbfaea9387546d4908a5899efb1dd0ad4a8a81a41fec7293a3a0814a9abda11bf00bea1a237f3ec4181c21591a49e9b0d80b4e9e08c5486d1be9d3f23aa0a72488b13ea3a612f7d073f5132aec63a66a0aafeac29b6591df76bb3a68eb0cc3492d683b3e709d8c18d042043131bd58a8fef78db26a37d158b371bbacaa9d78bb2e035a6a70d74df2b0de1864a391e3a383cf7d23ae88ece3e9bb0c607a80f5f98f1f053fb920ab74a719340d10521ae0e1a1085ccb53ad379e3c77aeeed7539c6d4f4d6a3a58767ca82fb9b9b709c8ad8baa98fec7e67c906734b13d6f15483e1c482e8cc610ddf16d3b7970e65d4ddbd6fdc6aaa7ff5715529c77a85c2d85beb77aad34c67959d9b4f77fe6d23bed55cb34920f91b9f4ce3c98a1b6c069941240bb7ba2b1351eeb3ab7f1ed3f7e5100363d9d0b3d6e8be3b94761674227f02394794158db8ff2583299662128c9c63fe31efb66204909a327a5796df2d7abd412572b33ef7f690cffb949e1bc3b3f3b00ed7fe0eaebb8a977ededf5c9b16bb9f8f325d458b8f4c6fff3fe5bfbc60c3d50c3b61813553c23941acc0d477ed45e2d51d1043f8ba77800ff1ff6879d7f8a88d41fc7008640e2fb15b5f22b88b9c791e26f1d09fb6ad544edf29c707f981ca9bf61be342ede5e41b41cdff3360f38a1934373c904e0a9ffd95f01d9c83e9c278fbd897431d2d378111c182856d0b4f21c64e9b4550e36516ad792070c08cbbc48f0566e83d878fd759b5c0309d653d6894729449f301a1f89930383e3188b48786cd4b609bc94164684f95086531a01d3c6a7f72c1bd27e66a4604ae178103bf860b1473e5e2315fc30fe22e8fcc6a9759ed6ff2e8a83b3a75a8c0c9eb482db5e3f43e06fc57239538a6c187cfa1e93bae8e3a0cf9e039655f446ad628bded924c06cfdb16b20ec7cda6478ce4cb38e7f90518cf2f68f03c9b59cc6ae7f884d3cde11e3f32b47c570101766cdd755041ed40f3b2a44c79334df150f353c842d2ef8025b3e51a424b411c5fa405313325c6e595c792c847f76cf99a98d3cc590af660bb94aac34b595b7e0d8588d135b79969238fba37aced9a036bbdbd65a30835411e1069201356798f5df80e8f8f0117f38df58d8bdbfe8685c0e0248c0bc9a84377168c85010e280bfead31fb48a2b44338efae345f45e36f3710b0c794ac88192c7c1fdeaa232fab590d2e33516f2e2cf1720715c352807a2649898bfe044a70731c5d9bb0f0a16f73aa66f2b106492b3aa41ac63cc7c4ea737961d3dd934c6e8a401bfff4a27d11e8cb5e53fa008ebf1dcb1b6806856bbc3dfec53c60dd15864f020a88a29bab4ec70b9a6116b01bbc8592bfacb9e6e5e43179bc7be919eab4b9276e35e85fe90802a08a8e4b882968cd02a0ba6876088c16c3e9ffe12521cc10a1265bba9a2f7322e04587ee8f76db172aea587116bef2b436a6e02e0d7524cd30bbe2b457f92b0cbdff64d81adb95e19d5b3a645eea078696abd2025b2283ebb442ba4d8c6007cdcaf4fc9e7e3cd460316c6c939cd17976ec3a18a0c7d2547966e3453631ff5e9aacdba5c67490253c14525594d7b0c7ca8f62fe830a65235fc2a832159c734a396a206c49a8a8872633744795e83625a2d28245369fb6772550e97aec0639b8440c87a46c1f8dac73729a22c85bbe65d28115102b675898e4324e660388bbbcab3dba53764871178822512685147f13a466ae1e1cedb318257b061c918c910747f04c2a7a6fa95a8edf2253c4a086526208aff5ad54956cf6c4310e4da6694b75ccf17ae162c73090548f42417db6892d269b810078e0ed0bea93e1195971c1272ad6416b811c67e94e2733bd2cc36e4597b60a7bc504719ccbcc2c588b10a893e76249c22d593ed33bc498252ea1c3b274f929e62e289fb57bd1c48c5bbd49584c0b983f71f08b886da860c089962c3e7093eae3ffe88980b03888ae4d72ffb3106900e08732b4a08e9bf032c84c48d198a638c9a8ca26202023e8754d689f55b6064a216692763eb44044ed6e0b6e4e6a391852210fc1ca61436f70c8b422a6a54a8d6feee581edde7ca25eb90b01382ccda60de743e158fc7dbc0e22c4d15477848465b735f29973d2e0217541665caea8f7d629fa7921fbea0135a4fb6f098f1ac09051563550a2aa71aff2c3c27d1bb5835bd686a577a70536a944919f860efc800f63a66336998c5d566ba36ad8a0352b32eea3da24d6e882ce318a0f2e4848cfc69a7d68aecde5737472d11e04c69daa8f6aebee7b16d060fe2bedce4ee4386568d025dfaf17364e9468e25a86a2378a770170778f6a856ba280870696c41a6287cd64aa89729d3b600c92012e493e28a770e19e49864e5b6d4dec31758659f0535d0562b78548065f9f9a9d780ed4c410cd887552c88f1607820a0722bcad1eab3d0fdfb167a511a7c784b01521a145a69c1e781a0749bed3acb68d09e5e85299dab4d107fabb1494a8f9962c339e49d1e8c4a45a78358d119d46197db9624093ae69e6c220122ae0997d88a15b262425b17eb9e2e3414c33adc4fed9b100356cd87b5862917d2f30d1abe4cea433658c405bf29d659e881e331f8d3137d9a90e084503f861927118d48d34a0926952e4abaa0a691c0c32c906ca3ff2480eb5878ffa9c6868a5c8b88c355afe78e9c93bb7603ca30731f6187a1637c93988eb621bac108c59b643115e82650c58e807e422cad6dc4004a92c45750b7786c02383086b3d22873be98548475ca7fc53b4758f410227db203a789483100dfa1cc284dd9725448d6ffae7828d2690cba24f01279c0528601ce9cd54d98e1e69c558210aca8f26fba3d348ccf62a4b4032ce682f47cf4703d24d69bf01ce15db6562264ff56a2f833517c0725b9ae67ffea9698f655c5947ea7f289ce6131778227a6ffb60c2724eeb043025f13b9a70154ccc45e38d196e8c2df581a25cd5266d4584822c3a962cc563ee08395ab86743f0a7030a31a31a42c0cc97aa421c3dac7ce33c13ae74e29ffbdcc8874b82e359576005e0b8c0417f4e3664662abc801b51d0601ad22e4407e05816d9a04f2555980ef2d5fcade4f08bcbd1147e9b3a7450ae5fdc430660c88bc8d9c533e63e485ad4c325c55fd538caac059f079f192c173a2dbbd939256e12ce09990d8a6824da0c4e13fceb5d539a51042cd15c0029f090ad957b2eca0bb4bfe4cb20e1987b5e65ec4dadd52608dc98ef2d0273bc07dcd3875c6f6c217dd8b6c3a68f4d62924a91c2116f8a8001810d64c67d3457e033d018eac1967d391833d67e5e1797582f01b7cd6e7ef694036971b92f4dcda8e21a0b5b38e0d6143522ac8873d7d024cfe98acb5eee4930fdd563f6ec95af4a4def440f22d3aa869620eba1e5d1c8ea3a4d29200055427dc33af8cf46274f888ae625136aa1b3e5c8aa083ccb1333b9ed35566736377a6659caeb57f1a0076a39e7d9b043d02499836e2508b50f9977508a15204ac18d70cf6b96d8bae7a2f7ff143652843120a83120305d4381b86e012ffcc8e60e829cf88d40625ccc51b5f5ce02e0aea3867c4485861855e5261a7420c6aadd7854faae91c7d3ce5b68cdd13f70fb79e0da63bdeaa64bd01e0e3243a1e68d84fb7cbd4144be5913e49177f11a334a785a16734897609d44ecae847854cfd06617d10f17053540aa7e80d816accb5026c8ff9bbddcd81e22d7d8ff5f3211439ce175123e7791653e6ef3f7a1ff4ef413c405cbc3d6c4d9d0224358243ea850f782f0c372b073e476be90fc2dbe505f567be63337fdb77059ee8bd032781af355ab65bd0f66a36bf5eaf65942424ae07cfddd0f009e856c4fc457c1aae74bdeb2d342338bd1b1ecbbc7b3e20b291fa1880e14db5f41961f50871322ff7f2ee8eee7b39f913378cbcfdc29dd51c5f46967b34455d3d31d2d79e646ecded59079a0a63a8aa6f72f5c7f3dab2b80669635b0e314504e5070d620ef889ad5eb1e3a5bcd51158db0d95d01cfc2b76e8a1b3545158c83a89cea4c373e3adf1d9cbb6de0e72077c08a9d6903fa397b5be308a5d3d4098b9d5b871b0ad6cc0b43565c190666efe4536395f4d755b3284dbd985363a78cb3833c9022a6d34d504cd0d44e183e1e4c42efe39d515cbb2bf9a6211ae324a3f9549bab10a01a0200b21540feadb22ebd34285c45777d81f57e765e8769496e3016b0957fd05d4f44bbee33b466a437b0e8136154bbde0fee0be375b6a180d3eb77744ac0fc9d514229edccc81394ca8323103293810687ae38a693963ead147274007275c6d08c336d2836b5990a46c6676c1a1b8cea4da09f7f2856a1385cabde6345e588024958ff997d161bd7b64aea4f887344a58a2e7770a6556cbe8fe9c3effa6b5b390b688cf0ddd969d9e551f30d350728b5a4b6f1ba3d6cd5ff1a708ba2cb8e85630b7be0f042742a31e4bbc117010777ca19deb146630817a7e6ec0c4172c98b11eb3919bfbb4b50a4cee01a26e3e04990dbf17c8010285f7e26c06fda8a9221f9bdbce7f343c32706e1df84e58649f9c3114818f41bc3874cbb9c6bd9a3b2a282a8fe56b9f3a536a94b3260b6cd10d67743856724beb7fbb6bdc0ee563b9feab52df2aff86a4be1cb281f607106d807a33cd5f920b409d102e58377314ceaa6cb54cc5da9017a7eaa76e62601ad8f275bc391a411e60ba06e1dc19b5f09de974fbf10ea5b42ae00b0434d37ff03f189685bb3a4f9bc24f706ac348da61806747c7d1ad9da77c58763859cca894b940a85d47f4817f940a324a0c21fd6880bc5ec75032c85a0ed06463e408d22901a7ecd4995bcb46bc2e94e87b098ebfe9eeb9e89123d64eece05ede4f51e9f9bfcc4d63ed9e4f1544922161460491c01a0bee3d627d04be76de34610eb9182bd628e2f0f9b742f675103ba4be214ff4a9810df1816d181423742999491f065afe206dcbed2a9710dc8c16240c674261d7187927610ae7a4ded9ca05e1cf973fac9d4b5af73002aa901932b9867b8c806cacd59f671decce839f8c717476644d754e0208d1cbce0d18bfa86c5b23158160ca784649e6c5783960b0ab8eb8e4110f505976da1960cc077841eb6cbde6c3944af516cf723a3c2c7176497d8f5d55b3290a78f9dcc4f45e253eafd511ea5e78ca347d9bde943bffef40d6a86d56674c8fb054b2d0ccf43169b86906c971a8f88751df8fd4de874bd295122db9561a24563bae7cd8edb9ff352b7122e528106aecd31d07a47083b4794b16814dba5bd217b0acc67153fd00a1c696c590490889a014d03e5b4788d7c5eb1dd9ffa6bd2282e2344b02a4a4e60321e77ccec1acba320bb6d1811bd8d6945a14baf2cfad70a5cee62816c5d3a2450b94103446373b07d746c78be8011a85884832dda356635cc63a888c80c0b693a99d6d35468d13d6fa6d0fe10540231978732c11ac87dac58b19a3cc7ba3527f8a61e6eb3479743d2a83152dcfb31fe916154a5f9182bf2bb21df69d85766fcbd0c8623b26824a5aba002406dd8e327019f64e65799dfdeb3ad219bcf036ff62de1b38d8a2ddbe7a4b40b0ff50b25714d67f6e671ec6c84b27ba8b42a2e725fb43fd9803b6591c67f7fdbf2eaf02ef33c61cb6b11ed877ad6c373fbf10ca3f7b92d4619acbea2e06ed304bf02a0f08344969ff77ef311f970fc9fb2f77a5c5c5b2d3dd89d2848c243e3c34b25f23ed68cc69df4dd41d47687a1b225c7f5fb7ffd7e3a86e678e8973e66e2f0d7583d5fd72eb896ecf479bf3462dd59689fb5a7f414c282f6829d6eb599e1b570391394d638d4bc603ad3201ca25272d640c62e04d701288295607ffd0d8c7bb8658cd53f5979138570473d6153858fa90ddf9315cd4844fed0cdd05895bf34f475b2691a6eeab89e019f101e6fa6fba9b7342d347f53e4f8d11759af5ec6d5b60a412f1d49f16ad8f69fef43ca6d0d9c84f6102a7565a6d5e90c97ced33f20360f71f7d525203ce4b79a3e6db4a3c727ea582c7d5b91cc9c236651a32017cbcda15f623c0d87f7614e6b888a7c0c78384af9432becc473b58d8ca8f8de87b8c69a57493c0a4c08319efb4313e7b91bd9d4bd12a38190d33f9534973a08d0301dd06b53e8fe54ddf03d596c3746d923a333ba58bf586f0ed731be218ea1b1689b77fa2f6973c5b101f152fa8f302cf037451d0808486393c3d06b98d62193a1766f4d9ec4e3843ae6f94c40da2c9ec0d6908a6db9bd9ebd3bcf9dff560e7795fe0ab2ab24ce3579847be7a8a8fdbf0cd96d41ddbb6fde64a76de6c9d3a73d59c3e6cf3330d561b2db720042592b29c17b781dc3f5b12918293b2133bd7d1f09d93e63f3f29f57d5661ae245c19047d834586b186eed742f3e1ea037b56d0145cbddbd630c6679c2cc40ae8b8e140c6706b9a77788fdb56f44b6b002211c7356119afd52cda04c6b92c5a613dccd349724dd0551cf45e29ca5e0262098fc4553ee142a26e93a0ed1ef94dd73eae94ad1006c84cdc98f23b01fa03c3e32d5413bc9c7628b0d8cd6f0803410dd0af627c2885b74624338c4e8f1fff9dd753c9c91a1825ac531057a78d0a5756bb2249333fda5f4f64ee0feaadfe1046f35b547f83f7946de6ad4c8d80f4bec8cc6776f8936b53cc11d45c5b954060987e43700afcb16f7337e6b29831302e2df4563c9e688b9c25cbdda5861a0fa021d6ebd7a81c92f4969d3428dba10e732b97e3f11e549bfdc25e4c4af925a0b4386c1512f53b7f4fae1787a7a0d5482952049c61a344a78dce1540158d1e2537cbc21abfa8b68efd47539e67c55c0890e784fed602c8155750134a3037e82d713a9f90407b4bac3828a0ce874ef50b5a1674ca36fc54bf630cb97b823fb8d24faf919e6db2061fe12df5db18d581bf4cd9b51e2175d523838408370f3eb93f5421346ec87ed9d529765502d02028625c6abf44cf9b795dfbf78cb74733ccb465c0274e90ccd6a1d7dd05a22954a3489ea721254bff7c4797a251a06b0217a3e29fe1d2944f447e0368511d125f4865f96c11699abcb7dc6ec5b9437c370ff0597981036292094df30bb54eb97d3faf3e5fe449d0259656342173c97e489448cf84136a86cd914cae24202a1c8f2da0b8161d46cbb9ef179bb38ff5ffc82e9951dac6482b09ee5d072c51bd56a38d0d51c827829b899053ecb7af42de639fd53dcb8a6020cfb6ae169fccccc5186782d1927a8b1d9c305481e52ea3a0df90166970e49f134b7ee85df19c164ad8a562e6cc0f6d304b6f02e6575f187094bf364511178491e08a419803cc199968203db4519f8aa5e0e8ef591a30599a2d4b233201724b9a5efd5840af0f40a446431b0013b9e8f62698d4851c81684747785aa944a8b02672715000f56c915782feec3cd7ea9f0e761cd75ffb8d85d8506ee77583d4614f86a3965837787e1fcc02ea96b4db7716cfe40b72d3cf2cd75eb3438cc4b8f9158c1dd141bf532104d0a7daf768a17225cdff66495f0b3a6494af3d20de7a2a8db44dc81bccff8189454900666461d648518470b69e1ebf747eddf8de0c95f3a352bcef325e04123be242dd237e08525c271885907ddeb61b00653ab536e10fdbcbd49aa94864ca835d7ea8e184b50ba9d7189ade50645b6373dc3d7eef8a375012b64e6e331be37d6e82f264b9e7ebe509d398ac71686d276c29a3464f95f048a0e8f04de6ccea8ff08824fa9c73b00d2a5048aba441689678f7e4e9c4c91762a82076f7500e13b7d9759f2107b893c23c021de13e17220906282dfa9fee71f64cb5238486a56d94efa51fbfff11452a21646c31dfcee3336d0a84649b0ae6d78d076d0c3c8b7db836288a9e02d1181cb576e6f632c4d161d8c06afd6562371c16d67225197a5fa5a71a05d3a91835c080eb5ad80d7c237a1eb1e48f6ffd414ebeb2e8b930f11fc1f321d9813252d565a950fbe0365a6c714ea2d2b901d5c36840bc1c890031cd39c47979df2e38d20ac592350b00c5f98330556ce0148462f975e669dd490d01383a0c7001ba7882658f21363c1961d655e60f42a3646cbbf32f5223e0bffa8664b335c0f241222c564711163d016432a925547401245b77257f625928c009a84b1597926fe49465544f53fe6cc851e3e3b96eb673855657b0b2f3194456044e97d323ee4fa3ff8f875e1b2ec3650164b5c399ccb9be118f2a08157e1d41207f929e7f284ff9f83bb8e1ed3b903119da92ad97d880c4fc394c7a96bffb32b2d3e39c63790851eb0efba3300deafbb4c185c04431321af6a813267a6756d4fe23145daeb4922748934d21a569a323613f1503980094b0f88f4eec736d7bab9a941dd4fb7c8add8db8a905e2ca6894f15ffa650a80c12210a3976a552b4d581f437eaea5dbce05e7eb81fcd5f1388c475b22fcfd45a78f7f240eeb3bab2b9739b88cb5dcd313d047941041cd02d2f8881351a6d5d028149cb9165f00f9ba95dec1b90d4f8f4214c833a189591c849e870cd774da39d80c359c475c31948dd24021f3d887dc5ccf3dfa32dc220bc56257723f0e50b8612d534c2d9d566a9e34d3904f80f4dea5a78fa19ed049ddd68e6dc1d804d7573c9e06aff4567e8153cff1fb06d4c794343f17e7d26fba6532abd7991d1766701c78bd8b4563690b4e43120487036b4c0ccfe37c00a82262ef2f15b6bd77fa88a7113394137602e96d80a7cbadf61eaf5923346240ec56331ad9a68f0388aaaa0e2b0c0b06092e47d02d50f6a4b994aeed9123ab811fe275d9c8110ca63527b5b7b4168dd212d693ebafaedd9f60b872fd84782ef21ab6eb9c19da54dd5f66df8f932b97c3d336f365f36d91f6a7312c768809761889432b2c2db6326f5655336b8b60c3c7b01dfd67ce12c67af36540202d180da833d20eb64ea977607f830e551f1c90260810b631ea692319eeef427aa0b60c12109f2167913e3e3750b936c4b93cbb218f9f452cffcfa6643043bd96bf582fc93f6675cf82ced4458833a92e0ef6b2d49a98898c1ecca1c19ede40008680ff11bdc513fb144aca19ec61a86eabf343e2f94e843cf9f3ea2bc0ea73d126c6db0e20ac41b94bb7258f832d25067110c4dc452f0d25dd8015d3c94121eb4ffe38f510d44c1642cf16ff94771e430656f87f92412203d2bd12bd0bcd6866294822c3beacc60a845be1729fb68e6ae7b4c5b46c0c5e3bc422c22ca574414ee18090743ac04725041afa4cdb86b851081f80732d4f53f1addc8d2be7af5477a355df7bfd05bf2032bcb200aef2f65dda5fe0da1f7db2348485f4232ef6f1b630e7a724a0fe635de18783858b5539fd07cf51fc5221237b04a721c391f5d6e36ecc3d344abebe428ebf0082dbf12987b2ff04688a86610c5a96012e2d4006f3ba981d72bf12ab6895a57061e5655a228a69e45e039a3cf9e7d270fc235f4ea883d1a535ec7d9a76cde0d5dee933c64dbff0e82b1a9c3cb3fa55689daa0f4aa50578351f3db60b08eb8a206163ffd238637a48cbc35cbcbf5deca62656f85194010be02b7e4502bcc38d819b307d3cfaef8ca4165c299c3b888a72d35d2cc801d4019d90ea5321d40ac3a02ba978de3613ca2572d2f9fe33cfa4dcbfcfd22e0d76a650d42c2eaf91afd67ddb4f7e40ecea1fdf54ef51011257eb8e64f0391185bd98554968bdc2bdf2f009c38f1c41bc342f9d2cc3466fbca0a68faaf47f644c30fd9c44115108ea3c3c33a37c7247fcc229e32705f3ac7c94c50884ebcc8efb6723c14cf4cbe0f150f55db46682c779d486c2c0439234a4cd89f1e51d819ae1e46d857daadba88f390a9210204675f949186c2f6623c1e02d845e4ae43ab3388f0cf2dba84f0e92b0c97627eec00ace0eb865c7adb53d730ad066c9bd495660265ebc237d80249786c07f640cb7e831a32f62e1f6b70c9adde3d9de53bca81737b19f8fb8e123fbd0c74aa3bb9687554d553a661155fa72ec8e3fce8a54f9fb0a430b12e5e9a0c364025b202f27a3332522f6aad16a164a07b6e207f24730ef6c574fd0e7b606f8749366208d810c3a8bd15a71e678f9d26a663a2fde6945dd065967d07542d83d0add882b365f146cd753cbd184675ccb1c2b0c1b9c3d1f11eed33d887b35f051faafb8c9e5cfcdd09894436195f0f07540f96e9f8148c18fc0a1f582bb58aacaaaa814156ec6b7ea7fc18e2f7e01904b2b8e20330eccaf797be19e7fcc4b8fdbf7ccd8868d3827a6420fce223e50dd7516bae81781d88a14eb8ad775827366139ea68afe2fa8dbcfda3ef06c9913ae092a4227e11c7be92bbc4862d3914a72f3cc2346c381e375aa0377e55146ac5f1c032d86b5cd5744f601c0b1a395dcfbe84e6cf95f345e2ec399ab63dc7f9feb516e81e2e2c5c54e29984fe44480e32ca2defe8b7502d73020ccec52c1c7b6419af3ab78a3ba3aba5dc6388500f30dcdf8ad1981143cbba40bfdcac5875de18fafc16ce39a7c9a786b5aba7e87da3c4f9c7001c60cc2a329a8a281cb082c3c4690dbea73d588a1a4b35c1a98c5c64a9b647893bf602e7ff2e12e445d2c30a53c61331e25ea2eb24db623c171dfae6ac790e9d027a244c2feb88e69729bc401c4fe85d15e674fc4db948c25a84fc10d78c3abf00e92e3f3d4e628149295116c7b55222fa5a02317d045f97b0e8d916f7183a2641b5b99641c920915a249a0f97a120374c80cbf5cb4a5e1d281ae0d34271fe0cd3d1606f9015b463c6166699e31cab47f693d50376dc6269df87c788a74f1087a7b1a1b12ed97ac476c48544758fab1c314a6b6ac70e899b0ea2173139061a60fa7f0a3d1a0cc01c6b6f8ad6aea95c458ef75fabf29d1e2882ec28a83c47e85688f02942af46b260042115dc734a0b267182a0248ffcd85aa8eac95731f0868f4cd62584afc762f009d56fb1dda6c38e8bdccd8d48aa9b0e8649ba3dcdb82f0a3130c23fddd6b84668a0c25ad415c3057bd9129fcdae4481343350e6b97a7a913cfc0ff238a8aed3d0f0702c50703862fd687e4c2cafb24cef5904caa72c39a083edb97d17e81ed718e3a9ca8a7d5481673081db70aeebe17163917d631743604ab7603dbbd9f28354d3eb09ad887b41b054e7a2badf524ab13978e3979253135b8d83499f97d26e32f97c48768396fc10ffd5b41deb7b2b6e3bd83daab60aefad3f04d6a31ab8ceeb982ae6d754b2c70a1e20aca403eedd06f0112e10c89aa403ffffffffffff0f72a1df9a5bbfa36c43324949d28a155957d4fd4e534a29a59464d2fe41ccdb7ffc36951357119311ebb042f48efc28566bc96141a89dbbf74fa3b590c66151bd8fab7b565d1a6ab3449c0187656f51659a5548b13acf1ec40d12269cf18605a5943c2974e816525b1243419ce18645cdfe6466526850fb31c2196d609368d2cd36bb99e343b45727e1e9a5da95350fce60c392875a19deb3fa7ceae341dc2039c2196b58b6919de9ef56ea0e9b1a16a590dae64a4537669d4aa552691d8638230dc97a6d7a57fb944d22ee3b2ab4e792fd16f1f9e00c342cc676679649b39468fa8c332c665cfd90419fc60d42332c09a1f3cb4de6ac31fd679461d9fdbdb4d61fc36558c9b0186e3cc618d24bc9f68c61515d297b9142c64ef2248625bb97255b88b89abc61d0ee344c4f4fa38a698ba6eb7d6cfdee2055e36058509d1d4a266d37d5793de30b8be1c9947febb7f713173141397f8326314551e3c2195e5850f1169f457bb7feff8c2e2cafbcce19b3ff8a70b507677061392b29cc5cfa9f8aabb6b0fc295a4853edd102b2f16d7334d76d70b773d50e79f6f57965fa6670461616b75f44f8ea8fc73f61a14f4dd1d8cedd0fcd90ed4f33e2aeeea5fe8c2b2c7b16cd68baeeddbc9482226448ae17ceb0c2a29a3fa566b5eb9c5959a9a4a008194282f2463aa30a0ba23cac6e9d35ad92af33a86012d38ca7a16f5ee2eebeb76a75cdba14abd933a6b02619d70ce75deff26a5a08d55a5d874e9f43d26c9c218505a5740c552dff594d7d86035f3c230acb2374fcac5c4edbe6fd378afc9021a724290cce80c2f2471da34cc76aa54a6c5c70c613969526af17775a1a673861514c83ec983ceafaacd3863163db8c656daf7957a8199551c68cc592939f756efb18ba36424212c40d928a8e652cb8cc78277b4a66f2a4214b95b13032bf2bc4f5c45b55c2f686c9104cc6b266c896265fbe0cbb29617bc3640d6470e762b6a6adc935c55bf3a8d39b495b7cd6bff186c91a464c82542a6f980c513cc6d288bdfbb756bb2ba4256cc6ac2d25c249e989b041dc2001a2c3184bdb6922c4a84ba95fa618cbdbf2753ae5b29409173716741063695499dc8e2523bfe74739256c30890d635997d039ec33cabd1106a9542ac25836294b4d8bafcf4a864ad89607aa23188b2f6ae5687d1e6dc7048c65bd15772737298f17572a71d0f18b65dd0dd94c713a676bd9178b9b71c57c99e838cad38b6515bae3460fad5208bd8451da043a78b1ac74d239264e7b3b07d777b1f0eb41755c998cd964aa8be5efa0396c768c7750371874e462e95499e9e668a17e75e5206e9094e8c0c5c2e655de3a49bd2bc7d324b75814fd4966e84f1d5aeab658d02cffdd5422fda3a884adcff66a8197c6d04df3a2bbb19b2d1e6f667f528ad3512a15944ac5f524c5880e5a2cfb27fd9d3368974cd32c96fd73a68f2275ae0621592c7a4b57319b6349573516ec6dda0f978d69dc53346e97baf70da5f5730e8b459ec85fa993f248ca49a9542ac6482ca1082192bbaf58d425c75dad876873a95283c4150b422b213ebb6dcecf722b16c4f76767d23928bdae352b96fba490fbe27fdbecb48ac5a8a3a9678c3287898f2a96e5e384e9d5d8606f2a167784d2b331cbd68da10b80a001a405424e091a6baea003150bf6fdb1f7d4c7c8f42a614b1152440809c9aed10217d4600d186cca11d64eb19cc25595693c29decf0e850e532ccf47cf31eb09f9dd5f76424729964efc9f997e77cccedf408d4aa552c913212466b8091da4586e75e7ca9372a1cb8546b1b0ad994abffe24853cf518748862517b3ee8f8eaf8712d9433040d27838e502cabf72ce2b945c7c6204a1c878d4aa55269126b1d5bd0018a45a54bdbca7b7cf89895b09d9890a4fc1b69fd093edb4334683271f9f4948faa4568b375a0c3138bae835c5da545cb6afc2709a40d18542a954ea4e91a7673edcbb9cce6ec93b237debc4cef4ad8887c8a1092378420b49423468aa87166c66841dc2039d1c189a5ed8c31c99dd0d63259453c08425626e8d8c492686ed3613fa7755d7235da35b1a8dbcc3547351f674f995894ed54233d7bd0e246985810916175d38aaa1661099b1a97588c1d85d6bad654daa312363f394923bd111c305a6241975aa93129a9a42aa54a2cc86eeff05a7b72c2d3031d945872d1a91ecbb3a951fa492cdddba8e96a7ec6fd24616e13d3fbd418a31d4d7bf489ad0f4ad31189e512134a66ecf5fd55572a1dc40d12387440624964ea8e771dba745e8f580e61a21e4aa8f676c8118b49f7ee06ed496afdb2114bf2fd4c99b47d77b5296153434c56a69c3480a001440d206dac01c4c8a141a562e4103153d0c188e551d9aaf5f1d5db774c528aa8a1feac0b3a16b1a459ea18f46678fd61f446e268c349ec0b3a14b198eba1e5bd7ccdcff4891889a38d34e848c4e29d0e2d456388b9da8c640f3a10b1dc75a2eaa3e6294c46f3061d8758124a456fcc0ecd26fe1236236843d049393161a3523150d06188a591f9f842fd474d1e4bd341211653b62b11195e843acd1a1f74106259954eaec56698c7ec6a338865b93775db202f9ed615c4a28ccabc266390eae7c771925264c141a5920647a5624662697060ea4147209644b45c9d85f4395fcf24a5881a958a494a1121293a00b1284d09a56b378aa7fdfc6149a9ccadb7a5dafa9a04d2060c801831397941a562c4e444191d7e58148d6ad7d39c6bf58d9118cac241471f963e7d4ee74a4f26775907954aa512474aa5a2c6482ca508c7917226ab8810c387e577a55a0857baeef6770fe206890e2ae8d8c3b26dc7d9cefa45f20ea40d1800592a95f46afd0d2a1512a3051d7a58d42165aac9d49ee37a7958ec551dd3de9dd68c080f4ba376fdb5be380f75562a241dc40d9222e8b8c3a2b7765a132decd5b5346e00044f528ca01d164b69b7f7cf314ea8084f929214481b30005284e5890869038d4ae587a4a02328954a077183e4888e3a98339b34663b75b3bc88766690ed42f70619df55c2766202c719b248de103264c8efc5a1830ecb619548716e9b7747ec5c43c71c96b437df3e86174daa55c2f6cadc000d379394943f49411172e26de890c3923a1b75aaa2cb4d3d435e489087c3e4848d4a65d95086bc32214272b60c1d7158d8edd979d396fa2b75946a411121266c2c950a8a3a3946504f071d70585a9dbbd5a7bcd8b0a220e878c3a2c7aceaede2567fe712b6214788e0902334a8541a143adcb0a03388cad65a666e4a4bd88870463031a26d580efa4a5b678d5e916d099b10929322a05ca5c25cd0c18685572e36556790d5cf98a4b4694a9127f2431635e485a4913ed0b1862517ab750eb62f9bdb29613376dab9477099073ad4b0a4a156cb26a5e263cd256c4448c7486aa552a9e41ea9542a1555a45249d6f1041d69589cff72e1f1374546a8840d077b72869c84b244f821473d1c2747d25a10374854a0030d8b2d73bb34b7722964ec0ccbbe398fdcfcbca7319b1bc40d1220e8308326349adc8ce765f296c1d52193de5ef71e51ea20c362cc594fb3faf27c1ba5630ccba67585b896f921d6ccd52186853955baa575c6bd6e991e1d6148f7552bb96aa3be2f61cb65234484a01a3ac0b0185ea710bddd6ea3e316e2821fe8f8c2b296fef0d4dee985c91f0942507250a9542a448e14d9206e90201d5e5856bbb23c3588d7d26e4d1d5d58ec936fe2476cbc55a2ebe0c2a28ebf9fe99e6469d92a6133c217c193c7c1490a0eccf82405055dc71616feb647e40ad1f84d112129f243d8e2306292d4941e01d20610a44780f8bd0e2d2ce96f9f10e9da2e324ad1d09185c5d659dae75d5542f4752cd0818505e54a8f4eada37123661d5758d628f3e596ac574a733e5da0c30a8b3b9f3e958f8a68524e481c063aaab0fc5ac91439224a84068bfc1092d317e8a0c2a2ed678fa9a76696b153a2630a8bf342bcfa0a29a4765309dbda490a8a0e292c7d56f3f0f639aba654c2242842ce5c471416c6549692c26c7d672c615b45f244bec4c8397943ed8c65a0030a8b27c3d7f5cafee4327c9282a2e309cbe2853c33fdf61013139441dc2089810e272c8de6091dd97313f16a131685094d233e3b958c5b3261f953dbe7888c1e2b84a8cb121675d8cff4d3b9f5be7dba2861b9f3cfbb6fa55ca9264a1296bcbd377fbe9794d953c28624246f1c41aff690b0a0bae1951442dc6b1d2b6153c70856e25850fadc5fc4d75b7eb084ed8eb09ca2295eabfa31b45ec28662a2d2f42405658db0209a54c6276d2163747200c7b29a5f0f35face35ec66074716eb65061fedfe59a32e65e193687ecae6cc514394e57a2d6ca56c7d2646d314220b4f963ea7de189ad9634d53c236e49cbca18e91b3934f49c3bb08eb97a16944dcc364256c7d76842485c8ea348c78ae75ee30d3607e6f099b494a112124b947481ee5e41849a381c9b64994fd8834292b61d3932f52448d368a2cce8667fda8755017a221b2aca3af544acb77253255c2a63830eb14220b5130643929d7a8376ed49d3d2c6123493b2949449ec8aa136131a70dfde44a6d3c75b6401d362a159493ef0de206c91b4358f8b0ffdcb151cc2625dafe89493a214bdf695ca9c626dbd1710de206090f4a329d5f1a32761e99599741dc2011c21b0b4ac9a84a5d0f27dff113ac5747711bfad6677e0ef2cb1d4f4386f098cbb62c61436913a8e52dd14aebea7b8a7c4ad8e23843d0342d7dc8faf1e8f9735e47801653555b3ddcb57ac89c95aa511d4bdef5db48088bf16568eda7f76a9f1b21220411c97276dd3bcab3edc6bf83b024a5ea6ad9a07498c9a41a4058f43e559d844ed24bcb26ab881a494891c346a5c241dc20593f58fad672ea3fa6892fa5378a0821821b1f2c8d1077ea599686ca34da9e1bcbf1266eee9a293636b83d5856a9e4ea10ae358c58311bc40d921ef060318f6b46cd3227f4e64bd89410923712470a0369030640e228d2824a258e22a78dc5206e902c3b581aa956d785b8c6483ba083059967344acff6f8383a343fc8c19266199494f267a2af3b8252e38d22e706954aa58262c484c438881b24aa8d74cc6c68ad5fed6c4ad84e3e450d342a26a95241a9a471032067ec24c5880e38e0002f8d591bdb50d798367accbe7da354aba784ed531113ff54a40645d2d846316282831b2c78ce42aad8df283a8d256c1bb0819963d432ce44f7cc696ab091d09ca632ea1873ca53c28636831aa86370fd35a9694ec8673208727c2d1ed4d53be8eb6e031a3c9ee5f5ecc7d8495fc2a64c70b0061edefaad9567f19052cae40633306ee92993598e50cddd40068b31c49fd0e3ab45bc56c2d6c66ae84a69d111e1dabc75d7460c96df5b6936fda17bda2d41615b18589fe9e95343b41afb89989c18b1c3411a0b5e2b6367ad215e3f54c266c4e444995916bd95d4ee21834bfda512364941bb172cc9f98809513aa72f623224912421292705e5ccd058545a467dcf49bacc9a54c246c4e46465a5921e0e206dac018488c9491a954a8a0b2a150fe20609125cb0f4d1848a963a359af8256ced821620abe23708fb2c7a2be14aa552413d4931628405bec655d111799bcd5e6685081c43865416468a523722f444c93c02690306404e4cd61b47d0bf60881122424e891c29822944961156b01cd25b4bbb7aa8e6f755b078365a88949df48d27ad1a2958304f2564a77b5d1fd3123612345b4b0f470d50b09cb54cf1f29ce4d367256c679b4264e19e60b1b37cc9535ac5e6884bd8524e9a052658d61cbfef84188da2df218bdb975ce7f4d1e5a8c932a512b636eec520dde55e6697c1a5b084cd0826276fd8f19289d69c2bde5ce8974bd84e52507641b778a5c30be13a895ec2964264790e74e14374ff4d8bd3a9ec1236384ede8e7b908b3a9fc60fe399fe9456095b09ca11232427268b645b00040d206d0069630d20e975c01ac40d923570693f6e0eeaabef5ee94ad84e4e4922319f22e46407954a0a915541393b0062ee0890942344488c0671836407b76c2b6557f545bb74991236206dc000481f0192c60d800069630d2024458490183139517c272946f04f4c520671832405468272e48484440286e40887c8054a60242643484c8644a08201128060041a10019010a07c00041ff8802a7248d20321e880a16c800324abf7424e524200c4031b888006cec4e444021930921060400217b080052250010a50e00313380d48600211300818910718c99f2c9213939443010768a0012be548051840e448910518c99790902414214428a080dc0a24e008264648b10002560f0307e83312445262000c1400850023188091fc1b1e10000909087ea49c9c140f04e0360080226f0841c9800f4389e38940f2811e1ce071ca08119344426244583d23e9517807c907ced8800e232171533df524242947780ee4d029d81d94a1e3899c223c0c0f80c831801ca198852f5ac0231616a800052620810840e0010e68000316a080042080000310c08f000020478e1c3972e4d0b123878e3372e868468e1cccc89123478e1c3972e4c8518c1c3972e418468e1cbfc891c3173972f422470e5ee4c89123472e7220e0023c7220e0024674872306902314b0f0430b7230c0178dc0852d72e4c8a1230bbd7045912f214139a9a0f0b8c5197ec89183872d18d08b36dec08b48f0a8050f5ae42099852c72e4d8851872e400c2805dec60c02db4c0805bf08001b650430e3450941a97bd76884c86b8a016877098c0043c5c418b39f068052b04b10a55e4c0411b3c52c1e314a6c8918301b218461c455a7044120f18f129428a0859a3182264074386b4407d1f72e4e0210af5351832a4053972f008054a8e1c3c4051e4c8ca9183c7279410351af1297f928a98a091925a9023070f4f143109a2069183871fb213399a136b3972f0e0c32672e4388ce39c9cb40025470e1e98b8448e33724eda4051a3155ac8713a20928ea0d4d001ea800f95f8038f465022478e1c391832e4481a3f049d1493206a88490c1e0942709023078f49a49c98184129724eda30392992834fc324c8c32104c5c4a48d1c3978ec213c96b1a0f137c7cc9cf250c6d2d79d8ed5b4cdc27547782463d1f449d1a79fee83582d32963d86ec12fac7bc76ac54d8c0e318cb2b6d4cd374d54565ae889037849c986c21781863b1fd9352e92b166351b9dca831d748a53ba5081ec4587aa5655b87d722642c552a276690e0318c45257464d2ac26dfaba384e0210c4c630c76abc14333ae062d353a9c966e116283c158b80d9fff734c1b3bbc36a8544edc103c80b1a026dac5c4670f32837eb1a4e5398dfacd649e4a34ecc0c3178b617f6f65a8d9462d3642e4a42405c1a3178bff1e94d0a2bdc9737eb2b4a0c283174b4a6b97aa444db3a78c312d018f5d2c9be6579d75cf5d7e74b11cbeafc453eeeabc672e96e5c77022d3d746f91f2e96368350a39496d99d5e5682c72d96a44ea51d646bce4ae94d82872d96e5868cb265544a77743eb92678d462599d52df203a276d29eb4bf0a0c5c209d54a6b7f3d4a87cb089123954a1b21720467b19c7a2ba38cca3ccfc64f5a70b258565393dddcad35942f168be69dfbc6e55e7dd21932e4481a950a0a0f582cb7fc4f2fcd73f48eec9c9c9323f078c562b9d431e9737f6a73ae580e5959a9a2fff3fcd58a458d52833efdb66194162b1647ab2f4def52d2d6b58ae59c59671f2d3dc7552e552c7c6fda983d1f83e93f154b32c3ccd47c9a95dfa362715c4e5d264fafff54a758d61d5d35aef40cba27532c279375f9cae637955029164de5b5e3a7ddfe8c48b1a4bff7615f4ce7d8a1512c88559b5f09255d57eca258ec3a13cd29c308ed6c28963d26b9a6e467907a5d502c6e88c8f7feeb2064fa89e53c99abf2bb43d7293db1bcba6dd36621ef52cc4e2c8dc8ddfa9c6bd2a40c2796c46567d4259e6c85a9073c36b124523beba071569e6e6962492b950de284f4243528130bf274cef04a692d6c574c2c6b89b6caed29219abbc4b29c13a5e24dfcf76496b84b6edeec33c79c8ac6d81b34cac955af71255252ca20bcb4c528031e9458923f2f329d97d25a994ad84e841c232428879d24c564088a09c263120bff2f237e4f89c9ab925854c2fe7b74f2509b94256c79ea8f20248d3533121e91586cd50d277a5ce3fb4e3578406249add2389fe17396d3f278c4620c4aa5d4b5f24eec2b881b244478386239e87bce7c99c9657c2b1512c346f068c4f2299dd35796476f192571338c5834b15af7aeadeaff97c7226e8db39936ea687b768e6dd63f4ae68e41b74b79286299e636e4aade6f193384938837a6db11377b51d22b228408221242e8da7c29cf95b01941e9c3e310c6e6d69a631032b3ac842d8e1423445e83c0c31078fc6d19aa935208366db2d3e4b26d5be3a1ad9526b5df724e6aac846dc839ab011a406800a48d3580bc006f37881b248b072196336731e2a5bf45b6f5071e8358d4626f5b9e6c64ec773ef010c4a287fb24434be53a6db397071e8158dc8c19e7366fccaad3d9071e805814dffe9559c6305597112307ffb01833eebfd0da284cca78f86179473d664c9defc3a2abb99ed5ea2ac5343e2c89ceccd094516aeab41778ec613963c5f37e83cef0530f8b2ab44a71daf407d5681e9646346ece32297fb14934f0c0c3a278d6e82ce25d8492b71878dc6159e7385a66a1633d5cb6c3e2c638ba212b4646cde900081a406600a48d3580b81b78d46159f65febaa47656b4a3a2ce99acdaf9a2bb73c27e571e06ae03187e57dcfaabc83f094b29a030f392cadd45178d0555ea2fc22426610071e7158562a7dfbee368c961c0e0bdff69fb446e3b7d2a6a781c71b96540619bf84e97dd4628f81871b964bc9a46293148d6e771b16e38fa7bbdb8c3234cb0c3cd8b09c947aef7db51d75371b061e6b588e4ae43d758bd5ce130c3cd4b01c470b2d1fb2450ba1b56be0918645572b476ab9abfb3faa848d446d6fc0030dcb51766c0aad593faae47186c53699a3f227ba630c7998616935bf4b597d9deaea1978946149e814ea56081dbae384830c0b4a5efeec08ed3d61a301048d8d83c71816535b434ae5aa4bfdb8071e62588cc2574c5d73f0f4561896ec369a879455b31b836141de8f92e1336355a75f584cb71b32fb67993e8b5e5836d91ea174d06f9e735d58369da36c6c1642cf4bb9b0a0a4169ddd93b0d9a8f1d8c27278cdb1b55d8d788bfc101293222496060f2d2c09ddb9c76590e29185a486187b4f2be5e48185c5db91a3b3bf313347f1b8826e1e1be54b4d7743d745a7d049ce6ed36bb50c3cacb0202f563db77e94d2e51a7c1232040729425cc03ae4c0a30a8b23367afca8a34ea3691e545812532e94962829b3143122784c617936ee43fb88774735917372d8a8542a9584a35259226a09c7f921784861e1831817a5538657322b0a4be6de1e4e9e7d2ea187c272dc6c8f92316e2ed71396764da7ec51dbf192871316766673924f6a4d37aa19cb4a481f21775b87d44acc580e29ccb42aed2d4745cb58927ba35327376d1b3dca5812269e7fd5c57d6c9d8cc5a0a1f38376dfb69e91b1a0a5db4f83d0f4f43196c4764cb47fa7de781a63597e36f129fe7453098bb1a45a2feb1a2f9e1f23c672991a93f9fcfa0e1ac6d2f928dd3194ba4f23250c57c44e4743b39bd9c7e6e076721ea74a8d2718cbb9416cbde977293db473d8018c25e952d9ab2a11ba941c0d3b7eb1f0b9995ed436357cb1b4ee3943dd64838c380f3b7ab1e041e5a56b6911db311d76f062f14f08d7ff39da96da186b37ecd8c5e29754cf6a5386cc13aa547c872e1635a6bdbb8e5af2743817cb31aaeef9559aa575838be530199717951a55866fb1a4b4682d7e5464797e6cd16a9d87d8b69dec899c4a152f454588bf4f6bb1d85194122d4b98b88f2a413931a854f268b1244b09df1452e6a6ba67b1e89a61c7b409e9a263b258eee05de62eb56488170b53ecf355b3b6c9a986768e32a95326dc657783859e2b9eb1df62af311bb623ec78c5e299e639792363a57c5db134a66bd6c36ed4bcab562ce713f39dce3b562c6cea8d8b12b24593b963150b5abc8ebb1fad533a77627272f23b54b158deafaf2a5e6d274f2a301579ad8da71946b54b3f3b4b5d68d2d5f151b1a8ddd32af5bcd26eeb3bc5c229f9d939536bad3f534e0e1b4bd8618a6559d562ba74bf739e24093b4ab130da5bb6c7501fe463282888e2488a45cfea636a73d50f1fa2bd61c72816d7a58cf5f2f720efb543148b4969a952ebbf30a9b73ed32dec08c592b86cd4a85b5ecd4941b1a4437a4ea1312b79a3edf8c47249977965e9dcc688ef0b3b3cb124d47970a163de85cb113bb1a87ee49994bfab737c716249af6e255b5f6a130b26de9bd24e0b7f5dd2c4620c6bfee93a7f36a59958f856f74a6dc38f7b1ec40d12931d9858b6d72e633cc890fbd02516758e6f27d5d9ce98bec312b7bc6746d1cc2c6f4d1a3b6729ea4aff698c6109db8e4a2c9f7eff9819659ef5204a2ca6f454a1a7677db3b563128bde27eb5db35dd7a676486259c94fa6b4abb8c992ad60472496e3e6ac0a8fa259bf5ac28606831d905898cd9ee95b8ad5e29e4aa5523938fae03822e908e8851d8f585097514ff52fa5122bb32316346d345ca598be994f0c3b1ab1a0437e8e1d3f44241dc11823168592aaa34dbee857af2aec58c4f2071d234f9e291d97a01c31e2abed821d8a5892b1eda31acfd1636d89587c553d3a4d06710d3a221664ffe7d55a873be1c9432c6a4e5274659c3e5342432ca7342fd9a5c3ef8eae108be94d9c92327cedfd86107db606d518d6dd4dee5e579594e17163de6b10cbf9f4d48acc53ab418ac404b128d3445ce8d357b283815044a379c779666cbee694d284701fadaaa33001624188adc9fcf9566a7ba9e41576fc61c157d43b9bd4fdb0dca64f668ee52274b5fab01cc7d4ebc384f8b0a0616fa3fd646ed1dac3f2be8e1febaa66436f3d2ce96a9569c4461fdf380f8b1d4496cc696436f31d0fcb2d374be529f11d0ef58cb7ef6233f219a2f935a5eacbb41d9645774c3df2747f4c6ba5b25787054d5af6e269f479cce8b0ca9dd8ba06518faf8d6d9317b3a9b5bf65b4e6b02c6b430ba9f15a094d0e0bfaa5d3c8383a8378b5093be2b0acf32617197578bc762a951d70584c1ec568333d23e3868d0a3bdeb024d478f68edf3c63329529ec70c362083d0dc294942363572a958a939861471b96cfe6fdc36492e2e4aa844dd1de2822a4971d6c588ea7b44e2b53b65def1a16dd53dfdf6cfff586d4b0d85ada3a662df63b7f695892f9f37542ae16b7523bd0b0ac4ef3a59491b14da8cfb098a5a91572f74b2b3dee30831f9f257f3aa8cab0a85634676d5faf3e3c325ceba619c76bbc6d3644db69799fcd946e19cb60c71896476bea18a1994f8878871896fb73f468aa67f793768421cfcf587397d16e315115af56b6846ace656a302c68509af39aeb9439a44c6a61c717164e4d8750e13f7faaf5c262d2192d34e444544759efe8c2a2ab099971b4900976706141eb3d5da9b426f3dc99b0630b8b5acb76ec0d8d69eab4430b8b614caa6aef9cbea49c85e57b4d3f9b3a84cc1516fc34db530dd99def0ecfa0941add7f3a66a52b2c96167e5a7714e3faa33bacb0249f4e4b99f15beeef75d8518585cfa6f455ed4e86b8c3b0830a8babfb95689335dba754217112c30be206898e33ec98c2722ed9495c2a1342b770871418d393394db5cd262ff3a7a3dc505ab776446149c5d3a8ad2eef4e9db13fec80c2b2abf2cf25e30bcd399c840c4147d8a8542a954ac549cc8c9fb024a37ae149b5582df3b7c3090b6e227568ac08f9fa366341cf2ae131a7cdd0b967865d9f269bb1271a64c35de8f039bbc67a4ce72e635967d13198fad9c97d2963b9f3c72c364f7fd666256361e47f0a1de2830b17321685dc15a6e4bd8d38fd3196a3ac0c4268f4af15bf3196748ead5ab7af1ad1be188ba35e54890e21b46629622c798a0e2ef6d27fb486b118c7f7334af99afd0b6331a97bfcd09da7842a188b9921ca63f011fa4b09184b7a664e84eea7d650fac5827ece60da42c6a8c2e48bc591a3730a3991a54ba8170bb6a1dd937bac3c1df16241472bcdad7fbb6a3abb589ad79e32ce4629d3c675b1a0be356d57bc8c2b948b2539df59678f8bcda771b19ca349b5c1c47d8be5d42722e5aef0d05adb62394aa973f62aad5bd65c8b45d171b559635a2cdeb996327bbf6ff32c16a38f9907d7fefa49592ceb142e9a3a9d0935c662e9fb37d6e998a3c9a7b0580ea5a23da6dc2afdc9572c46295db7bbffaf085db124d37487beab8790c1562ca667f8d237ad5f988c158bffa65ef6c94ae1fd2a16f3ca38ee4954cb9ecc19aa58d6599732cd623a09256a319c918a85cd31eba0c5a3db9f4b0d79218c8ac56c23b46754f2d95d5c72c629164667791d4af5bdcee30b82b8417272862916c4fd892d176af50b4de18c522c9bcc5accfc6c4398162916d47f7a2de5b75af973148b659fbf4b4b6dd0fd8962c1ecf7c534eaa8a55a43b1f459c9d3bae14d885041e1b966e6dcdba676ad6928d9294343538de6d02716dc75e82d791a3d8dcb130b3a8954e1a65787145727964cbf3ed531c6def71627963cdf7fc90f3791d36f62d936e58ede285c8ee935b1e09b3ac3bf1622efa432b1bca52e4255be3af1284c2cae6ca6ceee76bab6bac4c2cb88e74d2247b9505962b94f87cca8eb396abf124bae45c9f4bf3a95525162c14696ce9cca4d9ed224167554697676a5fb6592c4d2abbfcc42796a59628ac482cb1c5246ebbce64b9058fe8daeca94a84c9da5472c6a7552d9780c559b428e5816528f6a2da3e1463e8d5890a346758b721dc277462c6ae64eb7bddaa24abd88259d45ca5329e4acf056118ba2be1ee3cbcde71d4dc4924eb71f9d44cb935311b1987baedfec64d8faf4108b2ecb95ce78eda1f4698865ad3e289959284fee6321da8d39cf273d2116a36cd450235f6ea66e10cba37dc67534d9a6844e104b9b5f6f387dfb4ae31788a55dd5cdf8292096b564dea049bbfa8a7f58585d233b47b4956dce0fcb5b424a2935ba6e93f761493dbebddcead73c1f96d388955ad727f91ddec3f287bdf5bc6d39df981e16f4864c9ad456e7ea0e1b3760630d207be48c3c2c7f5ab11b55fd95cc5ea9542a79061e163cc5e895b2d33d6c2638e30ecb1f76aa79648e359bd90967d861615b860cd2f736be9aeab0a8ea5dcae0a756e6937430ee67a9baecbcdbeb896b162f4e65fa90499ec3124b2255eb243666d6a1514e2c7796d058766253bd36b1a86549d3b97a93b85e138b39d6f52bbdc95de933b19c1fa3d09e3b798e8f89e552f17a53c88df9a74b2cba96aa56271fa9aab6c462d817e28348fd61e7acc4826c692fcd14df34272596c6ded36929a54ac83989e59f0f9759e36916da94c4d249fb4e0d5d456231e68d1bc446ffaa2e21b120d3c7f0c1644ea5b97cc4b2ea866e1fcd20bba523964cc91b59ad972ffe462c6a4c7b22d474883d3162e93bbb96276a27565fc472d47753e6522ad9392a62416bb91aa4db9888e5d5ba6432a974ff8b11118bf25447d49e2955150fb11c464aa1b65aa477898658f6af39991f7fb285588845331de6579ff6fc3924c472eb9ff97ded1be6e1209664069deb3107e5ed12c4624eafdd75e80462d14406cfefa893523d20969314523eaac888affeb074267a42449ac620757e58dcaedd9c5169afabebc3e28b93a94c77ee8f51c78705753f57cf2983e9e8f6b09c5d7546cfef223ee7f4b0644a475f74e68eb65f1e16cc755e7daccfbaeac3c38230d9d349b43e7b7d7758509b456ad1f4d96139a9f196313cdffb7c75585e11326f997219577c7458d23ab558fbd3e52edf1c165ccad8f1fe837cfd9e1c16e4e327b9af6344292f0e8bf359f5079d2d1ec583c3c28794f652b90a9532f786e59cd1a67eba5278ccb961416356a3f4698e67af362cdabdc61ff1d3dd2d362c7990c9f47834f7cc5ac39269e97ca9f7852e931a96f4c9e650ee725b8ad2b0bcd137a857a9530b1d342c862cdd39e674567dec0c8b5ae85acd2f21266233c372caa8b59faf5686651dde1a357f5778d4c8b01c93c637f3b81b94d2c6b02864920da9344b88d1c4b02c959c9c98370f0d5a1816ec94ac8bfba0a47b0686250f2a4ce9cbf8b4cdbeb0986d6336776e467b796131e6f471c5e6fb91595d3007d1bbf3252e2c994969a659c83df7b7b0589a3b497fd1aa99d7c27212ba3bb3f6fde3290b8bf946568dd04934762c2c8f1a1125751663f715963575b3c7c67bd36d8545ad934c6265ba0a0b5a636e84faacbfa642f719ab94763b85057b9d54654e4a61b94ccb890e657ab68bc2b27c8ce7a29594b63206005058d04a7bd5c9971ab40e3f61695b556d663ba9d46900e08445bd2963c98e4e33965e2b295688eeed879419cb4296cb579bf7e5f4b60c3ed4444c3698ce9dac6988d0eeba84e68d4e198b9f7fb3d9270d2545c9473216b4de926feaea44664862c85814ed5ede7994569ea5f618d7c7e8bd988ea6ec7e69ca76cef2a95da5ae84cd8db1ecf3ef724deecdfc5c8c0599dbdb3e99d8c64f89b1b8d9c3be799632744e7d0c6379b3462d8d396e3bea7d08c3b9d9e45e5b6aa2b69a55a498d27aecbb77c33e82b1309aa3d2ff3164d0f80c7c006371e5891bb5c95fd6bcbf58d0f5ce764aeb7759225f2c69cd5321f4c5b68b34881b2446f0d18b652f752bde7e32ebbd0f5e2c99dccfdb30fda93b7453f0b18b65139def7b2a3ebb2b5d2c7816a69ff737a80e251fb95834cd332746bc54ffb684cd71b12c4c8eda16fa5b6f7d256c7d8b0519354ee8f4a0fdb5aa84cd6cb174abb50c15a3d163524bd8d0063e6ab12ce3eb4f5e2223a4fc28b458d0ea95de0825575fda3c8bc515b13bf7a685a7777cc86251760affcf60327b2c16467a6971eeea4c63bc840d16cb4a369f365579995453c28627e424255fb1a461d44bcb5d6aeb57c2c6e68ac51f195c099dd63e750c4a2b16659032e7e82fdc5ecbc48415cb2594c828a5f44bd8ccad62c974879c7e5d26a2a354b11cc5b52b1d1f71ae33a958f290fb6c7ad387c7d5e203158b2a5c456a102dfe758a058dc935460a13d2a3bc84ad4db1d852da7ad29a73568a051993dda9fd478a659da19bb30e31a6e4a8846d47f1c7d42ccfdd3d2877b90f5174269e494b4b63345bd5d598e6323ec26c937c846239ea8f4d3eda048a65d58ef91eb3b5964affc4627a293c761ead63c7d380b40183214688a811870b50500e1bca048d4aa5623e3cb1a76bb097cd6ff1205a4911a73e3fe88ae0a3130b4ad4c49abad0dee255c2462264ad3435d2488308ca3142a57242cae083138b711fcda52c25a39b2d6123b29b58581115235f063bf1ff64a56b62f9367574d29da3d4e0d01af8c8c48292ae63fce871bb8489251d7e5a7ae9d5cf881c297289052d764273ecec937b0c7c5862f9b3b810dbc1bca4e8c7e0a3128bfdedba528fd7df8e3e28b174aed36bb54a739cc8580d1f9358cea069f7a9af32e75ac2d69258ac53216afb7184af4c09dbea4562799530cf63326e6ec64a1812444c4c48de38212109808f472c9f988d0b2dba3275658219f0e108554488118a1c49808f4698e195980d1dfdfd95b03dca902739312131728898a91b3e1881ecd6edc8a69df3b8557fe97a37e86c6ab44639eb32f0b188c558b222eed49b7e7ac8102133a85414b1244f2879f5e9d63ebfd268e023110babdd56f87d2b4f234241c4b20b21e44709a951ee432cea16ae2bf5454cbc1c0db178f2e2b4a72afb4fed74e0a3108be3a22f65e7fc4bbe12b66ec3072116d5ebf22ce95ae36774100b9a649aeeea5c9fa53784a05c101f82583a5d9771971e4aec5ec2168805dd5a5f5747b52e27402c9c681de7f4dcdcabb6842d51f9f8c392129eddb5ca5c7fca55c2e67e587ad1da57e7b6d5bba612b664c3471f16fc9496792a3cad945a09db1a0a490a8a4909c99e8910122328ca87e52c4ea7d1eddbba73b58745efd2171d4f7cd4bd7a585cad3e6e275a3dff9f87a5ef24a5a6fd3452d546f1818705253f54e9c94deaa7e3e30ecb69b28332a951cf48d961414f07e15aca6785dc7530dcc98ec876dce98dd641feead99c0e8b31b5b50e9baf6afe3587c5385a6a4f2bbf478f2b87452d74daa0b3361ba447921e0e1f71583a93d15a5ebbc82c49d85ee0030e4b1a4a6c0c7652bbd07ac3924ba14a46a9a342ee46213182b23edcb02874ce3aeac61895baa684adfb48dec0471b163ce6bce9bfbbb3f565c382ae3e7b95779149843ed6b0a8a3663ad551ae37cb1bc7393939aa06e4564bf436666e86bbd996d9542ea73f65d8581a96847833d935a1e33521263a20e2030d4b22b5d660eaef3b3c7ec4c71996b665786808996d820f332c48d9d193fee12f754d62aa041f6558f6dfd6e5779edbe322c392d051937adb0a99343686a5dfa47ca3de58a594db62583e0fb759bd3eed7099302c9bafef67668ebeeef900c3824e793a0b339da53efd1e7c7c61e9ed75e7183caaa708796131ed7c96d431cb5cd7fae8c2e2781673efd8acff1f157c70615906d5f273ac18d7fad9c2a2cce5ef9a59ea6db1b5b0f47df721c32b9d369f5958dc8eb34a6eabdf5a21161644087de76bf2ea5ee3e30acbaf315a97cedffcbdf8093eacb01c42a38bf6d1f96683360a3eaab0a434947b47511f34735458be4deafd637972e9691f5358f04fdd7256c675f9ef430ae64cd16c8dbb71ea35fb4a3f5dff6e55545bc34714166567d4e6d33b25f5018565297d3ef3e7914297aeb9e0e3098bf97f62ffcd43b6e9954aff890f272c99c66cd261dfe23ac94f7a346359c9acb4f0d5f1c6bd45e9c18ce57e71954289cee4590b25c564084a4ba1c73216749b9efbf97eb96dca58f80f539ec9a31e25c4642c09a54ab30c13f74006b679a79add2a9b346b549598cc31fdcb2d8fb160ca5cce699dde540831197a186349948e21f69de76476a5b91ec558b64f4297d0e9b23efc22463021314969206dc00088491b950a3196f467591e1b3a2a947c18cb4a26cd9db1b4857c2f8c651d6fe4743346a551d92318aec86cd29875465537d3ea6a52fd2d602c9eccb56de2f4fd07f3178bf995ccc1420f5f2cadeba8a92ab4379657c2443844d44ed0a3178bbf615ee95542f657ca79b168ab217a4246cdb32533f4d8c592add242537cbccad12d0e3d74b1e0762be3aec6836b66e6d023178b42c6f28ccd41fc948f833af4c0c5b20b2953674f6fdfa1552a282928ff8610c56de8718b45cfbbf9b436ad73e6962d16b3a9870e6ae3970bbd16cb5a6526296e665a2c7face9f5d6e9d4e6b3c72c9647f7492d21576c6a942cd236d7ac9965671a4a75ce3c27af77e62ef488c582d8707a5294cf06b5562a439e08272726454a124aa5b24ee050420f582c481d1eccf3948796517b74106fa1c72b166ba45cf3ff0c1371ba6251b938a932fd5f66946ac5829a67ce302dc30ab3dd6babe6d6b03937a64d527bbff9c89c5fc592f299d1d8faa2939a1aef7aa862795c3cbe4cb34e375b2a966596cd195c66a8ea302a96c48fe9c7a8158fbe9e824d5b6b1b57cf34cba65db9b579c5ae69a542648a05dfa4f557be947ae42e61334224e149eab321e706954a299675da7aa9e3744cd083144b4ae75e8a9b8ebad695b019117292823264538a08c9c11b425cc03c8ac5945949971a8556e266512c6886d0a9f756eb98bd502c6a27539fc6d4c713428210373d40b1a41e548590edd227f51c542a67e8f189e5933a0bd91f7e1e5c26a588902345e8e189e51ed75267daf39ef53ab19c844c3a7869d2b06e0f4e2c6f0e35e56ba71ca4187a6c6231aee798ccbe3fadf6647a6862e964fee9eb9fe80d0e210a5fe07de69989a5173254b85aeda8a41c13cbfa31631237dba6f7bac4621032d7349c29b5224b2c6effebe83f2d43a3a712ab9cdec6186563565bc54ed5dc866a9cdbfb9458dee8a22773deeaf87812cb3207294bcc7f8534690f492ce9d0bbca56e66ae624342a951e9158f6794f522b2db337dc9058ce31eac8484dca84d679c4b206f1e8a5aee7bd85d2a8542a151447f43273295da92292384e52fa0a3d1ab1982d57c6dc7f2ee3cf8845d5253a3ccb983e374bd8d0e238e97e418f452c7b9cdd5b994b5fa7b087221683965aff66bd6486532296560bb1ef2e5577577f420f442cac969b54fd70ed269a2cf438c4722b2da366a735dd6a54c28622a40d65889094238658566d172de4cad810ad37484e4c488a9cbc1a6c27df417a1462514b8e52bb1f1fe39ceb5ff046e2688383b84102470f422c77f816baa4d070b93a8358d0324367542de6f3b63d04b18eb8c8bdccc7b87dc7eaa05dbc7ca53e79842fc2c6102338384941f9428f402cf6071b1d55bf9651fc8058d67cdffe59da7f580ead8f1dcd46e5b558c2a6454c86a051a9700f3f2cbfda98c4ee8577aa911e7af461e9bf64e89c5c8c9b7ef161d93edbb9942e33bf50f7b02453acd2f0c2446e9f7a58d6f93fca0e5b652e5b8f3c2c6694f12232d568bd71206cac01c48df4c0c3829666f7eedaea1e8577580ce662648cf5597554edb0b85a3c544917afe386755890db99c4fecbcffa3b4b22f4a0c3d2ab5399540bf951cc8343e8318745a1b30e6abfb2b5c88c0ee9218705d72e5fea09b5a1a4f0c8903f31c2dd230e0bfbb13cde689a13d196a41c36b224e518c938522e7bc0410dd574f79ebafaad31f77854711b73ee162a612b4949d1931423263ddeb02c84941ae58448e96a2659cbc1a3380e0dcca5082922a4c8119247711c2267449e480f372c46b53226a9e46a79d4e9d186c50c4abe909dd5adea4c0f362c8ff96825b6a783de6f10ca1a954a147aac6171e3b484961ee21d536a58782d4e4bd159fd6a152ae19422271d1df419394490a4471a9653477850ebf2a6d58f86e5fce1a7b35dafac103ac3b2dedcd27d9e49967cccb01c45cb3f3467abd57a191663cc9eed67fe547325c372dbe911bfa2d5547763584e5b9bc58e96502f5c312c7c8e2b56bcb3e8dc6918163eb3d8acb569f92016426230e801066b6f65c3688cece8baf78eecf260aec22f2c86f49c44d3ea4c4a985e58561b333548b197d1378a0841393992fe84c4fe0db59c5f030d3480a41ca141a572f2ca2448e58ddd2b9322a96667a8a1471796464b472f99a37d90b9071796cb3d96964a1b1752ddc272a72d2db2e5eb7ee5f5d0c2b29c0e1bef31757978e1f81b542a70fc89137a646169ed4b963635f6c0c2f28fb6d6fd981e57406c3cd3b9ce6aadec96485b91aadfd58e2e991e565870a157ca0f9a6476ef4c624ce85185452946752ed9f11e54588cb1a23b22b73d8b70f56250a9748f292c871b19b3cce76e49d552d0430a8b41cadca5ee4eb57679099b322142028710c5ab978324d11e515854afb24f9c560d6ded081f83933782c91a3da0b05842cec3ac145a8d9063207a3c6131c8556d9759838ccf19440f272c49e92b3cc73bcaeb4f8ea41c6ec672d21f5b0dad49b53695b0a53c0a89391cb4bdc18319cbfd193cdea4eddac9542a46881c09a058ccbc1a1f75d66c353a9f587ce525640e328afecff1c472d8fa3ab1f3e9c4a26a7ecff2aa3168f97062613e2ae5725229f5966f6261769596e539ea8f51ae894597311df376cc6e936762b9937dccc23f475cc831b1a4f3b61a59cdb52de4975858a9849baa972973905b62e1a45c7bf9bbbeeaf14a2cc8ea6a3299438965f5314dc91cd4beba9358f216aa4f9d5c29ae4a62d94de9d196e323baf4482c661e51552ecfe3c93824163e78d41a95beb6f21fb198364a31527dd399ef8825b532b3721d9531a2462ce8e7e4f2994b463d8c584cf61b1e4d45b9d78b5832198f52a7861e9315b1dc31b8dcf8ccaf344ec48247ad4be7e8cdcd65236249776c539ab13ec492d07ddde967e7c967432cca18b3497d2b2ec46297ebf1d14a99e9141362f15e5f73a37cdb68e2412c7c77d631b2eab4eeb02096cfdf5f55848ebe610ec492ba884b21f24fb79401b118428aed90faf747ca7f58f619617293c8d796ec8725e99f836bcaf8a744eec3628c52a9da9451ae76cc87e5e049c6942b8318d7da3d2ca94d7b5532662dd5b57a58ff795657dada3c2c060d7f32099155e62f1e96a5904168970d23326aefb03c5a85ce8e172f4667edb0a8fb59bdfa6e9929df3a2cea8dfcec4286c6782f1d16fe930afbf4d974b2770ecbbaf327d235556879e5b0a4856a6af5bda542ba7158102e3b64126d59f2a3705814fd4929253b856c5adfb02cfff2c4b77d4e35ed86453d739a45c86d58143a830e6ba3abde65c36299efefea57aa7c5dc3f2a98cb9f4c7dc8753d5b0a0ea75cecbe36fbfd2b0207f427daffed74fa161514fe7d29a36af29d31996c757870a3ffd5a6586e5127de3ab3d8f6ba80c8be2e4bade0efac977322cae0c9929a227e7d53986e5243b68572a743ca72e86e56c676718964c9e1a19942ac1b0a434989677ea7ca6c92f2cb9cc1cf37e68d9e9e5852577d9da3d5ebdfa3c7661a1262e84decf8505d33d5a7b9eb4bcb48505992e464a99fd29a58545216f3eede356cb0f6661e1f3ee861f511b5f266161594c888e9b5cbcc292aa514fb917adb0d826739cac7a6122f52a2cabd5f64995d2302d2a2ca7fe8a931e7593a65358fc4ebbeaa371f7258545257a5264b767a1c5282c7d14b2cd6c95d8ea100acb2ae6aa3c741262f44f587e9d3d5da72e00272c67a1e5680e79d9d16dc69249d75bdb5a48612a33166556356bfd5221c2652c6992aa654cb6fa674e19cb26575de4edefc958d620738a1975994b858c4593593386d3ba4d4ec7585a2d3c99fe3bcf51c7184bfaff9ebdd35fcb783196b430913dab9f6326c6e2be692144cfb8187b188b4a5bccd37c979055184bf2b4d2b06b528a3383b1a46d6bf3adecac4466c0584ca15ea22ee59ebf58fa2e39af47c667b87cb1304a7355f57795ccf762593b6cff5385eb282f165dacfcd135b7ba3cbb58f6a8756309adf3b975b1a8eea14727114f6ee66251d8b98f6ef97d225c2cbbf86426f42b99b3313f6eb1a4956890adbd4147a94bd8e2782290388a11131283821fb658b0f711af3d3e976e45ce10365e9904e9572645127fd462e954a69652dc5decc94b8e16cba765aed4ef93bdcc514e5a70968ac481923a8b36dbaadabe6894d958cd32f4d4ee7eacc9ec0f592c0a5365ae3a37c8dbc7241a6cac01248d1b005103c58f5830ae2a2eb73963eb22a3a11eb56444c610eae13c493182b058d8289514d2b59891a255c216c7498a195b07718384053f5eb1b4c957b4fadf6cb22502a40d1800a9545aa003c41fae58ce9b3a88d82e4bd848549133e41cb662d195f220b73609f71c562cb9f0dc8c7bfb61d45bc592ddc9cccc6196b0191bc20f552ccb49214d4b66d2d175667a383c154baf22746f7dbcd05178e975d0c61a408ab098e9c0c30f542ca891257f62f273922b94532c88d11bfe520bf1639b31f9618aa55159b9a1aacb479cf0e44729964d3665d6ac5d099b5aca0f522c89fed4a7c5bdafae55091b8949904aa55249b31f829090228b148f6239476919b5bc96c9750413444284748620ffc00f512c6a213f85bcaf1afd3a144be2b5124af67678f6068a25995d6dd8f0394eebffc462a86bb966af6ffad713ae464da2595edf3544e75c5a6ece1ebb13cb1f5ff73b3e6ec5e88ce107279636a594c9d59c1bc40d12921f9b583a1d3fcf394fa13754a91c1c248e6204122328260b3f34b1e06af4939642e45f7f463041a3a3f02313cb9aae5f9d89ff7c9eaa6062e985efdc86de97583a9d53e7e4395a5df73f2cb1182a33eb0f79d7d8ed8f4a2c2b59a63cc89895fea0ffa0c4d2eb98a6be37223baf7e4c62c9dd9312e7ae57ab4afd90844193ddc87cdd9e99d6c8519d4f52660effcf8f482c9f566da9e4bf350a1948acfa6db719c7c63679ad4bed3228ad4f6c50063f1eb1f81ff48ed4933fd76e137e386259a696d13909f5a8b4da88850f52e9a9b715cd362316a5bed05166ca70a1d92216c48b8f8c21fb3767fc4311cb61c5fae8d2e2d57e9d88b434d3b8becec6dad3d97a61ab5c95d6c1b71f88580ec27f74897d98da1f0b3f0eb19875fc7ed8129fb55e97c9f0c3100bee9ec3b44cb3aa4c7ba4086f43ce912298422cd8cbcd76a6418777152116432951ae3609b1b2fc12b6bd810f6241e429a1372bc7576c2a951f82585ed5b9b47efdf00c9d93a55239275fa92421427e0462596a9549bcbaf41ca40c22e107209695e63b3fcd7af5ca6d093ffeb0e8a5a5fa0ea14f8fb87e5896531f7757558e5277c8f9d187859739f7d73c1f16558d6bcfab41f88cea33093ff6b038a6bd46940899f0430feeabd35176cef9a9f7c18f3c783a082d2f6e3385876db3b573545ec63c6dd4d744cffbf3e30ecb99359db497babdf3f8c30ecbbf7baaa693bf4829d76161d3cb482947aa7ac9d061518b4eea7a63efe1c71c96ed7d5669a53ee2da92c3b286c9088f2fbaeab43fe2b01cde492b8fb254faad7ec06171544b7fdd1ebdde4ca9c68f372cb7d0352bf5d7a6bbdf0dcbe6ae4f47cd2acb4da90d4bb6312293ea8bd332870d8b2ea3874d99a1e3b6bc06bee33ee633abad66075dd1913965e6fb871a16def4d3e383b91632f5230d8be184145f3d3a28f9d50f342c6b4d97426b6816aeb612b63f2b6222648dc45c0f7e9c61f1c48ee63ef5d1a5d4fe871996d48c7417f16dd1a3ff28c3e26e0b8fab31f259c6dff8418636a8e6cd6cc7eeb606977a5abb68195d5346436e8ff0630ccbd994fc95197b84081d0ede2822e42405a55239f2430c87968b1d5d1896621a326a21ffef223fc070542f27eb4bbece7a233fbe60ebdcc66f53ddcf9871e3a68ca1e5e8c6ff75f0c30bcbdb397b38fff0d516fad185a5919fc306a1e1af7b2e2c6e1ea9dc7fb43e4e5b58ce1ab40621a558d7911696c7565c6dcb6c884f1696852a25437e7b8c2d2cb0ba7d9f3ef72b2c88c9959991da39e85658ec9e4ffa465c85c5a04a9a4b5f25aec3545896ed425caa328f513a85c5da20c4eb98dbd7cf258545f5519ee84ef7afc61585c5a4aabf4a6b416149ce7dce9d95d499f43f9eb06c67ee992f579de77f38613154df484dc273bfcd58d2322a351fdf5f9dcc58fa1c99f97412224eb58c05f32edb1c6bdc334a198b9da9225fce5c9a52321666a52aadc3f43b9e90b1183cebeecbbaf6173ac6a2b77c36dde41942c8180b9e457b899dd1cf9e622cba965c69b255c6df89b1ac6544cc88573d1b1fc6e2acd966d67f42ea5918cbab838bb56d9de16f3016455d7c3495982a293016c39672d1d020645c7fb19cfccc940615e253e98bc511df3264e64b91662f96b588aaececda2e3f5e2cbbe9dfcecdad51cb76b19c231f661e665f64af8b0525befa36b637a9cde762419ce7d8b6932e3b0b170b22559ffdd698c7ac5b2c6ed0fba8566fdc8e2d96348f6caf916db67e2d16bbbe5fcb68a6697b5a2c778c61756b2835be9ac5b2b99062be5ec9f9942c16b4874f8db3f1b24ab1588c31dfc9ee91bfdd81c572f864e27d7514eff62b9693b67ca9a276c5c2bad0efeca832acdb8a25e5a75488334f0058b1fc62466f92a1fb39a602b08a5eebd7e4339b52c592da461dae6a747c52b1f4be225f4793eba1624967cea75f576a999e626964beba8e37dfa12916657c7e78ad5476f7a5585629b39be84dba7c522c7876ddfd2b65a6ac46b1b0f94b98bb8e49bc92289694c8244ea967ea0f85623979e8601bdfe547790a0028963eb33e2b2df654f314804f2c88ad932796eb4f88b8ee18b3efd489e5ec3166ceba99dcb58913cb651e7f940c35b2b46913cb716b749992e1f3479326f22c4b8d9272cdc4c2d8c8ef184d881715138ba7a536d1b0bdbacc7489658fd93cadad50328ac912cbeb2ebef9efb5085daac4828ac7fa4ea234bf9628b120550a1553b9e23c6b124b9a5fc744b8d4215e92582ccfdf4c2a676448456241ccaa2add78b2ad82c492d41cc59a14754a8b1eb118eb34b80e21e25b77c4a2f6997a92d13c576fc492b7fa24b30cee326c462cdf48fdb8f3d332c668118ba9f1e36ad5c6b42a52c4f2ed9bb8172b322aa2442c7af693a74d5f86fa102296d4350b152f93f95e87586cf1b9aec3b80ef50db198ee336bd05d9bd32fc4b2bdd2ece144f67c4588c5a4b33307bbd1f2518358f690d2855e5d1f834a100bd25785befc729d9302b19c25dfbee9ed3f8500b12c2eb35bcad149e8d01f16fb3b5cc8fd26371d3f2ca9562b32dc2bb942de87e5123a3da51825a5ce7c58d4f664a3396b9dce7b583c215ee99c6eabf3ea6139a30995afe5e485340fcba929e3eab51e0fcbf533524b31e5b9c77387459132b986d4328ad48e1d16b7ed5ba833e1a39a5387c5cf9a42dfbee8b0e4ca67837934f9e09ac3823425b370dd742f5f0ecbf32a334da9dcb8290e8be67bea36546cbe101c1647a649194ce959fd79c362544fb54ae6fb1ce56e581835cfd4c1b3d6726fc3c2bcd459bc523b1b96948ffaa8b3f8e47afb1a96a53a99e3c97796d976352c692d368ffc34335b7b1a16a50e1be1da63f0133b1a96d73e4a0ff9f144643fc392d868abd110a7f775332c6915132b46c6cbb0dc59c346eb92f9d3c6c9b0e06965cebd53d5e7c7b09ce483cca132e7245562583e61ffb2b52236288561d1d577fea0c49b3813181633a6cd28b1939a85beb0585a654e7d511e55c70b4babde47da27fbbcbd0b8ba69da21d663784ce85a57fdd5cba1e4e6c7c0bcb3156de768990216a2d2cf7e8aad2163ae5db5958d4b92bcc7eee4dd35858cc2d6eeb542835275f61d983de8aca18b6456885e5d13ad878381dcd835d8525253c6330e97d26c7a6c2622bd11aa74b53a44c4f6171b5147a93d62b946a4961316751adbfb2b3843e0a4b1f3ad5989e32f33e005058122956eff8aff89902f084e5d54a6ba5ba54ca300a80139684e8583a8d1236fa6ec6b28a6688ae8d594a3533165c7cde28a3cbcb58b8f5ccffcddff8282b6331ca937d52eccce4cac958ce2ea1a555898c85d3a419b3a5fedb3cc6c2bc14f23c5b8c7f8c8db12cb5b3d8e6139d8d713196958cd97371253e6d9818cbb1c376c89ee99159c358f0ac4b37eba03247bd3016756a394db23b8bad82b19cf24908539a2b3c058c25d32152ead58f5246fd6251eb9c57fb2a8d1a4abe586c21f74a0a155e5aeac56254f27532b151e58f78b1a419bb4c9f679d5f67178b5198e9a8a514aef7a38b051da4de75ffe869e3b958925b72f4499d377e8c8b65e1274f9ada66e5ef2d169550b2499b966c7d6db1fca1a5bd9ce89c325a8b05a163bbd4502efc95b45894ef1a153a3b9b94b3587eed78a695f89759288b45315a9fd4f020c775b15816fe526650d1a5b46c61b12853baa6d4303207d9be6269c783d0a9b5d6f531eb8ae5d23be739c768ad5bad58cef95ed50b99f455cf8a05ed2e424621b4e6f4ab581223956cf9952a16b3ce79dd4d3a5728150b2a85f89c52e6d39a848ac5d6cdebb9447a8ac5e449cc8a959b624928a121f38a198d7b2996c367eda8b35a316f9362413e87794c3267bcada358b2fd24ea77f4899055140bafa4fe93afc435c61a8a855979eaf37c496daa8262b974d4b2525e536ba17e62598b1d1952d46f99a89e581452d89e6c2164d6463b1190e8a864ed2604b248180a85028130181006a4e977150013140030181426114603128120c89a771480044a503c583426201e18128e04647138180e85c1a050200c0683c180502810840bc1d622362220a81f29614b3a9e12b2c71e101e028790104c8447168cc4bde5d3673996e5cd5799203f93c5e5c5c25aa02e440bae85af1866ac40d400b5b9583bc5b7e80b02ef83f2d030a48404e235168c959110a484042196f8f6f3314f2808f540c7f83fba40de10160e89d1181ec2460c66befd04326273accbabaf3e99fe5f3696173aab83ba11156c043f1918f943144c160194872789a7980283d5640a8a25c299a0151890fb1b9dcbc023113899050136812b2ea13972115564177bd1b014a80d51c19660b78cc4c8360860ded6a1ed57db387b361ab5d56d0ab6024d4157da946e454d7db1a24fd956af29ec2a36155b49538999ad8293470cc5031a83c076044c358b9367fca5f32aa065343599e7f41437607369801dd282d3674ee13571e3876a3c6b97e527392835a8adcb21f3155638f8fa002fd7761d713299a88e7a337b7db92e1fc819aed0c691fc3bf6e4be903558671124d6229caee642f96be60711d2c0e0a8b4a33114264195b39d3a89b0bbdaca7eb4155097fc8361081b8b892733f33850328a811ab42593cee100af0dd40aca0404024be9f446d0ae66f1030d68d3cf827f2fbc398d4af5322e386c83d5ede923716dd7a73d31184b3508752e0b65ac40874e7796f00d4e4575d9493678d0a55bb1e6ab9c427a69313faa8839dae2ed610c8c93248e394023dac83d4f74c5f3fe0db1cfc4d06f171f8fb3d24466d309923895de810b6ffd848a3f42db8c1884b5122954907e572b358dbb93f7622371e61f693d5a69dfa83090ef2c4d79ccb385a4f2b3d03be7a40196786be55347d790cc04a77beab6e8fbbdd7f812f3b4aa1bafffaf8c4bf159b93ad5165b846bbd3e49893e42308838afddcfc521c6f4d9126231cf63ee2dc456c8981a0f2ccab3bb382bfc3cdca1f582232907b1f011aaf8296998d0005a4f33e8c6c661cbc28bd2bd403ca5c5dc149191be4226d3944e424b2b680cc1b6c096fe7e6484810e4608ff8539d24ebdf13b5c672525f8d458eadaeafb0be14015b7a575af82330631c54adfd8bb795c0e607eeee1becf3bd7157788b9657d0a4e81be3f91caa38a984df2eedbff4e264377d439c9735ae0213f5ed17c7a03a1b23e5f2a4e2a39f4a5d71592e25a2906a1e088b89268893a5a12a8002f6c5138481b9cabb39f5a4ca268109492223c1b01e58313dd3cddf4477b77dde9a99aa2bc0cda6d83dc40260c0ba60ea88d815e19b69298468bb8109b4980068261fb0c5d699a23e2683d6ab342cd18b7dee6dc93a3acab5a5b238d56ff45df1f9c489091f78349982b99ffa479afc57bc81660c0349b288abaca603764f8c1cc48d2dc1f3e29ccca8d444b02df4c59387e55dd6064fe548b1305fa845520f96137d48e2374c29c8f7479ca9ae9ac748c1d9407feec012b09d12c25014b17e571768f69fd15c0b37d7577a28b1a9ecf4578f66cad8a8005bd646c7ff0ac444aa011806af659f65597ca150e649b22631ddca2b9c134834e54b3ddeb5a7389f955b3ccdfb200b7e61f67a1b22bab020fbc43d979af0aa36c8670745e9afdde34976c9750611cdb5db8649f64d37a9a62da6c6bbdd0e4dd188de667b669f8a8daa5ae30a8f8cb5e99a98f4855c68d0c5ffb51b060085aca29a4e1ca59f67071aeafe42a9519535b009c3ed34d7eeed6cc873eb192712933d30a409f3ad1374fb92a20596ae5585da9bf43840bab467f736e8206b1a05a315013a7e33cec7c6f5402b329602a58a6fde857646a896cc095e96e2c76a39b2e1aab1b3d13514c19f5c4ee94bc265baaae6884f9a548ca88998872dfb3a3502228f68f090f66c18eb110b507aa495424db0d1a0d14fe329866cc574368806b7a4959239a9b273cc65f2aaed6733f1da7627ecc69b64ed1f49ab9593005b36146d3758a265326b023e226810c54d684cea1993cd9137e324cbd26db343f36ae1200d1d152ba3d73c5b936853f508cd999017115a9782ae3d13de802f4dba8e4bdb3c2269b06700cb088001f0003f87d43d128db28a80834000474213cb8077e0c8e8cc118a031892820c00730c3ff608c8f418dd7411a5f83371e06613c0c6abc0ed2f0b9ba0377fa3498e30e1a59d68dc9f276634fbb758996f3488ffaa170aed6293af806056c4003f20109fc0c41e1e0bd210bfecbacf13708fb6111d66b50c7d3208fefc11f8f83313e828337a087afc11b0fc08117208d5f928e60fe48c101b891a48ce05f38024d83d4900b8552694957d34a2dbf25580c2bb05a0bba885678712ffc1a5c198bb1406b525144a0cfc45f8f2b86d3f5bb044e8b2cac271cf0bdfe750440106d20e8b6da8f9b513fc4c01bd0e00d08f0009cf03008e335a8e36990e20318f001329275bb97973c588419ea26e8225aa12a87b02e180d8119f4c00c5591407d944bf2924485946aac1cae25892f18400728c003425003a801413751092f580776b0000f50c0136ca01ba4c3698447f5d08f868800ce04050a7908a1911bc9e00d06d000c2e0384872f55edb34b4a9f3f9b6f5d3422c0a2ed5a34e0ab1bc881210f4dd9f12ab3e52f45a111b7e0276dd097b9d751f792cabee3ab2fbb3750ad94d04cad0a39a4ac1079b255c0c3da0c86a33f139c9d7516786168b4566ae32f8f55ff0483a24674000720a84b215cca01dd2bbefff6f2924c27e291aab0029d111f494eafc1ad41060d2b272c5f5241f87a378dd0c7e1e2531d626dc986009b0f9aa6e2ec927238ce339e155c065b23128fd4cb4637e1e44e870b499800117eac94a3be3b64e6d956aadebbecfeba88dc72f7468e5752c2a24c7f14f5e62139c3458a10aa9d53e38137bd63f95ac3e88070fa3c3cf536e80b49ceb26a7f080ed9183f3540cfeec0c1f2e9a62619cde6dddb724b85d4cc969ab6587f99af7ff7ae4ec79f80644b5b7dd9998bb529cfeab069c1645e34629bfd6000ff5cfa846e8f07ae161a4a642a0ea73380aa4d06e860fbdb6c953914821e6671e672cdb4bccee6283dd93ea038b0e3f229238a82859860969f848943fa8427a058a0f3c1964a4e244e769001f33e61427f7ab1f3bc16e3627c6a7dd5d2948b4ee1f822730264fe45814e8ee75ed6b5531fe7ddbc8aeaee506cdbbb9f5c25067865250412807799fb3934886550cae31376b94f0ca20e0160de806023e702e3e6190a8f0c54d0bc99fbcac84a1ae2118e3efff7d3d424dc6bc025d0686f9de248c34c7afe0b41561a6533a96187c88470588288f0d7e8323375bfc7420529ca8bf0d82dae0ed845e3ec18e2cb9d2d73a58b8bcfe4e076a6e4b61c6d7e9d8130928263baf0d105e05d6d9e2ad814a2440b92c40af5e98b062995c3ff3345df0cabdd53883e39936431ef552237a80614f3049a351e11029a0963c6d2a89252860aff0e0a105046a899ff4c29b09a322a4520a49af528902118940a63b9d101fd667d7514a757923400f86951731b7737f9e53b1830cd307d3a5a8ed60869467e4ad55893010830325d3dd87dbee9e8eccccabb9cf201c758ccd64c69f0ffd186329d3c8f8bad150d6bb0d3b4c097f07747063ccd3d4fb8ac12fc5126fef6fdf78006d70aeeab7d245ec423bd088352a453b6bcb1d5cc933b3f76cd9a47111498b74ab721e292e5bf448ed51171a6cb19ae24da0b70152da3dddc45a394287f1627621a8cadae89435b5bbab67a3c5bced2d0b352a2f5670d42ee2bb22bb2d6b31597e911196074eccf3f36832a317b5f32a3061248f05320b5e20e48f06ff67c31a27f80d1c1380dea44d474be82f17104baee423de45583fc0e8d704be9099f5460438648cc512b1123d9aa6e2679200988b3e8c102a8f0c9197b2ff60bd3da492d7e8d884a0929f53ebcb7ec9873702bef61e2845942f2526a536669b05d9368c1a92400174192291fdd30c65487d965aa31d5d360df68c05fd0b7a6b70e5c2544abd48b459b7f494ec08d3e2cb320fe7b5ff00600384e6c2d71ea571259830977a82985bc23561c7c2316863cf0d4f0ff6f6fb25da8f46e100aec09c629c8c11591eb9c741f1db54821eea9090d4da42b16936bfec840ae239b82701e2d94487d442b2b7936a7ade560ee985e2a977304b87bdb48835432098f9cbe4dcebd91ce8518f8cf8eb8e54b2106626ec22ac516104e07809deff975dce4e413f4a4ea5c02ef75300d517e322ecc5b1faac85704219de1317e5c7e0a576d86e5d21bc7349cd52e5f5e2366b92a7f47a9e89b08a72eef1effe470081b9dc4a997febefb259315ff3dc1a2bc16d922def83174d6e3a1643a1a2c3d9ad9eb4f3731c1f2cdcc8a5f6e95d188e75ea3a2ec717a3f7f56e2a960a151f74ce570f6a466ecfab39536a2ff3a975b1deda4fe344764c30a34cab3707075ea770b4ffdfcbdfc91cb9d4708850299b8d82c6b081c5de77ac4ab3b725f5d531af107914bceac5946a537cc23b8e527f24dc9ba9b3f8234a6a18196fdfa413784f17a3931be29ceff74e3107273502ecf2469eee45fec180263b19f8e659bd68d36e6482c01ef5167ffeda0edc2f9e6fd54a4df6f9d0e7c1d445a1b108cc0e79cfc915d01e21aaadc97cae919ca203b6abb2286d3df3f39906e86c108c34ca364e9e6deaf24ef06f7a563ea2cbd91c330210b7f73c7ccabd8b00c3b0d8cfbfd91e3a5222c1b8d2f7ba6c2deebf48393966be136c1a3035efa9334c4f516fa273259b1e10bba7d42e30060bc6cbc0ddd28790f800e2ce23e80b408cf2e817e77074e09a442e3911f7af231ccf04b1c4f7470dd269c74d06ac880c2ff69ac298c901100606c59db520d882e581af69862b2a9746bbd2737789eaafa4f83ba46eabb5103dda3a4c34906c126b4ab09f697268ae57a7b00a7bd14f7572cdc9b561bcc289e4bdddb51ea3022c8c91ba6fc1c644650cc1ccb61f6b8c8d656b00fa64f5fde624a0f0abb974951e4e3f086b0de499a723dea87090e27b68b1d6bc3c7200338a8cad853e0a7d5eeacb63067bdf6d329888e423d28b1ae4cea2810ca010de581d7b9f6fc63afd491a3d4f5bb1dd7a60cf0da4a0f873f7a18c91f36da6c5098914e2c901d8507ececfdab7c889b79bbf0ace350339fdbbe3412725058a65e723971b3a1bb5106eb7221755a9b7c9d9b5970ee6d105a8fe36f8ee80d594cbb877287467b8d622f8eab126ad795a2b33f8ad1018381cf5b9675c02e444a39c2ac66b3859d654d3ebde4d28b3f82f6dee1860db0ed968196c3c0cbdc61ad8dbe915c9e979aef36f75a001dffaa3d1c1af17740d35cbe022d0e56a1958cf2c832a4e32de5943eec218d8a5a785563075a3053c219377d7a762dcf4eb14cd4e9602b1136dca39f56610e8aacc2a4f76edaf031165c533162890084e358fc98691934249023b16a4c7e92a093d09ade2792d07abf20c9cba490ee805aeefcda6272b258818da5e59270bb8fae6280796bbfbaab71df81f1f11832651acad8dd3ebaa3b62aa86a13a0800b0a9a08c5838393c2f40535752953ade819ca4ca2d9ac956c444b74493b7da039400be8d8303a0ed7508b60e0434a8535afc3184fc7fea8cee0ea790621b3648c8092a6b517ba0a138d6230ecd7be370737a4ee88149fba6fefddb19e3941c143865e01b6ca041041395c277c517716e266e7469143058dc0117f441a131c17ed1b7b83a6614c6ef4b5ee022eab5f50d1a848149214bd4f922e51dc33646d3289963ad70cc3953059b8758d0573966cc2fd2dabac419473094bc5ac0feb3e6ca910c8252ed70c571ad2bd28195ef60ecb46e722695b7922fe5c92cfa4c5e4d40dac0600760da1a716abaf43edf3b14a52a07a95d6a0dedb204b46906dafd24e360ef3870c870a8731f7ce5b0e34e92d0ac12ab117240dcc0880b18295038441fe8a277c4c99fb041b03092978cc0afd16fef4194dc65607e624173a4e99560bad9b0faed18e9e1ff49e372140629a9b0839e969fe1add64f8298bb2746831d5d024e5d22986364e3cd6f7ebdd0ff68afb398636d1855f6062d63f9c9507dc31f46da736d70d18b33fc663fcee08b466c193cec7787ac05106d701fb07a8b8a20fb806e9af960c96fd81e359837be71bb12d39a835e660f09bc942e40a530adefe3ab2a9ebb549b53dad7e3ce5d7efbe354aa09267cadf87e58036239e7314a98213a77063a70dd091da7d5f2b2254221a6a1099c6e6d00b9b798763d490be66ab7abd46df5b85b60e7f9d287d0f189aad7596d3adb01ae36c36ef4adddfd16615e98b25111b4fd187cb6b79dd092d9d87dd3f716958cdc5084da9ce5a7434f135ecbba93267c0ebb41c8b7d6e5d153f866b39e635643a023fd82ffe1a4605aecc62f7bf52d2aaa0767a87e0715c2e11328d7376ad9123078503c3ce42e746fd22b73c8267e7afa673e0db45c93c97c218621d01d52d3a66417563bda792f0b51c360874ff28d627e10b426c9a887985d98afbfcb41ba2e0f0e6148af029df7af9d519f1439dd8bb895a8b94516b513f4c4a4a4410e47cd051a3377df02fc6fc0617540ba33ddaf999ff8d3c0dd6e6dd32fe2999154c8a830d56ddebbe488c4dbdcbb6ec465e4cccd57eb1bce45abeb481b64fa964add0da3bbf88d6a9cd4347e4aa25239b5c9cc843179daea40cb5bc51bbb3d229d05c135d24959d5e2fa9afddec5dd426f56ad90951b2adbf711634b3a2e485a9e7d793e2a67a7e8ed1e53da7d24b8ba464c84d3fa06fe6c984d4a530461f0afb9219859a05a28aabeb54b6d50d0af16bd0cc2d981990e85d96acfac9ea3498b2e0d15c79515d2a822e6e1a35e369594ab784924ed1765bbdbc6865a76448c297044d2cee221502736333690d1be924012e9a045db30fac04d30e732cb56c1154e135551b631dcd4cadd108079800b47a22b19873e3e3adc7840e7b27bea2f2ca1bf1fc98f269a754c50c88b6e6a1f4124eec373890d8b2e106f7e13baaca032b51e830836021df841022a40011d90011710800972601f77104801099003cc0264b7437af36a3405c28d281a494b21d014894a64f7d39d249131e32a604c969667d2db20cb786a41e329341f83732bdb23e0769784136c0bb445049fb0c37a8d60bc44c20c1c5cd8d617690640f9a23a3292ebaa83494b369de7c407600a11929915103e27cd2f5294b022afca8f39a57fb999b31649975ff37663c114ea596915ba4301b9349e51853c9f4d492b93ea38ed94198ac7c5477ec50818fc088a94c62570ae4b668a62f00d2f01314e00f6db4abe3bd3800cb3d483b0606c10813a500b3449f35da929ee0a3e912d3f4b4ca1a11f4c3229988f8454375156b1c7479a5d97c005b9ecacebbb1d4e0b8e7d9940832ff29765a989ead901c24f888b017fb28e7987c442d7b82324bbfe195ffd944a96c85418f121d0518da685ccf14de99597062a02229ddae0b215b10b493d577b93470d1314ed2bde90e210965bd8a869b7791c913a32b4a119c86bfdb51f572cca450ae010dc3654647f36c5a7a8b91ba64eaf2ff66f1f52047762ea9da6979fc8beea1000683879c32e3d25c2d63da2628dd55932b921b3b8ff42c29747b1f034e1cc6315f9384f4f186cec32bcd9474c498f53d2ed423562eb8845ad264622943b7330527146dd51f3ca21e56a0d9bea97781b0a68949660f93592bb7481d9eacc7c59cea71539ee0ab30153a2bdf93f6c7c4c0ecad7254f9cebfc116e6347cb9945574fe00f5555074d159c9ef9025675a9bdd3ba1b8854bf99548a527c6c64051d36712099c648ab1c842c35ceb4fcbd2d7d8a22323157f44b4677c08e8b2a48272e248be12b5f92df9822e22907c4b2f9ee7d2aa4749aabc7ea9a549eb582d5e0256fca1140e740e97b37d005ab439edabe1d1a90ce12772be6e3b65e8a055ead476cc03239e8beb42c8cd740531fae9e3e7b13eae6bb7ae21d2a74899b3ef2cee055e085ce839b875fde0126eac2ea5b72c0a2db540967a1fe41344bbb551b048956dea0399c989c6e3254e6d707acfc338db6699acf48bc620464b3f2fe24049322eab80d0704ffd4d566762a8e08051284ffdbe57730dec63a21b55de1fc1576b15d602818dd6690c504a63645ea9ccbf011f9d5e8194503c917186ef8bade995225fa5a008afd8eb521e49f75831122dc441891410c38014c1e01a0149e8708bd5251f64d2678f80b01a7d2f06ac0091e62610fd58afa3aca2c389cc0b2de5a33fab00d75fa7023d17e11c2f3230297fff2824c44d2790f53aae892c2a50e52457533fb422e6c8b3ddb2ace21339c30687a841a17b0a4674c9d3d86365ec47839c79866667158117ba1dbda37264faa71efc8343954ffe8dcf88d11ddc4a2d5f7f357e73f9cbbf2420aaf7449aa17d79887bc894bb6194cb7ef785be76681e5b0d3ddaf5209b5ccefe22d3a0c170887c4aba70bdf592a6cbda704e48a2e87eb55fae5b38d469406bbd3ba18cb93deb2a247b90b23ee8f0b4cd3059a7e0bf82f25ac6178598f525b9891ab1d6ebbbe11154b375ff456d3b92d4ef60f72d573c6c69a9400095d15b9ea8b77d83f84ea3802f80ae75994e25096aedfddda1e98a24bca8700598a97c81f660773010ed25de38c05fc92ca7ed3e598962010613e165aef2ef041f0097b701ea59f53850172d415cd02cb029461316d0708d8d572c37d15d41906c06851e1d0d6b37a795646a9c5bef13fc5517eade8250b804f7d925c757d9eb941fc3b6e43e77b8f0b69ab020fbb380cd5f4b3dd894d8721003b06d8245362ae0a220a989e0ec55d22ef76ec46de6e790a9c358ca9a200f580c0258bc1ef7688e7e872e8be06c49554621614806347ff566ecc60ffe5f9a3efb44aeb9f5632c45fadd92a79cb277546ece392e0f5a8d81e34bad1fbd999bb04831d36f69b30eb2b008ccb0da6f10d0b54285909d48c6aa5bf14b7fa9b989c04293c63fe5285e40cce531c8a8d2353f59de22c86cd111e843535e1ce26f38f584323cc7b9ba26ea2bfbf0a1632989680708bbb0ccf31e19cc5182818e2045d0f7afe751fca704afc1a92f43acc8cbae680334571979143be08147908ca5986da23076f44064b0ad4608c0a609e3b445650051b07c14b9b08f5f700be7d7a96694f1cd2e5f51cc247383a1671916ab871dbd8d7f8980374583bf8f28f54ff04703cf2edffa845b7a02b0944a913c31480d92a3f1866344809fd6bacc8405d82248dd58d980fbb424423408370136844e7f67e425c47e5525c28f970edfe9ccc13b343fe10611d7ae27115b237415643e446740c0d080ccbef0f9b154569082de1e0b716397af17900902550a30c192eb624bcb0f0e90de2fe4c6f72c8d59524ac0333bac8f86779c964c9a0c5ab0d06cb15b7a5fb5c6b3f0e00e0e7b9e1d0294baf9a3b502df9963881fc1b4fc1ba43fe10ea605df6c57d16b0d55ba379f66b4a24d185faa8e651f03b5982405d61f08b74f92fcd3bbb8bd0006d2fd1e91e75587d8bee909e904657bc03b7b8d74c637705a9eb3da0148a132baf428f5ec8ee58b918a2fd4d8d80cdaede0c9a25b186368f76434310fb98f726fce938b13593d1c141b863feb9eecd1b1f66898450856aa9afe10e41049fdea089699321fea67d34db17f495c78b332e72830ef4a81e8e579d2b676a6e39df7e794c9e17c8a1eca66e8c898e7171d2feccf8bec321b7e2af84b5f81bae1a69833748b3abfc1774a52fd74ea7a76caf03aeac830a87a940d55088c3a87a9aa5580f6968877103741c31e5834a6537f3560cc2e232f3477b1ad30e433486b3ecccb78a6da1d7e084f189318d6187211ac31923c38c720dd11933342605fdc6ce8a71c1b28610f56a855fa6a56db136dc35b26197c942a1c515e333e3691a81ac2ff63ac285038db766b250d9e84a1f23991a2eee3cbca47d783cd5ecbeac27cee215632b4a7283bb821ce3b4052ea7bb7088e9d1ed97aa9e2895216793b3a35cd83ef6beffe99482210edb116df791b77b1f0253239216aa5d1267022e50443fb4a206e9c88f62a97c09564345c8893462a3187510844828421c84a1294a507cee0d32bdc98a0f1c517b224ee5ed22d20f508dc2b3501766017002d2390a3fc4e419b0b46879a3c100144e150b837016685c5aa4a2a408112a55c261f3219618040def3c0f141bc2281a33aea2febe190d8f3ca91b58490b39be36401a501cb069c32cad4c6143078935dde526b7331e2eec38266716051b6f2cf8d5ca411ca5875b7dae5837edab0185744e27c4741cb1ca02c7e4331815af6e9560b1d714cc3a96d76b970f60df429b74a59bef34fa5b5b3d96e3a009d7f11bbab0880ae6e1eb0a00c5f6ee6655d4e13e1848d859411fa48738ae8df70ba2914202f8aa7b81079eddc84af1eb88f6f20aa18e7addc6813594be364f4f761b1b9ca5e348be0f499d467057bb342b4b8ca41d180a7e3d5438f9bc6b843e2a8c552864265804ccd3bb74416a158c66176e32a8f752afb3cf0e8f30b7f7bc8a9b2e97deb98edeb4ca4852266a258548a0c1b139341b8c0d8783eaa4e5e36754f0c011fc32e3a945deb416b0a8d7e0415854b2a88502c5ab2864c4439e54cb8d23737b09512eb63c6a4a13e30bf158dfab9ce28b6c468008761484323bfe77682ecddc63a8de5b40253db99fd23f68f296662f37031253d7346368498cf29ea12d9b685bbd158d6309921ae0002ea0467eecf837615888f64778941c2c4ab3ba609e023827b07c06a2e69bba392864b3554782a0420b8152e2dd6c13300b36e91182e4dbeebd0b3d88f9d9fce2e9d29da1fc1ca29c1692ee3ff7542eab20d2b0239b4c1709b2c2c63477f07ff7cfc84551f4c7e56a4718109a00d64a36605817d0397314f09f1dacfb32c144242cacc5c551c9fea2d025bee5e69d979ead6a8acaf2cd1df57f573b66bfce31786ab9056910c529436dc845a202bdea26b2e038c044e3f6b9e98ef42ef13a3630383004fe8854b33102e800492400083e7ecce9fa7f774861885f48457a6c1175f10023bdafa0f003de49e779ae890e1b8bf29eb71cf5b10413191b134110a7908409a97b01a09385b472506caad8ee691ba997da42e6f1a5911fd64986282ecc7ce221727aed5c996612c242c0fd396fd623494288992cfe9058a255d71c06d91771b4cc89d51c2abb12d6a1d14f48d880b8e05db7931cd52868c704a40e24a06f034876bfa635239b4489e35fc3cf4f311f93bd97327f6a8d6f6badcf51961909f6cbbc31303097d711495bca08d681314b95c4f417075018a3813e313e738e4014b402aec28715c864fde8862bd8298ebb1653d71ce835f79b2c23ad72cb8b8826e88a84184aadb8cdaa71526ec56b566191be5dff1cce35bb4db1ef5b96a4cf4c9577fb191ffbc0b437721b481d1ac70bad49dbecaf570e272b4e3aebaadf2254d6a492cb592d869b41bc950154f78e1fa74398be78479bcb9063722039f67cdbc7414e5031c99f3bfeefdfaa2c4cbe721a273f89b020f193437b70331940852af11f56c6b959fc79fbee784d3b34ca36ceeb712bca58470d3d6db0e792245de08d0a4f40fdf016189cbb3efcc7ed05477dac35bdcccdcb0b2a94ae1158f044bf731d541f0793d63ce67251a0d920126c796a016f5567beff370fcfbebf5808b46ef2bbf7d36799eaf223b6573b5bd64cc358303d38cc6a382b745944bab4c1c471c96b76f5626e0042e9ba8122c058ddd1069ba7f4156f88796b647aaa8b46a79c40f6957f33dbc4006c6793e24edf14464aa53625a5d49a0d0b3608d2f634ceaa2adb3d693a83a1ee5f6a8b93e8c0080c0d9adb286cb2ee542f9e4c29f2cdeb22d1ccd1e916f3196b58db72405f7b7a5dfdee43df09b41ec9c72489a9dc29e79fb4f8563600d44a58131252ab36f1fcf269188e60831097f19915cebc2447061d540ee87c9b94b1a31f2debb803ac8140b51d826d0d39d50fe4816cd0ab034a4f96b4b72edabe4f7ae1f01e73ecc8ee7e87b0740442a1f87543238e235fc357048520491e1c22c71678adb017997be72a45184f3be27cbeac2d9b9325b401f668f28d87153f549e9ea20ec42160b0b82427ec8bd81e783e9b2dfea2b45cea886dab0f6bdbb7e1a80412af54bac1e447102cb6db24c85223fbb71894e6f09a0eb679dd5af6b1333b8d12b5b2010a87ae87d41dca6a04f0d7a02db81c53a993864f4fa1fa0499f16de38cb5d826a15dd9fa9edd009f747a01abe2628bb030d5bcb0ce5c0ce4d8ce871c6f06000d65897a4d860c621c728e2a6066499cc723d71650798d48295089a79a3263718ad0146a3d089ad6b5e1809b6cb4285fc0cd06d9fe66d2a52056bb0730bef3e3d79f281922ccbd46861b37301f1b09e4a11d7f9b9398fbc62d85a7089c0c551bf4141abc36da1859e61f4d875d65e81c5ff4a3e55672810677af69aaea86acad3f016d9aff60d025fd4b8882f428b99b7bf3fe7e0954fefa0548b5ca12c68b9abdded58209483373a083cc058805513767ce0c956b701f0184a3ae8fa3db2c0e39110b826494c8f19263bfe1a16a29d6cc3fc4b2bed15e325f051f3df80e814658eed6ff9e55a60473807066062d80ce1a7cdbd597ca8470d88f6a31304fb4fdc2838b832f4e81840b485817faa8d3837099263a00a0735ea17ec91e0d8c6a9e7899941a66d0dae8c6766f6fa3a6ae9a3a8604cff33c29923b79fde21b5079f16fc0c8749b2f02f2f2543d82cbd283ad2a08aec23769aea46fef42981ab2464134540c6e0778adfb5c128b03b88be472021a6c80210470b371171c49d91d668fc0821411b70b5abb68c2974ac5e521b9a304c6d505963c0cdb4e804ae12c5033693a4722765e713111cdcc6741c6aa1560cb5cecfda7d96a927e4f57b98e4cf0f4043fb4050fba059138e5adda5be1f56cfb8c6f135678a2411badf0e35a1d162edcd1a4974a3347a7177cc5df7cf11e2a362d5f385166f6408df509ee35802d6aeb0e6f0e718c7bbe534d4a998354c9c8c89899a8c1208d15e49b415023d8696eb183877a31de98b3636c813881082c0bd799be2de90f275e9cb3d9ac24cf84b05a72e7a6889a14650232b30c57eb943813928d1e1d1e70c40dea3cd771e1858eb6fac5a21e6751e0ecbcfa11e93f13a10f287be1c99a6f5a327588761153f8727d0e32268482857721a68bcd35e1042a4d49484d797d02a72b007ecb4c52d4a451fb41201a31780aee9518539e923859953bd06f08fe5964b4c3a1433c16953f273ba2dde305063590ed13fe44d79714575c5281e08ac8f3566901f0cce75525880258c0bd39cd26cf21da274fc088c93264dbae6835f3c7b9282416f4b0f5b9c5460f927bf4d6166bf90c7e871a95e0d9494843d26d52c871e46f2d60c94567070394153bc99100c1122841d6c1257cdce73e2176fe0fab525eea9367296e6033beacd6994a0bd2cbfaceb0c1f83977062e57906a9e6abc2472e4123bc84b56b4d1d7456013437d2f252fad8e443f98272cf344ea7955c1fc040b58500ae46c9393d378e3238f9ff87ee3e1254fc161c46229e96f981d30d9428f359630a95aa06f7107297df57e106c402c15278de9cf23bcf3ee9c3f3a45c5bbfad173bbb5f6caee230cc6111d0f9aaaa781d1496563fe694edd8438df738febefb90454fe6a790c0db03b338527f0d3942f175c19c0f5c2609fa62acf15ee14aa5b56a097c78bcd945d01b139c2806fde3bd92b81e87cd48251dc260e0f93ba795ff3d0e2faf4dc106956b8b5c10c3764837bac46e02b52e6a4a556fd39a382ec5e8498b7dc0e8a71189081dd430eb262f934d5b6747e032cd69d1e0c1491acb5e3d43a46a6518c1cceee7b5a8f49f25c86c07564e8cc14d857638431112067f0b9f5fe846e4f6c675eb958528f1081305a436d00f78f168c6be91139a0c67eaa63083722d3951cf0afe7a47ce76167ad704f727e47899c8cc61a7a7fd363d36eedf585823fda0b4179bc846810d0d932be3d56979ad0fbd2367b0e5c6650336ad8adf7b5caea927a3260ed53e632b2cc9d18d3fdb304fa9749710846302a44bb60ab8404e72a1a338dd359712b388e787eecd5a9191d67fad7ded4b2c6805f2b1f5e876ec63b895e4a1b0c2b8e3996429347f685a160ff018d37602526c6e3160391839efa17dec1447a7558d39d65595d87e889329e88328e6e023f01f97107d001d0c6163f389b501e94f013f454fe10f14c138a998d52ace1965113f38fcf2f71e64c719412f9eba54d8188c90a84a9c5ef09871bd49c4e602bc3821019d637e9b9eaf9f8eb081986e811ac3a7cc067c92858340e33a90f09d430c41b685af94037e619a96bdc5446d7acc6fdbcbd7a356e45b0ca1417f37f21038ae392cf4d689d393a43ea7acf21035acc4c382f15f603be67a3b8ba80384f75597d217b2ab18321394ad745d4ddce186e98726654ce269f9e4a16c0e1ef3623c353be2689fda4f3fce391c26bc410217987581b7db5aa7931e5bce58db22950d551c0663d027c8c87d467726a0f54e7b493d0c64b029e190e2d8ada52b659b5a3370000e7223d3fc8eb47ce7b7161408908888405925bc3932fe93515c62845c8a57c49065a124c20ae14fc6a7be0ad7ad3d90440232098d82a8f8fc0215fb7652cf779ed6529fc7fc4e9b53b23374f9661901fcd54e2dd55a8cffa600790f232ea513812e66382daf7e2af5038d615bb68e83051c5fe4420dfd8cec1521432a311095d2bc60204ad26387e300e014c422fb89387539b96f264701507101d9758de3d9a81e04849ea270562a8a2491c0893efc1b914fa491097510aee4619e5d50232b1c59a32fc4d1ae7cd098a33ee001103ba34e9400a126abcac9e6524cecb246897a216f2f6e27b5f1977c490ce5a3432a1a6eb25ca699e4c986eb2d713254efa72c2e4923d9a3869ca879376d1c00c068b1390b639c5d77010aebbf74f13649730f28732184069bbc6738392683e39466824e98008124133b2313210b54ab9a0321ab1171afc4a684cb828351ab84878710c901e943c5cbd3e66b71f57c1b2e5b49b2d65b8ffafbf988156a722f18ef8037506040f1a3a7a8d5f1e92f94d09d6182552bce4de9268b42a1a5049f079e965c8a29876a04bb54c18f8ff25def0d165e13467603b7afb2e1f2ebf738bdca4fcd182fc541418263dc362ad731d3c417c76f2499f7f67b7b4607d09ea6caaa31e18b59bced1341c1cc766f464d08e021c57e6cbd2079526ad23914c2823028709560f84372ebfca87cdef06c2896f99d88d3238bb94800f0491921dc03b41d01cf4225ba495b642d504927cfbaa996b508311caa3f32ac63ab2f820eba909469c36338e5cfc63e334352efc9cd518c58a250ce4d733655fd8b238d4dab53a8a1d65a94a3d95a532b2b122aa9dc538c50b4a38281012106b668f697bf746fe0ec8322e0306b8deb5eb1a1ecfe1dd6ce71801d636d83f6ebabef82217ef8cf1dfd2ed398511e596b8751ce3afee815bc1e2fc189fe39e848e7468e58918880e03632d6f2b9e1979e9df44c695e1f159a67d0ae4f711fa5914ba1b0c7d425a742ad6e8b372c3d2262b14b662c11495fa1ba5b9e35ab9b1dc84b883b3eca6e9d339f9f47da498e8795298b98ae07662895ab726ae81122de11e9b2978ef6c67e25398a8e4ba5f923c32fce782ef02514816c3868317d76acb83697b68ae9f43c46de1307fe8c28cb042922ec6ec87e20e70770c224da9380fe9793141ec490a6f4a8533eb2c2ba068643872245ed19f8f413a2a492a52b44d44919748550f7e622f13d486964075e2806f9580a70922c421a59f5ba0eb1f93b0a461ec62dcd4c00867b516c43231cc3a2977cb33290db7587832525875ccd416963aeb58b13e5eae83ed5a875f93fab067f700d81be3f08f57c91089347f79ae61aea21f9249a80c71ac4fa5dbe75ebd36c04239d6300610516c2c5064d63131c0279b1bd3008553384a7df4314e9bac7e8de32f3f0059a785cb8cad352e68e2cd5c8b6956cc305a1a700576eba866cb18ed54311b95f745ae5113503382938d301b179ab1f3adb85e5c246b37c56848011f435ba8372acace4c68dd109c39026e6244fe0a277078e70ffc0ffc0ffc0f0cf36f9a7253f41a70969bc07393ac8854f024073dc9911c492febc040e40a160b370b661d49d9647ecd61c7118610558bb7d1eefe9e4698a23dee96a49cead8c308b3876ce220e5971cd545987365143e67f97d7cb622cc9ebd8d539474228c9d3a634f21a334a93222ccd02c7bc78a7c085384ec3997df64bbba86303d9eedf8ca17c2605a97b2e9b0b4d28430a66789473e0fc2144288c94e5b49951584793b2cfb51b018be6a204c21480c71106c4018f5bb7c25aee50fe61ccd89ebb8d8f14f3f181de50951a1cbade5ec83e155228aa7c639594af2c11022724a3d71d2ec8c7b303b58958d8cbf5672a807d3c5aec9b70af360883a9fa2526c2c4d8207e345d2cfef29fad1237730ed9a68569cf5f7d80ee6e8aaea9fc8d5c10c424f18cb0f72ac8ca383214a4e4e6ed9e6608e69114246b927e5c5e4a054ea49df5589831955edbea48f1d720e0e664dc71945cafff715bdc1f440fdcf3f94e488dd60b230b1a5d223cabb6d305f3eb14e122e495dd860d4b56871b234ec8cacc1fc7ae29375d2996d6a30dc4c32d14d2feb290da6980a6b1d7e5a2363ac208908004128001a4cc1c457fc42667bf80c86ce312b799c3f6e143398f42bef3b2c1f3beccb6016d752fffd7cd635190ca3df8d62c231decbc7600c0be5d520470ce638f76d1fcd1306935b9ca507e60183313a3baac13678ffce170c756e5a5b298549d2f18279445fd2fc7cbce99d4b2573ed10a9b96096fdcd0db15dcb7f0b46096175fbc1ac05e356dcbfea9c6ceac259307da4e4f0a7df73238c05f346789c75627d458faf60d29d7ad78fad158cdeddf20f237aee8bab600639f5198edf436da582412f42d60a977f44d52998545c7f6246cfd4a85230a5f171145cdf51eb250ac6afb43d2be90205c36ee7309d81b8bf5c9e60ae693d8baf473b392798553d23b6f7cb5fd70453789cb3a452ae9c5b32818af4472ec19c2fa5989fea2f750c9560dccc7d2cc127493068aa7e8e8548308bb8b785c7c142fa8e60eafef865b9b2563288114cb993846efcafeb5e04a38497aa0f1193cb12c11441233b0eed7d1b6f0806b7b9eb8b7c9fb9108cf69bb9e127a1831f0473a7c9d925f5e488a70040309a7e0a6f59554e56fb8541eb524bcc9fc48c7d61fe49e720e46fffa1d50bb3443893f4695e183a6dde85d9272f1dc47ce059d1851975920f09b9917c47b93074793d984871ddca172c0c6e0704c085d1abff1e5efc6f61f6748d1da5a8976b7e5b9872f28c480e91ac77af05492ea6ae45da69619471c7368d33de8ff82ccca5222ea11d4e1fe7c8c238f12ff28f3cc85939b130cc64e81844c98185c1c31a85ae38194b9d571843acddcdfa3f87bc2b0cab9197e3e41879f66e853956e6a343553892342b4c32fe293f63bdf1be0a635e7665e491d4c9556190b1e8581b87536148fd9cb1b1934b928c8a5ca2566d720a73579830fbf9e64a5318f633c6fdd1eedef196c2e85052aeb0eb125d521876eeb43be318c9ca5198c6e2fc416d4c38504561080d2fd487e87c4e28cc96a912112dcb970714a6baca2d9978589efe84e953dccea7638fea8a27cc79e219b754affbdd0993a514353ae4f1ac4b72c20cfa63bcf549aba33761daf9c61d5b3ce5859a306d668b7fc8312d6f98098396dc9ba5799cf7c184217574f7240f6adabd8419a6ff4aadf9f75b2c618c9a14ae3a924a181ac589f9b841286198e065b9365ba2e593309875ccf55b12865c927148952f12c6b3898daba555c2789030e420a9fea2e41e61061f7c3e58b0988ee20853d85699e49f1a49b34698dbe5d4662a54cfcf08530e529d9f23fa4faf4598231d955d63eb93b8228cf5f218ea3412618aecbe0e268b8676b482240684a0023c2000220c8e53d68fa9f51d81008730469e79b12c29bc7e5c8bc04000431cbf46a2a56c54276d20085008f34ba83c59a2b27d5647a9820084783c4462c4c43c7ef42088bae3a1c26a6ff54510f69c46ca87eecfc70a9252506a0f040884b9a35fc683fc6b231e4018a75b32fac7b50fc2e50fe62c96ba3a42fbdf4156903488007e30973f18c97d91f3394320401f4cad8ef16bbdca23fd9b40003e185d43eca1cf6be5990d01093080066e83188ca0010d8081bf80c90d76408310900d98200502c00301f660c6dee87e2eca4e62bb82a4149c1608a00753e6a4fa88afffe85108900763f5475f1d5d2f8f1e0fa60db58c2558145b99dcc110af6fa7755f3b984384fccff5d82b7cb80e268b8cea7262495785e8608e9ed1597b3cc67d3f0753459c9b207ea923a3e46069300a03049083f172f89c1ebb1fa758881c408038181c36bc74ef90aa0910000e26ad10527564984f0e4941051ad00002bcc11cdf29673f8c8c8ce31524d5c059402a6840031af00302b8c17469a24904ad48cff509046883a9a15d92b476d960fadaf724f143cc9d2328045883215423577dedec91b71a0c2ae218ce65e9dd504080349841721b4fa10e6210810634e0b80e2ed1e05ecee670cfbf2cbf82241710e00ca65fcbbd1d24228019b0ea14a7c3227e8ac1b181bbc005db81063460073a88c1a7e09c6d400358b03408c169054014042883966f262c5ed6abc90ab2010d78410c68f00d68800460c00215b080061c204f10800ca6141bb53f9edc296a40038a0830067cb2262a578747bb1870f0285d4ec3803b30b1cbfbff9e0403af923db979bee4be808e8709496e4208034ede80012f60c10a6ad0007701af0d70c000ce1b30605c0d08e08557c33b496ef08262831b68000614f00001ba50ce3013ebca29c9325211d5304b312e25bd5db07d30a04011800b668c937e8bd8630549640b04d88221bcfe2bb936beff4f0cba06a4063190c1068a6c032648010808a005a383b88aad974188e7c982293bbb62781e3b099f14088005e387be8e5fad9d974208700553706c6715adae20e99415ccba697a711a03c7c05c09100254c1e839c5bead6c895c710250c1fc29b62633a2bd27dd04049882513e486587624ac11cb93c69d8fce4c9d20d08100543348b7d67f1ebf17b37c01210000ae6fa9c2dff5d4d9eec4f3097cbdbc734b73c6e911410c009478662c1c243323323aad66c1d665f037743500119d48092004d303cf858f13544cbbbc304435ac465281fd33ded7646327d2e4d22400025981fcd5af48ec5ee8cf1000224c1dcf6ed8d63a7ece86824183a77e8b4dcf93fe51ec114d24c6ca5b7b6fc680453083a295d575ad68b45503c7d3a22987ce6373d8c4e7e670886fdb4962096de7ca40a104008c65dbbd41644a31a864130669735862f0f5f3b45002098fcda3a23a5b4d5bf30d7d99e7fed4ca5b82f8c5f16af9dfe6b2cdd0b636e38be14f6365fe585a962c8fb8a97bd85bb309c45c7133ec7db8fe8c210e3b18eadb930557ccfbef21e17669473b8a485fe16665429a5f3f030563bb6307b90f49effb1bf836b61ca18a75c07939d724a0b43b4bd91bc0fb1149c85494ac5bdec3e3325b2305638aa90133d1e5f2cccde511a86440e0b633c6875e0f05718ce1d58766d8b49c35d619e8c90957676a13ddf0ac325bd9c996a8f31feb0c2944d52eeef0f12f39e55984c2457ee8410721c8f2a8cda8eeb1d44a66c785261d4911091bf424e750715e6c7f9ede748b3f1744e61fc08958f7ea643d8db14a6065211afb397c26ca76395d1d4689e4d0ac3679cf3ea7ee558668fc29ce63c5285e4da48b6284c3712c2e46a7cf9c80e85e1a3ba1f4fd5ed4f1a14a6ca8cbb99496182a43f619edcd032b6762c1b694f986f2754cf55d599df0943ce719751a7efde0f73c2ecc8efb37dd6c17a7813868bfa7e36296da5963561088dd16464933361c858c26560bb396932260cf1730e9d22126b227c09c35834aaf4907c428a2d610a17f6b42e663f565c09b3bdfba4a824318f9812e69fb3fd5991b868f024cc515e95b195b1b7be1e49fc10e6f3d56ff9faac1f3d8630967f64700da5c3a985a02c43f78627f3394210be4caf23e5c9741066d3eab309fdca218230543c780caa715c6a74208cf71f725df21910944fa354ae1e76237f304b0821dee998e5e57e30cdcceb8d87e0e0d307a356dc47b62ea39b321f8c6db11c7e3657cf760fe6897428da13a3ddad1e4cd32b2b71745f2fac7930c555e5da477b469be2e1c6a042bab4e1a8b27107431eb324f31adf73297630ade78fa349e13abf1a6238401d5095ac0d655ba24d0763dbe3f449f9df56953918552cc5f7ab143250530e4c5c928e162b9e38182b4feed686e56865c2a146491f8a45db49ae208946180ef006938c571c6de91ceba21bcc1887fb5d4d8f9f2c69c3ef9ead753c4f54d860f6bb64b1df3cfb37c81a8cfdd959afca27633e35f01627397ebae86ba461147325dee3d0a1c1947fd2735547eef2cf6054d70a3231713318bb415bc9c4d55d489581d5e9db47ddfd1baf200969600319f0e00064307b4adf5c46765eee188c33d3a76e41bc5f138349a52e7f4e2e699141612898a77851d2bf78e3c1904855c3896421fd8251ac24a47ee9054348921c557434b95f72802e1862be6195ad4c8c6a70c1142f5aaac670291c600bb6e3ec4a61f3bd168adc25251d26bd16c9c2f071b8496942e2818566e2872df94bfd197705a35f6fa38c72c7bde85ac16cff187cd66547322955b0ad2cd742e7fa97a8a088379824e9b35f53d872bbd42363dc7dba140cf12578dcf95bb03638281c200aa4aa8c4d82ff5e83a1a0c5afada89b4a97f2278c523f5db7f969e4ad86fe9dd7fab2be4d783ea4ad745339e41c8009a6e0288ada6479f0f05fc2f1ef2045e790d47628e1e4e9cdb3d844679360ee9db4615ea51e4b47028eff62eea6a8a49e47b0363e8aa78e44ce08af6789973571a10314c12067561321ba5ba5fb0044289cbf25b1eac6c8fa21d439d78710cf412442184faf798ec67bbc1784da71f898f8bfeb197f0020943da5fc1eea2af78b2b9bbe6f5975aaee7c6148c92da2db799bc4db8b3e4b4ee5387ed7c68b62d756ca33d740ebdd45e7571d923fbe8f82ba481e34869dcb8595d21c95a5608ec7055641622ac5254b836f716c758cb2e655a8b660f734e651c6f239856aa124178facbfd738b4304de742545f3b3e6316797e5d5fcadc364f165dcea8815b9474dd1a0bae42168f56919ef2b078ede26a1fc4ec5e31cadb713c67e407ba62e9ee9ee0eb51713dad2059639897b4d33b4d58f1f7e4776c5f76045761ce919eee8f43483a892a88d10f8970a1329053917968cf20ac45560fa2c2a91f954e6db51eca5318f284109b91d2b4774ca1348aa6b38e32ab52181c39ca39dd871439c828fd3e7c0e3ed151585ef2a1cad2279d4461cea132d668c6819b5b8128182014c6c919954b1ea2a70e0a834ae98e7c4ccf9e439fd8c124070f2a82ccb99e38bea70b8d45b4f64e18a45fdd752c27e43b9e60004eb497ae425073ad47eb26ca1fefb7cbe6acd304a2a7d5e7c8842185facf5956ec4e764c186592edc4079af70ebf8451c42eb767d496304c4acaabc378fd70254c161ffd747c90912053c29c1cf6e978b08e8aee240cdaa981c56c5937874ac2b0924e3e4f4689049e356374bc41d6b12161c829788f4a368bf32a05e905033ce21c7ef13be4b73fe488457bbced2dd7db082394e5c3c7a0d1ca88e2a3c66e5ad27b2ec2a052951cc8564a5751447f2b591dfea5d4de27c2f4ebb7597e1e440cc2b8ac84f4be790e6176fd97eebce15da621cc8ea41a4978a71066f95453a1f2c7cfa943083a2b2f48ca6dbc0da28e9c0ed5a1e5b2ba20fcd3cc7b903ebb1508e3c788141a7c0c08634e8e9c54dbebbbef1f9493ca22df9e2cc50f76b8df4c59484615efc33dbafb71563d72ca873bf3a25d5c72bdec1e4c1b7165d7fef13a8aeac19194e00d1f8eecb97940a5c5dcd4ef623d878741766d8716c92f4dce1d0a4982fb6e353c0b713b18c3735c99dc2aabbe0ea62cfed93e5ec6f5391db27c19e438fbd28ede39e4a937773737ff9783b173f0bc61596d72ca3898711eb3bffacf1febc1c16a2413ff401d7fde50486be319bd6e30a8850f2d19f12ca9b5e1c7da216ed9e59b0d26a99c2cd954ad93576b30e518d33e11cb991e3550fb7b227feab9224f8379a71aa3b2600034982786e78b1d34e5527f06737a0c3dca7a96cf8f37c3d054c6310ec9df3298c187d8af2269fb2b4e06d3458be9b00fe1ffee3118238bcf58c68be1cbe89bf084c11c7f735af2e41f59c0f0a4f353f5f20b65bdb3dd19d1a8bd60ba183953742423a4b60ba60e6fabf095e3c2285acaf6e12d181a6455e44b650e2ea505d2af5eb677d4b964c16c5b6ad31fa34b44c282a1d5442ae3b993d7320506b8825992a42393d0db50b78262eadf393e6891dbab600e26a9636d6db27ec60a9252b0031ad8800af785b43d139a82b1f55dcc75f42f348e14465a0e631bc3fa8b76144cdeef56eb6d211d83a1700e19e9c53dd2b49f6094f91ce751ce39e18a90e76c2e477ffd4d307985643aeadf1d0f638297a63b5cb2822418b0e0532083a51a24837d81d120063658d58101966012e98fd0198baaa4d0201dd840062f3030e0000324c0000930c06fe0821d010324c0801d3806565083b5000324c000068420030c90c15291c1bec08801946092af757496f62f65d38c0d900453aef4d1b7a53ccfcd152419005661002418643d48f63dc93140020c90000324c0001a688001126000034290810634a0010d6085018e608e7df8d937792f59358011cc78723807df5f5e25af200f0246570628021f1d54a52bafd669600310d0c05db06d002298a3db6b441a3137ef94160c300473925e499d9fbe87fb160c2004e39c554af9dbd2874483608894968cac35ebe1c0820180605e0f2139a6566ad0458202fcc214ca73a3f0b8e85fc90a9290c8060ae00b73ce203356bf62bb1dd80b53a7cba0cc66f45c6a2714801786959812a6c361b50b6305f11cd153c838a63328802e0c5142863b66154b7eb61614201766f3f3bd3c8df49fd32b485a41c74006be8202e0c2105cdac14b5a465ee70a926490028b42016e61aa9cfad2877c27f3fa0a9286190a80130a600b8347713c293c3994edc0200647030b380c38d08006902c0a508ba2a39021555661c941e48a9d759797e6133f2b481ab430e4e9180dbd10034250810303d38006008014059885e9ca1ae407e5cac2281fee725245ff1f5c44140b7383f058bb301e62a70d64c0026fff8004740c0580851987a34e212532ea9c6101068420030c1043015e61f29cf2fc08731b512d802b4c77e3df5be1b01a550ad00aa3a7b9787f7275b39102b0c20cae52bcbb5c56905483183c049c9750805598e2bcf5a48e7dfff0b32e50005518c3d61a05bb759cf35d4112394f142015e66029e460fb2b17695b4192d50858200308f03a2f0f3f14001586a924d5972b3d7f031ae00d8318c0c0060d68400d1ad000093040023b7818a88005201881061ad0000930a0ec06388208c4e053e082f643031f034844014e614a7b9f9f1ae3ea0905308551b2f3995aceb5725f290c11d9f6fe73496cbca430a4e31033b9d3280c9ed3b6ef3afe5d7888c22833735f11a19dd7344201426148491a49ce11bfc76e28140014c6778c36eaee234c265328c027cc59c7d27f44ce1f245f4152f6a0009e304f96e04025fcb25f7605494e0319940e0ad009330ee1c349c706d971423841febcd9936c58f70a92720405d8842147d8444c6ba4200555301041031a50004d1824ec27c75521be2c54804c187ccf723d90d2c619b482a4183c0c58a082241b78054a110a8009935545e7f078bfd2f397307ed01ad7a990cfd4b784e9d6a3c465985dac7c254c0fda7214efe8f68fa784d1772c6ae8445e89fa244c296d35f248ae23a64bc270296d5d42cb62871e096343d5cbfe97cec973481c92ff5aa9781e112a802424800fa413b00773946832312f5ec40af560f628165dfdea2c03290179309bf64843877139b58c07f3bc456964bf0d3f7c77308eef8d59fdd967745121017630accf5f6fba5af413af90803a981bb5564bf2d0c170717dedea2dfff736076366cd45dacb3edeb91c0c3da29b922d458ff08983e1372c1d46aa3cd91238984f625b5a7f74a8f45148c01bcc1865c718e3fd8a8e221b780d6a30680b097083c91e47ab9c43420d24a00d667bc9efca11b9c4ad1524917902d860facff1e372a3cbf1dc3598835cb66790e17755c80a926cc08217b0c005b909508331e2fc43242d57a6bc831aac551a4c691aa1722ccfc61eb7e3c07c900034987de5513c587d073dde064c90020e24e00c265d2bc995380cd6062c6084800d5810810634c0062ce00d9820051d4880198c1d0eb561e7cb6e562b48721eb0c0062c80c1d6a00ca6f151cf895b165beb0a9252b00317c840065be84a90003298e2a4ab9ef6b76c213830d21324600c86b89ca8725c5ffd6831985bbce1e448179b74e321016130cfcd84bf7790bdd31d020283d9f53d83947aa1813e3e015f3097bec3bf92d50a61424102bc6068107d2cfa6fdac1ba82a461840474e19c4a7699fb78ae5b41520e96062970ff149021015c3079d6daf0e0a22ba5c0ca0209d88239c9a590ae6a1bda578783024302b460b628c16b5692e8a9e9850464c15cff212a5dc638c4bc3b406a0f09c08269fa25f34aca2b983cafea56c3a3bebe3924c00ae6928eb69b0a6a123b5530e94a048d0b96a482517a6f3ac752e475255330ebac3e8e5e69f52f1d1c12200573f48a480f6ef352582f0151305a75c8d0f4318a52900028982be579cbd1e14f30b59a4c6984ade038ed843f2c775b37301b0b69600319f420014d307d84b9a87cb9723a478943029860ec8f5efd8f0db3d1684b309f954a774e58daf2dd9000259851fc90b0549e336126c110d1dfd27a0cebaec90726608135240009e671d41949638c3424e0082689aab10d3bee5888450d09308221d64ec655e1423424a0088608b992fbb5554a1d13c1dc219ae433717970e12118f55ec527f2830e9b9e19122004d3c57674d1dd967b520e8c21014130639cfb3de3ad6d7c27b1210140304defa38f9ca3c3a58c2f20e017e68e5d8e333a3d091f5790d48006b4e320041960c00e681002a3761c10a92f0c77622a8fa203ffcff7c21c433b4549d9f3c2942d57faa9cf29a8f4bb3065a5bbd020ab57f8e8c2e4f9ba758e920b73ee5648907aad0ce2b830e4d63e73fcddc2a4d928f3d1bcd7576e0b837607b3d3add3caa985212adab6e24d0bb38446ff8d1ba5ac55c91910300be3bdc553bdf49185e937a342a2fee3994f2c0c391bc4978ca4d3ed8185f9ab3b05edca7985d9e5a23eb0e8b74e5d616af0797774247fec5a618888fa603aa39bd45861b617558d1cb2c15cab3084e49692c36ed0dd685598c54d24e8e43d943f158614362e675cfd60755498c48245ec0cc7b167a7303fdc9caf643615265314213bed5cc8e05218e493e5ecf493c2d4c0a35e847f4761c65221b8bae4c8a05e5118462a392e472a16f386c2d87fd9a2cab3fd5f1614c6cb93fc84396517ddc70ee473e20973a66d8460e39522a413064b5ae559328828dd72c234118ee28f397c94b19b30834bed592a57ac64551386898cce0fa962d267c228a99e54e4d3aa6c4c18ede62704e9cdbcf0250c9e82de390a8991a296305d87e4f7dfaf7c965209934e4a8f73a30b25ccc0cb77f5d2586b9e933063cba9d69e5212c6cfb6f0b12ab7f73212a6c893b7a2786c18718484a9d7d2a274e8ccfae023cc57de395c7f0e963ae80833aefcda92e5d0638a8d3085f0174f613ba5136484218f7f449dd391f17011c6ce71ddf1ce3fc7a1220ca7fdd1a9e367f90d1361588b101a574c29cb134418cca2ce3c66e7c99e1cc2f83956e70adb10e64f6321c2e43cad7321cc5ddb595daa5159268430845422194467ef996410e6be498f099d5d5b24823048a36d9cd23bd281241086d46c997b8feffc08204cf963a5c5d0889c0ef20773e5e8f9a711bbfbfbc13c59dc7374148d71be0fc6fbcba858a936463f3e18acd24bd72da5f8fcf660b8fccd4923973fa44f0f86e9797d6c7a9164be3c98a3ee41a74e9d4dc2c38339575a474dcff2cadd1dccd1f05383c919e556cd0ea6c828957a86a7944eab83e9342292fa7779b68c0e86ff776dd47f9a91d71c0c153caee7cf64945a723845b4c7d21312075394fc5b47fa695e8383d12dc457caf13baa566f30adb57894746aa38c7283e92a8c8479bdc4f5db60b238898d68d9cc3e3698c3a79ebad7680d866f8bac16cf1e32911a8c1e3a0daa34182f6c866499d6c61634985348ab9fbb7b1f79673045c48b8bd56217323398b72d4a7cae71e80a0494c110b2c75dcac8d3f2545320800c861819578c9b47c44a29103006c34b3ada6d954be921314080188cb532dfd2285520200c8614641fc897dae7ddc160ced99c98b895bbba7ec1a86e21bf2cd9bee5d10ba69334e1547feb41b420a00bc6fdd0f750f52d4b084100170cffa1ab3d54454d3a37c00009d800044e83184800015b30648f3adbb1aa97e868c124413f654f777b336a16cc495566dd63e3f89760c168e9310a92ca43c0154cfd75eaa8c7bb53dccf3a0d944000015630cb686535f9602149af82b9e3f566b278a58a53c19053bae4e29e77000c089882713d7a4aa7b5121fbf523047fc95d4be12ec721a05935ffa489a34718e52a060c838d4c42f74c593c7f8000324c080e101067420030c70810c5ec08214b80b6470031ba400c90b087882c93f560676592a55bcba800027982bb79fc78a907168e0c7200634e840031a408317bc200532a84122a009a60c87765e951afed91524612310c004a3eb84f6efea7093ee14d4c04f0c605037e0c00a6ab02bc880b3800621c8403b0d2a47818025500310a004d39fa47d05492980410c88d011084882f1d5b5ce4a2e4f5cb482a46440082a70011870a0010da8410b62108315181602014840c0114cdda37f72edad918e4a03028c604aa65a6ef1f416d0200639288259525013b3991c8d010144303f48fdfdf921040cc1fb067525777b0b62108315a4c00587055584408010cc2727eab971f56410322020086633fff94b639e11342c0302806094f31cfbcfb15eee06030e4860053660010920c000093080011260000324c000064880012060400832c0801b447e61c8db2167ffd10ed2a52f0c92b916d3b0b61e5507e885a13d845c93ede2f4745e18c2477bd949ef96e72e4c939af91dba1577b12e8c2d252712f3d9729ee4c254eb392eccff21bd85ae6415e73bc02d8c63f9d304eb3789ebae2049ab70005b28ba93bb2fe58adfb5307a12b7d78be3b87b9bc2016861ee8be968a7b37b247f168648bb901fd22e0b2ad6d2681b0bd37712f9fcc8d724d5b0305a187764f9234a96fb0a53c87d8c1d489ca5495d619c4a0e5afe3edadc5698d24895ee5e921566cbedad22d9adc2106e62c45ab479f1c70a5215869810263df74bd8cfa7c278f11979cc93c7e71f54186b92a73da88ebfd43985b973a6f765e74d4a1d5398f365742fc75d0aa37b0c7520a91dbbd9a430696c3a2a0f2e9d7e1d85297efdf927159368a9288c1e972b48834a28ccfddddbb8e1ded60714c6bda8dbecd05179929f3078527f189d2557f89e18ae5de8e420219d583672be2c51e4843be9bf22dd8421ad2bb5758e922be534611075cf403adca794970973d7573b06d1aef3c530614ee1a1adef3336bbeb12a6b0f34022ad650993e388a974de21afac4a9841565edd8a73b1aca284b127ca51c74fd6185493303b0ad239c44927d7491286defb495524cc95637f83f01c1a0c09d396c76f71afb028e911864eaada79792c65768439f5efa4fbc8b8f3d408b3a5d889faa713428311a6fadeecaddcf0ef7f115ca7b71c37df2269400390080e075004729d5d62bf62123b8930f73bd4d69e499f538f08435d843febdcd6059730e4640ff9b2254c8d326abc1271f6522a619a127fec5adff1154a1872747fa6caa4aa3209b344fcd94b3179a948c21c2e27efb8d1f82b190953aa8c72fe0aa171242161c6af16a562ee8c898f30c5dbd8ea5e879c42471882ab3f8a32698439b6743b86aa7de131c2f0e9a139d2bae8d02dc2e47f95d1f5cd5ead08633ac89e114d84e13cc4c96a25efa521c2ec12546b5d3b8439079551b392eba90ce17cb80cc25f0833f0ba10e6a867744298c4aa246689db58681086efcbe14e4241985ae6d3b4e718611f1808438e8cbf550702c218179722b687faf6ff6086298d4fc28412dbfd6070ec51ab410a29b7de07933a5249099d0f6690f7d431063f613c7b306dadbee77390726f3d98322e6c664887ac771e4c73d96aeb49cb77c683513ff7350e3d5651be83213fc65253723215dbc118f972238f708e515c07b3d8942309b16e194c0743eaded6c9d3ce78e76094aad0a235194865e560b4c9d1b137360e061f8df686161d54858349552a7c46f99125f50de69736ffffd16b98bac1a00d426d6b461aa66d30bfff4b598c07e21736987327358f9b90d89735985cd3c2a5f0dcb152d4609c8c499d3d2d42b0a4c1a41971737f52c44fa2c1d466276e2138c6769ec1d4d93ea78cbe7c759ac15039b5d393f5c52fcb5074644b295f4906f3c50e0f17a1a1f73806e3dc65b750a933ec89188c1549c28e657db891309872d7a6e7778454c1604e5267e19b3a9e7ec1249f62794e7954b6f382d145ecbdee8251577e3b7ab24a765c308639d6b2ff88796dc1148f42c628a405a3594e59af615930ebabb687d90916cca0d723aa55c415895cc114d53e9b85f14615112b98572a875bce7e2519a40a062ff59b0915cc713cf75218cd6c0c3205e37fd07fe85e96752918ffe1875bd1cb157d14cc9db32ac9f145c50e05c3afc965eb1025749e60d4926958b5134c22b9dc2d7c9a6094c995ad7d33c1d49b79532125bbcb124c162988ece5ae7cac047368d6abbe051d0727c1a413222496e7cc8f0493e34871943f827127d24ddf76878e110c1feec245ca16c1e8297f12f128118c0dbb1bc565014330dfbca97d6789e0960508c1701f34373fdf985a16100453f0546625faf1c2b900201846c7a30395cdb8e42f4c793d39f09026560efac2e45172aaa0622fcca13f5dd97734db9017e6cc6d155b51db89ecc2949523f161f338447461e8ae1017cc8529784d050fd1f51e5c1822b5a578f4ca856f6130b11eb320afbe9e2d4c6b169d9bd7c2e8e3a0de3f460b63a84cf9d8360b43c79e779c43a4e4992ccc511ac70829e3e38985f9dd9264576cfa0d0be35e5fc658e2a8ddf40a439a947ca942ae303fd4f7a46321de48ad3088674d945769c9b2c2f47eda96ea2acc934c2f245263bc8d538519adc8787e7ca930540a9151ebc64ee751617c7cd136b25398c7f6472f66a2546f0a9334fc90f17cea4a97c230ff1d331da4304fbcdcc7d04761e82025bed11185197e84328792b34c1e0a934c6bbd5b5b8e7883c2188efb71e6fd0963f74c4de5e839a3b4270cba0d5cb6ec2b3bba13c6ecbc15fa27ce3bcc09b35caacbbfcd7ebe9b30839a64961d74e5753561ba18e2e9153ff7b2993044abec66197698473161860d1aa4cae5a55f2e61f6f0f03ad7c51226bbaf9c6f2476cd5209b3a34eed78d9331da484d16f22e29493307b32bb47d171f2a1248cfd12d342484f9e23611cf9b1f5742b5242c2e4482fc44a1e618cf5e821c3d26e8d98021c61ce13d2b89d8bd8444c01658fb5095e21620a60c49f41ec7010ba4598752c5c485b11e69bbc6967c9c65d4b8429e7753017ded129438429be8448163292903f84c93f44b6ffeae8784318c244b45e9ab6f10a61ee9caebfb532429843be88d721fa8746d920cc392d4d444710a68f5607e9fceddf4018bc42a38c62bd68840061cab063a4e4102cd27f3063db37c933dd670df38339e47ca7e396da751fcc38279d5c89388f9e0f8674313f9defc19095723d18d2a3dcffed20789e0753e8e9758d1c3c9845628ea7eddcc17815ccfd439cc61f3b18efc7a452bcc87dd7c11cab2a72a84acada743069a4ac06b1c347da7330c8e4a852a932b249cbc11c1fdc8b6e778fd47130d884f49165c2f2633898e274dea7b30a91f70d663191d01a6929a4d50d6690652655febc16d63698f751ead8e0db3ea96c307ece778e4fd760ca6b1de63188f97f5183393f3ef2ef68469f067350b390fb2dd172120d46472edb95d16730b67547f0b6b3f6d10ce6bc171da98b65307a6cc7abc617134132982552fc4848b89043c6605cb34ac15266058d88c19c7a921be747913b1706939e854a29447a990f0c860e8e7d32f0862ede17cc6a5ebfdf25393dce0ba69447252d6ed50573ecd19bdad9d7dc8a0ba64fe7a525e72885565b306d58063b2e133967a50593e5106c2c9b390e5965c1d8b223f3293ff44815168cd1355b39ee2b985e2d7b8e5fea37a9ac6054079572889ce2034755c1fc1e2fa37af76419a3a8606efc30d351c67b979f82a125db7b10998cdca5604629a2faebffe7f32898b45278a40e52c27aa0609a0821d3249a95759e60724b4fe943630fd2718251dc1c4a3f4cabb89b606a282622eb19e6a599608a20692b6b99494a2fc154daa11b445909a60acf21d597a50f71128ce136973b9dddbb8b04439609be1ec1101e66523db4faac463045cec152e8b7ba9c16c1343afa1a3d11cc915274fe7031a196211825d885ed76b5d44230c5d4914e5f3339190463a472dc1b21fa47140004839f383899ca59bcfc8529bf4ef4b7a02f0cd2359f7bc45e98371f79a989fc4ac80b536af50349a99a38d985792ed8e6a5e3ae90e8c2d4fb686d7fde76be5c18cf51e5f8b91d6fe570616c64db0f4294ca92bb85a923fe4fe5982d0c49fb6cdee2c3eaab16a668d8b967bca1d4450b53636ccdc2ec0fe3645c259a2f0ba3fa5a701cd5f29d5818928458687d20f9c2c2389626921d4409788569afbe533a69899c1f097085e93fcf8590f8931d3f12d00aa3f75eb213af2cff19096005b962deab304d6e75b47d6b445b15a6c965ed91bc92073b15869056263af6176f1915869071bf7bc8a730e5a892162cd64a8a4d61eeb0f0ef713e470697c2fca1b6515e5897baa430b68597ee4721bfb2a33035f6468e234f3faba23064774ac6b962594e4361967f60b99a9d525a40610a91a1cfebf909439ebda9740ee2bcf484d12b4908a5e3f9b2d80973a8f5e9f83cec2872c268a1536d7cb896876cc2ec3ed697454d183a5abe8c1f4c86db65c29011f24df98a09535e744b572e6186958199a5bc36cf1286341d75c23ac8cb2a6108693e1a78a789a82861ac4fd9bbfb6f9d69128694e63d5db5f9684918a5c36765d70e138d8459a662eb3a1ebe080943909249ff38ab446324e011c692afb20cce778431f294e5f851234a5e8d30553cc6ff25d9d3c703070960c4feb8c16d768ed3007511a690423acb78bdaa244f80220c26dbc81a5df8e94f4984d12dd794a4f55b9e8c12901424001186addbf9f23891d3d84318d2d4ea785ccf9d8636b041d9010d4240820418c21ccdd5752bf9e5aee80a924450086a000c12408816246010647c9dc28390410881a0010de840068a68600319e82101823079e898103957ee309f4098b5e2acc13d3ef10fbea0d8e0061a70810c5ec00292840400c28caeebdb5b24ab4a16fcc198e97ff7a7e60dfc60980cc72242b0bf08199790803e98ef622603cfad3b69f5c3021cf835a00112300d6840031a2001067480011260c00718208106342089eaa8b4ebe62262b148201087c3c150481486eb5701531508201834208f469218854365de01140003542c22362828101a160c0e1410081c0a0a03c280d0401c0682016120180804855c21226808b42700287841f6c3b01d0bcc63764bcdc8fe11e6ddc7250a8c79786bcab1db7b1e4c57ed62b3fab18b467c476e3acb4d080967724a37f50f9fefd9c7901577e50962849fa8d5e620264a442a7e2b0cb8d0b95739d809af7f81656c87c5f1a5a3db3007b7d3800c3cdf2a975db20da73bed259fabc6fa3bd9de6a533ba21f81fa0ed2611afef27c27569e00c2ee378323d0a29b8e24f2eee4f772d731042f5c3b71a2598bfbe31d24b77e022a6002e49a327666052ca21066f54653dcbe10d9aae9d884940f7b172d0b38426f5bc07e04222424c082884647ee01110b8ff5460a8021009de53cdda3d323696c6a4d4b10ba079f37f3e22a869a1001a6db76d07305284335991a464303555fc6502942b1daa5742d6bb51bb2859a617b2bec8a8488e6e85749e81e0a7ba50bc21d1d29ae540681d58a28ea2c6065b5b316bb7474f2d3c6c358110c452e5628ce16b5a649ad64bd652d9b9b385d50c67adec96e62efae17652154552b4e0624003337ad7d24907737eeadf88884b03e62f057cdacb85a55fd5fafa797044d3083dadb55980d1e083aae47e8bd5cf1ac2ce1080f6b1b4e0138b9018763aaef5ae7510d402ba07a1704a615eebbea7d0bd9bd8f379232bb9acbce79f1e318c0186bd80bda1d2dbf34ddca44d87fbbbeb700247194d53a6a33257b22832d6bd7126d36775271ba14f2988a43646281356a5c7044f8bc7cf41860008773da456f7c1d0b4c630e4bc1d2a520887ab305aba074fdb92d49ec0e6ba246a3f8f262dba52ae69f1eaa6601641aff91f2e44a2df72cd6e16e37cb395d78869f8e9f8c1535ce637ae81e054f6cb75913ade2e8c54708d4e8f2133798d163f41861aa134794ee4592ce1063d803da7a18a2570d33bfc130b658c50ee6804623ac2878c50526b6d74273fd89f434faaf98175051fa6301b55eb33661297589eefb2644400c9241a0fc9dd6c0a81aaf2542d28ef01b0f759324a59267a7c973fc9dc2e50763373ca60df23b22b0845654ac899a92782d30a0cf506228dcc615378eba1f73068d23ef22eab8352e83bca252fdaf9163d4a50ba257ade72d1bcd81636700d515b91be9c4ee6e461b5820b0fa824d362bdade87a12def168add8e643945019b61ad5d3eaaa3fd3d0738a4c52882eaf3724299d305789b87ddbc1ae6dc7c5d00328473ecccab033e2844f0c9e708d60a8e76c6c6d1f8a9941ed0b4406c8dc190459a016016296bb4652345550ee2ae28b346162a4302d8b34605e2711090c61dab0b6ecc121504c65eba63d4833cb43bc4f661acae9f2c0ea0cfbf84a42da283423b7208fb1fdb7111f03efac1e256a1026db353e5e5c32a5d4e064ecf238e93f1b0a9a54bf10b66811a4c7181a57d587fc99bcda26919e949ee4d14e74309e1303aa549184b701974e0f421a74bbe74754e80fe37884531a48170e077b15e93db17ca3756410049bc896bd4087729a5555023aec7410977930c0704a90076cc99351702d506526931b16ad053834da840c8c6afdd030078360850528186a397b8261dbd40a8ca9903fbd512d5c7422c642e44c45969c82d9f39731501c0a428084025c54d062224cfbb5b8d038b42c77ba206a997e54d94547ed8b08fcfc424b5acae54e142eb5c5d61234e1ba8197ff46afa0d72752a23c52225a02088ca27533a2ea06d100a4c984fc79a4fbcee002a066b256b096af74fe41e4dae758f7f3373d3368ea73711fde215ad83b447beed43a62977d18437f09443fff8e5becb68182962a57aef700a0e84720e2cbf29602d3bb8c2911574eb2c0f96754a702eeac47a56efdeca3d251f153e21e9773f1849fe13ed4f53a01e4b382c7abc7b32315b456a333c41d7278625ab83d958b4a24ffdd55dc8532bc403e9e1fa125edf934c4765cd33fcced471b783b7ec513939099be1f001007a3d82692d13f6056d17caeb510ab4db0ec9460357334114ac96c17d0d1269c27384a362726542b413f8c632cea233661d86557853239c7d032bf14a205dd902675f10a418c3ddb36fde84d60f85b9ab67234a6767c5767e562a42f9560fe068f069a654ef06f0fcd73f4d8212cc0d07a598cd0ca6e530bc57d648340a8145e5ec0721f5a7374d124b089cbc57c9e6ea1d08a31178d4b4cbfea1872f7554eae8aa07f9fe39dce8aeea727d2d97afdd4961be4074ccf9b87bd3c9b67ae3332a41da82001c8de85cc2864680ad531df6161e9e699a6028cd346e769b0165447e81f46f81206dafdd42635ca2c00182352ead06d28d4259e3244ac371088c0070d3369382b8e7d88965c662d07f0c029bd2885780cc941a840dc8971b74bdaf81c270667c60a28727dea1327b10257924a92d92f290e01207bf439c6502406b0ab95b1b144dc0a426b8066f37bd882494b90677e8b8681e459690259b2402aeaad41fec18eb6fc6f25e74234612bbbf2277257879d8371b15109338593cd0e0f7407da2af98c421948868403fde2890b565ea040b6c35005688cbe4b0d5f3297845a716a4d6e9fa2bf7c016e99de310c2624dfc864846c83e5ba14f158d5d79de49bcd530d072eeb836fa117582db540ce9d3a00eee805691b19299c10c5cf6ea3b57323cedc5ea54d769e3820532db77c496543e9e2af9c74fe21153568aa5296b226efa2ad5d3e1d6b5068b292965e725ca1bb45becbdf8ad7e8dbeb33e23ec795c6c47a57481b3c3d02cf26f8d7923e061e8123423e73e61db17821f305210d01b67c61e5ea56eb6102e62a2eaaedf2516ef3920511f05c24bf777b3411ef6e798d7d7eed0e5ad4b0062a87b780987ed79eed96dc7d8623e2393641ea5da692acf2705e654b46e74ddea5ff72e55bd695fdaade985e905e98dc3cbb94bd75bd55bea8d8ab72e8fc626f0f36efdd622ab69b177f90c60eb94ebbed6cdd1cdf2bb69728f60edba6639defbd9fb94774bf7421767b7ba37be37a05706af7ded9e5b0950c54797a0d9ddda2ad5b0907409bad8ba847535bac1757774bb74ef747d74d5e866b3ddee811429155d7b73780b75317509ea2aba8175b7773b7b6f79fd75d5e8b674cde9267579ea32d465eab6d46dea0665f7b503243dcdea9dccebd055b3abdd9bf978cfc5ce000ca1eeccdc5d9e34921a2598b237b6b767e2ad538315679499a046d3bc6b42ad9d98bce807710b3f01271842255314c461359397ccd3c6c32e005433aec874fe686238b151636bea4731b2474b32230ac296da19c1b326459a19977a256930e40568d10790053d88f529381a5d6c50738b0abd51f7f922d7b9bd44327b776744132967d951c8e1108a494724ca29f726ba43a2e0c36104fdd1f85a9e93a0c0ba9be235831517d3ae49e453f154b1dfc6205c3d7624ab8b908cc38fa1d19b91f7e23f1b7b3f28717ab606938ed9f6869c2cfd7591c81c8bc78724c802d2007c0cb3860f2b2302d388d190a4614ea94a70036a0c5de861c52e4178b27393982e3ecd639c49a523237280a0233f444347c0434303441366943899632aaa99335f86beaf9c9d99e347585092fa6b126231bcc70ca676e95201bf36416da94920baee4fb92fd34e443562a18505ed480abb3efe42bffb0a9ce9422d2e4696e449d7374d784e71bcc930a9e6e28bb14ef6807d80749026d7d3b2a17f9023c8103412a60d075181d06b298a56b2037dd71100ee36c6446439b2d84474ab5f4b3d3ac3f396f45e05aac51429e801aa30db8c4c5eea54a94d7b18a89a23ba6081f25328a9087ab8ae0609fc2a5078131ad6ed45ccedabbd6574b0f9b68bef3df2362f20453817c294f7711a7aa5ac0f847051e2b422fcee337536fe8c1663df9f54be3c75f6cd904e78ae3a9564e45eb1d9719d5ff95ab0e88e16312d9fa2d27c66f121537fcfa1950a1cd383781bac21da21006427f030181348ea64b7f7f4ce3a29daa70e70ebdf314da84a8d9573f4b902a7ca536b627f827d5caec45705c00bd801140e00f3159d5a337ff78b91008610c5877e6033b46873d44c3c49ed0641790e84c90969891555dba181ccd29cf97c16b0c628f59675640f2d4b35e85605940a2806fa0b820cb394b42135814c9606d62acec0191ccfd0fb7ca160c5026e815581ea1bd8824af15b1b02cf023304f4d1c08be4d358ff06064590f97640758ce0f8fd4d5d47dfa69029e6737f3d608d5dd20c268f92327e327ae8d1929a238024a027f04204e285ecfb05a3c09c0098003c01f81488e7fa9ccd0b01d4603d00b20046193fc62fae4c8575b0d404bc30a63427cd2cb2ee6b6298aa227a1c5a2b23652ac323bd8bddb40d95fb489231ed696b0702f611787934b0bea004ac587e2cb4b60f1f0acb4d8db91a486c031e319089f5eac8a106aca9ed71bb9fcc4d80371836f00c82cc7d0240d409580788175dff4f206cdc795e78354fb0e0a15687702a333720c75a632d8d5ab8e19f4b39a05695081c0a24b57b96347ba1cb7155803a27f234d8496ab6f598162fa97aae82d518af42ee663596163d8f4c06e05d14184d20aa5714b736e9b46a82009c804f2759baa27b0e0d171a78340b5e6827545100a50156e75fafb109d24c12c9472fd745303d1612836d437b02e7fa28e0294106aac0a3220551fbfc31cdbe569b5c2b34544d3401118cf72a2dbfacc4484f6e38936456b0ee7c889a9d862d4ff0582190236018188faf4094570d6c16714a128f98882b92e25fdafc23c88cf74afbe0cf1ba3d1fe18d6c896784e15273e77160450e3ffba6cf9fb84045f4412bb4d1c2a251ba2640408613f02f30ccf68ce69fad23a0bcf75d493f107a02361ed536c41b80c42fbc80621f364e771d5fbe763ac7516e91093a16e3368b065c766b01f9b6374adb6c7b7b9b649cf9355154c39d33ab9d2eda8d79bfafb46c5a264292501de00330370886d43510dfb1d99472ded6c3834eb7980d19e776bef8492fafdff3ebc1f36dcb03e864ecc44ac011deec3c090cf5178d982a2c870630a5af7e19873caf9035546e3b6df35d5d68c93bcdaa0f911d708c85de8ea88b2c5e1eee043641b8fdbd7e41791e7c8ef5eac38369a10bf798013274628953710b4352727e2b302103c341eeb5bb4db3306c052daff95e1c4fdbcd2111c7dfc2703155774aed5f9937b5d340d65a7aec9b62e3304324a5fba4a3b765b83e96a2cfaadd085e50d6c8e018d6e344a0c82867077aacb63230daaaf413c4d938b7aa19b6c76d4432dcea8d48fd19f99e64d472d80948d6dd1abe8efb8c4f72c8ede70ea744c6b88e39be4ecccbd34af49801ce567c06910d4d921404f02846d0dde9279d345945ee3c36060dfb433c21742212011a94c6503be0b23a55dad4ab7a37b393796aac78460442ba0fd96a33a1b6cd43ef39eb471eb35019257c292029bdebe9f1a0f8aef0b8d7b2404a8f1235c8d2fb24bcddbef1d63dd6b99dd30bbde78408c165e99277859e3f21a019aa1c4860a1b5d47d93447f335a1404bdc4533b7c1a7ea58cf4d0cb41f0cf9e256ef51cee665b9cae051ea0cb4b109b1df7b183b03539d97df0b25a2da2d1f2869b0efabeda0416d424875fdc288d7971cb2a4d1af41d9f3ef0eca361c9591a6abd4c60e1b5adcea0c3bc34bd2827a8a9ada428c000a2b0b71fa72c78ccf39a983c02e3a4641802e5cfee22de65157bbb46186c4dadd40187bfae38617e62df31f11f48bf5c7eb18371c8395965643c6eaa0eba40e39d94341e3f4c0987ce3d11a4c1cda08c9d61a9dda85993c4ab5a44849a19adc3522ea9f66a88d79db9aa4dea089712e03e641c85779f00b72b1b4794443243a496cc764b01c06938a7b2ec9a7904649896e3b06416c606f17ce2fcf0ab26679ebf9c502c5bcdf976fc78a45ce9c08669818cebe07f314be3ed78145b410f7542173465789327994d06798e7758d59fa38a2bb208e1dd321d98bda6b7111257a90e645ff50d26629e465c621aa8da2a8289ccaee0aa4a4097c47151e545102189f200aad1f269a5143da2cc12b71520fe2ae32d05889831560be84c603632be47f049f288e4c0f54daf3b72d57e49576b3f82d9e912ce1b7b5f824edf962fe8270855383df2b6f8c58b8e01cb3a385183219aac3c7e771ba3fc11174950f1dd09c70726e9086e2cc404fc43af88264b16e6b0a0d8b9d1ac037915abe80fc3673edf873227916fc02ebaa621c956e1d3a59f1abad86101566099c9134682223d537aa812b8eeb6dcb61deca71e3cd3697920f739a576b1b8b78888826fab4fa1ed48f995e91589bb153ce20f862ee3c2fce36271d2a614672e2ccae9739efb6ad8bcfd9f76c4576c2a6886ced4602d067abc9038b0e4295c30191e7027725536029295f7a2bace2ec287e1d3fa5b0ee082aa7a68be185cdbf24a04e421144772b777d5f37c18a6393016cad56c51d10780933fb8b73c5e13b5b8de768f0d96deba3f8d3deec81241192a786c7159477c9a80768d789f5d671b4e6f3f27ac2e6419448df8cb41e491365b621f35761f5a6123ba417b1f7cdf906187c2048ff75ae33fdd92009bf4c11e990603f2b4db30f51cec65faeb416729f00e190d46faa93085cedda2faed2e173a76cba0d7899d94f5ad1aa096c29d0ca02701cc68d426c6a8c40be28d902aa40c637ac859ca0d01c2fe426ff9b622ee9245592cd45fe2bb0389436b3675055062c79dd213bb71d06e2b57b303f5442866342989349b8c95bb26a08144ec628aee0db8c8aaaaf6b4c9dc3991c45fc67889675c1d3c8d0e7d50c77f14505d5360fb61f062a38e90d3aab5ad0f0a593e9dbaa7ada40ba8331ee8da8b7fcbd5a8c1f5e9cb51e96a7f3daa92b2cccac84ab4f4732020bc573ead62021fa73f86219f9227475711bab08c9b0c5967e10cb87d180eef90010d949a87589eb6aa7313220bd278137403338f8745c61da42aec64de35196e7f9fc796c5e93169f969f2e3d42d80ba01f38388dd357292b4e796ce073c4dfbe17f77b9dc2d78b774527a0faf5a0695e095d9892eaa5a8a8af9aab16354218d4e54a07509f809b5aabff96fc97ce1ca9f359b11077f5bf59d9f79b57614d9c3a09287066582d8ae95db69a04410b1344442e20a24f193f91efe28cb4f1b260e8fc947928e62ba5b7abac2127c2800358856c7dc91a2831c03ce542cc35864b3ded9a9fa12b6ad10c89c9b9cf286edf90891397a966612226e81cd19ca3895264d95cd921bf825bc4851308148974a20c2701d4d98213ce8cfbdf043a996b62c6beecabb85710f5e5bdd0a5ee3e491625f8a0e0dfa1ad416390a44df223c575448634195d68cb568eb7dd86822b1af542132e7ba763372e7d75889426bf69f9f0e2e25e793054113a11fa2092830c59d6ac276bf988a1bb9a5e9704cff65a042ce8f66a712a453cec007ed792cccf4bd3676ae881d027a216130eca1326eb368b33b56b539a05f9a445f5709d916092296869a80decd12bfcbb6c5b53e2dbc9607816516d78266b321ac979844008500d3805ee81c4c03b307430e4dcbf730c188fe27e707478297273d8500cb8c620e02c810d6cb4afe2014c0c870d620f8118638b1c2509fa930c6e2414993f8860679444efc190b032511a0227c1852012fc085612f002ce4c958c8227207148c963c36e1bbde1057d3c6c304f40eb373070212ced11099835168b12e1eb587a3c1f25460f6326181121b9939832320de7736406413fb650867d7e2f9d892643a1dfe1ec70af336f95a1a6bdce4a07e9d00e72ecdfb0fc78cb685e18742a2074d20e67e7d371d605f43f529d30679d8373be3995f3bc4136f4da3427ec591121a0bb9d3d85429fed618cadec0cc19d1fa8aa4823f57ca12008aac1a80102f6388b52905d6734b18ae81ee6a720f41c3d7fe72879608bee7e29c2d0eb70b46bc40e55fbfcf5b0b54d8051ebe9e3fb3309140de901dd6bf6c63623f40291816c58e416e87e02b6418ea29444171a8dda4cdb31f5c13d4e160c9d356a060d342d7eb3f2a94b6848352341422d5590e940928e6ca5e1c8e5b49530444427eca9fb4a00c64b9d3822a8ef04fa72fc28092f0142e675637ba6bee4e47fc821a91dc54b621db87e11bd141695907251d89e003204c72967020897437d2c487f94191d895816663207892f50f5c3c53069ff5583b82cc21fc877fc853142b002897777718c2c9a205b028d223fe2cd25b741321ec3312a688a651cd96bda10869846e372ee316602656142b4a27a2efa832c83748fe2c4acb634a371c1393146f56118773454f86261a3de881a1a029fbd213700921b347bfa0b2c3b27493844a2147b4428519cfde78a153870698bc9393581ea5c6c1cd234dcdfcf0712dabb8d784d700dd86439101778b4527f680586c35d502a7de44cfdb575a51dcdf4707720066aca2fb17f65f3082f69bf46c907b851498398c4aca980a205ab91fd023986a130ac00e0a975ae6c27506ae0aac428a954aacec2a00204069f5401fb28c7972783d69c658cd4ed003ee83edfcf1d74bd9c1001fea02380f4bb018a72ad4f094efe05d1b78209bd8c8eea88cd9f83a60d17ff41def2b8f8990a51f0a14756dc7a8a1f83ff4ec3624b2aa19604dcb0868cd765db24e644894812dd59294d1e42846d0fd0996ba8c4dfa24acd69997258866fdc108e7801d0bd06cf97af9237c185949fdfb347095f1e1fc5f7e13cfd60e3306568f5e034be7c988a627bb7b5a03a2a518b76ba0c1a93efaf28ffa18e197be41fcb8b515340bf952e03a15babc2e71f6081add9699a2180ab9a785285f12df2fe1e2f830e4f5f71d0b5d466cffbe5118bd9df1b99c8452b50942da03765d91b08de96b537ecc6b2d24861af7232bb696da9b8e0162d06a03edc743e8dea2089d329c4806b3f9143b3628fb887a07ce72847029a7940f683b59572284363afc1825aeefa546c7796f1ac6eab9e8a0d228e8cbc329381da2d233620aff87013ddd3f5fa1308e8501cdb6cb688702aa97276b8bffc7cb6b61326dc256b635835cdaad5f3a8408258229cbe53c07ed5c986e1c9824a444e891c635d8a402065517491648d7904332da6131a0136f8b5d423cfd9c7d777b9bbd548546b6e758d559b5ec5357528e2c10b5393e90d8f1e3ff142f4e4ad746e64a1fcea294816d42adaa5060d86101b479b66357c6408b5bca45dade32c506e9429dd0bc08c80bbb39d300c38f9f812fd4e3763f0f36914562be493185823ab9b0ad625b5091ea57411d5afcd13f783e130db6bf60486e6473ebf0e63654fd3083c54dafa1571f828e82513669f2ec7256cb41f956392e32ddc50e03dcddfce9ea13ce29285533a6f9b96a2530c2121da4036d785fdc56f868ca8bc78a520ce8f90664666edfdc0ce04288acb83ecf87347483a62f280fb67bb9237d609d61bb1fa9de7c2ea35b79aeaad7a47876c5dc2c6e9ab13db2b15765886d84d585103c3c954def2a77899d243c87a8211e439b36c36821a26110878f19bb03b043e56f00649bd6d451b26b862d751feaa89be512fe7f5718f7180b8da6d366eccc8838a028aec9051894469aa3e5447b4c956c24dba949865ceaff2c6bb8819bcff44960a0a58efdbe79dbc7655aff57bc5ae5856813228d1d5625064b72145407025dec3c7f0313c860ce3616c88c7d18d1fdf6af93d648c9ee133e40c1f63c7f8889ea747fa003dc63a18bbe19728de5a580957402ab81256429410a5fd0407037cab022e0945d30c2e30f44c07c0300cc3300cda01482723ea275a262953bd917049fbe029a594649229aaf3856eb3b7b8781306c0ec0d030cef0c990c6bccc0a48e3f1e3c83bed294819310b42575eaab774b64e0b425dddd1abd17b43406c6ac7582defc295e2c89810bbea321b7745222248581d3eda1b282aba8094960e02745d024727d8b9ebec00995938ac81b5276c90b4cfea8a671439267495de09365483c2b7181778fe973a6243fe6fc1698982c724e217b8ef1d7029727fda79c449e907d165813f1d34cd5c5ba1e0b9c274b5e810d292491df9ede222b704987a6ceceec243f55e0daba73104bae993915f80e66426e2ae96bf514d031e4a5c0df0449599d8d026b22eb96ac160aac6f7c513944ec20ee1338bf51294b595576d4098cc6a4ba82d7046eef47ab6b52a222ca043eb3ae77aaa4325f02972bd2bccb74106e2a810f19946a0b39bcb449e094dec58cfb691e3290c09b89a09e3976a4143c06ab7df7adda71ab640c7e84ab6f0473cdf96270e6f927e4fe536f1383fd53f2f482f2ccd80d8317ebd1d14b04af9230b82e0db223b7c6206382c1a690c94ac8d4a94cc0e04d4b4dd2a43653fc177c998ee8a8eee611f305af9aad74647ac1c9dcaf3fabf082f1be4b757d179c6735355d962ed85c9a3309a956dfd5e782f5bc96e28237299262a6102ce4c8df82d38d41e4d415296ac8db8253a1272515f9d335f2b5e04534a54fa243544db4d0453bb36024e99bd8953a485216ec05cdbba539787a1f0b26063f931137b38960c188084f4adf2ea7f2bc82d399fcd4c44da9992b185dfbb1f094a023de0a4668767eab9d7c7956b012e2e73821c65cdf2a38d77c6d916a5594425e4d1e940a465f8558c51715ec7607539fdc53b039a6d469d3712bafa6607b7563454c0b9aa3a5e0b54abd9668b67e9514ec5ede10743b0adef55424bd59535da260729db0a4269a864443c1a7491972c9fda849a0604f6672d141d8a59c4fb01dd3baf5588ca07b821fbdcea349fbe59d9de03fc8309d5382b61539c1a595143d65c9f4eb6d827d2ddb94538a0a71a309ee92e4cab66a67f94cb0f1236fceb969b3334cf063322b678fb14de8126c868918aa2b8778154bb0b1eb92dfa75025f8dfcf1b47a41025b82c3a94a687d41443d02418b3d19833ae95984912bc5a3271bb14963429126c7a7928ef8a41d40f0946a9f014235da8d0fd23b8983caafb49d09bbd23b8bceddcbe135522df08c6c642fc8ea0f47fc40836a96707b10a39e5a045b0a74549bbed76ef902238efcbcaa7b35a5f28117c90f62ad2434d731c119cda9299ea2be27e7e083e57bd07171982abf41ebe9f7d93ae0bc196e73fffe8e32989108c07ad5e291efaf941b095dba3d65e0ca11404e3ff9a4b734e4d6f03c18bf2e02f2242d40408c627572695eb1f3875d1204ff503377a59aac634fbed0327e27a8bf4732d11f9c08b1695175c62ce31b80776eba4077624fe991c15cf511e58d32a39b978e0925a69b97777403533c60edc48aaf209eeaa2953073e644e971444f0fbe9c0c94d1e938b6af091cd81bf8d3957abaf9d6b72e02dad23a7cbe97bb438b065a2c181add4f5a53a5ed0aebc8189eb254b6b2425a63a6ee072355489324badd769036b227a760b62036331a70b5a2dc8ec92b306b6b3a84f963fbf29c951031731c6dca7abe4a7a434f0266388219eff65484203a73e9f921efa33709ed3c3abfcd2a7df0c8c488a1062eecbc0e613a5b53c3d6a069181f3af1b9d2a2a92058d81c99fb2e717fb10e111031b3cf577163d0c6cb01211aa93fa2f0e065623c61c62a6da4bfb05d6bb42b254773bc9f5027b9dd72ef04125ddfd5791d5572eb079bbd1c34f5be03f9ace0949827237b5c0a6dd9861a636be995960c543e40aeb4875251638a1fb2ebe05afc0c62bd9d12afeab67053e9b55889ed4b847ae0aacd99806770d153cd95ba7f29e02fb976731433785ac9102d79f3541e5fcaaa489026b57212b9e5e51218302bb296fa6c79ec0e7d89afe39bdbfa8b813b8f4aaeb6b294de03c96aa18b4a5a47b26b0df7ed1f73693a8e54b605395573e253fa95f096cbe85a77852401238912176f03c22d7961480045e735547da1fd1fd8fc1e6afba96161983c9aa7942278fe9e58bc1060f33cb8c264a44c460cd3ff865ef87c1e56c7929054d31a52061704945758c5d9dd99f607021887bcac9fcd27980c1dbc7b4aa7f6dbd9c5ff0f9ebcc7f33462eb92fb8112abd66ab4f5ef15e70da75f725e478c1771cf11a99a7b2d9bbe0ce644af9e2eac9af75c1f9282d79335e69a473c1d5a58a3caa6d927071c167105da545d9e5b6b7603fe97a336dda828ffd262c45e224356bc14aac93a2b682789c169c69266517eef5599c0527e26dd0d4a641c650169cde50d5d593bce2c5824b23430c792c491fc182efa0469675cc2bd84fa362901b4ca5a87105232f5de50d31dd0ab67c4fd684245459ac59c1c490360795bea4254baf82b30a2106192fe69c52ad0a6ed3eba78b68db24d2a9e0f4e3be6fa729a5218d0aee56947ed091371ae953f0125325517e320557a12b7adf4e474b2a05f723443bc716f52a9182d315abf43ccbac4aa3604b445688c12dfef9a2604d08e9a6f25a48c20f0593bf6d7276fe0eb90705a35a2bc7f491bf3efa04a794ee90214fb031788879c334e8d53bc16fe6b6dc3a32a4d539c109adb5316766accc37c1870e9a36794a6bead6045bb75766522be798ce04bf571d6697f3fbb398e0839d59d273f74bee25385d9d94f45e8dea5b824fb50ec9eaed52502538b9c127e91825e587127c5a7ad795d06d4f27c1664a6c9b14950497a1d62a84c50e291a095635e44dab97eaf484042754aa8f353e8253eb3b29a62b933982bbd839a458d9da62b2115cbb47c95bf9a7828c60b25ede360d17c1987774eb8f22d8a034dcd293ddee26116cb06cda93aaa0e46b10c18dce88a94e08891d3b049f3244724dcc10ac057d5aa2975e8da5107c7674112dd512a216bdcfa3fdda41b0263bc8979833c95cad20f8c9494dbbfb3ce56a03c15bd29b629937640f5940b0db4954c8dd183f4ef60fdc5e66e7f8b771a364fdc0db56ce932f047df9d407be2c9be81c3dd976121fd889a369d54cb2c9d31ef89520c2275dce514f7a6093caecca8fa09fa63cf01b29c894f9c703f79f76f4fdff2fe6efc0a74a954f56b251526407ae724e2a996d291583eac09e9d342d2934a40bd18155b3a03249d38e1134076e37ec3a88305da72307feb472e4d3afaca41307de73a974a33588fc3a1cf8b4d1425f820eadf91b389d2d94474ea615d36e603f66affd966bf8db06367b07730d394e122d1bb8bf88e943661731770dac0799d93a79303fa51ad8e03fc27f4dcffe4c039f134789dce02979120d8c9550a6d267e07376483a5494bf976660b54d721a5367da6519d8f6ccf5ca37f164920c8cb75587b797c8791c032f297a5041796891a318d81042fe1129775fbb30b067afd12595cae93760e052142d49b896b4fe0bfc69e8b7c6161ddd0b5ca624b25a4c5d60d3eb2787fe8ef91a17d8a0420a522db345d3b6c0757f7aeb8eb4c065b6cc9e274b3734cd0217e298523a6a4c9d53140b9ca766bdf368138445afc07d6a9a4e31e6d1a3522b70655182bf264f0d12ad02ef2b2ae9db1c3a1e512a30c2437f69d34f81d7a8a93599764fbe14589139855665d38e4781094a089dea9d3c68a1c08ae88c5127895e143d81d1c13bd47c4fc5e4042ec8102a4bce2b3adb04aef25772ee18325487098ceadb324d3a4e3097c0eae9edf7e80950022331782c551d32783a014960edb36ae9ccc9b5b30940021f546eaea04a95eaf6185ca924628690bd63516370124ffdad697cf16431f8c827c1748d12b64962b0312cab4ecaa376c961f0373978e57f26e1a330b84939948e1083af2718ac45dab2d171b73bc0e035fd4a4c8929237bbfe0e48b29f9ff49a6ccf9823ba126c77cb97964d70b36a6959716cf0ad5f082338b31448e0eba3bb60b26fe48522ab787654d174c1211c1f6b55cf0ea9ec5ce74f89f70c1a5e062e941b847f3168c90394753aba42d1893346a5c2dc74c95ac055b2a5be8cf49d28253b5dba347335696e42cb8a0a2764487caa49705577a53f4f190fe3bb1e027e74e7bcaa4086d820523926d25849457f05f95c6a4a5a9cf2557f0b691c23b4d63ea5bc19dbee5fc2bb182af3e8da0761d94c8af82115b31692152052f71437e0c69fc64502a38694906114d4d9d205430ea2e6ebcbce942e99c82cd1837546ace27a2c7146c2c79f9ba544c13724ac1568dba8da89382dff05d8d172e3ae2a3e056549d55d9eaed2d0a2e67dd9eb421294f772898e02d16226332dd1a14bcfb958f127a54dd8b4698ba09d2dd2d6a895c0e3ea4d3df670896e9233b234bdb70838d2be4d843c9a107d63e59d2c1f3ea251dcb1c79c0b49db8ef85d2cfc822c10b34071e380df93958c9cbe4b8035f2fa9c67eff1c76e052db06cd0d3a877cf91c75e0f3b7a913225e7a5242746083c48d2021f5b5d83d07c6e49969ae38ba64a939e4c066298b962ce418724673c481ddf40edaa39aa49895030ebc896c6f956d3a39a6e47803dba66aba9a9b1b1613e4700397f9aae63922a8944f6764f9e004a1ca07a7064fea0339dac0b7da85bd5994a03d31482d3863c10d7c08600939d8c06e985f4e9e5f21f86f06a936dc60430a39d6c0c4503299f69494d098c9a1062e5f0e5df9374a47093923ebdd5803083e7ef419ba468e34986f1f32c7539adb33b27ebc1a6bf82055a573a08175cb8be4224bf3c11b6dacf1c60fd00739ce6006377fd24b95d44644ffe1c61a69a4d1df0629c5f0214719f814aa4ea787d29519e420039fd35dce18dac2418e31f0b9a7fe3d45ede0a532258718f81c74de56c8d4ba1e623891230c7c0aed9c7c6d3ad37f4891030c7c6fc4902a629e81c8f10536051bb3dca2eebe792fb0b1eca35b577bce910b458e2e7096f559c3f4735fe6cec8b2f2460e2e309641c81c838fcee944c5448e2d304a984e6b25416b798e5e22871698782b7a255528b12b0d1f6ae4c80293eb34fd456db5b43158e063f55a26bd4ebb529121c71538614af4ab7bf2bb9eacc0da47cd69397455e0ab7436e14174c897c91c54e0b743da78987e0aace8acdfb7bae831e7a5c09d67d985e93e0a8c34fd8ef71662e7eaa1c0995039869043f3f6839ec0c61c9537b132e8582327f0a631761226d52bc94f13381973905c26e4e5c80f13b89129e48d77dbd7b62f81cdb14a62a45191eb5702fb39afe74b7be531d33992c0e8f518e48aaa1c91750e24b05be72a4295f6188c6ef5a8f1f4c6e054a444896161133c5b0cce563572c62d75ff2b31b8d166f9e9df47897c2294d24f6d61be30f88bda31a83011330f06a3d094f5844c2160f0934fe76aa6f70bdea3c9cd79359d47f37cc109378ba7136b3508af175e1ea5e993a98617dce77429877e8d21b4b60b267d90db7551f7c4325db0a251b4a511a973cc4b2e18b59eb137c471c15b052b9119928eff965bb0417e56c8ce9c1b715b3039e25d486aa337cf5a70a9f7b53eba9b6c5320c0410bf66fb38bdca07365f9b3e05bc74688decbf31c248beb4efac45c009e802316ac464dde3d1252091cb0e0d63e620eba27e6e6fb0c385ec17f2595bc4ca718f2775770213da36d57bc15fc0711a38e055119496505ff5d6a4d2611d4242757c177088d5c317b0c1d93aae024673291e36e59d61a472ab83555329679f55a0a51c1fe5bb0ebe4962776e614fce78570d3da925b1953702f1a9e1ed2941c5529051bdd53c89734450aae62cc371a7257d71e0537d62316592d578a105170d263e85dd0f96ae2474b8123149c7db9d6e84e5b891a5266bb800314bc8ec689e2d92757868001c727f8119e2a2a07bd1b707882fbfa1eeb2455947bde093ef78d891cbae10427644cfdb46a2262fe2638a12257768d29f69aa3092689143d6f3fa57c9d6682cb31a8f68e12d318494c70233a6ed01ff53fe5ff12dcb88a4a59eb5b82915fd2d4739b3ea16b2538b1324dbb9d39e61e08fd8312ac464bfadd2448fc0d4d8217e16e6a39e7d4299592602547cd9bff46c41cb148f0233a77094dea676b59230dd3230625e8d182203c2afbb10624b8bcbaaff7af3d820d3a3b67499db1462b1c8ee0fb3679bcb2246358d8021c8d38739021652edd703082bd4f2aa8bfd469cd2b05c722d858b1dc3fd2a664d32b82cb6b95c34af5cef39a08f6c42a28bd31a7931ac4020e44b01d826a9041241d55ea21b80d8dd143f7890a3186e03afd8a0a5a45c78d771c701482cb9321aea5f897fb070e3808c1b5c4fea0a1c34ac77b10bc9650ad1739e23db136e010c439479b8e95750c04fb92bf9479d0b13257c28003108cbde86cdfba9f29df7f60ec73cc9f5c37e7a6710d871fca142d68129d31fd81d478630df7e1c61b6ca881868ff369bc95fc81a30fec470b223ef0f6bb1a4b4fb34e74f6c06d4eed98a457f4c0694c0b1559724c9a3979e092ea5ec490f2261d723cb05f4a26153ceb77e0cb4786473ecd22bfb403e31ba2e8a471720af25207ae3ae6edfe943747a50c071d0ef24c86e690691f9c1a20351e0666f42069f0a7c1c61b31e8e10215f4581c73684d04d59e3b38e4c0e43bcdbc23e346b63a17471c385d9245858ce8c15f8503f77a1be39d9ef8624938dec028e5956e1d93af664f0738dcc09be86e9b763a6ded3a8e36c000071bd8d2a642baaaa4ac556d0d5cc5135da39b995496fc0fc338d4c087a0eee717b4d8c6ff8cac32caa8c5910636568550b2be4fafca33b2b48c4f0d8332caf0e183130483030da6bd1c3d6b77720d367e7c1b69021c6760fc933cb7bce9e149e4c60f355ca0821e6efc0f337afc70e3cb28e3c70f37be87193dccb836dc60630061c061862f7268ac0c709481513925fe869c4565d3c9c089b9e4fe204fab4b63e0525fdcdc1ea915fae16ffc30c50538c4c08b891011f4ba6abcb000471818dd9362d9dee778908f35dc000367a7fd157307959d6f83940f4e0daea800c717b88b7be937521e871758cb482146dd495b4988a30b7c3699ab4ed856ae45896102071798b89f73d54d9b05c71618cda9a693444fd2eb734696e2d042e111433a9d459f8c5e8d1da00183f2061c596082c827bc36443469212cf092264e3a318921aa73053ebe5fa6241642468e15f8ee94a5d512342bdd2a709ff9224c945aa8880a9c5645ecd41f44852aa7c06e9ed893464adc37498189bb291ea26b8a8ac128b076d22c7a484a37f70705468be7d5cad021dbfb04c6bc6cf2c930a55248700b389cc09f36b9ba9ea993a6df04266bf09c646deafd424c00028e25b092264ffec871a3faa704b6b4b76385d812646db4f13ed8681f64158e24f0257b93ba5d15081c4860d2ad9f86a4e516553c06a75392a23b2ba5fff491e207328cd1e7b3fd9c2de535ad8719a709328ac176101237e8ea85d0103288c19ace9b7ae49f0ca219710419c3e0bf4442dcd28d38a6148230184b71572b88a44b2579910419c1e0b3377d8a1d2466061d185e6b6a8cf96cff718320e317aca9a4f1b2d65414ad8719a67c94410519be60a4fe7e75685a46196a05327ac168b9047d398bc640062f388b7875f94fb34d62659451ca479d25c8d805d7b5fd3da269da13a40bbe4a5269f85d0c19c8c805e3934aaefec8b738e91f3dcc28a3948f3a3c90810b3e68bd4b2ad364abde7a98d163076aa0d1c38c1e583e0a4741c62df8d8973f48d552113351810c5bf0513d644eac4e5af2050c64d482cd227314a134e46e510d2df88a6d51af2e52a6e467c16e6ad0fad3df651a9205a7217ed25d623285f0c4824bba1e7bcfb64fe50e2cd80f953f9ad0ff92d2fe0a4e65ef919d9bba72ee0a46d3a68a1ecbebb56e05ab1d4c6bc692413dd8ace024e52cb9d99e47c67a157c16eb903f2a37544955c15aa9d76ff732159cbe8fd6ba955c534ca2820ba946988e123c055f99f6d635e7d2b49c291819d3ffe2674592201a6bb0f13e4023066594e105324ac1e579909c62e8da242978f3a41f44e6890c9e1905a39ae2efd97753c88b824bdb1d5248c1fab3b550b0aee9bd23ed4f2f4840c156758e243b25fb88ef2758ef8f29ca4c98c88e7b82d35be953d74fa49b38199d604d4d0e9226e59c23d1139451861bc8e004a374c6a44cfbde049f6aecd2fa4a7b454b13559ba5c4cae0d94c70164a66c5f5d8256aec61468f32ca50031998e0afb7828841477efdd825d858ff13a4c9bd04820c4b7097714b978c71c592a7470c54d0630b116454823b95ca76f3e428c17ed0aba9be920ab19d04a3d299a5acd53d1b8f24f8fedad21b53ce0e4a6d063222c1feae8e25351ae69983049742cef311267d043f71fc949af4273c6d47b067a2ec844cf972096523b8d6b13079415a5b14d5e02b90c1085e7c47f2afe9641e25642c8233694975e78abac0076bb441022b3a90a1087e44d475d7a02b2a3f3f84f0292023119ccc3475a22506119c088f54b293e9108c8c755bba762b537b48a0061addc608d010fce9bedcf0e4bddd27295f20a3107c882749a52b47084e93a7fd51df4d25a91eace123065a2063109c10318724b6179a562c4d2043105cd09e4ec8ca91b5731e08fe547bdb86ef89849433b2a240062008ee1252a8b9998b866c1622e30fbc69168f5d79fa640c9e91755820c30f8c70178d9bede49b521ff89084a8b39492fc58e203a725afe7babea855da03af76428fa8ef17fdf5c00611da952e520a269407c653aece65aa4479101e181534e516fd1df85013347b9262be213b7057ab3776ea533cd581b77c59cbb64785acd3818b97deb7f3a4c898039f839936a58248d9ec44861c18bbec8ca3d27160b3ae4b9a680cc95c3870aa31445159a3fab86fe02dbbba5a27bba7d60d6ccea2c5f4bfa856b50d4c5a8f413bcf06beee834c59e93796b90626d5ede98ff7967935709721a67d926960a3460dd14797d0c05a884197929b3370294632ab7beb32e5e9901305e3596428a546e91c53283825d307b7fd78f97a030a3e8b4e72f7ec2973c77c820da1fb2f44fff3b18d2778df10112328d5d0a5e9045b3afa7324fdc1448ce1045f5dfe49d44b5d0e319be0bdeca38aca9b26386d422925bb35d73c99c8ba7d635025c704a3c6d6ff638e2be9be047b1b4904752247cf194b301a393dc653418e6e5689b5f7b3bda894e06b74dccc79a22e9c041b634e22e56ddbc44c125c4553a5af47876c2a8b041bd40813957bccf604094e861ea1377d1ec1e5dbceeea33a828b16fb63c468eea92b8de054f618d57a46304a66d122f8bfdb497a7245302a449294a73b87cc5622f82cd2b4eadb3b6c2c4470664164a4b4eb10ece98ab4963d4c6b5886605c47a874ab27357655086e4dc468764289ec2142b0d6ae294faa589e4283e0dffa3b8fbc05c197ae18dc6272f73b10ac78a552d91744574070394dc7f8a222e470ffc0c4a8f71916294810fa81dd184ab7e9d19fe286f481bd9035fdb87e7bbc950fecd968d22afa9fff92122c600f8cf2b47c9f22f3a64aaf61017ae0921297e81f2aac529507c63bbb0791738f9aa4c6039bd63ac7245a3705d1de81f38e95cbfc3fdf946a0726efc694573159072ea80cfad143493ffde8c0c8a8218920e29ec4dce6c0dda80aa64268d21c39b0779e9f374ad4b08038f01ab2c81aa99b9ae3c381516e96d79644ce90f537f093ce2b9508d11d217b46a661016ee04c62c42cc949c83c69342ca00d8c0896475f4ceffb33b1814bfbebfa2b663939bf06767412b3d148fa4474d4c0e49077fb94b7b7779506364531bd25ef4403eb212d37f37c64c89b33b013eb2ae7d04cda259a810fa6a92142779610b1332ca00cbc49eda43e6f0c19383f5dd264b94e4a311b03b7b14b6f8724d7449218383f1192822c57d38a8781d51d1952c4d366a8b2d13ef081bee2b0003030d6e95466254bf26aff02135d47c895d8bf5d322f709a72e70ed94f4e0efa2e70fa5da66f6495a5a0c2054684ab5f1276dac296649688efbd5ae022a41bbd49080d9adb2cf01d1eab62b0ec76495860d287d0499ab7ba48f50a9c8ee962caa6d1bb64d20a5cb0ce9aba61153cbd9a2d444fb73b1510f9efd2e5208350ad4d810b76b916e4b8e47e8d0f0b900296821215921610053e5ebbbb96360962211458f3effc0cb5ea61014f7044248ffb9af6960538c1f0d0eed87d63a326701fd1a359e6601fb38909aec5530ba2ce4c6eb78025f07a42fc5d439012f8d22d7d5224060dd5594012f8709341284f2a0b400231a668fc94478fc81c83f5e0a37e951eaf4a6b8c7e92f60a7631b88eab12b33f4b8ce368b41029e5ccf2866170d57c1274b583c23082d039c41f25841b0c2ecbd6bf9398b21c638051e5f5a4ea764231d0f10bc62ea70ba54cc51756ccc943baca0d29bde05ca3468fa35379d0c10b6c2f95e93c5d2165d32e76df8b4164754b9173bae0ce34d59d89d6d86f6764fdd044e8c805974247da889f3f8485e082cb2354d34d75b0fa112274dc82cba0833ee5b14f4fdfb6e0b43b87fc192af604752dd8b4bda0cd532aebec68c185143773525a6bb4c6cc82b1bc1edc42fefda98a2cd888e97eec94af98ba6251cca764a6281b16bcee9a9f473cbf4bd52bd8e47ed9d15ac52dc8158cc58f7cb1528e97a3c408a1a315a8124965c9aebb531356309a557692a388dc745ac5a6a9323c644a115505e39a3f9bc7c8b944d0a88146b7815281bd4557bfa8da222a4abfae2f4d9f4a7b8a3e6a47b22f0f915953acab59523ff5c74a6929bccd4b2dbfeb94d7523a48c176ca6af1c5474bcc33081da3787392c80cea3de5d2e810059bef675e91c2a2086529213c9212848e50e021a667ca11d7aa8d77038daa1e3128418f129414f430a347a5e0d3f06ee3dd38011bed03523a40c19e781072fd6b1d9fa8320c053a3cc19727a144d24a9e8e4ee496797bda54678f137cf6493555b936dc6043c726d88ef9e97ebbd194b2e8d004a36bb925d267649971061d99b0926e8e9e3ad665ab7d58010012746062f18a242b08e167ada087193430c3aa4b709a4f44db686faa35b564d06109468f4a9653ab0b838e4a7022a92ca9644a398f327550821d9de9b3a97b8a219626613a24c128bf68e25722547dae23127c4aaa7c93a20409466a0e7a820cd623189da7c73594d69455a2c3119ca66c2a42e64f216f4e4723d8fcbed947c9aecfdad7406ffcb0820e46306935448d1e3b6b124a3a16c1e660a2d2c93cf6ed271d8ae0db35547617991df329117ca76bfd9f7c26624204bb155fb2e48f9ba36b8760b426d5fda0d1c4842c0d3a0cc1a73f7d4bb2c4f385c8051d8560f2a52a0d0d32d907f30a3a08c125114d875892932ce828021d8360d3be6e8cd1af3d84f48c2c1f56b6063a04c18bac24cd26de66c531108cde5cddf3542aa80d083686483aa54d11b5ed1fb820736d67d1fe5e59e4073e980ae93507bf8997f781539d3e846421256a7ef9c058929efd2a46f7c0c49042cc2427e64df7f4809e6a4b2a962e79e062ad862599c52afb06f1c024ad3d7ae944eec067eb343a45cf5f59b303a7e4de7ee954d781312ff54a2fba1f74d081fbb698f775b1937aaa7ffcf8151039e898033f6a17dad64f6f1a4d8f18a8a0871374c881495faa529da8a44fdf38f09b2f97074b9a42ed6594618a1e74c081714d13f2043715e2e674bc81f588f7a934c5e86e313adcc096aa8b218eaedac0568eae623152ded0c1067ef2aeb75590b132660df4c60f32051d6b602bf333254b7c9149ed820e35b09a37e27d4c7fdb77a7812dcf753968487540071a3477b1ce182da5f654cd5a9b941fbee2f79f19749c8135994da9e9e4e425c121e8300313278f4c4ba23d45ccc90a0237117494813f3b13727f2d3e7c70a5470c4a10833fe820c3679741b4a9ae05668c41c718f87eaf5832350479ca2406de4d624ed2d29ddcf330f031a8ec8281915bb2e37566bfc078b77be652d96e42f5029ba964aadfbd0be91c4a763e991f2ef0319ebd8b16dd1618adc1da2a4f694d11d7029bb9429a8a9644a7a0cd021f3b44d5dc1025242bb1c08585db974e1bb6a7bb02a3448deeedf3244f6e0526483e4d6de94cb3b52a701da3692e13e9473b440715d8e8e997934eaa6fad2441c714d830db18f1e35a071ba50e29683d6697924e9efc828e28e49a2984360b21e9b7a1f0798e59b5e4c40d7fe3870f83838e2770229daa6e8fa9c3096ca96822be7787c8e80a414713584b1f4b42dfd6c1043e64fe9074b4bb94a16fa30dbe36742c811fbbda94cb4ff8279312f86cd93fc6932244484e1238d531e5deccdf2593ae03097c9a0c6229ff3c06a72fa8fdf86756abd318fcae88975de724fe6231d84a0d295695480c4eff93b6e02582ca21330c4eb8e80ea1d2688eba1106a34c475bb4bb44099560b0bf56baa2a409cd6d010663b253546ac97fc16b5604257aa164fabee0839806df9d98363fd20bd6da4b4373da286a7d5e3039554410f5d8b9416817bcbbe667c918316d8574c1dd250fd7169d5cf096459992db1d3fc7830bbebd7454b38ba342e5dc82bbcad6fa313bb56bb705376ab2c33dedd6d35a0b7efc74365d3bc293a7b4e035f965299114e27ece824d93f4ee95530c2a93b2e0723635d9926f2cdd632cb8cd418504ed65754284059b310955d16465ec0cbe8213a9c7bcd38daee07e77eb3b7f5e09a15670371aabbd32a5bc946305ff2793642dcf1383e456c1e5ef31a51b9e273b46158c6951b3d3d61c726252c1f825fd1854d0dcec182a18bdfaaa74a64207f529b8789353caff4f63b629f8133f117b7f4f575b0a36a79351639fa4e093e57831e858954ca546c1a47a11dbfacd508fe410055bd74159c6f554af9f8d1ca160dc745b289be03992aa6ae31fada146d5a3d1861b9b03147c75c8addc93ff04af66f235794c97cd523cc17ad67fe4a8e51bba57030d5c418e4edc19379d4551af914602e0093938c17a50f74f55a333b2d858c30d34dc071b3fce083936c18b6b26d1ffc819593fda4023f960e307f11f6998f36cfc3045841c9ae07ab456074ba24cf07ddb954b9f12138ce5182d8252d7f21d2fc1fd86074f7fa352d3b504272b5f8a3cf9df3c69a4d1597ac4a0043ece70838d4741c851094ed9fdbe7bee4ffa254a7021c88ce49db43526951c93783d4acecb3b046ffce047707e065596073924c1284befb14eff049df748b02dca930ea612fbaa83046b19262c7dcefcb6ed115c6c93a53b47529afb76045f974a869ce2d9d8441bc1f79a4e4af3ed7a7918c15a4d4c59c274aad0390c722c82cd9bdafdf36a3f3a0d9343118cfea5b4a782d54db2e4204722384fca549b57be94ed470497f2e9f3d26a77ebfb2198dcb95363d5e854b13604976d1f34b7430e21bf85e03d5eee7b06330b4984e0ff3f8aae5e0dd2f28360d35a34119d7d4f7229083694505716cb43c66c20386d37cdb01073008253f172d2a47a8399a7e4f843499d0a76fa69f20357aa92e74922c95415ef036777e04452ad693b444dd4b81db85bdbbc27ca4209b3ebc047f05ccd2f5a3a70514fbf8d0ca18359760eecbb6b121a72c7ebc9ca8117cd11237fc80ffd6b1c8a233b706035fe6da70a3965eafa06de63bafc39fb3e249d1bb818454adab798d224d9066e93ca9dd9ec4799101b58f7dd4eb9f135b039c64db943836ae026474a1e2c8269603d491042c7aaddf8a381b1bdd310a4e67e1edd19f878fa19beee41fbe8ccc08f5031dd86ec19d12f033faa729514afd4eac8c07b7dcebdebd4749b1903e7c1b62b3b481eb18c18b8e0292c977af7f4a030b01d51837e5f090cec87c79f186a17f12a5f606b633093a7e4053e6b2fe71449c9beb70b7c04cd79628af4e7738153df4c162496b6c09ff012a9ae6981d52ca9bc6388ffe9226764f928a5470c4aa007066481eb3c0b49ee792915f4a26000165039430aef13ff0a7cbc18feefda7e820156e03a28cb49c43d195005ee3e75529d92252dc1002ab07eab39e5b3f813bb5209064c814f77c1544c4f5630400a7cd6c689d1deb792c49831200a7cc50c42a71ced1c2a04052ec51c5b3f9ddbdd9aa8c08027f03b7a3f5e2396938c33c0097cd61e3d41e8cfdc15a9c981014d60f5753cc44aa78c3218c0047e828a56ddcf10f34c4ba83218a0040624813d4b66d5a9e4850148e06ad72ce40b25449e760c366e2c19cdc7524a217d041ec640838d10c080013c8a418c1e3c86f1a30d34d808c18f34d658c30512e0218c606c800730088f5fa491469be18b5e6080072f2cc063173ed06023042e80000f5dfc51630d358e1a6bb0a0013c72f1001eb8f82184ef410478dc020d364210011eb6381eb5e8c1831608e0310b59f0e0110b1f68b01182f71601193c6061011eaf501eae58008f56fc7834d06023042570000f56fcf8f169bc1bedc60f1f0de0b18a04f050452a527f1a64f040851b6bacd1868f367ce0031facc0003c4ee1c38710be0714e0610ae4510a37fe870f520821fdbb0f34d8088110d2bf0870f018050e1ea238e3479f21011ea160c3c78f04043626c0031417e0f1091f6aacc1001e9ee8041b3e68e30c4e6c42136ba41d3c32f1c30d351e088f091f1ae0718906f0b0044a038d334e252ac0831214e031090bf090c40f08f088c40f36de58a38d1df870000f48fc68630d377eac61021d3c1ee1030d3642d0c6f7a08d356810011e8ef0a1c61a68c420033c1af1831110e0b1081e3c14e183013c12f163070f44b40f06f038848f03f03004193c0a81001e8428008f41f0317848a2ea93f2bebf020f41302a5a925497f7e5110836a98bbbd72504083ef2d58bc6ac1653f6f0f8032b761f4f8e6f5af9ee073ea59259734506c941b6861b6c08a18d833cfac07b2e7929b4d7eec8d5073cf8c0a8673af32e399ed6da0327967ddc6e5c846ba9072eaa7ef5a44ddad355fec60f7482cc039f526d25adada9a44ecd030fecffa81a9944c4e30e6cc6ecd151f275ec537180871df8102986d0f9b779f1af03fb2bee7ea9273d955883f3c1830e5c46c92109d1146b47c7630eec776fb20cca3e7bc669a3ff870f21b4d16aa0e1762ee021077f2ff69b529b1df0884395a1071e70302575d32f3966edc60f34540083476bb0a08d357efcf873def851c6efa07eeca04560460f646ff4e841ca1b3dbcbca18610900f373a0d129451861aef861b9d46aa2a027481c71bb8aa728fa7cf2da52bb981750feab446dcdbc0aae520bc2fe488954e36b06a3a8a4d50bb962cb306cedbee5275686bd44929010f3530ba3282e93125ac94d6682391fab11fe091063e99f76bee789a37da2df04003ffe31f5f824ca292483a03ab9a4727d8c574a33d33f0272be7d02054f49c2c1e65e047887c91d4a5f4f49c0c9c0c49e8d13e216a5f19039b5d1fa6deb3ebdaa515fbcbe6c1bd0a031f3c27a52f42464bd38a117880810b993a4b5f4a216668bec005c92bba54752ff023e297975e5d60340615e5393c5ce043945e9a1cb49f8d108f2d30da7e2bdb8b540bdcf6480f5d62423b8d2a0b9cb2f3ac9326a75352c2051e586082125d59748e4c41b55760540c29a9a02d6b055662069dffeb23664a5681937ed29366fb5259192ab01723be04dbf414f88c13530e115f44a9500a8c0c65b6e952b288138c0217440e79aa153f236f063ca0c055fc3c425f88f1b34a86c713f84c4b2afd8d7bce9f5911783881b1d4a7da64c510bf727c706a7050e0d104b6f30565b24d2b72481713f06002fb9af2b386e686c063099c679668bf53151e4a60e2faa9144d49891b396764a5d13e88c5814712d89ce2668ba6926764211ffa061e48e024784e89db9736687a46d631d8f70c91dc744cb602a14fba61873176148309f227478b787d779333b288c1e4eb7cebd1a64753f7d1c630b8eb0ca6a6631421728c1106272bf5c7b89f538d57cec8f2d14629c1602dbe57fe3ae11959c0e0624ab94b622ea17caf33b2aaa061c72f88ba79b4bab74b690d1f3d3868f4c00f3b7cc1ff7dbccad3fe8cac1dbd60548ee9acdfa4c8b1dc4702021b3edc38adc62b2f78b3131de28de7269d9c9195be0d1fb90b4e73f0eb47b361c2b043175cd60912bb5bf4fdab33b272c105b9a7d6394ac4c70f340c0c3b70c1aaa6bce4f974a9f9688d53f2167c9946b0d73bdbb6a048ecb005572131d9abe6207ca3b56093484c29ff9f3a19738ed8410b3697683e19764ac48e5930b14ce8994ca32176c8824be5a35a7a92f67d0eed88052783ceadbaeece9fb12dc40e5870a63eda8698e5ada7a484d8f10a3ea53755b1cb3e234b0d34fe0710d070e3b41b75831daee05a2b6b05a513e2c5c7f7a07d402c0d34dc78c3d860472b38c941624e573982a70b1f76b082cbdb28923fe8dfb17f156c96e6cad194af0ade4406b9a9562b7c47a9e075553f7f3508155c5cbb8b59a28d8bbfa7602d24ddda27f263d66b0a762b9f6f6f921d2497a5e0df840475a12505a73d4946cb29a7ed1047c1c9647d2288720d726444c14e0adea3b932f5b3150aee5744505dba25da8382ab94ef8256d23d71f40946898955ce1e62bcda13ac0795b427e6c13a5876748211511ad3290b31abc909562c9a98daa0dd3a256d820da9a24648d2ccca9234c1e778521d236711294399e0a386a4d55b3998e07f376687ebe813e55ec2743aa9d051444bb029cb644611424b245a092ec72033c83a213d8d45097e2d73d0ee793a9ea48c324a31764c82b31c9e694c9fe52404c10e49ec8804974d07bdf6c88104d72543ae5d87a830f923b8f7b46229a6db11dc464d37823725df9390b7c1b455463039f2a824ad4d49cb17c1058f6c29ed8ac55b4b115ce7d115f9d184d43849041796fee347f5c939428860f3f2f23bab7a0836c85c49994fcc1a7618829394cdbdff4db7e9a8106cef9985dece494a758460837a50ea72ddfa488b9a61c7203821f2421251da7e4a1dc30e417025aff24070a9723e750e3b00c16736cdd5d94e56fd49e1b0e30f5cc6985cf74f33db327ee0d647ff484ee3a554826fd8d107de72c454596342725a75b0830fac29534ae6f66469b0630fece9f6915b67631976e8811555a7f62e6af795bb64d891073e57085da2dd967376d0ae3d6250821d786043d606d591edb8039fe3d9ea496d52dff0366280d490811a2d30a3470f337afc93608d18f488810a7a202576d8812bad7e6da9f4e66477471d187d6ae26731addfe574e073e706e1fd93938c493607d64dfa859894ccd4b0430eac6889b6412b7b901363c38e38f03fd23f3764111cd88e29bdbc267e69d8f1065ea4a6e5865c1eb4e705073bdcc08a4af2c694a7520bfd0b76b4a16c12534e1792f4851d6c60948e560dc9ad59b2f4c28e35f025936da50e16b2fa038ded118312a8b1430df95de49bd88e34ec3726ef3744a8dab0030d6c8c24ad6db3e876297960c719981882f214b45c33f0b984469012246fc5b70c9c96681f4f7c32f06a63d9d9ad6234618d8155d1edc95b317061223fa70ecb1b6c8481915d1736b1b31d60e042e68ceafa495fe05f92054f9b17f5dae4057e7cd2fe7b8e1564307581fb1259b3554ce2029b524ca5b2b583992c6d81892554cd357a957eb4c058854aca23bf879093055e5448428fb6bdcd712c709da36a5e89d9cdec2bb0fe6e41dd48adc0d908cf1aefba92955f0576b4646a85f0a9c0ef28172172041593ca4f810d95c9bc944c13c924053e9b66ff8a6e14b8cc39f89f9857c5288202132c06cb6d2572080f3d81493adb43de9f08962127b01152529325869ac0e851bb2b3f51954a4ce035a4dfad1eff1a7309fcb54beecd56e93125b0b7d136bb82674712f8dc2f296af65eefecec4002e3416fe9fa6cefeffb3178ebcdd71625e48fb71b833fbd7f3a4ae2c5e0a39f486e26d9724e3731d8f292277c9247116d0f834f7af29916353956dac2e0b6821c91747bccae7530f8d050b1369d8d483a0b0c36a79eee5bc839e4777fc1ee2525434aca085a5d5f30b23e7e86e8509ad2ed05e71d9a9457baac132e2f381996dfd22fbb0bae2467ca9dfd21a56a75c1c74bc29224ef949c930b563f8552e2dd1a348d0bae744704b35119317d0b46e5c97a97ee62d66a0bbe4b959212453dccd45a70f929a83b2f559f374a0b3ed6aec7539da2c9340b76cda3760eb92efe4816fcf875946859f2a5642cb85c2a6f093d163e4958302a8229992c423a1d7b05934be77b8919aaf395aee02e28dd6d3f229e0ac95670a1ad2f462db1823d35d12969d4697856c1fee9f4d21e4755f041d4681665632a98a0ef4ae70ded54a643057741a5a0a308e91693ee145c109e64e63cd24787ce149c758a9336678cc1f72b055fa1d994b6d14c953e52706b95c193d5370a46b9fe5db6308c3fa844cd6402e3b150240e89c30141200c6eea3d00b3140830282c240ec501a12c4c24b51e148003482a1e3a2e2c161a1a160e16100e120e0c8542815030100683c180302010060331a53112a3fb4421b4e90d6d43561a106c0879174a10c20842915f23cfe3901193e826aa7d081122ee21a64894ab9873c7d62bca81cb6e7cc2209466b86036f4378412d1a310e4a1508aac130913c23604934ef4364f091c17fa1e874a68c83c8e550487c81d3cca75da617bdc50ce1131d4bee745b9bf9297d075f14187bc460b0375a33fc64e3fbcbb29b0700df6bf9269890428d6276f83cec94d2c3a18bd04563f54e6b0af676b266ad4c6b5d2e18685c8f77b7278b885b5cd9d4c6ca504db47f542d2c5f1c2946eb11a90002b806454d890e2176089bcef6139dc3d0840c0d9a3cbc4eba78aae45bbfaad6a7a39aa8014c7a9a2da54509de4d8e36bb6b435506b95a576e1db1b006e77f7990178acc7d4755dde8c32193d417ac886cda1da3d888040ab1f9920061826fd450740097ce6f6a5abb1e7a55497822e1310e12d60b8810b5d8303bec1847a43abcd00c1c43cfc087eb01ec9ebafe0265d4b1fed2b38210e1b04b1cc820aa769846a05412a238dcab082d00a15e691cdcb727e956d84df47c0e68cc61e8d1dfb3d47b78ba8095fab768f66fa9eeb195034bd7bceed5dd4ab9f59d8bd84afda56cdcd42bf88b3517c08898ccdb43a2ade3dea629e33bc594ed3d7d54e9ebba77b6ffb781eb55c53c26fe70a2a1b06157f039eb43824ff8768a47c523dde04c3140c5f82e7d395e85de83c2d10f0bcb238291917777652a314cef02ef9960e6e6ff8c9d1dbb950d5cff5b87078947fc70e3ab968dd3abea85ae8b8b7f914c137dcb058fbe3ac512cf80e489591b4382a8ab36144f6725162a230ad7206d5de4374f186a71a567f2a17aea33f8a9a058494fb21e67f2a7689302e561b0e2ae40acd0d36ce57b415463deccf3c0c7b14760d0b39367261ab62e02ed84940d737b10f922aa2899d3cd9cac4a1649c02c561a81144abdd7567197280a02ec54d37d70d0167e366f873f37ec7017671a5cb7d8a1acc2c37bf07884c1111246fc351bcf1ff469aa56c36392a760f69be62e56810e6471bcf1d4ebaad8f9bf61ccd94ec916c2e3a689103c7e69c40ad457b9a8e06cc895a040b295ff1a4a4a9e9dc8b32d269b6a15ab2a7d5499382872680d21644fc1826cb99b9fd9a829914f6ce604dc19bb2c446940248219446ad1a857f2099eca978ba4245d07665f94aac9ec16f3ee356d0eaf1dcb8829e73a8a7c5df50a64a5d2fa5079216236daf0a2a1bd06625f89444d57805b4ec4d4cb0c0f634b506adeccf438ed37e9f01cba1901896aa8bc826d1ccbcd354b539b0810777b40655e74ff86a5b1e02148ac0f1478f029ce92e7807577c45074bb4dd951ba23197111e3b6d4b3be664525b39d5e1a98b4da7fa31a8ced02524a513e635680d4e60fc3d7cfcde9112b89e58efdde46249217a37bd42cb293890f01ecf838a5095b9bc4de79d8c393c694915f0c2cf509e9ea2e35d7eac38babfe780b92e07b4c6db16e075ee1e9b3b99757d008cee2194cf53f4dd7ecedea0e152a38e708bd076aaa836521f6f6e4619e1fc2e69b92b0023cd7f4df48f4b14cad5c374d7ea3c6274d6346b0f4c4a3c6a766f8e3f6d90e8d09ba95073af919849aa5fa960c0451ba9f96bed6971913b8a56624792e07d5aa2e1dfc87c4dec2b5ed2fb731a3cc9c3693337167c2b960f7270c5821c320681c0e780e0f10382bff024f6d74038e80f4f6ae125aa31cd043f977016c1c93a60af0fd70bec969339b39ba3a8e8936a8c0c1812fa14b1b574915882ec933a69953d70ea454a3de5aa3fd6ad43768d0b172fdb9bd4e95302a27569df98ccd24be7cfb4092bfd36a6d76e3bb61a1e3e2df30eb5a6ba14b5c1d7022dc445a9c5421c6f5ec886db90206a527298f4ac923a407bcda27627f6c1c4d3fba5fa170a25891aa9366ca46fbd40d734db4246a504e9405d6b6d46b88245996a182c91f6a7544f4dc6f9b66e9911d4d889c0e89fe4b02fceb6416d27ead9472d1051bf5b3b8487006e7aec80f59a00d67cbaa0e70809482c162942eba72776f5f194c1c6f906cfdef8a567206cde8068da443b8534379ee4e7ffff2ed5b3009d300f80412f40e5275e7a12ad989d16a81100a05303dd73b1bd39b18fed41644c2327ede8f8ffdab2c7084b9ef82f657ae2ad8292084d37dae30bded57f89c5c1ed9c742dd1675779680f52722d2c914904d6636f6587c21dd6a57425e7f5314f97c6009037b85c480b3250ef57d117e032d3db99f1e26f814114f57238f3a3e3bb68665c43ea80f48fd0a25542265611bd9fae64a8950df2d865b775bc20bd5a296d0db82e77716108736eaba557f2225f237be19c107710a8d054919ef830c72500d840daba77e6b22af810c797762fa241958e403b52c961929df05721ea8d9a823968fca77771ceed9972727455930e3ec7fc40ed20f0ce65fc805329effe43523a7b46a06a0aecd087dd2b03aa72a9620c12b85a497e19182c687aa980bb9b741d2c37d24a2fbb95303832f04b9fac643a03fdeb0f4938c745e10a99d52f14bcbfd3b4b11354bda71f83b367ce09753f8e93d256ae6a38fca01e2d0a6e27bc654427cf0a35146a6b41cdf83e6213274ebbf1dac8985f33c925facbc5576be691cc93bfe390d2d1d1a8b120e8b129d231d7afef0d1b79e4a6444387238b6ec61bf775ccc6baae54f0f09b9b6c91655a8ecae40a27eca275ee8805f3e06912df5616d1094e281e4ec0084aad0d0db1db845870d7dc811fd0e74ba0c13b86b456d3a00574da76315b35bfcc2058d78405c4ef659b5ccc8df2d906261964236b1cd0ef84d1f69127e228a561b1f1a1e6a72c02c9094d9729046287a9368e63ffc4f494dd8740dffaaabfc4b049c8fad55f55ffb3fea2473ff047ab7bb3c28f419f397db77d9afacbea374b7f859d580ff9cd4313576d1de32f31f4858792a0be74e6515e42abfcb26a078d7d1f1b0a845d603d61930fb0511fdba0c60a78c040db157b13b30984025413523449fbedfaa30a6b644096a026a63ef86407131120ae89391f2c5dd5eb2a73d6c15881ba35ee9df15d2d47dffeb6b220dbc8348979e3bb2bc1fd3c26bf4eeff253257775c69fb4f949a527832b516da46f931a2751a961e8d595bab753a5806a944e51d51ae0d528ddaa7ce1610a5046105de695bf009fa4bf3d134660506b14706dba1efd28408c5839ee191ee99f253138d453128cd1439714aeccb3fd82c879c53b0c5500db6da45e44eba8fc2daa33d6b0028b0bafa44dc38dc4166511dedadb4a5ec9e2a7f0031b1526f662fd39125e7fb110c40e9fd0adc4c60fd727d9a4360237f7918ebdacc9e5a4ed120bea8fe03619d64883c15edeaa9f2fdf21f653b29a274f245eb1132d9a546a1dbcc901596352e86b566944cf800c9c7bb2892ea0f7ae965f811a03022115622df13c733addcd3e9147a776b63d7652eaf5cda6697a59ce469f260781234dd0c0e6ee1804d5fe93ab58a2480e5f7ad51a84216d9480cf58a383b4f816c8713156d79ceec6d1b3b6a108a06dbc38dacd8944b30f75c60a4992d752744a312bca0f01864dd77bcc47ea0ecabdd80b61d9e6aa51ebbdc480495c5697c5ab958bd1d46f36d287026d30c9010541418cb8d3920f9a34cdd747dbc6a4579945cd5094b5b854a9285b7867c402fb03462ec63e13e656c7769cdd7dee0be2cbb59c5aadd3123b0e03d4f00fef51534061572383805ddcc32a8845548b518ab4c1ee539970c56c213c4b06200f60f57a83f2374ff063f3eeb7a6d928addfdc06619c543b1e6a26509f1b376d0f2db640a1223f4720df1d7f082432db639c0464b156d15c5a53f4ad6a35513fc439dac0c24dca0ed25a0e3b1827adffa09043cf07ee21717c0dc9c56b5e79c6d9d254b2ddc191e804bdb473145d4705137fa007ce2070f4d4a30b08eb50d5bd11b98f56e85f6c5ed417d0da1fdd5a5214536a67e67af009b5116132c882d6686f74db45e08ba49170e4932544f1c42a8dac34d563bc61eb71fdb24b551e5b659c50f81217af0e6b22adfb0b06ee0ae07eb04168a1af2c25bbd334acf35c8ade049253c8a118f46a970eaa6c3be7262c01c5134a69be3b89f169d90cca0d54812ccbd59c382d2715cde26f9afb0f99678c06f8c18b1a53fee6a97bed68bb823d914db07d18d43bd20f5f3ecaed8b3daf5aa52a132defa91c6dec5ca4e0f5d892a69a39b0514353cc83c567aa6018fc2d82ad546d6022fe0f9c8162c359ea29601bb955e8a18327430810c920922712d914c734d93424c223c28a083c6f9272e2e867de0e8e2557e80649ea202845eb7694092a18072b0f8455c12b50d071645d2225936d55515a1c1b45c6fb0e763d2964670f8139cd1464e674682fe3ad60601a8b125e86fcb79cfece40db53f0e3c652ddf0b26b23cd5ca11aaf19689868b40b02c7838ed5b020484b40168fb0ce90a5537019c2c2f64795900a369afda35dcc1a220c2834ea2ee293a892730583e258a08131038b58e5ef179c7232a095b41659cc829aeed44f8ecc6cdbb5983a957fbe6ced3c6e8988b059a248dc14203d1594c437006b82c76d9e0b85624038a3d44fb3b89013d83887c4a7fa21e2080025c7878bd16985ffc99d18498a373c801f08f4bb908c9ea5edb3fd276459a048f71074b658304c411bfa2a50762764263eaf0f53ff87b37f1815345e0c32ea3704471217ea4aaeb66ef3c00762f86a276c7eb013c1fdf4a05658dcc15c7bab7b7546b11d321dc8b2c5d79ba3693cccaa561dada05941b5a2689583574362ee2c6cf158a9571a8f35d49ceb935aa8111dc6430b61663012dda0f7c4ce22f48195fd5d813797232c1db9ef79339037c8a35170c028516f81e7958ce9929941d1e0536196db7f211c02313e80191d0422b1b3a195540a71f965baebc60d714c342f928769027ea24287c6b8da0d55d0b211ff636c2ceef03fdf04ff0331e3a3e73f2f5fc903a965623400742eff6f7722928ffb4000da3bba24e3ec30b3bb7a387e6af9333564e34f3e204f53a0bc7897aa3ecb31a6af0642524ffadafdd414011963761bd936329904b4b65e2ffdef1a9d59cdf41891a8dedde485e7bd8916ba38ae76a5590323927df5ac010b5836e94422c22bf57e56054fb5e3910b80fe2a2a648a5ea0ddc5cb8ac5ece999a32fb54d6594bda0ca65ee83e29861c4f546192dd9f6ee84059295e440ab1b3e142d0c332908aa78face80c877eacfa77793a7314b91795660025ea6f0cff98b7dd6ab37a0ce81ed50865ce868bf28fddb0b71a99bca4fb41af540966f4619de037d9a777356f2e15c29484fe72340e2af1b5cadd5875fefd8670ff876f88849e58d94e3bd2d1fcdd840fe807e16481d1e03fee75b721e2ea39a9ee0babeda53b69587413dc7654872022b7c94a89064bd1683ab25b0653dba6a7d0ed10182cbaf1aa337962d263a3b9a80b9e6f3515ca289813595bb6e4049b96ad0582f8e348c6ee508c4a6933a572ebd830ca505bb2ac8c7d64a64f51809be905c018538549a0fb291ba50f5349e4f38e08818bd57fed5ba74d9fa00d8a062b0a6225e3778409cd969eaed7e076f1344e8bb4d95f1c045bb84758020c4b806f51391af68318ba88b0762d9e33f10d7840d5f2d6d964003dfab8772a98415cbe1d312d27e179c561d169c298c64ab50215d4efc0aa06c02a13f1d641826c51e320883162a0b34f92984e82f53e8691a238a919e1873f52c976f630c82b1d72e29010c1a775fe287c1c5f74cdf5b11c4b42f9bf3da182a1c79408f1d1920f77ad6167025a9f561c59383e73618978d5c7ecf3d11a242b24fcc9c19b714938e7310fe02845cb68d28ebebddc783bd261c6b1dca7de002b0e83b46a1e79f1b2b75c4dd26f38867a0098f18db72354c5670ea9923e222dd335332fafffa3220a8a34e3b2ff84de076076b1694876bec50413e9d4abef21612aaa0a31fb291509ed43ccbbb6bc2a5713db695809660d6fd0a9fc1fc02dd6c58a85daed986045b6380096a1f9a2393682383b560bf00ee9f9757e329ae74bbd6057972ef6752ee0dd6355531f64d010090ffe1669400403356168d63dd53f276f64880444c76ac38a26977510f633818c459d6d45fc43c6ccb8129358c1aa606e5f8f5e035cada82a08a36b568ebae11d0f15421656a245c962af1ee3c59c397bc55dc6ecb9015ffc8cfe903befb5421e21573bbf6e497ad38a3af7c7c66c96cd4333290714bbb306147825f1922401969a740ac20e3800d67474c0329484540c42db40e5c9a86db44bca76a91703834ad20e8646399a637804e408aa01d9828e454d4c2b308711011633fc82b59cd1bfdacf1fb80088829aeb4c2f4006a899dcf44cca4d5030851583f36a0382c1ea4e00b8f4446b59b9169400b31d5e96af4e355fab1dfe45b7f1993eb7683ffea13918492b7ca7556a5742d78a673aa6ec1b7fe5a1a5b349e89931dc25614ba11c5caf9e1ec7ef66800293c18394914c59ff8f8e1efc8de432acfcb85ed099b273a6b8a0ce7f41d8fc970a319049908a8f8f52be850a623b408ac7ef01e5692da04628ef80009187021824e91ac11aa0802497d2775252086fcc9482a7c7940bee4829020a40a4245137ea420af2029fc265012240a740251814b819ea02aa44b874f46c83c3c0f66088e0556a1a2c02a283d705230145cb478777abdc873041809f94341d161bd1ed9e4498354d2a0512c721c866a8e18d5de379326b5c4bc4ce57775cefc9af6781ba758a41c4b9121b3e633205e65b440a2e595d41e66220973af23048bc625cd0871f5d6327ff54ba79261e1419cccd27617d032eab6a44152ea92097840bb45736dad1fbc04c917f0676113b7883af10f463474097a0a013bb22e2743bd773f667cde8ee1d7138be55660ec88b263abc1141f8f05e6b17d7921f69e4e248266ad42ef1ba9e8525e1cc4a78a31e5ed4cbca39bb05e3a858dc467f8df2f3ccce9af869ddbd934d1611c42d8561fea52135752a457be1a2ed46d7c80581ca59e13256c8f5dae7d01f0b988914148d4fb651813085dd0db1a28bc8475694f0f7503b5d2348936a09d873c03b6e9c34b945e8142f56c46e7a10b9651fa6e256cfa75930e5133a0ffedd51d7fc87ad1299bb8b5f0668694e1f67a14292a12b2e304ca4f1bac870bea86a53d09c9459d86304b40f1e1a256979b3b9a12a96a196ae0623c24ad6a6743c348d36217f42987fc488b768f38d0946534a551a53733afaf856714ac68134d2e4f6a748ce82bc428ef7792391a31decc44a8a61c35036bb5e5be212625587f4ed487921df0989864313576d06a1131820ef1d4a2e98626613f21499f7071905f65d83c0d1402cbc5d84eb0a783f284c95488c0064411274e1560e05739b96c3b047e741ba08eecb300a6d882df07167489a5acf32790a1a8ece46b218adbbad546195753531f4201ceddb22f5263f0b672dd42bb5d061ad1ad892758dbfd97710dbca31b9e58ef458cb058fd9c53c6258ad34f040e08534521aacdd1f31293c51698b039e0a827061dbaf69ebed0bed15a912a6a62627e1a304a3552e0cc32bcd4c18f5a53780255f533e54e91be95b0f166b4ac99bb262290b03297e1bf0fee77bc5bc1407ca98a523fd0eca75ad0cd94c467493a8cb04143ecc2928dcecba3227a61dc0cd354703dfbb898aec4a0ac597c591aa7a3eaac451ae0e60438640f2438b910c8092f145ff82f2c13171a45ac4255f965205d25d9417e7c3cde6abde548148d85ced59a63be31f3f12df0dedb742e3f30bc749e58cdc6255ada5b2f52faa8722d191f5d345655cd78c37478ba472e1ee19ceb3a7b56b0d7e60d35d518705b16a3fc06fc08a3dbac1593a0220f5396177aa39c3b8cf0993123a8acef5c3d9ca066aad2ffd6f461d47215a1f02778854c453cfd10bea05c7318bc41448d5b0be11e9d3050f942207cca4884eb2f38772bb8c42490df9ec9c717adebaddc13d7da822fc3311983902b0825beb71008e42b7f4b7bb376f34b160fe089f215047a6d96e532036b56288cb59ec2439a3fba457780e3e83e5aefb7513be87c99ea2b3c74178b22404a628de7a258ccfabd65b91d46242e255de97a4ed714b055f9b9a97063777d4f7defaec51b07d5e45d3591808442bb2268db138ff5064d5de5ab92727c186a8f5db3a02f68a2c05e9273d598b054911bfe419f74265e93f07a57f4b88f176444bf44870270bf1be51ffbad7be5d26ce4dab2bd82972f54b94b25e696cd3b8e2d8edb7117e613deb944a50689f10b1c5b31500aa1aaa2d3d9532c2475eae504b390fb478cc8d4517b7857f8e3612b09202f93361cfb55d566e99dbb9ea6164ba356203d121e079009aae2380d5c772005a104a3407c8531430bd8c6f16f85c33f11d13318771ac2bfa961b5cb1803bafe5b3789a8accbfc2560b67cf83011c75b0d2c3e5dc04e36a5c3511349c75b9dd21c4520f98c68b3ade8b02b743f3bcaa7c9bd837f353e75fccb554a0f03f21f25f6679795f1c63678b867e413105105061a982d18fc80f8c95ab7e5060c35aeba01ceb65b1cecb9d3f6ebb4041e6bc4d6c3af0b9cae154ddf6b6490d18aa8683589110dc1cd1985653e86a4ba95ee47c8591e275c72389fb2f10496b4a4d8088bcdd3fe66766dbf81815b8a66aac6e3f9818c2f20d149f0504d5857cc7441509f5fcd81e7a03077b4b97577a87a0344f182328b4cd4624437ff5008e6d9329f140ea84da2e96682b0f9e36b36cc367ede9b31bdd61f60dc86fc3633baf06673fe11723e338098e94defe159de1a319a88f3081f10f7d164f17c81201e49c002f1b857a56f06e4c2a3ec0a430f32e87227c02fcd521ab9df4509916b2d1195b1744fe36379f0f52d8b6fbb766f814b8c7b2e0598d160c4cd5fd4091a2db0a84545f0ca5fec66e6829403e06972147c109a4be63357edd473f509b69a8cc2bd5300f52e1f4305baac2c12be639276965be6f9f61f092583228c925721ce08996423f29bce2d50a8670000fd34fb99d35e7dd8d8d25d52b4794b753ea815c1c5820f29b681bc072ecac42a2a1b8a57b309201b20f694eef5aa325140f7c9c53ac5c638285a57a62beeb6a940864d875178e81454a4c39febf17bd742d59597c46b201a874ce3357907529dd7be6d4110b29e90b3a3aa778671cb499d418dea68c8c6a01bb5cbb0688b27049d909ae73e83bf98a6d1ba9caaa691458ebb801de100a26e1de1db95235f2f5220b6b19c64ecd043c48820309ed752399c6af4889a7ba8cde1b20b3910de738f0940dcbf72a5c11c7f556ca5d13999c7b3ab3fba4cd273218d87de11e8b7d89dfef642e89bfb322ed89dd59e6edfcc9dfe919fb9a4a6586a3270bdd7749e60db66008418f2c891f427d04d0f6f19e81384e94a90fdb15aafa7bbd4bbe3d0b97f33034d452546dc190db665a3171437351d0c657639527b5bc133fa1ce1ce3a7f192c479654309f020a63321198c70d46152400b55e3df5bd6f42ae3de1e121ba127c16403720ae00a7810505bd0c20088c5f002e03cd4dd6e4402423bf0da6c49a4d15598cae65c1f1c5b48f8e88aa3a1c728b566831b2b43388f97942e52f77e72cd6201c57ac4d6de9360f067e4b14cbe8099f4b85b254a9d7d8d534c3820d54cb80fd05f2e1910fe4066843bbdd136e8572650dbacc896185c255dd8ce8dbffbe4b7c0c5d55e73c997863c357c9932aa9931e028af97c5422bbd6c94dcca73e5ab0ff62f0cd7f5132ce2195afbb3959f229b2be1f9ba8fac3ba9bc04018639ccde0ee91614f95946c89b3d9e414c9411535b0362484cebacfb4e096e03a2ef62117ad52d821b185b9954c3f55517dc292e307cc995c862bf42318b922225216d39601f06456c16c3268fef828e76dd7b29c2bc65aa847daaba69519d0f89495e2746eaf9e2fa525314f79ece0045d6b32ee6ee7e90428df9b0e05f05213a14e95ab525b0abbf1bd818b58170c8f3d99dec43db92051ffa3dbf5ce44659ee4beb1419af24128014845ab737b52ae56d8416a291763b666484d3561c7a5743a0a0f59a8fd2fe3486f52cd36b179bac2c15925834f5fc939a3f1903463984eec490af812ad5e55467e49eabfe959b45ce6a87e8817f7e88bf7ebc7da59f266a070447542b9c325458f7b7a50a1e747becd0898e4172f9125bae641c8f0dbfedde824afa3f374f738e087e09374104b973a840b00b6973f6b7b467787c92deea2ddd2f0a95bcf289339c9cc1605799d508ab36476e4f304d71f1d436f4c9098bcbf89cbc773fb47bd2864f41c45818290e2baeaa8f150a4a8004d2b68a39a2e39b49dd10a2e7371c01a6dc434189a35c9bf7f3ca481164443c5f73e2025f386376f3dcf6a4ca9a9b9451926a0203c9b05be6d58b1d4fa7903948c7ad05b52ae7d8bed5539360a2c64fc14542fda9b088441845de5348849fea00c2642918588d813756472276a5c974bc280aad5b88e654ef5922a79ec1550adf89242cd1840fef0c5341fa1a01f7d47752b6cb53a8391ce25596e69365b13d2e93663e1d790498c9836e81fc575f686f2d3f46597060e4a013ec79b9f7c853ecce5993e98df105c1fc51e1c2e83eadac9cd05d9a84501717adcb714b927f61c8fa551d2d1dd2c92f29dcbec1710952fcdf203dc5a22e61725e0864b67becc800f79eff2166712ae665c6ee01b90c781dfdd2a879afa73f2de212f132c7dd830b3a324d8f950c014ddab5f513ef1b5c467e7eb02f50bf890f0eab380297e5503dd7da6657be7a05f660e0aac28306186a7f69a1d5d105b84ffa61ad165a0ea59ec403c9656273930c4af4abf65543fd0edb2bbc75eccb79cd419e038adeb218264faca500d90c7c20532285d397667eaa9235917880b606072ec34c0f7cf750a1a51a8bf434112f20c45ab8e3298aecc9f8b0b15801996d5e920b5bb8abb7faeca189bf2895c8d903199b5d8b4c51822733e6c6dc3e4d7d9bb93d5954357680158ca077bba248aa1455f58f28003d8eb7029735a65f8a1c7ac7547c78ab34ec9ac7024004a8aa8ffdec87f83da14f296dd0f3c2b950ead5da6264bcb8f2ad03704876a01c797f698aa216ade644a8173bb89dec882013ab0432d62443b1a753b86ca4e624f5b5a9ad14083ed0ae12a91d2d7ba9c994500664718444519a99580981e6481e0a4234cf807f855df2c8b4b8b9cf6d6d999f2a4923029cc968836a1972594124a265c8551c0abccb5aa9440d20339d6d00056888c41b7ecd1bcf8872bdb199a6c3a57965443371810c020fc090554341846d6fa5adc694815358b5416d1c9b6020069ad838400a9f10bdf1606b8a158e73f75ffd1db2cdd0966bcec51d6c03db7f5915e2751e820e06243597fbab2142fe8b26a01c0b34ddc2eb2ba661b1b3ed0584631e1d14d197e6d67993fe0418db573f5096276dfe2c5960af90d96a11680e26c92b5de7de3c6bd3a08aa6044bebebc6f4ec4478cc79608d888f4f7d41660ba65e96714c71acccd554d5e57b48d3a0a3469dcbc7b41e946197050308b0b0fb242936fab5b9574a8821e64afb76f6eb9e533d83d71ba38b15c6e9741deeeef261e493bc58c9695f51f43b2529c16560fb97787dd3b9a0f9f99e5423a8b6138e005da611bb0f40883bcee0ec54f20b9f0642fabea7fb3d9db2e8110f704c927182bc333209100aae2cb064416533addb35be76f5fe73057257d4876f22dda6b971106318a1b0b3ba25d7f4f439a333e3c57e5aeedc24fa4edbeef1a8ae0b8bdc78cec72cf84e51aa8cb158f9060881a740102efb31e7ca2e24d23ef3692d9c733d0e070df407b92d7a0722d1bccfa933b647451138aba66693ab5a197002c6fbbdc1d4b57f171bdb943c02f00d2f953b9bdfb5a41404774b4ecc17e3d3ca7715237bd02e0f085877311e5c1cd81b4a001111c98508c7fb0830c7d6c2f086e2e7ec7ba89e5371ad12ad31878bcc18c3fda65869ff4b026ddca14e8797672bb5fcd88260c7b41f3084fdc56375d7336b7802d7fae569a3e5e410e0414002000232c28f4701b25164379a66b4b182145177b28806b87f60708c88037a6b14659638c6523a5f8d12e67fec9c3d6d20d3ff73ba60a17b13d82cf68e76091d08412dad205d6087150de4e57ad7377370001bf3d142110d786b0b8f7650a7c5679df20831fbf1667c63b6c5e833bcaf863af162d32b21a2456023e15447c0a3960b024850330333333333333333333a3bf52bf8dffff636c516eb2ef3620640612209599999939e517c205fcf6635bd399894f67263e1d7409a20a480a0f0a6ee78929446b848f6367087ea78b5dc48f87d6e2118267f9d6728f479a24c8088293c7e766d5f10308be07d79c3972df03193f70634a9aebc6e5ccc7df95c9f0811f621d1b19d647c8e8816b7393ee038dccdba391113278e026d10c314df64d9b4645c8d8812373f5e993a64bd963f0042143075e46da8f2bb45848390608193970d2a6ab2398e4a011627690818314c8b881a3a216dd93bc8a830c1b7861829cc7642ef21fd940a741460ddc1ef8206bd7f4464ab73268e0e6987dc37fec6d697f170b0083d8c0808c1978a92eedeab591210327e639b1ff49460c9c0ef729667d985c9001032f0fc587363769564b72f05ee174e5d1a87a1ef8a654395ce147b21e85889df46204619cc08b1a374e184fd25ae1e78890c73ef848791459133858e1bd4628190bf7d1a3b60a27e56041ad625b44cbd8d852859bdec736e695c7a749852f217fe72f95ae4817e70b2f6a34133850516edbf461f26c6c31c729bc54e12996744b0831c2e430859fb9657e9046628c3162636b4be14f46d230f3691b5b67040e52b8b94cbaafc27d3ba78b13dcf8826a081ca370720eff23f59ce4dde31285b7398f3bddc7594a33571d3842e1c84a89bf774baf4b77e000851f2e4acac3f6984f60a12d669994493a7078c2efcca8511aa25530b7135e857091826434ed9c87e1e084572d6335639b834886d7c0b109577cb03977e5520d1c9a702666b35e8071e3040ce84c782d3e417b2c79606fdf7260823c1e747f9ffb28fc20360c3157c786210ca0fa828b131cc7253ceb4dad7f2ffb92c97258c249f2b17c2ae70ecb6922382ae1441f240ba721d8050725bcd03eaa1ecf8519101c93f046fb44642494849b3da8a7f81ec81109bfe7526bca1f3de14adb8203127e8ff7c5f1083fc9a61f7c5f49b86fbd1881026c182fbef0d3c505b8f0e286039cc0e1087f24d56b75e3c398336d84b39e3ea43f4f3ff2f459fb030723fcd8e43f3dbe1f5d6c1f8bf0c735659d613c42844611fe47ea911f8944d9bf89f02ee688e9246f0eb5220722fcf179ca10f2721cc2f174e6e3d6b4ebb18673c06108a73624958bf263935829849fc5e76c345a0e42f89b255aacb05aed23eb3806518270a22fd27c70a505bae04b7004c295ce83bff1b9319b1f5e8401082f04ebe81ad27f70ce63f7776ced07af5f7b90915d8dc72901a9b1b71fe0e883e7294597f470f0c13fd3cedc834b759939f6e08f3475c9657661e0d08373dd7d1624f23005a9e4c119f9b3183c630e3cb8315da650f37f954fd93bb839e2fc424e559b6348f1c061076f6343fb24fb20988497c051076f425a0e3d68b5d61c2470d0c1fb414879dcb93e82a90f8e39f895ba327ef345f10ccbc1e9c15606b909e3e087b09db279f44846ab1a6068a16ae080836f7942b3533a25e6ce1b7c8f90b3a71ca6b5730f37b83efae0d182ab86a70dbe8fbbf2dd0fc2fb829505071e9016003470b0c1eb711e661e5a1e6bbb8860a8805400f3c0b1065f354d5d84ceac0d1c6a78fc3d8ef01f4896230d4e1e664d99e12d1a98249a9369d09833303eb08bbe31461e5938cce0c677c7ab8f63488f7519bc9447217b1c1123e5b78d830c5e9e8d59c3c7233b8df018d008f5f5a907036e90e2108317176a837c5ab5a86c1738c2707c49df60f0c3b5e7f06969f39d66a5058e2ff861b9cc3d69f644eaadc0e10537e7ce3153a70fea1976c169f53c5723f9fba3e60b1c5c7042ade74d3e95c7d7291c5b705d7238edf2aa5cdf6bc11fd8df87c6a4b1297064c1574fa97cb482646ad7a0c081052ffb20fc9002c7151c2f916816da59426bace06b64b5ca8a1fa53c9a3c81a30a8efa48a366f51c0838a8e0f78fb7d56436ce079a0c704cc1574f1d9baaf375871f2d05673284d8f6bfd23e9089c0110567637765c859127040c1891ef9678b9a1e5c7abc170f4601c713dc8ee9bf7b2d6c4d8c392a38e90587137cffa1869a29dfc6568dc7839065c18107d0a04183c60a0c590078c0d104370f7d3cec089130c1b7ac21e7144e51702cc1a96c0f3e48a79ae6b70664c180a24a058712fcac937c5935b38516364c36802309fcd88731b1add563090712bc3cf0358d50977ce8e12d701cc1ebf4242169d57ef4af11504faf96cf302b492da9388ae0a8f8a6c550411b5b6b1be063303888e0f9f4403d5aeeecc16d6c6c710c41f9d598027008c193cb79e439698a6121dbd8521a6b068e20b8612c6ae40cc966d2a0d15ce000827767397a1ce1caaa35c6f10337591ea5aa5ff651f9581b5b5f70d1010674a1c506bee0e20460e0f08117a2b9e6b160d3a0a1048e1eb8e2e30ef36c612acce781db923a85109e1df8a9e436e72813967ea303a77cc54aeccf81933a84d9ec74c1819bc6f2860a5ae9432a37f0bee27f368f2636f07ad0a38a32c9fd34a5066ecae639dcde57a3a934f0a3a79c471ad2879d6370064e5c46899210b6328f93815b21657a33d23f248b811355b307d263b1c8546d4150e0051747035d5c200b06148103065ee561241f85be0fb182478b1b1c786ca1850d060821c62b8ac623862bce297d14669e2b37b42018a856b839524f76448a1f664b0c56f81721117c26de6359a87c1063154e88a5268979fca92c07093154e1ffe0529aecc195cdc9a9f03b468ccb3e4a7f31a6a8f03d798538cf1872cc6711629cc29b3cb4caeda9c3df078f2186293c0b93bfa42ce4f1307c4ae1e74c21ef9eedf615b6b1f55eac0d300804706390c21fd697c71c62875f1e1863146e4d96f071beec093144e19be698e9935078eb833ea930a13ae7b1a0f072d5e577c96bd7aff984a3f11b346795c852315e50208627fc3cb0dcdd9fff52e5f71181189d70aaa2fa7883d53138e1888795b8c82ed7a6a141430b0cace04c6013ce660d898d31347a9aad6b1043136e18911f6b8e983d48f03c608b1899f0d24a74b3083d88299f8dfd189870436cce937531e754951897f0376cb667e754ef6a896189f3e87325ab347725fc51f644f164ae6673c6a0c4b59d9132ae2d53d5d5af2995ec7b45a23a2f624cc2f791dc8d46388b8b1649f8aae933f4a74a24fcac31fa7388f41f230d0947b2bee6b753528bf908376f082934e4ec957fa023fcd4633b7b8fd6565989d108a7ee4355cd765d8f633118e1e40dc1734f5d8fec47c5588427777945f8e3fe8148fa4ff4716f12e146a648497945849b7b9083f838a887b0188670b53f65c6a679fa486b0e6214c2ed3489ec32de21a686106e1ef4209c8ae5b0b941b8f92de7ce13b425b54c338821882e6d0cc1626b38107eb220399b950f08cf5be5ffd268d6543ffee04d141953d7c89ecef683132bf75862979c440bfbe0af0499c80ae7c9e4e318c4e0839ba3c77bb81ef7e0786b8a394df841859cd783df115eb2d4da0fd35ff2e045c66facf7306ae9463cb8e152688ef97d1ce1e371072ffb072edd954db33d3b7817b5b3adfa78d0e38dce0531eae0a43cb692b246ef0531e8e00f636a788da231738ee6e0884f34b7f4919c5f1e72702c5cfa78a75849138b835766353eb67049248f8683a3f94f0383186f70e4cc37b95dca82186ef03c2acd6986d3d0d5a30d8ec498611a42a37bb2a420061bfcf1ca560861977f58a68dadb303c45883f7ade111cd7c52ac8e1962a8c1510bda11f30fd2c7fe34f8752b9a278fba6da28f062f6b5676985e4d21f967b036a65c3f0ee59bc15b1f4aa827eb94c43f6570ee42fce822d705ff1c3278d162920937daa539670ccea9cf6db8bab6d9470cfe45d0f4c17fa6bbec230c6e1ee4d82ed2ebe38f1e60f036d2a7c8101f4f92cb8d3270328f448435915b8bb0888113438f3efd52f63a9b6001033fa7b50d3df9c7dda31faff03c936695abd015fe8a6a8fb2438c98529a6020805638bda15e63975ff08904c00a535a4beb34acce4db37e74db121a32db390f2d6cd4382cd0028c06e37471811b278c08086015ce5f58c952cb51856fed438959ac7e62e5a4c2d9f6f0f158da0779fd820a3f85ad8b58296415af9cc2b799bb1fd3f023c921a6702ba4187da8757e9ed3a5f0eedf63ec339914de6c5d964d5e3956b4a370b4b37556736f715f14fe49f2e879a8d150b81d39061f595a41e10f6e738f731e8934577ec2111f75121f8f2d86f8e109e77a5b32870976c2b94b3f8ccbd82ec1454eb8197a98247767a42b71137ec4b8ea51901fcd216ac2b34a6a95aebf4c3892a3a4d58f0f34bec3849763ecfad28f44d573092787c817965c43e58e25fc61c46829e7a41934a612bebbff4545c775968c12c56944360937450c79fc9d25322c25093f8cc4aef47d24bc983179e5411e7c6407127e92c9eebb6d37993cc29388417da8227eb6239c9cc1fe47f73ed0781be1add824fb71d88f6e6584172d327ace70116ec8e13187ecd10704a00837fa507aa816325c784f229cb48fb12c5410e1d5d90fab7a3687707a23e7eb8dc810be4d8a957c985de522a4106e55f2ece38308219c29eba1cb85a4bf24198493e6830e8b1e86f18e20fc0e2b39c57c04c2d7f0d321cdcaa7cb00c2eb2ca129331bfb92fd07b75342f8a7b3fde0d468e51f8b364926dc873f250fb6c456e6833f98ccd46112eb0729efc18d4bcb3fa137e4b2560fbeca66da853063f3c983132115ed7b90e987321ebcd0e67d16be6617dfc1e998d17bd03d883539b58393529692854cebe0a50fbea47ad6c7792c1dfcc8f441f8a8ca39b82e3596dc559483bf1eac2cf6944dfa5c1cfc488bb1ba520e0ebe868a72519fc27c907b831ff2978f524cb307ebb9c1db58956c6abbbf52d7063f68ca615ea22a6b3a36389a8739848e9bf08ab1353892de7d3c0e57d192626af0627acaed69b434f8e38b593ea4081b3d6668f02a95e4cc57ae31fd67f0a67dbe724a48f9376670d3754930c9de25923278339a244cb21e454a17199ccc6ceae30bbd726b8dc11f45c6a09e43478e6189c18fd8a33673efdc7109833f5315d721f64a4883c18ba9b3f3fce02fb825e3834e75717dad171c4b96f17717624c77c1bbe8e9b242ca05bff27c7a892509600b6e4e3953f34948b19d09400bd56dbd9c57a847324f5799bccc4d2b02c8823fa18752c9c7c3141dc358f0c36b30956895248571022eb8888071000621802bb81ac32d6e3a6abbf3b0821333f3c0dcb30f3573a60ade740f93c45b4d05bfbe07f9d3b73a05efa2fa5f3c4596cba7143c0fe703ed61555170d4eb2452c84849d91a55e78b1570600100288400a0e087a514bdffa6436de5094e88a924dda7fffa459ce048cc6069520ab339a69be07ff060d9471d62ac0d33c14b1783fd78c74b70d25bfa6ca7d049e35582d3e3cabf8d2d14948075110248829787b1071e2a6b4ead3e90e06b9f99c64efea391f808be4dd43cf89ed708ae9a471e48fa615df8b408fe306d2d48c5985131480437a34ff27c1e5585b00dc18b357f89151af3a847d9d84241096a3c395813480b401f04200427a57f72c8e358c9e307c1c9833cfa98d2493b8f870182b33e13c6ff26e355f303e72f48688b9bbc21293ef0eb342bcf8fef81b7f5e1da57a23158080fbcf1f1f1f578d856a1911d38a1c652a7b15807cee590e347129b29979b032fa5cd9b33638a034ff3fbfae44a16c907dec04b1f76f4896c1fbaff459b420036f02247caee3e8aef5c750d5c49a925bd7da1c7bdd2c04f29c9e7d1e5f29852390327ffc55ce69195c7bfc9c00b9e3ed7f43831f0630c539962c347a58de0716a3cb6d0c286492f0400833d47f8285c1e5a5ee1e4f1e47513b5719bda15fecf49f9f7385274865be1654de96d36b1494392154efaf1484e32a5cf53de2afc9cabc73f4c935785efa1828f2fd548b43f154ef6d8f60d793c96743e50e19a87fb18ebff711639856f7d2979d77f9030b229fc41884b0fc36350d9be14de69b5786c7ac91f6248e14dd894b47e22212e19851bf2859c9456886f5114aed9fc98c5ce42e16d488996db6653f80f0ab76b4cec22dd2e3aff0937e6de1cef616924329e702425471ec73cb25349e984e7b73e2226d9197d104e78171b3252ca924df817b2d2fc4cd27c6a6bc2489dbf33c42533e15ab498fa4b0be21962c2999fbf10cd1e49085fc28faf14c57b94dd23f32ce176956ff6309570dd3dbd67e898c7121e257c93109fee3cd6df9f842b977e10bcbe8724fc7ca63e1ea9252312d9fc4584d9e4cf16594706241c4d2f6ed3f661e7173546d08516253023b871b8287b84df79e42d69eb4759e5be51630b72c200a34609b63841d11a41175af4cb7084a361d2e3458dc709c39c7fa2022dbe8edcb8800ab4f8c3818c46b8d6a13eea2ec3dc256d6c25256430c239cb219be7f06163cb2e123216e18f452a794899c743cbb38dadb32c38f0801a8a08198a70632799aab1ce9d63b5d189f02dc20f7d20a3492c5612908108a7d3c4d083143fd2ccbf8dad0d64c100ee43f8293dcc83cfa3fb1fe6db104e590a69b1e683cb63554621bc6895349845dac9679b10fe784542889cda769563021983f022f2674f361f2d6e700009204310454303e1e7c8f031b74a559e2c20bc4e59ce4731ff7ff0a6b5a77efe6386f77e7082664edb963b4590be0faefd054919b30f3eb8e19249beebbb4f17b30737a7654b85cc5d51357af0d29aab6466f9bb0ec98393925b7d184265fb94e0c19f97b8e853ef1dbcc8a32413da7bf031cd76f02267f5d6e7b40e9e7a67fa54a9a27970d2c149f9f3fdd053cae832e7e059a5f21c234239f81dd38f3a44aadf6717072f325d089e1a1c9cb58df9473efafca3cadee0b57c8f23edcd47997783b7927c181562a57a4f1b9c1c6d7c3cf00c3965910daef4b0a2074f392eb306ff926bca3771d143576af033ff65e989982ddd0739368a64a4c1c9f21f7fd63ece16520164a0c1c93d214506b9c8dae39cc149a98e791cb6524ae6318317cac7e390f3b95bb81f6570536e9ff99cd1f25b850cde66cdf0d3e162882a8fc14be6e3f17c9c6c7e4bc5e084c8a3ba6c32f28336c3e08498ecbc7ed083891bc1e09bc488325bde173c19914db16925fc6a5e7035a60f2c0fa4479343aa0b5e68856a9b903dae262e78d9a3398f738ea69932356e788145c6169ccae33c793cb4e88dd96bc14b992b260b2125d6a85416021959f0b35df609e9099d3f050432b0e0ab6cd096e4e12d3694710522bbe6946247f8898d2daa13a00d30880d84810c2ba08c2a3cca979344ef6c218b32a8e087ba0f355d4ef96205617471821a678b2fb8d0028c1a5bdc3828f0a20b2fba401953f047e2ef1b2d861e0d3e300232a4e0b77f2e51f7e077799c283841625a88f68182bf926ac3fdf82c744a798213cd07a16743e441e7e1047fd8c33c4c162ca73ccca18c2638dae3184952c41e5b763298e09cf6a035a63f1b5b4c43c612fc41c43c1ea787b86c8478073294e0ddf738ea627617601cc84882a6beb9e3a20519487052b74a96689a2378329acb635af9b8b86d6cc930823316f2c03b4c2c8213e5ea3be5a898208308016b309b8fd2a306be4f674852e663af99065ec9c576fff561867706defff8785c1365b37246065e1e0f5e7e183613035f2447f518c42ef766060cfcab1ebaaf70b6a7674254fb817c882b1c4f4125bb3c748f7b90563897473f4c39cb6c9a346185db79d8ab1524e63dd8ab705a635544a3075655abc2cbe0a366a92977ffa9704ef24056c3f8c7ee282adcd618bd534c1ea7f0259da53cd8209b37aba6f032ff7a1e4bc6aa8b6a29fcacc13a260dfd9b9992c21f479e9cfa7e1c21131c859f7d1c5af5e289c2abf6cc5e2f67bd7528dc8a8bb1c7bcc7a15603852f52d616b426dcf89ff062c56c518f9dc71fe2097ff3206cf4c822bbc75627fc2dd7fca3d59a07c089d6a4b24b6acf6fc2cd0c96da62fbd0841f2c5ec3c4f9f5e02d99f092ff202d8698f623b531e1a7da9b85b2774b8f2fe126cf29f8e087ad25bc98563bba27f74044ad84d777b691dffd3b5639004ab8e9e3b3c8ea3e08b1fe24fcd165fc5f4cddfe9a2309a772660cd1ebc72f93130937bce572befc03127ec83f88aaca9df3fa783cc2c91033e5f1a05b423ac611fea86b7dca337d8f479b4610fbbbc7a3ed9c6184b77962e69cc35aac345984a319ec3626250fd2268af0ffe3334c089244382ae97be4c3ac929683082fb3bf8714fb1fc9e7106efaa9ce3cfa1ea70bb621bcf3a4c92d7f47fbaa0be19d8cafc6f483cce39b09e18a858a792b5bfc0479107e44fbceaadd83ce694138271272e81093845007c2efa18fc2667df0d99301849b72c8101fd6ea6fd33f78c1a422a6fa20a507a71fbc103284bf7c4e31ceec839f075152247e201f7cf9614a452b3f4b37eec195d37c11838a7a702cc66497589e265398076742f2eca13b25edfff0e0e6c18fc223e53c52c9dc1d7cab904b635ede47edd9c18b6f1fa4fb61570737c2c769b97bb53e6274f0224afa60a28fbf6be6e0645a49e2a3eac8615272702a7fdd6fb771a82bcbbac427e170f4a872f2d78a06f086a26106e006bf72cc69260d15f3b40368837799926565a84bb4a82a18001b9c9e9041b23c5becbaacc189298fae320f3578e7e38a91c4a3c796471a7cededa154f09ae888a0c14b9595efbe538ec9de33f83dce10e5073dcc36213583ab311d3c69f88b96d000cae06af430644a6ff52164f06fc2c2d94fc6e06b3013b77c1d31b8290fe24b33e5cfe3f17884c18d6411c6c35fd4250f30389a72b2bb13959aeff1056fa687d1e1152ff811e5fe724ed754d574c14d163287cdf7e3ee70c14b9e23e5f1e61593ac5e172db8e263d236165d530cc9826b21a5cc63cbce232ec182f7e3107b24295c84f2d15770647bb4d1a11ab92f6d054736a465bb90ae823f0ccb2e992261f20fa6822be12e9b2b67aa973c053fb3656b0bfe43ed1c4be1db6c9fcbde63a3e067ad9210ddc9a2c540c149ab3aadfaf1c02cf80447cb56c2f80f23b8a64ef093ff207cce93aa43cb26783f3f50dfcae34f1961829fe97d2aead2a5ea12fc8dab1c238450095ea73c8ee6fe5d129c1f26cbc9273cb9e70e094e0cd15254538ee0cdadd6f83058b4481ac1df1c34560ac94e7bb222f8d353d987dd9ed3f92082d35d7d9d3547bfe00ec12d8f9dc716eec3f228044f25c5929f942b0f421504ff5444c2c9e714daa10100c1db7016ea3db96d1e4d5c18c00f9ceaf61fc67c317d3ec707beca667ff99052c7d9037f826769f549e156191e38bda6e2a37435e13fca0efcd7c81aca5ef2e07e101d789b1d39fba4f90c5f0e4c4bb93b67f4cf0d1c38d34136fd5f0815f1dfc0f3893d96ab9279919401d8c0e998ccc7b9938f1a7851eefa7f3ad6c796d0c0f798cd73f6e8f0bf9981b7f65d3f8ea9fcdf6c19f8a308c90062e0754a35f3f1c801c0c08d169e7cfc7914452df60a825458b5455f1ec0c2157eb6f790ba10bb7b4f2b3c33cfd9e39826ac70fb247dfb4f74159e56b8d274792e7c94aaf0c7f9d2d48a8fc322157ecd6cf4e50f3ee84b63810a55528945da6acabb38c0e21446834d9157b8448839fb44ad144e487d2e4dbe6a1e73b624c082144963bbc06214ae4c758f3632788859ba065888c24b1f29e5af74e6c394eb0d45912a192267ccd9d8aad5020b50f416587c62045878c2eda8289f70b5c8a3c9c63ad927b0e88489010b4e103965bfc46c6ca109b0d844185868a268d4c0221346e30421c002137e4dc766feb14ccae3125e8819621e2709675b371696f0c52b8f2b867545890a8b4ab8f279bc4135ab4b7c8205255ccfa62194c7e8410e9b04603109a7442ea98f64a347174bc2cd56ae592e620e7d2b169170d4ecb5cecd0724ca2199f70827d5d847844feaa39c61e1087fd0036be94c37c2cf308de623738f950c233c8d51e7513ef9abb98bf0267f748e756e23732e010b45f8a97fe89ed9f3ddb675018b44382115c2c4da0f1b5b551c30e78b0dd0a0f1e8e284a182f3052c10e1c96af8c1446bb294f6218ce1c9a2cda754808521bceb939096d63e5f6f21d2b2bfd498935a90302a8ca381c72928604108e726bccd864ee5213d42c062105e48e6b4e8d79b073d04e1e718491a7afc2ca604c2adc95929487ad78401e1fb0f3dbaa8f87ff0ce34fca0c7792cd37b3f78167ad05124aa4abbef83f7661262657b3ef896928758d94943f2f7e0899c54f058777eb61e3ccbf56e41734e1eb37970dbee356aaa6c554523c4f530a4f20ebe670c3db04c4172ce8e1d9c8aec19d2c7a98367f37fa92b74f0071192c875faf1e07eccc19f0df5e951f09490918323e9c783fe41b4345112077ff340a33eadfc5c0b076f2be70e957f9c57a28f3738dff711ea738c1b1ccbdc23311fc4b4c1b9b9f4d698cb917db0c19b9851eb2c8f47216fca1a1c1fa7d7983c839ac6450dcee51482c76ef1ce68498373ed9dc137fa487e2c68f0e325aa6c87ca19bc947012d2fe354d6f06af373c552e4f474d19dc3c8ada941072b8ee4106b752a898073fb4ada8198313da6452a79288c18dc89ed83912063f72b6452cf3516f8e80c189f083ab0ee1a3b4395ff0c2d945c8f8682f7852217bbe50d11643ba0bae5636690b413b0fd3cd052779a5f5586d6ed1ed2d3821e64d2e7e939ab6d68213dc6662d63e0b6eacf3501f7605f560c11ff964ab1ee641f2cab9829f65f38dc4369990ade05790891f8dd1b9625b05b7c355a464fa66f2a082231ba6636a264c3d0527a5987d2811535896a5e0d506ff415ca5cf1846c1ad19afb49ae3ea3f283876311bce37fbe47a8227290f2353d8c7bda44ef03588864d704246c904efed8357b2b1cec3602ec157e96e8db6397279a904b747561633e74ebf7d123c11979cc77122c11f8acf058d29634e161ec14dd1de525923385266533ef615c1cbe34cfef6dd11c10fd5fcd172ccb9c7a91b822396c731b312a2c86f42707ef4d17de4df9fce6241f0a3fde71a0d01821bad42bee81e5d7dd87ee0468d7868b128392a3e70d2a764ad193cfde21e38fd962ed335d279ca0392a805d79ee00e7c917591f7b174e06de474755e29f5872a077e4fda9c1d1f1c78999ad2c46c4f212537f0f3c69c5ff34bc8dddac0cb90145a34b78fecac819f428f3226695591200d9cb7b454ae5155f398819b9255b21cbc4a0fb5b145e6808e4ef89ea1dc6c72ac0ef73e6e78618e06ba205f6ca00a1d9cf033434a299aad7505061d9bf0cab77bec430d99993e5d902fc0a8d106461711401b41175ab0269cacec9b49f5dd9ecc8e4cf87f93c4be42c4e6dce32a011d98c073e893bfdf8b076fa0e3126e0c4bb36111d558c1165f7c410a011d96703552e51c6bdeb96264636b0537ce094c5009bfcc335f46f717e8a0c424fcf8c1f8a8bb7204f1f05b6971830323e882cc031d9220bbc2aa5fc798f3f56040160e98c0021a50011a34caa3c60a6e78c1c5e18223e1f9c46a3e19b73a1fa703127e284b6123743cc2b7137f79ff91fafddae108274c3ac5ce8acb7037c277970ce132683a18e154f8f82073943b16e1e68d69f5691f1d8a70a2d38f345df645b64f4722dc8c0951794b298f3aa50311be640f235ddf86f7d6790867338f242c8f47fdf3cea0c3107e66ac569bf437512c347414c2e90b9a21997f0c4d96a183109e5bb66baa8f6cadcb163a06e16579f264b944aa2f3a04e15469478dfa20d2bbc5c6569e1b5e84b181403831850a9624caec2ce77c8118b802a327d0010847424eeeda117a94796363ab86178fb21674fcc1b3b4ac29c7f4ced0e1072f5fa52cee6b51c98e3e385222b669baeb42071f9c921cb62115434c986d6c65c18107908e3d5c871ebc8f1e7c8ae84d0790068d3c78f29b520efeb10e3c78ddb26973cea91e1b3aeee0fa559dfa3846860e3b782159cb6485afcf9bb28e3a38162aab8f6492cf18b4b155e30b2ecc71c180156cd1c505ce08ce165aa0408b1b18a042071d7cd1cee51e41d231075fa3ad271f67700a1d72f05d3a5b45c44467ad90d0110727daab6863eb9cd00107c7873ea8de2cbec1510d5e176bf287dce30ca1c30dbe6f46f113fb3c61aa6c839f37c59e6cc1c20647b5677bd285d7e0e54bf1b1e3c7e1b45a3578e929ca0f62cf59bc9a063f0f34bf86e951ee71f6d0e0456b69c8e3fb18724b7906bf071f911a42aedc1b43207498c17fe9719e187e351a422a081d65703dcc36bc6ca71f772b840e3278663f0e5172cc3d4c510dc38ed03106cf66427d948bf6d14b1d62f024a22f5d24a4230c5e1e46bee8715afe199f071d6070b2b25448c6d495f3f82fc0c841c717c2d0e105b7a3ad63fafc47035914e8e882131682bf7fead6e8210a985507177c4b39ff67882629def0e23c6a8071b8d0228c1a37bec60d2fbe06e10d72bad08202070c2d5270ccd1020359f9e8d882ff69dd96c75f6bc197cd9dba376678c969169cd4357962b2346f12dad802e3d105b13a13410716fcb19567a42f9b902aaf200c2de4d07105cf7fbaaca387ff8f731ca041430d1d5670ae6a32575c92530db1434715bcca9432871f7c56f87850c1cfbd7943feacd9bba273e898829766ece65565e23d34248c30c85637a0430a8e6fd21ce6437becab151fa0230a6eca4a781ff738e7915b1472b6d8827051e36fa080eb6fa0e00cd001052ff37978bb4a2936453a9ee067b57f3bb9920df79519a2c309be4b4c412589848607812c1890c5033c0b0664d1802c18d0838e2678f5df9eaf2fbfe6f499e0b6975f4c51930ff2384bf0364358c7bca9a7c84af023848f1dfbb349f03c86f65c3d0e127ccfc3ecadf7ff181f47f04ca6325da8444d598de0c4ea1452140f69219f45f083a40b61c43df90491086ee50b9542bfb4cb6a43208fba6baa7c1021789fa145bebef2288a1404a763ee51c66c9dc74307084e321f64f3717794b6941f389add7f25f92be78ff9e090c713ad72aa66470f7c9bbfe429557cf48cf2c0dba8340966e30e9c0fa1722b830e1df8e314dfdede289aa5d2a061d5868e1c783d981cb2ed2b11a26fd58103efa5235aa53cea0a1d37f0de723ad1d075d8c08b9ecfb136d858694a470d9c90aad38f24c5b4102e1a785759dd225d5c2daa5930200b1a341005346828a2c0ba0e1d33f05b2698e6f70ab73efd698075c8c09b174b39c4349c74ae23066ee6c8137169d527783a60e08f63ea185afb7e85db294d76862b9ccd6fa132450f177d9dd10a7f3c0a96439d65440f7a4d2e66b0c275ab2c49eb3d36b6acbe20373cb00adf3f584d0cb5b1d273ac8419aaf025b3f99846aefcf51d61462abccd8354339729f58a3f03157e8e1ee5fcb3f94a5d730a27fdfcf8d3e7978c98628aa2518aa23183147eb758adfa7f925069c6289c3caea499f2f8643cda6d8419a2f0c4d3fcb007a9c43b653f98110a3f7bcb3d6a5bcc3a060abfc42a67c8c3f868326161c6279c091a628eae1fd8269d30c3135e12efacdc155e923f1598d109a7b2f5a8c948d983199c68346d44a948c583199b70abefb3ce2d6a0ad5787cc1c5e36668c2e951cab1a256fef1208f343332e1a88fa4d67c17240386a26006265c4b397adc16e52e4e8061ccb8843f4a69be7d46a3e45650c3ecc60c4bf8ed030f953dc8aaecaf8d2d2f1e5c097fe8d2296bce779a156650c2f31fc534953a6b63eb0b2fc200036f5815664cc2a9981252e5a07e1b6c2eb4205b189384af99c2d7f25869c59c2f5470380b3322416640e2689c04663ca26874608623fcf185cb83f01f676f473d30a3113318e19dd78c670e4b29aaddc28c45b8608622dcf08390ad6e1f8f3eccc6561717a041a30b2f12e1bc87d78acae3d2f6cbc616185f7871a301529881082f76a7149253d6c6623a9871085f24c51ef98fa7198670c644d37dfe1e0bc8820314c8a2060d6614c217cb9c3ed45656f2cd0c42b8bd31d9db3dce682fcf18841346bcebbaef5b43d0c656175e30116608a2720927ea51614620a834af98ee7651895a97d8fe26b1439e3003107e5dfd5fd2b0f161ff7ff07ea266cb1add835c793ff811fb72cae3f3f17cf77df053cfcaa64bd2e341fef0c10b9e329d56ccd9839799c7e361b4ec673df8e8c1b1ca434bc959b47ce8c983e369e224548f2a42fe81077fd2798718d51d7cb3cf21392cda46da0ece0f33fc53f378e81ed6c14f93d635876a8c907ad0c1efecb2217a62fa28f49883a715717ef946233a460eaebba4f4583fa1cc3671f0c7e93fa58d1e0ebe270d2113c5737fe70d7e90cca621a7c50dfe78642d04b510dc72a50dae241f57c874d8e07576da90b25a84c7acc1d7d4223fc851eda3a206ff2cf727f5b169f0d394b7cd0473d588a0c16f1f67b710cd3ec3233379741f7db0199c9c25aa215e633be532f8f39124f5584a06ff2c56fed174b4eb713b0637c47caa7dd1a28fb31583133cc5b8a4d986c10b2949d5f2ffd9f66070b4c2fb62c65667f80b5eeaba907f3b7d99e9055ffae6524586bb4975c10d3e2adbf61e48f69072c11189b616de913ae6b105d7828f7c70deb16ea2057f5652cc83c9ede3d764c1f91e674ee9535f112c78211d7a1cb36fd0b65cc14fcb9b7e2bb7b644ade0866069eedeadc15305b7bc454d62f2618fa482677990ec876e1e6a654ec1b38e9d225e2a54f448c171db1c6a62c3fbca1805c7abd5e2dbe4830f0205bff230254f36d1298f7c827fd992e4a10f3c2794cb2e694df0369a87185b66e1aa31611f7687a908932dc1bf9c2a9fdd1999234af05462878b3ef693182d5d3e538947b090e0675665cc8f23389631ca5d309fd7a88ce0585cf4a1bd4d564a11bcb5510d1a7d22f8f31ee23b1c82b36e97d7c71eba2d2304bf262df2a5faa07f942038214797bb20a799672038ee2999e71eab851e4b337ee0af4d889c3464c8cad10c1f38f7e38b19e1223d7072a8d75c8fc2e4d4290f1c55b5cc03bf16fb3b7bc60e3c1fab88a7dd26cbb70e3c9f8cd942983a0b0e3c80055a58000361ccc88173ef79a5366a78f5781cf8a53dff0dbcbabfb68f9d53b0946303bf8b2ea824efc402b260280e87c40181300882869c0be3130800182c240e0622a1682c4f767d07148003592820362c2c162426161418188505a250200c088502814020180a074281504014160e4bb5e603032aa4c10de1c855b8b926580d5be3ed2a3f4ef429b151ca449976672408728391edc5211e40d83d8a2d3a8e4e9d90a29c90f1921c1843e3dfe23b38a14ed27a94960d9b62a766be6d28e8aca873406b304db64ff6d95d6c6035541605cce0cab57a1f7f627fc225f5ab415b167fed0efde13dc362c54e12a9e09455542c52ff82000fbf5551e43f7b48100e8a29f94443eb5933c8bcd502df3450fe00c6da5b1f2107394fe3c2f7f7f4a83a63ec5992522c28ad0050f1eef0ff6933287b4778203d3a162d4bfd65504d0dace403757aea8890ffe8dcb358b57ead935a6f09a81245ba588289d9809408b913ad662865cdae37152466f08cfe6d2f7c982ad178c2ceddbb754e24087f90fab72e57667928a2f64a4beadf22c7267385da110f18b6809bda8c904c54939abd4e4eb2d5bf8dad71debf39487229f7a9d85b1f7f5be8445d26e6be4c695fa0fc6641f460988b88ab746c47d9480e2b0e1d0cd3c295102a0aeb7ea15f8cf13e0fdd78fd6548f2015ae643e87c6af238873dcb5f17a2012e00e2a329c43687970f3b181531decbc4ab29c6d169c757a31f0d10e6069f119cc5f688f77ddd3afe101962a26bfba9d6808e67186fbcacb89d6670e5a1ef68ef7bcb9cd0643f3aa173107e064d8eaa3630e6fd452cd62b2f000a22c748acac756a21cfbc5d6c0b3607e794810fb970507e7da5dcbf703084c69c72b3f0511dc3982c6aa589d871f26f1b2343d35f5bcfe0b08f1f837b985276eecacef7277f4a1800410f76b84e90271b5eca421e4ea0744eb052dc8ab14f165eafa5c611836a9c769a86110c6751ec114434bfac699c4eec811bc28272c963b8098b28730311bc725585234c202e8023d217223aaf364b19a8ee930ea4cb8d19ab3c355afff072a21c21395b76e460d312057561acabdf761c9ac29aafefb4a720b74b7f167ed0604a79926409ce90b23819e0b33f452a3223f0c3a7494018c1dda9e8c5d5dd0b691de1a6ab7208c99cf59dbd42f4e1a4dce76125a03a6741ebb010646b360cc171471f4e8603f62f3ed625573ec3c4e5602c358039ec0acf430ba1711e6e46205dc40969244c328e7b65ee4c1120bb86995c7adbfa46a7d8b1ab6a9bb04fa449a32335691022962ed6688b7ff1b912da6da93ee9eaef5bb1c26968c49c9f8d2d72fb2634c5813d03d21d4eac9c671186e490ebf057455b784e74d6efe9812d40a4fc8d79025c045c10909240a6a1b69c0dc8035a0243842f09795d6d234bc47edc0eba902be4901076669a73fe3595618142f2c085aaa21a54288ab2bd241a95b8127a549749f86146b624b5436891f2b89c3071673627a18d9217620d104c618ec03271a3f0c2fdff23fa661fd445059be985cb550882a2b0fd269f40e8a1984a23266f50ba3229f31a58e1145d466dcf5fc251fab8270b890f3994aa310dcaf4afb81586486796c8e37481dae0be6ce9b8e2f0f5c38ca767d7e2aa15ffb551de31dbcb89d85d74113c4d116dda0e5b73f8e91e19fbd71d439f3f548f34dc5ccabcb93089db9c3c22e05238dcfcbc8a973305f3a43f52629201b2dfe4b524ea952e17d30b8fd065e7239212760449d5b17207048a451f56c88275a8ec93500d034a63c01a0a6f7d3777d88921327764ca5f24adbeab322dfee9d35ab83010aa06834032a109e953274e0c243b3a0f00bad58794f96e8493a18ecc28f19609005e81b12ef7fa05d24d17f24644490e9c675111bb36064203122ea9a2b84053258d0f569638934ca51dd3b408d6abf24895317fe31f4abbe5bd5b46c152a5811afb88b4b50bdc33286d829c3e7c49fc620c2b5e58068d491fef9313352632b3c4f2a2e249220fe7105b3222e54411515614b39868c15195c1c844c18b9d25b09a304296601ee8e894edb721ccb6d2993b2a5d24879585d295d3fbc5c817c6eea74e392bd850590361cce19d00f2d01e26dbe628c33e3e3d82bb8f098ca26cef804465c9ffc6ef1f75b2c6cc7e3d1462c88baa454234b23fae589bcc6b6ef086760bff8b51970a5206552f20e20110ca629e0eaa63d8fb28167b33525a56b80b1dbae97c36c5f9f81e673bb47673d9c5802cadfc2b3da05ca6c915752c1e30f01e5be3de1828c29877488a673411c58073a381028b4eef14c958546fc2c20135109425db636817f12e3bd2d3c26946982534cacc5130787e6da52b7f7f4276c7d906d187d84168e98fc59986b3d466ef3fc1cf92429a18524ba55f130c2ad4cf69257a6d8c59979f8d384262a9b4d0093907e2bac8a1a8059a49e2b6f2ddc7094a77c4269fdb605138dbba51a29d20a561a6f8e9c5af6b46223e3cc691266e0dfc9ae6712a3bfbca36a0177b100ce009a74507869026927462f23829fc8194d466e770ad0177f9f0de087b538eea02fc6d3bfedf523430d5126f865a0580d59f2e5610cf2da5f19f2fe874f6f97b146b39d840489d304b3476fbfda43da24d428404b7c4634931a46a6aaa5c86062988a101cd00c1462108ac6a18575d3496956e521de2a31a83938b2985b92003344cf8ae26187f8713d7d12d890b787605074e3e021a04ebb5811ab0b59172324b815f2399231eae69b63d5d917241fdf600ce1b0a380653c795981fe75d810e6fc3a1f2324357a263acf063d82e3d049047bb95d16278a97de275b861243480339f1892de4ec6f938a4e9f80ee13bb30b89f1dc037a19c273e2f51f5e9143d7362501c9259d9af76fd0527b8fedecd82a36252af2412f628dacc81276581306639dea68f4152865b29938c0e8c86b24cc5aa7134266c88a7dab9f484bced5d2c9af41bddc44e8841d8935f9323c993048793c13a6c7d1fe17e22c0254ee916e60ee79101d591ee3ef30ccf62d753703b2ed78b8808e9b8fe7e552c5300bff2d332e25682d8d2131b7249d400fd018c8f7097d236ff8859158d24b557beb24a58612f7017f0a398abe7e0b8ef6a3d8e087015c818834432954c27edd6901b15a417d56ea3175c7b7922593aebbea9445d0b3c39ce147ce910058cd8cc7fcbda71a82241e7d06c24d5ca76151661ec7efc2170ae107c12bde1889ad211881521027c1452d6361c78021f93b5bb38a02ac990070eaa7225b21f88d19be289c3c92c759dc5243b913eb1678612fe358462b2a4135fb6b1b532ef330a88c3f0b1b18c0bd6fc892d540c4fc250ed73d066245397f94e8a22f30b3aa83cccfaaca5019d4a44ab6312d081ab85f8361c38e2c4ac893ce34d7fe1e5e941b1a131d6ef404d454df304585a162a1e08d0a777d497bde1ae83a43dd4157a177e83e432bfe2703bcbb7a20b522b227a18b882a55ea79a7aa677abdbabb4244b5c2686dd793aa3e0a65047d41f91cb4a20cee4062a3a259eae98c8b0a859aa1e0ded44503465b08556adc7ae73ae43a5bdd91ae5cbddafeaf3ebcbdba1eaf4ece0e62df4d37d441d3d7d639b5322c5413d0f7b4c2c13a19cc5cdb1613ad23f5444ff6d4369dc25c455569aae64612f58c951df786b1a644978b65dcd611c681ba9e88491467e395b5abde55212ae3e9e44d53164c0bd3b573633dc33a269f47f53035e03aa0d40a3c51e53cafc24328cec8456161256aaba5f8fdd0c5630f5cbea38db200b8977ccb32b481f6e2d4a924cae9a3629872d1f9272e2bae55e0a754ac376337693e7e33517e59cf316e7fb58ac8e5b3dc7ca7f52c4b62fa7be8c1e095b33ec41de3c5f17cfc175e649eabf7a719470dede5535848ec16a789019639956f667c1298cbd16ee7d8df64ea5904d3e9052ee2d12088308fe6e1630c0a785d4f1edcb46525a23209f4e4939cbb7fee4d22c9a764844ba2266c876c41cc8aa8dc3228e8708015506dc3e581d50f480db4036482bd0599b85ac10f1e402298a70092d0c65c7e8a10dcc146dc0486032e415a05208cb7e21630047805d602680611042dd501b121f07b7ac2d104e007240a6683f31f7019af117b9800a10f6fc4b402f481f7edb39a406dc3af7af309b4d8cce91c029f14248a6196410aa0c4698ad2e4846f12b6a36b74fb24f2a2dcbc0fc1b999b4f8d473c8110953187d90f8e6bbed8e753618198e5c980c999ae3057c3d1f43085267b6ca942ea87333ec96893adbda64b221cf6613663301a31818b5c2c1a28de4e9cc4a444db15e96f4a1dda86f6a52539b1b3621d93863a3366f866db4630e05da70b271d146946ea631c8103a7677e3b71ca57052da00cbcd3b73e69e334b89f60e24669b312230adbc938df568338d28c35b09c9290f0742377fe42c5d8e359c84d8ccdaaf997bf8d48b44166a6a71b4aab86071703208c060c29bc17bbcbfb95a6ab14a8665482700c92f9ee2cecb647266e4ee01e73dfe859d89d8ca911cc1e4cea00ed8b287f038c9998d4d6f26262b5fdd9c53c79010ebd6951025baa4c9604409dac7d033c634502313bac4174c1f2695f961b6edd3772c371f4774c74be9a8452463ab7071b3fa425f2a4e08fa48ac03f946e55a4c0858d3422c2107ca31051c7b136f1b6aa3122de08501cbb82d03c8cfff2ee13e0ee747281852df694b1a8020924b4351c4bdfbf457f001ad572a78ecae2e250f9517c356bb657f12dd7f65bcf48ea27ff3717f236da259dbe597ffe5f6873888e69ba52db5057a4be9ed11cb6ac7536741daf7cd3077cb2420e065dcf47a4dc6c08eeeae8d463b0cef0b2c81be4b38f8320b76f8e4d1c4a1cf44c44b38b9fa4caad5955bca240614da3072a6e0699a4984006bb69ddd0a7ac5018dee3fd3e03e5bce8d2b49d271a18c622c62ea627bf26f06b2c0de4c3fe5569aa9163904c55e085f40b15989d89e5774a1d6ac3613277651970c0e81cb4629ae908c808fa05166a451220c31ecd1e394f108c162190aa9518816fa69d56c75dec920050d300924558cc4992b6c02fdf649a6660df816649c0bef88a97622511d54ece9fd3a48f7891914c8fe5fd6c892f65d0ddf72c6a980cd5750d1f2765d416a576ace05299564c843e44f8a7792e9147fb63629d64da11c8f2f73de40a09605822f90af7e9c2c39599417e1cb2b6c44a8d59c669e709e99fb1b4096bf08556661c382cd3e70bfd91215e6385bae26aa52e0f28cc48c6ee16a2a8f0ae8ab64862a7c784638bce0a3ed5d090de6d9f2009277c9f7281a3ee36b35dc180e257ce05ef32387079dfc3bd4d46685000f37de32f5dc688c50c301c3b78458e082f90ef30524c78cb7b156a2825bfda5042fbc1fde036faabd4b14475073e8ef1330be51935055e1e1bbb4b27de23d9681e197c43cc17ec3195eb25c429238bd7b0f9037c7fb9edf8c5c32a0fd0c08d0718e701f5cf5bb04fc757c3ebc3c3c349c0717a477f84e1db6b3757b3df82634b0d63e0d3a8065f0b3d7d2a78ee002e1ce6b8e810ed33bccd0cb0cb48987e865216312be09073cb5af781ebc149e12bc4b1b31247e08fafa2533a41946383c2c193dc411172e7ce5fe5aa0e7927c1b8fbfdacc1ba618d2121e12ce030548f1b003f95ba18387f51d7dc12fbcff9f2485b730fe151757163b05c28d052ea54aa2f722917c65e400e6c075313b6641577940b73dd901859762342a8f95e84f9754cdd31fb6d8566f290504e7f6c791edd8392e5d5a77b13b89b88b6c2b78e5ce29f1c614f07b5dee45db781786d4fb8a3ad7bd6f55c5b9d7666b04ccc5e2fc7242865b21cb879a8075727d231b9f8ddbc011b99d499fdcca756962ae8b2fde0aa296f9691d4f13e30a45389d129515f033997ae56af8750f11ed70b0febc6601e62415c4ecfeaa9ad4aee523ca4614baa1c3b38864c304770aef9d6d5aa20abc069f054749053e1f6d2d5228a2fef36b01c946b170362d5ab0414b12b86a7ff746ce20cbb3150a673d0789be5c754d92d6794e174321ef63ce319aa47589050983e8504a6c2583c903499e542001a132aa639e3794891335596e2507bc5d8996233157bc1fb679f0dcb2bfb0eb96c5121628d948b3220bc2247c202c48d5716ca1647354366eefae48685cb0c84125a4e50a21148e8a0ca11f0908082af557ab3969a80e690126464948df9139a0e9710add1033be46947711b93bfd3110b526d69a8cae282210137244ee8705e59d2f915b250f7335ca512fba334f755bd01dcf71c30b1a71c02bac6ffcb0b5dd03a5e85232664ac23d948289dade01d194a04795c444ee934c7370f0bed9699c06d31185b060f756df8daada31a860d97886dbe7392a3493b61481c7fe78a4071eb8b1ce43e5fe043c33c43279ebc74bdad6dbee6ec4a8750d373a03f00ee5329421508effcaf122e2464321f3f9ca4104e57b79867a68ad0ce694ef1bbb411761ca77b1dce7ab2ca882545ffed36953b445cd06ccbd08139cae0a853915157d0754f852585973a4d64f2b50c3ca5da731e225faee35e6940387dde2f0aeb64411432d6991c249b594b13539ddcd40c14f443d61adcc416287d8b6424ad53cd3d26c6b26efb36696a896f76dd6046516d26381bb16ee6de1ebdfc210bceb7493670bd61d0b8348db60896f0bb97901ba18762c2d8c8523976f17d7a04b17147d6118b964e6afad1646aeb90c684d4fe1b8b113e7adc346ec8925b7765668dc9d12dc92d78037f0d0dc05b33529a7dcbf1692ff1eca40da66123d70ec6bc316534c0f1993bb686cf3cb8c7c63f4a455e4d2e68873c280e2bfbd814ff74e758d76e78176b2e73551fe2db6cae4d37cb02fcce613b9146b601e315dc8fc51a1bf14f545c5056a5b0d2cfb4f3ef59dd2cc08c74e7022d2a11a098c6dbbd5305f8dcc355f7a1cf8016fa93c7c80c7e3e9fca6d301054e201d8b1d5b42e9bd9f131f623bfbd939c5165ecab3c9894c79fa12d3c1103582272273ad7f78a5f58a6969a45da394eb0344090a1b7e4b1726e49710e576d62b79d655c0860cf8ecbce16cec8f208238749ba722195bccdadd636bbeb7c11c661606e77b49a88fe1517dda834545105e2c3a8b6e90f66d93d745b144038a047e46c758e7f295b8cf5e3dac51caaa90273e14417e1a55b64f2a27cb67fbff8045b97117abdf16dce1034fde6558a35491331b678f72a35834f5dfa788b19b36c4e2df5e2aedb74990d2a1ffd923f6883040acea6e88f62f6e04a0dc5ab5988aead19aa8817634623dbf1e493bd1b1d348f470a5530cdee1101add85162a5d7689eeb1caacd334d91bb82bc3db82c9c6887fd9f416d515b873ca55355c83122bd7e952004aac6e2e114a0e3f0a7346852685bea6d85edb8b7e1d61c0b6602cb6fd7b51cebcd57aac0fcf140e56eb91cf3c16815dce60400a62aaba007f153b1b338b2d3b6874e7a30d2f0df810d24ece117ccae9c5f3dbcd107f49dc3b9525a913cd54905d36896fd86d0e8b9cc10ebca8073700cc15252166336405ed03b1fe5520919a70467db8ddde77ba4f294599565acf003cd89806aa2d642fd7054c26539d34471a4e0afe43637431a06acf28563e029c837c48160a583553ece5f5d787e4e9c1cf44878146d6469636b24eb95c76a3909f42800a953dcc1004f3bdb87319223dd610fad4f4f35d03b3de156c57beb688675c560c681e7b9fe42595afca3c81376c604ac3ac4491265951681294e66c391bf16c9812db6c687b639e01c36f6b4e3609800f8b643575f7fd89743e3254cff51ac8a1cc1d9351c4e37ed8a4fddc40dea32acae7ff51cc7a742d55eb2fb1f8b6497aa080cd081fb24dc3528bf430343740ff7575319623898123442bb1395108e03ac5004d57b249a2305f35e977e6a35363c0c42a885b308a2bfe2cf9c60ef7b36ff00f317e00469271e030d46068c045020eeaebdf3e8d0edcd1f47712b7a83510e7a3756e14dbad61bc80e70d3aab95388ea6072d6bf84082725f0caae61748c41be76c872d9e89c104faec1db28ad1ba46ef7172499040a02e4a1129b0c5d49f8397f69410a7053f36a2468845ae41a9d19500a6c86c2a79d7923c49d9380679f28a177afe1db9f9ce6b305225a8202c221d83de4b1639c320afa45248191f0c119c2e108b3ae91fe548ffcd1a340c607dd4550772c8ae745943408b90d26962064db78e86767b608adf09567644a11c5e1351d883a64177eb581d5dbf32f2682b3b458c8624d2b236c23244bd9294c334cd4cd9e6244e9690301fb9c334b9a12c810a550c306377471a3a2a5d2914a266a9717f59dc215400f414a8416b67ebd96faefd0960cd2fa2d949d5237f88d590dc07ef0bbb9333aa72f8c4179394994bdba5cf5b5398949326f802404c4f2a2b297b5c4d9496cebcecbdaeccaea21232b854190f52ecd46c19ab1034b17d97009635115779f6193eb0944fd737a95672c635770c14a624162ae21cf0cb4bf3ce14cae00d4746f8573485c00a0490da33020023a343c3f12e2b6a1efa6056e5c8f8ab5b5d2a42ba8f66e3686c606cbefd7db6d0121ae8a2bd1b05b03bb33c9f74997ff2ba2c590622348b5b816e6e1ed4a5fec280714a0a260ce16801862bbefb33d6ffb45ff9db3461ce2d3fcd24a5f0359088c24cc14535ad1fac56ca1cbad5662f6a90e0e216abf71ef168116dc20b0102483dffb44addd7c3cbba1e5aae791484dc32066a96a9a66beb7de236f17d207eb9f8cde5e3fd365b7cfc8c6e9fe804107ce7e010f7c1d68f11a8d41a885e9eb03aa3f56309cc153670163afcfd6e058ff692952f69487935b0aa332624806a31943bee50e54eb80e3b112fed4a1dfa600404a2e43fa7322b20791c01554e1bd28559fbfd97b52266b5000c8a17a0ce4c93416d0c9079f36b8c186ee06b5eb266e1926e3b0cced82c4bfd7c6339b895425438c221109c095aafff79461e001376132cefc7b7df66a3041859670629d5184d673252d584eb1905b647766cdbfc72d00c54956bcf2e943d085093746b785711b4c4060a169b66b4ac310b0cbd5b0194f016c80bd620242d0eae6cfdccc09526f32f7e1086f3afc4fb3e28778ad222e6cab4a4a4696c90b900684d1e94114a26c952f69ea071a0a6d1d79f010556d96410fec1718bd2bb3b406c010cca5de736b36903606dd9d7611b7d07bb0a5961466b06863f45dc2b3135b95252046065f8f0602478b2f0f915104a120d44795ff4225c69ac51176aa563ed2390ec469b1abaa0972371d229c56b18debb1e88265c6bf09aaf74495dd14a52511532be852a854796cdd0075e5d88c93025f2880d68121b5b1d6ece2a53c8d6a8e796c1b34ee8398f5972f2497657cc814f091a8d076031b19420a6d743cb5e205fd64cd8c7c9fae864ee91f2e3f2a5237ed405fcae8b134af981ea985d5a3b70eacb3403ef47a1d14253b882e323961ab4ed5fb778ad8c77e6cf724dc9284d49f3ad49825b00cf663e3c8dadc0f09f22a973b448ac04b1312b5243b6662cf8afd52a80ffeee609d8f3cd0f913481ddbf5203c0409c29e162409e81b6cb8fe0021a6269cad359e76a3424e9317a9254a4884018c0a9ded8bff37c8edc849c76c2a2e0acfdb6643d79eab10f8bfc16d9dac101b860f1303040939dea2f6511c25b92ba0c759f21561e73edb6e83374c52d7f26eec92e37713295b14a9143938ebc5f10d515cf43be9da7c1fc6a625bc6dbb06231184adf818cca6da892891d82d284c04920ced850899e44975ab580cb60882f682712a2ffac264b683947cb005e04c71230d35661ca51ae6d01be4d5828bd3d1447f5a3a4545f61c77c042d28e4c77d408ccd10c210fce9f5cfe9944e4ea1e90fb82153034f8390d2ad3670b901109ca9cde7d5d204dba03fb4a42b879dad17b3470e13a9c8bbfaf9bed8aeba075e03630146c2dc54119529985b190ce7e292d07aafc65d33fd21fb6a3e81dcb83ee1dd5fe28816fa3c93afb46d80b0d084798fa41af0055baeb86913b644ce9c7badfd88badd33dcd95f4290d0f45ffdfbec0a37aa53f076b85c83389488ade83024e28648f9604027a6cadaaffa1e241a2602cdaca451ac5a8d1c0ee516bac5607aa40ac4c9ce98dddf3503e8ca793b2e04d7d07c5de43e2822e6fa945eac71226b0ee79f439f980b133d523513676605c8252c3723b20d15360717422cbdf171d052adec1404f571a58bd088804206181b2486d0e7d6789372026c7814b03b37d67126e3fc7de9ff7d1bbc8aea620403dbb3b7809f4e2d54116e61041b3d19daecc007826cd938660929b008eade8607f26bee9541634469521516641cbac2aee5031932e0c336e41daac68d9ecfe851b48ea4afcb82f657cda0e6595c57caf865f2ff7d210d0f56a0d5e71e877f9fdc1536ca1f5f4fd83995b9e96fa9b0f05da4218f6545b369d01f0ad2c2808ed2f28aa35f52f8ca8e05f5ba1317b9ed55d0eb9a5915b15941ba34a0e42d2d6611c2efe651de5a0853b55e21d377ba4eb25a8301de87194b887a8c74d915693a63fda02b41b304e65fc453f076c2addff8999f38d5f03219219f740d734e460637b5889a42ff783e57b48a2b154befb87dc527079280e6198ccef00465289da783c5efc7a4d20e4d8298c3689d08ed2bfaa2e6b1ffe110672de18f6e5119461dfab385be86333447619f2e1913f03ba166d038fa4f3c042f99c009387409d0fd851abe13b89c3502da44c8bcb1438d0549e0ace00a820504a110641381d37cce5b2019dd452748f9cb3432f312aad502aeaeb4d5c1f6603c818bff92328f53d25a13c755b3ca0083b9bab6017864e4a543270847a37cffea2ba7a83d4a886df2100788624d9047f440ce20020d32bc3ff5e382a7271ed4d3b233fad7c3438bb202249ee30207751ff1dd9e2921f7732e2c404062e379356b8c28842917428aa061089c40180f20e49dc02826642aae9269606d297762b770a6ec7cb62dc0b2593c81122b29bf6cb1950360ad841a66390df9eabfa63059264295778d3eac77db4470e609a288bc60b41f4a8bbda57f565fc630cdf88b00d7ef7196ed526b18dcdd2d9546cd146fa7fe73d9be9caffbf1f0fc217affe40de7d91f48c9513b92dd0f43bc726982ac54c0b0b502aab434ca4e11457d05141049e5a21c8c02b0d909a51f226187affcc8243962a2975c3947ce50e5105a4316155068f56548c482b5214fb518579fbcde7a0e6b96d3b7398d427fd466d3363cabfde8d856e3db3d92a0fe065f15cf02b55809c7e191c64fcc0b0be46aed077de1c9f4e670f2727fb3d5beb9dfea2c38b33600f041006bcb9ec6c496cf7cf0d4dd1409ac395d9b60f9d85bee7aa1a79e36c094666c7452c63f526bcc3d80d9b96ad51622f65c62e591359a12ad56697931bcf50d9d7d84f6606ad8acd7b024588d56c5a08d18776503148dd3627f3c3cc94e6742d20158e0d7f975ca44c8bd7794254941b98021be18b2d2f15c29982142d08417c55d1f7f7875173d7b29a15224764f58e4d0a8826371837cbcc2608b251560ad0b1c30c48c5d604edf9ecfa1786d13813c4045a03620e223c5f55ec0358fa00af9463da09c40f66c845b9630f506bb218d08045b2c7a598335eb5771ff8a89664ed4698a0d250860c57017e41002e521a2859cff6c5340f38cbb083c92c5af4079aa7af0a04d6fb42002af3464b74c6405a17e885332846207c8b77ef84f574b10411285ff3345225aa2c8e81abe705e2929a4390aa5b798685215dd4c21145712c20b97b50cda2ed8d5d98f8081baf526ab732c93bf86adfa9082ca423585186ae8e3dacf521b9510c242960b7910725dc892903042ee5921624302948d026e16847b0a3760b46439330f0f0f0f0f0f0f0f6f706b4968db1892209394924a6e3c99e26d4929c994644aa201daf7227b35fc45daf01769c35f88f106bf0a260a660ae8e694d51c3306a24d79e35bbc0e205acb312771cfa67e62a3a1b6caf1877d4d663fb431cc4fe5ab129a7feec33232b3f6c7b57c58935213fe1a6164a4031c7be8841eeb94a4dc3b3b3d5cee31cb43a71f6442d6a474bc535e900370e0e10ad9344528028e3bb4e7793e29fa66c61f2f1c05c8cb7639ecd075a9c435315b253e4543f76c8cad4395667a2162fef6a735be580062c00c2db40043035b54e002650065e0a0c30938e65038e4d0cba8860c93153c046884e10dd8420b1f38e2d05f8a9d49e4d216d999861a071cba6849f5b48632d714dbc840044c8eb151c46a8801c61538ded0cc46cca124a9145ac434d46a0311d0428b1a5f040e37f4f132ecffe71c37bdcc00638c1925f8e28b2ed4021b5b6c4460230311d88800a380a30d6df410632296841ccc67431fda638831f5645ae41fe05843abc174f40a498586da176294ad3dfac20b0570a8a1fd8b5fdadd44ce07d3d078cf04003be040437bb1795248d1945209318e337466f9634eaaac359a85861a0752031c66e84447ac7c412425ae7e19daec164d574c4964e8a37576fe470bb96534867ea286f0963a460c5d5072c34f66f998141386beff24c9d3d4893f5a30744a787cfb89cb3c26fd42977dc172cebc29c247bd90e4e42245c5a076a1b7982d942c39135753b8d04fca29222c754f26650bbae4941a2279d442937cf467f1340d224bb2d0e6bd4ca22dcc69fe170b5d442ffd0bdfaed2c815fa14b34cf848cc621e8715da6ce23ac54408be21aa429ba406b358154374c854e8b357448d3a97b46568048e29f441d44d26a614f37e34091c52e87c435297785984d60f1438a2d0c7cf62c963a65e781f0a5dcc9cd068328236a572c7f184f633b446430d55c0e1847ee3efcfe906ab3cb92229e0684223b1ba44343fd196c9467030a1ff770939c5ce27a083e0584233a3994152f8a0f363dc070e25341ed52c55c345129a981d2bb72d494842c5041c4868ab4fe65b5065157e81bc18034bc071842b6446cb3b40014c48c061842677ca21c9440d5a9c31022fb840781ce02802115af3f852393b2567353986d06e90a3624cb173616a5060021c42d86487c924729a100902dab356fa84181d430542422c33c8f7833a280d3283ca77c1858b91387cf0a8ec317ee3e841952d63a31c3c6877cfcd5ffb42432d8c1178170b581070eca0d11a296bcc162903870eda896b2a4c4e34079dd0d312964b069553a720a2060e1c74524e7ceccca4ce71311ccd0023396ed05ac8d13f899ce1b0412729ef054d53564a475ccc5881185c78e128f82ebec61d470d9aa01a13e3dd32838306a4a43cf5e98e865add0a386660454e0d5b399868a86d083864d05fe868a6442bf9c4a2197f3d0f17468652d9804597d93fd1adb292102f0d5170c5365ed1c7f292212e5cd1c6f0cd2534fa59650e0db5195f2055c2462bda9c25e3c47a76f64bace852f88826622c79d858457f3d7f21ffb344ce962a5a37195f249c4e2a9aebd2151ac206156d082969e69f9e0e397b8a4697fcd25c1df17367136c98a2cb9c2a4fcf748a6165b4518af6bc73b7af760ce71829ed6c90a26f534d161e64deb8308fa251d18f24aecf15459f33750c1d5783b94b42d16bd01fbe537bce912191d80045bb5fb96362afe7202d49feb0f1894e7952f2212159870d4f747e32bc85bd136d92a94b97b6f988ec2e273a29615535e86bd1fb6fa28d14f16318fd51a22835d147d15da57e29a7ffcd44eb99e35b3c638a91c7446f39c9259964061d3dbf44633a85fa76d6fc2eaa25fa929f10c37e961c8357893eac8baa8a311e3c5d4ab47dd9e3b924e9868d49b41eb36a257574ee0b5d20c9b021894ecfe5d22db21489bf42d73bf4e62521d1fc5588794212bad9c9473479b382ea333709ff3ba2b7cad14995b2ca0f2a8d68f3a726cd929f534aab850d46f4d163325529a7919416d178862da5c2fe569b47117d756ec9a8f325546412d1ccc6ac29090b2a2ca90511fdc7ec1339593a44eb3106b95749690d8d3144bf49c7e429c80f2d3153886672a7fcd71427449f3f9ff227914b6aca41742a73e916e42888b64bbd730812c2784c02d1492e95fc937e050b1b80e87d3f4589d9b08b2fbea8c05d61e30fada408bfd797c423cb1b7ee8633ffe7e94e0f7a1bde899b993f64ce15b3ef415a2b3a6ca90f2c3dc437b3977cc907221d8d043a7af2b89d3a81e57611e1ab96d7a942ed9ade48fa17868945b4bcea49741258cbc43ff49540e3ac61873de858bf1851887810d3bf47ffe39684ff620be44436d0535c428b3c0461d1a4bde15528fae12d8a043e77162489e5b0f6ccca1dfa4db212869ea7115b809e4d0ffc5b7f079f2647827b011875e3676543fdf9c3d35ec40b00187e6a4e8d6ea0d7deae925d1f21762f7620cedc0861b4ccf8a79b6a1d17e89979ba634630535c4400d6cb0a193d728295a5ac477c6796417d85843a7acb2c4f60ed15023ac862e93bcfe19cf3d5135330606340d9dee895a9245dfa2031b5b6c4860630b0c24e07f01e847b1818626650d115e32630535c4288688828d33345ab39eaa4ea5d9f268862ed5937b86d01aa729fdc246193a1127be42679e49ae36c8d08fee6865a231f888908d31747263865f195d0c6d65f30ced294bbb886c61230c9d9012f725f6a8143b250c2e34021b6068f4570c6d60e30b9dccef9b9de3261d6412a3b0e18526efac8e7ad03c494a36bad09bb545308c0f43035a6851890d2ef4b1f144fc93d201bc898d2d20731ebf30e33127b9b1c537600f1b5ae87cad424ffe53becefd2f000f1b59e862abe28276070b8dbfe7899e9025b6728556925e917965746766acd05ae44d7193971964b60a9db22c67b93d89e636a9d0864e139ed22253e8834c10ea13d332ce047931c602d8131b52e84788d39e3465a2d0e9903f9c483619f673283421c9089729c256a9ef85170e10c3c613da7c223189985427b497e36bae0a8fec7969425f22448289e9539a2513ba1c49fcc8e9e49a3ac2808d2534395e52dd915425595a850d25f4b13fe8064d6561e35701296c24a18f2242cee6a4fe417e24f41355b28ed2958d23f4714f865f2c913bd7dc3042571a4f6eac64a93c4c2cd0848d2234bbc9744fd774d221b2c5465160638b8d9ac0c6161b25818d2d362a021b5b6c1404362a10818d376c10a18927517f47641a6a5b6c25b131843ee9b09033960e62c6d2c2890d21341e4568c8d77b79cf7280185f7c718117e38b093c622308adfc6ca96c3e7225836603085d490d0d41b926213e51c0c60fda0fdb5fa692b42ed7fc182770302840ee011b3e584772de1c739e1e34c1748b76796689568db0c183642768ccc87ecac0c60efa0bc243f8563632c0802abaa183bed2cd7cc6ca2fac5d380d74c0460eda3ca17c72beb0290e1a8961fd4278aef406edf5c91cb13d558e1b43436d86175f10b3416cd8a0dfdc5151297274c511ffb051835c23e7ac1c43bb41833e67d80b29e5f84f6dd1504b402239c2878d1974e245538ee9c9b12de4ecb02183b63d2de8d8b214825eb28845234aa8e6f2cff2d67c16b038dd3a89b2784557aab334982e21e39559b8a28d49964412f17e4996452bdab84158999988bc04b360453f96179e327ab2584567d631ee84f1f5187216aa6853949d3fab6865d69851e38b1978a96852e72a8d9d0ab240459f7da278b5c5f9e88a218b53b4622a550ca1ef173dccc2146dc8967f338c454a626aa14515b228451bb38652ed2943438d579005291a19fc63f75e6b9cc5281af7687199628ed1ee31200b517471e3274f5a4e34d4b0025ea393105984a2919f644f65848a0a1a3e64018aaef36e8978d94ac6cf175af274e8e55faef2cc0691cf1cba14577a44cca46723874684a7dc1d92981034250e5d95f60ab1281e379be0d09af99bb824f768ba3734f2aa66f2f39f0e5a71439b59deb4eea9f84d6a4327f5ad4ff733e712b1a1cfa7276a5211314a6be87379c59c9ad28210a71abafc5a2dbb6d26433e0d9db9eff89e5910a3a1d77811eaa14b650b9da18f33327898bddc1c33b4f227db5b62484b192c43bf9257d74bc6890b91a1978fd13b8aaca8b142c6d068970c66b221abf562e82be40d91e730b4edb1224abb60d02f3439c51cb443968f92e285cef3e62e15329b78b10b5dc8cfe193f210628c1c17ba9c573e2adb6da18d4964bc8aaa26d14f5f48c265a4ea59684686d916110b8d8ad39b3aa449d1ccaed088c490132fb342e3598390182b7fe8bf0a5d9eb8eb7b890acd76aa145250d6c18253e854126d218f69d11c2929349b5762b4bc4987f3390aa6c50708000524c0135a8b257294dcf7099b75425772f4db540a95eed126741db354ec9d99d0a61cc5fdf4a5345a40802594dcc2ffb24b9212facff01b77469f8436bfc8474f991a4b7524741653bc98fcba6254f708cd5fce7d42668b11badc9ae76405e93e9b5284b62ae5514a3648842e89043f1171937f121942bb6d1e2c478742e8f325953e2ae711e29220349663e7247229ffa01f03080084dea3c6d62039a490dafb4117ba544dcf645329a53e0c1fb4e1437c311dbf22c4a01ef49373475f4e0bf9e4e1412bb2b4340711a2fc66078d5f5e10e235f306a9d1417f3994550eabe7a08b15b2c63995e3a0f3ac3d3204f752f2dd1bb4ada3640a23378789890ddacdea4e59218b10f91a341e75b453b508d3b9d1a0cb172733a662f61cff0c1aef4e22b865ad303902c8a0cd39860bf229138b2e4592d52958862961d1c659e593eb896bb1bea2b75442e205a53c665071453f17feb4b2a99224c35634ba3b25879c8415cdc791a3cbf20993a28c5520f26e2966ae1855b46142d8355d2afad24df720fc47279c50d106612a49b427b93153326520e3145df613e143bf24490c09b9820c442ca8a05962ac40414629fa1cf55d2f4e481efd438a4e6852151e3556599c47d177c6d8d93bb6fb89a2e844bf42c498722eed48287a119243851c178fa081a29f985fe545356912eb13cd9afabf5a5658d0ae0c4f741e746abd8a6dda82298c1a5fac08323ad17e852d6daa72b30519464106273a0d4931531279e793888c4d74c2f3cf42cc87d81baa418626fa70f19470799272cf973b838c4cf4e366498f6e5e1265d9d8e2b5ac0b323071d06ee25d927b892e825716b15a5264042dd1f7be8a0ed77a251a917d620c61bb7f43a344eb32b1cff3b509f3ca24bac8f99364b588c94356126df5e4b051241a89c65a3b8428d310368a90e8c325b99ba3f223da58fa2be9889f23ba4a7132a3e9a9117d5ed2ee3029618497187138f9395944a333c23c9f056141744534a79efe97aff54fc444b4d6496bc81ef3e6181a221af191295890dd215a511de3d462d64c863090618846e445f49953cb199142b4339f2b56dc144ae610a2cd2e1e46e4a457df4174b17a84070db2209a94b21a4f09d79c491988b6c3e8f5734b01449f448a7b4a792471faf387fe2d244f254e8e63c8f04317f445739719c94992fad0b6f8e8cd91f48e328d0f5d4510e626dedf432b1ae5544e65d143bbe6beda9784567c501e5aff0967fa5478e87388561419f39265f60e7d32cd41751cd9a1cde15386d88e6b396b75687df39f488ee9d0252d298c8cbb113f9ae6d04e929d8fec9a29fb91436fa62d77cf5adeaf3e0e7d653453cbff15c23232e0d024a173cc61cd2a28113241c61b5a373d324ecaa7d73d54820c3774d2fccf444cf4ea1cce1fc868439731cf299d4abf53ec65b0a1af701982704f1d1da38c3534674a9cc778212187ec63c00932d4d0a830af6d9a3c9872d3d005d116277a4ad1d0249d5208197333a855ced025df36113ddf5e0e6498a18ddf953ba7aa5611a232e43988cfd7a77299ce9561410619da121944d8a0c306c999316851e486ec21fbc94e4e0cad57ac67f74c593a7a183af3d011db73ddb50543b3a1739d53f6936e5fe8b443b0247762e5b4d80b8dccce945972b5ffb85db012c8e0826921630bfd8490c309195532aa163a4b2a84a6f8cd39a94643cd0b2e66a047637471bcf8e2a82b6464a1f7e095f258fcbfe8140b9dde08e233fb8f694dafd0f5aa4c38dfd20a9d1e4da662fe2cbba52af429680f3249cb494e16a9a086b8631529e8981e1a9a5b430c308620630abd596a954939a9925ced4086143a8ba753d2edf49890140535c4205d826486163ac88042334ac8111b25c7d2fa131a71551253e2a9202e4e684fb689533a7a3d254d131a79ea338191626d427f04194b68dc440c9f62cf4ae867f2450cb316da194e42a3ae2149c49d91d0f685d392375a1219b2476894e69cc276921dbf4d2334aa33e524634a4bc22274b979561e84564a9c08bd28159fab4a4c100b0ea1ff34f3b188ee298888101a2554d2781e2f376a178466354d68ea1c27e809844665848e31d9595734193f6873263797981e1ff4a54dce4a4abe6b3ad983362c58fbc9242b6388f0a0bda45f517662a74ace0edaf1b78e9dafb4f2373ae874789b65121fb17334078d6eb028223fc3012275a4ac92d5c2818c1ba4c38345923b96639836b04a3c3d62c7b8c904b10cadbc71734c460dfa983b5b56fd5d060dba1416a2b1a49e8230c0f01460c00b0ad040c60c9aa412929c94bdfa3387792043067dee17592a397de5ac1870c4a27189bdd62f423e23a5051cb0e8f5f27a24adf9bbb59281f417e078452751f3653f3e56458a3b030e5734d625e35b64b6d29d4443cda0196178591809d81770b4a2b18ab9373e7a6b86112bfaeeb0417ce4bdce2f59459b67dbf79455250bc9aaa2176bad0ebf705926e14885a5152ac5891aa2c7bb00c304af43e04045a36244b648fa533fe4148e5374593b66563dcf533669a86dc1618ad673cc98a232d253975b8a3e674a195e35778849478a46256542c9cd29fb3446178e8262a368e4426b8f8e906b84e1db00bc0b7088a29f1877454a1e1984e484a25392accf734c2923555074397ae584d9b0d06bd150628fbe98002ec727163911f2c40e8f86d298915609e0f044a3e5db674b473b640431a09dd8625e6408030e4edc26fa4b724a8eee20630e319a68df7d92577ec99189d6b26efb26971c3b781c986883c8159d8299e5cbd0251af1c947a80e2ae5529cc312bd856a27158448def1af447fed9664d6ab50a26f13655237c44ca291d57122a414f3b5bc92687d230915ad4ca87c950e2447243a75796df990a37b1621d1c6d3b9563956dbe4f3883e6f24cbcecd107f2758010e47f4ad93728913173c685023da2b2ddd25c2f9c70c35b05181087030c2ff4849ef59f28e8c51e38b2d46e0c50546e0c505ea9cc6164e630b2db4701ac7699c19c80bafc1b1884675a876914146b66ac760037028a28d3974c7b026938846678841cb48de5e13d6482d3810d1e5e8ab1c3d9679c13f441f622a632ecd3cce86687c4d93ec7e0add092a44a79d33b39ca49452cc09d16f4c31ea482df5d87910eda414477abe108316a920fad63cfbe67c125c444c96f2e842632a46d8ce2b4fba835c38ccafb54af95fa76ca11fb196bbaa2734140c7f1a5b1e5a303dc54a5eb932ca53077864a1936d2123ba9b328d1f0bbd448d331f41e28ce95c1c023caed0ca7ed2a9af19d7e2c70a9d2acbb313f5636638a304fe350c9a1835be0803d5a30aa6d4e472f263c8d0501ba3920aea3105529829392bf2904213f2e768228849c192360a5d049f49923265886128f4b923982935997d528ac7131a212321e5f844916f7938c1a3094d9024733a75855eced99d053c98d08e124188d4b87c9ae3b184f64b6f76159557426fb27f3246d1a1b145496836e82097af5246181109cd48b314fde462ca7972844e54782e9d496c5f05cd044705840a1e46209e18d11e56c28504f00c1e4568a3e9f8868a4468e24c90f35e9563653e061843e83bc92cca62ac3895230f21f4f1a5156244675ff462d8a5c023088669ea982d1a1322c6185fb085512e081e401883c70ffad22d29276fcb3d2b4de1e183ae42b6986e3abf87e936b6e084470fdaefccfa392733080f1ef45772c63da7a7d49d2484c70efae07ff1623ed5415b16c53463941e39e83a789e84ada467544e073c70d0e8eeef5c2104994b2578dca0ff53aa3709990ac2c306fdc44a2512b73584354fffe05183b6d46492cdf690d1471a34b1359a8ab36e041e33e853ee1713a66377cafdd5c14306edc5e599d6f8d7923bb61a8bbefb3cdc53fcac84a58b2e5c8dd0018b463bf5f5041dc1cd64960e1dafe84b365676488d713c270e1dae502b8705195278e6d0d18a3ec6d3159697c38a2eb56b0c22590a00e0d0b18a563be4a05490336632a98a2e06092a238fcb45472a3a31bab179c14477eea0a25377b150e163d4723c4fd107cdf1634c25739cf7d0146d6a1016636ef66ff4cce000e0a0a3148d889c32254b527964320cff2e66a00f3a48d1e8609dcf52236698d028da0da37166639268fadb193a44d1659325439a6ace734b051da1e882b058a6a478f4588d91a103148d8edf9ec96da9a562868e4fb456e571d4d43fc68f3cd1b6c6e9ffe4b8f2788da1a3135d1415838ac154e9c99ed3c1893e649f2715c722eeeb1fe8d844972f9899129741869cb459e8d044ab419586183b842c5aa358e8c804424f99f6157dd250834107265a51b91db2173fe85668a8f9257a9df114a654febd3ceab0441b2244fc6e52537d255aff1232e5ce123ae6130d35e71d7450a22b51b2933211a72b29d1505b1d744ca23725cdb2766ad39d241a6a92683d5e359a5684cd4185865a24bacea4de5971e213355fa0bc410724fa784b9a4197cc4156d018603ca2ab9c71720e7aae4c5f1a6a60180e3a1cd14c506119d7f93e568d37267813cc10e34760d7838e4634f9527c6bef91869ad7104305ff05239a1ca9334d5cfcca2dd25023566ad0b1887673680d224e76092b7eb11b1960c0c6165f021703035e50400b2d8800ead0a188f62abfe41c4e9f887f47f3e5927ca588a003119df7282509741ca251a9741c29c134c34e0c1d86682e6577ccd10b7d2a9dc0133a0ad127add7174394fece3184e834d6520e27456ee554c720fa8f9e2f3a458b17ca14801f7408a2499e933da836a5e3840270838e40981614e800846951818e3f749a5cac72e60e99e48661d1e107b3644ecfa0a71916fcd748351e055fa3a30f9d0e37a574ac5db47f68a8a9a2830f8dca99f164fe988e3d742277ce3929afb861f47a68f3759ee54e5995e39c873a72b2ec9b710474e0a12b397931fb9b4a89f93bf4a942aee6093713a2d7e03a74d8a1ddc897a1bf7f3647d5518726269349c850396b0a4a74e864c25c0cda4b73e8254efe146304cb174d72e862f65ea4d4d372d3c7a1fd32a159b307c1a1b768a5642839ebdc794327f9ff5d35e95c458f1b7af5399f2bb5cc39316de8644b6cd9fcde193f674317465a59525a53d0c95d439f75528fd231f732ae6ae8573c27dddd9ba29a34b421b6a256675d1d33d1d08686529d84521d4a7567e83c73a7aad06186b652f6c549b00ccd06eb8b99f927439b3b77f2eb498b31f93174fafe8ba1919647a8d60eff210585a1d9bc92aa93f534081118da8c15434624e80bbd8f100de2344f7cd3f14223bd555c36ea7ccc7b17faec49a6987424f924c48576645c95b0fa164cb157d6429fb3e36cb894b3d079ca0e55539164b43016fa1d9311b44fc6ad70afd04696386135e35e45d60afd8e90f7a4bf748544abd08889e6a353259d4d5fa8d0974cd627c25445cd32852ecb34e8d37ea13d2b526894d69c21e5bf28ffc928742664082621040a6d0a59a55f720e97b37c42bfd921491f59cac2864e68e545758855de49e59bd06b8a3a966487666b98d099ec16333fb910df25749623d973c994d0c867864a427549e84f4d8c142174895199143a90d0bf87b21c2182e5544147e8b5423ed349ad0e233496dc43cce5a93cad3a8ad084984290f0eb4944ac8ba711867f042c79d041844664664eb14dc91f9dd94b740ca191d1eb519e5384d05b89e78fa8c9a4856410baa4631e9d33983cfd11085d6faaf7860bd14474fca0d19d93ec988c5b55bcd81e3a7cd0e74eaa914ace9a89680fba343159d7248859065da18307bd5e90983aff6ade20a742c70efaed92fd25e45cce57b142870e9ae8232349ab92837e7e44e52037d6818376c44ccede9d21c3bd8e1bf42156653b6cd0674e5953e6988bdcb18e1a349f1b5ad9f26ac88fe9a04113d62ce2c8733b66d08e9e447d8f271a6a334ef061a8ed023a64d0e6deff0d614f983051d0c5171808e30b302630022fb858c1f11a6378f1261881d7a051016b030162d1c952c2622e5e9c20ba44818d2d36d208008bfe5fbb94d06b39cffe2b3a1d9496379daff72f2886177f5cd1080fb160e169322c1e81175cd0c8408dafc0b6a2099692d0b1e75f474859d1eba41421a60e20c02a1a19832c19b3b98820e5a38aae63d4f74cb921450a622a102015cd242d2f5d624a06714145a3a485e8173a6ebc89a7e88376c6a6088f254233459347466cec90b21bab1f010386408052b4d9536eec4f94146d4aa154c4128d00a3e882e82023a5205134faf22fc5d85c3223a1e8646c176d265a43e512289aa02e6e290613a152e913ad27b50af9f2e70b274f34da532cb95945a8ca74a2d54f5a548ca72432ce89bebcb4df42d6df8c6fa26b535af4f5ab89c6f3cabd456a55ce7d26daea2033c6f408139d5ece6a42f5e812fdc8593795a63b660659a2958fa1e4c5dce821a24a7416f3e8243c73c6c8214a742a421c97b85eddf93389d6946835a1f4fb67cf914473b919b3591646869c48347b1e83dca4a23b2707126d9fb6eccca355b13a8f68bc4b5b5a92a0470739a24979fa3d5b10a55b348d68b4bbc7a472181d63c430a2cf0c9d32245db592994574c1742f68550a1535a388fe227a0ee2b46ace299388ce6268b01063a798841c119d8e4156f52771cfd60fd18cc6ca6939e4eaceb921fa492545a24abc108d67c965cd721183e584e84275e624e3697fe60ca20b25b2460a1f3a9b1444fba2133d654f22a3c681e83af67b9f751810ad9ab064b12b6f12417fe8bda29888d9cdc762fcd068d36b1649585f69fbd07f2ea92364521135b504e043f3af7a9d91a45870f7d05e85ea5129d45dc7d543a784d4b8cad8e6a1499553c44ba2c9a249f170e999f19c2de90e6d18f9c14396b8b9233b34628484f0a62dab995a8736b586164be854901fa325f5054959015ca2004ae8940871d67341cb855c00952840121a9d3f584e737dcfa984842e24e127bbd7591dff113abf9420840ee531f9c8088d8fb470ed95a6742c8bd06f24edf124a80a40842e3f2ff9fc8987d068ea9e4f3a7c9e66ff86500021b4418a10163e8442284010ba98a921557c0c844eb9fc6b2c7d2d12827e8089385396820e0805f0419f34c7c827223de84cab6acc4146f60705e041abae39db53a6fc09a31db49644d6f87a3e294ed5413b22e72063ca9b265205c8419ba7f307f1c94b478e3c210e28000e3aa1e43ac58b7ddedd29c00dda5826824cd2bc0d3a77cf2e1205a841dbfd29a4f828132faf601480065df8c58bc57c96534e0f11059841a39ee4829c104ec2890f510019b461ba93f40ac9820a2aff118baef3b67c8ad02523665560d126e95ad65d9a37f28a762e357e6f66d2e0160db5306a9031a0f0e18ace4d43d0ec504db2a78f5674f9a2f65c4c7156743a88291d66397faca209c22a95d09d4badab0f557421f165e246980d1fa96892c7901e49e4594f96f9404523927f5f3661b249a7740d1fa768c782d2d9b47990e2da186af830451f72c5109390efbe9f82c347291aa5ca52ce512529daca0f398b5b1239150bf1318a4633cefc58507e88a231eb18ddce18f3a9e42314edbfe9ea31e95d00bcf0018afe4410c9e72bbe53d05c7d7ca24daf8e21553301171f9ee854b2fec9102fc7c5a4138de8554b1ae339a6d01d514e744a5b5f9c9ace31a7f0265a899fb2c41c160c68a1451847f7f0a189aefdb7c467e61025fa99683b2b97574a5aa14310136d882185f8ee8bc997ba44d2f425e71cdb6237b33a7c58a249912546d3e196ed9f4e7c54a215b1952c7e9279656428d1cfcbe49cb359774b7612ad78c8254c7c8cb39d93442f328ff09131168946364bce21944adaea42a27393e182d2bb3ea217cbb191aad7b235c5117da4a44d859cc455df3e1ad189204907fd97f43cc77c30a211a9d5d5aef2c7225af1b06cbaa694faa188465c97cec13b826ab1a07e24a22b4d9d135d15118d4ca93587b6e610bd8660ba459c95c82363884ea614c3988998698b3e0ad1acc8082244d7a72207f149cca8f820da31193c64cce8e14c2288f693f60bda1dbe625803d1ba494d95525736d91e10cde53ecf49b6475612fda1d1fa9da7e3c4cdd2c1f8f04393636ab13c5d392de94de05eccd0157cf4a109dea2dc3fc85d8b232f7e043e0351f0c1873e566c889b0aa2a1661f7b68e74cba7fb094af0461b81833ca6a7ce861bfa024a74eb93c341abe9276533af881874e2cb5778892d4537c68858f3b74662afc6b902f7a7eb3437f4274848855952a7cd4a1b5d2a264a6f0b8a9e220f8a0435f4a8952593b6638dfe6d00819b2e6a4abdb64b660e0430e9d4aea334245ccbf1163250e8d07eb11d3bf29965af8030ef7f18626c81c1e83e5e7b03e9202840f37b025e35cc65e8a79f0d18646c324219799f15d8cc00b2ec2b07bc1071bdacc1c454c57c1183e230c2ec8181f6b686499e72427e6ec99facff81a5fa437f7a1864654ff6810424c764ef691863e898a7af1a182867eb4c2568e9d64a4c5848f33343ba73a998e500b1f66687757e4f46f5a862e98e54a2b599317d506aef041864ee470f25f445c3ec6709c8c1fb46eec430c4df0cb3129b53ec2d0c6dc69498769e4030c6d5810ca2fb6cd44f95ff8f0429fa95af22b4ab0d4330a1f5d4833e814ceddbb0f2e3822478b1fb3de1ae1630b9d52b96c4105f9418b0e7df0a1855e26fa4ff4d53019b72c7c64a14fa56dc2fc471f58e89330d318445636b678c2c715bae416eb1b72966abc8b2e9c86185c7000cdf06185f64db589c81946fb8318868f2a74ad412d66f6d1905946808d021f5468c2b8e409b2a652aa58828f29f46b2a35695892cb3ad2d0b3314cc00593e0430a6dc50acd1a46ff1185de2d488d78da25cac60e121f50684d5a4b94d3d9fce44f6864189f7cda6304933ba1cba7a2673719cc74b609cd6ee6dc414499d0a4123a4da35f9f597e096d4e9ee2098f1e1ae62ba1ebd4377d25f249683be69057693284543948e84f5e720a494dcfb2e6089dcfc8edcac8d9f4334668bea4cfcaebc694a917a1f710e38928173ee28308cd9608d9a1fd4c87d287d08645bf6e99989a1a0ba15349f57b9c3783d0f7e5ac90dd0742632a47798d97d354f2833fa305211ff45b6eb224aa3de872ced54ecd1667c4833e78bcdc2bf9a12a2b3be824b75634d9491d741696f7627672d0e964c257f54270d069d5d894e3456ed0c58b1983c7cf6c9d6dd06b8a4d31872082b5a5066d858ca3dda5ca443b1af426ad4d37c6d8c70cdab1603a29f9116263fb90417f4994ce913a985a1c0b0f5834ca4f6829bf98577442889988a482e7841c57746ae2b299a956089bb5a22b1dbc738c14ef59b3ace86228d5a3e62937c26315fd66feab4a113d43ee8cf05045a3a72792f87a523247450b1ea9e867bfd2820c42ea6c9924111ea8307fae5c9623ff893fe0718a2ee78ad9fe1e61c1c314fd88d251437896a63c96a2fd0f2a4b959aa6c52039840729ba58da3af2aae690aa1c45a74509cd6f667988a2b718476786e885a25dbda02df1a4e86b388d30aae0018aae528a61cef39fca2bfa443b5e2da32fe99e68dc73ee0ded1ff31761824727fa32b55cf13563a2ab9ce843d65b3f3586ee3d0a1e9be8b36c0acd1db4268ba9133c34d15fcc399c88b9db158432d17c90a364322d3ab94a010f4cf491b453cbfc7a09f64d3797e4105d4bf49d44469016749aec180db5ad445f32fc249d924d5f630c30ae0b0f4a3452d42fddd3f2259dd0505b810ab84824f098449fe7babad57292e84465d038597b57747ea5e01189ce430797131f1b4b6cce3c20d178e5d01ae272f8e0f188de7ac3e7cdf70d22766c0f1e8ee82da378f966deb7886944172c2f7c45bf90e48519d1f6c994a26eb78be8325382f80c29a2b31cc763e82ce22fc744349bb22c660a1344b4399a56c9a7cafd35b5048f43343a7f7c5664cea51e433441c8b5e0922cb6e5268cc5834721d0a3e43de90b642ef02044674a4555e8d03fc16310cc85696c4bb0b0229334f33767abd6f6603a33be40697532f010446b3986ce73994ad3f740342296506d1a93889539207a49415bea8c9c3f7422cdf3524e914408a31f9adc2133f89970cbbfe943db2352e6b7cbf3c4c987763367bb7dbe2f69687be83b04f352e14354d1e8a14999e4e5f0d4300d6e1e7a399d4a786874c7880f1363c26ed21dfa28f99212526432070f3bf4e5f1a2b45d5b729cebd08b5011d473ad4329131dfa7822cb76eafca1f19f43ab31e7f698e25c9624ecc2cf1711505bc19780bbf00678c8a1095bca53fe240e1e71e87775c73f5aca030ebd7a6e92b73821fe346fe862e7d893e22955b1440f3774b1621016fe5494cb590682471bdacc18fd2433e991612c0ff060439b93deb2b04957498bb935f4a7a192757691a0c4440c2278a8a151b2e2a1af52b3443f0d9d8e514325af9c152df7050abe4605b4d0a208c1030d5d07091f4fe4f8199a9042be3b6fcc4bf898a1f1109de31bf2a1235ce8e051864694bcb8c162e84186d6fb734cc1abaf37788ca1d7a41554d6982f6f38d7430cade55a72d9a062e86a30a0c50e3cc2d0c8881d2f31b344887c0dc1030ced6739f127d6ae6b418f2ff421f4e7acef1e3b688c2f6ae8d1c88087179a038da6a8249165f2582c1288c3a1300e82181cdb1e00731308001838260e8562d1783c0e85dd0714000556301c46322e121c201a101c188985c2703010088602815020140e8682c160402c54b220a90750ec386e472a6aabeafa50d23831aa616191d6e96e4d392166cd79a1a9a40e8e8344c9a1f2dd5e6c7d119fc22020c62de6e276372b0ce63a91a585b50d4d787b24ecf877cb990642baec91219bd774fa128ad2a874537d90b5410e0669a0d6a0b0217e9e3876b91ece1b4c139990918b3e5e1a01b9a30176f9818a5f13a10d9bac4bbf6ad60d0b3741bc302414abb0d3f734a484adac51beaddf44b2754a24a8fd7d5b112b4dcdacc42916c4fbfb854ad8eb265f97089da8b4c689b9517a29905b344e041faf922df3be6e4234f2f96330878d796cf6e58ab32d8fccb73d5bba1cc197dd2f8ccc6649f6e014ccd477a3de545076a759a8ea2149c159d35bc40da68d0a4be05be8862f1ce4a752a01fbf6d9f3224563a8d4b40c5c05b1375538ca85d5a1ba0c2715cab1da79e08d1a4f4c4cc882070f8c57e3a02b3880ef265d6a7256eaa83547112a8185e9758cf9632c75ef7e356a9efa579973b185cdc68027fbaf913c5d41297129074062173f4589aaa465058e647680af0bc213df906e358f227578bfbfddb810e066cdbcd7520165689b08a4d0a2f2d0deb36ea685b3a6882601d22684a95b4099f35b63b551089971472ec59827b485051a47ef47355d2a73ef3e44f9e213010ddc62e8f024038871a4a0eaefd42a62508c39615ddd6cd8f1a70f883f6603b3fa09f50db054e9fe44bd8044bf3c73de01eae0f8068754750d98adeb374485f1850ea0b8f58e2a55f45a80778e683d929a3aa7b4059911cae67d65f71b1fafa30152e1bf83c2f04a5d2fe6d5595f754b1cba67066b11c4157d267e82ee806fff0f40d10dce8d2dc57aedaf2ce713c9c0492e8d81a6da84431ae9d413a301b94c32e3dc7092d8af0f4276b1b21dc2d1cd42244fa05419240e47117c756d67a479dbb7ff45546b0d08b5849430698e28455eab30dc96591d87e8b25c362ec62d6992df4564e9ce7a4a01575de356f0e0e430232d85d4ef107f2b15bb0a567c7cdf39f9663b433d79448299e30905e2a6fe12aff088455e1ad3d8126ba6aa39d7a59a3ea2509af36a14d74a76927e33c851b2f92e5c3957e64c1d39df94bf82f5ac55bf90e6cf6474b3a6f6704a0df3fdc57fe3f17a1ea87bdc6dd98f312cdce8ecddf6a41bd5364d87638ee11c9b951bd8d2464253c77f703d1dc74660b646f2c40642ff97530bc25631aa7f00273d21b0e96a25a2eb060d36c7910ddb59d2795a8a47a08a1a43028fd6debeb0764a86fa39c8e049fa9e483ed358dd868416cc12b4b0d10fcd51e2a77c61ad4a6b719ab685498e335060cadb8b1542498c860b03a07019c77fd3f7c784eaf916f31c083b561c3c2a4d901033870bf80682f78de86f4ca393c20cca1711b85a8f2a3b2111648041ff451d98ff34d077168e52f29816d41873ec18ee2e5a81a2850e6984db40a1bf339ab220493ff82864da4dbc8e7cbe7a1dc5c25aa2fbda50914de7d7b14f3ed2b25f36703196d70b7b8e262c79509fca843317cf03771ade9b69d03852bebd9f6078e66fc2771bab3df922a0e451905fb2f216c8803e177746364c27a2d452796c6fbfdfe322a66ff4a59f9a6665ce6587761d3241b64531bf0e04a859955acada6dc0ec8adecf14291af4835a000f1b7dcaf5ffc36a105c12412ffe68dbb8b88bd2a082e9c68607fc7d8c21a93914ed7db738552c37a59369fcbb79ec350ba5b19dd4af8f6edfea5035aff8b750858bb1ef326be57c9973241f42cc742b9e6896d9621ccc057d61548fc1071a8fe8b34b7fade00264297f510c62974af217078293edcfe522d5bf6ba978525edb810ca04cb01ffc2032f28ac908f87e6d4336cec40bb2c5e4fda21c1eb6fc1c36bcfc1e01ac1df6be789df73a5e09958940f4c97cddd7ac0455f17380cd7936e7cfca3837c7f1c3684f9cbd03e838a9228a59cb7dcf04a877eee97dce6fa71f8511d167689b484283626a99c617d2114aaacc90eeb4f0016c93942bc345e10cdb47cedc2376d4aedf15ebba71b2d14fe7f99aaa2430da088902694bbd0951b6bf5c8f23df10b74db639f61d46b1e2e4d6eed3f790eec3b3d92cdb6b5b01962a573a186146c873bce48a1670ac6c5b1b3d0b5e5fbc361506b36a80682a2156e278f98a9d0910a39a8d08d053afa8af0ab638ec682017a0062a4cc22ed4ecbc459f37b4a8549cf5aaf5845d29fe0b5785e096ee9cb8f83a786dceb30506a8692bb1f95a4f588ce7031502d0c89bf1b7ff992cdcb25c8eb3ba408904ebdb80decdab18c8d071138b954cdabaf99feed19685dc186153443161d92da43072ebf543b0ac17cff3fbc003e36ebf9e99af77c15a124f1666c789a65c4ea43861dacb7ff85bfe43ff9ff8dcfae1bc8ab80c942fdb5a9aef0b20c14ce6c8e39e0ac07f9c23abe0aa9aa7496b8f70efb3541c4a4e70d143b14e1345f156706b6047f94770a77ee9bd2deddf14f3c994c30b6be5928970a60fbecc07517a872443bc14fff7ccfdf4105cc7acd6cfba5ffa5a5f6d496de63d839e876ec23215a8d57b74a4a1f770740fa09094d200b4ecf89446af7c0fc96bf8a9d71b1de1f3c6e6433453c1c34981a87678b54604b1a373601cf6043e42278f8ab60582c1406a8b488a86b83793af5ca3494378c28e206eeed07bc5b70126d1b9447382b1e5b0b396167c5c323f6eca56b41b668ef381c58e97d8ac3772fcbe1db9f118fe15ae4220836434b3f46ba439b4ca85670f9a6797ab0246afd37a728b6ff8ddd2294584a79b6c691ec2a16f7c469bde28aa39579e1107b2408a86912315ac2066ca534e0e68e1e63df2f1b0713a43ede41e440aa8e4d5f64a724fcc470168dede661909d541c5122b40f828a5a68710f6dd543f7e279c1b4a281b3d62910558f577133cfc85a1c184d1d4834a41af039e5f318ca0471c34f65bf265e525be65fc641409780dfaad4a063c3d353c073f3801532be65009a217320a333fc17d02f38c47968c152fce5d9f8269d1c2dedbaf83521e28f54746894195b0bc1eb8954a3beb5f84bac90d6cc9a2a9b7ae18316e4f1ce82680823fdde5e8fd9a6cafa32bc5129919187e26111ab2480d60024780ad25af9a5134b368c1041f83e2319c69d4b1cb37d22c825fbeeadf561c541372c213faaf453cbee5a42a9d1786c8109dac898c459bfe62070c85fcc9b48960a134b90b9ef486ea9261063c1f410422c0408123a1b442b85e881cce45a049610641020a5dd91071504280853ab89c04e95cbe784618ad60849486e47b2046c8aa5f98014c45625558427f69042ab94084c2945b742ef538e746b095a99a2eac9622478f56ed852fc2428c0218464307d64ab69ac215c38c018025bc7956a43bca3f250da735d445f27de227916a31243bb949030819b0b10ca18a62b685772623b8762db36318667ca09d17e82f7f4107bb9d51fadbe2940fb1f2a9592afafa7bef390338e0e9e84b7ff5499d60a13dcd043211c328342acb138729bc8ac0861e9be0431c5c331a8a81597a49970b93a9d37214bd2cdb083c49fc71842bcf3da8dfb6c1877ac4bd6f92af45fbecef336691fbce7c2ae7447711bcb5245c4a0879a39022753abb10ff452144b38d1cc27501ac35c75615237912007f3b0420351a898a46c2d32cb2f09c914987750ab412334071895892786c93a082a3ea0a871f84b2aa7ea093b57dbb12b53b4865c310bc67fa80f75adc647894763b9639c280652608a1e5e35e467cd86d590e7358cb9c2f143580af6659e0803bb10aabf9f91ba74b73af4917c3b3551ea6fca084404a0247b12610b8729d92b07aec348db78b00a04a96fbe72e47206c2884b6024f5aac9effc0508e6fa91c48d9d004690184202ab72228d4bbb3e256c54c21f1a8da119b4183b422e268af373a9e011037ec56dfe239b12e181b39b4fc7a8493373fb68f6e9a5748ee8df4c5784587f6ecc84bb5bf31c3a7be367687e93060f22e18222d22e69c7240d3b8e1e80fd7f9a92c1a49b9552624a2091fedd614aff7af6ad02de3aba81cf088bc3e2e56cb48f60ea4abb78c848020cea4ad6cda683922a5e4b4428978bb11e11412e852670a1bb6f5a6b4a6a8ca01b0868cda4a1209f2207116073ae7aff78a1f7c1c92a804082c3723a1ba94fd1357093d742ef458490deb2a02705fdf58977f9201a8cacab9cfc5a40892952266229620e8fb671749468d3509d084e72b39ae33e3e97fa7044e500286367603345ab0613c30183821143fa546c67c98d75c95731f6e02917c62ec9bc93885721e96ca2b0b3e684c3328b6e3743c14e6396f1c598591760c886c978ff410b4f8319ee52b26711a950848bc8cc6b2485a5dd6db421baf58cf409e2d93064056e1d3dc35b89b037f9be5660293e88fa5183430c16d967f809b421e183985842769d0e9ff6e8d26724f009aba063b57157cdc82e57a42d99ac1e423283e7c81e7d983622acc34cdd9a315c6b889e465684b2cc9fa48c8cda646abbc1c563e1de6f2b72e3ee57e56393a627768c945f1a6162f29122ae3560d26f10bfa721760c1e8641f1c0b42ca7ae6ed04d600dd9b9889661e10e9be6e0fde9be0ac4942aa60d80e5a47f5fb04b1ac61305360c73eed7953e54f39106e564886f6e0ce9682ab224cda9a302047b83bbdd9205b7eec0ae5f2e8ccffa5cc5422b69449408da3870fb81ff94564239de6df6fee3e9ca05c4cfee87ecf9655c4dcf8c8036ed32157be99281f0374e71d2dfd6fe2cd62ebc6762a30a8ed697727ee0818e1672ca59d077a8980ecd6df160de88b92701f36165634aa18986c63f5191b83d2309602038386f3325e92028d760003d318688f0dbbe78d7d1f1c91a02ee8670af2d20cc3711c14acd75acd641f7d6a37e217784ba4ef31a8d185b6c6c16169b54b7e6504d76151a980a69af9ae183a1e83f47f1e0a2ac5debc23673a266360851407d2545002f7555e4e340015d5eabf8ec519be47c7bae9d3094f17d1648b891c08f832b251671c667584c794852a588a4989f6e703924f4eeaa871361228458832ad1aebdc821834cc213b5a751f95936a78051294e922d4a9f5018df50e3989982581a2053eb9457a9b40ad525cb79566e2ce91e8c4c00595aa473f5969b7b407ec27dbdd73e449a64c23e2142750df5affa950f1782f451d390e7499281146f6689699f099cdb7e5faaa5728962d6649b28beac8466067e91403878772869a788ce28f560d5f187b321ae653507c0e6044c3b8678d093ad775cc1c30f8cdd772b1c4d6f3e3423cb6d1793c8c4e0f00c7bb15c09d31104f8424bfc4196f4ab2a5113e93cacfd01521fc0bd5c228927df9806442cc205c380d864379b7ecb3bb4d77a61edcb84d85c745540c676c56ed57cf21f5775066014a08a5d9d7f234be218b6d7ee017145e32fe685a161a214ca4631e28a6067f3549217171c48506c8dee31909e8e54ab7789e4e8827d50593f3916b9e23b766c65295b0e503914e7a185f05cd3682d61a7b1869cbdbcc056206cd87037490e2db8cc3fdf64ff90113e1d9a16ce503c21b27008407266a143feaa32193be781b043762e2cab94e487016c2506752fe9ee745d0867321fdbde50c0f56dc9a0ce4d49c18f34c98770ab8c06a541945327576bd12ed3663bc36af068c6c8d48f71eec939d7f6e9ab1b8a308e642826d964ae5d27abbfb93758118851213de837e0e36b296138a101a804b2940b05e1251edbb5165216c766f550b915d988b1e6f21c107d8f46d8d7c055740f60d7f463b3e9bfe0b197e89a339e0114e698cbfb1f3a9545f1d801c6374e292c12fa55a31c03e94855078134817c4bd90332f52fd198d08abd46a82b4428d9a7cb4ca244043129f601b8ee896836f9445c565255624a77361e268937cd7a6022e0bbcb4caff85ad8a82327e4503bd368ccacb46b92a2a97ecc06764934b435318cee234ae39d256b5e9039ac8890e1c20c33dfd3a5dbd80aa5b81b01af2c8a17b8a60e7a0d2ba007f0b4c35c946738918cae775183b36b542649f083a563491d092224afbc2589eaf88c745f2e91c9842012ba917024798e4496961868721f099e2a51754e1abb880faa74930c7139a68c10723c6daba71e005982442da755f2506478bce35f5a90e4e54ccf7b2ceab18be831a986cdf1f6e8b1bd07a17c50c7434e7a0ef299f790d36d1227c49364058bef719c42063aa5ab87de3c58f5c0e5418ec7fd3d74f570c6e3d8fdb11de7b83a6054102f1ecceb8326430a30e47b0339fd262dbe1e0d3989ba3cc64dc4e3743d40aa6b87420709b8c06ac89ddb2851730bd6b466182f06e1803c1c5cadf4568bb183acf24580c28c7d04a95b78e99d3233670071a5e248b1caa70e5addaff92e3b3f3a24234034dfe19525669361f544ebb0e71362a03594d2ddf0d5c58ce966d46d462f5c50deb074d9adcb6ed0713a2a061a9227768616a06e1b79cf30114677858eac01f172056b70eae2dbf1b6f3a128c2658719c344a3354192642d6596ec8ac2495219e08815f5c929b83bab853fb942f04e6e19464fa154213c4be41ae2e0b3fdb3b8df4e2202cca11a605360ea20289106ae11080c340ce2bef8a9b8030ba624fcddbc92bf03ee1264193a41a98b07b90e30c2089a37ca68a20fc31431b316cc35c02261f7a3a14921530b5dfdfec568e5e66155e177b15ca4647aaca803d8739417546000472eb8914ccb559d80d71899f27e83f8891d5a51b4f89e0e8e46056880fb4aa482585cee629f764de49c9ac013e98ac3734528aace492ea7d255317260d100bff2912b329b284b7da01330e6263d76feee41fecedcf21408614b55ba770ee4513971ace73f7adcbbfe89c5af5cfeb180e33a328a1b16279b8bf9a815f154f0d8420ba6b057c93783fae1778cd40d221751fb50b1c41e448b5f405d03006a80b9016010519725d5442aef34c3cd77654f31e9aa32d6c16e938d9a7ff95c73af321feca56dca8095cc6784b28ab529c7bbf24859f9bd4ae1798a86df17111056d4296c124fa60156c2a652657503a9ff492b5866a704931450a17566418f4bdf104714f298a5c2d23a89814476a99a7449da20f17c22880225a1263194e649aa94ac4a7b12fe44ca73ac901883a4c89da65de1a1d8dff4974f3396424dbf4df58f64150e2a6cdd63b11a572aa2a73fecbbd066587afe742d7d5470eb972b06d4fc4fd7ae70a0f86e0194403aa1a71e6f12cbca82d4d51666131f5f05291b0f6aa5c5ac890c8afa27a85d056c390fac084205789c8c4a3656fb360e0dac166a915d948884542aa91851cc9af497be02395427b2427a3cc90e85fa8ffb301a95a77e50e95f0e64c9c4cb94f4ab3f4e716ba82a7581f7803f682d0146013894520fcf074b823cd2ac0eaffb8a55be934cb814e079864a0b411578e5a98efcb81c062ded932885396782a18b8cd0c429985dcc1b6ef2ff02172ac4c8758d6fa8dfddc7cb9c387508417f58c633730f5d25f03288c177f0cad94c8bfc0b6c31fcd910e610cec69f40f3574c7ae61dd11daed9cc48ccb8bc39ca8f3840173b40586be07f9b99b2f11b14f4a1c030f28634997f0c666a7c08b7475c406ffc708430d43d12722fd0e76440fdc1fb1d2e3db170e445ae08da3a398240d404c279876257285a99469448d4514863280a2587a25939d437486d9a2ae8d10ab06a277e3bb7b2582dec850e811846254b4995b62a4491be3f036accbe57c6afc60ca607e66d019917fc315866314e8b11e759d471f5687ad2ea5f5ae46513f79ac0697ae20e8dac531dc126131d82e36d4812ed0b1e526ff038ef0cbe33d5ac8967279494322077ba9df19802bdd80c9f22bf875c38a674516d91f5c464d75617e46fb4d37943afc799471489bf896ebcb09c27475416e8fcf697a7d57a04405825495d364ceb94a1acad6003269448b683a30f7ece280759c54a780325fc9038a82193090bd7702df524cb03b121baf6193299938e341f6f103c0a1038a5dd994643e0c84504d57760c46d5680b2a46176309f312310d162dd558cf0588d2475c458413cf0ab5bec01b2038ed18eb64579598d3131d8f2b16cc70838f4d1d3748c407ecdc3500b0e21cf4ec73ca7c77e610728098cc804d97795d2da905be09a1781f33ae1eafbda39ec337d967f101335447e941c0a40225743cb03d698ec6c9735ee55e4ccd9b50e86f577b096b31fc92a1da2f6fcf329a5cf1c77f62135c2cc69e71b3f7bb2f0553fb1e39c9d7dc399f29a0141a4337f4ad05e5fe1fc70487746ccf9ad6a9a1401732de0699315192fcf3b22e4c28d8a1a076078e2c8048792a05efd7a9286c7dd01d6818f9dc8dc2f326e065e288b48382cbdf5958dbffe7a69b4ba10c9da59c30eee5be2899dc46e16285cd66a882f31c82ad9d68560b4de412abe808618e6c09848dd9315f2a4bf305c0caa1801bd9af4d0555daec46ec0fe0914cc9e97d6d1fe482dee9483e721f2ed98a8663c00a896d4f48fa1fe385777eef90dd94a92a8aea8959a2d8d625f218cc36518e530a28610c0b8b36739f2d5c3902fc76f369f436a809d24f76b434eb04b64f11b1f9b58a549b962f5c5079ccb7307d47e4e29d5823feea5284802fa1c9f6dac5b8034f611703263a80dfdd16d6b3f2708037edcb18906697b6d6c4419c23e5c325cd7e0d6d85924370bfa3aa1f0ba2d7c2ed4f4e268a74ead5401e9007a3b6d541af48dda45da5f311ebfb84fe36d170079e671caae6de67e3d3c3a9a12f639f35e3a1ab573a71e2f381da5a3d070eb402a51a30c94f35de10cde1aae56d792e79f4864d44cc87a1200101f506805896f05ee80b5894992f1df3e9a244aa9690bb37e249a8bf61925f86d48751dfa08859f946a2a434b62b247542b31c9ee79c8997107ba070ffc448d4c75fb654263d5c1c5d48bea7ba98dfa0b8894abdaf81119b9a81c54bb90801aadb348d07a4254de36c7036c843a11fb3debd84e8b1f7ef0a4898a59317fc7190a22f82efed3ff97f7b9d78af6253dc172e902e6faf9aa0bb99c0449130ba1ba907cdf74d7403cd5941e0c621c14e62c54e95ebe488ea7ef7501ae0832e5f1b96054f3d4e913e4bc538186662eda8a09028acf3aaae205cb2d3f6afeaf71312974b630f01122e8b4bce79b6c46947613ce93e869fe33d87f72440a03645c70b86ea46fa1084f785a44c88f173da83bb4fece5d341e2f9a3a7ff71058f13508efb1ddc1eb9477ecb2d7d9b0a3a501b776fab7f62481626b1af45b4f6362d20e6827a80157d96d1cdb038a61064727d7ee8895db29b008aae6d83447ab2539ae02111d0b1089e8002f54a1a752a79ed606aacf40a08b885054c9edc592ad3aa0ce857dc48f7019992d604754d53c403b1e5afb2428161790b712f63c4f9b54d3e25c02a9c11d3e46dc614d63dc8b830f1f071b929e18d706f06142308ec6aab9b0862146605546269c31594ef92d1eff5ad258d210d92b7deb1c066540f7330fdc12f2bb8c9094d7f8870487147d96f10c901d4baf7e902e1d4d7603b8fb5e9dc228af3e73ddbe0f25650554d2a73aa2f3042b6a5a10f37cf321babeb46f4a68738bd7c17c78cfd67d6df08565842f1d4b7851b8a94403f8cf02a1554f21331bb92df5a2f8cf85e57e11b28a527b87994fb77e31d13d8721d2e5eeed34d77bf2dedc2e4dfdf74f99ea53b30a968edd04c735313dbf7f953ee44375b792f6fe24a860d13e5063bf10ae20a1324f823461c80daf9e56936c7b47a21f9ac0625de469feaca073d0a58cf419178c70ab5ae866867ae03f215024f9c22dc7e7220a56b91aabaa46848b9d9115c1135cec0084819b24b669fe633857e0501497166b8391e0321c0de4bd58b8e8660d179f7a2b69b1b7d2dcc8c0a93aa200fa08c1e9a94437cae0547f426c3f40bc86be1b72f5f42b603d628b95d39ec2a01e1af02009caee4f78fa4c8b68c13418bc216bdea02fefa41d740c19baf3087b96f79237edd2c2824a01a1c5b8715a2c9dd4b46a7e960c0194ff29d323f8fa63fcbe963084f480af51123a78a54b5f63c1fdc03722f804fd349fe3fae93ffd69985b5b0e6d8d24fc6342d927f67fda830f4d8211aa7546ec649be996c5f7c65608104a5bda31c2eb3cc49b083c66454e40e0794fc788cdf1445cae2ad717aa865f893cdcf0e1c3750d0876c2d00ceb64feee7e628a3cb23c4bc68823a103a6e71a0eeb49bd37be4e27b4d8cace7cfaadbec30e4bcfb4e5f14e63c77aa890a80d31b443bdfdf0cb22fbdb2dfa6be06d64c705b5f0c48bd713147d34a6de0d6029097efe6abdddbc86ef410157dc5d209658d9fbfc7ea5c8815603013a82e0f4a05669f6de31c03859758447b28b846d83952e9c1aface06fd0767886f5246ec7705bb0b93b140673c963e2d95cdda911ea4f46845b56c143488df76c4bbb89329521831e49d450143efc52b94625e0aa96ddd7f4a43c88616a66be8cc0a870d6f5eff9b27e95e0a00bbb212d15f6f566f2b8a4a676cd3bdb6a10cd7c04e069b262cd0bd8a69b5d08ba11e5857990485144b0f8f1f806735d900278e94ca363b0e9264140ad177230cc8a185cf62a457cc9bfe9820cd75a8e855c2dec5e3c2b567e0087d71e830e21f5ae65b7496e53c5cb06cc311f4a20c09b2771384159f34e603d6634913f15f898febba299d84988730b2bfd004d2c1de574a8bcb359cad78422b19ba5eea528095fefcfb99aeb93daf598b0f22111ff58e72ce5919652c0335e838142554833c2ff3a8c85241f5f6de7f90e37a04d6de211062e5a856c6734009bda6fc67bb01d09db3582a2517233cfc15a7fd749c33dbd6c863ef7e051368f7787fc087c15e4422231a9c1c3441925d5936c62563dd64c1c92b3614bcfec534cddefa5e5966213559ec7ce9b2c81eccf6f7b4c58d49a84272f59e361e4b4d24b15307addac65d879e25df2a95b1b7db975ad5dfeca0dbc9f9b46ac74c2bec643dae93e51a3fbf1975a40def506ad397898e0b92a72a8e55af5b236d5e4247dadefc9e3668659a8e2490e9a1c62f70d8d10c28207518126ee4aa15c93dffa83519a39d0d02a99fcccdcb538af3c8c37ad9556a403649b0ff924e657798167423904f68b298fc7d64c342e6626683738e4a64f512eb86fb1b9a29ba1827d250d43217142aba17962664b8396c4a0376e3e44fd984a10151ea5dde63dd8bc5c95bf11b2dcb8177ab3065bf8ce270ff9fe11f56fc55e11c0a3a269241b2d950b99d4dcf8f50a307618c3c1922dd67ea2c6451a272a7b28f006c9ff6328725624d7817c0873c411a18b0d87bea27ed7663438b38ccec4b087b11b3f74a96b8d8a236b367bf590b8f22ad3ddecff1e9d44c281220346ea2f0e25e0796343697f14b5598b0096781d873d3c438ed49f7b481a7853746141055997a5e24b41f1926914a1463640a5a4d9c57905135d49afd341cace552a740622cb2a82f84a8355f3d154ca930014f1f63f8aba8809e8225251883a53ad52f2ad98423801f3e58f12da67ab2f80c5c600aec6123aa9359c033e4677ac11e0ac3e379a76e80fd930c2895a10b82f5106f75b31ce035db43925b5ea2ac68078006d6e33918f09752a75323820187d0603653ab211c53a4b2e5f96e44af8ecbe657cbb49637a922e2a37f57b1c01caf42ef2bbd5999323639bc786ecc2b80384bdb0bdb4d5fa2f272cb5bdba4121aa94ad6d2af4ae48edb55599731c79a467daa8d89c4996018833bec627a05fb6e9e2576a7351065e84b0c1310698dfb18266890b89815c798362baada62911422a310c11fe0a5f2cd7b5b931b05f88f6a9dcc028e5743c92093103ec2d21851d761d6aa0ba3839a10833c14875fb5085db2d7f8b7d552b7dd5b99b8c3dd101bb72f0d35fa451f3856b08425c7c637f9661a5265f6b577ebf59a6075b4020b0d2e10161580c39aad306d083860d8d53825815d0254ca455ab7364908ce9e1b50e63098ef0803ab032650d8e198d8fc53e93a1a5a5fe1fc4c46b6ed1442650d952f5ee5aa8ba937ec45858d55ae1ceff44ea351c9919516ac0a5dadb20d2abaf60764bb8633a292558fbc46e9119676ddeadd256e478e0214688145094d41792de5d8cb4153cbb36ffe70c2a06daa4a840bcdff51d55462a5b5bd961339ad82ae368a25ac6cc54bc146dfbb44aa408a2de3e5b837cf688a283b21751b0fb15f4a6d6e1d3148ace6876ec82e34b5baf19920c5f521970131cbd9284dc0ef080b9449b9410706649ec5a6c73a87a3b4a3628ccc8d23ba346612af38bfb5cb1fdc47ec8f43859beb9bebd742fa1ac0faf79552e47c0a3ec7a3773da1a1f43362d7ef59895fd9accaab5116f346e3d0d98c0afbd0297c96100e086888cc0ef9fa31711bc59629e4f2317af42357bf97d5b500f530738871bbcfc130713ac1bbcb43f4dce650e05e0ee6419a8b3227804e106dd388262a5eb1f101dedfc08e36719f0d941b9f64924ff40f63d834b0db8d16ccdf833577246a38ffcf0eccb337f4875a4eb819314f77783ee8a8e23da71c927a6386c9d064539c3261a163c527bd2522993d9e4a365cb3f8b7fa64696f7ab1242c4d4f1ec14f595e8597d134841a362cf8e04fc6def6fee0ae626fb44eb399ee45ea6532ce896211a0a1faed716531dbcde3c98c332785a3946cb39705bca5a962f862395d5839694b82d5c19f814cb6abc15bfc3a91bfba51b80daed8d57f48c2af2cae346032a1e5ba000c555c86ab446cbc3c343c30b0ef8b4c953f8cdc5718374ea74b9b62c5fd0e017fd23c1b23c531aff13ff2f90750e8dbe2cc8fbfa71073520f0c175bb2a5a194e46127d9f359e4aa4b973ec64c4486aee98c96cb5e3808e4078c8674dc5001501e92acd3ebd7921eed3907ec5d01a62b3e916d440a3f582a1db28a068d87bda80a29f2ba147512755bf706e0e80c9b4a421bb91b6146fba20100debd239486a15096446c15a7f004c57db9a7dc83c296148ca24a2300bbd96473a6f07f9f3c6998879f7db18030bb6c7119a66a0d10d016f0e5b182c10894b91343598052bb665e9f22b84f990d5c1a619a8b895df11c15c6dfd51b099f95edd47d87a46d26ad350a4506637f146a8ade715003aa86271cf016af97b1ab0a27ee3b8b533beb1e6d33ddb21aa377d80ca536d3cad13de0c9db42fa8add3ea1846e0767c220165827ce3722149a0596e7a8abeb66d3c607ccb093841ac836d86766f14ddb1a5f39b139a558cc6923ede80044856ae413746209b78d92f3d188449c61563358c4e08499f1e89c1f8f2dc9d8a8d0cb792e20ac3b331327a97ce4435adc93d83c35b5199f3115217eff80f7efa60d0b99c6974195a730cc1611482c741643fcc24f02cb8af1deba893da11c099e40b0f8421e47f4c1fb018752621b93855f7881fdc1d494524c4c85d4ca6d052deb526380732bc495b9f5a971689866f69085a1e215b728538f668c5c334a35fa498ad0a560a99bed1f7faba6bc2ef60a1006687e34dc527a6dcf96a494f12fa2b31d061bb39525f22a68e771ae06c5af3d982a25edbb6bb5c71c5eb6480a830d2665f5661e81df31091f0b5db55fb7cd88388983499b7c6fea22861aec29b349a2960014778bff94a95b55928f66b360fd1769e09a2462c18c9fd270aac8e0738c3343705bc4ab9ddff16243707b9415a4120209f4fb485835e1c32a34ffc214622839761c6b31269e2d45274df063ea2ad8d946c634552dab13f6bec0e1fff4b026aced9a32b9fd975302db979cb391e225e138d6919cd67ee4934cb28736068e54d0aecd975cc440e5409b2f825f66ac87a9d42603585a186648e2f4f9918c8c5e703ccf636ae0686d1827a23055ba6fb5b73c36d2196ec3d16298d1884b433740d3646895c25a7ea4a9577c835dca19d88e4c453c4bd5306ccc794c89ca2a09cb84c23a23d0f6cc308dde34471c9fa018b39e41ceeb65133aa5a604a6af97c683676442419cdc961d3001ae2816f27fb4aeb9b5264d50039472fbe168d60c241b4634b34f3c2bf9195e5925009d34968c9d8558d9651c1c9aa0b1e5fa342eb6ba75b39112af205ebc115908c07b1cd88b82c08ddc5ef4c005122f47824de923ebbc7cd6abbb7570e1144a2a0e1928ca74d12c0f0f13b8fc21f6e3468fa7a9ceb7eca5f067abbd38f7cd1521ba6c83e7f6d6209dc46d6a8ad08615d17cfdb572d48f18160c9fade36a3506d31c9d3ab4702040471235d49e18d3f612f5fdd9cd036cc302fe59c4170b3460b25472ff000000000000000000c098d5946d51a5e9a624e402a80f858057a4ac8848b9093778cd3b7807efe01dbc832d460504390bf90a3c0b495ec7f13c5b42a25a30a71695c833bdfa51b360f41cd747be8ec3b35549002c18724a0cef9f90b38b7a05d3549af81244b58239cb05f578ede8efa982b14b522c7a5430b95f9e488ed76c3b5330a7648f24d9aeea722998a287a9193a12c78e82e9543aec473514ccedf9224dad85b2399f60debde853edb71b0f2718d3d3ca871dd6cf2fd90453f214a472c8293acd67692000138c6f919ff3e5079225b90453c7e77b93efbaf65782297f3a5965497b590a19418024183d8d5b78fa4830c7af152ec4fd0886d02a9f23cf8d60b0c88c96969036ef22983aa40e62caa58c9508e6f8ea6285b6698f780886100f9f24729c63f8ee000208c1a85f612e58dd447804c1a4399a123a403056f037c966d9425e7e60f2b07591a51adfaf0fcc217fba551792ff1e18b743c57f492edd260fcc3979ff63497660bc943c694142001d183e08f92484656d8a8400393085641f677abaf4142502e0c0a8bebb691621c00d4cae13ceee3d8a2f1721800d8c1d7f4708d767953eb5305da41016232f9d7d68619addaac91ea2d4f3b3c02d6461f02fd3b5900e46f2b13079dada894a291da4616172efaec9eee4b3f32bcc41df9e89a956ea0e5798e62cd9b4f5e5945b61d4d2cb7233d2972cac3077f2dcaa93ff0eb2ab30569f57fcfbf03c5215269b20293edde5eb3415e6387e5eb508d1b30515a68e72a8321f75ca71790a73c4fabbfcf9be9b98c2101e27f6f57176bb1406dd8e3e963c29ccd9638e887ed816a330470e3bda3c148549a33de7ae2f14a60b2613452e54c50d14c6d0ccb4b4147e8220c92677afef09e3c95c149b79f9d077c2e01e3e549670412bce0973b8fc2872ed5dc7de84e1b5ccf3634bdf7f68c294531fee5b454ddf4c18afb365c45131616c4f217a4729472fc9254cdef15896a8a3250c1f47ea5d1e2b610a36e99235d299659430ba755c792efac53e0943a4f0f92f9b8fb77492305aad870ee3e27e942e1286fe487b152f64b51f128acc64e9f4f9230c57b136dc7e3b3c8e3045e409ee7f37c2e8d166c8990723cc9d93dc7fc81d7d14da2dc214e6267faa993c63518439ba4ca4368b12d126c250fda15ff8e41de724224c71aaaa1a512bfa4398ece4d4e388863087b81c5369d25b14c22cb1d472cb5c7cca11c2e0a66f314e3b47e5d9208cbf9683a9becb6f9d09c228365f29baa3e8c03f65d8221086b1886f926b9d3f00616abdbda9911c86f90773aeccfcc9c1c5f1fc600ee257b454d607835cbb445dae9e330992cac4167c30f707cf8b1f1d6e93edc11c29e9a9ee63f2e47a3047e1953be7fb5fdb7930670fb6a39c113f79a7dbb0051e4c1fd7fa546424eb90c28504f4015bdcc160214e9944db0ee61042ca952ccb52751dcc66af7dd1b3d773a68361f5c38e3dc77330476fa313cfe5fee3908321c7fb78a392844e471ccc1d7b050ec6ba0b36361dead2bec158592a1f7f965b59dd60ca3904cb716cae69d8065399b47c7b8e193a1b8ce9336e5241fa33aa3518f7f4762b470d46cbff1c44928c3cf93418e4aa24564a231accf1f6747cf73398ca3fb263c5f3a86306739c3d2c4931bdc316653054e538e510f1f66793c16ce11f2b4cbac8378fc164391ecbe3436e3b6705b785184c216946927784c114d5ba237e98bfbe6c74d8020c0693c8aa74f70be6ec39ad7e687ac1f051ae52f3bb60705dc921b992336cc105aa2db660b4f071143a9248f9205a30c7510af1382f0be6fad877e663c114428fa78997cf17bb82d1caf36c07e9e85159618b2a18a524dde78a4d0f2a98627f9ef7587e1042f482a30b1a35c2e0a2055b5d1c615c5d608b29983a2d89fea7764f5e19cbc0165230e9770ec43feb778790ffa2020358c000beb07183015e5460000b18000464c89021e3bb602e4ce0c50a4e148cf3293cc4e6a582b7a40b5b40c1e061648b1dfe22ed07edb4b0c51362b08513cc71b494e9f1b209a68faaffd22bbe8794230c5b30c1641176eb83fae86205c7799fc2164b30a5d78966569f27156f610b2518d5264775093d09c7122e1d5fcecff3c15fd8020906b7dce61237fe2687d4d0a2f161ace08be783778b23e0164668f5d22fece5300b5b146171cb213ee272d406a0010710620b2298c6bf83b5101de70e72c2f0e2c300830b30bcb0d15e4020095b0c810f72847f095b08c1d8b29f3a4831e27b8e83c2164130845c28eb91ec41ee3811b6008241f4a3c71e22a8876b61c16317071729b0e1c50bbab06181ff06ac81d1802d7e90cf4618f71ce56ce103532e6b29bbc9d9256e41d8a207e68deb20625677fad82e40d88207468fe3f073d4d212f5293dd86207e6c8a3f0dcf519bb1cfb600b1df456793d871a72da29ed850d2f2a115be4e08ca83877b7c0c1163cbc8bebff28de4e6c71833b3dcf637bedeb0edec206a87cac4b926389752d901c99e67b103f8d69719a6019b29f6265167f7d9aef70ac7d95851e8844980db7e9b762d1c71bfee993443a0a2ceef99734dd9b2ed9739688f18a27c97c36afc8514dc8ce10c31584b41b31625cc444a7156787a8b86e072be838fe0829fce4f0744118b90a2a66b4f5aaa788aaf073f6b493c8b9e0a5025f978e5b2dbe24c941c5371f7a36a5f724e753289652557c5d7d1453bc17c97d3bb090214629f6f9702a3b342c5d52d0da7160f9be448c5190b324044b9ba81ea2289ac6c6e408c5f17e781d821030c1a18030c0e0a20b2c33c4004591cfa3f0f2b9fe937b8f88f1892c566ee5d4a3b36b952186275ebffc09ee91952648c4e844151e3b45ca3e5e2d12313841d6ddd9fb78e6e64d3c6baf9ebe42469489261ab5949649f51f57993032b363ff52f7ac9848774cc4729c4b98f7a6f4e3b4d812ead427ab88ee215e09a2c40b1f84e5a051a48841893b6e7a0a9e1ed60e22c6241af9b8d24935e4639504af1bf7a972d26d2691306e5df2e0eb3a9d4ba79f05a586189038942cc95348d80d1ff1e55cefde71a84b9f23f81c215de769a68b84188d38c7510e92e3b0ae3a8c60c205e9e0928a5b16615a671b97a022cca84a9de291dd4d2776d81e27c2e01dedc30f7e1271af14d8b8d1802ec44084213d8ea27df2bab00f740f428c4398f2c7f1357e62734c8c610872b023fec1c6c506310a61ac7871ba3b96da44b7c42084714e3eec9ed864cd8e1c84c93b274f79278f87d986114310669b8e363c47a417b704c230d926c16ec2b6e3d82e6cfc0d05445b29f97ecc3e738f72c4f88329fe6d3f0832f77f0186175c5420861fc8113fe6e2cb27461f4cb93d2877a9b9460c3e9c9d7371ab3d18267cc4978f9b1eac9f5ced0862e4c1349f7dc26989a758a38fa6c28339be465eec2cbd1c79773069a5f839a4761cf964566807b3f4f5a4d78e915120461dccb11fd54e7d48fa1a113a982ee8747ccad17a2c360793dc67c9dda15fd72487d6639bec0d1b5c601ccc95f4bc3d7cc7f695b5ba06c48083313652848c77f059d53718ff434f0e19953b4e5edc5841187f83861787460ac0385a10868d30ee1410c30d265bf370f696b315724c10a30da6ecd0a1ffec44ca4b712ffe461e5f64200c2e1480e6c5f105180f88c1064ff27ed9487684d30b2e6c58e00531d6f0d4bcbf7f2426710584918206c0e0052d70410c3598badfd7239329ab06a00107a4c1143472ce92474583a963d9b4bc547c7818e30c268dcbf6ee2fa0b9e8028c23410c339893b647e99f7797634f8c32940c03c420837962533fa7384b5b7d8c3198c385d4b18cd4623056eac0febdcb72f47261408c30d093e9361d421b030c6c94dcfd765fe85eaca1953588e1858dd105e3c21dc45c4e498bb185e3f373b1ed17701e03189021a36f68e16264c160fde551e7f1d6a5b586ee186260c134ed39525f89edaf1f85ae60ca418eccc3f48bfcfa5ac16254c11c4fde8f2a9dd3c85a16f05cdcd00052c114a62c59aa8fe4a5a618534024f476cc0a6693d730b848410c29ec9ef2256fbfcf3025b08209288001cfc50d0d6c1519c48882c78082d13edeeecb6515cc3a0610e7cb608897f3e3a43fd1bf4d3298e473ccf3ecf4bda96e30630ca693ce71d8b1b23b454ac1c10c319863fb4e57be130693dda889bb9de4e83cc060ae8abeab1c962f184c42655f4bd2a1730e2f1827769e4e1d077b92ad0d6674c17c2176f46817463f5433b860b2ea388c8ad0b7602c8fba1c68840833b460d6daaef22887ecd1e5c88229afccddd97eaef02158300769776aaaae17227805937a88a567f3cdb082219ee5884f7760216654c19436a6f2c707b9aa43501033a8602c3df5fe701f16a2650ac6a81017eefd713c340331430a861c4908fd81fd8c87c46146144cd9b36cf7e3efeb08ea0c28982accc22e5659434b04339e6014c9eaf97a632b29aea1559c60b41c767071cbefc3f5c68c2618527e0ff593759634da173398600e2687b4e913cb9f820777d1c571689413cc5882692d745acb1e77dfe76628a164e88c24cc4082e1c4e378d34143af30e308e66a95991c9d52c5fb6a689133c308a64ab3fc9a2c7f12db456246114ce3b169f97f882f920168c0011648c40c2218e268e4c95b1f42891943305a0829428ad50fac3f5012338460eac0232c9d981104b34ca9c4cf396fe7396b68bda06968e5c9600610cc9683a073f9ef8184687f60160d4f7aa3e92266f8c0dc711ea767a58898d1034378cae1722c9e2266f0c010f9eda179f5efe7750786d8a1fe29c2de47617288193a30577f102547e5c050792721aabf14dcf80c63060ecc51d6b162223fcaf560ccb881052430c306469509e99cb35343cb8b159ca940462d4ce9fa514efde40964d0c254f1f427ea429d5e9d0719b3305c4e99d2792be23f3c2b2490210b73db76d2f934378bd31d64c4c2d86e6a973dc751062ccc1e751ccce484f515a6d8a8b614cd3ac8dec5d1ef0517295030c87085a1e38f53a86b4fe31d5b4365b4c268e6db593cf0682ec038d86a0b325861ae28cb13a9a372105e19ab304c7bca1d56a4d3889e1a5a302813830c55185654a2ae471397acd7d0f2028ca3c617990a737798292968a586162a0ce5b1488ea867b1d50f858c5318274d0e2b64fb386ab5a630fcc7c5f071cbec3856186494c228973eda8c78ea511d5298a3dcd94356728cc2aa924c14c6f86cf9539a381466adbb1cbeae0285c9c2c2e688bb8f6fc7274cd9574c5e27f67ef784f9db43cdff8fd20973acdaf53957faf452e184f13df2502d7f30056014199b30777496ad9bfe41fc9a307f0e1ef677c6781c2513a68febf34be5fbad2d268c1de63d88be189b1f4d43c6254cd2b9c2c37fbb9f485ac27c7d49bc3a142b619eed18e99e2dfa3da1842942d9641246cb297cdc58f49fed2461f8f01ee4345bb3795924cca925e5384b7efc512f4898d2e3bdac7bf3c82492f108c36ccd95ec24c311c6358fe53efc3052b0310b321a61b624611eb4fb549c560623d0f7d8a2accbb190b108b357f88b1f5829431146f150de632b09d5eec948846132247a0e15958188c7fe2b5bfa8628e310e6d097a2e7f6c4bba840d128c2022bb49061887daba3560bbdce4146210c15dfa2030fc35f321b1c309341085390bcfc2562b993e90419833079059f903fab166408c26cba71339f1e739d0ce399068db3c3808c4098aa269be9cf7fc3c6175f94ca0084d1e3e4b5f89e5b848c3f9883e71ce7ee2865f8c19083079523afb3eae2f0820b13dc3826b0d907c37f59b66462b9cd8364f0c1e47156e914c1a33812eec13021f5616dd352f0482eda059f32f460ce1dedcb85856d6dee850d2e4a7140461e8c2b1397923eca56d1b5ec800c3c183b8e139f3e5fe6e7957107e374f03bdbef90610743e545c4d0dc0b651a59838c3a98d327eb841c78b75a44061d4c2355da390efa111e2f630ec63889f46178c8c1fcb97f54b2c4f6d14c461c4c79b267ad905d527c30f60132e060941e97c871f294cd426a68e51bccd3bfb16e39e560a708c8708329e6bbeee4fd6883d13d5be8ed20df7e2e185cdcb0d1051f6890c106a37dc6bfa5bcebc108038c722e630da61c4773ff9185d8e5b00c3598fbe3dcc1c769aa6d2784a08c341856d75f3b9e6029a686a501098471e359e0858d94830c3498feee63fa2297869d32ce60f4e47174c9afa67d4086190c12c383e9e05306d36f7eca7e8456eec96088eb28a47d0a0b790ca61c7ab4c82945ed8718cce75bf51fa47b5d1d0653de55a77e3af71c07180cd142656544a473ec17cc162fce5f4aecc3d40be6c9f591e3b2bc6c66174c1fe48bf97ab960dc8e2d983ec77d66a1d4b4afa30543487e168c6921d3276d2c18c2756d34dfb37bf0150cf1b2fc87ed68f66305739214274ac7510553c497fb38b73ae40a15cc1693a6927bd27e85c89882f14c353f64f76548c11c2a313cae6c3ad2be8c2898c3ccec38be7b4f1ee46540c1b4feb199ac764b84308d4fc87882d142eca495ee9d602c8f733f0a93cefe34c16cff5fc9d633a2e7996076eff65c8f3dfbe3976016cd9576d9cb15b7128cbfb3df1e73124cfe765f219dc7e13112ccb9720e739623987debd6ec423a6a690473189b92c8412f8279cefcb244e84430dbd47cb4581d543c1f82a94d23467ecfc9552e04e3fd66c7e6f484fc04c1609d7b1ecae54fec4906104c395927e1237a94e3fcc07c2be75ec9373dd207e6c0030b15297a74ae07c64ab9f915ef1e4ece03a3a6c7dcce1d3b30e89da79b6cd181397adce99e6b0e0c2339f8f051c9c681612375246597e31e3730e5c90e39bda465d8c01c9d526bf5d6b530b6deb430f54795132d751ca7ccc2fcc17efc1f6a779847168620d172b695b68f8d8529c79125c9c18785713a07d1d4c3fc0a634d5e54995859f5b22bcca9444ba7cb554ce55618d4b7b4a77527c713c20ae3441fa930ead3b955984ebf42b8bd760f535598e67ce3dfc3e754692a0c9b3fb1b3127e69820a73f493c2edcf851c484e61f6fa28c63afad8595398d45a721c6cc71eb7580a435ca98a36968314e6b01f7b0e2dae5b5f3c0a93b8e7dc56cea230e7c4f5a449db71421c0a837a740b2efe923a0714e69bbefcdfc1774a399f305545e7b5e0f184296fb59484be9fed3b61ca619d5396b42c7a4e9883f9283ab116e6c33761900b1d94e78ff352ae0973f5a5081fd599305dce13df225a7a0ec684c9524c979cf541bde312a7e41f6efc7558c220294cbbb6b784eaa884e953983191303bc1a58439fa3821d557b2f49193307e1c050f2356766012499854c27dbe6b0f257c91306f64d317fd0ed276903067eb87f74d0b0f628f30f9c78f9453e60873e4e71f1e3cc73d698421fd8ea7ed1861f8f012b9f4e0aad522cc95d633f75184394a845cdb750f3e1d893044f30a71443a1061a895ce716ea99a528f0087304577e93c5e663bb721cc7a1d4d8f648530eb74e471ec10c21cff477aa62231da1c8429ee3aa7ef485cb71484a13d36b34a92c33d2410c68f3f4bc6a47d460410e64995bce7c33b0bf10fe68fdd27a63a3f98c4a2aae558a454b73e9872da4e93d3c60783841046ae2ddf47d983e183cd5ee8ae1056e9c1f069e2e84af0d419953c98bf5b357f7cc2e267098007a3a478dc9ffda3aa7f097007a3fe05f9683aebf32f01ec609ed7df93cb2221894a803a98e3f83b4ff623c1723a9824e4a0c2caabe54fcfc16839dfdbf6450ea6b493ef903fbabcc7c114c2876ca9cfeceb8583f1e6f306737c713fee94fe5210c00de670971869c27c7bda60d68ee711125b27ad6c6892c7f16b30eea73bf71ed5608ab157f1f3360d8629a9d21b0f0da68b1f7a8a0a57f1d59ec110b32b49b3bd623a66304c9876d49d9741698b6e913f9a0cc64af10ae21f6330ef79fa143dda90481183293d9a7d14be72a3120643fcb7e50bab97f2e2040083c1a2cd99d5a85f30eb7fb4913ef2a05356bd60f0b760a9afa3325bb50b468baefa134644ff542e98e2b493c4c484bf44b76030c7a9fa0f7d7a3a238928271852b228d1e379770a6e13cc816aec79e49fb8b017130cf79a16526a42c77d2dc1683152e33d0aea361e02885282a9d358ac685c8af1619504b3c54fa1ad563fce7b6ed4088354a290600a4bcb3d194b1e414ad411cc6312cbbaf2c974878d60482e31c2c3a5c5c81e24aa0886f08fba6db299021b371ae05e70d1001932445144307b2441c672c87c3ef3c3b0c1011932720d3504a36709be5ad17639ee1082a1c3e4ed6d7f8360f675bd12fd38dcf71c100cee16bf83f3fc39320901f503d3e6071f8778faddeb7d609290fa9f731c6b47f5f6c090b331eaee761e9d583c30e6a84769970517503b30770ee22d5d2a51bd1c30b848004aa074608ecae72ce7df0e5a5e0abc30011704059503f3fb9c8f4974f8a3e0082303c745e1c03036a96e2698e430923730979bdec48d89bc9f05eac0a83241d9c0d87942b05fcb41b530e7be47a9420853261e440b53ae7ae8796d274ca559184ffd52f2bc33c9c25cea21215dbcd309140b83a6a499186d6d2d2e8d4a5818625afa0edd59bf8264000b18c0a7e0a0400664c8a05179a057985344a7cfaef482a65fac0005366c48205d618e362b3cf4b9ed5ac8817ca0569892c47964565773d1215618faf3855f8eeb2dc2a25518b2ed8ec712f25a5a23551853427a0e453a7cdc1fa5c23c35b13ea99af31d8c0a43e518aa91737d053a85f9a2ba1090294cdf973e8c1ffd961442a5305e8ebfabfd425ee71091c2d8ae8551bca05198fc2a664d7e94272ac78dffc2868ac2a02e3988f4101a5028cc417b904d35cf25ec07288c1ee7b0e3e439ab5fa04f985dc3d34e46aebeb92817c813068bec38c6428e4e18b4d2ee59a4fad4d1e584f9726d8b88acb409e3498894238d10a2676e77481366c9d973301dbe3c98b286561860acc06998c00b2e962913c62f9d94b303111366b124c1f4e2ae4c90037409d34692d5df71310a640943b8df5ff197ea1c5d953007ffee6a69b289c4094409e34dfcb8e6b52c4d050a3409e348e8ff1c6325d5a3650b2409f3fc7cb48458d2c0c2801100588122618c9437fcdd2d5aa7bdea090409738a337fb14225956a35b41e618e5a5feb3e9adcc44e0ec81146fdd0c7a27585c9351100d8801a610e3d451bc9b08ee6631a66046284d147d7e5c277a998498b304ca476fefca02d8728a294621f5243cbca079408b36e4b0e3b5fb0778f22820e610ef395d4c4262d7c28990319c21ceeef513a8fa35e290b61c8ca37a939e998e12142182cca7fcae6e791ff85ca40833069697a34a16e3c965c10e688316a93e621761805c29cdf96fde3b1c89c0c10860eb33edecfc37a747f3086b4f86db4bf84d47e30a975fa997f5697bd0fa60faea7fb64c73db6f9600a12d3efc1902ec13df04897e2133d9872ca397aa98a06ca83295b4578c7d68ec3ed82075394f4f76d359f78f51d0c954bae26690763fcabfecde76ccfb93a98b5de2a8795a31f9bbc407430f4a67ce8a0567f953e680ea608c9252efa5776ae1c0cda35971ee9e3af0b691ccc56d9935b479df348100ee6fefda05ee9c63d9a107a03933c1ab5df8675416e30a49e903bfc28525c09a161c3c986406d307cfce8b6ca75bf27ca06b3d9e7f8ace7301d44346cf81a4c39da7e9ba80f4605e3c6db700502a9c13011ed738e4d2687d260b4ebd9b89cbe180f743f68d8f0fc01a1c11c244ba5bae7166e1713f8777106730e76627ab2bc10611b5d48c0cc60ee388a8ea3a4c8efde6b6871e1822350198c9f27a5cfe929ec420e190cf3d9e14348e81c51aed1a5031a8329f85a85646ece8aa40b2e50402406f3e4d8dcb2488ec2c8594369786183aa8b2e56d0806f2fe24061307668698f36b235b42e0066203018d4c6d5dea36df38fe378405f30b748f2d0ee5144f1ce8d378109b8b811068d17dc08a31479c11042d6e32323471ec25d30ec55e867ddfe40ab5317003210174c21782cad8b30357d16b405730c198f746dece2fd1a5a5cf8dff8c214415a307a6487ae59ececf474109485523e3377b6b354681c1b34ec8bc482e123c9514b4a99466890aa0b045dc1b86ee1e3fd783eacfc8281ac608a2a7926a4e3cb7f175405d387e838b63a3331f9dc0b1bac06a282d13f8f8b47f5dfb58b1b61348d230c30a660baa096b7d7c2bc4aa886d649a178d9e1cbe760fe2a325014cc6a1fb78510b7671f47503007a296e2788a316b2e3dc14916732368759815c80986b3e41d87b50f2c5013ccd164957ddc9fa8d09860ae8e52f547f7414b30ebdcc5ced1c7f9b7626509a404a3d487a6e79c94404930c72e91a3655c47785006909060ca694bbd13d743d38eba33d011cc79bf3bae94a84cb3c7404630c67edcc17d799bceaa052a8229fda744c831725db0b2404430c7d9a93c8e52a12198a45afa3c924908e6b379f77d15d749a930b8b8d1823b2550104c61facbdf2db7e3acb9e815f8df5019326c090404538eb36529e4844e4e3b81bc7174b10213fc0ddd0dd00fcc3943c2e46446a38b2f52c0c5150084403e304ebb78fcf214a807a68f429c091f6ca7902b0f4c531fcbe37c25146807a68b9be51d5d987460f0f06ec6b3ec3fb75505ca81f143c27b78ce1a957429100ecc9d3c4827b1f2a59205c6d1c5026ebc05cc403730b78edb459eca0364039376dccf66b1db3e592a30a316a67c9e2fe5e02cd56a575a182e564ef73895a7c9c92c8cd9fbbb1fa28b245716861cb95f08b52a9344b458cc8085c1542c54d49f35b48c05335ef1e7b826d4f2e46c292bc20c5718ecdb420ab9225e3c0bfe462b8cbf923fc48dc759697871b4b1c278f92e8574ade7729219ab30eef58aa87a96c7bfd5d0a25285c1a3e9f5ec462c15476f9f545f2a21cc4085217885a41e824ee50e5f14669c62bbf83cb9ef363a630d2d53182ad75a77b41f9ffb430312184029cc512686a9458ccfe10c529845dca3db25f507d7868d1ba3307bf47c59ec43a4d5ee4595cd108539ec346b160e85c1bbe683c4ec7b10a51a5af86633406156c9619b4d4acdf884a9e311c99e4c2cccf0c4a71663425be7555298d1098384ab0f0d30b8e084397fea385744985e98b109f3999c6c5f49bae86205c72a4b1356ecb2e8551e924c2a444aad942af8c7295dca16c83bccc884693aca431fbd08f760c26c2fd1ed2935bd5b42332e619a141d6787de29d4796a681d6186250c16d6732813afa18546985109836ca9a48a170b0fc11a5a288719943044b9ff0f23679330de87e19103fb54d2510dadac0168c0013264a8618624cc1e63245cea5c95cc120943e8e710cda3089e3b88026640c2143f2ef2c57a26c5f511a61c55b0bfccabf095bf812581198e307baa509fa7340db4e0c040590b8e1b0b98d18852089752ba53610623d80ee4425c3a4f98b1883edd7ddf7f080127cc50c493e2f1b2c28c44182e96e7b9a7e6e5c8e306035a70dc902183063310614a396e73ad83df4ed17208b394b9c5e8f03006330c610e3eb4fc98a89c2a7d210c73a9f54cebc37489cef15d9419cc2084396de551fb951af3388328277ff1f3b35910e6145f2b7ff4396a68398de28319813085ef935fd9c83b3d01611e4f7561ab2347a1e3300733fe60d8a8ec683d6de3627e30c7c588719f392122d20783c9eadc440a9583af35b4de6db48d05bcdba040a12ac00c3edcf28c3d9843da79cfab1c5a0e827a30054f09d172c78f486b461e0cff73d66198a586da08c30b08e0c11c7ab9c7710a1121b504c18c3b983aac9063a4d4396ebb1dcc992775923bb80e5e0757b12b39e8603e89d0d5aa36d9213b0753c4ea0b963de7725e0e46c9e192912c84c68c38183d7cfa38dcf6e46fde0206c0810158400203a00008686460061cca8c3798fd42429e74f7cf699ee1063e9a9310e771ed35a30da69d7f30122b2b8d54434b6f0f33d8f089743c9798f38c3518236de24fba5f0dc68ffab5721c466c879c06f37b58d57144d674d0a2c164a9e641f4d0d1c2a4669cc1e4e9f34dbcce7efdb90e6698c1905a1e2e74b8172d0120a071807382b12c072d7ab237000303b82698c623564c3a3a9ff698600af9e71f1dec4efde5805b42991255615d5119c9dbbce3546127b78405a70443c6e5c6e7b0def134b34b825923072124448f438239e46b4fb48a8f1ce772057704e3bcaa86df87a838df9f114c6d39753e5de98ae0a4d073edec99e088604a9d3f08398ebf9e7e43307e8a0e1d21797cec92aae08420830b021e10b8a87dee51f0f9cbb91f9c0f4cfb3b937268a16fa91b07ae07a6d8816ce48f3fce1ef9450a7a4b703cb0dbc1962a92a418512c976b250b8f326c3bba713a306a47071d98256d2d079703f36705f9f05f4bb23e6787037387be1f9d9287f33fdf0d8c7912fb4ebb0c9c0d8c23ebd69e729ec8b56b61faa99cb56bc13b6f4c0b731cc761b330fcf489e7b46ec995928521bbe791a90fcd144f2c4c9fd5a3840e75e4dc020b436ea5aef8f6d8a5a2dd81bdc29c6dfdbeebd269c485d0c05c61d6eb099522841edde800d60a63664627bbac91aa6c5618e23c22e5bebcaf925761caf1f75a5ec897af8a2acc514893d8908da4b7a6c218fe5b15af23adb7890a733cc13a1649eb173d4e61b22c1e8794831ced4789290c6f23e5b186570ad386c78f9472470a43f08e733ef73874906c14e6bf8eb3b2924267bd44618ed4ccdd72750e62b15018cc3df4f408f1dbe310280cc1839fff9eb97c3157fb04a135c3baa324494472899c3ebf965ccd85e609739cd37cc4b4f868a61bb04e98f672aa3e304f1fb1a3140ce384219f449aafcaf238961cb04d98bde5c366e7a22f304d982bfbeec743f9579ae4179609b3852c9dbd8e364c985385fcd7396f1d471959609730c7bb64affd7b8a3a530004343e6096306dde9e5f05914d9510ab84ed651a9153d77b09b8e098c0aea00118184015188c1226c99e7235f737d9e39330c7da2fcbaefea91c25e1cd6ce7a4146eec348b84d135c4e28e7fdafe09244c21b5e3f45ab7dca1f808b378ad4ebcf4b83c9d39c2903a8e6f3d56eed27fa55137ac11a5c42a8976b5c84821faa92aecff1a5a7b238c2f82608c30b4fea7c8adba08f36b5b49da6e4fb192354598363e70d7b33fad8852db1e91c262883007398aecaed39b1d2275f7f8f78cb40feb8019c2581f4b9af170b74298a3891eac84f60961a8547a1da77c1065d30ed3ff5210e6f5993699348d2c1f23b04018cc738ccfd1e58bddd20061cc0ffb336352f607338284c830f5a8685ad153fc0539fdb2201ee607d3a73c39ea14d751bf5304eb83c1abf42a27755c128c0fe610b43775532edfd22fb8a10125d81e0c314ed3d3e7363d18dea223847413b63c7930c771f08e53d6120f061befa87adab98339ec09e2416d4dea388e1d4c1eea3bc5ab5ddaaf83218667c5b5a8b9e1d2c1d075e9ff92763469cec114f282e59b7230ab6795b9749d2c483e0ea61c7b7c747e3898f73bc8219efe06f34b99e428a4b81b0c3af3575d6b1bcc96bdbeaa1e76cbc90643f7e4e5d4d3db9ef91a8ce11f7eaeab90ce8f1a0c761de4b2e0a7c1fc3a971dce8c06b2dae3fa8fd233983dc85fdb6a159f3683a93b4e39858edb72342983d9653c7d54e397354206a3d8a76a93e8205cd763304a67b58f546a311873b4e63d66a8661f0673071d42881983c13caedfe16a55b68bf117ccafa2baea29f682b1ad62ffc8d7e7a647170c97334423480717cce5361f32553d295fb6608e2c92e51f450ba6c859e452d75cc7a364c154712a2eca7d48b3162c98f543e59492761c4b7f0543ee74207a177175b782397deef0a32fc3e3bb0ac6ec0b9e6b96438ef652c1f4a2174f5ee2071fef149e1c5968a560a834c9c1b78e48e46814ccf13d4523522f99af5030a5b06a6d1ffa047359c717795e7de2552798c23c3a8f4f22dc45b509a6cf08b17ad483ed3d99608e0f3ae894f3c30e3d720926aff496e2944a305fa5d0e53f2955c59260ce8ef6ee672a645e8904d364558ffb117142fe0806add8d1bf7860ddb911cc9fa7fe238f9fe32c17c1389ffbfe2e4a04b4f2c4896c12320473e5b434322142305c0e35f6a3e7ff0a49104cbb13daf253e8ec39020473e039d28f7beec8e23f3025c929e4263ece15f681c1d259258d8f1e98673d55229e86eb0479600ed2577e9e77600a9fa32a0b93dde3203a308a45eb943f96186ae5c0649e52e7aea96d48880363bd8bb9fba7f58e7203b3ae87753d9b0dccfd777596db5e3fb416a6f9b579bb8c8c28d2c2ecee9de27c6e16a610e52bf1dac9c2b06d967e2b6eb130c7c1d7a68795e338cb060b835a87d87e49d29db5579873ac62ad26952cfeae30eb579470eb358fe75618ff4227b7cf3fe40f5698c76276fcfc1da4b9d42acc17d623ca3a946e5baa3069e59e728f71de51a5c2a0f78178bed78f2407158650e11d9227ed10fe294c717624477b9bc2104267911cc78ba71486ab2cd13bf592742185d923071b7927aa511845429a7417bc42a5578a50a23059e750bcbc52d84a9708150a83c4fab72e9d58698f100a14860b9715359f3bec8f1e17ea13a6f5be8f9d6763ff2558284f1842ff79ca4c3f0f33e913aa13e699bf949053bc48284e98e320d84c969011111111efeeeeeeeeccccccccccaaaaaaaa8aaaace652000434042085da8449e6a38f23f7f0e2f5ac09f357fead68f72a13c6da34f90e22294c98837f7c6449df13d425a86494256c355095a0c49611bae4bfdc23845e9370247ecc2d4306312a942488ae78fbc9f7f5b48a84214fd6b71cf8bcdee80509f3458afb615979ce71af47983a791ca69fd582b6a11f28479823ee6457dd32e97eff467aa01a61a8dabdf0b8157f35308a11c68e14b9d62e3f947817515a508a304bcabb99933d0e391acf82038cab0d54220caddbe7f1b5e595cbf1376c74894221c21cc874aadeffc5cff94318352582e4929ca30a1bc26ca9911a5a36b60a61300bd1e1e15f4556534258271f1d6f3508c35c4c7d3c99a8fbd1305660e353c0451882305c4a1e8d57dcae453710868a7349dda3f9322f6d84610508e3a465f5af10724821eb42fde120b247c5f59a3668786183c6172bf08329ca638bea1c7b20d15243c3b0718346e142f5c11c87ba2129dbc495a93485e283695ece72daf0d4b2ef1e68507a307bc8d9e396fb2077b8d6d0e2e28b83300f86bbf0d1274ba778305b8a8dd189f62aadeb0e76304bba8971ad9f37afd6d0052ca00e26d17f0b4b316662ba557430cb847a88a2bd39a1e161bc09146b0ea614febb428e3a1d6ea95a283998a62fe59c53cc8a83a9d43b2d73be2f48c161dd53f98e3d272172a8376cb5a19e53eec38b2a3718d3426acfd9fc2778a822a2da602eab10f2295267c448b1c13c29d7d6b51e6b309d79f4edb97d8bd8a9516a306507afd4ea1f576930544e578df7aa1c47586830d55aa85e54a786960dc726d419ccdd213f76b0cbcbf999c12c72ba5d162f3f54190cfa913a9fc5cd62646b0f450673241693a320f93caefa5063307a10ba42ee4f1d68878bc1dcd17739f6dc764ab61e2a0ca654c96ffe3fb6b4456030e4897596d3d65dd4174c398a0739555a49177997174c3293aafda23b74c7c6a1ba60d40eff39c3a307a13e3814178c1f39cdcdc5f528c75c300daa2d9826eeee5eb6490d2d3068e027c098505a30bb9956f66d85fc49b54065c114a5a562562776deb861c3ce505830c7b3547793763fe51cf7c286a3d515888f3eec1829446a68d108c3868d1b250c6505f3efa795f8713c899cf34ec386df16aa0aa6ad9024e639ff5592555430fce5c4acbb58a82998efd268e7ca55234a0aa6d7b58f26d6768fad8aa828182a2287243139f92d85110505b3e77e91ef684a26d74f301e8f34a8c47086226128128803c2380ac22034730f73130000000c1a91c742c158341c4bb2ea0314800457281c48382e14201c1c14221e8906a2502014088603816020000a0642a160901ccf731ed50053456744eecb71fdfe283c69334f00b71b1efc7be8fa4c361d6e4621451e02331d47eaef91c860c022b7775379f0d4087f37bc3a929f0691469de313f9773f095580ab2d4ea20c0a50417a7acaa58403b9ea9710c7e058bf383c5c7180d0045c3434b820ba42ba79d500a333ad52750175e7233d477a671ec8e7411a2db6f53204991a5825890458bf07d2b7ae2a6ba1a39a21065efc45d5380fa34c0d0fc72ca0e5d68ecc902e2dac632594c1b4408416f41c37c4a7ca8f77088229dc55f092b3006096e2ab1bfe20080698a876b4fac709752786795b49210e6044a272f13db13c75a48b5de94ee2308c1925a054b2510b2f9b396ca53d002b921d8ad010ca709b1c96ef2e22f93c275827fed9905c9c71adb22decf5530a85bf9e0153f35b20081a9ebb0d52d917c55ae8fc8830ae402bb4dceafbd37cc4cb2b06eb35bb177e0d8a99c20dad56db6335e3ba509a8a3214199235ddeb450130fa3daa0ef045a134550187840398f563ef67098489d9dc50f4a68f8f7e121a5e6754945621a394ac85d25fed7532244b1bfb295acd58f5f2d01ff62fa3df8336cdca45f90e442c91a8191e04af2050e412e321a52c353b82b08e7bff92a235378ab1495ff7efca3590c903d8a34956ebc0942217dd27bd20d5412fa76e3fd6a09426702ec1a0dfee3524c4fd5d76c8ae4b5bb52fac00ffebdaac58c403647fb601ccd38ca330c85cc1d2dc1ad3f67d29d90d12b0f372a5fb2f4daa53f251213bf9a2e2a5f0c0f777bdfa68bb4db2870fc3b9a68b6d310f15b73106dd50574f0e70829c6ba2fe7813601649d81d862d0405798aa3c2ecf25697ec0dc7c2024139ce20b96c489b45d8725332a598d8c2f415d1ca112446044e963c982c19d1d21877b8970ab8470193f106b1e7f3499f0c5a45e3ba72b12abba4107c98c9d057883f58cf36e27ed54ae052994c16a2cb6560855942f5e4bb421c67c99eb34f35e44b11924fe135a7d842a5fbebe28862416881829045900f8e0a93aa30b97bff655f3bb470572bf16bfe652a0f880920ca8c1eee8bb3d1ef2222c012b134a4febb40400de945b08dea75e289a8e273b5bde93910d3a358ebdaa10f1d8db8fe927a3ebaf4ee655152e31e6811bc45383eb1792c0b30f038844836f38cecfab6295a9ab4f45ae5428aa76b387812c918405ec41d6d301fb0fa754c1df0284ba60b75285fe80c112b83c1aa59bc992b2f0df19b20f16105cb255256660ff42cb81201634aa45a4862bdcb3d5f0105a08fc5caf7dc36efe1e5031de0fceb4d581938d9ff46f7a12789512a49a290dfaad56cae251bd301395327017455dc18f5abe11b2e2e95fd5680dab6f20d84d0b858b0b0fdd0e2f06944b180cdfa49a3a131834630802c1d586e3c1de066807ddf3401d6040d3ae451eedb633f6ced7779d134d4f501e4098422400ab0c402bbbe15cd58f57f04705a50a7626eeb284c9f9ccf22598f8b8f7a17a450b7952d323d4bbe32633a64eee8d5f31cec76f016c77affbf806bbbb128a02a5c1df40d32a218d31e9d32b10b8f0a46d19001a01ca061a129372cb2d54058582c900b1057e28ac12859f33d3f0b5421d415df3ecf802828a800df0808c74d500500d070cd2b5fbd4d5a059f43741790a99f5070a127ca490b8d2806def257332cd1a23a895d0306e309360567333e02585220936959c0163df7267a4794090e04805bc042a075e87259b7ff6a54000d8c27e41d08349d6995eec17bf2d32112030c86777968a82beaee6a4471df97b5853dc26ae5cb19341bc810bdbf56d0fcd8b0e3f4f43f94dffaf54d39d5849aef9d5c62433a7756c784aa93ccb3a6ee523b34d4f4a3b0dd14d2b6f8a0ef1355ef71231d045aaa3927d1cb7074f6363bda9c3143a8addf3303705a547816f6ce9f0275c4026196927dea78fdd232fa1bcba7d71a4d41f8e48252895f6ac53474bb2b4d5d8a2b591545aa44113514ae2a35d5ad8a12d5a5b8925551a44a145143e1aa5253752d5765b9d2cad5a95c3165250ea94ff5148a2654c9136a955e40b3858454e1e9016cb4270db53baaa01bac0912cd20f21d92f88defa41d639cd9a23ebb72350911110ec99c10b5db6e4061f783cf9b39d484ccee6a2913c8fcdb51ec1ae2d106bfd3ab6e3885a243b1974dc63b5036724ec1d032581b56acdec0b44d2221c2b4142fd08fc71d17cf61ebbab3e48f55c330458238f99967e39fc27d2cb24c477dd4d0c7e1a3efdb602b75de9317aaea0f62a515056229d3db6a67a54c8ffdd4459e815625f587a254b13a6efb3d6232acf617135d92041ffd8eae48193cd3ba98fd4f9f78404e7179e5ff80c088dacbecb58eeb2f70e017f9ec004255d5c6e781d39ea6a43b08a349d6316cdf1bfc63a88ac434a094b13f639b1b227a0da5db5a8b9399ed3d7aaa6025ec0e4d8cae75ec3ade87ec850461c5afda53b20b18f01b5df4fa7ed6d475ecd10bc0e576e1bf15e5007617a019a7961c24f663c8708397f667b0541919e0fc4f2d703d6bffb5fc710fead1b85c7b51bc6db38bc3fbc5bbdcc9c79c2a342505228609e46498360c94329480c70d177d7a0db7409fb8143748b78aa9a7206cb98c8db38e134334e7680f4576091851692c31188e74c751acd031bfb5a4d6761db5ac82ed6773879e62d638845b0d42e1acf4d28805be93056910f6becbaf5195a4bba991aa513d8bc9f37d11c0fb44a31297b854ef8c4f9886807aaee2b06e37b0fa4dcef331a82c9c4cb3febf7ceebd64a3b4c3d8e541948cb1fef6ef1781b496cbb6a3a88ea87aa86924921d4c8ee988082d30488226cc9fd5b4e4ae3404c8bd7194dc36f0fb43f1312fe6b1b1dfd48ec78e3c233e95b1d4bcc5455b932083d0ec291d39d0bdfcbaa6b50d3ade66af3ae3a2b857e07d716f558a70198af61d81fae9378ae86ce62a2c49da146c9488b171ee9f086dca3e393192b5a42b4b8aa4b0bde51f90985bf6809818c9384984ddd71da52cf122422ed0f87e9e394aaf4e2eba88220dee224a9da985f9e82798f0c308ee7140b431b228596d615257834af58164745346d33a8b540f1280841424ff9159ab4918ba1f4bec8901d80131108d208b10b832f36c84e5a6dcf01f0071f7d9ed9e251b04f377625cf5cbf4fc78b5aebc6f8d6ab2a7fa56e5579f463cd764f1929915de9ce46e5f5ec5d2a7d7a06a4339fc03a2342ed0f5359f9b742ddead5b2fa97eb17bec3fe323a61f98acee92bb15930cf34bbd35d126241dbd64b4e107ae37c855e28e08763066cb50a41aa50b9977d66f7533918e213301e15e58fbf1312e1189da560082ab06a46438560faf9881e1f50660f9e3aa165489253341dfc75e006c58b76cc889414c73dc5d69577ae1d6c41b4764585d7a1e95ff18ef702ed9b2ffa77651cf7bf59be2db32d14325d04dbfdbc962e7c0d4b542817f81ddcc449086b0ee905d28b32f74d3b2b1293bdb57827de1c5c3c15f47b331471f5fff360544668c7437197e4d4f6ad8c3c2b4836c86c76452f1f983ac91a719200bb3269bba2df8a8fe66010bfedd6d64c317122fe9f67dd480a8cb02d5672ccd8f4aed5d71d8f1720bb05b4f35299664d0f16292b07c95b867e449b55eb9e88312e3c235ae1686e847b5ce75d3e9674b960f26385b387da43672780bdf595064972dea15d83568fca2e4eb1f383202861be16d06d91a02284208b5ea6b80ecee35bf99011c63519e138da2107628259d8d6da727e906c6e37717deaf9c123192cc0d6af301c9406c70f15d8dafa1e5afb70f950b5c09494d581aee1a8879cfc59c4551f87085224638472856c720a16955bce4f6cbd0d88472bdfccf8e93ac8d7361026d54b53eb329179e97b2f3b1f11227bcb08b1efdeba9a8b93ac92d1316c56a93cc9d335d42eaa47fe9a5a34885bcfa25e0b7726918f3e00890ab010439f7cd71eb741ff97295d5426de6b320bf467ad6035645d771af440699c6423480a58529153a54492a285275e03fc4e5b7c6225086c9c5f952568e0414ae4f630bd8b2b5861d7e2bc580e7b6875625056cf5b8df01478e3f73b9ce68150d2e89424453d660579bd92411c23091a12cba2ed434c9552bdd5c3333cdaa61bbb19a969f58a741337296032b8e2382aa210be0b995c4abb730bb25e374d1dd677d7377157ce2fdaa4df1f2d997e5c69fdaaf8bb9834f7ddf26933ca811dc378b5b6f45914f0deb5bc90c4ac7bc211c6c51427a4c17ba51a84cf3fd8e15b39ff59b525288007c522bce02f5101c15fe3d9b79284dfcbc1cc5fd804497d96bccd4c8eb811bf088a3ae954a84ee8c4c030ce690c26f41e95f8c3bd19cc651e88573ab18f88070e3c40cc65983c0beab6de963dc4b359432e6af033610408d9764b4ceeae0c37bce2205d0b1596101bb7a5c47f64e23de7d1444539f6bceac4a4408efc98d3d04c95e60f6e0013524c4294f3137514cd958a232af1eb76a34f4d26b26ac54d252c60ea33d78342a1fd13b80b76e5dfc552e7ec34150783b3b66830ec09583cb742e03b6d368c59fce35bff97653d8c0af916672df4a3815ef789391b16ddd9456326624f3e59964f51f4017c92f006c81e3c7ac6b59b23ee003a7e585d594034b21c0502ed73ac85dcbde136486d7d166e35e92bb54f6415408f299b234ce607547fabf1d326d1401d614cf8b465a1dd8dab6ac238d619afe0298e7061bd59c05d5d2c16b263dc22f9e91ea8bdff14209cf502f12695b4678634c61f9f19f6ed24a0980bf865643fd902354febb3bc0a5ce342df4ca1475c306d6154d61b73a34bb4f72126f9a3312d5901b294b7a46c0268d3c6051e670029ea0b01a7ab8c58b7709cc9bc4fb506f68cfa1ce29a7a8f203ae672d65847c3a7590a22650019031cc9be5c8340d33820af3befa2beb30aac8f1e22dc4bbf03bb7b941a2a0579256cefcd215d8f31ffa17593a8b749aefa4fb9303df28c6149b613955f9b82f6819b65a0afdfe6735d4a915a024d6dc0d8b320c0b345fdf87a1a5d8242327d561761faf00f4e8cce8ce0a7831664d8b7c405a6cad043dd3f121d2f0863a30aeabbee20c7c6ac24f1672f290cb565cd7f76c538ee031a84942d37bc95c7182d2b2cef92bbe165db0d50bb0892061a4910ebda48e5de0d82577d6c946777368d777ab0d181a2fe4f8011f8524a61914dbf601fd090496062b3365b6c366115d64a50c2debd6d970ff735b563e6082404bfdda87aa4c7d8b6d21369db1a61781414fba38999206d926f868cce260f3e4a4e8b73f0e0475ab7df5d842de177a4da16f18822b791ae3f5a1b79ac0575c5c23919e85ce8d506eb5c9746192c361b9e65ca34bf5c5ad99ab992ac7f6c3e033daf524da6b1f6709fd14995e33c6972d58e35de4e8ca45fb7d793dfaf8c1e35e027e6215cc42dba130ff3acd1e6714d5f9f5072a82a9ee2ccca558b77b1b4eaa6203d7a98294a085d0fabc153243c914a743c0cc092198b695e3c09fb329a0b5a4e233c6e786a34ae3a356c60e889f8b6448e4736d0179c96609ede424df6dfb25fd4a0acdcae3622285cb6377046fa24a571d7ba96ec72987da201bb6cfe74e79b68015e524a8ae76229af3f02712795a3088891711097fcb4a64100d11676a7fac4188cc2ec513324ab41ea3911683f5a715aaa3ea0679231b07f1e5306238e572f83a4a2ea0c220467f32067cf595775e250e1786a764ef851d0a22ca4376d1240ec9c7c497a2ad951d4157afc505896d9a5969cc65f3b3d522bcb1c0a605e1ae73eebc0346d0ee7b7def4834b170ac377b0391c1c264a2f0e37e9739cb34882295893e8bbcd6b83b1ccb308c2a5ccae8aef0d7d0a77c7619f0b1b75863b2bdc92bdc5bec4d0421546a167307cd5a20f39feedf70d0db25c475f41e93342670a09b4c37c03403b204011ef1628120e8875f898e1e6bdd373652c4b11ab5d059555351fec5e60c82374dc38cd18cf8291628fe4894d156ee311154b5a157df0ef6820c87b76b2f2d24cef676db146524ffafc6676d7c8a2ec936b7556f5a895193ec04aefda891a8b9d63f84d50fc41b2151e84987bf939a8cb66bdc7cef4586daf82e3b780e78bfbefdab827d1444327ea26e3be1c7b6c5931e5cad1e098031fbb63c1ccf7bb1232fb4b0052e9653cad4d15bd5e3427ec45f1bf916bd334e462f9f0667a415b0d858b0f451565f0d490fe7e1df53fe807329c6cd379649f3c21b7f4afd716bb18aa48be950cb94cf236fb10203a6749e6c416d16e1c55c9dce664acb992e302a5bdbd0b652286b12f3415e47a1ae523c0afeda01ae82213e3013bc423c7a38ba0ad482f244b252d11da67d9220c76385b44674cec5bca9bb97848b25796dae4af9896524b3108e2dd6ed00d7c289d57493874dd5d5501048b1afa2c261a7ef5a929316d8994a71b0e308765ae2736c46822961e71a04aa5e11bd66b23eee428d4b2b5308019260a504c2832e2750950b752ec78265822e3f0b1c3dc28b0b296f225550ae1ce8b72c3dd44735af620439b878cb4bde34ad384fee4eaf7117a1c2b406a9a88e619b7997223206b69ce6c700f9ec4576d425bd081cb7bb6bc507feffb1441ace94fde9c8112056790f01cfc943162b99d03a80fc4d4a4d4ba2690f49de42d6681fdf5d614d8913e1dc2243b55695a1393c6ea2ed3adf28539f57296fde3ad0dceba47be1e1701b56376afa91a27dbc4a080900f9b263107134d8c9ddc19cbf0dd4bb44d8ba1d67c03ee3e0edfbd1c348ec1fadd6f2dfce54c7bf83b13356c3ad9108c90903373bf6045c5b71da2e855c7d1d7ed51fbf1d89d59d76dd37ff5103cf6ac783868c3eb95c0724547a7b3f58b5c03b636ee8e22f796532c0996d4a9869c5a9f73a0ef99086f3b6e0d3d93bdcee6ed3f41699ebdd5509a22f7a06e0bf42a756a138bc51db98548b891a067b6d3bafc06e969e6298c3a87f2d92f372d682fdb36a20de906073a094d58546ebb56d2c43b01fc6a835f93ab29afccbcc9be48fabdcf617d5dd6fd87ab36426c1d662da22d73f8249a67c133bf1d20a94c0ed5bbbeb171c7f45d5495191f5494ed41848ffe468b84e8d455f27d6cbcde676a6d8a1332616b58f6a2a36ba583d5f6e654e1442a2f756720d4bd71106eee02e54572af4781a1366fcefd7e18f65815cd57b601249b2245aa12112fffa1b0a174b2a72f0f8358687bc3524819e2c216b22d8a024d1578bb1c478cd8cb4385ddfc329b654f97658adad0568f2e6e8bf00da4321668453510188313411af758a4e4414ac64ab6cf0c79a980f4ab4e1c2addb24faf73e0be83407c1befe121dcaabcaa24395bebb6e688d9ba2781ab3192caf3be95ba243f66cb93141ba46ca7a9092ecd458abd25ffb0e12e251f436f960cb0f35e4ddf359aeaae9e15214dcfa8c99a23dfcc1d2b71d00d19c003494717fe8bc308813efd0fe6580681299228128d401c264efb3f62b657a1b9e0fe18a5376ef68d4fc72f16bc3ed7e474ac763146aca026ec6fa2382226aef4cf4feb1b0898a2639bbfd62664e01672adfd10d942747109046e724408eacd77eefa210cdd3d90096a08e1cdbd1b5ed159eee8010c08b7538c14b6d7775b8fb77234a9093f01f5ab2b23196f3cfb3c49680a53ae31b23e623e14760c5f12bf56488f78a03e5f81a7e1f43747f8f5a8f067472f1781df93e98565c746092defecae82c188561b57b1840032ffc5bdead56e4bc85672b08d4abeec09688b94c469570cf4f270f405817990e8257a409efa60227b5c1f230e9b03c57c4e6b0f420ef181e36b604a7eecf7e3209f5487cc81c690879ecbf1e0d6e2eebb52359d0fb00d1c303767b4acdd0ae28f0f74d92b9ca2a97dd14c126133f1008db671cfdf2a78d859d821792b7cb2386640e5a708d75b7804b65357b78129655f181a6978a3296e4b352681e7f888efca94e8243411711593a53e2b7077b118e0b7bd5a86e39a0ca0783ce99db48205facf141bc58641063ae0e8caf7c325151e3ad91a436aca42894d469bc9a6485aa67756c819ec75791bb6fd37e0ba8e0975351effc9954a488de5971255928d0c06d8e9bcd0959de2c5cab555d87314686140f9f014c1472c8de66b1003530a922f9c6f823807c55f2b23cdb9986fcad91bd670946183d680deea0abc2706c3ab5ef032fb2750717e07d34b7917754484224eb50061c9f976f52b1d06133618841db7d67f0203deffdde917bba0b1ac7b76de7ad97a64d854529a8a4b5ca2f958016bee72715080b5e5b3dfa57a6889e40588f8131424706343ae455594216bb15f0a7d9240f4f0fcef891794b38e20f03351fbe5a099ef836b59a63fa2895b2cdb486c339d84be11a328f26a5f8f2b12a56aa862ec9603636c3eb941fa300075ed7aa6cc2d2cbd1c4ab0975da7026184849ac2d80565b0c1868ff02d148166a5affca9ddf3a2c2fc0b822754e65bcb2604335d490c312649812462ccfdbaae171fa4db4f6012f9a065898cac752ef38cfd05b54d750d37209979e13e34de30f7f9025d55306573d7fe960bb91411977d36b5328f027d7bb1b05a3e2496d5213794cf9aea1ac6aa5d4672a0ea0360822dc4a6062b3505942c8e1c40d60e6aaac648516296a32145d4e50b7c1c3842573368db9652b3806916626385694b61dbefd01dcb3d85863e97a07ca640b6edc667ba0dbcee1d112b22e1092423ac981127bc97d0facc68a2c4e77a03932134977807ba5e79507685ed19cd8a574af641c4e8f2b4d8dad2577a2f03cecb2dfb65aca1153df839d810f115cc650624b910749fdc7e98afc7c6a071296b4b8680c51179b533668c9e9a48f5a28e1ca3af25a13202097301710dffd374fe70e6c79f1b3865977d98daba9387d93b293640762a88f1b74b74aec0be38f63b5002557c819f3bbec13cd7bd3ccdfd653b686b36b23ee74e0b5f589c31a1c75eab6a30031d6090c33742843b21dd5b0decda1e4afebda5b18eabdfff6bf7350c12b799974cb4da78787c7be3c97b0b6f0b4a39709b4aa77bf99e4ea99e3b6fc27ca52b2162161bf6151441f85980c97c9dc1a17c8b7a1bded8aac4ad1e02a2e61d259f3c418be7f590446214aa4c80f88f33e796a90ebfac952aeddc9f38f2b86ae2c57985088689f89ec556dd0ef0d32c7f77e703dde127ad74cf8415c77851c46a80555341a6dfc857581844041fe32f252937142addae6cd5f7992abd6b0f6b5f57a07843c30b11899e241225f12b7e6b42450816fad4e1b4b14483077450c8c49a0544d9645d9ad88dd7bf4a2efdc4aee18946a8805a1135a569fb1850d9e1c36562e5e84174a4745c4976f406c5ed51abafb6363df320a7b92c7863a249a960f6daf860185f53a128d4b3920e71a1776523a0e26eba030d394d2ec890e9cc721b9e60a99d5e154641221cec5352e4e85b928a088434ae26125e75eaf1bb39cf39a9876f9207705293c6002ac2411fdbf23541793ac5da8e13ba362940b24faf88767dd6e28cf42d87d4a72a4efc8b523224de302030f8ba254c7e22e7a60489dcceb504bf728ccdf202c56af11ae4ada15e2577074453512452ce438469569086c088d3ca708a5232ae7bab8b05f1f5b11a4bb35aacdb388f7e87de549e1409df375e5264be418bcd7e5674d476d76e01f91ee50111c1c56575a9d2488fa7e0aebffe096936034c5788cfd23d35c06e52e5c955cad41cfacd427eea36631b374442a8ff23e362dc5929f2ab4e02abcdb057d5693246c7a720f30ecd6243bdde889a39f35247795ca76a6a8940d8e57df82f9361373c1ffba288ad7c8413e8446567afe9183ba0175ba432084138be444765ff2306bf32413261c08d0f5ac0a9da348deaea9883bda08b8999ecd59d37cf4e932a58f540dcf389f7251b72ca8b22f8470a823336aca6b18c3eff3b3a770bab40dfcd4be6618e3f54c504629b77df4af562059e0715e17c9505604cbfe1a60dda7921b87573ffed8030e1a8f81741d7dbdd6932dcb2a122a8ec889017eb7173f258994e804a12b7510c5b3e045c09d7576f4cdfaaab401b8204d547fdc6a45819ac52e59565b9007bb90e04c01c88d7e17185539822e4f2f08575f40a8c1d86f4581b222a77332bf285b1e6044b00ac998556350a3625cabb2372551c50adc4064029bcd0d3a3c78e03595c8d6631d955a7fbea54cc974a8819e0b83efcbc190e652f29ab612a47b8a7b7a431b16989d2652a1c204775c8bdbf09d343855273e2171b380b5c93d8d2e7c5c32dcdd55971861570d47091f18542d5956e28237c6c0c7fe3948896815eaf6ab9c9cc7ca0f90b79595f8b871dbeaef3b988be8384efacf7f59f86be2452ee45910c13709fde45fb18ade7631a9c651d0d0731748c2c009106cd090e897199592969b85007bb5e844ff1cbef2faf7624e237bfff131355ac1d9e704cd4194d0f4540ae6710af1cbf97ecb2ab8d35c7173b0674710ee252dd640c029f4b190e083d0a2eb2bb30237042b265c9b068d739ca838317a1fd300418a0812c6ffbfe6522fe59e67d1d05f406a42343c1f61c754e5a5e2a7e411d83d1351c617614fe98b0f79022611d178cb0c0485c11f2aa97d3b34a08ef3d4cb6a7cf73122a74e7ced77e1e0ae3e47fe49ee91ab5c6b50294608267c8f6a0bb3296933a51137b893448214b1ff2518dd02ea61ba9e02bc530a7394aa1ab8ff2172fd2177e62fe55ab0ad4e512e0a9ca2558448e9e8cf780b717ef416ee7841514e9942cd5cf3b4c6a206c2da0ac49cc34c3841d35531ed53540b354bd6a386f7118c87e37f115492c43566a7fc235d0ceb334e80797071c4bfd340151a6b952ea1e39fb969f28541dcbd25a356b856c21e4eff17443a403e71ce0bdefc14973fb3f62f0370c12f3ad8c75f688a3dc30435f3dfa512dbba7e6a9e25cba0bbb903c3e4a47409cb68bfde7b3b3eab2c97102e1dfba297db18667d9329899cb2e7dfc4d6098159b8bc07d23d9f04cc2fb779b44054ef9e8c68e08ecf200200930062a02dcc13d413440a2771b812e50cab0e583540891fe767dd856492fc6bae82698608031162f8fbd43cd71b0970c13b1a57046e7919570c57f84166e01ad6d0cff072ef2e3bab3dbfc649bc035f4cd7213d449cb478c7d62c7ce05ce58726bdca001afd3fc3c40569c3198515836c8f0423781958f578b645840acc16b8743fae41e7cda76e3b873e67f662fa3f3c3a41e76a474e548e803a620c83dac335f0a72052547069c376b7ed13f857499bc140422fe60418579239db89f67bc50017b055339fbaeb9911ca5393ac148736d201cf27ae884fed1eba0dfef35e0e5ba82e1aee1a5f05321c158c7f04de8bd908713a730825ac1ade1328015e0cd26658fd68380dd913ed7eeadf2468d5fa9c9f81304fc3a906f7b91465a01b4614160e403afc27e8fb41fe036303e760d43b7f53ea699026e0130814d008700b74c2e0012b55834b4a0cb84db1929cbfc8d7c30cc0e5a04b481e6871595b5e88dbf651aaf7e1f0c83fbbed7ba9eca88d39c95e266e2e21607641861ab840da44f403ec079f0c69ea0dc10bec040a01eb61508195d28d7ec105fd074c712934692c049a0cf2009fe257519bcf9d5b4dde78c16a53c3008cf6367384418081bfe535c0ec20e8629c36b872190553c338991a303c8718038aa4a113848458fe094b1c02ba3fe2e1aa32c6a14cb8b2491633b58779780857e6d868a66d830bced5d920fcff5f00857c0de0151f220d9781a7e710035c8ea6a6aff417d07495d673d025bc1ca8027ae2a4691b61e8ee73d81649b7bdcd997c86b175555005563e37b82c35f2b9317c7f3c977d5efe2c47d4690c2e7ac0ee5db35c309eb8e99dd4961757c6efab450878d39cefa2c35457e5b4ce792c2d4003a88f71d1607d1870ad568fb3059013870d317a474b7a04bafa2826a272ecb2d57177b2bf1900d098101cb3ebaf132aec702add330205ca7afbd4d03fa80fc170ad748bd20a3afcfd93dec522c34d0057c675a02094cbdb3fdb51900a4e2191e9c888f169000e7869a8c670ad1b3a1905142e1d15cf3262d2af363a88816937cca07976b57695c3d903bdebb44583dd09db040c835a40cda4fa850d153815810d8e8f661e8df9157044d5fa32b81caa06de03e98c17c2ed80d3413d80a54123700d0c1de2ea1ee05ea8221492553fc0f83378f2b053804608ac1436118dc8a005c295dfa4a482f5fb0cf78480c1a0d9004ea040807a002b606548e956020ed9015cfa74f77156f8fd4b72c123a0d0133842ccc689fcf400ab54b7840e08cc5be26a7d435f2cf590073e897add0d64871863bf2760e719b2b1493e2a61067d28c475c1adcf9c605300028036e342fe57474a3d1075bc2a672cfb3e5fddda4626c02026fb74e92dae3ec5c78ac4058a032d24f496e94a41aefbdb1fb7fbde09651811b221869f622713650a1837ae63ce164f74e3e68bf2d689827a6f3517d9e29046a2ea364bff5e235b7832af00c3ffaf86f783021b7ebcca41d4fca5ce1a2ef421e0a9ecdd7a0d51cd418570e0405a7db309e3990fe8e5155c26373865832be19f0002e13f14c649a22d001c7813d88fe12a11412d1b3b078b02c781aaa07df12dff8a774ef4f0dae38a1c8061a8b2b7e83520481beebb32eb536da4d75385697039d083e3cbf8b9ce08b87054fdd2f8363d7d8e9942b58f68ca340f81bf008cd1c26cb09af46dfb4e56dbcb8533fce49ea5ac8f6c313d3e60664086380194d060ecbd2404546dbb4d9afa46ea3928c336c07c047538c3e5b737d0ef089703fd42074281a9bfeb64de5370e564b7fb37437ffed50ea9771abae76a32260ca84b1e481834246666f21d0e2b5c8a3a71b4860d564def9cca3f47ce844b0930ae773ab354189b306c02dece43ae0b63eea9081b8a324835e71a9b916f2cbb799f1e384f5b0f4a6dc4999585ebb041250c453d8440f4a50bfdf5a73d771eaca869d6ff45d356b3c15eb896a597a73a05382c06fcbbf4e9a5a4195d77c7583f86573c60598d342592d820f7ca7959d24f685c94fe652a133432591b242b7f9c97dd0218df1b24ac5a514af62af8ff1d300121921554366596c2409ccd2cb0595a6c1e80a373a7b0c57b3b47efef57afb45d99a70db2f060c02b5f29060da88d9b328787e74edffc8731f73bf74b14b4366a901637de2d30ae2f9180250309fb534371a4be955acff8b901665c5d127b931a1b5c74428fb2dc50099abe2081de8c6b0319fc9d526a6c97aeec5a162367958a5f3525132df5430a732e06a8b1347ab53487edb9e4912b9f63617ab1de5f7312006e73537cf6e88425e94a1bd4fa2c6617aeca6f4116db88d69ba1c8823dc1555dea62b62b34ad6b674b14e90fb24c5ea6616fca482ae440dcce5d8f33434268d29c7f184219e735d9657fc4f7a832f79180984be20964574b5366a4209446967e01c90b2d523f9208613294d078d8fd5f5133b6f5e7d2f0ab7cac61720a51978636bc49a780c50181234d05a101884ad0fe51971983cb2274a8f7283b4c98ea8b193a4f0efd8b1a23313a78bd6324bb507a696c9c5b12a0e182594c2cc96157f7f77d6c15e4b7ba87cde754c2200a9847bb8e77431ae97eb68d1aca4f2f85eb2926239ee8d5f623b192a57bbc954e776d47f05a3df1d154879242f7b08d809eb203c6b223118e053af00fa3f4ce197044a8557a8037342b78e88e4c54c558b784d22d5b23bfb21a8ea82f0b3a66d406f76b517aa6b12e7ea0a35233987d494d54cc246876594c6d8b9ae896f57664b6a81e29f2d692b219fb7df4e8ed5cf1f69a385860779e3c530458d57c1dba2b70e0b77f072ae31ea704c5697e2aa5405b75ce51971b95c2a7ad3b773ef22baf65546ae9e06e34c574d2b4a7510056ffeec2c12625e2525338e13b3f901ac24429042182212e030efab18687c398b922b64724e24c1d49182ac7e340814462b2d9956636fb63e704f90fd06295a61af2ad917b30e3a3ba4db4fbe2a2cb30295107881b99268e48113d1addd90ea5c64e0f0c65944fb58e2c032268d89cca178b2cc00903520c75e81fd25f7cf9d2039c6ae330dd01528b62ba976b1b997564c424f94c92c313c88d86e6e683d96d59a7778466394c1b12c40c68d924f8c8140cb7aab15070371004fe9edad9111925b1dff765a8bd57fccea8e45a9599709f5b7dedbf179d7ed9136da0d5606473623ce9b509a7ec588cfc1cb48d5804606c080d39a2e29008c4203efa4874bd4378dd28a0e15d902667b56c89bf8c68204a883a8d00ba8fa80ba27acd2ff143ed84c5ee1712b25c2617afa0bcfe55df32e254aa439ffd9be1cf0210ead62fc4d7a6397142ce01e49badfabe9d7e37aa66c6df7893570d42a781ba69e5f7876b3de0e0dae35144a7eed2db970c798276c67ad5ef81b21f3814a2250fcc602f7429e74a8a533c59a41c91a662e46b3152ec4bf0c516a9c84536f214c7a57847bd3338a2c38cfc6491c89ed3823912960cb37b760d134159576e4b99a247ac059b0364c21b68f01d3028a00258e17ad254323b4ddeedf9ba28705bae04766f24f3b97b2e0fe41004cb635d221fa7d8a0d8e5dd241b32d88a033043eca759832481c9725233298b5d057278cf30fccf929ed800259c00d729c0956ad41f664c44cbe31345582591f66ee79a5d2dcbe32cc351868421b7c4e758b54af4152ff6ac07f0e98baa8f2ed7f5b514a647a1092490dde3f299b5d4e4a990e3d2438ab1dd51370183a4365bfb709c7ad5b42517f3f0e8e937a0a4b42ca06c91793582033cdcec727e08c3eab5be9b2eefb687329168d131ea19710391948d98aaacb28853d3ee9c09d3b9f35932c3716f0129680e5af428c5fa55d0765ec55aaeaf0ccd675a3640a17febfc731e0b5e7e4b32907fc159f5d7dc0cb23dd3150f2852226a5e631a6c1c684a706d2e19600eefe717f25dc6a0c3a1e3d01f44f71183669c4f68873e1fa46b9951a1a551c03c6ce7d893e6a2c6bdf24abc548683ba68cb6507f7675ed9b94ae8b92e46c11295994e2d9eb9270af8fda2fbc696d18aa255c9ad351388e2be524d1d9c6128ec7ce3ad32cf5d152168c90dd251cb7e71e25ee4514304b7a16c741064d4e911f45ca66353bb6e7a9b4159a6d2fc9b4657756acedaed3d7cf8a0bc9102fd99e6702404063886a43980d9f2b4327d259cca0f1cf190aa6560726476f342acd27cb51fe5eb1ce049eb76a3ab96e4192c429b8476440c0f140c774cf7cd1136c0a99cb1b37c970c6bacd2cfb3acf5950ac3cfbeea080069eab4e045d07f41a49e0403548c5048daabff589c2391c9567ac4252d5afe964707a2438dff23251ef46fc9b87ecd36394a43c604f407d9c369389e835a09194078603836c3a0e077e1f0cfe299528710cf0af624af069f581c54b508d4c8aade5d6a28c6ecc4461f46b09b17eac5fe4f6e87cbb454280e3a370581b9bc7f8ec04ed7c3355e2460ebcdf1520130b660f33701e6d445ab4dd544fb1f09a890a4c90cd02ca990f412e6314b56c725ef5ba3bb520c36b041b397a8ed6f7e7dcdabf49a465a58a7b2a2863122610d3788a2d667e435cb0b968bb75e5b3984e5ee2763942538b439c23472f011c857dc707bf010e08d7cc4c41978482c95c33a957cf2354332431bc4944df110561ce5986d581dec90b24a0cf42dc56828491836ac0ae3a7ee0ff56c084219287df999ea96ce67029b6baf62ab1939d00fd4405686f90958bff3bf5a71df7de038d42733bb49a5eb2a48473a0d16fe1fd7057da000eafb64293260b62c07ffffffffffffff7f3fa51fb2b79140a278a2a494523245a9a939bfc3654a49a694d2c12d3d67a463ddd29cfa21017402690281026d7573af3922293fb5fb29f2745cc7de439243a7a97475587b8aa921095f32bbb5f05f6d21e97dcb57ada896f5fbfb610949aaa9a6af50b3ef20a97d61a7b7fedd1524293262cb5dbfb3811c40123b75e49e3d2a6e77ce1fc91dfdb7bd6243c6f9fc48cfbcd89e29978e9dd9ccf691543eb75aea7e1ee683bc2c1fe99dab866c57f59d3b5533768f96cd9b3ffe3787c5ea919e43c656b7a5989b477aebbd7376ae159dc5bc8be75fb078a4cc5c471fe6d2861c7231ec1d49357de7eda1a3f828fa2e9ecdb5579b3c61ed488fa1624f9b4389da3b6aeb486725b63afd4df9d95c74a4c7ca6d764375efe63947ebfbe75ea3c6c49537ac1ce99dbe964b257bdeda6a98c1c6911833536ab585bf0b476be7debaedcaf5467aa7ed5bf8dab675232d66897a9fc34e3d4c39b16d2475f99ad79f7364bca8cc1a1172d938afac992fc796ff2c985d23699fdda30a99aa91dc6ad7cdac9edaf5f6692477dcc71bf3f78fed381aa91d297cab15730b3dd6f68cf41e4a85cdfab95febda0cc478dab9771989dfc273c848fd966aab4db3db35d43e862ba2bf9e7c5d84faca8dd0c3c59abc6224f6d8f4ade4739ae266982bc48691d8fbea8291d66137e57c66566d5f24a48da1b51e1dd78b848e21545dd7ad8bb4de2573ce3c1917e9e5c1f5dc3b63ceaa6b8bf48d8b59d35eaa85fae9f38cf0b34f37d7506b47b9f3f983cd82e942c773b14808d75a6ff79e355ad47bc5af1569b1c59ab1913a236f4acf569158d17bf1a2a5ca1967cdcc4b0b960ac6f8fc52a699bf64f00283cc97992e3733344c81bb07557191f3fafa54746fb92d62ce5f5829d26b96c77757e25a37b3186c14295b5f7333a5ae5a5b4a7991b999f102c606d306d9a04b5f2d5b65221272c57b1e7aac290f915c277a7775fba956a5b210c913157b66ee74958348e799c3b6e8301ec6b80c44c62cfe216deedb863c15aad3bebb78dacc1ce5807d48cbf0553a660ef5f63a5516b887e45e4b6f6745ec658a9887b4fc7bb8a166737538577987a4dd9a3a6e2bd6f97d56590784f6f0ea7be261e71c92539efcefa0a5ca38a486eebd5c6ebe4e99a95bd696c4dfc9729ff2f673bad7d69294fa3ad67616d192945f7f3baff68fe6e39d25bdf59a43ecdbad2c29175beabfdde3b26abdb11c6e3fed0d4b6287bb9753afadff5df44a4ac650735407f1ef59b4aea4cfcceda6d4e15652af760e1172a7f02c645692f676fbed5fdcced8ae92de233c9947335795c45c33b48baf9b8b4d25f93aa610626cdfee128b4a42ebac3bddb231e4faec298953f520fade8654d9f0663ead29e9ad7daede1f3d8514bdab01a31e6c29e9214fc656fbb4252539b5ce7ba8cfa21de5a0edfeed3ef8a8aa487945d10d25b93e27d7bd83eca741492c9bfdea3b8d3e49a8d235e7795d9e24f51873f4b8dcea2431a4ce419a98271f9fd3633949ad54327ac7595bffb037498cbd479b9fcbf5f3d2d524bdf7468a316ede87b965929e1bbd3fad4a7df7314c12f343b67c3957d8fe7a493ac82dc2d330dd5a92d0fe3bfb0c296afc0fb792a4cfedf9e61e5a8f9867104b49628baa946aeaaba1f43349c2954dd15a889ccad34fc14a92d86bca177eaa6e2489ed5acce834b7633d084962a88f5d262ab67059ea3e92dcc367d89e1f62ac1cea2feb48ca862adf7a54ddd4ff37927a39cfc63811eb0cca48eab6ec385f7f527791d40b1d5dabab484a657fea612be44c1b3d129b485acf54737e54ef9c75da5a8524e68ba16afdbc29769918302149652fe5d6c4ff601085ac9df32c487268356763cb7539908489faac528e310664ff583fd23b7fa265ac38b3fbf4c147eab687b11e749ae1ead6e0be9c0e6adc4d070e861a07c26a8dbb99d9a3196922dcc3cdce2ad57bcb31f4e956b6a2c07a24c4d071ca8feb570b17cb233d65ff1c991f5eb5bef0480edd1d913b1ddee176a4a38833791f393bcb5d474287e821b6a8cb747c1e948f1e3df2b32227236ab7b8bf280243c3e648cfd5357dc6eeed2ec44a0013a6b90d96e5c8982f1c47e247c63dea919fb7620c47c6bc91316e681b1ac3460bbc466aaed3add7563b6a2467d6efbd7bb6103f434e23639686d1e83d23a9976fb5a5075fae4cf66c46c69491312e301909b1e43d4f99ebfb8792c7484d21b6b89527bad54b35c26238f3223ad8ac9db8c7d1596875f772cf57ad30527b88eca16ae6188ce4faed71dfbf97af2dee49f88bd4cc8f56bb667fe5cfb1170973ed6aafddda45ec1f4021dc45e264dea99cbf513bb7b848ff8d9d43bbda798bb434177b479ece2adf6991d6b9c37e903aecdef17633c3dadc171a44f081b3480fa9d50f9d6bbe0d9d61915e5b6e8f182bc577dcf2156965b6d778bd6d56246f6ba9852e75ab488da965bede4a5f8ba9464542c8fcd858632ad551dd8fa748ead67a36ff86dc6b3329d22f624ef725274791f03bffdde25a8c0f1f8aa4d6da7dc850732af809d698a9f7aaec445a7cd8719deab063478f2a3791d82b96a711af5d4da6ae473013a999428ffccddf9babb344d2c590fd34b5eb9bab2a2b918e42ecdaf27348f5074e22f5f27577dc51b58e8f541989f4dc39ab3da5bdd88947f1118917eaa3dcef428ef0f784b082cc086c44c6a4c04524ec7fd70f5b0b129c9c20730255d4079eabf50f5145f0800d5e6ebac030f365028cf18e4908d88d4d981a0200b0614dd05c025c6e6cc2903000000e061506862fcacb0101d8d43816a6c95003068113b800c0850b1706de0105904d020044c2c5c666c50c1080ba512d860000d48d6a32d4c418c045800610a871313075632323a300170016302025a25d78fe1c55d43d5dfc35c368d2b81a9919669a4c73286fbecc8c7078d8999b9a2e365e646410383baccc014787024e0e3b7333c34c0b232383c0c1010c0dbbc500b665676e9a0c3461646410e05ad2e1ddb5eadc1752e94d4b42fd6ddd71a56f5bae6649eba8cb4507a9546c9e348ec69b6549ebcb164bf4368061348ea6691ccdda7c99b9f1321366c9d4382f33606864608763b97136348ea6008665676ebc74b151323208f02b09f51e75e83974256573a45e33a71ab779732ba9a1852c593fd458497ad6f9d5e36bb95f25a9b5acd669cb5d913542aaa466c7a9d695ba5f280fa7925c43e8bc750c17a392beed42aabdbfa7176f17cf2f3334eb7c4ada97ec2c6ea2ebe2b9c2d8e4056c8a3aaeee653eb794aec0a5a45c3ccfb9d78fcb96e6064c4a7a3e08196a47eee2e915f028e9308610b766cea66d346051d2e347baf9123f94d7b0a163e5d8435e8741e14fd4938ce9449b13dde435d14cb23191676f33ea57f978b29b63675d0cca04c624355e6cfdee7d9edbf625c9799762dbd052b624b9fffae7581e57496299fb0d559b1d765e5355604ad25be6eb47bda3ca83cc93fc663e3f62e4e72077e4db08d5236a7e164b921443abeab1556a21d58b23498e976ae7b5902b3ad5500e0cc9739ddd16b32f55defc11a4cd99d9fbac9d8daca9d4ba86f068738f123992f617bd7ccf75abcb6c8d24f7de7bb7db773db99091b4dcb2cf6a87d022893547847d14ab228931a58ab1c5ae1349aff998a8df91db316444125a8e9b3acb8e968fa20c1f925af66e72e25bad1de46c487ac48326a8a2830e53c61863883146449a490772091404e4308e03499873926a371240303108c4380c632008a2288a184208218410a308218410326264d40db36806b60fb9d042b1cf85de9d9bdb3d958d62f61ac029fd71a1756e58e49e76de1d385c2b243d8fc511abc6d0e6bb45ce053d7f03ebcad03157c9e33dc3ae8655b2a788764dc2b86023eeda3ccceb90a804aa551a5ee590644848d025f962f1e8c0f5fb0858109d3d97c1b4f0de8b2ef86df02d4d6fb8ea253ed19df785b08b4eed065b32480759c96f71159ab84d06a2bcce77c21f24da1604f9450c81861aef61b8c05e883879cc43360ea86d55236f6e8bc70107d38b28c54b58655bbc2c94fec83a058250c9cd83238bec06260a61244dbe6bf54a7fa24e897f6f9c0a6ef3d71565c936f98a294e0bd8c75d5c81057008c5d25bc0db6e25c053360a61b61fc65c4fea7b6956bf1b729bf3d898a8950e58dbf7218b1d6f91b5601bc39aa6588d696b802cb50507e6078fafa8d0e7481dea2f1407dfd6acac665c129a33f39978974426361597b99c23607a72f714284d18c3960faf571ba6df6c1d3bb26565e7c1676a738ca0dd55bb5595c01098fb35f94de05695195935887ff7219b13102fa8b2ea11987e0de9790f21b68f51ed1429a865c29760feb97ef24a8ec2e284d75f205492a5e6826aeccc85766dd90ae328ca48f437a982b82527041fa3715eb8ab5cd367e2c22892a25db476fb5fc7050d93128183b8b5a8f834c925da776b33e9a6ba9049f07cffbefe1dfc678c951619d082e66f1e2f33bccd81a9515c5b293ecaf2de43a0b193e594e4d73b819f3f3dbb1eb89d0a88948d924fb0cf993ee94f284db453659fe6aa2a02a12dd032faafca08e52fbe31e8a9164b671b0da6e5fb7ae39b50d089ff296b6d40037dfc39231f8daf1ef17757e460a5386ede16b828a276ecb5d5cc15995360d29b769ae463b6630a988b29e09c4d143896dba059ca697a2e6647f65db433f03cf100f310f336084d0fbb68f121f5f979a836e7a64ac9490fbd5d1694a82b7c5dac1a1f2e574080340b571b943a671c7fb208612f9460921aef1c0892749cf547af2c086924c00fd114929a1c7fb2b2b229e3f2bfad945cd24827108224f78019ca1693009e947d7bc95c0d540494b854d9893aed2812e5db9bf316236921737a606fdce3c231d3d2f51c5563d565b61fb9bc8dd68bfc669a6b81e783abd5c41b146a9ff7df6a949484d664a9d8172a667556201aedaa7c2362ec85654edf3f026b2b69a46e3003630507b196c5364958ad7bd8541b470ff89dc6f0c0f1dbc06c9205f5c11fc49188e09bd788aaa8309b94064be202ca235aa519bcf3560eddbbdeb2117194fbf3e41453ac930c6cd7d0a8de503a30f49b0485245a84c950740661a5d13650765c81a3f01325bff8ada9ae155bfeae1040a86b0983f1fdea5a7a1febc819073d22f039cc59667aa540f9094fc406ea8f595d8f8e515566554cf8b84c539e061b155a1869a3dede11863d27321fbafe54892ec05a973d929635882fccbe0ea452168ad37c83bb841742a048beba325f994009083fdee8925466a990dd9dc3da54027253273104d8f3c3205e2e97253f14f4029d6843eaf8fda626cdc41880fc0fa9023ef000a18121dca938f0aab9263988207da514b0edd2e48eaf7a5cb4b06376e44ba544bb25cafcc8e78f6e25d07625ad8ebfb19595b0f5ca4393215bcb5bfc5378d04624a1eb134e810463c741af4e4285596668629bea0d0dc34c44d2168e14fca44f439ffb5186b9d240ddde5f07a0fd0e8b717a9d6011f44fc43a80a20ac1e94a21a9aa638449e3bb68629029ef7c8bf90d26831371018b1ed224b8f3e23d0ad7c4a3dbe48d8e4b439c4c4e25277b0dea7aba17965dafbeda1b6d40ed31395ad0f25e36bda3f13b009e05557cc411e39374332c73be6859eb781eadbfd1fcbece553fbf58729eda8946864a0a164f32bd5efc5d823906b7f0c1f404df50639be89b451b81bd0e0816c8adf695f92bddaf6cba4128980b8c112f600ca1676290810f1381908aa147b0e6daf51b7260aae120715c595e22bc6bdb64d85d5a034bee11e0262338d8a8918cbcdd54de1b7f3dac8e07da040235b5dc72db6c5075ebab0e99de4a8329b5d17c66b4f3d1455a027a84e91e936e64842a5284e45e112eb92cd9892314b31e90d503e09d45a64431c509eae2b11332698d1a5e2114b7ce2b26ec0a47cb65893a39610c63889b94928bd880a39bf6e811f1fe2b07658b1f70279474ee4f7de8016db1575e06951b2710b8147f6551b6709a78c68ff5f499c011e098209d3d8b3a18673e04968bfb25a6b87c631e54e22267c961cd7b15fffaab5d385a9d2692222f320d1d56b8a39724f34fc7ea6032a79117e1e0062b585f3526906411bb4a42e124aa2a01c38e949c26363985e87cf0e24375bb5e7ab474050847d3311549420461d5e0713795b5b0851fdc2dfab322cd23bb51a0a8e2132533009aad5e6b2b99b40c5d0511eac836a8054fa291249f132ccc3a92fd5f1d02c70723cd6a1ef60d0099d0de09cfb1f17eda6cd1686343051cb619f8aed9d071a19538cd7885c81b24b78a12ad52562b509c1e3f7592e0408f8d58441e3d0a0cf0c5c65bcd8e348b10c0feb6119e9ae0acdc9985755cc92793ded212caa01749082d7eff5f2152f2c341015cfe5588380ba58319fcdd2348f6f0e11b69f6c080e4184b35d6c11924ab0e068e7acd2c15ef23f7ced68e1ceaecff99243aa0b4093c03fc63544116d4e512bd60f09bffc23edb9919da6a2f1d76f48ee0df7c79178a9a495f78b1820724bd19f930232042266a490d8acda1fcf6a56d87749a3564221d8b588eea63601606cd8b87c7f03ba979b69499f98e44a7d9bbace3ef5e240ad01213937960043facd69616509e05e379de488855f77291aa1523c5c65766a5840a38ac256de93ad64e423e951dd23f3b90122d2a6a1b7f2eb2c2eb2d0177dc22e01adec7cfd669218efc69055bfc7f161b5c0a38e0fbe72ff89a668306e0c86a01427cb1ed1be9a4ce7914f5c0b4415c467404f7e013a78d7a503f966aae841513c23d3a0e2e3f814055b1d6f517c6881845602e7d19fbf8d13ac59058170f5e73bd10bd0601afcca7b2b100b8411a9aad2c45ce841a433ba943572e26a24ffc314c7f71034642b8092a8a9fc54b8ef62b415e6583e77484293a7ab5042ccf7bca1e7e3343aa39bb37dc817853bd5d31ad10c08410e287b827249d5c678e89033997cf0049284877d750075e3fae2295435d26d3581a19ea43d1d4931cb597e06d49ad1afe2a22248580b4a6785240680900ab5efe80ba30b7c6918097682ae9296a3447e40f4071f0129c63558c1ed198cfcf0fc186ef62de2e0bddb25c8f136cfe3765c37e75d140f56a89ab69e784f762310da4bfe7081537378116e40887288c8852e9a8bbad37848e2b48a4139a019339d835a22c583008", - "0x3a65787472696e7369635f696e646578": "0x00000000", - "0x3a6772616e6470615f617574686f726974696573": "0x0110094f736c315addde86b7cd5adac7984cd10b1dc187364e92f7ac901a5447609f0100000000000000cee75bb8d02be946f52be595adfd9e4a8ce0343a9894c5e2471429193926765301000000000000005e7084c57d9f04eaa7c22a86d33757cdef9bbcb6607dab1a7c2262dd1293d7ce01000000000000009ee080484f0429022dda72f19bc76cd0b142689d2782c0a68682bba5c5fb156e0100000000000000", - "0x3d9cad2baf702e20b136f4c8900cd8024e7b9012096b41c4eb3aaf947f6ea429": "0x0100", - "0x3db7a24cfdc9de785974746c14a99df94e7b9012096b41c4eb3aaf947f6ea429": "0x0400", - "0x3f1467a096bcd71a5b6a0c8155e208104e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x3fba98689ebed1138735e0e7a5a790ab4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x3fba98689ebed1138735e0e7a5a790abee99a84ccbfb4b82e714617e5e06f6f7": "0xd0070000", - "0x42b50b77ef717947e7043bb52127d6654e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x4da2c41eaffa8e1a791c5d65beeefd1f028685274e698e781f7f2766cba0cc8300000000": "0x1003000000010000000000000002000000abc3f086f5ac20eaab792c75933b2e196307835a61a955be82aa63bc0ff9617a0600000010ce68cabd54aaa5c1e9870f89645ee0f2b3cfafc58089b15387b1e87f59ec3d7e701aa8e4ebae70f627b5cca9726c5ac67133b9295eacdfd5f22a3e44297c4e3b866bd4b14f3f67a056b09c6834375bdc6d0b2d7ae387f8568f67afd1db9b8a1bacf21938aa46cda6a2eca3134629bfb201bf45cc62514672daeb4c55f6b2f332000000000000000000000000000000000000000100000000000000", - "0x4da2c41eaffa8e1a791c5d65beeefd1f4e5747352ae927817a9171156fb3da7f00000000": "0x00", - "0x4da2c41eaffa8e1a791c5d65beeefd1f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", - "0x4da2c41eaffa8e1a791c5d65beeefd1f5762b52ec4f696c1235b20491a567f8500000000": "0x00", - "0x4da2c41eaffa8e1a791c5d65beeefd1fff4a51b74593c3708682038efe5323b5": "0x00000000", - "0x50e709b04947c0cd2f04727ef76e88f64e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x5c0d1176a568c1f92944340dbfed9e9c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x5c0d1176a568c1f92944340dbfed9e9c530ebca703c85910e7164cb7d1c9e47b": "0x9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00", - "0x5f27b51b5ec208ee9cb25b55d8728243308ce9615de0775a82f8a94dc3d285a1": "0x01", - "0x5f27b51b5ec208ee9cb25b55d87282434e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x5f3e4907f716ac89b6347d15ececedca0b6a45321efae92aea15e0740ec7afe7": "0x00000000", - "0x5f3e4907f716ac89b6347d15ececedca138e71612491192d68deab7e6f563fe1": "0x0a000000", - "0x5f3e4907f716ac89b6347d15ececedca28dccb559b95c40168a1b2696581b5a7": "0x00000000000000000000000000000000", - "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe705e5f82ad672e896be4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b": "0x388f7ac281acf72b7782ada96bf0c0d3c09f9276c6f4b7c6271c375fa3a28716", - "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe70ad47afdd1ab6146118caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758": "0xb2858dfa47e91328dc2f41334228a288d19a853ce0e981cd0115c406f001225f", - "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe70ca9d64ddf2c4bc4afa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c": "0x18484954a9f3547cf962d6dec822c6353042b56776ec58316a5558d75e304f31", - "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe70dd959ae783e3505c005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f": "0xf628104fc1f6314effd92cd12cfdfb5ee5c913605174e76ec501797254c61d19", - "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc410675ed593218347060fc977d4c87a2318484954a9f3547cf962d6dec822c6353042b56776ec58316a5558d75e304f31": "0xfa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c0b00407a10f35a0b00407a10f35a0000", - "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc43c9981354ec1409d0ef80e92fad06bf6388f7ac281acf72b7782ada96bf0c0d3c09f9276c6f4b7c6271c375fa3a28716": "0xe4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b0b00407a10f35a0b00407a10f35a0000", - "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc488021e4d172831d344e0aa9a1b9bc22ab2858dfa47e91328dc2f41334228a288d19a853ce0e981cd0115c406f001225f": "0x18caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb7580b00407a10f35a0b00407a10f35a0000", - "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc4b5b6969754a268a0612ebdf3fad88e97f628104fc1f6314effd92cd12cfdfb5ee5c913605174e76ec501797254c61d19": "0x005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f0b00407a10f35a0b00407a10f35a0000", - "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a000000005e5f82ad672e896be4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b": "0x0b00407a10f35a0b00407a10f35a00", - "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a00000000ad47afdd1ab6146118caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758": "0x0b00407a10f35a0b00407a10f35a00", - "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a00000000ca9d64ddf2c4bc4afa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c": "0x0b00407a10f35a0b00407a10f35a00", - "0x5f3e4907f716ac89b6347d15ececedca42982b9d6c7acc99faa9094c912372c2b4def25cfda6ef3a00000000dd959ae783e3505c005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f": "0x0b00407a10f35a0b00407a10f35a00", - "0x5f3e4907f716ac89b6347d15ececedca487df464e44a534ba6b0cbb32407b587": "0x0000000000", - "0x5f3e4907f716ac89b6347d15ececedca4e7b9012096b41c4eb3aaf947f6ea429": "0x0d00", - "0x5f3e4907f716ac89b6347d15ececedca5579297f4dfb9609e7e4c2ebab9ce40a": "0x10fa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324fe4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b18caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758", - "0x5f3e4907f716ac89b6347d15ececedca666fdcbb473985b3ac933d13f4acff8d": "0x00000000000000000000000000000000", - "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a000000005e5f82ad672e896be4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b": "0x0000", - "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a00000000ad47afdd1ab6146118caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758": "0x0000", - "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a00000000ca9d64ddf2c4bc4afa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c": "0x0000", - "0x5f3e4907f716ac89b6347d15ececedca682db92dde20a10d96d00ff0e9e221c0b4def25cfda6ef3a00000000dd959ae783e3505c005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f": "0x0000", - "0x5f3e4907f716ac89b6347d15ececedca6ddc7809c6da9bb6093ee22e0fda4ba8": "0x04000000", - "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e169035e5f82ad672e896be4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b": "0x0000", - "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e16903ad47afdd1ab6146118caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758": "0x0000", - "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e16903ca9d64ddf2c4bc4afa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c": "0x0000", - "0x5f3e4907f716ac89b6347d15ececedca88dcde934c658227ee1dfafcd6e16903dd959ae783e3505c005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f": "0x0000", - "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a000000005e5f82ad672e896be4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b": "0x0b00407a10f35a0b00407a10f35a00", - "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a00000000ad47afdd1ab6146118caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758": "0x0b00407a10f35a0b00407a10f35a00", - "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a00000000ca9d64ddf2c4bc4afa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c": "0x0b00407a10f35a0b00407a10f35a00", - "0x5f3e4907f716ac89b6347d15ececedca8bde0a0ea8864605e3b68ed9cb2da01bb4def25cfda6ef3a00000000dd959ae783e3505c005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f": "0x0b00407a10f35a0b00407a10f35a00", - "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade985e5f82ad672e896be4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b": "0x00", - "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade98ad47afdd1ab6146118caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758": "0x00", - "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade98ca9d64ddf2c4bc4afa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c": "0x00", - "0x5f3e4907f716ac89b6347d15ececedca9220e172bed316605f73f1ff7b4ade98dd959ae783e3505c005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f": "0x00", - "0x5f3e4907f716ac89b6347d15ececedcaa141c4fe67c2d11f4a10c6aca7a79a04b4def25cfda6ef3a00000000": "0x0000e941cc6b01000000000000000000", - "0x5f3e4907f716ac89b6347d15ececedcaad811cd65a470ddc5f1d628ff0550982b4def25cfda6ef3a00000000": "0x00000000", - "0x5f3e4907f716ac89b6347d15ececedcab49a2738eeb30896aacb8b3fb46471bd": "0x04000000", - "0x5f3e4907f716ac89b6347d15ececedcac0d39ff577af2cc6b67ac3641fa9c4e7": "0x01000000", - "0x5f3e4907f716ac89b6347d15ececedcac29a0310e1bb45d20cace77ccb62c97d": "0x00e1f505", - "0x5f3e4907f716ac89b6347d15ececedcaea07de2b8f010516dca3f7ef52f7ac5a": "0x040000000000000000", - "0x5f3e4907f716ac89b6347d15ececedcaed441ceb81326c56263efbb60c95c2e4": "0x00000000000000000000000000000000", - "0x5f3e4907f716ac89b6347d15ececedcaf7dad0317324aecae8744b87fc95f2f3": "0x02", - "0x5f3e4907f716ac89b6347d15ececedcafab86d26e629e39b4903db94786fac74": "0xffffffffffffffff0000000000000000", - "0x5f9cc45b7a00c5899361e1c6099678dc4e7b9012096b41c4eb3aaf947f6ea429": "0x0400", - "0x5f9cc45b7a00c5899361e1c6099678dc8a2d09463effcc78a22d75b9cb87dffc": "0x0000000000000000", - "0x5f9cc45b7a00c5899361e1c6099678dcd47cb8f5328af743ddfb361e7180e7fcbb1bdbcacd6ac9340000000000000000": "0x00000000", - "0x63f78c98723ddc9073523ef3beefda0c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x6a0da05ca59913bc38a8630590f2627c2a351b6a99a5b21324516e668bb86a57": "0x00", - "0x6a0da05ca59913bc38a8630590f2627c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x6ac983d82528bf1595ab26438ae5b2cf4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x6cf4040bbce30824850f1a4823d8c65f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x7474449cca95dc5d0c00e71735a6d17d4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", - "0x74dd702da46f77d7acf77f5a48d4af7d4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b155e5f82ad672e896be4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b": "0xe4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b01005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f0118caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758e7f10262de5b000000407a10f35a0000", - "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b15ad47afdd1ab6146118caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758": "0x18caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb75801e4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b00e7f10262de5b000000407a10f35a0000", - "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b15ca9d64ddf2c4bc4afa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c": "0xfa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c0001005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324fe7f10262de5b000000407a10f35a0000", - "0x74dd702da46f77d7acf77f5a48d4af7d62556a85fcb7c61b2c6c750924846b15dd959ae783e3505c005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f": "0x005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f01fa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c01e4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1be7f10262de5b000000407a10f35a0000", - "0x74dd702da46f77d7acf77f5a48d4af7d7a6dc62e324093ba1331bf49fdb2f24a": "0x04000000", - "0x74dd702da46f77d7acf77f5a48d4af7de5c03730c8f59f00941607850b6633d8dec683721ac60452e7f10262de5b0000": "0x01fa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c0118caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758", - "0x7a6d38deaa01cb6e76ee69889f1696272be9a4e88368a2188d2b9100a9f3cd43": "0x00000000000000000000000000000000", - "0x7a6d38deaa01cb6e76ee69889f16962730256ea2c545a3e5e3744665ffb2ed28": "0x00020000", - "0x7a6d38deaa01cb6e76ee69889f1696273f0d64e1907361c689834a9c1cb0fbe0": "0x20000000", - "0x7a6d38deaa01cb6e76ee69889f16962749d67997de33812a1cc37310f765b82e": "0x00000000000000000000000000000000", - "0x7a6d38deaa01cb6e76ee69889f1696274e7b9012096b41c4eb3aaf947f6ea429": "0x0400", - "0x7a6d38deaa01cb6e76ee69889f169627ba93302f3b868c50785e6ade45c6a1d8": "0x10000000", - "0x94eadf0156a8ad5156507773d0471e4a16973e1142f5bd30d9464076794007db": "0x00", - "0x94eadf0156a8ad5156507773d0471e4a1e8de4295679f32032acb318db364135": "0x00", - "0x94eadf0156a8ad5156507773d0471e4a4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0x94eadf0156a8ad5156507773d0471e4a64fb6e378f53d72f7859ad0e6b6d8810": "0x0000000000", - "0x94eadf0156a8ad5156507773d0471e4a9ce0310edffce7a01a96c2039f92dd10": "0x01000000", - "0x94eadf0156a8ad5156507773d0471e4ab8ebad86f546c7e0b135a4212aace339": "0x00", - "0xa2ce73642c549ae79c14f0a671cf45f94e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0xb341e3a63e58a188839b242d17f8c9f82586833f834350b4d435d5fd269ecc8b": "0x1003000000010000000000000002000000", - "0xb341e3a63e58a188839b242d17f8c9f84e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0xb341e3a63e58a188839b242d17f8c9f87a50c904b368210021127f9238883a6e": "0x10ce68cabd54aaa5c1e9870f89645ee0f2b3cfafc58089b15387b1e87f59ec3d7e701aa8e4ebae70f627b5cca9726c5ac67133b9295eacdfd5f22a3e44297c4e3b866bd4b14f3f67a056b09c6834375bdc6d0b2d7ae387f8568f67afd1db9b8a1bacf21938aa46cda6a2eca3134629bfb201bf45cc62514672daeb4c55f6b2f332", - "0xb341e3a63e58a188839b242d17f8c9f8b5cab3380174032968897a4c3ce57c0a": "0x00000000", - "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc69a0d9ba64d584162e7d1fc85d6d19ad1005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f": "0x047374616b696e672000407a10f35a0000000000000000000002", - "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc6a1e0293801ecda3bccddad286cfce679fa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c": "0x047374616b696e672000407a10f35a0000000000000000000002", - "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc6e39abd9d6d25130391c9ff6fc64a35ef18caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758": "0x047374616b696e672000407a10f35a0000000000000000000002", - "0xc2261276cc9d1f8598ea4b6a74b15c2f218f26c73add634897550b4003b26bc6f4c6172605184c65d6c162727408dc0be4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b": "0x047374616b696e672000407a10f35a0000000000000000000002", - "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", - "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x0040c7f9727de20d0000000000000000", - "0xca32a41f4b3ed515863dc0a38697f84e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0xcd710b30bd2eab0352ddcc26417aa1944e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0xcd710b30bd2eab0352ddcc26417aa1949f4993f016e2d2f8e5f43be7bb259486": "0x00", - "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb35e5f82ad672e896be4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b": "0x5e7084c57d9f04eaa7c22a86d33757cdef9bbcb6607dab1a7c2262dd1293d7cee6b8162c3e767f8e61892f7fcd06d27041d806e5e0335c59dcdafa5c8e181c5bded28f03696a0c9f9dec223f3cbc44c4895d8b243ebe5cee12f9f02bf0c5043cacf21938aa46cda6a2eca3134629bfb201bf45cc62514672daeb4c55f6b2f332b2174a8685bb3c874484978b71c55b45c4057e290c57c0a076ba9aeb7b6618025ed9fdbd8dffeb5324935a7fafc536de96d62abee0a05d7eefa961c1cf3de266", - "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3ad47afdd1ab6146118caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758": "0xcee75bb8d02be946f52be595adfd9e4a8ce0343a9894c5e2471429193926765322371e9715d00b3a21c9a899ba3eafd11f5143b821b159b864025ba1eabdb631ce83a2b5c733f98b4018856a1fb0bdf0138dd883cc93a883f97de48b762d6b12701aa8e4ebae70f627b5cca9726c5ac67133b9295eacdfd5f22a3e44297c4e3bd815b1a9dc0077cdf10a4cd3bedc7dd0b5de4b873f9932ae8f8b9d147f43d3000e93248544c963f34bb9cde63c97f85ef7a1939d3c9075907b26edf368fe846e", - "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3ca9d64ddf2c4bc4afa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c": "0x9ee080484f0429022dda72f19bc76cd0b142689d2782c0a68682bba5c5fb156e585a72774ca9465ba0e7407e4e66d239febbe906cbf090169b6cfa15dd44e5779e3e67bfc0daed31db022fce484b2cf0d757e9aafded1988293da74301275b38ce68cabd54aaa5c1e9870f89645ee0f2b3cfafc58089b15387b1e87f59ec3d7e62f0e85adce6f9782769ae007691df98557e3a04452ac0be90309f88f513f55dca24971e2ec596d510c673f4f8d36d0a8a407b59ffd0643f621369973a335656", - "0xcec5070d609dd3497f72bde07fc96ba04c014e6bf8b8c2c011e7290b85696bb3dd959ae783e3505c005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f": "0x094f736c315addde86b7cd5adac7984cd10b1dc187364e92f7ac901a5447609f006078f6e6a00db1f40097f0d07953008b04cda71ad831e70f37e93eb2b404314a611c52c43142e11767e4443eb56b908babae266b4f446271d11ffaaafbb16e866bd4b14f3f67a056b09c6834375bdc6d0b2d7ae387f8568f67afd1db9b8a1bca5ff4e343aa58559db1467ab84f5241f95baf8fd4bbc4d90856089e74d32669b691bfd2cd584abd1531b7deff6d0e34893960b59ae550348c33abd76af4cb49", - "0xcec5070d609dd3497f72bde07fc96ba04e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195005b6dcd704a27908696d6f6e804a611c52c43142e11767e4443eb56b908babae266b4f446271d11ffaaafbb16e": "0x005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19500a7d72b76c2ec9b06173676e8062f0e85adce6f9782769ae007691df98557e3a04452ac0be90309f88f513f55d": "0xfa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950110db7b3540f726061756469805ed9fdbd8dffeb5324935a7fafc536de96d62abee0a05d7eefa961c1cf3de266": "0xe4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195014a98987c6f4654c6261626580e6b8162c3e767f8e61892f7fcd06d27041d806e5e0335c59dcdafa5c8e181c5b": "0xe4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950270bb04a2a9e106e696d6f6e80ce83a2b5c733f98b4018856a1fb0bdf0138dd883cc93a883f97de48b762d6b12": "0x18caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195031063675260bb8076261626580006078f6e6a00db1f40097f0d07953008b04cda71ad831e70f37e93eb2b40431": "0x005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950413ab9d61fa646a76772616e80094f736c315addde86b7cd5adac7984cd10b1dc187364e92f7ac901a5447609f": "0x005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19505404aed8a9c40e507061726180866bd4b14f3f67a056b09c6834375bdc6d0b2d7ae387f8568f67afd1db9b8a1b": "0x005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950597968238adfa9af6772616e80cee75bb8d02be946f52be595adfd9e4a8ce0343a9894c5e24714291939267653": "0x18caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19505b639c79d4e8330c696d6f6e809e3e67bfc0daed31db022fce484b2cf0d757e9aafded1988293da74301275b38": "0xfa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa195061ccbc794cd1e95c6175646980b691bfd2cd584abd1531b7deff6d0e34893960b59ae550348c33abd76af4cb49": "0x005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19507f0621f339620f26696d6f6e80ded28f03696a0c9f9dec223f3cbc44c4895d8b243ebe5cee12f9f02bf0c5043c": "0xe4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950949420096ce6b2176772616e805e7084c57d9f04eaa7c22a86d33757cdef9bbcb6607dab1a7c2262dd1293d7ce": "0xe4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa19509af54e7103657a4c7061726180701aa8e4ebae70f627b5cca9726c5ac67133b9295eacdfd5f22a3e44297c4e3b": "0x18caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950a359a745f65c1e456261626580585a72774ca9465ba0e7407e4e66d239febbe906cbf090169b6cfa15dd44e577": "0xfa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950af162637344b36a96173676e80d815b1a9dc0077cdf10a4cd3bedc7dd0b5de4b873f9932ae8f8b9d147f43d300": "0x18caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950b229c28236e354a26173676e80b2174a8685bb3c874484978b71c55b45c4057e290c57c0a076ba9aeb7b661802": "0xe4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950b6b8ce596a13561b7061726180acf21938aa46cda6a2eca3134629bfb201bf45cc62514672daeb4c55f6b2f332": "0xe4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950bee8d7df4d460d9d61756469800e93248544c963f34bb9cde63c97f85ef7a1939d3c9075907b26edf368fe846e": "0x18caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950c02fd5bdeb0ec6f06175646980ca24971e2ec596d510c673f4f8d36d0a8a407b59ffd0643f621369973a335656": "0xfa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950d9ebe2452f14a591626162658022371e9715d00b3a21c9a899ba3eafd11f5143b821b159b864025ba1eabdb631": "0x18caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950e322099b0a5bb5836772616e809ee080484f0429022dda72f19bc76cd0b142689d2782c0a68682bba5c5fb156e": "0xfa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950e6ddf4dc42f9b1b66173676e80ca5ff4e343aa58559db1467ab84f5241f95baf8fd4bbc4d90856089e74d32669": "0x005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f", - "0xcec5070d609dd3497f72bde07fc96ba0726380404683fc89e8233450c8aa1950f8bc7112b190dae97061726180ce68cabd54aaa5c1e9870f89645ee0f2b3cfafc58089b15387b1e87f59ec3d7e": "0xfa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c", - "0xcec5070d609dd3497f72bde07fc96ba088dcde934c658227ee1dfafcd6e16903": "0x10005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f18caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758e4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1bfa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c", - "0xcec5070d609dd3497f72bde07fc96ba0e0cdd062e6eaf24295ad4ccfc41d4609": "0x10005203395fd92c2b411136466e88ef74dd6327c0a6f32b3be7e38d56a2e1324f094f736c315addde86b7cd5adac7984cd10b1dc187364e92f7ac901a5447609f006078f6e6a00db1f40097f0d07953008b04cda71ad831e70f37e93eb2b404314a611c52c43142e11767e4443eb56b908babae266b4f446271d11ffaaafbb16e866bd4b14f3f67a056b09c6834375bdc6d0b2d7ae387f8568f67afd1db9b8a1bca5ff4e343aa58559db1467ab84f5241f95baf8fd4bbc4d90856089e74d32669b691bfd2cd584abd1531b7deff6d0e34893960b59ae550348c33abd76af4cb4918caf23bb6b8cda7f3f90c1dc2b2f6c2b7143b13c956ef0a12dfe486e83cb758cee75bb8d02be946f52be595adfd9e4a8ce0343a9894c5e2471429193926765322371e9715d00b3a21c9a899ba3eafd11f5143b821b159b864025ba1eabdb631ce83a2b5c733f98b4018856a1fb0bdf0138dd883cc93a883f97de48b762d6b12701aa8e4ebae70f627b5cca9726c5ac67133b9295eacdfd5f22a3e44297c4e3bd815b1a9dc0077cdf10a4cd3bedc7dd0b5de4b873f9932ae8f8b9d147f43d3000e93248544c963f34bb9cde63c97f85ef7a1939d3c9075907b26edf368fe846ee4c1d81c7e8df384e1ae9667a668825c56e95b0f7d3b1ba2f7539d4c470abb1b5e7084c57d9f04eaa7c22a86d33757cdef9bbcb6607dab1a7c2262dd1293d7cee6b8162c3e767f8e61892f7fcd06d27041d806e5e0335c59dcdafa5c8e181c5bded28f03696a0c9f9dec223f3cbc44c4895d8b243ebe5cee12f9f02bf0c5043cacf21938aa46cda6a2eca3134629bfb201bf45cc62514672daeb4c55f6b2f332b2174a8685bb3c874484978b71c55b45c4057e290c57c0a076ba9aeb7b6618025ed9fdbd8dffeb5324935a7fafc536de96d62abee0a05d7eefa961c1cf3de266fa6a6474ec1a9234888f7b20d3978a706d386d0f16344765faa48cb376db331c9ee080484f0429022dda72f19bc76cd0b142689d2782c0a68682bba5c5fb156e585a72774ca9465ba0e7407e4e66d239febbe906cbf090169b6cfa15dd44e5779e3e67bfc0daed31db022fce484b2cf0d757e9aafded1988293da74301275b38ce68cabd54aaa5c1e9870f89645ee0f2b3cfafc58089b15387b1e87f59ec3d7e62f0e85adce6f9782769ae007691df98557e3a04452ac0be90309f88f513f55dca24971e2ec596d510c673f4f8d36d0a8a407b59ffd0643f621369973a335656", - "0xd57bce545fb382c34570e5dfbf338f5e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0xd5c41b52a371aa36c9254ce34324f2a54e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0xd5e1a2fa16732ce6906189438c0a82c64e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0xd8bbe27baf3aa64bb483afabc240f68e4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0xd8f314b7f4e6b095f0f8ee4656a448254e7b9012096b41c4eb3aaf947f6ea429": "0x0100", - "0xede8e4fdc3c8b556f0ce2f77fc2575e34e7b9012096b41c4eb3aaf947f6ea429": "0x0100", - "0xf0c365c3cf59d671eb72da0e7a4113c44e7b9012096b41c4eb3aaf947f6ea429": "0x0000", - "0xf5207f03cfdce586301014700e2c25934e7b9012096b41c4eb3aaf947f6ea429": "0x0100", - "0xf5a4963e4efb097983d7a693b0c1ee454e7b9012096b41c4eb3aaf947f6ea429": "0x0100" - }, - "childrenDefault": {} - } - } -} diff --git a/polkadot/node/service/src/benchmarking.rs b/polkadot/node/service/src/benchmarking.rs index 4dcff2078419..186bea3960e8 100644 --- a/polkadot/node/service/src/benchmarking.rs +++ b/polkadot/node/service/src/benchmarking.rs @@ -189,7 +189,7 @@ fn westend_sign_call( use sp_core::Pair; use westend_runtime as runtime; - let extra: runtime::SignedExtra = ( + let tx_ext: runtime::TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -202,11 +202,12 @@ fn westend_sign_call( frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), frame_metadata_hash_extension::CheckMetadataHash::::new(false), - ); + ) + .into(); let payload = runtime::SignedPayload::from_raw( call.clone(), - extra.clone(), + tx_ext.clone(), ( (), runtime::VERSION.spec_version, @@ -225,7 +226,7 @@ fn westend_sign_call( call, sp_runtime::AccountId32::from(acc.public()).into(), polkadot_core_primitives::Signature::Sr25519(signature), - extra, + tx_ext, ) .into() } @@ -243,7 +244,7 @@ fn rococo_sign_call( use rococo_runtime as runtime; use sp_core::Pair; - let extra: runtime::SignedExtra = ( + let tx_ext: runtime::TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -256,11 +257,12 @@ fn rococo_sign_call( frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(0), frame_metadata_hash_extension::CheckMetadataHash::::new(false), - ); + ) + .into(); let payload = runtime::SignedPayload::from_raw( call.clone(), - extra.clone(), + tx_ext.clone(), ( (), runtime::VERSION.spec_version, @@ -279,7 +281,7 @@ fn rococo_sign_call( call, sp_runtime::AccountId32::from(acc.public()).into(), polkadot_core_primitives::Signature::Sr25519(signature), - extra, + tx_ext, ) .into() } diff --git a/polkadot/node/service/src/chain_spec.rs b/polkadot/node/service/src/chain_spec.rs index 0358bc300ab0..3866c6950e09 100644 --- a/polkadot/node/service/src/chain_spec.rs +++ b/polkadot/node/service/src/chain_spec.rs @@ -16,16 +16,6 @@ //! Polkadot chain configurations. -#[cfg(feature = "westend-native")] -use pallet_staking::Forcing; -use polkadot_primitives::{AccountId, AccountPublic, AssignmentId, ValidatorId}; -use sc_consensus_grandpa::AuthorityId as GrandpaId; -use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; -use sp_consensus_babe::AuthorityId as BabeId; -use sp_consensus_beefy::ecdsa_crypto::AuthorityId as BeefyId; - -#[cfg(feature = "westend-native")] -use polkadot_primitives::vstaging::SchedulerParams; #[cfg(feature = "rococo-native")] use rococo_runtime as rococo; use sc_chain_spec::ChainSpecExtension; @@ -34,14 +24,8 @@ use sc_chain_spec::ChainType; #[cfg(any(feature = "westend-native", feature = "rococo-native"))] use sc_telemetry::TelemetryEndpoints; use serde::{Deserialize, Serialize}; -use sp_core::{sr25519, Pair, Public}; -use sp_runtime::traits::IdentifyAccount; -#[cfg(feature = "westend-native")] -use sp_runtime::Perbill; #[cfg(feature = "westend-native")] use westend_runtime as westend; -#[cfg(feature = "westend-native")] -use westend_runtime_constants::currency::UNITS as WND; #[cfg(feature = "westend-native")] const WESTEND_STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; @@ -110,269 +94,6 @@ pub fn rococo_config() -> Result { RococoChainSpec::from_json_bytes(&include_bytes!("../chain-specs/rococo.json")[..]) } -/// This is a temporary testnet that uses the same runtime as rococo. -pub fn wococo_config() -> Result { - RococoChainSpec::from_json_bytes(&include_bytes!("../chain-specs/wococo.json")[..]) -} - -/// The default parachains host configuration. -#[cfg(feature = "westend-native")] -fn default_parachains_host_configuration( -) -> polkadot_runtime_parachains::configuration::HostConfiguration -{ - use polkadot_primitives::{ - node_features::FeatureIndex, ApprovalVotingParams, AsyncBackingParams, MAX_CODE_SIZE, - MAX_POV_SIZE, - }; - - polkadot_runtime_parachains::configuration::HostConfiguration { - validation_upgrade_cooldown: 2u32, - validation_upgrade_delay: 2, - code_retention_period: 1200, - max_code_size: MAX_CODE_SIZE, - max_pov_size: MAX_POV_SIZE, - max_head_data_size: 32 * 1024, - max_upward_queue_count: 8, - max_upward_queue_size: 1024 * 1024, - max_downward_message_size: 1024 * 1024, - max_upward_message_size: 50 * 1024, - max_upward_message_num_per_candidate: 5, - hrmp_sender_deposit: 0, - hrmp_recipient_deposit: 0, - hrmp_channel_max_capacity: 8, - hrmp_channel_max_total_size: 8 * 1024, - hrmp_max_parachain_inbound_channels: 4, - hrmp_channel_max_message_size: 1024 * 1024, - hrmp_max_parachain_outbound_channels: 4, - hrmp_max_message_num_per_candidate: 5, - dispute_period: 6, - no_show_slots: 2, - n_delay_tranches: 25, - needed_approvals: 2, - relay_vrf_modulo_samples: 2, - zeroth_delay_tranche_width: 0, - minimum_validation_upgrade_delay: 5, - async_backing_params: AsyncBackingParams { - max_candidate_depth: 3, - allowed_ancestry_len: 2, - }, - node_features: bitvec::vec::BitVec::from_element( - 1u8 << (FeatureIndex::ElasticScalingMVP as usize) | - 1u8 << (FeatureIndex::EnableAssignmentsV2 as usize), - ), - scheduler_params: SchedulerParams { - lookahead: 2, - group_rotation_frequency: 20, - paras_availability_period: 4, - ..Default::default() - }, - approval_voting_params: ApprovalVotingParams { max_approval_coalesce_count: 5 }, - ..Default::default() - } -} - -#[cfg(feature = "westend-native")] -#[test] -fn default_parachains_host_configuration_is_consistent() { - default_parachains_host_configuration().panic_if_not_consistent(); -} - -#[cfg(feature = "westend-native")] -fn westend_session_keys( - babe: BabeId, - grandpa: GrandpaId, - para_validator: ValidatorId, - para_assignment: AssignmentId, - authority_discovery: AuthorityDiscoveryId, - beefy: BeefyId, -) -> westend::SessionKeys { - westend::SessionKeys { - babe, - grandpa, - para_validator, - para_assignment, - authority_discovery, - beefy, - } -} - -#[cfg(feature = "westend-native")] -fn westend_staging_testnet_config_genesis() -> serde_json::Value { - use hex_literal::hex; - use sp_core::crypto::UncheckedInto; - - // Following keys are used in genesis config for development chains. - // DO NOT use them in production chains as the secret seed is public. - // - // SECRET_SEED="slow awkward present example safe bundle science ocean cradle word tennis earn" - // subkey inspect -n polkadot "$SECRET_SEED" - let endowed_accounts = vec![ - // 15S75FkhCWEowEGfxWwVfrW3LQuy8w8PNhVmrzfsVhCMjUh1 - hex!["c416837e232d9603e83162ef4bda08e61580eeefe60fe92fc044aa508559ae42"].into(), - ]; - // SECRET=$SECRET_SEED ./scripts/prepare-test-net.sh 4 - let initial_authorities: Vec<( - AccountId, - AccountId, - BabeId, - GrandpaId, - ValidatorId, - AssignmentId, - AuthorityDiscoveryId, - BeefyId, - )> = vec![ - ( - //5EvydUTtHvt39Khac3mMxNPgzcfu49uPDzUs3TL7KEzyrwbw - hex!["7ecfd50629cdd246649959d88d490b31508db511487e111a52a392e6e458f518"].into(), - //5HQyX5gyy77m9QLXguAhiwjTArHYjYspeY98dYDu1JDetfZg - hex!["eca2cca09bdc66a7e6d8c3d9499a0be2ad4690061be8a9834972e17d13d2fe7e"].into(), - //5G13qYRudTyttwTJvHvnwp8StFtcfigyPnwfD4v7LNopsnX4 - hex!["ae27367cb77850fb195fe1f9c60b73210409e68c5ad953088070f7d8513d464c"] - .unchecked_into(), - //5Eb7wM65PNgtY6e33FEAzYtU5cRTXt6WQvZTnzaKQwkVcABk - hex!["6faae44b21c6f2681a7f60df708e9f79d340f7d441d28bd987fab8d05c6487e8"] - .unchecked_into(), - //5FqMLAgygdX9UqzukDp15Uid9PAKdFAR621U7xtp5ut2NfrW - hex!["a6c1a5b501985a83cb1c37630c5b41e6b0a15b3675b2fd94694758e6cfa6794d"] - .unchecked_into(), - //5DhXAV75BKvF9o447ikWqLttyL2wHtLMFSX7GrsKF9Ny61Ta - hex!["485051748ab9c15732f19f3fbcf1fd00a6d9709635f084505107fbb059c33d2f"] - .unchecked_into(), - //5GNHfmrtWLTawnGCmc39rjAEiW97vKvE7DGePYe4am5JtE4i - hex!["be59ed75a72f7b47221ce081ba4262cf2e1ea7867e30e0b3781822f942b97677"] - .unchecked_into(), - //5DA6Z8RUF626stn94aTRBCeobDCYcFbU7Pdk4Tz1R9vA8B8F - hex!["0207e43990799e1d02b0507451e342a1240ff836ea769c57297589a5fd072ad8f4"] - .unchecked_into(), - ), - ( - //5DFpvDUdCgw54E3E357GR1PyJe3Ft9s7Qyp7wbELAoJH9RQa - hex!["34b7b3efd35fcc3c1926ca065381682b1af29b57dabbcd091042c6de1d541b7d"].into(), - //5DZSSsND5wCjngvyXv27qvF3yPzt3MCU8rWnqNy4imqZmjT8 - hex!["4226796fa792ac78875e023ff2e30e3c2cf79f0b7b3431254cd0f14a3007bc0e"].into(), - //5CPrgfRNDQvQSnLRdeCphP3ibj5PJW9ESbqj2fw29vBMNQNn - hex!["0e9b60f04be3bffe362eb2212ea99d2b909b052f4bff7c714e13c2416a797f5d"] - .unchecked_into(), - //5FXFsPReTUEYPRNKhbTdUathcWBsxTNsLbk2mTpYdKCJewjA - hex!["98f4d81cb383898c2c3d54dab28698c0f717c81b509cb32dc6905af3cc697b18"] - .unchecked_into(), - //5CZjurB78XbSHf6SLkLhCdkqw52Zm7aBYUDdfkLqEDWJ9Zhj - hex!["162508accd470e379b04cb0c7c60b35a7d5357e84407a89ed2dd48db4b726960"] - .unchecked_into(), - //5DkAqCtSjUMVoJFauuGoAbSEgn2aFCRGziKJiLGpPwYgE1pS - hex!["4a559c028b69a7f784ce553393e547bec0aa530352157603396d515f9c83463b"] - .unchecked_into(), - //5GsBt9MhGwkg8Jfb1F9LAy2kcr88WNyNy4L5ezwbCr8NWKQU - hex!["d464908266c878acbf181bf8fda398b3aa3fd2d05508013e414aaece4cf0d702"] - .unchecked_into(), - //5DtJVkz8AHevEnpszy3X4dUcPvACW6x1qBMQZtFxjexLr5bq - hex!["02fdf30222d2cb88f2376d558d3de9cb83f9fde3aa4b2dd40c93e3104e3488bcd2"] - .unchecked_into(), - ), - ( - //5E2cob2jrXsBkTih56pizwSqENjE4siaVdXhaD6akLdDyVq7 - hex!["56e0f73c563d49ee4a3971c393e17c44eaa313dabad7fcf297dc3271d803f303"].into(), - //5D4rNYgP9uFNi5GMyDEXTfiaFLjXyDEEX2VvuqBVi3f1qgCh - hex!["2c58e5e1d5aef77774480cead4f6876b1a1a6261170166995184d7f86140572b"].into(), - //5Ea2D65KXqe625sz4uV1jjhSfuigVnkezC8VgEj9LXN7ERAk - hex!["6ed45cb7af613be5d88a2622921e18d147225165f24538af03b93f2a03ce6e13"] - .unchecked_into(), - //5G4kCbgqUhEyrRHCyFwFEkgBZXoYA8sbgsRxT9rY8Tp5Jj5F - hex!["b0f8d2b9e4e1eafd4dab6358e0b9d5380d78af27c094e69ae9d6d30ca300fd86"] - .unchecked_into(), - //5CS7thd2n54WfqeKU3cjvZzK4z5p7zku1Zw97mSzXgPioAAs - hex!["1055100a283968271a0781450b389b9093231be809be1e48a305ebad2a90497e"] - .unchecked_into(), - //5DSaL4ZmSYarZSazhL5NQh7LT6pWhNRDcefk2QS9RxEXfsJe - hex!["3cea4ab74bab4adf176cf05a6e18c1599a7bc217d4c6c217275bfbe3b037a527"] - .unchecked_into(), - //5CaNLkYEbFYXZodXhd3UjV6RNLjFGNLiYafc8X5NooMkZiAq - hex!["169faa81aebfe74533518bda28567f2e2664014c8905aa07ea003336afda5a58"] - .unchecked_into(), - //5ERwhKiePayukzZStMuzGzRJGxGRFpwxYUXVarQpMSMrXzDS - hex!["03429d0d20f6ac5ca8b349f04d014f7b5b864acf382a744104d5d9a51108156c0f"] - .unchecked_into(), - ), - ( - //5H6j9ovzYk9opckVjvM9SvVfaK37ASTtPTzWeRfqk1tgLJUN - hex!["deb804ed2ed2bb696a3dd4ed7de4cd5c496528a2b204051c6ace385bacd66a3a"].into(), - //5DJ51tMW916mGwjMpfS1o9skcNt6Sb28YnZQXaKVg4h89agE - hex!["366da6a748afedb31f07902f2de36ab265beccee37762d3ae1f237de234d9c36"].into(), - //5CSPYDYoCDGSoSLgSp4EHkJ52YasZLHG2woqhPZkdbtNQpke - hex!["1089bc0cd60237d061872925e81d36c9d9205d250d5d8b542c8e08a8ecf1b911"] - .unchecked_into(), - //5ChfdrAqmLjCeDJvynbMjcxYLHYzPe8UWXd3HnX9JDThUMbn - hex!["1c309a70b4e274314b84c9a0a1f973c9c4fc084df5479ef686c54b1ae4950424"] - .unchecked_into(), - //5D8C3HHEp5E8fJsXRD56494F413CdRSR9QKGXe7v5ZEfymdj - hex!["2ee4d78f328db178c54f205ac809da12e291a33bcbd4f29f081ce7e74bdc5044"] - .unchecked_into(), - //5GxeTYCGmp1C3ZRLDkRWqJc6gB2GYmuqnygweuH3vsivMQq6 - hex!["d88e40e3c2c7a7c5abf96ffdd8f7b7bec8798cc277bc97e255881871ab73b529"] - .unchecked_into(), - //5DoGpsgSLcJsHa9B8V4PKjxegWAqDZttWfxicAd68prUX654 - hex!["4cb3863271b70daa38612acd5dae4f5afcb7c165fa277629e5150d2214df322a"] - .unchecked_into(), - //5G1KLjqFyMsPAodnjSRkwRFJztTTEzmZWxow2Q3ZSRCPdthM - hex!["03be5ec86d10a94db89c9b7a396d3c7742e3bec5f85159d4cf308cef505966ddf5"] - .unchecked_into(), - ), - ]; - - const ENDOWMENT: u128 = 1_000_000 * WND; - const STASH: u128 = 100 * WND; - - serde_json::json!({ - "balances": { - "balances": endowed_accounts - .iter() - .map(|k: &AccountId| (k.clone(), ENDOWMENT)) - .chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH))) - .collect::>(), - }, - "session": { - "keys": initial_authorities - .iter() - .map(|x| { - ( - x.0.clone(), - x.0.clone(), - westend_session_keys( - x.2.clone(), - x.3.clone(), - x.4.clone(), - x.5.clone(), - x.6.clone(), - x.7.clone(), - ), - ) - }) - .collect::>(), - }, - "staking": { - "validatorCount": 50, - "minimumValidatorCount": 4, - "stakers": initial_authorities - .iter() - .map(|x| (x.0.clone(), x.0.clone(), STASH, westend::StakerStatus::::Validator)) - .collect::>(), - "invulnerables": initial_authorities.iter().map(|x| x.0.clone()).collect::>(), - "forceEra": Forcing::ForceNone, - "slashRewardFraction": Perbill::from_percent(10), - }, - "babe": { - "epochConfig": Some(westend::BABE_GENESIS_EPOCH_CONFIG), - }, - "sudo": { "key": Some(endowed_accounts[0].clone()) }, - "configuration": { - "config": default_parachains_host_configuration(), - }, - "registrar": { - "nextFreeParaId": polkadot_primitives::LOWEST_PUBLIC_ID, - }, - }) -} - /// Westend staging testnet config. #[cfg(feature = "westend-native")] pub fn westend_staging_testnet_config() -> Result { @@ -383,7 +104,7 @@ pub fn westend_staging_testnet_config() -> Result { .with_name("Westend Staging Testnet") .with_id("westend_staging_testnet") .with_chain_type(ChainType::Live) - .with_genesis_config_patch(westend_staging_testnet_config_genesis()) + .with_genesis_config_preset_name("staging_testnet") .with_telemetry_endpoints( TelemetryEndpoints::new(vec![(WESTEND_STAGING_TELEMETRY_URL.to_string(), 0)]) .expect("Westend Staging telemetry url is valid; qed"), @@ -442,148 +163,6 @@ pub fn versi_staging_testnet_config() -> Result { .build()) } -/// Helper function to generate a crypto pair from seed -pub fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() -} - -/// Helper function to generate an account ID from seed -pub fn get_account_id_from_seed(seed: &str) -> AccountId -where - AccountPublic: From<::Public>, -{ - AccountPublic::from(get_from_seed::(seed)).into_account() -} - -/// Helper function to generate stash, controller and session key from seed -pub fn get_authority_keys_from_seed( - seed: &str, -) -> ( - AccountId, - AccountId, - BabeId, - GrandpaId, - ValidatorId, - AssignmentId, - AuthorityDiscoveryId, - BeefyId, -) { - let keys = get_authority_keys_from_seed_no_beefy(seed); - (keys.0, keys.1, keys.2, keys.3, keys.4, keys.5, keys.6, get_from_seed::(seed)) -} - -/// Helper function to generate stash, controller and session key from seed -pub fn get_authority_keys_from_seed_no_beefy( - seed: &str, -) -> (AccountId, AccountId, BabeId, GrandpaId, ValidatorId, AssignmentId, AuthorityDiscoveryId) { - ( - get_account_id_from_seed::(&format!("{}//stash", seed)), - get_account_id_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - ) -} - -#[cfg(feature = "westend-native")] -fn testnet_accounts() -> Vec { - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ] -} - -/// Helper function to create westend runtime `GenesisConfig` patch for testing -#[cfg(feature = "westend-native")] -pub fn westend_testnet_genesis( - initial_authorities: Vec<( - AccountId, - AccountId, - BabeId, - GrandpaId, - ValidatorId, - AssignmentId, - AuthorityDiscoveryId, - BeefyId, - )>, - root_key: AccountId, - endowed_accounts: Option>, -) -> serde_json::Value { - let endowed_accounts: Vec = endowed_accounts.unwrap_or_else(testnet_accounts); - - const ENDOWMENT: u128 = 1_000_000 * WND; - const STASH: u128 = 100 * WND; - - serde_json::json!({ - "balances": { - "balances": endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect::>(), - }, - "session": { - "keys": initial_authorities - .iter() - .map(|x| { - ( - x.0.clone(), - x.0.clone(), - westend_session_keys( - x.2.clone(), - x.3.clone(), - x.4.clone(), - x.5.clone(), - x.6.clone(), - x.7.clone(), - ), - ) - }) - .collect::>(), - }, - "staking": { - "minimumValidatorCount": 1, - "validatorCount": initial_authorities.len() as u32, - "stakers": initial_authorities - .iter() - .map(|x| (x.0.clone(), x.0.clone(), STASH, westend::StakerStatus::::Validator)) - .collect::>(), - "invulnerables": initial_authorities.iter().map(|x| x.0.clone()).collect::>(), - "forceEra": Forcing::NotForcing, - "slashRewardFraction": Perbill::from_percent(10), - }, - "babe": { - "epochConfig": Some(westend::BABE_GENESIS_EPOCH_CONFIG), - }, - "sudo": { "key": Some(root_key) }, - "configuration": { - "config": default_parachains_host_configuration(), - }, - "registrar": { - "nextFreeParaId": polkadot_primitives::LOWEST_PUBLIC_ID, - }, - }) -} - -#[cfg(feature = "westend-native")] -fn westend_development_config_genesis() -> serde_json::Value { - westend_testnet_genesis( - vec![get_authority_keys_from_seed("Alice")], - get_account_id_from_seed::("Alice"), - None, - ) -} - /// Westend development config (single validator Alice) #[cfg(feature = "westend-native")] pub fn westend_development_config() -> Result { @@ -594,7 +173,7 @@ pub fn westend_development_config() -> Result { .with_name("Development") .with_id("westend_dev") .with_chain_type(ChainType::Development) - .with_genesis_config_patch(westend_development_config_genesis()) + .with_genesis_config_preset_name(sp_genesis_builder::DEV_RUNTIME_PRESET) .with_protocol_id(DEFAULT_PROTOCOL_ID) .build()) } @@ -609,7 +188,7 @@ pub fn rococo_development_config() -> Result { .with_name("Development") .with_id("rococo_dev") .with_chain_type(ChainType::Development) - .with_genesis_config_preset_name("development") + .with_genesis_config_preset_name(sp_genesis_builder::DEV_RUNTIME_PRESET) .with_protocol_id(DEFAULT_PROTOCOL_ID) .build()) } @@ -624,47 +203,23 @@ pub fn versi_development_config() -> Result { .with_name("Development") .with_id("versi_dev") .with_chain_type(ChainType::Development) - .with_genesis_config_preset_name("development") + .with_genesis_config_preset_name(sp_genesis_builder::DEV_RUNTIME_PRESET) .with_protocol_id("versi") .build()) } -/// Wococo development config (single validator Alice) -#[cfg(feature = "rococo-native")] -pub fn wococo_development_config() -> Result { - const WOCOCO_DEV_PROTOCOL_ID: &str = "woco"; - Ok(RococoChainSpec::builder( - rococo::WASM_BINARY.ok_or("Wococo development wasm not available")?, - Default::default(), - ) - .with_name("Development") - .with_id("wococo_dev") - .with_chain_type(ChainType::Development) - .with_genesis_config_preset_name("development") - .with_protocol_id(WOCOCO_DEV_PROTOCOL_ID) - .build()) -} - -#[cfg(feature = "westend-native")] -fn westend_local_testnet_genesis() -> serde_json::Value { - westend_testnet_genesis( - vec![get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob")], - get_account_id_from_seed::("Alice"), - None, - ) -} - /// Westend local testnet config (multivalidator Alice + Bob) #[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") .with_id("westend_local_testnet") .with_chain_type(ChainType::Local) - .with_genesis_config_patch(westend_local_testnet_genesis()) + .with_genesis_config_preset_name(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) .with_protocol_id(DEFAULT_PROTOCOL_ID) .build()) } @@ -679,22 +234,7 @@ pub fn rococo_local_testnet_config() -> Result { .with_name("Rococo Local Testnet") .with_id("rococo_local_testnet") .with_chain_type(ChainType::Local) - .with_genesis_config_preset_name("local_testnet") - .with_protocol_id(DEFAULT_PROTOCOL_ID) - .build()) -} - -/// Wococo local testnet config (multivalidator Alice + Bob + Charlie + Dave) -#[cfg(feature = "rococo-native")] -pub fn wococo_local_testnet_config() -> Result { - Ok(RococoChainSpec::builder( - rococo::WASM_BINARY.ok_or("Rococo development wasm (used for wococo) not available")?, - Default::default(), - ) - .with_name("Wococo Local Testnet") - .with_id("wococo_local_testnet") - .with_chain_type(ChainType::Local) - .with_genesis_config_preset_name("wococo_local_testnet") + .with_genesis_config_preset_name(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) .with_protocol_id(DEFAULT_PROTOCOL_ID) .build()) } diff --git a/polkadot/node/service/src/fake_runtime_api.rs b/polkadot/node/service/src/fake_runtime_api.rs index e971830c95cb..d8f147a9cf7b 100644 --- a/polkadot/node/service/src/fake_runtime_api.rs +++ b/polkadot/node/service/src/fake_runtime_api.rs @@ -21,12 +21,16 @@ use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo}; use polkadot_primitives::{ - runtime_api, slashing, AccountId, AuthorityDiscoveryId, Balance, Block, BlockNumber, - CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreState, - DisputeState, ExecutorParams, GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, - InboundHrmpMessage, Nonce, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, - ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, - ValidatorId, ValidatorIndex, ValidatorSignature, + runtime_api, slashing, + vstaging::{ + CandidateEvent, CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CoreState, + ScrapedOnChainVotes, + }, + AccountId, AuthorityDiscoveryId, Balance, Block, BlockNumber, CandidateCommitments, + CandidateHash, DisputeState, ExecutorParams, GroupRotationInfo, Hash, Id as ParaId, + InboundDownwardMessage, InboundHrmpMessage, Nonce, OccupiedCoreAssumption, + PersistedValidationData, PvfCheckStatement, SessionIndex, SessionInfo, ValidationCode, + ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, }; use sp_consensus_beefy::ecdsa_crypto::{AuthorityId as BeefyId, Signature as BeefySignature}; use sp_consensus_grandpa::AuthorityId as GrandpaId; @@ -49,6 +53,7 @@ sp_api::decl_runtime_apis! { } } +#[allow(dead_code)] struct Runtime; sp_api::impl_runtime_apis! { @@ -252,12 +257,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 b4f63bd2aa06..da3ab760ed22 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -59,10 +59,10 @@ use { sc_client_api::BlockBackend, sc_consensus_grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider}, sc_transaction_pool_api::OffchainTransactionPoolFactory, - sp_core::traits::SpawnNamed, }; use polkadot_node_subsystem_util::database::Database; +use polkadot_overseer::SpawnGlue; #[cfg(feature = "full-node")] pub use { @@ -75,15 +75,12 @@ pub use { sp_consensus_babe::BabeApi, }; -#[cfg(feature = "full-node")] -use polkadot_node_subsystem::jaeger; - use std::{collections::HashMap, path::PathBuf, sync::Arc, time::Duration}; use prometheus_endpoint::Registry; #[cfg(feature = "full-node")] use sc_service::KeystoreContainer; -use sc_service::RpcHandlers; +use sc_service::{build_polkadot_syncing_strategy, RpcHandlers, SpawnTaskHandle}; use sc_telemetry::TelemetryWorker; #[cfg(feature = "full-node")] use sc_telemetry::{Telemetry, TelemetryWorkerHandle}; @@ -221,9 +218,6 @@ pub enum Error { #[error(transparent)] Telemetry(#[from] sc_telemetry::Error), - #[error(transparent)] - Jaeger(#[from] polkadot_node_subsystem::jaeger::JaegerError), - #[cfg(feature = "full-node")] #[error(transparent)] Availability(#[from] AvailabilityError), @@ -289,9 +283,6 @@ pub trait IdentifyVariant { /// Returns if this is a configuration for the `Rococo` network. fn is_rococo(&self) -> bool; - /// Returns if this is a configuration for the `Wococo` test network. - fn is_wococo(&self) -> bool; - /// Returns if this is a configuration for the `Versi` test network. fn is_versi(&self) -> bool; @@ -315,9 +306,6 @@ impl IdentifyVariant for Box { fn is_rococo(&self) -> bool { self.id().starts_with("rococo") || self.id().starts_with("rco") } - fn is_wococo(&self) -> bool { - self.id().starts_with("wococo") || self.id().starts_with("wco") - } fn is_versi(&self) -> bool { self.id().starts_with("versi") || self.id().starts_with("vrs") } @@ -331,7 +319,7 @@ impl IdentifyVariant for Box { Chain::Kusama } else if self.is_westend() { Chain::Westend - } else if self.is_rococo() || self.is_versi() || self.is_wococo() { + } else if self.is_rococo() || self.is_versi() { Chain::Rococo } else { Chain::Unknown @@ -370,25 +358,6 @@ pub fn open_database(db_source: &DatabaseSource) -> Result, Er Ok(parachains_db) } -/// Initialize the `Jeager` collector. The destination must listen -/// on the given address and port for `UDP` packets. -#[cfg(any(test, feature = "full-node"))] -fn jaeger_launch_collector_with_agent( - spawner: impl SpawnNamed, - config: &Configuration, - agent: Option, -) -> Result<(), Error> { - if let Some(agent) = agent { - let cfg = jaeger::JaegerConfig::builder() - .agent(agent) - .named(&config.network.node_name) - .build(); - - jaeger::Jaeger::new(cfg).launch(spawner)?; - } - Ok(()) -} - #[cfg(feature = "full-node")] type FullSelectChain = relay_chain_selection::SelectRelayChain; #[cfg(feature = "full-node")] @@ -416,7 +385,6 @@ struct Basics { #[cfg(feature = "full-node")] fn new_partial_basics( config: &mut Configuration, - jaeger_agent: Option, telemetry_worker_handle: Option, ) -> Result { let telemetry = config @@ -437,15 +405,16 @@ fn new_partial_basics( .transpose()?; let heap_pages = config + .executor .default_heap_pages .map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| HeapAllocStrategy::Static { extra_pages: h as _ }); let executor = WasmExecutor::builder() - .with_execution_method(config.wasm_method) + .with_execution_method(config.executor.wasm_method) .with_onchain_heap_alloc_strategy(heap_pages) .with_offchain_heap_alloc_strategy(heap_pages) - .with_max_runtime_instances(config.max_runtime_instances) - .with_runtime_cache_size(config.runtime_cache_size) + .with_max_runtime_instances(config.executor.max_runtime_instances) + .with_runtime_cache_size(config.executor.runtime_cache_size) .build(); let (client, backend, keystore_container, task_manager) = @@ -467,8 +436,6 @@ fn new_partial_basics( telemetry }); - jaeger_launch_collector_with_agent(task_manager.spawn_handle(), &*config, jaeger_agent)?; - Ok(Basics { task_manager, client, backend, keystore_container, telemetry }) } @@ -483,10 +450,9 @@ fn new_partial( FullBackend, ChainSelection, sc_consensus::DefaultImportQueue, - sc_transaction_pool::FullPool, + sc_transaction_pool::TransactionPoolHandle, ( impl Fn( - polkadot_rpc::DenyUnsafe, polkadot_rpc::SubscriptionTaskExecutor, ) -> Result, ( @@ -512,12 +478,15 @@ fn new_partial( where ChainSelection: 'static + SelectChain, { - let transaction_pool = sc_transaction_pool::BasicPool::new_full( - config.transaction_pool.clone(), - config.role.is_authority().into(), - config.prometheus_registry(), - task_manager.spawn_essential_handle(), - client.clone(), + let transaction_pool = Arc::from( + sc_transaction_pool::Builder::new( + task_manager.spawn_essential_handle(), + client.clone(), + config.role.is_authority().into(), + ) + .with_options(config.transaction_pool.clone()) + .with_prometheus(config.prometheus_registry()) + .build(), ); let grandpa_hard_forks = if config.chain_spec.is_kusama() { @@ -593,15 +562,13 @@ where let chain_spec = config.chain_spec.cloned_box(); let backend = backend.clone(); - move |deny_unsafe, - subscription_executor: polkadot_rpc::SubscriptionTaskExecutor| + move |subscription_executor: polkadot_rpc::SubscriptionTaskExecutor| -> Result { let deps = polkadot_rpc::FullDeps { client: client.clone(), pool: transaction_pool.clone(), select_chain: select_chain.clone(), chain_spec: chain_spec.cloned_box(), - deny_unsafe, babe: polkadot_rpc::BabeDeps { babe_worker_handle: babe_worker_handle.clone(), keystore: keystore.clone(), @@ -644,7 +611,6 @@ pub struct NewFullParams { /// Whether to enable the block authoring backoff on production networks /// where it isn't enabled by default. pub force_authoring_backoff: bool, - pub jaeger_agent: Option, pub telemetry_worker_handle: Option, /// The version of the node. TESTING ONLY: `None` can be passed to skip the node/worker version /// check, both on startup and in the workers. @@ -667,6 +633,8 @@ pub struct NewFullParams { #[allow(dead_code)] pub malus_finality_delay: Option, pub hwbench: Option, + /// Enable approval voting processing in parallel. + pub enable_approval_voting_parallel: bool, } #[cfg(feature = "full-node")] @@ -747,7 +715,6 @@ pub fn new_full< is_parachain_node, enable_beefy, force_authoring_backoff, - jaeger_agent, telemetry_worker_handle, node_version, secure_validator_mode, @@ -760,14 +727,16 @@ pub fn new_full< execute_workers_max_num, prepare_workers_soft_max_num, prepare_workers_hard_max_num, + enable_approval_voting_parallel, }: NewFullParams, ) -> Result { use polkadot_availability_recovery::FETCH_CHUNKS_THRESHOLD; use polkadot_node_network_protocol::request_response::IncomingRequest; - use sc_network_sync::WarpSyncParams; + use sc_network_sync::WarpSyncConfig; + use sc_sysinfo::Metric; let is_offchain_indexing_enabled = config.offchain_worker.indexing_enabled; - let role = config.role.clone(); + let role = config.role; let force_authoring = config.force_authoring; let backoff_authoring_blocks = if !force_authoring_backoff && (config.chain_spec.is_polkadot() || config.chain_spec.is_kusama()) @@ -778,7 +747,6 @@ pub fn new_full< let mut backoff = sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging::default(); if config.chain_spec.is_rococo() || - config.chain_spec.is_wococo() || config.chain_spec.is_versi() || config.chain_spec.is_dev() { @@ -791,18 +759,24 @@ pub fn new_full< Some(backoff) }; + // Running approval voting in parallel is enabled by default on all networks except Polkadot and + // Kusama, unless explicitly enabled by the commandline option. + // This is meant to be temporary until we have enough confidence in the new system to enable it + // by default on all networks. + let enable_approval_voting_parallel = (!config.chain_spec.is_kusama() && + !config.chain_spec.is_polkadot()) || + enable_approval_voting_parallel; + let disable_grandpa = config.disable_grandpa; let name = config.network.node_name.clone(); - let basics = new_partial_basics(&mut config, jaeger_agent, telemetry_worker_handle)?; + let basics = new_partial_basics(&mut config, telemetry_worker_handle)?; let prometheus_registry = config.prometheus_registry().cloned(); let overseer_connector = OverseerConnector::default(); let overseer_handle = Handle::new(overseer_connector.handle()); - let chain_spec = config.chain_spec.cloned_box(); - let keystore = basics.keystore_container.local_keystore(); let auth_or_collator = role.is_authority() || is_parachain_node.is_collator(); @@ -815,6 +789,7 @@ pub fn new_full< overseer_handle.clone(), metrics, Some(basics.task_manager.spawn_handle()), + enable_approval_voting_parallel, ) } else { SelectRelayChain::new_longest_chain(basics.backend.clone()) @@ -838,8 +813,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(); @@ -1023,9 +1000,20 @@ pub fn new_full< dispute_coordinator_config, chain_selection_config, fetch_chunks_threshold, + enable_approval_voting_parallel, }) }; + let syncing_strategy = build_polkadot_syncing_strategy( + config.protocol_id(), + config.chain_spec.fork_id(), + &mut net_config, + Some(WarpSyncConfig::WithProvider(warp_sync)), + client.clone(), + &task_manager.spawn_handle(), + config.prometheus_config.as_ref().map(|config| &config.registry), + )?; + let (network, system_rpc_tx, tx_handler_controller, network_starter, sync_service) = sc_service::build_network(sc_service::BuildNetworkParams { config: &config, @@ -1035,7 +1023,7 @@ pub fn new_full< spawn_handle: task_manager.spawn_handle(), import_queue, block_announce_validator_builder: None, - warp_sync_params: Some(WarpSyncParams::WithProvider(warp_sync)), + syncing_strategy, block_relay: None, metrics, })?; @@ -1080,13 +1068,31 @@ pub fn new_full< if let Some(hwbench) = hwbench { sc_sysinfo::print_hwbench(&hwbench); - match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) { + match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench, role.is_authority()) { Err(err) if role.is_authority() => { - log::warn!( - "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority' find out more at:\n\ - https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", - err - ); + if err + .0 + .iter() + .any(|failure| matches!(failure.metric, Metric::Blake2256Parallel { .. })) + { + log::warn!( + "⚠️ Starting January 2025 the hardware will fail the minimal physical CPU cores requirements {} for role 'Authority',\n\ + find out more when this will become mandatory at:\n\ + https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", + err + ); + } + if err + .0 + .iter() + .any(|failure| !matches!(failure.metric, Metric::Blake2256Parallel { .. })) + { + log::warn!( + "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority' find out more at:\n\ + https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", + err + ); + } }, _ => {}, } @@ -1297,7 +1303,7 @@ pub fn new_full< runtime: client.clone(), key_store: keystore_opt.clone(), network_params, - min_block_delta: if chain_spec.is_wococo() { 4 } else { 8 }, + min_block_delta: 8, prometheus_registry: prometheus_registry.clone(), links: beefy_links, on_demand_justifications_handler: beefy_on_demand_justifications_handler, @@ -1403,11 +1409,10 @@ pub fn new_full< #[cfg(feature = "full-node")] macro_rules! chain_ops { - ($config:expr, $jaeger_agent:expr, $telemetry_worker_handle:expr) => {{ + ($config:expr, $telemetry_worker_handle:expr) => {{ let telemetry_worker_handle = $telemetry_worker_handle; - let jaeger_agent = $jaeger_agent; let mut config = $config; - let basics = new_partial_basics(config, jaeger_agent, telemetry_worker_handle)?; + let basics = new_partial_basics(config, telemetry_worker_handle)?; use ::sc_consensus::LongestChain; // use the longest chain selection, since there is no overseer available @@ -1423,22 +1428,18 @@ macro_rules! chain_ops { #[cfg(feature = "full-node")] pub fn new_chain_ops( config: &mut Configuration, - jaeger_agent: Option, ) -> Result<(Arc, Arc, sc_consensus::BasicQueue, TaskManager), Error> { config.keystore = sc_service::config::KeystoreConfig::InMemory; - if config.chain_spec.is_rococo() || - config.chain_spec.is_wococo() || - config.chain_spec.is_versi() - { - chain_ops!(config, jaeger_agent, None) + if config.chain_spec.is_rococo() || config.chain_spec.is_versi() { + chain_ops!(config, None) } else if config.chain_spec.is_kusama() { - chain_ops!(config, jaeger_agent, None) + chain_ops!(config, None) } else if config.chain_spec.is_westend() { - return chain_ops!(config, jaeger_agent, None) + return chain_ops!(config, None) } else { - chain_ops!(config, jaeger_agent, None) + chain_ops!(config, None) } } @@ -1481,6 +1482,7 @@ pub fn revert_backend( backend: Arc, blocks: BlockNumber, config: Configuration, + task_handle: SpawnTaskHandle, ) -> Result<(), Error> { let best_number = client.info().best_number; let finalized = client.info().finalized_number; @@ -1501,7 +1503,7 @@ pub fn revert_backend( let parachains_db = open_database(&config.database) .map_err(|err| sp_blockchain::Error::Backend(err.to_string()))?; - revert_approval_voting(parachains_db.clone(), hash)?; + revert_approval_voting(parachains_db.clone(), hash, task_handle)?; revert_chain_selection(parachains_db, hash)?; // Revert Substrate consensus related components sc_consensus_babe::revert(client.clone(), backend, blocks)?; @@ -1524,7 +1526,11 @@ fn revert_chain_selection(db: Arc, hash: Hash) -> sp_blockchain::R .map_err(|err| sp_blockchain::Error::Backend(err.to_string())) } -fn revert_approval_voting(db: Arc, hash: Hash) -> sp_blockchain::Result<()> { +fn revert_approval_voting( + db: Arc, + hash: Hash, + task_handle: SpawnTaskHandle, +) -> sp_blockchain::Result<()> { let config = approval_voting_subsystem::Config { col_approval_data: parachains_db::REAL_COLUMNS.col_approval_data, slot_duration_millis: Default::default(), @@ -1536,6 +1542,7 @@ fn revert_approval_voting(db: Arc, hash: Hash) -> sp_blockchain::R Arc::new(sc_keystore::LocalKeystore::in_memory()), Box::new(sp_consensus::NoNetwork), approval_voting_subsystem::Metrics::default(), + Arc::new(SpawnGlue(task_handle)), ); approval_voting diff --git a/polkadot/node/service/src/overseer.rs b/polkadot/node/service/src/overseer.rs index 5f4db99b00ef..279b6ff80704 100644 --- a/polkadot/node/service/src/overseer.rs +++ b/polkadot/node/service/src/overseer.rs @@ -20,7 +20,7 @@ use polkadot_overseer::{DummySubsystem, InitializedOverseerBuilder, SubsystemErr use sp_core::traits::SpawnNamed; use polkadot_availability_distribution::IncomingRequestReceivers; -use polkadot_node_core_approval_voting::Config as ApprovalVotingConfig; +use polkadot_node_core_approval_voting::{Config as ApprovalVotingConfig, RealAssignmentCriteria}; use polkadot_node_core_av_store::Config as AvailabilityConfig; use polkadot_node_core_candidate_validation::Config as CandidateValidationConfig; use polkadot_node_core_chain_selection::Config as ChainSelectionConfig; @@ -58,6 +58,9 @@ pub use polkadot_network_bridge::{ }; pub use polkadot_node_collation_generation::CollationGenerationSubsystem; pub use polkadot_node_core_approval_voting::ApprovalVotingSubsystem; +pub use polkadot_node_core_approval_voting_parallel::{ + ApprovalVotingParallelSubsystem, Metrics as ApprovalVotingParallelMetrics, +}; pub use polkadot_node_core_av_store::AvailabilityStoreSubsystem; pub use polkadot_node_core_backing::CandidateBackingSubsystem; pub use polkadot_node_core_bitfield_signing::BitfieldSigningSubsystem; @@ -139,9 +142,16 @@ pub struct ExtendedOverseerGenArgs { /// than the value put in here we always try to recovery availability from backers. /// The presence of this parameter here is needed to have different values per chain. pub fetch_chunks_threshold: Option, + /// Enable approval-voting-parallel subsystem and disable the standalone approval-voting and + /// approval-distribution subsystems. + pub enable_approval_voting_parallel: bool, } /// Obtain a prepared validator `Overseer`, that is initialized with all default values. +/// +/// The difference between this function and `validator_with_parallel_overseer_builder` is that this +/// function enables the standalone approval-voting and approval-distribution subsystems +/// and disables the approval-voting-parallel subsystem. pub fn validator_overseer_builder( OverseerGenArgs { runtime_client, @@ -174,6 +184,7 @@ pub fn validator_overseer_builder( dispute_coordinator_config, chain_selection_config, fetch_chunks_threshold, + enable_approval_voting_parallel, }: ExtendedOverseerGenArgs, ) -> Result< InitializedOverseerBuilder< @@ -203,6 +214,7 @@ pub fn validator_overseer_builder( CollatorProtocolSubsystem, ApprovalDistributionSubsystem, ApprovalVotingSubsystem, + DummySubsystem, GossipSupportSubsystem, DisputeCoordinatorSubsystem, DisputeDistributionSubsystem, @@ -223,7 +235,8 @@ where let spawner = SpawnGlue(spawner); let network_bridge_metrics: NetworkBridgeMetrics = Metrics::register(registry)?; - + let approval_voting_parallel_metrics: ApprovalVotingParallelMetrics = + Metrics::register(registry)?; let builder = Overseer::builder() .network_bridge_tx(NetworkBridgeTxSubsystem::new( network_service.clone(), @@ -241,6 +254,7 @@ where peerset_protocol_names, notification_services, notification_sinks, + enable_approval_voting_parallel, )) .availability_distribution(AvailabilityDistributionSubsystem::new( keystore.clone(), @@ -275,6 +289,7 @@ where )) .candidate_validation(CandidateValidationSubsystem::with_config( candidate_validation_config, + keystore.clone(), Metrics::register(registry)?, // candidate-validation metrics Metrics::register(registry)?, // validation host metrics )) @@ -308,14 +323,241 @@ where Metrics::register(registry)?, rand::rngs::StdRng::from_entropy(), )) - .approval_distribution(ApprovalDistributionSubsystem::new(Metrics::register(registry)?)) + .approval_distribution(ApprovalDistributionSubsystem::new( + approval_voting_parallel_metrics.approval_distribution_metrics(), + approval_voting_config.slot_duration_millis, + Arc::new(RealAssignmentCriteria {}), + )) .approval_voting(ApprovalVotingSubsystem::with_config( - approval_voting_config, + approval_voting_config.clone(), parachains_db.clone(), keystore.clone(), Box::new(sync_service.clone()), + approval_voting_parallel_metrics.approval_voting_metrics(), + Arc::new(spawner.clone()), + )) + .approval_voting_parallel(DummySubsystem) + .gossip_support(GossipSupportSubsystem::new( + keystore.clone(), + authority_discovery_service.clone(), Metrics::register(registry)?, )) + .dispute_coordinator(DisputeCoordinatorSubsystem::new( + parachains_db.clone(), + dispute_coordinator_config, + keystore.clone(), + Metrics::register(registry)?, + enable_approval_voting_parallel, + )) + .dispute_distribution(DisputeDistributionSubsystem::new( + keystore.clone(), + dispute_req_receiver, + authority_discovery_service.clone(), + Metrics::register(registry)?, + )) + .chain_selection(ChainSelectionSubsystem::new(chain_selection_config, parachains_db)) + .prospective_parachains(ProspectiveParachainsSubsystem::new(Metrics::register(registry)?)) + .activation_external_listeners(Default::default()) + .active_leaves(Default::default()) + .supports_parachains(runtime_client) + .metrics(metrics) + .spawner(spawner); + + let builder = if let Some(capacity) = overseer_message_channel_capacity_override { + builder.message_channel_capacity(capacity) + } else { + builder + }; + Ok(builder) +} + +/// Obtain a prepared validator `Overseer`, that is initialized with all default values. +/// +/// The difference between this function and `validator_overseer_builder` is that this +/// function enables the approval-voting-parallel subsystem and disables the standalone +/// approval-voting and approval-distribution subsystems. +pub fn validator_with_parallel_overseer_builder( + OverseerGenArgs { + runtime_client, + network_service, + sync_service, + authority_discovery_service, + collation_req_v1_receiver: _, + collation_req_v2_receiver: _, + available_data_req_receiver, + registry, + spawner, + is_parachain_node, + overseer_message_channel_capacity_override, + req_protocol_names, + peerset_protocol_names, + notification_services, + }: OverseerGenArgs, + ExtendedOverseerGenArgs { + keystore, + parachains_db, + candidate_validation_config, + availability_config, + pov_req_receiver, + chunk_req_v1_receiver, + chunk_req_v2_receiver, + statement_req_receiver, + candidate_req_v2_receiver, + approval_voting_config, + dispute_req_receiver, + dispute_coordinator_config, + chain_selection_config, + fetch_chunks_threshold, + enable_approval_voting_parallel, + }: ExtendedOverseerGenArgs, +) -> Result< + InitializedOverseerBuilder< + SpawnGlue, + Arc, + CandidateValidationSubsystem, + PvfCheckerSubsystem, + CandidateBackingSubsystem, + StatementDistributionSubsystem, + AvailabilityDistributionSubsystem, + AvailabilityRecoverySubsystem, + BitfieldSigningSubsystem, + BitfieldDistributionSubsystem, + ProvisionerSubsystem, + RuntimeApiSubsystem, + AvailabilityStoreSubsystem, + NetworkBridgeRxSubsystem< + Arc, + AuthorityDiscoveryService, + >, + NetworkBridgeTxSubsystem< + Arc, + AuthorityDiscoveryService, + >, + ChainApiSubsystem, + CollationGenerationSubsystem, + CollatorProtocolSubsystem, + DummySubsystem, + DummySubsystem, + ApprovalVotingParallelSubsystem, + GossipSupportSubsystem, + DisputeCoordinatorSubsystem, + DisputeDistributionSubsystem, + ChainSelectionSubsystem, + ProspectiveParachainsSubsystem, + >, + Error, +> +where + RuntimeClient: RuntimeApiSubsystemClient + ChainApiBackend + AuxStore + 'static, + Spawner: 'static + SpawnNamed + Clone + Unpin, +{ + use polkadot_node_subsystem_util::metrics::Metrics; + + let metrics = ::register(registry)?; + let notification_sinks = Arc::new(Mutex::new(HashMap::new())); + + let spawner = SpawnGlue(spawner); + + let network_bridge_metrics: NetworkBridgeMetrics = Metrics::register(registry)?; + let approval_voting_parallel_metrics: ApprovalVotingParallelMetrics = + Metrics::register(registry)?; + let builder = Overseer::builder() + .network_bridge_tx(NetworkBridgeTxSubsystem::new( + network_service.clone(), + authority_discovery_service.clone(), + network_bridge_metrics.clone(), + req_protocol_names.clone(), + peerset_protocol_names.clone(), + notification_sinks.clone(), + )) + .network_bridge_rx(NetworkBridgeRxSubsystem::new( + network_service.clone(), + authority_discovery_service.clone(), + Box::new(sync_service.clone()), + network_bridge_metrics, + peerset_protocol_names, + notification_services, + notification_sinks, + enable_approval_voting_parallel, + )) + .availability_distribution(AvailabilityDistributionSubsystem::new( + keystore.clone(), + IncomingRequestReceivers { + pov_req_receiver, + chunk_req_v1_receiver, + chunk_req_v2_receiver, + }, + req_protocol_names.clone(), + Metrics::register(registry)?, + )) + .availability_recovery(AvailabilityRecoverySubsystem::for_validator( + fetch_chunks_threshold, + available_data_req_receiver, + &req_protocol_names, + Metrics::register(registry)?, + )) + .availability_store(AvailabilityStoreSubsystem::new( + parachains_db.clone(), + availability_config, + Box::new(sync_service.clone()), + Metrics::register(registry)?, + )) + .bitfield_distribution(BitfieldDistributionSubsystem::new(Metrics::register(registry)?)) + .bitfield_signing(BitfieldSigningSubsystem::new( + keystore.clone(), + Metrics::register(registry)?, + )) + .candidate_backing(CandidateBackingSubsystem::new( + keystore.clone(), + Metrics::register(registry)?, + )) + .candidate_validation(CandidateValidationSubsystem::with_config( + candidate_validation_config, + keystore.clone(), + Metrics::register(registry)?, // candidate-validation metrics + Metrics::register(registry)?, // validation host metrics + )) + .pvf_checker(PvfCheckerSubsystem::new(keystore.clone(), Metrics::register(registry)?)) + .chain_api(ChainApiSubsystem::new(runtime_client.clone(), Metrics::register(registry)?)) + .collation_generation(CollationGenerationSubsystem::new(Metrics::register(registry)?)) + .collator_protocol({ + let side = match is_parachain_node { + IsParachainNode::Collator(_) | IsParachainNode::FullNode => + return Err(Error::Overseer(SubsystemError::Context( + "build validator overseer for parachain node".to_owned(), + ))), + IsParachainNode::No => ProtocolSide::Validator { + keystore: keystore.clone(), + eviction_policy: Default::default(), + metrics: Metrics::register(registry)?, + }, + }; + CollatorProtocolSubsystem::new(side) + }) + .provisioner(ProvisionerSubsystem::new(Metrics::register(registry)?)) + .runtime_api(RuntimeApiSubsystem::new( + runtime_client.clone(), + Metrics::register(registry)?, + spawner.clone(), + )) + .statement_distribution(StatementDistributionSubsystem::new( + keystore.clone(), + statement_req_receiver, + candidate_req_v2_receiver, + Metrics::register(registry)?, + rand::rngs::StdRng::from_entropy(), + )) + .approval_distribution(DummySubsystem) + .approval_voting(DummySubsystem) + .approval_voting_parallel(ApprovalVotingParallelSubsystem::with_config( + approval_voting_config, + parachains_db.clone(), + keystore.clone(), + Box::new(sync_service.clone()), + approval_voting_parallel_metrics, + spawner.clone(), + overseer_message_channel_capacity_override, + )) .gossip_support(GossipSupportSubsystem::new( keystore.clone(), authority_discovery_service.clone(), @@ -326,6 +568,7 @@ where dispute_coordinator_config, keystore.clone(), Metrics::register(registry)?, + enable_approval_voting_parallel, )) .dispute_distribution(DisputeDistributionSubsystem::new( keystore.clone(), @@ -336,7 +579,6 @@ where .chain_selection(ChainSelectionSubsystem::new(chain_selection_config, parachains_db)) .prospective_parachains(ProspectiveParachainsSubsystem::new(Metrics::register(registry)?)) .activation_external_listeners(Default::default()) - .span_per_active_leaf(Default::default()) .active_leaves(Default::default()) .supports_parachains(runtime_client) .metrics(metrics) @@ -401,6 +643,7 @@ pub fn collator_overseer_builder( DummySubsystem, DummySubsystem, DummySubsystem, + DummySubsystem, >, Error, > @@ -433,6 +676,7 @@ where peerset_protocol_names, notification_services, notification_sinks, + false, )) .availability_distribution(DummySubsystem) .availability_recovery(AvailabilityRecoverySubsystem::for_collator( @@ -475,13 +719,13 @@ where .statement_distribution(DummySubsystem) .approval_distribution(DummySubsystem) .approval_voting(DummySubsystem) + .approval_voting_parallel(DummySubsystem) .gossip_support(DummySubsystem) .dispute_coordinator(DummySubsystem) .dispute_distribution(DummySubsystem) .chain_selection(DummySubsystem) .prospective_parachains(DummySubsystem) .activation_external_listeners(Default::default()) - .span_per_active_leaf(Default::default()) .active_leaves(Default::default()) .supports_parachains(runtime_client) .metrics(Metrics::register(registry)?) @@ -531,9 +775,15 @@ impl OverseerGen for ValidatorOverseerGen { "create validator overseer as mandatory extended arguments were not provided" .to_owned(), )))?; - validator_overseer_builder(args, ext_args)? - .build_with_connector(connector) - .map_err(|e| e.into()) + if ext_args.enable_approval_voting_parallel { + validator_with_parallel_overseer_builder(args, ext_args)? + .build_with_connector(connector) + .map_err(|e| e.into()) + } else { + validator_overseer_builder(args, ext_args)? + .build_with_connector(connector) + .map_err(|e| e.into()) + } } } diff --git a/polkadot/node/service/src/parachains_db/mod.rs b/polkadot/node/service/src/parachains_db/mod.rs index 59af30dceeb9..887db80a3034 100644 --- a/polkadot/node/service/src/parachains_db/mod.rs +++ b/polkadot/node/service/src/parachains_db/mod.rs @@ -100,18 +100,11 @@ pub struct CacheSizes { pub availability_meta: usize, /// Cache used by approval data. pub approval_data: usize, - /// Cache used by session window data - pub session_data: usize, } impl Default for CacheSizes { fn default() -> Self { - CacheSizes { - availability_data: 25, - availability_meta: 1, - approval_data: 5, - session_data: 1, - } + CacheSizes { availability_data: 25, availability_meta: 1, approval_data: 5 } } } diff --git a/polkadot/node/service/src/relay_chain_selection.rs b/polkadot/node/service/src/relay_chain_selection.rs index c0b1ce8b0ebe..e48874f01ca6 100644 --- a/polkadot/node/service/src/relay_chain_selection.rs +++ b/polkadot/node/service/src/relay_chain_selection.rs @@ -39,8 +39,8 @@ use super::{HeaderProvider, HeaderProviderProvider}; use futures::channel::oneshot; use polkadot_node_primitives::MAX_FINALITY_LAG as PRIMITIVES_MAX_FINALITY_LAG; use polkadot_node_subsystem::messages::{ - ApprovalDistributionMessage, ApprovalVotingMessage, ChainSelectionMessage, - DisputeCoordinatorMessage, HighestApprovedAncestorBlock, + ApprovalDistributionMessage, ApprovalVotingMessage, ApprovalVotingParallelMessage, + ChainSelectionMessage, DisputeCoordinatorMessage, HighestApprovedAncestorBlock, }; use polkadot_node_subsystem_util::metrics::{self, prometheus}; use polkadot_overseer::{AllMessages, Handle}; @@ -169,6 +169,7 @@ where overseer: Handle, metrics: Metrics, spawn_handle: Option, + approval_voting_parallel_enabled: bool, ) -> Self { gum::debug!(target: LOG_TARGET, "Using dispute aware relay-chain selection algorithm",); @@ -179,6 +180,7 @@ where overseer, metrics, spawn_handle, + approval_voting_parallel_enabled, )), } } @@ -230,6 +232,7 @@ pub struct SelectRelayChainInner { overseer: OH, metrics: Metrics, spawn_handle: Option, + approval_voting_parallel_enabled: bool, } impl SelectRelayChainInner @@ -244,8 +247,15 @@ where overseer: OH, metrics: Metrics, spawn_handle: Option, + approval_voting_parallel_enabled: bool, ) -> Self { - SelectRelayChainInner { backend, overseer, metrics, spawn_handle } + SelectRelayChainInner { + backend, + overseer, + metrics, + spawn_handle, + approval_voting_parallel_enabled, + } } fn block_header(&self, hash: Hash) -> Result { @@ -284,6 +294,7 @@ where overseer: self.overseer.clone(), metrics: self.metrics.clone(), spawn_handle: self.spawn_handle.clone(), + approval_voting_parallel_enabled: self.approval_voting_parallel_enabled, } } } @@ -448,13 +459,25 @@ where // 2. Constrain according to `ApprovedAncestor`. let (subchain_head, subchain_number, subchain_block_descriptions) = { let (tx, rx) = oneshot::channel(); - overseer - .send_msg( - ApprovalVotingMessage::ApprovedAncestor(subchain_head, target_number, tx), - std::any::type_name::(), - ) - .await; - + if self.approval_voting_parallel_enabled { + overseer + .send_msg( + ApprovalVotingParallelMessage::ApprovedAncestor( + subchain_head, + target_number, + tx, + ), + std::any::type_name::(), + ) + .await; + } else { + overseer + .send_msg( + ApprovalVotingMessage::ApprovedAncestor(subchain_head, target_number, tx), + std::any::type_name::(), + ) + .await; + } match rx .await .map_err(Error::ApprovedAncestorCanceled) @@ -476,13 +499,23 @@ where // task for sending the message to not block here and delay finality. if let Some(spawn_handle) = &self.spawn_handle { let mut overseer_handle = self.overseer.clone(); + let approval_voting_parallel_enabled = self.approval_voting_parallel_enabled; let lag_update_task = async move { - overseer_handle - .send_msg( - ApprovalDistributionMessage::ApprovalCheckingLagUpdate(lag), - std::any::type_name::(), - ) - .await; + if approval_voting_parallel_enabled { + overseer_handle + .send_msg( + ApprovalVotingParallelMessage::ApprovalCheckingLagUpdate(lag), + std::any::type_name::(), + ) + .await; + } else { + overseer_handle + .send_msg( + ApprovalDistributionMessage::ApprovalCheckingLagUpdate(lag), + std::any::type_name::(), + ) + .await; + } }; spawn_handle.spawn( diff --git a/polkadot/node/service/src/tests.rs b/polkadot/node/service/src/tests.rs index bebd05071013..78bbfcd5444f 100644 --- a/polkadot/node/service/src/tests.rs +++ b/polkadot/node/service/src/tests.rs @@ -63,17 +63,11 @@ struct TestHarness { finality_target_rx: Receiver>, } -#[derive(Default)] -struct HarnessConfig; - 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) = @@ -86,6 +80,7 @@ fn test_harness>( context.sender().clone(), Default::default(), None, + false, ); let target_hash = case_vars.target_block; diff --git a/polkadot/node/subsystem-bench/Cargo.toml b/polkadot/node/subsystem-bench/Cargo.toml index 0325613d25f9..293df9f6e6d5 100644 --- a/polkadot/node/subsystem-bench/Cargo.toml +++ b/polkadot/node/subsystem-bench/Cargo.toml @@ -19,7 +19,11 @@ path = "src/cli/subsystem-bench.rs" # Prevent rustdoc error. Already documented from top-level Cargo.toml. doc = false + [dependencies] +tikv-jemallocator = { features = ["profiling", "unprefixed_malloc_on_supported_platforms"], workspace = true, optional = true } +jemalloc_pprof = { workspace = true, optional = true } +polkadot-service = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } polkadot-node-subsystem-util = { workspace = true, default-features = true } polkadot-node-subsystem-types = { workspace = true, default-features = true } @@ -49,7 +53,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 } @@ -76,6 +80,7 @@ serde_yaml = { workspace = true } serde_json = { workspace = true } polkadot-node-core-approval-voting = { workspace = true, default-features = true } +polkadot-node-core-approval-voting-parallel = { workspace = true, default-features = true } polkadot-approval-distribution = { workspace = true, default-features = true } sp-consensus-babe = { workspace = true, default-features = true } sp-runtime = { workspace = true } @@ -93,3 +98,7 @@ strum = { features = ["derive"], workspace = true, default-features = true } [features] default = [] +memprofile = [ + "dep:jemalloc_pprof", + "dep:tikv-jemallocator", +] diff --git a/polkadot/node/subsystem-bench/README.md b/polkadot/node/subsystem-bench/README.md index 228fba41c46c..8d20f1f49c0e 100644 --- a/polkadot/node/subsystem-bench/README.md +++ b/polkadot/node/subsystem-bench/README.md @@ -260,6 +260,41 @@ This file is best interpreted with `cg_annotate --auto=yes cachegrind.out.` For finer profiling of cache misses, better use `perf` on a bare-metal machine. +### Profile memory usage using jemalloc + +Bellow you can find instructions how to setup and run profiling with jemalloc, this is complementary +with using other memory profiling tools like: . + +#### Prerequisites + +Install tooling with: + +``` +sudo apt install libjemalloc-dev graphviz +``` + +#### Generate memory usage snapshots + +Memory usage can be profiled by running any subsystem benchmark with `--features memprofile`, e.g: + +``` +RUSTFLAGS=-g cargo run -p polkadot-subsystem-bench --release --features memprofile -- polkadot/node/subsystem-bench/examples/approvals_throughput.yaml +``` + +#### Interpret the results + +After the benchmark ran the memory usage snapshots can be found in `/tmp/subsystem-bench*`, to extract the information +from a snapshot you can use `jeprof` like this: + +``` +jeprof --text PATH_TO_EXECUTABLE_WITH_DEBUG_SYMBOLS /tmp/subsystem-bench.1222895.199.i199.heap > statistics.txt +``` + +Useful links: + +- Tutorial: +- Jemalloc configuration options: + ## Create new test objectives This tool is intended to make it easy to write new test objectives that focus individual subsystems, diff --git a/polkadot/node/subsystem-bench/examples/approvals_no_shows.yaml b/polkadot/node/subsystem-bench/examples/approvals_no_shows.yaml index cae1a30914da..1423d324df3f 100644 --- a/polkadot/node/subsystem-bench/examples/approvals_no_shows.yaml +++ b/polkadot/node/subsystem-bench/examples/approvals_no_shows.yaml @@ -9,6 +9,7 @@ TestConfiguration: coalesce_tranche_diff: 12 num_no_shows_per_candidate: 10 workdir_prefix: "/tmp/" + approval_voting_parallel_enabled: false n_validators: 500 n_cores: 100 min_pov_size: 1120 diff --git a/polkadot/node/subsystem-bench/examples/approvals_throughput.yaml b/polkadot/node/subsystem-bench/examples/approvals_throughput.yaml index 7edb48e302a4..87c6103a5d0a 100644 --- a/polkadot/node/subsystem-bench/examples/approvals_throughput.yaml +++ b/polkadot/node/subsystem-bench/examples/approvals_throughput.yaml @@ -9,6 +9,7 @@ TestConfiguration: coalesce_tranche_diff: 12 num_no_shows_per_candidate: 0 workdir_prefix: "/tmp" + approval_voting_parallel_enabled: true n_validators: 500 n_cores: 100 min_pov_size: 1120 diff --git a/polkadot/node/subsystem-bench/examples/approvals_throughput_best_case.yaml b/polkadot/node/subsystem-bench/examples/approvals_throughput_best_case.yaml index 7c24f50e6af5..5e2ea3817d17 100644 --- a/polkadot/node/subsystem-bench/examples/approvals_throughput_best_case.yaml +++ b/polkadot/node/subsystem-bench/examples/approvals_throughput_best_case.yaml @@ -8,6 +8,7 @@ TestConfiguration: stop_when_approved: true coalesce_tranche_diff: 12 num_no_shows_per_candidate: 0 + approval_voting_parallel_enabled: false workdir_prefix: "/tmp/" n_validators: 500 n_cores: 100 diff --git a/polkadot/node/subsystem-bench/src/cli/subsystem-bench.rs b/polkadot/node/subsystem-bench/src/cli/subsystem-bench.rs index 346a058b9796..0f68b905b4ca 100644 --- a/polkadot/node/subsystem-bench/src/cli/subsystem-bench.rs +++ b/polkadot/node/subsystem-bench/src/cli/subsystem-bench.rs @@ -182,16 +182,20 @@ impl BenchCli { } } +#[cfg(feature = "memprofile")] +#[global_allocator] +static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; + +#[cfg(feature = "memprofile")] +#[allow(non_upper_case_globals)] +#[export_name = "malloc_conf"] +// See https://jemalloc.net/jemalloc.3.html for more information on the configuration options. +pub static malloc_conf: &[u8] = + b"prof:true,prof_active:true,lg_prof_interval:30,lg_prof_sample:21,prof_prefix:/tmp/subsystem-bench\0"; + 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/helpers.rs b/polkadot/node/subsystem-bench/src/lib/approval/helpers.rs index ca58875c8139..a3a475ac6b98 100644 --- a/polkadot/node/subsystem-bench/src/lib/approval/helpers.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/helpers.rs @@ -16,13 +16,16 @@ use crate::configuration::TestAuthorities; use itertools::Itertools; -use polkadot_node_core_approval_voting::time::{Clock, SystemClock, Tick}; use polkadot_node_network_protocol::{ grid_topology::{SessionGridTopology, TopologyPeerInfo}, View, }; +use polkadot_node_primitives::approval::time::{Clock, SystemClock, Tick}; +use polkadot_node_subsystem::messages::{ + ApprovalDistributionMessage, ApprovalVotingParallelMessage, +}; use polkadot_node_subsystem_types::messages::{ - network_bridge_event::NewGossipTopology, ApprovalDistributionMessage, NetworkBridgeEvent, + network_bridge_event::NewGossipTopology, NetworkBridgeEvent, }; use polkadot_overseer::AllMessages; use polkadot_primitives::{ @@ -121,6 +124,7 @@ pub fn generate_topology(test_authorities: &TestAuthorities) -> SessionGridTopol pub fn generate_new_session_topology( test_authorities: &TestAuthorities, test_node: ValidatorIndex, + approval_voting_parallel_enabled: bool, ) -> Vec { let topology = generate_topology(test_authorities); @@ -129,14 +133,29 @@ pub fn generate_new_session_topology( topology, local_index: Some(test_node), }); - vec![AllMessages::ApprovalDistribution(ApprovalDistributionMessage::NetworkBridgeUpdate(event))] + vec![if approval_voting_parallel_enabled { + AllMessages::ApprovalVotingParallel(ApprovalVotingParallelMessage::NetworkBridgeUpdate( + event, + )) + } else { + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::NetworkBridgeUpdate(event)) + }] } /// Generates a peer view change for the passed `block_hash` -pub fn generate_peer_view_change_for(block_hash: Hash, peer_id: PeerId) -> AllMessages { +pub fn generate_peer_view_change_for( + block_hash: Hash, + peer_id: PeerId, + approval_voting_parallel_enabled: bool, +) -> AllMessages { let network = NetworkBridgeEvent::PeerViewChange(peer_id, View::new([block_hash], 0)); - - AllMessages::ApprovalDistribution(ApprovalDistributionMessage::NetworkBridgeUpdate(network)) + if approval_voting_parallel_enabled { + AllMessages::ApprovalVotingParallel(ApprovalVotingParallelMessage::NetworkBridgeUpdate( + network, + )) + } else { + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::NetworkBridgeUpdate(network)) + } } /// Helper function to create a a signature for the block header. diff --git a/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs b/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs index 6d3e7dd92db1..807afb0438c9 100644 --- a/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/message_generator.rs @@ -28,16 +28,15 @@ use crate::{ use codec::Encode; use futures::SinkExt; use itertools::Itertools; -use polkadot_node_core_approval_voting::{ - criteria::{compute_assignments, Config}, - time::tranche_to_tick, -}; +use polkadot_node_core_approval_voting::criteria::{compute_assignments, Config}; + use polkadot_node_network_protocol::{ grid_topology::{GridNeighbors, RandomRouting, RequiredRouting, SessionGridTopology}, v3 as protocol_v3, }; use polkadot_node_primitives::approval::{ self, + time::tranche_to_tick, v2::{CoreBitfield, IndirectAssignmentCertV2, IndirectSignedApprovalVoteV2}, }; use polkadot_primitives::{ @@ -402,7 +401,7 @@ impl PeerMessagesGenerator { /// We can not sample every time for all the messages because that would be too expensive to /// perform, so pre-generate a list of samples for a given network size. /// - result[i] give us as a list of random nodes that would send a given message to the node under -/// test. +/// test. fn random_samplings_to_node( node_under_test: ValidatorIndex, num_validators: usize, @@ -475,8 +474,7 @@ fn issue_approvals( coalesce_approvals_len(options.coalesce_mean, options.coalesce_std_dev, rand_chacha); let result = assignments .iter() - .enumerate() - .map(|(_index, message)| match &message.msg { + .map(|message| match &message.msg { protocol_v3::ApprovalDistributionMessage::Assignments(assignments) => { let mut approvals_to_create = Vec::new(); diff --git a/polkadot/node/subsystem-bench/src/lib/approval/mock_chain_selection.rs b/polkadot/node/subsystem-bench/src/lib/approval/mock_chain_selection.rs index 77ba80d4b2bb..709d56d52f0b 100644 --- a/polkadot/node/subsystem-bench/src/lib/approval/mock_chain_selection.rs +++ b/polkadot/node/subsystem-bench/src/lib/approval/mock_chain_selection.rs @@ -16,7 +16,7 @@ use crate::approval::{ApprovalTestState, PastSystemClock, LOG_TARGET, SLOT_DURATION_MILLIS}; use futures::FutureExt; -use polkadot_node_core_approval_voting::time::{slot_number_to_tick, Clock, TICK_DURATION_MILLIS}; +use polkadot_node_primitives::approval::time::{slot_number_to_tick, Clock, TICK_DURATION_MILLIS}; use polkadot_node_subsystem::{overseer, SpawnedSubsystem, SubsystemError}; use polkadot_node_subsystem_types::messages::ChainSelectionMessage; diff --git a/polkadot/node/subsystem-bench/src/lib/approval/mod.rs b/polkadot/node/subsystem-bench/src/lib/approval/mod.rs index 4ac044ea3459..29ebc4a419ae 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}, @@ -47,25 +49,31 @@ use itertools::Itertools; use orchestra::TimeoutExt; use overseer::{metrics::Metrics as OverseerMetrics, MetricsTrait}; use polkadot_approval_distribution::ApprovalDistribution; +use polkadot_node_core_approval_voting_parallel::ApprovalVotingParallelSubsystem; +use polkadot_node_primitives::approval::time::{ + slot_number_to_tick, tick_to_slot_number, Clock, ClockExt, SystemClock, +}; + use polkadot_node_core_approval_voting::{ - time::{slot_number_to_tick, tick_to_slot_number, Clock, ClockExt, SystemClock}, - ApprovalVotingSubsystem, Config as ApprovalVotingConfig, Metrics as ApprovalVotingMetrics, + ApprovalVotingSubsystem, Config as ApprovalVotingConfig, RealAssignmentCriteria, }; use polkadot_node_network_protocol::v3 as protocol_v3; use polkadot_node_primitives::approval::{self, v1::RelayVRFStory}; -use polkadot_node_subsystem::{overseer, AllMessages, Overseer, OverseerConnector, SpawnGlue}; +use polkadot_node_subsystem::{ + messages::{ApprovalDistributionMessage, ApprovalVotingMessage, ApprovalVotingParallelMessage}, + overseer, AllMessages, Overseer, OverseerConnector, SpawnGlue, +}; use polkadot_node_subsystem_test_helpers::mock::new_block_import_info; -use polkadot_node_subsystem_types::messages::{ApprovalDistributionMessage, ApprovalVotingMessage}; -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; @@ -131,6 +139,9 @@ pub struct ApprovalsOptions { /// The number of no shows per candidate #[clap(short, long, default_value_t = 0)] pub num_no_shows_per_candidate: u32, + /// Enable approval voting parallel. + #[clap(short, long, default_value_t = true)] + pub approval_voting_parallel_enabled: bool, } impl ApprovalsOptions { @@ -265,7 +276,7 @@ pub struct ApprovalTestState { /// Total unique sent messages. total_unique_messages: Arc, /// Approval voting metrics. - approval_voting_metrics: ApprovalVotingMetrics, + approval_voting_parallel_metrics: polkadot_node_core_approval_voting_parallel::Metrics, /// The delta ticks from the tick the messages were generated to the the time we start this /// message. delta_tick_from_generated: Arc, @@ -323,7 +334,10 @@ impl ApprovalTestState { total_sent_messages_from_node: Arc::new(AtomicU64::new(0)), total_unique_messages: Arc::new(AtomicU64::new(0)), options, - approval_voting_metrics: ApprovalVotingMetrics::try_register(&dependencies.registry) + approval_voting_parallel_metrics: + polkadot_node_core_approval_voting_parallel::Metrics::try_register( + &dependencies.registry, + ) .unwrap(), delta_tick_from_generated: Arc::new(AtomicU64::new(630720000)), configuration: configuration.clone(), @@ -449,6 +463,14 @@ impl ApprovalTestState { }) .collect() } + + fn subsystem_name(&self) -> &'static str { + if self.options.approval_voting_parallel_enabled { + "approval-voting-parallel-subsystem" + } else { + "approval-distribution-subsystem" + } + } } impl ApprovalTestState { @@ -590,13 +612,16 @@ impl PeerMessageProducer { // so when the approval-distribution answered to it, we know it doesn't have anything // else to process. let (tx, rx) = oneshot::channel(); - let msg = ApprovalDistributionMessage::GetApprovalSignatures(HashSet::new(), tx); - self.send_overseer_message( - AllMessages::ApprovalDistribution(msg), - ValidatorIndex(0), - None, - ) - .await; + let msg = if self.options.approval_voting_parallel_enabled { + AllMessages::ApprovalVotingParallel( + ApprovalVotingParallelMessage::GetApprovalSignatures(HashSet::new(), tx), + ) + } else { + AllMessages::ApprovalDistribution( + ApprovalDistributionMessage::GetApprovalSignatures(HashSet::new(), tx), + ) + }; + self.send_overseer_message(msg, ValidatorIndex(0), None).await; rx.await.expect("Failed to get signatures"); self.notify_done.send(()).expect("Failed to notify main loop"); gum::info!("All messages processed "); @@ -736,7 +761,11 @@ impl PeerMessageProducer { for validator in 1..self.state.test_authorities.validator_authority_id.len() as u32 { let peer_id = self.state.test_authorities.peer_ids.get(validator as usize).unwrap(); let validator = ValidatorIndex(validator); - let view_update = generate_peer_view_change_for(block_info.hash, *peer_id); + let view_update = generate_peer_view_change_for( + block_info.hash, + *peer_id, + self.state.options.approval_voting_parallel_enabled, + ); self.send_overseer_message(view_update, validator, None).await; } @@ -792,22 +821,21 @@ 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()); - let approval_voting = ApprovalVotingSubsystem::with_config_and_clock( - TEST_CONFIG, - Arc::new(db), - Arc::new(keystore), - Box::new(TestSyncOracle {}), - state.approval_voting_metrics.clone(), - Box::new(system_clock.clone()), - ); + let keystore = Arc::new(keystore); + let db = Arc::new(db); - let approval_distribution = - ApprovalDistribution::new(Metrics::register(Some(&dependencies.registry)).unwrap()); let mock_chain_api = MockChainApi::new(state.build_chain_api_state()); - let mock_chain_selection = MockChainSelection { state: state.clone(), clock: system_clock }; + let mock_chain_selection = + MockChainSelection { state: state.clone(), clock: system_clock.clone() }; let mock_runtime_api = MockRuntimeApi::new( config.clone(), state.test_authorities.clone(), @@ -822,19 +850,61 @@ fn build_overseer( network_interface.subsystem_sender(), state.test_authorities.clone(), ); - let mock_rx_bridge = MockNetworkBridgeRx::new(network_receiver, None); + let mock_rx_bridge = MockNetworkBridgeRx::new( + network_receiver, + None, + state.options.approval_voting_parallel_enabled, + ); let overseer_metrics = OverseerMetrics::try_register(&dependencies.registry).unwrap(); - let dummy = dummy_builder!(spawn_task_handle, overseer_metrics) - .replace_approval_distribution(|_| approval_distribution) - .replace_approval_voting(|_| approval_voting) + let task_handle = spawn_task_handle.clone(); + let dummy = dummy_builder!(task_handle, overseer_metrics) .replace_chain_api(|_| mock_chain_api) .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) = if state.options.approval_voting_parallel_enabled { + let approval_voting_parallel = ApprovalVotingParallelSubsystem::with_config_and_clock( + TEST_CONFIG, + db.clone(), + keystore.clone(), + Box::new(TestSyncOracle {}), + state.approval_voting_parallel_metrics.clone(), + Arc::new(system_clock.clone()), + SpawnGlue(spawn_task_handle.clone()), + None, + ); + dummy + .replace_approval_voting_parallel(|_| approval_voting_parallel) + .build_with_connector(overseer_connector) + .expect("Should not fail") + } else { + let approval_voting = ApprovalVotingSubsystem::with_config_and_clock( + TEST_CONFIG, + db.clone(), + keystore.clone(), + Box::new(TestSyncOracle {}), + state.approval_voting_parallel_metrics.approval_voting_metrics(), + Arc::new(system_clock.clone()), + Arc::new(SpawnGlue(spawn_task_handle.clone())), + ); + + let approval_distribution = ApprovalDistribution::new_with_clock( + state.approval_voting_parallel_metrics.approval_distribution_metrics(), + TEST_CONFIG.slot_duration_millis, + Arc::new(system_clock.clone()), + Arc::new(RealAssignmentCriteria {}), + ); - let (overseer, raw_handle) = - dummy.build_with_connector(overseer_connector).expect("Should not fail"); + dummy + .replace_approval_voting(|_| approval_voting) + .replace_approval_distribution(|_| approval_distribution) + .build_with_connector(overseer_connector) + .expect("Should not fail") + }; let overseer_handle = OverseerHandleReal::new(raw_handle); (overseer, overseer_handle) @@ -923,11 +993,18 @@ pub async fn bench_approvals_run( // First create the initialization messages that make sure that then node under // tests receives notifications about the topology used and the connected peers. let mut initialization_messages = env.network().generate_peer_connected(|e| { - AllMessages::ApprovalDistribution(ApprovalDistributionMessage::NetworkBridgeUpdate(e)) + if state.options.approval_voting_parallel_enabled { + AllMessages::ApprovalVotingParallel(ApprovalVotingParallelMessage::NetworkBridgeUpdate( + e, + )) + } else { + AllMessages::ApprovalDistribution(ApprovalDistributionMessage::NetworkBridgeUpdate(e)) + } }); initialization_messages.extend(generate_new_session_topology( &state.test_authorities, ValidatorIndex(NODE_UNDER_TEST), + state.options.approval_voting_parallel_enabled, )); for message in initialization_messages { env.send_message(message).await; @@ -992,7 +1069,14 @@ pub async fn bench_approvals_run( state.total_sent_messages_to_node.load(std::sync::atomic::Ordering::SeqCst) as usize; env.wait_until_metric( "polkadot_parachain_subsystem_bounded_received", - Some(("subsystem_name", "approval-distribution-subsystem")), + Some(( + "subsystem_name", + if state.options.approval_voting_parallel_enabled { + "approval-voting-parallel-subsystem" + } else { + "approval-distribution-subsystem" + }, + )), |value| { gum::debug!(target: LOG_TARGET, ?value, ?at_least_messages, "Waiting metric"); value >= at_least_messages as f64 @@ -1009,11 +1093,22 @@ pub async fn bench_approvals_run( CandidateEvent::CandidateIncluded(receipt_fetch, _head, _, _) => { let (tx, rx) = oneshot::channel(); - let msg = ApprovalVotingMessage::GetApprovalSignaturesForCandidate( - receipt_fetch.hash(), - tx, - ); - env.send_message(AllMessages::ApprovalVoting(msg)).await; + let msg = if state.options.approval_voting_parallel_enabled { + AllMessages::ApprovalVotingParallel( + ApprovalVotingParallelMessage::GetApprovalSignaturesForCandidate( + receipt_fetch.hash(), + tx, + ), + ) + } else { + AllMessages::ApprovalVoting( + ApprovalVotingMessage::GetApprovalSignaturesForCandidate( + receipt_fetch.hash(), + tx, + ), + ) + }; + env.send_message(msg).await; let result = rx.await.unwrap(); @@ -1037,7 +1132,7 @@ pub async fn bench_approvals_run( state.total_sent_messages_to_node.load(std::sync::atomic::Ordering::SeqCst) as usize; env.wait_until_metric( "polkadot_parachain_subsystem_bounded_received", - Some(("subsystem_name", "approval-distribution-subsystem")), + Some(("subsystem_name", state.subsystem_name())), |value| { gum::debug!(target: LOG_TARGET, ?value, ?at_least_messages, "Waiting metric"); value >= at_least_messages as f64 @@ -1078,5 +1173,8 @@ pub async fn bench_approvals_run( state.total_unique_messages.load(std::sync::atomic::Ordering::SeqCst) ); - env.collect_resource_usage(&["approval-distribution", "approval-voting"]) + env.collect_resource_usage( + &["approval-distribution", "approval-voting", "approval-voting-parallel"], + true, + ) } diff --git a/polkadot/node/subsystem-bench/src/lib/availability/mod.rs b/polkadot/node/subsystem-bench/src/lib/availability/mod.rs index 32dc8ae2c8dc..a99f013195fa 100644 --- a/polkadot/node/subsystem-bench/src/lib/availability/mod.rs +++ b/polkadot/node/subsystem-bench/src/lib/availability/mod.rs @@ -49,10 +49,7 @@ use polkadot_node_subsystem::{ messages::{AllMessages, AvailabilityRecoveryMessage}, Overseer, OverseerConnector, SpawnGlue, }; -use polkadot_node_subsystem_types::{ - messages::{AvailabilityStoreMessage, NetworkBridgeEvent}, - Span, -}; +use polkadot_node_subsystem_types::messages::{AvailabilityStoreMessage, NetworkBridgeEvent}; use polkadot_overseer::{metrics::Metrics as OverseerMetrics, Handle as OverseerHandle}; use polkadot_primitives::{Block, CoreIndex, GroupIndex, Hash}; use sc_network::request_responses::{IncomingRequest as RawIncomingRequest, ProtocolConfig}; @@ -210,7 +207,7 @@ pub fn prepare_test( state.test_authorities.clone(), ); let network_bridge_rx = - network_bridge::MockNetworkBridgeRx::new(network_receiver, Some(chunk_req_v2_cfg)); + network_bridge::MockNetworkBridgeRx::new(network_receiver, Some(chunk_req_v2_cfg), false); let runtime_api = MockRuntimeApi::new( state.config.clone(), @@ -372,7 +369,7 @@ pub async fn benchmark_availability_read( ); env.stop().await; - env.collect_resource_usage(&["availability-recovery"]) + env.collect_resource_usage(&["availability-recovery"], false) } pub async fn benchmark_availability_write( @@ -421,7 +418,7 @@ pub async fn benchmark_availability_write( // Inform bitfield distribution about our view of current test block let message = polkadot_node_subsystem_types::messages::BitfieldDistributionMessage::NetworkBridgeUpdate( - NetworkBridgeEvent::OurViewChange(OurView::new(vec![(relay_block_hash, Arc::new(Span::Disabled))], 0)) + NetworkBridgeEvent::OurViewChange(OurView::new(vec![relay_block_hash], 0)) ); env.send_message(AllMessages::BitfieldDistribution(message)).await; @@ -506,9 +503,8 @@ pub async fn benchmark_availability_write( ); env.stop().await; - env.collect_resource_usage(&[ - "availability-distribution", - "bitfield-distribution", - "availability-store", - ]) + env.collect_resource_usage( + &["availability-distribution", "bitfield-distribution", "availability-store"], + false, + ) } diff --git a/polkadot/node/subsystem-bench/src/lib/display.rs b/polkadot/node/subsystem-bench/src/lib/display.rs index b153d54a7c36..c47dd9a07900 100644 --- a/polkadot/node/subsystem-bench/src/lib/display.rs +++ b/polkadot/node/subsystem-bench/src/lib/display.rs @@ -96,6 +96,23 @@ pub struct TestMetric { value: f64, } +impl TestMetric { + pub fn name(&self) -> &str { + &self.name + } + + pub fn value(&self) -> f64 { + self.value + } + + pub fn label_value(&self, label_name: &str) -> Option<&str> { + self.label_names + .iter() + .position(|name| name == label_name) + .and_then(|index| self.label_values.get(index).map(|s| s.as_str())) + } +} + impl Display for TestMetric { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( diff --git a/polkadot/node/subsystem-bench/src/lib/environment.rs b/polkadot/node/subsystem-bench/src/lib/environment.rs index a63f90da50b3..4de683ad6487 100644 --- a/polkadot/node/subsystem-bench/src/lib/environment.rs +++ b/polkadot/node/subsystem-bench/src/lib/environment.rs @@ -351,10 +351,14 @@ impl TestEnvironment { } } - pub fn collect_resource_usage(&self, subsystems_under_test: &[&str]) -> BenchmarkUsage { + pub fn collect_resource_usage( + &self, + subsystems_under_test: &[&str], + break_down_cpu_usage_per_task: bool, + ) -> BenchmarkUsage { BenchmarkUsage { network_usage: self.network_usage(), - cpu_usage: self.cpu_usage(subsystems_under_test), + cpu_usage: self.cpu_usage(subsystems_under_test, break_down_cpu_usage_per_task), } } @@ -378,7 +382,11 @@ impl TestEnvironment { ] } - fn cpu_usage(&self, subsystems_under_test: &[&str]) -> Vec { + fn cpu_usage( + &self, + subsystems_under_test: &[&str], + break_down_per_task: bool, + ) -> Vec { let test_metrics = super::display::parse_metrics(self.registry()); let mut usage = vec![]; let num_blocks = self.config().num_blocks as f64; @@ -392,6 +400,22 @@ impl TestEnvironment { total: total_cpu, per_block: total_cpu / num_blocks, }); + + if break_down_per_task { + for metric in subsystem_cpu_metrics.all() { + if metric.name() != "substrate_tasks_polling_duration_sum" { + continue; + } + + if let Some(task_name) = metric.label_value("task_name") { + usage.push(ResourceUsage { + resource_name: format!("{}/{}", subsystem, task_name), + total: metric.value(), + per_block: metric.value() / num_blocks, + }); + } + } + } } let test_env_cpu_metrics = 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 000000000000..713226de6ad8 --- /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 000000000000..941fac2a38c6 --- /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/dummy.rs b/polkadot/node/subsystem-bench/src/lib/mock/dummy.rs index 8783b35f1c04..092a8fc5f4c1 100644 --- a/polkadot/node/subsystem-bench/src/lib/mock/dummy.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/dummy.rs @@ -96,5 +96,6 @@ mock!(NetworkBridgeTx); mock!(ChainApi); mock!(ChainSelection); mock!(ApprovalVoting); +mock!(ApprovalVotingParallel); mock!(ApprovalDistribution); mock!(RuntimeApi); diff --git a/polkadot/node/subsystem-bench/src/lib/mock/mod.rs b/polkadot/node/subsystem-bench/src/lib/mock/mod.rs index 12766374bfa9..00c19fe62cc4 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; @@ -45,6 +47,7 @@ macro_rules! dummy_builder { // All subsystem except approval_voting and approval_distribution are mock subsystems. Overseer::builder() .approval_voting(MockApprovalVoting {}) + .approval_voting_parallel(MockApprovalVotingParallel {}) .approval_distribution(MockApprovalDistribution {}) .availability_recovery(MockAvailabilityRecovery {}) .candidate_validation(MockCandidateValidation {}) @@ -68,7 +71,6 @@ macro_rules! dummy_builder { .dispute_distribution(MockDisputeDistribution {}) .prospective_parachains(MockProspectiveParachains {}) .activation_external_listeners(Default::default()) - .span_per_active_leaf(Default::default()) .active_leaves(Default::default()) .metrics($metrics) .supports_parachains(AlwaysSupportsParachains {}) diff --git a/polkadot/node/subsystem-bench/src/lib/mock/network_bridge.rs b/polkadot/node/subsystem-bench/src/lib/mock/network_bridge.rs index d70953926d13..f5474a61e3dc 100644 --- a/polkadot/node/subsystem-bench/src/lib/mock/network_bridge.rs +++ b/polkadot/node/subsystem-bench/src/lib/mock/network_bridge.rs @@ -24,13 +24,13 @@ use crate::{ use futures::{channel::mpsc::UnboundedSender, FutureExt, StreamExt}; use polkadot_node_network_protocol::Versioned; use polkadot_node_subsystem::{ - messages::NetworkBridgeTxMessage, overseer, SpawnedSubsystem, SubsystemError, -}; -use polkadot_node_subsystem_types::{ messages::{ - ApprovalDistributionMessage, BitfieldDistributionMessage, NetworkBridgeEvent, - StatementDistributionMessage, + ApprovalDistributionMessage, ApprovalVotingParallelMessage, NetworkBridgeTxMessage, }, + overseer, SpawnedSubsystem, SubsystemError, +}; +use polkadot_node_subsystem_types::{ + messages::{BitfieldDistributionMessage, NetworkBridgeEvent, StatementDistributionMessage}, OverseerSignal, }; use sc_network::{request_responses::ProtocolConfig, RequestFailure}; @@ -57,6 +57,8 @@ pub struct MockNetworkBridgeRx { network_receiver: NetworkInterfaceReceiver, /// Chunk request sender chunk_request_sender: Option, + /// Approval voting parallel enabled. + approval_voting_parallel_enabled: bool, } impl MockNetworkBridgeTx { @@ -73,8 +75,9 @@ impl MockNetworkBridgeRx { pub fn new( network_receiver: NetworkInterfaceReceiver, chunk_request_sender: Option, + approval_voting_parallel_enabled: bool, ) -> MockNetworkBridgeRx { - Self { network_receiver, chunk_request_sender } + Self { network_receiver, chunk_request_sender, approval_voting_parallel_enabled } } } @@ -199,9 +202,15 @@ impl MockNetworkBridgeRx { Versioned::V3( polkadot_node_network_protocol::v3::ValidationProtocol::ApprovalDistribution(msg) ) => { - ctx.send_message( - ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage(peer_id, polkadot_node_network_protocol::Versioned::V3(msg))) - ).await; + if self.approval_voting_parallel_enabled { + ctx.send_message( + ApprovalVotingParallelMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage(peer_id, polkadot_node_network_protocol::Versioned::V3(msg))) + ).await; + } else { + ctx.send_message( + ApprovalDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage(peer_id, polkadot_node_network_protocol::Versioned::V3(msg))) + ).await; + } } Versioned::V3( polkadot_node_network_protocol::v3::ValidationProtocol::StatementDistribution(msg) 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 ee45ea05c925..61523de1f1b5 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-bench/src/lib/statement/mod.rs b/polkadot/node/subsystem-bench/src/lib/statement/mod.rs index bd47505f56ae..dd7095d3b00c 100644 --- a/polkadot/node/subsystem-bench/src/lib/statement/mod.rs +++ b/polkadot/node/subsystem-bench/src/lib/statement/mod.rs @@ -114,14 +114,14 @@ fn build_overseer( state.pvd.clone(), state.own_backing_group.clone(), ); - let (statement_req_receiver, statement_req_cfg) = IncomingRequest::get_config_receiver::< - Block, - sc_network::NetworkWorker, - >(&ReqProtocolNames::new(GENESIS_HASH, None)); - let (candidate_req_receiver, candidate_req_cfg) = IncomingRequest::get_config_receiver::< - Block, - sc_network::NetworkWorker, - >(&ReqProtocolNames::new(GENESIS_HASH, None)); + let (statement_req_receiver, statement_req_cfg) = + IncomingRequest::get_config_receiver::>( + &ReqProtocolNames::new(GENESIS_HASH, None), + ); + let (candidate_req_receiver, candidate_req_cfg) = + IncomingRequest::get_config_receiver::>( + &ReqProtocolNames::new(GENESIS_HASH, None), + ); let keystore = make_keystore(); let subsystem = StatementDistributionSubsystem::new( keystore.clone(), @@ -135,7 +135,8 @@ fn build_overseer( network_interface.subsystem_sender(), state.test_authorities.clone(), ); - let network_bridge_rx = MockNetworkBridgeRx::new(network_receiver, Some(candidate_req_cfg)); + let network_bridge_rx = + MockNetworkBridgeRx::new(network_receiver, Some(candidate_req_cfg), false); let dummy = dummy_builder!(spawn_task_handle, overseer_metrics) .replace_runtime_api(|_| mock_runtime_api) @@ -445,5 +446,5 @@ pub async fn benchmark_statement_distribution( ); env.stop().await; - env.collect_resource_usage(&["statement-distribution"]) + env.collect_resource_usage(&["statement-distribution"], false) } diff --git a/polkadot/node/subsystem-bench/src/lib/usage.rs b/polkadot/node/subsystem-bench/src/lib/usage.rs index 883e9aa7ad0a..5f691ae2db39 100644 --- a/polkadot/node/subsystem-bench/src/lib/usage.rs +++ b/polkadot/node/subsystem-bench/src/lib/usage.rs @@ -32,14 +32,14 @@ impl std::fmt::Display for BenchmarkUsage { write!( f, "\n{}\n{}\n\n{}\n{}\n", - format!("{:<32}{:>12}{:>12}", "Network usage, KiB", "total", "per block").blue(), + format!("{:<64}{:>12}{:>12}", "Network usage, KiB", "total", "per block").blue(), self.network_usage .iter() .map(|v| v.to_string()) .sorted() .collect::>() .join("\n"), - format!("{:<32}{:>12}{:>12}", "CPU usage, seconds", "total", "per block").blue(), + format!("{:<64}{:>12}{:>12}", "CPU usage, seconds", "total", "per block").blue(), self.cpu_usage .iter() .map(|v| v.to_string()) @@ -134,7 +134,7 @@ pub struct ResourceUsage { impl std::fmt::Display for ResourceUsage { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{:<32}{:>12.4}{:>12.4}", self.resource_name.cyan(), self.total, self.per_block) + write!(f, "{:<64}{:>12.4}{:>12.4}", self.resource_name.cyan(), self.total, self.per_block) } } diff --git a/polkadot/node/subsystem-test-helpers/src/lib.rs b/polkadot/node/subsystem-test-helpers/src/lib.rs index bdb0647fee6f..5b1f8d3223d1 100644 --- a/polkadot/node/subsystem-test-helpers/src/lib.rs +++ b/polkadot/node/subsystem-test-helpers/src/lib.rs @@ -294,6 +294,9 @@ pub struct TestSubsystemContextHandle { /// Message counter over subsystems. pub message_counter: MessageCounter, + + /// Intermediate buffer for a message when using `peek`. + message_buffer: Option, } impl TestSubsystemContextHandle { @@ -323,12 +326,30 @@ impl TestSubsystemContextHandle { /// Receive the next message from the subsystem, or `None` if the channel has been closed. pub async fn try_recv(&mut self) -> Option { + if let Some(msg) = self.message_buffer.take() { + return Some(msg) + } + self.rx .next() .timeout(Self::TIMEOUT) .await .expect("`try_recv` does not timeout") } + + /// Peek into the next message from the subsystem or `None` if the channel has been closed. + pub async fn peek(&mut self) -> Option<&AllMessages> { + if self.message_buffer.is_none() { + self.message_buffer = self + .rx + .next() + .timeout(Self::TIMEOUT) + .await + .expect("`try_recv` does not timeout"); + } + + self.message_buffer.as_ref() + } } /// Make a test subsystem context with `buffer_size == 0`. This is used by most @@ -392,6 +413,7 @@ pub fn make_buffered_subsystem_context( tx: overseer_tx, rx: all_messages_rx, message_counter: message_counter.clone(), + message_buffer: None, }, ) } diff --git a/polkadot/node/subsystem-test-helpers/src/mock.rs b/polkadot/node/subsystem-test-helpers/src/mock.rs index 14026960ac13..f73b4b573ff5 100644 --- a/polkadot/node/subsystem-test-helpers/src/mock.rs +++ b/polkadot/node/subsystem-test-helpers/src/mock.rs @@ -16,7 +16,7 @@ use std::sync::Arc; -use polkadot_node_subsystem::{jaeger, ActivatedLeaf, BlockInfo}; +use polkadot_node_subsystem::{ActivatedLeaf, BlockInfo}; use sc_client_api::UnpinHandle; use sc_keystore::LocalKeystore; use sc_utils::mpsc::tracing_unbounded; @@ -52,12 +52,7 @@ pub fn dummy_unpin_handle(block: Hash) -> UnpinHandle { /// Create a new leaf with the given hash and number. pub fn new_leaf(hash: Hash, number: BlockNumber) -> ActivatedLeaf { - ActivatedLeaf { - hash, - number, - unpin_handle: dummy_unpin_handle(hash), - span: Arc::new(jaeger::Span::Disabled), - } + ActivatedLeaf { hash, number, unpin_handle: dummy_unpin_handle(hash) } } /// Create a new leaf with the given hash and number. diff --git a/polkadot/node/subsystem-types/Cargo.toml b/polkadot/node/subsystem-types/Cargo.toml index c8fc324699e1..b8bad8f8a295 100644 --- a/polkadot/node/subsystem-types/Cargo.toml +++ b/polkadot/node/subsystem-types/Cargo.toml @@ -17,7 +17,6 @@ polkadot-primitives = { workspace = true, default-features = true } polkadot-node-primitives = { workspace = true, default-features = true } polkadot-node-network-protocol = { workspace = true, default-features = true } polkadot-statement-table = { workspace = true, default-features = true } -polkadot-node-jaeger = { workspace = true, default-features = true } orchestra = { features = ["futures_channel"], workspace = true } sc-network = { workspace = true, default-features = true } sc-network-types = { workspace = true, default-features = true } @@ -33,3 +32,4 @@ prometheus-endpoint = { workspace = true, default-features = true } thiserror = { workspace = true } async-trait = { workspace = true } bitvec = { features = ["alloc"], workspace = true } +strum = { features = ["derive"], workspace = true, default-features = true } diff --git a/polkadot/node/subsystem-types/src/errors.rs b/polkadot/node/subsystem-types/src/errors.rs index 8e1b515c8db0..8770f3a3d9a1 100644 --- a/polkadot/node/subsystem-types/src/errors.rs +++ b/polkadot/node/subsystem-types/src/errors.rs @@ -16,7 +16,6 @@ //! Error types for the subsystem requests. -use crate::JaegerError; use ::orchestra::OrchestraError as OverseerError; use fatality::fatality; @@ -109,9 +108,6 @@ pub enum SubsystemError { #[error(transparent)] Prometheus(#[from] prometheus_endpoint::PrometheusError), - #[error(transparent)] - Jaeger(#[from] JaegerError), - #[error("Failed to {0}")] Context(String), diff --git a/polkadot/node/subsystem-types/src/lib.rs b/polkadot/node/subsystem-types/src/lib.rs index cd39aa03e567..cde6bba18e7a 100644 --- a/polkadot/node/subsystem-types/src/lib.rs +++ b/polkadot/node/subsystem-types/src/lib.rs @@ -23,7 +23,7 @@ #![warn(missing_docs)] use smallvec::SmallVec; -use std::{fmt, sync::Arc}; +use std::fmt; pub use polkadot_primitives::{Block, BlockNumber, Hash}; @@ -42,9 +42,6 @@ pub mod messages; mod runtime_client; pub use runtime_client::{ChainApiBackend, DefaultSubsystemClient, RuntimeApiSubsystemClient}; -pub use jaeger::*; -pub use polkadot_node_jaeger as jaeger; - /// How many slots are stack-reserved for active leaves updates /// /// If there are fewer than this number of slots, then we've wasted some stack space. @@ -60,11 +57,6 @@ pub struct ActivatedLeaf { pub number: BlockNumber, /// A handle to unpin the block on drop. pub unpin_handle: UnpinHandle, - /// An associated [`jaeger::Span`]. - /// - /// NOTE: Each span should only be kept active as long as the leaf is considered active and - /// should be dropped when the leaf is deactivated. - pub span: Arc, } /// Changes in the set of active leaves: the parachain heads which we care to work on. diff --git a/polkadot/node/subsystem-types/src/messages.rs b/polkadot/node/subsystem-types/src/messages.rs index ee937bca05bf..0017adb45568 100644 --- a/polkadot/node/subsystem-types/src/messages.rs +++ b/polkadot/node/subsystem-types/src/messages.rs @@ -24,6 +24,7 @@ use futures::channel::oneshot; use sc_network::{Multiaddr, ReputationChange}; +use strum::EnumIter; use thiserror::Error; pub use sc_network::IfDisconnected; @@ -33,7 +34,7 @@ use polkadot_node_network_protocol::{ }; use polkadot_node_primitives::{ approval::{ - v1::BlockApprovalMeta, + v1::{BlockApprovalMeta, DelayTranche}, v2::{CandidateBitfield, IndirectAssignmentCertV2, IndirectSignedApprovalVoteV2}, }, AvailableData, BabeEpoch, BlockWeight, CandidateVotes, CollationGenerationConfig, @@ -43,13 +44,14 @@ 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 as RuntimePvfExecKind, SessionIndex, SessionInfo, SignedAvailabilityBitfield, + SignedAvailabilityBitfields, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, + ValidatorSignature, }; use polkadot_statement_table::v2::Misbehavior; use std::{ @@ -142,28 +144,6 @@ pub enum PreCheckOutcome { /// or `Ok(ValidationResult::Invalid)`. #[derive(Debug)] pub enum CandidateValidationMessage { - /// Validate a candidate with provided parameters using relay-chain state. - /// - /// This will implicitly attempt to gather the `PersistedValidationData` and `ValidationCode` - /// from the runtime API of the chain, based on the `relay_parent` - /// of the `CandidateReceipt`. - /// - /// This will also perform checking of validation outputs against the acceptance criteria. - /// - /// If there is no state available which can provide this data or the core for - /// the para is not free at the relay-parent, an error is returned. - ValidateFromChainState { - /// The candidate receipt - candidate_receipt: CandidateReceipt, - /// The proof-of-validity - pov: Arc, - /// Session's executor parameters - executor_params: ExecutorParams, - /// Execution kind, used for timeouts and retries (backing/approvals) - exec_kind: PvfExecKind, - /// The sending side of the response channel - response_sender: oneshot::Sender>, - }, /// Validate a candidate with provided, exhaustive parameters for validation. /// /// Explicitly provide the `PersistedValidationData` and `ValidationCode` so this can do full @@ -204,6 +184,45 @@ pub enum CandidateValidationMessage { }, } +/// Extends primitives::PvfExecKind, which is a runtime parameter we don't want to change, +/// to separate and prioritize execution jobs by request type. +/// The order is important, because we iterate through the values and assume it is going from higher +/// to lowest priority. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, EnumIter)] +pub enum PvfExecKind { + /// For dispute requests + Dispute, + /// For approval requests + Approval, + /// For backing requests from system parachains. + BackingSystemParas, + /// For backing requests. + Backing, +} + +impl PvfExecKind { + /// Converts priority level to &str + pub fn as_str(&self) -> &str { + match *self { + Self::Dispute => "dispute", + Self::Approval => "approval", + Self::BackingSystemParas => "backing_system_paras", + Self::Backing => "backing", + } + } +} + +impl From for RuntimePvfExecKind { + fn from(exec: PvfExecKind) -> Self { + match exec { + PvfExecKind::Dispute => RuntimePvfExecKind::Approval, + PvfExecKind::Approval => RuntimePvfExecKind::Approval, + PvfExecKind::BackingSystemParas => RuntimePvfExecKind::Backing, + PvfExecKind::Backing => RuntimePvfExecKind::Backing, + } + } +} + /// Messages received by the Collator Protocol subsystem. #[derive(Debug, derive_more::From)] pub enum CollatorProtocolMessage { @@ -444,6 +463,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. @@ -869,7 +898,7 @@ pub enum CollationGenerationMessage { SubmitCollation(SubmitCollationParams), } -/// The result type of [`ApprovalVotingMessage::CheckAndImportAssignment`] request. +/// The result type of [`ApprovalVotingMessage::ImportAssignment`] request. #[derive(Debug, Clone, PartialEq, Eq)] pub enum AssignmentCheckResult { /// The vote was accepted and should be propagated onwards. @@ -882,7 +911,7 @@ pub enum AssignmentCheckResult { Bad(AssignmentCheckError), } -/// The error result type of [`ApprovalVotingMessage::CheckAndImportAssignment`] request. +/// The error result type of [`ApprovalVotingMessage::ImportAssignment`] request. #[derive(Error, Debug, Clone, PartialEq, Eq)] #[allow(missing_docs)] pub enum AssignmentCheckError { @@ -902,7 +931,7 @@ pub enum AssignmentCheckError { InvalidBitfield(usize), } -/// The result type of [`ApprovalVotingMessage::CheckAndImportApproval`] request. +/// The result type of [`ApprovalVotingMessage::ImportApproval`] request. #[derive(Debug, Clone, PartialEq, Eq)] pub enum ApprovalCheckResult { /// The vote was accepted and should be propagated onwards. @@ -911,7 +940,7 @@ pub enum ApprovalCheckResult { Bad(ApprovalCheckError), } -/// The error result type of [`ApprovalVotingMessage::CheckAndImportApproval`] request. +/// The error result type of [`ApprovalVotingMessage::ImportApproval`] request. #[derive(Error, Debug, Clone, PartialEq, Eq)] #[allow(missing_docs)] pub enum ApprovalCheckError { @@ -945,6 +974,103 @@ pub struct BlockDescription { pub candidates: Vec, } +/// Message to the approval voting parallel subsystem running both approval-distribution and +/// approval-voting logic in parallel. This is a combination of all the messages ApprovalVoting and +/// ApprovalDistribution subsystems can receive. +/// +/// The reason this exists is, so that we can keep both modes of running in the same polkadot +/// binary, based on the value of `--approval-voting-parallel-enabled`, we decide if we run with two +/// different subsystems for approval-distribution and approval-voting or run the approval-voting +/// parallel which has several parallel workers for the approval-distribution and a worker for +/// approval-voting. +/// +/// This is meant to be a temporary state until we can safely remove running the two subsystems +/// individually. +#[derive(Debug, derive_more::From)] +pub enum ApprovalVotingParallelMessage { + /// Gets mapped into `ApprovalVotingMessage::ApprovedAncestor` + ApprovedAncestor(Hash, BlockNumber, oneshot::Sender>), + + /// Gets mapped into `ApprovalVotingMessage::GetApprovalSignaturesForCandidate` + GetApprovalSignaturesForCandidate( + CandidateHash, + oneshot::Sender, ValidatorSignature)>>, + ), + /// Gets mapped into `ApprovalDistributionMessage::NewBlocks` + NewBlocks(Vec), + /// Gets mapped into `ApprovalDistributionMessage::DistributeAssignment` + DistributeAssignment(IndirectAssignmentCertV2, CandidateBitfield), + /// Gets mapped into `ApprovalDistributionMessage::DistributeApproval` + DistributeApproval(IndirectSignedApprovalVoteV2), + /// An update from the network bridge, gets mapped into + /// `ApprovalDistributionMessage::NetworkBridgeUpdate` + #[from] + NetworkBridgeUpdate(NetworkBridgeEvent), + + /// Gets mapped into `ApprovalDistributionMessage::GetApprovalSignatures` + GetApprovalSignatures( + HashSet<(Hash, CandidateIndex)>, + oneshot::Sender, ValidatorSignature)>>, + ), + /// Gets mapped into `ApprovalDistributionMessage::ApprovalCheckingLagUpdate` + ApprovalCheckingLagUpdate(BlockNumber), +} + +impl TryFrom for ApprovalVotingMessage { + type Error = (); + + fn try_from(msg: ApprovalVotingParallelMessage) -> Result { + match msg { + ApprovalVotingParallelMessage::ApprovedAncestor(hash, number, tx) => + Ok(ApprovalVotingMessage::ApprovedAncestor(hash, number, tx)), + ApprovalVotingParallelMessage::GetApprovalSignaturesForCandidate(candidate, tx) => + Ok(ApprovalVotingMessage::GetApprovalSignaturesForCandidate(candidate, tx)), + _ => Err(()), + } + } +} + +impl TryFrom for ApprovalDistributionMessage { + type Error = (); + + fn try_from(msg: ApprovalVotingParallelMessage) -> Result { + match msg { + ApprovalVotingParallelMessage::NewBlocks(blocks) => + Ok(ApprovalDistributionMessage::NewBlocks(blocks)), + ApprovalVotingParallelMessage::DistributeAssignment(assignment, claimed_cores) => + Ok(ApprovalDistributionMessage::DistributeAssignment(assignment, claimed_cores)), + ApprovalVotingParallelMessage::DistributeApproval(vote) => + Ok(ApprovalDistributionMessage::DistributeApproval(vote)), + ApprovalVotingParallelMessage::NetworkBridgeUpdate(msg) => + Ok(ApprovalDistributionMessage::NetworkBridgeUpdate(msg)), + ApprovalVotingParallelMessage::GetApprovalSignatures(candidate_indicies, tx) => + Ok(ApprovalDistributionMessage::GetApprovalSignatures(candidate_indicies, tx)), + ApprovalVotingParallelMessage::ApprovalCheckingLagUpdate(lag) => + Ok(ApprovalDistributionMessage::ApprovalCheckingLagUpdate(lag)), + _ => Err(()), + } + } +} + +impl From for ApprovalVotingParallelMessage { + fn from(msg: ApprovalDistributionMessage) -> Self { + match msg { + ApprovalDistributionMessage::NewBlocks(blocks) => + ApprovalVotingParallelMessage::NewBlocks(blocks), + ApprovalDistributionMessage::DistributeAssignment(cert, bitfield) => + ApprovalVotingParallelMessage::DistributeAssignment(cert, bitfield), + ApprovalDistributionMessage::DistributeApproval(vote) => + ApprovalVotingParallelMessage::DistributeApproval(vote), + ApprovalDistributionMessage::NetworkBridgeUpdate(msg) => + ApprovalVotingParallelMessage::NetworkBridgeUpdate(msg), + ApprovalDistributionMessage::GetApprovalSignatures(candidate_indicies, tx) => + ApprovalVotingParallelMessage::GetApprovalSignatures(candidate_indicies, tx), + ApprovalDistributionMessage::ApprovalCheckingLagUpdate(lag) => + ApprovalVotingParallelMessage::ApprovalCheckingLagUpdate(lag), + } + } +} + /// Response type to `ApprovalVotingMessage::ApprovedAncestor`. #[derive(Clone, Debug)] pub struct HighestApprovedAncestorBlock { @@ -959,21 +1085,68 @@ pub struct HighestApprovedAncestorBlock { pub descriptions: Vec, } +/// A checked indirect assignment, the crypto for the cert has been validated +/// and the `candidate_bitfield` is correctly claimed at `delay_tranche`. +#[derive(Debug)] +pub struct CheckedIndirectAssignment { + assignment: IndirectAssignmentCertV2, + candidate_indices: CandidateBitfield, + tranche: DelayTranche, +} + +impl CheckedIndirectAssignment { + /// Builds a checked assignment from an assignment that was checked to be valid for the + /// `claimed_candidate_indices` at the give tranche + pub fn from_checked( + assignment: IndirectAssignmentCertV2, + claimed_candidate_indices: CandidateBitfield, + tranche: DelayTranche, + ) -> Self { + Self { assignment, candidate_indices: claimed_candidate_indices, tranche } + } + + /// Returns the indirect assignment. + pub fn assignment(&self) -> &IndirectAssignmentCertV2 { + &self.assignment + } + + /// Returns the candidate bitfield claimed by the assignment. + pub fn candidate_indices(&self) -> &CandidateBitfield { + &self.candidate_indices + } + + /// Returns the tranche this assignment is claimed at. + pub fn tranche(&self) -> DelayTranche { + self.tranche + } +} + +/// A checked indirect signed approval vote. +/// +/// The crypto for the vote has been validated and the signature can be trusted as being valid and +/// to correspond to the `validator_index` inside the structure. +#[derive(Debug, derive_more::Deref, derive_more::Into)] +pub struct CheckedIndirectSignedApprovalVote(IndirectSignedApprovalVoteV2); + +impl CheckedIndirectSignedApprovalVote { + /// Builds a checked vote from a vote that was checked to be valid and correctly signed. + pub fn from_checked(vote: IndirectSignedApprovalVoteV2) -> Self { + Self(vote) + } +} + /// Message to the Approval Voting subsystem. #[derive(Debug)] pub enum ApprovalVotingMessage { - /// Check if the assignment is valid and can be accepted by our view of the protocol. - /// Should not be sent unless the block hash is known. - CheckAndImportAssignment( - IndirectAssignmentCertV2, - CandidateBitfield, - oneshot::Sender, - ), - /// Check if the approval vote is valid and can be accepted by our view of the - /// protocol. + /// Import an assignment into the approval-voting database. /// - /// Should not be sent unless the block hash within the indirect vote is known. - CheckAndImportApproval(IndirectSignedApprovalVoteV2, oneshot::Sender), + /// Should not be sent unless the block hash is known and the VRF assignment checks out. + ImportAssignment(CheckedIndirectAssignment, Option>), + /// Import an approval vote into approval-voting database + /// + /// Should not be sent unless the block hash within the indirect vote is known, vote is + /// correctly signed and we had a previous assignment for the candidate. + ImportApproval(CheckedIndirectSignedApprovalVote, Option>), /// Returns the highest possible ancestor hash of the provided block hash which is /// acceptable to vote on finality for. /// The `BlockNumber` provided is the number of the block's ancestor which is the @@ -1116,6 +1289,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-types/src/runtime_client.rs b/polkadot/node/subsystem-types/src/runtime_client.rs index e5e1e4d24ef9..a8af8b7996f9 100644 --- a/polkadot/node/subsystem-types/src/runtime_client.rs +++ b/polkadot/node/subsystem-types/src/runtime_client.rs @@ -380,7 +380,10 @@ where &self, at: Hash, ) -> Result>, ApiError> { - self.client.runtime_api().availability_cores(at) + self.client + .runtime_api() + .availability_cores(at) + .map(|cores| cores.into_iter().map(|core| core.into()).collect::>()) } async fn persisted_validation_data( @@ -433,7 +436,10 @@ where at: Hash, para_id: Id, ) -> Result>, ApiError> { - self.client.runtime_api().candidate_pending_availability(at, para_id) + self.client + .runtime_api() + .candidate_pending_availability(at, para_id) + .map(|maybe_candidate| maybe_candidate.map(|candidate| candidate.into())) } async fn candidates_pending_availability( @@ -441,11 +447,19 @@ where at: Hash, para_id: Id, ) -> Result>, ApiError> { - self.client.runtime_api().candidates_pending_availability(at, para_id) + self.client + .runtime_api() + .candidates_pending_availability(at, para_id) + .map(|candidates| { + candidates.into_iter().map(|candidate| candidate.into()).collect::>() + }) } async fn candidate_events(&self, at: Hash) -> Result>, ApiError> { - self.client.runtime_api().candidate_events(at) + self.client + .runtime_api() + .candidate_events(at) + .map(|events| events.into_iter().map(|event| event.into()).collect::>()) } async fn dmq_contents( @@ -476,7 +490,10 @@ where &self, at: Hash, ) -> Result>, ApiError> { - self.client.runtime_api().on_chain_votes(at) + self.client + .runtime_api() + .on_chain_votes(at) + .map(|maybe_votes| maybe_votes.map(|votes| votes.into())) } async fn session_executor_params( @@ -588,7 +605,12 @@ where at: Hash, para_id: Id, ) -> Result, ApiError> { - self.client.runtime_api().para_backing_state(at, para_id) + self.client + .runtime_api() + .para_backing_state(at, para_id) + .map(|maybe_backing_state| { + maybe_backing_state.map(|backing_state| backing_state.into()) + }) } async fn async_backing_params( @@ -643,7 +665,8 @@ where fn number( &self, hash: Block::Hash, - ) -> sc_client_api::blockchain::Result::Header as HeaderT>::Number>> { + ) -> sc_client_api::blockchain::Result::Header as HeaderT>::Number>> + { self.client.number(hash) } diff --git a/polkadot/node/subsystem-util/Cargo.toml b/polkadot/node/subsystem-util/Cargo.toml index 98ea21f250ed..d12daa572055 100644 --- a/polkadot/node/subsystem-util/Cargo.toml +++ b/polkadot/node/subsystem-util/Cargo.toml @@ -27,7 +27,6 @@ schnellru = { workspace = true } polkadot-erasure-coding = { workspace = true, default-features = true } polkadot-node-subsystem = { workspace = true, default-features = true } polkadot-node-subsystem-types = { workspace = true, default-features = true } -polkadot-node-jaeger = { workspace = true, default-features = true } polkadot-node-metrics = { workspace = true, default-features = true } polkadot-node-network-protocol = { workspace = true, default-features = true } polkadot-primitives = { workspace = true, default-features = true } @@ -45,11 +44,9 @@ 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 } -lazy_static = { workspace = true } polkadot-primitives-test-helpers = { workspace = true } kvdb-shared-tests = { workspace = true } tempfile = { 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 23a758d25715..a805ef8165e5 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 b5aef325c8b4..0c3b40743495 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/subsystem-util/src/lib.rs b/polkadot/node/subsystem-util/src/lib.rs index 92f2cd189054..4bab4e80fe50 100644 --- a/polkadot/node/subsystem-util/src/lib.rs +++ b/polkadot/node/subsystem-util/src/lib.rs @@ -49,6 +49,7 @@ use polkadot_primitives::{ ValidatorSignature, }; pub use rand; +use runtime::get_disabled_validators_with_fallback; use sp_application_crypto::AppCrypto; use sp_core::ByteArray; use sp_keystore::{Error as KeystoreError, KeystorePtr}; @@ -57,7 +58,6 @@ use std::{ time::Duration, }; use thiserror::Error; -use vstaging::get_disabled_validators_with_fallback; pub use determine_new_blocks::determine_new_blocks; pub use metered; diff --git a/polkadot/node/subsystem-util/src/runtime/mod.rs b/polkadot/node/subsystem-util/src/runtime/mod.rs index 2c9ec8db3778..2f9d3ed7b4f4 100644 --- a/polkadot/node/subsystem-util/src/runtime/mod.rs +++ b/polkadot/node/subsystem-util/src/runtime/mod.rs @@ -32,17 +32,20 @@ use polkadot_node_subsystem_types::UnpinHandle; use polkadot_primitives::{ node_features::FeatureIndex, slashing, AsyncBackingParams, CandidateEvent, CandidateHash, CoreIndex, CoreState, EncodeAs, ExecutorParams, GroupIndex, GroupRotationInfo, Hash, - IndexedVec, NodeFeatures, OccupiedCore, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signed, - SigningContext, UncheckedSigned, ValidationCode, ValidationCodeHash, ValidatorId, - ValidatorIndex, LEGACY_MIN_BACKING_VOTES, + Id as ParaId, IndexedVec, NodeFeatures, OccupiedCore, ScrapedOnChainVotes, SessionIndex, + SessionInfo, Signed, SigningContext, UncheckedSigned, ValidationCode, ValidationCodeHash, + ValidatorId, ValidatorIndex, LEGACY_MIN_BACKING_VOTES, }; +use std::collections::{BTreeMap, VecDeque}; + use crate::{ - request_async_backing_params, request_availability_cores, request_candidate_events, + has_required_runtime, request_async_backing_params, request_availability_cores, + request_candidate_events, request_claim_queue, request_disabled_validators, request_from_runtime, request_key_ownership_proof, request_on_chain_votes, request_session_executor_params, request_session_index_for_child, request_session_info, request_submit_report_dispute_lost, request_unapplied_slashes, request_validation_code_by_hash, - request_validator_groups, vstaging::get_disabled_validators_with_fallback, + request_validator_groups, }; /// Errors that can happen on runtime fetches. @@ -579,3 +582,98 @@ pub async fn request_node_features( res.map(Some) } } + +/// A snapshot of the runtime claim queue at an arbitrary relay chain block. +#[derive(Default)] +pub struct ClaimQueueSnapshot(pub BTreeMap>); + +impl From>> for ClaimQueueSnapshot { + fn from(claim_queue_snapshot: BTreeMap>) -> Self { + ClaimQueueSnapshot(claim_queue_snapshot) + } +} + +impl ClaimQueueSnapshot { + /// Returns the `ParaId` that has a claim for `core_index` at the specified `depth` in the + /// claim queue. A depth of `0` means the very next block. + pub fn get_claim_for(&self, core_index: CoreIndex, depth: usize) -> Option { + self.0.get(&core_index)?.get(depth).copied() + } + + /// Returns an iterator over all claimed cores and the claiming `ParaId` at the specified + /// `depth` in the claim queue. + pub fn iter_claims_at_depth( + &self, + depth: usize, + ) -> impl Iterator + '_ { + self.0 + .iter() + .filter_map(move |(core_index, paras)| Some((*core_index, *paras.get(depth)?))) + } + + /// Returns an iterator over all claims on the given core. + pub fn iter_claims_for_core( + &self, + core_index: &CoreIndex, + ) -> impl Iterator + '_ { + self.0.get(core_index).map(|c| c.iter()).into_iter().flatten() + } + + /// Returns an iterator over the whole claim queue. + pub fn iter_all_claims(&self) -> impl Iterator)> + '_ { + self.0.iter() + } +} + +// TODO: https://github.com/paritytech/polkadot-sdk/issues/1940 +/// Returns disabled validators list if the runtime supports it. Otherwise logs a debug messages and +/// returns an empty vec. +/// Once runtime ver `DISABLED_VALIDATORS_RUNTIME_REQUIREMENT` is released remove this function and +/// replace all usages with `request_disabled_validators` +pub async fn get_disabled_validators_with_fallback>( + sender: &mut Sender, + relay_parent: Hash, +) -> Result> { + let disabled_validators = if has_required_runtime( + sender, + relay_parent, + RuntimeApiRequest::DISABLED_VALIDATORS_RUNTIME_REQUIREMENT, + ) + .await + { + request_disabled_validators(relay_parent, sender) + .await + .await + .map_err(Error::RuntimeRequestCanceled)?? + } else { + gum::debug!(target: LOG_TARGET, "Runtime doesn't support `DisabledValidators` - continuing with an empty disabled validators set"); + vec![] + }; + + Ok(disabled_validators) +} + +/// Checks if the runtime supports `request_claim_queue` and attempts to fetch the claim queue. +/// Returns `ClaimQueueSnapshot` or `None` if claim queue API is not supported by runtime. +/// Any specific `RuntimeApiError` is bubbled up to the caller. +pub async fn fetch_claim_queue( + sender: &mut impl SubsystemSender, + relay_parent: Hash, +) -> Result> { + if has_required_runtime( + sender, + relay_parent, + RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT, + ) + .await + { + let res = request_claim_queue(relay_parent, sender) + .await + .await + .map_err(Error::RuntimeRequestCanceled)??; + Ok(Some(res.into())) + } else { + gum::trace!(target: LOG_TARGET, "Runtime doesn't support `request_claim_queue`"); + Ok(None) + } +} diff --git a/polkadot/node/subsystem-util/src/vstaging.rs b/polkadot/node/subsystem-util/src/vstaging.rs index b6cd73f412b3..b608bb416ff6 100644 --- a/polkadot/node/subsystem-util/src/vstaging.rs +++ b/polkadot/node/subsystem-util/src/vstaging.rs @@ -18,108 +18,3 @@ //! //! This module is intended to contain common boiler plate code handling unreleased runtime API //! calls. - -use std::collections::{BTreeMap, VecDeque}; - -use polkadot_node_subsystem_types::messages::{RuntimeApiMessage, RuntimeApiRequest}; -use polkadot_overseer::SubsystemSender; -use polkadot_primitives::{CoreIndex, Hash, Id as ParaId, ValidatorIndex}; - -use crate::{has_required_runtime, request_claim_queue, request_disabled_validators, runtime}; - -const LOG_TARGET: &'static str = "parachain::subsystem-util-vstaging"; - -/// A snapshot of the runtime claim queue at an arbitrary relay chain block. -#[derive(Default)] -pub struct ClaimQueueSnapshot(pub BTreeMap>); - -impl From>> for ClaimQueueSnapshot { - fn from(claim_queue_snapshot: BTreeMap>) -> Self { - ClaimQueueSnapshot(claim_queue_snapshot) - } -} - -impl ClaimQueueSnapshot { - /// Returns the `ParaId` that has a claim for `core_index` at the specified `depth` in the - /// claim queue. A depth of `0` means the very next block. - pub fn get_claim_for(&self, core_index: CoreIndex, depth: usize) -> Option { - self.0.get(&core_index)?.get(depth).copied() - } - - /// Returns an iterator over all claimed cores and the claiming `ParaId` at the specified - /// `depth` in the claim queue. - pub fn iter_claims_at_depth( - &self, - depth: usize, - ) -> impl Iterator + '_ { - self.0 - .iter() - .filter_map(move |(core_index, paras)| Some((*core_index, *paras.get(depth)?))) - } - - /// Returns an iterator over all claims on the given core. - pub fn iter_claims_for_core( - &self, - core_index: &CoreIndex, - ) -> impl Iterator + '_ { - self.0.get(core_index).map(|c| c.iter()).into_iter().flatten() - } - - /// Returns an iterator over the whole claim queue. - pub fn iter_all_claims(&self) -> impl Iterator)> + '_ { - self.0.iter() - } -} - -// TODO: https://github.com/paritytech/polkadot-sdk/issues/1940 -/// Returns disabled validators list if the runtime supports it. Otherwise logs a debug messages and -/// returns an empty vec. -/// Once runtime ver `DISABLED_VALIDATORS_RUNTIME_REQUIREMENT` is released remove this function and -/// replace all usages with `request_disabled_validators` -pub async fn get_disabled_validators_with_fallback>( - sender: &mut Sender, - relay_parent: Hash, -) -> Result, runtime::Error> { - let disabled_validators = if has_required_runtime( - sender, - relay_parent, - RuntimeApiRequest::DISABLED_VALIDATORS_RUNTIME_REQUIREMENT, - ) - .await - { - request_disabled_validators(relay_parent, sender) - .await - .await - .map_err(runtime::Error::RuntimeRequestCanceled)?? - } else { - gum::debug!(target: LOG_TARGET, "Runtime doesn't support `DisabledValidators` - continuing with an empty disabled validators set"); - vec![] - }; - - Ok(disabled_validators) -} - -/// Checks if the runtime supports `request_claim_queue` and attempts to fetch the claim queue. -/// Returns `ClaimQueueSnapshot` or `None` if claim queue API is not supported by runtime. -/// Any specific `RuntimeApiError` is bubbled up to the caller. -pub async fn fetch_claim_queue( - sender: &mut impl SubsystemSender, - relay_parent: Hash, -) -> Result, runtime::Error> { - if has_required_runtime( - sender, - relay_parent, - RuntimeApiRequest::CLAIM_QUEUE_RUNTIME_REQUIREMENT, - ) - .await - { - let res = request_claim_queue(relay_parent, sender) - .await - .await - .map_err(runtime::Error::RuntimeRequestCanceled)??; - Ok(Some(res.into())) - } else { - gum::trace!(target: LOG_TARGET, "Runtime doesn't support `request_claim_queue`"); - Ok(None) - } -} diff --git a/polkadot/node/subsystem/Cargo.toml b/polkadot/node/subsystem/Cargo.toml index 8edfea9e26bf..ce4bceec7336 100644 --- a/polkadot/node/subsystem/Cargo.toml +++ b/polkadot/node/subsystem/Cargo.toml @@ -12,4 +12,3 @@ workspace = true [dependencies] polkadot-overseer = { workspace = true, default-features = true } polkadot-node-subsystem-types = { workspace = true, default-features = true } -polkadot-node-jaeger = { workspace = true, default-features = true } diff --git a/polkadot/node/subsystem/src/lib.rs b/polkadot/node/subsystem/src/lib.rs index 8b407c75a0c8..bde5a623c476 100644 --- a/polkadot/node/subsystem/src/lib.rs +++ b/polkadot/node/subsystem/src/lib.rs @@ -21,9 +21,6 @@ #![deny(missing_docs)] #![deny(unused_crate_dependencies)] -pub use jaeger::*; -pub use polkadot_node_jaeger as jaeger; - pub use polkadot_overseer::{self as overseer, *}; pub use polkadot_node_subsystem_types::{ diff --git a/polkadot/node/test/client/src/block_builder.rs b/polkadot/node/test/client/src/block_builder.rs index 71bcdaffac4e..9375aca6ed73 100644 --- a/polkadot/node/test/client/src/block_builder.rs +++ b/polkadot/node/test/client/src/block_builder.rs @@ -16,7 +16,7 @@ use crate::Client; use codec::{Decode, Encode}; -use polkadot_primitives::{Block, InherentData as ParachainsInherentData}; +use polkadot_primitives::{vstaging::InherentData as ParachainsInherentData, Block}; use polkadot_test_runtime::UncheckedExtrinsic; use polkadot_test_service::GetLastTimestamp; use sc_block_builder::{BlockBuilder, BlockBuilderBuilder}; diff --git a/polkadot/node/test/client/src/lib.rs b/polkadot/node/test/client/src/lib.rs index 6b205c09f2f3..498994d9a0a8 100644 --- a/polkadot/node/test/client/src/lib.rs +++ b/polkadot/node/test/client/src/lib.rs @@ -102,7 +102,7 @@ mod tests { #[test] fn ensure_test_client_can_build_and_import_block() { - let mut client = TestClientBuilder::new().build(); + let client = TestClientBuilder::new().build(); let block_builder = client.init_polkadot_block_builder(); let block = block_builder.build().expect("Finalizes the block").block; @@ -113,7 +113,7 @@ mod tests { #[test] fn ensure_test_client_can_push_extrinsic() { - let mut client = TestClientBuilder::new().build(); + let client = TestClientBuilder::new().build(); let transfer = construct_transfer_extrinsic( &client, diff --git a/polkadot/node/test/service/Cargo.toml b/polkadot/node/test/service/Cargo.toml index 8eb6105f98e2..4ef9d88621fb 100644 --- a/polkadot/node/test/service/Cargo.toml +++ b/polkadot/node/test/service/Cargo.toml @@ -71,6 +71,7 @@ runtime-benchmarks = [ "frame-system/runtime-benchmarks", "pallet-balances/runtime-benchmarks", "pallet-staking/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", "polkadot-runtime-common/runtime-benchmarks", diff --git a/polkadot/node/test/service/src/chain_spec.rs b/polkadot/node/test/service/src/chain_spec.rs index bd53fd843c69..ae4e84b7725e 100644 --- a/polkadot/node/test/service/src/chain_spec.rs +++ b/polkadot/node/test/service/src/chain_spec.rs @@ -18,15 +18,16 @@ use pallet_staking::Forcing; use polkadot_primitives::{ - vstaging::SchedulerParams, AccountId, AssignmentId, ValidatorId, MAX_CODE_SIZE, MAX_POV_SIZE, + AccountId, AssignmentId, SchedulerParams, ValidatorId, MAX_CODE_SIZE, MAX_POV_SIZE, }; -use polkadot_service::chain_spec::{get_account_id_from_seed, get_from_seed, Extensions}; +use polkadot_service::chain_spec::Extensions; use polkadot_test_runtime::BABE_GENESIS_EPOCH_CONFIG; use sc_chain_spec::{ChainSpec, ChainType}; use sc_consensus_grandpa::AuthorityId as GrandpaId; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; -use sp_core::sr25519; +use sp_core::{crypto::get_public_from_string_or_panic, sr25519}; +use sp_keyring::Sr25519Keyring; use sp_runtime::Perbill; use test_runtime_constants::currency::DOTS; @@ -64,7 +65,7 @@ pub fn polkadot_local_testnet_config() -> PolkadotChainSpec { pub fn polkadot_local_testnet_genesis() -> serde_json::Value { polkadot_testnet_genesis( vec![get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob")], - get_account_id_from_seed::("Alice"), + Sr25519Keyring::Alice.to_account_id(), None, ) } @@ -74,31 +75,18 @@ fn get_authority_keys_from_seed( seed: &str, ) -> (AccountId, AccountId, BabeId, GrandpaId, ValidatorId, AssignmentId, AuthorityDiscoveryId) { ( - get_account_id_from_seed::(&format!("{}//stash", seed)), - get_account_id_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), + get_public_from_string_or_panic::(&format!("{}//stash", seed)).into(), + get_public_from_string_or_panic::(seed).into(), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), ) } fn testnet_accounts() -> Vec { - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ] + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect() } /// Helper function to create polkadot `RuntimeGenesisConfig` for testing diff --git a/polkadot/node/test/service/src/lib.rs b/polkadot/node/test/service/src/lib.rs index 35156a3a9372..6e09bb9e4310 100644 --- a/polkadot/node/test/service/src/lib.rs +++ b/polkadot/node/test/service/src/lib.rs @@ -32,7 +32,7 @@ use polkadot_service::{ Error, FullClient, IsParachainNode, NewFull, OverseerGen, PrometheusConfig, }; use polkadot_test_runtime::{ - ParasCall, ParasSudoWrapperCall, Runtime, SignedExtra, SignedPayload, SudoCall, + ParasCall, ParasSudoWrapperCall, Runtime, SignedPayload, SudoCall, TxExtension, UncheckedExtrinsic, VERSION, }; @@ -68,6 +68,7 @@ use substrate_test_client::{ pub type Client = FullClient; pub use polkadot_service::{FullBackend, GetLastTimestamp}; +use sc_service::config::{ExecutorConfiguration, RpcConfiguration}; /// Create a new full node. #[sc_tracing::logging::prefix_logs_with(config.network.node_name.as_str())] @@ -87,7 +88,6 @@ pub fn new_full( is_parachain_node, enable_beefy: true, force_authoring_backoff: false, - jaeger_agent: None, telemetry_worker_handle: None, node_version: None, secure_validator_mode: false, @@ -100,6 +100,7 @@ pub fn new_full( execute_workers_max_num: None, prepare_workers_hard_max_num: None, prepare_workers_soft_max_num: None, + enable_approval_voting_parallel: false, }, ), sc_network::config::NetworkBackendType::Litep2p => @@ -109,7 +110,6 @@ pub fn new_full( is_parachain_node, enable_beefy: true, force_authoring_backoff: false, - jaeger_agent: None, telemetry_worker_handle: None, node_version: None, secure_validator_mode: false, @@ -122,6 +122,7 @@ pub fn new_full( execute_workers_max_num: None, prepare_workers_hard_max_num: None, prepare_workers_soft_max_num: None, + enable_approval_voting_parallel: false, }, ), } @@ -200,39 +201,40 @@ pub fn node_config( state_pruning: Default::default(), blocks_pruning: BlocksPruning::KeepFinalized, chain_spec: Box::new(spec), - wasm_method: WasmExecutionMethod::Compiled { - instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, + executor: ExecutorConfiguration { + wasm_method: WasmExecutionMethod::Compiled { + instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, + }, + ..ExecutorConfiguration::default() }, wasm_runtime_overrides: Default::default(), - rpc_addr: Default::default(), - rpc_max_request_size: Default::default(), - rpc_max_response_size: Default::default(), - rpc_max_connections: Default::default(), - rpc_cors: None, - rpc_methods: Default::default(), - rpc_id_provider: None, - rpc_max_subs_per_conn: Default::default(), - rpc_port: 9944, - rpc_message_buffer_capacity: Default::default(), - rpc_batch_config: RpcBatchRequestConfig::Unlimited, - rpc_rate_limit: None, - rpc_rate_limit_whitelisted_ips: Default::default(), - rpc_rate_limit_trust_proxy_headers: Default::default(), + rpc: RpcConfiguration { + addr: Default::default(), + max_request_size: Default::default(), + max_response_size: Default::default(), + max_connections: Default::default(), + cors: None, + methods: Default::default(), + id_provider: None, + max_subs_per_conn: Default::default(), + port: 9944, + message_buffer_capacity: Default::default(), + batch_config: RpcBatchRequestConfig::Unlimited, + rate_limit: None, + rate_limit_whitelisted_ips: Default::default(), + rate_limit_trust_proxy_headers: Default::default(), + }, prometheus_config: None, telemetry_endpoints: None, - default_heap_pages: None, offchain_worker: Default::default(), force_authoring: false, disable_grandpa: false, dev_key_seed: Some(key_seed), tracing_targets: None, tracing_receiver: Default::default(), - max_runtime_instances: 8, - runtime_cache_size: 2, announce_block: true, data_path: root, base_path, - informant_output_format: Default::default(), } } @@ -412,7 +414,7 @@ pub fn construct_extrinsic( let period = BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64; let tip = 0; - let extra: SignedExtra = ( + let tx_ext: TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -421,10 +423,11 @@ pub fn construct_extrinsic( frame_system::CheckNonce::::from(nonce), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), - ); + ) + .into(); let raw_payload = SignedPayload::from_raw( function.clone(), - extra.clone(), + tx_ext.clone(), ( (), VERSION.spec_version, @@ -441,7 +444,7 @@ pub fn construct_extrinsic( function.clone(), polkadot_test_runtime::Address::Id(caller.public().into()), polkadot_primitives::Signature::Sr25519(signature), - extra.clone(), + tx_ext.clone(), ) } diff --git a/polkadot/node/zombienet-backchannel/Cargo.toml b/polkadot/node/zombienet-backchannel/Cargo.toml index a9bf1f5ef093..56c49a1ec305 100644 --- a/polkadot/node/zombienet-backchannel/Cargo.toml +++ b/polkadot/node/zombienet-backchannel/Cargo.toml @@ -16,7 +16,6 @@ tokio = { features = ["macros", "net", "rt-multi-thread", "sync"], workspace = t url = { workspace = true } tokio-tungstenite = { workspace = true } futures-util = { workspace = true, default-features = true } -lazy_static = { workspace = true } codec = { features = ["derive"], workspace = true, default-features = true } reqwest = { features = ["rustls-tls"], workspace = true } thiserror = { workspace = true } diff --git a/polkadot/node/zombienet-backchannel/src/lib.rs b/polkadot/node/zombienet-backchannel/src/lib.rs index 9068b03399ca..080dcf1c2b75 100644 --- a/polkadot/node/zombienet-backchannel/src/lib.rs +++ b/polkadot/node/zombienet-backchannel/src/lib.rs @@ -21,7 +21,6 @@ use codec; use futures_util::{SinkExt, StreamExt}; -use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; use std::{env, sync::Mutex}; use tokio::sync::broadcast; @@ -30,9 +29,7 @@ use tokio_tungstenite::{connect_async, tungstenite::protocol::Message}; mod errors; use errors::BackchannelError; -lazy_static! { - pub static ref ZOMBIENET_BACKCHANNEL: Mutex> = Mutex::new(None); -} +pub static ZOMBIENET_BACKCHANNEL: Mutex> = Mutex::new(None); #[derive(Debug)] pub struct ZombienetBackchannel { diff --git a/polkadot/parachain/test-parachains/adder/collator/src/main.rs b/polkadot/parachain/test-parachains/adder/collator/src/main.rs index e8588274df27..416e58b0a8ac 100644 --- a/polkadot/parachain/test-parachains/adder/collator/src/main.rs +++ b/polkadot/parachain/test-parachains/adder/collator/src/main.rs @@ -82,7 +82,6 @@ fn main() -> Result<()> { ), enable_beefy: false, force_authoring_backoff: false, - jaeger_agent: None, telemetry_worker_handle: None, // Collators don't spawn PVF workers, so we can disable version checks. @@ -98,6 +97,7 @@ fn main() -> Result<()> { execute_workers_max_num: None, prepare_workers_hard_max_num: None, prepare_workers_soft_max_num: None, + enable_approval_voting_parallel: false, }, ) .map_err(|e| e.to_string())?; diff --git a/polkadot/parachain/test-parachains/undying/collator/src/main.rs b/polkadot/parachain/test-parachains/undying/collator/src/main.rs index 7198a831a477..017eefe5ee31 100644 --- a/polkadot/parachain/test-parachains/undying/collator/src/main.rs +++ b/polkadot/parachain/test-parachains/undying/collator/src/main.rs @@ -84,7 +84,6 @@ fn main() -> Result<()> { ), enable_beefy: false, force_authoring_backoff: false, - jaeger_agent: None, telemetry_worker_handle: None, // Collators don't spawn PVF workers, so we can disable version checks. @@ -100,6 +99,7 @@ fn main() -> Result<()> { execute_workers_max_num: None, prepare_workers_hard_max_num: None, prepare_workers_soft_max_num: None, + enable_approval_voting_parallel: false, }, ) .map_err(|e| e.to_string())?; diff --git a/polkadot/primitives/Cargo.toml b/polkadot/primitives/Cargo.toml index 8f7ec314ecff..a8cd6cb5f4e0 100644 --- a/polkadot/primitives/Cargo.toml +++ b/polkadot/primitives/Cargo.toml @@ -28,10 +28,14 @@ sp-consensus-slots = { features = ["serde"], workspace = true } sp-io = { workspace = true } sp-keystore = { optional = true, workspace = true } sp-staking = { features = ["serde"], workspace = true } +sp-std = { workspace = true, optional = true } polkadot-core-primitives = { workspace = true } polkadot-parachain-primitives = { workspace = true } +[dev-dependencies] +polkadot-primitives-test-helpers = { workspace = true } + [features] default = ["std"] std = [ @@ -54,9 +58,11 @@ std = [ "sp-keystore?/std", "sp-runtime/std", "sp-staking/std", + "sp-std/std", ] runtime-benchmarks = [ "polkadot-parachain-primitives/runtime-benchmarks", "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", ] +test = [] diff --git a/polkadot/primitives/src/lib.rs b/polkadot/primitives/src/lib.rs index 73736fd4a3d6..493f9fb5ba92 100644 --- a/polkadot/primitives/src/lib.rs +++ b/polkadot/primitives/src/lib.rs @@ -19,8 +19,8 @@ #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] -// `v6` is currently the latest stable version of the runtime API. -pub mod v7; +// `v11` is currently the latest stable version of the runtime API. +pub mod v8; // The 'staging' version is special - it contains primitives which are // still in development. Once they are considered stable, they will be @@ -35,7 +35,7 @@ extern crate alloc; // Current primitives not requiring versioning are exported here. // Primitives requiring versioning must not be exported and must be referred by an exact version. -pub use v7::{ +pub use v8::{ async_backing, byzantine_threshold, check_candidate_backing, collator_signature_payload, effective_minimum_backing_votes, executor_params, metric_definitions, node_features, slashing, supermajority_threshold, well_known_keys, AbridgedHostConfiguration, AbridgedHrmpChannel, @@ -54,16 +54,17 @@ pub use v7::{ OutboundHrmpMessage, ParathreadClaim, ParathreadEntry, PersistedValidationData, PvfCheckStatement, PvfExecKind, PvfPrepKind, RuntimeMetricLabel, RuntimeMetricLabelValue, RuntimeMetricLabelValues, RuntimeMetricLabels, RuntimeMetricOp, RuntimeMetricUpdate, - ScheduledCore, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signature, Signed, - SignedAvailabilityBitfield, SignedAvailabilityBitfields, SignedStatement, SigningContext, Slot, - UncheckedSigned, UncheckedSignedAvailabilityBitfield, UncheckedSignedAvailabilityBitfields, - UncheckedSignedStatement, UpgradeGoAhead, UpgradeRestriction, UpwardMessage, - ValidDisputeStatementKind, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, - ValidatorSignature, ValidityAttestation, ValidityError, ASSIGNMENT_KEY_TYPE_ID, - LEGACY_MIN_BACKING_VOTES, LOWEST_PUBLIC_ID, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, - MIN_CODE_SIZE, ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, ON_DEMAND_MAX_QUEUE_MAX_SIZE, - PARACHAINS_INHERENT_IDENTIFIER, PARACHAIN_KEY_TYPE_ID, + ScheduledCore, SchedulerParams, ScrapedOnChainVotes, SessionIndex, SessionInfo, Signature, + Signed, SignedAvailabilityBitfield, SignedAvailabilityBitfields, SignedStatement, + SigningContext, Slot, UncheckedSigned, UncheckedSignedAvailabilityBitfield, + UncheckedSignedAvailabilityBitfields, UncheckedSignedStatement, UpgradeGoAhead, + UpgradeRestriction, UpwardMessage, ValidDisputeStatementKind, ValidationCode, + ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, ValidityAttestation, + ValidityError, ASSIGNMENT_KEY_TYPE_ID, LEGACY_MIN_BACKING_VOTES, LOWEST_PUBLIC_ID, + MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MAX_POV_SIZE, MIN_CODE_SIZE, + ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, ON_DEMAND_MAX_QUEUE_MAX_SIZE, PARACHAINS_INHERENT_IDENTIFIER, + PARACHAIN_KEY_TYPE_ID, }; #[cfg(feature = "std")] -pub use v7::{AssignmentPair, CollatorPair, ValidatorPair}; +pub use v8::{AssignmentPair, CollatorPair, ValidatorPair}; diff --git a/polkadot/primitives/src/runtime_api.rs b/polkadot/primitives/src/runtime_api.rs index b4816ad15075..3c90c050baed 100644 --- a/polkadot/primitives/src/runtime_api.rs +++ b/polkadot/primitives/src/runtime_api.rs @@ -36,7 +36,7 @@ //! //! Let's see a quick example: //! -//! ```rust(ignore) +//! ```nocompile //! sp_api::decl_runtime_apis! { //! #[api_version(2)] //! pub trait MyApi { @@ -114,11 +114,15 @@ //! separated from the stable primitives. use crate::{ - async_backing, slashing, ApprovalVotingParams, AsyncBackingParams, BlockNumber, - CandidateCommitments, CandidateEvent, CandidateHash, CommittedCandidateReceipt, CoreIndex, - CoreState, DisputeState, ExecutorParams, GroupRotationInfo, Hash, NodeFeatures, - OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, ScrapedOnChainVotes, - SessionIndex, SessionInfo, ValidatorId, ValidatorIndex, ValidatorSignature, + slashing, + vstaging::{ + self, CandidateEvent, CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CoreState, + ScrapedOnChainVotes, + }, + ApprovalVotingParams, AsyncBackingParams, BlockNumber, CandidateCommitments, CandidateHash, + CoreIndex, DisputeState, ExecutorParams, GroupRotationInfo, Hash, NodeFeatures, + OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, SessionIndex, SessionInfo, + ValidatorId, ValidatorIndex, ValidatorSignature, }; use alloc::{ @@ -260,7 +264,7 @@ sp_api::decl_runtime_apis! { /// Returns the state of parachain backing for a given para. #[api_version(7)] - fn para_backing_state(_: ppp::Id) -> Option>; + fn para_backing_state(_: ppp::Id) -> Option>; /// Returns candidate's acceptance limitations for asynchronous backing for a relay parent. #[api_version(7)] diff --git a/polkadot/primitives/src/v7/async_backing.rs b/polkadot/primitives/src/v8/async_backing.rs similarity index 100% rename from polkadot/primitives/src/v7/async_backing.rs rename to polkadot/primitives/src/v8/async_backing.rs diff --git a/polkadot/primitives/src/v7/executor_params.rs b/polkadot/primitives/src/v8/executor_params.rs similarity index 100% rename from polkadot/primitives/src/v7/executor_params.rs rename to polkadot/primitives/src/v8/executor_params.rs diff --git a/polkadot/primitives/src/v7/metrics.rs b/polkadot/primitives/src/v8/metrics.rs similarity index 96% rename from polkadot/primitives/src/v7/metrics.rs rename to polkadot/primitives/src/v8/metrics.rs index 1d66c9848a7c..409efc86bc9b 100644 --- a/polkadot/primitives/src/v7/metrics.rs +++ b/polkadot/primitives/src/v8/metrics.rs @@ -91,18 +91,6 @@ pub type RuntimeMetricLabelValue = RuntimeMetricLabel; /// A set of metric label values. pub type RuntimeMetricLabelValues = RuntimeMetricLabels; -/// Trait for converting Vec to `&str`. -pub trait AsStr { - /// Return a str reference. - fn as_str(&self) -> Option<&str>; -} - -impl AsStr for RuntimeMetricLabel { - fn as_str(&self) -> Option<&str> { - alloc::str::from_utf8(&self.0).ok() - } -} - impl From<&'static str> for RuntimeMetricLabel { fn from(s: &'static str) -> Self { Self(s.as_bytes().to_vec()) diff --git a/polkadot/primitives/src/v7/mod.rs b/polkadot/primitives/src/v8/mod.rs similarity index 95% rename from polkadot/primitives/src/v7/mod.rs rename to polkadot/primitives/src/v8/mod.rs index 06b704652083..cca327df42c9 100644 --- a/polkadot/primitives/src/v7/mod.rs +++ b/polkadot/primitives/src/v8/mod.rs @@ -15,7 +15,6 @@ // along with Polkadot. If not, see . //! `V7` Primitives. - use alloc::{ vec, vec::{IntoIter, Vec}, @@ -29,7 +28,10 @@ use core::{ use scale_info::TypeInfo; use sp_application_crypto::KeyTypeId; -use sp_arithmetic::traits::{BaseArithmetic, Saturating}; +use sp_arithmetic::{ + traits::{BaseArithmetic, Saturating}, + Perbill, +}; use sp_core::RuntimeDebug; use sp_inherents::InherentIdentifier; use sp_runtime::traits::{AppVerify, Header as HeaderT}; @@ -1154,7 +1156,7 @@ pub enum OccupiedCoreAssumption { Free, } -/// An even concerning a candidate. +/// An event concerning a candidate. #[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)] #[cfg_attr(feature = "std", derive(PartialEq))] pub enum CandidateEvent { @@ -2040,15 +2042,97 @@ 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, + } +} + +/// Scheduler configuration parameters. All coretime/ondemand parameters are here. +#[derive( + RuntimeDebug, + Copy, + Clone, + PartialEq, + Encode, + Decode, + TypeInfo, + serde::Serialize, + serde::Deserialize, +)] +pub struct SchedulerParams { + /// How often parachain groups should be rotated across parachains. + /// + /// Must be non-zero. + pub group_rotation_frequency: BlockNumber, + /// Availability timeout for a block on a core, measured in blocks. + /// + /// This is the maximum amount of blocks after a core became occupied that validators have time + /// to make the block available. + /// + /// This value only has effect on group rotations. If backers backed something at the end of + /// their rotation, the occupied core affects the backing group that comes afterwards. We limit + /// the effect one backing group can have on the next to `paras_availability_period` blocks. + /// + /// Within a group rotation there is no timeout as backers are only affecting themselves. + /// + /// Must be at least 1. With a value of 1, the previous group will not be able to negatively + /// affect the following group at the expense of a tight availability timeline at group + /// rotation boundaries. + pub paras_availability_period: BlockNumber, + /// The maximum number of validators to have per core. + /// + /// `None` means no maximum. + pub max_validators_per_core: Option, + /// The amount of blocks ahead to schedule paras. + pub lookahead: u32, + /// How many cores are managed by the coretime chain. + pub num_cores: u32, + /// Deprecated and no longer used by the runtime. + /// Removal is tracked by . + #[deprecated] + pub max_availability_timeouts: u32, + /// The maximum queue size of the pay as you go module. + pub on_demand_queue_max_size: u32, + /// The target utilization of the spot price queue in percentages. + pub on_demand_target_queue_utilization: Perbill, + /// How quickly the fee rises in reaction to increased utilization. + /// The lower the number the slower the increase. + pub on_demand_fee_variability: Perbill, + /// The minimum amount needed to claim a slot in the spot pricing queue. + pub on_demand_base_fee: Balance, + /// Deprecated and no longer used by the runtime. + /// Removal is tracked by . + #[deprecated] + pub ttl: BlockNumber, +} + +impl> Default for SchedulerParams { + #[allow(deprecated)] + fn default() -> Self { + Self { + group_rotation_frequency: 1u32.into(), + paras_availability_period: 1u32.into(), + max_validators_per_core: Default::default(), + lookahead: 1, + num_cores: Default::default(), + max_availability_timeouts: Default::default(), + on_demand_queue_max_size: ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, + on_demand_target_queue_utilization: Perbill::from_percent(25), + on_demand_fee_variability: Perbill::from_percent(3), + on_demand_base_fee: 10_000_000u128, + ttl: 5u32.into(), + } } } #[cfg(test)] -mod tests { +pub mod tests { use super::*; use bitvec::bitvec; use sp_core::sr25519; diff --git a/polkadot/primitives/src/v7/signed.rs b/polkadot/primitives/src/v8/signed.rs similarity index 100% rename from polkadot/primitives/src/v7/signed.rs rename to polkadot/primitives/src/v8/signed.rs diff --git a/polkadot/primitives/src/v7/slashing.rs b/polkadot/primitives/src/v8/slashing.rs similarity index 100% rename from polkadot/primitives/src/v7/slashing.rs rename to polkadot/primitives/src/v8/slashing.rs diff --git a/polkadot/primitives/src/vstaging/async_backing.rs b/polkadot/primitives/src/vstaging/async_backing.rs new file mode 100644 index 000000000000..8706214b5a01 --- /dev/null +++ b/polkadot/primitives/src/vstaging/async_backing.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 . + +use super::*; + +use alloc::vec::Vec; +use codec::{Decode, Encode}; +use scale_info::TypeInfo; +use sp_core::RuntimeDebug; + +/// A candidate pending availability. +#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)] +pub struct CandidatePendingAvailability { + /// The hash of the candidate. + pub candidate_hash: CandidateHash, + /// The candidate's descriptor. + pub descriptor: CandidateDescriptorV2, + /// The commitments of the candidate. + pub commitments: CandidateCommitments, + /// The candidate's relay parent's number. + pub relay_parent_number: N, + /// The maximum Proof-of-Validity size allowed, in bytes. + pub max_pov_size: u32, +} + +impl From> + for crate::v8::async_backing::CandidatePendingAvailability +{ + fn from(value: CandidatePendingAvailability) -> Self { + Self { + candidate_hash: value.candidate_hash, + descriptor: value.descriptor.into(), + commitments: value.commitments, + relay_parent_number: value.relay_parent_number, + max_pov_size: value.max_pov_size, + } + } +} + +/// The per-parachain state of the backing system, including +/// state-machine constraints and candidates pending availability. +#[derive(RuntimeDebug, Clone, PartialEq, Encode, Decode, TypeInfo)] +pub struct BackingState { + /// The state-machine constraints of the parachain. + pub constraints: Constraints, + /// The candidates pending availability. These should be ordered, i.e. they should form + /// a sub-chain, where the first candidate builds on top of the required parent of the + /// constraints and each subsequent builds on top of the previous head-data. + pub pending_availability: Vec>, +} + +impl From> for crate::v8::async_backing::BackingState { + fn from(value: BackingState) -> Self { + Self { + constraints: value.constraints, + pending_availability: value + .pending_availability + .into_iter() + .map(|candidate| candidate.into()) + .collect::>(), + } + } +} diff --git a/polkadot/primitives/src/vstaging/mod.rs b/polkadot/primitives/src/vstaging/mod.rs index 27296213e611..bc687f7e2fbe 100644 --- a/polkadot/primitives/src/vstaging/mod.rs +++ b/polkadot/primitives/src/vstaging/mod.rs @@ -15,86 +15,1060 @@ // along with Polkadot. If not, see . //! Staging Primitives. +use crate::{ValidatorIndex, ValidityAttestation}; // Put any primitives used by staging APIs functions here -use crate::v7::*; - +use super::{ + async_backing::Constraints, BlakeTwo256, BlockNumber, CandidateCommitments, + CandidateDescriptor, CandidateHash, CollatorId, CollatorSignature, CoreIndex, GroupIndex, Hash, + HashT, HeadData, Header, Id, Id as ParaId, MultiDisputeStatementSet, ScheduledCore, + UncheckedSignedAvailabilityBitfields, ValidationCodeHash, +}; +use alloc::{ + collections::{BTreeMap, BTreeSet, VecDeque}, + vec, + vec::Vec, +}; +use bitvec::prelude::*; use codec::{Decode, Encode}; use scale_info::TypeInfo; -use sp_arithmetic::Perbill; +use sp_application_crypto::ByteArray; use sp_core::RuntimeDebug; +use sp_runtime::traits::Header as HeaderT; +use sp_staking::SessionIndex; +/// Async backing primitives +pub mod async_backing; -/// Scheduler configuration parameters. All coretime/ondemand parameters are here. -#[derive( - RuntimeDebug, - Copy, - Clone, - PartialEq, - Encode, - Decode, - TypeInfo, - serde::Serialize, - serde::Deserialize, -)] -pub struct SchedulerParams { - /// How often parachain groups should be rotated across parachains. - /// - /// Must be non-zero. - pub group_rotation_frequency: BlockNumber, - /// Availability timeout for a block on a core, measured in blocks. - /// - /// This is the maximum amount of blocks after a core became occupied that validators have time - /// to make the block available. +/// A type representing the version of the candidate descriptor and internal version number. +#[derive(PartialEq, Eq, Encode, Decode, Clone, TypeInfo, RuntimeDebug, Copy)] +#[cfg_attr(feature = "std", derive(Hash))] +pub struct InternalVersion(pub u8); + +/// A type representing the version of the candidate descriptor. +#[derive(PartialEq, Eq, Clone, TypeInfo, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Hash))] +pub enum CandidateDescriptorVersion { + /// The old candidate descriptor version. + V1, + /// The new `CandidateDescriptorV2`. + V2, + /// An unknown version. + Unknown, +} + +/// A unique descriptor of the candidate receipt. +#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Hash))] +pub struct CandidateDescriptorV2 { + /// The ID of the para this is a candidate for. + para_id: ParaId, + /// The hash of the relay-chain block this is executed in the context of. + relay_parent: H, + /// Version field. The raw value here is not exposed, instead it is used + /// to determine the `CandidateDescriptorVersion`, see `fn version()`. + /// For the current version this field is set to `0` and will be incremented + /// by next versions. + version: InternalVersion, + /// The core index where the candidate is backed. + core_index: u16, + /// The session index of the candidate relay parent. + session_index: SessionIndex, + /// Reserved bytes. + reserved1: [u8; 25], + /// The blake2-256 hash of the persisted validation data. This is extra data derived from + /// relay-chain state which may vary based on bitfields included before the candidate. + /// Thus it cannot be derived entirely from the relay-parent. + persisted_validation_data_hash: Hash, + /// The blake2-256 hash of the PoV. + pov_hash: Hash, + /// The root of a block's erasure encoding Merkle tree. + erasure_root: Hash, + /// Reserved bytes. + reserved2: [u8; 64], + /// Hash of the para header that is being generated by this candidate. + para_head: Hash, + /// The blake2-256 hash of the validation code bytes. + validation_code_hash: ValidationCodeHash, +} + +impl From> for CandidateDescriptor { + fn from(value: CandidateDescriptorV2) -> Self { + Self { + para_id: value.para_id, + relay_parent: value.relay_parent, + collator: value.rebuild_collator_field(), + persisted_validation_data_hash: value.persisted_validation_data_hash, + pov_hash: value.pov_hash, + erasure_root: value.erasure_root, + signature: value.rebuild_signature_field(), + para_head: value.para_head, + validation_code_hash: value.validation_code_hash, + } + } +} + +#[cfg(any(feature = "runtime-benchmarks", feature = "test"))] +impl From> for CandidateDescriptorV2 { + fn from(value: CandidateDescriptor) -> Self { + Decode::decode(&mut value.encode().as_slice()).unwrap() + } +} + +impl CandidateDescriptorV2 { + /// Constructor + pub fn new( + para_id: Id, + relay_parent: H, + core_index: CoreIndex, + session_index: SessionIndex, + persisted_validation_data_hash: Hash, + pov_hash: Hash, + erasure_root: Hash, + para_head: Hash, + validation_code_hash: ValidationCodeHash, + ) -> Self { + Self { + para_id, + relay_parent, + version: InternalVersion(0), + core_index: core_index.0 as u16, + session_index, + reserved1: [0; 25], + persisted_validation_data_hash, + pov_hash, + erasure_root, + reserved2: [0; 64], + para_head, + validation_code_hash, + } + } + + /// Set the PoV size in the descriptor. Only for tests. + #[cfg(feature = "test")] + pub fn set_pov_hash(&mut self, pov_hash: Hash) { + self.pov_hash = pov_hash; + } + + /// Set the version in the descriptor. Only for tests. + #[cfg(feature = "test")] + pub fn set_version(&mut self, version: InternalVersion) { + self.version = version; + } +} + +/// A candidate-receipt at version 2. +#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Hash))] +pub struct CandidateReceiptV2 { + /// The descriptor of the candidate. + pub descriptor: CandidateDescriptorV2, + /// The hash of the encoded commitments made as a result of candidate execution. + pub commitments_hash: Hash, +} + +/// A candidate-receipt with commitments directly included. +#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(Hash))] +pub struct CommittedCandidateReceiptV2 { + /// The descriptor of the candidate. + pub descriptor: CandidateDescriptorV2, + /// The commitments of the candidate receipt. + pub commitments: CandidateCommitments, +} + +/// An event concerning a candidate. +#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(PartialEq))] +pub enum CandidateEvent { + /// This candidate receipt was backed in the most recent block. + /// This includes the core index the candidate is now occupying. + #[codec(index = 0)] + CandidateBacked(CandidateReceiptV2, HeadData, CoreIndex, GroupIndex), + /// This candidate receipt was included and became a parablock at the most recent block. + /// This includes the core index the candidate was occupying as well as the group responsible + /// for backing the candidate. + #[codec(index = 1)] + CandidateIncluded(CandidateReceiptV2, HeadData, CoreIndex, GroupIndex), + /// This candidate receipt was not made available in time and timed out. + /// This includes the core index the candidate was occupying. + #[codec(index = 2)] + CandidateTimedOut(CandidateReceiptV2, HeadData, CoreIndex), +} + +impl From> for super::v8::CandidateEvent { + fn from(value: CandidateEvent) -> Self { + match value { + CandidateEvent::CandidateBacked(receipt, head_data, core_index, group_index) => + super::v8::CandidateEvent::CandidateBacked( + receipt.into(), + head_data, + core_index, + group_index, + ), + CandidateEvent::CandidateIncluded(receipt, head_data, core_index, group_index) => + super::v8::CandidateEvent::CandidateIncluded( + receipt.into(), + head_data, + core_index, + group_index, + ), + CandidateEvent::CandidateTimedOut(receipt, head_data, core_index) => + super::v8::CandidateEvent::CandidateTimedOut(receipt.into(), head_data, core_index), + } + } +} + +impl CandidateReceiptV2 { + /// Get a reference to the candidate descriptor. + pub fn descriptor(&self) -> &CandidateDescriptorV2 { + &self.descriptor + } + + /// Computes the blake2-256 hash of the receipt. + pub fn hash(&self) -> CandidateHash + where + H: Encode, + { + CandidateHash(BlakeTwo256::hash_of(self)) + } +} + +impl CommittedCandidateReceiptV2 { + /// Transforms this into a plain `CandidateReceipt`. + pub fn to_plain(&self) -> CandidateReceiptV2 { + CandidateReceiptV2 { + descriptor: self.descriptor.clone(), + commitments_hash: self.commitments.hash(), + } + } + + /// Computes the hash of the committed candidate receipt. /// - /// This value only has effect on group rotations. If backers backed something at the end of - /// their rotation, the occupied core affects the backing group that comes afterwards. We limit - /// the effect one backing group can have on the next to `paras_availability_period` blocks. + /// This computes the canonical hash, not the hash of the directly encoded data. + /// Thus this is a shortcut for `candidate.to_plain().hash()`. + pub fn hash(&self) -> CandidateHash + where + H: Encode, + { + self.to_plain().hash() + } + + /// Does this committed candidate receipt corresponds to the given [`CandidateReceiptV2`]? + pub fn corresponds_to(&self, receipt: &CandidateReceiptV2) -> bool + where + H: PartialEq, + { + receipt.descriptor == self.descriptor && receipt.commitments_hash == self.commitments.hash() + } +} + +impl PartialOrd for CommittedCandidateReceiptV2 { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for CommittedCandidateReceiptV2 { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.descriptor + .para_id + .cmp(&other.descriptor.para_id) + .then_with(|| self.commitments.head_data.cmp(&other.commitments.head_data)) + } +} + +impl From> for super::v8::CommittedCandidateReceipt { + fn from(value: CommittedCandidateReceiptV2) -> Self { + Self { descriptor: value.descriptor.into(), commitments: value.commitments } + } +} + +impl From> for super::v8::CandidateReceipt { + fn from(value: CandidateReceiptV2) -> Self { + Self { descriptor: value.descriptor.into(), commitments_hash: value.commitments_hash } + } +} + +/// A strictly increasing sequence number, typically this would be the least significant byte of the +/// block number. +#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)] +pub struct CoreSelector(pub u8); + +/// An offset in the relay chain claim queue. +#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)] +pub struct ClaimQueueOffset(pub u8); + +/// Signals that a parachain can send to the relay chain via the UMP queue. +#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)] +pub enum UMPSignal { + /// A message sent by a parachain to select the core the candidate is committed to. + /// Relay chain validators, in particular backers, use the `CoreSelector` and + /// `ClaimQueueOffset` to compute the index of the core the candidate has committed to. + SelectCore(CoreSelector, ClaimQueueOffset), +} +/// Separator between `XCM` and `UMPSignal`. +pub const UMP_SEPARATOR: Vec = vec![]; + +impl CandidateCommitments { + /// Returns the core selector and claim queue offset the candidate has committed to, if any. + pub fn selected_core(&self) -> Option<(CoreSelector, ClaimQueueOffset)> { + // We need at least 2 messages for the separator and core selector + if self.upward_messages.len() < 2 { + return None + } + + let separator_pos = + self.upward_messages.iter().rposition(|message| message == &UMP_SEPARATOR)?; + + // Use first commitment + let message = self.upward_messages.get(separator_pos + 1)?; + + match UMPSignal::decode(&mut message.as_slice()).ok()? { + UMPSignal::SelectCore(core_selector, cq_offset) => Some((core_selector, cq_offset)), + } + } + + /// Returns the core index determined by `UMPSignal::SelectCore` commitment + /// and `assigned_cores`. /// - /// Within a group rotation there is no timeout as backers are only affecting themselves. + /// Returns `None` if there is no `UMPSignal::SelectCore` commitment or + /// assigned cores is empty. /// - /// Must be at least 1. With a value of 1, the previous group will not be able to negatively - /// affect the following group at the expense of a tight availability timeline at group - /// rotation boundaries. - pub paras_availability_period: BlockNumber, - /// The maximum number of validators to have per core. + /// `assigned_cores` must be a sorted vec of all core indices assigned to a parachain. + pub fn committed_core_index(&self, assigned_cores: &[&CoreIndex]) -> Option { + if assigned_cores.is_empty() { + return None + } + + self.selected_core().and_then(|(core_selector, _cq_offset)| { + let core_index = + **assigned_cores.get(core_selector.0 as usize % assigned_cores.len())?; + Some(core_index) + }) + } +} + +/// CandidateReceipt construction errors. +#[derive(PartialEq, Eq, Clone, Encode, Decode, TypeInfo, RuntimeDebug)] +pub enum CandidateReceiptError { + /// The specified core index is invalid. + InvalidCoreIndex, + /// The core index in commitments doesn't match the one in descriptor + CoreIndexMismatch, + /// The core selector or claim queue offset is invalid. + InvalidSelectedCore, + /// The parachain is not assigned to any core at specified claim queue offset. + NoAssignment, + /// No core was selected. The `SelectCore` commitment is mandatory for + /// v2 receipts if parachains has multiple cores assigned. + NoCoreSelected, + /// Unknown version. + UnknownVersion(InternalVersion), +} + +macro_rules! impl_getter { + ($field:ident, $type:ident) => { + /// Returns the value of $field field. + pub fn $field(&self) -> $type { + self.$field + } + }; +} + +impl CandidateDescriptorV2 { + impl_getter!(erasure_root, Hash); + impl_getter!(para_head, Hash); + impl_getter!(relay_parent, H); + impl_getter!(para_id, ParaId); + impl_getter!(persisted_validation_data_hash, Hash); + impl_getter!(pov_hash, Hash); + impl_getter!(validation_code_hash, ValidationCodeHash); + + /// Returns the candidate descriptor version. + /// The candidate is at version 2 if the reserved fields are zeroed out + /// and the internal `version` field is 0. + pub fn version(&self) -> CandidateDescriptorVersion { + if self.reserved2 != [0u8; 64] || self.reserved1 != [0u8; 25] { + return CandidateDescriptorVersion::V1 + } + + match self.version.0 { + 0 => CandidateDescriptorVersion::V2, + _ => CandidateDescriptorVersion::Unknown, + } + } + + fn rebuild_collator_field(&self) -> CollatorId { + let mut collator_id = Vec::with_capacity(32); + let core_index: [u8; 2] = self.core_index.to_ne_bytes(); + let session_index: [u8; 4] = self.session_index.to_ne_bytes(); + + collator_id.push(self.version.0); + collator_id.extend_from_slice(core_index.as_slice()); + collator_id.extend_from_slice(session_index.as_slice()); + collator_id.extend_from_slice(self.reserved1.as_slice()); + + CollatorId::from_slice(&collator_id.as_slice()) + .expect("Slice size is exactly 32 bytes; qed") + } + + /// Returns the collator id if this is a v1 `CandidateDescriptor` + pub fn collator(&self) -> Option { + if self.version() == CandidateDescriptorVersion::V1 { + Some(self.rebuild_collator_field()) + } else { + None + } + } + + fn rebuild_signature_field(&self) -> CollatorSignature { + CollatorSignature::from_slice(self.reserved2.as_slice()) + .expect("Slice size is exactly 64 bytes; qed") + } + + /// Returns the collator signature of `V1` candidate descriptors, `None` otherwise. + pub fn signature(&self) -> Option { + if self.version() == CandidateDescriptorVersion::V1 { + return Some(self.rebuild_signature_field()) + } + + None + } + + /// Returns the `core_index` of `V2` candidate descriptors, `None` otherwise. + pub fn core_index(&self) -> Option { + if self.version() == CandidateDescriptorVersion::V1 { + return None + } + + Some(CoreIndex(self.core_index as u32)) + } + + /// Returns the `core_index` of `V2` candidate descriptors, `None` otherwise. + pub fn session_index(&self) -> Option { + if self.version() == CandidateDescriptorVersion::V1 { + return None + } + + Some(self.session_index) + } +} + +impl CommittedCandidateReceiptV2 { + /// Checks if descriptor core index is equal to the committed core index. + /// Input `cores_per_para` is a claim queue snapshot stored as a mapping + /// between `ParaId` and the cores assigned per depth. + pub fn check_core_index( + &self, + cores_per_para: &TransposedClaimQueue, + ) -> Result<(), CandidateReceiptError> { + match self.descriptor.version() { + // Don't check v1 descriptors. + CandidateDescriptorVersion::V1 => return Ok(()), + CandidateDescriptorVersion::V2 => {}, + CandidateDescriptorVersion::Unknown => + return Err(CandidateReceiptError::UnknownVersion(self.descriptor.version)), + } + + if cores_per_para.is_empty() { + return Err(CandidateReceiptError::NoAssignment) + } + + let (offset, core_selected) = + if let Some((_core_selector, cq_offset)) = self.commitments.selected_core() { + (cq_offset.0, true) + } else { + // If no core has been selected then we use offset 0 (top of claim queue) + (0, false) + }; + + // The cores assigned to the parachain at above computed offset. + let assigned_cores = cores_per_para + .get(&self.descriptor.para_id()) + .ok_or(CandidateReceiptError::NoAssignment)? + .get(&offset) + .ok_or(CandidateReceiptError::NoAssignment)? + .into_iter() + .collect::>(); + + let core_index = if core_selected { + self.commitments + .committed_core_index(assigned_cores.as_slice()) + .ok_or(CandidateReceiptError::NoAssignment)? + } else { + // `SelectCore` commitment is mandatory for elastic scaling parachains. + if assigned_cores.len() > 1 { + return Err(CandidateReceiptError::NoCoreSelected) + } + + **assigned_cores.get(0).ok_or(CandidateReceiptError::NoAssignment)? + }; + + let descriptor_core_index = CoreIndex(self.descriptor.core_index as u32); + if core_index != descriptor_core_index { + return Err(CandidateReceiptError::CoreIndexMismatch) + } + + Ok(()) + } +} + +/// A backed (or backable, depending on context) candidate. +#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug, TypeInfo)] +pub struct BackedCandidate { + /// The candidate referred to. + candidate: CommittedCandidateReceiptV2, + /// The validity votes themselves, expressed as signatures. + validity_votes: Vec, + /// The indices of the validators within the group, expressed as a bitfield. May be extended + /// beyond the backing group size to contain the assigned core index, if ElasticScalingMVP is + /// enabled. + validator_indices: BitVec, +} + +/// Parachains inherent-data passed into the runtime by a block author +#[derive(Encode, Decode, Clone, PartialEq, RuntimeDebug, TypeInfo)] +pub struct InherentData { + /// Signed bitfields by validators about availability. + pub bitfields: UncheckedSignedAvailabilityBitfields, + /// Backed candidates for inclusion in the block. + pub backed_candidates: Vec>, + /// Sets of dispute votes for inclusion, + pub disputes: MultiDisputeStatementSet, + /// The parent block header. Used for checking state proofs. + pub parent_header: HDR, +} + +impl BackedCandidate { + /// Constructor + pub fn new( + candidate: CommittedCandidateReceiptV2, + validity_votes: Vec, + validator_indices: BitVec, + core_index: Option, + ) -> Self { + let mut instance = Self { candidate, validity_votes, validator_indices }; + if let Some(core_index) = core_index { + instance.inject_core_index(core_index); + } + instance + } + + /// Get a reference to the committed candidate receipt of the candidate. + pub fn candidate(&self) -> &CommittedCandidateReceiptV2 { + &self.candidate + } + + /// Get a mutable reference to the committed candidate receipt of the candidate. + /// Only for testing. + #[cfg(feature = "test")] + pub fn candidate_mut(&mut self) -> &mut CommittedCandidateReceiptV2 { + &mut self.candidate + } + /// Get a reference to the descriptor of the candidate. + pub fn descriptor(&self) -> &CandidateDescriptorV2 { + &self.candidate.descriptor + } + + /// Get a mutable reference to the descriptor of the candidate. Only for testing. + #[cfg(feature = "test")] + pub fn descriptor_mut(&mut self) -> &mut CandidateDescriptorV2 { + &mut self.candidate.descriptor + } + + /// Get a reference to the validity votes of the candidate. + pub fn validity_votes(&self) -> &[ValidityAttestation] { + &self.validity_votes + } + + /// Get a mutable reference to validity votes of the para. + pub fn validity_votes_mut(&mut self) -> &mut Vec { + &mut self.validity_votes + } + + /// Compute this candidate's hash. + pub fn hash(&self) -> CandidateHash + where + H: Clone + Encode, + { + self.candidate.to_plain().hash() + } + + /// Get this candidate's receipt. + pub fn receipt(&self) -> CandidateReceiptV2 + where + H: Clone, + { + self.candidate.to_plain() + } + + /// Get a copy of the validator indices and the assumed core index, if any. + pub fn validator_indices_and_core_index( + &self, + core_index_enabled: bool, + ) -> (&BitSlice, Option) { + // This flag tells us if the block producers must enable Elastic Scaling MVP hack. + // It extends `BackedCandidate::validity_indices` to store a 8 bit core index. + if core_index_enabled { + let core_idx_offset = self.validator_indices.len().saturating_sub(8); + if core_idx_offset > 0 { + let (validator_indices_slice, core_idx_slice) = + self.validator_indices.split_at(core_idx_offset); + return ( + validator_indices_slice, + Some(CoreIndex(core_idx_slice.load::() as u32)), + ); + } + } + + (&self.validator_indices, None) + } + + /// Inject a core index in the validator_indices bitvec. + fn inject_core_index(&mut self, core_index: CoreIndex) { + let core_index_to_inject: BitVec = + BitVec::from_vec(vec![core_index.0 as u8]); + self.validator_indices.extend(core_index_to_inject); + } + + /// Update the validator indices and core index in the candidate. + pub fn set_validator_indices_and_core_index( + &mut self, + new_indices: BitVec, + maybe_core_index: Option, + ) { + self.validator_indices = new_indices; + + if let Some(core_index) = maybe_core_index { + self.inject_core_index(core_index); + } + } +} + +/// Scraped runtime backing votes and resolved disputes. +#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo)] +#[cfg_attr(feature = "std", derive(PartialEq))] +pub struct ScrapedOnChainVotes { + /// The session in which the block was included. + pub session: SessionIndex, + /// Set of backing validators for each candidate, represented by its candidate + /// receipt. + pub backing_validators_per_candidate: + Vec<(CandidateReceiptV2, Vec<(ValidatorIndex, ValidityAttestation)>)>, + /// On-chain-recorded set of disputes. + /// Note that the above `backing_validators` are + /// unrelated to the backers of the disputes candidates. + pub disputes: MultiDisputeStatementSet, +} + +impl From> for super::v8::ScrapedOnChainVotes { + fn from(value: ScrapedOnChainVotes) -> Self { + Self { + session: value.session, + backing_validators_per_candidate: value + .backing_validators_per_candidate + .into_iter() + .map(|(receipt, validators)| (receipt.into(), validators)) + .collect::>(), + disputes: value.disputes, + } + } +} + +/// Information about a core which is currently occupied. +#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(PartialEq))] +pub struct OccupiedCore { + // NOTE: this has no ParaId as it can be deduced from the candidate descriptor. + /// If this core is freed by availability, this is the assignment that is next up on this + /// core, if any. None if there is nothing queued for this core. + pub next_up_on_available: Option, + /// The relay-chain block number this began occupying the core at. + pub occupied_since: N, + /// The relay-chain block this will time-out at, if any. + pub time_out_at: N, + /// If this core is freed by being timed-out, this is the assignment that is next up on this + /// core. None if there is nothing queued for this core or there is no possibility of timing + /// out. + pub next_up_on_time_out: Option, + /// A bitfield with 1 bit for each validator in the set. `1` bits mean that the corresponding + /// validators has attested to availability on-chain. A 2/3+ majority of `1` bits means that + /// this will be available. + pub availability: BitVec, + /// The group assigned to distribute availability pieces of this candidate. + pub group_responsible: GroupIndex, + /// The hash of the candidate occupying the core. + pub candidate_hash: CandidateHash, + /// The descriptor of the candidate occupying the core. + pub candidate_descriptor: CandidateDescriptorV2, +} + +/// The state of a particular availability core. +#[derive(Clone, Encode, Decode, TypeInfo, RuntimeDebug)] +#[cfg_attr(feature = "std", derive(PartialEq))] +pub enum CoreState { + /// The core is currently occupied. + #[codec(index = 0)] + Occupied(OccupiedCore), + /// The core is currently free, with a para scheduled and given the opportunity + /// to occupy. /// - /// `None` means no maximum. - pub max_validators_per_core: Option, - /// The amount of blocks ahead to schedule paras. - pub lookahead: u32, - /// How many cores are managed by the coretime chain. - pub num_cores: u32, - /// The max number of times a claim can time out in availability. - pub max_availability_timeouts: u32, - /// The maximum queue size of the pay as you go module. - pub on_demand_queue_max_size: u32, - /// The target utilization of the spot price queue in percentages. - pub on_demand_target_queue_utilization: Perbill, - /// How quickly the fee rises in reaction to increased utilization. - /// The lower the number the slower the increase. - pub on_demand_fee_variability: Perbill, - /// The minimum amount needed to claim a slot in the spot pricing queue. - pub on_demand_base_fee: Balance, - /// The number of blocks a claim stays in the scheduler's claim queue before getting cleared. - /// This number should go reasonably higher than the number of blocks in the async backing - /// lookahead. - pub ttl: BlockNumber, -} - -impl> Default for SchedulerParams { - fn default() -> Self { + /// If a particular Collator is required to author this block, that is also present in this + /// variant. + #[codec(index = 1)] + Scheduled(ScheduledCore), + /// The core is currently free and there is nothing scheduled. This can be the case for + /// parathread cores when there are no parathread blocks queued. Parachain cores will never be + /// left idle. + #[codec(index = 2)] + Free, +} + +impl From> for super::v8::OccupiedCore { + fn from(value: OccupiedCore) -> Self { Self { - group_rotation_frequency: 1u32.into(), - paras_availability_period: 1u32.into(), - max_validators_per_core: Default::default(), - lookahead: 1, - num_cores: Default::default(), - max_availability_timeouts: Default::default(), - on_demand_queue_max_size: ON_DEMAND_DEFAULT_QUEUE_MAX_SIZE, - on_demand_target_queue_utilization: Perbill::from_percent(25), - on_demand_fee_variability: Perbill::from_percent(3), - on_demand_base_fee: 10_000_000u128, - ttl: 5u32.into(), + next_up_on_available: value.next_up_on_available, + occupied_since: value.occupied_since, + time_out_at: value.time_out_at, + next_up_on_time_out: value.next_up_on_time_out, + availability: value.availability, + group_responsible: value.group_responsible, + candidate_hash: value.candidate_hash, + candidate_descriptor: value.candidate_descriptor.into(), + } + } +} + +impl From> for super::v8::CoreState { + fn from(value: CoreState) -> Self { + match value { + CoreState::Free => super::v8::CoreState::Free, + CoreState::Scheduled(core) => super::v8::CoreState::Scheduled(core), + CoreState::Occupied(occupied_core) => + super::v8::CoreState::Occupied(occupied_core.into()), + } + } +} + +/// The claim queue mapped by parachain id. +pub type TransposedClaimQueue = BTreeMap>>; + +/// Returns a mapping between the para id and the core indices assigned at different +/// depths in the claim queue. +pub fn transpose_claim_queue( + claim_queue: BTreeMap>, +) -> TransposedClaimQueue { + let mut per_para_claim_queue = BTreeMap::new(); + + for (core, paras) in claim_queue { + // Iterate paras assigned to this core at each depth. + for (depth, para) in paras.into_iter().enumerate() { + let depths: &mut BTreeMap> = + per_para_claim_queue.entry(para).or_insert_with(|| Default::default()); + + depths.entry(depth as u8).or_default().insert(core); + } + } + + per_para_claim_queue +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + v8::{ + tests::dummy_committed_candidate_receipt as dummy_old_committed_candidate_receipt, + CommittedCandidateReceipt, Hash, HeadData, ValidationCode, + }, + vstaging::{CandidateDescriptorV2, CommittedCandidateReceiptV2}, + }; + + fn dummy_collator_signature() -> CollatorSignature { + CollatorSignature::from_slice(&mut (0..64).into_iter().collect::>().as_slice()) + .expect("64 bytes; qed") + } + + fn dummy_collator_id() -> CollatorId { + CollatorId::from_slice(&mut (0..32).into_iter().collect::>().as_slice()) + .expect("32 bytes; qed") + } + + pub fn dummy_committed_candidate_receipt_v2() -> CommittedCandidateReceiptV2 { + let zeros = Hash::zero(); + let reserved2 = [0; 64]; + + CommittedCandidateReceiptV2 { + descriptor: CandidateDescriptorV2 { + para_id: 0.into(), + relay_parent: zeros, + version: InternalVersion(0), + core_index: 123, + session_index: 1, + reserved1: Default::default(), + persisted_validation_data_hash: zeros, + pov_hash: zeros, + erasure_root: zeros, + reserved2, + para_head: zeros, + validation_code_hash: ValidationCode(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]).hash(), + }, + commitments: CandidateCommitments { + head_data: HeadData(vec![]), + upward_messages: vec![].try_into().expect("empty vec fits within bounds"), + new_validation_code: None, + horizontal_messages: vec![].try_into().expect("empty vec fits within bounds"), + processed_downward_messages: 0, + hrmp_watermark: 0_u32, + }, } } + + #[test] + fn is_binary_compatibile() { + let old_ccr = dummy_old_committed_candidate_receipt(); + let new_ccr = dummy_committed_candidate_receipt_v2(); + + assert_eq!(old_ccr.encoded_size(), new_ccr.encoded_size()); + + let encoded_old = old_ccr.encode(); + + // Deserialize from old candidate receipt. + let new_ccr: CommittedCandidateReceiptV2 = + Decode::decode(&mut encoded_old.as_slice()).unwrap(); + + // We get same candidate hash. + assert_eq!(old_ccr.hash(), new_ccr.hash()); + } + + #[test] + fn invalid_version_descriptor() { + let mut new_ccr = dummy_committed_candidate_receipt_v2(); + assert_eq!(new_ccr.descriptor.version(), CandidateDescriptorVersion::V2); + // Put some unknown version. + new_ccr.descriptor.version = InternalVersion(100); + + // Deserialize as V1. + let new_ccr: CommittedCandidateReceiptV2 = + Decode::decode(&mut new_ccr.encode().as_slice()).unwrap(); + + assert_eq!(new_ccr.descriptor.version(), CandidateDescriptorVersion::Unknown); + assert_eq!( + new_ccr.check_core_index(&BTreeMap::new()), + Err(CandidateReceiptError::UnknownVersion(InternalVersion(100))) + ) + } + + #[test] + fn test_ump_commitment() { + let mut new_ccr = dummy_committed_candidate_receipt_v2(); + new_ccr.descriptor.core_index = 123; + new_ccr.descriptor.para_id = ParaId::new(1000); + + // dummy XCM messages + new_ccr.commitments.upward_messages.force_push(vec![0u8; 256]); + new_ccr.commitments.upward_messages.force_push(vec![0xff; 256]); + + // separator + new_ccr.commitments.upward_messages.force_push(UMP_SEPARATOR); + + // CoreIndex commitment + new_ccr + .commitments + .upward_messages + .force_push(UMPSignal::SelectCore(CoreSelector(0), ClaimQueueOffset(1)).encode()); + + let mut cq = BTreeMap::new(); + cq.insert( + CoreIndex(123), + vec![new_ccr.descriptor.para_id(), new_ccr.descriptor.para_id()].into(), + ); + + assert_eq!(new_ccr.check_core_index(&transpose_claim_queue(cq)), Ok(())); + } + + #[test] + fn test_invalid_ump_commitment() { + let mut new_ccr = dummy_committed_candidate_receipt_v2(); + new_ccr.descriptor.core_index = 0; + new_ccr.descriptor.para_id = ParaId::new(1000); + + new_ccr.commitments.upward_messages.force_push(UMP_SEPARATOR); + new_ccr.commitments.upward_messages.force_push(UMP_SEPARATOR); + + let mut cq = BTreeMap::new(); + cq.insert(CoreIndex(0), vec![new_ccr.descriptor.para_id()].into()); + + // The check should not fail because no `SelectCore` signal was sent. + // The message is optional. + assert!(new_ccr.check_core_index(&transpose_claim_queue(cq)).is_ok()); + + // Garbage message. + new_ccr.commitments.upward_messages.force_push(vec![0, 13, 200].encode()); + + // No `SelectCore` can be decoded. + assert_eq!(new_ccr.commitments.selected_core(), None); + + let mut cq = BTreeMap::new(); + cq.insert( + CoreIndex(0), + vec![new_ccr.descriptor.para_id(), new_ccr.descriptor.para_id()].into(), + ); + cq.insert( + CoreIndex(100), + vec![new_ccr.descriptor.para_id(), new_ccr.descriptor.para_id()].into(), + ); + + assert_eq!( + new_ccr.check_core_index(&transpose_claim_queue(cq.clone())), + Err(CandidateReceiptError::NoCoreSelected) + ); + + new_ccr.commitments.upward_messages.clear(); + new_ccr.commitments.upward_messages.force_push(UMP_SEPARATOR); + + new_ccr + .commitments + .upward_messages + .force_push(UMPSignal::SelectCore(CoreSelector(0), ClaimQueueOffset(1)).encode()); + + // Duplicate + new_ccr + .commitments + .upward_messages + .force_push(UMPSignal::SelectCore(CoreSelector(1), ClaimQueueOffset(1)).encode()); + + // Duplicate doesn't override first signal. + assert_eq!(new_ccr.check_core_index(&transpose_claim_queue(cq)), Ok(())); + } + + #[test] + fn test_version2_receipts_decoded_as_v1() { + let mut new_ccr = dummy_committed_candidate_receipt_v2(); + new_ccr.descriptor.core_index = 123; + new_ccr.descriptor.para_id = ParaId::new(1000); + + // dummy XCM messages + new_ccr.commitments.upward_messages.force_push(vec![0u8; 256]); + new_ccr.commitments.upward_messages.force_push(vec![0xff; 256]); + + // separator + new_ccr.commitments.upward_messages.force_push(UMP_SEPARATOR); + + // CoreIndex commitment + new_ccr + .commitments + .upward_messages + .force_push(UMPSignal::SelectCore(CoreSelector(0), ClaimQueueOffset(1)).encode()); + + let encoded_ccr = new_ccr.encode(); + let decoded_ccr: CommittedCandidateReceipt = + Decode::decode(&mut encoded_ccr.as_slice()).unwrap(); + + assert_eq!(decoded_ccr.descriptor.relay_parent, new_ccr.descriptor.relay_parent()); + assert_eq!(decoded_ccr.descriptor.para_id, new_ccr.descriptor.para_id()); + + assert_eq!(new_ccr.hash(), decoded_ccr.hash()); + + // Encode v1 and decode as V2 + let encoded_ccr = new_ccr.encode(); + let v2_ccr: CommittedCandidateReceiptV2 = + Decode::decode(&mut encoded_ccr.as_slice()).unwrap(); + + assert_eq!(v2_ccr.descriptor.core_index(), Some(CoreIndex(123))); + + let mut cq = BTreeMap::new(); + cq.insert( + CoreIndex(123), + vec![new_ccr.descriptor.para_id(), new_ccr.descriptor.para_id()].into(), + ); + + assert_eq!(new_ccr.check_core_index(&transpose_claim_queue(cq)), Ok(())); + + assert_eq!(new_ccr.hash(), v2_ccr.hash()); + } + + // Only check descriptor `core_index` field of v2 descriptors. If it is v1, that field + // will be garbage. + #[test] + fn test_v1_descriptors_with_ump_signal() { + let mut ccr = dummy_old_committed_candidate_receipt(); + ccr.descriptor.para_id = ParaId::new(1024); + // Adding collator signature should make it decode as v1. + ccr.descriptor.signature = dummy_collator_signature(); + ccr.descriptor.collator = dummy_collator_id(); + + ccr.commitments.upward_messages.force_push(UMP_SEPARATOR); + ccr.commitments + .upward_messages + .force_push(UMPSignal::SelectCore(CoreSelector(1), ClaimQueueOffset(1)).encode()); + + let encoded_ccr: Vec = ccr.encode(); + + let v1_ccr: CommittedCandidateReceiptV2 = + Decode::decode(&mut encoded_ccr.as_slice()).unwrap(); + + assert_eq!(v1_ccr.descriptor.version(), CandidateDescriptorVersion::V1); + assert!(v1_ccr.commitments.selected_core().is_some()); + + let mut cq = BTreeMap::new(); + cq.insert(CoreIndex(0), vec![v1_ccr.descriptor.para_id()].into()); + cq.insert(CoreIndex(1), vec![v1_ccr.descriptor.para_id()].into()); + + assert!(v1_ccr.check_core_index(&transpose_claim_queue(cq)).is_ok()); + + assert_eq!( + v1_ccr.commitments.committed_core_index(&vec![&CoreIndex(10), &CoreIndex(5)]), + Some(CoreIndex(5)), + ); + + assert_eq!(v1_ccr.descriptor.core_index(), None); + } + + #[test] + fn test_core_select_is_optional() { + // Testing edge case when collators provide zeroed signature and collator id. + let mut old_ccr = dummy_old_committed_candidate_receipt(); + old_ccr.descriptor.para_id = ParaId::new(1000); + let encoded_ccr: Vec = old_ccr.encode(); + + let new_ccr: CommittedCandidateReceiptV2 = + Decode::decode(&mut encoded_ccr.as_slice()).unwrap(); + + let mut cq = BTreeMap::new(); + cq.insert(CoreIndex(0), vec![new_ccr.descriptor.para_id()].into()); + + // Since collator sig and id are zeroed, it means that the descriptor uses format + // version 2. Should still pass checks without core selector. + assert!(new_ccr.check_core_index(&transpose_claim_queue(cq)).is_ok()); + + let mut cq = BTreeMap::new(); + cq.insert(CoreIndex(0), vec![new_ccr.descriptor.para_id()].into()); + cq.insert(CoreIndex(1), vec![new_ccr.descriptor.para_id()].into()); + + // Should fail because 2 cores are assigned, + assert_eq!( + new_ccr.check_core_index(&transpose_claim_queue(cq)), + Err(CandidateReceiptError::NoCoreSelected) + ); + + // Adding collator signature should make it decode as v1. + old_ccr.descriptor.signature = dummy_collator_signature(); + old_ccr.descriptor.collator = dummy_collator_id(); + + let old_ccr_hash = old_ccr.hash(); + + let encoded_ccr: Vec = old_ccr.encode(); + + let new_ccr: CommittedCandidateReceiptV2 = + Decode::decode(&mut encoded_ccr.as_slice()).unwrap(); + + assert_eq!(new_ccr.descriptor.signature(), Some(old_ccr.descriptor.signature)); + assert_eq!(new_ccr.descriptor.collator(), Some(old_ccr.descriptor.collator)); + + assert_eq!(new_ccr.descriptor.core_index(), None); + assert_eq!(new_ccr.descriptor.para_id(), ParaId::new(1000)); + + assert_eq!(old_ccr_hash, new_ccr.hash()); + } } diff --git a/polkadot/primitives/test-helpers/src/lib.rs b/polkadot/primitives/test-helpers/src/lib.rs index d43cf3317e57..b0f78717dd97 100644 --- a/polkadot/primitives/test-helpers/src/lib.rs +++ b/polkadot/primitives/test-helpers/src/lib.rs @@ -23,9 +23,10 @@ //! Note that `dummy_` prefixed values are meant to be fillers, that should not matter, and will //! contain randomness based data. use polkadot_primitives::{ + vstaging::{CandidateDescriptorV2, CandidateReceiptV2, CommittedCandidateReceiptV2}, CandidateCommitments, CandidateDescriptor, CandidateReceipt, CollatorId, CollatorSignature, - CommittedCandidateReceipt, Hash, HeadData, Id as ParaId, PersistedValidationData, - ValidationCode, ValidationCodeHash, ValidatorId, + CommittedCandidateReceipt, CoreIndex, Hash, HeadData, Id as ParaId, PersistedValidationData, + SessionIndex, ValidationCode, ValidationCodeHash, ValidatorId, }; pub use rand; use sp_application_crypto::sr25519; @@ -42,6 +43,14 @@ pub fn dummy_candidate_receipt>(relay_parent: H) -> CandidateRece } } +/// Creates a v2 candidate receipt with filler data. +pub fn dummy_candidate_receipt_v2>(relay_parent: H) -> CandidateReceiptV2 { + CandidateReceiptV2:: { + commitments_hash: dummy_candidate_commitments(dummy_head_data()).hash(), + descriptor: dummy_candidate_descriptor_v2(relay_parent), + } +} + /// Creates a committed candidate receipt with filler data. pub fn dummy_committed_candidate_receipt>( relay_parent: H, @@ -52,6 +61,16 @@ pub fn dummy_committed_candidate_receipt>( } } +/// Creates a v2 committed candidate receipt with filler data. +pub fn dummy_committed_candidate_receipt_v2>( + relay_parent: H, +) -> CommittedCandidateReceiptV2 { + CommittedCandidateReceiptV2 { + descriptor: dummy_candidate_descriptor_v2::(relay_parent), + commitments: dummy_candidate_commitments(dummy_head_data()), + } +} + /// Create a candidate receipt with a bogus signature and filler data. Optionally set the commitment /// hash with the `commitments` arg. pub fn dummy_candidate_receipt_bad_sig( @@ -124,6 +143,23 @@ pub fn dummy_candidate_descriptor>(relay_parent: H) -> CandidateD descriptor } +/// Create a v2 candidate descriptor with filler data. +pub fn dummy_candidate_descriptor_v2>(relay_parent: H) -> CandidateDescriptorV2 { + let invalid = Hash::zero(); + let descriptor = make_valid_candidate_descriptor_v2( + 1.into(), + relay_parent, + CoreIndex(1), + 1, + invalid, + invalid, + invalid, + invalid, + invalid, + ); + descriptor +} + /// Create meaningless validation code. pub fn dummy_validation_code() -> ValidationCode { ValidationCode(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]) @@ -134,16 +170,16 @@ pub fn dummy_head_data() -> HeadData { HeadData(vec![]) } -/// Create a meaningless collator id. -pub fn dummy_collator() -> CollatorId { - CollatorId::from(sr25519::Public::default()) -} - /// Create a meaningless validator id. pub fn dummy_validator() -> ValidatorId { ValidatorId::from(sr25519::Public::default()) } +/// Create a meaningless collator id. +pub fn dummy_collator() -> CollatorId { + CollatorId::from(sr25519::Public::default()) +} + /// Create a meaningless collator signature. pub fn dummy_collator_signature() -> CollatorSignature { CollatorSignature::from(sr25519::Signature::default()) @@ -232,6 +268,34 @@ pub fn make_valid_candidate_descriptor>( descriptor } +/// Create a v2 candidate descriptor. +pub fn make_valid_candidate_descriptor_v2>( + para_id: ParaId, + relay_parent: H, + core_index: CoreIndex, + session_index: SessionIndex, + persisted_validation_data_hash: Hash, + pov_hash: Hash, + validation_code_hash: impl Into, + para_head: Hash, + erasure_root: Hash, +) -> CandidateDescriptorV2 { + let validation_code_hash = validation_code_hash.into(); + + let descriptor = CandidateDescriptorV2::new( + para_id, + relay_parent, + core_index, + session_index, + persisted_validation_data_hash, + pov_hash, + erasure_root, + para_head, + validation_code_hash, + ); + + descriptor +} /// After manually modifying the candidate descriptor, resign with a defined collator key. pub fn resign_candidate_descriptor_with_collator>( descriptor: &mut CandidateDescriptor, diff --git a/polkadot/roadmap/implementers-guide/src/node/approval/approval-distribution.md b/polkadot/roadmap/implementers-guide/src/node/approval/approval-distribution.md index c987b7fe5bea..e09418c7d5ab 100644 --- a/polkadot/roadmap/implementers-guide/src/node/approval/approval-distribution.md +++ b/polkadot/roadmap/implementers-guide/src/node/approval/approval-distribution.md @@ -66,8 +66,8 @@ Input: * `OverseerSignal::BlockFinalized` Output: - * `ApprovalVotingMessage::CheckAndImportAssignment` - * `ApprovalVotingMessage::CheckAndImportApproval` + * `ApprovalVotingMessage::ImportAssignment` + * `ApprovalVotingMessage::ImportApproval` * `NetworkBridgeMessage::SendValidationMessage::ApprovalDistribution` ## Functionality @@ -253,8 +253,30 @@ The algorithm is the following: boost, add the fingerprint to the peer's knowledge only if it knows about the block and return. Note that we must do this after checking for out-of-view and if the peers knows about the block to avoid being spammed. If we did this check earlier, a peer could provide data out-of-view repeatedly and be rewarded for it. - * Dispatch `ApprovalVotingMessage::CheckAndImportAssignment(assignment)` and wait for the response. + * Check the assignment certificate is valid. + * If the cert kind is `RelayVRFModulo`, then the certificate is valid as long as `sample < + session_info.relay_vrf_samples` and the VRF is valid for the validator's key with the input + `block_entry.relay_vrf_story ++ sample.encode()` as described with + [the approvals protocol section](../../protocol-approval.md#assignment-criteria). We set + `core_index = vrf.make_bytes().to_u32() % session_info.n_cores`. If the `BlockEntry` causes + inclusion of a candidate at `core_index`, then this is a valid assignment for the candidate + at `core_index` and has delay tranche 0. Otherwise, it can be ignored. + * If the cert kind is `RelayVRFModuloCompact`, then the certificate is valid as long as the VRF + is valid for the validator's key with the input `block_entry.relay_vrf_story ++ relay_vrf_samples.encode()` + as described with [the approvals protocol section](../../protocol-approval.md#assignment-criteria). + We enforce that all `core_bitfield` indices are included in the set of the core indices sampled from the + VRF Output. The assignment is considered a valid tranche0 assignment for all claimed candidates if all + `core_bitfield` indices match the core indices where the claimed candidates were included at. + * If the cert kind is `RelayVRFDelay`, then we check if the VRF is valid for the validator's key with the + input `block_entry.relay_vrf_story ++ cert.core_index.encode()` as described in [the approvals protocol + section](../../protocol-approval.md#assignment-criteria). The cert can be ignored if the block did not + cause inclusion of a candidate on that core index. Otherwise, this is a valid assignment for the included + candidate. The delay tranche for the assignment is determined by reducing + `(vrf.make_bytes().to_u64() % (session_info.n_delay_tranches + session_info.zeroth_delay_tranche_width)).saturating_sub(session_info.zeroth_delay_tranche_width)`. + * We also check that the core index derived by the output is covered by the `VRFProof` by means of an auxiliary signature. + * If the delay tranche is too far in the future, return `AssignmentCheckResult::TooFarInFuture`. * If the result is `AssignmentCheckResult::Accepted` + * Dispatch `ApprovalVotingMessage::ImportAssignment(assignment)` to approval-voting to import the assignment. * If the vote was accepted but not duplicate, give the peer a positive reputation boost * add the fingerprint to both our and the peer's knowledge in the `BlockEntry`. Note that we only doing this after making sure we have the right fingerprint. @@ -293,10 +315,12 @@ Imports an approval signature referenced by block hash and candidate index: boost, add the fingerprint to the peer's knowledge only if it knows about the block and return. Note that we must do this after checking for out-of-view to avoid being spammed. If we did this check earlier, a peer could provide data out-of-view repeatedly and be rewarded for it. - * Dispatch `ApprovalVotingMessage::CheckAndImportApproval(approval)` and wait for the response. - * If the result is `VoteCheckResult::Accepted(())`: + * Construct a `SignedApprovalVote` using the candidates hashes and check against the validator's approval key, + based on the session info of the block. If invalid or no such validator, return `Err(InvalidVoteError)`. + * If the result of checking the signature is `Ok(CheckedIndirectSignedApprovalVote)`: + * Dispatch `ApprovalVotingMessage::ImportApproval(approval)` . * Give the peer a positive reputation boost and add the fingerprint to both our and the peer's knowledge. - * If the result is `VoteCheckResult::Bad`: + * If the result is `Err(InvalidVoteError)`: * Report the peer and return. * Load the candidate entry for the given candidate index. It should exist unless there is a logic error in the approval voting subsystem. diff --git a/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting-parallel.md b/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting-parallel.md new file mode 100644 index 000000000000..84661b7bf9b3 --- /dev/null +++ b/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting-parallel.md @@ -0,0 +1,30 @@ +# Approval voting parallel + +The approval-voting-parallel subsystem acts as an orchestrator for the tasks handled by the [Approval Voting](approval-voting.md) +and [Approval Distribution](approval-distribution.md) subsystems. Initially, these two systems operated separately and interacted +with each other and other subsystems through orchestra. + +With approval-voting-parallel, we have a single subsystem that creates two types of workers: +- Four approval-distribution workers that operate in parallel, each handling tasks based on the validator_index of the message + originator. +- One approval-voting worker that performs the tasks previously managed by the standalone approval-voting subsystem. + +This subsystem does not maintain any state. Instead, it functions as an orchestrator that: +- Spawns and initializes each workers. +- Forwards each message and signal to the appropriate worker. +- Aggregates results for messages that require input from more than one worker, such as GetApprovalSignatures. + +## Forwarding logic + +The messages received and forwarded by approval-voting-parallel split in three categories: +- Signals which need to be forwarded to all workers. +- Messages that only the `approval-voting` worker needs to handle, `ApprovalVotingParallelMessage::ApprovedAncestor` + and `ApprovalVotingParallelMessage::GetApprovalSignaturesForCandidate` +- Control messages that all `approval-distribution` workers need to receive `ApprovalVotingParallelMessage::NewBlocks`, + `ApprovalVotingParallelMessage::ApprovalCheckingLagUpdate` and all network bridge variants `ApprovalVotingParallelMessage::NetworkBridgeUpdate` + except `ApprovalVotingParallelMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage)` +- Data messages `ApprovalVotingParallelMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage)` which need to be sent + just to a single `approval-distribution` worker based on the ValidatorIndex. The logic for assigning the work is: + ``` + assigned_worker_index = validator_index % number_of_workers; + ``` diff --git a/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting.md b/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting.md index 9b4082c49e2f..40394412d81b 100644 --- a/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting.md +++ b/polkadot/roadmap/implementers-guide/src/node/approval/approval-voting.md @@ -39,8 +39,8 @@ been approved. ## Protocol Input: - * `ApprovalVotingMessage::CheckAndImportAssignment` - * `ApprovalVotingMessage::CheckAndImportApproval` + * `ApprovalVotingMessage::ImportAssignment` + * `ApprovalVotingMessage::ImportApproval` * `ApprovalVotingMessage::ApprovedAncestor` Output: @@ -266,39 +266,17 @@ On receiving an `OverseerSignal::ActiveLeavesUpdate(update)`: 0-tranche assignment, kick off approval work, and schedule the next delay. * Dispatch an `ApprovalDistributionMessage::NewBlocks` with the meta information filled out for each new block. -#### `ApprovalVotingMessage::CheckAndImportAssignment` +#### `ApprovalVotingMessage::ImportAssignment` -On receiving a `ApprovalVotingMessage::CheckAndImportAssignment` message, we check the assignment cert against the block -entry. The cert itself contains information necessary to determine the candidate that is being assigned-to. In detail: +On receiving a `ApprovalVotingMessage::ImportAssignment` message, we assume the assignment cert itself has already been +checked to be valid we proceed then to import the assignment inside the block entry. The cert itself contains +information necessary to determine the candidate that is being assigned-to. In detail: * Load the `BlockEntry` for the relay-parent referenced by the message. If there is none, return `AssignmentCheckResult::Bad`. * Fetch the `SessionInfo` for the session of the block * Determine the assignment key of the validator based on that. * Determine the claimed core index by looking up the candidate with given index in `block_entry.candidates`. Return `AssignmentCheckResult::Bad` if missing. - * Check the assignment cert - * If the cert kind is `RelayVRFModulo`, then the certificate is valid as long as `sample < - session_info.relay_vrf_samples` and the VRF is valid for the validator's key with the input - `block_entry.relay_vrf_story ++ sample.encode()` as described with - [the approvals protocol section](../../protocol-approval.md#assignment-criteria). We set - `core_index = vrf.make_bytes().to_u32() % session_info.n_cores`. If the `BlockEntry` causes - inclusion of a candidate at `core_index`, then this is a valid assignment for the candidate - at `core_index` and has delay tranche 0. Otherwise, it can be ignored. - * If the cert kind is `RelayVRFModuloCompact`, then the certificate is valid as long as the VRF - is valid for the validator's key with the input `block_entry.relay_vrf_story ++ relay_vrf_samples.encode()` - as described with [the approvals protocol section](../../protocol-approval.md#assignment-criteria). - We enforce that all `core_bitfield` indices are included in the set of the core indices sampled from the - VRF Output. The assignment is considered a valid tranche0 assignment for all claimed candidates if all - `core_bitfield` indices match the core indices where the claimed candidates were included at. - - * If the cert kind is `RelayVRFDelay`, then we check if the VRF is valid for the validator's key with the - input `block_entry.relay_vrf_story ++ cert.core_index.encode()` as described in [the approvals protocol - section](../../protocol-approval.md#assignment-criteria). The cert can be ignored if the block did not - cause inclusion of a candidate on that core index. Otherwise, this is a valid assignment for the included - candidate. The delay tranche for the assignment is determined by reducing - `(vrf.make_bytes().to_u64() % (session_info.n_delay_tranches + session_info.zeroth_delay_tranche_width)).saturating_sub(session_info.zeroth_delay_tranche_width)`. - * We also check that the core index derived by the output is covered by the `VRFProof` by means of an auxiliary signature. - * If the delay tranche is too far in the future, return `AssignmentCheckResult::TooFarInFuture`. * Import the assignment. * Load the candidate in question and access the `approval_entry` for the block hash the cert references. * Ignore if we already observe the validator as having been assigned. @@ -309,14 +287,12 @@ entry. The cert itself contains information necessary to determine the candidate * [Schedule a wakeup](#schedule-wakeup) for this block, candidate pair. * return the appropriate `AssignmentCheckResult` on the response channel. -#### `ApprovalVotingMessage::CheckAndImportApproval` +#### `ApprovalVotingMessage::ImportApproval` -On receiving a `CheckAndImportApproval(indirect_approval_vote, response_channel)` message: +On receiving a `ImportApproval(indirect_approval_vote, response_channel)` message: * Fetch the `BlockEntry` from the indirect approval vote's `block_hash`. If none, return `ApprovalCheckResult::Bad`. * Fetch all `CandidateEntry` from the indirect approval vote's `candidate_indices`. If the block did not trigger inclusion of enough candidates, return `ApprovalCheckResult::Bad`. - * Construct a `SignedApprovalVote` using the candidates hashes and check against the validator's approval key, - based on the session info of the block. If invalid or no such validator, return `ApprovalCheckResult::Bad`. * Send `ApprovalCheckResult::Accepted` * [Import the checked approval vote](#import-checked-approval) for all candidates diff --git a/polkadot/roadmap/implementers-guide/src/node/utility/candidate-validation.md b/polkadot/roadmap/implementers-guide/src/node/utility/candidate-validation.md index 1a3ff1c6aff0..aad77de0aded 100644 --- a/polkadot/roadmap/implementers-guide/src/node/utility/candidate-validation.md +++ b/polkadot/roadmap/implementers-guide/src/node/utility/candidate-validation.md @@ -85,7 +85,7 @@ state. Once we have all parameters, we can spin up a background task to perform the validation in a way that doesn't hold up the entire event loop. Before invoking the validation function itself, this should first do some basic checks: - * The collator signature is valid + * The collator signature is valid (only if `CandidateDescriptor` has version 1) * The PoV provided matches the `pov_hash` field of the descriptor For more details please see [PVF Host and Workers](pvf-host-and-workers.md). diff --git a/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md b/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md index 5031433cf5a1..48909db07ba5 100644 --- a/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md +++ b/polkadot/roadmap/implementers-guide/src/runtime/inclusion.md @@ -109,7 +109,7 @@ All failed checks should lead to an unrecoverable error making the block invalid 1. Ensure that any code upgrade scheduled by the candidate does not happen within `config.validation_upgrade_cooldown` of `Paras::last_code_upgrade(para_id, true)`, if any, comparing against the value of `Paras::FutureCodeUpgrades` for the given para ID. - 1. Check the collator's signature on the candidate data. + 1. Check the collator's signature on the candidate data (only if `CandidateDescriptor` is version 1) 1. check the backing of the candidate using the signatures and the bitfields, comparing against the validators assigned to the groups, fetched with the `group_validators` lookup, while group indices are computed by `Scheduler` according to group rotation info. diff --git a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md index c82d89d2d879..6e24d969dde4 100644 --- a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md +++ b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md @@ -111,21 +111,15 @@ pub enum ApprovalCheckError { } enum ApprovalVotingMessage { - /// Check if the assignment is valid and can be accepted by our view of the protocol. - /// Should not be sent unless the block hash is known. - CheckAndImportAssignment( - IndirectAssignmentCert, - CandidateIndex, // The index of the candidate included in the block. - ResponseChannel, - ), - /// Check if the approval vote is valid and can be accepted by our view of the - /// protocol. - /// - /// Should not be sent unless the block hash within the indirect vote is known. - CheckAndImportApproval( - IndirectSignedApprovalVote, - ResponseChannel, - ), + /// Import an assignment into the approval-voting database. + /// + /// Should not be sent unless the block hash is known and the VRF assignment checks out. + ImportAssignment(CheckedIndirectAssignment, Option>), + /// Import an approval vote into approval-voting database + /// + /// Should not be sent unless the block hash within the indirect vote is known, vote is + /// correctly signed and we had a previous assignment for the candidate. + ImportApproval(CheckedIndirectSignedApprovalVote, Option>), /// Returns the highest possible ancestor hash of the provided block hash which is /// acceptable to vote on finality for. Along with that, return the lists of candidate hashes /// which appear in every block from the (non-inclusive) base number up to (inclusive) the specified @@ -907,22 +901,6 @@ const APPROVAL_EXECUTION_TIMEOUT: Duration = 6 seconds; /// or `Ok(ValidationResult::Invalid)`. #[derive(Debug)] pub enum CandidateValidationMessage { - /// Validate a candidate with provided parameters using relay-chain state. - /// - /// This will implicitly attempt to gather the `PersistedValidationData` and `ValidationCode` - /// from the runtime API of the chain, based on the `relay_parent` - /// of the `CandidateDescriptor`. - /// - /// This will also perform checking of validation outputs against the acceptance criteria. - /// - /// If there is no state available which can provide this data or the core for - /// the para is not free at the relay-parent, an error is returned. - ValidateFromChainState( - CandidateDescriptor, - Arc, - Duration, // Execution timeout. - oneshot::Sender>, - ), /// Validate a candidate with provided, exhaustive parameters for validation. /// /// Explicitly provide the `PersistedValidationData` and `ValidationCode` so this can do full diff --git a/polkadot/rpc/src/lib.rs b/polkadot/rpc/src/lib.rs index 7d678ada5ff5..0007df908e2b 100644 --- a/polkadot/rpc/src/lib.rs +++ b/polkadot/rpc/src/lib.rs @@ -27,7 +27,7 @@ use sc_consensus_beefy::communication::notification::{ BeefyBestBlockStream, BeefyVersionedFinalityProofStream, }; use sc_consensus_grandpa::FinalityProofProvider; -pub use sc_rpc::{DenyUnsafe, SubscriptionTaskExecutor}; +pub use sc_rpc::SubscriptionTaskExecutor; use sc_transaction_pool_api::TransactionPool; use sp_api::ProvideRuntimeApi; use sp_application_crypto::RuntimeAppPublic; @@ -83,8 +83,6 @@ pub struct FullDeps { pub select_chain: SC, /// A copy of the chain spec. pub chain_spec: Box, - /// Whether to deny unsafe calls - pub deny_unsafe: DenyUnsafe, /// BABE specific dependencies. pub babe: BabeDeps, /// GRANDPA specific dependencies. @@ -97,7 +95,13 @@ pub struct FullDeps { /// Instantiate all RPC extensions. pub fn create_full( - FullDeps { client, pool, select_chain, chain_spec, deny_unsafe, babe, grandpa, beefy, backend } : FullDeps, + FullDeps { client, pool, select_chain, chain_spec, babe, grandpa, beefy, backend }: FullDeps< + C, + P, + SC, + B, + AuthorityId, + >, ) -> Result> where C: ProvideRuntimeApi @@ -124,7 +128,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,13 +142,8 @@ 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(StateMigration::new(client.clone(), backend.clone()).into_rpc())?; + io.merge(System::new(client.clone(), pool.clone()).into_rpc())?; io.merge(TransactionPayment::new(client.clone()).into_rpc())?; io.merge( Mmr::new( @@ -157,8 +155,7 @@ where .into_rpc(), )?; io.merge( - Babe::new(client.clone(), babe_worker_handle.clone(), keystore, select_chain, deny_unsafe) - .into_rpc(), + Babe::new(client.clone(), babe_worker_handle.clone(), keystore, select_chain).into_rpc(), )?; io.merge( Grandpa::new( diff --git a/polkadot/runtime/common/Cargo.toml b/polkadot/runtime/common/Cargo.toml index cda6f3240dd2..01b56b31cf20 100644 --- a/polkadot/runtime/common/Cargo.toml +++ b/polkadot/runtime/common/Cargo.toml @@ -27,6 +27,7 @@ sp-runtime = { features = ["serde"], workspace = true } sp-session = { workspace = true } sp-staking = { features = ["serde"], workspace = true } sp-core = { features = ["serde"], workspace = true } +sp-keyring = { workspace = true } sp-npos-elections = { features = ["serde"], workspace = true } pallet-authorship = { workspace = true } @@ -130,6 +131,7 @@ runtime-benchmarks = [ "pallet-identity/runtime-benchmarks", "pallet-staking/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", diff --git a/polkadot/runtime/common/src/assigned_slots/mod.rs b/polkadot/runtime/common/src/assigned_slots/mod.rs index dd39789e10cf..65942c127b1c 100644 --- a/polkadot/runtime/common/src/assigned_slots/mod.rs +++ b/polkadot/runtime/common/src/assigned_slots/mod.rs @@ -186,6 +186,7 @@ pub mod pallet { pub struct GenesisConfig { pub max_temporary_slots: u32, pub max_permanent_slots: u32, + #[serde(skip)] pub _config: PhantomData, } @@ -664,12 +665,21 @@ mod tests { } ); - impl frame_system::offchain::SendTransactionTypes for Test + impl frame_system::offchain::CreateTransactionBase for Test where RuntimeCall: From, { type Extrinsic = UncheckedExtrinsic; - type OverarchingCall = RuntimeCall; + type RuntimeCall = RuntimeCall; + } + + impl frame_system::offchain::CreateInherent for Test + where + RuntimeCall: From, + { + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { + UncheckedExtrinsic::new_bare(call) + } } #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] diff --git a/polkadot/runtime/common/src/claims.rs b/polkadot/runtime/common/src/claims.rs index 162bf01c3843..2b36c19efce7 100644 --- a/polkadot/runtime/common/src/claims.rs +++ b/polkadot/runtime/common/src/claims.rs @@ -1,18 +1,18 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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 Substrate. If not, see . +// along with Polkadot. If not, see . //! Pallet to process claims from Ethereum addresses. @@ -33,7 +33,11 @@ use scale_info::TypeInfo; use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; use sp_io::{crypto::secp256k1_ecdsa_recover, hashing::keccak_256}; use sp_runtime::{ - traits::{CheckedSub, DispatchInfoOf, SignedExtension, Zero}, + impl_tx_ext_default, + traits::{ + AsSystemOriginSigner, AsTransactionAuthorizedOrigin, CheckedSub, DispatchInfoOf, + Dispatchable, TransactionExtension, Zero, + }, transaction_validity::{ InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction, }, @@ -51,6 +55,7 @@ pub trait WeightInfo { fn claim_attest() -> Weight; fn attest() -> Weight; fn move_claim() -> Weight; + fn prevalidate_attests() -> Weight; } pub struct TestWeightInfo; @@ -70,6 +75,9 @@ impl WeightInfo for TestWeightInfo { fn move_claim() -> Weight { Weight::zero() } + fn prevalidate_attests() -> Weight { + Weight::zero() + } } /// The kind of statement an account needs to make for a claim to be valid. @@ -400,7 +408,7 @@ pub mod pallet { /// Attest to a statement, needed to finalize the claims process. /// /// WARNING: Insecure unless your chain includes `PrevalidateAttests` as a - /// `SignedExtension`. + /// `TransactionExtension`. /// /// Unsigned Validation: /// A call to attest is deemed valid if the sender has a `Preclaim` registered @@ -611,58 +619,56 @@ impl PrevalidateAttests where ::RuntimeCall: IsSubType>, { - /// Create new `SignedExtension` to check runtime version. + /// Create new `TransactionExtension` to check runtime version. pub fn new() -> Self { Self(core::marker::PhantomData) } } -impl SignedExtension for PrevalidateAttests +impl TransactionExtension for PrevalidateAttests where ::RuntimeCall: IsSubType>, + <::RuntimeCall as Dispatchable>::RuntimeOrigin: + AsSystemOriginSigner + AsTransactionAuthorizedOrigin + Clone, { - type AccountId = T::AccountId; - type Call = ::RuntimeCall; - type AdditionalSigned = (); - type Pre = (); const IDENTIFIER: &'static str = "PrevalidateAttests"; + type Implicit = (); + type Pre = (); + type Val = (); - fn additional_signed(&self) -> Result { - Ok(()) - } - - fn pre_dispatch( - self, - who: &Self::AccountId, - call: &Self::Call, - info: &DispatchInfoOf, - len: usize, - ) -> Result { - self.validate(who, call, info, len).map(|_| ()) + fn weight(&self, call: &T::RuntimeCall) -> Weight { + if let Some(Call::attest { .. }) = call.is_sub_type() { + T::WeightInfo::prevalidate_attests() + } else { + Weight::zero() + } } - // - // The weight of this logic is included in the `attest` dispatchable. - // fn validate( &self, - who: &Self::AccountId, - call: &Self::Call, - _info: &DispatchInfoOf, + origin: ::RuntimeOrigin, + call: &T::RuntimeCall, + _info: &DispatchInfoOf, _len: usize, - ) -> TransactionValidity { - if let Some(local_call) = call.is_sub_type() { - if let Call::attest { statement: attested_statement } = local_call { - let signer = Preclaims::::get(who) - .ok_or(InvalidTransaction::Custom(ValidityError::SignerHasNoClaim.into()))?; - if let Some(s) = Signing::::get(signer) { - let e = InvalidTransaction::Custom(ValidityError::InvalidStatement.into()); - ensure!(&attested_statement[..] == s.to_text(), e); - } + _self_implicit: Self::Implicit, + _inherited_implication: &impl Encode, + ) -> Result< + (ValidTransaction, Self::Val, ::RuntimeOrigin), + TransactionValidityError, + > { + if let Some(Call::attest { statement: attested_statement }) = call.is_sub_type() { + let who = origin.as_system_origin_signer().ok_or(InvalidTransaction::BadSigner)?; + let signer = Preclaims::::get(who) + .ok_or(InvalidTransaction::Custom(ValidityError::SignerHasNoClaim.into()))?; + if let Some(s) = Signing::::get(signer) { + let e = InvalidTransaction::Custom(ValidityError::InvalidStatement.into()); + ensure!(&attested_statement[..] == s.to_text(), e); } } - Ok(ValidTransaction::default()) + Ok((ValidTransaction::default(), (), origin)) } + + impl_tx_ext_default!(T::RuntimeCall; prepare); } #[cfg(any(test, feature = "runtime-benchmarks"))] @@ -713,8 +719,11 @@ mod tests { }; use pallet_balances; use sp_runtime::{ - traits::Identity, transaction_validity::TransactionLongevity, BuildStorage, - DispatchError::BadOrigin, TokenError, + traits::{DispatchTransaction, Identity}, + transaction_validity::TransactionLongevity, + BuildStorage, + DispatchError::BadOrigin, + TokenError, }; type Block = frame_system::mocking::MockBlock; @@ -1055,8 +1064,8 @@ mod tests { }); let di = c.get_dispatch_info(); assert_eq!(di.pays_fee, Pays::No); - let r = p.validate(&42, &c, &di, 20); - assert_eq!(r, TransactionValidity::Ok(ValidTransaction::default())); + let r = p.validate_only(Some(42).into(), &c, &di, 20); + assert_eq!(r.unwrap().0, ValidTransaction::default()); }); } @@ -1068,13 +1077,13 @@ mod tests { statement: StatementKind::Regular.to_text().to_vec(), }); let di = c.get_dispatch_info(); - let r = p.validate(&42, &c, &di, 20); + let r = p.validate_only(Some(42).into(), &c, &di, 20); assert!(r.is_err()); let c = RuntimeCall::Claims(ClaimsCall::attest { statement: StatementKind::Saft.to_text().to_vec(), }); let di = c.get_dispatch_info(); - let r = p.validate(&69, &c, &di, 20); + let r = p.validate_only(Some(69).into(), &c, &di, 20); assert!(r.is_err()); }); } @@ -1432,10 +1441,16 @@ mod benchmarking { use super::*; use crate::claims::Call; use frame_benchmarking::{account, benchmarks}; - use frame_support::traits::UnfilteredDispatchable; + use frame_support::{ + dispatch::{DispatchInfo, GetDispatchInfo}, + traits::UnfilteredDispatchable, + }; use frame_system::RawOrigin; use secp_utils::*; - use sp_runtime::{traits::ValidateUnsigned, DispatchResult}; + use sp_runtime::{ + traits::{DispatchTransaction, ValidateUnsigned}, + DispatchResult, + }; const SEED: u32 = 0; @@ -1471,6 +1486,12 @@ mod benchmarking { } benchmarks! { + where_clause { where ::RuntimeCall: IsSubType> + From>, + ::RuntimeCall: Dispatchable + GetDispatchInfo, + <::RuntimeCall as Dispatchable>::RuntimeOrigin: AsSystemOriginSigner + AsTransactionAuthorizedOrigin + Clone, + <::RuntimeCall as Dispatchable>::PostInfo: Default, + } + // Benchmark `claim` including `validate_unsigned` logic. claim { let c = MAX_CLAIMS; @@ -1574,24 +1595,9 @@ mod benchmarking { Preclaims::::insert(&account, eth_address); assert_eq!(Claims::::get(eth_address), Some(VALUE.into())); - let call = super::Call::::attest { statement: StatementKind::Regular.to_text().to_vec() }; - // We have to copy the validate statement here because of trait issues... :( - let validate = |who: &T::AccountId, call: &super::Call| -> DispatchResult { - if let Call::attest{ statement: attested_statement } = call { - let signer = Preclaims::::get(who).ok_or("signer has no claim")?; - if let Some(s) = Signing::::get(signer) { - ensure!(&attested_statement[..] == s.to_text(), "invalid statement"); - } - } - Ok(()) - }; - let call_enc = call.encode(); - }: { - let call = as Decode>::decode(&mut &*call_enc) - .expect("call is encoded above, encoding must be correct"); - validate(&account, &call)?; - call.dispatch_bypass_filter(RawOrigin::Signed(account).into())?; - } + let stmt = StatementKind::Regular.to_text().to_vec(); + }: + _(RawOrigin::Signed(account), stmt) verify { assert_eq!(Claims::::get(eth_address), None); } @@ -1649,6 +1655,42 @@ mod benchmarking { } } + prevalidate_attests { + let c = MAX_CLAIMS; + + for i in 0 .. c / 2 { + create_claim::(c)?; + create_claim_attest::(u32::MAX - c)?; + } + + let ext = PrevalidateAttests::::new(); + let call = super::Call::attest { + statement: StatementKind::Regular.to_text().to_vec(), + }; + let call: ::RuntimeCall = call.into(); + let info = call.get_dispatch_info(); + let attest_c = u32::MAX - c; + let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&attest_c.encode())).unwrap(); + let eth_address = eth(&secret_key); + let account: T::AccountId = account("user", c, SEED); + let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into())); + let statement = StatementKind::Regular; + let signature = sig::(&secret_key, &account.encode(), statement.to_text()); + super::Pallet::::mint_claim(RawOrigin::Root.into(), eth_address, VALUE.into(), vesting, Some(statement))?; + Preclaims::::insert(&account, eth_address); + assert_eq!(Claims::::get(eth_address), Some(VALUE.into())); + }: { + assert!(ext.test_run( + RawOrigin::Signed(account).into(), + &call, + &info, + 0, + |_| { + Ok(Default::default()) + } + ).unwrap().is_ok()); + } + impl_benchmark_test_suite!( Pallet, crate::claims::tests::new_test_ext(), diff --git a/polkadot/runtime/common/src/impls.rs b/polkadot/runtime/common/src/impls.rs index 9d61cd018731..b6a93cf53685 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/common/src/integration_tests.rs b/polkadot/runtime/common/src/integration_tests.rs index 7a689a517eaa..bfeed04a919f 100644 --- a/polkadot/runtime/common/src/integration_tests.rs +++ b/polkadot/runtime/common/src/integration_tests.rs @@ -98,12 +98,21 @@ frame_support::construct_runtime!( } ); -impl frame_system::offchain::SendTransactionTypes for Test +impl frame_system::offchain::CreateTransactionBase for Test where RuntimeCall: From, { type Extrinsic = UncheckedExtrinsic; - type OverarchingCall = RuntimeCall; + type RuntimeCall = RuntimeCall; +} + +impl frame_system::offchain::CreateInherent for Test +where + RuntimeCall: From, +{ + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { + UncheckedExtrinsic::new_bare(call) + } } use crate::{auctions::Error as AuctionsError, crowdloan::Error as CrowdloanError}; diff --git a/polkadot/runtime/common/src/paras_registrar/mod.rs b/polkadot/runtime/common/src/paras_registrar/mod.rs index 07f02e926561..2ead621dedf0 100644 --- a/polkadot/runtime/common/src/paras_registrar/mod.rs +++ b/polkadot/runtime/common/src/paras_registrar/mod.rs @@ -752,12 +752,21 @@ mod tests { } ); - impl frame_system::offchain::SendTransactionTypes for Test + impl frame_system::offchain::CreateTransactionBase for Test where RuntimeCall: From, { type Extrinsic = UncheckedExtrinsic; - type OverarchingCall = RuntimeCall; + type RuntimeCall = RuntimeCall; + } + + impl frame_system::offchain::CreateInherent for Test + where + RuntimeCall: From, + { + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { + UncheckedExtrinsic::new_bare(call) + } } const NORMAL_RATIO: Perbill = Perbill::from_percent(75); diff --git a/polkadot/runtime/common/src/purchase.rs b/polkadot/runtime/common/src/purchase.rs index d650548b8ac3..cec92540654c 100644 --- a/polkadot/runtime/common/src/purchase.rs +++ b/polkadot/runtime/common/src/purchase.rs @@ -1,18 +1,18 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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 Substrate. If not, see . +// along with Polkadot. If not, see . //! Pallet to process purchase of DOTs. @@ -479,7 +479,8 @@ where mod tests { use super::*; - use sp_core::{crypto::AccountId32, ed25519, Pair, Public, H256}; + use sp_core::{crypto::AccountId32, H256}; + use sp_keyring::{Ed25519Keyring, Sr25519Keyring}; // The testing primitives are very useful for avoiding having to work with signatures // or public keys. `u64` is used as the `AccountId` and no `Signature`s are required. use crate::purchase; @@ -488,10 +489,9 @@ mod tests { traits::{Currency, WithdrawReasons}, }; use sp_runtime::{ - traits::{BlakeTwo256, Dispatchable, IdentifyAccount, Identity, IdentityLookup, Verify}, + traits::{BlakeTwo256, Dispatchable, Identity, IdentityLookup}, ArithmeticError, BuildStorage, DispatchError::BadOrigin, - MultiSignature, }; type Block = frame_system::mocking::MockBlock; @@ -602,33 +602,16 @@ mod tests { Balances::make_free_balance_be(&payment_account(), 100_000); } - type AccountPublic = ::Signer; - - /// Helper function to generate a crypto pair from seed - fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() - } - - /// Helper function to generate an account ID from seed - fn get_account_id_from_seed(seed: &str) -> AccountId - where - AccountPublic: From<::Public>, - { - AccountPublic::from(get_from_seed::(seed)).into_account() - } - fn alice() -> AccountId { - get_account_id_from_seed::("Alice") + Sr25519Keyring::Alice.to_account_id() } fn alice_ed25519() -> AccountId { - get_account_id_from_seed::("Alice") + Ed25519Keyring::Alice.to_account_id() } fn bob() -> AccountId { - get_account_id_from_seed::("Bob") + Sr25519Keyring::Bob.to_account_id() } fn alice_signature() -> [u8; 64] { diff --git a/polkadot/runtime/common/src/xcm_sender.rs b/polkadot/runtime/common/src/xcm_sender.rs index dace785a535b..37fe7f0b59e9 100644 --- a/polkadot/runtime/common/src/xcm_sender.rs +++ b/polkadot/runtime/common/src/xcm_sender.rs @@ -141,6 +141,11 @@ where } impl InspectMessageQueues for ChildParachainRouter { + fn clear_messages() { + // Best effort. + let _ = dmp::DownwardMessageQueues::::clear(u32::MAX, None); + } + fn get_messages() -> Vec<(VersionedLocation, Vec>)> { dmp::DownwardMessageQueues::::iter() .map(|(para_id, messages)| { diff --git a/polkadot/runtime/parachains/Cargo.toml b/polkadot/runtime/parachains/Cargo.toml index 7afdf49fe551..a3eec3f9d961 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 } @@ -57,6 +59,8 @@ polkadot-runtime-metrics = { workspace = true } polkadot-core-primitives = { workspace = true } [dev-dependencies] +polkadot-primitives = { workspace = true, features = ["test"] } + futures = { workspace = true } hex-literal = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } @@ -86,6 +90,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 +114,7 @@ std = [ "sp-runtime/std", "sp-session/std", "sp-staking/std", + "sp-std?/std", "xcm-executor/std", "xcm/std", ] @@ -120,6 +126,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 +135,7 @@ runtime-benchmarks = [ "sp-application-crypto", "sp-runtime/runtime-benchmarks", "sp-staking/runtime-benchmarks", + "sp-std", "static_assertions", "xcm-executor/runtime-benchmarks", ] @@ -141,6 +149,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 9ed007919b81..33a36a1bb2ea 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 @@ -322,9 +318,12 @@ impl AssignmentProvider> for Pallet { Assignment::Bulk(para_id) } - fn session_core_count() -> u32 { - let config = configuration::ActiveConfig::::get(); - config.scheduler_params.num_cores + fn assignment_duplicated(assignment: &Assignment) { + match assignment { + Assignment::Pool { para_id, core_index } => + on_demand::Pallet::::assignment_duplicated(*para_id, *core_index), + Assignment::Bulk(_) => {}, + } } } diff --git a/polkadot/runtime/parachains/src/assigner_coretime/tests.rs b/polkadot/runtime/parachains/src/assigner_coretime/tests.rs index 9b0cbcb2d7d6..25007f0eed6a 100644 --- a/polkadot/runtime/parachains/src/assigner_coretime/tests.rs +++ b/polkadot/runtime/parachains/src/assigner_coretime/tests.rs @@ -20,13 +20,12 @@ use crate::{ assigner_coretime::{mock_helpers::GenesisConfigBuilder, pallet::Error, Schedule}, initializer::SessionChangeNotification, mock::{ - new_test_ext, Balances, CoretimeAssigner, OnDemandAssigner, Paras, ParasShared, - RuntimeOrigin, Scheduler, System, Test, + new_test_ext, Balances, CoretimeAssigner, OnDemand, Paras, ParasShared, RuntimeOrigin, + Scheduler, System, Test, }, paras::{ParaGenesisArgs, ParaKind}, scheduler::common::Assignment, }; -use alloc::collections::btree_map::BTreeMap; use frame_support::{assert_noop, assert_ok, pallet_prelude::*, traits::Currency}; use pallet_broker::TaskId; use polkadot_primitives::{BlockNumber, Id as ParaId, SessionIndex, ValidationCode}; @@ -75,10 +74,10 @@ 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); + Scheduler::advance_claim_queue(&Default::default()); } } @@ -527,11 +526,7 @@ fn pop_assignment_for_core_works() { schedule_blank_para(para_id, ParaKind::Parathread); Balances::make_free_balance_be(&alice, amt); run_to_block(1, |n| if n == 1 { Some(Default::default()) } else { None }); - assert_ok!(OnDemandAssigner::place_order_allow_death( - RuntimeOrigin::signed(alice), - amt, - para_id - )); + assert_ok!(OnDemand::place_order_allow_death(RuntimeOrigin::signed(alice), amt, para_id)); // Case 1: Assignment idle assert_ok!(CoretimeAssigner::assign_core( diff --git a/polkadot/runtime/parachains/src/assigner_parachains.rs b/polkadot/runtime/parachains/src/assigner_parachains.rs index 3c735b999cf2..53edae5c32fc 100644 --- a/polkadot/runtime/parachains/src/assigner_parachains.rs +++ b/polkadot/runtime/parachains/src/assigner_parachains.rs @@ -63,7 +63,5 @@ impl AssignmentProvider> for Pallet { Assignment::Bulk(para_id) } - fn session_core_count() -> u32 { - paras::Parachains::::decode_len().unwrap_or(0) as u32 - } + fn assignment_duplicated(_: &Assignment) {} } diff --git a/polkadot/runtime/parachains/src/assigner_parachains/tests.rs b/polkadot/runtime/parachains/src/assigner_parachains/tests.rs index 817e43a7138d..6e8e185bb48d 100644 --- a/polkadot/runtime/parachains/src/assigner_parachains/tests.rs +++ b/polkadot/runtime/parachains/src/assigner_parachains/tests.rs @@ -23,7 +23,6 @@ use crate::{ }, paras::{ParaGenesisArgs, ParaKind}, }; -use alloc::collections::btree_map::BTreeMap; use frame_support::{assert_ok, pallet_prelude::*}; use polkadot_primitives::{BlockNumber, Id as ParaId, SessionIndex, ValidationCode}; @@ -71,7 +70,7 @@ fn run_to_block( Scheduler::initializer_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); + Scheduler::advance_claim_queue(&Default::default()); } } diff --git a/polkadot/runtime/parachains/src/builder.rs b/polkadot/runtime/parachains/src/builder.rs index ec07cca2107e..fa9497f8ccd5 100644 --- a/polkadot/runtime/parachains/src/builder.rs +++ b/polkadot/runtime/parachains/src/builder.rs @@ -18,7 +18,10 @@ use crate::{ configuration, inclusion, initializer, paras, paras::ParaKind, paras_inherent, - scheduler::{self, common::AssignmentProvider, CoreOccupied, ParasEntry}, + scheduler::{ + self, + common::{Assignment, AssignmentProvider}, + }, session_info, shared, }; use alloc::{ @@ -30,25 +33,40 @@ 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, + vstaging::{ + BackedCandidate, CandidateDescriptorV2, ClaimQueueOffset, + CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CoreSelector, + InherentData as ParachainsInherentData, UMPSignal, UMP_SEPARATOR, + }, + AvailabilityBitfield, CandidateCommitments, CandidateDescriptor, CandidateHash, CollatorId, + CollatorSignature, CompactStatement, CoreIndex, DisputeStatement, DisputeStatementSet, + GroupIndex, HeadData, Id as ParaId, IndexedVec, InvalidDisputeStatementKind, + PersistedValidationData, SessionIndex, SigningContext, UncheckedSigned, + ValidDisputeStatementKind, ValidationCode, ValidatorId, ValidatorIndex, ValidityAttestation, }; -use sp_core::{sr25519, H256}; +use sp_core::{ByteArray, H256}; use sp_runtime::{ generic::Digest, traits::{Header as HeaderT, One, TrailingZeroInput, Zero}, RuntimeAppPublic, }; - fn mock_validation_code() -> ValidationCode { ValidationCode(vec![1, 2, 3]) } +/// Create a dummy collator id suitable to be used in a V1 candidate descriptor. +pub fn junk_collator() -> CollatorId { + CollatorId::from_slice(&mut (0..32).into_iter().collect::>().as_slice()) + .expect("32 bytes; qed") +} + +/// Creates a dummy collator signature suitable to be used in a V1 candidate descriptor. +pub fn junk_collator_signature() -> CollatorSignature { + CollatorSignature::from_slice(&mut (0..64).into_iter().collect::>().as_slice()) + .expect("64 bytes; qed") +} + /// Grab an account, seeded by a name and index. /// /// This is directly from frame-benchmarking. Copy/pasted so we can use it when not compiling with @@ -59,6 +77,21 @@ fn account(name: &'static str, index: u32, seed: u32) -> Acco .expect("infinite input; no invalid input; qed") } +pub fn generate_validator_pairs( + validator_count: u32, +) -> Vec<(T::AccountId, ValidatorId)> { + (0..validator_count) + .map(|i| { + let public = ValidatorId::generate_pair(None); + + // The account Id is not actually used anywhere, just necessary to fulfill the + // expected type of the `validators` param of `test_trigger_on_new_session`. + let account: T::AccountId = account("validator", i, i); + (account, public) + }) + .collect() +} + /// Create a 32 byte slice based on the given number. fn byte32_slice_from(n: u32) -> [u8; 32] { let mut slice = [0u8; 32]; @@ -108,13 +141,18 @@ pub(crate) struct BenchBuilder { /// Make every candidate include a code upgrade by setting this to `Some` where the interior /// value is the byte length of the new code. code_upgrade: Option, - /// Specifies whether the claimqueue should be filled. - fill_claimqueue: bool, /// Cores which should not be available when being populated with pending candidates. unavailable_cores: Vec, + /// Use v2 candidate descriptor. + candidate_descriptor_v2: bool, + /// Apply custom changes to generated candidates + candidate_modifier: Option>, _phantom: core::marker::PhantomData, } +pub type CandidateModifier = + fn(CommittedCandidateReceipt) -> CommittedCandidateReceipt; + /// Paras inherent `enter` benchmark scenario. #[cfg(any(feature = "runtime-benchmarks", test))] pub(crate) struct Bench { @@ -141,8 +179,9 @@ impl BenchBuilder { backed_in_inherent_paras: Default::default(), elastic_paras: Default::default(), code_upgrade: None, - fill_claimqueue: true, unavailable_cores: vec![], + candidate_descriptor_v2: false, + candidate_modifier: None, _phantom: core::marker::PhantomData::, } } @@ -212,9 +251,10 @@ impl BenchBuilder { .expect("self.block_number is u32") } - /// Maximum number of validators that may be part of a validator group. + /// Fallback for the maximum number of validators participating in parachains consensus (a.k.a. + /// active validators). pub(crate) fn fallback_max_validators() -> u32 { - configuration::ActiveConfig::::get().max_validators.unwrap_or(200) + configuration::ActiveConfig::::get().max_validators.unwrap_or(1024) } /// Maximum number of validators participating in parachains consensus (a.k.a. active @@ -250,6 +290,21 @@ impl BenchBuilder { self } + /// Toggle usage of v2 candidate descriptors. + pub(crate) fn set_candidate_descriptor_v2(mut self, enable: bool) -> Self { + self.candidate_descriptor_v2 = enable; + self + } + + /// Set the candidate modifier. + pub(crate) fn set_candidate_modifier( + mut self, + modifier: Option>, + ) -> Self { + self.candidate_modifier = modifier; + self + } + /// Get the maximum number of validators per core. fn max_validators_per_core(&self) -> u32 { self.max_validators_per_core.unwrap_or(Self::fallback_max_validators_per_core()) @@ -267,17 +322,10 @@ impl BenchBuilder { self.max_validators() / self.max_validators_per_core() } - /// Set whether the claim queue should be filled. - #[cfg(not(feature = "runtime-benchmarks"))] - pub(crate) fn set_fill_claimqueue(mut self, f: bool) -> Self { - self.fill_claimqueue = f; - self - } - /// Get the minimum number of validity votes in order for a backed candidate to be included. #[cfg(feature = "runtime-benchmarks")] - pub(crate) fn fallback_min_validity_votes() -> u32 { - (Self::fallback_max_validators() / 2) + 1 + pub(crate) fn fallback_min_backing_votes() -> u32 { + 2 } fn mock_head_data() -> HeadData { @@ -285,38 +333,62 @@ impl BenchBuilder { HeadData(vec![0xFF; max_head_size as usize]) } - fn candidate_descriptor_mock() -> CandidateDescriptor { - CandidateDescriptor:: { - para_id: 0.into(), - relay_parent: Default::default(), - collator: CollatorId::from(sr25519::Public::from_raw([42u8; 32])), - persisted_validation_data_hash: Default::default(), - pov_hash: Default::default(), - erasure_root: Default::default(), - signature: CollatorSignature::from(sr25519::Signature::from_raw([42u8; 64])), - para_head: Default::default(), - validation_code_hash: mock_validation_code().hash(), + fn candidate_descriptor_mock( + para_id: ParaId, + candidate_descriptor_v2: bool, + ) -> CandidateDescriptorV2 { + if candidate_descriptor_v2 { + CandidateDescriptorV2::new( + para_id, + Default::default(), + CoreIndex(200), + 2, + Default::default(), + Default::default(), + Default::default(), + Default::default(), + mock_validation_code().hash(), + ) + } else { + // Convert v1 to v2. + CandidateDescriptor:: { + para_id, + relay_parent: Default::default(), + collator: junk_collator(), + persisted_validation_data_hash: Default::default(), + pov_hash: Default::default(), + erasure_root: Default::default(), + signature: junk_collator_signature(), + para_head: Default::default(), + validation_code_hash: mock_validation_code().hash(), + } + .into() } + .into() } /// Create a mock of `CandidatePendingAvailability`. fn candidate_availability_mock( + para_id: ParaId, group_idx: GroupIndex, core_idx: CoreIndex, candidate_hash: CandidateHash, availability_votes: BitVec, commitments: CandidateCommitments, + candidate_descriptor_v2: bool, ) -> inclusion::CandidatePendingAvailability> { inclusion::CandidatePendingAvailability::>::new( - core_idx, // core - candidate_hash, // hash - Self::candidate_descriptor_mock(), // candidate descriptor - commitments, // commitments - availability_votes, // availability votes - Default::default(), // backers - Zero::zero(), // relay parent - One::one(), // relay chain block this was backed in - group_idx, // backing group + core_idx, // core + candidate_hash, // hash + Self::candidate_descriptor_mock(para_id, candidate_descriptor_v2), /* candidate descriptor */ + commitments, // commitments + availability_votes, /* availability + * votes */ + Default::default(), // backers + Zero::zero(), // relay parent + One::one(), /* relay chain block this + * was backed in */ + group_idx, // backing group ) } @@ -331,6 +403,7 @@ impl BenchBuilder { group_idx: GroupIndex, availability_votes: BitVec, candidate_hash: CandidateHash, + candidate_descriptor_v2: bool, ) { let commitments = CandidateCommitments:: { upward_messages: Default::default(), @@ -341,17 +414,19 @@ impl BenchBuilder { hrmp_watermark: 0u32.into(), }; let candidate_availability = Self::candidate_availability_mock( + para_id, group_idx, core_idx, candidate_hash, availability_votes, commitments, + candidate_descriptor_v2, ); - inclusion::PendingAvailability::::mutate(para_id, |maybe_andidates| { - if let Some(candidates) = maybe_andidates { + inclusion::PendingAvailability::::mutate(para_id, |maybe_candidates| { + if let Some(candidates) = maybe_candidates { candidates.push_back(candidate_availability); } else { - *maybe_andidates = + *maybe_candidates = Some([candidate_availability].into_iter().collect::>()); } }); @@ -413,20 +488,6 @@ impl BenchBuilder { } } - /// Generate validator key pairs and account ids. - fn generate_validator_pairs(validator_count: u32) -> Vec<(T::AccountId, ValidatorId)> { - (0..validator_count) - .map(|i| { - let public = ValidatorId::generate_pair(None); - - // The account Id is not actually used anywhere, just necessary to fulfill the - // expected type of the `validators` param of `test_trigger_on_new_session`. - let account: T::AccountId = account("validator", i, i); - (account, public) - }) - .collect() - } - fn signing_context(&self) -> SigningContext { SigningContext { parent_hash: Self::header(self.block_number).hash(), @@ -519,6 +580,7 @@ impl BenchBuilder { // No validators have made this candidate available yet. bitvec::bitvec![u8, bitvec::order::Lsb0; 0; validators.len()], CandidateHash(H256::from(byte32_slice_from(current_core_idx))), + self.candidate_descriptor_v2, ); if !self.unavailable_cores.contains(¤t_core_idx) { concluding_cores.insert(current_core_idx); @@ -584,7 +646,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 +675,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(); @@ -630,18 +683,35 @@ impl BenchBuilder { let group_validators = scheduler::Pallet::::group_validators(group_idx).unwrap(); - let candidate = CommittedCandidateReceipt:: { - descriptor: CandidateDescriptor:: { + let descriptor = if self.candidate_descriptor_v2 { + CandidateDescriptorV2::new( para_id, relay_parent, - collator: collator_public, + core_idx, + self.target_session, + persisted_validation_data_hash, + pov_hash, + Default::default(), + head_data.hash(), + validation_code_hash, + ) + } else { + CandidateDescriptor:: { + para_id, + relay_parent, + collator: junk_collator(), persisted_validation_data_hash, pov_hash, erasure_root: Default::default(), - signature, + signature: junk_collator_signature(), para_head: head_data.hash(), validation_code_hash, - }, + } + .into() + }; + + let mut candidate = CommittedCandidateReceipt:: { + descriptor, commitments: CandidateCommitments:: { upward_messages: Default::default(), horizontal_messages: Default::default(), @@ -653,6 +723,27 @@ impl BenchBuilder { }, }; + if self.candidate_descriptor_v2 { + // `UMPSignal` separator. + candidate.commitments.upward_messages.force_push(UMP_SEPARATOR); + + // `SelectCore` commitment. + // Claim queue offset must be `0` so this candidate is for the very + // next block. + candidate.commitments.upward_messages.force_push( + UMPSignal::SelectCore( + CoreSelector(chain_idx as u8), + ClaimQueueOffset(0), + ) + .encode(), + ); + } + + // Maybe apply the candidate modifier + if let Some(modifier) = self.candidate_modifier { + candidate = modifier(candidate); + } + let candidate_hash = candidate.hash(); let validity_votes: Vec<_> = group_validators @@ -672,12 +763,15 @@ impl BenchBuilder { }) .collect(); - // Check if the elastic scaling bit is set, if so we need to supply the core - // index in the generated candidate. - let core_idx = configuration::ActiveConfig::::get() - .node_features - .get(FeatureIndex::ElasticScalingMVP as usize) - .map(|_the_bit| core_idx); + // Don't inject core when it is available in descriptor. + let core_idx = if candidate.descriptor.core_index().is_some() { + None + } else { + configuration::ActiveConfig::::get() + .node_features + .get(FeatureIndex::ElasticScalingMVP as usize) + .and_then(|the_bit| if *the_bit { Some(core_idx) } else { None }) + }; BackedCandidate::::new( candidate, @@ -730,6 +824,7 @@ impl BenchBuilder { group_idx, Self::validator_availability_votes_yes(validators.len()), candidate_hash, + self.candidate_descriptor_v2, ); let statements_len = @@ -790,23 +885,20 @@ impl BenchBuilder { extra_cores; assert!(used_cores <= max_cores); - let fill_claimqueue = self.fill_claimqueue; // NOTE: there is an n+2 session delay for these actions to take effect. // We are currently in Session 0, so these changes will take effect in Session 2. Self::setup_para_ids(used_cores - extra_cores); - configuration::ActiveConfig::::mutate(|c| { - c.scheduler_params.num_cores = used_cores as u32; - }); + configuration::Pallet::::set_coretime_cores_unchecked(used_cores as u32).unwrap(); - let validator_ids = Self::generate_validator_pairs(self.max_validators()); + let validator_ids = generate_validator_pairs::(self.max_validators()); let target_session = SessionIndex::from(self.target_session); let builder = self.setup_session(target_session, validator_ids, used_cores, extra_cores); let bitfields = builder.create_availability_bitfields( &builder.backed_and_concluding_paras, &builder.elastic_paras, - used_cores, + scheduler::Pallet::::num_availability_cores(), ); let mut backed_in_inherent = BTreeMap::new(); @@ -834,66 +926,57 @@ impl BenchBuilder { assert_eq!(inclusion::PendingAvailability::::iter().count(), used_cores - extra_cores); - // Mark all the used cores as occupied. We expect that there are - // `backed_and_concluding_paras` that are pending availability and that there are - // `used_cores - backed_and_concluding_paras ` which are about to be disputed. - let now = frame_system::Pallet::::block_number() + One::one(); - + // Sanity check that the occupied cores reported by the inclusion module are what we expect + // to be. let mut core_idx = 0u32; let elastic_paras = &builder.elastic_paras; - // Assign potentially multiple cores to same parachains, - let cores = all_cores + + let mut occupied_cores = inclusion::Pallet::::get_occupied_cores() + .map(|(core, candidate)| (core, candidate.candidate_descriptor().para_id())) + .collect::>(); + occupied_cores.sort_by(|(core_a, _), (core_b, _)| core_a.0.cmp(&core_b.0)); + + let mut expected_cores = all_cores .iter() .flat_map(|(para_id, _)| { (0..elastic_paras.get(¶_id).cloned().unwrap_or(1)) .map(|_para_local_core_idx| { - let ttl = configuration::ActiveConfig::::get().scheduler_params.ttl; - // Load an assignment into provider so that one is present to pop - let assignment = - ::AssignmentProvider::get_mock_assignment( - CoreIndex(core_idx), - ParaId::from(*para_id), - ); + let old_core_idx = core_idx; core_idx += 1; - CoreOccupied::Paras(ParasEntry::new(assignment, now + ttl)) + (CoreIndex(old_core_idx), ParaId::from(*para_id)) }) - .collect::>>() + .collect::>() }) - .collect::>>(); + .collect::>(); - scheduler::AvailabilityCores::::set(cores); + expected_cores.sort_by(|(core_a, _), (core_b, _)| core_a.0.cmp(&core_b.0)); - core_idx = 0u32; + assert_eq!(expected_cores, occupied_cores); // We need entries in the claim queue for those: all_cores.append(&mut builder.backed_in_inherent_paras.clone()); - if fill_claimqueue { - let cores = all_cores - .keys() - .flat_map(|para_id| { - (0..elastic_paras.get(¶_id).cloned().unwrap_or(1)) - .map(|_para_local_core_idx| { - let ttl = configuration::ActiveConfig::::get().scheduler_params.ttl; - // Load an assignment into provider so that one is present to pop - let assignment = - ::AssignmentProvider::get_mock_assignment( - CoreIndex(core_idx), - ParaId::from(*para_id), - ); - - core_idx += 1; - ( - CoreIndex(core_idx - 1), - [ParasEntry::new(assignment, now + ttl)].into(), - ) - }) - .collect::>)>>() - }) - .collect::>>>(); + let mut core_idx = 0u32; + let cores = all_cores + .keys() + .flat_map(|para_id| { + (0..elastic_paras.get(¶_id).cloned().unwrap_or(1)) + .map(|_para_local_core_idx| { + // Load an assignment into provider so that one is present to pop + let assignment = + ::AssignmentProvider::get_mock_assignment( + CoreIndex(core_idx), + ParaId::from(*para_id), + ); - scheduler::ClaimQueue::::set(cores); - } + core_idx += 1; + (CoreIndex(core_idx - 1), [assignment].into()) + }) + .collect::)>>() + }) + .collect::>>(); + + scheduler::ClaimQueue::::set(cores); Bench:: { data: ParachainsInherentData { diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs index d09962ef2b44..e5cf7c4d276e 100644 --- a/polkadot/runtime/parachains/src/configuration.rs +++ b/polkadot/runtime/parachains/src/configuration.rs @@ -29,7 +29,7 @@ use polkadot_parachain_primitives::primitives::{ use polkadot_primitives::{ ApprovalVotingParams, AsyncBackingParams, Balance, ExecutorParamError, ExecutorParams, NodeFeatures, SessionIndex, LEGACY_MIN_BACKING_VOTES, MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, - MAX_POV_SIZE, ON_DEMAND_MAX_QUEUE_MAX_SIZE, + ON_DEMAND_MAX_QUEUE_MAX_SIZE, }; use sp_runtime::{traits::Zero, Perbill, Percent}; @@ -42,10 +42,14 @@ mod benchmarking; pub mod migration; pub use pallet::*; -use polkadot_primitives::vstaging::SchedulerParams; +use polkadot_primitives::SchedulerParams; const LOG_TARGET: &str = "runtime::configuration"; +// This value is derived from network layer limits. See `sc_network::MAX_RESPONSE_SIZE` and +// `polkadot_node_network_protocol::POV_RESPONSE_SIZE`. +const POV_SIZE_HARD_LIMIT: u32 = 16 * 1024 * 1024; + /// All configuration of the runtime with respect to paras. #[derive( Clone, @@ -310,7 +314,7 @@ pub enum InconsistentError { MaxCodeSizeExceedHardLimit { max_code_size: u32 }, /// `max_head_data_size` exceeds the hard limit of `MAX_HEAD_DATA_SIZE`. MaxHeadDataSizeExceedHardLimit { max_head_data_size: u32 }, - /// `max_pov_size` exceeds the hard limit of `MAX_POV_SIZE`. + /// `max_pov_size` exceeds the hard limit of `POV_SIZE_HARD_LIMIT`. MaxPovSizeExceedHardLimit { max_pov_size: u32 }, /// `minimum_validation_upgrade_delay` is less than `paras_availability_period`. MinimumValidationUpgradeDelayLessThanChainAvailabilityPeriod { @@ -333,8 +337,6 @@ pub enum InconsistentError { ZeroMinimumBackingVotes, /// `executor_params` are inconsistent. InconsistentExecutorParams { inner: ExecutorParamError }, - /// TTL should be bigger than lookahead - LookaheadExceedsTTL, /// Lookahead is zero, while it must be at least 1 for parachains to work. LookaheadZero, /// Passed in queue size for on-demand was too large. @@ -377,7 +379,7 @@ where }) } - if self.max_pov_size > MAX_POV_SIZE { + if self.max_pov_size > POV_SIZE_HARD_LIMIT { return Err(MaxPovSizeExceedHardLimit { max_pov_size: self.max_pov_size }) } @@ -430,10 +432,6 @@ where return Err(InconsistentExecutorParams { inner }) } - if self.scheduler_params.ttl < self.scheduler_params.lookahead.into() { - return Err(LookaheadExceedsTTL) - } - if self.scheduler_params.lookahead == 0 { return Err(LookaheadZero) } @@ -557,7 +555,7 @@ pub mod pallet { /// The list is sorted ascending by session index. Also, this list can only contain at most /// 2 items: for the next session and for the `scheduled_session`. #[pallet::storage] - pub(crate) type PendingConfigs = + pub type PendingConfigs = StorageValue<_, Vec<(SessionIndex, HostConfiguration>)>, ValueQuery>; /// If this is set, then the configuration setters will bypass the consistency checks. This @@ -682,18 +680,7 @@ pub mod pallet { Self::set_coretime_cores_unchecked(new) } - /// Set the max number of times a claim may timeout on a core before it is abandoned - #[pallet::call_index(7)] - #[pallet::weight(( - T::WeightInfo::set_config_with_u32(), - DispatchClass::Operational, - ))] - pub fn set_max_availability_timeouts(origin: OriginFor, new: u32) -> DispatchResult { - ensure_root(origin)?; - Self::schedule_config_update(|config| { - config.scheduler_params.max_availability_timeouts = new; - }) - } + // Call index 7 used to be `set_max_availability_timeouts`, which was removed. /// Set the parachain validator-group rotation frequency #[pallet::call_index(8)] @@ -1189,18 +1176,8 @@ pub mod pallet { config.scheduler_params.on_demand_target_queue_utilization = new; }) } - /// Set the on demand (parathreads) ttl in the claimqueue. - #[pallet::call_index(51)] - #[pallet::weight(( - T::WeightInfo::set_config_with_block_number(), - DispatchClass::Operational - ))] - pub fn set_on_demand_ttl(origin: OriginFor, new: BlockNumberFor) -> DispatchResult { - ensure_root(origin)?; - Self::schedule_config_update(|config| { - config.scheduler_params.ttl = new; - }) - } + + // Call index 51 used to be `set_on_demand_ttl`, which was removed. /// Set the minimum backing votes threshold. #[pallet::call_index(52)] diff --git a/polkadot/runtime/parachains/src/configuration/migration/v12.rs b/polkadot/runtime/parachains/src/configuration/migration/v12.rs index 6b77655687f0..d1e0cf10a0ff 100644 --- a/polkadot/runtime/parachains/src/configuration/migration/v12.rs +++ b/polkadot/runtime/parachains/src/configuration/migration/v12.rs @@ -24,7 +24,7 @@ use frame_support::{ traits::{Defensive, UncheckedOnRuntimeUpgrade}, }; use frame_system::pallet_prelude::BlockNumberFor; -use polkadot_primitives::vstaging::SchedulerParams; +use polkadot_primitives::SchedulerParams; use sp_core::Get; use sp_staking::SessionIndex; @@ -143,6 +143,7 @@ fn migrate_to_v12() -> Weight { minimum_backing_votes : pre.minimum_backing_votes, node_features : pre.node_features, approval_voting_params : pre.approval_voting_params, + #[allow(deprecated)] scheduler_params: SchedulerParams { group_rotation_frequency : pre.group_rotation_frequency, paras_availability_period : pre.paras_availability_period, @@ -231,7 +232,10 @@ mod tests { assert_eq!(v12.scheduler_params.paras_availability_period, 4); assert_eq!(v12.scheduler_params.lookahead, 1); assert_eq!(v12.scheduler_params.num_cores, 1); - assert_eq!(v12.scheduler_params.max_availability_timeouts, 0); + #[allow(deprecated)] + { + assert_eq!(v12.scheduler_params.max_availability_timeouts, 0); + } assert_eq!(v12.scheduler_params.on_demand_queue_max_size, 10_000); assert_eq!( v12.scheduler_params.on_demand_target_queue_utilization, @@ -239,7 +243,10 @@ mod tests { ); assert_eq!(v12.scheduler_params.on_demand_fee_variability, Perbill::from_percent(3)); assert_eq!(v12.scheduler_params.on_demand_base_fee, 10_000_000); - assert_eq!(v12.scheduler_params.ttl, 5); + #[allow(deprecated)] + { + assert_eq!(v12.scheduler_params.ttl, 5); + } } #[test] @@ -282,6 +289,7 @@ mod tests { for (_, v12) in configs_to_check { #[rustfmt::skip] + #[allow(deprecated)] { assert_eq!(v11.max_code_size , v12.max_code_size); assert_eq!(v11.max_head_data_size , v12.max_head_data_size); diff --git a/polkadot/runtime/parachains/src/configuration/tests.rs b/polkadot/runtime/parachains/src/configuration/tests.rs index dad8b6458e10..a8689a04fe04 100644 --- a/polkadot/runtime/parachains/src/configuration/tests.rs +++ b/polkadot/runtime/parachains/src/configuration/tests.rs @@ -210,7 +210,7 @@ fn invariants() { ); assert_err!( - Configuration::set_max_pov_size(RuntimeOrigin::root(), MAX_POV_SIZE + 1), + Configuration::set_max_pov_size(RuntimeOrigin::root(), POV_SIZE_HARD_LIMIT + 1), Error::::InvalidNewValue ); @@ -316,13 +316,14 @@ fn setting_pending_config_members() { approval_voting_params: ApprovalVotingParams { max_approval_coalesce_count: 1 }, minimum_backing_votes: 5, node_features: bitvec![u8, Lsb0; 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1], + #[allow(deprecated)] scheduler_params: SchedulerParams { group_rotation_frequency: 20, paras_availability_period: 10, max_validators_per_core: None, lookahead: 3, num_cores: 2, - max_availability_timeouts: 5, + max_availability_timeouts: 0, on_demand_queue_max_size: 10_000u32, on_demand_base_fee: 10_000_000u128, on_demand_fee_variability: Perbill::from_percent(3), @@ -355,11 +356,6 @@ fn setting_pending_config_members() { new_config.scheduler_params.num_cores, ) .unwrap(); - Configuration::set_max_availability_timeouts( - RuntimeOrigin::root(), - new_config.scheduler_params.max_availability_timeouts, - ) - .unwrap(); Configuration::set_group_rotation_frequency( RuntimeOrigin::root(), new_config.scheduler_params.group_rotation_frequency, diff --git a/polkadot/runtime/parachains/src/coretime/benchmarking.rs b/polkadot/runtime/parachains/src/coretime/benchmarking.rs index 028250e188ee..6d593f1954ff 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/migration.rs b/polkadot/runtime/parachains/src/coretime/migration.rs index 4e7508867559..52189be3d247 100644 --- a/polkadot/runtime/parachains/src/coretime/migration.rs +++ b/polkadot/runtime/parachains/src/coretime/migration.rs @@ -19,12 +19,9 @@ pub use v_coretime::{GetLegacyLease, MigrateToCoretime}; mod v_coretime { - #[cfg(feature = "try-runtime")] - use crate::scheduler::common::AssignmentProvider; use crate::{ assigner_coretime, configuration, coretime::{mk_coretime_call, Config, PartsOf57600, WeightInfo}, - paras, }; use alloc::{vec, vec::Vec}; #[cfg(feature = "try-runtime")] @@ -51,18 +48,24 @@ mod v_coretime { pub trait GetLegacyLease { /// If parachain is a lease holding parachain, return the block at which the lease expires. fn get_parachain_lease_in_blocks(para: ParaId) -> Option; + // All parachains holding a lease, no matter if there are gaps in the slots or not. + fn get_all_parachains_with_leases() -> Vec; } /// Migrate a chain to use coretime. /// /// This assumes that the `Coretime` and the `AssignerCoretime` pallets are added at the same /// time to a runtime. - pub struct MigrateToCoretime( + pub struct MigrateToCoretime( core::marker::PhantomData<(T, SendXcm, LegacyLease)>, ); - impl>> - MigrateToCoretime + impl< + T: Config, + SendXcm: xcm::v4::SendXcm, + LegacyLease: GetLegacyLease>, + const TIMESLICE_PERIOD: u32, + > MigrateToCoretime { fn already_migrated() -> bool { // We are using the assigner coretime because the coretime pallet doesn't has any @@ -94,7 +97,8 @@ mod v_coretime { T: Config + crate::dmp::Config, SendXcm: xcm::v4::SendXcm, LegacyLease: GetLegacyLease>, - > OnRuntimeUpgrade for MigrateToCoretime + const TIMESLICE_PERIOD: u32, + > OnRuntimeUpgrade for MigrateToCoretime { fn on_runtime_upgrade() -> Weight { if Self::already_migrated() { @@ -102,7 +106,7 @@ mod v_coretime { } log::info!("Migrating existing parachains to coretime."); - migrate_to_coretime::() + migrate_to_coretime::() } #[cfg(feature = "try-runtime")] @@ -111,7 +115,7 @@ mod v_coretime { return Ok(Vec::new()) } - let legacy_paras = paras::Parachains::::get(); + let legacy_paras = LegacyLease::get_all_parachains_with_leases(); let config = configuration::ActiveConfig::::get(); let total_core_count = config.scheduler_params.num_cores + legacy_paras.len() as u32; @@ -136,7 +140,8 @@ mod v_coretime { let dmp_queue_size = crate::dmp::Pallet::::dmq_contents(T::BrokerId::get().into()).len() as u32; - let new_core_count = assigner_coretime::Pallet::::session_core_count(); + let config = configuration::ActiveConfig::::get(); + let new_core_count = config.scheduler_params.num_cores; ensure!(new_core_count == prev_core_count, "Total number of cores need to not change."); ensure!( dmp_queue_size > prev_dmp_queue_size, @@ -154,8 +159,9 @@ mod v_coretime { T: Config, SendXcm: xcm::v4::SendXcm, LegacyLease: GetLegacyLease>, + const TIMESLICE_PERIOD: u32, >() -> Weight { - let legacy_paras = paras::Parachains::::get(); + let legacy_paras = LegacyLease::get_all_parachains_with_leases(); let legacy_count = legacy_paras.len() as u32; let now = frame_system::Pallet::::block_number(); for (core, para_id) in legacy_paras.into_iter().enumerate() { @@ -175,7 +181,6 @@ mod v_coretime { } let config = configuration::ActiveConfig::::get(); - // num_cores was on_demand_cores until now: for on_demand in 0..config.scheduler_params.num_cores { let core = CoreIndex(legacy_count.saturating_add(on_demand as _)); let r = assigner_coretime::Pallet::::assign_core( @@ -193,7 +198,9 @@ mod v_coretime { c.scheduler_params.num_cores = total_cores; }); - if let Err(err) = migrate_send_assignments_to_coretime_chain::() { + if let Err(err) = + migrate_send_assignments_to_coretime_chain::( + ) { log::error!("Sending legacy chain data to coretime chain failed: {:?}", err); } @@ -210,8 +217,9 @@ mod v_coretime { T: Config, SendXcm: xcm::v4::SendXcm, LegacyLease: GetLegacyLease>, + const TIMESLICE_PERIOD: u32, >() -> result::Result<(), SendError> { - let legacy_paras = paras::Parachains::::get(); + let legacy_paras = LegacyLease::get_all_parachains_with_leases(); let legacy_paras_count = legacy_paras.len(); let (system_chains, lease_holding): (Vec<_>, Vec<_>) = legacy_paras.into_iter().partition(IsSystem::is_system); @@ -224,7 +232,7 @@ mod v_coretime { mk_coretime_call::(crate::coretime::CoretimeCalls::Reserve(schedule)) }); - let leases = lease_holding.into_iter().filter_map(|p| { + let mut leases = lease_holding.into_iter().filter_map(|p| { log::trace!(target: "coretime-migration", "Preparing sending of lease holding para {:?}", p); let Some(valid_until) = LegacyLease::get_parachain_lease_in_blocks(p) else { log::error!("Lease holding chain with no lease information?!"); @@ -237,10 +245,7 @@ mod v_coretime { return None }, }; - // We assume the coretime chain set this parameter to the recommended value in RFC-1: - const TIME_SLICE_PERIOD: u32 = 80; - let round_up = if valid_until % TIME_SLICE_PERIOD > 0 { 1 } else { 0 }; - let time_slice = valid_until / TIME_SLICE_PERIOD + TIME_SLICE_PERIOD * round_up; + let time_slice = (valid_until + TIMESLICE_PERIOD - 1) / TIMESLICE_PERIOD; log::trace!(target: "coretime-migration", "Sending of lease holding para {:?}, valid_until: {:?}, time_slice: {:?}", p, valid_until, time_slice); Some(mk_coretime_call::(crate::coretime::CoretimeCalls::SetLease(p.into(), time_slice))) }); @@ -269,16 +274,30 @@ mod v_coretime { }); let reservation_content = message_content.clone().chain(reservations).collect(); - let pool_content = message_content.clone().chain(pool).collect(); - let leases_content = message_content.clone().chain(leases).collect(); + let leases_content_1 = message_content + .clone() + .chain(leases.by_ref().take(legacy_paras_count / 2)) // split in two messages to avoid overweighted XCM + .collect(); + let leases_content_2 = message_content.clone().chain(leases).collect(); let set_core_count_content = message_content.clone().chain(set_core_count).collect(); - - let messages = vec![ - Xcm(reservation_content), - Xcm(pool_content), - Xcm(leases_content), - Xcm(set_core_count_content), - ]; + // If `pool_content` is empty don't send a blank XCM message + let messages = if core_count as usize > legacy_paras_count { + let pool_content = message_content.clone().chain(pool).collect(); + vec![ + Xcm(reservation_content), + Xcm(pool_content), + Xcm(leases_content_1), + Xcm(leases_content_2), + Xcm(set_core_count_content), + ] + } else { + vec![ + Xcm(reservation_content), + Xcm(leases_content_1), + Xcm(leases_content_2), + Xcm(set_core_count_content), + ] + }; for message in messages { send_xcm::( diff --git a/polkadot/runtime/parachains/src/coretime/mod.rs b/polkadot/runtime/parachains/src/coretime/mod.rs index 1c38b3989232..9b9bdb86878f 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(|_| { @@ -359,20 +358,24 @@ fn mk_coretime_call(call: crate::coretime::CoretimeCalls) -> Instruct fn do_notify_revenue(when: BlockNumber, raw_revenue: Balance) -> Result<(), XcmError> { let dest = Junction::Parachain(T::BrokerId::get()).into_location(); - let mut message = Vec::new(); + let mut message = vec![Instruction::UnpaidExecution { + weight_limit: WeightLimit::Unlimited, + check_origin: None, + }]; let asset = Asset { id: AssetId(Location::here()), fun: Fungible(raw_revenue) }; let dummy_xcm_context = XcmContext { origin: None, message_id: [0; 32], topic: None }; if raw_revenue > 0 { let on_demand_pot = - T::AccountToLocation::try_convert(&>::account_id()) - .map_err(|err| { + 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)?; @@ -384,10 +387,6 @@ fn do_notify_revenue(when: BlockNumber, raw_revenue: Balance) -> Resu message.extend( [ - Instruction::UnpaidExecution { - weight_limit: WeightLimit::Unlimited, - check_origin: None, - }, ReceiveTeleportedAsset(assets_reanchored), DepositAsset { assets: Wild(AllCounted(1)), diff --git a/polkadot/runtime/parachains/src/disputes.rs b/polkadot/runtime/parachains/src/disputes.rs index f86573dadf56..d5a3f31e5943 100644 --- a/polkadot/runtime/parachains/src/disputes.rs +++ b/polkadot/runtime/parachains/src/disputes.rs @@ -1309,3 +1309,11 @@ fn check_signature( res } + +#[cfg(all(not(feature = "runtime-benchmarks"), test))] +// Test helper for clearing the on-chain dispute data. +pub(crate) fn clear_dispute_storage() { + let _ = Disputes::::clear(u32::MAX, None); + let _ = BackersOnDisputes::::clear(u32::MAX, None); + let _ = Included::::clear(u32::MAX, None); +} diff --git a/polkadot/runtime/parachains/src/disputes/slashing.rs b/polkadot/runtime/parachains/src/disputes/slashing.rs index 4b76fb47e1f8..2e09ea667f74 100644 --- a/polkadot/runtime/parachains/src/disputes/slashing.rs +++ b/polkadot/runtime/parachains/src/disputes/slashing.rs @@ -653,7 +653,7 @@ impl Default for SlashingReportHandler { impl HandleReports for SlashingReportHandler where - T: Config + frame_system::offchain::SendTransactionTypes>, + T: Config + frame_system::offchain::CreateInherent>, R: ReportOffence< T::AccountId, T::KeyOwnerIdentification, @@ -685,7 +685,7 @@ where dispute_proof: DisputeProof, key_owner_proof: ::KeyOwnerProof, ) -> Result<(), sp_runtime::TryRuntimeError> { - use frame_system::offchain::SubmitTransaction; + use frame_system::offchain::{CreateInherent, SubmitTransaction}; let session_index = dispute_proof.time_slot.session_index; let validator_index = dispute_proof.validator_index.0; @@ -696,7 +696,8 @@ where key_owner_proof, }; - match SubmitTransaction::>::submit_unsigned_transaction(call.into()) { + let xt = >>::create_inherent(call.into()); + match SubmitTransaction::>::submit_transaction(xt) { Ok(()) => { log::info!( target: LOG_TARGET, diff --git a/polkadot/runtime/parachains/src/dmp.rs b/polkadot/runtime/parachains/src/dmp.rs index 54e112d1b8b4..03580e11b8e9 100644 --- a/polkadot/runtime/parachains/src/dmp.rs +++ b/polkadot/runtime/parachains/src/dmp.rs @@ -287,7 +287,7 @@ impl Pallet { } /// Prunes the specified number of messages from the downward message queue of the given para. - pub(crate) fn prune_dmq(para: ParaId, processed_downward_messages: u32) -> Weight { + pub(crate) fn prune_dmq(para: ParaId, processed_downward_messages: u32) { let q_len = DownwardMessageQueues::::mutate(para, |q| { let processed_downward_messages = processed_downward_messages as usize; if processed_downward_messages > q.len() { @@ -306,7 +306,6 @@ impl Pallet { if q_len <= (threshold as usize) { Self::decrease_fee_factor(para); } - T::DbWeight::get().reads_writes(1, 1) } /// Returns the Head of Message Queue Chain for the given para or `None` if there is none diff --git a/polkadot/runtime/parachains/src/hrmp.rs b/polkadot/runtime/parachains/src/hrmp.rs index 8b01a755c3c7..220543f00ec3 100644 --- a/polkadot/runtime/parachains/src/hrmp.rs +++ b/polkadot/runtime/parachains/src/hrmp.rs @@ -945,7 +945,7 @@ impl Pallet { outgoing_paras.len() as u32 )) .saturating_add(::WeightInfo::force_process_hrmp_close( - outgoing_paras.len() as u32 + outgoing_paras.len() as u32, )) } @@ -1305,9 +1305,7 @@ impl Pallet { remaining } - pub(crate) fn prune_hrmp(recipient: ParaId, new_hrmp_watermark: BlockNumberFor) -> Weight { - let mut weight = Weight::zero(); - + pub(crate) fn prune_hrmp(recipient: ParaId, new_hrmp_watermark: BlockNumberFor) { // sift through the incoming messages digest to collect the paras that sent at least one // message to this parachain between the old and new watermarks. let senders = HrmpChannelDigests::::mutate(&recipient, |digest| { @@ -1323,7 +1321,6 @@ impl Pallet { *digest = leftover; senders }); - weight += T::DbWeight::get().reads_writes(1, 1); // having all senders we can trivially find out the channels which we need to prune. let channels_to_prune = @@ -1356,21 +1353,13 @@ impl Pallet { channel.total_size -= pruned_size as u32; } }); - - weight += T::DbWeight::get().reads_writes(2, 2); } HrmpWatermarks::::insert(&recipient, new_hrmp_watermark); - weight += T::DbWeight::get().reads_writes(0, 1); - - weight } /// Process the outbound HRMP messages by putting them into the appropriate recipient queues. - /// - /// Returns the amount of weight consumed. - pub(crate) fn queue_outbound_hrmp(sender: ParaId, out_hrmp_msgs: HorizontalMessages) -> Weight { - let mut weight = Weight::zero(); + pub(crate) fn queue_outbound_hrmp(sender: ParaId, out_hrmp_msgs: HorizontalMessages) { let now = frame_system::Pallet::::block_number(); for out_msg in out_hrmp_msgs { @@ -1426,11 +1415,7 @@ impl Pallet { recipient_digest.push((now, vec![sender])); } HrmpChannelDigests::::insert(&channel_id.recipient, recipient_digest); - - weight += T::DbWeight::get().reads_writes(2, 2); } - - weight } /// Initiate opening a channel from a parachain to a given recipient with given channel diff --git a/polkadot/runtime/parachains/src/inclusion/benchmarking.rs b/polkadot/runtime/parachains/src/inclusion/benchmarking.rs index 169e858deda8..1dac3c92cf16 100644 --- a/polkadot/runtime/parachains/src/inclusion/benchmarking.rs +++ b/polkadot/runtime/parachains/src/inclusion/benchmarking.rs @@ -15,23 +15,133 @@ // along with Polkadot. If not, see . use super::*; +use crate::{ + builder::generate_validator_pairs, + configuration, + hrmp::{HrmpChannel, HrmpChannels}, + initializer, HeadData, ValidationCode, +}; +use bitvec::{bitvec, prelude::Lsb0}; use frame_benchmarking::benchmarks; use pallet_message_queue as mq; +use polkadot_primitives::{ + vstaging::CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CandidateCommitments, + HrmpChannelId, OutboundHrmpMessage, SessionIndex, +}; + +fn create_candidate_commitments( + para_id: ParaId, + head_data: HeadData, + max_msg_len: usize, + ump_msg_count: u32, + hrmp_msg_count: u32, + code_upgrade: bool, +) -> CandidateCommitments { + let upward_messages = { + let unbounded = create_messages(max_msg_len, ump_msg_count as _); + BoundedVec::truncate_from(unbounded) + }; + + let horizontal_messages = { + let unbounded = create_messages(max_msg_len, hrmp_msg_count as _); + + for n in 0..unbounded.len() { + let channel_id = HrmpChannelId { sender: para_id, recipient: para_id + n as u32 + 1 }; + HrmpChannels::::insert( + &channel_id, + HrmpChannel { + sender_deposit: 42, + recipient_deposit: 42, + max_capacity: 10_000_000, + max_total_size: 1_000_000_000, + max_message_size: 10_000_000, + msg_count: 0, + total_size: 0, + mqc_head: None, + }, + ); + } + + let unbounded = unbounded + .into_iter() + .enumerate() + .map(|(n, data)| OutboundHrmpMessage { recipient: para_id + n as u32 + 1, data }) + .collect(); + BoundedVec::truncate_from(unbounded) + }; + + let new_validation_code = code_upgrade.then_some(ValidationCode(vec![42u8; 1024])); + + CandidateCommitments:: { + upward_messages, + horizontal_messages, + new_validation_code, + head_data, + processed_downward_messages: 0, + hrmp_watermark: 10, + } +} + +fn create_messages(msg_len: usize, n_msgs: usize) -> Vec> { + let best_number = 73_u8; // Chuck Norris of numbers + vec![vec![best_number; msg_len]; n_msgs] +} benchmarks! { where_clause { where - T: mq::Config, + T: mq::Config + configuration::Config + initializer::Config, } - receive_upward_messages { - let i in 1 .. 1000; + enact_candidate { + let u in 0 .. 2; + let h in 0 .. 2; + let c in 0 .. 1; + + let para = 42_u32.into(); // not especially important. let max_len = mq::MaxMessageLenOf::::get() as usize; - let para = 42u32.into(); // not especially important. - let upward_messages = vec![vec![0; max_len]; i as usize]; + + let config = configuration::ActiveConfig::::get(); + let n_validators = config.max_validators.unwrap_or(500); + let validators = generate_validator_pairs::(n_validators); + + let session = SessionIndex::from(0u32); + initializer::Pallet::::test_trigger_on_new_session( + false, + session, + validators.iter().map(|(a, v)| (a, v.clone())), + None, + ); + let backing_group_size = config.scheduler_params.max_validators_per_core.unwrap_or(5); + let head_data = HeadData(vec![0xFF; 1024]); + + let relay_parent_number = BlockNumberFor::::from(10u32); + let commitments = create_candidate_commitments::(para, head_data, max_len, u, h, c != 0); + let backers = bitvec![u8, Lsb0; 1; backing_group_size as usize]; + let availability_votes = bitvec![u8, Lsb0; 1; n_validators as usize]; + let core_index = CoreIndex::from(0); + let backing_group = GroupIndex::from(0); + + let descriptor = CandidateDescriptor::::new( + para, + Default::default(), + CoreIndex(0), + 1, + Default::default(), + Default::default(), + Default::default(), + Default::default(), + ValidationCode(vec![1, 2, 3]).hash(), + ); + + let receipt = CommittedCandidateReceipt:: { + descriptor, + commitments, + }; + Pallet::::receive_upward_messages(para, vec![vec![0; max_len]; 1].as_slice()); - }: { Pallet::::receive_upward_messages(para, upward_messages.as_slice()) } + } : { Pallet::::enact_candidate(relay_parent_number, receipt, backers, availability_votes, core_index, backing_group) } impl_benchmark_test_suite!( Pallet, diff --git a/polkadot/runtime/parachains/src/inclusion/migration.rs b/polkadot/runtime/parachains/src/inclusion/migration.rs index 36a810d341c6..2a215d5d595c 100644 --- a/polkadot/runtime/parachains/src/inclusion/migration.rs +++ b/polkadot/runtime/parachains/src/inclusion/migration.rs @@ -20,8 +20,8 @@ pub mod v0 { use frame_support::{storage_alias, Twox64Concat}; use frame_system::pallet_prelude::BlockNumberFor; use polkadot_primitives::{ - AvailabilityBitfield, CandidateCommitments, CandidateDescriptor, CandidateHash, CoreIndex, - GroupIndex, Id as ParaId, ValidatorIndex, + vstaging::CandidateDescriptorV2 as CandidateDescriptor, AvailabilityBitfield, + CandidateCommitments, CandidateHash, CoreIndex, GroupIndex, Id as ParaId, ValidatorIndex, }; use scale_info::TypeInfo; @@ -219,7 +219,7 @@ mod tests { use frame_support::traits::UncheckedOnRuntimeUpgrade; use polkadot_primitives::{AvailabilityBitfield, Id as ParaId}; use polkadot_primitives_test_helpers::{ - dummy_candidate_commitments, dummy_candidate_descriptor, dummy_hash, + dummy_candidate_commitments, dummy_candidate_descriptor_v2, dummy_hash, }; #[test] @@ -235,7 +235,7 @@ mod tests { let mut expected = vec![]; for i in 1..5 { - let descriptor = dummy_candidate_descriptor(dummy_hash()); + let descriptor = dummy_candidate_descriptor_v2(dummy_hash()); v0::PendingAvailability::::insert( ParaId::from(i), v0::CandidatePendingAvailability { @@ -285,7 +285,7 @@ mod tests { ParaId::from(6), v0::CandidatePendingAvailability { core: CoreIndex(6), - descriptor: dummy_candidate_descriptor(dummy_hash()), + descriptor: dummy_candidate_descriptor_v2(dummy_hash()), relay_parent_number: 6, hash: CandidateHash(dummy_hash()), availability_votes: Default::default(), diff --git a/polkadot/runtime/parachains/src/inclusion/mod.rs b/polkadot/runtime/parachains/src/inclusion/mod.rs index 281dc5d0c5f4..ea3a5d3cdda9 100644 --- a/polkadot/runtime/parachains/src/inclusion/mod.rs +++ b/polkadot/runtime/parachains/src/inclusion/mod.rs @@ -34,7 +34,6 @@ use alloc::{ }; use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec}; use codec::{Decode, Encode}; -#[cfg(feature = "std")] use core::fmt; use frame_support::{ defensive, @@ -45,11 +44,15 @@ use frame_support::{ use frame_system::pallet_prelude::*; use pallet_message_queue::OnQueueChanged; use polkadot_primitives::{ - effective_minimum_backing_votes, supermajority_threshold, well_known_keys, BackedCandidate, - CandidateCommitments, CandidateDescriptor, CandidateHash, CandidateReceipt, - CommittedCandidateReceipt, CoreIndex, GroupIndex, Hash, HeadData, Id as ParaId, - SignedAvailabilityBitfields, SigningContext, UpwardMessage, ValidatorId, ValidatorIndex, - ValidityAttestation, + effective_minimum_backing_votes, supermajority_threshold, + vstaging::{ + BackedCandidate, CandidateDescriptorV2 as CandidateDescriptor, + CandidateReceiptV2 as CandidateReceipt, + CommittedCandidateReceiptV2 as CommittedCandidateReceipt, + }, + well_known_keys, CandidateCommitments, CandidateHash, CoreIndex, GroupIndex, HeadData, + Id as ParaId, SignedAvailabilityBitfields, SigningContext, UpwardMessage, ValidatorId, + ValidatorIndex, ValidityAttestation, }; use scale_info::TypeInfo; use sp_runtime::{traits::One, DispatchError, SaturatedConversion, Saturating}; @@ -65,18 +68,23 @@ mod benchmarking; pub mod migration; pub trait WeightInfo { - fn receive_upward_messages(i: u32) -> Weight; + /// Weight for `enact_candidate` extrinsic given the number of sent messages + /// (ump, hrmp) and whether there is a new code for a runtime upgrade. + /// + /// NOTE: due to a shortcoming of the current benchmarking framework, + /// we use `u32` for the code upgrade, even though it is a `bool`. + fn enact_candidate(u: u32, h: u32, c: u32) -> Weight; } pub struct TestWeightInfo; impl WeightInfo for TestWeightInfo { - fn receive_upward_messages(_: u32) -> Weight { - Weight::MAX + fn enact_candidate(_u: u32, _h: u32, _c: u32) -> Weight { + Weight::zero() } } impl WeightInfo for () { - fn receive_upward_messages(_: u32) -> Weight { + fn enact_candidate(_u: u32, _h: u32, _c: u32) -> Weight { Weight::zero() } } @@ -153,16 +161,6 @@ impl CandidatePendingAvailability { self.relay_parent_number.clone() } - /// Get the candidate backing group. - pub(crate) fn backing_group(&self) -> GroupIndex { - self.backing_group - } - - /// Get the candidate's backers. - pub(crate) fn backers(&self) -> &BitVec { - &self.backers - } - #[cfg(any(feature = "runtime-benchmarks", test))] pub(crate) fn new( core: CoreIndex, @@ -199,24 +197,6 @@ pub trait RewardValidators { fn reward_bitfields(validators: impl IntoIterator); } -/// Helper return type for `process_candidates`. -#[derive(Encode, Decode, PartialEq, TypeInfo)] -#[cfg_attr(test, derive(Debug))] -pub(crate) struct ProcessedCandidates { - pub(crate) core_indices: Vec<(CoreIndex, ParaId)>, - pub(crate) candidate_receipt_with_backing_validator_indices: - Vec<(CandidateReceipt, Vec<(ValidatorIndex, ValidityAttestation)>)>, -} - -impl Default for ProcessedCandidates { - fn default() -> Self { - Self { - core_indices: Vec::new(), - candidate_receipt_with_backing_validator_indices: Vec::new(), - } - } -} - /// Reads the footprint of queues for a specific origin type. pub trait QueueFootprinter { type Origin; @@ -338,8 +318,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. @@ -378,7 +356,7 @@ pub mod pallet { const LOG_TARGET: &str = "runtime::inclusion"; /// The reason that a candidate's outputs were rejected for. -#[cfg_attr(feature = "std", derive(Debug))] +#[derive(Debug)] enum AcceptanceCheckErr { HeadDataTooLarge, /// Code upgrades are not permitted at the current time. @@ -434,9 +412,13 @@ pub(crate) enum UmpAcceptanceCheckErr { TotalSizeExceeded { total_size: u64, limit: u64 }, /// A para-chain cannot send UMP messages while it is offboarding. IsOffboarding, + /// The allowed number of `UMPSignal` messages in the queue was exceeded. + /// Currenly only one such message is allowed. + TooManyUMPSignals { count: u32 }, + /// The UMP queue contains an invalid `UMPSignal` + NoUmpSignal, } -#[cfg(feature = "std")] impl fmt::Debug for UmpAcceptanceCheckErr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -463,6 +445,12 @@ impl fmt::Debug for UmpAcceptanceCheckErr { UmpAcceptanceCheckErr::IsOffboarding => { write!(fmt, "upward message rejected because the para is off-boarding") }, + UmpAcceptanceCheckErr::TooManyUMPSignals { count } => { + write!(fmt, "the ump queue has too many `UMPSignal` messages ({} > 1 )", count) + }, + UmpAcceptanceCheckErr::NoUmpSignal => { + write!(fmt, "Required UMP signal not found") + }, } } } @@ -498,6 +486,14 @@ impl Pallet { T::MessageQueue::sweep_queue(AggregateMessageOrigin::Ump(UmpQueueId::Para(para))); } + pub(crate) fn get_occupied_cores( + ) -> impl Iterator>)> + { + PendingAvailability::::iter_values().flat_map(|pending_candidates| { + pending_candidates.into_iter().map(|c| (c.core, c.clone())) + }) + } + /// Extract the freed cores based on cores that became available. /// /// Bitfields are expected to have been sanitized already. E.g. via `sanitize_bitfields`! @@ -509,7 +505,7 @@ impl Pallet { pub(crate) fn update_pending_availability_and_get_freed_cores( validators: &[ValidatorId], signed_bitfields: SignedAvailabilityBitfields, - ) -> Vec<(CoreIndex, CandidateHash)> { + ) -> (Weight, Vec<(CoreIndex, CandidateHash)>) { let threshold = availability_threshold(validators.len()); let mut votes_per_core: BTreeMap> = BTreeMap::new(); @@ -530,6 +526,7 @@ impl Pallet { } let mut freed_cores = vec![]; + let mut weight = Weight::zero(); let pending_paraids: Vec<_> = PendingAvailability::::iter_keys().collect(); for paraid in pending_paraids { @@ -583,7 +580,17 @@ impl Pallet { descriptor: candidate.descriptor, commitments: candidate.commitments, }; - let _weight = Self::enact_candidate( + + let has_runtime_upgrade = + receipt.commitments.new_validation_code.as_ref().map_or(0, |_| 1); + let u = receipt.commitments.upward_messages.len() as u32; + let h = receipt.commitments.horizontal_messages.len() as u32; + let enact_weight = ::WeightInfo::enact_candidate( + u, + h, + has_runtime_upgrade, + ); + Self::enact_candidate( candidate.relay_parent_number, receipt, candidate.backers, @@ -591,13 +598,14 @@ impl Pallet { candidate.core, candidate.backing_group, ); + weight.saturating_accrue(enact_weight); } } } }); } - freed_cores + (weight, freed_cores) } /// Process candidates that have been backed. Provide a set of @@ -612,12 +620,15 @@ impl Pallet { candidates: &BTreeMap, CoreIndex)>>, group_validators: GV, core_index_enabled: bool, - ) -> Result, DispatchError> + ) -> Result< + Vec<(CandidateReceipt, Vec<(ValidatorIndex, ValidityAttestation)>)>, + DispatchError, + > where GV: Fn(GroupIndex) -> Option>, { if candidates.is_empty() { - return Ok(ProcessedCandidates::default()) + return Ok(Default::default()) } let now = frame_system::Pallet::::block_number(); @@ -626,7 +637,6 @@ impl Pallet { // Collect candidate receipts with backers. let mut candidate_receipt_with_backing_validator_indices = Vec::with_capacity(candidates.len()); - let mut core_indices = Vec::with_capacity(candidates.len()); for (para_id, para_candidates) in candidates { let mut latest_head_data = match Self::para_latest_head_data(para_id) { @@ -640,6 +650,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, @@ -678,7 +690,6 @@ impl Pallet { latest_head_data = candidate.candidate().commitments.head_data.clone(); candidate_receipt_with_backing_validator_indices .push((candidate.receipt(), backer_idx_and_attestation)); - core_indices.push((*core, *para_id)); // Update storage now PendingAvailability::::mutate(¶_id, |pending_availability| { @@ -713,13 +724,10 @@ impl Pallet { } } - Ok(ProcessedCandidates:: { - core_indices, - candidate_receipt_with_backing_validator_indices, - }) + Ok(candidate_receipt_with_backing_validator_indices) } - // 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 +737,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], @@ -739,7 +757,7 @@ impl Pallet { let mut backers = bitvec::bitvec![u8, BitOrderLsb0; 0; validators.len()]; let signing_context = SigningContext { - parent_hash: backed_candidate.descriptor().relay_parent, + parent_hash: backed_candidate.descriptor().relay_parent(), session_index: shared::CurrentSessionIndex::::get(), }; @@ -798,26 +816,23 @@ 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 - .check_validation_outputs( - para_id, - relay_parent_number, - &validation_outputs.head_data, - &validation_outputs.new_validation_code, - validation_outputs.processed_downward_messages, - &validation_outputs.upward_messages, - BlockNumberFor::::from(validation_outputs.hrmp_watermark), - &validation_outputs.horizontal_messages, - ) - .is_err() - { + if let Err(err) = check_ctx.check_validation_outputs( + para_id, + relay_parent_number, + &validation_outputs.head_data, + &validation_outputs.new_validation_code, + validation_outputs.processed_downward_messages, + &validation_outputs.upward_messages, + BlockNumberFor::::from(validation_outputs.hrmp_watermark), + &validation_outputs.horizontal_messages, + ) { log::debug!( target: LOG_TARGET, - "Validation outputs checking for parachain `{}` failed", - u32::from(para_id), + "Validation outputs checking for parachain `{}` failed, error: {:?}", + u32::from(para_id), err ); false } else { @@ -832,7 +847,7 @@ impl Pallet { availability_votes: BitVec, core_index: CoreIndex, backing_group: GroupIndex, - ) -> Weight { + ) { let plain = receipt.to_plain(); let commitments = receipt.commitments; let config = configuration::ActiveConfig::::get(); @@ -853,38 +868,36 @@ impl Pallet { .map(|(i, _)| ValidatorIndex(i as _)), ); - // initial weight is config read. - let mut weight = T::DbWeight::get().reads_writes(1, 0); if let Some(new_code) = commitments.new_validation_code { // Block number of candidate's inclusion. let now = frame_system::Pallet::::block_number(); - weight.saturating_add(paras::Pallet::::schedule_code_upgrade( - receipt.descriptor.para_id, + paras::Pallet::::schedule_code_upgrade( + receipt.descriptor.para_id(), new_code, now, &config, UpgradeStrategy::SetGoAheadSignal, - )); + ); } // enact the messaging facet of the candidate. - weight.saturating_accrue(dmp::Pallet::::prune_dmq( - receipt.descriptor.para_id, + dmp::Pallet::::prune_dmq( + receipt.descriptor.para_id(), commitments.processed_downward_messages, - )); - weight.saturating_accrue(Self::receive_upward_messages( - receipt.descriptor.para_id, + ); + Self::receive_upward_messages( + receipt.descriptor.para_id(), commitments.upward_messages.as_slice(), - )); - weight.saturating_accrue(hrmp::Pallet::::prune_hrmp( - receipt.descriptor.para_id, + ); + hrmp::Pallet::::prune_hrmp( + receipt.descriptor.para_id(), BlockNumberFor::::from(commitments.hrmp_watermark), - )); - weight.saturating_accrue(hrmp::Pallet::::queue_outbound_hrmp( - receipt.descriptor.para_id, + ); + hrmp::Pallet::::queue_outbound_hrmp( + receipt.descriptor.para_id(), commitments.horizontal_messages, - )); + ); Self::deposit_event(Event::::CandidateIncluded( plain, @@ -893,11 +906,11 @@ impl Pallet { backing_group, )); - weight.saturating_add(paras::Pallet::::note_new_head( - receipt.descriptor.para_id, + paras::Pallet::::note_new_head( + receipt.descriptor.para_id(), commitments.head_data, relay_parent_number, - )) + ); } pub(crate) fn relay_dispatch_queue_size(para_id: ParaId) -> (u32, u32) { @@ -911,6 +924,27 @@ impl Pallet { para: ParaId, upward_messages: &[UpwardMessage], ) -> Result<(), UmpAcceptanceCheckErr> { + // Filter any pending UMP signals and the separator. + let upward_messages = if let Some(separator_index) = + upward_messages.iter().position(|message| message.is_empty()) + { + let (upward_messages, ump_signals) = upward_messages.split_at(separator_index); + + if ump_signals.len() > 2 { + return Err(UmpAcceptanceCheckErr::TooManyUMPSignals { + count: ump_signals.len() as u32, + }) + } + + if ump_signals.len() == 1 { + return Err(UmpAcceptanceCheckErr::NoUmpSignal) + } + + upward_messages + } else { + upward_messages + }; + // Cannot send UMP messages while off-boarding. if paras::Pallet::::is_offboarding(para) { ensure!(upward_messages.is_empty(), UmpAcceptanceCheckErr::IsOffboarding); @@ -962,14 +996,15 @@ impl Pallet { /// This function is infallible since the candidate was already accepted and we therefore need /// to deal with the messages as given. Messages that are too long will be ignored since such /// candidates should have already been rejected in [`Self::check_upward_messages`]. - pub(crate) fn receive_upward_messages(para: ParaId, upward_messages: &[Vec]) -> Weight { + pub(crate) fn receive_upward_messages(para: ParaId, upward_messages: &[Vec]) { let bounded = upward_messages .iter() + // Stop once we hit the `UMPSignal` separator. + .take_while(|message| !message.is_empty()) .filter_map(|d| { BoundedSlice::try_from(&d[..]) - .map_err(|e| { + .inspect_err(|_| { defensive!("Accepted candidate contains too long msg, len=", d.len()); - e }) .ok() }) @@ -981,19 +1016,17 @@ impl Pallet { pub(crate) fn receive_bounded_upward_messages( para: ParaId, messages: Vec>>, - ) -> Weight { + ) { let count = messages.len() as u32; if count == 0 { - return Weight::zero() + return } T::MessageQueue::enqueue_messages( messages.into_iter(), AggregateMessageOrigin::Ump(UmpQueueId::Para(para)), ); - let weight = ::WeightInfo::receive_upward_messages(count); Self::deposit_event(Event::UpwardMessagesReceived { from: para, count }); - weight } /// Cleans up all timed out candidates as well as their descendant candidates. @@ -1118,7 +1151,9 @@ impl Pallet { /// Returns the first `CommittedCandidateReceipt` pending availability for the para provided, if /// any. - pub(crate) fn candidate_pending_availability( + /// A para_id could have more than one candidates pending availability, if it's using elastic + /// scaling. These candidates form a chain. This function returns the first in the chain. + pub(crate) fn first_candidate_pending_availability( para: ParaId, ) -> Option> { PendingAvailability::::get(¶).and_then(|p| { @@ -1146,24 +1181,6 @@ impl Pallet { }) .unwrap_or_default() } - - /// Returns the metadata around the first candidate pending availability for the - /// para provided, if any. - pub(crate) fn pending_availability( - para: ParaId, - ) -> Option>> { - PendingAvailability::::get(¶).and_then(|p| p.get(0).cloned()) - } - - /// Returns the metadata around the candidate pending availability occupying the supplied core, - /// if any. - pub(crate) fn pending_availability_with_core( - para: ParaId, - core: CoreIndex, - ) -> Option>> { - PendingAvailability::::get(¶) - .and_then(|p| p.iter().find(|c| c.core == core).cloned()) - } } const fn availability_threshold(n_validators: usize) -> usize { @@ -1222,7 +1239,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 /// @@ -1233,47 +1249,42 @@ impl CandidateCheckContext { backed_candidate_receipt: &CommittedCandidateReceipt<::Hash>, parent_head_data: HeadData, ) -> Result, Error> { - let para_id = backed_candidate_receipt.descriptor().para_id; - let relay_parent = backed_candidate_receipt.descriptor().relay_parent; + let para_id = backed_candidate_receipt.descriptor.para_id(); + let relay_parent = backed_candidate_receipt.descriptor.relay_parent(); // Check that the relay-parent is one of the allowed relay-parents. - let (relay_parent_storage_root, relay_parent_number) = { + let (state_root, relay_parent_number) = { match allowed_relay_parents.acquire_info(relay_parent, self.prev_context) { None => return Err(Error::::DisallowedRelayParent), - Some(info) => info, + Some((info, relay_parent_number)) => (info.state_root, relay_parent_number), } }; { let persisted_validation_data = make_persisted_validation_data_with_parent::( relay_parent_number, - relay_parent_storage_root, + state_root, parent_head_data, ); let expected = persisted_validation_data.hash(); ensure!( - expected == backed_candidate_receipt.descriptor().persisted_validation_data_hash, + expected == backed_candidate_receipt.descriptor.persisted_validation_data_hash(), Error::::ValidationDataHashMismatch, ); } - 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)?; ensure!( - backed_candidate_receipt.descriptor().validation_code_hash == validation_code_hash, + backed_candidate_receipt.descriptor.validation_code_hash() == validation_code_hash, Error::::InvalidValidationCodeHash, ); ensure!( - backed_candidate_receipt.descriptor().para_head == + backed_candidate_receipt.descriptor.para_head() == backed_candidate_receipt.commitments.head_data.hash(), Error::::ParaHeadMismatch, ); @@ -1290,9 +1301,10 @@ impl CandidateCheckContext { ) { log::debug!( target: LOG_TARGET, - "Validation outputs checking during inclusion of a candidate {:?} for parachain `{}` failed", + "Validation outputs checking during inclusion of a candidate {:?} for parachain `{}` failed, error: {:?}", backed_candidate_receipt.hash(), u32::from(para_id), + err ); Err(err.strip_into_dispatch_err::())?; }; @@ -1348,10 +1360,49 @@ impl CandidateCheckContext { para_id, relay_parent_number, processed_downward_messages, + ) + .map_err(|e| { + log::debug!( + target: LOG_TARGET, + "Check processed downward messages for parachain `{}` on relay parent number `{:?}` failed, error: {:?}", + u32::from(para_id), + relay_parent_number, + e + ); + e + })?; + Pallet::::check_upward_messages(&self.config, para_id, upward_messages).map_err( + |e| { + log::debug!( + target: LOG_TARGET, + "Check upward messages for parachain `{}` failed, error: {:?}", + u32::from(para_id), + e + ); + e + }, )?; - Pallet::::check_upward_messages(&self.config, para_id, upward_messages)?; - hrmp::Pallet::::check_hrmp_watermark(para_id, relay_parent_number, hrmp_watermark)?; - hrmp::Pallet::::check_outbound_hrmp(&self.config, para_id, horizontal_messages)?; + hrmp::Pallet::::check_hrmp_watermark(para_id, relay_parent_number, hrmp_watermark) + .map_err(|e| { + log::debug!( + target: LOG_TARGET, + "Check hrmp watermark for parachain `{}` on relay parent number `{:?}` failed, error: {:?}", + u32::from(para_id), + relay_parent_number, + e + ); + e + })?; + hrmp::Pallet::::check_outbound_hrmp(&self.config, para_id, horizontal_messages) + .map_err(|e| { + log::debug!( + target: LOG_TARGET, + "Check outbound hrmp for parachain `{}` failed, error: {:?}", + u32::from(para_id), + e + ); + e + })?; Ok(()) } diff --git a/polkadot/runtime/parachains/src/inclusion/tests.rs b/polkadot/runtime/parachains/src/inclusion/tests.rs index 18def664f4b2..188ba4995d83 100644 --- a/polkadot/runtime/parachains/src/inclusion/tests.rs +++ b/polkadot/runtime/parachains/src/inclusion/tests.rs @@ -26,7 +26,12 @@ use crate::{ shared::AllowedRelayParentsTracker, }; use polkadot_primitives::{ - effective_minimum_backing_votes, AvailabilityBitfield, SignedAvailabilityBitfields, + effective_minimum_backing_votes, + vstaging::{ + CandidateDescriptorV2, CandidateDescriptorVersion, ClaimQueueOffset, CoreSelector, + UMPSignal, UMP_SEPARATOR, + }, + AvailabilityBitfield, CandidateDescriptor, SignedAvailabilityBitfields, UncheckedSignedAvailabilityBitfields, }; @@ -34,14 +39,13 @@ use assert_matches::assert_matches; use codec::DecodeAll; use frame_support::assert_noop; use polkadot_primitives::{ - BlockNumber, CandidateCommitments, CandidateDescriptor, CollatorId, + BlockNumber, CandidateCommitments, CollatorId, CollatorSignature, CompactStatement as Statement, Hash, SignedAvailabilityBitfield, SignedStatement, ValidationCode, ValidatorId, ValidityAttestation, PARACHAIN_KEY_TYPE_ID, }; -use polkadot_primitives_test_helpers::{ - dummy_collator, dummy_collator_signature, dummy_validation_code, -}; +use polkadot_primitives_test_helpers::dummy_validation_code; use sc_keystore::LocalKeystore; +use sp_core::ByteArray; use sp_keyring::Sr25519Keyring; use sp_keystore::{Keystore, KeystorePtr}; use std::sync::Arc; @@ -84,7 +88,7 @@ fn default_allowed_relay_parent_tracker() -> AllowedRelayParentsTracker, pub(crate) validation_code: ValidationCode, pub(crate) hrmp_watermark: BlockNumber, + /// Creates a v2 descriptor if set. + pub(crate) core_index: Option, + /// The core selector to use. + pub(crate) core_selector: Option, } impl std::default::Default for TestCandidateBuilder { @@ -296,14 +286,28 @@ impl std::default::Default for TestCandidateBuilder { new_validation_code: None, validation_code: dummy_validation_code(), hrmp_watermark: 0u32.into(), + core_index: None, + core_selector: None, } } } impl TestCandidateBuilder { pub(crate) fn build(self) -> CommittedCandidateReceipt { - CommittedCandidateReceipt { - descriptor: CandidateDescriptor { + let descriptor = if let Some(core_index) = self.core_index { + CandidateDescriptorV2::new( + self.para_id, + self.relay_parent, + core_index, + 0, + self.persisted_validation_data_hash, + self.pov_hash, + Default::default(), + self.para_head_hash.unwrap_or_else(|| self.head_data.hash()), + self.validation_code.hash(), + ) + } else { + CandidateDescriptor { para_id: self.para_id, pov_hash: self.pov_hash, relay_parent: self.relay_parent, @@ -311,16 +315,40 @@ impl TestCandidateBuilder { validation_code_hash: self.validation_code.hash(), para_head: self.para_head_hash.unwrap_or_else(|| self.head_data.hash()), erasure_root: Default::default(), - signature: dummy_collator_signature(), - collator: dummy_collator(), - }, + signature: CollatorSignature::from_slice( + &mut (0..64).into_iter().collect::>().as_slice(), + ) + .expect("64 bytes; qed"), + collator: CollatorId::from_slice( + &mut (0..32).into_iter().collect::>().as_slice(), + ) + .expect("32 bytes; qed"), + } + .into() + }; + let mut ccr = CommittedCandidateReceipt { + descriptor, commitments: CandidateCommitments { head_data: self.head_data, new_validation_code: self.new_validation_code, hrmp_watermark: self.hrmp_watermark, ..Default::default() }, + }; + + if ccr.descriptor.version() == CandidateDescriptorVersion::V2 { + ccr.commitments.upward_messages.force_push(UMP_SEPARATOR); + + ccr.commitments.upward_messages.force_push( + UMPSignal::SelectCore( + CoreSelector(self.core_selector.unwrap_or_default()), + ClaimQueueOffset(0), + ) + .encode(), + ); } + + ccr } } @@ -366,10 +394,11 @@ pub(crate) fn process_bitfields( ) -> Vec<(CoreIndex, CandidateHash)> { let validators = shared::ActiveValidatorKeys::::get(); - ParaInclusion::update_pending_availability_and_get_freed_cores( + let (_weight, bitfields) = ParaInclusion::update_pending_availability_and_get_freed_cores( &validators[..], signed_bitfields, - ) + ); + bitfields } #[test] @@ -1238,12 +1267,12 @@ fn candidate_checks() { &group_validators, false ), - Ok(ProcessedCandidates::default()) + Ok(Default::default()) ); // Check candidate ordering { - let mut candidate_a = TestCandidateBuilder { + let candidate_a = TestCandidateBuilder { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(1), @@ -1252,7 +1281,7 @@ fn candidate_checks() { ..Default::default() } .build(); - let mut candidate_b_1 = TestCandidateBuilder { + let candidate_b_1 = TestCandidateBuilder { para_id: chain_b, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(2), @@ -1264,7 +1293,7 @@ fn candidate_checks() { .build(); // Make candidate b2 a child of b1. - let mut candidate_b_2 = TestCandidateBuilder { + let candidate_b_2 = TestCandidateBuilder { para_id: chain_b, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(3), @@ -1280,10 +1309,6 @@ fn candidate_checks() { } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate_a); - collator_sign_candidate(Sr25519Keyring::Two, &mut candidate_b_1); - collator_sign_candidate(Sr25519Keyring::Two, &mut candidate_b_2); - let backed_a = back_candidate( candidate_a, &validators, @@ -1355,7 +1380,7 @@ fn candidate_checks() { // candidate does not build on top of the latest unincluded head - let mut candidate_b_3 = TestCandidateBuilder { + let candidate_b_3 = TestCandidateBuilder { para_id: chain_b, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(4), @@ -1370,7 +1395,6 @@ fn candidate_checks() { ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::Two, &mut candidate_b_3); let backed_b_3 = back_candidate( candidate_b_3, @@ -1395,7 +1419,7 @@ fn candidate_checks() { // candidate not backed. { - let mut candidate = TestCandidateBuilder { + let candidate = TestCandidateBuilder { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(1), @@ -1404,7 +1428,6 @@ fn candidate_checks() { ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); // Insufficient backing. let backed = back_candidate( @@ -1458,7 +1481,7 @@ fn candidate_checks() { let wrong_parent_hash = Hash::repeat_byte(222); assert!(System::parent_hash() != wrong_parent_hash); - let mut candidate_a = TestCandidateBuilder { + let candidate_a = TestCandidateBuilder { para_id: chain_a, relay_parent: wrong_parent_hash, pov_hash: Hash::repeat_byte(1), @@ -1467,7 +1490,7 @@ fn candidate_checks() { } .build(); - let mut candidate_b = TestCandidateBuilder { + let candidate_b = TestCandidateBuilder { para_id: chain_b, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(2), @@ -1477,10 +1500,6 @@ fn candidate_checks() { } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate_a); - - collator_sign_candidate(Sr25519Keyring::Two, &mut candidate_b); - let backed_a = back_candidate( candidate_a, &validators, @@ -1530,10 +1549,9 @@ fn candidate_checks() { .build(); assert_eq!(CollatorId::from(Sr25519Keyring::Two.public()), thread_collator); - collator_sign_candidate(Sr25519Keyring::Two, &mut candidate); // change the candidate after signing. - candidate.descriptor.pov_hash = Hash::repeat_byte(2); + candidate.descriptor.set_pov_hash(Hash::repeat_byte(2)); let backed = back_candidate( candidate, @@ -1545,22 +1563,54 @@ fn candidate_checks() { None, ); - assert_noop!( + let candidate_receipt_with_backing_validator_indices = ParaInclusion::process_candidates( &allowed_relay_parents, - &vec![(thread_a_assignment.0, vec![(backed, thread_a_assignment.1)])] + &vec![(thread_a_assignment.0, vec![(backed.clone(), thread_a_assignment.1)])] .into_iter() .collect(), &group_validators, - false - ), - Error::::NotCollatorSigned + false, + ) + .expect("candidate is accepted with bad collator signature"); + + 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() ); } // interfering code upgrade - reject { - let mut candidate = TestCandidateBuilder { + let candidate = TestCandidateBuilder { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(1), @@ -1571,8 +1621,6 @@ fn candidate_checks() { } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); - let backed = back_candidate( candidate, &validators, @@ -1611,7 +1659,7 @@ fn candidate_checks() { // Bad validation data hash - reject { - let mut candidate = TestCandidateBuilder { + let candidate = TestCandidateBuilder { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(1), @@ -1621,8 +1669,6 @@ fn candidate_checks() { } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); - let backed = back_candidate( candidate, &validators, @@ -1648,7 +1694,7 @@ fn candidate_checks() { // bad validation code hash { - let mut candidate = TestCandidateBuilder { + let candidate = TestCandidateBuilder { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(1), @@ -1659,8 +1705,6 @@ fn candidate_checks() { } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); - let backed = back_candidate( candidate, &validators, @@ -1686,7 +1730,7 @@ fn candidate_checks() { // Para head hash in descriptor doesn't match head data { - let mut candidate = TestCandidateBuilder { + let candidate = TestCandidateBuilder { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(1), @@ -1697,8 +1741,6 @@ fn candidate_checks() { } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); - let backed = back_candidate( candidate, &validators, @@ -1789,7 +1831,7 @@ fn backing_works() { let chain_b_assignment = (chain_b, CoreIndex::from(1)); let thread_a_assignment = (thread_a, CoreIndex::from(2)); - let mut candidate_a = TestCandidateBuilder { + let candidate_a = TestCandidateBuilder { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(1), @@ -1798,9 +1840,8 @@ fn backing_works() { ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate_a); - let mut candidate_b = TestCandidateBuilder { + let candidate_b = TestCandidateBuilder { para_id: chain_b, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(2), @@ -1809,9 +1850,8 @@ fn backing_works() { ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate_b); - let mut candidate_c = TestCandidateBuilder { + let candidate_c = TestCandidateBuilder { para_id: thread_a, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(3), @@ -1820,7 +1860,6 @@ fn backing_works() { ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::Two, &mut candidate_c); let backed_a = back_candidate( candidate_a.clone(), @@ -1881,10 +1920,7 @@ fn backing_works() { } }; - let ProcessedCandidates { - core_indices: occupied_cores, - candidate_receipt_with_backing_validator_indices, - } = ParaInclusion::process_candidates( + let candidate_receipt_with_backing_validator_indices = ParaInclusion::process_candidates( &allowed_relay_parents, &backed_candidates, &group_validators, @@ -1892,15 +1928,6 @@ fn backing_works() { ) .expect("candidates scheduled, in order, and backed"); - assert_eq!( - occupied_cores, - vec![ - (CoreIndex::from(0), chain_a), - (CoreIndex::from(1), chain_b), - (CoreIndex::from(2), thread_a) - ] - ); - // Transform the votes into the setup we expect let expected = { let mut intermediate = std::collections::HashMap::< @@ -1941,7 +1968,7 @@ fn backing_works() { Vec<(ValidatorIndex, ValidityAttestation)>, )>| { candidate_receipts_with_backers.sort_by(|(cr1, _), (cr2, _)| { - cr1.descriptor().para_id.cmp(&cr2.descriptor().para_id) + cr1.descriptor().para_id().cmp(&cr2.descriptor().para_id()) }); candidate_receipts_with_backers }; @@ -2084,7 +2111,7 @@ fn backing_works_with_elastic_scaling_mvp() { let allowed_relay_parents = default_allowed_relay_parent_tracker(); - let mut candidate_a = TestCandidateBuilder { + let candidate_a = TestCandidateBuilder { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(1), @@ -2093,9 +2120,8 @@ fn backing_works_with_elastic_scaling_mvp() { ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate_a); - let mut candidate_b_1 = TestCandidateBuilder { + let candidate_b_1 = TestCandidateBuilder { para_id: chain_b, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(2), @@ -2104,10 +2130,9 @@ fn backing_works_with_elastic_scaling_mvp() { ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate_b_1); // Make candidate b2 a child of b1. - let mut candidate_b_2 = TestCandidateBuilder { + let candidate_b_2 = TestCandidateBuilder { para_id: chain_b, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(3), @@ -2121,7 +2146,6 @@ fn backing_works_with_elastic_scaling_mvp() { ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate_b_2); let backed_a = back_candidate( candidate_a.clone(), @@ -2184,10 +2208,7 @@ fn backing_works_with_elastic_scaling_mvp() { } }; - let ProcessedCandidates { - core_indices: occupied_cores, - candidate_receipt_with_backing_validator_indices, - } = ParaInclusion::process_candidates( + let candidate_receipt_with_backing_validator_indices = ParaInclusion::process_candidates( &allowed_relay_parents, &backed_candidates, &group_validators, @@ -2195,16 +2216,6 @@ fn backing_works_with_elastic_scaling_mvp() { ) .expect("candidates scheduled, in order, and backed"); - // Both b candidates will be backed. - assert_eq!( - occupied_cores, - vec![ - (CoreIndex::from(0), chain_a), - (CoreIndex::from(1), chain_b), - (CoreIndex::from(2), chain_b), - ] - ); - // Transform the votes into the setup we expect let mut expected = std::collections::HashMap::< CandidateHash, @@ -2359,7 +2370,7 @@ fn can_include_candidate_with_ok_code_upgrade() { let allowed_relay_parents = default_allowed_relay_parent_tracker(); let chain_a_assignment = (chain_a, CoreIndex::from(0)); - let mut candidate_a = TestCandidateBuilder { + let candidate_a = TestCandidateBuilder { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(1), @@ -2369,7 +2380,6 @@ fn can_include_candidate_with_ok_code_upgrade() { ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate_a); let backed_a = back_candidate( candidate_a.clone(), @@ -2381,18 +2391,15 @@ fn can_include_candidate_with_ok_code_upgrade() { None, ); - let ProcessedCandidates { core_indices: occupied_cores, .. } = - ParaInclusion::process_candidates( - &allowed_relay_parents, - &vec![(chain_a_assignment.0, vec![(backed_a, chain_a_assignment.1)])] - .into_iter() - .collect::>(), - group_validators, - false, - ) - .expect("candidates scheduled, in order, and backed"); - - assert_eq!(occupied_cores, vec![(CoreIndex::from(0), chain_a)]); + let _ = ParaInclusion::process_candidates( + &allowed_relay_parents, + &vec![(chain_a_assignment.0, vec![(backed_a, chain_a_assignment.1)])] + .into_iter() + .collect::>(), + group_validators, + false, + ) + .expect("candidates scheduled, in order, and backed"); let backers = { let num_backers = effective_minimum_backing_votes( @@ -2498,18 +2505,21 @@ fn check_allowed_relay_parents() { allowed_relay_parents.update( relay_parent_a.1, Hash::zero(), + Default::default(), relay_parent_a.0, max_ancestry_len, ); allowed_relay_parents.update( relay_parent_b.1, Hash::zero(), + Default::default(), relay_parent_b.0, max_ancestry_len, ); allowed_relay_parents.update( relay_parent_c.1, Hash::zero(), + Default::default(), relay_parent_c.0, max_ancestry_len, ); @@ -2519,7 +2529,7 @@ fn check_allowed_relay_parents() { let chain_b_assignment = (chain_b, CoreIndex::from(1)); let thread_a_assignment = (thread_a, CoreIndex::from(2)); - let mut candidate_a = TestCandidateBuilder { + let candidate_a = TestCandidateBuilder { para_id: chain_a, relay_parent: relay_parent_a.1, pov_hash: Hash::repeat_byte(1), @@ -2532,10 +2542,9 @@ fn check_allowed_relay_parents() { ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate_a); let signing_context_a = SigningContext { parent_hash: relay_parent_a.1, session_index: 5 }; - let mut candidate_b = TestCandidateBuilder { + let candidate_b = TestCandidateBuilder { para_id: chain_b, relay_parent: relay_parent_b.1, pov_hash: Hash::repeat_byte(2), @@ -2548,10 +2557,9 @@ fn check_allowed_relay_parents() { ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate_b); let signing_context_b = SigningContext { parent_hash: relay_parent_b.1, session_index: 5 }; - let mut candidate_c = TestCandidateBuilder { + let candidate_c = TestCandidateBuilder { para_id: thread_a, relay_parent: relay_parent_c.1, pov_hash: Hash::repeat_byte(3), @@ -2564,7 +2572,6 @@ fn check_allowed_relay_parents() { ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::Two, &mut candidate_c); let signing_context_c = SigningContext { parent_hash: relay_parent_c.1, session_index: 5 }; let backed_a = back_candidate( @@ -2786,7 +2793,7 @@ fn para_upgrade_delay_scheduled_from_inclusion() { let allowed_relay_parents = default_allowed_relay_parent_tracker(); let chain_a_assignment = (chain_a, CoreIndex::from(0)); - let mut candidate_a = TestCandidateBuilder { + let candidate_a = TestCandidateBuilder { para_id: chain_a, relay_parent: System::parent_hash(), pov_hash: Hash::repeat_byte(1), @@ -2796,7 +2803,6 @@ fn para_upgrade_delay_scheduled_from_inclusion() { ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate_a); let backed_a = back_candidate( candidate_a.clone(), @@ -2808,7 +2814,7 @@ fn para_upgrade_delay_scheduled_from_inclusion() { None, ); - let ProcessedCandidates { core_indices: occupied_cores, .. } = + let _ = ParaInclusion::process_candidates( &allowed_relay_parents, &vec![(chain_a_assignment.0, vec![(backed_a, chain_a_assignment.1)])] @@ -2819,8 +2825,6 @@ fn para_upgrade_delay_scheduled_from_inclusion() { ) .expect("candidates scheduled, in order, and backed"); - assert_eq!(occupied_cores, vec![(CoreIndex::from(0), chain_a)]); - // Run a couple of blocks before the inclusion. run_to_block(7, |_| None); diff --git a/polkadot/runtime/parachains/src/initializer.rs b/polkadot/runtime/parachains/src/initializer.rs index 340f727097b5..6ee245fb5230 100644 --- a/polkadot/runtime/parachains/src/initializer.rs +++ b/polkadot/runtime/parachains/src/initializer.rs @@ -87,10 +87,10 @@ impl> Default for SessionChangeNotification, - queued: Vec, - session_index: SessionIndex, +pub(crate) struct BufferedSessionChange { + pub validators: Vec, + pub queued: Vec, + pub session_index: SessionIndex, } pub trait WeightInfo { @@ -149,7 +149,7 @@ pub mod pallet { #[pallet::storage] pub(super) type HasInitialized = StorageValue<_, ()>; - /// Buffered session changes along with the block number at which they should be applied. + /// Buffered session changes. /// /// Typically this will be empty or one element long. Apart from that this item never hits /// the storage. @@ -157,7 +157,7 @@ pub mod pallet { /// However this is a `Vec` regardless to handle various edge cases that may occur at runtime /// upgrade boundaries or if governance intervenes. #[pallet::storage] - pub(super) type BufferedSessionChanges = + pub(crate) type BufferedSessionChanges = StorageValue<_, Vec, ValueQuery>; #[pallet::hooks] @@ -254,9 +254,6 @@ impl Pallet { buf }; - // inform about upcoming new session - scheduler::Pallet::::pre_new_session(); - let configuration::SessionChangeOutcome { prev_config, new_config } = configuration::Pallet::::initializer_on_new_session(&session_index); let new_config = new_config.unwrap_or_else(|| prev_config.clone()); @@ -328,6 +325,11 @@ impl Pallet { { Self::on_new_session(changed, session_index, validators, queued) } + + /// Return whether at the end of this block a new session will be initialized. + pub(crate) fn upcoming_session_change() -> bool { + !BufferedSessionChanges::::get().is_empty() + } } impl sp_runtime::BoundToRuntimeAppPublic for Pallet { diff --git a/polkadot/runtime/parachains/src/lib.rs b/polkadot/runtime/parachains/src/lib.rs index f2995d770e71..f1162e1cc215 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 45576668f6d6..c23918708b21 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, @@ -91,12 +90,21 @@ frame_support::construct_runtime!( } ); -impl frame_system::offchain::SendTransactionTypes for Test +impl frame_system::offchain::CreateTransactionBase for Test where RuntimeCall: From, { type Extrinsic = UncheckedExtrinsic; - type OverarchingCall = RuntimeCall; + type RuntimeCall = RuntimeCall; +} + +impl frame_system::offchain::CreateInherent for Test +where + RuntimeCall: From, +{ + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { + UncheckedExtrinsic::new_bare(call) + } } parameter_types! { @@ -401,11 +409,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; } @@ -450,8 +458,16 @@ impl SendXcm for DummyXcmSender { } } +pub struct InclusionWeightInfo; + +impl crate::inclusion::WeightInfo for InclusionWeightInfo { + fn enact_candidate(_u: u32, _h: u32, _c: u32) -> Weight { + Weight::from_parts(1024 * 1024, 0) + } +} + impl crate::inclusion::Config for Test { - type WeightInfo = (); + type WeightInfo = InclusionWeightInfo; type RuntimeEvent = RuntimeEvent; type DisputesHandler = Disputes; type RewardValidators = TestRewardValidators; @@ -504,9 +520,6 @@ pub mod mock_assigner { #[pallet::storage] pub(super) type MockAssignmentQueue = StorageValue<_, VecDeque, ValueQuery>; - - #[pallet::storage] - pub(super) type MockCoreCount = StorageValue<_, u32, OptionQuery>; } impl Pallet { @@ -515,12 +528,6 @@ pub mod mock_assigner { pub fn add_test_assignment(assignment: Assignment) { MockAssignmentQueue::::mutate(|queue| queue.push_back(assignment)); } - - // Allows for customized core count in scheduler tests, rather than a core count - // derived from on-demand config + parachain count. - pub fn set_core_count(count: u32) { - MockCoreCount::::set(Some(count)); - } } impl AssignmentProvider for Pallet { @@ -538,20 +545,18 @@ pub mod mock_assigner { } // We don't care about core affinity in the test assigner - fn report_processed(_assignment: Assignment) {} + fn report_processed(_: Assignment) {} - // The results of this are tested in assigner_on_demand tests. No need to represent it - // in the mock assigner. - fn push_back_assignment(_assignment: Assignment) {} + fn push_back_assignment(assignment: Assignment) { + Self::add_test_assignment(assignment); + } #[cfg(any(feature = "runtime-benchmarks", test))] fn get_mock_assignment(_: CoreIndex, para_id: ParaId) -> Assignment { Assignment::Bulk(para_id) } - fn session_core_count() -> u32 { - MockCoreCount::::get().unwrap_or(5) - } + fn assignment_duplicated(_: &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 b0ebfe77a966..d494a77a5c4d 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 03f63d7333b6..6cc25b20afb8 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 98% rename from polkadot/runtime/parachains/src/assigner_on_demand/mod.rs rename to polkadot/runtime/parachains/src/on_demand/mod.rs index f045e957a690..66400eb00fd9 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::*; @@ -317,6 +317,11 @@ where Some(assignment) } + /// Report that an assignment was duplicated by the scheduler. + pub fn assignment_duplicated(para_id: ParaId, core_index: CoreIndex) { + Pallet::::increase_affinity(para_id, core_index); + } + /// Report that the `para_id` & `core_index` combination was processed. /// /// This should be called once it is clear that the assignment won't get pushed back anymore. diff --git a/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs b/polkadot/runtime/parachains/src/on_demand/tests.rs similarity index 71% rename from polkadot/runtime/parachains/src/assigner_on_demand/tests.rs rename to polkadot/runtime/parachains/src/on_demand/tests.rs index 0bad4346cfd9..7da16942c7ad 100644 --- a/polkadot/runtime/parachains/src/assigner_on_demand/tests.rs +++ b/polkadot/runtime/parachains/src/on_demand/tests.rs @@ -17,20 +17,19 @@ 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; use core::cmp::{Ord, Ordering}; use frame_support::{assert_noop, assert_ok}; use pallet_balances::Error as BalancesError; @@ -83,10 +82,10 @@ 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); + Scheduler::advance_claim_queue(&Default::default()); } } @@ -99,7 +98,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 +324,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 +341,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 +351,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 +384,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 +414,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 +424,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 +448,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 +480,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 +488,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 +552,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 +579,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 +663,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 +675,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 +706,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 +739,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 +749,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 +763,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 +772,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 +783,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 +800,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 96367b971fed..c87e7abaf860 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 630b86132ab8..7bf8b833ed91 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 000000000000..ab007692e78d --- /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 3f0b8659b159..e0f244dbd863 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; @@ -615,7 +615,7 @@ pub mod pallet { frame_system::Config + configuration::Config + shared::Config - + frame_system::offchain::SendTransactionTypes> + + frame_system::offchain::CreateInherent> { type RuntimeEvent: From + IsType<::RuntimeEvent>; @@ -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. @@ -1937,14 +1956,12 @@ impl Pallet { inclusion_block_number: BlockNumberFor, cfg: &configuration::HostConfiguration>, upgrade_strategy: UpgradeStrategy, - ) -> Weight { - let mut weight = T::DbWeight::get().reads(1); - + ) { // Should be prevented by checks in `schedule_code_upgrade_external` let new_code_len = new_code.0.len(); if new_code_len < MIN_CODE_SIZE as usize || new_code_len > cfg.max_code_size as usize { log::warn!(target: LOG_TARGET, "attempted to schedule an upgrade with invalid new validation code",); - return weight + return } // Enacting this should be prevented by the `can_upgrade_validation_code` @@ -1958,7 +1975,7 @@ impl Pallet { // NOTE: we cannot set `UpgradeGoAheadSignal` signal here since this will be reset by // the following call `note_new_head` log::warn!(target: LOG_TARGET, "ended up scheduling an upgrade while one is pending",); - return weight + return } let code_hash = new_code.hash(); @@ -1967,7 +1984,6 @@ impl Pallet { // process right away. // // We do not want to allow this since it will mess with the code reference counting. - weight += T::DbWeight::get().reads(1); if CurrentCodeHash::::get(&id) == Some(code_hash) { // NOTE: we cannot set `UpgradeGoAheadSignal` signal here since this will be reset by // the following call `note_new_head` @@ -1975,15 +1991,13 @@ impl Pallet { target: LOG_TARGET, "para tried to upgrade to the same code. Abort the upgrade", ); - return weight + return } // This is the start of the upgrade process. Prevent any further attempts at upgrading. - weight += T::DbWeight::get().writes(2); FutureCodeHash::::insert(&id, &code_hash); UpgradeRestrictionSignal::::insert(&id, UpgradeRestriction::Present); - weight += T::DbWeight::get().reads_writes(1, 1); let next_possible_upgrade_at = inclusion_block_number + cfg.validation_upgrade_cooldown; UpgradeCooldowns::::mutate(|upgrade_cooldowns| { let insert_idx = upgrade_cooldowns @@ -1992,14 +2006,12 @@ impl Pallet { upgrade_cooldowns.insert(insert_idx, (id, next_possible_upgrade_at)); }); - weight += Self::kick_off_pvf_check( + Self::kick_off_pvf_check( PvfCheckCause::Upgrade { id, included_at: inclusion_block_number, upgrade_strategy }, code_hash, new_code, cfg, ); - - weight } /// Makes sure that the given code hash has passed pre-checking. @@ -2089,11 +2101,11 @@ impl Pallet { id: ParaId, new_head: HeadData, execution_context: BlockNumberFor, - ) -> Weight { + ) { Heads::::insert(&id, &new_head); MostRecentContext::::insert(&id, execution_context); - let weight = if let Some(expected_at) = FutureCodeUpgrades::::get(&id) { + if let Some(expected_at) = FutureCodeUpgrades::::get(&id) { if expected_at <= execution_context { FutureCodeUpgrades::::remove(&id); UpgradeGoAheadSignal::::remove(&id); @@ -2103,14 +2115,10 @@ impl Pallet { new_code_hash } else { log::error!(target: LOG_TARGET, "Missing future code hash for {:?}", &id); - return T::DbWeight::get().reads_writes(3, 1 + 3) + return }; - let weight = Self::set_current_code(id, new_code_hash, expected_at); - - weight + T::DbWeight::get().reads_writes(3, 3) - } else { - T::DbWeight::get().reads_writes(1, 1 + 0) + Self::set_current_code(id, new_code_hash, expected_at); } } else { // This means there is no upgrade scheduled. @@ -2118,10 +2126,9 @@ impl Pallet { // In case the upgrade was aborted by the relay-chain we should reset // the `Abort` signal. UpgradeGoAheadSignal::::remove(&id); - T::DbWeight::get().reads_writes(1, 2) }; - weight.saturating_add(T::OnNewHead::on_new_head(id, &new_head)) + T::OnNewHead::on_new_head(id, &new_head); } /// Set the current code for the given parachain. @@ -2170,9 +2177,8 @@ impl Pallet { ) { use frame_system::offchain::SubmitTransaction; - if let Err(e) = SubmitTransaction::>::submit_unsigned_transaction( - Call::include_pvf_check_statement { stmt, signature }.into(), - ) { + let xt = T::create_inherent(Call::include_pvf_check_statement { stmt, signature }.into()); + if let Err(e) = SubmitTransaction::>::submit_transaction(xt) { log::error!(target: LOG_TARGET, "Error submitting pvf check statement: {:?}", e,); } } diff --git a/polkadot/runtime/parachains/src/paras/tests.rs b/polkadot/runtime/parachains/src/paras/tests.rs index 732b75417387..6e4f99aa3d84 100644 --- a/polkadot/runtime/parachains/src/paras/tests.rs +++ b/polkadot/runtime/parachains/src/paras/tests.rs @@ -16,7 +16,7 @@ use super::*; use frame_support::{assert_err, assert_ok, assert_storage_noop}; -use polkadot_primitives::{vstaging::SchedulerParams, BlockNumber, PARACHAIN_KEY_TYPE_ID}; +use polkadot_primitives::{BlockNumber, SchedulerParams, PARACHAIN_KEY_TYPE_ID}; use polkadot_primitives_test_helpers::{dummy_head_data, dummy_validation_code, validator_pubkeys}; use sc_keystore::LocalKeystore; use sp_keyring::Sr25519Keyring; diff --git a/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs b/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs index c5284ba1dd1f..485e7211c1d2 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/benchmarking.rs @@ -17,19 +17,34 @@ use super::*; use crate::{inclusion, ParaId}; use alloc::collections::btree_map::BTreeMap; -use core::cmp::min; +use core::cmp::{max, min}; use frame_benchmarking::{benchmarks, impl_benchmark_test_suite}; use frame_system::RawOrigin; -use polkadot_primitives::v7::GroupIndex; +use polkadot_primitives::v8::GroupIndex; use crate::builder::BenchBuilder; benchmarks! { + enter_empty { + let scenario = BenchBuilder::::new() + .build(); + + let mut benchmark = scenario.data.clone(); + + benchmark.bitfields.clear(); + benchmark.backed_candidates.clear(); + benchmark.disputes.clear(); + }: enter(RawOrigin::None, benchmark) + verify { + // Assert that the block was not discarded + assert!(Included::::get().is_some()); + } // Variant over `v`, the number of dispute statements in a dispute statement set. This gives the // weight of a single dispute statement set. enter_variable_disputes { - let v in 10..BenchBuilder::::fallback_max_validators(); + // The number of statements needs to be at least a third of the validator set size. + let v in 400..BenchBuilder::::fallback_max_validators(); let scenario = BenchBuilder::::new() .set_dispute_sessions(&[2]) @@ -92,18 +107,8 @@ benchmarks! { // Variant over `v`, the amount of validity votes for a backed candidate. This gives the weight // of a single backed candidate. enter_backed_candidates_variable { - // NOTE: the starting value must be over half of the max validators per group so the backed - // candidate is not rejected. Also, we cannot have more validity votes than validators in - // the group. - - // Do not use this range for Rococo because it only has 1 validator per backing group, - // which causes issues when trying to create slopes with the benchmarking analysis. Instead - // use v = 1 for running Rococo benchmarks - let v in (BenchBuilder::::fallback_min_validity_votes()) - ..(BenchBuilder::::fallback_max_validators()); - - // Comment in for running rococo benchmarks - // let v = 1; + let v in (BenchBuilder::::fallback_min_backing_votes()) + .. max(BenchBuilder::::fallback_min_backing_votes() + 1, BenchBuilder::::fallback_max_validators_per_core()); let cores_with_backed: BTreeMap<_, _> = vec![(0, v)] // The backed candidate will have `v` validity votes. @@ -119,7 +124,6 @@ benchmarks! { // There is 1 backed, assert_eq!(benchmark.backed_candidates.len(), 1); // with `v` validity votes. - // let votes = v as usize; let votes = min(scheduler::Pallet::::group_validators(GroupIndex::from(0)).unwrap().len(), v as usize); assert_eq!(benchmark.backed_candidates.get(0).unwrap().validity_votes().len(), votes); @@ -141,8 +145,8 @@ benchmarks! { // Traverse candidates and assert descriptors are as expected for (para_id, backing_validators) in vote.backing_validators_per_candidate.iter().enumerate() { let descriptor = backing_validators.0.descriptor(); - assert_eq!(ParaId::from(para_id), descriptor.para_id); - assert_eq!(header.hash(), descriptor.relay_parent); + assert_eq!(ParaId::from(para_id), descriptor.para_id()); + assert_eq!(header.hash(), descriptor.relay_parent()); assert_eq!(backing_validators.1.len(), votes); } @@ -157,7 +161,7 @@ benchmarks! { let v = crate::configuration::ActiveConfig::::get().max_code_size; let cores_with_backed: BTreeMap<_, _> - = vec![(0, BenchBuilder::::fallback_min_validity_votes())] + = vec![(0, BenchBuilder::::fallback_min_backing_votes())] .into_iter() .collect(); @@ -168,8 +172,10 @@ benchmarks! { let mut benchmark = scenario.data.clone(); - // let votes = BenchBuilder::::fallback_min_validity_votes() as usize; - let votes = min(scheduler::Pallet::::group_validators(GroupIndex::from(0)).unwrap().len(), BenchBuilder::::fallback_min_validity_votes() as usize); + let votes = min( + scheduler::Pallet::::group_validators(GroupIndex::from(0)).unwrap().len(), + BenchBuilder::::fallback_min_backing_votes() as usize + ); // There is 1 backed assert_eq!(benchmark.backed_candidates.len(), 1); @@ -198,8 +204,8 @@ benchmarks! { for (para_id, backing_validators) in vote.backing_validators_per_candidate.iter().enumerate() { let descriptor = backing_validators.0.descriptor(); - assert_eq!(ParaId::from(para_id), descriptor.para_id); - assert_eq!(header.hash(), descriptor.relay_parent); + assert_eq!(ParaId::from(para_id), descriptor.para_id()); + assert_eq!(header.hash(), descriptor.relay_parent()); assert_eq!( backing_validators.1.len(), votes, diff --git a/polkadot/runtime/parachains/src/paras_inherent/mod.rs b/polkadot/runtime/parachains/src/paras_inherent/mod.rs index fe4eef16f022..4c1394fd1347 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/mod.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/mod.rs @@ -27,8 +27,7 @@ use crate::{ inclusion::{self, CandidateCheckContext}, initializer, metrics::METRICS, - paras, - scheduler::{self, FreedReason}, + paras, scheduler, shared::{self, AllowedRelayParentsTracker}, ParaId, }; @@ -38,6 +37,7 @@ use alloc::{ vec::Vec, }; use bitvec::prelude::BitVec; +use core::result::Result; use frame_support::{ defensive, dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo}, @@ -45,15 +45,21 @@ use frame_support::{ pallet_prelude::*, traits::Randomness, }; + use frame_system::pallet_prelude::*; use pallet_babe::{self, ParentBlockRandomness}; use polkadot_primitives::{ - effective_minimum_backing_votes, node_features::FeatureIndex, BackedCandidate, CandidateHash, - CandidateReceipt, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, CoreIndex, - DisputeStatementSet, HeadData, InherentData as ParachainsInherentData, - MultiDisputeStatementSet, ScrapedOnChainVotes, SessionIndex, SignedAvailabilityBitfields, - SigningContext, UncheckedSignedAvailabilityBitfield, UncheckedSignedAvailabilityBitfields, - ValidatorId, ValidatorIndex, ValidityAttestation, PARACHAINS_INHERENT_IDENTIFIER, + effective_minimum_backing_votes, + node_features::FeatureIndex, + vstaging::{ + BackedCandidate, CandidateDescriptorVersion, CandidateReceiptV2 as CandidateReceipt, + InherentData as ParachainsInherentData, ScrapedOnChainVotes, + }, + CandidateHash, CheckedDisputeStatementSet, CheckedMultiDisputeStatementSet, CoreIndex, + DisputeStatementSet, HeadData, MultiDisputeStatementSet, SessionIndex, + SignedAvailabilityBitfields, SigningContext, UncheckedSignedAvailabilityBitfield, + UncheckedSignedAvailabilityBitfields, ValidatorId, ValidatorIndex, ValidityAttestation, + PARACHAINS_INHERENT_IDENTIFIER, }; use rand::{seq::SliceRandom, SeedableRng}; use scale_info::TypeInfo; @@ -99,15 +105,6 @@ impl DisputedBitfield { } } -/// The context in which the inherent data is checked or processed. -#[derive(PartialEq)] -pub enum ProcessInherentDataContext { - /// Enables filtering/limits weight of inherent up to maximum block weight. - /// Invariant: InherentWeight <= BlockWeight. - ProvideInherent, - /// Checks the InherentWeight invariant. - Enter, -} pub use pallet::*; #[frame_support::pallet] @@ -134,11 +131,9 @@ pub mod pallet { /// The hash of the submitted parent header doesn't correspond to the saved block hash of /// the parent. InvalidParentHeader, - /// The data given to the inherent will result in an overweight block. - InherentOverweight, - /// A candidate was filtered during inherent execution. This should have only been done + /// Inherent data was filtered during execution. This should have only been done /// during creation. - CandidatesFilteredDuringExecution, + InherentDataFilteredDuringExecution, /// Too many candidates supplied. UnscheduledCandidate, } @@ -247,9 +242,12 @@ pub mod pallet { ensure!(!Included::::exists(), Error::::TooManyInclusionInherents); Included::::set(Some(())); + let initial_data = data.clone(); - Self::process_inherent_data(data, ProcessInherentDataContext::Enter) - .map(|(_processed, post_info)| post_info) + Self::process_inherent_data(data).and_then(|(processed, post_info)| { + ensure!(initial_data == processed, Error::::InherentDataFilteredDuringExecution); + Ok(post_info) + }) } } } @@ -267,10 +265,7 @@ impl Pallet { return None }, }; - match Self::process_inherent_data( - parachains_inherent_data, - ProcessInherentDataContext::ProvideInherent, - ) { + match Self::process_inherent_data(parachains_inherent_data) { Ok((processed, _)) => Some(processed), Err(err) => { log::warn!(target: LOG_TARGET, "Processing inherent data failed: {:?}", err); @@ -284,21 +279,12 @@ impl Pallet { /// The given inherent data is processed and state is altered accordingly. If any data could /// not be applied (inconsistencies, weight limit, ...) it is removed. /// - /// When called from `create_inherent` the `context` must be set to - /// `ProcessInherentDataContext::ProvideInherent` so it guarantees the invariant that inherent - /// is not overweight. - /// It is **mandatory** that calls from `enter` set `context` to - /// `ProcessInherentDataContext::Enter` to ensure the weight invariant is checked. - /// /// Returns: Result containing processed inherent data and weight, the processed inherent would /// consume. fn process_inherent_data( data: ParachainsInherentData>, - context: ProcessInherentDataContext, - ) -> core::result::Result< - (ParachainsInherentData>, PostDispatchInfo), - DispatchErrorWithPostInfo, - > { + ) -> Result<(ParachainsInherentData>, PostDispatchInfo), DispatchErrorWithPostInfo> + { #[cfg(feature = "runtime-metrics")] sp_io::init_tracing(); @@ -336,26 +322,31 @@ impl Pallet { tracker.update( parent_hash, parent_storage_root, + scheduler::ClaimQueue::::get() + .into_iter() + .map(|(core_index, paras)| { + (core_index, paras.into_iter().map(|e| e.para_id()).collect()) + }) + .collect(), parent_number, config.async_backing_params.allowed_ancestry_len, ); }); } - let allowed_relay_parents = shared::AllowedRelayParents::::get(); let candidates_weight = backed_candidates_weight::(&backed_candidates); let bitfields_weight = signed_bitfields_weight::(&bitfields); let disputes_weight = multi_dispute_statement_sets_weight::(&disputes); - // Weight before filtering/sanitization - let all_weight_before = candidates_weight + bitfields_weight + disputes_weight; + // Weight before filtering/sanitization except for enacting the candidates + let weight_before_filtering = candidates_weight + bitfields_weight + disputes_weight; - METRICS.on_before_filter(all_weight_before.ref_time()); - log::debug!(target: LOG_TARGET, "Size before filter: {}, candidates + bitfields: {}, disputes: {}", all_weight_before.proof_size(), candidates_weight.proof_size() + bitfields_weight.proof_size(), disputes_weight.proof_size()); - log::debug!(target: LOG_TARGET, "Time weight before filter: {}, candidates + bitfields: {}, disputes: {}", all_weight_before.ref_time(), candidates_weight.ref_time() + bitfields_weight.ref_time(), disputes_weight.ref_time()); + METRICS.on_before_filter(weight_before_filtering.ref_time()); + log::debug!(target: LOG_TARGET, "Size before filter: {}, candidates + bitfields: {}, disputes: {}", weight_before_filtering.proof_size(), candidates_weight.proof_size() + bitfields_weight.proof_size(), disputes_weight.proof_size()); + log::debug!(target: LOG_TARGET, "Time weight before filter: {}, candidates + bitfields: {}, disputes: {}", weight_before_filtering.ref_time(), candidates_weight.ref_time() + bitfields_weight.ref_time(), disputes_weight.ref_time()); let current_session = shared::CurrentSessionIndex::::get(); - let expected_bits = scheduler::AvailabilityCores::::get().len(); + let expected_bits = scheduler::Pallet::::num_availability_cores(); let validator_public = shared::ActiveValidatorKeys::::get(); // We are assuming (incorrectly) to have all the weight (for the mandatory class or even @@ -400,7 +391,7 @@ impl Pallet { T::DisputesHandler::filter_dispute_data(set, post_conclusion_acceptance_period) }; - // Limit the disputes first, since the following statements depend on the votes include + // Limit the disputes first, since the following statements depend on the votes included // here. let (checked_disputes_sets, checked_disputes_sets_consumed_weight) = limit_and_sanitize_disputes::( @@ -409,7 +400,7 @@ impl Pallet { max_block_weight, ); - let all_weight_after = if context == ProcessInherentDataContext::ProvideInherent { + let mut all_weight_after = { // Assure the maximum block weight is adhered, by limiting bitfields and backed // candidates. Dispute statement sets were already limited before. let non_disputes_weight = apply_weight_limit::( @@ -424,11 +415,11 @@ impl Pallet { METRICS.on_after_filter(all_weight_after.ref_time()); log::debug!( - target: LOG_TARGET, - "[process_inherent_data] after filter: bitfields.len(): {}, backed_candidates.len(): {}, checked_disputes_sets.len() {}", - bitfields.len(), - backed_candidates.len(), - checked_disputes_sets.len() + target: LOG_TARGET, + "[process_inherent_data] after filter: bitfields.len(): {}, backed_candidates.len(): {}, checked_disputes_sets.len() {}", + bitfields.len(), + backed_candidates.len(), + checked_disputes_sets.len() ); log::debug!(target: LOG_TARGET, "Size after filter: {}, candidates + bitfields: {}, disputes: {}", all_weight_after.proof_size(), non_disputes_weight.proof_size(), checked_disputes_sets_consumed_weight.proof_size()); log::debug!(target: LOG_TARGET, "Time weight after filter: {}, candidates + bitfields: {}, disputes: {}", all_weight_after.ref_time(), non_disputes_weight.ref_time(), checked_disputes_sets_consumed_weight.ref_time()); @@ -437,20 +428,6 @@ impl Pallet { log::warn!(target: LOG_TARGET, "Post weight limiting weight is still too large, time: {}, size: {}", all_weight_after.ref_time(), all_weight_after.proof_size()); } all_weight_after - } else { - // This check is performed in the context of block execution. Ensures inherent weight - // invariants guaranteed by `create_inherent_data` for block authorship. - if all_weight_before.any_gt(max_block_weight) { - log::error!( - "Overweight para inherent data reached the runtime {:?}: {} > {}", - parent_hash, - all_weight_before, - max_block_weight - ); - } - - ensure!(all_weight_before.all_lte(max_block_weight), Error::::InherentOverweight); - all_weight_before }; // Note that `process_checked_multi_dispute_data` will iterate and import each @@ -529,11 +506,32 @@ impl Pallet { // Process new availability bitfields, yielding any availability cores whose // work has now concluded. - let freed_concluded = + let (enact_weight, freed_concluded) = inclusion::Pallet::::update_pending_availability_and_get_freed_cores( &validator_public[..], bitfields.clone(), ); + all_weight_after.saturating_accrue(enact_weight); + log::debug!( + target: LOG_TARGET, + "Enacting weight: {}, all weight: {}", + enact_weight.ref_time(), + all_weight_after.ref_time(), + ); + + // It's possible that that after the enacting the candidates, the total weight + // goes over the limit, however, we can't do anything about it at this point. + // By using the `Mandatory` weight, we ensure the block is still accepted, + // but no other (user) transactions can be included. + if all_weight_after.any_gt(max_block_weight) { + log::warn!( + target: LOG_TARGET, + "Overweight para inherent data after enacting the candidates {:?}: {} > {}", + parent_hash, + all_weight_after, + max_block_weight, + ); + } // Inform the disputes module of all included candidates. for (_, candidate_hash) in &freed_concluded { @@ -553,68 +551,9 @@ impl Pallet { log::debug!(target: LOG_TARGET, "Evicted timed out cores: {:?}", freed_timeout); } - // We'll schedule paras again, given freed cores, and reasons for freeing. - let freed = freed_concluded - .into_iter() - .map(|(c, _hash)| (c, FreedReason::Concluded)) - .chain(freed_disputed.into_iter().map(|core| (core, FreedReason::Concluded))) - .chain(freed_timeout.into_iter().map(|c| (c, FreedReason::TimedOut))) - .collect::>(); - scheduler::Pallet::::free_cores_and_fill_claim_queue(freed, now); - - METRICS.on_candidates_processed_total(backed_candidates.len() as u64); - - let core_index_enabled = configuration::ActiveConfig::::get() - .node_features - .get(FeatureIndex::ElasticScalingMVP as usize) - .map(|b| *b) - .unwrap_or(false); - - let mut eligible: BTreeMap> = BTreeMap::new(); - let mut total_eligible_cores = 0; - - for (core_idx, para_id) in scheduler::Pallet::::eligible_paras() { - total_eligible_cores += 1; - log::trace!(target: LOG_TARGET, "Found eligible para {:?} on core {:?}", para_id, core_idx); - eligible.entry(para_id).or_default().insert(core_idx); - } - - let initial_candidate_count = backed_candidates.len(); - let backed_candidates_with_core = sanitize_backed_candidates::( - backed_candidates, - &allowed_relay_parents, - concluded_invalid_hashes, - eligible, - core_index_enabled, - ); - let count = count_backed_candidates(&backed_candidates_with_core); - - ensure!(count <= total_eligible_cores, Error::::UnscheduledCandidate); - - METRICS.on_candidates_sanitized(count as u64); - - // In `Enter` context (invoked during execution) no more candidates should be filtered, - // because they have already been filtered during `ProvideInherent` context. Abort in such - // cases. - if context == ProcessInherentDataContext::Enter { - ensure!( - initial_candidate_count == count, - Error::::CandidatesFilteredDuringExecution - ); - } - - // Process backed candidates according to scheduled cores. - let inclusion::ProcessedCandidates::< as HeaderT>::Hash> { - core_indices: occupied, - candidate_receipt_with_backing_validator_indices, - } = inclusion::Pallet::::process_candidates( - &allowed_relay_parents, - &backed_candidates_with_core, - scheduler::Pallet::::group_validators, - core_index_enabled, - )?; - // Note which of the scheduled cores were actually occupied by a backed candidate. - scheduler::Pallet::::occupied(occupied.into_iter().map(|e| (e.0, e.1)).collect()); + // Back candidates. + let (candidate_receipt_with_backing_validator_indices, backed_candidates_with_core) = + Self::back_candidates(concluded_invalid_hashes, backed_candidates)?; set_scrapable_on_chain_backings::( current_session, @@ -628,6 +567,7 @@ impl Pallet { let bitfields = bitfields.into_iter().map(|v| v.into_unchecked()).collect(); + let count = backed_candidates_with_core.len(); let processed = ParachainsInherentData { bitfields, backed_candidates: backed_candidates_with_core.into_iter().fold( @@ -642,6 +582,104 @@ impl Pallet { }; Ok((processed, Some(all_weight_after).into())) } + + fn back_candidates( + concluded_invalid_hashes: BTreeSet, + backed_candidates: Vec>, + ) -> Result< + ( + Vec<(CandidateReceipt, Vec<(ValidatorIndex, ValidityAttestation)>)>, + BTreeMap, CoreIndex)>>, + ), + DispatchErrorWithPostInfo, + > { + let allowed_relay_parents = shared::AllowedRelayParents::::get(); + let upcoming_new_session = initializer::Pallet::::upcoming_session_change(); + + METRICS.on_candidates_processed_total(backed_candidates.len() as u64); + + if !upcoming_new_session { + let occupied_cores = + inclusion::Pallet::::get_occupied_cores().map(|(core, _)| core).collect(); + + let mut eligible: BTreeMap> = BTreeMap::new(); + let mut total_eligible_cores = 0; + + for (core_idx, para_id) in Self::eligible_paras(&occupied_cores) { + total_eligible_cores += 1; + log::trace!(target: LOG_TARGET, "Found eligible para {:?} on core {:?}", para_id, core_idx); + eligible.entry(para_id).or_default().insert(core_idx); + } + + let node_features = configuration::ActiveConfig::::get().node_features; + let core_index_enabled = node_features + .get(FeatureIndex::ElasticScalingMVP as usize) + .map(|b| *b) + .unwrap_or(false); + + let allow_v2_receipts = node_features + .get(FeatureIndex::CandidateReceiptV2 as usize) + .map(|b| *b) + .unwrap_or(false); + + let backed_candidates_with_core = sanitize_backed_candidates::( + backed_candidates, + &allowed_relay_parents, + concluded_invalid_hashes, + eligible, + core_index_enabled, + allow_v2_receipts, + ); + let count = count_backed_candidates(&backed_candidates_with_core); + + ensure!(count <= total_eligible_cores, Error::::UnscheduledCandidate); + + METRICS.on_candidates_sanitized(count as u64); + + // Process backed candidates according to scheduled cores. + let candidate_receipt_with_backing_validator_indices = + inclusion::Pallet::::process_candidates( + &allowed_relay_parents, + &backed_candidates_with_core, + scheduler::Pallet::::group_validators, + core_index_enabled, + )?; + + // We need to advance the claim queue on all cores, except for the ones that did not + // get freed in this block. The ones that did not get freed also cannot be newly + // occupied. + scheduler::Pallet::::advance_claim_queue(&occupied_cores); + + Ok((candidate_receipt_with_backing_validator_indices, backed_candidates_with_core)) + } else { + log::debug!( + target: LOG_TARGET, + "Upcoming session change, not backing any new candidates." + ); + // If we'll initialize a new session at the end of the block, we don't want to + // advance the claim queue. + + Ok((vec![], BTreeMap::new())) + } + } + + /// Paras that may get backed on cores. + /// + /// 1. The para must be scheduled on core. + /// 2. Core needs to be free, otherwise backing is not possible. + /// + /// We get a set of the occupied cores as input. + pub(crate) fn eligible_paras<'a>( + occupied_cores: &'a BTreeSet, + ) -> impl Iterator + 'a { + scheduler::ClaimQueue::::get().into_iter().filter_map(|(core_idx, queue)| { + if occupied_cores.contains(&core_idx) { + return None + } + let next_scheduled = queue.front()?; + Some((core_idx, next_scheduled.para_id())) + }) + } } /// Derive a bitfield from dispute @@ -763,7 +801,7 @@ pub(crate) fn apply_weight_limit( let mut current_para_id = None; for candidate in core::mem::take(candidates).into_iter() { - let candidate_para_id = candidate.descriptor().para_id; + let candidate_para_id = candidate.descriptor().para_id(); if Some(candidate_para_id) == current_para_id { let chain = chained_candidates .last_mut() @@ -936,20 +974,101 @@ pub(crate) fn sanitize_bitfields( bitfields } +/// Perform required checks for given candidate receipt. +/// +/// Returns `true` if candidate descriptor is version 1. +/// +/// Otherwise returns `false` if: +/// - version 2 descriptors are not allowed +/// - the core index in descriptor doesn't match the one computed from the commitments +/// - the `SelectCore` signal does not refer to a core at the top of claim queue +fn sanitize_backed_candidate_v2( + candidate: &BackedCandidate, + allowed_relay_parents: &AllowedRelayParentsTracker>, + allow_v2_receipts: bool, +) -> bool { + if candidate.descriptor().version() == CandidateDescriptorVersion::V1 { + return true + } + + // It is mandatory to filter these before calling `filter_unchained_candidates` to ensure + // any v1 descendants of v2 candidates are dropped. + if !allow_v2_receipts { + log::debug!( + target: LOG_TARGET, + "V2 candidate descriptors not allowed. Dropping candidate {:?} for paraid {:?}.", + candidate.candidate().hash(), + candidate.descriptor().para_id() + ); + return false + } + + let Some(session_index) = candidate.descriptor().session_index() else { + log::debug!( + target: LOG_TARGET, + "Invalid V2 candidate receipt {:?} for paraid {:?}, missing session index.", + candidate.candidate().hash(), + candidate.descriptor().para_id(), + ); + return false + }; + + // Check if session index is equal to current session index. + if session_index != shared::CurrentSessionIndex::::get() { + log::debug!( + target: LOG_TARGET, + "Dropping V2 candidate receipt {:?} for paraid {:?}, invalid session index {}, current session {}", + candidate.candidate().hash(), + candidate.descriptor().para_id(), + session_index, + shared::CurrentSessionIndex::::get() + ); + return false + } + + // Get the claim queue snapshot at the candidate relay parent. + let Some((rp_info, _)) = + allowed_relay_parents.acquire_info(candidate.descriptor().relay_parent(), None) + else { + log::debug!( + target: LOG_TARGET, + "Relay parent {:?} for candidate {:?} is not in the allowed relay parents.", + candidate.descriptor().relay_parent(), + candidate.candidate().hash(), + ); + return false + }; + + // Check validity of `core_index`. + if let Err(err) = candidate.candidate().check_core_index(&rp_info.claim_queue) { + log::debug!( + target: LOG_TARGET, + "Dropping candidate {:?} for paraid {:?}, {:?}", + candidate.candidate().hash(), + candidate.descriptor().para_id(), + err, + ); + + return false + } + true +} + /// Performs various filtering on the backed candidates inherent data. /// Must maintain the invariant that the returned candidate collection contains the candidates /// sorted in dependency order for each para. When doing any filtering, we must therefore drop any /// subsequent candidates after the filtered one. /// /// Filter out: -/// 1. any candidates which don't form a chain with the other candidates of the paraid (even if they +/// 1. Candidates that have v2 descriptors if the node `CandidateReceiptV2` feature is not enabled. +/// 2. any candidates which don't form a chain with the other candidates of the paraid (even if they /// do form a chain but are not in the right order). -/// 2. any candidates that have a concluded invalid dispute or who are descendants of a concluded +/// 3. any candidates that have a concluded invalid dispute or who are descendants of a concluded /// invalid candidate. -/// 3. any unscheduled candidates, as well as candidates whose paraid has multiple cores assigned +/// 4. any unscheduled candidates, as well as candidates whose paraid has multiple cores assigned /// but have no injected core index. -/// 4. all backing votes from disabled validators -/// 5. any candidates that end up with less than `effective_minimum_backing_votes` backing votes +/// 5. all backing votes from disabled validators +/// 6. any candidates that end up with less than `effective_minimum_backing_votes` backing votes /// /// Returns the scheduled /// backed candidates which passed filtering, mapped by para id and in the right dependency order. @@ -959,13 +1078,20 @@ fn sanitize_backed_candidates( concluded_invalid_with_descendants: BTreeSet, scheduled: BTreeMap>, core_index_enabled: bool, + allow_v2_receipts: bool, ) -> BTreeMap, CoreIndex)>> { // Map the candidates to the right paraids, while making sure that the order between candidates // of the same para is preserved. let mut candidates_per_para: BTreeMap> = BTreeMap::new(); + for candidate in backed_candidates { + if !sanitize_backed_candidate_v2::(&candidate, allowed_relay_parents, allow_v2_receipts) + { + continue + } + candidates_per_para - .entry(candidate.descriptor().para_id) + .entry(candidate.descriptor().para_id()) .or_default() .push(candidate); } @@ -984,7 +1110,7 @@ fn sanitize_backed_candidates( target: LOG_TARGET, "Found backed candidate {:?} which was concluded invalid or is a descendant of a concluded invalid candidate, for paraid {:?}.", candidate.candidate().hash(), - candidate.descriptor().para_id + candidate.descriptor().para_id() ); } keep @@ -1012,10 +1138,7 @@ fn sanitize_backed_candidates( } fn count_backed_candidates(backed_candidates: &BTreeMap>) -> usize { - backed_candidates.iter().fold(0, |mut count, (_id, candidates)| { - count += candidates.len(); - count - }) + backed_candidates.values().map(|c| c.len()).sum() } /// Derive entropy from babe provided per block randomness. @@ -1158,24 +1281,26 @@ fn filter_backed_statements_from_disabled_validators< // 1. Core index assigned to the parachain which has produced the candidate // 2. The relay chain block number of the candidate retain_candidates::(backed_candidates_with_core, |para_id, (bc, core_idx)| { + // `CoreIndex` not used, we just need a copy to write it back later. let (validator_indices, maybe_core_index) = bc.validator_indices_and_core_index(core_index_enabled); let mut validator_indices = BitVec::<_>::from(validator_indices); // Get relay parent block number of the candidate. We need this to get the group index // assigned to this core at this block number - let relay_parent_block_number = - match allowed_relay_parents.acquire_info(bc.descriptor().relay_parent, None) { - Some((_, block_num)) => block_num, - None => { - log::debug!( - target: LOG_TARGET, - "Relay parent {:?} for candidate is not in the allowed relay parents. Dropping the candidate.", - bc.descriptor().relay_parent - ); - return false - }, - }; + let relay_parent_block_number = match allowed_relay_parents + .acquire_info(bc.descriptor().relay_parent(), None) + { + Some((_, block_num)) => block_num, + None => { + log::debug!( + target: LOG_TARGET, + "Relay parent {:?} for candidate is not in the allowed relay parents. Dropping the candidate.", + bc.descriptor().relay_parent() + ); + return false + }, + }; // Get the group index for the core let group_idx = match scheduler::Pallet::::group_assigned_to_core( @@ -1243,22 +1368,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 = @@ -1277,15 +1407,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, @@ -1296,21 +1434,14 @@ fn filter_unchained_candidates= 1 && core_index_enabled { - // We must preserve the dependency order given in the input. - let mut temp_backed_candidates = Vec::with_capacity(scheduled_cores.len()); - - for candidate in backed_candidates { - if scheduled_cores.len() == 0 { - // We've got candidates for all of this para's assigned cores. Move on to - // the next para. - log::debug!( - target: LOG_TARGET, - "Found enough candidates for paraid: {:?}.", - candidate.descriptor().para_id - ); - break; - } - let maybe_injected_core_index: Option = - get_injected_core_index::(allowed_relay_parents, &candidate); - - if let Some(core_index) = maybe_injected_core_index { - if scheduled_cores.remove(&core_index) { - temp_backed_candidates.push((candidate, core_index)); - } else { - // if we got a candidate for a core index which is not scheduled, stop - // the work for this para. the already processed candidate chain in - // temp_backed_candidates is still fine though. - log::debug!( - target: LOG_TARGET, - "Found a backed candidate {:?} with injected core index {}, which is not scheduled for paraid {:?}.", - candidate.candidate().hash(), - core_index.0, - candidate.descriptor().para_id - ); - - break; - } - } else { - // if we got a candidate which does not contain its core index, stop the - // work for this para. the already processed candidate chain in - // temp_backed_candidates is still fine though. - - log::debug!( - target: LOG_TARGET, - "Found a backed candidate {:?} with no injected core index, for paraid {:?} which has multiple scheduled cores.", - candidate.candidate().hash(), - candidate.descriptor().para_id - ); - - break; - } - } + if let Some(core_index) = + get_core_index::(core_index_enabled, allowed_relay_parents, &candidate) + { + if scheduled_cores.remove(&core_index) { + temp_backed_candidates.push((candidate, core_index)); + } else { + // if we got a candidate for a core index which is not scheduled, stop + // the work for this para. the already processed candidate chain in + // temp_backed_candidates is still fine though. + log::debug!( + target: LOG_TARGET, + "Found a backed candidate {:?} with core index {}, which is not scheduled for paraid {:?}.", + candidate.candidate().hash(), + core_index.0, + candidate.descriptor().para_id() + ); - if !temp_backed_candidates.is_empty() { - backed_candidates_with_core - .entry(para_id) - .or_insert_with(|| vec![]) - .extend(temp_backed_candidates); + break; } } else { - log::warn!( + // No core index is fine, if para has just 1 core assigned. + if scheduled_cores.len() == 1 { + temp_backed_candidates + .push((candidate, scheduled_cores.pop_first().expect("Length is 1"))); + break; + } + + // if we got a candidate which does not contain its core index, stop the + // work for this para. the already processed candidate chain in + // temp_backed_candidates is still fine though. + + log::debug!( target: LOG_TARGET, - "Found a paraid {:?} which has multiple scheduled cores but ElasticScalingMVP feature is not enabled: {:?}", - para_id, - scheduled_cores + "Found a backed candidate {:?} without core index information, but paraid {:?} has multiple scheduled cores.", + candidate.candidate().hash(), + candidate.descriptor().para_id() ); + + break; } - } else { - log::debug!( - target: LOG_TARGET, - "Paraid: {:?} has no entry in scheduled cores but {} candidates were supplied.", - para_id, - backed_candidates.len() - ); + } + + if !temp_backed_candidates.is_empty() { + backed_candidates_with_core + .entry(para_id) + .or_insert_with(|| vec![]) + .extend(temp_backed_candidates); } } backed_candidates_with_core } +// Must be called only for candidates that have been sanitized already. +fn get_core_index( + core_index_enabled: bool, + allowed_relay_parents: &AllowedRelayParentsTracker>, + candidate: &BackedCandidate, +) -> Option { + candidate.candidate().descriptor.core_index().or_else(|| { + get_injected_core_index::(core_index_enabled, allowed_relay_parents, &candidate) + }) +} + fn get_injected_core_index( + core_index_enabled: bool, allowed_relay_parents: &AllowedRelayParentsTracker>, candidate: &BackedCandidate, ) -> Option { // After stripping the 8 bit extensions, the `validator_indices` field length is expected // to be equal to backing group size. If these don't match, the `CoreIndex` is badly encoded, // or not supported. - let (validator_indices, maybe_core_idx) = candidate.validator_indices_and_core_index(true); + let (validator_indices, maybe_core_idx) = + candidate.validator_indices_and_core_index(core_index_enabled); let Some(core_idx) = maybe_core_idx else { return None }; let relay_parent_block_number = - match allowed_relay_parents.acquire_info(candidate.descriptor().relay_parent, None) { + match allowed_relay_parents.acquire_info(candidate.descriptor().relay_parent(), None) { Some((_, block_num)) => block_num, None => { log::debug!( target: LOG_TARGET, "Relay parent {:?} for candidate {:?} is not in the allowed relay parents.", - candidate.descriptor().relay_parent, + candidate.descriptor().relay_parent(), candidate.candidate().hash(), ); return None diff --git a/polkadot/runtime/parachains/src/paras_inherent/tests.rs b/polkadot/runtime/parachains/src/paras_inherent/tests.rs index 0d5653eb729d..2c65298baf01 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/tests.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/tests.rs @@ -20,7 +20,7 @@ use crate::{ configuration::{self, HostConfiguration}, mock::MockGenesisConfig, }; -use polkadot_primitives::vstaging::SchedulerParams; +use polkadot_primitives::SchedulerParams; fn default_config() -> MockGenesisConfig { MockGenesisConfig { @@ -44,13 +44,15 @@ fn default_config() -> MockGenesisConfig { #[cfg(not(feature = "runtime-benchmarks"))] mod enter { use super::{inclusion::tests::TestCandidateBuilder, *}; + use polkadot_primitives::vstaging::{ClaimQueueOffset, CoreSelector, UMPSignal, UMP_SEPARATOR}; + use rstest::rstest; + use crate::{ - builder::{Bench, BenchBuilder}, + builder::{junk_collator, junk_collator_signature, Bench, BenchBuilder, CandidateModifier}, + disputes::clear_dispute_storage, + initializer::BufferedSessionChange, mock::{mock_assigner, new_test_ext, BlockLength, BlockWeights, RuntimeOrigin, Test}, - scheduler::{ - common::{Assignment, AssignmentProvider}, - ParasEntry, - }, + scheduler::common::{Assignment, AssignmentProvider}, session_info, }; use alloc::collections::btree_map::BTreeMap; @@ -58,7 +60,10 @@ mod enter { use core::panic; use frame_support::assert_ok; use frame_system::limits; - use polkadot_primitives::{vstaging::SchedulerParams, AvailabilityBitfield, UncheckedSigned}; + use polkadot_primitives::{ + vstaging::{CandidateDescriptorV2, CommittedCandidateReceiptV2, InternalVersion}, + AvailabilityBitfield, CandidateDescriptor, UncheckedSigned, + }; use sp_runtime::Perbill; struct TestConfig { @@ -67,9 +72,10 @@ mod enter { backed_and_concluding: BTreeMap, num_validators_per_core: u32, code_upgrade: Option, - fill_claimqueue: bool, elastic_paras: BTreeMap, unavailable_cores: Vec, + v2_descriptor: bool, + candidate_modifier: Option::Hash>>, } fn make_inherent_data( @@ -79,9 +85,10 @@ mod enter { backed_and_concluding, num_validators_per_core, code_upgrade, - fill_claimqueue, elastic_paras, unavailable_cores, + v2_descriptor, + candidate_modifier, }: TestConfig, ) -> Bench { let extra_cores = elastic_paras @@ -98,12 +105,11 @@ mod enter { .set_dispute_statements(dispute_statements) .set_backed_and_concluding_paras(backed_and_concluding.clone()) .set_dispute_sessions(&dispute_sessions[..]) - .set_fill_claimqueue(fill_claimqueue) - .set_unavailable_cores(unavailable_cores); + .set_unavailable_cores(unavailable_cores) + .set_candidate_descriptor_v2(v2_descriptor) + .set_candidate_modifier(candidate_modifier); // Setup some assignments as needed: - mock_assigner::Pallet::::set_core_count(builder.max_cores()); - (0..(builder.max_cores() as usize - extra_cores)).for_each(|para_id| { (0..elastic_paras.get(&(para_id as u32)).cloned().unwrap_or(1)).for_each( |_para_local_core_idx| { @@ -121,15 +127,25 @@ mod enter { } } - #[test] + #[rstest] + #[case(true)] + #[case(false)] // Validate that if we create 2 backed candidates which are assigned to 2 cores that will be // freed via becoming fully available, the backed candidates will not be filtered out in // `create_inherent` and will not cause `enter` to early. - fn include_backed_candidates() { + fn include_backed_candidates(#[case] v2_descriptor: bool) { let config = MockGenesisConfig::default(); assert!(config.configuration.config.scheduler_params.lookahead > 0); new_test_ext(config).execute_with(|| { + // Enable the v2 receipts. + configuration::Pallet::::set_node_feature( + RuntimeOrigin::root(), + FeatureIndex::CandidateReceiptV2 as u8, + v2_descriptor, + ) + .unwrap(); + let dispute_statements = BTreeMap::new(); let mut backed_and_concluding = BTreeMap::new(); @@ -142,9 +158,10 @@ mod enter { backed_and_concluding, num_validators_per_core: 1, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], + v2_descriptor, + candidate_modifier: None, }); // We expect the scenario to have cores 0 & 1 with pending availability. The backed @@ -164,9 +181,7 @@ mod enter { inherent_data .put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data) .unwrap(); - - // The current schedule is empty prior to calling `create_inherent_enter`. - assert!(scheduler::Pallet::::claim_queue_is_empty()); + assert!(!scheduler::Pallet::::claim_queue_is_empty()); // Nothing is filtered out (including the backed candidates.) assert_eq!( @@ -206,8 +221,14 @@ mod enter { }); } - #[test] - fn include_backed_candidates_elastic_scaling() { + #[rstest] + #[case(true, false)] + #[case(true, true)] + #[case(false, true)] + fn include_backed_candidates_elastic_scaling( + #[case] v2_descriptor: bool, + #[case] injected_core: bool, + ) { // ParaId 0 has one pending candidate on core 0. // ParaId 1 has one pending candidate on core 1. // ParaId 2 has three pending candidates on cores 2, 3 and 4. @@ -220,7 +241,15 @@ mod enter { configuration::Pallet::::set_node_feature( RuntimeOrigin::root(), FeatureIndex::ElasticScalingMVP as u8, - true, + injected_core, + ) + .unwrap(); + + // Enable the v2 receipts. + configuration::Pallet::::set_node_feature( + RuntimeOrigin::root(), + FeatureIndex::CandidateReceiptV2 as u8, + v2_descriptor, ) .unwrap(); @@ -237,9 +266,10 @@ mod enter { backed_and_concluding, num_validators_per_core: 1, code_upgrade: None, - fill_claimqueue: false, elastic_paras: [(2, 3)].into_iter().collect(), unavailable_cores: vec![], + v2_descriptor, + candidate_modifier: None, }); let expected_para_inherent_data = scenario.data.clone(); @@ -256,9 +286,7 @@ mod enter { .put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data) .unwrap(); - // The current schedule is empty prior to calling `create_inherent_enter`. - assert!(scheduler::Pallet::::claim_queue_is_empty()); - + assert!(!scheduler::Pallet::::claim_queue_is_empty()); assert!(pallet::OnChainVotes::::get().is_none()); // Nothing is filtered out (including the backed candidates.) @@ -341,9 +369,10 @@ mod enter { backed_and_concluding, num_validators_per_core: 1, code_upgrade: None, - fill_claimqueue: true, elastic_paras: [(2, 4)].into_iter().collect(), unavailable_cores: unavailable_cores.clone(), + v2_descriptor: false, + candidate_modifier: None, }); let mut expected_para_inherent_data = scenario.data.clone(); @@ -491,6 +520,101 @@ mod enter { }); } + #[test] + // Test that no new candidates are backed if there's an upcoming session change scheduled at the + // end of the block. Claim queue will also not be advanced. + fn session_change() { + let config = MockGenesisConfig::default(); + assert!(config.configuration.config.scheduler_params.lookahead > 0); + + new_test_ext(config).execute_with(|| { + let dispute_statements = BTreeMap::new(); + + let mut backed_and_concluding = BTreeMap::new(); + backed_and_concluding.insert(0, 1); + backed_and_concluding.insert(1, 1); + + let scenario = make_inherent_data(TestConfig { + dispute_statements, + dispute_sessions: vec![], // No disputes + backed_and_concluding, + num_validators_per_core: 1, + code_upgrade: None, + elastic_paras: BTreeMap::new(), + unavailable_cores: vec![], + v2_descriptor: false, + candidate_modifier: None, + }); + + let prev_claim_queue = scheduler::ClaimQueue::::get(); + + assert_eq!(inclusion::PendingAvailability::::iter().count(), 2); + assert_eq!( + inclusion::PendingAvailability::::get(ParaId::from(0)).unwrap().len(), + 1 + ); + assert_eq!( + inclusion::PendingAvailability::::get(ParaId::from(1)).unwrap().len(), + 1 + ); + + // We expect the scenario to have cores 0 & 1 with pending availability. The backed + // candidates are also created for cores 0 & 1. The pending available candidates will + // become available but the new candidates will not be backed since there is an upcoming + // session change. + let mut expected_para_inherent_data = scenario.data.clone(); + expected_para_inherent_data.backed_candidates.clear(); + + // Check the para inherent data is as expected: + // * 1 bitfield per validator (2 validators) + assert_eq!(expected_para_inherent_data.bitfields.len(), 2); + // * 0 disputes. + assert_eq!(expected_para_inherent_data.disputes.len(), 0); + let mut inherent_data = InherentData::new(); + inherent_data + .put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data) + .unwrap(); + assert!(!scheduler::Pallet::::claim_queue_is_empty()); + + // Simulate a session change scheduled to happen at the end of the block. + initializer::BufferedSessionChanges::::put(vec![BufferedSessionChange { + validators: vec![], + queued: vec![], + session_index: 3, + }]); + + // Only backed candidates are filtered out. + assert_eq!( + Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(), + expected_para_inherent_data + ); + + assert_eq!( + // No candidates backed. + OnChainVotes::::get().unwrap().backing_validators_per_candidate.len(), + 0 + ); + + assert_eq!( + // The session of the on chain votes should equal the current session, which is 2 + OnChainVotes::::get().unwrap().session, + 2 + ); + + // No pending availability candidates. + assert_eq!(inclusion::PendingAvailability::::iter().count(), 2); + assert!(inclusion::PendingAvailability::::get(ParaId::from(0)) + .unwrap() + .is_empty()); + assert!(inclusion::PendingAvailability::::get(ParaId::from(1)) + .unwrap() + .is_empty()); + + // The claim queue should not have been advanced. + assert_eq!(prev_claim_queue, scheduler::ClaimQueue::::get()); + }); + } + #[test] fn test_session_is_tracked_in_on_chain_scraping() { use crate::disputes::run_to_block; @@ -597,9 +721,10 @@ mod enter { backed_and_concluding, num_validators_per_core: 5, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], + v2_descriptor: false, + candidate_modifier: None, }); let expected_para_inherent_data = scenario.data.clone(); @@ -617,8 +742,7 @@ mod enter { .put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data) .unwrap(); - // The current schedule is empty prior to calling `create_inherent_enter`. - assert!(scheduler::Pallet::::claim_queue_is_empty()); + assert!(!scheduler::Pallet::::claim_queue_is_empty()); let multi_dispute_inherent_data = Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(); @@ -633,6 +757,8 @@ mod enter { &expected_para_inherent_data.disputes[..2], ); + clear_dispute_storage::(); + assert_ok!(Pallet::::enter( frame_system::RawOrigin::None.into(), multi_dispute_inherent_data, @@ -670,9 +796,10 @@ mod enter { backed_and_concluding, num_validators_per_core: 6, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], + v2_descriptor: false, + candidate_modifier: None, }); let expected_para_inherent_data = scenario.data.clone(); @@ -689,8 +816,7 @@ mod enter { .put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data) .unwrap(); - // The current schedule is empty prior to calling `create_inherent_enter`. - assert!(scheduler::Pallet::::claim_queue_is_empty()); + assert!(!scheduler::Pallet::::claim_queue_is_empty()); let limit_inherent_data = Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(); @@ -702,6 +828,8 @@ mod enter { assert_eq!(limit_inherent_data.disputes[0].session, 1); assert_eq!(limit_inherent_data.disputes[1].session, 2); + clear_dispute_storage::(); + assert_ok!(Pallet::::enter( frame_system::RawOrigin::None.into(), limit_inherent_data, @@ -741,9 +869,10 @@ mod enter { backed_and_concluding, num_validators_per_core: 4, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], + v2_descriptor: false, + candidate_modifier: None, }); let expected_para_inherent_data = scenario.data.clone(); @@ -761,8 +890,7 @@ mod enter { .put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data) .unwrap(); - // The current schedule is empty prior to calling `create_inherent_enter`. - assert!(scheduler::Pallet::::claim_queue_is_empty()); + assert!(!scheduler::Pallet::::claim_queue_is_empty()); // Nothing is filtered out (including the backed candidates.) let limit_inherent_data = @@ -784,6 +912,8 @@ mod enter { // over weight assert_eq!(limit_inherent_data.backed_candidates.len(), 0); + clear_dispute_storage::(); + assert_ok!(Pallet::::enter( frame_system::RawOrigin::None.into(), limit_inherent_data, @@ -828,9 +958,10 @@ mod enter { backed_and_concluding, num_validators_per_core: 5, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], + v2_descriptor: false, + candidate_modifier: None, }); let expected_para_inherent_data = scenario.data.clone(); @@ -848,10 +979,8 @@ mod enter { .put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data) .unwrap(); - // The current schedule is empty prior to calling `create_inherent_enter`. - assert!(scheduler::Pallet::::claim_queue_is_empty()); + assert!(!scheduler::Pallet::::claim_queue_is_empty()); - // Nothing is filtered out (including the backed candidates.) let limit_inherent_data = Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(); assert_ne!(limit_inherent_data, expected_para_inherent_data); @@ -872,9 +1001,11 @@ mod enter { // over weight assert_eq!(limit_inherent_data.backed_candidates.len(), 0); + clear_dispute_storage::(); + assert_ok!(Pallet::::enter( frame_system::RawOrigin::None.into(), - limit_inherent_data, + limit_inherent_data )); assert_eq!( @@ -915,9 +1046,10 @@ mod enter { backed_and_concluding, num_validators_per_core: 5, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], + v2_descriptor: false, + candidate_modifier: None, }); let expected_para_inherent_data = scenario.data.clone(); @@ -943,6 +1075,81 @@ mod enter { }); } + // Ensure that even if the block is over weight due to candidates enactment, + // we still can import it. + #[test] + fn overweight_candidates_enactment_is_fine() { + sp_tracing::try_init_simple(); + new_test_ext(MockGenesisConfig::default()).execute_with(|| { + use crate::inclusion::WeightInfo as _; + + let mut backed_and_concluding = BTreeMap::new(); + // The number of candidates is chosen to go over the weight limit + // of the mock runtime together with the `enact_candidate`s weight. + let num_candidates = 5u32; + let max_weight = ::BlockWeights::get().max_block; + assert!(::WeightInfo::enact_candidate(0, 0, 0) + .saturating_mul(u64::from(num_candidates)) + .any_gt(max_weight)); + + for i in 0..num_candidates { + backed_and_concluding.insert(i, 2); + } + + let num_validators_per_core: u32 = 5; + let num_backed = backed_and_concluding.len(); + let bitfields_len = num_validators_per_core as usize * num_backed; + + let scenario = make_inherent_data(TestConfig { + dispute_statements: BTreeMap::new(), + dispute_sessions: vec![], + backed_and_concluding, + num_validators_per_core, + code_upgrade: None, + elastic_paras: BTreeMap::new(), + unavailable_cores: vec![], + v2_descriptor: false, + candidate_modifier: None, + }); + + let expected_para_inherent_data = scenario.data.clone(); + + // Check the para inherent data is as expected: + assert_eq!(expected_para_inherent_data.bitfields.len(), bitfields_len); + assert_eq!(expected_para_inherent_data.backed_candidates.len(), num_backed); + assert_eq!(expected_para_inherent_data.disputes.len(), 0); + + let mut inherent_data = InherentData::new(); + inherent_data + .put_data(PARACHAINS_INHERENT_IDENTIFIER, &expected_para_inherent_data) + .unwrap(); + + let limit_inherent_data = + Pallet::::create_inherent_inner(&inherent_data.clone()).unwrap(); + assert!(limit_inherent_data == expected_para_inherent_data); + + // Cores were scheduled. We should put the assignments back, before calling enter(). + let cores = (0..num_candidates) + .into_iter() + .map(|i| { + // Load an assignment into provider so that one is present to pop + let assignment = + ::AssignmentProvider::get_mock_assignment( + CoreIndex(i), + ParaId::from(i), + ); + (CoreIndex(i), [assignment].into()) + }) + .collect(); + scheduler::ClaimQueue::::set(cores); + + assert_ok!(Pallet::::enter( + frame_system::RawOrigin::None.into(), + limit_inherent_data, + )); + }); + } + fn max_block_weight_proof_size_adjusted() -> Weight { let raw_weight = ::BlockWeights::get().max_block; let block_length = ::BlockLength::get(); @@ -1001,9 +1208,10 @@ mod enter { backed_and_concluding, num_validators_per_core: 5, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], + v2_descriptor: false, + candidate_modifier: None, }); let expected_para_inherent_data = scenario.data.clone(); @@ -1057,24 +1265,23 @@ mod enter { ); // One core was scheduled. We should put the assignment back, before calling enter(). - let now = frame_system::Pallet::::block_number() + 1; let used_cores = 5; let cores = (0..used_cores) .into_iter() .map(|i| { - let SchedulerParams { ttl, .. } = - configuration::ActiveConfig::::get().scheduler_params; // Load an assignment into provider so that one is present to pop let assignment = ::AssignmentProvider::get_mock_assignment( CoreIndex(i), ParaId::from(i), ); - (CoreIndex(i), [ParasEntry::new(assignment, now + ttl)].into()) + (CoreIndex(i), [assignment].into()) }) .collect(); scheduler::ClaimQueue::::set(cores); + clear_dispute_storage::(); + assert_ok!(Pallet::::enter( frame_system::RawOrigin::None.into(), limit_inherent_data, @@ -1108,9 +1315,10 @@ mod enter { backed_and_concluding, num_validators_per_core: 5, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], + v2_descriptor: false, + candidate_modifier: None, }); let expected_para_inherent_data = scenario.data.clone(); @@ -1176,9 +1384,10 @@ mod enter { backed_and_concluding, num_validators_per_core: 5, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], + v2_descriptor: false, + candidate_modifier: None, }); let expected_para_inherent_data = scenario.data.clone(); @@ -1242,9 +1451,10 @@ mod enter { backed_and_concluding, num_validators_per_core: 5, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], + v2_descriptor: false, + candidate_modifier: None, }); let expected_para_inherent_data = scenario.data.clone(); @@ -1311,6 +1521,15 @@ mod enter { ccr.commitments.processed_downward_messages = idx as u32; let core_index = start_core_index + idx; + // `UMPSignal` separator. + ccr.commitments.upward_messages.force_push(UMP_SEPARATOR); + + // `SelectCore` commitment. + // Claim queue offset must be `0`` so this candidate is for the very next block. + ccr.commitments.upward_messages.force_push( + UMPSignal::SelectCore(CoreSelector(idx as u8), ClaimQueueOffset(0)).encode(), + ); + BackedCandidate::new( ccr.into(), Default::default(), @@ -1322,9 +1541,10 @@ mod enter { } // Ensure that overweight parachain inherents are always rejected by the runtime. - // Runtime should panic and return `InherentOverweight` error. - #[test] - fn test_backed_candidates_apply_weight_works_for_elastic_scaling() { + #[rstest] + #[case(true)] + #[case(false)] + fn test_backed_candidates_apply_weight_works_for_elastic_scaling(#[case] v2_descriptor: bool) { new_test_ext(MockGenesisConfig::default()).execute_with(|| { let seed = [ 1, 0, 52, 0, 0, 0, 0, 0, 1, 0, 10, 0, 22, 32, 0, 0, 2, 0, 55, 49, 0, 11, 0, 0, 3, @@ -1335,6 +1555,14 @@ mod enter { // Create an overweight inherent and oversized block let mut backed_and_concluding = BTreeMap::new(); + // Enable the v2 receipts. + configuration::Pallet::::set_node_feature( + RuntimeOrigin::root(), + FeatureIndex::CandidateReceiptV2 as u8, + v2_descriptor, + ) + .unwrap(); + for i in 0..30 { backed_and_concluding.insert(i, i); } @@ -1345,9 +1573,10 @@ mod enter { backed_and_concluding, num_validators_per_core: 5, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], + v2_descriptor, + candidate_modifier: None, }); let mut para_inherent_data = scenario.data.clone(); @@ -1381,7 +1610,7 @@ mod enter { // The chained candidates are not picked, instead a single other candidate is picked assert_eq!(backed_candidates.len(), 1); - assert_ne!(backed_candidates[0].descriptor().para_id, ParaId::from(1000)); + assert_ne!(backed_candidates[0].descriptor().para_id(), ParaId::from(1000)); // All bitfields are kept. assert_eq!(bitfields.len(), 150); @@ -1402,9 +1631,9 @@ mod enter { // Only the chained candidates should pass filter. assert_eq!(backed_candidates.len(), 3); // Check the actual candidates - assert_eq!(backed_candidates[0].descriptor().para_id, ParaId::from(1000)); - assert_eq!(backed_candidates[1].descriptor().para_id, ParaId::from(1000)); - assert_eq!(backed_candidates[2].descriptor().para_id, ParaId::from(1000)); + assert_eq!(backed_candidates[0].descriptor().para_id(), ParaId::from(1000)); + assert_eq!(backed_candidates[1].descriptor().para_id(), ParaId::from(1000)); + assert_eq!(backed_candidates[2].descriptor().para_id(), ParaId::from(1000)); // All bitfields are kept. assert_eq!(bitfields.len(), 150); @@ -1412,7 +1641,6 @@ mod enter { } // Ensure that overweight parachain inherents are always rejected by the runtime. - // Runtime should panic and return `InherentOverweight` error. #[test] fn inherent_create_weight_invariant() { new_test_ext(MockGenesisConfig::default()).execute_with(|| { @@ -1434,9 +1662,10 @@ mod enter { backed_and_concluding, num_validators_per_core: 5, code_upgrade: None, - fill_claimqueue: false, elastic_paras: BTreeMap::new(), unavailable_cores: vec![], + v2_descriptor: false, + candidate_modifier: None, }); let expected_para_inherent_data = scenario.data.clone(); @@ -1462,449 +1691,1505 @@ mod enter { .unwrap_err() .error; - assert_eq!(dispatch_error, Error::::InherentOverweight.into()); + assert_eq!(dispatch_error, Error::::InherentDataFilteredDuringExecution.into()); }); } -} -fn default_header() -> polkadot_primitives::Header { - polkadot_primitives::Header { - parent_hash: Default::default(), - number: 0, - state_root: Default::default(), - extrinsics_root: Default::default(), - digest: Default::default(), - } -} + #[test] + fn v2_descriptors_are_filtered() { + let config = default_config(); + assert!(config.configuration.config.scheduler_params.lookahead > 0); + new_test_ext(config).execute_with(|| { + // Set the elastic scaling MVP feature. + configuration::Pallet::::set_node_feature( + RuntimeOrigin::root(), + FeatureIndex::ElasticScalingMVP as u8, + true, + ) + .unwrap(); -mod sanitizers { - use super::*; + let mut backed_and_concluding = BTreeMap::new(); + backed_and_concluding.insert(0, 1); + backed_and_concluding.insert(1, 1); + backed_and_concluding.insert(2, 1); - use crate::{ - inclusion::tests::{ - back_candidate, collator_sign_candidate, BackingKind, TestCandidateBuilder, - }, - mock::new_test_ext, - }; - use bitvec::order::Lsb0; - use polkadot_primitives::{ - AvailabilityBitfield, GroupIndex, Hash, Id as ParaId, SignedAvailabilityBitfield, - ValidatorIndex, - }; - use rstest::rstest; - use sp_core::crypto::UncheckedFrom; + let unavailable_cores = vec![]; - use crate::mock::Test; - use polkadot_primitives::PARACHAIN_KEY_TYPE_ID; - use sc_keystore::LocalKeystore; - use sp_keyring::Sr25519Keyring; - use sp_keystore::{Keystore, KeystorePtr}; - use std::sync::Arc; + let scenario = make_inherent_data(TestConfig { + dispute_statements: BTreeMap::new(), + dispute_sessions: vec![], // No disputes + backed_and_concluding, + num_validators_per_core: 5, + code_upgrade: None, + elastic_paras: [(2, 8)].into_iter().collect(), + unavailable_cores: unavailable_cores.clone(), + v2_descriptor: true, + candidate_modifier: None, + }); - fn validator_pubkeys(val_ids: &[sp_keyring::Sr25519Keyring]) -> Vec { - val_ids.iter().map(|v| v.public().into()).collect() - } + let mut unfiltered_para_inherent_data = scenario.data.clone(); - #[test] - fn bitfields() { - let header = default_header(); - let parent_hash = header.hash(); - // 2 cores means two bits - let expected_bits = 2; - let session_index = SessionIndex::from(0_u32); + // Check the para inherent data is as expected: + // * 1 bitfield per validator (5 validators per core, 10 backed candidates) + assert_eq!(unfiltered_para_inherent_data.bitfields.len(), 50); + // * 10 v2 candidate descriptors. + assert_eq!(unfiltered_para_inherent_data.backed_candidates.len(), 10); - let crypto_store = LocalKeystore::in_memory(); - let crypto_store = Arc::new(crypto_store) as KeystorePtr; - let signing_context = SigningContext { parent_hash, session_index }; + // Make the last candidate look like v1, by using an unknown version. + unfiltered_para_inherent_data.backed_candidates[9] + .descriptor_mut() + .set_version(InternalVersion(123)); - let validators = vec![ - sp_keyring::Sr25519Keyring::Alice, - sp_keyring::Sr25519Keyring::Bob, - sp_keyring::Sr25519Keyring::Charlie, - sp_keyring::Sr25519Keyring::Dave, - ]; - for validator in validators.iter() { - Keystore::sr25519_generate_new( - &*crypto_store, - PARACHAIN_KEY_TYPE_ID, - Some(&validator.to_seed()), + let mut inherent_data = InherentData::new(); + inherent_data + .put_data(PARACHAINS_INHERENT_IDENTIFIER, &unfiltered_para_inherent_data) + .unwrap(); + + // We expect all backed candidates to be filtered out. + let filtered_para_inherend_data = + Pallet::::create_inherent_inner(&inherent_data).unwrap(); + + assert_eq!(filtered_para_inherend_data.backed_candidates.len(), 0); + + let dispatch_error = Pallet::::enter( + frame_system::RawOrigin::None.into(), + unfiltered_para_inherent_data, ) - .unwrap(); - } - let validator_public = validator_pubkeys(&validators); + .unwrap_err() + .error; - let checked_bitfields = [ - BitVec::::repeat(true, expected_bits), - BitVec::::repeat(true, expected_bits), - { - let mut bv = BitVec::::repeat(false, expected_bits); - bv.set(expected_bits - 1, true); - bv - }, - ] - .iter() - .enumerate() - .map(|(vi, ab)| { - let validator_index = ValidatorIndex::from(vi as u32); - SignedAvailabilityBitfield::sign( - &crypto_store, - AvailabilityBitfield::from(ab.clone()), - &signing_context, - validator_index, - &validator_public[vi], + // We expect `enter` to fail because the inherent data contains backed candidates with + // v2 descriptors. + assert_eq!(dispatch_error, Error::::InherentDataFilteredDuringExecution.into()); + }); + } + + #[test] + fn too_many_ump_signals() { + let config = default_config(); + assert!(config.configuration.config.scheduler_params.lookahead > 0); + new_test_ext(config).execute_with(|| { + // Set the elastic scaling MVP feature. + configuration::Pallet::::set_node_feature( + RuntimeOrigin::root(), + FeatureIndex::CandidateReceiptV2 as u8, + true, ) - .unwrap() - .unwrap() - }) - .collect::>(); + .unwrap(); - let unchecked_bitfields = checked_bitfields - .iter() - .cloned() - .map(|v| v.into_unchecked()) - .collect::>(); + let mut backed_and_concluding = BTreeMap::new(); + backed_and_concluding.insert(0, 1); + backed_and_concluding.insert(1, 1); + backed_and_concluding.insert(2, 1); - let disputed_bitfield = DisputedBitfield::zeros(expected_bits); + let unavailable_cores = vec![]; - { - assert_eq!( - sanitize_bitfields::( - unchecked_bitfields.clone(), - disputed_bitfield.clone(), - expected_bits, - parent_hash, - session_index, - &validator_public[..], - ), - checked_bitfields.clone() - ); - assert_eq!( - sanitize_bitfields::( - unchecked_bitfields.clone(), - disputed_bitfield.clone(), - expected_bits, - parent_hash, - session_index, - &validator_public[..], - ), - checked_bitfields.clone() - ); - } + let scenario = make_inherent_data(TestConfig { + dispute_statements: BTreeMap::new(), + dispute_sessions: vec![], // No disputes + backed_and_concluding, + num_validators_per_core: 1, + code_upgrade: None, + elastic_paras: [(2, 8)].into_iter().collect(), + unavailable_cores: unavailable_cores.clone(), + v2_descriptor: true, + candidate_modifier: Some(|mut candidate: CommittedCandidateReceiptV2| { + if candidate.descriptor.para_id() == 2.into() { + // Add an extra message so `verify_backed_candidates` fails. + candidate.commitments.upward_messages.force_push( + UMPSignal::SelectCore(CoreSelector(123 as u8), ClaimQueueOffset(2)) + .encode(), + ); + } + candidate + }), + }); - // disputed bitfield is non-zero - { - let mut disputed_bitfield = DisputedBitfield::zeros(expected_bits); - // pretend the first core was freed by either a malicious validator - // or by resolved dispute - disputed_bitfield.0.set(0, true); + let unfiltered_para_inherent_data = scenario.data.clone(); - assert_eq!( - sanitize_bitfields::( - unchecked_bitfields.clone(), - disputed_bitfield.clone(), - expected_bits, - parent_hash, - session_index, - &validator_public[..], - ) - .len(), - 1 - ); - assert_eq!( - sanitize_bitfields::( - unchecked_bitfields.clone(), - disputed_bitfield.clone(), - expected_bits, - parent_hash, - session_index, - &validator_public[..], - ) - .len(), - 1 - ); - } + // Check the para inherent data is as expected: + // * 1 bitfield per validator (1 validators per core, 10 backed candidates) + assert_eq!(unfiltered_para_inherent_data.bitfields.len(), 10); + // * 10 v2 candidate descriptors. + assert_eq!(unfiltered_para_inherent_data.backed_candidates.len(), 10); - // bitfield size mismatch - { - assert!(sanitize_bitfields::( - unchecked_bitfields.clone(), - disputed_bitfield.clone(), - expected_bits + 1, - parent_hash, - session_index, - &validator_public[..], - ) - .is_empty()); - assert!(sanitize_bitfields::( - unchecked_bitfields.clone(), - disputed_bitfield.clone(), - expected_bits + 1, - parent_hash, - session_index, - &validator_public[..], + let mut inherent_data = InherentData::new(); + inherent_data + .put_data(PARACHAINS_INHERENT_IDENTIFIER, &unfiltered_para_inherent_data) + .unwrap(); + + let dispatch_error = Pallet::::enter( + frame_system::RawOrigin::None.into(), + unfiltered_para_inherent_data, ) - .is_empty()); - } + .unwrap_err() + .error; - // remove the last validator - { - let shortened = validator_public.len() - 2; - assert_eq!( - &sanitize_bitfields::( - unchecked_bitfields.clone(), - disputed_bitfield.clone(), - expected_bits, - parent_hash, - session_index, - &validator_public[..shortened], - )[..], - &checked_bitfields[..shortened] - ); - assert_eq!( - &sanitize_bitfields::( - unchecked_bitfields.clone(), - disputed_bitfield.clone(), - expected_bits, - parent_hash, - session_index, - &validator_public[..shortened], - )[..], - &checked_bitfields[..shortened] - ); - } + // We expect `enter` to fail because the inherent data contains backed candidates with + // v2 descriptors. + assert_eq!(dispatch_error, Error::::InherentDataFilteredDuringExecution.into()); + }); + } - // switch ordering of bitfields - { - let mut unchecked_bitfields = unchecked_bitfields.clone(); - let x = unchecked_bitfields.swap_remove(0); - unchecked_bitfields.push(x); - let result: UncheckedSignedAvailabilityBitfields = sanitize_bitfields::( - unchecked_bitfields.clone(), - disputed_bitfield.clone(), - expected_bits, - parent_hash, - session_index, - &validator_public[..], + #[test] + fn invalid_ump_signals() { + let config = default_config(); + assert!(config.configuration.config.scheduler_params.lookahead > 0); + new_test_ext(config).execute_with(|| { + // Set the elastic scaling MVP feature. + configuration::Pallet::::set_node_feature( + RuntimeOrigin::root(), + FeatureIndex::CandidateReceiptV2 as u8, + true, ) - .into_iter() - .map(|v| v.into_unchecked()) - .collect(); - assert_eq!(&result, &unchecked_bitfields[..(unchecked_bitfields.len() - 2)]); - } + .unwrap(); - // check the validators signature - { - let mut unchecked_bitfields = unchecked_bitfields.clone(); + let mut backed_and_concluding = BTreeMap::new(); + backed_and_concluding.insert(0, 1); + backed_and_concluding.insert(1, 1); + backed_and_concluding.insert(2, 1); - // insert a bad signature for the last bitfield - let last_bit_idx = unchecked_bitfields.len() - 1; - unchecked_bitfields - .get_mut(last_bit_idx) - .and_then(|u| Some(u.set_signature(UncheckedFrom::unchecked_from([1u8; 64])))) - .expect("we are accessing a valid index"); - assert_eq!( - &sanitize_bitfields::( - unchecked_bitfields.clone(), - disputed_bitfield.clone(), - expected_bits, - parent_hash, - session_index, - &validator_public[..], - )[..], - &checked_bitfields[..last_bit_idx] - ); - } - // duplicate bitfields - { - let mut unchecked_bitfields = unchecked_bitfields.clone(); + let unavailable_cores = vec![]; - // insert a bad signature for the last bitfield - let last_bit_idx = unchecked_bitfields.len() - 1; - unchecked_bitfields - .get_mut(last_bit_idx) - .and_then(|u| Some(u.set_signature(UncheckedFrom::unchecked_from([1u8; 64])))) - .expect("we are accessing a valid index"); - assert_eq!( - &sanitize_bitfields::( - unchecked_bitfields.clone().into_iter().chain(unchecked_bitfields).collect(), - disputed_bitfield.clone(), - expected_bits, - parent_hash, - session_index, - &validator_public[..], - )[..], - &checked_bitfields[..last_bit_idx] - ); - } - } + let scenario = make_inherent_data(TestConfig { + dispute_statements: BTreeMap::new(), + dispute_sessions: vec![], // No disputes + backed_and_concluding, + num_validators_per_core: 1, + code_upgrade: None, + elastic_paras: [(2, 8)].into_iter().collect(), + unavailable_cores: unavailable_cores.clone(), + v2_descriptor: true, + candidate_modifier: Some(|mut candidate: CommittedCandidateReceiptV2| { + if candidate.descriptor.para_id() == 1.into() { + // Drop the core selector to make it invalid + candidate + .commitments + .upward_messages + .truncate(candidate.commitments.upward_messages.len() - 1); + } + candidate + }), + }); - mod candidates { - use crate::{ - mock::{set_disabled_validators, RuntimeOrigin}, - scheduler::{common::Assignment, ParasEntry}, - util::{make_persisted_validation_data, make_persisted_validation_data_with_parent}, - }; - use alloc::collections::vec_deque::VecDeque; - use polkadot_primitives::ValidationCode; + let unfiltered_para_inherent_data = scenario.data.clone(); - use super::*; + // Check the para inherent data is as expected: + // * 1 bitfield per validator (1 validator per core, 10 backed candidates) + assert_eq!(unfiltered_para_inherent_data.bitfields.len(), 10); + // * 10 v2 candidate descriptors. + assert_eq!(unfiltered_para_inherent_data.backed_candidates.len(), 10); - // Backed candidates and scheduled parachains used for `sanitize_backed_candidates` testing - struct TestData { - backed_candidates: Vec, - expected_backed_candidates_with_core: - BTreeMap>, - scheduled_paras: BTreeMap>, - } + let mut inherent_data = InherentData::new(); + inherent_data + .put_data(PARACHAINS_INHERENT_IDENTIFIER, &unfiltered_para_inherent_data) + .unwrap(); - // Generate test data for the candidates and assert that the environment is set as expected - // (check the comments for details) - fn get_test_data_one_core_per_para(core_index_enabled: bool) -> TestData { - const RELAY_PARENT_NUM: u32 = 3; + let dispatch_error = Pallet::::enter( + frame_system::RawOrigin::None.into(), + unfiltered_para_inherent_data, + ) + .unwrap_err() + .error; - // 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(), - Default::default(), - RELAY_PARENT_NUM, - 1, - ); + // We expect `enter` to fail because the inherent data contains backed candidates with + // v2 descriptors. + assert_eq!(dispatch_error, Error::::InherentDataFilteredDuringExecution.into()); + }); + } + #[test] + fn v2_descriptors_are_accepted() { + let config = default_config(); + assert!(config.configuration.config.scheduler_params.lookahead > 0); + new_test_ext(config).execute_with(|| { + // Set the elastic scaling MVP feature. + configuration::Pallet::::set_node_feature( + RuntimeOrigin::root(), + FeatureIndex::ElasticScalingMVP as u8, + true, + ) + .unwrap(); - let header = default_header(); - let relay_parent = header.hash(); - let session_index = SessionIndex::from(0_u32); + // Enable the v2 receipts. + configuration::Pallet::::set_node_feature( + RuntimeOrigin::root(), + FeatureIndex::CandidateReceiptV2 as u8, + true, + ) + .unwrap(); - let keystore = LocalKeystore::in_memory(); - let keystore = Arc::new(keystore) as KeystorePtr; - let signing_context = SigningContext { parent_hash: relay_parent, session_index }; + let mut backed_and_concluding = BTreeMap::new(); + backed_and_concluding.insert(0, 1); + backed_and_concluding.insert(1, 1); + backed_and_concluding.insert(2, 1); - let validators = vec![ - sp_keyring::Sr25519Keyring::Alice, - sp_keyring::Sr25519Keyring::Bob, - sp_keyring::Sr25519Keyring::Charlie, - sp_keyring::Sr25519Keyring::Dave, - sp_keyring::Sr25519Keyring::Eve, - ]; - for validator in validators.iter() { - Keystore::sr25519_generate_new( - &*keystore, - PARACHAIN_KEY_TYPE_ID, - Some(&validator.to_seed()), - ) - .unwrap(); + let unavailable_cores = vec![]; + + let scenario = make_inherent_data(TestConfig { + dispute_statements: BTreeMap::new(), + dispute_sessions: vec![], // No disputes + backed_and_concluding, + num_validators_per_core: 1, + code_upgrade: None, + elastic_paras: [(2, 3)].into_iter().collect(), + unavailable_cores: unavailable_cores.clone(), + v2_descriptor: true, + candidate_modifier: None, + }); + + let inherent_data = scenario.data.clone(); + + // Check the para inherent data is as expected: + // * 1 bitfield per validator (2 validators per core, 5 backed candidates) + assert_eq!(inherent_data.bitfields.len(), 5); + // * 5 v2 candidate descriptors. + assert_eq!(inherent_data.backed_candidates.len(), 5); + + Pallet::::enter(frame_system::RawOrigin::None.into(), inherent_data).unwrap(); + }); + } + + // Test when parachain runtime is upgraded to support the new commitments + // but some collators are not and provide v1 descriptors. + #[test] + fn elastic_scaling_mixed_v1_v2_descriptors() { + let config = default_config(); + assert!(config.configuration.config.scheduler_params.lookahead > 0); + new_test_ext(config).execute_with(|| { + // Set the elastic scaling MVP feature. + configuration::Pallet::::set_node_feature( + RuntimeOrigin::root(), + FeatureIndex::ElasticScalingMVP as u8, + true, + ) + .unwrap(); + + // Enable the v2 receipts. + configuration::Pallet::::set_node_feature( + RuntimeOrigin::root(), + FeatureIndex::CandidateReceiptV2 as u8, + true, + ) + .unwrap(); + + let mut backed_and_concluding = BTreeMap::new(); + backed_and_concluding.insert(0, 1); + backed_and_concluding.insert(1, 1); + backed_and_concluding.insert(2, 1); + + let unavailable_cores = vec![]; + + let scenario = make_inherent_data(TestConfig { + dispute_statements: BTreeMap::new(), + dispute_sessions: vec![], // No disputes + backed_and_concluding, + num_validators_per_core: 1, + code_upgrade: None, + elastic_paras: [(2, 3)].into_iter().collect(), + unavailable_cores: unavailable_cores.clone(), + v2_descriptor: true, + candidate_modifier: None, + }); + + let mut inherent_data = scenario.data.clone(); + let candidate_count = inherent_data.backed_candidates.len(); + + // Make last 2 candidates v1 + for index in candidate_count - 2..candidate_count { + let encoded = inherent_data.backed_candidates[index].descriptor().encode(); + + let mut decoded: CandidateDescriptor = + Decode::decode(&mut encoded.as_slice()).unwrap(); + decoded.collator = junk_collator(); + decoded.signature = junk_collator_signature(); + + *inherent_data.backed_candidates[index].descriptor_mut() = + Decode::decode(&mut encoded.as_slice()).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); + // Check the para inherent data is as expected: + // * 1 bitfield per validator (2 validators per core, 5 backed candidates) + assert_eq!(inherent_data.bitfields.len(), 5); + // * 5 v2 candidate descriptors. + assert_eq!(inherent_data.backed_candidates.len(), 5); - // Two scheduled parachains - ParaId(1) on CoreIndex(0) and ParaId(2) on CoreIndex(1) - let scheduled: BTreeMap> = (0_usize..2) - .into_iter() - .map(|idx| { - ( - ParaId::from(1_u32 + idx as u32), - [CoreIndex::from(idx as u32)].into_iter().collect(), - ) - }) - .collect::>(); + Pallet::::enter(frame_system::RawOrigin::None.into(), inherent_data).unwrap(); + }); + } - // Set the validator groups in `scheduler` - scheduler::Pallet::::set_validator_groups(vec![ - vec![ValidatorIndex(0), ValidatorIndex(1)], - vec![ValidatorIndex(2), ValidatorIndex(3)], - ]); + // Mixed test with v1, v2 with/without `UMPSignal::SelectCore` + #[test] + fn mixed_v1_and_v2_optional_commitments() { + let config = default_config(); + assert!(config.configuration.config.scheduler_params.lookahead > 0); + new_test_ext(config).execute_with(|| { + // Set the elastic scaling MVP feature. + configuration::Pallet::::set_node_feature( + RuntimeOrigin::root(), + FeatureIndex::ElasticScalingMVP as u8, + true, + ) + .unwrap(); - // 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: 2.into(), core_index: CoreIndex(1) }, - RELAY_PARENT_NUM, - )]), - ), - ])); + // Enable the v2 receipts. + configuration::Pallet::::set_node_feature( + RuntimeOrigin::root(), + FeatureIndex::CandidateReceiptV2 as u8, + true, + ) + .unwrap(); - // Set the on-chain included head data for paras. - paras::Pallet::::set_current_head(ParaId::from(1), HeadData(vec![1])); - paras::Pallet::::set_current_head(ParaId::from(2), HeadData(vec![2])); + let mut backed_and_concluding = BTreeMap::new(); + backed_and_concluding.insert(0, 1); + backed_and_concluding.insert(1, 1); + backed_and_concluding.insert(2, 1); + backed_and_concluding.insert(3, 1); + backed_and_concluding.insert(4, 1); - // Set the current_code_hash - paras::Pallet::::force_set_current_code( + let unavailable_cores = vec![]; + + let candidate_modifier = |mut candidate: CommittedCandidateReceiptV2| { + // first candidate has v2 descriptor with no commitments + if candidate.descriptor.para_id() == ParaId::from(0) { + candidate.commitments.upward_messages.clear(); + } + + if candidate.descriptor.para_id() > ParaId::from(2) { + let mut v1: CandidateDescriptor = candidate.descriptor.into(); + + v1.collator = junk_collator(); + v1.signature = junk_collator_signature(); + + candidate.descriptor = v1.into(); + } + candidate + }; + + let scenario = make_inherent_data(TestConfig { + dispute_statements: BTreeMap::new(), + dispute_sessions: vec![], // No disputes + backed_and_concluding, + num_validators_per_core: 1, + code_upgrade: None, + elastic_paras: Default::default(), + unavailable_cores: unavailable_cores.clone(), + v2_descriptor: true, + candidate_modifier: Some(candidate_modifier), + }); + + let inherent_data = scenario.data.clone(); + + // Check the para inherent data is as expected: + // * 1 bitfield per validator (2 validators per core, 5 backed candidates) + assert_eq!(inherent_data.bitfields.len(), 5); + // * 5 v2 candidate descriptors. + assert_eq!(inherent_data.backed_candidates.len(), 5); + + Pallet::::enter(frame_system::RawOrigin::None.into(), inherent_data).unwrap(); + }); + } + + // A test to ensure that the `paras_inherent` filters out candidates with invalid + // session index in the descriptor. + #[test] + fn invalid_session_index() { + let config = default_config(); + assert!(config.configuration.config.scheduler_params.lookahead > 0); + new_test_ext(config).execute_with(|| { + // Set the elastic scaling MVP feature. + configuration::Pallet::::set_node_feature( RuntimeOrigin::root(), - ParaId::from(1), - ValidationCode(vec![1]), + FeatureIndex::ElasticScalingMVP as u8, + true, ) .unwrap(); - paras::Pallet::::force_set_current_code( + + // Enable the v2 receipts. + configuration::Pallet::::set_node_feature( RuntimeOrigin::root(), - ParaId::from(2), - ValidationCode(vec![2]), + FeatureIndex::CandidateReceiptV2 as u8, + true, ) .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, 1]), - group_index if group_index == GroupIndex::from(1) => Some(vec![2, 3]), - _ => panic!("Group index out of bounds"), + let mut backed_and_concluding = BTreeMap::new(); + backed_and_concluding.insert(0, 1); + backed_and_concluding.insert(1, 1); + backed_and_concluding.insert(2, 1); + + let unavailable_cores = vec![]; + + let scenario = make_inherent_data(TestConfig { + dispute_statements: BTreeMap::new(), + dispute_sessions: vec![], // No disputes + backed_and_concluding, + num_validators_per_core: 1, + code_upgrade: None, + elastic_paras: [(2, 3)].into_iter().collect(), + unavailable_cores, + v2_descriptor: true, + candidate_modifier: None, + }); + + let mut inherent_data = scenario.data.clone(); + + // Check the para inherent data is as expected: + // * 1 bitfield per validator (2 validators per core, 5 backed candidates) + assert_eq!(inherent_data.bitfields.len(), 5); + // * 5 v2 candidate descriptors passed, 1 is invalid + assert_eq!(inherent_data.backed_candidates.len(), 5); + + let index = inherent_data.backed_candidates.len() - 1; + + // Put invalid session index in last candidate + let backed_candidate = inherent_data.backed_candidates[index].clone(); + + let candidate = CommittedCandidateReceiptV2 { + descriptor: CandidateDescriptorV2::new( + backed_candidate.descriptor().para_id(), + backed_candidate.descriptor().relay_parent(), + backed_candidate.descriptor().core_index().unwrap(), + 100, + backed_candidate.descriptor().persisted_validation_data_hash(), + backed_candidate.descriptor().pov_hash(), + backed_candidate.descriptor().erasure_root(), + backed_candidate.descriptor().para_head(), + backed_candidate.descriptor().validation_code_hash(), + ), + commitments: backed_candidate.candidate().commitments.clone(), + }; + + inherent_data.backed_candidates[index] = BackedCandidate::new( + candidate, + backed_candidate.validity_votes().to_vec(), + backed_candidate.validator_indices_and_core_index(false).0.into(), + None, + ); + + let mut expected_inherent_data = inherent_data.clone(); + expected_inherent_data.backed_candidates.truncate(index); + + let mut create_inherent_data = InherentData::new(); + create_inherent_data + .put_data(PARACHAINS_INHERENT_IDENTIFIER, &inherent_data) + .unwrap(); + + // 1 candidate with invalid session is filtered out + assert_eq!( + Pallet::::create_inherent_inner(&create_inherent_data).unwrap(), + expected_inherent_data + ); + + Pallet::::enter(frame_system::RawOrigin::None.into(), inherent_data).unwrap_err(); + }); + } +} + +fn default_header() -> polkadot_primitives::Header { + polkadot_primitives::Header { + parent_hash: Default::default(), + number: 0, + state_root: Default::default(), + extrinsics_root: Default::default(), + digest: Default::default(), + } +} + +mod sanitizers { + use super::*; + + use crate::{ + inclusion::tests::{back_candidate, BackingKind, TestCandidateBuilder}, + mock::new_test_ext, + }; + use bitvec::order::Lsb0; + use polkadot_primitives::{ + AvailabilityBitfield, GroupIndex, Hash, Id as ParaId, SignedAvailabilityBitfield, + ValidatorIndex, + }; + use rstest::rstest; + use sp_core::crypto::UncheckedFrom; + + use crate::mock::Test; + use polkadot_primitives::PARACHAIN_KEY_TYPE_ID; + use sc_keystore::LocalKeystore; + use sp_keystore::{Keystore, KeystorePtr}; + use std::sync::Arc; + + fn validator_pubkeys(val_ids: &[sp_keyring::Sr25519Keyring]) -> Vec { + val_ids.iter().map(|v| v.public().into()).collect() + } + + #[test] + fn bitfields() { + let header = default_header(); + let parent_hash = header.hash(); + // 2 cores means two bits + let expected_bits = 2; + let session_index = SessionIndex::from(0_u32); + + let crypto_store = LocalKeystore::in_memory(); + let crypto_store = Arc::new(crypto_store) as KeystorePtr; + let signing_context = SigningContext { parent_hash, session_index }; + + let validators = vec![ + sp_keyring::Sr25519Keyring::Alice, + sp_keyring::Sr25519Keyring::Bob, + sp_keyring::Sr25519Keyring::Charlie, + sp_keyring::Sr25519Keyring::Dave, + ]; + for validator in validators.iter() { + Keystore::sr25519_generate_new( + &*crypto_store, + PARACHAIN_KEY_TYPE_ID, + Some(&validator.to_seed()), + ) + .unwrap(); + } + let validator_public = validator_pubkeys(&validators); + + let checked_bitfields = [ + BitVec::::repeat(true, expected_bits), + BitVec::::repeat(true, expected_bits), + { + let mut bv = BitVec::::repeat(false, expected_bits); + bv.set(expected_bits - 1, true); + bv + }, + ] + .iter() + .enumerate() + .map(|(vi, ab)| { + let validator_index = ValidatorIndex::from(vi as u32); + SignedAvailabilityBitfield::sign( + &crypto_store, + AvailabilityBitfield::from(ab.clone()), + &signing_context, + validator_index, + &validator_public[vi], + ) + .unwrap() + .unwrap() + }) + .collect::>(); + + let unchecked_bitfields = checked_bitfields + .iter() + .cloned() + .map(|v| v.into_unchecked()) + .collect::>(); + + let disputed_bitfield = DisputedBitfield::zeros(expected_bits); + + { + assert_eq!( + sanitize_bitfields::( + unchecked_bitfields.clone(), + disputed_bitfield.clone(), + expected_bits, + parent_hash, + session_index, + &validator_public[..], + ), + checked_bitfields.clone() + ); + assert_eq!( + sanitize_bitfields::( + unchecked_bitfields.clone(), + disputed_bitfield.clone(), + expected_bits, + parent_hash, + session_index, + &validator_public[..], + ), + checked_bitfields.clone() + ); + } + + // disputed bitfield is non-zero + { + let mut disputed_bitfield = DisputedBitfield::zeros(expected_bits); + // pretend the first core was freed by either a malicious validator + // or by resolved dispute + disputed_bitfield.0.set(0, true); + + assert_eq!( + sanitize_bitfields::( + unchecked_bitfields.clone(), + disputed_bitfield.clone(), + expected_bits, + parent_hash, + session_index, + &validator_public[..], + ) + .len(), + 1 + ); + assert_eq!( + sanitize_bitfields::( + unchecked_bitfields.clone(), + disputed_bitfield.clone(), + expected_bits, + parent_hash, + session_index, + &validator_public[..], + ) + .len(), + 1 + ); + } + + // bitfield size mismatch + { + assert!(sanitize_bitfields::( + unchecked_bitfields.clone(), + disputed_bitfield.clone(), + expected_bits + 1, + parent_hash, + session_index, + &validator_public[..], + ) + .is_empty()); + assert!(sanitize_bitfields::( + unchecked_bitfields.clone(), + disputed_bitfield.clone(), + expected_bits + 1, + parent_hash, + session_index, + &validator_public[..], + ) + .is_empty()); + } + + // remove the last validator + { + let shortened = validator_public.len() - 2; + assert_eq!( + &sanitize_bitfields::( + unchecked_bitfields.clone(), + disputed_bitfield.clone(), + expected_bits, + parent_hash, + session_index, + &validator_public[..shortened], + )[..], + &checked_bitfields[..shortened] + ); + assert_eq!( + &sanitize_bitfields::( + unchecked_bitfields.clone(), + disputed_bitfield.clone(), + expected_bits, + parent_hash, + session_index, + &validator_public[..shortened], + )[..], + &checked_bitfields[..shortened] + ); + } + + // switch ordering of bitfields + { + let mut unchecked_bitfields = unchecked_bitfields.clone(); + let x = unchecked_bitfields.swap_remove(0); + unchecked_bitfields.push(x); + let result: UncheckedSignedAvailabilityBitfields = sanitize_bitfields::( + unchecked_bitfields.clone(), + disputed_bitfield.clone(), + expected_bits, + parent_hash, + session_index, + &validator_public[..], + ) + .into_iter() + .map(|v| v.into_unchecked()) + .collect(); + assert_eq!(&result, &unchecked_bitfields[..(unchecked_bitfields.len() - 2)]); + } + + // check the validators signature + { + let mut unchecked_bitfields = unchecked_bitfields.clone(); + + // insert a bad signature for the last bitfield + let last_bit_idx = unchecked_bitfields.len() - 1; + unchecked_bitfields + .get_mut(last_bit_idx) + .and_then(|u| Some(u.set_signature(UncheckedFrom::unchecked_from([1u8; 64])))) + .expect("we are accessing a valid index"); + assert_eq!( + &sanitize_bitfields::( + unchecked_bitfields.clone(), + disputed_bitfield.clone(), + expected_bits, + parent_hash, + session_index, + &validator_public[..], + )[..], + &checked_bitfields[..last_bit_idx] + ); + } + // duplicate bitfields + { + let mut unchecked_bitfields = unchecked_bitfields.clone(); + + // insert a bad signature for the last bitfield + let last_bit_idx = unchecked_bitfields.len() - 1; + unchecked_bitfields + .get_mut(last_bit_idx) + .and_then(|u| Some(u.set_signature(UncheckedFrom::unchecked_from([1u8; 64])))) + .expect("we are accessing a valid index"); + assert_eq!( + &sanitize_bitfields::( + unchecked_bitfields.clone().into_iter().chain(unchecked_bitfields).collect(), + disputed_bitfield.clone(), + expected_bits, + parent_hash, + session_index, + &validator_public[..], + )[..], + &checked_bitfields[..last_bit_idx] + ); + } + } + + mod candidates { + use crate::{ + mock::{set_disabled_validators, RuntimeOrigin}, + scheduler::common::Assignment, + util::{make_persisted_validation_data, make_persisted_validation_data_with_parent}, + }; + use alloc::collections::vec_deque::VecDeque; + use polkadot_primitives::ValidationCode; + + use super::*; + + // Backed candidates and scheduled parachains used for `sanitize_backed_candidates` testing + struct TestData { + backed_candidates: Vec, + expected_backed_candidates_with_core: + BTreeMap>, + scheduled_paras: BTreeMap>, + } + + // Generate test data for the candidates and assert that the environment is set as expected + // (check the comments for details) + fn get_test_data_one_core_per_para(core_index_enabled: bool) -> TestData { + const RELAY_PARENT_NUM: u32 = 3; + + // 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(), + Default::default(), + 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(); + 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, + ]; + 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); + + // Two scheduled parachains - ParaId(1) on CoreIndex(0) and ParaId(2) on CoreIndex(1) + let scheduled: BTreeMap> = (0_usize..2) + .into_iter() + .map(|idx| { + ( + ParaId::from(1_u32 + idx as u32), + [CoreIndex::from(idx as u32)].into_iter().collect(), + ) + }) + .collect::>(); + + // Set the validator groups in `scheduler` + scheduler::Pallet::::set_validator_groups(vec![ + vec![ValidatorIndex(0), ValidatorIndex(1)], + vec![ValidatorIndex(2), ValidatorIndex(3)], + ]); + + // Update scheduler's claimqueue with the parachains + scheduler::Pallet::::set_claim_queue(BTreeMap::from([ + ( + CoreIndex::from(0), + VecDeque::from([Assignment::Pool { + para_id: 1.into(), + core_index: CoreIndex(0), + }]), + ), + ( + CoreIndex::from(1), + VecDeque::from([Assignment::Pool { + para_id: 2.into(), + core_index: CoreIndex(1), + }]), + ), + ])); + + // Set the on-chain included head data for paras. + paras::Pallet::::set_current_head(ParaId::from(1), HeadData(vec![1])); + paras::Pallet::::set_current_head(ParaId::from(2), HeadData(vec![2])); + + // Set the current_code_hash + paras::Pallet::::force_set_current_code( + RuntimeOrigin::root(), + ParaId::from(1), + ValidationCode(vec![1]), + ) + .unwrap(); + paras::Pallet::::force_set_current_code( + RuntimeOrigin::root(), + ParaId::from(2), + ValidationCode(vec![2]), + ) + .unwrap(); + // Set the most recent relay parent. + paras::Pallet::::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| { + match group_index { + group_index if group_index == GroupIndex::from(0) => Some(vec![0, 1]), + group_index if group_index == GroupIndex::from(1) => Some(vec![2, 3]), + _ => panic!("Group index out of bounds"), + } + .map(|m| m.into_iter().map(ValidatorIndex).collect::>()) + }; + + // One backed candidate from each parachain + let backed_candidates = (0_usize..2) + .into_iter() + .map(|idx0| { + let idx1 = idx0 + 1; + let candidate = TestCandidateBuilder { + para_id: ParaId::from(idx1), + relay_parent, + pov_hash: Hash::repeat_byte(idx1 as u8), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(idx1), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![idx1 as u8]), + ..Default::default() + } + .build(); + + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(idx0 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(idx0 as u32)), + ); + backed + }) + .collect::>(); + + // State sanity checks + assert_eq!( + Pallet::::eligible_paras(&Default::default()).collect::>(), + vec![(CoreIndex(0), ParaId::from(1)), (CoreIndex(1), ParaId::from(2))] + ); + assert_eq!( + shared::ActiveValidatorIndices::::get(), + vec![ + ValidatorIndex(0), + ValidatorIndex(1), + ValidatorIndex(2), + ValidatorIndex(3), + ValidatorIndex(4) + ] + ); + + let mut expected_backed_candidates_with_core = BTreeMap::new(); + + for candidate in backed_candidates.iter() { + let para_id = candidate.descriptor().para_id(); + + expected_backed_candidates_with_core.entry(para_id).or_insert(vec![]).push(( + candidate.clone(), + scheduled.get(¶_id).unwrap().first().copied().unwrap(), + )); + } + + TestData { + backed_candidates, + scheduled_paras: scheduled, + expected_backed_candidates_with_core, + } + } + + // Generate test data for the candidates and assert that the environment is set as expected + // (check the comments for details) + // Para 1 scheduled on core 0 and core 1. Two candidates are supplied. + // Para 2 scheduled on cores 2 and 3. One candidate supplied. + // Para 3 scheduled on core 4. One candidate supplied. + // Para 4 scheduled on core 5. Two candidates supplied. + // Para 5 scheduled on core 6. No candidates supplied. + // Para 6 is not scheduled. One candidate supplied. + // Para 7 is scheduled on core 7 and 8, but the candidate contains the wrong core index. + // Para 8 is scheduled on core 9, but the candidate contains the wrong core index. + fn get_test_data_multiple_cores_per_para( + core_index_enabled: bool, + v2_descriptor: bool, + ) -> TestData { + const RELAY_PARENT_NUM: u32 = 3; + + let header = default_header(); + let relay_parent = header.hash(); + 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, + sp_keyring::Sr25519Keyring::One, + sp_keyring::Sr25519Keyring::Two, + ]; + 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)], + vec![ValidatorIndex(6)], + vec![ValidatorIndex(7)], + ]); + + // Update scheduler's claimqueue with the parachains + scheduler::Pallet::::set_claim_queue(BTreeMap::from([ + ( + CoreIndex::from(0), + VecDeque::from([Assignment::Pool { + para_id: 1.into(), + core_index: CoreIndex(0), + }]), + ), + ( + CoreIndex::from(1), + VecDeque::from([Assignment::Pool { + para_id: 1.into(), + core_index: CoreIndex(1), + }]), + ), + ( + CoreIndex::from(2), + VecDeque::from([Assignment::Pool { + para_id: 2.into(), + core_index: CoreIndex(2), + }]), + ), + ( + CoreIndex::from(3), + VecDeque::from([Assignment::Pool { + para_id: 2.into(), + core_index: CoreIndex(3), + }]), + ), + ( + CoreIndex::from(4), + VecDeque::from([Assignment::Pool { + para_id: 3.into(), + core_index: CoreIndex(4), + }]), + ), + ( + CoreIndex::from(5), + VecDeque::from([Assignment::Pool { + para_id: 4.into(), + core_index: CoreIndex(5), + }]), + ), + ( + CoreIndex::from(6), + VecDeque::from([Assignment::Pool { + para_id: 5.into(), + core_index: CoreIndex(6), + }]), + ), + ( + CoreIndex::from(7), + VecDeque::from([Assignment::Pool { + para_id: 7.into(), + core_index: CoreIndex(7), + }]), + ), + ( + CoreIndex::from(8), + VecDeque::from([Assignment::Pool { + para_id: 7.into(), + core_index: CoreIndex(8), + }]), + ), + ( + CoreIndex::from(9), + VecDeque::from([Assignment::Pool { + para_id: 8.into(), + core_index: CoreIndex(9), + }]), + ), + ])); + + // 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( + relay_parent, + Default::default(), + scheduler::ClaimQueue::::get() + .into_iter() + .map(|(core_index, paras)| { + (core_index, paras.into_iter().map(|e| e.para_id()).collect()) + }) + .collect(), + RELAY_PARENT_NUM, + 1, + ); + + // Set the on-chain included head data and current code hash. + for id in 1..=8u32 { + 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(); + + let maybe_core_index = |core_index: CoreIndex| -> Option { + if !v2_descriptor { + None + } else { + Some(core_index) + } + }; + + // Para 1 + { + let 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(), + hrmp_watermark: RELAY_PARENT_NUM, + head_data: HeadData(vec![1, 1]), + validation_code: ValidationCode(vec![1]), + core_index: maybe_core_index(CoreIndex(0)), + ..Default::default() + } + .build(); + + 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 || v2_descriptor { + expected_backed_candidates_with_core + .entry(ParaId::from(1)) + .or_insert(vec![]) + .push((backed, CoreIndex(0))); + } + + let candidate = TestCandidateBuilder { + para_id: ParaId::from(1), + 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![1]), + core_index: maybe_core_index(CoreIndex(1)), + core_selector: Some(1), + ..Default::default() + } + .build(); + + 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()); + if core_index_enabled || v2_descriptor { + expected_backed_candidates_with_core + .entry(ParaId::from(1)) + .or_insert(vec![]) + .push((backed, CoreIndex(1))); + } + } + + // Para 2 + { + let candidate = TestCandidateBuilder { + para_id: ParaId::from(2), + relay_parent, + pov_hash: Hash::repeat_byte(3 as u8), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(2), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![2]), + core_index: maybe_core_index(CoreIndex(2)), + ..Default::default() + } + .build(); + + 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()); + if core_index_enabled || v2_descriptor { + expected_backed_candidates_with_core + .entry(ParaId::from(2)) + .or_insert(vec![]) + .push((backed, CoreIndex(2))); + } + } + + // Para 3 + { + let candidate = TestCandidateBuilder { + para_id: ParaId::from(3), + relay_parent, + pov_hash: Hash::repeat_byte(4 as u8), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(3), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![3]), + core_index: maybe_core_index(CoreIndex(4)), + ..Default::default() + } + .build(); + + 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()); + expected_backed_candidates_with_core + .entry(ParaId::from(3)) + .or_insert(vec![]) + .push((backed, CoreIndex(4))); + } + + // Para 4 + { + let candidate = TestCandidateBuilder { + para_id: ParaId::from(4), + relay_parent, + pov_hash: Hash::repeat_byte(5 as u8), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(4), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![4]), + core_index: maybe_core_index(CoreIndex(5)), + ..Default::default() + } + .build(); + + let prev_candidate = candidate.clone(); + 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()); + expected_backed_candidates_with_core + .entry(ParaId::from(4)) + .or_insert(vec![]) + .push((backed, CoreIndex(5))); + + let candidate = TestCandidateBuilder { + para_id: ParaId::from(4), + relay_parent, + pov_hash: Hash::repeat_byte(6 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![4]), + core_index: maybe_core_index(CoreIndex(5)), + ..Default::default() + } + .build(); + + 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()); + } + + // No candidate for para 5. + + // Para 6. + { + let candidate = TestCandidateBuilder { + para_id: ParaId::from(6), + relay_parent, + pov_hash: Hash::repeat_byte(3 as u8), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(6), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![6]), + core_index: maybe_core_index(CoreIndex(6)), + ..Default::default() + } + .build(); + + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(6 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(6 as u32)), + ); + backed_candidates.push(backed.clone()); + } + + // Para 7. + { + let candidate = TestCandidateBuilder { + para_id: ParaId::from(7), + relay_parent, + pov_hash: Hash::repeat_byte(3 as u8), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(7), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![7]), + core_index: maybe_core_index(CoreIndex(6)), + ..Default::default() } - .map(|m| m.into_iter().map(ValidatorIndex).collect::>()) - }; + .build(); - // One backed candidate from each parachain - let backed_candidates = (0_usize..2) - .into_iter() - .map(|idx0| { - let idx1 = idx0 + 1; - let mut candidate = TestCandidateBuilder { - para_id: ParaId::from(idx1), - relay_parent, - pov_hash: Hash::repeat_byte(idx1 as u8), - persisted_validation_data_hash: make_persisted_validation_data::( - ParaId::from(idx1), - RELAY_PARENT_NUM, - Default::default(), - ) - .unwrap() - .hash(), - hrmp_watermark: RELAY_PARENT_NUM, - validation_code: ValidationCode(vec![idx1 as u8]), - ..Default::default() - } - .build(); + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(6 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(6 as u32)), + ); + backed_candidates.push(backed.clone()); + } - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); + // Para 8. + { + let candidate = TestCandidateBuilder { + para_id: ParaId::from(8), + relay_parent, + pov_hash: Hash::repeat_byte(3 as u8), + persisted_validation_data_hash: make_persisted_validation_data::( + ParaId::from(8), + RELAY_PARENT_NUM, + Default::default(), + ) + .unwrap() + .hash(), + hrmp_watermark: RELAY_PARENT_NUM, + validation_code: ValidationCode(vec![8]), + core_index: maybe_core_index(CoreIndex(7)), + ..Default::default() + } + .build(); - let backed = back_candidate( - candidate, - &validators, - group_validators(GroupIndex::from(idx0 as u32)).unwrap().as_ref(), - &keystore, - &signing_context, - BackingKind::Threshold, - core_index_enabled.then_some(CoreIndex(idx0 as u32)), - ); - backed - }) - .collect::>(); + let backed = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(6 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(7 as u32)), + ); + backed_candidates.push(backed.clone()); + if !core_index_enabled && !v2_descriptor { + expected_backed_candidates_with_core + .entry(ParaId::from(8)) + .or_insert(vec![]) + .push((backed, CoreIndex(9))); + } + } // State sanity checks assert_eq!( - scheduler::Pallet::::scheduled_paras().collect::>(), - vec![(CoreIndex(0), ParaId::from(1)), (CoreIndex(1), ParaId::from(2))] + Pallet::::eligible_paras(&Default::default()).collect::>(), + vec![ + (CoreIndex(0), ParaId::from(1)), + (CoreIndex(1), ParaId::from(1)), + (CoreIndex(2), ParaId::from(2)), + (CoreIndex(3), ParaId::from(2)), + (CoreIndex(4), ParaId::from(3)), + (CoreIndex(5), ParaId::from(4)), + (CoreIndex(6), ParaId::from(5)), + (CoreIndex(7), ParaId::from(7)), + (CoreIndex(8), ParaId::from(7)), + (CoreIndex(9), ParaId::from(8)), + ] ); + let mut scheduled: BTreeMap> = BTreeMap::new(); + for (core_idx, para_id) in Pallet::::eligible_paras(&Default::default()) { + scheduled.entry(para_id).or_default().insert(core_idx); + } + assert_eq!( shared::ActiveValidatorIndices::::get(), vec![ @@ -1912,21 +3197,13 @@ mod sanitizers { ValidatorIndex(1), ValidatorIndex(2), ValidatorIndex(3), - ValidatorIndex(4) + ValidatorIndex(4), + ValidatorIndex(5), + ValidatorIndex(6), + ValidatorIndex(7), ] ); - let mut expected_backed_candidates_with_core = BTreeMap::new(); - - for candidate in backed_candidates.iter() { - let para_id = candidate.descriptor().para_id; - - expected_backed_candidates_with_core.entry(para_id).or_insert(vec![]).push(( - candidate.clone(), - scheduled.get(¶_id).unwrap().first().copied().unwrap(), - )); - } - TestData { backed_candidates, scheduled_paras: scheduled, @@ -1934,30 +3211,17 @@ mod sanitizers { } } - // Generate test data for the candidates and assert that the environment is set as expected - // (check the comments for details) - // Para 1 scheduled on core 0 and core 1. Two candidates are supplied. - // Para 2 scheduled on cores 2 and 3. One candidate supplied. - // Para 3 scheduled on core 4. One candidate supplied. - // Para 4 scheduled on core 5. Two candidates supplied. - // Para 5 scheduled on core 6. No candidates supplied. - // Para 6 is not scheduled. One candidate supplied. - // Para 7 is scheduled on core 7 and 8, but the candidate contains the wrong core index. - // Para 8 is scheduled on core 9, but the candidate contains the wrong core index. - fn get_test_data_multiple_cores_per_para(core_index_enabled: bool) -> TestData { + // Para 1 scheduled on core 0 and core 1. Two candidates are supplied. They form a chain but + // in the wrong order. + // Para 2 scheduled on core 2, core 3 and core 4. Three candidates are supplied. The second + // one is not part of the chain. + // Para 3 scheduled on core 5 and 6. Two candidates are supplied and they all form a chain. + // 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; - - // 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(), - 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(); @@ -1973,6 +3237,7 @@ mod sanitizers { sp_keyring::Sr25519Keyring::Ferdie, sp_keyring::Sr25519Keyring::One, sp_keyring::Sr25519Keyring::Two, + sp_keyring::Sr25519Keyring::AliceStash, ]; for validator in validators.iter() { Keystore::sr25519_generate_new( @@ -1998,84 +3263,91 @@ mod sanitizers { vec![ValidatorIndex(5)], vec![ValidatorIndex(6)], vec![ValidatorIndex(7)], + vec![ValidatorIndex(8)], ]); // 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, - )]), + VecDeque::from([Assignment::Pool { + para_id: 1.into(), + core_index: CoreIndex(0), + }]), ), ( CoreIndex::from(1), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 1.into(), core_index: CoreIndex(1) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 1.into(), + core_index: CoreIndex(1), + }]), ), ( CoreIndex::from(2), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(2) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 2.into(), + core_index: CoreIndex(2), + }]), ), ( CoreIndex::from(3), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(3) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 2.into(), + core_index: CoreIndex(3), + }]), ), ( CoreIndex::from(4), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 3.into(), core_index: CoreIndex(4) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 2.into(), + core_index: CoreIndex(4), + }]), ), ( CoreIndex::from(5), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 4.into(), core_index: CoreIndex(5) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 3.into(), + core_index: CoreIndex(5), + }]), ), ( CoreIndex::from(6), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 5.into(), core_index: CoreIndex(6) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 3.into(), + core_index: CoreIndex(6), + }]), ), ( CoreIndex::from(7), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 7.into(), core_index: CoreIndex(7) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 4.into(), + core_index: CoreIndex(7), + }]), ), ( CoreIndex::from(8), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 7.into(), core_index: CoreIndex(8) }, - RELAY_PARENT_NUM, - )]), - ), - ( - CoreIndex::from(9), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 8.into(), core_index: CoreIndex(9) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 4.into(), + core_index: CoreIndex(8), + }]), ), ])); + shared::Pallet::::add_allowed_relay_parent( + relay_parent, + Default::default(), + scheduler::ClaimQueue::::get() + .into_iter() + .map(|(core_index, paras)| { + (core_index, paras.into_iter().map(|e| e.para_id()).collect()) + }) + .collect(), + RELAY_PARENT_NUM, + 1, + ); + // Set the on-chain included head data and current code hash. - for id in 1..=8u32 { + for id in 1..=4u32 { paras::Pallet::::set_current_head(ParaId::from(id), HeadData(vec![id as u8])); paras::Pallet::::force_set_current_code( RuntimeOrigin::root(), @@ -2083,23 +3355,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![]; @@ -2107,7 +3377,7 @@ mod sanitizers { // Para 1 { - let mut candidate = TestCandidateBuilder { + let candidate = TestCandidateBuilder { para_id: ParaId::from(1), relay_parent, pov_hash: Hash::repeat_byte(1 as u8), @@ -2118,17 +3388,15 @@ mod sanitizers { ) .unwrap() .hash(), - hrmp_watermark: RELAY_PARENT_NUM, 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( + let prev_backed: BackedCandidate = back_candidate( candidate, &validators, group_validators(GroupIndex::from(0 as u32)).unwrap().as_ref(), @@ -2137,15 +3405,8 @@ mod sanitizers { 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 { + let candidate = TestCandidateBuilder { para_id: ParaId::from(1), relay_parent, pov_hash: Hash::repeat_byte(2 as u8), @@ -2163,8 +3424,6 @@ mod sanitizers { } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); - let backed = back_candidate( candidate, &validators, @@ -2175,17 +3434,12 @@ mod sanitizers { core_index_enabled.then_some(CoreIndex(1 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(1))); - } + backed_candidates.push(prev_backed.clone()); } - // Para 2 + // Para 2. { - let mut candidate = TestCandidateBuilder { + let candidate_1 = TestCandidateBuilder { para_id: ParaId::from(2), relay_parent, pov_hash: Hash::repeat_byte(3 as u8), @@ -2196,16 +3450,15 @@ mod sanitizers { ) .unwrap() .hash(), + head_data: HeadData(vec![2, 2]), hrmp_watermark: RELAY_PARENT_NUM, validation_code: ValidationCode(vec![2]), ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); - - let backed = back_candidate( - candidate, + let backed_1: BackedCandidate = back_candidate( + candidate_1, &validators, group_validators(GroupIndex::from(2 as u32)).unwrap().as_ref(), &keystore, @@ -2213,177 +3466,130 @@ mod sanitizers { BackingKind::Threshold, core_index_enabled.then_some(CoreIndex(2 as u32)), ); - backed_candidates.push(backed.clone()); + + backed_candidates.push(backed_1.clone()); if core_index_enabled { expected_backed_candidates_with_core .entry(ParaId::from(2)) .or_insert(vec![]) - .push((backed, CoreIndex(2))); + .push((backed_1, CoreIndex(2))); } - } - // Para 3 - { - let mut candidate = TestCandidateBuilder { - para_id: ParaId::from(3), + let candidate_2 = TestCandidateBuilder { + para_id: ParaId::from(2), relay_parent, pov_hash: Hash::repeat_byte(4 as u8), persisted_validation_data_hash: make_persisted_validation_data::( - ParaId::from(3), - RELAY_PARENT_NUM, - Default::default(), - ) - .unwrap() - .hash(), - hrmp_watermark: RELAY_PARENT_NUM, - validation_code: ValidationCode(vec![3]), - ..Default::default() - } - .build(); - - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); - - 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()); - expected_backed_candidates_with_core - .entry(ParaId::from(3)) - .or_insert(vec![]) - .push((backed, CoreIndex(4))); - } - - // Para 4 - { - let mut candidate = TestCandidateBuilder { - para_id: ParaId::from(4), - relay_parent, - pov_hash: Hash::repeat_byte(5 as u8), - persisted_validation_data_hash: make_persisted_validation_data::( - ParaId::from(4), + ParaId::from(2), RELAY_PARENT_NUM, Default::default(), ) .unwrap() .hash(), hrmp_watermark: RELAY_PARENT_NUM, - validation_code: ValidationCode(vec![4]), + validation_code: ValidationCode(vec![2]), + head_data: HeadData(vec![3, 3]), ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); - - let prev_candidate = candidate.clone(); - let backed = back_candidate( - candidate, + let backed_2 = back_candidate( + candidate_2.clone(), &validators, - group_validators(GroupIndex::from(5 as u32)).unwrap().as_ref(), + group_validators(GroupIndex::from(3 as u32)).unwrap().as_ref(), &keystore, &signing_context, BackingKind::Threshold, - core_index_enabled.then_some(CoreIndex(5 as u32)), + core_index_enabled.then_some(CoreIndex(3 as u32)), ); - backed_candidates.push(backed.clone()); - expected_backed_candidates_with_core - .entry(ParaId::from(4)) - .or_insert(vec![]) - .push((backed, CoreIndex(5))); + backed_candidates.push(backed_2.clone()); - let mut candidate = TestCandidateBuilder { - para_id: ParaId::from(4), + let candidate_3 = TestCandidateBuilder { + para_id: ParaId::from(2), relay_parent, - pov_hash: Hash::repeat_byte(6 as u8), + pov_hash: Hash::repeat_byte(5 as u8), persisted_validation_data_hash: make_persisted_validation_data_with_parent::< Test, >( RELAY_PARENT_NUM, Default::default(), - prev_candidate.commitments.head_data, + candidate_2.commitments.head_data, ) .hash(), hrmp_watermark: RELAY_PARENT_NUM, - validation_code: ValidationCode(vec![4]), + validation_code: ValidationCode(vec![2]), ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); - - let backed = back_candidate( - candidate, + let backed_3 = back_candidate( + candidate_3, &validators, - group_validators(GroupIndex::from(5 as u32)).unwrap().as_ref(), + group_validators(GroupIndex::from(4 as u32)).unwrap().as_ref(), &keystore, &signing_context, BackingKind::Threshold, - core_index_enabled.then_some(CoreIndex(5 as u32)), + core_index_enabled.then_some(CoreIndex(4 as u32)), ); - backed_candidates.push(backed.clone()); + backed_candidates.push(backed_3.clone()); } - // No candidate for para 5. - - // Para 6. + // Para 3 { - let mut candidate = TestCandidateBuilder { - para_id: ParaId::from(6), + let candidate = TestCandidateBuilder { + para_id: ParaId::from(3), relay_parent, - pov_hash: Hash::repeat_byte(3 as u8), + pov_hash: Hash::repeat_byte(6 as u8), persisted_validation_data_hash: make_persisted_validation_data::( - ParaId::from(6), + ParaId::from(3), RELAY_PARENT_NUM, Default::default(), ) .unwrap() .hash(), + head_data: HeadData(vec![3, 3]), hrmp_watermark: RELAY_PARENT_NUM, - validation_code: ValidationCode(vec![6]), + validation_code: ValidationCode(vec![3]), ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); - - let backed = back_candidate( + let prev_candidate = candidate.clone(); + let backed: BackedCandidate = back_candidate( candidate, &validators, - group_validators(GroupIndex::from(6 as u32)).unwrap().as_ref(), + group_validators(GroupIndex::from(5 as u32)).unwrap().as_ref(), &keystore, &signing_context, BackingKind::Threshold, - core_index_enabled.then_some(CoreIndex(6 as u32)), + 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(3)) + .or_insert(vec![]) + .push((backed, CoreIndex(5))); + } - // Para 7. - { - let mut candidate = TestCandidateBuilder { - para_id: ParaId::from(7), + let candidate = TestCandidateBuilder { + para_id: ParaId::from(3), relay_parent, - pov_hash: Hash::repeat_byte(3 as u8), - persisted_validation_data_hash: make_persisted_validation_data::( - ParaId::from(7), + pov_hash: Hash::repeat_byte(6 as u8), + persisted_validation_data_hash: make_persisted_validation_data_with_parent::< + Test, + >( RELAY_PARENT_NUM, Default::default(), + prev_candidate.commitments.head_data, ) - .unwrap() .hash(), hrmp_watermark: RELAY_PARENT_NUM, - validation_code: ValidationCode(vec![7]), + validation_code: ValidationCode(vec![3]), ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); - let backed = back_candidate( candidate, &validators, @@ -2394,65 +3600,80 @@ mod sanitizers { core_index_enabled.then_some(CoreIndex(6 as u32)), ); backed_candidates.push(backed.clone()); + if core_index_enabled { + expected_backed_candidates_with_core + .entry(ParaId::from(3)) + .or_insert(vec![]) + .push((backed, CoreIndex(6))); + } } - // Para 8. + // Para 4 { - let mut candidate = TestCandidateBuilder { - para_id: ParaId::from(8), + let candidate = TestCandidateBuilder { + para_id: ParaId::from(4), relay_parent, - pov_hash: Hash::repeat_byte(3 as u8), + pov_hash: Hash::repeat_byte(8 as u8), persisted_validation_data_hash: make_persisted_validation_data::( - ParaId::from(8), + ParaId::from(4), RELAY_PARENT_NUM, Default::default(), ) .unwrap() .hash(), + head_data: HeadData(vec![4]), hrmp_watermark: RELAY_PARENT_NUM, - validation_code: ValidationCode(vec![8]), + validation_code: ValidationCode(vec![4]), ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); - - let backed = back_candidate( - candidate, + let backed: BackedCandidate = back_candidate( + candidate.clone(), &validators, - group_validators(GroupIndex::from(6 as u32)).unwrap().as_ref(), + group_validators(GroupIndex::from(7 as u32)).unwrap().as_ref(), &keystore, &signing_context, BackingKind::Threshold, core_index_enabled.then_some(CoreIndex(7 as u32)), ); backed_candidates.push(backed.clone()); - if !core_index_enabled { + if core_index_enabled { expected_backed_candidates_with_core - .entry(ParaId::from(8)) + .entry(ParaId::from(4)) .or_insert(vec![]) - .push((backed, CoreIndex(9))); + .push((backed, CoreIndex(7))); } + + let backed: BackedCandidate = back_candidate( + candidate, + &validators, + group_validators(GroupIndex::from(7 as u32)).unwrap().as_ref(), + &keystore, + &signing_context, + BackingKind::Threshold, + core_index_enabled.then_some(CoreIndex(8 as u32)), + ); + backed_candidates.push(backed.clone()); } // State sanity checks assert_eq!( - scheduler::Pallet::::scheduled_paras().collect::>(), + Pallet::::eligible_paras(&Default::default()).collect::>(), vec![ (CoreIndex(0), ParaId::from(1)), (CoreIndex(1), ParaId::from(1)), (CoreIndex(2), ParaId::from(2)), (CoreIndex(3), ParaId::from(2)), - (CoreIndex(4), ParaId::from(3)), - (CoreIndex(5), ParaId::from(4)), - (CoreIndex(6), ParaId::from(5)), - (CoreIndex(7), ParaId::from(7)), - (CoreIndex(8), ParaId::from(7)), - (CoreIndex(9), ParaId::from(8)), + (CoreIndex(4), ParaId::from(2)), + (CoreIndex(5), ParaId::from(3)), + (CoreIndex(6), ParaId::from(3)), + (CoreIndex(7), ParaId::from(4)), + (CoreIndex(8), ParaId::from(4)), ] ); let mut scheduled: BTreeMap> = BTreeMap::new(); - for (core_idx, para_id) in scheduler::Pallet::::scheduled_paras() { + for (core_idx, para_id) in Pallet::::eligible_paras(&Default::default()) { scheduled.entry(para_id).or_default().insert(core_idx); } @@ -2467,6 +3688,7 @@ mod sanitizers { ValidatorIndex(5), ValidatorIndex(6), ValidatorIndex(7), + ValidatorIndex(8), ] ); @@ -2477,26 +3699,59 @@ mod sanitizers { } } - // Para 1 scheduled on core 0 and core 1. Two candidates are supplied. They form a chain but - // in the wrong order. - // Para 2 scheduled on core 2, core 3 and core 4. Three candidates are supplied. The second - // one is not part of the chain. - // Para 3 scheduled on core 5 and 6. Two candidates are supplied and they all form a chain. - // Para 4 scheduled on core 7 and 8. Duplicated candidates. - fn get_test_data_for_order_checks(core_index_enabled: bool) -> TestData { + // 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( - default_header().hash(), + prev_relay_parent, + Default::default(), + Default::default(), + RELAY_PARENT_NUM - 1, + 2, + ); + + shared::Pallet::::add_allowed_relay_parent( + relay_parent, + Default::default(), Default::default(), RELAY_PARENT_NUM, - 1, + 2, + ); + + shared::Pallet::::add_allowed_relay_parent( + next_relay_parent, + Default::default(), + Default::default(), + RELAY_PARENT_NUM + 1, + 2, ); - let header = default_header(); - let relay_parent = header.hash(); let session_index = SessionIndex::from(0_u32); let keystore = LocalKeystore::in_memory(); @@ -2510,9 +3765,6 @@ mod sanitizers { sp_keyring::Sr25519Keyring::Dave, sp_keyring::Sr25519Keyring::Eve, sp_keyring::Sr25519Keyring::Ferdie, - sp_keyring::Sr25519Keyring::One, - sp_keyring::Sr25519Keyring::Two, - sp_keyring::Sr25519Keyring::AliceStash, ]; for validator in validators.iter() { Keystore::sr25519_generate_new( @@ -2536,80 +3788,56 @@ mod sanitizers { vec![ValidatorIndex(3)], vec![ValidatorIndex(4)], vec![ValidatorIndex(5)], - vec![ValidatorIndex(6)], - vec![ValidatorIndex(7)], - vec![ValidatorIndex(8)], ]); // 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, - )]), + VecDeque::from([Assignment::Pool { + para_id: 1.into(), + core_index: CoreIndex(0), + }]), ), ( CoreIndex::from(1), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 1.into(), core_index: CoreIndex(1) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 1.into(), + core_index: CoreIndex(1), + }]), ), ( CoreIndex::from(2), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(2) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 1.into(), + core_index: CoreIndex(2), + }]), ), ( CoreIndex::from(3), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(3) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 2.into(), + core_index: CoreIndex(3), + }]), ), ( CoreIndex::from(4), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 2.into(), core_index: CoreIndex(4) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 2.into(), + core_index: CoreIndex(4), + }]), ), ( CoreIndex::from(5), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 3.into(), core_index: CoreIndex(5) }, - RELAY_PARENT_NUM, - )]), - ), - ( - CoreIndex::from(6), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 3.into(), core_index: CoreIndex(6) }, - RELAY_PARENT_NUM, - )]), - ), - ( - CoreIndex::from(7), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 4.into(), core_index: CoreIndex(7) }, - RELAY_PARENT_NUM, - )]), - ), - ( - CoreIndex::from(8), - VecDeque::from([ParasEntry::new( - Assignment::Pool { para_id: 4.into(), core_index: CoreIndex(8) }, - RELAY_PARENT_NUM, - )]), + VecDeque::from([Assignment::Pool { + para_id: 2.into(), + core_index: CoreIndex(5), + }]), ), ])); // Set the on-chain included head data and current code hash. - for id in 1..=4u32 { + 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(), @@ -2617,24 +3845,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![]; @@ -2642,7 +3867,7 @@ mod sanitizers { // Para 1 { - let mut candidate = TestCandidateBuilder { + let candidate = TestCandidateBuilder { para_id: ParaId::from(1), relay_parent, pov_hash: Hash::repeat_byte(1 as u8), @@ -2653,206 +3878,135 @@ mod sanitizers { ) .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 prev_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)), - ); - - let mut candidate = TestCandidateBuilder { - para_id: ParaId::from(1), - 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![1]), - ..Default::default() - } - .build(); - - collator_sign_candidate(Sr25519Keyring::One, &mut candidate); - - 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()); - backed_candidates.push(prev_backed.clone()); - } - - // Para 2. - { - let mut candidate_1 = TestCandidateBuilder { - para_id: ParaId::from(2), - relay_parent, - pov_hash: Hash::repeat_byte(3 as u8), - persisted_validation_data_hash: make_persisted_validation_data::( - ParaId::from(2), - RELAY_PARENT_NUM, - Default::default(), - ) - .unwrap() - .hash(), - head_data: HeadData(vec![2, 2]), + head_data: HeadData(vec![1, 1]), hrmp_watermark: RELAY_PARENT_NUM, - validation_code: ValidationCode(vec![2]), + validation_code: ValidationCode(vec![1]), ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate_1); - - let backed_1: BackedCandidate = back_candidate( - candidate_1, + let prev_candidate = candidate.clone(); + let backed: BackedCandidate = back_candidate( + candidate, &validators, - group_validators(GroupIndex::from(2 as u32)).unwrap().as_ref(), + group_validators(GroupIndex::from(0 as u32)).unwrap().as_ref(), &keystore, &signing_context, BackingKind::Threshold, - core_index_enabled.then_some(CoreIndex(2 as u32)), + core_index_enabled.then_some(CoreIndex(0 as u32)), ); - - backed_candidates.push(backed_1.clone()); + backed_candidates.push(backed.clone()); if core_index_enabled { expected_backed_candidates_with_core - .entry(ParaId::from(2)) + .entry(ParaId::from(1)) .or_insert(vec![]) - .push((backed_1, CoreIndex(2))); + .push((backed, CoreIndex(0))); } - let mut candidate_2 = TestCandidateBuilder { - para_id: ParaId::from(2), - relay_parent, - pov_hash: Hash::repeat_byte(4 as u8), - persisted_validation_data_hash: make_persisted_validation_data::( - ParaId::from(2), - RELAY_PARENT_NUM, + let 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, ) - .unwrap() .hash(), - hrmp_watermark: RELAY_PARENT_NUM, - validation_code: ValidationCode(vec![2]), - head_data: HeadData(vec![3, 3]), + 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_2); - - let backed_2 = back_candidate( - candidate_2.clone(), + let prev_candidate = candidate.clone(); + let backed = back_candidate( + candidate, &validators, - group_validators(GroupIndex::from(3 as u32)).unwrap().as_ref(), + group_validators(GroupIndex::from(1 as u32)).unwrap().as_ref(), &keystore, &signing_context, BackingKind::Threshold, - core_index_enabled.then_some(CoreIndex(3 as u32)), + core_index_enabled.then_some(CoreIndex(1 as u32)), ); - backed_candidates.push(backed_2.clone()); + backed_candidates.push(backed.clone()); - let mut candidate_3 = TestCandidateBuilder { - para_id: ParaId::from(2), + let candidate = TestCandidateBuilder { + para_id: ParaId::from(1), relay_parent, - pov_hash: Hash::repeat_byte(5 as u8), + pov_hash: Hash::repeat_byte(1 as u8), persisted_validation_data_hash: make_persisted_validation_data_with_parent::< Test, >( RELAY_PARENT_NUM, Default::default(), - candidate_2.commitments.head_data, + prev_candidate.commitments.head_data, ) .hash(), hrmp_watermark: RELAY_PARENT_NUM, - validation_code: ValidationCode(vec![2]), + validation_code: ValidationCode(vec![1]), + head_data: HeadData(vec![1, 1, 1, 1]), ..Default::default() } .build(); - collator_sign_candidate(Sr25519Keyring::One, &mut candidate_3); - - let backed_3 = back_candidate( - candidate_3, + let backed = back_candidate( + candidate, &validators, - group_validators(GroupIndex::from(4 as u32)).unwrap().as_ref(), + group_validators(GroupIndex::from(2 as u32)).unwrap().as_ref(), &keystore, &signing_context, BackingKind::Threshold, - core_index_enabled.then_some(CoreIndex(4 as u32)), + core_index_enabled.then_some(CoreIndex(2 as u32)), ); - backed_candidates.push(backed_3.clone()); + backed_candidates.push(backed.clone()); } - // Para 3 + // Para 2 { - let mut candidate = TestCandidateBuilder { - para_id: ParaId::from(3), - relay_parent, - pov_hash: Hash::repeat_byte(6 as u8), + let 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(3), - RELAY_PARENT_NUM, + ParaId::from(2), + RELAY_PARENT_NUM - 1, Default::default(), ) .unwrap() .hash(), - head_data: HeadData(vec![3, 3]), - hrmp_watermark: RELAY_PARENT_NUM, - validation_code: ValidationCode(vec![3]), + 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(5 as u32)).unwrap().as_ref(), + group_validators(GroupIndex::from(3 as u32)).unwrap().as_ref(), &keystore, &signing_context, BackingKind::Threshold, - core_index_enabled.then_some(CoreIndex(5 as u32)), + 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(3)) + .entry(ParaId::from(2)) .or_insert(vec![]) - .push((backed, CoreIndex(5))); + .push((backed, CoreIndex(3))); } - let mut candidate = TestCandidateBuilder { - para_id: ParaId::from(3), + let candidate = TestCandidateBuilder { + para_id: ParaId::from(2), relay_parent, - pov_hash: Hash::repeat_byte(6 as u8), + pov_hash: Hash::repeat_byte(2 as u8), persisted_validation_data_hash: make_persisted_validation_data_with_parent::< Test, >( @@ -2862,99 +4016,82 @@ mod sanitizers { ) .hash(), hrmp_watermark: RELAY_PARENT_NUM, - validation_code: ValidationCode(vec![3]), + 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(6 as u32)).unwrap().as_ref(), + group_validators(GroupIndex::from(4 as u32)).unwrap().as_ref(), &keystore, &signing_context, BackingKind::Threshold, - core_index_enabled.then_some(CoreIndex(6 as u32)), + 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(3)) + .entry(ParaId::from(2)) .or_insert(vec![]) - .push((backed, CoreIndex(6))); + .push((backed, CoreIndex(4))); } - } - // Para 4 - { - let mut candidate = TestCandidateBuilder { - para_id: ParaId::from(4), + let candidate = TestCandidateBuilder { + para_id: ParaId::from(2), relay_parent, - pov_hash: Hash::repeat_byte(8 as u8), - persisted_validation_data_hash: make_persisted_validation_data::( - ParaId::from(4), + 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, ) - .unwrap() .hash(), - head_data: HeadData(vec![4]), hrmp_watermark: RELAY_PARENT_NUM, - validation_code: ValidationCode(vec![4]), + 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: BackedCandidate = back_candidate( - candidate.clone(), + let backed = back_candidate( + candidate, &validators, - group_validators(GroupIndex::from(7 as u32)).unwrap().as_ref(), + group_validators(GroupIndex::from(5 as u32)).unwrap().as_ref(), &keystore, &signing_context, BackingKind::Threshold, - core_index_enabled.then_some(CoreIndex(7 as u32)), + 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(4)) + .entry(ParaId::from(2)) .or_insert(vec![]) - .push((backed, CoreIndex(7))); + .push((backed, CoreIndex(5))); } - - let backed: BackedCandidate = back_candidate( - candidate, - &validators, - group_validators(GroupIndex::from(7 as u32)).unwrap().as_ref(), - &keystore, - &signing_context, - BackingKind::Threshold, - core_index_enabled.then_some(CoreIndex(8 as u32)), - ); - backed_candidates.push(backed.clone()); } // State sanity checks assert_eq!( - scheduler::Pallet::::scheduled_paras().collect::>(), + Pallet::::eligible_paras(&Default::default()).collect::>(), vec![ (CoreIndex(0), ParaId::from(1)), (CoreIndex(1), ParaId::from(1)), - (CoreIndex(2), ParaId::from(2)), + (CoreIndex(2), ParaId::from(1)), (CoreIndex(3), ParaId::from(2)), (CoreIndex(4), ParaId::from(2)), - (CoreIndex(5), ParaId::from(3)), - (CoreIndex(6), ParaId::from(3)), - (CoreIndex(7), ParaId::from(4)), - (CoreIndex(8), ParaId::from(4)), + (CoreIndex(5), ParaId::from(2)), ] ); let mut scheduled: BTreeMap> = BTreeMap::new(); - for (core_idx, para_id) in scheduler::Pallet::::scheduled_paras() { + for (core_idx, para_id) in Pallet::::eligible_paras(&Default::default()) { scheduled.entry(para_id).or_default().insert(core_idx); } @@ -2966,10 +4103,7 @@ mod sanitizers { ValidatorIndex(2), ValidatorIndex(3), ValidatorIndex(4), - ValidatorIndex(5), - ValidatorIndex(6), - ValidatorIndex(7), - ValidatorIndex(8), + ValidatorIndex(5) ] ); @@ -2997,7 +4131,8 @@ mod sanitizers { &shared::AllowedRelayParents::::get(), BTreeSet::new(), scheduled, - core_index_enabled + core_index_enabled, + false, ), expected_backed_candidates_with_core, ); @@ -3005,15 +4140,20 @@ mod sanitizers { } #[rstest] - #[case(false)] - #[case(true)] - fn test_with_multiple_cores_per_para(#[case] core_index_enabled: bool) { + #[case(false, false)] + #[case(true, false)] + #[case(false, true)] + #[case(true, true)] + fn test_with_multiple_cores_per_para( + #[case] core_index_enabled: bool, + #[case] v2_descriptor: bool, + ) { new_test_ext(default_config()).execute_with(|| { let TestData { backed_candidates, expected_backed_candidates_with_core, scheduled_paras: scheduled, - } = get_test_data_multiple_cores_per_para(core_index_enabled); + } = get_test_data_multiple_cores_per_para(core_index_enabled, v2_descriptor); assert_eq!( sanitize_backed_candidates::( @@ -3021,7 +4161,8 @@ mod sanitizers { &shared::AllowedRelayParents::::get(), BTreeSet::new(), scheduled, - core_index_enabled + core_index_enabled, + v2_descriptor, ), expected_backed_candidates_with_core, ); @@ -3046,25 +4187,184 @@ mod sanitizers { BTreeSet::new(), scheduled, core_index_enabled, + false, + ), + expected_backed_candidates_with_core + ); + }); + } + + #[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, + false, ), 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, + false, + ); + + 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, + false, + ); + + 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)] - #[case(true, true)] - #[case(false, true)] - #[case(true, false)] + #[case(false, false, true)] + #[case(true, true, true)] + #[case(false, true, true)] + #[case(true, false, true)] + #[case(false, false, false)] + #[case(true, true, false)] + #[case(false, true, false)] + #[case(true, false, false)] fn nothing_scheduled( #[case] core_index_enabled: bool, #[case] multiple_cores_per_para: bool, + #[case] v2_descriptor: bool, ) { new_test_ext(default_config()).execute_with(|| { let TestData { backed_candidates, .. } = if multiple_cores_per_para { - get_test_data_multiple_cores_per_para(core_index_enabled) + get_test_data_multiple_cores_per_para(core_index_enabled, v2_descriptor) } else { get_test_data_one_core_per_para(core_index_enabled) }; @@ -3076,6 +4376,7 @@ mod sanitizers { BTreeSet::new(), scheduled, core_index_enabled, + false, ); assert!(sanitized_backed_candidates.is_empty()); @@ -3112,6 +4413,7 @@ mod sanitizers { set, scheduled, core_index_enabled, + false, ); assert_eq!(sanitized_backed_candidates.len(), backed_candidates.len() / 2); @@ -3119,8 +4421,14 @@ mod sanitizers { } // candidates that have concluded as invalid are filtered out, as well as their descendants. - #[test] - fn concluded_invalid_are_filtered_out_multiple_cores_per_para() { + #[rstest] + #[case(false, true)] + #[case(true, false)] + #[case(true, true)] + fn concluded_invalid_are_filtered_out_multiple_cores_per_para( + #[case] core_index_enabled: bool, + #[case] v2_descriptor: bool, + ) { // Mark the first candidate of paraid 1 as invalid. Its descendant should also // be dropped. Also mark the candidate of paraid 3 as invalid. new_test_ext(default_config()).execute_with(|| { @@ -3129,14 +4437,14 @@ mod sanitizers { scheduled_paras: scheduled, mut expected_backed_candidates_with_core, .. - } = get_test_data_multiple_cores_per_para(true); + } = get_test_data_multiple_cores_per_para(core_index_enabled, v2_descriptor); let mut invalid_set = std::collections::BTreeSet::new(); for (idx, backed_candidate) in backed_candidates.iter().enumerate() { - if backed_candidate.descriptor().para_id == ParaId::from(1) && idx == 0 { + if backed_candidate.descriptor().para_id() == ParaId::from(1) && idx == 0 { invalid_set.insert(backed_candidate.hash()); - } else if backed_candidate.descriptor().para_id == ParaId::from(3) { + } else if backed_candidate.descriptor().para_id() == ParaId::from(3) { invalid_set.insert(backed_candidate.hash()); } } @@ -3148,7 +4456,8 @@ mod sanitizers { &shared::AllowedRelayParents::::get(), invalid_set, scheduled, - true, + core_index_enabled, + v2_descriptor, ); // We'll be left with candidates from paraid 2 and 4. @@ -3167,12 +4476,12 @@ mod sanitizers { scheduled_paras: scheduled, mut expected_backed_candidates_with_core, .. - } = get_test_data_multiple_cores_per_para(true); + } = get_test_data_multiple_cores_per_para(core_index_enabled, v2_descriptor); let mut invalid_set = std::collections::BTreeSet::new(); for (idx, backed_candidate) in backed_candidates.iter().enumerate() { - if backed_candidate.descriptor().para_id == ParaId::from(1) && idx == 1 { + if backed_candidate.descriptor().para_id() == ParaId::from(1) && idx == 1 { invalid_set.insert(backed_candidate.hash()); } } @@ -3184,7 +4493,8 @@ mod sanitizers { &shared::AllowedRelayParents::::get(), invalid_set, scheduled, - true, + core_index_enabled, + v2_descriptor, ); // Only the second candidate of paraid 1 should be removed. @@ -3395,7 +4705,7 @@ mod sanitizers { // Disable Bob, only the second candidate of paraid 1 should be removed. new_test_ext(default_config()).execute_with(|| { let TestData { mut expected_backed_candidates_with_core, .. } = - get_test_data_multiple_cores_per_para(true); + get_test_data_multiple_cores_per_para(true, false); set_disabled_validators(vec![1]); @@ -3417,7 +4727,7 @@ mod sanitizers { for disabled in [vec![0], vec![0, 1]] { new_test_ext(default_config()).execute_with(|| { let TestData { mut expected_backed_candidates_with_core, .. } = - get_test_data_multiple_cores_per_para(true); + get_test_data_multiple_cores_per_para(true, false); set_disabled_validators(disabled); diff --git a/polkadot/runtime/parachains/src/paras_inherent/weights.rs b/polkadot/runtime/parachains/src/paras_inherent/weights.rs index 37809396a823..81c926a90e0b 100644 --- a/polkadot/runtime/parachains/src/paras_inherent/weights.rs +++ b/polkadot/runtime/parachains/src/paras_inherent/weights.rs @@ -19,6 +19,7 @@ //! the relay chain, but we do care about the size of the block, by putting the tx in the //! proof_size we can use the already existing weight limiting code to limit the used size as well. +use crate::{configuration, inclusion}; use codec::{Encode, WrapperTypeEncode}; use polkadot_primitives::{ CheckedMultiDisputeStatementSet, MultiDisputeStatementSet, UncheckedSignedAvailabilityBitfield, @@ -28,6 +29,8 @@ use polkadot_primitives::{ use super::{BackedCandidate, Config, DisputeStatementSet, Weight}; pub trait WeightInfo { + /// The weight of processing an empty parachain inherent. + fn enter_empty() -> Weight; /// Variant over `v`, the count of dispute statements in a dispute statement set. This gives the /// weight of a single dispute statement set. fn enter_variable_disputes(v: u32) -> Weight; @@ -45,6 +48,9 @@ pub struct TestWeightInfo; // mock. #[cfg(not(feature = "runtime-benchmarks"))] impl WeightInfo for TestWeightInfo { + fn enter_empty() -> Weight { + Weight::zero() + } fn enter_variable_disputes(v: u32) -> Weight { // MAX Block Weight should fit 4 disputes Weight::from_parts(80_000 * v as u64 + 80_000, 0) @@ -66,6 +72,9 @@ impl WeightInfo for TestWeightInfo { // running as a test. #[cfg(feature = "runtime-benchmarks")] impl WeightInfo for TestWeightInfo { + fn enter_empty() -> Weight { + Weight::zero() + } fn enter_variable_disputes(_v: u32) -> Weight { Weight::zero() } @@ -88,6 +97,7 @@ pub fn paras_inherent_total_weight( backed_candidates_weight::(backed_candidates) .saturating_add(signed_bitfields_weight::(bitfields)) .saturating_add(multi_dispute_statement_sets_weight::(disputes)) + .saturating_add(enact_candidates_max_weight::(bitfields)) } pub fn multi_dispute_statement_sets_weight( @@ -123,7 +133,8 @@ where set_proof_size_to_tx_size( <::WeightInfo as WeightInfo>::enter_variable_disputes( statement_set.as_ref().statements.len() as u32, - ), + ) + .saturating_sub(<::WeightInfo as WeightInfo>::enter_empty()), statement_set, ) } @@ -133,6 +144,7 @@ pub fn signed_bitfields_weight( ) -> Weight { set_proof_size_to_tx_size( <::WeightInfo as WeightInfo>::enter_bitfields() + .saturating_sub(<::WeightInfo as WeightInfo>::enter_empty()) .saturating_mul(bitfields.len() as u64), bitfields, ) @@ -140,11 +152,33 @@ pub fn signed_bitfields_weight( pub fn signed_bitfield_weight(bitfield: &UncheckedSignedAvailabilityBitfield) -> Weight { set_proof_size_to_tx_size( - <::WeightInfo as WeightInfo>::enter_bitfields(), + <::WeightInfo as WeightInfo>::enter_bitfields() + .saturating_sub(<::WeightInfo as WeightInfo>::enter_empty()), bitfield, ) } +/// Worst case scenario is all candidates have been enacted +/// and process a maximum number of messages. +pub fn enact_candidates_max_weight( + bitfields: &UncheckedSignedAvailabilityBitfields, +) -> Weight { + let config = configuration::ActiveConfig::::get(); + let max_ump_msgs = config.max_upward_message_num_per_candidate; + let max_hrmp_msgs = config.hrmp_max_message_num_per_candidate; + // No bitfields - no enacted candidates + let bitfield_size = bitfields.first().map(|b| b.unchecked_payload().0.len()).unwrap_or(0); + set_proof_size_to_tx_size( + <::WeightInfo as inclusion::WeightInfo>::enact_candidate( + max_ump_msgs, + max_hrmp_msgs, + 1, // runtime upgrade + ) + .saturating_mul(bitfield_size as u64), + bitfields, + ) +} + pub fn backed_candidate_weight( candidate: &BackedCandidate, ) -> Weight { @@ -155,7 +189,8 @@ pub fn backed_candidate_weight( <::WeightInfo as WeightInfo>::enter_backed_candidates_variable( candidate.validity_votes().len() as u32, ) - }, + } + .saturating_sub(<::WeightInfo as WeightInfo>::enter_empty()), candidate, ) } diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs b/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs index ed2e95b3cfa9..ad80856e2393 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/mod.rs @@ -26,5 +26,5 @@ //! 2. Move methods from `vstaging` to `v3`. The new stable version should include all methods from //! `vstaging` tagged with the new version number (e.g. all `v3` methods). -pub mod v10; +pub mod v11; pub mod vstaging; diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/v10.rs b/polkadot/runtime/parachains/src/runtime_api_impl/v11.rs similarity index 81% rename from polkadot/runtime/parachains/src/runtime_api_impl/v10.rs rename to polkadot/runtime/parachains/src/runtime_api_impl/v11.rs index 697890232211..e9327bc7641a 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/v10.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/v11.rs @@ -14,28 +14,35 @@ //! A module exporting runtime API implementation functions for all runtime APIs using `v5` //! primitives. //! -//! Runtimes implementing the v10 runtime API are recommended to forward directly to these +//! Runtimes implementing the v11 runtime API are recommended to forward directly to these //! functions. use crate::{ - configuration, disputes, dmp, hrmp, inclusion, initializer, paras, paras_inherent, - scheduler::{self, CoreOccupied}, + configuration, disputes, dmp, hrmp, inclusion, initializer, paras, paras_inherent, scheduler, session_info, shared, }; -use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec}; +use alloc::{ + collections::{btree_map::BTreeMap, vec_deque::VecDeque}, + vec, + vec::Vec, +}; use frame_support::traits::{GetStorageVersion, StorageVersion}; use frame_system::pallet_prelude::*; use polkadot_primitives::{ async_backing::{ - AsyncBackingParams, BackingState, CandidatePendingAvailability, Constraints, - InboundHrmpLimitations, OutboundHrmpChannelLimitations, + AsyncBackingParams, Constraints, InboundHrmpLimitations, OutboundHrmpChannelLimitations, + }, + slashing, + vstaging::{ + async_backing::{BackingState, CandidatePendingAvailability}, + CandidateEvent, CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CoreState, + OccupiedCore, ScrapedOnChainVotes, }, - slashing, ApprovalVotingParams, AuthorityDiscoveryId, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, GroupIndex, - GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, - NodeFeatures, OccupiedCore, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, - ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, - ValidatorId, ValidatorIndex, ValidatorSignature, + ApprovalVotingParams, AuthorityDiscoveryId, CandidateHash, CoreIndex, DisputeState, + ExecutorParams, GroupIndex, GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, + InboundHrmpMessage, NodeFeatures, OccupiedCoreAssumption, PersistedValidationData, + PvfCheckStatement, SessionIndex, SessionInfo, ValidationCode, ValidationCodeHash, ValidatorId, + ValidatorIndex, ValidatorSignature, }; use sp_runtime::traits::One; @@ -59,15 +66,6 @@ pub fn validator_groups( /// Implementation for the `availability_cores` function of the runtime API. pub fn availability_cores() -> Vec>> { - let cores = scheduler::AvailabilityCores::::get(); - let now = frame_system::Pallet::::block_number() + One::one(); - - // This explicit update is only strictly required for session boundaries: - // - // At the end of a session we clear the claim queues: Without this update call, nothing would be - // scheduled to the client. - scheduler::Pallet::::free_cores_and_fill_claim_queue(Vec::new(), now); - let time_out_for = scheduler::Pallet::::availability_timeout_predicate(); let group_responsible_for = @@ -87,76 +85,42 @@ pub fn availability_cores() -> Vec = scheduler::Pallet::::scheduled_paras().collect(); - - cores - .into_iter() - .enumerate() - .map(|(i, core)| match core { - CoreOccupied::Paras(entry) => { - // Due to https://github.com/paritytech/polkadot-sdk/issues/64, using the new storage types would cause - // this runtime API to panic. We explicitly handle the storage for version 0 to - // prevent that. When removing the inclusion v0 -> v1 migration, this bit of code - // can also be removed. - let pending_availability = if inclusion::Pallet::::on_chain_storage_version() == - StorageVersion::new(0) - { - inclusion::migration::v0::PendingAvailability::::get(entry.para_id()) - .expect("Occupied core always has pending availability; qed") - } else { - let candidate = inclusion::Pallet::::pending_availability_with_core( - entry.para_id(), - CoreIndex(i as u32), - ) - .expect("Occupied core always has pending availability; qed"); - - // Translate to the old candidate format, as we don't need the commitments now. - inclusion::migration::v0::CandidatePendingAvailability { - core: candidate.core_occupied(), - hash: candidate.candidate_hash(), - descriptor: candidate.candidate_descriptor().clone(), - availability_votes: candidate.availability_votes().clone(), - backers: candidate.backers().clone(), - relay_parent_number: candidate.relay_parent_number(), - backed_in_number: candidate.backed_in_number(), - backing_group: candidate.backing_group(), - } - }; - - let backed_in_number = pending_availability.backed_in_number; + let claim_queue = scheduler::Pallet::::get_claim_queue(); + let occupied_cores: BTreeMap> = + inclusion::Pallet::::get_occupied_cores().collect(); + let n_cores = scheduler::Pallet::::num_availability_cores(); + (0..n_cores) + .map(|core_idx| { + let core_idx = CoreIndex(core_idx as u32); + if let Some(pending_availability) = occupied_cores.get(&core_idx) { // Use the same block number for determining the responsible group as what the // backing subsystem would use when it calls validator_groups api. let backing_group_allocation_time = - pending_availability.relay_parent_number + One::one(); + pending_availability.relay_parent_number() + One::one(); CoreState::Occupied(OccupiedCore { - next_up_on_available: scheduler::Pallet::::next_up_on_available(CoreIndex( - i as u32, - )), - occupied_since: backed_in_number, - time_out_at: time_out_for(backed_in_number).live_until, - next_up_on_time_out: scheduler::Pallet::::next_up_on_time_out(CoreIndex( - i as u32, - )), - availability: pending_availability.availability_votes.clone(), + next_up_on_available: scheduler::Pallet::::next_up_on_available(core_idx), + occupied_since: pending_availability.backed_in_number(), + time_out_at: time_out_for(pending_availability.backed_in_number()).live_until, + next_up_on_time_out: scheduler::Pallet::::next_up_on_available(core_idx), + availability: pending_availability.availability_votes().clone(), group_responsible: group_responsible_for( backing_group_allocation_time, - pending_availability.core, + pending_availability.core_occupied(), ), - candidate_hash: pending_availability.hash, - candidate_descriptor: pending_availability.descriptor, + candidate_hash: pending_availability.candidate_hash(), + candidate_descriptor: pending_availability.candidate_descriptor().clone(), }) - }, - CoreOccupied::Free => { - if let Some(para_id) = scheduled.get(&CoreIndex(i as _)).cloned() { + } else { + if let Some(assignment) = claim_queue.get(&core_idx).and_then(|q| q.front()) { CoreState::Scheduled(polkadot_primitives::ScheduledCore { - para_id, + para_id: assignment.para_id(), collator: None, }) } else { CoreState::Free } - }, + } }) .collect() } @@ -187,13 +151,12 @@ where build() }, OccupiedCoreAssumption::TimedOut => build(), - OccupiedCoreAssumption::Free => { - if >::pending_availability(para_id).is_some() { + OccupiedCoreAssumption::Free => + if !>::candidates_pending_availability(para_id).is_empty() { None } else { build() - } - }, + }, } } @@ -232,10 +195,12 @@ pub fn assumed_validation_data( let persisted_validation_data = make_validation_data().or_else(|| { // Try again with force enacting the pending candidates. This check only makes sense if // there are any pending candidates. - inclusion::Pallet::::pending_availability(para_id).and_then(|_| { - inclusion::Pallet::::force_enact(para_id); - make_validation_data() - }) + (!inclusion::Pallet::::candidates_pending_availability(para_id).is_empty()) + .then_some(()) + .and_then(|_| { + inclusion::Pallet::::force_enact(para_id); + make_validation_data() + }) }); // If we were successful, also query current validation code hash. persisted_validation_data.zip(paras::CurrentCodeHash::::get(¶_id)) @@ -311,7 +276,7 @@ pub fn validation_code( pub fn candidate_pending_availability( para_id: ParaId, ) -> Option> { - inclusion::Pallet::::candidate_pending_availability(para_id) + inclusion::Pallet::::first_candidate_pending_availability(para_id) } /// Implementation for the `candidate_events` function of the runtime API. @@ -447,8 +412,22 @@ pub fn backing_state( // // Thus, minimum relay parent is ensured to have asynchronous backing enabled. let now = frame_system::Pallet::::block_number(); - let min_relay_parent_number = shared::AllowedRelayParents::::get() - .hypothetical_earliest_block_number(now, config.async_backing_params.allowed_ancestry_len); + + // Use the right storage depending on version to ensure #64 doesn't cause issues with this + // migration. + let min_relay_parent_number = if shared::Pallet::::on_chain_storage_version() == + StorageVersion::new(0) + { + shared::migration::v0::AllowedRelayParents::::get().hypothetical_earliest_block_number( + now, + config.async_backing_params.allowed_ancestry_len, + ) + } else { + shared::AllowedRelayParents::::get().hypothetical_earliest_block_number( + now, + config.async_backing_params.allowed_ancestry_len, + ) + }; let required_parent = paras::Heads::::get(para_id)?; let validation_code_hash = paras::CurrentCodeHash::::get(para_id)?; @@ -543,3 +522,27 @@ pub fn node_features() -> NodeFeatures { pub fn approval_voting_params() -> ApprovalVotingParams { configuration::ActiveConfig::::get().approval_voting_params } + +/// Returns the claimqueue from the scheduler +pub fn claim_queue() -> BTreeMap> { + let config = configuration::ActiveConfig::::get(); + // Extra sanity, config should already never be smaller than 1: + let n_lookahead = config.scheduler_params.lookahead.max(1); + scheduler::Pallet::::get_claim_queue() + .into_iter() + .map(|(core_index, entries)| { + ( + core_index, + entries.into_iter().map(|e| e.para_id()).take(n_lookahead as usize).collect(), + ) + }) + .collect() +} + +/// Returns all the candidates that are pending availability for a given `ParaId`. +/// Deprecates `candidate_pending_availability` in favor of supporting elastic scaling. +pub fn candidates_pending_availability( + para_id: ParaId, +) -> Vec> { + >::candidates_pending_availability(para_id) +} diff --git a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs index 4aa381e33b1b..d01b543630c3 100644 --- a/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs +++ b/polkadot/runtime/parachains/src/runtime_api_impl/vstaging.rs @@ -15,46 +15,3 @@ // along with Polkadot. If not, see . //! Put implementations of functions from staging APIs here. - -use crate::{configuration, inclusion, initializer, scheduler}; -use alloc::{ - collections::{btree_map::BTreeMap, vec_deque::VecDeque}, - vec::Vec, -}; -use polkadot_primitives::{CommittedCandidateReceipt, CoreIndex, Id as ParaId}; -use sp_runtime::traits::One; - -/// Returns the claimqueue from the scheduler -pub fn claim_queue() -> BTreeMap> { - let now = >::block_number() + One::one(); - - // This is needed so that the claim queue always has the right size (equal to - // scheduling_lookahead). Otherwise, if a candidate is backed in the same block where the - // previous candidate is included, the claim queue will have already pop()-ed the next item - // from the queue and the length would be `scheduling_lookahead - 1`. - >::free_cores_and_fill_claim_queue(Vec::new(), now); - let config = configuration::ActiveConfig::::get(); - // Extra sanity, config should already never be smaller than 1: - let n_lookahead = config.scheduler_params.lookahead.max(1); - - scheduler::ClaimQueue::::get() - .into_iter() - .map(|(core_index, entries)| { - // on cores timing out internal claim queue size may be temporarily longer than it - // should be as the timed out assignment might got pushed back to an already full claim - // queue: - ( - core_index, - entries.into_iter().map(|e| e.para_id()).take(n_lookahead as usize).collect(), - ) - }) - .collect() -} - -/// Returns all the candidates that are pending availability for a given `ParaId`. -/// Deprecates `candidate_pending_availability` in favor of supporting elastic scaling. -pub fn candidates_pending_availability( - para_id: ParaId, -) -> Vec> { - >::candidates_pending_availability(para_id) -} diff --git a/polkadot/runtime/parachains/src/scheduler.rs b/polkadot/runtime/parachains/src/scheduler.rs index 445583d929ab..329df3a8a9de 100644 --- a/polkadot/runtime/parachains/src/scheduler.rs +++ b/polkadot/runtime/parachains/src/scheduler.rs @@ -36,14 +36,9 @@ //! number of groups as availability cores. Validator groups will be assigned to different //! availability cores over time. -use core::iter::Peekable; - use crate::{configuration, initializer::SessionChangeNotification, paras}; use alloc::{ - collections::{ - btree_map::{self, BTreeMap}, - vec_deque::VecDeque, - }, + collections::{btree_map::BTreeMap, btree_set::BTreeSet, vec_deque::VecDeque}, vec::Vec, }; use frame_support::{pallet_prelude::*, traits::Defensive}; @@ -71,7 +66,7 @@ pub mod migration; pub mod pallet { use super::*; - const STORAGE_VERSION: StorageVersion = StorageVersion::new(2); + const STORAGE_VERSION: StorageVersion = StorageVersion::new(3); #[pallet::pallet] #[pallet::without_storage_info] @@ -93,47 +88,6 @@ pub mod pallet { #[pallet::storage] pub type ValidatorGroups = StorageValue<_, Vec>, ValueQuery>; - /// One entry for each availability core. The i'th parachain belongs to the i'th core, with the - /// remaining cores all being on demand parachain multiplexers. - /// - /// Bounded by the maximum of either of these two values: - /// * The number of parachains and parathread multiplexers - /// * The number of validators divided by `configuration.max_validators_per_core`. - #[pallet::storage] - pub type AvailabilityCores = StorageValue<_, Vec>, ValueQuery>; - - /// Representation of a core in `AvailabilityCores`. - /// - /// This is not to be confused with `CoreState` which is an enriched variant of this and exposed - /// to the node side. It also provides information about scheduled/upcoming assignments for - /// example and is computed on the fly in the `availability_cores` runtime call. - #[derive(Encode, Decode, TypeInfo, RuntimeDebug, PartialEq)] - pub enum CoreOccupied { - /// No candidate is waiting availability on this core right now (the core is not occupied). - Free, - /// A para is currently waiting for availability/inclusion on this core. - Paras(ParasEntry), - } - - /// Convenience type alias for `CoreOccupied`. - pub type CoreOccupiedType = CoreOccupied>; - - impl CoreOccupied { - /// Is core free? - pub fn is_free(&self) -> bool { - matches!(self, Self::Free) - } - } - - /// Reasons a core might be freed. - #[derive(Clone, Copy)] - pub enum FreedReason { - /// The core's work concluded and the parablock assigned to it is considered available. - Concluded, - /// The core's work timed out. - TimedOut, - } - /// The block number where the session start occurred. Used to track how many group rotations /// have occurred. /// @@ -145,40 +99,9 @@ pub mod pallet { pub type SessionStartBlock = StorageValue<_, BlockNumberFor, ValueQuery>; /// One entry for each availability core. The `VecDeque` represents the assignments to be - /// scheduled on that core. The value contained here will not be valid after the end of - /// a block. Runtime APIs should be used to determine scheduled cores for the upcoming block. + /// scheduled on that core. #[pallet::storage] - pub type ClaimQueue = - StorageValue<_, BTreeMap>>, ValueQuery>; - - /// Assignments as tracked in the claim queue. - #[derive(Encode, Decode, TypeInfo, RuntimeDebug, PartialEq, Clone)] - pub struct ParasEntry { - /// The underlying [`Assignment`]. - pub assignment: Assignment, - /// The number of times the entry has timed out in availability already. - pub availability_timeouts: u32, - /// The block height until this entry needs to be backed. - /// - /// If missed the entry will be removed from the claim queue without ever having occupied - /// the core. - pub ttl: N, - } - - /// Convenience type declaration for `ParasEntry`. - pub type ParasEntryType = ParasEntry>; - - impl ParasEntry { - /// Create a new `ParasEntry`. - pub fn new(assignment: Assignment, now: N) -> Self { - ParasEntry { assignment, availability_timeouts: 0, ttl: now } - } - - /// Return `Id` from the underlying `Assignment`. - pub fn para_id(&self) -> ParaId { - self.assignment.para_id() - } - } + pub type ClaimQueue = StorageValue<_, BTreeMap>, ValueQuery>; /// Availability timeout status of a core. pub(crate) struct AvailabilityTimeoutStatus { @@ -195,30 +118,6 @@ pub mod pallet { } } -type PositionInClaimQueue = u32; - -struct ClaimQueueIterator { - next_idx: u32, - queue: Peekable>>, -} - -impl Iterator for ClaimQueueIterator { - type Item = (CoreIndex, VecDeque); - - fn next(&mut self) -> Option { - let (idx, _) = self.queue.peek()?; - let val = if idx != &CoreIndex(self.next_idx) { - log::trace!(target: LOG_TARGET, "idx did not match claim queue idx: {:?} vs {:?}", idx, self.next_idx); - (CoreIndex(self.next_idx), VecDeque::new()) - } else { - let (idx, q) = self.queue.next()?; - (idx, q) - }; - self.next_idx += 1; - Some(val) - } -} - impl Pallet { /// Called by the initializer to initialize the scheduler pallet. pub(crate) fn initializer_initialize(_now: BlockNumberFor) -> Weight { @@ -228,31 +127,22 @@ impl Pallet { /// Called by the initializer to finalize the scheduler pallet. pub(crate) fn initializer_finalize() {} - /// Called before the initializer notifies of a new session. - pub(crate) fn pre_new_session() { - Self::push_claim_queue_items_to_assignment_provider(); - Self::push_occupied_cores_to_assignment_provider(); - } - /// Called by the initializer to note that a new session has started. pub(crate) fn initializer_on_new_session( notification: &SessionChangeNotification>, ) { - let SessionChangeNotification { validators, new_config, .. } = notification; + let SessionChangeNotification { validators, new_config, prev_config, .. } = notification; let config = new_config; + let assigner_cores = config.scheduler_params.num_cores; let n_cores = core::cmp::max( - T::AssignmentProvider::session_core_count(), + assigner_cores, match config.scheduler_params.max_validators_per_core { Some(x) if x != 0 => validators.len() as u32 / x, _ => 0, }, ); - AvailabilityCores::::mutate(|cores| { - cores.resize_with(n_cores as _, || CoreOccupied::Free); - }); - // shuffle validators into groups. if n_cores == 0 || validators.is_empty() { ValidatorGroups::::set(Vec::new()); @@ -295,151 +185,24 @@ impl Pallet { ValidatorGroups::::set(groups); } + // Resize and populate claim queue. + Self::maybe_resize_claim_queue(prev_config.scheduler_params.num_cores, assigner_cores); + Self::populate_claim_queue_after_session_change(); + let now = frame_system::Pallet::::block_number() + One::one(); SessionStartBlock::::set(now); } - /// Free unassigned cores. Provide a list of cores that should be considered newly-freed along - /// with the reason for them being freed. Returns a tuple of concluded and timedout paras. - fn free_cores( - just_freed_cores: impl IntoIterator, - ) -> (BTreeMap, BTreeMap>) { - let mut timedout_paras: BTreeMap> = BTreeMap::new(); - let mut concluded_paras = BTreeMap::new(); - - AvailabilityCores::::mutate(|cores| { - let c_len = cores.len(); - - just_freed_cores - .into_iter() - .filter(|(freed_index, _)| (freed_index.0 as usize) < c_len) - .for_each(|(freed_index, freed_reason)| { - match core::mem::replace(&mut cores[freed_index.0 as usize], CoreOccupied::Free) - { - CoreOccupied::Free => {}, - CoreOccupied::Paras(entry) => { - match freed_reason { - FreedReason::Concluded => { - concluded_paras.insert(freed_index, entry.assignment); - }, - FreedReason::TimedOut => { - timedout_paras.insert(freed_index, entry); - }, - }; - }, - }; - }) - }); - - (concluded_paras, timedout_paras) - } - - /// Get an iterator into the claim queues. - /// - /// This iterator will have an item for each and every core index up to the maximum core index - /// found in the claim queue. In other words there will be no holes/missing core indices, - /// between core 0 and the maximum, even if the claim queue was missing entries for particular - /// indices in between. (The iterator will return an empty `VecDeque` for those indices. - fn claim_queue_iterator() -> impl Iterator>)> { - let queues = ClaimQueue::::get(); - return ClaimQueueIterator::> { - next_idx: 0, - queue: queues.into_iter().peekable(), - } - } - - /// Note that the given cores have become occupied. Update the claim queue accordingly. - /// This will not push a new entry onto the claim queue, so the length after this call will be - /// the expected length - 1. The claim_queue runtime API will take care of adding another entry - /// here, to ensure the right lookahead. - pub(crate) fn occupied( - now_occupied: BTreeMap, - ) -> BTreeMap { - let mut availability_cores = AvailabilityCores::::get(); - - log::debug!(target: LOG_TARGET, "[occupied] now_occupied {:?}", now_occupied); - - let pos_mapping: BTreeMap = now_occupied - .iter() - .flat_map(|(core_idx, para_id)| { - match Self::remove_from_claim_queue(*core_idx, *para_id) { - Err(e) => { - log::debug!( - target: LOG_TARGET, - "[occupied] error on remove_from_claim queue {}", - e - ); - None - }, - Ok((pos_in_claim_queue, pe)) => { - availability_cores[core_idx.0 as usize] = CoreOccupied::Paras(pe); - - Some((*core_idx, pos_in_claim_queue)) - }, - } - }) - .collect(); - - // Drop expired claims after processing now_occupied. - Self::drop_expired_claims_from_claim_queue(); - - AvailabilityCores::::set(availability_cores); - - pos_mapping - } - - /// Iterates through every element in all claim queues and tries to add new assignments from the - /// `AssignmentProvider`. A claim is considered expired if it's `ttl` field is lower than the - /// current block height. - fn drop_expired_claims_from_claim_queue() { - let now = frame_system::Pallet::::block_number(); - let availability_cores = AvailabilityCores::::get(); - let ttl = configuration::ActiveConfig::::get().scheduler_params.ttl; - - ClaimQueue::::mutate(|cq| { - for (idx, _) in (0u32..).zip(availability_cores) { - let core_idx = CoreIndex(idx); - if let Some(core_claim_queue) = cq.get_mut(&core_idx) { - let mut i = 0; - let mut num_dropped = 0; - while i < core_claim_queue.len() { - let maybe_dropped = if let Some(entry) = core_claim_queue.get(i) { - if entry.ttl < now { - core_claim_queue.remove(i) - } else { - None - } - } else { - None - }; - - if let Some(dropped) = maybe_dropped { - num_dropped += 1; - T::AssignmentProvider::report_processed(dropped.assignment); - } else { - i += 1; - } - } - - for _ in 0..num_dropped { - // For all claims dropped due to TTL, attempt to pop a new entry to - // the back of the claim queue. - if let Some(assignment) = - T::AssignmentProvider::pop_assignment_for_core(core_idx) - { - core_claim_queue.push_back(ParasEntry::new(assignment, now + ttl)); - } - } - } - } - }); - } - /// Get the validators in the given group, if the group index is valid for this session. pub(crate) fn group_validators(group_index: GroupIndex) -> Option> { ValidatorGroups::::get().get(group_index.0 as usize).map(|g| g.clone()) } + /// Get the number of cores. + pub(crate) fn num_availability_cores() -> usize { + ValidatorGroups::::decode_len().unwrap_or(0) + } + /// Get the group assigned to a specific core by index at the current block number. Result /// undefined if the core index is unknown or the block number is less than the session start /// index. @@ -531,183 +294,137 @@ impl Pallet { /// Return the next thing that will be scheduled on this core assuming it is currently /// occupied and the candidate occupying it became available. pub(crate) fn next_up_on_available(core: CoreIndex) -> Option { - ClaimQueue::::get() - .get(&core) - .and_then(|a| a.front().map(|pe| Self::paras_entry_to_scheduled_core(pe))) + // Since this is being called from a runtime API, we need to workaround for #64. + if Self::on_chain_storage_version() == StorageVersion::new(2) { + migration::v2::ClaimQueue::::get() + .get(&core) + .and_then(|a| a.front().map(|entry| entry.assignment.para_id())) + } else { + ClaimQueue::::get() + .get(&core) + .and_then(|a| a.front().map(|assignment| assignment.para_id())) + } + .map(|para_id| ScheduledCore { para_id, collator: None }) } - fn paras_entry_to_scheduled_core(pe: &ParasEntryType) -> ScheduledCore { - ScheduledCore { para_id: pe.para_id(), collator: None } + // Since this is being called from a runtime API, we need to workaround for #64. + pub(crate) fn get_claim_queue() -> BTreeMap> { + if Self::on_chain_storage_version() == StorageVersion::new(2) { + migration::v2::ClaimQueue::::get() + .into_iter() + .map(|(core_index, entries)| { + (core_index, entries.into_iter().map(|e| e.assignment).collect()) + }) + .collect() + } else { + ClaimQueue::::get() + } } - /// Return the next thing that will be scheduled on this core assuming it is currently - /// occupied and the candidate occupying it times out. - pub(crate) fn next_up_on_time_out(core: CoreIndex) -> Option { - let max_availability_timeouts = configuration::ActiveConfig::::get() - .scheduler_params - .max_availability_timeouts; - Self::next_up_on_available(core).or_else(|| { - // Or, if none, the claim currently occupying the core, - // as it would be put back on the queue after timing out if number of retries is not at - // the maximum. - let cores = AvailabilityCores::::get(); - cores.get(core.0 as usize).and_then(|c| match c { - CoreOccupied::Free => None, - CoreOccupied::Paras(pe) => - if pe.availability_timeouts < max_availability_timeouts { - Some(Self::paras_entry_to_scheduled_core(pe)) - } else { - None - }, - }) - }) - } + /// For each core that isn't part of the `except_for` set, pop the first item of the claim queue + /// and fill the queue from the assignment provider. + pub(crate) fn advance_claim_queue(except_for: &BTreeSet) { + let config = configuration::ActiveConfig::::get(); + let num_assigner_cores = config.scheduler_params.num_cores; + // Extra sanity, config should already never be smaller than 1: + let n_lookahead = config.scheduler_params.lookahead.max(1); + + for core_idx in 0..num_assigner_cores { + let core_idx = CoreIndex::from(core_idx); + + if !except_for.contains(&core_idx) { + let core_idx = CoreIndex::from(core_idx); - /// Pushes occupied cores to the assignment provider. - fn push_occupied_cores_to_assignment_provider() { - AvailabilityCores::::mutate(|cores| { - for core in cores.iter_mut() { - match core::mem::replace(core, CoreOccupied::Free) { - CoreOccupied::Free => continue, - CoreOccupied::Paras(entry) => { - Self::maybe_push_assignment(entry); - }, + if let Some(dropped_para) = Self::pop_front_of_claim_queue(&core_idx) { + T::AssignmentProvider::report_processed(dropped_para); } - } - }); - } - // on new session - fn push_claim_queue_items_to_assignment_provider() { - for (_, claim_queue) in ClaimQueue::::take() { - // Push back in reverse order so that when we pop from the provider again, - // the entries in the claim queue are in the same order as they are right now. - for para_entry in claim_queue.into_iter().rev() { - Self::maybe_push_assignment(para_entry); + Self::fill_claim_queue(core_idx, n_lookahead); } } } - /// Push assignments back to the provider on session change unless the paras - /// timed out on availability before. - fn maybe_push_assignment(pe: ParasEntryType) { - if pe.availability_timeouts == 0 { - T::AssignmentProvider::push_back_assignment(pe.assignment); + // on new session + fn maybe_resize_claim_queue(old_core_count: u32, new_core_count: u32) { + if new_core_count < old_core_count { + ClaimQueue::::mutate(|cq| { + let to_remove: Vec<_> = cq + .range(CoreIndex(new_core_count)..CoreIndex(old_core_count)) + .map(|(k, _)| *k) + .collect(); + for key in to_remove { + if let Some(dropped_assignments) = cq.remove(&key) { + Self::push_back_to_assignment_provider(dropped_assignments.into_iter()); + } + } + }); } } - /// Frees cores and fills the free claim queue spots by popping from the `AssignmentProvider`. - pub fn free_cores_and_fill_claim_queue( - just_freed_cores: impl IntoIterator, - now: BlockNumberFor, - ) { - let (mut concluded_paras, mut timedout_paras) = Self::free_cores(just_freed_cores); - - // This can only happen on new sessions at which we move all assignments back to the - // provider. Hence, there's nothing we need to do here. - if ValidatorGroups::::decode_len().map_or(true, |l| l == 0) { - return - } - let n_session_cores = T::AssignmentProvider::session_core_count(); - let cq = ClaimQueue::::get(); + // Populate the claim queue. To be called on new session, after all the other modules were + // initialized. + fn populate_claim_queue_after_session_change() { let config = configuration::ActiveConfig::::get(); // Extra sanity, config should already never be smaller than 1: let n_lookahead = config.scheduler_params.lookahead.max(1); - let max_availability_timeouts = config.scheduler_params.max_availability_timeouts; - let ttl = config.scheduler_params.ttl; + let new_core_count = config.scheduler_params.num_cores; - for core_idx in 0..n_session_cores { + for core_idx in 0..new_core_count { let core_idx = CoreIndex::from(core_idx); + Self::fill_claim_queue(core_idx, n_lookahead); + } + } - let n_lookahead_used = cq.get(&core_idx).map_or(0, |v| v.len() as u32); - - // add previously timedout paras back into the queue - if let Some(mut entry) = timedout_paras.remove(&core_idx) { - if entry.availability_timeouts < max_availability_timeouts { - // Increment the timeout counter. - entry.availability_timeouts += 1; - if n_lookahead_used < n_lookahead { - entry.ttl = now + ttl; - } else { - // Over max capacity, we need to bump ttl (we exceeded the claim queue - // size, so otherwise the entry might get dropped before reaching the top): - entry.ttl = now + ttl + One::one(); - } - Self::add_to_claim_queue(core_idx, entry); - // The claim has been added back into the claim queue. - // Do not pop another assignment for the core. - continue - } else { - // Consider timed out assignments for on demand parachains as concluded for - // the assignment provider - let ret = concluded_paras.insert(core_idx, entry.assignment); - debug_assert!(ret.is_none()); + /// Push some assignments back to the provider. + fn push_back_to_assignment_provider( + assignments: impl core::iter::DoubleEndedIterator, + ) { + // Push back in reverse order so that when we pop from the provider again, + // the entries in the claim queue are in the same order as they are right + // now. + for assignment in assignments.rev() { + T::AssignmentProvider::push_back_assignment(assignment); + } + } + + fn fill_claim_queue(core_idx: CoreIndex, n_lookahead: u32) { + ClaimQueue::::mutate(|la| { + let cq = la.entry(core_idx).or_default(); + + let mut n_lookahead_used = cq.len() as u32; + + // If the claim queue used to be empty, we need to double the first assignment. + // Otherwise, the para will only be able to get the collation in right at the next block + // (synchronous backing). + // Only do this if the configured lookahead is greater than 1. Otherwise, it doesn't + // make sense. + if n_lookahead_used == 0 && n_lookahead > 1 { + if let Some(assignment) = T::AssignmentProvider::pop_assignment_for_core(core_idx) { + T::AssignmentProvider::assignment_duplicated(&assignment); + cq.push_back(assignment.clone()); + cq.push_back(assignment); + n_lookahead_used += 2; } } - if let Some(concluded_para) = concluded_paras.remove(&core_idx) { - T::AssignmentProvider::report_processed(concluded_para); - } for _ in n_lookahead_used..n_lookahead { if let Some(assignment) = T::AssignmentProvider::pop_assignment_for_core(core_idx) { - Self::add_to_claim_queue(core_idx, ParasEntry::new(assignment, now + ttl)); + cq.push_back(assignment); + } else { + break } } - } - debug_assert!(timedout_paras.is_empty()); - debug_assert!(concluded_paras.is_empty()); - } - - fn add_to_claim_queue(core_idx: CoreIndex, pe: ParasEntryType) { - ClaimQueue::::mutate(|la| { - la.entry(core_idx).or_default().push_back(pe); + // If we didn't end up pushing anything, remove the entry. We don't want to waste the + // space if we've no assignments. + if cq.is_empty() { + la.remove(&core_idx); + } }); } - /// Returns `ParasEntry` with `para_id` at `core_idx` if found. - fn remove_from_claim_queue( - core_idx: CoreIndex, - para_id: ParaId, - ) -> Result<(PositionInClaimQueue, ParasEntryType), &'static str> { - ClaimQueue::::mutate(|cq| { - let core_claims = cq.get_mut(&core_idx).ok_or("core_idx not found in lookahead")?; - - let pos = core_claims - .iter() - .position(|pe| pe.para_id() == para_id) - .ok_or("para id not found at core_idx lookahead")?; - - let pe = core_claims.remove(pos).ok_or("remove returned None")?; - - Ok((pos as u32, pe)) - }) - } - - /// Paras scheduled next in the claim queue. - pub(crate) fn scheduled_paras() -> impl Iterator { - let claim_queue = ClaimQueue::::get(); - claim_queue - .into_iter() - .filter_map(|(core_idx, v)| v.front().map(|e| (core_idx, e.assignment.para_id()))) - } - - /// Paras that may get backed on cores. - /// - /// 1. The para must be scheduled on core. - /// 2. Core needs to be free, otherwise backing is not possible. - pub(crate) fn eligible_paras() -> impl Iterator { - let availability_cores = AvailabilityCores::::get(); - - Self::claim_queue_iterator().zip(availability_cores.into_iter()).filter_map( - |((core_idx, queue), core)| { - if core != CoreOccupied::Free { - return None - } - let next_scheduled = queue.front()?; - Some((core_idx, next_scheduled.assignment.para_id())) - }, - ) + fn pop_front_of_claim_queue(core_idx: &CoreIndex) -> Option { + ClaimQueue::::mutate(|cq| cq.get_mut(core_idx)?.pop_front()) } #[cfg(any(feature = "try-runtime", test))] @@ -726,7 +443,7 @@ impl Pallet { } #[cfg(test)] - pub(crate) fn set_claim_queue(claim_queue: BTreeMap>>) { + pub(crate) fn set_claim_queue(claim_queue: BTreeMap>) { ClaimQueue::::set(claim_queue); } } diff --git a/polkadot/runtime/parachains/src/scheduler/common.rs b/polkadot/runtime/parachains/src/scheduler/common.rs index 114cd4b940bc..bf8a2bee74e3 100644 --- a/polkadot/runtime/parachains/src/scheduler/common.rs +++ b/polkadot/runtime/parachains/src/scheduler/common.rs @@ -77,11 +77,6 @@ pub trait AssignmentProvider { #[cfg(any(feature = "runtime-benchmarks", test))] fn get_mock_assignment(core_idx: CoreIndex, para_id: ParaId) -> Assignment; - /// How many cores are allocated to this provider. - /// - /// As the name suggests the core count has to be session buffered: - /// - /// - Core count has to be predetermined for the next session in the current session. - /// - Core count must not change during a session. - fn session_core_count() -> u32; + /// Report that an assignment was duplicated by the scheduler. + fn assignment_duplicated(assignment: &Assignment); } diff --git a/polkadot/runtime/parachains/src/scheduler/migration.rs b/polkadot/runtime/parachains/src/scheduler/migration.rs index 125f105ef706..e741711cad6d 100644 --- a/polkadot/runtime/parachains/src/scheduler/migration.rs +++ b/polkadot/runtime/parachains/src/scheduler/migration.rs @@ -268,7 +268,7 @@ pub type MigrateV0ToV1 = VersionedMigration< ::DbWeight, >; -mod v2 { +pub(crate) mod v2 { use super::*; use crate::scheduler; @@ -406,3 +406,89 @@ pub type MigrateV1ToV2 = VersionedMigration< Pallet, ::DbWeight, >; + +/// Migration for TTL and availability timeout retries removal. +/// AvailabilityCores storage is removed and ClaimQueue now holds `Assignment`s instead of +/// `ParasEntryType` +mod v3 { + use super::*; + use crate::scheduler; + + #[storage_alias] + pub(crate) type ClaimQueue = + StorageValue, BTreeMap>, ValueQuery>; + /// Migration to V3 + pub struct UncheckedMigrateToV3(core::marker::PhantomData); + + impl UncheckedOnRuntimeUpgrade for UncheckedMigrateToV3 { + fn on_runtime_upgrade() -> Weight { + let mut weight: Weight = Weight::zero(); + + // Migrate ClaimQueuee to new format. + + let old = v2::ClaimQueue::::take(); + let new = old + .into_iter() + .map(|(k, v)| { + ( + k, + v.into_iter() + .map(|paras_entry| paras_entry.assignment) + .collect::>(), + ) + }) + .collect::>>(); + + v3::ClaimQueue::::put(new); + + // Clear AvailabilityCores storage + v2::AvailabilityCores::::kill(); + + weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2)); + + log::info!(target: scheduler::LOG_TARGET, "Migrating para scheduler storage to v3"); + + weight + } + + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::DispatchError> { + log::trace!( + target: crate::scheduler::LOG_TARGET, + "ClaimQueue before migration: {}", + v2::ClaimQueue::::get().len() + ); + + let bytes = u32::to_be_bytes(v2::ClaimQueue::::get().len() as u32); + + Ok(bytes.to_vec()) + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), sp_runtime::DispatchError> { + log::trace!(target: crate::scheduler::LOG_TARGET, "Running post_upgrade()"); + + let old_len = u32::from_be_bytes(state.try_into().unwrap()); + ensure!( + v3::ClaimQueue::::get().len() as u32 == old_len, + "Old ClaimQueue completely moved to new ClaimQueue after migration" + ); + + ensure!( + !v2::AvailabilityCores::::exists(), + "AvailabilityCores storage should have been completely killed" + ); + + Ok(()) + } + } +} + +/// Migrate `V2` to `V3` of the storage format. +pub type MigrateV2ToV3 = VersionedMigration< + 2, + 3, + v3::UncheckedMigrateToV3, + Pallet, + ::DbWeight, +>; diff --git a/polkadot/runtime/parachains/src/scheduler/tests.rs b/polkadot/runtime/parachains/src/scheduler/tests.rs index f3866146e811..5be7e084f3bc 100644 --- a/polkadot/runtime/parachains/src/scheduler/tests.rs +++ b/polkadot/runtime/parachains/src/scheduler/tests.rs @@ -16,10 +16,10 @@ use super::*; -use alloc::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; +use alloc::collections::btree_map::BTreeMap; use frame_support::assert_ok; use polkadot_primitives::{ - vstaging::SchedulerParams, BlockNumber, SessionIndex, ValidationCode, ValidatorId, + BlockNumber, SchedulerParams, SessionIndex, ValidationCode, ValidatorId, }; use sp_keyring::Sr25519Keyring; @@ -27,14 +27,14 @@ use crate::{ configuration::HostConfiguration, initializer::SessionChangeNotification, mock::{ - new_test_ext, MockAssigner, MockGenesisConfig, Paras, ParasShared, RuntimeOrigin, - Scheduler, System, Test, + new_test_ext, Configuration, MockAssigner, MockGenesisConfig, Paras, ParasShared, + RuntimeOrigin, Scheduler, System, Test, }, paras::{ParaGenesisArgs, ParaKind}, scheduler::{self, common::Assignment, ClaimQueue}, }; -fn schedule_blank_para(id: ParaId) { +fn register_para(id: ParaId) { let validation_code: ValidationCode = vec![1, 2, 3].into(); assert_ok!(Paras::schedule_para_initialize( id, @@ -58,17 +58,18 @@ fn run_to_block( Scheduler::initializer_finalize(); Paras::initializer_finalize(b); - if let Some(notification) = new_session(b + 1) { - let mut notification_with_session_index = notification; + if let Some(mut notification) = new_session(b + 1) { // We will make every session change trigger an action queue. Normally this may require // 2 or more session changes. - if notification_with_session_index.session_index == SessionIndex::default() { - notification_with_session_index.session_index = ParasShared::scheduled_session(); + if notification.session_index == SessionIndex::default() { + notification.session_index = ParasShared::scheduled_session(); } - Scheduler::pre_new_session(); - Paras::initializer_on_new_session(¬ification_with_session_index); - Scheduler::initializer_on_new_session(¬ification_with_session_index); + Configuration::force_set_active_config(notification.new_config.clone()); + + Paras::initializer_on_new_session(¬ification); + + Scheduler::initializer_on_new_session(¬ification); } System::on_finalize(b); @@ -79,28 +80,8 @@ fn run_to_block( Paras::initializer_initialize(b + 1); Scheduler::initializer_initialize(b + 1); - // In the real runtime this is expected to be called by the `InclusionInherent` pallet. - Scheduler::free_cores_and_fill_claim_queue(BTreeMap::new(), b + 1); - } -} - -fn run_to_end_of_block( - to: BlockNumber, - new_session: impl Fn(BlockNumber) -> Option>, -) { - run_to_block(to, &new_session); - - Scheduler::initializer_finalize(); - Paras::initializer_finalize(to); - - if let Some(notification) = new_session(to + 1) { - Scheduler::pre_new_session(); - - Paras::initializer_on_new_session(¬ification); - Scheduler::initializer_on_new_session(¬ification); + Scheduler::advance_claim_queue(&Default::default()); } - - System::on_finalize(to); } fn default_config() -> HostConfiguration { @@ -110,6 +91,7 @@ fn default_config() -> HostConfiguration { // `minimum_validation_upgrade_delay` is greater than `chain_availability_period` and // `thread_availability_period`. minimum_validation_upgrade_delay: 6, + #[allow(deprecated)] scheduler_params: SchedulerParams { group_rotation_frequency: 10, paras_availability_period: 3, @@ -129,172 +111,27 @@ fn genesis_config(config: &HostConfiguration) -> MockGenesisConfig } } -fn claimqueue_contains_para_ids(pids: Vec) -> bool { - let set: BTreeSet = ClaimQueue::::get() +/// Internal access to assignments at the top of the claim queue. +fn next_assignments() -> impl Iterator { + let claim_queue = ClaimQueue::::get(); + claim_queue .into_iter() - .flat_map(|(_, paras_entries)| paras_entries.into_iter().map(|pe| pe.assignment.para_id())) - .collect(); - - pids.into_iter().all(|pid| set.contains(&pid)) -} - -fn availability_cores_contains_para_ids(pids: Vec) -> bool { - let set: BTreeSet = AvailabilityCores::::get() - .into_iter() - .filter_map(|core| match core { - CoreOccupied::Free => None, - CoreOccupied::Paras(entry) => Some(entry.para_id()), - }) - .collect(); - - pids.into_iter().all(|pid| set.contains(&pid)) -} - -/// Internal access to entries at the top of the claim queue. -fn scheduled_entries() -> impl Iterator>)> { - let claimqueue = ClaimQueue::::get(); - claimqueue - .into_iter() - .filter_map(|(core_idx, v)| v.front().map(|e| (core_idx, e.clone()))) -} - -#[test] -fn claim_queue_iterator_handles_holes_correctly() { - let mut queue = BTreeMap::new(); - queue.insert(CoreIndex(1), ["abc"].into_iter().collect()); - queue.insert(CoreIndex(4), ["cde"].into_iter().collect()); - let queue = queue.into_iter().peekable(); - let mut i = ClaimQueueIterator { next_idx: 0, queue }; - - let (idx, e) = i.next().unwrap(); - assert_eq!(idx, CoreIndex(0)); - assert!(e.is_empty()); - - let (idx, e) = i.next().unwrap(); - assert_eq!(idx, CoreIndex(1)); - assert!(e.len() == 1); - - let (idx, e) = i.next().unwrap(); - assert_eq!(idx, CoreIndex(2)); - assert!(e.is_empty()); - - let (idx, e) = i.next().unwrap(); - assert_eq!(idx, CoreIndex(3)); - assert!(e.is_empty()); - - let (idx, e) = i.next().unwrap(); - assert_eq!(idx, CoreIndex(4)); - assert!(e.len() == 1); - - assert!(i.next().is_none()); + .filter_map(|(core_idx, v)| v.front().map(|a| (core_idx, a.clone()))) } #[test] -fn claimqueue_ttl_drop_fn_works() { +fn session_change_shuffles_validators() { let mut config = default_config(); - config.scheduler_params.lookahead = 3; + // Need five cores for this test + config.scheduler_params.num_cores = 5; let genesis_config = genesis_config(&config); - let para_id = ParaId::from(100); - let core_idx = CoreIndex::from(0); - let mut now = 10; - new_test_ext(genesis_config).execute_with(|| { - assert!(config.scheduler_params.ttl == 5); - // Register and run to a blockheight where the para is in a valid state. - schedule_blank_para(para_id); - run_to_block(now, |n| if n == now { Some(Default::default()) } else { None }); - - // Add a claim on core 0 with a ttl in the past. - let paras_entry = ParasEntry::new(Assignment::Bulk(para_id), now - 5 as u32); - Scheduler::add_to_claim_queue(core_idx, paras_entry.clone()); - - // Claim is in queue prior to call. - assert!(claimqueue_contains_para_ids::(vec![para_id])); - - // Claim is dropped post call. - Scheduler::drop_expired_claims_from_claim_queue(); - assert!(!claimqueue_contains_para_ids::(vec![para_id])); - - // Add a claim on core 0 with a ttl in the future (15). - let paras_entry = ParasEntry::new(Assignment::Bulk(para_id), now + 5); - Scheduler::add_to_claim_queue(core_idx, paras_entry.clone()); - - // Claim is in queue post call. - Scheduler::drop_expired_claims_from_claim_queue(); - assert!(claimqueue_contains_para_ids::(vec![para_id])); - - now = now + 6; - run_to_block(now, |_| None); - - // Claim is dropped - Scheduler::drop_expired_claims_from_claim_queue(); - assert!(!claimqueue_contains_para_ids::(vec![para_id])); + assert!(ValidatorGroups::::get().is_empty()); - // Add a claim on core 0 with a ttl == now (16) - let paras_entry = ParasEntry::new(Assignment::Bulk(para_id), now); - Scheduler::add_to_claim_queue(core_idx, paras_entry.clone()); - - // Claim is in queue post call. - Scheduler::drop_expired_claims_from_claim_queue(); - assert!(claimqueue_contains_para_ids::(vec![para_id])); - - now = now + 1; - run_to_block(now, |_| None); - - // Drop expired claim. - Scheduler::drop_expired_claims_from_claim_queue(); - assert!(!claimqueue_contains_para_ids::(vec![para_id])); - - // Add a claim on core 0 with a ttl == now (17) - let paras_entry_non_expired = ParasEntry::new(Assignment::Bulk(para_id), now); - let paras_entry_expired = ParasEntry::new(Assignment::Bulk(para_id), now - 2); - // ttls = [17, 15, 17] - Scheduler::add_to_claim_queue(core_idx, paras_entry_non_expired.clone()); - Scheduler::add_to_claim_queue(core_idx, paras_entry_expired.clone()); - Scheduler::add_to_claim_queue(core_idx, paras_entry_non_expired.clone()); - let cq = scheduler::ClaimQueue::::get(); - assert_eq!(cq.get(&core_idx).unwrap().len(), 3); - - // Add a claim to the test assignment provider. - let assignment = Assignment::Bulk(para_id); - - MockAssigner::add_test_assignment(assignment.clone()); - - // Drop expired claim. - Scheduler::drop_expired_claims_from_claim_queue(); - - let cq = scheduler::ClaimQueue::::get(); - let cqc = cq.get(&core_idx).unwrap(); - // Same number of claims, because a new claim is popped from `MockAssigner` instead of the - // expired one - assert_eq!(cqc.len(), 3); - - // The first 2 claims in the queue should have a ttl of 17, - // being the ones set up prior in this test as claims 1 and 3. - // The third claim is popped from the assignment provider and - // has a new ttl set by the scheduler of now + - // assignment_provider_ttl. ttls = [17, 17, 22] - assert!(cqc.iter().enumerate().all(|(index, entry)| { - match index { - 0 | 1 => entry.clone().ttl == 17, - 2 => entry.clone().ttl == 22, - _ => false, - } - })) - }); -} - -#[test] -fn session_change_shuffles_validators() { - let genesis_config = genesis_config(&default_config()); - - new_test_ext(genesis_config).execute_with(|| { - // Need five cores for this test - MockAssigner::set_core_count(5); run_to_block(1, |number| match number { 1 => Some(SessionChangeNotification { - new_config: default_config(), + new_config: config.clone(), validators: vec![ ValidatorId::from(Sr25519Keyring::Alice.public()), ValidatorId::from(Sr25519Keyring::Bob.public()), @@ -328,6 +165,8 @@ fn session_change_shuffles_validators() { fn session_change_takes_only_max_per_core() { let config = { let mut config = default_config(); + // Simulate 2 cores between all usage types + config.scheduler_params.num_cores = 2; config.scheduler_params.max_validators_per_core = Some(1); config }; @@ -335,9 +174,6 @@ fn session_change_takes_only_max_per_core() { let genesis_config = genesis_config(&config); new_test_ext(genesis_config).execute_with(|| { - // Simulate 2 cores between all usage types - MockAssigner::set_core_count(2); - run_to_block(1, |number| match number { 1 => Some(SessionChangeNotification { new_config: config.clone(), @@ -367,8 +203,12 @@ fn session_change_takes_only_max_per_core() { } #[test] -fn fill_claimqueue_fills() { - let config = default_config(); +// Test that `advance_claim_queue` doubles the first assignment only for a core that didn't use to +// have any assignments. +fn advance_claim_queue_doubles_assignment_only_if_empty() { + let mut config = default_config(); + config.scheduler_params.lookahead = 3; + config.scheduler_params.num_cores = 2; let genesis_config = genesis_config(&config); let para_a = ParaId::from(3_u32); @@ -380,18 +220,15 @@ fn fill_claimqueue_fills() { let assignment_c = Assignment::Bulk(para_c); new_test_ext(genesis_config).execute_with(|| { - MockAssigner::set_core_count(2); - let coretime_ttl = config.scheduler_params.ttl; - // Add 3 paras - schedule_blank_para(para_a); - schedule_blank_para(para_b); - schedule_blank_para(para_c); + register_para(para_a); + register_para(para_b); + register_para(para_c); // start a new session to activate, 2 validators for 2 cores. run_to_block(1, |number| match number { 1 => Some(SessionChangeNotification { - new_config: default_config(), + new_config: config.clone(), validators: vec![ ValidatorId::from(Sr25519Keyring::Alice.public()), ValidatorId::from(Sr25519Keyring::Bob.public()), @@ -406,224 +243,108 @@ fn fill_claimqueue_fills() { MockAssigner::add_test_assignment(assignment_b.clone()); MockAssigner::add_test_assignment(assignment_c.clone()); + // This will call advance_claim_queue run_to_block(2, |_| None); { - assert_eq!(Scheduler::claim_queue_len(), 3); - let scheduled: BTreeMap<_, _> = scheduled_entries().collect(); + assert_eq!(Scheduler::claim_queue_len(), 5); + let mut claim_queue = scheduler::ClaimQueue::::get(); - // Was added a block later, note the TTL. - assert_eq!( - scheduled.get(&CoreIndex(0)).unwrap(), - &ParasEntry { - assignment: assignment_a.clone(), - availability_timeouts: 0, - ttl: 2 + coretime_ttl - }, - ); - // Sits on the same core as `para_a` + // Because the claim queue used to be empty, the first assignment is doubled for every + // core so that the first para gets a fair shot at backing something. assert_eq!( - scheduler::ClaimQueue::::get().get(&CoreIndex(0)).unwrap()[1], - ParasEntry { - assignment: assignment_b.clone(), - availability_timeouts: 0, - ttl: 2 + coretime_ttl - } + claim_queue.remove(&CoreIndex(0)).unwrap(), + [assignment_a.clone(), assignment_a, assignment_b] + .into_iter() + .collect::>() ); assert_eq!( - scheduled.get(&CoreIndex(1)).unwrap(), - &ParasEntry { - assignment: assignment_c.clone(), - availability_timeouts: 0, - ttl: 2 + coretime_ttl - }, + claim_queue.remove(&CoreIndex(1)).unwrap(), + [assignment_c.clone(), assignment_c].into_iter().collect::>() ); } }); } #[test] -fn schedule_schedules_including_just_freed() { +// Test that `advance_claim_queue` doesn't populate for cores which have no assignments. +fn advance_claim_queue_no_entry_if_empty() { let mut config = default_config(); - // NOTE: This test expects on demand cores to each get slotted on to a different core - // and not fill up the claimqueue of each core first. - config.scheduler_params.lookahead = 1; + config.scheduler_params.lookahead = 3; + config.scheduler_params.num_cores = 2; let genesis_config = genesis_config(&config); let para_a = ParaId::from(3_u32); - let para_b = ParaId::from(4_u32); - let para_c = ParaId::from(5_u32); - let para_d = ParaId::from(6_u32); - let para_e = ParaId::from(7_u32); - let assignment_a = Assignment::Bulk(para_a); - let assignment_b = Assignment::Bulk(para_b); - let assignment_c = Assignment::Bulk(para_c); - let assignment_d = Assignment::Bulk(para_d); - let assignment_e = Assignment::Bulk(para_e); new_test_ext(genesis_config).execute_with(|| { - MockAssigner::set_core_count(3); - - // add 5 paras - schedule_blank_para(para_a); - schedule_blank_para(para_b); - schedule_blank_para(para_c); - schedule_blank_para(para_d); - schedule_blank_para(para_e); + // Add 1 para + register_para(para_a); - // start a new session to activate, 3 validators for 3 cores. + // start a new session to activate, 2 validators for 2 cores. run_to_block(1, |number| match number { 1 => Some(SessionChangeNotification { - new_config: default_config(), + new_config: config.clone(), validators: vec![ ValidatorId::from(Sr25519Keyring::Alice.public()), ValidatorId::from(Sr25519Keyring::Bob.public()), - ValidatorId::from(Sr25519Keyring::Charlie.public()), ], ..Default::default() }), _ => None, }); - // add a couple of para claims now that paras are live - MockAssigner::add_test_assignment(assignment_a.clone()); - MockAssigner::add_test_assignment(assignment_c.clone()); - - let mut now = 2; - run_to_block(now, |_| None); - - assert_eq!(Scheduler::scheduled_paras().collect::>().len(), 2); - - // cores 0, 1 should be occupied. mark them as such. - let mut occupied_map: BTreeMap = BTreeMap::new(); - occupied_map.insert(CoreIndex(0), para_a); - occupied_map.insert(CoreIndex(1), para_c); - Scheduler::occupied(occupied_map); - - { - let cores = AvailabilityCores::::get(); - - // cores 0, 1 are `CoreOccupied::Paras(ParasEntry...)` - assert!(cores[0] != CoreOccupied::Free); - assert!(cores[1] != CoreOccupied::Free); - - // core 2 is free - assert!(cores[2] == CoreOccupied::Free); - - assert!(Scheduler::scheduled_paras().collect::>().is_empty()); - - // All `core_queue`s should be empty - scheduler::ClaimQueue::::get() - .iter() - .for_each(|(_core_idx, core_queue)| assert_eq!(core_queue.len(), 0)) - } - MockAssigner::add_test_assignment(assignment_a.clone()); - MockAssigner::add_test_assignment(assignment_c.clone()); - MockAssigner::add_test_assignment(assignment_b.clone()); - MockAssigner::add_test_assignment(assignment_d.clone()); - MockAssigner::add_test_assignment(assignment_e.clone()); - now = 3; - run_to_block(now, |_| None); - { - let scheduled: BTreeMap<_, _> = scheduled_entries().collect(); - - assert_eq!(scheduled.len(), 3); - assert_eq!( - scheduled.get(&CoreIndex(2)).unwrap(), - &ParasEntry { - assignment: Assignment::Bulk(para_b), - availability_timeouts: 0, - ttl: 8 - }, - ); - } - - // now note that cores 0 and 1 were freed. - let just_updated: BTreeMap = vec![ - (CoreIndex(0), FreedReason::Concluded), - (CoreIndex(1), FreedReason::TimedOut), // should go back on queue. - ] - .into_iter() - .collect(); - Scheduler::free_cores_and_fill_claim_queue(just_updated, now); + // This will call advance_claim_queue + run_to_block(3, |_| None); { - let scheduled: BTreeMap<_, _> = scheduled_entries().collect(); + let mut claim_queue = scheduler::ClaimQueue::::get(); - // 1 thing scheduled before, + 2 cores freed. - assert_eq!(scheduled.len(), 3); - assert_eq!( - scheduled.get(&CoreIndex(0)).unwrap(), - &ParasEntry { - // Next entry in queue is `a` again: - assignment: Assignment::Bulk(para_a), - availability_timeouts: 0, - ttl: 8 - }, - ); - // Although C was descheduled, the core `2` was occupied so C goes back to the queue. assert_eq!( - scheduler::ClaimQueue::::get()[&CoreIndex(1)][1], - ParasEntry { - assignment: Assignment::Bulk(para_c), - // End of the queue should be the pushed back entry: - availability_timeouts: 1, - // ttl 1 higher: - ttl: 9 - }, - ); - assert_eq!( - scheduled.get(&CoreIndex(1)).unwrap(), - &ParasEntry { - assignment: Assignment::Bulk(para_c), - availability_timeouts: 0, - ttl: 8 - }, - ); - assert_eq!( - scheduled.get(&CoreIndex(2)).unwrap(), - &ParasEntry { - assignment: Assignment::Bulk(para_b), - availability_timeouts: 0, - ttl: 8 - }, + claim_queue.remove(&CoreIndex(0)).unwrap(), + [assignment_a].into_iter().collect::>() ); - assert!(claimqueue_contains_para_ids::(vec![para_c])); - assert!(!availability_cores_contains_para_ids::(vec![para_a, para_c])); + // Even though core 1 exists, there's no assignment for it so it's not present in the + // claim queue. + assert!(claim_queue.remove(&CoreIndex(1)).is_none()); } }); } #[test] -fn schedule_clears_availability_cores() { +// Test that `advance_claim_queue` only advances for cores that are not part of the `except_for` +// set. +fn advance_claim_queue_except_for() { let mut config = default_config(); + // NOTE: This test expects on demand cores to each get slotted on to a different core + // and not fill up the claimqueue of each core first. config.scheduler_params.lookahead = 1; + config.scheduler_params.num_cores = 3; + let genesis_config = genesis_config(&config); let para_a = ParaId::from(1_u32); let para_b = ParaId::from(2_u32); let para_c = ParaId::from(3_u32); + let para_d = ParaId::from(4_u32); + let para_e = ParaId::from(5_u32); let assignment_a = Assignment::Bulk(para_a); let assignment_b = Assignment::Bulk(para_b); let assignment_c = Assignment::Bulk(para_c); + let assignment_d = Assignment::Bulk(para_d); + let assignment_e = Assignment::Bulk(para_e); new_test_ext(genesis_config).execute_with(|| { - MockAssigner::set_core_count(3); - - // register 3 paras - schedule_blank_para(para_a); - schedule_blank_para(para_b); - schedule_blank_para(para_c); - - // Adding assignments then running block to populate claim queue - MockAssigner::add_test_assignment(assignment_a.clone()); - MockAssigner::add_test_assignment(assignment_b.clone()); - MockAssigner::add_test_assignment(assignment_c.clone()); + // add 5 paras + register_para(para_a); + register_para(para_b); + register_para(para_c); + register_para(para_d); + register_para(para_e); // start a new session to activate, 3 validators for 3 cores. run_to_block(1, |number| match number { @@ -639,91 +360,69 @@ fn schedule_clears_availability_cores() { _ => None, }); - run_to_block(2, |_| None); - - assert_eq!(scheduler::ClaimQueue::::get().len(), 3); - - // cores 0, 1, and 2 should be occupied. mark them as such. - Scheduler::occupied( - vec![(CoreIndex(0), para_a), (CoreIndex(1), para_b), (CoreIndex(2), para_c)] - .into_iter() - .collect(), - ); + // add a couple of para claims now that paras are live + MockAssigner::add_test_assignment(assignment_a.clone()); + MockAssigner::add_test_assignment(assignment_c.clone()); - { - let cores = AvailabilityCores::::get(); + run_to_block(2, |_| None); - assert_eq!(cores[0].is_free(), false); - assert_eq!(cores[1].is_free(), false); - assert_eq!(cores[2].is_free(), false); + Scheduler::advance_claim_queue(&Default::default()); - // All `core_queue`s should be empty - scheduler::ClaimQueue::::get() - .iter() - .for_each(|(_core_idx, core_queue)| assert!(core_queue.len() == 0)) - } + // Queues of all cores should be empty + assert_eq!(Scheduler::claim_queue_len(), 0); - // Add more assignments MockAssigner::add_test_assignment(assignment_a.clone()); - MockAssigner::add_test_assignment(assignment_b.clone()); MockAssigner::add_test_assignment(assignment_c.clone()); + MockAssigner::add_test_assignment(assignment_b.clone()); + MockAssigner::add_test_assignment(assignment_d.clone()); + MockAssigner::add_test_assignment(assignment_e.clone()); run_to_block(3, |_| None); - // now note that cores 0 and 2 were freed. - Scheduler::free_cores_and_fill_claim_queue( - vec![(CoreIndex(0), FreedReason::Concluded), (CoreIndex(2), FreedReason::Concluded)] - .into_iter() - .collect::>(), - 3, - ); + { + let scheduled: BTreeMap<_, _> = next_assignments().collect(); + + assert_eq!(scheduled.len(), 3); + assert_eq!(scheduled.get(&CoreIndex(0)).unwrap(), &Assignment::Bulk(para_a)); + assert_eq!(scheduled.get(&CoreIndex(1)).unwrap(), &Assignment::Bulk(para_c)); + assert_eq!(scheduled.get(&CoreIndex(2)).unwrap(), &Assignment::Bulk(para_b)); + } + + // now note that cores 0 and 1 were freed. + Scheduler::advance_claim_queue(&std::iter::once(CoreIndex(2)).collect()); { - let claimqueue = ClaimQueue::::get(); - let claimqueue_0 = claimqueue.get(&CoreIndex(0)).unwrap().clone(); - let claimqueue_2 = claimqueue.get(&CoreIndex(2)).unwrap().clone(); - let entry_ttl = 8; - assert_eq!(claimqueue_0.len(), 1); - assert_eq!(claimqueue_2.len(), 1); - let queue_0_expectation: VecDeque> = - vec![ParasEntry::new(assignment_a, entry_ttl as u32)].into_iter().collect(); - let queue_2_expectation: VecDeque> = - vec![ParasEntry::new(assignment_c, entry_ttl as u32)].into_iter().collect(); - assert_eq!(claimqueue_0, queue_0_expectation); - assert_eq!(claimqueue_2, queue_2_expectation); - - // The freed cores should be `Free` in `AvailabilityCores`. - let cores = AvailabilityCores::::get(); - assert!(cores[0].is_free()); - assert!(cores[2].is_free()); + let scheduled: BTreeMap<_, _> = next_assignments().collect(); + + // 1 thing scheduled before, + 2 cores freed. + assert_eq!(scheduled.len(), 3); + assert_eq!(scheduled.get(&CoreIndex(0)).unwrap(), &Assignment::Bulk(para_d)); + assert_eq!(scheduled.get(&CoreIndex(1)).unwrap(), &Assignment::Bulk(para_e)); + assert_eq!(scheduled.get(&CoreIndex(2)).unwrap(), &Assignment::Bulk(para_b)); } }); } #[test] fn schedule_rotates_groups() { + let on_demand_cores = 2; let config = { let mut config = default_config(); config.scheduler_params.lookahead = 1; + config.scheduler_params.num_cores = on_demand_cores; config }; let rotation_frequency = config.scheduler_params.group_rotation_frequency; - let on_demand_cores = 2; let genesis_config = genesis_config(&config); let para_a = ParaId::from(1_u32); let para_b = ParaId::from(2_u32); - let assignment_a = Assignment::Bulk(para_a); - let assignment_b = Assignment::Bulk(para_b); - new_test_ext(genesis_config).execute_with(|| { - MockAssigner::set_core_count(on_demand_cores); - - schedule_blank_para(para_a); - schedule_blank_para(para_b); + register_para(para_a); + register_para(para_b); // start a new session to activate, 2 validators for 2 cores. run_to_block(1, |number| match number { @@ -741,15 +440,10 @@ fn schedule_rotates_groups() { let session_start_block = scheduler::SessionStartBlock::::get(); assert_eq!(session_start_block, 1); - MockAssigner::add_test_assignment(assignment_a.clone()); - MockAssigner::add_test_assignment(assignment_b.clone()); - let mut now = 2; run_to_block(now, |_| None); let assert_groups_rotated = |rotations: u32, now: &BlockNumberFor| { - let scheduled: BTreeMap<_, _> = Scheduler::scheduled_paras().collect(); - assert_eq!(scheduled.len(), 2); assert_eq!( Scheduler::group_assigned_to_core(CoreIndex(0), *now).unwrap(), GroupIndex((0u32 + rotations) % on_demand_cores) @@ -764,7 +458,7 @@ fn schedule_rotates_groups() { // one block before first rotation. now = rotation_frequency; - run_to_block(rotation_frequency, |_| None); + run_to_block(now, |_| None); assert_groups_rotated(0, &now); @@ -785,134 +479,6 @@ fn schedule_rotates_groups() { }); } -#[test] -fn on_demand_claims_are_pruned_after_timing_out() { - let max_timeouts = 20; - let mut config = default_config(); - config.scheduler_params.lookahead = 1; - // Need more timeouts for this test - config.scheduler_params.max_availability_timeouts = max_timeouts; - config.scheduler_params.ttl = BlockNumber::from(5u32); - let genesis_config = genesis_config(&config); - - let para_a = ParaId::from(1_u32); - - let assignment_a = Assignment::Bulk(para_a); - - new_test_ext(genesis_config).execute_with(|| { - MockAssigner::set_core_count(2); - schedule_blank_para(para_a); - - // #1 - let mut now = 1; - run_to_block(now, |number| match number { - 1 => Some(SessionChangeNotification { - new_config: default_config(), - validators: vec![ - ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ], - ..Default::default() - }), - _ => None, - }); - - MockAssigner::add_test_assignment(assignment_a.clone()); - - // #2 - now += 1; - run_to_block(now, |_| None); - assert_eq!(scheduler::ClaimQueue::::get().len(), 1); - // ParaId a is in the claimqueue. - assert!(claimqueue_contains_para_ids::(vec![para_a])); - - Scheduler::occupied(vec![(CoreIndex(0), para_a)].into_iter().collect()); - // ParaId a is no longer in the claimqueue. - assert!(!claimqueue_contains_para_ids::(vec![para_a])); - // It is in availability cores. - assert!(availability_cores_contains_para_ids::(vec![para_a])); - - // #3 - now += 1; - // Run to block #n over the max_retries value. - // In this case, both validator groups with time out on availability and - // the assignment will be dropped. - for n in now..=(now + max_timeouts + 1) { - // #n - run_to_block(n, |_| None); - // Time out on core 0. - let just_updated: BTreeMap = vec![ - (CoreIndex(0), FreedReason::TimedOut), // should go back on queue. - ] - .into_iter() - .collect(); - Scheduler::free_cores_and_fill_claim_queue(just_updated, now); - - // ParaId a exists in the claim queue until max_retries is reached. - if n < max_timeouts + now { - assert!(claimqueue_contains_para_ids::(vec![para_a])); - } else { - assert!(!claimqueue_contains_para_ids::(vec![para_a])); - } - - let core_assignments = Scheduler::scheduled_paras().collect(); - Scheduler::occupied(core_assignments); - } - - // ParaId a does not exist in the claimqueue/availability_cores after - // threshold has been reached. - assert!(!claimqueue_contains_para_ids::(vec![para_a])); - assert!(!availability_cores_contains_para_ids::(vec![para_a])); - - // #25 - now += max_timeouts + 2; - - // Add assignment back to the mix. - MockAssigner::add_test_assignment(assignment_a.clone()); - run_to_block(now, |_| None); - - assert!(claimqueue_contains_para_ids::(vec![para_a])); - - // #26 - now += 1; - // Run to block #n but this time have group 1 conclude the availability. - for n in now..=(now + max_timeouts + 1) { - // #n - run_to_block(n, |_| None); - // Time out core 0 if group 0 is assigned to it, if group 1 is assigned, conclude. - let mut just_updated: BTreeMap = BTreeMap::new(); - if let Some(group) = Scheduler::group_assigned_to_core(CoreIndex(0), n) { - match group { - GroupIndex(0) => { - just_updated.insert(CoreIndex(0), FreedReason::TimedOut); // should go back on queue. - }, - GroupIndex(1) => { - just_updated.insert(CoreIndex(0), FreedReason::Concluded); - }, - _ => panic!("Should only have 2 groups here"), - } - } - - Scheduler::free_cores_and_fill_claim_queue(just_updated, now); - - // ParaId a exists in the claim queue until groups are rotated. - if n < 31 { - assert!(claimqueue_contains_para_ids::(vec![para_a])); - } else { - assert!(!claimqueue_contains_para_ids::(vec![para_a])); - } - - let core_assignments = Scheduler::scheduled_paras().collect(); - Scheduler::occupied(core_assignments); - } - - // ParaId a does not exist in the claimqueue/availability_cores after - // being concluded - assert!(!claimqueue_contains_para_ids::(vec![para_a])); - assert!(!availability_cores_contains_para_ids::(vec![para_a])); - }); -} - #[test] fn availability_predicate_works() { let genesis_config = genesis_config(&default_config()); @@ -948,20 +514,21 @@ fn availability_predicate_works() { #[test] fn next_up_on_available_uses_next_scheduled_or_none() { - let genesis_config = genesis_config(&default_config()); + let mut config = default_config(); + config.scheduler_params.num_cores = 1; + let genesis_config = genesis_config(&config); let para_a = ParaId::from(1_u32); let para_b = ParaId::from(2_u32); new_test_ext(genesis_config).execute_with(|| { - MockAssigner::set_core_count(1); - schedule_blank_para(para_a); - schedule_blank_para(para_b); + register_para(para_a); + register_para(para_b); // start a new session to activate, 2 validators for 2 cores. run_to_block(1, |number| match number { 1 => Some(SessionChangeNotification { - new_config: default_config(), + new_config: config.clone(), validators: vec![ ValidatorId::from(Sr25519Keyring::Alice.public()), ValidatorId::from(Sr25519Keyring::Eve.public()), @@ -971,69 +538,57 @@ fn next_up_on_available_uses_next_scheduled_or_none() { _ => None, }); - let entry_a = ParasEntry { - assignment: Assignment::Bulk(para_a), - availability_timeouts: 0 as u32, - ttl: 5 as u32, - }; - let entry_b = ParasEntry { - assignment: Assignment::Bulk(para_b), - availability_timeouts: 0 as u32, - ttl: 5 as u32, - }; - - Scheduler::add_to_claim_queue(CoreIndex(0), entry_a.clone()); + MockAssigner::add_test_assignment(Assignment::Bulk(para_a)); run_to_block(2, |_| None); { - assert_eq!(Scheduler::claim_queue_len(), 1); - assert_eq!(scheduler::AvailabilityCores::::get().len(), 1); - - let mut map = BTreeMap::new(); - map.insert(CoreIndex(0), para_a); - Scheduler::occupied(map); + // Two assignments for A on core 0, because the claim queue used to be empty. + assert_eq!(Scheduler::claim_queue_len(), 2); - let cores = scheduler::AvailabilityCores::::get(); - match &cores[0] { - CoreOccupied::Paras(entry) => assert_eq!(entry, &entry_a), - _ => panic!("There should only be one test assigner core"), - } - - assert!(Scheduler::next_up_on_available(CoreIndex(0)).is_none()); + assert!(Scheduler::next_up_on_available(CoreIndex(1)).is_none()); - Scheduler::add_to_claim_queue(CoreIndex(0), entry_b); + assert_eq!( + Scheduler::next_up_on_available(CoreIndex(0)).unwrap(), + ScheduledCore { para_id: para_a, collator: None } + ); + Scheduler::advance_claim_queue(&Default::default()); assert_eq!( Scheduler::next_up_on_available(CoreIndex(0)).unwrap(), - ScheduledCore { para_id: para_b, collator: None } + ScheduledCore { para_id: para_a, collator: None } ); + + Scheduler::advance_claim_queue(&Default::default()); + assert!(Scheduler::next_up_on_available(CoreIndex(0)).is_none()); } }); } #[test] -fn next_up_on_time_out_reuses_claim_if_nothing_queued() { - let genesis_config = genesis_config(&default_config()); +fn session_change_increasing_number_of_cores() { + let mut config = default_config(); + config.scheduler_params.num_cores = 2; + let genesis_config = genesis_config(&config); - let para_a = ParaId::from(1_u32); - let para_b = ParaId::from(2_u32); + let para_a = ParaId::from(3_u32); + let para_b = ParaId::from(4_u32); let assignment_a = Assignment::Bulk(para_a); let assignment_b = Assignment::Bulk(para_b); new_test_ext(genesis_config).execute_with(|| { - MockAssigner::set_core_count(1); - schedule_blank_para(para_a); - schedule_blank_para(para_b); + // Add 2 paras + register_para(para_a); + register_para(para_b); // start a new session to activate, 2 validators for 2 cores. run_to_block(1, |number| match number { 1 => Some(SessionChangeNotification { - new_config: default_config(), + new_config: config.clone(), validators: vec![ ValidatorId::from(Sr25519Keyring::Alice.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), + ValidatorId::from(Sr25519Keyring::Bob.public()), ], ..Default::default() }), @@ -1041,193 +596,236 @@ fn next_up_on_time_out_reuses_claim_if_nothing_queued() { }); MockAssigner::add_test_assignment(assignment_a.clone()); + MockAssigner::add_test_assignment(assignment_b.clone()); + // This will call advance_claim_queue run_to_block(2, |_| None); { - assert_eq!(scheduler::ClaimQueue::::get().len(), 1); - assert_eq!(scheduler::AvailabilityCores::::get().len(), 1); - - let mut map = BTreeMap::new(); - map.insert(CoreIndex(0), para_a); - Scheduler::occupied(map); - - let cores = scheduler::AvailabilityCores::::get(); - match cores.get(0).unwrap() { - CoreOccupied::Paras(entry) => { - assert_eq!(entry.assignment, assignment_a.clone()); - }, - _ => panic!("There should only be a single test assigner core"), - } - - // There's nothing more to pop for core 0 from the assignment provider. - assert!(MockAssigner::pop_assignment_for_core(CoreIndex(0)).is_none()); + let mut claim_queue = scheduler::ClaimQueue::::get(); + assert_eq!(Scheduler::claim_queue_len(), 4); assert_eq!( - Scheduler::next_up_on_time_out(CoreIndex(0)).unwrap(), - ScheduledCore { para_id: para_a, collator: None } + claim_queue.remove(&CoreIndex(0)).unwrap(), + [assignment_a.clone(), assignment_a.clone()] + .into_iter() + .collect::>() + ); + assert_eq!( + claim_queue.remove(&CoreIndex(1)).unwrap(), + [assignment_b.clone(), assignment_b.clone()] + .into_iter() + .collect::>() ); + } + + // Increase number of cores to 4. + let old_config = config; + let mut new_config = old_config.clone(); + new_config.scheduler_params.num_cores = 4; - MockAssigner::add_test_assignment(assignment_b.clone()); + // add another assignment for para b. + MockAssigner::add_test_assignment(assignment_b.clone()); + + run_to_block(3, |number| match number { + 3 => Some(SessionChangeNotification { + new_config: new_config.clone(), + prev_config: old_config.clone(), + validators: vec![ + ValidatorId::from(Sr25519Keyring::Alice.public()), + ValidatorId::from(Sr25519Keyring::Bob.public()), + ValidatorId::from(Sr25519Keyring::Charlie.public()), + ValidatorId::from(Sr25519Keyring::Dave.public()), + ], + ..Default::default() + }), + _ => None, + }); - // Pop assignment_b into the claimqueue - Scheduler::free_cores_and_fill_claim_queue(BTreeMap::new(), 2); + { + let mut claim_queue = scheduler::ClaimQueue::::get(); + assert_eq!(Scheduler::claim_queue_len(), 3); - //// Now that there is an earlier next-up, we use that. assert_eq!( - Scheduler::next_up_on_available(CoreIndex(0)).unwrap(), - ScheduledCore { para_id: para_b, collator: None } + claim_queue.remove(&CoreIndex(0)).unwrap(), + [assignment_a].into_iter().collect::>() + ); + assert_eq!( + claim_queue.remove(&CoreIndex(1)).unwrap(), + [assignment_b.clone()].into_iter().collect::>() + ); + assert_eq!( + claim_queue.remove(&CoreIndex(2)).unwrap(), + [assignment_b.clone()].into_iter().collect::>() ); } }); } #[test] -fn session_change_requires_reschedule_dropping_removed_paras() { +fn session_change_decreasing_number_of_cores() { let mut config = default_config(); - config.scheduler_params.lookahead = 1; + config.scheduler_params.num_cores = 3; let genesis_config = genesis_config(&config); - let para_a = ParaId::from(1_u32); - let para_b = ParaId::from(2_u32); + let para_a = ParaId::from(3_u32); + let para_b = ParaId::from(4_u32); let assignment_a = Assignment::Bulk(para_a); let assignment_b = Assignment::Bulk(para_b); new_test_ext(genesis_config).execute_with(|| { - // Setting explicit core count - MockAssigner::set_core_count(5); - let coretime_ttl = configuration::ActiveConfig::::get().scheduler_params.ttl; - - schedule_blank_para(para_a); - schedule_blank_para(para_b); - - // Add assignments - MockAssigner::add_test_assignment(assignment_a.clone()); - MockAssigner::add_test_assignment(assignment_b.clone()); + // Add 2 paras + register_para(para_a); + register_para(para_b); + // start a new session to activate, 2 validators for 2 cores. run_to_block(1, |number| match number { 1 => Some(SessionChangeNotification { - new_config: default_config(), + new_config: config.clone(), validators: vec![ ValidatorId::from(Sr25519Keyring::Alice.public()), ValidatorId::from(Sr25519Keyring::Bob.public()), - ValidatorId::from(Sr25519Keyring::Charlie.public()), - ValidatorId::from(Sr25519Keyring::Dave.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ValidatorId::from(Sr25519Keyring::Ferdie.public()), - ValidatorId::from(Sr25519Keyring::One.public()), ], - random_seed: [99; 32], ..Default::default() }), _ => None, }); - assert_eq!(scheduler::ClaimQueue::::get().len(), 2); + scheduler::Pallet::::set_claim_queue(BTreeMap::from([ + (CoreIndex::from(0), VecDeque::from([assignment_a.clone()])), + // Leave a hole for core 1. + (CoreIndex::from(2), VecDeque::from([assignment_b.clone(), assignment_b.clone()])), + ])); - let groups = ValidatorGroups::::get(); - assert_eq!(groups.len(), 5); + // Decrease number of cores to 1. + let old_config = config; + let mut new_config = old_config.clone(); + new_config.scheduler_params.num_cores = 1; - assert_ok!(Paras::schedule_para_cleanup(para_b)); + // Session change. + // Assignment A had its shot already so will be dropped for good. + // The two assignments of B will be pushed back to the assignment provider. + run_to_block(3, |number| match number { + 3 => Some(SessionChangeNotification { + new_config: new_config.clone(), + prev_config: old_config.clone(), + validators: vec![ValidatorId::from(Sr25519Keyring::Alice.public())], + ..Default::default() + }), + _ => None, + }); - // Add assignment - MockAssigner::add_test_assignment(assignment_a.clone()); + let mut claim_queue = scheduler::ClaimQueue::::get(); + assert_eq!(Scheduler::claim_queue_len(), 1); - run_to_end_of_block(2, |number| match number { - 2 => Some(SessionChangeNotification { - new_config: default_config(), + // There's only one assignment for B because run_to_block also calls advance_claim_queue at + // the end. + assert_eq!( + claim_queue.remove(&CoreIndex(0)).unwrap(), + [assignment_b.clone()].into_iter().collect::>() + ); + + // No more assignments now. + Scheduler::advance_claim_queue(&Default::default()); + assert_eq!(Scheduler::claim_queue_len(), 0); + }); +} + +#[test] +fn session_change_increasing_lookahead() { + let mut config = default_config(); + config.scheduler_params.num_cores = 2; + config.scheduler_params.lookahead = 2; + let genesis_config = genesis_config(&config); + + let para_a = ParaId::from(3_u32); + let para_b = ParaId::from(4_u32); + + let assignment_a = Assignment::Bulk(para_a); + let assignment_b = Assignment::Bulk(para_b); + + new_test_ext(genesis_config).execute_with(|| { + // Add 2 paras + register_para(para_a); + register_para(para_b); + + // start a new session to activate, 2 validators for 2 cores. + run_to_block(1, |number| match number { + 1 => Some(SessionChangeNotification { + new_config: config.clone(), validators: vec![ ValidatorId::from(Sr25519Keyring::Alice.public()), ValidatorId::from(Sr25519Keyring::Bob.public()), - ValidatorId::from(Sr25519Keyring::Charlie.public()), - ValidatorId::from(Sr25519Keyring::Dave.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ValidatorId::from(Sr25519Keyring::Ferdie.public()), - ValidatorId::from(Sr25519Keyring::One.public()), ], - random_seed: [99; 32], ..Default::default() }), _ => None, }); - Scheduler::free_cores_and_fill_claim_queue(BTreeMap::new(), 3); + MockAssigner::add_test_assignment(assignment_a.clone()); + MockAssigner::add_test_assignment(assignment_a.clone()); + MockAssigner::add_test_assignment(assignment_a.clone()); + MockAssigner::add_test_assignment(assignment_b.clone()); + MockAssigner::add_test_assignment(assignment_b.clone()); + MockAssigner::add_test_assignment(assignment_b.clone()); + + // Lookahead is currently 2. - assert_eq!( - scheduler::ClaimQueue::::get(), - vec![( - CoreIndex(0), - vec![ParasEntry::new( - Assignment::Bulk(para_a), - // At end of block 2 - coretime_ttl + 2 - )] - .into_iter() - .collect() - )] - .into_iter() - .collect() - ); + run_to_block(2, |_| None); - // Add para back - schedule_blank_para(para_b); + { + let mut claim_queue = scheduler::ClaimQueue::::get(); + assert_eq!(Scheduler::claim_queue_len(), 4); - // Add assignments - MockAssigner::add_test_assignment(assignment_a.clone()); - MockAssigner::add_test_assignment(assignment_b.clone()); + assert_eq!( + claim_queue.remove(&CoreIndex(0)).unwrap(), + [assignment_a.clone(), assignment_a.clone()] + .into_iter() + .collect::>() + ); + assert_eq!( + claim_queue.remove(&CoreIndex(1)).unwrap(), + [assignment_a.clone(), assignment_a.clone()] + .into_iter() + .collect::>() + ); + } + + // Increase lookahead to 4. + let old_config = config; + let mut new_config = old_config.clone(); + new_config.scheduler_params.lookahead = 4; run_to_block(3, |number| match number { 3 => Some(SessionChangeNotification { - new_config: default_config(), + new_config: new_config.clone(), + prev_config: old_config.clone(), validators: vec![ ValidatorId::from(Sr25519Keyring::Alice.public()), ValidatorId::from(Sr25519Keyring::Bob.public()), - ValidatorId::from(Sr25519Keyring::Charlie.public()), - ValidatorId::from(Sr25519Keyring::Dave.public()), - ValidatorId::from(Sr25519Keyring::Eve.public()), - ValidatorId::from(Sr25519Keyring::Ferdie.public()), - ValidatorId::from(Sr25519Keyring::One.public()), ], - random_seed: [99; 32], ..Default::default() }), _ => None, }); - assert_eq!(scheduler::ClaimQueue::::get().len(), 2); - - let groups = ValidatorGroups::::get(); - assert_eq!(groups.len(), 5); - - Scheduler::free_cores_and_fill_claim_queue(BTreeMap::new(), 4); + { + let mut claim_queue = scheduler::ClaimQueue::::get(); + assert_eq!(Scheduler::claim_queue_len(), 6); - assert_eq!( - scheduler::ClaimQueue::::get(), - vec![ - ( - CoreIndex(0), - vec![ParasEntry::new( - Assignment::Bulk(para_a), - // At block 3 - coretime_ttl + 3 - )] + assert_eq!( + claim_queue.remove(&CoreIndex(0)).unwrap(), + [assignment_a.clone(), assignment_a.clone(), assignment_b.clone()] .into_iter() - .collect() - ), - ( - CoreIndex(1), - vec![ParasEntry::new( - Assignment::Bulk(para_b), - // At block 3 - coretime_ttl + 3 - )] + .collect::>() + ); + assert_eq!( + claim_queue.remove(&CoreIndex(1)).unwrap(), + [assignment_a.clone(), assignment_b.clone(), assignment_b.clone()] .into_iter() - .collect() - ), - ] - .into_iter() - .collect() - ); + .collect::>() + ); + } }); } diff --git a/polkadot/runtime/parachains/src/session_info.rs b/polkadot/runtime/parachains/src/session_info.rs index ea05c1aacaa9..0ec01755095b 100644 --- a/polkadot/runtime/parachains/src/session_info.rs +++ b/polkadot/runtime/parachains/src/session_info.rs @@ -135,8 +135,8 @@ impl Pallet { let assignment_keys = AssignmentKeysUnsafe::::get(); let active_set = shared::ActiveValidatorIndices::::get(); - let validator_groups = scheduler::ValidatorGroups::::get().into(); - let n_cores = scheduler::AvailabilityCores::::get().len() as u32; + let validator_groups = scheduler::ValidatorGroups::::get(); + let n_cores = validator_groups.len() as u32; let zeroth_delay_tranche_width = config.zeroth_delay_tranche_width; let relay_vrf_modulo_samples = config.relay_vrf_modulo_samples; let n_delay_tranches = config.n_delay_tranches; @@ -177,7 +177,7 @@ impl Pallet { validators, // these are from the notification and are thus already correct. discovery_keys: take_active_subset_and_inactive(&active_set, &discovery_keys), assignment_keys: take_active_subset(&active_set, &assignment_keys), - validator_groups, + validator_groups: validator_groups.into(), n_cores, zeroth_delay_tranche_width, relay_vrf_modulo_samples, diff --git a/polkadot/runtime/parachains/src/session_info/tests.rs b/polkadot/runtime/parachains/src/session_info/tests.rs index 3e81ca498713..aec0ff56e670 100644 --- a/polkadot/runtime/parachains/src/session_info/tests.rs +++ b/polkadot/runtime/parachains/src/session_info/tests.rs @@ -24,7 +24,7 @@ use crate::{ }, util::take_active_subset, }; -use polkadot_primitives::{vstaging::SchedulerParams, BlockNumber, ValidatorId, ValidatorIndex}; +use polkadot_primitives::{BlockNumber, SchedulerParams, ValidatorId, ValidatorIndex}; use sp_keyring::Sr25519Keyring; fn run_to_block( diff --git a/polkadot/runtime/parachains/src/shared.rs b/polkadot/runtime/parachains/src/shared.rs index 154b7cfefc3a..473c1aba7a06 100644 --- a/polkadot/runtime/parachains/src/shared.rs +++ b/polkadot/runtime/parachains/src/shared.rs @@ -20,12 +20,14 @@ //! dependent on any of the other pallets. use alloc::{ - collections::{btree_map::BTreeMap, vec_deque::VecDeque}, + collections::{btree_map::BTreeMap, btree_set::BTreeSet, vec_deque::VecDeque}, vec::Vec, }; use frame_support::{pallet_prelude::*, traits::DisabledValidators}; use frame_system::pallet_prelude::BlockNumberFor; -use polkadot_primitives::{SessionIndex, ValidatorId, ValidatorIndex}; +use polkadot_primitives::{ + vstaging::transpose_claim_queue, CoreIndex, Id, SessionIndex, ValidatorId, ValidatorIndex, +}; use sp_runtime::traits::AtLeast32BitUnsigned; use rand::{seq::SliceRandom, SeedableRng}; @@ -43,16 +45,28 @@ pub(crate) const SESSION_DELAY: SessionIndex = 2; #[cfg(test)] mod tests; -/// Information about past relay-parents. +pub mod migration; + +/// Information about a relay parent. +#[derive(Encode, Decode, Default, TypeInfo, Debug)] +pub struct RelayParentInfo { + // Relay parent hash + pub relay_parent: Hash, + // The state root at this block + pub state_root: Hash, + // Claim queue snapshot, optimized for accessing the assignments by `ParaId`. + // For each para we store the cores assigned per depth. + pub claim_queue: BTreeMap>>, +} + +/// Keeps tracks of information about all viable relay parents. #[derive(Encode, Decode, Default, TypeInfo)] pub struct AllowedRelayParentsTracker { - // The past relay parents, paired with state roots, that are viable to build upon. + // Information about past relay parents that are viable to build upon. // // They are in ascending chronologic order, so the newest relay parents are at // the back of the deque. - // - // (relay_parent, state_root) - buffer: VecDeque<(Hash, Hash)>, + buffer: VecDeque>, // The number of the most recent relay-parent, if any. // If the buffer is empty, this value has no meaning and may @@ -66,17 +80,27 @@ impl /// Add a new relay-parent to the allowed relay parents, along with info about the header. /// Provide a maximum ancestry length for the buffer, which will cause old relay-parents to be /// pruned. + /// If the relay parent hash is already present, do nothing. pub(crate) fn update( &mut self, relay_parent: Hash, state_root: Hash, + claim_queue: BTreeMap>, number: BlockNumber, max_ancestry_len: u32, ) { + if self.buffer.iter().any(|info| info.relay_parent == relay_parent) { + // Already present. + return + } + + let claim_queue = transpose_claim_queue(claim_queue); + // + 1 for the most recent block, which is always allowed. let buffer_size_limit = max_ancestry_len as usize + 1; - self.buffer.push_back((relay_parent, state_root)); + self.buffer.push_back(RelayParentInfo { relay_parent, state_root, claim_queue }); + self.latest_number = number; while self.buffer.len() > buffer_size_limit { let _ = self.buffer.pop_front(); @@ -96,8 +120,8 @@ impl &self, relay_parent: Hash, prev: Option, - ) -> Option<(Hash, BlockNumber)> { - let pos = self.buffer.iter().position(|(rp, _)| rp == &relay_parent)?; + ) -> Option<(&RelayParentInfo, BlockNumber)> { + let pos = self.buffer.iter().position(|info| info.relay_parent == relay_parent)?; let age = (self.buffer.len() - 1) - pos; let number = self.latest_number - BlockNumber::from(age as u32); @@ -107,7 +131,7 @@ impl } } - Some((self.buffer[pos].1, number)) + Some((&self.buffer[pos], number)) } /// Returns block number of the earliest block the buffer would contain if @@ -127,8 +151,11 @@ impl pub mod pallet { use super::*; + const STORAGE_VERSION: StorageVersion = StorageVersion::new(1); + #[pallet::pallet] #[pallet::without_storage_info] + #[pallet::storage_version(STORAGE_VERSION)] pub struct Pallet(_); #[pallet::config] @@ -263,11 +290,12 @@ impl Pallet { pub(crate) fn add_allowed_relay_parent( relay_parent: T::Hash, state_root: T::Hash, + claim_queue: BTreeMap>, number: BlockNumberFor, max_ancestry_len: u32, ) { AllowedRelayParents::::mutate(|tracker| { - tracker.update(relay_parent, state_root, number, max_ancestry_len) + tracker.update(relay_parent, state_root, claim_queue, number, max_ancestry_len) }) } } diff --git a/polkadot/runtime/parachains/src/shared/migration.rs b/polkadot/runtime/parachains/src/shared/migration.rs new file mode 100644 index 000000000000..ae0412c6e26c --- /dev/null +++ b/polkadot/runtime/parachains/src/shared/migration.rs @@ -0,0 +1,196 @@ +// 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. + +use super::*; +use codec::{Decode, Encode}; +use frame_support::{ + pallet_prelude::ValueQuery, traits::UncheckedOnRuntimeUpgrade, weights::Weight, +}; + +#[cfg(feature = "try-runtime")] +const LOG_TARGET: &str = "runtime::shared"; + +pub mod v0 { + use super::*; + use alloc::collections::vec_deque::VecDeque; + + use frame_support::storage_alias; + + /// All allowed relay-parents storage at version 0. + #[storage_alias] + pub(crate) type AllowedRelayParents = StorageValue< + Pallet, + super::v0::AllowedRelayParentsTracker<::Hash, BlockNumberFor>, + ValueQuery, + >; + + #[derive(Encode, Decode, Default, TypeInfo)] + pub struct AllowedRelayParentsTracker { + // The past relay parents, paired with state roots, that are viable to build upon. + // + // They are in ascending chronologic order, so the newest relay parents are at + // the back of the deque. + // + // (relay_parent, state_root) + pub buffer: VecDeque<(Hash, Hash)>, + + // The number of the most recent relay-parent, if any. + // If the buffer is empty, this value has no meaning and may + // be nonsensical. + pub latest_number: BlockNumber, + } + + // Required to workaround #64. + impl + AllowedRelayParentsTracker + { + /// Returns block number of the earliest block the buffer would contain if + /// `now` is pushed into it. + pub(crate) fn hypothetical_earliest_block_number( + &self, + now: BlockNumber, + max_ancestry_len: u32, + ) -> BlockNumber { + let allowed_ancestry_len = max_ancestry_len.min(self.buffer.len() as u32); + + now - allowed_ancestry_len.into() + } + } + + impl From> + for super::AllowedRelayParentsTracker + { + fn from(value: AllowedRelayParentsTracker) -> Self { + Self { + latest_number: value.latest_number, + buffer: value + .buffer + .into_iter() + .map(|(relay_parent, state_root)| super::RelayParentInfo { + relay_parent, + state_root, + claim_queue: Default::default(), + }) + .collect(), + } + } + } +} + +mod v1 { + use super::*; + + #[cfg(feature = "try-runtime")] + use frame_support::{ + ensure, + traits::{GetStorageVersion, StorageVersion}, + }; + + pub struct VersionUncheckedMigrateToV1(core::marker::PhantomData); + + impl UncheckedOnRuntimeUpgrade for VersionUncheckedMigrateToV1 { + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { + log::trace!(target: LOG_TARGET, "Running pre_upgrade() for shared MigrateToV1"); + let bytes = u32::to_ne_bytes(v0::AllowedRelayParents::::get().buffer.len() as u32); + + Ok(bytes.to_vec()) + } + + fn on_runtime_upgrade() -> Weight { + let mut weight: Weight = Weight::zero(); + + // Read old storage. + let old_rp_tracker = v0::AllowedRelayParents::::take(); + + super::AllowedRelayParents::::set(old_rp_tracker.into()); + + weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1)); + + weight + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { + log::trace!(target: LOG_TARGET, "Running post_upgrade() for shared MigrateToV1"); + ensure!( + Pallet::::on_chain_storage_version() >= StorageVersion::new(1), + "Storage version should be >= 1 after the migration" + ); + + let relay_parent_count = u32::from_ne_bytes( + state + .try_into() + .expect("u32::from_ne_bytes(to_ne_bytes(u32)) always works; qed"), + ); + + let rp_tracker = AllowedRelayParents::::get(); + + ensure!( + relay_parent_count as usize == rp_tracker.buffer.len(), + "Number of allowed relay parents should be the same as the one before the upgrade." + ); + + Ok(()) + } + } +} + +/// Migrate shared module storage to v1. +pub type MigrateToV1 = frame_support::migrations::VersionedMigration< + 0, + 1, + v1::VersionUncheckedMigrateToV1, + Pallet, + ::DbWeight, +>; + +#[cfg(test)] +mod tests { + use super::{v1::VersionUncheckedMigrateToV1, *}; + use crate::mock::{new_test_ext, MockGenesisConfig, Test}; + use frame_support::traits::UncheckedOnRuntimeUpgrade; + use polkadot_primitives::Hash; + + #[test] + fn migrate_to_v1() { + new_test_ext(MockGenesisConfig::default()).execute_with(|| { + let rp_tracker = v0::AllowedRelayParentsTracker { + latest_number: 9, + buffer: (0..10u64) + .into_iter() + .map(|idx| (Hash::from_low_u64_ne(idx), Hash::from_low_u64_ne(2 * idx))) + .collect::>(), + }; + + v0::AllowedRelayParents::::put(rp_tracker); + + as UncheckedOnRuntimeUpgrade>::on_runtime_upgrade(); + + let rp_tracker = AllowedRelayParents::::get(); + + assert_eq!(rp_tracker.buffer.len(), 10); + + for idx in 0..10u64 { + let relay_parent = Hash::from_low_u64_ne(idx); + let state_root = Hash::from_low_u64_ne(2 * idx); + let (info, block_num) = rp_tracker.acquire_info(relay_parent, None).unwrap(); + + assert!(info.claim_queue.is_empty()); + assert_eq!(info.relay_parent, relay_parent); + assert_eq!(info.state_root, state_root); + assert_eq!(block_num as u64, idx); + } + }); + } +} diff --git a/polkadot/runtime/parachains/src/shared/tests.rs b/polkadot/runtime/parachains/src/shared/tests.rs index e47d1fd9cfe0..f7ea5148ce33 100644 --- a/polkadot/runtime/parachains/src/shared/tests.rs +++ b/polkadot/runtime/parachains/src/shared/tests.rs @@ -36,22 +36,77 @@ fn tracker_earliest_block_number() { // Push a single block into the tracker, suppose max capacity is 1. let max_ancestry_len = 0; - tracker.update(Hash::zero(), Hash::zero(), 0, max_ancestry_len); + tracker.update(Hash::zero(), Hash::zero(), Default::default(), 0, max_ancestry_len); assert_eq!(tracker.hypothetical_earliest_block_number(now, max_ancestry_len), now); // Test a greater capacity. let max_ancestry_len = 4; let now = 4; for i in 1..now { - tracker.update(Hash::zero(), Hash::zero(), i, max_ancestry_len); + tracker.update( + Hash::from([i as u8; 32]), + Hash::zero(), + Default::default(), + i, + max_ancestry_len, + ); assert_eq!(tracker.hypothetical_earliest_block_number(i + 1, max_ancestry_len), 0); } // Capacity exceeded. - tracker.update(Hash::zero(), Hash::zero(), now, max_ancestry_len); + tracker.update(Hash::zero(), Hash::zero(), Default::default(), now, max_ancestry_len); assert_eq!(tracker.hypothetical_earliest_block_number(now + 1, max_ancestry_len), 1); } +#[test] +fn tracker_claim_queue_transpose() { + let mut tracker = AllowedRelayParentsTracker::::default(); + + let mut claim_queue = BTreeMap::new(); + claim_queue.insert(CoreIndex(0), vec![Id::from(0), Id::from(1), Id::from(2)].into()); + claim_queue.insert(CoreIndex(1), vec![Id::from(0), Id::from(0), Id::from(100)].into()); + claim_queue.insert(CoreIndex(2), vec![Id::from(1), Id::from(2), Id::from(100)].into()); + + tracker.update(Hash::zero(), Hash::zero(), claim_queue, 1u32, 3u32); + + let (info, _block_num) = tracker.acquire_info(Hash::zero(), None).unwrap(); + assert_eq!( + info.claim_queue.get(&Id::from(0)).unwrap()[&0], + vec![CoreIndex(0), CoreIndex(1)].into_iter().collect::>() + ); + assert_eq!( + info.claim_queue.get(&Id::from(1)).unwrap()[&0], + vec![CoreIndex(2)].into_iter().collect::>() + ); + assert_eq!(info.claim_queue.get(&Id::from(2)).unwrap().get(&0), None); + assert_eq!(info.claim_queue.get(&Id::from(100)).unwrap().get(&0), None); + + assert_eq!( + info.claim_queue.get(&Id::from(0)).unwrap()[&1], + vec![CoreIndex(1)].into_iter().collect::>() + ); + assert_eq!( + info.claim_queue.get(&Id::from(1)).unwrap()[&1], + vec![CoreIndex(0)].into_iter().collect::>() + ); + assert_eq!( + info.claim_queue.get(&Id::from(2)).unwrap()[&1], + vec![CoreIndex(2)].into_iter().collect::>() + ); + assert_eq!(info.claim_queue.get(&Id::from(100)).unwrap().get(&1), None); + + assert_eq!(info.claim_queue.get(&Id::from(0)).unwrap().get(&2), None); + assert_eq!(info.claim_queue.get(&Id::from(1)).unwrap().get(&2), None); + assert_eq!( + info.claim_queue.get(&Id::from(2)).unwrap()[&2], + vec![CoreIndex(0)].into_iter().collect::>() + ); + assert_eq!( + info.claim_queue.get(&Id::from(100)).unwrap()[&2], + vec![CoreIndex(1), CoreIndex(2)].into_iter().collect::>() + ); +} + #[test] fn tracker_acquire_info() { let mut tracker = AllowedRelayParentsTracker::::default(); @@ -65,20 +120,28 @@ fn tracker_acquire_info() { ]; let (relay_parent, state_root) = blocks[0]; - tracker.update(relay_parent, state_root, 0, max_ancestry_len); + tracker.update(relay_parent, state_root, Default::default(), 0, max_ancestry_len); + assert_matches!( + tracker.acquire_info(relay_parent, None), + Some((s, b)) if s.state_root == state_root && b == 0 + ); + + // Try to push a duplicate. Should be ignored. + tracker.update(relay_parent, Hash::repeat_byte(13), Default::default(), 0, max_ancestry_len); + assert_eq!(tracker.buffer.len(), 1); assert_matches!( tracker.acquire_info(relay_parent, None), - Some((s, b)) if s == state_root && b == 0 + Some((s, b)) if s.state_root == state_root && b == 0 ); let (relay_parent, state_root) = blocks[1]; - tracker.update(relay_parent, state_root, 1u32, max_ancestry_len); + tracker.update(relay_parent, state_root, Default::default(), 1u32, max_ancestry_len); let (relay_parent, state_root) = blocks[2]; - tracker.update(relay_parent, state_root, 2u32, max_ancestry_len); + tracker.update(relay_parent, state_root, Default::default(), 2u32, max_ancestry_len); for (block_num, (rp, state_root)) in blocks.iter().enumerate().take(2) { assert_matches!( tracker.acquire_info(*rp, None), - Some((s, b)) if &s == state_root && b == block_num as u32 + Some((s, b)) if &s.state_root == state_root && b == block_num as u32 ); assert!(tracker.acquire_info(*rp, Some(2)).is_none()); @@ -87,7 +150,7 @@ fn tracker_acquire_info() { for (block_num, (rp, state_root)) in blocks.iter().enumerate().skip(1) { assert_matches!( tracker.acquire_info(*rp, Some(block_num as u32 - 1)), - Some((s, b)) if &s == state_root && b == block_num as u32 + Some((s, b)) if &s.state_root == state_root && b == block_num as u32 ); } } diff --git a/polkadot/runtime/parachains/src/ump_tests.rs b/polkadot/runtime/parachains/src/ump_tests.rs index d914bf8b6661..cd7951ac9aa9 100644 --- a/polkadot/runtime/parachains/src/ump_tests.rs +++ b/polkadot/runtime/parachains/src/ump_tests.rs @@ -31,7 +31,10 @@ use frame_support::{ traits::{EnqueueMessage, ExecuteOverweightError, ServiceQueues}, weights::Weight, }; -use polkadot_primitives::{well_known_keys, Id as ParaId, UpwardMessage}; +use polkadot_primitives::{ + vstaging::{ClaimQueueOffset, CoreSelector, UMPSignal, UMP_SEPARATOR}, + well_known_keys, Id as ParaId, UpwardMessage, +}; use sp_crypto_hashing::{blake2_256, twox_64}; use sp_runtime::traits::Bounded; @@ -141,12 +144,12 @@ mod check_upward_messages { configuration::ActiveConfig::::get().max_upward_message_num_per_candidate; for sent in 0..permitted + 1 { - check(P_0, vec![msg(""); sent as usize], None); + check(P_0, vec![msg("a"); sent as usize], None); } for sent in permitted + 1..permitted + 10 { check( P_0, - vec![msg(""); sent as usize], + vec![msg("a"); sent as usize], Some(UmpAcceptanceCheckErr::MoreMessagesThanPermitted { sent, permitted }), ); } @@ -161,7 +164,7 @@ mod check_upward_messages { let max_per_candidate = configuration::ActiveConfig::::get().max_upward_message_num_per_candidate; - for msg_size in 0..=max_size { + for msg_size in 1..=max_size { check(P_0, vec![vec![0; msg_size as usize]], None); } for msg_size in max_size + 1..max_size + 10 { @@ -185,18 +188,18 @@ mod check_upward_messages { let limit = configuration::ActiveConfig::::get().max_upward_queue_count as u64; for _ in 0..limit { - check(P_0, vec![msg("")], None); - queue(P_0, vec![msg("")]); + check(P_0, vec![msg("a")], None); + queue(P_0, vec![msg("a")]); } check( P_0, - vec![msg("")], + vec![msg("a")], Some(UmpAcceptanceCheckErr::CapacityExceeded { count: limit + 1, limit }), ); check( P_0, - vec![msg(""); 2], + vec![msg("a"); 2], Some(UmpAcceptanceCheckErr::CapacityExceeded { count: limit + 2, limit }), ); }); @@ -462,10 +465,11 @@ fn verify_relay_dispatch_queue_size_is_externally_accessible() { fn assert_queue_size(para: ParaId, count: u32, size: u32) { #[allow(deprecated)] - let raw_queue_size = sp_io::storage::get(&well_known_keys::relay_dispatch_queue_size(para)).expect( - "enqueuing a message should create the dispatch queue\ + let raw_queue_size = sp_io::storage::get(&well_known_keys::relay_dispatch_queue_size(para)) + .expect( + "enqueuing a message should create the dispatch queue\ and it should be accessible via the well known keys", - ); + ); let (c, s) = <(u32, u32)>::decode(&mut &raw_queue_size[..]) .expect("the dispatch queue size should be decodable into (u32, u32)"); assert_eq!((c, s), (count, size)); @@ -641,6 +645,42 @@ fn cannot_offboard_while_ump_dispatch_queued() { }); } +/// Test UMP signals are filtered out and don't consume `max_upward_message_num_per_candidate`. +#[test] +fn enqueue_ump_signals() { + let para = 100.into(); + + new_test_ext(GenesisConfigBuilder::default().build()).execute_with(|| { + register_parachain(para); + run_to_block(5, vec![4, 5]); + + let config = configuration::ActiveConfig::::get(); + let mut messages = (0..config.max_upward_message_num_per_candidate) + .into_iter() + .map(|_| "msg".encode()) + .collect::>(); + let expected_messages = messages.iter().cloned().map(|msg| (para, msg)).collect::>(); + + // `UMPSignals` and separator do not count as XCM messages. The below check must pass. + messages.append(&mut vec![ + UMP_SEPARATOR, + UMPSignal::SelectCore(CoreSelector(0), ClaimQueueOffset(0)).encode(), + ]); + + ParaInclusion::check_upward_messages( + &configuration::ActiveConfig::::get(), + para, + &messages, + ) + .unwrap(); + + // We expect that all messages except UMP signal and separator are processed + ParaInclusion::receive_upward_messages(para, &messages); + MessageQueue::service_queues(Weight::max_value()); + assert_eq!(Processed::take(), expected_messages); + }); +} + /// A para-chain cannot send an UMP to the relay chain while it is offboarding. #[test] fn cannot_enqueue_ump_while_offboarding() { diff --git a/polkadot/runtime/rococo/Cargo.toml b/polkadot/runtime/rococo/Cargo.toml index f93a3ad65754..6bcb0da3d999 100644 --- a/polkadot/runtime/rococo/Cargo.toml +++ b/polkadot/runtime/rococo/Cargo.toml @@ -42,6 +42,7 @@ sp-storage = { workspace = true } sp-version = { workspace = true } sp-transaction-pool = { workspace = true } sp-block-builder = { workspace = true } +sp-keyring = { workspace = true } pallet-authority-discovery = { workspace = true } pallet-authorship = { workspace = true } @@ -226,6 +227,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", @@ -254,6 +256,7 @@ runtime-benchmarks = [ "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "pallet-tips/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", @@ -330,9 +333,12 @@ 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 # to make it smaller, like logging for example. -on-chain-release-build = ["metadata-hash", "sp-api/disable-logging"] +on-chain-release-build = ["metadata-hash"] diff --git a/polkadot/runtime/rococo/build.rs b/polkadot/runtime/rococo/build.rs index 7aae84cd5e0f..aab666b0f11c 100644 --- a/polkadot/runtime/rococo/build.rs +++ b/polkadot/runtime/rococo/build.rs @@ -1,18 +1,18 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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 Substrate. If not, see . +// along with Polkadot. If not, see . #[cfg(all(not(feature = "metadata-hash"), feature = "std"))] fn main() { diff --git a/polkadot/runtime/rococo/constants/Cargo.toml b/polkadot/runtime/rococo/constants/Cargo.toml index b67c36d71fd8..1d0adac44af4 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/constants/src/weights/block_weights.rs b/polkadot/runtime/rococo/constants/src/weights/block_weights.rs index e2aa4a6cab7f..f7dc2f19316d 100644 --- a/polkadot/runtime/rococo/constants/src/weights/block_weights.rs +++ b/polkadot/runtime/rococo/constants/src/weights/block_weights.rs @@ -14,13 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26 (Y/M/D) -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29 (Y/M/D) +//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! //! SHORT-NAME: `block`, LONG-NAME: `BlockExecution`, RUNTIME: `Development` //! WARMUPS: `10`, REPEAT: `100` -//! WEIGHT-PATH: `runtime/rococo/constants/src/weights/` +//! WEIGHT-PATH: `./polkadot/runtime/rococo/constants/src/weights/` //! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1.0`, WEIGHT-ADD: `0` // Executed Command: @@ -28,12 +28,11 @@ // benchmark // overhead // --chain=rococo-dev -// --execution=wasm // --wasm-execution=compiled -// --weight-path=runtime/rococo/constants/src/weights/ +// --weight-path=./polkadot/runtime/rococo/constants/src/weights/ // --warmup=10 // --repeat=100 -// --header=./file_header.txt +// --header=./polkadot/file_header.txt use sp_core::parameter_types; use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight}; @@ -43,17 +42,17 @@ parameter_types! { /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 408_659, 450_716 - /// Average: 417_412 - /// Median: 411_177 - /// Std-Dev: 12242.31 + /// Min, Max: 440_142, 476_907 + /// Average: 450_240 + /// Median: 448_633 + /// Std-Dev: 7301.18 /// /// Percentiles nanoseconds: - /// 99th: 445_142 - /// 95th: 442_275 - /// 75th: 414_217 + /// 99th: 470_733 + /// 95th: 465_082 + /// 75th: 452_536 pub const BlockExecutionWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(417_412), 0); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(450_240), 0); } #[cfg(test)] diff --git a/polkadot/runtime/rococo/constants/src/weights/extrinsic_weights.rs b/polkadot/runtime/rococo/constants/src/weights/extrinsic_weights.rs index adce840ebbc1..000cee8a237c 100644 --- a/polkadot/runtime/rococo/constants/src/weights/extrinsic_weights.rs +++ b/polkadot/runtime/rococo/constants/src/weights/extrinsic_weights.rs @@ -14,13 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26 (Y/M/D) -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29 (Y/M/D) +//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! //! SHORT-NAME: `extrinsic`, LONG-NAME: `ExtrinsicBase`, RUNTIME: `Development` //! WARMUPS: `10`, REPEAT: `100` -//! WEIGHT-PATH: `runtime/rococo/constants/src/weights/` +//! WEIGHT-PATH: `./polkadot/runtime/rococo/constants/src/weights/` //! WEIGHT-METRIC: `Average`, WEIGHT-MUL: `1.0`, WEIGHT-ADD: `0` // Executed Command: @@ -28,12 +28,11 @@ // benchmark // overhead // --chain=rococo-dev -// --execution=wasm // --wasm-execution=compiled -// --weight-path=runtime/rococo/constants/src/weights/ +// --weight-path=./polkadot/runtime/rococo/constants/src/weights/ // --warmup=10 // --repeat=100 -// --header=./file_header.txt +// --header=./polkadot/file_header.txt use sp_core::parameter_types; use sp_weights::{constants::WEIGHT_REF_TIME_PER_NANOS, Weight}; @@ -43,17 +42,17 @@ parameter_types! { /// Calculated by multiplying the *Average* with `1.0` and adding `0`. /// /// Stats nanoseconds: - /// Min, Max: 97_574, 100_119 - /// Average: 98_236 - /// Median: 98_179 - /// Std-Dev: 394.9 + /// Min, Max: 92_961, 94_143 + /// Average: 93_369 + /// Median: 93_331 + /// Std-Dev: 217.39 /// /// Percentiles nanoseconds: - /// 99th: 99_893 - /// 95th: 98_850 - /// 75th: 98_318 + /// 99th: 93_848 + /// 95th: 93_691 + /// 75th: 93_514 pub const ExtrinsicBaseWeight: Weight = - Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(98_236), 0); + Weight::from_parts(WEIGHT_REF_TIME_PER_NANOS.saturating_mul(93_369), 0); } #[cfg(test)] diff --git a/polkadot/runtime/rococo/constants/src/weights/mod.rs b/polkadot/runtime/rococo/constants/src/weights/mod.rs index 23812ce7ed05..2648608a2f8a 100644 --- a/polkadot/runtime/rococo/constants/src/weights/mod.rs +++ b/polkadot/runtime/rococo/constants/src/weights/mod.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Polkadot. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/polkadot/runtime/rococo/constants/src/weights/paritydb_weights.rs b/polkadot/runtime/rococo/constants/src/weights/paritydb_weights.rs index 25679703831a..67d5286022ee 100644 --- a/polkadot/runtime/rococo/constants/src/weights/paritydb_weights.rs +++ b/polkadot/runtime/rococo/constants/src/weights/paritydb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Polkadot. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/polkadot/runtime/rococo/constants/src/weights/rocksdb_weights.rs b/polkadot/runtime/rococo/constants/src/weights/rocksdb_weights.rs index 3dd817aa6f13..57f49e1202c1 100644 --- a/polkadot/runtime/rococo/constants/src/weights/rocksdb_weights.rs +++ b/polkadot/runtime/rococo/constants/src/weights/rocksdb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Polkadot. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/polkadot/runtime/rococo/src/genesis_config_presets.rs b/polkadot/runtime/rococo/src/genesis_config_presets.rs index 67dcd6cd7a51..d609548aed27 100644 --- a/polkadot/runtime/rococo/src/genesis_config_presets.rs +++ b/polkadot/runtime/rococo/src/genesis_config_presets.rs @@ -16,35 +16,22 @@ //! Genesis configs presets for the Rococo runtime -use crate::{SessionKeys, BABE_GENESIS_EPOCH_CONFIG}; +use crate::{ + BabeConfig, BalancesConfig, ConfigurationConfig, RegistrarConfig, RuntimeGenesisConfig, + SessionConfig, SessionKeys, SudoConfig, BABE_GENESIS_EPOCH_CONFIG, +}; #[cfg(not(feature = "std"))] use alloc::format; -use alloc::vec::Vec; -use polkadot_primitives::{ - vstaging::SchedulerParams, AccountId, AccountPublic, AssignmentId, ValidatorId, -}; +use alloc::{vec, vec::Vec}; +use polkadot_primitives::{AccountId, AssignmentId, SchedulerParams, ValidatorId}; use rococo_runtime_constants::currency::UNITS as ROC; use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; use sp_consensus_beefy::ecdsa_crypto::AuthorityId as BeefyId; use sp_consensus_grandpa::AuthorityId as GrandpaId; -use sp_core::{sr25519, Pair, Public}; -use sp_runtime::traits::IdentifyAccount; - -/// Helper function to generate a crypto pair from seed -fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() -} - -/// Helper function to generate an account ID from seed -fn get_account_id_from_seed(seed: &str) -> AccountId -where - AccountPublic: From<::Public>, -{ - AccountPublic::from(get_from_seed::(seed)).into_account() -} +use sp_core::{crypto::get_public_from_string_or_panic, sr25519}; +use sp_genesis_builder::PresetId; +use sp_keyring::Sr25519Keyring; /// Helper function to generate stash, controller and session key from seed fn get_authority_keys_from_seed( @@ -60,7 +47,16 @@ fn get_authority_keys_from_seed( BeefyId, ) { let keys = get_authority_keys_from_seed_no_beefy(seed); - (keys.0, keys.1, keys.2, keys.3, keys.4, keys.5, keys.6, get_from_seed::(seed)) + ( + keys.0, + keys.1, + keys.2, + keys.3, + keys.4, + keys.5, + keys.6, + get_public_from_string_or_panic::(seed), + ) } /// Helper function to generate stash, controller and session key from seed @@ -68,31 +64,18 @@ fn get_authority_keys_from_seed_no_beefy( seed: &str, ) -> (AccountId, AccountId, BabeId, GrandpaId, ValidatorId, AssignmentId, AuthorityDiscoveryId) { ( - get_account_id_from_seed::(&format!("{}//stash", seed)), - get_account_id_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), + get_public_from_string_or_panic::(&format!("{}//stash", seed)).into(), + get_public_from_string_or_panic::(seed).into(), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), ) } fn testnet_accounts() -> Vec { - Vec::from([ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ]) + Sr25519Keyring::well_known().map(|x| x.to_account_id()).collect() } fn rococo_session_keys( @@ -180,12 +163,12 @@ fn rococo_testnet_genesis( const ENDOWMENT: u128 = 1_000_000 * ROC; - serde_json::json!({ - "balances": { - "balances": endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect::>(), + let config = RuntimeGenesisConfig { + balances: BalancesConfig { + balances: endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect::>(), }, - "session": { - "keys": initial_authorities + session: SessionConfig { + keys: initial_authorities .iter() .map(|x| { ( @@ -202,13 +185,12 @@ fn rococo_testnet_genesis( ) }) .collect::>(), + ..Default::default() }, - "babe": { - "epochConfig": Some(BABE_GENESIS_EPOCH_CONFIG), - }, - "sudo": { "key": Some(root_key.clone()) }, - "configuration": { - "config": polkadot_runtime_parachains::configuration::HostConfiguration { + babe: BabeConfig { epoch_config: BABE_GENESIS_EPOCH_CONFIG, ..Default::default() }, + sudo: SudoConfig { key: Some(root_key.clone()) }, + configuration: ConfigurationConfig { + config: polkadot_runtime_parachains::configuration::HostConfiguration { scheduler_params: SchedulerParams { max_validators_per_core: Some(1), ..default_parachains_host_configuration().scheduler_params @@ -216,10 +198,14 @@ fn rococo_testnet_genesis( ..default_parachains_host_configuration() }, }, - "registrar": { - "nextFreeParaId": polkadot_primitives::LOWEST_PUBLIC_ID, - } - }) + registrar: RegistrarConfig { + next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID, + ..Default::default() + }, + ..Default::default() + }; + + serde_json::to_value(config).expect("Could not build genesis config.") } // staging_testnet @@ -441,51 +427,39 @@ fn rococo_staging_testnet_config_genesis() -> serde_json::Value { const ENDOWMENT: u128 = 1_000_000 * ROC; const STASH: u128 = 100 * ROC; - serde_json::json!({ - "balances": { - "balances": endowed_accounts + let config = RuntimeGenesisConfig { + balances: BalancesConfig { + balances: endowed_accounts .iter() .map(|k: &AccountId| (k.clone(), ENDOWMENT)) .chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH))) .collect::>(), }, - "session": { - "keys": initial_authorities + session: SessionConfig { + keys: initial_authorities .into_iter() - .map(|x| { - ( - x.0.clone(), - x.0, - rococo_session_keys( - x.2, - x.3, - x.4, - x.5, - x.6, - x.7, - ), - ) - }) + .map(|x| (x.0.clone(), x.0, rococo_session_keys(x.2, x.3, x.4, x.5, x.6, x.7))) .collect::>(), + ..Default::default() }, - "babe": { - "epochConfig": Some(BABE_GENESIS_EPOCH_CONFIG), - }, - "sudo": { "key": Some(endowed_accounts[0].clone()) }, - "configuration": { - "config": default_parachains_host_configuration(), - }, - "registrar": { - "nextFreeParaId": polkadot_primitives::LOWEST_PUBLIC_ID, + babe: BabeConfig { epoch_config: BABE_GENESIS_EPOCH_CONFIG, ..Default::default() }, + sudo: SudoConfig { key: Some(endowed_accounts[0].clone()) }, + configuration: ConfigurationConfig { config: default_parachains_host_configuration() }, + registrar: RegistrarConfig { + next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID, + ..Default::default() }, - }) + ..Default::default() + }; + + serde_json::to_value(config).expect("Could not build genesis config.") } //development fn rococo_development_config_genesis() -> serde_json::Value { rococo_testnet_genesis( Vec::from([get_authority_keys_from_seed("Alice")]), - get_account_id_from_seed::("Alice"), + Sr25519Keyring::Alice.to_account_id(), None, ) } @@ -494,7 +468,7 @@ fn rococo_development_config_genesis() -> serde_json::Value { fn rococo_local_testnet_genesis() -> serde_json::Value { rococo_testnet_genesis( Vec::from([get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob")]), - get_account_id_from_seed::("Alice"), + Sr25519Keyring::Alice.to_account_id(), None, ) } @@ -509,33 +483,17 @@ fn versi_local_testnet_genesis() -> serde_json::Value { get_authority_keys_from_seed("Charlie"), get_authority_keys_from_seed("Dave"), ]), - get_account_id_from_seed::("Alice"), - None, - ) -} - -/// Wococo is a temporary testnet that uses almost the same runtime as rococo. -//wococo_local_testnet -fn wococo_local_testnet_genesis() -> serde_json::Value { - rococo_testnet_genesis( - Vec::from([ - get_authority_keys_from_seed("Alice"), - get_authority_keys_from_seed("Bob"), - get_authority_keys_from_seed("Charlie"), - get_authority_keys_from_seed("Dave"), - ]), - get_account_id_from_seed::("Alice"), + Sr25519Keyring::Alice.to_account_id(), None, ) } /// Provides the JSON representation of predefined genesis config for given `id`. -pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option> { +pub fn get_preset(id: &PresetId) -> Option> { let patch = match id.try_into() { - Ok("local_testnet") => rococo_local_testnet_genesis(), - Ok("development") => rococo_development_config_genesis(), + Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) => rococo_local_testnet_genesis(), + Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => rococo_development_config_genesis(), Ok("staging_testnet") => rococo_staging_testnet_config_genesis(), - Ok("wococo_local_testnet") => wococo_local_testnet_genesis(), Ok("versi_local_testnet") => versi_local_testnet_genesis(), _ => return None, }; @@ -545,3 +503,13 @@ pub fn get_preset(id: &sp_genesis_builder::PresetId) -> Option Vec { + vec![ + PresetId::from(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET), + PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET), + PresetId::from("staging_testnet"), + PresetId::from("versi_local_testnet"), + ] +} diff --git a/polkadot/runtime/rococo/src/impls.rs b/polkadot/runtime/rococo/src/impls.rs index a4440a1c6e0b..f01440ea02bc 100644 --- a/polkadot/runtime/rococo/src/impls.rs +++ b/polkadot/runtime/rococo/src/impls.rs @@ -90,7 +90,7 @@ where fn on_reap_identity(who: &AccountId, fields: u32, subs: u32) -> DispatchResult { use crate::{ impls::IdentityMigratorCalls::PokeDeposit, - weights::runtime_common_identity_migrator::WeightInfo as MigratorWeights, + weights::polkadot_runtime_common_identity_migrator::WeightInfo as MigratorWeights, }; let total_to_send = Self::calculate_remote_deposit(fields, subs); diff --git a/polkadot/runtime/rococo/src/lib.rs b/polkadot/runtime/rococo/src/lib.rs index 5adffbd7422f..e94b6666ed07 100644 --- a/polkadot/runtime/rococo/src/lib.rs +++ b/polkadot/runtime/rococo/src/lib.rs @@ -33,14 +33,19 @@ use frame_support::{ dynamic_params::{dynamic_pallet_params, dynamic_params}, traits::FromContains, }; +use pallet_balances::WeightInfo; use pallet_nis::WithMaximumOf; use polkadot_primitives::{ - slashing, AccountId, AccountIndex, ApprovalVotingParams, Balance, BlockNumber, CandidateEvent, - CandidateHash, CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, - GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, Moment, - NodeFeatures, Nonce, OccupiedCoreAssumption, PersistedValidationData, ScrapedOnChainVotes, - SessionInfo, Signature, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, - PARACHAIN_KEY_TYPE_ID, + slashing, + vstaging::{ + CandidateEvent, CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CoreState, + ScrapedOnChainVotes, + }, + AccountId, AccountIndex, ApprovalVotingParams, Balance, BlockNumber, CandidateHash, CoreIndex, + DisputeState, ExecutorParams, GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, + InboundHrmpMessage, Moment, NodeFeatures, Nonce, OccupiedCoreAssumption, + PersistedValidationData, SessionInfo, Signature, ValidationCode, ValidationCodeHash, + ValidatorId, ValidatorIndex, PARACHAIN_KEY_TYPE_ID, }; use polkadot_runtime_common::{ assigned_slots, auctions, claims, crowdloan, identity_migrator, impl_runtime_weights, @@ -53,18 +58,16 @@ 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, - }, + runtime_api_impl::v11 as parachains_runtime_api_impl, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; @@ -99,9 +102,8 @@ use sp_core::{ConstU128, ConstU8, Get, OpaqueMetadata, H256}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{ - AccountIdConversion, BlakeTwo256, Block as BlockT, ConstU32, ConvertInto, - Extrinsic as ExtrinsicT, IdentityLookup, Keccak256, OpaqueKeys, SaturatedConversion, - Verify, + AccountIdConversion, BlakeTwo256, Block as BlockT, ConstU32, ConvertInto, IdentityLookup, + Keccak256, OpaqueKeys, SaturatedConversion, Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, Permill, RuntimeDebug, @@ -166,11 +168,11 @@ 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_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 26, - state_version: 1, + system_version: 1, }; /// The BABE epoch configuration at genesis. @@ -216,6 +218,7 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type MaxConsumers = frame_support::traits::ConstU32<16>; } @@ -398,6 +401,7 @@ impl pallet_balances::Config for Runtime { type RuntimeHoldReason = RuntimeHoldReason; type RuntimeFreezeReason = RuntimeFreezeReason; type MaxFreezes = ConstU32<1>; + type DoneSlashHandler = (); } parameter_types! { @@ -414,6 +418,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -602,18 +607,33 @@ impl pallet_grandpa::Config for Runtime { pallet_grandpa::EquivocationReportSystem; } -/// Submits a transaction with the node's public and signature type. Adheres to the signed extension -/// format of the chain. +impl frame_system::offchain::SigningTypes for Runtime { + type Public = ::Signer; + type Signature = Signature; +} + +impl frame_system::offchain::CreateTransactionBase for Runtime +where + RuntimeCall: From, +{ + type Extrinsic = UncheckedExtrinsic; + type RuntimeCall = RuntimeCall; +} + +/// Submits a transaction with the node's public and signature type. Adheres to the signed +/// extension format of the chain. impl frame_system::offchain::CreateSignedTransaction for Runtime where RuntimeCall: From, { - fn create_transaction>( + fn create_signed_transaction< + C: frame_system::offchain::AppCrypto, + >( call: RuntimeCall, public: ::Signer, account: AccountId, nonce: ::Nonce, - ) -> Option<(RuntimeCall, ::SignaturePayload)> { + ) -> Option { use sp_runtime::traits::StaticLookup; // take the biggest period possible. let period = @@ -625,7 +645,7 @@ where // so the actual block number is `n`. .saturating_sub(1); let tip = 0; - let extra: SignedExtra = ( + let tx_ext: TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -638,31 +658,39 @@ where frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), frame_metadata_hash_extension::CheckMetadataHash::new(true), - ); - - let raw_payload = SignedPayload::new(call, extra) + ) + .into(); + let raw_payload = SignedPayload::new(call, tx_ext) .map_err(|e| { log::warn!("Unable to create signed payload: {:?}", e); }) .ok()?; let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?; - let (call, extra, _) = raw_payload.deconstruct(); + let (call, tx_ext, _) = raw_payload.deconstruct(); let address = ::Lookup::unlookup(account); - Some((call, (address, signature, extra))) + let transaction = UncheckedExtrinsic::new_signed(call, address, signature, tx_ext); + Some(transaction) } } -impl frame_system::offchain::SigningTypes for Runtime { - type Public = ::Signer; - type Signature = Signature; +impl frame_system::offchain::CreateTransaction for Runtime +where + RuntimeCall: From, +{ + type Extension = TxExtension; + + fn create_transaction(call: RuntimeCall, tx_ext: Self::Extension) -> UncheckedExtrinsic { + UncheckedExtrinsic::new_transaction(call, tx_ext) + } } -impl frame_system::offchain::SendTransactionTypes for Runtime +impl frame_system::offchain::CreateInherent for Runtime where - RuntimeCall: From, + RuntimeCall: From, { - type Extrinsic = UncheckedExtrinsic; - type OverarchingCall = RuntimeCall; + fn create_inherent(call: RuntimeCall) -> UncheckedExtrinsic { + UncheckedExtrinsic::new_bare(call) + } } parameter_types! { @@ -674,7 +702,7 @@ impl claims::Config for Runtime { type VestingSchedule = Vesting; type Prefix = Prefix; type MoveClaimOrigin = EnsureRoot; - type WeightInfo = weights::runtime_common_claims::WeightInfo; + type WeightInfo = weights::polkadot_runtime_common_claims::WeightInfo; } parameter_types! { @@ -940,7 +968,7 @@ impl pallet_proxy::Config for Runtime { impl parachains_origin::Config for Runtime {} impl parachains_configuration::Config for Runtime { - type WeightInfo = weights::runtime_parachains_configuration::WeightInfo; + type WeightInfo = weights::polkadot_runtime_parachains_configuration::WeightInfo; } impl parachains_shared::Config for Runtime { @@ -963,7 +991,7 @@ impl parachains_inclusion::Config for Runtime { type DisputesHandler = ParasDisputes; type RewardValidators = RewardValidators; type MessageQueue = MessageQueue; - type WeightInfo = weights::runtime_parachains_inclusion::WeightInfo; + type WeightInfo = weights::polkadot_runtime_parachains_inclusion::WeightInfo; } parameter_types! { @@ -972,7 +1000,7 @@ parameter_types! { impl parachains_paras::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::runtime_parachains_paras::WeightInfo; + type WeightInfo = weights::polkadot_runtime_parachains_paras::WeightInfo; type UnsignedPriority = ParasUnsignedPriority; type QueueFootprinter = ParaInclusion; type NextSessionRotation = Babe; @@ -1046,11 +1074,11 @@ impl parachains_hrmp::Config for Runtime { HrmpChannelSizeAndCapacityWithSystemRatio, >; type VersionWrapper = crate::XcmPallet; - type WeightInfo = weights::runtime_parachains_hrmp::WeightInfo; + type WeightInfo = weights::polkadot_runtime_parachains_hrmp::WeightInfo; } impl parachains_paras_inherent::Config for Runtime { - type WeightInfo = weights::runtime_parachains_paras_inherent::WeightInfo; + type WeightInfo = weights::polkadot_runtime_parachains_paras_inherent::WeightInfo; } impl parachains_scheduler::Config for Runtime { @@ -1079,7 +1107,7 @@ impl coretime::Config for Runtime { type Currency = Balances; type BrokerId = BrokerId; type BrokerPotLocation = BrokerPot; - type WeightInfo = weights::runtime_parachains_coretime::WeightInfo; + type WeightInfo = weights::polkadot_runtime_parachains_coretime::WeightInfo; type SendXcm = crate::xcm_config::XcmRouter; type AssetTransactor = crate::xcm_config::LocalAssetTransactor; type AccountToLocation = xcm_builder::AliasesIntoAccountId32< @@ -1096,11 +1124,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::polkadot_runtime_parachains_on_demand::WeightInfo; type MaxHistoricalRevenue = MaxHistoricalRevenue; type PalletId = OnDemandPalletId; } @@ -1110,7 +1138,7 @@ impl parachains_assigner_coretime::Config for Runtime {} impl parachains_initializer::Config for Runtime { type Randomness = pallet_babe::RandomnessFromOneEpochAgo; type ForceOrigin = EnsureRoot; - type WeightInfo = weights::runtime_parachains_initializer::WeightInfo; + type WeightInfo = weights::polkadot_runtime_parachains_initializer::WeightInfo; type CoretimeOnNewSession = Coretime; } @@ -1118,7 +1146,7 @@ impl parachains_disputes::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RewardValidators = (); type SlashingHandler = parachains_slashing::SlashValidatorsForDisputes; - type WeightInfo = weights::runtime_parachains_disputes::WeightInfo; + type WeightInfo = weights::polkadot_runtime_parachains_disputes::WeightInfo; } impl parachains_slashing::Config for Runtime { @@ -1149,7 +1177,7 @@ impl paras_registrar::Config for Runtime { type OnSwap = (Crowdloan, Slots, SwapLeases); type ParaDeposit = ParaDeposit; type DataDepositPerByte = DataDepositPerByte; - type WeightInfo = weights::runtime_common_paras_registrar::WeightInfo; + type WeightInfo = weights::polkadot_runtime_common_paras_registrar::WeightInfo; } parameter_types! { @@ -1163,7 +1191,7 @@ impl slots::Config for Runtime { type LeasePeriod = LeasePeriod; type LeaseOffset = (); type ForceOrigin = EitherOf, LeaseAdmin>; - type WeightInfo = weights::runtime_common_slots::WeightInfo; + type WeightInfo = weights::polkadot_runtime_common_slots::WeightInfo; } parameter_types! { @@ -1184,7 +1212,7 @@ impl crowdloan::Config for Runtime { type Registrar = Registrar; type Auctioneer = Auctions; type MaxMemoLength = MaxMemoLength; - type WeightInfo = weights::runtime_common_crowdloan::WeightInfo; + type WeightInfo = weights::polkadot_runtime_common_crowdloan::WeightInfo; } parameter_types! { @@ -1203,14 +1231,14 @@ impl auctions::Config for Runtime { type SampleLength = SampleLength; type Randomness = pallet_babe::RandomnessFromOneEpochAgo; type InitiateOrigin = EitherOf, AuctionAdmin>; - type WeightInfo = weights::runtime_common_auctions::WeightInfo; + type WeightInfo = weights::polkadot_runtime_common_auctions::WeightInfo; } impl identity_migrator::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Reaper = EnsureSigned; type ReapIdentityHandler = ToParachainIdentityReaper; - type WeightInfo = weights::runtime_common_identity_migrator::WeightInfo; + type WeightInfo = weights::polkadot_runtime_common_identity_migrator::WeightInfo; } type NisCounterpartInstance = pallet_balances::Instance2; @@ -1232,6 +1260,7 @@ impl pallet_balances::Config for Runtime { type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxFreezes = ConstU32<1>; + type DoneSlashHandler = (); } parameter_types! { @@ -1307,9 +1336,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 +1350,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 +1364,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 {} @@ -1355,7 +1382,7 @@ impl assigned_slots::Config for Runtime { type PermanentSlotLeasePeriodLength = PermanentSlotLeasePeriodLength; type TemporarySlotLeasePeriodLength = TemporarySlotLeasePeriodLength; type MaxTemporarySlotPerLeasePeriod = MaxTemporarySlotPerLeasePeriod; - type WeightInfo = weights::runtime_common_assigned_slots::WeightInfo; + type WeightInfo = weights::polkadot_runtime_common_assigned_slots::WeightInfo; } impl validator_manager::Config for Runtime { @@ -1485,7 +1512,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. @@ -1535,8 +1562,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// `BlockId` type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The `SignedExtension` to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -1550,7 +1577,10 @@ pub type SignedExtra = ( /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; +/// Unchecked signature payload type as expected by this runtime. +pub type UncheckedSignaturePayload = + generic::UncheckedSignaturePayload; /// All migrations that will run on the next runtime upgrade. /// @@ -1582,6 +1612,13 @@ pub mod migrations { as Leaser>::lease_period_index(now)?; Some(index.saturating_add(lease.len() as u32).saturating_mul(LeasePeriod::get())) } + + fn get_all_parachains_with_leases() -> Vec { + slots::Leases::::iter() + .filter(|(_, lease)| !lease.is_empty()) + .map(|(para, _)| para) + .collect::>() + } } parameter_types! { @@ -1592,6 +1629,8 @@ pub mod migrations { pub const TechnicalMembershipPalletName: &'static str = "TechnicalMembership"; pub const TipsPalletName: &'static str = "Tips"; pub const PhragmenElectionPalletId: LockIdentifier = *b"phrelect"; + /// Weight for balance unreservations + pub BalanceUnreserveWeight: Weight = weights::pallet_balances_balances::WeightInfo::::force_unreserve(); } // Special Config for Gov V1 pallets, allowing us to run migrations for them without @@ -1632,47 +1671,48 @@ 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, + pallet_treasury::migration::cleanup_proposals::Migration, + + // 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, + parachains_shared::migration::MigrateToV1, + parachains_scheduler::migration::MigrateV2ToV3, + ); } /// Executive: handles dispatch to the various modules. @@ -1685,7 +1725,7 @@ pub type Executive = frame_executive::Executive< Migrations, >; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; parameter_types! { // The deposit configuration for the singed migration. Specially if you want to allow any signed account to do the migration (see `SignedFilter`, these deposits should be high) @@ -1738,6 +1778,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 +1787,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] @@ -1757,7 +1799,9 @@ mod benches { [pallet_scheduler, Scheduler] [pallet_sudo, Sudo] [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_timestamp, Timestamp] + [pallet_transaction_payment, TransactionPayment] [pallet_treasury, Treasury] [pallet_utility, Utility] [pallet_vesting, Vesting] @@ -2027,7 +2071,7 @@ sp_api::impl_runtime_apis! { parachains_runtime_api_impl::minimum_backing_votes::() } - fn para_backing_state(para_id: ParaId) -> Option { + fn para_backing_state(para_id: ParaId) -> Option { parachains_runtime_api_impl::backing_state::(para_id) } @@ -2048,15 +2092,15 @@ sp_api::impl_runtime_apis! { } fn claim_queue() -> BTreeMap> { - vstaging_parachains_runtime_api_impl::claim_queue::() + parachains_runtime_api_impl::claim_queue::() } fn candidates_pending_availability(para_id: ParaId) -> Vec> { - vstaging_parachains_runtime_api_impl::candidates_pending_availability::(para_id) + parachains_runtime_api_impl::candidates_pending_availability::(para_id) } } - #[api_version(4)] + #[api_version(5)] impl sp_consensus_beefy::BeefyApi for Runtime { fn beefy_genesis() -> Option { pallet_beefy::GenesisBlock::::get() @@ -2082,6 +2126,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 +2161,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)] @@ -2308,6 +2388,7 @@ sp_api::impl_runtime_apis! { use frame_support::traits::StorageInfoTrait; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use frame_benchmarking::baseline::Pallet as Baseline; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; @@ -2328,6 +2409,7 @@ sp_api::impl_runtime_apis! { use frame_support::traits::WhitelistedStorageKeys; use frame_benchmarking::{Benchmarking, BenchmarkBatch, BenchmarkError}; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use frame_benchmarking::baseline::Pallet as Baseline; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use sp_storage::TrackedStorageKey; @@ -2537,13 +2619,7 @@ sp_api::impl_runtime_apis! { } fn preset_names() -> Vec { - vec![ - PresetId::from("local_testnet"), - PresetId::from("development"), - PresetId::from("staging_testnet"), - PresetId::from("wococo_local_testnet"), - PresetId::from("versi_local_testnet"), - ] + genesis_config_presets::preset_names() } } } diff --git a/polkadot/runtime/rococo/src/tests.rs b/polkadot/runtime/rococo/src/tests.rs index 464a8c4f5454..01eaad87e342 100644 --- a/polkadot/runtime/rococo/src/tests.rs +++ b/polkadot/runtime/rococo/src/tests.rs @@ -19,8 +19,11 @@ use crate::*; use std::collections::HashSet; +use crate::xcm_config::LocationConverter; use frame_support::traits::WhitelistedStorageKeys; -use sp_core::hexdisplay::HexDisplay; +use sp_core::{crypto::Ss58Codec, hexdisplay::HexDisplay}; +use sp_keyring::AccountKeyring::Alice; +use xcm_runtime_apis::conversions::LocationToAccountHelper; #[test] fn check_whitelist() { @@ -61,3 +64,76 @@ mod encoding_tests { assert_eq!(RuntimeHoldReason::Nis(pallet_nis::HoldReason::NftReceipt).encode(), [38, 0]); } } + +#[test] +fn location_conversion_works() { + // the purpose of hardcoded values is to catch an unintended location conversion logic change. + struct TestCase { + description: &'static str, + location: Location, + expected_account_id_str: &'static str, + } + + let test_cases = vec![ + // DescribeTerminus + TestCase { + description: "DescribeTerminus Child", + location: Location::new(0, [Parachain(1111)]), + expected_account_id_str: "5Ec4AhP4h37t7TFsAZ4HhFq6k92usAAJDUC3ADSZ4H4Acru3", + }, + // DescribePalletTerminal + TestCase { + description: "DescribePalletTerminal Child", + location: Location::new(0, [Parachain(1111), PalletInstance(50)]), + expected_account_id_str: "5FjEBrKn3STAFsZpQF4jzwxUYHNGnNgzdZqSQfTzeJ82XKp6", + }, + // DescribeAccountId32Terminal + TestCase { + description: "DescribeAccountId32Terminal Child", + location: Location::new( + 0, + [Parachain(1111), AccountId32 { network: None, id: AccountId::from(Alice).into() }], + ), + expected_account_id_str: "5EEMro9RRDpne4jn9TuD7cTB6Amv1raVZ3xspSkqb2BF3FJH", + }, + // DescribeAccountKey20Terminal + TestCase { + description: "DescribeAccountKey20Terminal Child", + location: Location::new( + 0, + [Parachain(1111), AccountKey20 { network: None, key: [0u8; 20] }], + ), + expected_account_id_str: "5HohjXdjs6afcYcgHHSstkrtGfxgfGKsnZ1jtewBpFiGu4DL", + }, + // DescribeTreasuryVoiceTerminal + TestCase { + description: "DescribeTreasuryVoiceTerminal Child", + location: Location::new( + 0, + [Parachain(1111), Plurality { id: BodyId::Treasury, part: BodyPart::Voice }], + ), + expected_account_id_str: "5GenE4vJgHvwYVcD6b4nBvH5HNY4pzpVHWoqwFpNMFT7a2oX", + }, + // DescribeBodyTerminal + TestCase { + description: "DescribeBodyTerminal Child", + location: Location::new( + 0, + [Parachain(1111), Plurality { id: BodyId::Unit, part: BodyPart::Voice }], + ), + expected_account_id_str: "5DPgGBFTTYm1dGbtB1VWHJ3T3ScvdrskGGx6vSJZNP1WNStV", + }, + ]; + + for tc in test_cases { + let expected = + AccountId::from_string(tc.expected_account_id_str).expect("Invalid AccountId string"); + + let got = LocationToAccountHelper::::convert_location( + tc.location.into(), + ) + .unwrap(); + + assert_eq!(got, expected, "{}", tc.description); + } +} diff --git a/polkadot/runtime/rococo/src/weights/frame_benchmarking_baseline.rs b/polkadot/runtime/rococo/src/weights/frame_benchmarking_baseline.rs index dfba0cfc4aa9..0f68a5c6fb37 100644 --- a/polkadot/runtime/rococo/src/weights/frame_benchmarking_baseline.rs +++ b/polkadot/runtime/rococo/src/weights/frame_benchmarking_baseline.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `frame_benchmarking::baseline` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-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-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=frame_benchmarking::baseline // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/frame_benchmarking_baseline.rs +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/frame_benchmarking_baseline.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -52,8 +55,8 @@ impl frame_benchmarking::baseline::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 157_000 picoseconds. - Weight::from_parts(175_233, 0) + // Minimum execution time: 172_000 picoseconds. + Weight::from_parts(199_481, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `i` is `[0, 1000000]`. @@ -61,8 +64,8 @@ impl frame_benchmarking::baseline::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 149_000 picoseconds. - Weight::from_parts(183_285, 0) + // Minimum execution time: 171_000 picoseconds. + Weight::from_parts(197_821, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `i` is `[0, 1000000]`. @@ -70,8 +73,8 @@ impl frame_benchmarking::baseline::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 158_000 picoseconds. - Weight::from_parts(184_720, 0) + // Minimum execution time: 172_000 picoseconds. + Weight::from_parts(200_942, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `i` is `[0, 1000000]`. @@ -79,16 +82,16 @@ impl frame_benchmarking::baseline::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 152_000 picoseconds. - Weight::from_parts(177_496, 0) + // Minimum execution time: 170_000 picoseconds. + Weight::from_parts(196_906, 0) .saturating_add(Weight::from_parts(0, 0)) } fn hashing() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 19_907_376_000 picoseconds. - Weight::from_parts(19_988_727_000, 0) + // Minimum execution time: 23_346_876_000 picoseconds. + Weight::from_parts(23_363_744_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `i` is `[0, 100]`. @@ -96,10 +99,10 @@ impl frame_benchmarking::baseline::WeightInfo for Weigh // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 198_000 picoseconds. - Weight::from_parts(228_000, 0) + // Minimum execution time: 201_000 picoseconds. + Weight::from_parts(219_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 20_467 - .saturating_add(Weight::from_parts(47_443_635, 0).saturating_mul(i.into())) + // Standard Error: 14_372 + .saturating_add(Weight::from_parts(45_375_800, 0).saturating_mul(i.into())) } } diff --git a/polkadot/runtime/rococo/src/weights/frame_system.rs b/polkadot/runtime/rococo/src/weights/frame_system.rs index 2e49483dcc62..1742a761ca77 100644 --- a/polkadot/runtime/rococo/src/weights/frame_system.rs +++ b/polkadot/runtime/rococo/src/weights/frame_system.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `frame_system` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-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-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=frame_system // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -52,91 +55,91 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_283_000 picoseconds. - Weight::from_parts(2_305_000, 0) + // Minimum execution time: 1_541_000 picoseconds. + Weight::from_parts(2_581_470, 0) .saturating_add(Weight::from_parts(0, 0)) // Standard Error: 0 - .saturating_add(Weight::from_parts(366, 0).saturating_mul(b.into())) + .saturating_add(Weight::from_parts(387, 0).saturating_mul(b.into())) } /// The range of component `b` is `[0, 3932160]`. fn remark_with_event(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_435_000 picoseconds. - Weight::from_parts(7_581_000, 0) + // Minimum execution time: 5_060_000 picoseconds. + Weight::from_parts(5_167_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 0 - .saturating_add(Weight::from_parts(1_408, 0).saturating_mul(b.into())) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_696, 0).saturating_mul(b.into())) } - /// Storage: System Digest (r:1 w:1) - /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a686561707061676573` (r:0 w:1) - /// Proof Skipped: unknown `0x3a686561707061676573` (r:0 w:1) + /// Storage: `System::Digest` (r:1 w:1) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: UNKNOWN KEY `0x3a686561707061676573` (r:0 w:1) + /// Proof: UNKNOWN KEY `0x3a686561707061676573` (r:0 w:1) fn set_heap_pages() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1485` - // Minimum execution time: 4_010_000 picoseconds. - Weight::from_parts(4_112_000, 0) + // Minimum execution time: 2_649_000 picoseconds. + Weight::from_parts(2_909_000, 0) .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: System Digest (r:1 w:1) - /// Proof Skipped: System Digest (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a636f6465` (r:0 w:1) - /// Proof Skipped: unknown `0x3a636f6465` (r:0 w:1) + /// Storage: `System::Digest` (r:1 w:1) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) + /// Proof: UNKNOWN KEY `0x3a636f6465` (r:0 w:1) fn set_code() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1485` - // Minimum execution time: 80_405_511_000 picoseconds. - Weight::from_parts(83_066_478_000, 0) + // Minimum execution time: 88_417_540_000 picoseconds. + Weight::from_parts(91_809_291_000, 0) .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) + /// Storage: `Skipped::Metadata` (r:0 w:0) + /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `i` is `[0, 1000]`. fn set_storage(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_210_000 picoseconds. - Weight::from_parts(2_247_000, 0) + // Minimum execution time: 1_538_000 picoseconds. + Weight::from_parts(1_589_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_058 - .saturating_add(Weight::from_parts(673_943, 0).saturating_mul(i.into())) + // Standard Error: 1_740 + .saturating_add(Weight::from_parts(730_941, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) + /// Storage: `Skipped::Metadata` (r:0 w:0) + /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `i` is `[0, 1000]`. fn kill_storage(i: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_125_000 picoseconds. - Weight::from_parts(2_154_000, 0) + // Minimum execution time: 1_567_000 picoseconds. + Weight::from_parts(1_750_000, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 816 - .saturating_add(Weight::from_parts(491_194, 0).saturating_mul(i.into())) + // Standard Error: 835 + .saturating_add(Weight::from_parts(543_218, 0).saturating_mul(i.into())) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) } - /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) + /// Storage: `Skipped::Metadata` (r:0 w:0) + /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) /// The range of component `p` is `[0, 1000]`. fn kill_prefix(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `129 + p * (69 ±0)` - // Estimated: `125 + p * (70 ±0)` - // Minimum execution time: 4_002_000 picoseconds. - Weight::from_parts(4_145_000, 0) - .saturating_add(Weight::from_parts(0, 125)) - // Standard Error: 1_108 - .saturating_add(Weight::from_parts(1_014_971, 0).saturating_mul(p.into())) + // Measured: `80 + p * (69 ±0)` + // Estimated: `83 + p * (70 ±0)` + // Minimum execution time: 3_412_000 picoseconds. + Weight::from_parts(3_448_000, 0) + .saturating_add(Weight::from_parts(0, 83)) + // Standard Error: 1_395 + .saturating_add(Weight::from_parts(1_142_347, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(p.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) .saturating_add(Weight::from_parts(0, 70).saturating_mul(p.into())) @@ -147,8 +150,8 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 33_027_000 picoseconds. - Weight::from_parts(33_027_000, 0) + // Minimum execution time: 9_178_000 picoseconds. + Weight::from_parts(9_780_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -162,8 +165,8 @@ impl frame_system::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `22` // Estimated: `1518` - // Minimum execution time: 118_101_992_000 picoseconds. - Weight::from_parts(118_101_992_000, 0) + // Minimum execution time: 94_523_563_000 picoseconds. + Weight::from_parts(96_983_131_000, 0) .saturating_add(Weight::from_parts(0, 1518)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(3)) diff --git a/polkadot/runtime/rococo/src/weights/frame_system_extensions.rs b/polkadot/runtime/rococo/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..99dac1ba75f0 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/frame_system_extensions.rs @@ -0,0 +1,134 @@ +// 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 `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot +// benchmark +// pallet +// --chain=rococo-dev +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=frame_system_extensions +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --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 `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_genesis() -> Weight { + // Proof Size summary in bytes: + // Measured: `54` + // Estimated: `3509` + // Minimum execution time: 3_262_000 picoseconds. + Weight::from_parts(3_497_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_mortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_416_000 picoseconds. + Weight::from_parts(5_690_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_immortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 5_416_000 picoseconds. + Weight::from_parts(5_690_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 471_000 picoseconds. + Weight::from_parts(552_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `101` + // Estimated: `3593` + // Minimum execution time: 4_847_000 picoseconds. + Weight::from_parts(5_091_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 388_000 picoseconds. + Weight::from_parts(421_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 378_000 picoseconds. + Weight::from_parts(440_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1489` + // Minimum execution time: 3_402_000 picoseconds. + Weight::from_parts(3_627_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/mod.rs b/polkadot/runtime/rococo/src/weights/mod.rs index 3c6845dfb43e..99477baeb281 100644 --- a/polkadot/runtime/rococo/src/weights/mod.rs +++ b/polkadot/runtime/rococo/src/weights/mod.rs @@ -16,15 +16,18 @@ //! A list of the different weight modules for our runtime. pub mod frame_system; +pub mod frame_system_extensions; 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; @@ -37,25 +40,26 @@ pub mod pallet_scheduler; pub mod pallet_session; pub mod pallet_sudo; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_treasury; pub mod pallet_utility; pub mod pallet_vesting; pub mod pallet_whitelist; pub mod pallet_xcm; -pub mod runtime_common_assigned_slots; -pub mod runtime_common_auctions; -pub mod runtime_common_claims; -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_paras; -pub mod runtime_parachains_paras_inherent; +pub mod polkadot_runtime_common_assigned_slots; +pub mod polkadot_runtime_common_auctions; +pub mod polkadot_runtime_common_claims; +pub mod polkadot_runtime_common_crowdloan; +pub mod polkadot_runtime_common_identity_migrator; +pub mod polkadot_runtime_common_paras_registrar; +pub mod polkadot_runtime_common_slots; +pub mod polkadot_runtime_parachains_configuration; +pub mod polkadot_runtime_parachains_coretime; +pub mod polkadot_runtime_parachains_disputes; +pub mod polkadot_runtime_parachains_hrmp; +pub mod polkadot_runtime_parachains_inclusion; +pub mod polkadot_runtime_parachains_initializer; +pub mod polkadot_runtime_parachains_on_demand; +pub mod polkadot_runtime_parachains_paras; +pub mod polkadot_runtime_parachains_paras_inherent; pub mod xcm; diff --git a/polkadot/runtime/rococo/src/weights/pallet_asset_rate.rs b/polkadot/runtime/rococo/src/weights/pallet_asset_rate.rs index da2d1958cefc..56b1e2cbc571 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_asset_rate.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_asset_rate.rs @@ -16,25 +16,28 @@ //! Autogenerated weights for `pallet_asset_rate` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-03, STEPS: `50`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `cob`, CPU: `` -//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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/debug/polkadot +// ./target/production/polkadot // benchmark // pallet // --chain=rococo-dev // --steps=50 -// --repeat=2 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_asset_rate // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./runtime/rococo/src/weights/ -// --header=./file_header.txt +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,39 +50,39 @@ use core::marker::PhantomData; /// Weight functions for `pallet_asset_rate`. pub struct WeightInfo(PhantomData); impl pallet_asset_rate::WeightInfo for WeightInfo { - /// Storage: AssetRate ConversionRateToNative (r:1 w:1) - /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen) + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, mode: `MaxEncodedLen`) fn create() -> Weight { // Proof Size summary in bytes: - // Measured: `42` - // Estimated: `4702` - // Minimum execution time: 143_000_000 picoseconds. - Weight::from_parts(155_000_000, 0) - .saturating_add(Weight::from_parts(0, 4702)) + // Measured: `142` + // Estimated: `4703` + // Minimum execution time: 10_277_000 picoseconds. + Weight::from_parts(10_487_000, 0) + .saturating_add(Weight::from_parts(0, 4703)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: AssetRate ConversionRateToNative (r:1 w:1) - /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen) + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, mode: `MaxEncodedLen`) fn update() -> Weight { // Proof Size summary in bytes: - // Measured: `110` - // Estimated: `4702` - // Minimum execution time: 156_000_000 picoseconds. - Weight::from_parts(172_000_000, 0) - .saturating_add(Weight::from_parts(0, 4702)) + // Measured: `210` + // Estimated: `4703` + // Minimum execution time: 10_917_000 picoseconds. + Weight::from_parts(11_249_000, 0) + .saturating_add(Weight::from_parts(0, 4703)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: AssetRate ConversionRateToNative (r:1 w:1) - /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen) + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:1) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, mode: `MaxEncodedLen`) fn remove() -> Weight { // Proof Size summary in bytes: - // Measured: `110` - // Estimated: `4702` - // Minimum execution time: 150_000_000 picoseconds. - Weight::from_parts(160_000_000, 0) - .saturating_add(Weight::from_parts(0, 4702)) + // Measured: `210` + // Estimated: `4703` + // Minimum execution time: 11_332_000 picoseconds. + Weight::from_parts(11_866_000, 0) + .saturating_add(Weight::from_parts(0, 4703)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_balances_balances.rs b/polkadot/runtime/rococo/src/weights/pallet_balances_balances.rs index d37bb9369c68..c3c3315edff2 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_balances_balances.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_balances_balances.rs @@ -23,17 +23,19 @@ //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// target/production/polkadot +// ./target/production/polkadot // benchmark // pallet +// --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=pallet_balances // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_balances -// --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ diff --git a/polkadot/runtime/rococo/src/weights/pallet_balances_nis_counterpart_balances.rs b/polkadot/runtime/rococo/src/weights/pallet_balances_nis_counterpart_balances.rs index 706653aeb769..697e51faf537 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_balances_nis_counterpart_balances.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_balances_nis_counterpart_balances.rs @@ -23,17 +23,19 @@ //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// target/production/polkadot +// ./target/production/polkadot // benchmark // pallet +// --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=pallet_balances // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_balances -// --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ 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 000000000000..317c9149ec6c --- /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_bounties.rs b/polkadot/runtime/rococo/src/weights/pallet_bounties.rs index 38d3645316f2..8f8be5f2386f 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_bounties.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_bounties.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_bounties` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-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-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_bounties // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,118 +50,181 @@ use core::marker::PhantomData; /// Weight functions for `pallet_bounties`. pub struct WeightInfo(PhantomData); impl pallet_bounties::WeightInfo for WeightInfo { - /// Storage: Bounties BountyCount (r:1 w:1) - /// Proof: Bounties BountyCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Bounties BountyDescriptions (r:0 w:1) - /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) - /// Storage: Bounties Bounties (r:0 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) + /// Storage: `Bounties::BountyCount` (r:1 w:1) + /// Proof: `Bounties::BountyCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) + /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(16400), added: 18875, mode: `MaxEncodedLen`) + /// Storage: `Bounties::Bounties` (r:0 w:1) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) /// The range of component `d` is `[0, 16384]`. fn propose_bounty(d: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `210` // Estimated: `3593` - // Minimum execution time: 28_907_000 picoseconds. - Weight::from_parts(31_356_074, 0) + // Minimum execution time: 21_772_000 picoseconds. + Weight::from_parts(22_861_341, 0) .saturating_add(Weight::from_parts(0, 3593)) - // Standard Error: 18 - .saturating_add(Weight::from_parts(606, 0).saturating_mul(d.into())) + // Standard Error: 3 + .saturating_add(Weight::from_parts(721, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } + /// Storage: `Bounties::Bounties` (r:1 w:1) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `Bounties::BountyApprovals` (r:1 w:1) + /// Proof: `Bounties::BountyApprovals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) fn approve_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `302` + // Estimated: `3642` + // Minimum execution time: 11_218_000 picoseconds. + Weight::from_parts(11_796_000, 0) + .saturating_add(Weight::from_parts(0, 3642)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } + /// Storage: `Bounties::Bounties` (r:1 w:1) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) fn propose_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `322` + // Estimated: `3642` + // Minimum execution time: 10_959_000 picoseconds. + Weight::from_parts(11_658_000, 0) + .saturating_add(Weight::from_parts(0, 3642)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `Bounties::Bounties` (r:1 w:1) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn unassign_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `498` + // Estimated: `3642` + // Minimum execution time: 37_419_000 picoseconds. + Weight::from_parts(38_362_000, 0) + .saturating_add(Weight::from_parts(0, 3642)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } + /// Storage: `Bounties::Bounties` (r:1 w:1) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn accept_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `494` + // Estimated: `3642` + // Minimum execution time: 27_328_000 picoseconds. + Weight::from_parts(27_661_000, 0) + .saturating_add(Weight::from_parts(0, 3642)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) } + /// Storage: `Bounties::Bounties` (r:1 w:1) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:0) + /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) fn award_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `400` + // Estimated: `3642` + // Minimum execution time: 16_067_000 picoseconds. + Weight::from_parts(16_865_000, 0) + .saturating_add(Weight::from_parts(0, 3642)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `Bounties::Bounties` (r:1 w:1) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:3 w:3) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) + /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) + /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(16400), added: 18875, mode: `MaxEncodedLen`) fn claim_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `764` + // Estimated: `8799` + // Minimum execution time: 101_153_000 picoseconds. + Weight::from_parts(102_480_000, 0) + .saturating_add(Weight::from_parts(0, 8799)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(6)) } - /// Storage: Bounties Bounties (r:1 w:1) - /// Proof: Bounties Bounties (max_values: None, max_size: Some(177), added: 2652, mode: MaxEncodedLen) - /// Storage: ChildBounties ParentChildBounties (r:1 w:0) - /// Proof: ChildBounties ParentChildBounties (max_values: None, max_size: Some(16), added: 2491, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Bounties BountyDescriptions (r:0 w:1) - /// Proof: Bounties BountyDescriptions (max_values: None, max_size: Some(16400), added: 18875, mode: MaxEncodedLen) + /// Storage: `Bounties::Bounties` (r:1 w:1) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:0) + /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) + /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(16400), added: 18875, mode: `MaxEncodedLen`) fn close_bounty_proposed() -> Weight { // Proof Size summary in bytes: - // Measured: `482` + // Measured: `444` // Estimated: `3642` - // Minimum execution time: 46_020_000 picoseconds. - Weight::from_parts(46_711_000, 0) + // Minimum execution time: 38_838_000 picoseconds. + Weight::from_parts(39_549_000, 0) .saturating_add(Weight::from_parts(0, 3642)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } + /// Storage: `Bounties::Bounties` (r:1 w:1) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:0) + /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Bounties::BountyDescriptions` (r:0 w:1) + /// Proof: `Bounties::BountyDescriptions` (`max_values`: None, `max_size`: Some(16400), added: 18875, mode: `MaxEncodedLen`) fn close_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `680` + // Estimated: `6196` + // Minimum execution time: 68_592_000 picoseconds. + Weight::from_parts(70_727_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) } + /// Storage: `Bounties::Bounties` (r:1 w:1) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) fn extend_bounty_expiry() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `358` + // Estimated: `3642` + // Minimum execution time: 11_272_000 picoseconds. + Weight::from_parts(11_592_000, 0) + .saturating_add(Weight::from_parts(0, 3642)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Bounties BountyApprovals (r:1 w:1) - /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: `Bounties::BountyApprovals` (r:1 w:1) + /// Proof: `Bounties::BountyApprovals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: `Bounties::Bounties` (r:100 w:100) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:200 w:200) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `b` is `[0, 100]`. - fn spend_funds(_b: u32, ) -> Weight { + fn spend_funds(b: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `1887` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(2_405_233, 0) + // Measured: `0 + b * (297 ±0)` + // Estimated: `1887 + b * (5206 ±0)` + // Minimum execution time: 2_844_000 picoseconds. + Weight::from_parts(2_900_000, 0) .saturating_add(Weight::from_parts(0, 1887)) + // Standard Error: 9_467 + .saturating_add(Weight::from_parts(32_326_595, 0).saturating_mul(b.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(b.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(b.into()))) + .saturating_add(Weight::from_parts(0, 5206).saturating_mul(b.into())) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_child_bounties.rs b/polkadot/runtime/rococo/src/weights/pallet_child_bounties.rs index e8c798d45e72..47ae3a5c90d1 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_child_bounties.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_child_bounties.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_child_bounties` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-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-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_child_bounties // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,69 +50,153 @@ use core::marker::PhantomData; /// Weight functions for `pallet_child_bounties`. pub struct WeightInfo(PhantomData); impl pallet_child_bounties::WeightInfo for WeightInfo { + /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: `Bounties::Bounties` (r:1 w:0) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBountyCount` (r:1 w:1) + /// Proof: `ChildBounties::ChildBountyCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) + /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(16400), added: 18875, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBounties` (r:0 w:1) + /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) /// The range of component `d` is `[0, 16384]`. - fn add_child_bounty(_d: u32, ) -> Weight { + fn add_child_bounty(d: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `540` + // Estimated: `6196` + // Minimum execution time: 57_964_000 picoseconds. + Weight::from_parts(59_559_565, 0) + .saturating_add(Weight::from_parts(0, 6196)) + // Standard Error: 11 + .saturating_add(Weight::from_parts(697, 0).saturating_mul(d.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(6)) } + /// Storage: `Bounties::Bounties` (r:1 w:0) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) + /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) fn propose_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `594` + // Estimated: `3642` + // Minimum execution time: 17_527_000 picoseconds. + Weight::from_parts(18_257_000, 0) + .saturating_add(Weight::from_parts(0, 3642)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) } + /// Storage: `Bounties::Bounties` (r:1 w:0) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn accept_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `740` + // Estimated: `3642` + // Minimum execution time: 29_354_000 picoseconds. + Weight::from_parts(30_629_000, 0) + .saturating_add(Weight::from_parts(0, 3642)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) } + /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) + /// Storage: `Bounties::Bounties` (r:1 w:0) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn unassign_curator() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `740` + // Estimated: `3642` + // Minimum execution time: 40_643_000 picoseconds. + Weight::from_parts(42_072_000, 0) + .saturating_add(Weight::from_parts(0, 3642)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) } + /// Storage: `Bounties::Bounties` (r:1 w:0) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) fn award_child_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `637` + // Estimated: `3642` + // Minimum execution time: 18_616_000 picoseconds. + Weight::from_parts(19_316_000, 0) + .saturating_add(Weight::from_parts(0, 3642)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:3 w:3) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) + /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(16400), added: 18875, mode: `MaxEncodedLen`) fn claim_child_bounty() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `576` + // Estimated: `8799` + // Minimum execution time: 96_376_000 picoseconds. + Weight::from_parts(98_476_000, 0) + .saturating_add(Weight::from_parts(0, 8799)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(6)) } + /// Storage: `Bounties::Bounties` (r:1 w:0) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) + /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) + /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(16400), added: 18875, mode: `MaxEncodedLen`) fn close_child_bounty_added() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `840` + // Estimated: `6196` + // Minimum execution time: 64_640_000 picoseconds. + Weight::from_parts(66_174_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(6)) } + /// Storage: `Bounties::Bounties` (r:1 w:0) + /// Proof: `Bounties::Bounties` (`max_values`: None, `max_size`: Some(177), added: 2652, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ChildBounties` (`max_values`: None, `max_size`: Some(145), added: 2620, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:3 w:3) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildrenCuratorFees` (r:1 w:1) + /// Proof: `ChildBounties::ChildrenCuratorFees` (`max_values`: None, `max_size`: Some(28), added: 2503, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ParentChildBounties` (r:1 w:1) + /// Proof: `ChildBounties::ParentChildBounties` (`max_values`: None, `max_size`: Some(16), added: 2491, mode: `MaxEncodedLen`) + /// Storage: `ChildBounties::ChildBountyDescriptions` (r:0 w:1) + /// Proof: `ChildBounties::ChildBountyDescriptions` (`max_values`: None, `max_size`: Some(16400), added: 18875, mode: `MaxEncodedLen`) fn close_child_bounty_active() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 0_000 picoseconds. - Weight::from_parts(0, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `1027` + // Estimated: `8799` + // Minimum execution time: 78_159_000 picoseconds. + Weight::from_parts(79_820_000, 0) + .saturating_add(Weight::from_parts(0, 8799)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(7)) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_conviction_voting.rs b/polkadot/runtime/rococo/src/weights/pallet_conviction_voting.rs index ba505737f1b0..5d92c158df44 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_conviction_voting.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_conviction_voting.rs @@ -16,17 +16,17 @@ //! Autogenerated weights for `pallet_conviction_voting` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 -// --chain=kusama-dev +// --chain=rococo-dev // --steps=50 // --repeat=20 // --no-storage-info @@ -36,8 +36,8 @@ // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,144 +50,152 @@ use core::marker::PhantomData; /// Weight functions for `pallet_conviction_voting`. pub struct WeightInfo(PhantomData); impl pallet_conviction_voting::WeightInfo for WeightInfo { - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: ConvictionVoting VotingFor (r:1 w:1) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) - /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(311), added: 2786, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(311), added: 2786, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:1 w:1) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn vote_new() -> Weight { // Proof Size summary in bytes: - // Measured: `13445` + // Measured: `13407` // Estimated: `42428` - // Minimum execution time: 151_077_000 picoseconds. - Weight::from_parts(165_283_000, 0) + // Minimum execution time: 128_378_000 picoseconds. + Weight::from_parts(131_028_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: ConvictionVoting VotingFor (r:1 w:1) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) - /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(311), added: 2786, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(311), added: 2786, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn vote_existing() -> Weight { // Proof Size summary in bytes: - // Measured: `14166` + // Measured: `14128` // Estimated: `83866` - // Minimum execution time: 232_420_000 picoseconds. - Weight::from_parts(244_439_000, 0) + // Minimum execution time: 155_379_000 picoseconds. + Weight::from_parts(161_597_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().writes(7)) } - /// Storage: ConvictionVoting VotingFor (r:1 w:1) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: Referenda ReferendumInfoFor (r:1 w:1) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn remove_vote() -> Weight { // Proof Size summary in bytes: // Measured: `13918` // Estimated: `83866` - // Minimum execution time: 205_017_000 picoseconds. - Weight::from_parts(216_594_000, 0) + // Minimum execution time: 130_885_000 picoseconds. + Weight::from_parts(138_080_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: ConvictionVoting VotingFor (r:1 w:1) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: Referenda ReferendumInfoFor (r:1 w:0) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) fn remove_other_vote() -> Weight { // Proof Size summary in bytes: - // Measured: `13004` + // Measured: `13005` // Estimated: `30706` - // Minimum execution time: 84_226_000 picoseconds. - Weight::from_parts(91_255_000, 0) + // Minimum execution time: 71_743_000 picoseconds. + Weight::from_parts(75_170_000, 0) .saturating_add(Weight::from_parts(0, 30706)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: ConvictionVoting VotingFor (r:2 w:2) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: Referenda ReferendumInfoFor (r:512 w:512) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) - /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(311), added: 2786, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: `ConvictionVoting::VotingFor` (r:2 w:2) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:512 w:512) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(311), added: 2786, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:50) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 512]`. fn delegate(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `29640 + r * (365 ±0)` + // Measured: `29602 + r * (365 ±0)` // Estimated: `83866 + r * (3411 ±0)` - // Minimum execution time: 78_708_000 picoseconds. - Weight::from_parts(2_053_488_615, 0) + // Minimum execution time: 58_504_000 picoseconds. + Weight::from_parts(814_301_018, 0) .saturating_add(Weight::from_parts(0, 83866)) - // Standard Error: 179_271 - .saturating_add(Weight::from_parts(47_806_482, 0).saturating_mul(r.into())) + // Standard Error: 59_961 + .saturating_add(Weight::from_parts(20_002_833, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(7)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().writes(45)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 3411).saturating_mul(r.into())) } - /// Storage: ConvictionVoting VotingFor (r:2 w:2) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: Referenda ReferendumInfoFor (r:512 w:512) - /// Proof: Referenda ReferendumInfoFor (max_values: None, max_size: Some(936), added: 3411, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) + /// Storage: `ConvictionVoting::VotingFor` (r:2 w:2) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `Referenda::ReferendumInfoFor` (r:512 w:512) + /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Agenda` (r:2 w:2) + /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:50) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// The range of component `r` is `[0, 512]`. fn undelegate(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `29555 + r * (365 ±0)` // Estimated: `83866 + r * (3411 ±0)` - // Minimum execution time: 45_232_000 picoseconds. - Weight::from_parts(2_045_021_014, 0) + // Minimum execution time: 34_970_000 picoseconds. + Weight::from_parts(771_155_804, 0) .saturating_add(Weight::from_parts(0, 83866)) - // Standard Error: 185_130 - .saturating_add(Weight::from_parts(47_896_011, 0).saturating_mul(r.into())) + // Standard Error: 57_795 + .saturating_add(Weight::from_parts(19_781_645, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(r.into()))) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(43)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(r.into()))) .saturating_add(Weight::from_parts(0, 3411).saturating_mul(r.into())) } - /// Storage: ConvictionVoting VotingFor (r:1 w:1) - /// Proof: ConvictionVoting VotingFor (max_values: None, max_size: Some(27241), added: 29716, mode: MaxEncodedLen) - /// Storage: ConvictionVoting ClassLocksFor (r:1 w:1) - /// Proof: ConvictionVoting ClassLocksFor (max_values: None, max_size: Some(311), added: 2786, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(49), added: 2524, mode: MaxEncodedLen) + /// Storage: `ConvictionVoting::VotingFor` (r:1 w:1) + /// Proof: `ConvictionVoting::VotingFor` (`max_values`: None, `max_size`: Some(27241), added: 29716, mode: `MaxEncodedLen`) + /// Storage: `ConvictionVoting::ClassLocksFor` (r:1 w:1) + /// Proof: `ConvictionVoting::ClassLocksFor` (`max_values`: None, `max_size`: Some(311), added: 2786, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) fn unlock() -> Weight { // Proof Size summary in bytes: - // Measured: `12218` + // Measured: `12180` // Estimated: `30706` - // Minimum execution time: 116_446_000 picoseconds. - Weight::from_parts(124_043_000, 0) + // Minimum execution time: 89_648_000 picoseconds. + Weight::from_parts(97_144_000, 0) .saturating_add(Weight::from_parts(0, 30706)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_identity.rs b/polkadot/runtime/rococo/src/weights/pallet_identity.rs index b334e21ea031..6df16351f2c2 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_identity.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_identity.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_identity` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-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-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_identity // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,290 +50,291 @@ use core::marker::PhantomData; /// Weight functions for `pallet_identity`. pub struct WeightInfo(PhantomData); impl pallet_identity::WeightInfo for WeightInfo { - /// Storage: Identity Registrars (r:1 w:1) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: `Identity::Registrars` (r:1 w:1) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 19]`. fn add_registrar(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `32 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 12_290_000 picoseconds. - Weight::from_parts(12_664_362, 0) + // Minimum execution time: 7_673_000 picoseconds. + Weight::from_parts(8_351_866, 0) .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 1_347 - .saturating_add(Weight::from_parts(88_179, 0).saturating_mul(r.into())) + // Standard Error: 1_302 + .saturating_add(Weight::from_parts(79_198, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 20]`. fn set_identity(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `442 + r * (5 ±0)` - // Estimated: `11003` - // Minimum execution time: 31_373_000 picoseconds. - Weight::from_parts(30_435_545, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 2_307 - .saturating_add(Weight::from_parts(92_753, 0).saturating_mul(r.into())) + // Measured: `6978 + r * (5 ±0)` + // Estimated: `11037` + // Minimum execution time: 111_646_000 picoseconds. + Weight::from_parts(113_254_991, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 6_611 + .saturating_add(Weight::from_parts(162_119, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Identity IdentityOf (r:1 w:0) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:100 w:100) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:100 w:100) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 100]`. fn set_subs_new(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `101` - // Estimated: `11003 + s * (2589 ±0)` - // Minimum execution time: 9_251_000 picoseconds. - Weight::from_parts(22_039_210, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 40_779 - .saturating_add(Weight::from_parts(2_898_525, 0).saturating_mul(s.into())) + // Estimated: `11037 + s * (2589 ±0)` + // Minimum execution time: 8_010_000 picoseconds. + Weight::from_parts(19_868_412, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 5_018 + .saturating_add(Weight::from_parts(3_115_007, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(s.into()))) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) .saturating_add(Weight::from_parts(0, 2589).saturating_mul(s.into())) } - /// Storage: Identity IdentityOf (r:1 w:0) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:0 w:100) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:0 w:100) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) /// The range of component `p` is `[0, 100]`. fn set_subs_old(p: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `194 + p * (32 ±0)` - // Estimated: `11003` - // Minimum execution time: 9_329_000 picoseconds. - Weight::from_parts(24_055_061, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 3_428 - .saturating_add(Weight::from_parts(1_130_604, 0).saturating_mul(p.into())) + // Estimated: `11037` + // Minimum execution time: 8_111_000 picoseconds. + Weight::from_parts(19_482_392, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 3_156 + .saturating_add(Weight::from_parts(1_305_890, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(p.into()))) } - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:0 w:100) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:0 w:100) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. - fn clear_identity(_r: u32, s: u32, ) -> Weight { + fn clear_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `469 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 53_365_000 picoseconds. - Weight::from_parts(35_391_422, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 1_353 - .saturating_add(Weight::from_parts(1_074_019, 0).saturating_mul(s.into())) + // Measured: `7070 + r * (5 ±0) + s * (32 ±0)` + // Estimated: `11037` + // Minimum execution time: 54_107_000 picoseconds. + Weight::from_parts(56_347_715, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 10_944 + .saturating_add(Weight::from_parts(191_321, 0).saturating_mul(r.into())) + // Standard Error: 2_135 + .saturating_add(Weight::from_parts(1_295_872, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) } - /// Storage: Identity Registrars (r:1 w:0) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: `Identity::Registrars` (r:1 w:0) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 20]`. fn request_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `367 + r * (57 ±0) + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 32_509_000 picoseconds. - Weight::from_parts(31_745_585, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 2_214 - .saturating_add(Weight::from_parts(83_822, 0).saturating_mul(r.into())) - + // Measured: `6968 + r * (57 ±0)` + // Estimated: `11037` + // Minimum execution time: 75_780_000 picoseconds. + Weight::from_parts(76_869_773, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 5_456 + .saturating_add(Weight::from_parts(135_316, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 20]`. fn cancel_request(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `398 + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 29_609_000 picoseconds. - Weight::from_parts(28_572_602, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 2_528 - .saturating_add(Weight::from_parts(85_593, 0).saturating_mul(r.into())) + // Measured: `6999` + // Estimated: `11037` + // Minimum execution time: 75_769_000 picoseconds. + Weight::from_parts(76_805_143, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 3_598 + .saturating_add(Weight::from_parts(84_593, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Identity Registrars (r:1 w:1) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: `Identity::Registrars` (r:1 w:1) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 19]`. fn set_fee(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 7_793_000 picoseconds. - Weight::from_parts(8_173_888, 0) + // Minimum execution time: 5_357_000 picoseconds. + Weight::from_parts(5_732_132, 0) .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 1_569 - .saturating_add(Weight::from_parts(72_367, 0).saturating_mul(r.into())) + // Standard Error: 927 + .saturating_add(Weight::from_parts(70_832, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Identity Registrars (r:1 w:1) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: `Identity::Registrars` (r:1 w:1) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 19]`. fn set_account_id(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 7_708_000 picoseconds. - Weight::from_parts(8_091_149, 0) + // Minimum execution time: 5_484_000 picoseconds. + Weight::from_parts(5_892_704, 0) .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 869 - .saturating_add(Weight::from_parts(87_993, 0).saturating_mul(r.into())) + // Standard Error: 947 + .saturating_add(Weight::from_parts(71_231, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Identity Registrars (r:1 w:1) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) + /// Storage: `Identity::Registrars` (r:1 w:1) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 19]`. fn set_fields(r: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `89 + r * (57 ±0)` // Estimated: `2626` - // Minimum execution time: 7_601_000 picoseconds. - Weight::from_parts(8_038_414, 0) + // Minimum execution time: 5_310_000 picoseconds. + Weight::from_parts(5_766_651, 0) .saturating_add(Weight::from_parts(0, 2626)) - // Standard Error: 1_041 - .saturating_add(Weight::from_parts(82_588, 0).saturating_mul(r.into())) + // Standard Error: 916 + .saturating_add(Weight::from_parts(74_776, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Identity Registrars (r:1 w:0) - /// Proof: Identity Registrars (max_values: Some(1), max_size: Some(1141), added: 1636, mode: MaxEncodedLen) - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) + /// Storage: `Identity::Registrars` (r:1 w:0) + /// Proof: `Identity::Registrars` (`max_values`: Some(1), `max_size`: Some(1141), added: 1636, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 19]`. fn provide_judgement(r: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `445 + r * (57 ±0) + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 23_114_000 picoseconds. - Weight::from_parts(22_076_548, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 2_881 - .saturating_add(Weight::from_parts(109_812, 0).saturating_mul(r.into())) + // Measured: `7046 + r * (57 ±0)` + // Estimated: `11037` + // Minimum execution time: 98_200_000 picoseconds. + Weight::from_parts(100_105_482, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 6_152 + .saturating_add(Weight::from_parts(58_906, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// Storage: Identity IdentityOf (r:1 w:1) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:0 w:100) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) + /// Storage: `Identity::IdentityOf` (r:1 w:1) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:0 w:100) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) /// The range of component `r` is `[1, 20]`. /// The range of component `s` is `[0, 100]`. fn kill_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `676 + r * (5 ±0) + s * (32 ±0) + x * (66 ±0)` - // Estimated: `11003` - // Minimum execution time: 70_007_000 picoseconds. - Weight::from_parts(50_186_495, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 6_533 - .saturating_add(Weight::from_parts(15_486, 0).saturating_mul(r.into())) - // Standard Error: 1_275 - .saturating_add(Weight::from_parts(1_085_117, 0).saturating_mul(s.into())) + // Measured: `7277 + r * (5 ±0) + s * (32 ±0)` + // Estimated: `11037` + // Minimum execution time: 64_647_000 picoseconds. + Weight::from_parts(68_877_027, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 9_965 + .saturating_add(Weight::from_parts(135_044, 0).saturating_mul(r.into())) + // Standard Error: 1_944 + .saturating_add(Weight::from_parts(1_388_151, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) } - /// Storage: Identity IdentityOf (r:1 w:0) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:1 w:1) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:1 w:1) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 99]`. fn add_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `475 + s * (36 ±0)` - // Estimated: `11003` - // Minimum execution time: 28_453_000 picoseconds. - Weight::from_parts(33_165_934, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 1_217 - .saturating_add(Weight::from_parts(65_401, 0).saturating_mul(s.into())) + // Estimated: `11037` + // Minimum execution time: 23_550_000 picoseconds. + Weight::from_parts(29_439_842, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 1_453 + .saturating_add(Weight::from_parts(96_324, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Identity IdentityOf (r:1 w:0) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:1 w:1) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:1 w:1) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 100]`. fn rename_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `591 + s * (3 ±0)` - // Estimated: `11003` - // Minimum execution time: 12_846_000 picoseconds. - Weight::from_parts(14_710_284, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 496 - .saturating_add(Weight::from_parts(19_539, 0).saturating_mul(s.into())) + // Estimated: `11037` + // Minimum execution time: 13_704_000 picoseconds. + Weight::from_parts(15_241_441, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 498 + .saturating_add(Weight::from_parts(40_973, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Identity IdentityOf (r:1 w:0) - /// Proof: Identity IdentityOf (max_values: None, max_size: Some(7538), added: 10013, mode: MaxEncodedLen) - /// Storage: Identity SuperOf (r:1 w:1) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) + /// Storage: `Identity::IdentityOf` (r:1 w:0) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) + /// Storage: `Identity::SuperOf` (r:1 w:1) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 100]`. fn remove_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `638 + s * (35 ±0)` - // Estimated: `11003` - // Minimum execution time: 32_183_000 picoseconds. - Weight::from_parts(35_296_731, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 854 - .saturating_add(Weight::from_parts(52_028, 0).saturating_mul(s.into())) + // Estimated: `11037` + // Minimum execution time: 29_310_000 picoseconds. + Weight::from_parts(31_712_666, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 967 + .saturating_add(Weight::from_parts(81_250, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Identity SuperOf (r:1 w:1) - /// Proof: Identity SuperOf (max_values: None, max_size: Some(114), added: 2589, mode: MaxEncodedLen) - /// Storage: Identity SubsOf (r:1 w:1) - /// Proof: Identity SubsOf (max_values: None, max_size: Some(3258), added: 5733, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Identity::SuperOf` (r:1 w:1) + /// Proof: `Identity::SuperOf` (`max_values`: None, `max_size`: Some(114), added: 2589, mode: `MaxEncodedLen`) + /// Storage: `Identity::SubsOf` (r:1 w:1) + /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 99]`. fn quit_sub(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `704 + s * (37 ±0)` // Estimated: `6723` - // Minimum execution time: 24_941_000 picoseconds. - Weight::from_parts(27_433_059, 0) + // Minimum execution time: 22_906_000 picoseconds. + Weight::from_parts(24_638_729, 0) .saturating_add(Weight::from_parts(0, 6723)) - // Standard Error: 856 - .saturating_add(Weight::from_parts(57_463, 0).saturating_mul(s.into())) + // Standard Error: 645 + .saturating_add(Weight::from_parts(75_121, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -340,90 +344,93 @@ impl pallet_identity::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 13_873_000 picoseconds. - Weight::from_parts(13_873_000, 0) + // Minimum execution time: 6_056_000 picoseconds. + Weight::from_parts(6_349_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: `Identity::UsernameAuthorities` (r:0 w:1) + /// Storage: `Identity::UsernameAuthorities` (r:1 w:1) /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn remove_username_authority() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 10_653_000 picoseconds. - Weight::from_parts(10_653_000, 0) - .saturating_add(Weight::from_parts(0, 0)) + // Measured: `80` + // Estimated: `3517` + // Minimum execution time: 9_003_000 picoseconds. + Weight::from_parts(9_276_000, 0) + .saturating_add(Weight::from_parts(0, 3517)) + .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Identity::UsernameAuthorities` (r:1 w:1) /// Proof: `Identity::UsernameAuthorities` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Storage: `Identity::PendingUsernames` (r:1 w:0) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) fn set_username_for() -> Weight { // Proof Size summary in bytes: // Measured: `80` // Estimated: `11037` - // Minimum execution time: 75_928_000 picoseconds. - Weight::from_parts(75_928_000, 0) + // Minimum execution time: 64_724_000 picoseconds. + Weight::from_parts(66_597_000, 0) .saturating_add(Weight::from_parts(0, 11037)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Identity::PendingUsernames` (r:1 w:1) - /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) /// Storage: `Identity::AccountOfUsername` (r:0 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) fn accept_username() -> Weight { // Proof Size summary in bytes: - // Measured: `106` + // Measured: `115` // Estimated: `11037` - // Minimum execution time: 38_157_000 picoseconds. - Weight::from_parts(38_157_000, 0) + // Minimum execution time: 19_538_000 picoseconds. + Weight::from_parts(20_204_000, 0) .saturating_add(Weight::from_parts(0, 11037)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Identity::PendingUsernames` (r:1 w:1) - /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(77), added: 2552, mode: `MaxEncodedLen`) + /// Proof: `Identity::PendingUsernames` (`max_values`: None, `max_size`: Some(85), added: 2560, mode: `MaxEncodedLen`) fn remove_expired_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `106` - // Estimated: `3542` - // Minimum execution time: 46_821_000 picoseconds. - Weight::from_parts(46_821_000, 0) - .saturating_add(Weight::from_parts(0, 3542)) + // Measured: `115` + // Estimated: `3550` + // Minimum execution time: 16_000_000 picoseconds. + Weight::from_parts(19_354_000, 0) + .saturating_add(Weight::from_parts(0, 3550)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Identity::AccountOfUsername` (r:1 w:0) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:1) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) fn set_primary_username() -> Weight { // Proof Size summary in bytes: - // Measured: `247` + // Measured: `257` // Estimated: `11037` - // Minimum execution time: 22_515_000 picoseconds. - Weight::from_parts(22_515_000, 0) + // Minimum execution time: 15_298_000 picoseconds. + Weight::from_parts(15_760_000, 0) .saturating_add(Weight::from_parts(0, 11037)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Identity::AccountOfUsername` (r:1 w:1) - /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(73), added: 2548, mode: `MaxEncodedLen`) + /// Proof: `Identity::AccountOfUsername` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) /// Storage: `Identity::IdentityOf` (r:1 w:0) /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) fn remove_dangling_username() -> Weight { // Proof Size summary in bytes: - // Measured: `126` + // Measured: `98` // Estimated: `11037` - // Minimum execution time: 15_997_000 picoseconds. - Weight::from_parts(15_997_000, 0) + // Minimum execution time: 10_829_000 picoseconds. + Weight::from_parts(11_113_000, 0) .saturating_add(Weight::from_parts(0, 11037)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_indices.rs b/polkadot/runtime/rococo/src/weights/pallet_indices.rs index 99ffd3210ed2..434db97d4a79 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_indices.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_indices.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_indices` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-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-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_indices // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,66 +50,66 @@ use core::marker::PhantomData; /// Weight functions for `pallet_indices`. pub struct WeightInfo(PhantomData); impl pallet_indices::WeightInfo for WeightInfo { - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: `Indices::Accounts` (r:1 w:1) + /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) fn claim() -> Weight { // Proof Size summary in bytes: - // Measured: `142` + // Measured: `4` // Estimated: `3534` - // Minimum execution time: 25_107_000 picoseconds. - Weight::from_parts(25_655_000, 0) + // Minimum execution time: 18_092_000 picoseconds. + Weight::from_parts(18_533_000, 0) .saturating_add(Weight::from_parts(0, 3534)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Indices::Accounts` (r:1 w:1) + /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `341` + // Measured: `203` // Estimated: `3593` - // Minimum execution time: 36_208_000 picoseconds. - Weight::from_parts(36_521_000, 0) + // Minimum execution time: 31_616_000 picoseconds. + Weight::from_parts(32_556_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: `Indices::Accounts` (r:1 w:1) + /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) fn free() -> Weight { // Proof Size summary in bytes: - // Measured: `238` + // Measured: `100` // Estimated: `3534` - // Minimum execution time: 25_915_000 picoseconds. - Weight::from_parts(26_220_000, 0) + // Minimum execution time: 19_593_000 picoseconds. + Weight::from_parts(20_100_000, 0) .saturating_add(Weight::from_parts(0, 3534)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Indices::Accounts` (r:1 w:1) + /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn force_transfer() -> Weight { // Proof Size summary in bytes: - // Measured: `341` + // Measured: `203` // Estimated: `3593` - // Minimum execution time: 28_232_000 picoseconds. - Weight::from_parts(28_845_000, 0) + // Minimum execution time: 21_429_000 picoseconds. + Weight::from_parts(22_146_000, 0) .saturating_add(Weight::from_parts(0, 3593)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Indices Accounts (r:1 w:1) - /// Proof: Indices Accounts (max_values: None, max_size: Some(69), added: 2544, mode: MaxEncodedLen) + /// Storage: `Indices::Accounts` (r:1 w:1) + /// Proof: `Indices::Accounts` (`max_values`: None, `max_size`: Some(69), added: 2544, mode: `MaxEncodedLen`) fn freeze() -> Weight { // Proof Size summary in bytes: - // Measured: `238` + // Measured: `100` // Estimated: `3534` - // Minimum execution time: 27_282_000 picoseconds. - Weight::from_parts(27_754_000, 0) + // Minimum execution time: 20_425_000 picoseconds. + Weight::from_parts(21_023_000, 0) .saturating_add(Weight::from_parts(0, 3534)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_message_queue.rs b/polkadot/runtime/rococo/src/weights/pallet_message_queue.rs index e1e360d374a0..6ebfcd060b64 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_message_queue.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_message_queue.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_message_queue` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-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-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_message_queue // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,150 +50,149 @@ use core::marker::PhantomData; /// Weight functions for `pallet_message_queue`. pub struct WeightInfo(PhantomData); impl pallet_message_queue::WeightInfo for WeightInfo { - /// Storage: MessageQueue ServiceHead (r:1 w:0) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(6), added: 501, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:0) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(6), added: 501, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) fn ready_ring_knit() -> Weight { // Proof Size summary in bytes: - // Measured: `248` + // Measured: `281` // Estimated: `6050` - // Minimum execution time: 12_106_000 picoseconds. - Weight::from_parts(12_387_000, 0) + // Minimum execution time: 12_830_000 picoseconds. + Weight::from_parts(13_476_000, 0) .saturating_add(Weight::from_parts(0, 6050)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: MessageQueue BookStateFor (r:2 w:2) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(6), added: 501, mode: MaxEncodedLen) + /// Storage: `MessageQueue::BookStateFor` (r:2 w:2) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(6), added: 501, mode: `MaxEncodedLen`) fn ready_ring_unknit() -> Weight { // Proof Size summary in bytes: - // Measured: `248` + // Measured: `281` // Estimated: `6050` - // Minimum execution time: 11_227_000 picoseconds. - Weight::from_parts(11_616_000, 0) + // Minimum execution time: 11_583_000 picoseconds. + Weight::from_parts(11_902_000, 0) .saturating_add(Weight::from_parts(0, 6050)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) fn service_queue_base() -> Weight { // Proof Size summary in bytes: // Measured: `42` // Estimated: `3520` - // Minimum execution time: 5_052_000 picoseconds. - Weight::from_parts(5_216_000, 0) + // Minimum execution time: 3_801_000 picoseconds. + Weight::from_parts(3_943_000, 0) .saturating_add(Weight::from_parts(0, 3520)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(32818), added: 35293, mode: MaxEncodedLen) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) fn service_page_base_completion() -> Weight { // Proof Size summary in bytes: // Measured: `115` // Estimated: `36283` - // Minimum execution time: 6_522_000 picoseconds. - Weight::from_parts(6_794_000, 0) + // Minimum execution time: 5_517_000 picoseconds. + Weight::from_parts(5_861_000, 0) .saturating_add(Weight::from_parts(0, 36283)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(32818), added: 35293, mode: MaxEncodedLen) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) fn service_page_base_no_completion() -> Weight { // Proof Size summary in bytes: // Measured: `115` // Estimated: `36283` - // Minimum execution time: 6_918_000 picoseconds. - Weight::from_parts(7_083_000, 0) + // Minimum execution time: 5_870_000 picoseconds. + Weight::from_parts(6_028_000, 0) .saturating_add(Weight::from_parts(0, 36283)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `MessageQueue::BookStateFor` (r:0 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:0 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) fn service_page_item() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 28_445_000 picoseconds. - Weight::from_parts(28_659_000, 0) + // Minimum execution time: 80_681_000 picoseconds. + Weight::from_parts(81_818_000, 0) .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: MessageQueue ServiceHead (r:1 w:1) - /// Proof: MessageQueue ServiceHead (max_values: Some(1), max_size: Some(6), added: 501, mode: MaxEncodedLen) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) + /// Storage: `MessageQueue::ServiceHead` (r:1 w:1) + /// Proof: `MessageQueue::ServiceHead` (`max_values`: Some(1), `max_size`: Some(6), added: 501, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:0) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) fn bump_service_head() -> Weight { // Proof Size summary in bytes: - // Measured: `149` + // Measured: `220` // Estimated: `3520` - // Minimum execution time: 7_224_000 picoseconds. - Weight::from_parts(7_441_000, 0) + // Minimum execution time: 8_641_000 picoseconds. + Weight::from_parts(8_995_000, 0) .saturating_add(Weight::from_parts(0, 3520)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(32818), added: 35293, mode: MaxEncodedLen) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Proof: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Storage: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Proof: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) fn reap_page() -> Weight { // Proof Size summary in bytes: - // Measured: `33232` + // Measured: `32945` // Estimated: `36283` - // Minimum execution time: 45_211_000 picoseconds. - Weight::from_parts(45_505_000, 0) + // Minimum execution time: 38_473_000 picoseconds. + Weight::from_parts(39_831_000, 0) .saturating_add(Weight::from_parts(0, 36283)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(32818), added: 35293, mode: MaxEncodedLen) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Proof: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Storage: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Proof: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) fn execute_overweight_page_removed() -> Weight { // Proof Size summary in bytes: - // Measured: `33232` + // Measured: `32945` // Estimated: `36283` - // Minimum execution time: 52_346_000 picoseconds. - Weight::from_parts(52_745_000, 0) + // Minimum execution time: 48_717_000 picoseconds. + Weight::from_parts(49_724_000, 0) .saturating_add(Weight::from_parts(0, 36283)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:1) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(32818), added: 35293, mode: MaxEncodedLen) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:1) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) + /// Storage: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Proof: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Storage: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Proof: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) fn execute_overweight_page_updated() -> Weight { // Proof Size summary in bytes: - // Measured: `33232` + // Measured: `32945` // Estimated: `36283` - // Minimum execution time: 72_567_000 picoseconds. - Weight::from_parts(73_300_000, 0) + // Minimum execution time: 72_718_000 picoseconds. + Weight::from_parts(74_081_000, 0) .saturating_add(Weight::from_parts(0, 36283)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } } 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 000000000000..361bfc7a661b --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_mmr.rs @@ -0,0 +1,77 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// This file is part of Polkadot. + +// Polkadot is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Polkadot is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Polkadot. If not, see . + +//! Autogenerated weights for `pallet_mmr` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-15, STEPS: `5`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// target/testnet/polkadot +// benchmark +// pallet +// --steps=5 +// --repeat=1 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --pallet=pallet_mmr +// --chain=westend-dev +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/westend/src/weights/ + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::Weight}; +use core::marker::PhantomData; + +/// Weight functions for `pallet_mmr`. +pub struct WeightInfo(PhantomData); +impl pallet_mmr::WeightInfo for WeightInfo { + /// Storage: `Mmr::NumberOfLeaves` (r:1 w:1) + /// Proof: `Mmr::NumberOfLeaves` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `Paras::Heads` (r:2049 w:0) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `BeefyMmrLeaf::BeefyNextAuthorities` (r:1 w:0) + /// Proof: `BeefyMmrLeaf::BeefyNextAuthorities` (`max_values`: Some(1), `max_size`: Some(44), added: 539, mode: `MaxEncodedLen`) + /// Storage: `System::Digest` (r:1 w:1) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Mmr::Nodes` (r:0 w:1000) + /// Proof: `Mmr::Nodes` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) + /// Storage: `Mmr::RootHash` (r:0 w:1) + /// Proof: `Mmr::RootHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// The range of component `x` is `[1, 1000]`. + fn on_initialize(x: u32) -> Weight { + // Proof Size summary in bytes: + // Measured: `2140817` + // Estimated: `7213082` + // Minimum execution time: 20_387_000_000 picoseconds. + Weight::from_parts(223_625_477_528, 0) + .saturating_add(Weight::from_parts(0, 7213082)) + // Standard Error: 310_550_970 + .saturating_add(Weight::from_parts(16_906_397_286, 0).saturating_mul(x.into())) + .saturating_add(T::DbWeight::get().reads(2053)) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(x.into()))) + } +} diff --git a/polkadot/runtime/rococo/src/weights/pallet_multisig.rs b/polkadot/runtime/rococo/src/weights/pallet_multisig.rs index a4f33fe198ca..f1b81759ece6 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_multisig.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_multisig.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_multisig` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-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-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_multisig // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -52,110 +55,110 @@ impl pallet_multisig::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 11_475_000 picoseconds. - Weight::from_parts(11_904_745, 0) + // Minimum execution time: 12_023_000 picoseconds. + Weight::from_parts(12_643_116, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(492, 0).saturating_mul(z.into())) + // Standard Error: 3 + .saturating_add(Weight::from_parts(582, 0).saturating_mul(z.into())) } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_create(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `193 + s * (2 ±0)` + // Measured: `229 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 38_857_000 picoseconds. - Weight::from_parts(33_611_791, 0) + // Minimum execution time: 39_339_000 picoseconds. + Weight::from_parts(27_243_033, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 400 - .saturating_add(Weight::from_parts(59_263, 0).saturating_mul(s.into())) - // Standard Error: 3 - .saturating_add(Weight::from_parts(1_211, 0).saturating_mul(z.into())) + // Standard Error: 1_319 + .saturating_add(Weight::from_parts(142_212, 0).saturating_mul(s.into())) + // Standard Error: 12 + .saturating_add(Weight::from_parts(1_592, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) /// The range of component `s` is `[3, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_approve(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `248` // Estimated: `6811` - // Minimum execution time: 25_715_000 picoseconds. - Weight::from_parts(20_607_294, 0) + // Minimum execution time: 27_647_000 picoseconds. + Weight::from_parts(15_828_725, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 285 - .saturating_add(Weight::from_parts(58_225, 0).saturating_mul(s.into())) - // Standard Error: 2 - .saturating_add(Weight::from_parts(1_160, 0).saturating_mul(z.into())) + // Standard Error: 908 + .saturating_add(Weight::from_parts(130_880, 0).saturating_mul(s.into())) + // Standard Error: 8 + .saturating_add(Weight::from_parts(1_532, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `s` is `[2, 100]`. /// The range of component `z` is `[0, 10000]`. fn as_multi_complete(s: u32, z: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `317 + s * (33 ±0)` + // Measured: `354 + s * (33 ±0)` // Estimated: `6811` - // Minimum execution time: 43_751_000 picoseconds. - Weight::from_parts(37_398_513, 0) + // Minimum execution time: 46_971_000 picoseconds. + Weight::from_parts(32_150_393, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 426 - .saturating_add(Weight::from_parts(70_904, 0).saturating_mul(s.into())) - // Standard Error: 4 - .saturating_add(Weight::from_parts(1_235, 0).saturating_mul(z.into())) + // Standard Error: 1_129 + .saturating_add(Weight::from_parts(154_796, 0).saturating_mul(s.into())) + // Standard Error: 11 + .saturating_add(Weight::from_parts(1_603, 0).saturating_mul(z.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_create(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `193 + s * (2 ±0)` + // Measured: `229 + s * (2 ±0)` // Estimated: `6811` - // Minimum execution time: 31_278_000 picoseconds. - Weight::from_parts(32_075_573, 0) + // Minimum execution time: 24_947_000 picoseconds. + Weight::from_parts(26_497_183, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 452 - .saturating_add(Weight::from_parts(62_018, 0).saturating_mul(s.into())) + // Standard Error: 1_615 + .saturating_add(Weight::from_parts(147_071, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) /// The range of component `s` is `[2, 100]`. fn approve_as_multi_approve(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `211` + // Measured: `248` // Estimated: `6811` - // Minimum execution time: 18_178_000 picoseconds. - Weight::from_parts(18_649_867, 0) + // Minimum execution time: 13_897_000 picoseconds. + Weight::from_parts(14_828_339, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 293 - .saturating_add(Weight::from_parts(56_475, 0).saturating_mul(s.into())) + // Standard Error: 1_136 + .saturating_add(Weight::from_parts(133_925, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Multisig Multisigs (r:1 w:1) - /// Proof: Multisig Multisigs (max_values: None, max_size: Some(3346), added: 5821, mode: MaxEncodedLen) + /// Storage: `Multisig::Multisigs` (r:1 w:1) + /// Proof: `Multisig::Multisigs` (`max_values`: None, `max_size`: Some(3346), added: 5821, mode: `MaxEncodedLen`) /// The range of component `s` is `[2, 100]`. fn cancel_as_multi(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `383 + s * (1 ±0)` + // Measured: `420 + s * (1 ±0)` // Estimated: `6811` - // Minimum execution time: 32_265_000 picoseconds. - Weight::from_parts(32_984_014, 0) + // Minimum execution time: 28_984_000 picoseconds. + Weight::from_parts(29_853_232, 0) .saturating_add(Weight::from_parts(0, 6811)) - // Standard Error: 452 - .saturating_add(Weight::from_parts(59_934, 0).saturating_mul(s.into())) + // Standard Error: 650 + .saturating_add(Weight::from_parts(113_440, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_nis.rs b/polkadot/runtime/rococo/src/weights/pallet_nis.rs index 35dad482129e..38b41f3a8e24 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_nis.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_nis.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_nis` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-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-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_nis // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,202 +50,186 @@ use core::marker::PhantomData; /// Weight functions for `pallet_nis`. pub struct WeightInfo(PhantomData); impl pallet_nis::WeightInfo for WeightInfo { - /// Storage: Nis Queues (r:1 w:1) - /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) - /// Storage: Balances Holds (r:1 w:1) - /// Proof: Balances Holds (max_values: None, max_size: Some(67), added: 2542, mode: MaxEncodedLen) - /// Storage: Nis QueueTotals (r:1 w:1) - /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) + /// Storage: `Nis::Queues` (r:1 w:1) + /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) + /// Storage: `Nis::QueueTotals` (r:1 w:1) + /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 999]`. fn place_bid(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `6209 + l * (48 ±0)` // Estimated: `51487` - // Minimum execution time: 44_704_000 picoseconds. - Weight::from_parts(44_933_886, 0) + // Minimum execution time: 39_592_000 picoseconds. + Weight::from_parts(38_234_037, 0) .saturating_add(Weight::from_parts(0, 51487)) - // Standard Error: 712 - .saturating_add(Weight::from_parts(71_570, 0).saturating_mul(l.into())) + // Standard Error: 1_237 + .saturating_add(Weight::from_parts(88_816, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Nis Queues (r:1 w:1) - /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) - /// Storage: Balances Holds (r:1 w:1) - /// Proof: Balances Holds (max_values: None, max_size: Some(67), added: 2542, mode: MaxEncodedLen) - /// Storage: Nis QueueTotals (r:1 w:1) - /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) + /// Storage: `Nis::Queues` (r:1 w:1) + /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) + /// Storage: `Nis::QueueTotals` (r:1 w:1) + /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) fn place_bid_max() -> Weight { // Proof Size summary in bytes: // Measured: `54211` // Estimated: `51487` - // Minimum execution time: 126_544_000 picoseconds. - Weight::from_parts(128_271_000, 0) + // Minimum execution time: 134_847_000 picoseconds. + Weight::from_parts(139_510_000, 0) .saturating_add(Weight::from_parts(0, 51487)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Nis Queues (r:1 w:1) - /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) - /// Storage: Balances Holds (r:1 w:1) - /// Proof: Balances Holds (max_values: None, max_size: Some(67), added: 2542, mode: MaxEncodedLen) - /// Storage: Nis QueueTotals (r:1 w:1) - /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) + /// Storage: `Nis::Queues` (r:1 w:1) + /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) + /// Storage: `Nis::QueueTotals` (r:1 w:1) + /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) /// The range of component `l` is `[1, 1000]`. fn retract_bid(l: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `6209 + l * (48 ±0)` // Estimated: `51487` - // Minimum execution time: 47_640_000 picoseconds. - Weight::from_parts(42_214_261, 0) + // Minimum execution time: 43_330_000 picoseconds. + Weight::from_parts(35_097_881, 0) .saturating_add(Weight::from_parts(0, 51487)) - // Standard Error: 732 - .saturating_add(Weight::from_parts(87_277, 0).saturating_mul(l.into())) + // Standard Error: 1_119 + .saturating_add(Weight::from_parts(73_640, 0).saturating_mul(l.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Nis Summary (r:1 w:0) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Nis::Summary` (r:1 w:0) + /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn fund_deficit() -> Weight { // Proof Size summary in bytes: // Measured: `225` // Estimated: `3593` - // Minimum execution time: 38_031_000 picoseconds. - Weight::from_parts(38_441_000, 0) + // Minimum execution time: 29_989_000 picoseconds. + Weight::from_parts(30_865_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Nis Receipts (r:1 w:1) - /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) - /// Storage: Balances Holds (r:1 w:1) - /// Proof: Balances Holds (max_values: None, max_size: Some(67), added: 2542, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Nis Summary (r:1 w:1) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances TotalIssuance (r:1 w:1) - /// Proof: NisCounterpartBalances TotalIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances Account (r:1 w:1) - /// Proof: NisCounterpartBalances Account (max_values: None, max_size: Some(112), added: 2587, mode: MaxEncodedLen) + /// Storage: `Nis::Receipts` (r:1 w:1) + /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Nis::Summary` (r:1 w:1) + /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) + /// Storage: `NisCounterpartBalances::Account` (r:1 w:1) + /// Proof: `NisCounterpartBalances::Account` (`max_values`: None, `max_size`: Some(112), added: 2587, mode: `MaxEncodedLen`) fn communify() -> Weight { // Proof Size summary in bytes: - // Measured: `469` + // Measured: `387` // Estimated: `3593` - // Minimum execution time: 69_269_000 picoseconds. - Weight::from_parts(70_000_000, 0) + // Minimum execution time: 58_114_000 picoseconds. + Weight::from_parts(59_540_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: Nis Receipts (r:1 w:1) - /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) - /// Storage: Nis Summary (r:1 w:1) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances Account (r:1 w:1) - /// Proof: NisCounterpartBalances Account (max_values: None, max_size: Some(112), added: 2587, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances TotalIssuance (r:1 w:1) - /// Proof: NisCounterpartBalances TotalIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Balances Holds (r:1 w:1) - /// Proof: Balances Holds (max_values: None, max_size: Some(67), added: 2542, mode: MaxEncodedLen) + /// Storage: `Nis::Receipts` (r:1 w:1) + /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Storage: `Nis::Summary` (r:1 w:1) + /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `NisCounterpartBalances::Account` (r:1 w:1) + /// Proof: `NisCounterpartBalances::Account` (`max_values`: None, `max_size`: Some(112), added: 2587, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) fn privatize() -> Weight { // Proof Size summary in bytes: - // Measured: `659` + // Measured: `543` // Estimated: `3593` - // Minimum execution time: 85_763_000 picoseconds. - Weight::from_parts(86_707_000, 0) + // Minimum execution time: 75_780_000 picoseconds. + Weight::from_parts(77_097_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: Nis Receipts (r:1 w:1) - /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) - /// Storage: Nis Summary (r:1 w:1) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Holds (r:1 w:1) - /// Proof: Balances Holds (max_values: None, max_size: Some(67), added: 2542, mode: MaxEncodedLen) + /// Storage: `Nis::Receipts` (r:1 w:1) + /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Storage: `Nis::Summary` (r:1 w:1) + /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) fn thaw_private() -> Weight { // Proof Size summary in bytes: // Measured: `387` // Estimated: `3593` - // Minimum execution time: 47_336_000 picoseconds. - Weight::from_parts(47_623_000, 0) + // Minimum execution time: 46_133_000 picoseconds. + Weight::from_parts(47_250_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Nis Receipts (r:1 w:1) - /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) - /// Storage: Nis Summary (r:1 w:1) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances Account (r:1 w:1) - /// Proof: NisCounterpartBalances Account (max_values: None, max_size: Some(112), added: 2587, mode: MaxEncodedLen) - /// Storage: NisCounterpartBalances TotalIssuance (r:1 w:1) - /// Proof: NisCounterpartBalances TotalIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Nis::Receipts` (r:1 w:1) + /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) + /// Storage: `Nis::Summary` (r:1 w:1) + /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) + /// Storage: `NisCounterpartBalances::Account` (r:1 w:1) + /// Proof: `NisCounterpartBalances::Account` (`max_values`: None, `max_size`: Some(112), added: 2587, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) fn thaw_communal() -> Weight { // Proof Size summary in bytes: - // Measured: `604` + // Measured: `488` // Estimated: `3593` - // Minimum execution time: 90_972_000 picoseconds. - Weight::from_parts(92_074_000, 0) + // Minimum execution time: 77_916_000 picoseconds. + Weight::from_parts(79_427_000, 0) .saturating_add(Weight::from_parts(0, 3593)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) } - /// Storage: Nis Summary (r:1 w:1) - /// Proof: Nis Summary (max_values: Some(1), max_size: Some(40), added: 535, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:0) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Nis QueueTotals (r:1 w:1) - /// Proof: Nis QueueTotals (max_values: Some(1), max_size: Some(6002), added: 6497, mode: MaxEncodedLen) + /// Storage: `Nis::Summary` (r:1 w:1) + /// Proof: `Nis::Summary` (`max_values`: Some(1), `max_size`: Some(40), added: 535, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Nis::QueueTotals` (r:1 w:1) + /// Proof: `Nis::QueueTotals` (`max_values`: Some(1), `max_size`: Some(6002), added: 6497, mode: `MaxEncodedLen`) fn process_queues() -> Weight { // Proof Size summary in bytes: // Measured: `6658` // Estimated: `7487` - // Minimum execution time: 21_469_000 picoseconds. - Weight::from_parts(21_983_000, 0) + // Minimum execution time: 22_992_000 picoseconds. + Weight::from_parts(24_112_000, 0) .saturating_add(Weight::from_parts(0, 7487)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Nis Queues (r:1 w:1) - /// Proof: Nis Queues (max_values: None, max_size: Some(48022), added: 50497, mode: MaxEncodedLen) + /// Storage: `Nis::Queues` (r:1 w:1) + /// Proof: `Nis::Queues` (`max_values`: None, `max_size`: Some(48022), added: 50497, mode: `MaxEncodedLen`) fn process_queue() -> Weight { // Proof Size summary in bytes: // Measured: `76` // Estimated: `51487` - // Minimum execution time: 4_912_000 picoseconds. - Weight::from_parts(5_013_000, 0) + // Minimum execution time: 3_856_000 picoseconds. + Weight::from_parts(4_125_000, 0) .saturating_add(Weight::from_parts(0, 51487)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Nis Receipts (r:0 w:1) - /// Proof: Nis Receipts (max_values: None, max_size: Some(81), added: 2556, mode: MaxEncodedLen) + /// Storage: `Nis::Receipts` (r:0 w:1) + /// Proof: `Nis::Receipts` (`max_values`: None, `max_size`: Some(81), added: 2556, mode: `MaxEncodedLen`) fn process_bid() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_048_000 picoseconds. - Weight::from_parts(7_278_000, 0) + // Minimum execution time: 4_344_000 picoseconds. + Weight::from_parts(4_545_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_preimage.rs b/polkadot/runtime/rococo/src/weights/pallet_preimage.rs index e051ebd5bbab..7a2b77b84d80 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_preimage.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_preimage.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_preimage` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-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-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_preimage // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,184 +50,219 @@ use core::marker::PhantomData; /// Weight functions for `pallet_preimage`. pub struct WeightInfo(PhantomData); impl pallet_preimage::WeightInfo for WeightInfo { - fn ensure_updated(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `193 + n * (91 ±0)` - // Estimated: `3593 + n * (2566 ±0)` - // Minimum execution time: 2_000_000 picoseconds. - Weight::from_parts(2_000_000, 3593) - // Standard Error: 13_720 - .saturating_add(Weight::from_parts(17_309_199, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(1_u64)) - .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2566).saturating_mul(n.into())) - } - - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:0 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 4194304]`. fn note_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `215` - // Estimated: `3556` - // Minimum execution time: 31_040_000 picoseconds. - Weight::from_parts(31_236_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_974, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `114` + // Estimated: `3568` + // Minimum execution time: 40_363_000 picoseconds. + Weight::from_parts(41_052_000, 0) + .saturating_add(Weight::from_parts(0, 3568)) + // Standard Error: 6 + .saturating_add(Weight::from_parts(2_298, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:0 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 4194304]`. fn note_requested_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `178` // Estimated: `3556` - // Minimum execution time: 18_025_000 picoseconds. - Weight::from_parts(18_264_000, 0) + // Minimum execution time: 14_570_000 picoseconds. + Weight::from_parts(14_890_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_974, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) + // Standard Error: 2 + .saturating_add(Weight::from_parts(2_364, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:0 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) /// The range of component `s` is `[0, 4194304]`. fn note_no_deposit_preimage(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `178` // Estimated: `3556` - // Minimum execution time: 17_122_000 picoseconds. - Weight::from_parts(17_332_000, 0) + // Minimum execution time: 13_933_000 picoseconds. + Weight::from_parts(14_290_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_968, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) + // Standard Error: 2 + .saturating_add(Weight::from_parts(2_349, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1 w:1) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:0 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) fn unnote_preimage() -> Weight { // Proof Size summary in bytes: - // Measured: `361` - // Estimated: `3556` - // Minimum execution time: 38_218_000 picoseconds. - Weight::from_parts(39_841_000, 0) - .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) + // Measured: `315` + // Estimated: `3568` + // Minimum execution time: 54_373_000 picoseconds. + Weight::from_parts(58_205_000, 0) + .saturating_add(Weight::from_parts(0, 3568)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:0 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) fn unnote_no_deposit_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `216` // Estimated: `3556` - // Minimum execution time: 23_217_000 picoseconds. - Weight::from_parts(24_246_000, 0) + // Minimum execution time: 24_267_000 picoseconds. + Weight::from_parts(27_063_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn request_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `260` // Estimated: `3556` - // Minimum execution time: 21_032_000 picoseconds. - Weight::from_parts(21_844_000, 0) + // Minimum execution time: 25_569_000 picoseconds. + Weight::from_parts(27_895_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn request_no_deposit_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `216` // Estimated: `3556` - // Minimum execution time: 13_954_000 picoseconds. - Weight::from_parts(14_501_000, 0) + // Minimum execution time: 14_182_000 picoseconds. + Weight::from_parts(16_098_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn request_unnoted_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `114` // Estimated: `3556` - // Minimum execution time: 14_874_000 picoseconds. - Weight::from_parts(15_380_000, 0) + // Minimum execution time: 14_681_000 picoseconds. + Weight::from_parts(15_549_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn request_requested_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `178` // Estimated: `3556` - // Minimum execution time: 10_199_000 picoseconds. - Weight::from_parts(10_493_000, 0) + // Minimum execution time: 9_577_000 picoseconds. + Weight::from_parts(10_146_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: Preimage PreimageFor (r:0 w:1) - /// Proof: Preimage PreimageFor (max_values: None, max_size: Some(4194344), added: 4196819, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::PreimageFor` (r:0 w:1) + /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `MaxEncodedLen`) fn unrequest_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `216` // Estimated: `3556` - // Minimum execution time: 21_772_000 picoseconds. - Weight::from_parts(22_554_000, 0) + // Minimum execution time: 21_003_000 picoseconds. + Weight::from_parts(23_549_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn unrequest_unnoted_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `178` // Estimated: `3556` - // Minimum execution time: 10_115_000 picoseconds. - Weight::from_parts(10_452_000, 0) + // Minimum execution time: 9_507_000 picoseconds. + Weight::from_parts(10_013_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Preimage StatusFor (r:1 w:1) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) + /// Storage: `Preimage::StatusFor` (r:1 w:0) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn unrequest_multi_referenced_preimage() -> Weight { // Proof Size summary in bytes: // Measured: `178` // Estimated: `3556` - // Minimum execution time: 10_031_000 picoseconds. - Weight::from_parts(10_310_000, 0) + // Minimum execution time: 9_293_000 picoseconds. + Weight::from_parts(10_055_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `Preimage::StatusFor` (r:1023 w:1023) + /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1023 w:1023) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Holds` (r:1023 w:1023) + /// Proof: `Balances::Holds` (`max_values`: None, `max_size`: Some(103), added: 2578, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:0 w:1023) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 1024]`. + fn ensure_updated(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0 + n * (227 ±0)` + // Estimated: `990 + n * (2603 ±0)` + // Minimum execution time: 48_846_000 picoseconds. + Weight::from_parts(49_378_000, 0) + .saturating_add(Weight::from_parts(0, 990)) + // Standard Error: 38_493 + .saturating_add(Weight::from_parts(47_418_285, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2603).saturating_mul(n.into())) + } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_proxy.rs b/polkadot/runtime/rococo/src/weights/pallet_proxy.rs index d9737a85c05a..c92025930950 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_proxy.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_proxy.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_proxy` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-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-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_proxy // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,172 +50,176 @@ use core::marker::PhantomData; /// Weight functions for `pallet_proxy`. pub struct WeightInfo(PhantomData); impl pallet_proxy::WeightInfo for WeightInfo { - /// Storage: Proxy Proxies (r:1 w:0) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 31]`. fn proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `227 + p * (37 ±0)` + // Measured: `89 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 15_956_000 picoseconds. - Weight::from_parts(16_300_358, 0) + // Minimum execution time: 11_267_000 picoseconds. + Weight::from_parts(11_798_007, 0) .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 652 - .saturating_add(Weight::from_parts(30_807, 0).saturating_mul(p.into())) + // Standard Error: 858 + .saturating_add(Weight::from_parts(43_735, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) } - /// Storage: Proxy Proxies (r:1 w:0) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn proxy_announced(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `554 + a * (68 ±0) + p * (37 ±0)` + // Measured: `416 + a * (68 ±0) + p * (37 ±0)` // Estimated: `5698` - // Minimum execution time: 37_584_000 picoseconds. - Weight::from_parts(37_858_207, 0) + // Minimum execution time: 32_791_000 picoseconds. + Weight::from_parts(32_776_904, 0) .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_868 - .saturating_add(Weight::from_parts(148_967, 0).saturating_mul(a.into())) - // Standard Error: 1_930 - .saturating_add(Weight::from_parts(13_017, 0).saturating_mul(p.into())) + // Standard Error: 2_382 + .saturating_add(Weight::from_parts(143_857, 0).saturating_mul(a.into())) + // Standard Error: 2_461 + .saturating_add(Weight::from_parts(40_024, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. - fn remove_announcement(a: u32, _p: u32, ) -> Weight { + fn remove_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `469 + a * (68 ±0)` + // Measured: `331 + a * (68 ±0)` // Estimated: `5698` - // Minimum execution time: 24_642_000 picoseconds. - Weight::from_parts(25_526_588, 0) + // Minimum execution time: 21_831_000 picoseconds. + Weight::from_parts(22_479_938, 0) .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_138 - .saturating_add(Weight::from_parts(131_157, 0).saturating_mul(a.into())) + // Standard Error: 1_738 + .saturating_add(Weight::from_parts(146_532, 0).saturating_mul(a.into())) + // Standard Error: 1_796 + .saturating_add(Weight::from_parts(7_499, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. - fn reject_announcement(a: u32, _p: u32, ) -> Weight { + fn reject_announcement(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `469 + a * (68 ±0)` + // Measured: `331 + a * (68 ±0)` // Estimated: `5698` - // Minimum execution time: 24_377_000 picoseconds. - Weight::from_parts(25_464_033, 0) + // Minimum execution time: 21_776_000 picoseconds. + Weight::from_parts(22_762_843, 0) .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_116 - .saturating_add(Weight::from_parts(130_722, 0).saturating_mul(a.into())) + // Standard Error: 1_402 + .saturating_add(Weight::from_parts(137_512, 0).saturating_mul(a.into())) + // Standard Error: 1_449 + .saturating_add(Weight::from_parts(3_645, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Proxy Proxies (r:1 w:0) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) - /// Storage: Proxy Announcements (r:1 w:1) - /// Proof: Proxy Announcements (max_values: None, max_size: Some(2233), added: 4708, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Proxy::Proxies` (r:1 w:0) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) + /// Storage: `Proxy::Announcements` (r:1 w:1) + /// Proof: `Proxy::Announcements` (`max_values`: None, `max_size`: Some(2233), added: 4708, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `a` is `[0, 31]`. /// The range of component `p` is `[1, 31]`. fn announce(a: u32, p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `486 + a * (68 ±0) + p * (37 ±0)` + // Measured: `348 + a * (68 ±0) + p * (37 ±0)` // Estimated: `5698` - // Minimum execution time: 34_202_000 picoseconds. - Weight::from_parts(34_610_079, 0) + // Minimum execution time: 29_108_000 picoseconds. + Weight::from_parts(29_508_910, 0) .saturating_add(Weight::from_parts(0, 5698)) - // Standard Error: 1_234 - .saturating_add(Weight::from_parts(134_197, 0).saturating_mul(a.into())) - // Standard Error: 1_275 - .saturating_add(Weight::from_parts(15_970, 0).saturating_mul(p.into())) + // Standard Error: 2_268 + .saturating_add(Weight::from_parts(144_770, 0).saturating_mul(a.into())) + // Standard Error: 2_343 + .saturating_add(Weight::from_parts(25_851, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 31]`. fn add_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `227 + p * (37 ±0)` + // Measured: `89 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 25_492_000 picoseconds. - Weight::from_parts(25_984_867, 0) + // Minimum execution time: 18_942_000 picoseconds. + Weight::from_parts(19_518_812, 0) .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 893 - .saturating_add(Weight::from_parts(51_868, 0).saturating_mul(p.into())) + // Standard Error: 1_078 + .saturating_add(Weight::from_parts(46_147, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 31]`. fn remove_proxy(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `227 + p * (37 ±0)` + // Measured: `89 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 25_492_000 picoseconds. - Weight::from_parts(26_283_445, 0) + // Minimum execution time: 18_993_000 picoseconds. + Weight::from_parts(19_871_741, 0) .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 1_442 - .saturating_add(Weight::from_parts(53_504, 0).saturating_mul(p.into())) + // Standard Error: 1_883 + .saturating_add(Weight::from_parts(46_033, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 31]`. fn remove_proxies(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `227 + p * (37 ±0)` + // Measured: `89 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 22_083_000 picoseconds. - Weight::from_parts(22_688_835, 0) + // Minimum execution time: 17_849_000 picoseconds. + Weight::from_parts(18_776_170, 0) .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 994 - .saturating_add(Weight::from_parts(32_994, 0).saturating_mul(p.into())) + // Standard Error: 1_239 + .saturating_add(Weight::from_parts(27_960, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) /// The range of component `p` is `[1, 31]`. fn create_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `239` + // Measured: `101` // Estimated: `4706` - // Minimum execution time: 27_042_000 picoseconds. - Weight::from_parts(27_624_587, 0) + // Minimum execution time: 20_049_000 picoseconds. + Weight::from_parts(20_881_515, 0) .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 671 - .saturating_add(Weight::from_parts(5_888, 0).saturating_mul(p.into())) + // Standard Error: 952 + .saturating_add(Weight::from_parts(5_970, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Proxy Proxies (r:1 w:1) - /// Proof: Proxy Proxies (max_values: None, max_size: Some(1241), added: 3716, mode: MaxEncodedLen) + /// Storage: `Proxy::Proxies` (r:1 w:1) + /// Proof: `Proxy::Proxies` (`max_values`: None, `max_size`: Some(1241), added: 3716, mode: `MaxEncodedLen`) /// The range of component `p` is `[0, 30]`. fn kill_pure(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `264 + p * (37 ±0)` + // Measured: `126 + p * (37 ±0)` // Estimated: `4706` - // Minimum execution time: 23_396_000 picoseconds. - Weight::from_parts(24_003_080, 0) + // Minimum execution time: 18_528_000 picoseconds. + Weight::from_parts(19_384_189, 0) .saturating_add(Weight::from_parts(0, 4706)) - // Standard Error: 684 - .saturating_add(Weight::from_parts(29_878, 0).saturating_mul(p.into())) + // Standard Error: 1_106 + .saturating_add(Weight::from_parts(35_698, 0).saturating_mul(p.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_ranked_collective.rs b/polkadot/runtime/rococo/src/weights/pallet_ranked_collective.rs index ce9d5fcc0c71..fa2decb16716 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_ranked_collective.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_ranked_collective.rs @@ -16,24 +16,26 @@ //! Autogenerated weights for `pallet_ranked_collective` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2024-01-24, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-grjcggob-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-bn-ce5rx-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 +// ./target/production/polkadot // benchmark // pallet +// --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=pallet_ranked_collective // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_ranked_collective -// --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ @@ -60,8 +62,8 @@ impl pallet_ranked_collective::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `42` // Estimated: `3507` - // Minimum execution time: 13_480_000 picoseconds. - Weight::from_parts(13_786_000, 0) + // Minimum execution time: 13_428_000 picoseconds. + Weight::from_parts(14_019_000, 0) .saturating_add(Weight::from_parts(0, 3507)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) @@ -79,11 +81,11 @@ impl pallet_ranked_collective::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `516 + r * (281 ±0)` // Estimated: `3519 + r * (2529 ±0)` - // Minimum execution time: 28_771_000 picoseconds. - Weight::from_parts(29_256_825, 0) + // Minimum execution time: 28_566_000 picoseconds. + Weight::from_parts(29_346_952, 0) .saturating_add(Weight::from_parts(0, 3519)) - // Standard Error: 21_594 - .saturating_add(Weight::from_parts(14_649_527, 0).saturating_mul(r.into())) + // Standard Error: 21_068 + .saturating_add(Weight::from_parts(14_471_237, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(r.into()))) .saturating_add(T::DbWeight::get().writes(6)) @@ -103,11 +105,11 @@ impl pallet_ranked_collective::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `214 + r * (17 ±0)` // Estimated: `3507` - // Minimum execution time: 16_117_000 picoseconds. - Weight::from_parts(16_978_453, 0) + // Minimum execution time: 16_161_000 picoseconds. + Weight::from_parts(16_981_334, 0) .saturating_add(Weight::from_parts(0, 3507)) - // Standard Error: 4_511 - .saturating_add(Weight::from_parts(324_261, 0).saturating_mul(r.into())) + // Standard Error: 4_596 + .saturating_add(Weight::from_parts(313_386, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -124,11 +126,11 @@ impl pallet_ranked_collective::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `532 + r * (72 ±0)` // Estimated: `3519` - // Minimum execution time: 28_995_000 picoseconds. - Weight::from_parts(31_343_215, 0) + // Minimum execution time: 28_406_000 picoseconds. + Weight::from_parts(31_178_557, 0) .saturating_add(Weight::from_parts(0, 3519)) - // Standard Error: 16_438 - .saturating_add(Weight::from_parts(637_462, 0).saturating_mul(r.into())) + // Standard Error: 17_737 + .saturating_add(Weight::from_parts(627_757, 0).saturating_mul(r.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(6)) } @@ -140,15 +142,17 @@ impl pallet_ranked_collective::WeightInfo for WeightInf /// Proof: `FellowshipCollective::Voting` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn vote() -> Weight { // Proof Size summary in bytes: // Measured: `603` // Estimated: `83866` - // Minimum execution time: 38_820_000 picoseconds. - Weight::from_parts(40_240_000, 0) + // Minimum execution time: 41_164_000 picoseconds. + Weight::from_parts(42_163_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:0) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) @@ -161,11 +165,11 @@ impl pallet_ranked_collective::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `400 + n * (50 ±0)` // Estimated: `4365 + n * (2540 ±0)` - // Minimum execution time: 12_972_000 picoseconds. - Weight::from_parts(15_829_333, 0) + // Minimum execution time: 13_183_000 picoseconds. + Weight::from_parts(15_604_064, 0) .saturating_add(Weight::from_parts(0, 4365)) - // Standard Error: 1_754 - .saturating_add(Weight::from_parts(1_116_520, 0).saturating_mul(n.into())) + // Standard Error: 2_018 + .saturating_add(Weight::from_parts(1_101_088, 0).saturating_mul(n.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(n.into()))) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(n.into()))) @@ -183,8 +187,8 @@ impl pallet_ranked_collective::WeightInfo for WeightInf // Proof Size summary in bytes: // Measured: `337` // Estimated: `6048` - // Minimum execution time: 44_601_000 picoseconds. - Weight::from_parts(45_714_000, 0) + // Minimum execution time: 43_603_000 picoseconds. + Weight::from_parts(44_809_000, 0) .saturating_add(Weight::from_parts(0, 6048)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(10)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_recovery.rs b/polkadot/runtime/rococo/src/weights/pallet_recovery.rs new file mode 100644 index 000000000000..ed79aa2b1f17 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_recovery.rs @@ -0,0 +1,186 @@ +// 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_recovery` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot +// benchmark +// pallet +// --chain=rococo-dev +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=pallet_recovery +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --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_recovery`. +pub struct WeightInfo(PhantomData); +impl pallet_recovery::WeightInfo for WeightInfo { + /// Storage: `Recovery::Proxy` (r:1 w:0) + /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + fn as_recovered() -> Weight { + // Proof Size summary in bytes: + // Measured: `215` + // Estimated: `3545` + // Minimum execution time: 7_899_000 picoseconds. + Weight::from_parts(8_205_000, 0) + .saturating_add(Weight::from_parts(0, 3545)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `Recovery::Proxy` (r:0 w:1) + /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + fn set_recovered() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_258_000 picoseconds. + Weight::from_parts(6_494_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Recovery::Recoverable` (r:1 w:1) + /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 9]`. + fn create_recovery(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `109` + // Estimated: `3816` + // Minimum execution time: 19_369_000 picoseconds. + Weight::from_parts(20_185_132, 0) + .saturating_add(Weight::from_parts(0, 3816)) + // Standard Error: 4_275 + .saturating_add(Weight::from_parts(78_024, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Recovery::Recoverable` (r:1 w:0) + /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) + /// Storage: `Recovery::ActiveRecoveries` (r:1 w:1) + /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) + fn initiate_recovery() -> Weight { + // Proof Size summary in bytes: + // Measured: `206` + // Estimated: `3854` + // Minimum execution time: 22_425_000 picoseconds. + Weight::from_parts(23_171_000, 0) + .saturating_add(Weight::from_parts(0, 3854)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Recovery::Recoverable` (r:1 w:0) + /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) + /// Storage: `Recovery::ActiveRecoveries` (r:1 w:1) + /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 9]`. + fn vouch_recovery(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `294 + n * (64 ±0)` + // Estimated: `3854` + // Minimum execution time: 17_308_000 picoseconds. + Weight::from_parts(18_118_782, 0) + .saturating_add(Weight::from_parts(0, 3854)) + // Standard Error: 4_309 + .saturating_add(Weight::from_parts(126_278, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Recovery::Recoverable` (r:1 w:0) + /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) + /// Storage: `Recovery::ActiveRecoveries` (r:1 w:0) + /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) + /// Storage: `Recovery::Proxy` (r:1 w:1) + /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 9]`. + fn claim_recovery(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `326 + n * (64 ±0)` + // Estimated: `3854` + // Minimum execution time: 20_755_000 picoseconds. + Weight::from_parts(21_821_713, 0) + .saturating_add(Weight::from_parts(0, 3854)) + // Standard Error: 4_550 + .saturating_add(Weight::from_parts(101_916, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Recovery::ActiveRecoveries` (r:1 w:1) + /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 9]`. + fn close_recovery(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `447 + n * (32 ±0)` + // Estimated: `3854` + // Minimum execution time: 29_957_000 picoseconds. + Weight::from_parts(31_010_309, 0) + .saturating_add(Weight::from_parts(0, 3854)) + // Standard Error: 5_913 + .saturating_add(Weight::from_parts(110_070, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Recovery::ActiveRecoveries` (r:1 w:0) + /// Proof: `Recovery::ActiveRecoveries` (`max_values`: None, `max_size`: Some(389), added: 2864, mode: `MaxEncodedLen`) + /// Storage: `Recovery::Recoverable` (r:1 w:1) + /// Proof: `Recovery::Recoverable` (`max_values`: None, `max_size`: Some(351), added: 2826, mode: `MaxEncodedLen`) + /// The range of component `n` is `[1, 9]`. + fn remove_recovery(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `204 + n * (32 ±0)` + // Estimated: `3854` + // Minimum execution time: 24_430_000 picoseconds. + Weight::from_parts(24_462_856, 0) + .saturating_add(Weight::from_parts(0, 3854)) + // Standard Error: 13_646 + .saturating_add(Weight::from_parts(507_715, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Recovery::Proxy` (r:1 w:1) + /// Proof: `Recovery::Proxy` (`max_values`: None, `max_size`: Some(80), added: 2555, mode: `MaxEncodedLen`) + fn cancel_recovered() -> Weight { + // Proof Size summary in bytes: + // Measured: `215` + // Estimated: `3545` + // Minimum execution time: 9_686_000 picoseconds. + Weight::from_parts(10_071_000, 0) + .saturating_add(Weight::from_parts(0, 3545)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/pallet_referenda_fellowship_referenda.rs b/polkadot/runtime/rococo/src/weights/pallet_referenda_fellowship_referenda.rs index 96f172230e13..6dfcea2b8327 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_referenda_fellowship_referenda.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_referenda_fellowship_referenda.rs @@ -16,27 +16,28 @@ //! Autogenerated weights for `pallet_referenda` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-xerhrdyb-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: `Some(Wasm)`, WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 +// ./target/production/polkadot // benchmark // pallet +// --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=pallet_referenda // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json -// --pallet=pallet_referenda -// --chain=rococo-dev -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -59,10 +60,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) fn submit() -> Weight { // Proof Size summary in bytes: - // Measured: `327` + // Measured: `292` // Estimated: `42428` - // Minimum execution time: 29_909_000 picoseconds. - Weight::from_parts(30_645_000, 0) + // Minimum execution time: 24_053_000 picoseconds. + Weight::from_parts(25_121_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) @@ -71,15 +72,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `438` + // Measured: `403` // Estimated: `83866` - // Minimum execution time: 54_405_000 picoseconds. - Weight::from_parts(55_583_000, 0) + // Minimum execution time: 45_064_000 picoseconds. + Weight::from_parts(46_112_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) @@ -89,15 +92,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `2076` + // Measured: `2041` // Estimated: `42428` - // Minimum execution time: 110_477_000 picoseconds. - Weight::from_parts(119_187_000, 0) + // Minimum execution time: 94_146_000 picoseconds. + Weight::from_parts(98_587_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) @@ -107,15 +112,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `2117` + // Measured: `2082` // Estimated: `42428` - // Minimum execution time: 111_467_000 picoseconds. - Weight::from_parts(117_758_000, 0) + // Minimum execution time: 93_002_000 picoseconds. + Weight::from_parts(96_924_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) @@ -125,15 +132,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `774` + // Measured: `739` // Estimated: `83866` - // Minimum execution time: 191_135_000 picoseconds. - Weight::from_parts(210_535_000, 0) + // Minimum execution time: 160_918_000 picoseconds. + Weight::from_parts(175_603_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) @@ -143,24 +152,26 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipCollective::MemberCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `639` + // Measured: `604` // Estimated: `83866` - // Minimum execution time: 67_168_000 picoseconds. - Weight::from_parts(68_895_000, 0) + // Minimum execution time: 55_253_000 picoseconds. + Weight::from_parts(56_488_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) fn refund_decision_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `351` + // Measured: `317` // Estimated: `4365` - // Minimum execution time: 31_298_000 picoseconds. - Weight::from_parts(32_570_000, 0) + // Minimum execution time: 24_497_000 picoseconds. + Weight::from_parts(25_280_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -169,10 +180,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) fn refund_submission_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `201` + // Measured: `167` // Estimated: `4365` - // Minimum execution time: 15_674_000 picoseconds. - Weight::from_parts(16_190_000, 0) + // Minimum execution time: 11_374_000 picoseconds. + Weight::from_parts(11_817_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -181,15 +192,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `383` + // Measured: `348` // Estimated: `83866` - // Minimum execution time: 38_927_000 picoseconds. - Weight::from_parts(40_545_000, 0) + // Minimum execution time: 31_805_000 picoseconds. + Weight::from_parts(32_622_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) @@ -197,15 +210,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `FellowshipReferenda::MetadataOf` (r:1 w:0) /// Proof: `FellowshipReferenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn kill() -> Weight { // Proof Size summary in bytes: - // Measured: `484` + // Measured: `449` // Estimated: `83866` - // Minimum execution time: 80_209_000 picoseconds. - Weight::from_parts(82_084_000, 0) + // Minimum execution time: 62_364_000 picoseconds. + Weight::from_parts(63_798_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `FellowshipReferenda::TrackQueue` (r:1 w:0) /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) @@ -213,10 +228,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) fn one_fewer_deciding_queue_empty() -> Weight { // Proof Size summary in bytes: - // Measured: `174` + // Measured: `140` // Estimated: `4277` - // Minimum execution time: 9_520_000 picoseconds. - Weight::from_parts(10_088_000, 0) + // Minimum execution time: 8_811_000 picoseconds. + Weight::from_parts(9_224_000, 0) .saturating_add(Weight::from_parts(0, 4277)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -231,10 +246,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn one_fewer_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `2376` + // Measured: `2341` // Estimated: `42428` - // Minimum execution time: 93_893_000 picoseconds. - Weight::from_parts(101_065_000, 0) + // Minimum execution time: 83_292_000 picoseconds. + Weight::from_parts(89_114_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -249,10 +264,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn one_fewer_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `2362` + // Measured: `2327` // Estimated: `42428` - // Minimum execution time: 98_811_000 picoseconds. - Weight::from_parts(103_590_000, 0) + // Minimum execution time: 84_648_000 picoseconds. + Weight::from_parts(89_332_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -263,10 +278,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) fn nudge_referendum_requeued_insertion() -> Weight { // Proof Size summary in bytes: - // Measured: `1841` + // Measured: `1807` // Estimated: `4365` - // Minimum execution time: 43_230_000 picoseconds. - Weight::from_parts(46_120_000, 0) + // Minimum execution time: 40_529_000 picoseconds. + Weight::from_parts(45_217_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -277,10 +292,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) fn nudge_referendum_requeued_slide() -> Weight { // Proof Size summary in bytes: - // Measured: `1808` + // Measured: `1774` // Estimated: `4365` - // Minimum execution time: 43_092_000 picoseconds. - Weight::from_parts(46_018_000, 0) + // Minimum execution time: 40_894_000 picoseconds. + Weight::from_parts(45_726_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -293,10 +308,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) fn nudge_referendum_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `1824` + // Measured: `1790` // Estimated: `4365` - // Minimum execution time: 49_697_000 picoseconds. - Weight::from_parts(53_795_000, 0) + // Minimum execution time: 48_187_000 picoseconds. + Weight::from_parts(52_655_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -309,10 +324,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::TrackQueue` (`max_values`: None, `max_size`: Some(812), added: 3287, mode: `MaxEncodedLen`) fn nudge_referendum_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `1865` + // Measured: `1831` // Estimated: `4365` - // Minimum execution time: 50_417_000 picoseconds. - Weight::from_parts(53_214_000, 0) + // Minimum execution time: 47_548_000 picoseconds. + Weight::from_parts(51_547_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -323,10 +338,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_no_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `335` + // Measured: `300` // Estimated: `42428` - // Minimum execution time: 25_688_000 picoseconds. - Weight::from_parts(26_575_000, 0) + // Minimum execution time: 20_959_000 picoseconds. + Weight::from_parts(21_837_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -337,10 +352,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `383` + // Measured: `348` // Estimated: `42428` - // Minimum execution time: 26_230_000 picoseconds. - Weight::from_parts(27_235_000, 0) + // Minimum execution time: 21_628_000 picoseconds. + Weight::from_parts(22_192_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -349,10 +364,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) fn nudge_referendum_timed_out() -> Weight { // Proof Size summary in bytes: - // Measured: `242` + // Measured: `208` // Estimated: `4365` - // Minimum execution time: 17_585_000 picoseconds. - Weight::from_parts(18_225_000, 0) + // Minimum execution time: 12_309_000 picoseconds. + Weight::from_parts(12_644_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -367,10 +382,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_begin_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `584` + // Measured: `549` // Estimated: `42428` - // Minimum execution time: 38_243_000 picoseconds. - Weight::from_parts(39_959_000, 0) + // Minimum execution time: 31_871_000 picoseconds. + Weight::from_parts(33_123_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -385,10 +400,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_begin_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `719` + // Measured: `684` // Estimated: `42428` - // Minimum execution time: 88_424_000 picoseconds. - Weight::from_parts(92_969_000, 0) + // Minimum execution time: 73_715_000 picoseconds. + Weight::from_parts(79_980_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) @@ -401,10 +416,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_begin_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `770` + // Measured: `735` // Estimated: `42428` - // Minimum execution time: 138_207_000 picoseconds. - Weight::from_parts(151_726_000, 0) + // Minimum execution time: 128_564_000 picoseconds. + Weight::from_parts(138_536_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -417,10 +432,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_end_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `755` + // Measured: `720` // Estimated: `42428` - // Minimum execution time: 131_001_000 picoseconds. - Weight::from_parts(148_651_000, 0) + // Minimum execution time: 129_775_000 picoseconds. + Weight::from_parts(139_001_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -433,10 +448,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_continue_not_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `770` + // Measured: `735` // Estimated: `42428` - // Minimum execution time: 109_612_000 picoseconds. - Weight::from_parts(143_626_000, 0) + // Minimum execution time: 128_233_000 picoseconds. + Weight::from_parts(135_796_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -449,10 +464,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_continue_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `776` + // Measured: `741` // Estimated: `42428` - // Minimum execution time: 71_754_000 picoseconds. - Weight::from_parts(77_329_000, 0) + // Minimum execution time: 66_995_000 picoseconds. + Weight::from_parts(72_678_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -467,10 +482,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn nudge_referendum_approved() -> Weight { // Proof Size summary in bytes: - // Measured: `776` + // Measured: `741` // Estimated: `83866` - // Minimum execution time: 153_244_000 picoseconds. - Weight::from_parts(169_961_000, 0) + // Minimum execution time: 137_764_000 picoseconds. + Weight::from_parts(152_260_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) @@ -483,10 +498,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_rejected() -> Weight { // Proof Size summary in bytes: - // Measured: `772` + // Measured: `737` // Estimated: `42428` - // Minimum execution time: 137_997_000 picoseconds. - Weight::from_parts(157_862_000, 0) + // Minimum execution time: 119_992_000 picoseconds. + Weight::from_parts(134_805_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -495,16 +510,18 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(900), added: 3375, mode: `MaxEncodedLen`) /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:0) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `FellowshipReferenda::MetadataOf` (r:0 w:1) /// Proof: `FellowshipReferenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn set_some_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `458` + // Measured: `424` // Estimated: `4365` - // Minimum execution time: 21_794_000 picoseconds. - Weight::from_parts(22_341_000, 0) + // Minimum execution time: 20_927_000 picoseconds. + Weight::from_parts(21_802_000, 0) .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `FellowshipReferenda::ReferendumInfoFor` (r:1 w:0) @@ -513,10 +530,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `FellowshipReferenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `319` + // Measured: `285` // Estimated: `4365` - // Minimum execution time: 18_458_000 picoseconds. - Weight::from_parts(19_097_000, 0) + // Minimum execution time: 14_253_000 picoseconds. + Weight::from_parts(15_031_000, 0) .saturating_add(Weight::from_parts(0, 4365)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_referenda_referenda.rs b/polkadot/runtime/rococo/src/weights/pallet_referenda_referenda.rs index b7cc5df28b91..c35925198f9d 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_referenda_referenda.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_referenda_referenda.rs @@ -16,27 +16,28 @@ //! Autogenerated weights for `pallet_referenda` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-11, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-xerhrdyb-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: `Some(Wasm)`, WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 +// ./target/production/polkadot // benchmark // pallet +// --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=pallet_referenda // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json -// --pallet=pallet_referenda -// --chain=rococo-dev -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -57,10 +58,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) fn submit() -> Weight { // Proof Size summary in bytes: - // Measured: `324` + // Measured: `185` // Estimated: `42428` - // Minimum execution time: 39_852_000 picoseconds. - Weight::from_parts(41_610_000, 0) + // Minimum execution time: 28_612_000 picoseconds. + Weight::from_parts(30_060_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(3)) @@ -69,15 +70,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `577` + // Measured: `438` // Estimated: `83866` - // Minimum execution time: 52_588_000 picoseconds. - Weight::from_parts(54_154_000, 0) + // Minimum execution time: 42_827_000 picoseconds. + Weight::from_parts(44_072_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) @@ -87,15 +90,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3334` + // Measured: `3225` // Estimated: `42428` - // Minimum execution time: 70_483_000 picoseconds. - Weight::from_parts(72_731_000, 0) + // Minimum execution time: 56_475_000 picoseconds. + Weight::from_parts(58_888_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) @@ -105,60 +110,62 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3354` + // Measured: `3245` // Estimated: `42428` - // Minimum execution time: 68_099_000 picoseconds. - Weight::from_parts(71_560_000, 0) + // Minimum execution time: 56_542_000 picoseconds. + Weight::from_parts(58_616_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Referenda::DecidingCount` (r:1 w:1) /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `577` + // Measured: `438` // Estimated: `83866` - // Minimum execution time: 64_357_000 picoseconds. - Weight::from_parts(66_081_000, 0) + // Minimum execution time: 51_218_000 picoseconds. + Weight::from_parts(53_148_000, 0) .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Referenda::DecidingCount` (r:1 w:1) /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn place_decision_deposit_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `577` + // Measured: `438` // Estimated: `83866` - // Minimum execution time: 62_709_000 picoseconds. - Weight::from_parts(64_534_000, 0) + // Minimum execution time: 49_097_000 picoseconds. + Weight::from_parts(50_796_000, 0) .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(5)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) fn refund_decision_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `417` + // Measured: `279` // Estimated: `4401` - // Minimum execution time: 31_296_000 picoseconds. - Weight::from_parts(32_221_000, 0) + // Minimum execution time: 23_720_000 picoseconds. + Weight::from_parts(24_327_000, 0) .saturating_add(Weight::from_parts(0, 4401)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -167,10 +174,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) fn refund_submission_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `407` + // Measured: `269` // Estimated: `4401` - // Minimum execution time: 31_209_000 picoseconds. - Weight::from_parts(32_168_000, 0) + // Minimum execution time: 24_089_000 picoseconds. + Weight::from_parts(24_556_000, 0) .saturating_add(Weight::from_parts(0, 4401)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -179,15 +186,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn cancel() -> Weight { // Proof Size summary in bytes: - // Measured: `485` + // Measured: `346` // Estimated: `83866` - // Minimum execution time: 38_887_000 picoseconds. - Weight::from_parts(40_193_000, 0) + // Minimum execution time: 29_022_000 picoseconds. + Weight::from_parts(29_590_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) @@ -195,15 +204,17 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `Referenda::MetadataOf` (r:1 w:0) /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) fn kill() -> Weight { // Proof Size summary in bytes: - // Measured: `726` + // Measured: `587` // Estimated: `83866` - // Minimum execution time: 106_054_000 picoseconds. - Weight::from_parts(108_318_000, 0) + // Minimum execution time: 81_920_000 picoseconds. + Weight::from_parts(84_492_000, 0) .saturating_add(Weight::from_parts(0, 83866)) .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Referenda::TrackQueue` (r:1 w:0) /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) @@ -211,10 +222,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) fn one_fewer_deciding_queue_empty() -> Weight { // Proof Size summary in bytes: - // Measured: `240` + // Measured: `102` // Estimated: `5477` - // Minimum execution time: 9_263_000 picoseconds. - Weight::from_parts(9_763_000, 0) + // Minimum execution time: 8_134_000 picoseconds. + Weight::from_parts(8_574_000, 0) .saturating_add(Weight::from_parts(0, 5477)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -223,36 +234,32 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn one_fewer_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `3254` + // Measured: `3115` // Estimated: `42428` - // Minimum execution time: 50_080_000 picoseconds. - Weight::from_parts(51_858_000, 0) + // Minimum execution time: 39_932_000 picoseconds. + Weight::from_parts(42_086_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Referenda::TrackQueue` (r:1 w:1) /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn one_fewer_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `3254` + // Measured: `3115` // Estimated: `42428` - // Minimum execution time: 53_889_000 picoseconds. - Weight::from_parts(55_959_000, 0) + // Minimum execution time: 42_727_000 picoseconds. + Weight::from_parts(44_280_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) @@ -261,10 +268,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) fn nudge_referendum_requeued_insertion() -> Weight { // Proof Size summary in bytes: - // Measured: `3077` + // Measured: `2939` // Estimated: `5477` - // Minimum execution time: 23_266_000 picoseconds. - Weight::from_parts(24_624_000, 0) + // Minimum execution time: 20_918_000 picoseconds. + Weight::from_parts(22_180_000, 0) .saturating_add(Weight::from_parts(0, 5477)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -275,10 +282,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) fn nudge_referendum_requeued_slide() -> Weight { // Proof Size summary in bytes: - // Measured: `3077` + // Measured: `2939` // Estimated: `5477` - // Minimum execution time: 22_846_000 picoseconds. - Weight::from_parts(24_793_000, 0) + // Minimum execution time: 20_943_000 picoseconds. + Weight::from_parts(21_932_000, 0) .saturating_add(Weight::from_parts(0, 5477)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -291,10 +298,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) fn nudge_referendum_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3081` + // Measured: `2943` // Estimated: `5477` - // Minimum execution time: 28_284_000 picoseconds. - Weight::from_parts(29_940_000, 0) + // Minimum execution time: 25_197_000 picoseconds. + Weight::from_parts(26_083_000, 0) .saturating_add(Weight::from_parts(0, 5477)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -307,10 +314,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::TrackQueue` (`max_values`: None, `max_size`: Some(2012), added: 4487, mode: `MaxEncodedLen`) fn nudge_referendum_not_queued() -> Weight { // Proof Size summary in bytes: - // Measured: `3101` + // Measured: `2963` // Estimated: `5477` - // Minimum execution time: 28_133_000 picoseconds. - Weight::from_parts(29_638_000, 0) + // Minimum execution time: 24_969_000 picoseconds. + Weight::from_parts(26_096_000, 0) .saturating_add(Weight::from_parts(0, 5477)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) @@ -321,10 +328,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_no_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `437` + // Measured: `298` // Estimated: `42428` - // Minimum execution time: 25_710_000 picoseconds. - Weight::from_parts(26_500_000, 0) + // Minimum execution time: 18_050_000 picoseconds. + Weight::from_parts(18_790_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -335,10 +342,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_preparing() -> Weight { // Proof Size summary in bytes: - // Measured: `485` + // Measured: `346` // Estimated: `42428` - // Minimum execution time: 25_935_000 picoseconds. - Weight::from_parts(26_803_000, 0) + // Minimum execution time: 18_357_000 picoseconds. + Weight::from_parts(18_957_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) @@ -347,10 +354,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) fn nudge_referendum_timed_out() -> Weight { // Proof Size summary in bytes: - // Measured: `344` + // Measured: `206` // Estimated: `4401` - // Minimum execution time: 17_390_000 picoseconds. - Weight::from_parts(18_042_000, 0) + // Minimum execution time: 11_479_000 picoseconds. + Weight::from_parts(11_968_000, 0) .saturating_add(Weight::from_parts(0, 4401)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -359,150 +366,136 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Referenda::DecidingCount` (r:1 w:1) /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_begin_deciding_failing() -> Weight { // Proof Size summary in bytes: - // Measured: `485` + // Measured: `346` // Estimated: `42428` - // Minimum execution time: 35_141_000 picoseconds. - Weight::from_parts(36_318_000, 0) + // Minimum execution time: 24_471_000 picoseconds. + Weight::from_parts(25_440_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Referenda::DecidingCount` (r:1 w:1) /// Proof: `Referenda::DecidingCount` (`max_values`: None, `max_size`: Some(14), added: 2489, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_begin_deciding_passing() -> Weight { // Proof Size summary in bytes: - // Measured: `485` + // Measured: `346` // Estimated: `42428` - // Minimum execution time: 37_815_000 picoseconds. - Weight::from_parts(39_243_000, 0) + // Minimum execution time: 26_580_000 picoseconds. + Weight::from_parts(27_570_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_begin_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `538` + // Measured: `399` // Estimated: `42428` - // Minimum execution time: 30_779_000 picoseconds. - Weight::from_parts(31_845_000, 0) + // Minimum execution time: 24_331_000 picoseconds. + Weight::from_parts(25_291_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_end_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `521` + // Measured: `382` // Estimated: `42428` - // Minimum execution time: 31_908_000 picoseconds. - Weight::from_parts(33_253_000, 0) + // Minimum execution time: 24_768_000 picoseconds. + Weight::from_parts(25_746_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_continue_not_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `538` + // Measured: `399` // Estimated: `42428` - // Minimum execution time: 28_951_000 picoseconds. - Weight::from_parts(30_004_000, 0) + // Minimum execution time: 23_171_000 picoseconds. + Weight::from_parts(24_161_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_continue_confirming() -> Weight { // Proof Size summary in bytes: - // Measured: `542` + // Measured: `403` // Estimated: `42428` - // Minimum execution time: 27_750_000 picoseconds. - Weight::from_parts(28_588_000, 0) + // Minimum execution time: 22_263_000 picoseconds. + Weight::from_parts(23_062_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:2 w:2) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Lookup` (r:1 w:1) /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) fn nudge_referendum_approved() -> Weight { // Proof Size summary in bytes: - // Measured: `542` + // Measured: `403` // Estimated: `83866` - // Minimum execution time: 43_950_000 picoseconds. - Weight::from_parts(46_164_000, 0) + // Minimum execution time: 33_710_000 picoseconds. + Weight::from_parts(34_871_000, 0) .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:1) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) - /// Storage: `Balances::InactiveIssuance` (r:1 w:0) - /// Proof: `Balances::InactiveIssuance` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) fn nudge_referendum_rejected() -> Weight { // Proof Size summary in bytes: - // Measured: `538` + // Measured: `399` // Estimated: `42428` - // Minimum execution time: 31_050_000 picoseconds. - Weight::from_parts(32_169_000, 0) + // Minimum execution time: 24_260_000 picoseconds. + Weight::from_parts(25_104_000, 0) .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) /// Proof: `Referenda::ReferendumInfoFor` (`max_values`: None, `max_size`: Some(936), added: 3411, mode: `MaxEncodedLen`) /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:0) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// Storage: `Referenda::MetadataOf` (r:0 w:1) /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn set_some_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `560` + // Measured: `422` // Estimated: `4401` - // Minimum execution time: 21_193_000 picoseconds. - Weight::from_parts(22_116_000, 0) + // Minimum execution time: 19_821_000 picoseconds. + Weight::from_parts(20_641_000, 0) .saturating_add(Weight::from_parts(0, 4401)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Referenda::ReferendumInfoFor` (r:1 w:0) @@ -511,10 +504,10 @@ impl pallet_referenda::WeightInfo for WeightInfo { /// Proof: `Referenda::MetadataOf` (`max_values`: None, `max_size`: Some(52), added: 2527, mode: `MaxEncodedLen`) fn clear_metadata() -> Weight { // Proof Size summary in bytes: - // Measured: `421` + // Measured: `283` // Estimated: `4401` - // Minimum execution time: 18_065_000 picoseconds. - Weight::from_parts(18_781_000, 0) + // Minimum execution time: 13_411_000 picoseconds. + Weight::from_parts(14_070_000, 0) .saturating_add(Weight::from_parts(0, 4401)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_scheduler.rs b/polkadot/runtime/rococo/src/weights/pallet_scheduler.rs index 0f36dbd384df..5f6b41d2b54e 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_scheduler.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_scheduler.rs @@ -16,24 +16,26 @@ //! Autogenerated weights for `pallet_scheduler` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2024-01-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-grjcggob-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-bn-ce5rx-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 +// ./target/production/polkadot // benchmark // pallet +// --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=pallet_scheduler // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_scheduler -// --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ @@ -54,8 +56,8 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `68` // Estimated: `1489` - // Minimum execution time: 2_869_000 picoseconds. - Weight::from_parts(3_109_000, 0) + // Minimum execution time: 3_114_000 picoseconds. + Weight::from_parts(3_245_000, 0) .saturating_add(Weight::from_parts(0, 1489)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -67,11 +69,11 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `115 + s * (177 ±0)` // Estimated: `42428` - // Minimum execution time: 3_326_000 picoseconds. - Weight::from_parts(5_818_563, 0) + // Minimum execution time: 3_430_000 picoseconds. + Weight::from_parts(6_250_920, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 1_261 - .saturating_add(Weight::from_parts(336_446, 0).saturating_mul(s.into())) + // Standard Error: 1_350 + .saturating_add(Weight::from_parts(333_245, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -79,8 +81,8 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 3_007_000 picoseconds. - Weight::from_parts(3_197_000, 0) + // Minimum execution time: 3_166_000 picoseconds. + Weight::from_parts(3_295_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `Preimage::PreimageFor` (r:1 w:1) @@ -94,11 +96,11 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `251 + s * (1 ±0)` // Estimated: `3716 + s * (1 ±0)` - // Minimum execution time: 16_590_000 picoseconds. - Weight::from_parts(16_869_000, 0) + // Minimum execution time: 17_072_000 picoseconds. + Weight::from_parts(17_393_000, 0) .saturating_add(Weight::from_parts(0, 3716)) - // Standard Error: 9 - .saturating_add(Weight::from_parts(1_308, 0).saturating_mul(s.into())) + // Standard Error: 1 + .saturating_add(Weight::from_parts(1_204, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(s.into())) @@ -109,8 +111,8 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_320_000 picoseconds. - Weight::from_parts(4_594_000, 0) + // Minimum execution time: 4_566_000 picoseconds. + Weight::from_parts(4_775_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -118,24 +120,24 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_956_000 picoseconds. - Weight::from_parts(3_216_000, 0) + // Minimum execution time: 3_180_000 picoseconds. + Weight::from_parts(3_339_000, 0) .saturating_add(Weight::from_parts(0, 0)) } fn execute_dispatch_signed() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_824_000 picoseconds. - Weight::from_parts(1_929_000, 0) + // Minimum execution time: 1_656_000 picoseconds. + Weight::from_parts(1_829_000, 0) .saturating_add(Weight::from_parts(0, 0)) } fn execute_dispatch_unsigned() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_749_000 picoseconds. - Weight::from_parts(1_916_000, 0) + // Minimum execution time: 1_628_000 picoseconds. + Weight::from_parts(1_840_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `Scheduler::Agenda` (r:1 w:1) @@ -145,16 +147,18 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `115 + s * (177 ±0)` // Estimated: `42428` - // Minimum execution time: 9_086_000 picoseconds. - Weight::from_parts(11_733_696, 0) + // Minimum execution time: 9_523_000 picoseconds. + Weight::from_parts(12_482_434, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 1_362 - .saturating_add(Weight::from_parts(375_266, 0).saturating_mul(s.into())) + // Standard Error: 1_663 + .saturating_add(Weight::from_parts(370_122, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Lookup` (r:0 w:1) /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 50]`. @@ -162,13 +166,13 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `115 + s * (177 ±0)` // Estimated: `42428` - // Minimum execution time: 12_716_000 picoseconds. - Weight::from_parts(12_529_180, 0) + // Minimum execution time: 14_649_000 picoseconds. + Weight::from_parts(14_705_132, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 867 - .saturating_add(Weight::from_parts(548_188, 0).saturating_mul(s.into())) + // Standard Error: 1_126 + .saturating_add(Weight::from_parts(547_438, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes(3)) } /// Storage: `Scheduler::Lookup` (r:1 w:1) /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) @@ -179,11 +183,11 @@ impl pallet_scheduler::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `292 + s * (185 ±0)` // Estimated: `42428` - // Minimum execution time: 12_053_000 picoseconds. - Weight::from_parts(15_358_056, 0) + // Minimum execution time: 12_335_000 picoseconds. + Weight::from_parts(16_144_217, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 3_176 - .saturating_add(Weight::from_parts(421_589, 0).saturating_mul(s.into())) + // Standard Error: 3_533 + .saturating_add(Weight::from_parts(413_823, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } @@ -191,49 +195,48 @@ impl pallet_scheduler::WeightInfo for WeightInfo { /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 50]`. fn cancel_named(s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `318 + s * (185 ±0)` // Estimated: `42428` - // Minimum execution time: 14_803_000 picoseconds. - Weight::from_parts(15_805_714, 0) + // Minimum execution time: 16_906_000 picoseconds. + Weight::from_parts(17_846_662, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 2_597 - .saturating_add(Weight::from_parts(611_053, 0).saturating_mul(s.into())) + // Standard Error: 2_687 + .saturating_add(Weight::from_parts(613_356, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: `Scheduler::Retries` (r:1 w:2) - /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Agenda` (r:1 w:1) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) - /// Storage: `Scheduler::Lookup` (r:0 w:1) - /// Proof: `Scheduler::Lookup` (`max_values`: None, `max_size`: Some(48), added: 2523, mode: `MaxEncodedLen`) + /// Storage: `Scheduler::Retries` (r:0 w:1) + /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) /// The range of component `s` is `[1, 50]`. fn schedule_retry(s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `196` + // Measured: `155` // Estimated: `42428` - // Minimum execution time: 13_156_000 picoseconds. - Weight::from_parts(13_801_287, 0) + // Minimum execution time: 8_988_000 picoseconds. + Weight::from_parts(9_527_838, 0) .saturating_add(Weight::from_parts(0, 42428)) - // Standard Error: 568 - .saturating_add(Weight::from_parts(35_441, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(4)) + // Standard Error: 523 + .saturating_add(Weight::from_parts(25_453, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Scheduler::Agenda` (r:1 w:0) /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Retries` (r:0 w:1) /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) - /// The range of component `s` is `[1, 50]`. fn set_retry() -> Weight { // Proof Size summary in bytes: - // Measured: `115 + s * (177 ±0)` + // Measured: `8965` // Estimated: `42428` - // Minimum execution time: 7_912_000 picoseconds. - Weight::from_parts(8_081_460, 0) + // Minimum execution time: 23_337_000 picoseconds. + Weight::from_parts(24_255_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -244,13 +247,12 @@ impl pallet_scheduler::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Retries` (r:0 w:1) /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) - /// The range of component `s` is `[1, 50]`. fn set_retry_named() -> Weight { // Proof Size summary in bytes: - // Measured: `324 + s * (185 ±0)` + // Measured: `9643` // Estimated: `42428` - // Minimum execution time: 10_673_000 picoseconds. - Weight::from_parts(12_212_185, 0) + // Minimum execution time: 30_704_000 picoseconds. + Weight::from_parts(31_646_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) @@ -259,13 +261,12 @@ impl pallet_scheduler::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Retries` (r:0 w:1) /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) - /// The range of component `s` is `[1, 50]`. fn cancel_retry() -> Weight { // Proof Size summary in bytes: - // Measured: `115 + s * (177 ±0)` + // Measured: `8977` // Estimated: `42428` - // Minimum execution time: 7_912_000 picoseconds. - Weight::from_parts(8_081_460, 0) + // Minimum execution time: 22_279_000 picoseconds. + Weight::from_parts(23_106_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -276,13 +277,12 @@ impl pallet_scheduler::WeightInfo for WeightInfo { /// Proof: `Scheduler::Agenda` (`max_values`: None, `max_size`: Some(38963), added: 41438, mode: `MaxEncodedLen`) /// Storage: `Scheduler::Retries` (r:0 w:1) /// Proof: `Scheduler::Retries` (`max_values`: None, `max_size`: Some(30), added: 2505, mode: `MaxEncodedLen`) - /// The range of component `s` is `[1, 50]`. fn cancel_retry_named() -> Weight { // Proof Size summary in bytes: - // Measured: `324 + s * (185 ±0)` + // Measured: `9655` // Estimated: `42428` - // Minimum execution time: 10_673_000 picoseconds. - Weight::from_parts(12_212_185, 0) + // Minimum execution time: 29_649_000 picoseconds. + Weight::from_parts(30_472_000, 0) .saturating_add(Weight::from_parts(0, 42428)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_sudo.rs b/polkadot/runtime/rococo/src/weights/pallet_sudo.rs index 694174954fc7..ecc31dc3fa9d 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_sudo.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_sudo.rs @@ -16,24 +16,26 @@ //! Autogenerated weights for `pallet_sudo` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, 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-bn-ce5rx-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 +// ./target/production/polkadot // benchmark // pallet +// --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=pallet_sudo // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_sudo -// --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ @@ -54,8 +56,8 @@ impl pallet_sudo::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `132` // Estimated: `1517` - // Minimum execution time: 8_432_000 picoseconds. - Weight::from_parts(8_757_000, 0) + // Minimum execution time: 8_336_000 picoseconds. + Weight::from_parts(8_569_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) @@ -66,8 +68,8 @@ impl pallet_sudo::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `132` // Estimated: `1517` - // Minimum execution time: 9_167_000 picoseconds. - Weight::from_parts(9_397_000, 0) + // Minimum execution time: 8_858_000 picoseconds. + Weight::from_parts(9_238_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) } @@ -77,8 +79,8 @@ impl pallet_sudo::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `132` // Estimated: `1517` - // Minimum execution time: 9_133_000 picoseconds. - Weight::from_parts(9_573_000, 0) + // Minimum execution time: 8_921_000 picoseconds. + Weight::from_parts(9_324_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) } @@ -88,10 +90,21 @@ impl pallet_sudo::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `132` // Estimated: `1517` - // Minimum execution time: 7_374_000 picoseconds. - Weight::from_parts(7_702_000, 0) + // Minimum execution time: 7_398_000 picoseconds. + Weight::from_parts(7_869_000, 0) .saturating_add(Weight::from_parts(0, 1517)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `Sudo::Key` (r:1 w:0) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + fn check_only_sudo_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `132` + // Estimated: `1517` + // Minimum execution time: 3_146_000 picoseconds. + Weight::from_parts(3_314_000, 0) + .saturating_add(Weight::from_parts(0, 1517)) + .saturating_add(T::DbWeight::get().reads(1)) + } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_timestamp.rs b/polkadot/runtime/rococo/src/weights/pallet_timestamp.rs index 1bb2e227ab7d..7d79621b9e65 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_timestamp.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_timestamp.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_timestamp` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-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-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_timestamp // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,26 +50,26 @@ use core::marker::PhantomData; /// Weight functions for `pallet_timestamp`. pub struct WeightInfo(PhantomData); impl pallet_timestamp::WeightInfo for WeightInfo { - /// Storage: Timestamp Now (r:1 w:1) - /// Proof: Timestamp Now (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Babe CurrentSlot (r:1 w:0) - /// Proof: Babe CurrentSlot (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: `Timestamp::Now` (r:1 w:1) + /// Proof: `Timestamp::Now` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Babe::CurrentSlot` (r:1 w:0) + /// Proof: `Babe::CurrentSlot` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) fn set() -> Weight { // Proof Size summary in bytes: - // Measured: `311` + // Measured: `137` // Estimated: `1493` - // Minimum execution time: 10_103_000 picoseconds. - Weight::from_parts(10_597_000, 0) + // Minimum execution time: 5_596_000 picoseconds. + Weight::from_parts(5_823_000, 0) .saturating_add(Weight::from_parts(0, 1493)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(1)) } fn on_finalize() -> Weight { // Proof Size summary in bytes: - // Measured: `94` + // Measured: `57` // Estimated: `0` - // Minimum execution time: 4_718_000 picoseconds. - Weight::from_parts(4_839_000, 0) + // Minimum execution time: 2_777_000 picoseconds. + Weight::from_parts(2_900_000, 0) .saturating_add(Weight::from_parts(0, 0)) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_transaction_payment.rs b/polkadot/runtime/rococo/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..44dfab289fb2 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,68 @@ +// 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_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot +// benchmark +// pallet +// --chain=rococo-dev +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=pallet_transaction_payment +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --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_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, 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`) + fn charge_transaction_payment() -> Weight { + // Proof Size summary in bytes: + // Measured: `252` + // Estimated: `1737` + // Minimum execution time: 33_070_000 picoseconds. + Weight::from_parts(33_730_000, 0) + .saturating_add(Weight::from_parts(0, 1737)) + .saturating_add(T::DbWeight::get().reads(3)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/pallet_treasury.rs b/polkadot/runtime/rococo/src/weights/pallet_treasury.rs index 06246ada72f1..42d7b2607645 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_treasury.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_treasury.rs @@ -16,25 +16,28 @@ //! Autogenerated weights for `pallet_treasury` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-07-07, STEPS: `50`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `cob`, CPU: `` -//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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/debug/polkadot +// ./target/production/polkadot // benchmark // pallet // --chain=rococo-dev // --steps=50 -// --repeat=2 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_treasury // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --output=./runtime/rococo/src/weights/ -// --header=./file_header.txt +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,18 +50,18 @@ use core::marker::PhantomData; /// Weight functions for `pallet_treasury`. pub struct WeightInfo(PhantomData); impl pallet_treasury::WeightInfo for WeightInfo { - /// Storage: Treasury ProposalCount (r:1 w:1) - /// Proof: Treasury ProposalCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Treasury Approvals (r:1 w:1) - /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - /// Storage: Treasury Proposals (r:0 w:1) - /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) + /// Storage: `Treasury::ProposalCount` (r:1 w:1) + /// Proof: `Treasury::ProposalCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Approvals` (r:1 w:1) + /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Proposals` (r:0 w:1) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) fn spend_local() -> Weight { // Proof Size summary in bytes: - // Measured: `42` + // Measured: `142` // Estimated: `1887` - // Minimum execution time: 177_000_000 picoseconds. - Weight::from_parts(191_000_000, 0) + // Minimum execution time: 9_928_000 picoseconds. + Weight::from_parts(10_560_000, 0) .saturating_add(Weight::from_parts(0, 1887)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(3)) @@ -67,111 +70,103 @@ impl pallet_treasury::WeightInfo for WeightInfo { /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) fn remove_approval() -> Weight { // Proof Size summary in bytes: - // Measured: `127` + // Measured: `227` // Estimated: `1887` - // Minimum execution time: 80_000_000 picoseconds. - Weight::from_parts(82_000_000, 0) + // Minimum execution time: 5_386_000 picoseconds. + Weight::from_parts(5_585_000, 0) .saturating_add(Weight::from_parts(0, 1887)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } - /// Storage: Treasury Deactivated (r:1 w:1) - /// Proof: Treasury Deactivated (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:1) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Treasury Approvals (r:1 w:1) - /// Proof: Treasury Approvals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) - /// Storage: Treasury Proposals (r:99 w:99) - /// Proof: Treasury Proposals (max_values: None, max_size: Some(108), added: 2583, mode: MaxEncodedLen) - /// Storage: System Account (r:199 w:199) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Bounties BountyApprovals (r:1 w:1) - /// Proof: Bounties BountyApprovals (max_values: Some(1), max_size: Some(402), added: 897, mode: MaxEncodedLen) + /// Storage: `Treasury::Deactivated` (r:1 w:1) + /// Proof: `Treasury::Deactivated` (`max_values`: Some(1), `max_size`: Some(16), added: 511, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Approvals` (r:1 w:1) + /// Proof: `Treasury::Approvals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Proposals` (r:99 w:99) + /// Proof: `Treasury::Proposals` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:199 w:199) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Bounties::BountyApprovals` (r:1 w:1) + /// Proof: `Bounties::BountyApprovals` (`max_values`: Some(1), `max_size`: Some(402), added: 897, mode: `MaxEncodedLen`) /// The range of component `p` is `[0, 99]`. fn on_initialize_proposals(p: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `331 + p * (251 ±0)` + // Measured: `431 + p * (251 ±0)` // Estimated: `3593 + p * (5206 ±0)` - // Minimum execution time: 887_000_000 picoseconds. - Weight::from_parts(828_616_021, 0) + // Minimum execution time: 43_737_000 picoseconds. + Weight::from_parts(39_883_021, 0) .saturating_add(Weight::from_parts(0, 3593)) - // Standard Error: 695_351 - .saturating_add(Weight::from_parts(566_114_524, 0).saturating_mul(p.into())) - .saturating_add(T::DbWeight::get().reads(5)) + // Standard Error: 12_917 + .saturating_add(Weight::from_parts(31_796_205, 0).saturating_mul(p.into())) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(p.into()))) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes(4)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(p.into()))) .saturating_add(Weight::from_parts(0, 5206).saturating_mul(p.into())) } - /// Storage: AssetRate ConversionRateToNative (r:1 w:0) - /// Proof: AssetRate ConversionRateToNative (max_values: None, max_size: Some(1237), added: 3712, mode: MaxEncodedLen) - /// Storage: Treasury SpendCount (r:1 w:1) - /// Proof: Treasury SpendCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Treasury Spends (r:0 w:1) - /// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen) + /// Storage: `AssetRate::ConversionRateToNative` (r:1 w:0) + /// Proof: `AssetRate::ConversionRateToNative` (`max_values`: None, `max_size`: Some(1238), added: 3713, mode: `MaxEncodedLen`) + /// Storage: `Treasury::SpendCount` (r:1 w:1) + /// Proof: `Treasury::SpendCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Treasury::Spends` (r:0 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(1853), added: 4328, mode: `MaxEncodedLen`) fn spend() -> Weight { // Proof Size summary in bytes: - // Measured: `114` - // Estimated: `4702` - // Minimum execution time: 208_000_000 picoseconds. - Weight::from_parts(222_000_000, 0) - .saturating_add(Weight::from_parts(0, 4702)) + // Measured: `215` + // Estimated: `4703` + // Minimum execution time: 16_829_000 picoseconds. + Weight::from_parts(17_251_000, 0) + .saturating_add(Weight::from_parts(0, 4703)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Treasury Spends (r:1 w:1) - /// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen) - /// Storage: XcmPallet QueryCounter (r:1 w:1) - /// Proof Skipped: XcmPallet QueryCounter (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DeliveryFeeFactor (r:1 w:0) - /// Proof Skipped: Dmp DeliveryFeeFactor (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet SupportedVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SupportedVersion (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet VersionDiscoveryQueue (r:1 w:1) - /// Proof Skipped: XcmPallet VersionDiscoveryQueue (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: XcmPallet SafeXcmVersion (r:1 w:0) - /// Proof Skipped: XcmPallet SafeXcmVersion (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueues (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueues (max_values: None, max_size: None, mode: Measured) - /// Storage: Dmp DownwardMessageQueueHeads (r:1 w:1) - /// Proof Skipped: Dmp DownwardMessageQueueHeads (max_values: None, max_size: None, mode: Measured) - /// Storage: XcmPallet Queries (r:0 w:1) - /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) + /// Storage: `Treasury::Spends` (r:1 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(1853), added: 4328, mode: `MaxEncodedLen`) + /// Storage: `XcmPallet::QueryCounter` (r:1 w:1) + /// Proof: `XcmPallet::QueryCounter` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::Queries` (r:0 w:1) + /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn payout() -> Weight { // Proof Size summary in bytes: - // Measured: `737` - // Estimated: `5313` - // Minimum execution time: 551_000_000 picoseconds. - Weight::from_parts(569_000_000, 0) - .saturating_add(Weight::from_parts(0, 5313)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(6)) + // Measured: `458` + // Estimated: `5318` + // Minimum execution time: 41_554_000 picoseconds. + Weight::from_parts(42_451_000, 0) + .saturating_add(Weight::from_parts(0, 5318)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: Treasury Spends (r:1 w:1) - /// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen) - /// Storage: XcmPallet Queries (r:1 w:1) - /// Proof Skipped: XcmPallet Queries (max_values: None, max_size: None, mode: Measured) + /// Storage: `Treasury::Spends` (r:1 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(1853), added: 4328, mode: `MaxEncodedLen`) + /// Storage: `XcmPallet::Queries` (r:1 w:1) + /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) fn check_status() -> Weight { // Proof Size summary in bytes: - // Measured: `442` - // Estimated: `5313` - // Minimum execution time: 245_000_000 picoseconds. - Weight::from_parts(281_000_000, 0) - .saturating_add(Weight::from_parts(0, 5313)) + // Measured: `306` + // Estimated: `5318` + // Minimum execution time: 22_546_000 picoseconds. + Weight::from_parts(23_151_000, 0) + .saturating_add(Weight::from_parts(0, 5318)) .saturating_add(T::DbWeight::get().reads(2)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Treasury Spends (r:1 w:1) - /// Proof: Treasury Spends (max_values: None, max_size: Some(1848), added: 4323, mode: MaxEncodedLen) + /// Storage: `Treasury::Spends` (r:1 w:1) + /// Proof: `Treasury::Spends` (`max_values`: None, `max_size`: Some(1853), added: 4328, mode: `MaxEncodedLen`) fn void_spend() -> Weight { // Proof Size summary in bytes: - // Measured: `172` - // Estimated: `5313` - // Minimum execution time: 147_000_000 picoseconds. - Weight::from_parts(160_000_000, 0) - .saturating_add(Weight::from_parts(0, 5313)) + // Measured: `278` + // Estimated: `5318` + // Minimum execution time: 12_169_000 picoseconds. + Weight::from_parts(12_484_000, 0) + .saturating_add(Weight::from_parts(0, 5318)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_utility.rs b/polkadot/runtime/rococo/src/weights/pallet_utility.rs index f50f60eaad7f..6f2a374247f8 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_utility.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_utility.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_utility` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-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-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_utility // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -52,18 +55,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_738_000 picoseconds. - Weight::from_parts(2_704_821, 0) + // Minimum execution time: 4_041_000 picoseconds. + Weight::from_parts(5_685_496, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_999 - .saturating_add(Weight::from_parts(4_627_278, 0).saturating_mul(c.into())) + // Standard Error: 810 + .saturating_add(Weight::from_parts(3_177_197, 0).saturating_mul(c.into())) } fn as_derivative() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 5_294_000 picoseconds. - Weight::from_parts(5_467_000, 0) + // Minimum execution time: 3_667_000 picoseconds. + Weight::from_parts(3_871_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -71,18 +74,18 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_828_000 picoseconds. - Weight::from_parts(4_650_678, 0) + // Minimum execution time: 4_116_000 picoseconds. + Weight::from_parts(6_453_932, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2_789 - .saturating_add(Weight::from_parts(4_885_004, 0).saturating_mul(c.into())) + // Standard Error: 825 + .saturating_add(Weight::from_parts(3_366_112, 0).saturating_mul(c.into())) } fn dispatch_as() -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 9_020_000 picoseconds. - Weight::from_parts(9_205_000, 0) + // Minimum execution time: 5_630_000 picoseconds. + Weight::from_parts(5_956_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// The range of component `c` is `[0, 1000]`. @@ -90,10 +93,10 @@ impl pallet_utility::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_852_000 picoseconds. - Weight::from_parts(20_703_134, 0) + // Minimum execution time: 4_165_000 picoseconds. + Weight::from_parts(5_442_561, 0) .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 3_924 - .saturating_add(Weight::from_parts(4_604_529, 0).saturating_mul(c.into())) + // Standard Error: 460 + .saturating_add(Weight::from_parts(3_173_577, 0).saturating_mul(c.into())) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_vesting.rs b/polkadot/runtime/rococo/src/weights/pallet_vesting.rs index 2596207d5837..c21ab0877742 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_vesting.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_vesting.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `pallet_vesting` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-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-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=pallet_vesting // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -47,143 +50,143 @@ use core::marker::PhantomData; /// Weight functions for `pallet_vesting`. pub struct WeightInfo(PhantomData); impl pallet_vesting::WeightInfo for WeightInfo { - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `277 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 32_820_000 picoseconds. - Weight::from_parts(31_640_992, 0) + // Minimum execution time: 29_288_000 picoseconds. + Weight::from_parts(29_095_507, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 449 - .saturating_add(Weight::from_parts(45_254, 0).saturating_mul(l.into())) - // Standard Error: 800 - .saturating_add(Weight::from_parts(72_178, 0).saturating_mul(s.into())) + // Standard Error: 1_679 + .saturating_add(Weight::from_parts(33_164, 0).saturating_mul(l.into())) + // Standard Error: 2_988 + .saturating_add(Weight::from_parts(67_092, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `277 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 36_054_000 picoseconds. - Weight::from_parts(35_825_428, 0) + // Minimum execution time: 31_003_000 picoseconds. + Weight::from_parts(30_528_438, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 749 - .saturating_add(Weight::from_parts(31_738, 0).saturating_mul(l.into())) - // Standard Error: 1_333 - .saturating_add(Weight::from_parts(40_580, 0).saturating_mul(s.into())) + // Standard Error: 1_586 + .saturating_add(Weight::from_parts(35_429, 0).saturating_mul(l.into())) + // Standard Error: 2_823 + .saturating_add(Weight::from_parts(76_505, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_other_locked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `380 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 35_440_000 picoseconds. - Weight::from_parts(34_652_647, 0) + // Minimum execution time: 31_269_000 picoseconds. + Weight::from_parts(30_661_898, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 517 - .saturating_add(Weight::from_parts(41_942, 0).saturating_mul(l.into())) - // Standard Error: 920 - .saturating_add(Weight::from_parts(66_074, 0).saturating_mul(s.into())) + // Standard Error: 1_394 + .saturating_add(Weight::from_parts(39_300, 0).saturating_mul(l.into())) + // Standard Error: 2_480 + .saturating_add(Weight::from_parts(78_849, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[1, 28]`. fn vest_other_unlocked(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `380 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 38_880_000 picoseconds. - Weight::from_parts(39_625_819, 0) + // Minimum execution time: 33_040_000 picoseconds. + Weight::from_parts(32_469_674, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 1_032 - .saturating_add(Weight::from_parts(29_856, 0).saturating_mul(l.into())) - // Standard Error: 1_837 - .saturating_add(Weight::from_parts(6_210, 0).saturating_mul(s.into())) + // Standard Error: 1_418 + .saturating_add(Weight::from_parts(44_206, 0).saturating_mul(l.into())) + // Standard Error: 2_523 + .saturating_add(Weight::from_parts(74_224, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[0, 27]`. fn vested_transfer(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `451 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 68_294_000 picoseconds. - Weight::from_parts(68_313_394, 0) + // Minimum execution time: 62_032_000 picoseconds. + Weight::from_parts(63_305_621, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 983 - .saturating_add(Weight::from_parts(48_156, 0).saturating_mul(l.into())) - // Standard Error: 1_750 - .saturating_add(Weight::from_parts(87_719, 0).saturating_mul(s.into())) + // Standard Error: 2_277 + .saturating_add(Weight::from_parts(42_767, 0).saturating_mul(l.into())) + // Standard Error: 4_051 + .saturating_add(Weight::from_parts(65_487, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: System Account (r:2 w:2) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:2 w:2) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[0, 27]`. fn force_vested_transfer(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `554 + l * (25 ±0) + s * (36 ±0)` // Estimated: `6196` - // Minimum execution time: 70_529_000 picoseconds. - Weight::from_parts(70_619_962, 0) + // Minimum execution time: 63_303_000 picoseconds. + Weight::from_parts(65_180_847, 0) .saturating_add(Weight::from_parts(0, 6196)) - // Standard Error: 1_259 - .saturating_add(Weight::from_parts(50_685, 0).saturating_mul(l.into())) - // Standard Error: 2_241 - .saturating_add(Weight::from_parts(91_444, 0).saturating_mul(s.into())) + // Standard Error: 2_220 + .saturating_add(Weight::from_parts(28_829, 0).saturating_mul(l.into())) + // Standard Error: 3_951 + .saturating_add(Weight::from_parts(84_970, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) } @@ -192,59 +195,70 @@ impl pallet_vesting::WeightInfo for WeightInfo { /// Storage: `Balances::Locks` (r:1 w:1) /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) /// Storage: `Balances::Freezes` (r:1 w:0) - /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(67), added: 2542, mode: `MaxEncodedLen`) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 28]`. - fn force_remove_vesting_schedule(l: u32, s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `555 + l * (25 ±0) + s * (36 ±0)` - // Estimated: `4764` - // Minimum execution time: 41_497_000 picoseconds. - Weight::from_parts(38_763_834, 4764) - // Standard Error: 2_030 - .saturating_add(Weight::from_parts(99_580, 0).saturating_mul(l.into())) - // Standard Error: 3_750 - .saturating_add(Weight::from_parts(132_188, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(4_u64)) - .saturating_add(T::DbWeight::get().writes(3_u64)) - } fn not_unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `378 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 36_428_000 picoseconds. - Weight::from_parts(35_604_430, 0) + // Minimum execution time: 31_440_000 picoseconds. + Weight::from_parts(30_773_053, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 504 - .saturating_add(Weight::from_parts(43_191, 0).saturating_mul(l.into())) - // Standard Error: 931 - .saturating_add(Weight::from_parts(66_795, 0).saturating_mul(s.into())) + // Standard Error: 1_474 + .saturating_add(Weight::from_parts(43_019, 0).saturating_mul(l.into())) + // Standard Error: 2_723 + .saturating_add(Weight::from_parts(73_360, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// The range of component `l` is `[0, 49]`. /// The range of component `s` is `[2, 28]`. fn unlocking_merge_schedules(l: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `378 + l * (25 ±0) + s * (36 ±0)` // Estimated: `4764` - // Minimum execution time: 40_696_000 picoseconds. - Weight::from_parts(39_741_284, 0) + // Minimum execution time: 34_221_000 picoseconds. + Weight::from_parts(33_201_125, 0) + .saturating_add(Weight::from_parts(0, 4764)) + // Standard Error: 1_751 + .saturating_add(Weight::from_parts(44_088, 0).saturating_mul(l.into())) + // Standard Error: 3_234 + .saturating_add(Weight::from_parts(86_228, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `l` is `[0, 49]`. + /// The range of component `s` is `[2, 28]`. + fn force_remove_vesting_schedule(l: u32, s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `451 + l * (25 ±0) + s * (36 ±0)` + // Estimated: `4764` + // Minimum execution time: 35_553_000 picoseconds. + Weight::from_parts(34_974_083, 0) .saturating_add(Weight::from_parts(0, 4764)) - // Standard Error: 478 - .saturating_add(Weight::from_parts(43_792, 0).saturating_mul(l.into())) - // Standard Error: 883 - .saturating_add(Weight::from_parts(66_540, 0).saturating_mul(s.into())) + // Standard Error: 1_560 + .saturating_add(Weight::from_parts(34_615, 0).saturating_mul(l.into())) + // Standard Error: 2_882 + .saturating_add(Weight::from_parts(83_419, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) } diff --git a/polkadot/runtime/rococo/src/weights/pallet_whitelist.rs b/polkadot/runtime/rococo/src/weights/pallet_whitelist.rs index 7c307deec4c6..ec67268d1449 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_whitelist.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_whitelist.rs @@ -16,26 +16,28 @@ //! Autogenerated weights for `pallet_whitelist` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-08-25, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-aahe6cbd-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-bn-ce5rx-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 +// ./target/production/polkadot // benchmark // pallet +// --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=pallet_whitelist // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json -// --pallet=pallet_whitelist -// --chain=rococo-dev -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/ #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -50,67 +52,75 @@ pub struct WeightInfo(PhantomData); impl pallet_whitelist::WeightInfo for WeightInfo { /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:1) + /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn whitelist_call() -> Weight { // Proof Size summary in bytes: // Measured: `223` // Estimated: `3556` - // Minimum execution time: 20_035_000 picoseconds. - Weight::from_parts(20_452_000, 0) + // Minimum execution time: 16_686_000 picoseconds. + Weight::from_parts(17_042_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:1) + /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) fn remove_whitelisted_call() -> Weight { // Proof Size summary in bytes: // Measured: `352` // Estimated: `3556` - // Minimum execution time: 20_247_000 picoseconds. - Weight::from_parts(20_808_000, 0) + // Minimum execution time: 18_250_000 picoseconds. + Weight::from_parts(19_026_000, 0) .saturating_add(Weight::from_parts(0, 3556)) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) /// Storage: `Preimage::PreimageFor` (r:1 w:1) /// Proof: `Preimage::PreimageFor` (`max_values`: None, `max_size`: Some(4194344), added: 4196819, mode: `Measured`) - /// Storage: `Preimage::StatusFor` (r:1 w:1) + /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 4194294]`. fn dispatch_whitelisted_call(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `428 + n * (1 ±0)` // Estimated: `3892 + n * (1 ±0)` - // Minimum execution time: 32_633_000 picoseconds. - Weight::from_parts(32_855_000, 0) + // Minimum execution time: 28_741_000 picoseconds. + Weight::from_parts(29_024_000, 0) .saturating_add(Weight::from_parts(0, 3892)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_223, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(3)) + // Standard Error: 7 + .saturating_add(Weight::from_parts(1_305, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(3)) .saturating_add(Weight::from_parts(0, 1).saturating_mul(n.into())) } /// Storage: `Whitelist::WhitelistedCall` (r:1 w:1) /// Proof: `Whitelist::WhitelistedCall` (`max_values`: None, `max_size`: Some(40), added: 2515, mode: `MaxEncodedLen`) - /// Storage: `Preimage::StatusFor` (r:1 w:1) + /// Storage: `Preimage::StatusFor` (r:1 w:0) /// Proof: `Preimage::StatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) + /// Storage: `Preimage::RequestStatusFor` (r:1 w:1) + /// Proof: `Preimage::RequestStatusFor` (`max_values`: None, `max_size`: Some(91), added: 2566, mode: `MaxEncodedLen`) /// The range of component `n` is `[1, 10000]`. fn dispatch_whitelisted_call_with_preimage(n: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `352` // Estimated: `3556` - // Minimum execution time: 23_833_000 picoseconds. - Weight::from_parts(24_698_994, 0) + // Minimum execution time: 21_670_000 picoseconds. + Weight::from_parts(22_561_364, 0) .saturating_add(Weight::from_parts(0, 3556)) // Standard Error: 4 - .saturating_add(Weight::from_parts(1_454, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(Weight::from_parts(1_468, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(2)) } } diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs index 5544ca44658c..d5cf33515e6b 100644 --- a/polkadot/runtime/rococo/src/weights/pallet_xcm.rs +++ b/polkadot/runtime/rococo/src/weights/pallet_xcm.rs @@ -17,23 +17,25 @@ //! Autogenerated weights for `pallet_xcm` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-20, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// target/production/polkadot +// ./target/production/polkadot // benchmark // pallet +// --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=pallet_xcm // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=pallet_xcm -// --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ @@ -60,8 +62,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 25_043_000 picoseconds. - Weight::from_parts(25_682_000, 0) + // Minimum execution time: 25_521_000 picoseconds. + Weight::from_parts(25_922_000, 0) .saturating_add(Weight::from_parts(0, 3645)) .saturating_add(T::DbWeight::get().reads(4)) .saturating_add(T::DbWeight::get().writes(2)) @@ -80,8 +82,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 107_570_000 picoseconds. - Weight::from_parts(109_878_000, 0) + // Minimum execution time: 112_185_000 picoseconds. + Weight::from_parts(115_991_000, 0) .saturating_add(Weight::from_parts(0, 3645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) @@ -100,8 +102,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `232` // Estimated: `3697` - // Minimum execution time: 106_341_000 picoseconds. - Weight::from_parts(109_135_000, 0) + // Minimum execution time: 108_693_000 picoseconds. + Weight::from_parts(111_853_000, 0) .saturating_add(Weight::from_parts(0, 3697)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) @@ -120,8 +122,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 108_372_000 picoseconds. - Weight::from_parts(112_890_000, 0) + // Minimum execution time: 113_040_000 picoseconds. + Weight::from_parts(115_635_000, 0) .saturating_add(Weight::from_parts(0, 3645)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) @@ -130,8 +132,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 6_957_000 picoseconds. - Weight::from_parts(7_417_000, 0) + // Minimum execution time: 6_979_000 picoseconds. + Weight::from_parts(7_342_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `XcmPallet::SupportedVersion` (r:0 w:1) @@ -140,8 +142,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_053_000 picoseconds. - Weight::from_parts(7_462_000, 0) + // Minimum execution time: 7_144_000 picoseconds. + Weight::from_parts(7_297_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -149,8 +151,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_918_000 picoseconds. - Weight::from_parts(2_037_000, 0) + // Minimum execution time: 1_886_000 picoseconds. + Weight::from_parts(1_995_000, 0) .saturating_add(Weight::from_parts(0, 0)) } /// Storage: `XcmPallet::VersionNotifiers` (r:1 w:1) @@ -171,8 +173,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `180` // Estimated: `3645` - // Minimum execution time: 30_417_000 picoseconds. - Weight::from_parts(31_191_000, 0) + // Minimum execution time: 31_238_000 picoseconds. + Weight::from_parts(31_955_000, 0) .saturating_add(Weight::from_parts(0, 3645)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(5)) @@ -193,8 +195,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `360` // Estimated: `3825` - // Minimum execution time: 36_666_000 picoseconds. - Weight::from_parts(37_779_000, 0) + // Minimum execution time: 37_237_000 picoseconds. + Weight::from_parts(38_569_000, 0) .saturating_add(Weight::from_parts(0, 3825)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(4)) @@ -205,8 +207,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 1_869_000 picoseconds. - Weight::from_parts(2_003_000, 0) + // Minimum execution time: 1_884_000 picoseconds. + Weight::from_parts(2_028_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -216,8 +218,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `22` // Estimated: `13387` - // Minimum execution time: 16_188_000 picoseconds. - Weight::from_parts(16_435_000, 0) + // Minimum execution time: 16_048_000 picoseconds. + Weight::from_parts(16_617_000, 0) .saturating_add(Weight::from_parts(0, 13387)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -228,8 +230,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `26` // Estimated: `13391` - // Minimum execution time: 16_431_000 picoseconds. - Weight::from_parts(16_935_000, 0) + // Minimum execution time: 16_073_000 picoseconds. + Weight::from_parts(16_672_000, 0) .saturating_add(Weight::from_parts(0, 13391)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -240,8 +242,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `40` // Estimated: `15880` - // Minimum execution time: 18_460_000 picoseconds. - Weight::from_parts(18_885_000, 0) + // Minimum execution time: 18_422_000 picoseconds. + Weight::from_parts(18_900_000, 0) .saturating_add(Weight::from_parts(0, 15880)) .saturating_add(T::DbWeight::get().reads(6)) } @@ -259,8 +261,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `216` // Estimated: `6156` - // Minimum execution time: 29_623_000 picoseconds. - Weight::from_parts(30_661_000, 0) + // Minimum execution time: 30_373_000 picoseconds. + Weight::from_parts(30_972_000, 0) .saturating_add(Weight::from_parts(0, 6156)) .saturating_add(T::DbWeight::get().reads(6)) .saturating_add(T::DbWeight::get().writes(3)) @@ -271,8 +273,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `69` // Estimated: `10959` - // Minimum execution time: 12_043_000 picoseconds. - Weight::from_parts(12_360_000, 0) + // Minimum execution time: 11_863_000 picoseconds. + Weight::from_parts(12_270_000, 0) .saturating_add(Weight::from_parts(0, 10959)) .saturating_add(T::DbWeight::get().reads(4)) } @@ -282,8 +284,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `33` // Estimated: `13398` - // Minimum execution time: 16_511_000 picoseconds. - Weight::from_parts(17_011_000, 0) + // Minimum execution time: 16_733_000 picoseconds. + Weight::from_parts(17_094_000, 0) .saturating_add(Weight::from_parts(0, 13398)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(2)) @@ -302,8 +304,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `216` // Estimated: `13581` - // Minimum execution time: 39_041_000 picoseconds. - Weight::from_parts(39_883_000, 0) + // Minimum execution time: 39_236_000 picoseconds. + Weight::from_parts(40_587_000, 0) .saturating_add(Weight::from_parts(0, 13581)) .saturating_add(T::DbWeight::get().reads(9)) .saturating_add(T::DbWeight::get().writes(4)) @@ -316,8 +318,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `0` // Estimated: `1485` - // Minimum execution time: 2_030_000 picoseconds. - Weight::from_parts(2_150_000, 0) + // Minimum execution time: 2_145_000 picoseconds. + Weight::from_parts(2_255_000, 0) .saturating_add(Weight::from_parts(0, 1485)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(2)) @@ -328,8 +330,8 @@ impl pallet_xcm::WeightInfo for WeightInfo { // Proof Size summary in bytes: // Measured: `7576` // Estimated: `11041` - // Minimum execution time: 22_615_000 picoseconds. - Weight::from_parts(23_008_000, 0) + // Minimum execution time: 22_518_000 picoseconds. + Weight::from_parts(22_926_000, 0) .saturating_add(Weight::from_parts(0, 11041)) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_fungible.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_fungible.rs new file mode 100644 index 000000000000..dc5e5d8ca4b1 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_fungible.rs @@ -0,0 +1,191 @@ +// 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_xcm_benchmarks::fungible` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot +// benchmark +// pallet +// --chain=rococo-dev +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=pallet_xcm_benchmarks::fungible +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_fungible.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 `pallet_xcm_benchmarks::fungible`. +pub struct WeightInfo(PhantomData); +impl pallet_xcm_benchmarks::fungible::WeightInfo for WeightInfo { + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn withdraw_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `101` + // Estimated: `3593` + // Minimum execution time: 27_223_000 picoseconds. + Weight::from_parts(27_947_000, 0) + .saturating_add(Weight::from_parts(0, 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`) + fn transfer_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `101` + // Estimated: `6196` + // Minimum execution time: 36_502_000 picoseconds. + Weight::from_parts(37_023_000, 0) + .saturating_add(Weight::from_parts(0, 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: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn transfer_reserve_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `6196` + // Minimum execution time: 85_152_000 picoseconds. + Weight::from_parts(86_442_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(T::DbWeight::get().reads(6)) + .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`) + 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) + .saturating_add(Weight::from_parts(0, 0)) + } + /// 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`) + fn initiate_reserve_withdraw() -> Weight { + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `3746` + // Minimum execution time: 56_571_000 picoseconds. + Weight::from_parts(58_163_000, 0) + .saturating_add(Weight::from_parts(0, 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`) + fn receive_teleported_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `103` + // Estimated: `3593` + // Minimum execution time: 27_411_000 picoseconds. + Weight::from_parts(27_953_000, 0) + .saturating_add(Weight::from_parts(0, 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`) + fn deposit_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3593` + // Minimum execution time: 20_776_000 picoseconds. + Weight::from_parts(21_145_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// 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`) + fn deposit_reserve_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `180` + // Estimated: `3645` + // Minimum execution time: 51_738_000 picoseconds. + Weight::from_parts(53_251_000, 0) + .saturating_add(Weight::from_parts(0, 3645)) + .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`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn initiate_teleport() -> Weight { + // Proof Size summary in bytes: + // Measured: `180` + // Estimated: `3645` + // Minimum execution time: 39_333_000 picoseconds. + Weight::from_parts(40_515_000, 0) + .saturating_add(Weight::from_parts(0, 3645)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs b/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs new file mode 100644 index 000000000000..b62f36172baf --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.rs @@ -0,0 +1,347 @@ +// 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_xcm_benchmarks::generic` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot +// benchmark +// pallet +// --chain=rococo-dev +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=pallet_xcm_benchmarks::generic +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/pallet_xcm_benchmarks_generic.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 `pallet_xcm_benchmarks::generic`. +pub struct WeightInfo(PhantomData); +impl pallet_xcm_benchmarks::generic::WeightInfo for WeightInfo { + /// 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`) + fn report_holding() -> Weight { + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `3746` + // Minimum execution time: 55_210_000 picoseconds. + Weight::from_parts(56_613_000, 0) + .saturating_add(Weight::from_parts(0, 3746)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + fn buy_execution() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_246_000 picoseconds. + Weight::from_parts(1_339_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `XcmPallet::Queries` (r:1 w:0) + /// Proof: `XcmPallet::Queries` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn query_response() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `3465` + // Minimum execution time: 5_377_000 picoseconds. + Weight::from_parts(5_549_000, 0) + .saturating_add(Weight::from_parts(0, 3465)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn transact() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_008_000 picoseconds. + Weight::from_parts(7_361_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn refund_surplus() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_700_000 picoseconds. + Weight::from_parts(1_848_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn set_error_handler() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_198_000 picoseconds. + Weight::from_parts(1_265_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn set_appendix() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_197_000 picoseconds. + Weight::from_parts(1_267_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn clear_error() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_193_000 picoseconds. + Weight::from_parts(1_258_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn descend_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_268_000 picoseconds. + Weight::from_parts(1_342_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn clear_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_173_000 picoseconds. + Weight::from_parts(1_248_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// 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`) + fn report_error() -> Weight { + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `3746` + // Minimum execution time: 53_715_000 picoseconds. + Weight::from_parts(54_860_000, 0) + .saturating_add(Weight::from_parts(0, 3746)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `XcmPallet::AssetTraps` (r:1 w:1) + /// Proof: `XcmPallet::AssetTraps` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn claim_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `23` + // Estimated: `3488` + // Minimum execution time: 8_621_000 picoseconds. + Weight::from_parts(8_903_000, 0) + .saturating_add(Weight::from_parts(0, 3488)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn trap() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_211_000 picoseconds. + Weight::from_parts(1_281_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `XcmPallet::VersionNotifyTargets` (r:1 w:1) + /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:0) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `XcmPallet::SupportedVersion` (r:1 w:0) + /// Proof: `XcmPallet::SupportedVersion` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueueHeads` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueueHeads` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn subscribe_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `180` + // Estimated: `3645` + // Minimum execution time: 26_448_000 picoseconds. + Weight::from_parts(27_057_000, 0) + .saturating_add(Weight::from_parts(0, 3645)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `XcmPallet::VersionNotifyTargets` (r:0 w:1) + /// Proof: `XcmPallet::VersionNotifyTargets` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn unsubscribe_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 3_498_000 picoseconds. + Weight::from_parts(3_614_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn burn_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_575_000 picoseconds. + Weight::from_parts(1_698_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn expect_asset() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_334_000 picoseconds. + Weight::from_parts(1_435_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn expect_origin() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_244_000 picoseconds. + Weight::from_parts(1_337_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn expect_error() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_244_000 picoseconds. + Weight::from_parts(1_331_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn expect_transact_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_407_000 picoseconds. + Weight::from_parts(1_522_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// 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`) + fn query_pallet() -> Weight { + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `3746` + // Minimum execution time: 62_963_000 picoseconds. + Weight::from_parts(64_556_000, 0) + .saturating_add(Weight::from_parts(0, 3746)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + fn expect_pallet() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_458_000 picoseconds. + Weight::from_parts(8_741_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// 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`) + fn report_transact_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `281` + // Estimated: `3746` + // Minimum execution time: 54_068_000 picoseconds. + Weight::from_parts(55_665_000, 0) + .saturating_add(Weight::from_parts(0, 3746)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + fn clear_transact_status() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_290_000 picoseconds. + Weight::from_parts(1_348_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn set_topic() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_189_000 picoseconds. + Weight::from_parts(1_268_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn clear_topic() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_197_000 picoseconds. + Weight::from_parts(1_276_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn set_fees_mode() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_197_000 picoseconds. + Weight::from_parts(1_253_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn unpaid_execution() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 1_250_000 picoseconds. + Weight::from_parts(1_354_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/runtime_common_assigned_slots.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_assigned_slots.rs similarity index 83% rename from polkadot/runtime/rococo/src/weights/runtime_common_assigned_slots.rs rename to polkadot/runtime/rococo/src/weights/polkadot_runtime_common_assigned_slots.rs index 2aaf282c59d5..fd13c2ac9461 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_common_assigned_slots.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_assigned_slots.rs @@ -16,26 +16,28 @@ //! Autogenerated weights for `runtime_common::assigned_slots` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-08-07, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-ynta1nyy-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: ``, WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 +// ./target/production/polkadot // benchmark // pallet +// --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=runtime_common::assigned_slots // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot/.git/.artifacts/bench.json -// --pallet=runtime_common::assigned_slots -// --chain=rococo-dev -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/ +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_common_assigned_slots.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -68,15 +70,15 @@ impl polkadot_runtime_common::assigned_slots::WeightInf /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) fn assign_perm_parachain_slot() -> Weight { // Proof Size summary in bytes: - // Measured: `673` - // Estimated: `4138` - // Minimum execution time: 84_646_000 picoseconds. - Weight::from_parts(91_791_000, 0) - .saturating_add(Weight::from_parts(0, 4138)) + // Measured: `730` + // Estimated: `4195` + // Minimum execution time: 71_337_000 picoseconds. + Weight::from_parts(80_807_000, 0) + .saturating_add(Weight::from_parts(0, 4195)) .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().writes(5)) } - /// Storage: `Registrar::Paras` (r:1 w:1) + /// Storage: `Registrar::Paras` (r:1 w:0) /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::ParaLifecycles` (r:1 w:1) /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) @@ -98,13 +100,13 @@ impl polkadot_runtime_common::assigned_slots::WeightInf /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) fn assign_temp_parachain_slot() -> Weight { // Proof Size summary in bytes: - // Measured: `673` - // Estimated: `4138` - // Minimum execution time: 68_091_000 picoseconds. - Weight::from_parts(77_310_000, 0) - .saturating_add(Weight::from_parts(0, 4138)) + // Measured: `730` + // Estimated: `4195` + // Minimum execution time: 60_188_000 picoseconds. + Weight::from_parts(63_932_000, 0) + .saturating_add(Weight::from_parts(0, 4195)) .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(7)) + .saturating_add(T::DbWeight::get().writes(6)) } /// Storage: `AssignedSlots::PermanentSlots` (r:1 w:0) /// Proof: `AssignedSlots::PermanentSlots` (`max_values`: None, `max_size`: Some(20), added: 2495, mode: `MaxEncodedLen`) @@ -118,11 +120,11 @@ impl polkadot_runtime_common::assigned_slots::WeightInf /// Proof: `AssignedSlots::TemporarySlotCount` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) fn unassign_parachain_slot() -> Weight { // Proof Size summary in bytes: - // Measured: `823` - // Estimated: `4288` - // Minimum execution time: 38_081_000 picoseconds. - Weight::from_parts(40_987_000, 0) - .saturating_add(Weight::from_parts(0, 4288)) + // Measured: `856` + // Estimated: `4321` + // Minimum execution time: 35_764_000 picoseconds. + Weight::from_parts(38_355_000, 0) + .saturating_add(Weight::from_parts(0, 4321)) .saturating_add(T::DbWeight::get().reads(5)) .saturating_add(T::DbWeight::get().writes(3)) } @@ -132,8 +134,8 @@ impl polkadot_runtime_common::assigned_slots::WeightInf // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_182_000 picoseconds. - Weight::from_parts(7_437_000, 0) + // Minimum execution time: 4_634_000 picoseconds. + Weight::from_parts(4_852_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } @@ -143,8 +145,8 @@ impl polkadot_runtime_common::assigned_slots::WeightInf // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 7_153_000 picoseconds. - Weight::from_parts(7_456_000, 0) + // Minimum execution time: 4_563_000 picoseconds. + Weight::from_parts(4_829_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_auctions.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_auctions.rs new file mode 100644 index 000000000000..acf2da8cab96 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_auctions.rs @@ -0,0 +1,141 @@ +// 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 `runtime_common::auctions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot +// benchmark +// pallet +// --chain=rococo-dev +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=runtime_common::auctions +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_common_auctions.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 `runtime_common::auctions`. +pub struct WeightInfo(PhantomData); +impl polkadot_runtime_common::auctions::WeightInfo for WeightInfo { + /// Storage: Auctions AuctionInfo (r:1 w:1) + /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) + /// Storage: Auctions AuctionCounter (r:1 w:1) + /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn new_auction() -> Weight { + // Proof Size summary in bytes: + // Measured: `4` + // Estimated: `1493` + // Minimum execution time: 7_307_000 picoseconds. + Weight::from_parts(7_680_000, 0) + .saturating_add(Weight::from_parts(0, 1493)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Paras::ParaLifecycles` (r:1 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Auctions::AuctionCounter` (r:1 w:0) + /// Proof: `Auctions::AuctionCounter` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Auctions::AuctionInfo` (r:1 w:0) + /// Proof: `Auctions::AuctionInfo` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Slots::Leases` (r:1 w:0) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Auctions::Winning` (r:1 w:1) + /// Proof: `Auctions::Winning` (`max_values`: None, `max_size`: Some(1920), added: 4395, mode: `MaxEncodedLen`) + /// Storage: `Auctions::ReservedAmounts` (r:2 w:2) + /// Proof: `Auctions::ReservedAmounts` (`max_values`: None, `max_size`: Some(60), added: 2535, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn bid() -> Weight { + // Proof Size summary in bytes: + // Measured: `761` + // Estimated: `6060` + // Minimum execution time: 75_448_000 picoseconds. + Weight::from_parts(78_716_000, 0) + .saturating_add(Weight::from_parts(0, 6060)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Auctions::AuctionInfo` (r:1 w:1) + /// Proof: `Auctions::AuctionInfo` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Babe::NextRandomness` (r:1 w:0) + /// Proof: `Babe::NextRandomness` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `Babe::EpochStart` (r:1 w:0) + /// Proof: `Babe::EpochStart` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Auctions::AuctionCounter` (r:1 w:0) + /// Proof: `Auctions::AuctionCounter` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Auctions::Winning` (r:3600 w:3600) + /// Proof: `Auctions::Winning` (`max_values`: None, `max_size`: Some(1920), added: 4395, mode: `MaxEncodedLen`) + /// Storage: `Auctions::ReservedAmounts` (r:37 w:36) + /// Proof: `Auctions::ReservedAmounts` (`max_values`: None, `max_size`: Some(60), added: 2535, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:36 w:36) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Slots::Leases` (r:2 w:2) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:1) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn on_initialize() -> Weight { + // Proof Size summary in bytes: + // Measured: `6947017` + // Estimated: `15822990` + // Minimum execution time: 7_120_207_000 picoseconds. + Weight::from_parts(7_273_496_000, 0) + .saturating_add(Weight::from_parts(0, 15822990)) + .saturating_add(T::DbWeight::get().reads(3682)) + .saturating_add(T::DbWeight::get().writes(3677)) + } + /// Storage: `Auctions::ReservedAmounts` (r:37 w:36) + /// Proof: `Auctions::ReservedAmounts` (`max_values`: None, `max_size`: Some(60), added: 2535, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:36 w:36) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Auctions::Winning` (r:3600 w:3600) + /// Proof: `Auctions::Winning` (`max_values`: None, `max_size`: Some(1920), added: 4395, mode: `MaxEncodedLen`) + /// Storage: `Auctions::AuctionInfo` (r:0 w:1) + /// Proof: `Auctions::AuctionInfo` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + fn cancel_auction() -> Weight { + // Proof Size summary in bytes: + // Measured: `177732` + // Estimated: `15822990` + // Minimum execution time: 5_536_281_000 picoseconds. + Weight::from_parts(5_675_163_000, 0) + .saturating_add(Weight::from_parts(0, 15822990)) + .saturating_add(T::DbWeight::get().reads(3673)) + .saturating_add(T::DbWeight::get().writes(3673)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_claims.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_claims.rs new file mode 100644 index 000000000000..3871310678ef --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_claims.rs @@ -0,0 +1,182 @@ +// 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 `runtime_common::claims` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot +// benchmark +// pallet +// --chain=rococo-dev +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=runtime_common::claims +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_common_claims.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 `runtime_common::claims`. +pub struct WeightInfo(PhantomData); +impl polkadot_runtime_common::claims::WeightInfo for WeightInfo { + /// Storage: Claims Claims (r:1 w:1) + /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) + /// Storage: Claims Signing (r:1 w:1) + /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) + /// Storage: Claims Total (r:1 w:1) + /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Claims Vesting (r:1 w:1) + /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) + /// Storage: Vesting Vesting (r:1 w:1) + /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) + /// Storage: System Account (r:1 w:0) + /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) + /// Storage: Balances Locks (r:1 w:1) + /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) + /// Storage: Balances Freezes (r:1 w:0) + /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) + fn claim() -> Weight { + // Proof Size summary in bytes: + // Measured: `558` + // Estimated: `4764` + // Minimum execution time: 181_028_000 picoseconds. + Weight::from_parts(194_590_000, 0) + .saturating_add(Weight::from_parts(0, 4764)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `Claims::Total` (r:1 w:1) + /// Proof: `Claims::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Vesting` (r:0 w:1) + /// Proof: `Claims::Vesting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Claims` (r:0 w:1) + /// Proof: `Claims::Claims` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Signing` (r:0 w:1) + /// Proof: `Claims::Signing` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn mint_claim() -> Weight { + // Proof Size summary in bytes: + // Measured: `216` + // Estimated: `1701` + // Minimum execution time: 11_224_000 picoseconds. + Weight::from_parts(13_342_000, 0) + .saturating_add(Weight::from_parts(0, 1701)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Claims::Claims` (r:1 w:1) + /// Proof: `Claims::Claims` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Signing` (r:1 w:1) + /// Proof: `Claims::Signing` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Total` (r:1 w:1) + /// Proof: `Claims::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Vesting` (r:1 w:1) + /// Proof: `Claims::Vesting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + fn claim_attest() -> Weight { + // Proof Size summary in bytes: + // Measured: `558` + // Estimated: `4764` + // Minimum execution time: 187_964_000 picoseconds. + Weight::from_parts(202_553_000, 0) + .saturating_add(Weight::from_parts(0, 4764)) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `Claims::Preclaims` (r:1 w:1) + /// Proof: `Claims::Preclaims` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Signing` (r:1 w:1) + /// Proof: `Claims::Signing` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Claims` (r:1 w:1) + /// Proof: `Claims::Claims` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Total` (r:1 w:1) + /// Proof: `Claims::Total` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Vesting` (r:1 w:1) + /// Proof: `Claims::Vesting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Vesting::Vesting` (r:1 w:1) + /// Proof: `Vesting::Vesting` (`max_values`: None, `max_size`: Some(1057), added: 3532, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:0) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Balances::Locks` (r:1 w:1) + /// Proof: `Balances::Locks` (`max_values`: None, `max_size`: Some(1299), added: 3774, mode: `MaxEncodedLen`) + /// Storage: `Balances::Freezes` (r:1 w:0) + /// Proof: `Balances::Freezes` (`max_values`: None, `max_size`: Some(65), added: 2540, mode: `MaxEncodedLen`) + fn attest() -> Weight { + // Proof Size summary in bytes: + // Measured: `632` + // Estimated: `4764` + // Minimum execution time: 78_210_000 picoseconds. + Weight::from_parts(84_581_000, 0) + .saturating_add(Weight::from_parts(0, 4764)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(7)) + } + /// Storage: `Claims::Claims` (r:1 w:2) + /// Proof: `Claims::Claims` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Vesting` (r:1 w:2) + /// Proof: `Claims::Vesting` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Signing` (r:1 w:2) + /// Proof: `Claims::Signing` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Preclaims` (r:1 w:1) + /// Proof: `Claims::Preclaims` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn move_claim() -> Weight { + // Proof Size summary in bytes: + // Measured: `440` + // Estimated: `3905` + // Minimum execution time: 33_940_000 picoseconds. + Weight::from_parts(48_438_000, 0) + .saturating_add(Weight::from_parts(0, 3905)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(7)) + } + /// Storage: `Claims::Preclaims` (r:1 w:0) + /// Proof: `Claims::Preclaims` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Claims::Signing` (r:1 w:0) + /// Proof: `Claims::Signing` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn prevalidate_attests() -> Weight { + // Proof Size summary in bytes: + // Measured: `296` + // Estimated: `3761` + // Minimum execution time: 9_025_000 picoseconds. + Weight::from_parts(10_563_000, 0) + .saturating_add(Weight::from_parts(0, 3761)) + .saturating_add(T::DbWeight::get().reads(2)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_crowdloan.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_crowdloan.rs new file mode 100644 index 000000000000..2a01de67acc5 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_crowdloan.rs @@ -0,0 +1,221 @@ +// 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 `runtime_common::crowdloan` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot +// benchmark +// pallet +// --chain=rococo-dev +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=runtime_common::crowdloan +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_common_crowdloan.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 `runtime_common::crowdloan`. +pub struct WeightInfo(PhantomData); +impl polkadot_runtime_common::crowdloan::WeightInfo for WeightInfo { + /// Storage: Crowdloan Funds (r:1 w:1) + /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) + /// Storage: Registrar Paras (r:1 w:1) + /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras ParaLifecycles (r:1 w:0) + /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) + /// Storage: Crowdloan NextFundIndex (r:1 w:1) + /// Proof Skipped: Crowdloan NextFundIndex (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) + fn create() -> Weight { + // Proof Size summary in bytes: + // Measured: `438` + // Estimated: `3903` + // Minimum execution time: 46_095_000 picoseconds. + Weight::from_parts(48_111_000, 0) + .saturating_add(Weight::from_parts(0, 3903)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Crowdloan::Funds` (r:1 w:1) + /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Slots::Leases` (r:1 w:0) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Auctions::AuctionInfo` (r:1 w:0) + /// Proof: `Auctions::AuctionInfo` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// Storage: `Crowdloan::EndingsCount` (r:1 w:0) + /// Proof: `Crowdloan::EndingsCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Crowdloan::NewRaise` (r:1 w:1) + /// Proof: `Crowdloan::NewRaise` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: UNKNOWN KEY `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) + fn contribute() -> Weight { + // Proof Size summary in bytes: + // Measured: `563` + // Estimated: `4028` + // Minimum execution time: 133_059_000 picoseconds. + Weight::from_parts(136_515_000, 0) + .saturating_add(Weight::from_parts(0, 4028)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Crowdloan::Funds` (r:1 w:1) + /// Proof: `Crowdloan::Funds` (`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: UNKNOWN KEY `0xc85982571aa615c788ef9b2c16f54f25773fd439e8ee1ed2aa3ae43d48e880f0` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xc85982571aa615c788ef9b2c16f54f25773fd439e8ee1ed2aa3ae43d48e880f0` (r:1 w:1) + fn withdraw() -> Weight { + // Proof Size summary in bytes: + // Measured: `687` + // Estimated: `6196` + // Minimum execution time: 71_733_000 picoseconds. + Weight::from_parts(74_034_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Skipped::Metadata` (r:0 w:0) + /// Proof: `Skipped::Metadata` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `k` is `[0, 1000]`. + fn refund(k: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `125 + k * (189 ±0)` + // Estimated: `138 + k * (189 ±0)` + // Minimum execution time: 46_016_000 picoseconds. + Weight::from_parts(48_260_000, 0) + .saturating_add(Weight::from_parts(0, 138)) + // Standard Error: 21_140 + .saturating_add(Weight::from_parts(39_141_925, 0).saturating_mul(k.into())) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(k.into()))) + .saturating_add(T::DbWeight::get().writes(2)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(k.into()))) + .saturating_add(Weight::from_parts(0, 189).saturating_mul(k.into())) + } + /// Storage: `Crowdloan::Funds` (r:1 w:1) + /// Proof: `Crowdloan::Funds` (`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`) + fn dissolve() -> Weight { + // Proof Size summary in bytes: + // Measured: `514` + // Estimated: `6196` + // Minimum execution time: 44_724_000 picoseconds. + Weight::from_parts(47_931_000, 0) + .saturating_add(Weight::from_parts(0, 6196)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Crowdloan::Funds` (r:1 w:1) + /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn edit() -> Weight { + // Proof Size summary in bytes: + // Measured: `234` + // Estimated: `3699` + // Minimum execution time: 19_512_000 picoseconds. + Weight::from_parts(21_129_000, 0) + .saturating_add(Weight::from_parts(0, 3699)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Crowdloan::Funds` (r:1 w:0) + /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: UNKNOWN KEY `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) + /// Proof: UNKNOWN KEY `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) + fn add_memo() -> Weight { + // Proof Size summary in bytes: + // Measured: `412` + // Estimated: `3877` + // Minimum execution time: 33_529_000 picoseconds. + Weight::from_parts(37_082_000, 0) + .saturating_add(Weight::from_parts(0, 3877)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Crowdloan::Funds` (r:1 w:0) + /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Crowdloan::NewRaise` (r:1 w:1) + /// Proof: `Crowdloan::NewRaise` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn poke() -> Weight { + // Proof Size summary in bytes: + // Measured: `238` + // Estimated: `3703` + // Minimum execution time: 23_153_000 picoseconds. + Weight::from_parts(24_181_000, 0) + .saturating_add(Weight::from_parts(0, 3703)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Auctions::AuctionInfo` (r:1 w:0) + /// Proof: `Auctions::AuctionInfo` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `Crowdloan::EndingsCount` (r:1 w:1) + /// Proof: `Crowdloan::EndingsCount` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Crowdloan::NewRaise` (r:1 w:1) + /// Proof: `Crowdloan::NewRaise` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Crowdloan::Funds` (r:100 w:0) + /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Auctions::AuctionCounter` (r:1 w:0) + /// Proof: `Auctions::AuctionCounter` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + /// Storage: `Paras::ParaLifecycles` (r:100 w:0) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Slots::Leases` (r:100 w:0) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Auctions::Winning` (r:1 w:1) + /// Proof: `Auctions::Winning` (`max_values`: None, `max_size`: Some(1920), added: 4395, mode: `MaxEncodedLen`) + /// Storage: `Auctions::ReservedAmounts` (r:100 w:100) + /// Proof: `Auctions::ReservedAmounts` (`max_values`: None, `max_size`: Some(60), added: 2535, mode: `MaxEncodedLen`) + /// Storage: `System::Account` (r:100 w:100) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + /// The range of component `n` is `[2, 100]`. + fn on_initialize(n: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `229 + n * (356 ±0)` + // Estimated: `5385 + n * (2832 ±0)` + // Minimum execution time: 120_164_000 picoseconds. + Weight::from_parts(3_390_119, 0) + .saturating_add(Weight::from_parts(0, 5385)) + // Standard Error: 41_727 + .saturating_add(Weight::from_parts(54_453_016, 0).saturating_mul(n.into())) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n.into()))) + .saturating_add(T::DbWeight::get().writes(3)) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) + .saturating_add(Weight::from_parts(0, 2832).saturating_mul(n.into())) + } +} diff --git a/polkadot/runtime/westend/src/weights/runtime_common_identity_migrator.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_identity_migrator.rs similarity index 58% rename from polkadot/runtime/westend/src/weights/runtime_common_identity_migrator.rs rename to polkadot/runtime/rococo/src/weights/polkadot_runtime_common_identity_migrator.rs index 4ea6f6796801..3df3c6c8dd92 100644 --- a/polkadot/runtime/westend/src/weights/runtime_common_identity_migrator.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_identity_migrator.rs @@ -1,36 +1,43 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 +// This file is part of Polkadot. -// 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. +// 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 `runtime_common::identity_migrator` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-11-07, STEPS: `2`, REPEAT: `1`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `sbtb`, CPU: `13th Gen Intel(R) Core(TM) i7-1365U` +//! HOSTNAME: `runner-bn-ce5rx-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/release/polkadot +// ./target/production/polkadot // benchmark // pallet // --chain=rococo-dev -// --steps=2 -// --repeat=1 +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=runtime_common::identity_migrator // --extrinsic=* -// --output=./migrator-release.rs +// --execution=wasm +// --wasm-execution=compiled +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_common_identity_migrator.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -44,7 +51,7 @@ use core::marker::PhantomData; pub struct WeightInfo(PhantomData); impl polkadot_runtime_common::identity_migrator::WeightInfo for WeightInfo { /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) /// Storage: `Identity::SubsOf` (r:1 w:1) /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:2 w:2) @@ -63,34 +70,34 @@ impl polkadot_runtime_common::identity_migrator::Weight /// The range of component `s` is `[0, 100]`. fn reap_identity(r: u32, s: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `7292 + r * (8 ±0) + s * (32 ±0)` - // Estimated: `11003 + r * (8 ±0) + s * (33 ±0)` - // Minimum execution time: 163_756_000 picoseconds. - Weight::from_parts(158_982_500, 0) - .saturating_add(Weight::from_parts(0, 11003)) - // Standard Error: 1_143_629 - .saturating_add(Weight::from_parts(238_675, 0).saturating_mul(r.into())) - // Standard Error: 228_725 - .saturating_add(Weight::from_parts(1_529_645, 0).saturating_mul(s.into())) + // Measured: `7457 + r * (5 ±0) + s * (32 ±0)` + // Estimated: `11037 + r * (7 ±0) + s * (32 ±0)` + // Minimum execution time: 157_343_000 picoseconds. + Weight::from_parts(159_289_236, 0) + .saturating_add(Weight::from_parts(0, 11037)) + // Standard Error: 16_439 + .saturating_add(Weight::from_parts(224_293, 0).saturating_mul(r.into())) + // Standard Error: 3_367 + .saturating_add(Weight::from_parts(1_383_637, 0).saturating_mul(s.into())) .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(5)) + .saturating_add(T::DbWeight::get().writes(6)) .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(s.into()))) - .saturating_add(Weight::from_parts(0, 8).saturating_mul(r.into())) - .saturating_add(Weight::from_parts(0, 33).saturating_mul(s.into())) + .saturating_add(Weight::from_parts(0, 7).saturating_mul(r.into())) + .saturating_add(Weight::from_parts(0, 32).saturating_mul(s.into())) } /// Storage: `Identity::IdentityOf` (r:1 w:1) - /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7538), added: 10013, mode: `MaxEncodedLen`) + /// Proof: `Identity::IdentityOf` (`max_values`: None, `max_size`: Some(7572), added: 10047, mode: `MaxEncodedLen`) /// Storage: `System::Account` (r:1 w:1) /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) /// Storage: `Identity::SubsOf` (r:1 w:1) /// Proof: `Identity::SubsOf` (`max_values`: None, `max_size`: Some(3258), added: 5733, mode: `MaxEncodedLen`) fn poke_deposit() -> Weight { // Proof Size summary in bytes: - // Measured: `7229` - // Estimated: `11003` - // Minimum execution time: 137_570_000 picoseconds. - Weight::from_parts(137_570_000, 0) - .saturating_add(Weight::from_parts(0, 11003)) + // Measured: `7242` + // Estimated: `11037` + // Minimum execution time: 114_384_000 picoseconds. + Weight::from_parts(115_741_000, 0) + .saturating_add(Weight::from_parts(0, 11037)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(3)) } diff --git a/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_paras_registrar.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_paras_registrar.rs new file mode 100644 index 000000000000..ad261a7f7747 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_paras_registrar.rs @@ -0,0 +1,218 @@ +// 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 `runtime_common::paras_registrar` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot +// benchmark +// pallet +// --chain=rococo-dev +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=runtime_common::paras_registrar +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_common_paras_registrar.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 `runtime_common::paras_registrar`. +pub struct WeightInfo(PhantomData); +impl polkadot_runtime_common::paras_registrar::WeightInfo for WeightInfo { + /// Storage: Registrar NextFreeParaId (r:1 w:1) + /// Proof Skipped: Registrar NextFreeParaId (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Registrar Paras (r:1 w:1) + /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras ParaLifecycles (r:1 w:0) + /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) + fn reserve() -> Weight { + // Proof Size summary in bytes: + // Measured: `96` + // Estimated: `3561` + // Minimum execution time: 24_109_000 picoseconds. + Weight::from_parts(24_922_000, 0) + .saturating_add(Weight::from_parts(0, 3561)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Registrar::Paras` (r:1 w:1) + /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:1) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHash` (r:1 w:1) + /// Proof: `Paras::CodeByHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHashRefs` (r:1 w:1) + /// Proof: `Paras::CodeByHashRefs` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CurrentCodeHash` (r:0 w:1) + /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpcomingParasGenesis` (r:0 w:1) + /// Proof: `Paras::UpcomingParasGenesis` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn register() -> Weight { + // Proof Size summary in bytes: + // Measured: `352` + // Estimated: `3817` + // Minimum execution time: 7_207_580_000 picoseconds. + Weight::from_parts(7_298_567_000, 0) + .saturating_add(Weight::from_parts(0, 3817)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(8)) + } + /// Storage: `Registrar::Paras` (r:1 w:1) + /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:1) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHash` (r:1 w:1) + /// Proof: `Paras::CodeByHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHashRefs` (r:1 w:1) + /// Proof: `Paras::CodeByHashRefs` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CurrentCodeHash` (r:0 w:1) + /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpcomingParasGenesis` (r:0 w:1) + /// Proof: `Paras::UpcomingParasGenesis` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn force_register() -> Weight { + // Proof Size summary in bytes: + // Measured: `269` + // Estimated: `3734` + // Minimum execution time: 7_196_460_000 picoseconds. + Weight::from_parts(7_385_729_000, 0) + .saturating_add(Weight::from_parts(0, 3734)) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(8)) + } + /// Storage: `Registrar::Paras` (r:1 w:1) + /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:1) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::FutureCodeHash` (r:1 w:0) + /// Proof: `Paras::FutureCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:0) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `Registrar::PendingSwap` (r:0 w:1) + /// Proof: `Registrar::PendingSwap` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn deregister() -> Weight { + // Proof Size summary in bytes: + // Measured: `499` + // Estimated: `3964` + // Minimum execution time: 54_761_000 picoseconds. + Weight::from_parts(57_931_000, 0) + .saturating_add(Weight::from_parts(0, 3964)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(4)) + } + /// Storage: `Registrar::Paras` (r:1 w:0) + /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:2 w:2) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Registrar::PendingSwap` (r:1 w:1) + /// Proof: `Registrar::PendingSwap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Crowdloan::Funds` (r:2 w:2) + /// Proof: `Crowdloan::Funds` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Slots::Leases` (r:2 w:2) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn swap() -> Weight { + // Proof Size summary in bytes: + // Measured: `837` + // Estimated: `6777` + // Minimum execution time: 59_564_000 picoseconds. + Weight::from_parts(62_910_000, 0) + .saturating_add(Weight::from_parts(0, 6777)) + .saturating_add(T::DbWeight::get().reads(10)) + .saturating_add(T::DbWeight::get().writes(8)) + } + /// Storage: `Paras::FutureCodeHash` (r:1 w:1) + /// Proof: `Paras::FutureCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeRestrictionSignal` (r:1 w:1) + /// Proof: `Paras::UpgradeRestrictionSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) + /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeCooldowns` (r:1 w:1) + /// Proof: `Paras::UpgradeCooldowns` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHash` (r:1 w:1) + /// Proof: `Paras::CodeByHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHashRefs` (r:1 w:1) + /// Proof: `Paras::CodeByHashRefs` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `b` is `[9, 3145728]`. + fn schedule_code_upgrade(b: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `201` + // Estimated: `3666` + // Minimum execution time: 33_106_000 picoseconds. + Weight::from_parts(33_526_000, 0) + .saturating_add(Weight::from_parts(0, 3666)) + // Standard Error: 2 + .saturating_add(Weight::from_parts(2_334, 0).saturating_mul(b.into())) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(7)) + } + /// Storage: `Paras::Heads` (r:0 w:1) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `b` is `[1, 1048576]`. + fn set_current_head(b: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_992_000 picoseconds. + Weight::from_parts(12_059_689, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 0 + .saturating_add(Weight::from_parts(959, 0).saturating_mul(b.into())) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_slots.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_slots.rs new file mode 100644 index 000000000000..b99ee1f9a0d3 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_common_slots.rs @@ -0,0 +1,131 @@ +// 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 `runtime_common::slots` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot +// benchmark +// pallet +// --chain=rococo-dev +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=runtime_common::slots +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_common_slots.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 `runtime_common::slots`. +pub struct WeightInfo(PhantomData); +impl polkadot_runtime_common::slots::WeightInfo for WeightInfo { + /// Storage: Slots Leases (r:1 w:1) + /// Proof Skipped: Slots Leases (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) + fn force_lease() -> Weight { + // Proof Size summary in bytes: + // Measured: `320` + // Estimated: `3785` + // Minimum execution time: 26_570_000 picoseconds. + Weight::from_parts(27_619_000, 0) + .saturating_add(Weight::from_parts(0, 3785)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(2)) + } + /// Storage: `Paras::Parachains` (r:1 w:0) + /// Proof: `Paras::Parachains` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Slots::Leases` (r:101 w:100) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:200 w:200) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `c` is `[0, 100]`. + /// The range of component `t` is `[0, 100]`. + fn manage_lease_period_start(c: u32, t: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `594 + c * (20 ±0) + t * (234 ±0)` + // Estimated: `4065 + c * (2496 ±0) + t * (2709 ±0)` + // Minimum execution time: 729_793_000 picoseconds. + Weight::from_parts(740_820_000, 0) + .saturating_add(Weight::from_parts(0, 4065)) + // Standard Error: 88_206 + .saturating_add(Weight::from_parts(2_793_142, 0).saturating_mul(c.into())) + // Standard Error: 88_206 + .saturating_add(Weight::from_parts(8_933_065, 0).saturating_mul(t.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) + .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(t.into()))) + .saturating_add(T::DbWeight::get().writes(1)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) + .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(t.into()))) + .saturating_add(Weight::from_parts(0, 2496).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 2709).saturating_mul(t.into())) + } + /// Storage: `Slots::Leases` (r:1 w:1) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `System::Account` (r:8 w:8) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn clear_all_leases() -> Weight { + // Proof Size summary in bytes: + // Measured: `2792` + // Estimated: `21814` + // Minimum execution time: 123_888_000 picoseconds. + Weight::from_parts(131_245_000, 0) + .saturating_add(Weight::from_parts(0, 21814)) + .saturating_add(T::DbWeight::get().reads(9)) + .saturating_add(T::DbWeight::get().writes(9)) + } + /// Storage: `Slots::Leases` (r:1 w:0) + /// Proof: `Slots::Leases` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ParaLifecycles` (r:1 w:1) + /// Proof: `Paras::ParaLifecycles` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn trigger_onboard() -> Weight { + // Proof Size summary in bytes: + // Measured: `612` + // Estimated: `4077` + // Minimum execution time: 27_341_000 picoseconds. + Weight::from_parts(28_697_000, 0) + .saturating_add(Weight::from_parts(0, 4077)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_configuration.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_configuration.rs similarity index 89% rename from polkadot/runtime/rococo/src/weights/runtime_parachains_configuration.rs rename to polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_configuration.rs index 5592a85c90fa..3ca49aaa1651 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_configuration.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_configuration.rs @@ -17,25 +17,27 @@ //! Autogenerated weights for `runtime_parachains::configuration` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-02-08, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` //! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// target/production/polkadot +// ./target/production/polkadot // benchmark // pallet +// --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=runtime_parachains::configuration // --extrinsic=* +// --execution=wasm // --wasm-execution=compiled -// --heap-pages=4096 -// --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=runtime_parachains::configuration -// --chain=rococo-dev // --header=./polkadot/file_header.txt -// --output=./polkadot/runtime/rococo/src/weights/ +// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_configuration.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -58,8 +60,8 @@ impl polkadot_runtime_parachains::configuration::Weight // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_789_000 picoseconds. - Weight::from_parts(8_269_000, 0) + // Minimum execution time: 7_689_000 picoseconds. + Weight::from_parts(8_089_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -74,8 +76,8 @@ impl polkadot_runtime_parachains::configuration::Weight // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_851_000 picoseconds. - Weight::from_parts(8_152_000, 0) + // Minimum execution time: 7_735_000 picoseconds. + Weight::from_parts(8_150_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -90,8 +92,8 @@ impl polkadot_runtime_parachains::configuration::Weight // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_960_000 picoseconds. - Weight::from_parts(8_276_000, 0) + // Minimum execution time: 7_902_000 picoseconds. + Weight::from_parts(8_196_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -116,8 +118,8 @@ impl polkadot_runtime_parachains::configuration::Weight // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_912_000 picoseconds. - Weight::from_parts(8_164_000, 0) + // Minimum execution time: 7_634_000 picoseconds. + Weight::from_parts(7_983_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -132,8 +134,8 @@ impl polkadot_runtime_parachains::configuration::Weight // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 9_782_000 picoseconds. - Weight::from_parts(10_373_000, 0) + // Minimum execution time: 9_580_000 picoseconds. + Weight::from_parts(9_989_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -148,8 +150,8 @@ impl polkadot_runtime_parachains::configuration::Weight // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_870_000 picoseconds. - Weight::from_parts(8_274_000, 0) + // Minimum execution time: 7_787_000 picoseconds. + Weight::from_parts(8_008_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -164,8 +166,8 @@ impl polkadot_runtime_parachains::configuration::Weight // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 9_960_000 picoseconds. - Weight::from_parts(10_514_000, 0) + // Minimum execution time: 9_557_000 picoseconds. + Weight::from_parts(9_994_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) @@ -180,8 +182,8 @@ impl polkadot_runtime_parachains::configuration::Weight // Proof Size summary in bytes: // Measured: `151` // Estimated: `1636` - // Minimum execution time: 7_913_000 picoseconds. - Weight::from_parts(8_338_000, 0) + // Minimum execution time: 7_775_000 picoseconds. + Weight::from_parts(7_989_000, 0) .saturating_add(Weight::from_parts(0, 1636)) .saturating_add(T::DbWeight::get().reads(3)) .saturating_add(T::DbWeight::get().writes(1)) diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_coretime.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_coretime.rs similarity index 100% rename from polkadot/runtime/rococo/src/weights/runtime_parachains_coretime.rs rename to polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_coretime.rs diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_disputes.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_disputes.rs similarity index 78% rename from polkadot/runtime/rococo/src/weights/runtime_parachains_disputes.rs rename to polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_disputes.rs index a20515502b19..6f86d6a12599 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_disputes.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_disputes.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_parachains::disputes` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-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-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=runtime_parachains::disputes // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_parachains_disputes.rs +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_disputes.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -53,8 +56,8 @@ impl polkadot_runtime_parachains::disputes::WeightInfo // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 2_937_000 picoseconds. - Weight::from_parts(3_082_000, 0) + // Minimum execution time: 1_855_000 picoseconds. + Weight::from_parts(2_015_000, 0) .saturating_add(Weight::from_parts(0, 0)) .saturating_add(T::DbWeight::get().writes(1)) } diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_hrmp.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_hrmp.rs similarity index 100% rename from polkadot/runtime/rococo/src/weights/runtime_parachains_hrmp.rs rename to polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_hrmp.rs diff --git a/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_inclusion.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_inclusion.rs new file mode 100644 index 000000000000..5824658383be --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_inclusion.rs @@ -0,0 +1,126 @@ +// 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 `polkadot_runtime_parachains::inclusion` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-08-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-svzsllib-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=polkadot_runtime_parachains::inclusion +// --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 `polkadot_runtime_parachains::inclusion`. +pub struct WeightInfo(PhantomData); +impl polkadot_runtime_parachains::inclusion::WeightInfo for WeightInfo { + /// Storage: `Paras::FutureCodeHash` (r:1 w:1) + /// Proof: `Paras::FutureCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) + /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeCooldowns` (r:1 w:1) + /// Proof: `Paras::UpgradeCooldowns` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHash` (r:1 w:1) + /// Proof: `Paras::CodeByHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHashRefs` (r:1 w:1) + /// Proof: `Paras::CodeByHashRefs` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:10) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(32818), added: 35293, mode: `MaxEncodedLen`) + /// Storage: `Hrmp::HrmpChannelDigests` (r:11 w:11) + /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannels` (r:10 w:10) + /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannelContents` (r:10 w:10) + /// Proof: `Hrmp::HrmpChannelContents` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0) + /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Registrar::Paras` (r:1 w:0) + /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Proof: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) + /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:0 w:1) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1) + /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::MostRecentContext` (r:0 w:1) + /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeRestrictionSignal` (r:0 w:1) + /// Proof: `Paras::UpgradeRestrictionSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Proof: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// The range of component `u` is `[0, 10]`. + /// The range of component `h` is `[0, 10]`. + /// The range of component `c` is `[0, 1]`. + fn enact_candidate(u: u32, h: u32, c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `33352 + c * (16115 ±0) + h * (76 ±0)` + // Estimated: `36283 + c * (19327 ±403) + h * (3057 ±59) + u * (1314 ±59)` + // Minimum execution time: 1_334_017_000 picoseconds. + Weight::from_parts(5_805_317, 0) + .saturating_add(Weight::from_parts(0, 36283)) + // Standard Error: 282_194 + .saturating_add(Weight::from_parts(128_332_196, 0).saturating_mul(u.into())) + // Standard Error: 282_194 + .saturating_add(Weight::from_parts(146_910_684, 0).saturating_mul(h.into())) + // Standard Error: 1_905_330 + .saturating_add(Weight::from_parts(91_514_854, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(h.into()))) + .saturating_add(T::DbWeight::get().reads((8_u64).saturating_mul(c.into()))) + .saturating_add(T::DbWeight::get().writes(8)) + .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(u.into()))) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(h.into()))) + .saturating_add(T::DbWeight::get().writes((7_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_parts(0, 19327).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 3057).saturating_mul(h.into())) + .saturating_add(Weight::from_parts(0, 1314).saturating_mul(u.into())) + } +} diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_initializer.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_initializer.rs similarity index 77% rename from polkadot/runtime/rococo/src/weights/runtime_parachains_initializer.rs rename to polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_initializer.rs index 6065c32b1741..b915c4ec0f36 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_initializer.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_initializer.rs @@ -16,11 +16,11 @@ //! Autogenerated weights for `runtime_parachains::initializer` //! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-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-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 +//! HOSTNAME: `runner-bn-ce5rx-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 @@ -29,12 +29,15 @@ // --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares // --pallet=runtime_parachains::initializer // --extrinsic=* // --execution=wasm // --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_parachains_initializer.rs +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_initializer.rs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -54,11 +57,11 @@ impl polkadot_runtime_parachains::initializer::WeightIn // Proof Size summary in bytes: // Measured: `0 + d * (11 ±0)` // Estimated: `1480 + d * (11 ±0)` - // Minimum execution time: 3_771_000 picoseconds. - Weight::from_parts(6_491_437, 0) + // Minimum execution time: 2_634_000 picoseconds. + Weight::from_parts(2_728_000, 0) .saturating_add(Weight::from_parts(0, 1480)) - // Standard Error: 9 - .saturating_add(Weight::from_parts(1_356, 0).saturating_mul(d.into())) + // Standard Error: 19 + .saturating_add(Weight::from_parts(2_499, 0).saturating_mul(d.into())) .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) .saturating_add(Weight::from_parts(0, 11).saturating_mul(d.into())) diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_on_demand.rs similarity index 92% rename from polkadot/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs rename to polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_on_demand.rs index abcc1893c29b..1dd62d129f9a 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_assigner_on_demand.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_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: `[]` @@ -23,16 +23,22 @@ //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: -// target/production/polkadot +// ./target/production/polkadot // benchmark // pallet +// --chain=rococo-dev // --steps=50 // --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=runtime_parachains::assigner_on_demand // --extrinsic=* +// --execution=wasm // --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 +51,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/polkadot_runtime_parachains_paras.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_paras.rs new file mode 100644 index 000000000000..c463552b6ad4 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_paras.rs @@ -0,0 +1,298 @@ +// 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 `runtime_parachains::paras` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot +// benchmark +// pallet +// --chain=rococo-dev +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=runtime_parachains::paras +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_parachains_paras.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 `runtime_parachains::paras`. +pub struct WeightInfo(PhantomData); +impl polkadot_runtime_parachains::paras::WeightInfo for WeightInfo { + /// Storage: Paras CurrentCodeHash (r:1 w:1) + /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras CodeByHashRefs (r:1 w:1) + /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras PastCodeMeta (r:1 w:1) + /// Proof Skipped: Paras PastCodeMeta (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras PastCodePruning (r:1 w:1) + /// Proof Skipped: Paras PastCodePruning (max_values: Some(1), max_size: None, mode: Measured) + /// Storage: Paras PastCodeHash (r:0 w:1) + /// Proof Skipped: Paras PastCodeHash (max_values: None, max_size: None, mode: Measured) + /// Storage: Paras CodeByHash (r:0 w:1) + /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) + /// The range of component `c` is `[1, 3145728]`. + fn force_set_current_code(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `8309` + // Estimated: `11774` + // Minimum execution time: 27_488_000 picoseconds. + Weight::from_parts(27_810_000, 0) + .saturating_add(Weight::from_parts(0, 11774)) + // Standard Error: 8 + .saturating_add(Weight::from_parts(2_189, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `Paras::Heads` (r:0 w:1) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `s` is `[1, 1048576]`. + fn force_set_current_head(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 5_793_000 picoseconds. + Weight::from_parts(7_987_606, 0) + .saturating_add(Weight::from_parts(0, 0)) + // Standard Error: 1 + .saturating_add(Weight::from_parts(971, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Paras::MostRecentContext` (r:0 w:1) + /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn force_set_most_recent_context() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 2_733_000 picoseconds. + Weight::from_parts(2_954_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Paras::FutureCodeHash` (r:1 w:1) + /// Proof: `Paras::FutureCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) + /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeCooldowns` (r:1 w:1) + /// Proof: `Paras::UpgradeCooldowns` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHash` (r:1 w:1) + /// Proof: `Paras::CodeByHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHashRefs` (r:1 w:1) + /// Proof: `Paras::CodeByHashRefs` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeRestrictionSignal` (r:0 w:1) + /// Proof: `Paras::UpgradeRestrictionSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `c` is `[1, 3145728]`. + fn force_schedule_code_upgrade(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `8452` + // Estimated: `11917` + // Minimum execution time: 6_072_000 picoseconds. + Weight::from_parts(6_128_000, 0) + .saturating_add(Weight::from_parts(0, 11917)) + // Standard Error: 2 + .saturating_add(Weight::from_parts(2_334, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(7)) + .saturating_add(T::DbWeight::get().writes(6)) + } + /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0) + /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Registrar::Paras` (r:1 w:0) + /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:0 w:1) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1) + /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::MostRecentContext` (r:0 w:1) + /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `s` is `[1, 1048576]`. + fn force_note_new_head(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `163` + // Estimated: `3628` + // Minimum execution time: 15_166_000 picoseconds. + Weight::from_parts(21_398_053, 0) + .saturating_add(Weight::from_parts(0, 3628)) + // Standard Error: 1 + .saturating_add(Weight::from_parts(976, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn force_queue_action() -> Weight { + // Proof Size summary in bytes: + // Measured: `4312` + // Estimated: `7777` + // Minimum execution time: 16_345_000 picoseconds. + Weight::from_parts(16_712_000, 0) + .saturating_add(Weight::from_parts(0, 7777)) + .saturating_add(T::DbWeight::get().reads(2)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `c` is `[1, 3145728]`. + fn add_trusted_validation_code(c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `683` + // Estimated: `4148` + // Minimum execution time: 78_076_000 picoseconds. + Weight::from_parts(123_193_814, 0) + .saturating_add(Weight::from_parts(0, 4148)) + // Standard Error: 5 + .saturating_add(Weight::from_parts(1_770, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `Paras::CodeByHashRefs` (r:1 w:0) + /// Proof: `Paras::CodeByHashRefs` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHash` (r:0 w:1) + /// Proof: `Paras::CodeByHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn poke_unused_validation_code() -> Weight { + // Proof Size summary in bytes: + // Measured: `28` + // Estimated: `3493` + // Minimum execution time: 5_184_000 picoseconds. + Weight::from_parts(5_430_000, 0) + .saturating_add(Weight::from_parts(0, 3493)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn include_pvf_check_statement() -> Weight { + // Proof Size summary in bytes: + // Measured: `26706` + // Estimated: `30171` + // Minimum execution time: 102_995_000 picoseconds. + Weight::from_parts(108_977_000, 0) + .saturating_add(Weight::from_parts(0, 30171)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpcomingUpgrades` (r:1 w:1) + /// Proof: `Paras::UpcomingUpgrades` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::Digest` (r:1 w:1) + /// Proof: `System::Digest` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::FutureCodeUpgrades` (r:0 w:100) + /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn include_pvf_check_statement_finalize_upgrade_accept() -> Weight { + // Proof Size summary in bytes: + // Measured: `27360` + // Estimated: `30825` + // Minimum execution time: 709_433_000 picoseconds. + Weight::from_parts(725_074_000, 0) + .saturating_add(Weight::from_parts(0, 30825)) + .saturating_add(T::DbWeight::get().reads(6)) + .saturating_add(T::DbWeight::get().writes(104)) + } + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn include_pvf_check_statement_finalize_upgrade_reject() -> Weight { + // Proof Size summary in bytes: + // Measured: `27338` + // Estimated: `30803` + // Minimum execution time: 98_973_000 picoseconds. + Weight::from_parts(104_715_000, 0) + .saturating_add(Weight::from_parts(0, 30803)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::ActionsQueue` (r:1 w:1) + /// Proof: `Paras::ActionsQueue` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn include_pvf_check_statement_finalize_onboarding_accept() -> Weight { + // Proof Size summary in bytes: + // Measured: `26728` + // Estimated: `30193` + // Minimum execution time: 550_958_000 picoseconds. + Weight::from_parts(564_497_000, 0) + .saturating_add(Weight::from_parts(0, 30193)) + .saturating_add(T::DbWeight::get().reads(5)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + fn include_pvf_check_statement_finalize_onboarding_reject() -> Weight { + // Proof Size summary in bytes: + // Measured: `26706` + // Estimated: `30171` + // Minimum execution time: 97_088_000 picoseconds. + Weight::from_parts(103_617_000, 0) + .saturating_add(Weight::from_parts(0, 30171)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_paras_inherent.rs similarity index 78% rename from polkadot/runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs rename to polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_paras_inherent.rs index c00966fb8048..71a0bb6fc7b2 100644 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_paras_inherent.rs +++ b/polkadot/runtime/rococo/src/weights/polkadot_runtime_parachains_paras_inherent.rs @@ -14,12 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Autogenerated weights for `runtime_parachains::paras_inherent` +//! Autogenerated weights for `polkadot_runtime_parachains::paras_inherent` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-10-21, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-augrssgt-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 // Executed Command: @@ -32,7 +32,7 @@ // --wasm-execution=compiled // --heap-pages=4096 // --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=runtime_parachains::paras_inherent +// --pallet=polkadot_runtime_parachains::paras_inherent // --chain=rococo-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/rococo/src/weights/ @@ -45,7 +45,7 @@ use frame_support::{traits::Get, weights::Weight}; use core::marker::PhantomData; -/// Weight functions for `runtime_parachains::paras_inherent`. +/// Weight functions for `polkadot_runtime_parachains::paras_inherent`. pub struct WeightInfo(PhantomData); impl polkadot_runtime_parachains::paras_inherent::WeightInfo for WeightInfo { /// Storage: `ParaInherent::Included` (r:1 w:1) @@ -54,10 +54,52 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:0) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) + /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) + /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1) + /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Frozen` (r:1 w:0) + /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaInclusion::V1` (r:1 w:0) + /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) + /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Session::DisabledValidators` (r:1 w:0) + /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn enter_empty() -> Weight { + // Proof Size summary in bytes: + // Measured: `42760` + // Estimated: `46225` + // Minimum execution time: 228_252_000 picoseconds. + Weight::from_parts(234_368_000, 0) + .saturating_add(Weight::from_parts(0, 46225)) + .saturating_add(T::DbWeight::get().reads(15)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `ParaInherent::Included` (r:1 w:1) + /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) + /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) @@ -88,16 +130,14 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Session::DisabledValidators` (r:1 w:0) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::Heads` (r:0 w:1) @@ -106,19 +146,18 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::MostRecentContext` (r:0 w:1) /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `v` is `[10, 200]`. + /// The range of component `v` is `[400, 1024]`. fn enter_variable_disputes(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `67785` - // Estimated: `73725 + v * (23 ±0)` - // Minimum execution time: 949_716_000 picoseconds. - Weight::from_parts(482_361_515, 0) - .saturating_add(Weight::from_parts(0, 73725)) - // Standard Error: 17_471 - .saturating_add(Weight::from_parts(50_100_764, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(25)) - .saturating_add(T::DbWeight::get().writes(15)) - .saturating_add(Weight::from_parts(0, 23).saturating_mul(v.into())) + // Measured: `203155` + // Estimated: `209095` + // Minimum execution time: 17_510_015_000 picoseconds. + Weight::from_parts(948_178_084, 0) + .saturating_add(Weight::from_parts(0, 209095)) + // Standard Error: 16_345 + .saturating_add(Weight::from_parts(41_627_958, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(26)) + .saturating_add(T::DbWeight::get().writes(16)) } /// Storage: `ParaInherent::Included` (r:1 w:1) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -126,10 +165,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:0) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) @@ -140,49 +181,23 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParaInclusion::V1` (r:2 w:1) /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1) - /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0) - /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Registrar::Paras` (r:1 w:0) - /// Proof: `Registrar::Paras` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasDisputes::Disputes` (r:1 w:0) - /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Session::DisabledValidators` (r:1 w:0) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasDisputes::Included` (r:0 w:1) - /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) - /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::Heads` (r:0 w:1) - /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1) - /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::MostRecentContext` (r:0 w:1) - /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) fn enter_bitfields() -> Weight { // Proof Size summary in bytes: - // Measured: `42757` - // Estimated: `48697` - // Minimum execution time: 437_627_000 picoseconds. - Weight::from_parts(460_975_000, 0) - .saturating_add(Weight::from_parts(0, 48697)) - .saturating_add(T::DbWeight::get().reads(23)) - .saturating_add(T::DbWeight::get().writes(15)) + // Measured: `76066` + // Estimated: `82006` + // Minimum execution time: 501_266_000 picoseconds. + Weight::from_parts(517_989_000, 0) + .saturating_add(Weight::from_parts(0, 82006)) + .saturating_add(T::DbWeight::get().reads(16)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `ParaInherent::Included` (r:1 w:1) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -190,10 +205,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) @@ -218,12 +235,8 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::ParaLifecycles` (r:1 w:0) @@ -234,6 +247,8 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Session::DisabledValidators` (r:1 w:0) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParasDisputes::Included` (r:0 w:1) /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) @@ -244,18 +259,18 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::MostRecentContext` (r:0 w:1) /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `v` is `[101, 200]`. + /// The range of component `v` is `[2, 3]`. fn enter_backed_candidates_variable(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `42829` - // Estimated: `48769` - // Minimum execution time: 1_305_254_000 picoseconds. - Weight::from_parts(1_347_160_667, 0) - .saturating_add(Weight::from_parts(0, 48769)) - // Standard Error: 22_128 - .saturating_add(Weight::from_parts(57_229, 0).saturating_mul(v.into())) + // Measured: `76842` + // Estimated: `82782` + // Minimum execution time: 1_861_799_000 picoseconds. + Weight::from_parts(1_891_155_030, 0) + .saturating_add(Weight::from_parts(0, 82782)) + // Standard Error: 2_415_944 + .saturating_add(Weight::from_parts(7_924_189, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(26)) - .saturating_add(T::DbWeight::get().writes(15)) + .saturating_add(T::DbWeight::get().writes(14)) } /// Storage: `ParaInherent::Included` (r:1 w:1) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -263,10 +278,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) @@ -291,12 +308,8 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::FutureCodeHash` (r:1 w:0) @@ -311,6 +324,8 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Session::DisabledValidators` (r:1 w:0) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParasDisputes::Included` (r:0 w:1) /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) @@ -323,12 +338,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) fn enter_backed_candidate_code_upgrade() -> Weight { // Proof Size summary in bytes: - // Measured: `42842` - // Estimated: `48782` - // Minimum execution time: 38_637_547_000 picoseconds. - Weight::from_parts(41_447_412_000, 0) - .saturating_add(Weight::from_parts(0, 48782)) + // Measured: `76855` + // Estimated: `82795` + // Minimum execution time: 37_682_370_000 picoseconds. + Weight::from_parts(41_118_445_000, 0) + .saturating_add(Weight::from_parts(0, 82795)) .saturating_add(T::DbWeight::get().reads(28)) - .saturating_add(T::DbWeight::get().writes(15)) + .saturating_add(T::DbWeight::get().writes(14)) } } diff --git a/polkadot/runtime/rococo/src/weights/runtime_common_auctions.rs b/polkadot/runtime/rococo/src/weights/runtime_common_auctions.rs deleted file mode 100644 index 897dc1c1752a..000000000000 --- a/polkadot/runtime/rococo/src/weights/runtime_common_auctions.rs +++ /dev/null @@ -1,140 +0,0 @@ -// 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 `runtime_common::auctions` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --pallet=runtime_common::auctions -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_common_auctions.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 `runtime_common::auctions`. -pub struct WeightInfo(PhantomData); -impl polkadot_runtime_common::auctions::WeightInfo for WeightInfo { - /// Storage: Auctions AuctionInfo (r:1 w:1) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Auctions AuctionCounter (r:1 w:1) - /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn new_auction() -> Weight { - // Proof Size summary in bytes: - // Measured: `4` - // Estimated: `1493` - // Minimum execution time: 12_805_000 picoseconds. - Weight::from_parts(13_153_000, 0) - .saturating_add(Weight::from_parts(0, 1493)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Paras ParaLifecycles (r:1 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions AuctionCounter (r:1 w:0) - /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Auctions AuctionInfo (r:1 w:0) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Slots Leases (r:1 w:0) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions Winning (r:1 w:1) - /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) - /// Storage: Auctions ReservedAmounts (r:2 w:2) - /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn bid() -> Weight { - // Proof Size summary in bytes: - // Measured: `728` - // Estimated: `6060` - // Minimum execution time: 77_380_000 picoseconds. - Weight::from_parts(80_503_000, 0) - .saturating_add(Weight::from_parts(0, 6060)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Auctions AuctionInfo (r:1 w:1) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Babe NextRandomness (r:1 w:0) - /// Proof: Babe NextRandomness (max_values: Some(1), max_size: Some(32), added: 527, mode: MaxEncodedLen) - /// Storage: Babe EpochStart (r:1 w:0) - /// Proof: Babe EpochStart (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Auctions AuctionCounter (r:1 w:0) - /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Auctions Winning (r:3600 w:3600) - /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) - /// Storage: Auctions ReservedAmounts (r:37 w:36) - /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) - /// Storage: System Account (r:36 w:36) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Slots Leases (r:2 w:2) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - fn on_initialize() -> Weight { - // Proof Size summary in bytes: - // Measured: `6947789` - // Estimated: `15822990` - // Minimum execution time: 6_311_055_000 picoseconds. - Weight::from_parts(6_409_142_000, 0) - .saturating_add(Weight::from_parts(0, 15822990)) - .saturating_add(T::DbWeight::get().reads(3683)) - .saturating_add(T::DbWeight::get().writes(3678)) - } - /// Storage: Auctions ReservedAmounts (r:37 w:36) - /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) - /// Storage: System Account (r:36 w:36) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Auctions Winning (r:3600 w:3600) - /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) - /// Storage: Auctions AuctionInfo (r:0 w:1) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - fn cancel_auction() -> Weight { - // Proof Size summary in bytes: - // Measured: `177732` - // Estimated: `15822990` - // Minimum execution time: 4_849_561_000 picoseconds. - Weight::from_parts(4_955_226_000, 0) - .saturating_add(Weight::from_parts(0, 15822990)) - .saturating_add(T::DbWeight::get().reads(3673)) - .saturating_add(T::DbWeight::get().writes(3673)) - } -} diff --git a/polkadot/runtime/rococo/src/weights/runtime_common_claims.rs b/polkadot/runtime/rococo/src/weights/runtime_common_claims.rs deleted file mode 100644 index 8fbc798dbd46..000000000000 --- a/polkadot/runtime/rococo/src/weights/runtime_common_claims.rs +++ /dev/null @@ -1,166 +0,0 @@ -// 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 `runtime_common::claims` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --pallet=runtime_common::claims -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_common_claims.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 `runtime_common::claims`. -pub struct WeightInfo(PhantomData); -impl polkadot_runtime_common::claims::WeightInfo for WeightInfo { - /// Storage: Claims Claims (r:1 w:1) - /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Signing (r:1 w:1) - /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Total (r:1 w:1) - /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Claims Vesting (r:1 w:1) - /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - fn claim() -> Weight { - // Proof Size summary in bytes: - // Measured: `558` - // Estimated: `4764` - // Minimum execution time: 144_931_000 picoseconds. - Weight::from_parts(156_550_000, 0) - .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Claims Total (r:1 w:1) - /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Claims Vesting (r:0 w:1) - /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Claims (r:0 w:1) - /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Signing (r:0 w:1) - /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) - fn mint_claim() -> Weight { - // Proof Size summary in bytes: - // Measured: `216` - // Estimated: `1701` - // Minimum execution time: 11_300_000 picoseconds. - Weight::from_parts(11_642_000, 0) - .saturating_add(Weight::from_parts(0, 1701)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Claims Claims (r:1 w:1) - /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Signing (r:1 w:1) - /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Total (r:1 w:1) - /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Claims Vesting (r:1 w:1) - /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - fn claim_attest() -> Weight { - // Proof Size summary in bytes: - // Measured: `558` - // Estimated: `4764` - // Minimum execution time: 149_112_000 picoseconds. - Weight::from_parts(153_872_000, 0) - .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Claims Preclaims (r:1 w:1) - /// Proof Skipped: Claims Preclaims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Signing (r:1 w:1) - /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Claims (r:1 w:1) - /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Total (r:1 w:1) - /// Proof Skipped: Claims Total (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Claims Vesting (r:1 w:1) - /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) - /// Storage: Vesting Vesting (r:1 w:1) - /// Proof: Vesting Vesting (max_values: None, max_size: Some(1057), added: 3532, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:0) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances Locks (r:1 w:1) - /// Proof: Balances Locks (max_values: None, max_size: Some(1299), added: 3774, mode: MaxEncodedLen) - /// Storage: Balances Freezes (r:1 w:0) - /// Proof: Balances Freezes (max_values: None, max_size: Some(65), added: 2540, mode: MaxEncodedLen) - fn attest() -> Weight { - // Proof Size summary in bytes: - // Measured: `632` - // Estimated: `4764` - // Minimum execution time: 69_619_000 picoseconds. - Weight::from_parts(79_242_000, 0) - .saturating_add(Weight::from_parts(0, 4764)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Claims Claims (r:1 w:2) - /// Proof Skipped: Claims Claims (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Vesting (r:1 w:2) - /// Proof Skipped: Claims Vesting (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Signing (r:1 w:2) - /// Proof Skipped: Claims Signing (max_values: None, max_size: None, mode: Measured) - /// Storage: Claims Preclaims (r:1 w:1) - /// Proof Skipped: Claims Preclaims (max_values: None, max_size: None, mode: Measured) - fn move_claim() -> Weight { - // Proof Size summary in bytes: - // Measured: `440` - // Estimated: `3905` - // Minimum execution time: 22_066_000 picoseconds. - Weight::from_parts(22_483_000, 0) - .saturating_add(Weight::from_parts(0, 3905)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(7)) - } -} diff --git a/polkadot/runtime/rococo/src/weights/runtime_common_coretime.rs b/polkadot/runtime/rococo/src/weights/runtime_common_coretime.rs new file mode 100644 index 000000000000..d068f07e7594 --- /dev/null +++ b/polkadot/runtime/rococo/src/weights/runtime_common_coretime.rs @@ -0,0 +1,86 @@ +// 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 `runtime_common::coretime` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-02-29, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/production/polkadot +// benchmark +// pallet +// --chain=rococo-dev +// --steps=50 +// --repeat=20 +// --no-storage-info +// --no-median-slopes +// --no-min-squares +// --pallet=runtime_common::coretime +// --extrinsic=* +// --execution=wasm +// --wasm-execution=compiled +// --header=./polkadot/file_header.txt +// --output=./polkadot/runtime/rococo/src/weights/runtime_common_coretime.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 `runtime_common::coretime`. +pub struct WeightInfo(PhantomData); +impl runtime_common::coretime::WeightInfo for WeightInfo { + /// Storage: `Configuration::PendingConfigs` (r:1 w:1) + /// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0) + /// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn request_core_count() -> Weight { + // Proof Size summary in bytes: + // Measured: `151` + // Estimated: `1636` + // Minimum execution time: 7_543_000 picoseconds. + Weight::from_parts(7_745_000, 0) + .saturating_add(Weight::from_parts(0, 1636)) + .saturating_add(T::DbWeight::get().reads(3)) + .saturating_add(T::DbWeight::get().writes(1)) + } + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreSchedules` (r:0 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreSchedules` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// The range of component `s` is `[1, 100]`. + fn assign_core(s: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `180` + // Estimated: `3645` + // Minimum execution time: 9_367_000 picoseconds. + Weight::from_parts(9_932_305, 0) + .saturating_add(Weight::from_parts(0, 3645)) + // Standard Error: 231 + .saturating_add(Weight::from_parts(12_947, 0).saturating_mul(s.into())) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(2)) + } +} diff --git a/polkadot/runtime/rococo/src/weights/runtime_common_crowdloan.rs b/polkadot/runtime/rococo/src/weights/runtime_common_crowdloan.rs deleted file mode 100644 index b75ff8d42e7e..000000000000 --- a/polkadot/runtime/rococo/src/weights/runtime_common_crowdloan.rs +++ /dev/null @@ -1,222 +0,0 @@ -// 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 `runtime_common::crowdloan` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --pallet=runtime_common::crowdloan -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_common_crowdloan.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 `runtime_common::crowdloan`. -pub struct WeightInfo(PhantomData); -impl polkadot_runtime_common::crowdloan::WeightInfo for WeightInfo { - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Crowdloan NextFundIndex (r:1 w:1) - /// Proof Skipped: Crowdloan NextFundIndex (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) - fn create() -> Weight { - // Proof Size summary in bytes: - // Measured: `438` - // Estimated: `3903` - // Minimum execution time: 50_399_000 picoseconds. - Weight::from_parts(51_641_000, 0) - .saturating_add(Weight::from_parts(0, 3903)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Slots Leases (r:1 w:0) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions AuctionInfo (r:1 w:0) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: System Account (r:1 w:1) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// Storage: Balances InactiveIssuance (r:1 w:1) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: Crowdloan EndingsCount (r:1 w:0) - /// Proof Skipped: Crowdloan EndingsCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Crowdloan NewRaise (r:1 w:1) - /// Proof Skipped: Crowdloan NewRaise (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) - /// Proof Skipped: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) - fn contribute() -> Weight { - // Proof Size summary in bytes: - // Measured: `530` - // Estimated: `3995` - // Minimum execution time: 128_898_000 picoseconds. - Weight::from_parts(130_277_000, 0) - .saturating_add(Weight::from_parts(0, 3995)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (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: Balances InactiveIssuance (r:1 w:1) - /// Proof: Balances InactiveIssuance (max_values: Some(1), max_size: Some(16), added: 511, mode: MaxEncodedLen) - /// Storage: unknown `0xc85982571aa615c788ef9b2c16f54f25773fd439e8ee1ed2aa3ae43d48e880f0` (r:1 w:1) - /// Proof Skipped: unknown `0xc85982571aa615c788ef9b2c16f54f25773fd439e8ee1ed2aa3ae43d48e880f0` (r:1 w:1) - fn withdraw() -> Weight { - // Proof Size summary in bytes: - // Measured: `689` - // Estimated: `6196` - // Minimum execution time: 69_543_000 picoseconds. - Weight::from_parts(71_522_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(5)) - } - /// Storage: Skipped Metadata (r:0 w:0) - /// Proof Skipped: Skipped Metadata (max_values: None, max_size: None, mode: Measured) - /// The range of component `k` is `[0, 1000]`. - fn refund(k: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `127 + k * (189 ±0)` - // Estimated: `140 + k * (189 ±0)` - // Minimum execution time: 50_735_000 picoseconds. - Weight::from_parts(52_282_000, 0) - .saturating_add(Weight::from_parts(0, 140)) - // Standard Error: 21_607 - .saturating_add(Weight::from_parts(38_955_985, 0).saturating_mul(k.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().reads((2_u64).saturating_mul(k.into()))) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(k.into()))) - .saturating_add(Weight::from_parts(0, 189).saturating_mul(k.into())) - } - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (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) - fn dissolve() -> Weight { - // Proof Size summary in bytes: - // Measured: `515` - // Estimated: `6196` - // Minimum execution time: 43_100_000 picoseconds. - Weight::from_parts(44_272_000, 0) - .saturating_add(Weight::from_parts(0, 6196)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Crowdloan Funds (r:1 w:1) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - fn edit() -> Weight { - // Proof Size summary in bytes: - // Measured: `235` - // Estimated: `3700` - // Minimum execution time: 18_702_000 picoseconds. - Weight::from_parts(19_408_000, 0) - .saturating_add(Weight::from_parts(0, 3700)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Crowdloan Funds (r:1 w:0) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) - /// Proof Skipped: unknown `0xd861ea1ebf4800d4b89f4ff787ad79ee96d9a708c85b57da7eb8f9ddeda61291` (r:1 w:1) - fn add_memo() -> Weight { - // Proof Size summary in bytes: - // Measured: `412` - // Estimated: `3877` - // Minimum execution time: 25_568_000 picoseconds. - Weight::from_parts(26_203_000, 0) - .saturating_add(Weight::from_parts(0, 3877)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Crowdloan Funds (r:1 w:0) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Crowdloan NewRaise (r:1 w:1) - /// Proof Skipped: Crowdloan NewRaise (max_values: Some(1), max_size: None, mode: Measured) - fn poke() -> Weight { - // Proof Size summary in bytes: - // Measured: `239` - // Estimated: `3704` - // Minimum execution time: 17_832_000 picoseconds. - Weight::from_parts(18_769_000, 0) - .saturating_add(Weight::from_parts(0, 3704)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Auctions AuctionInfo (r:1 w:0) - /// Proof: Auctions AuctionInfo (max_values: Some(1), max_size: Some(8), added: 503, mode: MaxEncodedLen) - /// Storage: Crowdloan EndingsCount (r:1 w:1) - /// Proof Skipped: Crowdloan EndingsCount (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Crowdloan NewRaise (r:1 w:1) - /// Proof Skipped: Crowdloan NewRaise (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Crowdloan Funds (r:100 w:0) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions AuctionCounter (r:1 w:0) - /// Proof: Auctions AuctionCounter (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Paras ParaLifecycles (r:100 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Slots Leases (r:100 w:0) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Auctions Winning (r:1 w:1) - /// Proof: Auctions Winning (max_values: None, max_size: Some(1920), added: 4395, mode: MaxEncodedLen) - /// Storage: Auctions ReservedAmounts (r:100 w:100) - /// Proof: Auctions ReservedAmounts (max_values: None, max_size: Some(60), added: 2535, mode: MaxEncodedLen) - /// Storage: System Account (r:100 w:100) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - /// The range of component `n` is `[2, 100]`. - fn on_initialize(n: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `197 + n * (356 ±0)` - // Estimated: `5385 + n * (2832 ±0)` - // Minimum execution time: 128_319_000 picoseconds. - Weight::from_parts(130_877_000, 0) - .saturating_add(Weight::from_parts(0, 5385)) - // Standard Error: 61_381 - .saturating_add(Weight::from_parts(60_209_202, 0).saturating_mul(n.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().reads((5_u64).saturating_mul(n.into()))) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(n.into()))) - .saturating_add(Weight::from_parts(0, 2832).saturating_mul(n.into())) - } -} diff --git a/polkadot/runtime/rococo/src/weights/runtime_common_paras_registrar.rs b/polkadot/runtime/rococo/src/weights/runtime_common_paras_registrar.rs deleted file mode 100644 index 0ce09d1be2a4..000000000000 --- a/polkadot/runtime/rococo/src/weights/runtime_common_paras_registrar.rs +++ /dev/null @@ -1,221 +0,0 @@ -// 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 `runtime_common::paras_registrar` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --pallet=runtime_common::paras_registrar -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_common_paras_registrar.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 `runtime_common::paras_registrar`. -pub struct WeightInfo(PhantomData); -impl polkadot_runtime_common::paras_registrar::WeightInfo for WeightInfo { - /// Storage: Registrar NextFreeParaId (r:1 w:1) - /// Proof Skipped: Registrar NextFreeParaId (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:0) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - fn reserve() -> Weight { - // Proof Size summary in bytes: - // Measured: `97` - // Estimated: `3562` - // Minimum execution time: 29_948_000 picoseconds. - Weight::from_parts(30_433_000, 0) - .saturating_add(Weight::from_parts(0, 3562)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:1 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CodeByHashRefs (r:1 w:1) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:0 w:1) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpcomingParasGenesis (r:0 w:1) - /// Proof Skipped: Paras UpcomingParasGenesis (max_values: None, max_size: None, mode: Measured) - fn register() -> Weight { - // Proof Size summary in bytes: - // Measured: `616` - // Estimated: `4081` - // Minimum execution time: 6_332_113_000 picoseconds. - Weight::from_parts(6_407_158_000, 0) - .saturating_add(Weight::from_parts(0, 4081)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(8)) - } - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:1 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CodeByHashRefs (r:1 w:1) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:0 w:1) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpcomingParasGenesis (r:0 w:1) - /// Proof Skipped: Paras UpcomingParasGenesis (max_values: None, max_size: None, mode: Measured) - fn force_register() -> Weight { - // Proof Size summary in bytes: - // Measured: `533` - // Estimated: `3998` - // Minimum execution time: 6_245_403_000 picoseconds. - Weight::from_parts(6_289_575_000, 0) - .saturating_add(Weight::from_parts(0, 3998)) - .saturating_add(T::DbWeight::get().reads(8)) - .saturating_add(T::DbWeight::get().writes(8)) - } - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras FutureCodeHash (r:1 w:0) - /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: MessageQueue BookStateFor (r:1 w:0) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: Registrar PendingSwap (r:0 w:1) - /// Proof Skipped: Registrar PendingSwap (max_values: None, max_size: None, mode: Measured) - fn deregister() -> Weight { - // Proof Size summary in bytes: - // Measured: `476` - // Estimated: `3941` - // Minimum execution time: 49_822_000 picoseconds. - Weight::from_parts(50_604_000, 0) - .saturating_add(Weight::from_parts(0, 3941)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: Registrar Paras (r:1 w:0) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:2 w:2) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: Registrar PendingSwap (r:1 w:1) - /// Proof Skipped: Registrar PendingSwap (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: Crowdloan Funds (r:2 w:2) - /// Proof Skipped: Crowdloan Funds (max_values: None, max_size: None, mode: Measured) - /// Storage: Slots Leases (r:2 w:2) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - fn swap() -> Weight { - // Proof Size summary in bytes: - // Measured: `780` - // Estimated: `6720` - // Minimum execution time: 55_166_000 picoseconds. - Weight::from_parts(56_913_000, 0) - .saturating_add(Weight::from_parts(0, 6720)) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(8)) - } - /// Storage: Paras FutureCodeHash (r:1 w:1) - /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeRestrictionSignal (r:1 w:1) - /// Proof Skipped: Paras UpgradeRestrictionSignal (max_values: None, max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:1 w:0) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeCooldowns (r:1 w:1) - /// Proof Skipped: Paras UpgradeCooldowns (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:1 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CodeByHashRefs (r:1 w:1) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// The range of component `b` is `[1, 3145728]`. - fn schedule_code_upgrade(b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `464` - // Estimated: `3929` - // Minimum execution time: 43_650_000 picoseconds. - Weight::from_parts(43_918_000, 0) - .saturating_add(Weight::from_parts(0, 3929)) - // Standard Error: 6 - .saturating_add(Weight::from_parts(2_041, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().reads(10)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// The range of component `b` is `[1, 1048576]`. - fn set_current_head(b: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_666_000 picoseconds. - Weight::from_parts(8_893_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2 - .saturating_add(Weight::from_parts(855, 0).saturating_mul(b.into())) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/rococo/src/weights/runtime_common_slots.rs b/polkadot/runtime/rococo/src/weights/runtime_common_slots.rs deleted file mode 100644 index 8c601aa8486f..000000000000 --- a/polkadot/runtime/rococo/src/weights/runtime_common_slots.rs +++ /dev/null @@ -1,132 +0,0 @@ -// 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 `runtime_common::slots` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --pallet=runtime_common::slots -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_common_slots.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 `runtime_common::slots`. -pub struct WeightInfo(PhantomData); -impl polkadot_runtime_common::slots::WeightInfo for WeightInfo { - /// Storage: Slots Leases (r:1 w:1) - /// Proof Skipped: Slots Leases (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) - fn force_lease() -> Weight { - // Proof Size summary in bytes: - // Measured: `287` - // Estimated: `3752` - // Minimum execution time: 29_932_000 picoseconds. - Weight::from_parts(30_334_000, 0) - .saturating_add(Weight::from_parts(0, 3752)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: Paras Parachains (r:1 w:0) - /// Proof Skipped: Paras Parachains (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Slots Leases (r:101 w:100) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:200 w:200) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: Registrar Paras (r:100 w:100) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - /// The range of component `c` is `[0, 100]`. - /// The range of component `t` is `[0, 100]`. - fn manage_lease_period_start(c: u32, t: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `26 + c * (47 ±0) + t * (308 ±0)` - // Estimated: `2800 + c * (2526 ±0) + t * (2789 ±0)` - // Minimum execution time: 634_547_000 picoseconds. - Weight::from_parts(643_045_000, 0) - .saturating_add(Weight::from_parts(0, 2800)) - // Standard Error: 81_521 - .saturating_add(Weight::from_parts(2_705_219, 0).saturating_mul(c.into())) - // Standard Error: 81_521 - .saturating_add(Weight::from_parts(11_464_132, 0).saturating_mul(t.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(c.into()))) - .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(t.into()))) - .saturating_add(T::DbWeight::get().writes(1)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(c.into()))) - .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(t.into()))) - .saturating_add(Weight::from_parts(0, 2526).saturating_mul(c.into())) - .saturating_add(Weight::from_parts(0, 2789).saturating_mul(t.into())) - } - /// Storage: Slots Leases (r:1 w:1) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: System Account (r:8 w:8) - /// Proof: System Account (max_values: None, max_size: Some(128), added: 2603, mode: MaxEncodedLen) - fn clear_all_leases() -> Weight { - // Proof Size summary in bytes: - // Measured: `2759` - // Estimated: `21814` - // Minimum execution time: 129_756_000 picoseconds. - Weight::from_parts(131_810_000, 0) - .saturating_add(Weight::from_parts(0, 21814)) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(9)) - } - /// Storage: Slots Leases (r:1 w:0) - /// Proof Skipped: Slots Leases (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras ParaLifecycles (r:1 w:1) - /// Proof Skipped: Paras ParaLifecycles (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// Storage: Registrar Paras (r:1 w:1) - /// Proof Skipped: Registrar Paras (max_values: None, max_size: None, mode: Measured) - fn trigger_onboard() -> Weight { - // Proof Size summary in bytes: - // Measured: `707` - // Estimated: `4172` - // Minimum execution time: 29_527_000 picoseconds. - Weight::from_parts(30_055_000, 0) - .saturating_add(Weight::from_parts(0, 4172)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } -} diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_inclusion.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_inclusion.rs deleted file mode 100644 index da1b7a0dad9a..000000000000 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_inclusion.rs +++ /dev/null @@ -1,74 +0,0 @@ -// 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 `runtime_parachains::inclusion` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --pallet=runtime_parachains::inclusion -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_parachains_inclusion.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 `runtime_parachains::inclusion`. -pub struct WeightInfo(PhantomData); -impl polkadot_runtime_parachains::inclusion::WeightInfo for WeightInfo { - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:999) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(32818), added: 35293, mode: MaxEncodedLen) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// The range of component `i` is `[1, 1000]`. - fn receive_upward_messages(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `33280` - // Estimated: `36283` - // Minimum execution time: 71_094_000 picoseconds. - Weight::from_parts(71_436_000, 0) - .saturating_add(Weight::from_parts(0, 36283)) - // Standard Error: 22_149 - .saturating_add(Weight::from_parts(51_495_472, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) - } -} diff --git a/polkadot/runtime/rococo/src/weights/runtime_parachains_paras.rs b/polkadot/runtime/rococo/src/weights/runtime_parachains_paras.rs deleted file mode 100644 index 2dcabb7c36bb..000000000000 --- a/polkadot/runtime/rococo/src/weights/runtime_parachains_paras.rs +++ /dev/null @@ -1,294 +0,0 @@ -// 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 `runtime_parachains::paras` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-05-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bm5`, CPU: `Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("rococo-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=rococo-dev -// --steps=50 -// --repeat=20 -// --pallet=runtime_parachains::paras -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/rococo/src/weights/runtime_parachains_paras.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 `runtime_parachains::paras`. -pub struct WeightInfo(PhantomData); -impl polkadot_runtime_parachains::paras::WeightInfo for WeightInfo { - /// Storage: Paras CurrentCodeHash (r:1 w:1) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHashRefs (r:1 w:1) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PastCodeMeta (r:1 w:1) - /// Proof Skipped: Paras PastCodeMeta (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PastCodePruning (r:1 w:1) - /// Proof Skipped: Paras PastCodePruning (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PastCodeHash (r:0 w:1) - /// Proof Skipped: Paras PastCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:0 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - /// The range of component `c` is `[1, 3145728]`. - fn force_set_current_code(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `8309` - // Estimated: `11774` - // Minimum execution time: 31_941_000 picoseconds. - Weight::from_parts(32_139_000, 0) - .saturating_add(Weight::from_parts(0, 11774)) - // Standard Error: 5 - .saturating_add(Weight::from_parts(2_011, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(6)) - } - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// The range of component `s` is `[1, 1048576]`. - fn force_set_current_head(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_275_000 picoseconds. - Weight::from_parts(8_321_000, 0) - .saturating_add(Weight::from_parts(0, 0)) - // Standard Error: 2 - .saturating_add(Weight::from_parts(858, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage: Paras Heads (r:0 w:1) - fn force_set_most_recent_context() -> Weight { - Weight::from_parts(10_155_000, 0) - // Standard Error: 0 - .saturating_add(T::DbWeight::get().writes(1 as u64)) - } - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras FutureCodeHash (r:1 w:1) - /// Proof Skipped: Paras FutureCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CurrentCodeHash (r:1 w:0) - /// Proof Skipped: Paras CurrentCodeHash (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeCooldowns (r:1 w:1) - /// Proof Skipped: Paras UpgradeCooldowns (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:1 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras CodeByHashRefs (r:1 w:1) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeRestrictionSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeRestrictionSignal (max_values: None, max_size: None, mode: Measured) - /// The range of component `c` is `[1, 3145728]`. - fn force_schedule_code_upgrade(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `8715` - // Estimated: `12180` - // Minimum execution time: 49_923_000 picoseconds. - Weight::from_parts(50_688_000, 0) - .saturating_add(Weight::from_parts(0, 12180)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_976, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(9)) - .saturating_add(T::DbWeight::get().writes(7)) - } - /// Storage: Paras FutureCodeUpgrades (r:1 w:0) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras Heads (r:0 w:1) - /// Proof Skipped: Paras Heads (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras UpgradeGoAheadSignal (r:0 w:1) - /// Proof Skipped: Paras UpgradeGoAheadSignal (max_values: None, max_size: None, mode: Measured) - /// The range of component `s` is `[1, 1048576]`. - fn force_note_new_head(s: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `95` - // Estimated: `3560` - // Minimum execution time: 14_408_000 picoseconds. - Weight::from_parts(14_647_000, 0) - .saturating_add(Weight::from_parts(0, 3560)) - // Standard Error: 2 - .saturating_add(Weight::from_parts(858, 0).saturating_mul(s.into())) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - fn force_queue_action() -> Weight { - // Proof Size summary in bytes: - // Measured: `4288` - // Estimated: `7753` - // Minimum execution time: 20_009_000 picoseconds. - Weight::from_parts(20_518_000, 0) - .saturating_add(Weight::from_parts(0, 7753)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - /// The range of component `c` is `[1, 3145728]`. - fn add_trusted_validation_code(c: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `946` - // Estimated: `4411` - // Minimum execution time: 80_626_000 picoseconds. - Weight::from_parts(52_721_755, 0) - .saturating_add(Weight::from_parts(0, 4411)) - // Standard Error: 1 - .saturating_add(Weight::from_parts(1_443, 0).saturating_mul(c.into())) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: Paras CodeByHashRefs (r:1 w:0) - /// Proof Skipped: Paras CodeByHashRefs (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras CodeByHash (r:0 w:1) - /// Proof Skipped: Paras CodeByHash (max_values: None, max_size: None, mode: Measured) - fn poke_unused_validation_code() -> Weight { - // Proof Size summary in bytes: - // Measured: `28` - // Estimated: `3493` - // Minimum execution time: 6_692_000 picoseconds. - Weight::from_parts(7_009_000, 0) - .saturating_add(Weight::from_parts(0, 3493)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - fn include_pvf_check_statement() -> Weight { - // Proof Size summary in bytes: - // Measured: `26682` - // Estimated: `30147` - // Minimum execution time: 87_994_000 picoseconds. - Weight::from_parts(89_933_000, 0) - .saturating_add(Weight::from_parts(0, 30147)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras UpcomingUpgrades (r:1 w:1) - /// Proof Skipped: Paras UpcomingUpgrades (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) - /// Storage: Paras FutureCodeUpgrades (r:0 w:100) - /// Proof Skipped: Paras FutureCodeUpgrades (max_values: None, max_size: None, mode: Measured) - fn include_pvf_check_statement_finalize_upgrade_accept() -> Weight { - // Proof Size summary in bytes: - // Measured: `27523` - // Estimated: `30988` - // Minimum execution time: 783_222_000 picoseconds. - Weight::from_parts(794_959_000, 0) - .saturating_add(Weight::from_parts(0, 30988)) - .saturating_add(T::DbWeight::get().reads(7)) - .saturating_add(T::DbWeight::get().writes(104)) - } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - fn include_pvf_check_statement_finalize_upgrade_reject() -> Weight { - // Proof Size summary in bytes: - // Measured: `27214` - // Estimated: `30679` - // Minimum execution time: 87_424_000 picoseconds. - Weight::from_parts(88_737_000, 0) - .saturating_add(Weight::from_parts(0, 30679)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteList (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteList (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Configuration ActiveConfig (r:1 w:0) - /// Proof Skipped: Configuration ActiveConfig (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras ActionsQueue (r:1 w:1) - /// Proof Skipped: Paras ActionsQueue (max_values: None, max_size: None, mode: Measured) - fn include_pvf_check_statement_finalize_onboarding_accept() -> Weight { - // Proof Size summary in bytes: - // Measured: `26991` - // Estimated: `30456` - // Minimum execution time: 612_485_000 picoseconds. - Weight::from_parts(621_670_000, 0) - .saturating_add(Weight::from_parts(0, 30456)) - .saturating_add(T::DbWeight::get().reads(6)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: ParasShared ActiveValidatorKeys (r:1 w:0) - /// Proof Skipped: ParasShared ActiveValidatorKeys (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: ParasShared CurrentSessionIndex (r:1 w:0) - /// Proof Skipped: ParasShared CurrentSessionIndex (max_values: Some(1), max_size: None, mode: Measured) - /// Storage: Paras PvfActiveVoteMap (r:1 w:1) - /// Proof Skipped: Paras PvfActiveVoteMap (max_values: None, max_size: None, mode: Measured) - fn include_pvf_check_statement_finalize_onboarding_reject() -> Weight { - // Proof Size summary in bytes: - // Measured: `26682` - // Estimated: `30147` - // Minimum execution time: 86_673_000 picoseconds. - Weight::from_parts(87_424_000, 0) - .saturating_add(Weight::from_parts(0, 30147)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} 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 60c40429b1ac..7d743b209124 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 96416821e4c8..05e0ee64820a 100644 --- a/polkadot/runtime/rococo/src/xcm_config.rs +++ b/polkadot/runtime/rococo/src/xcm_config.rs @@ -41,10 +41,10 @@ use xcm_builder::{ AllowSubscriptionsFrom, AllowTopLevelPaidExecutionFrom, ChildParachainAsNative, ChildParachainConvertsVia, DescribeAllTerminal, DescribeFamily, FixedWeightBounds, FrameTransactionalProcessor, FungibleAdapter, HashedDescription, IsChildSystemParachain, - IsConcrete, MintLocation, OriginToPluralityVoice, SignedAccountId32AsNative, - SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId, - UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, - XcmFeeManagerFromComponents, XcmFeeToAccount, + IsConcrete, MintLocation, OriginToPluralityVoice, SendXcmFeeToAccount, + SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, + TrailingSetTopicAsId, UsingComponents, WeightInfoBounds, WithComputedOrigin, WithUniqueTopic, + XcmFeeManagerFromComponents, }; use xcm_executor::XcmExecutor; @@ -213,7 +213,7 @@ impl xcm_executor::Config for XcmConfig { type MaxAssetsIntoHolding = MaxAssetsIntoHolding; type FeeManager = XcmFeeManagerFromComponents< WaivedLocations, - XcmFeeToAccount, + SendXcmFeeToAccount, >; type MessageExporter = (); type UniversalAliases = Nothing; diff --git a/polkadot/runtime/test-runtime/Cargo.toml b/polkadot/runtime/test-runtime/Cargo.toml index ac379b69e3f2..90a0285cd17b 100644 --- a/polkadot/runtime/test-runtime/Cargo.toml +++ b/polkadot/runtime/test-runtime/Cargo.toml @@ -144,6 +144,7 @@ runtime-benchmarks = [ "pallet-staking/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", diff --git a/polkadot/runtime/test-runtime/constants/src/weights/block_weights.rs b/polkadot/runtime/test-runtime/constants/src/weights/block_weights.rs index e7fdb2aae2a0..07316759104f 100644 --- a/polkadot/runtime/test-runtime/constants/src/weights/block_weights.rs +++ b/polkadot/runtime/test-runtime/constants/src/weights/block_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Polkadot. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/polkadot/runtime/test-runtime/constants/src/weights/extrinsic_weights.rs b/polkadot/runtime/test-runtime/constants/src/weights/extrinsic_weights.rs index 1a4adb968bb7..d0af4ec8921d 100644 --- a/polkadot/runtime/test-runtime/constants/src/weights/extrinsic_weights.rs +++ b/polkadot/runtime/test-runtime/constants/src/weights/extrinsic_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Polkadot. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/polkadot/runtime/test-runtime/constants/src/weights/mod.rs b/polkadot/runtime/test-runtime/constants/src/weights/mod.rs index 30fa2c406068..d9087d7f057e 100644 --- a/polkadot/runtime/test-runtime/constants/src/weights/mod.rs +++ b/polkadot/runtime/test-runtime/constants/src/weights/mod.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Polkadot. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/polkadot/runtime/test-runtime/constants/src/weights/paritydb_weights.rs b/polkadot/runtime/test-runtime/constants/src/weights/paritydb_weights.rs index 25679703831a..67d5286022ee 100644 --- a/polkadot/runtime/test-runtime/constants/src/weights/paritydb_weights.rs +++ b/polkadot/runtime/test-runtime/constants/src/weights/paritydb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Polkadot. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/polkadot/runtime/test-runtime/constants/src/weights/rocksdb_weights.rs b/polkadot/runtime/test-runtime/constants/src/weights/rocksdb_weights.rs index 3dd817aa6f13..57f49e1202c1 100644 --- a/polkadot/runtime/test-runtime/constants/src/weights/rocksdb_weights.rs +++ b/polkadot/runtime/test-runtime/constants/src/weights/rocksdb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Polkadot. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs index a8a369a68e66..9e7ee488af72 100644 --- a/polkadot/runtime/test-runtime/src/lib.rs +++ b/polkadot/runtime/test-runtime/src/lib.rs @@ -31,15 +31,13 @@ use codec::Encode; use pallet_transaction_payment::FungibleAdapter; use polkadot_runtime_parachains::{ - assigner_parachains as parachains_assigner_parachains, - configuration as parachains_configuration, - configuration::ActiveConfigHrmpChannelSizeAndCapacityRatio, - disputes as parachains_disputes, - disputes::slashing as parachains_slashing, + 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, - initializer as parachains_initializer, origin as parachains_origin, paras as parachains_paras, - paras_inherent as parachains_paras_inherent, - runtime_api_impl::{v10 as runtime_impl, vstaging as vstaging_parachains_runtime_api_impl}, + 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::v11 as runtime_impl, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; @@ -51,18 +49,24 @@ use frame_election_provider_support::{ use frame_support::{ construct_runtime, derive_impl, genesis_builder_helper::{build_state, get_preset}, + pallet_prelude::Get, parameter_types, traits::{KeyOwnerProofSystem, WithdrawReasons}, + PalletId, }; use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId}; use pallet_session::historical as session_historical; use pallet_timestamp::Now; use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo}; use polkadot_primitives::{ - slashing, AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CandidateHash, - CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, - GroupRotationInfo, Hash as HashT, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, - Moment, Nonce, OccupiedCoreAssumption, PersistedValidationData, ScrapedOnChainVotes, + slashing, + vstaging::{ + CandidateEvent, CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CoreState, + ScrapedOnChainVotes, + }, + AccountId, AccountIndex, Balance, BlockNumber, CandidateHash, CoreIndex, DisputeState, + ExecutorParams, GroupRotationInfo, Hash as HashT, Id as ParaId, InboundDownwardMessage, + InboundHrmpMessage, Moment, Nonce, OccupiedCoreAssumption, PersistedValidationData, SessionInfo as SessionInfoData, Signature, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex, PARACHAIN_KEY_TYPE_ID, }; @@ -80,8 +84,8 @@ use sp_runtime::{ curve::PiecewiseLinear, generic, impl_opaque_keys, traits::{ - BlakeTwo256, Block as BlockT, ConvertInto, Extrinsic as ExtrinsicT, OpaqueKeys, - SaturatedConversion, StaticLookup, Verify, + BlakeTwo256, Block as BlockT, ConvertInto, OpaqueKeys, SaturatedConversion, StaticLookup, + Verify, }, transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity}, ApplyExtrinsicResult, FixedU128, KeyTypeId, Perbill, Percent, @@ -90,6 +94,7 @@ use sp_staking::SessionIndex; #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; use sp_version::RuntimeVersion; +use xcm::v4::{Assets, InteriorLocation, Location, SendError, SendResult, SendXcm, XcmHash}; pub use pallet_balances::Call as BalancesCall; #[cfg(feature = "std")] @@ -121,7 +126,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 1, - state_version: 1, + system_version: 1, }; /// The BABE epoch configuration at genesis. @@ -165,14 +170,34 @@ impl frame_system::Config for Runtime { type MaxConsumers = frame_support::traits::ConstU32<16>; } -impl frame_system::offchain::SendTransactionTypes for Runtime +impl frame_system::offchain::CreateTransactionBase for Runtime where RuntimeCall: From, { - type OverarchingCall = RuntimeCall; + type RuntimeCall = RuntimeCall; type Extrinsic = UncheckedExtrinsic; } +impl frame_system::offchain::CreateInherent for Runtime +where + RuntimeCall: From, +{ + fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic { + UncheckedExtrinsic::new_bare(call) + } +} + +impl frame_system::offchain::CreateTransaction for Runtime +where + RuntimeCall: From, +{ + type Extension = TxExtension; + + fn create_transaction(call: Self::RuntimeCall, extension: Self::Extension) -> Self::Extrinsic { + UncheckedExtrinsic::new_transaction(call, extension) + } +} + parameter_types! { pub storage EpochDuration: u64 = EPOCH_DURATION_IN_SLOTS as u64; pub storage ExpectedBlockTime: Moment = MILLISECS_PER_BLOCK; @@ -232,6 +257,7 @@ impl pallet_balances::Config for Runtime { type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxFreezes = ConstU32<0>; + type DoneSlashHandler = (); } parameter_types! { @@ -248,6 +274,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = frame_support::weights::ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type WeightInfo = (); } parameter_types! { @@ -392,18 +419,20 @@ impl frame_system::offchain::CreateSignedTransaction for R where RuntimeCall: From, { - fn create_transaction>( + fn create_signed_transaction< + C: frame_system::offchain::AppCrypto, + >( call: RuntimeCall, public: ::Signer, account: AccountId, nonce: ::Nonce, - ) -> Option<(RuntimeCall, ::SignaturePayload)> { + ) -> Option { let period = BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64; let current_block = System::block_number().saturated_into::().saturating_sub(1); let tip = 0; - let extra: SignedExtra = ( + let tx_ext: TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -415,16 +444,18 @@ where frame_system::CheckNonce::::from(nonce), frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), - ); - let raw_payload = SignedPayload::new(call, extra) + ) + .into(); + let raw_payload = SignedPayload::new(call, tx_ext) .map_err(|e| { log::warn!("Unable to create signed payload: {:?}", e); }) .ok()?; let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?; - let (call, extra, _) = raw_payload.deconstruct(); + let (call, tx_ext, _) = raw_payload.deconstruct(); let address = Indices::unlookup(account); - Some((call, (address, signature, extra))) + let transaction = UncheckedExtrinsic::new_signed(call, address, signature, tx_ext); + Some(transaction) } } @@ -531,7 +562,7 @@ impl parachains_initializer::Config for Runtime { type Randomness = pallet_babe::RandomnessFromOneEpochAgo; type ForceOrigin = frame_system::EnsureRoot; type WeightInfo = (); - type CoretimeOnNewSession = (); + type CoretimeOnNewSession = Coretime; } impl parachains_session_info::Config for Runtime { @@ -549,15 +580,26 @@ impl parachains_paras::Config for Runtime { type QueueFootprinter = ParaInclusion; type NextSessionRotation = Babe; type OnNewHead = (); - type AssignCoretime = (); + type AssignCoretime = CoretimeAssignmentProvider; } parameter_types! { pub const BrokerId: u32 = 10u32; + pub MaxXcmTransactWeight: Weight = Weight::from_parts(10_000_000, 10_000); +} + +pub struct BrokerPot; +impl Get for BrokerPot { + fn get() -> InteriorLocation { + unimplemented!() + } } parameter_types! { pub const OnDemandTrafficDefaultValue: FixedU128 = FixedU128::from_u32(1); + // Keep 2 timeslices worth of revenue information. + pub const MaxHistoricalRevenue: BlockNumber = 2 * 5; + pub const OnDemandPalletId: PalletId = PalletId(*b"py/ondmd"); } impl parachains_dmp::Config for Runtime {} @@ -579,10 +621,48 @@ impl parachains_hrmp::Config for Runtime { type WeightInfo = parachains_hrmp::TestWeightInfo; } -impl parachains_assigner_parachains::Config for Runtime {} +impl parachains_on_demand::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type TrafficDefaultValue = OnDemandTrafficDefaultValue; + type WeightInfo = parachains_on_demand::TestWeightInfo; + type MaxHistoricalRevenue = MaxHistoricalRevenue; + type PalletId = OnDemandPalletId; +} + +impl parachains_assigner_coretime::Config for Runtime {} impl parachains_scheduler::Config for Runtime { - type AssignmentProvider = ParaAssignmentProvider; + type AssignmentProvider = CoretimeAssignmentProvider; +} + +pub struct DummyXcmSender; +impl SendXcm for DummyXcmSender { + type Ticket = (); + fn validate( + _: &mut Option, + _: &mut Option>, + ) -> SendResult { + Ok(((), Assets::new())) + } + + /// Actually carry out the delivery operation for a previously validated message sending. + fn deliver(_ticket: Self::Ticket) -> Result { + Ok([0u8; 32]) + } +} + +impl coretime::Config for Runtime { + type RuntimeOrigin = RuntimeOrigin; + type RuntimeEvent = RuntimeEvent; + type Currency = pallet_balances::Pallet; + type BrokerId = BrokerId; + type WeightInfo = crate::coretime::TestWeightInfo; + type SendXcm = DummyXcmSender; + type MaxXcmTransactWeight = MaxXcmTransactWeight; + type BrokerPotLocation = BrokerPot; + type AssetTransactor = (); + type AccountToLocation = (); } impl paras_sudo_wrapper::Config for Runtime {} @@ -725,7 +805,9 @@ construct_runtime! { Xcm: pallet_xcm, ParasDisputes: parachains_disputes, ParasSlashing: parachains_slashing, - ParaAssignmentProvider: parachains_assigner_parachains, + OnDemandAssignmentProvider: parachains_on_demand, + CoretimeAssignmentProvider: parachains_assigner_coretime, + Coretime: coretime, Sudo: pallet_sudo, @@ -743,8 +825,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// `BlockId` type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The `SignedExtension` to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -756,7 +838,10 @@ pub type SignedExtra = ( ); /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; +/// Unchecked signature payload type as expected by this runtime. +pub type UncheckedSignaturePayload = + generic::UncheckedSignaturePayload; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< @@ -767,7 +852,7 @@ pub type Executive = frame_executive::Executive< AllPalletsWithSystem, >; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; pub type Hash = ::Hash; pub type Extrinsic = ::Extrinsic; @@ -978,7 +1063,7 @@ sp_api::impl_runtime_apis! { runtime_impl::minimum_backing_votes::() } - fn para_backing_state(para_id: ParaId) -> Option { + fn para_backing_state(para_id: ParaId) -> Option { runtime_impl::backing_state::(para_id) } @@ -999,11 +1084,11 @@ sp_api::impl_runtime_apis! { } fn claim_queue() -> BTreeMap> { - vstaging_parachains_runtime_api_impl::claim_queue::() + runtime_impl::claim_queue::() } fn candidates_pending_availability(para_id: ParaId) -> Vec> { - vstaging_parachains_runtime_api_impl::candidates_pending_availability::(para_id) + runtime_impl::candidates_pending_availability::(para_id) } } @@ -1029,12 +1114,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 9e739f4c7fe6..fcb5719de895 100644 --- a/polkadot/runtime/westend/Cargo.toml +++ b/polkadot/runtime/westend/Cargo.toml @@ -17,11 +17,13 @@ scale-info = { features = ["derive"], workspace = true } log = { workspace = true } serde = { workspace = true } serde_derive = { optional = true, workspace = true } +serde_json = { features = ["alloc"], workspace = true } smallvec = { workspace = true, default-features = true } sp-authority-discovery = { workspace = true } sp-consensus-babe = { workspace = true } sp-consensus-beefy = { workspace = true } +sp-consensus-grandpa = { workspace = true } binary-merkle-tree = { workspace = true } sp-inherents = { workspace = true } sp-offchain = { workspace = true } @@ -40,6 +42,7 @@ sp-version = { workspace = true } sp-transaction-pool = { workspace = true } sp-block-builder = { workspace = true } sp-npos-elections = { workspace = true } +sp-keyring = { workspace = true } frame-election-provider-support = { workspace = true } frame-executive = { workspace = true } @@ -71,6 +74,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 +83,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 } @@ -103,7 +106,7 @@ pallet-election-provider-support-benchmarking = { optional = true, workspace = t pallet-nomination-pools-benchmarking = { optional = true, workspace = true } pallet-offences-benchmarking = { optional = true, workspace = true } pallet-session-benchmarking = { optional = true, workspace = true } -hex-literal = { optional = true, workspace = true, default-features = true } +hex-literal = { workspace = true, default-features = true } polkadot-runtime-common = { workspace = true } polkadot-primitives = { workspace = true } @@ -116,7 +119,7 @@ xcm-builder = { workspace = true } xcm-runtime-apis = { workspace = true } [dev-dependencies] -hex-literal = { workspace = true, default-features = true } +approx = { workspace = true } tiny-keccak = { features = ["keccak"], workspace = true } sp-keyring = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } @@ -173,6 +176,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", @@ -202,6 +206,7 @@ std = [ "scale-info/std", "serde/std", "serde_derive", + "serde_json/std", "sp-api/std", "sp-application-crypto/std", "sp-arithmetic/std", @@ -209,6 +214,7 @@ std = [ "sp-block-builder/std", "sp-consensus-babe/std", "sp-consensus-beefy/std", + "sp-consensus-grandpa/std", "sp-core/std", "sp-genesis-builder/std", "sp-inherents/std", @@ -235,11 +241,11 @@ runtime-benchmarks = [ "frame-support/runtime-benchmarks", "frame-system-benchmarking/runtime-benchmarks", "frame-system/runtime-benchmarks", - "hex-literal", "pallet-asset-rate/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 +265,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", @@ -270,6 +277,7 @@ runtime-benchmarks = [ "pallet-state-trie-migration/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", + "pallet-transaction-payment/runtime-benchmarks", "pallet-treasury/runtime-benchmarks", "pallet-utility/runtime-benchmarks", "pallet-vesting/runtime-benchmarks", @@ -317,6 +325,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,9 +355,12 @@ 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 # to make it smaller, like logging for example. -on-chain-release-build = ["metadata-hash", "sp-api/disable-logging"] +on-chain-release-build = ["metadata-hash"] diff --git a/polkadot/runtime/westend/build.rs b/polkadot/runtime/westend/build.rs index 8ff3a4fb9112..cf4097a2da6c 100644 --- a/polkadot/runtime/westend/build.rs +++ b/polkadot/runtime/westend/build.rs @@ -6,7 +6,7 @@ // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// Substrate is distributed in the hope that it will be useful, +// 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. @@ -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 f9b99ea5284d..27d5b19b8e77 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/constants/src/weights/mod.rs b/polkadot/runtime/westend/constants/src/weights/mod.rs index 23812ce7ed05..2648608a2f8a 100644 --- a/polkadot/runtime/westend/constants/src/weights/mod.rs +++ b/polkadot/runtime/westend/constants/src/weights/mod.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Polkadot. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/polkadot/runtime/westend/constants/src/weights/paritydb_weights.rs b/polkadot/runtime/westend/constants/src/weights/paritydb_weights.rs index 25679703831a..67d5286022ee 100644 --- a/polkadot/runtime/westend/constants/src/weights/paritydb_weights.rs +++ b/polkadot/runtime/westend/constants/src/weights/paritydb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Polkadot. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/polkadot/runtime/westend/constants/src/weights/rocksdb_weights.rs b/polkadot/runtime/westend/constants/src/weights/rocksdb_weights.rs index 3dd817aa6f13..57f49e1202c1 100644 --- a/polkadot/runtime/westend/constants/src/weights/rocksdb_weights.rs +++ b/polkadot/runtime/westend/constants/src/weights/rocksdb_weights.rs @@ -1,4 +1,4 @@ -// This file is part of Substrate. +// This file is part of Polkadot. // Copyright (C) Parity Technologies (UK) Ltd. // SPDX-License-Identifier: Apache-2.0 diff --git a/polkadot/runtime/westend/src/genesis_config_presets.rs b/polkadot/runtime/westend/src/genesis_config_presets.rs new file mode 100644 index 000000000000..621ef38f0b75 --- /dev/null +++ b/polkadot/runtime/westend/src/genesis_config_presets.rs @@ -0,0 +1,441 @@ +// 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 . + +//! Genesis configs presets for the Westend runtime + +use crate::{ + BabeConfig, BalancesConfig, ConfigurationConfig, RegistrarConfig, RuntimeGenesisConfig, + SessionConfig, SessionKeys, StakingConfig, SudoConfig, BABE_GENESIS_EPOCH_CONFIG, +}; +#[cfg(not(feature = "std"))] +use alloc::format; +use alloc::{vec, vec::Vec}; +use pallet_staking::{Forcing, StakerStatus}; +use polkadot_primitives::{AccountId, AssignmentId, SchedulerParams, ValidatorId}; +use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; +use sp_consensus_babe::AuthorityId as BabeId; +use sp_consensus_beefy::ecdsa_crypto::AuthorityId as BeefyId; +use sp_consensus_grandpa::AuthorityId as GrandpaId; +use sp_core::{crypto::get_public_from_string_or_panic, sr25519}; +use sp_genesis_builder::PresetId; +use sp_keyring::Sr25519Keyring; +use sp_runtime::Perbill; +use westend_runtime_constants::currency::UNITS as WND; + +/// Helper function to generate stash, controller and session key from seed +fn get_authority_keys_from_seed( + seed: &str, +) -> ( + AccountId, + AccountId, + BabeId, + GrandpaId, + ValidatorId, + AssignmentId, + AuthorityDiscoveryId, + BeefyId, +) { + let keys = get_authority_keys_from_seed_no_beefy(seed); + ( + keys.0, + keys.1, + keys.2, + keys.3, + keys.4, + keys.5, + keys.6, + get_public_from_string_or_panic::(seed), + ) +} + +/// Helper function to generate stash, controller and session key from seed +fn get_authority_keys_from_seed_no_beefy( + seed: &str, +) -> (AccountId, AccountId, BabeId, GrandpaId, ValidatorId, AssignmentId, AuthorityDiscoveryId) { + ( + get_public_from_string_or_panic::(&format!("{}//stash", seed)).into(), + get_public_from_string_or_panic::(seed).into(), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + ) +} + +fn testnet_accounts() -> Vec { + Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect() +} + +fn westend_session_keys( + babe: BabeId, + grandpa: GrandpaId, + para_validator: ValidatorId, + para_assignment: AssignmentId, + authority_discovery: AuthorityDiscoveryId, + beefy: BeefyId, +) -> SessionKeys { + SessionKeys { babe, grandpa, para_validator, para_assignment, authority_discovery, beefy } +} + +fn default_parachains_host_configuration( +) -> polkadot_runtime_parachains::configuration::HostConfiguration +{ + use polkadot_primitives::{ + node_features::FeatureIndex, ApprovalVotingParams, AsyncBackingParams, MAX_CODE_SIZE, + MAX_POV_SIZE, + }; + + polkadot_runtime_parachains::configuration::HostConfiguration { + validation_upgrade_cooldown: 2u32, + validation_upgrade_delay: 2, + code_retention_period: 1200, + max_code_size: MAX_CODE_SIZE, + max_pov_size: MAX_POV_SIZE, + max_head_data_size: 32 * 1024, + max_upward_queue_count: 8, + max_upward_queue_size: 1024 * 1024, + max_downward_message_size: 1024 * 1024, + max_upward_message_size: 50 * 1024, + max_upward_message_num_per_candidate: 5, + hrmp_sender_deposit: 0, + hrmp_recipient_deposit: 0, + hrmp_channel_max_capacity: 8, + hrmp_channel_max_total_size: 8 * 1024, + hrmp_max_parachain_inbound_channels: 4, + hrmp_channel_max_message_size: 1024 * 1024, + hrmp_max_parachain_outbound_channels: 4, + hrmp_max_message_num_per_candidate: 5, + dispute_period: 6, + no_show_slots: 2, + n_delay_tranches: 25, + needed_approvals: 2, + relay_vrf_modulo_samples: 2, + zeroth_delay_tranche_width: 0, + minimum_validation_upgrade_delay: 5, + async_backing_params: AsyncBackingParams { + max_candidate_depth: 3, + allowed_ancestry_len: 2, + }, + node_features: bitvec::vec::BitVec::from_element( + 1u8 << (FeatureIndex::ElasticScalingMVP as usize) | + 1u8 << (FeatureIndex::EnableAssignmentsV2 as usize), + ), + scheduler_params: SchedulerParams { + lookahead: 2, + group_rotation_frequency: 20, + paras_availability_period: 4, + ..Default::default() + }, + approval_voting_params: ApprovalVotingParams { max_approval_coalesce_count: 5 }, + ..Default::default() + } +} + +#[test] +fn default_parachains_host_configuration_is_consistent() { + default_parachains_host_configuration().panic_if_not_consistent(); +} + +/// Helper function to create westend runtime `GenesisConfig` patch for testing +fn westend_testnet_genesis( + initial_authorities: Vec<( + AccountId, + AccountId, + BabeId, + GrandpaId, + ValidatorId, + AssignmentId, + AuthorityDiscoveryId, + BeefyId, + )>, + root_key: AccountId, + endowed_accounts: Option>, +) -> serde_json::Value { + let endowed_accounts: Vec = endowed_accounts.unwrap_or_else(testnet_accounts); + + const ENDOWMENT: u128 = 1_000_000 * WND; + const STASH: u128 = 100 * WND; + + let config = RuntimeGenesisConfig { + balances: BalancesConfig { + balances: endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect::>(), + }, + session: SessionConfig { + keys: initial_authorities + .iter() + .map(|x| { + ( + x.0.clone(), + x.0.clone(), + westend_session_keys( + x.2.clone(), + x.3.clone(), + x.4.clone(), + x.5.clone(), + x.6.clone(), + x.7.clone(), + ), + ) + }) + .collect::>(), + ..Default::default() + }, + staking: StakingConfig { + minimum_validator_count: 1, + validator_count: initial_authorities.len() as u32, + stakers: initial_authorities + .iter() + .map(|x| (x.0.clone(), x.0.clone(), STASH, StakerStatus::::Validator)) + .collect::>(), + invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect::>(), + force_era: Forcing::NotForcing, + slash_reward_fraction: Perbill::from_percent(10), + ..Default::default() + }, + babe: BabeConfig { epoch_config: BABE_GENESIS_EPOCH_CONFIG, ..Default::default() }, + sudo: SudoConfig { key: Some(root_key) }, + configuration: ConfigurationConfig { config: default_parachains_host_configuration() }, + registrar: RegistrarConfig { + next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID, + ..Default::default() + }, + ..Default::default() + }; + + serde_json::to_value(config).expect("Could not build genesis config.") +} + +// staging_testnet +fn westend_staging_testnet_config_genesis() -> serde_json::Value { + use hex_literal::hex; + use sp_core::crypto::UncheckedInto; + + // Following keys are used in genesis config for development chains. + // DO NOT use them in production chains as the secret seed is public. + // + // SECRET_SEED="slow awkward present example safe bundle science ocean cradle word tennis earn" + // subkey inspect -n polkadot "$SECRET_SEED" + let endowed_accounts = vec![ + // 15S75FkhCWEowEGfxWwVfrW3LQuy8w8PNhVmrzfsVhCMjUh1 + hex!["c416837e232d9603e83162ef4bda08e61580eeefe60fe92fc044aa508559ae42"].into(), + ]; + // SECRET=$SECRET_SEED ./scripts/prepare-test-net.sh 4 + let initial_authorities: Vec<( + AccountId, + AccountId, + BabeId, + GrandpaId, + ValidatorId, + AssignmentId, + AuthorityDiscoveryId, + BeefyId, + )> = Vec::from([ + ( + //5EvydUTtHvt39Khac3mMxNPgzcfu49uPDzUs3TL7KEzyrwbw + hex!["7ecfd50629cdd246649959d88d490b31508db511487e111a52a392e6e458f518"].into(), + //5HQyX5gyy77m9QLXguAhiwjTArHYjYspeY98dYDu1JDetfZg + hex!["eca2cca09bdc66a7e6d8c3d9499a0be2ad4690061be8a9834972e17d13d2fe7e"].into(), + //5G13qYRudTyttwTJvHvnwp8StFtcfigyPnwfD4v7LNopsnX4 + hex!["ae27367cb77850fb195fe1f9c60b73210409e68c5ad953088070f7d8513d464c"] + .unchecked_into(), + //5Eb7wM65PNgtY6e33FEAzYtU5cRTXt6WQvZTnzaKQwkVcABk + hex!["6faae44b21c6f2681a7f60df708e9f79d340f7d441d28bd987fab8d05c6487e8"] + .unchecked_into(), + //5FqMLAgygdX9UqzukDp15Uid9PAKdFAR621U7xtp5ut2NfrW + hex!["a6c1a5b501985a83cb1c37630c5b41e6b0a15b3675b2fd94694758e6cfa6794d"] + .unchecked_into(), + //5DhXAV75BKvF9o447ikWqLttyL2wHtLMFSX7GrsKF9Ny61Ta + hex!["485051748ab9c15732f19f3fbcf1fd00a6d9709635f084505107fbb059c33d2f"] + .unchecked_into(), + //5GNHfmrtWLTawnGCmc39rjAEiW97vKvE7DGePYe4am5JtE4i + hex!["be59ed75a72f7b47221ce081ba4262cf2e1ea7867e30e0b3781822f942b97677"] + .unchecked_into(), + //5DA6Z8RUF626stn94aTRBCeobDCYcFbU7Pdk4Tz1R9vA8B8F + hex!["0207e43990799e1d02b0507451e342a1240ff836ea769c57297589a5fd072ad8f4"] + .unchecked_into(), + ), + ( + //5DFpvDUdCgw54E3E357GR1PyJe3Ft9s7Qyp7wbELAoJH9RQa + hex!["34b7b3efd35fcc3c1926ca065381682b1af29b57dabbcd091042c6de1d541b7d"].into(), + //5DZSSsND5wCjngvyXv27qvF3yPzt3MCU8rWnqNy4imqZmjT8 + hex!["4226796fa792ac78875e023ff2e30e3c2cf79f0b7b3431254cd0f14a3007bc0e"].into(), + //5CPrgfRNDQvQSnLRdeCphP3ibj5PJW9ESbqj2fw29vBMNQNn + hex!["0e9b60f04be3bffe362eb2212ea99d2b909b052f4bff7c714e13c2416a797f5d"] + .unchecked_into(), + //5FXFsPReTUEYPRNKhbTdUathcWBsxTNsLbk2mTpYdKCJewjA + hex!["98f4d81cb383898c2c3d54dab28698c0f717c81b509cb32dc6905af3cc697b18"] + .unchecked_into(), + //5CZjurB78XbSHf6SLkLhCdkqw52Zm7aBYUDdfkLqEDWJ9Zhj + hex!["162508accd470e379b04cb0c7c60b35a7d5357e84407a89ed2dd48db4b726960"] + .unchecked_into(), + //5DkAqCtSjUMVoJFauuGoAbSEgn2aFCRGziKJiLGpPwYgE1pS + hex!["4a559c028b69a7f784ce553393e547bec0aa530352157603396d515f9c83463b"] + .unchecked_into(), + //5GsBt9MhGwkg8Jfb1F9LAy2kcr88WNyNy4L5ezwbCr8NWKQU + hex!["d464908266c878acbf181bf8fda398b3aa3fd2d05508013e414aaece4cf0d702"] + .unchecked_into(), + //5DtJVkz8AHevEnpszy3X4dUcPvACW6x1qBMQZtFxjexLr5bq + hex!["02fdf30222d2cb88f2376d558d3de9cb83f9fde3aa4b2dd40c93e3104e3488bcd2"] + .unchecked_into(), + ), + ( + //5E2cob2jrXsBkTih56pizwSqENjE4siaVdXhaD6akLdDyVq7 + hex!["56e0f73c563d49ee4a3971c393e17c44eaa313dabad7fcf297dc3271d803f303"].into(), + //5D4rNYgP9uFNi5GMyDEXTfiaFLjXyDEEX2VvuqBVi3f1qgCh + hex!["2c58e5e1d5aef77774480cead4f6876b1a1a6261170166995184d7f86140572b"].into(), + //5Ea2D65KXqe625sz4uV1jjhSfuigVnkezC8VgEj9LXN7ERAk + hex!["6ed45cb7af613be5d88a2622921e18d147225165f24538af03b93f2a03ce6e13"] + .unchecked_into(), + //5G4kCbgqUhEyrRHCyFwFEkgBZXoYA8sbgsRxT9rY8Tp5Jj5F + hex!["b0f8d2b9e4e1eafd4dab6358e0b9d5380d78af27c094e69ae9d6d30ca300fd86"] + .unchecked_into(), + //5CS7thd2n54WfqeKU3cjvZzK4z5p7zku1Zw97mSzXgPioAAs + hex!["1055100a283968271a0781450b389b9093231be809be1e48a305ebad2a90497e"] + .unchecked_into(), + //5DSaL4ZmSYarZSazhL5NQh7LT6pWhNRDcefk2QS9RxEXfsJe + hex!["3cea4ab74bab4adf176cf05a6e18c1599a7bc217d4c6c217275bfbe3b037a527"] + .unchecked_into(), + //5CaNLkYEbFYXZodXhd3UjV6RNLjFGNLiYafc8X5NooMkZiAq + hex!["169faa81aebfe74533518bda28567f2e2664014c8905aa07ea003336afda5a58"] + .unchecked_into(), + //5ERwhKiePayukzZStMuzGzRJGxGRFpwxYUXVarQpMSMrXzDS + hex!["03429d0d20f6ac5ca8b349f04d014f7b5b864acf382a744104d5d9a51108156c0f"] + .unchecked_into(), + ), + ( + //5H6j9ovzYk9opckVjvM9SvVfaK37ASTtPTzWeRfqk1tgLJUN + hex!["deb804ed2ed2bb696a3dd4ed7de4cd5c496528a2b204051c6ace385bacd66a3a"].into(), + //5DJ51tMW916mGwjMpfS1o9skcNt6Sb28YnZQXaKVg4h89agE + hex!["366da6a748afedb31f07902f2de36ab265beccee37762d3ae1f237de234d9c36"].into(), + //5CSPYDYoCDGSoSLgSp4EHkJ52YasZLHG2woqhPZkdbtNQpke + hex!["1089bc0cd60237d061872925e81d36c9d9205d250d5d8b542c8e08a8ecf1b911"] + .unchecked_into(), + //5ChfdrAqmLjCeDJvynbMjcxYLHYzPe8UWXd3HnX9JDThUMbn + hex!["1c309a70b4e274314b84c9a0a1f973c9c4fc084df5479ef686c54b1ae4950424"] + .unchecked_into(), + //5D8C3HHEp5E8fJsXRD56494F413CdRSR9QKGXe7v5ZEfymdj + hex!["2ee4d78f328db178c54f205ac809da12e291a33bcbd4f29f081ce7e74bdc5044"] + .unchecked_into(), + //5GxeTYCGmp1C3ZRLDkRWqJc6gB2GYmuqnygweuH3vsivMQq6 + hex!["d88e40e3c2c7a7c5abf96ffdd8f7b7bec8798cc277bc97e255881871ab73b529"] + .unchecked_into(), + //5DoGpsgSLcJsHa9B8V4PKjxegWAqDZttWfxicAd68prUX654 + hex!["4cb3863271b70daa38612acd5dae4f5afcb7c165fa277629e5150d2214df322a"] + .unchecked_into(), + //5G1KLjqFyMsPAodnjSRkwRFJztTTEzmZWxow2Q3ZSRCPdthM + hex!["03be5ec86d10a94db89c9b7a396d3c7742e3bec5f85159d4cf308cef505966ddf5"] + .unchecked_into(), + ), + ]); + + const ENDOWMENT: u128 = 1_000_000 * WND; + const STASH: u128 = 100 * WND; + + let config = RuntimeGenesisConfig { + balances: BalancesConfig { + balances: endowed_accounts + .iter() + .map(|k: &AccountId| (k.clone(), ENDOWMENT)) + .chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH))) + .collect::>(), + }, + session: SessionConfig { + keys: initial_authorities + .iter() + .map(|x| { + ( + x.0.clone(), + x.0.clone(), + westend_session_keys( + x.2.clone(), + x.3.clone(), + x.4.clone(), + x.5.clone(), + x.6.clone(), + x.7.clone(), + ), + ) + }) + .collect::>(), + ..Default::default() + }, + staking: StakingConfig { + validator_count: 50, + minimum_validator_count: 4, + stakers: initial_authorities + .iter() + .map(|x| (x.0.clone(), x.0.clone(), STASH, StakerStatus::::Validator)) + .collect::>(), + invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect::>(), + force_era: Forcing::ForceNone, + slash_reward_fraction: Perbill::from_percent(10), + ..Default::default() + }, + babe: BabeConfig { epoch_config: BABE_GENESIS_EPOCH_CONFIG, ..Default::default() }, + sudo: SudoConfig { key: Some(endowed_accounts[0].clone()) }, + configuration: ConfigurationConfig { config: default_parachains_host_configuration() }, + registrar: RegistrarConfig { + next_free_para_id: polkadot_primitives::LOWEST_PUBLIC_ID, + ..Default::default() + }, + ..Default::default() + }; + + serde_json::to_value(config).expect("Could not build genesis config.") +} + +//development +fn westend_development_config_genesis() -> serde_json::Value { + westend_testnet_genesis( + Vec::from([get_authority_keys_from_seed("Alice")]), + Sr25519Keyring::Alice.to_account_id(), + None, + ) +} + +//local_testnet +fn westend_local_testnet_genesis() -> serde_json::Value { + westend_testnet_genesis( + Vec::from([get_authority_keys_from_seed("Alice"), get_authority_keys_from_seed("Bob")]), + Sr25519Keyring::Alice.to_account_id(), + None, + ) +} + +/// Provides the JSON representation of predefined genesis config for given `id`. +pub fn get_preset(id: &PresetId) -> Option> { + let patch = match id.try_into() { + Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) => westend_local_testnet_genesis(), + Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) => westend_development_config_genesis(), + Ok("staging_testnet") => westend_staging_testnet_config_genesis(), + _ => return None, + }; + Some( + serde_json::to_string(&patch) + .expect("serialization to json is expected to work. qed.") + .into_bytes(), + ) +} + +/// List of supported presets. +pub fn preset_names() -> Vec { + vec![ + PresetId::from(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET), + PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET), + PresetId::from("staging_testnet"), + ] +} diff --git a/polkadot/runtime/westend/src/impls.rs b/polkadot/runtime/westend/src/impls.rs index 11665953bd8e..ac3f9e679f8d 100644 --- a/polkadot/runtime/westend/src/impls.rs +++ b/polkadot/runtime/westend/src/impls.rs @@ -90,7 +90,7 @@ where fn on_reap_identity(who: &AccountId, fields: u32, subs: u32) -> DispatchResult { use crate::{ impls::IdentityMigratorCalls::PokeDeposit, - weights::runtime_common_identity_migrator::WeightInfo as MigratorWeights, + weights::polkadot_runtime_common_identity_migrator::WeightInfo as MigratorWeights, }; let total_to_send = Self::calculate_remote_deposit(fields, subs); diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs index f0b16e731d9e..461be186ee51 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, @@ -47,12 +49,16 @@ use pallet_identity::legacy::IdentityInfo; use pallet_session::historical as session_historical; use pallet_transaction_payment::{FeeDetails, FungibleAdapter, RuntimeDispatchInfo}; use polkadot_primitives::{ - slashing, AccountId, AccountIndex, ApprovalVotingParams, Balance, BlockNumber, CandidateEvent, - CandidateHash, CommittedCandidateReceipt, CoreIndex, CoreState, DisputeState, ExecutorParams, - GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage, Moment, - NodeFeatures, Nonce, OccupiedCoreAssumption, PersistedValidationData, PvfCheckStatement, - ScrapedOnChainVotes, SessionInfo, Signature, ValidationCode, ValidationCodeHash, ValidatorId, - ValidatorIndex, ValidatorSignature, PARACHAIN_KEY_TYPE_ID, + slashing, + vstaging::{ + CandidateEvent, CommittedCandidateReceiptV2 as CommittedCandidateReceipt, CoreState, + ScrapedOnChainVotes, + }, + AccountId, AccountIndex, ApprovalVotingParams, Balance, BlockNumber, CandidateHash, CoreIndex, + DisputeState, ExecutorParams, GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, + InboundHrmpMessage, Moment, NodeFeatures, Nonce, OccupiedCoreAssumption, + PersistedValidationData, PvfCheckStatement, SessionInfo, Signature, ValidationCode, + ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature, PARACHAIN_KEY_TYPE_ID, }; use polkadot_runtime_common::{ assigned_slots, auctions, crowdloan, @@ -63,23 +69,21 @@ use polkadot_runtime_common::{ VersionedLocationConverter, }, paras_registrar, paras_sudo_wrapper, prod_or_fast, slots, - traits::{Leaser, OnSwap}, + traits::OnSwap, BalanceToU256, BlockHashCount, BlockLength, CurrencyToVote, SlowAdjustingFeeUpdate, 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, - }, + runtime_api_impl::v11 as parachains_runtime_api_impl, scheduler as parachains_scheduler, session_info as parachains_session_info, shared as parachains_shared, }; @@ -91,15 +95,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, + AccountIdConversion, BlakeTwo256, Block as BlockT, ConvertInto, 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))] @@ -116,8 +118,6 @@ use xcm_runtime_apis::{ pub use frame_system::Call as SystemCall; pub use pallet_balances::Call as BalancesCall; pub use pallet_election_provider_multi_phase::{Call as EPMCall, GeometricDepositBase}; -#[cfg(feature = "std")] -pub use pallet_staking::StakerStatus; use pallet_staking::UseValidatorsMap; pub use pallet_timestamp::Call as TimestampCall; use sp_runtime::traits::Get; @@ -133,6 +133,7 @@ use westend_runtime_constants::{ }; mod bag_thresholds; +mod genesis_config_presets; mod weights; pub mod xcm_config; @@ -156,17 +157,22 @@ 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_016_001, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 26, - state_version: 1, + system_version: 1, }; /// The BABE epoch configuration at genesis. @@ -212,6 +218,7 @@ impl frame_system::Config for Runtime { type Version = Version; type AccountData = pallet_balances::AccountData; type SystemWeightInfo = weights::frame_system::WeightInfo; + type ExtensionsWeightInfo = weights::frame_system_extensions::WeightInfo; type SS58Prefix = SS58Prefix; type MaxConsumers = frame_support::traits::ConstU32<16>; } @@ -244,6 +251,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; @@ -319,6 +400,7 @@ impl pallet_balances::Config for Runtime { type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = RuntimeFreezeReason; type MaxFreezes = VariantCountOf; + type DoneSlashHandler = (); } parameter_types! { @@ -342,9 +424,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 +450,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 +464,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! { @@ -401,6 +481,7 @@ impl pallet_transaction_payment::Config for Runtime { type WeightToFee = WeightToFee; type LengthToFee = ConstantMultiplier; type FeeMultiplierUpdate = SlowAdjustingFeeUpdate; + type WeightInfo = weights::pallet_transaction_payment::WeightInfo; } parameter_types! { @@ -525,20 +606,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 +640,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 +680,30 @@ 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; + // A normal-sized era will have 1 / 365.25 here: + let relative_era_len = + FixedU128::from_rational(era_duration_millis.into(), MILLISECONDS_PER_YEAR.into()); + + // Fixed total TI that we use as baseline for the issuance. + let fixed_total_issuance: i128 = 5_216_342_402_773_185_773; + let fixed_inflation_rate = FixedU128::from_rational(8, 100); + let yearly_emission = fixed_inflation_rate.saturating_mul_int(fixed_total_issuance); + + let era_emission = relative_era_len.saturating_mul_int(yearly_emission); + // 15% to treasury, as per Polkadot ref 1139. + let to_treasury = FixedU128::from_rational(15, 100).saturating_mul_int(era_emission); + let to_stakers = era_emission.saturating_sub(to_treasury); + + (to_stakers.saturated_into(), to_treasury.saturated_into()) + } } parameter_types! { @@ -617,7 +713,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 +736,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; @@ -760,18 +855,44 @@ impl pallet_grandpa::Config for Runtime { pallet_grandpa::EquivocationReportSystem; } +impl frame_system::offchain::SigningTypes for Runtime { + type Public = ::Signer; + type Signature = Signature; +} + +impl frame_system::offchain::CreateTransactionBase for Runtime +where + RuntimeCall: From, +{ + type RuntimeCall = RuntimeCall; + type Extrinsic = UncheckedExtrinsic; +} + +impl frame_system::offchain::CreateTransaction for Runtime +where + RuntimeCall: From, +{ + type Extension = TxExtension; + + fn create_transaction(call: RuntimeCall, extension: TxExtension) -> UncheckedExtrinsic { + UncheckedExtrinsic::new_transaction(call, extension) + } +} + /// Submits a transaction with the node's public and signature type. Adheres to the signed extension /// format of the chain. impl frame_system::offchain::CreateSignedTransaction for Runtime where RuntimeCall: From, { - fn create_transaction>( + fn create_signed_transaction< + C: frame_system::offchain::AppCrypto, + >( call: RuntimeCall, public: ::Signer, account: AccountId, nonce: ::Nonce, - ) -> Option<(RuntimeCall, ::SignaturePayload)> { + ) -> Option { use sp_runtime::traits::StaticLookup; // take the biggest period possible. let period = @@ -783,7 +904,7 @@ where // so the actual block number is `n`. .saturating_sub(1); let tip = 0; - let extra: SignedExtra = ( + let tx_ext: TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -796,30 +917,28 @@ where frame_system::CheckWeight::::new(), pallet_transaction_payment::ChargeTransactionPayment::::from(tip), frame_metadata_hash_extension::CheckMetadataHash::::new(true), - ); - let raw_payload = SignedPayload::new(call, extra) + ) + .into(); + let raw_payload = SignedPayload::new(call, tx_ext) .map_err(|e| { log::warn!("Unable to create signed payload: {:?}", e); }) .ok()?; let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?; - let (call, extra, _) = raw_payload.deconstruct(); + let (call, tx_ext, _) = raw_payload.deconstruct(); let address = ::Lookup::unlookup(account); - Some((call, (address, signature, extra))) + let transaction = UncheckedExtrinsic::new_signed(call, address, signature, tx_ext); + Some(transaction) } } -impl frame_system::offchain::SigningTypes for Runtime { - type Public = ::Signer; - type Signature = Signature; -} - -impl frame_system::offchain::SendTransactionTypes for Runtime +impl frame_system::offchain::CreateInherent for Runtime where - RuntimeCall: From, + RuntimeCall: From, { - type OverarchingCall = RuntimeCall; - type Extrinsic = UncheckedExtrinsic; + fn create_inherent(call: RuntimeCall) -> UncheckedExtrinsic { + UncheckedExtrinsic::new_bare(call) + } } parameter_types! { @@ -1011,7 +1130,8 @@ impl InstanceFilter for ProxyType { matches!( c, RuntimeCall::Staking(..) | - RuntimeCall::Session(..) | RuntimeCall::Utility(..) | + RuntimeCall::Session(..) | + RuntimeCall::Utility(..) | RuntimeCall::FastUnstake(..) | RuntimeCall::VoterList(..) | RuntimeCall::NominationPools(..) @@ -1080,7 +1200,7 @@ impl pallet_proxy::Config for Runtime { impl parachains_origin::Config for Runtime {} impl parachains_configuration::Config for Runtime { - type WeightInfo = weights::runtime_parachains_configuration::WeightInfo; + type WeightInfo = weights::polkadot_runtime_parachains_configuration::WeightInfo; } impl parachains_shared::Config for Runtime { @@ -1096,7 +1216,7 @@ impl parachains_inclusion::Config for Runtime { type DisputesHandler = ParasDisputes; type RewardValidators = parachains_reward_points::RewardValidatorsWithEraPoints; type MessageQueue = MessageQueue; - type WeightInfo = weights::runtime_parachains_inclusion::WeightInfo; + type WeightInfo = weights::polkadot_runtime_parachains_inclusion::WeightInfo; } parameter_types! { @@ -1105,7 +1225,7 @@ parameter_types! { impl parachains_paras::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type WeightInfo = weights::runtime_parachains_paras::WeightInfo; + type WeightInfo = weights::polkadot_runtime_parachains_paras::WeightInfo; type UnsignedPriority = ParasUnsignedPriority; type QueueFootprinter = ParaInclusion; type NextSessionRotation = Babe; @@ -1179,11 +1299,11 @@ impl parachains_hrmp::Config for Runtime { HrmpChannelSizeAndCapacityWithSystemRatio, >; type VersionWrapper = crate::XcmPallet; - type WeightInfo = weights::runtime_parachains_hrmp::WeightInfo; + type WeightInfo = weights::polkadot_runtime_parachains_hrmp::WeightInfo; } impl parachains_paras_inherent::Config for Runtime { - type WeightInfo = weights::runtime_parachains_paras_inherent::WeightInfo; + type WeightInfo = weights::polkadot_runtime_parachains_paras_inherent::WeightInfo; } impl parachains_scheduler::Config for Runtime { @@ -1212,7 +1332,7 @@ impl coretime::Config for Runtime { type Currency = Balances; type BrokerId = BrokerId; type BrokerPotLocation = BrokerPot; - type WeightInfo = weights::runtime_parachains_coretime::WeightInfo; + type WeightInfo = weights::polkadot_runtime_parachains_coretime::WeightInfo; type SendXcm = crate::xcm_config::XcmRouter; type AssetTransactor = crate::xcm_config::LocalAssetTransactor; type AccountToLocation = xcm_builder::AliasesIntoAccountId32< @@ -1229,11 +1349,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::polkadot_runtime_parachains_on_demand::WeightInfo; type MaxHistoricalRevenue = MaxHistoricalRevenue; type PalletId = OnDemandPalletId; } @@ -1243,7 +1363,7 @@ impl parachains_assigner_coretime::Config for Runtime {} impl parachains_initializer::Config for Runtime { type Randomness = pallet_babe::RandomnessFromOneEpochAgo; type ForceOrigin = EnsureRoot; - type WeightInfo = weights::runtime_parachains_initializer::WeightInfo; + type WeightInfo = weights::polkadot_runtime_parachains_initializer::WeightInfo; type CoretimeOnNewSession = Coretime; } @@ -1262,14 +1382,14 @@ impl assigned_slots::Config for Runtime { type PermanentSlotLeasePeriodLength = PermanentSlotLeasePeriodLength; type TemporarySlotLeasePeriodLength = TemporarySlotLeasePeriodLength; type MaxTemporarySlotPerLeasePeriod = MaxTemporarySlotPerLeasePeriod; - type WeightInfo = weights::runtime_common_assigned_slots::WeightInfo; + type WeightInfo = weights::polkadot_runtime_common_assigned_slots::WeightInfo; } impl parachains_disputes::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RewardValidators = parachains_reward_points::RewardValidatorsWithEraPoints; type SlashingHandler = parachains_slashing::SlashValidatorsForDisputes; - type WeightInfo = weights::runtime_parachains_disputes::WeightInfo; + type WeightInfo = weights::polkadot_runtime_parachains_disputes::WeightInfo; } impl parachains_slashing::Config for Runtime { @@ -1285,7 +1405,7 @@ impl parachains_slashing::Config for Runtime { Offences, ReportLongevity, >; - type WeightInfo = weights::runtime_parachains_disputes_slashing::WeightInfo; + type WeightInfo = weights::polkadot_runtime_parachains_disputes_slashing::WeightInfo; type BenchmarkingConfig = parachains_slashing::BenchConfig<300>; } @@ -1301,7 +1421,7 @@ impl paras_registrar::Config for Runtime { type OnSwap = (Crowdloan, Slots, SwapLeases); type ParaDeposit = ParaDeposit; type DataDepositPerByte = RegistrarDataDepositPerByte; - type WeightInfo = weights::runtime_common_paras_registrar::WeightInfo; + type WeightInfo = weights::polkadot_runtime_common_paras_registrar::WeightInfo; } parameter_types! { @@ -1315,7 +1435,7 @@ impl slots::Config for Runtime { type LeasePeriod = LeasePeriod; type LeaseOffset = (); type ForceOrigin = EitherOf, LeaseAdmin>; - type WeightInfo = weights::runtime_common_slots::WeightInfo; + type WeightInfo = weights::polkadot_runtime_common_slots::WeightInfo; } parameter_types! { @@ -1336,7 +1456,7 @@ impl crowdloan::Config for Runtime { type Registrar = Registrar; type Auctioneer = Auctions; type MaxMemoLength = MaxMemoLength; - type WeightInfo = weights::runtime_common_crowdloan::WeightInfo; + type WeightInfo = weights::polkadot_runtime_common_crowdloan::WeightInfo; } parameter_types! { @@ -1355,14 +1475,14 @@ impl auctions::Config for Runtime { type SampleLength = SampleLength; type Randomness = pallet_babe::RandomnessFromOneEpochAgo; type InitiateOrigin = EitherOf, AuctionAdmin>; - type WeightInfo = weights::runtime_common_auctions::WeightInfo; + type WeightInfo = weights::polkadot_runtime_common_auctions::WeightInfo; } impl identity_migrator::Config for Runtime { type RuntimeEvent = RuntimeEvent; type Reaper = EnsureSigned; type ReapIdentityHandler = ToParachainIdentityReaper; - type WeightInfo = weights::runtime_common_identity_migrator::WeightInfo; + type WeightInfo = weights::polkadot_runtime_common_identity_migrator::WeightInfo; } parameter_types! { @@ -1478,6 +1598,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 +1707,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; @@ -1646,8 +1768,8 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// `BlockId` type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The `SignedExtension` to the basic transaction logic. -pub type SignedExtra = ( +/// The extension to the basic transaction logic. +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -1660,11 +1782,8 @@ pub type SignedExtra = ( ); parameter_types! { - // This is the max pools that will be migrated in the runtime upgrade. Westend has more pools - // than this, but we want to emulate some non migrated pools. In prod runtimes, if weight is not - // a concern, it is recommended to set to (existing pools + 10) to also account for any new - // pools getting created before the migration is actually executed. - pub const MaxPoolsToMigrate: u32 = 250; + /// Bounding number of agent pot accounts to be migrated in a single block. + pub const MaxAgentsToMigrate: u32 = 300; } /// All migrations that will run on the next runtime upgrade. @@ -1678,39 +1797,25 @@ pub type Migrations = migrations::Unreleased; pub mod migrations { use super::*; - pub struct GetLegacyLeaseImpl; - impl coretime::migration::GetLegacyLease for GetLegacyLeaseImpl { - fn get_parachain_lease_in_blocks(para: ParaId) -> Option { - let now = frame_system::Pallet::::block_number(); - let lease = slots::Leases::::get(para); - if lease.is_empty() { - return None; - } - // Lease not yet started, ignore: - if lease.iter().any(Option::is_none) { - return None; - } - let (index, _) = - as Leaser>::lease_period_index(now)?; - Some(index.saturating_add(lease.len() as u32).saturating_mul(LeasePeriod::get())) - } - } - /// Unreleased migrations. Add new ones here: pub type Unreleased = ( - // Migrate NominationPools to `DelegateStake` adapter. This is unversioned upgrade and - // should not be applied yet in Kusama/Polkadot. - pallet_nomination_pools::migration::unversioned::DelegationStakeMigration< + // This is only needed for Westend. + pallet_delegated_staking::migration::unversioned::ProxyDelegatorMigration< Runtime, - MaxPoolsToMigrate, + MaxAgentsToMigrate, >, - pallet_staking::migrations::v15::MigrateV14ToV15, + parachains_shared::migration::MigrateToV1, + parachains_scheduler::migration::MigrateV2ToV3, ); } /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; +/// Unchecked signature payload type as expected by this runtime. +pub type UncheckedSignaturePayload = + generic::UncheckedSignaturePayload; + /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -1721,7 +1826,7 @@ pub type Executive = frame_executive::Executive< Migrations, >; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; #[cfg(feature = "runtime-benchmarks")] mod benches { @@ -1743,11 +1848,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 +1861,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] @@ -1767,7 +1875,9 @@ mod benches { [pallet_staking, Staking] [pallet_sudo, Sudo] [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_timestamp, Timestamp] + [pallet_transaction_payment, TransactionPayment] [pallet_treasury, Treasury] [pallet_utility, Utility] [pallet_vesting, Vesting] @@ -1984,7 +2094,7 @@ sp_api::impl_runtime_apis! { parachains_runtime_api_impl::minimum_backing_votes::() } - fn para_backing_state(para_id: ParaId) -> Option { + fn para_backing_state(para_id: ParaId) -> Option { parachains_runtime_api_impl::backing_state::(para_id) } @@ -2005,15 +2115,15 @@ sp_api::impl_runtime_apis! { } fn claim_queue() -> BTreeMap> { - vstaging_parachains_runtime_api_impl::claim_queue::() + parachains_runtime_api_impl::claim_queue::() } fn candidates_pending_availability(para_id: ParaId) -> Vec> { - vstaging_parachains_runtime_api_impl::candidates_pending_availability::(para_id) + parachains_runtime_api_impl::candidates_pending_availability::(para_id) } } - #[api_version(4)] + #[api_version(5)] impl sp_consensus_beefy::BeefyApi for Runtime { fn beefy_genesis() -> Option { pallet_beefy::GenesisBlock::::get() @@ -2039,6 +2149,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 +2184,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 +2483,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 { @@ -2387,6 +2541,7 @@ sp_api::impl_runtime_apis! { use pallet_election_provider_support_benchmarking::Pallet as ElectionProviderBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; type XcmBalances = pallet_xcm_benchmarks::fungible::Pallet::; @@ -2415,6 +2570,7 @@ sp_api::impl_runtime_apis! { use pallet_election_provider_support_benchmarking::Pallet as ElectionProviderBench; use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; impl pallet_session_benchmarking::Config for Runtime {} @@ -2628,96 +2784,11 @@ sp_api::impl_runtime_apis! { } fn get_preset(id: &Option) -> Option> { - get_preset::(id, |_| None) + get_preset::(id, &genesis_config_presets::get_preset) } fn preset_names() -> Vec { - vec![] - } - } -} - -#[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")] - use super::Vec; - use frame_support::{pallet_prelude::*, storage_alias, traits::OnRuntimeUpgrade}; - use pallet_state_trie_migration::MigrationLimits; - - #[storage_alias] - type AutoLimits = StorageValue, ValueQuery>; - - // Actual type of value is `MigrationTask`, putting a dummy - // one to avoid the trait constraint on T. - // Since we only use `kill` it is fine. - #[storage_alias] - type MigrationProcess = StorageValue; - - #[storage_alias] - type SignedMigrationMaxLimits = StorageValue; - - /// Initialize an automatic migration process. - pub struct CleanMigrate; - - impl OnRuntimeUpgrade for CleanMigrate { - #[cfg(feature = "try-runtime")] - fn pre_upgrade() -> Result, sp_runtime::TryRuntimeError> { - Ok(Default::default()) - } - - fn on_runtime_upgrade() -> frame_support::weights::Weight { - MigrationProcess::kill(); - AutoLimits::kill(); - SignedMigrationMaxLimits::kill(); - ::DbWeight::get().writes(3) - } - - #[cfg(feature = "try-runtime")] - fn post_upgrade(_state: Vec) -> Result<(), sp_runtime::TryRuntimeError> { - frame_support::ensure!( - !AutoLimits::exists() && !SignedMigrationMaxLimits::exists(), - "State migration clean.", - ); - Ok(()) + genesis_config_presets::preset_names() } } } diff --git a/polkadot/runtime/westend/src/tests.rs b/polkadot/runtime/westend/src/tests.rs index 4d5e2e946bce..02fd6b61496b 100644 --- a/polkadot/runtime/westend/src/tests.rs +++ b/polkadot/runtime/westend/src/tests.rs @@ -18,9 +18,15 @@ use std::collections::HashSet; -use crate::*; +use crate::{xcm_config::LocationConverter, *}; +use approx::assert_relative_eq; use frame_support::traits::WhitelistedStorageKeys; -use sp_core::hexdisplay::HexDisplay; +use pallet_staking::EraPayout; +use sp_core::{crypto::Ss58Codec, hexdisplay::HexDisplay}; +use sp_keyring::AccountKeyring::Alice; +use xcm_runtime_apis::conversions::LocationToAccountHelper; + +const MILLISECONDS_PER_HOUR: u64 = 60 * 60 * 1000; #[test] fn remove_keys_weight_is_sensible() { @@ -62,7 +68,7 @@ fn sanity_check_teleport_assets_weight() { weight_limit: Unlimited, } .get_dispatch_info() - .weight; + .call_weight; assert!((weight * 50).all_lt(BlockWeights::get().max_block)); } @@ -99,3 +105,304 @@ 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 + ); + }); + } +} + +#[test] +fn location_conversion_works() { + // the purpose of hardcoded values is to catch an unintended location conversion logic change. + struct TestCase { + description: &'static str, + location: Location, + expected_account_id_str: &'static str, + } + + let test_cases = vec![ + // DescribeTerminus + TestCase { + description: "DescribeTerminus Child", + location: Location::new(0, [Parachain(1111)]), + expected_account_id_str: "5Ec4AhP4h37t7TFsAZ4HhFq6k92usAAJDUC3ADSZ4H4Acru3", + }, + // DescribePalletTerminal + TestCase { + description: "DescribePalletTerminal Child", + location: Location::new(0, [Parachain(1111), PalletInstance(50)]), + expected_account_id_str: "5FjEBrKn3STAFsZpQF4jzwxUYHNGnNgzdZqSQfTzeJ82XKp6", + }, + // DescribeAccountId32Terminal + TestCase { + description: "DescribeAccountId32Terminal Child", + location: Location::new( + 0, + [Parachain(1111), AccountId32 { network: None, id: AccountId::from(Alice).into() }], + ), + expected_account_id_str: "5EEMro9RRDpne4jn9TuD7cTB6Amv1raVZ3xspSkqb2BF3FJH", + }, + // DescribeAccountKey20Terminal + TestCase { + description: "DescribeAccountKey20Terminal Child", + location: Location::new( + 0, + [Parachain(1111), AccountKey20 { network: None, key: [0u8; 20] }], + ), + expected_account_id_str: "5HohjXdjs6afcYcgHHSstkrtGfxgfGKsnZ1jtewBpFiGu4DL", + }, + // DescribeTreasuryVoiceTerminal + TestCase { + description: "DescribeTreasuryVoiceTerminal Child", + location: Location::new( + 0, + [Parachain(1111), Plurality { id: BodyId::Treasury, part: BodyPart::Voice }], + ), + expected_account_id_str: "5GenE4vJgHvwYVcD6b4nBvH5HNY4pzpVHWoqwFpNMFT7a2oX", + }, + // DescribeBodyTerminal + TestCase { + description: "DescribeBodyTerminal Child", + location: Location::new( + 0, + [Parachain(1111), Plurality { id: BodyId::Unit, part: BodyPart::Voice }], + ), + expected_account_id_str: "5DPgGBFTTYm1dGbtB1VWHJ3T3ScvdrskGGx6vSJZNP1WNStV", + }, + ]; + + for tc in test_cases { + let expected = + AccountId::from_string(tc.expected_account_id_str).expect("Invalid AccountId string"); + + let got = LocationToAccountHelper::::convert_location( + tc.location.into(), + ) + .unwrap(); + + assert_eq!(got, expected, "{}", tc.description); + } +} + +#[test] +fn staking_inflation_correct_single_era() { + let (to_stakers, to_treasury) = super::EraPayout::era_payout( + 123, // ignored + 456, // ignored + MILLISECONDS_PER_HOUR, + ); + + assert_relative_eq!(to_stakers as f64, (4_046 * CENTS) as f64, max_relative = 0.01); + assert_relative_eq!(to_treasury as f64, (714 * CENTS) as f64, max_relative = 0.01); + // Total per hour is ~47.6 WND + assert_relative_eq!( + (to_stakers as f64 + to_treasury as f64), + (4_760 * CENTS) as f64, + max_relative = 0.001 + ); +} + +#[test] +fn staking_inflation_correct_longer_era() { + // Twice the era duration means twice the emission: + let (to_stakers, to_treasury) = super::EraPayout::era_payout( + 123, // ignored + 456, // ignored + 2 * MILLISECONDS_PER_HOUR, + ); + + assert_relative_eq!(to_stakers as f64, (4_046 * CENTS) as f64 * 2.0, max_relative = 0.001); + assert_relative_eq!(to_treasury as f64, (714 * CENTS) as f64 * 2.0, max_relative = 0.001); +} + +#[test] +fn staking_inflation_correct_whole_year() { + let (to_stakers, to_treasury) = super::EraPayout::era_payout( + 123, // ignored + 456, // ignored + (36525 * 24 * MILLISECONDS_PER_HOUR) / 100, // 1 year + ); + + // Our yearly emissions is about 417k WND: + let yearly_emission = 417_307 * UNITS; + assert_relative_eq!( + to_stakers as f64 + to_treasury as f64, + yearly_emission as f64, + max_relative = 0.001 + ); + + assert_relative_eq!(to_stakers as f64, yearly_emission as f64 * 0.85, max_relative = 0.001); + assert_relative_eq!(to_treasury as f64, yearly_emission as f64 * 0.15, max_relative = 0.001); +} + +// 10 years into the future, our values do not overflow. +#[test] +fn staking_inflation_correct_not_overflow() { + let (to_stakers, to_treasury) = super::EraPayout::era_payout( + 123, // ignored + 456, // ignored + (36525 * 24 * MILLISECONDS_PER_HOUR) / 10, // 10 years + ); + let initial_ti: i128 = 5_216_342_402_773_185_773; + let projected_total_issuance = (to_stakers as i128 + to_treasury as i128) + initial_ti; + + // In 2034, there will be about 9.39 million WND in existence. + assert_relative_eq!( + projected_total_issuance as f64, + (9_390_000 * UNITS) as f64, + max_relative = 0.001 + ); +} + +// Print percent per year, just as convenience. +#[test] +fn staking_inflation_correct_print_percent() { + let (to_stakers, to_treasury) = super::EraPayout::era_payout( + 123, // ignored + 456, // ignored + (36525 * 24 * MILLISECONDS_PER_HOUR) / 100, // 1 year + ); + let yearly_emission = to_stakers + to_treasury; + let mut ti: i128 = 5_216_342_402_773_185_773; + + for y in 0..10 { + let new_ti = ti + yearly_emission as i128; + let inflation = 100.0 * (new_ti - ti) as f64 / ti as f64; + println!("Year {y} inflation: {inflation}%"); + ti = new_ti; + + assert!(inflation <= 8.0 && inflation > 2.0, "sanity check"); + } +} diff --git a/polkadot/runtime/westend/src/weights/frame_system_extensions.rs b/polkadot/runtime/westend/src/weights/frame_system_extensions.rs new file mode 100644 index 000000000000..048f23fbcb91 --- /dev/null +++ b/polkadot/runtime/westend/src/weights/frame_system_extensions.rs @@ -0,0 +1,131 @@ +// 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 `frame_system_extensions` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-12, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/polkadot +// benchmark +// pallet +// --steps=2 +// --repeat=2 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --pallet=frame-system-extensions +// --chain=westend-dev +// --output=./polkadot/runtime/westend/src/weights/ +// --header=./polkadot/file_header.txt + +#![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 `frame_system_extensions`. +pub struct WeightInfo(PhantomData); +impl frame_system::ExtensionsWeightInfo for WeightInfo { + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_genesis() -> Weight { + // Proof Size summary in bytes: + // Measured: `54` + // Estimated: `3509` + // Minimum execution time: 75_764_000 picoseconds. + Weight::from_parts(85_402_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_mortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 118_233_000 picoseconds. + Weight::from_parts(126_539_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + /// Storage: `System::BlockHash` (r:1 w:0) + /// Proof: `System::BlockHash` (`max_values`: None, `max_size`: Some(44), added: 2519, mode: `MaxEncodedLen`) + fn check_mortality_immortal_transaction() -> Weight { + // Proof Size summary in bytes: + // Measured: `92` + // Estimated: `3509` + // Minimum execution time: 118_233_000 picoseconds. + Weight::from_parts(126_539_000, 0) + .saturating_add(Weight::from_parts(0, 3509)) + .saturating_add(T::DbWeight::get().reads(1)) + } + fn check_non_zero_sender() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 7_885_000 picoseconds. + Weight::from_parts(12_784_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::Account` (r:1 w:1) + /// Proof: `System::Account` (`max_values`: None, `max_size`: Some(128), added: 2603, mode: `MaxEncodedLen`) + fn check_nonce() -> Weight { + // Proof Size summary in bytes: + // Measured: `101` + // Estimated: `3593` + // Minimum execution time: 104_237_000 picoseconds. + Weight::from_parts(110_910_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } + fn check_spec_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_141_000 picoseconds. + Weight::from_parts(11_502_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + fn check_tx_version() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 6_192_000 picoseconds. + Weight::from_parts(11_481_000, 0) + .saturating_add(Weight::from_parts(0, 0)) + } + /// Storage: `System::AllExtrinsicsLen` (r:1 w:1) + /// Proof: `System::AllExtrinsicsLen` (`max_values`: Some(1), `max_size`: Some(4), added: 499, mode: `MaxEncodedLen`) + fn check_weight() -> Weight { + // Proof Size summary in bytes: + // Measured: `24` + // Estimated: `1489` + // Minimum execution time: 87_616_000 picoseconds. + Weight::from_parts(93_607_000, 0) + .saturating_add(Weight::from_parts(0, 1489)) + .saturating_add(T::DbWeight::get().reads(1)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/polkadot/runtime/westend/src/weights/mod.rs b/polkadot/runtime/westend/src/weights/mod.rs index f6a9008d7187..8c12c1adb9ca 100644 --- a/polkadot/runtime/westend/src/weights/mod.rs +++ b/polkadot/runtime/westend/src/weights/mod.rs @@ -17,45 +17,49 @@ pub mod frame_election_provider_support; pub mod frame_system; +pub mod frame_system_extensions; 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; pub mod pallet_referenda_referenda; pub mod pallet_scheduler; pub mod pallet_session; pub mod pallet_staking; pub mod pallet_sudo; pub mod pallet_timestamp; +pub mod pallet_transaction_payment; pub mod pallet_treasury; pub mod pallet_utility; pub mod pallet_vesting; pub mod pallet_whitelist; pub mod pallet_xcm; -pub mod runtime_common_assigned_slots; -pub mod runtime_common_auctions; -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_disputes_slashing; -pub mod runtime_parachains_hrmp; -pub mod runtime_parachains_inclusion; -pub mod runtime_parachains_initializer; -pub mod runtime_parachains_paras; -pub mod runtime_parachains_paras_inherent; +pub mod polkadot_runtime_common_assigned_slots; +pub mod polkadot_runtime_common_auctions; +pub mod polkadot_runtime_common_crowdloan; +pub mod polkadot_runtime_common_identity_migrator; +pub mod polkadot_runtime_common_paras_registrar; +pub mod polkadot_runtime_common_slots; +pub mod polkadot_runtime_parachains_configuration; +pub mod polkadot_runtime_parachains_coretime; +pub mod polkadot_runtime_parachains_disputes; +pub mod polkadot_runtime_parachains_disputes_slashing; +pub mod polkadot_runtime_parachains_hrmp; +pub mod polkadot_runtime_parachains_inclusion; +pub mod polkadot_runtime_parachains_initializer; +pub mod polkadot_runtime_parachains_on_demand; +pub mod polkadot_runtime_parachains_paras; +pub mod polkadot_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 000000000000..5be207e3fcff --- /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 000000000000..1a410e7fc46e --- /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 000000000000..2e131ce55f31 --- /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/pallet_referenda_fellowship_referenda.rs b/polkadot/runtime/westend/src/weights/pallet_referenda_fellowship_referenda.rs deleted file mode 100644 index a4ac06679116..000000000000 --- a/polkadot/runtime/westend/src/weights/pallet_referenda_fellowship_referenda.rs +++ /dev/null @@ -1,525 +0,0 @@ -// 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_referenda` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-19, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-e8ezs4ez-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("kusama-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=kusama-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=pallet_referenda -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/kusama/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_referenda`. -pub struct WeightInfo(PhantomData); -impl pallet_referenda::WeightInfo for WeightInfo { - /// Storage: FellowshipCollective Members (r:1 w:0) - /// Proof: FellowshipCollective Members (max_values: None, max_size: Some(42), added: 2517, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda ReferendumCount (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumCount (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda ReferendumInfoFor (r:0 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - fn submit() -> Weight { - // Proof Size summary in bytes: - // Measured: `327` - // Estimated: `42428` - // Minimum execution time: 28_969_000 picoseconds. - Weight::from_parts(30_902_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn place_decision_deposit_preparing() -> Weight { - // Proof Size summary in bytes: - // Measured: `404` - // Estimated: `83866` - // Minimum execution time: 53_500_000 picoseconds. - Weight::from_parts(54_447_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda DecidingCount (r:1 w:0) - /// Proof: FellowshipReferenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda TrackQueue (r:1 w:1) - /// Proof: FellowshipReferenda TrackQueue (max_values: None, max_size: Some(812), added: 3287, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn place_decision_deposit_queued() -> Weight { - // Proof Size summary in bytes: - // Measured: `2042` - // Estimated: `42428` - // Minimum execution time: 114_321_000 picoseconds. - Weight::from_parts(122_607_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda DecidingCount (r:1 w:0) - /// Proof: FellowshipReferenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda TrackQueue (r:1 w:1) - /// Proof: FellowshipReferenda TrackQueue (max_values: None, max_size: Some(812), added: 3287, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn place_decision_deposit_not_queued() -> Weight { - // Proof Size summary in bytes: - // Measured: `2083` - // Estimated: `42428` - // Minimum execution time: 113_476_000 picoseconds. - Weight::from_parts(120_078_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda DecidingCount (r:1 w:1) - /// Proof: FellowshipReferenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn place_decision_deposit_passing() -> Weight { - // Proof Size summary in bytes: - // Measured: `774` - // Estimated: `83866` - // Minimum execution time: 194_798_000 picoseconds. - Weight::from_parts(208_378_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda DecidingCount (r:1 w:1) - /// Proof: FellowshipReferenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn place_decision_deposit_failing() -> Weight { - // Proof Size summary in bytes: - // Measured: `639` - // Estimated: `83866` - // Minimum execution time: 69_502_000 picoseconds. - Weight::from_parts(71_500_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - fn refund_decision_deposit() -> Weight { - // Proof Size summary in bytes: - // Measured: `317` - // Estimated: `4365` - // Minimum execution time: 30_561_000 picoseconds. - Weight::from_parts(31_427_000, 0) - .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - fn refund_submission_deposit() -> Weight { - // Proof Size summary in bytes: - // Measured: `167` - // Estimated: `4365` - // Minimum execution time: 14_535_000 picoseconds. - Weight::from_parts(14_999_000, 0) - .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn cancel() -> Weight { - // Proof Size summary in bytes: - // Measured: `349` - // Estimated: `83866` - // Minimum execution time: 38_532_000 picoseconds. - Weight::from_parts(39_361_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda MetadataOf (r:1 w:0) - /// Proof: FellowshipReferenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn kill() -> Weight { - // Proof Size summary in bytes: - // Measured: `450` - // Estimated: `83866` - // Minimum execution time: 78_956_000 picoseconds. - Weight::from_parts(80_594_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda TrackQueue (r:1 w:0) - /// Proof: FellowshipReferenda TrackQueue (max_values: None, max_size: Some(812), added: 3287, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda DecidingCount (r:1 w:1) - /// Proof: FellowshipReferenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - fn one_fewer_deciding_queue_empty() -> Weight { - // Proof Size summary in bytes: - // Measured: `140` - // Estimated: `4277` - // Minimum execution time: 9_450_000 picoseconds. - Weight::from_parts(9_881_000, 0) - .saturating_add(Weight::from_parts(0, 4277)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: FellowshipReferenda TrackQueue (r:1 w:1) - /// Proof: FellowshipReferenda TrackQueue (max_values: None, max_size: Some(812), added: 3287, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn one_fewer_deciding_failing() -> Weight { - // Proof Size summary in bytes: - // Measured: `2376` - // Estimated: `42428` - // Minimum execution time: 98_126_000 picoseconds. - Weight::from_parts(102_511_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda TrackQueue (r:1 w:1) - /// Proof: FellowshipReferenda TrackQueue (max_values: None, max_size: Some(812), added: 3287, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn one_fewer_deciding_passing() -> Weight { - // Proof Size summary in bytes: - // Measured: `2362` - // Estimated: `42428` - // Minimum execution time: 99_398_000 picoseconds. - Weight::from_parts(104_045_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:0) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda TrackQueue (r:1 w:1) - /// Proof: FellowshipReferenda TrackQueue (max_values: None, max_size: Some(812), added: 3287, mode: MaxEncodedLen) - fn nudge_referendum_requeued_insertion() -> Weight { - // Proof Size summary in bytes: - // Measured: `1807` - // Estimated: `4365` - // Minimum execution time: 43_734_000 picoseconds. - Weight::from_parts(46_962_000, 0) - .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:0) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda TrackQueue (r:1 w:1) - /// Proof: FellowshipReferenda TrackQueue (max_values: None, max_size: Some(812), added: 3287, mode: MaxEncodedLen) - fn nudge_referendum_requeued_slide() -> Weight { - // Proof Size summary in bytes: - // Measured: `1774` - // Estimated: `4365` - // Minimum execution time: 42_863_000 picoseconds. - Weight::from_parts(46_241_000, 0) - .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda DecidingCount (r:1 w:0) - /// Proof: FellowshipReferenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda TrackQueue (r:1 w:1) - /// Proof: FellowshipReferenda TrackQueue (max_values: None, max_size: Some(812), added: 3287, mode: MaxEncodedLen) - fn nudge_referendum_queued() -> Weight { - // Proof Size summary in bytes: - // Measured: `1790` - // Estimated: `4365` - // Minimum execution time: 57_511_000 picoseconds. - Weight::from_parts(64_027_000, 0) - .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda DecidingCount (r:1 w:0) - /// Proof: FellowshipReferenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda TrackQueue (r:1 w:1) - /// Proof: FellowshipReferenda TrackQueue (max_values: None, max_size: Some(812), added: 3287, mode: MaxEncodedLen) - fn nudge_referendum_not_queued() -> Weight { - // Proof Size summary in bytes: - // Measured: `1831` - // Estimated: `4365` - // Minimum execution time: 56_726_000 picoseconds. - Weight::from_parts(61_962_000, 0) - .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_no_deposit() -> Weight { - // Proof Size summary in bytes: - // Measured: `301` - // Estimated: `42428` - // Minimum execution time: 24_870_000 picoseconds. - Weight::from_parts(25_837_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_preparing() -> Weight { - // Proof Size summary in bytes: - // Measured: `349` - // Estimated: `42428` - // Minimum execution time: 25_297_000 picoseconds. - Weight::from_parts(26_086_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - fn nudge_referendum_timed_out() -> Weight { - // Proof Size summary in bytes: - // Measured: `208` - // Estimated: `4365` - // Minimum execution time: 16_776_000 picoseconds. - Weight::from_parts(17_396_000, 0) - .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda DecidingCount (r:1 w:1) - /// Proof: FellowshipReferenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_begin_deciding_failing() -> Weight { - // Proof Size summary in bytes: - // Measured: `584` - // Estimated: `42428` - // Minimum execution time: 37_780_000 picoseconds. - Weight::from_parts(38_626_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda DecidingCount (r:1 w:1) - /// Proof: FellowshipReferenda DecidingCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_begin_deciding_passing() -> Weight { - // Proof Size summary in bytes: - // Measured: `719` - // Estimated: `42428` - // Minimum execution time: 85_265_000 picoseconds. - Weight::from_parts(89_986_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(4)) - .saturating_add(T::DbWeight::get().writes(3)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_begin_confirming() -> Weight { - // Proof Size summary in bytes: - // Measured: `770` - // Estimated: `42428` - // Minimum execution time: 143_283_000 picoseconds. - Weight::from_parts(158_540_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_end_confirming() -> Weight { - // Proof Size summary in bytes: - // Measured: `755` - // Estimated: `42428` - // Minimum execution time: 143_736_000 picoseconds. - Weight::from_parts(162_755_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_continue_not_confirming() -> Weight { - // Proof Size summary in bytes: - // Measured: `770` - // Estimated: `42428` - // Minimum execution time: 139_021_000 picoseconds. - Weight::from_parts(157_398_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_continue_confirming() -> Weight { - // Proof Size summary in bytes: - // Measured: `776` - // Estimated: `42428` - // Minimum execution time: 78_530_000 picoseconds. - Weight::from_parts(83_556_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:2 w:2) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - /// Storage: Scheduler Lookup (r:1 w:1) - /// Proof: Scheduler Lookup (max_values: None, max_size: Some(48), added: 2523, mode: MaxEncodedLen) - fn nudge_referendum_approved() -> Weight { - // Proof Size summary in bytes: - // Measured: `776` - // Estimated: `83866` - // Minimum execution time: 174_165_000 picoseconds. - Weight::from_parts(188_496_000, 0) - .saturating_add(Weight::from_parts(0, 83866)) - .saturating_add(T::DbWeight::get().reads(5)) - .saturating_add(T::DbWeight::get().writes(4)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:1) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipCollective MemberCount (r:1 w:0) - /// Proof: FellowshipCollective MemberCount (max_values: None, max_size: Some(14), added: 2489, mode: MaxEncodedLen) - /// Storage: Scheduler Agenda (r:1 w:1) - /// Proof: Scheduler Agenda (max_values: None, max_size: Some(38963), added: 41438, mode: MaxEncodedLen) - fn nudge_referendum_rejected() -> Weight { - // Proof Size summary in bytes: - // Measured: `772` - // Estimated: `42428` - // Minimum execution time: 142_964_000 picoseconds. - Weight::from_parts(157_257_000, 0) - .saturating_add(Weight::from_parts(0, 42428)) - .saturating_add(T::DbWeight::get().reads(3)) - .saturating_add(T::DbWeight::get().writes(2)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:0) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: Preimage StatusFor (r:1 w:0) - /// Proof: Preimage StatusFor (max_values: None, max_size: Some(91), added: 2566, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda MetadataOf (r:0 w:1) - /// Proof: FellowshipReferenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn set_some_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `352` - // Estimated: `4365` - // Minimum execution time: 20_126_000 picoseconds. - Weight::from_parts(20_635_000, 0) - .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } - /// Storage: FellowshipReferenda ReferendumInfoFor (r:1 w:0) - /// Proof: FellowshipReferenda ReferendumInfoFor (max_values: None, max_size: Some(900), added: 3375, mode: MaxEncodedLen) - /// Storage: FellowshipReferenda MetadataOf (r:1 w:1) - /// Proof: FellowshipReferenda MetadataOf (max_values: None, max_size: Some(52), added: 2527, mode: MaxEncodedLen) - fn clear_metadata() -> Weight { - // Proof Size summary in bytes: - // Measured: `285` - // Estimated: `4365` - // Minimum execution time: 17_716_000 picoseconds. - Weight::from_parts(18_324_000, 0) - .saturating_add(Weight::from_parts(0, 4365)) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(1)) - } -} diff --git a/polkadot/runtime/westend/src/weights/pallet_sudo.rs b/polkadot/runtime/westend/src/weights/pallet_sudo.rs index e9ab3ad37a4c..649c43e031dc 100644 --- a/polkadot/runtime/westend/src/weights/pallet_sudo.rs +++ b/polkadot/runtime/westend/src/weights/pallet_sudo.rs @@ -94,4 +94,15 @@ impl pallet_sudo::WeightInfo for WeightInfo { .saturating_add(T::DbWeight::get().reads(1)) .saturating_add(T::DbWeight::get().writes(1)) } + /// Storage: `Sudo::Key` (r:1 w:0) + /// Proof: `Sudo::Key` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + fn check_only_sudo_account() -> Weight { + // Proof Size summary in bytes: + // Measured: `132` + // Estimated: `1517` + // Minimum execution time: 2_875_000 picoseconds. + Weight::from_parts(6_803_000, 0) + .saturating_add(Weight::from_parts(0, 1517)) + .saturating_add(T::DbWeight::get().reads(1)) + } } diff --git a/polkadot/runtime/westend/src/weights/pallet_transaction_payment.rs b/polkadot/runtime/westend/src/weights/pallet_transaction_payment.rs new file mode 100644 index 000000000000..71a01b6a0c2e --- /dev/null +++ b/polkadot/runtime/westend/src/weights/pallet_transaction_payment.rs @@ -0,0 +1,68 @@ +// 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_transaction_payment` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-09-12, STEPS: `2`, REPEAT: `2`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `gleipnir`, CPU: `AMD Ryzen 9 7900X 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 + +// Executed Command: +// ./target/debug/polkadot +// benchmark +// pallet +// --steps=2 +// --repeat=2 +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 +// --pallet=pallet-transaction-payment +// --chain=westend-dev +// --output=./polkadot/runtime/westend/src/weights/ +// --header=./polkadot/file_header.txt + +#![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_transaction_payment`. +pub struct WeightInfo(PhantomData); +impl pallet_transaction_payment::WeightInfo for WeightInfo { + /// Storage: `TransactionPayment::NextFeeMultiplier` (r:1 w:0) + /// Proof: `TransactionPayment::NextFeeMultiplier` (`max_values`: Some(1), `max_size`: Some(16), added: 511, 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`) + fn charge_transaction_payment() -> Weight { + // Proof Size summary in bytes: + // Measured: `320` + // Estimated: `3593` + // Minimum execution time: 569_518_000 picoseconds. + Weight::from_parts(590_438_000, 0) + .saturating_add(Weight::from_parts(0, 3593)) + .saturating_add(T::DbWeight::get().reads(4)) + .saturating_add(T::DbWeight::get().writes(1)) + } +} diff --git a/polkadot/runtime/westend/src/weights/runtime_common_assigned_slots.rs b/polkadot/runtime/westend/src/weights/polkadot_runtime_common_assigned_slots.rs similarity index 100% rename from polkadot/runtime/westend/src/weights/runtime_common_assigned_slots.rs rename to polkadot/runtime/westend/src/weights/polkadot_runtime_common_assigned_slots.rs diff --git a/polkadot/runtime/westend/src/weights/runtime_common_auctions.rs b/polkadot/runtime/westend/src/weights/polkadot_runtime_common_auctions.rs similarity index 100% rename from polkadot/runtime/westend/src/weights/runtime_common_auctions.rs rename to polkadot/runtime/westend/src/weights/polkadot_runtime_common_auctions.rs diff --git a/polkadot/runtime/westend/src/weights/runtime_common_crowdloan.rs b/polkadot/runtime/westend/src/weights/polkadot_runtime_common_crowdloan.rs similarity index 100% rename from polkadot/runtime/westend/src/weights/runtime_common_crowdloan.rs rename to polkadot/runtime/westend/src/weights/polkadot_runtime_common_crowdloan.rs diff --git a/polkadot/runtime/rococo/src/weights/runtime_common_identity_migrator.rs b/polkadot/runtime/westend/src/weights/polkadot_runtime_common_identity_migrator.rs similarity index 100% rename from polkadot/runtime/rococo/src/weights/runtime_common_identity_migrator.rs rename to polkadot/runtime/westend/src/weights/polkadot_runtime_common_identity_migrator.rs diff --git a/polkadot/runtime/westend/src/weights/runtime_common_paras_registrar.rs b/polkadot/runtime/westend/src/weights/polkadot_runtime_common_paras_registrar.rs similarity index 100% rename from polkadot/runtime/westend/src/weights/runtime_common_paras_registrar.rs rename to polkadot/runtime/westend/src/weights/polkadot_runtime_common_paras_registrar.rs diff --git a/polkadot/runtime/westend/src/weights/runtime_common_slots.rs b/polkadot/runtime/westend/src/weights/polkadot_runtime_common_slots.rs similarity index 100% rename from polkadot/runtime/westend/src/weights/runtime_common_slots.rs rename to polkadot/runtime/westend/src/weights/polkadot_runtime_common_slots.rs diff --git a/polkadot/runtime/westend/src/weights/runtime_parachains_configuration.rs b/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_configuration.rs similarity index 100% rename from polkadot/runtime/westend/src/weights/runtime_parachains_configuration.rs rename to polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_configuration.rs diff --git a/polkadot/runtime/westend/src/weights/runtime_parachains_coretime.rs b/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_coretime.rs similarity index 100% rename from polkadot/runtime/westend/src/weights/runtime_parachains_coretime.rs rename to polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_coretime.rs diff --git a/polkadot/runtime/westend/src/weights/runtime_parachains_disputes.rs b/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_disputes.rs similarity index 100% rename from polkadot/runtime/westend/src/weights/runtime_parachains_disputes.rs rename to polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_disputes.rs diff --git a/polkadot/runtime/westend/src/weights/runtime_parachains_disputes_slashing.rs b/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_disputes_slashing.rs similarity index 100% rename from polkadot/runtime/westend/src/weights/runtime_parachains_disputes_slashing.rs rename to polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_disputes_slashing.rs diff --git a/polkadot/runtime/westend/src/weights/runtime_parachains_hrmp.rs b/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_hrmp.rs similarity index 100% rename from polkadot/runtime/westend/src/weights/runtime_parachains_hrmp.rs rename to polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_hrmp.rs diff --git a/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_inclusion.rs b/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_inclusion.rs new file mode 100644 index 000000000000..28d8aa8ea323 --- /dev/null +++ b/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_inclusion.rs @@ -0,0 +1,135 @@ +// 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 `polkadot_runtime_parachains::inclusion` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-08-31, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `runner-svzsllib-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=polkadot_runtime_parachains::inclusion +// --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 `polkadot_runtime_parachains::inclusion`. +pub struct WeightInfo(PhantomData); +impl polkadot_runtime_parachains::inclusion::WeightInfo for WeightInfo { + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaSessionInfo::AccountKeys` (r:1 w:0) + /// Proof: `ParaSessionInfo::AccountKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Session::Validators` (r:1 w:0) + /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Staking::ActiveEra` (r:1 w:0) + /// Proof: `Staking::ActiveEra` (`max_values`: Some(1), `max_size`: Some(13), added: 508, mode: `MaxEncodedLen`) + /// Storage: `Staking::ErasRewardPoints` (r:1 w:1) + /// Proof: `Staking::ErasRewardPoints` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::FutureCodeHash` (r:1 w:1) + /// Proof: `Paras::FutureCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) + /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeCooldowns` (r:1 w:1) + /// Proof: `Paras::UpgradeCooldowns` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteMap` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteMap` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHash` (r:1 w:1) + /// Proof: `Paras::CodeByHash` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::PvfActiveVoteList` (r:1 w:1) + /// Proof: `Paras::PvfActiveVoteList` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Paras::CodeByHashRefs` (r:1 w:1) + /// Proof: `Paras::CodeByHashRefs` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) + /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1) + /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `MessageQueue::BookStateFor` (r:1 w:1) + /// Proof: `MessageQueue::BookStateFor` (`max_values`: None, `max_size`: Some(55), added: 2530, mode: `MaxEncodedLen`) + /// Storage: `MessageQueue::Pages` (r:1 w:2) + /// Proof: `MessageQueue::Pages` (`max_values`: None, `max_size`: Some(131122), added: 133597, mode: `MaxEncodedLen`) + /// Storage: `Hrmp::HrmpChannelDigests` (r:3 w:3) + /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannels` (r:2 w:2) + /// Proof: `Hrmp::HrmpChannels` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Hrmp::HrmpChannelContents` (r:2 w:2) + /// Proof: `Hrmp::HrmpChannelContents` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0) + /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Proof: UNKNOWN KEY `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) + /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) + /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::Heads` (r:0 w:1) + /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1) + /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::MostRecentContext` (r:0 w:1) + /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Paras::UpgradeRestrictionSignal` (r:0 w:1) + /// Proof: `Paras::UpgradeRestrictionSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// Proof: UNKNOWN KEY `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) + /// The range of component `u` is `[0, 2]`. + /// The range of component `h` is `[0, 2]`. + /// The range of component `c` is `[0, 1]`. + fn enact_candidate(u: u32, h: u32, c: u32, ) -> Weight { + // Proof Size summary in bytes: + // Measured: `1447 + c * (15992 ±0) + h * (92 ±0) + u * (131259 ±0)` + // Estimated: `134587 + c * (25419 ±939) + h * (29985 ±511) + u * (82828 ±511)` + // Minimum execution time: 1_065_780_000 picoseconds. + Weight::from_parts(192_328_221, 0) + .saturating_add(Weight::from_parts(0, 134587)) + // Standard Error: 1_263_527 + .saturating_add(Weight::from_parts(454_948_671, 0).saturating_mul(u.into())) + // Standard Error: 1_263_527 + .saturating_add(Weight::from_parts(527_131_211, 0).saturating_mul(h.into())) + // Standard Error: 2_093_815 + .saturating_add(Weight::from_parts(11_112_489, 0).saturating_mul(c.into())) + .saturating_add(T::DbWeight::get().reads(8)) + .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(u.into()))) + .saturating_add(T::DbWeight::get().reads((3_u64).saturating_mul(h.into()))) + .saturating_add(T::DbWeight::get().reads((9_u64).saturating_mul(c.into()))) + .saturating_add(T::DbWeight::get().writes(6)) + .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(u.into()))) + .saturating_add(T::DbWeight::get().writes((4_u64).saturating_mul(h.into()))) + .saturating_add(T::DbWeight::get().writes((8_u64).saturating_mul(c.into()))) + .saturating_add(Weight::from_parts(0, 25419).saturating_mul(c.into())) + .saturating_add(Weight::from_parts(0, 29985).saturating_mul(h.into())) + .saturating_add(Weight::from_parts(0, 82828).saturating_mul(u.into())) + } +} diff --git a/polkadot/runtime/westend/src/weights/runtime_parachains_initializer.rs b/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_initializer.rs similarity index 100% rename from polkadot/runtime/westend/src/weights/runtime_parachains_initializer.rs rename to polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_initializer.rs diff --git a/polkadot/runtime/westend/src/weights/runtime_parachains_assigner_on_demand.rs b/polkadot/runtime/westend/src/weights/polkadot_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/polkadot_runtime_parachains_on_demand.rs index 1bd9fa31b81b..fc7efa6edfcf 100644 --- a/polkadot/runtime/westend/src/weights/runtime_parachains_assigner_on_demand.rs +++ b/polkadot/runtime/westend/src/weights/polkadot_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/runtime_parachains_paras.rs b/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_paras.rs similarity index 100% rename from polkadot/runtime/westend/src/weights/runtime_parachains_paras.rs rename to polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_paras.rs diff --git a/polkadot/runtime/westend/src/weights/runtime_parachains_paras_inherent.rs b/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_paras_inherent.rs similarity index 79% rename from polkadot/runtime/westend/src/weights/runtime_parachains_paras_inherent.rs rename to polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_paras_inherent.rs index 74dd55cc3f2c..36aafc1d2f2a 100644 --- a/polkadot/runtime/westend/src/weights/runtime_parachains_paras_inherent.rs +++ b/polkadot/runtime/westend/src/weights/polkadot_runtime_parachains_paras_inherent.rs @@ -14,12 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Autogenerated weights for `runtime_parachains::paras_inherent` +//! Autogenerated weights for `polkadot_runtime_parachains::paras_inherent` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 -//! DATE: 2024-03-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2024-10-17, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner-h2rr8wx7-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` +//! HOSTNAME: `runner-dr4vwrkf-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024 // Executed Command: @@ -32,7 +32,7 @@ // --wasm-execution=compiled // --heap-pages=4096 // --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json -// --pallet=runtime_parachains::paras_inherent +// --pallet=polkadot_runtime_parachains::paras_inherent // --chain=westend-dev // --header=./polkadot/file_header.txt // --output=./polkadot/runtime/westend/src/weights/ @@ -45,7 +45,7 @@ use frame_support::{traits::Get, weights::Weight}; use core::marker::PhantomData; -/// Weight functions for `runtime_parachains::paras_inherent`. +/// Weight functions for `polkadot_runtime_parachains::paras_inherent`. pub struct WeightInfo(PhantomData); impl polkadot_runtime_parachains::paras_inherent::WeightInfo for WeightInfo { /// Storage: `ParaInherent::Included` (r:1 w:1) @@ -54,10 +54,52 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:0) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) + /// Proof: `Babe::AuthorVrfRandomness` (`max_values`: Some(1), `max_size`: Some(33), added: 528, mode: `MaxEncodedLen`) + /// Storage: `ParaInherent::OnChainVotes` (r:1 w:1) + /// Proof: `ParaInherent::OnChainVotes` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasDisputes::Frozen` (r:1 w:0) + /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaInclusion::V1` (r:1 w:0) + /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) + /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) + /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Session::DisabledValidators` (r:1 w:0) + /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn enter_empty() -> Weight { + // Proof Size summary in bytes: + // Measured: `37559` + // Estimated: `41024` + // Minimum execution time: 217_257_000 picoseconds. + Weight::from_parts(228_878_000, 0) + .saturating_add(Weight::from_parts(0, 41024)) + .saturating_add(T::DbWeight::get().reads(15)) + .saturating_add(T::DbWeight::get().writes(3)) + } + /// Storage: `ParaInherent::Included` (r:1 w:1) + /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `System::ParentHash` (r:1 w:0) + /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) + /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) + /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) + /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) @@ -94,16 +136,14 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Session::DisabledValidators` (r:1 w:0) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::Heads` (r:0 w:1) @@ -112,19 +152,18 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::MostRecentContext` (r:0 w:1) /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `v` is `[10, 200]`. + /// The range of component `v` is `[400, 1024]`. fn enter_variable_disputes(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `67518` - // Estimated: `73458 + v * (23 ±0)` - // Minimum execution time: 844_022_000 picoseconds. - Weight::from_parts(456_682_337, 0) - .saturating_add(Weight::from_parts(0, 73458)) - // Standard Error: 16_403 - .saturating_add(Weight::from_parts(41_871_245, 0).saturating_mul(v.into())) - .saturating_add(T::DbWeight::get().reads(28)) - .saturating_add(T::DbWeight::get().writes(16)) - .saturating_add(Weight::from_parts(0, 23).saturating_mul(v.into())) + // Measured: `117547` + // Estimated: `123487` + // Minimum execution time: 21_077_090_000 picoseconds. + Weight::from_parts(703_350_265, 0) + .saturating_add(Weight::from_parts(0, 123487)) + // Standard Error: 21_944 + .saturating_add(Weight::from_parts(51_197_317, 0).saturating_mul(v.into())) + .saturating_add(T::DbWeight::get().reads(29)) + .saturating_add(T::DbWeight::get().writes(17)) } /// Storage: `ParaInherent::Included` (r:1 w:1) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -132,10 +171,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:0) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) @@ -146,55 +187,23 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParasDisputes::Frozen` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParaInclusion::V1` (r:2 w:1) /// Proof: `ParaInclusion::V1` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParaSessionInfo::AccountKeys` (r:1 w:0) - /// Proof: `ParaSessionInfo::AccountKeys` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Session::Validators` (r:1 w:0) - /// Proof: `Session::Validators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `Staking::ActiveEra` (r:1 w:0) - /// Proof: `Staking::ActiveEra` (`max_values`: Some(1), `max_size`: Some(13), added: 508, mode: `MaxEncodedLen`) - /// Storage: `Staking::ErasRewardPoints` (r:1 w:1) - /// Proof: `Staking::ErasRewardPoints` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DownwardMessageQueues` (r:1 w:1) - /// Proof: `Dmp::DownwardMessageQueues` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Dmp::DeliveryFeeFactor` (r:1 w:1) - /// Proof: `Dmp::DeliveryFeeFactor` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpChannelDigests` (r:1 w:1) - /// Proof: `Hrmp::HrmpChannelDigests` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::FutureCodeUpgrades` (r:1 w:0) - /// Proof: `Paras::FutureCodeUpgrades` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `ParasDisputes::Disputes` (r:1 w:0) - /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorIndices` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Session::DisabledValidators` (r:1 w:0) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParasDisputes::Included` (r:0 w:1) - /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) - /// Proof: `Hrmp::HrmpWatermarks` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::Heads` (r:0 w:1) - /// Proof: `Paras::Heads` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::UpgradeGoAheadSignal` (r:0 w:1) - /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// Storage: `Paras::MostRecentContext` (r:0 w:1) - /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) fn enter_bitfields() -> Weight { // Proof Size summary in bytes: - // Measured: `43196` - // Estimated: `49136` - // Minimum execution time: 438_637_000 picoseconds. - Weight::from_parts(458_342_000, 0) - .saturating_add(Weight::from_parts(0, 49136)) - .saturating_add(T::DbWeight::get().reads(26)) - .saturating_add(T::DbWeight::get().writes(16)) + // Measured: `74967` + // Estimated: `80907` + // Minimum execution time: 487_605_000 picoseconds. + Weight::from_parts(506_014_000, 0) + .saturating_add(Weight::from_parts(0, 80907)) + .saturating_add(T::DbWeight::get().reads(16)) + .saturating_add(T::DbWeight::get().writes(4)) } /// Storage: `ParaInherent::Included` (r:1 w:1) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -202,10 +211,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) @@ -236,12 +247,8 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::ParaLifecycles` (r:1 w:0) @@ -252,6 +259,8 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Session::DisabledValidators` (r:1 w:0) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParasDisputes::Included` (r:0 w:1) /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) @@ -262,18 +271,18 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `Paras::UpgradeGoAheadSignal` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::MostRecentContext` (r:0 w:1) /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) - /// The range of component `v` is `[101, 200]`. + /// The range of component `v` is `[2, 5]`. fn enter_backed_candidates_variable(v: u32, ) -> Weight { // Proof Size summary in bytes: - // Measured: `43269` - // Estimated: `49209` - // Minimum execution time: 5_955_361_000 picoseconds. - Weight::from_parts(1_285_398_956, 0) - .saturating_add(Weight::from_parts(0, 49209)) - // Standard Error: 57_369 - .saturating_add(Weight::from_parts(47_073_853, 0).saturating_mul(v.into())) + // Measured: `76491` + // Estimated: `82431` + // Minimum execution time: 1_496_985_000 picoseconds. + Weight::from_parts(1_466_448_265, 0) + .saturating_add(Weight::from_parts(0, 82431)) + // Standard Error: 403_753 + .saturating_add(Weight::from_parts(44_015_233, 0).saturating_mul(v.into())) .saturating_add(T::DbWeight::get().reads(29)) - .saturating_add(T::DbWeight::get().writes(16)) + .saturating_add(T::DbWeight::get().writes(15)) } /// Storage: `ParaInherent::Included` (r:1 w:1) /// Proof: `ParaInherent::Included` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) @@ -281,10 +290,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `System::ParentHash` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`) /// Storage: `ParasShared::AllowedRelayParents` (r:1 w:1) /// Proof: `ParasShared::AllowedRelayParents` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) + /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0) /// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::AvailabilityCores` (r:1 w:1) - /// Proof: `ParaScheduler::AvailabilityCores` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) + /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `ParasShared::ActiveValidatorKeys` (r:1 w:0) /// Proof: `ParasShared::ActiveValidatorKeys` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Babe::AuthorVrfRandomness` (r:1 w:0) @@ -315,12 +326,8 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParasDisputes::Disputes` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParaScheduler::SessionStartBlock` (r:1 w:0) /// Proof: `ParaScheduler::SessionStartBlock` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ValidatorGroups` (r:1 w:0) - /// Proof: `ParaScheduler::ValidatorGroups` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `ParaScheduler::ClaimQueue` (r:1 w:1) - /// Proof: `ParaScheduler::ClaimQueue` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) - /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) - /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) + /// Storage: `Initializer::BufferedSessionChanges` (r:1 w:0) + /// Proof: `Initializer::BufferedSessionChanges` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Paras::CurrentCodeHash` (r:1 w:0) /// Proof: `Paras::CurrentCodeHash` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Paras::FutureCodeHash` (r:1 w:0) @@ -335,6 +342,8 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `ParasShared::ActiveValidatorIndices` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) /// Storage: `Session::DisabledValidators` (r:1 w:0) /// Proof: `Session::DisabledValidators` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1) + /// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `ParasDisputes::Included` (r:0 w:1) /// Proof: `ParasDisputes::Included` (`max_values`: None, `max_size`: None, mode: `Measured`) /// Storage: `Hrmp::HrmpWatermarks` (r:0 w:1) @@ -347,12 +356,12 @@ impl polkadot_runtime_parachains::paras_inherent::Weigh /// Proof: `Paras::MostRecentContext` (`max_values`: None, `max_size`: None, mode: `Measured`) fn enter_backed_candidate_code_upgrade() -> Weight { // Proof Size summary in bytes: - // Measured: `43282` - // Estimated: `49222` - // Minimum execution time: 42_128_606_000 picoseconds. - Weight::from_parts(42_822_806_000, 0) - .saturating_add(Weight::from_parts(0, 49222)) + // Measured: `76504` + // Estimated: `82444` + // Minimum execution time: 40_136_167_000 picoseconds. + Weight::from_parts(41_572_376_000, 0) + .saturating_add(Weight::from_parts(0, 82444)) .saturating_add(T::DbWeight::get().reads(31)) - .saturating_add(T::DbWeight::get().writes(16)) + .saturating_add(T::DbWeight::get().writes(15)) } } diff --git a/polkadot/runtime/westend/src/weights/runtime_parachains_inclusion.rs b/polkadot/runtime/westend/src/weights/runtime_parachains_inclusion.rs deleted file mode 100644 index 25909beb6a07..000000000000 --- a/polkadot/runtime/westend/src/weights/runtime_parachains_inclusion.rs +++ /dev/null @@ -1,75 +0,0 @@ -// 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 `runtime_parachains::inclusion` -//! -//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-06-14, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` -//! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `runner--ss9ysm1-project-163-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("westend-dev"), DB CACHE: 1024 - -// Executed Command: -// ./target/production/polkadot -// benchmark -// pallet -// --chain=westend-dev -// --steps=50 -// --repeat=20 -// --no-storage-info -// --no-median-slopes -// --no-min-squares -// --pallet=runtime_parachains::inclusion -// --extrinsic=* -// --execution=wasm -// --wasm-execution=compiled -// --header=./file_header.txt -// --output=./runtime/westend/src/weights/runtime_parachains_inclusion.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 `runtime_parachains::inclusion`. -pub struct WeightInfo(PhantomData); -impl polkadot_runtime_parachains::inclusion::WeightInfo for WeightInfo { - /// Storage: MessageQueue BookStateFor (r:1 w:1) - /// Proof: MessageQueue BookStateFor (max_values: None, max_size: Some(55), added: 2530, mode: MaxEncodedLen) - /// Storage: MessageQueue Pages (r:1 w:999) - /// Proof: MessageQueue Pages (max_values: None, max_size: Some(131122), added: 133597, mode: MaxEncodedLen) - /// Storage: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Proof Skipped: unknown `0x3a72656c61795f64697370617463685f71756575655f72656d61696e696e675f` (r:0 w:1) - /// Storage: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// Proof Skipped: unknown `0xf5207f03cfdce586301014700e2c2593fad157e461d71fd4c1f936839a5f1f3e` (r:0 w:1) - /// The range of component `i` is `[1, 1000]`. - fn receive_upward_messages(i: u32, ) -> Weight { - // Proof Size summary in bytes: - // Measured: `131297` - // Estimated: `134587` - // Minimum execution time: 209_898_000 picoseconds. - Weight::from_parts(210_955_000, 0) - .saturating_add(Weight::from_parts(0, 134587)) - // Standard Error: 97_069 - .saturating_add(Weight::from_parts(207_030_437, 0).saturating_mul(i.into())) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(3)) - .saturating_add(T::DbWeight::get().writes((1_u64).saturating_mul(i.into()))) - } -} 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 9939f16aa29f..e0c61c8e2bf2 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 9d7143c96bb5..d75083929a04 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/scripts/list-syscalls/execute-worker-syscalls b/polkadot/scripts/list-syscalls/execute-worker-syscalls index 349af783cf1a..4b22f6787864 100644 --- a/polkadot/scripts/list-syscalls/execute-worker-syscalls +++ b/polkadot/scripts/list-syscalls/execute-worker-syscalls @@ -20,6 +20,7 @@ 24 (sched_yield) 25 (mremap) 28 (madvise) +34 (pause) 39 (getpid) 41 (socket) 42 (connect) diff --git a/polkadot/scripts/list-syscalls/prepare-worker-syscalls b/polkadot/scripts/list-syscalls/prepare-worker-syscalls index 05281b61591a..fd46a788537d 100644 --- a/polkadot/scripts/list-syscalls/prepare-worker-syscalls +++ b/polkadot/scripts/list-syscalls/prepare-worker-syscalls @@ -20,6 +20,7 @@ 24 (sched_yield) 25 (mremap) 28 (madvise) +34 (pause) 39 (getpid) 41 (socket) 42 (connect) diff --git a/polkadot/statement-table/src/generic.rs b/polkadot/statement-table/src/generic.rs index e96ed6af73d9..e3c470fcdeec 100644 --- a/polkadot/statement-table/src/generic.rs +++ b/polkadot/statement-table/src/generic.rs @@ -245,7 +245,8 @@ impl CandidateData { pub fn attested( &self, validity_threshold: usize, - ) -> Option> { + ) -> Option> + { let valid_votes = self.validity_votes.len(); if valid_votes < validity_threshold { return None @@ -321,7 +322,8 @@ impl Table { digest: &Ctx::Digest, context: &Ctx, minimum_backing_votes: u32, - ) -> Option> { + ) -> Option> + { self.candidate_votes.get(digest).and_then(|data| { let v_threshold = context.get_group_size(&data.group_id).map_or(usize::MAX, |len| { effective_minimum_backing_votes(len, minimum_backing_votes) @@ -477,10 +479,7 @@ impl Table { if !context.is_member_of(&from, &votes.group_id) { let sig = match vote { ValidityVote::Valid(s) => s, - ValidityVote::Issued(_) => panic!( - "implicit issuance vote only cast from `import_candidate` after \ - checking group membership of issuer; qed" - ), + ValidityVote::Issued(s) => s, }; return Err(Misbehavior::UnauthorizedStatement(UnauthorizedStatement { diff --git a/polkadot/tests/common.rs b/polkadot/tests/common.rs index dbee2d365034..c13bb8cd1432 100644 --- a/polkadot/tests/common.rs +++ b/polkadot/tests/common.rs @@ -1,18 +1,18 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Substrate. +// This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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 Substrate. If not, see . +// along with Polkadot. If not, see . use polkadot_core_primitives::{Block, Hash, Header}; use std::{ diff --git a/polkadot/tests/invalid_order_arguments.rs b/polkadot/tests/invalid_order_arguments.rs index 8b5f4e31c17a..f9213bbdc308 100644 --- a/polkadot/tests/invalid_order_arguments.rs +++ b/polkadot/tests/invalid_order_arguments.rs @@ -1,18 +1,18 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Substrate. +// This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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 Substrate. If not, see . +// along with Polkadot. If not, see . use assert_cmd::cargo::cargo_bin; use std::process::Command; diff --git a/polkadot/tests/purge_chain_works.rs b/polkadot/tests/purge_chain_works.rs index f5a73e232e0c..bc36097b8d21 100644 --- a/polkadot/tests/purge_chain_works.rs +++ b/polkadot/tests/purge_chain_works.rs @@ -1,18 +1,18 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Substrate. +// This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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 Substrate. If not, see . +// along with Polkadot. If not, see . #![cfg(unix)] diff --git a/polkadot/tests/running_the_node_and_interrupt.rs b/polkadot/tests/running_the_node_and_interrupt.rs index 85c073d3023a..053acc966796 100644 --- a/polkadot/tests/running_the_node_and_interrupt.rs +++ b/polkadot/tests/running_the_node_and_interrupt.rs @@ -1,18 +1,18 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Substrate. +// This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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 Substrate. If not, see . +// along with Polkadot. If not, see . use assert_cmd::cargo::cargo_bin; use std::process::{self, Command}; diff --git a/polkadot/xcm/Cargo.toml b/polkadot/xcm/Cargo.toml index 72174bda2340..862f5557a012 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/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs index 99f17693093e..7cb230f6e006 100644 --- a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/parachain/xcm_config.rs @@ -152,7 +152,7 @@ impl pallet_xcm::Config for Runtime { // We turn off sending for these tests type SendXcmOrigin = EnsureXcmOrigin; type XcmRouter = super::super::network::ParachainXcmRouter; // Provided by xcm-simulator - // Anyone can execute XCM programs + // Anyone can execute XCM programs type ExecuteXcmOrigin = EnsureXcmOrigin; // We execute any type of program type XcmExecuteFilter = Everything; diff --git a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs index 987bb3f9ab66..a31e664d8216 100644 --- a/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs +++ b/polkadot/xcm/docs/src/cookbook/relay_token_transactor/relay_chain/xcm_config.rs @@ -125,7 +125,7 @@ impl pallet_xcm::Config for Runtime { // No one can call `send` type SendXcmOrigin = EnsureXcmOrigin; type XcmRouter = super::super::network::RelayChainXcmRouter; // Provided by xcm-simulator - // Anyone can execute XCM programs + // Anyone can execute XCM programs type ExecuteXcmOrigin = EnsureXcmOrigin; // We execute any type of program type XcmExecuteFilter = Everything; diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs index 40a7da58a687..f1ec3f604d7b 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/generic/benchmarking.rs @@ -121,7 +121,7 @@ benchmarks! { let instruction = Instruction::Transact { origin_kind: OriginKind::SovereignAccount, - require_weight_at_most: noop_call.get_dispatch_info().weight, + require_weight_at_most: noop_call.get_dispatch_info().call_weight, call: double_encoded_noop_call, }; let xcm = Xcm(vec![instruction]); diff --git a/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs b/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs index 4a12bb7f47c6..5f8482bdcb8c 100644 --- a/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs +++ b/polkadot/xcm/pallet-xcm-benchmarks/src/lib.rs @@ -62,7 +62,7 @@ const SEED: u32 = 0; /// The XCM executor to use for doing stuff. pub type ExecutorOf = xcm_executor::XcmExecutor<::XcmConfig>; /// The overarching call type. -pub type OverArchingCallOf = ::RuntimeCall; +pub type RuntimeCallOf = ::RuntimeCall; /// The asset transactor of our executor pub type AssetTransactorOf = <::XcmConfig as XcmConfig>::AssetTransactor; /// The call type of executor's config. Should eventually resolve to the same overarching call type. @@ -72,7 +72,7 @@ pub fn generate_holding_assets(max_assets: u32) -> Assets { let fungibles_amount: u128 = 100; let holding_fungibles = max_assets / 2; let holding_non_fungibles = max_assets - holding_fungibles - 1; // -1 because of adding `Here` asset - // add count of `holding_fungibles` + // add count of `holding_fungibles` (0..holding_fungibles) .map(|i| { Asset { diff --git a/polkadot/xcm/pallet-xcm/Cargo.toml b/polkadot/xcm/pallet-xcm/Cargo.toml index ed4b441d7c33..4d44d75e34dd 100644 --- a/polkadot/xcm/pallet-xcm/Cargo.toml +++ b/polkadot/xcm/pallet-xcm/Cargo.toml @@ -14,7 +14,7 @@ bounded-collections = { workspace = true } codec = { features = ["derive"], workspace = true } scale-info = { features = ["derive"], workspace = true } serde = { optional = true, features = ["derive"], workspace = true, default-features = true } -log = { workspace = true } +tracing = { workspace = true } frame-support = { workspace = true } frame-system = { workspace = true } @@ -44,13 +44,13 @@ std = [ "frame-benchmarking?/std", "frame-support/std", "frame-system/std", - "log/std", "pallet-balances/std", "scale-info/std", "serde", "sp-core/std", "sp-io/std", "sp-runtime/std", + "tracing/std", "xcm-builder/std", "xcm-executor/std", "xcm-runtime-apis/std", diff --git a/polkadot/xcm/pallet-xcm/src/benchmarking.rs b/polkadot/xcm/pallet-xcm/src/benchmarking.rs index d09c81bf434e..404b9358d4d9 100644 --- a/polkadot/xcm/pallet-xcm/src/benchmarking.rs +++ b/polkadot/xcm/pallet-xcm/src/benchmarking.rs @@ -128,14 +128,14 @@ benchmarks! { &origin_location, None, ).map_err(|error| { - log::error!("Fungible asset couldn't be deposited, error: {:?}", error); + tracing::error!("Fungible asset couldn't be deposited, error: {:?}", error); BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)) })?; }, NonFungible(instance) => { ::AssetTransactor::deposit_asset(&asset, &origin_location, None) .map_err(|error| { - log::error!("Nonfungible asset couldn't be deposited, error: {:?}", error); + tracing::error!("Nonfungible asset couldn't be deposited, error: {:?}", error); BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)) })?; } @@ -178,14 +178,14 @@ benchmarks! { &origin_location, None, ).map_err(|error| { - log::error!("Fungible asset couldn't be deposited, error: {:?}", error); + tracing::error!("Fungible asset couldn't be deposited, error: {:?}", error); BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)) })?; }, NonFungible(instance) => { ::AssetTransactor::deposit_asset(&asset, &origin_location, None) .map_err(|error| { - log::error!("Nonfungible asset couldn't be deposited, error: {:?}", error); + tracing::error!("Nonfungible asset couldn't be deposited, error: {:?}", error); BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)) })?; } diff --git a/polkadot/xcm/pallet-xcm/src/lib.rs b/polkadot/xcm/pallet-xcm/src/lib.rs index 6451901279b1..254bc2c7b83d 100644 --- a/polkadot/xcm/pallet-xcm/src/lib.rs +++ b/polkadot/xcm/pallet-xcm/src/lib.rs @@ -70,6 +70,7 @@ use xcm_executor::{ use xcm_runtime_apis::{ dry_run::{CallDryRunEffects, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::Error as XcmPaymentApiError, + trusted_query::Error as TrustedQueryApiError, }; #[cfg(any(feature = "try-runtime", test))] @@ -307,7 +308,7 @@ pub mod pallet { message: Box::RuntimeCall>>, max_weight: Weight, ) -> Result { - log::trace!(target: "xcm::pallet_xcm::execute", "message {:?}, max_weight {:?}", message, max_weight); + tracing::trace!(target: "xcm::pallet_xcm::execute", ?message, ?max_weight); let outcome = (|| { let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; let mut hash = message.using_encoded(sp_io::hashing::blake2_256); @@ -330,7 +331,7 @@ pub mod pallet { Self::deposit_event(Event::Attempted { outcome: outcome.clone() }); let weight_used = outcome.weight_used(); outcome.ensure_complete().map_err(|error| { - log::error!(target: "xcm::pallet_xcm::execute", "XCM execution failed with error {:?}", error); + tracing::error!(target: "xcm::pallet_xcm::execute", ?error, "XCM execution failed with error"); Error::::LocalExecutionIncomplete.with_weight( weight_used.saturating_add( ::execute(), @@ -897,10 +898,10 @@ pub mod pallet { pub fn migrate_to_v1( ) -> frame_support::weights::Weight { let on_chain_storage_version =

::on_chain_storage_version(); - log::info!( + tracing::info!( target: "runtime::xcm", - "Running migration storage v1 for xcm with storage version {:?}", - on_chain_storage_version, + ?on_chain_storage_version, + "Running migration storage v1 for xcm with storage version", ); if on_chain_storage_version < 1 { @@ -910,18 +911,18 @@ pub mod pallet { Some(value.into()) }); StorageVersion::new(1).put::

(); - log::info!( + tracing::info!( target: "runtime::xcm", - "Running migration storage v1 for xcm with storage version {:?} was complete", - on_chain_storage_version, + ?on_chain_storage_version, + "Running migration storage v1 for xcm with storage version was complete", ); // calculate and return migration weights T::DbWeight::get().reads_writes(count as u64 + 1, count as u64 + 1) } else { - log::warn!( + tracing::warn!( target: "runtime::xcm", - "Attempted to apply migration to v1 but failed because storage version is {:?}", - on_chain_storage_version, + ?on_chain_storage_version, + "Attempted to apply migration to v1 but failed because storage version is", ); T::DbWeight::get().reads(1) } @@ -1269,10 +1270,9 @@ pub mod pallet { let beneficiary: Location = (*beneficiary).try_into().map_err(|()| Error::::BadVersion)?; let assets: Assets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; - log::debug!( + tracing::debug!( target: "xcm::pallet_xcm::transfer_assets", - "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, fee-idx {:?}, weight_limit {:?}", - origin, dest, beneficiary, assets, fee_asset_item, weight_limit, + ?origin, ?dest, ?beneficiary, ?assets, ?fee_asset_item, ?weight_limit, ); ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets); @@ -1307,7 +1307,7 @@ pub mod pallet { beneficiary: Box, ) -> DispatchResult { let origin_location = T::ExecuteXcmOrigin::ensure_origin(origin)?; - log::debug!(target: "xcm::pallet_xcm::claim_assets", "origin: {:?}, assets: {:?}, beneficiary: {:?}", origin_location, assets, beneficiary); + tracing::debug!(target: "xcm::pallet_xcm::claim_assets", ?origin_location, ?assets, ?beneficiary); // Extract version from `assets`. let assets_version = assets.identify_version(); let assets: Assets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; @@ -1330,7 +1330,7 @@ pub mod pallet { weight, ); outcome.ensure_complete().map_err(|error| { - log::error!(target: "xcm::pallet_xcm::claim_assets", "XCM execution failed with error: {:?}", error); + tracing::error!(target: "xcm::pallet_xcm::claim_assets", ?error, "XCM execution failed with error"); Error::::LocalExecutionIncomplete })?; Ok(()) @@ -1403,11 +1403,10 @@ pub mod pallet { (*remote_fees_id).try_into().map_err(|()| Error::::BadVersion)?; let remote_xcm: Xcm<()> = (*custom_xcm_on_dest).try_into().map_err(|()| Error::::BadVersion)?; - log::debug!( + tracing::debug!( target: "xcm::pallet_xcm::transfer_assets_using_type_and_then", - "origin {origin_location:?}, dest {dest:?}, assets {assets:?} through {assets_transfer_type:?}, \ - remote_fees_id {fees_id:?} through {fees_transfer_type:?}, \ - custom_xcm_on_dest {remote_xcm:?}, weight-limit {weight_limit:?}", + ?origin_location, ?dest, ?assets, ?assets_transfer_type, ?fees_id, ?fees_transfer_type, + ?remote_xcm, ?weight_limit, ); let assets = assets.into_inner(); @@ -1568,10 +1567,9 @@ impl Pallet { let beneficiary: Location = (*beneficiary).try_into().map_err(|()| Error::::BadVersion)?; let assets: Assets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; - log::debug!( + tracing::debug!( target: "xcm::pallet_xcm::do_reserve_transfer_assets", - "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, fee-idx {:?}", - origin_location, dest, beneficiary, assets, fee_asset_item, + ?origin_location, ?dest, ?beneficiary, ?assets, ?fee_asset_item, ); ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets); @@ -1615,10 +1613,9 @@ impl Pallet { let beneficiary: Location = (*beneficiary).try_into().map_err(|()| Error::::BadVersion)?; let assets: Assets = (*assets).try_into().map_err(|()| Error::::BadVersion)?; - log::debug!( + tracing::debug!( target: "xcm::pallet_xcm::do_teleport_assets", - "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, fee-idx {:?}, weight_limit {:?}", - origin_location, dest, beneficiary, assets, fee_asset_item, weight_limit, + ?origin_location, ?dest, ?beneficiary, ?assets, ?fee_asset_item, ?weight_limit, ); ensure!(assets.len() <= MAX_ASSETS_FOR_TRANSFER, Error::::TooManyAssets); @@ -1719,11 +1716,9 @@ impl Pallet { fees: FeesHandling, weight_limit: WeightLimit, ) -> Result<(Xcm<::RuntimeCall>, Option>), Error> { - log::debug!( + tracing::debug!( target: "xcm::pallet_xcm::build_xcm_transfer_type", - "origin {:?}, dest {:?}, beneficiary {:?}, assets {:?}, transfer_type {:?}, \ - fees_handling {:?}, weight_limit: {:?}", - origin, dest, beneficiary, assets, transfer_type, fees, weight_limit, + ?origin, ?dest, ?beneficiary, ?assets, ?transfer_type, ?fees, ?weight_limit, ); match transfer_type { TransferType::LocalReserve => Self::local_reserve_transfer_programs( @@ -1778,10 +1773,9 @@ impl Pallet { mut local_xcm: Xcm<::RuntimeCall>, remote_xcm: Option>, ) -> DispatchResult { - log::debug!( + tracing::debug!( target: "xcm::pallet_xcm::execute_xcm_transfer", - "origin {:?}, dest {:?}, local_xcm {:?}, remote_xcm {:?}", - origin, dest, local_xcm, remote_xcm, + ?origin, ?dest, ?local_xcm, ?remote_xcm, ); let weight = @@ -1795,10 +1789,10 @@ impl Pallet { weight, ); Self::deposit_event(Event::Attempted { outcome: outcome.clone() }); - outcome.ensure_complete().map_err(|error| { - log::error!( + outcome.clone().ensure_complete().map_err(|error| { + tracing::error!( target: "xcm::pallet_xcm::execute_xcm_transfer", - "XCM execution failed with error {:?}", error + ?error, "XCM execution failed with error with outcome: {:?}", outcome ); Error::::LocalExecutionIncomplete })?; @@ -1807,10 +1801,10 @@ impl Pallet { let (ticket, price) = validate_send::(dest.clone(), remote_xcm.clone()) .map_err(Error::::from)?; if origin != Here.into_location() { - Self::charge_fees(origin.clone(), price).map_err(|error| { - log::error!( + Self::charge_fees(origin.clone(), price.clone()).map_err(|error| { + tracing::error!( target: "xcm::pallet_xcm::execute_xcm_transfer", - "Unable to charge fee with error {:?}", error + ?error, ?price, ?origin, "Unable to charge fee", ); Error::::FeesNotMet })?; @@ -1836,7 +1830,10 @@ impl Pallet { // no custom fees instructions, they are batched together with `assets` transfer; // BuyExecution happens after receiving all `assets` let reanchored_fees = - fees.reanchored(&dest, &context).map_err(|_| Error::::CannotReanchor)?; + fees.reanchored(&dest, &context).map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::add_fees_to_xcm", ?e, ?dest, ?context, "Failed to re-anchor fees"); + Error::::CannotReanchor + })?; // buy execution using `fees` batched together with above `reanchored_assets` remote.inner_mut().push(BuyExecution { fees: reanchored_fees, weight_limit }); }, @@ -1901,7 +1898,10 @@ impl Pallet { let mut reanchored_assets = assets.clone(); reanchored_assets .reanchor(&dest, &context) - .map_err(|_| Error::::CannotReanchor)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::local_reserve_transfer_programs", ?e, ?dest, ?context, "Failed to re-anchor assets"); + Error::::CannotReanchor + })?; // XCM instructions to be executed on local chain let mut local_execute_xcm = Xcm(vec![ @@ -1939,12 +1939,19 @@ impl Pallet { ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { let value = (origin, vec![fees.clone()]); ensure!(T::XcmReserveTransferFilter::contains(&value), Error::::Filtered); + ensure!( + ::IsReserve::contains(&fees, &dest), + Error::::InvalidAssetUnsupportedReserve + ); let context = T::UniversalLocation::get(); let reanchored_fees = fees .clone() .reanchored(&dest, &context) - .map_err(|_| Error::::CannotReanchor)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::destination_reserve_fees_instructions", ?e, ?dest,?context, "Failed to re-anchor fees"); + Error::::CannotReanchor + })?; let fees: Assets = fees.into(); let local_execute_xcm = Xcm(vec![ @@ -1973,6 +1980,12 @@ impl Pallet { let value = (origin, assets); ensure!(T::XcmReserveTransferFilter::contains(&value), Error::::Filtered); let (_, assets) = value; + for asset in assets.iter() { + ensure!( + ::IsReserve::contains(&asset, &dest), + Error::::InvalidAssetUnsupportedReserve + ); + } // max assets is `assets` (+ potentially separately handled fee) let max_assets = @@ -1982,7 +1995,10 @@ impl Pallet { let mut reanchored_assets = assets.clone(); reanchored_assets .reanchor(&dest, &context) - .map_err(|_| Error::::CannotReanchor)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::destination_reserve_transfer_programs", ?e, ?dest, ?context, "Failed to re-anchor assets"); + Error::::CannotReanchor + })?; // XCM instructions to be executed on local chain let mut local_execute_xcm = Xcm(vec![ @@ -2036,13 +2052,22 @@ impl Pallet { // identifies fee item as seen by `reserve` - to be used at reserve chain let reserve_fees = fees_half_1 .reanchored(&reserve, &context) - .map_err(|_| Error::::CannotReanchor)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::remote_reserve_transfer_program", ?e, ?reserve, ?context, "Failed to re-anchor reserve_fees"); + Error::::CannotReanchor + })?; // identifies fee item as seen by `dest` - to be used at destination chain let dest_fees = fees_half_2 .reanchored(&dest, &context) - .map_err(|_| Error::::CannotReanchor)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::remote_reserve_transfer_program", ?e, ?dest, ?context, "Failed to re-anchor dest_fees"); + Error::::CannotReanchor + })?; // identifies `dest` as seen by `reserve` - let dest = dest.reanchored(&reserve, &context).map_err(|_| Error::::CannotReanchor)?; + let dest = dest.reanchored(&reserve, &context).map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::remote_reserve_transfer_program", ?e, ?reserve, ?context, "Failed to re-anchor dest"); + Error::::CannotReanchor + })?; // xcm to be executed at dest let mut xcm_on_dest = Xcm(vec![BuyExecution { fees: dest_fees, weight_limit: weight_limit.clone() }]); @@ -2079,12 +2104,19 @@ impl Pallet { ) -> Result<(Xcm<::RuntimeCall>, Xcm<()>), Error> { let value = (origin, vec![fees.clone()]); ensure!(T::XcmTeleportFilter::contains(&value), Error::::Filtered); + ensure!( + ::IsTeleporter::contains(&fees, &dest), + Error::::Filtered + ); let context = T::UniversalLocation::get(); let reanchored_fees = fees .clone() .reanchored(&dest, &context) - .map_err(|_| Error::::CannotReanchor)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::teleport_fees_instructions", ?e, ?dest, ?context, "Failed to re-anchor fees"); + Error::::CannotReanchor + })?; // XcmContext irrelevant in teleports checks let dummy_context = @@ -2098,7 +2130,10 @@ impl Pallet { &fees, &dummy_context, ) - .map_err(|_| Error::::CannotCheckOutTeleport)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::teleport_fees_instructions", ?e, ?fees, ?dest, "Failed can_check_out"); + Error::::CannotCheckOutTeleport + })?; // safe to do this here, we're in a transactional call that will be reverted on any // errors down the line ::AssetTransactor::check_out( @@ -2134,6 +2169,12 @@ impl Pallet { let value = (origin, assets); ensure!(T::XcmTeleportFilter::contains(&value), Error::::Filtered); let (_, assets) = value; + for asset in assets.iter() { + ensure!( + ::IsTeleporter::contains(&asset, &dest), + Error::::Filtered + ); + } // max assets is `assets` (+ potentially separately handled fee) let max_assets = @@ -2143,7 +2184,10 @@ impl Pallet { let mut reanchored_assets = assets.clone(); reanchored_assets .reanchor(&dest, &context) - .map_err(|_| Error::::CannotReanchor)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::teleport_assets_program", ?e, ?dest, ?context, "Failed to re-anchor asset"); + Error::::CannotReanchor + })?; // XcmContext irrelevant in teleports checks let dummy_context = @@ -2158,7 +2202,10 @@ impl Pallet { asset, &dummy_context, ) - .map_err(|_| Error::::CannotCheckOutTeleport)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::teleport_assets_program", ?e, ?asset, ?dest, "Failed can_check_out asset"); + Error::::CannotCheckOutTeleport + })?; } for asset in assets.inner() { // safe to do this here, we're in a transactional call that will be reverted on any @@ -2428,10 +2475,17 @@ impl Pallet { } else { None }; - log::debug!(target: "xcm::send_xcm", "dest: {:?}, message: {:?}", &dest, &message); + tracing::debug!(target: "xcm::send_xcm", "{:?}, {:?}", dest.clone(), message.clone()); let (ticket, price) = validate_send::(dest, message)?; if let Some(fee_payer) = maybe_fee_payer { - Self::charge_fees(fee_payer, price).map_err(|_| SendError::Fees)?; + Self::charge_fees(fee_payer, price).map_err(|e| { + tracing::error!( + target: "xcm::pallet_xcm::send_xcm", + ?e, + "Charging fees failed with error", + ); + SendError::Fees + })?; } T::XcmRouter::deliver(ticket) } @@ -2457,10 +2511,14 @@ impl Pallet { ::RuntimeOrigin: From, { crate::Pallet::::set_record_xcm(true); - frame_system::Pallet::::reset_events(); // To make sure we only record events from current call. + // Clear other messages in queues... + Router::clear_messages(); + // ...and reset events to make sure we only record events from current call. + frame_system::Pallet::::reset_events(); let result = call.dispatch(origin.into()); crate::Pallet::::set_record_xcm(false); let local_xcm = crate::Pallet::::recorded_xcm(); + // Should only get messages from this call since we cleared previous ones. let forwarded_xcms = Router::get_messages(); let events: Vec<::RuntimeEvent> = frame_system::Pallet::::read_events_no_consensus() @@ -2488,18 +2546,16 @@ impl Pallet { XcmConfig: xcm_executor::Config, { let origin_location: Location = origin_location.try_into().map_err(|error| { - log::error!( + tracing::error!( target: "xcm::DryRunApi::dry_run_xcm", - "Location version conversion failed with error: {:?}", - error, + ?error, "Location version conversion failed with error" ); XcmDryRunApiError::VersionedConversionFailed })?; let xcm: Xcm = xcm.try_into().map_err(|error| { - log::error!( + tracing::error!( target: "xcm::DryRunApi::dry_run_xcm", - "Xcm version conversion failed with error {:?}", - error, + ?error, "Xcm version conversion failed with error" ); XcmDryRunApiError::VersionedConversionFailed })?; @@ -2536,36 +2592,100 @@ impl Pallet { } pub fn query_xcm_weight(message: VersionedXcm<()>) -> Result { - let message = Xcm::<()>::try_from(message) - .map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; + let message = Xcm::<()>::try_from(message.clone()) + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::query_xcm_weight", ?e, ?message, "Failed to convert versioned message"); + XcmPaymentApiError::VersionedConversionFailed + })?; - T::Weigher::weight(&mut message.into()).map_err(|()| { - log::error!(target: "xcm::pallet_xcm::query_xcm_weight", "Error when querying XCM weight"); + T::Weigher::weight(&mut message.clone().into()).map_err(|()| { + tracing::error!(target: "xcm::pallet_xcm::query_xcm_weight", ?message, "Error when querying XCM weight"); XcmPaymentApiError::WeightNotComputable }) } + /// Given an Asset and a Location, returns if the provided location is a trusted reserve for the + /// given asset. + pub fn is_trusted_reserve( + asset: VersionedAsset, + location: VersionedLocation, + ) -> Result { + let location: Location = location.try_into().map_err(|e| { + tracing::debug!( + target: "xcm::pallet_xcm::is_trusted_reserve", + "Asset version conversion failed with error: {:?}", + e, + ); + TrustedQueryApiError::VersionedLocationConversionFailed + })?; + + let a: Asset = asset.try_into().map_err(|e| { + tracing::debug!( + target: "xcm::pallet_xcm::is_trusted_reserve", + "Location version conversion failed with error: {:?}", + e, + ); + TrustedQueryApiError::VersionedAssetConversionFailed + })?; + + Ok(::IsReserve::contains(&a, &location)) + } + + /// Given an Asset and a Location, returns if the asset can be teleported to provided location. + pub fn is_trusted_teleporter( + asset: VersionedAsset, + location: VersionedLocation, + ) -> Result { + let location: Location = location.try_into().map_err(|e| { + tracing::debug!( + target: "xcm::pallet_xcm::is_trusted_teleporter", + "Asset version conversion failed with error: {:?}", + e, + ); + TrustedQueryApiError::VersionedLocationConversionFailed + })?; + let a: Asset = asset.try_into().map_err(|e| { + tracing::debug!( + target: "xcm::pallet_xcm::is_trusted_teleporter", + "Location version conversion failed with error: {:?}", + e, + ); + TrustedQueryApiError::VersionedAssetConversionFailed + })?; + Ok(::IsTeleporter::contains(&a, &location)) + } + pub fn query_delivery_fees( destination: VersionedLocation, message: VersionedXcm<()>, ) -> Result { let result_version = destination.identify_version().max(message.identify_version()); - let destination = destination + let destination: Location = destination + .clone() .try_into() - .map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::query_delivery_fees", ?e, ?destination, "Failed to convert versioned destination"); + XcmPaymentApiError::VersionedConversionFailed + })?; - let message = - message.try_into().map_err(|_| XcmPaymentApiError::VersionedConversionFailed)?; + let message: Xcm<()> = + message.clone().try_into().map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::query_delivery_fees", ?e, ?message, "Failed to convert versioned message"); + XcmPaymentApiError::VersionedConversionFailed + })?; - let (_, fees) = validate_send::(destination, message).map_err(|error| { - log::error!(target: "xcm::pallet_xcm::query_delivery_fees", "Error when querying delivery fees: {:?}", error); + let (_, fees) = validate_send::(destination.clone(), message.clone()).map_err(|error| { + tracing::error!(target: "xcm::pallet_xcm::query_delivery_fees", ?error, ?destination, ?message, "Failed to validate send to destination"); XcmPaymentApiError::Unroutable })?; VersionedAssets::from(fees) .into_version(result_version) - .map_err(|_| XcmPaymentApiError::VersionedConversionFailed) + .map_err(|e| { + tracing::error!(target: "xcm::pallet_xcm::query_delivery_fees", ?e, ?result_version, "Failed to convert fees into version"); + XcmPaymentApiError::VersionedConversionFailed + }) } /// Create a new expectation of a query response with the querier being here. @@ -2624,7 +2744,7 @@ impl Pallet { .invert_target(&responder) .map_err(|()| XcmError::LocationNotInvertible)?; let notify: ::RuntimeCall = notify.into(); - let max_weight = notify.get_dispatch_info().weight; + let max_weight = notify.get_dispatch_info().call_weight; let query_id = Self::new_notify_query(responder, notify, timeout, Here); let response_info = QueryResponseInfo { destination, query_id, max_weight }; let report_error = Xcm(vec![ReportError(response_info)]); @@ -2649,10 +2769,9 @@ impl Pallet { /// Note that a particular destination to whom we would like to send a message is unknown /// and queue it for version discovery. fn note_unknown_version(dest: &Location) { - log::trace!( + tracing::trace!( target: "xcm::pallet_xcm::note_unknown_version", - "XCM version is unknown for destination: {:?}", - dest, + ?dest, "XCM version is unknown for destination" ); let versioned_dest = VersionedLocation::from(dest.clone()); VersionDiscoveryQueue::::mutate(|q| { @@ -2920,10 +3039,9 @@ impl WrapVersion for Pallet { SafeXcmVersion::::get() }) .ok_or_else(|| { - log::trace!( + tracing::trace!( target: "xcm::pallet_xcm::wrap_version", - "Could not determine a version to wrap XCM for destination: {:?}", - dest, + ?dest, "Could not determine a version to wrap XCM for destination", ); () }) @@ -3160,7 +3278,7 @@ impl OnResponse for Pallet { ::RuntimeCall::decode(&mut bytes) }) { Queries::::remove(query_id); - let weight = call.get_dispatch_info().weight; + let weight = call.get_dispatch_info().call_weight; if weight.any_gt(max_weight) { let e = Event::NotifyOverweight { query_id, diff --git a/polkadot/xcm/pallet-xcm/src/migration.rs b/polkadot/xcm/pallet-xcm/src/migration.rs index 0aec97ab4105..2c5b2620f535 100644 --- a/polkadot/xcm/pallet-xcm/src/migration.rs +++ b/polkadot/xcm/pallet-xcm/src/migration.rs @@ -40,7 +40,7 @@ pub mod v1 { let mut weight = T::DbWeight::get().reads(1); if StorageVersion::get::>() != 0 { - log::warn!("skipping v1, should be removed"); + tracing::warn!("skipping v1, should be removed"); return weight } @@ -50,13 +50,13 @@ pub mod v1 { let translate = |pre: (u64, u64, u32)| -> Option<(u64, Weight, u32)> { weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1)); let translated = (pre.0, Weight::from_parts(pre.1, DEFAULT_PROOF_SIZE), pre.2); - log::info!("Migrated VersionNotifyTarget {:?} to {:?}", pre, translated); + tracing::info!("Migrated VersionNotifyTarget {:?} to {:?}", pre, translated); Some(translated) }; VersionNotifyTargets::::translate_values(translate); - log::info!("v1 applied successfully"); + tracing::info!("v1 applied successfully"); weight.saturating_accrue(T::DbWeight::get().writes(1)); StorageVersion::new(1).put::>(); weight diff --git a/polkadot/xcm/pallet-xcm/src/mock.rs b/polkadot/xcm/pallet-xcm/src/mock.rs index 3941d104b81c..8d0476b0e70d 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 a7db183bcdbf..83b35d19cf7e 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/procedural/tests/ui.rs b/polkadot/xcm/procedural/tests/ui.rs index b3469b520eb7..4d0c8af45005 100644 --- a/polkadot/xcm/procedural/tests/ui.rs +++ b/polkadot/xcm/procedural/tests/ui.rs @@ -16,7 +16,6 @@ //! UI tests for XCM procedural macros -#[cfg(not(feature = "disable-ui-tests"))] #[test] fn ui() { // Only run the ui tests when `RUN_UI_TESTS` is set. diff --git a/polkadot/xcm/src/lib.rs b/polkadot/xcm/src/lib.rs index 1f5191c23407..0b916c87f549 100644 --- a/polkadot/xcm/src/lib.rs +++ b/polkadot/xcm/src/lib.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/polkadot/xcm/src/v2/mod.rs b/polkadot/xcm/src/v2/mod.rs index 1afc120f500c..e3358f08d410 100644 --- a/polkadot/xcm/src/v2/mod.rs +++ b/polkadot/xcm/src/v2/mod.rs @@ -1,18 +1,18 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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 Cumulus. If not, see . +// along with Polkadot. If not, see . //! # XCM Version 2 //! diff --git a/polkadot/xcm/src/v2/multiasset.rs b/polkadot/xcm/src/v2/multiasset.rs index 7090ef138ca2..218f21b63b0a 100644 --- a/polkadot/xcm/src/v2/multiasset.rs +++ b/polkadot/xcm/src/v2/multiasset.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/polkadot/xcm/src/v2/traits.rs b/polkadot/xcm/src/v2/traits.rs index 4dcb4c50c68c..815495b81271 100644 --- a/polkadot/xcm/src/v2/traits.rs +++ b/polkadot/xcm/src/v2/traits.rs @@ -1,18 +1,18 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Cumulus. +// This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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 Cumulus. If not, see . +// along with Polkadot. If not, see . //! Cross-Consensus Message format data structures. diff --git a/polkadot/xcm/src/v3/mod.rs b/polkadot/xcm/src/v3/mod.rs index 880520cfedc2..ff64c98e15b3 100644 --- a/polkadot/xcm/src/v3/mod.rs +++ b/polkadot/xcm/src/v3/mod.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/polkadot/xcm/src/v3/multiasset.rs b/polkadot/xcm/src/v3/multiasset.rs index 7db0fa736902..56b46b1d921e 100644 --- a/polkadot/xcm/src/v3/multiasset.rs +++ b/polkadot/xcm/src/v3/multiasset.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/polkadot/xcm/src/v3/traits.rs b/polkadot/xcm/src/v3/traits.rs index 7fa8824c3568..34c46453b9a8 100644 --- a/polkadot/xcm/src/v3/traits.rs +++ b/polkadot/xcm/src/v3/traits.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/polkadot/xcm/src/v4/asset.rs b/polkadot/xcm/src/v4/asset.rs index a081b595adb1..41f1f82f828c 100644 --- a/polkadot/xcm/src/v4/asset.rs +++ b/polkadot/xcm/src/v4/asset.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/polkadot/xcm/src/v4/location.rs b/polkadot/xcm/src/v4/location.rs index 9e94d13626d6..f2c302495c73 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 57840562ba3e..a2b12dcc54ce 100644 --- a/polkadot/xcm/src/v4/mod.rs +++ b/polkadot/xcm/src/v4/mod.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. @@ -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/src/v4/traits.rs b/polkadot/xcm/src/v4/traits.rs index 351de92c80ed..f32b26fb163d 100644 --- a/polkadot/xcm/src/v4/traits.rs +++ b/polkadot/xcm/src/v4/traits.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/polkadot/xcm/xcm-builder/Cargo.toml b/polkadot/xcm/xcm-builder/Cargo.toml index 7702e2f9be07..eaa115740f3e 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,9 +45,11 @@ 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", + "pallet-transaction-payment/runtime-benchmarks", "pallet-xcm/runtime-benchmarks", "polkadot-parachain-primitives/runtime-benchmarks", "polkadot-primitives/runtime-benchmarks", @@ -59,8 +63,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_conversion.rs b/polkadot/xcm/xcm-builder/src/asset_conversion.rs index 16ae05c20795..6d090b04886c 100644 --- a/polkadot/xcm/xcm-builder/src/asset_conversion.rs +++ b/polkadot/xcm/xcm-builder/src/asset_conversion.rs @@ -137,7 +137,13 @@ impl< ConvertClassId: MaybeEquivalence, ConvertInstanceId: MaybeEquivalence, > MatchesNonFungibles - for MatchedConvertedConcreteId + for MatchedConvertedConcreteId< + ClassId, + InstanceId, + MatchClassId, + ConvertClassId, + ConvertInstanceId, + > { fn matches_nonfungibles(a: &Asset) -> result::Result<(ClassId, InstanceId), MatchError> { let (instance, class) = match (&a.fun, &a.id) { diff --git a/bridges/bin/runtime-common/src/extensions/mod.rs b/polkadot/xcm/xcm-builder/src/asset_exchange/mod.rs similarity index 51% rename from bridges/bin/runtime-common/src/extensions/mod.rs rename to polkadot/xcm/xcm-builder/src/asset_exchange/mod.rs index 3f1b506aaae3..d42a443c9be1 100644 --- a/bridges/bin/runtime-common/src/extensions/mod.rs +++ b/polkadot/xcm/xcm-builder/src/asset_exchange/mod.rs @@ -1,21 +1,22 @@ // Copyright (C) Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. +// This file is part of Polkadot. -// Parity Bridges Common is free software: you can redistribute it and/or modify +// 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. -// Parity Bridges Common is distributed in the hope that it will be useful, +// 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 Parity Bridges Common. If not, see . +// along with Polkadot. If not, see . -//! Bridge-specific transaction extensions. +//! Adapters for the AssetExchanger config item. +//! +//! E.g. types that implement the [`xcm_executor::traits::AssetExchange`] trait. -pub mod check_obsolete_extension; -pub mod priority_calculator; -pub mod refund_relayer_extension; +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 000000000000..3108068686f9 --- /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, if credit_change.peek() > 0 { Some(credit_change) } else { None }) + }; + + // 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 000000000000..4d9809e84f88 --- /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/node/jaeger/src/errors.rs b/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mod.rs similarity index 69% rename from polkadot/node/jaeger/src/errors.rs rename to polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mod.rs index adedda34c7fc..2a47832923f7 100644 --- a/polkadot/node/jaeger/src/errors.rs +++ b/polkadot/xcm/xcm-builder/src/asset_exchange/single_asset_adapter/mod.rs @@ -14,15 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Polkadot. If not, see . -//! Polkadot Jaeger error definitions. +//! SingleAssetExchangeAdapter. -/// A description of an error during jaeger initialization. -#[derive(Debug, thiserror::Error)] -#[allow(missing_docs)] -pub enum JaegerError { - #[error("Already launched the collector thread")] - AlreadyLaunched, +mod adapter; +pub use adapter::SingleAssetExchangeAdapter; - #[error("Missing jaeger configuration")] - MissingConfiguration, -} +#[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 000000000000..83f57f32822f --- /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/barriers.rs b/polkadot/xcm/xcm-builder/src/barriers.rs index 5d95005eb663..c995361ea8a3 100644 --- a/polkadot/xcm/xcm-builder/src/barriers.rs +++ b/polkadot/xcm/xcm-builder/src/barriers.rs @@ -57,8 +57,9 @@ const MAX_ASSETS_FOR_BUY_EXECUTION: usize = 2; /// Allows execution from `origin` if it is contained in `T` (i.e. `T::Contains(origin)`) taking /// payments into account. /// -/// Only allows for `TeleportAsset`, `WithdrawAsset`, `ClaimAsset` and `ReserveAssetDeposit` XCMs -/// because they are the only ones that place assets in the Holding Register to pay for execution. +/// Only allows for `WithdrawAsset`, `ReceiveTeleportedAsset`, `ReserveAssetDeposited` and +/// `ClaimAsset` XCMs because they are the only ones that place assets in the Holding Register to +/// pay for execution. pub struct AllowTopLevelPaidExecutionFrom(PhantomData); impl> ShouldExecute for AllowTopLevelPaidExecutionFrom { fn should_execute( @@ -81,9 +82,9 @@ impl> ShouldExecute for AllowTopLevelPaidExecutionFrom instructions[..end] .matcher() .match_next_inst(|inst| match inst { + WithdrawAsset(ref assets) | ReceiveTeleportedAsset(ref assets) | ReserveAssetDeposited(ref assets) | - WithdrawAsset(ref assets) | ClaimAsset { ref assets, .. } => if assets.len() <= MAX_ASSETS_FOR_BUY_EXECUTION { Ok(()) @@ -92,7 +93,10 @@ impl> ShouldExecute for AllowTopLevelPaidExecutionFrom }, _ => Err(ProcessMessageError::BadFormat), })? - .skip_inst_while(|inst| matches!(inst, ClearOrigin))? + .skip_inst_while(|inst| { + matches!(inst, ClearOrigin | AliasOrigin(..)) || + matches!(inst, DescendOrigin(child) if child != &Here) + })? .match_next_inst(|inst| match inst { BuyExecution { weight_limit: Limited(ref mut weight), .. } if weight.all_gte(max_weight) => diff --git a/polkadot/xcm/xcm-builder/src/fee_handling.rs b/polkadot/xcm/xcm-builder/src/fee_handling.rs index e114b3601c84..17e9e64e00c9 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 c3495601cd87..bec3bdcb05a0 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/matcher.rs b/polkadot/xcm/xcm-builder/src/matcher.rs index eae43b290fb2..ab515f180527 100644 --- a/polkadot/xcm/xcm-builder/src/matcher.rs +++ b/polkadot/xcm/xcm-builder/src/matcher.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs b/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs index b111a05a4f1f..006c28954bce 100644 --- a/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs +++ b/polkadot/xcm/xcm-builder/src/nonfungibles_adapter.rs @@ -270,7 +270,14 @@ impl< CheckAsset: AssetChecking, CheckingAccount: Get>, > TransactAsset - for NonFungiblesAdapter + for NonFungiblesAdapter< + Assets, + Matcher, + AccountIdConverter, + AccountId, + CheckAsset, + CheckingAccount, + > { fn can_check_in(origin: &Location, what: &Asset, context: &XcmContext) -> XcmResult { NonFungiblesMutateAdapter::< diff --git a/polkadot/xcm/xcm-builder/src/routing.rs b/polkadot/xcm/xcm-builder/src/routing.rs index 03ef780ef032..fc2de89d2128 100644 --- a/polkadot/xcm/xcm-builder/src/routing.rs +++ b/polkadot/xcm/xcm-builder/src/routing.rs @@ -62,6 +62,10 @@ impl SendXcm for WithUniqueTopic { } } impl InspectMessageQueues for WithUniqueTopic { + fn clear_messages() { + Inner::clear_messages() + } + fn get_messages() -> Vec<(VersionedLocation, Vec>)> { Inner::get_messages() } @@ -149,12 +153,21 @@ impl EnsureDelivery for Tuple { /// Inspects messages in queues. /// Meant to be used in runtime APIs, not in runtimes. pub trait InspectMessageQueues { + /// Clear the queues at the beginning of Runtime API call, so that subsequent + /// `Self::get_messages()` will return only messages generated by said Runtime API. + fn clear_messages(); /// Get queued messages and their destinations. fn get_messages() -> Vec<(VersionedLocation, Vec>)>; } #[impl_trait_for_tuples::impl_for_tuples(30)] impl InspectMessageQueues for Tuple { + fn clear_messages() { + for_tuples!( #( + Tuple::clear_messages(); + )* ); + } + fn get_messages() -> Vec<(VersionedLocation, Vec>)> { let mut messages = Vec::new(); diff --git a/polkadot/xcm/xcm-builder/src/test_utils.rs b/polkadot/xcm/xcm-builder/src/test_utils.rs index 37a49a1b3dc7..90afb2c9a3d3 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/barriers.rs b/polkadot/xcm/xcm-builder/src/tests/barriers.rs index 665b5febc61f..cd2b6db66efc 100644 --- a/polkadot/xcm/xcm-builder/src/tests/barriers.rs +++ b/polkadot/xcm/xcm-builder/src/tests/barriers.rs @@ -283,6 +283,56 @@ fn allow_paid_should_work() { assert_eq!(r, Ok(())) } +#[test] +fn allow_paid_should_deprivilege_origin() { + AllowPaidFrom::set(vec![Parent.into()]); + let fees = (Parent, 1).into(); + + let mut paying_message_clears_origin = Xcm::<()>(vec![ + ReserveAssetDeposited((Parent, 100).into()), + ClearOrigin, + BuyExecution { fees, weight_limit: Limited(Weight::from_parts(30, 30)) }, + DepositAsset { assets: AllCounted(1).into(), beneficiary: Here.into() }, + ]); + let r = AllowTopLevelPaidExecutionFrom::>::should_execute( + &Parent.into(), + paying_message_clears_origin.inner_mut(), + Weight::from_parts(30, 30), + &mut props(Weight::zero()), + ); + assert_eq!(r, Ok(())); + + let mut paying_message_aliases_origin = paying_message_clears_origin.clone(); + paying_message_aliases_origin.0[1] = AliasOrigin(Parachain(1).into()); + let r = AllowTopLevelPaidExecutionFrom::>::should_execute( + &Parent.into(), + paying_message_aliases_origin.inner_mut(), + Weight::from_parts(30, 30), + &mut props(Weight::zero()), + ); + assert_eq!(r, Ok(())); + + let mut paying_message_descends_origin = paying_message_clears_origin.clone(); + paying_message_descends_origin.0[1] = DescendOrigin(Parachain(1).into()); + let r = AllowTopLevelPaidExecutionFrom::>::should_execute( + &Parent.into(), + paying_message_descends_origin.inner_mut(), + Weight::from_parts(30, 30), + &mut props(Weight::zero()), + ); + assert_eq!(r, Ok(())); + + let mut paying_message_fake_descends_origin = paying_message_clears_origin.clone(); + paying_message_fake_descends_origin.0[1] = DescendOrigin(Here.into()); + let r = AllowTopLevelPaidExecutionFrom::>::should_execute( + &Parent.into(), + paying_message_fake_descends_origin.inner_mut(), + Weight::from_parts(30, 30), + &mut props(Weight::zero()), + ); + assert_eq!(r, Err(ProcessMessageError::Overweight(Weight::from_parts(30, 30)))); +} + #[test] fn suspension_should_work() { TestSuspender::set_suspended(true); diff --git a/polkadot/xcm/xcm-builder/src/tests/mock.rs b/polkadot/xcm/xcm-builder/src/tests/mock.rs index ac43d217ff3f..bec7b253977b 100644 --- a/polkadot/xcm/xcm-builder/src/tests/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/mock.rs @@ -100,13 +100,13 @@ impl Dispatchable for TestCall { impl GetDispatchInfo for TestCall { fn get_dispatch_info(&self) -> DispatchInfo { - let weight = *match self { + let call_weight = *match self { TestCall::OnlyRoot(estimate, ..) | TestCall::OnlyParachain(estimate, ..) | TestCall::OnlySigned(estimate, ..) | TestCall::Any(estimate, ..) => estimate, }; - DispatchInfo { weight, ..Default::default() } + DispatchInfo { call_weight, ..Default::default() } } } @@ -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-builder/src/tests/pay/mock.rs b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs index 18bde3aab485..d76ff21b8597 100644 --- a/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs +++ b/polkadot/xcm/xcm-builder/src/tests/pay/mock.rs @@ -26,13 +26,21 @@ use frame_support::{ }; use frame_system::{EnsureRoot, EnsureSigned}; use polkadot_primitives::{AccountIndex, BlakeTwo256, Signature}; -use polkadot_test_runtime::SignedExtra; use sp_runtime::{generic, traits::MaybeEquivalence, AccountId32, BuildStorage}; use xcm_executor::{traits::ConvertLocation, XcmExecutor}; +pub type TxExtension = ( + frame_system::CheckNonZeroSender, + frame_system::CheckSpecVersion, + frame_system::CheckTxVersion, + frame_system::CheckGenesis, + frame_system::CheckMortality, + frame_system::CheckNonce, + frame_system::CheckWeight, +); pub type Address = sp_runtime::MultiAddress; pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; pub type Header = generic::Header; pub type Block = generic::Block; @@ -77,6 +85,7 @@ impl pallet_balances::Config for Test { type RuntimeFreezeReason = RuntimeFreezeReason; type FreezeIdentifier = (); type MaxFreezes = ConstU32<0>; + type DoneSlashHandler = (); } parameter_types! { diff --git a/polkadot/xcm/xcm-builder/src/universal_exports.rs b/polkadot/xcm/xcm-builder/src/universal_exports.rs index 8aa9602fcc29..5c754f01ec0a 100644 --- a/polkadot/xcm/xcm-builder/src/universal_exports.rs +++ b/polkadot/xcm/xcm-builder/src/universal_exports.rs @@ -337,11 +337,15 @@ impl InspectMessageQueues +impl InspectMessageQueues for SovereignPaidRemoteExporter { + fn clear_messages() {} + + /// This router needs to implement `InspectMessageQueues` but doesn't have to + /// return any messages, since it just reuses the `XcmpQueue` router. fn get_messages() -> Vec<(VersionedLocation, Vec>)> { - Router::get_messages() + Vec::new() } } diff --git a/polkadot/xcm/xcm-builder/tests/scenarios.rs b/polkadot/xcm/xcm-builder/tests/scenarios.rs index ee1aeffbb4e7..99c14f5bba1b 100644 --- a/polkadot/xcm/xcm-builder/tests/scenarios.rs +++ b/polkadot/xcm/xcm-builder/tests/scenarios.rs @@ -22,7 +22,7 @@ use mock::{ }; use polkadot_parachain_primitives::primitives::Id as ParaId; use sp_runtime::traits::AccountIdConversion; -use xcm::latest::prelude::*; +use xcm::latest::{prelude::*, Error::UntrustedTeleportLocation}; use xcm_executor::XcmExecutor; pub const ALICE: AccountId = AccountId::new([0u8; 32]); @@ -217,7 +217,7 @@ fn teleport_to_asset_hub_works() { ]; let weight = BaseXcmWeight::get() * 3; - // teleports are allowed to community chains, even in the absence of trust from their side. + // teleports are not allowed to other chains, in the absence of trust from their side let message = Xcm(vec![ WithdrawAsset((Here, amount).into()), buy_execution(), @@ -235,16 +235,7 @@ fn teleport_to_asset_hub_works() { weight, Weight::zero(), ); - assert_eq!(r, Outcome::Complete { used: weight }); - let expected_msg = Xcm(vec![ReceiveTeleportedAsset((Parent, amount).into()), ClearOrigin] - .into_iter() - .chain(teleport_effects.clone().into_iter()) - .collect()); - let expected_hash = fake_message_hash(&expected_msg); - assert_eq!( - mock::sent_xcm(), - vec![(Parachain(other_para_id).into(), expected_msg, expected_hash,)] - ); + assert_eq!(r, Outcome::Incomplete { used: weight, error: UntrustedTeleportLocation }); // teleports are allowed from asset hub to kusama. let message = Xcm(vec![ @@ -274,10 +265,7 @@ fn teleport_to_asset_hub_works() { let expected_hash = fake_message_hash(&expected_msg); assert_eq!( mock::sent_xcm(), - vec![ - (Parachain(other_para_id).into(), expected_msg.clone(), expected_hash,), - (Parachain(asset_hub_id).into(), expected_msg, expected_hash,) - ] + vec![(Parachain(asset_hub_id).into(), expected_msg, expected_hash,)] ); }); } diff --git a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml index e669e5d2b231..7e6bfe967b90 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml +++ b/polkadot/xcm/xcm-executor/integration-tests/Cargo.toml @@ -13,14 +13,12 @@ workspace = true [dependencies] codec = { workspace = true, default-features = true } frame-support = { workspace = true } -frame-system = { workspace = true, default-features = true } futures = { workspace = true } pallet-transaction-payment = { workspace = true, default-features = true } pallet-xcm = { workspace = true, default-features = true } polkadot-test-client = { workspace = true } polkadot-test-runtime = { workspace = true } polkadot-test-service = { workspace = true } -polkadot-service = { workspace = true, default-features = true } sp-consensus = { workspace = true, default-features = true } sp-keyring = { workspace = true, default-features = true } sp-runtime = { workspace = true } diff --git a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs index 279d7118f8cf..e95473c5407e 100644 --- a/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs +++ b/polkadot/xcm/xcm-executor/integration-tests/src/lib.rs @@ -18,14 +18,12 @@ use codec::Encode; use frame_support::{dispatch::GetDispatchInfo, weights::Weight}; -use polkadot_service::chain_spec::get_account_id_from_seed; use polkadot_test_client::{ BlockBuilderExt, ClientBlockImportExt, DefaultTestClientBuilderExt, InitPolkadotBlockBuilder, TestClientBuilder, TestClientBuilderExt, }; use polkadot_test_runtime::{pallet_test_notifier, xcm_config::XcmConfig}; use polkadot_test_service::construct_extrinsic; -use sp_core::sr25519; use sp_runtime::traits::Block; use sp_state_machine::InspectState; use xcm::{latest::prelude::*, VersionedResponse, VersionedXcm}; @@ -34,7 +32,7 @@ use xcm_executor::traits::WeightBounds; #[test] fn basic_buy_fees_message_executes() { sp_tracing::try_init_simple(); - let mut client = TestClientBuilder::new().build(); + let client = TestClientBuilder::new().build(); let msg = Xcm(vec![ WithdrawAsset((Parent, 100).into()), @@ -75,7 +73,7 @@ fn basic_buy_fees_message_executes() { #[test] fn transact_recursion_limit_works() { sp_tracing::try_init_simple(); - let mut client = TestClientBuilder::new().build(); + let client = TestClientBuilder::new().build(); let base_xcm = |call: polkadot_test_runtime::RuntimeCall| { Xcm(vec![ @@ -83,7 +81,7 @@ fn transact_recursion_limit_works() { BuyExecution { fees: (Here, 1).into(), weight_limit: Unlimited }, Transact { origin_kind: OriginKind::Native, - require_weight_at_most: call.get_dispatch_info().weight, + require_weight_at_most: call.get_dispatch_info().call_weight, call: call.encode().into(), }, ]) @@ -174,7 +172,7 @@ fn query_response_fires() { use polkadot_test_runtime::RuntimeEvent::TestNotifier; sp_tracing::try_init_simple(); - let mut client = TestClientBuilder::new().build(); + let client = TestClientBuilder::new().build(); let mut block_builder = client.init_polkadot_block_builder(); @@ -256,7 +254,7 @@ fn query_response_elicits_handler() { use polkadot_test_runtime::RuntimeEvent::TestNotifier; sp_tracing::try_init_simple(); - let mut client = TestClientBuilder::new().build(); + let client = TestClientBuilder::new().build(); let mut block_builder = client.init_polkadot_block_builder(); @@ -332,7 +330,7 @@ fn query_response_elicits_handler() { #[test] fn deposit_reserve_asset_works_for_any_xcm_sender() { sp_tracing::try_init_simple(); - let mut client = TestClientBuilder::new().build(); + let client = TestClientBuilder::new().build(); // Init values for the simulated origin Parachain let amount_to_send: u128 = 1_000_000_000_000; @@ -343,7 +341,7 @@ fn deposit_reserve_asset_works_for_any_xcm_sender() { let weight_limit = Unlimited; let reserve = Location::parent(); let dest = Location::new(1, [Parachain(2000)]); - let beneficiary_id = get_account_id_from_seed::("Alice"); + let beneficiary_id = sp_keyring::Sr25519Keyring::Alice.to_account_id(); let beneficiary = Location::new(0, [AccountId32 { network: None, id: beneficiary_id.into() }]); // spends up to half of fees for execution on reserve and other half for execution on diff --git a/polkadot/xcm/xcm-executor/src/config.rs b/polkadot/xcm/xcm-executor/src/config.rs index 63b113bc250f..5bcbbd3466e8 100644 --- a/polkadot/xcm/xcm-executor/src/config.rs +++ b/polkadot/xcm/xcm-executor/src/config.rs @@ -33,6 +33,10 @@ pub trait Config { type RuntimeCall: Parameter + Dispatchable + GetDispatchInfo; /// How to send an onward XCM message. + /// + /// The sender is tasked with returning the assets it needs to pay for delivery fees. + /// Only one asset should be returned as delivery fees, any other will be ignored by + /// the executor. type XcmSender: SendXcm; /// How to withdraw and deposit an asset. @@ -74,6 +78,9 @@ pub trait Config { type AssetLocker: AssetLock; /// Handler for exchanging assets. + /// + /// This is used in the executor to swap the asset wanted for fees with the asset needed for + /// delivery fees. type AssetExchanger: AssetExchange; /// The handler for when there is an instruction to claim assets. diff --git a/polkadot/xcm/xcm-executor/src/lib.rs b/polkadot/xcm/xcm-executor/src/lib.rs index 1daf5ae750cf..e3addfa3e794 100644 --- a/polkadot/xcm/xcm-executor/src/lib.rs +++ b/polkadot/xcm/xcm-executor/src/lib.rs @@ -83,6 +83,9 @@ pub struct XcmExecutor { appendix_weight: Weight, transact_status: MaybeErrorCode, fees_mode: FeesMode, + /// Asset provided in last `BuyExecution` instruction (if any) in current XCM program. Same + /// asset type will be used for paying any potential delivery fees incurred by the program. + asset_used_for_fees: Option, _config: PhantomData, } @@ -269,7 +272,7 @@ impl ExecuteXcm for XcmExecutor XcmExecutor { appendix_weight: Weight::zero(), transact_status: Default::default(), fees_mode: FeesMode { jit_withdraw: false }, + asset_used_for_fees: None, _config: PhantomData, } } @@ -469,31 +473,114 @@ impl XcmExecutor { Ok(()) } - fn take_fee(&mut self, fee: Assets, reason: FeeReason) -> XcmResult { + fn take_fee(&mut self, fees: Assets, reason: FeeReason) -> XcmResult { if Config::FeeManager::is_waived(self.origin_ref(), reason.clone()) { return Ok(()) } tracing::trace!( target: "xcm::fees", - ?fee, + ?fees, origin_ref = ?self.origin_ref(), fees_mode = ?self.fees_mode, ?reason, "Taking fees", ); - let paid = if self.fees_mode.jit_withdraw { + // We only ever use the first asset from `fees`. + let asset_needed_for_fees = match fees.get(0) { + Some(fee) => fee, + None => return Ok(()), // No delivery fees need to be paid. + }; + // If `BuyExecution` was called, we use that asset for delivery fees as well. + let asset_to_pay_for_fees = + self.calculate_asset_for_delivery_fees(asset_needed_for_fees.clone()); + tracing::trace!(target: "xcm::fees", ?asset_to_pay_for_fees); + // We withdraw or take from holding the asset the user wants to use for fee payment. + let withdrawn_fee_asset: AssetsInHolding = if self.fees_mode.jit_withdraw { let origin = self.origin_ref().ok_or(XcmError::BadOrigin)?; - for asset in fee.inner() { - Config::AssetTransactor::withdraw_asset(&asset, origin, Some(&self.context))?; - } - fee + Config::AssetTransactor::withdraw_asset( + &asset_to_pay_for_fees, + origin, + Some(&self.context), + )?; + tracing::trace!(target: "xcm::fees", ?asset_needed_for_fees); + asset_to_pay_for_fees.clone().into() } else { - self.holding.try_take(fee.into()).map_err(|_| XcmError::NotHoldingFees)?.into() + let assets_taken_from_holding_to_pay_delivery_fees = self + .holding + .try_take(asset_to_pay_for_fees.clone().into()) + .map_err(|e| { + tracing::error!(target: "xcm::fees", ?e, ?asset_to_pay_for_fees, "Failed to take asset_to_pay_for_fees from holding"); + XcmError::NotHoldingFees + })?; + tracing::trace!(target: "xcm::fees", ?assets_taken_from_holding_to_pay_delivery_fees); + let mut iter = assets_taken_from_holding_to_pay_delivery_fees.fungible_assets_iter(); + let asset = iter.next().ok_or(XcmError::NotHoldingFees)?; + asset.into() + }; + // We perform the swap, if needed, to pay fees. + let paid = if asset_to_pay_for_fees.id != asset_needed_for_fees.id { + let swapped_asset: Assets = Config::AssetExchanger::exchange_asset( + self.origin_ref(), + withdrawn_fee_asset.clone().into(), + &asset_needed_for_fees.clone().into(), + false, + ) + .map_err(|given_assets| { + tracing::error!( + target: "xcm::fees", + ?given_assets, "Swap was deemed necessary but couldn't be done for withdrawn_fee_asset: {:?} and asset_needed_for_fees: {:?}", withdrawn_fee_asset.clone(), asset_needed_for_fees, + ); + XcmError::FeesNotMet + })? + .into(); + swapped_asset + } else { + // If the asset wanted to pay for fees is the one that was needed, + // we don't need to do any swap. + // We just use the assets withdrawn or taken from holding. + withdrawn_fee_asset.into() }; Config::FeeManager::handle_fee(paid, Some(&self.context), reason); Ok(()) } + /// Calculates the amount of `self.asset_used_for_fees` required to swap for + /// `asset_needed_for_fees`. + /// + /// The calculation is done by `Config::AssetExchanger`. + /// If `self.asset_used_for_fees` is not set, it will just return `asset_needed_for_fees`. + fn calculate_asset_for_delivery_fees(&self, asset_needed_for_fees: Asset) -> Asset { + if let Some(asset_wanted_for_fees) = &self.asset_used_for_fees { + if *asset_wanted_for_fees != asset_needed_for_fees.id { + match Config::AssetExchanger::quote_exchange_price( + &(asset_wanted_for_fees.clone(), Fungible(0)).into(), + &asset_needed_for_fees.clone().into(), + false, // Minimal. + ) { + Some(necessary_assets) => + // We only use the first asset for fees. + // If this is not enough to swap for the fee asset then it will error later down + // the line. + necessary_assets.get(0).unwrap_or(&asset_needed_for_fees.clone()).clone(), + // If we can't convert, then we return the original asset. + // It will error later in any case. + None => { + tracing::trace!( + target: "xcm::calculate_asset_for_delivery_fees", + ?asset_wanted_for_fees, + "Could not convert fees", + ); + asset_needed_for_fees.clone() + }, + } + } else { + asset_needed_for_fees + } + } else { + asset_needed_for_fees + } + } + /// Calculates what `local_querier` would be from the perspective of `destination`. fn to_querier( local_querier: Option, @@ -502,8 +589,10 @@ impl XcmExecutor { Ok(match local_querier { None => None, Some(q) => Some( - q.reanchored(&destination, &Config::UniversalLocation::get()) - .map_err(|_| XcmError::ReanchorFailed)?, + q.reanchored(&destination, &Config::UniversalLocation::get()).map_err(|e| { + tracing::error!(target: "xcm::xcm_executor::to_querier", ?e, ?destination, "Failed to re-anchor local_querier"); + XcmError::ReanchorFailed + })?, ), }) } @@ -532,7 +621,7 @@ impl XcmExecutor { let reanchor_context = Config::UniversalLocation::get(); let reanchored = reanchorable.reanchored(&destination, &reanchor_context).map_err(|error| { - tracing::error!(target: "xcm::reanchor", ?error, "Failed reanchoring with error"); + tracing::error!(target: "xcm::reanchor", ?error, ?destination, ?reanchor_context, "Failed reanchoring with error."); XcmError::ReanchorFailed })?; Ok((reanchored, reanchor_context)) @@ -772,7 +861,7 @@ impl XcmExecutor { "Dispatching with origin", ); - let weight = message_call.get_dispatch_info().weight; + let weight = message_call.get_dispatch_info().call_weight; if !weight.all_lte(require_weight_at_most) { tracing::trace!( @@ -809,7 +898,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. // @@ -838,7 +927,10 @@ impl XcmExecutor { .as_mut() .ok_or(XcmError::BadOrigin)? .append_with(who) - .map_err(|_| XcmError::LocationFull), + .map_err(|e| { + tracing::error!(target: "xcm::process_instruction::descend_origin", ?e, "Failed to append junctions"); + XcmError::LocationFull + }), ClearOrigin => { self.context.origin = None; Ok(()) @@ -858,14 +950,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; @@ -885,22 +970,34 @@ impl XcmExecutor { message_to_weigh.extend(xcm.0.clone().into_iter()); let (_, fee) = validate_send::(dest.clone(), Xcm(message_to_weigh))?; - // set aside fee to be charged by XcmSender - let transport_fee = self.holding.saturating_take(fee.into()); - - // now take assets to deposit (excluding transport_fee) + let maybe_delivery_fee = fee.get(0).map(|asset_needed_for_fees| { + tracing::trace!( + target: "xcm::DepositReserveAsset", + "Asset provided to pay for fees {:?}, asset required for delivery fees: {:?}", + self.asset_used_for_fees, asset_needed_for_fees, + ); + let asset_to_pay_for_fees = + self.calculate_asset_for_delivery_fees(asset_needed_for_fees.clone()); + // set aside fee to be charged by XcmSender + let delivery_fee = + self.holding.saturating_take(asset_to_pay_for_fees.into()); + tracing::trace!(target: "xcm::DepositReserveAsset", ?delivery_fee); + delivery_fee + }); + // now take assets to deposit (after having taken delivery fees) let deposited = self.holding.saturating_take(assets); - for asset in deposited.assets_iter() { - Config::AssetTransactor::deposit_asset(&asset, &dest, Some(&self.context))?; - } + tracing::trace!(target: "xcm::DepositReserveAsset", ?deposited, "Assets except delivery fee"); + 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. let assets = Self::reanchored(deposited, &dest, None); let mut message = vec![ReserveAssetDeposited(assets), ClearOrigin]; message.extend(xcm.0.into_iter()); - // put back transport_fee in holding register to be charged by XcmSender - self.holding.subsume_assets(transport_fee); + // put back delivery_fee in holding register to be charged by XcmSender + if let Some(delivery_fee) = maybe_delivery_fee { + self.holding.subsume_assets(delivery_fee); + } self.send(dest, Xcm(message), FeeReason::DepositReserveAsset)?; Ok(()) }); @@ -912,13 +1009,18 @@ impl XcmExecutor { InitiateReserveWithdraw { assets, reserve, xcm } => { let old_holding = self.holding.clone(); let result = Config::TransactionalProcessor::process(|| { + let assets = self.holding.saturating_take(assets); + // Must ensure that we recognise the assets as being managed by the destination. + #[cfg(not(feature = "runtime-benchmarks"))] + for asset in assets.assets_iter() { + ensure!( + Config::IsReserve::contains(&asset, &reserve), + XcmError::UntrustedReserveLocation + ); + } // Note that here we are able to place any assets which could not be reanchored // back into Holding. - let assets = Self::reanchored( - self.holding.saturating_take(assets), - &reserve, - Some(&mut self.holding), - ); + let assets = Self::reanchored(assets, &reserve, Some(&mut self.holding)); let mut message = vec![WithdrawAsset(assets), ClearOrigin]; message.extend(xcm.0.into_iter()); self.send(reserve, Xcm(message), FeeReason::InitiateReserveWithdraw)?; @@ -934,6 +1036,14 @@ impl XcmExecutor { let result = (|| -> Result<(), XcmError> { // We must do this first in order to resolve wildcards. let assets = self.holding.saturating_take(assets); + // Must ensure that we have teleport trust with destination for these assets. + #[cfg(not(feature = "runtime-benchmarks"))] + for asset in assets.assets_iter() { + ensure!( + Config::IsTeleporter::contains(&asset, &dest), + XcmError::UntrustedTeleportLocation + ); + } for asset in assets.assets_iter() { // We should check that the asset can actually be teleported out (for this // to be in error, there would need to be an accounting violation by @@ -978,9 +1088,16 @@ impl XcmExecutor { // should be executed. let Some(weight) = Option::::from(weight_limit) else { return Ok(()) }; let old_holding = self.holding.clone(); + // Save the asset being used for execution fees, so we later know what should be + // used for delivery fees. + self.asset_used_for_fees = Some(fees.id.clone()); + tracing::trace!(target: "xcm::executor::BuyExecution", asset_used_for_fees = ?self.asset_used_for_fees); // pay for `weight` using up to `fees` of the holding register. let max_fee = - self.holding.try_take(fees.into()).map_err(|_| XcmError::NotHoldingFees)?; + self.holding.try_take(fees.clone().into()).map_err(|e| { + tracing::error!(target: "xcm::process_instruction::buy_execution", ?e, ?fees, "Failed to take fees from holding"); + XcmError::NotHoldingFees + })?; let result = || -> Result<(), XcmError> { let unspent = self.trader.buy_weight(weight, max_fee, &self.context)?; self.holding.subsume_assets(unspent); @@ -1043,7 +1160,10 @@ impl XcmExecutor { Ok(()) }, ExpectAsset(assets) => - self.holding.ensure_contains(&assets).map_err(|_| XcmError::ExpectationFalse), + self.holding.ensure_contains(&assets).map_err(|e| { + tracing::error!(target: "xcm::process_instruction::expect_asset", ?e, ?assets, "assets not contained in holding"); + XcmError::ExpectationFalse + }), ExpectOrigin(origin) => { ensure!(self.context.origin == origin, XcmError::ExpectationFalse); Ok(()) @@ -1165,9 +1285,10 @@ impl XcmExecutor { let (remote_asset, context) = Self::try_reanchor(asset.clone(), &unlocker)?; let lock_ticket = Config::AssetLocker::prepare_lock(unlocker.clone(), asset, origin.clone())?; - let owner = origin - .reanchored(&unlocker, &context) - .map_err(|_| XcmError::ReanchorFailed)?; + let owner = origin.reanchored(&unlocker, &context).map_err(|e| { + tracing::error!(target: "xcm::xcm_executor::process_instruction", ?e, ?unlocker, ?context, "Failed to re-anchor origin"); + XcmError::ReanchorFailed + })?; let msg = Xcm::<()>(vec![NoteUnlockable { asset: remote_asset, owner }]); let (ticket, price) = validate_send::(unlocker, msg)?; self.take_fee(price, FeeReason::LockAsset)?; @@ -1282,4 +1403,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 432a7498ed4c..f4b7135d4206 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-executor/src/traits/export.rs b/polkadot/xcm/xcm-executor/src/traits/export.rs index 78aa68ce2644..b356e0da7df7 100644 --- a/polkadot/xcm/xcm-executor/src/traits/export.rs +++ b/polkadot/xcm/xcm-executor/src/traits/export.rs @@ -20,7 +20,7 @@ use xcm::latest::prelude::*; /// spoofed origin. This essentially defines the behaviour of the `ExportMessage` XCM instruction. /// /// This is quite different to `SendXcm`; `SendXcm` assumes that the local side's location will be -/// preserved to be represented as the value of the Origin register in the messages execution. +/// preserved to be represented as the value of the Origin register during the message's execution. /// /// This trait on the other hand assumes that we do not necessarily want the Origin register to /// contain the local (i.e. the caller chain's) location, since it will generally be exporting a @@ -44,8 +44,8 @@ pub trait ExportXcm { /// The `destination` and `message` must be `Some` (or else an error will be returned) and they /// may only be consumed if the `Err` is not `NotApplicable`. /// - /// If it is not a destination which can be reached with this type but possibly could by others, - /// then this *MUST* return `NotApplicable`. Any other error will cause the tuple + /// If it is not a destination that can be reached with this type, but possibly could be with + /// others, then this *MUST* return `NotApplicable`. Any other error will cause the tuple /// implementation (used to compose routing systems from different delivery agents) to exit /// early without trying alternative means of delivery. fn validate( diff --git a/polkadot/xcm/xcm-executor/src/traits/weight.rs b/polkadot/xcm/xcm-executor/src/traits/weight.rs index 72de3e0f433b..61545c330621 100644 --- a/polkadot/xcm/xcm-executor/src/traits/weight.rs +++ b/polkadot/xcm/xcm-executor/src/traits/weight.rs @@ -29,13 +29,6 @@ pub trait WeightBounds { fn instr_weight(instruction: &Instruction) -> Result; } -/// A means of getting approximate weight consumption for a given destination message executor and a -/// message. -pub trait UniversalWeigher { - /// Get the upper limit of weight required for `dest` to execute `message`. - fn weigh(dest: impl Into, message: Xcm<()>) -> Result; -} - /// Charge for weight in order to execute XCM. /// /// A `WeightTrader` may also be put into a tuple, in which case the default behavior of diff --git a/polkadot/xcm/xcm-runtime-apis/Cargo.toml b/polkadot/xcm/xcm-runtime-apis/Cargo.toml index 748d5af68a1f..9ccca76c321c 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/src/conversions.rs b/polkadot/xcm/xcm-runtime-apis/src/conversions.rs index e5eeac013fee..22f0809ea5f9 100644 --- a/polkadot/xcm/xcm-runtime-apis/src/conversions.rs +++ b/polkadot/xcm/xcm-runtime-apis/src/conversions.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/polkadot/xcm/xcm-runtime-apis/src/dry_run.rs b/polkadot/xcm/xcm-runtime-apis/src/dry_run.rs index 2a1a0daf0d5d..f0a70b0dacfe 100644 --- a/polkadot/xcm/xcm-runtime-apis/src/dry_run.rs +++ b/polkadot/xcm/xcm-runtime-apis/src/dry_run.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. @@ -57,7 +57,12 @@ sp_api::decl_runtime_apis! { /// Calls or XCMs might fail when executed, this doesn't mean the result of these calls will be an `Err`. /// In those cases, there might still be a valid result, with the execution error inside it. /// The only reasons why these calls might return an error are listed in the [`Error`] enum. - pub trait DryRunApi { + pub trait DryRunApi + where + Call: Encode, + Event: Decode, + OriginCaller: Encode + { /// Dry run call. fn dry_run_call(origin: OriginCaller, call: Call) -> Result, Error>; diff --git a/polkadot/xcm/xcm-runtime-apis/src/fees.rs b/polkadot/xcm/xcm-runtime-apis/src/fees.rs index 3445d42ecab3..9500a7f7281f 100644 --- a/polkadot/xcm/xcm-runtime-apis/src/fees.rs +++ b/polkadot/xcm/xcm-runtime-apis/src/fees.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/polkadot/xcm/xcm-runtime-apis/src/lib.rs b/polkadot/xcm/xcm-runtime-apis/src/lib.rs index b106836c1132..f9a857c7c4ce 100644 --- a/polkadot/xcm/xcm-runtime-apis/src/lib.rs +++ b/polkadot/xcm/xcm-runtime-apis/src/lib.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. @@ -30,3 +30,7 @@ pub mod dry_run; /// Fee estimation API. /// Given an XCM program, it will return the fees needed to execute it properly or send it. pub mod fees; + +// Exposes runtime API for querying whether a Location is trusted as a reserve or teleporter for a +// given Asset. +pub mod trusted_query; diff --git a/polkadot/xcm/xcm-runtime-apis/src/trusted_query.rs b/polkadot/xcm/xcm-runtime-apis/src/trusted_query.rs new file mode 100644 index 000000000000..a2e3e1625486 --- /dev/null +++ b/polkadot/xcm/xcm-runtime-apis/src/trusted_query.rs @@ -0,0 +1,50 @@ +// 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 . + +//! Runtime API definition for checking if given is trusted reserve or teleporter. + +use codec::{Decode, Encode}; +use frame_support::pallet_prelude::TypeInfo; +use xcm::{VersionedAsset, VersionedLocation}; + +/// Result of [`TrustedQueryApi`] functions. +pub type XcmTrustedQueryResult = Result; + +sp_api::decl_runtime_apis! { + // API for querying trusted reserves and trusted teleporters. + pub trait TrustedQueryApi { + /// Returns if the location is a trusted reserve for the asset. + /// + /// # Arguments + /// * `asset`: `VersionedAsset`. + /// * `location`: `VersionedLocation`. + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> XcmTrustedQueryResult; + /// Returns if the asset can be teleported to the location. + /// + /// # Arguments + /// * `asset`: `VersionedAsset`. + /// * `location`: `VersionedLocation`. + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> XcmTrustedQueryResult; + } +} + +#[derive(Copy, Clone, Encode, Decode, Eq, PartialEq, Debug, TypeInfo)] +pub enum Error { + /// Converting a versioned Asset structure from one version to another failed. + VersionedAssetConversionFailed, + /// Converting a versioned Location structure from one version to another failed. + VersionedLocationConversionFailed, +} diff --git a/polkadot/xcm/xcm-runtime-apis/tests/conversions.rs b/polkadot/xcm/xcm-runtime-apis/tests/conversions.rs index 7f0f0923b092..c7a1dda0169c 100644 --- a/polkadot/xcm/xcm-runtime-apis/tests/conversions.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/conversions.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. diff --git a/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs b/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs index 59ee17973805..2d14b4e571c6 100644 --- a/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/fee_estimation.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. @@ -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,9 +195,9 @@ 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. + // Native token used for fees. let balances = vec![(who, DeliveryFees::get() + ExistentialDeposit::get())]; // Relay token is the one we want to transfer. let assets = vec![(1, who, 100)]; // id, account_id, balance. @@ -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/xcm/xcm-runtime-apis/tests/mock.rs b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs index c76b26fcd2a3..b3afa23503e3 100644 --- a/polkadot/xcm/xcm-runtime-apis/tests/mock.rs +++ b/polkadot/xcm/xcm-runtime-apis/tests/mock.rs @@ -1,12 +1,12 @@ // Copyright (C) Parity Technologies (UK) Ltd. // This file is part of Polkadot. -// Substrate is free software: you can redistribute it and/or modify +// 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. -// Substrate is distributed in the hope that it will be useful, +// 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. @@ -48,6 +48,7 @@ use xcm_runtime_apis::{ conversions::{Error as LocationToAccountApiError, LocationToAccountApi}, dry_run::{CallDryRunEffects, DryRunApi, Error as XcmDryRunApiError, XcmDryRunEffects}, fees::{Error as XcmPaymentApiError, XcmPaymentApi}, + trusted_query::{Error as TrustedQueryApiError, TrustedQueryApi}, }; construct_runtime! { @@ -59,9 +60,16 @@ construct_runtime! { } } -pub type SignedExtra = (frame_system::CheckWeight,); -pub type TestXt = sp_runtime::testing::TestXt; -type Block = sp_runtime::testing::Block; +pub type TxExtension = (frame_system::CheckWeight,); + +// we only use the hash type from this, so using the mock should be fine. +pub(crate) type Extrinsic = sp_runtime::generic::UncheckedExtrinsic< + u64, + RuntimeCall, + sp_runtime::testing::UintAuthorityId, + TxExtension, +>; +type Block = sp_runtime::testing::Block; type Balance = u128; type AssetIdForAssetsPallet = u32; type AccountId = u64; @@ -414,6 +422,16 @@ impl sp_api::ProvideRuntimeApi for TestClient { } sp_api::mock_impl_runtime_apis! { + impl TrustedQueryApi for RuntimeApi { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> Result { + XcmPallet::is_trusted_reserve(asset, location) + } + + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> Result { + XcmPallet::is_trusted_teleporter(asset, location) + } + } + impl LocationToAccountApi for RuntimeApi { fn convert_location(location: VersionedLocation) -> Result { let location = location.try_into().map_err(|_| LocationToAccountApiError::VersionedConversionFailed)?; diff --git a/polkadot/xcm/xcm-runtime-apis/tests/trusted_query.rs b/polkadot/xcm/xcm-runtime-apis/tests/trusted_query.rs new file mode 100644 index 000000000000..5e3a68b9225b --- /dev/null +++ b/polkadot/xcm/xcm-runtime-apis/tests/trusted_query.rs @@ -0,0 +1,150 @@ +// 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 . + +mod mock; + +use frame_support::sp_runtime::testing::H256; +use mock::*; +use sp_api::ProvideRuntimeApi; +use xcm::{prelude::*, v3}; +use xcm_runtime_apis::trusted_query::{Error, TrustedQueryApi}; + +#[test] +fn query_trusted_reserve() { + #[derive(Debug)] + struct TestCase { + name: &'static str, + asset: VersionedAsset, + location: VersionedLocation, + expected: Result, + } + + sp_io::TestExternalities::default().execute_with(|| { + let client = TestClient {}; + let runtime_api = client.runtime_api(); + + let test_cases: Vec = vec![ + TestCase { + // matches!(asset.id.0.unpack(), (1, [])) && matches!(origin.unpack(), (1, + // [Parachain(1000)])) + name: "Valid asset and location", + asset: Asset { id: AssetId(Location::parent()), fun: Fungible(123) }.into(), + location: (Parent, Parachain(1000)).into(), + expected: Ok(true), + }, + TestCase { + name: "Invalid location and valid asset", + asset: Asset { id: AssetId(Location::parent()), fun: Fungible(100) }.into(), + location: (Parent, Parachain(1002)).into(), + expected: Ok(false), + }, + TestCase { + name: "Valid location and invalid asset", + asset: Asset { id: AssetId(Location::new(0, [])), fun: Fungible(100) }.into(), + location: (Parent, Parachain(1000)).into(), + expected: Ok(false), + }, + TestCase { + name: "Invalid asset conversion", + asset: VersionedAsset::V3(v3::MultiAsset { + id: v3::AssetId::Abstract([1; 32]), + fun: v3::Fungibility::Fungible(1), + }), + location: (Parent, Parachain(1000)).into(), + expected: Err(Error::VersionedAssetConversionFailed), + }, + ]; + + for tc in test_cases { + let res = + runtime_api.is_trusted_reserve(H256::zero(), tc.asset.clone(), tc.location.clone()); + let inner_res = res.unwrap_or_else(|e| { + panic!("Test case '{}' failed with ApiError: {:?}", tc.name, e); + }); + + assert_eq!( + tc.expected, inner_res, + "Test case '{}' failed: expected {:?}, got {:?}", + tc.name, tc.expected, inner_res + ); + } + }); +} + +#[test] +fn query_trusted_teleporter() { + #[derive(Debug)] + struct TestCase { + name: &'static str, + asset: VersionedAsset, + location: VersionedLocation, + expected: Result, + } + + sp_io::TestExternalities::default().execute_with(|| { + let client = TestClient {}; + let runtime_api = client.runtime_api(); + + let test_cases: Vec = vec![ + TestCase { + // matches!(asset.id.0.unpack(), (0, [])) && matches!(origin.unpack(), (1, + // [Parachain(1000)])) + name: "Valid asset and location", + asset: Asset { id: AssetId(Location::new(0, [])), fun: Fungible(100) }.into(), + location: (Parent, Parachain(1000)).into(), + expected: Ok(true), + }, + TestCase { + name: "Invalid location and valid asset", + asset: Asset { id: AssetId(Location::new(0, [])), fun: Fungible(100) }.into(), + location: (Parent, Parachain(1002)).into(), + expected: Ok(false), + }, + TestCase { + name: "Valid location and invalid asset", + asset: Asset { id: AssetId(Location::new(1, [])), fun: Fungible(100) }.into(), + location: (Parent, Parachain(1002)).into(), + expected: Ok(false), + }, + TestCase { + name: "Invalid asset conversion", + asset: VersionedAsset::V3(v3::MultiAsset { + id: v3::AssetId::Abstract([1; 32]), + fun: v3::Fungibility::Fungible(1), + }), + location: (Parent, Parachain(1000)).into(), + expected: Err(Error::VersionedAssetConversionFailed), + }, + ]; + + for tc in test_cases { + let res = runtime_api.is_trusted_teleporter( + H256::zero(), + tc.asset.clone(), + tc.location.clone(), + ); + let inner_res = res.unwrap_or_else(|e| { + panic!("Test case '{}' failed with ApiError: {:?}", tc.name, e); + }); + + assert_eq!( + tc.expected, inner_res, + "Test case '{}' failed: expected {:?}, got {:?}", + tc.name, tc.expected, inner_res + ); + } + }); +} diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/mod.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/mod.rs index c5d5fa66732b..6218915cd12d 100644 --- a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/mod.rs +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/mod.rs @@ -19,6 +19,7 @@ pub mod barrier; pub mod constants; pub mod location_converter; pub mod origin_converter; +pub mod teleporter; pub mod weigher; use crate::relay_chain::{RuntimeCall, XcmPallet}; @@ -36,7 +37,7 @@ impl Config for XcmConfig { type AssetTransactor = asset_transactor::AssetTransactor; type OriginConverter = origin_converter::OriginConverter; type IsReserve = (); - type IsTeleporter = (); + type IsTeleporter = teleporter::TrustedTeleporters; type UniversalLocation = constants::UniversalLocation; type Barrier = barrier::Barrier; type Weigher = weigher::Weigher; diff --git a/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/teleporter.rs b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/teleporter.rs new file mode 100644 index 000000000000..92e5065044e6 --- /dev/null +++ b/polkadot/xcm/xcm-simulator/example/src/relay_chain/xcm_config/teleporter.rs @@ -0,0 +1,26 @@ +// 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 . + +use frame_support::parameter_types; +use xcm::latest::prelude::*; + +parameter_types! { + pub NftCollectionOnRelay: AssetFilter + = Wild(AllOf { fun: WildNonFungible, id: AssetId(GeneralIndex(1).into()) }); + pub NftCollectionForChild: (AssetFilter, Location) + = (NftCollectionOnRelay::get(), Parachain(1).into()); +} +pub type TrustedTeleporters = xcm_builder::Case; diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs index 616329a2f06b..fc650ae55a78 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/parachain.rs @@ -44,13 +44,13 @@ use xcm_builder::{ }; use xcm_executor::{Config, XcmExecutor}; -pub type SignedExtra = (frame_system::CheckNonZeroSender,); +pub type TxExtension = (frame_system::CheckNonZeroSender,); pub type BlockNumber = u64; pub type Address = MultiAddress; pub type Header = generic::Header; pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; pub type Block = generic::Block; pub type Signature = MultiSignature; diff --git a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs index 459d2640b6d9..58687b478526 100644 --- a/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs +++ b/polkadot/xcm/xcm-simulator/fuzzer/src/relay_chain.rs @@ -45,13 +45,13 @@ use xcm_builder::{ }; use xcm_executor::{Config, XcmExecutor}; -pub type SignedExtra = (frame_system::CheckNonZeroSender,); +pub type TxExtension = (frame_system::CheckNonZeroSender,); pub type BlockNumber = u64; pub type Address = MultiAddress; pub type Header = generic::Header; pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + generic::UncheckedExtrinsic; pub type Block = generic::Block; pub type Signature = MultiSignature; diff --git a/polkadot/zombienet-sdk-tests/Cargo.toml b/polkadot/zombienet-sdk-tests/Cargo.toml new file mode 100644 index 000000000000..4eac7af49f8a --- /dev/null +++ b/polkadot/zombienet-sdk-tests/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "polkadot-zombienet-sdk-tests" +version = "0.1.0" +description = "Zomebienet-sdk tests." +authors.workspace = true +edition.workspace = true +license.workspace = true +publish = false + +[dependencies] +env_logger = { workspace = true } +log = { workspace = true } +subxt = { workspace = true, features = ["substrate-compat"] } +subxt-signer = { workspace = true } +tokio = { workspace = true, features = ["rt-multi-thread"] } +anyhow = { workspace = true } +zombienet-sdk = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +codec = { workspace = true, features = ["derive"] } + +[features] +zombie-metadata = [] + +[build-dependencies] +substrate-build-script-utils = { workspace = true, default-features = true } +subwasmlib = { git = "https://github.com/chevdor/subwasm", rev = "v0.21.3" } diff --git a/polkadot/zombienet-sdk-tests/build.rs b/polkadot/zombienet-sdk-tests/build.rs new file mode 100644 index 000000000000..240d86386af2 --- /dev/null +++ b/polkadot/zombienet-sdk-tests/build.rs @@ -0,0 +1,151 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +use std::{ + env, fs, path, + path::{Path, PathBuf}, + process::Command, +}; + +use subwasmlib::{source::Source, OutputFormat, Subwasm}; + +macro_rules! debug_output { + ($($tokens: tt)*) => { + if env::var("ZOMBIE_METADATA_BUILD_DEBUG").is_ok() { + println!("cargo:warning={}", format!($($tokens)*)) + } + } +} + +fn replace_dashes(k: &str) -> String { + k.replace('-', "_") +} + +fn make_env_key(k: &str) -> String { + replace_dashes(&k.to_ascii_uppercase()) +} + +fn find_wasm(chain: &str) -> Option { + const PROFILES: [&str; 2] = ["release", "testnet"]; + let manifest_path = env::var("CARGO_WORKSPACE_ROOT_DIR").unwrap(); + let manifest_path = manifest_path.strip_suffix('/').unwrap(); + debug_output!("manifest_path is : {}", manifest_path); + let package = format!("{chain}-runtime"); + let profile = PROFILES.into_iter().find(|p| { + let full_path = format!( + "{}/target/{}/wbuild/{}/{}.wasm", + manifest_path, + p, + &package, + replace_dashes(&package) + ); + debug_output!("checking wasm at : {}", full_path); + matches!(path::PathBuf::from(&full_path).try_exists(), Ok(true)) + }); + + debug_output!("profile is : {:?}", profile); + profile.map(|profile| { + PathBuf::from(&format!( + "{}/target/{}/wbuild/{}/{}.wasm", + manifest_path, + profile, + &package, + replace_dashes(&package) + )) + }) +} + +// based on https://gist.github.com/s0me0ne-unkn0wn/bbd83fe32ce10327086adbf13e750eec +fn build_wasm(chain: &str) -> PathBuf { + let package = format!("{chain}-runtime"); + + let cargo = env::var("CARGO").unwrap(); + let target = env::var("TARGET").unwrap(); + let out_dir = env::var("OUT_DIR").unwrap(); + let target_dir = format!("{}/runtimes", out_dir); + let args = vec![ + "build", + "-p", + &package, + "--profile", + "release", + "--target", + &target, + "--target-dir", + &target_dir, + ]; + debug_output!("building metadata with args: {}", args.join(" ")); + Command::new(cargo) + .env_remove("SKIP_WASM_BUILD") // force build to get the metadata + .args(&args) + .status() + .unwrap(); + + let wasm_path = &format!( + "{target_dir}/{target}/release/wbuild/{}/{}.wasm", + &package, + replace_dashes(&package) + ); + PathBuf::from(wasm_path) +} + +fn generate_metadata_file(wasm_path: &Path, output_path: &Path) { + let source = Source::from_options(Some(wasm_path.to_path_buf()), None, None, None).unwrap(); + let subwasm = Subwasm::new(&source.try_into().unwrap()).unwrap(); + let mut output_file = std::fs::File::create(output_path).unwrap(); + subwasm.write_metadata(OutputFormat::Scale, None, &mut output_file).unwrap(); +} + +fn fetch_metadata_file(chain: &str, output_path: &Path) { + // First check if we have an explicit path to use + let env_key = format!("{}_METADATA_FILE", make_env_key(chain)); + + if let Ok(path_to_use) = env::var(env_key) { + debug_output!("metadata file to use (from env): {}\n", path_to_use); + let metadata_file = PathBuf::from(&path_to_use); + fs::copy(metadata_file, output_path).unwrap(); + } else if let Some(exisiting_wasm) = find_wasm(chain) { + debug_output!("exisiting wasm: {:?}", exisiting_wasm); + // generate metadata + generate_metadata_file(&exisiting_wasm, output_path); + } else { + // build runtime + let wasm_path = build_wasm(chain); + debug_output!("created wasm: {:?}", wasm_path); + // genetate metadata + generate_metadata_file(&wasm_path, output_path); + } +} + +fn main() { + if env::var("CARGO_FEATURE_ZOMBIE_METADATA").is_err() { + debug_output!("zombie-metadata feature not enabled, not need to check metadata files."); + return; + } + + // Ensure we have the needed metadata files in place to run zombienet tests + let manifest_path = env::var("CARGO_MANIFEST_DIR").unwrap(); + const METADATA_DIR: &str = "metadata-files"; + const CHAINS: [&str; 2] = ["rococo", "coretime-rococo"]; + + let metadata_path = format!("{manifest_path}/{METADATA_DIR}"); + + for chain in CHAINS { + let full_path = format!("{metadata_path}/{chain}-local.scale"); + let output_path = path::PathBuf::from(&full_path); + + match output_path.try_exists() { + Ok(true) => { + debug_output!("got: {}", full_path); + }, + _ => { + debug_output!("needs: {}", full_path); + fetch_metadata_file(chain, &output_path); + }, + }; + } + + substrate_build_script_utils::generate_cargo_keys(); + substrate_build_script_utils::rerun_if_git_head_changed(); + println!("cargo:rerun-if-changed={}", metadata_path); +} diff --git a/polkadot/zombienet-sdk-tests/metadata-files/.gitkeep b/polkadot/zombienet-sdk-tests/metadata-files/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/polkadot/zombienet-sdk-tests/src/lib.rs b/polkadot/zombienet-sdk-tests/src/lib.rs new file mode 100644 index 000000000000..fe0aa995d77a --- /dev/null +++ b/polkadot/zombienet-sdk-tests/src/lib.rs @@ -0,0 +1,2 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 diff --git a/polkadot/zombienet-sdk-tests/tests/lib.rs b/polkadot/zombienet-sdk-tests/tests/lib.rs new file mode 100644 index 000000000000..74cdc0765600 --- /dev/null +++ b/polkadot/zombienet-sdk-tests/tests/lib.rs @@ -0,0 +1,4 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +mod smoke; diff --git a/polkadot/zombienet-sdk-tests/tests/smoke/coretime_revenue.rs b/polkadot/zombienet-sdk-tests/tests/smoke/coretime_revenue.rs new file mode 100644 index 000000000000..7880dc782d05 --- /dev/null +++ b/polkadot/zombienet-sdk-tests/tests/smoke/coretime_revenue.rs @@ -0,0 +1,505 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +//! Binaries for this test should be built with `fast-runtime` feature enabled: +//! `cargo build -r -F fast-runtime -p polkadot-parachain-bin && \` +//! `cargo build -r -F fast-runtime --bin polkadot --bin polkadot-execute-worker --bin +//! polkadot-prepare-worker` +//! +//! Running with normal runtimes is possible but would take ages. Running fast relay runtime with +//! normal parachain runtime WILL mess things up. + +use anyhow::anyhow; +#[subxt::subxt(runtime_metadata_path = "metadata-files/rococo-local.scale")] +pub mod rococo {} + +#[subxt::subxt(runtime_metadata_path = "metadata-files/coretime-rococo-local.scale")] +mod coretime_rococo {} + +use rococo::runtime_types::{ + staging_xcm::v4::{ + asset::{Asset, AssetId, Assets, Fungibility}, + junction::Junction, + junctions::Junctions, + location::Location, + }, + xcm::{VersionedAssets, VersionedLocation}, +}; +use serde_json::json; +use std::{fmt::Display, sync::Arc}; +use subxt::{events::StaticEvent, utils::AccountId32, OnlineClient, PolkadotConfig}; +use subxt_signer::sr25519::dev; +use tokio::sync::RwLock; +use zombienet_sdk::NetworkConfigBuilder; + +use coretime_rococo::{ + self as coretime_api, + broker::events as broker_events, + runtime_types::{ + pallet_broker::types::{ConfigRecord as BrokerConfigRecord, Finality as BrokerFinality}, + sp_arithmetic::per_things::Perbill, + }, +}; + +use rococo::{self as rococo_api, runtime_types::polkadot_parachain_primitives::primitives}; + +type CoretimeRuntimeCall = coretime_api::runtime_types::coretime_rococo_runtime::RuntimeCall; +type CoretimeUtilityCall = coretime_api::runtime_types::pallet_utility::pallet::Call; +type CoretimeBrokerCall = coretime_api::runtime_types::pallet_broker::pallet::Call; + +// On-demand coretime base fee (set at the genesis) +const ON_DEMAND_BASE_FEE: u128 = 50_000_000; + +async fn get_total_issuance( + relay: OnlineClient, + coretime: OnlineClient, +) -> (u128, u128) { + ( + relay + .storage() + .at_latest() + .await + .unwrap() + .fetch(&rococo_api::storage().balances().total_issuance()) + .await + .unwrap() + .unwrap(), + coretime + .storage() + .at_latest() + .await + .unwrap() + .fetch(&coretime_api::storage().balances().total_issuance()) + .await + .unwrap() + .unwrap(), + ) +} + +async fn assert_total_issuance( + relay: OnlineClient, + coretime: OnlineClient, + ti: (u128, u128), +) { + let actual_ti = get_total_issuance(relay, coretime).await; + log::debug!("Asserting total issuance: actual: {actual_ti:?}, expected: {ti:?}"); + assert_eq!(ti, actual_ti); +} + +type ParaEvents = Arc)>>>; + +macro_rules! trace_event { + ($event:ident : $mod:ident => $($ev:ident),*) => { + match $event.variant_name() { + $( + stringify!($ev) => + log::trace!("{:#?}", $event.as_event::<$mod::$ev>().unwrap().unwrap()), + )* + _ => () + } + }; +} + +async fn para_watcher(api: OnlineClient, events: ParaEvents) +where + ::Number: Display, +{ + let mut blocks_sub = api.blocks().subscribe_finalized().await.unwrap(); + + log::debug!("Starting parachain watcher"); + while let Some(block) = blocks_sub.next().await { + let block = block.unwrap(); + log::debug!("Finalized parachain block {}", block.number()); + + for event in block.events().await.unwrap().iter() { + let event = event.unwrap(); + log::debug!("Got event: {} :: {}", event.pallet_name(), event.variant_name()); + { + events.write().await.push((block.number().into(), event.clone())); + } + + if event.pallet_name() == "Broker" { + trace_event!(event: broker_events => + Purchased, SaleInitialized, HistoryInitialized, CoreAssigned, Pooled, + ClaimsReady, RevenueClaimBegun, RevenueClaimItem, RevenueClaimPaid + ); + } + } + } +} + +async fn wait_for_para_event bool + Copy>( + events: ParaEvents, + pallet: &'static str, + variant: &'static str, + predicate: P, +) -> E { + loop { + let mut events = events.write().await; + if let Some(entry) = events.iter().find(|&e| { + e.1.pallet_name() == pallet && + e.1.variant_name() == variant && + predicate(&e.1.as_event::().unwrap().unwrap()) + }) { + let entry = entry.clone(); + events.retain(|e| e.0 > entry.0); + return entry.1.as_event::().unwrap().unwrap(); + } + drop(events); + tokio::time::sleep(std::time::Duration::from_secs(6)).await; + } +} + +async fn ti_watcher(api: OnlineClient, prefix: &'static str) +where + ::Number: Display, +{ + let mut blocks_sub = api.blocks().subscribe_finalized().await.unwrap(); + + let mut issuance = 0i128; + + log::debug!("Starting parachain watcher"); + while let Some(block) = blocks_sub.next().await { + let block = block.unwrap(); + + let ti = api + .storage() + .at(block.reference()) + .fetch(&rococo_api::storage().balances().total_issuance()) + .await + .unwrap() + .unwrap() as i128; + + let diff = ti - issuance; + if diff != 0 { + log::info!("{} #{} issuance {} ({:+})", prefix, block.number(), ti, diff); + } + issuance = ti; + } +} + +#[tokio::test(flavor = "multi_thread")] +async fn coretime_revenue_test() -> Result<(), anyhow::Error> { + env_logger::init_from_env( + env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"), + ); + + let images = zombienet_sdk::environment::get_images_from_env(); + let config = NetworkConfigBuilder::new() + .with_relaychain(|r| { + r.with_chain("rococo-local") + .with_default_command("polkadot") + .with_default_image(images.polkadot.as_str()) + .with_genesis_overrides( + json!({ "configuration": { "config": { "scheduler_params": { "on_demand_base_fee": ON_DEMAND_BASE_FEE }}}}), + ) + .with_node(|node| node.with_name("alice")) + .with_node(|node| node.with_name("bob")) + .with_node(|node| node.with_name("charlie")) + }) + .with_parachain(|p| { + p.with_id(1005) + .with_default_command("polkadot-parachain") + .with_default_image(images.cumulus.as_str()) + .with_chain("coretime-rococo-local") + .with_collator(|n| n.with_name("coretime")) + }) + .build() + .map_err(|e| { + let errs = e.into_iter().map(|e| e.to_string()).collect::>().join(" "); + anyhow!("config errs: {errs}") + })?; + + let spawn_fn = zombienet_sdk::environment::get_spawn_fn(); + let network = spawn_fn(config).await?; + + let relay_node = network.get_node("alice")?; + let para_node = network.get_node("coretime")?; + + let relay_client: OnlineClient = relay_node.wait_client().await?; + let para_client: OnlineClient = para_node.wait_client().await?; + + // Get total issuance on both sides + let mut total_issuance = get_total_issuance(relay_client.clone(), para_client.clone()).await; + log::info!("Reference total issuance: {total_issuance:?}"); + + // Prepare everything + let alice = dev::alice(); + let alice_acc = AccountId32(alice.public_key().0); + + let bob = dev::bob(); + + let para_events: ParaEvents = Arc::new(RwLock::new(Vec::new())); + let p_api = para_node.wait_client().await?; + let p_events = para_events.clone(); + + let _subscriber = tokio::spawn(async move { + para_watcher(p_api, p_events).await; + }); + + let api: OnlineClient = para_node.wait_client().await?; + let _s1 = tokio::spawn(async move { + ti_watcher(api, "PARA").await; + }); + let api: OnlineClient = relay_node.wait_client().await?; + let _s2 = tokio::spawn(async move { + ti_watcher(api, "RELAY").await; + }); + + log::info!("Initiating teleport from RC's account of Alice to PC's one"); + + // Teleport some Alice's tokens to the Coretime chain. Although her account is pre-funded on + // the PC, that is still neccessary to bootstrap RC's `CheckedAccount`. + relay_client + .tx() + .sign_and_submit_default( + &rococo_api::tx().xcm_pallet().teleport_assets( + VersionedLocation::V4(Location { + parents: 0, + interior: Junctions::X1([Junction::Parachain(1005)]), + }), + VersionedLocation::V4(Location { + parents: 0, + interior: Junctions::X1([Junction::AccountId32 { + network: None, + id: alice.public_key().0, + }]), + }), + VersionedAssets::V4(Assets(vec![Asset { + id: AssetId(Location { parents: 0, interior: Junctions::Here }), + fun: Fungibility::Fungible(1_500_000_000), + }])), + 0, + ), + &alice, + ) + .await?; + + wait_for_para_event( + para_events.clone(), + "Balances", + "Minted", + |e: &coretime_api::balances::events::Minted| e.who == alice_acc, + ) + .await; + + // RC's total issuance doen't change, but PC's one increases after the teleport. + + total_issuance.1 += 1_500_000_000; + assert_total_issuance(relay_client.clone(), para_client.clone(), total_issuance).await; + + log::info!("Initializing broker and starting sales"); + + // Initialize broker and start sales + + para_client + .tx() + .sign_and_submit_default( + &coretime_api::tx().sudo().sudo(CoretimeRuntimeCall::Utility( + CoretimeUtilityCall::batch { + calls: vec![ + CoretimeRuntimeCall::Broker(CoretimeBrokerCall::configure { + config: BrokerConfigRecord { + advance_notice: 5, + interlude_length: 1, + leadin_length: 1, + region_length: 1, + ideal_bulk_proportion: Perbill(100), + limit_cores_offered: None, + renewal_bump: Perbill(10), + contribution_timeout: 5, + }, + }), + CoretimeRuntimeCall::Broker(CoretimeBrokerCall::set_lease { + task: 1005, + until: 1000, + }), + CoretimeRuntimeCall::Broker(CoretimeBrokerCall::start_sales { + end_price: 45_000_000, + extra_cores: 2, + }), + ], + }, + )), + &alice, + ) + .await?; + + log::info!("Waiting for a full-length sale to begin"); + + // Skip the first sale completeley as it may be a short one. Also, `request_code_count` requires + // two session boundaries to propagate. Given that the `fast-runtime` session is 10 blocks and + // the timeslice is 20 blocks, we should be just in time. + + let _: coretime_api::broker::events::SaleInitialized = + wait_for_para_event(para_events.clone(), "Broker", "SaleInitialized", |_| true).await; + log::info!("Skipped short sale"); + + let sale: coretime_api::broker::events::SaleInitialized = + wait_for_para_event(para_events.clone(), "Broker", "SaleInitialized", |_| true).await; + log::info!("{:?}", sale); + + // Alice buys a region + + log::info!("Alice is going to buy a region"); + + para_client + .tx() + .sign_and_submit_default(&coretime_api::tx().broker().purchase(1_000_000_000), &alice) + .await?; + + let purchase = wait_for_para_event( + para_events.clone(), + "Broker", + "Purchased", + |e: &broker_events::Purchased| e.who == alice_acc, + ) + .await; + + let region_begin = purchase.region_id.begin; + + // Somewhere below this point, the revenue from this sale will be teleported to the RC and burnt + // on both chains. Let's account that but not assert just yet. + + total_issuance.0 -= purchase.price; + total_issuance.1 -= purchase.price; + + // Alice pools the region + + log::info!("Alice is going to put the region into the pool"); + + para_client + .tx() + .sign_and_submit_default( + &coretime_api::tx().broker().pool( + purchase.region_id, + alice_acc.clone(), + BrokerFinality::Final, + ), + &alice, + ) + .await?; + + let pooled = wait_for_para_event( + para_events.clone(), + "Broker", + "Pooled", + |e: &broker_events::Pooled| e.region_id.begin == region_begin, + ) + .await; + + // Wait until the beginning of the timeslice where the region belongs to + + log::info!("Waiting for the region to begin"); + + let hist = wait_for_para_event( + para_events.clone(), + "Broker", + "HistoryInitialized", + |e: &broker_events::HistoryInitialized| e.when == pooled.region_id.begin, + ) + .await; + + // Alice's private contribution should be there + + assert!(hist.private_pool_size > 0); + + // Bob places an order to buy insta coretime as RC + + log::info!("Bob is going to buy an on-demand core"); + + let r = relay_client + .tx() + .sign_and_submit_then_watch_default( + &rococo_api::tx() + .on_demand_assignment_provider() + .place_order_allow_death(100_000_000, primitives::Id(100)), + &bob, + ) + .await? + .wait_for_finalized_success() + .await?; + + let order = r + .find_first::()? + .unwrap(); + + // As there's no spot traffic, Bob will only pay base fee + + assert_eq!(order.spot_price, ON_DEMAND_BASE_FEE); + + // Somewhere below this point, revenue is generated and is teleported to the PC (that happens + // once a timeslice so we're not ready to assert it yet, let's just account). That checks out + // tokens from the RC and mints them on the PC. + + total_issuance.1 += ON_DEMAND_BASE_FEE; + + // As soon as the PC receives the tokens, it divides them half by half into system and private + // contributions (we have 3 cores, one is leased to Coretime itself, one is pooled by the + // system, and one is pooled by Alice). + + // Now we're waiting for the moment when Alice may claim her revenue + + log::info!("Waiting for Alice's revenue to be ready to claim"); + + let claims_ready = wait_for_para_event( + para_events.clone(), + "Broker", + "ClaimsReady", + |e: &broker_events::ClaimsReady| e.when == pooled.region_id.begin, + ) + .await; + + // The revenue should be half of the spot price, which is equal to the base fee. + + assert_eq!(claims_ready.private_payout, ON_DEMAND_BASE_FEE / 2); + + // By this moment, we're sure that revenue was received by the PC and can assert the total + // issuance + + assert_total_issuance(relay_client.clone(), para_client.clone(), total_issuance).await; + + // Alice claims her revenue + + log::info!("Alice is going to claim her revenue"); + + para_client + .tx() + .sign_and_submit_default( + &coretime_api::tx().broker().claim_revenue(pooled.region_id, pooled.duration), + &alice, + ) + .await?; + + let claim_paid = wait_for_para_event( + para_events.clone(), + "Broker", + "RevenueClaimPaid", + |e: &broker_events::RevenueClaimPaid| e.who == alice_acc, + ) + .await; + + log::info!("Revenue claimed, waiting for 2 timeslices until the system revenue is burnt"); + + assert_eq!(claim_paid.amount, ON_DEMAND_BASE_FEE / 2); + + // As for the system revenue, it is teleported back to the RC and burnt there. Those burns are + // batched and are processed once a timeslice, after a new one starts. So we have to wait for + // two timeslice boundaries to pass to be sure the teleport has already happened somewhere in + // between. + + let _: coretime_api::broker::events::SaleInitialized = + wait_for_para_event(para_events.clone(), "Broker", "SaleInitialized", |_| true).await; + + total_issuance.0 -= ON_DEMAND_BASE_FEE / 2; + total_issuance.1 -= ON_DEMAND_BASE_FEE / 2; + + let _: coretime_api::broker::events::SaleInitialized = + wait_for_para_event(para_events.clone(), "Broker", "SaleInitialized", |_| true).await; + + assert_total_issuance(relay_client.clone(), para_client.clone(), total_issuance).await; + + log::info!("Test finished successfuly"); + + Ok(()) +} diff --git a/polkadot/zombienet-sdk-tests/tests/smoke/mod.rs b/polkadot/zombienet-sdk-tests/tests/smoke/mod.rs new file mode 100644 index 000000000000..a3fe15382674 --- /dev/null +++ b/polkadot/zombienet-sdk-tests/tests/smoke/mod.rs @@ -0,0 +1,5 @@ +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +#[cfg(feature = "zombie-metadata")] +mod coretime_revenue; diff --git a/polkadot/zombienet_tests/functional/0003-beefy-and-mmr.zndsl b/polkadot/zombienet_tests/functional/0003-beefy-and-mmr.zndsl index 8300ef051f09..4fc066a13b07 100644 --- a/polkadot/zombienet_tests/functional/0003-beefy-and-mmr.zndsl +++ b/polkadot/zombienet_tests/functional/0003-beefy-and-mmr.zndsl @@ -18,22 +18,22 @@ validator-unstable: reports substrate_beefy_best_block is at least 1 within 60 s validator-unstable: pause # Verify validator sets get changed on new sessions. -validator: reports substrate_beefy_validator_set_id is at least 1 within 70 seconds +validator: reports substrate_beefy_validator_set_id is at least 1 within 180 seconds # Check next session too. -validator: reports substrate_beefy_validator_set_id is at least 2 within 130 seconds +validator: reports substrate_beefy_validator_set_id is at least 2 within 180 seconds # Verify voting happens and blocks are being finalized for new sessions too: # since we verified we're at least in the 3rd session, verify BEEFY finalized mandatory #21. -validator: reports substrate_beefy_best_block is at least 21 within 130 seconds +validator: reports substrate_beefy_best_block is at least 21 within 180 seconds # Custom JS to test BEEFY RPCs. -validator-0: js-script ./0003-beefy-finalized-heads.js with "validator-0,validator-1,validator-2" return is 1 within 5 seconds +validator-0: js-script ./0003-beefy-finalized-heads.js with "validator-0,validator-1,validator-2" return is 1 within 60 seconds # Custom JS to test MMR RPCs. -validator: js-script ./0003-mmr-leaves.js with "21" return is 1 within 5 seconds -validator: js-script ./0003-mmr-generate-and-verify-proof.js with "validator-0,validator-1,validator-2" return is 1 within 5 seconds +validator: js-script ./0003-mmr-leaves.js with "21" return is 1 within 60 seconds +validator: js-script ./0003-mmr-generate-and-verify-proof.js with "validator-0,validator-1,validator-2" return is 1 within 60 seconds # Resume validator-unstable and verify it imports all BEEFY justification and catches up. validator-unstable: resume -validator-unstable: reports substrate_beefy_validator_set_id is at least 2 within 30 seconds -validator-unstable: reports substrate_beefy_best_block is at least 21 within 30 seconds +validator-unstable: reports substrate_beefy_validator_set_id is at least 2 within 60 seconds +validator-unstable: reports substrate_beefy_best_block is at least 21 within 60 seconds diff --git a/polkadot/zombienet_tests/functional/0003-mmr-generate-and-verify-proof.js b/polkadot/zombienet_tests/functional/0003-mmr-generate-and-verify-proof.js index 6583173e40c3..20d0c2a988b1 100644 --- a/polkadot/zombienet_tests/functional/0003-mmr-generate-and-verify-proof.js +++ b/polkadot/zombienet_tests/functional/0003-mmr-generate-and-verify-proof.js @@ -3,9 +3,9 @@ const common = require('./0003-common.js'); async function run(nodeName, networkInfo, nodeNames) { const apis = await common.getApis(networkInfo, nodeNames); - const proof = await apis[nodeName].rpc.mmr.generateProof([1, 9, 20]); - - const root = await apis[nodeName].rpc.mmr.root() + let at = await apis[nodeName].rpc.chain.getBlockHash(21); + const root = await apis[nodeName].rpc.mmr.root(at); + const proof = await apis[nodeName].rpc.mmr.generateProof([1, 9, 20], 21, at); const proofVerifications = await Promise.all( Object.values(apis).map(async (api) => { diff --git a/polkadot/zombienet_tests/functional/0009-approval-voting-coalescing.toml b/polkadot/zombienet_tests/functional/0009-approval-voting-coalescing.toml index 19c7015403d7..113de0e73aa1 100644 --- a/polkadot/zombienet_tests/functional/0009-approval-voting-coalescing.toml +++ b/polkadot/zombienet_tests/functional/0009-approval-voting-coalescing.toml @@ -18,7 +18,7 @@ requests = { memory = "2G", cpu = "1" } [[relaychain.node_groups]] name = "alice" - args = [ "-lparachain=trace,runtime=debug" ] + args = [ "-lparachain=debug,runtime=debug" ] count = 13 [[parachains]] diff --git a/polkadot/zombienet_tests/functional/0015-coretime-shared-core.zndsl b/polkadot/zombienet_tests/functional/0015-coretime-shared-core.zndsl index b8b8887df857..8f883dffa5e1 100644 --- a/polkadot/zombienet_tests/functional/0015-coretime-shared-core.zndsl +++ b/polkadot/zombienet_tests/functional/0015-coretime-shared-core.zndsl @@ -5,8 +5,8 @@ Creds: config validator: reports node_roles is 4 # register paras 2 by 2 to speed up the test. registering all at once will exceed the weight limit. -validator-0: js-script ./0015-force-register-paras.js with "2000,2001" return is 0 within 600 seconds -validator-0: js-script ./0015-force-register-paras.js with "2002,2003" return is 0 within 600 seconds +validator-0: js-script ./force-register-paras.js with "2000,2001" return is 0 within 600 seconds +validator-0: js-script ./force-register-paras.js with "2002,2003" return is 0 within 600 seconds # assign core 0 to be shared by all paras. validator-0: js-script ./assign-core.js with "0,2000,14400,2001,14400,2002,14400,2003,14400" return is 0 within 600 seconds diff --git a/polkadot/zombienet_tests/functional/0016-approval-voting-parallel.toml b/polkadot/zombienet_tests/functional/0016-approval-voting-parallel.toml new file mode 100644 index 000000000000..c035e23639c1 --- /dev/null +++ b/polkadot/zombienet_tests/functional/0016-approval-voting-parallel.toml @@ -0,0 +1,120 @@ +[settings] +timeout = 1000 + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +chain = "rococo-local" + +[relaychain.genesis.runtimeGenesis.patch.configuration.config] + needed_approvals = 4 + relay_vrf_modulo_samples = 2 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.approval_voting_params] + max_approval_coalesce_count = 5 + +[relaychain.default_resources] +limits = { memory = "4G", cpu = "2" } +requests = { memory = "2G", cpu = "1" } + + [[relaychain.node_groups]] + name = "alice" + args = ["-lparachain=debug,runtime=debug", "--enable-approval-voting-parallel"] + count = 8 + + [[relaychain.node_groups]] + name = "bob" + args = ["-lparachain=debug,runtime=debug"] + count = 7 + +[[parachains]] +id = 2000 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=1" + + [parachains.collator] + name = "collator01" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=100000", "--pvf-complexity=1", "--parachain-id=2000"] + +[[parachains]] +id = 2001 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=10" + + [parachains.collator] + name = "collator02" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=100000", "--parachain-id=2001", "--pvf-complexity=10"] + +[[parachains]] +id = 2002 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=100" + + [parachains.collator] + name = "collator03" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=100000", "--parachain-id=2002", "--pvf-complexity=100"] + +[[parachains]] +id = 2003 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=20000 --pvf-complexity=300" + + [parachains.collator] + name = "collator04" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=20000", "--parachain-id=2003", "--pvf-complexity=300"] + +[[parachains]] +id = 2004 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=300" + + [parachains.collator] + name = "collator05" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=100000", "--parachain-id=2004", "--pvf-complexity=300"] + +[[parachains]] +id = 2005 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=20000 --pvf-complexity=400" + + [parachains.collator] + name = "collator06" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=20000", "--pvf-complexity=400", "--parachain-id=2005"] + +[[parachains]] +id = 2006 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=300" + + [parachains.collator] + name = "collator07" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=100000", "--pvf-complexity=300", "--parachain-id=2006"] + +[[parachains]] +id = 2007 +addToGenesis = true +genesis_state_generator = "undying-collator export-genesis-state --pov-size=100000 --pvf-complexity=300" + + [parachains.collator] + name = "collator08" + image = "{{COL_IMAGE}}" + command = "undying-collator" + args = ["-lparachain=debug", "--pov-size=100000", "--pvf-complexity=300", "--parachain-id=2007"] + +[types.Header] +number = "u64" +parent_hash = "Hash" +post_state = "Hash" \ No newline at end of file diff --git a/polkadot/zombienet_tests/functional/0016-approval-voting-parallel.zndsl b/polkadot/zombienet_tests/functional/0016-approval-voting-parallel.zndsl new file mode 100644 index 000000000000..d70707747474 --- /dev/null +++ b/polkadot/zombienet_tests/functional/0016-approval-voting-parallel.zndsl @@ -0,0 +1,35 @@ +Description: Check finality works with approval voting parallel enabled +Network: ./0016-approval-voting-parallel.toml +Creds: config + +# Check authority status. +alice: reports node_roles is 4 + +# Ensure parachains are registered. +alice: parachain 2000 is registered within 60 seconds +alice: parachain 2001 is registered within 60 seconds +alice: parachain 2002 is registered within 60 seconds +alice: parachain 2003 is registered within 60 seconds +alice: parachain 2004 is registered within 60 seconds +alice: parachain 2005 is registered within 60 seconds +alice: parachain 2006 is registered within 60 seconds +alice: parachain 2007 is registered within 60 seconds + +# Ensure parachains made progress. +alice: parachain 2000 block height is at least 10 within 300 seconds +alice: parachain 2001 block height is at least 10 within 300 seconds +alice: parachain 2002 block height is at least 10 within 300 seconds +alice: parachain 2003 block height is at least 10 within 300 seconds +alice: parachain 2004 block height is at least 10 within 300 seconds +alice: parachain 2005 block height is at least 10 within 300 seconds +alice: parachain 2006 block height is at least 10 within 300 seconds +alice: parachain 2007 block height is at least 10 within 300 seconds + +alice: reports substrate_block_height{status="finalized"} is at least 30 within 180 seconds +bob: reports substrate_block_height{status="finalized"} is at least 30 within 180 seconds + +alice: reports polkadot_parachain_approval_checking_finality_lag < 3 +bob: reports polkadot_parachain_approval_checking_finality_lag < 3 + +alice: reports polkadot_parachain_approvals_no_shows_total < 3 within 10 seconds +bob: reports polkadot_parachain_approvals_no_shows_total < 3 within 10 seconds diff --git a/polkadot/zombienet_tests/functional/0017-sync-backing.toml b/polkadot/zombienet_tests/functional/0017-sync-backing.toml new file mode 100644 index 000000000000..2550054c8dad --- /dev/null +++ b/polkadot/zombienet_tests/functional/0017-sync-backing.toml @@ -0,0 +1,48 @@ +[settings] +timeout = 1000 + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +chain = "rococo-local" + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.async_backing_params] + max_candidate_depth = 0 + allowed_ancestry_len = 0 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] + lookahead = 2 + group_rotation_frequency = 4 + +[relaychain.default_resources] +limits = { memory = "4G", cpu = "2" } +requests = { memory = "2G", cpu = "1" } + + [[relaychain.node_groups]] + name = "alice" + args = [ "-lparachain=debug" ] + count = 10 + +[[parachains]] +id = 2000 +addToGenesis = true + + [parachains.collator] + name = "collator01" + image = "{{COL_IMAGE}}" + command = "adder-collator" + args = ["-lparachain=debug"] + +[[parachains]] +id = 2001 +cumulus_based = true + + [parachains.collator] + name = "collator02" + image = "{{CUMULUS_IMAGE}}" + command = "polkadot-parachain" + args = ["-lparachain=debug"] + +[types.Header] +number = "u64" +parent_hash = "Hash" +post_state = "Hash" \ No newline at end of file diff --git a/polkadot/zombienet_tests/functional/0017-sync-backing.zndsl b/polkadot/zombienet_tests/functional/0017-sync-backing.zndsl new file mode 100644 index 000000000000..a53de784b2d1 --- /dev/null +++ b/polkadot/zombienet_tests/functional/0017-sync-backing.zndsl @@ -0,0 +1,22 @@ +Description: Test we are producing 12-second parachain blocks if sync backing is configured +Network: ./0017-sync-backing.toml +Creds: config + +# Check authority status. +alice: reports node_roles is 4 + +# Ensure parachains are registered. +alice: parachain 2000 is registered within 60 seconds +alice: parachain 2001 is registered within 60 seconds + +# Ensure parachains made progress. +alice: reports substrate_block_height{status="finalized"} is at least 10 within 100 seconds + +# This parachains should produce blocks at 12s clip, let's assume an 14s rate, allowing for +# some slots to be missed on slower machines +alice: parachain 2000 block height is at least 21 within 300 seconds +alice: parachain 2000 block height is lower than 25 within 2 seconds + +# This should already have produced the needed blocks +alice: parachain 2001 block height is at least 21 within 10 seconds +alice: parachain 2001 block height is lower than 25 within 2 seconds diff --git a/polkadot/zombienet_tests/functional/0018-shared-core-idle-parachain.toml b/polkadot/zombienet_tests/functional/0018-shared-core-idle-parachain.toml new file mode 100644 index 000000000000..745c4f9e24b1 --- /dev/null +++ b/polkadot/zombienet_tests/functional/0018-shared-core-idle-parachain.toml @@ -0,0 +1,39 @@ +[settings] +timeout = 1000 + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.scheduler_params] + max_validators_per_core = 2 + lookahead = 2 + num_cores = 4 + group_rotation_frequency = 4 + + +[relaychain.genesis.runtimeGenesis.patch.configuration.config.approval_voting_params] + needed_approvals = 3 + +[relaychain] +default_image = "{{ZOMBIENET_INTEGRATION_TEST_IMAGE}}" +chain = "rococo-local" +command = "polkadot" + + [[relaychain.node_groups]] + name = "validator" + args = ["-lruntime=debug,parachain=debug"] + count = 4 + +[[parachains]] +id = 2000 +register_para = false +onboard_as_parachain = false +add_to_genesis = false +chain = "glutton-westend-local-2000" + [parachains.genesis.runtimeGenesis.patch.glutton] + compute = "50000000" + storage = "2500000000" + trashDataCount = 5120 + + [parachains.collator] + name = "collator-2000" + image = "{{CUMULUS_IMAGE}}" + command = "polkadot-parachain" + args = ["-lparachain=debug"] diff --git a/polkadot/zombienet_tests/functional/0018-shared-core-idle-parachain.zndsl b/polkadot/zombienet_tests/functional/0018-shared-core-idle-parachain.zndsl new file mode 100644 index 000000000000..80ecf6ae1b9b --- /dev/null +++ b/polkadot/zombienet_tests/functional/0018-shared-core-idle-parachain.zndsl @@ -0,0 +1,11 @@ +Description: Test that a parachain can keep producing blocks even if the other parachain with which it's sharing a core doesn't +Network: ./0018-shared-core-idle-parachain.toml +Creds: config + +validator: reports node_roles is 4 + +validator-0: js-script ./force-register-paras.js with "2000" return is 0 within 600 seconds +# assign core 0 to be shared by two paras, but only one exists +validator-0: js-script ./assign-core.js with "0,2000,28800,2001,28800" return is 0 within 600 seconds + +collator-2000: reports block height is at least 10 within 180 seconds diff --git a/polkadot/zombienet_tests/functional/0015-force-register-paras.js b/polkadot/zombienet_tests/functional/force-register-paras.js similarity index 100% rename from polkadot/zombienet_tests/functional/0015-force-register-paras.js rename to polkadot/zombienet_tests/functional/force-register-paras.js 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 000000000000..9963ce74d64e --- /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 000000000000..2baf21b96cc1 --- /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 000000000000..3ac68caf7e1b --- /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 000000000000..16e7d87d0ffc --- /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 000000000000..aba7bc3601fb --- /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 6ec3f6552a4a..3433f63f3029 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 705325126060..a8db0f9e1ea1 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/pr_4997.prdoc b/prdoc/1.15.0/pr_4997.prdoc similarity index 100% rename from prdoc/pr_4997.prdoc rename to prdoc/1.15.0/pr_4997.prdoc 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/pr_5040.prdoc b/prdoc/1.15.0/pr_5040.prdoc similarity index 100% rename from prdoc/pr_5040.prdoc rename to prdoc/1.15.0/pr_5040.prdoc diff --git a/prdoc/1.15.0/pr_5103.prdoc b/prdoc/1.15.0/pr_5103.prdoc new file mode 100644 index 000000000000..b0f72bf531f1 --- /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 000000000000..4f43b52d8edf --- /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/1.15.1/pr_4791.prdoc b/prdoc/1.15.1/pr_4791.prdoc new file mode 100644 index 000000000000..9a7a9ca44e16 --- /dev/null +++ b/prdoc/1.15.1/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/1.15.1/pr_4937.prdoc b/prdoc/1.15.1/pr_4937.prdoc new file mode 100644 index 000000000000..37b7bc3dda59 --- /dev/null +++ b/prdoc/1.15.1/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/1.15.1/pr_5273.prdoc b/prdoc/1.15.1/pr_5273.prdoc new file mode 100644 index 000000000000..981172c6c13f --- /dev/null +++ b/prdoc/1.15.1/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/1.15.1/pr_5281.prdoc b/prdoc/1.15.1/pr_5281.prdoc new file mode 100644 index 000000000000..60feab412aff --- /dev/null +++ b/prdoc/1.15.1/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/1.15.1/pr_5321.prdoc b/prdoc/1.15.1/pr_5321.prdoc new file mode 100644 index 000000000000..97f75d28dd52 --- /dev/null +++ b/prdoc/1.15.1/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/1.16.0/pr_2923.prdoc b/prdoc/1.16.0/pr_2923.prdoc new file mode 100644 index 000000000000..88bf1d48dd84 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_3049.prdoc b/prdoc/1.16.0/pr_3049.prdoc new file mode 100644 index 000000000000..9cead8e2a4e5 --- /dev/null +++ b/prdoc/1.16.0/pr_3049.prdoc @@ -0,0 +1,11 @@ +title: "Fix treasury benchmarks when `SpendOrigin` being `None`" + +doc: + - audience: Runtime Dev + description: | + Fix treasury benchmarks when `SpendOrigin` not returning any succesful origin. + This is for example the case when `SpendOrigin` is set to `NeverOrigin`. + +crates: + - name: pallet-treasury + bump: patch diff --git a/prdoc/1.16.0/pr_3786.prdoc b/prdoc/1.16.0/pr_3786.prdoc new file mode 100644 index 000000000000..0bb9e6c23f75 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_3996.prdoc b/prdoc/1.16.0/pr_3996.prdoc new file mode 100644 index 000000000000..7590d8992368 --- /dev/null +++ b/prdoc/1.16.0/pr_3996.prdoc @@ -0,0 +1,20 @@ +title: asset-hub-rococo - genesis config presets added + +doc: + - audience: Node Dev + description: | + `asset-hub-rococo` genesis state was moved to runtime. + - audience: Runtime Dev + description: | + `asset-hub-rococo` genesis state was moved to runtime. + + +crates: + - name: parachains-common + bump: minor + - name: testnet-parachains-constants + bump: minor + - name: asset-hub-rococo-runtime + bump: minor + - name: polkadot-parachain-bin + bump: minor diff --git a/prdoc/1.16.0/pr_4129.prdoc b/prdoc/1.16.0/pr_4129.prdoc new file mode 100644 index 000000000000..dfcc9b9ef030 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4424.prdoc b/prdoc/1.16.0/pr_4424.prdoc new file mode 100644 index 000000000000..7131ebfca274 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4460.prdoc b/prdoc/1.16.0/pr_4460.prdoc new file mode 100644 index 000000000000..81636c3313fc --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4487.prdoc b/prdoc/1.16.0/pr_4487.prdoc new file mode 100644 index 000000000000..fb2bab2a57a8 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4488.prdoc b/prdoc/1.16.0/pr_4488.prdoc new file mode 100644 index 000000000000..d0b6a877be6b --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4527.prdoc b/prdoc/1.16.0/pr_4527.prdoc new file mode 100644 index 000000000000..12056f87575b --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4564.prdoc b/prdoc/1.16.0/pr_4564.prdoc new file mode 100644 index 000000000000..896e49ee6b9f --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4586.prdoc b/prdoc/1.16.0/pr_4586.prdoc new file mode 100644 index 000000000000..46d166d0f977 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4613.prdoc b/prdoc/1.16.0/pr_4613.prdoc new file mode 100644 index 000000000000..e6b2e6adc612 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4640.prdoc b/prdoc/1.16.0/pr_4640.prdoc new file mode 100644 index 000000000000..52abc8f4baa5 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4665.prdoc b/prdoc/1.16.0/pr_4665.prdoc new file mode 100644 index 000000000000..7a8ec7398e64 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4706.prdoc b/prdoc/1.16.0/pr_4706.prdoc new file mode 100644 index 000000000000..ab235768b10d --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4739.prdoc b/prdoc/1.16.0/pr_4739.prdoc new file mode 100644 index 000000000000..9ca230e3e763 --- /dev/null +++ b/prdoc/1.16.0/pr_4739.prdoc @@ -0,0 +1,15 @@ +title: parachain-template - genesis config presets added + +doc: + - audience: Node Dev + description: | + - common DEV_RUNTIME_PRESET ("development") const added to sp-genesis-builder. + - parachain-templates are now using presets. + +crates: + - name: sp-genesis-builder + bump: minor + - name: parachain-template-node + bump: patch + - name: parachain-template-runtime + bump: patch diff --git a/prdoc/1.16.0/pr_4751.prdoc b/prdoc/1.16.0/pr_4751.prdoc new file mode 100644 index 000000000000..5a2c42209088 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4792.prdoc b/prdoc/1.16.0/pr_4792.prdoc new file mode 100644 index 000000000000..5ce4303bcf75 --- /dev/null +++ b/prdoc/1.16.0/pr_4792.prdoc @@ -0,0 +1,62 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "rpc: bind to `ipv6` if available and add `CLI --experimental-rpc-endpoint` to specify listen addr" + +doc: + - audience: Node Operator + description: | + This PR changes/adds the following: + + 1. The default setting is that substrate starts a rpc server that listens to localhost both ipv4 and ipv6 on the same port. + ipv6 is allowed to fail because some platforms may not support it + 2. A new RPC CLI option `--experimental-rpc-endpoint` is introduced which allows to configure arbitrary listen addresses including the port, + if this is enabled no other interfaces are enabled. + 3. If the local addr is not found for any of the sockets the server is not started and throws an error. + 4. Remove the deny_unsafe from the RPC implementations instead this is an extension to allow different polices for different interfaces/sockets + such one may enable unsafe on local interface and safe on only the external interface. + 5. This new `--experimental-rpc-endpoint` has several options and in the help menu all possible parameters are documented. + 6. The log emitted by jsonrpc server when it has been started has been modified to indicate all started rpc endpoints. + + So for instance it's now possible to start up three RPC endpoints as follows: + ``` + $ polkadot --experimental-rpc-endpoint "listen-addr=127.0.0.1:9944,methods=unsafe" --experimental-rpc-endpoint "listen-addr=0.0.0.0:9945,methods=safe,rate-limit=100" --experimental-rpc-endpoint "listen-addr=[::1]:9944,optional=true" + ``` + +crates: + - name: sc-rpc-server + bump: major + - name: sc-rpc + bump: major + - name: sc-cli + bump: major + - name: sc-service + bump: major + - name: sc-rpc-api + bump: patch + - name: polkadot-dispute-distribution + bump: patch + - name: polkadot-parachain-lib + bump: patch + - name: substrate-frame-rpc-system + bump: major + - name: substrate-state-trie-migration-rpc + bump: major + - name: cumulus-client-cli + bump: major + validate: false + - name: sc-consensus-beefy-rpc + bump: major + validate: false + - name: sc-consensus-grandpa-rpc + bump: major + validate: false + - name: sc-consensus-babe-rpc + bump: major + validate: false + - name: polkadot-rpc + bump: major + validate: false + - name: polkadot-service + bump: major + validate: false diff --git a/prdoc/1.16.0/pr_4822.prdoc b/prdoc/1.16.0/pr_4822.prdoc new file mode 100644 index 000000000000..44f3e41d8d5a --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4845.prdoc b/prdoc/1.16.0/pr_4845.prdoc new file mode 100644 index 000000000000..012d34ef090e --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4928.prdoc b/prdoc/1.16.0/pr_4928.prdoc new file mode 100644 index 000000000000..9935652dc511 --- /dev/null +++ b/prdoc/1.16.0/pr_4928.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: Move assignment VRF check and vote signature in approval-distribution + +doc: + - audience: Node Dev + description: | + This PR moves the assignment VRF check and approval vote signature from approval-voting into approval-distribution. + This optimization creates a better pipelining for processing new messages, because in this way approval-distribution + does not have to wait after approval-voting anymore and it will just notify it when it received a valid message that + is ready to be imported. + +crates: + - name: polkadot-node-subsystem-types + bump: major + - name: polkadot-approval-distribution + bump: major + - name: polkadot-node-core-approval-voting + bump: major + - name: polkadot-node-primitives + bump: major + - name: polkadot-service + bump: major + - name: polkadot-subsystem-bench + bump: major + - name: polkadot-overseer + bump: patch \ No newline at end of file diff --git a/prdoc/1.16.0/pr_4930.prdoc b/prdoc/1.16.0/pr_4930.prdoc new file mode 100644 index 000000000000..a7c9a302b118 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4936.prdoc b/prdoc/1.16.0/pr_4936.prdoc new file mode 100644 index 000000000000..f9b7ee506a7a --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4938.prdoc b/prdoc/1.16.0/pr_4938.prdoc new file mode 100644 index 000000000000..acc2a7c98e0e --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4949.prdoc b/prdoc/1.16.0/pr_4949.prdoc new file mode 100644 index 000000000000..4a5c09c6fa8d --- /dev/null +++ b/prdoc/1.16.0/pr_4949.prdoc @@ -0,0 +1,78 @@ +title: "[bridges-v2] Permissionless lanes" + +doc: +- audience: Runtime Dev + description: | + This PR adds support for opening and closing dynamic, also known as permissionless, lanes. + This means that authorized origins (relay chain, sibling parachains) + can open and close bridges with other bridged (substrate-like) consensuses supported by Bridge Hubs. + The Bridge Hubs, particularly the `pallet-xcm-bridge-hub`, introduce new extrinsics `open_bridge` and `close_bridge`, + which can be called using `xcm::Transact`. + +crates: +- name: bridge-runtime-common + bump: major +- name: bp-bridge-hub-rococo + bump: minor +- name: bp-bridge-hub-westend + bump: minor +- name: pallet-bridge-grandpa + bump: major +- name: pallet-bridge-messages + bump: major +- name: pallet-bridge-parachains + bump: major +- name: pallet-bridge-relayers + bump: major +- name: pallet-xcm-bridge-hub + bump: major +- name: pallet-xcm-bridge-hub-router + bump: major +- name: bp-header-chain + bump: patch +- name: bp-messages + bump: major +- name: bp-parachains + bump: major +- name: bp-polkadot-core + bump: none +- name: bp-relayers + bump: major +- name: bp-runtime + bump: minor +- name: bp-xcm-bridge-hub-router + bump: patch +- name: bp-xcm-bridge-hub + bump: major +- name: relay-substrate-client + bump: none +- name: substrate-relay-helper + bump: major +- name: messages-relay + bump: major +- name: parachains-relay + bump: none +- name: cumulus-pallet-xcmp-queue + bump: patch +- name: parachains-relay + bump: none +- name: asset-hub-rococo-runtime + bump: major +- name: asset-hub-westend-runtime + bump: major +- name: bridge-hub-rococo-runtime + bump: major +- name: bridge-hub-westend-runtime + bump: major +- name: emulated-integration-tests-common + bump: minor +- name: asset-test-utils + bump: patch +- name: parachains-runtimes-test-utils + bump: minor +- name: bridge-hub-common + bump: minor +- name: bridge-hub-test-utils + bump: major +- name: xcm-emulator + bump: major diff --git a/prdoc/1.16.0/pr_4956.prdoc b/prdoc/1.16.0/pr_4956.prdoc new file mode 100644 index 000000000000..a72ca303aaca --- /dev/null +++ b/prdoc/1.16.0/pr_4956.prdoc @@ -0,0 +1,39 @@ +title: Add build options to the srtool build step and delete `disanle-logging` feature + +doc: +- audience: Runtime Dev + description: | + This PR adds possibility to set BUILD_OPTIONS to the "Srtool Build\" step in the release pipeline while building runtimes. + And deletes the `disable-logging` feature from test runtimes to be able to build those with an activated logging. + + + +crates: +- name: people-rococo-runtime + bump: patch +- name: people-westend-runtime + bump: patch +- name: rococo-parachain-runtime + bump: patch +- name: asset-hub-rococo-runtime + bump: patch +- name: asset-hub-westend-runtime + bump: patch +- name: bridge-hub-rococo-runtime + bump: patch +- name: bridge-hub-westend-runtime + bump: patch +- name: collectives-westend-runtime + bump: patch +- name: contracts-rococo-runtime + bump: patch +- name: coretime-rococo-runtime + bump: patch +- name: coretime-westend-runtime + bump: patch +- name: glutton-westend-runtime + bump: patch +- name: rococo-runtime + bump: patch +- name: westend-runtime + bump: patch diff --git a/prdoc/1.16.0/pr_4959.prdoc b/prdoc/1.16.0/pr_4959.prdoc new file mode 100644 index 000000000000..4891a9791795 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4962.prdoc b/prdoc/1.16.0/pr_4962.prdoc new file mode 100644 index 000000000000..0957f85b6628 --- /dev/null +++ b/prdoc/1.16.0/pr_4962.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-treasury + +doc: + - audience: Runtime Dev + description: | + This PR removed `pallet::getter`s from `pallet-treasury`s storage items. + Instead use the syntax `StorageItem::::get()`. + +crates: + - name: pallet-treasury + bump: minor \ No newline at end of file diff --git a/prdoc/1.16.0/pr_4963.prdoc b/prdoc/1.16.0/pr_4963.prdoc new file mode 100644 index 000000000000..e274d2cbb689 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4967.prdoc b/prdoc/1.16.0/pr_4967.prdoc new file mode 100644 index 000000000000..0ce4219daa1c --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4970.prdoc b/prdoc/1.16.0/pr_4970.prdoc new file mode 100644 index 000000000000..d86f1af1e860 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4973.prdoc b/prdoc/1.16.0/pr_4973.prdoc new file mode 100644 index 000000000000..20b8c94dd8a9 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4976.prdoc b/prdoc/1.16.0/pr_4976.prdoc new file mode 100644 index 000000000000..72b7b92bc47f --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4993.prdoc b/prdoc/1.16.0/pr_4993.prdoc new file mode 100644 index 000000000000..d822d5cd6c76 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4998.prdoc b/prdoc/1.16.0/pr_4998.prdoc new file mode 100644 index 000000000000..41e3886405cc --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_4999.prdoc b/prdoc/1.16.0/pr_4999.prdoc new file mode 100644 index 000000000000..d396fcdbe8b3 --- /dev/null +++ b/prdoc/1.16.0/pr_4999.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: Fixes entropy for derivation of proxy delegator account. + +doc: + - audience: Runtime Dev + description: | + This fixes how ProxyDelegator accounts are derived but may cause issues in Westend since it would use the old + derivative accounts. Does not affect Polkadot/Kusama as this pallet is not deployed to them yet. + +crates: + - name: westend-runtime + bump: patch + - name: pallet-delegated-staking + bump: patch + - name: pallet-nomination-pools + bump: patch \ No newline at end of file diff --git a/prdoc/1.16.0/pr_5029.prdoc b/prdoc/1.16.0/pr_5029.prdoc new file mode 100644 index 000000000000..d446ddf274b8 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5036.prdoc b/prdoc/1.16.0/pr_5036.prdoc new file mode 100644 index 000000000000..e9f21f823b64 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5055.prdoc b/prdoc/1.16.0/pr_5055.prdoc new file mode 100644 index 000000000000..2367bd5925f8 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5065.prdoc b/prdoc/1.16.0/pr_5065.prdoc new file mode 100644 index 000000000000..11fca2ab71d6 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5067.prdoc b/prdoc/1.16.0/pr_5067.prdoc new file mode 100644 index 000000000000..9a11f96b5104 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5074.prdoc b/prdoc/1.16.0/pr_5074.prdoc new file mode 100644 index 000000000000..cddf15ffb47c --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5078.prdoc b/prdoc/1.16.0/pr_5078.prdoc new file mode 100644 index 000000000000..1805a27c3f28 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5082.prdoc b/prdoc/1.16.0/pr_5082.prdoc new file mode 100644 index 000000000000..d309f4e7266e --- /dev/null +++ b/prdoc/1.16.0/pr_5082.prdoc @@ -0,0 +1,15 @@ +title: "Fix ParaInherent weight overestimation" + +doc: + - audience: Runtime Dev + description: | + This PR fixes the relay chain inherent weight overestimation allowing it + to support more cores and validators. + +crates: +- name: polkadot-runtime-parachains + bump: major +- name: westend-runtime + bump: minor +- name: rococo-runtime + bump: minor diff --git a/prdoc/1.16.0/pr_5113.prdoc b/prdoc/1.16.0/pr_5113.prdoc new file mode 100644 index 000000000000..64563f7a735d --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5114.prdoc b/prdoc/1.16.0/pr_5114.prdoc new file mode 100644 index 000000000000..d57141490a3e --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5124.prdoc b/prdoc/1.16.0/pr_5124.prdoc new file mode 100644 index 000000000000..966761721fc7 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5127.prdoc b/prdoc/1.16.0/pr_5127.prdoc new file mode 100644 index 000000000000..c08f4e7fb8fa --- /dev/null +++ b/prdoc/1.16.0/pr_5127.prdoc @@ -0,0 +1,25 @@ +title: Add benchmark to check upcoming minimum required hw cores + +doc: + - audience: Node Operator + description: | + Add benchmark that checks hardware satisifies the minimum required hardware cores + for a validators. The new minimum requirements are schedule to come into effect + in January 2025, for more details see: https://polkadot.subsquare.io/referenda/1051. + + +crates: + - name: sc-sysinfo + bump: major + - name: frame-benchmarking-cli + bump: major + - name: staging-node-cli + bump: patch + - name: polkadot-service + bump: patch + - name: polkadot-parachain-lib + bump: patch + - name: polkadot-cli + bump: patch + - name: parachain-template-node + bump: patch diff --git a/prdoc/1.16.0/pr_5129.prdoc b/prdoc/1.16.0/pr_5129.prdoc new file mode 100644 index 000000000000..beb7eb4d282d --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5130.prdoc b/prdoc/1.16.0/pr_5130.prdoc new file mode 100644 index 000000000000..c6a00505babc --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5131.prdoc b/prdoc/1.16.0/pr_5131.prdoc new file mode 100644 index 000000000000..db1003ab4033 --- /dev/null +++ b/prdoc/1.16.0/pr_5131.prdoc @@ -0,0 +1,42 @@ +# 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: Swap for paying delivery fees in different assets + +doc: + - audience: Runtime User + description: | + If the `AssetExchanger` is configured on a runtime, the XCM executor is now able to swap assets + to pay for delivery fees. + This was already possible for execution fees via the `SwapFirstAssetTrader`. + A runtime where this will be possible is Asset Hub. + That means reserve asset transfers from Parachain A to Parachain B passing through Asset Hub no + longer need to have any DOT to pay for fees on AssetHub. + They can have any asset in a pool with DOT on Asset Hub, for example USDT or USDC. + - audience: Runtime Dev + description: | + Using the `AssetExchanger` XCM config item, the executor now swaps fees to use for delivery fees, + if possible. + If you want your runtime to support this, you need to configure this new item. + Thankfully, `xcm-builder` now has a new adapter for this, which lets you use `pallet-asset-conversion` + or any type that implements the `SwapCredit` and `QuotePrice` traits. + It's called `SingleAssetExchangeAdapter`, you can read more about it in its rust docs. + This item is already configured in Asset Hub. + + IMPORTANT: The executor now only takes the first asset for delivery fees. If you have configured a custom router + that returns more than one asset for delivery fees, then only the first one will be taken into account. + This is most likely not what you want. + +crates: + - name: staging-xcm-executor + bump: minor + - name: asset-hub-westend-runtime + bump: minor + - name: asset-hub-rococo-runtime + bump: minor + - name: staging-xcm-builder + bump: patch + - name: assets-common + bump: patch + - name: penpal-runtime + bump: minor diff --git a/prdoc/1.16.0/pr_5132.prdoc b/prdoc/1.16.0/pr_5132.prdoc new file mode 100644 index 000000000000..f23574e04b79 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5142.prdoc b/prdoc/1.16.0/pr_5142.prdoc new file mode 100644 index 000000000000..4083e5bf53cd --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5155.prdoc b/prdoc/1.16.0/pr_5155.prdoc new file mode 100644 index 000000000000..373522eea1c3 --- /dev/null +++ b/prdoc/1.16.0/pr_5155.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: Use umbrella crate for minimal template + +doc: + - audience: Runtime Dev + description: | + Minor additions to the `polkadot-sdk-frame` crate and making it ready for usage in more templates. This PR already integrates it in the minimal template. + + +crates: + - name: polkadot-sdk + bump: major + - name: polkadot-sdk-frame + bump: patch + - name: sp-wasm-interface + bump: patch + - name: pallet-revive + bump: patch + - name: pallet-revive-fixtures + bump: patch + - name: frame-support + bump: patch + - name: pallet-balances + bump: patch + diff --git a/prdoc/1.16.0/pr_5173.prdoc b/prdoc/1.16.0/pr_5173.prdoc new file mode 100644 index 000000000000..81ddcd9578ba --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5174.prdoc b/prdoc/1.16.0/pr_5174.prdoc new file mode 100644 index 000000000000..2c7a6983377c --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5188.prdoc b/prdoc/1.16.0/pr_5188.prdoc new file mode 100644 index 000000000000..b2ab9ff6653b --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5195.prdoc b/prdoc/1.16.0/pr_5195.prdoc new file mode 100644 index 000000000000..cfd435fa289d --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5196.prdoc b/prdoc/1.16.0/pr_5196.prdoc new file mode 100644 index 000000000000..3ed4fbdff3f3 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5197.prdoc b/prdoc/1.16.0/pr_5197.prdoc new file mode 100644 index 000000000000..40e25cf70dd1 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5204.prdoc b/prdoc/1.16.0/pr_5204.prdoc new file mode 100644 index 000000000000..38a73b6b00ef --- /dev/null +++ b/prdoc/1.16.0/pr_5204.prdoc @@ -0,0 +1,13 @@ +title: "Pallet assets: fix doc: start_destroy never required asset to be frozen" + +doc: + - audience: Runtime Dev + description: | + In pallet assets calling `start_destroy` doesn't require the asset to be frozen. Doc is fixed. + + +crates: + - name: pallet-assets + bump: patch + - name: frame-support + bump: patch diff --git a/prdoc/1.16.0/pr_5205.prdoc b/prdoc/1.16.0/pr_5205.prdoc new file mode 100644 index 000000000000..48abfe50ca24 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5214.prdoc b/prdoc/1.16.0/pr_5214.prdoc new file mode 100644 index 000000000000..4dc8b28c5948 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5240.prdoc b/prdoc/1.16.0/pr_5240.prdoc new file mode 100644 index 000000000000..3622a6ada76b --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5250.prdoc b/prdoc/1.16.0/pr_5250.prdoc new file mode 100644 index 000000000000..2cac6b2383e3 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5252.prdoc b/prdoc/1.16.0/pr_5252.prdoc new file mode 100644 index 000000000000..fd4454ac3b9d --- /dev/null +++ b/prdoc/1.16.0/pr_5252.prdoc @@ -0,0 +1,11 @@ +title: Additional logging in `dispute-coordinator` subsystem + +doc: + - audience: Node Dev + description: | + Additional logging in `dispute-coordinator` subsystem tracing the list of offchain disabled + validators and the reason why an import statement is considered spam. + +crates: + - name: polkadot-node-core-dispute-coordinator + bump: patch \ No newline at end of file diff --git a/prdoc/1.16.0/pr_5257.prdoc b/prdoc/1.16.0/pr_5257.prdoc new file mode 100644 index 000000000000..7a4cff671af0 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5262.prdoc b/prdoc/1.16.0/pr_5262.prdoc new file mode 100644 index 000000000000..828f0ffeb1bc --- /dev/null +++ b/prdoc/1.16.0/pr_5262.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: Correct some typos in crates' descriptions + +doc: + - audience: Runtime Dev + description: | + Corrected typos and copy-paste errors in crates' descriptions. + +crates: + - name: cumulus-client-pov-recovery + bump: patch + - name: cumulus-pallet-aura-ext + bump: patch + - name: bridge-hub-rococo-runtime + bump: patch + - name: frame-try-runtime + bump: patch + - name: pallet-whitelist + bump: patch + - name: polkadot-sdk + bump: patch + - name: polkadot-runtime-parachains + bump: none diff --git a/prdoc/1.16.0/pr_5269.prdoc b/prdoc/1.16.0/pr_5269.prdoc new file mode 100644 index 000000000000..e4401f2406ce --- /dev/null +++ b/prdoc/1.16.0/pr_5269.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: Added the possibility to build a parachain node with block number u64 + +doc: + - audience: Node Dev + description: | + Added the possibility to build a parachain node with block number u64. + +crates: + - name: polkadot-parachain-lib + bump: minor + - name: polkadot-parachain-bin + bump: patch diff --git a/prdoc/1.16.0/pr_5270.prdoc b/prdoc/1.16.0/pr_5270.prdoc new file mode 100644 index 000000000000..e6d7142cabd0 --- /dev/null +++ b/prdoc/1.16.0/pr_5270.prdoc @@ -0,0 +1,20 @@ +title: "Inclusion: account for enact_candidate weight" + +doc: + - audience: Runtime Dev + description: | + We are now properly accounting for the `enact_candidate`s weight in + processing of a relay chain block inherent. This may result in some + of the user relay chain transactions not being included in the block if + it's really heavy. This should be fine though as we are moving towards + the minimal relay chain. + +crates: +- name: polkadot-runtime-parachains + bump: major +- name: westend-runtime + bump: patch +- name: rococo-runtime + bump: patch +- name: polkadot-node-core-pvf-common + bump: none diff --git a/prdoc/1.16.0/pr_5284.prdoc b/prdoc/1.16.0/pr_5284.prdoc new file mode 100644 index 000000000000..a3244a82c860 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5288.prdoc b/prdoc/1.16.0/pr_5288.prdoc new file mode 100644 index 000000000000..8241e75876f1 --- /dev/null +++ b/prdoc/1.16.0/pr_5288.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: Added `polkadot-parachain-lib` helper library that can be used to build a parachain node + +doc: + - audience: Node Dev + description: | + This PR adds the `polkadot-parachain-lib` helper library that can be used to build a parachain node. + +crates: + - name: polkadot-parachain-bin + bump: patch + - name: polkadot-parachain-lib + bump: patch + - name: polkadot-sdk + bump: patch diff --git a/prdoc/1.16.0/pr_5293.prdoc b/prdoc/1.16.0/pr_5293.prdoc new file mode 100644 index 000000000000..90528a224e8d --- /dev/null +++ b/prdoc/1.16.0/pr_5293.prdoc @@ -0,0 +1,22 @@ +title: Add initial version of pallet_revive + +doc: + - audience: Runtime Dev + description: | + Adds initial **experimental** version of the new pallet_revive. It will run PolkaVM + contracts which were recompiled from YUL using the revive compiler. Do not use the + pallet in production, yet. It is work in progress. + +crates: + - name: polkadot-sdk + bump: minor + - name: pallet-revive + bump: minor + - name: pallet-revive-fixtures + bump: minor + - name: pallet-revive-proc-macro + bump: minor + - name: pallet-revive-uapi + bump: minor + - name: pallet-revive-mock-network + bump: minor diff --git a/prdoc/1.16.0/pr_5316.prdoc b/prdoc/1.16.0/pr_5316.prdoc new file mode 100644 index 000000000000..75b431c941d5 --- /dev/null +++ b/prdoc/1.16.0/pr_5316.prdoc @@ -0,0 +1,11 @@ +title: add timestamp function to sp-consensus-slots + +doc: + - audience: Node Dev + description: | + Added timestamp function to sp-consensus-slots to get the first timestamp + of the given slot. + +crates: + - name: sp-consensus-slots + bump: minor diff --git a/prdoc/1.16.0/pr_5326.prdoc b/prdoc/1.16.0/pr_5326.prdoc new file mode 100644 index 000000000000..0301b8c17a30 --- /dev/null +++ b/prdoc/1.16.0/pr_5326.prdoc @@ -0,0 +1,13 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: Update Readme of the `polkadot` crate + +doc: + - audience: Node Operator + description: | + Updated Readme of the `polkadot` crate. + +crates: + - name: polkadot + bump: patch diff --git a/prdoc/1.16.0/pr_5327.prdoc b/prdoc/1.16.0/pr_5327.prdoc new file mode 100644 index 000000000000..a3821790590b --- /dev/null +++ b/prdoc/1.16.0/pr_5327.prdoc @@ -0,0 +1,43 @@ +# 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: "Moved presets to the testnet runtimes" + +doc: + - audience: Runtime Dev + description: | + This PR migrates the genesis config presets from `polkadot-parachain-bin` to the relevant runtimes. + +crates: + - name: polkadot-runtime-common + bump: patch + - name: rococo-runtime + bump: patch + - name: westend-runtime + bump: patch + - name: parachains-common + bump: patch + - name: testnet-parachains-constants + bump: patch + - name: asset-hub-rococo-runtime + bump: patch + - name: asset-hub-westend-runtime + bump: patch + - name: bridge-hub-rococo-runtime + bump: patch + - name: bridge-hub-westend-runtime + bump: patch + - name: collectives-westend-runtime + bump: patch + - name: polkadot-parachain-bin + bump: patch + - name: polkadot-runtime-parachains + bump: none + - name: polkadot-service + bump: major + - name: polkadot-cli + bump: patch + - name: sc-chain-spec + bump: none + - name: sp-genesis-builder + bump: none diff --git a/prdoc/1.16.0/pr_5339.prdoc b/prdoc/1.16.0/pr_5339.prdoc new file mode 100644 index 000000000000..850ba903e126 --- /dev/null +++ b/prdoc/1.16.0/pr_5339.prdoc @@ -0,0 +1,45 @@ +title: Replace unnecessary `&mut self` with `&self` in `BlockImport::import_block()` + +doc: + - audience: Node Dev + description: | + Simplifies block import API to match intended design where independent blocks can technically be imported + concurrently and in practice was called through `Arc` anyway + +crates: + - name: cumulus-client-consensus-common + bump: major + - name: cumulus-client-network + bump: none + - name: cumulus-relay-chain-inprocess-interface + bump: none + - name: cumulus-pallet-parachain-system + bump: none + - name: sc-basic-authorship + bump: patch + - name: sc-consensus-babe + bump: major + - name: sc-consensus-beefy + bump: major + - name: sc-consensus + bump: major + - name: sc-consensus-grandpa + bump: major + - name: sc-consensus-pow + bump: major + - name: mmr-gadget + bump: none + - name: sc-network + bump: none + - name: sc-network-sync + bump: none + - name: sc-offchain + bump: none + - name: sc-rpc-spec-v2 + bump: none + - name: sc-rpc + bump: none + - name: sc-service + bump: major + - name: sc-transaction-pool + bump: none diff --git a/prdoc/1.16.0/pr_5344.prdoc b/prdoc/1.16.0/pr_5344.prdoc new file mode 100644 index 000000000000..9f83c113686d --- /dev/null +++ b/prdoc/1.16.0/pr_5344.prdoc @@ -0,0 +1,10 @@ +title: Fix storage weight reclaim bug. + +doc: + - audience: Node Dev + description: | + Improvement in slot worker loop that will not call create inherent data providers if the major sync is in progress. Before it was called every slot and the results were discarded during major sync. + +crates: + - name: sc-consensus-slots + bump: minor diff --git a/prdoc/1.16.0/pr_5348.prdoc b/prdoc/1.16.0/pr_5348.prdoc new file mode 100644 index 000000000000..c2282c4c74c4 --- /dev/null +++ b/prdoc/1.16.0/pr_5348.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: allow for u8 to be used as hold/freeze reason + +doc: + - audience: Runtime Dev + description: | + Allows for `u8` type to be configured as `HoldReason` and `FreezeReason` + +crates: + - name: frame-support + bump: patch diff --git a/prdoc/1.16.0/pr_5352.prdoc b/prdoc/1.16.0/pr_5352.prdoc new file mode 100644 index 000000000000..4b055d81cb51 --- /dev/null +++ b/prdoc/1.16.0/pr_5352.prdoc @@ -0,0 +1,10 @@ +title: "Aura: Ensure parachains are building on all relay chain forks" + +doc: + - audience: Node Dev + description: | + Ensure that parachains using the `basic` collator are building on all relay chain forks. + +crates: + - name: cumulus-client-consensus-aura + bump: patch diff --git a/prdoc/1.16.0/pr_5354.prdoc b/prdoc/1.16.0/pr_5354.prdoc new file mode 100644 index 000000000000..e3037b66fbca --- /dev/null +++ b/prdoc/1.16.0/pr_5354.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: Fix benchmark failures when using insecure_zero_ed flag + +doc: + - audience: Runtime Dev + description: | + Currently, when the pallet is compiled with the insecure_zero_ed flag, benchmarks fail because the minimum balance is set to zero. + + The PR aims to resolve this issue by implementing a placeholder value for the minimum balance when the insecure_zero_ed flag is active. it ensures that benchmarks run successfully regardless of whether this flag is used or not + +crates: +- name: pallet-balances + bump: minor diff --git a/prdoc/1.16.0/pr_5356.prdoc b/prdoc/1.16.0/pr_5356.prdoc new file mode 100644 index 000000000000..a306be335440 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5359.prdoc b/prdoc/1.16.0/pr_5359.prdoc new file mode 100644 index 000000000000..bf059129a436 --- /dev/null +++ b/prdoc/1.16.0/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/1.16.0/pr_5360.prdoc b/prdoc/1.16.0/pr_5360.prdoc new file mode 100644 index 000000000000..4b07f30bfd09 --- /dev/null +++ b/prdoc/1.16.0/pr_5360.prdoc @@ -0,0 +1,3 @@ +crates: + - name: sc-service + bump: none diff --git a/prdoc/1.16.0/pr_5364.prdoc b/prdoc/1.16.0/pr_5364.prdoc new file mode 100644 index 000000000000..35a72f65fb1e --- /dev/null +++ b/prdoc/1.16.0/pr_5364.prdoc @@ -0,0 +1,39 @@ +title: Improve `sc-service` API + +doc: + - audience: Node Dev + description: | + This improves `sc-service` API by not requiring the whole `&Configuration`, using specific configuration options + instead. `RpcConfiguration` and `ExecutorConfiguration` were also extracted from `Configuration` to group all RPC + and executor options together. + If `sc-service` is used as a library with lower-level APIs, `Configuration` can now be avoided in most cases. + + This mainly impacts you on your node implementation. There you need to change this: + ``` + with_execution_method(config.wasm_method) + ``` + + to this: + ``` + with_execution_method(config.executor.wasm_method) + ``` + + There are similar changes required as well, but all are around the initialization of the wasm executor. + +crates: + - name: sc-service + bump: major + - name: sc-network-common + bump: patch + - name: sc-cli + bump: major + - name: polkadot-service + bump: patch + - name: cumulus-relay-chain-minimal-node + bump: none + - name: polkadot-parachain-bin + bump: major + - name: polkadot-parachain-lib + bump: major + - name: staging-node-inspect + bump: major diff --git a/prdoc/1.16.0/pr_5369.prdoc b/prdoc/1.16.0/pr_5369.prdoc new file mode 100644 index 000000000000..1baa5e1cbe7d --- /dev/null +++ b/prdoc/1.16.0/pr_5369.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: Fix failing XCM from relay to Coretime Chain when revenue is zero + +doc: + - audience: Runtime Dev + description: | + The coretime assigner now always includes UnpaidExecution when calling `notify_revenue` via a + `Transact`, not just when revenue is nonzero. This fixes an issue where the XCM would fail to + process on the receiving side. + +crates: + - name: polkadot-runtime-parachains + bump: patch diff --git a/prdoc/1.16.0/pr_5376.prdoc b/prdoc/1.16.0/pr_5376.prdoc new file mode 100644 index 000000000000..c9874ef7d865 --- /dev/null +++ b/prdoc/1.16.0/pr_5376.prdoc @@ -0,0 +1,3 @@ +crates: + - name: binary-merkle-tree + bump: none diff --git a/prdoc/1.16.0/pr_5380.prdoc b/prdoc/1.16.0/pr_5380.prdoc new file mode 100644 index 000000000000..75063e335343 --- /dev/null +++ b/prdoc/1.16.0/pr_5380.prdoc @@ -0,0 +1,15 @@ +title: Fix leases with gaps and time slice calculation in MigrateToCoretime + +doc: + - audience: Runtime Dev + description: | + Agile Coretime storage migration wasn't transferring correctly leases with gaps and was + miscalculating time lease period. This patch provides fixes for both issues. + +crates: + - name: rococo-runtime + bump: patch + - name: westend-runtime + bump: major + - name: polkadot-runtime-parachains + bump: patch \ No newline at end of file diff --git a/prdoc/1.16.0/pr_5384.prdoc b/prdoc/1.16.0/pr_5384.prdoc new file mode 100644 index 000000000000..74d477f8e153 --- /dev/null +++ b/prdoc/1.16.0/pr_5384.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: "`MaybeConsideration` extension trait for `Consideration`" + +doc: + - audience: Runtime Dev + description: | + The trait allows for the management of tickets that may represent no cost. While + the `MaybeConsideration` still requires proper handling, it introduces the ability + to determine if a ticket represents no cost and can be safely forgotten without any + side effects. + + The new trait is particularly useful when a consumer expects the cost to be zero under + certain conditions (e.g., when the proposal count is below a threshold N) and does not want + to store such consideration tickets in storage. The extension approach allows us to avoid + breaking changes to the existing trait and to continue using it as a non-optional version + for migrating pallets that utilize the `Currency` and `fungible` traits for `holds` and + `freezes`, without requiring any storage migration. + +crates: + - name: frame-support + bump: minor + - name: pallet-balances + bump: patch diff --git a/prdoc/1.16.0/pr_5392.prdoc b/prdoc/1.16.0/pr_5392.prdoc new file mode 100644 index 000000000000..aeeb05de0bc3 --- /dev/null +++ b/prdoc/1.16.0/pr_5392.prdoc @@ -0,0 +1,11 @@ +title: "Don't disconnect disabled nodes sending us dispute messages" + +doc: + - audience: Node Operator + description: | + No longer disconnect peers which we consider disabled when raising + disputes as this will affect the approval process and thus finality. + +crates: + - name: polkadot-dispute-distribution + bump: patch diff --git a/prdoc/1.16.0/pr_5393.prdoc b/prdoc/1.16.0/pr_5393.prdoc new file mode 100644 index 000000000000..7fcf3067fabc --- /dev/null +++ b/prdoc/1.16.0/pr_5393.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: Allow to enable full PoV size + +doc: + - audience: Node Dev + description: | + A feature is introduced allowing a collator to enable full PoV size at compile time. + WARNING: To use this feature, security considerations must be understood and the latest + SDK version must be used. + +crates: + - name: cumulus-client-consensus-aura + bump: minor diff --git a/prdoc/1.16.0/pr_5396.prdoc b/prdoc/1.16.0/pr_5396.prdoc new file mode 100644 index 000000000000..d78e9ac46932 --- /dev/null +++ b/prdoc/1.16.0/pr_5396.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: Simplify `SyncingEngine::new()` + +doc: + - audience: Node Dev + description: | + Tiny changes to simplify the internal implemenation of API `SyncingEngine::new()` to prevent panics while fetching the genesis hash and to eliminate unnecessary allocation for reserved peers. + +crates: +- name: sc-network-sync + bump: none diff --git a/prdoc/1.16.0/pr_5407.prdoc b/prdoc/1.16.0/pr_5407.prdoc new file mode 100644 index 000000000000..f7e6b86f9d1e --- /dev/null +++ b/prdoc/1.16.0/pr_5407.prdoc @@ -0,0 +1,17 @@ +title: Prepare PVFs if node is a validator in the next session + +doc: + - audience: [Node Operator, Node Dev] + description: | + This PR aims to remove the noise caused by the peer store's reputation system. + A warning was emitted each time a reputation was reported for a banned peer, + regardless of the reputation being positive. This has led in the past to + situations where it was hard to identify the actual reason of the ban and + caused noise for node operators. + + The `Banned, disconnecting.` warning is logged only when the peer is banned. + Other misbehaves are logged as `Misbehaved during the ban threshold`. + +crates: + - name: sc-network + bump: patch diff --git a/prdoc/1.16.0/pr_5410.prdoc b/prdoc/1.16.0/pr_5410.prdoc new file mode 100644 index 000000000000..d0a32bec7423 --- /dev/null +++ b/prdoc/1.16.0/pr_5410.prdoc @@ -0,0 +1,11 @@ +title: Reactive syncing metrics + +doc: + - audience: Node Dev + description: | + Syncing metrics are now updated immediate as changes happen rather than every 1100ms as it was happening before. + This resulted in minor, but breaking API changes. + +crates: + - name: sc-network-sync + bump: major diff --git a/prdoc/1.16.0/pr_5411.prdoc b/prdoc/1.16.0/pr_5411.prdoc new file mode 100644 index 000000000000..c24001d77bda --- /dev/null +++ b/prdoc/1.16.0/pr_5411.prdoc @@ -0,0 +1,3 @@ +crates: + - name: polkadot-approval-distribution + bump: none diff --git a/prdoc/1.16.0/pr_5424.prdoc b/prdoc/1.16.0/pr_5424.prdoc new file mode 100644 index 000000000000..a94bf7aaeba2 --- /dev/null +++ b/prdoc/1.16.0/pr_5424.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: Suppress the log output for transaction propagation when no transactions are present + +doc: + - audience: Node Dev + description: | + Previously, the log message `Propagating transactions` would always be printed, even when there were no transactions to propagate. This patch optimizes the logging by returning early when no transactions are present, resulting in cleaner and more relevant log output. + +crates: +- name: sc-network-transactions + bump: none diff --git a/prdoc/1.16.0/pr_5430.prdoc b/prdoc/1.16.0/pr_5430.prdoc new file mode 100644 index 000000000000..83d6d81e252e --- /dev/null +++ b/prdoc/1.16.0/pr_5430.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: "pallet-collator-selection: correctly register weight in `new_session`" + +doc: + - audience: Runtime Dev + description: | + - Fixes an incorrect usage of the `WeightInfo` trait for `new_session`. + +crates: + - name: pallet-collator-selection + bump: patch diff --git a/prdoc/1.16.0/pr_5431.prdoc b/prdoc/1.16.0/pr_5431.prdoc new file mode 100644 index 000000000000..9f6db7136a58 --- /dev/null +++ b/prdoc/1.16.0/pr_5431.prdoc @@ -0,0 +1,20 @@ +title: Remove the need to wait for target block header in warp sync implementation + +doc: + - audience: Node Dev + description: | + Previously warp sync needed to wait for target block header of the relay chain to become available before warp + sync can start, which resulted in cumbersome APIs. Parachain initialization was refactored to initialize warp sync + with target block header from the very beginning, improving and simplifying sync API. + +crates: + - name: sc-service + bump: major + - name: sc-network-sync + bump: major + - name: polkadot-service + bump: major + - name: cumulus-client-service + bump: major + - name: sc-informant + bump: major diff --git a/prdoc/1.16.0/pr_5436.prdoc b/prdoc/1.16.0/pr_5436.prdoc new file mode 100644 index 000000000000..ea624b7bc32d --- /dev/null +++ b/prdoc/1.16.0/pr_5436.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 Coretime Chain genesis chain-spec + +doc: + - audience: Node Operator + description: | + The Polkadot Coretime Chain can now be run as all other system parachains without specifying a + chain-spec. However this will soon be deprecated and `--chain ./chain-spec.json` should continue + to be used instead. + + - audience: Runtime User + description: | + The Polkadot Coretime Chain chain-specs 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 \ No newline at end of file diff --git a/prdoc/1.16.0/pr_5439.prdoc b/prdoc/1.16.0/pr_5439.prdoc new file mode 100644 index 000000000000..00fa48de0e25 --- /dev/null +++ b/prdoc/1.16.0/pr_5439.prdoc @@ -0,0 +1,16 @@ +title: "Deprecated calls removed in cumulus parachain system pallet" + +doc: + - audience: [Runtime Dev, Runtime User] + description: | + Call `authorize_upgrade` in parachain system pallet `cumulus-pallet-parachain-system` has + been removed, use `authorize_upgrade` or `authorize_upgrade_without_checks` calls in system + pallet `frame-system` instead. + Call `enact_authorized_upgrade` in parachain system pallet `cumulus-pallet-parachain-system` + has been removed, use `apply_authorized_upgrade` call in system pallet `frame-system` instead. + +crates: + - name: cumulus-pallet-parachain-system + bump: major + - name: cumulus-pallet-xcmp-queue + bump: none diff --git a/prdoc/1.16.0/pr_5442.prdoc b/prdoc/1.16.0/pr_5442.prdoc new file mode 100644 index 000000000000..6adc34d71ad3 --- /dev/null +++ b/prdoc/1.16.0/pr_5442.prdoc @@ -0,0 +1,10 @@ +title: Derive `Clone` on `EncodableOpaqueLeaf` + +doc: + - audience: Runtime Dev + description: | + `Clone` was derived on `EncodableOpaqueLeaf` for convenience of downstream users + +crates: + - name: sp-mmr-primitives + bump: patch diff --git a/prdoc/1.16.0/pr_5443.prdoc b/prdoc/1.16.0/pr_5443.prdoc new file mode 100644 index 000000000000..0fd396be06a2 --- /dev/null +++ b/prdoc/1.16.0/pr_5443.prdoc @@ -0,0 +1,10 @@ +crates: +- name: frame-remote-externalities + bump: patch +doc: +- audience: Runtime Dev + description: as part of https://github.com/paritytech/devops/issues/3502, try-runtime + nodes were migrated to a new provider with a new domain address. The PR fixes + all the references to try-runtime nodes on rococo, westend, kusama and polkadot + networks +title: change try-runtime rpc domains diff --git a/prdoc/1.16.0/pr_5450.prdoc b/prdoc/1.16.0/pr_5450.prdoc new file mode 100644 index 000000000000..ccd319cad246 --- /dev/null +++ b/prdoc/1.16.0/pr_5450.prdoc @@ -0,0 +1,18 @@ +title: Sync status refactoring + +doc: + - audience: Node Dev + description: | + `SyncingService` API in `sc-network-sync` has changed with some of the redundant methods related to sync status + removed that were mostly used internally or for testing purposes and is unlikely to impact external code. + `ExtendedPeerInfo` now has working `Clone` and `Copy` implementation. + +crates: + - name: sc-informant + bump: major + - name: sc-network-sync + bump: major + - name: sc-network-test + bump: major + - name: sc-service + bump: major diff --git a/prdoc/1.16.0/pr_5465.prdoc b/prdoc/1.16.0/pr_5465.prdoc new file mode 100644 index 000000000000..ae185dc250f6 --- /dev/null +++ b/prdoc/1.16.0/pr_5465.prdoc @@ -0,0 +1,10 @@ +title: try-state check invariant for nomination-pools (points >= stake) + +doc: + - audience: Runtime Dev + description: | + Adds a new try-state invariant to the nomination pools that checks that for each bonded pool, the pool's points can never be lower than its staked balance. + +crates: + - name: pallet-nomination-pools + bump: minor diff --git a/prdoc/1.16.0/pr_5466.prdoc b/prdoc/1.16.0/pr_5466.prdoc new file mode 100644 index 000000000000..57f20b3585b4 --- /dev/null +++ b/prdoc/1.16.0/pr_5466.prdoc @@ -0,0 +1,14 @@ +crates: +- bump: patch + name: frame-omni-bencher +- bump: patch + name: frame-benchmarking-cli +doc: +- audience: Runtime Dev + description: | + Changes: + - Set default level to `Info` again. Seems like a dependency update set it to something higher. + - Fix docs to not use `--locked` since we rely on dependency bumps via cargo. + - Add README with rust docs. + - Fix bug where the node ignored `--heap-pages` argument. +title: frame-omni-bencher maintenance diff --git a/prdoc/1.16.0/pr_5467.prdoc b/prdoc/1.16.0/pr_5467.prdoc new file mode 100644 index 000000000000..2634c255e168 --- /dev/null +++ b/prdoc/1.16.0/pr_5467.prdoc @@ -0,0 +1,10 @@ +title: Make PendingConfigs storage item public + +doc: + - audience: Runtime Dev + description: | + Make PendingConfigs storage item in polkadot's configuration crate public. + +crates: + - name: polkadot-runtime-parachains + bump: minor \ No newline at end of file diff --git a/prdoc/1.16.0/pr_5509.prdoc b/prdoc/1.16.0/pr_5509.prdoc new file mode 100644 index 000000000000..154146034e6f --- /dev/null +++ b/prdoc/1.16.0/pr_5509.prdoc @@ -0,0 +1,17 @@ +title: Add `pallet_proxy` to People Chain and Coretime Chain testnet runtimes. + +doc: + - audience: Runtime User + description: | + Proxies can now be used on `coretime-rococo`, `coretime-westend`, `people-rococo` and + `people-westend` in the same way as they can be on Kusama and Polkadot chains. + +crates: + - name: coretime-rococo-runtime + bump: major + - name: coretime-westend-runtime + bump: major + - name: people-rococo-runtime + bump: major + - name: people-westend-runtime + bump: major diff --git a/prdoc/1.16.0/pr_5513.prdoc b/prdoc/1.16.0/pr_5513.prdoc new file mode 100644 index 000000000000..0eda8b02cde0 --- /dev/null +++ b/prdoc/1.16.0/pr_5513.prdoc @@ -0,0 +1,10 @@ +title: Add more logs to trace AcceptanceCheckErr + +doc: + - audience: Runtime Dev + description: | + `Debug` was derived on `AcceptanceCheckErr` to print the error. This PR adds more logs to trace the error. + +crates: + - name: polkadot-runtime-parachains + bump: patch diff --git a/prdoc/1.16.0/pr_5527.prdoc b/prdoc/1.16.0/pr_5527.prdoc new file mode 100644 index 000000000000..38eb75affe44 --- /dev/null +++ b/prdoc/1.16.0/pr_5527.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: Report BestBlock events only for newBlock reports + +doc: + - audience: Node Dev + description: | + This PR ensures that the chainHead_v1_follow method of the RPC-v2 API is always + reporting a `BestBlock` event after a `NewBlock`. + There was a race condition in the chainHead follow logic which led to the `BestBlock` + event to be emitted without an associated `NewBlock` event. + +crates: + - name: sc-rpc-spec-v2 + bump: minor + diff --git a/prdoc/1.16.0/pr_5538.prdoc b/prdoc/1.16.0/pr_5538.prdoc new file mode 100644 index 000000000000..5924f9789040 --- /dev/null +++ b/prdoc/1.16.0/pr_5538.prdoc @@ -0,0 +1,11 @@ +title: "collator-protocol: Remove race condition" + +doc: + - audience: Node Dev + description: | + Remove a race condition in the collator protocol that could lead + to collations not being announced to a validator. + +crates: + - name: polkadot-collator-protocol + bump: patch diff --git a/prdoc/1.16.0/pr_5546.prdoc b/prdoc/1.16.0/pr_5546.prdoc new file mode 100644 index 000000000000..95f02dbe13b2 --- /dev/null +++ b/prdoc/1.16.0/pr_5546.prdoc @@ -0,0 +1,36 @@ +title: "Transfer polkadot native assets to Ethereum through snowbridge" + +doc: + - audience: Runtime Dev + description: | + Transfer polkadot native asset to Ethereum through snowbridge. + +crates: + - name: snowbridge-pallet-inbound-queue + bump: patch + - name: snowbridge-pallet-inbound-queue + bump: patch + - name: snowbridge-pallet-outbound-queue + bump: patch + - name: snowbridge-pallet-system + bump: minor + validate: false + - name: snowbridge-core + bump: minor + validate: false + - name: snowbridge-router-primitives + bump: minor + validate: false + - name: bridge-hub-westend-runtime + bump: patch + - name: bridge-hub-rococo-runtime + bump: patch + - name: bridge-hub-westend-emulated-chain + bump: patch + - name: bridge-hub-westend-integration-tests + bump: minor + - name: asset-hub-westend-emulated-chain + bump: patch + - name: emulated-integration-tests-common + bump: patch + diff --git a/prdoc/1.16.0/pr_5563.prdoc b/prdoc/1.16.0/pr_5563.prdoc new file mode 100644 index 000000000000..cbf436125bb5 --- /dev/null +++ b/prdoc/1.16.0/pr_5563.prdoc @@ -0,0 +1,14 @@ +title: "snowbridge: improve destination fee handling to avoid trapping fees dust" + +doc: + - audience: Runtime User + description: | + On Ethereum -> Polkadot Asset Hub messages, whether they are a token transfer + or a `Transact` for registering a new token, any unspent fees are deposited to + Snowbridge's sovereign account on Asset Hub, rather than trapped in AH's asset trap. + +crates: + - name: snowbridge-router-primitives + bump: patch + - name: snowbridge-pallet-inbound-queue + bump: patch diff --git a/prdoc/1.16.0/pr_5580.prdoc b/prdoc/1.16.0/pr_5580.prdoc new file mode 100644 index 000000000000..e03b946070aa --- /dev/null +++ b/prdoc/1.16.0/pr_5580.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: Fix error message on pallet macro + +doc: + - audience: Runtime Dev + description: | + Improve error message for pallet macro generated code. + +crates: + - name: frame-support-procedural + bump: patch diff --git a/prdoc/1.16.0/pr_5581.prdoc b/prdoc/1.16.0/pr_5581.prdoc new file mode 100644 index 000000000000..e33690939d8b --- /dev/null +++ b/prdoc/1.16.0/pr_5581.prdoc @@ -0,0 +1,30 @@ +# 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: Clear other messages before dry-running + +doc: + - audience: Runtime Dev + description: | + The DryRunApi.dry_run_call and DryRunApi.dry_run_xcm functions used to populate + `forwarded_xcms` with all the existing messages in the queues at the time. + Now, existing (irrelevant) messages are cleared when dry-running, meaning only the + messages produced by the dry-run call (or xcm) will be returned in `forwarded_xcms`. + +crates: + - name: pallet-xcm + bump: minor + - name: staging-xcm-builder + bump: major + - name: pallet-xcm-bridge-hub-router + bump: minor + - name: cumulus-pallet-parachain-system + bump: minor + - name: cumulus-pallet-xcmp-queue + bump: minor + - name: cumulus-primitives-utility + bump: minor + - name: polkadot-runtime-common + bump: minor + - name: pallet-xcm-bridge-hub + bump: minor diff --git a/prdoc/1.16.0/pr_5594.prdoc b/prdoc/1.16.0/pr_5594.prdoc new file mode 100644 index 000000000000..dbdc7937b73d --- /dev/null +++ b/prdoc/1.16.0/pr_5594.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: "Add debugging info for `StorageWeightReclaim`" + +doc: + - audience: Runtime Dev + description: | + - Includes extrinsic index to be displayed in the logs when the consumed weight is higher than the measured one. + +crates: + - name: cumulus-primitives-storage-weight-reclaim + bump: patch diff --git a/prdoc/1.16.0/pr_5632.prdoc b/prdoc/1.16.0/pr_5632.prdoc new file mode 100644 index 000000000000..f76428bbc8f6 --- /dev/null +++ b/prdoc/1.16.0/pr_5632.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: Fix `alloc` not found error in `format_runtime_string!` + +doc: + - audience: Runtime Dev + description: | + Fixes the macro hygiene in the `format_runtime_string!` macro to fix the `alloc` not found build error. + +crates: + - name: sp-runtime + bump: patch diff --git a/prdoc/1.16.0/pr_5644.prdoc b/prdoc/1.16.0/pr_5644.prdoc new file mode 100644 index 000000000000..3300d557fce4 --- /dev/null +++ b/prdoc/1.16.0/pr_5644.prdoc @@ -0,0 +1,8 @@ +title: 'pallet-utility: Improve weight annotations' +doc: +- audience: Runtime Dev + description: |- + Prevent allocations when calculating the weights. +crates: +- name: pallet-utility + bump: patch diff --git a/prdoc/1.16.0/pr_5649.prdoc b/prdoc/1.16.0/pr_5649.prdoc new file mode 100644 index 000000000000..1f4c97aa1753 --- /dev/null +++ b/prdoc/1.16.0/pr_5649.prdoc @@ -0,0 +1,49 @@ +title: "Bridges lane id agnostic for backwards compatibility" + +doc: +- audience: Runtime Dev + description: | + This PR improves support for handling `LaneId` backwards compatibility with the previously merged [PR](https://github.com/paritytech/polkadot-sdk/pull/4949). + If `pallet_bridge_messages` or `pallet_bridge_relayers` used `LaneId([u8; 4])` previously, they should now set `type LaneId = LegacyLaneId;`. + +crates: +- name: bridge-runtime-common + bump: patch +- name: bp-runtime + bump: patch +- name: staging-xcm-executor + bump: none +- name: parachains-runtimes-test-utils + bump: patch +- name: bp-messages + bump: major +- name: bp-relayers + bump: major +- name: bp-xcm-bridge-hub + bump: major +- name: pallet-bridge-messages + bump: patch +- name: pallet-bridge-relayers + bump: patch +- name: pallet-xcm-bridge-hub + bump: major +- name: emulated-integration-tests-common + bump: patch +- name: bp-bridge-hub-kusama + bump: patch +- name: bp-bridge-hub-polkadot + bump: patch +- name: bp-bridge-hub-rococo + bump: patch +- name: bp-bridge-hub-westend + bump: patch +- name: bp-polkadot-bulletin + bump: patch +- name: bridge-hub-rococo-runtime + bump: major +- name: bridge-hub-westend-runtime + bump: patch +- name: polkadot-parachain-bin + bump: none +- name: bridge-hub-test-utils + bump: major diff --git a/prdoc/1.16.0/pr_5655.prdoc b/prdoc/1.16.0/pr_5655.prdoc new file mode 100644 index 000000000000..bfa2e295d157 --- /dev/null +++ b/prdoc/1.16.0/pr_5655.prdoc @@ -0,0 +1,15 @@ +title: '[benchmarking] Reset to genesis storage after each run' +doc: +- audience: Runtime Dev + description: |- + The genesis state is currently partially provided via `OverlayedChanges`, but these changes are reset by the runtime after the first repetition, causing the second repitition to use an invalid genesis state. + + Changes: + - Provide the genesis state as a `Storage` without any `OverlayedChanges` to make it work correctly with repetitions. + - Add `--genesis-builder-preset` option to use different genesis preset names. + - Improve error messages. +crates: +- name: frame-benchmarking-cli + bump: major +- name: frame-benchmarking-pallet-pov + bump: patch diff --git a/prdoc/1.16.0/pr_5660.prdoc b/prdoc/1.16.0/pr_5660.prdoc new file mode 100644 index 000000000000..fce791cebb65 --- /dev/null +++ b/prdoc/1.16.0/pr_5660.prdoc @@ -0,0 +1,30 @@ +# 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: validate destinations for ReserveWithdraw and Teleport transfers" + +doc: + - audience: + - Runtime User + - Runtime Dev + description: | + This change adds the required validation for stronger UX guarantees when using + `InitiateReserveWithdraw` or `InitiateTeleport` XCM instructions. Execution of + the instructions will fail if the local chain is not configured to trust the + "destination" or "reserve" chain as a reserve/trusted-teleporter for the provided + "assets". + With this change, misuse of `InitiateReserveWithdraw`/`InitiateTeleport` fails on + origin with no overall side-effects, rather than failing on destination (with + side-effects to origin's assets issuance). + The commit also makes the same validations for pallet-xcm transfers, and adds + regression tests. + +crates: + - name: staging-xcm-executor + bump: patch + - name: staging-xcm-builder + bump: patch + - name: pallet-xcm + bump: patch + - name: xcm-simulator-example + bump: patch diff --git a/prdoc/1.16.0/pr_5671.prdoc b/prdoc/1.16.0/pr_5671.prdoc new file mode 100644 index 000000000000..364165ec820e --- /dev/null +++ b/prdoc/1.16.0/pr_5671.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: Snowbridge free consensus updates border condition fix + +doc: + - audience: Runtime Dev + description: | + A fix for a border condition introduced with the Ethereum client free consensus updates. A malicious relayer could + spam the Ethereum client with sync committee updates that have already been imported for the period. This PR adds + a storage item to track the last imported sync committee period, so that subsequent irrelevant updates are not free. + No impact for users or relayers, since the feature introducing the border condition has not been released. + +crates: + - name: snowbridge-pallet-ethereum-client + bump: patch diff --git a/prdoc/1.16.0/pr_5678.prdoc b/prdoc/1.16.0/pr_5678.prdoc new file mode 100644 index 000000000000..ebb5e5a0d79f --- /dev/null +++ b/prdoc/1.16.0/pr_5678.prdoc @@ -0,0 +1,14 @@ +title: 'rpc server: fix deny unsafe on RpcMethods::Auto' +doc: +- audience: Node Operator + description: |- + Close #5677 + + I made a nit when I moved this code: https://github.com/paritytech/polkadot-sdk/blob/v1.14.0-rc1/substrate/client/service/src/lib.rs#L379-#L385 in https://github.com/paritytech/polkadot-sdk/pull/4792 + + Thus: + - (ip.is_loopback(), RpcMethods::Auto) -> allow unsafe + - (!ip.is_loopback(), RpcMethods::Auto) -> deny unsafe +crates: +- name: sc-rpc-server + bump: patch diff --git a/prdoc/1.16.0/pr_5688.prdoc b/prdoc/1.16.0/pr_5688.prdoc new file mode 100644 index 000000000000..88e712fcba68 --- /dev/null +++ b/prdoc/1.16.0/pr_5688.prdoc @@ -0,0 +1,10 @@ +title: "Fix `paras_inherent` benchmark" + +doc: + - audience: Runtime Dev + description: | + Fixes the benchmark for relay chains like rococo-dev with `max_validators_per_core` value lower than 2. + +crates: +- name: polkadot-runtime-parachains + bump: patch diff --git a/prdoc/1.16.0/pr_5695.prdoc b/prdoc/1.16.0/pr_5695.prdoc new file mode 100644 index 000000000000..202eafa26ebd --- /dev/null +++ b/prdoc/1.16.0/pr_5695.prdoc @@ -0,0 +1,15 @@ +title: 'pallet-migrations: fix index access for singluar migrations' +doc: +- audience: Runtime Dev + description: |- + Discovered a bug in the migrations pallet while debugging https://github.com/paritytech/try-runtime-cli/pull/90. + It only occurs when a single MBM is configured - hence it did not happen when Ajuna Network tried it... + + Changes: + - Check len of the tuple before accessing its nth_id + - Make nth_id return `None` on unary tuples and n>0 +crates: +- name: pallet-migrations + bump: patch +- name: frame-support + bump: patch diff --git a/prdoc/1.16.0/pr_5712.prdoc b/prdoc/1.16.0/pr_5712.prdoc new file mode 100644 index 000000000000..321ed12f3135 --- /dev/null +++ b/prdoc/1.16.0/pr_5712.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: Better logs for XCM emulator + +doc: + - audience: Runtime Dev + description: | + Now the XCM emulator has a log every time `execute_with` is called, to know + which chain is being used. + Also, the logs for UMP, DMP, HRMP processing were included in the `xcm` log filter + and changed from showing the message as an array of bytes to a hex string. + This means running the tests with `RUST_LOG=xcm` should give you everything you need, + you can always filter by `RUST_LOG=xcm::hrmp` or any other if you need it. + +crates: + - name: xcm-emulator + bump: patch diff --git a/prdoc/1.16.0/pr_5713.prdoc b/prdoc/1.16.0/pr_5713.prdoc new file mode 100644 index 000000000000..54d3619cdcaf --- /dev/null +++ b/prdoc/1.16.0/pr_5713.prdoc @@ -0,0 +1,10 @@ +title: "pallet-treasury: Improve `remove_approval` benchmark" + +doc: + - audience: Runtime Dev + description: | + Fix the `remove_approval` benchmark when `SpendOrigin` doesn't return any `succesful_origin`. + +crates: + - name: pallet-treasury + bump: patch diff --git a/prdoc/1.16.0/pr_5747.prdoc b/prdoc/1.16.0/pr_5747.prdoc new file mode 100644 index 000000000000..ee786db658c8 --- /dev/null +++ b/prdoc/1.16.0/pr_5747.prdoc @@ -0,0 +1,13 @@ +title: "Snowbridge runtime migration on Westend" + +doc: + - audience: Runtime Dev + description: | + This is a backport for https://github.com/paritytech/polkadot-sdk/pull/5074 which missed + the runtime migration to initialize channels of the bridge. + +crates: + - name: bridge-hub-westend-runtime + bump: patch + + diff --git a/prdoc/1.16.1/pr_4803.prdoc b/prdoc/1.16.1/pr_4803.prdoc new file mode 100644 index 000000000000..0d2ad08d610f --- /dev/null +++ b/prdoc/1.16.1/pr_4803.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: Fix for issue #4762 + +doc: + - audience: Runtime Dev + description: | + When the status of the queue is on_initialize, throw a defensive message and return weight of 0, + however when status is on_idle, do not throw a defensive message, only return weight of 0 + +crates: + - name: pallet-message-queue + bump: patch diff --git a/prdoc/1.16.1/pr_5599.prdoc b/prdoc/1.16.1/pr_5599.prdoc new file mode 100644 index 000000000000..990d2bb4e18f --- /dev/null +++ b/prdoc/1.16.1/pr_5599.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: Add assets in pool with native to query_acceptable_payment_assets + +doc: + - audience: Runtime Dev + description: | + The `XcmPaymentApi::query_acceptable_payment_assets` API can be used to get a list of all + the assets that can be used for fee payment. + This is usually just the native asset, but the asset hubs have the asset conversion pallet. + In the case of the asset hubs, this list now includes all assets in a liquidity pool with + the native one. + +crates: + - name: asset-hub-rococo-runtime + bump: minor + - name: asset-hub-westend-runtime + bump: minor diff --git a/prdoc/1.16.1/pr_5753.prdoc b/prdoc/1.16.1/pr_5753.prdoc new file mode 100644 index 000000000000..dca181ff5c40 --- /dev/null +++ b/prdoc/1.16.1/pr_5753.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: Use maximum allowed response size for request/response protocols + +doc: + - audience: Node Dev + description: | + Increase maximum PoV response size to 16MB which is equal to the default value used in the substrate. + +crates: + - name: sc-network + bump: patch + - name: sc-network-light + bump: patch + - name: sc-network-sync + bump: patch + - name: polkadot-node-network-protocol + bump: patch + - name: sc-network-transactions + bump: patch diff --git a/prdoc/1.16.1/pr_5887.prdoc b/prdoc/1.16.1/pr_5887.prdoc new file mode 100644 index 000000000000..3ee6ac05a11a --- /dev/null +++ b/prdoc/1.16.1/pr_5887.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: "Set reasonable hard limit for PoV size config value" + +doc: + - audience: + - Runtime Dev + - Runtime User + description: | + Sets the hard limit of the `max_pov_size` host configuration parameter to correspond to the + actual network-related limit rather than to a random constant. + +crates: + - name: polkadot-runtime-parachains + bump: patch + diff --git a/prdoc/1.16.1/pr_5913.prdoc b/prdoc/1.16.1/pr_5913.prdoc new file mode 100644 index 000000000000..f50cd722c714 --- /dev/null +++ b/prdoc/1.16.1/pr_5913.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: Remove redundant XCMs from dry run's forwarded xcms + +doc: + - audience: Runtime User + description: | + The DryRunApi was returning the same message repeated multiple times in the + `forwarded_xcms` field. This is no longer the case. + +crates: + - name: pallet-xcm-bridge-hub-router + bump: patch + - name: cumulus-pallet-parachain-system + bump: patch + - name: staging-xcm-builder + bump: patch + - name: emulated-integration-tests-common + bump: minor diff --git a/prdoc/1.16.1/pr_6031.prdoc b/prdoc/1.16.1/pr_6031.prdoc new file mode 100644 index 000000000000..702d0c12fa06 --- /dev/null +++ b/prdoc/1.16.1/pr_6031.prdoc @@ -0,0 +1,10 @@ +title: "Import vec to bridges/primitives/header-chain" + +doc: + - audience: Runtime Dev + description: | + Add the `vec` dependency to these files to resolve compiler errors. + +crates: + - name: bp-header-chain + bump: patch diff --git a/prdoc/1.9.0/pr_1378.prdoc b/prdoc/1.9.0/pr_1378.prdoc index 6533dcb66303..03427cdba99d 100644 --- a/prdoc/1.9.0/pr_1378.prdoc +++ b/prdoc/1.9.0/pr_1378.prdoc @@ -10,7 +10,7 @@ doc: 3. `#[runtime::pallet_index]` must be attached to a pallet to define its index 4. `#[runtime::disable_call]` can be optionally attached to a pallet to disable its calls 5. `#[runtime::disable_unsigned]` can be optionally attached to a pallet to disable unsigned calls - 6. A pallet instance can be defined as `TemplateModule: pallet_template` + 6. A pallet instance can be defined as `Template: pallet_template` An optional attribute can be defined as `#[frame_support::runtime(legacy_ordering)]` to ensure that the order of hooks is same as the order of pallets (and not based on the pallet_index). This is to support legacy runtimes and should be avoided for new ones. diff --git a/prdoc/pr_3151.prdoc b/prdoc/pr_3151.prdoc new file mode 100644 index 000000000000..5e43b86a9753 --- /dev/null +++ b/prdoc/pr_3151.prdoc @@ -0,0 +1,49 @@ +# 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: Dynamic deposit based on number of proposals + +doc: + - audience: + - Runtime User + - Runtime Dev + description: | + Introduce a dynamic proposal deposit mechanism influenced by the total number of active + proposals, with the option to set the deposit to none. + + The potential cost (e.g., balance hold) for proposal submission and storage is determined + by the implementation of the `Consideration` trait. The footprint is defined as `proposal_count`, + representing the total number of active proposals in the system, excluding the one currently + being proposed. This cost may vary based on the proposal count. The pallet also offers various + types to define a cost strategy based on the number of proposals. + + Two new calls are introduced: + - kill(origin, proposal_hash): the cancellation of a proposal, accompanied by the burning + of the associated cost/consideration ticket. + - release_proposal_cost(origin, proposal_hash): the release of the cost for a non-active proposal. + + New config parameters: + - DisapproveOrigin: origin from which a proposal in any status may be disapproved without + associated cost for a proposer; + - KillOrigin: Origin from which any malicious proposal may be killed with associated cost + for a proposer; + - Consideration: mechanism to assess the necessity of some cost for publishing and storing + a proposal. Set to unit type to have not submission cost; + + Additionally change: + - benchmarks have been upgraded to benchmarks::v2 for collective pallet; + - `ensure_successful` function added to the `Consideration` under `runtime-benchmarks` feature. + +crates: + - name: pallet-collective + bump: major + - name: collectives-westend-runtime + bump: major + - name: kitchensink-runtime + bump: major + - name: pallet-alliance + bump: patch + - name: pallet-balances + bump: patch + - name: pallet-utility + bump: patch diff --git a/prdoc/pr_3685.prdoc b/prdoc/pr_3685.prdoc new file mode 100644 index 000000000000..bd414c93a6fe --- /dev/null +++ b/prdoc/pr_3685.prdoc @@ -0,0 +1,300 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: FRAME Reintroduce `TransactionExtension` as a replacement for `SignedExtension` + +doc: + - audience: [Runtime Dev, Runtime User, Node Operator, Node Dev] + description: | + Introduces a new trait `TransactionExtension` to replace `SignedExtension`. Introduce the + idea of transactions which obey the runtime's extensions and have according Extension data + (né Extra data) yet do not have hard-coded signatures. + + Deprecate the terminology of "Unsigned" when used for transactions/extrinsics owing to there + now being "proper" unsigned transactions which obey the extension framework and "old-style" + unsigned which do not. Instead we have `General` for the former and `Bare` for the latter. + Unsigned will be phased out as a type of transaction, and `Bare` will only be used for + Inherents. + + Types of extrinsic are now therefore + - Bare (no hardcoded signature, no Extra data; used to be known as "Unsigned") + - Bare transactions (deprecated) - Gossiped, validated with `ValidateUnsigned` + (deprecated) and the `_bare_compat` bits of `TransactionExtension` (deprecated). + - Inherents - Not gossiped, validated with `ProvideInherent`. + - Extended (Extra data) - Gossiped, validated via `TransactionExtension`. + - Signed transactions (with a hardcoded signature). + - General transactions (without a hardcoded signature). + + Notable information on `TransactionExtension` and the differences from `SignedExtension` + - `AdditionalSigned`/`additional_signed` is renamed to `Implicit`/`implicit`. It is encoded + for the entire transaction and passed in to each extension as a new argument to validate. + - `pre_dispatch` is renamed to `prepare`. + - `validate` runs transaction validation logic both off-chain and on-chain, and is + non-mutating. + - `prepare` runs on-chain pre-execution logic using information extracted during validation + and is mutating. + - `validate` and `prepare` are now passed an `Origin` rather than an `AccountId`. If the + extension logic presumes an `AccountId`, consider using the trait function + `AsSystemOriginSigner::as_system_origin_signer`. + - A signature on the underlying transaction may validly not be present. + - The origin may be altered during validation. + - Validation functionality present in `validate` should not be repeated in `prepare`. + Useful information obtained during `validate` should now be passed in to `prepare` using + the new user-specifiable type `Val`. + - Unsigned logic should be temporarily migrated from the old `*_unsigned` functions into the + regular versions of the new functions where the `Origin` is `None`, until the deprecation + of `ValidateUnsigned` in phase 2 of Extrinsic Horizon. + - The `Call` type defining the runtime call is now a type parameter. + - Extensions now track the weight they consume during validation, preparation and + post-dispatch through the `TransactionExtensionBase::weight` function. + - `TestXt` was removed and its usage in tests was replaced with `UncheckedExtrinsic` + instances. + + To fix the build issues introduced by this change, use the `AsTransactionExtension` adapter + to wrap existing `SignedExtension`s by converting them using the `From` + generic implementation for `AsTransactionExtension`. More details on migrating existing + `SignedExtension` implementations to `TransactionExtension` in the PR description. + +crates: + - name: bridge-runtime-common + bump: major + - name: bp-bridge-hub-cumulus + bump: major + - name: bp-bridge-hub-rococo + bump: major + - name: bp-bridge-hub-westend + bump: major + - name: bp-kusama + bump: major + - name: bp-polkadot-bulletin + bump: major + - name: bp-polkadot + bump: major + - name: bp-rococo + bump: major + - name: bp-westend + bump: major + - name: pallet-bridge-relayers + bump: major + - name: bp-polkadot-core + bump: major + - name: bp-relayers + bump: major + - name: bp-runtime + bump: major + - name: substrate-relay-helper + bump: major + - name: snowbridge-pallet-ethereum-client + bump: major + - name: snowbridge-pallet-inbound-queue + bump: major + - name: snowbridge-pallet-outbound-queue + bump: major + - name: snowbridge-pallet-system + bump: major + - name: snowbridge-runtime-test-common + bump: major + - name: parachain-template-runtime + bump: major + - name: cumulus-pallet-parachain-system + bump: major + - name: asset-hub-rococo-runtime + bump: major + - name: asset-hub-westend-runtime + bump: major + - name: bridge-hub-rococo-runtime + bump: major + - name: bridge-hub-westend-runtime + bump: major + - name: collectives-westend-runtime + bump: major + - name: contracts-rococo-runtime + bump: major + - name: coretime-rococo-runtime + bump: major + - name: coretime-westend-runtime + bump: major + - name: glutton-westend-runtime + bump: major + - name: people-rococo-runtime + bump: major + - name: people-westend-runtime + bump: major + - name: parachains-runtimes-test-utils + bump: major + - name: penpal-runtime + bump: major + - name: rococo-parachain-runtime + bump: major + - name: polkadot-omni-node + bump: major + - name: polkadot-parachain-bin + bump: major + - name: cumulus-primitives-storage-weight-reclaim + bump: major + - name: cumulus-test-client + bump: major + - name: cumulus-test-runtime + bump: major + - name: cumulus-test-service + bump: major + - name: polkadot-sdk-docs + bump: major + - name: polkadot-service + bump: major + - name: polkadot-test-service + bump: major + - name: polkadot-runtime-common + bump: major + - name: polkadot-runtime-parachains + bump: major + - name: rococo-runtime + bump: major + - name: polkadot-test-runtime + bump: major + - name: westend-runtime + bump: major + - name: pallet-xcm-benchmarks + bump: major + - name: pallet-xcm + bump: major + - name: staging-xcm-builder + bump: major + - name: staging-xcm-executor + bump: major + - name: xcm-runtime-apis + bump: major + - name: xcm-simulator + bump: major + - name: minimal-template-runtime + bump: major + - name: minimal-template-node + bump: major + - name: solochain-template-runtime + bump: major + - name: staging-node-cli + bump: major + - name: kitchensink-runtime + bump: major + - name: node-testing + bump: major + - name: sc-client-api + bump: major + - name: sc-client-db + bump: major + - name: sc-network-gossip + bump: major + - name: sc-network-sync + bump: major + - name: sc-transaction-pool + bump: major + - name: polkadot-sdk-frame + bump: major + - name: pallet-alliance + bump: major + - name: pallet-assets + bump: major + - name: pallet-asset-conversion + bump: major + - name: pallet-babe + bump: major + - name: pallet-balances + bump: major + - name: pallet-beefy + bump: major + - name: pallet-collective + bump: major + - name: pallet-contracts + bump: major + - name: pallet-election-provider-multi-phase + bump: major + - name: pallet-elections-phragmen + bump: major + - name: pallet-example-basic + bump: major + - name: pallet-example-tasks + bump: major + - name: pallet-example-offchain-worker + bump: major + - name: pallet-examples + bump: major + - name: frame-executive + bump: major + - name: pallet-grandpa + bump: major + - name: pallet-im-online + bump: major + - name: pallet-lottery + bump: major + - name: frame-metadata-hash-extension + bump: major + - name: pallet-mixnet + bump: major + - name: pallet-multisig + bump: major + - name: pallet-offences + bump: major + - name: pallet-proxy + bump: major + - name: pallet-recovery + bump: major + - name: pallet-revive + bump: major + - name: pallet-sassafras + bump: major + - name: pallet-scheduler + bump: major + - name: pallet-state-trie-migration + bump: major + - name: pallet-sudo + bump: major + - name: frame-support-procedural + bump: major + - name: frame-support + bump: major + - name: frame-support-test + bump: major + - name: frame-system + bump: major + - name: frame-system-benchmarking + bump: major + - name: pallet-transaction-payment + bump: major + - name: pallet-asset-conversion-tx-payment + bump: major + - name: pallet-asset-tx-payment + bump: major + - name: pallet-skip-feeless-payment + bump: major + - name: pallet-utility + bump: major + - name: pallet-whitelist + bump: major + - name: sp-inherents + bump: major + - name: sp-metadata-ir + bump: major + - name: sp-runtime + bump: major + - name: sp-storage + bump: major + - name: sp-test-primitives + bump: major + - name: substrate-test-runtime + bump: major + - name: substrate-test-utils + bump: major + - name: frame-benchmarking-cli + bump: major + - name: frame-remote-externalities + bump: major + - name: substrate-rpc-client + bump: major + - name: minimal-template-runtime + bump: major + - name: parachain-template-runtime + bump: major + - name: solochain-template-node + bump: major + - name: polkadot-sdk + bump: major diff --git a/prdoc/pr_3881.prdoc b/prdoc/pr_3881.prdoc new file mode 100644 index 000000000000..4cf6425e73a5 --- /dev/null +++ b/prdoc/pr_3881.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: Introduce a Generic Proving Trie + +doc: + - audience: Runtime Dev + description: | + This PR introduces a Proving Trie object which can be used inside the runtime. This can allow + for things like airdrops where a single hash is stored on chain representing the whole airdrop + and individuals present a proof of their inclusion in the airdrop. + +crates: + - name: sp-runtime + bump: major diff --git a/prdoc/pr_4251.prdoc b/prdoc/pr_4251.prdoc new file mode 100644 index 000000000000..4d4fcd734692 --- /dev/null +++ b/prdoc/pr_4251.prdoc @@ -0,0 +1,79 @@ +title: MBM `try-runtime` support +doc: +- audience: Runtime Dev + description: | + # MBM try-runtime support + + This MR adds support to the try-runtime + trait such that the try-runtime-CLI will be able to support MBM testing [here](https://github.com/paritytech/try-runtime-cli/pull/90). + It mainly adds two feature-gated hooks to the `SteppedMigration` hook to facilitate + testing. These hooks are named `pre_upgrade` and `post_upgrade` and have the + same signature and implications as for single-block migrations. + + ## Integration + + To make use of this in your Multi-Block-Migration, just implement the two new hooks and test pre- and post-conditions in them: + + ```rust + #[cfg(feature = "try-runtime")] + fn pre_upgrade() -> Result, frame_support::sp_runtime::TryRuntimeError> + { + // ... + } + + #[cfg(feature = "try-runtime")] + fn post_upgrade(prev: Vec) -> Result<(), frame_support::sp_runtime::TryRuntimeError> { + // ... + } + ``` + + You may return an error or panic in these functions to indicate failure. + This will then show up in the try-runtime-CLI and can be used in CI for testing. + + + Changes: + - Adds `try-runtime` gated methods `pre_upgrade` and `post_upgrade` + on `SteppedMigration` + - Adds `try-runtime` gated methods `nth_pre_upgrade` + and `nth_post_upgrade` on `SteppedMigrations` + - Modifies `pallet_migrations` + implementation to run pre_upgrade and post_upgrade steps at the appropriate times, and panic in the event of migration failure. +crates: +- 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: polkadot-parachain-bin + bump: minor +- name: rococo-runtime + bump: minor +- name: westend-runtime + bump: minor +- name: frame-executive + bump: minor +- name: pallet-migrations + bump: minor +- name: frame-support + bump: minor +- name: frame-system + bump: minor +- name: frame-try-runtime + bump: minor diff --git a/prdoc/pr_4257.prdoc b/prdoc/pr_4257.prdoc new file mode 100644 index 000000000000..860b85a4888e --- /dev/null +++ b/prdoc/pr_4257.prdoc @@ -0,0 +1,76 @@ +# 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 `state_version` in `RuntimeVersion` to `system_version`. + +doc: + - audience: Runtime Dev + description: | + This PR renames `state_version` in `RuntimeVersion` to `system_version`. `system_version=2` signifies + that extrinsic root derivation uses `StateVersion::V1`. + + - audience: Runtime User + description: | + `RuntimeVersion`'s `state_version` is renamed to `system_version`. Applications using that type and its field + must update their code to reflect the changes. For easier migration serde serialization produces both new + `systemVersion` and old `stateVersion` fields and deserialization supports `stateVersion` as an alias as too. + +crates: + - name: frame-system + bump: major + - name: sp-api + bump: none + - name: sp-version + bump: major + - name: sp-storage + bump: minor + - name: sp-version-proc-macro + bump: minor + - name: sc-block-builder + bump: major + - name: sc-executor + bump: major + - name: sc-rpc + bump: none + - name: sc-rpc-spec-v2 + bump: none + - name: cumulus-pallet-parachain-system + bump: none + - name: cumulus-client-pov-recovery + bump: none + - name: cumulus-client-network + bump: none + - name: rococo-runtime + bump: major + - name: westend-runtime + bump: major + - name: asset-hub-rococo-runtime + bump: major + - name: asset-hub-westend-runtime + bump: major + - name: bridge-hub-rococo-runtime + bump: major + - name: bridge-hub-westend-runtime + bump: major + - name: collectives-westend-runtime + bump: major + - name: coretime-rococo-runtime + bump: major + - name: coretime-westend-runtime + bump: major + - name: people-rococo-runtime + bump: major + - name: people-westend-runtime + bump: major + - name: penpal-runtime + bump: major + - name: contracts-rococo-runtime + bump: major + - name: glutton-westend-runtime + bump: major + - name: seedling-runtime + bump: major + - name: shell-runtime + bump: major + - name: rococo-parachain-runtime + bump: major diff --git a/prdoc/pr_4639.prdoc b/prdoc/pr_4639.prdoc new file mode 100644 index 000000000000..dfdd60f2bdb2 --- /dev/null +++ b/prdoc/pr_4639.prdoc @@ -0,0 +1,69 @@ +title: "Added the fork-aware transaction pool implementation" + +doc: + - audience: Node Dev + description: | + Most important changes introduced by this PR: + - The transaction pool references spread across codebase are now wrapper to a transaction pool trait object, + - The fork-aware pool implementation was added. + - The `sc-transaction-pool` refactored, + - Trasnaction pool builder was introduced to allow to instantiation of either old or new transaction pool. Refer to PR description for + more details on how to enable fork-aware pool in the custom node. + - audience: Node Operator + description: | + - New command line option was added, allowing to select implementation of transaction pool: + - `--pool-type=fork-aware` - new fork aware transaction pool, + - `--pool-type=single-state` - old transaction pool implementation which is still default, + +crates: + - name: sc-basic-authorship + bump: patch + - name: sc-cli + bump: major + - name: sc-consensus-manual-seal + bump: patch + - name: sc-network-transactions + bump: none + - name: sc-rpc + bump: patch + - name: sc-rpc-spec-v2 + bump: patch + - name: sc-offchain + bump: patch + - name: sc-service + bump: patch + - name: sc-service-test + bump: minor + - name: sc-transaction-pool + bump: major + - name: sc-transaction-pool-api + bump: major + validate: false + - name: sp-runtime + bump: patch + - name: substrate-test-runtime-transaction-pool + bump: minor + - name: staging-node-cli + bump: minor + - name: node-bench + bump: patch + - name: node-rpc + bump: minor + - name: substrate-prometheus-endpoint + bump: patch + - name: substrate-frame-rpc-system + bump: patch + - name: minimal-template-node + bump: minor + - name: parachain-template-node + bump: minor + - name: solochain-template-node + bump: minor + - name: polkadot-service + bump: patch + - name: cumulus-client-service + bump: patch + - name: cumulus-test-service + bump: major + - name: polkadot-omni-node-lib + bump: patch diff --git a/prdoc/pr_4837.prdoc b/prdoc/pr_4837.prdoc new file mode 100644 index 000000000000..55c12cc92a1c --- /dev/null +++ b/prdoc/pr_4837.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: Add PVF execution priority + +doc: + - audience: Node Dev + description: | + The new logic optimizes the distribution of execution jobs for disputes, approvals, and backings. + The main goal is to create back pressure for backing in the presence of disputes or numerous approval jobs. + +crates: + - name: polkadot-node-core-pvf + bump: major + - name: polkadot-overseer + bump: patch + - name: polkadot-node-subsystem-types + bump: patch + - name: polkadot-node-core-approval-voting + bump: patch + - name: polkadot-node-core-backing + bump: patch + - name: polkadot-node-core-candidate-validation + bump: patch + - name: polkadot-node-core-dispute-coordinator + bump: patch diff --git a/prdoc/pr_4846.prdoc b/prdoc/pr_4846.prdoc new file mode 100644 index 000000000000..eb18301b1010 --- /dev/null +++ b/prdoc/pr_4846.prdoc @@ -0,0 +1,13 @@ +title: "Make approval-voting runnable on a worker thread" + +doc: + - audience: Node Dev + description: | + Make approval-voting subsystem runnable on a separate worker thread without having to + to always pass to it an orchestra context. It achieves that by refactoring existing functions + to require only the minimal set of traits needed in the function instead of the general + `Context` + +crates: + - name: polkadot-node-core-approval-voting + bump: major diff --git a/prdoc/pr_4849.prdoc b/prdoc/pr_4849.prdoc new file mode 100644 index 000000000000..185295151068 --- /dev/null +++ b/prdoc/pr_4849.prdoc @@ -0,0 +1,47 @@ +title: Introduce approval-voting-parallel subsystem + +doc: + - audience: Node Dev + description: | + This introduces a new subsystem called approval-voting-parallel. It combines the tasks + previously handled by the approval-voting and approval-distribution subsystems. + + The new subsystem is enabled by default on all test networks. On production networks + like Polkadot and Kusama, the legacy system with two separate subsystems is still in use. + However, there is a CLI option --enable-approval-voting-parallel to gradually roll out + the new subsystem on specific nodes. Once we are confident that it works as expected, + it will be enabled by default on all networks. + + The approval-voting-parallel subsystem coordinates two groups of workers: + - Four approval-distribution workers that operate in parallel, each handling tasks based + on the validator_index of the message originator. + - One approval-voting worker that performs the tasks previously managed by the standalone + approval-voting subsystem. + +crates: + - name: polkadot-overseer + bump: major + - name: polkadot-node-primitives + bump: major + - name: polkadot-node-subsystem-types + bump: major + - name: polkadot-service + bump: major + - name: polkadot-approval-distribution + bump: major + - name: polkadot-node-core-approval-voting + bump: major + - name: polkadot-node-core-approval-voting-parallel + bump: major + - name: polkadot-network-bridge + bump: major + - name: polkadot-node-core-dispute-coordinator + bump: major + - name: cumulus-relay-chain-inprocess-interface + bump: major + - name: polkadot-cli + bump: major + - name: polkadot + bump: major + - name: polkadot-sdk + bump: minor diff --git a/prdoc/pr_4851.prdoc b/prdoc/pr_4851.prdoc new file mode 100644 index 000000000000..2110a68d401c --- /dev/null +++ b/prdoc/pr_4851.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 support for deprecation metadata in `RuntimeMetadataIr` entries. + +doc: + - audience: + - Runtime Dev + - Runtime User + description: | + Changes introduced are listed below. + Adds `DeprecationStatusIR` enum to sp_metadata_ir. + - Is a deprecation info for simple items. + Adds `DeprecationInfoIR` enum to sp_metadata_ir. + - It is a deprecation info for an enums/errors/calls. Contains `DeprecationStatusIR`. + Also denotes full/partial deprecation of the type or its variants/calls. + Adds `deprecation_info` field to + - `RuntimeApiMetadataIR` + - `RuntimeApiMethodMetadataIR` + - `StorageEntryMetadataIR` + - `PalletConstantMetadataIR` + - `PalletCallMetadataIR` + - `PalletMetadataIR` + - `PalletEventMetadataIR` + - `PalletErrorMetadataIR` + Examples of the deprecation info produced can be seen inside + - Tests for `frame-support` + - hackmd link https://hackmd.io/@Zett98/Bys0YgbcR + +crates: + - name: frame-support-procedural + bump: patch + - name: frame-support + bump: major + - name: sp-api-proc-macro + bump: patch + - name: sp-api + bump: patch + - name: sp-metadata-ir + bump: major diff --git a/prdoc/pr_4889.prdoc b/prdoc/pr_4889.prdoc new file mode 100644 index 000000000000..dfcdcd4f15bc --- /dev/null +++ b/prdoc/pr_4889.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 CLI options for parachain chain specifications + fix bug for swallowing custom fields + +doc: + - audience: Node Operator + description: | + Parachain ID and relay chain can be specified via the CLI arguments for when creating a chain spec. + A bug that also swallowed custom fields outside of the default config has also been fixed. + + +crates: + - name: staging-chain-spec-builder + bump: major diff --git a/prdoc/pr_4974.prdoc b/prdoc/pr_4974.prdoc new file mode 100644 index 000000000000..f764ea3f46fd --- /dev/null +++ b/prdoc/pr_4974.prdoc @@ -0,0 +1,15 @@ +# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0 +# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json + +title: "Remove libp2p dependency from sc-network-sync" + +doc: + - audience: Node Dev + description: | + This PR removes `libp2p::request_response::OutboundFailure` from `substrate/client/network/sync/src/engine.rs`. + +crates: + - name: sc-network + bump: patch + - name: sc-network-sync + bump: patch diff --git a/prdoc/pr_4982.prdoc b/prdoc/pr_4982.prdoc new file mode 100644 index 000000000000..9e6d103a0ad8 --- /dev/null +++ b/prdoc/pr_4982.prdoc @@ -0,0 +1,13 @@ +title: Add useful error logs in pallet-xcm + +doc: + - audience: Runtime Dev + description: | + This PR adds error logs to assist in debugging pallet-xcm. + Additionally, it replaces the usage of `log` with `tracing`. + +crates: + - name: staging-xcm-executor + bump: patch + - name: pallet-xcm + bump: patch diff --git a/prdoc/pr_5038.prdoc b/prdoc/pr_5038.prdoc new file mode 100644 index 000000000000..2bab8ef69f89 --- /dev/null +++ b/prdoc/pr_5038.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: Plumb RPC listener up to caller + +doc: + - audience: Node Dev + description: + This PR allows the RPC server's socket address to be returned when initializing the server. + This allows the library consumer to easily programmatically determine which port the RPC server is listening on. +crates: + - name: sc-rpc-server + bump: major + - name: sc-service + bump: major diff --git a/prdoc/pr_5198.prdoc b/prdoc/pr_5198.prdoc new file mode 100644 index 000000000000..417b0b5a4fd9 --- /dev/null +++ b/prdoc/pr_5198.prdoc @@ -0,0 +1,13 @@ +title: "MQ processor should be transactional" + +doc: + - audience: [Runtime User, Runtime Dev] + description: | + Enforce transactional processing on pallet Message Queue Processor. + + Storage changes that were done while processing a message will now be rolled back + when the processing returns an error. `Ok(false)` will not revert, only `Err(_)`. + +crates: + - name: pallet-message-queue + bump: major \ No newline at end of file diff --git a/prdoc/pr_5201.prdoc b/prdoc/pr_5201.prdoc new file mode 100644 index 000000000000..a0c1bbfd2e41 --- /dev/null +++ b/prdoc/pr_5201.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: Snowbridge free consensus updates + +doc: + - audience: Runtime Dev + description: | + Allow free consensus updates to the Snowbridge Ethereum client if the headers are more than a certain + number of headers apart. Relayers providing valid consensus updates are refunded for updates. Bridge + users are not affected. + +crates: + - name: snowbridge-pallet-ethereum-client + bump: patch + - name: snowbridge-pallet-inbound-queue + bump: patch + - name: snowbridge-runtime-test-common + bump: patch + - name: bridge-hub-rococo-runtime + bump: major + - name: bridge-hub-westend-runtime + bump: major diff --git a/prdoc/pr_5274.prdoc b/prdoc/pr_5274.prdoc new file mode 100644 index 000000000000..fb76ce661b4e --- /dev/null +++ b/prdoc/pr_5274.prdoc @@ -0,0 +1,24 @@ +title: Enrich metadata IR with associated types of config traits + +doc: + - audience: Runtime Dev + description: | + This feature is part of the upcoming metadata V16. The associated types of the `Config` trait that require the `TypeInfo` + or `Parameter` bounds are included in the metadata of the pallet. The metadata is not yet exposed to the end-user, however + the metadata intermediate representation (IR) contains these types. + + Developers can opt out of metadata collection of the associated types by specifying `without_metadata` optional attribute + to the `#[pallet::config]`. + + Furthermore, the `without_metadata` argument can be used in combination with the newly added `#[pallet::include_metadata]` + attribute to selectively include only certain associated types in the metadata collection. + +crates: + - name: frame-support + bump: patch + - name: frame-support-procedural + bump: patch + - name: frame-support-procedural-tools + bump: patch + - name: sp-metadata-ir + bump: major diff --git a/prdoc/pr_5322.prdoc b/prdoc/pr_5322.prdoc new file mode 100644 index 000000000000..b4cf261f33a4 --- /dev/null +++ b/prdoc/pr_5322.prdoc @@ -0,0 +1,30 @@ +title: Elastic scaling - introduce new candidate receipt primitive + +doc: + - audience: [Runtime Dev, Node Dev] + description: | + Introduces `CandidateDescriptorV2` primitive as described in [RFC 103](https://github.com/polkadot-fellows/RFCs/pull/103). + Updates parachains runtime, Westend, Rococo and test runtimes to use the new primitives. + This change does not implement the functionality of the new candidate receipts. + +crates: +- name: polkadot-primitives + bump: minor +- name: polkadot-primitives-test-helpers + bump: minor +- name: polkadot-runtime-parachains + bump: major +- name: rococo-runtime + bump: major +- name: westend-runtime + bump: major +- name: polkadot-test-runtime + bump: major +- name: polkadot-service + bump: patch +- name: polkadot-node-subsystem-types + bump: patch +- name: polkadot-test-client + bump: major +- name: cumulus-relay-chain-inprocess-interface + bump: patch diff --git a/prdoc/pr_5343.prdoc b/prdoc/pr_5343.prdoc new file mode 100644 index 000000000000..3cec70de93cb --- /dev/null +++ b/prdoc/pr_5343.prdoc @@ -0,0 +1,19 @@ +title: Allow to disable gap creation during block import + +doc: + - audience: Node Dev + description: | + New property `BlockImportParams::create_gap` allows to change whether to create block gap in case block + has no parent (defaults to `true` keeping existing behavior), which is helpful for sync protocols that do not need + to sync the gap after this happens. `BlockImportOperation::create_gap()` method was also introduced, though in + most cases `BlockImportParams::create_gap` will be used. + +crates: + - name: sc-client-api + bump: major + - name: sc-consensus + bump: minor + - name: sc-client-db + bump: minor + - name: sc-service + bump: minor diff --git a/prdoc/pr_5372.prdoc b/prdoc/pr_5372.prdoc new file mode 100644 index 000000000000..fec856b3c0d6 --- /dev/null +++ b/prdoc/pr_5372.prdoc @@ -0,0 +1,71 @@ +title: "elastic scaling: add core selector to cumulus" + +doc: + - audience: [Node Dev, Runtime Dev] + description: | + Adds a runtime API for querying the core selector of a parachain. + Also use the core selector API and the claim queue relay chain runtime API in the slot based collator (if available) + to determine which cores to build on. + Part of implementing https://github.com/polkadot-fellows/RFCs/pull/103. + +crates: + - name: cumulus-client-consensus-aura + bump: major + - name: cumulus-relay-chain-inprocess-interface + bump: patch + - name: cumulus-relay-chain-interface + bump: major + validate: false + - name: cumulus-relay-chain-minimal-node + bump: none + - name: cumulus-relay-chain-rpc-interface + bump: patch + - name: cumulus-pallet-parachain-system + bump: major + validate: false + - name: asset-hub-rococo-runtime + bump: patch + - name: asset-hub-westend-runtime + bump: patch + - name: bridge-hub-rococo-runtime + bump: patch + - name: bridge-hub-westend-runtime + bump: patch + - name: collectives-westend-runtime + bump: patch + - name: contracts-rococo-runtime + bump: patch + - name: coretime-rococo-runtime + bump: patch + - name: coretime-westend-runtime + bump: patch + - name: glutton-westend-runtime + bump: patch + - name: people-rococo-runtime + bump: patch + - name: people-westend-runtime + bump: patch + - name: seedling-runtime + bump: patch + - name: shell-runtime + bump: patch + - name: penpal-runtime + bump: patch + - name: rococo-parachain-runtime + bump: patch + - name: polkadot-parachain-lib + bump: major + validate: false + - name: cumulus-primitives-core + bump: minor + validate: false + - name: cumulus-test-runtime + bump: minor + - name: cumulus-client-consensus-common + bump: none + - name: cumulus-client-pov-recovery + bump: none + - name: cumulus-client-network + bump: none + - name: cumulus-pallet-xcmp-queue + bump: none diff --git a/prdoc/pr_5423.prdoc b/prdoc/pr_5423.prdoc new file mode 100644 index 000000000000..dbd685d73dc3 --- /dev/null +++ b/prdoc/pr_5423.prdoc @@ -0,0 +1,20 @@ +title: Runtime support for candidate receipt v2 (RFC103) + +doc: + - audience: [Runtime Dev, Node Dev] + description: | + Implementation of [RFC103](https://github.com/polkadot-fellows/RFCs/pull/103) in the relay chain runtime. + The runtime will accept and validate the new receipts only if the `FeatureIndex::CandidateReceiptV2` + feature bit is enabled. + +crates: + - name: polkadot-primitives + bump: major + - name: polkadot-runtime-parachains + bump: patch + - name: rococo-runtime + bump: patch + - name: westend-runtime + bump: patch + - name: polkadot + bump: patch diff --git a/prdoc/pr_5435.prdoc b/prdoc/pr_5435.prdoc new file mode 100644 index 000000000000..d3621e385bcd --- /dev/null +++ b/prdoc/pr_5435.prdoc @@ -0,0 +1,16 @@ +title: "Support registering assets on Asset Hubs over bridge" + +doc: + - audience: Runtime User + description: | + Allows one Asset Hub on one side, to register assets on the other Asset Hub over the bridge. + Rococo <> Ethereum test bridge will be dropped in favor of Westend <> Ethereum test bridge. + This PR also changes emulated tests to simulate double bridging from Ethereum<>Westend<>Rococo. + +crates: + - name: assets-common + bump: patch + - name: asset-hub-rococo-runtime + bump: patch + - name: asset-hub-westend-runtime + bump: patch diff --git a/prdoc/pr_5461.prdoc b/prdoc/pr_5461.prdoc new file mode 100644 index 000000000000..bf343216e29b --- /dev/null +++ b/prdoc/pr_5461.prdoc @@ -0,0 +1,20 @@ +title: "runtime: remove ttl" + +doc: + - audience: [Runtime Dev, Node Dev] + description: | + Resolves https://github.com/paritytech/polkadot-sdk/issues/4776. Removes the scheduling ttl used in the relay chain + runtimes, as well as the availability timeout retries. The extrinsics for configuring these two values are also removed. + Deprecates the `ttl` and `max_availability_timeouts` fields of the `HostConfiguration` primitive. + +crates: + - name: polkadot-runtime-parachains + bump: major + - name: polkadot-primitives + bump: major + - name: rococo-runtime + bump: major + - name: westend-runtime + bump: major + - name: polkadot + bump: none diff --git a/prdoc/pr_5469.prdoc b/prdoc/pr_5469.prdoc new file mode 100644 index 000000000000..1e6aa3c0c072 --- /dev/null +++ b/prdoc/pr_5469.prdoc @@ -0,0 +1,11 @@ +title: Syncing strategy refactoring + +doc: + - audience: Node Dev + description: | + Mostly internal changes to syncing strategies that is a step towards making them configurable/extensible in the + future. It is unlikely that external developers will need to change their code. + +crates: + - name: sc-network-sync + bump: major diff --git a/prdoc/pr_5515.prdoc b/prdoc/pr_5515.prdoc new file mode 100644 index 000000000000..60f43b922c7f --- /dev/null +++ b/prdoc/pr_5515.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 retry logic in relay chain rpc interface + +doc: + - audience: [ Node Dev, Node Operator ] + description: | + Added a basic retry logic for collators connecting to external RPC servers. The collator + will try for 5 times to connect to each RPC server from the provided list. In between + each iteration will wait a duration which will increase exponentailly by a factor of two. + The maximum time a collator can spend in the retry logic is 1 + 2 + 4 + 8 + 16 = 31 seconds. +crates: + - name: cumulus-relay-chain-rpc-interface + bump: minor diff --git a/prdoc/pr_5521.prdoc b/prdoc/pr_5521.prdoc new file mode 100644 index 000000000000..564d9df58ceb --- /dev/null +++ b/prdoc/pr_5521.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: Allow to call arbitrary runtime apis using RelayChainInterface + +doc: + - audience: Node Dev + description: | + This PR adds a `call_runtime_api` method to RelayChainInterface trait, and a separate function also named `call_runtime_api` + which allows the caller to specify the input and output types, as opposed to having to encode them. + +crates: + - name: cumulus-relay-chain-interface + bump: patch + - name: cumulus-client-consensus-common + bump: patch + - name: cumulus-client-pov-recovery + bump: patch + - name: cumulus-client-network + bump: patch + - name: cumulus-relay-chain-inprocess-interface + bump: patch + - name: cumulus-relay-chain-rpc-interface + bump: patch diff --git a/prdoc/pr_5526.prdoc b/prdoc/pr_5526.prdoc new file mode 100644 index 000000000000..0c0a4b055f6a --- /dev/null +++ b/prdoc/pr_5526.prdoc @@ -0,0 +1,13 @@ +title: "Fix enact_candidate weight generation" +doc: + - audience: Runtime Dev + description: | + This PR works around an issue in multivariate linear regression of weight generation. + +crates: + - name: polkadot-runtime-parachains + bump: patch + - name: rococo-runtime + bump: patch + - name: westend-runtime + bump: patch diff --git a/prdoc/pr_5540.prdoc b/prdoc/pr_5540.prdoc new file mode 100644 index 000000000000..2c00714c4f86 --- /dev/null +++ b/prdoc/pr_5540.prdoc @@ -0,0 +1,12 @@ +title: Avoid unnecessary block gap updates + +doc: + - audience: Node Dev + description: | + Previously, the block gap storage in database and state in `BlockchainDb` could be updated even if no changes occurred. + This commit refines the logic to ensure updates only occur when the block gap value actually changes, reducing unnecessary + writes and enhancing overall efficiency. + +crates: + - name: sc-client-db + bump: none diff --git a/prdoc/pr_5548.prdoc b/prdoc/pr_5548.prdoc new file mode 100644 index 000000000000..69e79213fa29 --- /dev/null +++ b/prdoc/pr_5548.prdoc @@ -0,0 +1,16 @@ +title: Use H160 when interfacing with contracts + +doc: + - audience: Runtime Dev + description: | + When interfacing with a contract we now use the native ethereum address + type and map it to AccountId32 when interfacing with the rest + of substrate. + +crates: + - name: pallet-revive + bump: major + - name: pallet-revive-fixtures + bump: major + - name: pallet-revive-mock-network + bump: major diff --git a/prdoc/pr_5555.prdoc b/prdoc/pr_5555.prdoc new file mode 100644 index 000000000000..630345b9b5a1 --- /dev/null +++ b/prdoc/pr_5555.prdoc @@ -0,0 +1,15 @@ +title: Make salt optional + +doc: + - audience: Runtime Dev + description: | + Remove address_len and salt_len from uapi as both are now fixed size + +crates: + - name: pallet-revive + bump: patch + - name: pallet-revive-uapi + bump: patch + - name: pallet-revive-fixtures + bump: patch + diff --git a/prdoc/pr_5556.prdoc b/prdoc/pr_5556.prdoc new file mode 100644 index 000000000000..4865ec1e338d --- /dev/null +++ b/prdoc/pr_5556.prdoc @@ -0,0 +1,11 @@ +title: Make salt optional + +doc: + - audience: Runtime Dev + description: | + By making salt optional we allow clients to use CREATE1 semantics + when deploying a new contract. + +crates: + - name: pallet-revive + bump: major diff --git a/prdoc/pr_5572.prdoc b/prdoc/pr_5572.prdoc new file mode 100644 index 000000000000..c0707e4b7eba --- /dev/null +++ b/prdoc/pr_5572.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: added RPC metrics for the collator + +doc: + - audience: [ Node Dev, Node Operator ] + description: | + The metric is named `relay_chain_rpc_interface` and can be scraped by prometheus agents from the parachain prometheus exporter. The metric provide information about `count`, `sum` and `duration` in seconds (with exponential buckets with parameters as start = 0.001, factor = 4, count = 9) for all RPC requests made with the `relay-chain-rpc-interface`. +crates: + - name: cumulus-relay-chain-rpc-interface + bump: major + - name: cumulus-relay-chain-minimal-node + bump: major + - name: cumulus-test-service + bump: patch + - name: substrate-prometheus-endpoint + bump: patch + - name: cumulus-client-service + bump: patch + diff --git a/prdoc/pr_5592.prdoc b/prdoc/pr_5592.prdoc new file mode 100644 index 000000000000..9d51917db7b1 --- /dev/null +++ b/prdoc/pr_5592.prdoc @@ -0,0 +1,26 @@ +title: Introduce `BlockGap` + +doc: + - audience: Node Dev + description: | + This is the first step towards https://github.com/paritytech/polkadot-sdk/issues/5406, + refactoring the representation of block gap. This refactor converts the existing + `(NumberFor, NumberFor)` into a dedicated `BlockGap>` + struct. This change is purely structural and does not alter existing logic, but lays + the groundwork for the follow-up PR. The compatibility concern in the database caused + by the new structure transition is addressed as well. + + The `BlockGap` refactoring results in breaking changes in the `Info` structure returned + in `client.info()`. + +crates: + - name: sc-consensus-babe + bump: none + - name: sc-client-db + bump: none + - name: sc-network-sync + bump: none + - name: sc-service + bump: none + - name: sp-blockchain + bump: major diff --git a/prdoc/pr_5601.prdoc b/prdoc/pr_5601.prdoc new file mode 100644 index 000000000000..3a0ec9ee8714 --- /dev/null +++ b/prdoc/pr_5601.prdoc @@ -0,0 +1,12 @@ +title: Introduce `RpcParams` in sc-cli + +doc: + - audience: Node Dev + description: | + Refactors and consolidates all RPC-related parameters in the run command into a dedicated `RpcParams` struct. This change allows downstream users to build custom run command without duplicating code. + +crates: + - name: cumulus-client-cli + bump: none + - name: sc-cli + bump: major diff --git a/prdoc/pr_5606.prdoc b/prdoc/pr_5606.prdoc new file mode 100644 index 000000000000..46883c5722cd --- /dev/null +++ b/prdoc/pr_5606.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: Fix PVF precompilation for Kusama + +doc: + - audience: Node Operator + description: | + Tweaks the PVF precompilation on Kusama to allow prepare PVFs when the node is an authority but not a validator. + +crates: + - name: polkadot-node-core-candidate-validation + bump: patch diff --git a/prdoc/pr_5608.prdoc b/prdoc/pr_5608.prdoc new file mode 100644 index 000000000000..9a0748e46bab --- /dev/null +++ b/prdoc/pr_5608.prdoc @@ -0,0 +1,16 @@ +title: "[pallet-revive] update runtime types" + +doc: + - audience: Runtime Dev + description: | + Refactor the Ext trait to use U256 instead of BalanceOf or MomentOf + +crates: + - name: pallet-revive + bump: major + - name: pallet-revive-uapi + bump: patch + - name: pallet-revive-fixtures + bump: patch + + diff --git a/prdoc/pr_5609.prdoc b/prdoc/pr_5609.prdoc new file mode 100644 index 000000000000..799071f04c1e --- /dev/null +++ b/prdoc/pr_5609.prdoc @@ -0,0 +1,21 @@ +title: Update litep2p network backend to v0.7.0 + +doc: + - audience: [ Node Dev, Node Operator ] + description: | + This PR updates the Litep2p network backend to version 0.7.0. + This new release introduces several new features, improvements, and fixes to the litep2p library. + Key updates include enhanced error handling propagated through metrics, configurable connection limits, + and a new API for managing public addresses. + + The Identify protocol no longer includes public addresses in its configuration. + Instead, we rely on the `litep2p.public_addresses` interface to propagate external addresses of the node. + + Litep2p uses hickory DNS resolver (formerly known as trust DNS). + Similarly to the trust DNS, the hickory logs are silenced. + +crates: + - name: sc-network + bump: patch + - name: sc-tracing + bump: minor diff --git a/prdoc/pr_5623.prdoc b/prdoc/pr_5623.prdoc new file mode 100644 index 000000000000..c0701e0e1b51 --- /dev/null +++ b/prdoc/pr_5623.prdoc @@ -0,0 +1,89 @@ +# 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: Generic slashing side-effects + +doc: + - audience: Runtime Dev + description: | + What? + Make it possible for other pallets to implement their own logic when a slash on a balance occurs. + + How? + First we abstract the done_slash function of holds::Balanced to it's own trait that any pallet can implement. + Then we add a config type in pallet-balances that accepts a callback tuple of all the pallets that implement this trait. + Finally implement done_slash for pallet-balances such that it calls the config type. + Integration + The default implementation of done_slash is still an empty function, and the new config type of pallet-balances can be set to an empty tuple, so nothing changes by default. + +crates: + - name: frame-support + bump: major + + - name: pallet-balances + bump: major + + - name: pallet-broker + bump: minor + + - name: rococo-runtime + bump: minor + + - name: pallet-nis + bump: minor + + - name: westend-runtime + bump: minor + + - name: pallet-assets-freezer + bump: minor + + - name: pallet-contracts-mock-network + bump: minor + + - name: pallet-revive-mock-network + 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: 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: contracts-rococo-runtime + bump: minor + + - name: rococo-parachain-runtime + bump: minor + + - name: staging-xcm-builder + bump: minor + + - name: polkadot-sdk + bump: minor + + diff --git a/prdoc/pr_5630.prdoc b/prdoc/pr_5630.prdoc new file mode 100644 index 000000000000..bafb9e746d40 --- /dev/null +++ b/prdoc/pr_5630.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: Introduce and Implement the `VestedTransfer` Trait + +doc: + - audience: Runtime Dev + description: | + This PR introduces a new trait `VestedTransfer` which is implemented by `pallet_vesting`. With this, other pallets can easily introduce vested transfers into their logic. + +crates: + - name: frame-support + bump: minor + - name: pallet-vesting + bump: minor diff --git a/prdoc/pr_5635.prdoc b/prdoc/pr_5635.prdoc new file mode 100644 index 000000000000..168d65970c95 --- /dev/null +++ b/prdoc/pr_5635.prdoc @@ -0,0 +1,13 @@ +title: Fix edge case where state sync is not triggered + +doc: + - audience: Node Dev + description: | + There is an edge case where the finalized block notification is received, but the conditions required to initiate the + state sync are not fully met. In such cases, state sync would fail to start as expected and remain stalled. + This patch addresses it by storing the pending attempt and trying to start the state sync later when the conditions + are satisfied. + +crates: + - name: sc-network-sync + bump: patch diff --git a/prdoc/pr_5640.prdoc b/prdoc/pr_5640.prdoc new file mode 100644 index 000000000000..fdd7f5e1b893 --- /dev/null +++ b/prdoc/pr_5640.prdoc @@ -0,0 +1,10 @@ +title: "[pallet-revive] Move event's topics" + +doc: + - audience: Runtime Dev + description: | + Move event's topics inside body + +crates: + - name: pallet-revive + bump: major diff --git a/prdoc/pr_5664.prdoc b/prdoc/pr_5664.prdoc new file mode 100644 index 000000000000..7fbe15006da3 --- /dev/null +++ b/prdoc/pr_5664.prdoc @@ -0,0 +1,11 @@ +title: Calling an address without associated code is a balance transfer + +doc: + - audience: Runtime Dev + description: | + This makes pallet_revive behave like EVM where a balance transfer + is just a call to a plain wallet. + +crates: + - name: pallet-revive + bump: patch diff --git a/prdoc/pr_5665.prdoc b/prdoc/pr_5665.prdoc new file mode 100644 index 000000000000..2b2f0547dc01 --- /dev/null +++ b/prdoc/pr_5665.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: "[pallet-contracts] remove riscv support" + +doc: + - audience: Runtime Dev + description: | + RISC-V support is now being built inside the new fork pallet-revive + +crates: + - name: pallet-contracts + bump: patch + - name: pallet-contracts-fixtures + bump: patch + - name: pallet-contracts-uapi + bump: patch diff --git a/prdoc/pr_5666.prdoc b/prdoc/pr_5666.prdoc new file mode 100644 index 000000000000..08bd9815cdd4 --- /dev/null +++ b/prdoc/pr_5666.prdoc @@ -0,0 +1,19 @@ +title: Make syncing strategy an argument of the syncing engine + +doc: + - audience: Node Dev + description: | + Syncing strategy is no longer implicitly created when building network, but needs to be instantiated explicitly. + Previously default implementation can be created with new function `build_polkadot_syncing_strategy` or custom + syncing strategy could be implemented and used instead if desired, providing greater flexibility for chain + developers. + +crates: + - name: cumulus-client-service + bump: patch + - name: polkadot-service + bump: patch + - name: sc-service + bump: major + - name: sc-network-sync + bump: major diff --git a/prdoc/pr_5675.prdoc b/prdoc/pr_5675.prdoc new file mode 100644 index 000000000000..ceae446dab1b --- /dev/null +++ b/prdoc/pr_5675.prdoc @@ -0,0 +1,14 @@ +title: "[pallet-revive] Add balance_of syscyall for fetching foreign balances" + +doc: + - audience: Runtime Dev + description: | + This adds an API method balance_of, corresponding to the BALANCE EVM opcode. + +crates: + - name: pallet-revive + bump: minor + - name: pallet-revive-uapi + bump: minor + - name: pallet-revive-fixtures + bump: minor diff --git a/prdoc/pr_5676.prdoc b/prdoc/pr_5676.prdoc new file mode 100644 index 000000000000..dfe23e120b4b --- /dev/null +++ b/prdoc/pr_5676.prdoc @@ -0,0 +1,174 @@ +title: '[ci] Update CI image with rust 1.81.0 and 2024-09-11' +doc: +- audience: [Runtime Dev, Node Dev, Node Operator] + description: |- + cc https://github.com/paritytech/ci_cd/issues/1035 + + close https://github.com/paritytech/ci_cd/issues/1023 +crates: +- name: pallet-xcm-bridge-hub + bump: patch +- name: snowbridge-router-primitives + bump: patch +- name: snowbridge-runtime-common + bump: patch +- name: cumulus-pallet-parachain-system + bump: patch +- name: asset-hub-rococo-runtime + bump: patch +- name: asset-hub-westend-runtime + bump: patch +- name: asset-test-utils + bump: patch +- name: bridge-hub-test-utils + bump: patch +- name: cumulus-primitives-utility + bump: patch +- name: polkadot-node-core-approval-voting + bump: patch +- name: polkadot-node-core-pvf-common + bump: patch +- name: polkadot-approval-distribution + bump: patch +- name: polkadot-availability-recovery + bump: patch +- name: polkadot-node-subsystem-types + bump: patch +- name: polkadot-runtime-parachains + bump: patch +- name: westend-runtime + bump: patch +- name: polkadot-statement-table + bump: patch +- name: pallet-xcm-benchmarks + bump: patch +- name: staging-xcm-builder + bump: patch +- name: xcm-runtime-apis + bump: patch +- name: sc-cli + bump: patch +- name: sc-consensus-grandpa + bump: patch +- name: sc-network + bump: patch +- name: sc-network-sync + bump: patch +- name: sc-rpc-spec-v2 + bump: patch +- name: pallet-bags-list + bump: patch +- name: pallet-balances + bump: patch +- name: pallet-bounties + bump: patch +- name: pallet-child-bounties + bump: patch +- name: pallet-nis + bump: patch +- name: pallet-referenda + bump: patch +- name: pallet-revive-proc-macro + bump: patch +- name: pallet-society + bump: patch +- name: pallet-staking + bump: patch +- name: frame-support-procedural + bump: patch +- name: frame-support + bump: patch +- name: pallet-transaction-payment + bump: patch +- name: pallet-utility + bump: patch +- name: pallet-vesting + bump: patch +- name: substrate-wasm-builder + bump: patch +- name: snowbridge-outbound-queue-merkle-tree + bump: patch +- name: shell-runtime + bump: patch +- name: polkadot-parachain-lib + bump: patch +- name: polkadot-cli + bump: patch +- name: polkadot-node-core-pvf + bump: patch +- name: polkadot-service + bump: patch +- name: polkadot-primitives + bump: patch +- name: staging-xcm-executor + bump: patch +- name: sc-consensus-beefy + bump: patch +- name: sc-consensus-slots + bump: patch +- name: frame-benchmarking-pallet-pov + bump: patch +- name: pallet-contracts + bump: patch +- name: frame-election-provider-support + bump: patch +- name: pallet-revive-mock-network + bump: patch +- name: frame-benchmarking-cli + bump: patch +- name: sc-utils + bump: patch +- name: pallet-beefy-mmr + bump: patch +- name: sp-state-machine + bump: patch +- name: fork-tree + bump: patch +- name: sc-transaction-pool + bump: patch +- name: pallet-delegated-staking + bump: patch +- name: sc-executor-wasmtime + bump: patch +- name: cumulus-pallet-xcmp-queue + bump: patch +- name: xcm-procedural + bump: patch +- name: sp-application-crypto + bump: patch +- name: sp-core + bump: patch +- name: sp-keyring + bump: patch +- name: polkadot-availability-distribution + bump: patch +- name: sp-runtime + bump: patch +- name: sc-authority-discovery + bump: patch +- name: frame-system + bump: patch +- name: sc-network-gossip + bump: patch +- name: pallet-authorship + bump: patch +- name: pallet-election-provider-multi-phase + bump: patch +- name: sp-runtime-interface + bump: patch +- name: pallet-bridge-grandpa + bump: patch +- name: pallet-elections-phragmen + bump: patch +- name: frame-executive + bump: patch +- name: bp-header-chain + bump: patch +- name: polkadot-overseer + bump: patch +- name: polkadot + bump: patch +- name: bridge-hub-westend-runtime + bump: major +- name: bp-messages + bump: patch diff --git a/prdoc/pr_5682.prdoc b/prdoc/pr_5682.prdoc new file mode 100644 index 000000000000..2b05d73ef552 --- /dev/null +++ b/prdoc/pr_5682.prdoc @@ -0,0 +1,15 @@ +title: Introduces `VerifyExistenceProof` trait + +doc: + - audience: Runtime Dev + description: | + Introduces `VerifyExistenceProof` trait for verifying proofs in the runtime. + An implementation of the trait for binary and 16 patricia merkle tree is provided. + +crates: + - name: binary-merkle-tree + bump: major + - name: sp-runtime + bump: patch + - name: frame-support + bump: minor diff --git a/prdoc/pr_5684.prdoc b/prdoc/pr_5684.prdoc new file mode 100644 index 000000000000..9800c85de2ae --- /dev/null +++ b/prdoc/pr_5684.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: "[pallet-revive]" + +doc: + - audience: Runtime Dev + description: | + Update xcm runtime api, and fix pallet-revive xcm tests + +crates: + - name: pallet-revive + bump: patch + - name: pallet-revive-fixtures + bump: patch + - name: pallet-revive-mock-network + bump: patch + - name: polkadot-sdk + bump: patch diff --git a/prdoc/pr_5686.prdoc b/prdoc/pr_5686.prdoc new file mode 100644 index 000000000000..3f0da912a34c --- /dev/null +++ b/prdoc/pr_5686.prdoc @@ -0,0 +1,15 @@ +title: "sync: Remove checking of the extrinsics root" + +doc: + - audience: Node Dev + description: | + Remove checking the extrinsics root as part of the sync code. + With the introduction of `system_version` and the possibility to use the `V1` + layout for the trie when calculating the extrinsics root, it would require the + sync code to fetch the runtime version first before knowing which layout to use + when building the extrinsic root. + The extrinsics root is still checked when executing a block on chain. + +crates: + - name: sc-network-sync + bump: patch diff --git a/prdoc/pr_5687.prdoc b/prdoc/pr_5687.prdoc new file mode 100644 index 000000000000..f84f8e722269 --- /dev/null +++ b/prdoc/pr_5687.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: "Westend/Rococo Asset Hub: auto incremented asset id for trust backed assets" + +doc: + - audience: Runtime User + description: | + Setup auto incremented asset id to `50_000_000` for trust backed assets. + + ### Migration + This change does not break the API but introduces a new constraint. It implements + an auto-incremented ID strategy for Trust-Backed Assets (50 pallet instance indexes on both + networks), starting at ID 50,000,000. Each new asset must be created with an ID that is one + greater than the last asset created. The next ID can be fetched from the `NextAssetId` + storage item of the assets pallet. An empty `NextAssetId` storage item indicates no + constraint on the next asset ID and can serve as a feature flag for this release. + + +crates: + - name: asset-hub-rococo-runtime + bump: major + - name: asset-hub-westend-runtime + bump: major diff --git a/prdoc/pr_5701.prdoc b/prdoc/pr_5701.prdoc new file mode 100644 index 000000000000..3d237eb34e74 --- /dev/null +++ b/prdoc/pr_5701.prdoc @@ -0,0 +1,14 @@ +title: "[pallet-revive] uapi: allow create1 equivalent calls" + +doc: + - audience: Runtime Dev + description: | + The salt argument should be optional to allow create1 equivalent calls. + +crates: + - name: pallet-revive + bump: minor + - name: pallet-revive-uapi + bump: major + - name: pallet-revive-fixtures + bump: patch diff --git a/prdoc/pr_5707.prdoc b/prdoc/pr_5707.prdoc new file mode 100644 index 000000000000..11136b3c3626 --- /dev/null +++ b/prdoc/pr_5707.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: Remove ValidateFromChainState + +doc: + - audience: Node Dev + description: | + Removed the `CandidateValidationMessage::ValidateFromChainState`, which was previously used by backing, but is no longer relevant since initial async backing implementation + +crates: + - name: polkadot-node-subsystem-types + bump: major + - name: polkadot-node-core-candidate-validation + bump: major + - name: polkadot + bump: patch + - name: polkadot-overseer + bump: patch diff --git a/prdoc/pr_5716.prdoc b/prdoc/pr_5716.prdoc new file mode 100644 index 000000000000..a98666233729 --- /dev/null +++ b/prdoc/pr_5716.prdoc @@ -0,0 +1,37 @@ +# 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 `lazy_static` with `LazyLock` + +doc: + - audience: Node Dev + description: | + Replace all lazy_static usages with LazyLock from the Rust standard library. This will bring us less dependencies. + +crates: + - name: sp-core + bump: patch + - name: sp-panic-handler + bump: patch + - name: sp-trie + bump: patch + - name: sc-utils + bump: major + - name: cumulus-pallet-parachain-system + bump: patch + - name: sp-consensus-beefy + bump: patch + - name: polkadot-node-primitives + bump: patch + - name: polkadot-node-jaeger + bump: patch + - name: frame-benchmarking-cli + bump: major + - name: sc-offchain + bump: patch + - name: polkadot-dispute-distribution + bump: patch + - name: polkadot-gossip-support + bump: patch + - name: xcm-emulator + bump: patch diff --git a/prdoc/pr_5726.prdoc b/prdoc/pr_5726.prdoc new file mode 100644 index 000000000000..ce666647bad3 --- /dev/null +++ b/prdoc/pr_5726.prdoc @@ -0,0 +1,14 @@ +title: "revive: Limit the amount of static memory" + +doc: + - audience: Runtime Dev + description: | + Limit the amount of static memory a contract can declare. + +crates: + - name: pallet-revive + bump: major + - name: pallet-revive-fixtures + bump: minor + - name: pallet-revive-uapi + bump: patch diff --git a/prdoc/pr_5741.prdoc b/prdoc/pr_5741.prdoc new file mode 100644 index 000000000000..5eafbc90ee85 --- /dev/null +++ b/prdoc/pr_5741.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: make RPC endpoint `chainHead_v1_storage` faster + +doc: + - audience: Node Operator + description: | + The RPC endpoint `chainHead_v1_storage` now relies solely on backpressure to + determine how quickly to serve back values instead of handing back a fixed number + of entries and then expecting the client to ask for more. This should improve the + throughput for bigger storage queries significantly. + + Benchmarks using subxt on localhost: + - Iterate over 10 accounts on westend-dev -> ~2-3x faster + - Fetch 1024 storage values (i.e, not descedant values) -> ~50x faster + - Fetch 1024 descendant values -> ~500x faster + +crates: + - name: sc-rpc-spec-v2 + bump: major + - name: sc-rpc-server + bump: patch + - name: sc-service + bump: major diff --git a/prdoc/pr_5743.prdoc b/prdoc/pr_5743.prdoc new file mode 100644 index 000000000000..0059cbaf790c --- /dev/null +++ b/prdoc/pr_5743.prdoc @@ -0,0 +1,22 @@ +title: "[pallet-revive] write sandbox output according to the provided output buffer length" + +doc: + - audience: Runtime Dev + description: | + Instead of error out if the provided output buffer is smaller than what we want to write, + we can just write what fits into the output buffer instead. + We already write back the actual bytes written to the in-out pointer, + so contracts can check it anyways. + + This in turn introduces the benefit of allowing contracts to implicitly request only a portion + of the returned data from calls and incantations. + Which is especially beneficial for YUL as the call family opcodes have a return data size + argument and this change removes the need to work around it in contract code. + +crates: + - name: pallet-revive + bump: major + - name: pallet-revive-fixtures + bump: patch + - name: pallet-revive-uapi + bump: patch diff --git a/prdoc/pr_5745.prdoc b/prdoc/pr_5745.prdoc new file mode 100644 index 000000000000..7463589378a0 --- /dev/null +++ b/prdoc/pr_5745.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: Implement `try_append` for `StorageNMap` + +doc: + - audience: Runtime Dev + description: | + This PR introduces the `try_append` api which is available on other storage map types, + but missing on `StorageNMap`. + +crates: + - name: frame-support + bump: minor diff --git a/prdoc/pr_5756.prdoc b/prdoc/pr_5756.prdoc new file mode 100644 index 000000000000..525f955d3ac1 --- /dev/null +++ b/prdoc/pr_5756.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: Improve APIs for Tries in Runtime + +doc: + - audience: Runtime Dev + description: | + This PR introduces a trait `ProvingTrie` which has all the function you need to use tries in the runtime. + This trait includes the ability to create, query, and prove data in a trie. Another trait `ProofToHashes` + allows developers to express the computational complexity of proof verification using the proof data. +crates: + - name: sp-runtime + bump: major + - name: frame-support + bump: major diff --git a/prdoc/pr_5762.prdoc b/prdoc/pr_5762.prdoc new file mode 100644 index 000000000000..730b3a46df84 --- /dev/null +++ b/prdoc/pr_5762.prdoc @@ -0,0 +1,10 @@ +title: Fast return for invalid request of node health + +doc: + - audience: Node Dev + description: | + Return directly when invalid request for node health api + +crates: + - name: sc-rpc-server + bump: patch diff --git a/prdoc/pr_5765.prdoc b/prdoc/pr_5765.prdoc new file mode 100644 index 000000000000..e8ecca8ba0ff --- /dev/null +++ b/prdoc/pr_5765.prdoc @@ -0,0 +1,42 @@ +# 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 foreign locations to local accounts converter to all the parachains." + +doc: + - audience: Runtime Dev + description: | + Added foreign locations to local accounts converter to all the parachains. + i.e. added HashedDescription> to LocationToAccountId + + - audience: Runtime User + description: | + Now any user account can have a sovereign account on another chain controlled by the original account. + +crates: + - name: asset-hub-westend-runtime + bump: patch + - name: bridge-hub-rococo-runtime + bump: patch + - name: bridge-hub-westend-runtime + bump: patch + - name: collectives-westend-runtime + bump: patch + - name: contracts-rococo-runtime + bump: patch + - name: coretime-rococo-runtime + bump: patch + - name: coretime-westend-runtime + bump: minor + - name: people-rococo-runtime + bump: patch + - name: people-westend-runtime + bump: patch + - name: penpal-runtime + bump: patch + - name: rococo-runtime + bump: patch + - name: westend-runtime + bump: patch + - name: asset-hub-rococo-runtime + bump: patch diff --git a/prdoc/pr_5768.prdoc b/prdoc/pr_5768.prdoc new file mode 100644 index 000000000000..5c6060065618 --- /dev/null +++ b/prdoc/pr_5768.prdoc @@ -0,0 +1,10 @@ +title: "export NodeHealthProxyLayer" + +doc: + - audience: Node Dev + description: | + This PR export `NodeHealthProxyLayer` from sc-rpc-server. + +crates: + - name: sc-rpc-server + bump: patch diff --git a/prdoc/pr_5774.prdoc b/prdoc/pr_5774.prdoc new file mode 100644 index 000000000000..15aa64f54104 --- /dev/null +++ b/prdoc/pr_5774.prdoc @@ -0,0 +1,13 @@ +title: Avoid unnecessary state reset of allowed_requests when no block requests are sent + +doc: + - audience: Node Dev + description: | + Previously, the state of `allowed_requests` was always reset to the default + even if there were no new block requests. This could cause an edge case + because `peer_block_request()` will return early next time when there are no ongoing block requests. + This patch fixes it by checking whether block requests are empty before updating the state. + +crates: + - name: sc-network-sync + bump: patch diff --git a/prdoc/pr_5779.prdoc b/prdoc/pr_5779.prdoc new file mode 100644 index 000000000000..659a3a19f695 --- /dev/null +++ b/prdoc/pr_5779.prdoc @@ -0,0 +1,38 @@ +title: "[pallet-revive] last call return data API" + +doc: + - audience: Runtime Dev + description: | + This PR introduces 2 new syscall: `return_data_size` and `return_data_copy`, + resembling the semantics of the EVM `RETURNDATASIZE` and `RETURNDATACOPY` opcodes. + + The ownership of `ExecReturnValue` (the return data) has moved to the `Frame`. + This allows implementing the new contract API surface functionality in ext with no additional copies. + Returned data is passed via contract memory, memory is (will be) metered, + hence the amount of returned data can not be statically known, + so we should avoid storing copies of the returned data if we can. + By moving the ownership of the exectuables return value into the `Frame` struct we achieve this. + + A zero-copy implementation of those APIs would be technically possible without that internal change by making + the callsite in the runtime responsible for moving the returned data into the frame after any call. + However, resetting the stored output needs to be handled in ext, since plain transfers will _not_ affect the + stored return data (and we don't want to handle this special call case inside the `runtime` API). + This has drawbacks: + - It can not be tested easily in the mock. + - It introduces an inconsistency where resetting the stored output is handled in ext, + but the runtime API is responsible to store it back correctly after any calls made. + Instead, with ownership of the data in `Frame`, both can be handled in a single place. + Handling both in `fn run()` is more natural and leaves less room for runtime API bugs. + + The returned output is reset each time _before_ running any executable in a nested stack. + This change should not incur any overhead to the overall memory usage as _only_ the returned data from the last + executed frame will be kept around at any time. + +crates: + - name: pallet-revive + bump: major + - name: pallet-revive-fixtures + bump: minor + - name: pallet-revive-uapi + bump: minor + \ No newline at end of file diff --git a/prdoc/pr_5787.prdoc b/prdoc/pr_5787.prdoc new file mode 100644 index 000000000000..59d4118f1905 --- /dev/null +++ b/prdoc/pr_5787.prdoc @@ -0,0 +1,13 @@ +title: "Move bitfield_distribution to blocking task pool and set capacity to 8192" + +doc: + - audience: Node Dev + description: | + This is moving bitfield_distribution to the blocking task pool because it does cpu + intensive work and to make it snappier. Additionally, also increase the message + capacity of the subsystem to make sure the queue does not get full if there is a + burst of messages. + +crates: + - name: polkadot-overseer + bump: patch diff --git a/prdoc/pr_5789.prdoc b/prdoc/pr_5789.prdoc new file mode 100644 index 000000000000..9a808fc89d59 --- /dev/null +++ b/prdoc/pr_5789.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: Prevents EthereumBlobExporter from consuming parameters when returning NotApplicable + +doc: + - audience: Node Dev + description: | + When the EthereumBlobExporter returned a NotApplicable error, it consumed parameters `universal_source`, + `destination` and `message`. As a result, subsequent exporters could not use these values. This PR corrects + this incorrect behaviour. It also changes error type from `Unroutable` to `NotApplicable` when the global consensus + system cannot be extracted from the `universal_source`, or when the source location cannot be converted to an agent + ID. Lastly, it changes the error type from `MissingArgument` to `NotApplicable` when the parachain ID cannot be + extracted from the location. These changes should have no effect - it is purely to correct behvaiour should + multiple exporters be used. + +crates: + - name: snowbridge-router-primitives + bump: patch diff --git a/prdoc/pr_5796.prdoc b/prdoc/pr_5796.prdoc new file mode 100644 index 000000000000..76958e3db4f3 --- /dev/null +++ b/prdoc/pr_5796.prdoc @@ -0,0 +1,8 @@ +title: "Fix RPC relay chain interface" + +doc: + +crates: + - name: cumulus-relay-chain-rpc-interface + bump: none + validate: false diff --git a/prdoc/pr_5804.prdoc b/prdoc/pr_5804.prdoc new file mode 100644 index 000000000000..beef83860cc5 --- /dev/null +++ b/prdoc/pr_5804.prdoc @@ -0,0 +1,42 @@ +# 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: Refactor get_account_id_from_seed / get_from_seed to one common place + +doc: + - audience: Runtime Dev + description: | + `get_account_id_from_seed / get_from_seed` were copied all over the place. This PR removes unnecessary code duplication. + `Keyring::iter()` provides the same functionality and is used instead. + +crates: + - name: polkadot-runtime-common + bump: patch + - name: polkadot-service + bump: major + - name: sp-keyring + bump: major + - name: rococo-runtime + bump: patch + - name: westend-runtime + bump: patch + - name: parachains-common + bump: major + - name: emulated-integration-tests-common + bump: major + - name: xcm-emulator + bump: major + - name: asset-hub-rococo-runtime + bump: patch + - name: asset-hub-westend-runtime + bump: patch + - name: bridge-hub-rococo-runtime + bump: patch + - name: bridge-hub-westend-runtime + bump: patch + - name: collectives-westend-runtime + bump: patch + - name: polkadot-parachain-bin + bump: patch + - name: sp-core + bump: patch diff --git a/prdoc/pr_5807.prdoc b/prdoc/pr_5807.prdoc new file mode 100644 index 000000000000..3447ea64e439 --- /dev/null +++ b/prdoc/pr_5807.prdoc @@ -0,0 +1,16 @@ +title: "[pallet-revive] last call return data API" + +doc: + - audience: Runtime Dev + description: | + This PR adds the EVM chain ID to Config as well as a corresponding runtime API so contracts can query it. + + Related issue: https://github.com/paritytech/revive/issues/44 + +crates: + - name: pallet-revive + bump: major + - name: pallet-revive-fixtures + bump: patch + - name: pallet-revive-uapi + bump: minor diff --git a/prdoc/pr_5811.prdoc b/prdoc/pr_5811.prdoc new file mode 100644 index 000000000000..103fef4bb8b0 --- /dev/null +++ b/prdoc/pr_5811.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: "Improve `import_notification_stream` documentation" + +doc: + - audience: Node Dev + description: | + "Updates the doc comment on the `import_notification_stream` to make its behaviour clearer. Now it specifically states that this notification stream is fired on every import notification after the initial sync, and only when there are re-orgs in the initial sync." + +crates: + - name: sc-client-api + bump: patch diff --git a/prdoc/pr_5824.prdoc b/prdoc/pr_5824.prdoc new file mode 100644 index 000000000000..136cd6bfee84 --- /dev/null +++ b/prdoc/pr_5824.prdoc @@ -0,0 +1,17 @@ +title: "Bump parachains runtime API to v11" + +doc: + - audience: [ Node Dev, Runtime Dev ] + description: | + This PR promotes all staging methods in v10 to stable and releases v11 stable runtime + APIs. + +crates: + - name: polkadot-runtime-parachains + bump: major + - name: rococo-runtime + bump: patch + - name: westend-runtime + bump: patch + - name: polkadot-test-runtime + bump: patch diff --git a/prdoc/pr_5830.prdoc b/prdoc/pr_5830.prdoc new file mode 100644 index 000000000000..10b586e4a4af --- /dev/null +++ b/prdoc/pr_5830.prdoc @@ -0,0 +1,13 @@ +title: "Remove jaeger from approval-voting and approval-distribution" + +doc: + - audience: Node Dev + description: | + Jaeger was remove from approval-voting and approval-distribution because + it did not prove to improve the debugging and it wasted precious cpu cycles. + +crates: + - name: polkadot-approval-distribution + bump: none + - name: polkadot-node-core-approval-voting + bump: none diff --git a/prdoc/pr_5838.prdoc b/prdoc/pr_5838.prdoc new file mode 100644 index 000000000000..f6ce091a12de --- /dev/null +++ b/prdoc/pr_5838.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 wasm builder diagnostics propagation + +doc: + - audience: Runtime Dev + description: | + `substrate-wasm-builder` is used as a build dependency by crates that implement FRAME runtimes. + Errors that occur in these crates can not be detected by IDEs that use rust-analyzer as a language + server because rust-analyzer needs the errors to be reported as diagnostic message in json format to + be able to publish them to language server clients. This PR adds `WASM_BUILD_CARGO_ARGS` environment + variable, which can hold a space separated list of args that will be parsed and passed to the `cargo` + command that it is used for building against wasm target. It can be used for the stated initial case, + but it is also flexible enough to allow passing other arguments or formatting the messages using another + available type. +crates: + - name: substrate-wasm-builder + bump: patch + diff --git a/prdoc/pr_5839.prdoc b/prdoc/pr_5839.prdoc new file mode 100644 index 000000000000..1dc95fe5c333 --- /dev/null +++ b/prdoc/pr_5839.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 internal workaround for compiler bug + +doc: + - audience: + - Runtime Dev + - Node Dev + description: | + Remove a workaround we had in the `impl_runtime_apis` macro for a compiler bug that has been long fixed. + No impact on downstream users is expected, except relaxed trait bounds in a few places where the compiler + is now able to deduce more type info itself. + +crates: + - name: sp-api-proc-macro + bump: patch + - name: frame-support-procedural + bump: patch + - name: polkadot-parachain-lib + bump: patch diff --git a/prdoc/pr_5845.prdoc b/prdoc/pr_5845.prdoc new file mode 100644 index 000000000000..6b214d7599b5 --- /dev/null +++ b/prdoc/pr_5845.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: Fix compilation after renaming some of benchmarks in pallet_revive. + +doc: + - audience: Runtime Dev + description: | + Changed the "instr" benchmark so that it should no longer return to little weight. It is still bogus but at least benchmarking should not work. + +crates: + - name: pallet-revive + bump: patch + - name: pallet-revive-fixtures + bump: major \ No newline at end of file diff --git a/prdoc/pr_5856.prdoc b/prdoc/pr_5856.prdoc new file mode 100644 index 000000000000..383e95e3da88 --- /dev/null +++ b/prdoc/pr_5856.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: Extend state tracking of chainHead to capture notification gaps + +doc: + - audience: Node Dev + description: | + This PR extends the state tracking of the RPC-v2 chainHead methods. + ChainHead tracks the reported blocks to detect notification gaps. + This state tracking ensures we can detect `NewBlock` events for + which we did not report previously the parent hash. + +crates: + - name: sc-rpc-spec-v2 + bump: minor + diff --git a/prdoc/pr_5857.prdoc b/prdoc/pr_5857.prdoc new file mode 100644 index 000000000000..00ee0a8cc704 --- /dev/null +++ b/prdoc/pr_5857.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: "Beefy equivocation: check all the MMR roots" + +doc: + - audience: + - Runtime Dev + - Runtime User + description: | + This PR adjusts the logic for `report_fork_voting` exposed by `pallet-beefy`. + Normally, the BEEFY protocol only accepts a single MMR Root entry in a commitment's payload. But, in order to + be extra careful, now, when validating equivocation reports, we check all the MMR roots, if there are more. + +crates: + - name: sp-consensus-beefy + bump: patch + - name: pallet-beefy-mmr + bump: patch diff --git a/prdoc/pr_5859.prdoc b/prdoc/pr_5859.prdoc new file mode 100644 index 000000000000..edb3008238b3 --- /dev/null +++ b/prdoc/pr_5859.prdoc @@ -0,0 +1,11 @@ +title: Add number of live peers available for requests + +doc: + - audience: [Node Operator, Node Dev] + description: | + This PR adds a new metric for the number of live peers available for beefy requests. + The metric is exposed under the name `substrate_beefy_on_demand_live_peers`. + +crates: + - name: sc-consensus-beefy + bump: minor diff --git a/prdoc/pr_5861.prdoc b/prdoc/pr_5861.prdoc new file mode 100644 index 000000000000..e2187dc1bdde --- /dev/null +++ b/prdoc/pr_5861.prdoc @@ -0,0 +1,37 @@ +title: "[pallet-revive] immutable data storage" + +doc: + - audience: Runtime Dev + description: | + This PR introduces the concept of immutable storage data, used for + [Solidity immutable variables](https://docs.soliditylang.org/en/latest/contracts.html#immutable). + + This is a minimal implementation. Immutable data is attached to a contract; to + `ContractInfo` fixed in size, we only store the length there, and store the immutable + data in a dedicated storage map instead. Which comes at the cost of requiring an + storage read (costly) for contracts using this feature. + + We discussed more optimal solutions not requiring any additional storage accesses + internally, but they turned out to be non-trivial to implement. Another optimization + benefiting multiple calls to the same contract in a single call stack would be to cache + the immutable data in `Stack`. However, this potential creates a DOS vulnerability (the + attack vector is to call into as many contracts in a single stack as possible, where + they all have maximum immutable data to fill the cache as efficiently as possible). So + this either has to be guaranteed to be a non-issue by limits, or, more likely, to have + some logic to bound the cache. Eventually, we should think about introducing the concept + of warm and cold storage reads (akin to EVM). Since immutable variables are commonly + used in contracts, this change is blocking our initial launch and we should only + optimize it properly in follow-ups. + + This PR also disables the `set_code_hash` API (which isn't usable for Solidity contracts + without pre-compiles anyways). With immutable storage attached to contracts, we now want + to run the constructor of the new code hash to collect the immutable data during + `set_code_hash`. This will be implemented in a follow up PR. + +crates: + - name: pallet-revive + bump: major + - name: pallet-revive-fixtures + bump: patch + - name: pallet-revive-uapi + bump: minor diff --git a/prdoc/pr_5866.prdoc b/prdoc/pr_5866.prdoc new file mode 100644 index 000000000000..44fffe1d2129 --- /dev/null +++ b/prdoc/pr_5866.prdoc @@ -0,0 +1,23 @@ +title: "[pallet-revive] Ethereum JSON-RPC integration" + +doc: + - audience: Runtime Dev + description: | + Related PR: https://github.com/paritytech/revive-ethereum-rpc/pull/5 + + Changes Included: + - A new pallet::call eth_transact. + - A custom UncheckedExtrinsic struct to dispatch unsigned eth_transact calls from an Ethereum JSON-RPC proxy. + - Generated types and traits to support implementing a JSON-RPC Ethereum proxy. +crates: + - name: pallet-revive + bump: major + - name: pallet-revive-fixtures + bump: patch + - name: pallet-revive-mock-network + bump: patch + - name: pallet-revive-uapi + bump: patch + - name: polkadot-sdk + bump: patch + diff --git a/prdoc/pr_5872.prdoc b/prdoc/pr_5872.prdoc new file mode 100644 index 000000000000..cf4f0b24f8db --- /dev/null +++ b/prdoc/pr_5872.prdoc @@ -0,0 +1,13 @@ +title: '[omni-bencher] Make all runtimes work' +doc: +- audience: Runtime Dev + description: |- + Changes: + - Add `--exclude-pallets` to exclude some pallets from runtimes where we dont have genesis presets yet + - Make `--genesis-builder-policy=none` work with `--runtime` + - CI: Run the frame-omni-bencher for all runtimes +crates: +- name: frame-benchmarking-cli + bump: major +- name: contracts-rococo-runtime + bump: patch diff --git a/prdoc/pr_5875.prdoc b/prdoc/pr_5875.prdoc new file mode 100644 index 000000000000..fb308c02dde5 --- /dev/null +++ b/prdoc/pr_5875.prdoc @@ -0,0 +1,47 @@ +title: "Remove jaeger from polkadot" + +doc: + - audience: [ Node Dev, Node Operator ] + description: | + Jaeger was remove from the codebase because it was not used by anyone + and it did not help with the debugging. + +crates: + - name: polkadot-sdk + bump: patch + - name: polkadot-overseer + bump: major + - name: polkadot-node-subsystem + bump: patch + - name: polkadot-node-subsystem-types + bump: major + - name: polkadot-node-network-protocol + bump: major + - name: polkadot-service + bump: major + - name: polkadot-availability-distribution + bump: patch + - name: polkadot-availability-recovery + bump: patch + - name: polkadot-node-core-av-store + bump: patch + - name: polkadot-statement-distribution + bump: patch + - name: polkadot-collator-protocol + bump: patch + - name: polkadot-availability-bitfield-distribution + bump: patch + - name: polkadot-network-bridge + bump: patch + - name: polkadot-node-collation-generation + bump: patch + - name: polkadot-node-core-bitfield-signing + bump: patch + - name: polkadot-node-core-candidate-validation + bump: patch + - name: polkadot-node-core-provisioner + bump: patch + - name: cumulus-relay-chain-inprocess-interface + bump: patch + - name: polkadot-cli + bump: major diff --git a/prdoc/pr_5880.prdoc b/prdoc/pr_5880.prdoc new file mode 100644 index 000000000000..b246bff11f8d --- /dev/null +++ b/prdoc/pr_5880.prdoc @@ -0,0 +1,11 @@ +title: Fix prospective parachains test to use shuffled candidate list + +doc: + - audience: Node Dev + description: | + Fix prospective parachains test to use shuffled candidate list. + Resolves https://github.com/paritytech/polkadot-sdk/issues/5617. + +crates: + - name: polkadot-node-core-prospective-parachains + bump: none diff --git a/prdoc/pr_5886.prdoc b/prdoc/pr_5886.prdoc new file mode 100644 index 000000000000..f5e597281197 --- /dev/null +++ b/prdoc/pr_5886.prdoc @@ -0,0 +1,18 @@ +title: Bump some dependencies +doc: +- audience: Runtime Dev + description: |- + This bumps `ethbloom`, `ethereum-types`, `primitive-types` and `rlp` to their latest version. + + Fixes: https://github.com/paritytech/polkadot-sdk/issues/5870 +crates: +- name: sc-consensus-babe + bump: patch +- name: pallet-babe + bump: patch +- name: pallet-revive + bump: patch +- name: sp-runtime + bump: patch +- name: bp-polkadot-core + bump: major diff --git a/prdoc/pr_5888.prdoc b/prdoc/pr_5888.prdoc new file mode 100644 index 000000000000..9552eada6915 --- /dev/null +++ b/prdoc/pr_5888.prdoc @@ -0,0 +1,16 @@ +title: 'parachain-system: send core selector ump signal' + +doc: + - audience: Runtime Dev + description: | + Send the core selector ump signal in cumulus. Guarded by a compile time feature called `experimental-ump-signals` + until nodes are upgraded to a version that includes https://github.com/paritytech/polkadot-sdk/pull/5423 for + gracefully handling ump signals. + +crates: + - name: cumulus-client-consensus-aura + bump: minor + - name: cumulus-pallet-parachain-system + bump: major + - name: cumulus-primitives-core + bump: minor diff --git a/prdoc/pr_5892.prdoc b/prdoc/pr_5892.prdoc new file mode 100644 index 000000000000..b909e443328b --- /dev/null +++ b/prdoc/pr_5892.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: "Treasury: add migration to clean up unapproved deprecated proposals" + +doc: + - audience: Runtime Dev + description: | + It is no longer possible to create `Proposals` storage item in `pallet-treasury` due to migration from + governance v1 model but there are some `Proposals` whose bonds are still on hold with no way to release them. + The purpose of this migration is to clear `Proposals` which are stuck and return bonds to the proposers. + +crates: + - name: pallet-treasury + bump: patch + - name: rococo-runtime + bump: patch diff --git a/prdoc/pr_5901.prdoc b/prdoc/pr_5901.prdoc new file mode 100644 index 000000000000..4d3bce7f45a2 --- /dev/null +++ b/prdoc/pr_5901.prdoc @@ -0,0 +1,3 @@ +crates: + - name: polkadot-node-core-dispute-coordinator + bump: none diff --git a/prdoc/pr_5911.prdoc b/prdoc/pr_5911.prdoc new file mode 100644 index 000000000000..8b063242f24f --- /dev/null +++ b/prdoc/pr_5911.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: Removed the possibility to start a shell parachain node + +doc: + - audience: Node Dev + description: | + Removed the possibility to start a shell parachain node using the polkadot-parachain-lib or + polkadot-parachain-bin. + +crates: + - name: polkadot-parachain-lib + bump: minor + - name: polkadot-parachain-bin + bump: minor diff --git a/prdoc/pr_5915.prdoc b/prdoc/pr_5915.prdoc new file mode 100644 index 000000000000..a9303e2563d1 --- /dev/null +++ b/prdoc/pr_5915.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: Omni-Node renamings + +doc: + - audience: Node Dev + description: | + This PR renames the `polkadot-parachain-lib` crate to `polkadot-omni-node-lib` and introduces a new + `polkadot-omni-node` binary. + +crates: + - name: polkadot-omni-node-lib + bump: patch + - name: polkadot-parachain-bin + bump: patch + - name: polkadot-sdk + bump: patch diff --git a/prdoc/pr_5917.prdoc b/prdoc/pr_5917.prdoc new file mode 100644 index 000000000000..54b2e42ed9c3 --- /dev/null +++ b/prdoc/pr_5917.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: "XCM paid execution barrier supports more origin altering instructions" + +doc: + - audience: Runtime Dev + description: | + Updates the `AllowTopLevelPaidExecutionFrom` barrier to also support messages that + use `DescendOrigin` or `AliasOrigin` for altering the computed origin during execution. + +crates: + - name: staging-xcm-builder + bump: patch diff --git a/prdoc/pr_5924.prdoc b/prdoc/pr_5924.prdoc new file mode 100644 index 000000000000..26bde8eec0de --- /dev/null +++ b/prdoc/pr_5924.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: Bump PoV request timeout + +doc: + - audience: Node Dev + description: | + With asynchronous backing and PoV size 10MB, we can increase the PoV request timeout from 1.2s to 2s. + +crates: + - name: polkadot-node-network-protocol + bump: patch diff --git a/prdoc/pr_5939.prdoc b/prdoc/pr_5939.prdoc new file mode 100644 index 000000000000..babb26281ecd --- /dev/null +++ b/prdoc/pr_5939.prdoc @@ -0,0 +1,14 @@ +title: "[pallet-revive] Bump PolkaVM and add static code validation" + +doc: + - audience: Runtime Dev + description: | + Statically validate basic block sizes and instructions. + +crates: + - name: pallet-revive + bump: major + - name: pallet-revive-fixtures + bump: minor + - name: pallet-revive-uapi + bump: patch diff --git a/prdoc/pr_5941.prdoc b/prdoc/pr_5941.prdoc new file mode 100644 index 000000000000..4e88400f4ef0 --- /dev/null +++ b/prdoc/pr_5941.prdoc @@ -0,0 +1,16 @@ +title: "`SolochainDefaultConfig`: Use correct `AccountData`" + +doc: + - audience: Runtime Dev + description: | + `SolochainDefaultConfig` by default was setting `AccountData` to `AccountInfo`. + Thus, the actual account data was recursively nested the same type. By default + it should be set `()`, because this is the only reasonable `AccountData`. + + If you have used `SolochainDefaultConfig` before and did not overwrite, `AccountData` + you should now overwrite it to `AccountInfo` or you will need to write a migration to + change the data. + +crates: + - name: frame-system + bump: patch diff --git a/prdoc/pr_5946.prdoc b/prdoc/pr_5946.prdoc new file mode 100644 index 000000000000..9a858c980a19 --- /dev/null +++ b/prdoc/pr_5946.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: "[FRAME] fix: Do not emit `Issued { amount: 0 }` event" + +doc: + - audience: + - Runtime Dev + - Runtime User + description: | + Filter out `Issued` events in `pallet-balances` module when its balance amount is zero. + +crates: + - name: pallet-balances + bump: patch diff --git a/prdoc/pr_5994.prdoc b/prdoc/pr_5994.prdoc new file mode 100644 index 000000000000..425653e52646 --- /dev/null +++ b/prdoc/pr_5994.prdoc @@ -0,0 +1,3 @@ +crates: + - name: sc-consensus-babe + bump: none diff --git a/prdoc/pr_5998.prdoc b/prdoc/pr_5998.prdoc new file mode 100644 index 000000000000..e3279051ca6a --- /dev/null +++ b/prdoc/pr_5998.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: Fix memory leak in litep2p public addresses + +doc: + - audience: [ Node Dev, Node Operator ] + description: | + This PR bounds the number of public addresses of litep2p to 32 entries. + This ensures we do not increase the number of addresses over time, and that the DHT + authority records will not exceed the upper size limit. + +crates: + - name: sc-network + bump: patch diff --git a/prdoc/pr_5999.prdoc b/prdoc/pr_5999.prdoc new file mode 100644 index 000000000000..5252de6289d1 --- /dev/null +++ b/prdoc/pr_5999.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: "Westend: Constant yearly emission" + +doc: + - audience: Runtime User + description: | + Integrating the new inflation approach from https://github.com/polkadot-fellows/runtimes/pull/471 + into Westend first to check that it is working. + + +crates: + - name: westend-runtime + bump: patch diff --git a/prdoc/pr_6015.prdoc b/prdoc/pr_6015.prdoc new file mode 100644 index 000000000000..d5a7d1e18d5d --- /dev/null +++ b/prdoc/pr_6015.prdoc @@ -0,0 +1,9 @@ +title: Rename QueueEvent::StartWork +doc: +- audience: Node Dev + description: |- + When we send `QueueEvent::StartWork`, we have already completed the execution. Therefore, `QueueEvent::FinishWork` is a better match. + +crates: +- name: polkadot-node-core-pvf + bump: patch diff --git a/prdoc/pr_6022.prdoc b/prdoc/pr_6022.prdoc new file mode 100644 index 000000000000..804d46af6613 --- /dev/null +++ b/prdoc/pr_6022.prdoc @@ -0,0 +1,14 @@ +title: '[Coretime chain] Add high assignment count mitigation to testnets' +doc: +- audience: Runtime User + description: | + We can handle a maximum of 28 assignments inside one XCM, while it's possible to have 80 (if a + region is interlaced 79 times). This can be chunked on the coretime chain side but currently the + relay does not support this. This PR truncates the additional assignments on Rococo and Westend + to mitigate this until the relay is fixed. The first 27 assignments are taken, the final 28th is + used to pad with idle to complete the mask. Any other assignments are dropped. +crates: +- name: coretime-rococo-runtime + bump: patch +- name: coretime-westend-runtime + bump: patch diff --git a/prdoc/pr_6023.prdoc b/prdoc/pr_6023.prdoc new file mode 100644 index 000000000000..3b3b5a4cb5fd --- /dev/null +++ b/prdoc/pr_6023.prdoc @@ -0,0 +1,11 @@ +title: Fix storage in pallet section + +doc: + - audience: Runtime Dev + description: | + Fix compilation of `pallet::storage` in a pallet section: a local binding definition was not + correctly referenced due to macro hygiene. + +crates: + - name: frame-support-procedural + bump: patch diff --git a/prdoc/pr_6025.prdoc b/prdoc/pr_6025.prdoc new file mode 100644 index 000000000000..64072c0ae632 --- /dev/null +++ b/prdoc/pr_6025.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: Refactor staking pallet benchmarks to `v2` + +doc: + - audience: Runtime Dev + description: | + Update benchmarks in staking pallet to the second version of the `frame_benchmarking` runtime benchmarking framework. + +crates: + - name: pallet-staking + bump: patch \ No newline at end of file diff --git a/prdoc/pr_6027.prdoc b/prdoc/pr_6027.prdoc new file mode 100644 index 000000000000..36bdb57b25f5 --- /dev/null +++ b/prdoc/pr_6027.prdoc @@ -0,0 +1,9 @@ +title: Remove pallet::getter from pallet-offences +doc: + - audience: Runtime Dev + description: | + This PR removes pallet::getter from pallet-offences from type Reports. It also adds a test to verify that retrieval of Reports still works with storage::getter. + +crates: + - name: pallet-offences + bump: patch diff --git a/prdoc/pr_6032.prdoc b/prdoc/pr_6032.prdoc new file mode 100644 index 000000000000..ed47750f8fd7 --- /dev/null +++ b/prdoc/pr_6032.prdoc @@ -0,0 +1,11 @@ +title: Fix `feeless_if` in pallet section + +doc: + - audience: Runtime Dev + description: | + Fix compilation with `pallet::feeless_if` in a pallet section: a local binding unexpectely + resolved to a macro definition. + +crates: + - name: frame-support-procedural + bump: patch diff --git a/prdoc/pr_6039.prdoc b/prdoc/pr_6039.prdoc new file mode 100644 index 000000000000..e14ea8f3e17b --- /dev/null +++ b/prdoc/pr_6039.prdoc @@ -0,0 +1,54 @@ +# 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 Trusted Query API calls." + +doc: + - audience: Runtime Dev + description: | + Added is_trusted_reserve and is_trusted_teleporter API calls to all the runtimes. + Given an asset and a location, they return if the chain trusts that location as a reserve or teleporter for that asset respectively. + You can implement them on your runtime by simply calling a helper function on `pallet-xcm`. + ```rust + impl xcm_runtime_apis::trusted_query::TrustedQueryApi for Runtime { + fn is_trusted_reserve(asset: VersionedAsset, location: VersionedLocation) -> Result { + PolkadotXcm::is_trusted_reserve(asset, location) + } + fn is_trusted_teleporter(asset: VersionedAsset, location: VersionedLocation) -> Result { + PolkadotXcm::is_trusted_teleporter(asset, location) + } + } + ``` + + - audience: Runtime User + description: | + There's a new runtime API to check if a chain trust a Location as a reserve or teleporter for a given Asset. + It's implemented in all the relays and system parachains in Westend and Rococo. + +crates: + - 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: asset-hub-rococo-runtime + bump: minor + - name: pallet-xcm + bump: minor + - name: xcm-runtime-apis + bump: minor diff --git a/prdoc/pr_6045.prdoc b/prdoc/pr_6045.prdoc new file mode 100644 index 000000000000..d1b3fb4e77f2 --- /dev/null +++ b/prdoc/pr_6045.prdoc @@ -0,0 +1,10 @@ +title: '[pallet-revive] ensure the return data is reset if no frame was instantiated' + +doc: +- audience: + - Runtime Dev + description: Failed call frames do not produce new return data but still reset it. + +crates: +- name: pallet-revive + bump: patch diff --git a/prdoc/pr_6058.prdoc b/prdoc/pr_6058.prdoc new file mode 100644 index 000000000000..5b99467b413f --- /dev/null +++ b/prdoc/pr_6058.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: backpressure `chainhead_v1_follow` + +doc: + - audience: Node Operator + description: | + The RPC endpoint `chainHead_v1_follow` now relies on backpressure + to determine whether or not the subscription should be closed instead of continuing to send more events + to a consumer which can't keep up. + This should significantly improve memory consumption as substrate will be keeping less messages in memory. + +crates: + - name: sc-rpc-spec-v2 + bump: major + - name: sc-rpc + bump: major diff --git a/prdoc/pr_6061.prdoc b/prdoc/pr_6061.prdoc new file mode 100644 index 000000000000..742e69ea9eca --- /dev/null +++ b/prdoc/pr_6061.prdoc @@ -0,0 +1,10 @@ +title: Remove check-migrations for rococo chain + +doc: + - audience: [Runtime User] + description: | + This PR adds the missing `cumulus_pallet_xcmp_queue` v5 migration to the coretime-westend runtime. + +crates: +- name: coretime-westend-runtime + bump: none diff --git a/prdoc/pr_6087.prdoc b/prdoc/pr_6087.prdoc new file mode 100644 index 000000000000..db083ba645b9 --- /dev/null +++ b/prdoc/pr_6087.prdoc @@ -0,0 +1,12 @@ +title: Expose private structs in pallet_nfts and pallet_uniques. + +doc: + - audience: Runtime Dev + description: | + PR changes certain structs in pallet_nfts and pallet_uniques into public. It also changes 2 storages (collection & asset metadata) into public in pallet_uniques. + +crates: + - name: pallet-nfts + bump: patch + - name: pallet-uniques + bump: patch diff --git a/prdoc/pr_6088.prdoc b/prdoc/pr_6088.prdoc new file mode 100644 index 000000000000..93e435bbd458 --- /dev/null +++ b/prdoc/pr_6088.prdoc @@ -0,0 +1,14 @@ +title: "[pallet-revive] EXTCODEHASH to match EIP-1052" + +doc: + - audience: Runtime Dev + description: | + Update `ext_code_hash` to match [EIP-1052](https://eips.ethereum.org/EIPS/eip-1052) specs. + +crates: + - name: pallet-revive + bump: major + - name: pallet-revive-fixtures + bump: patch + - name: pallet-revive-uapi + bump: major diff --git a/prdoc/pr_6129.prdoc b/prdoc/pr_6129.prdoc new file mode 100644 index 000000000000..61719c213e8d --- /dev/null +++ b/prdoc/pr_6129.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: "Improved TrustedQueryAPI signatures." + +doc: + - audience: Runtime Dev + description: | + Changed returned type of API methods from `Result` to a typed one: + `type XcmTrustedQueryResult = Result` + +crates: + - name: asset-hub-westend-runtime + bump: patch + - name: bridge-hub-rococo-runtime + bump: patch + - name: bridge-hub-westend-runtime + bump: patch + - name: collectives-westend-runtime + bump: patch + - name: contracts-rococo-runtime + bump: patch + - name: coretime-rococo-runtime + bump: patch + - name: coretime-westend-runtime + bump: patch + - name: people-rococo-runtime + bump: patch + - name: people-westend-runtime + bump: patch + - name: penpal-runtime + bump: patch diff --git a/prdoc/pr_6141.prdoc b/prdoc/pr_6141.prdoc new file mode 100644 index 000000000000..d9994ac4f842 --- /dev/null +++ b/prdoc/pr_6141.prdoc @@ -0,0 +1,11 @@ +title: Improve `CheckMetadataHash` transaction extension weight and logic + +doc: + - audience: Runtime Dev + description: | + The compilation now panics if the optional compile-time environment variable `RUNTIME_METADATA_HASH` contains an invalid value. + The weight for the `CheckMetadataHash` transaction extension is more accurate as it is almost compile-time. + +crates: +- name: frame-metadata-hash-extension + bump: minor diff --git a/prdoc/schema_user.json b/prdoc/schema_user.json index e6c0468aaf85..5f7d460a5cc0 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/bench-all.sh b/scripts/bench-all.sh deleted file mode 100755 index e5512e26bbad..000000000000 --- a/scripts/bench-all.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -set -eu -o pipefail -shopt -s inherit_errexit -shopt -s globstar - -. "$(realpath "$(dirname "${BASH_SOURCE[0]}")/command-utils.sh")" - -get_arg optional --pallet "$@" -PALLET="${out:-""}" - -if [[ ! -z "$PALLET" ]]; then - . "$(dirname "${BASH_SOURCE[0]}")/lib/bench-all-pallet.sh" "$@" -else - . "$(dirname "${BASH_SOURCE[0]}")/bench.sh" --subcommand=all "$@" -fi diff --git a/scripts/bench.sh b/scripts/bench.sh deleted file mode 100755 index 2f4ef7ec6a14..000000000000 --- a/scripts/bench.sh +++ /dev/null @@ -1,117 +0,0 @@ -#!/bin/bash -# Initially based on https://github.com/paritytech/bench-bot/blob/cd3b2943d911ae29e41fe6204788ef99c19412c3/bench.js - -# Most external variables used in this script, such as $GH_CONTRIBUTOR, are -# related to https://github.com/paritytech/try-runtime-bot - -# This script relies on $GITHUB_TOKEN which is probably a protected GitLab CI -# variable; if this assumption holds true, it is implied that this script should -# be ran only on protected pipelines - -set -eu -o pipefail -shopt -s inherit_errexit - -# realpath allows to reuse the current -BENCH_ROOT_DIR=$(realpath "$(dirname "${BASH_SOURCE[0]}")") - -. "$(realpath "$(dirname "${BASH_SOURCE[0]}")/command-utils.sh")" - -repository_name="$(basename "$PWD")" - -get_arg optional --target_dir "$@" -target_dir="${out:-""}" - -get_arg optional --noexit "$@" -noexit="${out:-""}" - -output_path="." - -profile="production" - -if [[ "$repository_name" == "polkadot-sdk" ]]; then - output_path="./$target_dir" -fi - -cargo_run_benchmarks="cargo run --quiet --profile=${profile}" - -echo "Repository: $repository_name" -echo "Target Dir: $target_dir" -echo "Output Path: $output_path" - -cargo_run() { - echo "Running $cargo_run_benchmarks" "${args[@]}" - - # if not patched with PATCH_something=123 then use --locked - if [[ -z "${BENCH_PATCHED:-}" ]]; then - cargo_run_benchmarks+=" --locked" - fi - - $cargo_run_benchmarks "${args[@]}" -} - - -main() { - - # Remove the "github" remote since the same repository might be reused by a - # GitLab runner, therefore the remote might already exist from a previous run - # in case it was not cleaned up properly for some reason - &>/dev/null git remote remove github || : - - tmp_dirs=() - cleanup() { - exit_code=$? - # Clean up the "github" remote at the end since it contains the - # $GITHUB_TOKEN secret, which is only available for protected pipelines on - # GitLab - &>/dev/null git remote remove github || : - rm -rf "${tmp_dirs[@]}" - echo "Done, exit: $exit_code" - exit $exit_code - } - - # avoid exit if --noexit is passed - if [ -z "$noexit" ]; then - trap cleanup EXIT - fi - - # set -x - - get_arg required --subcommand "$@" - local subcommand="${out:-""}" - - case "$subcommand" in - runtime|pallet|xcm) - echo 'Running bench_pallet' - . "$BENCH_ROOT_DIR/lib/bench-pallet.sh" "$@" - ;; - overhead) - echo 'Running bench_overhead' - . "$BENCH_ROOT_DIR/lib/bench-overhead.sh" "$@" - ;; - all) - echo "Running all-$target_dir" - . "$BENCH_ROOT_DIR/lib/bench-all-${target_dir}.sh" "$@" - ;; - *) - die "Invalid subcommand $subcommand to process_args" - ;; - esac - - # set +x - - # in case we used diener to patch some dependency during benchmark execution, - # revert the patches so that they're not included in the diff - git checkout --quiet HEAD Cargo.toml - - # Save the generated weights to GitLab artifacts in case commit+push fails - echo "Showing weights diff for command" - git diff -P | tee -a "${ARTIFACTS_DIR}/weights.patch" - echo "Wrote weights patch to \"${ARTIFACTS_DIR}/weights.patch\"" - - - # instead of using `cargo run --locked`, we allow the Cargo files to be updated - # but avoid committing them. It is so `cmd_runner_apply_patches` can work - git restore --staged Cargo.* -} - -main "$@" diff --git a/scripts/command-utils.sh b/scripts/command-utils.sh deleted file mode 100644 index 252e4c86480e..000000000000 --- a/scripts/command-utils.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/env bash - -if [ "${LOADED_UTILS_SH:-}" ]; then - return -else - export LOADED_UTILS_SH=true -fi - -export ARTIFACTS_DIR="$PWD/.git/.artifacts" - -die() { - if [ "${1:-}" ]; then - >&2 echo "$1" - fi - exit 1 -} - -get_arg() { - local arg_type="$1" - shift - - local is_required - case "$arg_type" in - required|required-many) - is_required=true - ;; - optional|optional-many) ;; - *) - die "Invalid is_required argument \"$2\" in get_arg" - ;; - esac - - local has_many_values - if [ "${arg_type: -6}" == "-many" ]; then - has_many_values=true - fi - - local option_arg="$1" - shift - - local args=("$@") - - unset out - out=() - - local get_next_arg - for arg in "${args[@]}"; do - if [ "${get_next_arg:-}" ]; then - out+=("$arg") - unset get_next_arg - if [ ! "${has_many_values:-}" ]; then - break - fi - # --foo=bar (get the value after '=') - elif [ "${arg:0:$(( ${#option_arg} + 1 ))}" == "$option_arg=" ]; then - out+=("${arg:$(( ${#option_arg} + 1 ))}") - if [ ! "${has_many_values:-}" ]; then - break - fi - # --foo bar (get the next argument) - elif [ "$arg" == "$option_arg" ]; then - get_next_arg=true - fi - done - - # arg list ended with --something but no argument was provided next - if [ "${get_next_arg:-}" ]; then - die "Expected argument after \"${args[-1]}"\" - fi - - if [ "${out[0]:-}" ]; then - if [ ! "${has_many_values:-}" ]; then - out="${out[0]}" - fi - elif [ "${is_required:-}" ]; then - die "Argument $option_arg is required, but was not found" - else - unset out - fi -} diff --git a/scripts/generate-umbrella.py b/scripts/generate-umbrella.py index 0bdf160e63b1..e1ef6de86f9c 100644 --- a/scripts/generate-umbrella.py +++ b/scripts/generate-umbrella.py @@ -5,10 +5,10 @@ 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 @@ """ 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. @@ -63,7 +64,7 @@ def main(path, version): if manifest['lib']['proc-macro']: nostd_crates.append((crate, path)) continue - + # Crates without a lib.rs cannot be no_std if not os.path.exists(lib_path): print(f"Skipping {crate.name} as it does not have a 'src/lib.rs'") @@ -85,16 +86,18 @@ def main(path, version): # Sort by name std_crates.sort(key=lambda x: x[0].name) nostd_crates.sort(key=lambda x: x[0].name) + + runtime_crates = [crate for crate in nostd_crates if 'frame' in crate[0].name or crate[0].name.startswith('sp-')] all_crates = std_crates + nostd_crates all_crates.sort(key=lambda x: x[0].name) dependencies = {} for (crate, path) in nostd_crates: dependencies[crate.name] = {"path": f"../{path}", "default-features": False, "optional": True} - + for (crate, path) in std_crates: dependencies[crate.name] = {"path": f"../{path}", "default-features": False, "optional": True} - + # The empty features are filled by Zepter features = { "default": [ "std" ], @@ -104,9 +107,11 @@ def main(path, version): "serde": [], "experimental": [], "with-tracing": [], - "runtime": list([f"{d.name}" for d, _ in nostd_crates]), + "runtime-full": list([f"{d.name}" for d, _ in nostd_crates]), + "runtime": list([f"{d.name}" for d, _ in runtime_crates]), "node": ["std"] + list([f"{d.name}" for d, _ in std_crates]), "tuples-96": [], + "riscv": [], } manifest = { @@ -118,7 +123,7 @@ def main(path, version): "description": "Polkadot SDK umbrella crate.", "license": "Apache-2.0", "metadata": { "docs": { "rs": { - "features": ["runtime", "node"], + "features": ["runtime-full", "node"], "targets": ["x86_64-unknown-linux-gnu"] }}} }, @@ -158,9 +163,9 @@ def main(path, version): f.write(f'\n/// {desc}') f.write(f'\n#[cfg(feature = "{crate.name}")]\n') f.write(f"pub use {use};\n") - + print(f"Wrote {lib_path}") - + add_to_workspace(workspace.path) """ @@ -187,7 +192,7 @@ def add_to_workspace(path): manifest = re.sub(r'^members = \[', 'members = [\n "umbrella",', manifest, flags=re.M) with open(os.path.join(path, "Cargo.toml"), "w") as f: f.write(manifest) - + os.chdir(path) # hack os.system("cargo metadata --format-version 1 > /dev/null") # update the lockfile os.system(f"zepter") # enable the features @@ -202,3 +207,4 @@ def parse_args(): if __name__ == "__main__": args = parse_args() main(args.sdk, args.version) + diff --git a/scripts/getting-started.sh b/scripts/getting-started.sh new file mode 100755 index 000000000000..d5fd545481d1 --- /dev/null +++ b/scripts/getting-started.sh @@ -0,0 +1,179 @@ +#!/usr/bin/env sh + +set -e + +prompt() { + while true; do + printf "$1 [y/N]\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 + * ) printf "Please answer yes or no.\n";; + esac + done +} + +prompt_default_yes() { + while true; do + printf "$1 [Y/n]\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 + * ) printf "Please answer yes or no.\n";; + esac + done +} + +clone_and_enter_template() { + template="$1" # minimal, solochain, or parachain + if [ -d "${template}-template" ]; then + printf "\n✅︎ ${template}-template directory already exists. -> Entering.\n" + else + printf "\n↓ Let's grab the ${template} template from github.\n" + git clone --quiet https://github.com/paritytech/polkadot-sdk-${template}-template.git ${template}-template + fi + cd ${template}-template +} + +cat </dev/null 2>&1; then + printf "\n✅︎🍺 Homebrew already installed.\n" + else + if prompt_default_yes "\n🍺 Homebrew is not installed. Install it?\n"; then + printf "🍺 Installing Homebrew.\n" + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" + else + printf "❌ Cannot continue without homebrew. Aborting.\n" + exit 1 + fi + fi + + brew update + if command -v git >/dev/null 2>&1; then + printf "\n✅︎🍺 git already installed.\n" + else + if prompt_default_yes "\n🍺 git seems to be missing but we will need it; install git?\n"; then + brew install git + else + printf "❌ Cannot continue without git. Aborting.\n" + exit 1 + fi + fi + + if prompt "\n🍺 Install cmake, openssl and protobuf?"; then + brew install cmake openssl protobuf + else + printf "🍺 Assuming cmake, openssl and protobuf are present.\n" + 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 + printf "\n🐧 Detected Ubuntu. Using apt to install dependencies.\n" + sudo apt -qq update + sudo apt -qq install --assume-yes git clang curl libssl-dev protobuf-compiler make + elif [ "$distro" = "debian" ]; then + printf "\n🐧 Detected Debian. Using apt to install dependencies.\n" + sudo apt -qq update + sudo apt -qq install --assume-yes git clang curl libssl-dev llvm libudev-dev make protobuf-compiler + elif [ "$distro" = "arch" ]; then + printf "\n🐧 Detected Arch Linux. Using pacman to install dependencies.\n" + pacman -Syu --needed --noconfirm curl git clang make protobuf + elif [ "$distro" = "fedora" ]; then + printf "\n🐧 Detected Fedora. Using dnf to install dependencies.\n" + sudo dnf update --assumeyes + sudo dnf install --assumeyes clang curl git openssl-devel make protobuf-compiler perl + elif [ "$distro" = "opensuse" ]; then + printf "\n🐧 Detected openSUSE. Using zypper to install dependencies.\n" + sudo zypper install --no-confirm clang gcc gcc-c++ curl git openssl-devel llvm-devel libudev-devel make awk protobuf-devel + else + if prompt "\n🐧 Unknown Linux distribution. Unable to install dependencies. Continue anyway?\n"; then + printf "\n🐧 Proceeding with unknown linux distribution...\n" + else + exit 1 + fi + fi +else + printf "❌ Unknown operating system. Aborting.\n" + exit 1 +fi + +# Check if rust is installed +[ -f "$HOME/.cargo/env" ] && . "$HOME/.cargo/env" +if command -v rustc >/dev/null 2>&1; then + printf "\n✅︎🦀 Rust already installed.\n" +else + if prompt_default_yes "\n🦀 Rust is not installed. Install it?"; then + printf "🦀 Installing via rustup.\n" + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + . "$HOME/.cargo/env" + else + printf "Aborting.\n" + exit 1 + fi +fi + +# Ensure that we have wasm support +if prompt_default_yes "\n🦀 Setup the Rust environment (e.g. WASM support)?"; then + printf "🦀 Setting up Rust environment.\n" + rustup default stable + rustup update + rustup target add wasm32-unknown-unknown + rustup component add rust-src +fi + +if ! prompt "\nWould you like to start with one of the templates?"; then + printf "⚡ All done, the environment is ready for hacking.\n" + exit 0 +fi + +while true; do + printf "\nWhich template would you like to start with?\n" + printf "1) minimal template\n" + printf "2) parachain template\n" + printf "3) solochain template\n" + printf "q) cancel\n" + read -p "#? " template + case $template in + [1]* ) clone_and_enter_template minimal; break;; + [2]* ) clone_and_enter_template parachain; break;; + [3]* ) clone_and_enter_template solochain; break;; + [qQ]* ) printf "Canceling, not using a template.\n"; exit 0;; + * ) printf "Selection not recognized.\n";; + esac +done + +if ! prompt_default_yes "\n⚙️ Let's compile the node? It might take a while."; then + printf "⚡ Script finished, you can continue in the ${template}-template directory.\n" + exit 0 +fi + +cargo build --release + +if prompt_default_yes "\n🚀 Everything ready to go, let's run the node?\n"; then + cargo run --release -- --dev +fi diff --git a/scripts/lib/bench-all-cumulus.sh b/scripts/lib/bench-all-cumulus.sh deleted file mode 100755 index f4c2a35c6b6b..000000000000 --- a/scripts/lib/bench-all-cumulus.sh +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env bash -# originally moved from https://github.com/paritytech/cumulus/blob/445f9277ab55b4d930ced4fbbb38d27c617c6658/scripts/benchmarks-ci.sh - -# default RUST_LOG is warn, but could be overridden -export RUST_LOG="${RUST_LOG:-error}" - -THIS_DIR=$(dirname "${BASH_SOURCE[0]}") -. "$THIS_DIR/../command-utils.sh" - -POLKADOT_PARACHAIN="./target/$profile/polkadot-parachain" - -run_cumulus_bench() { - local artifactsDir="$ARTIFACTS_DIR" - local category=$1 - local runtimeName=$2 - local paraId=${3:-} - - local benchmarkOutput="$output_path/parachains/runtimes/$category/$runtimeName/src/weights" - local benchmarkRuntimeChain - if [[ ! -z "$paraId" ]]; then - benchmarkRuntimeChain="${runtimeName}-dev-$paraId" - else - benchmarkRuntimeChain="$runtimeName-dev" - fi - - local benchmarkMetadataOutputDir="$artifactsDir/$runtimeName" - mkdir -p "$benchmarkMetadataOutputDir" - - # Load all pallet names in an array. - echo "[+] Listing pallets for runtime $runtimeName for chain: $benchmarkRuntimeChain ..." - local pallets=($( - $POLKADOT_PARACHAIN benchmark pallet --list --chain="${benchmarkRuntimeChain}" |\ - tail -n+2 |\ - cut -d',' -f1 |\ - sort |\ - uniq - )) - - if [ ${#pallets[@]} -ne 0 ]; then - echo "[+] Benchmarking ${#pallets[@]} pallets for runtime $runtimeName for chain: $benchmarkRuntimeChain, pallets:" - for pallet in "${pallets[@]}"; do - echo " [+] $pallet" - done - else - echo "$runtimeName pallet list not found in benchmarks-ci.sh" - exit 1 - fi - - for pallet in "${pallets[@]}"; do - # (by default) do not choose output_file, like `pallet_assets.rs` because it does not work for multiple instances - # `benchmark pallet` command will decide the output_file name if there are multiple instances - local output_file="" - local extra_args="" - # a little hack for pallet_xcm_benchmarks - we want to force custom implementation for XcmWeightInfo - if [[ "$pallet" == "pallet_xcm_benchmarks::generic" ]] || [[ "$pallet" == "pallet_xcm_benchmarks::fungible" ]]; then - output_file="xcm/${pallet//::/_}.rs" - extra_args="--template=$output_path/templates/xcm-bench-template.hbs" - fi - $POLKADOT_PARACHAIN benchmark pallet \ - $extra_args \ - --chain="${benchmarkRuntimeChain}" \ - --wasm-execution=compiled \ - --pallet="$pallet" \ - --no-storage-info \ - --no-median-slopes \ - --no-min-squares \ - --extrinsic='*' \ - --steps=50 \ - --repeat=20 \ - --json \ - --header="$output_path/file_header.txt" \ - --output="${benchmarkOutput}/${output_file}" >> "$benchmarkMetadataOutputDir/${pallet//::/_}_benchmark.json" - done -} - - -echo "[+] Compiling benchmarks..." -cargo build --profile $profile --locked --features=runtime-benchmarks -p polkadot-parachain-bin - -# Run benchmarks for all pallets of a given runtime if runtime argument provided -get_arg optional --runtime "$@" -runtime="${out:-""}" - -if [[ $runtime ]]; then - paraId="" - case "$runtime" in - asset-*) - category="assets" - ;; - collectives-*) - category="collectives" - ;; - coretime-*) - category="coretime" - ;; - bridge-*) - category="bridge-hubs" - ;; - contracts-*) - category="contracts" - ;; - people-*) - category="people" - ;; - glutton-*) - category="glutton" - paraId="1300" - ;; - *) - echo "Unknown runtime: $runtime" - exit 1 - ;; - esac - - run_cumulus_bench $category $runtime $paraId - -else # run all - # Assets - run_cumulus_bench assets asset-hub-rococo - run_cumulus_bench assets asset-hub-westend - - # Collectives - run_cumulus_bench collectives collectives-westend - - # Coretime - run_cumulus_bench coretime coretime-rococo - run_cumulus_bench coretime coretime-westend - - # People - run_cumulus_bench people people-rococo - run_cumulus_bench people people-westend - - # Bridge Hubs - run_cumulus_bench bridge-hubs bridge-hub-rococo - run_cumulus_bench bridge-hubs bridge-hub-westend - - # Glutton - run_cumulus_bench glutton glutton-westend 1300 -fi diff --git a/scripts/lib/bench-all-pallet.sh b/scripts/lib/bench-all-pallet.sh deleted file mode 100644 index e6908045ddbd..000000000000 --- a/scripts/lib/bench-all-pallet.sh +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env bash - -set -eu -o pipefail -shopt -s inherit_errexit -shopt -s globstar - -. "$(dirname "${BASH_SOURCE[0]}")/../command-utils.sh" - -get_arg required --pallet "$@" -PALLET="${out:-""}" - -REPO_NAME="$(basename "$PWD")" -BASE_COMMAND="$(dirname "${BASH_SOURCE[0]}")/../../bench/bench.sh --noexit=true --subcommand=pallet" - -WEIGHT_FILE_PATHS=( $(find . -type f -name "${PALLET}.rs" -path "**/weights/*" | sed 's|^\./||g') ) - -# convert pallet_ranked_collective to ranked-collective -CLEAN_PALLET=$(echo $PALLET | sed 's/pallet_//g' | sed 's/_/-/g') - -# add substrate pallet weights to a list -SUBSTRATE_PALLET_PATH=$(ls substrate/frame/$CLEAN_PALLET/src/weights.rs || :) -if [ ! -z "${SUBSTRATE_PALLET_PATH}" ]; then - WEIGHT_FILE_PATHS+=("$SUBSTRATE_PALLET_PATH") -fi - -# add trappist pallet weights to a list -TRAPPIST_PALLET_PATH=$(ls pallet/$CLEAN_PALLET/src/weights.rs || :) -if [ ! -z "${TRAPPIST_PALLET_PATH}" ]; then - WEIGHT_FILE_PATHS+=("$TRAPPIST_PALLET_PATH") -fi - -COMMANDS=() - -if [ "${#WEIGHT_FILE_PATHS[@]}" -eq 0 ]; then - echo "No weights files found for pallet: $PALLET" - exit 1 -else - echo "Found weights files for pallet: $PALLET" -fi - -for f in ${WEIGHT_FILE_PATHS[@]}; do - echo "- $f" - # f examples: - # cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_balances.rs - # polkadot/runtime/rococo/src/weights/pallet_balances.rs - # runtime/trappist/src/weights/pallet_assets.rs - TARGET_DIR=$(echo $f | cut -d'/' -f 1) - - if [ "$REPO_NAME" == "polkadot-sdk" ]; then - case $TARGET_DIR in - cumulus) - TYPE=$(echo $f | cut -d'/' -f 2) - # Example: cumulus/parachains/runtimes/assets/asset-hub-rococo/src/weights/pallet_balances.rs - if [ "$TYPE" == "parachains" ]; then - RUNTIME=$(echo $f | cut -d'/' -f 5) - RUNTIME_DIR=$(echo $f | cut -d'/' -f 4) - COMMANDS+=("$BASE_COMMAND --runtime=$RUNTIME --runtime_dir=$RUNTIME_DIR --target_dir=$TARGET_DIR --pallet=$PALLET") - fi - ;; - polkadot) - # Example: polkadot/runtime/rococo/src/weights/pallet_balances.rs - RUNTIME=$(echo $f | cut -d'/' -f 3) - COMMANDS+=("$BASE_COMMAND --runtime=$RUNTIME --target_dir=$TARGET_DIR --pallet=$PALLET") - ;; - substrate) - # Example: substrate/frame/contracts/src/weights.rs - COMMANDS+=("$BASE_COMMAND --target_dir=$TARGET_DIR --runtime=dev --pallet=$PALLET") - ;; - *) - echo "Unknown dir: $TARGET_DIR" - exit 1 - ;; - esac - fi - - if [ "$REPO_NAME" == "trappist" ]; then - case $TARGET_DIR in - runtime) - TYPE=$(echo $f | cut -d'/' -f 2) - if [ "$TYPE" == "trappist" || "$TYPE" == "stout" ]; then - # Example: runtime/trappist/src/weights/pallet_assets.rs - COMMANDS+=("$BASE_COMMAND --target_dir=trappist --runtime=$TYPE --pallet=$PALLET") - fi - ;; - *) - echo "Unknown dir: $TARGET_DIR" - exit 1 - ;; - esac - fi -done - -for cmd in "${COMMANDS[@]}"; do - echo "Running command: $cmd" - . $cmd -done diff --git a/scripts/lib/bench-all-polkadot.sh b/scripts/lib/bench-all-polkadot.sh deleted file mode 100644 index ac52e00140e3..000000000000 --- a/scripts/lib/bench-all-polkadot.sh +++ /dev/null @@ -1,88 +0,0 @@ -#!/bin/bash - -# Runs all benchmarks for all pallets, for a given runtime, provided by $1 -# Should be run on a reference machine to gain accurate benchmarks -# current reference machine: https://github.com/paritytech/polkadot/pull/6508/files -# original source: https://github.com/paritytech/polkadot/blob/b9842c4b52f6791fef6c11ecd020b22fe614f041/scripts/run_all_benches.sh - -get_arg required --runtime "$@" -runtime="${out:-""}" - -# default RUST_LOG is error, but could be overridden -export RUST_LOG="${RUST_LOG:-error}" - -echo "[+] Compiling benchmarks..." -cargo build --profile $profile --locked --features=runtime-benchmarks -p polkadot - -POLKADOT_BIN="./target/$profile/polkadot" - -# Update the block and extrinsic overhead weights. -echo "[+] Benchmarking block and extrinsic overheads..." -OUTPUT=$( - $POLKADOT_BIN benchmark overhead \ - --chain="${runtime}-dev" \ - --wasm-execution=compiled \ - --weight-path="$output_path/runtime/${runtime}/constants/src/weights/" \ - --warmup=10 \ - --repeat=100 \ - --header="$output_path/file_header.txt" -) -if [ $? -ne 0 ]; then - echo "$OUTPUT" >> "$ERR_FILE" - echo "[-] Failed to benchmark the block and extrinsic overheads. Error written to $ERR_FILE; continuing..." -fi - - -# Load all pallet names in an array. -PALLETS=($( - $POLKADOT_BIN benchmark pallet --list --chain="${runtime}-dev" |\ - tail -n+2 |\ - cut -d',' -f1 |\ - sort |\ - uniq -)) - -echo "[+] Benchmarking ${#PALLETS[@]} pallets for runtime $runtime" - -# Define the error file. -ERR_FILE="${ARTIFACTS_DIR}/benchmarking_errors.txt" -# Delete the error file before each run. -rm -f $ERR_FILE - -# Benchmark each pallet. -for PALLET in "${PALLETS[@]}"; do - echo "[+] Benchmarking $PALLET for $runtime"; - - output_file="" - if [[ $PALLET == *"::"* ]]; then - # translates e.g. "pallet_foo::bar" to "pallet_foo_bar" - output_file="${PALLET//::/_}.rs" - fi - - OUTPUT=$( - $POLKADOT_BIN benchmark pallet \ - --chain="${runtime}-dev" \ - --steps=50 \ - --repeat=20 \ - --no-storage-info \ - --no-median-slopes \ - --no-min-squares \ - --pallet="$PALLET" \ - --extrinsic="*" \ - --execution=wasm \ - --wasm-execution=compiled \ - --header="$output_path/file_header.txt" \ - --output="$output_path/runtime/${runtime}/src/weights/${output_file}" 2>&1 - ) - if [ $? -ne 0 ]; then - echo "$OUTPUT" >> "$ERR_FILE" - echo "[-] Failed to benchmark $PALLET. Error written to $ERR_FILE; continuing..." - fi -done - -# Check if the error file exists. -if [ -f "$ERR_FILE" ]; then - echo "[-] Some benchmarks failed. See: $ERR_FILE" -else - echo "[+] All benchmarks passed." -fi diff --git a/scripts/lib/bench-all-substrate.sh b/scripts/lib/bench-all-substrate.sh deleted file mode 100644 index eeb18cdd8bbb..000000000000 --- a/scripts/lib/bench-all-substrate.sh +++ /dev/null @@ -1,148 +0,0 @@ -#!/usr/bin/env bash - -# This file is part of Substrate. -# Copyright (C) 2022 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. - -# This script has three parts which all use the Substrate runtime: -# - Pallet benchmarking to update the pallet weights -# - Overhead benchmarking for the Extrinsic and Block weights -# - Machine benchmarking -# -# Should be run on a reference machine to gain accurate benchmarks -# current reference machine: https://github.com/paritytech/substrate/pull/5848 - -# Original source: https://github.com/paritytech/substrate/blob/ff9921a260a67e3a71f25c8b402cd5c7da787a96/scripts/run_all_benchmarks.sh -# Fail if any sub-command in a pipe fails, not just the last one. -set -o pipefail -# Fail on undeclared variables. -set -u -# Fail if any sub-command fails. -set -e -# Fail on traps. -# set -E - -# default RUST_LOG is warn, but could be overridden -export RUST_LOG="${RUST_LOG:-error}" - -echo "[+] Compiling Substrate benchmarks..." -cargo build --profile=$profile --locked --features=runtime-benchmarks -p staging-node-cli - -# The executable to use. -SUBSTRATE="./target/$profile/substrate-node" - -# Manually exclude some pallets. -EXCLUDED_PALLETS=( - # Helper pallets - "pallet_election_provider_support_benchmarking" - # Pallets without automatic benchmarking - "pallet_babe" - "pallet_grandpa" - "pallet_mmr" - "pallet_offences" - # Only used for testing, does not need real weights. - "frame_benchmarking_pallet_pov" - "pallet_example_tasks" - "pallet_example_basic" - "pallet_example_split" - "pallet_example_kitchensink" - "pallet_example_mbm" - "tasks_example" -) - -# Load all pallet names in an array. -ALL_PALLETS=($( - $SUBSTRATE benchmark pallet --list --chain=dev |\ - tail -n+2 |\ - cut -d',' -f1 |\ - sort |\ - uniq -)) - -# Define the error file. -ERR_FILE="${ARTIFACTS_DIR}/benchmarking_errors.txt" - -# Delete the error file before each run. -rm -f "$ERR_FILE" - -mkdir -p "$(dirname "$ERR_FILE")" - -# Update the block and extrinsic overhead weights. -echo "[+] Benchmarking block and extrinsic overheads..." -OUTPUT=$( - $SUBSTRATE benchmark overhead \ - --chain=dev \ - --wasm-execution=compiled \ - --weight-path="$output_path/frame/support/src/weights/" \ - --header="$output_path/HEADER-APACHE2" \ - --warmup=10 \ - --repeat=100 2>&1 -) -if [ $? -ne 0 ]; then - echo "$OUTPUT" >> "$ERR_FILE" - echo "[-] Failed to benchmark the block and extrinsic overheads. Error written to $ERR_FILE; continuing..." -fi - -echo "[+] Benchmarking ${#ALL_PALLETS[@]} Substrate pallets and excluding ${#EXCLUDED_PALLETS[@]}." - -echo "[+] Excluded pallets ${EXCLUDED_PALLETS[@]}" -echo "[+] ------ " -echo "[+] Whole list pallets ${ALL_PALLETS[@]}" - -# Benchmark each pallet. -for PALLET in "${ALL_PALLETS[@]}"; do - FOLDER="$(echo "${PALLET#*_}" | tr '_' '-')"; - WEIGHT_FILE="$output_path/frame/${FOLDER}/src/weights.rs" - - # Skip the pallet if it is in the excluded list. - - if [[ " ${EXCLUDED_PALLETS[@]} " =~ " ${PALLET} " ]]; then - echo "[+] Skipping $PALLET as it is in the excluded list." - continue - fi - - echo "[+] Benchmarking $PALLET with weight file $WEIGHT_FILE"; - - set +e # Disable exit on error for the benchmarking of the pallets - OUTPUT=$( - $SUBSTRATE benchmark pallet \ - --chain=dev \ - --steps=50 \ - --repeat=20 \ - --pallet="$PALLET" \ - --no-storage-info \ - --no-median-slopes \ - --no-min-squares \ - --extrinsic="*" \ - --wasm-execution=compiled \ - --heap-pages=4096 \ - --output="$WEIGHT_FILE" \ - --header="$output_path/HEADER-APACHE2" \ - --template="$output_path/.maintain/frame-weight-template.hbs" 2>&1 - ) - if [ $? -ne 0 ]; then - echo -e "$PALLET: $OUTPUT\n" >> "$ERR_FILE" - echo "[-] Failed to benchmark $PALLET. Error written to $ERR_FILE; continuing..." - fi - set -e # Re-enable exit on error -done - - -# Check if the error file exists. -if [ -s "$ERR_FILE" ]; then - echo "[-] Some benchmarks failed. See: $ERR_FILE" - exit 1 -else - echo "[+] All benchmarks passed." -fi diff --git a/scripts/lib/bench-overhead.sh b/scripts/lib/bench-overhead.sh deleted file mode 100644 index c4cca8b4c128..000000000000 --- a/scripts/lib/bench-overhead.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash - -THIS_DIR=$(dirname "${BASH_SOURCE[0]}") -. "$THIS_DIR/../command-utils.sh" - -bench_overhead_common_args=( - -- - benchmark - overhead - --wasm-execution=compiled - --warmup=10 - --repeat=100 -) -bench_overhead() { - local args - case "$target_dir" in - substrate) - args=( - --bin=substrate - "${bench_overhead_common_args[@]}" - --header="$output_path/HEADER-APACHE2" - --weight-path="$output_path/frame/support/src/weights" - --chain="dev" - ) - ;; - polkadot) - get_arg required --runtime "$@" - local runtime="${out:-""}" - args=( - --bin=polkadot - "${bench_overhead_common_args[@]}" - --header="$output_path/file_header.txt" - --weight-path="$output_path/runtime/$runtime/constants/src/weights" - --chain="$runtime-dev" - ) - ;; - cumulus) - get_arg required --runtime "$@" - local runtime="${out:-""}" - args=( - -p=polkadot-parachain-bin - "${bench_overhead_common_args[@]}" - --header="$output_path/file_header.txt" - --weight-path="$output_path/parachains/runtimes/assets/$runtime/src/weights" - --chain="$runtime" - ) - ;; - trappist) - get_arg required --runtime "$@" - local runtime="${out:-""}" - args=( - "${bench_overhead_common_args[@]}" - --header="$output_path/templates/file_header.txt" - --weight-path="$output_path/runtime/$runtime/src/weights" - --chain="$runtime-dev" - ) - ;; - *) - die "Target Dir \"$target_dir\" is not supported in bench_overhead" - ;; - esac - - cargo_run "${args[@]}" -} - -bench_overhead "$@" diff --git a/scripts/lib/bench-pallet.sh b/scripts/lib/bench-pallet.sh deleted file mode 100644 index 15eac31e3a45..000000000000 --- a/scripts/lib/bench-pallet.sh +++ /dev/null @@ -1,178 +0,0 @@ -#!/bin/bash - -THIS_DIR=$(dirname "${BASH_SOURCE[0]}") -. "$THIS_DIR/../command-utils.sh" - -bench_pallet_common_args=( - -- - benchmark - pallet - --steps=50 - --repeat=20 - --extrinsic="*" - --wasm-execution=compiled - --heap-pages=4096 - --json-file="${ARTIFACTS_DIR}/bench.json" -) -bench_pallet() { - get_arg required --subcommand "$@" - local subcommand="${out:-""}" - - get_arg required --runtime "$@" - local runtime="${out:-""}" - - get_arg required --pallet "$@" - local pallet="${out:-""}" - - local args - case "$target_dir" in - substrate) - args=( - --features=runtime-benchmarks - --manifest-path="$output_path/bin/node/cli/Cargo.toml" - "${bench_pallet_common_args[@]}" - --pallet="$pallet" - --chain="$runtime" - ) - - case "$subcommand" in - pallet) - # Translates e.g. "pallet_foo::bar" to "pallet_foo_bar" - local output_dir="${pallet//::/_}" - - # Substrate benchmarks are output to the "frame" directory but they aren't - # named exactly after the $pallet argument. For example: - # - When $pallet == pallet_balances, the output folder is frame/balances - # - When $pallet == frame_benchmarking, the output folder is frame/benchmarking - # The common pattern we infer from those examples is that we should remove - # the prefix - if [[ "$output_dir" =~ ^[A-Za-z]*[^A-Za-z](.*)$ ]]; then - output_dir="${BASH_REMATCH[1]}" - fi - - # We also need to translate '_' to '-' due to the folders' naming - # conventions - output_dir="${output_dir//_/-}" - - args+=( - --header="$output_path/HEADER-APACHE2" - --output="$output_path/frame/$output_dir/src/weights.rs" - --template="$output_path/.maintain/frame-weight-template.hbs" - ) - ;; - *) - die "Subcommand $subcommand is not supported for $target_dir in bench_pallet" - ;; - esac - ;; - polkadot) - # For backward compatibility: replace "-dev" with "" - runtime=${runtime/-dev/} - - local weights_dir="$output_path/runtime/${runtime}/src/weights" - - args=( - --bin=polkadot - --features=runtime-benchmarks - "${bench_pallet_common_args[@]}" - --pallet="$pallet" - --chain="${runtime}-dev" - ) - - case "$subcommand" in - pallet) - args+=( - --header="$output_path/file_header.txt" - --output="${weights_dir}/" - ) - ;; - xcm) - args+=( - --header="$output_path/file_header.txt" - --template="$output_path/xcm/pallet-xcm-benchmarks/template.hbs" - --output="${weights_dir}/xcm/" - ) - ;; - *) - die "Subcommand $subcommand is not supported for $target_dir in bench_pallet" - ;; - esac - ;; - cumulus) - get_arg required --runtime_dir "$@" - local runtime_dir="${out:-""}" - local chain="$runtime" - - # to support specifying parachain id from runtime name (e.g. ["glutton-westend", "glutton-westend-dev-1300"]) - # If runtime ends with "-dev" or "-dev-\d+", leave as it is, otherwise concat "-dev" at the end of $chain - if [[ ! "$runtime" =~ -dev(-[0-9]+)?$ ]]; then - chain="${runtime}-dev" - fi - - # replace "-dev" or "-dev-\d+" with "" for runtime - runtime=$(echo "$runtime" | sed 's/-dev.*//g') - - args=( - -p=polkadot-parachain-bin - --features=runtime-benchmarks - "${bench_pallet_common_args[@]}" - --pallet="$pallet" - --chain="${chain}" - --header="$output_path/file_header.txt" - ) - - case "$subcommand" in - pallet) - args+=( - --output="$output_path/parachains/runtimes/$runtime_dir/$runtime/src/weights/" - ) - ;; - xcm) - mkdir -p "$output_path/parachains/runtimes/$runtime_dir/$runtime/src/weights/xcm" - args+=( - --template="$output_path/templates/xcm-bench-template.hbs" - --output="$output_path/parachains/runtimes/$runtime_dir/$runtime/src/weights/xcm/" - ) - ;; - *) - die "Subcommand $subcommand is not supported for $target_dir in bench_pallet" - ;; - esac - ;; - trappist) - local weights_dir="$output_path/runtime/$runtime/src/weights" - - args=( - --features=runtime-benchmarks - "${bench_pallet_common_args[@]}" - --pallet="$pallet" - --chain="${runtime}-dev" - --header="$output_path/templates/file_header.txt" - ) - - case "$subcommand" in - pallet) - args+=( - --output="${weights_dir}/" - ) - ;; - xcm) - args+=( - --template="$output_path/templates/xcm-bench-template.hbs" - --output="${weights_dir}/xcm/" - ) - ;; - *) - die "Subcommand $subcommand is not supported for $target_dir in bench_pallet" - ;; - esac - ;; - *) - die "Repository $target_dir is not supported in bench_pallet" - ;; - esac - - cargo_run "${args[@]}" -} - -bench_pallet "$@" diff --git a/scripts/release/build-changelogs.sh b/scripts/release/build-changelogs.sh index d73f06c8cd6b..d1bbe136ad48 100755 --- a/scripts/release/build-changelogs.sh +++ b/scripts/release/build-changelogs.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash export PRODUCT=polkadot -export VERSION=${VERSION:-1.5.0} +export VERSION=${VERSION:-stable2409} export ENGINE=${ENGINE:-podman} export REF1=${REF1:-'HEAD'} export REF2=${REF2} @@ -66,33 +66,21 @@ echo "Changelog ready in $OUTPUT/relnote_commits.md" # Show the files tree -s -h -c $OUTPUT/ -ASSET_HUB_ROCOCO_DIGEST=${ASSET_HUB_ROCOCO_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/asset-hub-rococo-srtool-digest.json"} ASSET_HUB_WESTEND_DIGEST=${ASSET_HUB_WESTEND_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/asset-hub-westend-srtool-digest.json"} -BRIDGE_HUB_ROCOCO_DIGEST=${BRIDGE_HUB_ROCOCO_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/bridge-hub-rococo-srtool-digest.json"} BRIDGE_HUB_WESTEND_DIGEST=${BRIDGE_HUB_WESTEND_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/bridge-hub-westend-srtool-digest.json"} COLLECTIVES_WESTEND_DIGEST=${COLLECTIVES_WESTEND_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/collectives-westend-srtool-digest.json"} -CONTRACTS_ROCOCO_DIGEST=${CONTRACTS_ROCOCO_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/contracts-rococo-srtool-digest.json"} -CORETIME_ROCOCO_DIGEST=${CORETIME_ROCOCO_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/coretime-rococo-srtool-digest.json"} CORETIME_WESTEND_DIGEST=${CORETIME_WESTEND_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/coretime-westend-srtool-digest.json"} GLUTTON_WESTEND_DIGEST=${GLUTTON_WESTEND_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/glutton-westend-srtool-digest.json"} -PEOPLE_ROCOCO_DIGEST=${PEOPLE_ROCOCO_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/people-rococo-srtool-digest.json"} PEOPLE_WESTEND_DIGEST=${PEOPLE_WESTEND_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/people-westend-srtool-digest.json"} -ROCOCO_DIGEST=${ROCOCO_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/rococo-srtool-digest.json"} WESTEND_DIGEST=${WESTEND_DIGEST:-"$PROJECT_ROOT/scripts/release/digests/westend-srtool-digest.json"} jq \ - --slurpfile srtool_asset_hub_rococo $ASSET_HUB_ROCOCO_DIGEST \ --slurpfile srtool_asset_hub_westend $ASSET_HUB_WESTEND_DIGEST \ - --slurpfile srtool_bridge_hub_rococo $BRIDGE_HUB_ROCOCO_DIGEST \ --slurpfile srtool_bridge_hub_westend $BRIDGE_HUB_WESTEND_DIGEST \ --slurpfile srtool_collectives_westend $COLLECTIVES_WESTEND_DIGEST \ - --slurpfile srtool_contracts_rococo $CONTRACTS_ROCOCO_DIGEST \ - --slurpfile srtool_coretime_rococo $CORETIME_ROCOCO_DIGEST\ --slurpfile srtool_coretime_westend $CORETIME_WESTEND_DIGEST \ --slurpfile srtool_glutton_westend $GLUTTON_WESTEND_DIGEST \ - --slurpfile srtool_people_rococ $PEOPLE_ROCOCO_DIGEST \ --slurpfile srtool_people_westend $PEOPLE_WESTEND_DIGEST \ - --slurpfile srtool_rococo $ROCOCO_DIGEST \ --slurpfile srtool_westend $WESTEND_DIGEST \ -n '{ srtool: [ @@ -102,13 +90,7 @@ jq \ { order: 13, name: "Westend Collectives", data: $srtool_collectives_westend[0] }, { order: 14, name: "Westend Coretime", data: $srtool_coretime_westend[0] }, { order: 15, name: "Westend Glutton", data: $srtool_glutton_westend[0] }, - { order: 16, name: "Westend People", data: $srtool_people_westend[0] }, - { order: 17, name: "Rococo", data: $srtool_rococo[0] }, - { order: 18, name: "Rococo AssetHub", data: $srtool_asset_hub_rococo[0] }, - { order: 19, name: "Rococo BridgeHub", data: $srtool_bridge_hub_rococo[0] }, - { order: 20, name: "Rococo Contracts", data: $srtool_contracts_rococo[0] }, - { order: 21, name: "Rococo Coretime", data: $srtool_coretime_rococo[0] }, - { order: 22, name: "Rococo People", data: $srtool_people_rococ[0] } + { order: 16, name: "Westend People", data: $srtool_people_westend[0] } ] }' > "$PROJECT_ROOT/scripts/release/context.json" RELEASE_DIR="$PROJECT_ROOT/scripts/release/" diff --git a/scripts/release/templates/changelog.md.tera b/scripts/release/templates/changelog.md.tera index aaba761e8e47..8d17451c8d05 100644 --- a/scripts/release/templates/changelog.md.tera +++ b/scripts/release/templates/changelog.md.tera @@ -1,4 +1,4 @@ -## Changelog for `{{ env.PRODUCT | capitalize }} v{{ env.VERSION }}` +## Changelog for `{{ env.PRODUCT | capitalize }} {{ env.VERSION }}` {% for file in prdoc | sort(attribute="doc_filename.number") -%} {%- set author= file.content.author | default(value="n/a") -%} diff --git a/scripts/sync.sh b/scripts/sync.sh deleted file mode 100755 index b5d8a5219937..000000000000 --- a/scripts/sync.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env bash - -set -eu -o pipefail - -. "$(realpath "$(dirname "${BASH_SOURCE[0]}")/command-utils.sh")" - - -# Function to check syncing status -check_syncing() { - # Send the system_health request and parse the isSyncing field - RESPONSE=$(curl -sSX POST http://127.0.0.1:9944 \ - --header 'Content-Type: application/json' \ - --data-raw '{"jsonrpc": "2.0", "method": "system_health", "params": [], "id": "1"}') - - # Check for errors in the curl command - if [ $? -ne 0 ]; then - echo "Error: Unable to send request to Polkadot node" - fi - - IS_SYNCING=$(echo $RESPONSE | jq -r '.result.isSyncing') - - # Check for errors in the jq command or missing field in the response - if [ $? -ne 0 ] || [ "$IS_SYNCING" == "null" ]; then - echo "Error: Unable to parse sync status from response" - fi - - # Return the isSyncing value - echo $IS_SYNCING -} - -main() { - get_arg required --chain "$@" - local chain="${out:-""}" - - get_arg required --type "$@" - local type="${out:-""}" - - export RUST_LOG="${RUST_LOG:-remote-ext=debug,runtime=trace}" - - cargo build --release - - cp "./target/release/polkadot" ./polkadot-bin - - # Start sync. - # "&" runs the process in the background - # "> /dev/tty" redirects the output of the process to the terminal - ./polkadot-bin --sync="$type" --chain="$chain" > "$ARTIFACTS_DIR/sync.log" 2>&1 & - - # Get the PID of process - POLKADOT_SYNC_PID=$! - - sleep 10 - - # Poll the node every 100 seconds until syncing is complete - while :; do - SYNC_STATUS="$(check_syncing)" - if [ "$SYNC_STATUS" == "true" ]; then - echo "Node is still syncing..." - sleep 100 - elif [ "$SYNC_STATUS" == "false" ]; then - echo "Node sync is complete!" - kill "$POLKADOT_SYNC_PID" # Stop the Polkadot node process once syncing is complete - exit 0 # Success - elif [[ "$SYNC_STATUS" = Error:* ]]; then - echo "$SYNC_STATUS" - exit 1 # Error - else - echo "Unknown error: $SYNC_STATUS" - exit 1 # Unknown error - fi - done -} - -main "$@" diff --git a/scripts/update-ui-tests.sh b/scripts/update-ui-tests.sh index dedee8e641f8..c25b22fa7f75 100755 --- a/scripts/update-ui-tests.sh +++ b/scripts/update-ui-tests.sh @@ -21,7 +21,7 @@ if [ ! -z "$1" ]; then echo "rustup needs to be installed" exit fi - + rustup install $RUST_VERSION rustup component add rust-src --toolchain $RUST_VERSION fi @@ -32,9 +32,12 @@ export RUN_UI_TESTS=1 export SKIP_WASM_BUILD=1 # Let trybuild overwrite the .stderr files export TRYBUILD=overwrite +# Warnings are part of our UI and the CI also sets this. +export RUSTFLAGS="-C debug-assertions -D warnings" # ./substrate -$RUSTUP_RUN cargo test --manifest-path substrate/primitives/runtime-interface/Cargo.toml ui -$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 -q --locked --manifest-path substrate/primitives/runtime-interface/Cargo.toml ui +$RUSTUP_RUN cargo test -q --locked -p sp-api-test ui +$RUSTUP_RUN cargo test -q --locked -p frame-election-provider-solution-type ui +$RUSTUP_RUN cargo test -q --locked -p frame-support-test --features=no-metadata-docs,try-runtime,experimental ui +$RUSTUP_RUN cargo test -q --locked -p xcm-procedural ui diff --git a/substrate/.maintain/frame-weight-template.hbs b/substrate/.maintain/frame-weight-template.hbs index ecd384a51456..ec9eee205cee 100644 --- a/substrate/.maintain/frame-weight-template.hbs +++ b/substrate/.maintain/frame-weight-template.hbs @@ -33,7 +33,7 @@ pub trait WeightInfo { /// Weights for `{{pallet}}` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); -{{#if (eq pallet "frame_system")}} +{{#if (or (eq pallet "frame_system") (eq pallet "frame_system_extensions"))}} impl WeightInfo for SubstrateWeight { {{else}} impl WeightInfo for SubstrateWeight { diff --git a/substrate/bin/node/bench/Cargo.toml b/substrate/bin/node/bench/Cargo.toml index 6b061955184e..8c6556da682c 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 @@ -40,7 +40,6 @@ hash-db = { workspace = true, default-features = true } tempfile = { workspace = true } fs_extra = { workspace = true } rand = { features = ["small_rng"], workspace = true, default-features = true } -lazy_static = { workspace = true } parity-db = { workspace = true } sc-transaction-pool = { workspace = true, default-features = true } sc-transaction-pool-api = { workspace = true, default-features = true } diff --git a/substrate/bin/node/bench/src/construct.rs b/substrate/bin/node/bench/src/construct.rs index 23d0a0cc1ee5..bed6e3d914c2 100644 --- a/substrate/bin/node/bench/src/construct.rs +++ b/substrate/bin/node/bench/src/construct.rs @@ -35,7 +35,7 @@ use sc_transaction_pool_api::{ }; use sp_consensus::{Environment, Proposer}; use sp_inherents::InherentDataProvider; -use sp_runtime::{traits::NumberFor, OpaqueExtrinsic}; +use sp_runtime::OpaqueExtrinsic; use crate::{ common::SizeType, @@ -165,18 +165,18 @@ impl core::Benchmark for ConstructionBenchmark { #[derive(Clone, Debug)] pub struct PoolTransaction { - data: OpaqueExtrinsic, + data: Arc, hash: node_primitives::Hash, } impl From for PoolTransaction { fn from(e: OpaqueExtrinsic) -> Self { - PoolTransaction { data: e, hash: node_primitives::Hash::zero() } + PoolTransaction { data: Arc::from(e), hash: node_primitives::Hash::zero() } } } impl sc_transaction_pool_api::InPoolTransaction for PoolTransaction { - type Transaction = OpaqueExtrinsic; + type Transaction = Arc; type Hash = node_primitives::Hash; fn data(&self) -> &Self::Transaction { @@ -261,7 +261,7 @@ impl sc_transaction_pool_api::TransactionPool for Transactions { fn ready_at( &self, - _at: NumberFor, + _at: Self::Hash, ) -> Pin< Box< dyn Future< @@ -305,4 +305,19 @@ impl sc_transaction_pool_api::TransactionPool for Transactions { fn ready_transaction(&self, _hash: &TxHash) -> Option> { unimplemented!() } + + fn ready_at_with_timeout( + &self, + _at: Self::Hash, + _timeout: std::time::Duration, + ) -> Pin< + Box< + dyn Future< + Output = Box> + Send>, + > + Send + + '_, + >, + > { + unimplemented!() + } } diff --git a/substrate/bin/node/bench/src/import.rs b/substrate/bin/node/bench/src/import.rs index e340869dea02..0b972650ef5a 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/bench/src/trie.rs b/substrate/bin/node/bench/src/trie.rs index 09ab405c03b2..402a186767ee 100644 --- a/substrate/bin/node/bench/src/trie.rs +++ b/substrate/bin/node/bench/src/trie.rs @@ -20,11 +20,14 @@ use hash_db::Prefix; use kvdb::KeyValueDB; -use lazy_static::lazy_static; use rand::Rng; use sp_state_machine::Backend as _; use sp_trie::{trie_types::TrieDBMutBuilderV1, TrieMut as _}; -use std::{borrow::Cow, collections::HashMap, sync::Arc}; +use std::{ + borrow::Cow, + collections::HashMap, + sync::{Arc, LazyLock}, +}; use node_primitives::Hash; @@ -57,10 +60,8 @@ pub enum DatabaseSize { Huge, } -lazy_static! { - static ref KUSAMA_STATE_DISTRIBUTION: SizePool = - SizePool::from_histogram(crate::state_sizes::KUSAMA_STATE_DISTRIBUTION); -} +static KUSAMA_STATE_DISTRIBUTION: LazyLock = + LazyLock::new(|| SizePool::from_histogram(crate::state_sizes::KUSAMA_STATE_DISTRIBUTION)); impl DatabaseSize { /// Should be multiple of SAMPLE_SIZE! diff --git a/substrate/bin/node/cli/Cargo.toml b/substrate/bin/node/cli/Cargo.toml index ab665f0792a4..933406670e5c 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 @@ -46,9 +46,92 @@ futures = { workspace = true } log = { workspace = true, default-features = true } rand = { workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } +subxt-signer = { workspace = true, features = ["unstable-eth"] } # The Polkadot-SDK: -polkadot-sdk = { features = ["node"], workspace = true, default-features = true } +polkadot-sdk = { features = [ + "fork-tree", + "frame-benchmarking-cli", + "frame-remote-externalities", + "frame-support-procedural-tools", + "generate-bags", + "mmr-gadget", + "mmr-rpc", + "pallet-transaction-payment-rpc", + "sc-allocator", + "sc-authority-discovery", + "sc-basic-authorship", + "sc-block-builder", + "sc-chain-spec", + "sc-cli", + "sc-client-api", + "sc-client-db", + "sc-consensus", + "sc-consensus-aura", + "sc-consensus-babe", + "sc-consensus-babe-rpc", + "sc-consensus-beefy", + "sc-consensus-beefy-rpc", + "sc-consensus-epochs", + "sc-consensus-grandpa", + "sc-consensus-grandpa-rpc", + "sc-consensus-manual-seal", + "sc-consensus-pow", + "sc-consensus-slots", + "sc-executor", + "sc-executor-common", + "sc-executor-polkavm", + "sc-executor-wasmtime", + "sc-informant", + "sc-keystore", + "sc-mixnet", + "sc-network", + "sc-network-common", + "sc-network-gossip", + "sc-network-light", + "sc-network-statement", + "sc-network-sync", + "sc-network-transactions", + "sc-network-types", + "sc-offchain", + "sc-proposer-metrics", + "sc-rpc", + "sc-rpc-api", + "sc-rpc-server", + "sc-rpc-spec-v2", + "sc-service", + "sc-state-db", + "sc-statement-store", + "sc-storage-monitor", + "sc-sync-state-rpc", + "sc-sysinfo", + "sc-telemetry", + "sc-tracing", + "sc-transaction-pool", + "sc-transaction-pool-api", + "sc-utils", + "sp-blockchain", + "sp-consensus", + "sp-core-hashing", + "sp-core-hashing-proc-macro", + "sp-database", + "sp-maybe-compressed-blob", + "sp-panic-handler", + "sp-rpc", + "staging-chain-spec-builder", + "staging-node-inspect", + "staging-tracking-allocator", + "std", + "subkey", + "substrate-build-script-utils", + "substrate-frame-rpc-support", + "substrate-frame-rpc-system", + "substrate-prometheus-endpoint", + "substrate-rpc-client", + "substrate-state-trie-migration-rpc", + "substrate-wasm-builder", + "tracing-gum", +], workspace = true, default-features = true } # Shared code between the staging node and kitchensink runtime: kitchensink-runtime = { workspace = true } @@ -71,6 +154,8 @@ wait-timeout = { workspace = true } wat = { workspace = true } serde_json = { workspace = true, default-features = true } scale-info = { features = ["derive", "serde"], workspace = true, default-features = true } +sp-keyring = { workspace = true } +pretty_assertions.workspace = true # These testing-only dependencies are not exported by the Polkadot-SDK crate: node-testing = { workspace = true } @@ -87,12 +172,7 @@ polkadot-sdk = { features = ["frame-benchmarking-cli", "sc-cli", "sc-storage-mon [features] default = ["cli"] -cli = [ - "clap", - "clap_complete", - "node-inspect", - "polkadot-sdk", -] +cli = ["clap", "clap_complete", "node-inspect", "polkadot-sdk"] runtime-benchmarks = [ "kitchensink-runtime/runtime-benchmarks", "node-inspect?/runtime-benchmarks", @@ -103,6 +183,7 @@ try-runtime = [ "polkadot-sdk/try-runtime", "substrate-cli-test-utils/try-runtime", ] +riscv = ["kitchensink-runtime/riscv", "polkadot-sdk/riscv"] [[bench]] name = "transaction_pool" diff --git a/substrate/bin/node/cli/benches/block_production.rs b/substrate/bin/node/cli/benches/block_production.rs index c16b25187e5f..da82729dbec0 100644 --- a/substrate/bin/node/cli/benches/block_production.rs +++ b/substrate/bin/node/cli/benches/block_production.rs @@ -22,6 +22,7 @@ use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughpu use kitchensink_runtime::{constants::currency::*, BalancesCall}; use node_cli::service::{create_extrinsic, FullClient}; +use polkadot_sdk::sc_service::config::{ExecutorConfiguration, RpcConfiguration}; use sc_block_builder::{BlockBuilderBuilder, BuiltBlock}; use sc_consensus::{ block_import::{BlockImportParams, ForkChoiceStrategy}, @@ -38,6 +39,7 @@ use sp_blockchain::{ApplyExtrinsicFailed::Validity, Error::ApplyExtrinsicFailed} use sp_consensus::BlockOrigin; use sp_keyring::Sr25519Keyring; use sp_runtime::{ + generic, transaction_validity::{InvalidTransaction, TransactionValidityError}, AccountId32, MultiAddress, OpaqueExtrinsic, }; @@ -73,38 +75,39 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { state_pruning: Some(PruningMode::ArchiveAll), blocks_pruning: BlocksPruning::KeepAll, chain_spec: spec, - wasm_method: WasmExecutionMethod::Compiled { - instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, + executor: ExecutorConfiguration { + wasm_method: WasmExecutionMethod::Compiled { + instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, + }, + ..ExecutorConfiguration::default() + }, + rpc: RpcConfiguration { + addr: None, + max_connections: Default::default(), + cors: None, + methods: Default::default(), + max_request_size: Default::default(), + max_response_size: Default::default(), + id_provider: Default::default(), + max_subs_per_conn: Default::default(), + port: 9944, + message_buffer_capacity: Default::default(), + batch_config: RpcBatchRequestConfig::Unlimited, + rate_limit: None, + rate_limit_whitelisted_ips: Default::default(), + rate_limit_trust_proxy_headers: Default::default(), }, - rpc_addr: None, - rpc_max_connections: Default::default(), - rpc_cors: None, - rpc_methods: Default::default(), - rpc_max_request_size: Default::default(), - rpc_max_response_size: Default::default(), - rpc_id_provider: Default::default(), - rpc_max_subs_per_conn: Default::default(), - rpc_port: 9944, - rpc_message_buffer_capacity: Default::default(), - rpc_batch_config: RpcBatchRequestConfig::Unlimited, - rpc_rate_limit: None, - rpc_rate_limit_whitelisted_ips: Default::default(), - rpc_rate_limit_trust_proxy_headers: Default::default(), prometheus_config: None, telemetry_endpoints: None, - default_heap_pages: None, offchain_worker: OffchainWorkerConfig { enabled: true, indexing_enabled: false }, force_authoring: false, disable_grandpa: false, dev_key_seed: Some(Sr25519Keyring::Alice.to_seed()), tracing_targets: None, tracing_receiver: Default::default(), - max_runtime_instances: 8, - runtime_cache_size: 2, announce_block: true, data_path: base_path.path().into(), base_path, - informant_output_format: Default::default(), wasm_runtime_overrides: None, }; @@ -118,14 +121,14 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { } fn extrinsic_set_time(now: u64) -> OpaqueExtrinsic { - kitchensink_runtime::UncheckedExtrinsic { - signature: None, - function: kitchensink_runtime::RuntimeCall::Timestamp(pallet_timestamp::Call::set { now }), - } - .into() + let utx: kitchensink_runtime::UncheckedExtrinsic = generic::UncheckedExtrinsic::new_bare( + kitchensink_runtime::RuntimeCall::Timestamp(pallet_timestamp::Call::set { now }), + ) + .into(); + utx.into() } -fn import_block(mut client: &FullClient, built: BuiltBlock) { +fn import_block(client: &FullClient, built: BuiltBlock) { let mut params = BlockImportParams::new(BlockOrigin::File, built.block.header); params.state_action = StateAction::ApplyChanges(sc_consensus::StorageChanges::Changes(built.storage_changes)); diff --git a/substrate/bin/node/cli/benches/executor.rs b/substrate/bin/node/cli/benches/executor.rs index fa4da5c13d43..412b7f0ba0fc 100644 --- a/substrate/bin/node/cli/benches/executor.rs +++ b/substrate/bin/node/cli/benches/executor.rs @@ -31,7 +31,7 @@ use sp_core::{ storage::well_known_keys, traits::{CallContext, CodeExecutor, RuntimeCode}, }; -use sp_runtime::traits::BlakeTwo256; +use sp_runtime::{generic::ExtrinsicFormat, traits::BlakeTwo256}; use sp_state_machine::TestExternalities as CoreTestExternalities; use staging_node_cli::service::RuntimeExecutor; @@ -146,11 +146,11 @@ fn test_blocks( ) -> Vec<(Vec, Hash)> { let mut test_ext = new_test_ext(genesis_config); let mut block1_extrinsics = vec![CheckedExtrinsic { - signed: None, + format: ExtrinsicFormat::Bare, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: 0 }), }]; block1_extrinsics.extend((0..20).map(|i| CheckedExtrinsic { - signed: Some((alice(), signed_extra(i, 0))), + format: ExtrinsicFormat::Signed(alice(), tx_ext(i, 0)), function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: bob().into(), value: 1 * DOLLARS, diff --git a/substrate/bin/node/cli/benches/transaction_pool.rs b/substrate/bin/node/cli/benches/transaction_pool.rs index 6618f4b1132e..c07cb3ec0d13 100644 --- a/substrate/bin/node/cli/benches/transaction_pool.rs +++ b/substrate/bin/node/cli/benches/transaction_pool.rs @@ -16,14 +16,16 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use polkadot_sdk::*; -use std::time::Duration; - use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput}; use futures::{future, StreamExt}; use kitchensink_runtime::{constants::currency::*, BalancesCall, SudoCall}; use node_cli::service::{create_extrinsic, fetch_nonce, FullClient, TransactionPool}; use node_primitives::AccountId; +use polkadot_sdk::{ + sc_service::config::{ExecutorConfiguration, RpcConfiguration}, + sc_transaction_pool_api::TransactionPool as _, + *, +}; use sc_service::{ config::{ BlocksPruning, DatabaseSource, KeystoreConfig, NetworkConfiguration, OffchainWorkerConfig, @@ -31,8 +33,7 @@ use sc_service::{ }, BasePath, Configuration, Role, }; -use sc_transaction_pool::PoolLimit; -use sc_transaction_pool_api::{TransactionPool as _, TransactionSource, TransactionStatus}; +use sc_transaction_pool_api::{TransactionSource, TransactionStatus}; use sp_core::{crypto::Pair, sr25519}; use sp_keyring::Sr25519Keyring; use sp_runtime::OpaqueExtrinsic; @@ -57,12 +58,7 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { impl_version: "1.0".into(), role: Role::Authority, tokio_handle: tokio_handle.clone(), - transaction_pool: TransactionPoolOptions { - ready: PoolLimit { count: 100_000, total_bytes: 100 * 1024 * 1024 }, - future: PoolLimit { count: 100_000, total_bytes: 100 * 1024 * 1024 }, - reject_future_transactions: false, - ban_time: Duration::from_secs(30 * 60), - }, + transaction_pool: TransactionPoolOptions::new_for_benchmarks(), network: network_config, keystore: KeystoreConfig::InMemory, database: DatabaseSource::RocksDb { path: root.join("db"), cache_size: 128 }, @@ -70,36 +66,34 @@ fn new_node(tokio_handle: Handle) -> node_cli::service::NewFullBase { state_pruning: Some(PruningMode::ArchiveAll), blocks_pruning: BlocksPruning::KeepAll, chain_spec: spec, - wasm_method: Default::default(), - rpc_addr: None, - rpc_max_connections: Default::default(), - rpc_cors: None, - rpc_methods: Default::default(), - rpc_max_request_size: Default::default(), - rpc_max_response_size: Default::default(), - rpc_id_provider: Default::default(), - rpc_max_subs_per_conn: Default::default(), - rpc_port: 9944, - rpc_message_buffer_capacity: Default::default(), - rpc_batch_config: RpcBatchRequestConfig::Unlimited, - rpc_rate_limit: None, - rpc_rate_limit_whitelisted_ips: Default::default(), - rpc_rate_limit_trust_proxy_headers: Default::default(), + executor: ExecutorConfiguration::default(), + rpc: RpcConfiguration { + addr: None, + max_connections: Default::default(), + cors: None, + methods: Default::default(), + max_request_size: Default::default(), + max_response_size: Default::default(), + id_provider: Default::default(), + max_subs_per_conn: Default::default(), + port: 9944, + message_buffer_capacity: Default::default(), + batch_config: RpcBatchRequestConfig::Unlimited, + rate_limit: None, + rate_limit_whitelisted_ips: Default::default(), + rate_limit_trust_proxy_headers: Default::default(), + }, prometheus_config: None, telemetry_endpoints: None, - default_heap_pages: None, offchain_worker: OffchainWorkerConfig { enabled: true, indexing_enabled: false }, force_authoring: false, disable_grandpa: false, dev_key_seed: Some(Sr25519Keyring::Alice.to_seed()), tracing_targets: None, tracing_receiver: Default::default(), - max_runtime_instances: 8, - runtime_cache_size: 2, 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/chain_spec.rs b/substrate/bin/node/cli/src/chain_spec.rs index bc7821bfcf30..362deacba5f3 100644 --- a/substrate/bin/node/cli/src/chain_spec.rs +++ b/substrate/bin/node/cli/src/chain_spec.rs @@ -20,6 +20,7 @@ use polkadot_sdk::*; +use crate::chain_spec::{sc_service::Properties, sp_runtime::AccountId32}; use kitchensink_runtime::{ constants::currency::*, wasm_binary_unwrap, Block, MaxNominations, SessionKeys, StakerStatus, }; @@ -32,18 +33,17 @@ use sp_authority_discovery::AuthorityId as AuthorityDiscoveryId; use sp_consensus_babe::AuthorityId as BabeId; use sp_consensus_beefy::ecdsa_crypto::AuthorityId as BeefyId; use sp_consensus_grandpa::AuthorityId as GrandpaId; -use sp_core::{crypto::UncheckedInto, sr25519, Pair, Public}; -use sp_mixnet::types::AuthorityId as MixnetId; -use sp_runtime::{ - traits::{IdentifyAccount, Verify}, - Perbill, +use sp_core::{ + crypto::{get_public_from_string_or_panic, UncheckedInto}, + sr25519, }; +use sp_keyring::Sr25519Keyring; +use sp_mixnet::types::AuthorityId as MixnetId; +use sp_runtime::Perbill; pub use kitchensink_runtime::RuntimeGenesisConfig; pub use node_primitives::{AccountId, Balance, Signature}; -type AccountPublic = ::Signer; - const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; const ENDOWMENT: Balance = 10_000_000 * DOLLARS; const STASH: Balance = ENDOWMENT / 1000; @@ -246,35 +246,20 @@ pub fn staging_testnet_config() -> ChainSpec { .build() } -/// Helper function to generate a crypto pair from seed. -pub fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() -} - -/// Helper function to generate an account ID from seed. -pub fn get_account_id_from_seed(seed: &str) -> AccountId -where - AccountPublic: From<::Public>, -{ - AccountPublic::from(get_from_seed::(seed)).into_account() -} - /// Helper function to generate stash, controller and session key from seed. pub fn authority_keys_from_seed( seed: &str, ) -> (AccountId, AccountId, GrandpaId, BabeId, ImOnlineId, AuthorityDiscoveryId, MixnetId, BeefyId) { ( - get_account_id_from_seed::(&format!("{}//stash", seed)), - get_account_id_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), - get_from_seed::(seed), + get_public_from_string_or_panic::(&format!("{}//stash", seed)).into(), + get_public_from_string_or_panic::(seed).into(), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), + get_public_from_string_or_panic::(seed), ) } @@ -307,22 +292,8 @@ fn configure_accounts( usize, Vec<(AccountId, AccountId, Balance, StakerStatus)>, ) { - let mut endowed_accounts: Vec = endowed_accounts.unwrap_or_else(|| { - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - ] - }); + let mut endowed_accounts: Vec = + endowed_accounts.unwrap_or_else(default_endowed_accounts); // endow all authorities and nominators. initial_authorities .iter() @@ -429,7 +400,7 @@ pub fn testnet_genesis( "society": { "pot": 0 }, "assets": { // This asset is used by the NIS pallet as counterpart currency. - "assets": vec![(9, get_account_id_from_seed::("Alice"), true, 1)], + "assets": vec![(9, Sr25519Keyring::Alice.to_account_id(), true, 1)], }, "nominationPools": { "minCreateBond": 10 * DOLLARS, @@ -442,17 +413,45 @@ fn development_config_genesis_json() -> serde_json::Value { testnet_genesis( vec![authority_keys_from_seed("Alice")], vec![], - get_account_id_from_seed::("Alice"), + Sr25519Keyring::Alice.to_account_id(), None, ) } +fn props() -> Properties { + let mut properties = Properties::new(); + properties.insert("tokenDecimals".to_string(), 12.into()); + properties +} + +fn eth_account(from: subxt_signer::eth::Keypair) -> AccountId32 { + let mut account_id = AccountId32::new([0xEE; 32]); + >::as_mut(&mut account_id)[..20] + .copy_from_slice(&from.account_id().0); + account_id +} + +fn default_endowed_accounts() -> Vec { + Sr25519Keyring::well_known() + .map(|k| k.to_account_id()) + .chain([ + eth_account(subxt_signer::eth::dev::alith()), + eth_account(subxt_signer::eth::dev::baltathar()), + eth_account(subxt_signer::eth::dev::charleth()), + eth_account(subxt_signer::eth::dev::dorothy()), + eth_account(subxt_signer::eth::dev::ethan()), + eth_account(subxt_signer::eth::dev::faith()), + ]) + .collect() +} + /// Development config (single validator Alice). pub fn development_config() -> ChainSpec { ChainSpec::builder(wasm_binary_unwrap(), Default::default()) .with_name("Development") .with_id("dev") .with_chain_type(ChainType::Development) + .with_properties(props()) .with_genesis_config_patch(development_config_genesis_json()) .build() } @@ -461,7 +460,7 @@ fn local_testnet_genesis() -> serde_json::Value { testnet_genesis( vec![authority_keys_from_seed("Alice"), authority_keys_from_seed("Bob")], vec![], - get_account_id_from_seed::("Alice"), + Sr25519Keyring::Alice.to_account_id(), None, ) } @@ -492,7 +491,7 @@ pub(crate) mod tests { .with_genesis_config_patch(testnet_genesis( vec![authority_keys_from_seed("Alice")], vec![], - get_account_id_from_seed::("Alice"), + Sr25519Keyring::Alice.to_account_id(), None, )) .build() diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index e57ca04f3b74..d71f1304caf5 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -32,15 +32,17 @@ use frame_system_rpc_runtime_api::AccountNonceApi; use futures::prelude::*; use kitchensink_runtime::RuntimeApi; use node_primitives::Block; +use polkadot_sdk::sc_service::build_polkadot_syncing_strategy; use sc_client_api::{Backend, BlockBackend}; use sc_consensus_babe::{self, SlotProportion}; use sc_network::{ event::Event, service::traits::NetworkService, NetworkBackend, NetworkEventStream, }; -use sc_network_sync::{strategy::warp::WarpSyncParams, SyncingService}; +use sc_network_sync::{strategy::warp::WarpSyncConfig, SyncingService}; use sc_service::{config::Configuration, error::Error as ServiceError, RpcHandlers, TaskManager}; use sc_statement_store::Store as StatementStore; use sc_telemetry::{Telemetry, TelemetryWorker}; +use sc_transaction_pool::TransactionPoolHandle; use sc_transaction_pool_api::OffchainTransactionPoolFactory; use sp_api::ProvideRuntimeApi; use sp_core::crypto::Pair; @@ -79,7 +81,7 @@ type FullBeefyBlockImport = beefy::import::BeefyBlockImport< >; /// The transaction pool type definition. -pub type TransactionPool = sc_transaction_pool::FullPool; +pub type TransactionPool = sc_transaction_pool::TransactionPoolHandle; /// The minimum period of blocks on which justifications will be /// imported and generated. @@ -119,7 +121,7 @@ pub fn create_extrinsic( .map(|c| c / 2) .unwrap_or(2) as u64; let tip = 0; - let extra: kitchensink_runtime::SignedExtra = + let tx_ext: kitchensink_runtime::TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), @@ -141,7 +143,7 @@ pub fn create_extrinsic( let raw_payload = kitchensink_runtime::SignedPayload::from_raw( function.clone(), - extra.clone(), + tx_ext.clone(), ( (), kitchensink_runtime::VERSION.spec_version, @@ -156,12 +158,13 @@ pub fn create_extrinsic( ); let signature = raw_payload.using_encoded(|e| sender.sign(e)); - kitchensink_runtime::UncheckedExtrinsic::new_signed( + generic::UncheckedExtrinsic::new_signed( function, sp_runtime::AccountId32::from(sender.public()).into(), kitchensink_runtime::Signature::Sr25519(signature), - extra, + tx_ext, ) + .into() } /// Creates a new partial node. @@ -174,10 +177,9 @@ pub fn new_partial( FullBackend, FullSelectChain, sc_consensus::DefaultImportQueue, - sc_transaction_pool::FullPool, + sc_transaction_pool::TransactionPoolHandle, ( impl Fn( - node_rpc::DenyUnsafe, sc_rpc::SubscriptionTaskExecutor, ) -> Result, sc_service::Error>, ( @@ -209,7 +211,7 @@ pub fn new_partial( }) .transpose()?; - let executor = sc_service::new_wasm_executor(&config); + let executor = sc_service::new_wasm_executor(&config.executor); let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts::( @@ -226,12 +228,15 @@ pub fn new_partial( let select_chain = sc_consensus::LongestChain::new(backend.clone()); - let transaction_pool = sc_transaction_pool::BasicPool::new_full( - config.transaction_pool.clone(), - config.role.is_authority().into(), - config.prometheus_registry(), - task_manager.spawn_essential_handle(), - client.clone(), + let transaction_pool = Arc::from( + sc_transaction_pool::Builder::new( + task_manager.spawn_essential_handle(), + client.clone(), + config.role.is_authority().into(), + ) + .with_options(config.transaction_pool.clone()) + .with_prometheus(config.prometheus_registry()) + .build(), ); let (grandpa_block_import, grandpa_link) = grandpa::block_import( @@ -318,13 +323,12 @@ pub fn new_partial( let rpc_backend = backend.clone(); let rpc_statement_store = statement_store.clone(); let rpc_extensions_builder = - move |deny_unsafe, subscription_executor: node_rpc::SubscriptionTaskExecutor| { + move |subscription_executor: node_rpc::SubscriptionTaskExecutor| { let deps = node_rpc::FullDeps { client: client.clone(), pool: pool.clone(), select_chain: select_chain.clone(), chain_spec: chain_spec.cloned_box(), - deny_unsafe, babe: node_rpc::BabeDeps { keystore: keystore.clone(), babe_worker_handle: babe_worker_handle.clone(), @@ -386,7 +390,7 @@ pub struct NewFullBase { /// The syncing service of the node. pub sync: Arc>, /// The transaction pool of the node. - pub transaction_pool: Arc, + pub transaction_pool: Arc>, /// The rpc handlers of the node. pub rpc_handlers: RpcHandlers, } @@ -406,7 +410,7 @@ pub fn new_full_base::Hash>>( ), ) -> Result { let is_offchain_indexing_enabled = config.offchain_worker.indexing_enabled; - let role = config.role.clone(); + let role = config.role; let force_authoring = config.force_authoring; let backoff_authoring_blocks = Some(sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging::default()); @@ -418,7 +422,7 @@ pub fn new_full_base::Hash>>( let hwbench = (!disable_hardware_benchmarks) .then_some(config.database.path().map(|database_path| { let _ = std::fs::create_dir_all(&database_path); - sc_sysinfo::gather_hwbench(Some(database_path)) + sc_sysinfo::gather_hwbench(Some(database_path), &SUBSTRATE_REFERENCE_HARDWARE) })) .flatten(); @@ -441,8 +445,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(); @@ -506,6 +512,16 @@ pub fn new_full_base::Hash>>( Vec::default(), )); + let syncing_strategy = build_polkadot_syncing_strategy( + config.protocol_id(), + config.chain_spec.fork_id(), + &mut net_config, + Some(WarpSyncConfig::WithProvider(warp_sync)), + client.clone(), + &task_manager.spawn_handle(), + config.prometheus_config.as_ref().map(|config| &config.registry), + )?; + let (network, system_rpc_tx, tx_handler_controller, network_starter, sync_service) = sc_service::build_network(sc_service::BuildNetworkParams { config: &config, @@ -515,7 +531,7 @@ pub fn new_full_base::Hash>>( spawn_handle: task_manager.spawn_handle(), import_queue, block_announce_validator_builder: None, - warp_sync_params: Some(WarpSyncParams::WithProvider(warp_sync)), + syncing_strategy, block_relay: None, metrics, })?; @@ -553,7 +569,7 @@ pub fn new_full_base::Hash>>( if let Some(hwbench) = hwbench { sc_sysinfo::print_hwbench(&hwbench); - match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) { + match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench, false) { Err(err) if role.is_authority() => { log::warn!( "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority'.", @@ -717,7 +733,7 @@ pub fn new_full_base::Hash>>( name: Some(name), observer_enabled: false, keystore, - local_role: role.clone(), + local_role: role, telemetry: telemetry.as_ref().map(|x| x.handle()), protocol_name: grandpa_protocol_name, }; @@ -851,24 +867,24 @@ mod tests { use codec::Encode; use kitchensink_runtime::{ constants::{currency::CENTS, time::SLOT_DURATION}, - Address, BalancesCall, RuntimeCall, UncheckedExtrinsic, + Address, BalancesCall, RuntimeCall, TxExtension, }; use node_primitives::{Block, DigestItem, Signature}; - use polkadot_sdk::*; + use polkadot_sdk::{sc_transaction_pool_api::MaintainedTransactionPool, *}; use sc_client_api::BlockBackend; use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy}; use sc_consensus_babe::{BabeIntermediate, CompatibleDigestItem, INTERMEDIATE_KEY}; use sc_consensus_epochs::descendent_query; use sc_keystore::LocalKeystore; use sc_service_test::TestNetNode; - use sc_transaction_pool_api::{ChainEvent, MaintainedTransactionPool}; + use sc_transaction_pool_api::ChainEvent; use sp_consensus::{BlockOrigin, Environment, Proposer}; use sp_core::crypto::Pair; use sp_inherents::InherentDataProvider; use sp_keyring::AccountKeyring; use sp_keystore::KeystorePtr; use sp_runtime::{ - generic::{Digest, Era, SignedPayload}, + generic::{self, Digest, Era, SignedPayload}, key_types::BABE, traits::{Block as BlockT, Header as HeaderT, IdentifyAccount, Verify}, RuntimeAppPublic, @@ -1055,7 +1071,7 @@ mod tests { pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::from(0, None), ); let metadata_hash = frame_metadata_hash_extension::CheckMetadataHash::new(false); - let extra = ( + let tx_ext: TxExtension = ( check_non_zero_sender, check_spec_version, check_tx_version, @@ -1068,7 +1084,7 @@ mod tests { ); let raw_payload = SignedPayload::from_raw( function, - extra, + tx_ext, ( (), spec_version, @@ -1082,10 +1098,18 @@ mod tests { ), ); let signature = raw_payload.using_encoded(|payload| signer.sign(payload)); - let (function, extra, _) = raw_payload.deconstruct(); + let (function, tx_ext, _) = raw_payload.deconstruct(); index += 1; - UncheckedExtrinsic::new_signed(function, from.into(), signature.into(), extra) - .into() + let utx: kitchensink_runtime::UncheckedExtrinsic = + generic::UncheckedExtrinsic::new_signed( + function, + from.into(), + signature.into(), + tx_ext, + ) + .into(); + + utx.into() }, ); } diff --git a/substrate/bin/node/cli/tests/basic.rs b/substrate/bin/node/cli/tests/basic.rs index b1f737ce399b..8f1475fce4f8 100644 --- a/substrate/bin/node/cli/tests/basic.rs +++ b/substrate/bin/node/cli/tests/basic.rs @@ -17,11 +17,11 @@ use codec::{Decode, Encode, Joiner}; use frame_support::{ - dispatch::{DispatchClass, DispatchInfo, GetDispatchInfo}, + dispatch::{DispatchClass, GetDispatchInfo}, traits::Currency, weights::Weight, }; -use frame_system::{self, AccountInfo, EventRecord, Phase}; +use frame_system::{self, AccountInfo, DispatchEventInfo, EventRecord, Phase}; use polkadot_sdk::*; use sp_core::{storage::well_known_keys, traits::Externalities}; use sp_runtime::{ @@ -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; @@ -58,17 +59,23 @@ pub fn bloaty_code_unwrap() -> &'static [u8] { /// Note that reads the multiplier from storage directly, hence to get the fee of `extrinsic` /// at block `n`, it must be called prior to executing block `n` to do the calculation with the /// correct multiplier. -fn transfer_fee(extrinsic: &E) -> Balance { - TransactionPayment::compute_fee( - extrinsic.encode().len() as u32, - &default_transfer_call().get_dispatch_info(), - 0, - ) +fn transfer_fee(extrinsic: &UncheckedExtrinsic) -> Balance { + let mut info = default_transfer_call().get_dispatch_info(); + info.extension_weight = extrinsic.0.extension_weight(); + TransactionPayment::compute_fee(extrinsic.encode().len() as u32, &info, 0) +} + +/// Default transfer fee, same as `transfer_fee`, but with a weight refund factored in. +fn transfer_fee_with_refund(extrinsic: &UncheckedExtrinsic, weight_refund: Weight) -> Balance { + let mut info = default_transfer_call().get_dispatch_info(); + info.extension_weight = extrinsic.0.extension_weight(); + let post_info = (Some(info.total_weight().saturating_sub(weight_refund)), info.pays_fee).into(); + TransactionPayment::compute_actual_fee(extrinsic.encode().len() as u32, &info, &post_info, 0) } fn xt() -> UncheckedExtrinsic { sign(CheckedExtrinsic { - signed: Some((alice(), signed_extra(0, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(0, 0)), function: RuntimeCall::Balances(default_transfer_call()), }) } @@ -85,11 +92,11 @@ fn changes_trie_block() -> (Vec, Hash) { GENESIS_HASH.into(), vec![ CheckedExtrinsic { - signed: None, + format: sp_runtime::generic::ExtrinsicFormat::Bare, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time }), }, CheckedExtrinsic { - signed: Some((alice(), signed_extra(0, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(0, 0)), function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: bob().into(), value: 69 * DOLLARS, @@ -112,11 +119,11 @@ fn blocks() -> ((Vec, Hash), (Vec, Hash)) { GENESIS_HASH.into(), vec![ CheckedExtrinsic { - signed: None, + format: sp_runtime::generic::ExtrinsicFormat::Bare, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time1 }), }, CheckedExtrinsic { - signed: Some((alice(), signed_extra(0, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(0, 0)), function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: bob().into(), value: 69 * DOLLARS, @@ -132,18 +139,18 @@ fn blocks() -> ((Vec, Hash), (Vec, Hash)) { block1.1, vec![ CheckedExtrinsic { - signed: None, + format: sp_runtime::generic::ExtrinsicFormat::Bare, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time2 }), }, CheckedExtrinsic { - signed: Some((bob(), signed_extra(0, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(bob(), tx_ext(0, 0)), function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: alice().into(), value: 5 * DOLLARS, }), }, CheckedExtrinsic { - signed: Some((alice(), signed_extra(1, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(1, 0)), function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest: bob().into(), value: 15 * DOLLARS, @@ -167,11 +174,11 @@ fn block_with_size(time: u64, nonce: u32, size: usize) -> (Vec, Hash) { GENESIS_HASH.into(), vec![ CheckedExtrinsic { - signed: None, + format: sp_runtime::generic::ExtrinsicFormat::Bare, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time * 1000 }), }, CheckedExtrinsic { - signed: Some((alice(), signed_extra(nonce, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(nonce, 0)), function: RuntimeCall::System(frame_system::Call::remark { remark: vec![0; size] }), }, ], @@ -256,13 +263,14 @@ fn successful_execution_with_native_equivalent_code_gives_ok() { let r = executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32))).0; assert!(r.is_ok()); - let fees = t.execute_with(|| transfer_fee(&xt())); + let weight_refund = Weight::zero(); + let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund)); let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt())).0; assert!(r.is_ok()); t.execute_with(|| { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees_after_refund); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } @@ -296,13 +304,14 @@ fn successful_execution_with_foreign_code_gives_ok() { let r = executor_call(&mut t, "Core_initialize_block", &vec![].and(&from_block_number(1u32))).0; assert!(r.is_ok()); - let fees = t.execute_with(|| transfer_fee(&xt())); + let weight_refund = Weight::zero(); + let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund)); let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt())).0; assert!(r.is_ok()); t.execute_with(|| { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees_after_refund); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } @@ -315,15 +324,18 @@ fn full_native_block_import_works() { let mut alice_last_known_balance: Balance = Default::default(); let mut fees = t.execute_with(|| transfer_fee(&xt())); + let extension_weight = xt().0.extension_weight(); + let weight_refund = Weight::zero(); + let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund)); - let transfer_weight = default_transfer_call().get_dispatch_info().weight.saturating_add( + let transfer_weight = default_transfer_call().get_dispatch_info().call_weight.saturating_add( ::BlockWeights::get() .get(DispatchClass::Normal) .base_extrinsic, ); let timestamp_weight = pallet_timestamp::Call::set:: { now: Default::default() } .get_dispatch_info() - .weight + .call_weight .saturating_add( ::BlockWeights::get() .get(DispatchClass::Mandatory) @@ -333,17 +345,17 @@ fn full_native_block_import_works() { executor_call(&mut t, "Core_execute_block", &block1.0).0.unwrap(); t.execute_with(|| { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees_after_refund); assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); alice_last_known_balance = Balances::total_balance(&alice()); let events = vec![ EventRecord { phase: Phase::ApplyExtrinsic(0), event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { - dispatch_info: DispatchInfo { + dispatch_info: DispatchEventInfo { weight: timestamp_weight, class: DispatchClass::Mandatory, - ..Default::default() + pays_fee: Default::default(), }, }), topics: vec![], @@ -369,14 +381,21 @@ fn full_native_block_import_works() { phase: Phase::ApplyExtrinsic(1), event: RuntimeEvent::Balances(pallet_balances::Event::Deposit { who: pallet_treasury::Pallet::::account_id(), - amount: fees * 8 / 10, + amount: fees_after_refund * 8 / 10, }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: RuntimeEvent::Treasury(pallet_treasury::Event::Deposit { - value: fees * 8 / 10, + value: fees_after_refund * 8 / 10, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(1), + event: RuntimeEvent::Balances(pallet_balances::Event::Rescinded { + amount: fees_after_refund * 2 / 10, }), topics: vec![], }, @@ -385,7 +404,7 @@ fn full_native_block_import_works() { event: RuntimeEvent::TransactionPayment( pallet_transaction_payment::Event::TransactionFeePaid { who: alice().into(), - actual_fee: fees, + actual_fee: fees_after_refund, tip: 0, }, ), @@ -394,7 +413,11 @@ fn full_native_block_import_works() { EventRecord { phase: Phase::ApplyExtrinsic(1), event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { - dispatch_info: DispatchInfo { weight: transfer_weight, ..Default::default() }, + dispatch_info: DispatchEventInfo { + weight: transfer_weight + .saturating_add(extension_weight.saturating_sub(weight_refund)), + ..Default::default() + }, }), topics: vec![], }, @@ -404,15 +427,18 @@ fn full_native_block_import_works() { fees = t.execute_with(|| transfer_fee(&xt())); let pot = t.execute_with(|| Treasury::pot()); + let extension_weight = xt().0.extension_weight(); + let weight_refund = Weight::zero(); + let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund)); executor_call(&mut t, "Core_execute_block", &block2.0).0.unwrap(); t.execute_with(|| { assert_eq!( Balances::total_balance(&alice()), - alice_last_known_balance - 10 * DOLLARS - fees, + alice_last_known_balance - 10 * DOLLARS - fees_after_refund, ); - assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - fees); + assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - fees_after_refund); let events = vec![ EventRecord { phase: Phase::Initialization, @@ -425,10 +451,10 @@ fn full_native_block_import_works() { EventRecord { phase: Phase::ApplyExtrinsic(0), event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { - dispatch_info: DispatchInfo { + dispatch_info: DispatchEventInfo { weight: timestamp_weight, class: DispatchClass::Mandatory, - ..Default::default() + pays_fee: Default::default(), }, }), topics: vec![], @@ -454,14 +480,21 @@ fn full_native_block_import_works() { phase: Phase::ApplyExtrinsic(1), event: RuntimeEvent::Balances(pallet_balances::Event::Deposit { who: pallet_treasury::Pallet::::account_id(), - amount: fees * 8 / 10, + amount: fees_after_refund * 8 / 10, }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(1), event: RuntimeEvent::Treasury(pallet_treasury::Event::Deposit { - value: fees * 8 / 10, + value: fees_after_refund * 8 / 10, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(1), + event: RuntimeEvent::Balances(pallet_balances::Event::Rescinded { + amount: fees_after_refund - fees_after_refund * 8 / 10, }), topics: vec![], }, @@ -470,7 +503,7 @@ fn full_native_block_import_works() { event: RuntimeEvent::TransactionPayment( pallet_transaction_payment::Event::TransactionFeePaid { who: bob().into(), - actual_fee: fees, + actual_fee: fees_after_refund, tip: 0, }, ), @@ -479,7 +512,11 @@ fn full_native_block_import_works() { EventRecord { phase: Phase::ApplyExtrinsic(1), event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { - dispatch_info: DispatchInfo { weight: transfer_weight, ..Default::default() }, + dispatch_info: DispatchEventInfo { + weight: transfer_weight + .saturating_add(extension_weight.saturating_sub(weight_refund)), + ..Default::default() + }, }), topics: vec![], }, @@ -504,14 +541,21 @@ fn full_native_block_import_works() { phase: Phase::ApplyExtrinsic(2), event: RuntimeEvent::Balances(pallet_balances::Event::Deposit { who: pallet_treasury::Pallet::::account_id(), - amount: fees * 8 / 10, + amount: fees_after_refund * 8 / 10, }), topics: vec![], }, EventRecord { phase: Phase::ApplyExtrinsic(2), event: RuntimeEvent::Treasury(pallet_treasury::Event::Deposit { - value: fees * 8 / 10, + value: fees_after_refund * 8 / 10, + }), + topics: vec![], + }, + EventRecord { + phase: Phase::ApplyExtrinsic(2), + event: RuntimeEvent::Balances(pallet_balances::Event::Rescinded { + amount: fees_after_refund - fees_after_refund * 8 / 10, }), topics: vec![], }, @@ -520,7 +564,7 @@ fn full_native_block_import_works() { event: RuntimeEvent::TransactionPayment( pallet_transaction_payment::Event::TransactionFeePaid { who: alice().into(), - actual_fee: fees, + actual_fee: fees_after_refund, tip: 0, }, ), @@ -529,7 +573,11 @@ fn full_native_block_import_works() { EventRecord { phase: Phase::ApplyExtrinsic(2), event: RuntimeEvent::System(frame_system::Event::ExtrinsicSuccess { - dispatch_info: DispatchInfo { weight: transfer_weight, ..Default::default() }, + dispatch_info: DispatchEventInfo { + weight: transfer_weight + .saturating_add(extension_weight.saturating_sub(weight_refund)), + ..Default::default() + }, }), topics: vec![], }, @@ -545,26 +593,28 @@ fn full_wasm_block_import_works() { let (block1, block2) = blocks(); let mut alice_last_known_balance: Balance = Default::default(); - let mut fees = t.execute_with(|| transfer_fee(&xt())); + let weight_refund = Weight::zero(); + let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund)); executor_call(&mut t, "Core_execute_block", &block1.0).0.unwrap(); t.execute_with(|| { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees_after_refund); assert_eq!(Balances::total_balance(&bob()), 169 * DOLLARS); alice_last_known_balance = Balances::total_balance(&alice()); }); - fees = t.execute_with(|| transfer_fee(&xt())); + let weight_refund = Weight::zero(); + let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund)); executor_call(&mut t, "Core_execute_block", &block2.0).0.unwrap(); t.execute_with(|| { assert_eq!( Balances::total_balance(&alice()), - alice_last_known_balance - 10 * DOLLARS - fees, + alice_last_known_balance - 10 * DOLLARS - fees_after_refund, ); - assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - 1 * fees); + assert_eq!(Balances::total_balance(&bob()), 179 * DOLLARS - 1 * fees_after_refund); }); } @@ -678,11 +728,11 @@ fn deploying_wasm_contract_should_work() { GENESIS_HASH.into(), vec![ CheckedExtrinsic { - signed: None, + format: sp_runtime::generic::ExtrinsicFormat::Bare, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time }), }, CheckedExtrinsic { - signed: Some((charlie(), signed_extra(0, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(charlie(), tx_ext(0, 0)), function: RuntimeCall::Contracts(pallet_contracts::Call::instantiate_with_code::< Runtime, > { @@ -695,7 +745,7 @@ fn deploying_wasm_contract_should_work() { }), }, CheckedExtrinsic { - signed: Some((charlie(), signed_extra(1, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(charlie(), tx_ext(1, 0)), function: RuntimeCall::Contracts(pallet_contracts::Call::call:: { dest: sp_runtime::MultiAddress::Id(addr.clone()), value: 10, @@ -806,7 +856,8 @@ fn successful_execution_gives_ok() { assert_eq!(Balances::total_balance(&alice()), 111 * DOLLARS); }); - let fees = t.execute_with(|| transfer_fee(&xt())); + let weight_refund = Weight::zero(); + let fees_after_refund = t.execute_with(|| transfer_fee_with_refund(&xt(), weight_refund)); let r = executor_call(&mut t, "BlockBuilder_apply_extrinsic", &vec![].and(&xt())) .0 @@ -817,7 +868,7 @@ fn successful_execution_gives_ok() { .expect("Extrinsic failed"); t.execute_with(|| { - assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees); + assert_eq!(Balances::total_balance(&alice()), 42 * DOLLARS - fees_after_refund); assert_eq!(Balances::total_balance(&bob()), 69 * DOLLARS); }); } @@ -828,7 +879,7 @@ fn should_import_block_with_test_client() { sp_consensus::BlockOrigin, ClientBlockImportExt, TestClientBuilder, TestClientBuilderExt, }; - let mut client = TestClientBuilder::new().build(); + let client = TestClientBuilder::new().build(); let block1 = changes_trie_block(); let block_data = block1.0; let block = node_primitives::Block::decode(&mut &block_data[..]).unwrap(); diff --git a/substrate/bin/node/cli/tests/benchmark_pallet_works.rs b/substrate/bin/node/cli/tests/benchmark_pallet_works.rs index 8441333429be..d913228881a4 100644 --- a/substrate/bin/node/cli/tests/benchmark_pallet_works.rs +++ b/substrate/bin/node/cli/tests/benchmark_pallet_works.rs @@ -33,6 +33,31 @@ fn benchmark_pallet_works() { benchmark_pallet(20, 50, true); } +#[test] +fn benchmark_pallet_args_work() { + benchmark_pallet_args(&["--list", "--pallet=pallet_balances"], true); + benchmark_pallet_args(&["--list", "--pallet=pallet_balances"], true); + benchmark_pallet_args( + &["--list", "--pallet=pallet_balances", "--genesis-builder=spec-genesis"], + true, + ); + benchmark_pallet_args( + &["--list", "--pallet=pallet_balances", "--chain=dev", "--genesis-builder=spec-genesis"], + true, + ); + + // Error because the genesis runtime does not have any presets in it: + benchmark_pallet_args( + &["--list", "--pallet=pallet_balances", "--chain=dev", "--genesis-builder=spec-runtime"], + false, + ); + // Error because no runtime is provided: + benchmark_pallet_args( + &["--list", "--pallet=pallet_balances", "--chain=dev", "--genesis-builder=runtime"], + false, + ); +} + fn benchmark_pallet(steps: u32, repeat: u32, should_work: bool) { let status = Command::new(cargo_bin("substrate-node")) .args(["benchmark", "pallet", "--dev"]) @@ -51,3 +76,13 @@ fn benchmark_pallet(steps: u32, repeat: u32, should_work: bool) { assert_eq!(status.success(), should_work); } + +fn benchmark_pallet_args(args: &[&str], should_work: bool) { + let status = Command::new(cargo_bin("substrate-node")) + .args(["benchmark", "pallet"]) + .args(args) + .status() + .unwrap(); + + assert_eq!(status.success(), should_work); +} diff --git a/substrate/bin/node/cli/tests/fees.rs b/substrate/bin/node/cli/tests/fees.rs index 9f82338b4fb0..da9d2662408e 100644 --- a/substrate/bin/node/cli/tests/fees.rs +++ b/substrate/bin/node/cli/tests/fees.rs @@ -55,11 +55,11 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() { GENESIS_HASH.into(), vec![ CheckedExtrinsic { - signed: None, + format: sp_runtime::generic::ExtrinsicFormat::Bare, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time1 }), }, CheckedExtrinsic { - signed: Some((charlie(), signed_extra(0, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(charlie(), tx_ext(0, 0)), function: RuntimeCall::Sudo(pallet_sudo::Call::sudo { call: Box::new(RuntimeCall::RootTesting( pallet_root_testing::Call::fill_block { ratio: Perbill::from_percent(60) }, @@ -78,11 +78,11 @@ fn fee_multiplier_increases_and_decreases_on_big_weight() { block1.1, vec![ CheckedExtrinsic { - signed: None, + format: sp_runtime::generic::ExtrinsicFormat::Bare, function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time2 }), }, CheckedExtrinsic { - signed: Some((charlie(), signed_extra(1, 0))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(charlie(), tx_ext(1, 0)), function: RuntimeCall::System(frame_system::Call::remark { remark: vec![0; 1] }), }, ], @@ -148,7 +148,7 @@ fn transaction_fee_is_correct() { let tip = 1_000_000; let xt = sign(CheckedExtrinsic { - signed: Some((alice(), signed_extra(0, tip))), + format: sp_runtime::generic::ExtrinsicFormat::Signed(alice(), tx_ext(0, tip)), function: RuntimeCall::Balances(default_transfer_call()), }); @@ -174,7 +174,9 @@ fn transaction_fee_is_correct() { let length_fee = TransactionByteFee::get() * (xt.clone().encode().len() as Balance); balance_alice -= length_fee; - let weight = default_transfer_call().get_dispatch_info().weight; + let mut info = default_transfer_call().get_dispatch_info(); + info.extension_weight = xt.0.extension_weight(); + let weight = info.total_weight(); let weight_fee = IdentityFee::::weight_to_fee(&weight); // we know that weight to fee multiplier is effect-less in block 1. @@ -188,135 +190,3 @@ fn transaction_fee_is_correct() { assert_eq!(Balances::total_balance(&alice()), balance_alice); }); } - -#[test] -#[should_panic] -#[cfg(feature = "stress-test")] -fn block_weight_capacity_report() { - // Just report how many transfer calls you could fit into a block. The number should at least - // be a few hundred (250 at the time of writing but can change over time). Runs until panic. - use node_primitives::Nonce; - - // execution ext. - let mut t = new_test_ext(compact_code_unwrap()); - // setup ext. - let mut tt = new_test_ext(compact_code_unwrap()); - - let factor = 50; - let mut time = 10; - let mut nonce: Nonce = 0; - let mut block_number = 1; - let mut previous_hash: node_primitives::Hash = GENESIS_HASH.into(); - - loop { - let num_transfers = block_number * factor; - let mut xts = (0..num_transfers) - .map(|i| CheckedExtrinsic { - signed: Some((charlie(), signed_extra(nonce + i as Nonce, 0))), - function: RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { - dest: bob().into(), - value: 0, - }), - }) - .collect::>(); - - xts.insert( - 0, - CheckedExtrinsic { - signed: None, - function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { now: time * 1000 }), - }, - ); - - // NOTE: this is super slow. Can probably be improved. - let block = construct_block( - &mut tt, - block_number, - previous_hash, - xts, - (time * 1000 / SLOT_DURATION).into(), - ); - - let len = block.0.len(); - print!( - "++ Executing block with {} transfers. Block size = {} bytes / {} kb / {} mb", - num_transfers, - len, - len / 1024, - len / 1024 / 1024, - ); - - let r = executor_call(&mut t, "Core_execute_block", &block.0).0; - - println!(" || Result = {:?}", r); - assert!(r.is_ok()); - - previous_hash = block.1; - nonce += num_transfers; - time += 10; - block_number += 1; - } -} - -#[test] -#[should_panic] -#[cfg(feature = "stress-test")] -fn block_length_capacity_report() { - // Just report how big a block can get. Executes until panic. Should be ignored unless if - // manually inspected. The number should at least be a few megabytes (5 at the time of - // writing but can change over time). - use node_primitives::Nonce; - - // execution ext. - let mut t = new_test_ext(compact_code_unwrap()); - // setup ext. - let mut tt = new_test_ext(compact_code_unwrap()); - - let factor = 256 * 1024; - let mut time = 10; - let mut nonce: Nonce = 0; - let mut block_number = 1; - let mut previous_hash: node_primitives::Hash = GENESIS_HASH.into(); - - loop { - // NOTE: this is super slow. Can probably be improved. - let block = construct_block( - &mut tt, - block_number, - previous_hash, - vec![ - CheckedExtrinsic { - signed: None, - function: RuntimeCall::Timestamp(pallet_timestamp::Call::set { - now: time * 1000, - }), - }, - CheckedExtrinsic { - signed: Some((charlie(), signed_extra(nonce, 0))), - function: RuntimeCall::System(frame_system::Call::remark { - remark: vec![0u8; (block_number * factor) as usize], - }), - }, - ], - (time * 1000 / SLOT_DURATION).into(), - ); - - let len = block.0.len(); - print!( - "++ Executing block with big remark. Block size = {} bytes / {} kb / {} mb", - len, - len / 1024, - len / 1024 / 1024, - ); - - let r = executor_call(&mut t, "Core_execute_block", &block.0).0; - - println!(" || Result = {:?}", r); - assert!(r.is_ok()); - - previous_hash = block.1; - nonce += 1; - time += 10; - block_number += 1; - } -} 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 b63e5ff549ef..a2e52837d882 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/cli/tests/submit_transaction.rs b/substrate/bin/node/cli/tests/submit_transaction.rs index 18826e7e90a7..3672432ae342 100644 --- a/substrate/bin/node/cli/tests/submit_transaction.rs +++ b/substrate/bin/node/cli/tests/submit_transaction.rs @@ -23,6 +23,7 @@ use sp_application_crypto::AppCrypto; use sp_core::offchain::{testing::TestTransactionPoolExt, TransactionPoolExt}; use sp_keyring::sr25519::Keyring::Alice; use sp_keystore::{testing::MemoryKeystore, Keystore, KeystoreExt}; +use sp_runtime::generic; pub mod common; use self::common::*; @@ -44,10 +45,9 @@ fn should_submit_unsigned_transaction() { }; let call = pallet_im_online::Call::heartbeat { heartbeat: heartbeat_data, signature }; - SubmitTransaction::>::submit_unsigned_transaction( - call.into(), - ) - .unwrap(); + let xt = generic::UncheckedExtrinsic::new_bare(call.into()).into(); + SubmitTransaction::>::submit_transaction(xt) + .unwrap(); assert_eq!(state.read().transactions.len(), 1) }); @@ -131,7 +131,7 @@ fn should_submit_signed_twice_from_the_same_account() { // now check that the transaction nonces are not equal let s = state.read(); fn nonce(tx: UncheckedExtrinsic) -> frame_system::CheckNonce { - let extra = tx.signature.unwrap().2; + let extra = tx.0.preamble.to_signed().unwrap().2; extra.5 } let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap()); @@ -180,7 +180,7 @@ fn should_submit_signed_twice_from_all_accounts() { // now check that the transaction nonces are not equal let s = state.read(); fn nonce(tx: UncheckedExtrinsic) -> frame_system::CheckNonce { - let extra = tx.signature.unwrap().2; + let extra = tx.0.preamble.to_signed().unwrap().2; extra.5 } let nonce1 = nonce(UncheckedExtrinsic::decode(&mut &*s.transactions[0]).unwrap()); @@ -237,7 +237,7 @@ fn submitted_transaction_should_be_valid() { let source = TransactionSource::External; let extrinsic = UncheckedExtrinsic::decode(&mut &*tx0).unwrap(); // add balance to the account - let author = extrinsic.signature.clone().unwrap().0; + let author = extrinsic.0.preamble.clone().to_signed().clone().unwrap().0; let address = Indices::lookup(author).unwrap(); let data = pallet_balances::AccountData { free: 5_000_000_000_000, ..Default::default() }; let account = frame_system::AccountInfo { providers: 1, data, ..Default::default() }; diff --git a/substrate/bin/node/inspect/Cargo.toml b/substrate/bin/node/inspect/Cargo.toml index 68769ffb4fa4..6c8a4e59f68d 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/inspect/src/command.rs b/substrate/bin/node/inspect/src/command.rs index e0e25707e31b..b9e5e55be8ef 100644 --- a/substrate/bin/node/inspect/src/command.rs +++ b/substrate/bin/node/inspect/src/command.rs @@ -36,7 +36,7 @@ impl InspectCmd { B: Block, RA: Send + Sync + 'static, { - let executor = sc_service::new_wasm_executor::(&config); + let executor = sc_service::new_wasm_executor::(&config.executor); let client = sc_service::new_full_client::(&config, None, executor)?; let inspect = Inspector::::new(client); diff --git a/substrate/bin/node/primitives/Cargo.toml b/substrate/bin/node/primitives/Cargo.toml index de295fd59d45..87271439921a 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 fa1e96e67e98..02f5d9a4a702 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 @@ -31,8 +31,6 @@ sc-consensus-grandpa = { workspace = true, default-features = true } sc-consensus-grandpa-rpc = { workspace = true, default-features = true } sc-mixnet = { workspace = true, default-features = true } sc-rpc = { workspace = true, default-features = true } -sc-rpc-api = { workspace = true, default-features = true } -sc-rpc-spec-v2 = { workspace = true, default-features = true } sc-sync-state-rpc = { workspace = true, default-features = true } sc-transaction-pool-api = { workspace = true, default-features = true } sp-api = { workspace = true, default-features = true } diff --git a/substrate/bin/node/rpc/src/lib.rs b/substrate/bin/node/rpc/src/lib.rs index 52cd7f9561d2..988502bb2bfd 100644 --- a/substrate/bin/node/rpc/src/lib.rs +++ b/substrate/bin/node/rpc/src/lib.rs @@ -44,7 +44,6 @@ use sc_consensus_grandpa::{ FinalityProofProvider, GrandpaJustificationStream, SharedAuthoritySet, SharedVoterState, }; pub use sc_rpc::SubscriptionTaskExecutor; -pub use sc_rpc_api::DenyUnsafe; use sc_transaction_pool_api::TransactionPool; use sp_api::ProvideRuntimeApi; use sp_application_crypto::RuntimeAppPublic; @@ -97,8 +96,6 @@ pub struct FullDeps { pub select_chain: SC, /// A copy of the chain spec. pub chain_spec: Box, - /// Whether to deny unsafe calls - pub deny_unsafe: DenyUnsafe, /// BABE specific dependencies. pub babe: BabeDeps, /// GRANDPA specific dependencies. @@ -120,7 +117,6 @@ pub fn create_full( pool, select_chain, chain_spec, - deny_unsafe, babe, grandpa, beefy, @@ -160,7 +156,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,12 +171,7 @@ 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())?; + io.merge(System::new(client.clone(), pool).into_rpc())?; // Making synchronous calls in light client freezes the browser currently, // more context: https://github.com/paritytech/substrate/pull/3480 // These RPCs should use an asynchronous caller instead. @@ -196,8 +186,7 @@ where )?; io.merge(TransactionPayment::new(client.clone()).into_rpc())?; io.merge( - Babe::new(client.clone(), babe_worker_handle.clone(), keystore, select_chain, deny_unsafe) - .into_rpc(), + Babe::new(client.clone(), babe_worker_handle.clone(), keystore, select_chain).into_rpc(), )?; io.merge( Grandpa::new( @@ -215,10 +204,9 @@ where .into_rpc(), )?; - io.merge(StateMigration::new(client.clone(), backend, deny_unsafe).into_rpc())?; - io.merge(Dev::new(client, deny_unsafe).into_rpc())?; - let statement_store = - sc_rpc::statement::StatementStore::new(statement_store, deny_unsafe).into_rpc(); + io.merge(StateMigration::new(client.clone(), backend).into_rpc())?; + io.merge(Dev::new(client).into_rpc())?; + let statement_store = sc_rpc::statement::StatementStore::new(statement_store).into_rpc(); io.merge(statement_store)?; if let Some(mixnet_api) = mixnet_api { diff --git a/substrate/bin/node/runtime/Cargo.toml b/substrate/bin/node/runtime/Cargo.toml index c1c470f1dcd6..7acf4294c51b 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 @@ -27,11 +27,12 @@ scale-info = { features = ["derive", "serde"], workspace = true } static_assertions = { workspace = true, default-features = true } log = { workspace = true } serde_json = { features = ["alloc", "arbitrary_precision"], workspace = true } +sp-debug-derive = { workspace = true, features = ["force-debug"] } # pallet-asset-conversion: turn on "num-traits" feature primitive-types = { features = ["codec", "num-traits", "scale-info"], workspace = true } -polkadot-sdk = { features = ["runtime", "tuples-96"], workspace = true } +polkadot-sdk = { features = ["runtime-full", "tuples-96"], workspace = true } # shared code between runtime and node node-primitives = { workspace = true } @@ -56,6 +57,7 @@ std = [ "primitive-types/std", "scale-info/std", "serde_json/std", + "sp-debug-derive/std", "substrate-wasm-builder", ] runtime-benchmarks = [ @@ -71,5 +73,5 @@ try-runtime = [ experimental = [ "pallet-example-tasks/experimental", ] - metadata-hash = ["substrate-wasm-builder/metadata-hash"] +riscv = ["polkadot-sdk/riscv"] diff --git a/substrate/bin/node/runtime/src/impls.rs b/substrate/bin/node/runtime/src/impls.rs index 6c121fad624b..43e7a766e0e8 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 a1896325ee93..d6a17856e470 100644 --- a/substrate/bin/node/runtime/src/lib.rs +++ b/substrate/bin/node/runtime/src/lib.rs @@ -49,8 +49,8 @@ use frame_support::{ imbalance::ResolveAssetTo, nonfungibles_v2::Inspect, pay::PayAssetFromAccount, GetSalary, PayFromAccount, }, - AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, Contains, Currency, - EitherOfDiverse, EnsureOriginWithArg, EqualPrivilegeOnly, Imbalance, InsideBoth, + AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, ConstU64, Contains, + Currency, EitherOfDiverse, EnsureOriginWithArg, EqualPrivilegeOnly, Imbalance, InsideBoth, InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, LockIdentifier, Nothing, OnUnbalanced, VariantCountOf, WithdrawReasons, }, @@ -69,15 +69,18 @@ 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; use pallet_im_online::sr25519::AuthorityId as ImOnlineId; use pallet_nfts::PalletFeatures; use pallet_nis::WithMaximumOf; +use pallet_revive::evm::runtime::EthExtra; 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}; @@ -89,19 +92,19 @@ use sp_consensus_beefy::{ mmr::MmrLeafVersion, }; use sp_consensus_grandpa::AuthorityId as GrandpaId; -use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; +use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H160}; use sp_inherents::{CheckInherentsResult, InherentData}; use sp_runtime::{ create_runtime_str, 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, - RuntimeDebug, + ApplyExtrinsicResult, FixedPointNumber, FixedU128, MultiSignature, MultiSigner, Perbill, + Percent, Permill, Perquintill, RuntimeDebug, }; #[cfg(any(feature = "std", test))] use sp_version::NativeVersion; @@ -123,7 +126,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; @@ -169,7 +172,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 2, - state_version: 1, + system_version: 1, }; /// The BABE epoch configuration at genesis. @@ -189,7 +192,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); @@ -505,8 +508,7 @@ impl pallet_babe::Config for Runtime { type WeightInfo = (); type MaxAuthorities = MaxAuthorities; type MaxNominators = MaxNominators; - type KeyOwnerProof = - >::Proof; + type KeyOwnerProof = sp_session::MembershipProof; type EquivocationReportSystem = pallet_babe::EquivocationReportSystem; } @@ -545,6 +547,7 @@ impl pallet_balances::Config for Runtime { type WeightInfo = pallet_balances::weights::SubstrateWeight; type FreezeIdentifier = RuntimeFreezeReason; type MaxFreezes = VariantCountOf; + type DoneSlashHandler = (); } parameter_types! { @@ -572,25 +575,21 @@ impl pallet_transaction_payment::Config for Runtime { MinimumMultiplier, MaximumMultiplier, >; -} - -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, - >; + type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight; } 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, >; + type WeightInfo = pallet_asset_conversion_tx_payment::weights::SubstrateWeight; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = AssetConversionTxHelper; } impl pallet_skip_feeless_payment::Config for Runtime { @@ -859,7 +858,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; @@ -1120,6 +1119,9 @@ parameter_types! { pub const CouncilMotionDuration: BlockNumber = 5 * DAYS; pub const CouncilMaxProposals: u32 = 100; pub const CouncilMaxMembers: u32 = 100; + pub const ProposalDepositOffset: Balance = ExistentialDeposit::get() + ExistentialDeposit::get(); + pub const ProposalHoldReason: RuntimeHoldReason = + RuntimeHoldReason::Council(pallet_collective::HoldReason::ProposalSubmission); } type CouncilCollective = pallet_collective::Instance1; @@ -1134,6 +1136,18 @@ impl pallet_collective::Config for Runtime { type WeightInfo = pallet_collective::weights::SubstrateWeight; type SetMembersOrigin = EnsureRoot; type MaxProposalWeight = MaxCollectivesProposalWeight; + type DisapproveOrigin = EnsureRoot; + type KillOrigin = EnsureRoot; + type Consideration = HoldConsideration< + AccountId, + Balances, + ProposalHoldReason, + pallet_collective::deposit::Delayed< + ConstU32<2>, + pallet_collective::deposit::Linear, ProposalDepositOffset>, + >, + u32, + >; } parameter_types! { @@ -1195,6 +1209,9 @@ impl pallet_collective::Config for Runtime { type WeightInfo = pallet_collective::weights::SubstrateWeight; type SetMembersOrigin = EnsureRoot; type MaxProposalWeight = MaxCollectivesProposalWeight; + type DisapproveOrigin = EnsureRoot; + type KillOrigin = EnsureRoot; + type Consideration = (); } type EnsureRootOrHalfCouncil = EitherOfDiverse< @@ -1387,6 +1404,30 @@ impl pallet_contracts::Config for Runtime { type Xcm = (); } +impl pallet_revive::Config for Runtime { + type Time = Timestamp; + type Currency = Balances; + type RuntimeEvent = RuntimeEvent; + type RuntimeCall = RuntimeCall; + type CallFilter = Nothing; + type DepositPerItem = DepositPerItem; + type DepositPerByte = DepositPerByte; + type WeightPrice = pallet_transaction_payment::Pallet; + type WeightInfo = pallet_revive::weights::SubstrateWeight; + type ChainExtension = (); + type AddressMapper = pallet_revive::DefaultAddressMapper; + type RuntimeMemory = ConstU32<{ 128 * 1024 * 1024 }>; + type PVFMemory = ConstU32<{ 512 * 1024 * 1024 }>; + type UnsafeUnstableInterface = ConstBool; + type UploadOrigin = EnsureSigned; + type InstantiateOrigin = EnsureSigned; + type RuntimeHoldReason = RuntimeHoldReason; + type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent; + type Debug = (); + type Xcm = (); + type ChainId = ConstU64<420_420_420>; +} + impl pallet_sudo::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; @@ -1402,16 +1443,29 @@ parameter_types! { pub const MaxPeerInHeartbeats: u32 = 10_000; } +impl frame_system::offchain::CreateTransaction for Runtime +where + RuntimeCall: From, +{ + type Extension = TxExtension; + + fn create_transaction(call: RuntimeCall, extension: TxExtension) -> UncheckedExtrinsic { + generic::UncheckedExtrinsic::new_transaction(call, extension).into() + } +} + impl frame_system::offchain::CreateSignedTransaction for Runtime where RuntimeCall: From, { - fn create_transaction>( + fn create_signed_transaction< + C: frame_system::offchain::AppCrypto, + >( call: RuntimeCall, public: ::Signer, account: AccountId, nonce: Nonce, - ) -> Option<(RuntimeCall, ::SignaturePayload)> { + ) -> Option { let tip = 0; // take the biggest period possible. let period = @@ -1422,7 +1476,7 @@ where // so the actual block number is `n`. .saturating_sub(1); let era = Era::mortal(period, current_block); - let extra = ( + let tx_ext: TxExtension = ( frame_system::CheckNonZeroSender::::new(), frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), @@ -1437,15 +1491,27 @@ where ), frame_metadata_hash_extension::CheckMetadataHash::new(false), ); - let raw_payload = SignedPayload::new(call, extra) + + let raw_payload = SignedPayload::new(call, tx_ext) .map_err(|e| { log::warn!("Unable to create signed payload: {:?}", e); }) .ok()?; let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?; let address = Indices::unlookup(account); - let (call, extra, _) = raw_payload.deconstruct(); - Some((call, (address, signature, extra))) + let (call, tx_ext, _) = raw_payload.deconstruct(); + let transaction = + generic::UncheckedExtrinsic::new_signed(call, address, signature, tx_ext).into(); + Some(transaction) + } +} + +impl frame_system::offchain::CreateInherent for Runtime +where + RuntimeCall: From, +{ + fn create_inherent(call: RuntimeCall) -> UncheckedExtrinsic { + generic::UncheckedExtrinsic::new_bare(call).into() } } @@ -1454,12 +1520,12 @@ impl frame_system::offchain::SigningTypes for Runtime { type Signature = Signature; } -impl frame_system::offchain::SendTransactionTypes for Runtime +impl frame_system::offchain::CreateTransactionBase for Runtime where RuntimeCall: From, { type Extrinsic = UncheckedExtrinsic; - type OverarchingCall = RuntimeCall; + type RuntimeCall = RuntimeCall; } impl pallet_im_online::Config for Runtime { @@ -1494,7 +1560,7 @@ impl pallet_grandpa::Config for Runtime { type MaxAuthorities = MaxAuthorities; type MaxNominators = MaxNominators; type MaxSetIdSessionEntries = MaxSetIdSessionEntries; - type KeyOwnerProof = >::Proof; + type KeyOwnerProof = sp_session::MembershipProof; type EquivocationReportSystem = pallet_grandpa::EquivocationReportSystem; } @@ -1605,6 +1671,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 +1684,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 +1772,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< @@ -1948,6 +2020,30 @@ impl pallet_transaction_storage::Config for Runtime { ConstU32<{ pallet_transaction_storage::DEFAULT_MAX_TRANSACTION_SIZE }>; } +#[cfg(feature = "runtime-benchmarks")] +pub struct VerifySignatureBenchmarkHelper; +#[cfg(feature = "runtime-benchmarks")] +impl pallet_verify_signature::BenchmarkHelper + for VerifySignatureBenchmarkHelper +{ + fn create_signature(_entropy: &[u8], msg: &[u8]) -> (MultiSignature, AccountId) { + use sp_io::crypto::{sr25519_generate, sr25519_sign}; + use sp_runtime::traits::IdentifyAccount; + let public = sr25519_generate(0.into(), None); + let who_account: AccountId = MultiSigner::Sr25519(public).into_account().into(); + let signature = MultiSignature::Sr25519(sr25519_sign(0.into(), &public, msg).unwrap()); + (signature, who_account) + } +} + +impl pallet_verify_signature::Config for Runtime { + type Signature = MultiSignature; + type AccountIdentifier = MultiSigner; + type WeightInfo = pallet_verify_signature::weights::SubstrateWeight; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = VerifySignatureBenchmarkHelper; +} + impl pallet_whitelist::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; @@ -1999,6 +2095,9 @@ impl pallet_collective::Config for Runtime { type WeightInfo = pallet_collective::weights::SubstrateWeight; type SetMembersOrigin = EnsureRoot; type MaxProposalWeight = MaxCollectivesProposalWeight; + type DisapproveOrigin = EnsureRoot; + type KillOrigin = EnsureRoot; + type Consideration = (); } parameter_types! { @@ -2117,6 +2216,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 +2237,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 +2367,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; @@ -2474,8 +2581,24 @@ mod runtime { #[runtime::pallet_index(79)] pub type AssetConversionMigration = pallet_asset_conversion_ops::Pallet; + + #[runtime::pallet_index(80)] + pub type Revive = pallet_revive::Pallet; + + #[runtime::pallet_index(81)] + pub type VerifySignature = pallet_verify_signature::Pallet; } +impl TryFrom for pallet_revive::Call { + type Error = (); + + fn try_from(value: RuntimeCall) -> Result { + match value { + RuntimeCall::Revive(call) => Ok(call), + _ => Err(()), + } + } +} /// The address format for describing accounts. pub type Address = sp_runtime::MultiAddress; /// Block header type as expected by this runtime. @@ -2486,12 +2609,12 @@ pub type Block = generic::Block; pub type SignedBlock = generic::SignedBlock; /// BlockId type as expected by this runtime. pub type BlockId = generic::BlockId; -/// The SignedExtension to the basic transaction logic. +/// The TransactionExtension to the basic transaction logic. /// /// When you change this, you **MUST** modify [`sign`] in `bin/node/testing/src/keyring.rs`! /// /// [`sign`]: <../../testing/src/keyring.rs.html> -pub type SignedExtra = ( +pub type TxExtension = ( frame_system::CheckNonZeroSender, frame_system::CheckSpecVersion, frame_system::CheckTxVersion, @@ -2506,13 +2629,39 @@ pub type SignedExtra = ( frame_metadata_hash_extension::CheckMetadataHash, ); +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct EthExtraImpl; + +impl EthExtra for EthExtraImpl { + type Config = Runtime; + type Extension = TxExtension; + + fn get_eth_extension(nonce: u32, tip: Balance) -> Self::Extension { + ( + frame_system::CheckNonZeroSender::::new(), + frame_system::CheckSpecVersion::::new(), + frame_system::CheckTxVersion::::new(), + frame_system::CheckGenesis::::new(), + frame_system::CheckEra::from(crate::generic::Era::Immortal), + frame_system::CheckNonce::::from(nonce), + frame_system::CheckWeight::::new(), + pallet_asset_conversion_tx_payment::ChargeAssetTxPayment::::from(tip, None) + .into(), + frame_metadata_hash_extension::CheckMetadataHash::::new(false), + ) + } +} + /// Unchecked extrinsic type as expected by this runtime. pub type UncheckedExtrinsic = - generic::UncheckedExtrinsic; + pallet_revive::evm::runtime::UncheckedExtrinsic; +/// Unchecked signature payload type as expected by this runtime. +pub type UncheckedSignaturePayload = + generic::UncheckedSignaturePayload; /// The payload being signed in transactions. -pub type SignedPayload = generic::SignedPayload; +pub type SignedPayload = generic::SignedPayload; /// Extrinsic type that has already been checked. -pub type CheckedExtrinsic = generic::CheckedExtrinsic; +pub type CheckedExtrinsic = generic::CheckedExtrinsic; /// Executive: handles dispatch to the various modules. pub type Executive = frame_executive::Executive< Runtime, @@ -2553,7 +2702,7 @@ impl pallet_beefy::Config for Runtime { type OnNewValidatorSet = MmrLeaf; type AncestryHelper = MmrLeaf; type WeightInfo = (); - type KeyOwnerProof = >::Proof; + type KeyOwnerProof = sp_session::MembershipProof; type EquivocationReportSystem = pallet_beefy::EquivocationReportSystem; } @@ -2568,6 +2717,62 @@ mod mmr { pub type Hashing = ::Hashing; } +#[cfg(feature = "runtime-benchmarks")] +pub struct AssetConversionTxHelper; + +#[cfg(feature = "runtime-benchmarks")] +impl + pallet_asset_conversion_tx_payment::BenchmarkHelperTrait< + AccountId, + NativeOrWithId, + NativeOrWithId, + > for AssetConversionTxHelper +{ + fn create_asset_id_parameter(seed: u32) -> (NativeOrWithId, NativeOrWithId) { + (NativeOrWithId::WithId(seed), NativeOrWithId::WithId(seed)) + } + + fn setup_balances_and_pool(asset_id: NativeOrWithId, account: AccountId) { + use frame_support::{assert_ok, traits::fungibles::Mutate}; + let NativeOrWithId::WithId(asset_idx) = asset_id.clone() else { unimplemented!() }; + assert_ok!(Assets::force_create( + RuntimeOrigin::root(), + asset_idx.into(), + account.clone().into(), /* owner */ + true, /* is_sufficient */ + 1, + )); + + let lp_provider = account.clone(); + let _ = Balances::deposit_creating(&lp_provider, ((u64::MAX as u128) * 100).into()); + assert_ok!(Assets::mint_into( + asset_idx.into(), + &lp_provider, + ((u64::MAX as u128) * 100).into() + )); + + let token_native = alloc::boxed::Box::new(NativeOrWithId::Native); + let token_second = alloc::boxed::Box::new(asset_id); + + assert_ok!(AssetConversion::create_pool( + RuntimeOrigin::signed(lp_provider.clone()), + token_native.clone(), + token_second.clone() + )); + + assert_ok!(AssetConversion::add_liquidity( + RuntimeOrigin::signed(lp_provider.clone()), + token_native, + token_second, + u64::MAX.into(), // 1 desired + u64::MAX.into(), // 2 desired + 1, // 1 min + 1, // 2 min + lp_provider, + )); + } +} + #[cfg(feature = "runtime-benchmarks")] mod benches { polkadot_sdk::frame_benchmarking::define_benchmarks!( @@ -2578,16 +2783,20 @@ 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] [pallet_collective, Council] [pallet_conviction_voting, ConvictionVoting] [pallet_contracts, Contracts] + [pallet_revive, Revive] [pallet_core_fellowship, CoreFellowship] - [tasks_example, TasksExample] + [pallet_example_tasks, TasksExample] [pallet_democracy, Democracy] [pallet_asset_conversion, AssetConversion] + [pallet_asset_conversion_tx_payment, AssetConversionTxPayment] + [pallet_transaction_payment, TransactionPayment] [pallet_election_provider_multi_phase, ElectionProviderMultiPhase] [pallet_election_provider_support_benchmarking, EPSBench::] [pallet_elections_phragmen, Elections] @@ -2621,6 +2830,7 @@ mod benches { [pallet_state_trie_migration, StateTrieMigration] [pallet_sudo, Sudo] [frame_system, SystemBench::] + [frame_system_extensions, SystemExtensionsBench::] [pallet_timestamp, Timestamp] [pallet_tips, Tips] [pallet_transaction_storage, TransactionStorage] @@ -2636,6 +2846,7 @@ mod benches { [pallet_safe_mode, SafeMode] [pallet_example_mbm, PalletExampleMbms] [pallet_asset_conversion_ops, AssetConversionMigration] + [pallet_verify_signature, VerifySignature] ); } @@ -2775,6 +2986,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 { @@ -2938,6 +3157,107 @@ impl_runtime_apis! { } } + impl pallet_revive::ReviveApi for Runtime + { + fn eth_transact( + from: H160, + dest: Option, + value: Balance, + input: Vec, + gas_limit: Option, + storage_deposit_limit: Option, + ) -> pallet_revive::EthContractResult + { + use pallet_revive::AddressMapper; + let blockweights: BlockWeights = ::BlockWeights::get(); + let origin = ::AddressMapper::to_account_id(&from); + + let encoded_size = |pallet_call| { + let call = RuntimeCall::Revive(pallet_call); + let uxt: UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic::new_bare(call).into(); + uxt.encoded_size() as u32 + }; + + Revive::bare_eth_transact( + origin, + dest, + value, + input, + gas_limit.unwrap_or(blockweights.max_block), + storage_deposit_limit.unwrap_or(u128::MAX), + encoded_size, + pallet_revive::DebugInfo::UnsafeDebug, + pallet_revive::CollectEvents::UnsafeCollect, + ) + } + + fn call( + origin: AccountId, + dest: H160, + value: Balance, + gas_limit: Option, + storage_deposit_limit: Option, + input_data: Vec, + ) -> pallet_revive::ContractResult { + Revive::bare_call( + RuntimeOrigin::signed(origin), + dest, + value, + gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block), + storage_deposit_limit.unwrap_or(u128::MAX), + input_data, + pallet_revive::DebugInfo::UnsafeDebug, + pallet_revive::CollectEvents::UnsafeCollect, + ) + } + + fn instantiate( + origin: AccountId, + value: Balance, + gas_limit: Option, + storage_deposit_limit: Option, + code: pallet_revive::Code, + data: Vec, + salt: Option<[u8; 32]>, + ) -> pallet_revive::ContractResult + { + Revive::bare_instantiate( + RuntimeOrigin::signed(origin), + value, + gas_limit.unwrap_or(RuntimeBlockWeights::get().max_block), + storage_deposit_limit.unwrap_or(u128::MAX), + code, + data, + salt, + pallet_revive::DebugInfo::UnsafeDebug, + pallet_revive::CollectEvents::UnsafeCollect, + ) + } + + fn upload_code( + origin: AccountId, + code: Vec, + storage_deposit_limit: Option, + ) -> pallet_revive::CodeUploadResult + { + Revive::bare_upload_code( + RuntimeOrigin::signed(origin), + code, + storage_deposit_limit.unwrap_or(u128::MAX), + ) + } + + fn get_storage( + address: H160, + key: [u8; 32], + ) -> pallet_revive::GetStorageResult { + Revive::get_storage( + address, + key + ) + } + } + impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi< Block, Balance, @@ -3036,7 +3356,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 +3382,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 +3415,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< @@ -3190,6 +3546,7 @@ impl_runtime_apis! { use pallet_offences_benchmarking::Pallet as OffencesBench; use pallet_election_provider_support_benchmarking::Pallet as EPSBench; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use baseline::Pallet as BaselineBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; @@ -3214,6 +3571,7 @@ impl_runtime_apis! { use pallet_offences_benchmarking::Pallet as OffencesBench; use pallet_election_provider_support_benchmarking::Pallet as EPSBench; use frame_system_benchmarking::Pallet as SystemBench; + use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench; use baseline::Pallet as BaselineBench; use pallet_nomination_pools_benchmarking::Pallet as NominationPoolsBench; diff --git a/substrate/bin/node/testing/Cargo.toml b/substrate/bin/node/testing/Cargo.toml index 90c9ee0555cf..16112386ad7c 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 @@ -28,6 +28,7 @@ node-primitives = { workspace = true, default-features = true } kitchensink-runtime = { workspace = true } pallet-asset-conversion = { workspace = true, default-features = true } pallet-assets = { workspace = true, default-features = true } +pallet-revive = { workspace = true, default-features = true } pallet-asset-conversion-tx-payment = { workspace = true, default-features = true } pallet-asset-tx-payment = { workspace = true, default-features = true } pallet-skip-feeless-payment = { workspace = true, default-features = true } diff --git a/substrate/bin/node/testing/src/bench.rs b/substrate/bin/node/testing/src/bench.rs index 007d314684cf..3812524f0b1f 100644 --- a/substrate/bin/node/testing/src/bench.rs +++ b/substrate/bin/node/testing/src/bench.rs @@ -47,10 +47,13 @@ use sc_executor::{WasmExecutionMethod, WasmtimeInstantiationStrategy}; use sp_api::ProvideRuntimeApi; use sp_block_builder::BlockBuilder; use sp_consensus::BlockOrigin; -use sp_core::{ed25519, sr25519, traits::SpawnNamed, Pair, Public}; +use sp_core::{ + crypto::get_public_from_string_or_panic, ed25519, sr25519, traits::SpawnNamed, Pair, +}; use sp_crypto_hashing::blake2_256; use sp_inherents::InherentData; use sp_runtime::{ + generic::{self, ExtrinsicFormat, Preamble, EXTRINSIC_FORMAT_VERSION}, traits::{Block as BlockT, IdentifyAccount, Verify}, OpaqueExtrinsic, }; @@ -288,17 +291,18 @@ impl<'a> Iterator for BlockContentIterator<'a> { } let sender = self.keyring.at(self.iteration); - let receiver = get_account_id_from_seed::(&format!( + let receiver = get_public_from_string_or_panic::(&format!( "random-user//{}", self.iteration - )); + )) + .into(); let signed = self.keyring.sign( CheckedExtrinsic { - signed: Some(( + format: ExtrinsicFormat::Signed( sender, - signed_extra(0, kitchensink_runtime::ExistentialDeposit::get() + 1), - )), + tx_ext(0, kitchensink_runtime::ExistentialDeposit::get() + 1), + ), function: match self.content.block_type { BlockType::RandomTransfersKeepAlive => RuntimeCall::Balances(BalancesCall::transfer_keep_alive { @@ -562,11 +566,11 @@ impl BenchKeyring { tx_version: u32, genesis_hash: [u8; 32], ) -> UncheckedExtrinsic { - match xt.signed { - Some((signed, extra)) => { + match xt.format { + ExtrinsicFormat::Signed(signed, tx_ext) => { let payload = ( xt.function, - extra.clone(), + tx_ext.clone(), spec_version, tx_version, genesis_hash, @@ -582,12 +586,27 @@ impl BenchKeyring { key.sign(b) } }); - UncheckedExtrinsic { - signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)), + generic::UncheckedExtrinsic { + preamble: Preamble::Signed( + sp_runtime::MultiAddress::Id(signed), + signature, + 0, + tx_ext, + ), function: payload.0, } + .into() }, - None => UncheckedExtrinsic { signature: None, function: xt.function }, + ExtrinsicFormat::Bare => generic::UncheckedExtrinsic { + preamble: Preamble::Bare(EXTRINSIC_FORMAT_VERSION), + function: xt.function, + } + .into(), + ExtrinsicFormat::General(tx_ext) => generic::UncheckedExtrinsic { + preamble: sp_runtime::generic::Preamble::General(0, tx_ext), + function: xt.function, + } + .into(), } } @@ -630,19 +649,6 @@ pub struct BenchContext { type AccountPublic = ::Signer; -fn get_from_seed(seed: &str) -> ::Public { - TPublic::Pair::from_string(&format!("//{}", seed), None) - .expect("static values are valid; qed") - .public() -} - -fn get_account_id_from_seed(seed: &str) -> AccountId -where - AccountPublic: From<::Public>, -{ - AccountPublic::from(get_from_seed::(seed)).into_account() -} - impl BenchContext { /// Import some block. pub fn import_block(&mut self, block: Block) { diff --git a/substrate/bin/node/testing/src/genesis.rs b/substrate/bin/node/testing/src/genesis.rs index c79612d68444..7f5364744c66 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/node/testing/src/keyring.rs b/substrate/bin/node/testing/src/keyring.rs index eab088d9100e..20497e85eab9 100644 --- a/substrate/bin/node/testing/src/keyring.rs +++ b/substrate/bin/node/testing/src/keyring.rs @@ -19,58 +19,61 @@ //! Test accounts. use codec::Encode; -use kitchensink_runtime::{CheckedExtrinsic, SessionKeys, SignedExtra, UncheckedExtrinsic}; -use node_cli::chain_spec::get_from_seed; +use kitchensink_runtime::{CheckedExtrinsic, SessionKeys, TxExtension, UncheckedExtrinsic}; use node_primitives::{AccountId, Balance, Nonce}; -use sp_core::{ecdsa, ed25519, sr25519}; +use sp_core::{crypto::get_public_from_string_or_panic, ecdsa, ed25519, sr25519}; use sp_crypto_hashing::blake2_256; -use sp_keyring::AccountKeyring; -use sp_runtime::generic::Era; +use sp_keyring::Sr25519Keyring; +use sp_runtime::generic::{self, Era, ExtrinsicFormat, EXTRINSIC_FORMAT_VERSION}; /// Alice's account id. pub fn alice() -> AccountId { - AccountKeyring::Alice.into() + Sr25519Keyring::Alice.into() } /// Bob's account id. pub fn bob() -> AccountId { - AccountKeyring::Bob.into() + Sr25519Keyring::Bob.into() } /// Charlie's account id. pub fn charlie() -> AccountId { - AccountKeyring::Charlie.into() + Sr25519Keyring::Charlie.into() } /// Dave's account id. pub fn dave() -> AccountId { - AccountKeyring::Dave.into() + Sr25519Keyring::Dave.into() } /// Eve's account id. pub fn eve() -> AccountId { - AccountKeyring::Eve.into() + Sr25519Keyring::Eve.into() } /// Ferdie's account id. pub fn ferdie() -> AccountId { - AccountKeyring::Ferdie.into() + Sr25519Keyring::Ferdie.into() } /// Convert keyrings into `SessionKeys`. +/// +/// # Panics +/// +/// Function will panic when invalid string is provided. pub fn session_keys_from_seed(seed: &str) -> SessionKeys { SessionKeys { - grandpa: get_from_seed::(seed).into(), - babe: get_from_seed::(seed).into(), - im_online: get_from_seed::(seed).into(), - authority_discovery: get_from_seed::(seed).into(), - mixnet: get_from_seed::(seed).into(), - beefy: get_from_seed::(seed).into(), + grandpa: get_public_from_string_or_panic::(seed).into(), + babe: get_public_from_string_or_panic::(seed).into(), + im_online: get_public_from_string_or_panic::(seed).into(), + authority_discovery: get_public_from_string_or_panic::(seed).into(), + mixnet: get_public_from_string_or_panic::(seed).into(), + beefy: get_public_from_string_or_panic::(seed).into(), } } /// Returns transaction extra. -pub fn signed_extra(nonce: Nonce, extra_fee: Balance) -> SignedExtra { +pub fn tx_ext(nonce: Nonce, extra_fee: Balance) -> TxExtension { ( frame_system::CheckNonZeroSender::new(), frame_system::CheckSpecVersion::new(), @@ -94,18 +97,18 @@ pub fn sign( genesis_hash: [u8; 32], metadata_hash: Option<[u8; 32]>, ) -> UncheckedExtrinsic { - match xt.signed { - Some((signed, extra)) => { + match xt.format { + ExtrinsicFormat::Signed(signed, tx_ext) => { let payload = ( xt.function, - extra.clone(), + tx_ext.clone(), spec_version, tx_version, genesis_hash, genesis_hash, metadata_hash, ); - let key = AccountKeyring::from_account_id(&signed).unwrap(); + let key = Sr25519Keyring::from_account_id(&signed).unwrap(); let signature = payload .using_encoded(|b| { @@ -116,11 +119,26 @@ pub fn sign( } }) .into(); - UncheckedExtrinsic { - signature: Some((sp_runtime::MultiAddress::Id(signed), signature, extra)), + generic::UncheckedExtrinsic { + preamble: sp_runtime::generic::Preamble::Signed( + sp_runtime::MultiAddress::Id(signed), + signature, + 0, + tx_ext, + ), function: payload.0, } + .into() }, - None => UncheckedExtrinsic { signature: None, function: xt.function }, + ExtrinsicFormat::Bare => generic::UncheckedExtrinsic { + preamble: sp_runtime::generic::Preamble::Bare(EXTRINSIC_FORMAT_VERSION), + function: xt.function, + } + .into(), + ExtrinsicFormat::General(tx_ext) => generic::UncheckedExtrinsic { + preamble: sp_runtime::generic::Preamble::General(0, tx_ext), + function: xt.function, + } + .into(), } } diff --git a/substrate/bin/utils/chain-spec-builder/Cargo.toml b/substrate/bin/utils/chain-spec-builder/Cargo.toml index 083f2191f3c5..f2fe8cb7e166 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`" @@ -28,4 +28,8 @@ clap = { features = ["derive"], workspace = true } log = { workspace = true, default-features = true } sc-chain-spec = { features = ["clap"], workspace = true, default-features = true } serde_json = { workspace = true, default-features = true } +serde = { workspace = true, default-features = true } sp-tracing = { workspace = true, default-features = true } + +[dev-dependencies] +substrate-test-runtime = { workspace = true } diff --git a/substrate/bin/utils/chain-spec-builder/bin/main.rs b/substrate/bin/utils/chain-spec-builder/bin/main.rs index 39fa054b4806..9898a582dd14 100644 --- a/substrate/bin/utils/chain-spec-builder/bin/main.rs +++ b/substrate/bin/utils/chain-spec-builder/bin/main.rs @@ -16,19 +16,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use chain_spec_builder::{ - generate_chain_spec_for_runtime, AddCodeSubstituteCmd, ChainSpecBuilder, ChainSpecBuilderCmd, - ConvertToRawCmd, DisplayPresetCmd, ListPresetsCmd, UpdateCodeCmd, VerifyCmd, -}; +use chain_spec_builder::ChainSpecBuilder; use clap::Parser; -use sc_chain_spec::{ - set_code_substitute_in_json_chain_spec, update_code_in_json_chain_spec, GenericChainSpec, - GenesisConfigBuilderRuntimeCaller, -}; use staging_chain_spec_builder as chain_spec_builder; -use std::fs; - -type ChainSpec = GenericChainSpec<(), ()>; //avoid error message escaping fn main() { @@ -42,99 +32,5 @@ fn inner_main() -> Result<(), String> { sp_tracing::try_init_simple(); let builder = ChainSpecBuilder::parse(); - let chain_spec_path = builder.chain_spec_path.to_path_buf(); - - match builder.command { - ChainSpecBuilderCmd::Create(cmd) => { - let chain_spec_json = generate_chain_spec_for_runtime(&cmd)?; - fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string())?; - }, - ChainSpecBuilderCmd::UpdateCode(UpdateCodeCmd { - ref input_chain_spec, - ref runtime_wasm_path, - }) => { - let chain_spec = ChainSpec::from_json_file(input_chain_spec.clone())?; - - let mut chain_spec_json = - serde_json::from_str::(&chain_spec.as_json(false)?) - .map_err(|e| format!("Conversion to json failed: {e}"))?; - update_code_in_json_chain_spec( - &mut chain_spec_json, - &fs::read(runtime_wasm_path.as_path()) - .map_err(|e| format!("Wasm blob file could not be read: {e}"))?[..], - ); - - let chain_spec_json = serde_json::to_string_pretty(&chain_spec_json) - .map_err(|e| format!("to pretty failed: {e}"))?; - fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string())?; - }, - ChainSpecBuilderCmd::AddCodeSubstitute(AddCodeSubstituteCmd { - ref input_chain_spec, - ref runtime_wasm_path, - block_height, - }) => { - let chain_spec = ChainSpec::from_json_file(input_chain_spec.clone())?; - - let mut chain_spec_json = - serde_json::from_str::(&chain_spec.as_json(false)?) - .map_err(|e| format!("Conversion to json failed: {e}"))?; - - set_code_substitute_in_json_chain_spec( - &mut chain_spec_json, - &fs::read(runtime_wasm_path.as_path()) - .map_err(|e| format!("Wasm blob file could not be read: {e}"))?[..], - block_height, - ); - let chain_spec_json = serde_json::to_string_pretty(&chain_spec_json) - .map_err(|e| format!("to pretty failed: {e}"))?; - fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string())?; - }, - ChainSpecBuilderCmd::ConvertToRaw(ConvertToRawCmd { ref input_chain_spec }) => { - let chain_spec = ChainSpec::from_json_file(input_chain_spec.clone())?; - - let chain_spec_json = - serde_json::from_str::(&chain_spec.as_json(true)?) - .map_err(|e| format!("Conversion to json failed: {e}"))?; - - let chain_spec_json = serde_json::to_string_pretty(&chain_spec_json) - .map_err(|e| format!("Conversion to pretty failed: {e}"))?; - fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string())?; - }, - ChainSpecBuilderCmd::Verify(VerifyCmd { ref input_chain_spec }) => { - let chain_spec = ChainSpec::from_json_file(input_chain_spec.clone())?; - let _ = serde_json::from_str::(&chain_spec.as_json(true)?) - .map_err(|e| format!("Conversion to json failed: {e}"))?; - }, - ChainSpecBuilderCmd::ListPresets(ListPresetsCmd { runtime_wasm_path }) => { - let code = fs::read(runtime_wasm_path.as_path()) - .map_err(|e| format!("wasm blob shall be readable {e}"))?; - let caller: GenesisConfigBuilderRuntimeCaller = - GenesisConfigBuilderRuntimeCaller::new(&code[..]); - let presets = caller - .preset_names() - .map_err(|e| format!("getting default config from runtime should work: {e}"))?; - let presets: Vec = presets - .into_iter() - .map(|preset| { - String::from( - TryInto::<&str>::try_into(&preset) - .unwrap_or_else(|_| "cannot display preset id") - .to_string(), - ) - }) - .collect(); - println!("{}", serde_json::json!({"presets":presets}).to_string()); - }, - ChainSpecBuilderCmd::DisplayPreset(DisplayPresetCmd { runtime_wasm_path, preset_name }) => { - let code = fs::read(runtime_wasm_path.as_path()) - .map_err(|e| format!("wasm blob shall be readable {e}"))?; - let caller: GenesisConfigBuilderRuntimeCaller = - GenesisConfigBuilderRuntimeCaller::new(&code[..]); - let preset = caller - .get_named_preset(preset_name.as_ref()) - .map_err(|e| format!("getting default config from runtime should work: {e}"))?; - println!("{preset}"); - }, - }; - Ok(()) + builder.run() } diff --git a/substrate/bin/utils/chain-spec-builder/src/lib.rs b/substrate/bin/utils/chain-spec-builder/src/lib.rs index 6c679f109a00..629edcf68568 100644 --- a/substrate/bin/utils/chain-spec-builder/src/lib.rs +++ b/substrate/bin/utils/chain-spec-builder/src/lib.rs @@ -117,11 +117,18 @@ //! [sp-genesis-builder-list]: ../sp_genesis_builder/trait.GenesisBuilder.html#method.preset_names //! [sp-genesis-builder-get-preset]: ../sp_genesis_builder/trait.GenesisBuilder.html#method.get_preset -use std::{fs, path::PathBuf}; - use clap::{Parser, Subcommand}; -use sc_chain_spec::{ChainType, GenericChainSpec, GenesisConfigBuilderRuntimeCaller}; +use sc_chain_spec::{ + json_patch, set_code_substitute_in_json_chain_spec, update_code_in_json_chain_spec, ChainType, + GenericChainSpec, GenesisConfigBuilderRuntimeCaller, +}; +use serde::{Deserialize, Serialize}; use serde_json::Value; +use std::{ + borrow::Cow, + fs, + path::{Path, PathBuf}, +}; /// A utility to easily create a chain spec definition. #[derive(Debug, Parser)] @@ -158,9 +165,15 @@ pub struct CreateCmd { /// The chain type. #[arg(value_enum, short = 't', default_value = "live")] chain_type: ChainType, + /// The para ID for your chain. + #[arg(long, value_enum, short = 'p', requires = "relay_chain")] + pub para_id: Option, + /// The relay chain you wish to connect to. + #[arg(long, value_enum, short = 'c', requires = "para_id")] + pub relay_chain: Option, /// The path to runtime wasm blob. - #[arg(long, short)] - runtime_wasm_path: PathBuf, + #[arg(long, short, alias = "runtime-wasm-path")] + runtime: PathBuf, /// Export chainspec as raw storage. #[arg(long, short = 's')] raw_storage: bool, @@ -170,6 +183,10 @@ pub struct CreateCmd { verify: bool, #[command(subcommand)] action: GenesisBuildAction, + + /// Allows to provide the runtime code blob, instead of reading it from the provided file path. + #[clap(skip)] + code: Option>, } #[derive(Subcommand, Debug, Clone)] @@ -220,7 +237,8 @@ pub struct UpdateCodeCmd { /// Please note that the file will not be updated in-place. pub input_chain_spec: PathBuf, /// The path to new runtime wasm blob to be stored into chain-spec. - pub runtime_wasm_path: PathBuf, + #[arg(alias = "runtime-wasm-path")] + pub runtime: PathBuf, } /// Add a code substitute in the chain spec. @@ -237,7 +255,8 @@ pub struct AddCodeSubstituteCmd { /// Chain spec to be updated. pub input_chain_spec: PathBuf, /// New runtime wasm blob that should replace the existing code. - pub runtime_wasm_path: PathBuf, + #[arg(alias = "runtime-wasm-path")] + pub runtime: PathBuf, /// The block height at which the code should be substituted. pub block_height: u64, } @@ -253,16 +272,16 @@ pub struct ConvertToRawCmd { #[derive(Parser, Debug, Clone)] pub struct ListPresetsCmd { /// The path to runtime wasm blob. - #[arg(long, short)] - pub runtime_wasm_path: PathBuf, + #[arg(long, short, alias = "runtime-wasm-path")] + pub runtime: PathBuf, } /// Displays given preset #[derive(Parser, Debug, Clone)] pub struct DisplayPresetCmd { /// The path to runtime wasm blob. - #[arg(long, short)] - pub runtime_wasm_path: PathBuf, + #[arg(long, short, alias = "runtime-wasm-path")] + pub runtime: PathBuf, /// Preset to be displayed. If none is given default will be displayed. #[arg(long, short)] pub preset_name: Option, @@ -279,18 +298,146 @@ pub struct VerifyCmd { pub input_chain_spec: PathBuf, } -/// Processes `CreateCmd` and returns JSON version of `ChainSpec`. -pub fn generate_chain_spec_for_runtime(cmd: &CreateCmd) -> Result { - let code = fs::read(cmd.runtime_wasm_path.as_path()) - .map_err(|e| format!("wasm blob shall be readable {e}"))?; +#[derive(Deserialize, Serialize, Clone)] +pub struct ParachainExtension { + /// The relay chain of the Parachain. + pub relay_chain: String, + /// The id of the Parachain. + pub para_id: u32, +} - let chain_type = &cmd.chain_type; +type ChainSpec = GenericChainSpec<()>; - let builder = GenericChainSpec::<()>::builder(&code[..], Default::default()) - .with_name(&cmd.chain_name[..]) - .with_id(&cmd.chain_id[..]) - .with_chain_type(chain_type.clone()); +impl ChainSpecBuilder { + /// Executes the internal command. + pub fn run(self) -> Result<(), String> { + let chain_spec_path = self.chain_spec_path.to_path_buf(); + + match self.command { + ChainSpecBuilderCmd::Create(cmd) => { + let chain_spec_json = generate_chain_spec_for_runtime(&cmd)?; + fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string())?; + }, + ChainSpecBuilderCmd::UpdateCode(UpdateCodeCmd { + ref input_chain_spec, + ref runtime, + }) => { + let mut chain_spec_json = extract_chain_spec_json(input_chain_spec.as_path())?; + + update_code_in_json_chain_spec( + &mut chain_spec_json, + &fs::read(runtime.as_path()) + .map_err(|e| format!("Wasm blob file could not be read: {e}"))?[..], + ); + + let chain_spec_json = serde_json::to_string_pretty(&chain_spec_json) + .map_err(|e| format!("to pretty failed: {e}"))?; + fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string())?; + }, + ChainSpecBuilderCmd::AddCodeSubstitute(AddCodeSubstituteCmd { + ref input_chain_spec, + ref runtime, + block_height, + }) => { + let mut chain_spec_json = extract_chain_spec_json(input_chain_spec.as_path())?; + + set_code_substitute_in_json_chain_spec( + &mut chain_spec_json, + &fs::read(runtime.as_path()) + .map_err(|e| format!("Wasm blob file could not be read: {e}"))?[..], + block_height, + ); + let chain_spec_json = serde_json::to_string_pretty(&chain_spec_json) + .map_err(|e| format!("to pretty failed: {e}"))?; + fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string())?; + }, + ChainSpecBuilderCmd::ConvertToRaw(ConvertToRawCmd { ref input_chain_spec }) => { + let chain_spec = ChainSpec::from_json_file(input_chain_spec.clone())?; + + let mut genesis_json = + serde_json::from_str::(&chain_spec.as_json(true)?) + .map_err(|e| format!("Conversion to json failed: {e}"))?; + + // We want to extract only raw genesis ("genesis::raw" key), and apply it as a patch + // for the original json file. However, the file also contains original plain + // genesis ("genesis::runtimeGenesis") so set it to null so the patch will erase it. + genesis_json.as_object_mut().map(|map| { + map.retain(|key, _| key == "genesis"); + map.get_mut("genesis").map(|genesis| { + genesis.as_object_mut().map(|genesis_map| { + genesis_map + .insert("runtimeGenesis".to_string(), serde_json::Value::Null); + }); + }); + }); + + let mut org_chain_spec_json = extract_chain_spec_json(input_chain_spec.as_path())?; + json_patch::merge(&mut org_chain_spec_json, genesis_json); + + let chain_spec_json = serde_json::to_string_pretty(&org_chain_spec_json) + .map_err(|e| format!("Conversion to pretty failed: {e}"))?; + fs::write(chain_spec_path, chain_spec_json).map_err(|err| err.to_string())?; + }, + ChainSpecBuilderCmd::Verify(VerifyCmd { ref input_chain_spec }) => { + let chain_spec = ChainSpec::from_json_file(input_chain_spec.clone())?; + let _ = serde_json::from_str::(&chain_spec.as_json(true)?) + .map_err(|e| format!("Conversion to json failed: {e}"))?; + }, + ChainSpecBuilderCmd::ListPresets(ListPresetsCmd { runtime }) => { + let code = fs::read(runtime.as_path()) + .map_err(|e| format!("wasm blob shall be readable {e}"))?; + let caller: GenesisConfigBuilderRuntimeCaller = + GenesisConfigBuilderRuntimeCaller::new(&code[..]); + let presets = caller + .preset_names() + .map_err(|e| format!("getting default config from runtime should work: {e}"))?; + let presets: Vec = presets + .into_iter() + .map(|preset| { + String::from( + TryInto::<&str>::try_into(&preset) + .unwrap_or_else(|_| "cannot display preset id") + .to_string(), + ) + }) + .collect(); + println!("{}", serde_json::json!({"presets":presets}).to_string()); + }, + ChainSpecBuilderCmd::DisplayPreset(DisplayPresetCmd { runtime, preset_name }) => { + let code = fs::read(runtime.as_path()) + .map_err(|e| format!("wasm blob shall be readable {e}"))?; + let caller: GenesisConfigBuilderRuntimeCaller = + GenesisConfigBuilderRuntimeCaller::new(&code[..]); + let preset = caller + .get_named_preset(preset_name.as_ref()) + .map_err(|e| format!("getting default config from runtime should work: {e}"))?; + println!("{preset}"); + }, + } + Ok(()) + } + + /// Sets the code used by [`CreateCmd`] + /// + /// The file pointed by `CreateCmd::runtime` field will not be read. Provided blob will used + /// instead for chain spec generation. + pub fn set_create_cmd_runtime_code(&mut self, code: Cow<'static, [u8]>) { + match &mut self.command { + ChainSpecBuilderCmd::Create(cmd) => { + cmd.code = Some(code); + }, + _ => { + panic!("Overwriting code blob is only supported for CreateCmd"); + }, + }; + } +} +fn process_action( + cmd: &CreateCmd, + code: &[u8], + builder: sc_chain_spec::ChainSpecBuilder, +) -> Result { let builder = match cmd.action { GenesisBuildAction::NamedPreset(NamedPresetCmd { ref preset_name }) => builder.with_genesis_config_preset_name(&preset_name), @@ -310,7 +457,7 @@ pub fn generate_chain_spec_for_runtime(cmd: &CreateCmd) -> Result { let caller: GenesisConfigBuilderRuntimeCaller = - GenesisConfigBuilderRuntimeCaller::new(&code[..]); + GenesisConfigBuilderRuntimeCaller::new(&code); let default_config = caller .get_default_config() .map_err(|e| format!("getting default config from runtime should work: {e}"))?; @@ -330,3 +477,59 @@ pub fn generate_chain_spec_for_runtime(cmd: &CreateCmd) -> Result chain_spec.as_json(false), } } + +impl CreateCmd { + /// Returns the associated runtime code. + /// + /// If the code blob was previously set, returns it. Otherwise reads the file. + fn get_runtime_code(&self) -> Result, String> { + Ok(if let Some(code) = self.code.clone() { + code + } else { + fs::read(self.runtime.as_path()) + .map_err(|e| format!("wasm blob shall be readable {e}"))? + .into() + }) + } +} + +/// Processes `CreateCmd` and returns string represenataion of JSON version of `ChainSpec`. +pub fn generate_chain_spec_for_runtime(cmd: &CreateCmd) -> Result { + let code = cmd.get_runtime_code()?; + + let chain_type = &cmd.chain_type; + + let mut properties = sc_chain_spec::Properties::new(); + properties.insert("tokenSymbol".into(), "UNIT".into()); + properties.insert("tokenDecimals".into(), 12.into()); + + let builder = ChainSpec::builder(&code[..], Default::default()) + .with_name(&cmd.chain_name[..]) + .with_id(&cmd.chain_id[..]) + .with_properties(properties) + .with_chain_type(chain_type.clone()); + + let chain_spec_json_string = process_action(&cmd, &code[..], builder)?; + + if let (Some(para_id), Some(ref relay_chain)) = (cmd.para_id, &cmd.relay_chain) { + let parachain_properties = serde_json::json!({ + "relay_chain": relay_chain, + "para_id": para_id, + }); + let mut chain_spec_json_blob = serde_json::from_str(chain_spec_json_string.as_str()) + .map_err(|e| format!("deserialization a json failed {e}"))?; + json_patch::merge(&mut chain_spec_json_blob, parachain_properties); + Ok(serde_json::to_string_pretty(&chain_spec_json_blob) + .map_err(|e| format!("to pretty failed: {e}"))?) + } else { + Ok(chain_spec_json_string) + } +} + +/// Extract any chain spec and convert it to JSON +fn extract_chain_spec_json(input_chain_spec: &Path) -> Result { + let chain_spec = &fs::read(input_chain_spec) + .map_err(|e| format!("Provided chain spec could not be read: {e}"))?; + + serde_json::from_slice(&chain_spec).map_err(|e| format!("Conversion to json failed: {e}")) +} diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/add_code_substitute.json b/substrate/bin/utils/chain-spec-builder/tests/expected/add_code_substitute.json new file mode 100644 index 000000000000..b957b09f5646 --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/add_code_substitute.json @@ -0,0 +1,42 @@ +{ + "bootNodes": [], + "chainType": "Live", + "codeSubstitutes": { + "100": "0x040506" + }, + "custom_field": "custom_value", + "genesis": { + "runtimeGenesis": { + "code": "0x010203", + "config": { + "babe": { + "authorities": [], + "epochConfig": { + "allowed_slots": "PrimaryAndSecondaryVRFSlots", + "c": [ + 1, + 4 + ] + } + }, + "balances": { + "balances": [] + }, + "substrateTest": { + "authorities": [] + }, + "system": {} + } + } + }, + "id": "custom", + "name": "Custom", + "para_id": 10101, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "protocolId": null, + "relay_chain": "rococo-local", + "telemetryEndpoints": null +} \ No newline at end of file diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/convert_to_raw.json b/substrate/bin/utils/chain-spec-builder/tests/expected/convert_to_raw.json new file mode 100644 index 000000000000..5b1b4e2f04cf --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/convert_to_raw.json @@ -0,0 +1,38 @@ +{ + "name": "Custom", + "id": "custom", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "relay_chain": "rococo-local", + "para_id": 10101, + "custom_field": "custom_value", + "codeSubstitutes": {}, + "genesis": { + "raw": { + "childrenDefault": {}, + "top": { + "0x00771836bebdd29870ff246d305c578c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x00771836bebdd29870ff246d305c578c5e0621c4869aa60c02be9adcc98a0d1d": "0x00", + "0x1cb6f36e027abb2091cfb5110ab5087f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x1cb6f36e027abb2091cfb5110ab5087f66e8f035c8adbe7f1547b43c51e6f8a4": "0x00000000", + "0x1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef": "0x0100000000000000040000000000000002", + "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746bb1bdbcacd6ac9340000000000000000": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x0000", + "0x3a636f6465": "0x010203", + "0x3a65787472696e7369635f696e646578": "0x00000000", + "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x0000000000000000" + } + } + } +} diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/create_default.json b/substrate/bin/utils/chain-spec-builder/tests/expected/create_default.json new file mode 100644 index 000000000000..ac67aef93345 --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/create_default.json @@ -0,0 +1,37 @@ +{ + "name": "Custom", + "id": "custom", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "code": "0x010203", + "config": { + "babe": { + "authorities": [], + "epochConfig": { + "allowed_slots": "PrimaryAndSecondaryVRFSlots", + "c": [ + 1, + 4 + ] + } + }, + "balances": { + "balances": [] + }, + "substrateTest": { + "authorities": [] + }, + "system": {} + } + } + } +} diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/create_parachain.json b/substrate/bin/utils/chain-spec-builder/tests/expected/create_parachain.json new file mode 100644 index 000000000000..7106b4b50dc5 --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/create_parachain.json @@ -0,0 +1,39 @@ +{ + "name": "test_chain", + "id": "100", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "relay_chain": "rococo-local", + "para_id": 10101, + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "code": "0x010203", + "config": { + "babe": { + "authorities": [], + "epochConfig": { + "allowed_slots": "PrimaryAndSecondaryVRFSlots", + "c": [ + 1, + 4 + ] + } + }, + "balances": { + "balances": [] + }, + "substrateTest": { + "authorities": [] + }, + "system": {} + } + } + } +} diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/create_raw_storage.json b/substrate/bin/utils/chain-spec-builder/tests/expected/create_raw_storage.json new file mode 100644 index 000000000000..0501d6cbe45b --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/create_raw_storage.json @@ -0,0 +1,38 @@ +{ + "name": "Custom", + "id": "custom", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "codeSubstitutes": {}, + "genesis": { + "raw": { + "top": { + "0x00771836bebdd29870ff246d305c578c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x00771836bebdd29870ff246d305c578c5e0621c4869aa60c02be9adcc98a0d1d": "0x0cd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c186e1bafbb1430668c95d89b77217a402a74f64c3e103137b69e95e4b6e06b1e", + "0x1cb6f36e027abb2091cfb5110ab5087f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x1cb6f36e027abb2091cfb5110ab5087f66e8f035c8adbe7f1547b43c51e6f8a4": "0x00000000", + "0x1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef": "0x0100000000000000040000000000000002", + "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746bb1bdbcacd6ac9340000000000000000": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da92c2a60ec6dd16cd8ab911865ecf7555b186e1bafbb1430668c95d89b77217a402a74f64c3e103137b69e95e4b6e06b1e": "0x00000000000000000000000001000000000000000080e03779c311000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48": "0x00000000000000000000000001000000000000000080c6a47e8d03000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9b0edae20838083f2cde1c4080db8cf8090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22": "0x00000000000000000000000001000000000000000080c6a47e8d03000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x0000", + "0x3a636f6465": "0x010203", + "0x3a65787472696e7369635f696e646578": "0x00000000", + "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x00806d8176de1800" + }, + "childrenDefault": {} + } + } +} diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/create_with_full.json b/substrate/bin/utils/chain-spec-builder/tests/expected/create_with_full.json new file mode 100644 index 000000000000..6d127b6c0aca --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/create_with_full.json @@ -0,0 +1,58 @@ +{ + "name": "Custom", + "id": "custom", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "code": "0x010203", + "config": { + "babe": { + "authorities": [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", + "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b" + ], + "epochConfig": { + "allowed_slots": "PrimaryAndSecondaryVRFSlots", + "c": [ + 2, + 4 + ] + } + }, + "balances": { + "balances": [ + [ + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + 2000000000000000 + ], + [ + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y", + 2000000000000000 + ], + [ + "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b", + 5000000000000000 + ] + ] + }, + "substrateTest": { + "authorities": [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", + "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b" + ] + }, + "system": {} + } + } + } +} diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/create_with_named_preset.json b/substrate/bin/utils/chain-spec-builder/tests/expected/create_with_named_preset.json new file mode 100644 index 000000000000..2bf84281c59e --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/create_with_named_preset.json @@ -0,0 +1,38 @@ +{ + "name": "Custom", + "id": "custom", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "code": "0x010203", + "patch": { + "balances": { + "balances": [ + [ + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + 1000000000000000 + ], + [ + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y", + 1000000000000000 + ] + ] + }, + "substrateTest": { + "authorities": [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL" + ] + } + } + } + } +} diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/create_with_params.json b/substrate/bin/utils/chain-spec-builder/tests/expected/create_with_params.json new file mode 100644 index 000000000000..5aedd5b5c18b --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/create_with_params.json @@ -0,0 +1,37 @@ +{ + "name": "test_chain", + "id": "100", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "code": "0x010203", + "config": { + "babe": { + "authorities": [], + "epochConfig": { + "allowed_slots": "PrimaryAndSecondaryVRFSlots", + "c": [ + 1, + 4 + ] + } + }, + "balances": { + "balances": [] + }, + "substrateTest": { + "authorities": [] + }, + "system": {} + } + } + } +} diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/create_with_patch.json b/substrate/bin/utils/chain-spec-builder/tests/expected/create_with_patch.json new file mode 100644 index 000000000000..f98be3d7cfbe --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/create_with_patch.json @@ -0,0 +1,43 @@ +{ + "name": "Custom", + "id": "custom", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "code": "0x010203", + "patch": { + "balances": { + "balances": [ + [ + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + 1000000000000000 + ], + [ + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y", + 1000000000000000 + ], + [ + "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b", + 5000000000000000 + ] + ] + }, + "substrateTest": { + "authorities": [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", + "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b" + ] + } + } + } + } +} diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/update_code.json b/substrate/bin/utils/chain-spec-builder/tests/expected/update_code.json new file mode 100644 index 000000000000..dde561a594ff --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/update_code.json @@ -0,0 +1,40 @@ +{ + "name": "Custom", + "id": "custom", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "relay_chain": "rococo-local", + "para_id": 10101, + "custom_field": "custom_value", + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "code": "0x040506", + "config": { + "babe": { + "authorities": [], + "epochConfig": { + "allowed_slots": "PrimaryAndSecondaryVRFSlots", + "c": [ + 1, + 4 + ] + } + }, + "balances": { + "balances": [] + }, + "substrateTest": { + "authorities": [] + }, + "system": {} + } + } + } +} diff --git a/substrate/bin/utils/chain-spec-builder/tests/expected/update_code_raw.json b/substrate/bin/utils/chain-spec-builder/tests/expected/update_code_raw.json new file mode 100644 index 000000000000..d8c558a0ccbb --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/expected/update_code_raw.json @@ -0,0 +1,38 @@ +{ + "name": "Custom", + "id": "custom", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "codeSubstitutes": {}, + "genesis": { + "raw": { + "top": { + "0x00771836bebdd29870ff246d305c578c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x00771836bebdd29870ff246d305c578c5e0621c4869aa60c02be9adcc98a0d1d": "0x0cd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c186e1bafbb1430668c95d89b77217a402a74f64c3e103137b69e95e4b6e06b1e", + "0x1cb6f36e027abb2091cfb5110ab5087f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x1cb6f36e027abb2091cfb5110ab5087f66e8f035c8adbe7f1547b43c51e6f8a4": "0x00000000", + "0x1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef": "0x0100000000000000040000000000000002", + "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746bb1bdbcacd6ac9340000000000000000": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da92c2a60ec6dd16cd8ab911865ecf7555b186e1bafbb1430668c95d89b77217a402a74f64c3e103137b69e95e4b6e06b1e": "0x00000000000000000000000001000000000000000080e03779c311000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48": "0x00000000000000000000000001000000000000000080c6a47e8d03000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9b0edae20838083f2cde1c4080db8cf8090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22": "0x00000000000000000000000001000000000000000080c6a47e8d03000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x0000", + "0x3a636f6465": "0x040506", + "0x3a65787472696e7369635f696e646578": "0x00000000", + "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x00806d8176de1800" + }, + "childrenDefault": {} + } + } +} diff --git a/substrate/bin/utils/chain-spec-builder/tests/input/chain_spec_conversion_test.json b/substrate/bin/utils/chain-spec-builder/tests/input/chain_spec_conversion_test.json new file mode 100644 index 000000000000..6a390c0d38b1 --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/input/chain_spec_conversion_test.json @@ -0,0 +1,40 @@ +{ + "name": "Custom", + "id": "custom", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "relay_chain": "rococo-local", + "para_id": 10101, + "custom_field": "custom_value", + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "code": "0x0061736d0100000001b4033b60017f0060017f017f60037f7f7f017f60027f7f017f60027f7f0060037f7f7f0060047f7f7f7f0060057f7f7f7f7f0060000060047f7f7f7f017f60067f7f7f7f7f7f0060087f7f7f7f7f7f7f7f006000017f60047f7e7e7e0060027e7e0060017e0060027e7e017e60017e017e60037e7e7f017e60017f017e60017e017f60027f7e017f60037f7f7e017e60037f7e7f017f60037f7e7e0060047e7e7e7f017e60037e7e7e0060027e7f017f60047f7f7e7e0060037e7f7f0060047e7e7f7f017f60067f7f7f7f7f7f017f60057f7f7f7f7f017f600f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f017f60077f7f7f7f7f7f7f0060047f7c7f7f017f60037f7c7f017f60037e7f7f017f60077f7f7f7f7f7f7f017f60097f7f7f7f7f7f7e7e7e0060067f7f7f7e7e7f0060097f7f7f7e7e7f7f7f7f0060027e7f0060027c7f017f60067f7f7e7e7f7f0060027f7e00600a7f7f7f7f7f7f7f7f7f7f006000017e60067f7f7e7f7f7f0060057f7f7f7e7f0060047f7f7f7e0060027f7f017e60057f7f7e7f7f0060037f7f7e0060027f7e017e600b7f7f7f7f7f7f7f7f7f7f7f0060037f7f7c0060057f7e7e7e7e0060047f7e7e7f0002800d2a03656e76066d656d6f727902001203656e761c6578745f73746f726167655f617070656e645f76657273696f6e5f31000e03656e761b6578745f73746f726167655f636c6561725f76657273696f6e5f31000f03656e76226578745f73746f726167655f636c6561725f7072656669785f76657273696f6e5f32001003656e76286578745f73746f726167655f636f6d6d69745f7472616e73616374696f6e5f76657273696f6e5f31000803656e76196578745f73746f726167655f6765745f76657273696f6e5f31001103656e761e6578745f73746f726167655f6e6578745f6b65795f76657273696f6e5f31001103656e761a6578745f73746f726167655f726561645f76657273696f6e5f31001203656e762a6578745f73746f726167655f726f6c6c6261636b5f7472616e73616374696f6e5f76657273696f6e5f31000803656e761a6578745f73746f726167655f726f6f745f76657273696f6e5f32001303656e76196578745f73746f726167655f7365745f76657273696f6e5f31000e03656e76276578745f73746f726167655f73746172745f7472616e73616374696f6e5f76657273696f6e5f31000803656e76206578745f68617368696e675f626c616b65325f3132385f76657273696f6e5f31001403656e76206578745f68617368696e675f626c616b65325f3235365f76657273696f6e5f31001403656e761e6578745f68617368696e675f74776f785f3132385f76657273696f6e5f31001403656e761d6578745f68617368696e675f74776f785f36345f76657273696f6e5f31001403656e76226578745f6f6666636861696e5f696e6465785f636c6561725f76657273696f6e5f31000f03656e76206578745f6f6666636861696e5f696e6465785f7365745f76657273696f6e5f31000e03656e76236578745f63727970746f5f65636473615f67656e65726174655f76657273696f6e5f31001503656e76266578745f63727970746f5f65636473615f7075626c69635f6b6579735f76657273696f6e5f31001303656e761f6578745f63727970746f5f65636473615f7369676e5f76657273696f6e5f31001603656e76216578745f63727970746f5f65636473615f7665726966795f76657273696f6e5f32001703656e76256578745f63727970746f5f656432353531395f67656e65726174655f76657273696f6e5f31001503656e76286578745f63727970746f5f656432353531395f7075626c69635f6b6579735f76657273696f6e5f31001303656e76216578745f63727970746f5f656432353531395f7369676e5f76657273696f6e5f31001603656e76236578745f63727970746f5f656432353531395f7665726966795f76657273696f6e5f31001703656e76256578745f63727970746f5f737232353531395f67656e65726174655f76657273696f6e5f31001503656e76286578745f63727970746f5f737232353531395f7075626c69635f6b6579735f76657273696f6e5f31001303656e76216578745f63727970746f5f737232353531395f7369676e5f76657273696f6e5f31001603656e76236578745f63727970746f5f737232353531395f7665726966795f76657273696f6e5f32001703656e76296578745f6f6666636861696e5f7375626d69745f7472616e73616374696f6e5f76657273696f6e5f31001103656e76256578745f7472616e73616374696f6e5f696e6465785f696e6465785f76657273696f6e5f31000503656e76196578745f6c6f6767696e675f6c6f675f76657273696f6e5f31001803656e761f6578745f6c6f6767696e675f6d61785f6c6576656c5f76657273696f6e5f31000c03656e761c6578745f616c6c6f6361746f725f667265655f76657273696f6e5f31000003656e761e6578745f616c6c6f6361746f725f6d616c6c6f635f76657273696f6e5f31000103656e76286578745f64656661756c745f6368696c645f73746f726167655f726561645f76657273696f6e5f31001903656e76276578745f64656661756c745f6368696c645f73746f726167655f7365745f76657273696f6e5f31001a03656e762a6578745f747269655f626c616b65325f3235365f6f7264657265645f726f6f745f76657273696f6e5f32001b03656e761c6578745f6d6973635f7072696e745f6865785f76657273696f6e5f31000f03656e761d6578745f6d6973635f7072696e745f757466385f76657273696f6e5f31000f03656e76226578745f6d6973635f72756e74696d655f76657273696f6e5f76657273696f6e5f31001103e40de20d0403000203080506040400000303040402031c0a00030406060105060a060605060605010606010508061d1e0300050302031f20020302210302030303030304030302222323240303070100000405050507220503250303030300030303000007020320020203030607030505050707260103030607270005050405040505050404040405040505040404040304040500040404040404040406050504040404000004040428050404040404040404010505040504000029050505010404040400060406040404050505050000000003030c00070004040404000000040400030100010004040400000000060404050505060604000304000703000604050707060404000000030605040205030004040506002a2b2c07040404040404040404060405050504040407060000000703220303031c03050500000000000000030007040303030300030303030203020000030303020c03030301010203020c0604000504030401060405030003020303030400000604050000000000000000000404040604040505050004040006040505000604040505050000040404040000000000000000000000000000060606060000000604000000000604060405050505000000000400000005000404040000000000000006040505050604042d2d2d040003030300040506010300040504070805050a080406080505050504060504070905040709050407090104020405070c040404040400010b0a05040405040404040000000405040404060606060606060606060606060404040505050505000000040404040004000003030300000304000004040500000000000000000000000607060405060707000403030300030003000605020605040000000404040604040505050400060000000000060400030000040607060707050505060505050505050505050505050505050506050505220a220a040000040404000000000307060505070605050505050506070706070704040a0a040606222206222206060705070707070700000a0a06060605040404040404040404040404040404040505050505050509030304040404040404040404040404040404040404040404040404050404040403030004092d09090209090909090300060000000000000000000000000000000000000000000005050004040404040400040404050407030305050404040400000000070404050504040404040404040404000000000000000004040400000304000000061400000000030404010506000705050504050400050400000406050f2d03030303030303000000030506040404060a0004030000000001050600040400000004040504050404042d042a040404040400030f000400070602030204050606050505000404040004040400040004040000000003030a000003030305031313130405030505050504040000030404000000000000000000000004040003050304030403060501000a0304050303040504030504040404050000000c0000000000000000080404040000040004040404040405000303030303030303030303030303030303030303030303000000000000070707070700070303030303040300040404040502040004030303030303030303030000000000000403030b0b2e2e06070506020404040406010911040000040400062f0000000804050800030003040500000000000500030504030404040004000000040000010500000000300008060506050508040308040000000401040000000404000000000000030d03000000050304040f050404040404040404000606040a030302053131313105320101070502030103010106070305000000000301090203090401040404040401040404040a200a0a0a220606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606060606040305050505050505053333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333330400000000000000000000000334353130360100000503040401040104000000040404040404040404030303030b0404040404000537040a07040404050607070707060404000400000000000000040404060404040606050707050506060203030400040406020400040f050001040008000506000004000600070406050504040403030000000306050505040206020404030000000000000000000000040138063535051c1c03030303030303030000000703060300010406151c3300040103332d040305050304000704050304040303040404090400030403050303030300000800080306050500000304393a39023902020202023a3a390239020407017001c404c4040619037f01418080c0000b7f004198a4c6000b7f0041a0a4c6000b078b0c33195f5f696e6469726563745f66756e6374696f6e5f7461626c6501000c436f72655f76657273696f6e00de0b12436f72655f657865637574655f626c6f636b00df0b15436f72655f696e697469616c697a655f626c6f636b00e00b114d657461646174615f6d6574616461746100e10b1c4d657461646174615f6d657461646174615f61745f76657273696f6e00e20b1a4d657461646174615f6d657461646174615f76657273696f6e7300e30b2b5461676765645472616e73616374696f6e51756575655f76616c69646174655f7472616e73616374696f6e00e40b1c426c6f636b4275696c6465725f6170706c795f65787472696e73696300e50b1b426c6f636b4275696c6465725f66696e616c697a655f626c6f636b00e60b20426c6f636b4275696c6465725f696e686572656e745f65787472696e7369637300e70b1c426c6f636b4275696c6465725f636865636b5f696e686572656e747300e80b1d4163636f756e744e6f6e63654170695f6163636f756e745f6e6f6e636500e90b12546573744150495f62616c616e63655f6f6600ea0b19546573744150495f62656e63686d61726b5f6164645f6f6e6500eb0b20546573744150495f62656e63686d61726b5f766563746f725f6164645f6f6e6500ec0b22546573744150495f66756e6374696f6e5f7369676e61747572655f6368616e67656400ed0b10546573744150495f7573655f7472696500ee0b1f546573744150495f62656e63686d61726b5f696e6469726563745f63616c6c00ef0b1d546573744150495f62656e63686d61726b5f6469726563745f63616c6c00f00b19546573744150495f7665635f776974685f636170616369747900f10b18546573744150495f6765745f626c6f636b5f6e756d62657200f20b1b546573744150495f746573745f656432353531395f63727970746f00f30b1b546573744150495f746573745f737232353531395f63727970746f00f40b19546573744150495f746573745f65636473615f63727970746f00f50b14546573744150495f746573745f73746f7261676500f60b14546573744150495f746573745f7769746e65737300f70b1f546573744150495f746573745f6d756c7469706c655f617267756d656e747300f80b14546573744150495f646f5f74726163655f6c6f6700f90b16546573744150495f7665726966795f6564323535313900fa0b17546573744150495f77726974655f6b65795f76616c756500fb0b15417572614170695f736c6f745f6475726174696f6e00fc0b13417572614170695f617574686f72697469657300fd0b15426162654170695f636f6e66696775726174696f6e00fe0b1b426162654170695f63757272656e745f65706f63685f737461727400ff0b15426162654170695f63757272656e745f65706f636800800c12426162654170695f6e6578745f65706f636800810c35426162654170695f7375626d69745f7265706f72745f65717569766f636174696f6e5f756e7369676e65645f65787472696e73696300820c24426162654170695f67656e65726174655f6b65795f6f776e6572736869705f70726f6f6600830c214f6666636861696e576f726b65724170695f6f6666636861696e5f776f726b657200840c2153657373696f6e4b6579735f67656e65726174655f73657373696f6e5f6b65797300850c1f53657373696f6e4b6579735f6465636f64655f73657373696f6e5f6b65797300860c1e4772616e6470614170695f6772616e6470615f617574686f72697469657300870c194772616e6470614170695f63757272656e745f7365745f696400880c384772616e6470614170695f7375626d69745f7265706f72745f65717569766f636174696f6e5f756e7369676e65645f65787472696e73696300890c274772616e6470614170695f67656e65726174655f6b65795f6f776e6572736869705f70726f6f66008a0c1a47656e657369734275696c6465725f6275696c645f7374617465008b0c1947656e657369734275696c6465725f6765745f707265736574008c0c1b47656e657369734275696c6465725f7072657365745f6e616d6573008d0c0a5f5f646174615f656e6403010b5f5f686561705f62617365030209e208010041010bc3042b2c2d2a800134393a3335364041424344464c48494a4b3d3e4d4e4f509301568a018b018f0167655a75687466860185018301840163b905f501f401f901f801fd01da02e302900282029102840288028a028302fa049d029e029f02a00255a302a202e502af02bb02e102d502d902db02e802e7026182018101f10264eb0271ec02ed02ef02f402f502ee02fe02fa02970384039603f802fc02fb029203f702f902930395039403a403a503a303a603b903cb03e402cd03c003ce03c703c103df03c803cc03d803f003cf03d003d103da03d903ea03f203ee03ef03f703fa03f803f603f903e002fb0389048a048b048d048c04900491048f049204950496049704980499049a049b049c049d049e049f04a604a704a804a904aa04ab04ac04ad04ae04af04b004b104b704b804c004c104c204c304c404c504a004a104a204a304a404a504be04bf04b604b204fe04f104e80483058605ff04a7038405ee04e704f204f5049d05f304f404f604f704f804f904e9049b019c01960595059405980593059905ae05a305a205b105b205b005b305b705e308e605dd05fb05e105fa05e005fe05d106dd06e206e903db0ca307aa0aa407a707850d830db403e106b602a90ad70cc508e306ff068c0987079b039a03dd03a0039f03ae078d09d303900c940ca607ff02db07d907d707da078003d807d2078709d5079709e602850582058005e607a708820df6099202ef069908ea068509f0079d08f0069f08ee06a208e706e506a508e906b508a908ad08aa08900999098e09dd0a9809c308de03a203a103c708c908ca08b109cb08c20ae901cf08d108de08df08d508db08b805c208c608fd08f206f106f004a308eb06ab09a0098607a209af089e09ad09b0099d099209b80c8a0988098b098609c10996099b09ab08ba0cd50bb90c8f0994099f099c09a109aa099109ac099509a40aa50aa30ab807b707c108ac0cad0cab0cda0cd50c8705b405e606930ceb038105e707fc03e406d60ce907a107e006a105e307a507a207c408ec06e003d90cc903970c960cca03c603920c950ca4088805910ce8068f0cf406e807f409c808f509f709cc09ed0cc10dc709b409b509e30cec0ce60cea0ce80cc509be09d407d909da09d209d609d309d509d409c809f30cf40cc609d709d809e40c9b0de70ceb0ce90ccd099c0d9d0dc70ddb09c209c60ddc09b209c409c309f109e50793099a0a7f9a09f00c9302f2078c02ba058702e202fa09ae0ab30ab50aaf0ab20af302910de00abc09df0af2028909bd09bb09d006c009a608bf09cf06b70cb00ad107f601ae02ed06b103f506f306e009fb08d80cec03fa08d203f701a00db502900d9a0cd607c10cc00cc40cbe0cbf0cfe09ee0cad02a807ac02940d8b088a0889088c088e088d08930dd307b70db80dbe0d70b90dba0dbf0db50dbb0dbc0dbd0dae0db00db10db30db40db20dc20daf0db60d58c40dcb0dcc0dd20dd50dcd0dca0dd30dd40dce0dd60dcf0dd00dc80dd10dc90dd70dc30de50de60dec0def0df30dee0ded0dea0df80deb0df90d0afd9e49e20d0d002000200110b780808000000b12002000418080c08000200110d9808080000b220002402000280200450d00200028020441002802c0a3c68000118080808000000b0b4b01017f02402000280200200028020822036b20024f0d0020002003200210af80808000200028020821030b200028020420036a2001200210848e8080001a2000200320026a36020841000bf20201027f23808080800041106b220224808080800002400240024002402001418001490d002002410036020c2001418010490d0102402001418080044f0d0020022001413f71418001723a000e20022001410c7641e001723a000c20022001410676413f71418001723a000d410321010c030b20022001413f71418001723a000f20022001410676413f71418001723a000e20022001410c76413f71418001723a000d2002200141127641077141f001723a000c410421010c020b0240200028020822032000280200470d002000200310b180808000200028020821030b200028020420036a20013a00002000200028020841016a3602080c020b20022001413f71418001723a000d2002200141067641c001723a000c410221010b02402000280200200028020822036b20014f0d0020002003200110af80808000200028020821030b200028020420036a2002410c6a200110848e8080001a2000200320016a3602080b200241106a24808080800041000b4e01017f23808080800041206b2200248080808000200041146a42003702002000410136020c2000419c81c080003602082000419880c08000360210200041086a41a481c0800010f680808000000be20101027f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024108200241084b1b2202417f73411f7621040240024020010d00200341003602180c010b2003200136021c20034101360218200320002802043602140b200341086a20042002200341146a10b080808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000b860201017f024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d0020020d02410121010c030b20032802002103200241002802c8a3c68000118180808000002201450d0320012003200410848e8080001a200341002802c0a3c68000118080808000000c020b20020d00410121010c010b41002d00fca3c680001a200241002802c8a3c68000118180808000002201450d010b20002001360204200041086a2002360200200041003602000f0b20004101360204200041086a2002360200200041013602000f0b20004100360204200041086a2002360200200041013602000f0b20004100360204200041013602000be00101037f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014108200141084b1b2201417f73411f7621040240024020030d00200241003602180c010b2002200336021c20024101360218200220002802043602140b200241086a20042001200241146a10b080808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000b0d002001200010a980808000000b02000b220002402000280200450d00200028020441002802c0a3c68000118080808000000b0b2100200128021441b481c080004105200141186a28020028020c118280808000000b2100200128021441b981c08000410b200141186a28020028020c118280808000000bc60101017f23808080800041306b22022480808080002002200036020c024041002d00fda3c680000d002002411c6a420137020020024102360214200241e881c08000360210200241858080800036022c2002200241286a36021820022002410c6a360228200241106a410041e882c0800010f780808000000b2002411c6a420137020020024102360214200241e881c08000360210200241858080800036022c2002200241286a36021820022002410c6a360228200241106a41f882c0800010f680808000000bb80301077f23808080800041106b220224808080800002400240024002400240024020012802042203450d00200128020021042003410371210502400240200341044f0d0041002103410021060c010b2004411c6a21072003417c712108410021034100210603402007280200200741786a280200200741706a280200200741686a28020020036a6a6a6a2103200741206a21072008200641046a2206470d000b0b02402005450d00200641037420046a41046a21070340200728020020036a2103200741086a21072005417f6a22050d000b0b02402001410c6a280200450d0020034100480d012003411049200428020445710d01200341017421030b20030d010b41012107410021030c010b2003417f4c0d0141002d00fca3c680001a200341002802c8a3c68000118180808000002207450d020b2002410036020820022007360204200220033602002002418883c08000200110d980808000450d0241a083c0800041332002410f6a41d483c0800041d484c08000108981808000000b10ae80808000000b4101200310b280808000000b20002002290200370200200041086a200241086a280200360200200241106a2480808080000b4b01017f02402000280200200028020822036b20024f0d0020002003200210af80808000200028020821030b200028020420036a2001200210848e8080001a2000200320026a36020841000bf20201027f23808080800041106b220224808080800002400240024002402001418001490d002002410036020c2001418010490d0102402001418080044f0d0020022001413f71418001723a000e20022001410c7641e001723a000c20022001410676413f71418001723a000d410321010c030b20022001413f71418001723a000f20022001410676413f71418001723a000e20022001410c76413f71418001723a000d2002200141127641077141f001723a000c410421010c020b0240200028020822032000280200470d002000200310b180808000200028020821030b200028020420036a20013a00002000200028020841016a3602080c020b20022001413f71418001723a000d2002200141067641c001723a000c410221010b02402000280200200028020822036b20014f0d0020002003200110af80808000200028020821030b200028020420036a2002410c6a200110848e8080001a2000200320016a3602080b200241106a24808080800041000b892e07027e017f087e017f0a7e017f157e200020002903102204200129002022057c200041306a220629030022077c2208200129002822097c200820028542ebfa86dabfb5f6c11f85422089220a42abf0d3f4afeebcb73c7c220b200785422889220c7c220d200129006022027c2000290318220e200129003022087c200041386a220f29030022107c2211200129003822127c201120038542f9c2f89b91a3b3f0db0085422089220342f1edf4f8a5a7fda7a57f7c221120108542288922137c2214200385423089221520117c221620138542018922177c2218200129006822037c201820002903082219200129001022117c200041286a221a290300221b7c221c200129001822137c201c429fd8f9d9c291da829b7f85422089221c42bbceaaa6d8d0ebb3bb7f7c221d201b85422889221e7c221f201c85423089222085422089222120002903002222200129000022187c200029032022237c22242001290008221c7c200029034020248542d1859aeffacf9487d100854220892224428892f39dffccf984ea007c222520238542288922267c2227202485423089222820257c22257c2229201785422889222a7c222b200129004822177c201f200129005022247c200d200a85423089220d200b7c221f200c85420189220b7c220c2001290058220a7c200c202885422089220c20167c2216200b85422889220b7c2228200c85423089222c20167c2216200b85420189222d7c222e2001290078220b7c202e20142001290070220c7c202520268542018922147c2225200b7c2025200d85422089220d2020201d7c221d7c222020148542288922147c2225200d85423089222685422089222e20272001290040220d7c201d201e85420189221d7c221e20177c201e2015854220892215201f7c221e201d85422889221d7c221f2015854230892215201e7c221e7c2227202d85422889222d7c222f200a7c202520037c202b202185423089222120297c2225202a8542018922297c222a20087c202a201585422089221520167c221620298542288922297c222a201585423089221520167c221620298542018922297c222b20127c202b202820057c201e201d85420189221d7c221e200d7c201e202185422089221e202620207c22207c2221201d85422889221d7c2226201e85423089221e854220892228201f200c7c202020148542018922147c221f20247c201f202c85422089221f20257c222020148542288922147c2225201f85423089221f20207c22207c222b20298542288922297c222c20097c202620187c202f202e85423089222620277c2227202d85420189222d7c222e20117c202e201f85422089221f20167c2216202d85422889222d7c222e201f85423089221f20167c2216202d85420189222d7c222f20117c202f202a20097c202020148542018922147c222020137c20202026854220892220201e20217c221e7c222120148542288922147c2226202085423089222085422089222a2025201c7c201e201d85420189221d7c221e20027c201e201585422089221520277c221e201d85422889221d7c22252015854230892215201e7c221e7c2227202d85422889222d7c222f20127c2026200b7c202c2028854230892226202b7c222820298542018922297c222b20037c202b201585422089221520167c221620298542288922297c222b201585423089221520167c221620298542018922297c222c201c7c202c202e20027c201e201d85420189221d7c221e20187c201e202685422089221e202020217c22207c2221201d85422889221d7c2226201e85423089221e85422089222c2025200a7c202020148542018922147c2220200d7c2020201f85422089221f20287c222020148542288922147c2225201f85423089221f20207c22207c222820298542288922297c222e20037c202620137c202f202a85423089222620277c2227202d85420189222a7c222d20087c202d201f85422089221f20167c2216202a85422889222a7c222d201f85423089221f20167c2216202a85420189222a7c222f20027c202f202b20177c202020148542018922147c222020057c20202026854220892220201e20217c221e7c222120148542288922147c2226202085423089222085422089222b202520247c201e201d85420189221d7c221e200c7c201e201585422089221520277c221e201d85422889221d7c22252015854230892215201e7c221e7c2227202a85422889222a7c222f20057c2026200a7c202e202c85423089222620287c222820298542018922297c222c200c7c202c201585422089221520167c221620298542288922297c222c201585423089221520167c221620298542018922297c222e20187c202e202d20137c201e201d85420189221d7c221e201c7c201e202685422089221e202020217c22207c2221201d85422889221d7c2226201e85423089221e85422089222d202520127c202020148542018922147c222020177c2020201f85422089221f20287c222020148542288922147c2225201f85423089221f20207c22207c222820298542288922297c222e20117c202620097c202f202b85423089222620277c2227202a85420189222a7c222b20247c202b201f85422089221f20167c2216202a85422889222a7c222b201f85423089221f20167c2216202a85420189222a7c222f20057c202f202c200b7c202020148542018922147c2220200d7c20202026854220892220201e20217c221e7c222120148542288922147c2226202085423089222085422089222c202520117c201e201d85420189221d7c221e20087c201e201585422089221520277c221e201d85422889221d7c22252015854230892215201e7c221e7c2227202a85422889222a7c222f20087c202620247c202e202d85423089222620287c222820298542018922297c222d200b7c202d201585422089221520167c221620298542288922297c222d201585423089221520167c221620298542018922297c222e200d7c202e202b20097c201e201d85420189221d7c221e20127c201e202685422089221e202020217c22207c2221201d85422889221d7c2226201e85423089221e85422089222b202520177c202020148542018922147c222020187c2020201f85422089221f20287c222020148542288922147c2225201f85423089221f20207c22207c222820298542288922297c222e20187c2026200a7c202f202c85423089222620277c2227202a85420189222a7c222c20027c202c201f85422089221f20167c2216202a85422889222a7c222c201f85423089221f20167c2216202a85420189222a7c222f200a7c202f202d20137c202020148542018922147c222020037c20202026854220892220201e20217c221e7c222120148542288922147c2226202085423089222085422089222d2025200c7c201e201d85420189221d7c221e201c7c201e201585422089221520277c221e201d85422889221d7c22252015854230892215201e7c221e7c2227202a85422889222a7c222f200b7c2026200d7c202e202b85423089222620287c222820298542018922297c222b20137c202b201585422089221520167c221620298542288922297c222b201585423089221520167c221620298542018922297c222e200c7c202e202c20087c201e201d85420189221d7c221e20247c201e202685422089221e202020217c22207c2221201d85422889221d7c2226201e85423089221e85422089222c202520117c202020148542018922147c222020027c2020201f85422089221f20287c222020148542288922147c2225201f85423089221f20207c22207c222820298542288922297c222e200c7c202620127c202f202d85423089222620277c2227202a85420189222a7c222d20097c202d201f85422089221f20167c2216202a85422889222a7c222d201f85423089221f20167c2216202a85420189222a7c222f20037c202f202b201c7c202020148542018922147c222020177c20202026854220892220201e20217c221e7c222120148542288922147c2226202085423089222085422089222b202520057c201e201d85420189221d7c221e20037c201e201585422089221520277c221e201d85422889221d7c22252015854230892215201e7c221e7c2227202a85422889222a7c222f20177c202620057c202e202c85423089222620287c222820298542018922297c222c20247c202c201585422089221520167c221620298542288922297c222c201585423089221520167c221620298542018922297c222e20117c202e202d201c7c201e201d85420189221d7c221e200b7c201e202685422089221e202020217c22207c2221201d85422889221d7c2226201e85423089221e85422089222d202520027c202020148542018922147c222020097c2020201f85422089221f20287c222020148542288922147c2225201f85423089221f20207c22207c222820298542288922297c222e20027c202620087c202f202b85423089222620277c2227202a85420189222a7c222b20137c202b201f85422089221f20167c2216202a85422889222a7c222b201f85423089221f20167c2216202a85420189222a7c222f201c7c202f202c200d7c202020148542018922147c2220200a7c20202026854220892220201e20217c221e7c222120148542288922147c2226202085423089222085422089222c202520187c201e201d85420189221d7c221e20127c201e201585422089221520277c221e201d85422889221d7c22252015854230892215201e7c221e7c2227202a85422889222a7c222f200d7c202620137c202e202d85423089222620287c222820298542018922297c222d20177c202d201585422089221520167c221620298542288922297c222d201585423089221520167c221620298542018922297c222e20087c202e202b20127c201e201d85420189221d7c221e200c7c201e202685422089221e202020217c22207c2221201d85422889221d7c2226201e85423089221e85422089222b202520037c202020148542018922147c2220200a7c2020201f85422089221f20287c222020148542288922147c2225201f85423089221f20207c22207c222820298542288922297c222e200a7c2026200b7c202f202c85423089222620277c2227202a85420189222a7c222c20057c202c201f85422089221f20167c2216202a85422889222a7c222c201f85423089221f20167c2216202a85420189222a7c222f20137c202f202d20117c202020148542018922147c222020247c20202026854220892220201e20217c221e7c222120148542288922147c2226202085423089222085422089222d202520097c201e201d85420189221d7c221e20187c201e201585422089221520277c221e201d85422889221d7c22252015854230892215201e7c221e7c2227202a85422889222a7c222f201c7c202620187c202e202b85423089222620287c222820298542018922297c222b200d7c202b201585422089221520167c221620298542288922297c222b201585423089221520167c221620298542018922297c222e20057c202e202c200c7c201e201d85420189221d7c221e20177c201e202685422089221e202020217c22207c2221201d85422889221d7c2226201e85423089221e85422089222c202520087c202020148542018922147c2220200b7c2020201f85422089221f20287c222020148542288922147c2225201f85423089221f20207c22207c222820298542288922297c222e20127c202620037c202f202d85423089222620277c2227202a85420189222a7c222d20127c202d201f85422089221f20167c2216202a85422889222a7c222d201f85423089221f20167c2216202a85420189222a7c222f20087c202f202b20247c202020148542018922147c222020097c20202026854220892220201e20217c221e7c222120148542288922147c2226202085423089222085422089222b202520027c201e201d85420189221d7c221e20117c201e201585422089221520277c221e201d85422889221d7c22252015854230892215201e7c221e7c2227202a85422889222a7c222f20137c2026201c7c202e202c85423089222620287c222820298542018922297c222c20097c202c201585422089221520167c221620298542288922297c222c201585423089221520167c221620298542018922297c222e20027c202e202d200d7c201e201d85420189221d7c221e20057c201e202685422089221e202020217c22207c2221201d85422889221d7c2226201e85423089221e85422089222d202520247c202020148542018922147c222020117c2020201f85422089221f20287c222020148542288922147c2225201f85423089221f20207c22207c222820298542288922297c222e20057c202620177c202f202b85423089222620277c2227202a85420189222a7c222b200c7c202b201f85422089221f20167c2216202a85422889222a7c222b201f85423089221f20167c2216202a85420189222a7c222f20097c202f202c20037c202020148542018922147c222020187c20202026854220892220201e20217c221e7c222120148542288922147c2226202085423089222085422089222c2025200b7c201e201d85420189221d7c221e200a7c201e201585422089221520277c221e201d85422889221d7c22252015854230892215201e7c221e7c2227202a85422889222a7c222f20027c202620087c202e202d85423089222620287c222820298542018922297c222d20127c202d201585422089221520167c221620298542288922297c222d201585423089221520167c221620298542018922297c222e20037c202e202b20117c201e201d85420189221d7c221e20137c201e202685422089221e202020217c22207c2221201d85422889221d7c2226201e85423089221e85422089222b202520187c202020148542018922147c2220201c7c2020201f85422089221f20287c222020148542288922147c2225201f85423089221f20207c22207c222820298542288922297c222e20177c202620247c202f202c85423089222620277c2227202a85420189222a7c222c200a7c202c201f85422089221f20167c2216202a85422889222a7c222c201f85423089221f20167c2216202a85420189222a7c222f200b7c202f202d200c7c202020148542018922147c2220200b7c2020202685422089220b201e20217c221e7c222020148542288922147c2221200b85423089220b8542208922262025200d7c201e201d85420189221d7c221e20177c201e201585422089221720277c2215201d85422889221d7c221e201785423089221720157c22157c2225202a8542288922277c222a200a7c202120037c202e202b85423089220320287c220a20298542018922217c222820087c2028201785422089220820167c221720218542288922167c2221200885423089220820177c221720168542018922167c222820127c2028202c20057c2015201d8542018922057c2212200d7c20122003854220892212200b20207c22037c220b20058542288922057c220d2012854230892212854220892215201e200c7c200320148542018922037c220c20247c200c201f854220892224200a7c220a20038542288922037c220c2024854230892224200a7c220a7c221420168542288922167c221d200485200c201c7c2012200b7c221220058542018922057c221c20027c201c2008854220892202202a202685423089220820257c221c7c220b20058542288922057c220c2002854230892202200b7c220b853703102000200e2013202120097c200a20038542018922097c22037c2003200885422089220820127c221220098542288922097c2203852011200d20187c201c20278542018922137c22187c2018202485422089221120177c221820138542288922137c221c201185423089221120187c2218853703182000201c2019852003200885423089220820127c2212853703082000200c202285201d201585423089220320147c221c85370300201a201b200b20058542018985200385370300200f2010201c2016854201898520028537030020062007201820138542018985200885370300200020232012200985420189852011853703200b8b0601097f0240024002400240024020020d00410021060c010b200120026a210720052d008001210841002106200121094100210a03400240024020092c0000220b4100480d002005200b41ff0171220b6a2d0000220c41ff01470d012000200a3602042000200b3602000f0b2000200a3602042000418280c4003602000f0b02400240200620044b0d00200320066a210d2006450d01024002402006410371220e0d002003210b0c010b2003210b0340200b200b2d0000413a6c200c6a220c3a0000200b41016a210b200c410876210c200e417f6a220e0d000b0b20064104490d010340200b200b2d0000413a6c200c6a220c3a0000200b41016a220e200e2d0000413a6c200c4108766a220c3a0000200b41026a220e200e2d0000413a6c200c4108766a220c3a0000200b41036a220e200e2d0000413a6c200c4108766a220c3a0000200c410876210c200b41046a220b200d470d000c020b0b20062004418c88c08000109581808000000b0240200c450d00200620044f0d04200d200c3a0000200641016a21060b200a41016a210a200941016a22092007470d000b20062004200620044b1b210e200841ff0171210c0240034020012d0000200c470d01200320066a410020062004491b210b200e2006460d03200141016a2101200b41003a0000200641016a21062002417f6a22020d000b0b200620044b0d0320064102490d00200320066a200641017622046b210a4100210b024020044101460d002006417f6a210c200441feffffff077121014100210b03402003200c6a220d2d00002109200d2003200b6a220e2d00003a0000200e20093a0000200a2004200b417e736a6a220d2d00002109200d200e41016a220e2d00003a0000200e20093a0000200c417e6a210c2001200b41026a220b470d000b0b2006410271450d002003200b6a220c2d0000210e200c200a2004200b417f736a6a220b2d00003a0000200b200e3a00000b2000418380c400360200200020063602040f0b2000200b3602042000418080c4003602000f0b2000428080c4003702000f0b2006200441fc87c08000109581808000000b02000b21002001280214419c88c08000410b200141186a28020028020c118280808000000bd20101037f200128020421020240024002402001280208220320012802002204460d0041002d00fca3c680001a410c41002802c8a3c68000118180808000002201450d0220014101360208200120043602042001200236020041908ac0800021040c010b024020030d00418489c08000210441002101419c88c0800021020c010b41a489c08000210402402002410171450d00200221010c010b20024101722101419489c0800021040b2000200136020c2000200336020820002002360204200020043602000f0b4104410c10b280808000000b22002000410036020c20002003360208200020023602042000418489c080003602000b7801017f024002400240024020030d00410121040c010b2003417f4c0d0141002d00fca3c680001a200341002802c8a3c68000118180808000002204450d020b20042002200310848e80800021022000200336020820002002360204200020033602000f0b10ae80808000000b4101200310b280808000000b040041000b02000b6b01017f024020012802002204410171450d002000200120042004417e712002200310c5808080000f0b20042004280208220141016a36020802402001417f4c0d002000200436020c2000200336020820002002360204200041908ac080003602000f0b10d180808000000be00101017f41002d00fca3c680001a02400240410c41002802c8a3c68000118180808000002206450d0020064102360208200620033602002006200420036b20056a360204200120062001280200220320032002461b360200024020032002470d002000200636020c2000200536020820002004360204200041908ac080003602000f0b20032003280208220241016a3602082002417f4c0d012000200336020c2000200536020820002004360204200041908ac08000360200200641002802c0a3c68000118080808000000f0b4104410c10b280808000000b10d180808000000b4d00024020012802002201410171450d002001417e712002200310fe8d808000210120002003360208200020013602042000200220036a20016b3602000f0b200020012002200310c7808080000bdb0201037f23808080800041106b220424808080800041012105200141002001280208220620064101461b3602080240024002400240024020064101470d002001280204210620012802002105200141002802c0a3c6800011808080800000200020052002200310fe8d808000360204200020063602000c010b02402003450d002003417f4c0d0241002d00fca3c680001a200341002802c8a3c68000118180808000002205450d030b20052002200310848e8080002102200120012802082206417f6a360208024020064101470d00200141046a280200417f4c0d04200128020041002802c0a3c6800011808080800000200141002802c0a3c68000118080808000000b20002002360204200020033602000b20002003360208200441106a2480808080000f0b10ae80808000000b4101200310b280808000000b41b489c08000412b2004410f6a41e089c0800041808ac08000108981808000000bea0101017f23808080800041106b2203248080808000024002400240024020002802002200410171450d00200120026a2000417e7122006b417f4c0d02200041002802c0a3c68000118080808000000c010b200020002802082202417f6a36020820024101470d00200041046a280200417f4c0d02200028020041002802c0a3c6800011808080800000200041002802c0a3c68000118080808000000b200341106a2480808080000f0b41b489c08000412b2003410f6a41e089c0800041f089c08000108981808000000b41b489c08000412b2003410f6a41e089c0800041808ac08000108981808000000b6801017f024020012802002204410171450d0020002001200420042002200310c5808080000f0b20042004280208220141016a36020802402001417f4c0d002000200436020c2000200336020820002002360204200041908ac080003602000f0b10d180808000000b4a00024020012802002201410171450d0020012002200310fe8d808000210120002003360208200020013602042000200220036a20016b3602000f0b200020012002200310c7808080000be50101017f23808080800041106b2203248080808000024002400240024020002802002200410171450d00200120026a20006b417f4c0d02200041002802c0a3c68000118080808000000c010b200020002802082202417f6a36020820024101470d00200041046a280200417f4c0d02200028020041002802c0a3c6800011808080800000200041002802c0a3c68000118080808000000b200341106a2480808080000f0b41b489c08000412b2003410f6a41e089c0800041f089c08000108981808000000b41b489c08000412b2003410f6a41e089c0800041808ac08000108981808000000b2301017f410121010240200028020022004101710d00200028020841014621010b20010b4901017f200128020022012001280208220441016a36020802402004417f4a0d0010d180808000000b2000200136020c2000200336020820002002360204200041908ac080003602000b1300200020012802002002200310c7808080000b0d0020002802002802084101460b960101027f23808080800041106b22032480808080002000280200220020002802082204417f6a3602080240024020044101470d00200041046a280200417f4c0d01200028020041002802c0a3c6800011808080800000200041002802c0a3c68000118080808000000b200341106a2480808080000f0b41b489c08000412b2003410f6a41e089c0800041808ac08000108981808000000b170041a08ac08000410541808bc0800010f880808000000bd10805017f027e017f017e027f23808080800041e0006b22042480808080002004200336023c02400240024002402003417e6a41234f0d0020020d01200041003a00010c020b200441cc006a420137020020044101360244200441cc8bc08000360240200441858080800036025c2004200441d8006a36024820042004413c6a360258200441c0006a41c48cc0800010f680808000000b0240024002400240024020012d000041556a0e03010200020b20024101460d03200141016a21012003ad2105024002400240200241104b0d0020034111490d010b024002402003410a4b0d002002417f6a21024200210603402002450d07200441286a20062006423f872005420010878e80800020012d000041506a220720034f0d08200429033020042903282208423f87520d04200141016a21012002417f6a21022007ad2206420055200820067d220620085373450d000c020b0b2002417f6a21024200210603402002450d06200441186a20062006423f872005420010878e8080002004290318210820042903202106024020012d0000220941506a2207410a490d00417f2009412072220741a97f6a220920092007419f7f6a491b220720034f0d080b20062008423f87520d03200141016a21012002417f6a21022007ad2206420055200820067d220620085373450d000b0b200041033a00010c060b02402003410a4b0d002002417f6a210242002106034020012d000041506a220720034f0d06200141016a2101200620057e2007ad7d21062002417f6a22020d000c050b0b2002417f6a2107420021060340024020012d0000220941506a2202410a490d00417f2009412072220241a97f6a220920092002419f7f6a491b220220034f0d060b200141016a2101200620057e2002ad7d21062007417f6a22070d000c040b0b200041033a00010c040b2002417f6a2202450d02200141016a21010b2003ad210802400240200341104b0d0020024110490d010b2003410b49210a42002106024003402002450d03200441086a20062006423f872008420010878e80800020012d0000220941506a2107200429030821052004290310210602400240200a0d002007410a490d01417f2009412072220741a97f6a220920092007419f7f6a491b21070b200720034f0d050b20062005423f87520d01200141016a21012002417f6a21022007ad2206420053200520067c220620055373450d000b200041023a00010c040b200041023a00010c030b02402003410a4b0d0042002106034020012d000041506a220720034f0d03200141016a2101200620087e2007ad7c21062002417f6a22020d000c020b0b420021060340024020012d0000220941506a2207410a490d00417f2009412072220741a97f6a220920092007419f7f6a491b220720034f0d030b200141016a2101200620087e2007ad7c21062002417f6a22020d000b0b20002006370308410021010c020b41012101200041013a00010c010b410121010b200020013a0000200441e0006a2480808080000bc50605027f017e017f017e027f02402002280200220341134d0d00024002400240200042808084fea6dee111540d002002200341706a2204360200200120046a2000200042808084fea6dee11180220542808084fea6dee1117e7d2200428080e983b1de1680a741017441da8dc080006a2f00003b0000200320016a2206417c6a200042e40080220742e40082a741017441da8dc080006a2f00003b00002006417a6a20004290ce008042e40082a741017441da8dc080006a2f00003b0000200641786a200042c0843d8042e40082a741017441da8dc080006a2f00003b0000200641766a20004280c2d72f80a741e4007041017441da8dc080006a2f00003b0000200641746a20004280c8afa02580a741e4007041017441da8dc080006a2f00003b0000200641726a20004280a094a58d1d80a741ffff037141e4007041017441da8dc080006a2f00003b00002000200742e4007e7da721060c010b024020004280c2d72f5a0d0020032104200021050c020b2001200341786a22046a200020004280c2d72f8022054280c2d72f7e7da7220641c0843d6e41017441da8dc080006a2f00003b0000200320016a2208417c6a200641e4006e220941e4007041017441da8dc080006a2f00003b00002008417a6a20064190ce006e41ffff037141e4007041017441da8dc080006a2f00003b00002006200941e4006c6b21060b200320016a417e6a200641017441da8dc080006a2f00003b00000b024002402005a722084190ce004f0d0020042103200821060c010b20012004417c6a22036a200820084190ce006e22064190ce006c6b220841ffff037141e4006e220941017441da8dc080006a2f00003b0000200420016a417e6a2008200941e4006c6b41ffff037141017441da8dc080006a2f00003b00000b02400240200641ffff0371220441e4004f0d00200621040c010b20012003417e6a22036a2006200441e4006e220441e4006c6b41ffff037141017441da8dc080006a2f00003b00000b0240200441ffff0371410a490d0020012003417e6a22036a200441ffff037141017441da8dc080006a2f00003b0000200220033602000f0b20012003417f6a22036a200441306a3a0000200220033602000f0b41a28fc08000411c41c08fc0800010f880808000000bd10403017f027e017f2380808080004190016b22042480808080002004412736028c0102400240200142808020540d00200441306a2000420042f3b2d8c19e9ebdcc957f420010878e808000200441206a2000420042d2e1aadaeda7c987f600420010878e808000200441d0006a2001420042f3b2d8c19e9ebdcc957f420010878e808000200441c0006a2001420042d2e1aadaeda7c987f600420010878e808000200441c0006a41086a290300200441206a41086a290300200441306a41086a290300220520042903207c2201200554ad7c220620042903407c2205200654ad7c2005200441d0006a41086a290300200120042903507c200154ad7c7c2201200554ad7c2206423e8821052001423e8820064202868421010c010b20004213882001422d868442bda282a38eab04802101420021050b200441106a20012005428080e0b0b79fb79cf500420010878e808000200429031020007c200441e5006a2004418c016a10d380808000200428028c012107024020012005844200510d00200441e5006a41146a41302007416c6a108a8e8080001a2004411436028c01200420014213882005422d8684220542bda282a38eab048022002001428080e0b0b79fb79cf500420010878e808000200429030020017c200441e5006a2004418c016a10d380808000200428028c012107200542bda282a38eab04540d00200441e6006a41302007417f6a108a8e8080001a20042000a74130723a0065410021070b2003200241d08fc080004100200441e5006a20076a412720076b10db80808000210720044190016a24808080800020070ba60101037f2380808080004180016b220224808080800020002d00002103410021000340200220006a41ff006a20034101714130723a00002000417f6a2100200341ff017122044101762103200441024f0d000b024020004180016a22034180014d0d00200341800141c88dc08000109481808000000b2001410141d88dc080004102200220006a4180016a410020006b10db80808000210020024180016a24808080800020000b02000bb10701017f23808080800041106b2203248080808000024002400240024002400240024002400240024020010e2805080808080808080801030808020808080808080808080808080808080808080808060808080807000b200141dc00460d030c070b20004180043b010a20004200370102200041dce8013b01000c070b20004180043b010a20004200370102200041dce4013b01000c060b20004180043b010a20004200370102200041dcdc013b01000c050b20004180043b010a20004200370102200041dcb8013b01000c040b20004180043b010a20004200370102200041dce0003b01000c030b20024180800471450d0120004180043b010a20004200370102200041dcc4003b01000c020b200241800271450d0020004180043b010a20004200370102200041dcce003b01000c010b024002400240024002402002410171450d00200110f3808080000d010b2001109a81808000450d012000200136020420004180013a00000c040b200341066a41026a41003a0000200341003b0106200341fd003a000f20032001410f714190bdc080006a2d00003a000e20032001410476410f714190bdc080006a2d00003a000d20032001410876410f714190bdc080006a2d00003a000c20032001410c76410f714190bdc080006a2d00003a000b20032001411076410f714190bdc080006a2d00003a000a20032001411476410f714190bdc080006a2d00003a0009200141017267410276417e6a2201410b4f0d01200341066a20016a220241002f008fbec080003b0000200241026a41002d0091bec080003a00002000410a3a000b200020013a000a20002003290106370000200041086a200341066a41086a2f01003b00000c030b200341066a41026a41003a0000200341003b0106200341fd003a000f20032001410f714190bdc080006a2d00003a000e20032001410476410f714190bdc080006a2d00003a000d20032001410876410f714190bdc080006a2d00003a000c20032001410c76410f714190bdc080006a2d00003a000b20032001411076410f714190bdc080006a2d00003a000a20032001411476410f714190bdc080006a2d00003a0009200141017267410276417e6a2201410b4f0d01200341066a20016a220241002f008fbec080003b0000200241026a41002d0091bec080003a00002000410a3a000b200020013a000a20002003290106370000200041086a200341066a41086a2f01003b00000c020b2001410a4194bec08000109481808000000b2001410a4194bec08000109481808000000b200341106a2480808080000b17002001280214200141186a280200200010d9808080000be105010b7f23808080800041306b2203248080808000200341246a2001360200200341033a002c2003412036021c410021042003410036022820032000360220200341003602142003410036020c02400240024002400240200228021022050d002002410c6a2802002200450d012002280208220120004103746a21062000417f6a41ffffffff017141016a2104200228020021004100210703400240200041046a2802002208450d00200328022020002802002008200328022428020c118280808000000d040b20012802002003410c6a200141046a280200118380808000000d03200741016a2107200041086a2100200141086a22012006470d000c020b0b200241146a2802002201450d00200141057421092001417f6a41ffffff3f7141016a21042002280208210a20022802002100410021074100210b03400240200041046a2802002201450d00200328022020002802002001200328022428020c118280808000000d030b2003200520076a220141106a28020036021c20032001411c6a2d00003a002c2003200141186a2802003602282001410c6a28020021064100210c41002108024002400240200141086a2802000e03010002010b2006410374210d41002108200a200d6a220d280204419d80808000470d01200d28020028020021060b410121080b200320063602102003200836020c200141046a280200210802400240024020012802000e03010002010b20084103742106200a20066a2206280204419d80808000470d01200628020028020021080b4101210c0b200320083602182003200c360214200a200141146a2802004103746a22012802002003410c6a200141046a280200118380808000000d02200b41016a210b200041086a21002009200741206a2207470d000b0b200420022802044f0d012003280220200228020020044103746a22012802002001280204200328022428020c11828080800000450d010b410121010c010b410021010b200341306a24808080800020010b17002001280214200141186a280200200010d9808080000bad0601077f0240024020010d00200541016a2106200028021c2107412d21080c010b412b418080c400200028021c220741017122011b2108200120056a21060b0240024020074104710d00410021020c010b0240024020034110490d002002200310fd8080800021010c010b024020030d00410021010c010b2003410371210902400240200341044f0d00410021014100210a0c010b2003417c71210b410021014100210a034020012002200a6a220c2c000041bf7f4a6a200c41016a2c000041bf7f4a6a200c41026a2c000041bf7f4a6a200c41036a2c000041bf7f4a6a2101200b200a41046a220a470d000b0b2009450d002002200a6a210c03402001200c2c000041bf7f4a6a2101200c41016a210c2009417f6a22090d000b0b200120066a21060b0240024020002802000d00410121012000280214220c2000280218220a20082002200310dc808080000d01200c20042005200a28020c118280808000000f0b02402000280204220920064b0d00410121012000280214220c2000280218220a20082002200310dc808080000d01200c20042005200a28020c118280808000000f0b02402007410871450d002000280210210b2000413036021020002d0020210741012101200041013a00202000280214220c2000280218220a20082002200310dc808080000d01200920066b41016a2101024003402001417f6a2201450d01200c4130200a28021011838080800000450d000b41010f0b41012101200c20042005200a28020c118280808000000d01200020073a00202000200b360210410021010c010b200920066b210602400240024020002d002022010e0402000100020b20062101410021060c010b20064101762101200641016a41017621060b200141016a2101200041186a280200210c200028021021092000280214210a024003402001417f6a2201450d01200a2009200c28021011838080800000450d000b41010f0b41012101200a200c20082002200310dc808080000d00200a20042005200c28020c118280808000000d00410021010340024020062001470d0020062006490f0b200141016a2101200a2009200c28021011838080800000450d000b2001417f6a2006490f0b20010b4a01017f0240024002402002418080c400460d0041012105200020022001280210118380808000000d010b20030d01410021050b20050f0b200020032004200128020c118280808000000bd20701087f0240200028020022032000280208220472450d0002402004450d00200120026a21052000410c6a28020041016a2106410021072001210802400340200821042006417f6a2206450d0120042005460d020240024020042c00002209417f4c0d00200441016a2108200941ff017121090c010b20042d0001413f71210a2009411f71210802402009415f4b0d002008410674200a722109200441026a21080c010b200a41067420042d0002413f7172210a0240200941704f0d00200a2008410c74722109200441036a21080c010b200a41067420042d0003413f71722008411274418080f00071722209418080c400460d03200441046a21080b200720046b20086a21072009418080c400470d000c020b0b20042005460d00024020042c00002208417f4a0d0020084160490d0020084170490d0020042d0002413f7141067420042d0001413f71410c747220042d0003413f7172200841ff0171411274418080f0007172418080c400460d010b024002402007450d00024020072002490d004100210420072002460d010c020b41002104200120076a2c00004140480d010b200121040b2007200220041b21022004200120041b21010b024020030d00200028021420012002200041186a28020028020c118280808000000f0b200028020421050240024020024110490d002001200210fd8080800021040c010b024020020d00410021040c010b2002410371210602400240200241044f0d0041002104410021090c010b2002417c712107410021044100210903402004200120096a22082c000041bf7f4a6a200841016a2c000041bf7f4a6a200841026a2c000041bf7f4a6a200841036a2c000041bf7f4a6a21042007200941046a2209470d000b0b2006450d00200120096a21080340200420082c000041bf7f4a6a2104200841016a21082006417f6a22060d000b0b02400240200520044d0d00200520046b21074100210402400240024020002d00200e0402000102020b20072104410021070c010b20074101762104200741016a41017621070b200441016a2104200041186a2802002108200028021021062000280214210903402004417f6a2204450d0220092006200828021011838080800000450d000b41010f0b200028021420012002200041186a28020028020c118280808000000f0b410121040240200920012002200828020c118280808000000d004100210402400340024020072004470d00200721040c020b200441016a210420092006200828021011838080800000450d000b2004417f6a21040b200420074921040b20040f0b200028021420012002200041186a28020028020c118280808000000b9d05010a7f23808080800041106b2202248080808000024002400240024002402000280200450d00200028020421032002410c6a2001410c6a280200220436020020022001280208220536020820022001280204220636020420022001280200220136020020002d002021072000280210210820002d001c4108710d0120062101200821092007210a0c020b20002802142000280218200110df8080800021050c030b200028021420012006200041186a28020028020c118280808000000d014101210a200041013a002041302109200041303602104100210120024100360204200241e88fc080003602004100200320066b2206200620034b1b21030b02402004450d002004410c6c21040340024002400240024020052f01000e03000201000b200541046a28020021060c020b200541086a28020021060c010b0240200541026a2f0100220b41e807490d0041044105200b4190ce00491b21060c010b41012106200b410a490d0041024103200b41e400491b21060b2005410c6a2105200620016a2101200441746a22040d000b0b024002400240200320014d0d00200320016b2104024002400240200a41ff017122050e0402000100020b20042105410021040c010b20044101762105200441016a41017621040b200541016a2105200041186a28020021012000280214210603402005417f6a2205450d0220062009200128021011838080800000450d000c040b0b20002802142000280218200210df8080800021050c010b20062001200210df808080000d014100210502400340024020042005470d00200421050c020b200541016a210520062009200128021011838080800000450d000b2005417f6a21050b200520044921050b200020073a0020200020083602100c010b410121050b200241106a24808080800020050b9f0501087f23808080800041106b22032480808080000240024020022802042204450d0041012105200020022802002004200128020c118280808000000d010b02402002410c6a2802002205450d00200228020822062005410c6c6a2107200341086a41046a21080340024002400240024020062f01000e03000201000b024002402006280204220241c100490d002001410c6a280200210503400240200041d890c0800041c000200511828080800000450d00410121050c090b200241406a220241c0004b0d000c020b0b2002450d032001410c6a28020021050b200041d890c080002002200511828080800000450d02410121050c050b20002006280204200641086a2802002001410c6a28020011828080800000450d01410121050c040b20062f01022102200841003a00002003410036020802400240024002400240024020062f01000e03020100020b200641086a21050c020b024020062f0102220541e807490d004104410520054190ce00491b21090c030b410121092005410a490d0241024103200541e400491b21090c020b200641046a21050b02402005280200220941064f0d0020090d01410021090c020b20094105419891c08000109581808000000b200341086a20096a21040240024020094101710d00200221050c010b2004417f6a22042002200241ffff0371410a6e2205410a6c6b4130723a00000b20094101460d002004417e6a210203402002200541ffff03712204410a6e220a410a704130723a0000200241016a2005200a410a6c6b4130723a0000200441e4006e21052002200341086a4621042002417e6a21022004450d000b0b2000200341086a20092001410c6a28020011828080800000450d00410121050c030b2006410c6a22062007470d000b0b410021050b200341106a24808080800020050b820201017f23808080800041106b220f248080808000200028021420012002200041186a28020028020c118280808000002102200f41003a000d200f20023a000c200f2000360208200f41086a2003200420052006108c81808000200720082009200a108c81808000200b200c200d200e108c818080002101200f2d000c210202400240200f2d000d0d00200241ff017141004721000c010b41012100200241ff01710d000240200128020022002d001c4104710d0020002802144187a5c080004102200028021828020c1182808080000021000c010b20002802144186a5c080004101200028021828020c1182808080000021000b200f41106a24808080800020000b2d00024020002d00000d00200141a891c08000410510dd808080000f0b200141ad91c08000410410dd808080000bd107030d7f017e017f23808080800041206b22032480808080004101210402400240200228021422054122200241186a28020022062802102207118380808000000d000240024020010d0041002102410021010c010b200020016a210841002102200021094100210a024002400340024002402009220b2c0000220c417f4c0d00200b41016a2109200c41ff0171210d0c010b200b2d0001413f71210e200c411f71210f0240200c415f4b0d00200f410674200e72210d200b41026a21090c010b200e410674200b2d0002413f7172210e200b41036a21090240200c41704f0d00200e200f410c7472210d0c010b200e41067420092d0000413f7172200f411274418080f0007172220d418080c400460d03200b41046a21090b200341046a200d4181800410d7808080000240024020032d0004418001460d0020032d000f20032d000e6b41ff01714101460d00200a2002490d0302402002450d00024020022001490d0020022001460d010c050b200020026a2c00004140480d040b0240200a450d000240200a2001490d00200a2001460d010c050b2000200a6a2c000041bf7f4c0d040b024002402005200020026a200a20026b200628020c118280808000000d00200341106a41086a220f200341046a41086a28020036020020032003290204221037031002402010a741ff0171418001470d00418001210e034002400240200e41ff0171418001460d0020032d001a220c20032d001b4f0d052003200c41016a3a001a200c410a4f0d07200341106a200c6a2d000021020c010b4100210e200f410036020020032802142102200342003703100b20052002200711838080800000450d000c020b0b20032d001a2202410a2002410a4b1b210c20032d001b220e2002200e20024b1b2111034020112002460d022003200241016a220e3a001a200c2002460d04200341106a20026a210f200e21022005200f2d0000200711838080800000450d000b0b410121040c070b410121020240200d418001490d0041022102200d418010490d0041034104200d41808004491b21020b2002200a6a21020b200a200b6b20096a210a20092008470d010c030b0b200c410a41a4bec0800010f980808000000b200020012002200a41c491c08000109781808000000b024020020d00410021020c010b0240200120024b0d0020012002470d03200120026b210c20012102200c21010c010b200020026a2c000041bf7f4c0d02200120026b21010b2005200020026a2001200628020c118280808000000d002005412220071183808080000021040b200341206a24808080800020040f0b200020012002200141b491c08000109781808000000be40201077f23808080800041106b22022480808080004101210302400240200128021422044127200141186a2802002802102205118380808000000d002002200028020041810210d7808080000240024020022d0000418001470d00200241086a21064180012107034002400240200741ff0171418001460d0020022d000a220020022d000b4f0d042002200041016a3a000a2000410a4f0d06200220006a2d000021010c010b410021072006410036020020022802042101200242003703000b20042001200511838080800000450d000c030b0b20022d000a2201410a2001410a4b1b210020022d000b22072001200720014b1b2108034020082001460d012002200141016a22073a000a20002001460d03200220016a210620072101200420062d0000200511838080800000450d000c020b0b2004412720051183808080000021030b200241106a24808080800020030f0b2000410a41a4bec0800010f980808000000bbb0201017f23808080800041106b220224808080800020002802002100024002402001280200200128020872450d002002410036020c02400240024002402000418001490d002000418010490d012000418080044f0d0220022000413f71418001723a000e20022000410c7641e001723a000c20022000410676413f71418001723a000d410321000c030b200220003a000c410121000c020b20022000413f71418001723a000d2002200041067641c001723a000c410221000c010b20022000413f71418001723a000f2002200041127641f001723a000c20022000410676413f71418001723a000e20022000410c76413f71418001723a000d410421000b20012002410c6a200010dd8080800021010c010b20012802142000200141186a2802002802101183808080000021010b200241106a24808080800020010b180020002802002001200028020428020c118380808000000bf80202027f017e2380808080004180016b22022480808080002000280200210002400240024002400240200128021c22034110710d0020034120710d0120002903004101200110fe8080800021000c020b20002903002104410021000340200220006a41ff006a413041d7002004a7410f712203410a491b20036a3a00002000417f6a210020044210542103200442048821042003450d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000c010b20002903002104410021000340200220006a41ff006a413041372004a7410f712203410a491b20036a3a00002000417f6a210020044210542103200442048821042003450d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000b20024180016a24808080800020000f0b200341800141c88dc08000109481808000000b200341800141c88dc08000109481808000000b140020012000280200200028020410dd808080000b2000200042d7e8a9deef8fddde6a370308200042f0c6e287c69783ad393703000bb30301057f23808080800041c0006b22022480808080004101210302402001280214220441d491c08000410c200141186a280200220528020c2206118280808000000d00200028020c2101200241106a410c6a42033702002002413c6a418580808000360200200241286a410c6a41858080800036020020024103360214200241f49fc0800036021020022001410c6a3602382002200141086a360230200241a28080800036022c200220013602282002200241286a36021820042005200241106a10d9808080000d000240024020002802082201450d00200441e091c0800041022006118280808000000d02200241286a41106a200141106a290200370300200241286a41086a200141086a2902003703002002200129020037032820042005200241286a10d9808080000d020c010b2002200028020022012000280204410c6a28020011848080800000200229030042c1f7f9e8cc93b2d14185200241086a29030042e4dec78590d085de7d858450450d00200441e091c0800041022006118280808000000d012004200128020020012802042006118280808000000d010b410021030b200241c0006a24808080800020030b8a0401077f0240024002400240200141800a4f0d00200141057621020240024020002802a0012203450d00200341284b0d032002417f6a2104200341027420006a417c6a2105200320026a41027420006a417c6a21060340200420036a41274b0d02200620052802003602002006417c6a21062005417c6a21052003417f6a22030d000b0b2001411f712104024020014120490d002000410020024101200241014b1b410274108a8e8080001a0b20002802a00120026a2105024020040d00200020053602a00120000f0b2005417f6a220341274b0d0320052107200020034102746a2802002206410020016b2208762203450d040240200541274b0d00200020054102746a2003360200200541016a21070c050b2005412841d892c0800010f980808000000b200220036a417f6a412841d892c0800010f980808000000b418293c08000411d41d892c0800010f880808000000b2003417f6a412841d892c0800010f980808000000b2003412841d892c0800010f980808000000b02400240200241016a220120054f0d002008411f712108200541027420006a41786a210303402005417e6a41284f0d02200341046a200620047420032802002206200876723602002003417c6a210320012005417f6a2205490d000b0b200020024102746a22032003280200200474360200200020073602a00120000f0b417f412841d892c0800010f980808000000bb806030b7f027e017f23808080800041a0016b22032480808080002003410041a001108a8e80800021040240024002400240024020002802a00122052002490d00200541294f0d01200120024102746a21060240024002402005450d00200541016a21072005410274210241002108410021090340200420084102746a210a03402008210b200a210320012006460d09200341046a210a200b41016a21082001280200210c200141046a220d2101200c450d000b200cad210e4200210f2002210c200b21012000210a0340200141284f0d042003200f20033502007c200a350200200e7e7c220f3e0200200f422088210f200341046a2103200141016a2101200a41046a210a200c417c6a220c0d000b200521030240200fa72201450d00200b20056a220341284f0d03200420034102746a2001360200200721030b20092003200b6a2203200920034b1b2109200d21010c000b0b4100210941002103034020012006460d07200341016a21032001280200210a200141046a22082101200a450d0020092003417f6a2201200920014b1b2109200821010c000b0b2003412841d892c0800010f980808000000b2001412841d892c0800010f980808000000b200541294f0d0120024102742107200241016a2110200020054102746a210d4100210b2000210a4100210903402004200b4102746a21080340200b210c20082103200a200d460d05200341046a2108200c41016a210b200a2802002106200a41046a2205210a2006450d000b2006ad210e4200210f20072106200c210a2001210802400340200a41284f0d012003200f20033502007c2008350200200e7e7c220f3e0200200f422088210f200341046a2103200a41016a210a200841046a21082006417c6a22060d000b200221030240200fa7220a450d00200c20026a220341284f0d05200420034102746a200a360200201021030b20092003200c6a2203200920034b1b21092005210a0c010b0b200a412841d892c0800010f980808000000b2005412841d892c08000109581808000000b2005412841d892c08000109581808000000b2003412841d892c0800010f980808000000b2000200441a00110848e808000220320093602a001200441a0016a24808080800020030bc203000240024002402002450d0020012d000041304d0d01200641034d0d02200541023b01000240024002400240200341107441107522064101480d0020052001360204200341ffff0371220320024f0d01200541023b0118200541023b010c20052003360208200541206a200220036b22023602002005411c6a200120036a360200200541146a4101360200200541106a41c895c0800036020041032101200420024d0d03200420026b21040c020b200541023b0118200541003b010c20054102360208200541c995c08000360204200541206a20023602002005411c6a2001360200200541106a410020066b220336020041032101200420024d0d02200420026b220220034d0d02200220066a21040c010b200541003b010c20052002360208200541106a200320026b360200024020040d00410221010c020b200541023b0118200541206a41013602002005411c6a41c895c080003602000b200541003b0124200541286a2004360200410421010b20002001360204200020053602000f0b41b294c08000412141d494c0800010f880808000000b41e494c08000411f418495c0800010f880808000000b419495c08000412241b895c0800010f880808000000b970809017f017e017f017e017f037e027f017e017f23808080800041f0086b22042480808080002001bd21050240024020012001610d00410221060c010b200542ffffffffffffff0783220742808080808080800884200542018642feffffffffffff0f832005423488a741ff0f7122081b2209420183210a4103210602400240024041014102410420054280808080808080f8ff0083220b50220c1b200b4280808080808080f8ff00511b41034104200c1b2007501b417f6a0e0403000102030b410421060c020b200841cd776a210d200a5021064201210e0c010b428080808080808020200942018620094280808080808080085122061b21094202420120061b210e41cb7741cc7720061b20086a210d200a5021060b2004200d3b01e8082004200e3703e008200442013703d808200420093703d008200420063a00ea080240024002400240024002402006417e6a41ff01712206410320064103491b2208450d0041f095c0800041ef95c0800020021b41ef95c080002005423f87a7220f417f4a1b210c410121064101200f4180017141077620021b21022008417f6a0e03010203010b2004410336029808200441f195c0800036029408200441023b0190084101210620044190086a210d4100210241ef95c08000210c0c040b2004410336029808200441f495c0800036029408200441023b01900820044190086a210d0c030b41022106200441023b0190082003450d01200441a0086a2003360200200441003b019c082004410236029808200441c995c080003602940820044190086a210d0c020b024041744105200d41107441107522064100481b20066c220641c0fd004f0d0020044190086a200441d0086a200441106a200641047641156a220d410020036b4180807e200341808002491b2206109e8180800020064110744110752106024002402004280290080d00200441c0086a200441d0086a200441106a200d20061092818080000c010b200441c0086a41086a20044190086a41086a28020036020020042004290290083703c0080b024020042e01c808220d20064c0d00200441086a20042802c00820042802c408200d200320044190086a410410ec80808000200428020c21062004280208210d0c030b41022106200441023b019008024020030d00410121062004410136029808200441f795c080003602940820044190086a210d0c030b200441a0086a2003360200200441003b019c082004410236029808200441c995c080003602940820044190086a210d0c020b41fb95c08000412541a096c0800010f880808000000b410121062004410136029808200441f795c080003602940820044190086a210d0b200441cc086a20063602002004200d3602c808200420023602c4082004200c3602c0082000200441c0086a10de808080002106200441f0086a24808080800020060bac0608017f017e017f017e017f037e027f017e2380808080004180016b22042480808080002001bd21050240024020012001610d00410221060c010b200542ffffffffffffff0783220742808080808080800884200542018642feffffffffffff0f832005423488a741ff0f7122081b2209420183210a4103210602400240024041014102410420054280808080808080f8ff0083220b50220c1b200b4280808080808080f8ff00511b41034104200c1b2007501b417f6a0e0403000102030b410421060c020b200841cd776a210d200a5021064201210e0c010b428080808080808020200942018620094280808080808080085122061b21094202420120061b210e41cb7741cc7720061b20086a210d200a5021060b2004200d3b01782004200e3703702004420137036820042009370360200420063a007a02400240024002402006417e6a41ff01712206410320064103491b220c450d0041f095c0800041ef95c080002005423f87a72208417f4a22061b41ef95c0800041ef95c0800020061b20021b210d41012106410120084180017141077620021b21020240200c417f6a0e03020300020b200441206a200441e0006a2004410f6a4111109d818080000240024020042802200d00200441d0006a200441e0006a2004410f6a41111091818080000c010b200441d0006a41086a200441206a41086a280200360200200420042902203703500b20042004280250200428025420042f01582003200441206a410410ec80808000200428020421062004280200210c0c030b20044103360228200441f195c08000360224200441023b012041012106200441206a210c4100210241ef95c08000210d0c020b20044103360228200441f495c08000360224200441023b0120200441206a210c0c010b41022106200441023b012002402003450d00200441306a4101360200200441003b012c20044102360228200441c995c08000360224200441206a210c0c010b4101210620044101360228200441f795c08000360224200441206a210c0b200441dc006a20063602002004200c360258200420023602542004200d3602502000200441d0006a10de80808000210620044180016a24808080800020060bf10709017f017e017f017e017f037e027f017e017f2380808080004190016b22032480808080002001bd21040240024020012001610d00410221050c010b200442ffffffffffffff0783220642808080808080800884200442018642feffffffffffff0f832004423488a741ff0f7122071b220842018321094103210502400240024041014102410420044280808080808080f8ff0083220a50220b1b200a4280808080808080f8ff00511b41034104200b1b2006501b417f6a0e0403000102030b410421050c020b200741cd776a210c20095021054201210d0c010b428080808080808020200842018620084280808080808080085122051b21084202420120051b210d41cb7741cc7720051b20076a210c20095021050b2003200c3b0188012003200d370380012003420137037820032008370370200320053a008a01024002400240024002400240024002402005417e6a41ff01712205410320054103491b220b450d0041f095c0800041ef95c0800020021b41ef95c080002004423f87a72207417f4a1b210c41012105410120074180017141077620021b21020240200b417f6a0e03020300020b200341186a200341f0006a200341076a4111109d818080000240024020032802180d00200341e0006a200341f0006a200341076a41111091818080000c010b200341e0006a41086a200341186a41086a280200360200200320032902183703600b20032802642207450d032003280260220e2d000041304d0d0420032e0168210b200341013602202003200e36021c200341023b011841012105200741014b0d050c060b20034103360220200341f195c0800036021c200341023b0118410121054100210241ef95c08000210c0c060b20034103360220200341f495c0800036021c200341023b01180c050b20034103360220200341f895c0800036021c200341023b01180c040b41b294c08000412141cc95c0800010f880808000000b41e494c08000411f41dc95c0800010f880808000000b200341386a2007417f6a360200200341346a200e41016a3602002003412c6a4101360200200341286a41c895c08000360200200341023b0130200341023b0124410321050b02400240200b4101480d00200341186a2005410c6c6a22074101360208200741ec95c08000360204200741023b0100200b417f6a21070c010b200341186a2005410c6c6a22074102360208200741ed95c08000360204200741023b01004101200b6b21070b2005410c6c200341186a6a220b410e6a20073b0100200b410c6a41013b0100200541026a21050b200341ec006a2005360200200320023602642003200c3602602003200341186a3602682000200341e0006a10de80808000210520034190016a24808080800020050b950103017f017e027c200128021c410171210202402001280208450d00200120002b030020022001410c6a28020010ed808080000f0b20002903002203bf21040240200342ffffffffffffffffff0083bf2205440080e03779c34143660d002005440000000000000000622005442d431cebe2361a3f63710d00200120042002410110ee808080000f0b20012004200210ef808080000b4502017f017c200128021c410171210220002b0300210302402001280208450d002001200320022001410c6a28020010ed808080000f0b200120032002410010ee808080000bb00c03097f017e017f024020040d002000200336023820002001360230200041003a000e20004181023b010c20002002360208200042003703002000413c6a4100360200200041346a20023602000f0b41012105410021060240024002400240024002400240024002400240024020044101470d0041002107410121080c010b41012109410121054100210a4101210b410021060340200b210c2006200a6a220b20044f0d0202400240200320096a2d000041ff017122092003200b6a2d0000220b4f0d00200c20066a41016a220b200a6b2105410021060c010b02402009200b460d0041012105200c41016a210b41002106200c210a0c010b4100200641016a220b200b20054622091b2106200b410020091b200c6a210b0b200b20066a22092004490d000b4101210941012108410021074101210b410021060340200b210c200620076a220b20044f0d0302400240200320096a2d000041ff017122092003200b6a2d0000220b4d0d00200c20066a41016a220b20076b2108410021060c010b02402009200b460d0041012108200c41016a210b41002106200c21070c010b4100200641016a220b200b20084622091b2106200b410020091b200c6a210b0b200b20066a22092004490d000b200a21060b200420062007200620074b220b1b220d490d0220052008200b1b220b200d6a2206200b490d03200620044b0d040240024020032003200b6a200d10888e808000450d002004410371210c024002402004417f6a41034f0d004100210b4200210e0c010b2004417c7121094100210b4200210e034042012003200b6a220641036a310000864201200641026a310000864201200641016a310000864201200631000086200e84848484210e2009200b41046a220b470d000b0b2004200d6b21090240200c450d002003200b6a210603404201200631000086200e84210e200641016a2106200c417f6a220c0d000b0b200d2009200d20094b1b41016a210b417f210a200d2105417f21060c010b41012107410021064101210941002105024003402009220c20066a220820044f0d01200420066b200c417f736a220920044f0d082006417f7320046a20056b220a20044f0d0902400240200320096a2d000041ff017122092003200a6a2d0000220a4f0d00200841016a220920056b2107410021060c010b02402009200a460d00200c41016a21094100210641012107200c21050c010b4100200641016a22092009200746220a1b210620094100200a1b200c6a21090b2007200b470d000b0b41012107410021064101210941002108024003402009220c20066a220f20044f0d01200420066b200c417f736a220920044f0d0a2006417f7320046a20086b220a20044f0d0b02400240200320096a2d000041ff017122092003200a6a2d0000220a4d0d00200f41016a220920086b2107410021060c010b02402009200a460d00200c41016a21094100210641012107200c21080c010b4100200641016a22092009200746220a1b210620094100200a1b200c6a21090b2007200b470d000b0b200420052008200520084b1b6b210502400240200b0d004200210e4100210b4100210a0c010b200b41037121094100210a02400240200b41044f0d004200210e4100210c0c010b200b417c7121074100210c4200210e034042012003200c6a220641036a310000864201200641026a310000864201200641016a310000864201200631000086200e84848484210e2007200c41046a220c470d000b0b2009450d002003200c6a210603404201200631000086200e84210e200641016a21062009417f6a22090d000b0b200421060b2000200336023820002001360230200020063602282000200a360224200020023602202000410036021c2000200b360218200020053602142000200d3602102000200e370308200041013602002000413c6a2004360200200041346a20023602000f0b200b200441c497c0800010f980808000000b200b200441c497c0800010f980808000000b200d200441a497c08000109581808000000b200b200641b497c08000109681808000000b2006200441b497c08000109581808000000b2009200441d497c0800010f980808000000b200a200441e497c0800010f980808000000b2009200441d497c0800010f980808000000b200a200441e497c0800010f980808000000bf00201057f2000410b742101410021024121210341212104024002400340200341017620026a2203410274419499c080006a280200410b7422052001460d0120032004200520014b1b2204200341016a200220052001491b22026b2103200420024b0d000c020b0b200341016a21020b0240024002400240200241204b0d0020024102742203419499c080006a280200411576210120024120470d01411f210241d70521050c020b2002412141f498c0800010f980808000000b2003419899c080006a2802004115762105024020020d00410021020c020b2002417f6a21020b2002410274419499c080006a28020041ffffff007121020b0240024020052001417f736a450d00200020026b2104200141d705200141d7054b1b21032005417f6a210541002102034020032001460d022002200141989ac080006a2d00006a220220044b0d012005200141016a2201470d000b200521010b20014101710f0b200341d705418499c0800010f980808000000b02000b02000b4c01017f23808080800041206b2202248080808000200241013b011c20022001360218200220003602142002418ca0c08000360210200241f09fc0800036020c2002410c6a109384808000000b7d01017f23808080800041306b2203248080808000200341106a200041106a290200370300200341086a200041086a29020037030020032000290200370300200320013a002d200341003a002c200320023602282003418ca0c08000360220200341f09fc0800036021c200320033602242003411c6a109384808000000b5401017f23808080800041206b22032480808080002003410c6a420037020020034101360204200341f09fc080003602082003200136021c200320003602182003200341186a3602002003200210f680808000000b870101017f23808080800041306b22032480808080002003200136020420032000360200200341086a410c6a4202370200200341206a410c6a4185808080003602002003410236020c200341d0a0c0800036020820034185808080003602242003200341206a360210200320033602282003200341046a360220200341086a200210f680808000000b4601017f23808080800041106b22052480808080002005200236020c200520013602082000200541086a41e0a0c080002005410c6a41e0a0c080002003200410fb80808000000bd90301017f23808080800041f0006b22072480808080002007200236020c2007200136020820072004360214200720033602100240024002400240200041ff01710e03000102000b200741f0a0c08000360218410221020c020b200741f2a0c08000360218410221020c010b200741f4a0c08000360218410721020b2007200236021c024020052802000d00200741cc006a41a380808000360200200741386a410c6a41a380808000360200200741d8006a410c6a42033702002007410336025c200741aca1c08000360258200741a28080800036023c2007200741386a3602602007200741106a3602482007200741086a3602402007200741186a360238200741d8006a200610f680808000000b200741206a41106a200541106a290200370300200741206a41086a200541086a29020037030020072005290200370320200741d8006a410c6a4204370200200741d4006a41a380808000360200200741cc006a41a380808000360200200741386a410c6a41a4808080003602002007410436025c200741e0a1c08000360258200741a28080800036023c2007200741386a3602602007200741106a3602502007200741086a3602482007200741206a3602402007200741186a360238200741d8006a200610f680808000000bf90503057f027e017f02402002450d004100200241796a2203200320024b1b2104200141036a417c7120016b21054100210303400240024002400240200120036a2d0000220641187441187522074100480d00200520036b4103710d01200320044f0d020340200120036a220641046a280200200628020072418081828478710d03200341086a22032004490d000c030b0b428080808080202108428080808010210902400240024002400240024002400240024002400240024020064180a2c080006a2d0000417e6a0e030001020a0b200341016a22062002490d0242002108420021090c090b42002108200341016a220a2002490d02420021090c080b42002108200341016a220a2002490d02420021090c070b4280808080802021084280808080102109200120066a2c000041bf7f4a0d060c070b2001200a6a2c0000210a024002400240200641a07e6a0e0e0002020202020202020202020201020b200a41607141a07f460d040c030b200a419f7f4a0d020c030b02402007411f6a41ff0171410c490d002007417e71416e470d02200a4140480d030c020b200a4140480d020c010b2001200a6a2c0000210a0240024002400240200641907e6a0e050100000002000b2007410f6a41ff017141024b0d03200a41404e0d030c020b200a41f0006a41ff017141304f0d020c010b200a418f7f4a0d010b0240200341026a22062002490d00420021090c050b200120066a2c000041bf7f4a0d0242002109200341036a220620024f0d04200120066a2c000041bf7f4c0d05428080808080e00021080c030b4280808080802021080c020b42002109200341026a220620024f0d02200120066a2c000041bf7f4c0d030b428080808080c00021080b42808080801021090b200020082003ad84200984370204200041013602000f0b200641016a21030c020b200341016a21030c010b200320024f0d000340200120036a2c00004100480d012002200341016a2203470d000c030b0b20032002490d000b0b20002001360204200041086a2002360200200041003602000b800701097f024002402001200041036a417c71220220006b2203490d00200120036b22044104490d002004410371210541002106410021010240200220004622070d00410021010240024020022000417f736a41034f0d00410021080c010b4100210803402001200020086a22092c000041bf7f4a6a200941016a2c000041bf7f4a6a200941026a2c000041bf7f4a6a200941036a2c000041bf7f4a6a2101200841046a22080d000b0b20070d00200020026b2102200020086a21090340200120092c000041bf7f4a6a2101200941016a2109200241016a22020d000b0b200020036a210802402005450d0020082004417c716a22092c000041bf7f4a210620054101460d00200620092c000141bf7f4a6a210620054102460d00200620092c000241bf7f4a6a21060b20044102762103200620016a21020340200821062003450d02200341c001200341c001491b220441037121052004410274210702400240200441fc0171220a0d00410021090c010b2006200a4102746a21004100210920062101034020012802002208417f7341077620084106767241818284087120096a200141046a2802002209417f734107762009410676724181828408716a200141086a2802002209417f734107762009410676724181828408716a2001410c6a2802002209417f734107762009410676724181828408716a2109200141106a22012000470d000b0b200320046b2103200620076a2108200941087641ff81fc0771200941ff81fc07716a418180046c41107620026a21022005450d000b2006200a4102746a22092802002201417f734107762001410676724181828408712101024020054101460d0020092802042208417f7341077620084106767241818284087120016a210120054102460d0020092802082209417f7341077620094106767241818284087120016a21010b200141087641ff811c71200141ff81fc07716a418180046c41107620026a21020c010b024020010d0041000f0b2001410371210802400240200141044f0d0041002102410021090c010b2001417c712103410021024100210903402002200020096a22012c000041bf7f4a6a200141016a2c000041bf7f4a6a200141026a2c000041bf7f4a6a200141036a2c000041bf7f4a6a21022003200941046a2209470d000b0b2008450d00200020096a21010340200220012c000041bf7f4a6a2102200141016a21012008417f6a22080d000b0b20020be90203027f017e037f23808080800041306b2203248080808000412721040240024020004290ce005a0d00200021050c010b412721040340200341096a20046a2206417c6a200020004290ce008022054290ce007e7da7220741ffff037141e4006e220841017441da8dc080006a2f00003b00002006417e6a2007200841e4006c6b41ffff037141017441da8dc080006a2f00003b00002004417c6a2104200042ffc1d72f5621062005210020060d000b0b02402005a7220641e3004d0d00200341096a2004417e6a22046a2005a72206200641ffff037141e4006e220641e4006c6b41ffff037141017441da8dc080006a2f00003b00000b024002402006410a490d00200341096a2004417e6a22046a200641017441da8dc080006a2f00003b00000c010b200341096a2004417f6a22046a200641306a3a00000b200220014180a4c080004100200341096a20046a412720046b10db808080002104200341306a24808080800020040b110020003100004101200110fe808080000b110020003502004101200110fe808080000b2301027e200029030022022002423f8722038520037d2002427f55200110fe808080000b110020002903004101200110fe808080000b02000b850601047f2380808080004180016b22022480808080000240024002400240024002400240200128021c22034110710d00024020034120710d004101210320003502004101200110fe80808000450d020c030b20002802002103410021040340200220046a41ff006a413041372003410f712205410a491b20056a3a00002004417f6a210420034110492105200341047621032005450d000b20044180016a22034180014b0d03410121032001410141c48dc080004102200220046a4180016a410020046b10db80808000450d010c020b20002802002103410021040340200220046a41ff006a413041d7002003410f712205410a491b20056a3a00002004417f6a210420034110492105200341047621032005450d000b20044180016a22034180014b0d03410121032001410141c48dc080004102200220046a4180016a410020046b10db808080000d010b2002410c6a4200370200410121032002410136020420024184a4c0800036020020024180a4c080003602082001280214200141186a280200200210d9808080000d0002400240200128021c22034110710d0020034120710d0120003502044101200110fe8080800021030c020b20002802042103410021040340200220046a41ff006a413041d7002003410f712205410a491b20056a3a00002004417f6a210420034110492105200341047621032005450d000b20044180016a22034180014b0d042001410141c48dc080004102200220046a4180016a410020046b10db8080800021030c010b20002802042103410021040340200220046a41ff006a413041372003410f712205410a491b20056a3a00002004417f6a210420034110492105200341047621032005450d000b20044180016a22034180014b0d042001410141c48dc080004102200220046a4180016a410020046b10db8080800021030b20024180016a24808080800020030f0b200341800141c88dc08000109481808000000b200341800141c88dc08000109481808000000b200341800141c88dc08000109481808000000b200341800141c88dc08000109481808000000b21002001280214418ca4c08000410b200141186a28020028020c118280808000000b210020012802144197a4c08000410e200141186a28020028020c118280808000000b5e01017f23808080800041306b2201248080808000200141186a420137020020014101360210200141b8a4c0800036020c200141a9808080003602282001200141246a36021420012001412f6a3602242001410c6a200010f680808000000b5e01017f23808080800041306b2201248080808000200141186a420137020020014101360210200141dca4c0800036020c200141aa808080003602282001200141246a36021420012001412f6a3602242001410c6a200010f680808000000b990101017f23808080800041c0006b22052480808080002005200136020c200520003602082005200336021420052002360210200541186a410c6a4202370200200541306a410c6a41a3808080003602002005410236021c200541e8a4c08000360218200541a2808080003602342005200541306a3602202005200541106a3602382005200541086a360230200541186a200410f680808000000bc404010b7f2000280204210320002802002104200028020821054100210641002107410021084100210902400340200941ff01710d0102400240200820024b0d000340200120086a210a02400240024002400240200220086b220b4108490d00200a41036a417c712200200a460d012000200a6b2200450d014100210c0340200a200c6a2d0000410a460d052000200c41016a220c470d000b2000200b41786a220d4b0d030c020b024020022008470d00200221080c060b4100210c0340200a200c6a2d0000410a460d04200b200c41016a220c470d000b200221080c050b200b41786a210d410021000b0340200a20006a220c41046a2802002209418a94a8d0007341fffdfb776a2009417f7371200c280200220c418a94a8d0007341fffdfb776a200c417f737172418081828478710d01200041086a2200200d4d0d000b0b02402000200b470d00200221080c030b03400240200a20006a2d0000410a470d002000210c0c020b200b200041016a2200470d000b200221080c020b200c20086a220041016a21080240200020024f0d00200120006a2d0000410a470d00410021092008210d200821000c030b200820024d0d000b0b410121092007210d2002210020072002460d020b0240024020052d0000450d00200441f8a4c080004104200328020c118280808000000d010b200120076a210c200020076b210a4100210b024020002007460d00200a200c6a417f6a2d0000410a46210b0b2005200b3a0000200d21072004200c200a200328020c11828080800000450d010b0b410121060b20060b5801027f20002802042102200028020021030240200028020822002d0000450d00200341f8a4c080004104200228020c11828080800000450d0041010f0b20002001410a463a0000200320012002280210118380808000000be40302057f017e23808080800041c0006b220524808080800041012106024020002d00040d0020002d0005210702402000280200220828021c22094104710d0041012106200828021441ffa4c0800041fca4c08000200741ff017122071b4102410320071b200841186a28020028020c118280808000000d0141012106200828021420012002200828021828020c118280808000000d0141012106200828021441e4a4c080004102200828021828020c118280808000000d0120032008200428020c1183808080000021060c010b0240200741ff01710d004101210620082802144181a5c080004103200841186a28020028020c118280808000000d01200828021c21090b41012106200541013a001b200541346a41d08fc080003602002005200829021437020c20052005411b6a360214200520082902083702242008290200210a200520093602382005200828021036022c200520082d00203a003c2005200a37021c20052005410c6a3602302005410c6a20012002108a818080000d002005410c6a41e4a4c080004102108a818080000d0020032005411c6a200428020c118380808000000d0020052802304184a5c080004102200528023428020c1182808080000021060b200041013a0005200020063a0004200541c0006a24808080800020000bf70202057f017e23808080800041c0006b22032480808080002000280200210441012105024020002d00080d0002402000280204220628021c22074104710d0041012105200628021441ffa4c080004189a5c0800020041b4102410120041b200641186a28020028020c118280808000000d0120012006200228020c1183808080000021050c010b024020040d00410121052006280214418aa5c080004102200641186a28020028020c118280808000000d01200628021c21070b41012105200341013a001b200341346a41d08fc080003602002003200629021437020c20032003411b6a3602142003200629020837022420062902002108200320073602382003200628021036022c200320062d00203a003c2003200837021c20032003410c6a36023020012003411c6a200228020c118380808000000d0020032802304184a5c080004102200328023428020c1182808080000021050b200020053a00082000200441016a360200200341c0006a24808080800020000bf90202047f017e23808080800041c0006b220324808080800041012104024020002d00040d0020002d00052104024002402000280200220528021c22064104710d00200441ff0171450d0141012104200528021441ffa4c080004102200541186a28020028020c11828080800000450d010c020b0240200441ff01710d00410121042005280214418ea5c080004101200541186a28020028020c118280808000000d02200528021c21060b41012104200341013a001b200341346a41d08fc080003602002003200529021437020c20032003411b6a3602142003200529020837022420052902002107200320063602382003200528021036022c200320052d00203a003c2003200737021c20032003410c6a36023020012003411c6a200228020c118380808000000d0120032802304184a5c080004102200328023428020c1182808080000021040c010b20012005200228020c1183808080000021040b200041013a0005200020043a0004200341c0006a24808080800020000b120020004194a5c08000200110d9808080000ba00705027f017e027f017e017f024020014107712202450d000240024020002802a001220341294f0d00024020030d00200041003602a0010c030b200241027441aca5c080006a35020021042003417f6a41ffffffff0371220241016a220541037121060240200241034f0d0042002107200021020c020b200541fcffffff07712105420021072000210203402002200235020020047e20077c22073e0200200241046a2208200835020020047e20074220887c22073e0200200241086a2208200835020020047e20074220887c22073e02002002410c6a2208200835020020047e20074220887c22073e020020074220882107200241106a21022005417c6a22050d000c020b0b2003412841d892c08000109581808000000b02402006450d0003402002200235020020047e20077c22073e0200200241046a2102200742208821072006417f6a22060d000b0b024002402007a72202450d00200341274b0d01200020034102746a2002360200200341016a21030b200020033602a0010c010b4128412841d892c0800010f980808000000b024002402001410871450d0002400240024020002802a001220341294f0d00024020030d00410021030c030b2003417f6a41ffffffff0371220241016a220541037121060240200241034f0d0042002104200021020c020b200541fcffffff0771210542002104200021020340200220023502004280c2d72f7e20047c22043e0200200241046a220820083502004280c2d72f7e20044220887c22043e0200200241086a220820083502004280c2d72f7e20044220887c22043e02002002410c6a220820083502004280c2d72f7e20044220887c22043e020020044220882104200241106a21022005417c6a22050d000c020b0b2003412841d892c08000109581808000000b02402006450d000340200220023502004280c2d72f7e20047c22043e0200200241046a2102200442208821042006417f6a22060d000b0b2004a72202450d00200341274b0d02200020034102746a2002360200200341016a21030b200020033602a0010b02402001411071450d00200041fca5c08000410210eb808080001a0b02402001412071450d0020004184a6c08000410410eb808080001a0b0240200141c00071450d0020004194a6c08000410710eb808080001a0b0240200141800171450d00200041b0a6c08000410e10eb808080001a0b0240200141800271450d00200041e8a6c08000411b10eb808080001a0b20000f0b4128412841d892c0800010f980808000000bc53103017f047e1c7f23808080800041a00a6b2204248080808000024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240200129030022054200510d00200129030822064200510d01200129031022074200510d02200520077c22082005540d0320052006540d04200341104d0d0520012c001a210920012f01182101200420053e0200200441014102200542808080801054220a1b3602a001200441002005422088a7200a1b360204200441086a4100419801108a8e8080001a200420063e02a401200441014102200642808080801054220a1b3602c402200441002006422088a7200a1b3602a801200441a4016a41086a4100419801108a8e8080001a200420073e02c802200441014102200742808080801054220a1b3602e803200441002007422088a7200a1b3602cc02200441c8026a41086a4100419801108a8e8080001a200441f0036a4100419c01108a8e8080001a200441013602ec032004410136028c052001ad4230864230872008427f7c797d42c29ac1e8047e4280a1cda0b4027c422088a7220a411074411075210b024002402001411074411075220c4100480d002004200110ea808080001a200441a4016a200110ea808080001a200441c8026a200110ea808080001a0c010b200441ec036a4100200c6b41107441107510ea808080001a0b02400240200b417f4a0d0020044100200b6b41107441107522011090818080001a200441a4016a20011090818080001a200441c8026a20011090818080001a0c010b200441ec036a200a41ffff03711090818080001a0b20042802a001210d200441fc086a200441a00110848e8080001a2004200d36029c0a200d20042802e803220e200d200e4b1b220f41294f0d060240200f0d004100210f0c090b200f41017121100240200f4101470d0041002111410021120c080b200f417e71211341002111200441fc086a2101200441c8026a210a410021120340200120012802002214200a2802006a220c20114101716a2215360200200141046a221120112802002216200a41046a2802006a2211200c2014492015200c49726a220c3602002011201649200c201149722111200a41086a210a200141086a21012013201241026a2212470d000c080b0b41d8a8c08000411c41f4a8c0800010f880808000000b4184a9c08000411d41a4a9c0800010f880808000000b41b4a9c08000411c41d0a9c0800010f880808000000b4198abc08000413641d0abc0800010f880808000000b41d0aac0800041374188abc0800010f880808000000b41e0a9c08000412d4190aac0800010f880808000000b200f412841d892c08000109581808000000b02402010450d00200441fc086a201241027422016a220a200a280200220a200441c8026a20016a2802006a220120116a220c3602002001200a49200c2001497221110b2011410171450d00200f41274b0d01200441fc086a200f4102746a4101360200200f41016a210f0b2004200f36029c0a200428028c052212200f2012200f4b1b220141294f0d01200141027421010240024003402001450d01417f2001417c6a2201200441fc086a6a280200220a2001200441ec036a6a280200220c47200a200c4b1b220a450d000c020b0b417f410020011b210a0b0240200a2009480d000240200d0d004100210d0c050b200d417f6a41ffffffff0371220141016a220c410371210a0240200141034f0d0020042101420021050c040b200c41fcffffff0771210c2004210142002105034020012001350200420a7e20057c22053e0200200141046a22112011350200420a7e20054220887c22053e0200200141086a22112011350200420a7e20054220887c22053e02002001410c6a22112011350200420a7e20054220887c22053e020020054220882105200141106a2101200c417c6a220c0d000c040b0b200b41016a210b0c0b0b4128412841d892c0800010f980808000000b2001412841d892c08000109581808000000b0240200a450d00034020012001350200420a7e20057c22053e0200200141046a210120054220882105200a417f6a220a0d000b0b2005a72201450d00200d41274b0d012004200d4102746a2001360200200d41016a210d0b2004200d3602a00120042802c402221441294f0d0141002115410021012014450d032014417f6a41ffffffff0371220141016a220c410371210a0240200141034f0d00200441a4016a2101420021050c030b200c41fcffffff0771210c200441a4016a210142002105034020012001350200420a7e20057c22053e0200200141046a22112011350200420a7e20054220887c22053e0200200141086a22112011350200420a7e20054220887c22053e02002001410c6a22112011350200420a7e20054220887c22053e020020054220882105200141106a2101200c417c6a220c0d000c030b0b4128412841d892c0800010f980808000000b2014412841d892c08000109581808000000b0240200a450d00034020012001350200420a7e20057c22053e0200200141046a210120054220882105200a417f6a220a0d000b0b02402005a722010d00201421010c010b201441274b0d01200441a4016a20144102746a2001360200201441016a21010b200420013602c402200e450d02200e417f6a41ffffffff0371220141016a220c410371210a0240200141034f0d00200441c8026a2101420021050c020b200c41fcffffff0771210c200441c8026a210142002105034020012001350200420a7e20057c22053e0200200141046a22112011350200420a7e20054220887c22053e0200200141086a22112011350200420a7e20054220887c22053e02002001410c6a22112011350200420a7e20054220887c22053e020020054220882105200141106a2101200c417c6a220c0d000c020b0b4128412841d892c0800010f980808000000b0240200a450d00034020012001350200420a7e20057c22053e0200200141046a210120054220882105200a417f6a220a0d000b0b02402005a722010d002004200e3602e8030c020b200e41274b0d02200441c8026a200e4102746a2001360200200e41016a21150b200420153602e8030b20044190056a200441ec036a41a00110848e8080001a200420123602b00620044190056a410110ea808080002117200428028c052101200441b4066a200441ec036a41a00110848e8080001a200420013602d407200441b4066a410210ea808080002118200428028c052101200441d8076a200441ec036a41a00110848e8080001a200420013602f808200441d8076a410310ea8080800021190240024020042802a001221220042802f808221a2012201a4b1b221041284b0d0020044190056a417c6a210e200441b4066a417c6a210d200441d8076a417c6a210f200428028c05211b20042802b006211c20042802d407211d4100211e0340201e211f201041027421010240024003402001450d01417f200f20016a280200220a2001417c6a220120046a280200220c47200a200c4b1b220a450d000c020b0b417f410020011b210a0b410021200240024002400240024002400240024002400240024002400240024002400240024002400240024002400240200a41014b0d0002402010450d00410121112010410171212141002112024020104101460d002010417e712113410021124101211120042101200441d8076a210a0340200120012802002214200a280200417f736a220c20114101716a2215360200200141046a221120112802002216200a41046a280200417f736a2211200c2014492015200c49726a220c3602002011201649200c201149722111200a41086a210a200141086a21012013201241026a2212470d000b0b02402021450d002004201241027422016a220a200a280200220a201920016a280200417f736a220120116a220c3602002001200a49200c2001497221110b2011410171450d020b200420103602a00141082120201021120b2012201d2012201d4b1b221341294f0d01201341027421010240024003402001450d01417f200d20016a280200220a2001417c6a220120046a280200220c47200a200c4b1b220a450d000c020b0b417f410020011b210a0b02400240200a41014d0d00201221130c010b02402013450d00410121112013410171212141002112024020134101460d002013417e712110410021124101211120042101200441b4066a210a0340200120012802002214200a280200417f736a220c20114101716a2215360200200141046a221120112802002216200a41046a280200417f736a2211200c2014492015200c49726a220c3602002011201649200c201149722111200a41086a210a200141086a21012010201241026a2212470d000b0b02402021450d002004201241027422016a220a200a280200220a201820016a280200417f736a220120116a220c3602002001200a49200c2001497221110b2011410171450d040b200420133602a001202041047221200b2013201c2013201c4b1b222141294f0d03202141027421010240024003402001450d01417f200e20016a280200220a2001417c6a220120046a280200220c47200a200c4b1b220a450d000c020b0b417f410020011b210a0b02400240200a41014d0d00201321210c010b02402021450d00410121112021410171211041002112024020214101460d002021417e71211341002112410121112004210120044190056a210a0340200120012802002214200a280200417f736a220c20114101716a2215360200200141046a221120112802002216200a41046a280200417f736a2211200c2014492015200c49726a220c3602002011201649200c201149722111200a41086a210a200141086a21012013201241026a2212470d000b0b02402010450d002004201241027422016a220a200a280200220a201720016a280200417f736a220120116a220c3602002001200a49200c2001497221110b2011410171450d060b200420213602a001202041026a21200b2021201b2021201b4b1b221041294f0d05201041027421010240024003402001450d01417f2001417c6a2201200441ec036a6a280200220a200120046a280200220c47200a200c4b1b220a450d000c020b0b417f410020011b210a0b02400240200a41014d0d00202121100c010b02402010450d00410121112010410171212141002112024020104101460d002010417e712113410021124101211120042101200441ec036a210a0340200120012802002214200a280200417f736a220c20114101716a2215360200200141046a221120112802002216200a41046a280200417f736a2211200c2014492015200c49726a220c3602002011201649200c201149722111200a41086a210a200141086a21012013201241026a2212470d000b0b02402021450d002004201241027422016a220a200a280200220a200441ec036a20016a280200417f736a220120116a220c3602002001200a49200c2001497221110b2011410171450d080b200420103602a001202041016a21200b201f2003460d0b2002201f6a202041306a3a0000201020042802c4022222201020224b1b220141294f0d07201f41016a211e200141027421010240024003402001450d01417f2001417c6a2201200441a4016a6a280200220a200120046a280200220c47200a200c4b1b2213450d000c020b0b417f410020011b21130b200441fc086a200441a00110848e8080001a2004201036029c0a201020042802e8032223201020234b1b222041294f0d080240024020200d00410021200c010b202041017121244100211141002112024020204101460d002020417e71212141002111200441fc086a2101200441c8026a210a410021120340200120012802002214200a2802006a220c20114101716a2215360200200141046a221120112802002216200a41046a2802006a2211200c2014492015200c49726a220c3602002011201649200c201149722111200a41086a210a200141086a21012021201241026a2212470d000b0b02402024450d00200441fc086a201241027422016a220a200a280200220a200441c8026a20016a2802006a220120116a220c3602002001200a49200c2001497221110b2011410171450d00202041274b0d0a200441fc086a20204102746a4101360200202041016a21200b2004202036029c0a201b2020201b20204b1b220141294f0d0a200141027421010240024003402001450d01417f2001417c6a2201200441fc086a6a280200220a2001200441ec036a6a280200220c47200a200c4b1b220a450d000c020b0b417f410020011b210a0b024002400240201320094822010d00200a20094e0d010b200a20094e0d1c20010d010c1b0b41002114410021122010450d0f2010417f6a41ffffffff0371220141016a220c410371210a0240200141034f0d0020042101420021050c0f0b200c41fcffffff0771210c2004210142002105034020012001350200420a7e20057c22053e0200200141046a22112011350200420a7e20054220887c22053e0200200141086a22112011350200420a7e20054220887c22053e02002001410c6a22112011350200420a7e20054220887c22053e020020054220882105200141106a2101200c417c6a220c0d000c0f0b0b2004410110ea808080001a20042802a0012201200428028c05220a2001200a4b1b220141294f0d0c200141027421012004417c6a2111200441ec036a417c6a21120240024003402001450d01201120016a210a201220016a210c2001417c6a2101417f200c280200220c200a280200220a47200c200a4b1b220a450d000c020b0b417f410020011b210a0b200a4102490d190c1a0b41e892c08000411a41d892c0800010f880808000000b2013412841d892c08000109581808000000b41e892c08000411a41d892c0800010f880808000000b2021412841d892c08000109581808000000b41e892c08000411a41d892c0800010f880808000000b2010412841d892c08000109581808000000b41e892c08000411a41d892c0800010f880808000000b2001412841d892c08000109581808000000b2020412841d892c08000109581808000000b4128412841d892c0800010f980808000000b2001412841d892c08000109581808000000b2003200341a0aac0800010f980808000000b2001412841d892c08000109581808000000b0240200a450d00034020012001350200420a7e20057c22053e0200200141046a210120054220882105200a417f6a220a0d000b0b02402005a722010d00201021120c010b201041274b0d01200420104102746a2001360200201041016a21120b200420123602a0012022450d022022417f6a41ffffffff0371220141016a220c410371210a0240200141034f0d00200441a4016a2101420021050c020b200c41fcffffff0771210c200441a4016a210142002105034020012001350200420a7e20057c22053e0200200141046a22112011350200420a7e20054220887c22053e0200200141086a22112011350200420a7e20054220887c22053e02002001410c6a22112011350200420a7e20054220887c22053e020020054220882105200141106a2101200c417c6a220c0d000c020b0b4128412841d892c0800010f980808000000b0240200a450d00034020012001350200420a7e20057c22053e0200200141046a210120054220882105200a417f6a220a0d000b0b02402005a722010d00202221140c010b202241274b0d01200441a4016a20224102746a2001360200202241016a21140b200420143602c402024020230d00410021230c030b2023417f6a41ffffffff0371220141016a220c410371210a0240200141034f0d00200441c8026a2101420021050c020b200c41fcffffff0771210c200441c8026a210142002105034020012001350200420a7e20057c22053e0200200141046a22112011350200420a7e20054220887c22053e0200200141086a22112011350200420a7e20054220887c22053e02002001410c6a22112011350200420a7e20054220887c22053e020020054220882105200141106a2101200c417c6a220c0d000c020b0b4128412841d892c0800010f980808000000b0240200a450d00034020012001350200420a7e20057c22053e0200200141046a210120054220882105200a417f6a220a0d000b0b2005a72201450d00202341274b0d03200441c8026a20234102746a2001360200202341016a21230b200420233602e8032012201a2012201a4b1b221041284d0d000b0b2010412841d892c08000109581808000000b4128412841d892c0800010f980808000000b4128412841d892c0800010f980808000000b2002201e6a2112201f2101417f210a024003402001417f460d01200a41016a210a200220016a210c2001417f6a22112101200c2d00004139460d000b200220116a220c41016a220120012d000041016a3a0000201141026a201e4f0d01200c41026a4130200a108a8e8080001a0c010b02400240201e0d00413121010c010b200241313a00000240201f0d00413021010c010b41302101200241016a4130201f108a8e8080001a0b0240201e20034f0d00201220013a0000200b41016a210b201f41026a211e0c010b201e200341b0aac0800010f980808000000b0240201e20034b0d002000200b3b01082000201e36020420002002360200200441a00a6a2480808080000f0b201e200341c0aac08000109581808000000b872a03017f037e1a7f23808080800041c0066b22052480808080000240024002400240024002400240024002400240024002400240024002400240024002400240200129030022064200510d00200129030822074200510d01200129031022084200510d02200620087c2006540d0320062007540d0420012f01182101200520063e020c20054101410220064280808080105422091b3602ac01200541002006422088a720091b360210200541146a4100419801108a8e8080001a200541b4016a4100419c01108a8e8080001a200541013602b001200541013602d0022001ad4230864230872006427f7c797d42c29ac1e8047e4280a1cda0b4027c422088a72209411074411075210a024002402001411074411075220b4100480d002005410c6a200110ea808080001a0c010b200541b0016a4100200b6b41107441107510ea808080001a0b02400240200a417f4a0d002005410c6a4100200a6b4110744110751090818080001a0c010b200541b0016a200941ffff03711090818080001a0b20052802d002210c2005419c056a200541b0016a41a00110848e8080001a2005200c3602bc062003210d02402003410a490d0002400240200c41284d0d00200c21010c010b2005419c056a41786a210e2003210d200c2101034002402001450d002001417f6a41ffffffff0371220941016a220b410171210f200141027421010240024020090d002005419c056a20016a2101420021060c010b200b41feffffff07712109200e20016a2101420021060340200141046a220b2006422086200b350200842206428094ebdc038022073e0200200120062007428094ebdc037e7d4220862001350200842206428094ebdc038022073e020020062007428094ebdc037e7d2106200141786a21012009417e6a22090d000b200141086a21010b200f450d002001417c6a22012006422086200135020084428094ebdc03803e02000b200d41776a220d41094d0d0220052802bc0622014129490d000b0b2001412841d892c08000109581808000000b200d41027441d4a5c080006a2802002209450d0520052802bc06220141294f0d060240024020010d00410021010c010b2001417f6a41ffffffff0371220b41016a220f410171210d200141027421012009ad210602400240200b0d002005419c056a20016a2101420021070c010b200f41feffffff0771210920012005419c056a6a41786a2101420021070340200141046a220b2007422086200b35020084220720068022083e020020012007200820067e7d422086200135020084220720068022083e02002007200820067e7d2107200141786a21012009417e6a22090d000b200141086a21010b0240200d450d002001417c6a220120074220862001350200842006803e02000b20052802bc0621010b200120052802ac012210200120104b1b221141294f0d07024020110d00410021110c0a0b20114101712112024020114101470d004100210d4100210f0c090b2011417e7121134100210d2005419c056a21012005410c6a21094100210f034020012001280200220e20092802006a220b200d4101716a2214360200200141046a220d200d2802002215200941046a2802006a220d200b200e492014200b49726a220b360200200d201549200b200d4972210d200941086a2109200141086a21012013200f41026a220f470d000c090b0b41d8a8c08000411c41e0abc0800010f880808000000b4184a9c08000411d41f0abc0800010f880808000000b41b4a9c08000411c4180acc0800010f880808000000b4198abc08000413641f0acc0800010f880808000000b41d0aac08000413741e0acc0800010f880808000000b419f93c08000411b41d892c0800010f880808000000b2001412841d892c08000109581808000000b2011412841d892c08000109581808000000b02402012450d002005419c056a200f41027422016a2209200928020022092005410c6a20016a2802006a2201200d6a220b3602002001200949200b20014972210d0b200d410171450d00201141274b0d012005419c056a20114102746a4101360200201141016a21110b200520113602bc062011200c2011200c4b1b220141294f0d01200141027421010240024003402001450d01417f2001417c6a2201200541b0016a6a280200220920012005419c056a6a280200220b472009200b4b1b2209450d000c020b0b417f410020011b21090b0240200941014b0d00200a41016a210a0c050b024020100d00410021100c040b2010417f6a41ffffffff0371220141016a220b41037121090240200141034f0d002005410c6a2101420021060c030b200b41fcffffff0771210b2005410c6a210142002106034020012001350200420a7e20067c22063e0200200141046a220d200d350200420a7e20064220887c22063e0200200141086a220d200d350200420a7e20064220887c22063e02002001410c6a220d200d350200420a7e20064220887c22063e020020064220882106200141106a2101200b417c6a220b0d000c030b0b4128412841d892c0800010f980808000000b2001412841d892c08000109581808000000b02402009450d00034020012001350200420a7e20067c22063e0200200141046a2101200642208821062009417f6a22090d000b0b2006a72201450d00201041274b0d022005410c6a20104102746a2001360200201041016a21100b200520103602ac010b4100210e02400240200a411074411075220120044110744110752209480d00200a20046b4110744110752003200120096b2003491b220d0d014100210e0b4100210d0c020b200541d4026a200541b0016a41a00110848e8080001a2005200c3602f403200541d4026a410110ea80808000211620052802d0022101200541f8036a200541b0016a41a00110848e8080001a2005200136029805200541f8036a410210ea80808000211720052802d00221012005419c056a200541b0016a41a00110848e8080001a200520013602bc06200541b0016a417c6a2113200541d4026a417c6a2115200541f8036a417c6a21142005419c056a417c6a210e2005419c056a410310ea80808000211820052802d002210c20052802f4032119200528029805211a20052802bc06211b20052802ac0121104100211c02400340201c211d0240024002400240024002400240024002400240024002400240201041294f0d00201d41016a211c2010410274210b410021010240024002400340200b2001460d012005410c6a20016a2109200141046a21012009280200450d000b2010201b2010201b4b1b221e41294f0d04201e41027421010240024003402001450d01417f200e20016a28020022092001417c6a22012005410c6a6a280200220b472009200b4b1b2209450d000c020b0b417f410020011b21090b4100211f0240200941024f0d000240201e450d004101210f201e410171211f410021100240201e4101460d00201e417e712120410021104101210f2005410c6a21012005419c056a210903402001200128020022112009280200417f736a220b200f4101716a2212360200200141046a220f200f2802002221200941046a280200417f736a220f200b2011492012200b49726a220b360200200f202149200b200f4972210f200941086a2109200141086a21012020201041026a2210470d000b0b0240201f450d002005410c6a201041027422016a220920092802002209201820016a280200417f736a2201200f6a220b3602002001200949200b20014972210f0b200f410171450d080b2005201e3602ac014108211f201e21100b2010201a2010201a4b1b222041294f0d072020410274210103402001450d02417f201420016a28020022092001417c6a22012005410c6a6a280200220b472009200b4b1b2209450d000c030b0b200d20034b0d04200d201d460d132002201d6a4130200d201d6b108a8e8080001a0c130b417f410020011b21090b02400240200941014d0d00201021200c010b02402020450d004101210f2020410171212241002110024020204101460d002020417e71211e410021104101210f2005410c6a2101200541f8036a210903402001200128020022112009280200417f736a220b200f4101716a2212360200200141046a220f200f2802002221200941046a280200417f736a220f200b2011492012200b49726a220b360200200f202149200b200f4972210f200941086a2109200141086a2101201e201041026a2210470d000b0b02402022450d002005410c6a201041027422016a220920092802002209201720016a280200417f736a2201200f6a220b3602002001200949200b20014972210f0b200f410171450d070b200520203602ac01201f410472211f0b20202019202020194b1b221e41294f0d06201e41027421010240024003402001450d01417f201520016a28020022092001417c6a22012005410c6a6a280200220b472009200b4b1b2209450d000c020b0b417f410020011b21090b02400240200941014d0d002020211e0c010b0240201e450d004101210f201e4101712122410021100240201e4101460d00201e417e712120410021104101210f2005410c6a2101200541d4026a210903402001200128020022112009280200417f736a220b200f4101716a2212360200200141046a220f200f2802002221200941046a280200417f736a220f200b2011492012200b49726a220b360200200f202149200b200f4972210f200941086a2109200141086a21012020201041026a2210470d000b0b02402022450d002005410c6a201041027422016a220920092802002209201620016a280200417f736a2201200f6a220b3602002001200949200b20014972210f0b200f410171450d090b2005201e3602ac01201f41026a211f0b201e200c201e200c4b1b221041294f0d08201041027421010240024003402001450d01417f201320016a28020022092001417c6a22012005410c6a6a280200220b472009200b4b1b2209450d000c020b0b417f410020011b21090b02400240200941014d0d00201e21100c010b02402010450d004101210f2010410171212241002111024020104101460d002010417e71211e410021114101210f2005410c6a2101200541b0016a210903402001200128020022122009280200417f736a220b200f4101716a2221360200200141046a220f200f2802002220200941046a280200417f736a220f200b2012492021200b49726a220b360200200f202049200b200f4972210f200941086a2109200141086a2101201e201141026a2211470d000b0b02402022450d002005410c6a201141027422016a220920092802002209200541b0016a20016a280200417f736a2201200f6a220b3602002001200949200b20014972210f0b200f410171450d0b0b200520103602ac01201f41016a211f0b0240201d2003460d002002201d6a201f41306a3a0000201041294f0d0b024020100d00410021100c0e0b2010417f6a41ffffffff0371220141016a220b41037121090240200141034f0d002005410c6a2101420021060c0d0b200b41fcffffff0771210b2005410c6a210142002106034020012001350200420a7e20067c22063e0200200141046a220f200f350200420a7e20064220887c22063e0200200141086a220f200f350200420a7e20064220887c22063e02002001410c6a220f200f350200420a7e20064220887c22063e020020064220882106200141106a2101200b417c6a220b0d000c0d0b0b2003200341c0acc0800010f980808000000b2010412841d892c08000109581808000000b201e412841d892c08000109581808000000b200d200341d0acc08000109581808000000b41e892c08000411a41d892c0800010f880808000000b2020412841d892c08000109581808000000b41e892c08000411a41d892c0800010f880808000000b201e412841d892c08000109581808000000b41e892c08000411a41d892c0800010f880808000000b2010412841d892c08000109581808000000b41e892c08000411a41d892c0800010f880808000000b2010412841d892c08000109581808000000b02402009450d00034020012001350200420a7e20067c22063e0200200141046a2101200642208821062009417f6a22090d000b0b2006a72201450d00201041274b0d022005410c6a20104102746a2001360200201041016a21100b200520103602ac01201c200d470d000b4101210e0c020b4128412841d892c0800010f980808000000b4128412841d892c0800010f980808000000b0240024002400240024002400240200c41294f0d000240200c0d004100210c0c030b200c417f6a41ffffffff0371220141016a220b41037121090240200141034f0d00200541b0016a2101420021060c020b200b41fcffffff0771210b200541b0016a21014200210603402001200135020042057e20067c22063e0200200141046a220f200f35020042057e20064220887c22063e0200200141086a220f200f35020042057e20064220887c22063e02002001410c6a220f200f35020042057e20064220887c22063e020020064220882106200141106a2101200b417c6a220b0d000c020b0b200c412841d892c08000109581808000000b02402009450d0003402001200135020042057e20067c22063e0200200141046a2101200642208821062009417f6a22090d000b0b2006a72201450d00200c41274b0d01200541b0016a200c4102746a2001360200200c41016a210c0b2005200c3602d0022010200c2010200c4b1b220141294f0d0120014102742101024002400240024003402001450d01417f2001417c6a2201200541b0016a6a280200220920012005410c6a6a280200220b472009200b4b1b2209450d000b200941ff01714101460d010c070b200e20014571450d06200d417f6a220120034f0d01200220016a2d0000410171450d060b200d20034b0d042002200d6a210f410021012002210902400340200d2001460d01200141016a21012009417f6a2209200d6a220b2d00004139460d000b200b200b2d000041016a3a0000200d20016b41016a200d4f0d06200b41016a41302001417f6a108a8e8080001a0c060b02400240200d0d00413121010c010b200241313a000041302101200d4101460d0041302101200241016a4130200d417f6a108a8e8080001a0b200a411074418080046a411075220a20044110744110754a0d010c050b200120034190acc0800010f980808000000b200d20034f0d03200f20013a0000200d41016a210d0c030b4128412841d892c0800010f980808000000b2001412841d892c08000109581808000000b200d200341a0acc08000109581808000000b200d20034b0d010b2000200a3b01082000200d36020420002002360200200541c0066a2480808080000f0b200d200341b0acc08000109581808000000b0d0020002802001a037f0c000b0b870101017f23808080800041306b22032480808080002003200036020020032001360204200341086a410c6a4202370200200341206a410c6a4185808080003602002003410236020c200341b4adc0800036020820034185808080003602242003200341206a3602102003200341046a36022820032003360220200341086a200210f680808000000b870101017f23808080800041306b22032480808080002003200036020020032001360204200341086a410c6a4202370200200341206a410c6a4185808080003602002003410236020c200341d4adc0800036020820034185808080003602242003200341206a3602102003200341046a36022820032003360220200341086a200210f680808000000b870101017f23808080800041306b22032480808080002003200036020020032001360204200341086a410c6a4202370200200341206a410c6a4185808080003602002003410236020c20034188aec0800036020820034185808080003602242003200341206a3602102003200341046a36022820032003360220200341086a200210f680808000000b130020002001200220032004109881808000000bf70901057f23808080800041f0006b22052480808080002005200336020c20052002360208024002402001418102490d004180022106024020002c00800241bf7f4a0d0041ff01210620002c00ff0141bf7f4a0d0041fe01210620002c00fe0141bf7f4a0d0041fd0121060b2005200636021420052000360210410521064198aec0800021070c010b2005200136021420052000360210410021064180adc0800021070b2005200636021c2005200736021802400240024002400240200220014b22060d00200320014b0d00200220034b0d01024002402002450d00200220014f0d00200020026a2c00004140480d010b200321020b20052002360220200121030240200220014f0d0041002002417d6a2203200320024b1b2203200241016a22064b0d03024020032006460d00200020066a200020036a22086b21060240200020026a22092c000041bf7f4c0d002006417f6a21070c010b20032002460d0002402009417f6a22022c000041bf7f4c0d002006417e6a21070c010b20082002460d0002402009417e6a22022c000041bf7f4c0d002006417d6a21070c010b20082002460d0002402009417d6a22022c000041bf7f4c0d002006417c6a21070c010b20082002460d002006417b6a21070b200720036a21030b02402003450d0002400240200120034b0d0020012003460d010c070b200020036a2c000041bf7f4c0d060b200120036b21010b2001450d030240024002400240200020036a22012c00002202417f4a0d0020012d0001413f7121002002411f7121062002415f4b0d01200641067420007221010c020b2005200241ff0171360224410121020c020b200041067420012d0002413f717221000240200241704f0d0020002006410c747221010c010b200041067420012d0003413f71722006411274418080f00071722201418080c400460d050b20052001360224410121022001418001490d00410221022001418010490d0041034104200141808004491b21020b200520033602282005200220036a36022c200541306a410c6a4205370200200541ec006a41a280808000360200200541e4006a41a280808000360200200541dc006a41ac80808000360200200541c8006a410c6a41ad8080800036020020054105360234200541a0afc08000360230200541858080800036024c2005200541c8006a3602382005200541186a3602682005200541106a3602602005200541286a3602582005200541246a3602502005200541206a360248200541306a200410f680808000000b20052002200320061b360228200541306a410c6a4203370200200541dc006a41a280808000360200200541c8006a410c6a41a28080800036020020054103360234200541e0afc08000360230200541858080800036024c2005200541c8006a3602382005200541186a3602582005200541106a3602502005200541286a360248200541306a200410f680808000000b200541e4006a41a280808000360200200541dc006a41a280808000360200200541c8006a410c6a418580808000360200200541306a410c6a420437020020054104360234200541c0aec08000360230200541858080800036024c2005200541c8006a3602382005200541186a3602602005200541106a36025820052005410c6a3602502005200541086a360248200541306a200410f680808000000b2003200641e8b0c08000109681808000000b200410a081808000000b20002001200320012004109781808000000b8a0301077f41012107024002402002450d00200120024101746a210820004180fe037141087621094100210a200041ff0171210b0340200141026a210c200a20012d000122026a210d024020012d000022012009460d00200120094b0d02200d210a200c2101200c2008460d020c010b024002400240200a200d4b0d00200d20044b0d012003200a6a210103402002450d032002417f6a210220012d0000210a200141016a2101200a200b470d000b410021070c050b200a200d4184b2c08000109681808000000b200d20044184b2c08000109581808000000b200d210a200c2101200c2008470d000b0b2006450d00200520066a210b200041ffff0371210a200520064100476a21024101210703400240024020052d00002201411874411875220d4100480d00200221050c010b02402002200b460d00200241016a2105200d41ff007141087420022d00007221010c010b41f4b1c0800010a081808000000b200a20016b220a4100480d012007410173210720052005200b4722016a210220010d000b0b20074101710ba10201017f0240200041204f0d0041000f0b4101210102400240200041ff00490d00200041808004490d0102400240200041808008490d000240200041d0b8736a41d0ba2b4f0d0041000f0b0240200041b5d9736a41054f0d0041000f0b0240200041e28b746a41e20b4f0d0041000f0b02402000419fa8746a419f184f0d0041000f0b0240200041dee2746a410e4f0d0041000f0b02402000417e71419ef00a470d0041000f0b200041607141e0cd0a470d0141000f0b20004194b2c08000412c41ecb2c0800041c40141b0b4c0800041c2031099818080000f0b41002101200041c691756a4106490d002000418080bc7f6a41f083744921010b20010f0b200041f2b7c08000412841c2b8c08000419f0241e1bac0800041af021099818080000bed0201037f2380808080004180016b220224808080800002400240024002400240200128021c22034110710d0020034120710d0120003502004101200110fe8080800021000c020b20002802002100410021030340200220036a41ff006a413041d7002000410f712204410a491b20046a3a00002003417f6a210320004110492104200041047621002004450d000b20034180016a22004180014b0d022001410141c48dc080004102200220036a4180016a410020036b10db8080800021000c010b20002802002100410021030340200220036a41ff006a413041372000410f712204410a491b20046a3a00002003417f6a210320004110492104200041047621002004450d000b20034180016a22004180014b0d022001410141c48dc080004102200220036a4180016a410020036b10db8080800021000b20024180016a24808080800020000f0b200041800141c88dc08000109481808000000b200041800141c88dc08000109481808000000be40201037f2380808080004180016b22022480808080002000280200210002400240024002400240200128021c22034110710d0020034120710d012000ad4101200110fe8080800021000c020b410021030340200220036a41ff006a413041d7002000410f712204410a491b20046a3a00002003417f6a210320004110492104200041047621002004450d000b20034180016a22004180014b0d022001410141c48dc080004102200220036a4180016a410020036b10db8080800021000c010b410021030340200220036a41ff006a413041372000410f712204410a491b20046a3a00002003417f6a210320004110492104200041047621002004450d000b20034180016a22004180014b0d022001410141c48dc080004102200220036a4180016a410020036b10db8080800021000b20024180016a24808080800020000f0b200041800141c88dc08000109481808000000b200041800141c88dc08000109481808000000bb01107017f037e027f127e027f027e037f23808080800041306b22042480808080000240024002400240024002400240024002400240024002400240200129030022054200510d00200129030822064200510d01200129031022074200510d02200520077c22072005540d0320052006540d04200341104d0d052007428080808080808080205a0d06200420012f011822013b01082004200520067d22063703002001200141606a200120074280808080105422081b220941706a20092007422086200720081b220742808080808080c0005422081b220941786a20092007421086200720081b2207428080808080808080015422081b2209417c6a20092007420886200720081b2207428080808080808080105422081b2209417e6a20092007420486200720081b2207428080808080808080c0005422081b2007420286200720081b220a427f556b22086b4110744110752209417f4c0d07200420062009ad220786220b200788220c370310200c2006520d08200420013b010820042005370300200420052007423f832206862207200688220637031020062005520d0941a07f20086b41107441107541d0006c41b0a7056a41ce106d220141d1004f0d0a200141047422014188c0c080006a290300220642ffffffff0f8322052007422088220d7e220c422088220e2006422088220f200d7e7c200f200742ffffffff0f8322077e220642208822107c2111200c42ffffffff0f83200520077e4220887c200642ffffffff0f837c4280808080087c422088211242014100200820014190c0c080006a2f01006a6b413f71ad2207862213427f7c21142005200b42208822067e220c42ffffffff0f832005200b42ffffffff0f83220b7e4220887c200f200b7e220b42ffffffff0f837c4280808080087c4220882115200f20067e2106200b422088210b200c422088210c20014192c0c080006a2f010021010240200f200a200a427f85423f8886220a42208822167e2217200520167e221842208822197c200f200a42ffffffff0f83220a7e221a422088221b7c201842ffffffff0f832005200a7e4220887c201a42ffffffff0f837c4280808080087c422088221a7c42017c2218200788a722094190ce00490d00200941c0843d490d0c024020094180c2d72f490d00410841092009418094ebdc034922081b211c4180c2d72f418094ebdc0320081b21080c0e0b4106410720094180ade2044922081b211c41c0843d4180ade20420081b21080c0d0b0240200941e400490d0041024103200941e8074922081b211c41e40041e80720081b21080c0d0b410a4101200941094b221c1b21080c0c0b41accbc08000411c41c8cbc0800010f880808000000b41d8cbc08000411d41f8cbc0800010f880808000000b4188ccc08000411c41a4ccc0800010f880808000000b41d4cec080004136418ccfc0800010f880808000000b418ccec08000413741c4cec0800010f880808000000b41b4ccc08000412d41e4ccc0800010f880808000000b41f4ccc08000412d41a4cdc0800010f880808000000b41b4bec08000411d41c8bfc0800010f880808000000b200441003602184100200441106a2004200441186a41d8bfc0800010fa80808000000b200441003602184100200441106a2004200441186a41d8bfc0800010fa80808000000b200141d100419ccbc0800010f980808000000b41044105200941a08d064922081b211c4190ce0041a08d0620081b21080b201120127c211120182014832105201c20016b41016a211d2018200c20067c200b7c20157c221e7d221f42017c220c201483210a41002101024002400240024002400240024002400340200920086e212020032001460d02200220016a2221202041306a22223a000002400240200c2009202020086c6b2209ad200786220620057c220b560d00201c2001470d01200141016a21014201210603402006210b200a210c200120034f0d06200220016a2005420a7e2205200788a741306a22083a0000200141016a2101200b420a7e2106200c420a7e220a20052014832205580d000b2006201820117d7e220720067c2112200a20057d20135422090d07200720067d22142005560d030c070b200c200b7d220c2008ad2007862207542108201820117d220a42017c2115200a427f7c2213200b580d05200c2007540d05200520077c220b200e7c20107c20127c200f200d20167d7e7c20197d201b7d201a7d210c2019201b7c201a7c20177c210a42002011200620057c7c7d210d4202201e200b20067c7c7d2118034002402006200b7c22142013540d00200d200a7c2006200c7c5a0d00200620057c210b410021080c070b20212022417f6a22223a0000200520077c21052018200a7c210f0240201420135a0d00200b20077c210b200c20077c210c200a20077d210a200f20075a0d010b0b200f2007542108200620057c210b0c050b200141016a21012008410a4921202008410a6e21082020450d000b41d0cdc08000411941b4cdc0800010f880808000000b200220016a417f6a2120200c420a7e201320057c7d210f201320147d2118201420057d210d4200210703400240200520137c22062014540d00200d20077c201820057c5a0d00410021090c050b20202008417f6a22083a0000200f20077c220c2013542109200620145a0d05200720137d210720062105200c2013540d050c000b0b2003200341eccdc0800010f980808000000b2001200341fccdc0800010f980808000000b02402015200b580d0020080d000240200b20077c22052015540d002015200b7d200520157d540d010b200041003602000c040b02400240200b4202540d00200b201f427d7c580d010b200041003602000c040b2000201d3b01082000200141016a3602040c020b200521060b024020122006580d0020090d000240200620137c22052012540d00201220067d200520127d540d010b200041003602000c020b02400240200b42147e2006560d002006200b42587e200a7c580d010b200041003602000c020b2000201d3b0108200020013602040b200020023602000b200441306a2480808080000b9e0906017e017f047e027f017e057f0240024002400240024002400240200129030022054200510d002005428080808080808080205a0d012003450d0241a07f20012f0118220141606a200120054280808080105422061b220141706a20012005422086200520061b220542808080808080c0005422061b220141786a20012005421086200520061b2205428080808080808080015422061b2201417c6a20012005420886200520061b2205428080808080808080105422061b2201417e6a20012005420486200520061b2205428080808080808080c0005422061b2005420286200520061b2205427f556b22066b41107441107541d0006c41b0a7056a41ce106d220141d1004f0d03200141047422014188c0c080006a290300220742ffffffff0f83220820052005427f85423f8886220542208822097e220a4220882007422088220720097e7c2007200542ffffffff0f8322057e22074220887c200a42ffffffff0f83200820057e4220887c200742ffffffff0f837c4280808080087c4220887c22054140200620014190c0c080006a2f01006a6b220b413f71ad220888a7210c20014192c0c080006a2f01002101024020054201200886220d427f7c22098322074200520d002003410a4b0d0720034102744190d0c080006a280200200c4b0d070b0240200c4190ce00490d00200c41c0843d490d050240200c4180c2d72f490d0041084109200c418094ebdc034922061b210e4180c2d72f418094ebdc0320061b21060c070b41064107200c4180ade2044922061b210e41c0843d4180ade20420061b21060c060b0240200c41e400490d0041024103200c41e8074922061b210e41e40041e80720061b21060c060b410a4101200c41094b220e1b21060c050b41accbc08000411c41c0cfc0800010f880808000000b41d0cfc08000412441f4cfc0800010f880808000000b419ccfc0800041214184d0c0800010f880808000000b200141d100419ccbc0800010f980808000000b41044105200c41a08d064922061b210e4190ce0041a08d0620061b21060b02400240024002400240200e20016b411074418080046a411075220f200441107441107522014c0d00200b41ffff03712110200f20046b4110744110752003200f20016b2003491b2211417f6a2112410021010340200c20066e210b20032001460d03200c200b20066c6b210c200220016a200b41306a3a000020122001460d04200e2001460d02200141016a21012006410a49210b2006410a6e2106200b450d000b41d0cdc08000411941bcd0c0800010f880808000000b2000200220034100200f20042005420a802006ad200886200d109f818080000f0b200141016a21012010417f6a413f71ad210a42012105034002402005200a88500d00200041003602000f0b200120034f0d03200220016a2007420a7e2207200888a741306a3a00002005420a7e2105200720098321072011200141016a2201470d000b2000200220032011200f20042007200d2005109f818080000f0b2003200341ccd0c0800010f980808000000b2000200220032011200f2004200cad20088620077c2006ad200886200d109f818080000f0b2001200341dcd0c0800010f980808000000b200041003602000bae0301047f024002400240024002400240024020072008580d00200720087d2008580d01024002400240200720067d2006580d00200720064201867d20084201865a0d010b20062008560d010c080b200320024b0d030c060b2007200620087d22087d2008560d06200320024b0d03200120036a21094100210a2001210b024003402003200a460d01200a41016a210a200b417f6a220b20036a220c2d00004139460d000b200c200c2d000041016a3a00002003200a6b41016a20034f0d05200c41016a4130200a417f6a108a8e8080001a0c050b0240024020030d004131210a0c010b200141313a00004130210a20034101460d004130210a200141016a41302003417f6a108a8e8080001a0b2004411074418080046a4110752104200320024f0d04200420054110744110754c0d042009200a3a0000200341016a21030c040b200041003602000f0b200041003602000f0b20032002418cd1c08000109581808000000b2003200241ecd0c08000109581808000000b200320024d0d002003200241fcd0c08000109581808000000b200020043b010820002003360204200020013602000f0b200041003602000b1300419cd1c08000412b200010f880808000000b6c01017f23808080800041306b22032480808080002003200136020c200320003602082003411c6a420137020020034101360214200341c8d1c08000360210200341a28080800036022c2003200341286a3602182003200341086a360228200341106a200210f680808000000b870101017f23808080800041306b22032480808080002003200136020420032000360200200341086a410c6a4202370200200341206a410c6a4185808080003602002003410336020c20034194d2c0800036020820034185808080003602242003200341206a360210200320033602282003200341046a360220200341086a200210f680808000000b840602087e0a7f200020013502102202421a8820013502147c220342198820013502187c2204421a88200135021c7c220542198820013502207c2206421a8820013502247c220742198842137e2001350200220842ffffff1f837c2209a741ffffff1f71220a41136a411a762009421a882008421a8820013502047c220842ffffff0f837ca7220b6a411976200842198820013502087c2208a741ffffff1f71220c6a411a762008421a88200135020c7c2208a741ffffff0f71220d6a4119762008421988200242ffffff1f837c2202a741ffffff1f71220e6a411a762002421a88200342ffffff0f837ca7220f6a4119762004a741ffffff1f7122106a411a762005a741ffffff0f7122116a4119762006a741ffffff1f7122126a411a762007a741ffffff0f7122136a41197641136c200a6a22013a0000200020014110763a0002200020014108763a000120002001411a76200b6a220a410e763a00052000200a4106763a00042000200a4102742001411876410371723a00032000200a411976200c6a2201410d763a0008200020014105763a000720002001410374200a418080800e71411676723a000620002001411a76200d6a220a410b763a000b2000200a4103763a000a2000200a4105742001411576411f71723a00092000200a411976200e6a22014112763a000f20002001410a763a000e200020014102763a000d20002001411a76200f6a220b3a001020002001410674200a411376413f71723a000c2000200b4110763a00122000200b4108763a00112000200b41197620106a2201410f763a0015200020014107763a001420002001410174200b411876410171723a001320002001411a7620116a220a410d763a00182000200a4105763a00172000200a4103742001411776410771723a00162000200a41197620126a2201410c763a001b200020014104763a001a20002001410474200a411576410f71723a001920002001411a7620136a220a410a763a001e2000200a4102763a001d2000200a418080f00f714112763a001f2000200a4106742001411476413f71723a001c0b832404017f067e0f7f027e23808080800041f0076b2203248080808000200341a0076a200210a581808000200320032903d00720032903c80720032903c0072204421a887c22054219887c2206a741ffffff1f7136029007200320032903b00720032903a80720032903a0072207421a887c22084219887c2209a741ffffff1f7136028007200320032903d8072006421a887c2206a741ffffff0f7136029407200320032903b8072009421a887c2209a741ffffff0f71360284072003200642198820032903e0077c2206a741ffffff1f713602980720032009421988200442ffffff1f837c2204421a88200542ffffff0f837c3e028c0720032004a741ffffff1f713602880720032006421a8820032903e8077c2204a741ffffff0f7136029c072003200442198842137e200742ffffff1f837c2204421a88200842ffffff0f837c3e02fc0620032004a741ffffff1f713602f806200341086a200341f8066a200210a681808000200341a0076a200341086a10a581808000200320032903d00720032903c80720032903c0072204421a887c22054219887c2206a741ffffff1f7136029007200320032903b00720032903a80720032903a0072207421a887c22084219887c2209a741ffffff1f7136028007200320032903d8072006421a887c2206a741ffffff0f7136029407200320032903b8072009421a887c2209a741ffffff0f71360284072003200642198820032903e0077c2206a741ffffff1f713602980720032009421988200442ffffff1f837c2204421a88200542ffffff0f837c3e028c0720032004a741ffffff1f713602880720032006421a8820032903e8077c2204a741ffffff0f7136029c072003200442198842137e200742ffffff1f837c2204421a88200842ffffff0f837c3e02fc0620032004a741ffffff1f713602f806200341306a200341f8066a200210a681808000200341d8006a2001200341086a10a68180800020034180016a2001200341306a10a681808000200341a0076a20034180016a10a581808000200320032903d00720032903c80720032903c0072204421a887c22054219887c2206a741ffffff1f713602c001200320032903b00720032903a80720032903a0072207421a887c22084219887c2209a741ffffff1f713602b001200320032903d8072006421a887c2206a741ffffff0f713602c401200320032903b8072009421a887c2209a741ffffff0f713602b4012003200642198820032903e0077c2206a741ffffff1f713602c80120032009421988200442ffffff1f837c2204421a88200542ffffff0f837c3e02bc0120032004a741ffffff1f713602b80120032006421a8820032903e8077c2204a741ffffff0f713602cc012003200442198842137e200742ffffff1f837c2204421a88200842ffffff0f837c3e02ac0120032004a741ffffff1f713602a801200341a0076a200341a8016a10a581808000200320032903d00720032903c80720032903c0072204421a887c22054219887c2206a741ffffff1f7136029007200320032903b00720032903a80720032903a0072207421a887c22084219887c2209a741ffffff1f7136028007200320032903d8072006421a887c2206a741ffffff0f7136029407200320032903b8072009421a887c2209a741ffffff0f71360284072003200642198820032903e0077c2206a741ffffff1f713602980720032009421988200442ffffff1f837c2204421a88200542ffffff0f837c3e028c0720032004a741ffffff1f713602880720032006421a8820032903e8077c2204a741ffffff0f7136029c072003200442198842137e200742ffffff1f837c2204421a88200842ffffff0f837c3e02fc0620032004a741ffffff1f713602f806200341a0076a200341f8066a10a581808000200320032903d00720032903c80720032903c0072204421a887c22054219887c2206a741ffffff1f713602e801200320032903b00720032903a80720032903a0072207421a887c22084219887c2209a741ffffff1f713602d801200320032903d8072006421a887c2206a741ffffff0f713602ec01200320032903b8072009421a887c2209a741ffffff0f713602dc012003200642198820032903e0077c2206a741ffffff1f713602f00120032009421988200442ffffff1f837c2204421a88200542ffffff0f837c3e02e40120032004a741ffffff1f713602e00120032006421a8820032903e8077c2204a741ffffff0f713602f4012003200442198842137e200742ffffff1f837c2204421a88200842ffffff0f837c3e02d40120032004a741ffffff1f713602d001200341f8016a20034180016a200341d0016a10a681808000200341a0026a200341a8016a200341f8016a10a681808000200341a0076a200341a0026a10a581808000200320032903d00720032903c80720032903c0072204421a887c22054219887c2206a741ffffff1f713602e002200320032903b00720032903a80720032903a0072207421a887c22084219887c2209a741ffffff1f713602d002200320032903d8072006421a887c2206a741ffffff0f713602e402200320032903b8072009421a887c2209a741ffffff0f713602d4022003200642198820032903e0077c2206a741ffffff1f713602e80220032009421988200442ffffff1f837c2204421a88200542ffffff0f837c3e02dc0220032004a741ffffff1f713602d80220032006421a8820032903e8077c2204a741ffffff0f713602ec022003200442198842137e200742ffffff1f837c2204421a88200842ffffff0f837c3e02cc0220032004a741ffffff1f713602c802200341f0026a200341f8016a200341c8026a10a68180800020034198036a200341f0026a410510a781808000200341c0036a20034198036a200341f0026a10a681808000200341e8036a200341c0036a410a10a78180800020034190046a200341e8036a200341c0036a10a681808000200341b8046a20034190046a411410a781808000200341e0046a200341b8046a20034190046a10a68180800020034188056a200341e0046a410a10a781808000200341b0056a20034188056a200341c0036a10a681808000200341d8056a200341b0056a413210a78180800020034180066a200341d8056a200341b0056a10a681808000200341a8066a20034180066a41e40010a781808000200341d0066a200341a8066a20034180066a10a681808000200341f8066a200341d0066a413210a781808000200341a0076a200341f8066a200341b0056a10a681808000200341f8066a41206a200341a0076a41206a290200370300200341f8066a41186a200341a0076a41186a290200370300200341f8066a41106a200341a0076a41106a290200370300200341f8066a41086a200341a0076a41086a290200370300200320032902a0073703f806200341a0076a200341f8066a410210a781808000200341d0066a20034180016a200341a0076a10a681808000200341a8066a200341d8006a200341d0066a10a681808000200341a0076a200341a8066a10a581808000200320032903d00720032903c80720032903c0072204421a887c22054219887c2206a741ffffff1f7136029007200320032903b00720032903a80720032903a0072207421a887c22084219887c2209a741ffffff1f7136028007200320032903d8072006421a887c2206a741ffffff0f7136029407200320032903b8072009421a887c2209a741ffffff0f71360284072003200642198820032903e0077c2206a741ffffff1f713602980720032009421988200442ffffff1f837c2204421a88200542ffffff0f837c3e028c0720032004a741ffffff1f713602880720032006421a8820032903e8077c2204a741ffffff0f7136029c072003200442198842137e200742ffffff1f837c2204421a88200842ffffff0f837c3e02fc0620032004a741ffffff1f713602f806200341d0066a2002200341f8066a10a681808000200341f8066a200341d0066a10a381808000200341a0076a200110a381808000410021024101210a0340200341f8066a20026a2d0000200341a0076a20026a2d00004610ad8d808000200a71210a200241016a22024120470d000b200a10ad8d808000210b200341f0ffffff0320012802106bad2204421a8841f0ffffff0120012802146bad7c220542198841f0ffffff0320012802186bad7c2206a741ffffff1f71220c3602b807200341d0fdffff0320012802006bad2207421a8841f0ffffff0120012802046bad7c220842198841f0ffffff0320012802086bad7c2209a741ffffff1f71220d3602a80720032006421a8841f0ffffff01200128021c6bad7c2206a741ffffff0f71220e3602bc0720032009421a8841f0ffffff01200128020c6bad7c2209a741ffffff0f71220f3602ac072003200642198841f0ffffff0320012802206bad7c2206a741ffffff1f7122103602c00720032009421988200442ffffff1f837c2204a741ffffff1f7122113602b00720032004421a88200542ffffff0f837ca722123602b40720032006421a8841f0ffffff0120012802246bad7c2204a741ffffff0f7122013602c4072003200442198842137e200742ffffff1f837c2204a741ffffff1f7122133602a00720032004421a88200842ffffff0f837ca722143602a40720034180066a200341d0066a10a381808000200341f8066a200341a0076a10a381808000410021024101210a034020034180066a20026a2d0000200341f8066a20026a2d00004610ad8d808000200a71210a200241016a22024120470d000b200a10ad8d8080002115200320013602c407200320103602c0072003200e3602bc072003200c3602b807200320123602b407200320113602b0072003200f3602ac072003200d3602a807200320143602a407200320133602a007200341f8066a200341a0076a41d4d2c0800010a681808000200341d8056a200341d0066a10a38180800020034180066a200341f8066a10a381808000410021024101210a0340200341d8056a20026a2d000020034180066a20026a2d00004610ad8d808000200a71210a200241016a22024120470d000b200a10ad8d8080002102200341a0076a41d4d2c08000200341a8066a10a681808000200220157210ad8d8080002102200341b0066a220a20032802a807200a2802002201734100200241ff01716b2202712001732201360200200341b8066a220c20032802b007200c280200220d73200271200d73220d360200200341c0066a220e20032802b807200e280200220f73200271200f73220f360200200320032802ac0720032802b40622107320027120107322103602b406200320032802a40720032802ac0622117320027120117322113602ac06200320032802a00720032802a80622127320027120127322123602a806200320032802b40720032802bc0622137320027120137322133602bc06200320032802bc0720032802c40622147320027120147322143602c406200341c8066a221620032802c00720162802002217732002712017732217360200200320032802c40720032802cc0622187320027120187322183602cc06200341f8066a200341a8066a10a381808000201641f0ffffff03200d6bad2204421a8841f0ffffff0120136bad7c220542198841f0ffffff03200f6bad7c2206421a8841f0ffffff0120146bad7c220742198841f0ffffff0320176bad7c2208a741ffffff1f71201773410020032d00f80641017110ad8d80800041ff01716b220271201773360200200e2006a741ffffff1f71200f73200271200f73360200200c200442ffffff1f8341d0fdffff0320126bad2204421a8841f0ffffff0120116bad7c220642198841f0ffffff0320016bad7c2209421a8841f0ffffff0120106bad7c22194219887c221aa741ffffff1f71200d73200271200d73360200200a2009a741ffffff1f7120017320027120017336020020032008421a8841f0ffffff0120186bad7c2208a741ffffff0f712018732002712018733602cc0620032007a741ffffff0f712014732002712014733602c40620032013200542ffffff0f83201a421a887ca7732002712013733602bc0620032019a741ffffff0f712010732002712010733602b4062003200842198842137e200442ffffff1f837c2204a741ffffff1f712012732002712012733602a806200320112004421a88200642ffffff0f837ca7732002712011733602ac0620002015200b7210ad8d8080003a0000200041246a20162902003702002000411c6a200e290200370200200041146a200c2902003702002000410c6a200a290200370200200020032902a806370204200341f0076a2480808080000bcd0412017f017e017f017e017f017e017f017e017f017e017f017e017f017e017f017e017f0c7e2000200128020c2202ad220320012802002204410174ad22057e20012802042206410174ad220720012802082208ad22097e7c2001280220220a41136cad220b2001280214220c410174ad220d7e7c2001280224220e41136cad220f20012802102210ad22117e200128021c221241136cad221320012802182201ad22147e7c4201867c3703182000200141136cad2215200d7e20052006ad22167e7c200b2002410174ad22177e7c200f20097e201320117e7c4201867c3703082000201420177e2010410174ad2218200cad22197e7c2012ad221a2008410174ad221b7e7c200aad221c20077e7c200ead221d20057e7c37034820002019201b7e201720117e7c201420077e7c201a20057e7c201c200f7e4201867c3703382000201120077e201b20037e7c201920057e7c200b2012410174ad221e7e7c2014200f7e4201867c3703282000201720077e200920097e7c201120057e7c200b2001410174ad7e7c200f200d7e2013201a7e7c4201867c3703202000200920057e200720167e7c201520147e7c200b20187e7c200f20177e2013200d7e7c4201867c3703102000201520187e2004ad220920097e7c200b201b7e7c201320177e200c41136cad20197e7c200f20077e7c4201867c37030020002014201b7e201120117e7c200d20177e7c201e20077e7c201c20057e7c201d200f7e4201867c3703402000201720037e2011201b7e7c200d20077e7c201420057e7c200b201c7e7c201e200f7e4201867c3703300bc7081a017f017e017f017e017f017e017f017e017f017e017f017e017f017e017f027e017f017e017f017e017f027e017f027e017f147e2000200128020c2203410174ad2204200228020c2205ad22067e20012802042207410174ad220820022802142209ad220a7e7c2001280214220b410174ad220c2002280204220dad220e7e7c200128021c220f410174ad22102002280224221141136cad22127e7c2001350200221320022802182214ad22157e7c20012802242216410174ad2217200228021c221841136cad22197e7c2001350208221a2002280210221bad221c7e7c2001350210221d2002280208221ead221f7e7c20013502182220200235020022217e7c200135022022222002280220220241136cad22237e7c2003ad2224201f7e2007ad2225201c7e7c200fad222620237e7c2016ad2227201441136cad22287e7c2013200a7e7c2021200bad22297e7c201a20067e7c201d200e7e7c202020127e7c202220197e7c2004200e7e200820067e7c200c20127e7c201020197e7c2013201c7e7c2017200941136cad222a7e7c201a201f7e7c201d20217e7c202020237e7c202220287e7c222b421a887c222c4219887c222da741ffffff1f713602182000200420127e2008200e7e7c200c20197e7c2010202a7e7c2013201f7e7c2017200541136cad222e7e7c201a20217e7c201d20237e7c202020287e7c2022201b41136cad222f7e7c202920287e202420237e7c2026202f7e7c2027201e41136cad22307e7c2013200e7e7c202120257e7c201a20127e7c201d20197e7c2020202a7e7c2022202e7e7c200420197e200820127e7c200c202a7e7c2010202e7e7c2017200d41136cad7e7c202120137e7c201a20237e7c201d20287e7c2020202f7e7c202220307e7c2230421a887c22314219887c2232a741ffffff1f7136020820002024201c7e202520157e7c2029201f7e7c202720237e7c20132018ad222e7e7c202120267e7c201a200a7e7c201d20067e7c2020200e7e7c202220127e7c202d421a887c222da741ffffff0f7136021c2000202920237e2025201f7e7c202620287e7c2027202f7e7c201320067e7c202120247e7c201a200e7e7c201d20127e7c202020197e7c2022202a7e7c2032421a887c2223a741ffffff0f7136020c20002004200a7e2008202e7e7c200c20067e7c2010200e7e7c20132002ad22197e7c201720127e7c201a20157e7c201d201c7e7c2020201f7e7c202220217e7c202d4219887c2212a741ffffff1f7136022020002023421988202b42ffffff1f837c2223421a88202c42ffffff0f837c3e021420002023a741ffffff1f713602102000202420157e202520197e7c2029201c7e7c2026201f7e7c20132011ad7e7c202120277e7c201a202e7e7c201d200a7e7c202020067e7c2022200e7e7c2012421a887c2213a741ffffff0f713602242000201342198842137e203042ffffff1f837c2213421a88203142ffffff0f837c3e020420002013a741ffffff1f713602000be20502017f067e2380808080004180016b2203248080808000200341306a200110a58180800020032003290360200329035820032903502204421a887c22054219887c2206a741ffffff1f7136022020032003290340200329033820032903302207421a887c22084219887c2209a741ffffff1f71360210200320032903682006421a887c2206a741ffffff0f71360224200320032903482009421a887c2209a741ffffff0f713602142003200642198820032903707c2206a741ffffff1f7136022820032009421988200442ffffff1f837c2204421a88200542ffffff0f837c3e021c20032004a741ffffff1f7136021820032006421a8820032903787c2204a741ffffff0f7136022c2003200442198842137e200742ffffff1f837c2204421a88200842ffffff0f837c3e020c20032004a741ffffff1f71360208024020024102490d002002417f6a21020340200341306a200341086a10a58180800020032003290360200329035820032903502204421a887c22054219887c2206a741ffffff1f7136022020032003290340200329033820032903302207421a887c22084219887c2209a741ffffff1f71360210200320032903682006421a887c2206a741ffffff0f71360224200320032903482009421a887c2209a741ffffff0f713602142003200642198820032903707c2206a741ffffff1f7136022820032009421988200442ffffff1f837c2204421a88200542ffffff0f837c3e021c20032004a741ffffff1f7136021820032006421a8820032903787c2204a741ffffff0f7136022c2003200442198842137e200742ffffff1f837c2204421a88200842ffffff0f837c3e020c20032004a741ffffff1f713602082002417f6a22020d000b0b20002003290208370200200041206a200341086a41206a290200370200200041186a200341086a41186a290200370200200041106a200341086a41106a290200370200200041086a200341086a41086a29020037020020034180016a2480808080000be103020e7f067e20022802242103200128022421042002280220210520012802202106200228020c2107200128020c2108200228021c2109200128021c210a2002280208210b2001280208210c2002280204210d2001280204210e2002280200210f200128020021102000200128021020022802106b41f0ffffff036aad2211421a88200128021420022802146b41f0ffffff016aad7c2212421988200128021820022802186b41f0ffffff036aad7c2213a741ffffff1f7136021820002010200f6b41d0fdffff036aad2214421a88200e200d6b41f0ffffff016aad7c2215421988200c200b6b41f0ffffff036aad7c2216a741ffffff1f7136020820002013421a88200a20096b41f0ffffff016aad7c2213a741ffffff0f7136021c20002016421a88200820076b41f0ffffff016aad7c2216a741ffffff0f7136020c20002013421988200620056b41f0ffffff036aad7c2213a741ffffff1f7136022020002016421988201142ffffff1f837c2211421a88201242ffffff0f837c3e021420002011a741ffffff1f7136021020002013421a88200420036b41f0ffffff016aad7c2211a741ffffff0f713602242000201142198842137e201442ffffff1f837c2211421a88201542ffffff0f837c3e020420002011a741ffffff1f713602000beb0201067e200041f0ffffff0320012802106bad2202421a8841f0ffffff0120012802146bad7c220342198841f0ffffff0320012802186bad7c2204a741ffffff1f71360218200041d0fdffff0320012802006bad2205421a8841f0ffffff0120012802046bad7c220642198841f0ffffff0320012802086bad7c2207a741ffffff1f7136020820002004421a8841f0ffffff01200128021c6bad7c2204a741ffffff0f7136021c20002007421a8841f0ffffff01200128020c6bad7c2207a741ffffff0f7136020c2000200442198841f0ffffff0320012802206bad7c2204a741ffffff1f7136022020002007421988200242ffffff1f837c2202421a88200342ffffff0f837c3e021420002002a741ffffff1f7136021020002004421a8841f0ffffff0120012802246bad7c2202a741ffffff0f713602242000200242198842137e200542ffffff1f837c2202421a88200642ffffff0f837c3e020420002002a741ffffff1f713602000be00302187e017f20013100052102200131000421032001310015210420013100142105200131000821062001310007210720013100062108200131000b2109200131000a210a2001310009210b200131000f210c200131000e210d200131000d210e200131000c210f200131001821102001310017211120013100162112200131001b2113200131001a211420013100192115200131001f2116200131001e2117200131001d2118200131001c21192001280000211a20002001280010220141ffffff0f713602142000201a41ffffff1f7136020020002016421286428080f00f8320184202862019420688842017420a8684843e022420002019421486428080c01f8320144204862015420488842013420c8684843e022020002015421586428080800f8320114205862012420388842010420d8684843e021c2000200e420286200f42068884200d420a8684200c421286843e02102000200f421386428080e00f83200a420386200b420588842009420b8684843e020c2000200b421586428080801f8320074205862008420388842006420d8684843e020820002012421786428080801c8320054207862001411976ad842004420f8684843e021820002008421686428080800e832003420686201a411a76ad842002420e8684843e02040bfe0c0a017f027e017f017e017f017e017f027e017f157e23808080800041f0006b2202248080808000200241046a200110ae8180800020022002350214220342ecf3b78a037e20022802082201ad220442e7e2e4b3017e20022802042205ad220642eecaf5ff017e7c200228020c2207ad2208428c93f0fb007e7c20022802102209ad220a4283e685d3017e7c200342edf3b78a017e7c220b7d2002280218220c20056aad220d42eecaf5ff017e7c200228021c220520016aad220e42e6e2a4b4017e7c2002280220220120076aad220f428b93f0fb027e7c20022802242207ad221042ffffffff017e22112001ad221242ffffffff017e22137c22142005ad221542ffff3f7e7c22167d200720096aad22174282e685d3037e7c200642ff037e42ffffffff0183221842d2b1cc047e200442edf3b78a017e20064283e685d3017e7c22197c201842eda7d7e7017e200642edf3b78a017e221a7c421d887c221b429bfcd192017e42ffffffff0183221c4214867c200842e7e2e4b3017e200442eecaf5ff017e7c200a428c93f0fb007e7c20034283e685d3017e7c200cad221d42ffffffff017e221e7d221f201a7d200d42ecf3b78a037e7c201c42cd027e7c20044283e685d3017e2006428c93f0fb007e7c200842edf3b78a017e7c222020184296eb9cef017e7c201c42d2b1cc047e7c201c42eda7d7e7017e201b7c421d887c221b429bfcd192017e42ffffffff0183221a42c5faceef017e7c2004428c93f0fb007e200642e7e2e4b3017e7c20084283e685d3017e7c200a42edf3b78a017e7c2221201842c5faceef017e7c201c4296eb9cef017e7c201a42d2b1cc047e7c201a42eda7d7e7017e201b7c421d887c2204429bfcd192017e42ffffffff018322064296eb9cef017e7c200b201842cd027e7c201c42c5faceef017e7c201a4296eb9cef017e7c200642d2b1cc047e7c200642eda7d7e7017e20047c421d887c2204429bfcd192017e42ffffffff0183221c42d2b1cc047e7c201c42eda7d7e7017e20047c421d887c220b429bfcd192017e42ffffffff0183220442cd027e7c200d4282e685d3037e20197d200e42ecf3b78a037e7c200a42e7e2e4b3017e200842eecaf5ff017e7c2003428c93f0fb007e7c201542ffffffff017e2215201e7c22197d221b7c201a42cd027e7c200642c5faceef017e7c201c4296eb9cef017e7c200442d2b1cc047e7c200442eda7d7e7017e200b7c421d887c220b429bfcd192017e42ffffffff0183220842c5faceef017e7c200d428b93f0fb027e20207d200e4282e685d3037e7c200f42ecf3b78a037e7c200342e7e2e4b3017e200a42eecaf5ff017e7c201320197c7d22137c200642cd027e7c201c42c5faceef017e7c20044296eb9cef017e7c200842d2b1cc047e7c200842eda7d7e7017e200b7c421d887c220b429bfcd192017e42ffffffff0183220a4296eb9cef017e7c201842148620217d200342eecaf5ff017e7c200d42e6e2a4b4017e7c200e428b93f0fb027e7c200f4282e685d3037e7c2014201d42ffff3f7e7c20157c220d7d201742ecf3b78a037e7c201c42cd027e7c200442c5faceef017e7c20084296eb9cef017e7c200a42d2b1cc047e7c200a42eda7d7e7017e200b7c421d887c220b429bfcd192017e42ffffffff0183221842d2b1cc047e7c201842eda7d7e7017e200b7c421d887c220ba741ffffffff017136024c200220034282e685d3037e201f7d200e42eecaf5ff017e7c200f42e6e2a4b4017e7c2011201242ffff3f7e7c220e7d2017428b93f0fb027e7c201a4214867c200842cd027e7c200a42c5faceef017e7c20184296eb9cef017e7c200b421d887c221aa741ffffffff017136025020022003428b93f0fb027e201b201042ffff3f7e220b7c7d200f42eecaf5ff017e7c201742e6e2a4b4017e7c20064214867c200a42cd027e7c201842c5faceef017e7c201a421d887c2206a741ffffffff01713602542002200342e6e2a4b4017e20137d201742eecaf5ff017e7c201c4214867c201842cd027e7c2006421d887c2203a741ffffffff017136025820022004421486200d7c2003421d887c2203a741ffffffff017136025c2002200842148620167c2003421d887c2203a741ffffffff01713602602002200a421486200e7c2003421d887c2203a741ffffffff017136026420022018421486200b7c2003421d887c2203421d883e026c20022003a741ffffffff0171360268200241286a200241cc006a41fcd2c0800010ad818080002000200241286a10ac81808000200241f0006a2480808080000b950301077f2000200128022022023a001d2000200128020022033a0000200020024110763a001f200020024108763a001e2000200128021c22044115763a001c20002004410d763a001b200020044105763a001a2000200128021822024112763a001820002002410a763a0017200020024102763a0016200020012802142205410f763a0014200020054107763a00132000200128021022064114763a001120002006410c763a0010200020064104763a000f2000200128020c22074111763a000d200020074109763a000c200020074101763a000b200020012802082208410e763a0009200020084106763a00082000200128020422014113763a000620002001410b763a0005200020014103763a0004200020034110763a0002200020034108763a0001200020044103742002411a76723a0019200020024106742005411776723a0015200020054101742006411c76723a0012200020064104742007411976723a000e200020074107742008411676723a000a200020084102742001411b76723a0007200020014105742003411876723a00030bcd04010e7f23808080800041106b2203200128022020022802206b200128021c200228021c6b200128021820022802186b200128021420022802146b200128021020022802106b200128020c200228020c6b200128020820022802086b200128020020022802006b2204411f7520012802046a20022802046b2201411f756a2205411f756a2206411f756a2207411f756a2208411f756a2209411f756a220a411f756a220b411f75220236020c200328020c210c2003200236020c200328020c210d2003200236020c200328020c210e2003200236020c200328020c210f2003200236020c200328020c21102003200236020c200328020c1a2003200236020c200328020c1a2003200236020c200328020c1a2003200236020c200328020c21032000200c41eda7d7e70171200441ffffffff01716a2202411d76200141ffffffff01716a200d41d2b1cc04716a2201411d76200541ffffffff01716a200e4196eb9cef01716a2204411d76200641ffffffff01716a200f41c5faceef01716a2205411d76200741ffffffff01716a201041cd02716a2206411d76200841ffffffff01716a2207411d76200941ffffffff01716a2208411d76200a41ffffffff01716a220941ffffffff017136021c2000200841ffffffff01713602182000200741ffffffff01713602142000200641ffffffff01713602102000200541ffffffff017136020c2000200441ffffffff01713602082000200141ffffffff01713602042000200241ffffffff017136020020002009411d76200b6a2003418080c000716a41ffffffff01713602200bd50301187f20012f0004210220012d0006210320012d0018210420012d0016210520012d0017210620012f0008210720012d0007210820012f000c210920012d000b210a20012d000a210b20012f0010210c20012d000f210d20012d000e210e20012d0014210f20012d0015211020012d0013211120012d0012211220012d001c211320012d0019211420012d001a211520012d001b211620012f0000211720012d0002211820012d00032119200020012f001d20012d001f41107472360220200020172018411074722019411874220141808080f80171723602002000201341157420154110742016411874722014410874221372410b767236021c2000200f2010410874221072410f7420114118742012411074220f724111767241ffffffff01713602142000200c200f72410c74200d411874200e411074220c724114767241ffffffff017136021020002009200c72410974200a411874200b4110742209724117767241ffffffff017136020c2000200720097241067420084118742207411a767241ffffffff0171360208200020132004724112742005411074200641187472201072410e767241ffffffff0171360218200020022003411074722007724103742001411d767241ffffffff01713602040bcf08011b7f23808080800041a0026b22032480808080002001412c6a2802002104200141306a2802002105200141346a2802002106200141386a28020021072001413c6a2802002108200141c0006a2802002109200141c4006a280200210a200141c8006a280200210b200141cc006a280200210c2001280204210d2001280208210e200128020c210f200128021021102001280214211120012802182112200128021c211320012802202114200128022421152003200128020020012802286a36020820032015200c6a36022c20032014200b6a36022820032013200a6a3602242003201220096a3602202003201120086a36021c2003201020076a3602182003200f20066a3602142003200e20056a3602102003200d20046a36020c200341306a200141286a200110a881808000200341d8006a200341086a200210a68180800020034180016a200341306a200241286a10a681808000200341a8016a200141f8006a200241f8006a10a681808000200341d0016a200141d0006a200241d0006a10a681808000200320032802d00141017422013602f801200320032802d40141017422023602fc01200320032802d801410174220436028002200320032802dc01410174220536028402200320032802e001410174220636028802200320032802e401410174220736028c02200320032802e801410174220836029002200320032802ec01410174220936029402200320032802f001410174220a36029802200320032802f401410174220b36029c022000200341d8006a20034180016a10a881808000200328028001210c2003280258210d200328028401210e200328025c210f200328028801211020032802602111200328028c012112200328026421132003280290012114200328026821152003280294012116200328026c2117200328029801211820032802702119200328029c01211a2003280274211b20032802a001211c2003280278211d200041cc006a20032802a401200328027c6a360200200041c8006a201c201d6a360200200041c4006a201a201b6a360200200041c0006a201820196a3602002000413c6a201620176a360200200041386a201420156a360200200041346a201220136a360200200041306a201020116a3602002000412c6a200e200f6a3602002000200c200d6a36022820032802a801210c20032802ac01210d20032802b001210e20032802b401210f20032802b801211020032802bc01211120032802c001211220032802c401211320032802c8012114200041f4006a20032802cc01200b6a360200200041f0006a2014200a6a360200200041ec006a201320096a360200200041e8006a201220086a360200200041e4006a201120076a360200200041e0006a201020066a360200200041dc006a200f20056a360200200041d8006a200e20046a360200200041d4006a200d20026a3602002000200c20016a360250200041f8006a200341f8016a200341a8016a10a881808000200341a0026a2480808080000ba40401137f23808080800041c0026b22032480808080002002412c6a2802002104200241306a2802002105200241346a2802002106200241386a28020021072002413c6a2802002108200241c0006a2802002109200241c4006a280200210a200241c8006a280200210b2002280200210c2002280228210d2002280204210e2002280208210f200228020c2110200228021021112002280214211220022802182113200228021c21142002280220211520032002280224200241cc006a2802006a3602c40120032015200b6a3602c00120032014200a6a3602bc012003201320096a3602b8012003201220086a3602b4012003201120076a3602b0012003201020066a3602ac012003200f20056a3602a8012003200e20046a3602a4012003200c200d6a3602a001200341a0016a41286a200241286a200210a881808000200341a0016a41f0006a200241f0006a290200370200200341a0016a41e8006a200241e8006a290200370200200341a0016a41e0006a200241e0006a290200370200200341a0016a41d8006a200241d8006a290200370200200320022902503702f001200341a0016a41f8006a200241f8006a41a0d3c0800010a68180800020032001200341a0016a10af8180800020002003200341f8006a220210a681808000200041286a200341286a2201200341d0006a220410a681808000200041d0006a2004200210a681808000200041f8006a2003200110a681808000200341c0026a2480808080000bae0201047f23808080800041f0026b2202248080808000200241cc016a200110b681808000200241086a200241d8016a290200370300200241106a200241e0016a290200370300200241186a200241e8016a290200370300200241206a200241f0016a290200370300200220022902d00137030041002101024020022d00cd0120022d00cc01417f7341017110ad8d8080007210ad8d80800041ff01710d00200241cc016a200210b78180800020022d00ce01210320022d00cd01210420022d00cc012105200241286a200241cc016a41046a41a00110848e8080001a200320042005417f7341017110ad8d8080007210ad8d8080007210ad8d80800041ff01710d00200041046a200241286a41a00110848e8080001a410121010b20002001360200200241f0026a2480808080000bb1160a067f017e017f017e017f017e017f027e0d7f017e23808080800041e0046b2202248080808000200241086a41206a2203200141206a290200370300200241086a41186a2204200141186a290200370300200241086a41106a2205200141106a290200370300200241086a41086a2206200141086a29020037030020022001290200370308200241306a41206a2207200141c8006a2902002208370300200241306a41186a2209200141c0006a290200220a370300200241306a41106a220b200141386a290200220c370300200241306a41086a220d200141306a290200220e37030020022001290228220f370330200141d4006a2802002110200141d8006a2802002111200141dc006a2802002112200141e0006a2802002113200141e4006a2802002114200141e8006a2802002115200141ec006a2802002116200141f0006a28020021172001280250211820022802342119200228023c211a2002280244211b200228024c211c20022002280254200141f4006a2802006a36028c04200220172008a76a360288042002201c20166a3602840420022015200aa76a360280042002201b20146a3602fc0320022013200ca76a3602f8032002201a20126a3602f40320022011200ea76a3602f0032002201920106a3602ec0320022018200fa76a3602e80320024190046a200141d0006a2214200241306a10a881808000200241d8006a200241e8036a20024190046a10a68180800020024180016a200241086a200241306a10a68180800020024190046a20024180016a10a581808000200220022903c00420022903b80420022903b0042208421a887c220a4219887c220ca741ffffff1f7136028004200220022903a004200229039804200229039004220e421a887c220f4219887c221da741ffffff1f713602f003200220022903c804200c421a887c220ca741ffffff0f7136028404200220022903a804201d421a887c221da741ffffff0f713602f4032002200c42198820022903d0047c220ca741ffffff1f71360288042002201d421988200842ffffff1f837c2208421a88200a42ffffff0f837c3e02fc0320022008a741ffffff1f713602f8032002200c421a8820022903d8047c2208a741ffffff0f7136028c042002200842198842137e200e42ffffff1f837c2208421a88200f42ffffff0f837c3e02ec0320022008a741ffffff1f713602e803200241c0036a200241d8006a200241e8036a10a68180800020024190046a41acd2c08000200241c0036a10a481808000200241a8016a41206a200241b4046a290200370300200241a8016a41186a200241ac046a290200370300200241a8016a41106a200241a4046a290200370300200241a8016a41086a2002419c046a29020037030020022002290294043703a801200241d0016a200241a8016a200241d8006a10a681808000200241f8016a200241a8016a20024180016a10a68180800020024190046a200241f8016a200141f8006a220110a681808000200241a0026a200241d0016a20024190046a10a681808000200241c8026a41206a2210200241f8016a41206a290200370300200241c8026a41186a2211200241f8016a41186a290200370300200241c8026a41106a2212200241f8016a41106a290200370300200241c8026a41086a2213200241f8016a41086a290200370300200220022902f8013703c802200241f0026a200241086a4198d4c0800010a68180800020024198036a200241306a4198d4c0800010a681808000200241c0036a200241d0016a41c0d4c0800010a68180800020024190046a2001200241a0026a10a681808000200241e8036a20024190046a10a38180800020022d00e80341017110ad8d8080002101200620022802a00320062802002215734100200141ff01716b220171201573360200200520022802a8032005280200220673200171200673360200200220022802980320022802082205732001712005733602082002200228029c03200228020c22057320017120057336020c200220022802a4032002280214220573200171200573360214200220022802ac03200228021c22057320017120057336021c200420022802b0032004280200220573200171200573360200200220022802b4032002280224220473200171200473360224200320022802b8032003280200220473200171200473360200200220022802bc03200228022c22037320017120037336022c200220022802f0022002280230220373200171200373360230200220022802f4022002280234220373200171200373360234200d20022802f802200d280200220373200171200373360200200220022802fc02200228023c22037320017120037336023c200b200228028003200b28020022037320017120037336020020022002280284032002280244220373200171200373360244200920022802880320092802002203732001712003733602002002200228028c03200228024c22037320017120037336024c2007200228029003200728020022037320017120037336020020022002280294032002280254220373200171200373360254200220022802c00320022802c8022203732001712003733602c802200220022802c40320022802cc022203732001712003733602cc02201320022802c8032013280200220373200171200373360200200220022802cc0320022802d4022203732001712003733602d402201220022802d0032012280200220373200171200373360200200220022802d40320022802dc022203732001712003733602dc02201120022802d8032011280200220373200171200373360200200220022802dc0320022802e4022203732001712003733602e402201020022802e0032010280200220373200171200373360200200220022802e40320022802ec022203732001712003733602ec02200241e8036a200241086a200241a0026a10a68180800020024190046a200241e8036a10a38180800020022d00900441017110ad8d808000210120024190046a200241306a10a981808000200d200228029804200d2802002203734100200141ff01716b220171200373360200200b20022802a004200b280200220d73200171200d73360200200920022802a8042009280200220b73200171200b7336020020022002280290042002280230220973200171200973360230200220022802940420022802342209732001712009733602342002200228029c04200228023c22097320017120097336023c200220022802a4042002280244220973200171200973360244200220022802ac04200228024c22097320017120097336024c200720022802b0042007280200220973200171200973360200200220022802b404200228025422077320017120077336025420024190046a2014200241306a10a881808000200241e8036a200241c8026a20024190046a10a68180800020024190046a200241e8036a10a38180800020022d00900441017110ad8d808000210120024190046a200241e8036a10a981808000200220022802900420022802e8032207734100200141ff01716b2201712007733602e803200220022802940420022802ec032207732001712007733602ec03200220022802980420022802f0032207732001712007733602f0032002200228029c0420022802f4032207732001712007733602f403200220022802a00420022802f8032207732001712007733602f803200220022802a40420022802fc032207732001712007733602fc03200220022802a80420022802800422077320017120077336028004200220022802ac0420022802840422077320017120077336028404200220022802b00420022802880422077320017120077336028804200220022802b404200228028c0422077320017120077336028c042000200241e8036a10a381808000200241e0046a2480808080000bee1803097f067e0e7f2380808080004180066b2202248080808000200241086a41206a22034100290290d4c08000370300200241086a41186a22044100290288d4c08000370300200241086a41106a22054100290280d4c08000370300200241086a41086a220641002902f8d3c08000370300200241002902f0d3c08000370308200241306a41206a220741002902e8d3c08000370300200241306a41186a220841002902e0d3c08000370300200241306a41106a220941002902d8d3c08000370300200241306a41086a220a41002902d0d3c08000370300200241002902c8d3c0800037033020024190046a200110a581808000200220022903c00420022903b80420022903b004220b421a887c220c4219887c220da741ffffff1f7136028803200220022903a004200229039804200229039004220e421a887c220f4219887c2210a741ffffff1f713602f802200220022903c804200d421a887c220da741ffffff0f7136028c03200220022903a8042010421a887c2210a741ffffff0f713602fc022002200d42198820022903d0047c220da741ffffff1f713602900320022010421988200b42ffffff1f837c220b421a88200c42ffffff0f837c3e0284032002200ba741ffffff1f71360280032002200d421a8820022903d8047c220ba741ffffff0f71360294032002200b42198842137e200e42ffffff1f837c220b421a88200f42ffffff0f837c3e02f4022002200ba741ffffff1f713602f002200241d8006a4198d4c08000200241f0026a10a681808000200a280200210a2009280200210920082802002108200728020021072002280258211120022802302112200228025c2113200228023421142002280260211520022802642116200228023c211720022802682118200228026c21192002280244211a2002280270211b2002280274211c200228024c211d2002280278211e20022002280254200228027c6a3602b40420022007201e6a3602b0042002201d201c6a3602ac0420022008201b6a3602a8042002201a20196a3602a4042002200920186a3602a0042002201720166a36029c042002200a20156a360298042002201420136a360294042002201220116a3602900420024180016a20024190046a41e8d4c0800010a681808000200241f0026a4190d5c08000200241d8006a10a681808000200241d8056a200241086a200241f0026a10a8818080002002200228027c41b39ba00a6a3602b4042002200228027841ffed8a176a3602b004200220022802744198e3b90e6a3602ac042002200228027041bbf9801d6a3602a8042002200228026c4198d1e70b6a3602a4042002200228026841a980076a3602a00420022002280264418e94a8036a36029c042002200228026041bdddd5186a360298042002200228025c4184e5cd066a360294042002200228025841a3f1e51a6a36029004200241a8016a200241d8056a20024190046a10a68180800020024190046a20024180016a200241a8016a10a48180800020022d0090042111200241d0016a41206a2207200241b4046a290200370300200241d0016a41186a2208200241ac046a290200370300200241d0016a41106a2209200241a4046a290200370300200241d0016a41086a220a2002419c046a29020037030020022002290294043703d001200241f8016a200241d0016a200110a68180800020024190046a200241f8016a10a38180800020022d00900441017110ad8d808000417f7341017110ad8d808000210120024190046a200241f8016a10a981808000200220022802900420022802f8012212734100200141ff01716b2201712012733602f801200220022802940420022802fc012212732001712012733602fc012002200228029804200228028002221273200171201273360280022002200228029c0420022802840222127320017120127336028402200220022802a00420022802880222127320017120127336028802200220022802a404200228028c0222127320017120127336028c02200220022802a80420022802900222127320017120127336029002200220022802ac0420022802940222127320017120127336029402200220022802b00420022802980222127320017120127336029802200220022802b404200228029c0222127320017120127336029c022011417f73410171221110ad8d8080002101200a200228028002200a2802002212734100200141ff01716b2201712012733602002009200228028802200928020022127320017120127336020020082002280290022008280200221273200171201273360200200220022802f80120022802d0012212732001712012733602d001200220022802fc0120022802d4012212732001712012733602d401200220022802840220022802dc012212732001712012733602dc012002200228028c0220022802e4012212732001712012733602e401200220022802940220022802ec012212732001712012733602ec01200720022802980220072802002212732001712012733602002002200228029c0220022802f4012212732001712012733602f401201110ad8d80800021012006200228026020062802002211734100200141ff01716b2201712011733602002005200228026820052802002206732001712006733602002004200228027020042802002205732001712005733602002002200228025820022802082204732001712004733602082002200228025c200228020c22047320017120047336020c2002200228026420022802142204732001712004733602142002200228026c200228021c22047320017120047336021c2002200228027420022802242204732001712004733602242003200228027820032802002204732001712004733602002002200228027c200228022c22037320017120037336022c20024190046a200241d8006a200241306a10a881808000200241f0026a200241086a20024190046a10a681808000200241d8056a200241f0026a41b8d5c0800010a681808000200241a0026a200241d8056a200241a8016a10a88180800020024190046a200241d0016a10a581808000200220022903c00420022903b80420022903b004220b421a887c220c4219887c220da741ffffff1f713602e002200220022903a004200229039804200229039004220e421a887c220f4219887c2210a741ffffff1f713602d002200220022903c804200d421a887c220da741ffffff0f713602e402200220022903a8042010421a887c2210a741ffffff0f713602d4022002200d42198820022903d0047c220da741ffffff1f713602e80220022010421988200b42ffffff1f837c220b421a88200c42ffffff0f837c3e02dc022002200ba741ffffff1f713602d8022002200d421a8820022903d8047c220ba741ffffff0f713602ec022002200b42198842137e200e42ffffff1f837c220b421a88200f42ffffff0f837c3e02cc022002200ba741ffffff1f713602c802200220022802f4014101743602fc05200220072802004101743602f805200220022802ec014101743602f405200220082802004101743602f005200220022802e4014101743602ec05200220092802004101743602e805200220022802dc014101743602e4052002200a2802004101743602e005200220022802d4014101743602dc05200220022802d0014101743602d805200241b0056a200241d8056a200241a8016a10a681808000200241f0026a200241a0026a41e0d5c0800010a68180800020024190046a41286a220141c8d3c08000200241c8026a10a881808000200241ac056a20022802ec02360200200241a4056a20022902e4023702002002419c056a20022902dc0237020020024194056a20022902d4023702002002418c056a20022902cc0237020020024190046a41086a200241b0056a41086a29020037030020024190046a41106a200241b0056a41106a29020037030020024190046a41186a200241b0056a41186a29020037030020024190046a41206a200241b0056a41206a290200370300200220022902b00537039004200220022802c80241016a3602880520024180056a200241f0026a41206a290200370300200241f8046a200241f0026a41186a290200370300200241f0046a200241f0026a41106a290200370300200241e8046a200241f0026a41086a290200370300200220022902f0023703e004200241f0026a20024190046a20024190046a41f8006a220710a681808000200241f0026a41286a200120024190046a41d0006a220810a681808000200241f0026a41d0006a2008200710a681808000200241f0026a41f8006a20024190046a200110a6818080002000200241f0026a41a00110848e8080001a20024180066a2480808080000bf90101017f23808080800041d0036b2202248080808000200241186a200141186a290000370300200241106a200141106a290000370300200241086a200141086a29000037030020022001290000370300200241206a200210aa81808000200241c8006a200241206a10b381808000200241e8016a41186a200141386a290000370300200241e8016a41106a200141306a290000370300200241e8016a41086a200141286a290000370300200220012900203703e80120024188026a200241e8016a10aa81808000200241b0026a20024188026a10b3818080002000200241c8006a200241b0026a10b081808000200241d0036a2480808080000bbf0201037f23808080800041e0016b220224808080800020022000200141286a220310a681808000200241286a200041286a2204200110a681808000200241d0006a2000200110a681808000200241f8006a2004200310a681808000200241a0016a200210a381808000200241c0016a200241286a10a38180800041002101410121000340200241a0016a20016a2d0000200241c0016a20016a2d00004610ad8d8080002000712100200141016a22014120470d000b200010ad8d8080002103200241a0016a200241d0006a10a381808000200241c0016a200241f8006a10a38180800041002101410121000340200241a0016a20016a2d0000200241c0016a20016a2d00004610ad8d8080002000712100200141016a22014120470d000b200010ad8d80800020037210ad8d8080002101200241e0016a24808080800020010bf80101037f23808080800041f0006b2202248080808000200241086a200110aa81808000200241306a200241086a10a38180800041002103410121040340200241306a20036a2d0000200120036a2d00004610ad8d8080002004712104200341016a22034120470d000b200410ad8d8080002103200241d0006a200241086a10a38180800020022d005041017110ad8d8080002104200041246a200241286a2902003702002000411c6a200241206a290200370200200041146a200241186a2902003702002000410c6a200241106a29020037020020002002290208370204200020043a0001200020033a0000200241f0006a2480808080000bd51503067f067e0e7f23808080800041a0066b220224808080800041002103200241206a220441002902a8d6c08000370300200241186a220541002902a0d6c08000370300200241106a22064100290298d6c08000370300200241086a22074100290290d6c0800037030020024100290288d6c0800037030020024180056a200110a581808000200220022903b00520022903a80520022903a0052208421a887c22094219887c220aa741ffffff1f713602402002200229039005200229038805200229038005220b421a887c220c4219887c220da741ffffff1f71360230200220022903b805200a421a887c220aa741ffffff0f713602442002200229039805200d421a887c220da741ffffff0f713602342002200a42198820022903c0057c220aa741ffffff1f713602482002200d421988200842ffffff1f837c2208421a88200942ffffff0f837c3e023c20022008a741ffffff1f713602382002200a421a8820022903c8057c2208a741ffffff0f7136024c2002200842198842137e200b42ffffff1f837c2208421a88200c42ffffff0f837c3e022c20022008a741ffffff1f71360228200241d0006a2002200241286a10a881808000200728020021072006280200210620052802002105200428020021042002280200210e2002280228210f20022802042110200228022c211120022802302112200228020c2113200228023421142002280238211520022802142116200228023c211720022802402118200228021c21192002280244211a2002280248211b2002200228024c20022802246a36029c012002201b20046a360298012002201a20196a360294012002201820056a360290012002201720166a36028c012002201520066a360288012002201420136a360284012002201220076a360280012002201120106a36027c2002200f200e6a36027820024180056a200241f8006a10a581808000200220022903b00520022903a80520022903a0052208421a887c22094219887c220aa741ffffff1f713602b8012002200229039005200229038805200229038005220b421a887c220c4219887c220da741ffffff1f713602a801200220022903b805200a421a887c220aa741ffffff0f713602bc012002200229039805200d421a887c220da741ffffff0f713602ac012002200a42198820022903c0057c220aa741ffffff1f713602c0012002200d421988200842ffffff1f837c2208421a88200942ffffff0f837c3e02b40120022008a741ffffff1f713602b0012002200a421a8820022903c8057c2208a741ffffff0f713602c4012002200842198842137e200b42ffffff1f837c2208421a88200c42ffffff0f837c3e02a40120022008a741ffffff1f713602a001200241b8036a41b0d6c0800010a98180800020024180056a200241d0006a10a581808000200220022903b00520022903a80520022903a0052208421a887c22094219887c220aa741ffffff1f713602f8032002200229039005200229038805200229038005220b421a887c220c4219887c220da741ffffff1f713602e803200220022903b805200a421a887c220aa741ffffff0f713602fc032002200229039805200d421a887c220da741ffffff0f713602ec032002200a42198820022903c0057c220aa741ffffff1f71360280042002200d421988200842ffffff1f837c2208421a88200942ffffff0f837c3e02f40320022008a741ffffff1f713602f0032002200a421a8820022903c8057c2208a741ffffff0f71360284042002200842198842137e200b42ffffff1f837c2208421a88200c42ffffff0f837c3e02e40320022008a741ffffff1f713602e00320024180056a200241b8036a200241e0036a10a681808000200241c8016a20024180056a200241a0016a10a881808000200241e0036a200241c8016a200241a0016a10a68180800020024180056a41acd2c08000200241e0036a10a48180800020022d0080052104200241f0016a41206a200241a4056a290200370300200241f0016a41186a2002419c056a290200370300200241f0016a41106a20024194056a290200370300200241f0016a41086a2002418c056a29020037030020022002290284053703f00120024198026a200241f0016a200241f8006a10a68180800020024180056a20024198026a200241c8016a10a681808000200241c0026a200241f0016a20024180056a10a681808000200220012802244101743602a405200220012802204101743602a0052002200128021c41017436029c052002200128021841017436029805200220012802144101743602940520022001280210410174360290052002200128020c41017436028c05200220012802084101743602880520022001280204410174360284052002200128020041017436028005200241e8026a20024180056a20024198026a10a68180800020024180056a200241e8026a10a38180800020022d00800541017110ad8d808000210120024180056a200241e8026a10a981808000200220022802800520022802e8022205734100200141ff01716b2201712005733602e802200220022802840520022802ec022205732001712005733602ec02200220022802880520022802f0022205732001712005733602f0022002200228028c0520022802f4022205732001712005733602f402200220022802900520022802f8022205732001712005733602f802200220022802940520022802fc022205732001712005733602fc022002200228029805200228028003220573200171200573360280032002200228029c0520022802840322057320017120057336028403200220022802a00520022802880322057320017120057336028803200220022802a405200228028c0322057320017120057336028c0320024190036a200241d0006a200241c0026a10a681808000200241b8036a200241e8026a20024190036a10a68180800020024180056a200241b8036a10a38180800020022d00800541017110ad8d8080002105200241e0036a41186a4200370300200241e0036a41106a4200370300200241e0036a41086a4200370300200242003703e00320024180056a20024190036a10a38180800041012101034020024180056a20036a2d0000200241e0036a20036a2d00004610ad8d8080002001712101200341016a22034120470d000b200110ad8d808000210320024180056a41206a200241e8026a41206a29020037030020024180056a41186a200241e8026a41186a29020037030020024180056a41106a200241e8026a41106a29020037030020024180056a41086a200241e8026a41086a290200370300200241b0056a20024190036a41086a290200370300200241b8056a20024190036a41106a290200370300200241c0056a20024190036a41186a290200370300200241c8056a20024190036a41206a290200370300200220022902e8023703800520022002290290033703a805200241f0056a200241206a290300370300200241e8056a200241186a290300370300200241e0056a200241106a290300370300200241d8056a200241086a29030037030020024198066a200241b8036a41206a29020037030020024190066a200241b8036a41186a29020037030020024188066a200241b8036a41106a29020037030020024180066a200241b8036a41086a290200370300200220022903003703d005200220022902b8033703f805200241e0036a20024180056a41a00110848e8080001a200020033a0002200020053a0001200020043a0000200041046a200241e0036a41a00110848e8080001a200241a0066a2480808080000bde0101047f23808080800041106b220324808080800002402001450d00200020014104746a21040340200028020021052003200028020422013602082003200341086a36020c2003410c6a200210cb8180800002402002280200200228020822066b20014f0d0020022006200110b182808000200228020821060b200228020420066a2005200110848e8080001a2002200620016a3602082003200041086a36020c2003410c6a200210cb8180800020032000410c6a36020c2003410c6a200210cb81808000200041106a22002004470d000b0b200341106a2480808080000b9506010e7f20002802042101024020002802082202450d0041002103034002402001200341386c6a2204280200450d00200428020441002802c0a3c68000118080808000000b0240200428020c450d00200441106a28020041002802c0a3c68000118080808000000b0240024002400240024020042d00240e050001040402040b2004412c6a21050240200441306a2802002206450d00200528020021072006410171210841002109024020064101460d002006417e71210a4100210920072106034002402006280200450d00200641046a28020041002802c0a3c68000118080808000000b0240200641206a280200450d00200641246a28020041002802c0a3c68000118080808000000b200641c0006a2106200a200941026a2209470d000b0b2008450d00200720094105746a2206280200450d00200628020441002802c0a3c68000118080808000000b20042802280d020c030b2004412c6a21050240200441306a280200220b450d002005280200210c4100210703400240200c200741246c6a22082802082206450d002008280204210d2006410171210e41002109024020064101460d002006417e71210a41002109200d2106034002402006280200450d00200641046a28020041002802c0a3c68000118080808000000b0240200641206a280200450d00200641246a28020041002802c0a3c68000118080808000000b200641c0006a2106200a200941026a2209470d000b0b200e450d00200d20094105746a2206280200450d00200628020441002802c0a3c68000118080808000000b02402008280200450d00200828020441002802c0a3c68000118080808000000b0240200828020c450d002008410c6a28020441002802c0a3c68000118080808000000b200741016a2207200b470d000b0b20042802280d010c020b200441286a280200450d012004412c6a21050b200528020041002802c0a3c68000118080808000000b02402004280218450d002004411c6a28020041002802c0a3c68000118080808000000b200341016a22032002470d000b0b02402000280200450d00200141002802c0a3c68000118080808000000b0bb703010a7f23808080800041e0016b2202248080808000200128020c2203200128020422046b220541077621062001280208210720012802002108024002400240024020032004470d002002200336020c200220073602082002200836020041002101410421090c010b2005418099b3e67c4b0d01200641d0006c220a417f4c0d01200128021021054100210141002d00fca3c680001a200a41002802c8a3c68000118180808000002209450d022002200336020c20022007360208200220043602042002200836020020024184016a220a41086a210b200921070240034020042802702208418080808078460d01200241106a200441f00010848e8080001a200b200441fc006a280200360200200a2004290274370200200220083602800120024190016a200241106a200510e381808000200720024190016a41d00010848e80800041d0006a2107200141016a210120044180016a2208210420082003470d000b200321040c010b20044180016a21040b20022004360204200210ca81808000200020013602082000200936020420002006360200200241e0016a2480808080000f0b10ae80808000000b4104200a10b280808000000bc204020b7f027e23808080800041c0006b220224808080800020012802082103200128020c220421052001280200220621070240200128020422082004460d002001280210210920062107024003402008220a280200220b418080808078460d01200a28020c210c200a290218210d200a290210210e200a2802042108200a28020821052002200936023c20022008200541386c6a3602382002200b360234200220083602302002200836022c200241086a2002412c6a10bc8180800020072002290308370200200741106a200e370200200741186a200d3702002002200c41ffffffff0171360214200741086a200241086a41086a290300370200200741206a2107200a41206a22082004470d000b0b200a41206a21050b20014284808080c00037020020014280808080c000370208024020042005460d00200420056b41057621044100210c034002402005200c4105746a220b2802082208450d00200b28020441306a210a03400240200a41706a280200450d00200a41746a28020041002802c0a3c68000118080808000000b0240200a417c6a280200450d00200a28020041002802c0a3c68000118080808000000b200a41386a210a2008417f6a22080d000b0b0240200b280200450d00200b28020441002802c0a3c68000118080808000000b0240200b28020c450d00200b410c6a28020441002802c0a3c68000118080808000000b200c41016a220c2004470d000b0b200020063602042000200341ffffff3f713602002000200720066b410576360208200241c0006a2480808080000b8505020d7f017e23808080800041e0006b2202248080808000200128020c2203200128020422046b220541386e21062001280208210720012802002108024002400240024020032004470d00410021094104210a0c010b200541a8e3f1b87c4b0d01200641246c2209417f4c0d012001280210210b4100210c41002d00fca3c680001a200941002802c8a3c6800011818080800000220a450d02200541486a210d200a210541002109024003402004200c6a2201412c6a280200220e418080808078460d01200141306a290300210f200241286a200141286a280200360200200241206a200141206a290300370300200241186a200141186a290300370300200241106a200141106a290300370300200241086a200141086a2903003703002002200f3703302002200e36022c20022001290300370300200241386a2002200b10e281808000200541206a200241386a41206a280200360200200541186a200241386a41186a290300370200200541106a200241386a41106a290300370200200541086a200241386a41086a29030037020020052002290338370200200541246a2105200941016a21092004200c41386a220c6a2003470d000c020b0b200141386a2003460d00200141e8006a2101200d200c6b41386e210503400240200141706a280200450d00200141746a28020041002802c0a3c68000118080808000000b02402001417c6a280200450d00200128020041002802c0a3c68000118080808000000b200141386a21012005417f6a22050d000b0b02402007450d00200841002802c0a3c68000118080808000000b200020093602082000200a36020420002006360200200241e0006a2480808080000f0b10ae80808000000b4104200910b280808000000bac0201087f23808080800041306b2202248080808000200128020c2203200128020422046b220541e8006e2106200128021021072001280208210820012802002109024002400240024020032004470d00410421010c010b200541d0b6dbed7e4b0d01200641386c2205417f4c0d0141002d00fca3c680001a200541002802c8a3c68000118180808000002201450d020b200241046a41086a220541003602002002200136020820022006360204200220073602202002200336021c2002200836021820022004360214200220093602102002200136022c2002410036022820022005360224200241106a200241246a10c881808000200041086a200528020036020020002002290204370200200241306a2480808080000f0b10ae80808000000b4104200510b280808000000bb703010a7f23808080800041d0016b2202248080808000200128020c2203200128020422046b220541f8006e21062001280208210720012802002108024002400240024020032004470d002002200336020c200220073602082002200836020041002101410421090c010b200541f8c2878f7e4b0d01200641c4006c220a417f4c0d01200128021021054100210141002d00fca3c680001a200a41002802c8a3c68000118180808000002209450d022002200336020c200220073602082002200436020420022008360200200241f8006a220a41086a210b200921070240034020042802642208418080808078460d01200241106a200441e40010848e8080001a200b200441f0006a290300370300200a20042903683703002002200836027420024188016a200241106a200510cf81808000200720024188016a41c40010848e80800041c4006a2107200141016a2101200441f8006a2208210420082003470d000b200321040c010b200441f8006a21040b20022004360204200210c981808000200020013602082000200936020420002006360200200241d0016a2480808080000f0b10ae80808000000b4104200a10b280808000000bab0201087f23808080800041306b2202248080808000200128020c2203200128020422046b220541386e2106200128021021072001280208210820012802002109024002400240024020032004470d00410421010c010b200541a8e3f1b87c4b0d01200641246c2205417f4c0d0141002d00fca3c680001a200541002802c8a3c68000118180808000002201450d020b200241046a41086a220541003602002002200136020820022006360204200220073602202002200336021c2002200836021820022004360214200220093602102002200136022c2002410036022820022005360224200241106a200241246a10c581808000200041086a200528020036020020002002290204370200200241306a2480808080000f0b10ae80808000000b4104200510b280808000000b850703077f017e027f2380808080004190016b2202248080808000200241386a200110db81808000024002400240024002402002280258418080808078460d00200228023c210320022802382104200241e8006a41206a200241e0006a290300370300200241e8006a41186a2205200241386a41206a290300370300200241e8006a41106a200241386a41186a290300370300200241f0006a200241386a41106a290300370300200220022903403703682001280224200241e8006a10dd82808000210620052802002205418080808078470d010b2000410036020820004280808080c000370200200110df818080000c010b200128022041016a2207417f20071b22074104200741044b1b220741d5aad52a4b0d01200741186c2208417f4c0d0120024184016a290200210941002d00fca3c680001a200841002802c8a3c6800011818080800000220a450d02200a2006360214200a200937020c200a2005360208200a2003360204200a20043602002002410136020c2002200a36020820022007360204200241106a41206a200141206a290200370300200241106a41186a200141186a290200370300200241106a41106a200141106a290200370300200241106a41086a200141086a29020037030020022001290200370310200241386a200241106a10db8180800002402002280258418080808078460d00200241386a41086a2101412c2104410121030340200228023c210620022802382107200241e8006a41206a200141206a290300370300200241e8006a41186a2205200141186a290300370300200241e8006a41106a200141106a290300370300200241e8006a41086a200141086a290300370300200220012903003703682002280234200241e8006a10dd8280800021082005280200220b418080808078460d012002290284012109024020032002280204470d00200241046a2003200228023041016a2205417f20051b10c3818080002002280208210a0b200a20046a22052008360200200541786a2009370200200541746a200b360200200541706a20063602002005416c6a20073602002002200341016a220336020c200441186a2104200241386a200241106a10db818080002002280258418080808078470d000b0b200241106a10df8180800020002002290204370200200041086a200241046a41086a2802003602000b20024190016a2480808080000f0b10ae80808000000b4104200810b280808000000bd10c01077f2000200110d781808000024002400240024002400240024002400240200128020022004188808080786a410f2000418780808078481b41786a0e0701020304050607000b200110b9818080000240200141146a2802002202450d00200141106a280200210341002104034002402003200441d0006c6a22052802302200418080808078460d00200541306a21060240200541386a2802002207450d00200541346a280200210003400240200041186a2802002208418080808078460d002008450d002000411c6a28020041002802c0a3c68000118080808000000b02402000280200450d00200041046a28020041002802c0a3c68000118080808000000b02402000410c6a280200450d00200041106a28020041002802c0a3c68000118080808000000b200041386a21002007417f6a22070d000b200628020021000b2000450d00200628020441002802c0a3c68000118080808000000b0240200541206a2802002207450d002005411c6a2802002100034002402000280200450d00200041046a28020041002802c0a3c68000118080808000000b02402000410c6a280200450d00200041106a28020041002802c0a3c68000118080808000000b200041246a21002007417f6a22070d000b0b02402005280218450d00200541186a28020441002802c0a3c68000118080808000000b02402005280224450d00200541246a28020441002802c0a3c68000118080808000000b200441016a22042002470d000b0b0240200128020c450d00200128021041002802c0a3c68000118080808000000b02402001280218450d002001411c6a28020041002802c0a3c68000118080808000000b0240200141c0006a2802002204450d002001413c6a28020021064100210503400240200620054105746a22082802082207450d0020082802042100034002402000280200450d00200041046a28020041002802c0a3c68000118080808000000b02402000410c6a280200450d00200041106a28020041002802c0a3c68000118080808000000b200041246a21002007417f6a22070d000b0b02402008280200450d00200828020441002802c0a3c68000118080808000000b0240200828020c450d002008410c6a28020441002802c0a3c68000118080808000000b200541016a22052004470d000b0b02402001280238450d00200128023c41002802c0a3c68000118080808000000b200141d4006a10de818080000f0b2001280204450d06200141086a28020041002802c0a3c68000118080808000000f0b2001280204450d05200141086a28020041002802c0a3c68000118080808000000f0b2001280204450d04200141086a28020041002802c0a3c68000118080808000000f0b2001280204450d03200141086a28020041002802c0a3c68000118080808000000f0b2001280204450d02200141086a28020041002802c0a3c68000118080808000000f0b2001280204450d01200141086a28020041002802c0a3c68000118080808000000f0b200141046a10b9818080000240200141186a2802002202450d00200141146a280200210341002104034002402003200441c4006c6a22052802242200418080808078460d00200541246a210602402005412c6a2802002207450d00200541286a280200210003400240200041186a2802002208418080808078460d002008450d002000411c6a28020041002802c0a3c68000118080808000000b02402000280200450d00200041046a28020041002802c0a3c68000118080808000000b02402000410c6a280200450d00200041106a28020041002802c0a3c68000118080808000000b200041386a21002007417f6a22070d000b200628020021000b2000450d00200628020441002802c0a3c68000118080808000000b0240200541206a2802002207450d002005411c6a2802002100034002402000280200450d00200041046a28020041002802c0a3c68000118080808000000b02402000410c6a280200450d00200041106a28020041002802c0a3c68000118080808000000b200041246a21002007417f6a22070d000b0b02402005280218450d00200541186a28020441002802c0a3c68000118080808000000b200441016a22042002470d000b0b0240200141106a280200450d00200128021441002802c0a3c68000118080808000000b2001411c6a280200450d00200141206a28020041002802c0a3c68000118080808000000b0ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b220241186c2104200241d6aad52a4941027421050240024020010d00200341003602180c010b200341043602182003200141186c36021c200320002802043602140b200341086a20052004200341146a10c281808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bb21208067f017e027f017e017f017e057f017e23808080800041c0006b220324808080800020002802002104024020002802042205450d0002400240200541037122060d00200521070c010b2005210703402007417f6a2107200420042f018e024102746a4190026a28020021042006417f6a22060d000b0b20054104490d000340200420042f018e024102746a4190026a280200220420042f018e024102746a4190026a280200220420042f018e024102746a4190026a280200220420042f018e024102746a4190026a28020021042007417c6a22070d000b0b200341086a41206a200141206a290200370300200341086a41186a200141186a290200370300200341086a41106a200141106a290200370300200341086a41086a200141086a29020037030020032001290200370308200341146a21080340200329030821092003280224210120032802102106200328022c210a0240024003402003418180808078360210200341086a2105024002402006418180808078460d00200121072006210b2009210c0c010b2001200a460d022003200141186a22073602242001280208210b2001290200210c200121050b0240200b418080808078460d00200528020c210d2005290210210e200c422088a72105200ca7210f02402007200a470d0020034180808080783602100c040b2003200741186a22013602242007290200210920072802082106200729020c210c200841086a200741146a2802003602002008200c370200200320063602102006418080808078460d0320052009422088a7470d03200f2009a7200510888e8080000d03200b450d01200d41002802c0a3c68000118080808000000c010b0b20032009370308200a2007460d00200a20076b220441186e22014101712105410021060240200441686a4118490d00200741246a2104200141feffffff007121014100210603400240200441646a280200450d00200441686a28020041002802c0a3c68000118080808000000b02402004417c6a280200450d00200428020041002802c0a3c68000118080808000000b200441306a21042001200641026a2206470d000b0b2005450d002007200641186c6a2204280208450d00200441086a28020441002802c0a3c68000118080808000000b0240200341286a280200450d00200328022041002802c0a3c68000118080808000000b02402000280204220b450d00200028020021060340024002400240024020062f018e022207450d0020064190026a220520074102746a28020022042f018e02220141054f0d0320052007417f6a220d4102746a28020022052f018e022207410520016b220f490d0120052007200f6b22083b018e02200441053b018e02200441b0016a2200200f4103746a2000200141037410fe8d8080001a2004200f4104746a2004200141047410fe8d8080001a2007200841016a220a6b2207410420016b470d022000200541b0016a2202200a4103746a2007410374221010848e808000210020042005200a4104746a2007410474221110848e8080002107200341086a41086a200520084104746a221241086a290200220c3703002006200d4103746a41b0016a2213290200210e201229020021092013200220084103746a290200370200200320093703082006200d4104746a2206290200211420062009370200200641086a220629020021092006200c370200200020106a200e370200200720116a22062014370200200641086a2009370200200b4101460d0320074190026a2206200f410274220f6a2006200141027441046a10fe8d8080001a20062005200a4102746a4190026a200f10848e8080001a200728029002220641003b018c02200620073602880220074194026a280200220641013b018c02200620073602880220074198026a280200220641023b018c0220062007360288022007419c026a280200220641033b018c022006200736028802200741a0026a280200220641043b018c022006200736028802200741a4026a280200220641053b018c0220062007360288020c030b41f8d8c0800041194194d9c0800010f880808000000b41c0d8c08000412741e8d8c0800010f880808000000b4188d8c08000412841b0d8c0800010f880808000000b20042106200b417f6a220b0d000b0b200341c0006a2480808080000f0b20032009370308024002400240024002400240024020042f018e022207410b490d004100210a0240024003402004280288022204450d01200a41016a210a20042f018e02410b4f0d000c020b0b200028020421062000280200210741002d00fca3c680001a41c00241002802c8a3c68000118180808000002204450d022004200736029002200441003b018e02200441003602880220002004360200200741003b018c0220072004360288022000200641016a220a3602040b41002d00fca3c680001a41900241002802c8a3c68000118180808000002206450d02200641003b018e022006410036028802200a417f6a2201450d04034041002d00fca3c680001a41c00241002802c8a3c68000118180808000002207450d042007200636029002200741003b018e022007410036028802200641003b018c022006200736028802200721062001417f6a2201450d050c000b0b2004200741016a3b018e02200420074103746a220641b0016a200f360200200641b4016a2005360200200420074104746a2207200b3602002007200d3602042007200e3702080c040b410441c00210b280808000000b410441900210b280808000000b410441c00210b280808000000b20042f018e022207410b4f0d012004200741016a22013b018e02200420074103746a221041b0016a200f360200201041b4016a2005360200200420074104746a2207200b3602002007200d3602042007200e370208200420014102746a4190026a2006360200200620013b018c022006200436028802200a450d0002400240200a41037122060d00200a21070c010b200a210703402007417f6a2107200420042f018e024102746a4190026a28020021042006417f6a22060d000b0b200a4104490d000340200420042f018e024102746a4190026a280200220420042f018e024102746a4190026a280200220420042f018e024102746a4190026a280200220420042f018e024102746a4190026a28020021042007417c6a22070d000b0b2002200228020041016a3602000c010b0b41d8d6c08000412041f8d7c0800010f880808000000bc804020d7f037e23808080800041c0006b22022480808080002001280204210320012802002104200028020821052000280200210602400240024020002802042207200028020c2208460d00200028021021092001280208200341246c6a2101200820076b41486a210a200241086a41206a210b200241086a41086a210c4100210d03402007200d6a2200412c6a280200220e418080808078460d02200041306a290300210f200241086a41286a200041286a280200360200200b200041206a290300370300200241086a41186a200041186a290300370300200241086a41106a200041106a290300370300200c200041086a2903003703002002200029030022103703082002200f3703382002200e3602342009200c10dd828080002100200b290200210f2002280234210e20022903382111200141086a200b41086a2802003602002001200f370200200141206a2000360200200141186a2010370200200141106a20113702002001410c6a200e41ffffffff0171360200200141246a2101200341016a21032007200d41386a220d6a2008470d000b0b200420033602000c010b20042003360200200041386a2008460d00200041e8006a2100200a200d6b41386e210103400240200041706a280200450d00200041746a28020041002802c0a3c68000118080808000000b02402000417c6a280200450d00200028020041002802c0a3c68000118080808000000b200041386a21002001417f6a22010d000b0b02402005450d00200641002802c0a3c68000118080808000000b200241c0006a2480808080000bab02010d7f23808080800041206b220224808080800020012802042103200128020021042000280208210520002802002106024020002802042207200028020c2208460d002000280210210920012802082003410c6c6a2100200241086a210a2002410472220b41186a210c200b41106a210d034020072802002201450d01200b2007290204370200200c2007411c6a280200360200200d200741146a290200370200200b41086a2007410c6a290200370200200220013602002002280204210e200041086a2009200a10dd82808000360200200041046a200e360200200020013602002000410c6a2100200341016a2103200741206a22072008470d000b0b2004200336020002402005450d00200641002802c0a3c68000118080808000000b200241206a2480808080000b870301107f23808080800041c0006b220224808080800020012802042103200128020021042000280208210520002802002106024020002802042207200028020c2208460d0020002802102109200128020820034104746a2100200241086a41206a210a200241086a41086a210b200241086a410472220141306a210c200141286a210d200141186a210e03402007280200220f450d0120012007290204370200200c200741346a280200360200200d2007412c6a290200370200200141206a200741246a290200370200200e2007411c6a290200370200200141106a200741146a290200370200200141086a2007410c6a2902003702002002200f360208200228020c21102009200b10dd8280800021112000410c6a2009200a10dd82808000360200200041086a2011360200200041046a20103602002000200f360200200041106a2100200341016a2103200741386a22072008470d000b0b2004200336020002402005450d00200641002802c0a3c68000118080808000000b200241c0006a2480808080000b9a0605097f027e087f027e017f23808080800041c0006b2202248080808000200128020421032001280200210420002802082105200028020021060240024020002802042207200028020c2208460d00200028021021092001280208200341386c6a2100200241086a2101024003402007280200220a4102460d012001200741d0006a28020036020020022007290248370300200741106a290200210b2007290208210c20072d0060210d200728025c210e2007280258210f2007280254211020072802442111200728024021122007280218211302400240200a0d002002200c370328200220133602382002200b3703302009200241286a10dd82808000210a41808080807821140c010b200741306a2902002115200729022821162007280238210a200728021c211720072802042114200220072802203602202002201736021c200220133602182002200b37031020022015370330200220163703282002200a3602382009200241106a10dd8280800021172009200241286a10dd828080002113200ca7210a0b20002002290300370200200041346a200d3a0000200041306a20113602002000412c6a2012360200200041286a2013360200200041246a2017360200200041206a200c422088a73602002000411c6a200a360200200041186a2014360200200041146a200e360200200041106a200f3602002000410c6a201041ffffffff0171360200200041086a2001280200360200200041386a2100200341016a2103200741e8006a22072008470d000b200420033602000c020b200741e8006a21070b20042003360200200820076b41e8006e210020082007460d00034002402007280200450d00200741046a280200450d00200741086a28020041002802c0a3c68000118080808000000b0240200741c8006a280200450d00200741cc006a28020041002802c0a3c68000118080808000000b0240200741d4006a280200450d00200741d8006a28020041002802c0a3c68000118080808000000b200741e8006a21072000417f6a22000d000b0b02402005450d00200641002802c0a3c68000118080808000000b200241c0006a2480808080000be00301077f200028020c2201200028020422026b41f8006e2103024020012002460d0041002104034002402002200441f8006c6a22052802502201418080808078460d000240200541d0006a22062802082207450d0020062802042101034002402001280200450d00200141046a280200450d00200141086a28020041002802c0a3c68000118080808000000b0240200141c8006a280200450d00200141cc006a28020041002802c0a3c68000118080808000000b0240200141d4006a280200450d00200141d8006a28020041002802c0a3c68000118080808000000b200141e8006a21012007417f6a22070d000b200628020021010b2001450d00200628020441002802c0a3c68000118080808000000b0240200541ec006a2802002207450d00200541e8006a28020041306a210103400240200141706a280200450d00200141746a28020041002802c0a3c68000118080808000000b02402001417c6a280200450d00200128020041002802c0a3c68000118080808000000b200141386a21012007417f6a22070d000b0b0240200541e4006a2201280200450d00200128020441002802c0a3c68000118080808000000b200441016a22042003470d000b0b02402000280208450d00200028020041002802c0a3c68000118080808000000b0b820401077f0240200028020c220120002802042202460d00200120026b41077621034100210403400240200220044107746a22052802502201418080808078460d000240200541d0006a22062802082207450d0020062802042101034002402001280200450d00200141046a280200450d00200141086a28020041002802c0a3c68000118080808000000b0240200141c8006a280200450d00200141cc006a28020041002802c0a3c68000118080808000000b0240200141d4006a280200450d00200141d8006a28020041002802c0a3c68000118080808000000b200141e8006a21012007417f6a22070d000b200628020021010b2001450d00200628020441002802c0a3c68000118080808000000b0240200541ec006a2802002207450d00200541e8006a28020041306a210103400240200141706a280200450d00200141746a28020041002802c0a3c68000118080808000000b02402001417c6a280200450d00200128020041002802c0a3c68000118080808000000b200141386a21012007417f6a22070d000b0b0240200541e4006a2201280200450d00200128020441002802c0a3c68000118080808000000b02402005280270450d00200541f0006a28020441002802c0a3c68000118080808000000b200441016a22042003470d000b0b02402000280208450d00200028020041002802c0a3c68000118080808000000b0b950301037f0240200028020022022802002200413f4b0d00200041027421020240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a20023a00000f0b0240200041ffff004b0d002000410274410172210202402001280200200128020822006b41014b0d0020012000410210b182808000200128020821000b2001200041026a360208200128020420006a20023b00000f0b0240200041ffffffff034b0d002000410274410272210202402001280200200128020822006b41034b0d0020012000410410b182808000200128020821000b2001200041046a360208200128020420006a20023600000f0b02402001280200220320012802082200470d0020012000410110b18280800020012802002103200128020821000b2001280204220420006a41033a00002001200041016a2200360208200228020021020240200320006b41034b0d0020012000410410b18280800020012802042104200128020821000b2001200041046a360208200420006a20023600000bd80301057f23808080800041106b22022480808080002000280218210320022000411c6a28020022043602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822056b20044f0d0020012005200410b182808000200128020821050b200128020420056a2003200410848e8080001a2001200520046a3602082002200041206a36020c2002410c6a200110cb81808000200028020421032002200028020822043602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822056b20044f0d0020012005200410b182808000200128020821050b200128020420056a2003200410848e8080001a2001200520046a360208200041106a28020021042002200041146a28020022003602082002200241086a36020c2002410c6a200110cb8180800002402000450d00200420004103746a21060340200428020021032002200428020422003602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822056b20004f0d0020012005200010b182808000200128020821050b200128020420056a2003200010848e8080001a2001200520006a360208200441086a22042006470d000b0b200241106a2480808080000bdf0601067f23808080800041106b2202248080808000200028022c21032002200041306a28020022043602082002200241086a36020c2002410c6a200110cb81808000024020012802002205200128020822066b20044f0d0020012006200410b18280800020012802002105200128020821060b2001280204220720066a2003200410848e8080001a2001200620046a220436020820002d00342106024020052004470d0020012005410110b18280800020012802042107200128020821040b200720046a20063a00002001200441016a2204360208024002402000280218418080808078470d00024020012802002004470d0020012004410110b18280800020012802042107200128020821040b2000411c6a21062001200441016a360208200720046a41003a00000c010b024020012802002004470d0020012004410110b18280800020012802042107200128020821040b2001200441016a360208200720046a41013a0000200028021c21062002200041206a28020022073602082002200241086a36020c2002410c6a200110cb8180800002402007450d00034020062d000021050240200128020020012802082204470d0020012004410110b182808000200128020821040b200641016a21062001200441016a360208200128020420046a20053a00002007417f6a22070d000b0b2002200041246a36020c2002410c6a200110cb81808000200041286a21060b2002200636020c2002410c6a200110cb81808000200028020421072002200028020822043602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822066b20044f0d0020012006200410b182808000200128020821060b200128020420066a2007200410848e8080001a2001200620046a360208200041106a28020021042002200041146a28020022063602082002200241086a36020c2002410c6a200110cb8180800002402006450d00200420064103746a21000340200428020021052002200428020422063602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822076b20064f0d0020012007200610b182808000200128020821070b200128020420076a2005200610848e8080001a2001200720066a360208200441086a22042000470d000b0b200241106a2480808080000bcf0701117f23808080800041b0016b220624808080800020062004370310200620033703082006200536021841002107200641206a41206a41003602002006420037023420064200370228200642808080808001370220200620012802003602800120062001280204220536027c2006200536027820062005200128020841f8006c6a360284012006200641206a36028801200641c4006a200641f8006a10be81808000200641206a200210dd8280800021082002411c6a28020021092002280218210a20022d0024210b024002400240200241206a280200220c0d004104210d0c010b4100210741002d00fca3c680001a200c410474220241002802c8a3c6800011818080800000220d450d012009200c41386c6a210e200641f8006a41206a210f200641f8006a41086a2110200641f8006a410472220541306a2111200541286a2112200541186a2113200d210120092102034020022802002214450d01200520022902043702002011200241346a28020036020020122002412c6a290200370200200541206a200241246a29020037020020132002411c6a290200370200200541106a200241146a290200370200200541086a2002410c6a29020037020020062014360278200628027c2115200641206a201010dd8280800021162001410c6a200641206a200f10dd82808000360200200141086a2016360200200141046a201536020020012014360200200141106a2101200741016a2107200241386a2202200e470d000b0b0240200a450d00200941002802c0a3c68000118080808000000b200641206a200641086a10dd828080002101200641d0006a41206a200641206a41206a2802002205360200200641d0006a41186a2214200641206a41186a2902002204370300200641d0006a41106a200641206a41106a290200370300200641d0006a41086a200641206a41086a290200370300200620062902203703502006200541002004a722021b360298012006200641d0006a411c6a28020022053602940120062002360290012006410036028c0120062002410047221536028801200620053602840120062002360280012006410036027c200620153602782000200641f8006a10c882808000200641dc006a10d38280800002402006280250450d00200628025441002802c0a3c68000118080808000000b201410d482808000200041146a200641c4006a41086a2802003602002000200629024437020c2000200136022c200041286a200b3a0000200041246a2008360200200041206a20073602002000411c6a200d3602002000200c360218200641b0016a2480808080000f0b4104200210b280808000000b900503057f017e067f23808080800041c0006b2203248080808000200141cc006a2802002104200128024821054180808080782106024020012802502207418080808078460d00200141dc006a2902002108200141d4006a2802002109200141d8006a28020021062003200236023820032009200641e8006c6a360234200320073602302003200936022c20032009360228200341146a200341286a10bd81808000200341086a200837030020032003290218370300200328021421060b4100210702400240200128021022090d004100210a0c010b200129030021082003200141086a29030037033020032008370328200320093602382002200341286a10dd82808000210b4101210a0b02400240200141286a28020022090d000c010b200129031821082003200141206a29030037033020032008370328200320093602382002200341286a10dd82808000210c410121070b200141ec006a280200210d200141e8006a28020021092001280264210e200320023602382003200e3602302003200936022c2003200936022820032009200d41386c6a360234200341146a200341286a10bf8180800002400240200141c0006a28020022090d00410021020c010b200129033021082003200141386a29030037033020032008370328200320093602382002200341286a10dd828080002109410121020b2000200536023820002006360224200020073602082000200b3602042000200a36020020002003290214370218200020023602102000413c6a2004360200200041286a20032903003702002000410c6a200c360200200020012d00703a0040200041146a2009360200200041306a200341086a290300370200200041206a200341146a41086a280200360200200341c0006a2480808080000b850301037f23808080800041106b2202248080808000200028020421032002200028020822043602082002200241086a36020c2002410c6a200110cb8180800002402004450d00200441386c210403402003200110d681808000200341386a2103200441486a22040d000b0b200041106a28020021032002200041146a28020022043602082002200241086a36020c2002410c6a200110cb8180800002402004450d00200441c4006c210403402003200110d181808000200341c4006a2103200441bc7f6a22040d000b0b2002200041246a36020c2002410c6a200110cb81808000200041286a2d000021040240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a20043a00002001200341016a3602082000411c6a28020021032002200041206a28020022043602082002200241086a36020c2002410c6a200110cb8180800020032004200110b88180800020022000412c6a36020c2002410c6a200110cb81808000200241106a2480808080000bb00701057f23808080800041106b22022480808080002000280238210320022000413c6a28020022043602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822056b20044f0d0020012005200410b182808000200128020821050b2001280204220620056a2003200410848e8080001a2001200520046a2204360208024002402000280224418080808078470d00024020012802002004470d0020012004410110b18280800020012802042106200128020821040b2001200441016a360208200620046a41003a00000c010b200041246a2105024020012802002004470d0020012004410110b18280800020012802042106200128020821040b2001200441016a360208200620046a41013a00002005200110d2818080000b0240024020002802000d000240200128020020012802082204470d0020012004410110b182808000200128020821040b2001200441016a360208200128020420046a41003a00000c010b0240200128020020012802082204470d0020012004410110b182808000200128020821040b2001200441016a360208200128020420046a41013a00002002200041046a36020c2002410c6a200110cb818080000b0240024020002802080d000240200128020020012802082204470d0020012004410110b182808000200128020821040b2001200441016a360208200128020420046a41003a00000c010b0240200128020020012802082204470d0020012004410110b182808000200128020821040b2001200441016a360208200128020420046a41013a000020022000410c6a36020c2002410c6a200110cb818080000b2000411c6a28020021042002200041206a28020022053602082002200241086a36020c2002410c6a200110cb8180800002402005450d00200541246c210503402004200110cc81808000200441246a21042005415c6a22050d000b0b0240024020002802100d000240200128020020012802082205470d0020012005410110b182808000200128020821050b2001200541016a2204360208200128020420056a41003a00000c010b0240200128020020012802082204470d0020012004410110b182808000200128020821040b2001200441016a360208200128020420046a41013a00002002200041146a36020c2002410c6a200110cb81808000200128020821040b20002d00402105024020012802002004470d0020012004410110b182808000200128020821040b2001200441016a360208200128020420046a20053a0000200241106a2480808080000be80101047f23808080800041106b2202248080808000200028020c21032002200041106a28020022043602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822056b20044f0d0020012005200410b182808000200128020821050b200128020420056a2003200410848e8080001a2001200520046a360208200028020421042002200028020822003602082002200241086a36020c2002410c6a200110cb8180800002402000450d00200041386c210003402004200110cd81808000200441386a2104200041486a22000d000b0b200241106a2480808080000ba80201047f23808080800041106b22022480808080002000280208210320022000410c6a28020022043602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822056b20044f0d0020012005200410b182808000200128020821050b200128020420056a2003200410848e8080001a2001200520046a22043602080240024020002802000d00024020012802002004470d0020012004410110b182808000200128020821040b2001200441016a360208200128020420046a41003a00000c010b024020012802002004470d0020012004410110b182808000200128020821040b2001200441016a360208200128020420046a41013a00002002200041046a360204200241046a200110cb818080000b200241106a2480808080000bdb0501057f23808080800041106b220224808080800002400240200028020c22030d000240200128020020012802082204470d0020012004410110b182808000200128020821040b200128020420046a41003a0000200441016a21040c010b0240200128020020012802082204470d0020012004410110b182808000200128020821040b200128020420046a41013a00002001200441016a3602082002200041106a28020022043602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822056b20044f0d0020012005200410b182808000200128020821050b200128020420056a2003200410848e8080001a200520046a21040b200120043602082002200041146a36020c2002410c6a200110cb8180800002400240200028021822030d000240200128020020012802082204470d0020012004410110b182808000200128020821040b200128020420046a41003a0000200441016a21040c010b0240200128020020012802082204470d0020012004410110b182808000200128020821040b200128020420046a41013a00002001200441016a36020820022000411c6a28020022043602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822056b20044f0d0020012005200410b182808000200128020821050b200128020420056a2003200410848e8080001a200520046a21040b20012004360208200028020421042002200028020822003602082002200241086a36020c2002410c6a200110cb8180800002402000450d00200420004103746a21060340200428020021032002200428020422003602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822056b20004f0d0020012005200010b182808000200128020821050b200128020420056a2003200010848e8080001a2001200520006a360208200441086a22042006470d000b0b200241106a2480808080000beb0301057f23808080800041106b22022480808080002000280218210320022000411c6a28020022043602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822056b20044f0d0020012005200410b182808000200128020821050b200128020420056a2003200410848e8080001a2001200520046a360208200028020421042002200028020822053602082002200241086a36020c2002410c6a200110cb8180800002402005450d002005410574210503402004200110d481808000200441206a2104200541606a22050d000b0b20002d002021050240200128020020012802082204470d0020012004410110b182808000200128020821040b2001200441016a360208200128020420046a20053a0000200041106a28020021042002200041146a28020022053602082002200241086a36020c2002410c6a200110cb8180800002402005450d00200420054103746a21060340200428020021032002200428020422053602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822006b20054f0d0020012000200510b182808000200128020821000b200128020420006a2003200510848e8080001a2001200020056a360208200441086a22042006470d000b0b200241106a2480808080000bb70c01067f23808080800041106b22022480808080002002200041346a36020c2002410c6a200110cb81808000200028020421032002200028020822043602082002200241086a36020c2002410c6a200110cb8180800002402004450d00200320044103746a21050340200328020021062002200328020422043602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822076b20044f0d0020012007200410b182808000200128020821070b200128020420076a2006200410848e8080001a2001200720046a360208200341086a22032005470d000b0b200041106a28020021032002200041146a28020022043602082002200241086a36020c2002410c6a200110cb8180800002402004450d002004410474210403402003200110d381808000200341106a2103200441706a22040d000b0b02400240024002400240024002400240024020002d00240e080001020304050607000b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41003a00002001200341016a3602082000412c6a28020021032002200041306a28020022043602082002200241086a36020c2002410c6a200110cb818080002004450d072004410574210403402003200110d481808000200341206a2103200441606a22040d000c080b0b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41013a00002001200341016a3602082000412c6a28020021032002200041306a28020022043602082002200241086a36020c2002410c6a200110cb818080002004450d06200441246c210403402003200110d581808000200341246a21032004415c6a22040d000c070b0b0240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a41023a00002002200041286a36020c2002410c6a200110cb818080000c050b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41033a00002001200341016a2203360208200041286a28020021040240200128020020036b41034b0d0020012003410410b182808000200128020821030b2001200341046a360208200128020420036a200436000020022000412c6a36020c2002410c6a200110cb818080000c040b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41043a00002001200341016a3602082000412c6a28020021032002200041306a28020022043602082002200241086a36020c2002410c6a200110cb818080002004450d032004410274210403402002200336020c2002410c6a200110cb81808000200341046a21032004417c6a22040d000c040b0b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41053a00002001200341016a2203360208200041256a2d00002104024020012802002003470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a20043a00000c020b0240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a41063a00002002200041286a36020c2002410c6a200110cb818080000c010b0240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a41073a00002002200041286a36020c2002410c6a200110cb8180800020022000412c6a36020c2002410c6a200110cb818080000b2000411c6a28020021032002200041206a28020022043602082002200241086a36020c2002410c6a200110cb8180800002402004450d00200320044103746a21050340200328020021062002200328020422043602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822076b20044f0d0020012007200410b182808000200128020821070b200128020420076a2006200410848e8080001a2001200720046a360208200341086a22032005470d000b0b200241106a2480808080000bf40b01037f23808080800041206b220224808080800002400240417f200110d881808000220341046a220420042003491b2203417f4c0d0041002d00fca3c680001a200341002802c8a3c68000118180808000002204450d01200220043602102002200336020c200420012802603600004104210420024104360214024002400240024002400240024002400240200128020022034188808080786a410f2003418780808078481b41786a0e080001020304050607000b410421030240200228020c4104470d002002410c6a4104410110b182808000200228021421030b200228021020036a41083a00002002200341016a360214200141086a280200210420022001410c6a28020022013602182002200241186a36021c2002411c6a2002410c6a10cb818080000240200228020c200228021422036b20014f0d002002410c6a2003200110b182808000200228021421030b200228021020036a2004200110848e8080001a2002200320016a3602140c070b410421030240200228020c4104470d002002410c6a4104410110b182808000200228021421030b200228021020036a41093a00002002200341016a360214200141086a280200210420022001410c6a28020022013602182002200241186a36021c2002411c6a2002410c6a10cb818080000240200228020c200228021422036b20014f0d002002410c6a2003200110b182808000200228021421030b200228021020036a2004200110848e8080001a2002200320016a3602140c060b410421030240200228020c4104470d002002410c6a4104410110b182808000200228021421030b200228021020036a410a3a00002002200341016a360214200141086a280200210420022001410c6a28020022013602182002200241186a36021c2002411c6a2002410c6a10cb818080000240200228020c200228021422036b20014f0d002002410c6a2003200110b182808000200228021421030b200228021020036a2004200110848e8080001a2002200320016a3602140c050b410421030240200228020c4104470d002002410c6a4104410110b182808000200228021421030b200228021020036a410b3a00002002200341016a360214200141086a280200210420022001410c6a28020022013602182002200241186a36021c2002411c6a2002410c6a10cb818080000240200228020c200228021422036b20014f0d002002410c6a2003200110b182808000200228021421030b200228021020036a2004200110848e8080001a2002200320016a3602140c040b410421030240200228020c4104470d002002410c6a4104410110b182808000200228021421030b200228021020036a410c3a00002002200341016a360214200141086a280200210420022001410c6a28020022013602182002200241186a36021c2002411c6a2002410c6a10cb818080000240200228020c200228021422036b20014f0d002002410c6a2003200110b182808000200228021421030b200228021020036a2004200110848e8080001a2002200320016a3602140c030b410421030240200228020c4104470d002002410c6a4104410110b182808000200228021421030b200228021020036a410d3a00002002200341016a360214200141086a280200210420022001410c6a28020022013602182002200241186a36021c2002411c6a2002410c6a10cb818080000240200228020c200228021422036b20014f0d002002410c6a2003200110b182808000200228021421030b200228021020036a2004200110848e8080001a2002200320016a3602140c020b410421030240200228020c4104470d002002410c6a4104410110b182808000200228021421030b200228021020036a410e3a00002002200341016a360214200141046a2002410c6a10d0818080000c010b0240200228020c4104470d002002410c6a4104410110b182808000200228021421040b200228021020046a410f3a00002002200441016a36021420012002410c6a10e5818080000b2000200229020c370200200041086a2002410c6a41086a280200360200200241206a2480808080000f0b10ae80808000000b4101200310b280808000000b840301057f024002400240024002400240024002400240200028020022014188808080786a410f2001418780808078481b41786a0e080001020304050607000b2000410c6a28020041046a21000c070b2000410c6a28020041046a21000c060b2000410c6a28020041046a21000c050b2000410c6a28020041046a21000c040b2000410c6a28020041046a21000c030b2000410c6a28020041046a21000c020b200041186a21022000410c6a2103410621010240200041286a280200220441c000490d0041072101200441808001490d004109410a2004418080808004491b21010b2002280200210420032802002103200041246a2802002105410121020240200041306a280200220041c000490d0041022102200041808001490d00410441052000418080808004491b21020b417f417f417f200441c4006c200341386c41047222006a41046a220320032000491b220020054104742001726a220120012000491b220020026a220120012000491b21000c010b200010e48180800021000b200041016a0b931003137f017e047f23808080800041206b2203248080808000024002400240024020014115490d0041002d00fca3c680001a0240200141017641186c41002802c8a3c68000118180808000002204450d0041002d00fca3c680001a41800141002802c8a3c68000118180808000002205450d04200041686a2106200041346a210741002108410021094110210a0240034020002008220b41186c220c6a210d0240024002402001200b6b220e4102490d000240200d41186a280200220f200d280200200d411c6a2802002210200d41046a280200221120102011491b10888e8080002212201020116b20121b4100480d0041022112200e4102460d022007200c6a21114102211203402011417c6a2802002213200f20112802002214201020142010491b10888e808000220f201420106b200f1b4100480d03201141186a2111201421102013210f200e201241016a2212460d020c000b0b410221120240200e4102460d002007200c6a21114102211203402011417c6a2802002213200f20112802002214201020142010491b10888e808000220f201420106b200f1b417f4a0d01201141186a2111201421102013210f200e201241016a2212470d000b200e21120b024002402012200b6a22082012490d00200820014b0d0120124102490d042012410176210e200c201241186c6a2115200621142000210f0340200f200c6a221041086a221329020021162013201420156a221141086a221729020037020020172016370200201141146a2802002113201141106a221728020021182017201041106a221929020037020020102902002116201020112902003702002011201637020020192018360200201041146a2013360200201441686a2114200f41186a210f200e417f6a220e0d000c050b0b200b200841c8dbc08000109681808000000b2008200141c8dbc08000109581808000000b200e21120b2012200b6a21080b024002402008200b490d00200820014d0d010b41b8dcc08000412c41e4dcc0800010f880808000000b024002400240200820014f0d002012410a490d010b2008200b6b21100c010b200b410a6a2210200120102001491b2208200b490d02200d2008200b6b221020124101201241014b1b10da818080000b024002402009200a470d0041002d00fca3c680001a200941047441002802c8a3c68000118180808000002211450d012009410174210a20112005200941037410848e8080002111200541002802c0a3c6800011808080800000201121050b200520094103746a2211200b36020420112010360200200941016a22152109024020154102490d0003400240024002400240200520152213417f6a22154103746a2209280200221020092802046a2001460d00201341037420056a221441706a280200221220104d0d0041022109201341024d0d0520052013417d6a22184103746a2802002211201220106a4d0d0141032109201341034d0d05201441606a280200201120126a4d0d01201321090c050b20134103490d0120052013417d6a22184103746a28020021110b20112010490d010b2013417e6a21180b024002400240024002400240201320184d0d002013201841016a22104d0d01200520104103746a22192802042019280200221a6a2211200520184103746a220d280204220c490d02201120014b0d032000200c41186c6a2209200d280200221741186c22126a2110201141186c211402402011200c6b220f20176b221120174f0d0020042010201141186c221210848e808000220e20126a211220174101480d0520114101480d05200620146a2111034020112012201241686a2214280200201041686a220f280200201441046a2802002214200f41046a280200220f2014200f491b10888e808000220b2014200f6b200b1b2214411f75220f417f7341186c6a22122010200f41186c6a22102014417f4a1b2214290200370200201141106a201441106a290200370200201141086a201441086a290200370200201020094d0d06201141686a21112012200e4d0d060c000b0b20042009201210848e808000221120126a21120240201741014e0d00201121110c060b0240200f20174a0d00201121110c060b200020146a210e20112111034020092011201020102802002011280200201041046a2802002214201141046a280200220f2014200f491b10888e808000220b2014200f6b200b1b220b417f4a220f1b2214290200370200200941106a201441106a290200370200200941086a201441086a290200370200200941186a21092011200f41186c6a221120124f0d062010200b411f7641186c6a2210200e490d000c060b0b200341146a42003702002003410136020c200341ccdac08000360208200341d4dac08000360210200341086a41d8dbc0800010f680808000000b200341146a42003702002003410136020c200341ccdac08000360208200341d4dac08000360210200341086a41e8dbc0800010f680808000000b200c201141f8dbc08000109681808000000b2011200141f8dbc08000109581808000000b20102109200e21110b20092011201220116b10848e8080001a2019200c3602042019201a20176a360200200d200d41086a20132018417f736a41037410fe8d8080001a41012109201541014b0d000b0b200820014f0d050c010b0b41a8dcc0800010a081808000000b200b200841f4dcc08000109681808000000b4188dcc0800010a081808000000b200141014d0d0120002001410110da818080000c010b200541002802c0a3c6800011808080800000200441002802c0a3c68000118080808000000b200341206a2480808080000f0b4198dcc0800010a081808000000bba0303097f017e017f23808080800041106b220324808080800002402002417f6a20014f0d000240200220014f0d00200241186c20006a41506a2104034002402000200241186c6a22052802002206200541686a2207280200200541046a2802002208200741046a280200220920082009491b10888e808000220a200820096b200a1b417f4a0d0020052007290200370200200341086a220b200541106a2209290200370300200541086a2205290200210c2005200741086a2902003702002009200741106a2902003702002003200c370300024020024101460d004101210d200421050340200541186a2107200620052802002008200541046a280200220920082009491b10888e808000220a200820096b200a1b417f4a0d0120072005290200370200200741106a200541106a290200370200200741086a200541086a290200370200200541686a21052002200d41016a220d470d000b200021070b200720083602042007200636020020072003290300370208200741106a200b2903003702000b200441186a2104200241016a22022001470d000b0b200341106a2480808080000f0b4184ddc08000412e41b4ddc0800010f880808000000bef0602077f017e0240200128022022020d00200128020021022001410036020002402002450d000240200128020422020d0020012802082102200128020c2203450d0002400240200341077122040d00200321050c010b2003210503402005417f6a210520022802980421022004417f6a22040d000b0b20034108490d000340200228029804280298042802980428029804280298042802980428029804280298042102200541786a22050d000b0b03402002280290042105200241002802c0a3c68000118080808000002005210220050d000b0b20004180808080783602200f0b20012002417f6a360220200128020421020240024002400240024020012802002205450d002002450d010b2005450d022001410c6a2802002104200141086a28020021030c010b200141086a280200210202402001410c6a2802002203450d0002400240200341077122040d00200321050c010b2003210503402005417f6a210520022802980421022004417f6a22040d000b0b20034108490d000340200228029804280298042802980428029804280298042802980428029804280298042102200541786a22050d000b0b20014200370208200120023602042001410136020041002104410021030b0240200420022f0196044f0d00200221050c020b024003402002280290042205450d0120022f0194042104200241002802c0a3c6800011808080800000200341016a210320052102200420052f019604490d030c000b0b200241002802c0a3c680001180808080000041a8dac0800010a081808000000b41c8dec0800010a081808000000b200441016a21060240024020030d00200521020c010b200520064102746a4198046a2802002102410021062003417f6a2207450d002003417e6a2108024020074107712203450d0003402007417f6a210720022802980421022003417f6a22030d000b0b20084107490d000340200228029804280298042802980428029804280298042802980428029804280298042102200741786a22070d000b0b2001200636020c2001410036020820012002360204200520044103746a290200210920002005200441286c6a220241d8006a290300370308200041106a200241e0006a290300370300200041186a200241e8006a290300370300200041206a200241f0006a290300370300200041286a200241f8006a290300370300200020093703000be50101047f23808080800041106b2203248080808000200320013602082003200341086a36020c2003410c6a200210cb8180800002402001450d0020002001410c6c6a21040340200028020021052003200028020422013602082003200341086a36020c2003410c6a200210cb8180800002402002280200200228020822066b20014f0d0020022006200110b182808000200228020821060b200228020420066a2005200110848e8080001a2002200620016a3602082003200041086a36020c2003410c6a200210cb818080002000410c6a22002004470d000b0b200341106a2480808080000bfb0201057f23808080800041106b22022480808080002000280218210320022000411c6a28020022043602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822056b20044f0d0020012005200410b182808000200128020821050b200128020420056a2003200410848e8080001a2001200520046a36020820002802042000280208200110dc818080002002200041206a36020c2002410c6a200110cb81808000200041106a28020021042002200041146a28020022003602082002200241086a36020c2002410c6a200110cb8180800002402000450d00200420004103746a21060340200428020021032002200428020422003602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822056b20004f0d0020012005200010b182808000200128020821050b200128020420056a2003200010848e8080001a2001200520006a360208200441086a22042006470d000b0b200241106a2480808080000ba70501077f024020002802002201450d00200028020421020240024020002802082203450d00410021000340024002402000450d002001210420022105200021010c010b4100210402402002450d0020022100024020024107712205450d0003402000417f6a210020012802900221012005417f6a22050d000b0b20024108490d000340200128029002280290022802900228029002280290022802900228029002280290022101200041786a22000d000b0b410021050b024002400240200520012f018e02490d0003402001280288022200450d0220012f018c022105200141002802c0a3c6800011808080800000200441016a210420002101200520002f018e024f0d000b200021010b200541016a2102024020040d00200121000c020b200120024102746a4190026a2802002100410021022004417f6a2206450d012004417e6a2107024020064107712204450d0003402006417f6a210620002802900221002004417f6a22040d000b0b20074107490d010340200028029002280290022802900228029002280290022802900228029002280290022100200641786a22060d000c020b0b200141002802c0a3c680001180808080000041a8dac0800010a081808000000b0240200120054104746a2201280200450d00200128020441002802c0a3c68000118080808000000b410021012003417f6a22030d000c020b0b024020020d00200121000c010b02400240200241077122050d0020012100200221010c010b200121002002210103402001417f6a210120002802900221002005417f6a22050d000b0b20024108490d000340200028029002280290022802900228029002280290022802900228029002280290022100200141786a22010d000b0b03402000280288022101200041002802c0a3c68000118080808000002001210020010d000b0b0ba00601097f2000280200210102400240024020002802202202450d0020002802042103034020002002417f6a220236022002400240024002400240024002402001450d0020030d0020002802082104200028020c2205450d03200541077122060d01200521030c020b2001450d04200028020c210620002802082105200321040c030b2005210303402003417f6a210320042802980421042006417f6a22060d000b0b20054108490d000340200428029804280298042802980428029804280298042802980428029804280298042104200341786a22030d000b0b2000420037020820002004360204410121012000410136020041002106410021050b02400240200620042f019604490d0003402004280290042203450d0220042f0194042106200441002802c0a3c6800011808080800000200541016a210520032104200620032f0196044f0d000b200321040b200641016a2107024020050d00200421030c030b200420074102746a4198046a2802002103410021072005417f6a2208450d022005417e6a2109024020084107712205450d0003402008417f6a210820032802980421032005417f6a22050d000b0b20094107490d020340200328029804280298042802980428029804280298042802980428029804280298042103200841786a22080d000c030b0b200441002802c0a3c680001180808080000041a8dac0800010a081808000000b41c8dec0800010a081808000000b2000200736020c200041003602082000200336020402402004200641286c6a41f0006a2204280200450d00200428020441002802c0a3c68000118080808000000b20020d000b200041003602000c010b200041003602002001450d01200028020422030d0020002802082103200028020c2205450d0002400240200541077122060d00200521040c010b2005210403402004417f6a210420032802980421032006417f6a22060d000b0b20054108490d000340200328029804280298042802980428029804280298042802980428029804280298042103200441786a22040d000b0b03402003280290042104200341002802c0a3c68000118080808000002004210320040d000b0b0be70801097f23808080800041d0016b2209248080808000200920043703102009200337030820092005360218200941206a41206a220a41003602002009420037023420094200370228200942808080808001370220200920012802003602b4012009200128020422053602b001200920053602ac012009200520012802084107746a3602b8012009200941206a3602bc01200941c4006a200941ac016a10ba8180800020022d006c210b200941206a200210dd82808000210c200941206a200241186a10dd82808000210d200941206a200241306a10dd82808000210e200941206a200241c8006a10dd82808000210f200241e4006a280200210120022802602110024002400240200241e8006a28020022020d00410421050c010b41002d00fca3c680001a2002410474221141002802c8a3c68000118180808000002205450d010b200941a0016a41086a22114100360200200920053602a401200920023602a00120092001200241386c6a3602b801200920103602b401200920013602b001200920013602ac012009200941206a3602bc0120092005360280012009410036027c20092011360278200941ac016a200941f8006a10c781808000200941d0006a41086a22012011280200360200200920092902a001370350200941206a200941086a10dd828080002105200920062802003602b4012009200628020422023602b001200920023602ac012009200220062802084105746a3602b8012009200941206a3602bc01200941e0006a200941ac016a10bb81808000200941206a200710dd828080002106200941206a200741186a10dd828080002111200941206a200741306a10dd828080002107200941ec006a2008200941206a10e181808000200941f8006a41206a200a2802002208360200200941f8006a41186a220a200941206a41186a2902002204370300200941f8006a41106a200941206a41106a290200370300200941f8006a41086a200941206a41086a290200370300200920092902203703782009200841002004a722021b3602cc01200920094194016a28020022083602c801200920023602c401200941003602c0012009200241004722103602bc01200920083602b801200920023602b401200941003602b001200920103602ac012000200941ac016a10c88280800020094184016a10d38280800002402009280278450d00200928027c41002802c0a3c68000118080808000000b200a10d482808000200041146a200941c4006a41086a2802003602002000200929024437020c20002009290350370218200041206a200128020036020020002005360244200041346a200b3a0000200041306a200f3602002000412c6a200e360200200041286a200d360200200041246a200c36020020002009290260370238200041c0006a200941e0006a41086a280200360200200041d0006a2007360200200041cc006a2011360200200020063602482000200929026c370254200041dc006a200941ec006a41086a280200360200200941d0016a2480808080000f0b4104201110b280808000000bb80301037f23808080800041d0006b22032480808080002001280204210420012802082105200128020021012003200236024420032005410020011b3602402003200436023c20032001360238200341003602342003200141004722023602302003200436022c200320013602282003410036022420032002360220200341086a200341206a10c081808000200328020c2101024002400240200328021022020d0002402003280208450d00200141002802c0a3c68000118080808000000b41002101410021020c010b2003200341cf006a36022020012002200341206a10d9818080002003280208210541002d00fca3c680001a41900241002802c8a3c68000118180808000002204450d01200441003b018e02200441003602880220034100360218200320043602142003410036021c20032001200241186c6a360244200320053602402003200136023c200320013602382003418180808078360228200341146a200341206a2003411c6a10c4818080002003280214210120032802182104200328021c21020b200020023602082000200436020420002001360200200341d0006a2480808080000f0b410441900210b280808000000bcd0201087f23808080800041306b2203248080808000200141246a280200210420012802202105200128020421062001280200210702400240200141286a28020022080d00410421090c010b41002d00fca3c680001a2008410c6c220a41002802c8a3c680001181808080000022090d004104200a10b280808000000b200341046a41086a220a41003602002003200936020820032008360204200320023602202003200420084105746a36021c2003200536021820032004360214200320043602102003200936022c200341003602282003200a360224200341106a200341246a10c681808000200041086a200a2802003602002000200329020437020020002002200141086a10dd828080003602202000411c6a200636020020002007360218200041106a200141306a2903003702002000200128022c41ffffffff017136020c200341306a2480808080000bb30503057f017e067f23808080800041c0006b2203248080808000200141cc006a2802002104200128024821054180808080782106024020012802502207418080808078460d00200141dc006a2902002108200141d4006a2802002109200141d8006a28020021062003200236023820032009200641e8006c6a360234200320073602302003200936022c20032009360228200341146a200341286a10bd81808000200341086a200837030020032003290218370300200328021421060b4100210702400240200128021022090d004100210a0c010b200129030021082003200141086a29030037033020032008370328200320093602382002200341286a10dd82808000210b4101210a0b02400240200141286a28020022090d000c010b200129031821082003200141206a29030037033020032008370328200320093602382002200341286a10dd82808000210c410121070b200141ec006a280200210d200141e8006a28020021092001280264210e200320023602382003200e3602302003200936022c2003200936022820032009200d41386c6a360234200341146a200341286a10bf8180800002400240200141c0006a28020022090d00410021020c010b200129033021082003200141386a29030037033020032008370328200320093602382002200341286a10dd828080002109410121020b2000200536024420002006360230200020073602082000200b3602042000200a36020020002003290214370218200041c8006a2004360200200041346a20032903003702002000410c6a200c360200200041286a200141f4006a2902003702002000200128027041ffffffff01713602242000413c6a200341086a290300370200200041206a200341146a41086a280200360200200020012d007c3a004c200041146a200936020020002002360210200341c0006a2480808080000bfa04010d7f410221010240200041246a280200220241c000490d0041032101200241808001490d00410541062002418080808004491b21010b41012102410121030240200041286a280200220441c000490d0041022103200441808001490d00410441052004418080808004491b21030b02402000412c6a280200220441c000490d0041022102200441808001490d00410441052004418080808004491b21020b41012104410121050240200041306a280200220641c000490d0041022105200641808001490d00410441052006418080808004491b21050b02402000280244220641c000490d0041022104200641808001490d00410441052006418080808004491b21040b410121064101210702402000280248220841c000490d0041022107200841808001490d00410441052008418080808004491b21070b200041146a2108200041206a2109200041c0006a210a0240200041cc006a280200220b41c000490d0041022106200b41808001490d0041044105200b418080808004491b21060b2008280200210b2000280208210c20092802002109200a280200210a410121080240200041d0006a280200220d41c000490d0041022108200d41808001490d0041044105200d418080808004491b21080b417f417f417f417f417f417f200c41386c410472220c200b41d0006c6a41046a220b200b200c491b220b417f200320016a20026a20056a220120094104746a41046a220220022001491b6a22012001200b491b220120046a220220022001491b2201200a4105746a41046a220220022001491b2201200620076a20086a6a220220022001491b2201200041dc006a280200220041047420004103746a6a41046a220020002001491b0bec0a01097f23808080800041106b2202248080808000200028020421032002200028020822043602082002200241086a36020c2002410c6a200110cb8180800002402004450d00200441386c210403402003200110d681808000200341386a2103200441486a22040d000b0b200041106a28020021032002200041146a28020022043602082002200241086a36020c2002410c6a200110cb8180800002402004450d00200441d0006c210403402003200110e681808000200341d0006a2103200441b07f6a22040d000b0b200041346a2d000021040240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a20043a00002002200041246a36020c2002410c6a200110cb818080002002200041286a36020c2002410c6a200110cb8180800020022000412c6a36020c2002410c6a200110cb818080002002200041306a36020c2002410c6a200110cb818080002000411c6a28020021032002200041206a28020022043602082002200241086a36020c2002410c6a200110cb8180800020032004200110b8818080002002200041c4006a36020c2002410c6a200110cb818080002000413c6a28020021032002200041c0006a28020022043602082002200241086a36020c2002410c6a200110cb8180800002402004450d002004410574210403402003200110e781808000200341206a2103200441606a22040d000b0b2002200041c8006a36020c2002410c6a200110cb818080002002200041cc006a36020c2002410c6a200110cb818080002002200041d0006a36020c2002410c6a200110cb818080002002200041dc006a28020022053602082002200241086a36020c2002410c6a200110cb81808000024002402005450d0020002802542206450d004100210320064100472107200041d8006a280200210003400240024002402007450d002003450d010b20070d0141e8dec0800010a081808000000b410121072006210302402000450d0020002104024020004107712206450d0003402004417f6a210420032802900221032006417f6a22060d000b0b20004108490d000340200328029002280290022802900228029002280290022802900228029002280290022103200441786a22040d000b0b41002106410021000b0240200020032f018e02490d0003402003280288022204450d04200641016a210620032f018c02210020042103200020042f018e024f0d000b0b200041016a21080240024020060d00200321040c010b200320084102746a4190026a2802002104410021082006417f6a2209450d002006417e6a210a024020094107712206450d0003402009417f6a210920042802900221042006417f6a22060d000b0b200a4107490d000340200428029002280290022802900228029002280290022802900228029002280290022104200941786a22090d000b0b200320004103746a220641b0016a28020021092002200641b4016a28020022063602082002200241086a36020c2002410c6a200110cb81808000200320004104746a210302402001280200200128020822006b20064f0d0020012000200610b182808000200128020821000b200128020420006a2009200610848e8080001a2001200020066a36020820022003410c6a36020c2002410c6a200110cb81808000200328020421062002200328020822033602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822006b20034f0d0020012000200310b182808000200128020821000b200128020420006a2006200310848e8080001a2001200020036a3602084100210620082100200421032005417f6a22050d000b0b200241106a2480808080000f0b41d8dec0800010a081808000000be70801057f23808080800041106b2202248080808000200028024421032002200041c8006a28020022043602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822056b20044f0d0020012005200410b182808000200128020821050b200128020420056a2003200410848e8080001a2001200520046a2204360208024002402000280230418080808078470d00024020012802002004470d0020012004410110b182808000200128020821040b2001200441016a360208200128020420046a41003a00000c010b200041306a2105024020012802002004470d0020012004410110b182808000200128020821040b2001200441016a360208200128020420046a41013a00002005200110d2818080000b0240024020002802000d000240200128020020012802082204470d0020012004410110b182808000200128020821040b2001200441016a360208200128020420046a41003a00000c010b0240200128020020012802082204470d0020012004410110b182808000200128020821040b2001200441016a360208200128020420046a41013a00002002200041046a36020c2002410c6a200110cb818080000b0240024020002802080d000240200128020020012802082204470d0020012004410110b182808000200128020821040b2001200441016a360208200128020420046a41003a00000c010b0240200128020020012802082204470d0020012004410110b182808000200128020821040b2001200441016a360208200128020420046a41013a000020022000410c6a36020c2002410c6a200110cb818080000b2000411c6a28020021042002200041206a28020022053602082002200241086a36020c2002410c6a200110cb8180800002402005450d00200541246c210503402004200110cc81808000200441246a21042005415c6a22050d000b0b0240024020002802100d000240200128020020012802082205470d0020012005410110b182808000200128020821050b2001200541016a2204360208200128020420056a41003a00000c010b0240200128020020012802082204470d0020012004410110b182808000200128020821040b2001200441016a360208200128020420046a41013a00002002200041146a36020c2002410c6a200110cb81808000200128020821040b20002d004c2105024020012802002004470d0020012004410110b182808000200128020821040b200128020420046a20053a00002001200441016a360208200041286a280200210420022000412c6a28020022053602082002200241086a36020c2002410c6a200110cb8180800002402005450d00200420054103746a21060340200428020021032002200428020422053602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822006b20054f0d0020012000200510b182808000200128020821000b200128020420006a2003200510848e8080001a2001200020056a360208200441086a22042006470d000b0b200241106a2480808080000ba80301057f23808080800041106b22022480808080002000280218210320022000411c6a28020022043602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822056b20044f0d0020012005200410b182808000200128020821050b200128020420056a2003200410848e8080001a2001200520046a360208200028020421042002200028020822053602082002200241086a36020c2002410c6a200110cb8180800002402005450d00200541246c210503402004200110dd81808000200441246a21042005415c6a22050d000b0b200041106a28020021042002200041146a28020022053602082002200241086a36020c2002410c6a200110cb8180800002402005450d00200420054103746a21060340200428020021032002200428020422053602082002200241086a36020c2002410c6a200110cb8180800002402001280200200128020822006b20054f0d0020012000200510b182808000200128020821000b200128020420006a2003200510848e8080001a2001200020056a360208200441086a22042006470d000b0b200241106a2480808080000bc00302057f017e0240024002400240024020012d00000d004100210241002d00fca3c680001a412041002802c8a3c68000118180808000002203450d0241ffdfc080002101034002402001417f6a2d0000412072220441506a220541ff0171410a490d00200441997f6a41ff017141f9014d0d05200441a97f6a21050b024020012d0000412072220641506a220441ff0171410a490d00200641997f6a41ff017141f9014d0d06200641a97f6a21040b200320026a20042005410474723a0000200141026a2101200241016a2205210220054120470d000b200020032f00003b0001200041106a200329000f370000200041036a200341026a2d00003a0000200041186a200341176a290000370000200041206a2003411f6a2d00003a000020032900032107200328000b2101200341002802c0a3c68000118080808000002000410c6a2001360000200041046a20073700000c010b20002001290001370001200041196a200141196a290000370000200041116a200141116a290000370000200041096a200141096a2900003700000b200041013a00000f0b4101412010b280808000000b418087c0800010a081808000000b419087c0800010a081808000000bf20305027f017e027f017e017f23808080800041c0006b2201248080808000200141246a41bee0c08000410441c2e0c08000411d41fcdfc08000410010d882808000200141086a410036020020014280808080c00037030020012802242102200129022821032001410c6a41086a2204410036020020014280808080c00037020c2001410c6a410010eb818080002001280210200428020041246c6a220541003a00202005410836021c200541dfe0c080003602182005420437021020054200370208200542808080808001370200200141306a41086a200428020041016a22053602002001200129020c2206370330024020052006a7470d00200141306a200510eb81808000200128023821050b2001280234200541246c6a220541013a00202005410736021c200541e7e0c08000360218200542043702102005420037020820054280808080800137020002402002418080808078470d0041f8dec08000411141ecdfc0800010a181808000000b20012802342105200128023021042001280238210720002001290300370350200042808080808001370244200020023602382000200536020820002004360204200041013a0000200041cc006a41003602002000413c6a20033702002000200741016a36020c200041d8006a200141086a280200360200200141c0006a2480808080000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141246c2104200141e4f1b81c4941027421050240024020030d00200241003602180c010b200241043602182002200341246c36021c200220002802043602140b200241086a20052004200241146a10ea81808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000be00101037f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014108200141084b1b2201417f73411f7621040240024020030d00200241003602180c010b2002200336021c20024101360218200220002802043602140b200241086a20042001200241146a10ec81808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141386c210420014193c9a4124941037421050240024020030d00200241003602180c010b200241083602182002200341386c36021c200220002802043602140b200241086a20052004200241146a10ec81808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141246c2104200141e4f1b81c4941027421050240024020030d00200241003602180c010b200241043602182002200341246c36021c200220002802043602140b200241086a20052004200241146a10ec81808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b220241386c210420024193c9a4124941037421050240024020010d00200341003602180c010b200341083602182003200141386c36021c200320002802043602140b200341086a20052004200341146a10ec81808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b22024105742104200241808080204941037421050240024020010d00200341003602180c010b200341083602182003200141057436021c200320002802043602140b200341086a20052004200341146a10ec81808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b220241246c2104200241e4f1b81c4941027421050240024020010d00200341003602180c010b200341043602182003200141246c36021c200320002802043602140b200341086a20052004200341146a10ec81808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000be20101027f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024108200241084b1b2202417f73411f7621040240024020010d00200341003602180c010b2003200136021c20034101360218200320002802043602140b200341086a20042002200341146a10ec81808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bba0504057f017e027f017e23808080800041c0006b2201248080808000200141246a41a0e2c08000410441a4e2c08000411741a0e2c08000410010d8828080002001411c6a42043702002001420037021420014280808080800137020c2001428880808080013702302001428080808080013702382001410c6a200141306a10fe81808000200141086a200141206a28020036020020012001290218370300200128020c2102200128021021032001280214210420012802242105200129022821062001410c6a41086a2207410036020020014280808080c00037020c2001410c6a410010ef818080002001280210200728020041246c6a220841003a00202008410336021c2008419ae2c080003602182008420437021020084200370208200842808080808001370200200141306a41086a200728020041016a22083602002001200129020c2209370330024020082009a7470d00200141306a200810ef81808000200128023821080b2001280234200841246c6a220841013a00202008410236021c2008419de2c0800036021820084204370210200842003702082008428080808080013702002001280238210720012802342108200120012802303602142001200836020c20012008200741246c6a41246a36021820012008360210200141306a2001410c6a10808280800002402005418080808078470d0041eee0c08000411141e0e1c0800010a181808000000b200120023602142001200336020c200120033602102001200320044105746a360218200041c4006a2001410c6a10fe81808000200141176a200141306a41086a2802003600002000413c6a200637020020002005360238200041013a000020002001290300370350200041d8006a200141086a2802003602002001200129023037000f2000200129000c370001200041086a200141136a290000370000200141c0006a2480808080000bbf0604057f017e037f017e23808080800041d0006b2201248080808000200141306a41bbe2c08000410d41a4e2c08000411741a0e2c08000410010d882808000200141286a420437020020014200370220200142808080808001370218200142888080808001370240200142808080808001370248200141186a200141c0006a10fe81808000200141086a41086a2001412c6a2802003602002001200129022437030820012802182102200128021c2103200128022021042001280230210520012902342106200141186a41086a2207410036020020014280808080c000370218200141186a410010ef81808000200128021c200728020041246c6a220841003a00202008410636021c200841c8e2c080003602182008420437021020084200370208200842808080808001370200200141c0006a41086a2209200728020041016a220836020020012001290218220a37034002402008200aa7470d00200141c0006a200810ef81808000200128024821080b2001280244200841246c6a220841013a00202008410b36021c200841cee2c0800036021820084204370210200842003702082008428080808080013702002007200928020041016a220836020020012001290340220a37031802402008200aa7470d00200141186a200810ef81808000200128022021080b200128021c200841246c6a220841023a00202008410936021c200841d9e2c08000360218200842043702102008420037020820084280808080800137020020012802202107200128021c2108200120012802183602202001200836021820012008200741246c6a41246a3602242001200836021c200141c0006a200141186a10808280800002402005418080808078470d0041eee0c08000411141e0e1c0800010a181808000000b20012002360220200120033602182001200336021c2001200320044105746a360224200041c4006a200141186a10fe81808000200141236a200141c0006a41086a2802003600002000413c6a200637020020002005360238200041013a000020002001290308370350200041d8006a200141086a41086a2802003602002001200129024037001b20002001290018370001200041086a2001411f6a290000370000200141d0006a2480808080000b9f0704057f017e037f017e23808080800041d0006b2201248080808000200141286a41e2e2c08000410c41a4e2c08000411741a0e2c08000410010d882808000200141206a420437020020014200370218200142808080808001370210200142888080808001370240200142808080808001370248200141106a200141c0006a10fe81808000200141086a200141246a2802003602002001200129021c37030020012802102102200128021421032001280218210420012802282105200129022c2106200141106a41086a22074100360200200142808080808001370210200141106a410010ee818080002001280214200728020041386c6a2208420437022c20084206370224200841f6e1c080003602202008410636021c200841f0e1c08000360218200841ae808080003602102008428a96cd9bb2e69e8d723703082008429b99b4f08dc8ccdea77f370300200141c0006a41086a2209200728020041016a220836020020012001290210220a37034002402008200aa7470d00200141c0006a200810ee81808000200128024821080b2001280244200841386c6a2208420437022c2008420d37022420084181e2c080003602202008410536021c200841fce1c08000360218200841af80808000360210200842a3e3bbd692f2b9f9c000370308200842b79f92f0eda6f987be7f3703002007200928020041016a220836020020012001290340220a37031002402008200aa7470d00200141106a200810ee81808000200128021821080b2001280214200841386c6a2208420437022c2008420437022420084196e2c080003602202008410836021c2008418ee2c08000360218200841b080808000360210200842d58ec2d7bbaa93feab7f370308200842b3e2d6a8e7e4a79f77370300200128021821072001280214210820012001280210360248200120083602402001200836024420012008200741386c6a41386a36024c200141346a200141c0006a10ff8180800002402005418080808078470d0041eee0c08000411141e0e1c0800010a181808000000b2001200236021820012003360210200120033602142001200320044105746a36021c200041c4006a200141106a10fe818080002001411b6a200141346a41086a2802003600002000413c6a200637020020002005360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000bba0504057f017e027f017e23808080800041c0006b2201248080808000200141246a41f0e2c08000410d41fde2c08000412341f0e2c08000410010d8828080002001411c6a42043702002001420037021420014280808080800137020c2001428880808080013702302001428080808080013702382001410c6a200141306a10fe81808000200141086a200141206a28020036020020012001290218370300200128020c2102200128021021032001280214210420012802242105200129022821062001410c6a41086a2207410036020020014280808080c00037020c2001410c6a410010ef818080002001280210200728020041246c6a220841003a00202008410436021c200841a0e3c080003602182008420437021020084200370208200842808080808001370200200141306a41086a200728020041016a22083602002001200129020c2209370330024020082009a7470d00200141306a200810ef81808000200128023821080b2001280234200841246c6a220841013a00202008410836021c200841a4e3c0800036021820084204370210200842003702082008428080808080013702002001280238210720012802342108200120012802303602142001200836020c20012008200741246c6a41246a36021820012008360210200141306a2001410c6a10808280800002402005418080808078470d0041eee0c08000411141e0e1c0800010a181808000000b200120023602142001200336020c200120033602102001200320044105746a360218200041c4006a2001410c6a10fe81808000200141176a200141306a41086a2802003600002000413c6a200637020020002005360238200041013a000020002001290300370350200041d8006a200141086a2802003602002001200129023037000f2000200129000c370001200041086a200141136a290000370000200141c0006a2480808080000b140020012000280204200028020810dd808080000b2100200128021441ace3c080004105200141186a28020028020c118280808000000bc40403027f017e047f2380808080004190016b220024808080800041002101200041086a41b1e3c08000411341002802b8a1c680001185808080000002402000280208450d00200041186a41086a200041086a41086a290200220237030020002000290208370318200028021c210302402002a7220441034b0d0002400240417f4100280284a4c680002201410147200141014b1b2201417f460d00200141ff01710d010b2000413c6a41e4e5c08000410241b1e3c08000411310fc818080002000412c6a410c6a41b180808000360200200041b28080800036023020002000418f016a36023420002000413c6a36022c4100280290a1c680002101410028028ca1c6800021054100280280a4c68000210620004180016a4202370200200041f8006a4102360200200041f0006a4110360200200041ec006a41e6e5c08000360200200041e0006a41f6e5c08000ad4280808080900d84370200200041c8006a410c6a41dfe6c08000ad4280808080800484370200200041fc006a2000412c6a360200200041d4e5c08000360274200041013602682000410036025c2000410036025020004281808080c003370248200541ecf2c08000200641024622061b200041c8006a200141d4f2c0800020061b28021011848080800000200028023c450d00200028024041002802c0a3c68000118080808000000b200041246a20032004200028021828020c11858080800000410021010c010b20032800002101200041246a20032004200028021828020c118580808000000b20004190016a24808080800020010b890301047f23808080800041d0006b2201248080808000024002400240024010fa8180800022020e020001020b0240417f4100280284a4c680002202410247200241024b1b2202417f460d00200241ff01710d030b4100280290a1c680002102410028028ca1c6800021034100280280a4c680002104200141c4006a4200370200200141c0006a41ace3c080003602002001413c6a4101360200200141346a4125360200200141306a41a8e4c08000360200200141246a41cde4c08000ad4280808080e00d84370200200141186a41a8e4c08000ad4280808080d00484370200200141a0e4c08000360238200141003602202001410036021420014281808080800937020c2001410236022c200341ecf2c08000200441024622041b2001410c6a200241d4f2c0800020041b280210118480808000000c020b41b1e3c08000411341002802a0a1c68000118480808000000c010b20012002417f6a36020c41b1e3c0800041132001410c6a410441002802e0a1c68000118680808000000b200141d0006a2480808080000beb0601057f23808080800041106b220524808080800041012106024002400240200441017420026a2207450d002007417f4c0d0241002d00fca3c680001a200741002802c8a3c68000118180808000002206450d010b4100210820054100360208200520063602042005200736020002402002450d00200120026a210741002108034002400240024020012c00002202417f4c0d00200141016a2101200241ff017121020c010b20012d0001413f7121062002411f712109024002402002415f4b0d0020094106742006722102200141026a21010c010b200641067420012d0002413f717221060240200241704f0d0020062009410c74722102200141036a21010c010b200641067420012d0003413f71722009411274418080f00071722202418080c400460d04200141046a21010b2002418001490d002005410036020c024002402002418010490d0002402002418080044f0d0020052002413f71418001723a000e20052002410c7641e001723a000c20052002410676413f71418001723a000d410321020c020b20052002413f71418001723a000f2005200241127641f001723a000c20052002410676413f71418001723a000e20052002410c76413f71418001723a000d410421020c010b20052002413f71418001723a000d2005200241067641c001723a000c410221020b0240200528020020086b20024f0d0020052008200210f381808000200528020821080b200528020420086a2005410c6a200210848e8080001a200820026a21080c010b024020082005280200470d002005200810ed81808000200528020821080b200528020420086a20023a0000200528020841016a21080b2005200836020820012007470d000b0b02402004450d000340413041d70020032d0000220141a001491b20014104766a2102024020082005280200470d002005200810ed81808000200528020821080b200528020420086a20023a00002005200528020841016a2208360208024020082005280200470d002005200810ed81808000200528020821080b200341016a2103200528020420086a413041d7002001410f712208410a491b20086a3a00002005200528020841016a22083602082004417f6a22040d000b0b20002005290200370200200041086a200541086a280200360200200541106a2480808080000f0b4101200710b280808000000b10ae80808000000b130020004200370200200041086a42043702000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b22064105762207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710f18180800020022802082109200228020c21080b200920084105746a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b4105762107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b220641386e2207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710f08180800020022802082109200228020c21080b2009200841386c6a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b41386e2107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b220641246e2207200128020822014101764f0d01410021082002410036020c20024280808080c00037020441042109024020052004460d00200241046a4100200710f28180800020022802082109200228020c21080b2009200841246c6a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b41246e2107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000b9c07010b7f23808080800041306b22022480808080002001280208210302400240024002400240024002400240024002400240200128020022040d0020030d01200242808080801037020c410021050c080b200128020420046b210520030d01200521060c020b2001410c6a28020020036b21060c010b20052001410c6a28020020036b6a22062005490d010b0240024020060d00410121070c010b2006417f4c0d0641002d00fca3c680001a200641002802c8a3c68000118180808000002207450d070b4100210520024100360214200220073602102002200636020c200128020c21082001280204210102400240024020040d002003450d07200820036b21090c010b200120046b2105024020030d00200521090c010b2005200820036b6a22092005490d010b410021050240200620094f0d002002410c6a4100200910f38180800020022802102107200228021421050b2004450d0420042001460d04200120046b2206410371210a2004417f7320016a41034f0d02410021010c030b200241246a42003702002002410136021c20024190e7c0800036021820024198e7c08000360220200241186a41a0e9c0800010f680808000000b200241186a410c6a42003702002002410136021c20024190e7c0800036021820024198e7c08000360220200241186a419ce8c0800010f680808000000b200720056a210b2006417c71210c410021010340200b20016a2206200420016a22092d00003a0000200641016a200941016a2d00003a0000200641026a200941026a2d00003a0000200641036a200941036a2d00003a0000200c200141046a2201470d000b200520016a21050b200a450d00200420016a21010340200720056a20012d00003a0000200141016a2101200541016a2105200a417f6a220a0d000b0b2003450d0020032008460d00200820036b2201410371210a024002402003417f7320086a41034f0d00410021010c010b200720056a21042001417c71210b410021010340200420016a2206200320016a22092d00003a0000200641016a200941016a2d00003a0000200641026a200941026a2d00003a0000200641036a200941036a2d00003a0000200b200141046a2201470d000b200520016a21050b200a450d00200320016a21010340200720056a20012d00003a0000200141016a2101200541016a2105200a417f6a220a0d000b0b2000200229020c370200200041086a2005360200200241306a2480808080000f0b10ae80808000000b4101200610b280808000000bf20503037f017e037f23808080800041c0006b220124808080800020014106360210200141b0e9c0800036020c41002d00fca3c680001a024002400240410841002802c8a3c68000118180808000002202450d00200241b0e9c08000360200200241046a410636020041b0e9c08000410610d782808000450d0141002d00fca3c680001a412041002802c8a3c68000118180808000002203450d022003429b99b4f08dc8ccdea77f370308200341ae8080800036021820034101360204200341b6e9c08000360200200341106a428a96cd9bb2e69e8d7237030020014101360220200120033602182001200341206a3602242001200336021c200141306a200141186a108f828080002001290230210420012802382105200141186a41086a2206410036020020014280808080c000370218200141186a4100109582808000200128021c200628020041246c6a220341003a00202003410436021c200341b7e9c080003602182003420437021020034200370208200342808080808001370200200141306a41086a2207200628020041016a360200200120012902183703302001410c6a200141306a41bbe9c080004104109a828080002001200128020c36022020012001280210220336021820012003200128021441246c6a3602242001200336021c200141306a200141186a108d82808000200141236a2007280200360000200041cc006a2005360200200020043702442000413c6a2002ad4280808080108437020020004101360238200041013a0000200041d8006a410036020020004280808080c0003703502001200129023037001b20002001290018370001200041086a2001411f6a290000370000200141c0006a2480808080000f0b4104410810b280808000000b200241002802c0a3c6800011808080800000200141246a42013702002001410236021c20014180ddc18000360218200141b4808080003602342001200141306a36022020012001410c6a360230200141186a4190ddc1800010f680808000000b4108412010b280808000000b6e00200042d7c9cb8fc1cf97db3e37030820004280808080c00037033820004280808080c000370350200041b580808000360218200041063a0000200041106a42e88488d0c0e3aebc13370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b02000bd70809017e027f027e017f077e017f037e017f037e200141386a29030021022001290330502103200141c0006a2104427f200141286a2903002205200129031822065022071b2108200141d0006a290300210920014190026a290300210a2001290348210b02400240427f200141206a290300220c20071b220d200129038802220e580d002008200a580d00200d200b580d004100210f20082009560d010b200d200884420052210f0b20042903002110200141a0026a2107427f200220031b21022001290310211120012903082112410121040240024020012802002213450d002012500d012011500d010b20134520124200200d200b7d22142014200d561b5820114200200820097d220d200d2008561b587172410173200f7221040b427f201020031b21122007290300210d2001290398022108024002402002200b580d0020122009560d010b200220128442005220047221040b2008200b200e7c58200d2009200a7c58722006a7410047200c2008562005200d56727172200472210320014190016a290300211120014188016a29030050210720014198016a2104427f20014180016a290300220c200141f0006a290300221050220f1b210b200141a8016a2903002102200141a0016a290300210902400240427f200141f8006a2903002214200f1b2212200e580d00200b200a580d0020122009580d00200b2002560d010b2012200b8442005220037221030b20042903002115427f201120071b2111200141e8006a2903002106200141e0006a290300210541012104024002402001280258220f450d002005500d012006500d010b200f4520054200201220097d221620162012561b5820064200200b20027d22122012200b561b58717241017320037221040b427f201520071b210b0240024020112009580d00200b2002560d010b2011200b8442005220047221040b20082009200e7c58200d2002200a7c58722010a74100472014200856200c200d567271722004722103200141e8016a2903002111200141e0016a290300502107200141f0016a2104427f200141d8016a2903002210200141c8016a290300221450220f1b210b20014180026a2903002102200141f8016a290300210902400240427f200141d0016a2903002215200f1b2212200e580d00200b200a580d0020122009580d00200b2002560d010b2012200b8442005220037221030b2004290300210c427f201120071b2111200141c0016a2903002106200141b8016a2903002105410121040240024020012802b001220f450d002005500d012006500d010b200f4520054200201220097d221620162012561b5820064200200b20027d22122012200b561b58717241017320037221040b427f200c20071b210b0240024020112009580d00200b2002560d010b2011200b8442005220047221040b024020082009200e7c580d00200d2002200a7c580d002014a74520152008582010200d587172450d0020040d002000200141a80210848e8080001a0f0b20004202370300200041013a00080bfe0606017f027e017f017e037f027e23808080800041b0026b2202248080808000200241086a200141a80210848e8080001a200241a8026a290300210320022903a0022104024020022903205022050d00200241306a2903002206200320062003561b2103200241286a2903002206200420062004561b21040b0240200241f8006a2903005022070d0020024188016a2903002206200320062003561b210320024180016a2903002206200420062004561b21040b200141ac026a210820012802a80221010240200241d0016a2903005022090d00200241e0016a2903002206200320062003561b2103200241d8016a2903002206200420062004561b21040b20083502002106200220033703a802200220043703a00202402001450d0020032003428094ebdc0380220a428094ebdc037e7d20067e2203428094ebdc0380220b200a20067e7c2003200b428094ebdc037e7d4280cab5ee0156ad7c210b20042004428094ebdc03802203428094ebdc037e7d20067e2204428094ebdc0380220a200320067e7c2004200a428094ebdc037e7d4280cab5ee0156ad7c21060240200229030850450d00024002402005450d004200210a0c010b42004200200241306a2903002203200b7d220420042003561b2203200241d8006a2903007d220420042003561b210442004200200241286a290300220320067d220a200a2003561b220320022903507d220a200a2003561b21034201210a0b20022004370318200220033703102002200a3703080b024020022903604200520d004200210a024020070d004200420020024188016a2903002203200b7d220420042003561b2203200241b0016a2903007d220420042003561b21044200420020024180016a290300220320067d220a200a2003561b2203200241a8016a2903007d220a200a2003561b21034201210a0b200241f0006a2004370300200241e8006a20033703002002200a3703600b20022903b8014200520d00024002402009450d00420021060c010b42004200200241e0016a2903002203200b7d220420042003561b220320024188026a2903007d220420042003561b210442004200200241d8016a290300220320067d220620062003561b220320024180026a2903007d220620062003561b2103420121060b200241c8016a2004370300200241c0016a2003370300200220063703b8010b2000200241086a108582808000200241b0026a2480808080000bc40403057f017e037f23808080800041d0006b2201248080808000200141286a41afebc08000410b41baebc08000411441c0e9c08000410010d882808000200141206a42043702002001420037021820014280808080800137021020014288808080800137023420014280808080800137023c200141106a200141346a108f82808000200141086a2202200141106a41146a2802003602002001200129021c370300200128021021032001280214210420012802182105200129022c21062001280228210720014100360218200142808080808001370210200141106a41001096828080002001280214200128021841386c6a2208420437022c2008421537022420084182eec080003602202008410336021c200841ffedc08000360218200841b680808000360210200842a5968aeabda0f18d34370308200842a2c6d1e2c3c0eaf01f370300200128021821092001280214210820012001280210360218200120083602102001200836021420012008200941386c6a41386a36021c200141c4006a200141106a108e8280800002402007418080808078470d0041e3ecc08000411141d4edc0800010a181808000000b200141346a410b6a200141c4006a41086a2802003600002000200336024420002007360238200041003a000020002001290300370350200041cc006a2005360200200041c8006a20043602002000413c6a20063702002001200129024437003720002001290034370001200041d8006a2002280200360200200041086a2001413b6a290000370000200141d0006a2480808080000b2100200128021441a0ebc08000410f200141186a28020028020c118280808000000bd20403027f017e047f410121014101210202402000290348220342c000540d0041022102200342808001540d00410421022003428080808004540d004109200379a74103766b21020b0240200041d0006a290300220342c000540d0041022101200342808001540d00410421012003428080808004540d004109200379a74103766b21010b410121044101210502402000290300500d004102210502402000290308220342c000540d0041032105200342808001540d00410521052003428080808004540d00410a200379a74103766b21050b410121060240200041106a290300220342c000540d0041022106200342808001540d00410421062003428080808004540d004109200379a74103766b21060b200520066a21050b02402000290318500d00410221040240200041206a290300220342c000540d0041032104200342808001540d00410521042003428080808004540d00410a200379a74103766b21040b410121060240200041286a290300220342c000540d0041022106200342808001540d00410421062003428080808004540d004109200379a74103766b21060b200420066a21040b02400240200029033050450d00410121000c010b410221060240200041386a290300220342c000540d0041032106200342808001540d00410521062003428080808004540d00410a200379a74103766b21060b410121070240200041c0006a290300220342c000540d0041022107200342808001540d00410421072003428080808004540d004109200379a74103766b21070b200620076a21000b200120026a20056a20046a20006a0bbf0804057f017e037f017e23808080800041e0006b2201248080808000200141306a41ceebc08000410f41baebc08000411441c0e9c08000410010d882808000200141286a420437020020014200370220200142808080808001370218200142888080808001370240200142808080808001370248200141186a200141c0006a108f82808000200141086a41086a200141186a41146a2802003602002001200129022437030820012802182102200128021c2103200128022021042001280230210520012902342106200141186a41086a22074100360200200142808080808001370218200141186a4100109682808000200128021c200728020041386c6a2208420437022c20084206370224200841a5eec080003602202008410e36021c20084197eec08000360218200841ae808080003602102008428a96cd9bb2e69e8d723703082008429b99b4f08dc8ccdea77f370300200141c0006a41086a2209200728020041016a220836020020012001290218220a37034002402008200aa7470d00200141c0006a2008109682808000200128024821080b2001280244200841386c6a2208420437022c2008420e370224200841b8eec080003602202008410d36021c200841abeec08000360218200841b7808080003602102008428caaf9b7c8a1dba0c900370308200842e3cce7c1b8e587e3ba7f3703002007200928020041016a220836020020012001290340220a37031802402008200aa7470d00200141186a2008109682808000200128022021080b200128021c200841386c6a2208420437022c2008420e370224200841b8eec080003602202008410936021c200841c6eec08000360218200841b7808080003602102008428caaf9b7c8a1dba0c900370308200842e3cce7c1b8e587e3ba7f370300200141c0006a41086a200141186a41086a28020041016a220836020020012001290318220a37034002402008200aa7470d00200141c0006a2008109682808000200128024821080b2001280244200841386c6a2208420437022c2008420e370224200841b8eec080003602202008410836021c200841cfeec08000360218200841b7808080003602102008428caaf9b7c8a1dba0c900370308200842e3cce7c1b8e587e3ba7f370300200128024821072001280244210820012001280240360220200120083602182001200836021c20012008200741386c6a41386a360224200141d4006a200141186a108e8280800002402005418080808078470d0041e3ecc08000411141d4edc0800010a181808000000b200141cb006a200141d4006a41086a2802003600002000200236024420002005360238200041003a000020002001290308370350200041cc006a2004360200200041c8006a20033602002000413c6a20063702002001200129025437004320002001290040370001200041d8006a200141086a41086a280200360200200041086a200141c7006a290000370000200141e0006a2480808080000bd40203027f017e027f41012101410121020240200029038802220342c000540d0041022102200342808001540d00410421022003428080808004540d004109200379a74103766b21020b024020004190026a290300220342c000540d0041022101200342808001540d00410421012003428080808004540d004109200379a74103766b21010b41012104410121050240200029039802220342c000540d0041022105200342808001540d00410421052003428080808004540d004109200379a74103766b21050b0240200041a0026a290300220342c000540d0041022104200342808001540d00410421042003428080808004540d004109200379a74103766b21040b417f200120026a20056a20046a2201417f417f20001089828080002202200041d8006a1089828080006a220420042002491b2202200041b0016a1089828080006a220020002002491b6a220020002001491b0b940704057f017e037f017e23808080800041e0006b2201248080808000200141306a41ddebc08000410c41baebc08000411441c0e9c08000410010d882808000200141286a420437020020014200370220200142808080808001370218200142888080808001370240200142808080808001370248200141186a200141c0006a108f82808000200141086a41086a200141186a41146a2802003602002001200129022437030820012802182102200128021c2103200128022021042001280230210520012902342106200141186a41086a22074100360200200142808080808001370218200141186a4100109682808000200128021c200728020041386c6a2208420437022c20084206370224200841a5eec080003602202008410a36021c200841d7eec08000360218200841ae808080003602102008428a96cd9bb2e69e8d723703082008429b99b4f08dc8ccdea77f370300200141c0006a41086a2209200728020041016a220836020020012001290218220a37034002402008200aa7470d00200141c0006a2008109682808000200128024821080b2001280244200841386c6a2208420437022c20084206370224200841a5eec080003602202008410936021c200841e1eec08000360218200841ae808080003602102008428a96cd9bb2e69e8d723703082008429b99b4f08dc8ccdea77f3703002007200928020041016a220836020020012001290340220a37031802402008200aa7470d00200141186a2008109682808000200128022021080b200128021c200841386c6a2208420437022c20084221370224200841f3eec080003602202008410936021c200841eaeec08000360218200841b8808080003602102008429de3c1c199ed89c7f200370308200842b6a3f7ac9ac487f47237030020012802202107200128021c210820012001280218360220200120083602182001200836021c20012008200741386c6a41386a360224200141d4006a200141186a108e8280800002402005418080808078470d0041e3ecc08000411141d4edc0800010a181808000000b200141cb006a200141d4006a41086a2802003600002000200236024420002005360238200041003a000020002001290308370350200041cc006a2004360200200041c8006a20033602002000413c6a20063702002001200129025437004320002001290040370001200041d8006a200141086a41086a280200360200200041086a200141c7006a290000370000200141e0006a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b220641246e2207200128020822014101764f0d01410021082002410036020c20024280808080c00037020441042109024020052004460d00200241046a4100200710988280800020022802082109200228020c21080b2009200841246c6a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b41246e2107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b220641386e2207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710998280800020022802082109200228020c21080b2009200841386c6a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b41386e2107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b22064105762207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710978280800020022802082109200228020c21080b200920084105746a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b4105762107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000be50604047f017e027f017e23808080800041d0006b2201248080808000200141306a41ecebc08000411041fcebc08000411741ecebc08000410010d8828080002001412c6a410036020020014280808080c00037022441002d00fca3c680001a02400240412041002802c8a3c68000118180808000002202450d00200242d7c9cb8fc1cf97db3e370308200241b5808080003602182002410136020420024193ecc08000360200200241106a42e88488d0c0e3aebc13370300200141086a41086a200141246a220341086a280200360200200120032902003703082001280230210420012902342105200141186a41086a22064100360200200142808080808001370218200141186a4100109682808000200128021c200628020041386c6a2203420437022c20034201370224200341ededc080003602202003410636021c200341eeedc08000360218200341b580808000360210200342e88488d0c0e3aebc13370308200342d7c9cb8fc1cf97db3e370300200141c0006a41086a2207200628020041016a2203360200200120012902182208370340024020032008a7470d00200141c0006a2003109682808000200128024821030b2001280244200341386c6a2203420437022c20034201370224200341ededc080003602202003410b36021c200341f4edc08000360218200341b580808000360210200342e88488d0c0e3aebc13370308200342d7c9cb8fc1cf97db3e3703002006200728020041016a2203360200200120012903402208370318024020032008a7470d00200141186a2003109682808000200128022021030b200128021c200341386c6a2203420437022c20034201370224200341ededc080003602202003410936021c200341e4edc08000360218200341b580808000360210200342e88488d0c0e3aebc13370308200342d7c9cb8fc1cf97db3e3703002004418080808078460d012001280220210320012802182106200128021c210720004101360244200020043602382000200736020820002006360204200041003a000020002001290308370350200041cc006a4101360200200041c8006a20023602002000413c6a20053702002000200341016a36020c200041d8006a200141106a280200360200200141d0006a2480808080000f0b4108412010b280808000000b41e3ecc08000411141d4edc0800010a181808000000be90604047f017e027f017e23808080800041d0006b2201248080808000200141306a41ecebc08000411041fcebc08000411741ecebc08000410010d8828080002001412c6a410036020020014280808080c00037022441002d00fca3c680001a02400240412041002802c8a3c68000118180808000002202450d0020024296a2989994a79f81d800370308200241bb808080003602182002410136020420024193ecc08000360200200241106a4295f8a9f7f1dbffef28370300200141086a41086a200141246a220341086a280200360200200120032902003703082001280230210420012902342105200141186a41086a22064100360200200142808080808001370218200141186a4100109682808000200128021c200628020041386c6a2203420437022c20034201370224200341ededc080003602202003410636021c200341eeedc08000360218200341bb8080800036021020034295f8a9f7f1dbffef2837030820034296a2989994a79f81d800370300200141c0006a41086a2207200628020041016a2203360200200120012902182208370340024020032008a7470d00200141c0006a2003109682808000200128024821030b2001280244200341386c6a2203420437022c20034201370224200341ededc080003602202003410b36021c200341f4edc08000360218200341bb8080800036021020034295f8a9f7f1dbffef2837030820034296a2989994a79f81d8003703002006200728020041016a2203360200200120012903402208370318024020032008a7470d00200141186a2003109682808000200128022021030b200128021c200341386c6a2203420437022c20034201370224200341ededc080003602202003410936021c200341e4edc08000360218200341bb8080800036021020034295f8a9f7f1dbffef2837030820034296a2989994a79f81d8003703002004418080808078460d012001280220210320012802182106200128021c210720004101360244200020043602382000200736020820002006360204200041003a000020002001290308370350200041cc006a4101360200200041c8006a20023602002000413c6a20053702002000200341016a36020c200041d8006a200141106a280200360200200141d0006a2480808080000f0b4108412010b280808000000b41e3ecc08000411141d4edc0800010a181808000000b9e0405027f017e017f017e027f23808080800041c0006b2201248080808000200141286a4194ecc0800041054199ecc08000410c41ecebc08000410010d882808000200141086a410036020020014280808080c00037030020012802282102200129022c21032001410036021820014280808080c000370210200141346a200141106a41a5ecc08000410e109b828080000240200128023c22042001280234470d00200141346a2004109582808000200128023c21040b2001280238200441246c6a220441013a00202004410c36021c200441b3ecc080003602182004420437021020044200370208200442808080808001370200200141106a41086a200141346a41086a28020041016a2204360200200120012902342205370310024020042005a7470d00200141106a2004109582808000200128021821040b2001280214200441246c6a220441023a00202004410e36021c200441bfecc08000360218200442043702102004420037020820044280808080800137020002402002418080808078470d0041e3ecc08000411141d4edc0800010a181808000000b200128021421042001280210210620012802182107200042808080808001370244200020023602382000200436020820002006360204200041013a000020002001290300370350200041cc006a41003602002000413c6a20033702002000200741016a36020c200041d8006a200141086a280200360200200141c0006a2480808080000bb80405027f017e027f017e017f23808080800041c0006b2201248080808000200141246a41cdecc0800041164199ecc08000410c41ecebc08000410010d882808000200141086a410036020020014280808080c00037030020012802242102200129022821032001410c6a41086a2204410036020020014280808080800137020c2001410c6a41001096828080002001280210200428020041386c6a2205420437022c20054213370224200541a3efc080003602202005410c36021c20054197efc08000360218200541bc80808000360210200542b2b8a880edaaf0a1c000370308200542e1ffbd85d68ecce4b97f370300200141306a41086a200428020041016a22053602002001200129020c2206370330024020052006a7470d00200141306a2005109682808000200128023821050b2001280234200541386c6a2205420437022c20054219370224200541bfefc080003602202005410936021c200541b6efc08000360218200541bd80808000360210200542efc9c9edb5e7b3a6c700370308200542acf6debeefe0d9c8d30037030002402002418080808078470d0041e3ecc08000411141d4edc0800010a181808000000b200128023821052001280230210420012802342107200042808080808001370244200020023602382000200736020820002004360204200041003a000020002001290300370350200041cc006a41003602002000413c6a20033702002000200541016a36020c200041d8006a200141086a280200360200200141c0006a2480808080000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141246c2104200141e4f1b81c4941027421050240024020030d00200241003602180c010b200241043602182002200341246c36021c200220002802043602140b200241086a20052004200241146a109482808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141386c210420014193c9a4124941037421050240024020030d00200241003602180c010b200241083602182002200341386c36021c200220002802043602140b200241086a20052004200241146a109482808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b22024105742104200241808080204941037421050240024020010d00200341003602180c010b200341083602182003200141057436021c200320002802043602140b200341086a20052004200341146a109482808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b220241246c2104200241e4f1b81c4941027421050240024020010d00200341003602180c010b200341043602182003200141246c36021c200320002802043602140b200341086a20052004200341146a109482808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b220241386c210420024193c9a4124941037421050240024020010d00200341003602180c010b200341083602182003200141386c36021c200320002802043602140b200341086a20052004200341146a109482808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bbf0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a41001096828080002004280208200428020c220541386c6a2206410036023020064280808080c0003703282006410036022020064100360218200641ae808080003602102006428a96cd9bb2e69e8d723703082006429b99b4f08dc8ccdea77f37030020042802042107200428020821080240200128020822062001280200470d0020012006109582808000200128020821060b2001280204200641246c6a220641013a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bbd0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a41001096828080002004280208200428020c220541386c6a2206420437022c2006420337022420064194efc0800036022020064100360218200641b580808000360210200642e88488d0c0e3aebc13370308200642d7c9cb8fc1cf97db3e37030020042802042107200428020821080240200128020822062001280200470d0020012006109582808000200128020821060b2001280204200641246c6a220641003a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000be708012d7e0240200141184b0d000240411820016b41037441e8efc080006a41a8f1c08000460d00410020014103746b210120002903c0012102200029039801210320002903702104200029034821052000290320210620002903b80121072000290390012108200029036821092000290340210a2000290318210b20002903b001210c200029038801210d2000290360210e2000290338210f2000290310211020002903a8012111200029038001211220002903582113200029033021142000290308211520002903a00121162000290378211720002903502118200029032821192000290300211a03402017201685201885201985201a85221b200d200c85200e85200f85201085221c42018985221d201485211e201b4201892008200785200985200a85200b85221f85221b2002852120201d2011854202892221201c2003200285200485200585200685222242018985221c200a8542378922232012201185201385201485201585220a201f42018985221f201085423e892224427f8583852102200a42018920228522102017854229892222201b2004854227892225427f85832023852111201d201385420a892226201c2007854238892227201f200d85420f892228427f858385210d202620102019854224892229427f8583201b200685421b89222a852117201f200f85420689222b201d201585420189222c427f858320102016854212892216852104201b200385420889222d201c200985421989222e427f8583202b852113201b200585421489221b201c200b85421c89220b427f8583201f200c85423d89220f852105201d201285422d89221d200b200f427f858385210a200f201d427f85832010201885420389221585210f201d2015427f8583201b8521142015201b427f8583200b8521192010201a85221d2020420e89221b427f8583201c200885421589221c85210b201b201c427f8583201f200e85422b89221f852110201e422c892206201c201f427f8583852115200141a8f1c080006a290300201f2006427f858385201d85211a2029202a427f8583202785221c21032006201d427f8583201b85221d210620242021427f8583202285221b2107202a2027427f8583202885221f2108202c2016427f8583202d852227210920212022427f85832025852221210c2016202d427f8583202e852222210e20282026427f85832029852226211220252023427f858320248522232116202c202e202b427f85838522242118200141086a22010d000b200020233703a001200020173703782000202437035020002019370328200020113703a8012000202637038001200020133703582000201437033020002015370308200020213703b0012000200d37038801200020223703602000200f370338200020103703102000201b3703b8012000201f37039001200020273703682000200a3703402000200b370318200020023703c0012000201c3703980120002004370370200020053703482000201d3703202000201a3703000b0f0b4181f2c0800041c10041c4f2c0800010f880808000000b02000b040041000b02000b02000bc00202057f057e23808080800041d0006b220524808080800002402003450d00200541186a420037020020054101360210200541b8f3c0800036020c200541d4f2c080003602142005410c6a41a4f4c0800010f680808000000b4100280290a1c680002103410028028ca1c6800021064100280280a4c6800021072002280210220828020821092000290200210a2002290208210b2008290200210c2002290200210d2000290208210e200541c8006a2000290210370200200541c0006a200e370200200541306a200d370200200541246a200c370200200541186a200b3702002005200a3702382005200136022c2005410036022020054100360214200520093602102005410136020c200641ecf2c08000200741024622021b2005410c6a200341d4f2c0800020021b28021011848080800000200541d0006a2480808080000bf60201037f2380808080004180016b22022480808080002000280200210002400240024002400240200128021c22034110710d0020034120710d0120003100004101200110fe8080800021000c020b20002d00002103410021000340200220006a41ff006a413041d7002003410f712204410a491b20046a3a00002000417f6a2100200341ff017122044104762103200441104f0d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000c010b20002d00002103410021000340200220006a41ff006a413041372003410f712204410a491b20046a3a00002000417f6a2100200341ff017122044104762103200441104f0d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000b20024180016a24808080800020000f0b200341800141c88dc08000109481808000000b200341800141c88dc08000109481808000000b02000b4601017f23808080800041106b22042480808080002004200136020c200420003602084100200441086a41b4f4c080002004410c6a41b4f4c080002002200310fb80808000000ba70401037f23808080800041206b22022480808080002002200141087122033a000702400240024020030d00200020013a00ca0120002d00c9012104200020002d00c801220341016a3a00c9010240200341c7014b0d00200020036a220320032d00002004733a0000200020002d00c80141016a22033a00c80102400240200341ff0171220341a601470d00200020002d00a60120002d00c901733a00a601200020002d00a701418401733a00a70120004118109c8280800041002103200041003b01c8010c010b200341c7014b0d010b200020036a220320032d00002001733a0000200020002d00c80141016a22033a00c801024002400240200341ff017141a601470d00200020002d00a60120002d00c901733a00a60141840121030c010b2001412471450d01200341ff01712203450d01200341c7014b0d04200020036a220320032d000020002d00c901733a000020002d00c80141016a41ff0171220341c8014f0d05200020036a220320032d00004104733a000041800121030b200020002d00a7012003733a00a70120004118109c82808000200041003b01c8010b200241206a2480808080000f0b200341c80141d4f5c0800010f980808000000b20024200370214200241b4f4c080003602102002410136020c200241b4f6c08000360208200241076a41bcf6c08000200241086a41c0f6c0800010a482808000000b200341c80141b4f5c0800010f980808000000b200341c80141c4f5c0800010f980808000000b890d01027f23808080800041a0036b2203248080808000200341002f00a4f5c080003b0104200341002800a0f5c08000360200200341126a410041b601108a8e8080001a2003410e6a41002800aef5c08000360100200341002900a6f5c0800037010620034118109c82808000200341d0016a200341c80110848e8080001a200341003a009a03200341003b019803200341d0016a411210a582808000024020032d009803220441c7014b0d00200341d0016a20046a220420042d000041cd00733a0000200320032d00980341016a22043a00980302400240200441ff0171220441a601470d00200320032d00f60220032d009903733a00f602200320032d00f702418401733a00f702200341d0016a4118109c8280800041002104200341003b0198030c010b200441c7014b0d010b200341d0016a20046a220420042d000041e500733a0000200320032d00980341016a22043a00980302400240200441ff0171220441a601470d00200320032d00f60220032d009903733a00f602200320032d00f702418401733a00f702200341d0016a4118109c8280800041002104200341003b0198030c010b200441c7014b0d010b200341d0016a20046a220420042d000041f200733a0000200320032d00980341016a22043a00980302400240200441ff0171220441a601470d00200320032d00f60220032d009903733a00f602200320032d00f702418401733a00f702200341d0016a4118109c8280800041002104200341003b0198030c010b200441c7014b0d010b200341d0016a20046a220420042d000041ec00733a0000200320032d00980341016a22043a00980302400240200441ff0171220441a601470d00200320032d00f60220032d009903733a00f602200320032d00f702418401733a00f702200341d0016a4118109c8280800041002104200341003b0198030c010b200441c7014b0d010b200341d0016a20046a220420042d000041e900733a0000200320032d00980341016a22043a00980302400240200441ff0171220441a601470d00200320032d00f60220032d009903733a00f602200320032d00f702418401733a00f702200341d0016a4118109c8280800041002104200341003b0198030c010b200441c7014b0d010b200341d0016a20046a220420042d000041ee00733a0000200320032d00980341016a22043a00980302400240200441ff0171220441a601470d00200320032d00f60220032d009903733a00f602200320032d00f702418401733a00f702200341d0016a4118109c8280800041002104200341003b0198030c010b200441c7014b0d010b200341d0016a20046a220420042d00004120733a0000200320032d00980341016a22043a00980302400240200441ff0171220441a601470d00200320032d00f60220032d009903733a00f602200320032d00f702418401733a00f702200341d0016a4118109c8280800041002104200341003b0198030c010b200441c7014b0d010b200341d0016a20046a220420042d000041f600733a0000200320032d00980341016a22043a00980302400240200441ff0171220441a601470d00200320032d00f60220032d009903733a00f602200320032d00f702418401733a00f702200341d0016a4118109c8280800041002104200341003b0198030c010b200441c7014b0d010b200341d0016a20046a220420042d00004131733a0000200320032d00980341016a22043a00980302400240200441ff0171220441a601470d00200320032d00f60220032d009903733a00f602200320032d00f702418401733a00f702200341d0016a4118109c8280800041002104200341003b0198030c010b200441c7014b0d010b200341d0016a20046a220420042d0000412e733a0000200320032d00980341016a22043a00980302400240200441ff0171220441a601470d00200320032d00f60220032d009903733a00f602200320032d00f702418401733a00f702200341d0016a4118109c8280800041002104200341003b0198030c010b200441c7014b0d010b200341d0016a20046a220420042d00004130733a0000200320032d00980341016a22043a0098030240200441ff017141a601470d00200320032d00f60220032d009903733a00f602200320032d00f702418401733a00f702200341d0016a4118109c82808000200341003b0198030b2003200341d0016a41d00110848e808000220341a0f7c0800041072001200210a7828080002000200341d00110848e8080001a200341a0036a2480808080000f0b200441c80141d4f5c0800010f980808000000b8c0901027f23808080800041f0006b22052480808080002000411210a582808000024002400240024002402002450d0020002d00c80121060340200641ff0171220641c7014b0d02200020066a220620062d000020012d0000733a0000200020002d00c80141016a22063a00c8010240200641ff017141a601470d00200020002d00a60120002d00c901733a00a601200020002d00a701418401733a00a70120004118109c8280800041002106200041003b01c8010b200141016a21012002417f6a22020d000b0b200541123a000720002d00ca014112470d0120002d00c801220641c7014b0d02200020066a220620062d00002004733a0000200020002d00c80141016a22063a00c80102400240200641ff0171220641a601470d00200020002d00a60120002d00c901733a00a601200020002d00a701418401733a00a70120004118109c8280800041002106200041003b01c8010c010b200641c7014b0d030b200020066a220620062d00002004410876733a0000200020002d00c80141016a22063a00c80102400240200641ff0171220641a601470d00200020002d00a60120002d00c901733a00a601200020002d00a701418401733a00a70120004118109c8280800041002106200041003b01c8010c010b200641c7014b0d030b200020066a220620062d00002004411076733a0000200020002d00c80141016a22063a00c80102400240200641ff0171220641a601470d00200020002d00a60120002d00c901733a00a601200020002d00a701418401733a00a70120004118109c8280800041002106200041003b01c8010c010b200641c7014b0d030b200020066a220620062d00002004411876733a0000200020002d00c80141016a22063a00c8010240200641ff017141a601470d00200020002d00a60120002d00c901733a00a601200020002d00a701418401733a00a70120004118109c82808000200041003b01c8010b2000410210a58280800002402004450d0020002d00c80121060340200641ff0171220641c7014b0d05200020066a220620062d000020032d0000733a0000200020002d00c80141016a22063a00c8010240200641ff017141a601470d00200020002d00a60120002d00c901733a00a601200020002d00a701418401733a00a70120004118109c8280800041002106200041003b01c8010b200341016a21032004417f6a22040d000b0b200541f0006a2480808080000f0b200641c80141d4f5c0800010f980808000000b2005412c6a41c280808000360200200541c2808080003602242005200041ca016a22003602202005200541076a360228200541ec006a41033a0000200541e8006a4104360200200541e0006a42a080808010370200200541d8006a41023602002005410236021c200541023602142005410236020c20054180f7c0800036020820054102360250200541033a004c200541043602482005422037024020054102360238200541023602302005200541306a3602182005200541206a3602102000200541076a200541086a4190f7c0800010a482808000000b200641c80141d4f5c0800010f980808000000b200641c80141d4f5c0800010f980808000000b910901027f23808080800041f0006b22052480808080002000411210a582808000024002400240024002402002450d0020002d00c80121060340200641ff0171220641c7014b0d02200020066a220620062d000020012d0000733a0000200020002d00c80141016a22063a00c8010240200641ff017141a601470d00200020002d00a60120002d00c901733a00a601200020002d00a701418401733a00a70120004118109c8280800041002106200041003b01c8010b200141016a21012002417f6a22020d000b0b200541123a000720002d00ca014112470d0120002d00c801220641c7014b0d02200020066a220620062d00002004733a0000200020002d00c80141016a22063a00c80102400240200641ff0171220641a601470d00200020002d00a60120002d00c901733a00a601200020002d00a701418401733a00a70120004118109c8280800041002106200041003b01c8010c010b200641c7014b0d030b200020066a220620062d00002004410876733a0000200020002d00c80141016a22063a00c80102400240200641ff0171220641a601470d00200020002d00a60120002d00c901733a00a601200020002d00a701418401733a00a70120004118109c8280800041002106200041003b01c8010c010b200641c7014b0d030b200020066a220620062d00002004411076733a0000200020002d00c80141016a22063a00c80102400240200641ff0171220641a601470d00200020002d00a60120002d00c901733a00a601200020002d00a701418401733a00a70120004118109c8280800041002106200041003b01c8010c010b200641c7014b0d030b200020066a220620062d00002004411876733a0000200020002d00c80141016a22063a00c8010240200641ff017141a601470d00200020002d00a60120002d00c901733a00a601200020002d00a701418401733a00a70120004118109c82808000200041003b01c8010b2000410710a58280800002402004450d0020002d00c80121060340200641ff0171220641c8014f0d05200020066a22062d00002101200641003a0000200320013a0000200020002d00c80141016a22063a00c8010240200641ff017141a601470d00200020002d00a60120002d00c901733a00a601200020002d00a701418401733a00a70120004118109c8280800041002106200041003b01c8010b200341016a21032004417f6a22040d000b0b200541f0006a2480808080000f0b200641c80141d4f5c0800010f980808000000b2005412c6a41c280808000360200200541c2808080003602242005200041ca016a22003602202005200541076a360228200541ec006a41033a0000200541e8006a4104360200200541e0006a42a080808010370200200541d8006a41023602002005410236021c200541023602142005410236020c20054180f7c0800036020820054102360250200541033a004c200541043602482005422037024020054102360238200541023602302005200541306a3602182005200541206a3602102000200541076a200541086a4190f7c0800010a482808000000b200641c80141d4f5c0800010f980808000000b200641c80141e4f5c0800010f980808000000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141246c2104200141e4f1b81c4941027421050240024020030d00200241003602180c010b200241043602182002200341246c36021c200220002802043602140b200241086a20052004200241146a10a982808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141386c210420014193c9a4124941037421050240024020030d00200241003602180c010b200241083602182002200341386c36021c200220002802043602140b200241086a20052004200241146a10a982808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000be10405027f017e037f017e017f23808080800041d0006b2201248080808000200141306a41a8f7c08000410741aff7c08000411641a8f7c08000410010d882808000200141086a41086a410036020020014280808080c0003703082001280230210220012902342103200141186a41086a2204410036020020014280808080c000370218200141186a410010aa82808000200141c0006a41086a2004280200220541016a2206360200200128021c200541246c6a220541003a00202005410336021c200541c5f7c080003602182005420437021020054200370208200542808080808001370200200120012902182207370340024020062007a7470d00200141c0006a200610aa82808000200128024821060b2004200641016a22083602002001280244200641246c6a220541013a00202005410436021c200541c8f7c080003602182005420437021020054200370208200542808080808001370200200120012903402207370318024020082007a72206470d00200141186a200810aa8280800020012802182106200128022021080b200128021c2204200841246c6a220541023a00202005410336021c200541ccf7c08000360218200542043702102005420037020820054280808080800137020002402002418080808078470d0041fcf7c08000411141f0f8c0800010a181808000000b200042808080808001370244200020023602382000200436020820002006360204200041013a000020002001290308370350200041cc006a41003602002000413c6a20033702002000200841016a36020c200041d8006a200141106a280200360200200141d0006a2480808080000bf20203027f017e047f23808080800041306b2201248080808000200141246a41cff7c08000410a41aff7c08000411641a8f7c08000410010d882808000200141086a2202410036020020014280808080c00037030020012902282103200128022421042001410036021420014280808080800137020c2001410c6a410010ab82808000200128021022052001280214220641386c6a220742e987d8bed5a3d0fbfb00370308200742e2e68fceaa92ce9c7b3703002007420437022c2007420437022420074180f9c0800036022020074100360218200741c58080800036021002402004418080808078470d0041fcf7c08000411141f0f8c0800010a181808000000b200128020c2107200042808080808001370244200020043602382000200536020820002007360204200041003a000020002001290300370350200041cc006a41003602002000413c6a20033702002000200641016a36020c200041d8006a2002280200360200200141306a2480808080000be70305027f017e027f017e027f23808080800041c0006b2201248080808000200141246a41d9f7c08000411341aff7c08000411641a8f7c08000410010d882808000200141086a410036020020014280808080c00037030020012802242102200129022821032001410c6a41086a2204410036020020014280808080c00037020c2001410c6a410010aa82808000200141306a41086a2004280200220441016a22053602002001280210200441246c6a220441003a00202004410836021c200441ecf7c0800036021820044204370210200442003702082004428080808080013702002001200129020c2206370330024020052006a72207470d00200141306a200510aa8280800020012802302107200128023821050b20012802342208200541246c6a220441013a00202004410836021c200441f4f7c08000360218200442043702102004420037020820044280808080800137020002402002418080808078470d0041fcf7c08000411141f0f8c0800010a181808000000b200042808080808001370244200020023602382000200836020820002007360204200041013a000020002001290300370350200041cc006a41003602002000413c6a20033702002000200541016a36020c200041d8006a200141086a280200360200200141c0006a2480808080000bed0201037f2380808080004180016b220224808080800002400240024002400240200128021c22034110710d0020034120710d0120003502004101200110fe8080800021000c020b20002802002100410021030340200220036a41ff006a413041d7002000410f712204410a491b20046a3a00002003417f6a210320004110492104200041047621002004450d000b20034180016a22004180014b0d022001410141c48dc080004102200220036a4180016a410020036b10db8080800021000c010b20002802002100410021030340200220036a41ff006a413041372000410f712204410a491b20046a3a00002003417f6a210320004110492104200041047621002004450d000b20034180016a22004180014b0d022001410141c48dc080004102200220036a4180016a410020036b10db8080800021000b20024180016a24808080800020000f0b200041800141c88dc08000109481808000000b200041800141c88dc08000109481808000000b860201017f024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d0020020d02410121010c030b20032802002103200241002802c8a3c68000118180808000002201450d0320012003200410848e8080001a200341002802c0a3c68000118080808000000c020b20020d00410121010c010b41002d00fca3c680001a200241002802c8a3c68000118180808000002201450d010b20002001360204200041086a2002360200200041003602000f0b20004101360204200041086a2002360200200041013602000f0b20004100360204200041086a2002360200200041013602000f0b20004100360204200041013602000be20101027f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024108200241084b1b2202417f73411f7621040240024020010d00200341003602180c010b2003200136021c20034101360218200320002802043602140b200341086a20042002200341146a10b082808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bc10601067f23808080800041306b220224808080800002400240024002400240024002402001280208220320012802102204460d0002400240024002400240200441016a2205450d0020032005490d0120012802042106200120053602100240024002400240200620046a2d000022074103710e0400020103000b200741027621040c070b200241096a20073a0000200241013a0008200220013602042002410036021c200241046a2002411c6a410410b3828080000d07200228021c220541808004490d07200541027621040c050b200241096a20073a0000200241013a000820022001360204200241003b011c200241046a2002411c6a410210b3828080000d0620022f011c2205418002490d06200541027621040c040b20074104490d020c050b417f20054190fbc08000109681808000000b200520034190fbc08000109581808000000b200320056b4104490d02200441056a21042005417b4b0d04200420034b0d0520012004360210200620056a2800002204418080808004490d020b20012802082103200128021021050b2002200536020020032005490d042001200320056b22033602082001200128020420056a220536020420014100360210200420034d0d01200041003602000c060b200041003602000c050b20032004460d03024020040d00200042003702082000419c88c080003602042000418489c080003602000c050b200241046a2001410c6a20052003200128020028020011868080800000200241046a41086a22052004360200200020022902043702002001200128020820046b3602082001200128020420046a360204200041086a20052902003702000c040b200520044190fbc08000109681808000000b200420034190fbc08000109581808000000b2002411c6a410c6a41c680808000360200200241046a410c6a420237020020024102360208200241acf9c08000360204200241c6808080003602202002200336022c20022002411c6a36020c20022002412c6a3602242002200236021c200241046a4198fac0800010f680808000000b200020012902003702002001419c88c080003602042001418489c08000360200200041086a200141086a2201290200370200200142003702000b200241306a2480808080000ba10201037f20002d00042103200041003a0004024002400240024002400240024020030d0041012103200028020022002802082204200028021022056b2002490d02200520026a22032005490d03200320044b0d042001200028020420056a200210848e8080001a200020033602100c010b2001200041056a2d00003a000041012103200028020022002802082204200028021022056b2002417f6a2202490d01200520026a22032005490d04200320044b0d05200141016a200028020420056a200210848e8080001a200020033602100b410021030b20030f0b200520034190fbc08000109681808000000b200320044190fbc08000109581808000000b200520034190fbc08000109681808000000b200320044190fbc08000109581808000000bc40301047f23808080800041106b2203248080808000024002400240024002400240200241046a2204450d002004417f4c0d0241002d00fca3c680001a200441002802c8a3c68000118180808000002205450d03200320053602082003200436020402402002413f4b0d00200520024102743a0000410121060c060b200241ffff004b0d0141022106200520024102744101723b00000c050b2003410036020c2003428080808010370204200341046a4100410110b1828080002003280208210520032802042104200328020c21060c030b41002106200241ffffffff034b0d0220052002410274410272360000410421060c030b10ae80808000000b4101200410b280808000000b200520066a41033a00002003200641016a220636020c0240200420066b41034b0d00200341046a2006410410b1828080002003280204210420032802082105200328020c21060b200520066a2002360000200641046a21060b2003200636020c0240200420066b20024f0d00200341046a2006200210b18280800020032802082105200328020c21060b200520066a2001200210848e8080001a200041086a200620026a36020020002003290204370200200341106a2480808080000b2100200128021441a0fbc08000410b200141186a28020028020c118280808000000b840303027f017e047f23808080800041306b2201248080808000200141246a41bbfbc08000410441acfbc08000410f41acfbc08000410010d882808000200141086a2202410036020020014280808080c00037030020012902282103200128022421042001410036021420014280808080800137020c2001410c6a410010b782808000200128021022052001280214220641386c6a220742a4d2928ecac0faa432370308200742c4ccab9c81ebb4b8db003703002007420437022c20074208370224200741c0fcc0800036022020074100360218200741c78080800036021002402004418080808078470d0041bffbc08000411141b0fcc0800010a181808000000b200128020c210720014288808080800137020c200142808080808001370214200041c4006a2001410c6a10b8828080002000413c6a2003370200200020043602382000200641016a36020c2000200536020820002007360204200041003a000020002001290300370350200041d8006a2002280200360200200141306a2480808080000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141386c210420014193c9a4124941037421050240024020030d00200241003602180c010b200241083602182002200341386c36021c200220002802043602140b200241086a20052004200241146a10ba82808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b22064105762207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710b98280800020022802082109200228020c21080b200920084105746a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b4105762107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b22024105742104200241808080204941037421050240024020010d00200341003602180c010b200341083602182003200141057436021c200320002802043602140b200341086a20052004200341146a10ba82808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000b7600200042dbd791d5c2919eaecd0037030820004280808080c00037033820004280808080c00037035020004120360220200041c880808000360218200041033a0000200041106a42e6ed8d82cc91adcb05370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000bda0303017f017e047f0240024020004280808080105a0d0020012102200021030c010b200141786a220220004280c2d72f8022034280bea8d00f7e20007ca722044190ce006e22054190ce0070220641ffff037141e4006e22074101744188d0c180006a2f00003b00002001417c6a200420054190ce006c6b220441ffff037141e4006e22054101744188d0c180006a2f00003b00002001417a6a2006200741e4006c6b41ffff03714101744188d0c180006a2f00003b00002001417e6a2004200541e4006c6b41ffff03714101744188d0c180006a2f00003b00000b024002402003a722014190ce004f0d00200121040c010b2002417c6a21020340200220014190ce006e220441f0b17f6c20016a220541e4006e22064101744188d0c180006a2f00003b0000200241026a2005200641e4006c6b4101744188d0c180006a2f00003b00002002417c6a2102200141ffc1d72f4b21052004210120050d000b200241046a21020b02400240200441e3004b0d00200421010c010b2002417e6a22022004200441ffff037141e4006e220141e4006c6b41ffff03714101744188d0c180006a2f00003b00000b0240200141094b0d002002417f6a200141306a3a00000f0b2002417e6a20014101744188d0c180006a2f00003b00000bb51509017f027e037f017e027f037e017f027e017f23808080800041a0026b22022480808080002000bd220342ffffffffffffff078321042003423488a7210541002106024020034200590d002001412d3a0000410121060b200541ff0f712105024002400240024002400240024020044200520d002005450d010b20044200522005410249722107200442808080808080800884200420051b22034202862104200342018321080240200541cb776a41cc7720051b2205417f4a0d0020024190026a41a8a7c1800020054185a2536c4114762005417f476b220920056a220a41047422056b290300220342002004420284220b420010878e80800020024180026a41b0a7c1800020056b290300220c4200200b420010878e808000200241f0016a20024190026a41086a290300220b2002290380027c220d20024180026a41086a290300200d200b54ad7c2009200a41b1d9b51f6c4113766b413c6a41ff0071220510fc8d808000200241b0016a2003420020042007ad427f857c220b420010878e808000200241a0016a200c4200200b420010878e80800020024190016a200241b0016a41086a290300220b20022903a0017c220d200241a0016a41086a290300200d200b54ad7c200510fc8d808000200241e0016a200342002004420010878e808000200241d0016a200c42002004420010878e808000200241c0016a200241e0016a41086a290300220320022903d0017c220c200241d0016a41086a290300200c200354ad7c200510fc8d80800020022903c001210b200229039001210d20022903f001210c024020094102490d002009413e4b0d032004427f2009ad86427f858350450d030c040b200c20087d210c200720085071210e410121090c040b20024180016a200541c1e8046c411276200541034b6b220a410474220941c8fcc080006a290300220c420020044202842203420010878e808000200241f0006a200941d0fcc080006a290300220b42002003420010878e808000200241e0006a20024180016a41086a290300220d20022903707c220f200241f0006a41086a290300200f200d54ad7c200a20056b200a41cfa6ca006c4113766a413d6a41ff0071220510fc8d808000200241206a200c420020042007ad2210427f857c220d420010878e808000200241106a200b4200200d420010878e8080002002200241206a41086a290300220d20022903107c220f200241106a41086a290300200f200d54ad7c200510fc8d808000200241d0006a200c42002004420010878e808000200241c0006a200b42002004420010878e808000200241306a200241d0006a41086a290300220c20022903407c220b200241c0006a41086a290300200b200c54ad7c200510fc8d8080002002290330210b2002290300210d2002290360210c200a41164f0d0102402004420580a7417b6c41002004a76b470d00417f210503402004a72107200541016a210520044205802204a7417b6c410020076b460d000b2005200a4f0d030c020b02402008500d00417f210503402003a72107200541016a210520034205802203a7417b6c410020076b460d000b200c2005200a4fad7d210c0c020b2010427f8520047c2104417f210503402004a72107200541016a210520044205802204a7417b6c410020076b460d000b2005200a490d014101210e410021090c030b200120066a220541002f00d0d1c180003b0000200541026a41002d00d2d1c180003a00002003423f88a741036a21050c040b4100210702400240200c42e400802203200d42e40080220f560d0041002105200d210f200c2103200b21040c010b200b42e400802204a7419c7f6c200ba76a41314b2107410221050b02402003420a802203200f420a80220c580d000340200541016a21052004220b420a8021042003420a802203200c220f420a80220c560d000b2004a741766c200ba76a41044b21070b2004200f5120077221070c020b4100210e410121090b4100210702400240200c420a802204200d420a80220f560d0041002105200d2103200b210c0c010b41002105410021070340200e200f2203a741766c4100200da76b4671210e200541016a21052009200741ff017145712109200b420a80220ca741766c200ba76a2107200c210b2003210d2004420a8022042003420a80220f560d000b0b024002400240200e450d002003420a80220ba741766c41002003a76b460d010b200c21040c010b0340200ba72111200541016a21052009200741ff017145712109200c420a802204a741766c200ca76a2107200b2103200b420a80220d210b2004210c200da741766c410020116b460d000b0b2008420052200e417f7372200420035171410441052004420183501b2007200741ff01714105461b200720091b41ff017141044b7221070b2005200a6a210941112105024020042007ad7c220442ffff83fea6dee111560d0041102105200442ffff99a6eaafe301560d00410f2105200442ffffe883b1de16560d00410e2105200442ffbfcaf384a302560d00410d2105200442ff9f94a58d1d560d00410c2105200442ffcfdbc3f402560d00410b2105200442ffc7afa025560d00410a2105200442ff93ebdc03560d0041092105200442ffc1d72f560d0041082105200442fface204560d0041072105200442bf843d560d00410621052004429f8d06560d00410521052004428fce00560d0041042105200442e707560d0041032105200442e300560d004102410120044209561b21050b200520096a2107024002400240024002400240024002400240024020094100480d0020074111480d010b2007417f6a22094110490d01200741046a4105490d02200620016a221141016a210e20054101470d05200e41e5003a000020112004a741306a3a00002001200641027222066a210e20094100480d03200921050c040b20042001200520066a6a220e10bc828080000240200520074e0d00200e41302009108a8e8080001a0b2001200720066a22056a41aee0003b0000200541026a21050c080b200420012005200641016a22096a22056a10bc82808000200120066a200120096a200710fe8d8080001a2001200720066a6a412e3a00000c070b200120066a220e41b0dc003b0000410220076b210902402007417f4a0d00200e41026a413020094103200941034a1b417e6a108a8e8080001a0b20042001200520066a20096a22056a10bc828080000c060b200e412d3a0000410120076b2105200e41016a210e0b200541e3004a0d010240200541094a0d00200e200541306a3a00002009411f7641016a20066a21050c050b200e20054101744188d0c180006a2f00003b00002009411f7641027220066a21050c040b2004200520066a220520016a41016a220610bc828080002011200e2d00003a0000200e412e3a0000200641e5003a00002001200541026a22066a210e20094100480d01200921050c020b200e200541e4006e220741306a3a0000200e2005200741e4006c6b4101744188d0c180006a2f00003b00012009411f7641036a20066a21050c020b200e412d3a0000410120076b2105200e41016a210e0b0240200541e3004a0d000240200541094a0d00200e200541306a3a00002009411f7641016a20066a21050c020b200e20054101744188d0c180006a2f00003b00002009411f7641027220066a21050c010b200e200541e4006e220741306a3a0000200e2005200741e4006c6b4101744188d0c180006a2f00003b00012009411f7641036a20066a21050b200241a0026a24808080800020050b8414030b7f027e057f0240024002400240024002400240024002400240024002400240024002400240024002400240024002400240200128020022062f01e2012207410b490d004101210841042107200128020822094105490d03200921072009417b6a0e020302010b2006200128020822094104746a210a2001280204210b200941016a220120074d0d03200a2002370300200a20033703080c040b200941796a210941002108410621070c010b4100210841052107410021090b2001280204210a41002d00fca3c680001a41e80141002802c8a3c6800011818080800000220c450d05200c41003b01e201200c41003602b001200c20062f01e201220d2007417f736a22013b01e2012001410c4f0d06200d200741016a220e6b2001470d07200641b4016a220d20074102746a280200210f200620074104746a22102903002111201041086a2903002112200c2006200e4104746a200141047410848e808000221041b4016a200d200e4102746a200141027410848e8080001a200620073b01e2012006201020081b221320094104746a210120132f01e201220720094b0d0220012002370300200120033703080c030b200620014104746a200a200720096b220841047410fe8d8080001a200a2003370308200a2002370300200641b4016a220a20014102746a200a20094102746a200841027410fe8d8080001a0b200620094102746a41b4016a20043602002006200741016a3b01e2010c020b2013200941016a220e4104746a2001200720096b220d41047410fe8d8080001a2001200337030820012002370300201341b4016a2201200e4102746a200120094102746a200d41027410fe8d8080001a0b200a410020081b210b201320094102746a41b4016a20043602002013200741016a3b01e20102400240024020062802b00122010d00410021100c010b410021100340200621072012210320112102200f2114200c211520012106200a2010470d0720072f01e001210102400240024020062f01e2012210410b490d004101210e200141054f0d012001210d410421010c020b200141016a2107201041016a2104200620014104746a210a0240024020012010490d00200a2002370300200a2003370308200620014102746a41b4016a20143602000c010b200620074104746a200a201020016b220841047410fe8d8080001a200a2003370308200a2002370300200641b4016a220a2007410274220e6a200a2001410274220d6a220a2008410274220810fe8d8080001a200a2014360200200d200641e8016a220a6a41086a200a200e6a200810fe8d8080001a0b200620043b01e201200620074102746a41e8016a20153602002007201041026a22084f0d040240201020016b220e41016a410371220a450d00200620014102746a41ec016a210103402001280200220420073b01e001200420063602b001200141046a2101200741016a2107200a417f6a220a0d000b0b200e4103490d04200741027420066a41f4016a21010340200141746a280200220a20073b01e001200a20063602b001200141786a280200220a200741016a3b01e001200a20063602b0012001417c6a280200220a200741026a3b01e001200a20063602b0012001280200220a200741036a3b01e001200a20063602b001200141106a21012008200741046a2207470d000c050b0b2001210d024002402001417b6a0e020201000b200141796a210d4100210e410621010c010b4100210e410521014100210d0b41002d00fca3c680001a41980241002802c8a3c6800011818080800000220c450d08200c41003b01e201200c41003602b001200c20062f01e20122042001417f736a22073b01e2012007410c4f0d092004200141016a22086b2007470d0a200641b4016a221620014102746a280200210f200620014104746a22042903002111200441086a2903002112200c200620084104746a200741047410848e808000220441b4016a2016200841027422176a200741027410848e8080001a200620013b01e20120042f01e201220741016a21082007410c4f0d0b201020016b22012008470d0c200a41016a2110200441e8016a200620176a41e8016a200141027410848e80800021084100210102400340200820014102746a280200220a20013b01e001200a20043602b001200120074f0d01200120012007496a220120074d0d000b0b20062004200e1b2207200d4104746a210402400240200d41016a220120072f01e201220a4d0d0020042002370300200420033703080c010b200720014104746a2004200a200d6b220841047410fe8d8080001a2004200337030820042002370300200741b4016a220420014102746a2004200d4102746a200841027410fe8d8080001a0b200a41016a21082007200d4102746a221641b4016a2014360200200741e8016a21040240200d41026a2214200a41026a220e4f0d00200420144102746a200420014102746a200a200d6b41027410fe8d8080001a0b200420014102746a2015360200200720083b01e20102402001200e4f0d000240200a200d6b220d41016a4103712204450d00201641ec016a210a0340200a280200220820013b01e001200820073602b001200a41046a210a200141016a21012004417f6a22040d000b0b200d4103490d00200720014102746a41f4016a210a0340200a41746a280200220420013b01e001200420073602b001200a41786a2802002204200141016a3b01e001200420073602b001200a417c6a2802002204200141026a3b01e001200420073602b001200a2802002204200141036a3b01e001200420073602b001200a41106a210a200e200141046a2201470d000b0b2010210a20062802b00122010d000b0b20052802002207280200220a450d0b2007280204210441002d00fca3c680001a41980241002802c8a3c68000118180808000002201450d0c2001200a3602e801200141003b01e201200141003602b00120072001360200200a41003b01e001200a20013602b0012007200441016a36020420042010470d0d20012f01e2012207410b4f0d0e2001200741016a220a3b01e201200120074104746a2204201237030820042011370300200141e8016a200a4102746a200c360200200120074102746a41b4016a200f360200200c200a3b01e001200c20013602b0010b201321060b200020093602082000200b360204200020063602000f0b410841e80110b280808000000b2001410b4190d5c18000109581808000000b41d8d4c1800041284180d5c1800010f880808000000b41b0d5c18000413541e8d5c1800010f880808000000b410841980210b280808000000b2007410b4190d5c18000109581808000000b41d8d4c1800041284180d5c1800010f880808000000b2008410c41a0d5c18000109581808000000b41d8d4c1800041284180d5c1800010f880808000000b41d8d2c1800010a081808000000b410841980210b280808000000b4188d4c18000413041b8d4c1800010f880808000000b41e8d2c18000412041c8d4c1800010f880808000000bf51f011a7f23808080800041c0016b220524808080800002400240024002400240024002400240024002400240024002400240024002400240024002400240200128020022062f01ee042207410b490d0041012108410421092001280208220a4105490d03200a2109200a417b6a0e020302010b200641046a22092001280208220a4102746a210b2001280204210c02400240200a41016a220120074d0d00200b20023602000c010b200920014102746a200b2007200a6b220941027410fe8d8080001a200b2002360200200641306a220b200141346c6a200b200a41346c6a200941346c10fe8d8080001a0b2006200a41346c6a220141e0006a200341306a280200360200200141d8006a200341286a290200370200200141d0006a200341206a290200370200200141c8006a200341186a290200370200200141c0006a200341106a290200370200200141386a200341086a290200370200200141306a20032902003702002006200741016a3b01ee040c030b200a41796a210a41002108410621090c010b41002108410521094100210a0b2001280204210b41002d00fca3c680001a41f00441002802c8a3c68000118180808000002207450d03200741003b01ee0420074100360200200720062f01ee04220d2009417f736a220e3b01ee0420054198016a200641306a220f200941346c6a2201410c6a290200370300200541a0016a200141146a290200370300200541a8016a2001411c6a290200370300200541b0016a200141246a290200370300200541b8016a2001412c6a2902003703002005200129020437039001200e410c4f0d04200d200941016a22106b200e470d0520012802002111200641046a220120094102746a2802002112200741046a200120104102746a200e41027410848e8080001a200741306a200f201041346c6a200e41346c10848e8080001a200620093b01ee04200541e0006a41086a20054190016a41086a290300370300200541e0006a41106a20054190016a41106a290300370300200541e0006a41186a20054190016a41186a290300370300200541e0006a41206a20054190016a41206a290300370300200541e0006a41286a20054190016a41286a29030037030020052005290390013703602006200720081b221341046a200a4102746a21010240024020132f01ee042209200a4b0d00200120023602000c010b200141046a20012009200a6b220e41027410fe8d8080001a200120023602002013200a41346c6a220141e4006a200141306a200e41346c10fe8d8080001a0b200b410020081b210c2013200a41346c6a220141e0006a200341306a280200360200200141d8006a200341286a290200370200200141d0006a200341206a290200370200200141c8006a200341186a290200370200200141c0006a200341106a290200370200200141386a200341086a290200370200200141306a2003290200370200200541086a2203200541e0006a41086a290300370300200541106a2201200541e0006a41106a290300370300200541186a220e200541e0006a41186a290300370300200541206a2202200541e0006a41206a290300370300200541286a2208200541e0006a41286a2903003703002013200941016a3b01ee04200520052903603703002011418080808078470d01201321060b2000200a3602082000200c360204200020063602000c010b200541306a41286a2008290300370300200541306a41206a2002290300370300200541306a41186a200e290300370300200541306a41106a2001290300370300200541306a41086a200329030037030020052005290300370330024002400240200628020022030d00410021140c010b20054190016a41086a210820054190016a41106a211020054190016a41186a210d20054190016a41206a210f20054190016a41286a21154100211420072116201221172011211803402003210e200b2014470d0720062f01ec042106024002400240200e2f01ee042214410b490d0041012119200641054f0d0120062109410421060c020b200e41046a220b200641027422096a2101200641016a2103201441016a21070240024020062014490d0020012017360200200e200641346c6a220141306a2018360200200141346a20052903303702002001413c6a200541386a290300370200200141c4006a200541c0006a290300370200200141cc006a200541c8006a290300370200200141d4006a200541d0006a290300370200200141dc006a200541d8006a2903003702000c010b200b200341027422026a2001201420066b220b410274220810fe8d8080001a20012017360200200e41306a2201200341346c6a2001200641346c6a2201200b41346c10fe8d8080001a20012018360200200120052903303702042001410c6a200541306a41086a290300370200200141146a200541c0006a2903003702002001411c6a200541c8006a290300370200200141246a200541d0006a2903003702002001412c6a200541d8006a2903003702002009200e41f0046a22016a41086a200120026a200810fe8d8080001a0b200e20073b01ee04200e20034102746a41f0046a20163602002003201441026a220b4f0d040240201420066b220941016a4103712201450d00200e20064102746a41f4046a210603402006280200220720033b01ec042007200e360200200641046a2106200341016a21032001417f6a22010d000b0b20094103490d042003410274200e6a41fc046a21060340200641746a280200220120033b01ec042001200e360200200641786a2802002201200341016a3b01ec042001200e3602002006417c6a2802002201200341026a3b01ec042001200e36020020062802002201200341036a3b01ec042001200e360200200641106a2106200b200341046a2203470d000c050b0b20062109024002402006417b6a0e020201000b200641796a210941002119410621060c010b4100211941052106410021090b41002d00fca3c680001a41a00541002802c8a3c68000118180808000002207450d08200741003b01ee04200741003602002007200e2f01ee0422112006417f736a22013b01ee042008200e41306a221a200641346c6a2203410c6a2902003703002010200341146a290200370300200d2003411c6a290200370300200f200341246a29020037030020152003412c6a29020037030020052003290204370390012001410c4f0d092011200641016a22026b2001470d0a20032802002111200e41046a220320064102746a2802002112200741046a20032002410274221b6a200141027410848e8080001a200741306a201a200241346c6a200141346c10848e8080001a200e20063b01ee04200541e0006a41086a22022008290300370300200541e0006a41106a221a2010290300370300200541e0006a41186a221c200d290300370300200541e0006a41206a221d200f290300370300200541e0006a41286a221e2015290300370300200520052903900137036020072f01ee04220341016a21012003410c4f0d0b201420066b22062001470d0c200b41016a2114200741f0046a200e201b6a41f0046a200641027410848e808000210b4100210602400340200b20064102746a280200220120063b01ec0420012007360200200620034f0d01200620062003496a220620034d0d000b0b2015201e290300370300200f201d290300370300200d201c2903003703002010201a290300370300200820022903003703002005200529036037039001200e200720191b220141046a22022009410274221e6a210302400240200941016a220620012f01ee04220b4d0d00200320173602000c010b200220064102746a2003200b20096b220241027410fe8d8080001a20032017360200200141306a2203200641346c6a2003200941346c6a200241346c10fe8d8080001a0b200b41016a21192001200941346c6a220341306a2018360200200341346a20052903303702002003413c6a200541306a41086a2218290300370200200341c4006a200541306a41106a2217290300370200200341cc006a200541306a41186a221a290300370200200341d4006a200541306a41206a221b290300370200200341dc006a200541306a41286a221c290300370200200141f0046a21030240200941026a221d200b41026a22024f0d002003201d4102746a200320064102746a200b20096b41027410fe8d8080001a0b200320064102746a2016360200200120193b01ee040240200620024f0d000240200b20096b221941016a410371220b450d002001201e6a41f4046a210303402003280200220920063b01ec0420092001360200200341046a2103200641016a2106200b417f6a220b0d000b0b20194103490d00200120064102746a41fc046a21030340200341746a280200220b20063b01ec04200b2001360200200341786a280200220b200641016a3b01ec04200b20013602002003417c6a280200220b200641026a3b01ec04200b20013602002003280200220b200641036a3b01ec04200b2001360200200341106a21032002200641046a2206470d000b0b200541286a22062015290300370300200541206a2203200f290300370300200541186a2201200d290300370300200541106a220b2010290300370300200541086a2209200829030037030020052005290390013703002011418080808078460d02201c2006290300370300201b2003290300370300201a20012903003703002017200b290300370300201820092903003703002005200529030037033020072116201221172014210b200e210620112118200e28020022030d000b0b200428020022032802002201450d0b2003280204210b41002d00fca3c680001a41a00541002802c8a3c68000118180808000002206450d0c200620013602f004200641003b01ee042006410036020020032006360200200141003b01ec04200120063602002003200b41016a360204200b2014470d0d20062f01ee042201410b4f0d0e2006200141016a220b3b01ee042006200141346c6a220341346a20052903303702002003413c6a200541386a290300370200200341c4006a200541c0006a290300370200200341cc006a200541c8006a290300370200200341d4006a200541d0006a290300370200200341dc006a200541d8006a290300370200200341306a2011360200200620014102746a41046a2012360200200641f0046a200b4102746a20073602002007200b3b01ec04200720063602000b2000200a3602082000200c360204200020133602000b200541c0016a2480808080000f0b410441f00410b280808000000b200e410b4190d5c18000109581808000000b41d8d4c1800041284180d5c1800010f880808000000b41b0d5c18000413541e8d5c1800010f880808000000b410441a00510b280808000000b2001410b4190d5c18000109581808000000b41d8d4c1800041284180d5c1800010f880808000000b2001410c41a0d5c18000109581808000000b41d8d4c1800041284180d5c1800010f880808000000b41d8d2c1800010a081808000000b410441a00510b280808000000b4188d4c18000413041b8d4c1800010f880808000000b41e8d2c18000412041c8d4c1800010f880808000000bc909030f7f017e057f4100210202400240024002400240024002402001280200220341024622040d00024020012d00490d004100200120041b210520012802302106024002400240024020030d002001410e6a2d00000d032001410c6a2d00002107200141346a2802002204210802400240024020012802042203450d0002400240200420034b0d0020042003460d010c030b200620036a2c00004140480d020b200420036b21080b2008450d0302400240200620036a22092c00002208417f4a0d0020092d0001413f71210a2008411f71210b0240200841604f0d00200b410674200a7221080c020b200a41067420092d0002413f7172210a0240200841704f0d00200a200b410c747221080c020b200a41067420092d0003413f7172200b411274418080f000717221080c010b200841ff017121080b200741ff01710d0a2008418080c400460d014101210702402008418001490d00410221072008418010490d0041034104200841808004491b21070b2001200720036a22033602042003450d0902400240200420034b0d0020042003470d010c0a0b200620036a2c000041bf7f4a0d090b410121070b200120074101733a000c200620042003200441b0d8c18000109781808000000b200141013a000c0c020b02402001411c6a28020022082001413c6a280200220c417f6a220d6a2203200141346a28020022094f0d002001280238210a200c200141186a280200220e6b210f200141106a280200211020012903082111200141246a2802002212417f46211320122114034002400240024002402011200620036a31000088a74101710d0020012008200c6a220836021c0c010b201020102014201020144b1b20131b2215200c2015200c4b1b210b200620086a21162015210302400240024003400240200b2003470d004100201420131b2107201021030340024020072003490d0020012008200c6a220336021c2012417f460d15200141003602240c150b2003417f6a2203200c4f0d05200320086a220420094f0d03200a20036a2d0000200620046a2d0000460d000b20012008200e6a220836021c200f21032013450d060c070b200820036a20094f0d02201620036a2104200a20036a2107200341016a210320072d000020042d0000460d000b200820106b20036a21080c030b200420094190d8c1800010f980808000000b2009201520086a2203200920034b1b200941a0d8c1800010f980808000000b2003200c4180d8c1800010f980808000000b4100210320130d010b20012003360224200321140b2008200d6a22032009490d000b0b2001200936021c0c020b200120074101733a000c20032108200741ff01710d080b200141013a000e0b200141013a00490240024020052d0048450d0020052802442103200528024021040c010b2005280244220320052802402204460d010b200320046b2103200620046a21020c070b200141023602000b024020012802500d000c060b200141d4006a2203280200210220034100360200200141d8006a28020021030c050b200420036b21040b024020040d00410021040c020b41012107200620036a2c00002204417f4a0d0020044160491a0b200741017321040b200120043a000c200321080b2005280240210120052003360240200820016b2103200620016a21020b20002003360204200020023602000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b22064105762207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710cb8280800020022802082109200228020c21080b200920084105746a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b4105762107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bab0201087f23808080800041306b2202248080808000200128020c2203200128020422046b220541386e2106200128021021072001280208210820012802002109024002400240024020032004470d00410421010c010b200541c8ffffff7d4b0d0120064105742205417f4c0d0141002d00fca3c680001a200541002802c8a3c68000118180808000002201450d020b200241046a41086a220541003602002002200136020820022006360204200220073602202002200336021c2002200836021820022004360214200220093602102002200136022c2002410036022820022005360224200241106a200241246a10ce82808000200041086a200528020036020020002002290204370200200241306a2480808080000f0b10ae80808000000b4104200510b280808000000bbd05030a7f027e027f23808080800041c0006b220224808080800020012802082103200128020c220421052001280200220621070240200128020422082004460d0020012802102105200621070240034020082209280200220a418080808078460d01200928020c210b2009290218210c2009290210210d20092d0020210e200928020421082009280208210f2002200536023c20022008200f41386c6a3602382002200a360234200220083602302002200836022c200241086a2002412c6a10c282808000200241086a41206a2208200e3a000020072002290308370200200741106a200d370200200741186a200c3702002002200b41ffffffff0171360214200741086a200241086a41086a290300370200200741206a2008280200360200200741246a2107200941246a22082004470d000b0b200941246a21050b20014284808080c00037020020014280808080c000370208200420056b41246e2101024020042005460d004100210e034002402005200e41246c6a220b280208220a450d00200b2802042104200a410171210f410021080240200a4101460d00200441e4006a2109200a417e71210a4100210803400240200941446a280200450d00200941486a28020041002802c0a3c68000118080808000000b02402009417c6a280200450d00200928020041002802c0a3c68000118080808000000b200941f0006a2109200a200841026a2208470d000b0b200f450d002004200841386c6a2209280228450d00200941286a28020441002802c0a3c68000118080808000000b0240200b280200450d00200b28020441002802c0a3c68000118080808000000b0240200b28020c450d00200b410c6a28020441002802c0a3c68000118080808000000b200e41016a220e2001470d000b0b200020063602042000200720066b41246e3602082000200341246c41246e360200200241c0006a2480808080000b9d03010e7f02400240024002400240200128020822020d00410421030c010b200241ffffff1f4b0d0220024105742204417f4c0d022001280204210141002d00fca3c680001a200441002802c8a3c68000118180808000002203450d014100210520022106034020042005460d012001411c6a2802002107200141106a2802002108200128020421092001280218210a2001280214210b200128020c210c024002402001280208220d0d004104210e4100210f0c010b200d41ffffffff004b0d04200d410374220f417f4c0d0441002d00fca3c680001a200f41002802c8a3c6800011818080800000220e450d050b200141206a2101200e2009200f10848e8080002109200320056a220f200d360200200f411c6a2007360200200f41186a200a360200200f41146a200b360200200f41106a2008360200200f410c6a200c360200200f41086a200d360200200f41046a2009360200200541206a21052006417f6a22060d000b0b2000200236020820002003360204200020023602000f0b4104200410b280808000000b10ae80808000000b4104200f10b280808000000b860601177f0240024002400240024002400240200128020822020d00410421030c010b200241e3f1b81c4b0d04200241246c2204417f4c0d042001280204210541002d00fca3c680001a200441002802c8a3c68000118180808000002203450d012005200241246c6a21062002210741002108034020052006460d012005411c6a28020021092005280218210a4104210b4104210c02402005280208220d450d00200d41ffffff1f4b0d06200d410574220e417f4c0d062005280204210141002d00fca3c680001a200e41002802c8a3c6800011818080800000220c450d044100210f200d21100340200e200f460d012001411c6a2802002111200141106a2802002112200128020421132001280218211420012802142115200128020c211602400240200128020822170d0041042118410021040c010b201741ffffffff004b0d0820174103742204417f4c0d0841002d00fca3c680001a200441002802c8a3c68000118180808000002218450d070b200141206a210120182013200410848e8080002113200c200f6a220420173602002004411c6a2011360200200441186a2014360200200441146a2015360200200441106a20123602002004410c6a2016360200200441086a2017360200200441046a2013360200200f41206a210f2010417f6a22100d000b0b200541106a280200211720052d0020210f02400240200541146a28020022040d00410021010c010b200441ffffffff004b0d0620044103742201417f4c0d0641002d00fca3c680001a200141002802c8a3c6800011818080800000220b450d070b200541246a2105200b2017200110848e80800021172003200841246c6a2201200f3a00202001200936021c2001200a36021820012004360214200120173602102001200436020c2001200d3602082001200c3602042001200d360200200841016a21082007417f6a22070d000b0b2000200236020820002003360204200020023602000f0b4104200410b280808000000b4104200e10b280808000000b4104200410b280808000000b10ae80808000000b4104200110b280808000000b880301067f2380808080004190016b2202248080808000200241186a200110c082808000024002400240200228021822030d002000410036020820004280808080c0003702000c010b200228021c210441002d00fca3c680001a412041002802c8a3c68000118180808000002205450d0120052003360200200520043602042002410136022c2002200536022820024104360224200241306a200141e00010848e8080001a200241106a200241306a10c082808000024020022802102204450d0020022802142106410c2103410121010340024020012002280224470d00200241246a2001410241012002280284011b41012002280280011b10cd82808000200228022821050b200520036a220720063602002007417c6a20043602002002200141016a220136022c200341086a2103200241086a200241306a10c082808000200228020c2106200228020822040d000b0b20002002290224370200200041086a200241246a41086a2802003602000b20024190016a2480808080000f0b4104412010b280808000000bcc0401077f2380808080004190016b2202248080808000200241106a200141086a10c0828080000240024002400240024020022802102203450d002002280214210420012802042205450d0220012802002106200541047421050340024020062802042004470d0020032006280200200410888e808000450d030b200641106a2106200541706a22050d000c030b0b2000410036020820004280808080c0003702000c020b2006410c6a2802002104200641086a28020021030b41002d00fca3c680001a412041002802c8a3c68000118180808000002207450d01200720043602042007200336020020024101360224200220073602202002410436021c200241286a200141e80010848e8080001a200241086a200241286a41086a220810c082808000024020022802082203450d00200228020c21044101210103400240200228022c2205450d00200228022821062005410474210502400340024020062802042004470d0020032006280200200410888e808000450d020b200641106a2106200541706a22050d000c020b0b2006410c6a2802002104200641086a28020021030b02402001200228021c470d002002411c6a2001410241012002280284011b41012002280280011b10cd82808000200228022021070b200720014103746a22062004360204200620033602002002200141016a22013602242002200810c08280800020022802042104200228020022030d000b0b2000200229021c370200200041086a2002411c6a41086a2802003602000b20024190016a2480808080000f0b4104412010b280808000000bbf0801117f23808080800041d0006b22022480808080002002200110d08280800002400240024002400240024020022802002203450d0020032802002103200241186a200228020410cf828080002002200336024c2002280218418080808078470d010b2000410036020820004280808080c0003702000c010b2001280220220441016a2203417f20031b22034104200341044b1b22034192c9a4124b0d03200341386c2205417f4c0d0341002d00fca3c680001a200541002802c8a3c68000118180808000002206450d0220062002290218370200200641306a200241186a41306a2207290200370200200641286a200241186a41286a2208290200370200200641206a200241186a41206a2209290200370200200641186a200241186a41186a220a290200370200200641106a200241186a41106a220b290200370200200641086a200241186a41086a220c29020037020020024101360214200220063602102002200336020c02402004450d00200128020c210d20012802082103200128020421052001280200210e4101210f0340024002400240200e450d002005450d010b200e0d0141f8dac1800010a081808000000b4101210e0240200d450d00200d21050240200d4107712201450d0003402005417f6a210520032802f00421032001417f6a22010d000b0b200d4108490d00034020032802f0042802f0042802f0042802f0042802f0042802f0042802f0042802f0042103200541786a22050d000b0b4100210d20032105410021030b0240200d20052f01ee04490d00034020052802002201450d05200341016a210320052f01ec04210d20012105200d20012f01ee044f0d000b0b200d41016a21100240024020030d00200521010c010b200520104102746a41f0046a2802002101410021102003417f6a2211450d002003417e6a2112024020114107712203450d0003402011417f6a211120012802f00421012003417f6a22030d000b0b20124107490d00034020012802f0042802f0042802f0042802f0042802f0042802f0042802f0042802f0042101201141786a22110d000b0b2005200d4102746a41046a2802002103200241186a2005200d41346c6a41306a10cf828080002002200336024c2002280218418080808078460d012004417f6a21040240200f200228020c470d002002410c6a200f200441016a2203417f20031b10cc82808000200228021021060b2006200f41386c6a22032002290218370200200341306a2007290200370200200341286a2008290200370200200341206a2009290200370200200341186a200a290200370200200341106a200b290200370200200341086a200c2902003702002002200f41016a220f36021441002103200121052010210d20040d000b0b2000200229020c370200200041086a2002410c6a41086a2802003602000b200241d0006a2480808080000f0b41e8dac1800010a081808000000b4104200510b280808000000b10ae80808000000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000bee0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b22014104742104200141808080c0004941037421050240024020030d00200241003602180c010b200241083602182002200341047436021c200220002802043602140b200241086a20052004200241146a10c982808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b22024105742104200241808080204941037421050240024020010d00200341003602180c010b200341083602182003200141057436021c200320002802043602140b200341086a20052004200341146a10c982808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b220241386c210420024193c9a4124941027421050240024020010d00200341003602180c010b200341043602182003200141386c36021c200320002802043602140b200341086a20052004200341146a10c982808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bf00101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b2202410374210420024180808080014941027421050240024020010d00200341003602180c010b200341043602182003200141037436021c200320002802043602140b200341086a20052004200341146a10c982808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000b9505020c7f037e23808080800041c0006b22022480808080002001280204210320012802002104200028020821052000280200210602400240024020002802042207200028020c2208460d00200241086a412c6a21092000280210210a200128020820034105746a21014100210b03402007200b6a220041286a280200220c418080808078460d02200241086a41206a220d200041206a290300370300200241086a41186a200041186a290300220e370300200241086a41106a200041106a290300370300200241086a41086a200041086a2903003703002002200029030037030820092000412c6a290200370200200941086a200041346a2802003602002002200c360230200a200241086a10dd828080002100200d290300210f2002280230210c20022902342110200141146a2000360200200141186a200f3702002001410c6a200e370200200141046a20103702002001200c41ffffffff0171360200200141206a2101200341016a21032007200b41386a220b6a2008470d000b0b200420033602000c010b20042003360200200041386a2008460d00200820076b200b6b220341486a220c41386e4101712109410021010240200341907f6a4138490d002000419c016a2100200c41f0006e41017421034100210103400240200041446a280200450d00200041486a28020041002802c0a3c68000118080808000000b02402000417c6a280200450d00200028020041002802c0a3c68000118080808000000b200041f0006a21002003200141026a2201470d000b0b2009450d002007200141386c6a200b6a220041e0006a280200450d00200041e4006a28020041002802c0a3c68000118080808000000b02402005450d00200641002802c0a3c68000118080808000000b200241c0006a2480808080000ba90703097f017e047f23808080800041106b220224808080800020012802042103410421040240024002400240024002400240200128020822050d0041002106410421070c010b200541ffffffff004b0d0420054103742206417f4c0d0441002d00fca3c680001a200641002802c8a3c68000118180808000002207450d010b20072003200610848e80800021080240200141146a2802002209450d00200941ffffff3f4b0d042009410474220a417f4c0d04200141106a28020021034100210641002d00fca3c680001a200a41002802c8a3c68000118180808000002204450d02200921070340200a2006460d012003290208210b200420066a220c2003290200370200200c41086a200b370200200641106a2106200341106a21032007417f6a22070d000b0b0240024002400240024002400240024002400240024020012d00240e080001020304050607000b2002200141286a10c482808000200228020821072002280204210c2002280200210a4100210d0c080b2002200141286a10c582808000200228020821072002280204210c2002280200210a4101210d0c070b200141286a280200210a4102210d0c060b2001412c6a280200210c200141286a280200210a4103210d0c040b2001412c6a28020021034104210d02400240200141306a28020022070d00410021064104210c0c010b200741ffffffff014b0d0a20074102742206417f4c0d0a41002d00fca3c680001a200641002802c8a3c6800011818080800000220c450d090b200c2003200610848e8080001a2007210a0c040b200141256a2d0000210e4105210d0c040b200141286a280200210a4106210d0c020b2001412c6a280200210c200141286a280200210a4107210d0b0b0b2001411c6a280200210f02400240200141206a28020022060d0041042101410021030c010b200641ffffffff004b0d0420064103742203417f4c0d0441002d00fca3c680001a200341002802c8a3c68000118180808000002201450d050b2001200f200310848e8080002103200041206a20063602002000411c6a200336020020002006360218200041306a20073602002000412c6a200c360200200041286a200a360200200041256a200e3a00002000200d3a0024200041146a2009360200200041106a20043602002000200936020c200020053602082000200836020420002005360200200241106a2480808080000f0b4104200610b280808000000b4104200a10b280808000000b4104200610b280808000000b10ae80808000000b4104200310b280808000000bbb0401077f0240024002400240200128022022020d00410021020c010b20012002417f6a3602202001280204210202400240024020012802002203450d002002450d010b2003450d032001410c6a2802002104200141086a28020021050c010b200141086a280200210202402001410c6a2802002205450d0002400240200541077122040d00200521030c010b2005210303402003417f6a210320022802f00421022004417f6a22040d000b0b20054108490d00034020022802f0042802f0042802f0042802f0042802f0042802f0042802f0042802f0042102200341786a22030d000b0b20014200370208200120023602042001410136020041002104410021050b02400240200420022f01ee044f0d00200221030c010b034020022802002203450d04200541016a210520022f01ec04210420032102200420032f01ee044f0d000b0b200441016a21060240024020050d00200321020c010b200320064102746a41f0046a2802002102410021062005417f6a2207450d002005417e6a2108024020074107712205450d0003402007417f6a210720022802f00421022005417f6a22050d000b0b20084107490d00034020022802f0042802f0042802f0042802f0042802f0042802f0042802f0042802f0042102200741786a22070d000b0b2001200636020c20014100360208200120023602042003200441346c6a41306a2105200320044102746a41046a21020b20002005360204200020023602000f0b41f8dac1800010a081808000000b41e8dac1800010a081808000000bd009030e7f017e087f23808080800041c0006b22052480808080002005200120022003200410f28080800020052802302106200541346a2802002107024002400240024020052802000d00200221032005410e6a2d00000d032006200528020422086a21092005410c6a2d00002104024020080d00024020070d0020022103200441ff0171450d0503402004410173220441ff01710d000b200221030c050b024020092c0000220a4100480d00200441ff0171450d0403402004410173220441ff01710d000c050b0b0240200a4160490d000240200a4170490d0020092d0002413f7141067420092d0001413f71410c74722107200441ff0171450d0403402004410173220441ff01710d000c050b0b200441ff0171450d0403402004410173220441ff01710d000c050b0b200441ff0171450d0303402004410173220441ff01710d000c040b0b02400240200820074f0d0020092c0000220a4140480d01200441017321030240200a4100480d00200441ff0171450d050340200341ff017121042003410173210320040d000c060b0b0240200a4160490d000240200a4170490d0020092d0002413f7141067420092d0001413f71410c74722107200441ff0171450d050340200341ff017121042003410173210320040d000c060b0b200441ff0171450d050340200341ff017121042003410173210320040d000c060b0b200441ff0171450d040340200341ff017121042003410173210320040d000c050b0b20082007470d0020022103200441ff0171450d0403402004410173220441ff01710d000b200221030c040b20062007200820074188dbc18000109781808000000b200221032005411c6a28020022092007460d022005413c6a280200220b200541186a280200220c6b210d200b417f6a210e200541246a280200210f2005280238210a200620096a2110200541106a280200221120096b211220052903082113034002402009200e6a22032007490d00200921030c040b410020126b21142009200b6a21152009200c6a2116200f2117200f2118200921040340024020092004460d00200921030c050b0240024002402013200620036a31000088a74101710d004100210320152104200f417f460d020c010b201120112018201120184b1b200f417f4622191b221a200b201a200b4b1b211b201a210402400240024003400240201b2004470d004100201820191b2108201121040340024020082004490d002017410020191b210f2010200b6a21102012200b6b21122015210920152007470d0a200221030c0d0b2004417f6a2204200b4f0d03200420096a220320074f0d04200a20046a2d0000200620036a2d0000460d000b200d2103201621042019450d050c060b200920046a20074f0d03201020046a2103200a20046a2108200441016a210420082d000020032d0000460d000b201420046a2104410021032019450d030c040b2004200b41b4d9c1800010f980808000000b2003200741c4d9c1800010f980808000000b2007201a20096a2204200720044b1b200741d4d9c1800010f980808000000b20032117200321180b2004200e6a22032007490d000b0b200921030c020b20022103200720092d0003413f7172200a411274418080f0007172418080c400460d010b200821030b2000200220036b3602042000200120036a360200200541c0006a2480808080000bda0501097f23808080800041306b220424808080800002400240024002400240200128020022050d0041002d00fca3c680001a41f00441002802c8a3c680001181808080000022060d01410441f00410b280808000000b2001280204210703402005417c6a210820052f01ee042209410274210a41002106417f210b024003400240200a2006470d002009210b0c020b200520066a210c200641046a2106200b41016a210b200841346a2108417f200c41046a280200220c200247200c20024b1b220c4101460d000b200c41ff0171450d040b02402007450d002007417f6a21072005200b4102746a41f0046a28020021050c010b0b200441003602102004200536020c20042002360208200420013602042004200b360214200441206a200b3602002004200429020c370318200441246a200441186a20022003200441046a10bf8280800020042802042206200628020841016a3602080c010b200641013b01ee04200641003602002006200236020420062003290200370230200641386a200341086a290200370200200641c0006a200341106a290200370200200641c8006a200341186a290200370200200641d0006a200341206a290200370200200641d8006a200341286a290200370200200641e0006a200341306a2802003602002001428080808010370204200120063602000b20004180808080783602000c010b20002008290200370200200041306a200841306a2206280200360200200041286a200841286a220b290200370200200041206a200841206a2202290200370200200041186a200841186a220c290200370200200041106a200841106a2205290200370200200041086a200841086a220a29020037020020082003290200370200200a200341086a2902003702002005200341106a290200370200200c200341186a2902003702002002200341206a290200370200200b200341286a2902003702002006200341306a2802003602000b200441306a2480808080000bff0401057f024020002802002201450d00200028020421020240024020002802082203450d00410021000340024002402000450d002002210420012105200021010c010b4100210402402002450d0020022100024020024107712205450d0003402000417f6a210020012802e80121012005417f6a22050d000b0b20024108490d00034020012802e8012802e8012802e8012802e8012802e8012802e8012802e8012802e8012101200041786a22000d000b0b410021050b024002400240200420012f01e201490d00034020012802b0012200450d0220012f01e0012104200141002802c0a3c6800011808080800000200541016a210520002101200420002f01e2014f0d000b200021010b200441016a2102024020050d00200121000c020b200120024102746a41e8016a2802002100410021022005417f6a2201450d012005417e6a2104024020014107712205450d0003402001417f6a210120002802e80121002005417f6a22050d000b0b20044107490d01034020002802e8012802e8012802e8012802e8012802e8012802e8012802e8012802e8012100200141786a22010d000c020b0b200141002802c0a3c680001180808080000041fcd6c1800010a081808000000b410021012003417f6a22030d000c020b0b024020020d00200121000c010b02400240200241077122050d0020012100200221010c010b200121002002210103402001417f6a210120002802e80121002005417f6a22050d000b0b20024108490d00034020002802e8012802e8012802e8012802e8012802e8012802e8012802e8012802e8012100200141786a22010d000b0b034020002802b0012101200041002802c0a3c68000118080808000002001210020010d000b0b0bc50a010c7f024020002802002201450d00200028020421020240024020002802082203450d00410021040340024002402004450d002002210520012106200421010c010b4100210502402002450d0020022100024020024107712204450d0003402000417f6a210020012802f00421012004417f6a22040d000b0b20024108490d00034020012802f0042802f0042802f0042802f0042802f0042802f0042802f0042802f0042101200041786a22000d000b0b410021060b024002400240200520012f01ee04490d00034020012802002200450d0220012f01ec042105200141002802c0a3c6800011808080800000200641016a210620002101200520002f01ee044f0d000b200021010b200541016a2102024020060d00200121040c020b200120024102746a41f0046a2802002104410021022006417f6a2200450d012006417e6a2107024020004107712206450d0003402000417f6a210020042802f00421042006417f6a22060d000b0b20074107490d01034020042802f0042802f0042802f0042802f0042802f0042802f0042802f0042802f0042104200041786a22000d000c020b0b200141002802c0a3c680001180808080000041fcd6c1800010a081808000000b02402001200541346c6a41306a2208280200450d00200828020441002802c0a3c68000118080808000000b0240200828020c450d00200841106a28020041002802c0a3c68000118080808000000b0240024002400240024020082d00240e050001040402040b2008412c6a28020021090240200841306a2802002201450d002001410171210641002100024020014101460d002001417e7121054100210020092101034002402001280200450d00200141046a28020041002802c0a3c68000118080808000000b0240200141206a280200450d00200141246a28020041002802c0a3c68000118080808000000b200141c0006a21012005200041026a2200470d000b0b2006450d00200920004105746a2201280200450d00200128020441002802c0a3c68000118080808000000b20082802280d020c030b2008412c6a28020021090240200841306a280200220a450d0041002107034002402009200741246c6a22062802082201450d002006280204210b2001410171210c41002100024020014101460d002001417e71210541002100200b2101034002402001280200450d00200141046a28020041002802c0a3c68000118080808000000b0240200141206a280200450d00200141246a28020041002802c0a3c68000118080808000000b200141c0006a21012005200041026a2200470d000b0b200c450d00200b20004105746a2201280200450d00200128020441002802c0a3c68000118080808000000b02402006280200450d00200628020441002802c0a3c68000118080808000000b0240200628020c450d002006410c6a28020441002802c0a3c68000118080808000000b200741016a2207200a470d000b0b20082802280d010c020b200841286a280200450d012008412c6a28020021090b200941002802c0a3c68000118080808000000b02402008280218450d002008411c6a28020041002802c0a3c68000118080808000000b410021012003417f6a22030d000c020b0b024020020d00200121040c010b02400240200241077122000d0020012104200221010c010b200121042002210103402001417f6a210120042802f00421042000417f6a22000d000b0b20024108490d00034020042802f0042802f0042802f0042802f0042802f0042802f0042802f0042802f0042104200141786a22010d000b0b034020042802002101200441002802c0a3c68000118080808000002001210420010d000b0b0b02000bd00201027f23808080800041f0006b2205248080808000200541106a200320044198dbc18000410210f280808000200520023602682005200136026420054101360260200541013b0158200520043602544100210120054100360250200541046a200541106a10c682808000024002400240200528020c22060d000c010b2005280208220120064103746a21024100210320012104034002402004280200200441046a28020010d7828080000d00410121010c020b200341016a2103200441086a22042002470d000b024020052802042204418080808078470d00200621030c020b200020063602082000200136020420002004360200200541f0006a2480808080000f0b2005280204450d00200528020841002802c0a3c68000118080808000000b2005200336021420052001360210419adbc180004132200541106a41ccdbc1800041c0dcc18000108981808000000ba90301057f23808080800041106b2202248080808000024002400240024020014104490d00200041036a417c71220320006b220420014d0d010b2000417f6a21042001210303402003450d02200420036a21052003417f6a210320052c0000417f4a0d000b410021050c020b410021052000280000418081828478710d0102404104200420032000461b22032001417c6a22044f0d000340200020036a280200418081828478710d03200341046a22032004490d000b0b200020046a280000418081828478710d010b200241086a2000200141a0ddc18000410210d18280800041002105200228020c2204450d0020022802082203450d0041012106024020032d0000220541df00460d00410121062005419f7f6a41ff0171411a490d00200541bf7f6a41ff0171411a4921060b200341016a21032004417f6a21040240034020042200450d012000417f6a210420032d00002105200341016a22012103200541506a41ff0171410a490d0020012103200541ff017141df00460d00200121032005415f7141bf7f6a41ff0171411a490d000b0b20062000457121050b200241106a24808080800020050be10201017f2380808080004180016b2207248080808000200741186a41086a200320044198dbc18000410210f280808000200720023602782007200136027420074101360270200741013b01682007200436026441002101200741003602602007200636021c200720053602182007410c6a200741186a10c782808000024002400240200728021422060d000c010b2007280210220120064103746a21024100210320012104034002402004280200200441046a28020010d7828080000d00410121010c020b200341016a2103200441086a22042002470d000b0240200728020c2204418080808078470d00200621030c020b20002006360208200020013602042000200436020020074180016a2480808080000f0b200728020c450d00200728021041002802c0a3c68000118080808000000b2007200336021c20072001360218419adbc180004132200741186a41ccdbc1800041d0dcc18000108981808000000bac0201027f23808080800041106b22022480808080000240024020002802000d00200128021441a2ddc18000410f200141186a28020028020c1182808080000021010c010b2002200041046a360204200128021441b1ddc180004111200141186a28020028020c118280808000002100200241003a000d200220003a000c20022001360208200241086a41c2ddc180004107200241046a41ccddc18000108c81808000210320022d000c2100024020022d000d0d00200041ff017141004721010c010b41012101200041ff01710d000240200328020022012d001c4104710d0020012802144187a5c080004102200128021828020c1182808080000021010c010b20012802144186a5c080004101200128021828020c1182808080000021010b200241106a24808080800020010b140020002802002000280204200110e2808080000bf40201037f2380808080004180016b22022480808080002000280200210002400240024002400240200128021c22034110710d0020034120710d0120003502004101200110fe8080800021000c020b20002802002100410021030340200220036a41ff006a413041d7002000410f712204410a491b20046a3a00002003417f6a210320004110492104200041047621002004450d000b20034180016a22004180014b0d022001410141c48dc080004102200220036a4180016a410020036b10db8080800021000c010b20002802002100410021030340200220036a41ff006a413041372000410f712204410a491b20046a3a00002003417f6a210320004110492104200041047621002004450d000b20034180016a22004180014b0d022001410141c48dc080004102200220036a4180016a410020036b10db8080800021000b20024180016a24808080800020000f0b200041800141c88dc08000109481808000000b200041800141c88dc08000109481808000000b8505020a7f027e23808080800041c0006b2204248080808000200128020821050240024002400240200128020c22060d00410021060c010b200141106a28020021070340200641b0016a210820062f01e2012209410474210a4100210b417f210c0240024003400240200a200b470d002009210c0c020b2006200b6a210d200b41106a210b200c41016a210c200841046a2108417f200d290300220e200285200d41086a290300220f20038584420052200e200256200f200356200f2003511b1b220d4101460d000b200d41ff0171450d010b2007450d022007417f6a21072006200c4102746a41e8016a28020021060c010b0b200828020021054100210b0c010b20042001410c6a3602242004200c3602202004410036021c20042006360218200420023e0208200420024220883e020c200420033e0210200420034220883e02140240024020060d0041002d00fca3c680001a41e80141002802c8a3c6800011818080800000220b450d03200b41013b01e201200b41003602b001200b20053602b401200b2004290308370300200b200441106a290300370308200141106a4280808080103702002001200b36020c0c010b200441286a41086a200441186a220b41086a2802003602002004200b290200370328200441346a200441286a2004290308200441086a41086a2903002005200441246a10be828080002004280224220b200b28020841016a3602080b02402001280208220b2001280200470d002001200b10ca828080002001280208210b0b2001280204200b4104746a220b2003370308200b20023703004101210b2001200128020841016a3602080b200020053602042000200b3a0000200441c0006a2480808080000f0b410841e80110b280808000000bf409030c7f017e017f23808080800041c0016b2202248080808000200241086a20002001290300200141086a29030010dc82808000200228020c21030240024020022d0008450d00200241c8006a200128021011808080800000200220024184016a290200370218200220022802800141ffffffff017136021420024190016a2802002104200228028c0121050240024020024194016a28020022060d0041002107410421080c010b4100210741002d00fca3c680001a2006410474220141002802c8a3c68000118180808000002208450d02200420064105746a21092008210a2004210103402001280200220b450d012001280204210c024002402001280218220d0d004100210d0c010b2001290208210e2002200141106a2902003703b0012002200e3703a8012002200d3602b8012000200241a8016a10dd82808000210f4101210d0b200a200d360200200a410c6a200c360200200a41086a200b360200200a41046a200f360200200a41106a210a200741016a2107200141206a22012009470d000b0b02402005450d00200441002802c0a3c68000118080808000000b200241286a2007360200200241246a200836020020022006360220200241386a200241c8006a200010de82808000200241306a2002419c016a290200370200200220022802980141ffffffff017136022c200241c8006a200041186a2003200241146a10d28280800020022802482201418080808078460d0002402001450d00200228024c41002802c0a3c68000118080808000000b02402002280254450d00200241d8006a28020041002802c0a3c68000118080808000000b0240024002400240024020022d006c0e050001040402040b200241f4006a280200210d0240200241f8006a2802002201450d002001410171210b4100210a024020014101460d002001417e712107200d21014100210a034002402001280200450d00200141046a28020041002802c0a3c68000118080808000000b0240200141206a280200450d00200141246a28020041002802c0a3c68000118080808000000b200141c0006a21012007200a41026a220a470d000b0b200b450d00200d200a4105746a2201280200450d00200128020441002802c0a3c68000118080808000000b20022802700d020c030b200241f4006a280200210d0240200241f8006a2802002209450d004100210c03400240200d200c41246c6a220b2802082201450d00200b280204210f200141017121004100210a024020014101460d002001417e7121074100210a200f2101034002402001280200450d00200141046a28020041002802c0a3c68000118080808000000b0240200141206a280200450d00200141246a28020041002802c0a3c68000118080808000000b200141c0006a21012007200a41026a220a470d000b0b2000450d00200f200a4105746a2201280200450d00200128020441002802c0a3c68000118080808000000b0240200b280200450d00200b28020441002802c0a3c68000118080808000000b0240200b28020c450d00200b410c6a28020441002802c0a3c68000118080808000000b200c41016a220c2009470d000b0b20022802700d010c020b200241f0006a280200450d01200241f4006a280200210d0b200d41002802c0a3c68000118080808000000b2002280260450d00200241e4006a28020041002802c0a3c68000118080808000000b200241c0016a24808080800020030f0b4104200110b280808000000bab0603027f017e077f23808080800041d0006b2203248080808000024002400240024002400240024002400240024020012d00000e080001020304050607000b200041046a2002200141046a10df82808000410021010c070b20032002360248200320012802043602402003200141086a280200220436023c20032004360238200320042001410c6a28020041246c6a360244200041046a200341386a10c382808000410121010c060b200141186a2802002104200129030821052003200141106a290300370340200320053703382003200436024820002002200341386a10dd82808000360204410221010c050b200141206a2802002104200041086a2002200141086a10dd8280800036020020002004360204410321010c040b200141086a280200210620012802042107024002402001410c6a28020022080d00410021094104210a0c010b41002d00fca3c680001a2008410274220141002802c8a3c6800011818080800000220a450d052006200841186c6a210b200841037441786a41037641016a2109200a21042006210103402001280210210c200129030021052003200141086a290300370340200320053703382003200c36024820042002200341386a10dd82808000360200200441046a2104200141186a2201200b470d000b0b02402007450d00200641002802c0a3c68000118080808000000b200020083602042000410c6a2009360200200041086a200a360200410421010c030b200020012d00013a0001410521010c020b200141186a2802002104200129030821052003200141106a290300370340200320053703382003200436024820002002200341386a10dd82808000360204410621010c010b200341086a41286a200141306a290300370300200341086a41206a200141286a290300370300200341086a41186a2204200141206a290300370300200341086a41106a200141186a290300370300200341086a41086a200141106a290300370300200320012903083703082002200141086a10dd828080002101200041086a2002200410dd8280800036020020002001360204410721010b200020013a0000200341d0006a2480808080000f0b4104200110b280808000000b950201057f23808080800041306b220324808080800020022802042104200228020021050240024002400240200228020822020d00410421060c010b200241ffffff1f4b0d0120024105742207417f4c0d0141002d00fca3c680001a200741002802c8a3c68000118180808000002206450d020b200341046a41086a2207410036020020032006360208200320023602042003200136022020032004200241386c6a36021c2003200536021820032004360214200320043602102003200636022c2003410036022820032007360224200341106a200341246a10ce82808000200041086a200728020036020020002003290204370200200341306a2480808080000f0b10ae80808000000b4104200710b280808000000b420020004280808080c00037033820004280808080c000370350200041053b0100200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b430020004280808080c00037033820004280808080c00037035020004185063b0100200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b430020004280808080c00037033820004280808080c00037035020004185083b0100200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b430020004280808080c00037033820004280808080c000370350200041850a3b0100200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b430020004280808080c00037033820004280808080c000370350200041850c3b0100200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b430020004280808080c00037033820004280808080c000370350200041850e3b0100200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b550020004280808080c00037033820004280808080c0003703502000410036020c200042808080808001370204200041043a0000200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000bf60201037f2380808080004180016b22022480808080002000280200210002400240024002400240200128021c22034110710d0020034120710d0120003100004101200110fe8080800021000c020b20002d00002103410021000340200220006a41ff006a413041d7002003410f712204410a491b20046a3a00002000417f6a2100200341ff017122044104762103200441104f0d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000c010b20002d00002103410021000340200220006a41ff006a413041372003410f712204410a491b20046a3a00002000417f6a2100200341ff017122044104762103200441104f0d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000b20024180016a24808080800020000f0b200341800141c88dc08000109481808000000b200341800141c88dc08000109481808000000b02000b4601017f23808080800041106b22052480808080002005200236020c200520013602082000200541086a41dcddc180002005410c6a41dcddc180002003200410fb80808000000bd90201047f23808080800041c0006b220224808080800020012c001f417f4a10ad8d8080002103200241186a200141186a290000370300200241106a200141106a290000370300200241086a200141086a29000037030020022001290000370300200241206a200210ab8180800041002104410121050340200220046a2d0000200241206a20046a2d00004610ad8d8080002005712105200441016a22044120470d000b4100210402400240200510ad8d80800020037110ad8d8080002205417f7341017110ad8d80800041ff01710d00200220053a0000200541ff01714101470d0120002001290000370001200041196a200141186a290000370000200041116a200141106a290000370000200041096a200141086a290000370000410121040b200020043a0000200241c0006a2480808080000f0b200241003602204100200241ecddc18000200241206a41c8dec1800010e982808000000b140020002802002000280204200110e2808080000b1900200120002802002200280200200028020410dd808080000b140020012000280200200028020410dd808080000b1200200041d8dec18000200110d9808080000b02000b800902017f017c23808080800041306b2202248080808000024002400240024002400240024002400240024002400240024002400240024002400240024020002d00000e12000102030405060708090a0b0c0d0e0f1011000b200220002d00013a00082002411c6a42013702002002410236021420024190dfc18000360210200241ce8080800036022c200141186a28020021002002200241286a3602182002200241086a36022820012802142000200241106a10d98080800021010c110b200220002903083703082002411c6a420137020020024102360214200241acdfc18000360210200241cf8080800036022c200141186a28020021002002200241286a3602182002200241086a36022820012802142000200241106a10d98080800021010c100b200220002903083703082002411c6a420137020020024102360214200241acdfc18000360210200241d08080800036022c200141186a28020021002002200241286a3602182002200241086a36022820012802142000200241106a10d98080800021010c0f0b20002b030821032002411c6a420137020020024102360214200241ccdfc18000360210200241d18080800036020c20022003390328200141186a28020021002002200241086a3602182002200241286a36020820012802142000200241106a10d98080800021010c0e0b200220002802043602082002411c6a420137020020024102360214200241e8dfc18000360210200241d28080800036022c200141186a28020021002002200241286a3602182002200241086a36022820012802142000200241106a10d98080800021010c0d0b200220002902043702082002411c6a42013702002002410136021420024180e0c18000360210200241d38080800036022c200141186a28020021002002200241286a3602182002200241086a36022820012802142000200241106a10d98080800021010c0c0b200128021441fcdec18000410a200141186a28020028020c1182808080000021010c0b0b20012802144188e0c18000410a200141186a28020028020c1182808080000021010c0a0b20012802144192e0c18000410c200141186a28020028020c1182808080000021010c090b2001280214419ee0c18000410e200141186a28020028020c1182808080000021010c080b200128021441ace0c180004108200141186a28020028020c1182808080000021010c070b200128021441b4e0c180004103200141186a28020028020c1182808080000021010c060b200128021441b7e0c180004104200141186a28020028020c1182808080000021010c050b200128021441bbe0c18000410c200141186a28020028020c1182808080000021010c040b200128021441c7e0c18000410f200141186a28020028020c1182808080000021010c030b200128021441d6e0c18000410d200141186a28020028020c1182808080000021010c020b200128021441e3e0c18000410e200141186a28020028020c1182808080000021010c010b20012802142000280204200041086a280200200141186a28020028020c1182808080000021010b200241306a24808080800020010baf0201027f23808080800041306b220224808080800002400240200029030042ffffffffffffffffff0083bf44000000000000f07f630d002002411c6a420137020020024101360214200241a8e2c18000360210200241d48080800036022c20022000360228200141186a28020021002002200241286a36021820012802142000200241106a10d98080800021030c010b200241003a000c200220013602082002411c6a42013702004101210320024101360214200241a8e2c18000360210200241d48080800036022c200220003602282002200241286a360218200241086a41d8dec18000200241106a10d9808080000d00024020022d000c0d00200128021441b0e2c180004102200141186a28020028020c118280808000000d010b410021030b200241306a24808080800020030b2300200128021420002802002000280204200141186a28020028020c118280808000000bbc0401067f23808080800041306b220224808080800020002802002103024002400240024002400240200028020422040e03030201000b4101210020012802142205419ce2c180004107200141186a280200220628020c2207118280808000000d0420022003360214200241246a42013702002002410236021c200241ece1c18000360218200241d5808080003602082002200241046a3602202002200241146a36020420052006200241186a10d9808080000d03200341086a2101200441037441786a2103034020022001360214200541a3e2c1800041022007118280808000000d042002410236021c200241ece1c1800036021820024201370224200241d5808080003602082002200241046a3602202002200241146a36020420052006200241186a10d9808080000d04200141086a210141002100200341786a22030d000c050b0b200241046a410c6a41d680808000360200200241186a410c6a42023702002002410336021c20024184e2c18000360218200241d680808000360208200220033602042002200341086a36020c200141186a28020021002002200241046a36022020012802142000200241186a10d98080800021000c030b200241246a42013702002002410236021c200241ece1c18000360218200241d68080800036020820022003360204200141186a28020021002002200241046a36022020012802142000200241186a10d98080800021000c020b41f1e0c18000410e41dce1c1800010f880808000000b410121000b200241306a24808080800020000bc90301047f0240024002400240024020024108490d00200141036a417c7122032001460d01200320016b2204450d01200120036b21054101210620012103034020032d0000412e460d05200341016a2103200541016a22050d000b2004200241786a22064b0d030c020b024020020d00410021060c040b20012d0000412e4622060d0320024101460d0320012d0001412e4622060d0320024102460d0320012d0002412e4622060d0320024103460d0320012d0003412e4622060d0320024104460d0320012d0004412e4622060d0320024105460d0320012d0005412e4622060d0320024106460d0320012d0006412e4621060c030b200241786a2106410021040b0340200120046a220341046a280200220541aedcb8f1027341fffdfb776a2005417f73712003280200220341aedcb8f1027341fffdfb776a2003417f737172418081828478710d01200441086a220420064d0d000b0b4100210620042002460d00200120046a21032004417f7320026a210503402005210420032d0000412e4622060d01200341016a21032004417f6a210520040d000b0b2000200620002d0004410047723a00042000280200220328021420012002200341186a28020028020c118280808000000b330020002001412e4620002d0004410047723a0004200028020022002802142001200041186a280200280210118380808000000bfa0103017f017c017e23808080800041106b22032480808080000240024002400240024020002802000e0400010203000b20002b03082104200341033a00002003200439030820032001200210838380800021020c030b20002903082105200341013a00002003200537030820032001200210838380800021020c020b20002903082105200341023a00002003200537030820032001200210838380800021020c010b200341086a4106360200200341b5e2c18000360204200341113a000020032001200210838380800021022000280204450d00200041086a28020041002802c0a3c68000118080808000000b200341106a24808080800020020b02000b220002402000280200450d00200028020441002802c0a3c68000118080808000000b0b2100200128021441fcf8c180004105200141186a28020028020c118280808000000b140020002802042000280208200110e2808080000bf20201027f23808080800041106b220224808080800002400240024002402001418001490d002002410036020c2001418010490d0102402001418080044f0d0020022001413f71418001723a000e20022001410c7641e001723a000c20022001410676413f71418001723a000d410321010c030b20022001413f71418001723a000f20022001410676413f71418001723a000e20022001410c76413f71418001723a000d2002200141127641077141f001723a000c410421010c020b0240200028020822032000280200470d0020002003109083808000200028020821030b200028020420036a20013a00002000200028020841016a3602080c020b20022001413f71418001723a000d2002200141067641c001723a000c410221010b02402000280200200028020822036b20014f0d00200020032001109183808000200028020821030b200028020420036a2002410c6a200110848e8080001a2000200320016a3602080b200241106a24808080800041000b4b01017f02402000280200200028020822036b20024f0d00200020032002109183808000200028020821030b200028020420036a2001200210848e8080001a2000200320026a36020841000b4201017f41002d00fca3c680001a0240411441002802c8a3c680001181808080000022000d004104411410b280808000000b2000420037020c2000410136020020000b810700024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024020002802000e19000102030405060708090a0b0c0d0e0f101112131415161718000b20012802142000280204200041086a280200200141186a28020028020c118280808000000f0b200041046a20011098838080001a000b200128021441d4f9c180004118200141186a28020028020c118280808000000f0b200128021441ecf9c18000411b200141186a28020028020c118280808000000f0b20012802144187fac18000411a200141186a28020028020c118280808000000f0b200128021441a1fac180004119200141186a28020028020c118280808000000f0b200128021441bafac18000410c200141186a28020028020c118280808000000f0b200128021441c6fac180004113200141186a28020028020c118280808000000f0b200128021441d9fac180004113200141186a28020028020c118280808000000f0b200128021441ecfac18000410e200141186a28020028020c118280808000000f0b200128021441fafac18000410e200141186a28020028020c118280808000000f0b20012802144188fbc18000410c200141186a28020028020c118280808000000f0b20012802144194fbc18000410e200141186a28020028020c118280808000000f0b200128021441a2fbc18000410e200141186a28020028020c118280808000000f0b200128021441b0fbc180004113200141186a28020028020c118280808000000f0b200128021441c3fbc18000411a200141186a28020028020c118280808000000f0b200128021441ddfbc18000413e200141186a28020028020c118280808000000f0b2001280214419bfcc180004114200141186a28020028020c118280808000000f0b200128021441affcc180004134200141186a28020028020c118280808000000f0b200128021441e3fcc18000412c200141186a28020028020c118280808000000f0b2001280214418ffdc180004124200141186a28020028020c118280808000000f0b200128021441b3fdc18000410e200141186a28020028020c118280808000000f0b200128021441c1fdc180004113200141186a28020028020c118280808000000f0b200128021441d4fdc18000411c200141186a28020028020c118280808000000f0b200128021441f0fdc180004118200141186a28020028020c118280808000000bc80101017f23808080800041306b2202248080808000024002402000280200220028020c0d002000200110fe8280800021000c010b2002412c6a418580808000360200200241186a410c6a4185808080003602002002410c6a4203370200200241033602042002419cfec1800036020020022000410c6a360220200241db8080800036021c200220003602182002200041106a360228200141186a28020021002002200241186a36020820012802142000200210d98080800021000b200241306a24808080800020000bfb0201017f23808080800041f0006b220224808080800020002802002100200241003602482002428080808010370240200241cc006a41186a41e8f5c18000360200200241033a006c2002412036025c20024100360268200241003602542002410036024c2002200241c0006a36026002402000200241cc006a10fe828080000d00200241306a41086a200241c0006a41086a2802003602002002412c6a418580808000360200200241186a410c6a4185808080003602002002410c6a420337020020022002290240370330200241dc8080800036021c20024104360204200241d0fec180003602002002200041106a36022820022000410c6a360220200141186a28020021002002200241306a3602182002200241186a36020820012802142000200210d980808000210002402002280230450d00200228023441002802c0a3c68000118080808000000b200241f0006a24808080800020000f0b4180f6c180004137200241186a41b8f6c1800041b8f7c18000108981808000000b850201037f23808080800041106b22012480808080002000410c6a28020021020240024002400240024002400240024020002802040e020001020b20020d01410121034100210041c8f7c1800021020c030b2002450d010b200141046a200010b8808080000c020b2000280200220028020021020240200028020422000d0041012103410021000c010b2000417f4c0d0241002d00fca3c680001a200041002802c8a3c68000118180808000002203450d030b20032002200010848e80800021022001200036020c20012002360208200120003602040b200141046a1082838080002100200141106a24808080800020000f0b10ae80808000000b4101200010b280808000000bdd1303157f017e027f23808080800041c0006b2201248080808000200120002802042202200028020822034188fec18000410910f28080800002400240024002400240024020012802000d002001410e6a2d00000d032001410d6a2d00002104200141086a2802002205450d0120012802302106024002402005200141346a2802002207490d0020052007460d010c070b200620056a2c00004140480d060b0240200620056a2208417f6a2d00002209411874411875220a417f4a0d00024002402008417e6a2d00002209411874411875220b41bf7f4c0d002009411f7121090c010b024002402008417d6a2d00002209411874411875220c41bf7f4c0d002009410f7121090c010b2008417c6a2d0000410771410674200c413f717221090b2009410674200b413f717221090b2009410674200a413f717221090b200441ff01710d022009418080c400460d03417f210402402009418001490d00417e21042009418010490d00417d417c200941808004491b21040b0240200420056a22050d00410021050c030b0240024020052007490d0020052007470d070c010b200620056a2c000041bf7f4c0d060b200620056a2204417f6a2c0000417f4a0d022004417e6a2c000041bf7f4a1a0c020b200141206a280200220d2001413c6a280200220e6b2205200141346a280200220a4f0d02200141246a280200210f2001280230210b200141146a2802002210200e2010200e4b1b211120012802382212417f6a2113200141286a2802002114200141186a28020021152001290308211603400240024002402016200b20056a220c31000088a74101710d00200e21042005210d200f417f470d010c020b02400240024002400240024020102010201420102014491b200f417f4622171b2204417f6a2206200e4f0d00201320046a2109410020046b2106200420056a417f6a210403402006450d022004200a4f0d03200641016a2106200b20046a210720092d000021082004417f6a21042009417f6a2109200820072d0000460d000b200d20106b20066b210d200e210420170d070c060b20040d020b200e201420171b22042010200420104b1b210720102104034020072004460d0920112004460d03200520046a200a4f0d04200c20046a2106201220046a2109200441016a210420092d000020062d0000460d000b200d20156b210d201521042017450d040c050b2004200a41ecf8c1800010f980808000000b2006200e41dcf8c1800010f980808000000b2011200e41bcf8c1800010f980808000000b200a200520106a2204200a20044b1b200a41ccf8c1800010f980808000000b200421140b200d200e6b2205200a490d000c030b0b41002105200441ff0171450d010b200220056a210b200541096a220e20036b211241002104417720056b22112109200e21070240024002400240024002400340200520046a210a2003210602402011200446220c0d000240200a41096a2003490d00201220046a0d03200320096a21060c010b200b20046a41096a2c000041bf7f4c0d02200320076b21060b200b20046a2108024002402006450d00200841096a2d000041506a41ff0171410a490d010b200541096a2206200220046a22126a210d200620046a2114200620036b20046a2117200321070240200c0d000240024020142003490d002017450d010c0a0b200d2c000041bf7f4c0d090b200320096a21070b4101210620074108490d05200d29000042a0c6bde3d6ae9bb720520d05200441116a2109200320046b416f6a2111201241116a210641002112410020056b210f416f20056b2115200a20036b41116a2118200a41116a2213210a034020032107024002400240200520096a2210450d00024020102003490d0020052011470d02200f20116a21070c010b200620056a2c000041bf7f4c0d012003200a6b21070b02402007450d00200620056a2d000041506a41ff0171410a490d020b4101210620102003490d08200e20144b0d090240200e450d000240200e2003490d00200e2003460d010c0b0b2002200e6a2c00004140480d0a0b0240200c0d00024020142003490d0020170d0b0c010b200d2c000041bf7f4c0d0a0b2004450d080240024002402002200e6a22072d000041556a0e03010002000b2004210a0c080b20044101460d082004417f6a210a200741016a21070c070b2004210a20044101470d060c070b200220032010200341e880c28000109781808000000b200641016a2106200941016a2109201241016a21122011417f6a2111200a41016a210a0c000b0b2009417f6a2109200441016a2104200741016a21070c000b0b20022003200a41096a200341c880c28000109781808000000b02400240200a4109490d00410021090340200a450d0220072d000041506a220c41094b0d032009ad420a7e2216422088a74100470d03200741016a2107200a417f6a210a2016a7220e200c6a2209200e4f0d000c030b0b41002109034020072d000041506a220c41094b0d02200741016a2107200c2009410a6c6a2109200a417f6a220a0d000b0b0240201320104b0d00024020152004460d00024020132003490d002018450d010c020b200841116a2c00004140480d010b02402010450d0020052011470d010b2012450d02024002400240200841116a22042d000041556a0e03000201020b4101210620124101460d042012417f6a2112200841126a21040c010b4101210620124101460d030b0240024020124109490d004100210803402012450d024101210620042d000041506a220741094b0d052008ad420a7e2216422088a74100470d05200441016a21042012417f6a21122016a7220a20076a2208200a490d050c000b0b4100210841012106034020042d000041506a220741094b0d04200441016a210420072008410a6c6a21082012417f6a22120d000b0b4100210620032005490d06024002402005450d00200320054d0d00200b2c000041bf7f4c0d010b20002005360208200521030c070b4181f9c18000413041b4f9c1800010f880808000000b2002200320132010418881c28000109781808000000b410121060c040b0c030b20022003200e201441f880c28000109781808000000b200220032014200341d880c28000109781808000000b410121060b02400240024002402000280200220420034b0d00200221070c010b0240024020030d00410121070c010b200341002802c8a3c68000118180808000002207450d02200720022004200320042003491b10848e8080001a0b200241002802c0a3c68000118080808000000b41002d00fca3c680001a411441002802c8a3c68000118180808000002204450d0120042003360208200420073602042004410036020020044100200820061b36021020044100200920061b36020c200141c0006a24808080800020040f0b4101200310b280808000000b4104411410b280808000000b200620074100200541c4f9c18000109781808000000bb20101017f23808080800041c0006b22032480808080002003200236020420032001360200200341086a410c6a4202370200200341206a410c6a41dd80808000360200200341306a41086a200041086a2903003703002003410236020c2003418cffc18000360208200341de80808000360224200320002903003703302003200341206a360210200320033602282003200341306a360220200341086a1081838080002100200341c0006a24808080800020000bf70204017f017c017e027f23808080800041c0006b2202248080808000024002400240024020002d0000417d6a0e050100000002000b200241286a41086a200041086a29030037030020022000290300370328200241286a200110f08280800021000c020b0240024020002b03082203bd22044280808080808080f8ff00834280808080808080f8ff00510d00200241286a21002003200241286a10bd8280800021050c010b41a887c2800041ab87c280002004427f5522051b41af87c28000200442ffffffffffffff07835022061b21004103410420051b410320061b21050b2002410c6a42013702002002200536022420022000360220200241df8080800036021c20024102360204200241d0ffc18000360200200141186a28020021002002200241206a3602182002200241186a36020820012802142000200210d98080800021000c010b200128021441e0ffc180004104200141186a28020028020c1182808080000021000b200241c0006a24808080800020000bb20101017f23808080800041c0006b22032480808080002003200236020420032001360200200341086a410c6a4202370200200341206a410c6a41dd80808000360200200341306a41086a200041086a2903003703002003410236020c200341acffc18000360208200341de80808000360224200320002903003703302003200341206a360210200320033602282003200341306a360220200341086a1081838080002100200341c0006a24808080800020000b4201017f41002d00fca3c680001a0240411441002802c8a3c680001181808080000022000d004104411410b280808000000b2000420037020c2000410d36020020000bbd0401057f024002400240024002400240200320024b0d00410121044100210520034101480d04200120036a21060240200341034b0d000340200620014d0d062006417f6a22062d0000410a470d000c050b0b02402006417c6a2800002207417f732007418a94a8d0007341fffdfb776a7141808182847871450d000340200620014d0d062006417f6a22062d0000410a470d000c050b0b200320064103716b210720034109490d010340200722064108480d03200120066a220841786a2802002207417f732007418a94a8d0007341fffdfb776a71418081828478710d03200641786a21072008417c6a2802002208417f732008418a94a8d0007341fffdfb776a7141808182847871450d000c030b0b20032002418884c28000109581808000000b200120076a21060340200620014d0d032006417f6a22062d0000410a470d000c020b0b200120066a21060340200620014d0d022006417f6a22062d0000410a470d000b0b200620016b220641016a2105200620024f0d010b0240200120056a20014d0d0020054103712104024002402005417f6a41034f0d00410021060c010b2005417c712102410021060340200620012d0000410a466a20012d0001410a466a20012d0002410a466a20012d0003410a466a2106200141046a21012002417c6a22020d000b0b02402004450d000340200620012d0000410a466a2106200141016a21012004417f6a22040d000b0b200641016a21040b200020043602002000200320056b3602040f0b20052002419884c28000109581808000000b880501077f02402000280208220220002802042203460d000240024002400240024002400240200220034f0d002000280200220420026a2d000022054122460d07200541dc00460d0702402005411f4b0d0020010d080b2000200241016a2206360208200320066b2107024020010d0020074101480d070240200420036a2208200420066a22056b41034b0d002007210120052102034020022d000022034122460d08200341dc00460d08200241016a21022001417f6a22010d000c090b0b200721032005210220052800002201417f73418081828478712204200141a2c48891027341fffdfb776a71450d030c040b200441016a210541002007417c7122046b210103402001450d02200520026a2103200241046a2102200141046a210120032800002203417f73200341a2c48891027341fffdfb776a200341e0bffffe7d6a72200341dcb8f1e2057341fffdfb776a7271418081828478712203450d000b200020036841037620026a417d6a3602080f0b2002200341a884c2800010f980808000000b2000200420066a36020820001089838080000f0b20072103200521022004200141dcb8f1e2057341fffdfb776a710d002005417c7141046a22022008417c6a22044b0d01034020022802002203417f73418081828478712201200341a2c48891027341fffdfb776a710d022001200341dcb8f1e2057341fffdfb776a710d02200241046a220220044d0d000c020b0b034020022d000022014122460d02200141dc00460d02200241016a21022003417f6a22030d000c030b0b200220084f0d01200820026b2101034020022d000022034122460d01200341dc00460d01200241016a21022001417f6a22010d000c020b0b200220056b21070b2000200720066a3602080b0b5301047f024020002802082201200028020422024f0d00200028020021030340200320016a2d000022044122460d01200441dc00460d0120044120490d012000200141016a220136020820022001470d000b0b0bcc1501087f23808080800041e0006b2203248080808000200128020821042001410110888380800002400240024002402001280208220520012802042206460d000340024020052006490d002005200641b884c2800010f980808000000b02400240024002400240024002400240024002400240024002400240024002402001280200220720056a2d0000220841dc00460d0020084122460d012001200541016a2202360208200341106a20072006200210878380800041002d00fca3c680001a2003280214210120032802102105411441002802c8a3c68000118180808000002202450d032002200536020c2002411036020020002002360204200220013602100c120b024020052004490d00200720046a210902402002280200200228020822086b200520046b22044f0d00200220082004109183808000200228020821080b200228020420086a2009200410848e8080001a2001200541016a22093602082002200820046a220836020802400240024002400240024002400240024002400240200920064f0d002001200541026a2204360208200720096a2d0000415e6a0e5402010101010101010101010101040101010101010101010101010101010101010101010101010101010101010101010101010101010101010101030101010101050101010601010101010101070101010801090a010b200341c0006a20072006200910878380800041002d00fca3c680001a2003280244210120032802402105411441002802c8a3c68000118180808000002202450d0e2002200536020c20024104360200200220013602100c160b200341286a20072006200410878380800041002d00fca3c680001a200328022c210120032802282105411441002802c8a3c68000118180808000002202450d0e2002200536020c2002410c360200200220013602100c150b024020082002280200470d0020022008109083808000200228020821080b200228020420086a41223a00002002200228020841016a3602080c170b024020082002280200470d0020022008109083808000200228020821080b200228020420086a41dc003a00002002200228020841016a3602080c160b024020082002280200470d0020022008109083808000200228020821080b200228020420086a412f3a00002002200228020841016a3602080c150b024020082002280200470d0020022008109083808000200228020821080b200228020420086a41083a00002002200228020841016a3602080c140b024020082002280200470d0020022008109083808000200228020821080b200228020420086a410c3a00002002200228020841016a3602080c130b024020082002280200470d0020022008109083808000200228020821080b200228020420086a410a3a00002002200228020841016a3602080c120b024020082002280200470d0020022008109083808000200228020821080b200228020420086a410d3a00002002200228020841016a3602080c110b024020082002280200470d0020022008109083808000200228020821080b200228020420086a41093a00002002200228020841016a3602080c100b200341cc006a2001108b8380800020032f014c0d020240024002400240024020032f014e22054180f8037122044180b003460d0020044180b803460d0420054180b0bf7f73418090bc7f4f0d01419885c2800010a081808000000b2001280208220420012802042208490d02200341386a20012802002008200410878380800041002d00fca3c680001a200328023c210120032802382105411441002802c8a3c680001181808080000022020d014104411410b280808000000b200341003602542005418001490d09024020054180104f0d0020032005413f71418001723a00552003200541067641c001723a0054410221050c120b20032005413f71418001723a005620032005410c7641e001723a005420032005410676413f71418001723a0055410321050c110b2002200536020c20024104360200200220013602100c0e0b2001200441016a360208200128020020046a2d000041dc00460d0c200341173602542001200341d4006a108c8380800021020c0d0b200341306a20012802002001280204200128020810878380800041002d00fca3c680001a2003280234210120032802302105411441002802c8a3c68000118180808000002202450d072002200536020c20024114360200200220013602100c0c0b2004200541e884c28000109681808000000b20022802082208450d0820052004490d06200720046a210a0240200228020020086b200520046b22094f0d00200220082009109183808000200228020821080b200228020420086a200a200910848e8080001a410121042001200541016a22053602082002200820096a2201360208200341d4006a2002280204200110fc80808000024020032802540d00200020032902583702040c120b200341206a20072006200510878380800041002d00fca3c680001a2003280224210120032802202105411441002802c8a3c68000118180808000002202450d072002200536020c2002410f36020020022001360210200020023602040c100b200328025021020c090b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000b200320053a0054410121050c070b4104411410b280808000000b2004200541d884c28000109681808000000b4104411410b280808000000b0240024020052004490d002001200541016a2202360208200341d4006a200720046a200520046b10fc80808000024020032802540d0020002003290258370204410021040c0b0b200341186a20072006200210878380800041002d00fca3c680001a200328021c210120032802182105411441002802c8a3c68000118180808000002202450d012002200536020c2002410f36020020022001360210200020023602040c090b2004200541c884c28000109681808000000b4104411410b280808000000b200341d4006a2001108d83808000024020032d00540d0020032d005521082001200441026a3602080240200841f500470d00200341d4006a2001108b8380800020032f01540d01024020032f015622044180c0006a41ffff03714180f8034f0d00200341143602542001200341d4006a108c8380800021020c030b024020054180d0006a41ffff0371410a7420044180c8006a41ffff0371722208418080046a2205418080c400460d0020054180b00373418080bc7f6a41ff8fbc7f4b0d040b2003410f3602542001200341d4006a108c8380800021020c020b200341173602542001200341d4006a108c8380800021020c010b200328025821020b200020023602040c050b20032004413f71418001723a005720032008410676413f71418001723a005620032005410c76413f71418001723a00552003200541127641077141f001723a0054410421050b02402002280200200228020822046b20054f0d00200220042005109183808000200228020821040b200228020420046a200341d4006a200510848e8080001a2002200420056a360208200128020821040b200141011088838080002001280208220520012802042206470d000b0b200341086a20012802002005200510878380800041002d00fca3c680001a200328020c210120032802082105411441002802c8a3c68000118180808000002202450d022002200536020c2002410436020020002002360204200220013602100b410221040b20002004360200200341e0006a2480808080000f0b4104411410b280808000000bd00401097f23808080800041106b2202248080808000024002400240024002400240024002402001280208220341046a2204200128020422054b0d00200520034d0d03200128020021062001200341016a2207360208200620036a2d000041a885c280006a2d0000220841ff01470d01200721040c040b20012005360208200220012802002005200510878380800041002d00fca3c680001a2002280204210520022802002103411441002802c8a3c68000118180808000002201450d012001200336020c2001410436020020002001360204200120053602100c040b02404100200520036b2209200920054b1b22094101470d00200721030c020b2001200341026a220a3602080240200620076a2d000041a885c280006a2d0000220741ff01470d00200a21040c030b024020094102470d00200a21030c020b2001200341036a220336020802402006200a6a2d000041a885c280006a2d0000220a41ff01470d00200321040c030b20094103460d0120012004360208200620036a2d000041a885c280006a2d0000220141ff01460d022000200741047420084108746a200a6a41047420016a3b0102410021010c040b4104411410b280808000000b20032005418885c2800010f980808000000b200241086a20062005200410878380800041002d00fca3c680001a200228020c210520022802082103411441002802c8a3c68000118180808000002201450d022001200336020c2001410c36020020002001360204200120053602100b410121010b200020013b0100200241106a2480808080000f0b4104411410b280808000000ba00101037f23808080800041106b2202248080808000200241086a20002802002000280204200028020810878380800041002d00fca3c680001a200228020c2103200228020821040240411441002802c8a3c680001181808080000022000d004104411410b280808000000b2000200436020c2000200129020037020020002003360210200041086a200141086a280200360200200241106a24808080800020000bc60101037f23808080800041106b22022480808080000240024002402001280208220320012802042204490d00200241086a20012802002004200310878380800041002d00fca3c680001a200228020c210320022802082104411441002802c8a3c68000118180808000002201450d022001200436020c200141043602002000200136020420012003360210410121010c010b2000200128020020036a2d00003a0001410021010b200020013a0000200241106a2480808080000f0b4104411410b280808000000bef0501057f23808080800041306b2201248080808000200041011088838080000240024002402000280208220220002802042203460d000340024020022003490d002002200341f884c2800010f980808000000b0240024002400240024002402000280200220420026a2d0000220541dc00460d0020054122460d01200141106a20042003200210878380800041002d00fca3c680001a2001280214210220012802102103411441002802c8a3c68000118180808000002200450d022000200336020c20004110360200200020023602100c080b2000200241016a2205360208024002400240200520034f0d002000200241026a2202360208200420056a2d0000415e6a0e54070101010101010101010101010701010101010101010101010101010101010101010101010101010101010101010101010101010101010101010701010101010701010107010101010101010701010107010702010b200141206a20042003200510878380800041002d00fca3c680001a2001280224210220012802202103411441002802c8a3c68000118180808000002200450d042000200336020c20004104360200200020023602100c090b200141186a20042003200210878380800041002d00fca3c680001a200128021c210220012802182103411441002802c8a3c68000118180808000002200450d042000200336020c2000410c360200200020023602100c080b200141286a2000108b8380800020012f0128450d04200128022c21000c070b2000200241016a360208410021000c060b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000b200041011088838080002000280208220220002802042203470d000b0b200141086a20002802002002200210878380800041002d00fca3c680001a200128020c210220012802082103411441002802c8a3c68000118180808000002200450d012000200336020c20004104360200200020023602100b200141306a24808080800020000f0b4104411410b280808000000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000be00101037f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014108200141084b1b2201417f73411f7621040240024020030d00200241003602180c010b2002200336021c20024101360218200220002802043602140b200241086a20042001200241146a108f83808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000be20101027f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024108200241084b1b2202417f73411f7621040240024020010d00200341003602180c010b2003200136021c20034101360218200320002802043602140b200341086a20042002200341146a108f83808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000b1200200041b487c28000200110d9808080000b220002402000280200450d00200028020441002802c0a3c68000118080808000000b0bf20201027f23808080800041106b220224808080800002400240024002402001418001490d002002410036020c2001418010490d0102402001418080044f0d0020022001413f71418001723a000e20022001410c7641e001723a000c20022001410676413f71418001723a000d410321010c030b20022001413f71418001723a000f20022001410676413f71418001723a000e20022001410c76413f71418001723a000d2002200141127641077141f001723a000c410421010c020b0240200028020822032000280200470d0020002003109083808000200028020821030b200028020420036a20013a00002000200028020841016a3602080c020b20022001413f71418001723a000d2002200141067641c001723a000c410221010b02402000280200200028020822036b20014f0d00200020032001109183808000200028020821030b200028020420036a2002410c6a200110848e8080001a2000200320016a3602080b200241106a24808080800041000b4b01017f02402000280200200028020822036b20024f0d00200020032002109183808000200028020821030b200028020420036a2001200210848e8080001a2000200320026a36020841000b140020012000280200200028020410dd808080000b180020002802002001200028020428020c118380808000000b170041cc87c28000412841d888c2800010f880808000000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b22064105762207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a41002007109e8380800020022802082109200228020c21080b200920084105746a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b4105762107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bfc0203027f017e047f23808080800041306b2201248080808000200141246a41e888c28000410641ee88c28000412341e888c28000410010d882808000200141086a2202410036020020014280808080c00037030020012902282103200128022421042001410036021420014280808080800137020c2001410c6a4100109d838080002001280210200128021441386c6a2205420437022c2005420d370224200541c38ac2800036022020054100360218200541e980808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db0037030002402004418080808078470d00419a89c280004111418c8ac2800010a181808000000b20012802142105200128020c210620012802102107200042808080808001370244200020043602382000200736020820002006360204200041003a000020002001290300370350200041cc006a41003602002000413c6a20033702002000200541016a36020c200041d8006a2002280200360200200141306a2480808080000bfc0203027f017e047f23808080800041306b2201248080808000200141246a419189c28000410941ee88c28000412341e888c28000410010d882808000200141086a2202410036020020014280808080c00037030020012902282103200128022421042001410036021420014280808080800137020c2001410c6a4100109d838080002001280210200128021441386c6a2205420437022c20054210370224200541d98ac2800036022020054100360218200541ea80808000360210200542f0a3fcacaeba9c956f370308200542e3beec81d3e996af917f37030002402004418080808078470d00419a89c280004111418c8ac2800010a181808000000b20012802142105200128020c210620012802102107200042808080808001370244200020043602382000200736020820002006360204200041003a000020002001290300370350200041cc006a41003602002000413c6a20033702002000200541016a36020c200041d8006a2002280200360200200141306a2480808080000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141386c210420014193c9a4124941037421050240024020030d00200241003602180c010b200241083602182002200341386c36021c200220002802043602140b200241086a20052004200241146a109c83808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b22024105742104200241808080204941037421050240024020010d00200341003602180c010b200341083602182003200141057436021c200320002802043602140b200341086a20052004200341146a109c83808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bf60203027f017e057f23808080800041306b2201248080808000200141246a419c8ac28000410641a28ac280004121419c8ac28000410010d882808000200141086a2202410036020020014280808080c00037030020012902282103200128022421042001410036021420014280808080800137020c2001410c6a4100109d8380800020012802102205200128021441386c22066a2207429ae5abc8c1f8c7ab997f370308200742cfdf8096d7fe8c90c100370300200128020c21082007420437022c2007420d370224200741c38ac2800036022020074100360218200741eb8080800036021002402004418080808078470d00419a89c280004111418c8ac2800010a181808000000b200042808080808001370244200020043602382000200536020820002008360204200041003a000020002001290300370350200041cc006a41003602002000413c6a2003370200200041d8006a20022802003602002000200641386a41386e36020c200141306a2480808080000bf40203027f017e057f23808080800041306b2201248080808000200141246a41d08ac28000410941a28ac280004121419c8ac28000410010d882808000200141086a2202410036020020014280808080c00037030020012902282103200128022421042001410036021420014280808080800137020c2001410c6a4100109d8380800020012802102205200128021441386c22066a220742c4decdf7cda6c89430370308200742aad9ebaed398dbfa41370300200128020c21082007420437022c20074210370224200741d98ac2800036022020074100360218200741ec8080800036021002402004418080808078470d00419a89c280004111418c8ac2800010a181808000000b200042808080808001370244200020043602382000200536020820002008360204200041003a000020002001290300370350200041cc006a41003602002000413c6a2003370200200041d8006a20022802003602002000200641386a41386e36020c200141306a2480808080000bf50203027f017e057f23808080800041306b2201248080808000200141246a419c8ac28000410641e98ac280004123419c8ac28000410010d882808000200141086a2202410036020020014280808080c00037030020012902282103200128022421042001410036021420014280808080800137020c2001410c6a4100109d8380800020012802102205200128021441386c22066a220742a4d2928ecac0faa432370308200742c4ccab9c81ebb4b8db00370300200128020c21082007420437022c2007420d370224200741c38ac2800036022020074100360218200741e98080800036021002402004418080808078470d00419a89c280004111418c8ac2800010a181808000000b200042808080808001370244200020043602382000200536020820002008360204200041003a000020002001290300370350200041cc006a41003602002000413c6a2003370200200041d8006a20022802003602002000200641386a41386e36020c200141306a2480808080000bf50203027f017e057f23808080800041306b2201248080808000200141246a41d08ac28000410941e98ac280004123419c8ac28000410010d882808000200141086a2202410036020020014280808080c00037030020012902282103200128022421042001410036021420014280808080800137020c2001410c6a4100109d8380800020012802102205200128021441386c22066a220742f0a3fcacaeba9c956f370308200742e3beec81d3e996af917f370300200128020c21082007420437022c20074210370224200741d98ac2800036022020074100360218200741ea8080800036021002402004418080808078470d00419a89c280004111418c8ac2800010a181808000000b200042808080808001370244200020043602382000200536020820002008360204200041003a000020002001290300370350200041cc006a41003602002000413c6a2003370200200041d8006a20022802003602002000200641386a41386e36020c200141306a2480808080000baf0101017f23808080800041106b2201248080808000200142888080808001370200200142808080808001370208200041c4006a2001109983808000200041106a42e6ed8d82cc91adcb05370300200042dbd791d5c2919eaecd00370308200041c0006a410036020020004280808080c000370338200041d8006a410036020020004280808080c00037035020004121360220200041c880808000360218200041033a0000200141106a2480808080000baf0101017f23808080800041106b2201248080808000200142888080808001370200200142808080808001370208200041c4006a2001109983808000200041106a42e6ed8d82cc91adcb05370300200042dbd791d5c2919eaecd00370308200041c0006a410036020020004280808080c000370338200041d8006a410036020020004280808080c00037035020004120360220200041c880808000360218200041033a0000200141106a2480808080000bb00101017f23808080800041106b2201248080808000200142888080808001370200200142808080808001370208200041c4006a2001109983808000200041106a42e6ed8d82cc91adcb05370300200042dbd791d5c2919eaecd00370308200041c0006a410036020020004280808080c000370338200041d8006a410036020020004280808080c000370350200041c000360220200041c880808000360218200041033a0000200141106a2480808080000bb00101017f23808080800041106b2201248080808000200142888080808001370200200142808080808001370208200041c4006a2001109983808000200041106a42e6ed8d82cc91adcb05370300200042dbd791d5c2919eaecd00370308200041c0006a410036020020004280808080c000370338200041d8006a410036020020004280808080c000370350200041c100360220200041c880808000360218200041033a0000200141106a2480808080000bbf0604057f017e037f017e23808080800041d0006b2201248080808000200141306a418c8bc28000410f419b8bc28000410d418c8bc28000410010d882808000200141286a420437020020014200370220200142808080808001370218200142888080808001370240200142808080808001370248200141186a200141c0006a10a883808000200141086a41086a2001412c6a2802003602002001200129022437030820012802182102200128021c2103200128022021042001280230210520012902342106200141186a41086a2207410036020020014280808080c000370218200141186a410010ad83808000200128021c200728020041246c6a220841003a00202008410936021c200841a88bc280003602182008420437021020084200370208200842808080808001370200200141c0006a41086a2209200728020041016a220836020020012001290218220a37034002402008200aa7470d00200141c0006a200810ad83808000200128024821080b2001280244200841246c6a220841013a00202008410836021c200841b18bc2800036021820084204370210200842003702082008428080808080013702002007200928020041016a220836020020012001290340220a37031802402008200aa7470d00200141186a200810ad83808000200128022021080b200128021c200841246c6a220841023a00202008410e36021c200841b98bc28000360218200842043702102008420037020820084280808080800137020020012802202107200128021c2108200120012802183602202001200836021820012008200741246c6a41246a3602242001200836021c200141c0006a200141186a10a98380800002402005418080808078470d0041e88bc28000411141dc8cc2800010a181808000000b20012002360220200120033602182001200336021c2001200320044105746a360224200041c4006a200141186a10a883808000200141236a200141c0006a41086a2802003600002000413c6a200637020020002005360238200041013a000020002001290308370350200041d8006a200141086a41086a2802003602002001200129024037001b20002001290018370001200041086a2001411f6a290000370000200141d0006a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b22064105762207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710ae8380800020022802082109200228020c21080b200920084105746a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b4105762107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b220641246e2207200128020822014101764f0d01410021082002410036020c20024280808080c00037020441042109024020052004460d00200241046a4100200710af8380800020022802082109200228020c21080b2009200841246c6a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b41246e2107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b220641386e2207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710b08380800020022802082109200228020c21080b2009200841386c6a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b41386e2107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141386c210420014193c9a4124941037421050240024020030d00200241003602180c010b200241083602182002200341386c36021c200220002802043602140b200241086a20052004200241146a10ab83808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141246c2104200141e4f1b81c4941027421050240024020030d00200241003602180c010b200241043602182002200341246c36021c200220002802043602140b200241086a20052004200241146a10ab83808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b22024105742104200241808080204941037421050240024020010d00200341003602180c010b200341083602182003200141057436021c200320002802043602140b200341086a20052004200341146a10ab83808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b220241246c2104200241e4f1b81c4941027421050240024020010d00200341003602180c010b200341043602182003200141246c36021c200320002802043602140b200341086a20052004200341146a10ab83808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b220241386c210420024193c9a4124941037421050240024020010d00200341003602180c010b200341083602182003200141386c36021c200320002802043602140b200341086a20052004200341146a10ab83808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bcc0403057f017e037f23808080800041d0006b2201248080808000200141246a41e18bc28000410741c88bc28000411941c88bc28000410010d8828080002001411c6a42043702002001420037021420014280808080800137020c2001428880808080013702402001428080808080013702482001410c6a200141c0006a10a883808000200141086a2202200141206a28020036020020012001290218370300200128020c2103200128021021042001280214210520012902282106200128022421072001410036021420014280808080800137020c2001410c6a410010ac838080002001280210200128021441386c6a2208420437022c20084203370224200841ec8cc2800036022020084100360218200841b580808000360210200842e88488d0c0e3aebc13370308200842d7c9cb8fc1cf97db3e37030020012802142109200128021021082001200128020c360248200120083602402001200836024420012008200941386c6a41386a36024c200141306a200141c0006a10aa8380800002402007418080808078470d0041e88bc28000411141dc8cc2800010a181808000000b200120033602142001200436020c200120043602102001200420054105746a360218200041c4006a2001410c6a10a883808000200141176a200141306a41086a2802003600002000413c6a200637020020002007360238200041003a000020002001290300370350200041d8006a20022802003602002001200129033037000f2000200129000c370001200041086a2001410c6a41076a290000370000200141d0006a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b22064105762207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710b78380800020022802082109200228020c21080b200920084105746a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b4105762107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b220641386e2207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710b88380800020022802082109200228020c21080b2009200841386c6a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b41386e2107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bca0403057f017e037f23808080800041d0006b2201248080808000200141246a41808ec28000410641868ec28000412741808ec28000410010d8828080002001411c6a42043702002001420037021420014280808080800137020c2001428880808080013702402001428080808080013702482001410c6a200141c0006a10b283808000200141086a2202200141206a28020036020020012001290218370300200128020c2103200128021021042001280214210520012902282106200128022421072001410036021420014280808080800137020c2001410c6a410010b6838080002001280210200128021441386c6a2208420437022c2008420f370224200841f08dc2800036022020084100360218200841ed80808000360210200842a4d2928ecac0faa432370308200842c4ccab9c81ebb4b8db0037030020012802142109200128021021082001200128020c360248200120083602402001200836024420012008200941386c6a41386a36024c200141306a200141c0006a10b38380800002402007418080808078470d0041ef8cc28000411141e08dc2800010a181808000000b200120033602142001200436020c200120043602102001200420054105746a360218200041c4006a2001410c6a10b283808000200141176a200141306a41086a2802003600002000413c6a200637020020002007360238200041003a000020002001290300370350200041d8006a20022802003602002001200129033037000f2000200129000c370001200041086a200141136a290000370000200141d0006a2480808080000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141386c210420014193c9a4124941037421050240024020030d00200241003602180c010b200241083602182002200341386c36021c200220002802043602140b200241086a20052004200241146a10b583808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b22024105742104200241808080204941037421050240024020010d00200341003602180c010b200341083602182003200141057436021c200320002802043602140b200341086a20052004200341146a10b583808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b220241386c210420024193c9a4124941037421050240024020010d00200341003602180c010b200341083602182003200141386c36021c200320002802043602140b200341086a20052004200341146a10b583808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000baf0101017f23808080800041106b2201248080808000200142888080808001370200200142808080808001370208200041c4006a200110b283808000200041106a42e6ed8d82cc91adcb05370300200042dbd791d5c2919eaecd00370308200041c0006a410036020020004280808080c000370338200041d8006a410036020020004280808080c00037035020004120360220200041c880808000360218200041033a0000200141106a2480808080000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141246c2104200141e4f1b81c4941027421050240024020030d00200241003602180c010b200241043602182002200341246c36021c200220002802043602140b200241086a20052004200241146a10ba83808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141386c210420014193c9a4124941037421050240024020030d00200241003602180c010b200241083602182002200341386c36021c200220002802043602140b200241086a20052004200241146a10ba83808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b220241386c210420024193c9a4124941037421050240024020010d00200341003602180c010b200341083602182003200141386c36021c200320002802043602140b200341086a20052004200341146a10ba83808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b220241246c2104200241e4f1b81c4941027421050240024020010d00200341003602180c010b200341043602182003200141246c36021c200320002802043602140b200341086a20052004200341146a10ba83808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b22024105742104200241808080204941037421050240024020010d00200341003602180c010b200341083602182003200141057436021c200320002802043602140b200341086a20052004200341146a10ba83808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000b6e00200042e5f0b3f4e8a9b1b12a37030820004280808080c00037033820004280808080c000370350200041ee80808000360218200041023a0000200041106a4281ebc5ecd497b09a0a370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6f00200042dbd791d5c2919eaecd0037030820004280808080c00037033820004280808080c000370350200041c880808000360218200041023a0000200041106a42e6ed8d82cc91adcb05370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b220641246e2207200128020822014101764f0d01410021082002410036020c20024280808080c00037020441042109024020052004460d00200241046a4100200710be8380800020022802082109200228020c21080b2009200841246c6a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b41246e2107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b22064105762207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710bf8380800020022802082109200228020c21080b200920084105746a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b4105762107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b220641386e2207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710bd8380800020022802082109200228020c21080b2009200841386c6a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b41386e2107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bc90103057f027e017f20012802082102200128020022032104024020012802042205200128020c2206460d0020032104034002402005290300220742efb7e9de94adbae42685200541086a290300220842c785eb8b8b8eddc0618584500d0020052802102109200420083703082004200737030020042009360210200441186a21040b200541186a22052006470d000b0b200142888080808001370200200142808080808001370208200020033602042000200420036b41186e3602082000200241186c41186e3602000b920a04027f017e037f017e23808080800041d0006b2201248080808000200141286a41cc90c28000411141dd90c28000411141cc90c28000410010d882808000200141086a410036020020014280808080c00037030020012802282102200129022c2103200141106a41086a22044100360200200142808080808001370210200141106a410010bc838080002001280214200428020041386c6a2205420437022c200542033702242005419596c280003602202005410d36021c2005418896c28000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c370300200141c0006a41086a2206200428020041016a2205360200200120012902102207370340024020052007a7470d00200141c0006a200510bc83808000200128024821050b2001280244200541386c6a2205420437022c200542033702242005419596c280003602202005410c36021c2005419896c28000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c3703002004200628020041016a2205360200200120012903402207370310024020052007a7470d00200141106a200510bc83808000200128021821050b2001280214200541386c6a2205420437022c2005420a370224200541d695c280003602202005410136021c200541d595c28000360218200541f080808000360210200542e0df9add94b69bd2ff00370308200542bcf58bd0d59aa7c9db00370300200141c0006a41086a2204200141106a41086a220628020041016a2205360200200120012903102207370340024020052007a7470d00200141c0006a200510bc83808000200128024821050b2001280244200541386c6a2205420437022c20054227370224200541af96c280003602202005410b36021c200541a496c28000360218200541f180808000360210200542c6be9491c9dc9cca59370308200542c7e49fb5d2d4f6ebb47f3703002006200428020041016a2205360200200120012903402207370310024020052007a7470d00200141106a200510bc83808000200128021821050b2001280214200541386c6a2205420437022c2005420a370224200541e096c280003602202005410a36021c200541d696c28000360218200541f280808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200141c0006a41086a200141106a41086a28020041016a2205360200200120012903102207370340024020052007a7470d00200141c0006a200510bc83808000200128024821050b2001280244200541386c6a2205420437022c2005420c370224200541ed95c280003602202005410d36021c200541e095c28000360218200541f380808000360210200542edb3cdfa95de98ad10370308200542cde181a596cd91e354370300200128024821042001280244210520012001280240360218200120053602102001200536021420012005200441386c6a41386a36021c200141346a200141106a10c48380800002402002418080808078470d0041d293c28000411141c494c2800010a181808000000b200042808080808001370244200041cc006a4100360200200141cb006a200141346a41086a2802003600002000413c6a200337020020002002360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437004320002001290040370001200041086a200141c7006a290000370000200141d0006a2480808080000bc40504027f017e037f017e23808080800041d0006b2201248080808000200141306a41ee90c28000410c41dd90c28000411141cc90c28000410010d882808000200141086a41086a410036020020014280808080c0003703082001280230210220012902342103200141186a41086a2204410036020020014280808080c000370218200141186a410010bb83808000200128021c200428020041246c6a220541003a00202005410c36021c200541fa90c280003602182005420437021020054200370208200542808080808001370200200141c0006a41086a2206200428020041016a2205360200200120012902182207370340024020052007a7470d00200141c0006a200510bb83808000200128024821050b2001280244200541246c6a220541013a00202005411d36021c2005418691c2800036021820054204370210200542003702082005428080808080013702002004200628020041016a2205360200200120012903402207370318024020052007a7470d00200141186a200510bb83808000200128022021050b200128021c200541246c6a220541023a00202005411b36021c200541a391c28000360218200542043702102005420037020820054280808080800137020020012802202104200128021c2105200120012802183602202001200536021820012005200441246c6a41246a3602242001200536021c200141c0006a200141186a10c28380800002402002418080808078470d0041d293c28000411141c494c2800010a181808000000b200042808080808001370244200041cc006a4100360200200141236a200141c0006a41086a2802003600002000413c6a200337020020002002360238200041013a000020002001290308370350200041d8006a200141086a41086a2802003602002001200129024037001b20002001290018370001200041086a2001411f6a290000370000200141d0006a2480808080000b880504027f017e027f017e23808080800041d0006b2201248080808000200141286a41d091c28000411641dd90c28000411141cc90c28000410010d882808000200141086a410036020020014280808080c00037030020012802282102200129022c2103200141106a41086a22044100360200200142808080808001370210200141106a410010bc838080002001280214200428020041386c6a2205420437022c2005420a370224200541d695c280003602202005410136021c200541d595c28000360218200541f080808000360210200542e0df9add94b69bd2ff00370308200542bcf58bd0d59aa7c9db00370300200141c0006a41086a200428020041016a2205360200200120012902102206370340024020052006a7470d00200141c0006a200510bc83808000200128024821050b2001280244200541386c6a2205420437022c2005420c370224200541ed95c280003602202005410d36021c200541e095c28000360218200541f380808000360210200542edb3cdfa95de98ad10370308200542cde181a596cd91e354370300200128024821042001280244210520012001280240360218200120053602102001200536021420012005200441386c6a41386a36021c200141346a200141106a10c48380800002402002418080808078470d0041d293c28000411141c494c2800010a181808000000b200042808080808001370244200041cc006a4100360200200141cb006a200141346a41086a2802003600002000413c6a200337020020002002360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437004320002001290040370001200041086a200141c7006a290000370000200141d0006a2480808080000bd00303027f017e037f23808080800041d0006b2201248080808000200141286a418392c28000411741dd90c28000411141cc90c28000410010d882808000200141086a2202410036020020014280808080c000370300200129022c21032001280228210420014100360218200142808080808001370210200141106a410010bc838080002001280214200128021841386c6a2205420437022c20054207370224200541ea96c2800036022020054100360218200541f480808000360210200542b891b68c98adebcf61370308200542e7b0a091f3ed9c85c500370300200128021821062001280214210520012001280210360218200120053602102001200536021420012005200641386c6a41386a36021c200141346a200141106a10c48380800002402004418080808078470d0041d293c28000411141c494c2800010a181808000000b200042808080808001370244200041cc006a4100360200200141cc006a200141346a41086a2802003600002000413c6a200337020020002004360238200041003a000020002001290300370350200041d8006a20022802003602002001200129023437004420002001290041370001200041086a200141c8006a290000370000200141d0006a2480808080000b930a04027f017e037f017e23808080800041d0006b2201248080808000200141286a419a92c28000410541dd90c28000411141cc90c28000410010d882808000200141086a410036020020014280808080c00037030020012802282102200129022c2103200141106a41086a22044100360200200142808080808001370210200141106a410010bc838080002001280214200428020041386c6a2205420437022c200542033702242005419596c280003602202005410b36021c200541f196c28000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c370300200141c0006a41086a2206200428020041016a2205360200200120012902102207370340024020052007a7470d00200141c0006a200510bc83808000200128024821050b2001280244200541386c6a2205420437022c20054204370224200541fc94c280003602202005410a36021c200541fc96c28000360218200541f580808000360210200542b8b6d386cdcbfab1a07f370308200542e3a4fae3cee3d18d723703002004200628020041016a2205360200200120012903402207370310024020052007a7470d00200141106a200510bc83808000200128021821050b2001280214200541386c6a2205420437022c200542033702242005419596c280003602202005410836021c2005418697c28000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c370300200141c0006a41086a2204200141106a41086a220628020041016a2205360200200120012903102207370340024020052007a7470d00200141c0006a200510bc83808000200128024821050b2001280244200541386c6a2205420437022c20054227370224200541af96c280003602202005410b36021c200541a496c28000360218200541f180808000360210200542c6be9491c9dc9cca59370308200542c7e49fb5d2d4f6ebb47f3703002006200428020041016a2205360200200120012903402207370310024020052007a7470d00200141106a200510bc83808000200128021821050b2001280214200541386c6a2205420437022c2005420a370224200541e096c280003602202005410a36021c200541d696c28000360218200541f280808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200141c0006a41086a200141106a41086a28020041016a2205360200200120012903102207370340024020052007a7470d00200141c0006a200510bc83808000200128024821050b2001280244200541386c6a2205420437022c200542163702242005419497c280003602202005410636021c2005418e97c28000360218200541f680808000360210200542f2b3a2a5fbe78f9ac600370308200542b7e2f1ac9bf5d4dc827f370300200128024821042001280244210520012001280240360218200120053602102001200536021420012005200441386c6a41386a36021c200141346a200141106a10c48380800002402002418080808078470d0041d293c28000411141c494c2800010a181808000000b200042808080808001370244200041cc006a4100360200200141cb006a200141346a41086a2802003600002000413c6a200337020020002002360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437004320002001290040370001200041086a200141c7006a290000370000200141d0006a2480808080000bec0201027f23808080800041206b220124808080800041002d00fca3c680001a0240413041002802c8a3c680001181808080000022020d004108413010b280808000000b200242a5e9e3ab9e929adc2c370318200242e9b494c69bdbc4d608370308200242ead283debcdebd93d800370300200241f780808000360210200241206a4293888c8f89fdc6ec9e7f370300200241286a41ef808080003602002001200241306a36021c200141023602182001200236021420012002360210200141046a200141106a10c583808000200142888080808001370210200142808080808001370218200041c4006a200141106a10c3838080002001411b6a200141046a41086a280200360000200041c0006a410036020020004280808080c000370338200041043a0000200041d8006a410036020020004280808080c0003703502001200129020437001320002001290010370001200041086a200141176a290000370000200141206a2480808080000bca0403057f017e037f23808080800041d0006b2201248080808000200141286a41b693c28000410641bc93c28000411641a092c28000410010d882808000200141206a420437020020014200370218200142808080808001370210200142888080808001370240200142808080808001370248200141106a200141c0006a10c383808000200141086a2202200141246a2802003602002001200129021c370300200128021021032001280214210420012802182105200129022c21062001280228210720014100360218200142808080808001370210200141106a410010bc838080002001280214200128021841386c6a2208420437022c2008420f370224200841f995c2800036022020084100360218200841f880808000360210200842a4d2928ecac0faa432370308200842c4ccab9c81ebb4b8db00370300200128021821092001280214210820012001280210360248200120083602402001200836024420012008200941386c6a41386a36024c200141346a200141c0006a10c48380800002402007418080808078470d0041d293c28000411141c494c2800010a181808000000b2001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10c3838080002001411b6a200141346a41086a2802003600002000413c6a200637020020002007360238200041003a000020002001290300370350200041d8006a20022802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000bec0201027f23808080800041206b220124808080800041002d00fca3c680001a0240413041002802c8a3c680001181808080000022020d004108413010b280808000000b200242a5e9e3ab9e929adc2c37031820024293888c8f89fdc6ec9e7f370308200242a5e9e3ab9e929adc2c370300200241ef80808000360210200241206a4293888c8f89fdc6ec9e7f370300200241286a41ef808080003602002001200241306a36021c200141023602182001200236021420012002360210200141046a200141106a10c583808000200142888080808001370210200142808080808001370218200041c4006a200141106a10c3838080002001411b6a200141046a41086a280200360000200041c0006a410036020020004280808080c000370338200041043a0000200041d8006a410036020020004280808080c0003703502001200129020437001320002001290010370001200041086a200141176a290000370000200141206a2480808080000baf0101017f23808080800041106b2201248080808000200142888080808001370200200142808080808001370208200041c4006a200110c383808000200041106a42e6ed8d82cc91adcb05370300200042dbd791d5c2919eaecd00370308200041c0006a410036020020004280808080c000370338200041d8006a410036020020004280808080c00037035020004120360220200041c880808000360218200041033a0000200141106a2480808080000b9f0704057f017e037f017e23808080800041d0006b2201248080808000200141286a41a092c28000411041b092c28000411a41a092c28000410010d882808000200141106a41106a420437020020014200370218200142808080808001370210200142888080808001370240200142808080808001370248200141106a200141c0006a10c383808000200141086a200141246a2802003602002001200129021c37030020012802102102200128021421032001280218210420012802282105200129022c2106200141106a41086a22074100360200200142808080808001370210200141106a410010bc838080002001280214200728020041386c6a2208420437022c20084215370224200841e394c280003602202008410f36021c200841d494c28000360218200841b580808000360210200842e88488d0c0e3aebc13370308200842d7c9cb8fc1cf97db3e370300200141c0006a41086a2209200728020041016a220836020020012001290210220a37034002402008200aa7470d00200141c0006a200810bc83808000200128024821080b2001280244200841386c6a2208420437022c20084204370224200841fc94c280003602202008410436021c200841f894c28000360218200841f580808000360210200842b8b6d386cdcbfab1a07f370308200842e3a4fae3cee3d18d723703002007200928020041016a220836020020012001290340220a37031002402008200aa7470d00200141106a200810bc83808000200128021821080b2001280214200841386c6a2208420437022c2008420c3702242008418d95c280003602202008410d36021c2008418095c28000360218200841f980808000360210200842cd86adf4d1ba8a89763703082008428ad5e2d7bdbcbdc342370300200128021821072001280214210820012001280210360248200120083602402001200836024420012008200741386c6a41386a36024c200141346a200141c0006a10c48380800002402005418080808078470d0041d293c28000411141c494c2800010a181808000000b2001200236021820012003360210200120033602142001200320044105746a36021c200041c4006a200141106a10c3838080002001411b6a200141346a41086a2802003600002000413c6a200637020020002005360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000b810604057f017e027f017e23808080800041d0006b2201248080808000200141286a41ca92c28000411741b092c28000411a41a092c28000410010d882808000200141206a420437020020014200370218200142808080808001370210200142888080808001370240200142808080808001370248200141106a200141c0006a10c383808000200141086a200141246a2802003602002001200129021c37030020012802102102200128021421032001280218210420012802282105200129022c2106200141106a41086a22074100360200200142808080808001370210200141106a410010bc838080002001280214200728020041386c6a2208420437022c20084215370224200841e394c280003602202008410f36021c200841d494c28000360218200841b580808000360210200842e88488d0c0e3aebc13370308200842d7c9cb8fc1cf97db3e370300200141c0006a41086a200728020041016a2208360200200120012902102209370340024020082009a7470d00200141c0006a200810bc83808000200128024821080b2001280244200841386c6a2208420437022c20084204370224200841fc94c280003602202008410436021c200841f894c28000360218200841f580808000360210200842b8b6d386cdcbfab1a07f370308200842e3a4fae3cee3d18d72370300200128024821072001280244210820012001280240360248200120083602402001200836024420012008200741386c6a41386a36024c200141346a200141c0006a10c48380800002402005418080808078470d0041d293c28000411141c494c2800010a181808000000b2001200236021820012003360210200120033602142001200320044105746a36021c200041c4006a200141106a10c3838080002001411b6a200141346a41086a2802003600002000413c6a200637020020002005360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000b9c0704057f017e037f017e23808080800041d0006b2201248080808000200141286a41e192c28000411541b092c28000411a41a092c28000410010d882808000200141206a420437020020014200370218200142808080808001370210200142888080808001370240200142808080808001370248200141106a200141c0006a10c383808000200141086a200141246a2802003602002001200129021c37030020012802102102200128021421032001280218210420012802282105200129022c2106200141106a41086a22074100360200200142808080808001370210200141106a410010bc838080002001280214200728020041386c6a2208420437022c20084215370224200841e394c280003602202008410f36021c200841d494c28000360218200841b580808000360210200842e88488d0c0e3aebc13370308200842d7c9cb8fc1cf97db3e370300200141c0006a41086a2209200728020041016a220836020020012001290210220a37034002402008200aa7470d00200141c0006a200810bc83808000200128024821080b2001280244200841386c6a2208420437022c20084204370224200841fc94c280003602202008410436021c200841f894c28000360218200841f580808000360210200842b8b6d386cdcbfab1a07f370308200842e3a4fae3cee3d18d723703002007200928020041016a220836020020012001290340220a37031002402008200aa7470d00200141106a200810bc83808000200128021821080b2001280214200841386c6a2208420437022c2008420c3702242008418d95c280003602202008410d36021c2008418095c28000360218200841f980808000360210200842cd86adf4d1ba8a89763703082008428ad5e2d7bdbcbdc342370300200128021821072001280214210820012001280210360248200120083602402001200836024420012008200741386c6a41386a36024c200141346a200141c0006a10c48380800002402005418080808078470d0041d293c28000411141c494c2800010a181808000000b2001200236021820012003360210200120033602142001200320044105746a36021c200041c4006a200141106a10c3838080002001411b6a200141346a41086a2802003600002000413c6a200637020020002005360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000baa0403057f017e027f23808080800041d0006b2201248080808000200141286a41f692c28000410941b092c28000411a41a092c28000410010d882808000200141206a420437020020014200370218200142808080808001370210200142888080808001370240200142808080808001370248200141106a200141c0006a10c383808000200141086a2202200141246a2802003602002001200129021c370300200128021021032001280214210420012802182105200129022c2106200128022821072001410036021820014280808080c000370210200141c0006a200141106a41ff92c28000410710d483808000200141106a200141c0006a418693c28000410e10d683808000200141346a200141106a419493c28000410c10d7838080002001200128023436021820012001280238220836021020012008200128023c41246c6a36021c20012008360214200141c0006a200141106a10c28380800002402007418080808078470d0041d293c28000411141c494c2800010a181808000000b2001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10c3838080002001411b6a200141c0006a41086a2802003600002000413c6a200637020020002007360238200041013a000020002001290300370350200041d8006a20022802003602002001200129024037001320002001290010370001200041086a200141106a41076a290000370000200141d0006a2480808080000bf80303057f017e027f23808080800041d0006b2201248080808000200141286a41a093c28000411441b092c28000411a41a092c28000410010d882808000200141206a420437020020014200370218200142808080808001370210200142888080808001370240200142808080808001370248200141106a200141c0006a10c383808000200141086a2202200141106a41146a2802003602002001200129021c370300200128021021032001280214210420012802182105200129022c2106200128022821072001410036021820014280808080c000370210200141346a200141106a41b493c28000410210d5838080002001200128023436021820012001280238220836021020012008200128023c41246c6a36021c20012008360214200141c0006a200141106a10c28380800002402007418080808078470d0041d293c28000411141c494c2800010a181808000000b2001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10c3838080002001411b6a200141c0006a41086a2802003600002000413c6a200637020020002007360238200041013a000020002001290300370350200041d8006a20022802003602002001200129024037001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000bbe0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010bc838080002004280208200428020c220541386c6a2206420437022c200642103702242006419995c2800036022020064100360218200641fa80808000360210200642e1eab2d29ed8a59afd003703082006428b91acbbbb91f6d30b37030020042802042107200428020821080240200128020822062001280200470d002001200610bb83808000200128020821060b2001280204200641246c6a220641013a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bf20303037f017e027f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010bc8380800020042802182005280200220641386c6a2205420437022c2005420a370224200541d695c280003602202005410136021c200541d595c28000360218200541f080808000360210200542e0df9add94b69bd2ff00370308200542bcf58bd0d59aa7c9db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610bc83808000200428021021060b200428020c200641386c6a2205420437022c2005420c370224200541ed95c280003602202005410d36021c200541e095c28000360218200541f380808000360210200542edb3cdfa95de98ad10370308200542cde181a596cd91e35437030020042802082108200428020c21090240200128020822052001280200470d002001200510bb83808000200128020821050b2001280204200541246c6a220541013a00202005200336021c200520023602182005410036021420054280808080c00037020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000bbe0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010bc838080002004280208200428020c220541386c6a2206420437022c20064217370224200641a995c2800036022020064100360218200641fb80808000360210200642beb6e3c9cf8cb1be2137030820064290e384e9e5949acd8f7f37030020042802042107200428020821080240200128020822062001280200470d002001200610bb83808000200128020821060b2001280204200641246c6a220641023a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bbd0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010bc838080002004280208200428020c220541386c6a2206420437022c20064215370224200641c095c2800036022020064100360218200641fc80808000360210200642a8f8d28adee2a2ca163703082006429e8f89a5d7f0a0bf7d37030020042802042107200428020821080240200128020822062001280200470d002001200610bb83808000200128020821060b2001280204200641246c6a220641033a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000baf0101017f23808080800041106b2201248080808000200142888080808001370200200142808080808001370208200041c4006a200110c383808000200041106a42e6ed8d82cc91adcb05370300200042dbd791d5c2919eaecd00370308200041c0006a410036020020004280808080c000370338200041d8006a410036020020004280808080c00037035020004120360220200041c880808000360218200041033a0000200141106a2480808080000b7700200042dbd791d5c2919eaecd0037030820004280808080c00037033820004280808080c000370350200041c000360220200041c880808000360218200041033a0000200041106a42e6ed8d82cc91adcb05370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b7600200042dbd791d5c2919eaecd0037030820004280808080c00037033820004280808080c00037035020004120360220200041c880808000360218200041033a0000200041106a42e6ed8d82cc91adcb05370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141386c210420014193c9a4124941037421050240024020030d00200241003602180c010b200241083602182002200341386c36021c200220002802043602140b200241086a20052004200241146a10db83808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bf50203027f017e057f23808080800041306b2201248080808000200141246a41ac98c28000410641b298c28000411941ac98c28000410010d882808000200141086a2202410036020020014280808080c00037030020012902282103200128022421042001410036021420014280808080800137020c2001410c6a410010dc8380800020012802102205200128021441386c22066a220742a4d2928ecac0faa432370308200742c4ccab9c81ebb4b8db00370300200128020c21082007420437022c2007420f370224200741cb98c2800036022020074100360218200741fd8080800036021002402004418080808078470d0041aa97c280004111419c98c2800010a181808000000b200042808080808001370244200020043602382000200536020820002008360204200041003a000020002001290300370350200041cc006a41003602002000413c6a2003370200200041d8006a20022802003602002000200641386a41386e36020c200141306a2480808080000bf50203027f017e057f23808080800041306b2201248080808000200141246a41da98c28000410941b298c28000411941ac98c28000410010d882808000200141086a2202410036020020014280808080c00037030020012902282103200128022421042001410036021420014280808080800137020c2001410c6a410010dc8380800020012802102205200128021441386c22066a220742f0a3fcacaeba9c956f370308200742e3beec81d3e996af917f370300200128020c21082007420437022c20074212370224200741e398c2800036022020074100360218200741fe8080800036021002402004418080808078470d0041aa97c280004111419c98c2800010a181808000000b200042808080808001370244200020043602382000200536020820002008360204200041003a000020002001290300370350200041cc006a41003602002000413c6a2003370200200041d8006a20022802003602002000200641386a41386e36020c200141306a2480808080000bf20203027f017e057f23808080800041306b2201248080808000200141246a41f899c28000410441fc99c28000411241f899c28000410010d882808000200141086a2202410036020020014280808080c00037030020012902282103200128022421042001410036021420014280808080800137020c2001410c6a410010e283808000200128021022052001280214220641386c6a22074293888c8f89fdc6ec9e7f370308200742a5e9e3ab9e929adc2c370300200128020c21082007420437022c200742033702242007418e9ac2800036022020074100360218200741ef8080800036021002402004418080808078470d0041f598c28000411141e899c2800010a181808000000b20002001290300370350200042808080808001370244200020043602382000200536020820002008360204200041003a0000200041cc006a41003602002000413c6a20033702002000200641016a36020c200041d8006a2002280200360200200141306a2480808080000bf20203027f017e057f23808080800041306b2201248080808000200141246a41919ac28000410c41fc99c28000411241f899c28000410010d882808000200141086a2202410036020020014280808080c00037030020012902282103200128022421042001410036021420014280808080800137020c2001410c6a410010e283808000200128021022052001280214220641386c6a22074293888c8f89fdc6ec9e7f370308200742a5e9e3ab9e929adc2c370300200128020c21082007420437022c200742033702242007418e9ac2800036022020074100360218200741ef8080800036021002402004418080808078470d0041f598c28000411141e899c2800010a181808000000b20002001290300370350200042808080808001370244200020043602382000200536020820002008360204200041003a0000200041cc006a41003602002000413c6a20033702002000200641016a36020c200041d8006a2002280200360200200141306a2480808080000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141386c210420014193c9a4124941037421050240024020030d00200241003602180c010b200241083602182002200341386c36021c200220002802043602140b200241086a20052004200241146a10e183808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141386c210420014193c9a4124941037421050240024020030d00200241003602180c010b200241083602182002200341386c36021c200220002802043602140b200241086a20052004200241146a10e383808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b220241386c210420024193c9a4124941037421050240024020010d00200341003602180c010b200341083602182003200141386c36021c200320002802043602140b200341086a20052004200341146a10e383808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b22024105742104200241808080204941037421050240024020010d00200341003602180c010b200341083602182003200141057436021c200320002802043602140b200341086a20052004200341146a10e383808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b220241246c2104200241e4f1b81c4941027421050240024020010d00200341003602180c010b200341043602182003200141246c36021c200320002802043602140b200341086a20052004200341146a10e383808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bf10803067f057e027f23808080800041a0056b220324808080800020034200370340200342f9c2f89b91a3b3f0db00370338200342ebfa86dabfb5f6c11f3703302003429fd8f9d9c291da829b7f370328200342d1859aeffacf9487d100370320200342f1edf4f8a5a7fda7a57f370318200342abf0d3f4afeebcb73c370310200342bbceaaa6d8d0ebb3bb7f370308200342c892f795ffccf984ea00370300200341cf006a410041f900108a8e8080002104200341c8016a41073a0000200341cb006a41002800a39ac28000360000200341002800a09ac2800036024802400240200241fa00490d002004200141f90010848e8080001a20034280013703402003200341c8006a22054200420010bb80808000200141f9006a2201200241877f6a2202410776200241ff00712202456b22064107746a2107200241800120021b210402402006450d00200641077421020340200320032903404280017c370340200320014200420010bb8080800020014180016a2101200241807f6a22020d000b0b20052007200410848e8080001a0c010b20042001200210848e8080001a200241076a21040b200320043a00c80120034190026a200341d00110848e8080001a200320032903d002200341d8036a2d00002201ad7c3703d002200341d8026a210202402001418001460d00200220016a410041800120016b108a8e8080001a0b200341003a00d80320034190026a2002427f420010bb80808000200341a0046a41086a220120034190026a41086a290300370300200341a0046a41106a220220034190026a41106a290300370300200341a0046a41186a220420034190026a41186a290300370300200341a0046a41206a220620032903b002370300200341a0046a41286a220520034190026a41286a290300370300200341a0046a41306a220720034190026a41306a290300370300200341a0046a41386a220820034190026a41386a29030037030020032003290390023703a004200341e0036a41106a20022903002209370300200341e0036a41186a2004290300220a370300200341e0036a41206a2006290300220b370300200341e0036a41286a2005290300220c370300200341e0036a41306a2007290300220d370300200341d0016a41086a22022001290300370300200341d0016a41106a22042009370300200341d0016a41186a2206200a370300200341d0016a41206a2205200b370300200341d0016a41286a2207200c370300200341d0016a41306a220e200d370300200341d0016a41386a220f2008290300370300200320032903a0043703d00141002d00fca3c680001a024041c00041002802c8a3c680001181808080000022010d00410141c00010b280808000000b200120032903d001370000200041c00036020820002001360204200041c000360200200141386a200f290300370000200141306a200e290300370000200141286a2007290300370000200141206a2005290300370000200141186a2006290300370000200141106a2004290300370000200141086a2002290300370000200341a0056a2480808080000bca0403057f017e037f23808080800041d0006b2201248080808000200141286a41b69ac28000410941a79ac28000410f41a09ac28000410010d882808000200141206a420437020020014200370218200142808080808001370210200142888080808001370240200142808080808001370248200141106a200141c0006a10f483808000200141086a2202200141246a2802003602002001200129021c370300200128021021032001280214210420012802182105200129022c21062001280228210720014100360218200142808080808001370210200141106a410010e4838080002001280214200128021841386c6a2208420437022c20084207370224200841809cc2800036022020084100360218200841ff80808000360210200842d886fac2c186f9c46f3703082008429cfcf2b9cfebc9bfa37f370300200128021821092001280214210820012001280210360248200120083602402001200836024420012008200941386c6a41386a36024c200141346a200141c0006a10f58380800002402007418080808078470d0041fd9ac28000411141f09bc2800010a181808000000b2001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10f4838080002001411b6a200141346a41086a2802003600002000413c6a200637020020002007360238200041003a000020002001290300370350200041d8006a20022802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000baf0101017f23808080800041106b2201248080808000200142888080808001370200200142808080808001370208200041c4006a200110f483808000200041106a42e6ed8d82cc91adcb05370300200042dbd791d5c2919eaecd00370308200041c0006a410036020020004280808080c000370338200041d8006a410036020020004280808080c00037035020004104360220200041c880808000360218200041033a0000200141106a2480808080000bcd0403057f017e037f23808080800041d0006b2201248080808000200141286a41c09ac28000410e41ce9ac28000410741c09ac28000410010d882808000200141206a420437020020014200370218200142808080808001370210200142888080808001370240200142808080808001370248200141106a200141c0006a10f483808000200141086a2202200141246a2802003602002001200129021c370300200128021021032001280214210420012802182105200129022c21062001280228210720014100360218200142808080808001370210200141106a410010e4838080002001280214200128021841386c6a2208420437022c20084207370224200841879cc28000360220200841003602182008418081808000360210200842b891b68c98adebcf61370308200842e7b0a091f3ed9c85c500370300200128021821092001280214210820012001280210360248200120083602402001200836024420012008200941386c6a41386a36024c200141346a200141c0006a10f58380800002402007418080808078470d0041fd9ac28000411141f09bc2800010a181808000000b2001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10f4838080002001411b6a200141346a41086a2802003600002000413c6a200637020020002007360238200041003a000020002001290300370350200041d8006a20022802003602002001200129023437001320002001290010370001200041086a200141106a41076a290000370000200141d0006a2480808080000bb50303057f017e017f23808080800041c0006b2201248080808000200141246a41d59ac28000410441ce9ac28000410741c09ac28000410010d8828080002001411c6a42043702002001420037021420014280808080800137020c2001428880808080013702302001428080808080013702382001410c6a200141306a10f483808000200141086a2202200141206a28020036020020012001290218370300200128020c21032001280210210420012802142105200129022821062001280224210720014284808080c00037020c20014280808080c000370214200141306a2001410c6a10f38380800002402007418080808078470d0041fd9ac28000411141f09bc2800010a181808000000b200120033602142001200436020c200120043602102001200420054105746a360218200041c4006a2001410c6a10f483808000200141176a200141306a41086a2802003600002000413c6a200637020020002007360238200041013a000020002001290300370350200041d8006a20022802003602002001200129023037000f2000200129000c370001200041086a2001410c6a41076a290000370000200141c0006a2480808080000b950301037f0240200028020022022802002200413f4b0d00200041027421020240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a20023a00000f0b0240200041ffff004b0d002000410274410172210202402001280200200128020822006b41014b0d0020012000410210b182808000200128020821000b2001200041026a360208200128020420006a20023b00000f0b0240200041ffffffff034b0d002000410274410272210202402001280200200128020822006b41034b0d0020012000410410b182808000200128020821000b2001200041046a360208200128020420006a20023600000f0b02402001280200220320012802082200470d0020012000410110b18280800020012802002103200128020821000b2001280204220420006a41033a00002001200041016a2200360208200228020021020240200320006b41034b0d0020012000410410b18280800020012802042104200128020821000b2001200041046a360208200420006a20023600000b7600200042dbd791d5c2919eaecd0037030820004280808080c00037033820004280808080c00037035020004120360220200041c880808000360218200041033a0000200041106a42e6ed8d82cc91adcb05370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b7700200042dbd791d5c2919eaecd0037030820004280808080c00037033820004280808080c000370350200041c000360220200041c880808000360218200041033a0000200041106a42e6ed8d82cc91adcb05370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b880504027f017e027f017e23808080800041d0006b2201248080808000200141286a41dc9ac28000410c41e89ac28000411541dc9ac28000410010d882808000200141086a410036020020014280808080c00037030020012802282102200129022c2103200141106a41086a22044100360200200142808080808001370210200141106a410010e4838080002001280214200428020041386c6a2205420437022c2005420c370224200541989cc280003602202005410a36021c2005418e9cc280003602182005418181808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200141c0006a41086a200428020041016a2205360200200120012902102206370340024020052006a7470d00200141c0006a200510e483808000200128024821050b2001280244200541386c6a2205420437022c20054208370224200541a99cc280003602202005410536021c200541a49cc280003602182005418281808000360210200542f0a3fcacaeba9c956f370308200542e3beec81d3e996af917f370300200128024821042001280244210520012001280240360218200120053602102001200536021420012005200441386c6a41386a36021c200141346a200141106a10f58380800002402002418080808078470d0041fd9ac28000411141f09bc2800010a181808000000b200042808080808001370244200041cc006a4100360200200141cb006a200141346a41086a2802003600002000413c6a200337020020002002360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437004320002001290040370001200041086a200141c7006a290000370000200141d0006a2480808080000b810201037f23808080800041206b22032480808080000240024002400240200241046a22040d00410121050c010b2004417f4c0d0141002d00fca3c680001a200441002802c8a3c68000118180808000002205450d020b20034100360214200320053602102003200436020c200320023602182003200341186a36021c2003411c6a2003410c6a10ed838080000240200328020c200328021422046b20024f0d002003410c6a2004200210b182808000200328021421040b200328021020046a2001200210848e8080001a200041086a200420026a3602002000200329020c370200200341206a2480808080000f0b10ae80808000000b4101200410b280808000000b6f00200042dbd791d5c2919eaecd0037030820004280808080c00037033820004280808080c000370350200041c880808000360218200041023a0000200041106a42e6ed8d82cc91adcb05370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b220641246e2207200128020822014101764f0d01410021082002410036020c20024280808080c00037020441042109024020052004460d00200241046a4100200710e78380800020022802082109200228020c21080b2009200841246c6a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b41246e2107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b22064105762207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710e68380800020022802082109200228020c21080b200920084105746a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b4105762107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b220641386e2207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710e58380800020022802082109200228020c21080b2009200841386c6a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b41386e2107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000b6f002000428d9abfc787899e9d7f37030820004280808080c00037033820004280808080c0003703502000418381808000360218200041023a0000200041106a42aeabccc7cea8c39bcc00370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000be20101017f41002d00fca3c680001a0240413041002802c8a3c680001181808080000022010d004108413010b280808000000b200142e7b0a091f3ed9c85c500370318200142a8c7daf8defb9a8fc400370308200142a7b98ffce8cbcbd38b7f370300200141848180800036021020004280808080c00037033820004280808080c0003703502000410236020c2000200136020820004102360204200041043a0000200141206a42b891b68c98adebcf61370300200141286a418581808000360200200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6f00200042dbd791d5c2919eaecd0037030820004280808080c00037033820004280808080c000370350200041c880808000360218200041023a0000200041106a42e6ed8d82cc91adcb05370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b950501077f23808080800041306b22012480808080002001410836020c200141b49dc2800036020841002d00fca3c680001a024002400240410841002802c8a3c68000118180808000002202450d00200241b49dc28000360200200241046a410836020041b49dc28000410810d782808000450d0141002d00fca3c680001a41c00041002802c8a3c68000118180808000002203450d02200342a7b98ffce8cbcbd38b7f370308200341bd9dc28000360220200341848180800036021820034101360204200341bc9dc28000360200200341306a42b891b68c98adebcf61370300200341286a42e7b0a091f3ed9c85c500370300200341106a42a8c7daf8defb9a8fc400370300200341386a418581808000360200200341246a410136020020014100360218200142808080808001370210200141106a410010fe8380800020012802142204200128021841386c22056a220642bcc8e6aaf4e393df6c3703082006429de7d5c2a3c6909862370300200128021021072006410036023020064280808080c00037032820064100360220200641003602182006418681808000360210200041cc006a4102360200200041c8006a2003360200200041023602442000413c6a2002ad4280808080108437020020004101360238200041d8006a410036020020004280808080c0003703502000200541386a41386e36020c2000200436020820002007360204200041003a0000200141306a2480808080000f0b4104410810b280808000000b200241002802c0a3c68000118080808000002001411c6a42013702002001410236021420014180ddc18000360210200141b48080800036022c2001200141286a3602182001200141086a360228200141106a4190ddc1800010f680808000000b410841c00010b280808000000b7600200042dbd791d5c2919eaecd0037030820004280808080c00037033820004280808080c00037035020004108360220200041c880808000360218200041033a0000200041106a42e6ed8d82cc91adcb05370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b800303027f017e057f23808080800041306b2201248080808000200141246a41c09dc28000410c41cc9dc28000410c41c09dc28000410010d882808000200141086a2202410036020020014280808080c00037030020012902282103200128022421042001410036021420014280808080800137020c2001410c6a410010fe8380800020012802102205200128021441386c22066a2207428485acdad4b59be240370308200742f4d89fc7ac8bcaf8db00370300200128020c21082007420437022c20074225370224200741dc9dc280003602202007410436021c200741d89dc28000360218200741878180800036021002402004418080808078470d0041b19cc28000411141a49dc2800010a181808000000b200042808080808001370244200020043602382000200536020820002008360204200041003a000020002001290300370350200041cc006a41003602002000413c6a2003370200200041d8006a20022802003602002000200641386a41386e36020c200141306a2480808080000bcc0505027f017e037f017e017f23808080800041d0006b2201248080808000200141306a41819ec28000411441cc9dc28000410c41c09dc28000410010d882808000200141086a41086a410036020020014280808080c0003703082001280230210220012902342103200141186a41086a22044100360200200142808080808001370218200141186a410010fe83808000200128021c2004280200220541386c6a2206420437022c20064204370224200641999ec280003602202006410436021c200641959ec28000360218200641888180800036021020064298848fa1dab08ba174370308200642febac4ad81b6fafcb37f370300200141c0006a41086a200541016a2205360200200120012902182207370340024020052007a7470d00200141c0006a200510fe83808000200128024821050b2001280244200541386c6a2206420437022c20064204370224200641999ec280003602202006410b36021c2006419d9ec28000360218200641888180800036021020064298848fa1dab08ba174370308200642febac4ad81b6fafcb37f3703002004200541016a2206360200200120012903402207370318024020062007a72205470d00200141186a200610fe8380800020012802182105200128022021060b200128021c2204200641386c22086a220642aeb899d38addfa91213703082006429cc4c6fe96f1ecf5e0003703002006420437022c2006420c370224200641c09dc280003602202006410636021c200641a89ec28000360218200641898180800036021002402002418080808078470d0041b19cc28000411141a49dc2800010a181808000000b200042808080808001370244200020023602382000200436020820002005360204200041003a000020002001290308370350200041cc006a41003602002000413c6a2003370200200041d8006a200141106a2802003602002000200841386a41386e36020c200141d0006a2480808080000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141386c210420014193c9a4124941037421050240024020030d00200241003602180c010b200241083602182002200341386c36021c200220002802043602140b200241086a20052004200241146a10fd83808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000b8f04010a7f23808080800041c0006b220324808080800002400240024002402001280204220441216e2205200220052002491b22050d00410121060c010b200541bef0831f4b0d01200541216c2207417f4c0d0141002d00fca3c680001a200741002802c8a3c68000118180808000002206450d020b4100210720034100360214200320063602102003200536020c0240024002402002450d0020012802002105034020044121490d0220012004415f6a22043602042001200541216a2208360200200341186a41086a2209200541086a290000370300200341186a41106a220a200541106a290000370300200341186a41186a220b200541186a290000370300200341186a41206a220c200541206a2d00003a00002003200529000037031802402007200328020c470d002003410c6a200710838480800020032802102106200328021421070b2006200741216c6a22052003290318370000200541206a200c2d00003a0000200541186a200b290300370000200541106a200a290300370000200541086a20092903003700002003200741016a2207360214200821052002417f6a22020d000b0b2000200329020c370200200041086a2003410c6a41086a2802003602000c010b2000418080808078360200200328020c450d00200641002802c0a3c68000118080808000000b200341c0006a2480808080000f0b10ae80808000000b4101200710b280808000000beb0301097f23808080800041306b22032480808080000240024002400240200128020422044105762205200220052002491b22050d00410121060c010b200541ffffff1f4b0d0120054105742207417f4c0d0141002d00fca3c680001a200741002802c8a3c68000118180808000002206450d020b410021072003410036020c20032006360208200320053602040240024002402002450d0020012802002105034020044120490d022001200441606a22043602042001200541206a2208360200200341106a41086a2209200541086a290000370300200341106a41106a220a200541106a290000370300200341106a41186a220b200541186a29000037030020032005290000370310024020072003280204470d00200341046a200710848480800020032802082106200328020c21070b200620074105746a22052003290310370000200541186a200b290300370000200541106a200a290300370000200541086a20092903003700002003200741016a220736020c200821052002417f6a22020d000b0b20002003290204370200200041086a200341046a41086a2802003602000c010b20004180808080783602002003280204450d00200641002802c0a3c68000118080808000000b200341306a2480808080000f0b10ae80808000000b4101200710b280808000000beb0301097f23808080800041306b22032480808080000240024002400240200128020422044105762205200220052002491b22050d00410121060c010b200541ffffff1f4b0d0120054105742207417f4c0d0141002d00fca3c680001a200741002802c8a3c68000118180808000002206450d020b410021072003410036020c20032006360208200320053602040240024002402002450d0020012802002105034020044120490d022001200441606a22043602042001200541206a2208360200200341106a41086a2209200541086a290000370300200341106a41106a220a200541106a290000370300200341106a41186a220b200541186a29000037030020032005290000370310024020072003280204470d00200341046a200710848480800020032802082106200328020c21070b200620074105746a22052003290310370000200541186a200b290300370000200541106a200a290300370000200541086a20092903003700002003200741016a220736020c200821052002417f6a22020d000b0b20002003290204370200200041086a200341046a41086a2802003602000c010b20004180808080783602002003280204450d00200641002802c0a3c68000118080808000000b200341306a2480808080000f0b10ae80808000000b4101200710b280808000000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000bea0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141bff0831f492104200141216c21050240024020030d00200241003602180c010b200241013602182002200341216c36021c200220002802043602140b200241086a20042005200241146a108284808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bea0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b22014180808020492104200141057421050240024020030d00200241003602180c010b200241013602182002200341057436021c200220002802043602140b200241086a20042005200241146a108284808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000ba90301057f23808080800041206b22022480808080000240024002402001422088a722030d002000410036020820004280808080103702000c010b20022003417f6a220436021820022001a7220541016a3602140240024002400240024020052d000022064103710e0400030102000b200641027621030c030b20034104490d0420022003417c6a3602182002200541046a360214200541036a2d000041187420052f000141087472200672220341808004490d04200341027621030c020b200641044f0d0320034105490d0320022003417b6a3602182002200541056a360214200528000122034180808080044f0d010c030b2004450d0220022003417e6a3602182002200541026a36021420052d000141087420067241ffff03712203418002490d02200341027621030b200241086a200241146a20031081848080002002280208418080808078460d0120002002290208370200200041086a200241086a41086a280200360200200541002802c0a3c68000118080808000000b200241206a2480808080000f0b41ae9ec28000412e2002411f6a41dc9ec2800041dc9fc28000108981808000000ba90301057f23808080800041206b22022480808080000240024002402001422088a722030d002000410036020820004280808080103702000c010b20022003417f6a220436021820022001a7220541016a3602140240024002400240024020052d000022064103710e0400030102000b200641027621030c030b20034104490d0420022003417c6a3602182002200541046a360214200541036a2d000041187420052f000141087472200672220341808004490d04200341027621030c020b200641044f0d0320034105490d0320022003417b6a3602182002200541056a360214200528000122034180808080044f0d010c030b2004450d0220022003417e6a3602182002200541026a36021420052d000141087420067241ffff03712203418002490d02200341027621030b200241086a200241146a200310ff838080002002280208418080808078460d0120002002290208370200200041086a200241086a41086a280200360200200541002802c0a3c68000118080808000000b200241206a2480808080000f0b41ae9ec28000412e2002411f6a41dc9ec2800041dc9fc28000108981808000000ba90301057f23808080800041206b22022480808080000240024002402001422088a722030d002000410036020820004280808080103702000c010b20022003417f6a220436021820022001a7220541016a3602140240024002400240024020052d000022064103710e0400030102000b200641027621030c030b20034104490d0420022003417c6a3602182002200541046a360214200541036a2d000041187420052f000141087472200672220341808004490d04200341027621030c020b200641044f0d0320034105490d0320022003417b6a3602182002200541056a360214200528000122034180808080044f0d010c030b2004450d0220022003417e6a3602182002200541026a36021420052d000141087420067241ffff03712203418002490d02200341027621030b200241086a200241146a20031080848080002002280208418080808078460d0120002002290208370200200041086a200241086a41086a280200360200200541002802c0a3c68000118080808000000b200241206a2480808080000f0b41ae9ec28000412e2002411f6a41dc9ec2800041dc9fc28000108981808000000ba80301057f23808080800041206b22022480808080002001280204210302400240024002400240024020012802082201410c6c41046a22040d00410121050c010b2004417f4c0d0141002d00fca3c680001a200441002802c8a3c68000118180808000002205450d020b20024100360214200220053602102002200436020c200220013602182002200241186a36021c2002411c6a2002410c6a10b5848080002001450d022001410c6c2106200341086a210403402004417c6a28020021032002200428020022013602182002200241186a36021c2002411c6a2002410c6a10b5848080000240200228020c200228021422056b20014f0d002002410c6a2005200110b182808000200228021421050b200228021020056a2003200110848e8080001a2002200520016a22013602142004410c6a2104200641746a22060d000c040b0b10ae80808000000b4101200410b280808000000b200228021421010b200228020c2105200228021021042000410c6a2001360200200041086a2004360200200020053602042000410136020020002001ad4220862004ad84370310200241206a2480808080000b02000b2100200128021441ec9fc280004105200141186a28020028020c118280808000000b0f002000280200200110e9808080000b120020014198a2c28000410210dd808080000b02000bd30101027f2001410c6a2802002102024002400240024002400240024020012802040e020001020b20020d01410121034100210141b8a1c2800021020c030b2002450d010b2000200110b8808080000f0b2001280200220128020021020240200128020422010d0041012103410021010c010b2001417f4c0d0141002d00fca3c680001a200141002802c8a3c68000118180808000002203450d020b20032002200110848e80800021022000200136020820002002360204200020013602000f0b10ae80808000000b4101200110b280808000000b02000b22002000410036020c2000200336020820002002360204200041b8a1c280003602000b040041000b21002001280214419aa2c280004105200141186a28020028020c118280808000000b8a0101017f23808080800041306b2201248080808000200120003602002001411c6a420137020020014101360214200141a0a2c280003602102001418c8180800036022c2001200141286a36021820012001360228200141046a200141106a108e84808000410141a8a2c2800041072001280208200128020c41002802d0a2c680001187808080000000000bb20201067f41022102024002402001280208220320012802102204470d000c010b024002400240024002400240200441016a2205450d0020032005490d01200128020421062001200536021002400240200620046a2d00000e020001080b200320056b4104490d07200441056a21072005417b4b0d0341002102200720034b0d040c060b200320056b4104490d06200441056a21072005417b4b0d0441012102200720034d0d05200720034190fbc08000109581808000000b417f20054190fbc08000109681808000000b200520034190fbc08000109581808000000b200520074190fbc08000109681808000000b200720034190fbc08000109581808000000b200520074190fbc08000109681808000000b20012007360210200620056a28000021070b20002007360204200020023602000b40002001ad4220862000ad84200235020842208620022802042201ad8410808080800002402002280200450d00200141002802c0a3c68000118080808000000b0b12002001ad4220862000ad841081808080000b9d0302047f027e23808080800041206b22052480808080004100210641002d00fca3c680001a024002404105410120031b220741002802c8a3c68000118180808000002208450d002002ad42208621090240024020030d00428080808010210a0c010b200820043600014280808080d000210a410121060b200820063a00000240024020092001ad84200a2008ad841082808080002209422088a722020d0041b8a1c28000210341b8a1c280002106410021010c010b41a489c08000210602402009a72203410171450d00200321010c010b20034101722101419489c0800021060b2005410036021c2005200136021820052002360214200520033602102005200636020c20052005410c6a1094848080002005280204210620052802002103200541186a20052802102005280214200528020c28020c1185808080000020034102460d01200841002802c0a3c68000118080808000002000200636020420002003360200200541206a2480808080000f0b4101200710b280808000000b41c8a1c28000412e2005410c6a41f8a1c280004188a2c28000108981808000000b08001083808080000b800303017f017e027f23808080800041306b22032480808080000240024002402002ad4220862001ad841084808080002204422088a72202450d00410021052003410036021c2003200236021420032004a722023602102003410136021c200320022002410172200241017122011b360218200341a489c08000419489c0800020011b36020c200341186a21060240024020022d00000e020001040b41002101410121050c030b200341206a2003410c6a10b28280800020032802202201450d01200341086a2003412c6a28020036020020032003290224370300410121050c020b2003420037021820032002360214200341b8a1c28000360210200341b8a1c2800036020c200341186a2106410021050b0b200620032802102003280214200328020c28020c11858080800000024020050d0041c8a1c28000412e2003410c6a41f8a1c280004188a2c28000108981808000000b20002001360200200020032903003702042000410c6a200341086a280200360200200341306a2480808080000b9e0203017f017e027f23808080800041206b2203248080808000024002402002ad4220862001ad841085808080002204422088a722050d0041b8a1c28000210241b8a1c280002101410021060c010b41a489c08000210102402004a72202410171450d00200221060c010b20024101722106419489c0800021010b2003410036021c2003200636021820032005360214200320023602102003200136020c20032003410c6a10bc84808000200341186a20032802102003280214200328020c28020c1185808080000002402003280200418180808078470d0041c8a1c28000412e2003410c6a41f8a1c280004188a2c28000108981808000000b20002003290200370200200041086a200341086a280200360200200341206a2480808080000ba30202017f017e23808080800041206b2206248080808000024002402002ad4220862001ad842004ad4220862003ad8420051086808080002207422088a722020d0041b8a1c28000210441b8a1c280002103410021010c010b41a489c08000210302402007a72204410171450d00200421010c010b20044101722101419489c0800021030b2006410036021c2006200136021820062002360214200620043602102006200336020c20062006410c6a10ba848080002006280204210320062802002104200641186a20062802102006280214200628020c28020c11858080800000024020044102470d0041c8a1c28000412e2006410c6a41f8a1c280004188a2c28000108981808000000b2000200336020420002004360200200641206a2480808080000b08001087808080000b4101017e024020011088808080002202422088a722010d002000410036020820004280808080103702000f0b20002001360208200020023e0204200020013602000b1c002001ad4220862000ad842003ad4220862002ad841089808080000b0800108a808080000b380020002002ad4220862001ad84108b80808000220229000837000820002002290000370000200241002802c0a3c68000118080808000000b5e0020002002ad4220862001ad84108c808080002202290000370000200041186a200241186a290000370000200041106a200241106a290000370000200041086a200241086a290000370000200241002802c0a3c68000118080808000000b380020002002ad4220862001ad84108d80808000220229000837000820002002290000370000200241002802c0a3c68000118080808000000b2e0020002002ad4220862001ad84108e808080002202290000370000200241002802c0a3c68000118080808000000b12002001ad4220862000ad84108f808080000b1c002001ad4220862000ad842003ad4220862002ad841090808080000bf70101037f23808080800041106b220324808080800020032001360200200341046a200210b9848080002003280204210420002003200335020c42208620032802082205ad841091808080002201290000370000200041206a200141206a2d00003a0000200041186a200141186a290000370000200041106a200141106a290000370000200041086a200141086a290000370000200141002802c0a3c680001180808080000002402004450d00200541002802c0a3c68000118080808000000b024020022802002200418080808078460d002000450d00200228020441002802c0a3c68000118080808000000b200341106a2480808080000b3a01017f23808080800041106b22022480808080002002200136020c20002002410c6a109280808000108684808000200241106a2480808080000bac0202017f017e23808080800041f0006b22052480808080002005200136020002400240200520022004ad4220862003ad841093808080002206422088a722010d002005420037020c200541b8a1c28000360208200541b8a1c280003602040c010b2005200136021c200520063e021820052001360214200541046a200541146a10bf808080000b200541d8006a41086a2201200541046a41086a2902003703002005200529020437035820054100360268200541146a200541d8006a10bb84808000200541e4006a200528025c2001280200200528025828020c11858080800000024020052d00144102470d0041c8a1c28000412e200541d8006a41f8a1c280004188a2c28000108981808000000b2000200541146a41c20010848e8080001a200541f0006a2480808080000b190020002002ad4220862001ad8420031094808080004101460be70101037f23808080800041106b220324808080800020032001360200200341046a200210b9848080002003280204210420002003200335020c42208620032802082205ad841095808080002201290000370000200041186a200141186a290000370000200041106a200141106a290000370000200041086a200141086a290000370000200141002802c0a3c680001180808080000002402004450d00200541002802c0a3c68000118080808000000b024020022802002200418080808078460d002000450d00200228020441002802c0a3c68000118080808000000b200341106a2480808080000b3a01017f23808080800041106b22022480808080002002200136020c20002002410c6a109680808000108784808000200241106a2480808080000bac0202017f017e23808080800041f0006b22052480808080002005200136020002400240200520022004ad4220862003ad841097808080002206422088a722010d002005420037020c200541b8a1c28000360208200541b8a1c280003602040c010b2005200136021c200520063e021820052001360214200541046a200541146a10bf808080000b200541d8006a41086a2201200541046a41086a2902003703002005200529020437035820054100360268200541146a200541d8006a10bd84808000200541e4006a200528025c2001280200200528025828020c11858080800000024020052d00144102470d0041c8a1c28000412e200541d8006a41f8a1c280004188a2c28000108981808000000b2000200541146a41c10010848e8080001a200541f0006a2480808080000b190020002002ad4220862001ad8420031098808080004101460be70101037f23808080800041106b220324808080800020032001360200200341046a200210b9848080002003280204210420002003200335020c42208620032802082205ad841099808080002201290000370000200041186a200141186a290000370000200041106a200141106a290000370000200041086a200141086a290000370000200141002802c0a3c680001180808080000002402004450d00200541002802c0a3c68000118080808000000b024020022802002200418080808078460d002000450d00200228020441002802c0a3c68000118080808000000b200341106a2480808080000b3a01017f23808080800041106b22022480808080002002200136020c20002002410c6a109a80808000108584808000200241106a2480808080000bac0202017f017e23808080800041f0006b22052480808080002005200136020002400240200520022004ad4220862003ad84109b808080002206422088a722010d002005420037020c200541b8a1c28000360208200541b8a1c280003602040c010b2005200136021c200520063e021820052001360214200541046a200541146a10bf808080000b200541d8006a41086a2201200541046a41086a2902003703002005200529020437035820054100360268200541146a200541d8006a10bd84808000200541e4006a200528025c2001280200200528025828020c11858080800000024020052d00144102470d0041c8a1c28000412e200541d8006a41f8a1c280004188a2c28000108981808000000b2000200541146a41c10010848e8080001a200541f0006a2480808080000b190020002002ad4220862001ad842003109c808080004101460bdd0203027f017e047f23808080800041306b220124808080800002400240200035020842208620002802042202ad84109d808080002203422088a722040d0020014200370210200141b8a1c2800036020c200141b8a1c280003602080c010b20012004360220200120033e021c20012004360218200141086a200141186a10bf808080000b200141186a41086a200141086a41086a2902002203370300200120012902083703184100210420014100360228200128021c210502402003a72206450d0020052d0000210720014101360228200741ff01712207450d004101410220074101461b21040b200141246a20052006200128021828020c1185808080000002402006450d0020044102460d0002402000280200450d00200241002802c0a3c68000118080808000000b200141306a24808080800020044100470f0b41c8a1c28000412e200141186a41f8a1c280004188a2c28000108981808000000bd60301077f23808080800041106b22022480808080000240024002400240024002402001280208220320012802102204470d00410121050c010b200441016a2206450d0120032006490d02200128020421072001200636021002400240024002400240200720046a2d000022084103710e0400020301000b20084102762108410021050c040b4101210520084104490d020c030b200241096a20083a000041012105200241013a000820022001360204200241003b010c0240200241046a2002410c6a410210b4848080000d0020022f010c2201410276210820014180024921050c030b0c020b200241096a20083a000041012105200241013a0008200220013602042002410036020c0240200241046a2002410c6a410410b4848080000d00200228020c220141027621082001418080044921050c020b0c010b200320066b4104490d00200441056a21052006417b4b0d03200520034b0d0420012005360210200720066a28000022084180808080044921050b2000200836020420002005360200200241106a2480808080000f0b417f20064190fbc08000109681808000000b200620034190fbc08000109581808000000b200620054190fbc08000109681808000000b200520034190fbc08000109581808000000bad0201037f20002d00042103200041003a0004024002400240024002400240024002402002450d00200341ff01710d010b41012103200028020022002802082204200028021022056b2002490d02200520026a22032005490d03200320044b0d042001200028020420056a200210848e8080001a200020033602100c010b2001200041056a2d00003a000041012103200028020022002802082204200028021022056b2002417f6a2202490d01200520026a22032005490d04200320044b0d05200141016a200028020420056a200210848e8080001a200020033602100b410021030b20030f0b200520034190fbc08000109681808000000b200320044190fbc08000109581808000000b200520034190fbc08000109681808000000b200320044190fbc08000109581808000000b950301037f0240200028020022022802002200413f4b0d00200041027421020240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a20023a00000f0b0240200041ffff004b0d002000410274410172210202402001280200200128020822006b41014b0d0020012000410210b182808000200128020821000b2001200041026a360208200128020420006a20023b00000f0b0240200041ffffffff034b0d002000410274410272210202402001280200200128020822006b41034b0d0020012000410410b182808000200128020821000b2001200041046a360208200128020420006a20023600000f0b02402001280200220320012802082200470d0020012000410110b18280800020012802002103200128020821000b2001280204220420006a41033a00002001200041016a2200360208200228020021020240200320006b41034b0d0020012000410410b18280800020012802042104200128020821000b2001200041046a360208200420006a20023600000b0e00200020012002109e808080000b25002000417f6a41ff01712002ad4220862001ad842004ad4220862003ad84109f808080000b5601027f23808080800041106b2200248080808000024010a080808000220141ff01714106490d0041f19fc2800041342000410f6a41a8a0c2800041a8a1c28000108981808000000b200041106a24808080800020010bbb0301057f23808080800041206b2202248080808000024002400240024002402001280200418080808078460d00024002402001280208220341056a2204450d002004417f4c0d044100210541002d00fca3c680001a200441002802c8a3c68000118180808000002206450d05200220063602102002200436020c0c010b20024100360214200242808080801037020c2002410c6a4100410110b18280800020022802102106200228021421050b200620056a41013a00002002200541016a36021420012802042104200220033602182002200241186a36021c2002411c6a2002410c6a10b5848080000240200228020c200228021422016b20034f0d002002410c6a2001200310b182808000200228021421010b200228021020016a2004200310848e8080001a2002200120036a3602140c010b41002d00fca3c680001a410141002802c8a3c68000118180808000002201450d03200220013602102002410136020c200141003a0000200241013602140b2000200229020c370200200041086a2002410c6a41086a280200360200200241206a2480808080000f0b10ae80808000000b4101200410b280808000000b4101410110b280808000000bec0101067f410221020240024002400240024002402001280208220320012802102204470d000c010b200441016a2205450d0120032005490d02200128020421062001200536021002400240200620046a2d00000e020001020b410021020c010b200320056b4104490d00200441056a21072005417b4b0d03200720034b0d0420012007360210200620056a2800002107410121020b20002007360204200020023602000f0b417f20054190fbc08000109681808000000b200520034190fbc08000109581808000000b200520074190fbc08000109681808000000b200720034190fbc08000109581808000000bef0101057f41022102024002400240024002402001280208220320012802102204460d00200441016a2205450d0120032005490d02200128020421062001200536021002400240200620046a2d00000e020001020b200041003a00000f0b200320056b41c100490d00200441c2006a2104200541be7f4b0d03200420034b0d042001200436021041012102200041016a200620056a41c10010848e8080001a0b200020023a00000f0b417f20054190fbc08000109681808000000b200520034190fbc08000109581808000000b200520044190fbc08000109681808000000b200420034190fbc08000109581808000000ba80301067f23808080800041106b2202248080808000024002400240024002400240024002402001280208220320012802102204460d00200441016a2205450d02200520034b0d032001280204210320012005360210024002400240200320046a2d00000e020102000b20004181808080783602000c030b20004180808080783602000c020b200241086a200110b38480800020022802080d0020012802082205200128021022036b200228020c2204490d000240024020040d00410121060c010b2004417f4c0d05200441002802c8a3c68000118180808000002206450d06200641002004108a8e8080001a0b200320046a22072003490d06200720054b0d072006200128020420036a200410848e8080002103200020043602002001200736021020002004ad4220862003ad843702040c010b20004181808080783602000b200241106a2480808080000f0b417f20054190fbc08000109681808000000b200520034190fbc08000109581808000000b10ae80808000000b4101200410b280808000000b200320074190fbc08000109681808000000b200720054190fbc08000109581808000000bda0201057f41022102024002400240024002402001280208220320012802102204460d00200441016a2205450d0120032005490d02200128020421062001200536021002400240200620046a2d00000e020001020b200041003a00000f0b200320056b41c000490d00200441c1006a2104200541bf7f4b0d03200420034b0d04200120043602102000200620056a2201290000370001200041096a200141086a290000370000200041116a200141106a290000370000200041196a200141186a290000370000200041216a200141206a290000370000200041296a200141286a290000370000200041316a200141306a290000370000200041396a200141386a290000370000410121020b200020023a00000f0b417f20054190fbc08000109681808000000b200520034190fbc08000109581808000000b200520044190fbc08000109681808000000b200420034190fbc08000109581808000000b0a00200010a1808080000b0a00200010a2808080000bb60202017f017e23808080800041306b2208248080808000024002402002ad4220862001ad842004ad4220862003ad842006ad4220862005ad84200710a3808080002209422088a722060d0020084200370210200841b8a1c2800036020c200841b8a1c280003602080c010b20082006360220200820093e021c20082006360218200841086a200841186a10bf808080000b200841186a41086a2205200841086a41086a29020037030020082008290208370318200841003602282008200841186a10ba848080002008280204210420082802002106200841246a200828021c2005280200200828021828020c11858080800000024020064102470d0041c8a1c28000412e200841186a41f8a1c280004188a2c28000108981808000000b2000200436020420002006360200200841306a2480808080000b26002001ad4220862000ad842003ad4220862002ad842005ad4220862004ad8410a4808080000b9a0303017f017e037f23808080800041206b2203248080808000200341086a20011088848080002000200329031820032903102204200328020822051b200210a5808080002202290000370000200041186a200241186a290000370000200041106a200241106a290000370000200041086a200241086a290000370000200241002802c0a3c680001180808080000002402005450d00200328020c450d002004a741002802c0a3c68000118080808000000b20012802042106024020012802082200450d002000410171210741002102024020004101460d002000417e7121052006210041002102034002402000280200450d00200041046a28020041002802c0a3c68000118080808000000b02402000410c6a280200450d00200041106a28020041002802c0a3c68000118080808000000b200041186a21002005200241026a2202470d000b0b2007450d0020062002410c6c6a2200280200450d00200028020441002802c0a3c68000118080808000000b02402001280200450d00200641002802c0a3c68000118080808000000b200341206a2480808080000b12002001ad4220862000ad8410a6808080000b12002001ad4220862000ad8410a7808080000bad0202017f017e23808080800041c0006b2203248080808000024002402002ad4220862001ad8410a8808080002204422088a722020d0020034200370214200341b8a1c28000360210200341b8a1c2800036020c0c010b20032002360230200320043e022c200320023602282003410c6a200341286a10bf808080000b200341286a41086a22022003410c6a41086a2902003703002003200329020c370328200341003602382003411c6a200341286a10bc84808000200341346a200328022c2002280200200328022828020c118580808000000240200328021c418180808078470d0041c8a1c28000412e200341286a41f8a1c280004188a2c28000108981808000000b2000200329021c370200200041086a2003411c6a41086a280200360200200341c0006a2480808080000b8103010c7f2380808080004180026b220224808080800020012802082203410774220441f8006e2105200128020022062107024020012802042208200128020c2209460d00200241f4016a220a41086a210b200621070340200120084180016a220c3602042008280270220d418080808078460d0120024180016a200841f00010848e8080001a200b200841fc006a280200360200200a20082902743702002002200d3602f001200241086a20024180016a10d0848080002007200241086a41f80010848e80800041f8006a2107200c2108200c2009470d000b0b200110cb8480800020062108024002402003450d00200621082004200541f8006c220c460d00024020040d00410821080c010b200c41002802c8a3c68000118180808000002208450d0120082006200c10848e8080001a200641002802c0a3c68000118080808000000b20002008360204200020053602002000200720066b41f8006e360208200110cc8480800020024180026a2480808080000f0b4108200c10b280808000000be70304077f017e057f017e200128020c220221032001280200220421050240200128020422062002460d002004210503402006220741386a21060240200728022c2208418080808078470d00200621030c020b200741106a29030021092007280224220a210302402007280228220b450d00200a200b410574220b6a210c200a210303402003280200450d01200341206a2103200b41606a220b0d000b200c21030b2007280220210b2007280218210c2007280204210d2007280200210e2007290330210f200520072903083703082005200f3703302005200836022c2005200a3602242005200c3602182005200d3602042005200e360200200541106a20093703002005200b41ffffff3f7136022020052003200a6b410576360228200541386a210520062002470d000b200221030b20012802082107200142888080808001370200200142808080808001370208200220036b41386e210b024020022003460d00200341306a210303400240200341706a280200450d00200341746a28020041002802c0a3c68000118080808000000b02402003417c6a280200450d00200328020041002802c0a3c68000118080808000000b200341386a2103200b417f6a220b0d000b0b200020043602042000200520046b41386e3602082000200741386c41386e3602000be704020a7f017e23808080800041c0006b220224808080800020012802082103200128020c220421052001280200220621070240200128020422082004460d002002411c6a210920062107024003402008220a280200220b418080808078460d01200241086a2205200a41146a2802003602002002200a29020c370300200a290218210c2002200a2802042208200a28020841386c6a36023c2002200b3602382002200836023420022008360230200241106a200241306a10c784808000200241106a41186a2208200c370300200941086a200528020036020020092002290300370200200741186a2008290300370200200741106a200241106a41106a290300370200200741086a200241106a41086a29030037020020072002290310370200200741206a2107200a41206a22082004470d000b0b200a41206a21050b20014284808080c00037020020014280808080c000370208024020042005460d00200420056b41057621044100210b034002402005200b4105746a22092802082208450d00200928020441306a210a03400240200a41706a280200450d00200a41746a28020041002802c0a3c68000118080808000000b0240200a417c6a280200450d00200a28020041002802c0a3c68000118080808000000b200a41386a210a2008417f6a22080d000b0b02402009280200450d00200928020441002802c0a3c68000118080808000000b0240200928020c450d002009410c6a28020441002802c0a3c68000118080808000000b200b41016a220b2004470d000b0b200020063602042000200341ffffff3f713602002000200720066b410576360208200241c0006a2480808080000bc503010b7f23808080800041e0016b220224808080800020012802082103200128020c220421052001280200220621070240200128020422082004460d00200241146a2109200241106a210a4100210502400340200620056a2107200820056a220b280200220c4102460d012009200b41046a41e40010848e8080001a2002200c3602102002200736020c20022006360208200241f8006a200a10d1848080002007200241f8006a41e80010848e8080001a200541e8006a2105200b41e8006a2004470d000b200620056a21070b200b41e8006a21050b200142888080808001370200200142808080808001370208200420056b41e8006e210b024020042005460d00034002402005280200450d00200541046a280200450d00200541086a28020041002802c0a3c68000118080808000000b0240200541c8006a280200450d00200541cc006a28020041002802c0a3c68000118080808000000b0240200541d4006a280200450d00200541d8006a28020041002802c0a3c68000118080808000000b200541e8006a2105200b417f6a220b0d000b0b200020063602042000200720066b41e8006e3602082000200341e8006c41e8006e360200200241e0016a2480808080000be00301067f024020002802082201450d00200028020421024100210303400240200220034107746a22042802502200418080808078460d00200441d0006a21050240200441d8006a2802002206450d00200441d4006a2802002100034002402000280200450d00200041046a280200450d00200041086a28020041002802c0a3c68000118080808000000b0240200041c8006a280200450d00200041cc006a28020041002802c0a3c68000118080808000000b0240200041d4006a280200450d00200041d8006a28020041002802c0a3c68000118080808000000b200041e8006a21002006417f6a22060d000b200528020021000b2000450d00200528020441002802c0a3c68000118080808000000b0240200441ec006a2802002206450d00200441e8006a28020041306a210003400240200041706a280200450d00200041746a28020041002802c0a3c68000118080808000000b02402000417c6a280200450d00200028020041002802c0a3c68000118080808000000b200041386a21002006417f6a22060d000b0b02402004280264450d00200441e4006a28020441002802c0a3c68000118080808000000b02402004280270450d00200441f0006a28020441002802c0a3c68000118080808000000b200341016a22032001470d000b0b0bfe0301067f200028020c210120004280808080800137020820002802042102200042888080808001370200024020012002460d00200120026b41077621034100210403400240200220044107746a22052802502200418080808078460d000240200541d0006a22062802082201450d0020062802042100034002402000280200450d00200041046a280200450d00200041086a28020041002802c0a3c68000118080808000000b0240200041c8006a280200450d00200041cc006a28020041002802c0a3c68000118080808000000b0240200041d4006a280200450d00200041d8006a28020041002802c0a3c68000118080808000000b200041e8006a21002001417f6a22010d000b200628020021000b2000450d00200628020441002802c0a3c68000118080808000000b0240200541ec006a2802002201450d00200541e8006a28020041306a210003400240200041706a280200450d00200041746a28020041002802c0a3c68000118080808000000b02402000417c6a280200450d00200028020041002802c0a3c68000118080808000000b200041386a21002001417f6a22010d000b0b0240200541e4006a2200280200450d00200028020441002802c0a3c68000118080808000000b02402005280270450d00200541f0006a28020441002802c0a3c68000118080808000000b200441016a22042003470d000b0b0b820401077f0240200028020c220120002802042202460d00200120026b41077621034100210403400240200220044107746a22052802502201418080808078460d000240200541d0006a22062802082207450d0020062802042101034002402001280200450d00200141046a280200450d00200141086a28020041002802c0a3c68000118080808000000b0240200141c8006a280200450d00200141cc006a28020041002802c0a3c68000118080808000000b0240200141d4006a280200450d00200141d8006a28020041002802c0a3c68000118080808000000b200141e8006a21012007417f6a22070d000b200628020021010b2001450d00200628020441002802c0a3c68000118080808000000b0240200541ec006a2802002207450d00200541e8006a28020041306a210103400240200141706a280200450d00200141746a28020041002802c0a3c68000118080808000000b02402001417c6a280200450d00200128020041002802c0a3c68000118080808000000b200141386a21012007417f6a22070d000b0b0240200541e4006a2201280200450d00200128020441002802c0a3c68000118080808000000b02402005280270450d00200541f0006a28020441002802c0a3c68000118080808000000b200441016a22042003470d000b0b02402000280208450d00200028020041002802c0a3c68000118080808000000b0baa070b057f017e017f027e017f027e0f7f017e017f017e037f23808080800041c0006b2202248080808000200141cc006a2802002103200128024821044180808080782105024020012802502206418080808078460d00200141dc006a29020021072002200141d4006a2802002208200141d8006a28020041e8006c6a36023c200220063602382002200836023420022008360230200241186a200241306a10c984808000200241106a20073703002002200229021c370308200228021821050b200141206a2903002109200141086a290300210a200141286a280200210b2001290318210c2001290300210d2001280264210e2001280210210f200141e8006a280200221021110240200141ec006a2802002206450d002010200641386c22126a2111200241306a41046a2108200241186a41046a21134100211402400340201020146a2206412c6a22152802002216418080808078460d01200641306a22172903002107200641046a22182802002119200641186a221a280200211b200641086a221c290300211d200641106a221e290300211f20062802002120200241186a41086a200641246a222129020037030020022006411c6a2222290200370318200841086a201341086a28020036020020082013290200370200201e201f370300201c201d370300201a201b3602002018201936020020062020360200202220022902303702002021200241306a41086a29020037020020152016360200201720073702002012201441386a2214470d000c020b0b0240201241486a2014460d00200641e8006a2108201220146b41486a41386e211403400240200841706a280200450d00200841746a28020041002802c0a3c68000118080808000000b02402008417c6a280200450d00200828020041002802c0a3c68000118080808000000b200841386a21082014417f6a22140d000b0b200621110b2000200d3703002000200c37031820002005360250200020043602482000200f3602102000200a370308200041206a200937030020002001290330370330200041e8006a201036020020002001290370370370200041cc006a2003360200200041d4006a2002290308370200200041286a200b360200200020012d007c3a007c200041386a200141386a290300370300200041ec006a201120106b41386e3602002000200e41386c41386e360264200041f8006a200141f8006a280200360200200041dc006a200241086a41086a290300370200200041c0006a200141c0006a280200360200200241c0006a2480808080000b870c03067f107e137f2380808080004190046b22032480808080000240024002400240200241726a0e020102000b2000418780808078360200200141e8016a10ca84808000024020012802e801450d00200141ec016a28020041002802c0a3c68000118080808000000b0240200141d8016a280200450d00200141dc016a28020041002802c0a3c68000118080808000000b200141f8016a28020021040240200141fc016a2802002205450d004100210603400240200420064105746a22072802082208450d00200728020441306a210203400240200241706a280200450d00200241746a28020041002802c0a3c68000118080808000000b02402002417c6a280200450d00200228020041002802c0a3c68000118080808000000b200241386a21022008417f6a22080d000b0b02402007280200450d00200728020441002802c0a3c68000118080808000000b0240200728020c450d002007410c6a28020441002802c0a3c68000118080808000000b200641016a22062005470d000b0b20012802f401450d02200441002802c0a3c68000118080808000000c020b2003200141800210848e80800022024194036a200210cf84808000200241868080807836029003200241edcad18b063602f003200020024190036a41e40010848e8080001a0c010b200141c8016a2903002109200141b0016a290300210a20014198016a290300210b20014180016a290300210c200141d0006a290300210d200141386a290300210e200141206a290300210f200141086a290300211020012903c001211120012903a80121122001290390012113200129037821142001290348211520012903302116200129031821172001290300211820012802fc01211920012802f801211a20012802f401211b20012d00e401211c20012802e001211d20012802dc01211e20012802d801211f20012802d001212020012802b801212120012802a001212220012802880121232001280258212420012802402125200128022821262001280210212720012802e8012128200320012802ec01220720012802f001220841077422046a222936029802200320283602940220032007360290022003200736028c022007210202402008450d00200341086a210541002108200341fc006a222a41086a212b024002400340200720086a220241f0006a2802002201418080808078460d012005200241f00010848e808000210620032007360200202b200241fc006a280200360200202a200241f4006a290200370200200320013602782003200236020420034190036a200610cd84808000200220034190036a41800110848e8080001a200420084180016a2208470d000b200720086a21020c010b20024180016a21290b20032029360290020b2003418c026a10cb848080002003202841ffffff0f713602800220032007360284022003200220076b410776360288022003418c026a10cc84808000201e21020240201d450d00201e201d41386c6a2107201d41386c2108201e210203402002280200450d01200241386a2102200841486a22080d000b200721020b200341d0006a2009370300200341386a200a370300200341206a200b370300200341e4006a201e360200200341d8006a2020360200200341c0006a2021360200200341286a2022360200200341e8006a2002201e6b41386e360200200320113703482003201237033020032013370318200320143703002003201c3a006c200320233602102003200c3703082003201f41386c41386e3602602003201b3602b0022003201a3602ac022003201a3602a8022003201a20194105746a3602b4022003419c026a200341a8026a10c884808000200341b8026a41386a200d370300200341b8026a41206a200e370300200341b8026a41c0006a2024360200200341b8026a41286a2025360200200320153703e802200320163703d0022003200f3703c002200320173703b802200320263602c8022003410036028c03200341003602840320034190036a20034180026a20032018201020272003419c026a200341b8026a20034184036a10e081808000200341edcad18b063602f003200020034190036a41e40010848e8080001a0b20034190046a2480808080000be40405027f017e037f017e037f23808080800041d0006b2202248080808000200220012802e8013602202002200141ec016a280200220336021c2002200336021820022003200141f0016a2802004107746a3602242002410c6a200241186a10c684808000200141e8006a2903002104200141e4016a2d00002105200141d8016a2802002106200141f0006a280200210720012903602108200141dc016a280200220921030240200141e0016a280200220a450d002009200a41386c220a6a210b2009210303402003280200450d01200341386a2103200a41486a220a0d000b200b21030b200241c4006a2009360200200241c8006a200320096b41386e36020020022008370328200220053a004c20022007360238200220043703302002200641386c41386e36024020002002410c6a200241286a2001290300200141086a290300200128021010ce81808000200141f8016a28020021050240200141fc016a2802002206450d004100210003400240200520004105746a2209280208220a450d00200928020441306a210303400240200341706a280200450d00200341746a28020041002802c0a3c68000118080808000000b02402003417c6a280200450d00200328020041002802c0a3c68000118080808000000b200341386a2103200a417f6a220a0d000b0b02402009280200450d00200928020441002802c0a3c68000118080808000000b0240200928020c450d002009410c6a28020441002802c0a3c68000118080808000000b200041016a22002006470d000b0b024020012802f401450d00200541002802c0a3c68000118080808000000b200241d0006a2480808080000bb2070b057f017e017f027e017f027e0f7f017e017f017e037f23808080800041c0006b2202248080808000200141cc006a2802002103200128024821044180808080782105024020012802502206418080808078460d00200141dc006a29020021072002200141d4006a2802002208200141d8006a28020041e8006c6a36023c200220063602382002200836023420022008360230200241186a200241306a10c984808000200241106a20073703002002200229021c370308200228021821050b200141206a2903002109200141086a290300210a200141286a280200210b2001290318210c2001290300210d2001280264210e2001280210210f200141e8006a280200221021110240200141ec006a2802002206450d002010200641386c22126a2111200241306a41046a2108200241186a41046a21134100211402400340201020146a2206412c6a22152802002216418080808078460d01200641306a22172903002107200641046a22182802002119200641186a221a280200211b200641086a221c290300211d200641106a221e290300211f20062802002120200241186a41086a200641246a222129020037030020022006411c6a2222290200370318200841086a201341086a28020036020020082013290200370200201e201f370300201c201d370300201a201b3602002018201936020020062020360200202220022902303702002021200241306a41086a29020037020020152016360200201720073702002012201441386a2214470d000c020b0b0240201241486a2014460d00200641e8006a2108201220146b41486a41386e211403400240200841706a280200450d00200841746a28020041002802c0a3c68000118080808000000b02402008417c6a280200450d00200828020041002802c0a3c68000118080808000000b200841386a21082014417f6a22140d000b0b200621110b2000200c3703182000200d37030020002005360250200020043602482000200f36021020002001290330370330200041206a20093703002000200a370308200041e8006a2010360200200041cc006a2003360200200041d4006a2002290308370200200020012d007c3a0070200041286a200b360200200041386a200141386a290300370300200041ec006a201120106b41386e3602002000200e41386c41386e360264200041dc006a200241086a41086a290300370200200041c0006a200141c0006a28020036020002402001280270450d00200141f4006a28020041002802c0a3c68000118080808000000b200241c0006a2480808080000bb80205067f017e027f017e027f200141c4006a280200210220012d00602103200128024021040240024020012802000d00200141186a280200210520012802082106410021070c010b200141306a2903002108200141086a2802002106200141386a2802002109200141206a280200210a2001290328210b200128021c210c200128021821052001280204210d410121070b2000200b370328200020033a006020002004360240200020093602382000200a3602202000200c36021c20002005360218200020063602082000200d36020420002007360200200041306a20083703002000200129034837034820002001290254370254200041c4006a2002360200200020012903103703102000200128020c36020c200041d0006a200141d0006a280200360200200041dc006a200141dc006a2802003602000bbe0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010e1848080002004280208200428020c220541386c6a2206420437022c200642123702242006418ba5c2800036022020064100360218200641bc81808000360210200642c9a784c5fedbb0fa25370308200642efa8a2ace59194fdb37f37030020042802042107200428020821080240200128020822062001280200470d002001200610e084808000200128020821060b2001280204200641246c6a220641003a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bbe0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010e1848080002004280208200428020c220541386c6a2206420437022c20064202370224200641e0a4c2800036022020064100360218200641c880808000360210200642e6ed8d82cc91adcb05370308200642dbd791d5c2919eaecd0037030020042802042107200428020821080240200128020822062001280200470d002001200610e084808000200128020821060b2001280204200641246c6a220641073a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bdc0303037f017e027f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010e18480800020042802182005280200220641386c6a2205420437022c20054211370224200541b0a4c2800036022020054100360218200541bd81808000360210200542d886fac2c186f9c46f3703082005429cfcf2b9cfebc9bfa37f370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610e184808000200428021021060b200428020c200641386c6a2205420437022c20054207370224200541c1a4c2800036022020054100360218200541be81808000360210200542b891b68c98adebcf61370308200542e7b0a091f3ed9c85c50037030020042802082108200428020c21090240200128020822052001280200470d002001200510e084808000200128020821050b2001280204200541246c6a220541053a00202005200336021c200520023602182005410036021420054280808080c00037020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000bbd0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010e1848080002004280208200428020c220541386c6a2206420437022c2006420b370224200641e7a4c2800036022020064100360218200641bf81808000360210200642878ff9fb82dfe1a82a370308200642949ecee4d5a9a0866437030020042802042107200428020821080240200128020822062001280200470d002001200610e084808000200128020821060b2001280204200641246c6a220641033a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bbe0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010e1848080002004280208200428020c220541386c6a2206420437022c20064207370224200641c1a4c2800036022020064100360218200641be81808000360210200642b891b68c98adebcf61370308200642e7b0a091f3ed9c85c50037030020042802042107200428020821080240200128020822062001280200470d002001200610e084808000200128020821060b2001280204200641246c6a220641003a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bbf0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010e1848080002004280208200428020c220541386c6a2206420437022c2006420a370224200641f2a4c2800036022020064100360218200641c0818080003602102006428d999faad5ccf2dbca00370308200642a7cde9f3c9fe9ebfe30037030020042802042107200428020821080240200128020822062001280200470d002001200610e084808000200128020821060b2001280204200641246c6a220641073a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bbd0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010e1848080002004280208200428020c220541386c6a2206420437022c200642123702242006419da5c2800036022020064100360218200641c18180800036021020064283e8c09cb8d3f4c01f370308200642dcffb3b186d2b1f50637030020042802042107200428020821080240200128020822062001280200470d002001200610e084808000200128020821060b2001280204200641246c6a220641013a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bdc0303037f017e027f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010e18480800020042802182005280200220641386c6a2205420437022c20054211370224200541b0a4c2800036022020054100360218200541bd81808000360210200542d886fac2c186f9c46f3703082005429cfcf2b9cfebc9bfa37f370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610e184808000200428021021060b200428020c200641386c6a2205420437022c20054207370224200541c1a4c2800036022020054100360218200541be81808000360210200542b891b68c98adebcf61370308200542e7b0a091f3ed9c85c50037030020042802082108200428020c21090240200128020822052001280200470d002001200510e084808000200128020821050b2001280204200541246c6a220541063a00202005200336021c200520023602182005410036021420054280808080c00037020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000bbe0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010e1848080002004280208200428020c220541386c6a2206420437022c2006420f370224200641fca4c2800036022020064100360218200641c281808000360210200642f68af3a9c7b285af3c37030820064296b2f4978ff1ee81bf7f37030020042802042107200428020821080240200128020822062001280200470d002001200610e084808000200128020821060b2001280204200641246c6a220641083a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bbe0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010e1848080002004280208200428020c220541386c6a2206420437022c20064202370224200641e0a4c2800036022020064100360218200641c880808000360210200642e6ed8d82cc91adcb05370308200642dbd791d5c2919eaecd0037030020042802042107200428020821080240200128020822062001280200470d002001200610e084808000200128020821060b2001280204200641246c6a220641023a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bbf0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010e1848080002004280208200428020c220541386c6a2206420437022c20064212370224200641baa6c2800036022020064100360218200641c381808000360210200642c69182ab97bfe490ac7f37030820064286a3ebac9a8ef1cfee0037030020042802042107200428020821080240200128020822062001280200470d002001200610e084808000200128020821060b2001280204200641246c6a220641093a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bdc0303037f017e027f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010e18480800020042802182005280200220641386c6a2205420437022c20054211370224200541b0a4c2800036022020054100360218200541bd81808000360210200542d886fac2c186f9c46f3703082005429cfcf2b9cfebc9bfa37f370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610e184808000200428021021060b200428020c200641386c6a2205420437022c20054207370224200541c1a4c2800036022020054100360218200541be81808000360210200542b891b68c98adebcf61370308200542e7b0a091f3ed9c85c50037030020042802082108200428020c21090240200128020822052001280200470d002001200510e084808000200128020821050b2001280204200541246c6a220541043a00202005200336021c200520023602182005410036021420054280808080c00037020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141146c2104200141e7cc99334941027421050240024020030d00200241003602180c010b200241043602182002200341146c36021c200220002802043602140b200241086a20052004200241146a10de84808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141246c2104200141e4f1b81c4941027421050240024020030d00200241003602180c010b200241043602182002200341246c36021c200220002802043602140b200241086a20052004200241146a10de84808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141386c210420014193c9a4124941037421050240024020030d00200241003602180c010b200241083602182002200341386c36021c200220002802043602140b200241086a20052004200241146a10de84808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bf00101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b2202410c6c2104200241abd5aad5004941027421050240024020010d00200341003602180c010b2003410436021820032001410c6c36021c200320002802043602140b200341086a20052004200341146a10de84808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b220241246c2104200241e4f1b81c4941027421050240024020010d00200341003602180c010b200341043602182003200141246c36021c200320002802043602140b200341086a20052004200341146a10de84808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b220241386c210420024193c9a4124941037421050240024020010d00200341003602180c010b200341083602182003200141386c36021c200320002802043602140b200341086a20052004200341146a10de84808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b22024105742104200241808080204941037421050240024020010d00200341003602180c010b200341083602182003200141057436021c200320002802043602140b200341086a20052004200341146a10de84808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000b810201037f23808080800041206b22032480808080000240024002400240200241046a22040d00410121050c010b2004417f4c0d0141002d00fca3c680001a200441002802c8a3c68000118180808000002205450d020b20034100360214200320053602102003200436020c200320023602182003200341186a36021c2003411c6a2003410c6a10fb848080000240200328020c200328021422046b20024f0d002003410c6a2004200210b182808000200328021421040b200328021020046a2001200210848e8080001a200041086a200420026a3602002000200329020c370200200341206a2480808080000f0b10ae80808000000b4101200410b280808000000b70002000428ca3c7fa85a49cf2a17f37030820004280808080c00037033820004280808080c000370350200041c481808000360218200041023a0000200041106a42e0f4e1e1b7dafaaf8d7f370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6f00200042dbd791d5c2919eaecd0037030820004280808080c00037033820004280808080c000370350200041c880808000360218200041023a0000200041106a42e6ed8d82cc91adcb05370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6f00200042e7b0a091f3ed9c85c50037030820004280808080c00037033820004280808080c000370350200041be81808000360218200041023a0000200041106a42b891b68c98adebcf61370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b220641246e2207200128020822014101764f0d01410021082002410036020c20024280808080c00037020441042109024020052004460d00200241046a4100200710e38480800020022802082109200228020c21080b2009200841246c6a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b41246e2107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b220641386e2207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710e48480800020022802082109200228020c21080b2009200841386c6a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b41386e2107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b22064105762207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710e58480800020022802082109200228020c21080b200920084105746a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b4105762107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bf80701047f23808080800041206b220224808080800020024100360214200242808080801037020c02400240024002400240024020012802000e050001020304000b2001410c6a280200210320012802082104200128020421052002410c6a4100410110b1828080002002280210200228021422016a41063a00002002200141016a22013602140240200228020c20016b41034b0d002002410c6a2001410410b182808000200228021421010b200228021020016a20052800003600002002200141046a360214200220033602182002200241186a36021c2002411c6a2002410c6a10fb848080000240200228020c200228021422016b20034f0d002002410c6a2001200310b182808000200228021421010b200228021020016a2004200310848e8080001a200120036a21010c040b2001410c6a280200210320012802082104200128020421052002410c6a4100410110b1828080002002280210200228021422016a41043a00002002200141016a22013602140240200228020c20016b41034b0d002002410c6a2001410410b182808000200228021421010b200228021020016a20052800003600002002200141046a360214200220033602182002200241186a36021c2002411c6a2002410c6a10fb848080000240200228020c200228021422016b20034f0d002002410c6a2001200310b182808000200228021421010b200228021020016a2004200310848e8080001a200120036a21010c030b2001410c6a280200210320012802082104200128020421052002410c6a4100410110b1828080002002280210200228021422016a41053a00002002200141016a22013602140240200228020c20016b41034b0d002002410c6a2001410410b182808000200228021421010b200228021020016a20052800003600002002200141046a360214200220033602182002200241186a36021c2002411c6a2002410c6a10fb848080000240200228020c200228021422016b20034f0d002002410c6a2001200310b182808000200228021421010b200228021020016a2004200310848e8080001a200120036a21010c020b200141086a2802002103200128020421042002410c6a4100410110b1828080002002280210200228021422016a41003a00002002200141016a360214200220033602182002200241186a36021c2002411c6a2002410c6a10fb848080000240200228020c200228021422016b20034f0d002002410c6a2001200310b182808000200228021421010b200228021020016a2004200310848e8080001a200120036a21010c010b2002410c6a4100410110b1828080002002280210200228021422016a41083a0000200141016a21010b2000200229020c370200200041086a2001360200200241206a2480808080000bbc0402037f017e23808080800041c0006b2201248080808000200141186a41cca6c28000410a41d6a6c28000411b10d682808000200141146a410036020020014280808080c00037020c2001410036023820014280808080c000370230200141246a200141306a41f1a6c28000410a10d984808000200141306a200141246a41fba6c28000410910dd84808000200141246a200141306a4184a7c28000410410d484808000200141306a200141246a4188a7c28000410510d6848080000240200128023822022001280230470d00200141306a200210e084808000200128023821020b2001280234200241246c6a220241083a00202002411936021c2002418da7c2800036021820024204370210200242003702082002428080808080013702002001280238210320012802342102200120012802303602382001200236023020012002200341246c6a41246a36023c20012002360234200141246a200141306a10ea84808000024020012802182202418080808078470d0041afa3c28000411141a0a4c2800010a181808000000b2001411c6a2902002104200142888080808001370230200142808080808001370238200041c4006a200141306a10ec848080002001413b6a200141246a41086a2802003600002000413c6a200437020020002002360238200041013a000020002001410c6a2202290200370250200041d8006a200241086a2802003602002001200129022437003320002001290030370001200041086a200141376a290000370000200141c0006a2480808080000bdd0701047f23808080800041206b2202248080808000024002400240024002400240024020002d0000220320012d00002204470d000240024002400240024020030e04000102030b0b20030d0a20002800012001280001460d0341a6a7c2800041144100280280a3c68000118480808000000c080b20034101470d09024020002800012001280001460d0041a6a7c2800041144100280280a3c68000118480808000000c070b0240200041106a2802002203200141106a280200470d002000410c6a2802002001410c6a280200200310888e808000450d0a0b41a6a7c2800041144100280280a3c68000118480808000000c060b20034102470d08024020002800012001280001460d0041a6a7c2800041144100280280a3c68000118480808000000c050b0240200041106a2802002203200141106a280200470d002000410c6a2802002001410c6a280200200310888e808000450d090b41a6a7c2800041144100280280a3c68000118480808000000c040b20034103470d07200041086a280200210302402000410c6a28020022052001410c6a280200470d002003200141086a280200200510888e808000450d080b41a6a7c2800041144100280280a3c68000118480808000000c020b0240200041106a2802002203200141106a280200470d002000410c6a2802002001410c6a280200200310888e808000450d070b41a6a7c2800041144100280280a3c68000118480808000000c040b41a6a7c2800041144100280280a3c6800011848080800000024020030e050403020005040b2000410c6a2802002105200041086a28020021030b200241186a200536020020022003360214410321030c030b2002200041016a36021420022000410c6a290200370218410221030c020b410121032002200041016a36021420022000410c6a2902003702180c010b2002200041016a36021420022000410c6a290200370218410021030b20022003360210200241046a200241106a10ed8480800020022802082203200228020c41002802f8a2c680001184808080000002402002280204450d00200341002802c0a3c68000118080808000000b0240024002400240024020040e050001020304000b2002200141016a36021420022001410c6a2902003702180c030b2002200141016a36021420022001410c6a2902003702180c020b2002200141016a36021420022001410c6a2902003702180c010b2002200141086a2902003702140b20022004360210200241046a200241106a10ed8480800020022802082203200228020c41002802f8a2c68000118480808000002002280204450d00200341002802c0a3c68000118080808000000b200241206a2480808080000bd40403057f017e037f23808080800041d0006b2201248080808000200141286a41baa7c28000410641d6a6c28000411b41cca6c28000410010d882808000200141206a420437020020014200370218200142808080808001370210200142888080808001370240200142808080808001370248200141106a200141c0006a10ec84808000200141086a2202200141246a2802003602002001200129021c370300200128021021032001280214210420012802182105200129022c21062001280228210720014100360218200142808080808001370210200141106a410010e1848080002001280214200128021841386c6a2208420437022c2008420f370224200841cca4c280003602202008410436021c200841c8a4c28000360218200841c581808000360210200842dfbeb7dcc08ee1ef70370308200842d1c6e9d6b09296e819370300200128021821092001280214210820012001280210360248200120083602402001200836024420012008200941386c6a41386a36024c200141346a200141c0006a10eb8480800002402007418080808078470d0041afa3c28000411141a0a4c2800010a181808000000b2001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10ec848080002001411b6a200141346a41086a2802003600002000413c6a200637020020002007360238200041003a000020002001290300370350200041d8006a20022802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000b7600200042dbd791d5c2919eaecd0037030820004280808080c00037033820004280808080c00037035020004104360220200041c880808000360218200041033a0000200041106a42e6ed8d82cc91adcb05370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b1a002001280214200141186a280200200028020010d9808080000bbd0201027f23808080800041106b22022480808080002002410036020c02400240024002402001418001490d002001418010490d012001418080044f0d0220022001413f71418001723a000e20022001410c7641e001723a000c20022001410676413f71418001723a000d410321010c030b200220013a000c410121010c020b20022001413f71418001723a000d2002200141067641c001723a000c410221010c010b20022001413f71418001723a000f20022001410676413f71418001723a000e20022001410c76413f71418001723a000d2002200141127641077141f001723a000c410421010b02402000280200200028020822036b20014f0d00200020032001109c85808000200028020821030b200028020420036a2002410c6a200110848e8080001a2000200320016a360208200241106a24808080800041000b1200200041c0a7c28000200110d9808080000b220002402000280200450d00200028020441002802c0a3c68000118080808000000b0b02000b040041010bda0101017f23808080800041306b2202248080808000200242808080801037020020024100360208200241186a420137020020024101360210200241f0a7c2800036020c200241c68180800036022820022001412c6a36022c2002200241246a36021420022002412c6a360224200241c0a7c280002002410c6a10d9808080001a2001280220200141246a280200200141286a2802002002280204200228020841002802d0a2c680001187808080000002402002280200450d00200228020441002802c0a3c68000118080808000000b200241306a2480808080000b02000b7c01017f23808080800041106b2201248080808000200142888080808001370200200142808080808001370208200041c4006a200110c182808000200041c0006a410036020020004280808080c000370338200041d8006a410036020020004280808080c00037035020004185043b0100200141106a2480808080000b950301037f0240200028020022022802002200413f4b0d00200041027421020240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a20023a00000f0b0240200041ffff004b0d002000410274410172210202402001280200200128020822006b41014b0d0020012000410210b182808000200128020821000b2001200041026a360208200128020420006a20023b00000f0b0240200041ffffffff034b0d002000410274410272210202402001280200200128020822006b41034b0d0020012000410410b182808000200128020821000b2001200041046a360208200128020420006a20023600000f0b02402001280200220320012802082200470d0020012000410110b18280800020012802002103200128020821000b2001280204220420006a41033a00002001200041016a2200360208200228020021020240200320006b41034b0d0020012000410410b18280800020012802042104200128020821000b2001200041046a360208200420006a20023600000b7601017f20014180feff077141087621020240024020014101710d002002411874411875410274220241d0afc280006a2101200241a4afc280006a21020c010b200241187441187541027422024188b0c280006a2101200241fcafc280006a21020b20002001280200360204200020022802003602000ba90303027f027e037f200141106a2103200241146a2802002104200229030021052001290300210602402001280210200141186a28020022076b200241186a28020022084f0d0020032007200810e284808000200128021821070b200141146a2802002007410c6c6a20042008410c6c10848e8080001a2001200720086a3602182002410036021820002003290300370310200041186a200341086a2802003602002001411c6a2103200241206a28020021090240200128021c200141246a28020022076b200241246a28020022084f0d0020032007200810e284808000200128022421070b200141206a2802002007410c6c6a20092008410c6c10848e8080001a2001200720086a360224200241003602242000427f200620057c220520052006541b3703002000200329020037021c200041246a200341086a280200360200200020012d002841004720022d0028410047713a00282000200129030822062002290308220520062005541b37030802402002280210450d00200441002802c0a3c68000118080808000000b0240200228021c450d00200941002802c0a3c68000118080808000000b0be60d04057f017e037f017e23808080800041d0006b2201248080808000200141306a4181adc2800041124193adc2800041204188a8c28000410010d882808000200141286a420437020020014200370220200142808080808001370218200142888080808001370240200142808080808001370248200141186a200141c0006a10ec84808000200141086a41086a2001412c6a2802003602002001200129022437030820012802182102200128021c2103200128022021042001280230210520012902342106200141186a41086a2207410036020020014280808080c000370218200141186a410010e084808000200128021c200728020041246c6a220841003a00202008410436021c200841b3adc280003602182008420437021020084200370208200842808080808001370200200141c0006a41086a2209200728020041016a220836020020012001290218220a37034002402008200aa7470d00200141c0006a200810e084808000200128024821080b2001280244200841246c6a220841013a00202008410736021c200841b7adc2800036021820084204370210200842003702082008428080808080013702002007200928020041016a220836020020012001290340220a37031802402008200aa7470d00200141186a200810e084808000200128022021080b200128021c200841246c6a220841023a00202008410636021c200841beadc280003602182008420437021020084200370208200842808080808001370200200141c0006a41086a2207200141186a41086a220928020041016a220836020020012001290318220a37034002402008200aa7470d00200141c0006a200810e084808000200128024821080b2001280244200841246c6a220841033a00202008410536021c200841c4adc2800036021820084204370210200842003702082008428080808080013702002009200728020041016a220836020020012001290340220a37031802402008200aa7470d00200141186a200810e084808000200128022021080b200128021c200841246c6a220841043a00202008410836021c200841c9adc280003602182008420437021020084200370208200842808080808001370200200141c0006a41086a2207200141186a41086a220928020041016a220836020020012001290318220a37034002402008200aa7470d00200141c0006a200810e084808000200128024821080b2001280244200841246c6a220841053a00202008411136021c200841d1adc2800036021820084204370210200842003702082008428080808080013702002009200728020041016a220836020020012001290340220a37031802402008200aa7470d00200141186a200810e084808000200128022021080b200128021c200841246c6a220841063a00202008411136021c200841e2adc280003602182008420437021020084200370208200842808080808001370200200141c0006a41086a2207200141186a41086a220928020041016a36020020012001290318370340200141186a200141c0006a41f3adc28000410610d3848080000240200128022022082001280218470d00200141186a200810e084808000200128022021080b200128021c200841246c6a220841083a00202008410c36021c200841f9adc2800036021820084204370210200842003702082008428080808080013702002007200928020041016a220836020020012001290218220a37034002402008200aa7470d00200141c0006a200810e084808000200128024821080b2001280244200841246c6a220841093a00202008411336021c20084185aec280003602182008420437021020084200370208200842808080808001370200200141186a41086a200141c0006a41086a28020041016a220836020020012001290340220a37031802402008200aa7470d00200141186a200810e084808000200128022021080b200128021c200841246c6a2208410a3a00202008410936021c20084198aec28000360218200842043702102008420037020820084280808080800137020020012802202107200128021c2108200120012802183602202001200836021820012008200741246c6a41246a3602242001200836021c200141c0006a200141186a10ea8480800002402005418080808078470d0041afa3c28000411141a0a4c2800010a181808000000b20012002360220200120033602182001200336021c2001200320044105746a360224200041c4006a200141186a10ec84808000200141236a200141c0006a41086a2802003600002000413c6a200637020020002005360238200041013a000020002001290308370350200041d8006a200141086a41086a2802003602002001200129024037001b20002001290018370001200041086a2001411f6a290000370000200141d0006a2480808080000be70504057f017e037f017e23808080800041d0006b2201248080808000200141286a41a1aec2800041124193adc2800041204188a8c28000410010d882808000200141206a420437020020014200370218200142808080808001370210200142888080808001370240200142808080808001370248200141106a200141c0006a10ec84808000200141086a200141246a2802003602002001200129021c37030020012802102102200128021421032001280218210420012802282105200129022c2106200141106a41086a2207410036020020014280808080c000370210200141106a410010e0848080002001280214200728020041246c6a220841003a00202008410c36021c200841f5acc280003602182008420437021020084200370208200842808080808001370200200141c0006a41086a2209200728020041016a220836020020012001290210220a37034002402008200aa7470d00200141c0006a200810e084808000200128024821080b2001280244200841246c6a220841013a00202008411336021c200841b3aec2800036021820084204370210200842003702082008428080808080013702002007200928020041016a36020020012001290340370310200141346a200141106a41f3adc28000410610db848080002001200128023436021820012001280238220836021020012008200128023c41246c6a36021c20012008360214200141c0006a200141106a10ea8480800002402005418080808078470d0041afa3c28000411141a0a4c2800010a181808000000b2001200236021820012003360210200120033602142001200320044105746a36021c200041c4006a200141106a10ec848080002001411b6a200141c0006a41086a2802003600002000413c6a200637020020002005360238200041013a000020002001290300370350200041d8006a200141086a2802003602002001200129024037001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000b950403057f017e027f23808080800041d0006b2201248080808000200141106a41186a41c6aec2800041184193adc2800041204188a8c28000410010d882808000200141206a420437020020014200370218200142808080808001370210200142888080808001370240200142808080808001370248200141106a200141c0006a10ec84808000200141086a2202200141246a2802003602002001200129021c370300200128021021032001280214210420012802182105200129022c2106200128022821072001410036021820014280808080c000370210200141c0006a200141106a41deaec28000410710d284808000200141346a200141c0006a41e5aec28000410710d8848080002001200128023436021820012001280238220836021020012008200128023c41246c6a36021c20012008360214200141c0006a200141106a10ea8480800002402007418080808078470d0041afa3c28000411141a0a4c2800010a181808000000b2001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10ec848080002001411b6a200141c0006a41086a2802003600002000413c6a200637020020002007360238200041013a000020002001290300370350200041d8006a20022802003602002001200129024037001320002001290010370001200041086a200141106a41076a290000370000200141d0006a2480808080000bbf0604057f017e037f017e23808080800041d0006b2201248080808000200141306a41ecaec2800041114193adc2800041204188a8c28000410010d882808000200141286a420437020020014200370220200142808080808001370218200142888080808001370240200142808080808001370248200141186a200141c0006a10ec84808000200141086a41086a2001412c6a2802003602002001200129022437030820012802182102200128021c2103200128022021042001280230210520012902342106200141186a41086a2207410036020020014280808080c000370218200141186a410010e084808000200128021c200728020041246c6a220841003a00202008410736021c200841fdaec280003602182008420437021020084200370208200842808080808001370200200141c0006a41086a2209200728020041016a220836020020012001290218220a37034002402008200aa7470d00200141c0006a200810e084808000200128024821080b2001280244200841246c6a220841013a00202008410536021c20084184afc2800036021820084204370210200842003702082008428080808080013702002007200928020041016a220836020020012001290340220a37031802402008200aa7470d00200141186a200810e084808000200128022021080b200128021c200841246c6a220841023a00202008410836021c20084189afc28000360218200842043702102008420037020820084280808080800137020020012802202107200128021c2108200120012802183602202001200836021820012008200741246c6a41246a3602242001200836021c200141c0006a200141186a10ea8480800002402005418080808078470d0041afa3c28000411141a0a4c2800010a181808000000b20012002360220200120033602182001200336021c2001200320044105746a360224200041c4006a200141186a10ec84808000200141236a200141c0006a41086a2802003600002000413c6a200637020020002005360238200041013a000020002001290308370350200041d8006a200141086a41086a2802003602002001200129024037001b20002001290018370001200041086a2001411f6a290000370000200141d0006a2480808080000be70904057f017e037f017e23808080800041d0006b2201248080808000200141286a4191afc2800041104193adc2800041204188a8c28000410010d882808000200141106a41106a420437020020014200370218200142808080808001370210200142888080808001370240200142808080808001370248200141106a200141c0006a10ec84808000200141086a200141246a2802003602002001200129021c37030020012802102102200128021421032001280218210420012802282105200129022c2106200141106a41086a22074100360200200142808080808001370210200141106a410010e1848080002001280214200728020041386c6a2208420437022c20084213370224200841b7a5c280003602202008410836021c200841afa5c28000360218200841ef8080800036021020084293888c8f89fdc6ec9e7f370308200842a5e9e3ab9e929adc2c370300200141c0006a41086a2209200728020041016a220836020020012001290210220a37034002402008200aa7470d00200141c0006a200810e184808000200128024821080b2001280244200841386c6a2208420437022c20084213370224200841d2a5c280003602202008410836021c200841caa5c28000360218200841cf81808000360210200842aac2d79da4bfd9a04e370308200842e6afce95f6a1ffa6c3003703002007200928020041016a220836020020012001290340220a37031002402008200aa7470d00200141106a200810e184808000200128021821080b2001280214200841386c6a2208420437022c20084213370224200841d2a5c280003602202008410836021c200841e5a5c28000360218200841cf81808000360210200842aac2d79da4bfd9a04e370308200842e6afce95f6a1ffa6c300370300200141c0006a41086a2207200141106a41086a220928020041016a220836020020012001290310220a37034002402008200aa7470d00200141c0006a200810e184808000200128024821080b2001280244200841386c6a2208420437022c20084214370224200841f6a5c280003602202008410936021c200841eda5c28000360218200841ef8080800036021020084293888c8f89fdc6ec9e7f370308200842a5e9e3ab9e929adc2c3703002009200728020041016a220836020020012001290340220a37031002402008200aa7470d00200141106a200810e184808000200128021821080b2001280214200841386c6a2208420437022c2008420437022420084193a6c280003602202008410936021c2008418aa6c28000360218200841888180800036021020084298848fa1dab08ba174370308200842febac4ad81b6fafcb37f370300200128021821072001280214210820012001280210360248200120083602402001200836024420012008200741386c6a41386a36024c200141346a200141c0006a10eb8480800002402005418080808078470d0041afa3c28000411141a0a4c2800010a181808000000b2001200236021820012003360210200120033602142001200320044105746a36021c200041c4006a200141106a10ec848080002001411b6a200141346a41086a2802003600002000413c6a200637020020002005360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000b820604057f017e027f017e23808080800041d0006b2201248080808000200141286a41abb0c28000410b41a1b0c28000410a4194b0c28000410010d882808000200141206a420437020020014200370218200142808080808001370210200142888080808001370240200142808080808001370248200141106a200141c0006a10ec84808000200141086a200141246a2802003602002001200129021c37030020012802102102200128021421032001280218210420012802282105200129022c2106200141106a41086a22074100360200200142808080808001370210200141106a410010e1848080002001280214200728020041386c6a2208420437022c20084202370224200841e0a4c280003602202008410536021c200841dba4c28000360218200841c880808000360210200842e6ed8d82cc91adcb05370308200842dbd791d5c2919eaecd00370300200141c0006a41086a200728020041016a2208360200200120012902102209370340024020082009a7470d00200141c0006a200810e184808000200128024821080b2001280244200841386c6a2208420437022c2008422337022420084197a6c280003602202008410536021c200841e2a4c28000360218200841bd81808000360210200842d886fac2c186f9c46f3703082008429cfcf2b9cfebc9bfa37f370300200128024821072001280244210820012001280240360248200120083602402001200836024420012008200741386c6a41386a36024c200141346a200141c0006a10eb8480800002402005418080808078470d0041afa3c28000411141a0a4c2800010a181808000000b2001200236021820012003360210200120033602142001200320044105746a36021c200041c4006a200141106a10ec848080002001411b6a200141346a41086a2802003600002000413c6a200637020020002005360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000bbd0504057f017e027f017e23808080800041c0006b2201248080808000200141246a41b6b0c28000411241a1b0c28000410a4194b0c28000410010d8828080002001411c6a42043702002001420037021420014280808080800137020c2001428880808080013702302001428080808080013702382001410c6a200141306a10ec84808000200141086a200141206a28020036020020012001290218370300200128020c2102200128021021032001280214210420012802242105200129022821062001410c6a41086a2207410036020020014280808080c00037020c2001410c6a410010e0848080002001280210200728020041246c6a220841003a00202008410c36021c200841c8b0c280003602182008420437021020084200370208200842808080808001370200200141306a41086a200728020041016a22083602002001200129020c2209370330024020082009a7470d00200141306a200810e084808000200128023821080b2001280234200841246c6a220841013a00202008410736021c200841d4b0c2800036021820084204370210200842003702082008428080808080013702002001280238210720012802342108200120012802303602142001200836020c20012008200741246c6a41246a36021820012008360210200141306a2001410c6a10ea8480800002402005418080808078470d0041afa3c28000411141a0a4c2800010a181808000000b200120023602142001200336020c200120033602102001200320044105746a360218200041c4006a2001410c6a10ec84808000200141176a200141306a41086a2802003600002000413c6a200637020020002005360238200041013a000020002001290300370350200041d8006a200141086a2802003602002001200129023037000f2000200129000c370001200041086a2001410c6a41076a290000370000200141c0006a2480808080000bb40e04057f017e037f017e23808080800041d0006b2201248080808000200141306a4194b0c28000410d41a1b0c28000410a4194b0c28000410010d882808000200141286a420437020020014200370220200142808080808001370218200142888080808001370240200142808080808001370248200141186a200141c0006a10ec84808000200141086a41086a2001412c6a2802003602002001200129022437030820012802182102200128021c2103200128022021042001280230210520012902342106200141186a41086a2207410036020020014280808080c000370218200141186a410010e084808000200128021c200728020041246c6a220841003a00202008410536021c200841dbb0c280003602182008420437021020084200370208200842808080808001370200200141c0006a41086a2209200728020041016a220836020020012001290218220a37034002402008200aa7470d00200141c0006a200810e084808000200128024821080b2001280244200841246c6a220841013a00202008410c36021c200841e0b0c2800036021820084204370210200842003702082008428080808080013702002007200928020041016a220836020020012001290340220a37031802402008200aa7470d00200141186a200810e084808000200128022021080b200128021c200841246c6a220841023a00202008410936021c200841ecb0c280003602182008420437021020084200370208200842808080808001370200200141c0006a41086a2207200141186a41086a220928020041016a36020020012001290318370340200141186a200141c0006a41f5b0c28000410610d5848080000240200128022022082001280218470d00200141186a200810e084808000200128022021080b200128021c200841246c6a220841043a00202008411136021c200841fbb0c2800036021820084204370210200842003702082008428080808080013702002007200928020041016a220836020020012001290218220a37034002402008200aa7470d00200141c0006a200810e084808000200128024821080b2001280244200841246c6a220841053a00202008410b36021c2008418cb1c280003602182008420437021020084200370208200842808080808001370200200141186a41086a2207200141c0006a41086a220928020041016a220836020020012001290340220a37031802402008200aa7470d00200141186a200810e084808000200128022021080b200128021c200841246c6a220841063a00202008411036021c20084197b1c2800036021820084204370210200842003702082008428080808080013702002009200728020041016a36020020012001290318370340200141186a200141c0006a41a7b1c28000410510d784808000200141c0006a200141186a41acb1c28000410a10da84808000200141186a200141c0006a41b6b1c28000410d10dc848080000240200128022022082001280218470d00200141186a200810e084808000200128022021080b200128021c200841246c6a2208410a3a00202008410936021c200841c3b1c280003602182008420437021020084200370208200842808080808001370200200141c0006a41086a2207200141186a41086a220928020041016a220836020020012001290218220a37034002402008200aa7470d00200141c0006a200810e084808000200128024821080b2001280244200841246c6a2208410b3a00202008410a36021c200841ccb1c2800036021820084204370210200842003702082008428080808080013702002009200728020041016a220836020020012001290340220a37031802402008200aa7470d00200141186a200810e084808000200128022021080b200128021c200841246c6a2208410c3a00202008410b36021c200841d6b1c280003602182008420437021020084200370208200842808080808001370200200141c0006a41086a200141186a41086a28020041016a220836020020012001290318220a37034002402008200aa7470d00200141c0006a200810e084808000200128024821080b2001280244200841246c6a2208410d3a00202008410e36021c200841e1b1c2800036021820084204370210200842003702082008428080808080013702002001280248210720012802442108200120012802403602202001200836021820012008200741246c6a41246a3602242001200836021c200141c0006a200141186a10ea8480800002402005418080808078470d0041afa3c28000411141a0a4c2800010a181808000000b20012002360220200120033602182001200336021c2001200320044105746a360224200041c4006a200141186a10ec84808000200141236a200141c0006a41086a2802003600002000413c6a200637020020002005360238200041013a000020002001290308370350200041d8006a200141086a41086a2802003602002001200129024037001b20002001290018370001200041086a2001411f6a290000370000200141d0006a2480808080000bd10d04057f017e037f017e23808080800041d0006b2201248080808000200141306a41efb1c28000410a41a1b0c28000410a4194b0c28000410010d882808000200141186a41106a420437020020014200370220200142808080808001370218200142888080808001370240200142808080808001370248200141186a200141c0006a10ec84808000200141086a41086a2001412c6a2802003602002001200129022437030820012802182102200128021c2103200128022021042001280230210520012902342106200141186a41086a2207410036020020014280808080c000370218200141186a410010e084808000200128021c200728020041246c6a220841003a00202008411036021c200841f9b1c280003602182008420437021020084200370208200842808080808001370200200141c0006a41086a2209200728020041016a220836020020012001290218220a37034002402008200aa7470d00200141c0006a200810e084808000200128024821080b2001280244200841246c6a220841013a00202008410c36021c20084189b2c2800036021820084204370210200842003702082008428080808080013702002007200928020041016a220836020020012001290340220a37031802402008200aa7470d00200141186a200810e084808000200128022021080b200128021c200841246c6a220841023a00202008410c36021c20084195b2c280003602182008420437021020084200370208200842808080808001370200200141c0006a41086a2207200141186a41086a220928020041016a220836020020012001290318220a37034002402008200aa7470d00200141c0006a200810e084808000200128024821080b2001280244200841246c6a220841033a00202008410c36021c200841a1b2c2800036021820084204370210200842003702082008428080808080013702002009200728020041016a220836020020012001290340220a37031802402008200aa7470d00200141186a200810e084808000200128022021080b200128021c200841246c6a220841043a00202008410c36021c200841adb2c280003602182008420437021020084200370208200842808080808001370200200141c0006a41086a2207200141186a41086a220928020041016a220836020020012001290318220a37034002402008200aa7470d00200141c0006a200810e084808000200128024821080b2001280244200841246c6a220841053a00202008410636021c200841b9b2c2800036021820084204370210200842003702082008428080808080013702002009200728020041016a220836020020012001290340220a37031802402008200aa7470d00200141186a200810e084808000200128022021080b200128021c200841246c6a220841063a00202008410b36021c200841bfb2c280003602182008420437021020084200370208200842808080808001370200200141c0006a41086a2207200141186a41086a220928020041016a220836020020012001290318220a37034002402008200aa7470d00200141c0006a200810e084808000200128024821080b2001280244200841246c6a220841073a00202008411036021c200841cab2c2800036021820084204370210200842003702082008428080808080013702002009200728020041016a220836020020012001290340220a37031802402008200aa7470d00200141186a200810e084808000200128022021080b200128021c200841246c6a220841083a00202008410d36021c200841dab2c280003602182008420437021020084200370208200842808080808001370200200141c0006a41086a200141186a41086a28020041016a220836020020012001290318220a37034002402008200aa7470d00200141c0006a200810e084808000200128024821080b2001280244200841246c6a220841093a00202008410736021c200841e7b2c2800036021820084204370210200842003702082008428080808080013702002001280248210720012802442108200120012802403602202001200836021820012008200741246c6a41246a3602242001200836021c200141c0006a200141186a10ea8480800002402005418080808078470d0041afa3c28000411141a0a4c2800010a181808000000b20012002360220200120033602182001200336021c2001200320044105746a360224200041c4006a200141186a10ec84808000200141236a200141c0006a41086a2802003600002000413c6a200637020020002005360238200041013a000020002001290308370350200041d8006a200141086a41086a2802003602002001200129024037001b20002001290018370001200041086a200141186a41076a290000370000200141d0006a2480808080000bba0504057f017e027f017e23808080800041c0006b2201248080808000200141246a41eeb2c28000411641a1b0c28000410a4194b0c28000410010d8828080002001411c6a42043702002001420037021420014280808080800137020c2001428880808080013702302001428080808080013702382001410c6a200141306a10ec84808000200141086a200141206a28020036020020012001290218370300200128020c2102200128021021032001280214210420012802242105200129022821062001410c6a41086a2207410036020020014280808080c00037020c2001410c6a410010e0848080002001280210200728020041246c6a220841003a00202008410d36021c20084184b3c280003602182008420437021020084200370208200842808080808001370200200141306a41086a200728020041016a22083602002001200129020c2209370330024020082009a7470d00200141306a200810e084808000200128023821080b2001280234200841246c6a220841013a00202008410d36021c20084191b3c2800036021820084204370210200842003702082008428080808080013702002001280238210720012802342108200120012802303602142001200836020c20012008200741246c6a41246a36021820012008360210200141306a2001410c6a10ea8480800002402005418080808078470d0041afa3c28000411141a0a4c2800010a181808000000b200120023602142001200336020c200120033602102001200320044105746a360218200041c4006a2001410c6a10ec84808000200141176a200141306a41086a2802003600002000413c6a200637020020002005360238200041013a000020002001290300370350200041d8006a200141086a2802003602002001200129023037000f2000200129000c370001200041086a200141136a290000370000200141c0006a2480808080000bcd0403057f017e037f23808080800041d0006b2201248080808000200141286a419eb3c28000410b41a1b0c28000410a4194b0c28000410010d882808000200141206a420437020020014200370218200142808080808001370210200142888080808001370240200142808080808001370248200141106a200141c0006a10ec84808000200141086a2202200141246a2802003602002001200129021c370300200128021021032001280214210420012802182105200129022c21062001280228210720014100360218200142808080808001370210200141106a410010e1848080002001280214200128021841386c6a2208420437022c20084207370224200841c1a4c2800036022020084100360218200841be81808000360210200842b891b68c98adebcf61370308200842e7b0a091f3ed9c85c500370300200128021821092001280214210820012001280210360248200120083602402001200836024420012008200941386c6a41386a36024c200141346a200141c0006a10eb8480800002402007418080808078470d0041afa3c28000411141a0a4c2800010a181808000000b2001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10ec84808000200141106a410b6a200141346a41086a2802003600002000413c6a200637020020002007360238200041003a000020002001290300370350200041d8006a20022802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000bc611050a7f017e027f017e027f024002400240024002400240024002400240024002400240024002400240024002400240200128020022042f018a012205410b490d004101210641042105200128020822074105490d03200721052007417b6a0e020302010b200441046a21082001280204210902402001280208220741016a220120054b0d0020082001410c6c6a20082007410c6c6a200520076b410c6c10fe8d8080001a0b20082007410c6c6a22012002290200370200200141086a200241086a2802003602002004200541016a3b018a010c030b200741796a210741002106410621050c010b4100210641052105410021070b2001280204210a41002d00fca3c680001a418c0141002802c8a3c68000118180808000002208450d01200841003b018a0120084100360200200820042f018a01220b2005417f736a22013b018a012001410c4f0d02200b200541016a220c6b2001470d03200441046a220b2005410c6c6a220d290204210e200d280200210d200841046a200b200c410c6c6a2001410c6c10848e8080001a200420053b018a012004200820061b220f41046a21010240200f2f018a01220520074d0d0020012007410c6c6a220b410c6a200b200520076b410c6c10fe8d8080001a0b200a410020061b210920012007410c6c6a22012002290200370200200141086a200241086a280200360200200f200541016a3b018a010240200d418080808078460d00410021010240034020082110200e2111200d2112200422022802002204450d01200a2001470d0720022f018801210102400240024020042f018a012206410b490d004101210c200141054f0d012001210b410421010c020b200441046a220b2001410c6c6a2105200141016a2102200641016a21080240024020012006490d0020052011370204200520123602000c010b200b2002410c6c6a2005200620016b220b410c6c10fe8d8080001a200520113702042005201236020020014102742004418c016a22056a41086a200520024102746a200b41027410fe8d8080001a0b200420083b018a01200420024102746a418c016a20103602002002200641026a220b4f0d040240200620016b220641016a4103712205450d00200420014102746a4190016a210103402001280200220820023b01880120082004360200200141046a2101200241016a21022005417f6a22050d000b0b20064103490d04200241027420046a4198016a21010340200141746a280200220520023b01880120052004360200200141786a2802002205200241016a3b018801200520043602002001417c6a2802002205200241026a3b0188012005200436020020012802002205200241036a3b01880120052004360200200141106a2101200b200241046a2202470d000c050b0b2001210b024002402001417b6a0e020201000b200141796a210b4100210c410621010c010b4100210c410521014100210b0b41002d00fca3c680001a41bc0141002802c8a3c68000118180808000002208450d08200841003b018a0120084100360200200820042f018a01220d2001417f736a22023b018a012002410c4f0d09200d200141016a22056b2002470d0a200441046a22132001410c6c6a220d290204210e200d280200210d200841046a20132005410c6c6a2002410c6c10848e8080001a200420013b018a0120082f018a01220241016a21132002410c4f0d0b200620016b22012013470d0c200a41016a210a2008418c016a200420054102746a418c016a200141027410848e80800021064100210102400340200620014102746a280200220520013b01880120052008360200200120024f0d01200120012002496a220120024d0d000b0b20042008200c1b220541046a21060240200b41016a220120052f018a0122024b0d0020062001410c6c6a2006200b410c6c6a2002200b6b410c6c10fe8d8080001a0b200241016a21132006200b410c6c6a22062011370204200620123602002005418c016a21060240200b41026a2212200241026a220c4f0d00200620124102746a200620014102746a2002200b6b41027410fe8d8080001a0b200620014102746a2010360200200520133b018a0102402001200c4f0d0002402002200b6b221041016a4103712206450d002005200b4102746a4190016a210203402002280200220b20013b018801200b2005360200200241046a2102200141016a21012006417f6a22060d000b0b20104103490d00200520014102746a4198016a21020340200241746a280200220620013b01880120062005360200200241786a2802002206200141016a3b018801200620053602002002417c6a2802002206200141026a3b0188012006200536020020022802002206200141036a3b01880120062005360200200241106a2102200c200141046a2201470d000b0b200a2101200d418080808078470d000c020b0b200328020022052802002208450d0b2005280204210641002d00fca3c680001a41bc0141002802c8a3c68000118180808000002202450d0c2002200836028c01200241003b018a012002410036020020052002360200200841003b018801200820023602002005200641016a36020420062001470d0d20022f018a012201410b4f0d0e2002200141016a22053b018a0120022001410c6c6a220141086a2011370200200141046a20123602002002418c016a20054102746a2010360200201020053b018801201020023602000b200f21040b2000200736020820002009360204200020043602000f0b4104418c0110b280808000000b2001410b41e8b6c28000109581808000000b41b0b6c28000412841d8b6c2800010f880808000000b4188b7c28000413541c0b7c2800010f880808000000b410441bc0110b280808000000b2002410b41e8b6c28000109581808000000b41b0b6c28000412841d8b6c2800010f880808000000b2013410c41f8b6c28000109581808000000b41b0b6c28000412841d8b6c2800010f880808000000b41b0b4c2800010a081808000000b410441bc0110b280808000000b41e0b5c2800041304190b6c2800010f880808000000b41c0b4c28000412041a0b6c2800010f880808000000b8d17050c7f017e027f017e027f2380808080004180076b220524808080800002400240024002400240024002400240024002400240024002400240024002400240024002400240200128020022062f01aa142207410b490d004101210841042107200128020822094105490d03200921072009417b6a0e020302010b200641a4136a220820012802082209410c6c6a210a2001280204210b02400240200941016a220120074d0d00200a2002290200370200200a41086a200241086a2802003602000c010b20082001410c6c6a200a200720096b2208410c6c10fe8d8080001a200a41086a200241086a280200360200200a20022902003702002006200141e0016c6a2006200941e0016c6a200841e0016c10fe8d8080001a0b2006200941e0016c6a200341e00110848e8080001a2006200741016a3b01aa140c030b200941796a210941002108410621070c010b4100210841052107410021090b2001280204210a41002d00fca3c680001a41ac1441002802c8a3c6800011818080800000220c450d03200c41003b01aa14200c41003602a013200c20062f01aa14220d2007417f736a22013b01aa14200641a4136a220e2007410c6c6a220f2802002110200f2902042111200541a0056a2006200741e0016c6a41e00110848e8080001a2001410c4f0d04200d200741016a220f6b2001470d05200c41a4136a200e200f410c6c6a2001410c6c10848e8080001a200c2006200f41e0016c6a200141e0016c10848e808000210f200620073b01aa14200541c0036a200541a0056a41e00110848e8080001a2006200f20081b221241a4136a2009410c6c6a21010240024020122f01aa14220720094b0d0020012002290200370200200141086a200241086a2802003602000c010b2001410c6a2001200720096b220d410c6c10fe8d8080001a200141086a200241086a280200360200200120022902003702002012200941e0016c6a220141e0016a2001200d41e0016c10fe8d8080001a0b200a410020081b210b2012200941e0016c6a200341e00110848e8080001a2012200741016a3b01aa142005200541c0036a41e00110848e808000210d2010418080808078470d01201221060b200020093602082000200b360204200020063602000c010b200d41e0016a200d41e00110848e8080001a0240024020062802a01322010d004100210e0c010b4100210e200f21132011211420102115034020012108200a200e470d0620062f01a81421060240024002400240024020082f01aa14220e410b490d004101210f200641054f0d0120062103410421060c020b200841a4136a220a2006410c6c6a2107200641016a2101200e41016a2102024002402006200e490d0020072014370204200720153602002008200641e0016c6a200d41e0016a41e00110848e8080001a0c010b200a2001410c6c6a2007200e20066b220a410c6c10fe8d8080001a20072014370204200720153602002008200141e0016c6a2008200641e0016c6a2207200a41e0016c10fe8d8080001a2007200d41e0016a41e00110848e8080001a2006410274200841ac146a22076a41086a200720014102746a200a41027410fe8d8080001a0b200820023b01aa14200820014102746a41ac146a20133602002001200e41026a220a4f0d020240200e20066b220341016a4103712207450d00200820064102746a41b0146a210603402006280200220220013b01a814200220083602a013200641046a2106200141016a21012007417f6a22070d000b0b20034103490d02200141027420086a41b8146a21060340200641746a280200220720013b01a814200720083602a013200641786a2802002207200141016a3b01a814200720083602a0132006417c6a2802002207200141026a3b01a814200720083602a01320062802002207200141036a3b01a814200720083602a013200641106a2106200a200141046a2201470d000c030b0b20062103024002402006417b6a0e020201000b200641796a21034100210f410621060c010b4100210f41052106410021030b41002d00fca3c680001a41dc1441002802c8a3c6800011818080800000220c450d09200c41003b01aa14200c41003602a013200c20082f01aa1422022006417f736a22013b01aa14200841a4136a22162006410c6c6a2207280200211020072902042111200d41a0056a2008200641e0016c6a41e00110848e8080001a2001410c4f0d0a2002200641016a22076b2001470d0b200c41a4136a20162007410c6c6a2001410c6c10848e8080001a200c2008200741e0016c6a200141e0016c10848e8080002102200820063b01aa14200d41c0036a200d41a0056a41e00110848e8080001a20022f01aa14220141016a21162001410c4f0d0c200e20066b22062016470d0d200a41016a210e200241ac146a200820074102746a41ac146a200641027410848e808000210a4100210602400340200a20064102746a280200220720063b01a814200720023602a013200620014f0d01200620062001496a220620014d0d000b0b200d41a0056a200d41c0036a41e00110848e8080001a20082002200f1b220141a4136a220f2003410c6c6a210a02400240200341016a220620012f01aa1422074d0d00200a2014370204200a20153602000c010b200f2006410c6c6a200a200720036b220f410c6c10fe8d8080001a200a2014370204200a20153602002001200641e0016c6a2001200341e0016c6a200f41e0016c10fe8d8080001a0b200741016a21152001200341e0016c6a200d41e0016a41e00110848e8080001a200141ac146a210a0240200341026a2216200741026a220f4f0d00200a20164102746a200a20064102746a200720036b41027410fe8d8080001a0b200a20064102746a2013360200200120153b01aa1402402006200f4f0d000240200720036b221341016a410371220a450d00200120034102746a41b0146a210703402007280200220320063b01a814200320013602a013200741046a2107200641016a2106200a417f6a220a0d000b0b20134103490d00200120064102746a41b8146a21070340200741746a280200220a20063b01a814200a20013602a013200741786a280200220a200641016a3b01a814200a20013602a0132007417c6a280200220a200641026a3b01a814200a20013602a0132007280200220a200641036a3b01a814200a20013602a013200741106a2107200f200641046a2206470d000b0b200d200d41a0056a41e00110848e80800021062010418080808078470d010b200020093602082000200b360204200020123602000c030b200641e0016a200641e00110848e8080001a20022113200e210a20082106201121142010211520082802a01322010d000b0b200428020022012802002207450d0a2001280204210241002d00fca3c680001a41dc1441002802c8a3c68000118180808000002206450d0b200620073602ac14200641003b01aa14200641003602a01320012006360200200741003b01a814200720063602a0132001200241016a3602042002200e470d0c20062f01aa142201410b4f0d0d2006200141016a22073b01aa1420062001410c6c6a220241a8136a2011370200200241a4136a20103602002006200141e0016c6a200d41e0016a41e00110848e8080001a200641ac146a20074102746a200c360200200020093602082000200b36020420002012360200200c20073b01a814200c20063602a0130b20054180076a2480808080000f0b410441ac1410b280808000000b2001410b41e8b6c28000109581808000000b41b0b6c28000412841d8b6c2800010f880808000000b4188b7c28000413541c0b7c2800010f880808000000b410441dc1410b280808000000b2001410b41e8b6c28000109581808000000b41b0b6c28000412841d8b6c2800010f880808000000b2016410c41f8b6c28000109581808000000b41b0b6c28000412841d8b6c2800010f880808000000b41b0b4c2800010a081808000000b410441dc1410b280808000000b41e0b5c2800041304190b6c2800010f880808000000b41c0b4c28000412041a0b6c2800010f880808000000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000bee0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b2201410274210420014180808080024941027421050240024020030d00200241003602180c010b200241043602182002200341027436021c200220002802043602140b200241086a20052004200241146a108b85808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000be20101027f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024108200241084b1b2202417f73411f7621040240024020010d00200341003602180c010b2003200136021c20034101360218200320002802043602140b200341086a20042002200341146a108b85808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bf20301027f23808080800041c0006b22042480808080000240024020010d00410021010c010b41012101200241c000490d0041022101200241808001490d00410441052002418080808004491b21010b200420033602182004200441186a36021c2004410c6a2004411c6a10928580800002402000280200220228020822052001490d0020024100360208200228020421032004413c6a2004280210220020042802146a360200200441386a200428020c360200200441346a2000360200200420023602242004200336021c20042000360230200420013602282004200520016b36022c2004200320016a3602202004411c6a10918580800020042802202102200441d0b7c28000360220200428021c2103200441d0b7c2800036021c200428022c210102400240024020022003470d002001450d022004280224220041086a21032004280228220520002802082202460d012000280204220020026a200020056a200110fe8d8080001a0c010b2001450d012004280224220041086a21032004280228220520002802082202460d002000280204220020026a200020056a200110fe8d8080001a0b2003200220016a3602000b02402004280238450d00200428023041002802c0a3c68000118080808000000b200441c0006a2480808080000f0b2001200541dcbcc28000109581808000000be60701097f410341022001280200418080808078461b21052000280200210602400240024020020d00200041086a2802002006200641054b22071b22020d010b200041086a2102024002402000200641054b22074103746a28020022082006410520071b460d002002200020071b21022000280204200041046a20071b21060c010b2000109a8580800020002802082108200028020421060b20062008412c6c6a2206200129020037020c200620053602082006410036022820064280808080c000370220200641146a200141086a2802003602002002200228020041016a3602000c010b024002402002412c6c200041046a2202280200200220071b6a41546a220628020822084101460d00410221070c010b200641186a2207280200210920074100360200200641146a280200210a2006280210210b20064280808080103702102006410c6a280200210c2006280204210d200628020021070b02400240024002402008417e6a2208410220084102491b0e020103000b200641106a21080c010b2006410c6a21080b2008280200450d00200828020441002802c0a3c68000118080808000000b200620053602082006200129020037020c200641146a200141086a28020036020020074102460d0002400240200028020820002802002201200141054b22011b220641014d0d0002402006412c6c2002280200200220011b6a41a87f6a220128020841014b0d0041002106410021022001280200450d02410121022001280204220541c000490d0241022102200541808001490d02410441052005418080808004491b21020c020b200b450d02200a41002802c0a3c68000118080808000000c020b4198bbc2800041c00041d8bbc2800010a181808000000b02402007450d0041012106200d41c000490d0041022106200d41808001490d0041044105200d418080808004491b21060b2001200d360204200120073602002009200220066b200620026b20062002491b2207410020076b20022006491b200c6a220620092006491b210602402001280210450d00200141146a28020041002802c0a3c68000118080808000000b2001200b360210200141186a2006360200200141146a200a3602000b0240024020034101470d00200041086a28020020002802002201200141054b22011b2206450d012006412c6c2000280204200041046a20011b6a220141746a210002402001417c6a2802002201450d00200141027420002802046a417c6a2802002004460d010b024020012000280200470d0020002001108c85808000200028020821010b200028020420014102746a20043602002000200028020841016a3602080b0f0b41fcb8c2800041fc004188bbc2800010a181808000000b8c07010c7f23808080800041b0026b2205248080808000200128020421060240024002400240024002400240200128020822070d00410121080c010b2007417f4c0d0141002d00fca3c680001a200741002802c8a3c68000118180808000002208450d020b20082006200710848e808000210902402000280200220a0d004100210a0c030b2000280204210b024002400340200a41a4136a2108200a2f01aa14220c410c6c210d417f210e0240024003400240200d0d00200c210e0c020b200841086a210f200841046a2110200d41746a210d200e41016a210e2008410c6a2108417f200920102802002007200f280200220f2007200f491b10888e80800022102007200f6b20101b220f410047200f4100481b220f4101460d000b200f41ff0171450d010b200b450d02200b417f6a210b200a200e4102746a41ac146a280200210a0c010b0b2007450d01200941002802c0a3c68000118080808000000c010b2007418080808078470d032009210a2000210e0b200a200e41e0016c6a21080c030b10ae80808000000b4101200710b280808000000b2005200e360224200541003602202005200a36021c2005200036021820052007360214200520093602102005200736020c200541003602280240200a0d0041002d00fca3c680001a41ac1441002802c8a3c68000118180808000002208450d02200841013b01aa14200841003602a013200820073602a413200841ac136a2007360200200841a8136a20093602002008200541286a41e00110848e80800021072000428080808010370204200020073602000c010b20054188026a41086a2005411c6a220841086a2802003602002005200829020037038802200520073602ac02200520093602a802200520073602a40220054198026a20054188026a200541a4026a200541286a200541186a108a8580800020052802182208200828020841016a36020820052802980220052802a00241e0016c6a21080b02400240200041146a280200200028020c2207200741054b22071b220d450d00200041106a220f280200210e200541286a41086a200141086a28020036020020052001290200370328200d410c6c200e200f20071b6a41746a200541286a10978580800041017321070c010b024020012802000d00410021070c010b41002107200641002802c0a3c68000118080808000000b20082002200720032004108f85808000200541b0026a2480808080000f0b410441ac1410b280808000000bf608010c7f200041e8bbc28000360204200041e8bbc280003602000240200028021022010d00024020002802082202280200200228020822036b200041206a2802002204200041186a28020022056b22064f0d00200220032006108d85808000200228020821030b024020052004460d00200228020421072005417f7320046a2108024020064103712206450d000340200720036a20052d00003a0000200341016a2103200541016a21052006417f6a22060d000b0b024020084103490d00200720036a2109410021070340200920076a2208200520076a22062d00003a0000200841016a200641016a2d00003a0000200841026a200641026a2d00003a0000200841036a200641036a2d00003a0000200741046a2107200641046a2004470d000b200320076a21030b200020043602180b200220033602080f0b024002400240200028020c220a200028020822032802082205470d00200041206a2802002109200041186a28020021070c010b200a20056b2106200328020420056a2105200041186a2802002107200041206a2802002109034020072009460d02200520072d00003a00002000200741016a22073602182003200328020841016a360208200541016a21052006417f6a22060d000b0b0240024020092007470d0020092107200921060c010b02402003280200200a20016a22066b200920076b22054f0d00200320062005108d858080000b200328020422062005200a6a22046a2006200a6a200110fe8d8080001a2000200436020c0240200328020822062004470d002004210a200721060c010b200328020420066a2105200a20096a20066b210820072106034020062009460d02200520062d00003a00002000200641016a22063602182003200328020841016a360208200541016a21052008200741016a2207470d000b2004210a0b0240024020092006470d00410121020c010b02400240200920076b2208417f4c0d004100210541002d00fca3c680001a200841002802c8a3c68000118180808000002202450d01200920066b2208410371210b02402006417f7320096a4103490d002008417c71210c410021050340200220056a2208200620056a22042d00003a0000200841016a200441016a2d00003a0000200841026a200441026a2d00003a0000200841036a200441036a2d00003a0000200c200541046a2205470d000b200620056a21060b0240200b450d000340200220056a20062d00003a0000200541016a2105200641016a2106200b417f6a220b0d000b0b200020093602182005450d0202402003280200200a20016a22066b20054f0d00200320062005108d858080000b20032802042208200a20056a22066a2008200a6a200110fe8d8080001a2000200636020c200328020822082006460d02200328020420086a21002005200a20086b6a210841002106034020052006460d03200020066a200220066a2d00003a00002003200328020841016a3602082008200641016a2206460d030c000b0b10ae80808000000b4101200810b280808000000b20092007460d00200241002802c0a3c68000118080808000000b0bcb0301047f23808080800041106b220224808080800041012103024020012802002204280200220141c000490d0041022103200141808001490d00410441052001418080808004491b21030b41002d00fca3c680001a024002400240200341002802c8a3c68000118180808000002201450d002002410036020c2002200136020820022003360204024020042802002205413f4b0d00200120054102743a0000410121030c030b0240200541ffff004b0d0020054102744101722104410021050240200341014b0d00200241046a4100410210b18280800020022802082101200228020c21050b200120056a20043b0000200541026a21030c030b200541ffffffff034b0d0120054102744102722104410021050240200341034b0d00200241046a4100410410b18280800020022802082101200228020c21050b200120056a2004360000200541046a21030c020b4101200310b280808000000b200141033a0000410121052002410136020c200428020021040240200341044b0d00200241046a4101410410b18280800020022802082101200228020c21050b200120056a2004360000200541046a21030b20002002290204370200200041086a2003360200200241106a2480808080000b9a0201027f23808080800041106b2202248080808000200220002802002200360204200128021441ecbcc280004106200141186a28020028020c118280808000002103200241003a000d200220033a000c20022001360208200241086a41f2bcc280004104200041046a41f8bcc28000108c818080004188bdc280004105200241046a4190bdc28000108c81808000210320022d000c21000240024020022d000d0d00200041ff017141004721010c010b41012101200041ff01710d000240200328020022012d001c4104710d0020012802144187a5c080004102200128021828020c1182808080000021010c010b20012802144186a5c080004101200128021828020c1182808080000021010b200241106a24808080800020010bae0101017f23808080800041306b2202248080808000200028020021002002410c6a4202370200200241186a410c6a41d08180800036020020022000280200220036022820024103360204200241f0bfc08000360200200241d18180800036021c200220006836022c200141186a28020021002002200241186a36020820022002412c6a3602202002200241286a36021820012802142000200210d9808080002101200241306a24808080800020010bed0201037f2380808080004180016b220224808080800002400240024002400240200128021c22034110710d0020034120710d0120003502004101200110fe8080800021000c020b20002802002100410021030340200220036a41ff006a413041d7002000410f712204410a491b20046a3a00002003417f6a210320004110492104200041047621002004450d000b20034180016a22004180014b0d022001410141c48dc080004102200220036a4180016a410020036b10db8080800021000c010b20002802002100410021030340200220036a41ff006a413041372000410f712204410a491b20046a3a00002003417f6a210320004110492104200041047621002004450d000b20034180016a22004180014b0d022001410141c48dc080004102200220036a4180016a410020036b10db8080800021000b20024180016a24808080800020000f0b200041800141c88dc08000109481808000000b200041800141c88dc08000109481808000000b02000bed04020c7f017e23808080800041d0006b22022480808080000240024002400240200028020022030d00200141046a2104410021030c010b200141046a210420012802082105200128020421062000280204210702400340200341046a210820032f018a012209410c6c210a417f210b0240024003400240200a0d002009210b0c020b200841086a210c200841046a210d200a41746a210a200b41016a210b2008410c6a2108417f2006200d2802002005200c280200220c2005200c491b10888e808000220d2005200c6b200d1b220c410047200c4100481b220c4101460d000b200c41ff0171450d010b2007450d022007417f6a21072003200b4102746a418c016a28020021030c010b0b410121082001280200450d02200641002802c0a3c68000118080808000000c020b200bad422086210e0b410121082001280200220a418080808078460d002002200e3702202002200336021c200220003602182002200a36020c200220042902003702100240024020030d0041002d00fca3c680001a418c0141002802c8a3c68000118180808000002208450d0320084100360200200841013b018a01200241146a280200210a2008200229020c3702042008410c6a200a3602002000428080808010370204200020083602000c010b200241286a41086a2002411c6a220841086a28020036020020022008290200370328200241c0006a41086a2002410c6a41086a2802003602002002200229020c370340200241346a200241286a200241c0006a200241186a10898580800020022802182208200828020841016a3602080b410021080b200241d0006a24808080800020080f0b4104418c0110b280808000000b02000ba90201027f23808080800041106b22022480808080000240024020002802000d00200128021441a0bdc280004110200141186a28020028020c1182808080000021010c010b20022000360204200128021441b0bdc280004108200141186a28020028020c118280808000002100200241003a000d200220003a000c20022001360208200241086a41b8bdc280004106200241046a41c0bdc28000108c81808000210320022d000c2100024020022d000d0d00200041ff017141004721010c010b41012101200041ff01710d000240200328020022012d001c4104710d0020012802144187a5c080004102200128021828020c1182808080000021010c010b20012802144186a5c080004101200128021828020c1182808080000021010b200241106a24808080800020010bbd0402077f017e23808080800041106b2201248080808000024002400240024002400240200041086a28020020002802002202200241054b1b220341016a2204450d004100417f2004417f6a677620044102491b41016a2204450d00200320044b0d0120024105200241054b22051b21062000280204200041046a220720051b2105024020044106490d0020062004460d060240024002402004ad422c7e2208422088a70d002008a7220741fcffffff074b0d0020024106490d012006ad422c7e2208422088a70d002008a7220641fcffffff074b0d00200741002802c8a3c68000118180808000002202450d02200220052006200720062007491b10848e8080001a200541002802c0a3c68000118080808000000c080b41f8bec280004111418cbfc2800010f880808000000b41002d00fca3c680001a200741002802c8a3c680001181808080000022020d050b4104200710b280808000000b200241064f0d020c050b41f8bec280004111419cbfc2800010a181808000000b41acbfc28000412041ccbfc2800010f880808000000b200720052003412c6c10848e8080001a200020033602002006ad422c7e2208a7210002402008422088a70d00200041fdffffff074f0d00200541002802c0a3c68000118080808000000c030b2001200036020c2001410036020841acbec28000412b200141086a41d8bec2800041e8bec28000108981808000000b200220052003412c6c10848e8080001a0b2000200336020820002002360204200020043602000b200141106a2480808080000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000be20101027f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024108200241084b1b2202417f73411f7621040240024020010d00200341003602180c010b2003200136021c20034101360218200320002802043602140b200341086a20042002200341146a109b85808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000b4b01017f02402000280200200028020822036b20024f0d00200020032002109c85808000200028020821030b200028020420036a2001200210848e8080001a2000200320026a36020841000b860201017f024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d0020020d02410121010c030b20032802002103200241002802c8a3c68000118180808000002201450d0320012003200410848e8080001a200341002802c0a3c68000118080808000000c020b20020d00410121010c010b41002d00fca3c680001a200241002802c8a3c68000118180808000002201450d010b20002001360204200041086a2002360200200041003602000f0b20004101360204200041086a2002360200200041013602000f0b20004100360204200041086a2002360200200041013602000f0b20004100360204200041013602000be20101027f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024108200241084b1b2202417f73411f7621040240024020010d00200341003602180c010b2003200136021c20034101360218200320002802043602140b200341086a20042002200341146a109e85808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000be50201057f23808080800041106b220224808080800020012802042103024002400240024002402001280208220141176a22040d002002410036020c20024280808080103702040c010b2004417f4c0d024100210541002d00fca3c680001a200441002802c8a3c68000118180808000002206450d032002410036020c200220063602082002200436020420014169490d010b200241046a41004117109f8580800020022802082106200228020c21050b200620056a220441002900dcbfc280003700002004410f6a41002900ebbfc28000370000200441086a41002900e4bfc280003700002002200541176a220436020c0240200228020420046b20014f0d00200241046a20042001109f8580800020022802082106200228020c21040b200620046a2003200110848e8080001a200041086a200420016a36020020002002290204370200200241106a2480808080000f0b10ae80808000000b4101200410b280808000000b800303027f017e057f23808080800041306b2201248080808000200141246a4192c2c28000410c41fcc1c28000411641fcc1c28000410010d882808000200141086a2202410036020020014280808080c00037030020012902282103200128022421042001410036021420014280808080800137020c2001410c6a410010a98580800020012802102205200128021441386c22066a220742d1beacaad083ca85ad7f370308200742fbd1a5f0d984c58f51370300200128020c21082007420437022c20074211370224200741a8c2c280003602202007410a36021c2007419ec2c28000360218200741d88180800036021002402004418080808078470d0041f3bfc28000411141e4c0c2800010a181808000000b200042808080808001370244200020043602382000200536020820002008360204200041003a000020002001290300370350200041cc006a41003602002000413c6a2003370200200041d8006a20022802003602002000200641386a41386e36020c200141306a2480808080000b6f00200042e7b0a091f3ed9c85c50037030820004280808080c00037033820004280808080c000370350200041d981808000360218200041023a0000200041106a42b891b68c98adebcf61370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6f00200042dbd791d5c2919eaecd0037030820004280808080c00037033820004280808080c000370350200041c880808000360218200041023a0000200041106a42e6ed8d82cc91adcb05370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b22064105762207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710ac8580800020022802082109200228020c21080b200920084105746a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b4105762107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b220641386e2207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710ab8580800020022802082109200228020c21080b2009200841386c6a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b41386e2107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000ba707010d7f200141186a28020021022001410d6a2d00002103200141096a2d00002104200141146a28020021052001280210210620012d000c21072001280204210820012d000821092001280200210a0340024002400240024002400240024002400240024002400240024002400240024002400240200a417e6a0e020102000b0240200941ff0171220b4102460d002001200b454101743a000841002109200b450d002004210c0c030b0240200a450d002008450d0002402008418002490d002001200841817e6a220836020441ff01210c410221090c040b200141003602042008417f6a210c41022109410021080c030b41022109200141023602000b200741ff0171210a410221070240200a4102460d0041002107200141003a000c200a0d030b200141033602000b2006450d072005450d07200120052005200220052002491b220a6b220536021420012006200a6a220b360210024002400240200a0e020001020b4100410041c8c4c2800010f980808000000b4101410141d8c4c2800010f980808000000b20062d000041047420062d000172210c4103210a200b21060b2000280208220b2000280200470d0d200a4103470d024100210d4103210a2006450d0c2005450d0c2002450d01200520026e220d2005200d20026c6b4100476a210d0c0c0b410021072000280208220b2000280200460d024102210a2003210c0c0c0b41c0c3c28000411941acc3c2800010f880808000000b2006450d06200a4102470d024102210a200741ff01714102470d014100210d410221070c050b2003210c2006450d060b200741ff0171410047210d4102210a0c030b200741ff0171220d4102460d012009410171200d4100476a210d0c020b0f0b410221074100210d0240200941ff0171220e4102470d00410221090c010b200e410047210d0b4100210e024002402005450d002002450d01200520026e220e2005200e20026c6b4100476a210e0b417f200d200e6a220e200e200d491b210d0c040b41c0c3c28000411941acc3c2800010f880808000000b200a4102470d014102210a410021064100210d200741ff01714102460d020b41002106200741ff0171410047210d4102210a0c010b0240200741ff0171220d4102460d00410021062009410171200d4100476a210d0c010b410021060240200941ff0171220d4102470d00410221094100210d0c010b41002106200d410047210d0b2000200b200d41016a220d417f200d1b10aa858080000b2000200b41016a3602082000280204200b6a200c3a00000c000b0ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000be00101037f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014108200141084b1b2201417f73411f7621040240024020030d00200241003602180c010b2002200336021c20024101360218200220002802043602140b200241086a20042001200241146a10a785808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141386c210420014193c9a4124941037421050240024020030d00200241003602180c010b200241083602182002200341386c36021c200220002802043602140b200241086a20052004200241146a10a785808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000be20101027f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024108200241084b1b2202417f73411f7621040240024020010d00200341003602180c010b2003200136021c20034101360218200320002802043602140b200341086a20042002200341146a10a785808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b220241386c210420024193c9a4124941037421050240024020010d00200341003602180c010b200341083602182003200141386c36021c200320002802043602140b200341086a20052004200341146a10a785808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b22024105742104200241808080204941037421050240024020010d00200341003602180c010b200341083602182003200141057436021c200320002802043602140b200341086a20052004200341146a10a785808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000b950301037f0240200028020022022802002200413f4b0d00200041027421020240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a20023a00000f0b0240200041ffff004b0d002000410274410172210202402001280200200128020822006b41014b0d0020012000410210b182808000200128020821000b2001200041026a360208200128020420006a20023b00000f0b0240200041ffffffff034b0d002000410274410272210202402001280200200128020822006b41034b0d0020012000410410b182808000200128020821000b2001200041046a360208200128020420006a20023600000f0b02402001280200220320012802082200470d0020012000410110b18280800020012802002103200128020821000b2001280204220420006a41033a00002001200041016a2200360208200228020021020240200320006b41034b0d0020012000410410b18280800020012802042104200128020821000b2001200041046a360208200420006a20023600000bfe0501077f23808080800041c0006b220124808080800020014108360224200141d9c3c2800036022041002d00fca3c680001a024002400240410841002802c8a3c68000118180808000002202450d00200241d9c3c28000360200200241046a410836020041d9c3c28000410810d782808000450d0141002d00fca3c680001a412041002802c8a3c68000118180808000002203450d02200342e7b0a091f3ed9c85c500370308200341d98180800036021820034101360204200341e1c3c28000360200200341106a42b891b68c98adebcf6137030020014101360210200120033602082001200341206a3602142001200336020c200141306a200141086a10a48580800020012802382104200128023421052001280230210620014100360210200142808080808001370208200141086a410010a985808000200128020c200128021041386c6a2203410036023020034280808080c0003703282003410036022020034100360218200341da81808000360210200342aac2d79da4bfd9a04e370308200342e6afce95f6a1ffa6c30037030020012802102107200128020c210320012001280208360238200120033602302001200336023420012003200741386c6a41386a36023c200141206a200141306a10a58580800020012006360210200120053602082001200520044105746a3602142001200536020c200041c4006a200141086a10a485808000200141136a200141206a41086a2802003600002000413c6a2002ad4280808080108437020020004101360238200041003a0000200041d8006a410036020020004280808080c0003703502001200129032037000b20002001290008370001200041086a2001410f6a290000370000200141c0006a2480808080000f0b4104410810b280808000000b200241002802c0a3c6800011808080800000200141146a42013702002001410236020c20014180ddc18000360208200141b4808080003602342001200141306a3602102001200141206a360230200141086a4190ddc1800010f680808000000b4108412010b280808000000b9d0401057f23808080800041306b2204248080808000200241017121050240024020032802002206418080808078470d002002413e2002413e491b210602402005450d0020012d000021070b200441246a4102360200200441206a2002417e71360200200420073a0019200441013a00142004410136020c2004200220066b360210200420053a00182004200120056a36021c200441ff00200641c000722002413e4b1b3a001520002004410c6a10a6858080002004200341086a28020022023602282004200441286a36022c2004412c6a200010ad858080002003280204210502402000280200200028020822036b20024f0d0020002003200210aa85808000200028020821030b200028020420036a2005200210848e8080001a2000200320026a3602080c010b2002411e2002411e491b210702402005450d0020012d000021080b200441246a4102360200200441206a2002417e71360200200420083a0019200441013a00142004410136020c2004200220076b360210200420053a00182004200120056a36021c2004413f20074120722002411e4b1b3a001520002004410c6a10a6858080002003280204210502402000280200200028020822026b200328020822034f0d0020002002200310aa85808000200028020821020b200028020420026a2005200310848e8080001a2000200220036a3602082006450d00200541002802c0a3c68000118080808000000b200441306a2480808080000b6f00200042f9f59bcab3e385eb9e7f37030820004280808080c00037033820004280808080c000370350200041db81808000360218200041023a0000200041106a42e4a581ceab969ef15c370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000be10101017f41002d00fca3c680001a0240413041002802c8a3c680001181808080000022010d004108413010b280808000000b200142d7c9cb8fc1cf97db3e370318200142a8c7daf8defb9a8fc400370308200142a7b98ffce8cbcbd38b7f370300200141dc8180800036021020004280808080c00037033820004280808080c0003703502000410236020c2000200136020820004102360204200041043a0000200141206a42e88488d0c0e3aebc13370300200141286a41b580808000360200200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b7600200042dbd791d5c2919eaecd0037030820004280808080c00037033820004280808080c00037035020004108360220200041c880808000360218200041033a0000200041106a42e6ed8d82cc91adcb05370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000bcd0401077f23808080800041306b22012480808080002001410336020c200141dcc6c2800036020841002d00fca3c680001a024002400240410841002802c8a3c68000118180808000002202450d00200241dcc6c28000360200200241046a410336020041dcc6c28000410310d782808000450d0141002d00fca3c680001a412041002802c8a3c68000118180808000002203450d02200342cec69c9ba88e87eade00370308200341dd8180800036021820034101360204200341dfc6c28000360200200341106a428e89b0b185a4c6d5fa0037030020014100360218200142808080808001370210200141106a410010b68580800020012802142204200128021841386c22056a2206428e89b0b185a4c6d5fa00370308200642cec69c9ba88e87eade00370300200128021021072006410036023020064280808080c0003703282006410036022020064100360218200641dd81808000360210200041cc006a4101360200200041c8006a2003360200200041013602442000413c6a2002ad4280808080108437020020004101360238200041d8006a410036020020004280808080c0003703502000200541386a41386e36020c2000200436020820002007360204200041003a0000200141306a2480808080000f0b4104410810b280808000000b200241002802c0a3c68000118080808000002001411c6a42013702002001410236021420014180ddc18000360210200141b48080800036022c2001200141286a3602182001200141086a360228200141106a4190ddc1800010f680808000000b4108412010b280808000000bdf0b05027f017e037f017e017f23808080800041d0006b2201248080808000200141306a41e0c6c28000410e41eec6c28000410a41e0c6c28000410010d882808000200141086a41086a410036020020014280808080c0003703082001280230210220012902342103200141186a41086a22044100360200200142808080808001370218200141186a410010b685808000200128021c2004280200220541386c6a2206420437022c2006420d37022420064181c7c280003602202006410936021c200641f8c6c28000360218200641bd80808000360210200642efc9c9edb5e7b3a6c700370308200642acf6debeefe0d9c8d300370300200141c0006a41086a200541016a2205360200200120012902182207370340024020052007a7470d00200141c0006a200510b685808000200128024821050b2001280244200541386c6a2206420437022c2006420d37022420064181c7c280003602202006410936021c2006418ec7c28000360218200641bd80808000360210200642efc9c9edb5e7b3a6c700370308200642acf6debeefe0d9c8d3003703002004200541016a2205360200200120012903402207370318024020052007a7470d00200141186a200510b685808000200128022021050b200128021c200541386c6a2206420437022c20064203370224200641a8c7c280003602202006411136021c20064197c7c28000360218200641b580808000360210200642e88488d0c0e3aebc13370308200642d7c9cb8fc1cf97db3e370300200141c0006a41086a200541016a2205360200200120012903182207370340024020052007a7470d00200141c0006a200510b685808000200128024821050b2001280244200541386c6a2206420437022c20064203370224200641a8c7c280003602202006410c36021c200641abc7c28000360218200641b580808000360210200642e88488d0c0e3aebc13370308200642d7c9cb8fc1cf97db3e370300200141186a41086a200541016a2205360200200120012903402207370318024020052007a7470d00200141186a200510b685808000200128022021050b200128021c200541386c6a2206420437022c20064203370224200641a8c7c280003602202006410c36021c200641b7c7c28000360218200641b580808000360210200642e88488d0c0e3aebc13370308200642d7c9cb8fc1cf97db3e370300200141c0006a41086a200541016a2205360200200120012903182207370340024020052007a7470d00200141c0006a200510b685808000200128024821050b2001280244200541386c6a2206420437022c20064207370224200641c7c7c280003602202006410436021c200641c3c7c28000360218200641de81808000360210200642abd8aafbe989a3f863370308200642ccc2e78eb1d4fbf0bc7f370300200141186a41086a200541016a2205360200200120012903402207370318024020052007a7470d00200141186a200510b685808000200128022021050b200128021c200541386c6a2206420437022c20064203370224200641a8c7c280003602202006411336021c200641cec7c28000360218200641b580808000360210200642e88488d0c0e3aebc13370308200642d7c9cb8fc1cf97db3e370300200141c8006a200541016a2205360200200120012903182207370340024020052007a72204470d00200141c0006a200510b68580800020012802402104200128024821050b20012802442208200541386c6a220642e6ed8d82cc91adcb05370308200642dbd791d5c2919eaecd003703002006420437022c20064202370224200641eec7c280003602202006410d36021c200641e1c7c28000360218200641c88080800036021002402002418080808078470d0041d8c5c28000411141ccc6c2800010a181808000000b200042808080808001370244200020023602382000200836020820002004360204200041003a000020002001290308370350200041cc006a41003602002000413c6a2003370200200041d8006a200141106a2802003602002000200541386c41386a41386e36020c200141d0006a2480808080000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141386c210420014193c9a4124941037421050240024020030d00200241003602180c010b200241083602182002200341386c36021c200220002802043602140b200241086a20052004200241146a10b585808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000b6f00200042a5e9e3ab9e929adc2c37030820004280808080c00037033820004280808080c000370350200041ef80808000360218200041063a0000200041106a4293888c8f89fdc6ec9e7f370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b960101017f23808080800041306b2202248080808000200241206a410c6a41cf80808000360200200241086a410c6a42023702002002410336020c20024190c8c28000360208200241cf80808000360224200220003602202002200041086a360228200141186a28020021002002200241206a36021020012802142000200241086a10d9808080002100200241306a24808080800020000bab0405027f017e027f017e027f23808080800041c0006b2201248080808000200141246a41a8c8c28000410641aec8c28000411541f0c7c28000410010d882808000200141086a410036020020014280808080c00037030020012802242102200129022821032001410c6a41086a2204410036020020014280808080800137020c2001410c6a410010bb85808000200141306a41086a2004280200220441016a22053602002001280210200441386c6a220442899ac8f29d8ce69ac300370308200442e78dcee4d0becc97573703002004420437022c20044203370224200441e8c9c280003602202004410836021c200441e0c9c28000360218200441df818080003602102001200129020c2206370330024020052006a72207470d00200141306a200510bb8580800020012802302107200128023821050b20012802342208200541386c6a220442899ac8f29d8ce69ac300370308200442e78dcee4d0becc97573703002004420437022c20044203370224200441e8c9c280003602202004410a36021c200441ebc9c28000360218200441df8180800036021002402002418080808078470d0041dcc8c28000411141d0c9c2800010a181808000000b200042808080808001370244200020023602382000200836020820002007360204200041003a000020002001290300370350200041cc006a41003602002000413c6a20033702002000200541016a36020c200041d8006a200141086a280200360200200141c0006a2480808080000bab0405027f017e027f017e027f23808080800041c0006b2201248080808000200141246a41c3c8c28000410f41d2c8c28000410a41f0c7c28000410010d882808000200141086a410036020020014280808080c00037030020012802242102200129022821032001410c6a41086a2204410036020020014280808080800137020c2001410c6a410010bb85808000200141306a41086a2004280200220441016a22053602002001280210200441386c6a22044293888c8f89fdc6ec9e7f370308200442a5e9e3ab9e929adc2c3703002004420437022c20044203370224200441e8c9c280003602202004410436021c200441f5c9c28000360218200441ef808080003602102001200129020c2206370330024020052006a72207470d00200141306a200510bb8580800020012802302107200128023821050b20012802342208200541386c6a22044293888c8f89fdc6ec9e7f370308200442a5e9e3ab9e929adc2c3703002004420437022c20044203370224200441e8c9c280003602202004410536021c200441f9c9c28000360218200441ef8080800036021002402002418080808078470d0041dcc8c28000411141d0c9c2800010a181808000000b200042808080808001370244200020023602382000200836020820002007360204200041003a000020002001290300370350200041cc006a41003602002000413c6a20033702002000200541016a36020c200041d8006a200141086a280200360200200141c0006a2480808080000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141386c210420014193c9a4124941037421050240024020030d00200241003602180c010b200241083602182002200341386c36021c200220002802043602140b200241086a20052004200241146a10bc85808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000ba02001177f23808080800041c0016b220524808080800002400240024002400240024002400240024002400240024002400240024002400240024002400240200128020022062f0196042207410b490d0041012108410421092001280208220a4105490d03200a2109200a417b6a0e020302010b20062001280208220a4105746a21092001280204210b02400240200a41016a220120074d0d0020092002290000370000200941186a200241186a290000370000200941106a200241106a290000370000200941086a200241086a2900003700000c010b200620014105746a20092007200a6b220c41057410fe8d8080001a200941186a200241186a290000370000200941106a200241106a290000370000200941086a200241086a29000037000020092002290000370000200641e0026a220220014104746a2002200a4104746a200c41047410fe8d8080001a0b2006200a4104746a220241e8026a200341086a290200370200200241e0026a20032902003702002006200741016a3b0196040c030b200a41796a210a41002108410621090c010b41002108410521094100210a0b2001280204210741002d00fca3c680001a41980441002802c8a3c6800011818080800000220d450d03200d41003b019604200d41003602900420054190016a41086a200620094105746a220c41086a29000037030020054190016a41106a200c41106a29000037030020054190016a41186a200c41186a290000370300200541c0006a41086a200641e0026a220e20094104746a220f410c6a280200360200200d20062f01960422102009417f736a22013b0196042005200c290000370390012005200f2902043703402001410c4f0d042010200941016a220c6b2001470d05200f2802002111200d2006200c4105746a200141057410848e808000220f41e0026a200e200c4104746a200141047410848e8080001a200620093b019604200541f0006a41086a20054190016a41086a290300370300200541f0006a41106a20054190016a41106a290300370300200541f0006a41186a20054190016a41186a290300370300200541b0016a41086a200541c0006a41086a2802003602002005200529039001370370200520052903403703b0012006200f20081b2212200a4105746a21010240024020122f0196042209200a4b0d0020012002290000370000200141186a200241186a290000370000200141106a200241106a290000370000200141086a200241086a2900003700000c010b2012200a41016a220c4105746a20012009200a6b221041057410fe8d8080001a200141186a200241186a290000370000200141106a200241106a290000370000200141086a200241086a29000037000020012002290000370000201241e0026a2202200c4104746a2002200a4104746a201041047410fe8d8080001a0b2007410020081b210b2012200a4104746a220241e8026a200341086a290200370200200241e0026a2003290200370200200541106a41086a2202200541f0006a41086a290300370300200541106a41106a2201200541f0006a41106a290300370300200541106a41186a2203200541f0006a41186a290300370300200541e0006a41086a220c200541b0016a41086a2802003602002012200941016a3b01960420052005290370370310200520052903b0013703602011418080808078470d01201221060b2000200a3602082000200b360204200020063602000c010b200541c0006a41186a2003290300370300200541c0006a41106a2001290300370300200541c0006a41086a200229030037030020052005290310370340200541306a41086a200c2802003602002005200529036037033002400240024020062802900422020d00410021130c010b41002113200f21142011211503402002210c20072013470d0720062f0194042106024002400240200c2f0196042213410b490d0041012108200641054f0d0120062103410421060c020b200641016a2102201341016a2109200c20064105746a21010240024020062013490d0020012005290340370000200141186a200541c0006a41186a290300370000200141106a200541c0006a41106a290300370000200141086a200541c0006a41086a290300370000200c20064104746a220141e0026a2015360200200141e4026a2005290330370200200141ec026a200541306a41086a2802003602000c010b200c20024105746a2001201320066b220741057410fe8d8080001a200141186a200541c0006a41186a290300370000200141106a200541c0006a41106a290300370000200141086a200541c0006a41086a29030037000020012005290340370000200c41e0026a220120024104746a200120064104746a2201200741047410fe8d8080001a20012015360200200120052903303702042001410c6a200541306a41086a2802003602002006410274200c4198046a22016a41086a200120024102746a200741027410fe8d8080001a0b200c20093b019604200c20024102746a4198046a20143602002002201341026a22074f0d040240201320066b220341016a4103712201450d00200c20064102746a419c046a210603402006280200220920023b0194042009200c36029004200641046a2106200241016a21022001417f6a22010d000b0b20034103490d042002410274200c6a41a4046a21060340200641746a280200220120023b0194042001200c36029004200641786a2802002201200241016a3b0194042001200c360290042006417c6a2802002201200241026a3b0194042001200c3602900420062802002201200241036a3b0194042001200c36029004200641106a21062007200241046a2202470d000c050b0b20062103024002402006417b6a0e020201000b200641796a210341002108410621060c010b4100210841052106410021030b41002d00fca3c680001a41c80441002802c8a3c6800011818080800000220d450d08200d41003b019604200d41003602900420054190016a41086a220f200c20064105746a220141086a29000037030020054190016a41106a2210200141106a29000037030020054190016a41186a220e200141186a290000370300200541b0016a41086a2216200c41e0026a221720064104746a2209410c6a280200360200200d200c2f01960422112006417f736a22023b0196042005200129000037039001200520092902043703b0012002410c4f0d092011200641016a22016b2002470d0a20092802002111200d200c20014105746a200241057410848e808000220941e0026a201720014104746a200241047410848e8080001a200c20063b019604200541f0006a41086a2218200f290300370300200541f0006a41106a22192010290300370300200541f0006a41186a221a200e290300370300200541e0006a41086a221b20162802003602002005200529039001370370200520052903b00137036020092f019604220241016a21172002410c4f0d0b201320066b22062017470d0c200741016a211320094198046a200c20014102746a4198046a200641027410848e80800021074100210602400340200720064102746a280200220120063b0194042001200936029004200620024f0d01200620062002496a220620024d0d000b0b200e201a29030037030020102019290300370300200f20182903003703002016201b2802003602002005200529037037039001200520052903603703b001200c200920081b220220034105746a210102400240200341016a220620022f01960422074d0d0020012005290340370000200141186a200541c0006a41186a290300370000200141106a200541c0006a41106a290300370000200141086a200541c0006a41086a2903003700000c010b200220064105746a2001200720036b220841057410fe8d8080001a200141186a200541c0006a41186a290300370000200141106a200541c0006a41106a290300370000200141086a200541c0006a41086a29030037000020012005290340370000200241e0026a220120064104746a200120034104746a200841047410fe8d8080001a0b200741016a2117200220034104746a220141e0026a2015360200200141e4026a2005290330370200200141ec026a200541306a41086a221528020036020020024198046a21010240200341026a2218200741026a22084f0d00200120184102746a200120064102746a200720036b41027410fe8d8080001a0b200120064102746a2014360200200220173b0196040240200620084f0d000240200720036b221441016a4103712207450d00200220034102746a419c046a210103402001280200220320063b0194042003200236029004200141046a2101200641016a21062007417f6a22070d000b0b20144103490d00200220064102746a41a4046a21010340200141746a280200220720063b0194042007200236029004200141786a2802002207200641016a3b01940420072002360290042001417c6a2802002207200641026a3b019404200720023602900420012802002207200641036a3b0194042007200236029004200141106a21012008200641046a2206470d000b0b200541106a41186a2206200e290300370300200541106a41106a22022010290300370300200541106a41086a2201200f290300370300200541086a220720162802003602002005200529039001370310200520052903b0013703002011418080808078460d02200541c0006a41186a2006290300370300200541c0006a41106a2002290300370300200541c0006a41086a20012903003703002015200728020036020020052005290310370340200520052903003703302009211420132107200c210620112115200c2802900422020d000b0b200428020022022802002201450d0b2002280204210941002d00fca3c680001a41c80441002802c8a3c68000118180808000002206450d0c2006200136029804200641003b019604200641003602900420022006360200200141003b01940420012006360290042002200941016a36020420092013470d0d20062f0196042202410b4f0d0e2006200241016a22093b019604200620024105746a22012005290340370200200141086a200541c0006a41086a290300370200200141186a200541c0006a41186a290300370200200141106a200541c0006a41106a290300370200200620024104746a220241e0026a2011360200200241e4026a2005290330370200200241ec026a200541306a41086a28020036020020064198046a20094102746a200d360200200d20093b019404200d2006360290040b2000200a3602082000200b360204200020123602000b200541c0016a2480808080000f0b410441980410b280808000000b2001410b41bccdc28000109581808000000b4184cdc28000412841accdc2800010f880808000000b41dccdc2800041354194cec2800010f880808000000b410441c80410b280808000000b2002410b41bccdc28000109581808000000b4184cdc28000412841accdc2800010f880808000000b2017410c41cccdc28000109581808000000b4184cdc28000412841accdc2800010f880808000000b4184cbc2800010a081808000000b410441c80410b280808000000b41b4ccc28000413041e4ccc2800010f880808000000b4194cbc28000412041f4ccc2800010f880808000000ba61601137f23808080800041d0026b220424808080800002400240024002400240024002400240024002400240024002400240024002400240024002400240200128020022052f01f6062206410b490d004101210741042106200128020822084105490d03200821062008417b6a0e020302010b2001280204210902402001280208220841016a220120064b0d002005200141d0006c6a2005200841d0006c6a200620086b41d0006c10fe8d8080001a0b2005200841d0006c6a200241d00010848e8080001a2005200641016a3b01f6060c030b200841796a210841002107410621060c010b4100210741052106410021080b2001280204210a41002d00fca3c680001a41f80641002802c8a3c6800011818080800000220b450d03200b41003b01f606200b41003602f006200b20052f01f606220c2006417f736a22013b01f60620044180026a2005200641d0006c6a220d41cc0010848e8080001a200441e2006a200d41cf006a2d00003a00002004200d2f004d3b01602001410c4f0d04200c200641016a220e6b2001470d05200d2d004c210f200b2005200e41d0006c6a200141d0006c10848e808000210d200520063b01f606200441b0016a20044180026a41cc0010848e8080001a200441fc016a41026a2206200441e0006a41026a2d00003a0000200420042f01603b01fc0102402005200d20071b22102f01f606220120084d0d002010200841d0006c6a220c41d0006a200c200120086b41d0006c10fe8d8080001a0b200a410020071b21092010200841d0006c6a200241d00010848e8080001a2010200141016a3b01f606200441106a200441b0016a41cc0010848e8080001a200441ac016a41026a20062d00003a0000200420042f01fc013b01ac01200f41ff01714102470d01201021050b2000200836020820002009360204200020053602000c010b200441e0006a200441106a41cc0010848e8080001a200441dc006a41026a2211200441ac016a41026a22122d00003a0000200420042f01ac013b015c0240024020052802f00622010d00410021130c010b200441fc016a41026a210e41002113200d2114200f2115034020012107200a2013470d0620052f01f40621050240024002400240024020072f01f6062213410b490d0041012116200541054f0d012005210d410421050c020b200541016a21010240200520134f22020d002007200141d0006c6a2007200541d0006c6a201320056b41d0006c10fe8d8080001a0b201341016a210d2007200541d0006c6a200441e0006a41cc0010848e808000220620153a004c200620042f015c3b004d200641cf006a200441dc006a41026a2d00003a0000200741f8066a2106201341026a210a024020020d00200541027420066a41086a200620014102746a201320056b41027410fe8d8080001a0b2007200d3b01f606200620014102746a20143602002001200a4f0d020240201320056b220d41016a4103712206450d00200720054102746a41fc066a210503402005280200220220013b01f406200220073602f006200541046a2105200141016a21012006417f6a22060d000b0b200d4103490d02200141027420076a4184076a21050340200541746a280200220620013b01f406200620073602f006200541786a2802002206200141016a3b01f406200620073602f0062005417c6a2802002206200141026a3b01f406200620073602f00620052802002206200141036a3b01f406200620073602f006200541106a2105200a200141046a2201470d000c030b0b2005210d024002402005417b6a0e020201000b200541796a210d41002116410621050c010b41002116410521054100210d0b41002d00fca3c680001a41a80741002802c8a3c6800011818080800000220b450d09200b41003b01f606200b41003602f006200b20072f01f60622022005417f736a22013b01f60620044180026a2007200541d0006c6a220641cc0010848e8080001a200e200641cf006a2d00003a0000200420062f004d3b01fc012001410c4f0d0a2002200541016a220c6b2001470d0b20062d004c210f200b2007200c41d0006c6a200141d0006c10848e8080002102200720053b01f606200441b0016a20044180026a41cc0010848e8080001a2012200e2d00003a0000200420042f01fc013b01ac0120022f01f606220141016a21062001410c4f0d0c201320056b22052006470d0d200a41016a2113200241f8066a2007200c4102746a41f8066a200541027410848e808000210a4100210502400340200a20054102746a280200220620053b01f406200620023602f006200520014f0d01200520052001496a220520014d0d000b0b20044180026a200441b0016a41cc0010848e8080001a200e20122d00003a0000200420042f01ac013b01fc010240200d41016a22052007200220161b22062f01f60622014b0d002006200541d0006c6a2006200d41d0006c6a2001200d6b41d0006c10fe8d8080001a0b200141016a21162006200d41d0006c6a200441e0006a41cc0010848e808000220a20153a004c200a20042f015c3b004d200a41cf006a20112d00003a0000200641f8066a210a0240200d41026a2215200141026a220c4f0d00200a20154102746a200a20054102746a2001200d6b41027410fe8d8080001a0b200a20054102746a2014360200200620163b01f60602402005200c4f0d0002402001200d6b221641016a410371220a450d002006200d4102746a41fc066a210103402001280200220d20053b01f406200d20063602f006200141046a2101200541016a2105200a417f6a220a0d000b0b20164103490d00200620054102746a4184076a21010340200141746a280200220a20053b01f406200a20063602f006200141786a280200220a200541016a3b01f406200a20063602f0062001417c6a280200220a200541026a3b01f406200a20063602f0062001280200220a200541036a3b01f406200a20063602f006200141106a2101200c200541046a2205470d000b0b200441106a20044180026a41cc0010848e8080001a2004410c6a41026a2205200e2d00003a0000200420042f01fc013b010c200f41ff01714102470d010b2000200836020820002009360204200020103602000c030b200441e0006a200441106a41cc0010848e8080001a201120052d00003a0000200420042f010c3b015c200221142013210a20072105200f211520072802f00622010d000b0b200328020022012802002206450d0a2001280204210241002d00fca3c680001a41a80741002802c8a3c68000118180808000002205450d0b200520063602f806200541003b01f606200541003602f00620012005360200200641003b01f406200620053602f0062001200241016a36020420022013470d0c20052f01f6062201410b4f0d0d2005200141016a22063b01f6062005200141d0006c6a200441e0006a41cc0010848e8080002201200f3a004c200120042f015c3b004d200141cf006a200441dc006a41026a2d00003a0000200541f8066a20064102746a200b360200200020083602082000200936020420002010360200200b20063b01f406200b20053602f0060b200441d0026a2480808080000f0b410441f80610b280808000000b2001410b41bccdc28000109581808000000b4184cdc28000412841accdc2800010f880808000000b41dccdc2800041354194cec2800010f880808000000b410441a80710b280808000000b2001410b41bccdc28000109581808000000b4184cdc28000412841accdc2800010f880808000000b2006410c41cccdc28000109581808000000b4184cdc28000412841accdc2800010f880808000000b4184cbc2800010a081808000000b410441a80710b280808000000b41b4ccc28000413041e4ccc2800010f880808000000b4194cbc28000412041f4ccc2800010f880808000000b9718050b7f017e037f017e037f23808080800041c0006b220524808080800002400240024002400240024002400240024002400240024002400240024002400240024002400240200128020022062f01ba022207410b490d004101210841042107200128020822094105490d03200921072009417b6a0e020302010b200641b4016a220820012802082209410c6c6a210a2001280204210b02400240200941016a220120074d0d00200a2002290200370200200a41086a200241086a2802003602000c010b20082001410c6c6a200a200720096b2208410c6c10fe8d8080001a200a41086a200241086a280200360200200a2002290200370200200620014104746a200620094104746a200841047410fe8d8080001a0b200620094104746a220141086a200341086a290200370200200120032902003702002006200741016a3b01ba020c030b200941796a210941002108410621070c010b4100210841052107410021090b2001280204210a41002d00fca3c680001a41bc0241002802c8a3c6800011818080800000220c450d03200c41003b01ba02200c41003602b001200c20062f01ba02220d2007417f736a22013b01ba02200541306a41086a200620074104746a220e41086a2902003703002005200e2902003703302001410c4f0d04200d200741016a220e6b2001470d05200641b4016a220d2007410c6c6a220f2902042110200f280200210f200c41b4016a200d200e410c6c6a2001410c6c10848e8080001a200c2006200e4104746a200141047410848e808000210e200620073b01ba02200541206a41086a200541306a41086a290300370300200520052903303703202006200e20081b221141b4016a220d2009410c6c6a21010240024020112f01ba02220720094b0d0020012002290200370200200141086a200241086a2802003602000c010b200d200941016a2212410c6c6a2001200720096b220d410c6c10fe8d8080001a200141086a200241086a28020036020020012002290200370200201120124104746a201120094104746a200d41047410fe8d8080001a0b200a410020081b210b201120094104746a220141086a200341086a29020037020020012003290200370200200541086a2201200541206a41086a2903003703002011200741016a3b01ba0220052005290320370300200f418080808078470d01201121060b200020093602082000200b360204200020063602000c010b200541106a41086a2001290300370300200520052903003703100240024020062802b00122010d00410021120c010b41002112200e211320102114200f2115034020012108200a2012470d0620062f01b80221060240024002400240024020082f01ba022212410b490d004101210e200641054f0d0120062102410421060c020b200841b4016a220a2006410c6c6a2107200641016a2101201241016a21030240024020062012490d002007201437020420072015360200200820064104746a22072005290310370200200741086a200541106a41086a2903003702000c010b200a2001410c6c6a2007201220066b220a410c6c10fe8d8080001a2007201437020420072015360200200820014104746a200820064104746a2207200a41047410fe8d8080001a200741086a200541106a41086a290300370200200720052903103702002006410274200841bc026a22076a41086a200720014102746a200a41027410fe8d8080001a0b200820033b01ba02200820014102746a41bc026a20133602002001201241026a220a4f0d020240201220066b220241016a4103712207450d00200820064102746a41c0026a210603402006280200220320013b01b802200320083602b001200641046a2106200141016a21012007417f6a22070d000b0b20024103490d02200141027420086a41c8026a21060340200641746a280200220720013b01b802200720083602b001200641786a2802002207200141016a3b01b802200720083602b0012006417c6a2802002207200141026a3b01b802200720083602b00120062802002207200141036a3b01b802200720083602b001200641106a2106200a200141046a2201470d000c030b0b20062102024002402006417b6a0e020201000b200641796a21024100210e410621060c010b4100210e41052106410021020b41002d00fca3c680001a41ec0241002802c8a3c6800011818080800000220c450d09200c41003b01ba02200c41003602b001200c20082f01ba0222032006417f736a22013b01ba02200541306a41086a220d200820064104746a220741086a290200370300200520072902003703302001410c4f0d0a2003200641016a22076b2001470d0b200841b4016a22032006410c6c6a220f2902042110200f280200210f200c41b4016a20032007410c6c6a2001410c6c10848e8080001a200c200820074104746a200141047410848e8080002103200820063b01ba02200541206a41086a2216200d2903003703002005200529033037032020032f01ba02220141016a21172001410c4f0d0c201220066b22062017470d0d200a41016a2112200341bc026a200820074102746a41bc026a200641027410848e808000210a4100210602400340200a20064102746a280200220720063b01b802200720033602b001200620014f0d01200620062001496a220620014d0d000b0b200d20162903003703002005200529032037033020082003200e1b220141b4016a220e2002410c6c6a210a02400240200241016a220620012f01ba0222074d0d00200a2014370204200a20153602000c010b200e2006410c6c6a200a200720026b220e410c6c10fe8d8080001a200a2014370204200a2015360200200120064104746a200120024104746a200e41047410fe8d8080001a0b200741016a2115200120024104746a220a2005290310370200200a41086a200541106a41086a2217290300370200200141bc026a210a0240200241026a2216200741026a220e4f0d00200a20164102746a200a20064102746a200720026b41027410fe8d8080001a0b200a20064102746a2013360200200120153b01ba0202402006200e4f0d000240200720026b221341016a410371220a450d00200120024102746a41c0026a210703402007280200220220063b01b802200220013602b001200741046a2107200641016a2106200a417f6a220a0d000b0b20134103490d00200120064102746a41c8026a21070340200741746a280200220a20063b01b802200a20013602b001200741786a280200220a200641016a3b01b802200a20013602b0012007417c6a280200220a200641026a3b01b802200a20013602b0012007280200220a200641036a3b01b802200a20013602b001200741106a2107200e200641046a2206470d000b0b200541086a2206200d29030037030020052005290330370300200f418080808078470d010b200020093602082000200b360204200020113602000c030b2017200629030037030020052005290300370310200321132012210a2008210620102114200f211520082802b00122010d000b0b200428020022012802002207450d0a2001280204210341002d00fca3c680001a41ec0241002802c8a3c68000118180808000002206450d0b200620073602bc02200641003b01ba02200641003602b00120012006360200200741003b01b802200720063602b0012001200341016a36020420032012470d0c20062f01ba022201410b4f0d0d2006200141016a22073b01ba0220062001410c6c6a220341b8016a2010370200200341b4016a200f360200200620014104746a220141086a200541106a41086a29030037020020012005290310370200200641bc026a20074102746a200c360200200020093602082000200b36020420002011360200200c20073b01b802200c20063602b0010b200541c0006a2480808080000f0b410441bc0210b280808000000b2001410b41bccdc28000109581808000000b4184cdc28000412841accdc2800010f880808000000b41dccdc2800041354194cec2800010f880808000000b410441ec0210b280808000000b2001410b41bccdc28000109581808000000b4184cdc28000412841accdc2800010f880808000000b2017410c41cccdc28000109581808000000b4184cdc28000412841accdc2800010f880808000000b4184cbc2800010a081808000000b410441ec0210b280808000000b41b4ccc28000413041e4ccc2800010f880808000000b4194cbc28000412041f4ccc2800010f880808000000b9718050b7f017e037f017e037f23808080800041c0006b220524808080800002400240024002400240024002400240024002400240024002400240024002400240024002400240200128020022062f01ba022207410b490d004101210841042107200128020822094105490d03200921072009417b6a0e020302010b200641b4016a220820012802082209410c6c6a210a2001280204210b02400240200941016a220120074d0d00200a2002290200370200200a41086a200241086a2802003602000c010b20082001410c6c6a200a200720096b2208410c6c10fe8d8080001a200a41086a200241086a280200360200200a2002290200370200200620014104746a200620094104746a200841047410fe8d8080001a0b200620094104746a220141086a200341086a290200370200200120032902003702002006200741016a3b01ba020c030b200941796a210941002108410621070c010b4100210841052107410021090b2001280204210a41002d00fca3c680001a41bc0241002802c8a3c6800011818080800000220c450d03200c41003b01ba02200c41003602b001200c20062f01ba02220d2007417f736a22013b01ba02200541306a41086a200620074104746a220e41086a2902003703002005200e2902003703302001410c4f0d04200d200741016a220e6b2001470d05200641b4016a220d2007410c6c6a220f2902042110200f280200210f200c41b4016a200d200e410c6c6a2001410c6c10848e8080001a200c2006200e4104746a200141047410848e808000210e200620073b01ba02200541206a41086a200541306a41086a290300370300200520052903303703202006200e20081b221141b4016a220d2009410c6c6a21010240024020112f01ba02220720094b0d0020012002290200370200200141086a200241086a2802003602000c010b200d200941016a2212410c6c6a2001200720096b220d410c6c10fe8d8080001a200141086a200241086a28020036020020012002290200370200201120124104746a201120094104746a200d41047410fe8d8080001a0b200a410020081b210b201120094104746a220141086a200341086a29020037020020012003290200370200200541086a2201200541206a41086a2903003703002011200741016a3b01ba0220052005290320370300200f418080808078470d01201121060b200020093602082000200b360204200020063602000c010b200541106a41086a2001290300370300200520052903003703100240024020062802b00122010d00410021120c010b41002112200e211320102114200f2115034020012108200a2012470d0620062f01b80221060240024002400240024020082f01ba022212410b490d004101210e200641054f0d0120062102410421060c020b200841b4016a220a2006410c6c6a2107200641016a2101201241016a21030240024020062012490d002007201437020420072015360200200820064104746a22072005290310370200200741086a200541106a41086a2903003702000c010b200a2001410c6c6a2007201220066b220a410c6c10fe8d8080001a2007201437020420072015360200200820014104746a200820064104746a2207200a41047410fe8d8080001a200741086a200541106a41086a290300370200200720052903103702002006410274200841bc026a22076a41086a200720014102746a200a41027410fe8d8080001a0b200820033b01ba02200820014102746a41bc026a20133602002001201241026a220a4f0d020240201220066b220241016a4103712207450d00200820064102746a41c0026a210603402006280200220320013b01b802200320083602b001200641046a2106200141016a21012007417f6a22070d000b0b20024103490d02200141027420086a41c8026a21060340200641746a280200220720013b01b802200720083602b001200641786a2802002207200141016a3b01b802200720083602b0012006417c6a2802002207200141026a3b01b802200720083602b00120062802002207200141036a3b01b802200720083602b001200641106a2106200a200141046a2201470d000c030b0b20062102024002402006417b6a0e020201000b200641796a21024100210e410621060c010b4100210e41052106410021020b41002d00fca3c680001a41ec0241002802c8a3c6800011818080800000220c450d09200c41003b01ba02200c41003602b001200c20082f01ba0222032006417f736a22013b01ba02200541306a41086a220d200820064104746a220741086a290200370300200520072902003703302001410c4f0d0a2003200641016a22076b2001470d0b200841b4016a22032006410c6c6a220f2902042110200f280200210f200c41b4016a20032007410c6c6a2001410c6c10848e8080001a200c200820074104746a200141047410848e8080002103200820063b01ba02200541206a41086a2216200d2903003703002005200529033037032020032f01ba02220141016a21172001410c4f0d0c201220066b22062017470d0d200a41016a2112200341bc026a200820074102746a41bc026a200641027410848e808000210a4100210602400340200a20064102746a280200220720063b01b802200720033602b001200620014f0d01200620062001496a220620014d0d000b0b200d20162903003703002005200529032037033020082003200e1b220141b4016a220e2002410c6c6a210a02400240200241016a220620012f01ba0222074d0d00200a2014370204200a20153602000c010b200e2006410c6c6a200a200720026b220e410c6c10fe8d8080001a200a2014370204200a2015360200200120064104746a200120024104746a200e41047410fe8d8080001a0b200741016a2115200120024104746a220a2005290310370200200a41086a200541106a41086a2217290300370200200141bc026a210a0240200241026a2216200741026a220e4f0d00200a20164102746a200a20064102746a200720026b41027410fe8d8080001a0b200a20064102746a2013360200200120153b01ba0202402006200e4f0d000240200720026b221341016a410371220a450d00200120024102746a41c0026a210703402007280200220220063b01b802200220013602b001200741046a2107200641016a2106200a417f6a220a0d000b0b20134103490d00200120064102746a41c8026a21070340200741746a280200220a20063b01b802200a20013602b001200741786a280200220a200641016a3b01b802200a20013602b0012007417c6a280200220a200641026a3b01b802200a20013602b0012007280200220a200641036a3b01b802200a20013602b001200741106a2107200e200641046a2206470d000b0b200541086a2206200d29030037030020052005290330370300200f418080808078470d010b200020093602082000200b360204200020113602000c030b2017200629030037030020052005290300370310200321132012210a2008210620102114200f211520082802b00122010d000b0b200428020022012802002207450d0a2001280204210341002d00fca3c680001a41ec0241002802c8a3c68000118180808000002206450d0b200620073602bc02200641003b01ba02200641003602b00120012006360200200741003b01b802200720063602b0012001200341016a36020420032012470d0c20062f01ba022201410b4f0d0d2006200141016a22073b01ba0220062001410c6c6a220341b8016a2010370200200341b4016a200f360200200620014104746a220141086a200541106a41086a29030037020020012005290310370200200641bc026a20074102746a200c360200200020093602082000200b36020420002011360200200c20073b01b802200c20063602b0010b200541c0006a2480808080000f0b410441bc0210b280808000000b2001410b41bccdc28000109581808000000b4184cdc28000412841accdc2800010f880808000000b41dccdc2800041354194cec2800010f880808000000b410441ec0210b280808000000b2001410b41bccdc28000109581808000000b4184cdc28000412841accdc2800010f880808000000b2017410c41cccdc28000109581808000000b4184cdc28000412841accdc2800010f880808000000b4184cbc2800010a081808000000b410441ec0210b280808000000b41b4ccc28000413041e4ccc2800010f880808000000b4194cbc28000412041f4ccc2800010f880808000000b8d11030b7f037e047f23808080800041206b220324808080800020002802002104024020002802042205450d0002400240200541037122060d00200521070c010b2005210703402007417f6a2107200420042f01e2014102746a41e4016a28020021042006417f6a22060d000b0b20054104490d000340200420042f01e2014102746a41e4016a280200220420042f01e2014102746a41e4016a280200220420042f01e2014102746a41e4016a280200220420042f01e2014102746a41e4016a28020021042007417c6a22070d000b0b20012802202108200128021c2109200128021821062001280214210a2001280210210b200128020c210c2001280208210d2001290200210e0340200bad422086200cad84210f02400240034002400240200d418180808078460d0020062107200d2105200e21100c010b20062008460d02200641146a2107200629020c210f20062802082105200629020021100b02402005418080808078460d00200fa72111024020072008470d00418080808078210d200821060c040b200741146a21062007280210210b200728020c210c2007290200210e02402007280208220d418080808078470d00418080808078210d0c040b2010200e520d03200729020c210f2010210e2005450d01201141002802c0a3c68000118080808000002010210e0c010b0b20082007460d00200820076b220441146e220141017121054100210602402004416c6a4114490d00200741206a2104200141feffffff007121014100210603400240200441686a280200450d002004416c6a28020041002802c0a3c68000118080808000000b02402004417c6a280200450d00200428020041002802c0a3c68000118080808000000b200441286a21042001200641026a2206470d000b0b2005450d002007200641146c6a2204280208450d00200441086a28020441002802c0a3c68000118080808000000b02402009450d00200a41002802c0a3c68000118080808000000b02402000280204220d450d00200028020021060340024002400240024020062f01e2012207450d00200641e4016a220520074102746a28020022042f01e201220141054f0d0320052007417f6a22084102746a28020022052f01e2012207410520016b2212490d012005200720126b22133b01e201200441053b01e201200420124103746a2004200141037410fe8d8080001a200441dc006a220b2012410c6c6a200b2001410c6c10fe8d8080001a2007201341016a22116b220c410420016b470d022004200520114103746a200c410374220010848e8080002107200b200541dc006a22022011410c6c6a200c410c6c220c10848e808000210b200341086a20022013410c6c6a220241086a28020022143602002002290200210e200620084103746a220229000021102002200520134103746a2900003700002003200e37030020062008410c6c6a220641dc006a2213290200210f2013200e370200200641e4006a2206280200211320062014360200200720006a2010370000200b200c6a220641086a20133602002006200f370200200d4101460d03200741e4016a2206201241027422126a2006200141027441046a10fe8d8080001a2006200520114102746a41e4016a201210848e8080001a20072802e401220641003b01e00120062007360258200741e8016a280200220641013b01e00120062007360258200741ec016a280200220641023b01e00120062007360258200741f0016a280200220641033b01e00120062007360258200741f4016a280200220641043b01e00120062007360258200741f8016a280200220641053b01e001200620073602580c030b41dccec28000411941f8cec2800010f880808000000b41a4cec28000412741cccec2800010f880808000000b4184cdc28000412841accdc2800010f880808000000b20042106200d417f6a220d0d000b0b200341206a2480808080000f0b200f422088a72114024002400240024002400240024020042f01e2012207410b490d004100211302400240034020042802582204450d01201341016a211320042f01e201410b4f0d000c020b0b200028020421012000280200210741002d00fca3c680001a41940241002802c8a3c68000118180808000002204450d02200420073602e401200441003b01e2012004410036025820002004360200200741003b01e001200720043602582000200141016a22133602040b41002d00fca3c680001a41e40141002802c8a3c68000118180808000002201450d02200141003b01e201200141003602582013417f6a2212450d04034041002d00fca3c680001a41940241002802c8a3c68000118180808000002207450d04200720013602e401200741003b01e20120074100360258200141003b01e00120012007360258200721012012417f6a2212450d050c000b0b2004200741016a3b01e201200420074103746a201037000020042007410c6c6a220741e4006a2014360200200741e0006a2011360200200741dc006a20053602000c040b410441940210b280808000000b410441e40110b280808000000b410441940210b280808000000b20042f01e2012207410b4f0d012004200741016a22123b01e201200420074103746a201037000020042007410c6c6a220741e0006a2011360200200741dc006a2005360200200741e4006a2014360200200420124102746a41e4016a2001360200200120123b01e001200120043602582013450d0002400240201341037122010d00201321070c010b2013210703402007417f6a2107200420042f01e2014102746a41e4016a28020021042001417f6a22010d000b0b20134104490d000340200420042f01e2014102746a41e4016a280200220420042f01e2014102746a41e4016a280200220420042f01e2014102746a41e4016a280200220420042f01e2014102746a41e4016a28020021042007417c6a22070d000b0b2002200228020041016a3602000c010b0b4194cbc28000412041f4ccc2800010f880808000000bc513020f7f057e23808080800041c0016b220324808080800020002802002104024020002802042205450d0002400240200541037122060d00200521070c010b2005210703402007417f6a2107200420042f01e6024102746a41e8026a28020021042006417f6a22060d000b0b20054104490d000340200420042f01e6024102746a41e8026a280200220420042f01e6024102746a41e8026a280200220420042f01e6024102746a41e8026a280200220420042f01e6024102746a41e8026a28020021042007417c6a22070d000b0b200341306a200141306a280200360200200341286a200141286a290200370300200341206a200141206a290200370300200341186a200141186a290200370300200341106a200141106a290200370300200341086a200141086a2902003703002003200129020037030020034198016a41016a2108200341116a21090240034020032802042106200328020c210a0240024020032d001022074102460d0020082009290000370000200841186a200941186a290000370000200841106a200941106a290000370000200841086a200941086a29000037000020070d010c030b2006200a460d0220082006290000370000200841086a200641086a290000370000200841106a200641106a290000370000200841186a200641186a2900003700002003200641206a22063602040b200341f8006a41186a220b200841186a290000370300200341f8006a41106a220c200841106a290000370300200341f8006a41086a220d200841086a29000037030020032008290000370378024002402006200a460d0020092006290000370000200941086a2201200641086a220e290000370000200941106a2205200641106a220f290000370000200941186a2210200641186a22112900003700002003200641206a220736020402400240200341f8006a2009412010888e8080000d00200d200e290000370300200c200f290000370300200b2011290000370300200320062900003703782007200a460d0102400340200920072900003700002001200741086a2900003700002005200741106a2900003700002010200741186a290000370000200341f8006a2009412010888e8080000d01200d2001290000370300200c2005290000370300200b201029000037030020032009290000370378200741206a2207200a460d030c000b0b2003200741206a3602040b200341013a00100c020b2003200a3602040b2009200329039801370000200941086a20034198016a41086a290300370000200941106a20034198016a41106a290300370000200941186a20034198016a41186a290300370000200341003a00100b200341386a41186a2210200b290300370300200341386a41106a220a200c290300370300200341386a41086a220b200d29030037030020032003290378370338024002400240024002400240024020042f01e6022207410b490d004100210502400240034020042802e0022204450d01200541016a210520042f01e602410b4f0d000c020b0b200028020421062000280200210741002d00fca3c680001a41980341002802c8a3c68000118180808000002204450d02200420073602e802200441003b01e602200441003602e00220002004360200200741003b01e402200720043602e0022000200641016a22053602040b41002d00fca3c680001a41e80241002802c8a3c68000118180808000002206450d02200641003b01e602200641003602e0022005417f6a2201450d04034041002d00fca3c680001a41980341002802c8a3c68000118180808000002207450d04200720063602e802200741003b01e602200741003602e002200641003b01e402200620073602e002200721062001417f6a2201450d050c000b0b2004200741016a3b01e602200420074105746a22072003290338370000200741186a2010290300370000200741106a200a290300370000200741086a200b2903003700000c040b410441980310b280808000000b410441e80210b280808000000b410441980310b280808000000b20042f01e6022207410b4f0d012004200741016a22013b01e602200420074105746a22072003290338370000200741186a2010290300370000200741106a200a290300370000200741086a200b290300370000200420014102746a41e8026a2006360200200620013b01e402200620043602e0022005450d0002400240200541037122060d00200521070c010b2005210703402007417f6a2107200420042f01e6024102746a41e8026a28020021042006417f6a22060d000b0b20054104490d000340200420042f01e6024102746a41e8026a280200220420042f01e6024102746a41e8026a280200220420042f01e6024102746a41e8026a280200220420042f01e6024102746a41e8026a28020021042007417c6a22070d000b0b2002200228020041016a3602000c010b0b4194cbc28000412041f4ccc2800010f880808000000b02402003280208450d00200328020041002802c0a3c68000118080808000000b024020002802042205450d00200028020021060340024002400240024020062f01e6022204450d00200641e8026a220920044102746a28020022072f01e602220141054f0d0320092004417f6a220b4102746a28020022092f01e6022204410520016b2210490d012009200420106b22083b01e602200741053b01e602200720104105746a2007200141057410fe8d8080001a2004200841016a220a6b2204410420016b470d0220072009200a4105746a2004410574220c10848e80800021042006200b4105746a22062900002112200920084105746a220841086a2900002113200841106a2900002114200841186a290000211520062008290000370000200641186a2208290000211620082015370000200641106a2208290000211520082014370000200641086a22062900002114200620133700002004200c6a220641186a2016370000200641106a2015370000200641086a20143700002006201237000020054101460d05200441e8026a2206201041027422086a2006200141027441046a10fe8d8080001a20062009200a4102746a41e8026a200810848e8080001a20042802e802220641003b01e402200620043602e002200441ec026a280200220641013b01e402200620043602e002200441f0026a280200220641023b01e402200620043602e002200441f4026a280200220641033b01e402200620043602e002200441f8026a280200220641043b01e402200620043602e002200441fc026a280200220641053b01e402200620043602e0020c030b41dccec28000411941f8cec2800010f880808000000b41a4cec28000412741cccec2800010f880808000000b4184cdc28000412841accdc2800010f880808000000b200721062005417f6a22050d000b0b200341c0016a2480808080000b9e0f03087f017e027f23808080800041c0006b220324808080800020002802002104024020002802042205450d0002400240200541037122060d00200521070c010b2005210703402007417f6a2107200420042f018a014102746a418c016a28020021042006417f6a22060d000b0b20054104490d000340200420042f018a014102746a418c016a280200220420042f018a014102746a418c016a280200220420042f018a014102746a418c016a280200220420042f018a014102746a418c016a28020021042007417c6a22070d000b0b200341086a41186a2208200141186a280200360200200341086a41106a2209200141106a290200370300200341086a41086a200141086a29020037030020032001290200370308200341246a200341086a10b38980800002402003280224418080808078460d00200341246a41086a210a0240034002400240024002400240024020042f018a012207410b490d004100210502400240034020042802002204450d01200541016a210520042f018a01410b4f0d000c020b0b200028020421062000280200210741002d00fca3c680001a41bc0141002802c8a3c68000118180808000002204450d022004200736028c01200441003b018a012004410036020020002004360200200741003b018801200720043602002000200641016a22053602040b41002d00fca3c680001a418c0141002802c8a3c68000118180808000002206450d02200641003b018a01200641003602002005417f6a2201450d04034041002d00fca3c680001a41bc0141002802c8a3c68000118180808000002207450d042007200636028c01200741003b018a0120074100360200200641003b01880120062007360200200721062001417f6a2201450d050c000b0b2004200741016a3b018a012003290224210b20042007410c6c6a2207410c6a200a280200360200200741046a200b3702000c040b410441bc0110b280808000000b4104418c0110b280808000000b410441bc0110b280808000000b20042f018a012207410b4f0d022004200741016a22013b018a0120042007410c6c6a2207410c6a200a280200360200200741046a2003290224370200200420014102746a418c016a2006360200200620013b018801200620043602002005450d0002400240200541037122060d00200521070c010b2005210703402007417f6a2107200420042f018a014102746a418c016a28020021042006417f6a22060d000b0b20054104490d000340200420042f018a014102746a418c016a280200220420042f018a014102746a418c016a280200220420042f018a014102746a418c016a280200220420042f018a014102746a418c016a28020021042007417c6a22070d000b0b2002200228020041016a360200200341246a200341086a10b3898080002003280224418080808078470d000c020b0b4194cbc28000412041f4ccc2800010f880808000000b02402008280200220420092802002201460d00200420016b2204410c6e22064101712105410021070240200441746a410c490d00200641feffffff017121062001210441002107034002402004280200450d00200441046a28020041002802c0a3c68000118080808000000b02402004410c6a280200450d00200441106a28020041002802c0a3c68000118080808000000b200441186a21042006200741026a2207470d000b0b2005450d0020012007410c6c6a2204280200450d00200428020441002802c0a3c68000118080808000000b02402003411c6a280200450d00200328021441002802c0a3c68000118080808000000b024020032802082204418280808078480d002004450d00200328020c41002802c0a3c68000118080808000000b024020002802042201450d00200028020021070340024002400240024020072f018a012205450d002007418c016a220220054102746a28020022042f018a01220641054f0d0320022005417f6a220c4102746a28020022022f018a012200410520066b2205490d012002200020056b220a3b018a01200441053b018a01200441046a22082005410c6c6a20082006410c6c10fe8d8080001a2000200a41016a22096b2200410420066b470d022008200241046a220d2009410c6c6a2000410c6c220010848e8080002108200d200a410c6c6a220a41086a280200210d2007200c410c6c6a220741046a220c290200210b200c200a2902003702002007410c6a2207280200210a2007200d360200200820006a220741086a200a3602002007200b37020020014101460d052004418c016a2207200541027422056a2007200641027441046a10fe8d8080001a2007200220094102746a418c016a200510848e8080001a200428028c01220741003b0188012007200436020020044190016a280200220741013b0188012007200436020020044194016a280200220741023b0188012007200436020020044198016a280200220741033b018801200720043602002004419c016a280200220741043b01880120072004360200200441a0016a280200220741053b018801200720043602000c030b41dccec28000411941f8cec2800010f880808000000b41a4cec28000412741cccec2800010f880808000000b4184cdc28000412841accdc2800010f880808000000b200421072001417f6a22010d000b0b200341c0006a2480808080000be805010d7f200341246a280200200341c8006a2802002204200441284b22041b21052003280220200341206a20041b2106024002400240200341cc006a2d000041ff01712207450d00200341cd006a2d000041ff01712108034020012f01f606220941d0006c210a41002104417f210b4100210c024002400340200b210d200a2004460d010240417f2003200120046a220b412010888e808000220e410047200e4100481b220e0d00417f2006200b41206a220e280200200e200b41c8006a280200220f41284b22101b2005200b41246a280200200f20101b220e2005200e491b10888e808000220f2005200e6b200f1b220e410047200e4100481b220e0d0002402007200b41cc006a2d0000220f4f0d00200c21090c030b4101210e2007200f470d0002402008200b41cd006a2d000041ff0171220e4f0d00200c21090c030b2008200e47210e0b200c41016a210c200441d0006a2104200d41016a210b200e4101460d000b200e41ff0171450d01200d41016a21090b2002450d032002417f6a2102200120094102746a41f8066a28020021010c010b0b41002104200b21090c020b034020012f01f606220f41d0006c210c41002104417f2109024002400240024003400240200c2004470d00200f21090c030b0240417f2003200120046a220b412010888e808000220e410047200e4100481b220e0d00417f2006200b41206a220e280200200e200b41c8006a280200220d41284b220a1b2005200b41246a280200200d200a1b220e2005200e491b10888e808000220d2005200e6b200d1b220e410047200e4100481b220e450d020b200441d0006a2104200941016a2109200e4101460d000b200e41ff01710d01410021040c060b200b41cc006a2d0000450d01200941016a21090b20020d010c030b200941016a2109410021040c030b2002417f6a2102200120094102746a41f8066a28020021010c000b0b41012104410021020b20002001360204200020043602002000410c6a2009360200200041086a20023602000ba90402097f017e23808080800041306b22032480808080000240024002400240024002402001280204220441286e2205200220052002491b22050d00410821060c010b200541b3e6cc194b0d01200541286c2207417f4c0d0141002d00fca3c680001a200741002802c8a3c68000118180808000002206450d020b410021072003410036020c200320063602082003200536020402402002450d00200128020041206a2105034002402004411f4b0d00200328020421080c050b200120053602002001200441606a22063602042003280204210820064108490d042001200641786a22043602042001200541086a360200200341106a41086a2209200541606a220641086a290000370300200341106a41106a220a200641106a290000370300200341106a41186a220b200641186a290000370300200320062900003703102005290000210c024020072008470d00200341046a2007109a86808000200328020c21070b2003280208200741286c6a220620032903103703002006200c370320200641086a2009290300370300200641106a200a290300370300200641186a200b2903003703002003200741016a220736020c200541286a21052002417f6a22020d000b0b20002003290204370200200041086a200341046a41086a2802003602000c030b10ae80808000000b4108200710b280808000000b20004180808080783602002008450d00200328020841002802c0a3c68000118080808000000b200341306a2480808080000beb0301097f23808080800041306b22032480808080000240024002400240200128020422044105762205200220052002491b22050d00410121060c010b200541ffffff1f4b0d0120054105742207417f4c0d0141002d00fca3c680001a200741002802c8a3c68000118180808000002206450d020b410021072003410036020c20032006360208200320053602040240024002402002450d0020012802002105034020044120490d022001200441606a22043602042001200541206a2208360200200341106a41086a2209200541086a290000370300200341106a41106a220a200541106a290000370300200341106a41186a220b200541186a29000037030020032005290000370310024020072003280204470d00200341046a200710a18680800020032802082106200328020c21070b200620074105746a22052003290310370000200541186a200b290300370000200541106a200a290300370000200541086a20092903003700002003200741016a220736020c200821052002417f6a22020d000b0b20002003290204370200200041086a200341046a41086a2802003602000c010b20004180808080783602002003280204450d00200641002802c0a3c68000118080808000000b200341306a2480808080000f0b10ae80808000000b4101200710b280808000000b980501067f23808080800041c0006b2203248080808000410421040240024002400240200128020041046a28020041146e2205200220052002491b2205450d00200541e6cc99334b0d02200541146c2206417f4c0d0241002d00fca3c680001a200641002802c8a3c68000118180808000002204450d010b20012001280204220741016a2206360204200341003602102003200436020c2003200536020802400240200620012802084d0d0020004180808080783602000c010b024002402002450d00200341146a41017221040340200341146a2001109f8d80800020032d001422064105460d02200341286a410f6a22072004410f6a280000360000200341286a41086a2208200441086a290000370300200320042900003703280240200328021022052003280208470d00200341086a200510a586808000200328021021050b200328020c200541146c6a22052003290328370001200520063a0000200541096a2008290300370000200541106a20072800003600002003200328021041016a3602102002417f6a22020d000b2001280204417f6a21070b2001200736020420002003290208370200200041086a200341086a41086a2802003602000c040b200041808080807836020020032802102201450d00200328020c220621054100210403402006200441146c6a21020240024002400240024020052d00000e0400010102040b200541086a21020c020b200241086a21020c010b200241046a21020b2002280200450d00200228020441002802c0a3c68000118080808000000b200441016a2104200541146a21052001417f6a22010d000b0b2003280208450d02200328020c41002802c0a3c68000118080808000000c020b4104200610b280808000000b10ae80808000000b200341c0006a2480808080000ba204010a7f23808080800041306b2203248080808000410121040240024002402001280200220541046a2802004105762206200220062002491b2206450d00200641ffffff1f4b0d0120064105742207417f4c0d0141002d00fca3c680001a200741002802c8a3c68000118180808000002204450d020b20012001280204220841016a22073602042003410036020c200320043602082003200636020402400240200720012802084b0d00024002402002450d00200541046a220928020022064120490d0103402009200641606a36020020052005280200220641206a360200200341106a41086a220a200641086a290000370300200341106a41106a220b200641106a290000370300200341106a41186a220c200641186a290000370300200320062900003703100240200328020c22062003280204470d00200341046a200610a186808000200328020c21060b2003280208220420064105746a22072003290310370000200741086a200a290300370000200741106a200b290300370000200741186a200c2903003700002003200641016a36020c2002417f6a2202450d01200928020022064120490d020c000b0b2001200836020420002003290204370200200041086a200341046a41086a2802003602000c020b200328020421060b20004180808080783602002006450d00200441002802c0a3c68000118080808000000b200341306a2480808080000f0b10ae80808000000b4101200710b280808000000bda0401067f23808080800041c0006b220324808080800002400240024002400240200128020441146e2204200220042002491b22040d00410421050c010b200441e6cc99334b0d02200441146c2206417f4c0d0241002d00fca3c680001a200641002802c8a3c68000118180808000002205450d010b200341003602102003200536020c20032004360208024002402002450d00200341146a41017221050340200341146a2001109e8d80800020032d001422064105460d02200341286a410f6a22072005410f6a280000360000200341286a41086a2208200541086a290000370300200320052900003703280240200328021022042003280208470d00200341086a200410a586808000200328021021040b200328020c200441146c6a22042003290328370001200420063a0000200441096a2008290300370000200441106a20072800003600002003200328021041016a3602102002417f6a22020d000b0b20002003290208370200200041086a200341086a41086a2802003602000c030b2000418080808078360200024020032802102206450d00200328020c220721044100210503402007200541146c6a21020240024002400240024020042d00000e0400010102040b200441086a21020c020b200241086a21020c010b200241046a21020b2002280200450d00200228020441002802c0a3c68000118080808000000b200541016a2105200441146a21042006417f6a22060d000b0b2003280208450d02200328020c41002802c0a3c68000118080808000000c020b4104200610b280808000000b10ae80808000000b200341c0006a2480808080000beb0301097f23808080800041306b22032480808080000240024002400240200128020422044105762205200220052002491b22050d00410121060c010b200541ffffff1f4b0d0120054105742207417f4c0d0141002d00fca3c680001a200741002802c8a3c68000118180808000002206450d020b410021072003410036020c20032006360208200320053602040240024002402002450d0020012802002105034020044120490d022001200441606a22043602042001200541206a2208360200200341106a41086a2209200541086a290000370300200341106a41106a220a200541106a290000370300200341106a41186a220b200541186a29000037030020032005290000370310024020072003280204470d00200341046a200710a18680800020032802082106200328020c21070b200620074105746a22052003290310370000200541186a200b290300370000200541106a200a290300370000200541086a20092903003700002003200741016a220736020c200821052002417f6a22020d000b0b20002003290204370200200041086a200341046a41086a2802003602000c010b20004180808080783602002003280204450d00200641002802c0a3c68000118080808000000b200341306a2480808080000f0b10ae80808000000b4101200710b280808000000bb80302067f017e23808080800041106b2203248080808000024002400240024002400240200128020422044104762205200220052002491b22060d00410821070c010b200641ffffff3f4b0d0120064104742205417f4c0d0141002d00fca3c680001a200541002802c8a3c68000118180808000002207450d020b410021052003410036020c200320073602082003200636020402402002450d002001280200210603400240200441074b0d00200328020421080c050b2001200441786a22043602042001200641086a22073602002003280204210820044104490d042006290000210920012004417c6a22043602042001200741046a220636020020072800002107024020052008470d00200341046a200510a286808000200328020c21050b200328020820054104746a22052007360208200520093703002003200328020c41016a220536020c2002417f6a22020d000b0b20002003290204370200200041086a200341046a41086a2802003602000c030b10ae80808000000b4108200510b280808000000b20004180808080783602002008450d00200328020841002802c0a3c68000118080808000000b200341106a2480808080000bd70301057f23808080800041e0036b22032480808080000240024002400240200128020041046a28020041e8016e2204200220042002491b22040d00410821050c010b200441cbfbb4044b0d01200441e8016c2206417f4c0d0141002d00fca3c680001a200641002802c8a3c68000118180808000002205450d020b20012001280204220741016a22063602042003410036020c200320053602082003200436020402400240200620012802084b0d0002402002450d00200341106a41047221060340200341106a200110f58c80800020032802102205450d02200341fc016a200641e40110848e8080001a0240200328020c22042003280204470d00200341046a2004109786808000200328020c21040b2003280208200441e8016c6a22042005360200200441046a200341fc016a41e40110848e8080001a2003200328020c41016a36020c2002417f6a22020d000b2001280204417f6a21070b2001200736020420002003290204370200200041086a200341046a41086a2802003602000c010b2000418080808078360200200341046a108f878080002003280204450d00200328020841002802c0a3c68000118080808000000b200341e0036a2480808080000f0b10ae80808000000b4108200610b280808000000b9f0602077f027e23808080800041206b22032480808080004104210402400240024002400240024002400240200128020041046a280200410c6e2205200220052002491b2205450d00200541aad5aad5004b0d022005410c6c2206417f4c0d0241002d00fca3c680001a200641002802c8a3c68000118180808000002204450d010b20012001280204220741016a22063602042003410036021c2003200436021820032005360214200620012802084b0d032002450d050340200341086a200110bc8a80800020032802080d042001280200220641046a22072802002204200328020c2205490d040240024020050d00410121080c010b2005417f4c0d03200541002802c8a3c68000118180808000002208450d04200841002005108a8e8080001a200728020021040b0240200420054f0d00200841002802c0a3c68000118080808000000c050b200820062802002209200510848e80800021082007200420056b3602002006200920056a3602002005ad210a2008ad210b0240200328021c22042003280214470d00200341146a2004109986808000200328021c21040b20032802182004410c6c6a2204200a422086200b84370204200420053602002003200328021c41016a36021c2002417f6a2202450d050c000b0b4104200610b280808000000b10ae80808000000b4101200510b280808000000b20004180808080783602000240200328021c2205450d00200328021821022005410171210641002101024020054101460d002005417e7121042002210541002101034002402005280200450d00200541046a28020041002802c0a3c68000118080808000000b02402005410c6a280200450d00200541106a28020041002802c0a3c68000118080808000000b200541186a21052004200141026a2201470d000b0b2006450d0020022001410c6c6a2205280200450d00200528020441002802c0a3c68000118080808000000b2003280214450d02200328021841002802c0a3c68000118080808000000c020b2001280204417f6a21070b2001200736020420002003290214370200200041086a200341146a41086a2802003602000b200341206a2480808080000bb104010e7f23808080800041106b220324808080800002400240024002400240024020012802042204410c6e2205200220052002491b22050d00410421060c010b200541aad5aad5004b0d012005410c6c2207417f4c0d0141002d00fca3c680001a200741002802c8a3c68000118180808000002206450d020b410021072003410036020c200320063602082003200536020402402002450d002001280200210503400240200441074b0d00200328020421080c050b2001200441786a22043602042001200541086a22063602002003280204210820044104490d04200541076a2d00002109200541066a2d0000210a200541056a2d0000210b200541036a2d0000210c20052d0004210d20052d0002210e20052d0001210f20052d0000211020012004417c6a22043602042001200641046a220536020020062800002106024020072008470d00200341046a2007109986808000200328020c21070b20032802082007410c6c6a2207200e3a00022007200f3a0001200720103a000020072006360208200741036a200c3a00002007200d3a0004200741056a200b3a0000200741066a200a3a0000200741076a20093a00002003200328020c41016a220736020c2002417f6a22020d000b0b20002003290204370200200041086a200341046a41086a2802003602000c030b10ae80808000000b4104200710b280808000000b20004180808080783602002008450d00200328020841002802c0a3c68000118080808000000b200341106a2480808080000bf90401067f23808080800041c0006b220324808080800041042104024002400240200128020041046a28020041186e2205200220052002491b2205450d00200541d5aad52a4b0d01200541186c2206417f4c0d0141002d00fca3c680001a200641002802c8a3c68000118180808000002204450d020b20012001280204220741016a22063602042003410036020c2003200436020820032005360204024002400240200620012802084d0d0020004180808080783602000c010b024002402002450d00200341146a21040340200341106a200110fd8680800020032802102206418080808078460d02200341286a41106a2207200441106a280200360200200341286a41086a2208200441086a290200370300200320042902003703280240200328020c22052003280204470d00200341046a200510a686808000200328020c21050b2003280208200541186c6a22052003290328370204200520063602002005410c6a2008290300370200200541146a20072802003602002003200328020c41016a36020c2002417f6a22020d000b2001280204417f6a21070b2001200736020420002003290204370200200041086a200341046a41086a2802003602000c020b2000418080808078360200200328020c2204450d0020032802082105034002402005280200450d00200541046a28020041002802c0a3c68000118080808000000b02402005410c6a280200450d00200541106a28020041002802c0a3c68000118080808000000b200541186a21052004417f6a22040d000b0b2003280204450d00200328020841002802c0a3c68000118080808000000b200341c0006a2480808080000f0b10ae80808000000b4104200610b280808000000be10101037f0240024002402001280200220341046a28020022012002490d000240024020020d00410121040c010b2002417f4c0d02200241002802c8a3c68000118180808000002204450d03200441002002108a8e8080001a200341046a28020021010b024020012002490d00200420032802002205200210848e8080002104200341046a200120026b3602002003200520026a3602002000200236020020002002ad4220862004ad843702040f0b200441002802c0a3c68000118080808000000b20004180808080783602000f0b10ae80808000000b4101200210b280808000000bfb0101047f02400240200241ffffffff014b0d002001280200220341046a280200220420024103742201490d0002400240024002402002450d00200241ffffffff004b0d052001417f4c0d05200141002802c8a3c680001181808080000022050d014108200110b280808000000b410821050c010b200541002001108a8e8080002106200341046a28020022042001490d010b200520032802002206200110848e8080002105200341046a200420016b3602002003200620016a3602002000200236020020002002ad4220862005ad843702040f0b200641002802c0a3c68000118080808000000b20004180808080783602000f0b10ae80808000000bf90101047f23808080800041106b220324808080800002402001450d002001410c6c21040340024002402000280200418080808078470d00200341046a200041046a280200200041086a28020010b4828080000c010b200341046a2000280204200041086a28020010e6848080000b2003280208210502402002280200200228020822016b200328020c22064f0d0020022001200610b182808000200228020821010b200228020420016a2005200610848e8080001a2002200120066a36020802402003280204450d00200541002802c0a3c68000118080808000000b2000410c6a2100200441746a22040d000b0b200341106a2480808080000b8a0202057f017e23808080800041106b220324808080800002402001450d0020014103742104200228020821010340200341046a10b989808000200328020821050240200228020020016b200328020c22064f0d0020022001200610b182808000200228020821010b2002280204220720016a2005200610848e8080001a2002200120066a220636020802402003280204450d00200541002802c0a3c68000118080808000000b200029030021080240200228020020066b41074b0d0020022006410810b18280800020022802042107200228020821060b200041086a21002002200641086a2201360208200720066a2008370000200441786a22040d000b0b200341106a2480808080000bfd0101047f23808080800041106b220324808080800002402001450d00200141047421042000410c6a21010340200141786a280200210520032001417c6a28020022003602082003200341086a36020c2003410c6a200210c08a80800002402002280200200228020822066b20004f0d0020022006200010b182808000200228020821060b200228020420066a2005200010848e8080001a2002200620006a22003602080240200228020020006b41034b0d0020022000410410b182808000200228020821000b2002200041046a360208200228020420006a2001280200360000200141106a2101200441706a22040d000b0b200341106a2480808080000bab0201037f23808080800041206b22042480808080000240024002400240200141046a22050d00410121060c010b2005417f4c0d0141002d00fca3c680001a200541002802c8a3c68000118180808000002206450d020b20044100360214200420063602102004200536020c200420013602182004200441186a36021c2004411c6a2004410c6a10c08a8080000240200428020c200428021422056b20014f0d002004410c6a2005200110b182808000200428021421050b200428021020056a2000200110848e8080001a200428020c21002002200320042802102206200520016a41002802e0a1c680001186808080000002402000450d00200641002802c0a3c68000118080808000000b200441206a2480808080000f0b10ae80808000000b4101200510b280808000000b810201037f23808080800041206b22032480808080000240024002400240200241046a22040d00410121050c010b2004417f4c0d0141002d00fca3c680001a200441002802c8a3c68000118180808000002205450d020b20034100360214200320053602102003200436020c200320023602182003200341186a36021c2003411c6a2003410c6a10c08a8080000240200328020c200328021422046b20024f0d002003410c6a2004200210b182808000200328021421040b200328021020046a2001200210848e8080001a200041086a200420026a3602002000200329020c370200200341206a2480808080000f0b10ae80808000000b4101200410b280808000000bf60101047f23808080800041206b2203248080808000024002402002417f4c0d0041002d00fca3c680001a20024103742204410472220541002802c8a3c68000118180808000002206450d0120034100360214200320063602102003200536020c200320023602182003200341186a36021c2003411c6a2003410c6a10c08a8080000240200328020c200328021422026b20044f0d002003410c6a2002200410b182808000200328021421020b200328021020026a2001200410848e8080001a200041086a200220046a3602002000200329020c370200200341206a2480808080000f0b10ae80808000000b4101200510b280808000000b860201047f23808080800041206b220324808080800002400240024002402002410274220441046a22050d00410121060c010b2005417f4c0d0141002d00fca3c680001a200541002802c8a3c68000118180808000002206450d020b20034100360214200320063602102003200536020c200320023602182003200341186a36021c2003411c6a2003410c6a10c08a8080000240200328020c200328021422056b20044f0d002003410c6a2005200410b182808000200328021421050b200328021020056a2001200410848e8080001a200041086a200520046a3602002000200329020c370200200341206a2480808080000f0b10ae80808000000b4101200510b280808000000bc80401077f23808080800041c0006b2207248080808000200120042005200610e38d80800021060240024002400240024020032d00004102470d00200341086a28020021052002280200220841d4006a2802002109200328020421042008280250210a200128022c220841017621030240024020084101710d00200128020420012802282208200841284b22081b220b2003490d042001280200200120081b21084100210b0c010b200128020420012802282208200841284b1b220b2003490d04200b20034d0d05200741296a20012802002001200841284b1b220820036a2d000041f001713a00004101210b0b2007200b3a002820072003360224200720083602202007200a200741206a20042005200928021c1187808080000020022802002102200128020021082001280204210920012802282103200741206a41186a200741186a220a290000370300200741206a41106a200741106a220b290000370300200741206a41086a200741086a220c29000037030020072007290000370320200220082001200341284b220d1b20092003200d1b20042005200741206a10fd858080002001200610e08d808000200041003a0000200041196a200a290000370000200041116a200b290000370000200041096a200c290000370000200020072900003700010c010b200020022802002003200110ff858080002001200610e08d8080000b200741c0006a2480808080000f0b2003200b41ac95c68000109581808000000b2003200b41bc95c68000109581808000000b2003200b41cc95c6800010f980808000000beb0401097f23808080800041c0006b22062480808080002001280200220728020020032004200510e38d80800021050240024002400240024020022d00004102470d00200241086a280200210420012802042208280200220141d4006a2802002109200228020421032001280250210a2007280200220228022c220b410176210102400240200b4101710d0020022802042002280228220b200b41284b220b1b220c2001490d0420022802002002200b1b21024100210b0c010b20022802042002280228220b200b41284b1b220c2001490d04200c20014d0d05200641296a20022802002002200b41284b1b220220016a2d000041f001713a00004101210b0b2006200b3a002820062001360224200620023602202006200a200641206a20032004200928021c118780808000002008280200210b2007280200220228020021082002280204210920022802282101200641206a41186a200641186a220a290000370300200641206a41106a200641106a220c290000370300200641206a41086a200641086a220d29000037030020062006290000370320200b20082002200141284b220e1b20092001200e1b20032004200641206a10fc858080002007280200200510e08d808000200041003a0000200041196a200a290000370000200041116a200c290000370000200041096a200d290000370000200020062900003700010c010b20002001280204280200200220072802001080868080002007280200200510e08d8080000b200641c0006a2480808080000f0b2001200c41ac95c68000109581808000000b2001200c41bc95c68000109581808000000b2001200c41cc95c6800010f980808000000bc80401077f23808080800041c0006b2207248080808000200120042005200610e38d80800021060240024002400240024020032d00004102470d00200341086a28020021052002280200220841d4006a2802002109200328020421042008280250210a200128022c220841017621030240024020084101710d00200128020420012802282208200841284b22081b220b2003490d042001280200200120081b21084100210b0c010b200128020420012802282208200841284b1b220b2003490d04200b20034d0d05200741296a20012802002001200841284b1b220820036a2d000041f001713a00004101210b0b2007200b3a002820072003360224200720083602202007200a200741206a20042005200928021c1187808080000020022802002102200128020021082001280204210920012802282103200741206a41186a200741186a220a290000370300200741206a41106a200741106a220b290000370300200741206a41086a200741086a220c29000037030020072007290000370320200220082001200341284b220d1b20092003200d1b20042005200741206a10fc858080002001200610e08d808000200041003a0000200041196a200a290000370000200041116a200b290000370000200041096a200c290000370000200020072900003700010c010b20002002280200200320011080868080002001200610e08d8080000b200741c0006a2480808080000f0b2003200b41ac95c68000109581808000000b2003200b41bc95c68000109581808000000b2003200b41cc95c6800010f980808000000beb0401097f23808080800041c0006b22062480808080002001280200220728020020032004200510e38d80800021050240024002400240024020022d00004102470d00200241086a280200210420012802042208280200220141d4006a2802002109200228020421032001280250210a2007280200220228022c220b410176210102400240200b4101710d0020022802042002280228220b200b41284b220b1b220c2001490d0420022802002002200b1b21024100210b0c010b20022802042002280228220b200b41284b1b220c2001490d04200c20014d0d05200641296a20022802002002200b41284b1b220220016a2d000041f001713a00004101210b0b2006200b3a002820062001360224200620023602202006200a200641206a20032004200928021c118780808000002008280200210b2007280200220228020021082002280204210920022802282101200641206a41186a200641186a220a290000370300200641206a41106a200641106a220c290000370300200641206a41086a200641086a220d29000037030020062006290000370320200b20082002200141284b220e1b20092001200e1b20032004200641206a10fd858080002007280200200510e08d808000200041003a0000200041196a200a290000370000200041116a200c290000370000200041096a200d290000370000200020062900003700010c010b200020012802042802002002200728020010ff858080002007280200200510e08d8080000b200641c0006a2480808080000f0b2001200c41ac95c68000109581808000000b2001200c41bc95c68000109581808000000b2001200c41cc95c6800010f980808000000ba00301047f23808080800041f0086b2202248080808000200241e8016a2001280200220128020022032001280204220110c28c8080000240024002400240024020022802e80122044105470d002002410c6a410c6a200241e8016a410c6a290200370200200220022902ec013702102002410536020c0c010b200241e0086a41086a2205200241e8016a410c6a290200370300200220022902ec013703e00820024184076a41146a200241e8016a41146a41c80110848e8080001a20024184076a410c6a20052903003702002002200436028407200220022903e008370288072002410c6a20024184076a2003200110f48d808000200228020c22014105470d010b200241106a10de858080000c010b20024184076a41046a2002410c6a41046a41d80110848e8080001a2002200136028407200241e8016a20024184076a10b68a80800020022802e80122014108470d0120022802ec0110df858080000b41c0d3c2800041c2004184d4c2800010a181808000000b200041046a200241e8016a41046a41980510848e8080001a20002001360200200241f0086a2480808080000bc50101027f024002400240024020002802002201418080808078732202410220024104491b0e03030301000b0240024002402000280204220028020041fcffffff076a2202410320024105491b0e0404040102000b2000280204450d03200041086a28020041002802c0a3c68000118080808000000c030b2000280204450d02200041086a28020041002802c0a3c68000118080808000000c020b200010de858080000c010b2001450d01200028020421000b200041002802c0a3c68000118080808000000b0b8b0101017f0240024002400240200028020041fcffffff076a2201410320014105491b0e0403030102000b2000280204450d02200041086a28020041002802c0a3c68000118080808000000c020b2000280204450d01200041086a28020041002802c0a3c68000118080808000000c010b200010de858080000b200041002802c0a3c68000118080808000000b860101037f20012802042102200128020022012802042103200128020022012001280200220441016a36020002402004417f4a0d0000000b2000200336020820002001360204200041073602002000200229000037000c200041246a200241186a2900003700002000411c6a200241106a290000370000200041146a200241086a2900003700000ba00301047f23808080800041f0086b2202248080808000200241e8016a2001280200220128020022032001280204220110c28c8080000240024002400240024020022802e80122044105470d002002410c6a410c6a200241e8016a410c6a290200370200200220022902ec013702102002410536020c0c010b200241e0086a41086a2205200241e8016a410c6a290200370300200220022902ec013703e00820024184076a41146a200241e8016a41146a41c80110848e8080001a20024184076a410c6a20052903003702002002200436028407200220022903e008370288072002410c6a20024184076a2003200110f48d808000200228020c22014105470d010b200241106a10de858080000c010b20024184076a41046a2002410c6a41046a41d80110848e8080001a2002200136028407200241e8016a20024184076a10b78a80800020022802e80122014108470d0120022802ec0110df858080000b41c0d3c2800041c2004184d4c2800010a181808000000b200041046a200241e8016a41046a41980510848e8080001a20002001360200200241f0086a2480808080000be80201047f23808080800041106b220224808080800020012802082103200128020421040240024002400240024020012802000d00024020034100480d00200341f5ffffff074f0d0202402003410b6a417c7122050d00410421010c050b41002d00fca3c680001a200541002802c8a3c680001181808080000022010d044104200510b280808000000b41fc9bc68000412b2002410f6a41a89cc6800041b89cc68000108981808000000b20034120470d0120002004290000370001200041196a200441186a290000370000200041116a200441106a290000370000200041096a200441086a290000370000410121010c030b41e484c08000412b2002410f6a419085c08000419086c08000108981808000000b412020034190d1c2800010a281808000000b2001428180808010370200200141086a2004200310848e8080001a200041086a200336020020002001360204410021010b200020013a0000200241106a2480808080000b810401027f0240024002400240024020002d00002201417c6a41ff01712202410420024104491b0e0404010203000b0240200041dc006a2802004129490d00200041346a28020041002802c0a3c68000118080808000000b200028022c41002802c0a3c680001180808080000020014103460d0302400240024020010e020106000b2000280224220220022802002202417f6a36020020024101470d05200041246a21000c010b2000280204220220022802002202417f6a36020020024101470d04200041046a21000b200010e28a8080000c030b0240200041dc006a2802004129490d00200041346a28020041002802c0a3c68000118080808000000b02400240024020002d00040e020105000b200041286a2200280200220220022802002202417f6a36020020024101470d040c010b200041086a2200280200220220022802002202417f6a36020020024101470d030b200010e28a8080000f0b200041d4006a2802004129490d012000412c6a28020041002802c0a3c68000118080808000000f0b200028023041002802c0a3c680001180808080000020002d000422024103460d0002400240024020020e020103000b200041286a2200280200220220022802002202417f6a36020020024101470d020c010b200041086a2200280200220220022802002202417f6a36020020024101470d010b200010e28a8080000f0b0b6801017f024002400240024020002d00000e020103000b2000280224220120012802002201417f6a36020020014101470d02200041246a21000c010b2000280204220120012802002201417f6a36020020014101470d01200041046a21000b200010e28a8080000b0b7101017f024020002d000022014103460d0002400240024020010e020103000b2000280224220120012802002201417f6a36020020014101470d02200041246a21000c010b2000280204220120012802002201417f6a36020020014101470d01200041046a21000b200010e28a8080000b0b02000bdc0101017f0240024002400240024020002d00000e03000201040b20012d00000d03200041086a2802002202200141086a280200470d03200028020441086a200128020441086a200210888e808000450f0b20012d00004102460d010c020b20012d00004101470d01200041016a200141016a412010888e808000450f0b0240024020002d0001450d0020012d000141ff01710d010b200041286a2802002202200141286a280200470d01200028022441086a200128022441086a200210888e808000450f0b200041026a200141026a412010888e808000450f0b41000ba97407047f027e037f017e027f017e1b7f23808080800041d00f6b22052480808080002005200436020c200541e00d6a2002200310c28c80800002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024020052802e00d22064105470d00200541106a410c6a200541e00d6a410c6a290200370200200520052902e40d3702140c010b200541a0036a2207200541e00d6a410c6a290200370300200520052902e40d37039803200541800c6a41146a200541e00d6a41146a41c80110848e8080001a200541800c6a410c6a2007290300370200200520063602800c20052005290398033702840c200541106a200541800c6a2002200310f48d808000200528021022034105470d010b200541e00d6a41086a22032005411c6a290200370300200541e00d6a41186a2202200141086a290000370300200541e00d6a41206a2204200141106a290000370300200541e00d6a41286a2206200141186a290000370300200520052902143703e00d200520012900003703f00d41002d00fca3c680001a413041002802c8a3c680001181808080000022010d014104413010b280808000000b2005280228210220052802242106200528022021082005290218210920052802142107200541f0016a2005412c6a41a80110848e8080001a20052902d801210a20052802d401210b4104210c0240024002400240024002400240024020030e052d000301022d0b200541003602880e200541e00d6a200720072009a76a10f58d808000200541800c6a41186a200541e00d6a41186a290200370300200541800c6a41106a200541e00d6a41106a290200370300200541800c6a41086a200541e00d6a41086a290200370300200520052902e00d3703800c20052802800e210d20052902840e210e024020080d00024020024100480d00200241f5ffffff074f0d0a02402002410b6a417c7122010d004104210f0c2d0b41002d00fca3c680001a200141002802c8a3c6800011818080800000220f0d2c4104200110b280808000000b41fc9bc68000412b200541e00d6a41a89cc6800041b89cc68000108981808000000b20024120470d09200541106a41026a200641026a2d00003a0000200541e80d6a200641136a290000370300200541ed0d6a200641186a290000370000200520062f00003b01102005200629000b3703e00d200628000721022006280003210f410121100c2b0b200520023602f40d200520063602f00d200520083602ec0d200520093702e40d200520073602e00d200541e00d6a41186a200541f0016a41a80110848e8080002103200520013602d0074102210220052005410c6a3602d4072005200541e00d6a3602cc070240024020074102470d000c010b200541c00f6a41086a200541e00d6a41086a280200360200200520052902e00d3703c00f200541106a41186a200141186a290000370300200541106a41106a200141106a290000370300200541106a41086a200141086a29000037030020052001290000370310200541800c6a200541106a200541c00f6a200410e98580800020052d00800c22024102460d0a200541fe0b6a20052d00830c3a0000200541f8086a41086a200541800c6a41106a290200370300200541f8086a41106a200541800c6a41186a290200370300200541f8086a41186a200541a00c6a280200360200200520052f00810c3b01fc0b200520052902880c3703f80820052802840c210620052802ec0d2108200221020b4102210420054184046a41026a200541fc0b6a41026a2d00003a0000200541e8036a41086a200541f8086a41086a290300370300200541e8036a41106a200541f8086a41106a290300370300200541e8036a41186a200541f8086a41186a280200360200200520052f01fc0b3b018404200520052903f8083703e80320084102470d020c030b20052902e401211120052802e001210f200520023602e80d200520063602e40d200520083602e00d200541ec0d6a200541f0016a41a80110848e80800021032005200a3702980f2005200b3602940f200520013602d0074102210220052005410c6a3602d4072005200541e00d6a3602cc070240024020084102470d000c010b200541c00f6a41086a200541e00d6a41086a280200360200200520052902e00d3703c00f200541106a41186a200141186a290000370300200541106a41106a200141106a290000370300200541106a41086a200141086a29000037030020052001290000370310200541800c6a200541106a200541c00f6a200410e98580800020052d00800c22024102460d19200541fe0b6a20052d00830c3a0000200541f8086a41086a200541800c6a41106a290200370300200541f8086a41106a200541800c6a41186a290200370300200541f8086a41186a200541a00c6a280200360200200520052f00810c3b01fc0b200520052902880c3703f80820052802840c2106200221020b4102210420054194086a41026a200541fc0b6a41026a2d00003a0000200541f8076a41086a200541f8086a41086a290300370300200541f8076a41106a200541f8086a41106a290300370300200541f8076a41186a200541f8086a41186a280200360200200520052f01fc0b3b019408200520052903f8083703f80720052802ec0d4102470d030c040b200520023602e403200520063602e003200520083602dc03200541003602880e200541e00d6a200720072009a76a10f58d808000200541106a41086a2203200541e00d6a41106a290200370300200541106a41106a2202200541e00d6a41186a290200370300200541106a41186a2204200541800e6a290200370300200520052902e80d37031020052802e40d211220052802e00d211320052802880e210d200541800c6a41186a200141186a290000370300200541800c6a41106a200141106a290000370300200541800c6a41086a200141086a290000370300200520012900003703800c200541e00d6a200541800c6a200541dc036a200528020c10e985808000024020052d00e00d22104102460d00200541d4036a41026a20052d00e30d3a0000200541b8036a41086a200541f40d6a290200370300200541b8036a41106a200541fc0d6a29020037030020054198036a41086a200329030037030020054198036a41106a200229030037030020054198036a41186a2004290300370300200520052f00e10d3b01d403200520052902ec0d3703b80320052005290310370398032009422088a7211420052802e40d210f20052802e80d21024106210c0c2a0b20052802e40d2101200041083a000020002001360204200d4129490d2a201341002802c0a3c68000118080808000000c2a0b200541c00f6a41086a200541ec0d6a220441086a280200360200200520042902003703c00f200541106a41186a200141186a290000370300200541106a41106a200141106a290000370300200541106a41086a200141086a29000037030020052001290000370310200541800c6a200541106a200541c00f6a200528020c10e98580800020052d00800c22044102460d07200541fe0b6a20052d00830c3a000020054180096a200541800c6a41106a290200370300200541f8086a41106a200541800c6a41186a290200370300200541f8086a41186a200541a00c6a280200360200200520052f00810c3b01fc0b200520052902880c3703f80820052802840c2108200421040b41022107200541a4046a41026a200541fc0b6a41026a2d00003a000020054188046a41086a200541f8086a41086a29030037030020054188046a41106a200541f8086a41106a29030037030020054188046a41186a200541f8086a41186a280200360200200520052f01fc0b3b01a404200520052903f808370388040240024020052802f80d4102470d000c010b200541c00f6a41086a200341086a280200360200200520032902003703c00f200541106a41186a200141186a290000370300200541106a41106a200141106a290000370300200541106a41086a200141086a29000037030020052001290000370310200541800c6a200541106a200541c00f6a200528020c10e98580800020052d00800c22034102460d08200541fe0b6a20052d00830c3a000020054180096a200541800c6a41106a290200370300200541f8086a41106a200541800c6a41186a290200370300200541f8086a41186a200541a00c6a280200360200200520052f00810c3b01fc0b200520052902880c3703f80820052802840c210d200321070b41022103200541c4046a41026a200541fc0b6a41026a2d00003a0000200541a8046a41086a200541f8086a41086a290300370300200541a8046a41106a200541f8086a41106a290300370300200541a8046a41186a200541f8086a41186a280200360200200520052f01fc0b3b01c404200520052903f8083703a8040240024020052802840e4102470d000c010b200541c00f6a41086a200541840e6a220341086a280200360200200520032902003703c00f200541106a41186a200141186a290000370300200541106a41106a200141106a290000370300200541106a41086a200141086a29000037030020052001290000370310200541800c6a200541106a200541c00f6a200528020c10e98580800020052d00800c22014102460d09200541fe0b6a20052d00830c3a000020054180096a200541800c6a41106a290200370300200541f8086a41106a200541800c6a41186a290200370300200541f8086a41186a200541a00c6a280200360200200520052f00810c3b01fc0b200520052902880c3703f80820052802840c2113200121030b200541e4046a41026a200541fc0b6a41026a2d00003a0000200541c8046a41086a200541f8086a41086a290300370300200541c8046a41106a200541f8086a41106a290300370300200541c8046a41186a200541f8086a41186a280200360200200520052f01fc0b3b01e404200520052903f8083703c804200541800c6a200541cc076a410410ea8580800020052d00800c22014103460d0920054184056a41026a20052d00830c3a0000200541e8046a41086a200541800c6a41106a290200370300200541e8046a41106a200541800c6a41186a290200370300200541e8046a41186a200541a00c6a220f280200360200200520052f00810c3b018405200520052902880c3703e80420052802840c210c200541800c6a200541cc076a410510ea8580800020052d00800c22144103460d0a200541a4056a41026a20052d00830c3a000020054188056a41086a200541800c6a41106a221229020037030020054188056a41106a200541800c6a41186a221029020037030020054188056a41186a200f280200360200200520052f00810c3b01a405200520052902880c3703880520052802840c210f200541800c6a200541cc076a410610ea8580800020052d00800c22154103460d0b200541c4056a41026a20052d00830c3a0000200541a8056a41086a2012290200370300200541a8056a41106a2010290200370300200541a8056a41186a200541a00c6a2212280200360200200520052f00810c3b01c405200520052902880c3703a80520052802840c2116200541800c6a200541cc076a410710ea8580800020052d00800c22174103460d0c200541e4056a41026a20052d00830c3a0000200541c8056a41086a200541800c6a41106a2210290200370300200541c8056a41106a200541800c6a41186a2218290200370300200541c8056a41186a2012280200360200200520052f00810c3b01e405200520052902880c3703c80520052802840c2119200541800c6a200541cc076a410810ea8580800020052d00800c221a4103460d0d20054184066a41026a20052d00830c3a0000200541e8056a41086a2010290200370300200541e8056a41106a2018290200370300200541e8056a41186a200541a00c6a2212280200360200200520052f00810c3b018406200520052902880c3703e80520052802840c2118200541800c6a200541cc076a410910ea8580800020052d00800c221b4103460d0e200541a4066a41026a20052d00830c3a000020054188066a41086a200541800c6a41106a221029020037030020054188066a41106a200541800c6a41186a221c29020037030020054188066a41186a2012280200360200200520052f00810c3b01a406200520052902880c3703880620052802840c211d200541800c6a200541cc076a410a10ea8580800020052d00800c221e4103460d0f200541c4066a41026a20052d00830c3a0000200541a8066a41086a2010290200370300200541a8066a41106a201c290200370300200541a8066a41186a200541a00c6a2212280200360200200520052f00810c3b01c406200520052902880c3703a80620052802840c211c200541800c6a200541cc076a410b10ea8580800020052d00800c221f4103460d10200541e4066a41026a20052d00830c3a0000200541c8066a41086a200541800c6a41106a2210290200370300200541c8066a41106a200541800c6a41186a2220290200370300200541c8066a41186a2012280200360200200520052f00810c3b01e406200520052902880c3703c80620052802840c2121200541800c6a200541cc076a410c10ea8580800020052d00800c22224103460d1120054184076a41026a20052d00830c3a0000200541e8066a41086a2010290200370300200541e8066a41106a2020290200370300200541e8066a41186a200541a00c6a2212280200360200200520052f00810c3b018407200520052902880c3703e80620052802840c2120200541800c6a200541cc076a410d10ea8580800020052d00800c22234103460d12200541a4076a41026a20052d00830c3a000020054188076a41086a200541800c6a41106a221029020037030020054188076a41106a200541800c6a41186a222429020037030020054188076a41186a2012280200360200200520052f00810c3b01a407200520052902880c3703880720052802840c2125200541800c6a200541cc076a410e10ea8580800020052d00800c22264103460d13200541c8076a41026a20052d00830c3a0000200541a8076a41086a2010290200370300200541a8076a41106a2024290200370300200541a8076a41186a200541a00c6a2212280200360200200520052f00810c3b01c807200520052902880c3703a80720052802840c2124200541800c6a200541cc076a410f10ea8580800002400240024020052d00800c22274103460d00200541f4076a41026a222820052d00830c3a0000200541d8076a41086a2229200541800c6a41106a290200370300200541d8076a41106a222a200541800c6a41186a290200370300200541d8076a41186a222b2012280200360200200520052f00810c3b01f407200520052902880c3703d80720052802840c212c41002d00fca3c680001a41c00441002802c8a3c68000118180808000002212450d17201220023a0000201220052f0184043b000120122006360204201220052903e803370208201220043a0024201220052f01a4043b002541032110201241036a20054184046a41026a2d00003a0000201241106a200541e8036a41086a290300370200201241186a200541e8036a41106a290300370200201241206a200541e8036a41186a280200360200201241276a200541a4046a41026a2d00003a000020122008360228201220073a00482012200d36024c201220052903880437022c201241346a20054188046a41086a2903003702002012413c6a20054188046a41106a290300370200201241c4006a20054188046a41186a280200360200201220052f01c4043b0049201241cb006a200541c4046a41026a2d00003a0000201220052903a804370250201241d8006a200541a8046a41086a290300370200201241e0006a200541a8046a41106a290300370200201241e8006a200541a8046a41186a280200360200201220033a006c20122013360270201220013a009001201220052f01e4043b006d201241ef006a200541e4046a41026a2d00003a00002012418c016a200541c8046a41186a28020036020020124184016a200541c8046a41106a290300370200201241fc006a200541c8046a41086a290300370200201220052903c804370274201220052f0184053b00910120124193016a20054184056a41026a2d00003a00002012200c36029401201241b0016a200541e8046a41186a280200360200201241a8016a200541e8046a41106a290300370200201241a0016a200541e8046a41086a290300370200201220052903e80437029801201220143a00b401201241b7016a200541a4056a41026a2d00003a0000201220052f01a4053b00b5012012200f3602b801201241d4016a20054188056a41186a280200360200201241cc016a20054188056a41106a290300370200201241c4016a20054188056a41086a29030037020020122005290388053702bc01201220153a00d801201241db016a200541c4056a41026a2d00003a0000201220052f01c4053b00d901201220163602dc01201241f8016a200541a8056a41186a280200360200201241f0016a200541a8056a41106a290300370200201241e8016a200541a8056a41086a290300370200201220052903a8053702e001201220173a00fc01201241ff016a200541e4056a41026a2d00003a0000201220052f01e4053b00fd0120122019360280022012419c026a200541c8056a41186a28020036020020124194026a200541c8056a41106a2903003702002012418c026a200541c8056a41086a290300370200201220052903c805370284022012201a3a00a002201241a3026a20054184066a41026a2d00003a0000201220052f0184063b00a102201220183602a402201241c0026a200541e8056a41186a280200360200201241b8026a200541e8056a41106a290300370200201241b0026a200541e8056a41086a290300370200201220052903e8053702a8022012201b3a00c402201241c7026a200541a4066a41026a2d00003a0000201220052f01a4063b00c5022012201d3602c802201241e4026a20054188066a41186a280200360200201241dc026a20054188066a41106a290300370200201241d4026a20054188066a41086a29030037020020122005290388063702cc022012201e3a00e802201241eb026a200541c4066a41026a2d00003a0000201220052f01c4063b00e9022012201c3602ec0220124188036a200541a8066a41186a28020036020020124180036a200541a8066a41106a290300370200201241f8026a200541a8066a41086a290300370200201220052903a8063702f0022012201f3a008c032012418f036a200541e4066a41026a2d00003a0000201220052f01e4063b008d032012202136029003201241ac036a200541c8066a41186a280200360200201241a4036a200541c8066a41106a2903003702002012419c036a200541c8066a41086a290300370200201220052903c80637029403201220223a00b003201241b3036a20054184076a41026a2d00003a0000201220052f0184073b00b103201220203602b403201241d0036a200541e8066a41186a280200360200201241c8036a200541e8066a41106a290300370200201241c0036a200541e8066a41086a290300370200201220052903e8063702b803201220233a00d403201241d7036a200541a4076a41026a2d00003a0000201220052f01a4073b00d503201220253602d803201241f4036a20054188076a41186a280200360200201241ec036a20054188076a41106a290300370200201241e4036a20054188076a41086a29030037020020122005290388073702dc03201220263a00f803201241fb036a200541c8076a41026a2d00003a0000201220052f01c8073b00f903201220243602fc0320124198046a200541a8076a41186a28020036020020124190046a200541a8076a41106a29030037020020124188046a200541a8076a41086a290300370200201220052903a80737028004201220273a009c042012419f046a20282d00003a0000201220052f01f4073b009d042012202c3602a004201241bc046a202b280200360200201241b4046a202a290300370200201241ac046a2029290300370200201220052903d8073702a404200b4102470d010c020b20052802840c2101200041083a0000200020013602040c2a0b2005200a3702fc082005200b3602f808200541800c6a200541f8086a10e285808000200541da076a20052d00830c3a0000200541186a200541940c6a290200370300200541206a2005419c0c6a290200370300200520052f00810c3b01d8072005200529028c0c37031020052d00800c211020052802840c210f20052802880c210220052802a40c211420052802a80c21130b200541d4036a41026a200541d8076a41026a2d00003a0000200541b8036a41086a200541106a41086a290300370300200541b8036a41106a200541106a41106a290300370300200520052f01d8073b01d403200520052903103703b8034107210c0c270b200541c00f6a41086a200341086a280200360200200520032902003703c00f200541106a41186a200141186a290000370300200541106a41106a200141106a290000370300200541106a41086a200141086a29000037030020052001290000370310200541800c6a200541106a200541c00f6a200528020c10e98580800020052d00800c22034102460d15200541fe0b6a20052d00830c3a000020054180096a200541800c6a41106a290200370300200541f8086a41106a200541800c6a41186a290200370300200541f8086a41186a200541a00c6a280200360200200520052f00810c3b01fc0b200520052902880c3703f80820052802840c2108200321040b41022103200541b4086a41026a200541fc0b6a41026a2d00003a000020054198086a41086a200541f8086a41086a29030037030020054198086a41106a200541f8086a41106a29030037030020054198086a41186a200541f8086a41186a280200360200200520052f01fc0b3b01b408200520052903f808370398080240024020052802f80d4102470d000c010b200541c00f6a41086a200541e00d6a41186a220341086a280200360200200520032902003703c00f200541106a41186a200141186a290000370300200541106a41106a200141106a290000370300200541106a41086a200141086a29000037030020052001290000370310200541800c6a200541106a200541c00f6a200528020c10e98580800020052d00800c22034102460d16200541fe0b6a20052d00830c3a000020054180096a200541800c6a41106a290200370300200541f8086a41106a200541800c6a41186a290200370300200541f8086a41186a200541a00c6a280200360200200520052f00810c3b01fc0b200520052902880c3703f80820052802840c2110200321030b4102210d200541d4086a41026a200541fc0b6a41026a2d00003a0000200541b8086a41086a200541f8086a41086a290300370300200541b8086a41106a200541f8086a41106a290300370300200541b8086a41186a200541f8086a41186a280200360200200520052f01fc0b3b01d408200520052903f8083703b8080240024020052802840e4102470d000c010b200541c00f6a41086a200541840e6a220d41086a2802003602002005200d2902003703c00f200541106a41186a200141186a290000370300200541106a41106a200141106a290000370300200541106a41086a200141086a29000037030020052001290000370310200541800c6a200541106a200541c00f6a200528020c10e98580800020052d00800c220d4102460d17200541fe0b6a20052d00830c3a000020054180096a200541800c6a41106a290200370300200541f8086a41106a200541800c6a41186a290200370300200541f8086a41186a200541a00c6a280200360200200520052f00810c3b01fc0b200520052902880c3703f80820052802840c210b200d210d0b41022114200541f4086a41026a200541fc0b6a41026a2d00003a0000200541d8086a41086a200541f8086a41086a290300370300200541d8086a41106a200541f8086a41106a290300370300200541d8086a41186a200541f8086a41186a280200360200200520052f01fc0b3b01f408200520052903f8083703d8080240024020052802900e4102470d000c010b200541c00f6a41086a200541900e6a221341086a280200360200200520132902003703c00f200541106a41186a200141186a290000370300200541106a41106a200141106a290000370300200541106a41086a200141086a29000037030020052001290000370310200541800c6a200541106a200541c00f6a200528020c10e98580800020052d00800c22134102460d18200541fe0b6a20052d00830c3a000020054180096a200541800c6a41106a290200370300200541f8086a41106a200541800c6a41186a290200370300200541f8086a41186a200541a00c6a280200360200200520052f00810c3b01fc0b200520052902880c3703f80820052802840c2101201321140b200541b4096a41026a200541fc0b6a41026a2d00003a000020054198096a41086a200541f8086a41086a29030037030020054198096a41106a200541f8086a41106a29030037030020054198096a41186a200541f8086a41186a280200360200200520052f01fc0b3b01b409200520052903f80837039809200541800c6a200541cc076a410510eb8580800020052d00800c22154103460d18200541d4096a41026a20052d00830c3a0000200541b8096a41086a200541800c6a41106a290200370300200541b8096a41106a200541800c6a41186a290200370300200541b8096a41186a200541a00c6a2213280200360200200520052f00810c3b01d409200520052902880c3703b80920052802840c2116200541800c6a200541cc076a410610eb8580800020052d00800c22174103460d19200541f4096a41026a20052d00830c3a0000200541d8096a41086a200541800c6a41106a2212290200370300200541d8096a41106a200541800c6a41186a220c290200370300200541d8096a41186a2013280200360200200520052f00810c3b01f409200520052902880c3703d80920052802840c2118200541800c6a200541cc076a410710eb8580800020052d00800c22194103460d1a200541940a6a41026a20052d00830c3a0000200541f8096a41086a2012290200370300200541f8096a41106a200c290200370300200541f8096a41186a200541a00c6a2213280200360200200520052f00810c3b01940a200520052902880c3703f80920052802840c211a200541800c6a200541cc076a410810eb8580800020052d00800c221b4103460d1b200541b40a6a41026a20052d00830c3a0000200541980a6a41086a200541800c6a41106a2212290200370300200541980a6a41106a200541800c6a41186a220c290200370300200541980a6a41186a2013280200360200200520052f00810c3b01b40a200520052902880c3703980a20052802840c211c200541800c6a200541cc076a410910eb8580800020052d00800c221d4103460d1c200541d40a6a41026a20052d00830c3a0000200541b80a6a41086a2012290200370300200541b80a6a41106a200c290200370300200541b80a6a41186a200541a00c6a2213280200360200200520052f00810c3b01d40a200520052902880c3703b80a20052802840c211e200541800c6a200541cc076a410a10eb8580800020052d00800c221f4103460d1d200541f40a6a41026a20052d00830c3a0000200541d80a6a41086a200541800c6a41106a2212290200370300200541d80a6a41106a200541800c6a41186a220c290200370300200541d80a6a41186a2013280200360200200520052f00810c3b01f40a200520052902880c3703d80a20052802840c2120200541800c6a200541cc076a410b10eb8580800020052d00800c22214103460d1e200541940b6a41026a20052d00830c3a0000200541f80a6a41086a2012290200370300200541f80a6a41106a200c290200370300200541f80a6a41186a200541a00c6a2213280200360200200520052f00810c3b01940b200520052902880c3703f80a20052802840c2122200541800c6a200541cc076a410c10eb8580800020052d00800c22234103460d1f200541b40b6a41026a20052d00830c3a0000200541980b6a41086a200541800c6a41106a2212290200370300200541980b6a41106a200541800c6a41186a220c290200370300200541980b6a41186a2013280200360200200520052f00810c3b01b40b200520052902880c3703980b20052802840c2124200541800c6a200541cc076a410d10eb8580800020052d00800c22254103460d20200541d40b6a41026a20052d00830c3a0000200541b80b6a41086a2012290200370300200541b80b6a41106a200c290200370300200541b80b6a41186a200541a00c6a2213280200360200200520052f00810c3b01d40b200520052902880c3703b80b20052802840c2126200541800c6a200541cc076a410e10eb8580800020052d00800c22274103460d21200541f80b6a41026a20052d00830c3a0000200541d80b6a41086a200541800c6a41106a2212290200370300200541d80b6a41106a200541800c6a41186a220c290200370300200541d80b6a41186a2013280200360200200520052f00810c3b01f80b200520052902880c3703d80b20052802840c2128200541800c6a200541cc076a410f10eb8580800002400240024020052d00800c22294103460d00200541f4076a41026a20052d00830c3a0000200541d8076a41086a2012290200370300200541d8076a41106a200c290200370300200541d8076a41186a200541800c6a41206a280200360200200520052f00810c3b01f407200520052902880c3703d80720052802840c212a41002d00fca3c680001a41c00441002802c8a3c68000118180808000002213450d252009422088a72112201320023a0000201320052f0194083b000120132006360204201320052903f807370208201320043a0024201320052f01b4083b00254103210c201341036a20054194086a41026a2d00003a0000201341106a200541f8076a41086a290300370200201341186a200541f8076a41106a290300370200201341206a200541f8076a41186a280200360200201341276a200541b4086a41026a2d00003a000020132008360228201320033a00482013201036024c201320052903980837022c201341346a20054198086a41086a2903003702002013413c6a20054198086a41106a290300370200201341c4006a20054198086a41186a280200360200201320052f01d4083b0049201341cb006a200541d4086a41026a2d00003a0000201320052903b808370250201341d8006a200541b8086a41086a290300370200201341e0006a200541b8086a41106a290300370200201341e8006a200541b8086a41186a2802003602002013200d3a006c2013200b360270201320143a009001201320052f01f4083b006d201341ef006a200541f4086a41026a2d00003a00002013418c016a200541d8086a41186a28020036020020134184016a200541d8086a41106a290300370200201341fc006a200541d8086a41086a290300370200201320052903d808370274201320052f01b4093b00910120134193016a200541b4096a41026a2d00003a00002013200136029401201341b0016a20054198096a41186a280200360200201341a8016a20054198096a41106a290300370200201341a0016a20054198096a41086a290300370200201320052903980937029801201320153a00b401201341b7016a200541d4096a41026a2d00003a0000201320052f01d4093b00b501201320163602b801201341d4016a200541b8096a41186a280200360200201341cc016a200541b8096a41106a290300370200201341c4016a200541b8096a41086a290300370200201320052903b8093702bc01201320173a00d801201341db016a200541f4096a41026a2d00003a0000201320052f01f4093b00d901201320183602dc01201341f8016a200541d8096a41186a280200360200201341f0016a200541d8096a41106a290300370200201341e8016a200541d8096a41086a290300370200201320052903d8093702e001201320193a00fc01201341ff016a200541940a6a41026a2d00003a0000201320052f01940a3b00fd012013201a360280022013419c026a200541f8096a41186a28020036020020134194026a200541f8096a41106a2903003702002013418c026a200541f8096a41086a290300370200201320052903f809370284022013201b3a00a002201341a3026a200541b40a6a41026a2d00003a0000201320052f01b40a3b00a1022013201c3602a402201341c0026a200541980a6a41186a280200360200201341b8026a200541980a6a41106a290300370200201341b0026a200541980a6a41086a290300370200201320052903980a3702a8022013201d3a00c402201341c7026a200541d40a6a41026a2d00003a0000201320052f01d40a3b00c5022013201e3602c802201341e4026a200541b80a6a41186a280200360200201341dc026a200541b80a6a41106a290300370200201341d4026a200541b80a6a41086a290300370200201320052903b80a3702cc022013201f3a00e802201341eb026a200541f40a6a41026a2d00003a0000201320052f01f40a3b00e902201320203602ec0220134188036a200541d80a6a41186a28020036020020134180036a200541d80a6a41106a290300370200201341f8026a200541d80a6a41086a290300370200201320052903d80a3702f002201320213a008c032013418f036a200541940b6a41026a2d00003a0000201320052f01940b3b008d032013202236029003201341ac036a200541f80a6a41186a280200360200201341a4036a200541f80a6a41106a2903003702002013419c036a200541f80a6a41086a290300370200201320052903f80a37029403201320233a00b003201341b3036a200541b40b6a41026a2d00003a0000201320052f01b40b3b00b103201320243602b403201341d0036a200541980b6a41186a280200360200201341c8036a200541980b6a41106a290300370200201341c0036a200541980b6a41086a290300370200201320052903980b3702b803201320253a00d403201341d7036a200541d40b6a41026a2d00003a0000201320052f01d40b3b00d503201320263602d803201341f4036a200541b80b6a41186a280200360200201341ec036a200541b80b6a41106a290300370200201341e4036a200541b80b6a41086a290300370200201320052903b80b3702dc03201320273a00f803201341fb036a200541f80b6a41026a2d00003a0000201320052f01f80b3b00f903201320283602fc0320134198046a200541d80b6a41186a28020036020020134190046a200541d80b6a41106a29030037020020134188046a200541d80b6a41086a290300370200201320052903d80b37028004201320293a009c042013419f046a200541f4076a41026a2d00003a0000201320052f01f4073b009d042013202a3602a004201341bc046a200541d8076a41186a280200360200201341b4046a200541d8076a41106a290300370200201341ac046a200541d8076a41086a290300370200201320052903d8073702a404200541003602a80c200541800c6a200720072009a76a10f58d808000200541106a41186a2201200541800c6a41186a2202290200370300200541106a41106a2203200541800c6a41106a290200370300200541106a41086a2204200541800c6a41086a290200370300200520052902800c37031020052802a00c210d20052902a40c210e200f4102470d010c020b20052802840c2101200041083a0000200020013602040c280b200520113702dc072005200f3602d807200541800c6a200541d8076a10e285808000200541c00f6a41026a20052d00830c3a0000200541fc0b6a41026a200541870c6a2d00003a0000200541f8086a41086a2002290200370300200541f8086a41106a200541a00c6a290200370300200520052f00810c3b01c00f200520052f00850c3b01fc0b200520052902900c3703f80820052d00800c210c20052d00840c211020052802880c210f200528028c0c210220052802a80c21140b20054198036a41186a200129030037030020054198036a41106a200329030037030020054198036a41086a2004290300370300200541d8036a41026a200541c00f6a41026a2d00003a0000200541d4036a41026a200541fc0b6a41026a2d00003a0000200541b8036a41106a200541f8086a41106a290300370300200541b8036a41086a200541f8086a41086a2903003703002005200529031037039803200520052f01c00f3b01d803200520052f01fc0b3b01d403200520052903f8083703b8030c250b200120052903e00d370200200141286a2006290300370200200141206a2004290300370200200141186a2002290300370200200141106a200541e00d6a41106a290300370200200141086a2003290300370200200041083a0000200020013602040c250b41e484c08000412b200541e00d6a419085c08000419086c08000108981808000000b412020024190d1c2800010a281808000000b20052802840c2101200041083a0000200020013602040c220b20052802840c2101200041083a0000200020013602040c210b20052802840c2101200041083a0000200020013602040c200b20052802840c2101200041083a0000200020013602040c1f0b20052802840c2101200041083a0000200020013602040c1e0b20052802840c2101200041083a0000200020013602040c1d0b20052802840c2101200041083a0000200020013602040c1c0b20052802840c2101200041083a0000200020013602040c1b0b20052802840c2101200041083a0000200020013602040c1a0b20052802840c2101200041083a0000200020013602040c190b20052802840c2101200041083a0000200020013602040c180b20052802840c2101200041083a0000200020013602040c170b20052802840c2101200041083a0000200020013602040c160b20052802840c2101200041083a0000200020013602040c150b20052802840c2101200041083a0000200020013602040c140b410441c00410b280808000000b20052802840c2101200041083a0000200020013602040c120b20052802840c2101200041083a0000200020013602040c110b20052802840c2101200041083a0000200020013602040c100b20052802840c2101200041083a0000200020013602040c0f0b20052802840c2101200041083a0000200020013602040c0e0b20052802840c2101200041083a0000200020013602040c0d0b20052802840c2101200041083a0000200020013602040c0c0b20052802840c2101200041083a0000200020013602040c0b0b20052802840c2101200041083a0000200020013602040c0a0b20052802840c2101200041083a0000200020013602040c090b20052802840c2101200041083a0000200020013602040c080b20052802840c2101200041083a0000200020013602040c070b20052802840c2101200041083a0000200020013602040c060b20052802840c2101200041083a0000200020013602040c050b20052802840c2101200041083a0000200020013602040c040b410441c00410b280808000000b200f428180808010370200200f41086a2006200210848e8080001a410021100b2009422088a7211220054198036a41186a200541800c6a41186a29030037030020054198036a41106a200541800c6a41106a29030037030020054198036a41086a200541800c6a41086a290300370300200541d4036a41026a200541106a41026a2d00003a0000200541b8036a41086a200541e00d6a41086a290300370300200541b8036a41106a200541e00d6a41106a290300370300200520052903800c37039803200520052f01103b01d403200520052903e00d3703b8034105210c0b200020052f01d8033b0001200020052f01d4033b0005200020052903b8033702102000200529039803370234200041036a200541d8036a41026a2d00003a0000200041076a200541d4036a41026a2d00003a0000200041186a200541b8036a41086a290300370200200041206a200541b8036a41106a2903003702002000413c6a20054198036a41086a290300370200200041c4006a20054198036a41106a290300370200200041cc006a20054198036a41186a2903003702002000200e3702582000200d3602542000200f3602082000200236020c200020143602282000201336022c20002012360230200020103a00042000200c3a00000b200541d00f6a2480808080000ba30801057f23808080800041e0016b2204248080808000200241086a28020021052002280204210602400240024002400240024020022802000d00024002400240024020050d00410121020c010b20054120460d012005417f4c0d0441002d00fca3c680001a200541002802c8a3c68000118180808000002202450d050b20022006200510848e808000210341002d00fca3c680001a413041002802c8a3c680001181808080000022020d014104413010b280808000000b2004411c6a41026a200641026a2d00003a0000200441086a2006410f6a290000370300200441106a200641176a290000370300200441186a2006411f6a2d00003a0000200420062f00003b011c2004200629000737030020062800032102410121060c050b2002200536020c2002200336020820022005360204200241888080807836020020022001290000370010200241186a200141086a290000370000200241206a200141106a290000370000200241286a200141186a2900003700000c030b20044180016a41186a200141186a29000037030020044180016a41106a200141106a29000037030020044180016a41086a200141086a2900003703002004200129000037038001200441206a20044180016a20062005200310e885808000024020042d002022054108460d00200441dc016a41026a20042d00233a0000200420042f00213b01dc012004280224210720044180016a200441286a41d80010848e8080001a02400240200341186a2802002201450d0020032001417f6a36021841002106200341146a22012001280200220141016a22024100200328020c220820022008491b6b360200200341106a28020020014102746a2802002202200328020822014f0d01200328020420024107746a220141046a200120012d00004108461b10e385808000200120053a0004200141083a000020012007360208200120042f01dc013b0005200141076a200441de016a2d00003a00002001410c6a20044180016a41d80010848e8080001a0c060b0240200328020822012003280200470d0020032001109e86808000200328020821010b200328020420014107746a220120053a0004200141083a0000200120042f01dc013b000520012007360208200141076a200441de016a2d00003a00002001410c6a20044180016a41d80010848e8080001a20032003280208220241016a360208410021060c050b2002200141d4d7c2800010f980808000000b200428022421020c020b10ae80808000000b4101200510b280808000000b200041023a0000200020023602040c010b200020042f011c3b00012000200429030037020820002002360204200020063a0000200041036a2004411e6a2d00003a0000200041106a200441086a290300370200200041186a200441106a290300370200200041206a200441186a2802003602000b200441e0016a2480808080000bd40201017f23808080800041d0006b220324808080800002402002410f4b0d000240024020012802002002410c6c6a22022802004102470d00200041023a00000c010b200341086a200241086a28020036020020032002290200370300200341306a41086a2001280204220241086a290000370300200341306a41106a200241106a290000370300200341306a41186a200241186a290000370300200320022900003703302003410c6a200341306a2003200128020828020010e985808000024020032d000c4102460d002000200329020c370200200041206a2003410c6a41206a280200360200200041186a2003410c6a41186a290200370200200041106a2003410c6a41106a290200370200200041086a2003410c6a41086a2902003702000c010b20002003280210360204200041033a00000b200341d0006a2480808080000f0b2002411041b0d1c2800010f980808000000bd40201017f23808080800041d0006b220324808080800002402002410f4b0d000240024020012802002002410c6c6a22022802004102470d00200041023a00000c010b200341086a200241086a28020036020020032002290200370300200341306a41086a2001280204220241086a290000370300200341306a41106a200241106a290000370300200341306a41186a200241186a290000370300200320022900003703302003410c6a200341306a2003200128020828020010e985808000024020032d000c4102460d002000200329020c370200200041206a2003410c6a41206a280200360200200041186a2003410c6a41186a290200370200200041106a2003410c6a41106a290200370200200041086a2003410c6a41086a2902003702000c010b20002003280210360204200041033a00000b200341d0006a2480808080000f0b2002411041a0d1c2800010f980808000000ba97407047f027e037f017e027f017e1b7f23808080800041d00f6b22052480808080002005200436020c200541e00d6a2002200310c28c80800002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024020052802e00d22064105470d00200541106a410c6a200541e00d6a410c6a290200370200200520052902e40d3702140c010b200541a0036a2207200541e00d6a410c6a290200370300200520052902e40d37039803200541800c6a41146a200541e00d6a41146a41c80110848e8080001a200541800c6a410c6a2007290300370200200520063602800c20052005290398033702840c200541106a200541800c6a2002200310f48d808000200528021022034105470d010b200541e00d6a41086a22032005411c6a290200370300200541e00d6a41186a2202200141086a290000370300200541e00d6a41206a2204200141106a290000370300200541e00d6a41286a2206200141186a290000370300200520052902143703e00d200520012900003703f00d41002d00fca3c680001a413041002802c8a3c680001181808080000022010d014104413010b280808000000b2005280228210220052802242106200528022021082005290218210920052802142107200541f0016a2005412c6a41a80110848e8080001a20052902d801210a20052802d401210b4104210c0240024002400240024002400240024020030e052d000301022d0b200541003602880e200541e00d6a200720072009a76a10f58d808000200541800c6a41186a200541e00d6a41186a290200370300200541800c6a41106a200541e00d6a41106a290200370300200541800c6a41086a200541e00d6a41086a290200370300200520052902e00d3703800c20052802800e210d20052902840e210e024020080d00024020024100480d00200241f5ffffff074f0d0a02402002410b6a417c7122010d004104210f0c2d0b41002d00fca3c680001a200141002802c8a3c6800011818080800000220f0d2c4104200110b280808000000b41fc9bc68000412b200541e00d6a41a89cc6800041b89cc68000108981808000000b20024120470d09200541106a41026a200641026a2d00003a0000200541e80d6a200641136a290000370300200541ed0d6a200641186a290000370000200520062f00003b01102005200629000b3703e00d200628000721022006280003210f410121100c2b0b200520023602f40d200520063602f00d200520083602ec0d200520093702e40d200520073602e00d200541e00d6a41186a200541f0016a41a80110848e8080002103200520013602d0074102210220052005410c6a3602d4072005200541e00d6a3602cc070240024020074102470d000c010b200541c00f6a41086a200541e00d6a41086a280200360200200520052902e00d3703c00f200541106a41186a200141186a290000370300200541106a41106a200141106a290000370300200541106a41086a200141086a29000037030020052001290000370310200541800c6a200541106a200541c00f6a200410ed8580800020052d00800c22024102460d0a200541fe0b6a20052d00830c3a0000200541f8086a41086a200541800c6a41106a290200370300200541f8086a41106a200541800c6a41186a290200370300200541f8086a41186a200541a00c6a280200360200200520052f00810c3b01fc0b200520052902880c3703f80820052802840c210620052802ec0d2108200221020b4102210420054184046a41026a200541fc0b6a41026a2d00003a0000200541e8036a41086a200541f8086a41086a290300370300200541e8036a41106a200541f8086a41106a290300370300200541e8036a41186a200541f8086a41186a280200360200200520052f01fc0b3b018404200520052903f8083703e80320084102470d020c030b20052902e401211120052802e001210f200520023602e80d200520063602e40d200520083602e00d200541ec0d6a200541f0016a41a80110848e80800021032005200a3702980f2005200b3602940f200520013602d0074102210220052005410c6a3602d4072005200541e00d6a3602cc070240024020084102470d000c010b200541c00f6a41086a200541e00d6a41086a280200360200200520052902e00d3703c00f200541106a41186a200141186a290000370300200541106a41106a200141106a290000370300200541106a41086a200141086a29000037030020052001290000370310200541800c6a200541106a200541c00f6a200410ed8580800020052d00800c22024102460d19200541fe0b6a20052d00830c3a0000200541f8086a41086a200541800c6a41106a290200370300200541f8086a41106a200541800c6a41186a290200370300200541f8086a41186a200541a00c6a280200360200200520052f00810c3b01fc0b200520052902880c3703f80820052802840c2106200221020b4102210420054194086a41026a200541fc0b6a41026a2d00003a0000200541f8076a41086a200541f8086a41086a290300370300200541f8076a41106a200541f8086a41106a290300370300200541f8076a41186a200541f8086a41186a280200360200200520052f01fc0b3b019408200520052903f8083703f80720052802ec0d4102470d030c040b200520023602e403200520063602e003200520083602dc03200541003602880e200541e00d6a200720072009a76a10f58d808000200541106a41086a2203200541e00d6a41106a290200370300200541106a41106a2202200541e00d6a41186a290200370300200541106a41186a2204200541800e6a290200370300200520052902e80d37031020052802e40d211220052802e00d211320052802880e210d200541800c6a41186a200141186a290000370300200541800c6a41106a200141106a290000370300200541800c6a41086a200141086a290000370300200520012900003703800c200541e00d6a200541800c6a200541dc036a200528020c10ed85808000024020052d00e00d22104102460d00200541d4036a41026a20052d00e30d3a0000200541b8036a41086a200541f40d6a290200370300200541b8036a41106a200541fc0d6a29020037030020054198036a41086a200329030037030020054198036a41106a200229030037030020054198036a41186a2004290300370300200520052f00e10d3b01d403200520052902ec0d3703b80320052005290310370398032009422088a7211420052802e40d210f20052802e80d21024106210c0c2a0b20052802e40d2101200041083a000020002001360204200d4129490d2a201341002802c0a3c68000118080808000000c2a0b200541c00f6a41086a200541ec0d6a220441086a280200360200200520042902003703c00f200541106a41186a200141186a290000370300200541106a41106a200141106a290000370300200541106a41086a200141086a29000037030020052001290000370310200541800c6a200541106a200541c00f6a200528020c10ed8580800020052d00800c22044102460d07200541fe0b6a20052d00830c3a000020054180096a200541800c6a41106a290200370300200541f8086a41106a200541800c6a41186a290200370300200541f8086a41186a200541a00c6a280200360200200520052f00810c3b01fc0b200520052902880c3703f80820052802840c2108200421040b41022107200541a4046a41026a200541fc0b6a41026a2d00003a000020054188046a41086a200541f8086a41086a29030037030020054188046a41106a200541f8086a41106a29030037030020054188046a41186a200541f8086a41186a280200360200200520052f01fc0b3b01a404200520052903f808370388040240024020052802f80d4102470d000c010b200541c00f6a41086a200341086a280200360200200520032902003703c00f200541106a41186a200141186a290000370300200541106a41106a200141106a290000370300200541106a41086a200141086a29000037030020052001290000370310200541800c6a200541106a200541c00f6a200528020c10ed8580800020052d00800c22034102460d08200541fe0b6a20052d00830c3a000020054180096a200541800c6a41106a290200370300200541f8086a41106a200541800c6a41186a290200370300200541f8086a41186a200541a00c6a280200360200200520052f00810c3b01fc0b200520052902880c3703f80820052802840c210d200321070b41022103200541c4046a41026a200541fc0b6a41026a2d00003a0000200541a8046a41086a200541f8086a41086a290300370300200541a8046a41106a200541f8086a41106a290300370300200541a8046a41186a200541f8086a41186a280200360200200520052f01fc0b3b01c404200520052903f8083703a8040240024020052802840e4102470d000c010b200541c00f6a41086a200541840e6a220341086a280200360200200520032902003703c00f200541106a41186a200141186a290000370300200541106a41106a200141106a290000370300200541106a41086a200141086a29000037030020052001290000370310200541800c6a200541106a200541c00f6a200528020c10ed8580800020052d00800c22014102460d09200541fe0b6a20052d00830c3a000020054180096a200541800c6a41106a290200370300200541f8086a41106a200541800c6a41186a290200370300200541f8086a41186a200541a00c6a280200360200200520052f00810c3b01fc0b200520052902880c3703f80820052802840c2113200121030b200541e4046a41026a200541fc0b6a41026a2d00003a0000200541c8046a41086a200541f8086a41086a290300370300200541c8046a41106a200541f8086a41106a290300370300200541c8046a41186a200541f8086a41186a280200360200200520052f01fc0b3b01e404200520052903f8083703c804200541800c6a200541cc076a410410ee8580800020052d00800c22014103460d0920054184056a41026a20052d00830c3a0000200541e8046a41086a200541800c6a41106a290200370300200541e8046a41106a200541800c6a41186a290200370300200541e8046a41186a200541a00c6a220f280200360200200520052f00810c3b018405200520052902880c3703e80420052802840c210c200541800c6a200541cc076a410510ee8580800020052d00800c22144103460d0a200541a4056a41026a20052d00830c3a000020054188056a41086a200541800c6a41106a221229020037030020054188056a41106a200541800c6a41186a221029020037030020054188056a41186a200f280200360200200520052f00810c3b01a405200520052902880c3703880520052802840c210f200541800c6a200541cc076a410610ee8580800020052d00800c22154103460d0b200541c4056a41026a20052d00830c3a0000200541a8056a41086a2012290200370300200541a8056a41106a2010290200370300200541a8056a41186a200541a00c6a2212280200360200200520052f00810c3b01c405200520052902880c3703a80520052802840c2116200541800c6a200541cc076a410710ee8580800020052d00800c22174103460d0c200541e4056a41026a20052d00830c3a0000200541c8056a41086a200541800c6a41106a2210290200370300200541c8056a41106a200541800c6a41186a2218290200370300200541c8056a41186a2012280200360200200520052f00810c3b01e405200520052902880c3703c80520052802840c2119200541800c6a200541cc076a410810ee8580800020052d00800c221a4103460d0d20054184066a41026a20052d00830c3a0000200541e8056a41086a2010290200370300200541e8056a41106a2018290200370300200541e8056a41186a200541a00c6a2212280200360200200520052f00810c3b018406200520052902880c3703e80520052802840c2118200541800c6a200541cc076a410910ee8580800020052d00800c221b4103460d0e200541a4066a41026a20052d00830c3a000020054188066a41086a200541800c6a41106a221029020037030020054188066a41106a200541800c6a41186a221c29020037030020054188066a41186a2012280200360200200520052f00810c3b01a406200520052902880c3703880620052802840c211d200541800c6a200541cc076a410a10ee8580800020052d00800c221e4103460d0f200541c4066a41026a20052d00830c3a0000200541a8066a41086a2010290200370300200541a8066a41106a201c290200370300200541a8066a41186a200541a00c6a2212280200360200200520052f00810c3b01c406200520052902880c3703a80620052802840c211c200541800c6a200541cc076a410b10ee8580800020052d00800c221f4103460d10200541e4066a41026a20052d00830c3a0000200541c8066a41086a200541800c6a41106a2210290200370300200541c8066a41106a200541800c6a41186a2220290200370300200541c8066a41186a2012280200360200200520052f00810c3b01e406200520052902880c3703c80620052802840c2121200541800c6a200541cc076a410c10ee8580800020052d00800c22224103460d1120054184076a41026a20052d00830c3a0000200541e8066a41086a2010290200370300200541e8066a41106a2020290200370300200541e8066a41186a200541a00c6a2212280200360200200520052f00810c3b018407200520052902880c3703e80620052802840c2120200541800c6a200541cc076a410d10ee8580800020052d00800c22234103460d12200541a4076a41026a20052d00830c3a000020054188076a41086a200541800c6a41106a221029020037030020054188076a41106a200541800c6a41186a222429020037030020054188076a41186a2012280200360200200520052f00810c3b01a407200520052902880c3703880720052802840c2125200541800c6a200541cc076a410e10ee8580800020052d00800c22264103460d13200541c8076a41026a20052d00830c3a0000200541a8076a41086a2010290200370300200541a8076a41106a2024290200370300200541a8076a41186a200541a00c6a2212280200360200200520052f00810c3b01c807200520052902880c3703a80720052802840c2124200541800c6a200541cc076a410f10ee8580800002400240024020052d00800c22274103460d00200541f4076a41026a222820052d00830c3a0000200541d8076a41086a2229200541800c6a41106a290200370300200541d8076a41106a222a200541800c6a41186a290200370300200541d8076a41186a222b2012280200360200200520052f00810c3b01f407200520052902880c3703d80720052802840c212c41002d00fca3c680001a41c00441002802c8a3c68000118180808000002212450d17201220023a0000201220052f0184043b000120122006360204201220052903e803370208201220043a0024201220052f01a4043b002541032110201241036a20054184046a41026a2d00003a0000201241106a200541e8036a41086a290300370200201241186a200541e8036a41106a290300370200201241206a200541e8036a41186a280200360200201241276a200541a4046a41026a2d00003a000020122008360228201220073a00482012200d36024c201220052903880437022c201241346a20054188046a41086a2903003702002012413c6a20054188046a41106a290300370200201241c4006a20054188046a41186a280200360200201220052f01c4043b0049201241cb006a200541c4046a41026a2d00003a0000201220052903a804370250201241d8006a200541a8046a41086a290300370200201241e0006a200541a8046a41106a290300370200201241e8006a200541a8046a41186a280200360200201220033a006c20122013360270201220013a009001201220052f01e4043b006d201241ef006a200541e4046a41026a2d00003a00002012418c016a200541c8046a41186a28020036020020124184016a200541c8046a41106a290300370200201241fc006a200541c8046a41086a290300370200201220052903c804370274201220052f0184053b00910120124193016a20054184056a41026a2d00003a00002012200c36029401201241b0016a200541e8046a41186a280200360200201241a8016a200541e8046a41106a290300370200201241a0016a200541e8046a41086a290300370200201220052903e80437029801201220143a00b401201241b7016a200541a4056a41026a2d00003a0000201220052f01a4053b00b5012012200f3602b801201241d4016a20054188056a41186a280200360200201241cc016a20054188056a41106a290300370200201241c4016a20054188056a41086a29030037020020122005290388053702bc01201220153a00d801201241db016a200541c4056a41026a2d00003a0000201220052f01c4053b00d901201220163602dc01201241f8016a200541a8056a41186a280200360200201241f0016a200541a8056a41106a290300370200201241e8016a200541a8056a41086a290300370200201220052903a8053702e001201220173a00fc01201241ff016a200541e4056a41026a2d00003a0000201220052f01e4053b00fd0120122019360280022012419c026a200541c8056a41186a28020036020020124194026a200541c8056a41106a2903003702002012418c026a200541c8056a41086a290300370200201220052903c805370284022012201a3a00a002201241a3026a20054184066a41026a2d00003a0000201220052f0184063b00a102201220183602a402201241c0026a200541e8056a41186a280200360200201241b8026a200541e8056a41106a290300370200201241b0026a200541e8056a41086a290300370200201220052903e8053702a8022012201b3a00c402201241c7026a200541a4066a41026a2d00003a0000201220052f01a4063b00c5022012201d3602c802201241e4026a20054188066a41186a280200360200201241dc026a20054188066a41106a290300370200201241d4026a20054188066a41086a29030037020020122005290388063702cc022012201e3a00e802201241eb026a200541c4066a41026a2d00003a0000201220052f01c4063b00e9022012201c3602ec0220124188036a200541a8066a41186a28020036020020124180036a200541a8066a41106a290300370200201241f8026a200541a8066a41086a290300370200201220052903a8063702f0022012201f3a008c032012418f036a200541e4066a41026a2d00003a0000201220052f01e4063b008d032012202136029003201241ac036a200541c8066a41186a280200360200201241a4036a200541c8066a41106a2903003702002012419c036a200541c8066a41086a290300370200201220052903c80637029403201220223a00b003201241b3036a20054184076a41026a2d00003a0000201220052f0184073b00b103201220203602b403201241d0036a200541e8066a41186a280200360200201241c8036a200541e8066a41106a290300370200201241c0036a200541e8066a41086a290300370200201220052903e8063702b803201220233a00d403201241d7036a200541a4076a41026a2d00003a0000201220052f01a4073b00d503201220253602d803201241f4036a20054188076a41186a280200360200201241ec036a20054188076a41106a290300370200201241e4036a20054188076a41086a29030037020020122005290388073702dc03201220263a00f803201241fb036a200541c8076a41026a2d00003a0000201220052f01c8073b00f903201220243602fc0320124198046a200541a8076a41186a28020036020020124190046a200541a8076a41106a29030037020020124188046a200541a8076a41086a290300370200201220052903a80737028004201220273a009c042012419f046a20282d00003a0000201220052f01f4073b009d042012202c3602a004201241bc046a202b280200360200201241b4046a202a290300370200201241ac046a2029290300370200201220052903d8073702a404200b4102470d010c020b20052802840c2101200041083a0000200020013602040c2a0b2005200a3702fc082005200b3602f808200541800c6a200541f8086a10e285808000200541da076a20052d00830c3a0000200541186a200541940c6a290200370300200541206a2005419c0c6a290200370300200520052f00810c3b01d8072005200529028c0c37031020052d00800c211020052802840c210f20052802880c210220052802a40c211420052802a80c21130b200541d4036a41026a200541d8076a41026a2d00003a0000200541b8036a41086a200541106a41086a290300370300200541b8036a41106a200541106a41106a290300370300200520052f01d8073b01d403200520052903103703b8034107210c0c270b200541c00f6a41086a200341086a280200360200200520032902003703c00f200541106a41186a200141186a290000370300200541106a41106a200141106a290000370300200541106a41086a200141086a29000037030020052001290000370310200541800c6a200541106a200541c00f6a200528020c10ed8580800020052d00800c22034102460d15200541fe0b6a20052d00830c3a000020054180096a200541800c6a41106a290200370300200541f8086a41106a200541800c6a41186a290200370300200541f8086a41186a200541a00c6a280200360200200520052f00810c3b01fc0b200520052902880c3703f80820052802840c2108200321040b41022103200541b4086a41026a200541fc0b6a41026a2d00003a000020054198086a41086a200541f8086a41086a29030037030020054198086a41106a200541f8086a41106a29030037030020054198086a41186a200541f8086a41186a280200360200200520052f01fc0b3b01b408200520052903f808370398080240024020052802f80d4102470d000c010b200541c00f6a41086a200541e00d6a41186a220341086a280200360200200520032902003703c00f200541106a41186a200141186a290000370300200541106a41106a200141106a290000370300200541106a41086a200141086a29000037030020052001290000370310200541800c6a200541106a200541c00f6a200528020c10ed8580800020052d00800c22034102460d16200541fe0b6a20052d00830c3a000020054180096a200541800c6a41106a290200370300200541f8086a41106a200541800c6a41186a290200370300200541f8086a41186a200541a00c6a280200360200200520052f00810c3b01fc0b200520052902880c3703f80820052802840c2110200321030b4102210d200541d4086a41026a200541fc0b6a41026a2d00003a0000200541b8086a41086a200541f8086a41086a290300370300200541b8086a41106a200541f8086a41106a290300370300200541b8086a41186a200541f8086a41186a280200360200200520052f01fc0b3b01d408200520052903f8083703b8080240024020052802840e4102470d000c010b200541c00f6a41086a200541840e6a220d41086a2802003602002005200d2902003703c00f200541106a41186a200141186a290000370300200541106a41106a200141106a290000370300200541106a41086a200141086a29000037030020052001290000370310200541800c6a200541106a200541c00f6a200528020c10ed8580800020052d00800c220d4102460d17200541fe0b6a20052d00830c3a000020054180096a200541800c6a41106a290200370300200541f8086a41106a200541800c6a41186a290200370300200541f8086a41186a200541a00c6a280200360200200520052f00810c3b01fc0b200520052902880c3703f80820052802840c210b200d210d0b41022114200541f4086a41026a200541fc0b6a41026a2d00003a0000200541d8086a41086a200541f8086a41086a290300370300200541d8086a41106a200541f8086a41106a290300370300200541d8086a41186a200541f8086a41186a280200360200200520052f01fc0b3b01f408200520052903f8083703d8080240024020052802900e4102470d000c010b200541c00f6a41086a200541900e6a221341086a280200360200200520132902003703c00f200541106a41186a200141186a290000370300200541106a41106a200141106a290000370300200541106a41086a200141086a29000037030020052001290000370310200541800c6a200541106a200541c00f6a200528020c10ed8580800020052d00800c22134102460d18200541fe0b6a20052d00830c3a000020054180096a200541800c6a41106a290200370300200541f8086a41106a200541800c6a41186a290200370300200541f8086a41186a200541a00c6a280200360200200520052f00810c3b01fc0b200520052902880c3703f80820052802840c2101201321140b200541b4096a41026a200541fc0b6a41026a2d00003a000020054198096a41086a200541f8086a41086a29030037030020054198096a41106a200541f8086a41106a29030037030020054198096a41186a200541f8086a41186a280200360200200520052f01fc0b3b01b409200520052903f80837039809200541800c6a200541cc076a410510ef8580800020052d00800c22154103460d18200541d4096a41026a20052d00830c3a0000200541b8096a41086a200541800c6a41106a290200370300200541b8096a41106a200541800c6a41186a290200370300200541b8096a41186a200541a00c6a2213280200360200200520052f00810c3b01d409200520052902880c3703b80920052802840c2116200541800c6a200541cc076a410610ef8580800020052d00800c22174103460d19200541f4096a41026a20052d00830c3a0000200541d8096a41086a200541800c6a41106a2212290200370300200541d8096a41106a200541800c6a41186a220c290200370300200541d8096a41186a2013280200360200200520052f00810c3b01f409200520052902880c3703d80920052802840c2118200541800c6a200541cc076a410710ef8580800020052d00800c22194103460d1a200541940a6a41026a20052d00830c3a0000200541f8096a41086a2012290200370300200541f8096a41106a200c290200370300200541f8096a41186a200541a00c6a2213280200360200200520052f00810c3b01940a200520052902880c3703f80920052802840c211a200541800c6a200541cc076a410810ef8580800020052d00800c221b4103460d1b200541b40a6a41026a20052d00830c3a0000200541980a6a41086a200541800c6a41106a2212290200370300200541980a6a41106a200541800c6a41186a220c290200370300200541980a6a41186a2013280200360200200520052f00810c3b01b40a200520052902880c3703980a20052802840c211c200541800c6a200541cc076a410910ef8580800020052d00800c221d4103460d1c200541d40a6a41026a20052d00830c3a0000200541b80a6a41086a2012290200370300200541b80a6a41106a200c290200370300200541b80a6a41186a200541a00c6a2213280200360200200520052f00810c3b01d40a200520052902880c3703b80a20052802840c211e200541800c6a200541cc076a410a10ef8580800020052d00800c221f4103460d1d200541f40a6a41026a20052d00830c3a0000200541d80a6a41086a200541800c6a41106a2212290200370300200541d80a6a41106a200541800c6a41186a220c290200370300200541d80a6a41186a2013280200360200200520052f00810c3b01f40a200520052902880c3703d80a20052802840c2120200541800c6a200541cc076a410b10ef8580800020052d00800c22214103460d1e200541940b6a41026a20052d00830c3a0000200541f80a6a41086a2012290200370300200541f80a6a41106a200c290200370300200541f80a6a41186a200541a00c6a2213280200360200200520052f00810c3b01940b200520052902880c3703f80a20052802840c2122200541800c6a200541cc076a410c10ef8580800020052d00800c22234103460d1f200541b40b6a41026a20052d00830c3a0000200541980b6a41086a200541800c6a41106a2212290200370300200541980b6a41106a200541800c6a41186a220c290200370300200541980b6a41186a2013280200360200200520052f00810c3b01b40b200520052902880c3703980b20052802840c2124200541800c6a200541cc076a410d10ef8580800020052d00800c22254103460d20200541d40b6a41026a20052d00830c3a0000200541b80b6a41086a2012290200370300200541b80b6a41106a200c290200370300200541b80b6a41186a200541a00c6a2213280200360200200520052f00810c3b01d40b200520052902880c3703b80b20052802840c2126200541800c6a200541cc076a410e10ef8580800020052d00800c22274103460d21200541f80b6a41026a20052d00830c3a0000200541d80b6a41086a200541800c6a41106a2212290200370300200541d80b6a41106a200541800c6a41186a220c290200370300200541d80b6a41186a2013280200360200200520052f00810c3b01f80b200520052902880c3703d80b20052802840c2128200541800c6a200541cc076a410f10ef8580800002400240024020052d00800c22294103460d00200541f4076a41026a20052d00830c3a0000200541d8076a41086a2012290200370300200541d8076a41106a200c290200370300200541d8076a41186a200541800c6a41206a280200360200200520052f00810c3b01f407200520052902880c3703d80720052802840c212a41002d00fca3c680001a41c00441002802c8a3c68000118180808000002213450d252009422088a72112201320023a0000201320052f0194083b000120132006360204201320052903f807370208201320043a0024201320052f01b4083b00254103210c201341036a20054194086a41026a2d00003a0000201341106a200541f8076a41086a290300370200201341186a200541f8076a41106a290300370200201341206a200541f8076a41186a280200360200201341276a200541b4086a41026a2d00003a000020132008360228201320033a00482013201036024c201320052903980837022c201341346a20054198086a41086a2903003702002013413c6a20054198086a41106a290300370200201341c4006a20054198086a41186a280200360200201320052f01d4083b0049201341cb006a200541d4086a41026a2d00003a0000201320052903b808370250201341d8006a200541b8086a41086a290300370200201341e0006a200541b8086a41106a290300370200201341e8006a200541b8086a41186a2802003602002013200d3a006c2013200b360270201320143a009001201320052f01f4083b006d201341ef006a200541f4086a41026a2d00003a00002013418c016a200541d8086a41186a28020036020020134184016a200541d8086a41106a290300370200201341fc006a200541d8086a41086a290300370200201320052903d808370274201320052f01b4093b00910120134193016a200541b4096a41026a2d00003a00002013200136029401201341b0016a20054198096a41186a280200360200201341a8016a20054198096a41106a290300370200201341a0016a20054198096a41086a290300370200201320052903980937029801201320153a00b401201341b7016a200541d4096a41026a2d00003a0000201320052f01d4093b00b501201320163602b801201341d4016a200541b8096a41186a280200360200201341cc016a200541b8096a41106a290300370200201341c4016a200541b8096a41086a290300370200201320052903b8093702bc01201320173a00d801201341db016a200541f4096a41026a2d00003a0000201320052f01f4093b00d901201320183602dc01201341f8016a200541d8096a41186a280200360200201341f0016a200541d8096a41106a290300370200201341e8016a200541d8096a41086a290300370200201320052903d8093702e001201320193a00fc01201341ff016a200541940a6a41026a2d00003a0000201320052f01940a3b00fd012013201a360280022013419c026a200541f8096a41186a28020036020020134194026a200541f8096a41106a2903003702002013418c026a200541f8096a41086a290300370200201320052903f809370284022013201b3a00a002201341a3026a200541b40a6a41026a2d00003a0000201320052f01b40a3b00a1022013201c3602a402201341c0026a200541980a6a41186a280200360200201341b8026a200541980a6a41106a290300370200201341b0026a200541980a6a41086a290300370200201320052903980a3702a8022013201d3a00c402201341c7026a200541d40a6a41026a2d00003a0000201320052f01d40a3b00c5022013201e3602c802201341e4026a200541b80a6a41186a280200360200201341dc026a200541b80a6a41106a290300370200201341d4026a200541b80a6a41086a290300370200201320052903b80a3702cc022013201f3a00e802201341eb026a200541f40a6a41026a2d00003a0000201320052f01f40a3b00e902201320203602ec0220134188036a200541d80a6a41186a28020036020020134180036a200541d80a6a41106a290300370200201341f8026a200541d80a6a41086a290300370200201320052903d80a3702f002201320213a008c032013418f036a200541940b6a41026a2d00003a0000201320052f01940b3b008d032013202236029003201341ac036a200541f80a6a41186a280200360200201341a4036a200541f80a6a41106a2903003702002013419c036a200541f80a6a41086a290300370200201320052903f80a37029403201320233a00b003201341b3036a200541b40b6a41026a2d00003a0000201320052f01b40b3b00b103201320243602b403201341d0036a200541980b6a41186a280200360200201341c8036a200541980b6a41106a290300370200201341c0036a200541980b6a41086a290300370200201320052903980b3702b803201320253a00d403201341d7036a200541d40b6a41026a2d00003a0000201320052f01d40b3b00d503201320263602d803201341f4036a200541b80b6a41186a280200360200201341ec036a200541b80b6a41106a290300370200201341e4036a200541b80b6a41086a290300370200201320052903b80b3702dc03201320273a00f803201341fb036a200541f80b6a41026a2d00003a0000201320052f01f80b3b00f903201320283602fc0320134198046a200541d80b6a41186a28020036020020134190046a200541d80b6a41106a29030037020020134188046a200541d80b6a41086a290300370200201320052903d80b37028004201320293a009c042013419f046a200541f4076a41026a2d00003a0000201320052f01f4073b009d042013202a3602a004201341bc046a200541d8076a41186a280200360200201341b4046a200541d8076a41106a290300370200201341ac046a200541d8076a41086a290300370200201320052903d8073702a404200541003602a80c200541800c6a200720072009a76a10f58d808000200541106a41186a2201200541800c6a41186a2202290200370300200541106a41106a2203200541800c6a41106a290200370300200541106a41086a2204200541800c6a41086a290200370300200520052902800c37031020052802a00c210d20052902a40c210e200f4102470d010c020b20052802840c2101200041083a0000200020013602040c280b200520113702dc072005200f3602d807200541800c6a200541d8076a10e285808000200541c00f6a41026a20052d00830c3a0000200541fc0b6a41026a200541870c6a2d00003a0000200541f8086a41086a2002290200370300200541f8086a41106a200541a00c6a290200370300200520052f00810c3b01c00f200520052f00850c3b01fc0b200520052902900c3703f80820052d00800c210c20052d00840c211020052802880c210f200528028c0c210220052802a80c21140b20054198036a41186a200129030037030020054198036a41106a200329030037030020054198036a41086a2004290300370300200541d8036a41026a200541c00f6a41026a2d00003a0000200541d4036a41026a200541fc0b6a41026a2d00003a0000200541b8036a41106a200541f8086a41106a290300370300200541b8036a41086a200541f8086a41086a2903003703002005200529031037039803200520052f01c00f3b01d803200520052f01fc0b3b01d403200520052903f8083703b8030c250b200120052903e00d370200200141286a2006290300370200200141206a2004290300370200200141186a2002290300370200200141106a200541e00d6a41106a290300370200200141086a2003290300370200200041083a0000200020013602040c250b41e484c08000412b200541e00d6a419085c08000419086c08000108981808000000b412020024190d1c2800010a281808000000b20052802840c2101200041083a0000200020013602040c220b20052802840c2101200041083a0000200020013602040c210b20052802840c2101200041083a0000200020013602040c200b20052802840c2101200041083a0000200020013602040c1f0b20052802840c2101200041083a0000200020013602040c1e0b20052802840c2101200041083a0000200020013602040c1d0b20052802840c2101200041083a0000200020013602040c1c0b20052802840c2101200041083a0000200020013602040c1b0b20052802840c2101200041083a0000200020013602040c1a0b20052802840c2101200041083a0000200020013602040c190b20052802840c2101200041083a0000200020013602040c180b20052802840c2101200041083a0000200020013602040c170b20052802840c2101200041083a0000200020013602040c160b20052802840c2101200041083a0000200020013602040c150b20052802840c2101200041083a0000200020013602040c140b410441c00410b280808000000b20052802840c2101200041083a0000200020013602040c120b20052802840c2101200041083a0000200020013602040c110b20052802840c2101200041083a0000200020013602040c100b20052802840c2101200041083a0000200020013602040c0f0b20052802840c2101200041083a0000200020013602040c0e0b20052802840c2101200041083a0000200020013602040c0d0b20052802840c2101200041083a0000200020013602040c0c0b20052802840c2101200041083a0000200020013602040c0b0b20052802840c2101200041083a0000200020013602040c0a0b20052802840c2101200041083a0000200020013602040c090b20052802840c2101200041083a0000200020013602040c080b20052802840c2101200041083a0000200020013602040c070b20052802840c2101200041083a0000200020013602040c060b20052802840c2101200041083a0000200020013602040c050b20052802840c2101200041083a0000200020013602040c040b410441c00410b280808000000b200f428180808010370200200f41086a2006200210848e8080001a410021100b2009422088a7211220054198036a41186a200541800c6a41186a29030037030020054198036a41106a200541800c6a41106a29030037030020054198036a41086a200541800c6a41086a290300370300200541d4036a41026a200541106a41026a2d00003a0000200541b8036a41086a200541e00d6a41086a290300370300200541b8036a41106a200541e00d6a41106a290300370300200520052903800c37039803200520052f01103b01d403200520052903e00d3703b8034105210c0b200020052f01d8033b0001200020052f01d4033b0005200020052903b8033702102000200529039803370234200041036a200541d8036a41026a2d00003a0000200041076a200541d4036a41026a2d00003a0000200041186a200541b8036a41086a290300370200200041206a200541b8036a41106a2903003702002000413c6a20054198036a41086a290300370200200041c4006a20054198036a41106a290300370200200041cc006a20054198036a41186a2903003702002000200e3702582000200d3602542000200f3602082000200236020c200020143602282000201336022c20002012360230200020103a00042000200c3a00000b200541d00f6a2480808080000ba30801057f23808080800041e0016b2204248080808000200241086a28020021052002280204210602400240024002400240024020022802000d00024002400240024020050d00410121020c010b20054120460d012005417f4c0d0441002d00fca3c680001a200541002802c8a3c68000118180808000002202450d050b20022006200510848e808000210341002d00fca3c680001a413041002802c8a3c680001181808080000022020d014104413010b280808000000b2004411c6a41026a200641026a2d00003a0000200441086a2006410f6a290000370300200441106a200641176a290000370300200441186a2006411f6a2d00003a0000200420062f00003b011c2004200629000737030020062800032102410121060c050b2002200536020c2002200336020820022005360204200241888080807836020020022001290000370010200241186a200141086a290000370000200241206a200141106a290000370000200241286a200141186a2900003700000c030b20044180016a41186a200141186a29000037030020044180016a41106a200141106a29000037030020044180016a41086a200141086a2900003703002004200129000037038001200441206a20044180016a20062005200310ec85808000024020042d002022054108460d00200441dc016a41026a20042d00233a0000200420042f00213b01dc012004280224210720044180016a200441286a41d80010848e8080001a02400240200341186a2802002201450d0020032001417f6a36021841002106200341146a22012001280200220141016a22024100200328020c220820022008491b6b360200200341106a28020020014102746a2802002202200328020822014f0d01200328020420024107746a220141046a200120012d00004108461b10e385808000200120053a0004200141083a000020012007360208200120042f01dc013b0005200141076a200441de016a2d00003a00002001410c6a20044180016a41d80010848e8080001a0c060b0240200328020822012003280200470d0020032001109e86808000200328020821010b200328020420014107746a220120053a0004200141083a0000200120042f01dc013b000520012007360208200141076a200441de016a2d00003a00002001410c6a20044180016a41d80010848e8080001a20032003280208220241016a360208410021060c050b2002200141d4d7c2800010f980808000000b200428022421020c020b10ae80808000000b4101200510b280808000000b200041023a0000200020023602040c010b200020042f011c3b00012000200429030037020820002002360204200020063a0000200041036a2004411e6a2d00003a0000200041106a200441086a290300370200200041186a200441106a290300370200200041206a200441186a2802003602000b200441e0016a2480808080000bd40201017f23808080800041d0006b220324808080800002402002410f4b0d000240024020012802002002410c6c6a22022802004102470d00200041023a00000c010b200341086a200241086a28020036020020032002290200370300200341306a41086a2001280204220241086a290000370300200341306a41106a200241106a290000370300200341306a41186a200241186a290000370300200320022900003703302003410c6a200341306a2003200128020828020010ed85808000024020032d000c4102460d002000200329020c370200200041206a2003410c6a41206a280200360200200041186a2003410c6a41186a290200370200200041106a2003410c6a41106a290200370200200041086a2003410c6a41086a2902003702000c010b20002003280210360204200041033a00000b200341d0006a2480808080000f0b2002411041b0d1c2800010f980808000000bd40201017f23808080800041d0006b220324808080800002402002410f4b0d000240024020012802002002410c6c6a22022802004102470d00200041023a00000c010b200341086a200241086a28020036020020032002290200370300200341306a41086a2001280204220241086a290000370300200341306a41106a200241106a290000370300200341306a41186a200241186a290000370300200320022900003703302003410c6a200341306a2003200128020828020010ed85808000024020032d000c4102460d002000200329020c370200200041206a2003410c6a41206a280200360200200041186a2003410c6a41186a290200370200200041106a2003410c6a41106a290200370200200041086a2003410c6a41086a2902003702000c010b20002003280210360204200041033a00000b200341d0006a2480808080000f0b2002411041a0d1c2800010f980808000000bb09e0101617f23808080800041800c6b2203248080808000024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024020012802002204417e6a2205410420054106491b0e06050001020304050b200341980b6a200141046a10fa8d808000200141386a21050240024020012802342202450d002005280200210520022002280200220441016a360200410021012004417f4a0d010c1f0b200341026a200541026a2d00003a0000200341c00a6a200141cb006a290000370300200341c50a6a200141d0006a290000370000200320052f00003b0100200320012900433703b80a200128003f2105200128003b2102410121010b200020032902980b370230200020013a0004200041056a20032f01003b0000200041d8006a200341980b6a41286a290200370200200041d0006a200341980b6a41206a290200370200200041c8006a200341980b6a41186a290200370200200041c0006a200341980b6a41106a290200370200200041386a200341980b6a41086a290200370200200041076a200341026a2d00003a00002000410c6a2005360200200041086a2002360200200041053a0000200041106a20032903b80a370200200041186a200341b80a6a41086a290300370200200041206a200341b80a6a41106a290300370200200041286a200341b80a6a41186a2903003702000c1c0b2003200141286a10fa8d8080000240024020012d00040d00200341ba0a6a200141076a2d00003a0000200341980b6a41086a200141146a290200370300200341a80b6a2001411c6a290200370300200341b00b6a200141246a2d00003a00002003200141056a2f00003b01b80a20032001410c6a2902003703980b200141086a2802002101410121020c010b200341b80a6a200141086a280200200210f0858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002201450d0020022001417f6a360218200241146a22012001280200220141016a22054100200228020c220420052004491b6b360200200241106a28020020014102746a2802002201200228020822054f0d0b200228020420014107746a220241046a200220022d00004108461b10e385808000200241083a0000200241016a200341980b6a41e30010848e8080001a0c010b0240200228020822012002280200470d0020022001109e86808000200228020821010b200228020420014107746a220141083a0000200141016a200341980b6a41e30010848e8080001a20022002280208220141016a3602080b410021020b20002003290200370228200020023a0004200041056a20032f01b80a3b0000200041086a2001360200200041d0006a200341286a290200370200200041c8006a200341206a290200370200200041c0006a200341186a290200370200200041386a200341106a290200370200200041306a200341086a290200370200200041076a200341ba0a6a2d00003a0000200041063a0000200041246a200341980b6a41186a2802003602002000411c6a200341980b6a41106a290300370200200041146a200341980b6a41086a2903003702002000410c6a20032903980b3702000c1b0b4102210641022107024020012d003022044102460d000240024020040d00200341026a200141336a2d00003a0000200341a00b6a200141c0006a290200370300200341a80b6a200141c8006a290200370300200341b00b6a200141d0006a2d00003a00002003200141316a2f00003b01002003200141386a2902003703980b200141346a2802002105410121070c010b200341b80a6a200141346a280200200210f0858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002205450d0020022005417f6a360218200241146a22052005280200220541016a22044100200228020c220820042008491b6b360200200241106a28020020054102746a2802002205200228020822044f0d0c200228020420054107746a220441046a200420042d00004108461b10e385808000200441083a0000200441016a200341980b6a41e30010848e8080001a0c010b0240200228020822052002280200470d0020022005109e86808000200228020821050b200228020420054107746a220541083a0000200541016a200341980b6a41e30010848e8080001a20022002280208220541016a3602080b410021070b200341f0006a41026a200341026a2d00003a0000200341e0056a41086a200341980b6a41086a290300370300200341e0056a41106a200341980b6a41106a290300370300200341e0056a41186a200341980b6a41186a280200360200200320032f01003b0170200320032903980b3703e0050b0240200141d4006a2d000022084102460d000240024020080d00200341026a200141d7006a2d00003a0000200341a00b6a200141e4006a290200370300200341a80b6a200141ec006a290200370300200341b00b6a200141f4006a2d00003a00002003200141d5006a2f00003b01002003200141dc006a2902003703980b200141d8006a2802002104410121060c010b200341b80a6a200141d8006a280200200210f0858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002204450d0020022004417f6a360218200241146a22042004280200220441016a22084100200228020c220920082009491b6b360200200241106a28020020044102746a2802002204200228020822084f0d0d200228020420044107746a220841046a200820082d00004108461b10e385808000200841083a0000200841016a200341980b6a41e30010848e8080001a0c010b0240200228020822042002280200470d0020022004109e86808000200228020821040b200228020420044107746a220441083a0000200441016a200341980b6a41e30010848e8080001a20022002280208220441016a3602080b410021060b200341f4006a41026a200341026a2d00003a000020034188066a41086a200341980b6a41086a29030037030020034188066a41106a200341980b6a41106a29030037030020034188066a41186a200341980b6a41186a280200360200200320032f01003b0174200320032903980b370388060b4102210a4102210b0240200141f8006a2d000022094102460d000240024020090d00200341026a200141fb006a2d00003a0000200341a00b6a20014188016a290200370300200341a80b6a20014190016a290200370300200341b00b6a20014198016a2d00003a00002003200141f9006a2f00003b0100200320014180016a2902003703980b200141fc006a28020021084101210b0c010b200341b80a6a200141fc006a280200200210f0858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002208450d0020022008417f6a360218200241146a22082008280200220841016a22094100200228020c220c2009200c491b6b360200200241106a28020020084102746a2802002208200228020822094f0d0e200228020420084107746a220941046a200920092d00004108461b10e385808000200941083a0000200941016a200341980b6a41e30010848e8080001a0c010b0240200228020822082002280200470d0020022008109e86808000200228020821080b200228020420084107746a220841083a0000200841016a200341980b6a41e30010848e8080001a20022002280208220841016a3602080b4100210b0b200341f8006a41026a200341026a2d00003a0000200341b0066a41086a200341980b6a41086a290300370300200341b0066a41106a200341980b6a41106a290300370300200341b0066a41186a200341980b6a41186a280200360200200320032f01003b0178200320032903980b3703b0060b02402001419c016a2d0000220c4102460d0002400240200c0d00200341026a2001419f016a2d00003a0000200341a00b6a200141ac016a290200370300200341a80b6a200141b4016a290200370300200341b00b6a200141bc016a2d00003a000020032001419d016a2f00003b01002003200141a4016a2902003703980b200141a0016a28020021094101210a0c010b200341b80a6a200141a0016a280200200210f0858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002209450d0020022009417f6a360218200241146a22092009280200220941016a220c4100200228020c220d200c200d491b6b360200200241106a28020020094102746a28020022092002280208220c4f0d0f200228020420094107746a220c41046a200c200c2d00004108461b10e385808000200c41083a0000200c41016a200341980b6a41e30010848e8080001a0c010b0240200228020822092002280200470d0020022009109e86808000200228020821090b200228020420094107746a220941083a0000200941016a200341980b6a41e30010848e8080001a20022002280208220941016a3602080b4100210a0b200341fc006a41026a200341026a2d00003a0000200341d8066a41086a200341980b6a41086a290300370300200341d8066a41106a200341980b6a41106a290300370300200341d8066a41186a200341980b6a41186a280200360200200320032f01003b017c200320032903980b3703d8060b4102210e4102210f0240200141c0016a2d0000220d4102460d0002400240200d0d00200341026a200141c3016a2d00003a0000200341a00b6a200141d0016a290200370300200341a80b6a200141d8016a290200370300200341b00b6a200141e0016a2d00003a00002003200141c1016a2f00003b01002003200141c8016a2902003703980b200141c4016a280200210c4101210f0c010b200341b80a6a200141c4016a280200200210f0858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a280200220c450d002002200c417f6a360218200241146a220c200c280200220c41016a220d4100200228020c2210200d2010491b6b360200200241106a280200200c4102746a280200220c2002280208220d4f0d102002280204200c4107746a220d41046a200d200d2d00004108461b10e385808000200d41083a0000200d41016a200341980b6a41e30010848e8080001a0c010b02402002280208220c2002280200470d002002200c109e868080002002280208210c0b2002280204200c4107746a220c41083a0000200c41016a200341980b6a41e30010848e8080001a20022002280208220c41016a3602080b4100210f0b20034180016a41026a200341026a2d00003a000020034180076a41086a200341980b6a41086a29030037030020034180076a41106a200341980b6a41106a29030037030020034180076a41186a200341980b6a41186a280200360200200320032f01003b018001200320032903980b370380070b0240200141e4016a2d000022104102460d000240024020100d00200341026a200141e7016a2d00003a0000200341a00b6a200141f4016a290200370300200341a80b6a200141fc016a290200370300200341b00b6a20014184026a2d00003a00002003200141e5016a2f00003b01002003200141ec016a2902003703980b200141e8016a280200210d4101210e0c010b200341b80a6a200141e8016a280200200210f0858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a280200220d450d002002200d417f6a360218200241146a220d200d280200220d41016a22104100200228020c221120102011491b6b360200200241106a280200200d4102746a280200220d200228020822104f0d112002280204200d4107746a221041046a201020102d00004108461b10e385808000201041083a0000201041016a200341980b6a41e30010848e8080001a0c010b02402002280208220d2002280200470d002002200d109e868080002002280208210d0b2002280204200d4107746a220d41083a0000200d41016a200341980b6a41e30010848e8080001a20022002280208220d41016a3602080b4100210e0b20034184016a41026a200341026a2d00003a0000200341a8076a41086a200341980b6a41086a290300370300200341a8076a41106a200341980b6a41106a290300370300200341a8076a41186a200341980b6a41186a280200360200200320032f01003b018401200320032903980b3703a8070b4102211241022113024020014188026a2d000022114102460d000240024020110d00200341026a2001418b026a2d00003a0000200341a00b6a20014198026a290200370300200341a80b6a200141a0026a290200370300200341b00b6a200141a8026a2d00003a0000200320014189026a2f00003b0100200320014190026a2902003703980b2001418c026a2802002110410121130c010b200341b80a6a2001418c026a280200200210f0858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002210450d0020022010417f6a360218200241146a22102010280200221041016a22114100200228020c221420112014491b6b360200200241106a28020020104102746a2802002210200228020822114f0d12200228020420104107746a221141046a201120112d00004108461b10e385808000201141083a0000201141016a200341980b6a41e30010848e8080001a0c010b0240200228020822102002280200470d0020022010109e86808000200228020821100b200228020420104107746a221041083a0000201041016a200341980b6a41e30010848e8080001a20022002280208221041016a3602080b410021130b20034188016a41026a200341026a2d00003a0000200341d0076a41086a200341980b6a41086a290300370300200341d0076a41106a200341980b6a41106a290300370300200341d0076a41186a200341980b6a41186a280200360200200320032f01003b018801200320032903980b3703d0070b0240200141ac026a2d000022144102460d000240024020140d00200341026a200141af026a2d00003a0000200341a00b6a200141bc026a290200370300200341a80b6a200141c4026a290200370300200341b00b6a200141cc026a2d00003a00002003200141ad026a2f00003b01002003200141b4026a2902003703980b200141b0026a2802002111410121120c010b200341b80a6a200141b0026a280200200210f0858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002211450d0020022011417f6a360218200241146a22112011280200221141016a22144100200228020c221520142015491b6b360200200241106a28020020114102746a2802002211200228020822144f0d13200228020420114107746a221441046a201420142d00004108461b10e385808000201441083a0000201441016a200341980b6a41e30010848e8080001a0c010b0240200228020822112002280200470d0020022011109e86808000200228020821110b200228020420114107746a221141083a0000201141016a200341980b6a41e30010848e8080001a20022002280208221141016a3602080b410021120b2003418c016a41026a200341026a2d00003a0000200341f8076a41086a200341980b6a41086a290300370300200341f8076a41106a200341980b6a41106a290300370300200341f8076a41186a200341980b6a41186a280200360200200320032f01003b018c01200320032903980b3703f8070b41022116410221170240200141d0026a2d000022154102460d000240024020150d00200341026a200141d3026a2d00003a0000200341a00b6a200141e0026a290200370300200341a80b6a200141e8026a290200370300200341b00b6a200141f0026a2d00003a00002003200141d1026a2f00003b01002003200141d8026a2902003703980b200141d4026a2802002114410121170c010b200341b80a6a200141d4026a280200200210f0858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002214450d0020022014417f6a360218200241146a22142014280200221441016a22154100200228020c221820152018491b6b360200200241106a28020020144102746a2802002214200228020822154f0d14200228020420144107746a221541046a201520152d00004108461b10e385808000201541083a0000201541016a200341980b6a41e30010848e8080001a0c010b0240200228020822142002280200470d0020022014109e86808000200228020821140b200228020420144107746a221441083a0000201441016a200341980b6a41e30010848e8080001a20022002280208221441016a3602080b410021170b20034190016a41026a200341026a2d00003a0000200341a0086a41086a200341980b6a41086a290300370300200341a0086a41106a200341980b6a41106a290300370300200341a0086a41186a200341980b6a41186a280200360200200320032f01003b019001200320032903980b3703a0080b0240200141f4026a2d000022184102460d000240024020180d00200341026a200141f7026a2d00003a0000200341a00b6a20014184036a290200370300200341a80b6a2001418c036a290200370300200341b00b6a20014194036a2d00003a00002003200141f5026a2f00003b01002003200141fc026a2902003703980b200141f8026a2802002115410121160c010b200341b80a6a200141f8026a280200200210f0858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002215450d0020022015417f6a360218200241146a22152015280200221541016a22184100200228020c221920182019491b6b360200200241106a28020020154102746a2802002215200228020822184f0d15200228020420154107746a221841046a201820182d00004108461b10e385808000201841083a0000201841016a200341980b6a41e30010848e8080001a0c010b0240200228020822152002280200470d0020022015109e86808000200228020821150b200228020420154107746a221541083a0000201541016a200341980b6a41e30010848e8080001a20022002280208221541016a3602080b410021160b20034194016a41026a200341026a2d00003a0000200341c8086a41086a200341980b6a41086a290300370300200341c8086a41106a200341980b6a41106a290300370300200341c8086a41186a200341980b6a41186a280200360200200320032f01003b019401200320032903980b3703c8080b4102211a4102211b024020014198036a2d000022194102460d000240024020190d00200341026a2001419b036a2d00003a0000200341a00b6a200141a8036a290200370300200341a80b6a200141b0036a290200370300200341b00b6a200141b8036a2d00003a0000200320014199036a2f00003b01002003200141a0036a2902003703980b2001419c036a28020021184101211b0c010b200341b80a6a2001419c036a280200200210f0858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002218450d0020022018417f6a360218200241146a22182018280200221841016a22194100200228020c221c2019201c491b6b360200200241106a28020020184102746a2802002218200228020822194f0d16200228020420184107746a221941046a201920192d00004108461b10e385808000201941083a0000201941016a200341980b6a41e30010848e8080001a0c010b0240200228020822182002280200470d0020022018109e86808000200228020821180b200228020420184107746a221841083a0000201841016a200341980b6a41e30010848e8080001a20022002280208221841016a3602080b4100211b0b20034198016a41026a200341026a2d00003a0000200341f0086a41086a200341980b6a41086a290300370300200341f0086a41106a200341980b6a41106a290300370300200341f0086a41186a200341980b6a41186a280200360200200320032f01003b019801200320032903980b3703f0080b0240200141bc036a2d0000221c4102460d0002400240201c0d00200341026a200141bf036a2d00003a0000200341a00b6a200141cc036a290200370300200341a80b6a200141d4036a290200370300200341b00b6a200141dc036a2d00003a00002003200141bd036a2f00003b01002003200141c4036a2902003703980b200141c0036a28020021194101211a0c010b200341b80a6a200141c0036a280200200210f0858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002219450d0020022019417f6a360218200241146a22192019280200221941016a221c4100200228020c221d201c201d491b6b360200200241106a28020020194102746a28020022192002280208221c4f0d17200228020420194107746a221c41046a201c201c2d00004108461b10e385808000201c41083a0000201c41016a200341980b6a41e30010848e8080001a0c010b0240200228020822192002280200470d0020022019109e86808000200228020821190b200228020420194107746a221941083a0000201941016a200341980b6a41e30010848e8080001a20022002280208221941016a3602080b4100211a0b2003419c016a41026a200341026a2d00003a000020034198096a41086a200341980b6a41086a29030037030020034198096a41106a200341980b6a41106a29030037030020034198096a41186a200341980b6a41186a280200360200200320032f01003b019c01200320032903980b370398090b4102211e4102211f0240200141e0036a2d0000221d4102460d0002400240201d0d00200341026a200141e3036a2d00003a0000200341a00b6a200141f0036a290200370300200341a80b6a200141f8036a290200370300200341b00b6a20014180046a2d00003a00002003200141e1036a2f00003b01002003200141e8036a2902003703980b200141e4036a280200211c4101211f0c010b200341b80a6a200141e4036a280200200210f0858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a280200221c450d002002201c417f6a360218200241146a221c201c280200221c41016a221d4100200228020c2220201d2020491b6b360200200241106a280200201c4102746a280200221c2002280208221d4f0d182002280204201c4107746a221d41046a201d201d2d00004108461b10e385808000201d41083a0000201d41016a200341980b6a41e30010848e8080001a0c010b02402002280208221c2002280200470d002002201c109e868080002002280208211c0b2002280204201c4107746a221c41083a0000201c41016a200341980b6a41e30010848e8080001a20022002280208221c41016a3602080b4100211f0b200341a0016a41026a200341026a2d00003a0000200341c0096a41086a200341980b6a41086a290300370300200341c0096a41106a200341980b6a41106a290300370300200341c0096a41186a200341980b6a41186a280200360200200320032f01003b01a001200320032903980b3703c0090b024020014184046a2d000022204102460d000240024020200d00200341026a20014187046a2d00003a0000200341a00b6a20014194046a290200370300200341a80b6a2001419c046a290200370300200341b00b6a200141a4046a2d00003a0000200320014185046a2f00003b010020032001418c046a2902003703980b20014188046a280200211d4101211e0c010b200341b80a6a20014188046a280200200210f0858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a280200221d450d002002201d417f6a360218200241146a221d201d280200221d41016a22204100200228020c222120202021491b6b360200200241106a280200201d4102746a280200221d200228020822204f0d192002280204201d4107746a222041046a202020202d00004108461b10e385808000202041083a0000202041016a200341980b6a41e30010848e8080001a0c010b02402002280208221d2002280200470d002002201d109e868080002002280208211d0b2002280204201d4107746a221d41083a0000201d41016a200341980b6a41e30010848e8080001a20022002280208221d41016a3602080b4100211e0b200341a4016a41026a200341026a2d00003a0000200341e8096a41086a200341980b6a41086a290300370300200341e8096a41106a200341980b6a41106a290300370300200341e8096a41186a200341980b6a41186a280200360200200320032f01003b01a401200320032903980b3703e8090b41022122410221230240200141a8046a2d000022214102460d000240024020210d00200341026a200141ab046a2d00003a0000200341a00b6a200141b8046a290200370300200341a80b6a200141c0046a290200370300200341b00b6a200141c8046a2d00003a00002003200141a9046a2f00003b01002003200141b0046a2902003703980b200141ac046a2802002120410121230c010b200341b80a6a200141ac046a280200200210f0858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002220450d0020022020417f6a360218200241146a22202020280200222041016a22214100200228020c222320212023491b6b360200200241106a28020020204102746a2802002220200228020822214f0d1a200228020420204107746a222141046a202120212d00004108461b10e385808000202141083a0000202141016a200341980b6a41e30010848e8080001a0c010b0240200228020822202002280200470d0020022020109e86808000200228020821200b200228020420204107746a222041083a0000202041016a200341980b6a41e30010848e8080001a20022002280208222041016a3602080b410021230b200341a8016a41026a200341026a2d00003a0000200341900a6a41086a200341980b6a41086a290300370300200341900a6a41106a200341980b6a41106a290300370300200341900a6a41186a200341980b6a41186a280200360200200320032f01003b01a801200320032903980b3703900a0b0240200141cc046a2d000022244102460d000240024020240d00200341ba056a200141cf046a2d00003a0000200341a00b6a200141dc046a290200370300200341a80b6a200141e4046a290200370300200341b00b6a200141ec046a2d00003a00002003200141cd046a2f00003b01b8052003200141d4046a2902003703980b200141d0046a2802002121410121220c010b200341b80a6a200141d0046a280200200210f0858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002221450d0020022021417f6a360218200241146a22212021280200222141016a22224100200228020c222420222024491b6b360200200241106a28020020214102746a2802002221200228020822224f0d1b200228020420214107746a220241046a200220022d00004108461b10e385808000200241083a0000200241016a200341980b6a41e30010848e8080001a0c010b0240200228020822212002280200470d0020022021109e86808000200228020821210b200228020420214107746a222141083a0000202141016a200341980b6a41e30010848e8080001a20022002280208222141016a3602080b410021220b200341ac016a41026a200341b8056a41026a2d00003a0000200341086a200341980b6a41086a290300370300200341106a200341980b6a41106a290300370300200341186a200341980b6a41186a280200360200200320032f01b8053b01ac01200320032903980b3703000b200341ec006a41026a2224200341f0006a41026a2d00003a0000200341980b6a41086a2225200341e0056a41086a290300370300200341980b6a41106a2226200341e0056a41106a290300370300200341980b6a41186a2227200341e0056a41186a280200360200200341e8006a41026a2228200341f4006a41026a2d00003a0000200341b80a6a41186a222920034188066a41186a280200360200200341b80a6a41106a222a20034188066a41106a290300370300200341b80a6a41086a222b20034188066a41086a290300370300200320032f01703b016c200320032903e0053703980b200320032f01743b016820032003290388063703b80a200341e4006a41026a222c200341f8006a41026a2d00003a0000200341b8056a41086a222d200341b0066a41086a290300370300200341b8056a41106a222e200341b0066a41106a290300370300200341b8056a41186a222f200341b0066a41186a280200360200200341e0006a41026a2230200341fc006a41026a2d00003a000020034190056a41086a2231200341d8066a41086a29030037030020034190056a41106a2232200341d8066a41106a29030037030020034190056a41186a2233200341d8066a41186a280200360200200320032f01783b0164200320032903b0063703b805200320032f017c3b0160200320032903d80637039005200341dc006a41026a223420034180016a41026a2d00003a0000200341e8046a41186a223520034180076a41186a280200360200200341e8046a41106a223620034180076a41106a290300370300200341e8046a41086a223720034180076a41086a290300370300200341d8006a41026a223820034184016a41026a2d00003a0000200341c0046a41186a2239200341a8076a41186a280200360200200341c0046a41106a223a200341a8076a41106a290300370300200341c0046a41086a223b200341a8076a41086a290300370300200320032f0180013b015c20032003290380073703e804200320032f0184013b0158200320032903a8073703c004200341d4006a41026a223c20034188016a41026a2d00003a0000200320032f0188013b015420034198046a41186a223d200341d0076a41186a28020036020020034198046a41106a223e200341d0076a41106a29030037030020034198046a41086a223f200341d0076a41086a290300370300200320032903d00737039804200341d0006a41026a22402003418c016a41026a2d00003a0000200320032f018c013b0150200341f0036a41186a2241200341f8076a41186a280200360200200341f0036a41106a2242200341f8076a41106a290300370300200341f0036a41086a2243200341f8076a41086a290300370300200320032903f8073703f003200341cc006a41026a224420034190016a41026a2d00003a0000200320032f0190013b014c200341c8036a41186a2245200341a0086a41186a280200360200200341c8036a41106a2246200341a0086a41106a290300370300200341c8036a41086a2247200341a0086a41086a290300370300200320032903a0083703c803200341c8006a41026a224820034194016a41026a2d00003a0000200320032f0194013b0148200341a0036a41186a2249200341c8086a41186a280200360200200341a0036a41106a224a200341c8086a41106a290300370300200341a0036a41086a224b200341c8086a41086a290300370300200320032903c8083703a003200341c4006a41026a224c20034198016a41026a2d00003a0000200320032f0198013b0144200341f8026a41186a224d200341f0086a41186a280200360200200341f8026a41106a224e200341f0086a41106a290300370300200341f8026a41086a224f200341f0086a41086a290300370300200320032903f0083703f802200341c0006a41026a22502003419c016a41026a2d00003a0000200320032f019c013b0140200341d0026a41186a225120034198096a41186a280200360200200341d0026a41106a225220034198096a41106a290300370300200341d0026a41086a225320034198096a41086a29030037030020032003290398093703d0022003413c6a41026a2254200341a0016a41026a2d00003a0000200320032f01a0013b013c200341a8026a41186a2255200341c0096a41186a280200360200200341a8026a41106a2256200341c0096a41106a290300370300200341a8026a41086a2257200341c0096a41086a290300370300200320032903c0093703a802200341386a41026a2258200341a4016a41026a2d00003a0000200320032f01a4013b013820034180026a41186a2259200341e8096a41186a28020036020020034180026a41106a225a200341e8096a41106a29030037030020034180026a41086a225b200341e8096a41086a290300370300200320032903e80937038002200341346a41026a225c200341a8016a41026a2d00003a0000200320032f01a8013b0134200341d8016a41186a225d200341900a6a41186a280200360200200341d8016a41106a225e200341900a6a41106a290300370300200341d8016a41086a225f200341900a6a41086a290300370300200320032903900a3703d801200341306a41026a2260200341ac016a41026a2d00003a0000200320032f01ac013b0130200341b0016a41186a2261200341186a280200360200200341b0016a41106a2262200341106a290300370300200341b0016a41086a2263200341086a290300370300200320032903003703b00141002d00fca3c680001a41c00441002802c8a3c68000118180808000002202450d18200220073a0000200220032f016c3b000120022005360204200220032903980b370008200220063a0024200220032f01683b002541032107200241036a20242d00003a0000200241106a2025290300370000200241186a2026290300370000200241206a2027280200360000200241276a20282d00003a0000200220043602282002200b3a00482002200836024c200220032903b80a37002c200241346a202b2903003700002002413c6a202a290300370000200241c4006a2029280200360000200220032f01643b0049200241cb006a202c2d00003a0000200220032903b805370050200241d8006a202d290300370000200241e0006a202e290300370000200241e8006a202f2802003600002002200a3a006c200220093602702002200f3a009001200220032f01603b006d200241ef006a20302d00003a00002002418c016a203328020036000020024184016a2032290300370000200241fc006a20312903003700002002200329039005370074200220032f015c3b00910120024193016a20342d00003a00002002200c36029401200241b0016a2035280200360000200241a8016a2036290300370000200241a0016a2037290300370000200220032903e804370098012002200e3a00b401200241b7016a20382d00003a0000200220032f01583b00b5012002200d3602b801200241d4016a2039280200360000200241cc016a203a290300370000200241c4016a203b290300370000200220032903c0043700bc01200220133a00d801200241db016a203c2d00003a0000200220032f01543b00d901200220103602dc01200241f8016a203d280200360000200241f0016a203e290300370000200241e8016a203f29030037000020022003290398043700e001200220123a00fc01200241ff016a20402d00003a0000200220032f01503b00fd0120022011360280022002419c026a204128020036000020024194026a20422903003700002002418c026a2043290300370000200220032903f00337008402200220173a00a002200241a3026a20442d00003a0000200220032f014c3b00a102200220143602a402200241c0026a2045280200360000200241b8026a2046290300370000200241b0026a2047290300370000200220032903c8033700a802200220163a00c402200241c7026a20482d00003a0000200220032f01483b00c502200220153602c802200241e4026a2049280200360000200241dc026a204a290300370000200241d4026a204b290300370000200220032903a0033700cc022002201b3a00e802200241eb026a204c2d00003a0000200220032f01443b00e902200220183602ec0220024188036a204d28020036000020024180036a204e290300370000200241f8026a204f290300370000200220032903f8023700f0022002201a3a008c032002418f036a20502d00003a0000200220032f01403b008d032002201936029003200241ac036a2051280200360000200241a4036a20522903003700002002419c036a2053290300370000200220032903d002370094032002201f3a00b003200241b3036a20542d00003a0000200220032f013c3b00b1032002201c3602b403200241d0036a2055280200360000200241c8036a2056290300370000200241c0036a2057290300370000200220032903a8023700b8032002201e3a00d403200241d7036a20582d00003a0000200220032f01383b00d5032002201d3602d803200241f4036a2059280200360000200241ec036a205a290300370000200241e4036a205b29030037000020022003290380023700dc03200220233a00f803200241fb036a205c2d00003a0000200220032f01343b00f903200220203602fc0320024198046a205d28020036000020024190046a205e29030037000020024188046a205f290300370000200220032903d80137008004200220223a009c042002419f046a20602d00003a0000200220032f01303b009d04200220213602a004200241bc046a2061280200360000200241b4046a2062290300370000200241ac046a2063290300370000200220032903b0013700a40420012802040d030c040b4102210541022108024020012d002c4102460d00200341980b6a2001412c6a200210f18580800020034190066a200341a10b6a29000037030020034198066a200341a90b6a290000370300200341a0066a200341b10b6a290000370300200341a7066a200341b80b6a280000360000200320032900990b3703880620032d00980b21080b0240200141d0006a22092d00004102460d00200341980b6a2009200210f185808000200341b8066a200341a10b6a290000370300200341c0066a200341a90b6a290000370300200341c8066a200341b10b6a290000370300200341cf066a200341b80b6a280000360000200320032900990b3703b00620032d00980b21050b410221094102210c0240200141f4006a220d2d00004102460d00200341980b6a200d200210f185808000200341e0066a200341a10b6a290000370300200341e8066a200341a90b6a290000370300200341f0066a200341b10b6a290000370300200341f7066a200341b80b6a280000360000200320032900990b3703d80620032d00980b210c0b024020014198016a220d2d00004102460d00200341980b6a200d200210f18580800020034188076a200341a10b6a29000037030020034190076a200341a90b6a29000037030020034198076a200341b10b6a2900003703002003419f076a200341b80b6a280000360000200320032900990b3703800720032d00980b21090b4102210d410221100240200141bc016a22112d00004102460d00200341980b6a2011200210f185808000200341b0076a200341a10b6a290000370300200341b8076a200341a90b6a290000370300200341c0076a200341b10b6a290000370300200341c7076a200341b80b6a280000360000200320032900990b3703a80720032d00980b21100b0240200141e0016a22112d00004102460d00200341980b6a2011200210f185808000200341d8076a200341a10b6a290000370300200341e0076a200341a90b6a290000370300200341e8076a200341b10b6a290000370300200341ef076a200341b80b6a280000360000200320032900990b3703d00720032d00980b210d0b4102211141022114024020014184026a22152d00004102460d00200341980b6a2015200210f18580800020034180086a200341a10b6a29000037030020034188086a200341a90b6a29000037030020034190086a200341b10b6a29000037030020034197086a200341b80b6a280000360000200320032900990b3703f80720032d00980b21140b0240200141a8026a22152d00004102460d00200341980b6a2015200210f185808000200341a8086a200341a10b6a290000370300200341b0086a200341a90b6a290000370300200341b8086a200341b10b6a290000370300200341bf086a200341b80b6a280000360000200320032900990b3703a00820032d00980b21110b41022115410221180240200141cc026a22192d00004102460d00200341980b6a2019200210f185808000200341d0086a200341a10b6a290000370300200341d8086a200341a90b6a290000370300200341e0086a200341b10b6a290000370300200341e7086a200341b80b6a280000360000200320032900990b3703c80820032d00980b21180b0240200141f0026a22192d00004102460d00200341980b6a2019200210f185808000200341f8086a200341a10b6a29000037030020034180096a200341a90b6a29000037030020034188096a200341b10b6a2900003703002003418f096a200341b80b6a280000360000200320032900990b3703f00820032d00980b21150b410221194102211c024020014194036a221d2d00004102460d00200341980b6a201d200210f185808000200341a0096a200341a10b6a290000370300200341a8096a200341a90b6a290000370300200341b0096a200341b10b6a290000370300200341b7096a200341b80b6a280000360000200320032900990b3703980920032d00980b211c0b0240200141b8036a221d2d00004102460d00200341980b6a201d200210f185808000200341c8096a200341a10b6a290000370300200341d0096a200341a90b6a290000370300200341d8096a200341b10b6a290000370300200341df096a200341b80b6a280000360000200320032900990b3703c00920032d00980b21190b4102211d410221200240200141dc036a22212d00004102460d00200341980b6a2021200210f185808000200341f0096a200341a10b6a290000370300200341f8096a200341a90b6a290000370300200341800a6a200341b10b6a290000370300200341870a6a200341b80b6a280000360000200320032900990b3703e80920032d00980b21200b024020014180046a22212d00004102460d00200341980b6a2021200210f185808000200341980a6a200341a10b6a290000370300200341a00a6a200341a90b6a290000370300200341a80a6a200341b10b6a290000370300200341af0a6a200341b80b6a280000360000200320032900990b3703900a20032d00980b211d0b41022121410221070240200141a4046a22062d00004102460d00200341980b6a2006200210f185808000200341086a200341a10b6a290000370300200341106a200341a90b6a290000370300200341186a200341b10b6a2900003703002003411f6a200341b80b6a280000360000200320032900990b37030020032d00980b21070b0240200141c8046a22062d00004102460d00200341980b6a2006200210f185808000200341c00a6a200341a10b6a290000370300200341c80a6a200341a90b6a290000370300200341d00a6a200341b10b6a290000370300200341d70a6a200341b80b6a280000360000200320032900990b3703b80a20032d00980b21210b200341980b6a411f6a220620034188066a411f6a280000360000200341980b6a41186a220b20034188066a41186a290300370300200341980b6a41106a220a20034188066a41106a290300370300200341980b6a41086a220f20034188066a41086a290300370300200341e0056a41086a220e200341b0066a41086a290300370300200341e0056a41106a2213200341b0066a41106a290300370300200341e0056a41186a2212200341b0066a41186a290300370300200341e0056a411f6a2217200341b0066a411f6a28000036000020032003290388063703980b200320032903b0063703e005200341b8056a411f6a2216200341d8066a411f6a280000360000200341b8056a41186a221b200341d8066a41186a290300370300200341b8056a41106a221a200341d8066a41106a290300370300200341b8056a41086a221f200341d8066a41086a29030037030020034190056a41086a221e20034180076a41086a29030037030020034190056a41106a222320034180076a41106a29030037030020034190056a41186a222220034180076a41186a29030037030020034190056a411f6a222420034180076a411f6a280000360000200320032903d8063703b805200320032903800737039005200341e8046a411f6a2225200341a8076a411f6a280000360000200341e8046a41186a2226200341a8076a41186a290300370300200341e8046a41106a2227200341a8076a41106a290300370300200341e8046a41086a2228200341a8076a41086a290300370300200341c0046a411f6a2229200341d0076a411f6a280000360000200341c0046a41186a222a200341d0076a41186a290300370300200341c0046a41106a222b200341d0076a41106a290300370300200341c0046a41086a222c200341d0076a41086a290300370300200320032903a8073703e804200320032903d0073703c00420034198046a411f6a222d200341f8076a411f6a28000036000020034198046a41186a222e200341f8076a41186a29030037030020034198046a41106a222f200341f8076a41106a29030037030020034198046a41086a2230200341f8076a41086a290300370300200320032903f80737039804200341f0036a411f6a2231200341a0086a411f6a280000360000200341f0036a41186a2232200341a0086a41186a290300370300200341f0036a41106a2233200341a0086a41106a290300370300200341f0036a41086a2234200341a0086a41086a290300370300200320032903a0083703f003200341c8036a411f6a2235200341c8086a411f6a280000360000200341c8036a41186a2236200341c8086a41186a290300370300200341c8036a41106a2237200341c8086a41106a290300370300200341c8036a41086a2238200341c8086a41086a290300370300200320032903c8083703c803200341a0036a411f6a2239200341f0086a411f6a280000360000200341a0036a41186a223a200341f0086a41186a290300370300200341a0036a41106a223b200341f0086a41106a290300370300200341a0036a41086a223c200341f0086a41086a290300370300200320032903f0083703a003200341f8026a411f6a223d20034198096a411f6a280000360000200341f8026a41186a223e20034198096a41186a290300370300200341f8026a41106a223f20034198096a41106a290300370300200341f8026a41086a224020034198096a41086a29030037030020032003290398093703f802200341d0026a411f6a2241200341c0096a411f6a280000360000200341d0026a41186a2242200341c0096a41186a290300370300200341d0026a41106a2243200341c0096a41106a290300370300200341d0026a41086a2244200341c0096a41086a290300370300200320032903c0093703d002200341a8026a411f6a2245200341e8096a411f6a280000360000200341a8026a41186a2246200341e8096a41186a290300370300200341a8026a41106a2247200341e8096a41106a290300370300200341a8026a41086a2248200341e8096a41086a290300370300200320032903e8093703a80220034180026a411f6a2249200341900a6a411f6a28000036000020034180026a41186a224a200341900a6a41186a29030037030020034180026a41106a224b200341900a6a41106a29030037030020034180026a41086a224c200341900a6a41086a290300370300200320032903900a37038002200341d8016a411f6a224d2003411f6a280000360000200341d8016a41186a224e200341186a290300370300200341d8016a41106a224f200341106a290300370300200341d8016a41086a2250200341086a290300370300200320032903003703d801200341b0016a411f6a2251200341b80a6a411f6a280000360000200341b0016a41186a2252200341b80a6a41186a290300370300200341b0016a41106a2253200341b80a6a41106a290300370300200341b0016a41086a2254200341b80a6a41086a290300370300200320032903b80a3703b00141002d00fca3c680001a41c00441002802c8a3c68000118180808000002202450d18200220083a0000200220032903980b370001200220053a0024200220032903e005370025200241096a200f290300370000200241116a200a290300370000200241196a200b290300370000200241206a20062800003600002002412d6a200e290300370000200241356a20132903003700002002413d6a2012290300370000200241c4006a20172800003600002002200c3a0048200220093a006c200220032903b805370049200241d1006a201f290300370000200241d9006a201a290300370000200241e1006a201b290300370000200241e8006a2016280000360000200220032903900537006d200241f5006a201e290300370000200241fd006a202329030037000020024185016a20222903003700002002418c016a2024280000360000200220103a0090012002200d3a00b401200220032903e8043700910120024199016a2028290300370000200241a1016a2027290300370000200241a9016a2026290300370000200241b0016a2025280000360000200220032903c0043700b501200241bd016a202c290300370000200241c5016a202b290300370000200241cd016a202a290300370000200241d4016a2029280000360000200220143a00d801200241f8016a202d280000360000200241f1016a202e290300370000200241e9016a202f290300370000200241e1016a203029030037000020022003290398043700d901200220113a00fc012002419c026a203128000036000020024195026a20322903003700002002418d026a203329030037000020024185026a2034290300370000200220032903f0033700fd01200220183a00a002200241c0026a2035280000360000200241b9026a2036290300370000200241b1026a2037290300370000200241a9026a2038290300370000200220032903c8033700a102200220153a00c402200241e4026a2039280000360000200241dd026a203a290300370000200241d5026a203b290300370000200241cd026a203c290300370000200220032903a0033700c5022002201c3a00e80220024188036a203d28000036000020024181036a203e290300370000200241f9026a203f290300370000200241f1026a2040290300370000200220032903f8023700e902200220193a008c03200241ac036a2041280000360000200241a5036a20422903003700002002419d036a204329030037000020024195036a2044290300370000200220032903d00237008d03200220203a00b003200241d0036a2045280000360000200241c9036a2046290300370000200241c1036a2047290300370000200241b9036a2048290300370000200220032903a8023700b1032002201d3a00d403200241f4036a2049280000360000200241ed036a204a290300370000200241e5036a204b290300370000200241dd036a204c29030037000020022003290380023700d503200220073a00f80320024198046a204d28000036000020024191046a204e29030037000020024189046a204f29030037000020024181046a2050290300370000200220032903d8013700f903200220213a009c04200241bc046a2051280000360000200241b5046a2052290300370000200241ad046a2053290300370000200241a5046a2054290300370000200220032903b00137009d04200341980b6a200141ec046a10fa8d80800020040d04410321010c050b200341a40b6a42013702002003410136029c0b200341fcd1c280003602980b200341e0818080003602bc0a200341c4d2c280003602b80a2003200341b80a6a3602a00b200341980b6a41ccd2c2800010f680808000000b200041043a00000c170b2001410c6a210402400240200141086a2802002205450d002004280200210420052005280200220141016a360200410021072001417f4c0d190c010b200341026a200441026a2d00003a0000200341980b6a41086a2001411f6a290000370300200341a50b6a200141246a290000370000200320042f00003b0100200320012900173703980b20012800132104200128000f2105410121070b200341900a6a41026a200341026a2d00003a0000200341b80a6a41086a200341980b6a41086a290300370300200341b80a6a41106a200341980b6a41106a290300370300200341b80a6a41186a200341980b6a41186a290300370300200320032f01003b01900a200320032903980b3703b80a0b200020073a000420002002360230200041073a0000200041056a20032f01900a3b00002000410c6a2004360200200041086a2005360200200041106a20032903b80a370000200041076a200341920a6a2d00003a0000200041186a200341b80a6a41086a290300370000200041206a200341b80a6a41106a290300370000200041286a200341b80a6a41186a2903003700000c150b200141086a21040240024020012802042205450d002004280200210420052005280200220841016a360200410021012008417f4c0d170c010b200341900a6a41026a200441026a2d00003a0000200341b80a6a41086a2001411b6a290000370300200341c50a6a200141206a290000370000200320042f00003b01900a200320012900133703b80a200128000f2104200128000b2105410121010b200341e8096a41026a200341900a6a41026a2d00003a0000200341086a200341b80a6a41086a290300370300200341106a200341b80a6a41106a290300370300200341186a200341b80a6a41186a290300370300200320032f01900a3b01e809200320032903b80a3703000b200020032902980b3702302000200236022c200020013a0000200020032f01e8093b0001200041d8006a200341c00b6a290200370200200041d0006a200341980b6a41206a290200370200200041c8006a200341980b6a41186a290200370200200041c0006a200341980b6a41106a290200370200200041386a200341980b6a41086a290200370200200041036a200341ea096a2d00003a000020002004360208200020053602042000200329030037000c200041146a200341086a2903003700002000411c6a200341106a290300370000200041246a200341186a2903003700000c130b2001200541d4d7c2800010f980808000000b2005200441d4d7c2800010f980808000000b2004200841d4d7c2800010f980808000000b2008200941d4d7c2800010f980808000000b2009200c41d4d7c2800010f980808000000b200c200d41d4d7c2800010f980808000000b200d201041d4d7c2800010f980808000000b2010201141d4d7c2800010f980808000000b2011201441d4d7c2800010f980808000000b2014201541d4d7c2800010f980808000000b2015201841d4d7c2800010f980808000000b2018201941d4d7c2800010f980808000000b2019201c41d4d7c2800010f980808000000b201c201d41d4d7c2800010f980808000000b201d202041d4d7c2800010f980808000000b2020202141d4d7c2800010f980808000000b2021202241d4d7c2800010f980808000000b410441c00410b280808000000b410441c00410b280808000000b200341800c6a2480808080000f0b00000bb50301037f23808080800041d0016b220324808080800002400240024020012d00000d0020002001290001370001200041196a200141196a290000370000200041116a200141116a290000370000200041096a200141096a290000370000410121020c010b2003410c6a2001280204200210f085808000200341f0006a2003410c6a41e00010848e8080001a02400240200241186a2802002201450d0020022001417f6a360218200241146a22012001280200220141016a22044100200228020c220520042005491b6b360200200241106a28020020014102746a2802002201200228020822044f0d03200228020420014107746a220241046a200220022d00004108461b10e385808000200241083a0000200241016a200341ed006a41e30010848e8080001a0c010b0240200228020822012002280200470d0020022001109e86808000200228020821010b200228020420014107746a220141083a0000200141016a200341ed006a41e30010848e8080001a20022002280208220141016a3602080b20002001360204410021020b200020023a0000200341d0016a2480808080000f0b2001200441d4d7c2800010f980808000000bb09e0101617f23808080800041800c6b2203248080808000024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024020012802002204417e6a2205410420054106491b0e06050001020304050b200341980b6a200141046a10fa8d808000200141386a21050240024020012802342202450d002005280200210520022002280200220441016a360200410021012004417f4a0d010c1f0b200341026a200541026a2d00003a0000200341c00a6a200141cb006a290000370300200341c50a6a200141d0006a290000370000200320052f00003b0100200320012900433703b80a200128003f2105200128003b2102410121010b200020032902980b370230200020013a0004200041056a20032f01003b0000200041d8006a200341980b6a41286a290200370200200041d0006a200341980b6a41206a290200370200200041c8006a200341980b6a41186a290200370200200041c0006a200341980b6a41106a290200370200200041386a200341980b6a41086a290200370200200041076a200341026a2d00003a00002000410c6a2005360200200041086a2002360200200041053a0000200041106a20032903b80a370200200041186a200341b80a6a41086a290300370200200041206a200341b80a6a41106a290300370200200041286a200341b80a6a41186a2903003702000c1c0b2003200141286a10fa8d8080000240024020012d00040d00200341ba0a6a200141076a2d00003a0000200341980b6a41086a200141146a290200370300200341a80b6a2001411c6a290200370300200341b00b6a200141246a2d00003a00002003200141056a2f00003b01b80a20032001410c6a2902003703980b200141086a2802002101410121020c010b200341b80a6a200141086a280200200210f2858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002201450d0020022001417f6a360218200241146a22012001280200220141016a22054100200228020c220420052004491b6b360200200241106a28020020014102746a2802002201200228020822054f0d0b200228020420014107746a220241046a200220022d00004108461b10e385808000200241083a0000200241016a200341980b6a41e30010848e8080001a0c010b0240200228020822012002280200470d0020022001109e86808000200228020821010b200228020420014107746a220141083a0000200141016a200341980b6a41e30010848e8080001a20022002280208220141016a3602080b410021020b20002003290200370228200020023a0004200041056a20032f01b80a3b0000200041086a2001360200200041d0006a200341286a290200370200200041c8006a200341206a290200370200200041c0006a200341186a290200370200200041386a200341106a290200370200200041306a200341086a290200370200200041076a200341ba0a6a2d00003a0000200041063a0000200041246a200341980b6a41186a2802003602002000411c6a200341980b6a41106a290300370200200041146a200341980b6a41086a2903003702002000410c6a20032903980b3702000c1b0b4102210641022107024020012d003022044102460d000240024020040d00200341026a200141336a2d00003a0000200341a00b6a200141c0006a290200370300200341a80b6a200141c8006a290200370300200341b00b6a200141d0006a2d00003a00002003200141316a2f00003b01002003200141386a2902003703980b200141346a2802002105410121070c010b200341b80a6a200141346a280200200210f2858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002205450d0020022005417f6a360218200241146a22052005280200220541016a22044100200228020c220820042008491b6b360200200241106a28020020054102746a2802002205200228020822044f0d0c200228020420054107746a220441046a200420042d00004108461b10e385808000200441083a0000200441016a200341980b6a41e30010848e8080001a0c010b0240200228020822052002280200470d0020022005109e86808000200228020821050b200228020420054107746a220541083a0000200541016a200341980b6a41e30010848e8080001a20022002280208220541016a3602080b410021070b200341f0006a41026a200341026a2d00003a0000200341e0056a41086a200341980b6a41086a290300370300200341e0056a41106a200341980b6a41106a290300370300200341e0056a41186a200341980b6a41186a280200360200200320032f01003b0170200320032903980b3703e0050b0240200141d4006a2d000022084102460d000240024020080d00200341026a200141d7006a2d00003a0000200341a00b6a200141e4006a290200370300200341a80b6a200141ec006a290200370300200341b00b6a200141f4006a2d00003a00002003200141d5006a2f00003b01002003200141dc006a2902003703980b200141d8006a2802002104410121060c010b200341b80a6a200141d8006a280200200210f2858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002204450d0020022004417f6a360218200241146a22042004280200220441016a22084100200228020c220920082009491b6b360200200241106a28020020044102746a2802002204200228020822084f0d0d200228020420044107746a220841046a200820082d00004108461b10e385808000200841083a0000200841016a200341980b6a41e30010848e8080001a0c010b0240200228020822042002280200470d0020022004109e86808000200228020821040b200228020420044107746a220441083a0000200441016a200341980b6a41e30010848e8080001a20022002280208220441016a3602080b410021060b200341f4006a41026a200341026a2d00003a000020034188066a41086a200341980b6a41086a29030037030020034188066a41106a200341980b6a41106a29030037030020034188066a41186a200341980b6a41186a280200360200200320032f01003b0174200320032903980b370388060b4102210a4102210b0240200141f8006a2d000022094102460d000240024020090d00200341026a200141fb006a2d00003a0000200341a00b6a20014188016a290200370300200341a80b6a20014190016a290200370300200341b00b6a20014198016a2d00003a00002003200141f9006a2f00003b0100200320014180016a2902003703980b200141fc006a28020021084101210b0c010b200341b80a6a200141fc006a280200200210f2858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002208450d0020022008417f6a360218200241146a22082008280200220841016a22094100200228020c220c2009200c491b6b360200200241106a28020020084102746a2802002208200228020822094f0d0e200228020420084107746a220941046a200920092d00004108461b10e385808000200941083a0000200941016a200341980b6a41e30010848e8080001a0c010b0240200228020822082002280200470d0020022008109e86808000200228020821080b200228020420084107746a220841083a0000200841016a200341980b6a41e30010848e8080001a20022002280208220841016a3602080b4100210b0b200341f8006a41026a200341026a2d00003a0000200341b0066a41086a200341980b6a41086a290300370300200341b0066a41106a200341980b6a41106a290300370300200341b0066a41186a200341980b6a41186a280200360200200320032f01003b0178200320032903980b3703b0060b02402001419c016a2d0000220c4102460d0002400240200c0d00200341026a2001419f016a2d00003a0000200341a00b6a200141ac016a290200370300200341a80b6a200141b4016a290200370300200341b00b6a200141bc016a2d00003a000020032001419d016a2f00003b01002003200141a4016a2902003703980b200141a0016a28020021094101210a0c010b200341b80a6a200141a0016a280200200210f2858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002209450d0020022009417f6a360218200241146a22092009280200220941016a220c4100200228020c220d200c200d491b6b360200200241106a28020020094102746a28020022092002280208220c4f0d0f200228020420094107746a220c41046a200c200c2d00004108461b10e385808000200c41083a0000200c41016a200341980b6a41e30010848e8080001a0c010b0240200228020822092002280200470d0020022009109e86808000200228020821090b200228020420094107746a220941083a0000200941016a200341980b6a41e30010848e8080001a20022002280208220941016a3602080b4100210a0b200341fc006a41026a200341026a2d00003a0000200341d8066a41086a200341980b6a41086a290300370300200341d8066a41106a200341980b6a41106a290300370300200341d8066a41186a200341980b6a41186a280200360200200320032f01003b017c200320032903980b3703d8060b4102210e4102210f0240200141c0016a2d0000220d4102460d0002400240200d0d00200341026a200141c3016a2d00003a0000200341a00b6a200141d0016a290200370300200341a80b6a200141d8016a290200370300200341b00b6a200141e0016a2d00003a00002003200141c1016a2f00003b01002003200141c8016a2902003703980b200141c4016a280200210c4101210f0c010b200341b80a6a200141c4016a280200200210f2858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a280200220c450d002002200c417f6a360218200241146a220c200c280200220c41016a220d4100200228020c2210200d2010491b6b360200200241106a280200200c4102746a280200220c2002280208220d4f0d102002280204200c4107746a220d41046a200d200d2d00004108461b10e385808000200d41083a0000200d41016a200341980b6a41e30010848e8080001a0c010b02402002280208220c2002280200470d002002200c109e868080002002280208210c0b2002280204200c4107746a220c41083a0000200c41016a200341980b6a41e30010848e8080001a20022002280208220c41016a3602080b4100210f0b20034180016a41026a200341026a2d00003a000020034180076a41086a200341980b6a41086a29030037030020034180076a41106a200341980b6a41106a29030037030020034180076a41186a200341980b6a41186a280200360200200320032f01003b018001200320032903980b370380070b0240200141e4016a2d000022104102460d000240024020100d00200341026a200141e7016a2d00003a0000200341a00b6a200141f4016a290200370300200341a80b6a200141fc016a290200370300200341b00b6a20014184026a2d00003a00002003200141e5016a2f00003b01002003200141ec016a2902003703980b200141e8016a280200210d4101210e0c010b200341b80a6a200141e8016a280200200210f2858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a280200220d450d002002200d417f6a360218200241146a220d200d280200220d41016a22104100200228020c221120102011491b6b360200200241106a280200200d4102746a280200220d200228020822104f0d112002280204200d4107746a221041046a201020102d00004108461b10e385808000201041083a0000201041016a200341980b6a41e30010848e8080001a0c010b02402002280208220d2002280200470d002002200d109e868080002002280208210d0b2002280204200d4107746a220d41083a0000200d41016a200341980b6a41e30010848e8080001a20022002280208220d41016a3602080b4100210e0b20034184016a41026a200341026a2d00003a0000200341a8076a41086a200341980b6a41086a290300370300200341a8076a41106a200341980b6a41106a290300370300200341a8076a41186a200341980b6a41186a280200360200200320032f01003b018401200320032903980b3703a8070b4102211241022113024020014188026a2d000022114102460d000240024020110d00200341026a2001418b026a2d00003a0000200341a00b6a20014198026a290200370300200341a80b6a200141a0026a290200370300200341b00b6a200141a8026a2d00003a0000200320014189026a2f00003b0100200320014190026a2902003703980b2001418c026a2802002110410121130c010b200341b80a6a2001418c026a280200200210f2858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002210450d0020022010417f6a360218200241146a22102010280200221041016a22114100200228020c221420112014491b6b360200200241106a28020020104102746a2802002210200228020822114f0d12200228020420104107746a221141046a201120112d00004108461b10e385808000201141083a0000201141016a200341980b6a41e30010848e8080001a0c010b0240200228020822102002280200470d0020022010109e86808000200228020821100b200228020420104107746a221041083a0000201041016a200341980b6a41e30010848e8080001a20022002280208221041016a3602080b410021130b20034188016a41026a200341026a2d00003a0000200341d0076a41086a200341980b6a41086a290300370300200341d0076a41106a200341980b6a41106a290300370300200341d0076a41186a200341980b6a41186a280200360200200320032f01003b018801200320032903980b3703d0070b0240200141ac026a2d000022144102460d000240024020140d00200341026a200141af026a2d00003a0000200341a00b6a200141bc026a290200370300200341a80b6a200141c4026a290200370300200341b00b6a200141cc026a2d00003a00002003200141ad026a2f00003b01002003200141b4026a2902003703980b200141b0026a2802002111410121120c010b200341b80a6a200141b0026a280200200210f2858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002211450d0020022011417f6a360218200241146a22112011280200221141016a22144100200228020c221520142015491b6b360200200241106a28020020114102746a2802002211200228020822144f0d13200228020420114107746a221441046a201420142d00004108461b10e385808000201441083a0000201441016a200341980b6a41e30010848e8080001a0c010b0240200228020822112002280200470d0020022011109e86808000200228020821110b200228020420114107746a221141083a0000201141016a200341980b6a41e30010848e8080001a20022002280208221141016a3602080b410021120b2003418c016a41026a200341026a2d00003a0000200341f8076a41086a200341980b6a41086a290300370300200341f8076a41106a200341980b6a41106a290300370300200341f8076a41186a200341980b6a41186a280200360200200320032f01003b018c01200320032903980b3703f8070b41022116410221170240200141d0026a2d000022154102460d000240024020150d00200341026a200141d3026a2d00003a0000200341a00b6a200141e0026a290200370300200341a80b6a200141e8026a290200370300200341b00b6a200141f0026a2d00003a00002003200141d1026a2f00003b01002003200141d8026a2902003703980b200141d4026a2802002114410121170c010b200341b80a6a200141d4026a280200200210f2858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002214450d0020022014417f6a360218200241146a22142014280200221441016a22154100200228020c221820152018491b6b360200200241106a28020020144102746a2802002214200228020822154f0d14200228020420144107746a221541046a201520152d00004108461b10e385808000201541083a0000201541016a200341980b6a41e30010848e8080001a0c010b0240200228020822142002280200470d0020022014109e86808000200228020821140b200228020420144107746a221441083a0000201441016a200341980b6a41e30010848e8080001a20022002280208221441016a3602080b410021170b20034190016a41026a200341026a2d00003a0000200341a0086a41086a200341980b6a41086a290300370300200341a0086a41106a200341980b6a41106a290300370300200341a0086a41186a200341980b6a41186a280200360200200320032f01003b019001200320032903980b3703a0080b0240200141f4026a2d000022184102460d000240024020180d00200341026a200141f7026a2d00003a0000200341a00b6a20014184036a290200370300200341a80b6a2001418c036a290200370300200341b00b6a20014194036a2d00003a00002003200141f5026a2f00003b01002003200141fc026a2902003703980b200141f8026a2802002115410121160c010b200341b80a6a200141f8026a280200200210f2858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002215450d0020022015417f6a360218200241146a22152015280200221541016a22184100200228020c221920182019491b6b360200200241106a28020020154102746a2802002215200228020822184f0d15200228020420154107746a221841046a201820182d00004108461b10e385808000201841083a0000201841016a200341980b6a41e30010848e8080001a0c010b0240200228020822152002280200470d0020022015109e86808000200228020821150b200228020420154107746a221541083a0000201541016a200341980b6a41e30010848e8080001a20022002280208221541016a3602080b410021160b20034194016a41026a200341026a2d00003a0000200341c8086a41086a200341980b6a41086a290300370300200341c8086a41106a200341980b6a41106a290300370300200341c8086a41186a200341980b6a41186a280200360200200320032f01003b019401200320032903980b3703c8080b4102211a4102211b024020014198036a2d000022194102460d000240024020190d00200341026a2001419b036a2d00003a0000200341a00b6a200141a8036a290200370300200341a80b6a200141b0036a290200370300200341b00b6a200141b8036a2d00003a0000200320014199036a2f00003b01002003200141a0036a2902003703980b2001419c036a28020021184101211b0c010b200341b80a6a2001419c036a280200200210f2858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002218450d0020022018417f6a360218200241146a22182018280200221841016a22194100200228020c221c2019201c491b6b360200200241106a28020020184102746a2802002218200228020822194f0d16200228020420184107746a221941046a201920192d00004108461b10e385808000201941083a0000201941016a200341980b6a41e30010848e8080001a0c010b0240200228020822182002280200470d0020022018109e86808000200228020821180b200228020420184107746a221841083a0000201841016a200341980b6a41e30010848e8080001a20022002280208221841016a3602080b4100211b0b20034198016a41026a200341026a2d00003a0000200341f0086a41086a200341980b6a41086a290300370300200341f0086a41106a200341980b6a41106a290300370300200341f0086a41186a200341980b6a41186a280200360200200320032f01003b019801200320032903980b3703f0080b0240200141bc036a2d0000221c4102460d0002400240201c0d00200341026a200141bf036a2d00003a0000200341a00b6a200141cc036a290200370300200341a80b6a200141d4036a290200370300200341b00b6a200141dc036a2d00003a00002003200141bd036a2f00003b01002003200141c4036a2902003703980b200141c0036a28020021194101211a0c010b200341b80a6a200141c0036a280200200210f2858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002219450d0020022019417f6a360218200241146a22192019280200221941016a221c4100200228020c221d201c201d491b6b360200200241106a28020020194102746a28020022192002280208221c4f0d17200228020420194107746a221c41046a201c201c2d00004108461b10e385808000201c41083a0000201c41016a200341980b6a41e30010848e8080001a0c010b0240200228020822192002280200470d0020022019109e86808000200228020821190b200228020420194107746a221941083a0000201941016a200341980b6a41e30010848e8080001a20022002280208221941016a3602080b4100211a0b2003419c016a41026a200341026a2d00003a000020034198096a41086a200341980b6a41086a29030037030020034198096a41106a200341980b6a41106a29030037030020034198096a41186a200341980b6a41186a280200360200200320032f01003b019c01200320032903980b370398090b4102211e4102211f0240200141e0036a2d0000221d4102460d0002400240201d0d00200341026a200141e3036a2d00003a0000200341a00b6a200141f0036a290200370300200341a80b6a200141f8036a290200370300200341b00b6a20014180046a2d00003a00002003200141e1036a2f00003b01002003200141e8036a2902003703980b200141e4036a280200211c4101211f0c010b200341b80a6a200141e4036a280200200210f2858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a280200221c450d002002201c417f6a360218200241146a221c201c280200221c41016a221d4100200228020c2220201d2020491b6b360200200241106a280200201c4102746a280200221c2002280208221d4f0d182002280204201c4107746a221d41046a201d201d2d00004108461b10e385808000201d41083a0000201d41016a200341980b6a41e30010848e8080001a0c010b02402002280208221c2002280200470d002002201c109e868080002002280208211c0b2002280204201c4107746a221c41083a0000201c41016a200341980b6a41e30010848e8080001a20022002280208221c41016a3602080b4100211f0b200341a0016a41026a200341026a2d00003a0000200341c0096a41086a200341980b6a41086a290300370300200341c0096a41106a200341980b6a41106a290300370300200341c0096a41186a200341980b6a41186a280200360200200320032f01003b01a001200320032903980b3703c0090b024020014184046a2d000022204102460d000240024020200d00200341026a20014187046a2d00003a0000200341a00b6a20014194046a290200370300200341a80b6a2001419c046a290200370300200341b00b6a200141a4046a2d00003a0000200320014185046a2f00003b010020032001418c046a2902003703980b20014188046a280200211d4101211e0c010b200341b80a6a20014188046a280200200210f2858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a280200221d450d002002201d417f6a360218200241146a221d201d280200221d41016a22204100200228020c222120202021491b6b360200200241106a280200201d4102746a280200221d200228020822204f0d192002280204201d4107746a222041046a202020202d00004108461b10e385808000202041083a0000202041016a200341980b6a41e30010848e8080001a0c010b02402002280208221d2002280200470d002002201d109e868080002002280208211d0b2002280204201d4107746a221d41083a0000201d41016a200341980b6a41e30010848e8080001a20022002280208221d41016a3602080b4100211e0b200341a4016a41026a200341026a2d00003a0000200341e8096a41086a200341980b6a41086a290300370300200341e8096a41106a200341980b6a41106a290300370300200341e8096a41186a200341980b6a41186a280200360200200320032f01003b01a401200320032903980b3703e8090b41022122410221230240200141a8046a2d000022214102460d000240024020210d00200341026a200141ab046a2d00003a0000200341a00b6a200141b8046a290200370300200341a80b6a200141c0046a290200370300200341b00b6a200141c8046a2d00003a00002003200141a9046a2f00003b01002003200141b0046a2902003703980b200141ac046a2802002120410121230c010b200341b80a6a200141ac046a280200200210f2858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002220450d0020022020417f6a360218200241146a22202020280200222041016a22214100200228020c222320212023491b6b360200200241106a28020020204102746a2802002220200228020822214f0d1a200228020420204107746a222141046a202120212d00004108461b10e385808000202141083a0000202141016a200341980b6a41e30010848e8080001a0c010b0240200228020822202002280200470d0020022020109e86808000200228020821200b200228020420204107746a222041083a0000202041016a200341980b6a41e30010848e8080001a20022002280208222041016a3602080b410021230b200341a8016a41026a200341026a2d00003a0000200341900a6a41086a200341980b6a41086a290300370300200341900a6a41106a200341980b6a41106a290300370300200341900a6a41186a200341980b6a41186a280200360200200320032f01003b01a801200320032903980b3703900a0b0240200141cc046a2d000022244102460d000240024020240d00200341ba056a200141cf046a2d00003a0000200341a00b6a200141dc046a290200370300200341a80b6a200141e4046a290200370300200341b00b6a200141ec046a2d00003a00002003200141cd046a2f00003b01b8052003200141d4046a2902003703980b200141d0046a2802002121410121220c010b200341b80a6a200141d0046a280200200210f2858080002003419b0b6a200341b80a6a41e00010848e8080001a02400240200241186a2802002221450d0020022021417f6a360218200241146a22212021280200222141016a22224100200228020c222420222024491b6b360200200241106a28020020214102746a2802002221200228020822224f0d1b200228020420214107746a220241046a200220022d00004108461b10e385808000200241083a0000200241016a200341980b6a41e30010848e8080001a0c010b0240200228020822212002280200470d0020022021109e86808000200228020821210b200228020420214107746a222141083a0000202141016a200341980b6a41e30010848e8080001a20022002280208222141016a3602080b410021220b200341ac016a41026a200341b8056a41026a2d00003a0000200341086a200341980b6a41086a290300370300200341106a200341980b6a41106a290300370300200341186a200341980b6a41186a280200360200200320032f01b8053b01ac01200320032903980b3703000b200341ec006a41026a2224200341f0006a41026a2d00003a0000200341980b6a41086a2225200341e0056a41086a290300370300200341980b6a41106a2226200341e0056a41106a290300370300200341980b6a41186a2227200341e0056a41186a280200360200200341e8006a41026a2228200341f4006a41026a2d00003a0000200341b80a6a41186a222920034188066a41186a280200360200200341b80a6a41106a222a20034188066a41106a290300370300200341b80a6a41086a222b20034188066a41086a290300370300200320032f01703b016c200320032903e0053703980b200320032f01743b016820032003290388063703b80a200341e4006a41026a222c200341f8006a41026a2d00003a0000200341b8056a41086a222d200341b0066a41086a290300370300200341b8056a41106a222e200341b0066a41106a290300370300200341b8056a41186a222f200341b0066a41186a280200360200200341e0006a41026a2230200341fc006a41026a2d00003a000020034190056a41086a2231200341d8066a41086a29030037030020034190056a41106a2232200341d8066a41106a29030037030020034190056a41186a2233200341d8066a41186a280200360200200320032f01783b0164200320032903b0063703b805200320032f017c3b0160200320032903d80637039005200341dc006a41026a223420034180016a41026a2d00003a0000200341e8046a41186a223520034180076a41186a280200360200200341e8046a41106a223620034180076a41106a290300370300200341e8046a41086a223720034180076a41086a290300370300200341d8006a41026a223820034184016a41026a2d00003a0000200341c0046a41186a2239200341a8076a41186a280200360200200341c0046a41106a223a200341a8076a41106a290300370300200341c0046a41086a223b200341a8076a41086a290300370300200320032f0180013b015c20032003290380073703e804200320032f0184013b0158200320032903a8073703c004200341d4006a41026a223c20034188016a41026a2d00003a0000200320032f0188013b015420034198046a41186a223d200341d0076a41186a28020036020020034198046a41106a223e200341d0076a41106a29030037030020034198046a41086a223f200341d0076a41086a290300370300200320032903d00737039804200341d0006a41026a22402003418c016a41026a2d00003a0000200320032f018c013b0150200341f0036a41186a2241200341f8076a41186a280200360200200341f0036a41106a2242200341f8076a41106a290300370300200341f0036a41086a2243200341f8076a41086a290300370300200320032903f8073703f003200341cc006a41026a224420034190016a41026a2d00003a0000200320032f0190013b014c200341c8036a41186a2245200341a0086a41186a280200360200200341c8036a41106a2246200341a0086a41106a290300370300200341c8036a41086a2247200341a0086a41086a290300370300200320032903a0083703c803200341c8006a41026a224820034194016a41026a2d00003a0000200320032f0194013b0148200341a0036a41186a2249200341c8086a41186a280200360200200341a0036a41106a224a200341c8086a41106a290300370300200341a0036a41086a224b200341c8086a41086a290300370300200320032903c8083703a003200341c4006a41026a224c20034198016a41026a2d00003a0000200320032f0198013b0144200341f8026a41186a224d200341f0086a41186a280200360200200341f8026a41106a224e200341f0086a41106a290300370300200341f8026a41086a224f200341f0086a41086a290300370300200320032903f0083703f802200341c0006a41026a22502003419c016a41026a2d00003a0000200320032f019c013b0140200341d0026a41186a225120034198096a41186a280200360200200341d0026a41106a225220034198096a41106a290300370300200341d0026a41086a225320034198096a41086a29030037030020032003290398093703d0022003413c6a41026a2254200341a0016a41026a2d00003a0000200320032f01a0013b013c200341a8026a41186a2255200341c0096a41186a280200360200200341a8026a41106a2256200341c0096a41106a290300370300200341a8026a41086a2257200341c0096a41086a290300370300200320032903c0093703a802200341386a41026a2258200341a4016a41026a2d00003a0000200320032f01a4013b013820034180026a41186a2259200341e8096a41186a28020036020020034180026a41106a225a200341e8096a41106a29030037030020034180026a41086a225b200341e8096a41086a290300370300200320032903e80937038002200341346a41026a225c200341a8016a41026a2d00003a0000200320032f01a8013b0134200341d8016a41186a225d200341900a6a41186a280200360200200341d8016a41106a225e200341900a6a41106a290300370300200341d8016a41086a225f200341900a6a41086a290300370300200320032903900a3703d801200341306a41026a2260200341ac016a41026a2d00003a0000200320032f01ac013b0130200341b0016a41186a2261200341186a280200360200200341b0016a41106a2262200341106a290300370300200341b0016a41086a2263200341086a290300370300200320032903003703b00141002d00fca3c680001a41c00441002802c8a3c68000118180808000002202450d18200220073a0000200220032f016c3b000120022005360204200220032903980b370008200220063a0024200220032f01683b002541032107200241036a20242d00003a0000200241106a2025290300370000200241186a2026290300370000200241206a2027280200360000200241276a20282d00003a0000200220043602282002200b3a00482002200836024c200220032903b80a37002c200241346a202b2903003700002002413c6a202a290300370000200241c4006a2029280200360000200220032f01643b0049200241cb006a202c2d00003a0000200220032903b805370050200241d8006a202d290300370000200241e0006a202e290300370000200241e8006a202f2802003600002002200a3a006c200220093602702002200f3a009001200220032f01603b006d200241ef006a20302d00003a00002002418c016a203328020036000020024184016a2032290300370000200241fc006a20312903003700002002200329039005370074200220032f015c3b00910120024193016a20342d00003a00002002200c36029401200241b0016a2035280200360000200241a8016a2036290300370000200241a0016a2037290300370000200220032903e804370098012002200e3a00b401200241b7016a20382d00003a0000200220032f01583b00b5012002200d3602b801200241d4016a2039280200360000200241cc016a203a290300370000200241c4016a203b290300370000200220032903c0043700bc01200220133a00d801200241db016a203c2d00003a0000200220032f01543b00d901200220103602dc01200241f8016a203d280200360000200241f0016a203e290300370000200241e8016a203f29030037000020022003290398043700e001200220123a00fc01200241ff016a20402d00003a0000200220032f01503b00fd0120022011360280022002419c026a204128020036000020024194026a20422903003700002002418c026a2043290300370000200220032903f00337008402200220173a00a002200241a3026a20442d00003a0000200220032f014c3b00a102200220143602a402200241c0026a2045280200360000200241b8026a2046290300370000200241b0026a2047290300370000200220032903c8033700a802200220163a00c402200241c7026a20482d00003a0000200220032f01483b00c502200220153602c802200241e4026a2049280200360000200241dc026a204a290300370000200241d4026a204b290300370000200220032903a0033700cc022002201b3a00e802200241eb026a204c2d00003a0000200220032f01443b00e902200220183602ec0220024188036a204d28020036000020024180036a204e290300370000200241f8026a204f290300370000200220032903f8023700f0022002201a3a008c032002418f036a20502d00003a0000200220032f01403b008d032002201936029003200241ac036a2051280200360000200241a4036a20522903003700002002419c036a2053290300370000200220032903d002370094032002201f3a00b003200241b3036a20542d00003a0000200220032f013c3b00b1032002201c3602b403200241d0036a2055280200360000200241c8036a2056290300370000200241c0036a2057290300370000200220032903a8023700b8032002201e3a00d403200241d7036a20582d00003a0000200220032f01383b00d5032002201d3602d803200241f4036a2059280200360000200241ec036a205a290300370000200241e4036a205b29030037000020022003290380023700dc03200220233a00f803200241fb036a205c2d00003a0000200220032f01343b00f903200220203602fc0320024198046a205d28020036000020024190046a205e29030037000020024188046a205f290300370000200220032903d80137008004200220223a009c042002419f046a20602d00003a0000200220032f01303b009d04200220213602a004200241bc046a2061280200360000200241b4046a2062290300370000200241ac046a2063290300370000200220032903b0013700a40420012802040d030c040b4102210541022108024020012d002c4102460d00200341980b6a2001412c6a200210f38580800020034190066a200341a10b6a29000037030020034198066a200341a90b6a290000370300200341a0066a200341b10b6a290000370300200341a7066a200341b80b6a280000360000200320032900990b3703880620032d00980b21080b0240200141d0006a22092d00004102460d00200341980b6a2009200210f385808000200341b8066a200341a10b6a290000370300200341c0066a200341a90b6a290000370300200341c8066a200341b10b6a290000370300200341cf066a200341b80b6a280000360000200320032900990b3703b00620032d00980b21050b410221094102210c0240200141f4006a220d2d00004102460d00200341980b6a200d200210f385808000200341e0066a200341a10b6a290000370300200341e8066a200341a90b6a290000370300200341f0066a200341b10b6a290000370300200341f7066a200341b80b6a280000360000200320032900990b3703d80620032d00980b210c0b024020014198016a220d2d00004102460d00200341980b6a200d200210f38580800020034188076a200341a10b6a29000037030020034190076a200341a90b6a29000037030020034198076a200341b10b6a2900003703002003419f076a200341b80b6a280000360000200320032900990b3703800720032d00980b21090b4102210d410221100240200141bc016a22112d00004102460d00200341980b6a2011200210f385808000200341b0076a200341a10b6a290000370300200341b8076a200341a90b6a290000370300200341c0076a200341b10b6a290000370300200341c7076a200341b80b6a280000360000200320032900990b3703a80720032d00980b21100b0240200141e0016a22112d00004102460d00200341980b6a2011200210f385808000200341d8076a200341a10b6a290000370300200341e0076a200341a90b6a290000370300200341e8076a200341b10b6a290000370300200341ef076a200341b80b6a280000360000200320032900990b3703d00720032d00980b210d0b4102211141022114024020014184026a22152d00004102460d00200341980b6a2015200210f38580800020034180086a200341a10b6a29000037030020034188086a200341a90b6a29000037030020034190086a200341b10b6a29000037030020034197086a200341b80b6a280000360000200320032900990b3703f80720032d00980b21140b0240200141a8026a22152d00004102460d00200341980b6a2015200210f385808000200341a8086a200341a10b6a290000370300200341b0086a200341a90b6a290000370300200341b8086a200341b10b6a290000370300200341bf086a200341b80b6a280000360000200320032900990b3703a00820032d00980b21110b41022115410221180240200141cc026a22192d00004102460d00200341980b6a2019200210f385808000200341d0086a200341a10b6a290000370300200341d8086a200341a90b6a290000370300200341e0086a200341b10b6a290000370300200341e7086a200341b80b6a280000360000200320032900990b3703c80820032d00980b21180b0240200141f0026a22192d00004102460d00200341980b6a2019200210f385808000200341f8086a200341a10b6a29000037030020034180096a200341a90b6a29000037030020034188096a200341b10b6a2900003703002003418f096a200341b80b6a280000360000200320032900990b3703f00820032d00980b21150b410221194102211c024020014194036a221d2d00004102460d00200341980b6a201d200210f385808000200341a0096a200341a10b6a290000370300200341a8096a200341a90b6a290000370300200341b0096a200341b10b6a290000370300200341b7096a200341b80b6a280000360000200320032900990b3703980920032d00980b211c0b0240200141b8036a221d2d00004102460d00200341980b6a201d200210f385808000200341c8096a200341a10b6a290000370300200341d0096a200341a90b6a290000370300200341d8096a200341b10b6a290000370300200341df096a200341b80b6a280000360000200320032900990b3703c00920032d00980b21190b4102211d410221200240200141dc036a22212d00004102460d00200341980b6a2021200210f385808000200341f0096a200341a10b6a290000370300200341f8096a200341a90b6a290000370300200341800a6a200341b10b6a290000370300200341870a6a200341b80b6a280000360000200320032900990b3703e80920032d00980b21200b024020014180046a22212d00004102460d00200341980b6a2021200210f385808000200341980a6a200341a10b6a290000370300200341a00a6a200341a90b6a290000370300200341a80a6a200341b10b6a290000370300200341af0a6a200341b80b6a280000360000200320032900990b3703900a20032d00980b211d0b41022121410221070240200141a4046a22062d00004102460d00200341980b6a2006200210f385808000200341086a200341a10b6a290000370300200341106a200341a90b6a290000370300200341186a200341b10b6a2900003703002003411f6a200341b80b6a280000360000200320032900990b37030020032d00980b21070b0240200141c8046a22062d00004102460d00200341980b6a2006200210f385808000200341c00a6a200341a10b6a290000370300200341c80a6a200341a90b6a290000370300200341d00a6a200341b10b6a290000370300200341d70a6a200341b80b6a280000360000200320032900990b3703b80a20032d00980b21210b200341980b6a411f6a220620034188066a411f6a280000360000200341980b6a41186a220b20034188066a41186a290300370300200341980b6a41106a220a20034188066a41106a290300370300200341980b6a41086a220f20034188066a41086a290300370300200341e0056a41086a220e200341b0066a41086a290300370300200341e0056a41106a2213200341b0066a41106a290300370300200341e0056a41186a2212200341b0066a41186a290300370300200341e0056a411f6a2217200341b0066a411f6a28000036000020032003290388063703980b200320032903b0063703e005200341b8056a411f6a2216200341d8066a411f6a280000360000200341b8056a41186a221b200341d8066a41186a290300370300200341b8056a41106a221a200341d8066a41106a290300370300200341b8056a41086a221f200341d8066a41086a29030037030020034190056a41086a221e20034180076a41086a29030037030020034190056a41106a222320034180076a41106a29030037030020034190056a41186a222220034180076a41186a29030037030020034190056a411f6a222420034180076a411f6a280000360000200320032903d8063703b805200320032903800737039005200341e8046a411f6a2225200341a8076a411f6a280000360000200341e8046a41186a2226200341a8076a41186a290300370300200341e8046a41106a2227200341a8076a41106a290300370300200341e8046a41086a2228200341a8076a41086a290300370300200341c0046a411f6a2229200341d0076a411f6a280000360000200341c0046a41186a222a200341d0076a41186a290300370300200341c0046a41106a222b200341d0076a41106a290300370300200341c0046a41086a222c200341d0076a41086a290300370300200320032903a8073703e804200320032903d0073703c00420034198046a411f6a222d200341f8076a411f6a28000036000020034198046a41186a222e200341f8076a41186a29030037030020034198046a41106a222f200341f8076a41106a29030037030020034198046a41086a2230200341f8076a41086a290300370300200320032903f80737039804200341f0036a411f6a2231200341a0086a411f6a280000360000200341f0036a41186a2232200341a0086a41186a290300370300200341f0036a41106a2233200341a0086a41106a290300370300200341f0036a41086a2234200341a0086a41086a290300370300200320032903a0083703f003200341c8036a411f6a2235200341c8086a411f6a280000360000200341c8036a41186a2236200341c8086a41186a290300370300200341c8036a41106a2237200341c8086a41106a290300370300200341c8036a41086a2238200341c8086a41086a290300370300200320032903c8083703c803200341a0036a411f6a2239200341f0086a411f6a280000360000200341a0036a41186a223a200341f0086a41186a290300370300200341a0036a41106a223b200341f0086a41106a290300370300200341a0036a41086a223c200341f0086a41086a290300370300200320032903f0083703a003200341f8026a411f6a223d20034198096a411f6a280000360000200341f8026a41186a223e20034198096a41186a290300370300200341f8026a41106a223f20034198096a41106a290300370300200341f8026a41086a224020034198096a41086a29030037030020032003290398093703f802200341d0026a411f6a2241200341c0096a411f6a280000360000200341d0026a41186a2242200341c0096a41186a290300370300200341d0026a41106a2243200341c0096a41106a290300370300200341d0026a41086a2244200341c0096a41086a290300370300200320032903c0093703d002200341a8026a411f6a2245200341e8096a411f6a280000360000200341a8026a41186a2246200341e8096a41186a290300370300200341a8026a41106a2247200341e8096a41106a290300370300200341a8026a41086a2248200341e8096a41086a290300370300200320032903e8093703a80220034180026a411f6a2249200341900a6a411f6a28000036000020034180026a41186a224a200341900a6a41186a29030037030020034180026a41106a224b200341900a6a41106a29030037030020034180026a41086a224c200341900a6a41086a290300370300200320032903900a37038002200341d8016a411f6a224d2003411f6a280000360000200341d8016a41186a224e200341186a290300370300200341d8016a41106a224f200341106a290300370300200341d8016a41086a2250200341086a290300370300200320032903003703d801200341b0016a411f6a2251200341b80a6a411f6a280000360000200341b0016a41186a2252200341b80a6a41186a290300370300200341b0016a41106a2253200341b80a6a41106a290300370300200341b0016a41086a2254200341b80a6a41086a290300370300200320032903b80a3703b00141002d00fca3c680001a41c00441002802c8a3c68000118180808000002202450d18200220083a0000200220032903980b370001200220053a0024200220032903e005370025200241096a200f290300370000200241116a200a290300370000200241196a200b290300370000200241206a20062800003600002002412d6a200e290300370000200241356a20132903003700002002413d6a2012290300370000200241c4006a20172800003600002002200c3a0048200220093a006c200220032903b805370049200241d1006a201f290300370000200241d9006a201a290300370000200241e1006a201b290300370000200241e8006a2016280000360000200220032903900537006d200241f5006a201e290300370000200241fd006a202329030037000020024185016a20222903003700002002418c016a2024280000360000200220103a0090012002200d3a00b401200220032903e8043700910120024199016a2028290300370000200241a1016a2027290300370000200241a9016a2026290300370000200241b0016a2025280000360000200220032903c0043700b501200241bd016a202c290300370000200241c5016a202b290300370000200241cd016a202a290300370000200241d4016a2029280000360000200220143a00d801200241f8016a202d280000360000200241f1016a202e290300370000200241e9016a202f290300370000200241e1016a203029030037000020022003290398043700d901200220113a00fc012002419c026a203128000036000020024195026a20322903003700002002418d026a203329030037000020024185026a2034290300370000200220032903f0033700fd01200220183a00a002200241c0026a2035280000360000200241b9026a2036290300370000200241b1026a2037290300370000200241a9026a2038290300370000200220032903c8033700a102200220153a00c402200241e4026a2039280000360000200241dd026a203a290300370000200241d5026a203b290300370000200241cd026a203c290300370000200220032903a0033700c5022002201c3a00e80220024188036a203d28000036000020024181036a203e290300370000200241f9026a203f290300370000200241f1026a2040290300370000200220032903f8023700e902200220193a008c03200241ac036a2041280000360000200241a5036a20422903003700002002419d036a204329030037000020024195036a2044290300370000200220032903d00237008d03200220203a00b003200241d0036a2045280000360000200241c9036a2046290300370000200241c1036a2047290300370000200241b9036a2048290300370000200220032903a8023700b1032002201d3a00d403200241f4036a2049280000360000200241ed036a204a290300370000200241e5036a204b290300370000200241dd036a204c29030037000020022003290380023700d503200220073a00f80320024198046a204d28000036000020024191046a204e29030037000020024189046a204f29030037000020024181046a2050290300370000200220032903d8013700f903200220213a009c04200241bc046a2051280000360000200241b5046a2052290300370000200241ad046a2053290300370000200241a5046a2054290300370000200220032903b00137009d04200341980b6a200141ec046a10fa8d80800020040d04410321010c050b200341a40b6a42013702002003410136029c0b200341fcd1c280003602980b200341e0818080003602bc0a200341c4d2c280003602b80a2003200341b80a6a3602a00b200341980b6a41ccd2c2800010f680808000000b200041043a00000c170b2001410c6a210402400240200141086a2802002205450d002004280200210420052005280200220141016a360200410021072001417f4c0d190c010b200341026a200441026a2d00003a0000200341980b6a41086a2001411f6a290000370300200341a50b6a200141246a290000370000200320042f00003b0100200320012900173703980b20012800132104200128000f2105410121070b200341900a6a41026a200341026a2d00003a0000200341b80a6a41086a200341980b6a41086a290300370300200341b80a6a41106a200341980b6a41106a290300370300200341b80a6a41186a200341980b6a41186a290300370300200320032f01003b01900a200320032903980b3703b80a0b200020073a000420002002360230200041073a0000200041056a20032f01900a3b00002000410c6a2004360200200041086a2005360200200041106a20032903b80a370000200041076a200341920a6a2d00003a0000200041186a200341b80a6a41086a290300370000200041206a200341b80a6a41106a290300370000200041286a200341b80a6a41186a2903003700000c150b200141086a21040240024020012802042205450d002004280200210420052005280200220841016a360200410021012008417f4c0d170c010b200341900a6a41026a200441026a2d00003a0000200341b80a6a41086a2001411b6a290000370300200341c50a6a200141206a290000370000200320042f00003b01900a200320012900133703b80a200128000f2104200128000b2105410121010b200341e8096a41026a200341900a6a41026a2d00003a0000200341086a200341b80a6a41086a290300370300200341106a200341b80a6a41106a290300370300200341186a200341b80a6a41186a290300370300200320032f01900a3b01e809200320032903b80a3703000b200020032902980b3702302000200236022c200020013a0000200020032f01e8093b0001200041d8006a200341c00b6a290200370200200041d0006a200341980b6a41206a290200370200200041c8006a200341980b6a41186a290200370200200041c0006a200341980b6a41106a290200370200200041386a200341980b6a41086a290200370200200041036a200341ea096a2d00003a000020002004360208200020053602042000200329030037000c200041146a200341086a2903003700002000411c6a200341106a290300370000200041246a200341186a2903003700000c130b2001200541d4d7c2800010f980808000000b2005200441d4d7c2800010f980808000000b2004200841d4d7c2800010f980808000000b2008200941d4d7c2800010f980808000000b2009200c41d4d7c2800010f980808000000b200c200d41d4d7c2800010f980808000000b200d201041d4d7c2800010f980808000000b2010201141d4d7c2800010f980808000000b2011201441d4d7c2800010f980808000000b2014201541d4d7c2800010f980808000000b2015201841d4d7c2800010f980808000000b2018201941d4d7c2800010f980808000000b2019201c41d4d7c2800010f980808000000b201c201d41d4d7c2800010f980808000000b201d202041d4d7c2800010f980808000000b2020202141d4d7c2800010f980808000000b2021202241d4d7c2800010f980808000000b410441c00410b280808000000b410441c00410b280808000000b200341800c6a2480808080000f0b00000bb50301037f23808080800041d0016b220324808080800002400240024020012d00000d0020002001290001370001200041196a200141196a290000370000200041116a200141116a290000370000200041096a200141096a290000370000410121020c010b2003410c6a2001280204200210f285808000200341f0006a2003410c6a41e00010848e8080001a02400240200241186a2802002201450d0020022001417f6a360218200241146a22012001280200220141016a22044100200228020c220520042005491b6b360200200241106a28020020014102746a2802002201200228020822044f0d03200228020420014107746a220241046a200220022d00004108461b10e385808000200241083a0000200241016a200341ed006a41e30010848e8080001a0c010b0240200228020822012002280200470d0020022001109e86808000200228020821010b200228020420014107746a220141083a0000200141016a200341ed006a41e30010848e8080001a20022002280208220141016a3602080b20002001360204410021020b200020023a0000200341d0016a2480808080000f0b2001200441d4d7c2800010f980808000000bb60301017f2380808080004180016b22042480808080000240024002400240024020012d00000e03010200020b200441003a005420042002360250200441023a002c2004200141286a2802003602342004200128022441086a360230200441046a20032004412c6a20024100200410da8580800020042d00040d03200441f0006a22022004411d6a290000370300200441e8006a2203200441156a290000370300200441d8006a41086a2004410d6a29000037030020042004290005370358024020012d00010d00200141013a0001200141026a20042903583700002001411a6a2002290300370000200141126a20032903003700002001410a6a200441e0006a2903003700000b200141026a210241202101410121030c020b200128020441086a2102200141086a2802002101410021030c010b41012103200141016a2102412021010b20002001360208200020023602042000200336020020044180016a2480808080000f0b200441386a420137020020044101360230200441fcd1c2800036022c200441e08180800036027c20044180d3c280003602782004200441f8006a3602342004412c6a4188d3c2800010f680808000000bb80301017f2380808080004180016b22052480808080000240024002400240024020012d00000e03010200020b200541003a005420052002360250200541023a002c2005200141286a2802003602342005200128022441086a360230200541046a200320042005412c6a20024100200510db8580800020052d00040d03200541f0006a22022005411d6a290000370300200541e8006a2204200541156a290000370300200541d8006a41086a2005410d6a29000037030020052005290005370358024020012d00010d00200141013a0001200141026a20052903583700002001411a6a2002290300370000200141126a20042903003700002001410a6a200541e0006a2903003700000b200141026a210241202101410121040c020b200128020441086a2102200141086a2802002101410021040c010b41012104200141016a2102412021010b20002001360208200020023602042000200436020020054180016a2480808080000f0b200541386a420137020020054101360230200541fcd1c2800036022c200541e08180800036027c20054180d3c280003602782005200541f8006a3602342005412c6a4188d3c2800010f680808000000bb80301017f2380808080004180016b22052480808080000240024002400240024020012d00000e03010200020b200541003a005420052002360250200541023a002c2005200141286a2802003602342005200128022441086a360230200541046a200320042005412c6a20024100200510d98580800020052d00040d03200541f0006a22022005411d6a290000370300200541e8006a2204200541156a290000370300200541d8006a41086a2005410d6a29000037030020052005290005370358024020012d00010d00200141013a0001200141026a20052903583700002001411a6a2002290300370000200141126a20042903003700002001410a6a200541e0006a2903003700000b200141026a210241202101410121040c020b200128020441086a2102200141086a2802002101410021040c010b41012104200141016a2102412021010b20002001360208200020023602042000200436020020054180016a2480808080000f0b200541386a420137020020054101360230200541fcd1c2800036022c200541e08180800036027c20054180d3c280003602782005200541f8006a3602342005412c6a4188d3c2800010f680808000000bb60301017f2380808080004180016b22042480808080000240024002400240024020012d00000e03010200020b200441003a005420042002360250200441023a002c2004200141286a2802003602342004200128022441086a360230200441046a20032004412c6a20024100200410dc8580800020042d00040d03200441f0006a22022004411d6a290000370300200441e8006a2203200441156a290000370300200441d8006a41086a2004410d6a29000037030020042004290005370358024020012d00010d00200141013a0001200141026a20042903583700002001411a6a2002290300370000200141126a20032903003700002001410a6a200441e0006a2903003700000b200141026a210241202101410121030c020b200128020441086a2102200141086a2802002101410021030c010b41012103200141016a2102412021010b20002001360208200020023602042000200336020020044180016a2480808080000f0b200441386a420137020020044101360230200441fcd1c2800036022c200441e08180800036027c20044180d3c280003602782004200441f8006a3602342004412c6a4188d3c2800010f680808000000be31303057f047e077f23808080800041d0016b220524808080800020052003360218200520023602140240024002400240200028026822060d00410021000c010b200041ec006a280200220728021421002005200541146a360258200541086a20062001200541d8006a4198d3c28000200011878080800000200528020c210802402005280208450d000240024002400240200828020041fcffffff076a2200410320004105491b0e0403030102000b2008280204450d02200841086a28020041002802c0a3c68000118080808000000c020b2008280204450d01200841086a28020041002802c0a3c68000118080808000000c010b200810de858080000b200841002802c0a3c68000118080808000002004280200450d030c020b20054280808080c00037021c20054100360224024020042802002209450d00200541286a41286a2004412c6a290200370300200541286a41206a200441246a290200370300200541286a41186a2004411c6a290200370300200541286a41106a200441146a290200370300200541286a41086a2004410c6a29020037030020052004290204370328024002400240024002400240024020082802002203417e6a2200410420004106491b0e06060206000103060b2008280204450d05200841086a2203280200450d05200841106a21000c040b2003450d042008280204450d04200841046a21032008410c6a21000c030b20082802340d010c030b2008410c6a2100200841046a21030c010b200841346a21032008413c6a21000b20054190016a41186a200041186a290000220a37030020054190016a41106a200041106a290000220b37030020054190016a41086a200041086a290000220c37030020052000290000220d37039001200541d8006a41186a200a370300200541d8006a41106a200b370300200541d8006a41086a200c3703002005200d370358200528022821014101210002400240024002400240200528022c20052802502202200241284b22021b220e450d00200e417f4c0d0141002d00fca3c680001a200e41002802c8a3c68000118180808000002200450d020b20002001200541286a20021b200e10848e808000210f200341046a2802002101200328020022022002280200220041016a3602002000417f4c0d022005200136029401200520023602900103402002280204210003402000417f460d012000417f4c0d052002200041016a2002280204220320032000461b360204200320004721012003210020010d000b0b2005280294012103200528029001220020002802002200417f6a360200024020004101470d0020054190016a10f18d8080000b024020052802242200200528021c470d002005411c6a2000109f86808000200528022421000b2005280220200041386c6a220041023a000c2000200e3602082000200f3602042000200e3602002000200529035837000d2000200336023420002002360230200041156a200541e0006a2903003700002000411d6a200541e8006a290300370000200041256a200541f0006a2903003700002005200528022441016a3602240c040b10ae80808000000b4101200e10b280808000000b00000b10f08d808000000b20052802282103200528022c2102200528025021004100211020054190016a41286a2201410036020020054190016a2003200541286a200041284b220e1b2203200320022000200e1b6a10f686808000200541d8006a41286a2001280200360200200541d8006a41206a20054190016a41206a290200370300200541d8006a41186a20054190016a41186a290200370300200541d8006a41106a20054190016a41106a290200370300200541d8006a41086a20054190016a41086a290200370300200520052902900137035820052005280254360284012008280200210320052005411c6a3602c00141002111024002400240024002402003417e6a2203410420034106491b0e06040403000104040b200841306a21120c010b2008412c6a21120b41022111410021000c010b200841046a2100410121110b2012415c6a21132005200541c0016a3602c8012005200541d8006a3602c40103400240024002400240024020110e03010200010b20004110200041104b1b210e2012200041246c22026a2103201320026a2102200041087441807e6a21010340200e2000460d03200241246a210220014180026a2101200041016a210020032d00002108200341246a210320084102460d000b20014180fe0371410172210f200221140c030b200f41807e71410272210f0c020b200f41807e71210f0240201041ff01710d0041012110200021140c020b200f410272210f0c010b200f41807e71410272210f200e21000b0240200f41ff01714102460d0020142d0000450d01201428020421032005200541c4016a3602cc01200fad220a42ff01834202510d0120052003ad422086200a42ffff03838437039001200541cc016a20054190016a10bc8c8080000c010b0b02402005280280014129490d00200528025841002802c0a3c68000118080808000000b024020052802504129490d00200528022841002802c0a3c68000118080808000000b2005280220220f2005280224220341386c6a2108200528021c2114200f2100024002402003450d00200541d8006a41086a210320054188016a210e200f21000240034020002802002202418080808078460d01200028020421012000290204210a200e200041346a280200360200200541d8006a41286a2000412c6a290200370300200541d8006a41206a200041246a290200370300200541d8006a41186a2000411c6a290200370300200541d8006a41106a200041146a29020037030020032000410c6a29020037030020052000290204370358200541286a41286a200341286a280200360200200541286a41206a200341206a290200370300200541286a41186a200341186a290200370300200541286a41106a200341106a290200370300200541286a41086a200341086a290200370300200520032902003703282006200aa7200a422088a7200541286a20072802101186808080000002402002450d00200141002802c0a3c68000118080808000000b200041386a22002008470d000c030b0b200041386a21000b200820006b41386e210320082000460d00034002402000280200450d00200041046a28020041002802c0a3c68000118080808000000b02402000410c6a2d00004102490d00200041306a2802002202417f460d00200220022802042201417f6a36020420014101470d00200041346a280200410b6a4104490d00200241002802c0a3c68000118080808000000b200041386a21002003417f6a22030d000b0b2014450d00200f41002802c0a3c68000118080808000000b200941004721000b20000d012004280200450d010b2004412c6a2802004129490d00200428020441002802c0a3c68000118080808000000b200541d0016a2480808080000be31303057f047e077f23808080800041d0016b220524808080800020052003360218200520023602140240024002400240200028026822060d00410021000c010b200041ec006a280200220728021421002005200541146a360258200541086a20062001200541d8006a41acd3c28000200011878080800000200528020c210802402005280208450d000240024002400240200828020041fcffffff076a2200410320004105491b0e0403030102000b2008280204450d02200841086a28020041002802c0a3c68000118080808000000c020b2008280204450d01200841086a28020041002802c0a3c68000118080808000000c010b200810de858080000b200841002802c0a3c68000118080808000002004280200450d030c020b20054280808080c00037021c20054100360224024020042802002209450d00200541286a41286a2004412c6a290200370300200541286a41206a200441246a290200370300200541286a41186a2004411c6a290200370300200541286a41106a200441146a290200370300200541286a41086a2004410c6a29020037030020052004290204370328024002400240024002400240024020082802002203417e6a2200410420004106491b0e06060206000103060b2008280204450d05200841086a2203280200450d05200841106a21000c040b2003450d042008280204450d04200841046a21032008410c6a21000c030b20082802340d010c030b2008410c6a2100200841046a21030c010b200841346a21032008413c6a21000b20054190016a41186a200041186a290000220a37030020054190016a41106a200041106a290000220b37030020054190016a41086a200041086a290000220c37030020052000290000220d37039001200541d8006a41186a200a370300200541d8006a41106a200b370300200541d8006a41086a200c3703002005200d370358200528022821014101210002400240024002400240200528022c20052802502202200241284b22021b220e450d00200e417f4c0d0141002d00fca3c680001a200e41002802c8a3c68000118180808000002200450d020b20002001200541286a20021b200e10848e808000210f200341046a2802002101200328020022022002280200220041016a3602002000417f4c0d022005200136029401200520023602900103402002280204210003402000417f460d012000417f4c0d052002200041016a2002280204220320032000461b360204200320004721012003210020010d000b0b2005280294012103200528029001220020002802002200417f6a360200024020004101470d0020054190016a10f18d8080000b024020052802242200200528021c470d002005411c6a2000109f86808000200528022421000b2005280220200041386c6a220041023a000c2000200e3602082000200f3602042000200e3602002000200529035837000d2000200336023420002002360230200041156a200541e0006a2903003700002000411d6a200541e8006a290300370000200041256a200541f0006a2903003700002005200528022441016a3602240c040b10ae80808000000b4101200e10b280808000000b00000b10f08d808000000b20052802282103200528022c2102200528025021004100211020054190016a41286a2201410036020020054190016a2003200541286a200041284b220e1b2203200320022000200e1b6a10f686808000200541d8006a41286a2001280200360200200541d8006a41206a20054190016a41206a290200370300200541d8006a41186a20054190016a41186a290200370300200541d8006a41106a20054190016a41106a290200370300200541d8006a41086a20054190016a41086a290200370300200520052902900137035820052005280254360284012008280200210320052005411c6a3602c00141002111024002400240024002402003417e6a2203410420034106491b0e06040403000104040b200841306a21120c010b2008412c6a21120b41022111410021000c010b200841046a2100410121110b2012415c6a21132005200541c0016a3602c8012005200541d8006a3602c40103400240024002400240024020110e03010200010b20004110200041104b1b210e2012200041246c22026a2103201320026a2102200041087441807e6a21010340200e2000460d03200241246a210220014180026a2101200041016a210020032d00002108200341246a210320084102460d000b20014180fe0371410172210f200221140c030b200f41807e71410272210f0c020b200f41807e71210f0240201041ff01710d0041012110200021140c020b200f410272210f0c010b200f41807e71410272210f200e21000b0240200f41ff01714102460d0020142d0000450d01201428020421032005200541c4016a3602cc01200fad220a42ff01834202510d0120052003ad422086200a42ffff03838437039001200541cc016a20054190016a10bd8c8080000c010b0b02402005280280014129490d00200528025841002802c0a3c68000118080808000000b024020052802504129490d00200528022841002802c0a3c68000118080808000000b2005280220220f2005280224220341386c6a2108200528021c2114200f2100024002402003450d00200541d8006a41086a210320054188016a210e200f21000240034020002802002202418080808078460d01200028020421012000290204210a200e200041346a280200360200200541d8006a41286a2000412c6a290200370300200541d8006a41206a200041246a290200370300200541d8006a41186a2000411c6a290200370300200541d8006a41106a200041146a29020037030020032000410c6a29020037030020052000290204370358200541286a41286a200341286a280200360200200541286a41206a200341206a290200370300200541286a41186a200341186a290200370300200541286a41106a200341106a290200370300200541286a41086a200341086a290200370300200520032902003703282006200aa7200a422088a7200541286a20072802101186808080000002402002450d00200141002802c0a3c68000118080808000000b200041386a22002008470d000c030b0b200041386a21000b200820006b41386e210320082000460d00034002402000280200450d00200041046a28020041002802c0a3c68000118080808000000b02402000410c6a2d00004102490d00200041306a2802002202417f460d00200220022802042201417f6a36020420014101470d00200041346a280200410b6a4104490d00200241002802c0a3c68000118080808000000b200041386a21002003417f6a22030d000b0b2014450d00200f41002802c0a3c68000118080808000000b200941004721000b20000d012004280200450d010b2004412c6a2802004129490d00200428020441002802c0a3c68000118080808000000b200541d0016a2480808080000ba00301047f23808080800041f0086b2202248080808000200241e8016a2001280200220128020022032001280204220110c28c8080000240024002400240024020022802e80122044105470d002002410c6a410c6a200241e8016a410c6a290200370200200220022902ec013702102002410536020c0c010b200241e0086a41086a2205200241e8016a410c6a290200370300200220022902ec013703e00820024184076a41146a200241e8016a41146a41c80110848e8080001a20024184076a410c6a20052903003702002002200436028407200220022903e008370288072002410c6a20024184076a2003200110f48d808000200228020c22014105470d010b200241106a10de858080000c010b20024184076a41046a2002410c6a41046a41d80110848e8080001a2002200136028407200241e8016a20024184076a10b78a80800020022802e80122014108470d0120022802ec0110df858080000b41c0d3c2800041c2004184d4c2800010a181808000000b200041046a200241e8016a41046a41980510848e8080001a20002001360200200241f0086a2480808080000ba00301047f23808080800041f0086b2202248080808000200241e8016a2001280200220128020022032001280204220110c28c8080000240024002400240024020022802e80122044105470d002002410c6a410c6a200241e8016a410c6a290200370200200220022902ec013702102002410536020c0c010b200241e0086a41086a2205200241e8016a410c6a290200370300200220022902ec013703e00820024184076a41146a200241e8016a41146a41c80110848e8080001a20024184076a410c6a20052903003702002002200436028407200220022903e008370288072002410c6a20024184076a2003200110f48d808000200228020c22014105470d010b200241106a10de858080000c010b20024184076a41046a2002410c6a41046a41d80110848e8080001a2002200136028407200241e8016a20024184076a10b68a80800020022802e80122014108470d0120022802ec0110df858080000b41c0d3c2800041c2004184d4c2800010a181808000000b200041046a200241e8016a41046a41980510848e8080001a20002001360200200241f0086a2480808080000b9a0801047f23808080800041f0006b220624808080800002400240024020002802682207450d0002400240024020044100480d00200441f5ffffff074f0d0102402004410b6a417c7122080d00410421090c030b41002d00fca3c680001a200841002802c8a3c680001181808080000022090d024104200810b280808000000b41fc9bc68000412b200641186a41a89cc6800041b89cc68000108981808000000b41e484c08000412b200641186a419085c08000419086c08000108981808000000b2009428180808010370200200941086a2003200410848e8080001a2006200436021420062009360210200041ec006a2802002103200641186a41186a200541186a290000370300200641186a41106a200541106a290000370300200641186a41086a200541086a290000370300200620052900003703182006200536026c200328021421042006200641106a360268200641086a2007200641186a200641e8006a4194d4c28000200411878080800000200628020c220428020021000240024002400240024020062802080d00024002402000417e6a2209410420094106491b0e06060006030104060b20042802342200450d05200441346a21090c040b2000450d0420042802042200450d04200441046a21090c030b0240024002400240200041fcffffff076a2205410320054105491b0e0403030102000b2004280204450d02200441086a28020041002802c0a3c68000118080808000000c020b2004280204450d01200441086a28020041002802c0a3c68000118080808000000c010b200410de858080000b200441002802c0a3c68000118080808000000c030b2004280204450d02200441086a220928020022000d010c020b200441046a2109200428020421000b200941046a280200210920002000280200220441016a3602002004417f4c0d02200641c8006a41086a200541086a290000370300200641c8006a41106a200541106a290000370300200641c8006a41186a200541186a290000370300200620052900003703482006200936026c2006200036026803402000280204210503402005417f460d012005417f4c0d052000200541016a2000280204220420042005461b360204200420054721092004210520090d000b0b200628026c21052006280268220420042802002204417f6a360200024020044101470d00200641e8006a10f18d8080000b200641c0006a2005360200200641216a200641d0006a290300370000200641296a200641d8006a290300370000200641316a200641e0006a290300370000200620062903483700192006200036023c200641023a0018200720012002200641186a2003280210118680808000000b2006280210220520052802002205417f6a36020020054101470d00200641106a10e28a8080000b200641f0006a2480808080000f0b00000b10f08d808000000b9a0801047f23808080800041f0006b220624808080800002400240024020002802682207450d0002400240024020044100480d00200441f5ffffff074f0d0102402004410b6a417c7122080d00410421090c030b41002d00fca3c680001a200841002802c8a3c680001181808080000022090d024104200810b280808000000b41fc9bc68000412b200641186a41a89cc6800041b89cc68000108981808000000b41e484c08000412b200641186a419085c08000419086c08000108981808000000b2009428180808010370200200941086a2003200410848e8080001a2006200436021420062009360210200041ec006a2802002103200641186a41186a200541186a290000370300200641186a41106a200541106a290000370300200641186a41086a200541086a290000370300200620052900003703182006200536026c200328021421042006200641106a360268200641086a2007200641186a200641e8006a4194d4c28000200411878080800000200628020c220428020021000240024002400240024020062802080d00024002402000417e6a2209410420094106491b0e06060006030104060b20042802342200450d05200441346a21090c040b2000450d0420042802042200450d04200441046a21090c030b0240024002400240200041fcffffff076a2205410320054105491b0e0403030102000b2004280204450d02200441086a28020041002802c0a3c68000118080808000000c020b2004280204450d01200441086a28020041002802c0a3c68000118080808000000c010b200410de858080000b200441002802c0a3c68000118080808000000c030b2004280204450d02200441086a220928020022000d010c020b200441046a2109200428020421000b200941046a280200210920002000280200220441016a3602002004417f4c0d02200641c8006a41086a200541086a290000370300200641c8006a41106a200541106a290000370300200641c8006a41186a200541186a290000370300200620052900003703482006200936026c2006200036026803402000280204210503402005417f460d012005417f4c0d052000200541016a2000280204220420042005461b360204200420054721092004210520090d000b0b200628026c21052006280268220420042802002204417f6a360200024020044101470d00200641e8006a10f18d8080000b200641c0006a2005360200200641216a200641d0006a290300370000200641296a200641d8006a290300370000200641316a200641e0006a290300370000200620062903483700192006200036023c200641023a0018200720012002200641186a2003280210118680808000000b2006280210220520052802002205417f6a36020020054101470d00200641106a10e28a8080000b200641f0006a2480808080000f0b00000b10f08d808000000b870101037f2001280200220241046a2802002103200228020022022002280200220441016a36020002402004417f4a0d0000000b20002003360208200020023602042000410736020020002001280204220129000037000c200041146a200141086a2900003700002000411c6a200141106a290000370000200041246a200141186a2900003700000bc32103097f017e027f23808080800041b0046b22042480808080002004200336021420042001360210024002400240024002400240024002400240024020022d00000d00200228020421020240200141286a28020022052001411c6a22062802002203470d00200610a889808000200128021c2103200128022821050b200141206a280200200141246a28020020056a22054100200320052003491b6b4102746a20023602002001200128022841016a360228200141186a280200220320024d0d02200441186a200141146a28020020024107746a220141800110848e8080001a200141043a0004200141083a00000240024020042d00184108470d0020044198016a200441186a41046a41e00010848e8080001a02400240200428021028026822070d00410021080c010b2004280214220128020021032001280204210520012802282102200441d8036a41286a22064100360200200441d8036a20032001200241284b22091b220320032005200220091b6a10f686808000200441f0026a41286a2006280200360200200441f0026a41206a200441d8036a41206a290200370300200441f0026a41186a200441d8036a41186a290200370300200441f0026a41106a200441d8036a41106a290200370300200441f0026a41086a200441d8036a41086a290200370300200420042902d8033703f0022004200128022c220a36029c030240024002400240024020042d009801417c6a41ff01712201410420014104491b0e050400010402040b200441c8016a21010c020b20044198016a41286a21010c010b200441c8016a21010b200141086a2802002001412c6a2802002202200241284b22031b21022001280204200141046a20031b21052001280200220341017621010240024020034101710d00410021060240200120024b0d0020012103410021010c020b2001200241d492c68000109481808000000b200120024f0d0841012106200141016a2103200520016a2d0000410f7121010b200441e0036a200220036b360200200420013a00d903200420063a00d8032004200520036a3602dc03200441f0026a200441d8036a10e28d808000200428029c03210a0b200441f8016a41086a200441fc026a290200370300200441f8016a41106a20044184036a290200370300200441f8016a41186a2004418c036a290200370300200441f8016a41206a20044194036a280200360200200420042902f4023703f80120042802f002210b2004280298032106410121080b200441a8026a41086a20044198016a41096a290000370300200441a8026a41106a20044198016a41116a290000370300200441a8026a41186a20044198016a41196a290000370300200441a8026a411f6a20044198016a41206a29000037000020042004290099013703a80220042d009801210320042802c001210c20042802c401210520042802c80121022004200441106a3602ac032004200441146a3602a803200441cc016a210102400240024002400240024002400240024002402003417c6a41ff01712209410420094104491b0e050001020304000b41002d00fca3c680001a410141002802c8a3c68000118180808000002201450d0f200141003a0000200441013602a402200420013602a0022004410136029c020c080b200441fc026a200141086a29020037020020044184036a200141106a2902003702002004418c036a200141186a290200370200200441f0026a41246a200141206a2902003702002004419c036a2203200141286a280200360200200420023602f002200420012902003702f402200441d8036a41206a200441cb026a280000360200200441d8036a41186a200441c3026a290000370300200441d8036a41106a200441bb026a290000370300200441d8036a41086a200441b3026a290000370300200420042900ab023703d80320042005360280042004200c3602fc03200420023602ac04200420042802f80220032802002201200141284b22011b3602a804200420042802f402200441f0026a41046a20011b3602a40420044194046a200441d8036a200441a4046a200441a8036a10f78580800020042802ac042203410176210220042802a804210120042802a40421090240024020034101710d004100210c0240200220014b0d0020022105410021020c020b2002200141d492c68000109481808000000b200220014f0d104101210c200241016a2105200920026a2d0000410f7121020b200420023a00bd032004200c3a00bc03200441003602b8032004200120056b3602b4032004200920056a3602b0032004419c026a200441b0036a200141017420036b20044194046a10d08c808000024002400240024020042d00d8030e020103000b20042802fc03220120012802002201417f6a36020020014101470d02200441d8036a41246a21010c010b20042802dc03220120012802002201417f6a36020020014101470d01200441d8036a41047221010b200110e28a8080000b200428029c034129490d0720042802f40241002802c0a3c68000118080808000000c070b20044184036a200141086a2902003702002004418c036a200141106a29020037020020044194036a200141186a2902003702002004419c036a200141206a280200360200200420023602f802200420053602f4022004200c3602f002200420012902003702fc02200441d8036a41206a200441cb026a280000360200200441d8036a41186a200441c3026a290000370300200441d8036a41106a200441bb026a290000370300200441d8036a41086a200441b3026a290000370300200420042900ab023703d803200441086a200441f0026a41046a41c0d1c280001096878080002004200c3602ac04200420042903083702a40420044194046a200441a4046a10dc8d808000200441003a0080042004200441a4046a3602fc03200441b0036a200441a8036a200441d8036a200441a4046a4100200410dc858080002004419c026a20044194046a20042802a80441017420042802ac046b200441b0036a10cb8c808000000b200441f0026a41206a200441cb026a280000360200200441f0026a41186a200441c3026a290000370300200441f0026a41106a200441bb026a290000370300200441f0026a41086a200441b3026a290000370300200420042900ab02220d3703f00220042005360298032004200c36029403200da741ff01714103470d01410221000c020b200441fc026a200141086a29020037020020044184036a200141106a2902003702002004418c036a200141186a29020037020020044194036a200141206a2902003702002004419c036a2209200141286a280200360200200420023602f002200420012902003702f402200441d8036a41096a20044198016a410172220141086a290000370000200441d8036a41116a200141106a290000370000200441d8036a41196a200141186a290000370000200441d8036a41206a2001411f6a2900003700002004200c36028004200420012900003700d903200420033a00d8032004200236029004200420042802f80220092802002201200141284b22091b220136028c04200420042802f402200441f0026a41046a20091b220936028804200341ff01714103470d024102210e0c030b200441d8036a200441f0026a4100200441a8036a10f78580800020042902dc03210d20042802d80321000b2004200d3702b403200420003602b0032004419c026a200441d8036a200441b0036a10ca8c808000000b200441b0036a200441d8036a20044188046a200441a8036a10f78580800020042902b403210d20042802b003210e200428028c042101200428028804210920042802900421020b200241017621030240024020024101710d004100210f0240200320014b0d002003210c410021030c020b2003200141d492c68000109481808000000b200320014f0d0a4101210f200341016a210c200920036a2d0000410f7121030b200420033a00a1042004200f3a00a0042004410036029c0420042001200c6b3602980420042009200c6a36029404200441c0036a200441a8036a360200200441003602b803200420053602b0032004200541c0046a3602b4032004200441f0026a3602bc032004200d3702a8042004200e3602a4042004419c026a20044194046a200141017420026b200441b0036a200441a4046a10ce8c808000024020042d00d80322014103460d0002400240024020010e020103000b20042802fc03220120012802002201417f6a36020020014101470d02200441fc036a21010c010b20042802dc03220120012802002201417f6a36020020014101470d01200441dc036a21010b200110e28a8080000b200541002802c0a3c6800011808080800000200428029c034129490d0020042802f40241002802c0a3c68000118080808000000b0240024020042802a4022201411f4b0d0020042802a0022102200441f0026a20016a4100412020016b108a8e8080001a200441f0026a2002200110848e8080001a20002001360204200041206a200441f0026a41186a290000370000200041186a200441f0026a41106a290000370000200041106a200441f8026a290000370000200020042900f002370008410121030c010b2004280210220241d4006a28020021092002280250210c2004280214220228022c220541017621030240024020054101710d00200228020420022802282205200541284b22051b220e2003490d0c2002280200200220051b2102410021050c010b200228020420022802282205200541284b1b220e2003490d0c200e20034d0d0d200441f9026a20022802002002200541284b1b220220036a2d000041f001713a0000410121050b200420053a00f802200420033602f402200420023602f002200441d0026a200c200441f0026a20042802a00222022001200928021c1187808080000020042802102103200441f0026a41106a200441f8016a41086a290300370200200441f0026a41186a200441f8016a41106a290300370200200441f0026a41206a200441f8016a41186a29030037020020044198036a200441f8016a41206a2802003602002004200b3602f402200420083602f002200420042903f8013702f8022004200a3602a0032004200636029c03200441d8036a41186a200441d0026a41186a2205290000370300200441d8036a41106a200441d0026a41106a2209290000370300200441d8036a41086a200441d0026a41086a220a290000370300200420042900d0023703d8032003200441d8036a20022001200441f0026a10f985808000200041196a2005290000370000200041116a2009290000370000200041096a200a290000370000200020042900d002370001410021030b200020033a00000240200428029c02450d00200241002802c0a3c68000118080808000000b02402007450d002001411f4b0d0020064129490d00200b41002802c0a3c68000118080808000000b20042d00184108470d010c030b20002004290278370001200041003a0000200041196a20044190016a290200370000200041116a20044188016a290200370000200041096a20044180016a2902003700000b200441186a10e3858080000c010b200041003a000020002002290001370001200041196a200241196a290000370000200041116a200241116a290000370000200041096a200241096a2900003700000b200441b0046a2480808080000f0b2002200341e4d7c2800010f980808000000b2001200241e492c6800010f980808000000b4101410110b280808000000b2002200141e492c6800010f980808000000b2003200141e492c6800010f980808000000b2003200e41ac95c68000109581808000000b2003200e41bc95c68000109581808000000b2003200e41cc95c6800010f980808000000bc32103097f017e027f23808080800041b0046b22042480808080002004200336021420042001360210024002400240024002400240024002400240024020022d00000d00200228020421020240200141286a28020022052001411c6a22062802002203470d00200610a889808000200128021c2103200128022821050b200141206a280200200141246a28020020056a22054100200320052003491b6b4102746a20023602002001200128022841016a360228200141186a280200220320024d0d02200441186a200141146a28020020024107746a220141800110848e8080001a200141043a0004200141083a00000240024020042d00184108470d0020044198016a200441186a41046a41e00010848e8080001a02400240200428021028026822070d00410021080c010b2004280214220128020021032001280204210520012802282102200441d8036a41286a22064100360200200441d8036a20032001200241284b22091b220320032005200220091b6a10f686808000200441f0026a41286a2006280200360200200441f0026a41206a200441d8036a41206a290200370300200441f0026a41186a200441d8036a41186a290200370300200441f0026a41106a200441d8036a41106a290200370300200441f0026a41086a200441d8036a41086a290200370300200420042902d8033703f0022004200128022c220a36029c030240024002400240024020042d009801417c6a41ff01712201410420014104491b0e050400010402040b200441c8016a21010c020b20044198016a41286a21010c010b200441c8016a21010b200141086a2802002001412c6a2802002202200241284b22031b21022001280204200141046a20031b21052001280200220341017621010240024020034101710d00410021060240200120024b0d0020012103410021010c020b2001200241d492c68000109481808000000b200120024f0d0841012106200141016a2103200520016a2d0000410f7121010b200441e0036a200220036b360200200420013a00d903200420063a00d8032004200520036a3602dc03200441f0026a200441d8036a10e28d808000200428029c03210a0b200441f8016a41086a200441fc026a290200370300200441f8016a41106a20044184036a290200370300200441f8016a41186a2004418c036a290200370300200441f8016a41206a20044194036a280200360200200420042902f4023703f80120042802f002210b2004280298032106410121080b200441a8026a41086a20044198016a41096a290000370300200441a8026a41106a20044198016a41116a290000370300200441a8026a41186a20044198016a41196a290000370300200441a8026a411f6a20044198016a41206a29000037000020042004290099013703a80220042d009801210320042802c001210c20042802c401210520042802c80121022004200441106a3602ac032004200441146a3602a803200441cc016a210102400240024002400240024002400240024002402003417c6a41ff01712209410420094104491b0e050001020304000b41002d00fca3c680001a410141002802c8a3c68000118180808000002201450d0f200141003a0000200441013602a402200420013602a0022004410136029c020c080b200441fc026a200141086a29020037020020044184036a200141106a2902003702002004418c036a200141186a290200370200200441f0026a41246a200141206a2902003702002004419c036a2203200141286a280200360200200420023602f002200420012902003702f402200441d8036a41206a200441cb026a280000360200200441d8036a41186a200441c3026a290000370300200441d8036a41106a200441bb026a290000370300200441d8036a41086a200441b3026a290000370300200420042900ab023703d80320042005360280042004200c3602fc03200420023602ac04200420042802f80220032802002201200141284b22011b3602a804200420042802f402200441f0026a41046a20011b3602a40420044194046a200441d8036a200441a4046a200441a8036a10f48580800020042802ac042203410176210220042802a804210120042802a40421090240024020034101710d004100210c0240200220014b0d0020022105410021020c020b2002200141d492c68000109481808000000b200220014f0d104101210c200241016a2105200920026a2d0000410f7121020b200420023a00bd032004200c3a00bc03200441003602b8032004200120056b3602b4032004200920056a3602b0032004419c026a200441b0036a200141017420036b20044194046a10d08c808000024002400240024020042d00d8030e020103000b20042802fc03220120012802002201417f6a36020020014101470d02200441d8036a41246a21010c010b20042802dc03220120012802002201417f6a36020020014101470d01200441d8036a41047221010b200110e28a8080000b200428029c034129490d0720042802f40241002802c0a3c68000118080808000000c070b20044184036a200141086a2902003702002004418c036a200141106a29020037020020044194036a200141186a2902003702002004419c036a200141206a280200360200200420023602f802200420053602f4022004200c3602f002200420012902003702fc02200441d8036a41206a200441cb026a280000360200200441d8036a41186a200441c3026a290000370300200441d8036a41106a200441bb026a290000370300200441d8036a41086a200441b3026a290000370300200420042900ab023703d803200441086a200441f0026a41046a41c0d1c280001096878080002004200c3602ac04200420042903083702a40420044194046a200441a4046a10dc8d808000200441003a0080042004200441a4046a3602fc03200441b0036a200441a8036a200441d8036a200441a4046a4100200410da858080002004419c026a20044194046a20042802a80441017420042802ac046b200441b0036a10cb8c808000000b200441f0026a41206a200441cb026a280000360200200441f0026a41186a200441c3026a290000370300200441f0026a41106a200441bb026a290000370300200441f0026a41086a200441b3026a290000370300200420042900ab02220d3703f00220042005360298032004200c36029403200da741ff01714103470d01410221000c020b200441fc026a200141086a29020037020020044184036a200141106a2902003702002004418c036a200141186a29020037020020044194036a200141206a2902003702002004419c036a2209200141286a280200360200200420023602f002200420012902003702f402200441d8036a41096a20044198016a410172220141086a290000370000200441d8036a41116a200141106a290000370000200441d8036a41196a200141186a290000370000200441d8036a41206a2001411f6a2900003700002004200c36028004200420012900003700d903200420033a00d8032004200236029004200420042802f80220092802002201200141284b22091b220136028c04200420042802f402200441f0026a41046a20091b220936028804200341ff01714103470d024102210e0c030b200441d8036a200441f0026a4100200441a8036a10f48580800020042902dc03210d20042802d80321000b2004200d3702b403200420003602b0032004419c026a200441d8036a200441b0036a10ca8c808000000b200441b0036a200441d8036a20044188046a200441a8036a10f48580800020042902b403210d20042802b003210e200428028c042101200428028804210920042802900421020b200241017621030240024020024101710d004100210f0240200320014b0d002003210c410021030c020b2003200141d492c68000109481808000000b200320014f0d0a4101210f200341016a210c200920036a2d0000410f7121030b200420033a00a1042004200f3a00a0042004410036029c0420042001200c6b3602980420042009200c6a36029404200441c0036a200441a8036a360200200441003602b803200420053602b0032004200541c0046a3602b4032004200441f0026a3602bc032004200d3702a8042004200e3602a4042004419c026a20044194046a200141017420026b200441b0036a200441a4046a10cf8c808000024020042d00d80322014103460d0002400240024020010e020103000b20042802fc03220120012802002201417f6a36020020014101470d02200441fc036a21010c010b20042802dc03220120012802002201417f6a36020020014101470d01200441dc036a21010b200110e28a8080000b200541002802c0a3c6800011808080800000200428029c034129490d0020042802f40241002802c0a3c68000118080808000000b0240024020042802a4022201411f4b0d0020042802a0022102200441f0026a20016a4100412020016b108a8e8080001a200441f0026a2002200110848e8080001a20002001360204200041206a200441f0026a41186a290000370000200041186a200441f0026a41106a290000370000200041106a200441f8026a290000370000200020042900f002370008410121030c010b2004280210220241d4006a28020021092002280250210c2004280214220228022c220541017621030240024020054101710d00200228020420022802282205200541284b22051b220e2003490d0c2002280200200220051b2102410021050c010b200228020420022802282205200541284b1b220e2003490d0c200e20034d0d0d200441f9026a20022802002002200541284b1b220220036a2d000041f001713a0000410121050b200420053a00f802200420033602f402200420023602f002200441d0026a200c200441f0026a20042802a00222022001200928021c1187808080000020042802102103200441f0026a41106a200441f8016a41086a290300370200200441f0026a41186a200441f8016a41106a290300370200200441f0026a41206a200441f8016a41186a29030037020020044198036a200441f8016a41206a2802003602002004200b3602f402200420083602f002200420042903f8013702f8022004200a3602a0032004200636029c03200441d8036a41186a200441d0026a41186a2205290000370300200441d8036a41106a200441d0026a41106a2209290000370300200441d8036a41086a200441d0026a41086a220a290000370300200420042900d0023703d8032003200441d8036a20022001200441f0026a10f885808000200041196a2005290000370000200041116a2009290000370000200041096a200a290000370000200020042900d002370001410021030b200020033a00000240200428029c02450d00200241002802c0a3c68000118080808000000b02402007450d002001411f4b0d0020064129490d00200b41002802c0a3c68000118080808000000b20042d00184108470d010c030b20002004290278370001200041003a0000200041196a20044190016a290200370000200041116a20044188016a290200370000200041096a20044180016a2902003700000b200441186a10e3858080000c010b200041003a000020002002290001370001200041196a200241196a290000370000200041116a200241116a290000370000200041096a200241096a2900003700000b200441b0046a2480808080000f0b2002200341e4d7c2800010f980808000000b2001200241e492c6800010f980808000000b4101410110b280808000000b2002200141e492c6800010f980808000000b2003200141e492c6800010f980808000000b2003200e41ac95c68000109581808000000b2003200e41bc95c68000109581808000000b2003200e41cc95c6800010f980808000000b807703067f027e087f23808080800041f0066b2207248080808000200741086a41086a200341086a28020036020020072003290200370308024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024020022d0000417c6a41ff01712208410420084104491b0e050001020304000b200728021022084101762203200728020c22014b0d04200728020821024100210920074188066a41286a220a410036020020074188066a200220036a200220016a10f58d808000200741186a41286a200a280200360200200741186a41206a20074188066a41206a290200370300200741186a41186a20074188066a41186a290200370300200741186a41106a20074188066a41106a290200370300200741186a41086a20074188066a41086a29020037030020072007290288063703182008410171210a4105210341002106200521084100210b0c310b200741f0036a41286a200241d8006a290200370300200741f0036a41206a200241d0006a290200370300200741f0036a41186a200241c8006a290200370300200741f0036a41106a200241c0006a290200370300200741f0036a41086a2208200241386a290200370300200720022902303703f003200741a8026a41286a2002412c6a280200360200200741a8026a41206a200241246a290200370300200741a8026a41186a2002411c6a290200370300200741a8026a41106a200241146a290200370300200741a8026a41086a2002410c6a290200370300200720022902043703a802200720072802f0033602dc0220072008280200200741f0036a412c6a2802002208200841284b22081b3602d802200720072802f403200741f0036a410472220920081b3602d402200241046a2108200741086a200741d4026a10db8d808000220a20072802d802220b41017420072802dc02220c6b2202460d210c220b200741f0036a41286a200241d0006a29020037030020074190046a200241c8006a29020037030020074188046a200241c0006a29020037030020074180046a200241386a290200370300200741f0036a41086a200241306a290200220d37030020072002290228220e3703f003200241086a280200210f20022d000421102007200e3e02b0022007200da72007419c046a2802002208200841284b22081b3602ac02200720072802f403200741f0036a41047220081b3602a802200241046a210a200741086a200741a8026a10db8d808000210820072802ac02220c410174210920072802b002210b024002402008450d0020082009200b6b470d012003200328020820086a36020820074188066a2001200a2003200420052006108286808000200728028806210420072d008c0622024102460d1e20072802b0022208410176220120072802ac0222054b0d0b20072802a802210341002106200741b0066a220a410036020020074188066a200320016a200320056a10f58d808000200741206a20074188066a41106a290200370300200741186a41106a20074188066a41186a290200370300200741186a41186a20074188066a41206a290200370300200741186a41206a200a28020036020020072007290290063703182008410171210f200728028c06210a2007280288062108200245210b410621030c200b2009200b460d20200b4101762208200c4f0d0520072802a80220086a2d0000210c41002d00fca3c680001a41c00441002802c8a3c68000118180808000002208450d04200841023a0000200841023a009c04200841023a00f803200841023a00d403200841023a00b003200841023a008c03200841023a00e802200841023a00c402200841023a00a002200841023a00fc01200841023a00d801200841023a00b401200841023a009001200841023a006c200841023a0048200841023a00240240024020072802ac02220941017420072802b00222116b4101470d00200741c8046a41026a200241056a220a41026a2d00003a000020074188066a41086a2002410c6a220241086a29020037030020074188066a41106a200241106a29020037030020074188066a41186a200241186a2802003602002007200a2f00003b01c80420072002290200370388060c010b201141016a2210410176220f20094b0d0720072802a802210220074188066a41286a2211410036020020074188066a2002200f6a200220096a10f58d808000200741c8046a41286a2011280200360200200741c8046a41206a20074188066a41206a290200370300200741c8046a41186a20074188066a41186a290200370300200741c8046a41106a20074188066a41106a290200370300200741c8046a41086a20074188066a41086a29020037030020072007290288063703c804200741ac046a200a41086a290000370000200741b4046a200a41106a290000370000200741bc046a200a41186a290000370000200741c4046a200a41206a2800003600002007200a2900003700a4042010410171210a02400240200141286a2802002202450d0020012002417f6a360228200141246a22022002280200220241016a220941002001411c6a280200220f2009200f491b6b360200200141206a28020020024102746a280200220f200141186a28020022024f0d0a200141146a280200200f4107746a220241046a200220022d00004108461b10e385808000200241063a0004200241083a00002002200a36022c200220072900a1043700052002410d6a200741a1046a41086a290000370000200241156a200741a1046a41106a2900003700002002411d6a200741a1046a41186a290000370000200241246a200741c0046a290000370000200220072903c804370230200241386a200741c8046a41086a290300370200200241c0006a200741c8046a41106a290300370200200241c8006a200741c8046a41186a290300370200200241d0006a200741e8046a290300370200200241d8006a200741f0046a2802003602000c010b0240200141186a28020022022001280210470d00200141106a2002109e86808000200128021821020b200141146a28020020024107746a220241063a0004200241083a0000200220072900a1043700052002200a36022c200220072903c8043702302002410d6a200741a1046a41086a290000370000200241156a200741a1046a41106a2900003700002002411d6a200741a1046a41186a290000370000200241246a200741c0046a290000370000200241386a200741c8046a41086a290300370200200241c0006a200741c8046a41106a290300370200200241c8006a200741c8046a41186a290300370200200241d0006a200741e8046a290300370200200241d8006a200741f0046a28020036020020012001280218220f41016a3602180b410021100b2008200c410f71200c410476200b4101711b41246c6a220220103a0000200220072f01c8043b00012002200f3602042002200729038806370208200241036a200741c8046a41026a2d00003a0000200241106a20074188066a41086a290300370200200241186a20074188066a41106a290300370200200241206a20074188066a41186a280200360200200741033a00cc04200720083602f804200741073a00c80420074188066a2001200741c8046a20032004200520061081868080002007280288064102460d1c200741c8006a41086a200741a4066a290200370300200741c8006a41106a20074188066a41246a280200360200200741c0006a200741e8066a280200360200200741186a41206a200741e0066a290200370300200741186a41186a200741d8066a290200370300200741186a41106a200741d0066a290200370300200741186a41086a200741c8066a2902003703002007200729029c06370348200720072902c006370318200728028c06220341087621022007280298062105200728029406210420072f019206210c20072d009106210920072d009006210620072802b006210120072802b406210f20072802b806210820072802bc06210a0c1e0b200b20086a2209410176220b200c4b0d0720072802a802210220074188066a41286a220f410036020020074188066a2002200b6a2002200c6a10f58d808000200741fc056a200f280200360200200741f4056a20074188066a41206a290200370200200741ec056a20074188066a41186a290200370200200741e4056a20074188066a41106a290200370200200741dc056a20074188066a41086a2202290200370200200741d4056a200729028806370200200741b4056a200a41086a290200370200200741bc056a200a41106a290200370200200741c4056a200a41186a290200370200200741cc056a200a41206a2802003602002003200328020820086a360208200720094101713602d0052007200a2902003702ac05200741063a00a80520074188066a2001200741a8056a20032004200520061081868080002007280288064102460d1b200728028c062103200741c8046a200241dc0010848e8080001a20074188066a200741a8026a200810da8d80800002400240200141286a2802002202450d0020012002417f6a360228200141246a22022002280200220241016a220441002001411c6a280200220520042005491b6b360200200141206a28020020024102746a2802002204200141186a28020022024f0d0a200141146a28020020044107746a220241046a200220022d00004108461b10e38580800020022003360204200241083a0000200241086a200741c8046a41dc0010848e8080001a0c010b0240200141186a28020022022001280210470d00200141106a2002109e86808000200128021821020b200141146a28020020024107746a22022003360204200241083a0000200241086a200741c8046a41dc0010848e8080001a20012001280218220441016a3602180b200741206a2007419c066a290200370300200741286a200741a4066a290200370300200741306a200741ac066a290200370300200741386a200741b4066a2802003602002007200729029406370318200728028806210f200728028c062108200728029006210a41002106410621030c1d0b2002280230210a20074198046a2002412c6a28020036020020074190046a200241246a29020037030020074188046a2002411c6a29020037030020074180046a200241146a290200370300200741f0036a41086a2002410c6a290200370300200720022902043703f003200728020c220b41017420072802102208460d1920084101762202200b4f0d09200728020820026a2d000021022003200328020841016a360208200a2002410f71200241047620084101711b41246c6a22022d00002108200241023a000002400240024020084102460d00200741e0006a41096a200241096a290000370000200741e0006a41116a200241116a290000370000200741e0006a41196a200241196a290000370000200741e0006a41206a200241206a280000360000200720083a00602007200229000137006120074188066a2001200741e0006a2003200420052006108286808000200728028806210320072d008c0622044102460d0220022003360204200241003a000020040d0120074193066a200741f0036a41086a2903003700002007419b066a200741f0036a41106a290300370000200741a3066a200741f0036a41186a290300370000200741ab066a200741f0036a41206a290300370000200741b3066a20074198046a280200360000200720072903f00337008b0620002007290088063700052000410d6a20074188066a41086a290000370000200041156a20074188066a41106a2900003700002000411d6a20074188066a41186a290000370000200041256a20074188066a41206a2900003700002000412c6a200741af066a2900003700002000200a360234200041073a0004200041013602000c320b2003280208220641017622082003280204220b4b0d0c2003280200210320074188066a41286a220c410036020020074188066a200320086a2003200b6a10f58d808000200741c8046a41286a200c280200360200200741c8046a41206a20074188066a41206a290200370300200741c8046a41186a20074188066a41186a290200370300200741c8046a41106a20074188066a41106a290200370300200741c8046a41086a20074188066a41086a29020037030020072007290288063703c8042006410171210b02400240200141286a2802002203450d0020012003417f6a360228200141246a22032003280200220341016a220841002001411c6a280200220620082006491b6b360200200141206a28020020034102746a2802002208200141186a28020022034f0d0f200141146a28020020084107746a220341046a200320032d00004108461b10e3858080002003200b360234200320053600302003200436002c200320053600102003200436000c200341003b0008200341053a0004200341083a0000200320072903c804370238200341c0006a200741c8046a41086a290300370200200341c8006a200741d8046a290300370200200341d0006a200741e0046a290300370200200341d8006a200741e8046a290300370200200341e0006a200741f0046a2802003602000c010b0240200141186a28020022032001280210470d00200141106a2003109e86808000200128021821030b200141146a28020020034107746a2203200b360234200320053600302003200436002c200320053600102003200436000c200341003b0008200341053a0004200341083a0000200320072903c804370238200341c0006a200741c8046a41086a290300370200200341c8006a200741d8046a290300370200200341d0006a200741e0046a290300370200200341d8006a200741e8046a290300370200200341e0006a200741f0046a28020036020020012001280218220841016a3602180b20022008360204200241003a00000b200741d0006a20074184046a290200370300200741d8006a2007418c046a280200360200200720072902fc033703484100210b2007280298042108200728029404210f200728029004210120072802f803210520072802f403210420072f01f203210c20072d00f103210920072d00f0032106410721030c2f0b2000410236020020002003360204024020072d00f00322004103460d0002400240024020000e020103000b200728029404220020002802002200417f6a36020020004101470d0220074194046a21000c010b20072802f403220020002802002200417f6a36020020004101470d01200741f0036a41047221000b200010e28a8080000b200a41002802c0a3c68000118080808000000c2f0b200741c8046a41286a200241d8006a290200370300200741c8046a41206a200241d0006a290200370300200741c8046a41186a200241c8006a290200370300200741c8046a41106a200241c0006a290200370300200741c8046a41086a220a200241386a290200370300200720022902303703c804200228022c2108200741a8026a41286a200241286a280200360200200741a8026a41206a200241206a290200370300200741a8026a41186a200241186a290200370300200741a8026a41106a200241106a290200370300200741a8026a41086a200241086a290200370300200720022902003703a802200720072802c80436028c012007200a280200200741f4046a2802002202200241284b22021b36028801200720072802cc04200741c8046a41047220021b360284010240024002400240024002400240024002400240200741086a20074184016a10db8d808000220a2007280288012202410174200728028c01220f6b220b470d00200a200728020c41017420072802106b460d010b200a200b490d012007280210200a6a220b4101762202200728020c220c4f0d02200728020820026a2d000021022003200a20032802086a41016a36020820082002410f712002410476200b4101711b41246c6a22022d0000210a200241023a0000200a4102460d0320074184026a41096a200241096a29000037000020074184026a41116a200241116a29000037000020074184026a41196a200241196a29000037000020074184026a41206a200241206a2800003600002007200a3a008402200720022900013700850220074188066a200120074184026a2003200420052006108286808000200728028806210320072d008c0622044102460d0520022003360204200241003a000020040d04200041346a20074184016a10d98d80800020002008360230200041013602002000412c6a200741d0026a280200360200200041246a200741c8026a2903003702002000411c6a200741c0026a290300370200200041146a200741b8026a2903003702002000410c6a200741b0026a290300370200200020072903a8023702040c060b20072005360298042007200436029404200720053602f803200720043602f4034100210b200741003b01f003024020072d00a8024103460d00200741a8026a200741f0036a10e785808000210b0b200f410176220920024b0d13200728028401210a20074188066a41286a220c410036020020074188066a200a20096a200a20026a10f58d808000200741186a41286a200c280200360200200741186a41206a20074188066a41206a2202290200370300200741186a41186a20074188066a41186a2210290200370300200741186a41106a20074188066a41106a2211290200370300200741186a41086a20074188066a41086a221229020037030020072007290288063703182003280204210a2003280200210920032802082103200728028c012113200728028801211420072f00f103211520072d00f3032116200c200741a8026a41286a2802003602002002200741a8026a41206a2903003703002010200741a8026a41186a2903003703002011200741a8026a41106a2903003703002012200741a8026a41086a290300370300200720072903a802370388062003201441017420136b6a220341017621020240024020034101710d002002200a4b0d16200741003a00dc02200720023602d802200720093602d4020c010b2002200a4b0d162002200a4f0d17200720093602d402200720023602d802200741dd026a200920026a2d000041f001713a0000200741013a00dc020b2004411076210c20044108762109200f410171210a201520164110747221022001200620074188066a200741d4026a1083868080004100210320042106200521112005210f0c070b200f200a41016a22096a220c410176220b20024b0d16200728028401210320074188066a41286a2206410036020020074188066a2003200b6a200320026a10f58d80800020074190016a41286a200628020036020020074190016a41206a20074188066a41206a29020037030020074190016a41186a20074188066a41186a29020037030020074190016a41106a20074188066a41106a29020037030020074190016a41086a20074188066a41086a290200370300200741c0016a41086a200741a8026a41086a290300370300200741c0016a41106a200741a8026a41106a290300370300200741c0016a41186a200741a8026a41186a290300370300200741c0016a41206a200741a8026a41206a290300370300200741c0016a41286a200741a8026a41286a280200360200200720072902880637039001200720072903a8023703c001200728028c01200a6a220641017622022007280288012203490d0520022003418cd5c2800010f980808000000b2002200c418cd5c2800010f980808000000b20032802082206410176220a2003280204220b4b0d152003280200210320074188066a41286a220c410036020020074188066a2003200a6a2003200b6a10f58d808000200741f0036a41286a200c280200360200200741f0036a41206a20074188066a41206a290200370300200741f0036a41186a20074188066a41186a290200370300200741f0036a41106a20074188066a41106a290200370300200741f0036a41086a20074188066a41086a29020037030020072007290288063703f0032006410171210b02400240200141286a2802002203450d0020012003417f6a360228200141246a22032003280200220341016a220a41002001411c6a2802002206200a2006491b6b360200200141206a28020020034102746a280200220a200141186a28020022034f0d18200141146a280200200a4107746a220341046a200320032d00004108461b10e3858080002003200b360234200320053600302003200436002c200320053600102003200436000c200341003b0008200341053a0004200341083a0000200320072903f003370238200341c0006a200741f0036a41086a290300370200200341c8006a20074180046a290300370200200341d0006a20074188046a290300370200200341d8006a20074190046a290300370200200341e0006a20074198046a2802003602000c010b0240200141186a28020022032001280210470d00200141106a2003109e86808000200128021821030b200141146a28020020034107746a2203200b360234200320053600302003200436002c200320053600102003200436000c200341003b0008200341053a0004200341083a0000200320072903f003370238200341c0006a200741f0036a41086a290300370200200341c8006a20074180046a290300370200200341d0006a20074188046a290300370200200341d8006a20074190046a290300370200200341e0006a20074198046a28020036020020012001280218220a41016a3602180b2002200a360204200241003a00000b200728028c012201410176220320072802880122044b0d1620072802840121024100210b20074188066a41286a2205410036020020074188066a200220036a200220046a10f58d808000200741186a41286a2005280200360200200741186a41206a20074188066a41206a290200370300200741186a41186a20074188066a41186a290200370300200741186a41106a20074188066a41106a290200370300200741186a41086a20074188066a41086a290200370300200720072902880637031820072d00a802210320072d00ac02210620072d00ad02210920072f01ae02210c20072802b002211120072802b402210520072f00a902210220072d00ab022104200741c8006a41106a200741a8026a41206a280200360200200741c8006a41086a200741a8026a41186a290300370300200720072903b8023703482001410171210a2002200441107472210220072802d002210f20072802cc0221040c030b2000410236020020002003360204200741a8026a10e585808000200841002802c0a3c68000118080808000000b20072802f4044129490d3020072802cc0441002802c0a3c68000118080808000000c300b20072802840120026a2d0000210341002d00fca3c680001a41c00441002802c8a3c68000118180808000002210450d14200c410171210c201041023a009c04201041023a00f803201041023a00d403201041023a00b003201041023a008c03201041023a00e802201041023a00c402201041023a00a002201041023a00fc01201041023a00d801201041023a00b401201041023a009001201041023a006c201041023a0048201041023a0024201041023a0000200741b3066a200741c0016a41286a280200360000200741ab066a200741c0016a41206a290300370000200741a3066a200741c0016a41186a2903003700002007419b066a200741c0016a41106a29030037000020074193066a200741c8016a290300370000200720072903c00137008b06200141106a210f02400240200141286a2802002202450d0020012002417f6a360228200141246a22022002280200220241016a220b4100200128021c2211200b2011491b6b360200200141206a28020020024102746a280200220b200141186a221128020022024f0d17200141146a280200200b4107746a220241046a200220022d00004108461b10e385808000200241083a00002002200c360234200220083602302002200729008806370001200241096a20074188066a41086a290000370000200241116a20074188066a41106a290000370000200241196a20074188066a41186a290000370000200241216a20074188066a41206a290000370000200241286a200741af066a2900003700002002200729039001370238200241c0006a20074190016a41086a290300370200200241c8006a20074190016a41106a290300370200200241d0006a20074190016a41186a290300370200200241d8006a20074190016a41206a290300370200200241e0006a20074190016a41286a2802003602000c010b0240200141186a221128020022022001280210470d00200f2002109e86808000201128020021020b200141146a28020020024107746a220241083a000020022007290088063700012002200c360234200220083602302002200729039001370238200241096a20074188066a41086a290000370000200241116a20074188066a41106a290000370000200241196a20074188066a41186a290000370000200241216a20074188066a41206a290000370000200241286a200741af066a290000370000200241c0006a20074190016a41086a290300370200200241c8006a20074190016a41106a290300370200200241d0006a20074190016a41186a290300370200200241d8006a20074190016a41206a290300370200200241e0006a20074190016a41286a28020036020020012001280218220b41016a3602180b20102003410f71200341047620064101711b41246c6a2203200b36020441002102200341003a00000240200728020c22034101742007280210220b200a6a2208470d0020074188066a20074184016a200a10da8d808000200741c8006a41106a200741f0016a41106a280200360200200741c8006a41086a200741f0016a41086a290200370300200741186a41086a20074194066a290200370300200741186a41106a2007419c066a290200370300200741306a200741a4066a290200370300200741386a20074188066a41246a290200370300200741c0006a200741b4066a280200360200200720072902f0013703482007200729028c063703182004411076210c20044108762109200728028806210a20042106200521112005210f20102108410021034100210b0c010b2008410176220620034f0d18200b20096a2209410176220c20034b0d162007280208220220066a2d0000210b20074188066a41286a2206410036020020074188066a2002200c6a200220036a10f58d808000200741f0036a41286a2006280200360200200741f0036a41206a20074188066a41206a290200370300200741f0036a41186a20074188066a41186a290200370300200741f0036a41106a20074188066a41106a290200370300200741f0036a41086a20074188066a41086a29020037030020072007290288063703f003200941017121060240024020012802282202450d0020012002417f6a360228200141246a22022002280200220241016a22034100200128021c220c2003200c491b6b360200200141206a28020020024102746a2802002203200128021822024f0d19200141146a28020020034107746a220241046a200220022d00004108461b10e3858080002002410b6a41003a0000200241003b0009200220053602102002200436020c200241003a0008200241053a0004200241083a000020022006360234200220053602302002200436022c200220072902f001370218200241206a200741f0016a41086a290200370200200241286a200741f0016a41106a280200360200200220072903f003370238200241c0006a200741f0036a41086a290300370200200241c8006a200741f0036a41106a290300370200200241d0006a20074188046a290300370200200241d8006a200741f0036a41206a290300370200200241e0006a200741f0036a41286a2802003602000c010b024020112802002202200f280200470d00200f2002109e86808000201128020021020b200141146a28020020024107746a220241003b0009200220053602102002200436020c200241003a0008200241053a0004200241083a0000200220072902f00137021820022006360234200220053602302002200436022c200220072903f0033702382002410b6a41003a0000200241206a200741f0016a41086a290200370200200241286a200741f0016a41106a280200360200200241c0006a200741f0036a41086a290300370200200241c8006a200741f0036a41106a290300370200200241d0006a20074188046a290300370200200241d8006a200741f0036a41206a290300370200200241e0006a200741f0036a41286a28020036020020012001280218220341016a3602180b2010200b410f71200b41047620084101711b41246c6a220220033602044100210b200241003a000020074188066a20074184016a200a10da8d808000200741206a20074194066a290200370300200741286a2007419c066a290200370300200741306a200741a4066a290200370300200741386a20074188066a41246a290200370300200741c0006a200741b4066a2802003602002007200729028c06370318200728028806210a41032103201021080b024020072802f4044129490d0020072802cc0441002802c0a3c68000118080808000000b20042101201121040c2d0b2003200141e491c68000109481808000000b410441c00410b280808000000b2008200c418cd5c2800010f980808000000b200f200941e491c68000109481808000000b200f200241d4d7c2800010f980808000000b200b200c41e491c68000109481808000000b2004200241d4d7c2800010f980808000000b2001200541e491c68000109481808000000b2002200b418cd5c2800010f980808000000b2008200b41e491c68000109481808000000b2008200341d4d7c2800010f980808000000b2009200241e491c68000109481808000000b2002200a41f492c68000109581808000000b2002200a418493c68000109581808000000b2002200a419493c6800010f980808000000b200b200241e491c68000109481808000000b200a200b41e491c68000109481808000000b200a200341d4d7c2800010f980808000000b2003200441e491c68000109481808000000b410441c00410b280808000000b200b200241d4d7c2800010f980808000000b200c200341e491c68000109481808000000b2003200241d4d7c2800010f980808000000b20062003418cd5c2800010f980808000000b200720053602b006200720043602ac0620072005360290062007200436028c064100210b200741003b018806024020072d00f0034103460d00200741f0036a20074188066a10e785808000210b0b2003280208220c410176210802400240024002400240200c4101710d0020082003280204220c4b0d02200741003a00d004200720083602cc04200720032802003602c8040c010b20082003280204220c4b0d022008200c4f0d032007200328020022033602c804200720083602cc04200741d1046a200320086a2d000041f001713a0000200741013a00d0040b20012006200241046a200741c8046a1083868080004100210941072103410021062004210f200521080c170b2008200c41f492c68000109581808000000b2008200c418493c68000109581808000000b2008200c419493c6800010f980808000000b200728028c0621040b2000410236020020002004360204200728029c044129490d1320072802f40341002802c0a3c68000118080808000000c130b4100210b0b200728029c044129490d1020072802f40341002802c0a3c68000118080808000000c100b419cd5c28000412a41c8d5c2800010f880808000000b200a200728020c41017420072802106b470d00200741d0046a2005360200200720043602cc04200741003a00c804200741a8026a200741c8046a10e785808000210c2003280208200a6a220b41017621022003280204210a2003280200210302400240200b4101710d002002200a4b0d05200741003a0090062007200236028c0620072003360288060c010b2002200a4b0d052002200a4f0d0620072003360288062007200236028c0620074191066a200320026a2d000041f001713a0000200741013a0090060b20012006200820074188066a108386808000200741d4046a2102200c0d0120072802f003210a20072802f403210120072802f8032108200728029c0421034100210b20074188066a41286a2206410036020020074188066a20012009200341284b220c1b2201200120082003200c1b6a10f686808000200741186a41286a2006280200360200200741186a41206a20074188066a41206a290200370300200741186a41186a20074188066a41186a290200370300200741186a41106a20074188066a41106a290200370300200741186a41086a20074188066a41086a29020037030020072007290288063703180c020b200a2002490d07200c410176220a200b4b0d0520072802d402210220074188066a41286a2209410036020020074188066a2002200a6a2002200b6a10f58d808000200741c8046a41286a220a2009280200360200200741c8046a41206a220b20074188066a41206a290200370300200741c8046a41186a220920074188066a41186a290200370300200741c8046a41106a220f20074188066a41106a290200370300200741c8046a41086a221020074188066a41086a29020037030020072007290288063703c80441002d00fca3c680001a41c00441002802c8a3c68000118180808000002202450d06200241023a009c04200241023a00f803200241023a00d403200241023a00b003200241023a008c03200241023a00e802200241023a00c402200241023a00a002200241023a00fc01200241023a00d801200241023a00b401200241023a009001200241023a006c200241023a0048200241023a0024200241023a000020074190036a41086a200841086a29020037030020074190036a41106a200841106a29020037030020074190036a41186a200841186a29020037030020074190036a41206a200841206a29020037030020074190036a41286a200841286a2802003602002007200829020037039003200741c4036a20072903c804370200200741cc036a2010290300370200200741d4036a200f290300370200200741dc036a2009290300370200200741e4036a200b290300370200200741ec036a200a2802003602002007200c4101713602c003200720023602bc0320074188066a200120074190036a20032004200520061081868080002007280288064102460d08200741c8006a41086a200741a4066a290200370300200741c8006a41106a200741ac066a280200360200200741c0006a200741e8066a280200360200200741386a200741e0066a290200370300200741306a200741d8066a290200370300200741186a41106a200741d0066a290200370300200741186a41086a200741c8066a2902003703002007200729029c06370348200720072902c006370318200728028c06220341087621022007280298062105200728029406210420072f019206210c20072d009106210920072d009006210620072802b006210120072802b406210f20072802b806210820072802bc06210a4100210b0c0c0b20072802f003210a20072802f403210120072802f8032108200728029c04210320074188066a41286a220b410036020020074188066a20012009200341284b22061b220120012008200320061b6a10f686808000200741186a41286a200b280200360200200741186a41206a20074188066a41206a290200370300200741186a41186a20074188066a41186a290200370300200741186a41106a20074188066a41106a290200370300200741186a41086a20074188066a41086a29020037030020072007290288063703184101210b0b200741c8006a41106a200241106a280200360200200741c8006a41086a200241086a2902003703002007200229020037034841052103410021060c0a0b2002200a41f492c68000109581808000000b2002200a418493c68000109581808000000b2002200a419493c6800010f980808000000b200a200b41e491c68000109481808000000b410441c00410b280808000000b41002d00fca3c680001a41c00441002802c8a3c68000118180808000002202450d01200241023a0000200241023a009c04200241023a00f803200241023a00d403200241023a00b003200241023a008c03200241023a00e802200241023a00c402200241023a00a002200241023a00fc01200241023a00d801200241023a00b401200241023a009001200241023a006c200241023a0048200241023a0024024020072802dc02200a6a220c410176220f20072802d802220b490d00200f200b418cd5c2800010f980808000000b200c41016a22114101762210200b4b0d0220072802d4022209200f6a2d0000210f20074188066a41286a2212410036020020074188066a200920106a2009200b6a10f58d808000200741c8046a41286a2012280200360200200741c8046a41206a20074188066a41206a290200370300200741c8046a41186a20074188066a41186a290200370300200741c8046a41106a20074188066a41106a290200370300200741c8046a41086a20074188066a41086a29020037030020072007290288063703c804200741ec026a200841086a290000370000200741f4026a200841106a290000370000200741fc026a200841186a29000037000020074184036a200841206a2900003700002007418c036a200841286a280000360000200720082900003700e4022011410171210902400240200141286a2802002208450d0020012008417f6a360228200141246a22082008280200220841016a220b41002001411c6a2802002210200b2010491b6b360200200141206a28020020084102746a280200220b200141186a28020022084f0d05200141146a280200200b4107746a220841046a200820082d00004108461b10e385808000200841053a0004200841083a000020082009360234200820072900e1023700052008410d6a200741e1026a41086a290000370000200841156a200741e1026a41106a2900003700002008411d6a200741e1026a41186a290000370000200841256a200741e1026a41206a2900003700002008412c6a20074188036a290000370000200820072903c804370238200841c0006a200741c8046a41086a290300370200200841c8006a200741c8046a41106a290300370200200841d0006a200741c8046a41186a290300370200200841d8006a200741c8046a41206a290300370200200841e0006a200741f0046a2802003602000c010b0240200141186a28020022082001280210470d00200141106a2008109e86808000200128021821080b200141146a28020020084107746a220841053a0004200841083a0000200820072900e10237000520082009360234200820072903c8043702382008410d6a200741e1026a41086a290000370000200841156a200741e1026a41106a2900003700002008411d6a200741e1026a41186a290000370000200841256a200741e1026a41206a2900003700002008412c6a20074188036a290000370000200841c0006a200741c8046a41086a290300370200200841c8006a200741c8046a41106a290300370200200841d0006a200741c8046a41186a290300370200200841d8006a200741c8046a41206a290300370200200841e0006a200741f0046a28020036020020012001280218220b41016a3602180b2002200f410f71200f410476200c4101711b41246c6a2208200b3602044100210b200841003a0000200741f8046a200741086a200a10da8d808000200720023602f404200741033a00c80420074188066a2001200741c8046a20032004200520061081868080002007280288064102460d00200741c8006a41086a200741a4066a290200370300200741c8006a41106a20074188066a41246a280200360200200741c0006a200741e8066a280200360200200741386a200741e0066a290200370300200741306a200741d8066a290200370300200741186a41106a200741d0066a290200370300200741186a41086a200741c8066a2902003703002007200729029c06370348200720072902c006370318200728028c06220341087621022007280298062105200728029406210420072f019206210c20072d009106210920072d009006210620072802b006210120072802b406210f20072802b806210820072802bc06210a0c040b200728028c0621022000410236020020002002360204200728029c044129490d0520072802f40341002802c0a3c68000118080808000000c050b410441c00410b280808000000b2010200b41e491c68000109481808000000b200b200841d4d7c2800010f980808000000b200728029c044129490d0020072802f40341002802c0a3c68000118080808000000b200020023b0005200020053602102000200436020c2000200c3b010a200020093a0009200020063a0008200020033a00042000200b360200200020072903483702142000200a360234200020083602302000200f36022c20002001360228200041076a20024110763a00002000411c6a200741c8006a41086a290300370200200041246a200741c8006a41106a280200360200200041e0006a200741c0006a280200360200200041d8006a200741386a290300370200200041d0006a200741306a290300370200200041c8006a200741186a41106a290300370200200041c0006a200741186a41086a290300370200200020072903183702380b200741f0066a2480808080000bb11503057f017e157f23808080800041b0036b22072480808080002007200536020420072004360200024002400240024002400240024002400240024002400240024020022d00000d00200228020421020c010b200741206a200241196a290000370300200741186a200241116a290000370300200741106a200241096a290000370300200720022900013703082003280208220541017621020240024020054101710d002002200328020422054b0d05200741003a00ec01200720023602e801200720032802003602e4010c010b2002200328020422054b0d05200220054f0d062007200328020022053602e401200720023602e801200741ed016a200520026a2d000041f001713a0000200741013a00ec010b200741cc026a2001200741086a200741e4016a10878680800020072802d002210220072802cc020d010b0240200141286a28020022052001411c6a22082802002204470d00200810a889808000200128021c2104200128022821050b200141206a280200200141246a28020020056a22054100200420052004491b6b4102746a20023602002001200128022841016a360228200141186a280200220420024d0d05200141146a28020020024107746a22022d00002104200741296a200241016a41df0010848e8080001a200241043a0004200241083a0000200228026021092007280200210520072802042108024020044108470d00200741e4016a2007412c6a41dc0010848e8080001a200720033602c802200720093602c002200720013602c402200741cc026a2001200741e4016a200320052008200610818680800020072802cc0222034102460d022003410147210a20072802ac03210b20072902a403210c20072802a0032104200728029c03210520072802980321062007280294032108200728029003210d200728028c03210e200728028803210f2007280284032110200728028003211120072802fc02211220072802f802211320072802f402211420072802f002211520072802ec02211620072802e802211720072802e402211820072802e002211920072802dc02211a20072802d802211b20072802d402211c20072802d0022102410821034100211d0c090b2003280208211d2003280204210b2003280200210a200741e4016a410172200741296a41df0010848e8080001a200741e0016a200241fc006a280000360200200741d8016a200241f4006a290000370300200741c8016a41086a200241ec006a290000370300200720013602c402200720033602c802200720043a00e401200720022900643703c801200741cc026a2001200741e4016a200320052008200610818680800020072802cc0222034102460d0120072902a803210c20072802a403211e20072802a0032104200728029c03210520072802980321062007280294032108200728029003210d200728028c03210e200728028803210f2007280284032110200728028003211120072802fc02211220072802f802211320072802f402211420072802f002211520072802ec02211620072802e802211720072802e402211820072802e002211a20072802dc02211b20072802d802211c20072802d402211f20072802d0022102024020034101460d00201d410176210302400240201d4101710d0002402003200b4b0d00410021190c020b2003200b41f492c68000109581808000000b2003200b4b0d082003200b4f0d09200a20036a2d00004170712120410121190b200c422088a7210b4100211d200741cc026a41286a22214100360200200741cc026a200a200a20036a10f58d80800020074184026a220a41286a2021280200360200200a41206a200741cc026a41206a290200370200200a41186a200741cc026a41186a290200370200200a41106a200741cc026a41106a29020037020041082103200a41086a200741cc026a41086a290200370200200a20072902cc02370200200741b1026a20203a0000200741b0026a20193a0000200741f0016a200741c8016a41086a290300370200200741f8016a200741c8016a41106a29030037020020074180026a200741c8016a41186a280200360200200720093602e401200720072903c8013702e801200141dc006a200741e4016a10958d8080001a200c422086201ead84210c4101210a201a2119201b211a201c211b201f211c0c090b200741a8016a41186a200741c8016a41186a280200360200200741a8016a41106a200741c8016a41106a290300370300200741a8016a41086a200741c8016a41086a290300370300200720072903c8013703a801200241ff01712103200241807e71211d4100210a201821192017211820162117201521162014211520132114201221132011211220102111200f2110200e210f200d210e2008210d200621082005210620042105201e21042009210b201f21020c080b200041023a000420002002360200200420042802002201417f6a36020020014101470d08200710e28a8080000c080b20072802d0022101200041023a0004200020013602000c070b2002200541f492c68000109581808000000b20022005418493c68000109581808000000b20022005419493c6800010f980808000000b2002200441e4d7c2800010f980808000000b2003200b418493c68000109581808000000b2003200b419493c6800010f980808000000b20074188016a41186a200741a8016a41186a28020036020020074188016a41106a200741a8016a41106a29030037030020074188016a41086a200741a8016a41086a290300370300200720072903a801370388012003201d7221090240024020012802282203450d0020012003417f6a36022820012001280224220341016a221d4100200128021c221e201d201e491b6b360224200128022020034102746a28020022032001280218221d4f0d03200128021420034107746a220141046a200120012d00004108461b10e3858080002001200b3602602001200c37025820012004360254200120053602502001200636024c200120083602482001200d3602442001200e3602402001200f36023c2001201036023820012011360234200120123602302001201336022c2001201436022820012015360224200120163602202001201736021c20012018360218200120193602142001201a3602102001201b36020c2001201c3602082001200236020420012009360200200141fc006a200741a0016a280200360200200141f4006a20074198016a290300370200200141ec006a20074188016a41086a29030037020020012007290388013702640c010b0240200128021822032001280210470d00200141106a2003109e86808000200128021821030b200128021420034107746a2203200b3602602003200c37025820032004360254200320053602502003200636024c200320083602482003200d3602442003200e3602402003200f36023c2003201036023820032011360234200320123602302003201336022c2003201436022820032015360224200320163602202003201736021c20032018360218200320193602142003201a3602102003201b36020c2003201c3602082003200236020420032009360200200341fc006a200741a0016a280200360200200341f4006a20074198016a290300370200200341ec006a20074190016a290300370200200320072903880137026420012001280218220341016a3602180b2000200a3a0004200020033602000b200741b0036a2480808080000f0b2003201d41d4d7c2800010f980808000000b840502047f047e23808080800041b0016b2204248080808000024020022d000022054103460d0002400240024002402005417f6a0e020100040b20022d00010d010c030b200241016a21050c010b200241026a21050b200441086a41186a200541186a290000370300200441086a41106a200541106a290000370300200441086a41086a200541086a29000037030020042005290000370308200328020421062003280200210520044184016a41286a2207410036020020044184016a2005200520066a10f686808000200441d8006a41286a20072802002205360200200441d8006a41206a20044184016a41206a2902002208370300200441d8006a41186a20044184016a41186a2902002209370300200441d8006a41106a20044184016a41106a290200220a370300200441d8006a41086a20044184016a41086a290200220b370300200441086a41286a200b370300200441386a200a370300200441c0006a2009370300200441c8006a2008370300200441d0006a20053602002004200429028401220837035820042008370328200441d4006a20032f01083b0100200041dc006a200441086a10958d8080001a0b024020012d000022034103460d0002400240024020030e020103000b2001280224220320032802002203417f6a36020020034101470d02200141246a21030c010b2001280204220320032802002203417f6a36020020034101470d01200141046a21030b200310e28a8080000b20012002290200370200200141286a200241286a280200360200200141206a200241206a290200370200200141186a200241186a290200370200200141106a200241106a290200370200200141086a200241086a290200370200200441b0016a2480808080000bab7803097f027e067f23808080800041f0066b2207248080808000200741086a41086a200341086a28020036020020072003290200370308024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024020022d0000417c6a41ff01712208410420084104491b0e050001020304000b200728021022084101762203200728020c22014b0d04200728020821024100210920074188066a41286a220a410036020020074188066a200220036a200220016a10f58d808000200741186a41286a200a280200360200200741186a41206a20074188066a41206a290200370300200741186a41186a20074188066a41186a290200370300200741186a41106a20074188066a41106a290200370300200741186a41086a20074188066a41086a29020037030020072007290288063703182008410171210a200541204b410174210b4105210c2004210d200521084100210e0c310b200741f0036a41286a200241d8006a290200370300200741f0036a41206a200241d0006a290200370300200741f0036a41186a200241c8006a290200370300200741f0036a41106a200241c0006a290200370300200741f0036a41086a2208200241386a290200370300200720022902303703f003200741a8026a41286a2002412c6a280200360200200741a8026a41206a200241246a290200370300200741a8026a41186a2002411c6a290200370300200741a8026a41106a200241146a290200370300200741a8026a41086a2002410c6a290200370300200720022902043703a802200720072802f0033602dc0220072008280200200741f0036a412c6a2802002208200841284b22081b3602d802200720072802f403200741f0036a410472220f20081b3602d402200241046a2108200741086a200741d4026a10db8d808000220a20072802d802220e41017420072802dc02220c6b2202460d210c220b200741f0036a41286a200241d0006a29020037030020074190046a200241c8006a29020037030020074188046a200241c0006a29020037030020074180046a200241386a290200370300200741f0036a41086a200241306a29020022103703002007200229022822113703f003200241086a280200210d20022d0004210f200720113e02b00220072010a72007419c046a2802002208200841284b22081b3602ac02200720072802f403200741f0036a41047220081b3602a802200241046a210a200741086a200741a8026a10db8d808000210820072802ac02220c410174210b20072802b002210e024002402008450d002008200b200e6b470d012003200328020820086a36020820074188066a2001200a2003200420052006108586808000200728028806210420072d008c0622024102460d1e20072802b0022208410176220520072802ac0222014b0d0b20072802a80221034100210b200741b0066a220a410036020020074188066a200320056a200320016a10f58d808000200741206a20074188066a41106a290200370300200741186a41106a20074188066a41186a290200370300200741186a41186a20074188066a41206a290200370300200741186a41206a200a28020036020020072007290290063703182008410171210d200728028c06210a2007280288062108200245210e4106210c0c200b200b200e460d20200e4101762208200c4f0d0520072802a80220086a2d0000210c41002d00fca3c680001a41c00441002802c8a3c68000118180808000002208450d04200841023a0000200841023a009c04200841023a00f803200841023a00d403200841023a00b003200841023a008c03200841023a00e802200841023a00c402200841023a00a002200841023a00fc01200841023a00d801200841023a00b401200841023a009001200841023a006c200841023a0048200841023a00240240024020072802ac02220b41017420072802b00222096b4101470d00200741c8046a41026a200241056a220a41026a2d00003a000020074188066a41086a2002410c6a220241086a29020037030020074188066a41106a200241106a29020037030020074188066a41186a200241186a2802003602002007200a2f00003b01c80420072002290200370388060c010b200941016a220f410176220d200b4b0d0720072802a802210220074188066a41286a2209410036020020074188066a2002200d6a2002200b6a10f58d808000200741c8046a41286a2009280200360200200741c8046a41206a20074188066a41206a290200370300200741c8046a41186a20074188066a41186a290200370300200741c8046a41106a20074188066a41106a290200370300200741c8046a41086a20074188066a41086a29020037030020072007290288063703c804200741ac046a200a41086a290000370000200741b4046a200a41106a290000370000200741bc046a200a41186a290000370000200741c4046a200a41206a2800003600002007200a2900003700a404200f410171210a02400240200141286a2802002202450d0020012002417f6a360228200141246a22022002280200220241016a220b41002001411c6a280200220d200b200d491b6b360200200141206a28020020024102746a280200220d200141186a28020022024f0d0a200141146a280200200d4107746a220241046a200220022d00004108461b10e385808000200241063a0004200241083a00002002200a36022c200220072900a1043700052002410d6a200741a1046a41086a290000370000200241156a200741a1046a41106a2900003700002002411d6a200741a1046a41186a290000370000200241246a200741c0046a290000370000200220072903c804370230200241386a200741c8046a41086a290300370200200241c0006a200741c8046a41106a290300370200200241c8006a200741c8046a41186a290300370200200241d0006a200741e8046a290300370200200241d8006a200741f0046a2802003602000c010b0240200141186a28020022022001280210470d00200141106a2002109e86808000200128021821020b200141146a28020020024107746a220241063a0004200241083a0000200220072900a1043700052002200a36022c200220072903c8043702302002410d6a200741a1046a41086a290000370000200241156a200741a1046a41106a2900003700002002411d6a200741a1046a41186a290000370000200241246a200741c0046a290000370000200241386a200741c8046a41086a290300370200200241c0006a200741c8046a41106a290300370200200241c8006a200741c8046a41186a290300370200200241d0006a200741e8046a290300370200200241d8006a200741f0046a28020036020020012001280218220d41016a3602180b4100210f0b2008200c410f71200c410476200e4101711b41246c6a2202200f3a0000200220072f01c8043b00012002200d3602042002200729038806370208200241036a200741c8046a41026a2d00003a0000200241106a20074188066a41086a290300370200200241186a20074188066a41106a290300370200200241206a20074188066a41186a280200360200200741033a00cc04200720083602f804200741073a00c80420074188066a2001200741c8046a20032004200520061084868080002007280288064102460d1c200741c8006a41086a200741a4066a290200370300200741c8006a41106a20074188066a41246a280200360200200741c0006a200741e8066a280200360200200741186a41206a200741e0066a290200370300200741186a41186a200741d8066a290200370300200741186a41106a200741d0066a290200370300200741186a41086a200741c8066a2902003703002007200729029c06370348200720072902c006370318200728028c06220c41087621022007280298062105200728029406210420072f019206210f20072d009106210920072d009006210b20072802b006210320072802b406210d20072802b806210820072802bc06210a0c1e0b200e20086a220b410176220e200c4b0d0720072802a802210220074188066a41286a220d410036020020074188066a2002200e6a2002200c6a10f58d808000200741fc056a200d280200360200200741f4056a20074188066a41206a290200370200200741ec056a20074188066a41186a290200370200200741e4056a20074188066a41106a290200370200200741dc056a20074188066a41086a2202290200370200200741d4056a200729028806370200200741b4056a200a41086a290200370200200741bc056a200a41106a290200370200200741c4056a200a41186a290200370200200741cc056a200a41206a2802003602002003200328020820086a3602082007200b4101713602d0052007200a2902003702ac05200741063a00a80520074188066a2001200741a8056a20032004200520061084868080002007280288064102460d1b200728028c062103200741c8046a200241dc0010848e8080001a20074188066a200741a8026a200810da8d80800002400240200141286a2802002202450d0020012002417f6a360228200141246a22022002280200220241016a220441002001411c6a280200220520042005491b6b360200200141206a28020020024102746a2802002204200141186a28020022024f0d0a200141146a28020020044107746a220241046a200220022d00004108461b10e38580800020022003360204200241083a0000200241086a200741c8046a41dc0010848e8080001a0c010b0240200141186a28020022022001280210470d00200141106a2002109e86808000200128021821020b200141146a28020020024107746a22022003360204200241083a0000200241086a200741c8046a41dc0010848e8080001a20012001280218220441016a3602180b200741206a2007419c066a290200370300200741286a200741a4066a290200370300200741306a200741ac066a290200370300200741386a200741b4066a2802003602002007200729029406370318200728028806210d200728028c062108200728029006210a4100210b4106210c0c1d0b2002280230210a20074198046a2002412c6a280200360200200741f0036a41206a200241246a29020037030020074188046a2002411c6a29020037030020074180046a200241146a290200370300200741f0036a41086a2002410c6a290200370300200720022902043703f003200728020c220e41017420072802102208460d1920084101762202200e4f0d09200728020820026a2d000021022003200328020841016a360208200a2002410f71200241047620084101711b41246c6a22022d00002108200241023a000002400240024020084102460d00200741e0006a41096a200241096a290000370000200741e0006a41116a200241116a290000370000200741e0006a41196a200241196a290000370000200741e0006a41206a200241206a280000360000200720083a00602007200229000137006120074188066a2001200741e0006a2003200420052006108586808000200728028806210320072d008c0622044102460d0220022003360204200241003a000020040d0120074193066a200741f0036a41086a2903003700002007419b066a200741f0036a41106a290300370000200741a3066a200741f0036a41186a290300370000200741ab066a200741f0036a41206a290300370000200741b3066a20074198046a280200360000200720072903f00337008b0620002007290088063700052000410d6a20074188066a41086a290000370000200041156a20074188066a41106a2900003700002000411d6a20074188066a41186a290000370000200041256a20074188066a41206a2900003700002000412c6a200741af066a2900003700002000200a360234200041073a0004200041013602000c320b2003280208220641017622082003280204220e4b0d0c200541204b410174210b2003280200210320074188066a41286a220c410036020020074188066a200320086a2003200e6a10f58d808000200741c8046a41286a200c280200360200200741c8046a41206a20074188066a41206a290200370300200741c8046a41186a20074188066a41186a290200370300200741c8046a41106a20074188066a41106a290200370300200741c8046a41086a20074188066a41086a29020037030020072007290288063703c8042006410171210e02400240200141286a2802002203450d0020012003417f6a360228200141246a22032003280200220341016a220841002001411c6a280200220620082006491b6b360200200141206a28020020034102746a2802002208200141186a28020022034f0d0f200141146a28020020084107746a220341046a200320032d00004108461b10e3858080002003200e360234200320053600302003200436002c200320053600102003200436000c200341003a00092003200b3a0008200341053a0004200341083a0000200320072903c804370238200341c0006a200741c8046a41086a290300370200200341c8006a200741d8046a290300370200200341d0006a200741e0046a290300370200200341d8006a200741c8046a41206a290300370200200341e0006a200741f0046a2802003602000c010b0240200141186a28020022032001280210470d00200141106a2003109e86808000200128021821030b200141146a28020020034107746a2203200e360234200320053600302003200436002c200320053600102003200436000c200341003a00092003200b3a0008200341053a0004200341083a0000200320072903c804370238200341c0006a200741c8046a41086a290300370200200341c8006a200741d8046a290300370200200341d0006a200741e0046a290300370200200341d8006a200741e8046a290300370200200341e0006a200741f0046a28020036020020012001280218220841016a3602180b20022008360204200241003a00000b200741d0006a20074184046a290200370300200741d8006a2007418c046a280200360200200720072902fc033703484100210e2007280298042108200728029404210d200728029004210320072802f803210520072802f403210420072f01f203210f20072d00f103210920072d00f003210b4107210c0c2f0b2000410236020020002003360204024020072d00f00322004103460d0002400240024020000e020103000b200728029404220020002802002200417f6a36020020004101470d0220074194046a21000c010b20072802f403220020002802002200417f6a36020020004101470d01200741f0036a41047221000b200010e28a8080000b200a41002802c0a3c68000118080808000000c2f0b200741c8046a41286a200241d8006a290200370300200741c8046a41206a200241d0006a290200370300200741c8046a41186a200241c8006a290200370300200741c8046a41106a200241c0006a290200370300200741c8046a41086a220a200241386a290200370300200720022902303703c804200228022c2108200741a8026a41286a200241286a280200360200200741a8026a41206a200241206a290200370300200741a8026a41186a200241186a290200370300200741a8026a41106a200241106a290200370300200741a8026a41086a200241086a290200370300200720022902003703a802200720072802c80436028c012007200a280200200741f4046a2802002202200241284b22021b36028801200720072802cc04200741c8046a41047220021b360284010240024002400240024002400240024002400240200741086a20074184016a10db8d808000220a2007280288012202410174200728028c01220b6b220e470d00200a200728020c41017420072802106b460d010b200a200e490d012007280210200a6a220e4101762202200728020c220c4f0d02200728020820026a2d000021022003200a20032802086a41016a36020820082002410f712002410476200e4101711b41246c6a22022d0000210a200241023a0000200a4102460d0320074184026a41096a200241096a29000037000020074184026a41116a200241116a29000037000020074184026a41196a200241196a29000037000020074184026a41206a200241206a2800003600002007200a3a008402200720022900013700850220074188066a200120074184026a2003200420052006108586808000200728028806210320072d008c0622044102460d0520022003360204200241003a000020040d04200041346a20074184016a10d98d80800020002008360230200041013602002000412c6a200741d0026a280200360200200041246a200741c8026a2903003702002000411c6a200741c0026a290300370200200041146a200741b8026a2903003702002000410c6a200741b0026a290300370200200020072903a8023702040c060b20072005360298042007200436029404200720053602f803200720043602f4034100210e200741003a00f1032007200541204b410174220c3a00f003024020072d00a8024103460d00200741a8026a200741f0036a10e785808000210e0b200b410176220f20024b0d13200728028401210a20074188066a41286a220d410036020020074188066a200a200f6a200a20026a10f58d808000200741186a41286a200d280200360200200741186a41206a20074188066a41206a2202290200370300200741186a41186a20074188066a41186a2209290200370300200741186a41106a20074188066a41106a2212290200370300200741186a41086a20074188066a41086a221329020037030020072007290288063703182003280204210a2003280200210f20032802082103200728028c012114200728028801211520072f00f103211620072d00f3032117200d200741a8026a41286a2802003602002002200741a8026a41206a2903003703002009200741a8026a41186a2903003703002012200741a8026a41106a2903003703002013200741a8026a41086a290300370300200720072903a802370388062003201541017420146b6a220341017621020240024020034101710d002002200a4b0d16200741003a00dc02200720023602d8022007200f3602d4020c010b2002200a4b0d162002200a4f0d172007200f3602d402200720023602d802200741dd026a200f20026a2d000041f001713a0000200741013a00dc020b2004411076210f20044108762109200b410171210a201620174110747221022001200620074188066a200741d4026a1083868080002004210b200521012005210d0c070b200b200a41016a220d6a220c410176220e20024b0d16200728028401210320074188066a41286a2206410036020020074188066a2003200e6a200320026a10f58d80800020074190016a41286a200628020036020020074190016a41206a20074188066a41206a29020037030020074190016a41186a20074188066a41186a29020037030020074190016a41106a20074188066a41106a29020037030020074190016a41086a20074188066a41086a290200370300200741c0016a41086a200741a8026a41086a290300370300200741c0016a41106a200741a8026a41106a290300370300200741c0016a41186a200741a8026a41186a290300370300200741c0016a41206a200741a8026a41206a290300370300200741c0016a41286a200741a8026a41286a280200360200200720072902880637039001200720072903a8023703c001200728028c01200a6a220b41017622022007280288012203490d0520022003418cd5c2800010f980808000000b2002200c418cd5c2800010f980808000000b20032802082206410176220a2003280204220e4b0d15200541204b410174210b2003280200210320074188066a41286a220c410036020020074188066a2003200a6a2003200e6a10f58d808000200741f0036a41286a200c280200360200200741f0036a41206a20074188066a41206a290200370300200741f0036a41186a20074188066a41186a290200370300200741f0036a41106a20074188066a41106a290200370300200741f0036a41086a20074188066a41086a29020037030020072007290288063703f0032006410171210e02400240200141286a2802002203450d0020012003417f6a360228200141246a22032003280200220341016a220a41002001411c6a2802002206200a2006491b6b360200200141206a28020020034102746a280200220a200141186a28020022034f0d18200141146a280200200a4107746a220341046a200320032d00004108461b10e3858080002003200e360234200320053600302003200436002c200320053600102003200436000c200341003a00092003200b3a0008200341053a0004200341083a0000200320072903f003370238200341c0006a200741f0036a41086a290300370200200341c8006a20074180046a290300370200200341d0006a20074188046a290300370200200341d8006a200741f0036a41206a290300370200200341e0006a20074198046a2802003602000c010b0240200141186a28020022032001280210470d00200141106a2003109e86808000200128021821030b200141146a28020020034107746a2203200e360234200320053600302003200436002c200320053600102003200436000c200341003a00092003200b3a0008200341053a0004200341083a0000200320072903f003370238200341c0006a200741f0036a41086a290300370200200341c8006a20074180046a290300370200200341d0006a20074188046a290300370200200341d8006a20074190046a290300370200200341e0006a20074198046a28020036020020012001280218220a41016a3602180b2002200a360204200241003a00000b200728028c01220a410176220320072802880122044b0d1620072802840121024100210e20074188066a41286a2205410036020020074188066a200220036a200220046a10f58d808000200741186a41286a2005280200360200200741186a41206a20074188066a41206a290200370300200741186a41186a20074188066a41186a290200370300200741186a41106a20074188066a41106a290200370300200741186a41086a20074188066a41086a290200370300200720072902880637031820072d00a802210c20072d00ac02210b20072d00ad02210920072f01ae02210f20072802b002210120072802b402210520072f00a902210220072d00ab022103200741c8006a41106a200741a8026a41206a280200360200200741c8006a41086a200741a8026a41186a290300370300200720072903b802370348200a410171210a2002200341107472210220072802d002210d20072802cc0221040c030b2000410236020020002003360204200741a8026a10e585808000200841002802c0a3c68000118080808000000b20072802f4044129490d3020072802cc0441002802c0a3c68000118080808000000c300b20072802840120026a2d0000210e41002d00fca3c680001a41c00441002802c8a3c68000118180808000002203450d14200c410171210c200341023a009c04200341023a00f803200341023a00d403200341023a00b003200341023a008c03200341023a00e802200341023a00c402200341023a00a002200341023a00fc01200341023a00d801200341023a00b401200341023a009001200341023a006c200341023a0048200341023a0024200341023a0000200741b3066a200741c0016a41286a280200360000200741ab066a200741c0016a41206a290300370000200741a3066a200741c0016a41186a2903003700002007419b066a200741c0016a41106a29030037000020074193066a200741c8016a290300370000200720072903c00137008b06200141106a210f02400240200141286a2802002202450d0020012002417f6a360228200141246a22022002280200220241016a22064100200128021c220920062009491b6b360200200141206a28020020024102746a2802002206200141186a220928020022024f0d17200141146a28020020064107746a220241046a200220022d00004108461b10e385808000200241083a00002002200c360234200220083602302002200729008806370001200241096a20074188066a41086a290000370000200241116a20074188066a41106a290000370000200241196a20074188066a41186a290000370000200241216a20074188066a41206a290000370000200241286a200741af066a2900003700002002200729039001370238200241c0006a20074190016a41086a290300370200200241c8006a20074190016a41106a290300370200200241d0006a20074190016a41186a290300370200200241d8006a20074190016a41206a290300370200200241e0006a20074190016a41286a2802003602000c010b0240200141186a220928020022022001280210470d00200f2002109e86808000200928020021020b200141146a28020020024107746a220241083a000020022007290088063700012002200c360234200220083602302002200729039001370238200241096a20074188066a41086a290000370000200241116a20074188066a41106a290000370000200241196a20074188066a41186a290000370000200241216a20074188066a41206a290000370000200241286a200741af066a290000370000200241c0006a20074190016a41086a290300370200200241c8006a20074190016a41106a290300370200200241d0006a20074190016a41186a290300370200200241d8006a20074190016a41206a290300370200200241e0006a20074190016a41286a28020036020020012001280218220641016a3602180b2003200e410f71200e410476200b4101711b41246c6a2208200636020441002102200841003a0000200541204b410174210c0240200728020c220841017420072802102206200a6a220e470d0020074188066a20074184016a200a10da8d808000200741c8006a41106a200741f0016a41106a280200360200200741c8006a41086a200741f0016a41086a290200370300200741186a41086a20074194066a290200370300200741186a41106a2007419c066a290200370300200741306a200741a4066a290200370300200741186a41206a20074188066a41246a290200370300200741c0006a200741b4066a280200360200200720072902f0013703482007200729028c063703182004411076210f20044108762109200728028806210a2004210b200521012005210d200321084100210e0c010b200e410176220b20084f0d182006200d6a2212410176220d20084b0d1620072802082202200b6a2d0000210620074188066a41286a220b410036020020074188066a2002200d6a200220086a10f58d808000200741f0036a41286a200b280200360200200741f0036a41206a20074188066a41206a290200370300200741f0036a41186a20074188066a41186a290200370300200741f0036a41106a20074188066a41106a290200370300200741f0036a41086a20074188066a41086a29020037030020072007290288063703f0032012410171210b0240024020012802282202450d0020012002417f6a360228200141246a22022002280200220241016a22084100200128021c220d2008200d491b6b360200200141206a28020020024102746a2802002208200128021822024f0d19200141146a28020020084107746a220241046a200220022d00004108461b10e3858080002002410b6a41003a0000200241003b0009200220053602102002200436020c2002200c3a0008200241053a0004200241083a00002002200b360234200220053602302002200436022c200220072902f001370218200241206a200741f0016a41086a290200370200200241286a200741f0016a41106a280200360200200220072903f003370238200241c0006a200741f0036a41086a290300370200200241c8006a200741f0036a41106a290300370200200241d0006a20074188046a290300370200200241d8006a200741f0036a41206a290300370200200241e0006a200741f0036a41286a2802003602000c010b024020092802002202200f280200470d00200f2002109e86808000200928020021020b200141146a28020020024107746a220241003b0009200220053602102002200436020c2002200c3a0008200241053a0004200241083a0000200220072902f0013702182002200b360234200220053602302002200436022c200220072903f0033702382002410b6a41003a0000200241206a200741f0016a41086a290200370200200241286a200741f0016a41106a280200360200200241c0006a200741f0036a41086a290300370200200241c8006a200741f0036a41106a290300370200200241d0006a20074188046a290300370200200241d8006a200741f0036a41206a290300370200200241e0006a200741f0036a41286a28020036020020012001280218220841016a3602180b20032006410f712006410476200e4101711b41246c6a220220083602044100210e200241003a000020074188066a20074184016a200a10da8d808000200741206a20074194066a290200370300200741286a2007419c066a290200370300200741306a200741a4066a290200370300200741386a20074188066a41246a290200370300200741c0006a200741b4066a2802003602002007200729028c06370318200728028806210a4103210c200321080b024020072802f4044129490d0020072802cc0441002802c0a3c68000118080808000000b20042103200121040c2d0b2003200141e491c68000109481808000000b410441c00410b280808000000b2008200c418cd5c2800010f980808000000b200d200b41e491c68000109481808000000b200d200241d4d7c2800010f980808000000b200e200c41e491c68000109481808000000b2004200241d4d7c2800010f980808000000b2005200141e491c68000109481808000000b2002200e418cd5c2800010f980808000000b2008200e41e491c68000109481808000000b2008200341d4d7c2800010f980808000000b200f200241e491c68000109481808000000b2002200a41f492c68000109581808000000b2002200a418493c68000109581808000000b2002200a419493c6800010f980808000000b200e200241e491c68000109481808000000b200a200e41e491c68000109481808000000b200a200341d4d7c2800010f980808000000b2003200441e491c68000109481808000000b410441c00410b280808000000b2006200241d4d7c2800010f980808000000b200d200841e491c68000109481808000000b2008200241d4d7c2800010f980808000000b200b2008418cd5c2800010f980808000000b200720053602b006200720043602ac0620072005360290062007200436028c064100210e200741003a0089062007200541204b410174220b3a008806024020072d00f0034103460d00200741f0036a20074188066a10e785808000210e0b2003280208220c410176210802400240024002400240200c4101710d0020082003280204220c4b0d02200741003a00d004200720083602cc04200720032802003602c8040c010b20082003280204220c4b0d022008200c4f0d032007200328020022033602c804200720083602cc04200741d1046a200320086a2d000041f001713a0000200741013a00d0040b20012006200241046a200741c8046a108386808000410021094107210c2004210d200521080c170b2008200c41f492c68000109581808000000b2008200c418493c68000109581808000000b2008200c419493c6800010f980808000000b200728028c0621040b2000410236020020002004360204200728029c044129490d1320072802f40341002802c0a3c68000118080808000000c130b4100210e0b200728029c044129490d1020072802f40341002802c0a3c68000118080808000000c100b419cd5c28000412a41c8d5c2800010f880808000000b200a200728020c41017420072802106b470d0002400240200541204b0d00200720043602cc04200741d0046a21024100210b0c010b200720043602ec04200741003a00c904200741f0046a21024102210b2004210d0b200220053602002007200b3a00c804200741a8026a200741c8046a10e785808000210e2003280208200a6a220a4101762102200328020421052003280200210302400240200a4101710d00200220054b0d05200741003a0090062007200236028c0620072003360288060c010b200220054b0d05200220054f0d0620072003360288062007200236028c0620074191066a200320026a2d000041f001713a0000200741013a0090060b20012006200820074188066a108386808000200741d4046a2102200e0d0120072802f003210a20072802f403210520072802f8032101200728029c0421034100210e20074188066a41286a2208410036020020074188066a2005200f200341284b22061b220520052001200320061b6a10f686808000200741186a41286a2008280200360200200741186a41206a20074188066a41206a290200370300200741186a41186a20074188066a41186a290200370300200741186a41106a20074188066a41106a290200370300200741186a41086a20074188066a41086a29020037030020072007290288063703180c020b200a2002490d07200c410176220a200e4b0d0520072802d402210220074188066a41286a220b410036020020074188066a2002200a6a2002200e6a10f58d808000200741c8046a41286a220a200b280200360200200741c8046a41206a220e20074188066a41206a290200370300200741c8046a41186a220b20074188066a41186a290200370300200741c8046a41106a220d20074188066a41106a290200370300200741c8046a41086a220f20074188066a41086a29020037030020072007290288063703c80441002d00fca3c680001a41c00441002802c8a3c68000118180808000002202450d06200241023a009c04200241023a00f803200241023a00d403200241023a00b003200241023a008c03200241023a00e802200241023a00c402200241023a00a002200241023a00fc01200241023a00d801200241023a00b401200241023a009001200241023a006c200241023a0048200241023a0024200241023a000020074190036a41086a200841086a29020037030020074190036a41106a200841106a29020037030020074190036a41186a200841186a29020037030020074190036a41206a200841206a29020037030020074190036a41286a200841286a2802003602002007200829020037039003200741c4036a20072903c804370200200741cc036a200f290300370200200741d4036a200d290300370200200741dc036a200b290300370200200741e4036a200e290300370200200741ec036a200a2802003602002007200c4101713602c003200720023602bc0320074188066a200120074190036a20032004200520061084868080002007280288064102460d08200741c8006a41086a200741a4066a290200370300200741c8006a41106a200741ac066a280200360200200741c0006a200741e8066a280200360200200741386a200741e0066a290200370300200741306a200741d8066a290200370300200741186a41106a200741d0066a290200370300200741186a41086a200741c8066a2902003703002007200729029c06370348200720072902c006370318200728028c06220c41087621022007280298062105200728029406210420072f019206210f20072d009106210920072d009006210b20072802b006210320072802b406210d20072802b806210820072802bc06210a4100210e0c0c0b20072802f003210a20072802f403210520072802f8032101200728029c04210320074188066a41286a2208410036020020074188066a2005200f200341284b220e1b2205200520012003200e1b6a10f686808000200741186a41286a2008280200360200200741186a41206a20074188066a41206a290200370300200741186a41186a20074188066a41186a290200370300200741186a41106a20074188066a41106a290200370300200741186a41086a20074188066a41086a29020037030020072007290288063703184101210e0b200741c8006a41086a200241086a290200370300200741c8006a41106a200241106a2802003602002007200229020037034820072802d004210520072802f00421084105210c410021090c0a0b2002200541f492c68000109581808000000b20022005418493c68000109581808000000b20022005419493c6800010f980808000000b200a200e41e491c68000109481808000000b410441c00410b280808000000b41002d00fca3c680001a41c00441002802c8a3c68000118180808000002202450d01200241023a0000200241023a009c04200241023a00f803200241023a00d403200241023a00b003200241023a008c03200241023a00e802200241023a00c402200241023a00a002200241023a00fc01200241023a00d801200241023a00b401200241023a009001200241023a006c200241023a0048200241023a0024024020072802dc02200a6a220c410176220d20072802d802220e490d00200d200e418cd5c2800010f980808000000b200c41016a2209410176220f200e4b0d0220072802d402220b200d6a2d0000210d20074188066a41286a2212410036020020074188066a200b200f6a200b200e6a10f58d808000200741c8046a41286a2012280200360200200741c8046a41206a20074188066a41206a290200370300200741c8046a41186a20074188066a41186a290200370300200741c8046a41106a20074188066a41106a290200370300200741c8046a41086a20074188066a41086a29020037030020072007290288063703c804200741ec026a200841086a290000370000200741f4026a200841106a290000370000200741fc026a200841186a29000037000020074184036a200841206a2900003700002007418c036a200841286a280000360000200720082900003700e4022009410171210b02400240200141286a2802002208450d0020012008417f6a360228200141246a22082008280200220841016a220e41002001411c6a280200220f200e200f491b6b360200200141206a28020020084102746a280200220e200141186a28020022084f0d05200141146a280200200e4107746a220841046a200820082d00004108461b10e385808000200841053a0004200841083a00002008200b360234200820072900e1023700052008410d6a200741e1026a41086a290000370000200841156a200741e1026a41106a2900003700002008411d6a200741e1026a41186a290000370000200841256a200741e1026a41206a2900003700002008412c6a20074188036a290000370000200820072903c804370238200841c0006a200741c8046a41086a290300370200200841c8006a200741c8046a41106a290300370200200841d0006a200741c8046a41186a290300370200200841d8006a200741c8046a41206a290300370200200841e0006a200741f0046a2802003602000c010b0240200141186a28020022082001280210470d00200141106a2008109e86808000200128021821080b200141146a28020020084107746a220841053a0004200841083a0000200820072900e1023700052008200b360234200820072903c8043702382008410d6a200741e1026a41086a290000370000200841156a200741e1026a41106a2900003700002008411d6a200741e1026a41186a290000370000200841256a200741e1026a41206a2900003700002008412c6a20074188036a290000370000200841c0006a200741c8046a41086a290300370200200841c8006a200741c8046a41106a290300370200200841d0006a200741c8046a41186a290300370200200841d8006a200741c8046a41206a290300370200200841e0006a200741f0046a28020036020020012001280218220e41016a3602180b2002200d410f71200d410476200c4101711b41246c6a2208200e3602044100210e200841003a0000200741f8046a200741086a200a10da8d808000200720023602f404200741033a00c80420074188066a2001200741c8046a20032004200520061084868080002007280288064102460d00200741c8006a41086a200741a4066a290200370300200741c8006a41106a20074188066a41246a280200360200200741c0006a200741e8066a280200360200200741386a200741e0066a290200370300200741306a200741d8066a290200370300200741186a41106a200741d0066a290200370300200741186a41086a200741c8066a2902003703002007200729029c06370348200720072902c006370318200728028c06220c41087621022007280298062105200728029406210420072f019206210f20072d009106210920072d009006210b20072802b006210320072802b406210d20072802b806210820072802bc06210a0c040b200728028c0621022000410236020020002002360204200728029c044129490d0520072802f40341002802c0a3c68000118080808000000c050b410441c00410b280808000000b200f200e41e491c68000109481808000000b200e200841d4d7c2800010f980808000000b200728029c044129490d0020072802f40341002802c0a3c68000118080808000000b200020023b0005200020053602102000200436020c2000200f3b010a200020093a00092000200b3a00082000200c3a00042000200e360200200020072903483702142000200a360234200020083602302000200d36022c20002003360228200041076a20024110763a00002000411c6a200741c8006a41086a290300370200200041246a200741c8006a41106a280200360200200041e0006a200741c0006a280200360200200041d8006a200741386a290300370200200041d0006a200741306a290300370200200041c8006a200741186a41106a290300370200200041c0006a200741186a41086a290300370200200020072903183702380b200741f0066a2480808080000bb11503057f017e157f23808080800041b0036b22072480808080002007200536020420072004360200024002400240024002400240024002400240024002400240024020022d00000d00200228020421020c010b200741206a200241196a290000370300200741186a200241116a290000370300200741106a200241096a290000370300200720022900013703082003280208220541017621020240024020054101710d002002200328020422054b0d05200741003a00ec01200720023602e801200720032802003602e4010c010b2002200328020422054b0d05200220054f0d062007200328020022053602e401200720023602e801200741ed016a200520026a2d000041f001713a0000200741013a00ec010b200741cc026a2001200741086a200741e4016a10868680800020072802d002210220072802cc020d010b0240200141286a28020022052001411c6a22082802002204470d00200810a889808000200128021c2104200128022821050b200141206a280200200141246a28020020056a22054100200420052004491b6b4102746a20023602002001200128022841016a360228200141186a280200220420024d0d05200141146a28020020024107746a22022d00002104200741296a200241016a41df0010848e8080001a200241043a0004200241083a0000200228026021092007280200210520072802042108024020044108470d00200741e4016a2007412c6a41dc0010848e8080001a200720033602c802200720093602c002200720013602c402200741cc026a2001200741e4016a200320052008200610848680800020072802cc0222034102460d022003410147210a20072802ac03210b20072902a403210c20072802a0032104200728029c03210520072802980321062007280294032108200728029003210d200728028c03210e200728028803210f2007280284032110200728028003211120072802fc02211220072802f802211320072802f402211420072802f002211520072802ec02211620072802e802211720072802e402211820072802e002211920072802dc02211a20072802d802211b20072802d402211c20072802d0022102410821034100211d0c090b2003280208211d2003280204210b2003280200210a200741e4016a410172200741296a41df0010848e8080001a200741e0016a200241fc006a280000360200200741d8016a200241f4006a290000370300200741c8016a41086a200241ec006a290000370300200720013602c402200720033602c802200720043a00e401200720022900643703c801200741cc026a2001200741e4016a200320052008200610848680800020072802cc0222034102460d0120072902a803210c20072802a403211e20072802a0032104200728029c03210520072802980321062007280294032108200728029003210d200728028c03210e200728028803210f2007280284032110200728028003211120072802fc02211220072802f802211320072802f402211420072802f002211520072802ec02211620072802e802211720072802e402211820072802e002211a20072802dc02211b20072802d802211c20072802d402211f20072802d0022102024020034101460d00201d410176210302400240201d4101710d0002402003200b4b0d00410021190c020b2003200b41f492c68000109581808000000b2003200b4b0d082003200b4f0d09200a20036a2d00004170712120410121190b200c422088a7210b4100211d200741cc026a41286a22214100360200200741cc026a200a200a20036a10f58d80800020074184026a220a41286a2021280200360200200a41206a200741cc026a41206a290200370200200a41186a200741cc026a41186a290200370200200a41106a200741cc026a41106a29020037020041082103200a41086a200741cc026a41086a290200370200200a20072902cc02370200200741b1026a20203a0000200741b0026a20193a0000200741f0016a200741c8016a41086a290300370200200741f8016a200741c8016a41106a29030037020020074180026a200741c8016a41186a280200360200200720093602e401200720072903c8013702e801200141dc006a200741e4016a10958d8080001a200c422086201ead84210c4101210a201a2119201b211a201c211b201f211c0c090b200741a8016a41186a200741c8016a41186a280200360200200741a8016a41106a200741c8016a41106a290300370300200741a8016a41086a200741c8016a41086a290300370300200720072903c8013703a801200241ff01712103200241807e71211d4100210a201821192017211820162117201521162014211520132114201221132011211220102111200f2110200e210f200d210e2008210d200621082005210620042105201e21042009210b201f21020c080b200041023a000420002002360200200420042802002201417f6a36020020014101470d08200710e28a8080000c080b20072802d0022101200041023a0004200020013602000c070b2002200541f492c68000109581808000000b20022005418493c68000109581808000000b20022005419493c6800010f980808000000b2002200441e4d7c2800010f980808000000b2003200b418493c68000109581808000000b2003200b419493c6800010f980808000000b20074188016a41186a200741a8016a41186a28020036020020074188016a41106a200741a8016a41106a29030037030020074188016a41086a200741a8016a41086a290300370300200720072903a801370388012003201d7221090240024020012802282203450d0020012003417f6a36022820012001280224220341016a221d4100200128021c221e201d201e491b6b360224200128022020034102746a28020022032001280218221d4f0d03200128021420034107746a220141046a200120012d00004108461b10e3858080002001200b3602602001200c37025820012004360254200120053602502001200636024c200120083602482001200d3602442001200e3602402001200f36023c2001201036023820012011360234200120123602302001201336022c2001201436022820012015360224200120163602202001201736021c20012018360218200120193602142001201a3602102001201b36020c2001201c3602082001200236020420012009360200200141fc006a200741a0016a280200360200200141f4006a20074198016a290300370200200141ec006a20074188016a41086a29030037020020012007290388013702640c010b0240200128021822032001280210470d00200141106a2003109e86808000200128021821030b200128021420034107746a2203200b3602602003200c37025820032004360254200320053602502003200636024c200320083602482003200d3602442003200e3602402003200f36023c2003201036023820032011360234200320123602302003201336022c2003201436022820032015360224200320163602202003201736021c20032018360218200320193602142003201a3602102003201b36020c2003201c3602082003200236020420032009360200200341fc006a200741a0016a280200360200200341f4006a20074198016a290300370200200341ec006a20074190016a290300370200200320072903880137026420012001280218220341016a3602180b2000200a3a0004200020033602000b200741b0036a2480808080000f0b2003201d41d4d7c2800010f980808000000bc90a01057f2380808080004180026b2204248080808000024002400240024002400240024002400240024020012802682205450d0020052002200141ec006a2802002802181183808080000022050d010b200441e0006a200128025020022003200141d4006a280200280214118680808000000240024020042802602203418080808078470d0020044180016a41186a2205200241186a29000037030020044180016a41106a2203200241106a29000037030020044180016a41086a2206200241086a290000370300200420022900003703800141002d00fca3c680001a413041002802c8a3c680001181808080000022010d014104413010b280808000000b20042802682106200428026421052001280200450d032001280204450d0241d8d5c28000108781808000000b200141858080807836020020012004290380013702042001410c6a2006290300370200200141146a20032903003702002001411c6a200529030037020020004101360200200020013602040c070b02402001280200450d0002402001280204450d0041e8d5c28000108781808000000b2001417f360204200141086a28020021032001410c6a2802002106200441a0016a200241186a29000037020020044180016a41186a200241106a29000037020020044180016a41106a200241086a29000037020020042005360284012004418180808078360280012004200229000037028801200320044180016a200628020c11848080800000200141003602040b20042005200141106a10f2858080000c020b2001417f360204200141086a28020021072001410c6a280200210820044180016a410c6a200636020020044180016a41086a2005360200200441a8016a200241186a290000370200200441a0016a200241106a29000037020020044180016a41186a200241086a2900003702002004428280808088808080807f370280012004200229000037029001200720044180016a200828020c11848080800000200141003602040b200441e0006a41186a200241186a290000370300200441e0006a41106a200241106a290000370300200441e0006a41086a200241086a2900003703002004200229000037036020044180016a200441e0006a20052006200141106a10e88580800020042d00800122064108460d01200420042d0083013a0003200420042f0081013b00012004280284012107200441086a20044180016a41086a41d80010848e8080001a20042007360204200420063a00002003450d00200541002802c0a3c68000118080808000000b20044180016a200441e00010848e8080001a200441f8016a200241186a290000370200200441f0016a200241106a290000370200200441e8016a200241086a290000370200200420022900003702e001200141286a2802002202450d0120012002417f6a360228200141246a22022002280200220241016a220541002001411c6a280200220320052003491b6b360200200141206a28020020024102746a2802002202200141186a28020022054f0d04200141146a28020020024107746a220141046a200120012d00004108461b10e385808000200120044180016a41800110848e8080001a0c020b200428028401210120004101360200200020013602042003450d02200541002802c0a3c68000118080808000000c020b0240200141186a28020022022001280210470d00200141106a2002109e86808000200128021821020b200141146a28020020024107746a20044180016a41800110848e8080001a20012001280218220241016a3602180b20004100360200200020023602040b20044180026a2480808080000f0b2002200541d4d7c2800010f980808000000bc90a01057f2380808080004180026b2204248080808000024002400240024002400240024002400240024020012802682205450d0020052002200141ec006a2802002802181183808080000022050d010b200441e0006a200128025020022003200141d4006a280200280214118680808000000240024020042802602203418080808078470d0020044180016a41186a2205200241186a29000037030020044180016a41106a2203200241106a29000037030020044180016a41086a2206200241086a290000370300200420022900003703800141002d00fca3c680001a413041002802c8a3c680001181808080000022010d014104413010b280808000000b20042802682106200428026421052001280200450d032001280204450d0241d8d5c28000108781808000000b200141858080807836020020012004290380013702042001410c6a2006290300370200200141146a20032903003702002001411c6a200529030037020020004101360200200020013602040c070b02402001280200450d0002402001280204450d0041e8d5c28000108781808000000b2001417f360204200141086a28020021032001410c6a2802002106200441a0016a200241186a29000037020020044180016a41186a200241106a29000037020020044180016a41106a200241086a29000037020020042005360284012004418180808078360280012004200229000037028801200320044180016a200628020c11848080800000200141003602040b20042005200141106a10f0858080000c020b2001417f360204200141086a28020021072001410c6a280200210820044180016a410c6a200636020020044180016a41086a2005360200200441a8016a200241186a290000370200200441a0016a200241106a29000037020020044180016a41186a200241086a2900003702002004428280808088808080807f370280012004200229000037029001200720044180016a200828020c11848080800000200141003602040b200441e0006a41186a200241186a290000370300200441e0006a41106a200241106a290000370300200441e0006a41086a200241086a2900003703002004200229000037036020044180016a200441e0006a20052006200141106a10ec8580800020042d00800122064108460d01200420042d0083013a0003200420042f0081013b00012004280284012107200441086a20044180016a41086a41d80010848e8080001a20042007360204200420063a00002003450d00200541002802c0a3c68000118080808000000b20044180016a200441e00010848e8080001a200441f8016a200241186a290000370200200441f0016a200241106a290000370200200441e8016a200241086a290000370200200420022900003702e001200141286a2802002202450d0120012002417f6a360228200141246a22022002280200220241016a220541002001411c6a280200220320052003491b6b360200200141206a28020020024102746a2802002202200141186a28020022054f0d04200141146a28020020024107746a220141046a200120012d00004108461b10e385808000200120044180016a41800110848e8080001a0c020b200428028401210120004101360200200020013602042003450d02200541002802c0a3c68000118080808000000c020b0240200141186a28020022022001280210470d00200141106a2002109e86808000200128021821020b200141146a28020020024107746a20044180016a41800110848e8080001a20012001280218220241016a3602180b20004100360200200020023602040b20044180026a2480808080000f0b2002200541d4d7c2800010f980808000000b99950105107f017e017f047e397f23808080800041c0086b2205248080808000024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024020022d00002206417c6a41ff01712207410420074104491b417e6a0e03020108000b2000200241e00010848e8080001a0c200b200241056a210820022d000421092002280230220a2d00004102460d0141002106410121070c020b200541c8036a41286a200241d0006a290200370300200541e8036a200241c8006a290200370300200541c8036a41186a200241c0006a290200370300200541c8036a41106a200241386a290200370300200541c8036a41086a2207200241306a290200370300200520022902283703c803200541fe036a200241076a2d00003a000020054198016a41086a200241146a29020037030020054198016a41106a2002411c6a29020037030020054198016a41186a200241246a2802003602002005200241056a2f00003b01fc0320052002410c6a29020037039801200241086a280200210b20022d000421062003280200210a2003280204210820032802082109024002400240024002400240024002400240024020040d002007280200200541f4036a2802002204200441284b1b2207417f6a210c2007450d11200741017420096a20052802c803417f736a2209410176210720052802cc03200541c8036a410472200441284b1b200c6a2d0000410f71210c024020094101710d00200720084d0d022007200841f492c68000109581808000000b200720084b0d1220072008490d0220072008419493c6800010f980808000000b2009410176210702400240200941017122040d00200720084d0d012007200841f492c68000109581808000000b200720084b0d13200720084f0d14200a20076a2d000041707121090b2005420037028002200541003602d804200520073602d4042005200a3602d004200541d8016a200541d0046a4100200510e38d8080001a2004450d06200941f00171210820052d0084024101710d04200541d8016a41046a2104200541d8016a41044128200528028002220d41284b22091b6a280200220c200d412820091b460d022004200541d8016a41286a20091b210420052802d801200541d8016a20091b21090c030b410021042005410036028004200c410474210e20054180046a41046a210f410121080c070b200a20076a22042d0000210941002108200541d8016a41286a220d4100360200200541d8016a200a200410f686808000200541d0046a41286a2210200d280200220d360200200541d0046a41206a2211200541d8016a41206a290200370300200541d0046a41186a2212200541d8016a41186a290200370300200541d0046a41106a2213200541d8016a41106a290200370300200541d0046a41086a2214200541d8016a41086a290200370300200520052902d80122153703d004200541d0046a41047221042009417071200c72211602400240200541d0046a41044128200d41284b22091b6a280200220c200d412820091b460d002004201020091b21042015a7200541d0046a20091b21090c010b200541d0046a10f88680800020052802d404210c20052802d00421090b2009200c6a20163a00002004200428020041016a360200200541b0066a41086a20142903002215370300200541b0066a41106a20132903002217370300200541b0066a41186a20122903002218370300200541b0066a41206a20112903002219370300200541b0066a41286a20102802002204360200200520052903d004221a3703b0062005418c046a201537020020054194046a20173702002005419c046a2018370200200541a4046a2019370200200541ac046a200436020020054101360280042005201a3702840420054180046a41046a210f0c050b200541d8016a10f78d80800020052802dc01210c20052802d80121090b2009200c6a20083a00002004200428020041016a3602000c010b20052802dc012005280280022204200441284b22041b2209450d0f200920052802d801200541d8016a20041b6a417f6a220420042d00002008410476723a00000b200520052802840241016a360284020b200520052802c8033602d8042005200541d0036a280200200541f4036a2802002204200441284b22041b3602d404200520052802cc03200541c8036a41047220041b3602d004200541d8016a200541d0046a4100200510e38d8080001a200528028402220841017621040240024020084101710d0020052802dc012005280280022209200941284b22091b220c2004490d1020052802d801200541d8016a20091b21090c010b20052802dc012005280280022209200941284b1b220c2004490d10200c20044d0d1120052802d801200541d8016a200941284b1b220920046a2d0000417071210e0b200541d0046a41286a220c4100360200200541d0046a2009200920046a10f686808000200541b0066a41286a2204200c280200360200200541b0066a41206a2209200541d0046a41206a290200370300200541b0066a41186a220c200541d0046a41186a290200370300200541b0066a41106a220d200541d0046a41106a290200370300200541b0066a41086a2210200541d0046a41086a290200370300200520052902d0043703b00602402005280280024129490d0020052802d80141002802c0a3c68000118080808000000b2005418c046a201029030037020020054194046a200d2903003702002005419c046a200c290300370200200541a4046a2009290300370200200541ac046a20042802003602002005410136028004200520052903b0063702840420054184046a210f0b20052802880420052802ac042204200441284b22041b2109200528028404200f20041b21040b2009200720041b211b2008410171211c2004200a20041b211d024020064101710d000240200141286a28020022042001411c6a220a2802002207470d00200a10a889808000200128021c2107200128022821040b200141206a280200200141246a28020020046a22044100200720042007491b6b4102746a200b3602002001200128022841016a360228200141186a2802002207200b4b0d1c200b200741e4d7c2800010f980808000000b200541b0046a41026a200541fc036a41026a2d00003a0000200541bf046a20054198016a41086a290300370000200541c7046a200541a8016a290300370000200541cf046a200541b0016a2d00003a0000200520052f01fc033b01b0042005200b3600b30420052005290398013700b7042005200e3a00e1012005201c3a00e0012005201b3602dc012005201d3602d801200541d0046a2001200541b0046a200541d8016a10878680800020052802d404210b20052802d004450d1a200041083a00002000200b3602040240200528028004450d00200f2802284129490d0020052802840441002802c0a3c68000118080808000000b200541f4036a2802004129490d0620052802cc0341002802c0a3c68000118080808000000c060b4101210641022107200a2d00244102470d004102210641032107200a2d00484102470d000240200a2d006c4102460d0041032106410421070c010b0240200a2d0090014102460d0041042106410521070c010b0240200a2d00b4014102460d0041052106410621070c010b0240200a2d00d8014102460d0041062106410721070c010b0240200a2d00fc014102460d0041072106410821070c010b0240200a2d00a0024102460d0041082106410921070c010b0240200a2d00c4024102460d0041092106410a21070c010b0240200a2d00e8024102460d00410a2106410b21070c010b0240200a2d008c034102460d00410b2106410c21070c010b0240200a2d00b0034102460d00410c2106410d21070c010b0240200a2d00d4034102460d00410d2106410e21070c010b0240200a2d00f8034102460d00410e2106410f21070c010b200a2d009c044102460d01410f2106411021070b200741246c21070340200741246a220441e404460d02200a20076a210b20042107200b2d00004102460d000c180b0b200941ff01714103460d15200020082900003700052000412c6a200841276a280000360000200041256a200841206a2900003700002000411d6a200841186a290000370000200041156a200841106a2900003700002000410d6a200841086a290000370000200542003702dc01200541a0d1c280003602d801200041306a200541d8016a10d98d808000200020093a0004200041053a00000c010b200941ff01714103470d15200520063a00d004200541d8016a41286a22074100360200200541d8016a200541d0046a200541d0046a41016a10f58d808000200541086a41286a220b2007280200360200200541086a41206a2208200541d8016a41206a290200370300200541086a41186a2209200541d8016a41186a290200370300200541086a41106a220c200541d8016a41106a290200370300200541086a41086a220d200541d8016a41086a290200370300200520052902d801370308200a200641246c6a22072d00002104200741023a000020044102460d0b2005413d6a2007290001370000200541e4006a2005290308370200200541386a41246a200741206a280000360000200541d5006a200741196a290000370000200541cd006a200741116a290000370000200541c5006a200741096a290000370000200541ec006a200d290300370200200541f4006a200c290300370200200541fc006a200929030037020020054184016a20082903003702002005418c016a200b28020036020020054101360260200541063a0038200520043a003c20002001200541386a200341001088868080000b200a41002802c0a3c68000118080808000000c170b200541a0016a200241c4006a290200370300200541a8016a200241cc006a290200370300200541b0016a200241d4006a29020037030020052002413c6a2902003703980141012107200241016a2108200241306a2109200241dc006a2802002110200241386a2802002111200241346a2802002113200228023021124100210c024002400240200228022c220a2d0000220d4102470d004101210c41022107200a2d0024220d4102470d004102210c41032107200a2d0048220d4102470d000240200a2d006c220d4102460d004103210c410421070c010b0240200a2d009001220d4102460d004104210c410521070c010b0240200a2d00b401220d4102460d004105210c410621070c010b0240200a2d00d801220d4102460d004106210c410721070c010b0240200a2d00fc01220d4102460d004107210c410821070c010b0240200a2d00a002220d4102460d004108210c410921070c010b0240200a2d00c402220d4102460d004109210c410a21070c010b0240200a2d00e802220d4102460d00410a210c410b21070c010b0240200a2d008c03220d4102460d00410b210c410c21070c010b0240200a2d00b003220d4102460d00410c210c410d21070c010b0240200a2d00d403220d4102460d00410d210c410e21070c010b0240200a2d00f803220d4102460d00410e210c410f21070c010b200a2d009c04220d4102460d01410f210c411021070b200741246c21070340200741246a220441e404460d02200a20076a210b20042107200b2d00004102460d000c140b0b200641ff01714103460d1120002008290000370005200020092902003702302000412c6a200841276a280000360000200041256a200841206a2900003700002000411d6a200841186a290000370000200041156a200841106a2900003700002000410d6a200841086a290000370000200041386a200941086a290200370200200041c0006a200941106a290200370200200041c8006a200941186a290200370200200041d0006a200941206a290200370200200041d8006a200941286a290200370200200020063a0004200041053a00000c100b200641ff01714103470d11200a200c41246c6a220741023a0000200d4102460d0a2007280204210b200541bc086a41026a200741036a2d00003a0000200541c0016a200741106a290200370300200541b8016a41106a200741186a290200370300200541b8016a41186a200741206a280200360200200520072f00013b01bc08200520072902083703b801200328020820112010201041284b1b41017420126b6a220841017621072003280204210420032802002103024002400240024020084101710d00200720044d0d012007200441f492c68000109581808000000b200720044b0d0e20072004490d0120072004419493c6800010f980808000000b410021042005410036028004200c4104742109410121060c010b200320076a22042d0000210841002106200541d8016a41286a22094100360200200541d8016a2003200410f686808000200541d0046a41286a221420092802002209360200200541d0046a41206a221e200541d8016a41206a290200370300200541d0046a41186a221f200541d8016a41186a290200370300200541d0046a41106a2220200541d8016a41106a290200370300200541d0046a41086a2221200541d8016a41086a290200370300200520052902d80122153703d004200541d0046a41047221042008417071200c72212202400240200541d0046a41044128200941284b22081b6a28020022162009412820081b460d002004201420081b21042015a7200541d0046a20081b21080c010b200541d0046a10f88680800020052802d404211620052802d00421080b200820166a20223a00002004200428020041016a360200200541ac046a20142802002208360200200541a4046a201e2903003702002005419c046a201f29030037020020054194046a20202903003702002005418c046a2021290300370200200520052903d00422153702840420054101360280042015a720054180046a41046a200841284b22091b2104200528028804200820091b21080b2008200720041b21082004200320041b21070240200d4101710d000240200141286a28020022032001411c6a220d2802002204470d00200d10a889808000200128021c2104200128022821030b200141206a280200200141246a28020020036a22034100200420032004491b6b4102746a200b3602002001200128022841016a360228200141186a2802002204200b4d0d0d200541d8016a200141146a280200200b4107746a220441800110848e8080001a200441043a0004200441083a00000c0f0b200541d8026a41026a200541bc086a41026a2d00003a0000200541e7026a200541b8016a41086a290300370000200541ef026a200541b8016a41106a290300370000200541f7026a200541d0016a2d00003a0000200520052f01bc083b01d8022005200b3600db02200520052903b8013700df02200520093a00d904200520063a00d804200520083602d404200520073602d004200541b0066a2001200541d8026a200541d0046a10878680800020052802b406210420052802b006450d0d200041083a0000200020043602040240200528028004450d0020052802ac044129490d0020052802840441002802c0a3c68000118080808000000b200a41002802c0a3c680001180808080000020104129490d00201341002802c0a3c68000118080808000000b20022d0000417c6a41ff01712207410420074104491b417e6a4103490d170c160b200c200741f8d5c2800010f980808000000b20072008418493c68000109581808000000b20072008418493c68000109581808000000b20072008419493c6800010f980808000000b419c94c68000413a41d894c6800010a181808000000b2004200c41ac95c68000109581808000000b2004200c41bc95c68000109581808000000b2004200c41cc95c6800010f980808000000b41c8d6c28000412441ecd6c2800010a181808000000b41c8d6c280004124418cd7c2800010a181808000000b20072004418493c68000109581808000000b200b200441e4d7c2800010f980808000000b200541d8016a200141106a20041089868080000b0240024020052d00d80122044108470d00200541f8026a41086a200541e5016a290000370300200541f8026a41106a200541ed016a290000370300200541f8026a41186a200541f5016a290000370300200541f8026a41206a200541fd016a2900003703002005419f036a20054184026a280000360000200541b8056a41086a20054194026a290200370300200541b8056a41106a2005419c026a290200370300200541b8056a41186a200541a4026a290200370300200541b8056a41206a200541ac026a290200370300200541e0056a200541b4026a2902003703002005200541dd016a2900003703f80220052005418c026a2902003703b80520054188026a280200210b20052d00dc0121040c010b200541b0076a41086a220d200541e1016a290000370300200541b0076a41106a2214200541e9016a290000370300200541b0076a41186a2216200541f1016a290000370300200541b0076a41206a221e200541f9016a290000370300200541b0076a41276a221f200541d8016a41286a280000360000200541b0066a41086a2220200541d8016a41386a290200370300200541b0066a41106a2221200541d8016a41c0006a290200370300200541b0066a41186a2222200541d8016a41c8006a290200370300200541b0066a41206a2223200541a8026a290200370300200541b0066a41286a2224200541b0026a290200370300200520052900d9013703b00720052005290288023703b006200528028402210b200541a8036a41186a2225200541d0026a290200370300200541a8036a41106a2226200541c8026a290200370300200541a8036a41086a2227200541c0026a290200370300200520052902b8023703a803200541b8056a41286a22034100360200200541b8056a2007200720086a10f686808000200541c8036a41286a22072003280200360200200541c8036a41206a2208200541b8056a41206a220f290200370300200541c8036a41186a2228200541b8056a41186a2229290200370300200541c8036a41106a222a200541b8056a41106a222b290200370300200541c8036a41086a222c200541b8056a41086a222d290200370300200541d0046a41086a2027290300370300200541d0046a41106a2026290300370300200541d0046a41186a2025290300370300200520052902b8053703c803200520052903a8033703d004200541d0046a41c8006a2007280200360200200541d0046a41c0006a2008290300370300200541d0046a41386a202829030037030020054180056a202a290300370300200541d0046a41286a202c290300370300200520052903c8033703f0042005419d056a20093a00002005419c056a20063a0000200141dc006a200541d0046a10958d8080001a200541f8026a41086a200d290300370300200541f8026a41106a2014290300370300200541f8026a41186a2016290300370300200541f8026a41206a201e290300370300200541f8026a41276a201f280000360000202d2020290300370300202b202129030037030020292022290300370300200f202329030037030020032024290300370300200520052903b0073703f802200520052903b0063703b8050b02400240024002402004417c6a41ff01712207410420074104491b417f6a0e0401000002000b419cd7c28000412841c4d7c2800010f880808000000b200541b0066a41286a200541b8056a41286a290300370300200541b0066a41206a200541b8056a41206a290300370300200541b0066a41186a200541b8056a41186a290300370300200541b0066a41106a200541b8056a41106a290300370300200541b0066a41086a2204200541b8056a41086a290300370300200520052903b8053703b006200541d0046a41086a22012011360200200541e4046a20054198016a41086a290300370200200541ec046a20054198016a41106a290300370200200541f4046a20054198016a41186a290300370200200520133602d404200520123602d00420052005290398013702dc04200520103602fc04200541c8036a41086a22074101360200200541013602c8032005200c3a00b0072005200541b0076a3602cc03200541d0046a200541c8036a10e78d80800020072004280200200541dc066a22042802002203200341284b22031b360200200520052802b406200541b0066a41047220031b3602cc03200520052802b0063602c803200541d0046a200541c8036a10e78d808000200041d8006a200541d0046a41286a290200370200200041d0006a200541d0046a41206a290200370200200041c8006a200541d0046a41186a290200370200200041c0006a200541d0046a41106a290200370200200041386a2001290200370200200020052902d004370230200541c8036a410b6a200541f8026a410b6a290000370000200541c8036a41136a200541f8026a41136a290000370000200541c8036a411b6a200541f8026a411b6a290000370000200541c8036a41236a200541f8026a41236a290000370000200520052900fb023700cb03200041053a00002000200b36022c200020052900c803370001200041096a2007290000370000200041116a200541c8036a41106a290000370000200041196a200541c8036a41186a290000370000200041216a200541c8036a41206a290000370000200041286a200541ef036a28000036000020042802004129490d0120052802b40641002802c0a3c68000118080808000000c010b200020043a0000200020052903f802370001200541b0066a41286a200541b8056a41286a290300370300200541b0066a41206a200541b8056a41206a290300370300200541b0066a41186a200541b8056a41186a290300370300200541b0066a41106a200541b8056a41106a290300370300200541b0066a41086a2207200541b8056a41086a290300370300200041096a200541f8026a41086a290300370000200041116a200541f8026a41106a290300370000200041196a200541f8026a41186a290300370000200041216a200541f8026a41206a290300370000200041286a2005419f036a280000360000200520052903b8053703b006200541d0046a41086a22042011360200200541e4046a20054198016a41086a290300370200200541ec046a20054198016a41106a290300370200200541f4046a20054198016a41186a290300370200200520133602d404200520123602d00420052005290398013702dc04200520103602fc04200541c8036a41086a22014101360200200541013602c8032005200c3a00b0072005200541b0076a3602cc03200541d0046a200541c8036a10e78d80800020012007280200200541dc066a22072802002203200341284b22031b360200200520052802b406200541b0066a41047220031b3602cc03200520052802b0063602c803200541d0046a200541c8036a10e78d808000200041d8006a200541d0046a41286a290200370200200041d0006a200541d0046a41206a290200370200200041c8006a200541d0046a41186a290200370200200041c0006a200541d0046a41106a290200370200200041386a2004290200370200200020052902d0043702302000200b36022c20072802004129490d0020052802b40641002802c0a3c68000118080808000000b200528028004450d0020052802ac044129490d0020052802840441002802c0a3c68000118080808000000b200a41002802c0a3c68000118080808000000c060b4188d6c28000412f41fcd6c2800010f880808000000b2000200929020037023020002008290000370001200041d8006a200941286a290200370200200041d0006a200941206a290200370200200041c8006a200941186a290200370200200041c0006a200941106a290200370200200041386a200941086a290200370200200041096a200841086a290000370000200041116a200841106a290000370000200041196a200841186a290000370000200041216a200841206a290000370000200041286a200841276a2800003600002000200a36022c200020063a00000c040b4188d6c28000412f41b8d6c2800010f880808000000b2000200a360230200020093a0004200041073a0000200020082900003700052000412c6a200841276a280000360000200041256a200841206a2900003700002000411d6a200841186a290000370000200041156a200841106a2900003700002000410d6a200841086a2900003700000c020b0240200141286a28020022042001411c6a220a2802002207470d00200a10a889808000200128021c2107200128022821040b200141206a280200200141246a28020020046a22044100200720042007491b6b4102746a200b3602002001200128022841016a360228200141186a2802002207200b4b0d00200b200741e4d7c2800010f980808000000b200141146a280200200b4107746a22072d0060212e20072d005c210b20072d0058210a20072d0054210920072d0050210620072d004c210c20072d0048211020072d0044211120072d0040211220072d003c211420072d0038211620072d0034211e20072d0030212020072d002c212120072d0028212220072d0024212420072d0020212520072d001c212620072d0018212f20072d0014212320072d0010211f20072d000c211320072d0008210d20072d0004210820072d00002104200741043a0004200741083a0000200741e1006a2130200741dd006a2131200741d9006a2132200741d5006a2133200741d1006a2134200741cd006a2135200741c9006a2136200741c5006a2137200741c1006a21382007413d6a2139200741396a213a200741356a213b200741316a213c2007412d6a213d200741296a213e200741256a213f200741216a21402007411d6a212d200741196a212c200741156a212b200741116a212a2007410d6a2129200741096a2128200741056a21270240024020044108460d00200541b8056a41026a200741036a2d00003a0000200541b0076a41026a202741026a2d00003a0000200541b8016a41026a202841026a2d00003a0000200541bc086a41026a202941026a2d00003a0000200541b8086a41026a202a41026a2d00003a0000200520072f00013b01b805200520272f00003b01b007200520282f00003b01b801200520292f00003b01bc082005202a2f00003b01b808200541b4086a41026a202b41026a2d00003a0000200541b0086a41026a202c41026a2d00003a0000200541ac086a41026a202d41026a2d00003a0000200541a8086a41026a204041026a2d00003a0000200541a4086a41026a203f41026a2d00003a00002005202b2f00003b01b4082005202c2f00003b01b0082005202d2f00003b01ac08200520402f00003b01a8082005203f2f00003b01a408200541a0086a41026a203e41026a2d00003a00002005203e2f00003b01a0082005419c086a41026a203d41026a2d00003a00002005203d2f00003b019c0820054198086a41026a203c41026a2d00003a00002005203c2f00003b01980820054194086a41026a203b41026a2d00003a00002005203b2f00003b01940820054190086a41026a203a41026a2d00003a00002005203a2f00003b0190082005418c086a41026a203941026a2d00003a0000200520392f00003b018c0820054188086a41026a203841026a2d00003a0000200520382f00003b01880820054184086a41026a203741026a2d00003a0000200520372f00003b01840820054180086a41026a203641026a2d00003a0000200520362f00003b018008200541fc076a41026a203541026a2d00003a0000200520352f00003b01fc07200541f8076a41026a203441026a2d00003a0000200520342f00003b01f807200541f4076a41026a203341026a2d00003a0000200520332f00003b01f407200541f0076a41026a203241026a2d00003a0000200520322f00003b01f007200541ec076a41026a203141026a2d00003a0000200520312f00003b01ec07200541b0066a41026a203041026a2d00003a0000200520302f00003b01b006200541f0016a200741fc006a280000360200200541e8016a200741f4006a290000370300200541d8016a41086a200741ec006a290000370300200520072900643703d801200a2128200421272009210a20062109200c21062010210c20112110201221112014211220162114201e21162020211e2021212020222121202421222025212420262125202f21260c010b200541b8056a41026a202741026a2d00003a0000200541b0076a41026a202841026a2d00003a0000200541b8016a41026a202941026a2d00003a0000200541bc086a41026a202a41026a2d00003a0000200541b8086a41026a202b41026a2d00003a0000200520272f00003b01b805200520282f00003b01b007200520292f00003b01b8012005202a2f00003b01bc082005202b2f00003b01b808200541b4086a41026a202c41026a2d00003a0000200541b0086a41026a202d41026a2d00003a0000200541ac086a41026a204041026a2d00003a0000200541a8086a41026a203f41026a2d00003a0000200541a4086a41026a203e41026a2d00003a00002005202c2f00003b01b4082005202d2f00003b01b008200520402f00003b01ac082005203f2f00003b01a8082005203e2f00003b01a408200541a0086a41026a203d41026a2d00003a00002005203d2f00003b01a0082005419c086a41026a203c41026a2d00003a00002005203c2f00003b019c0820054198086a41026a203b41026a2d00003a00002005203b2f00003b01980820054194086a41026a203a41026a2d00003a00002005203a2f00003b01940820054190086a41026a203941026a2d00003a0000200520392f00003b0190082005418c086a41026a203841026a2d00003a0000200520382f00003b018c0820054188086a41026a203741026a2d00003a0000200520372f00003b01880820054184086a41026a203641026a2d00003a0000200520362f00003b01840820054180086a41026a203541026a2d00003a0000200520352f00003b018008200541fc076a41026a203441026a2d00003a0000200520342f00003b01fc07200541f8076a41026a203341026a2d00003a0000200520332f00003b01f807200541f4076a41026a203241026a2d00003a0000200520322f00003b01f407200541f0076a41026a203141026a2d00003a0000200520312f00003b01f007200541ec076a41026a203041026a2d00003a0000200520302f00003b01ec07200b2128202e210b20082127200d21082013210d201f21132023211f202f21230b200541d7046a200541b0076a41026a2d00003a0000200541db046a200541b8016a41026a2d00003a0000200541df046a200541bc086a41026a2d00003a0000200520052f01b8053b00d104200520083a00d404200520052f01b0073b00d5042005200d3a00d804200520052f01b8013b00d904200520133a00dc04200520052f01bc083b00dd042005200541b8056a41026a2d00003a00d304200520273a00d004200541e3046a200541b8086a41026a2d00003a0000200541e7046a200541b4086a41026a2d00003a0000200541eb046a200541b0086a41026a2d00003a0000200541ef046a200541ac086a41026a2d00003a00002005201f3a00e004200520233a00e404200520263a00e804200520253a00ec04200520052f01b8083b00e104200520052f01b4083b00e504200520052f01b0083b00e904200520052f01ac083b00ed04200541f3046a200541a8086a41026a2d00003a0000200541f7046a200541a4086a41026a2d00003a0000200541fb046a200541a0086a41026a2d00003a0000200541ff046a2005419c086a41026a2d00003a0000200520243a00f004200520223a00f404200520213a00f804200520203a00fc04200520052f01a8083b00f104200520052f01a4083b00f504200520052f01a0083b00f904200520052f019c083b00fd042005201e3a00800520054183056a20054198086a41026a2d00003a0000200520052f0198083b008105200520163a00840520054187056a20054194086a41026a2d00003a0000200520052f0194083b008505200520143a0088052005418b056a20054190086a41026a2d00003a0000200520052f0190083b008905200520123a008c052005418f056a2005418c086a41026a2d00003a0000200520052f018c083b008d05200520113a00900520054193056a20054188086a41026a2d00003a0000200520052f0188083b009105200520103a00940520054197056a20054184086a41026a2d00003a0000200520052f0184083b0095052005200c3a0098052005419b056a20054180086a41026a2d00003a0000200520052f0180083b009905200520063a009c052005419f056a200541fc076a41026a2d00003a0000200520052f01fc073b009d05200520093a00a005200541a3056a200541f8076a41026a2d00003a0000200520052f01f8073b00a1052005200a3a00a405200541a7056a200541f4076a41026a2d00003a0000200520052f01f4073b00a505200520283a00a805200541ab056a200541f0076a41026a2d00003a0000200520052f01f0073b00a9052005200b3a00ac05200541af056a200541ec076a41026a2d00003a0000200520052f01ec073b00ad05200541b4056a41026a200541b0066a41026a2d00003a0000200520052f01b0063b01b4054108212a200541f8026a41086a200541d8016a41086a290300370300200541f8026a41106a200541d8016a41106a290300370300200541f8026a41186a200541d8016a41186a280200360200200520052903d8013703f802200541d0046a41046a210702400240024002400240024002402027417c6a41ff01712229410420294104491b417f6a0e020102000b200541ad056a2107200541a9056a2103200541a5056a2129200541a1056a212b2005419d056a212c20054199056a212d20054195056a214020054191056a213f2005418d056a213e20054189056a213d20054185056a213c20054181056a213b200541fd046a213a200541f9046a2139200541f5046a2138200541f1046a2137200541ed046a2136200541e9046a2135200541e5046a2134200541e1046a2133200541dd046a2132200541d9046a2131200541d5046a2130200541d0046a410172211d20044108470d02200541e2076a2104200541e6076a210e200541e9076a211b200541ec076a211c200541f0076a212f200541f4076a2141200541f8076a2142200541fc076a214320054180086a214420054184086a214520054188086a21462005418c086a214720054190086a214820054194086a214920054198086a214a2005419c086a214b200541a0086a214c200541a4086a214d200541a8086a214e200541ac086a214f200541b0086a2150200541b4086a2151200541b8086a2152200541bc086a21530c030b200541b0066a41286a20054180056a220b41286a290200370300200541b0066a41206a200b41206a290200370300200541b0066a41186a200b41186a290200370300200541b0066a41106a200b41106a290200370300200541b0066a41086a200b41086a290200370300200541e0066a41086a200741086a290200370300200541e0066a41106a200741106a290200370300200541e0066a41186a200741186a290200370300200541e0066a41206a220a200741206a290200370300200541e0066a41286a200741286a2802003602002005200b2902003703b006200520072902003703e006024020044108460d00200541ac076a41026a2207200541b4056a41026a2d00003a000020054190076a41086a2204200541f8026a41086a29030037030020054190076a41106a220b200541f8026a41106a29030037030020054190076a41186a2203200541f8026a41186a280200360200200520052f01b4053b01ac07200520052903f80237039007200541b8056a41286a22084100360200200541b8056a201d201d201b6a10f686808000200541b0076a41286a22092008280200360200200541b0076a41206a2208200541b8056a41206a290200370300200541b0076a41186a2206200541b8056a41186a290200370300200541b0076a41106a220c200541b8056a41106a290200370300200541b0076a41086a220d200541b8056a41086a290200370300200520052902b8053703b0072005202e3a00d801200520052f01ac073b00d901200520072d00003a00db01200541f4016a2003280200360200200541ec016a200b290300370200200541e4016a200429030037020020052005290390073702dc01200541a0026a200928020036020020054198026a200829030037020020054190026a200629030037020020054188026a200c290300370200200541d8016a41286a200d290300370200200520052903b0073702f801200541a5026a200e3a0000200541a4026a201c3a0000200141dc006a200541d8016a10958d8080001a0b200541d8016a41286a2207200541c8036a41286a290300370300200541d8016a41206a2204200541c8036a41206a290300370300200541d8016a41186a220b200541c8036a41186a290300370300200541d8016a41106a2201200541c8036a41106a290300370300200541d8016a41086a2203200541c8036a41086a290300370300200520052903c8033703d801200541b8056a41086a2208200541b0066a41086a280200200541dc066a22092802002206200641284b22061b360200200520052802b406200541b0066a41047220061b3602bc05200520052802b0063602b805200541d8016a200541b8056a10e78d808000200041d8006a2007290300370200200041d0006a2004290300370200200041c8006a200b290300370200200041c0006a2001290300370200200041386a2003290300370200200020052903d801370230200541c3056a200541e0066a41086a290300370000200541cb056a200541e0066a41106a290300370000200541d3056a200541e0066a41186a290300370000200541db056a200a290300370000200541e3056a200541e0066a41286a280200360000200520052903e0063700bb05200041053a0000200020052900b805370001200041096a2008290000370000200041116a200541b8056a41106a290000370000200041196a200541b8056a41186a290000370000200041216a200541b8056a41206a290000370000200041286a200541df056a29000037000020092802004129490d0320052802b40641002802c0a3c68000118080808000000c030b200541b8056a41286a200541d0046a41286a220b41286a290200370300200541b8056a41206a200b41206a290200370300200541b8056a41186a200b41186a290200370300200541b8056a41106a200b41106a290200370300200541b8056a41086a200b41086a290200370300200541e8056a41086a200741086a290200370300200541e8056a41106a200741106a290200370300200541e8056a41186a200741186a290200370300200541e8056a41206a220a200741206a2802003602002005200b2902003703b805200520072902003703e805024020044108460d00200541ac066a41026a2207200541b4056a41026a2d00003a000020054190066a41086a2204200541f8026a41086a29030037030020054190066a41106a220b200541f8026a41106a29030037030020054190066a41186a2208200541f8026a41186a280200360200200520052f01b4053b01ac06200520052903f80237039006200541b0066a41286a22094100360200200541b0066a201d201d201b6a10f686808000200541b0076a41286a22062009280200360200200541b0076a41206a2209200541b0066a41206a290200370300200541b0076a41186a220c200541b0066a41186a290200370300200541b0076a41106a220d200541b0066a41106a290200370300200541b0076a41086a2210200541b0066a41086a290200370300200520052902b0063703b0072005202e3a00d801200520052f01ac063b00d901200520072d00003a00db01200541f4016a2008280200360200200541ec016a200b290300370200200541e4016a200429030037020020052005290390063702dc01200541a0026a200628020036020020054198026a200929030037020020054190026a200c29030037020020054188026a200d290300370200200541d8016a41286a2010290300370200200520052903b0073702f801200541a5026a200e3a0000200541a4026a201c3a0000200141dc006a200541d8016a10958d8080001a0b200541b0066a41286a2207200541c8036a41286a290300370300200541b0066a41206a2204200541c8036a41206a290300370300200541b0066a41186a220b200541c8036a41186a290300370300200541b0066a41106a2208200541c8036a41106a290300370300200541b0066a41086a2209200541c8036a41086a290300370300200520052903c8033703b006200541d8016a41086a200541b8056a41086a280200200541e4056a2206280200220c200c41284b220c1b360200200520052802bc05200541b8056a410472200c1b3602dc01200520052802b8053602d801200541b0066a200541d8016a10e78d808000200541a8026a2007290300370200200541a0026a200429030037020020054198026a200b29030037020020054190026a200829030037020020054188026a2009290300370200200541e4016a200541e8056a41086a290300370200200541ec016a200541e8056a41106a290300370200200541f4016a200541e8056a41186a290300370200200541fc016a200a280200360200200520052903b00637028002200520052903e8053702dc01200541063a00d80120002001200541d8016a2003410110888680800020062802004129490d0220052802bc0541002802c0a3c68000118080808000000c020b200541e2076a41026a200541b4056a41026a2d00003a0000200541b8056a41086a200541f8026a41086a290300370300200541b8056a41106a200541f8026a41106a290300370300200541b8056a41186a200541f8026a41186a280200360200200520052f01b4053b01e207200520052903f8023703b805200541e6076a2104200541e9076a210e200541ec076a211b200541f0076a211c200541f4076a212f200541f8076a2141200541fc076a214220054180086a214320054184086a214420054188086a21452005418c086a214620054190086a214720054194086a214820054198086a21492005419c086a214a200541a0086a214b200541a4086a214c200541a8086a214d200541ac086a214e200541b0086a214f200541b4086a2150200541b8086a2151200541bc086a2152200541b8016a21532027212a20082127200d21082013210d201f21132023211f202621232025212620242125202221242021212220202121201e21202016211e20142116201221142011211220102111200c21102006210c20092106200a21092028210a200b2128202e210b0b2053201d2f00003b0000205220302f00003b0000205120312f00003b0000205020322f00003b0000204f20332f00003b0000205341026a201d41026a2d00003a0000205241026a203041026a2d00003a0000205141026a203141026a2d00003a0000205041026a203241026a2d00003a0000204f41026a203341026a2d00003a0000204e41026a203441026a2d00003a0000204e20342f00003b0000204d20352f00003b0000204d41026a203541026a2d00003a0000204c20362f00003b0000204c41026a203641026a2d00003a0000204b20372f00003b0000204b41026a203741026a2d00003a0000204a41026a203841026a2d00003a0000204a20382f00003b0000204941026a203941026a2d00003a0000204920392f00003b0000204841026a203a41026a2d00003a00002048203a2f00003b0000204741026a203b41026a2d00003a00002047203b2f00003b0000204641026a203c41026a2d00003a00002046203c2f00003b0000204541026a203d41026a2d00003a00002045203d2f00003b0000204441026a203e41026a2d00003a00002044203e2f00003b0000204341026a203f41026a2d00003a00002043203f2f00003b0000204241026a204041026a2d00003a0000204220402f00003b0000204141026a202d41026a2d00003a00002041202d2f00003b0000202f41026a202c41026a2d00003a0000202f202c2f00003b0000201c41026a202b41026a2d00003a0000201c202b2f00003b0000201b41026a202941026a2d00003a0000201b20292f00003b0000200e41026a200341026a2d00003a0000200e20032f00003b0000200441026a200741026a2d00003a0000200420072f00003b0000200541d8016a41286a200541c8036a41286a290300370300200541d8016a41206a200541c8036a41206a290300370300200541d8016a41186a200541c8036a41186a290300370300200541d8016a41106a200541c8036a41106a290300370300200541d8016a41086a200541c8036a41086a290300370300200520052903c8033703d801024002400240200141286a2802002207450d0020012007417f6a360228200141246a22072007280200220741016a220441002001411c6a280200220320042003491b6b360200200141206a28020020074102746a2802002204200141186a28020022074f0d02200128021420044107746a220741046a200720072d00004108461b10e3858080002007202a3a0000200720273a0004200720083a00082007200d3a000c200720052f00b8013b0001200741036a200541b8016a41026a2d00003a0000200720052f00bc083b0005200741076a200541bc086a41026a2d00003a0000200720052f00b8083b00092007410b6a200541b8086a41026a2d00003a0000200720052f00b4083b000d2007410f6a200541b4086a41026a2d00003a0000200720133a00102007201f3a0014200720233a0018200720263a001c200720052f00b0083b0011200741136a200541b0086a41026a2d00003a0000200720052f00ac083b0015200741176a200541ac086a41026a2d00003a0000200720052f00a8083b00192007411b6a200541a8086a41026a2d00003a0000200720052f00a4083b001d2007411f6a200541a4086a41026a2d00003a0000200720253a0020200720243a0024200720223a0028200720213a002c200720052f00a0083b0021200741236a200541a0086a41026a2d00003a0000200720052f009c083b0025200741276a2005419c086a41026a2d00003a0000200720052f0098083b00292007412b6a20054198086a41026a2d00003a0000200720052f0094083b002d2007412f6a20054194086a41026a2d00003a0000200720203a0030200741336a20054190086a41026a2d00003a0000200720052f0090083b00312007201e3a0034200741376a2005418c086a41026a2d00003a0000200720052f008c083b0035200720163a00382007413b6a20054188086a41026a2d00003a0000200720052f0088083b0039200720143a003c2007413f6a20054184086a41026a2d00003a0000200720052f0084083b003d200720123a0040200741c3006a20054180086a41026a2d00003a0000200720052f0080083b0041200720113a0044200741c7006a200541fc076a41026a2d00003a0000200720052f00fc073b0045200720103a0048200741cb006a200541f8076a41026a2d00003a0000200720052f00f8073b00492007200c3a004c200741cf006a200541f4076a41026a2d00003a0000200720052f00f4073b004d200720063a0050200741d3006a200541f0076a41026a2d00003a0000200720052f00f0073b0051200720093a0054200741d7006a200541ec076a41026a2d00003a0000200720052f00ec073b00552007200a3a0058200741db006a200541e9076a41026a2d00003a0000200720052f00e9073b0059200720283a005c200741df006a200541e6076a41026a2d00003a0000200720052f00e6073b005d2007200b3a0060200741e3006a200541e2076a41026a2d00003a0000200720052f01e2073b0061200741fc006a200541d0056a280200360000200741f4006a200541c8056a290300370000200741ec006a200541b8056a41086a290300370000200720052903b8053700640c010b0240200141186a28020022072001280210470d00200141106a2007109e86808000200128021821070b200128021420074107746a2207202a3a0000200720052f00b8013b0001200720273a0004200720052f00bc083b0005200720083a0008200720052f00b8083b00092007200d3a000c200720052f00b4083b000d200741036a200541b8016a41026a2d00003a0000200741076a200541bc086a41026a2d00003a00002007410b6a200541b8086a41026a2d00003a00002007410f6a200541b4086a41026a2d00003a0000200720133a00102007201f3a0014200720233a0018200720263a001c200720052f00b0083b0011200741136a200541b0086a41026a2d00003a0000200720052f00ac083b0015200741176a200541ac086a41026a2d00003a0000200720052f00a8083b00192007411b6a200541a8086a41026a2d00003a0000200720052f00a4083b001d2007411f6a200541a4086a41026a2d00003a0000200720253a0020200741236a200541a0086a41026a2d00003a0000200720052f00a0083b0021200720243a0024200741276a2005419c086a41026a2d00003a0000200720052f009c083b0025200720223a00282007412b6a20054198086a41026a2d00003a0000200720052f0098083b0029200720213a002c2007412f6a20054194086a41026a2d00003a0000200720052f0094083b002d200720203a0030200741336a20054190086a41026a2d00003a0000200720052f0090083b00312007201e3a0034200741376a2005418c086a41026a2d00003a0000200720052f008c083b0035200720163a00382007413b6a20054188086a41026a2d00003a0000200720052f0088083b0039200720143a003c2007413f6a20054184086a41026a2d00003a0000200720052f0084083b003d200720123a0040200741c3006a20054180086a41026a2d00003a0000200720052f0080083b0041200720113a0044200741c7006a200541fc076a41026a2d00003a0000200720052f00fc073b0045200720103a0048200741cb006a200541f8076a41026a2d00003a0000200720052f00f8073b00492007200c3a004c200741cf006a200541f4076a41026a2d00003a0000200720052f00f4073b004d200720063a0050200741d3006a200541f0076a41026a2d00003a0000200720052f00f0073b0051200720093a0054200741d7006a200541ec076a41026a2d00003a0000200720052f00ec073b00552007200a3a0058200741db006a200541e9076a41026a2d00003a0000200720052f00e9073b0059200720283a005c200741df006a200541e6076a41026a2d00003a0000200720052f00e6073b005d2007200b3a0060200741e3006a200541e2076a41026a2d00003a0000200720052f01e2073b0061200741fc006a200541d0056a280200360000200741f4006a200541c8056a290300370000200741ec006a200541c0056a290300370000200720052903b80537006420012001280218220441016a3602180b200020052903d801370228200020052f00b0073b0005200020052902b00637020c200041d0006a20054180026a290300370200200041c8006a200541f8016a290300370200200041c0006a200541d8016a41186a290300370200200041386a200541d8016a41106a290300370200200041306a200541d8016a41086a290300370200200041076a200541b0076a41026a2d00003a0000200041146a200541b0066a41086a2902003702002000411c6a200541b0066a41106a290200370200200041246a200541b0066a41186a280200360200200041063a0000200020052f00d8013b0001200041036a200541d8016a41026a2d00003a000020002004360208200041003a00040c020b2004200741d4d7c2800010f980808000000b20052d00d004417c6a41ff01712207410420074104491b417f6a4102490d00200541d0046a10e3858080000b200528028004450d00200f2802284129490d0020052802840441002802c0a3c68000118080808000000b20022d0000417c6a41ff01712207410420074104491b417e6a4103490d010b200210e3858080000b200541c0086a2480808080000bb20101027f0240200141186a2802002203200128020c2204470d002001410c6a10a889808000200128020c2104200128021821030b200141106a280200200141146a28020020036a22034100200420032004491b6b4102746a20023602002001200128021841016a36021802402001280208220420024d0d002000200128020420024107746a220141800110848e8080001a200141043a0004200141083a00000f0b2002200441e4d7c2800010f980808000000b99950105107f017e017f047e397f23808080800041c0086b2205248080808000024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024020022d00002206417c6a41ff01712207410420074104491b417e6a0e03020108000b2000200241e00010848e8080001a0c200b200241056a210820022d000421092002280230220a2d00004102460d0141002106410121070c020b200541c8036a41286a200241d0006a290200370300200541e8036a200241c8006a290200370300200541c8036a41186a200241c0006a290200370300200541c8036a41106a200241386a290200370300200541c8036a41086a2207200241306a290200370300200520022902283703c803200541fe036a200241076a2d00003a000020054198016a41086a200241146a29020037030020054198016a41106a2002411c6a29020037030020054198016a41186a200241246a2802003602002005200241056a2f00003b01fc0320052002410c6a29020037039801200241086a280200210b20022d000421062003280200210a2003280204210820032802082109024002400240024002400240024002400240024020040d002007280200200541f4036a2802002204200441284b1b2207417f6a210c2007450d11200741017420096a20052802c803417f736a2209410176210720052802cc03200541c8036a410472200441284b1b200c6a2d0000410f71210c024020094101710d00200720084d0d022007200841f492c68000109581808000000b200720084b0d1220072008490d0220072008419493c6800010f980808000000b2009410176210702400240200941017122040d00200720084d0d012007200841f492c68000109581808000000b200720084b0d13200720084f0d14200a20076a2d000041707121090b2005420037028002200541003602d804200520073602d4042005200a3602d004200541d8016a200541d0046a4100200510e38d8080001a2004450d06200941f00171210820052d0084024101710d04200541d8016a41046a2104200541d8016a41044128200528028002220d41284b22091b6a280200220c200d412820091b460d022004200541d8016a41286a20091b210420052802d801200541d8016a20091b21090c030b410021042005410036028004200c410474210e20054180046a41046a210f410121080c070b200a20076a22042d0000210941002108200541d8016a41286a220d4100360200200541d8016a200a200410f686808000200541d0046a41286a2210200d280200220d360200200541d0046a41206a2211200541d8016a41206a290200370300200541d0046a41186a2212200541d8016a41186a290200370300200541d0046a41106a2213200541d8016a41106a290200370300200541d0046a41086a2214200541d8016a41086a290200370300200520052902d80122153703d004200541d0046a41047221042009417071200c72211602400240200541d0046a41044128200d41284b22091b6a280200220c200d412820091b460d002004201020091b21042015a7200541d0046a20091b21090c010b200541d0046a10f88680800020052802d404210c20052802d00421090b2009200c6a20163a00002004200428020041016a360200200541b0066a41086a20142903002215370300200541b0066a41106a20132903002217370300200541b0066a41186a20122903002218370300200541b0066a41206a20112903002219370300200541b0066a41286a20102802002204360200200520052903d004221a3703b0062005418c046a201537020020054194046a20173702002005419c046a2018370200200541a4046a2019370200200541ac046a200436020020054101360280042005201a3702840420054180046a41046a210f0c050b200541d8016a10f78d80800020052802dc01210c20052802d80121090b2009200c6a20083a00002004200428020041016a3602000c010b20052802dc012005280280022204200441284b22041b2209450d0f200920052802d801200541d8016a20041b6a417f6a220420042d00002008410476723a00000b200520052802840241016a360284020b200520052802c8033602d8042005200541d0036a280200200541f4036a2802002204200441284b22041b3602d404200520052802cc03200541c8036a41047220041b3602d004200541d8016a200541d0046a4100200510e38d8080001a200528028402220841017621040240024020084101710d0020052802dc012005280280022209200941284b22091b220c2004490d1020052802d801200541d8016a20091b21090c010b20052802dc012005280280022209200941284b1b220c2004490d10200c20044d0d1120052802d801200541d8016a200941284b1b220920046a2d0000417071210e0b200541d0046a41286a220c4100360200200541d0046a2009200920046a10f686808000200541b0066a41286a2204200c280200360200200541b0066a41206a2209200541d0046a41206a290200370300200541b0066a41186a220c200541d0046a41186a290200370300200541b0066a41106a220d200541d0046a41106a290200370300200541b0066a41086a2210200541d0046a41086a290200370300200520052902d0043703b00602402005280280024129490d0020052802d80141002802c0a3c68000118080808000000b2005418c046a201029030037020020054194046a200d2903003702002005419c046a200c290300370200200541a4046a2009290300370200200541ac046a20042802003602002005410136028004200520052903b0063702840420054184046a210f0b20052802880420052802ac042204200441284b22041b2109200528028404200f20041b21040b2009200720041b211b2008410171211c2004200a20041b211d024020064101710d000240200141286a28020022042001411c6a220a2802002207470d00200a10a889808000200128021c2107200128022821040b200141206a280200200141246a28020020046a22044100200720042007491b6b4102746a200b3602002001200128022841016a360228200141186a2802002207200b4b0d1c200b200741e4d7c2800010f980808000000b200541b0046a41026a200541fc036a41026a2d00003a0000200541bf046a20054198016a41086a290300370000200541c7046a200541a8016a290300370000200541cf046a200541b0016a2d00003a0000200520052f01fc033b01b0042005200b3600b30420052005290398013700b7042005200e3a00e1012005201c3a00e0012005201b3602dc012005201d3602d801200541d0046a2001200541b0046a200541d8016a10868680800020052802d404210b20052802d004450d1a200041083a00002000200b3602040240200528028004450d00200f2802284129490d0020052802840441002802c0a3c68000118080808000000b200541f4036a2802004129490d0620052802cc0341002802c0a3c68000118080808000000c060b4101210641022107200a2d00244102470d004102210641032107200a2d00484102470d000240200a2d006c4102460d0041032106410421070c010b0240200a2d0090014102460d0041042106410521070c010b0240200a2d00b4014102460d0041052106410621070c010b0240200a2d00d8014102460d0041062106410721070c010b0240200a2d00fc014102460d0041072106410821070c010b0240200a2d00a0024102460d0041082106410921070c010b0240200a2d00c4024102460d0041092106410a21070c010b0240200a2d00e8024102460d00410a2106410b21070c010b0240200a2d008c034102460d00410b2106410c21070c010b0240200a2d00b0034102460d00410c2106410d21070c010b0240200a2d00d4034102460d00410d2106410e21070c010b0240200a2d00f8034102460d00410e2106410f21070c010b200a2d009c044102460d01410f2106411021070b200741246c21070340200741246a220441e404460d02200a20076a210b20042107200b2d00004102460d000c180b0b200941ff01714103460d15200020082900003700052000412c6a200841276a280000360000200041256a200841206a2900003700002000411d6a200841186a290000370000200041156a200841106a2900003700002000410d6a200841086a290000370000200542003702dc01200541a0d1c280003602d801200041306a200541d8016a10d98d808000200020093a0004200041053a00000c010b200941ff01714103470d15200520063a00d004200541d8016a41286a22074100360200200541d8016a200541d0046a200541d0046a41016a10f58d808000200541086a41286a220b2007280200360200200541086a41206a2208200541d8016a41206a290200370300200541086a41186a2209200541d8016a41186a290200370300200541086a41106a220c200541d8016a41106a290200370300200541086a41086a220d200541d8016a41086a290200370300200520052902d801370308200a200641246c6a22072d00002104200741023a000020044102460d0b2005413d6a2007290001370000200541e4006a2005290308370200200541386a41246a200741206a280000360000200541d5006a200741196a290000370000200541cd006a200741116a290000370000200541c5006a200741096a290000370000200541ec006a200d290300370200200541f4006a200c290300370200200541fc006a200929030037020020054184016a20082903003702002005418c016a200b28020036020020054101360260200541063a0038200520043a003c20002001200541386a20034100108a868080000b200a41002802c0a3c68000118080808000000c170b200541a0016a200241c4006a290200370300200541a8016a200241cc006a290200370300200541b0016a200241d4006a29020037030020052002413c6a2902003703980141012107200241016a2108200241306a2109200241dc006a2802002110200241386a2802002111200241346a2802002113200228023021124100210c024002400240200228022c220a2d0000220d4102470d004101210c41022107200a2d0024220d4102470d004102210c41032107200a2d0048220d4102470d000240200a2d006c220d4102460d004103210c410421070c010b0240200a2d009001220d4102460d004104210c410521070c010b0240200a2d00b401220d4102460d004105210c410621070c010b0240200a2d00d801220d4102460d004106210c410721070c010b0240200a2d00fc01220d4102460d004107210c410821070c010b0240200a2d00a002220d4102460d004108210c410921070c010b0240200a2d00c402220d4102460d004109210c410a21070c010b0240200a2d00e802220d4102460d00410a210c410b21070c010b0240200a2d008c03220d4102460d00410b210c410c21070c010b0240200a2d00b003220d4102460d00410c210c410d21070c010b0240200a2d00d403220d4102460d00410d210c410e21070c010b0240200a2d00f803220d4102460d00410e210c410f21070c010b200a2d009c04220d4102460d01410f210c411021070b200741246c21070340200741246a220441e404460d02200a20076a210b20042107200b2d00004102460d000c140b0b200641ff01714103460d1120002008290000370005200020092902003702302000412c6a200841276a280000360000200041256a200841206a2900003700002000411d6a200841186a290000370000200041156a200841106a2900003700002000410d6a200841086a290000370000200041386a200941086a290200370200200041c0006a200941106a290200370200200041c8006a200941186a290200370200200041d0006a200941206a290200370200200041d8006a200941286a290200370200200020063a0004200041053a00000c100b200641ff01714103470d11200a200c41246c6a220741023a0000200d4102460d0a2007280204210b200541bc086a41026a200741036a2d00003a0000200541c0016a200741106a290200370300200541b8016a41106a200741186a290200370300200541b8016a41186a200741206a280200360200200520072f00013b01bc08200520072902083703b801200328020820112010201041284b1b41017420126b6a220841017621072003280204210420032802002103024002400240024020084101710d00200720044d0d012007200441f492c68000109581808000000b200720044b0d0e20072004490d0120072004419493c6800010f980808000000b410021042005410036028004200c4104742109410121060c010b200320076a22042d0000210841002106200541d8016a41286a22094100360200200541d8016a2003200410f686808000200541d0046a41286a221420092802002209360200200541d0046a41206a221e200541d8016a41206a290200370300200541d0046a41186a221f200541d8016a41186a290200370300200541d0046a41106a2220200541d8016a41106a290200370300200541d0046a41086a2221200541d8016a41086a290200370300200520052902d80122153703d004200541d0046a41047221042008417071200c72212202400240200541d0046a41044128200941284b22081b6a28020022162009412820081b460d002004201420081b21042015a7200541d0046a20081b21080c010b200541d0046a10f88680800020052802d404211620052802d00421080b200820166a20223a00002004200428020041016a360200200541ac046a20142802002208360200200541a4046a201e2903003702002005419c046a201f29030037020020054194046a20202903003702002005418c046a2021290300370200200520052903d00422153702840420054101360280042015a720054180046a41046a200841284b22091b2104200528028804200820091b21080b2008200720041b21082004200320041b21070240200d4101710d000240200141286a28020022032001411c6a220d2802002204470d00200d10a889808000200128021c2104200128022821030b200141206a280200200141246a28020020036a22034100200420032004491b6b4102746a200b3602002001200128022841016a360228200141186a2802002204200b4d0d0d200541d8016a200141146a280200200b4107746a220441800110848e8080001a200441043a0004200441083a00000c0f0b200541d8026a41026a200541bc086a41026a2d00003a0000200541e7026a200541b8016a41086a290300370000200541ef026a200541b8016a41106a290300370000200541f7026a200541d0016a2d00003a0000200520052f01bc083b01d8022005200b3600db02200520052903b8013700df02200520093a00d904200520063a00d804200520083602d404200520073602d004200541b0066a2001200541d8026a200541d0046a10868680800020052802b406210420052802b006450d0d200041083a0000200020043602040240200528028004450d0020052802ac044129490d0020052802840441002802c0a3c68000118080808000000b200a41002802c0a3c680001180808080000020104129490d00201341002802c0a3c68000118080808000000b20022d0000417c6a41ff01712207410420074104491b417e6a4103490d170c160b200c200741f8d5c2800010f980808000000b20072008418493c68000109581808000000b20072008418493c68000109581808000000b20072008419493c6800010f980808000000b419c94c68000413a41d894c6800010a181808000000b2004200c41ac95c68000109581808000000b2004200c41bc95c68000109581808000000b2004200c41cc95c6800010f980808000000b41c8d6c28000412441ecd6c2800010a181808000000b41c8d6c280004124418cd7c2800010a181808000000b20072004418493c68000109581808000000b200b200441e4d7c2800010f980808000000b200541d8016a200141106a20041089868080000b0240024020052d00d80122044108470d00200541f8026a41086a200541e5016a290000370300200541f8026a41106a200541ed016a290000370300200541f8026a41186a200541f5016a290000370300200541f8026a41206a200541fd016a2900003703002005419f036a20054184026a280000360000200541b8056a41086a20054194026a290200370300200541b8056a41106a2005419c026a290200370300200541b8056a41186a200541a4026a290200370300200541b8056a41206a200541ac026a290200370300200541e0056a200541b4026a2902003703002005200541dd016a2900003703f80220052005418c026a2902003703b80520054188026a280200210b20052d00dc0121040c010b200541b0076a41086a220d200541e1016a290000370300200541b0076a41106a2214200541e9016a290000370300200541b0076a41186a2216200541f1016a290000370300200541b0076a41206a221e200541f9016a290000370300200541b0076a41276a221f200541d8016a41286a280000360000200541b0066a41086a2220200541d8016a41386a290200370300200541b0066a41106a2221200541d8016a41c0006a290200370300200541b0066a41186a2222200541d8016a41c8006a290200370300200541b0066a41206a2223200541a8026a290200370300200541b0066a41286a2224200541b0026a290200370300200520052900d9013703b00720052005290288023703b006200528028402210b200541a8036a41186a2225200541d0026a290200370300200541a8036a41106a2226200541c8026a290200370300200541a8036a41086a2227200541c0026a290200370300200520052902b8023703a803200541b8056a41286a22034100360200200541b8056a2007200720086a10f686808000200541c8036a41286a22072003280200360200200541c8036a41206a2208200541b8056a41206a220f290200370300200541c8036a41186a2228200541b8056a41186a2229290200370300200541c8036a41106a222a200541b8056a41106a222b290200370300200541c8036a41086a222c200541b8056a41086a222d290200370300200541d0046a41086a2027290300370300200541d0046a41106a2026290300370300200541d0046a41186a2025290300370300200520052902b8053703c803200520052903a8033703d004200541d0046a41c8006a2007280200360200200541d0046a41c0006a2008290300370300200541d0046a41386a202829030037030020054180056a202a290300370300200541d0046a41286a202c290300370300200520052903c8033703f0042005419d056a20093a00002005419c056a20063a0000200141dc006a200541d0046a10958d8080001a200541f8026a41086a200d290300370300200541f8026a41106a2014290300370300200541f8026a41186a2016290300370300200541f8026a41206a201e290300370300200541f8026a41276a201f280000360000202d2020290300370300202b202129030037030020292022290300370300200f202329030037030020032024290300370300200520052903b0073703f802200520052903b0063703b8050b02400240024002402004417c6a41ff01712207410420074104491b417f6a0e0401000002000b419cd7c28000412841c4d7c2800010f880808000000b200541b0066a41286a200541b8056a41286a290300370300200541b0066a41206a200541b8056a41206a290300370300200541b0066a41186a200541b8056a41186a290300370300200541b0066a41106a200541b8056a41106a290300370300200541b0066a41086a2204200541b8056a41086a290300370300200520052903b8053703b006200541d0046a41086a22012011360200200541e4046a20054198016a41086a290300370200200541ec046a20054198016a41106a290300370200200541f4046a20054198016a41186a290300370200200520133602d404200520123602d00420052005290398013702dc04200520103602fc04200541c8036a41086a22074101360200200541013602c8032005200c3a00b0072005200541b0076a3602cc03200541d0046a200541c8036a10e78d80800020072004280200200541dc066a22042802002203200341284b22031b360200200520052802b406200541b0066a41047220031b3602cc03200520052802b0063602c803200541d0046a200541c8036a10e78d808000200041d8006a200541d0046a41286a290200370200200041d0006a200541d0046a41206a290200370200200041c8006a200541d0046a41186a290200370200200041c0006a200541d0046a41106a290200370200200041386a2001290200370200200020052902d004370230200541c8036a410b6a200541f8026a410b6a290000370000200541c8036a41136a200541f8026a41136a290000370000200541c8036a411b6a200541f8026a411b6a290000370000200541c8036a41236a200541f8026a41236a290000370000200520052900fb023700cb03200041053a00002000200b36022c200020052900c803370001200041096a2007290000370000200041116a200541c8036a41106a290000370000200041196a200541c8036a41186a290000370000200041216a200541c8036a41206a290000370000200041286a200541ef036a28000036000020042802004129490d0120052802b40641002802c0a3c68000118080808000000c010b200020043a0000200020052903f802370001200541b0066a41286a200541b8056a41286a290300370300200541b0066a41206a200541b8056a41206a290300370300200541b0066a41186a200541b8056a41186a290300370300200541b0066a41106a200541b8056a41106a290300370300200541b0066a41086a2207200541b8056a41086a290300370300200041096a200541f8026a41086a290300370000200041116a200541f8026a41106a290300370000200041196a200541f8026a41186a290300370000200041216a200541f8026a41206a290300370000200041286a2005419f036a280000360000200520052903b8053703b006200541d0046a41086a22042011360200200541e4046a20054198016a41086a290300370200200541ec046a20054198016a41106a290300370200200541f4046a20054198016a41186a290300370200200520133602d404200520123602d00420052005290398013702dc04200520103602fc04200541c8036a41086a22014101360200200541013602c8032005200c3a00b0072005200541b0076a3602cc03200541d0046a200541c8036a10e78d80800020012007280200200541dc066a22072802002203200341284b22031b360200200520052802b406200541b0066a41047220031b3602cc03200520052802b0063602c803200541d0046a200541c8036a10e78d808000200041d8006a200541d0046a41286a290200370200200041d0006a200541d0046a41206a290200370200200041c8006a200541d0046a41186a290200370200200041c0006a200541d0046a41106a290200370200200041386a2004290200370200200020052902d0043702302000200b36022c20072802004129490d0020052802b40641002802c0a3c68000118080808000000b200528028004450d0020052802ac044129490d0020052802840441002802c0a3c68000118080808000000b200a41002802c0a3c68000118080808000000c060b4188d6c28000412f41fcd6c2800010f880808000000b2000200929020037023020002008290000370001200041d8006a200941286a290200370200200041d0006a200941206a290200370200200041c8006a200941186a290200370200200041c0006a200941106a290200370200200041386a200941086a290200370200200041096a200841086a290000370000200041116a200841106a290000370000200041196a200841186a290000370000200041216a200841206a290000370000200041286a200841276a2800003600002000200a36022c200020063a00000c040b4188d6c28000412f41b8d6c2800010f880808000000b2000200a360230200020093a0004200041073a0000200020082900003700052000412c6a200841276a280000360000200041256a200841206a2900003700002000411d6a200841186a290000370000200041156a200841106a2900003700002000410d6a200841086a2900003700000c020b0240200141286a28020022042001411c6a220a2802002207470d00200a10a889808000200128021c2107200128022821040b200141206a280200200141246a28020020046a22044100200720042007491b6b4102746a200b3602002001200128022841016a360228200141186a2802002207200b4b0d00200b200741e4d7c2800010f980808000000b200141146a280200200b4107746a22072d0060212e20072d005c210b20072d0058210a20072d0054210920072d0050210620072d004c210c20072d0048211020072d0044211120072d0040211220072d003c211420072d0038211620072d0034211e20072d0030212020072d002c212120072d0028212220072d0024212420072d0020212520072d001c212620072d0018212f20072d0014212320072d0010211f20072d000c211320072d0008210d20072d0004210820072d00002104200741043a0004200741083a0000200741e1006a2130200741dd006a2131200741d9006a2132200741d5006a2133200741d1006a2134200741cd006a2135200741c9006a2136200741c5006a2137200741c1006a21382007413d6a2139200741396a213a200741356a213b200741316a213c2007412d6a213d200741296a213e200741256a213f200741216a21402007411d6a212d200741196a212c200741156a212b200741116a212a2007410d6a2129200741096a2128200741056a21270240024020044108460d00200541b8056a41026a200741036a2d00003a0000200541b0076a41026a202741026a2d00003a0000200541b8016a41026a202841026a2d00003a0000200541bc086a41026a202941026a2d00003a0000200541b8086a41026a202a41026a2d00003a0000200520072f00013b01b805200520272f00003b01b007200520282f00003b01b801200520292f00003b01bc082005202a2f00003b01b808200541b4086a41026a202b41026a2d00003a0000200541b0086a41026a202c41026a2d00003a0000200541ac086a41026a202d41026a2d00003a0000200541a8086a41026a204041026a2d00003a0000200541a4086a41026a203f41026a2d00003a00002005202b2f00003b01b4082005202c2f00003b01b0082005202d2f00003b01ac08200520402f00003b01a8082005203f2f00003b01a408200541a0086a41026a203e41026a2d00003a00002005203e2f00003b01a0082005419c086a41026a203d41026a2d00003a00002005203d2f00003b019c0820054198086a41026a203c41026a2d00003a00002005203c2f00003b01980820054194086a41026a203b41026a2d00003a00002005203b2f00003b01940820054190086a41026a203a41026a2d00003a00002005203a2f00003b0190082005418c086a41026a203941026a2d00003a0000200520392f00003b018c0820054188086a41026a203841026a2d00003a0000200520382f00003b01880820054184086a41026a203741026a2d00003a0000200520372f00003b01840820054180086a41026a203641026a2d00003a0000200520362f00003b018008200541fc076a41026a203541026a2d00003a0000200520352f00003b01fc07200541f8076a41026a203441026a2d00003a0000200520342f00003b01f807200541f4076a41026a203341026a2d00003a0000200520332f00003b01f407200541f0076a41026a203241026a2d00003a0000200520322f00003b01f007200541ec076a41026a203141026a2d00003a0000200520312f00003b01ec07200541b0066a41026a203041026a2d00003a0000200520302f00003b01b006200541f0016a200741fc006a280000360200200541e8016a200741f4006a290000370300200541d8016a41086a200741ec006a290000370300200520072900643703d801200a2128200421272009210a20062109200c21062010210c20112110201221112014211220162114201e21162020211e2021212020222121202421222025212420262125202f21260c010b200541b8056a41026a202741026a2d00003a0000200541b0076a41026a202841026a2d00003a0000200541b8016a41026a202941026a2d00003a0000200541bc086a41026a202a41026a2d00003a0000200541b8086a41026a202b41026a2d00003a0000200520272f00003b01b805200520282f00003b01b007200520292f00003b01b8012005202a2f00003b01bc082005202b2f00003b01b808200541b4086a41026a202c41026a2d00003a0000200541b0086a41026a202d41026a2d00003a0000200541ac086a41026a204041026a2d00003a0000200541a8086a41026a203f41026a2d00003a0000200541a4086a41026a203e41026a2d00003a00002005202c2f00003b01b4082005202d2f00003b01b008200520402f00003b01ac082005203f2f00003b01a8082005203e2f00003b01a408200541a0086a41026a203d41026a2d00003a00002005203d2f00003b01a0082005419c086a41026a203c41026a2d00003a00002005203c2f00003b019c0820054198086a41026a203b41026a2d00003a00002005203b2f00003b01980820054194086a41026a203a41026a2d00003a00002005203a2f00003b01940820054190086a41026a203941026a2d00003a0000200520392f00003b0190082005418c086a41026a203841026a2d00003a0000200520382f00003b018c0820054188086a41026a203741026a2d00003a0000200520372f00003b01880820054184086a41026a203641026a2d00003a0000200520362f00003b01840820054180086a41026a203541026a2d00003a0000200520352f00003b018008200541fc076a41026a203441026a2d00003a0000200520342f00003b01fc07200541f8076a41026a203341026a2d00003a0000200520332f00003b01f807200541f4076a41026a203241026a2d00003a0000200520322f00003b01f407200541f0076a41026a203141026a2d00003a0000200520312f00003b01f007200541ec076a41026a203041026a2d00003a0000200520302f00003b01ec07200b2128202e210b20082127200d21082013210d201f21132023211f202f21230b200541d7046a200541b0076a41026a2d00003a0000200541db046a200541b8016a41026a2d00003a0000200541df046a200541bc086a41026a2d00003a0000200520052f01b8053b00d104200520083a00d404200520052f01b0073b00d5042005200d3a00d804200520052f01b8013b00d904200520133a00dc04200520052f01bc083b00dd042005200541b8056a41026a2d00003a00d304200520273a00d004200541e3046a200541b8086a41026a2d00003a0000200541e7046a200541b4086a41026a2d00003a0000200541eb046a200541b0086a41026a2d00003a0000200541ef046a200541ac086a41026a2d00003a00002005201f3a00e004200520233a00e404200520263a00e804200520253a00ec04200520052f01b8083b00e104200520052f01b4083b00e504200520052f01b0083b00e904200520052f01ac083b00ed04200541f3046a200541a8086a41026a2d00003a0000200541f7046a200541a4086a41026a2d00003a0000200541fb046a200541a0086a41026a2d00003a0000200541ff046a2005419c086a41026a2d00003a0000200520243a00f004200520223a00f404200520213a00f804200520203a00fc04200520052f01a8083b00f104200520052f01a4083b00f504200520052f01a0083b00f904200520052f019c083b00fd042005201e3a00800520054183056a20054198086a41026a2d00003a0000200520052f0198083b008105200520163a00840520054187056a20054194086a41026a2d00003a0000200520052f0194083b008505200520143a0088052005418b056a20054190086a41026a2d00003a0000200520052f0190083b008905200520123a008c052005418f056a2005418c086a41026a2d00003a0000200520052f018c083b008d05200520113a00900520054193056a20054188086a41026a2d00003a0000200520052f0188083b009105200520103a00940520054197056a20054184086a41026a2d00003a0000200520052f0184083b0095052005200c3a0098052005419b056a20054180086a41026a2d00003a0000200520052f0180083b009905200520063a009c052005419f056a200541fc076a41026a2d00003a0000200520052f01fc073b009d05200520093a00a005200541a3056a200541f8076a41026a2d00003a0000200520052f01f8073b00a1052005200a3a00a405200541a7056a200541f4076a41026a2d00003a0000200520052f01f4073b00a505200520283a00a805200541ab056a200541f0076a41026a2d00003a0000200520052f01f0073b00a9052005200b3a00ac05200541af056a200541ec076a41026a2d00003a0000200520052f01ec073b00ad05200541b4056a41026a200541b0066a41026a2d00003a0000200520052f01b0063b01b4054108212a200541f8026a41086a200541d8016a41086a290300370300200541f8026a41106a200541d8016a41106a290300370300200541f8026a41186a200541d8016a41186a280200360200200520052903d8013703f802200541d0046a41046a210702400240024002400240024002402027417c6a41ff01712229410420294104491b417f6a0e020102000b200541ad056a2107200541a9056a2103200541a5056a2129200541a1056a212b2005419d056a212c20054199056a212d20054195056a214020054191056a213f2005418d056a213e20054189056a213d20054185056a213c20054181056a213b200541fd046a213a200541f9046a2139200541f5046a2138200541f1046a2137200541ed046a2136200541e9046a2135200541e5046a2134200541e1046a2133200541dd046a2132200541d9046a2131200541d5046a2130200541d0046a410172211d20044108470d02200541e2076a2104200541e6076a210e200541e9076a211b200541ec076a211c200541f0076a212f200541f4076a2141200541f8076a2142200541fc076a214320054180086a214420054184086a214520054188086a21462005418c086a214720054190086a214820054194086a214920054198086a214a2005419c086a214b200541a0086a214c200541a4086a214d200541a8086a214e200541ac086a214f200541b0086a2150200541b4086a2151200541b8086a2152200541bc086a21530c030b200541b0066a41286a20054180056a220b41286a290200370300200541b0066a41206a200b41206a290200370300200541b0066a41186a200b41186a290200370300200541b0066a41106a200b41106a290200370300200541b0066a41086a200b41086a290200370300200541e0066a41086a200741086a290200370300200541e0066a41106a200741106a290200370300200541e0066a41186a200741186a290200370300200541e0066a41206a220a200741206a290200370300200541e0066a41286a200741286a2802003602002005200b2902003703b006200520072902003703e006024020044108460d00200541ac076a41026a2207200541b4056a41026a2d00003a000020054190076a41086a2204200541f8026a41086a29030037030020054190076a41106a220b200541f8026a41106a29030037030020054190076a41186a2203200541f8026a41186a280200360200200520052f01b4053b01ac07200520052903f80237039007200541b8056a41286a22084100360200200541b8056a201d201d201b6a10f686808000200541b0076a41286a22092008280200360200200541b0076a41206a2208200541b8056a41206a290200370300200541b0076a41186a2206200541b8056a41186a290200370300200541b0076a41106a220c200541b8056a41106a290200370300200541b0076a41086a220d200541b8056a41086a290200370300200520052902b8053703b0072005202e3a00d801200520052f01ac073b00d901200520072d00003a00db01200541f4016a2003280200360200200541ec016a200b290300370200200541e4016a200429030037020020052005290390073702dc01200541a0026a200928020036020020054198026a200829030037020020054190026a200629030037020020054188026a200c290300370200200541d8016a41286a200d290300370200200520052903b0073702f801200541a5026a200e3a0000200541a4026a201c3a0000200141dc006a200541d8016a10958d8080001a0b200541d8016a41286a2207200541c8036a41286a290300370300200541d8016a41206a2204200541c8036a41206a290300370300200541d8016a41186a220b200541c8036a41186a290300370300200541d8016a41106a2201200541c8036a41106a290300370300200541d8016a41086a2203200541c8036a41086a290300370300200520052903c8033703d801200541b8056a41086a2208200541b0066a41086a280200200541dc066a22092802002206200641284b22061b360200200520052802b406200541b0066a41047220061b3602bc05200520052802b0063602b805200541d8016a200541b8056a10e78d808000200041d8006a2007290300370200200041d0006a2004290300370200200041c8006a200b290300370200200041c0006a2001290300370200200041386a2003290300370200200020052903d801370230200541c3056a200541e0066a41086a290300370000200541cb056a200541e0066a41106a290300370000200541d3056a200541e0066a41186a290300370000200541db056a200a290300370000200541e3056a200541e0066a41286a280200360000200520052903e0063700bb05200041053a0000200020052900b805370001200041096a2008290000370000200041116a200541b8056a41106a290000370000200041196a200541b8056a41186a290000370000200041216a200541b8056a41206a290000370000200041286a200541df056a29000037000020092802004129490d0320052802b40641002802c0a3c68000118080808000000c030b200541b8056a41286a200541d0046a41286a220b41286a290200370300200541b8056a41206a200b41206a290200370300200541b8056a41186a200b41186a290200370300200541b8056a41106a200b41106a290200370300200541b8056a41086a200b41086a290200370300200541e8056a41086a200741086a290200370300200541e8056a41106a200741106a290200370300200541e8056a41186a200741186a290200370300200541e8056a41206a220a200741206a2802003602002005200b2902003703b805200520072902003703e805024020044108460d00200541ac066a41026a2207200541b4056a41026a2d00003a000020054190066a41086a2204200541f8026a41086a29030037030020054190066a41106a220b200541f8026a41106a29030037030020054190066a41186a2208200541f8026a41186a280200360200200520052f01b4053b01ac06200520052903f80237039006200541b0066a41286a22094100360200200541b0066a201d201d201b6a10f686808000200541b0076a41286a22062009280200360200200541b0076a41206a2209200541b0066a41206a290200370300200541b0076a41186a220c200541b0066a41186a290200370300200541b0076a41106a220d200541b0066a41106a290200370300200541b0076a41086a2210200541b0066a41086a290200370300200520052902b0063703b0072005202e3a00d801200520052f01ac063b00d901200520072d00003a00db01200541f4016a2008280200360200200541ec016a200b290300370200200541e4016a200429030037020020052005290390063702dc01200541a0026a200628020036020020054198026a200929030037020020054190026a200c29030037020020054188026a200d290300370200200541d8016a41286a2010290300370200200520052903b0073702f801200541a5026a200e3a0000200541a4026a201c3a0000200141dc006a200541d8016a10958d8080001a0b200541b0066a41286a2207200541c8036a41286a290300370300200541b0066a41206a2204200541c8036a41206a290300370300200541b0066a41186a220b200541c8036a41186a290300370300200541b0066a41106a2208200541c8036a41106a290300370300200541b0066a41086a2209200541c8036a41086a290300370300200520052903c8033703b006200541d8016a41086a200541b8056a41086a280200200541e4056a2206280200220c200c41284b220c1b360200200520052802bc05200541b8056a410472200c1b3602dc01200520052802b8053602d801200541b0066a200541d8016a10e78d808000200541a8026a2007290300370200200541a0026a200429030037020020054198026a200b29030037020020054190026a200829030037020020054188026a2009290300370200200541e4016a200541e8056a41086a290300370200200541ec016a200541e8056a41106a290300370200200541f4016a200541e8056a41186a290300370200200541fc016a200a280200360200200520052903b00637028002200520052903e8053702dc01200541063a00d80120002001200541d8016a20034101108a8680800020062802004129490d0220052802bc0541002802c0a3c68000118080808000000c020b200541e2076a41026a200541b4056a41026a2d00003a0000200541b8056a41086a200541f8026a41086a290300370300200541b8056a41106a200541f8026a41106a290300370300200541b8056a41186a200541f8026a41186a280200360200200520052f01b4053b01e207200520052903f8023703b805200541e6076a2104200541e9076a210e200541ec076a211b200541f0076a211c200541f4076a212f200541f8076a2141200541fc076a214220054180086a214320054184086a214420054188086a21452005418c086a214620054190086a214720054194086a214820054198086a21492005419c086a214a200541a0086a214b200541a4086a214c200541a8086a214d200541ac086a214e200541b0086a214f200541b4086a2150200541b8086a2151200541bc086a2152200541b8016a21532027212a20082127200d21082013210d201f21132023211f202621232025212620242125202221242021212220202121201e21202016211e20142116201221142011211220102111200c21102006210c20092106200a21092028210a200b2128202e210b0b2053201d2f00003b0000205220302f00003b0000205120312f00003b0000205020322f00003b0000204f20332f00003b0000205341026a201d41026a2d00003a0000205241026a203041026a2d00003a0000205141026a203141026a2d00003a0000205041026a203241026a2d00003a0000204f41026a203341026a2d00003a0000204e41026a203441026a2d00003a0000204e20342f00003b0000204d20352f00003b0000204d41026a203541026a2d00003a0000204c20362f00003b0000204c41026a203641026a2d00003a0000204b20372f00003b0000204b41026a203741026a2d00003a0000204a41026a203841026a2d00003a0000204a20382f00003b0000204941026a203941026a2d00003a0000204920392f00003b0000204841026a203a41026a2d00003a00002048203a2f00003b0000204741026a203b41026a2d00003a00002047203b2f00003b0000204641026a203c41026a2d00003a00002046203c2f00003b0000204541026a203d41026a2d00003a00002045203d2f00003b0000204441026a203e41026a2d00003a00002044203e2f00003b0000204341026a203f41026a2d00003a00002043203f2f00003b0000204241026a204041026a2d00003a0000204220402f00003b0000204141026a202d41026a2d00003a00002041202d2f00003b0000202f41026a202c41026a2d00003a0000202f202c2f00003b0000201c41026a202b41026a2d00003a0000201c202b2f00003b0000201b41026a202941026a2d00003a0000201b20292f00003b0000200e41026a200341026a2d00003a0000200e20032f00003b0000200441026a200741026a2d00003a0000200420072f00003b0000200541d8016a41286a200541c8036a41286a290300370300200541d8016a41206a200541c8036a41206a290300370300200541d8016a41186a200541c8036a41186a290300370300200541d8016a41106a200541c8036a41106a290300370300200541d8016a41086a200541c8036a41086a290300370300200520052903c8033703d801024002400240200141286a2802002207450d0020012007417f6a360228200141246a22072007280200220741016a220441002001411c6a280200220320042003491b6b360200200141206a28020020074102746a2802002204200141186a28020022074f0d02200128021420044107746a220741046a200720072d00004108461b10e3858080002007202a3a0000200720273a0004200720083a00082007200d3a000c200720052f00b8013b0001200741036a200541b8016a41026a2d00003a0000200720052f00bc083b0005200741076a200541bc086a41026a2d00003a0000200720052f00b8083b00092007410b6a200541b8086a41026a2d00003a0000200720052f00b4083b000d2007410f6a200541b4086a41026a2d00003a0000200720133a00102007201f3a0014200720233a0018200720263a001c200720052f00b0083b0011200741136a200541b0086a41026a2d00003a0000200720052f00ac083b0015200741176a200541ac086a41026a2d00003a0000200720052f00a8083b00192007411b6a200541a8086a41026a2d00003a0000200720052f00a4083b001d2007411f6a200541a4086a41026a2d00003a0000200720253a0020200720243a0024200720223a0028200720213a002c200720052f00a0083b0021200741236a200541a0086a41026a2d00003a0000200720052f009c083b0025200741276a2005419c086a41026a2d00003a0000200720052f0098083b00292007412b6a20054198086a41026a2d00003a0000200720052f0094083b002d2007412f6a20054194086a41026a2d00003a0000200720203a0030200741336a20054190086a41026a2d00003a0000200720052f0090083b00312007201e3a0034200741376a2005418c086a41026a2d00003a0000200720052f008c083b0035200720163a00382007413b6a20054188086a41026a2d00003a0000200720052f0088083b0039200720143a003c2007413f6a20054184086a41026a2d00003a0000200720052f0084083b003d200720123a0040200741c3006a20054180086a41026a2d00003a0000200720052f0080083b0041200720113a0044200741c7006a200541fc076a41026a2d00003a0000200720052f00fc073b0045200720103a0048200741cb006a200541f8076a41026a2d00003a0000200720052f00f8073b00492007200c3a004c200741cf006a200541f4076a41026a2d00003a0000200720052f00f4073b004d200720063a0050200741d3006a200541f0076a41026a2d00003a0000200720052f00f0073b0051200720093a0054200741d7006a200541ec076a41026a2d00003a0000200720052f00ec073b00552007200a3a0058200741db006a200541e9076a41026a2d00003a0000200720052f00e9073b0059200720283a005c200741df006a200541e6076a41026a2d00003a0000200720052f00e6073b005d2007200b3a0060200741e3006a200541e2076a41026a2d00003a0000200720052f01e2073b0061200741fc006a200541d0056a280200360000200741f4006a200541c8056a290300370000200741ec006a200541b8056a41086a290300370000200720052903b8053700640c010b0240200141186a28020022072001280210470d00200141106a2007109e86808000200128021821070b200128021420074107746a2207202a3a0000200720052f00b8013b0001200720273a0004200720052f00bc083b0005200720083a0008200720052f00b8083b00092007200d3a000c200720052f00b4083b000d200741036a200541b8016a41026a2d00003a0000200741076a200541bc086a41026a2d00003a00002007410b6a200541b8086a41026a2d00003a00002007410f6a200541b4086a41026a2d00003a0000200720133a00102007201f3a0014200720233a0018200720263a001c200720052f00b0083b0011200741136a200541b0086a41026a2d00003a0000200720052f00ac083b0015200741176a200541ac086a41026a2d00003a0000200720052f00a8083b00192007411b6a200541a8086a41026a2d00003a0000200720052f00a4083b001d2007411f6a200541a4086a41026a2d00003a0000200720253a0020200741236a200541a0086a41026a2d00003a0000200720052f00a0083b0021200720243a0024200741276a2005419c086a41026a2d00003a0000200720052f009c083b0025200720223a00282007412b6a20054198086a41026a2d00003a0000200720052f0098083b0029200720213a002c2007412f6a20054194086a41026a2d00003a0000200720052f0094083b002d200720203a0030200741336a20054190086a41026a2d00003a0000200720052f0090083b00312007201e3a0034200741376a2005418c086a41026a2d00003a0000200720052f008c083b0035200720163a00382007413b6a20054188086a41026a2d00003a0000200720052f0088083b0039200720143a003c2007413f6a20054184086a41026a2d00003a0000200720052f0084083b003d200720123a0040200741c3006a20054180086a41026a2d00003a0000200720052f0080083b0041200720113a0044200741c7006a200541fc076a41026a2d00003a0000200720052f00fc073b0045200720103a0048200741cb006a200541f8076a41026a2d00003a0000200720052f00f8073b00492007200c3a004c200741cf006a200541f4076a41026a2d00003a0000200720052f00f4073b004d200720063a0050200741d3006a200541f0076a41026a2d00003a0000200720052f00f0073b0051200720093a0054200741d7006a200541ec076a41026a2d00003a0000200720052f00ec073b00552007200a3a0058200741db006a200541e9076a41026a2d00003a0000200720052f00e9073b0059200720283a005c200741df006a200541e6076a41026a2d00003a0000200720052f00e6073b005d2007200b3a0060200741e3006a200541e2076a41026a2d00003a0000200720052f01e2073b0061200741fc006a200541d0056a280200360000200741f4006a200541c8056a290300370000200741ec006a200541c0056a290300370000200720052903b80537006420012001280218220441016a3602180b200020052903d801370228200020052f00b0073b0005200020052902b00637020c200041d0006a20054180026a290300370200200041c8006a200541f8016a290300370200200041c0006a200541d8016a41186a290300370200200041386a200541d8016a41106a290300370200200041306a200541d8016a41086a290300370200200041076a200541b0076a41026a2d00003a0000200041146a200541b0066a41086a2902003702002000411c6a200541b0066a41106a290200370200200041246a200541b0066a41186a280200360200200041063a0000200020052f00d8013b0001200041036a200541d8016a41026a2d00003a000020002004360208200041003a00040c020b2004200741d4d7c2800010f980808000000b20052d00d004417c6a41ff01712207410420074104491b417f6a4102490d00200541d0046a10e3858080000b200528028004450d00200f2802284129490d0020052802840441002802c0a3c68000118080808000000b20022d0000417c6a41ff01712207410420074104491b417e6a4103490d010b200210e3858080000b200541c0086a2480808080000bab1903057f017e177f2380808080004190046b2205248080808000024002400240024002400240024002400240024002400240024020022d00000d00200228020421020240200141286a28020022062001411c6a22072802002208470d00200710a889808000200128021c2108200128022821060b200141206a280200200141246a28020020066a22064100200820062008491b6b4102746a20023602002001200128022841016a360228200141186a280200220820024b0d012002200841e4d7c2800010f980808000000b200541a0016a200241196a29000037030020054198016a200241116a29000037030020054190016a200241096a29000037030020052002290001370388012003280208220841017621020240024020084101710d002002200328020422084b0d04200541003a00b003200520023602ac03200520032802003602a8030c010b2002200328020422084b0d04200220084f0d052005200328020022083602a803200520023602ac03200541b1036a200820026a2d000041f001713a0000200541013a00b0030b200541c4026a200120054188016a200541a8036a10868680800020052802c802210220052802c4020d010240200141286a28020022062001411c6a22072802002208470d00200710a889808000200128021c2108200128022821060b200141206a280200200141246a28020020066a22064100200820062008491b6b4102746a20023602002001200128022841016a360228200141186a280200220820024d0d090b200141146a28020020024107746a22022d00002108200541296a200241016a41df0010848e8080001a200241043a0004200241083a0000200541086a41086a200241ec006a290200370300200541186a200241f4006a290200370300200541206a200241fc006a2802003602002005200229026437030820022802602102200541a9016a200541296a41df0010848e8080001a02400240024002400240024020084108470d00200541a8036a200541a9016a41036a41dc0010848e8080001a20052001360288042005200336028c042005200236028404200541c4026a20042001200541a8036a2003108c8680800020052802c40222034103460d0520052802a4032109200529029c03210a20052802980321062005280294032107200528029003210b200528028c03210c200528028803210d200528028403210e200528028003210f20052802fc02211020052802f802211120052802f402211220052802f002211320052802ec02211420052802e802211520052802e402211620052802e002211720052802dc02211820052802d802211920052802d402211a20052802d002211b20052802cc02211c20052802c8022108410121044108211d20030e03030201030b20032802082109200328020421192003280200211d200541a8036a410172200541296a41df0010848e8080001a20052001360288042005200336028c04200520083a00a803200541c4026a20042001200541a8036a2003108c8680800020052802c40222034103460d0420052902a003210a200528029c03211e20052802980321062005280294032107200528029003210b200528028c03210c200528028803210d200528028403210e200528028003210f20052802fc02211020052802f802211120052802f402211220052802f002211320052802ec02211420052802e802211520052802e402211620052802e002211720052802dc02211820052802d802211a20052802d402211b20052802d002211c20052802cc02211f20052802c802210802400240024020030e03000102000b200941017621040240024020094101710d000240200420194b0d00410021190c020b2004201941f492c68000109581808000000b200420194b0d0c200420194f0d0d201d20046a2d00004170712120410121190b200a422088a7210941002103200541c4026a41286a22214100360200200541c4026a201d201d20046a10f58d808000200541c8036a220441286a2021280200360200200441206a200541c4026a41206a290200370200200441186a200541c4026a41186a290200370200200441106a200541c4026a41106a2902003702004108211d200441086a200541c4026a41086a290200370200200420052902c402370200200541f5036a20203a0000200541f4036a20193a0000200541b4036a200541086a41086a290300370200200541bc036a200541086a41106a290300370200200541c4036a200541086a41186a280200360200200520023602a803200520052903083702ac03200141dc006a200541a8036a10958d8080001a200a422086201ead84210a41012104201a2119201b211a201c211b201f211c0c040b200541a8026a41186a200541086a41186a280200360200200541a8026a41106a200541086a41106a290300370300200541a8026a41086a200541086a41086a290300370300200520052903083703a802200841ff0171211d200841807e71210341002104201821192017211820162117201521162014211520132114201221132011211220102111200f2110200e210f200d210e200c210d200b210c2007210b20062107201e210620022109201f21080c030b200941017621030240024020094101710d000240200320194b0d00410021040c020b2003201941f492c68000109581808000000b200320194b0d0c200320194f0d0d201d20036a2d00004170712108410121040b200541c4026a41286a22064100360200200541c4026a201d201d20036a10f58d808000200541c8036a220341286a2006280200360200200341206a200541c4026a41206a290200370200200341186a200541c4026a41186a290200370200200341106a200541c4026a41106a290200370200200341086a200541c4026a41086a290200370200200320052902c402370200200541f5036a20083a0000200541f4036a20043a0000200541b4036a200541086a41086a290300370200200541bc036a200541086a41106a290300370200200541c4036a200541086a41186a280200360200200520023602a803200520052903083702ac03200141dc006a200541a8036a10958d8080001a0b410221040c020b41002103410021040b20054188026a41186a200541a8026a41186a28020036020020054188026a41106a200541a8026a41106a29030037030020054188026a41086a200541a8026a41086a290300370300200520052903a80237038802201d20037221030240200141286a2802002202450d0020012002417f6a360228200141246a22022002280200220241016a221d41002001411c6a280200221e201d201e491b6b360200200141206a28020020024102746a2802002202200141186a280200221d4f0d0c200128021420024107746a220141046a200120012d00004108461b10e385808000200120093602602001200a37025820012006360254200120073602502001200b36024c2001200c3602482001200d3602442001200e3602402001200f36023c2001201036023820012011360234200120123602302001201336022c2001201436022820012015360224200120163602202001201736021c20012018360218200120193602142001201a3602102001201b36020c2001201c3602082001200836020420012003360200200141fc006a200541a0026a280200360200200141f4006a20054198026a290300370200200141ec006a20054188026a41086a29030037020020012005290388023702640c010b0240200141186a28020022022001280210470d00200141106a2002109e86808000200128021821020b200128021420024107746a220220093602602002200a37025820022006360254200220073602502002200b36024c2002200c3602482002200d3602442002200e3602402002200f36023c2002201036023820022011360234200220123602302002201336022c2002201436022820022015360224200220163602202002201736021c20022018360218200220193602142002201a3602102002201b36020c2002201c3602082002200836020420022003360200200241fc006a200541a0026a280200360200200241f4006a20054198026a290300370200200241ec006a20054190026a290300370200200220052903880237026420012001280218220241016a3602180b200020043a0004200020023602000c0b0b20052802c80221020b200041033a0004200020023602000c090b2002200841f492c68000109581808000000b20022008418493c68000109581808000000b20022008419493c6800010f980808000000b20042019418493c68000109581808000000b20042019419493c6800010f980808000000b20032019418493c68000109581808000000b20032019419493c6800010f980808000000b2002200841e4d7c2800010f980808000000b2002201d41d4d7c2800010f980808000000b20054190046a2480808080000be54502117f017e23808080800041a0046b2205248080808000200541086a200441086a28020022063602002005200429020037030020052802042107200541e4006a200341e00010848e8080001a41012108200520062007410174220946220a3a00c4014101210b4102210c024002400240024002400240024002400240024002400240024002400240024002400240024002400240024020052d0064220d417c6a41ff0171220e4104200e4104491b0e051400010203140b200541c0036a41286a200541bc016a290200370300200541c0036a41206a200541b4016a290200370300200541c0036a41186a200541ac016a290200370300200541c0036a41106a200541a4016a290200370300200541c0036a41086a220f2005419c016a290200370300200541b0026a41086a200541f8006a290200370300200541b0026a41106a220b20054180016a290200370300200541b0026a41186a220e20054188016a28020036020020052005290294013703c0032005200541f0006a2902003703b002200541e4006a41086a2802002110200541e9006a2f00002103200541eb006a2d0000210720052d00682111200541e4006a412c6a2802002112200541e4006a41286a2802002113200520052802c003221436028002200520052802c403200541c0036a4104722215200541c0036a412c6a280200220c41284b22081b3602f8012005200f280200200c20081b22083602fc014101210c2003200741107472210f02400240200841017420146b2203200920066b470d00200541f8016a200510db8d8080002003460d0120052802c00321140b200541106a41286a201541286a280200360200200541106a41206a201541206a290200370300200541106a41186a201541186a290200370300200541106a41106a201541106a290200370300200541106a41086a201541086a290200370300200541c0006a41086a200541b0026a41086a290300370300200541c0006a41106a200b290300370300200541c0006a41186a200e280200360200200520052903b00237034020052015290200370310410521150c130b200428020421142004280200210c20042802082104200528028002211520052802fc012103200541e0026a41106a200541b8026a290300370200200541e0026a41186a200541b0026a41106a29030037020020054180036a200541b0026a41186a280200360200200520103602e402200520113a00e002200520052903b0023702e802200520123602880320052013360284032005200f3b00e1022005200f4110763a00e3022004200341017420156b6a221541017621040240024020154101710d00200420144b0d06200541003a00d001200520043602cc012005200c3602c8010c010b200420144b0d06200420144f0d072005200c3602c801200520043602cc01200541d1016a200c20046a2d000041f001713a0000200541013a00d0010b20022001200541e0026a200541c8016a1083868080004102210c024020052802ec0341294f0d00410521150c130b20052802c40341002802c0a3c6800011808080800000410521150c120b200541b0026a41286a200541b4016a290200370300200541b0026a41206a200541ac016a290200370300200541b0026a41186a200541a4016a290200370300200541b0026a41106a2005419c016a290200370300200541b0026a41086a220f20054194016a290200370300200541c8016a41086a200541f0006a290200370300200541c8016a41106a2214200541e4006a41146a290200370300200541c8016a41186a2211200541e4006a411c6a290200370300200541c8016a41206a2210200541e4006a41246a2802003602002005200529028c013703b002200520052902683703c801200520052802b0023602c8032005200f280200200541dc026a2212280200220f200f41284b220f1b3602c403200520052802b402200541b0026a410472200f1b3602c0034101210c0240200541c0036a200510db8d808000220f20052802c40341017420052802c8036b460d00200541106a41086a200541b0026a41146a290200370300200541106a41106a200541b0026a411c6a290200370300200541106a41186a200541b0026a41246a290200370300200541106a41206a2012280200360200200541c0006a41086a2014290300370300200541c0006a41106a2011290300370300200541c0006a41186a2010280200360200200520052902bc02370310200520052903d00137034020052f00c90120052d00cb0141107472210f4106211520052802cc01211020052d00c801211120052802b802211420052802b402211220052802b00221130c120b200541f8016a41086a200441086a2214280200221136020020142011200f6a360200200520042902003703f801200541c0036a2002200541c8016a20042001108b8680800020052802c00321100240024002400240024020052d00c4030e0400010204010b200541106a41086a200541c4026a290200370300200541206a200541cc026a290200370300200541286a200541d4026a290200370300200541306a200541dc026a280200360200200520052902bc02370310410021114106211520052802b802211420052802b402211220052802b00221130c150b200541c0036a41086a201036020020054190046a200541b0026a41286a29030037020020054188046a200541b0026a41206a29030037020020054180046a200541b0026a41186a290300370200200541f8036a200541b0026a41106a290300370200200541f0036a200541b0026a41086a290300370200200520052903b0023702e8034100210c200541003a00c403200541063a00c003200541e0026a2002200541c0036a200541f8016a4100108a8680800020052d00e00222154108460d01200541e2006a20052d00e3023a0000200541c0006a41086a200541f4026a290200370300200541c0006a41106a200541fc026a290200370300200541c0006a41186a20054184036a280200360200200520052f00e1023b0160200520052902ec0237034020052802e80221102005280288032113200528028c032112200528029003211420052802e4022111200541106a41286a200541bc036a280200360200200541106a41206a200541b4036a290200370300200541106a41186a200541ac036a290200370300200541106a41106a200541a4036a290200370300200541106a41086a2005419c036a29020037030020052005290294033703102011410876210f0c140b4102210c024020052802dc0241294f0d000c140b20052802b40241002802c0a3c68000118080808000000c130b20052802e402210420004103360200200020043602040c140b200041033602002000201036020420052802dc024129490d1320052802b40241002802c0a3c68000118080808000000c130b024002400240024002400240200a0d002005280294012114200541d8026a20054190016a280200360200200541d0026a200541e4006a41246a290200370300200541c8026a20054180016a290200370300200541c0026a200541f8006a290200370300200541b8026a200541f0006a290200370300200520052902683703b0022006410176220f20074f0d0120142005280200200f6a2d0000220f410f71200f41047620064101711b41246c6a220f2d00002111200f41023a000020114102460d02200541c8016a41096a200f41096a290000370000200541c8016a41116a200f41116a290000370000200541c8016a41196a200f41196a290000370000200541c8016a41206a200f41206a280000360000200541f8016a41086a200441086a2210280200220c360200200f29000121162010200c41016a360200200520113a00c801200520163700c901200520042902003703f801200541c0036a2002200541c8016a20042001108b8680800020052802c003210420052d00c4032211417e6a0e020407030b41032111200528029401211420052d00684103470d0441012108410721154101210b4101210c0c160b200f2007418cd5c2800010f980808000000b200541c8006a200541b0026a41106a290300370300200541c0006a41106a200541b0026a41186a290300370300200541c0006a41186a200541d0026a280200360200200520052903b80237034020052f00b10220052d00b30241107472210f4101210c0c110b200f2004360204200f41003a0000200541c0006a41086a200541b0026a41106a290300370300200541c0006a41106a200541b0026a41186a290300370300200541c0006a41186a200541b0026a41206a280200360200200520052903b80237034020052f00b10220052d00b30241107472210f201145210c0c100b200541ec036a200541b0026a41286a280200360200200541c0036a41246a200541b0026a41206a290300370200200541c0036a411c6a200541b0026a41186a290300370200200541c0036a41146a200541b0026a41106a290300370200200541cc036a200541b0026a41086a290300370200200520052903b0023702c403200520143602f003200541073a00c0034100210c200541e0026a2002200541c0036a200541f8016a4100108a86808000024020052d00e00222154108460d00200541e2006a20052d00e3023a0000200541c0006a41086a200541e0026a41146a290200370300200541c0006a41106a200541e0026a411c6a290200370300200541c0006a41186a200541e0026a41246a280200360200200520052f00e1023b0160200520052902ec0237034020052802e80221102005280288032113200528028c032112200528029003211420052802e4022111200541106a41286a200541bc036a280200360200200541306a200541b4036a290200370300200541106a41186a200541ac036a290200370300200541106a41106a200541a4036a290200370300200541106a41086a2005419c036a29020037030020052005290294033703102011410876210f0c110b20052802e402210420004103360200200020043602040c130b200541b0026a41286a200541e8006a220f41286a280200360200200541b0026a41206a200f41206a290200370300200541b0026a41186a200f41186a290200370300200541b0026a41106a200f41106a290200370300200541b0026a41086a200f41086a2902003703002005200f2902003703b00220042802082211410176210f0240024020114101710d00200f200428020422114b0d07200541003a00c8032005200f3602c403200520042802003602c0030c010b200f200428020422114b0d07200f20114f0d082005200428020022113602c0032005200f3602c403200541c9036a2011200f6a2d000041f001713a0000200541013a00c8030b20022001200541b0026a200541c0036a108386808000200541033a00c403200520143602f003200541073a00c003200541c8016a41086a200441086a280200360200200520042902003703c8014100210b200541e0026a2002200541c0036a200541c8016a4100108a86808000024020052d00e00222154108460d00200541e2006a20052d00e3023a0000200541c0006a41086a200541f4026a290200370300200541c0006a41106a200541fc026a290200370300200541c0006a41186a20054184036a280200360200200520052f00e1023b0160200520052902ec0237034020052802e80221102005280288032113200528028c032112200528029003211420052802e4022111200541386a200541bc036a280200360200200541306a200541b4036a290200370300200541106a41186a200541ac036a290200370300200541106a41106a200541a4036a290200370300200541106a41086a2005419c036a29020037030020052005290294033703102011410876210f410121084100210c0c120b20052802e402210420004103360200200020043602040c120b20054194016a210f0240200a0d00200541b0026a41286a200f41286a290200370300200541b0026a41206a200f41206a290200370300200541b0026a41186a200f41186a290200370300200541b0026a41106a200f41106a290200370300200541b0026a41086a2214200f41086a2902003703002005200f2902003703b0022005280290012112200541c8016a41286a200341286a280200360200200541c8016a41206a200341206a290200370300200541c8016a41186a200341186a290200370300200541c8016a41106a200341106a290200370300200541c8016a41086a200341086a290200370300200520032902003703c801200520052802b0023602c80320052014280200200541dc026a280200220f200f41284b22141b3602c403200520052802b402200541b0026a410472220f20141b3602c003200541c0036a200510db8d808000221420052802c40341017420052802c8036b2211470d0c2014200528020441017420052802086b470d0c41032115024020052d00c8014103470d00200541106a41086a200f41086a290200370300200541106a41106a200f41106a290200370300200541106a41186a200f41186a290200370300200541106a41206a200f41206a290200370300200541106a41286a200f41286a2802003602002005200f2902003703104101210c20052802b00221140c0e0b200541c0036a41286a200541c8016a41286a280200360200200541c0036a41206a200541c8016a41206a290300370300200541c0036a41186a200541c8016a41186a290300370300200541c0036a41106a200541c8016a41106a290300370300200541c0036a41086a200541c8016a41086a290300370300200520052903c8013703c003200541a0026a41086a200441086a220f28020020146a360200200520042902003703a002200541e0026a200541a0026a10dd8d80800020022001200541c0036a200541e0026a10838680800020054198046a200541b0026a41286a29030037020020054190046a200541b0026a41206a29030037020020054188046a200541b0026a41186a29030037020020054180046a200541b0026a41106a290300370200200541f8036a200541b0026a41086a290300370200200520052903b0023702f003200520123602ec03200541033a00c003200541f8016a41086a200f280200360200200520042902003703f8014100210c200541e0026a2002200541c0036a200541f8016a4100108a86808000024020052d00e00222154108460d00200541e2006a20052d00e3023a0000200541c0006a41086a200541f4026a290200370300200541c0006a41106a200541fc026a290200370300200541c0006a41186a20054184036a280200360200200520052f00e1023b0160200520052902ec0237034020052802e80221102005280288032113200528028c032112200528029003211420052802e4022111200541106a41286a200541bc036a280200360200200541106a41206a200541b4036a290200370300200541106a41186a200541ac036a290200370300200541106a41106a200541a4036a290200370300200541106a41086a2005419c036a29020037030020052005290294033703102011410876210f0c0e0b200020052802e402360204200041033602000c120b41032115200d41ff01714103460d0a20054198046a200f41286a29020037020020054190046a200f41206a29020037020020054188046a200f41186a29020037020020054180046a200f41106a290200370200200541f8036a200f41086a2902003702002005200f2902003702f003200528029001211120042802082214410176210f0240024020144101710d00200f200428020422144b0d09200541003a00e8022005200f3602e402200520042802003602e0020c010b200f200428020422144b0d09200f20144f0d0a2005200428020022143602e0022005200f3602e402200541e9026a2014200f6a2d000041f001713a0000200541013a00e8020b200220012003200541e0026a108386808000200520113602ec03200541033a00c003200541b0026a41086a200441086a280200360200200520042902003703b00241002108200541e0026a2002200541c0036a200541b0026a4100108a86808000024020052d00e00222154108460d00200541e2006a20052d00e3023a0000200541c0006a41086a200541f4026a290200370300200541c0006a41106a200541fc026a290200370300200541c0006a41186a20054184036a280200360200200520052f00e1023b0160200520052902ec0237034020052802e80221102005280288032113200528028c032112200528029003211420052802e4022111200541386a200541bc036a280200360200200541306a200541b4036a290200370300200541106a41186a200541ac036a290200370300200541106a41106a200541a4036a290200370300200541106a41086a2005419c036a29020037030020052005290294033703102011410876210f4101210b4100210c0c110b20052802e402210420004103360200200020043602040c110b2000410336020020002004360204200541b0026a10e585808000201441002802c0a3c68000118080808000000c100b2004201441f492c68000109581808000000b20042014418493c68000109581808000000b20042014419493c6800010f980808000000b200f201141f492c68000109581808000000b200f2011418493c68000109581808000000b200f2011419493c6800010f980808000000b200f201441f492c68000109581808000000b200f2014418493c68000109581808000000b200f2014419493c6800010f980808000000b200541186a200541a0016a290200370300200541206a200541a8016a290200370300200541286a200541b0016a290200370300200541306a200541b8016a290200370300200541386a200541c0016a280200360200200520054198016a29020037031041012108200528029001211220052802940121144101210b4101210c0c050b0240024002400240024002400240024020142011490d00200528020820146a221041017622112005280204220c4f0d012012200528020020116a2d00002211410f71201141047620104101711b41246c6a22112d00002110201141023a000020104102460d02200541f8016a41096a201141096a290000370000200541f8016a41116a201141116a290000370000200541f8016a41196a201141196a290000370000200541f8016a41206a201141206a280000360000200541a0026a41086a200441086a220c280200221536020020112900012116200c201420156a41016a360200200520103a00f801200520163700f901200520042902003703a002200541c0036a2002200541f8016a20042001108b8680800020052802c003210420052d00c403220c417e6a0e020304060b200541e2006a20052d00cb013a0000200541106a41086a200f41086a290200370300200541106a41106a200f41106a290200370300200541106a41186a200f41186a290200370300200541106a41206a200f41206a290200370300200541106a41286a200f41286a280200360200200520052f00c9013b01602005200f29020037031020052802b002211420052d00c8012115200541c0006a41086a200541dc016a290200370300200541c0006a41106a200541e4016a290200370300200541c0006a41186a200541ec016a280200360200200520052902d40137034020052f00cd0120052d00cf0141107472210f0c060b2011200c418cd5c2800010f980808000000b200541e0006a41026a20052d00cb013a0000200541106a41086a200f41086a290200370300200541106a41106a200f41106a290200370300200541106a41186a200f41186a290200370300200541106a41206a200f41206a290200370300200541106a41286a200f41286a280200360200200520052f00c9013b01602005200f29020037031020052802b002211420052d00c8012115200541c0006a41086a200541dc016a290200370300200541c0006a41106a200541e4016a290200370300200541c0006a41186a200541c8016a41246a280200360200200520052902d40137034020052f00cd0120052d00cf0141107472210f0c040b20054198046a200541b0026a41286a29030037030020054190046a200541b0026a41206a29030037030020054188046a200541b0026a41186a29030037030020054180046a200541b0026a41106a290300370300200541f8036a200541b0026a41086a290300370300200541c0036a41086a200541c8016a41086a290300370300200541c0036a41106a200541c8016a41106a290300370300200541c0036a41186a200541c8016a41186a290300370300200541c0036a41206a200541c8016a41206a290300370300200541c0036a41286a200541c8016a41286a280200360200200520052903b0023703f003200520052903c8013703c003200520123602ec034100210c200541e0026a2002200541c0036a200541a0026a4100108a8680800020052d00e00222154108460d01200541e2006a20052d00e3023a0000200541c0006a41086a200541f4026a290200370300200541c0006a41106a200541fc026a290200370300200541c0006a41186a20054184036a280200360200200520052f00e1023b0160200520052902ec0237034020052802e80221102005280288032113200528028c032112200528029003211420052802e4022111200541106a41286a200541bc036a280200360200200541306a200541b4036a290200370300200541106a41186a200541ac036a290200370300200541106a41106a200541a4036a290200370300200541106a41086a2005419c036a29020037030020052005290294033703102011410876210f0c040b2000410336020020002004360204024020052d00c8014103460d00200541c8016a10e4858080000b201241002802c0a3c680001180808080000020052802dc024129490d0820052802b40241002802c0a3c68000118080808000000c080b20052802e402210420004103360200200020043602040c070b20112004360204201141003a0000200541e2006a20052d00cb013a0000200541c0006a41086a200541dc016a290200370300200541c0006a41106a200541e4016a290200370300200541c0006a41186a200541ec016a280200360200200520052f00c9013b0160200520052902d40137034020052802f001211320052802d001211020052d00cc01211120052d00c801211520052802b002211420052f00cd01210420052d00cf012103200541106a41286a200f41286a280200360200200541106a41206a200f41206a290200370300200541106a41186a200f41186a290200370300200541106a41106a200f41106a290200370300200541106a41086a200f41086a2902003703002005200f2902003703102004200341107472210f200c45210c0c010b4101210c20052802f001211320052802d001211020052d00cc0121110b4101210b410021080c030b4107211520052802d802211220052802d402211320052802b402211020052d00b00221110b4100210b410121080c010b410121084101210b0b2000200f3b0009200020153a00042000200c360200200020052f01603b00052000201036020c200020113a0008200020052903403702102000201336022c20002012360230200020143602342000410b6a200f4110763a0000200041076a200541e2006a2d00003a0000200041186a200541c0006a41086a290300370200200041206a200541c0006a41106a290300370200200041286a200541c0006a41186a280200360200200041e0006a200541106a41286a280200360200200041d8006a200541106a41206a290300370200200041d0006a200541106a41186a290300370200200041c8006a200541106a41106a290300370200200041c0006a200541106a41086a29030037020020002005290310370238024002400240024020052d00642204417c6a41ff01712200410420004104491b417d6a0e020001040b200b450d0320052d006822004103460d03024020000e020004020b200541ec006a2200280200220420042802002204417f6a36020020044101460d020c030b2008450d0220044103460d020240024020040e020104000b200528028801220020002802002200417f6a36020020004101470d0320054188016a10e28a8080000c030b2005280268220020002802002200417f6a36020020004101470d02200541e8006a10e28a8080000c020b2005418c016a2200280200220420042802002204417f6a36020020044101470d010b200010e28a8080000b200541a0046a2480808080000bab1903057f017e177f2380808080004190046b2205248080808000024002400240024002400240024002400240024002400240024020022d00000d00200228020421020240200141286a28020022062001411c6a22072802002208470d00200710a889808000200128021c2108200128022821060b200141206a280200200141246a28020020066a22064100200820062008491b6b4102746a20023602002001200128022841016a360228200141186a280200220820024b0d012002200841e4d7c2800010f980808000000b200541a0016a200241196a29000037030020054198016a200241116a29000037030020054190016a200241096a29000037030020052002290001370388012003280208220841017621020240024020084101710d002002200328020422084b0d04200541003a00b003200520023602ac03200520032802003602a8030c010b2002200328020422084b0d04200220084f0d052005200328020022083602a803200520023602ac03200541b1036a200820026a2d000041f001713a0000200541013a00b0030b200541c4026a200120054188016a200541a8036a10878680800020052802c802210220052802c4020d010240200141286a28020022062001411c6a22072802002208470d00200710a889808000200128021c2108200128022821060b200141206a280200200141246a28020020066a22064100200820062008491b6b4102746a20023602002001200128022841016a360228200141186a280200220820024d0d090b200141146a28020020024107746a22022d00002108200541296a200241016a41df0010848e8080001a200241043a0004200241083a0000200541086a41086a200241ec006a290200370300200541186a200241f4006a290200370300200541206a200241fc006a2802003602002005200229026437030820022802602102200541a9016a200541296a41df0010848e8080001a02400240024002400240024020084108470d00200541a8036a200541a9016a41036a41dc0010848e8080001a20052001360288042005200336028c042005200236028404200541c4026a20042001200541a8036a2003108e8680800020052802c40222034103460d0520052802a4032109200529029c03210a20052802980321062005280294032107200528029003210b200528028c03210c200528028803210d200528028403210e200528028003210f20052802fc02211020052802f802211120052802f402211220052802f002211320052802ec02211420052802e802211520052802e402211620052802e002211720052802dc02211820052802d802211920052802d402211a20052802d002211b20052802cc02211c20052802c8022108410121044108211d20030e03030201030b20032802082109200328020421192003280200211d200541a8036a410172200541296a41df0010848e8080001a20052001360288042005200336028c04200520083a00a803200541c4026a20042001200541a8036a2003108e8680800020052802c40222034103460d0420052902a003210a200528029c03211e20052802980321062005280294032107200528029003210b200528028c03210c200528028803210d200528028403210e200528028003210f20052802fc02211020052802f802211120052802f402211220052802f002211320052802ec02211420052802e802211520052802e402211620052802e002211720052802dc02211820052802d802211a20052802d402211b20052802d002211c20052802cc02211f20052802c802210802400240024020030e03000102000b200941017621040240024020094101710d000240200420194b0d00410021190c020b2004201941f492c68000109581808000000b200420194b0d0c200420194f0d0d201d20046a2d00004170712120410121190b200a422088a7210941002103200541c4026a41286a22214100360200200541c4026a201d201d20046a10f58d808000200541c8036a220441286a2021280200360200200441206a200541c4026a41206a290200370200200441186a200541c4026a41186a290200370200200441106a200541c4026a41106a2902003702004108211d200441086a200541c4026a41086a290200370200200420052902c402370200200541f5036a20203a0000200541f4036a20193a0000200541b4036a200541086a41086a290300370200200541bc036a200541086a41106a290300370200200541c4036a200541086a41186a280200360200200520023602a803200520052903083702ac03200141dc006a200541a8036a10958d8080001a200a422086201ead84210a41012104201a2119201b211a201c211b201f211c0c040b200541a8026a41186a200541086a41186a280200360200200541a8026a41106a200541086a41106a290300370300200541a8026a41086a200541086a41086a290300370300200520052903083703a802200841ff0171211d200841807e71210341002104201821192017211820162117201521162014211520132114201221132011211220102111200f2110200e210f200d210e200c210d200b210c2007210b20062107201e210620022109201f21080c030b200941017621030240024020094101710d000240200320194b0d00410021040c020b2003201941f492c68000109581808000000b200320194b0d0c200320194f0d0d201d20036a2d00004170712108410121040b200541c4026a41286a22064100360200200541c4026a201d201d20036a10f58d808000200541c8036a220341286a2006280200360200200341206a200541c4026a41206a290200370200200341186a200541c4026a41186a290200370200200341106a200541c4026a41106a290200370200200341086a200541c4026a41086a290200370200200320052902c402370200200541f5036a20083a0000200541f4036a20043a0000200541b4036a200541086a41086a290300370200200541bc036a200541086a41106a290300370200200541c4036a200541086a41186a280200360200200520023602a803200520052903083702ac03200141dc006a200541a8036a10958d8080001a0b410221040c020b41002103410021040b20054188026a41186a200541a8026a41186a28020036020020054188026a41106a200541a8026a41106a29030037030020054188026a41086a200541a8026a41086a290300370300200520052903a80237038802201d20037221030240200141286a2802002202450d0020012002417f6a360228200141246a22022002280200220241016a221d41002001411c6a280200221e201d201e491b6b360200200141206a28020020024102746a2802002202200141186a280200221d4f0d0c200128021420024107746a220141046a200120012d00004108461b10e385808000200120093602602001200a37025820012006360254200120073602502001200b36024c2001200c3602482001200d3602442001200e3602402001200f36023c2001201036023820012011360234200120123602302001201336022c2001201436022820012015360224200120163602202001201736021c20012018360218200120193602142001201a3602102001201b36020c2001201c3602082001200836020420012003360200200141fc006a200541a0026a280200360200200141f4006a20054198026a290300370200200141ec006a20054188026a41086a29030037020020012005290388023702640c010b0240200141186a28020022022001280210470d00200141106a2002109e86808000200128021821020b200128021420024107746a220220093602602002200a37025820022006360254200220073602502002200b36024c2002200c3602482002200d3602442002200e3602402002200f36023c2002201036023820022011360234200220123602302002201336022c2002201436022820022015360224200220163602202002201736021c20022018360218200220193602142002201a3602102002201b36020c2002201c3602082002200836020420022003360200200241fc006a200541a0026a280200360200200241f4006a20054198026a290300370200200241ec006a20054190026a290300370200200220052903880237026420012001280218220241016a3602180b200020043a0004200020023602000c0b0b20052802c80221020b200041033a0004200020023602000c090b2002200841f492c68000109581808000000b20022008418493c68000109581808000000b20022008419493c6800010f980808000000b20042019418493c68000109581808000000b20042019419493c6800010f980808000000b20032019418493c68000109581808000000b20032019419493c6800010f980808000000b2002200841e4d7c2800010f980808000000b2002201d41d4d7c2800010f980808000000b20054190046a2480808080000be54502117f017e23808080800041a0046b2205248080808000200541086a200441086a28020022063602002005200429020037030020052802042107200541e4006a200341e00010848e8080001a41012108200520062007410174220946220a3a00c4014101210b4102210c024002400240024002400240024002400240024002400240024002400240024002400240024002400240024020052d0064220d417c6a41ff0171220e4104200e4104491b0e051400010203140b200541c0036a41286a200541bc016a290200370300200541c0036a41206a200541b4016a290200370300200541c0036a41186a200541ac016a290200370300200541c0036a41106a200541a4016a290200370300200541c0036a41086a220f2005419c016a290200370300200541b0026a41086a200541f8006a290200370300200541b0026a41106a220b20054180016a290200370300200541b0026a41186a220e20054188016a28020036020020052005290294013703c0032005200541f0006a2902003703b002200541e4006a41086a2802002110200541e9006a2f00002103200541eb006a2d0000210720052d00682111200541e4006a412c6a2802002112200541e4006a41286a2802002113200520052802c003221436028002200520052802c403200541c0036a4104722215200541c0036a412c6a280200220c41284b22081b3602f8012005200f280200200c20081b22083602fc014101210c2003200741107472210f02400240200841017420146b2203200920066b470d00200541f8016a200510db8d8080002003460d0120052802c00321140b200541106a41286a201541286a280200360200200541106a41206a201541206a290200370300200541106a41186a201541186a290200370300200541106a41106a201541106a290200370300200541106a41086a201541086a290200370300200541c0006a41086a200541b0026a41086a290300370300200541c0006a41106a200b290300370300200541c0006a41186a200e280200360200200520052903b00237034020052015290200370310410521150c130b200428020421142004280200210c20042802082104200528028002211520052802fc012103200541e0026a41106a200541b8026a290300370200200541e0026a41186a200541b0026a41106a29030037020020054180036a200541b0026a41186a280200360200200520103602e402200520113a00e002200520052903b0023702e802200520123602880320052013360284032005200f3b00e1022005200f4110763a00e3022004200341017420156b6a221541017621040240024020154101710d00200420144b0d06200541003a00d001200520043602cc012005200c3602c8010c010b200420144b0d06200420144f0d072005200c3602c801200520043602cc01200541d1016a200c20046a2d000041f001713a0000200541013a00d0010b20022001200541e0026a200541c8016a1083868080004102210c024020052802ec0341294f0d00410521150c130b20052802c40341002802c0a3c6800011808080800000410521150c120b200541b0026a41286a200541b4016a290200370300200541b0026a41206a200541ac016a290200370300200541b0026a41186a200541a4016a290200370300200541b0026a41106a2005419c016a290200370300200541b0026a41086a220f20054194016a290200370300200541c8016a41086a200541f0006a290200370300200541c8016a41106a2214200541e4006a41146a290200370300200541c8016a41186a2211200541e4006a411c6a290200370300200541c8016a41206a2210200541e4006a41246a2802003602002005200529028c013703b002200520052902683703c801200520052802b0023602c8032005200f280200200541dc026a2212280200220f200f41284b220f1b3602c403200520052802b402200541b0026a410472200f1b3602c0034101210c0240200541c0036a200510db8d808000220f20052802c40341017420052802c8036b460d00200541106a41086a200541b0026a41146a290200370300200541106a41106a200541b0026a411c6a290200370300200541106a41186a200541b0026a41246a290200370300200541106a41206a2012280200360200200541c0006a41086a2014290300370300200541c0006a41106a2011290300370300200541c0006a41186a2010280200360200200520052902bc02370310200520052903d00137034020052f00c90120052d00cb0141107472210f4106211520052802cc01211020052d00c801211120052802b802211420052802b402211220052802b00221130c120b200541f8016a41086a200441086a2214280200221136020020142011200f6a360200200520042902003703f801200541c0036a2002200541c8016a20042001108d8680800020052802c00321100240024002400240024020052d00c4030e0400010204010b200541106a41086a200541c4026a290200370300200541206a200541cc026a290200370300200541286a200541d4026a290200370300200541306a200541dc026a280200360200200520052902bc02370310410021114106211520052802b802211420052802b402211220052802b00221130c150b200541c0036a41086a201036020020054190046a200541b0026a41286a29030037020020054188046a200541b0026a41206a29030037020020054180046a200541b0026a41186a290300370200200541f8036a200541b0026a41106a290300370200200541f0036a200541b0026a41086a290300370200200520052903b0023702e8034100210c200541003a00c403200541063a00c003200541e0026a2002200541c0036a200541f8016a410010888680800020052d00e00222154108460d01200541e2006a20052d00e3023a0000200541c0006a41086a200541f4026a290200370300200541c0006a41106a200541fc026a290200370300200541c0006a41186a20054184036a280200360200200520052f00e1023b0160200520052902ec0237034020052802e80221102005280288032113200528028c032112200528029003211420052802e4022111200541106a41286a200541bc036a280200360200200541106a41206a200541b4036a290200370300200541106a41186a200541ac036a290200370300200541106a41106a200541a4036a290200370300200541106a41086a2005419c036a29020037030020052005290294033703102011410876210f0c140b4102210c024020052802dc0241294f0d000c140b20052802b40241002802c0a3c68000118080808000000c130b20052802e402210420004103360200200020043602040c140b200041033602002000201036020420052802dc024129490d1320052802b40241002802c0a3c68000118080808000000c130b024002400240024002400240200a0d002005280294012114200541d8026a20054190016a280200360200200541d0026a200541e4006a41246a290200370300200541c8026a20054180016a290200370300200541c0026a200541f8006a290200370300200541b8026a200541f0006a290200370300200520052902683703b0022006410176220f20074f0d0120142005280200200f6a2d0000220f410f71200f41047620064101711b41246c6a220f2d00002111200f41023a000020114102460d02200541c8016a41096a200f41096a290000370000200541c8016a41116a200f41116a290000370000200541c8016a41196a200f41196a290000370000200541c8016a41206a200f41206a280000360000200541f8016a41086a200441086a2210280200220c360200200f29000121162010200c41016a360200200520113a00c801200520163700c901200520042902003703f801200541c0036a2002200541c8016a20042001108d8680800020052802c003210420052d00c4032211417e6a0e020407030b41032111200528029401211420052d00684103470d0441012108410721154101210b4101210c0c160b200f2007418cd5c2800010f980808000000b200541c8006a200541b0026a41106a290300370300200541c0006a41106a200541b0026a41186a290300370300200541c0006a41186a200541d0026a280200360200200520052903b80237034020052f00b10220052d00b30241107472210f4101210c0c110b200f2004360204200f41003a0000200541c0006a41086a200541b0026a41106a290300370300200541c0006a41106a200541b0026a41186a290300370300200541c0006a41186a200541b0026a41206a280200360200200520052903b80237034020052f00b10220052d00b30241107472210f201145210c0c100b200541ec036a200541b0026a41286a280200360200200541c0036a41246a200541b0026a41206a290300370200200541c0036a411c6a200541b0026a41186a290300370200200541c0036a41146a200541b0026a41106a290300370200200541cc036a200541b0026a41086a290300370200200520052903b0023702c403200520143602f003200541073a00c0034100210c200541e0026a2002200541c0036a200541f8016a4100108886808000024020052d00e00222154108460d00200541e2006a20052d00e3023a0000200541c0006a41086a200541e0026a41146a290200370300200541c0006a41106a200541e0026a411c6a290200370300200541c0006a41186a200541e0026a41246a280200360200200520052f00e1023b0160200520052902ec0237034020052802e80221102005280288032113200528028c032112200528029003211420052802e4022111200541106a41286a200541bc036a280200360200200541306a200541b4036a290200370300200541106a41186a200541ac036a290200370300200541106a41106a200541a4036a290200370300200541106a41086a2005419c036a29020037030020052005290294033703102011410876210f0c110b20052802e402210420004103360200200020043602040c130b200541b0026a41286a200541e8006a220f41286a280200360200200541b0026a41206a200f41206a290200370300200541b0026a41186a200f41186a290200370300200541b0026a41106a200f41106a290200370300200541b0026a41086a200f41086a2902003703002005200f2902003703b00220042802082211410176210f0240024020114101710d00200f200428020422114b0d07200541003a00c8032005200f3602c403200520042802003602c0030c010b200f200428020422114b0d07200f20114f0d082005200428020022113602c0032005200f3602c403200541c9036a2011200f6a2d000041f001713a0000200541013a00c8030b20022001200541b0026a200541c0036a108386808000200541033a00c403200520143602f003200541073a00c003200541c8016a41086a200441086a280200360200200520042902003703c8014100210b200541e0026a2002200541c0036a200541c8016a4100108886808000024020052d00e00222154108460d00200541e2006a20052d00e3023a0000200541c0006a41086a200541f4026a290200370300200541c0006a41106a200541fc026a290200370300200541c0006a41186a20054184036a280200360200200520052f00e1023b0160200520052902ec0237034020052802e80221102005280288032113200528028c032112200528029003211420052802e4022111200541386a200541bc036a280200360200200541306a200541b4036a290200370300200541106a41186a200541ac036a290200370300200541106a41106a200541a4036a290200370300200541106a41086a2005419c036a29020037030020052005290294033703102011410876210f410121084100210c0c120b20052802e402210420004103360200200020043602040c120b20054194016a210f0240200a0d00200541b0026a41286a200f41286a290200370300200541b0026a41206a200f41206a290200370300200541b0026a41186a200f41186a290200370300200541b0026a41106a200f41106a290200370300200541b0026a41086a2214200f41086a2902003703002005200f2902003703b0022005280290012112200541c8016a41286a200341286a280200360200200541c8016a41206a200341206a290200370300200541c8016a41186a200341186a290200370300200541c8016a41106a200341106a290200370300200541c8016a41086a200341086a290200370300200520032902003703c801200520052802b0023602c80320052014280200200541dc026a280200220f200f41284b22141b3602c403200520052802b402200541b0026a410472220f20141b3602c003200541c0036a200510db8d808000221420052802c40341017420052802c8036b2211470d0c2014200528020441017420052802086b470d0c41032115024020052d00c8014103470d00200541106a41086a200f41086a290200370300200541106a41106a200f41106a290200370300200541106a41186a200f41186a290200370300200541106a41206a200f41206a290200370300200541106a41286a200f41286a2802003602002005200f2902003703104101210c20052802b00221140c0e0b200541c0036a41286a200541c8016a41286a280200360200200541c0036a41206a200541c8016a41206a290300370300200541c0036a41186a200541c8016a41186a290300370300200541c0036a41106a200541c8016a41106a290300370300200541c0036a41086a200541c8016a41086a290300370300200520052903c8013703c003200541a0026a41086a200441086a220f28020020146a360200200520042902003703a002200541e0026a200541a0026a10dd8d80800020022001200541c0036a200541e0026a10838680800020054198046a200541b0026a41286a29030037020020054190046a200541b0026a41206a29030037020020054188046a200541b0026a41186a29030037020020054180046a200541b0026a41106a290300370200200541f8036a200541b0026a41086a290300370200200520052903b0023702f003200520123602ec03200541033a00c003200541f8016a41086a200f280200360200200520042902003703f8014100210c200541e0026a2002200541c0036a200541f8016a4100108886808000024020052d00e00222154108460d00200541e2006a20052d00e3023a0000200541c0006a41086a200541f4026a290200370300200541c0006a41106a200541fc026a290200370300200541c0006a41186a20054184036a280200360200200520052f00e1023b0160200520052902ec0237034020052802e80221102005280288032113200528028c032112200528029003211420052802e4022111200541106a41286a200541bc036a280200360200200541106a41206a200541b4036a290200370300200541106a41186a200541ac036a290200370300200541106a41106a200541a4036a290200370300200541106a41086a2005419c036a29020037030020052005290294033703102011410876210f0c0e0b200020052802e402360204200041033602000c120b41032115200d41ff01714103460d0a20054198046a200f41286a29020037020020054190046a200f41206a29020037020020054188046a200f41186a29020037020020054180046a200f41106a290200370200200541f8036a200f41086a2902003702002005200f2902003702f003200528029001211120042802082214410176210f0240024020144101710d00200f200428020422144b0d09200541003a00e8022005200f3602e402200520042802003602e0020c010b200f200428020422144b0d09200f20144f0d0a2005200428020022143602e0022005200f3602e402200541e9026a2014200f6a2d000041f001713a0000200541013a00e8020b200220012003200541e0026a108386808000200520113602ec03200541033a00c003200541b0026a41086a200441086a280200360200200520042902003703b00241002108200541e0026a2002200541c0036a200541b0026a4100108886808000024020052d00e00222154108460d00200541e2006a20052d00e3023a0000200541c0006a41086a200541f4026a290200370300200541c0006a41106a200541fc026a290200370300200541c0006a41186a20054184036a280200360200200520052f00e1023b0160200520052902ec0237034020052802e80221102005280288032113200528028c032112200528029003211420052802e4022111200541386a200541bc036a280200360200200541306a200541b4036a290200370300200541106a41186a200541ac036a290200370300200541106a41106a200541a4036a290200370300200541106a41086a2005419c036a29020037030020052005290294033703102011410876210f4101210b4100210c0c110b20052802e402210420004103360200200020043602040c110b2000410336020020002004360204200541b0026a10e585808000201441002802c0a3c68000118080808000000c100b2004201441f492c68000109581808000000b20042014418493c68000109581808000000b20042014419493c6800010f980808000000b200f201141f492c68000109581808000000b200f2011418493c68000109581808000000b200f2011419493c6800010f980808000000b200f201441f492c68000109581808000000b200f2014418493c68000109581808000000b200f2014419493c6800010f980808000000b200541186a200541a0016a290200370300200541206a200541a8016a290200370300200541286a200541b0016a290200370300200541306a200541b8016a290200370300200541386a200541c0016a280200360200200520054198016a29020037031041012108200528029001211220052802940121144101210b4101210c0c050b0240024002400240024002400240024020142011490d00200528020820146a221041017622112005280204220c4f0d012012200528020020116a2d00002211410f71201141047620104101711b41246c6a22112d00002110201141023a000020104102460d02200541f8016a41096a201141096a290000370000200541f8016a41116a201141116a290000370000200541f8016a41196a201141196a290000370000200541f8016a41206a201141206a280000360000200541a0026a41086a200441086a220c280200221536020020112900012116200c201420156a41016a360200200520103a00f801200520163700f901200520042902003703a002200541c0036a2002200541f8016a20042001108d8680800020052802c003210420052d00c403220c417e6a0e020304060b200541e2006a20052d00cb013a0000200541106a41086a200f41086a290200370300200541106a41106a200f41106a290200370300200541106a41186a200f41186a290200370300200541106a41206a200f41206a290200370300200541106a41286a200f41286a280200360200200520052f00c9013b01602005200f29020037031020052802b002211420052d00c8012115200541c0006a41086a200541dc016a290200370300200541c0006a41106a200541e4016a290200370300200541c0006a41186a200541ec016a280200360200200520052902d40137034020052f00cd0120052d00cf0141107472210f0c060b2011200c418cd5c2800010f980808000000b200541e0006a41026a20052d00cb013a0000200541106a41086a200f41086a290200370300200541106a41106a200f41106a290200370300200541106a41186a200f41186a290200370300200541106a41206a200f41206a290200370300200541106a41286a200f41286a280200360200200520052f00c9013b01602005200f29020037031020052802b002211420052d00c8012115200541c0006a41086a200541dc016a290200370300200541c0006a41106a200541e4016a290200370300200541c0006a41186a200541c8016a41246a280200360200200520052902d40137034020052f00cd0120052d00cf0141107472210f0c040b20054198046a200541b0026a41286a29030037030020054190046a200541b0026a41206a29030037030020054188046a200541b0026a41186a29030037030020054180046a200541b0026a41106a290300370300200541f8036a200541b0026a41086a290300370300200541c0036a41086a200541c8016a41086a290300370300200541c0036a41106a200541c8016a41106a290300370300200541c0036a41186a200541c8016a41186a290300370300200541c0036a41206a200541c8016a41206a290300370300200541c0036a41286a200541c8016a41286a280200360200200520052903b0023703f003200520052903c8013703c003200520123602ec034100210c200541e0026a2002200541c0036a200541a0026a410010888680800020052d00e00222154108460d01200541e2006a20052d00e3023a0000200541c0006a41086a200541f4026a290200370300200541c0006a41106a200541fc026a290200370300200541c0006a41186a20054184036a280200360200200520052f00e1023b0160200520052902ec0237034020052802e80221102005280288032113200528028c032112200528029003211420052802e4022111200541106a41286a200541bc036a280200360200200541306a200541b4036a290200370300200541106a41186a200541ac036a290200370300200541106a41106a200541a4036a290200370300200541106a41086a2005419c036a29020037030020052005290294033703102011410876210f0c040b2000410336020020002004360204024020052d00c8014103460d00200541c8016a10e4858080000b201241002802c0a3c680001180808080000020052802dc024129490d0820052802b40241002802c0a3c68000118080808000000c080b20052802e402210420004103360200200020043602040c070b20112004360204201141003a0000200541e2006a20052d00cb013a0000200541c0006a41086a200541dc016a290200370300200541c0006a41106a200541e4016a290200370300200541c0006a41186a200541ec016a280200360200200520052f00c9013b0160200520052902d40137034020052802f001211320052802d001211020052d00cc01211120052d00c801211520052802b002211420052f00cd01210420052d00cf012103200541106a41286a200f41286a280200360200200541106a41206a200f41206a290200370300200541106a41186a200f41186a290200370300200541106a41106a200f41106a290200370300200541106a41086a200f41086a2902003703002005200f2902003703102004200341107472210f200c45210c0c010b4101210c20052802f001211320052802d001211020052d00cc0121110b4101210b410021080c030b4107211520052802d802211220052802d402211320052802b402211020052d00b00221110b4100210b410121080c010b410121084101210b0b2000200f3b0009200020153a00042000200c360200200020052f01603b00052000201036020c200020113a0008200020052903403702102000201336022c20002012360230200020143602342000410b6a200f4110763a0000200041076a200541e2006a2d00003a0000200041186a200541c0006a41086a290300370200200041206a200541c0006a41106a290300370200200041286a200541c0006a41186a280200360200200041e0006a200541106a41286a280200360200200041d8006a200541106a41206a290300370200200041d0006a200541106a41186a290300370200200041c8006a200541106a41106a290300370200200041c0006a200541106a41086a29030037020020002005290310370238024002400240024020052d00642204417c6a41ff01712200410420004104491b417d6a0e020001040b200b450d0320052d006822004103460d03024020000e020004020b200541ec006a2200280200220420042802002204417f6a36020020044101460d020c030b2008450d0220044103460d020240024020040e020104000b200528028801220020002802002200417f6a36020020004101470d0320054188016a10e28a8080000c030b2005280268220020002802002200417f6a36020020004101470d02200541e8006a10e28a8080000c020b2005418c016a2200280200220420042802002204417f6a36020020044101470d010b200010e28a8080000b200541a0046a2480808080000bdb2802087f037e2380808080004180056b2201248080808000200028025c21022000410036025c200041e4006a22032802002104200341003602002001200036020c200041e0006a280200210320012004410020021b3602d003200120033602cc03200120023602c803200141003602c4032001200241004722043602c003200120033602bc03200120023602b803200141003602b403200120043602b003200141106a200141b0036a10e28c808000024020012d005c22034102460d002001419d026a210520014190016a41206a2102200141dd006a2106034020014190016a200141106a41cc0010848e8080001a200541026a200641026a2d00003a0000200520062f00003b0000200141106a41186a20014190016a41186a290200370300200141106a41106a20014190016a41106a290200370300200141106a41086a20014190016a41086a290200370300200141f0016a41086a200241086a290200370300200141f0016a41106a200241106a290200370300200141f0016a41186a200241186a290200370300200141f0016a41206a200241206a290200370300200141f0016a41286a2204200241286a2802003602002001200129029001370310200120022902003703f001200120033a009c022000280250210720002802542108200120012d009d023a00ad02200120033a00ac02200120012802f40120042802002203200341284b22031b3602a802200120012802f001200141f0016a20031b3602a4022007200141106a200141a4026a200828022411858080800000024020042802004129490d0020012802f00141002802c0a3c68000118080808000000b200141106a200141b0036a10e28c80800020012d005c22034102470d000b0b200141b0036a10a48d8080000240024020002d002c0d00200041306a28020021020240200041286a28020022042000411c6a22052802002203470d00200510a889808000200028021c2103200028022821040b200041206a280200200041246a28020020046a22044100200320042003491b6b4102746a20023602002000200028022841016a3602280240024002400240024002400240024002400240200041186a280200220320024d0d00200041146a28020020024107746a22022d00002103200141106a200241016a41ff0010848e8080001a200241043a0004200241083a000002400240024002400240024020034108470d0020014190016a200141136a41e00010848e8080001a4100210220012d0090012104200128020c280268450d052004417c6a41ff01712203410420034104491b0e050501020503050b200128020c22022802582204200129006f370000200441186a20014187016a290000370000200441106a200141ff006a290000370000200441086a200141f7006a290000370000200141ef006a210402400240200241286a2802002200450d0020022000417f6a360228200241246a22002000280200220041016a220541002002411c6a280200220620052006491b6b360200200241206a28020020004102746a2802002200200241186a28020022054f0d08200241146a28020020004107746a220241046a200220022d00004108461b10e385808000200220033a0000200241016a200141106a41df0010848e8080001a200241f8006a200441186a290000370000200241f0006a200441106a290000370000200241e8006a200441086a290000370000200220042900003700600c010b0240200241186a28020022002002280210470d00200241106a2000109e86808000200228021821000b200241146a28020020004107746a220020033a0000200041016a200141106a41df0010848e8080001a200041f8006a200441186a290000370000200041f0006a200441106a290000370000200041e8006a200441086a2900003700002000200429000037006020022002280218220041016a3602180b200128020c220241003a002c200241306a20003602000c0f0b200141c0016a21020c020b200141b8016a21020c010b200141c0016a21020b200120022802003602b8032001200241086a2802002002412c6a2802002203200341284b22031b3602b40320012002280204200241046a20031b3602b003200141f0016a41046a200141b0036a10e48d8080004101210220012d00900121040b200120023602f001200142003702cc02200141e0026a411f6a20014190016a41206a290000370000200141e0026a41186a20014190016a41196a290000370300200141e0026a41106a20014190016a41116a290000370300200141e0026a41086a20014190016a41096a29000037030020012001290091013703e00220012802b801210620012802bc01210020012802c001210320012001410c6a3602ac032001200141a4026a3602a803200141c4016a2102024002400240024002400240024002402004417c6a41ff01712205410420054104491b0e050001020304000b41002d00fca3c680001a410141002802c8a3c68000118180808000002202450d09200241003a0000200141013602dc02200120023602d802200141013602d4020c100b200141bc036a200241086a290200370200200141c4036a200241106a290200370200200141cc036a200241186a290200370200200141b0036a41246a200241206a290200370200200141dc036a2204200241286a280200360200200120033602b003200120022902003702b403200141e0036a41206a20014183036a280000360200200141e0036a41186a200141fb026a290000370300200141e0036a41106a200141f3026a290000370300200141e0036a41086a200141eb026a290000370300200120012900e3023703e00320012000360288042001200636028404200120033602a404200120012802b80320042802002202200241284b22041b22023602a004200120012802b403200141b0036a41046a20041b220536029c04024002400240024020012d00e0030e03010200020b200141003a00f804200120003602d8042001200641086a3602d404200141023a00d00420012001419c046a3602f404200141a8046a200141a4026a2001410c6a200141d0046a2001419c046a4100200110db8580800020012d00a8040d0c200141e8046a2202200141c1046a290000370300200141e0046a2203200141b9046a290000370300200141d0046a41086a200141b1046a290000370300200120012900a9043703d004024020012d00e1030d00200141fa036a2002290300370100200141f2036a2003290300370100200141ea036a200141d8046a290300370100200120012903d0043701e203200141013a00e1030b200141e0036a4102722104412021004101210620012802a0042102200128029c04210520012802a40421030c020b20012802e40341086a2104200141e0036a41086a2802002100410021060c010b41012106200141e0036a4101722104412021000b200120003602b004200120043602ac04200120063602a804200341017621040240024020034101710d00410021060240200420024b0d0020042100410021040c020b2004200241d492c68000109481808000000b200420024f0d0b41012106200441016a2100200520046a2d0000410f7121040b200120043a00dd04200120063a00dc04200141003602d8042001200220006b3602d4042001200520006a3602d004200141d4026a200141d0046a200241017420036b200141a8046a10d08c808000024002400240024020012d00e0030e020103000b200128028404220220022802002202417f6a36020020024101470d02200141e0036a41246a21020c010b20012802e403220220022802002202417f6a36020020024101470d01200141e0036a41047221020b200210e28a8080000b20012802dc034129490d0f20012802b40341002802c0a3c68000118080808000000c0f0b200141c4036a200241086a290200370200200141cc036a200241106a290200370200200141d4036a200241186a290200370200200141dc036a200241206a280200360200200120033602b803200120003602b403200120063602b003200120022902003702bc03200141d0046a41206a20014183036a280000360200200141d0046a41186a200141fb026a290000370300200141d0046a41106a200141f3026a290000370300200141d0046a41086a200141eb026a290000370300200120012900e3023703d0042001200141b0036a41046a41c0d1c28000109687808000200120063602a4042001200129030037029c04200141a8046a2001419c046a10dc8d808000200141003a00f80420012001419c046a3602f404200141e0036a200141a4026a2001410c6a200141d0046a2001419c046a4100200110db85808000200141d4026a200141a8046a20012802a00441017420012802a4046b200141e0036a10cb8c808000000b200141b0036a41206a20014183036a280000360200200141b0036a41186a200141fb026a290000370300200141b0036a41106a200141f3026a290000370300200141b0036a41086a200141eb026a290000370300200120012900e30222093703b003200120003602d803200120063602d4032009a741ff01714103470d01410221020c020b200141bc036a200241086a290200370200200141c4036a200241106a290200370200200141cc036a200241186a290200370200200141d4036a200241206a290200370200200141dc036a2205200241286a280200360200200120033602b003200120022902003702b403200141e0036a41096a20014190016a410172220241086a290000370000200141e0036a41116a200241106a290000370000200141e0036a41196a200241186a290000370000200141e0036a41206a2002411f6a2900003700002001200636028804200120022900003700e103200120043a00e0032001200336029804200120012802b80320052802002202200241284b22051b220236029404200120012802b403200141b0036a41046a20051b220736029004200441ff01714103470d02410221080c0b0b200141d0046a200141b0036a4100200141a4026a2001410c6a10f58580800020012902d404210920012802d00421020b200120093702e403200120023602e003200141d4026a200141d0046a200141e0036a10ca8c808000000b200141e0036a4101722105428080808080042109410121080240200441ff01710e03070800080b200141003a00f804200120063602d804200120012802840441086a3602d404200141023a00d004200120014190046a3602f404200141a8046a200141a4026a2001410c6a200141d0046a20014190046a4100200110db8580800020012d00a8040d05200141e8046a2202200141c1046a290000370300200141e0046a2203200141b9046a290000370300200141d0046a41086a200141b1046a290000370300200120012900a9043703d004024020012d00e1030d00200141fa036a2002290300370100200141f2036a2003290300370100200141ea036a200141d8046a290300370100200120012903d0043701e203200141013a00e1030b200141e0036a41027221052001280294042102200128029004210720012802980421030c070b2002200341e4d7c2800010f980808000000b2000200541d4d7c2800010f980808000000b4101410110b280808000000b200141dc046a4201370200200141013602d404200141fcd1c280003602d004200141e0818080003602940420014180d3c2800036029004200120014190046a3602d804200141d0046a4188d3c2800010f680808000000b2004200241e492c6800010f980808000000b200141dc046a4201370200200141013602d404200141fcd1c280003602d004200141e0818080003602a00420014180d3c2800036029c0420012001419c046a3602d804200141d0046a4188d3c2800010f680808000000b20012802e40341086a2105200141e0036a41086a3502004220862109410021080b20092005ad8421090b200341017621040240024020034101710d00410021060240200420024b0d0020042105410021040c020b2004200241d492c68000109481808000000b200420024f0d0341012106200441016a2105200720046a2d0000410f7121040b200120043a00b504200120063a00b404200141003602b0042001200220056b3602ac042001200720056a3602a804200141e0046a200141a8036a360200200141003602d804200120003602d0042001200041c0046a3602d4042001200141b0036a3602dc04200120093702a0042001200836029c04200141d4026a200141a8046a200241017420036b200141d0046a2001419c046a10cd8c808000024020012d00e00322024103460d0002400240024020020e020103000b200128028404220220022802002202417f6a36020020024101470d0220014184046a21020c010b20012802e403220220022802002202417f6a36020020024101470d01200141e4036a21020b200210e28a8080000b200041002802c0a3c680001180808080000020012802dc034129490d0020012802b40341002802c0a3c68000118080808000000b200128020c220241d4006a280200210320022802502102200141d0046a41086a41002802e0efc08000360200200141002902d8efc080003703d004200141b0036a2002200141d0046a20012802d802220420012802dc022200200328021c11878080800000200128020c2203280258220220012900b003370000200241086a200141b0036a41086a2205290000370000200241106a200141b0036a41106a2206290000370000200241186a200141b0036a41186a220729000037000020052003280258220241086a2900003703002006200241106a2900003703002007200241186a290000370300200120022900003703b0032003200141b0036a20042000200141f0016a10f885808000200128020c2202280258220341186a2900002109200341106a290000210a200341086a290000210b2002412d6a2003290000370000200241013a002c200241356a200b3700002002413d6a200a370000200241c5006a2009370000024020012802d402450d00200441002802c0a3c68000118080808000000b20012802cc024129490d0020012802a40241002802c0a3c68000118080808000000b20014180056a2480808080000f0b2004200241e492c6800010f980808000000bdb2802087f037e2380808080004180056b2201248080808000200028025c21022000410036025c200041e4006a22032802002104200341003602002001200036020c200041e0006a280200210320012004410020021b3602d003200120033602cc03200120023602c803200141003602c4032001200241004722043602c003200120033602bc03200120023602b803200141003602b403200120043602b003200141106a200141b0036a10e28c808000024020012d005c22034102460d002001419d026a210520014190016a41206a2102200141dd006a2106034020014190016a200141106a41cc0010848e8080001a200541026a200641026a2d00003a0000200520062f00003b0000200141106a41186a20014190016a41186a290200370300200141106a41106a20014190016a41106a290200370300200141106a41086a20014190016a41086a290200370300200141f0016a41086a200241086a290200370300200141f0016a41106a200241106a290200370300200141f0016a41186a200241186a290200370300200141f0016a41206a200241206a290200370300200141f0016a41286a2204200241286a2802003602002001200129029001370310200120022902003703f001200120033a009c022000280250210720002802542108200120012d009d023a00ad02200120033a00ac02200120012802f40120042802002203200341284b22031b3602a802200120012802f001200141f0016a20031b3602a4022007200141106a200141a4026a200828022411858080800000024020042802004129490d0020012802f00141002802c0a3c68000118080808000000b200141106a200141b0036a10e28c80800020012d005c22034102470d000b0b200141b0036a10a48d8080000240024020002d002c0d00200041306a28020021020240200041286a28020022042000411c6a22052802002203470d00200510a889808000200028021c2103200028022821040b200041206a280200200041246a28020020046a22044100200320042003491b6b4102746a20023602002000200028022841016a3602280240024002400240024002400240024002400240200041186a280200220320024d0d00200041146a28020020024107746a22022d00002103200141106a200241016a41ff0010848e8080001a200241043a0004200241083a000002400240024002400240024020034108470d0020014190016a200141136a41e00010848e8080001a4100210220012d0090012104200128020c280268450d052004417c6a41ff01712203410420034104491b0e050501020503050b200128020c22022802582204200129006f370000200441186a20014187016a290000370000200441106a200141ff006a290000370000200441086a200141f7006a290000370000200141ef006a210402400240200241286a2802002200450d0020022000417f6a360228200241246a22002000280200220041016a220541002002411c6a280200220620052006491b6b360200200241206a28020020004102746a2802002200200241186a28020022054f0d08200241146a28020020004107746a220241046a200220022d00004108461b10e385808000200220033a0000200241016a200141106a41df0010848e8080001a200241f8006a200441186a290000370000200241f0006a200441106a290000370000200241e8006a200441086a290000370000200220042900003700600c010b0240200241186a28020022002002280210470d00200241106a2000109e86808000200228021821000b200241146a28020020004107746a220020033a0000200041016a200141106a41df0010848e8080001a200041f8006a200441186a290000370000200041f0006a200441106a290000370000200041e8006a200441086a2900003700002000200429000037006020022002280218220041016a3602180b200128020c220241003a002c200241306a20003602000c0f0b200141c0016a21020c020b200141b8016a21020c010b200141c0016a21020b200120022802003602b8032001200241086a2802002002412c6a2802002203200341284b22031b3602b40320012002280204200241046a20031b3602b003200141f0016a41046a200141b0036a10e48d8080004101210220012d00900121040b200120023602f001200142003702cc02200141e0026a411f6a20014190016a41206a290000370000200141e0026a41186a20014190016a41196a290000370300200141e0026a41106a20014190016a41116a290000370300200141e0026a41086a20014190016a41096a29000037030020012001290091013703e00220012802b801210620012802bc01210020012802c001210320012001410c6a3602ac032001200141a4026a3602a803200141c4016a2102024002400240024002400240024002402004417c6a41ff01712205410420054104491b0e050001020304000b41002d00fca3c680001a410141002802c8a3c68000118180808000002202450d09200241003a0000200141013602dc02200120023602d802200141013602d4020c100b200141bc036a200241086a290200370200200141c4036a200241106a290200370200200141cc036a200241186a290200370200200141b0036a41246a200241206a290200370200200141dc036a2204200241286a280200360200200120033602b003200120022902003702b403200141e0036a41206a20014183036a280000360200200141e0036a41186a200141fb026a290000370300200141e0036a41106a200141f3026a290000370300200141e0036a41086a200141eb026a290000370300200120012900e3023703e00320012000360288042001200636028404200120033602a404200120012802b80320042802002202200241284b22041b22023602a004200120012802b403200141b0036a41046a20041b220536029c04024002400240024020012d00e0030e03010200020b200141003a00f804200120003602d8042001200641086a3602d404200141023a00d00420012001419c046a3602f404200141a8046a200141a4026a2001410c6a200141d0046a2001419c046a4100200110d98580800020012d00a8040d0c200141e8046a2202200141c1046a290000370300200141e0046a2203200141b9046a290000370300200141d0046a41086a200141b1046a290000370300200120012900a9043703d004024020012d00e1030d00200141fa036a2002290300370100200141f2036a2003290300370100200141ea036a200141d8046a290300370100200120012903d0043701e203200141013a00e1030b200141e0036a4102722104412021004101210620012802a0042102200128029c04210520012802a40421030c020b20012802e40341086a2104200141e0036a41086a2802002100410021060c010b41012106200141e0036a4101722104412021000b200120003602b004200120043602ac04200120063602a804200341017621040240024020034101710d00410021060240200420024b0d0020042100410021040c020b2004200241d492c68000109481808000000b200420024f0d0b41012106200441016a2100200520046a2d0000410f7121040b200120043a00dd04200120063a00dc04200141003602d8042001200220006b3602d4042001200520006a3602d004200141d4026a200141d0046a200241017420036b200141a8046a10d08c808000024002400240024020012d00e0030e020103000b200128028404220220022802002202417f6a36020020024101470d02200141e0036a41246a21020c010b20012802e403220220022802002202417f6a36020020024101470d01200141e0036a41047221020b200210e28a8080000b20012802dc034129490d0f20012802b40341002802c0a3c68000118080808000000c0f0b200141c4036a200241086a290200370200200141cc036a200241106a290200370200200141d4036a200241186a290200370200200141dc036a200241206a280200360200200120033602b803200120003602b403200120063602b003200120022902003702bc03200141d0046a41206a20014183036a280000360200200141d0046a41186a200141fb026a290000370300200141d0046a41106a200141f3026a290000370300200141d0046a41086a200141eb026a290000370300200120012900e3023703d0042001200141b0036a41046a41c0d1c28000109687808000200120063602a4042001200129030037029c04200141a8046a2001419c046a10dc8d808000200141003a00f80420012001419c046a3602f404200141e0036a200141a4026a2001410c6a200141d0046a2001419c046a4100200110d985808000200141d4026a200141a8046a20012802a00441017420012802a4046b200141e0036a10cb8c808000000b200141b0036a41206a20014183036a280000360200200141b0036a41186a200141fb026a290000370300200141b0036a41106a200141f3026a290000370300200141b0036a41086a200141eb026a290000370300200120012900e30222093703b003200120003602d803200120063602d4032009a741ff01714103470d01410221020c020b200141bc036a200241086a290200370200200141c4036a200241106a290200370200200141cc036a200241186a290200370200200141d4036a200241206a290200370200200141dc036a2205200241286a280200360200200120033602b003200120022902003702b403200141e0036a41096a20014190016a410172220241086a290000370000200141e0036a41116a200241106a290000370000200141e0036a41196a200241186a290000370000200141e0036a41206a2002411f6a2900003700002001200636028804200120022900003700e103200120043a00e0032001200336029804200120012802b80320052802002202200241284b22051b220236029404200120012802b403200141b0036a41046a20051b220736029004200441ff01714103470d02410221080c0b0b200141d0046a200141b0036a4100200141a4026a2001410c6a10f68580800020012902d404210920012802d00421020b200120093702e403200120023602e003200141d4026a200141d0046a200141e0036a10ca8c808000000b200141e0036a4101722105428080808080042109410121080240200441ff01710e03070800080b200141003a00f804200120063602d804200120012802840441086a3602d404200141023a00d004200120014190046a3602f404200141a8046a200141a4026a2001410c6a200141d0046a20014190046a4100200110d98580800020012d00a8040d05200141e8046a2202200141c1046a290000370300200141e0046a2203200141b9046a290000370300200141d0046a41086a200141b1046a290000370300200120012900a9043703d004024020012d00e1030d00200141fa036a2002290300370100200141f2036a2003290300370100200141ea036a200141d8046a290300370100200120012903d0043701e203200141013a00e1030b200141e0036a41027221052001280294042102200128029004210720012802980421030c070b2002200341e4d7c2800010f980808000000b2000200541d4d7c2800010f980808000000b4101410110b280808000000b200141dc046a4201370200200141013602d404200141fcd1c280003602d004200141e0818080003602940420014180d3c2800036029004200120014190046a3602d804200141d0046a4188d3c2800010f680808000000b2004200241e492c6800010f980808000000b200141dc046a4201370200200141013602d404200141fcd1c280003602d004200141e0818080003602a00420014180d3c2800036029c0420012001419c046a3602d804200141d0046a4188d3c2800010f680808000000b20012802e40341086a2105200141e0036a41086a3502004220862109410021080b20092005ad8421090b200341017621040240024020034101710d00410021060240200420024b0d0020042105410021040c020b2004200241d492c68000109481808000000b200420024f0d0341012106200441016a2105200720046a2d0000410f7121040b200120043a00b504200120063a00b404200141003602b0042001200220056b3602ac042001200720056a3602a804200141e0046a200141a8036a360200200141003602d804200120003602d0042001200041c0046a3602d4042001200141b0036a3602dc04200120093702a0042001200836029c04200141d4026a200141a8046a200241017420036b200141d0046a2001419c046a10cc8c808000024020012d00e00322024103460d0002400240024020020e020103000b200128028404220220022802002202417f6a36020020024101470d0220014184046a21020c010b20012802e403220220022802002202417f6a36020020024101470d01200141e4036a21020b200210e28a8080000b200041002802c0a3c680001180808080000020012802dc034129490d0020012802b40341002802c0a3c68000118080808000000b200128020c220241d4006a280200210320022802502102200141d0046a41086a41002802e0efc08000360200200141002902d8efc080003703d004200141b0036a2002200141d0046a20012802d802220420012802dc022200200328021c11878080800000200128020c2203280258220220012900b003370000200241086a200141b0036a41086a2205290000370000200241106a200141b0036a41106a2206290000370000200241186a200141b0036a41186a220729000037000020052003280258220241086a2900003703002006200241106a2900003703002007200241186a290000370300200120022900003703b0032003200141b0036a20042000200141f0016a10f985808000200128020c2202280258220341186a2900002109200341106a290000210a200341086a290000210b2002412d6a2003290000370000200241013a002c200241356a200b3700002002413d6a200a370000200241c5006a2009370000024020012802d402450d00200441002802c0a3c68000118080808000000b20012802cc024129490d0020012802a40241002802c0a3c68000118080808000000b20014180056a2480808080000f0b2004200241e492c6800010f980808000000ba90601037f2380808080004190016b2206248080808000200641033a000c02400240024020054100480d00200541f5ffffff074f0d0102402005410b6a417c7122070d00410421080c030b41002d00fca3c680001a200741002802c8a3c680001181808080000022080d024104200710b280808000000b41fc9bc68000412b200641e0006a41a89cc6800041b89cc68000108981808000000b41e484c08000412b200641e0006a419085c08000419086c08000108981808000000b2008428180808010370200200841086a2004200510848e8080001a0240024020012d002c0d00200141306a2802002104410021070c010b200641d6006a2001412f6a2d00003a0000200641386a41086a2001413c6a290200370300200641c8006a200141c4006a290200370300200641d0006a200141cc006a2d00003a000020062001412d6a2f00003b01542006200141346a290200370338200141306a2802002104410121070b200641e0006a41106a200641386a41086a290300370200200641e0006a41186a200641386a41106a290300370200200641e0006a41206a200641386a41186a280200360200200620073a0060200620062f01543b006120062004360264200620062903383702682006200641d4006a41026a2d00003a00632006410036028c0120062003360288012006200236028401200641d8006a2001200641e0006a20064184016a200820052006410c6a108286808000200628025821050240024020062d005c4102460d00200141003a002c2000200629020c370200200141306a2005360200200041086a2006410c6a41086a290200370200200041106a2006410c6a41106a290200370200200041186a2006410c6a41186a290200370200200041206a2006410c6a41206a290200370200200041286a2006410c6a41286a2802003602000c010b200041043a00002000200536020420062d000c22014103460d000240024020010e020102000b2006280230220120012802002201417f6a36020020014101470d01200641306a10e28a8080000c010b2006280210220120012802002201417f6a36020020014101470d00200641106a10e28a8080000b20064190016a2480808080000ba90601037f2380808080004190016b2206248080808000200641033a000c02400240024020054100480d00200541f5ffffff074f0d0102402005410b6a417c7122070d00410421080c030b41002d00fca3c680001a200741002802c8a3c680001181808080000022080d024104200710b280808000000b41fc9bc68000412b200641e0006a41a89cc6800041b89cc68000108981808000000b41e484c08000412b200641e0006a419085c08000419086c08000108981808000000b2008428180808010370200200841086a2004200510848e8080001a0240024020012d002c0d00200141306a2802002104410021070c010b200641d6006a2001412f6a2d00003a0000200641386a41086a2001413c6a290200370300200641c8006a200141c4006a290200370300200641d0006a200141cc006a2d00003a000020062001412d6a2f00003b01542006200141346a290200370338200141306a2802002104410121070b200641e0006a41106a200641386a41086a290300370200200641e0006a41186a200641386a41106a290300370200200641e0006a41206a200641386a41186a280200360200200620073a0060200620062f01543b006120062004360264200620062903383702682006200641d4006a41026a2d00003a00632006410036028c0120062003360288012006200236028401200641d8006a2001200641e0006a20064184016a200820052006410c6a108586808000200628025821050240024020062d005c4102460d00200141003a002c2000200629020c370200200141306a2005360200200041086a2006410c6a41086a290200370200200041106a2006410c6a41106a290200370200200041186a2006410c6a41186a290200370200200041206a2006410c6a41206a290200370200200041286a2006410c6a41286a2802003602000c010b200041043a00002000200536020420062d000c22014103460d000240024020010e020102000b2006280230220120012802002201417f6a36020020014101470d01200641306a10e28a8080000c010b2006280210220120012802002201417f6a36020020014101470d00200641106a10e28a8080000b20064190016a2480808080000ba60601037f2380808080004190016b22042480808080000240024020012d002c0d00200141306a2802002105410021060c010b2004412a6a2001412f6a2d00003a0000200441106a2001413c6a290200370300200441186a200141c4006a290200370300200441206a200141cc006a2d00003a000020042001412d6a2f00003b01282004200141346a290200370308200141306a2802002105410121060b20044100360234200420033602302004200236022c200441033a0038200441ec006a41106a2203200441086a41086a290300370200200441ec006a41186a2202200441086a41106a2903003702002004418c016a200441086a41186a280200360200200420063a006c200420042f01283b006d20042004412a6a2d00003a006f2004200536027020042004290308370274200441e4006a2001200441ec006a2004412c6a200441386a108d86808000200428026421050240024002400240024020042d0068417e6a0e020100020b200041043a00002000200536020420042d003822014103460d030240024020010e020105000b200428025c220120012802002201417f6a36020020014101470d04200441dc006a10e28a8080000c040b200428023c220120012802002201417f6a36020020014101470d032004413c6a10e28a8080000c030b200441ec006a41badbc5800041014100280298a3c6800011858080800000200141013a002c2001412d6a200429006c370000200141356a200441ec006a41086a22052900003700002001413d6a2003290000370000200141c5006a2002290000370000200441ec006a41badbc5800041014100280298a3c680001185808080000020012802582201200429006c370000200141186a2002290000370000200141106a2003290000370000200141086a20052900003700000c010b200141003a002c200141306a20053602000b20002004290238370200200041286a200441386a41286a280200360200200041206a200441386a41206a290200370200200041186a200441386a41186a290200370200200041106a200441386a41106a290200370200200041086a200441386a41086a2902003702000b20044190016a2480808080000ba60601037f2380808080004190016b22042480808080000240024020012d002c0d00200141306a2802002105410021060c010b2004412a6a2001412f6a2d00003a0000200441106a2001413c6a290200370300200441186a200141c4006a290200370300200441206a200141cc006a2d00003a000020042001412d6a2f00003b01282004200141346a290200370308200141306a2802002105410121060b20044100360234200420033602302004200236022c200441033a0038200441ec006a41106a2203200441086a41086a290300370200200441ec006a41186a2202200441086a41106a2903003702002004418c016a200441086a41186a280200360200200420063a006c200420042f01283b006d20042004412a6a2d00003a006f2004200536027020042004290308370274200441e4006a2001200441ec006a2004412c6a200441386a108b86808000200428026421050240024002400240024020042d0068417e6a0e020100020b200041043a00002000200536020420042d003822014103460d030240024020010e020105000b200428025c220120012802002201417f6a36020020014101470d04200441dc006a10e28a8080000c040b200428023c220120012802002201417f6a36020020014101470d032004413c6a10e28a8080000c030b200441ec006a41badbc5800041014100280298a3c6800011858080800000200141013a002c2001412d6a200429006c370000200141356a200441ec006a41086a22052900003700002001413d6a2003290000370000200141c5006a2002290000370000200441ec006a41badbc5800041014100280298a3c680001185808080000020012802582201200429006c370000200141186a2002290000370000200141106a2003290000370000200141086a20052900003700000c010b200141003a002c200141306a20053602000b20002004290238370200200041286a200441386a41286a280200360200200041206a200441386a41206a290200370200200041186a200441386a41186a290200370200200041106a200441386a41106a290200370200200041086a200441386a41086a2902003702000b20044190016a2480808080000ba50201027f0240024002402001450d002002417f4c0d0102400240024002402003280204450d000240200341086a28020022040d00024020020d00200121030c030b41002d00fca3c680001a200241002802c8a3c680001181808080000021030c020b20032802002105200241002802c8a3c68000118180808000002203450d0320032005200410848e8080001a200541002802c0a3c68000118080808000000c020b024020020d00200121030c010b41002d00fca3c680001a200241002802c8a3c680001181808080000021030b2003450d010b20002003360204200041086a2002360200200041003602000f0b20002001360204200041086a20023602000c020b20004100360204200041086a20023602000c010b200041003602040b200041013602000b8f0100024002400240024020010d00410121020c010b2001417f4c0d0102402002450d00200141002802c8a3c68000118180808000002202450d03200241002001108a8e8080001a0c010b41002d00fca3c680001a200141002802c8a3c68000118180808000002202450d020b20002002360204200020013602000f0b10ae80808000000b4101200110b280808000000bef0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141e8016c2104200141ccfbb4044941037421050240024020030d00200241003602180c010b200241083602182002200341e8016c36021c200220002802043602140b200241086a20052004200241146a109586808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141306c2104200141abd5aa154941027421050240024020030d00200241003602180c010b200241043602182002200341306c36021c200220002802043602140b200241086a20052004200241146a109586808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bee0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b2201410c6c2104200141abd5aad5004941027421050240024020030d00200241003602180c010b2002410436021820022003410c6c36021c200220002802043602140b200241086a20052004200241146a109586808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141286c2104200141b4e6cc194941037421050240024020030d00200241003602180c010b200241083602182002200341286c36021c200220002802043602140b200241086a20052004200241146a109586808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bee0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b2201410274210420014180808080024941027421050240024020030d00200241003602180c010b200241043602182002200341027436021c200220002802043602140b200241086a20052004200241146a109586808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000be00101037f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014108200141084b1b2201417f73411f7621040240024020030d00200241003602180c010b2002200336021c20024101360218200220002802043602140b200241086a20042001200241146a109586808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bef0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141e8006c2104200141b2a7ec094941037421050240024020030d00200241003602180c010b200241083602182002200341e8006c36021c200220002802043602140b200241086a20052004200241146a109586808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b22014107742104200141808080084941027421050240024020030d00200241003602180c010b200241043602182002200341077436021c200220002802043602140b200241086a20052004200241146a109586808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141386c210420014193c9a4124941027421050240024020030d00200241003602180c010b200241043602182002200341386c36021c200220002802043602140b200241086a20052004200241146a109586808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141246c2104200141e4f1b81c4941027421050240024020030d00200241003602180c010b200241043602182002200341246c36021c200220002802043602140b200241086a20052004200241146a109586808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bea0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b22014180808020492104200141057421050240024020030d00200241003602180c010b200241013602182002200341057436021c200220002802043602140b200241086a20042005200241146a109586808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bee0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b22014104742104200141808080c0004941037421050240024020030d00200241003602180c010b200241083602182002200341047436021c200220002802043602140b200241086a20052004200241146a109586808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bee0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b22014104742104200141808080c0004941027421050240024020030d00200241003602180c010b20022000280204360214200241043602182002200341047436021c0b200241086a20052004200241146a109586808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141386c210420014193c9a4124941037421050240024020030d00200241003602180c010b200241083602182002200341386c36021c200220002802043602140b200241086a20052004200241146a109586808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141146c2104200141e7cc99334941027421050240024020030d00200241003602180c010b200241043602182002200341146c36021c200220002802043602140b200241086a20052004200241146a109586808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bed0101047f23808080800041206b220224808080800002400240200141016a2201450d002000280200220341017422042001200420014b1b22014104200141044b1b220141186c2104200141d6aad52a4941027421050240024020030d00200241003602180c010b200241043602182002200341186c36021c200220002802043602140b200241086a20052004200241146a109586808000200228020c2103024020022802080d0020002001360200200020033602040c020b2003418180808078460d012003450d002003200241106a28020010b280808000000b10ae80808000000b200241206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b220241386c210420024193c9a4124941037421050240024020010d00200341003602180c010b200341083602182003200141386c36021c200320002802043602140b200341086a20052004200341146a109586808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b220241146c2104200241e7cc99334941027421050240024020010d00200341003602180c010b200341043602182003200141146c36021c200320002802043602140b200341086a20052004200341146a109586808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b220241246c2104200241e4f1b81c4941027421050240024020010d00200341003602180c010b200341043602182003200141246c36021c200320002802043602140b200341086a20052004200341146a109586808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bf00101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b22024104742104200241808080c0004941027421050240024020010d00200341003602180c010b20032000280204360214200341043602182003200141047436021c0b200341086a20052004200341146a109586808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000be20101027f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024108200241084b1b2202417f73411f7621040240024020010d00200341003602180c010b2003200136021c20034101360218200320002802043602140b200341086a20042002200341146a109586808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bef0101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b22024105742104200241808080204941037421050240024020010d00200341003602180c010b200341083602182003200141057436021c200320002802043602140b200341086a20052004200341146a109586808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000bf00101037f23808080800041206b220324808080800002400240200120026a22022001490d002000280200220141017422042002200420024b1b22024104200241044b1b2202410c6c2104200241abd5aad5004941027421050240024020010d00200341003602180c010b2003410436021820032001410c6c36021c200320002802043602140b200341086a20052004200341146a109586808000200328020c2101024020032802080d0020002002360200200020013602040c020b2001418180808078460d012001450d002001200341106a28020010b280808000000b10ae80808000000b200341206a2480808080000b8d07010b7f02402000280200220428020020042802082200470d0020042000410110ab86808000200428020821000b200428020420006a41223a00002004200041016a22053602082002417f6a21062003417f732107200220036a2108410021092002210a02400340410021000240024002400240024002400240024002400240024003400240200a20006a220b2008470d00024020032009460d0002402009450d00200320094d0d04200220096a2c000041bf7f4c0d04200320096b21030b200220096a21000240200428020020056b20034f0d0020042005200310ab86808000200428020821050b200428020420056a2000200310848e8080001a2004200520036a22053602080b024020042802002005470d0020042005410110ab86808000200428020821050b200428020420056a41223a00002004200541016a36020841000f0b200041016a2100200b2d0000220c41a881c280006a2d0000220b450d000b02402009200920006a220d417f6a220e4f0d0002402009450d000240200320094b0d0020032009460d010c0f0b200220096a2c00004140480d0e0b02400240200e2003490d00200d20076a0d0f0c010b200620096a20006a2c000041bf7f4c0d0e0b0240200428020020056b2000417f6a220e4f0d0020042005200e10ab86808000200428020821050b200428020420056a200220096a200e10848e8080001a2004200520006a417f6a22053602080b200a20006a210a41b3d9c280002100200b41a47f6a0e1a080a0a0a0a0a010a0a0a060a0a0a0a0a0a0a050a0a0a040a0302070b2002200320092003418cd9c28000109781808000000b41b5d9c2800021000c060b200c410f71419881c280006a2d0000210b200c410476419881c280006a2d0000210c0240200428020020056b41054b0d0020042005410610ab86808000200428020821050b200428020420056a2200200b3a00052000200c3a0004200041dceac18103360000200541066a21050c060b41bdd9c2800021000c040b41bbd9c2800021000c030b41b9d9c2800021000c020b41b7d9c2800021000c010b200b4122470d0241b1d9c2800021000b0240200428020020056b41014b0d0020042005410210ab86808000200428020821050b200428020420056a20002f00003b0000200541026a21050b20042005360208200d21090c010b0b41f4d7c28000412841fcd8c2800010f880808000000b200220032009200920006a417f6a419cd9c28000109781808000000b830b010a7f0240024002400240024002400240024020002d00000e06000102050304000b024020012802002202280200200228020822006b41034b0d0020022000410410ab86808000200228020821000b200228020420006a41eeeab1e3063600002002200041046a3602080c050b20012802002102024020002d00010d0002402002280200200228020822006b41044b0d0020022000410510ab86808000200228020821000b2002200041056a360208200228020420006a220241002800acd9c28000360000200241046a41002d00b0d9c280003a000041000f0b02402002280200200228020822006b41034b0d0020022000410410ab86808000200228020821000b200228020420006a41f4e4d5ab063600002002200041046a3602080c040b200041086a2802002103024020012802002202280200200228020822046b2000410c6a28020022004f0d0020022004200010ab86808000200228020821040b200228020420046a2003200010848e8080001a2002200420006a3602080c030b2001200041046a10b0868080000f0b2000410c6a280200210402402001280200220528020020052802082202470d0020052002410110ab86808000200528020821020b200528020420026a41fb003a00002005200241016a22023602084180022106024020040d00024020052802002002470d0020052002410110ab86808000200528020821020b200528020420026a41fd003a00002005200241016a360208410021060b4100210220044100200028020422031b210720034100472108200041086a2802002104034002400240024002402007450d000240024020020d0020080d010b20080d0441f887c6800010a081808000000b41012108200321022004450d0220042100024020044107712203450d0003402000417f6a210020022802bc0221022003417f6a22030d000b0b200441084f0d010c020b0240200641ff01710d004100210020064180fe0371450d070240200528020020052802082202470d0020052002410110ab86808000200528020821020b200528020420026a41fd003a00002005200241016a36020841000f0b41f4d7c280004128419cdcc2800010f880808000000b034020022802bc022802bc022802bc022802bc022802bc022802bc022802bc022802bc022102200041786a22000d000b0b41002104410021030b024002400240200420022f01ba02490d00034020022802b0012200450d02200341016a210320022f01b802210420002102200420002f01ba024f0d000b0b200441016a2109024020030d00200221000c020b200220094102746a41bc026a2802002100410021092003417f6a220a450d012003417e6a210b0240200a4107712203450d000340200a417f6a210a20002802bc0221002003417f6a22030d000b0b200b4107490d01034020002802bc022802bc022802bc022802bc022802bc022802bc022802bc022802bc022100200a41786a220a0d000c020b0b41e887c6800010a081808000000b0240200641ff01710d002004410474210320022004410c6c6a220441bc016a280200210a200441b8016a2802002104024020064180fe0371418002460d00024020052802002005280208220b470d002005200b410110ab868080002005280208210b0b2005280204200b6a412c3a00002005200b41016a3602080b200220036a210b200120022004200a10ae868080001a0240200528020020052802082202470d0020052002410110ab86808000200528020821020b2007417f6a2107200641ff817c71418004722106200528020420026a413a3a00002005200241016a360208410021032009210420002102200b200110af868080002200450d010c040b0b41f4d7c280004128418cdcc2800010f880808000000b20012002200041086a2802002000410c6a28020010ae868080001a0b410021000b20000bfd0201047f200128020821022001280204210102402000280200220328020020032802082204470d0020032004410110ab86808000200328020821040b200328020420046a41db003a00002003200441016a22043602080240024002400240024002402002450d0020024104742105418002210203402002220441ff01710d02024020044180fe0371418002460d000240200328020020032802082202470d0020032002410110ab86808000200328020821020b200328020420026a412c3a00002003200241016a3602080b2001200010af8680800022020d06200141106a2101200441ff817c71418004722102200541706a22050d000b200441ff01710d02200328020020032802082204470d040c030b20032802002004460d020c030b41f4d7c28000412841acdcc2800010f880808000000b41f4d7c28000412841bcdcc2800010f880808000000b20032004410110ab86808000200328020821040b200328020420046a41dd003a00002003200441016a360208410021020b20020bc70602077f037e2380808080004180016b2202248080808000024002400240024002400240024010fa81808000220341fe014b0d002002200341016a3602284100210441b1e3c080004113200241286a410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200128020022032003280200417f6a22053602002001280228210620012d00042107024020050d00200341086a28020022082003410c6a28020022052802001180808080000002402005280204450d00200841002802c0a3c68000118080808000000b200341046a22052005280200417f6a220536020020050d00200341002802c0a3c68000118080808000000b0240200741ff0171450d00410221010c050b200241186a2001412c6a220141186a290000370300200241106a200141106a290000370300200241086a200141086a2900003703002002200129000037030020024200200629030022092009428080e983b1de16541b370320200241286a2002200241206a10a38c808000200241286a41106a290300210a200241286a41086a2903002109024020022802280d002002290320220b2009560d02200b20095a0d0320022009200b7d370328200241286a108d8a8080000c030b200228022c22014108762104200141ff0171410e470d040c030b200041093b0100200128020022012001280200417f6a220036020020000d05200141086a28020022032001410c6a28020022002802001180808080000002402000280204450d00200341002802c0a3c68000118080808000000b200141046a22002000280200417f6a220036020020000d05200141002802c0a3c68000118080808000000c050b2002200b20097d370328200241286a108f8a8080000b200241d0006a200241186a290300370300200241c8006a200241106a290300370300200241286a41186a200241086a2903003703002002200229030037033820022002290320370330200241033a0028200241286a108e8a808000410021040b2004410874410e72210141b0a1c6800021030c010b2004410874200141ff017172210141d0a1c6800021030b2003280200118880808000002000200a37020c2000200937020420002001360200200241ff006a10fb818080000b20024180016a2480808080000bdd0502067f027e23808080800041e0006b2202248080808000024002400240024010fa81808000220341fe014b0d002002200341016a36022041b1e3c080004113200241206a410441002802e0a1c680001186808080000041002802e8a1c68000118880808000002001280228210420012d00042105200128020022032003280200417f6a2206360200024020060d00200341086a28020022072003410c6a28020022062802001180808080000002402006280204450d00200741002802c0a3c68000118080808000000b200341046a22062006280200417f6a220636020020060d00200341002802c0a3c68000118080808000000b0240200541ff01714101460d0041002101410221030c020b200241186a200141056a220341186a290000370300200241106a200341106a290000370300200241086a200341086a29000037030020022003290000370300200241206a41186a2001412c6a220141186a290000370300200241206a41106a200141106a290000370300200241206a41086a200141086a2900003703002002200129000037032041002101200241c0006a2002200241206a20042903004100109d8c808000200241c0006a41106a2903002108200241c0006a41086a290300210902402002280240450d00200228024422034108762101200341ff0171410e470d020b2001410874410e72210141b0a1c6800021030c020b200041093b0100200128020022012001280200417f6a220036020020000d02200141086a28020022032001410c6a28020022002802001180808080000002402000280204450d00200341002802c0a3c68000118080808000000b200141046a22002000280200417f6a220036020020000d02200141002802c0a3c68000118080808000000c020b2001410874200341ff017172210141d0a1c6800021030b2003280200118880808000002000200837020c2000200937020420002001360200200241df006a10fb818080000b200241e0006a2480808080000be70501057f23808080800041106b2202248080808000024002400240024010fa81808000220341fe014b0d002002200341016a36020841b1e3c080004113200241086a410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200128020022032003280200417f6a22043602002001280228210520012d00042101024020040d00200341086a28020022062003410c6a28020022042802001180808080000002402004280204450d00200641002802c0a3c68000118080808000000b200341046a22042004280200417f6a220436020020040d00200341002802c0a3c68000118080808000000b200141ff01710d010240200541086a2802002203450d002003417f6a41ffffffff01712106200541046a2802002204210102402003410171450d0020042802042004280208200441106a280200200441146a28020041002802e0a1c6800011868080800000200441186a21010b2006450d002004200341186c6a210303402001280204200141086a280200200141106a280200200141146a28020041002802e0a1c68000118680808000002001411c6a280200200141206a280200200141286a2802002001412c6a28020041002802e0a1c6800011868080800000200141306a22012003470d000b0b4100210141002802b0a1c6800011888080800000200041003a001820004200370308200042023703000c020b200041003a001820004200370300200041093b0120200128020022012001280200417f6a220036020020000d02200141086a28020022032001410c6a28020022002802001180808080000002402000280204450d00200341002802c0a3c68000118080808000000b200141046a22002000280200417f6a220036020020000d02200141002802c0a3c68000118080808000000c020b41002802d0a1c680001188808080000020004200370300200041003a0018200041086a4200370300410221010b200020013a00202002410f6a10fb818080000b200241106a2480808080000bb30301047f23808080800041106b22022480808080000240024010fa81808000220341fe014b0d002002200341016a36020841b1e3c080004113200241086a410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200128020022032003280200417f6a220436020020012d00042101024020040d00200341086a28020022052003410c6a28020022042802001180808080000002402004280204450d00200541002802c0a3c68000118080808000000b200341046a22042004280200417f6a220436020020040d00200341002802c0a3c68000118080808000000b41b0a1c6800041d0a1c68000200141ff017141014622011b280200118880808000002000410e410220011b3a00002002410f6a10fb818080000c010b200041093b0100200128020022012001280200417f6a220036020020000d00200141086a28020022032001410c6a28020022002802001180808080000002402000280204450d00200341002802c0a3c68000118080808000000b200141046a22002000280200417f6a220036020020000d00200141002802c0a3c68000118080808000000b200241106a2480808080000bd00602077f027e23808080800041d0026b22022480808080000240024010fa81808000220341fe014b0d002002200341016a36022041b1e3c080004113200241206a410441002802e0a1c680001186808080000041002802e8a1c680001188808080000020012d00102104200128020821052001280204210320012802002106200128020c22012001280200417f6a2207360200024020070d00200141086a28020022082001410c6a28020022072802001180808080000002402007280204450d00200841002802c0a3c68000118080808000000b200141046a22072007280200417f6a220736020020070d00200141002802c0a3c68000118080808000000b4102210102400240200441ff01710d00200241206a2003200510978a808000024020022d00202201410e470d004100210141e7adc4800041052003200541002802e0a1c6800011868080800000200241043a0020200241206a10f588808000200241163a0020200241023a0028200241206a108e8a80800002402006450d00200341002802c0a3c68000118080808000000b200241206a10e189808000200241c0026a290300210920022903b802210a41002802b0a1c68000118880808000002000420137030820004202370300411021030c020b200241176a200241306a280000360000200241106a200241296a290000370300200220022900213703080b02402006450d00200341002802c0a3c68000118080808000000b20002002290308370021200041306a200241176a28000036000041082103200041296a200241086a41086a29030037000041002802d0a1c680001188808080000042002109200042003703004201210a0b200020036a200a370300200020013a002020002009370318200241cf026a10fb818080000c010b200041003a001820004200370300200041093b0120200128020c22002000280200417f6a2203360200024020030d00200041086a28020022042000410c6a28020022032802001180808080000002402003280204450d00200441002802c0a3c68000118080808000000b200041046a22032003280200417f6a220336020020030d00200041002802c0a3c68000118080808000000b2001280200450d00200128020441002802c0a3c68000118080808000000b200241d0026a2480808080000bf10603037f027e027f23808080800041d0006b22022480808080000240024002400240024002400240024010fa81808000220341fe014b0d002002200341016a36022041b1e3c080004113200241206a410441002802e0a1c680001186808080000041002802e8a1c680001188808080000020012d00382104200129033021052001290328210620012d00042103200128020022012001280200417f6a2207360200024020070d00200141086a28020022082001410c6a28020022072802001180808080000002402007280204450d00200841002802c0a3c68000118080808000000b200141046a22072007280200417f6a220736020020070d00200141002802c0a3c68000118080808000000b200341ff01710d0102400240200650450d002005500d05200441ff01710d010c050b2005500d040b200242919fd78da1a1ad84ff003703282002429ceccef7a6c0dedd2037032020024290f1f7a1ea9083df363703382002428b87a199bee8b0f0ac7f37033041002d00fca3c680001a411241002802c8a3c68000118180808000002201450d0220012006370001200141013a000020012005370009200120043a0011200241206a41202001411241002802e0a1c6800011868080800000200141002802c0a3c68000118080808000002002410e3a000c0c040b200041093b0100200128020022012001280200417f6a220036020020000d06200141086a28020022032001410c6a28020022002802001180808080000002402000280204450d00200341002802c0a3c68000118080808000000b200141046a22002000280200417f6a220036020020000d06200141002802c0a3c68000118080808000000c060b200241023a000c0c030b4101411210b280808000000b2002410c6a410410d28880800020022d000c410e470d010b200241206a41106a2002410c6a41106a280200360200200241206a41086a2002410c6a41086a2902003703002002200229020c37032041b0a1c6800021010c010b200241206a41106a2002410c6a41106a280200360200200241206a41086a2002410c6a41086a2902003703002002200229020c37032041d0a1c6800021010b20002002290320370200200041106a200241206a41106a280200360200200041086a200241206a41086a290300370200200128020011888080800000200241cf006a10fb818080000b200241d0006a2480808080000bc20503057f047e017f23808080800041a0016b2202248080808000024002400240024010fa81808000220341fe014b0d002002200341016a36022841b1e3c080004113200241286a410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200128020022032003280200417f6a22043602002001280228210520012d00042101024020040d00200341086a28020022062003410c6a28020022042802001180808080000002402004280204450d00200641002802c0a3c68000118080808000000b200341046a22042004280200417f6a220436020020040d00200341002802c0a3c68000118080808000000b200141ff0171450d014102210141d0a1c6800021030c020b200041093b0100200128020022012001280200417f6a220036020020000d02200141086a28020022032001410c6a28020022002802001180808080000002402000280204450d00200341002802c0a3c68000118080808000000b200141046a22002000280200417f6a220036020020000d02200141002802c0a3c68000118080808000000c020b200241086a41186a2201200541186a2900002207370300200241086a41106a2203200541106a2900002208370300200241086a41086a2204200541086a290000220937030020022005290000220a370308200241c1006a22052007370000200241396a22062008370000200241316a220b20093700002002200a370029200241003a0028200241ff006a10ac8a808000200241286a200241ff006a4120109388808000200241c9006a20012903003700002005200329030037000020062004290300370000200b2002290308370000200241d1006a41003a0000200241063a0030200241163a0028200241286a108e8a808000410e210141b0a1c6800021030b200328020011888080800000200020013a00002002419f016a10fb818080000b200241a0016a2480808080000bae0401057f23808080800041306b22022480808080000240024002400240024010fa81808000220341fe014b0d002002200341016a36020c41b1e3c0800041132002410c6a410441002802e0a1c680001186808080000041002802e8a1c68000118880808000002001280228210420012d00042103200128020022012001280200417f6a2205360200024020050d00200141086a28020022062001410c6a28020022052802001180808080000002402005280204450d00200641002802c0a3c68000118080808000000b200141046a22052005280200417f6a220536020020050d00200141002802c0a3c68000118080808000000b200341ff01714101470d022002410c6a2004280204200428020822014100280298a3c680001185808080000020024184dec28000411010d08880800020022802000d014188dfc2800010a081808000000b200041093b0100200128020022012001280200417f6a220036020020000d03200141086a28020022032001410c6a28020022002802001180808080000002402000280204450d00200341002802c0a3c68000118080808000000b200141046a22002000280200417f6a220036020020000d03200141002802c0a3c68000118080808000000c030b200228020420012002410c6a41002802d0a3c6800011858080800000410e210141b0a1c6800021030c010b4102210141d0a1c6800021030b200328020011888080800000200020013a00002002412f6a10fb818080000b200241306a2480808080000b8e0601057f23808080800041106b2202248080808000024002400240024010fa81808000220341fe014b0d002002200341016a36020841b1e3c080004113200241086a410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200128020022032003280200417f6a22043602002001280228210520012d00042101024020040d00200341086a28020022062003410c6a28020022042802001180808080000002402004280204450d00200641002802c0a3c68000118080808000000b200341046a22042004280200417f6a220436020020040d00200341002802c0a3c68000118080808000000b200141ff01710d010240200541086a2802002204450d002004417f6a41ffffffff03712106200541046a28020022052101024020044103712203450d002005210103402001280204200141086a28020041002802a0a1c68000118480808000002001410c6a21012003417f6a22030d000b0b20064103490d0020052004410c6c6a210303402001280204200141086a28020041002802a0a1c6800011848080800000200141106a280200200141146a28020041002802a0a1c68000118480808000002001411c6a280200200141206a28020041002802a0a1c6800011848080800000200141286a2802002001412c6a28020041002802a0a1c6800011848080800000200141306a22012003470d000b0b4100210141002802b0a1c6800011888080800000200041003a001820004200370308200042023703000c020b200041003a001820004200370300200041093b0120200128020022012001280200417f6a220336020020030d02200141086a28020022002001410c6a28020022032802001180808080000002402003280204450d00200041002802c0a3c68000118080808000000b200141046a22032003280200417f6a220336020020030d02200141002802c0a3c68000118080808000000c020b41002802d0a1c680001188808080000020004200370300200041003a0018200041086a4200370300410221010b200020013a00202002410f6a10fb818080000b200241106a2480808080000b9c0502057f017e23808080800041106b2202248080808000024002400240024010fa81808000220341fe014b0d002002200341016a36020841b1e3c080004113200241086a410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200128020022032003280200417f6a22043602002001280228210520012d00042101024020040d00200341086a28020022062003410c6a28020022042802001180808080000002402004280204450d00200641002802c0a3c68000118080808000000b200341046a22042004280200417f6a220436020020040d00200341002802c0a3c68000118080808000000b200141ff01714101470d01410021010240200541086a2802002206450d0020064105742104200541046a2802002103410021010340200141016a2205417f20051b2001200310a08c8080001b2101200341206a2103200441606a22040d000b02400240200120064b0d002001ad428094ebdc037e2006ad8022074280808080105a0d002007a721010c010b418094ebdc0321010b200141ffd193ad034b21010b41002802b0a1c6800011888080800000200041003a001820004200370308200042023703000c020b200041003a001820004200370300200041093b0120200128020022012001280200417f6a220336020020030d02200141086a28020022042001410c6a28020022032802001180808080000002402003280204450d00200441002802c0a3c68000118080808000000b200141046a22032003280200417f6a220336020020030d02200141002802c0a3c68000118080808000000c020b41002802d0a1c680001188808080000020004200370300200041003a0018200041086a4200370300410221010b200020013a00202002410f6a10fb818080000b200241106a2480808080000bf30402057f017e23808080800041206b22022480808080000240024002400240024010fa81808000220341fe014b0d002002200341016a36020841b1e3c080004113200241086a410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200128020022032003280200417f6a22043602002001280228210520012d00042101024020040d00200341086a28020022062003410c6a28020022042802001180808080000002402004280204450d00200641002802c0a3c68000118080808000000b200341046a22042004280200417f6a220436020020040d00200341002802c0a3c68000118080808000000b200141ff0171450d0141002802d0a1c680001188808080000041022101420021070c020b200041003a001820004200370300200041093b0120200128020022002000280200417f6a220136020020010d02200041086a28020022032000410c6a28020022012802001180808080000002402001280204450d00200341002802c0a3c68000118080808000000b200041046a22012001280200417f6a220136020020010d02200041002802c0a3c68000118080808000000c020b4100210141002d00fca3c680001a410841002802c8a3c68000118180808000002203450d022003200529030037000041bfd9c28000410a2003410841002802e0a1c6800011868080800000200341002802c0a3c6800011808080800000200241043a0008200241086a10f58880800041002802b0a1c6800011888080800000420221070b200020013a0020200041003a001820004200370308200020073703002002411f6a10fb818080000b200241206a2480808080000f0b4101410810b280808000000bfc0304027f027e017f017e23808080800041c0006b2202248080808000024002400240024010fa81808000220341fe014b0d002002200341016a36021041b1e3c080004113200241106a410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200241306a41086a200141086a28020036020020022001290200370330200241106a200241306a109c8a80800042022104200229031022054202510d01200220022800213602082002200241246a28000036000b20022d0020210120022802282103200228022c2106200229031821072000411c6a200228000b3600002000200228020836001941002802b0a1c6800011888080800000200020073703100c020b200041003a001820004200370300200041093b01202001280200450d02200128020441002802c0a3c68000118080808000000c020b2002200241216a2800003602082002200241246a28000036000b200241206a2d00002101200241286a2802002103200229031821042000412c6a200228000b3600002000200228020836002941002802d0a1c680001188808080000020002003360230200020013a00282004422088a721062004a7210342002104410021010b2000200636022420002003360220200020013a001820002005370308200020043703002002413f6a10fb818080000b200241c0006a2480808080000be10502067f027e23808080800041e0006b2202248080808000024002400240024010fa81808000220341fe014b0d002002200341016a36022041b1e3c080004113200241206a410441002802e0a1c680001186808080000041002802e8a1c68000118880808000002001280228210420012d00042105200128020022032003280200417f6a2206360200024020060d00200341086a28020022072003410c6a28020022062802001180808080000002402006280204450d00200741002802c0a3c68000118080808000000b200341046a22062006280200417f6a220636020020060d00200341002802c0a3c68000118080808000000b0240200541ff01714101460d0041002101410221030c020b200241186a200141056a220341186a290000370300200241106a200341106a290000370300200241086a200341086a29000037030020022003290000370300200241206a41186a2001412c6a220141186a290000370300200241206a41106a200141106a290000370300200241206a41086a200141086a29000037030020022001290000370320200241c0006a2002200241206a20042903004102109d8c808000200241c0006a41106a2903002108200241c0006a41086a29030021090240024020022802400d00410021010c010b200228024422034108762101200341ff0171410e470d020b2001410874410e72210141b0a1c6800021030c020b200041093b0100200128020022012001280200417f6a220036020020000d02200141086a28020022032001410c6a28020022002802001180808080000002402000280204450d00200341002802c0a3c68000118080808000000b200141046a22002000280200417f6a220036020020000d02200141002802c0a3c68000118080808000000c020b2001410874200341ff017172210141d0a1c6800021030b2003280200118880808000002000200837020c2000200937020420002001360200200241df006a10fb818080000b200241e0006a2480808080000b880502067f017e23808080800041a0016b2202248080808000024002400240024010fa81808000220341fe014b0d002002200341016a36024841b1e3c080004113200241c8006a410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200128020022032003280200417f6a22043602002001280228210520012d00042106024020040d00200341086a28020022072003410c6a28020022042802001180808080000002402004280204450d00200741002802c0a3c68000118080808000000b200341046a22042004280200417f6a220436020020040d00200341002802c0a3c68000118080808000000b200641ff01714101460d014102210141d0a1c680002103420021080c020b200041003a001820004200370300200041093b0120200128020022002000280200417f6a220136020020010d02200041086a28020022032000410c6a28020022012802001180808080000002402001280204450d00200341002802c0a3c68000118080808000000b200041046a22012001280200417f6a220136020020010d02200041002802c0a3c68000118080808000000c020b200241196a200141056a220141186a290000370000200241116a200141106a290000370000200241096a200141086a2900003700002002200129000037000141002101200241216a200528020420052802084100280298a3c6800011858080800000200241053a0000200241c8006a41086a200241c80010848e8080001a200241163a0048200241c8006a108e8a8080004202210841b0a1c6800021030b200328020011888080800000200020013a0020200041003a001820004200370308200020083703002002419f016a10fb818080000b200241a0016a2480808080000bf50301067f23808080800041106b2202248080808000024002400240024010fa81808000220341fe014b0d002002200341016a36020841b1e3c080004113200241086a410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200128020022032003280200417f6a2204360200200128022c21052001280228210620012d00042101024020040d00200341086a28020022072003410c6a28020022042802001180808080000002402004280204450d00200741002802c0a3c68000118080808000000b200341046a22042004280200417f6a220436020020040d00200341002802c0a3c68000118080808000000b200141ff01714101460d014102210141d0a1c6800021030c020b200041093b0100200128020022012001280200417f6a220036020020000d02200141086a28020022032001410c6a28020022002802001180808080000002402000280204450d00200341002802c0a3c68000118080808000000b200141046a22002000280200417f6a220036020020000d02200141002802c0a3c68000118080808000000c020b200628020420062802082005280204200528020841002802b8a3c6800011868080800000410e210141b0a1c6800021030b200328020011888080800000200020013a00002002410f6a10fb818080000b200241106a2480808080000be40301057f23808080800041106b2202248080808000024002400240024010fa81808000220341fe014b0d002002200341016a36020841b1e3c080004113200241086a410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200128020022032003280200417f6a22043602002001280228210520012d00042101024020040d00200341086a28020022062003410c6a28020022042802001180808080000002402004280204450d00200641002802c0a3c68000118080808000000b200341046a22042004280200417f6a220436020020040d00200341002802c0a3c68000118080808000000b200141ff01714101460d014102210141d0a1c6800021030c020b200041093b0100200128020022012001280200417f6a220036020020000d02200141086a28020022032001410c6a28020022002802001180808080000002402000280204450d00200341002802c0a3c68000118080808000000b200141046a22002000280200417f6a220036020020000d02200141002802c0a3c68000118080808000000c020b2005280204200528020841002802b0a3c6800011848080800000410e210141b0a1c6800021030b200328020011888080800000200020013a00002002410f6a10fb818080000b200241106a2480808080000b980502077f027e23808080800041c0006b22022480808080000240024002400240024010fa81808000220341fe014b0d002002200341016a36020041b1e3c0800041132002410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200128022c21042001280228210520012d00042106200128020022032003280200417f6a2207360200024020070d00200341086a28020022082003410c6a28020022072802001180808080000002402007280204450d00200841002802c0a3c68000118080808000000b200341046a22072007280200417f6a220736020020070d00200341002802c0a3c68000118080808000000b200641ff01714101470d01200241186a200141056a220141186a290000370300200241106a200141106a290000370300200241086a200141086a2900003703002002200129000037030041002101200241206a2002200429030020052d000041017441004100109e8c808000200241206a41106a2903002109200241206a41086a290300210a02402002280220450d00200228022422034108762101200341ff0171410e470d030b2001410874410e72210141b0a1c6800021030c030b200041093b0100200128020022012001280200417f6a220036020020000d03200141086a28020022032001410c6a28020022002802001180808080000002402000280204450d00200341002802c0a3c68000118080808000000b200141046a22002000280200417f6a220036020020000d03200141002802c0a3c68000118080808000000c030b41002101410221030b2001410874200341ff017172210141d0a1c6800021030b2003280200118880808000002000200937020c2000200a370204200020013602002002413f6a10fb818080000b200241c0006a2480808080000ba40401067f23808080800041306b2202248080808000024002400240024010fa81808000220341fe014b0d002002200341016a36020841b1e3c080004113200241086a410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200128020022032003280200417f6a22043602002001280228210520012d00042106024020040d00200341086a28020022072003410c6a28020022042802001180808080000002402004280204450d00200741002802c0a3c68000118080808000000b200341046a22042004280200417f6a220436020020040d00200341002802c0a3c68000118080808000000b200641ff01710d01200241086a41186a2001412c6a220141186a290000370300200241086a41106a200141106a290000370300200241086a41086a200141086a29000037030020022001290000370308200241086a2005290300109f8c8080001a41002802b0a1c6800011888080800000410e21010c020b200041093b0100200128020022012001280200417f6a220036020020000d02200141086a28020022032001410c6a28020022002802001180808080000002402000280204450d00200341002802c0a3c68000118080808000000b200141046a22002000280200417f6a220036020020000d02200141002802c0a3c68000118080808000000c020b41002802d0a1c6800011888080800000410221010b200020013a00002002412f6a10fb818080000b200241306a2480808080000ba10501067f23808080800041106b220224808080800002400240024002400240024010fa81808000220341fe014b0d002002200341016a36020841b1e3c080004113200241086a410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200128020022032003280200417f6a2204360200200128022c21052001280228210620012d00042101024020040d00200341086a28020022072003410c6a28020022042802001180808080000002402004280204450d00200741002802c0a3c68000118080808000000b200341046a22042004280200417f6a220436020020040d00200341002802c0a3c68000118080808000000b200141ff01710d0141002101200220062802042204200628020822034101200528020041002802a8a1c680001187808080000002402002280200450d002003450d002003417f4c0d0541002d00fca3c680001a200341002802c8a3c68000118180808000002206450d0620062004200310848e80800041002802c0a3c68000118080808000000b41002802b0a1c6800011888080800000200041003a001820004200370308200042023703000c020b200041003a001820004200370300200041093b0120200128020022002000280200417f6a220136020020010d02200041086a28020022032000410c6a28020022012802001180808080000002402001280204450d00200341002802c0a3c68000118080808000000b200041046a22012001280200417f6a220136020020010d02200041002802c0a3c68000118080808000000c020b41002802d0a1c680001188808080000020004200370300200041003a0018200041086a4200370300410221010b200020013a00202002410f6a10fb818080000b200241106a2480808080000f0b10ae80808000000b4101200310b280808000000bcf0502077f027e23808080800041b0026b22022480808080000240024010fa81808000220341fe014b0d002002200341016a36020041b1e3c0800041132002410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200128020c22032003280200417f6a220436020020012d00102105200128020821062001280204210720012802002108024020040d00200341086a28020022042003410c6a28020022012802001180808080000002402001280204450d00200441002802c0a3c68000118080808000000b200341046a22012001280200417f6a220136020020010d00200341002802c0a3c68000118080808000000b02400240200541ff01710d004100210141e7adc4800041052007200641002802e0a1c6800011868080800000200241043a0000200210f588808000200241163a0000200241023a00082002108e8a80800002402008450d00200741002802c0a3c68000118080808000000b200210e189808000200241a0026a2903002109200229039802210a41002802b0a1c68000118880808000002000420137030820004202370300411021030c010b02402008450d00200741002802c0a3c68000118080808000000b41002802d0a1c68000118880808000004200210920004200370300410221014201210a410821030b200020036a200a370300200020013a002020002009370318200241af026a10fb818080000c010b200041003a001820004200370300200041093b0120200128020c22002000280200417f6a2203360200024020030d00200041086a28020022042000410c6a28020022032802001180808080000002402003280204450d00200441002802c0a3c68000118080808000000b200041046a22032003280200417f6a220336020020030d00200041002802c0a3c68000118080808000000b2001280200450d00200128020441002802c0a3c68000118080808000000b200241b0026a2480808080000bc20503057f047e017f23808080800041a0016b2202248080808000024002400240024010fa81808000220341fe014b0d002002200341016a36022841b1e3c080004113200241286a410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200128020022032003280200417f6a22043602002001280228210520012d00042101024020040d00200341086a28020022062003410c6a28020022042802001180808080000002402004280204450d00200641002802c0a3c68000118080808000000b200341046a22042004280200417f6a220436020020040d00200341002802c0a3c68000118080808000000b200141ff0171450d014102210141d0a1c6800021030c020b200041093b0100200128020022012001280200417f6a220036020020000d02200141086a28020022032001410c6a28020022002802001180808080000002402000280204450d00200341002802c0a3c68000118080808000000b200141046a22002000280200417f6a220036020020000d02200141002802c0a3c68000118080808000000c020b200241086a41186a2201200541186a2900002207370300200241086a41106a2203200541106a2900002208370300200241086a41086a2204200541086a290000220937030020022005290000220a370308200241c1006a22052007370000200241396a22062008370000200241316a220b20093700002002200a370029200241013a0028200241ff006a10ac8a808000200241286a200241ff006a4120109388808000200241c9006a20012903003700002005200329030037000020062004290300370000200b2002290308370000200241d1006a41013a0000200241063a0030200241163a0028200241286a108e8a808000410e210141b0a1c6800021030b200328020011888080800000200020013a00002002419f016a10fb818080000b200241a0016a2480808080000bfb0602067f027e2380808080004180016b220224808080800002400240024002400240024010fa81808000220341fe014b0d002002200341016a36023841b1e3c080004113200241386a410441002802e0a1c680001186808080000041002802e8a1c68000118880808000002001280228210420012d00042105200128020022032003280200417f6a2206360200024020060d00200341086a28020022072003410c6a28020022062802001180808080000002402006280204450d00200741002802c0a3c68000118080808000000b200341046a22062006280200417f6a220636020020060d00200341002802c0a3c68000118080808000000b0240200541ff01714101460d0041002101410221030c040b2001412c6a2103200241186a200141056a220141186a290000370300200241106a200141106a290000370300200241086a200141086a2900003703002002200129000037030020042d00002101200241386a200210fa878080004200200241e0006a2903002208200241d8006a2903007d220920092008561b210820014101742105200241386a41186a290300210920010d012009500d02200241386a200210fa878080002002280268450d02200228026c4102490d010c020b200041093b0100200128020022012001280200417f6a220036020020000d04200141086a28020022032001410c6a28020022002802001180808080000002402000280204450d00200341002802c0a3c68000118080808000000b200141046a22002000280200417f6a220036020020000d04200141002802c0a3c68000118080808000000c040b2008428080e983b1de162008428080e983b1de16561b21080b200241386a41186a200341186a290000370300200241386a41106a200341106a290000370300200241386a41086a200341086a29000037030020022003290000370338200241206a2002200241386a4200200920087d220820082009561b2005109d8c808000200241206a41106a2903002109200241206a41086a29030021080240024020022802200d00410021010c010b200228022422034108762101200341ff0171410e470d010b2001410874410e72210141b0a1c6800021030c010b2001410874200341ff017172210141d0a1c6800021030b2003280200118880808000002000200937020c2000200837020420002001360200200241ff006a10fb818080000b20024180016a2480808080000bb20802067f027e23808080800041a0016b2202248080808000024002400240024002400240024010fa81808000220341fe014b0d002002200341016a36024041b1e3c080004113200241c0006a410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200128022c21042001280228210520012d00042103200128020022012001280200417f6a2206360200024020060d00200141086a28020022072001410c6a28020022062802001180808080000002402006280204450d00200741002802c0a3c68000118080808000000b200141046a22062006280200417f6a220636020020060d00200141002802c0a3c68000118080808000000b200341ff01710d010240200529030050450d00410c21010c030b20024298d5afd2c6aeacae2f370348200242c2cdc8b0c7b9e78f857f370340200242e4c5bdb4b2e9a5a6807f370358200242d790d7a3fef9fda0c800370350200241186a200241c0006a10e6888080002002290320420020022802181b2108200529030021090240024020042d00000d00427f200820097c220920092008541b21090c010b4200200820097d220920092008561b21090b20024298d5afd2c6aeacae2f370348200242c2cdc8b0c7b9e78f857f370340200242a2bba4efe3ffa586553703582002429c9a9bbf88a5a0fc937f370350200241086a200241c0006a10e68880800002402002280208450d00410b210120022903102009560d030b20024298d5afd2c6aeacae2f370348200242c2cdc8b0c7b9e78f857f370340200242e4c5bdb4b2e9a5a6807f370358200242d790d7a3fef9fda0c8003703502002200937039001200241c0006a412020024190016a410841002802e0a1c68000118680808000002002200937035020022008370348200241153a0040200241c0006a108e8a8080002002410e3a002c0c030b200041093b0100200128020022012001280200417f6a220036020020000d05200141086a28020022032001410c6a28020022002802001180808080000002402000280204450d00200341002802c0a3c68000118080808000000b200141046a22002000280200417f6a220036020020000d05200141002802c0a3c68000118080808000000c050b200241023a002c0c020b2002412c6a200110f88880800020022d002c410e470d010b200241c0006a41106a2002412c6a41106a280200360200200241c0006a41086a2002412c6a41086a2902003703002002200229022c37034041b0a1c6800021010c010b200241c0006a41106a2002412c6a41106a280200360200200241c0006a41086a2002412c6a41086a2902003703002002200229022c37034041d0a1c6800021010b20002002290340370200200041106a200241c0006a41106a280200360200200041086a200241c0006a41086a2903003702002001280200118880808000002002419f016a10fb818080000b200241a0016a2480808080000bdc0502077f027e23808080800041e0006b2202248080808000024002400240024010fa81808000220341fe014b0d002002200341016a3602204100210441b1e3c080004113200241206a410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200128020022032003280200417f6a22053602002001280228210620012d00042107024020050d00200341086a28020022082003410c6a28020022052802001180808080000002402005280204450d00200841002802c0a3c68000118080808000000b200341046a22052005280200417f6a220536020020050d00200341002802c0a3c68000118080808000000b0240200741ff0171450d00410221010c020b200241186a2001412c6a220341186a290000370300200241106a200341106a290000370300200241086a200341086a29000037030020022003290000370300200241206a41186a200141cc006a220141186a290000370300200241206a41106a200141106a290000370300200241206a41086a200141086a2900003703002002200129000037032041002104200241c0006a2002200241206a20062903004100109d8c808000200241c0006a41106a2903002109200241c0006a41086a290300210a02402002280240450d00200228024422014108762104200141ff0171410e470d020b2004410874410e72210141b0a1c6800021030c020b200041093b0100200128020022012001280200417f6a220036020020000d02200141086a28020022032001410c6a28020022002802001180808080000002402000280204450d00200341002802c0a3c68000118080808000000b200141046a22002000280200417f6a220036020020000d02200141002802c0a3c68000118080808000000c020b2004410874200141ff017172210141d0a1c6800021030b2003280200118880808000002000200937020c2000200a37020420002001360200200241df006a10fb818080000b200241e0006a2480808080000bc30202047f017e23808080800041106b22022480808080000240024010fa81808000220341fe014b0d002002200341016a36020841b1e3c080004113200241086a410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200128020c21030240024020012802002204418080808078470d002003280204200328020841002802a0a1c68000118480808000000c010b200128020421052003280204200328020820012902042206a72006422088a741002802e0a1c68000118680808000002004450d00200541002802c0a3c68000118080808000000b41002802b0a1c68000118880808000002000410e3a00002002410f6a10fb818080000c010b200041093b010020012802002200418080808078460d002000450d00200128020441002802c0a3c68000118080808000000b200241106a2480808080000bac0100024002400240024002400240200241746a0e12010404040404040404040404040404020400040b200141d5d9c28000411d10888e8080000d03200041013a00010c020b200141c9d9c28000410c10888e808000450d030c020b200141f2d9c28000411b10888e8080000d01200041023a00010b200041003a00000f0b2000200120024190dac28000410310e88a808000360204200041013a00000f0b200041003a0001200041003a00000bc80501087f23808080800041106b220224808080800002400240024002400240024002400240200141146a2802002203200141106a28020022044f0d00200128020c21050340200520036a2d0000220641776a220741194b0d06024041012007744193808004710d0020074119470d07200241046a200110ee8a80800020022d00040d0320022d00050e03040506040b2001200341016a220336021420042003470d000b0b2002410536020420002001200241046a10c78a8080003602040c050b200020022802083602040c040b41002105200041003a00010c040b200041013a0001410021050c030b200041023a0001410021050c020b0240200641fb00460d002002410a36020420002001200241046a10c78a8080003602040c010b200120012d0018417f6a22073a00180240200741ff0171450d002001200341016a360214200241046a200110ee8a80800002400240024020022d00040d0020022d00052107200110d78a80800022030d01024002400240024020070e03000102000b200110f08a80800022030d04410021080c020b200110f08a80800022030d03410121080c010b200110f08a80800022030d02410221080b41012105200120012d001841016a3a0018024020012802142203200128021022094f0d00200128020c21060340200620036a2d0000220441776a220741174b0d044101200774419380800471450d042001200341016a220336021420092003470d000b0b2002410336020420002001200241046a10d88a8080003602040c050b200228020821030b2000200336020441012105200120012d001841016a3a00180c030b0240200441fd00470d00200020083a00012001200341016a360214410021050c030b2002410a36020420002001200241046a10d88a8080003602040c010b2002411836020420002001200241046a10c78a8080003602040b410121050b200020053a0000200241106a2480808080000bb70301047f23808080800041106b220224808080800041052103024002400240024002400240024002400240200128020022040e03000201000b417f2001410c6a28020041286c220341246a220520052003410472491b41016a2203450d022003417f4a0d0110ae80808000000b411321030b41002d00fca3c680001a200341002802c8a3c68000118180808000002205450d052002200536020820022003360204024020040e03000304000b410021030c010b2002410036020c2002428080808010370204200241046a4100410110b18280800020022802082105200228020c21030b200520036a41013a00002002200341016a36020c200141046a200241046a10af8c8080000c020b200541023a0000410121032002410136020c2001280204210102402002280204417f6a41034b0d00200241046a4101410410b182808000200228020c21030b200228020820036a20013600002002200341046a36020c0c010b200541033a00002002410136020c200141086a200241046a10b08c8080000b20002002290204370200200041086a200241046a41086a280200360200200241106a2480808080000f0b4101200310b280808000000bb90703047f017e037f23808080800041206b220224808080800002400240417f200141d8006a280200220341286c220441cd006a220520052004410472491b2204417f4c0d0041002d00fca3c680001a200441002802c8a3c68000118180808000002205450d01200220053602102002200436020c200520012903183700002002410836021420012903202106410821040240200228020c4178714108470d002002410c6a4108410810b182808000200228021421040b200228021020046a20063700002002200441086a2204360214200129032821060240200228020c20046b41074b0d002002410c6a2004410810b182808000200228021421040b200228021020046a20063700002002200441086a360214200141d4006a2802002104200220033602182002200241186a36021c2002411c6a2002410c6a10c08a8080002002280214210502402003450d002004200341286c6a210703400240200228020c220820056b411f4b0d002002410c6a2005412010b182808000200228020c2108200228021421050b2002280210220920056a22032004290000370000200341186a200441186a290000370000200341106a200441106a290000370000200341086a200441086a2900003700002002200541206a2205360214200441206a29030021060240200820056b41074b0d002002410c6a2005410810b18280800020022802102109200228021421050b200920056a20063700002002200541086a2205360214200441286a22042007470d000b0b200141306a21040240200228020c220820056b411f4b0d002002410c6a2005412010b182808000200228020c2108200228021421050b2002280210220920056a22032004290000370000200341086a200441086a290000370000200341106a200441106a290000370000200341186a200441186a2900003700002002200541206a2204360214200129030021060240200820046b41074b0d002002410c6a2004410810b18280800020022802102109200228020c2108200228021421040b200920046a20063700002002200441086a2204360214200129030821060240200820046b41074b0d002002410c6a2004410810b18280800020022802102109200228021421040b200920046a20063700002002200441086a220436021420012d001021050240200228020c2004470d002002410c6a2004410110b182808000200228021421040b200228021020046a20053a0000200041086a200441016a3602002000200229020c370200200241206a2480808080000f0b10ae80808000000b4101200410b280808000000bf40603047f017e037f23808080800041206b220224808080800002400240417f200141c8006a280200220341286c220441c5006a220520052004410472491b2204417f4c0d0041002d00fca3c680001a200441002802c8a3c68000118180808000002205450d01200220053602102002200436020c200520012903003700002002410836021420012903082106410821040240200228020c4178714108470d002002410c6a4108410810b182808000200228021421040b200228021020046a20063700002002200441086a2204360214200129031021060240200228020c220520046b41074b0d002002410c6a2004410810b182808000200228020c2105200228021421040b2002280210220720046a20063700002002200441086a2204360214200141186a29030021060240200520046b41074b0d002002410c6a2004410810b18280800020022802102107200228021421040b200720046a20063700002002200441086a360214200141c4006a2802002104200220033602182002200241186a36021c2002411c6a2002410c6a10c08a8080002002280214210502402003450d002004200341286c6a210803400240200228020c220720056b411f4b0d002002410c6a2005412010b182808000200228020c2107200228021421050b2002280210220920056a22032004290000370000200341186a200441186a290000370000200341106a200441106a290000370000200341086a200441086a2900003700002002200541206a2205360214200441206a29030021060240200720056b41074b0d002002410c6a2005410810b18280800020022802102109200228021421050b200920056a20063700002002200541086a2205360214200441286a22042008470d000b0b200141206a21040240200228020c20056b411f4b0d002002410c6a2005412010b182808000200228021421050b2002280210220720056a22032004290000370000200341086a200441086a290000370000200341106a200441106a290000370000200341186a200441186a2900003700002002200541206a220436021420012d004c21050240200228020c2004470d002002410c6a2004410110b18280800020022802102107200228021421040b200720046a20053a0000200041086a200441016a3602002000200229020c370200200241206a2480808080000f0b10ae80808000000b4101200410b280808000000b2100200128021441e691c28000411d200141186a28020028020c118280808000000b2100200128021441be91c280004112200141186a28020028020c118280808000000b02000be80802077f027e23808080800041d0006b220224808080800002400240024002400240200128020822030d002002420437020c200220033602080c010b2001280204210441002d00fca3c680001a2003410474220541002802c8a3c68000118180808000002201450d032004200341286c6a2106200241003602102002200136020c20022003360208034041002d00fca3c680001a024002400240412041002802c8a3c68000118180808000002203450d002002200336021c2002410236021820024100360220200241286a200441002f0194a1c6800010c887808000200228022c210502400240200228023022010d00410121070c010b2001417f4c0d0641002d00fca3c680001a200141002802c8a3c68000118180808000002207450d020b20072005200110848e808000210702402002280228450d00200541002802c0a3c68000118080808000000b200320022f00283b0001200341033a00002003200736020820032001360204200341036a200241286a41026a22082d00003a00002003200136020c20024101360220411421030240200429032022094290ce005a0d002009210a0c030b411421030340200241286a20036a2201417c6a200920094290ce0080220a4290ce007e7da7220541ffff037141e4006e220741017441b6dac280006a2f00003b00002001417e6a2005200741e4006c6b41ffff037141017441b6dac280006a2f00003b00002003417c6a2103200942ffc1d72f562101200a210920010d000c030b0b4104412010b280808000000b4101200110b280808000000b0240200aa7220541e3004d0d00200241286a2003417e6a22036a200aa72201200141ffff037141e4006e220541e4006c6b41ffff037141017441b6dac280006a2f00003b00000b024002402005410a490d00200241286a2003417e6a22016a200541017441b6dac280006a2f00003b00000c010b200241286a2003417f6a22016a200541306a3a00000b411420016b210341012105024020014114460d002003417f4c0d0341002d00fca3c680001a200341002802c8a3c68000118180808000002205450d040b2005200241286a20016a200310848e80800021050240200228022022012002280218470d00200241186a200110a386808000200228022021010b200228021c20014104746a2201200336020c2001200536020820012003360204200141023a00002002200228022041016a36022020022802182101200229021c21090240200228021022032002280208470d00200241086a200310a386808000200228021021030b200228020c20034104746a220320022f00283b0001200341043a00002003200937020820032001360204200341036a20082d00003a00002002200228021041016a360210200441286a22042006470d000b0b200241336a200241086a41086a280200360000200041043a00002002200229030837002b20002002290028370001200041086a2002412f6a290000370000200241d0006a2480808080000f0b10ae80808000000b4101200310b280808000000b4104200510b280808000000ba50702047f027e23808080800041106b22042480808080000240024020002d00000d0020002802042105024020002d00014101460d0002402005280200220628020020062802082207470d0020062007410110ab86808000200628020821070b200628020420076a412c3a00002006200741016a3602080b200041023a0001200520052001200210ae868080001a02402005280200220028020020002802082206470d0020002006410110ab86808000200028020821060b200028020420066a413a3a00002000200641016a36020802402005280200220028020020002802082206470d0020002006410110ab86808000200028020821060b200028020420066a41fb003a00002000200641016a36020820032903082108200329030021092005200541a8dac28000410110ae868080001a02402005280200220028020020002802082206470d0020002006410110ab86808000200028020821060b200028020420066a413a3a00002000200641016a36020802402005280200220028020020002802082206470d0020002006410110ab86808000200028020821060b200028020420066a41db003a00002000200641016a3602082004200536020c2004418002360208200441086a200910d486808000200441086a200810d4868080002004280208220041ff01710d01024020004180fe0371450d000240200428020c280200220028020020002802082206470d0020002006410110ab86808000200028020821060b200028020420066a41dd003a00002000200641016a3602080b20032d0010210602402005280200220028020020002802082203470d0020002003410110ab86808000200028020821030b200028020420036a412c3a00002000200341016a3602082005200541a9dac28000410d10ae868080001a02402005280200220028020020002802082203470d0020002003410110ab86808000200028020821030b200028020420036a413a3a00002000200341016a360208024002400240024020060e03000102000b2005200541c9d9c28000410c10ae868080001a0c020b2005200541d5d9c28000411d10ae868080001a0c010b2005200541f2d9c28000411b10ae868080001a0b02402005280200220528020020052802082200470d0020052000410110ab86808000200528020821000b200528020420006a41fd003a00002005200041016a360208200441106a24808080800041000f0b41f4d7c280004128418cdcc2800010f880808000000b41f4d7c28000412841bcdcc2800010f880808000000b980402057f017e23808080800041306b22022480808080000240024020002d00000d0020002802042103024020002d00014101460d0002402003280200220428020020042802082205470d0020042005410110ab86808000200428020821050b200428020420056a412c3a00002004200541016a3602080b200041023a00012003280200210641142100024020014290ce005a0d00200121070c020b411421000340200241086a20006a2203417c6a200120014290ce008022074290ce007e7da7220441ffff037141e4006e220541017441b6dac280006a2f00003b00002003417e6a2004200541e4006c6b41ffff037141017441b6dac280006a2f00003b00002000417c6a2100200142ffc1d72f5621032007210120030d000c020b0b41f4d7c28000412841acdcc2800010f880808000000b02402007a7220341e3004d0d00200241086a2000417e6a22006a2007a72203200341ffff037141e4006e220341e4006c6b41ffff037141017441b6dac280006a2f00003b00000b024002402003410a490d00200241086a2000417e6a22046a200341017441b6dac280006a2f00003b00000c010b200241086a2000417f6a22046a200341306a3a00000b02402006280200200628020822006b411420046b22034f0d0020062000200310ab86808000200628020821000b200628020420006a200241086a20046a200310848e8080001a2006200020036a360208200241306a2480808080000bda0101037f024020002d00000d0020002802042104024020002d00014101460d0002402004280200220528020020052802082206470d0020052006410110ab86808000200528020821060b200528020420066a412c3a00002005200641016a3602080b200041023a0001200420002001200210ae868080001a02402004280200220028020020002802082205470d0020002005410110ab86808000200028020821050b200028020420056a413a3a00002000200541016a3602082003200410a48c8080000f0b41f4d7c280004128418cdcc2800010f880808000000be50701047f23808080800041106b22042480808080000240024020002d00000d0020002802042105024020002d00014101460d0002402005280200220628020020062802082207470d0020062007410110ab86808000200628020821070b200628020420076a412c3a00002006200741016a3602080b200041023a0001200520052001200210ae868080001a200328020821062003280204210202402005280200220028020020002802082203470d0020002003410110ab86808000200028020821030b200028020420036a413a3a00002000200341016a36020802402005280200220028020020002802082203470d0020002003410110ab86808000200028020821030b200028020420036a41db003a00002000200341016a220336020802400240024020060d00024020002802002003470d0020002003410110ab86808000200028020821030b200028020420036a41dd003a00002000200341016a3602080c010b024020002802002003470d0020002003410110ab86808000200028020821030b200028020420036a41db003a00002000200341016a3602082004200536020c20044180043602082002200510ae8980800022000d01200441086a200229032010d4868080002004280208220041ff01710d03024020004180fe0371450d000240200428020c280200220028020020002802082203470d0020002003410110ab86808000200028020821030b200028020420036a41dd003a00002000200341016a3602080b024020064101460d002002200641286c6a2101200241286a2103034002402005280200220028020020002802082206470d0020002006410110ab86808000200028020821060b200028020420066a412c3a00002000200641016a36020802402005280200220028020020002802082206470d0020002006410110ab86808000200028020821060b200028020420066a41db003a00002000200641016a3602082004200536020c20044180043602082003200510ae8980800022000d03200441086a200341206a29030010d4868080002004280208220041ff01710d05024020004180fe0371450d000240200428020c280200220028020020002802082206470d0020002006410110ab86808000200028020821060b200028020420066a41dd003a00002000200641016a3602080b200341286a22032001470d000b0b02402005280200220528020020052802082200470d0020052000410110ab86808000200528020821000b200528020420006a41dd003a00002005200041016a3602080b410021000b200441106a24808080800020000f0b41f4d7c280004128418cdcc2800010f880808000000b41f4d7c28000412841bcdcc2800010f880808000000be80101047f024020002d00000d00200128020821032001280204210420002802042101024020002d00014101460d0002402001280200220528020020052802082206470d0020052006410110ab86808000200528020821060b200528020420066a412c3a00002005200641016a3602080b200041023a0001200120002004200310ae868080001a02402001280200220028020020002802082205470d0020002005410110ab86808000200028020821050b200028020420056a413a3a00002000200541016a3602082002200110af868080000f0b41f4d7c280004128418cdcc2800010f880808000000bca0501047f23808080800041106b2204248080808000024020002d00000d0020002802042105024020002d00014101460d0002402005280200220628020020062802082207470d0020062007410110ab86808000200628020821070b200628020420076a412c3a00002006200741016a3602080b200041023a0001200520042001200210ae868080001a200328020821022003280204210602402005280200220028020020002802082203470d0020002003410110ab86808000200028020821030b200028020420036a413a3a00002000200341016a36020802402005280200220028020020002802082203470d0020002003410110ab86808000200028020821030b200028020420036a41db003a00002000200341016a22033602080240024020020d00200041086a2106200041046a210520002802002003470d0120002003410110ab86808000200028020821030c010b200441046a200641002f0194a1c6800010c8878080002005200420042802082200200428020c10ae868080001a02402004280204450d00200041002802c0a3c68000118080808000000b024020024101460d00200641206a2106200241057441606a2102034002402005280200220028020020002802082203470d0020002003410110ab86808000200028020821030b200028020420036a412c3a00002000200341016a360208200441046a200641002f0194a1c6800010c8878080002005200420042802082200200428020c10ae868080001a02402004280204450d00200041002802c0a3c68000118080808000000b200641206a2106200241606a22020d000b0b02402005280200220028020020002802082203470d0020002003410110ab86808000200028020821030b200041086a2106200041046a21050b200528020020036a41dd003a00002006200341016a360200200441106a24808080800041000f0b41f4d7c280004128418cdcc2800010f880808000000bd70801047f23808080800041206b22042480808080000240024020002d00000d0020002802042105024020002d00014101460d0002402005280200220628020020062802082207470d0020062007410110ab86808000200628020821070b200628020420076a412c3a00002006200741016a3602080b200041023a0001200520042001200210ae868080001a200328020821012003280204210702402005280200220028020020002802082203470d0020002003410110ab86808000200028020821030b200028020420036a413a3a00002000200341016a36020802402005280200220028020020002802082203470d0020002003410110ab86808000200028020821030b200041086a2106200028020420036a41db003a00002000200341016a2203360208200041046a21020240024020010d0020002802002003470d0120002003410110ab86808000200028020821030c010b024020002802002003470d0020002003410110ab86808000200028020821030b200228020020036a41db003a00002006200341016a3602002004200536020c2004418004360208200441146a200741002f0194a1c6800010c8878080002005200420042802182200200428021c10ae868080001a02402004280214450d00200041002802c0a3c68000118080808000000b200441086a200729032010d4868080002004280208220041ff01710d02024020004180fe0371450d000240200428020c280200220028020020002802082203470d0020002003410110ab86808000200028020821030b200028020420036a41dd003a00002000200341016a3602080b024020014101460d002007200141286c6a2102200741286a2103034002402005280200220028020020002802082206470d0020002006410110ab86808000200028020821060b200028020420066a412c3a00002000200641016a36020802402005280200220028020020002802082206470d0020002006410110ab86808000200028020821060b200028020420066a41db003a00002000200641016a3602082004200536020c2004418004360208200441146a200341002f0194a1c6800010c8878080002005200420042802182200200428021c10ae868080001a02402004280214450d00200041002802c0a3c68000118080808000000b200441086a200341206a29030010d4868080002004280208220041ff01710d04024020004180fe0371450d000240200428020c280200220028020020002802082206470d0020002006410110ab86808000200028020821060b200028020420066a41dd003a00002000200641016a3602080b200341286a22032002470d000b0b02402005280200220528020020052802082203470d0020052003410110ab86808000200528020821030b200541086a2106200541046a21020b200228020020036a41dd003a00002006200341016a360200200441206a24808080800041000f0b41f4d7c280004128418cdcc2800010f880808000000b41f4d7c28000412841bcdcc2800010f880808000000bce0201037f024020002d00000d0020002802042104024020002d00014101460d0002402004280200220528020020052802082206470d0020052006410110ab86808000200528020821060b200528020420066a412c3a00002005200641016a3602080b200041023a0001200420002001200210ae868080001a02402004280200220028020020002802082205470d0020002005410110ab86808000200028020821050b200028020420056a413a3a00002000200541016a36020802402004280200220028020020002802082204470d0020002004410110ab86808000200028020821040b200028020420046a41fb003a00002000200441016a2204360208024020002802002004470d0020002004410110ab86808000200028020821040b200028020420046a41fd003a00002000200441016a36020841000f0b41f4d7c280004128418cdcc2800010f880808000000bda0101037f024020002d00000d0020002802042104024020002d00014101460d0002402004280200220528020020052802082206470d0020052006410110ab86808000200528020821060b200528020420066a412c3a00002005200641016a3602080b200041023a0001200420002001200210ae868080001a02402004280200220028020020002802082205470d0020002005410110ab86808000200028020821050b200028020420056a413a3a00002000200541016a3602082003200410b9878080000f0b41f4d7c280004128418cdcc2800010f880808000000bda0101037f024020002d00000d0020002802042104024020002d00014101460d0002402004280200220528020020052802082206470d0020052006410110ab86808000200528020821060b200528020420066a412c3a00002005200641016a3602080b200041023a0001200420002001200210ae868080001a02402004280200220028020020002802082205470d0020002005410110ab86808000200028020821050b200028020420056a413a3a00002000200541016a3602082003200410be888080000f0b41f4d7c280004128418cdcc2800010f880808000000b2100200128021441fedbc28000410c200141186a28020028020c118280808000000ba40a01097f200028020c2201200028020422026b41e8016e2103024020012002460d004100210403400240024002400240024002402002200441e8016c6a2201280200220541736a2206410220064104491b0e03010203000b20012d00084106470d042001410c6a280200450d04200141106a28020021070c030b0240024002400240024002400240024020012d0008417f6a0e0a010b0203040506070b0b000b2001410c6a280200450d0a200141106a28020021070c090b2001410c6a280200450d09200141106a28020021070c080b2001410c6a280200450d08200141106a28020021070c070b2001410c6a280200450d07200141106a28020021070c060b0240200141146a2802002205450d00200141106a2802002106034002402006280200450d00200641046a28020041002802c0a3c68000118080808000000b02402006410c6a280200450d00200641106a28020041002802c0a3c68000118080808000000b200641186a21062005417f6a22050d000b0b200128020c450d06200128021021070c050b0240200141146a2802002206450d00200141106a28020021072006410171210841002105024020064101460d002006417e7121094100210520072106034002402006280200450d00200641046a28020041002802c0a3c68000118080808000000b02402006410c6a280200450d00200641106a28020041002802c0a3c68000118080808000000b200641186a21062009200541026a2205470d000b0b2008450d0020072005410c6c6a2206280200450d00200628020441002802c0a3c68000118080808000000b200128020c450d05200128021021070c040b200141106a280200450d04200141146a28020021070c030b2001410c6a280200450d03200141106a28020021070c020b200141186a2d0000417d6a41ff017141014b0d020240200128020822074198016a2802002209450d004100210620074194016a2802002208210103402008200641146c6a21050240024002400240024020012d00000e0400010102040b200141086a21050c020b200541086a21050c010b200541046a21050b2005280200450d00200528020441002802c0a3c68000118080808000000b200641016a2106200141146a21012009417f6a22090d000b0b0240200728029001450d0020072802940141002802c0a3c68000118080808000000b024020074190026a2802002209450d00410021062007418c026a2802002208210103402008200641146c6a21050240024002400240024020012d00000e0400010102040b200141086a21050c020b200541086a21050c010b200541046a21050b2005280200450d00200528020441002802c0a3c68000118080808000000b200641016a2106200141146a21012009417f6a22090d000b0b200728028802450d01200728028c0241002802c0a3c68000118080808000000c010b0240024002400240024002402005417e6a0e06000102000003070b200141046a21010c030b02402001280210450d00200141146a28020041002802c0a3c68000118080808000000b20012802042206418080808078460d05200141046a21010c030b02402001280204450d00200141086a28020041002802c0a3c68000118080808000000b200141106a21010c010b0240024020012d00040e0400000001050b2001410c6a21010c010b200141086a21010b200128020021060b2006450d01200128020421070b200741002802c0a3c68000118080808000000b200441016a22042003470d000b0b02402000280208450d00200028020041002802c0a3c68000118080808000000b0bab0202017f017e23808080800041106b22042480808080002004200128020020022003109188808000024002400240024002402004280200450d00200441086a28020021010240200428020422030d002001ad422086210541808080807821010c020b0240024020010d00410121020c010b2001417f4c0d0341002d00fca3c680001a200141002802c8a3c68000118180808000002202450d040b2001ad42208620022003200110848e808000ad8421050c010b200420012802042002200310ec8780800020042802002201418180808078460d03200429020421050b2000200537020420002001360200200441106a2480808080000f0b10ae80808000000b4101200110b280808000000b41dcdcc2800041302004410f6a41ccdcc2800041f4ddc28000108981808000000b6f00200042a5e9e3ab9e929adc2c37030820004280808080c00037033820004280808080c000370350200041ef80808000360218200041023a0000200041106a4293888c8f89fdc6ec9e7f370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000be10101017f41002d00fca3c680001a0240413041002802c8a3c680001181808080000022010d004108413010b280808000000b200142e7b0a091f3ed9c85c500370318200142b891b68c98adebcf61370308200142e7b0a091f3ed9c85c500370300200141ea8180800036021020004280808080c00037033820004280808080c0003703502000410236020c2000200136020820004102360204200041043a0000200141206a42b891b68c98adebcf61370300200141286a41ea81808000360200200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6f00200042dbd791d5c2919eaecd0037030820004280808080c00037033820004280808080c000370350200041c880808000360218200041023a0000200041106a42e6ed8d82cc91adcb05370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000be10101017f41002d00fca3c680001a0240413041002802c8a3c680001181808080000022010d004108413010b280808000000b200142cbc4c4bdb7cedec904370318200142b891b68c98adebcf61370308200142e7b0a091f3ed9c85c500370300200141ea8180800036021020004280808080c00037033820004280808080c0003703502000410236020c2000200136020820004102360204200041043a0000200141206a42f3d1f7c4e49ca3ecb07f370300200141286a41eb81808000360200200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b7000200042b7a18ef9ac95b6cbeb0037030820004280808080c00037033820004280808080c000370350200041ec81808000360218200041023a0000200041106a42dda1fc828d83b3faab7f370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b70002000429ca0fdd992b0ed90df0037030820004280808080c00037033820004280808080c000370350200041ed81808000360218200041023a0000200041106a42bbf8f5b8b9e2c39ac400370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6e00200042d7c9cb8fc1cf97db3e37030820004280808080c00037033820004280808080c000370350200041b580808000360218200041023a0000200041106a42e88488d0c0e3aebc13370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6f002000428291fa9e999aa9d24637030820004280808080c00037033820004280808080c000370350200041ee81808000360218200041023a0000200041106a42bc90c1fdf28f8bb0ff00370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6e0020004280c6969198fdafd00537030820004280808080c00037033820004280808080c000370350200041ef81808000360218200041023a0000200041106a42eaacebad91f388e55c370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6f00200042c4ccab9c81ebb4b8db0037030820004280808080c00037033820004280808080c000370350200041f081808000360218200041023a0000200041106a42a4d2928ecac0faa432370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6e0020004285cbd9e891b2d0c16137030820004280808080c00037033820004280808080c000370350200041f181808000360218200041023a0000200041106a4282d2add5d4f1deea6a370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6f00200042d7c9c3bdedbdd399957f37030820004280808080c00037033820004280808080c000370350200041f281808000360218200041023a0000200041106a42a6f8d4ee83cba9e440370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6f00200042ee93e0d6a2949dcf3137030820004280808080c00037033820004280808080c000370350200041f381808000360218200041023a0000200041106a42c49beac9c5ace288fd00370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6e00200042e1e0d7feab89e9c84837030820004280808080c00037033820004280808080c000370350200041f481808000360218200041023a0000200041106a42d391b3b4c8e6f89148370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6f00200042c4ccab9c81ebb4b8db0037030820004280808080c00037033820004280808080c000370350200041f081808000360218200041023a0000200041106a42a4d2928ecac0faa432370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6f00200042c194a6a793ccc3a85737030820004280808080c00037033820004280808080c000370350200041f581808000360218200041023a0000200041106a42ab8bffbed784ffa5937f370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6f00200042ef8683cfe1dddaca6337030820004280808080c00037033820004280808080c000370350200041f681808000360218200041023a0000200041106a4284b2a2d692ae8580b57f370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b7000200042c9fea184df91c8afd40037030820004280808080c00037033820004280808080c000370350200041f781808000360218200041023a0000200041106a42e2a4dca09a8089e2927f370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6e00200042e5f0b3f4e8a9b1b12a37030820004280808080c00037033820004280808080c000370350200041f881808000360218200041023a0000200041106a4281ebc5ecd497b09a0a370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6e00200042a9c4d590f68dedef5837030820004280808080c00037033820004280808080c000370350200041f981808000360218200041023a0000200041106a42dbbc81a3c9e8f4e22a370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b7000200042acf6debeefe0d9c8d30037030820004280808080c00037033820004280808080c000370350200041bd80808000360218200041023a0000200041106a42efc9c9edb5e7b3a6c700370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000b6f00200042e7b0a091f3ed9c85c50037030820004280808080c00037033820004280808080c000370350200041ea81808000360218200041023a0000200041106a42b891b68c98adebcf61370300200041c8006a4208370300200041c0006a4200370300200041d8006a41003602000be10301077f23808080800041106b2203248080808000200041286a2104024002400240200028022822054128200541284b22061b22072000280204200520061b22066b200220016b22084f0d00200620086a22052006490d014100417f2005417f6a677620054102491b41016a2205450d01200341086a2000200510f786808000024020032802082205418180808078460d002005450d022005200328020c10b280808000000b200428020022054128200541284b1b21070b200041046a22092004200541284b22061b21080240024020004104412820061b6a280200220520074f0d002000280200200020061b2106034020012002460d02200620056a20012d00003a0000200141016a21012007200541016a2205470d000b200721050b2008200536020020012002460d02034020012d00002108024002402000410441282000280228220741284b22051b6a28020022062007412820051b460d002009200420051b21072000280200200020051b21050c010b200010f8868080002000280204210620002802002105200921070b200520066a20083a00002007200728020041016a360200200141016a22012002470d000c030b0b200820053602000c010b4198dfc28000411141d8e2c2800010f880808000000b200341106a2480808080000bc70301067f23808080800041106b220324808080800002400240024002400240200128020420012802282204200441284b22051b220620024b0d002004412820051b21072001280200200120051b2108024020024129490d00418180808078210520072002460d040240200241004e0d00410021050c060b02400240024020044129490d002007417f4a0d0120072102410021050c080b41002d00fca3c680001a200241002802c8a3c680001181808080000022040d01410121050c070b0240200241002802c8a3c680001181808080000022040d00410121050c070b200420082007200220072002491b10848e8080001a200841002802c0a3c68000118080808000000c040b20042008200610848e8080001a0c030b418180808078210520044129490d0320012008200610848e80800020063602282007417f4c0d01200841002802c0a3c68000118080808000000c030b41f8e2c2800041204198e3c2800010f880808000000b2003200736020c20034100360208418ce2c28000412b200341086a41b8e2c2800041c8e2c28000108981808000000b2001200236022820012006360204200120043602000b0b2000200236020420002005360200200341106a2480808080000bb90101027f23808080800041106b220124808080800002400240200028020420002802282202200241284b1b41016a2202450d004100417f2002417f6a677620024102491b41016a2202450d00200141086a2000200210f786808000024020012802082200418180808078460d002000450d022000200128020c10b280808000000b200141106a2480808080000f0b4198dfc28000411141e8e2c2800010a181808000000b4198dfc28000411141d8e2c2800010f880808000000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b220641386e2207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710a78680800020022802082109200228020c21080b2009200841386c6a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b41386e2107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b22064105762207200128020822014101764f0d01410021082002410036020c20024280808080800137020441082109024020052004460d00200241046a4100200710ac8680800020022802082109200228020c21080b200920084105746a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b4105762107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bab0201087f23808080800041106b220224808080800002400240024002402001280200220320012802042204460d00200128020c220520046b220641246e2207200128020822014101764f0d01410021082002410036020c20024280808080c00037020441042109024020052004460d00200241046a4100200710a98680800020022802082109200228020c21080b2009200841246c6a2004200610848e8080001a2002200820076a36020c02402001450d00200341002802c0a3c68000118080808000000b20002002290204370200200041086a200241046a41086a2802003602000c030b200128020c20036b41246e2107200128020821010c010b20032004200610fe8d8080001a0b2000200736020820002003360204200020013602000b200241106a2480808080000bdc03010d7f23808080800041106b2202248080808000024002400240024002402001280200220328020422044108490d002003280200220541076a2d00002106200541066a2d00002107200541056a2d00002108200541036a2d0000210920052d0004210a20052d0002210b20052d0001210c20052d0000210d2003200541086a3602002003200441786a360204200241086a200110bc8a808000024020022802080d002001280200220141046a2802002203200228020c2205490d000240024020050d00410121040c010b2005417f4c0d05200541002802c8a3c68000118180808000002204450d06200441002005108a8e8080001a200141046a28020021030b200320054f0d02200441002802c0a3c68000118080808000000b20004180808080783602080c020b20004180808080783602080c010b20042001280200220e200510848e80800021042000200b3a00022000200c3a00012000200d3a0000200141046a200320056b3602002001200e20056a36020020002005360208200041036a20093a000020002005ad4220862004ad8437020c2000200a3a0004200041056a20083a0000200041066a20073a0000200041076a20063a00000b200241106a2480808080000f0b10ae80808000000b4101200510b280808000000b980401077f23808080800041106b2202248080808000200241086a200110bc8a808000024002400240024002400240024020022802080d002001280200220341046a2802002204200228020c2205490d000240024020050d00410121060c010b2005417f4c0d03200541002802c8a3c68000118180808000002206450d04200641002005108a8e8080001a200341046a28020021040b200420054f0d01200641002802c0a3c68000118080808000000b20004180808080783602000c050b200620032802002207200510848e8080002106200341046a200420056b3602002003200720056a3602002002200110bc8a808000024020022802000d002001280200220341046a280200220420022802042201490d000240024020010d00410121070c010b2001417f4c0d02200141002802c8a3c68000118180808000002207450d04200741002001108a8e8080001a200341046a28020021040b200420014f0d04200741002802c0a3c68000118080808000000b20004180808080783602002005450d04200641002802c0a3c68000118080808000000c040b10ae80808000000b4101200510b280808000000b4101200110b280808000000b200720032802002208200110848e8080002107200341046a200420016b3602002003200820016a3602002000200136020c20002005360208200020063602042000200536020020002001ad4220862007ad843702100b200241106a2480808080000b840201047f23808080800041106b2202248080808000200028020421032002200028020822043602082002200241086a36020c2002410c6a200110c08a80800002402001280200200128020822056b20044f0d0020012005200410b182808000200128020821050b200128020420056a2003200410848e8080001a2001200520046a360208200041106a28020021052002200041146a28020022003602082002200241086a36020c2002410c6a200110c08a80800002402001280200200128020822046b20004f0d0020012004200010b182808000200128020821040b200128020420046a2005200010848e8080001a2001200420006a360208200241106a2480808080000b02000bb70202067f017e23808080800041106b2202248080808000200028020421032002200028020822003602082002200241086a36020c2002410c6a200110c08a80800002402000450d002003200041286c6a210420012802082100034002402001280200220520006b411f4b0d0020012000412010b18280800020012802002105200128020821000b2001280204220620006a22072003290000370000200741186a200341186a290000370000200741106a200341106a290000370000200741086a200341086a2900003700002001200041206a2207360208200341206a29030021080240200520076b41074b0d0020012007410810b18280800020012802042106200128020821070b2001200741086a2200360208200620076a2008370000200341286a22032004470d000b0b200241106a2480808080000b850202067f017e23808080800041106b2202248080808000200028020421032002200028020822003602082002200241086a36020c2002410c6a200110c08a80800002402000450d00200320004104746a210420012802082100034002402001280200220520006b41074b0d0020012000410810b18280800020012802002105200128020821000b2001200041086a22063602082001280204220720006a2003290300370000200341086a29030021080240200520066b41074b0d0020012006410810b18280800020012802042107200128020821060b2001200641086a2200360208200720066a2008370000200341106a22032004470d000b0b200241106a2480808080000b880203037f017e047f23808080800041106b2202248080808000200028020421032002200028020822003602082002200241086a36020c2002410c6a200110c08a80800002402000450d00200320004104746a21042001280208210003402003290300210502402001280200220620006b41074b0d0020012000410810b18280800020012802002106200128020821000b2001200041086a22073602082001280204220820006a2005370000200328020821090240200620076b41034b0d0020012007410410b18280800020012802042108200128020821070b2001200741046a2200360208200820076a2009360000200341106a22032004470d000b0b200241106a2480808080000b4901017f02402000280200200028020822036b20024f0d0020002003200210ab86808000200028020821030b200028020420036a2001200210848e8080001a2000200320026a3602080bc90103057f027e017f20012802082102200128020022032104024020012802042205200128020c2206460d0020032104034002402005290300220742efb7e9de94adbae42685200541086a290300220842c785eb8b8b8eddc0618584500d0020052802102109200420083703082004200737030020042009360210200441186a21040b200541186a22052006470d000b0b200142888080808001370200200142808080808001370208200020033602042000200420036b41186e3602082000200241186c41186e3602000bc70201067f23808080800041106b220524808080800020032802042106200328020021070240200128020022012802082203200320026a22084f0d00200321080240200128020020036b20024f0d0020012003200210ab86808000200128020821080b2001280204220920086a210a024020024102490d00200a41002002417f6a2202108a8e8080001a2009200820026a22086a210a0b200a41003a0000200841016a21080b20012008360208024020082003490d00200541086a20072006200128020420036a200820036b200410bc80808000200528020c21080240024020052802082202418380c400470d0002402001280208200820036a2203490d00200120033602080b2000418380c400360200200020083602040c010b20002008360204200020023602000b200541106a2480808080000f0b200320084190e1c28000109481808000000bdb0101047f23808080800041106b22022480808080002000280208210320002802042100410121042001280214418fa5c080004101200141186a28020028020c118280808000002105200241003a0009200220053a00082002200136020402402003450d0003402002200036020c200241046a2002410c6a41d0cfc48000108e818080001a200041016a21002003417f6a22030d000b20022d000821050b0240200541ff01710d00200228020422002802144190a5c080004101200041186a28020028020c1182808080000021040b200241106a24808080800020040ba90201027f23808080800041106b22022480808080000240024020002802000d00200128021441a9dfc280004110200141186a28020028020c1182808080000021010c010b20022000360204200128021441b9dfc280004108200141186a28020028020c118280808000002100200241003a000d200220003a000c20022001360208200241086a41c1dfc280004106200241046a41c8dfc28000108c81808000210320022d000c2100024020022d000d0d00200041ff017141004721010c010b41012101200041ff01710d000240200328020022012d001c4104710d0020012802144187a5c080004102200128021828020c1182808080000021010c010b20012802144186a5c080004101200128021828020c1182808080000021010b200241106a24808080800020010bcc0501087f23808080800041206b22032480808080002003200136021c2003410036021820032002360214200341086a200341146a10bc8a808000024002400240024002400240024020032802080d002003280214220441046a2802002205200328020c2201490d000240024020010d00410121060c010b2001417f4c0d03200141002802c8a3c68000118180808000002206450d04200641002001108a8e8080001a200441046a28020021050b024020052001490d00200620042802002207200110848e8080002108200441046a200520016b3602002004200720016a3602002003200341146a10bc8a8080000240024020032802000d002003280214220541046a280200220720032802042204490d000240024020040d00410121090c010b2004417f4c0d06200441002802c8a3c68000118180808000002209450d08200941002004108a8e8080001a200541046a28020021070b200720044f0d01200941002802c0a3c68000118080808000000b20010d010c020b20092005280200220a200410848e8080002109200541046a200720046b3602002005200a20046a3602000240200328021422052802042207450d0020052007417f6a36020420052005280200220741016a3602004101410220072d000022054101461b410020051b22054102470d030b02402004450d00200941002802c0a3c68000118080808000000b2001450d010b200641002802c0a3c68000118080808000000b20004180808080783602000c050b2002280204450d03200041808080807836020002402001450d00200841002802c0a3c68000118080808000000b2004450d04200941002802c0a3c68000118080808000000c040b10ae80808000000b4101200110b280808000000b4101200410b280808000000b200020053a001820002004360214200020093602102000200436020c2000200136020820002008360204200020013602000b200341206a2480808080000bb20501087f23808080800041206b22032480808080002003200136021c2003410036021820032002360214200341086a200341146a10bc8a8080000240024020032802080d002003280214220441046a2802002205200328020c2201490d00024002400240024002400240024020010d00410121060c010b2001417f4c0d01200141002802c8a3c68000118180808000002206450d02200641002001108a8e8080001a200441046a28020021050b20052001490d04200620042802002207200110848e8080002108200441046a200520016b3602002004200720016a3602002003200341146a10bc8a8080000240024020032802000d002003280214220541046a280200220720032802042204490d000240024020040d00410121090c010b2004417f4c0d03200441002802c8a3c68000118180808000002209450d05200941002004108a8e8080001a200541046a28020021070b200720044f0d01200941002802c0a3c68000118080808000000b20010d050c060b20092005280200220a200410848e8080002109200541046a200720046b3602002005200a20046a3602002003280214220528020422074104490d0320052007417c6a36020420052005280200220641046a360200024020022802040d002000200628000036021820002004360214200020093602102000200436020c2000200136020820002008360204200020013602000c070b200041808080807836020002402001450d00200841002802c0a3c68000118080808000000b2004450d06200941002802c0a3c68000118080808000000c060b10ae80808000000b4101200110b280808000000b4101200410b280808000000b02402004450d00200941002802c0a3c68000118080808000000b2001450d010b200641002802c0a3c68000118080808000000b20004180808080783602000b200341206a2480808080000baf0201087f02400240024002400240200128020822020d00410421030c010b200241aad5aad5004b0d022002410c6c2204417f4c0d022001280204210541002d00fca3c680001a200441002802c8a3c68000118180808000002203450d014100210620022107034020042006460d012005280204210802400240200528020822010d00410121090c010b2001417f4c0d0441002d00fca3c680001a200141002802c8a3c68000118180808000002209450d050b2005410c6a210520092008200110848e8080002109200320066a22082001360200200841086a2001360200200841046a20093602002006410c6a21062007417f6a22070d000b0b2000200236020820002003360204200020023602000f0b4104200410b280808000000b10ae80808000000b4101200110b280808000000b840101027f200128020421020240024002400240200128020822010d00410121030c010b2001417f4c0d0141002d00fca3c680001a200141002802c8a3c68000118180808000002203450d020b20032002200110848e80800021022000200136020820002002360204200020013602000f0b10ae80808000000b4101200110b280808000000baa03010a7f024002400240024002400240200128020822020d00410421030c010b200241d5aad52a4b0d03200241186c2204417f4c0d032001280204210141002d00fca3c680001a200441002802c8a3c68000118180808000002203450d014100210520022106034020042005460d0120012802042107410121084101210902402001280208220a450d00200a417f4c0d0541002d00fca3c680001a200a41002802c8a3c68000118180808000002209450d040b20092007200a10848e808000210b200141106a28020021090240200141146a2802002207450d002007417f4c0d0541002d00fca3c680001a200741002802c8a3c68000118180808000002208450d060b200141186a210120082009200710848e8080002108200320056a2209200a360200200941146a2007360200200941106a20083602002009410c6a2007360200200941086a200a360200200941046a200b360200200541186a21052006417f6a22060d000b0b2000200236020820002003360204200020023602000f0b4104200410b280808000000b4101200a10b280808000000b10ae80808000000b4101200710b280808000000bfe06010f7f02400240024002400240024002400240200128020822020d00410421030c010b200241e6cc99334b0d05200241146c2204417f4c0d052001280204210541002d00fca3c680001a200441002802c8a3c68000118180808000002203450d014100210620022107034020042006460d014104210802400240024002400240200520066a22012d00000e050001020304000b200141046a2d00002109200141036a2d0000210a200141026a2d0000210b4101210c200141016a2d0000210d2001410c6a28020021080240200141106a280200220e450d00200e417f4c0d0b41002d00fca3c680001a200e41002802c8a3c6800011818080800000220c450d080b200c2008200e10848e8080001a41002108200e210f0c030b200141046a2d00002109200141036a2d0000210a200141026a2d0000210b41012108200141016a2d0000210d2001410c6a280200210f4101210c0240200141106a280200220e450d00200e417f4c0d0a41002d00fca3c680001a200e41002802c8a3c6800011818080800000220c450d080b200c200f200e10848e8080001a200e210f0c020b200141046a2d00002109200141036a2d0000210a200141026a2d0000210b4101210c200141016a2d0000210d2001410c6a28020021080240200141106a280200220e450d00200e417f4c0d0941002d00fca3c680001a200e41002802c8a3c6800011818080800000220c450d080b200c2008200e10848e8080001a41022108200e210f0c010b2001410f6a2d000021082001410d6a2f000021102001410c6a220e2d00002109200141086a280200210102400240200e280200220c0d004101210e0c010b200c417f4c0d0841002d00fca3c680001a200c41002802c8a3c6800011818080800000220e450d090b20102008411074722110200e2001200c10848e8080001a410321080b200320066a220120083a0000200141076a20104110763a0000200141056a20103b0000200141036a200a3a0000200141026a200b3a0000200141016a200d3a0000200141106a200f3602002001410c6a200c360200200141086a200e360200200141046a20093a0000200641146a21062007417f6a22070d000b0b2000200236020820002003360204200020023602000f0b4104200410b280808000000b4101200e10b280808000000b4101200e10b280808000000b4101200e10b280808000000b10ae80808000000b4101200c10b280808000000bee0601047f024002402000280200220141054b0d002001450d0102400240024002402000410c6a280200417e6a2202410220024102491b0e020103000b200041146a21020c010b200041106a21020b2002280200450d00200228020441002802c0a3c68000118080808000000b0240200041246a280200450d00200041286a28020041002802c0a3c68000118080808000000b20014101460d010240024002400240200041386a280200417e6a2202410220024102491b0e020003010b2000413c6a21020c010b200041c0006a21020b2002280200450d00200228020441002802c0a3c68000118080808000000b0240200041d0006a280200450d00200041d4006a28020041002802c0a3c68000118080808000000b20014102460d010240024002400240200041e4006a280200417e6a2202410220024102491b0e020003010b200041e8006a21020c010b200041ec006a21020b2002280200450d00200228020441002802c0a3c68000118080808000000b0240200041fc006a280200450d0020004180016a28020041002802c0a3c68000118080808000000b20014103460d01024002400240024020004190016a280200417e6a2202410220024102491b0e020003010b20004194016a21020c010b20004198016a21020b2002280200450d00200228020441002802c0a3c68000118080808000000b0240200041a8016a280200450d00200041ac016a28020041002802c0a3c68000118080808000000b20014104460d010240024002400240200041bc016a280200417e6a2201410220014102491b0e020003010b200041c0016a21010c010b200041c4016a21010b2001280200450d00200128020441002802c0a3c68000118080808000000b200041d4016a280200450d01200041d8016a28020041002802c0a3c68000118080808000000f0b200028020421030240200041086a2802002202450d00200341246a21004100210103400240024002400240200041646a280200417e6a2204410220044102491b0e020103000b20032001412c6c6a41106a21040c010b200041686a21040b2004280200450d00200428020441002802c0a3c68000118080808000000b02402000417c6a280200450d00200028020041002802c0a3c68000118080808000000b200141016a21012000412c6a21002002417f6a22020d000b0b200341002802c0a3c68000118080808000000b0be70901087f024020002802082201450d00200028020421024100210303400240024002400240024002402002200341e8016c6a2200280200220441736a2205410220054104491b0e03010203000b20002d00084106470d042000410c6a280200450d04200041106a28020021060c030b0240024002400240024002400240024020002d0008417f6a0e0a010b0203040506070b0b000b2000410c6a280200450d0a200041106a28020021060c090b2000410c6a280200450d09200041106a28020021060c080b2000410c6a280200450d08200041106a28020021060c070b2000410c6a280200450d07200041106a28020021060c060b0240200041146a2802002204450d00200041106a2802002105034002402005280200450d00200541046a28020041002802c0a3c68000118080808000000b02402005410c6a280200450d00200541106a28020041002802c0a3c68000118080808000000b200541186a21052004417f6a22040d000b0b200028020c450d06200028021021060c050b0240200041146a2802002205450d00200041106a28020021062005410171210741002104024020054101460d002005417e7121084100210420062105034002402005280200450d00200541046a28020041002802c0a3c68000118080808000000b02402005410c6a280200450d00200541106a28020041002802c0a3c68000118080808000000b200541186a21052008200441026a2204470d000b0b2007450d0020062004410c6c6a2205280200450d00200528020441002802c0a3c68000118080808000000b200028020c450d05200028021021060c040b200041106a280200450d04200041146a28020021060c030b2000410c6a280200450d03200041106a28020021060c020b200041186a2d0000417d6a41ff017141014b0d020240200028020822064198016a2802002208450d004100210520064194016a2802002207210003402007200541146c6a2104024002400240024020002d00000e0400000001030b200441086a21040c010b200041046a21040b2004280200450d00200428020441002802c0a3c68000118080808000000b200541016a2105200041146a21002008417f6a22080d000b0b024020064190016a280200450d0020062802940141002802c0a3c68000118080808000000b024020064190026a2802002208450d00410021052006418c026a2802002207210003402007200541146c6a2104024002400240024020002d00000e0400000001030b200441086a21040c010b200041046a21040b2004280200450d00200428020441002802c0a3c68000118080808000000b200541016a2105200041146a21002008417f6a22080d000b0b20064188026a280200450d01200628028c0241002802c0a3c68000118080808000000c010b0240024002400240024002402004417e6a0e06000102000003070b200041046a21000c030b02402000280210450d00200041146a28020041002802c0a3c68000118080808000000b20002802042205418080808078460d05200041046a21000c030b02402000280204450d00200041086a28020041002802c0a3c68000118080808000000b200041106a21000c010b0240024020002d00040e0400000001050b2000410c6a21000c010b200041086a21000b200028020021050b2005450d01200028020421060b200641002802c0a3c68000118080808000000b200341016a22032001470d000b0b0bb70401047f024020002802082201450d0020002802042100034002400240024002400240200041046a200020002d00004108461b22022d00002203417c6a41ff01712204410420044104491b0e0404010203000b0240200241dc006a2802004129490d00200241346a28020041002802c0a3c68000118080808000000b200228022c41002802c0a3c680001180808080000020034103460d030240024020030e020105000b2002280224220420042802002204417f6a36020020044101470d04200241246a10e28a8080000c040b2002280204220420042802002204417f6a36020020044101470d03200241046a10e28a8080000c030b0240200241dc006a2802004129490d00200241346a28020041002802c0a3c68000118080808000000b02400240024020022d00040e020105000b200241286a2202280200220420042802002204417f6a36020020044101460d010c040b200241086a2202280200220420042802002204417f6a36020020044101470d030b200210e28a8080000c020b200241d4006a2802004129490d012002412c6a28020041002802c0a3c68000118080808000000c010b200228023041002802c0a3c680001180808080000020022d000422044103460d0002400240024020040e020103000b200241286a2202280200220420042802002204417f6a36020020044101460d010c020b200241086a2202280200220420042802002204417f6a36020020044101470d010b200210e28a8080000b20004180016a21002001417f6a22010d000b0b0bd80201047f23808080800041306b2201248080808000024020002802082202450d002000280204210003400240024002400240024020002d00000e050404010203000b02400240200041046a28020022030d0041002103410021040c010b200120033602242001410036022020012003360214200141003602102001200041086a2802002203360228200120033602182000410c6a2802002104410121030b2001200436022c2001200336021c2001200336020c2001410c6a10aa8d8080000c030b200041046a280200450d02200041086a28020041002802c0a3c68000118080808000000c020b200041046a280200450d01200041086a28020041002802c0a3c68000118080808000000c010b200041046a22031091878080002003280200450d00200041086a28020041002802c0a3c68000118080808000000b200041106a21002002417f6a22020d000b0b200141306a2480808080000b980201057f23808080800041106b2205248080808000024020012802082206200620026a22074f0d00200621070240200128020020066b20024f0d0020012006200210ab86808000200128020821070b2001280204220820076a2109024020024102490d00200941002002417f6a2202108a8e8080001a2008200720026a22076a21090b200941003a0000200741016a21070b20012007360208024020072006490d00200541086a20032802002003280204200128020420066a200720066b200410a888808000200528020c21020240200528020822030d002007200220066a2206490d00200120063602080b2000200336020020002002360204200541106a2480808080000f0b2006200741fce1c28000109481808000000b5601017f23808080800041106b2202248080808000200241086a200110bd8a8080000240024020022802080d0020002001200228020c10ce858080000c010b20004180808080783602000b200241106a2480808080000b5601017f23808080800041106b2202248080808000200241086a200110bc8a8080000240024020022802080d0020002001200228020c10c7858080000c010b20004180808080783602000b200241106a2480808080000bbe0101077f41002103024002402001410f712204410f470d00410121032002280208220541016a200228020422064b0d0020022802002107410f2108200521010340200120064f0d022002200141016a3602080240200720016a2d0000220941ff01470d00200841ff016a210841012103200141026a2109200141016a2101200920064d0d010c020b0b200920086a2104410021030b20002004360204200020033602000f0b20052006200520064b1b200641ecc1c2800010f980808000000b2c01017f2000200128020420012802282203200341284b22031b36020420002001280200200120031b3602000b810701097f23808080800041106b22022480808080000240024002400240024002402001280208220341016a2204200128020422054b22060d000240200320054f0d0020012004360208024002400240024002400240024002400240024002402001280200220720036a2d00002208450d0020084106764102730e0403020a01030b200041003a00000c100b2008413f712208413f470d030240200341026a20054b0d00413f2108200421030340200320054f0d0d2001200341016a2209360208200720036a2d0000220a41ff01470d04200841ff016a2108200341026a210a20092103200a20054d0d000b0b200041053a00000c0f0b2008413f712208413f470d040240200341026a20054b0d00413f2108200421030340200320054f0d0d2001200341016a2209360208200720036a2d0000220a41ff01470d05200841ff016a2108200341026a210a20092103200a20054d0d000b0b200041053a00000c0e0b2008413f712208413f470d050240200341026a20054b0d00413f2108200421030340200320054f0d0d2001200341016a2209360208200720036a2d0000220a41ff01470d06200841ff016a2108200341026a210a20092103200a20054d0d000b0b200041053a00000c0d0b200a20086a21080b20002008360204200041023a00000c0b0b200a20086a21080b2000200836020420004181023b01000c090b200a20086a21080b20002008360204200041013b01000c070b0240024002400240200841e001714120460d00200841f001714110460d01200041053a00000c0a0b2008411f712208411f470d020240200341026a20054b0d00411f2108200421030340200320054f0d0a2001200341016a2209360208200720036a2d0000220a41ff01470d03200841ff016a2108200341026a210a20092103200a20054d0d000b0b200041053a00000c090b200241086a20082001109587808000024020022802080d00200228020c2101200041033a0000200020013602040c090b200041053a00000c080b200a20086a21080b20002008360204200041043a00000c060b2003200541ecc1c2800010f980808000000b200041053a00000c040b2004200520061b200541ecc1c2800010f980808000000b2004200520061b200541ecc1c2800010f980808000000b2004200520061b200541ecc1c2800010f980808000000b2004200520061b200541ecc1c2800010f980808000000b200241106a2480808080000bf70701047f02400240024002400240024020002d00000e050004010203000b0240200128020020012802082202470d0020012002410110b182808000200128020821020b2001200241016a360208200128020420026a41003a00000c040b41ff0020002802042202413e2002413e491b220041c000722002413e4b1b2103200220006b2102410121040340200441ff0171210041002104200321050240024020000e03000100010b2002450d05024002402002418002490d00200241817e6a210241ff0121050c010b2002417f6a2105410021020b410221040b0240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a20053a00000c000b0b411f20002802042202410e2002410e491b22004110722002410e4b1b2103200220006b2102410121040340200441ff0171210041002104200321050240024020000e03000100010b2002450d04024002402002418002490d00200241817e6a210241ff0121050c010b2002417f6a2105410021020b410221040b0240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a20053a00000c000b0b413f20002802042202411e2002411e491b22004120722002411e4b1b2103200220006b2102410121040340200441ff0171210041002104200321050240024020000e03000100010b2002450d03024002402002418002490d00200241817e6a210241ff0121050c010b2002417f6a2105410021020b410221040b0240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a20053a00000c000b0b200028020422042004413e2004413e491b22056b2102024020002d0001450d00417f20054140722004413e4b1b2103410121040340200441ff0171210041002104200321050240024020000e03000100010b2002450d03024002402002418002490d00200241817e6a210241ff0121050c010b2002417f6a2105410021020b410221040b0240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a20053a00000c000b0b41bf7f200541807f722004413e4b1b2103410121040340200441ff0171210041002104200321050240024020000e03000100010b2002450d02024002402002418002490d00200241817e6a210241ff0121050c010b2002417f6a2105410021020b410221040b0240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a20053a00000c000b0b0ba707010d7f200141186a28020021022001410d6a2d00002103200141096a2d00002104200141146a28020021052001280210210620012d000c21072001280204210820012d000821092001280200210a0340024002400240024002400240024002400240024002400240024002400240024002400240200a417e6a0e020102000b0240200941ff0171220b4102460d002001200b454101743a000841002109200b450d002004210c0c030b0240200a450d002008450d0002402008418002490d002001200841817e6a220836020441ff01210c410221090c040b200141003602042008417f6a210c41022109410021080c030b41022109200141023602000b200741ff0171210a410221070240200a4102460d0041002107200141003a000c200a0d030b200141033602000b2006450d072005450d07200120052005200220052002491b220a6b220536021420012006200a6a220b360210024002400240200a0e020001020b4100410041f4d3c4800010f980808000000b410141014184d4c4800010f980808000000b20062d000041047420062d000172210c4103210a200b21060b2000280208220b2000280200470d0d200a4103470d024100210d4103210a2006450d0c2005450d0c2002450d01200520026e220d2005200d20026c6b4100476a210d0c0c0b410021072000280208220b2000280200460d024102210a2003210c0c0c0b41b0e4c280004119419ce4c2800010f880808000000b2006450d06200a4102470d024102210a200741ff01714102470d014100210d410221070c050b2003210c2006450d060b200741ff0171410047210d4102210a0c030b200741ff0171220d4102460d012009410171200d4100476a210d0c020b0f0b410221074100210d0240200941ff0171220e4102470d00410221090c010b200e410047210d0b4100210e024002402005450d002002450d01200520026e220e2005200e20026c6b4100476a210e0b417f200d200e6a220e200e200d491b210d0c040b41b0e4c280004119419ce4c2800010f880808000000b200a4102470d014102210a410021064100210d200741ff01714102460d020b41002106200741ff0171410047210d4102210a0c010b0240200741ff0171220d4102460d00410021062009410171200d4100476a210d0c010b410021060240200941ff0171220d4102470d00410221094100210d0c010b41002106200d410047210d0b2000200b200d41016a220d417f200d1b10ab868080000b2000200b41016a3602082000280204200b6a200c3a00000c000b0bff0101077f20012802002102200128020421032001280208210402400240024020012d000c450d002001410d6a2d00002105200141003a000c2005410f7121060c010b200420034f0d012001200441016a2205360208200220046a2d00002106200521040b0240200028020822072000280200470d0020002007410110ab868080000b2000200741016a22053602082000280204220820076a20063a0000200420034f0d0003402001200441016a2207360208200220046a2d00002104024020052000280200470d0020002005410110ab86808000200028020421080b200820056a20043a00002000200541016a22053602082007210420032007470d000b0b0bca04020c7f027e23808080800041206b2202248080808000200241146a200110818a808000024002400240024002402002280214418080808078470d002000410036020820004280808080c0003702000c010b41002d00fca3c680001a413041002802c8a3c68000118180808000002203450d0120032002290214370200200341086a200241146a41086a280200360200200241013602102002200336020c20024104360208024020012802082204200128020422054d0d00200128020c210620012802002107200420056b2108411021054100210903402002200710bc8a8080000240024020022802000d002007280200220a41046a220b280200220420022802042201490d000240024020010d004101210c0c010b2001417f4c0d07200141002802c8a3c6800011818080800000220c450d08200c41002001108a8e8080001a200b28020021040b200420014f0d01200c41002802c0a3c68000118080808000000b200641013a00000c020b200c200a280200220d200110848e808000210c200b200420016b360200200a200d20016a3602002001ad210e200cad210f0240200941016a22042002280208470d00200241086a2004410110ad86808000200228020c21030b200320056a220a200e422086200f84370200200a417c6a20013602002002200941026a3602102005410c6a21052004210920082004470d000b0b20002002290208370200200041086a200241086a41086a2802003602000b200241206a2480808080000f0b4104413010b280808000000b10ae80808000000b4101200110b280808000000bae09010c7f2380808080004190016b2202248080808000200241186a200110e18c8080000240024002400240024020022802182203418080808078460d002002280228210420022802242105200228021c210602402001412c6a2802002207200141286a28020022084d0d0002402003450d00200641002802c0a3c68000118080808000000b2005450d01200441002802c0a3c68000118080808000000c010b200228022c21092002280220210a20012008417f6a36022820012001280224220841046a3602242002200936022c20022004360228200220053602242002200a3602202002200636021c200220073602342002200836023020022003360218200241f0006a2001413c6a200241186a10de8a8080002002280278418080808078470d010b2000410036020820004280808080c000370200200110ab8d8080000c010b20012802202203410020012802282205200128022c22046b41016a20052004491b220520032005491b41016a2203417f20031b22034104200341044b1b220341e6cc99334b0d01200341146c2205417f4c0d0141002d00fca3c680001a200541002802c8a3c6800011818080800000220b450d02200b2002290270370200200b41106a200241f0006a41106a280200360200200b41086a200241f0006a41086a290200370200200241013602142002200b3602102002200336020c200241186a41386a200141386a290200370300200241186a41306a200141306a290200370300200241186a41286a200141286a290200370300200241186a41206a200141206a290200370300200241186a41186a200141186a290200370300200241186a41106a200141106a290200370300200241186a41086a200141086a29020037030020022001290200370318200241f0006a200241186a10e18c808000024020022802702205418080808078460d00200241d4006a210c411421034101210103402002280280012106200228027c210420022802742107024020022802442208200228024022094d0d0002402005450d00200741002802c0a3c68000118080808000000b2004450d02200641002802c0a3c68000118080808000000c020b200228028401210a2002280278210d20022009417f6a3602402002200228023c220941046a36023c2002200a3602840120022006360280012002200436027c2002200d360278200220073602742002200836028c01200220093602880120022005360270200241dc006a200c200241f0006a10de8a8080002002280264418080808078460d0102402001200228020c470d002002410c6a200120022802382205410020022802402204200228024422066b41016a20042006491b220420052004491b41016a2205417f20051b10a8868080002002280210210b0b200b20036a2205200229025c370200200541106a200241dc006a41106a280200360200200541086a200241dc006a41086a2902003702002002200141016a2201360214200341146a2103200241f0006a200241186a10e18c80800020022802702205418080808078470d000b0b200241186a10ab8d808000200041086a2002410c6a41086a2802003602002000200229020c3702000b20024190016a2480808080000f0b10ae80808000000b4104200510b280808000000b8d0e010f7f23808080800041206b2202248080808000024002400240024002400240024020012802004102460d00200241086a200110e08c808000024020022802082203450d00200228020c220441086a28020020042802002205200541054b22051b2206450d03200328020821072003280204210802402006412c6c2004280204200441046a20051b6a41546a2204280208220341014b0d0020042802042106200428021c2105024020042802002209450d0020052006460d010b2002200441106a36021c2002411c6a200920062005108e858080002004200536020420044101360200200428020821030b410021050240024002402003417e6a2203410220034102491b0e03000501000b2004410c6a21040c010b200441106a21040b20042802082106200428020421050c020b200141023602000b20012802242204450d022004200141286a280200460d022001200441186a3602244100200441106a280200200428020c418080808078461b2105200441146a280200210620042802082107200428020421080b20012802242103024020012802004102470d0020030d03410021040c040b200128022021042003450d03417f2004200141286a28020020036b41186e6a220320032004491b21040c030b41fcb8c2800041fc0041f8bac2800010a181808000000b2000410036020820004280808080c0003702000c020b200141286a28020020036b41186e21040b0240200441016a2204417f20041b22044104200441044b1b220341ffffff3f4b0d0020034104742209417f4c0d0041002d00fca3c680001a0240200941002802c8a3c68000118180808000002204450d002004200636020c2004200536020820042007360204200420083602002002410136021820022004360214200220033602102001280228210a200128022421092001280220210b200128020c2103200128020821052001280204210420012802002107024002400340024002400240024002400240024002400240024020074102460d00200b0d014100210b0b2009450d012009200a460d014100200941106a280200200928020c418080808078461b2108200941146a280200210c2009280208210d2009280204210e41022107200941186a22012109200228021822062002280210460d050c080b024002402007450d002004450d010b20070d0441d4fec5800010a081808000000b41012107200521042003450d0220032101024020034107712205450d0003402001417f6a210120042802ac1421042005417f6a22050d000b0b200341084f0d010c020b20002002290210370200200041086a200241106a41086a2802003602000c0c0b034020042802ac142802ac142802ac142802ac142802ac142802ac142802ac142802ac142104200141786a22010d000b0b41002103410021050b0240200320042f01aa14490d00034020042802a0132201450d07200541016a210520042f01a814210320012104200320012f01aa144f0d000b0b200341016a210f0240024020050d00200421010c010b2004200f4102746a41ac146a28020021014100210f2005417f6a2206450d002005417e6a2108024020064107712205450d0003402006417f6a210620012802ac1421012005417f6a22050d000b0b20084107490d00034020012802ac142802ac142802ac142802ac142802ac142802ac142802ac142802ac142101200641786a22060d000b0b2004200341e0016c6a220541086a28020020052802002206200641054b22061b2208450d0620042003410c6c6a220441ac136a280200210d200441a8136a280200210e02402008412c6c2005280204200541046a20061b6a41546a2204280208220341014b0d0020042802042106200428021c2105024020042802002208450d0020052006460d010b2002200441106a36021c2002411c6a200820062005108e858080002004200536020420044101360200200428020821030b410021054100210802400240024002402003417e6a2203410220034102491b0e03000301000b2004410c6a21040c010b200441106a21040b2004280208210c200428020421080b200b417f6a210b0240200228021822062002280210460d0020012104200f21030c040b20074102470d01410221074100210520012104200f210320092101410021102009450d020b200a20016b41186e211041022107200121090c010b41002105024020090d0041002109200f210320012104200b21100c010b417f200b200a20096b41186e6a22042004200b491b2110200f2103200121040b200241106a2006201041016a2201417f20011b10aa868080000b200228021420064104746a2201200c36020c200120083602082001200d3602042001200e3602002002200641016a3602180c000b0b419cd0c2800010a081808000000b41fcb8c2800041fc0041f8bac2800010a181808000000b4104200910b280808000000b10ae80808000000b200241206a2480808080000bb00703077f027e057f23808080800041306b2202248080808000200141086a280200220320012802042204200320044b1b210520012802002106200128020c2107024002400240024003400240024020042005460d002001200441016a2204360204200241186a200610fc8680800020022802202208418080808078470d01200741013a00000b2000410036020820004280808080c0003702000c020b2008418180808078460d000b200229031821092002290224210a41002d00fca3c680001a41d00041002802c8a3c6800011818080800000220b450d01200b200a37020c200b2008360208200b2009370200200241013602142002200b3602102002410436020c0240200420034f0d00200420036b210c41202103410121080340024002402006280200220428020422014108490d002004280200220529000021092004200141786a3602042004200541086a360200200628020022042802042205450d0020042005417f6a220d36020420042004280200220141016a3602000240024002400240024020012d0000220e4103710e0400030102000b200e41027621040c030b20054104490d0320042005417c6a3602042004200141046a360200200141036a2d000041187420012f000141087472200e72220441808004490d03200441027621040c020b200e41044f0d0220054105490d0220042005417b6a3602042004200141056a360200200128000122044180808080044f0d010c020b200d450d0120042005417e6a3602042004200141026a36020020012d0001410874200e7241ffff03712204418002490d01200441027621040b2006280200220541046a220e28020022012004490d000240024020040d004101210d0c010b2004417f4c0d07200441002802c8a3c6800011818080800000220d450d08200d41002004108a8e8080001a200e28020021010b200120044f0d01200d41002802c0a3c68000118080808000000b200741013a00000c020b200d2005280200220f200410848e808000210d200e200120046b3602002005200f20046a3602002004ad422086200dad84210a02402008200228020c470d002002410c6a2008410110a8868080002002280210210b0b200b20036a2201200a3702002001417c6a2004360200200141746a20093702002002200841016a2208360214200341146a2103200c20086a4101470d000b0b2000200229020c370200200041086a2002410c6a41086a2802003602000b200241306a2480808080000f0b410441d00010b280808000000b10ae80808000000b4101200410b280808000000bc60a010b7f23808080800041206b2202248080808000200241086a200110e08c80800002400240024020022802082203450d00200228020c220441086a28020020042802002205200541054b22051b2206450d01200328020821072003280204210802402006412c6c2004280204200441046a20051b6a41546a2204280208220341014b0d0020042802042106200428021c2105024020042802002209450d0020052006460d010b2002200441106a36021c2002411c6a200920062005108e858080002004200536020420044101360200200428020821030b4100210502400240024002402003417e6a2203410220034102491b0e03000301000b2004410c6a21040c010b200441106a21040b20042802082106200428020421050b0240200128022041016a2204417f20041b22044104200441044b1b220341ffffff3f4b0d0020034104742209417f4c0d0041002d00fca3c680001a0240200941002802c8a3c68000118180808000002204450d002004200636020c20042005360208200420073602042004200836020020024101360218200220043602142002200336021002400240024020012802202207450d00200128020021082001280204210420012802082105200128020c210303400240024002402008450d002004450d010b20080d0141d4fec5800010a081808000000b410121082005210402402003450d0020032101024020034107712205450d0003402001417f6a210120042802ac1421042005417f6a22050d000b0b20034108490d00034020042802ac142802ac142802ac142802ac142802ac142802ac142802ac142802ac142104200141786a22010d000b0b41002103410021050b0240200320042f01aa14490d00034020042802a0132201450d04200541016a210520042f01a814210320012104200320012f01aa144f0d000b0b200341016a21090240024020050d00200421010c010b200420094102746a41ac146a2802002101410021092005417f6a2206450d002005417e6a210a024020064107712205450d0003402006417f6a210620012802ac1421012005417f6a22050d000b0b200a4107490d00034020012802ac142802ac142802ac142802ac142802ac142802ac142802ac142802ac142101200641786a22060d000b0b2004200341e0016c6a220541086a28020020052802002206200641054b22061b220a450d0320042003410c6c6a220441ac136a280200210b200441a8136a280200210c0240200a412c6c2005280204200541046a20061b6a41546a2204280208220341014b0d0020042802042106200428021c210502402004280200220a450d0020052006460d010b2002200441106a36021c2002411c6a200a20062005108e858080002004200536020420044101360200200428020821030b4100210502400240024002402003417e6a2203410220034102491b0e03000301000b2004410c6a21040c010b200441106a21040b20042802082106200428020421050b2007417f6a21070240200228021822032002280210470d00200241106a2003200741016a2204417f20041b10aa868080000b200228021420034104746a2204200636020c200420053602082004200b3602042004200c3602002002200341016a36021841002105200921032001210420070d000b0b20002002290210370200200041086a200241106a41086a2802003602000c060b419cd0c2800010a081808000000b41fcb8c2800041fc0041f8bac2800010a181808000000b4104200910b280808000000b10ae80808000000b2000410036020820004280808080c0003702000c010b41fcb8c2800041fc0041f8bac2800010a181808000000b200241206a2480808080000bd20201047f23808080800041c0006b2202248080808000200241206a41086a200141086a29020037030020022001290200370320200241086a200241206a109b87808000024002400240200228021022030d0020004100360208200041003602002002280208450d01200228020c41002802c0a3c68000118080808000000c010b200228020c220120032002413f6a10d88b8080002002280208210441002d00fca3c680001a418c0141002802c8a3c68000118180808000002205450d0120054100360200200541003b018a0120024100360218200220053602142002410036021c200220012003410c6c6a36023820022004360234200220013602302002200136022c2002418180808078360220200241146a200241206a2002411c6a10c3858080002000200228021c360208200020022902143702000b200241c0006a2480808080000f0b4104418c0110b280808000000b7c01017f23808080800041106b2201248080808000200142888080808001370200200142808080808001370208200041c4006a200110c182808000200041c0006a410036020020004280808080c000370338200041d8006a410036020020004280808080c000370350200041850c3b0100200141106a2480808080000bed0201027f23808080800041206b220124808080800041002d00fca3c680001a0240413041002802c8a3c680001181808080000022020d004108413010b280808000000b200242bea4ae99af91eca2827f370318200242dac1a9c58db4fcb8cb00370308200242f1acbf83d7fffdaeb77f370300200241fd81808000360210200241206a42a1efe9e2fe938eee74370300200241286a41fe818080003602002001200241306a36021c200141023602182001200236021420012002360210200141046a200141106a108487808000200142888080808001370210200142808080808001370218200041c4006a200141106a10fa868080002001411b6a200141046a41086a280200360000200041c0006a410036020020004280808080c000370338200041043a0000200041d8006a410036020020004280808080c0003703502001200129020437001320002001290010370001200041086a200141176a290000370000200141206a2480808080000beb0201027f23808080800041206b220124808080800041002d00fca3c680001a0240413041002802c8a3c680001181808080000022020d004108413010b280808000000b200242d7c9cb8fc1cf97db3e37031820024293888c8f89fdc6ec9e7f370308200242a5e9e3ab9e929adc2c370300200241ef80808000360210200241206a42e88488d0c0e3aebc13370300200241286a41b5808080003602002001200241306a36021c200141023602182001200236021420012002360210200141046a200141106a108487808000200142888080808001370210200142808080808001370218200041c4006a200141106a10fa868080002001411b6a200141046a41086a280200360000200041c0006a410036020020004280808080c000370338200041043a0000200041d8006a410036020020004280808080c0003703502001200129020437001320002001290010370001200041086a200141176a290000370000200141206a2480808080000bec0201027f23808080800041206b220124808080800041002d00fca3c680001a0240413041002802c8a3c680001181808080000022020d004108413010b280808000000b200242a5e9e3ab9e929adc2c370318200242949384fce98ae9ac977f370308200242c4a8f7cba2aea4ad35370300200241ff81808000360210200241206a4293888c8f89fdc6ec9e7f370300200241286a41ef808080003602002001200241306a36021c200141023602182001200236021420012002360210200141046a200141106a108487808000200142888080808001370210200142808080808001370218200041c4006a200141106a10fa868080002001411b6a200141046a41086a280200360000200041c0006a410036020020004280808080c000370338200041043a0000200041d8006a410036020020004280808080c0003703502001200129020437001320002001290010370001200041086a200141176a290000370000200141206a2480808080000beb0201027f23808080800041206b220124808080800041002d00fca3c680001a0240413041002802c8a3c680001181808080000022020d004108413010b280808000000b200242b7a0aca7a89ca5e845370318200242d4a5e8fca9e787a92e370308200242cce9ab8ffbfcead3703703002002418082808000360210200241206a42f58896d99bcda087da00370300200241286a4181828080003602002001200241306a36021c200141023602182001200236021420012002360210200141046a200141106a108487808000200142888080808001370210200142808080808001370218200041c4006a200141106a10fa868080002001411b6a200141046a41086a280200360000200041c0006a410036020020004280808080c000370338200041043a0000200041d8006a410036020020004280808080c0003703502001200129020437001320002001290010370001200041086a200141176a290000370000200141206a2480808080000bec0201027f23808080800041206b220124808080800041002d00fca3c680001a0240413041002802c8a3c680001181808080000022020d004108413010b280808000000b200242a5e9e3ab9e929adc2c37031820024293888c8f89fdc6ec9e7f370308200242a5e9e3ab9e929adc2c370300200241ef80808000360210200241206a4293888c8f89fdc6ec9e7f370300200241286a41ef808080003602002001200241306a36021c200141023602182001200236021420012002360210200141046a200141106a108487808000200142888080808001370210200142808080808001370218200041c4006a200141106a10fa868080002001411b6a200141046a41086a280200360000200041c0006a410036020020004280808080c000370338200041043a0000200041d8006a410036020020004280808080c0003703502001200129020437001320002001290010370001200041086a200141176a290000370000200141206a2480808080000baf0101017f23808080800041106b2201248080808000200142888080808001370200200142808080808001370208200041c4006a200110fa86808000200041106a42e6ed8d82cc91adcb05370300200042dbd791d5c2919eaecd00370308200041c0006a410036020020004280808080c000370338200041d8006a410036020020004280808080c00037035020004120360220200041c880808000360218200041033a0000200141106a2480808080000baf0101017f23808080800041106b2201248080808000200142888080808001370200200142808080808001370208200041c4006a200110fa86808000200041106a42e6ed8d82cc91adcb05370300200042dbd791d5c2919eaecd00370308200041c0006a410036020020004280808080c000370338200041d8006a410036020020004280808080c00037035020004108360220200041c880808000360218200041033a0000200141106a2480808080000b8f0503017f017e057f23808080800041106b22022480808080002000290300210302402001280200200128020822046b41074b0d0020012004410810b182808000200128020821040b2001200441086a360208200128020420046a2003370000200041146a28020021052002200041186a28020022043602082002200241086a36020c2002410c6a200110c08a80800002402004450d002004410c6c2106200541086a210503402005417c6a28020021072002200528020022043602082002200241086a36020c2002410c6a200110c08a80800002402001280200200128020822086b20044f0d0020012008200410b182808000200128020821080b200128020420086a2007200410848e8080001a2001200820046a3602082005410c6a2105200641746a22060d000b0b200041206a28020021052002200041246a28020022043602082002200241086a36020c2002410c6a200110c08a808000024002402004450d002004410c6c2106200541086a210503402005417c6a28020021072002200528020022043602082002200241086a36020c2002410c6a200110c08a80800002402001280200200128020822086b20044f0d0020012008200410b182808000200128020821080b200128020420086a2007200410848e8080001a2001200820046a22043602082005410c6a2105200641746a22060d000c020b0b200128020821040b200029030821030240200128020020046b41074b0d0020012004410810b182808000200128020821040b200128020420046a20033700002001200441086a220436020820002d00282105024020012802002004470d0020012004410110b182808000200128020821040b2001200441016a360208200128020420046a20053a0000200241106a2480808080000bd70801047f0240024020002d00000d000240200128020020012802082202470d0020012002410110b182808000200128020821020b2001200241016a22033602082001280204220420026a41003a00000240024002400240024002400240024002400240024020002d00010e0b000102030405060708090a000b024020012802002003470d0020012003410110b18280800020012802042104200128020821030b200420036a41003a00000c0b0b024020012802002003470d0020012003410110b18280800020012802042104200128020821030b200420036a41013a00000c0a0b024020012802002003470d0020012003410110b18280800020012802042104200128020821030b200420036a41023a00000c090b024020012802002003470d0020012003410110b18280800020012802042104200128020821030b200420036a41033a00000c080b024020012802002003470d0020012003410110b18280800020012802042104200128020821030b200420036a41043a00000c070b024020012802002003470d0020012003410110b18280800020012802042104200128020821030b200420036a41053a00000c060b024020012802002003470d0020012003410110b18280800020012802042104200128020821030b200420036a41063a00000c050b200041026a2d0000210502400240200128020022022003460d00200321000c010b20012003410110b1828080002001280200210220012802042104200128020821000b2001200041016a2203360208200420006a41073a0000024020022003470d0020012002410110b18280800020012802042104200128020821030b200420036a20053a00000c040b024020012802002003470d0020012003410110b18280800020012802042104200128020821030b200420036a41083a00000c030b024020012802002003470d0020012003410110b18280800020012802042104200128020821030b200420036a41093a00000c020b024020012802002003470d0020012003410110b18280800020012802042104200128020821030b200420036a410a3a00000c010b0240200128020020012802082202470d0020012002410110b182808000200128020821020b2001200241016a22033602082001280204220420026a41013a000002400240024020002d00010e03000102000b024020012802002003470d0020012003410110b18280800020012802042104200128020821030b200420036a41003a00000c020b024020012802002003470d0020012003410110b18280800020012802042104200128020821030b200420036a41013a00000c010b200041026a2d0000210502400240200128020022022003460d00200321000c010b20012003410110b1828080002001280200210220012802042104200128020821000b2001200041016a2203360208200420006a41023a0000024020022003470d0020012002410110b18280800020012802042104200128020821030b200420036a20053a00000b2001200341016a3602080bb92a03047f017e017f23808080800041f0016b220224808080800002400240024002400240024002400240024002400240024020012d0028417f6a0e0b000102030405060708090a000b200141306a28020021032001412c6a2802002104200128020021010240024010fa81808000220541fe014d0d0042002106410921050c010b2002200541016a3602484100210541b1e3c080004113200241c8006a410441002802e0a1c680001186808080000041002802e8a1c680001188808080000041002802b0a1c6800011888080800000200241c8006a10fb81808000420221060b02402004450d00200341002802c0a3c68000118080808000000b20012001280200417f6a2204360200024020040d00200141086a28020022032001410c6a28020022042802001180808080000002402004280204450d00200341002802c0a3c68000118080808000000b200141046a22042004280200417f6a220436020020040d00200141002802c0a3c68000118080808000000b2000420037030820002006370300200041216a41003a0000200041206a20053a0000200041186a41003a00000c0a0b200141306a2903002106200241b8016a41206a200141206a290300370300200241b8016a41186a2204200141186a290300370300200241b8016a41106a2205200141106a290300370300200241b8016a41086a2203200141086a290300370300200220012903003703b8012002200637038001200220024180016a3602e001200241c8006a200241b8016a10bb8680800002400240200229034822064202520d002004200241c8006a41206a2903003703002005200241c8006a41186a2903003703002003200241c8006a41106a290300370300200220022903503703b8010c010b200020022903703703282004200241c8006a41206a2903003703002005200241c8006a41186a2903003703002003200241c8006a41106a290300370300200041306a200241c8006a41306a290300370300200220022903503703b8010b200041086a220120022903b80137030020002006370300200141186a200241b8016a41186a290300370300200141106a200241b8016a41106a290300370300200141086a200241b8016a41086a2903003703000c090b20024180016a41086a2204200141346a28020036020020022001412c6a29020022063703800120024180016a412c6a200141206a290200370200200241a4016a200141186a2902003702002002419c016a200141106a29020037020020024194016a200141086a2902003702002002200129020037028c01200241b8016a41306a20024180016a41306a280200360200200241b8016a41286a20024180016a41286a290300370300200241b8016a41206a20024180016a41206a290300370300200241b8016a41186a220120024180016a41186a290300370300200241b8016a41106a220520024180016a41106a290300370300200241b8016a41086a22032004290300370300200220063703b801200241c8006a200241b8016a10b58680800002400240200229034822064202520d002001200241c8006a41206a2903003703002005200241c8006a41186a2903003703002003200241c8006a41106a290300370300200220022903503703b8010c010b200020022903703703282001200241c8006a41206a2903003703002005200241c8006a41186a2903003703002003200241c8006a41106a290300370300200041306a200241c8006a41306a290300370300200220022903503703b8010b200041086a220120022903b80137030020002006370300200141186a200241b8016a41186a290300370300200141106a200241b8016a41106a290300370300200141086a200241b8016a41086a2903003703000c080b20024180016a41086a2204200141346a28020036020020022001412c6a29020022063703800120024180016a412c6a200141206a290200370200200241a4016a200141186a2902003702002002419c016a200141106a29020037020020024194016a200141086a2902003702002002200129020037028c01200241b8016a41306a20024180016a41306a280200360200200241b8016a41286a20024180016a41286a290300370300200241b8016a41206a20024180016a41206a290300370300200241b8016a41186a220120024180016a41186a290300370300200241b8016a41106a220520024180016a41106a290300370300200241b8016a41086a22032004290300370300200220063703b801200241c8006a200241b8016a10c48680800002400240200229034822064202520d002001200241c8006a41206a2903003703002005200241c8006a41186a2903003703002003200241c8006a41106a290300370300200220022903503703b8010c010b200020022903703703282001200241c8006a41206a2903003703002005200241c8006a41186a2903003703002003200241c8006a41106a290300370300200041306a200241c8006a41306a290300370300200220022903503703b8010b200041086a220120022903b80137030020002006370300200141186a200241b8016a41186a290300370300200141106a200241b8016a41106a290300370300200141086a200241b8016a41086a2903003703000c070b200241086a41086a2204200141346a28020036020020022001412c6a290200370308200241b8016a41206a200141206a290300370300200241b8016a41186a200141186a290300370300200241b8016a41106a200141106a290300370300200241b8016a41086a200141086a290300370300200220012903003703b8012002200241086a3602e001200241c8006a200241b8016a10b386808000024020042802002204450d00200228020c2101034002402001280200450d00200141046a28020041002802c0a3c68000118080808000000b02402001410c6a280200450d00200141106a28020041002802c0a3c68000118080808000000b200141186a21012004417f6a22040d000b0b02402002280208450d00200228020c41002802c0a3c68000118080808000000b02400240200229034822064202520d00200241b8016a41186a200241e8006a290300370300200241b8016a41106a200241c8006a41186a290300370300200241b8016a41086a200241c8006a41106a290300370300200220022903503703b801200041086a21010c010b20002002290370370328200241b8016a41186a200241e8006a290300370300200241b8016a41106a200241c8006a41186a290300370300200241b8016a41086a200241c8006a41106a290300370300200041306a200241c8006a41306a290300370300200220022903503703b801200041086a21010b200120022903b80137030020002006370300200141186a200241b8016a41186a290300370300200141106a200241b8016a41106a290300370300200141086a200241b8016a41086a2903003703000c060b200241186a41086a2204200141346a28020036020020022001412c6a290200370318200241b8016a41206a200141206a290300370300200241b8016a41186a200141186a290300370300200241b8016a41106a200141106a290300370300200241b8016a41086a200141086a290300370300200220012903003703b8012002200241186a3602e001200241c8006a200241b8016a10b986808000024020042802002201450d00200228021c21072001410171210341002104024020014101460d002001417e7121052007210141002104034002402001280200450d00200141046a28020041002802c0a3c68000118080808000000b02402001410c6a280200450d00200141106a28020041002802c0a3c68000118080808000000b200141186a21012005200441026a2204470d000b0b2003450d0020072004410c6c6a2201280200450d00200128020441002802c0a3c68000118080808000000b02402002280218450d00200228021c41002802c0a3c68000118080808000000b02400240200229034822064202520d00200241b8016a41186a200241e8006a290300370300200241b8016a41106a200241c8006a41186a290300370300200241b8016a41086a200241c8006a41106a290300370300200220022903503703b801200041086a21010c010b20002002290370370328200241b8016a41186a200241e8006a290300370300200241b8016a41106a200241c8006a41186a290300370300200241b8016a41086a200241c8006a41106a290300370300200041306a200241c8006a41306a290300370300200220022903503703b801200041086a21010b200120022903b80137030020002006370300200141186a200241b8016a41186a290300370300200141106a200241b8016a41106a290300370300200141086a200241b8016a41086a2903003703000c050b200241286a41086a200141386a2802003602002002200141306a29020037032820022001412c6a28020036028001200241b8016a41206a200141206a290300370300200241b8016a41186a200141186a290300370300200241b8016a41106a200141106a290300370300200241b8016a41086a200141086a290300370300200220012903003703b801200220024180016a3602e4012002200241286a3602e001200241c8006a200241b8016a10c38680800002402002280228450d00200228022c41002802c0a3c68000118080808000000b02400240200229034822064202520d00200241b8016a41186a200241e8006a290300370300200241b8016a41106a200241c8006a41186a290300370300200241b8016a41086a200241c8006a41106a290300370300200220022903503703b801200041086a21010c010b20002002290370370328200241b8016a41186a200241e8006a290300370300200241b8016a41106a200241c8006a41186a290300370300200241b8016a41086a200241c8006a41106a290300370300200041306a200241c8006a41306a290300370300200220022903503703b801200041086a21010b200120022903b80137030020002006370300200141186a200241b8016a41186a290300370300200141106a200241b8016a41106a290300370300200141086a200241b8016a41086a2903003703000c040b200241386a41086a200141346a28020036020020022001412c6a290200370338200241b8016a41206a200141206a290300370300200241b8016a41186a200141186a290300370300200241b8016a41106a200141106a290300370300200241b8016a41086a200141086a290300370300200220012903003703b8012002200241386a3602e001200241c8006a200241b8016a10be8680800002402002280238450d00200228023c41002802c0a3c68000118080808000000b02400240200229034822064202520d00200241b8016a41186a200241e8006a290300370300200241b8016a41106a200241c8006a41186a290300370300200241b8016a41086a200241c8006a41106a290300370300200220022903503703b801200041086a21010c010b20002002290370370328200241b8016a41186a200241e8006a290300370300200241b8016a41106a200241c8006a41186a290300370300200241b8016a41086a200241c8006a41106a290300370300200041306a200241c8006a41306a290300370300200220022903503703b801200041086a21010b200120022903b80137030020002006370300200141186a200241b8016a41186a290300370300200141106a200241b8016a41106a290300370300200141086a200241b8016a41086a2903003703000c030b200241b8016a41186a200141c1006a290000370300200241b8016a41106a200141396a290000370300200241b8016a41086a200141316a2900003703002002200141296a2900003703b801200241c8006a41206a200141206a290300370300200241c8006a41186a200141186a290300370300200241c8006a41106a200141106a290300370300200241c8006a41086a200141086a290300370300200220012903003703482002200241b8016a36027020024180016a200241c8006a10c5868080000240024020022d008001410e470d0020004200370308200041206a2101420221060c010b2000200229028001370220200041286a20024180016a41086a290200370200200241ca006a20024193016a2d000022013a0000200220022f00910122043b014820022d0090012105200041336a20013a0000200041316a20043b0000200041306a20053a0000200041186a2101420021060b20002006370300200141003a00000c020b200241b8016a41186a200141c1006a290000370300200241b8016a41106a200141396a290000370300200241b8016a41086a200141316a2900003703002002200141296a2900003703b801200241c8006a41206a200141206a290300370300200241c8006a41186a200141186a290300370300200241c8006a41106a200141106a290300370300200241c8006a41086a200141086a290300370300200220012903003703482002200241b8016a36027020024180016a200241c8006a10b7868080000240024020022d008001410e470d0020004200370308200041206a2101420221060c010b2000200229028001370220200041286a20024180016a41086a290200370200200241ca006a20024193016a2d000022013a0000200220022f00910122043b014820022d0090012105200041336a20013a0000200041316a20043b0000200041306a20053a0000200041186a2101420021060b20002006370300200141003a00000c010b20012802002104200241b8016a41086a200141346a28020036020020022001412c6a2902003703b801200241c8006a200241b8016a10bc8680800020042004280200417f6a2201360200024020010d00200441086a28020022052004410c6a28020022012802001180808080000002402001280204450d00200541002802c0a3c68000118080808000000b200441046a22012001280200417f6a220136020020010d00200441002802c0a3c68000118080808000000b02400240200229034822064202520d00200241b8016a41186a200241e8006a290300370300200241b8016a41106a200241c8006a41186a290300370300200241b8016a41086a200241c8006a41106a290300370300200220022903503703b801200041086a21010c010b20002002290370370328200241b8016a41186a200241e8006a290300370300200241b8016a41106a200241c8006a41186a290300370300200241b8016a41086a200241c8006a41106a290300370300200041306a200241c8006a41306a290300370300200220022903503703b801200041086a21010b200120022903b80137030020002006370300200141186a200241b8016a41186a290300370300200141106a200241b8016a41106a290300370300200141086a200241b8016a41086a2903003703000b200241f0016a2480808080000b850702087f017e23808080800041306b2201248080808000200142919fd78da1a1ad84ff003703182001429ceccef7a6c0dedd20370310200142958ed1e593cab9fca47f370328200142e6d0c3af83b9abdfff0037032020014100360204200141106a4120200141046a410441002802e0a1c6800011868080800000024002400240024002400240200041206a2802002202450d002000411c6a2802002103200142919fd78da1a1ad84ff003703182001429ceccef7a6c0dedd2037031020014282fceae49dd9e2861d370328200142de8c84a1ecd0a6d30c370320200141046a200141106a10e288808000024020012802042204418080808078460d0020012802082105200128020c0d022004450d00200541002802c0a3c68000118080808000000b200241b3e6cc194b0d03200241286c2206417f4c0d034100210541002d00fca3c680001a200641002802c8a3c68000118180808000002207450d04200221080240034020062005460d0120032903202109200720056a22042003290300370300200441186a200341186a290300370300200441106a200341106a290300370300200441086a200341086a290300370300200441206a2009370300200541286a2105200341286a21032008417f6a22080d000b0b2002410a4b0d022001200236021020012002ad4220862007ad84370214200141106a10f188808000200141106a10f0888080002001280210450d00200128021441002802c0a3c68000118080808000000b200142919fd78da1a1ad84ff003703182001429ceccef7a6c0dedd20370310200142c2a5b2f6d3b4fb986f370328200142dcd7ddd8f18e8ca1e30037032041002d00fca3c680001a411141002802c8a3c68000118180808000002203450d042003200029030037000020032000290308370008200320002d00103a0010200141106a41202003411141002802e0a1c6800011868080800000200341002802c0a3c6800011808080800000200141306a2480808080000f0b02402004450d00200541002802c0a3c68000118080808000000b2001411c6a420037020020014101360214200141e4ecc28000360210200141e4e7c28000360218200141106a41ececc2800010f680808000000b200741002802c0a3c680001180808080000041dcebc2800041c400200141106a41a0ecc2800041b0ecc28000108981808000000b10ae80808000000b4108200610b280808000000b4101411110b280808000000bf10501047f2380808080004190016b2201248080808000200142919fd78da1a1ad84ff003703082001429ceccef7a6c0dedd20370300200141cc006a2001411041002802c0a1c680001185808080000002400240200128024c2202418080808078460d0020012802502103024020012802544110490d0020012003411010888e808000210402402002450d00200341002802c0a3c68000118080808000000b20040d010c020b2002450d00200341002802c0a3c68000118080808000000b41002102200141003b011e02400240417f4100280284a4c680002203410347200341034b1b2203450d00200341ff017141ff01470d010b200141286a410c6a418282808000360200200141838280800036022c20014104360224200141f5a6c4800036022020012001411e6a3602302001200141206a3602284100280290a1c680002102410028028ca1c6800021034100280280a4c68000210420014184016a4202370200200141fc006a4103360200200141f4006a4116360200200141f0006a41c1e5c28000360200200141e4006a41e8e4c28000ad4280808080900b84370200200141cc006a410c6a41d7e5c28000ad4280808080b0028437020020014180016a200141286a360200200141f0e6c280003602782001410336026c200141003602602001410036025420014281808080800e37024c200341ecf2c08000200441024622041b200141cc006a200241d4f2c0800020041b2802101184808080000020012f011e21020b200141cc006a41f5a6c48000410441002802a0a3c6800011858080800000200141cc006a41106a220341bccdc48000411541002802a0a3c6800011858080800000200141286a41186a200141cc006a41186a290000370300200141286a41106a2003290000370300200141286a41086a200141cc006a41086a2900003703002001200129004c370328200120023b014c200141286a4120200141cc006a410241002802e0a1c68000118680808000000b200042003703082000420037030020014190016a2480808080000b930201027f23808080800041106b2202248080808000200220003602002002200128021441fc94c38000410e200141186a28020028020c118280808000003a000c20022001360208200241003a000d20024100360204200241046a2002418c95c38000108d81808000210120022d000c210002400240200128020022030d00200041ff017141004721010c010b41012101200041ff01710d0020022802082100024020034101470d0020022d000d41ff0171450d0020002d001c4104710d00410121012000280214418ca5c080004101200041186a28020028020c118280808000000d010b2000280214418da5c080004101200041186a28020028020c1182808080000021010b200241106a24808080800020010bf51a03017f017e027f23808080800041c0016b2202248080808000024002400240024002400240024002400240024020012d0028417f6a0e09000102030405060708000b200241e4006a200141d0006a290200370200200241dc006a200141c8006a290200370200200241d4006a200141c0006a2902003702002002200141386a29020037024c200141306a2903002103200241206a41086a200141086a290300370300200241206a41106a200141106a290300370300200241206a41186a200141186a290300370300200241206a41206a200141206a29030037030020022001290300370320200220033703102002200241106a36024820024190016a200241206a10b2868080000240024020022d009001410e470d0020004200370308200041206a2101420221030c010b2000200229029001370220200041286a20024190016a41086a290200370200200241226a200241a3016a2d000022013a0000200220022f00a10122043b012020022d00a0012105200041336a20013a0000200041316a20043b0000200041306a20053a0000200041186a2101420021030b20002003370300200141003a00000c080b200241e4006a200141d0006a290200370200200241dc006a200141c8006a290200370200200241d4006a200141c0006a290200370200200241f4006a200141e0006a290200370200200241fc006a200141e8006a29020037020020024184016a200141f0006a2902003702002002200141386a29020037024c2002200141d8006a29020037026c200141306a2903002103200241206a41086a200141086a290300370300200241206a41106a200141106a290300370300200241206a41186a200141186a290300370300200241206a41206a200141206a29030037030020022001290300370320200220033703102002200241106a36024820024190016a200241206a10c8868080000240024020022d009001410e470d0020004200370308200041206a2101420221030c010b2000200229029001370220200041286a20024190016a41086a290200370200200241226a200241a3016a2d000022013a0000200220022f00a10122043b012020022d00a0012105200041336a20013a0000200041316a20043b0000200041306a20053a0000200041186a2101420021030b20002003370300200141003a00000c070b200241e4006a200141d0006a290200370200200241dc006a200141c8006a290200370200200241d4006a200141c0006a2902003702002002200141386a29020037024c200141306a2903002103200241206a41086a200141086a290300370300200241206a41106a200141106a290300370300200241206a41186a200141186a290300370300200241206a41206a200141206a29030037030020022001290300370320200220033703102002200241106a36024820024190016a200241206a10bd868080000240024020022d009001410e470d0020004200370308200041206a2101420221030c010b2000200229029001370220200041286a20024190016a41086a290200370200200241226a200241a3016a2d000022013a0000200220022f00a10122043b012020022d00a0012105200041336a20013a0000200041316a20043b0000200041306a20053a0000200041186a2101420021030b20002003370300200141003a00000c060b200241e4006a200141c1006a290000370200200241dc006a200141396a290000370200200241d4006a200141316a2900003702002002200141296a29000037024c200141c9006a2d00002104200241206a41086a200141086a290300370300200241206a41106a200141106a290300370300200241206a41186a200141186a290300370300200241206a41206a200141206a29030037030020022001290300370320200220043a00102002200241106a36024820024190016a200241206a10c6868080000240024020022d009001410e470d0020004200370308200041206a2101420221030c010b2000200229029001370220200041286a20024190016a41086a290200370200200241226a200241a3016a2d000022013a0000200220022f00a10122043b012020022d00a0012105200041336a20013a0000200041316a20043b0000200041306a20053a0000200041186a2101420021030b20002003370300200141003a00000c050b200241e4006a200141d0006a290200370200200241dc006a200141c8006a290200370200200241d4006a200141c0006a2902003702002002200141386a29020037024c200141306a2903002103200241206a41086a200141086a290300370300200241206a41106a200141106a290300370300200241206a41186a200141186a290300370300200241206a41206a200141206a29030037030020022001290300370320200220033703102002200241106a36024820024190016a200241206a10c2868080000240024020022d009001410e470d0020004200370308200041206a2101420221030c010b2000200229029001370220200041286a20024190016a41086a290200370200200241226a200241a3016a2d000022013a0000200220022f00a10122043b012020022d00a0012105200041336a20013a0000200041316a20043b0000200041306a20053a0000200041186a2101420021030b20002003370300200141003a00000c040b200241086a200141346a28020036020020022001412c6a29020037030020024190016a41206a200141206a29030037030020024190016a41186a200141186a29030037030020024190016a41106a200141106a29030037030020024190016a41086a200141086a2903003703002002200129030037039001200220023602b801200241206a20024190016a10ba8680800002402002280200450d00200228020441002802c0a3c68000118080808000000b02400240200229032022034202520d0020024190016a41186a200241c0006a29030037030020024190016a41106a200241206a41186a29030037030020024190016a41086a200241206a41106a2903003703002002200229032837039001200041086a21010c010b2000200229034837032820024190016a41186a200241c0006a29030037030020024190016a41106a200241206a41186a29030037030020024190016a41086a200241206a41106a290300370300200041306a200241206a41306a2903003703002002200229032837039001200041086a21010b200120022903900137030020002003370300200141186a20024190016a41186a290300370300200141106a20024190016a41106a290300370300200141086a20024190016a41086a2903003703000c030b200241e4006a200141d0006a290200370200200241dc006a200141c8006a290200370200200241d4006a200141c0006a2902003702002002200141386a29020037024c200141306a2903002103200241206a41086a200141086a290300370300200241206a41106a200141106a290300370300200241206a41186a200141186a290300370300200241206a41206a200141206a29030037030020022001290300370320200220033703102002200241106a36024820024190016a200241206a10b1868080000240024020022d009001410e470d0020004200370308200041206a2101420221030c010b2000200229029001370220200041286a20024190016a41086a290200370200200241226a200241a3016a2d000022013a0000200220022f00a10122043b012020022d00a0012105200041336a20013a0000200041316a20043b0000200041306a20053a0000200041186a2101420021030b20002003370300200141003a00000c020b200141306a2903002103200141296a2d00002104200241206a41206a200141206a290300370300200241206a41186a200141186a290300370300200241206a41106a200141106a290300370300200241206a41086a200141086a29030037030020022001290300370320200220043a001f2002200337031020022002411f6a36024c2002200241106a36024820024190016a200241206a10c7868080000240024020022d009001410e470d0020004200370308200041206a2101420221030c010b2000200229029001370220200041286a20024190016a41086a290200370200200241226a200241a3016a2d000022013a0000200220022f00a10122043b012020022d00a0012105200041336a20013a0000200041316a20043b0000200041306a20053a0000200041186a2101420021030b20002003370300200141003a00000c010b200141296a2d00002104200141306a2903002103200241206a41206a200141206a290300370300200241206a41186a200141186a290300370300200241206a41106a200141106a290300370300200241206a41086a200141086a2903003703002002200129030037032020022003370310200220043a001f2002200241106a36024c20022002411f6a36024820024190016a200241206a10c1868080000240024020022d009001410e470d0020004200370308200041206a2101420221030c010b2000200229029001370220200041286a20024190016a41086a290200370200200241226a200241a3016a2d000022013a0000200220022f00a10122043b012020022d00a0012105200041336a20013a0000200041316a20043b0000200041306a20053a0000200041186a2101420021030b20002003370300200141003a00000b200241c0016a2480808080000b910602027f027e23808080800041e0036b220124808080800041002d00fca3c680001a024041980241002802c8a3c680001181808080000022020d00410841980210b280808000000b20002903202103200141f0016a41186a200041c0006a290000370300200141f0016a41106a200041386a290000370300200141f0016a41086a200041306a290000370300200141f0016a41306a200041d8006a290000370300200141f0016a41386a200041e0006a290000370300200141f0016a41c0006a200041e8006a290000370300200141f0016a41d0006a200041f8006a290000370300200141f0016a41d8006a20004180016a290000370300200141f0016a41e0006a20004188016a290000370300200120002900283703f0012001200041d0006a290000370398022001200041f0006a2900003703b802200041c8006a2903002104200141f0016a41e8006a20004190016a108d878080002001200437039002200141e8026a41186a200041b8016a290000370300200141e8026a41106a200041b0016a290000370300200141e8026a41086a200041a8016a290000370300200141e8026a41306a200041d0016a290000370300200141e8026a41386a200041d8016a290000370300200141e8026a41c0006a200041e0016a290000370300200141e8026a41d0006a200041f0016a290000370300200141e8026a41d8006a200041f8016a290000370300200141e8026a41e0006a20004180026a290000370300200120002900a0013703e8022001200041c8016a290000370390032001200041e8016a2900003703b003200041c0016a2903002104200141e8026a41e8006a20004188026a108d878080002001200437038803200141f8006a200141f0016a41f80010848e8080001a2001200141e8026a41f80010848e8080002101200241186a200041186a290300370300200241106a200041106a290300370300200241086a200041086a2903003703002002200029030037030020022003370320200241286a200141f8006a41f80010848e8080001a200241a0016a200141f80010848e8080001a200141e0036a2480808080000b840903017f037e047f23808080800041b0016b2201248080808000200142919fd78da1a1ad84ff003703682001429ceccef7a6c0dedd20370360200142aac0b0e5d1eaef8d63370378200142b8e2b0fbfb91a8ed827f370370200141206a200141e0006a10e688808000024002400240024002402001290328420020012802201b42017c22024200510d00200142919fd78da1a1ad84ff003703682001429ceccef7a6c0dedd20370360200142dca0bb8e8acbf9b3da00370378200142e78ec688edebaee7ba7f3703702001200242004206420010878e808000200141106a200141e0006a10e78880800020012903084200520d01200129030022032001290318420020012802101b7c22042003540d01200142919fd78da1a1ad84ff003703682001429ceccef7a6c0dedd2037036020014292d189e4a1e58a9fcc00370378200142aa9f83c8cbf687edfa0037037020014190016a200141e0006a10e288808000200128029001210520012802940121062001280298012107200142919fd78da1a1ad84ff00370398012001429ceccef7a6c0dedd2037039001200142c2a6e5f5c0d0a4be463703a801200142fccce3cbd7d3cfff023703a001200141e0006a20014190016a10e5888080000240024020012d00600d00200141a8016a4200370300200141a0016a420037030020014198016a420037030020014200370390010c010b200141a8016a200141f9006a290000370300200141a0016a200141f1006a29000037030020014198016a200141e9006a29000037030020012001290061370390010b200142919fd78da1a1ad84ff003703682001429ceccef7a6c0dedd20370360200142addc97bf9599fde7e3003703782001429ad7aad8b5ececacd100370370200141306a200141e0006a10e88880800020012d00404103470d02200142919fd78da1a1ad84ff003703682001429ceccef7a6c0dedd20370360200142c2a5b2f6d3b4fb986f370378200142dcd7ddd8f18e8ca1e300370370200141c8006a200141e0006a10e88880800020012d00584103460d03200141e0006a41106a200141c8006a41106a290300370300200141e0006a41086a200141c8006a41086a290300370300200120012903483703600c040b41ece8c2800041ef0041dce9c2800010a181808000000b41c18fc2800041fa0041bc90c2800010a181808000000b200141e0006a41106a200141306a41106a290300370300200141e0006a41086a200141306a41086a290300370300200120012903303703600c010b41ece9c2800041c80041b4eac2800010a181808000000b200042063703282000200437032020002002370318200020012903900137003020002001290360370300200041d8006a4100200720054180808080784622081b360200200041d4006a4108200620081b36020020004100200520081b360250200041386a20014190016a41086a290300370000200041c0006a20014190016a41106a290300370000200041c8006a200141a8016a290300370000200041086a200141e0006a41086a290300370300200041106a200141e0006a41106a290300370300200141b0016a2480808080000bfb0705017f037e017f017e037f23808080800041b0016b2201248080808000200142919fd78da1a1ad84ff003703682001429ceccef7a6c0dedd20370360200142aac0b0e5d1eaef8d63370378200142b8e2b0fbfb91a8ed827f370370200141386a200141e0006a10e6888080002001290340210220012903382103200142919fd78da1a1ad84ff003703682001429ceccef7a6c0dedd20370360200142aac0b0e5d1eaef8d63370378200142b8e2b0fbfb91a8ed827f370370200141286a200141e0006a10e6888080002001290330210420012802282105200142919fd78da1a1ad84ff003703682001429ceccef7a6c0dedd20370360200142dca0bb8e8acbf9b3da00370378200142e78ec688edebaee7ba7f370370200141086a2004420020051b42004206420010878e808000200141186a200141e0006a10e7888080000240024020012903104200520d00200129030822042001290320420020012802181b7c22062004540d00200142919fd78da1a1ad84ff003703682001429ceccef7a6c0dedd2037036020014282fceae49dd9e2861d370378200142de8c84a1ecd0a6d30c37037020014190016a200141e0006a10e288808000200128029001210520012802940121072001280298012108200142919fd78da1a1ad84ff00370398012001429ceccef7a6c0dedd2037039001200142c6e4a9b1aaa1afebf2003703a801200142fa82b1828b81b8f31e3703a001200141e0006a20014190016a10e5888080000240024020012d00600d00200141a8016a4200370300200141a0016a420037030020014198016a420037030020014200370390010c010b200141a8016a200141f9006a290000370300200141a0016a200141f1006a29000037030020014198016a200141e9006a29000037030020012001290061370390010b200142919fd78da1a1ad84ff003703682001429ceccef7a6c0dedd20370360200142c2a5b2f6d3b4fb986f370378200142dcd7ddd8f18e8ca1e300370370200141c8006a200141e0006a10e88880800020012d00584103460d0120002001290348370300200041106a200141c8006a41106a290300370300200041086a200141c8006a41086a290300370300200041d8006a4100200820054180808080784622091b360200200041d4006a4108200720091b36020020004100200520091b36025020004206370328200020063703202000200242002003a71b3703182000200129039001370030200041386a20014190016a41086a290300370000200041c0006a20014190016a41106a290300370000200041c8006a200141a8016a290300370000200141b0016a2480808080000f0b41c18fc2800041fa0041bc90c2800010a181808000000b41ece9c2800041c80041c4eac2800010a181808000000bf61704017f017e017f017e2380808080004190026b22042480808080000240024002400240024002402000280208450d00200442919fd78da1a1ad84ff003703a8012004429ceccef7a6c0dedd203703a001200442e9c5fea9cdfbc4d26d3703b80120044286aaece2939beae4653703b001200441286a200441a0016a10e7888080002004290330210520042802282106200442919fd78da1a1ad84ff003703a8012004429ceccef7a6c0dedd203703a001200442dca0bb8e8acbf9b3da003703b801200442e78ec688edebaee7ba7f3703b001200441186a200441a0016a10e788808000200442002005420020061b22052004290320420020042802181b7d220720072005561b4206802205370338200442919fd78da1a1ad84ff003703a8012004429ceccef7a6c0dedd203703a001200442aac0b0e5d1eaef8d633703b801200442b8e2b0fbfb91a8ed827f3703b001200441086a200441a0016a10e68880800020024101470d04427f200429031042017c22072007501b420120042802081b2005520d010c040b417f4100280284a4c680002202410247200241024b1b2202450d01200241ff017141ff01460d010c020b200420033602a001200441386a200441a0016a10f788808000200429033821050c020b4100280290a1c680002102410028028ca1c6800021034100280280a4c680002106200441d8016a4200370200200441d4016a41e4e7c28000360200200441d0016a4101360200200441c8016a410d360200200441c4016a41c6e8c28000360200200441b8016a41e8e4c28000ad4280808080900b84370200200441ac016a41f8eac28000ad4280808080b00184370200200441f0eac280003602cc01200441003602b401200441003602a80120044281808080b0ce003702a001200441023602c001200341ecf2c08000200641024622061b200441a0016a200241d4f2c0800020061b280210118480808000000b02402001280200450d00200128020441002802c0a3c68000118080808000000b2000280200450d01200028020441002802c0a3c68000118080808000000c010b200442919fd78da1a1ad84ff003703a8012004429ceccef7a6c0dedd203703a001200442aac0b0e5d1eaef8d633703b801200442b8e2b0fbfb91a8ed827f3703b001200420053703f001200441a0016a4120200441f0016a410841002802e0a1c6800011868080800000200441a0016a41086a200041086a280200360200200420002902003703a001200441a0016a10f3888080000240200429033842017c220550450d004183ebc2800041c90041ccebc2800010a181808000000b200442919fd78da1a1ad84ff003703f8012004429ceccef7a6c0dedd203703f001200442c2a6e5f5c0d0a4be4637038802200442fccce3cbd7d3cfff0237038002200441a0016a200441f0016a10e5888080000240024020042d00a0010d00200441d8006a4200370300200441d0006a4200370300200441c8006a4200370300200442003703400c010b200441d8006a200441b9016a290000370300200441d0006a200441b1016a290000370300200441c8006a200441a9016a290000370300200420042900a1013703400b200442919fd78da1a1ad84ff003703a8012004429ceccef7a6c0dedd203703a001200442958ed1e593cab9fca47f3703b801200442e6d0c3af83b9abdfff003703b0012004200441a0016a412010d0888080002004280204210020042802002102200442919fd78da1a1ad84ff003703a8012004429ceccef7a6c0dedd203703a001200442958ed1e593cab9fca47f3703b801200442e6d0c3af83b9abdfff003703b001200441003602f001200441a0016a4120200441f0016a410441002802e0a1c6800011868080800000200441003602bc01200441003602ac01200442013702a00120042000410020021b22003602a801200441f0016a200441c0006a2005200441a0016a4101200041016a2200417f20001b41087410908a80800041002d00fca3c680001a200442919fd78da1a1ad84ff003703a8012004429ceccef7a6c0dedd203703a001200442c2a6e5f5c0d0a4be463703b801200442fccce3cbd7d3cfff023703b0010240024002400240412041002802c8a3c68000118180808000002200450d00200020042900f001370000200041186a200441f0016a41186a290000370000200041106a200441f0016a41106a290000370000200041086a200441f0016a41086a290000370000200441a0016a41202000412041002802e0a1c6800011868080800000200041002802c0a3c680001180808080000041002d00fca3c680001a200442919fd78da1a1ad84ff003703a8012004429ceccef7a6c0dedd203703a001200442c6e4a9b1aaa1afebf2003703b801200442fa82b1828b81b8f31e3703b001412041002802c8a3c68000118180808000002200450d0120002004290340370000200041186a200441c0006a41186a290300370000200041106a200441c0006a41106a290300370000200041086a200441c0006a41086a290300370000200441a0016a41202000412041002802e0a1c6800011868080800000200041002802c0a3c6800011808080800000200110f08880800010f688808000200442919fd78da1a1ad84ff003703f8012004429ceccef7a6c0dedd203703f001200442c2a6e5f5c0d0a4be4637038802200442fccce3cbd7d3cfff0237038002200441a0016a200441f0016a10e5888080000240024020042d00a0010d0020044184016a4200370200200441fc006a4200370200200441f4006a42003702002004420037026c0c010b20044184016a200441b9016a290000370200200441fc006a200441b1016a290000370200200441f4006a200441a9016a290000370200200420042900a10137026c0b200441e0006a41086a2200200141086a280200360200200420012902002205370360200441cc016a20044188016a280200360200200441c4016a20044180016a290300370200200441bc016a200441f8006a290300370200200441b4016a200441f0006a290300370200200441ac016a2000290300370200200420053702a401200441003602a001200441f0016a41086a200441a0016a10cc86808000200441f4016a41c5003a000020044181848592043602f001200441f0016a10f588808000024020042802a0010d0020042802a401450d00200441a8016a28020041002802c0a3c68000118080808000000b200442919fd78da1a1ad84ff003703a8012004429ceccef7a6c0dedd203703a001200442addc97bf9599fde7e3003703b8012004429ad7aad8b5ececacd1003703b001200441f0016a200441a0016a10e888808000024020042d00800222014103460d0020042903f801210520042903f0012107200442919fd78da1a1ad84ff003703a8012004429ceccef7a6c0dedd203703a001200442c2a5b2f6d3b4fb986f3703b801200442dcd7ddd8f18e8ca1e3003703b00141002d00fca3c680001a411141002802c8a3c68000118180808000002200450d032000200737000020002005370008200020013a0010200441a0016a41202000411141002802e0a1c6800011868080800000200041002802c0a3c68000118080808000000b200441f0016a10f48880800020042d00800222014103460d0420042903f801210520042903f0012107200442919fd78da1a1ad84ff003703a8012004429ceccef7a6c0dedd203703a001200442addc97bf9599fde7e3003703b8012004429ad7aad8b5ececacd1003703b00141002d00fca3c680001a411141002802c8a3c68000118180808000002200450d032000200737000020002005370008200020013a0010200441a0016a41202000411141002802e0a1c6800011868080800000200041002802c0a3c6800011808080800000200441b8016a20013a0000200441b0016a2005370300200441b9016a200428008102360000200441bc016a20044184026a280000360000200420073703a801200441023602a00120044194016a200441a0016a10cc8680800020044190016a41c5003a0000200441818485920436028c012004418c016a10f58880800020042802a0010d0420042802a401450d0420042802a80141002802c0a3c68000118080808000000c040b4101412010b280808000000b4101412010b280808000000b4101411110b280808000000b4101411110b280808000000b20044190026a2480808080000bae0302027f037e23808080800041e0006b2201248080808000410021020240024020004201510d00200142919fd78da1a1ad84ff003703482001429ceccef7a6c0dedd20370340200142e9c5fea9cdfbc4d26d37035820014286aaece2939beae465370350200141306a200141c0006a10e7888080002001290338210320012903302104200142919fd78da1a1ad84ff003703482001429ceccef7a6c0dedd20370340200142aac0b0e5d1eaef8d63370358200142b8e2b0fbfb91a8ed827f370350200141206a200141c0006a10e6888080002001290328210020012802202102200142919fd78da1a1ad84ff003703482001429ceccef7a6c0dedd20370340200142dca0bb8e8acbf9b3da00370358200142e78ec688edebaee7ba7f37035020012000420020021b42004206420010878e808000200141106a200141c0006a10e78880800020012903084200520d01200129030022002001290318420020012802101b7c22052000540d014200200342002004a71b220020057d220320032000561b42055621020b200141e0006a24808080800020020f0b41c18fc2800041fa0041bc90c2800010a181808000000ba42901047f23808080800041206b22012480808080002001410036021020014280808080800137020841002d00fca3c680001a024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240410841002802c8a3c68000118180808000002202450d00200241fcecc280003602002002411536020441002d00fca3c680001a410841002802c8a3c68000118180808000002203450d01200342003700000240200128021022042001280208470d00200141086a2004109d86808000200128021021040b200128020c200441e8006c6a220441013a00602004410136025c2004200236025820044288808080103703502004200336024c2004428a8080808001370244200441a8c0c38000360240200441ef8080800036021820044100360200200442a5e9e3ab9e929adc2c370308200441106a4293888c8f89fdc6ec9e7f3703002001200128021041016a36021041002d00fca3c680001a410841002802c8a3c68000118180808000002204450d022004411b36020420044191edc280003602002001410136021c2001200436021820014101360214200141146a200141086a10fc8880800041002d00fca3c680001a411041002802c8a3c68000118180808000002202450d03200241acedc28000360200200241eaedc280003602082002413e3602042002410c6a412436020041002d00fca3c680001a410841002802c8a3c68000118180808000002203450d04200342003700000240200128021022042001280208470d00200141086a2004109d86808000200128021021040b200128020c200441e8006c6a220441013a00602004410236025c2004200236025820044288808080203703502004200336024c2004428b8080808001370244200441fabdc38000360240200441f580808000360218200442e3a4fae3cee3d18d7237030820044100360200200441106a42b8b6d386cdcbfab1a07f37030041002d00fca3c680001a2001200128021041016a360210410841002802c8a3c68000118180808000002202450d052002418eeec280003602002002411536020441002d00fca3c680001a410841002802c8a3c68000118180808000002203450d06200342003700000240200128021022042001280208470d00200141086a2004109d86808000200128021021040b200128020c200441e8006c6a220441013a00602004410136025c2004200236025820044288808080103703502004200336024c2004428b8080808001370244200441b4bec38000360240200441f580808000360218200442e3a4fae3cee3d18d7237030820044100360200200441106a42b8b6d386cdcbfab1a07f37030041002d00fca3c680001a2001200128021041016a36021041d00041002802c8a3c68000118180808000002204450d07200441a6f1c28000360248200441e5f0c28000360240200441a0f0c28000360238200441dbefc280003602302004419defc28000360228200441dceec28000360220200441e4e7c28000360218200441d1eec28000360210200441e4e7c280003602082004412e360204200441a3eec28000360200200441cc006a41c300360200200441c4006a41c1003602002004413c6a41c500360200200441346a41c5003602002004412c6a413e360200200441246a41c1003602002004411c6a4100360200200441146a410b3602002004410c6a410036020041002d00fca3c680001a412041002802c8a3c68000118180808000002203450d0820034200370000200341186a4200370000200341106a4200370000200341086a42003700000240200128021022022001280208470d00200141086a2002109d86808000200128021021020b200128020c200241e8006c6a220241013a00602002410a36025c20022004360258200242a0808080a0013703502002200336024c2002428a808080800437024420024197c1c38000360240200241f081808000360218200242c4ccab9c81ebb4b8db0037030820024100360200200241106a42a4d2928ecac0faa43237030041002d00fca3c680001a2001200128021041016a360210410841002802c8a3c68000118180808000002202450d09200241e9f1c28000360200200241d80036020441002d00fca3c680001a410141002802c8a3c68000118180808000002203450d0a200341003a00000240200128021022042001280208470d00200141086a2004109d86808000200128021021040b200128020c200441e8006c6a220441003a00602004410136025c2004200236025820044281808080103703502004200336024c200442988080801037024420044181c0c380003602402004418482808000360218200442c7facddcf584b3fea87f37030820044100360200200441106a42a8dcd6c1f2afcba52b37030041002d00fca3c680001a2001200128021041016a360210410841002802c8a3c68000118180808000002203450d0b200341c1f2c280003602002003411736020441002d00fca3c680001a412041002802c8a3c68000118180808000002202450d0c20024200370000200241186a4200370000200241106a4200370000200241086a42003700000240200128021022042001280208470d00200141086a2004109d86808000200128021021040b200128020c200441e8006c6a220441013a00602004410136025c20042003360258200442a0808080103703502004200236024c2004428e808080800437024420044190bfc38000360240200441f08180800036021820044100360200200442c4ccab9c81ebb4b8db00370308200441106a42a4d2928ecac0faa4323703002001200128021041016a36021041002d00fca3c680001a410841002802c8a3c68000118180808000002204450d0d20044118360204200441d8f2c280003602002001410136021c2001200436021820014101360214200141146a200141086a10818980800041002d00fca3c680001a41c80041002802c8a3c68000118180808000002204450d0e200441f0f2c28000360200200441aff5c28000360240200441edf4c28000360238200441b2f4c28000360230200441e4e7c280003602282004418df4c28000360220200441cdf3c280003602182004418ff3c28000360210200441e4e7c280003602082004411f360204200441c4006a41073602002004413c6a41c200360200200441346a413b3602002004412c6a4100360200200441246a41253602002004411c6a41c000360200200441146a413e3602002004410c6a410036020041002d00fca3c680001a410441002802c8a3c68000118180808000002203450d0f200341003600000240200128021022022001280208470d00200141086a2002109d86808000200128021021020b200128020c200241e8006c6a220241013a00602002410936025c200220043602582002428480808090013703502002200336024c2002428c808080c000370244200241e1bfc38000360240200241b58080800036021820024100360200200242d7c9cb8fc1cf97db3e370308200241106a42e88488d0c0e3aebc133703002001200128021041016a36021041002d00fca3c680001a410841002802c8a3c68000118180808000002204450d10200441c500360204200441b6f5c280003602002001410136021c2001200436021820014101360214200141146a200141086a109e8880800041002d00fca3c680001a411041002802c8a3c68000118180808000002202450d11200241fbf5c28000360200200241bbf6c28000360208200241c0003602042002410c6a41c70036020041002d00fca3c680001a410141002802c8a3c68000118180808000002203450d12200341003a00000240200128021022042001280208470d00200141086a2004109d86808000200128021021040b200128020c200441e8006c6a220441003a00602004410236025c2004200236025820044281808080203703502004200336024c2004428b80808010370244200441a9bec380003602402004418582808000360218200442c3d5bbd5b981e38c0337030820044100360200200441106a42c98d9ad7c1aad5e25937030041002d00fca3c680001a2001200128021041016a360210412041002802c8a3c68000118180808000002202450d1320024182f7c280003602002002418df8c28000360218200241e4e7c28000360210200241c7f7c28000360208200241c5003602042002411c6a41d200360200200241146a41003602002002410c6a41c60036020041002d00fca3c680001a410141002802c8a3c68000118180808000002203450d14200341003a00000240200128021022042001280208470d00200141086a2004109d86808000200128021021040b200128020c200441e8006c6a220441013a00602004410436025c2004200236025820044281808080c0003703502004200336024c2004429380808010370244200441ecc0c3800036024020044186828080003602182004428cc882a2e2dcdde2f00037030820044100360200200441106a42aa8be08180efaa931e37030041002d00fca3c680001a2001200128021041016a360210412841002802c8a3c68000118180808000002204450d15200441dff8c28000360200200441e3fac280003602202004418dfac28000360218200441bbf9c28000360210200441b6f9c28000360208200441d700360204200441246a41d6003602002004411c6a41d600360200200441146a41d2003602002004410c6a410536020041002d00fca3c680001a411041002802c8a3c68000118180808000002203450d1620034200370000200341086a42003700000240200128021022022001280208470d00200141086a2002109d86808000200128021021020b200128020c200241e8006c6a220241013a00602002410536025c2002200436025820024290808080d0003703502002200336024c2002428a8080808002370244200241bdc0c380003602402002418782808000360218200242bcf58bd0d59aa7c9db0037030820024100360200200241106a42e0df9add94b69bd2ff0037030041002d00fca3c680001a2001200128021041016a360210412841002802c8a3c68000118180808000002204450d17200441b9fbc28000360200200441f8fcc28000360220200441b4fcc28000360218200441effbc28000360210200441e4e7c2800036020820044136360204200441246a412c3602002004411c6a41c400360200200441146a41c5003602002004410c6a410036020041002d00fca3c680001a410841002802c8a3c68000118180808000002203450d18200342003700000240200128021022022001280208470d00200141086a2002109d86808000200128021021020b200128020c200241e8006c6a220241013a00602002410536025c2002200436025820024288808080d0003703502002200336024c200242888080808001370244200241c7c0c38000360240200241ef80808000360218200242a5e9e3ab9e929adc2c37030820024100360200200241106a4293888c8f89fdc6ec9e7f37030041002d00fca3c680001a2001200128021041016a360210411041002802c8a3c68000118180808000002202450d19200241a4fdc28000360200200241fcfdc28000360208200241d8003602042002410c6a410936020041002d00fca3c680001a410141002802c8a3c68000118180808000002203450d1a200341003a00000240200128021022042001280208470d00200141086a2004109d86808000200128021021040b200128020c200441e8006c6a220441003a00602004410236025c2004200236025820044281808080203703502004200336024c2004428b80808010370244200441b2c0c38000360240200441f680808000360218200442b7e2f1ac9bf5d4dc827f37030820044100360200200441106a42f2b3a2a5fbe78f9ac60037030041002d00fca3c680001a2001200128021041016a360210411041002802c8a3c68000118180808000002202450d1b20024185fec28000360200200241d0fec28000360208200241cb003602042002410c6a413a36020041002d00fca3c680001a410141002802c8a3c68000118180808000002203450d1c200341003a00000240200128021022042001280208470d00200141086a2004109d86808000200128021021040b200128020c200441e8006c6a220441003a00602004410236025c2004200236025820044281808080203703502004200336024c2004428f808080103702442004419abec38000360240200441f68080800036021820044100360200200442b7e2f1ac9bf5d4dc827f370308200441106a42f2b3a2a5fbe78f9ac6003703002001200128021041016a36021041002d00fca3c680001a41c00041002802c8a3c68000118180808000002204450d1d200441a182c38000360238200441d781c380003602302004418981c38000360228200441bc80c38000360220200441f0ffc28000360218200441e4e7c28000360210200441d4ffc28000360208200441ca003602042004418affc280003602002004413c6a412c360200200441346a41ca003602002004412c6a41ce00360200200441246a41cd003602002004411c6a41cc00360200200441146a41003602002004410c6a411c3602002001410836021c2001200436021820014108360214200141146a200141086a108289808000200041086a200141086a41086a28020036020020002001290208370200200041106a4104360200200041f5a6c4800036020c200141206a2480808080000f0b4104410810b280808000000b4101410810b280808000000b4104410810b280808000000b4104411010b280808000000b4101410810b280808000000b4104410810b280808000000b4101410810b280808000000b410441d00010b280808000000b4101412010b280808000000b4104410810b280808000000b4101410110b280808000000b4104410810b280808000000b4101412010b280808000000b4104410810b280808000000b410441c80010b280808000000b4101410410b280808000000b4104410810b280808000000b4104411010b280808000000b4101410110b280808000000b4104412010b280808000000b4101410110b280808000000b4104412810b280808000000b4101411010b280808000000b4104412810b280808000000b4101410810b280808000000b4104411010b280808000000b4101410110b280808000000b4104411010b280808000000b4101410110b280808000000b410441c00010b280808000000ba80901097f41002d00fca3c680001a02400240024002400240024002400240024041e00141002802c8a3c68000118180808000002201450d0041002d00fca3c680001a410841002802c8a3c68000118180808000002202450d012002420637000041002d00fca3c680001a411841002802c8a3c68000118180808000002203450d02200341cd82c38000360200200341ce83c380003602102003418883c380003602082003413b360204200341146a41c8003602002003410c6a41c60036020041002d00fca3c680001a410841002802c8a3c68000118180808000002204450d0320044290ce0037000041002d00fca3c680001a412841002802c8a3c68000118180808000002205450d04200541a384c38000360200200541ab86c38000360220200541e985c38000360218200541a885c38000360210200541e484c38000360208200541c100360204200541246a41283602002005411c6a41c200360200200541146a41c1003602002005410c6a41c40036020041002d00fca3c680001a410441002802c8a3c68000118180808000002206450d052006410a36000041002d00fca3c680001a410841002802c8a3c68000118180808000002207450d06200741e486c380003602002007412236020441002d00fca3c680001a410441002802c8a3c68000118180808000002208450d07200841e40036000041002d00fca3c680001a410841002802c8a3c68000118180808000002209450d08200941353602042009419487c38000360200200141b8016a42e88488d0c0e3aebc13370300200141b0016a42d7c9cb8fc1cf97db3e37030020014180016a42e88488d0c0e3aebc13370300200141f8006a42d7c9cb8fc1cf97db3e370300200141c8006a4293888c8f89fdc6ec9e7f370300200141c0006a42a5e9e3ab9e929adc2c370300200141106a4293888c8f89fdc6ec9e7f370300200142a5e9e3ab9e929adc2c370308200141dc016a4101360200200141d8016a2009360200200141d0016a428480808010370200200141cc016a2008360200200141c8016a4104360200200141c0016a41b580808000360200200141ac016a410d360200200141c987c380003602a801200141a4016a4101360200200141a0016a200736020020014198016a42848080801037020020014194016a200636020020014190016a410436020020014188016a41b580808000360200200141f4006a410e3602002001418687c38000360270200141ec006a4105360200200141e8006a2005360200200141e0006a4288808080d000370200200141dc006a2004360200200141d8006a4108360200200141d0006a41ef808080003602002001413c6a4111360200200141d386c38000360238200141033602342001200336023020014288808080303702282001200236022420014108360220200141ef808080003602182001410d3602042001419684c380003602002000410436020820002001360204200041043602000f0b410841e00110b280808000000b4101410810b280808000000b4104411810b280808000000b4101410810b280808000000b4104412810b280808000000b4101410410b280808000000b4104410810b280808000000b4101410410b280808000000b4104410810b280808000000b860503057f017e027f23808080800041c0006b2201248080808000200141186a41d687c38000410441d7e5c28000411341e4e7c28000410010d882808000200141106a42043702002001420037020820014280808080800137020041002d00fca3c680001a024002400240412041002802c8a3c68000118180808000002202450d002002410036021820024101360204200241da87c3800036020020014101360238200120023602302001200241206a36023c200120023602342001200141306a10fa8680800041002d00fca3c680001a20012802002103200128020421022001280208210420012802182105200129021c2106410841002802c8a3c68000118180808000002207450d01200741002903a088c380003702002001410036020820014280808080c000370200200141306a200141a888c38000411310be8b8080002001200141306a41bb88c38000411c10c18b808000200141246a200141d788c38000411210c48b8080002001200128022436020820012001280228220836020020012008200128022c41246c6a36020c20012008360204200141306a200110fb868080002005418080808078460d022001200336020820012002360200200120023602042001200220044105746a36020c200041c4006a200110fa868080002001410b6a200141306a41086a2802003600002000413c6a200637020020002005360238200041013a0000200041d8006a4101360200200041d4006a2007360200200041013602502001200129023037000320002001290000370001200041086a200141076a290000370000200141c0006a2480808080000f0b4108412010b280808000000b4104410810b280808000000b41a8d8c480004111419cd9c4800010a181808000000be20a03067f017e037f23808080800041c0006b2201248080808000200141206a41e988c38000410541d7e5c28000411341e4e7c28000410010d882808000200141186a42043702002001420037021020014280808080800137020841002d00fca3c680001a0240024002400240024002400240412041002802c8a3c68000118180808000002202450d002002410036021820024101360204200241da87c3800036020020014101360238200120023602302001200241206a36023c20012002360234200141086a200141306a10fa8680800041002d00fca3c680001a20012802082103200128020c2104200128021021052001280220210620012902242107410841002802c8a3c68000118180808000002208450d012008410029039089c3800037020041002d00fca3c680001a41002802c8a3c6800021022001410036021020014280808080c00037020841082002118180808000002209450d02200941002903c8e2c48000370200200141086a410010a086808000200128020c200141086a41086a220a28020041246c6a220241003a00202002411836021c2002419889c3800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141306a41086a200a28020041016a3602002001200129020837033041002d00fca3c680001a410841002802c8a3c68000118180808000002209450d03200941002903f0e3c480003702000240200128023822022001280230470d00200141306a200210a086808000200128023821020b2001280234200241246c6a220241013a00202002411836021c200241b089c3800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141086a41086a200141306a41086a28020041016a3602002001200129033037030841002d00fca3c680001a410841002802c8a3c68000118180808000002209450d0420094100290398e3c480003702000240200128021022022001280208470d00200141086a200210a086808000200128021021020b200128020c200241246c6a220241023a00202002411636021c200241c889c3800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141306a41086a200141086a41086a28020041016a3602002001200129030837033041002d00fca3c680001a410841002802c8a3c68000118180808000002209450d05200941002903f0e1c480003702000240200128023822022001280230470d00200141306a200210a086808000200128023821020b2001280234200241246c6a220241033a00202002411436021c200241de89c38000360218200241013602142002200936021020024280808080103702082002428080808080013702002001280238210920012802342102200120012802303602102001200236020820012002200941246c6a41246a3602142001200236020c200141306a200141086a10fb868080002006418080808078460d0620012003360210200120043602082001200436020c2001200420054105746a360214200041c4006a200141086a10fa86808000200141136a200141306a41086a2802003600002000413c6a200737020020002006360238200041013a0000200041d8006a4101360200200041d4006a2008360200200041013602502001200129023037000b20002001290008370001200041086a2001410f6a290000370000200141c0006a2480808080000f0b4108412010b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b41a8d8c480004111419cd9c4800010a181808000000bd90201037f23808080800041106b220224808080800002402001280200220328020020032802082204470d0020032004410110ab86808000200328020821040b200328020420046a41fb003a00002003200441016a3602082002200136020c20024180023b010802400240200241086a41f289c38000410b200041186a10d68680800022030d00024020022d0008450d0041002d00fca3c680001a411441002802c8a3c68000118180808000002203450d022003420037020c2003410d3602000c010b200241086a41fd89c38000410b200010d38680800022030d0002402002280208220341ff01710d0020034180fe0371450d000240200228020c280200220328020020032802082204470d0020032004410110ab86808000200328020821040b200328020420046a41fd003a00002003200441016a3602080b410021030b200241106a24808080800020030f0b4104411410b280808000000b8a0c02077f027e23808080800041a0026b220224808080800002400240024002400240024002400240200128020022032802042204450d0020032004417f6a36020420032003280200220441016a36020020042d00000e03010504020b200041053a00100c050b2001200128020441016a22033602040240200320012802084b0d0041002d00fca3c680001a41980241002802c8a3c68000118180808000002205450d02200241086a2001108f8d80800002402002280290022203418080808078460d002005200241086a41880210848e80800022064194026a200241086a4194026a280200360200200620022902940237028c02200620033602880220012001280204417f6a3602040240200128020022012802042203450d0020012003417f6a3602042001200128020041016a3602000b024020064198016a2802002207450d0020064194016a280200220821014100210303402008200341146c6a21040240024002400240024020012d00000e0400010102040b200141086a21040c020b200441086a21040c010b200441046a21040b2004280200450d00200428020441002802c0a3c68000118080808000000b200341016a2103200141146a21012007417f6a22070d000b0b0240200628029001450d0020062802940141002802c0a3c68000118080808000000b024020064190026a2802002207450d00200628028c02220821014100210303402008200341146c6a21040240024002400240024020012d00000e0400010102040b200141086a21040c020b200441086a21040c010b200441046a21040b2004280200450d00200428020441002802c0a3c68000118080808000000b200341016a2103200141146a21012007417f6a22070d000b0b200628028802450d002006418c026a28020041002802c0a3c68000118080808000000b200541002802c0a3c68000118080808000000b200041053a00100c040b200041053a00100c030b410841980210b280808000000b0240200128020022012802042203450d0020012003417f6a36020420012001280200220441016a36020020042d00004101470d0020034109490d002001200341776a22073602042001200441096a36020020074108490d002004290001210920012003416f6a22073602042001200441116a3602002007450d002004290009210a20012003416e6a3602042001200441126a36020020042d0011220141034f0d00200020013a00102000200a370308200020093703000c020b200041053a00100c010b2001200128020441016a22033602040240200320012802084b0d0041002d00fca3c680001a41980241002802c8a3c68000118180808000002205450d02200241086a2001108f8d80800002402002280290022203418080808078460d002005200241086a41880210848e80800022064194026a200241086a4194026a280200360200200620022902940237028c02200620033602880220012001280204417f6a3602040240200128020022012802042203450d0020012003417f6a3602042001200128020041016a3602000b024020064198016a2802002207450d0020064194016a280200220821014100210303402008200341146c6a21040240024002400240024020012d00000e0400010102040b200141086a21040c020b200441086a21040c010b200441046a21040b2004280200450d00200428020441002802c0a3c68000118080808000000b200341016a2103200141146a21012007417f6a22070d000b0b0240200628029001450d0020062802940141002802c0a3c68000118080808000000b024020064190026a2802002207450d00200628028c02220821014100210303402008200341146c6a21040240024002400240024020012d00000e0400010102040b200141086a21040c020b200441086a21040c010b200441046a21040b2004280200450d00200428020441002802c0a3c68000118080808000000b200341016a2103200141146a21012007417f6a22070d000b0b200628028802450d002006418c026a28020041002802c0a3c68000118080808000000b200541002802c0a3c68000118080808000000b200041053a00100b200241a0026a2480808080000f0b410841980210b280808000000bb60702047f017e23808080800041106b2202248080808000024002400240024020002d0010417d6a41ff0171220341016a410320034102491b417f6a0e03000102030b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41003a00002001200341016a22033602082000280200210002402001280200220420036b411f4b0d0020012003412010b18280800020012802002104200128020821030b200128020420036a22052000290000370000200541186a200041186a290000370000200541106a200041106a290000370000200541086a200041086a2900003700002001200341206a2203360208200029032021060240200420036b41074b0d0020012003410810b182808000200128020821030b2001200341086a360208200128020420036a2006370000200041286a200110dd8c808000200041a0016a200110dd8c808000200241046a1095888080002002280208210502402001280200200128020822006b200228020c22034f0d0020012000200310b182808000200128020821000b200128020420006a2005200310848e8080001a2001200020036a3602082002280204450d02200541002802c0a3c68000118080808000000c020b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41013a00002001200341016a22033602082000280200210002402001280200220420036b411f4b0d0020012003412010b18280800020012802002104200128020821030b200128020420036a22052000290000370000200541186a200041186a290000370000200541106a200041106a290000370000200541086a200041086a2900003700002001200341206a2203360208200029032021060240200420036b41074b0d0020012003410810b182808000200128020821030b2001200341086a360208200128020420036a2006370000200041286a200110dd8c808000200041a0016a200110dd8c808000200241046a1095888080002002280208210502402001280200200128020822006b200228020c22034f0d0020012000200310b182808000200128020821000b200128020420006a2005200310848e8080001a2001200020036a3602082002280204450d01200541002802c0a3c68000118080808000000c010b0240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a41023a00002000200110b08c8080000b200241106a2480808080000b830402037f017e4101210141002102024002400240024020002d0010417d6a41ff0171220341016a410320034102491b417f6a0e03000102030b410121034101210102402000280200220241c8006a290300220442c000540d0041022101200442808001540d00410421012004428080808004540d004109200479a74103766b21010b20024198016a28020021000240200241c0016a290300220442c000540d0041022103200442808001540d00410421032004428080808004540d004109200479a74103766b21030b417f417f417f200041146c20016a41046a220020002001491b220041286a220120012000491b2200417f20024190026a28020041146c20036a41046a220220022003491b6a220220022000491b21020c020b02402000280200220241c8006a290300220442c000540d0041022101200442808001540d00410421012004428080808004540d004109200479a74103766b21010b20024198016a2802002103410121000240200241c0016a290300220442c000540d0041022100200442808001540d00410421002004428080808004540d004109200479a74103766b21000b417f417f417f200341146c20016a41046a220320032001491b220341286a220120012003491b2203417f20024190026a28020041146c20006a41046a220220022000491b6a220220022003491b21020c010b411221020b200241016a0b9c0601077f23808080800041d0006b2203248080808000200220016b220441286e210502400240024020022001460d0002400240200441d8ffffff794b0d0020054105742202417f4c0d004100210641002d00fca3c680001a200241002802c8a3c68000118180808000002207450d012005410371210802402005417f6a4103490d00200541fcffff3f712109410021062007210220012104034020022004290000370000200241186a200441186a290000370000200241106a200441106a290000370000200241086a200441086a290000370000200241386a200441c0006a290000370000200241306a200441386a290000370000200241286a200441306a290000370000200241206a200441286a290000370000200241d8006a200441e8006a290000370000200241d0006a200441e0006a290000370000200241c8006a200441d8006a290000370000200241c0006a200441d0006a290000370000200241e0006a200441f8006a290000370000200241e8006a20044180016a290000370000200241f0006a20044188016a290000370000200241f8006a20044190016a29000037000020024180016a2102200441a0016a21042009200641046a2206470d000b0b02402008450d002001200641286c6a2102200720064105746a2104034020042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a290000370000200241286a2102200441206a21042008417f6a22080d000b0b20072005200341cf006a10dc8b80800041002d00fca3c680001a41e80241002802c8a3c68000118180808000002202450d04200241003b01e602200241003602e002200341003602102003200236020c20034100360214200341023a00282003200736021c20032007360218200320053602202003200720054105746a3602242003410c6a200341186a200341146a10c285808000200020032802143602082000200329020c3702000c030b10ae80808000000b4101200210b280808000000b20004100360208200041003602000b200341d0006a2480808080000f0b410441e80210b280808000000bbe0905017f017e017f017e017f23808080800041c0026b2204248080808000024002400240024020014180016a2d00004102460d00200441c8006a200141f0006a290000370300200441c0006a200141e8006a290000370300200441386a200141e0006a29000037030020042001290058370330200141f8006a290300210520044180026a200441306a10fa8780800041012106024002400240024020042802b40220042802b80272450d0020042903800222072005510d014103410220072005561b21060b410021080c010b2004200542017c22053703800220044188016a41386a20044180026a41386a29030037030020044188016a41306a20044180026a41306a29030037030020044188016a41286a20044180026a41286a29030037030020044188016a41206a20044180026a41206a29030037030020044188016a41186a20044180026a41186a29030037030020044188016a41106a20044180026a41106a29030037030020044188016a41086a20044180026a41086a2903003703002004200537038801200441306a20044188016a10fe8780800002402002200310d388808000220841ff01714102460d0020084180feff077141087621060c010b200441306a20012002200310dd89808000220841ff01714102460d0120084180feff077141087621060b200020083a000820004203370300200041096a20063b00000c030b200441e0016a41186a200441306a41186a290300370300200441e0016a41106a200441306a41106a290300370300200441e0016a41086a200441306a41086a290300370300200420042903303703e001410121060c010b02402002200310d388808000220341ff01714102460d00200020033a000820004203370300200041096a20034108763b00000c020b4100210602400240024002400240200128020041736a2203410220034104491b0e03000102050b200141086a108a8a80800022034180feff077141087621080c020b4100210341002108200141186a2d00004104470d02200128020810b087808000000b200110ea8780800022034180feff077141087621080b200341ff01714102460d010b200020033a000820004203370300200041096a20083b00000c010b200441186a200441e0016a41086a290300370000200441206a200441e0016a41106a290300370000200441286a200441e0016a41186a290300370000200420063a000f200420042903e00137001020044188016a200141d80010848e8080001a20044180026a2004410f6a10f289808000200441d0006a20044188016a20044180026a10f38980800020044188016a41086a200441d0006a41086a2203200441d0006a20042903504202511b220141086a29030037030020044188016a41106a200141106a29030037030020044188016a41186a200141186a2903003703002004200129030037038801200220044188016a10cd88808000200041306a200441d0006a41306a290300370300200041286a200441d0006a41286a290300370300200041206a200441d0006a41206a290300370300200041186a200441d0006a41186a290300370300200041106a200441d0006a41106a290300370300200041086a2003290300370300200020042903503703000c010b200110bf878080000b200441c0026a2480808080000bef0901057f0240024002400240024002402000280200220141736a2202410220024104491b0e03010203000b20002d00084106470d042000410c6a280200450d04200041106a28020021030c030b0240024002400240024002400240024020002d0008417f6a0e0a010b0203040506070b0b000b2000410c6a280200450d0a200041106a28020021030c090b2000410c6a280200450d09200041106a28020021030c080b2000410c6a280200450d08200041106a28020021030c070b2000410c6a280200450d07200041106a28020021030c060b200041106a28020021030240200041146a2802002201450d0020032102034002402002280200450d00200241046a28020041002802c0a3c68000118080808000000b02402002410c6a280200450d00200241106a28020041002802c0a3c68000118080808000000b200241186a21022001417f6a22010d000b0b200028020c450d060c050b200041106a28020021030240200041146a2802002202450d002002410171210441002101024020024101460d002002417e7121052003210241002101034002402002280200450d00200241046a28020041002802c0a3c68000118080808000000b02402002410c6a280200450d00200241106a28020041002802c0a3c68000118080808000000b200241186a21022005200141026a2201470d000b0b2004450d0020032001410c6c6a2202280200450d00200228020441002802c0a3c68000118080808000000b200028020c0d040c050b200041106a280200450d04200041146a28020021030c030b2000410c6a280200450d03200041106a28020021030c020b200041186a2d0000417d6a41ff017141014b0d020240200028020822034198016a2802002205450d0020034194016a280200220421004100210203402004200241146c6a21010240024002400240024020002d00000e0400010102040b200041086a21010c020b200141086a21010c010b200141046a21010b2001280200450d00200128020441002802c0a3c68000118080808000000b200241016a2102200041146a21002005417f6a22050d000b0b0240200328029001450d0020032802940141002802c0a3c68000118080808000000b024020034190026a2802002205450d002003418c026a280200220421004100210203402004200241146c6a21010240024002400240024020002d00000e0400010102040b200041086a21010c020b200141086a21010c010b200141046a21010b2001280200450d00200128020441002802c0a3c68000118080808000000b200241016a2102200041146a21002005417f6a22050d000b0b200328028802450d01200328028c0241002802c0a3c68000118080808000000c010b024002400240024002400240024002402001417e6a0e06000102030405090b200041046a21000c050b02402000280210450d00200041146a28020041002802c0a3c68000118080808000000b20002802042202418080808078460d07200041046a21000c050b02402000280204450d00200041086a28020041002802c0a3c68000118080808000000b200041106a21000c030b200041046a21000c020b200041046a21000c010b024002400240024020002d00040e0400010203070b2000410c6a21000c030b2000410c6a21000c020b2000410c6a21000c010b200041086a21000b200028020021020b2002450d01200028020421030b200341002802c0a3c68000118080808000000f0b0bca0704067f017e017f017e2380808080004180016b22052480808080000240024020014180016a2d00004102460d002000200141f8006a200141d8006a20012003200410da888080000c010b200541d0006a20012003200410d688808000024020052802602203418080808078460d00200541086a2206200541d0006a41086a22072903003703002005200529035037030020052802642108200528026c21092005280270210a2005290378210b200528026821042005280274210c200541d0006a2002200110f989808000024020052802602201418080808078460d00200541106a41086a2007290300220d370300200541206a411c6a200541d0006a411c6a290200370200200541206a41246a200541d0006a41246a290200370200200541206a412c6a200541d0006a412c6a280200360200200541206a41086a200d370300200520052902643702342005200529035037032020052001360230200720062903003703002005200b3703782005200c3602742005200a3602702005200936026c200520043602682005200836026420052003360260200520052903003703502000200541d0006a200541206a10fd848080000c020b200520052d005222013a0012200520052f015022023b0110200041026a20013a0000200020023b0100200041808080807836021002402004450d002004410171210241002100024020044101460d002004417e7121042008210141002100034002402001280200450d00200141046a28020041002802c0a3c68000118080808000000b02402001410c6a280200450d00200141106a28020041002802c0a3c68000118080808000000b200141186a21012004200041026a2200470d000b0b2002450d0020082000410c6c6a2201280200450d00200128020441002802c0a3c68000118080808000000b02402003450d00200841002802c0a3c68000118080808000000b0240200c450d00200c4101712103410021000240200c4101460d00200c417e712104200a210141002100034002402001280200450d00200141046a28020041002802c0a3c68000118080808000000b02402001410c6a280200450d00200141106a28020041002802c0a3c68000118080808000000b200141186a21012004200041026a2200470d000b0b2003450d00200a2000410c6c6a2201280200450d00200128020441002802c0a3c68000118080808000000b2009450d01200a41002802c0a3c68000118080808000000c010b200520052d005222013a0012200520052f015022043b0110200041026a20013a0000200020043b010020004180808080783602100b20054180016a2480808080000bcb0601057f23808080800041106b22032480808080000240024002402001280204220441feffffff074b0d00200141086a2802000d02200320012802001180808080000002402001280204450d0041908cc38000108781808000000b2001417f36020420012802080d01200141013602082001410c6a2003290200370200200141146a200341086a290200370200410021040c020b41a08cc38000108881808000000b0240200141186a2802002205450d00200141146a28020021040340200428020022062006280200417f6a2207360200024020070d00200641046a22072007280200417f6a220736020020070d00200641002802c0a3c68000118080808000000b200441046a21042005417f6a22050d000b0b02402001280210450d00200128021441002802c0a3c68000118080808000000b200141013602082001410c6a2003290200370200200141146a200341086a2902003702002001200128020441016a2204360204200441ffffffff07490d0041808cc38000108881808000000b2001200441016a36020402400240024002402001410c6a280200220441feffffff074b0d0002400240200141186a280200450d002000200210ab878080000c010b20040d042001417f36020c2002280250280200210641002d00fca3c680001a411041002802c8a3c68000118180808000002204450d022004200636020c2004410036020820044281808080103702000240200128021822062001280210470d00200141106a2006109b86808000200128021821060b200141146a28020020064102746a20043602002001200128021841016a3602182001200128020c41016a36020c2000200210ab87808000200128020c0d032001417f36020c02400240200128021822040d00410021040c010b20012004417f6a2204360218200128021420044102746a28020022042004280200417f6a2206360200024020060d00200441046a22062006280200417f6a220636020020060d00200441002802c0a3c68000118080808000000b200128020c41016a21040b2001200436020c0b20012001280204417f6a360204200341106a2480808080000f0b41888bc38000108881808000000b4104411010b280808000000b41ec8fc38000108781808000000b41f88ac38000108781808000000bb60e02087f017e2380808080004190016b22032480808080000240024002402001280204220441feffffff074b0d00200141086a2802000d02200341d0006a20012802001180808080000002402001280204450d0041908cc38000108781808000000b2001417f36020420012802080d01200141013602082001410c6a2003290250370200200141146a200341d8006a290200370200410021040c020b41a08cc38000108881808000000b0240200141186a2802002205450d00200141146a28020021040340200428020022062006280200417f6a2207360200024020070d00200641046a22072007280200417f6a220736020020070d00200641002802c0a3c68000118080808000000b200441046a21042005417f6a22050d000b0b02402001280210450d00200128021441002802c0a3c68000118080808000000b200141013602082001410c6a2003290250370200200141146a200341d8006a2902003702002001200128020441016a2204360204200441ffffffff07490d0041808cc38000108881808000000b2001200441016a36020402400240024002402001410c6a280200220441feffffff074b0d000240024002400240200141186a280200450d00024020022d00382206417d6a41ff0171220441016a410320044102491b22044103460d002004417f6a0e020202020b200341186a41286a22042002290328370300200341186a41306a2205200241306a290300370300200341d0006a413c6a2002413c6a2800003600002003200228003936008901200341186a41086a2207200241086a290300370300200341186a41106a2208200241106a290300370300200341186a41186a2209200241186a290300370300200341186a41206a220a200241206a29030037030020032002290300370318200341d0006a41086a2007290300370300200341d0006a41106a2008290300370300200341d0006a41186a2009290300370300200341d0006a41206a200a290300370300200341d0006a41286a2004290300370300200341d0006a41306a200529030037030020032003290318370350200320063a008801200341046a200341d0006a10b6868080000240024020032d0004410e470d0020004200370308200041206a21044202210b0c010b20002003290204370220200041286a200341046a41086a290200370200200341d2006a200341176a2d000022043a0000200320032f001522063b015020032d00142102200041336a20043a0000200041316a20063b0000200041306a20023a0000200041186a21044200210b0b2000200b370300200441003a00000c030b20040d062001417f36020c2002280240280200210641002d00fca3c680001a411041002802c8a3c68000118180808000002204450d042004200636020c2004410036020820044281808080103702000240200128021822062001280210470d00200141106a2006109b86808000200128021821060b200141146a28020020064102746a20043602002001200128021841016a3602182001200128020c41016a36020c20022d00382206417d6a41ff0171220441016a410320044102491b22044103460d012004417f6a0e020000000b00000b200341186a41286a22042002290328370300200341186a41306a2205200241306a290300370300200341d0006a413c6a2002413c6a2800003600002003200228003936008901200341186a41086a2207200241086a290300370300200341186a41106a2208200241106a290300370300200341186a41186a2209200241186a290300370300200341186a41206a220a200241206a29030037030020032002290300370318200341d0006a41086a2007290300370300200341d0006a41106a2008290300370300200341d0006a41186a2009290300370300200341d0006a41206a200a290300370300200341d0006a41286a2004290300370300200341d0006a41306a200529030037030020032003290318370350200320063a008801200341046a200341d0006a10b6868080000240024020032d0004410e470d0020004200370308200041206a21064202210b0c010b20002003290204370220200041286a200341046a41086a290200370200200341d2006a200341176a2d000022043a0000200320032f001522063b015020032d00142102200041336a20043a0000200041316a20063b0000200041306a20023a0000200041186a21064200210b0b2000200b37030041002104200641003a0000200128020c0d032001417f36020c024020012802182206450d0020012006417f6a2204360218200128021420044102746a28020022042004280200417f6a2206360200024020060d00200441046a22062006280200417f6a220636020020060d00200441002802c0a3c68000118080808000000b200128020c41016a21040b2001200436020c0b20012001280204417f6a36020420034190016a2480808080000f0b41888bc38000108881808000000b4104411010b280808000000b41ec8fc38000108781808000000b41f88ac38000108781808000000bcc0601057f23808080800041106b22032480808080000240024002402001280204220441feffffff074b0d00200141086a2802000d02200320012802001180808080000002402001280204450d0041908cc38000108781808000000b2001417f36020420012802080d01200141013602082001410c6a2003290200370200200141146a200341086a290200370200410021040c020b41a08cc38000108881808000000b0240200141186a2802002205450d00200141146a28020021040340200428020022062006280200417f6a2207360200024020070d00200641046a22072007280200417f6a220736020020070d00200641002802c0a3c68000118080808000000b200441046a21042005417f6a22050d000b0b02402001280210450d00200128021441002802c0a3c68000118080808000000b200141013602082001410c6a2003290200370200200141146a200341086a2902003702002001200128020441016a2204360204200441ffffffff07490d0041808cc38000108881808000000b2001200441016a36020402400240024002402001410c6a280200220441feffffff074b0d0002400240200141186a280200450d002000200210c4878080000c010b20040d042001417f36020c200228028001280200210641002d00fca3c680001a411041002802c8a3c68000118180808000002204450d022004200636020c2004410036020820044281808080103702000240200128021822062001280210470d00200141106a2006109b86808000200128021821060b200141146a28020020064102746a20043602002001200128021841016a3602182001200128020c41016a36020c2000200210c487808000200128020c0d032001417f36020c02400240200128021822040d00410021040c010b20012004417f6a2204360218200128021420044102746a28020022042004280200417f6a2206360200024020060d00200441046a22062006280200417f6a220636020020060d00200441002802c0a3c68000118080808000000b200128020c41016a21040b2001200436020c0b20012001280204417f6a360204200341106a2480808080000f0b41888bc38000108881808000000b4104411010b280808000000b41ec8fc38000108781808000000b41f88ac38000108781808000000bf21e02057f017e23808080800041a0016b220224808080800002400240024002400240024002400240024002400240024002402001280200417f6a0e0c000102030405060708090a0b000b2001280258210141092103024010fa81808000220441fe014b0d002002200441016a36027041b1e3c080004113200241f0006a410441002802e0a1c680001186808080000041002802e8a1c680001188808080000041002802b0a1c6800011888080800000200241d8006a10fb81808000410e21030b20012001280200417f6a2205360200024020050d00200141086a28020022062001410c6a28020022052802001180808080000002402005280204450d00200641002802c0a3c68000118080808000000b200141046a22052005280200417f6a220536020020050d00200141002802c0a3c68000118080808000000b02400240200441fe014b0d0020004200370308200041206a2101420221070c010b200020033a0020200041216a41003a0000200041186a2101420021070b20002007370300200141003a00000c0b0b200141086a28020021032001280204210420024190016a200141f8006a29030037030020024188016a200141f0006a29030037030020024180016a200141e8006a290300370300200241f0006a41086a200141e0006a29030037030020022001290358370370200241d8006a200241f0006a10b48680800002402004450d00200341002802c0a3c68000118080808000000b0240024020022d0058410e470d0020004200370308200041206a2101420221070c010b20002002290258370220200041286a200241e0006a290200370200200241f2006a200241eb006a2d000022013a0000200220022f006922043b017020022d00682103200041336a20013a0000200041316a20043b0000200041306a20033a0000200041186a2101420021070b20002007370300200141003a00000c0a0b200241086a41086a200141186a2802003602002002200129021037030820012802582104200241d8006a41086a2001410c6a280200360200200220012902043703582002200241086a360264200241f0006a200241d8006a10c98680800002402002280208450d00200228020c41002802c0a3c68000118080808000000b20042004280200417f6a2201360200024020010d00200441086a28020022032004410c6a28020022012802001180808080000002402001280204450d00200341002802c0a3c68000118080808000000b200441046a22012001280200417f6a220136020020010d00200441002802c0a3c68000118080808000000b0240024020022d0070410e470d0020004200370308200041206a2101420221070c010b20002002290270370220200041286a200241f8006a290200370200200241da006a20024183016a2d000022013a0000200220022f00810122043b015820022d0080012103200041336a20013a0000200041316a20043b0000200041306a20033a0000200041186a2101420021070b20002007370300200141003a00000c090b200241186a41086a2001410c6a280200360200200241286a41086a200141186a280200360200200220012902043703182002200129021037032820024190016a200141f8006a290300370300200241f0006a41186a200141f0006a29030037030020024180016a200141e8006a290300370300200241f0006a41086a200141e0006a290300370300200220012903583703702002200241286a36029c012002200241186a36029801200241d8006a200241f0006a10bf8680800002402002280228450d00200228022c41002802c0a3c68000118080808000000b02402002280218450d00200228021c41002802c0a3c68000118080808000000b0240024020022d0058410e470d0020004200370308200041206a2101420221070c010b20002002290258370220200041286a200241e0006a290200370200200241f2006a200241eb006a2d000022013a0000200220022f006922043b017020022d00682103200041336a20013a0000200041316a20043b0000200041306a20033a0000200041186a2101420021070b20002007370300200141003a00000c080b200241386a41086a2001410c6a2802003602002002200129020437033820024190016a200141f8006a29030037030020024188016a200141f0006a29030037030020024180016a200141e8006a290300370300200241f0006a41086a200141e0006a290300370300200220012903583703702002200241386a36029801200241d8006a200241f0006a10c08680800002402002280238450d00200228023c41002802c0a3c68000118080808000000b0240024020022d0058410e470d0020004200370308200041206a2101420221070c010b20002002290258370220200041286a200241e0006a290200370200200241f2006a200241eb006a2d000022013a0000200220022f006922043b017020022d00682103200041336a20013a0000200041316a20043b0000200041306a20033a0000200041186a2101420021070b20002007370300200141003a00000c070b200241c8006a41086a2001410c6a2802003602002002200129020437034820024190016a200141f8006a29030037030020024188016a200141f0006a29030037030020024180016a200141e8006a290300370300200241f0006a41086a200141e0006a290300370300200220012903583703702002200241c8006a36029801200241d8006a200241f0006a10b88680800002402002280248450d00200228024c41002802c0a3c68000118080808000000b0240024020022d0058410e470d0020004200370308200041206a2101420221070c010b20002002290258370220200041286a200241e0006a290200370200200241f2006a200241eb006a2d000022013a0000200220022f006922043b017020022d00682103200041336a20013a0000200041316a20043b0000200041306a20033a0000200041186a2101420021070b20002007370300200141003a00000c060b200241f0006a41206a200141f8006a290200370300200241f0006a41186a200141f0006a29020037030020024180016a200141e8006a290200370300200241f0006a41086a200141e0006a29020037030020022001290258370370200241d8006a200241f0006a200141046a10b6888080000240024020022d0058410e470d0020004200370308200041206a2101420221070c010b20002002290258370220200041286a200241d8006a41086a290200370200200241f2006a200241eb006a2d000022013a0000200220022f006922043b017020022d00682103200041336a20013a0000200041316a20043b0000200041306a20033a0000200041186a2101420021070b20002007370300200141003a00000c050b2001280258210141092103024010fa81808000220441fe014b0d002002200441016a36027041b1e3c080004113200241f0006a410441002802e0a1c680001186808080000041002802e8a1c680001188808080000041002802b0a1c6800011888080800000200241d8006a10fb81808000410e21030b20012001280200417f6a2205360200024020050d00200141086a28020022062001410c6a28020022052802001180808080000002402005280204450d00200641002802c0a3c68000118080808000000b200141046a22052005280200417f6a220536020020050d00200141002802c0a3c68000118080808000000b02400240200441fe014b0d0020004200370308200041206a2101420221070c010b200020033a0020200041216a41003a0000200041186a2101420021070b20002007370300200141003a00000c040b2001280258210141092103024010fa81808000220441fe014b0d002002200441016a36027041b1e3c080004113200241f0006a410441002802e0a1c680001186808080000041002802e8a1c680001188808080000041002802b0a1c6800011888080800000200241d8006a10fb81808000410e21030b20012001280200417f6a2205360200024020050d00200141086a28020022062001410c6a28020022052802001180808080000002402005280204450d00200641002802c0a3c68000118080808000000b200141046a22052005280200417f6a220536020020050d00200141002802c0a3c68000118080808000000b02400240200441fe014b0d0020004200370308200041206a2101420221070c010b200020033a0020200041216a41003a0000200041186a2101420021070b20002007370300200141003a00000c030b200241f0006a41206a200141f8006a290300370300200241f0006a41186a200141f0006a29030037030020024180016a200141e8006a290300370300200241f0006a41086a200141e0006a29030037030020022001290358370370200241d8006a200241f0006a10b4868080000240024020022d0058410e470d0020004200370308200041206a2101420221070c010b20002002290258370220200041286a200241d8006a41086a290200370200200241f2006a200241eb006a2d000022013a0000200220022f006922043b017020022d00682103200041336a20013a0000200041316a20043b0000200041306a20033a0000200041186a2101420021070b20002007370300200141003a00000c020b20012802042104200241f0006a41206a200141f8006a290200370300200241f0006a41186a200141f0006a29020037030020024180016a200141e8006a290200370300200241f0006a41086a200141e0006a29020037030020022001290258370370200241d8006a200241f0006a200410b7888080000240024020022d0058410e470d0020004200370308200041206a2101420221070c010b20002002290258370220200041286a200241d8006a41086a290200370200200241f2006a200241eb006a2d000022013a0000200220022f006922043b017020022d00682103200041336a20013a0000200041316a20043b0000200041306a20033a0000200041186a2101420021070b20002007370300200141003a00000c010b20012802042104200241f0006a41206a200141f8006a290200370300200241f0006a41186a200141f0006a29020037030020024180016a200141e8006a290200370300200241f0006a41086a200141e0006a29020037030020022001290258370370200241d8006a200241f0006a200410b9888080000240024020022d0058410e470d0020004200370308200041206a2101420221070c010b20002002290258370220200041286a200241d8006a41086a290200370200200241f2006a200241eb006a2d000022013a0000200220022f006922043b017020022d00682103200041336a20013a0000200041316a20043b0000200041306a20033a0000200041186a2101420021070b20002007370300200141003a00000b200241a0016a2480808080000bcb0601057f23808080800041106b22032480808080000240024002402001280204220441feffffff074b0d00200141086a2802000d02200320012802001180808080000002402001280204450d0041908cc38000108781808000000b2001417f36020420012802080d01200141013602082001410c6a2003290200370200200141146a200341086a290200370200410021040c020b41a08cc38000108881808000000b0240200141186a2802002205450d00200141146a28020021040340200428020022062006280200417f6a2207360200024020070d00200641046a22072007280200417f6a220736020020070d00200641002802c0a3c68000118080808000000b200441046a21042005417f6a22050d000b0b02402001280210450d00200128021441002802c0a3c68000118080808000000b200141013602082001410c6a2003290200370200200141146a200341086a2902003702002001200128020441016a2204360204200441ffffffff07490d0041808cc38000108881808000000b2001200441016a36020402400240024002402001410c6a280200220441feffffff074b0d0002400240200141186a280200450d002000200210af878080000c010b20040d042001417f36020c2002280278280200210641002d00fca3c680001a411041002802c8a3c68000118180808000002204450d022004200636020c2004410036020820044281808080103702000240200128021822062001280210470d00200141106a2006109b86808000200128021821060b200141146a28020020064102746a20043602002001200128021841016a3602182001200128020c41016a36020c2000200210af87808000200128020c0d032001417f36020c02400240200128021822040d00410021040c010b20012004417f6a2204360218200128021420044102746a28020022042004280200417f6a2206360200024020060d00200441046a22062006280200417f6a220636020020060d00200441002802c0a3c68000118080808000000b200128020c41016a21040b2001200436020c0b20012001280204417f6a360204200341106a2480808080000f0b41888bc38000108881808000000b4104411010b280808000000b41ec8fc38000108781808000000b41f88ac38000108781808000000bd11d03057f047e067f2380808080004180026b220224808080800020012802002103200241386a4208370300200241306a4200370300200242808080801037032820024100360220200242808080808001370318200241023a0010200242043703082002420137030041002d00fca3c680001a02400240024002400240024041800141002802c8a3c68000118180808000002204450d00200241003602f801200220043602f40120024180013602f0012002200241f0016a3602d00102402002200241d0016a10fb898080002205450d0020022802f001450d0620022802f40141002802c0a3c68000118080808000000c060b20022802f401210520022802f0012206418080808078460d0502402003418180808078470d00200020022802f80136020820002005360204200020063602000c050b024002402003418080808078470d00200241d4006a41086a200141086a2802002203360200200241003602542002200128020422013602580c010b200241d4006a2001280204200128020810fc8080800020022802540d03200241dc006a2802002103200228025821010b0240024002400240024002400240024002400240024002400240024002402003417a6a0e020100110b200141b395c38000410710888e8080000d1041002d00fca3c680001a41c00041002802c8a3c68000118180808000002201450d0d200141386a4100290087a3c28000370000200141306a41002900ffa2c28000370000200141286a41002900f7a2c28000370000200141002900efa2c28000370020200141002900cfa2c28000370000200141086a41002900d7a2c28000370000200141106a41002900dfa2c28000370000200141186a41002900e7a2c28000370000200241003602742002410036026c41002d00fca3c680001a410841002802c8a3c68000118180808000002203450d0c200342e2c2b18be6edd8b2f300370000200241083602a801200220033602a401200241083602a001200241003602b401200241003602ac0141002d00fca3c680001a410841002802c8a3c68000118180808000002203450d0b200342e2c2b18be6edd8b2f300370000200241083602cc01200220033602c801200241083602c40141002d00fca3c680001a024041d00041002802c8a3c68000118180808000002203450d00200141086a2900002107200141106a2900002108200141186a29000021092001290000210a20034280809aa6eaafe301370320200341186a2009370000200341106a2008370000200341086a20073700002003200a370000200141206a220441086a2900002107200441106a2900002108200441186a290000210920032004290000370028200341c8006a4280809aa6eaafe301370300200341c0006a2009370000200341386a2008370000200341306a2007370000200141002802c0a3c6800011808080800000200241023602ec01200220033602e801200241023602e401200241f0016a200241e4016a10d28680800020022d00f0014106460d10200241d0016a41086a200241f0016a41086a290200370300200220022902f0013703d001200241f0016a200241ac016a200241c4016a200241d0016a10968d808000024020022d00f0014106460d00200241f0016a10c7878080000b024020022802e401450d0020022802e80141002802c0a3c68000118080808000000b200241dc016a200241b4016a280200360200200220022902ac013702d401200241053a00d001200241f0016a200241ec006a200241a0016a200241d0016a10968d808000024020022d00f0014106460d00200241f0016a10c7878080000b41002d00fca3c680001a410d41002802c8a3c68000118180808000002201450d08200141056a41002900d796c38000370000200141002900d296c380003700002002410d36028c0120022001360288012002410d36028401200241003602a801200241003602a00141002d00fca3c680001a410b41002802c8a3c68000118180808000002201450d07200141076a41002800f989c38000360000200141002900f289c380003700002002410b3602b401200220013602b0012002410b3602ac0141002d00fca3c680001a412041002802c8a3c68000118180808000002201450d06200241c4016a41afa2c2800041002f0194a1c6800010c8878080004101210b20022802c801210c41012104024020022802cc012203450d002003417f4c0d0641002d00fca3c680001a200341002802c8a3c68000118180808000002204450d050b2004200c200310848e808000210d200241e4016a418fa3c2800041002f0194a1c6800010c88780800020022802e801210e024020022802ec012204450d002004417f4c0d0641002d00fca3c680001a200441002802c8a3c6800011818080800000220b450d040b200b200e200410848e808000210b2001411c6a2004360200200141186a200b360200200141146a2004360200200141033a00102001200336020c2001200d36020820012003360204200141033a0000200241fc016a4102360200200241f8016a2001360200200241023602f401200241043a00f001200241d0016a200241a0016a200241ac016a200241f0016a10968d808000024020022d00d0014106460d00200241d0016a10c7878080000b024020022802e401450d00200e41002802c0a3c68000118080808000000b024020022802c401450d00200c41002802c0a3c68000118080808000000b200241f0016a410c6a200241a0016a41086a280200360200200220022902a0013702f401200241053a00f001200241d0016a200241ec006a20024184016a200241f0016a10968d808000024020022d00d0014106460d00200241d0016a10c7878080000b200241c4006a410c6a200241ec006a41086a2802003602002002200229026c370248200241053a00440c020b410841d00010b280808000000b200141ba95c38000410610888e8080000d0f200241003602cc01200241003602c40141002d00fca3c680001a410341002802c8a3c68000118180808000002201450d09200141026a41002d00c295c380003a0000200141002f00c095c380003b0000200241033602ec01200220013602e801200241033602e40141002d00fca3c680001a410341002802c8a3c68000118180808000002201450d08200141026a41002d00c595c380003a0000200141002f00c395c380003b0000200241033602fc01200220013602f801200241033602f401200241033a00f001200241d0016a200241c4016a200241e4016a200241f0016a10968d808000024020022d00d0014106460d00200241d0016a10c7878080000b200241d0006a200241cc016a280200360200200220022902c401370248200241053a00440b41002d00fca3c680001a41800141002802c8a3c68000118180808000002201450d06200220013602f40120024180013602f0012002200241f0016a3602e401200141fb003a0000200241013602f80141800221010240200241c4006a410c6a28020022030d0041012101024020022802f0014101470d00200241f0016a4101410110ab8680800020022802f80121010b20022802f40120016a41fd003a00002002200141016a3602f801410021010b200220013602d00141002101200341002002280248220c1b210e200c410047210f2002200241e4016a3602d401200241c4006a41086a2802002104024003400240024002400240200e450d0002400240200f450d002001450d010b200f0d0441f887c6800010a081808000000b4101210f200c21012004450d022004210302402004410771220c450d0003402003417f6a210320012802bc022101200c417f6a220c0d000b0b200441084f0d010c020b024020022802d001220141ff01710d00024020014180fe0371450d00024020022802d401280200220128020020012802082203470d0020012003410110ab86808000200128020821030b200128020420036a41fd003a00002001200341016a3602080b20022802f401210320022802f0012201418080808078460d05200020022802f8013602082000200336020420002001360200200241c4006a10c7878080000c150b41e493c38000412841ec94c3800010f880808000000b034020012802bc022802bc022802bc022802bc022802bc022802bc022802bc022802bc022101200341786a22030d000b0b410021044100210c0b024002400240200420012f01ba02490d00034020012802b0012203450d02200c41016a210c20012f01b802210420032101200420032f01ba024f0d000b0b2001210b2004220d41016a21040240200c0d00200b21010c020b200b20044102746a41bc026a280200210141002104200c417f6a2203450d01200c417e6a211002402003410771220c450d0003402003417f6a210320012802bc022101200c417f6a220c0d000b0b20104107490d01034020012802bc022802bc022802bc022802bc022802bc022802bc022802bc022802bc022101200341786a22030d000c020b0b41e887c6800010a081808000000b200e417f6a210e4100210c200241d0016a200b200d410c6c6a41b4016a200b200d4104746a10d7868080002203450d000b20022802f001450d0020022802f40141002802c0a3c68000118080808000000b200220033602f00141b08cc38000412f200241f0016a41e08cc3800041e096c38000108981808000000b4101200410b280808000000b4101200310b280808000000b10ae80808000000b4104412010b280808000000b4101410b10b280808000000b4101410d10b280808000000b410141800110b280808000000b4101410310b280808000000b4101410310b280808000000b4101410810b280808000000b4101410810b280808000000b410141c00010b280808000000b410141800110b280808000000b200220022802f4013602d00141c695c38000412b200241d0016a41e08cc3800041f096c38000108981808000000b20004180808080783602000b2006450d00200541002802c0a3c68000118080808000000b02402002280218450d00200228021c41002802c0a3c68000118080808000000b02402002280228450d00200228022c41002802c0a3c68000118080808000000b02402002280234450d00200228023841002802c0a3c68000118080808000000b20024180026a2480808080000f0b200220053602f00141b08cc38000412f200241f0016a41e08cc3800041e08dc38000108981808000000ba60201027f23808080800041306b22012480808080000240024002400240024020002d00000e050404010203000b02400240200028020422020d0041002100410021020c010b200120023602242001410036022020012002360214200141003602102001200041086a2802002202360228200120023602182000410c6a2802002102410121000b2001200236022c2001200036021c2001200036020c2001410c6a10aa8d8080000c030b2000280204450d02200041086a28020041002802c0a3c68000118080808000000c020b2000280204450d01200041086a28020041002802c0a3c68000118080808000000c010b200041046a1091878080002000280204450d00200041086a28020041002802c0a3c68000118080808000000b200141306a2480808080000b840501047f23808080800041c0006b220324808080800041002d00fca3c680001a41002802c8a3c680002104024002400240024002400240200241ffff00712205413f4b0d004101210641012004118180808000002204450d02200420023a00000c010b4102210641022004118180808000002204450d02200420024106742005410876723a00012004200241fc017141027641c000723a00000b200320063602182003200436021420032006360210200341106a2006412010ab8680800020032802142206200328021822046a22022001290000370000200241086a200141086a290000370000200241106a200141106a290000370000200241186a200141186a2900003700002003200441206a22013602182003411c6a2006200110e8838080002003280224220241014d0d022003280220210202402003280210220420016b41014b0d00200341106a2001410210ab868080002003280214210620032802102104200328021821010b200620016a20022f00003b00002003410036023020034280808080103702282003200341286a360234200320063602382003200141026a220536023c200341086a200341346a200141036a41017620056a200341386a41f091c3800010a9898080002003280208210102402004450d00200641002802c0a3c68000118080808000000b20010d0320002003290228370200200041086a200341286a41086a2802003602000240200328021c450d00200241002802c0a3c68000118080808000000b200341c0006a2480808080000f0b4101410110b280808000000b4101410210b280808000000b4102200241e091c38000109581808000000b41b4a1c38000412b200341386a41e0a1c3800041f0a1c38000108981808000000bc10501067f23808080800041b0016b22022480808080002001280204210320012802082104200241003602980120022004360294012002200336029001200241c0006a20024190016a10c58a808000024002400240024020022802742204418080808078470d0020022002280240360280012002419c016a4201370200410121052002410136029401200241848ec380003602900120024188828080003602ac012002200241a8016a36029801200220024180016a3602a80120024184016a20024190016a10b88080800020022802880121060240200228028c012204450d002004417f4c0d0341002d00fca3c680001a200441002802c8a3c68000118180808000002205450d040b20052006200410848e80800021070240200228028401450d00200641002802c0a3c68000118080808000000b024020022802800122052802000d00200541086a280200450d00200528020441002802c0a3c68000118080808000000b200541002802c0a3c68000118080808000002000200436020820002007360204200020043602000c010b200241146a200241c0006a41146a2902003702002002411c6a2205200241c0006a411c6a290200370200200241246a200241c0006a41246a2902003702002002412c6a200241c0006a412c6a2902003702002002200229024c37020c20022002290378370338200220043602342002200228024836020820022002290340370300200210f889808000200041818080807836020002402002280218450d00200528020041002802c0a3c68000118080808000000b02402002280228450d002002412c6a28020041002802c0a3c68000118080808000000b2002280234450d00200228023841002802c0a3c68000118080808000000b02402001280200450d00200341002802c0a3c68000118080808000000b200241b0016a2480808080000f0b10ae80808000000b4101200410b280808000000b4100200042919fd78da1a1ad84ff003700082000429ceccef7a6c0dedd20370000200042dca0bb8e8acbf9b3da00370018200042e78ec688edebaee7ba7f3700100b4000200042919fd78da1a1ad84ff003700082000429ceccef7a6c0dedd20370000200042aac0b0e5d1eaef8d63370018200042b8e2b0fbfb91a8ed827f3700100bae0301047f23808080800041106b2202248080808000200041c0006a210302402001280200200128020822046b411f4b0d0020012004412010b182808000200128020821040b200128020420046a22052003290000370000200541186a200341186a290000370000200541106a200341106a290000370000200541086a200341086a2900003700002001200441206a22033602080240200128020020036b413f4b0d002001200341c00010b182808000200128020821030b2001200341c0006a360208200128020420036a22032000290000370000200341086a200041086a290000370000200341106a200041106a290000370000200341186a200041186a290000370000200341206a200041206a290000370000200341286a200041286a290000370000200341306a200041306a290000370000200341386a200041386a2900003700002002200041e0006a36020c2002410c6a200110c18a808000200041e8006a2d000021030240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a20033a0000200241106a2480808080000b890301047f23808080800041206b2204248080808000024002402001417f4c0d0041002d00fca3c680001a2001410574410472220541002802c8a3c68000118180808000002206450d0120044100360214200420063602102004200536020c200420013602182004200441186a36021c2004411c6a2004410c6a10c08a8080000240024020010d0020042802142101200428021021070c010b200141057421062004280214210103400240200428020c20016b411f4b0d002004410c6a2001412010b182808000200428021421010b2004280210220720016a22052000290000370000200541086a200041086a290000370000200541106a200041106a290000370000200541186a200041186a2900003700002004200141206a2201360214200041206a2100200641606a22060d000b0b200428020c2100200220032007200141002802e0a1c680001186808080000002402000450d00200741002802c0a3c68000118080808000000b200441206a2480808080000f0b10ae80808000000b4101200510b280808000000baf0302057f017e23808080800041206b2203248080808000024002402002417f4c0d0041002d00fca3c680001a200241286c410472220441002802c8a3c68000118180808000002205450d0120034100360214200320053602102003200436020c200320023602182003200341186a36021c2003411c6a2003410c6a10c08a80800002402002450d002001200241286c6a21062003280214210203400240200328020c220520026b411f4b0d002003410c6a2002412010b182808000200328020c2105200328021421020b2003280210220720026a22042001290000370000200441186a200141186a290000370000200441106a200141106a290000370000200441086a200141086a2900003700002003200241206a2202360214200141206a29030021080240200520026b41074b0d002003410c6a2002410810b18280800020032802102107200328021421020b200720026a20083700002003200241086a2202360214200141286a22012006470d000b0b2000200329020c370200200041086a2003410c6a41086a280200360200200341206a2480808080000f0b10ae80808000000b4101200410b280808000000bc01404017f017e057f037e23808080800041900d6b2201248080808000200142919fd78da1a1ad84ff003703b80b2001429ceccef7a6c0dedd203703b00b200142d8d2dfcce2f8e593413703c80b200142faa5fa8ea9819ff1bd7f3703c00b200141a0086a200141b00b6a10e08880800002400240024020012903a00822024204510d00200141b00b6a412041002802a0a1c6800011848080800000200141a0056a200141a0086a41086a41f00010848e8080001a200141286a200141a0056a41f00010848e8080001a20024203510d00200120023703980120014198016a41086a200141286a41f00010848e8080001a20024201510d0020014188026a2802002103200142919fd78da1a1ad84ff003703a8082001429ceccef7a6c0dedd203703a00820014282fceae49dd9e2861d3703b808200142de8c84a1ecd0a6d30c3703b008200141a0056a200141a0086a10e2888080000240024020012802a0052204418080808078470d00410121050c010b20012802a4052106410021070240200320012802a8054f0d00200142919fd78da1a1ad84ff003703a8052001429ceccef7a6c0dedd203703a005200142c6e4a9b1aaa1afebf2003703b805200142fa82b1828b81b8f31e3703b0052006200341286c6a2103200141a0086a200141a0056a10e5888080000240024020012d00a0080d00200141b8056a4200370300200141b0056a4200370300200141a8056a4200370300200142003703a0050c010b200141b8056a200141b9086a290000370300200141b0056a200141b1086a290000370300200141a8056a200141a9086a290000370300200120012900a1083703a0050b200142919fd78da1a1ad84ff003703a8082001429ceccef7a6c0dedd203703a008200142e9c5fea9cdfbc4d26d3703b80820014286aaece2939beae4653703b008200141186a200141a0086a10e7888080002001290320210220012802182105200142919fd78da1a1ad84ff003703a8082001429ceccef7a6c0dedd203703a008200142aac0b0e5d1eaef8d633703b808200142b8e2b0fbfb91a8ed827f3703b008200141086a200141a0086a10e688808000200129031021082001280208210720012002420020051b3703e00320012008420020071b3703b00b200141a0086a41ad8ec28000410410a682808000200141a0086a41b18ec28000410b200141e0036a410810a782808000200141a0086a41bc8ec28000410d200141b00b6a410810a782808000200141a0086a41c98ec280004110200141a0056a412010a78280800020014190026a200141a0086a41d00110848e8080001a200141b00b6a41186a200341186a2900002202370300200141b00b6a41106a200341106a2900002208370300200141b00b6a41086a200341086a290000220937030020012003290000220a3703b00b200141a0056a41186a22032002370300200141a0056a41106a2008370300200141a0056a41086a20093703002001200a3703a005200141a0086a200141a0056a10b18180800002400240024020012802a008450d0020014189046a200141a0086a410d6a29000037000020014190046a200141b4086a290000370000200120012900a5083700810420012d00a408210520014198046a200141bc086a41880110848e8080001a200141e0036a41096a200141a0056a41096a290000370000200141e0036a41116a200141a0056a41116a290000370000200141e0036a41186a2003290000370000200120012900a1053700e103200120053a008004200120012d00a0053a00e00320012f01d803210320012d00da032105200141b00b6a20014190026a41c80110848e8080001a200120053a00fa0c200120033b01f80c200141a0086a200141e0016a200141e0036a200141b00b6a10c48a80800020012802a008450d010b410021070c010b200141a0056a200141a4086a41800310848e8080001a41012107200141a0086a41016a200141a0056a41a08ec38000411310c38a808000200141b80b6a200141a0086a41096a290000370300200141c00b6a200141a0086a41116a290000370300200141c80b6a200141b9086a290000370300200120012900a1083703b00b0b41002105034020014190026a20056a220341003a0000200341016a41003a0000200341026a41003a0000200341036a41003a0000200341046a41003a0000200541056a220541c801470d000b0b02402004450d00200641002802c0a3c68000118080808000000b20074521052007450d002001290398014200520d00200142919fd78da1a1ad84ff003703a8082001429ceccef7a6c0dedd203703a008200142958ed1e593cab9fca47f3703b808200142e6d0c3af83b9abdfff003703b0082001200141a0086a412010d08880800020012001280204410020012802001b3602880d20014190026a200141880d6a10f98780800002400240200128029802220341ff014b0d0002402003200128029002470d0020014190026a200310a18680800020012802980221030b20012802940220034105746a220520012903b00b370000200541086a200141b00b6a41086a290300370000200541106a200141b00b6a41106a290300370000200541186a200141b00b6a41186a2903003700002001200341016a36029802200141880d6a20014190026a1080888080000c010b200120012802880d41016a36028c0d41002d00fca3c680001a412041002802c8a3c68000118180808000002203450d03200320012903b00b370000200341186a200141b00b6a41186a290300370000200341106a200141b00b6a41106a290300370000200341086a200141b00b6a41086a290300370000200141013602a805200120033602a405200141013602a0052001418c0d6a200141a0056a108188808000200142919fd78da1a1ad84ff003703a8082001429ceccef7a6c0dedd203703a008200142958ed1e593cab9fca47f3703b808200142e6d0c3af83b9abdfff003703b0082001200128028c0d3602e003200141a0086a4120200141e0036a410441002802e0a1c68000118680808000000b0240200128029002450d0020012802940241002802c0a3c68000118080808000000b410021050b200142919fd78da1a1ad84ff003703a8082001429ceccef7a6c0dedd203703a0082001428fa194fdfdd0d0e2c5003703b808200142d0effddeadf1b688773703b008410121074100210441002d00fca3c680001a4101412120051b220641002802c8a3c68000118180808000002203450d02024020050d00200320012903b00b370001200341196a200141c80b6a290300370000200341116a200141c00b6a290300370000200341096a200141b80b6a29030037000041212107410121040b200320043a0000200141a0086a41202003200741002802e0a1c6800011868080800000200341002802c0a3c68000118080808000000b200142919fd78da1a1ad84ff003703a8082001429ceccef7a6c0dedd203703a008200142bdff9adbcf84adb29e7f3703b80820014283c69cb2f58af8c40f3703b008200141a0086a412041002802a0a1c6800011848080800000200141900d6a2480808080000f0b4101412010b280808000000b4101200610b280808000000bbb0d04037f017e037f057e23808080800041b0026b2202248080808000200242919fd78da1a1ad84ff003703282002429ceccef7a6c0dedd20370320200242d8d2dfcce2f8e59341370338200242faa5fa8ea9819ff1bd7f37033020024190016a200241206a10e08880800002402002290390014204520d0020024190026a10ee8880800020022802940221030240024020022802980222040d00420321050c010b200441146c210620032107024002400340024020072d00000d00200741016a280000210820022007410c6a29020037027c200841c28289aa04470d0020024190016a200241fc006a10ae8c80800020022903900122054203520d020b200741146a21072006416c6a22060d000b420321050c010b2002290398012109200241206a200241a0016a41d80010848e8080001a200229038002210a20022903f801210b0b200321074100210603402003200641146c6a21080240024002400240024020072d00000e0400010102040b200741086a21080c020b200841086a21080c010b200841046a21080b2008280200450d00200828020441002802c0a3c68000118080808000000b200641016a2106200741146a21072004417f6a22040d000b0b0240200228029002450d00200341002802c0a3c68000118080808000000b024020054203510d00200242919fd78da1a1ad84ff00370398012002429ceccef7a6c0dedd2037039001200242dca0bb8e8acbf9b3da003703a801200242e78ec688edebaee7ba7f3703a0012009200b20054201511b210c200241106a20024190016a10e788808000024002402002280210450d00200229031850450d010b200242919fd78da1a1ad84ff00370398012002429ceccef7a6c0dedd2037039001200242dca0bb8e8acbf9b3da003703a801200242e78ec688edebaee7ba7f3703a0012002200c3703900220024190016a412020024190026a410841002802e0a1c6800011868080800000200242919fd78da1a1ad84ff00370398012002429ceccef7a6c0dedd203703900120024282fceae49dd9e2861d3703a801200242de8c84a1ecd0a6d30c3703a00120024190026a20024190016a10e288808000200228029402210820022802980221042002280290022107200242919fd78da1a1ad84ff00370398022002429ceccef7a6c0dedd2037039002200242c6e4a9b1aaa1afebf2003703a802200242fa82b1828b81b8f31e3703a0024100200420074180808080784622061b21044108200820061b21084100200720061b210720024190016a20024190026a10e5888080000240024020022d0090010d00200241a8026a4200370300200241a0026a420037030020024190026a41086a420037030020024200370390020c010b200241a8026a200241a9016a290000370300200241a0026a200241a1016a29000037030020024190026a41086a20024199016a2900003703002002200229009101370390020b2002419c016a200436020020024190016a41086a200836020020024190016a41106a20022903900237030020024190016a41186a20024190026a41086a290300370300200241b0016a20024190026a41106a290300370300200241b8016a20024190026a41186a29030037030020022007360294012002410036029001200241fc006a41086a20024190016a10cc8680800020024180016a41c5003a0000200241818485920436027c200241fc006a10f5888080002002280290010d00200228029401450d0020022802980141002802c0a3c68000118080808000000b200242919fd78da1a1ad84ff00370398012002429ceccef7a6c0dedd2037039001200242e9c5fea9cdfbc4d26d3703a80120024286aaece2939beae4653703a001200220024190016a10e788808000200228020021072002290308210d200242919fd78da1a1ad84ff00370398012002429ceccef7a6c0dedd2037039001200242bdff9adbcf84adb29e7f3703a80120024283c69cb2f58af8c40f3703a00120024200200c200d42017c420120071b7d220d200d200c561b42ffffffff0f833703900220024190016a412020024190026a410841002802e0a1c6800011868080800000200242919fd78da1a1ad84ff00370398012002429ceccef7a6c0dedd2037039001200242e9c5fea9cdfbc4d26d3703a80120024286aaece2939beae4653703a0012002200c3703900220024190016a412020024190026a410841002802e0a1c68000118680808000000b20022009370398012002200537039001200241a0016a200241206a41d80010848e8080001a2002200a370380022002200b3703f80120024190016a10f288808000200110b88a8080000b2000420037030820004200370300200241b0026a2480808080000b21002001280214418c8ec380004114200141186a28020028020c118280808000000b040041000bb80201027f23808080800041206b2202248080808000200028020021002002200128021441e4e7c280004100200141186a28020028020c118280808000003a00142002200136021041012101200241013a00152002410036020c200220003602182002200041046a36021c2002410c6a200241186a41b88ec38000108d818080002002411c6a41c88ec38000108d81808000210020022d0014210302400240200028020022000d00200341ff017141004721010c010b200341ff01710d0020022802102103024020004101470d0020022d001541ff0171450d0020032d001c4104710d00410121012003280214418ca5c080004101200341186a28020028020c118280808000000d010b2003280214418da5c080004101200341186a28020028020c1182808080000021010b200241206a24808080800020010b2100200128021441e6acc28000410f200141186a28020028020c118280808000000bff0101027f23808080800041106b2202248080808000200220002802003602042001280214419c95c380004111200141186a28020028020c118280808000002100200241003a000d200220003a000c20022001360208200241086a41ad95c380004106200241046a418c95c38000108c81808000210320022d000c21000240024020022d000d0d00200041ff017141004721010c010b41012101200041ff01710d000240200328020022012d001c4104710d0020012802144187a5c080004102200128021828020c1182808080000021010c010b20012802144186a5c080004101200128021828020c1182808080000021010b200241106a24808080800020010b040041000b1200200141b38ec38000410210dd808080000b02000b02000b43000240200028020022002802000d00200041086a280200450d00200028020441002802c0a3c68000118080808000000b200041002802c0a3c68000118080808000000bdd0401027f23808080800041106b22022480808080000240024002400240024002400240024002400240024020002f01000e09000102030405060708000b200128021441d88ec380004109200141186a28020028020c1182808080000021010c090b200128021441e18ec380004109200141186a28020028020c1182808080000021010c080b2002200041026a3602002002200128021441ea8ec380004118200141186a28020028020c118280808000003a000c20022001360208200241003a000d20024100360204200241046a200241848fc38000108d81808000210120022d000c21000240200128020022030d00200041ff017141004721010c080b41012101200041ff01710d072002280208210020034101470d0620022d000d41ff0171450d0620002d001c4104710d06410121012000280214418ca5c080004101200041186a28020028020c11828080800000450d060c070b200128021441948fc38000410f200141186a28020028020c1182808080000021010c060b200128021441a38fc38000410d200141186a28020028020c1182808080000021010c050b200128021441b08fc38000410d200141186a28020028020c1182808080000021010c040b200128021441bd8fc38000410b200141186a28020028020c1182808080000021010c030b200128021441c88fc380004110200141186a28020028020c1182808080000021010c020b200128021441d88fc380004112200141186a28020028020c1182808080000021010c010b2000280214418da5c080004101200041186a28020028020c1182808080000021010b200241106a24808080800020010b960301047f23808080800041d0076b22032480808080002003200136028004200341003602fc03200320023602f8030240024020022802042201450d0020022001417f6a36020420022002280200220141016a36020020012d0000220141024b0d00200341e8056a200341f8036a10f58c80800020032802e805450d0020032802e805210420034184046a200341e8056a41047241e40110848e8080001a024020032802f8032205280204220641204f0d00200341e8056a10bf878080000c010b2005200641606a36020420052005280200220641206a36020020034194026a20034184046a41e40110848e8080001a2004450d00200341047220034194026a41e40110848e8080001a20034181026a200641186a290000370000200341f9016a200641106a290000370000200341f1016a200641086a290000370000200320062900003700e901200320013a00e80120032004360200024020022802040d002000200341900210848e8080001a0c020b20004100360200200310bf878080000c010b200041003602000b200341d0076a2480808080000baa03010a7f23808080800041d0006b22042480808080004100210541002106024002402001280200450d0020012802040d012001417f360204200141086a21060b02400240024002402001280210450d0020012802140d012001417f360214200141186a21050b200141246a21074100210820060d01410021090c020b41dc90c38000108781808000000b2006280204210a200628020021090b2007280200210b200128022821072001280220210c0240024020050d000c010b2005280204210d200528020021080b200441c0006a200d360200200441386a200a3602002004410c6a41106a200741086a2900003702002004410c6a41186a200741106a2900003702002004412c6a200741186a2900003702002004200b3602102004200c36020c2004200836023c20042009360234200420072900003702142004410036024c200420033602482004200236024420002004410c6a20022003200441c4006a10c68c80800002402005450d002001200128021441016a3602140b02402006450d002001200128020441016a3602040b200441d0006a2480808080000f0b41ec90c38000108781808000000b840f020a7f027e23808080800041e0006b2202248080808000200241286a200110f48a808000200228022c21030240024002400240024002400240024020022802282204418080808078460d0020022802302101200241f091c380003602502002200136024c20022003360248410021052002410036023020024280808080103702282002200241286a36025c200241d4006a200241dc006a2001200241c8006a41f091c3800010858780800002402002280254418380c400460d0002402002280228450d00200228022c41002802c0a3c68000118080808000000b410021050c050b20022802282206418080808078460d04200228022c210741012105200228023022084102490d0320072d0000220141c000490d0102402001411874411875417f4a0d00410421050c040b4102210920072d0001220a413f714108742001410274200a4106767241ff01717221010c020b200041013a0000200020033602040c060b410121090b2008200941226a470d000240200141feff0071412e470d00410721050c010b200241c8006a20072009412072220510e883808000024002400240024002402002280250220a41014d0d00200228024c210a0240024002400240200820056b4102470d00200720056a2f0000200a2f0000470d00200720096a22092f0003210520092f0001210820092d0000210b2002413f6a2009411c6a280000360000200241386a200941156a290000370300200241306a2009410d6a2900003703002002200929000537032802402002280248450d00200a41002802c0a3c68000118080808000000b02402006450d00200741002802c0a3c68000118080808000000b2001413a490d08200141c00f4a0d02200141b7034a0d01200141416a0ece010808080808080807080808070707080807070807070707070707070707070707070707070707070707070807070707080707080707070807070707070707070807070707080707070707070707070707070707070707070707070707070707070707070707070707070707070708070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070807070807070707070707070707070708030b02402002280248450d00200a41002802c0a3c68000118080808000000b410321050c080b0240200141d5084a0d00024020014194064a0d00200141b803460d082001419a05470d070c080b2001419506460d07200141e307470d060c070b0240200141d0756a0e0a07060606060606060607000b200141d608460d06200141ec0b470d050c060b0240200141de364a0d00024020014196114a0d000240200141bf706a0e30080707070707070707070707070707070707070707070807080707070707070707070707080707070707070707070708000b200141d46f6a220741144b0d064101200774418180c10071450d060c070b0240200141a51f4a0d002001419711460d07200141ce11460d07200141851a470d060c070b0240200141f1284a0d00200141a61f460d07200141e222470d060c070b200141f228460d06200141ce2f470d050c060b0240200141cecd004a0d000240200141a1c5004a0d000240200141a1496a0e0708070707070708000b2001418a39460d07200141df39470d060c070b200141deba7f6a220741144d0d030c040b0240200141fade004a0d000240200141ddd9004a0d00200141cfcd00460d07200141b9ce00470d060c070b200141ded900460d06200141acdc00470d050c060b0240200141bbe6004a0d00200141fbde00460d062001419fdf00470d050c060b200141bce600460d05200141e9f200460d050c040b200141a403470d030c040b4102200a41ac93c38000109581808000000b4101200774418180c800710d020b200141f0c600460d01200141cfcc00460d010b02400240200141c4094a0d00200141a87f6a0e320202020102020101010102020202010101010101010101010101010101010101010101010101010102020101010101010202010b200141bb766a4102490d01200141fc756a4102490d01200141e26e6a4102490d010b200141bca77f6a417d4b0d00200141002f0194a1c68000460d00410221050c030b200241086a41176a2201200241286a41176a280000360000200241086a41106a2207200241286a41106a290300370300200241086a41086a200241286a41086a290300220c37030020022002290328220d370308200041046a20053b0100200041026a20083b01002000200b3a0001200041066a200d3701002000410e6a200c370100200041166a20072903003701002000411d6a2001280000360000410021010c030b2006450d00200741002802c0a3c68000118080808000000b0b200220013b015e200220053b015c200241346a4201370200410121012002410136022c200241bc93c3800036022820024189828080003602582002200241d4006a3602302002200241dc006a360254200241c8006a200241286a10b8808080002000200241c8006a10ea8a8080003602040b200020013a00002004450d00200341002802c0a3c68000118080808000000b200241e0006a2480808080000bc708020c7f027e2380808080004190026b220224808080800002400240200128020422034120490d002001200341606a220436020420012001280200220541206a2206360200200241c8006a41086a200541086a290000370300200241c8006a41106a200541106a290000370300200241c8006a41186a200541186a29000037030020022005290000370348200441c000490d002001200341a07f6a3602042001200541e0006a360200200241e8006a41086a200641086a2201290000370300200241e8006a41106a200641106a2205290000370300200241e8006a41186a200641186a2203290000370300200241e8006a41206a2204200641206a290000370300200241e8006a41286a200641286a290000370300200241e8006a41306a200641306a290000370300200241e8006a41386a200641386a29000037030020022006290000370368200241a8016a41186a2003290000370300200241a8016a41106a2005290000370300200241a8016a41086a2001290000370300200220062900003703a801200241ef016a200241a8016a10ea8280800020022d00ef01450d00200241ee016a2201200241ef016a41036a22052d00003a0000200241d0016a41086a2206200241ef016a410d6a2203290000370300200241d0016a410f6a2207200241ef016a41146a2208290000370000200241c8016a41046a2209200241ef016a41206a2d00003a0000200220022f00f0013b01ec012002200241ef016a41056a220a2900003703d0012002200241ef016a411c6a220b2800003602c801200241ef016a41046a220c2d0000210d200241ef016a200410ea8280800020022d00ef01450d00200241086a220420032900003703002002410f6a22032008290000370000200220022f00f0013b0118200220052d00003a001a2002200a290000370300200220022f01ec013b0140200220012d00003a0042200b350000210e200241ef016a41206a310000210f200c2d00002101200241286a410f6a22052007290000370000200241286a41086a22072006290300370300200220022903d001370328200241206a41046a220620092d00003a0000200220022802c801360220200041d9006a200241e0006a290300370000200041d1006a200241d8006a290300370000200041c9006a200241c8006a41086a290300370000200041c1006a2002290348370000200041046a200d3a0000200020022f01403b0001200041036a20022d00423a0000200041056a20022903283700002000410d6a2007290300370000200041146a2005290000370000200041206a20062d00003a00002000411c6a2002280220360000200041236a20022d001a3a0000200041216a20022f01183b0000200041246a20013a0000200041346a20032900003700002000412d6a2004290300370000200041256a2002290300370000200041c0006a200f3c00002000413c6a200e3e0000200041003a00000c010b200041013a00000b20024190026a2480808080000bf80501087f2380808080004180016b220224808080800041002d00fca3c680001a02400240412041002802c8a3c68000118180808000002203450d0020032000290040370000200341186a2204200041d8006a290000370000200341106a2205200041d0006a290000370000200341086a2206200041c8006a29000037000002402001280200200128020822076b411f4b0d0020012007412010b182808000200128020821070b2001280204220820076a22092003290000370000200941086a2006290000370000200941106a2005290000370000200941186a20042900003700002001200741206a2209360208200341002802c0a3c6800011808080800000200241086a200041086a290000370300200241106a200041106a290000370300200241186a200041186a290000370300200241206a22032000290020370300200241286a2207200041286a290000370300200241306a2204200041306a290000370300200241386a2205200041386a2900003703002002200029000037030041002d00fca3c680001a41c00041002802c8a3c68000118180808000002200450d0120002002290300370000200041386a2005290300370000200041306a2004290300370000200041286a2007290300370000200041206a2003290300370000200041186a2207200241186a290300370000200041106a2204200241106a290300370000200041086a2205200241086a2903003700000240200128020020096b413f4b0d002001200941c00010b18280800020012802042108200128020821090b200820096a22032000290000370000200341386a200041386a290000370000200341306a200041306a290000370000200341286a200041286a290000370000200341206a200041206a290000370000200341186a2007290000370000200341106a2004290000370000200341086a20052900003700002001200941c0006a360208200041002802c0a3c680001180808080000020024180016a2480808080000f0b4101412010b280808000000b410141c00010b280808000000ba60401067f23808080800041d0006b2204248080808000200141246a28020028020c210520012802202106200441186a41086a2207200341086a280200360200200420032902003703182004410c6a20062002200441186a20051186808080000002400240024002400240200428020c2205418080808078470d00200441186a41186a2203200241186a290000370300200441186a41106a2205200241106a2900003703002007200241086a2900003703002004200229000037031841002d00fca3c680001a413041002802c8a3c680001181808080000022010d014104413010b280808000000b20042802142106200428021021072001280210450d022001280214450d0141c493c38000108781808000000b2001418580808078360200200120042903183702042001410c6a200441206a290300370200200141146a20052903003702002001411c6a20032903003702002000418080808078360200200020013602040c020b2001417f360214200141186a28020021082001411c6a2802002109200441c4006a200241186a2900003702002004413c6a200241106a290000370200200441186a411c6a200241086a290000370200200420063602202004200736021c20044180808080783602182004200229000037022c200420032902003702242008200441186a200928020c118480808000002001200128021441016a3602140b2000200636020820002007360204200020053602000b200441d0006a2480808080000b9c0e05047f027e017f017e027f23808080800041d0056b2206248080808000200341086a280200210720032802042108024002400240024002400240024002400240024002400240024002400240200328020022090d0020070d01410121030c020b0240024020070d00410121030c010b2007417f4c0d0741002d00fca3c680001a200741002802c8a3c68000118180808000002203450d080b20032008200710848e8080001a41002104200721080c030b20074120460d012007417f4c0d0541002d00fca3c680001a200741002802c8a3c68000118180808000002203450d070b20032008200710848e808000210841002d00fca3c680001a413041002802c8a3c680001181808080000022030d024104413010b280808000000b200841026a2d000021072008410f6a290000210a200841176a290000210b20082f000021032008280003210c2008290007210d20064188026a411f6a2008411f6a2d00003a000020064188026a41176a200b37000020064188026a410f6a200a37000020064188026a41026a20073a00002006200d37008f022006200c36008b02200620033b018802200141246a280200210720012802202103200641306a41086a200441086a280200360200200620042902003703302006410c6a200320064188026a200641306a200728020c11868080800000200628020c2207418080808078460d08200641f0036a41086a20064188026a41086a290100370300200641f0036a41106a20064188026a41106a290100370300200641f0036a41186a20064188026a41186a29010037030020062006290188023703f0032006280214210820062802102103410121040b200641156a200641f0036a41086a220e2903003700002006411d6a20064180046a220c290300370000200641256a20064188046a290300370000200620043a000c200620062903f00337000d200641f0036a2003200810c28c8080002006410d6a210420062802f003220f4105470d0120064188026a41086a200c2802003602002006200e2902003703880220062802f403210802402007450d00200341002802c0a3c68000118080808000000b200641f0036a41186a22032002200420091b220741186a290000370300200641f0036a41106a2202200741106a290000370300200641f0036a41086a2201200741086a290000370300200620072900003703f00341002d00fca3c680001a413041002802c8a3c680001181808080000022070d054104413010b280808000000b2003200736020c2003200836020820032007360204200341888080807836020020032002290000370010200341186a200241086a290000370000200341206a200241106a290000370000200341286a200241186a2900003700000c070b200641e0036a41086a2202200c280200360200200620062902f8033703e00320062802f403210c20064194026a20064184046a41c80110848e8080001a20064188026a41086a2002280200360200200620062903e00337038802200641306a20064188026a41d40110848e8080001a20090d042005450d042001280210450d04024020012802140d002001417f360214200141186a28020021022001411c6a2802002109200641fc036a2008360200200641f0036a41086a200336020020064198046a200441186a29000037020020064190046a200441106a290000370200200641f0036a41186a200441086a2900003702002006428280808088808080807f3702f00320062004290000370280042002200641f0036a200928020c118480808000002001200128021441016a3602140c050b41d493c38000108781808000000b10ae80808000000b4101200710b280808000000b4101200710b280808000000b200720083602002007200629038802370204200720062903f0033702102007410c6a20064188026a41086a280200360200200741186a2001290300370200200741206a2002290300370200200741286a200329030037020020004105360200200020073602040c030b200041086a200641306a41d40110848e8080001a200020073602dc01200020083602e401200020033602e0012000200c3602042000200f3602002000200629000c3700e801200041f0016a2006410c6a41086a290000370000200041f8016a2006411c6a29000037000020004180026a200641246a29000037000020004188026a2006412c6a2d00003a00000c020b20042d000821082004280204210741002d00fca3c680001a413041002802c8a3c6800011818080800000210302400240024020070d00200841ff0171450d010b418580808078210720030d014104413010b280808000000b418480808078210720030d004104413010b280808000000b2003200736020020032006290188023700042003410c6a20064190026a290100370000200341146a20064198026a2901003700002003411c6a200641a0026a2901003700000b20004105360200200020033602040b200641d0056a2480808080000bb00101017f23808080800041106b2201248080808000200142888080808001370200200142808080808001370208200041c4006a200110fa86808000200041106a42e6ed8d82cc91adcb05370300200042dbd791d5c2919eaecd00370308200041c0006a410036020020004280808080c000370338200041d8006a410036020020004280808080c000370350200041c000360220200041c880808000360218200041033a0000200141106a2480808080000b2a00200041003b01102000420037030820004280c2d72f42e097e1c29b0120012d00104103491b3703000bec0c01027f23808080800041106b22022480808080000240024002400240024002400240024002400240024002400240024002400240024002400240024020002d00000e0e000102030405060708090a0b0c0d000b2002200041046a36020020022001280214418ea2c380004105200141186a28020028020c118280808000003a000c20022001360208200241003a000d20024100360204200241046a20024194a2c38000108d81808000210120022d000c21000240200128020022010d00200041ff017141004721030c130b41012103200041ff01710d122002280208210020014101470d1120022d000d41ff0171450d1120002d001c4104710d11410121032000280214418ca5c080004101200041186a28020028020c11828080800000450d110c120b200128021441a4a2c38000410c200141186a28020028020c1182808080000021030c110b200128021441b0a2c380004109200141186a28020028020c1182808080000021030c100b2002200041046a3602002002200128021441b9a2c380004106200141186a28020028020c118280808000003a000c20022001360208200241003a000d20024100360204200241046a200241c0a2c38000108d81808000210120022d000c21000240200128020022010d00200041ff017141004721030c100b41012103200041ff01710d0f2002280208210020014101470d0d20022d000d41ff0171450d0d20002d001c4104710d0d410121032000280214418ca5c080004101200041186a28020028020c11828080800000450d0d0c0f0b200128021441d0a2c380004111200141186a28020028020c1182808080000021030c0e0b200128021441e1a2c38000410b200141186a28020028020c1182808080000021030c0d0b200128021441eca2c380004110200141186a28020028020c1182808080000021030c0c0b410121032002200041016a3602002002200128021441fca2c380004105200141186a28020028020c118280808000003a000c20022001360208200241003a000d20024100360204200241046a20024184a3c38000108d81808000210120022d000c21000240200128020022010d00200041ff017141004721030c0c0b200041ff01710d0b2002280208210020014101470d0820022d000d41ff0171450d0820002d001c4104710d08410121032000280214418ca5c080004101200041186a28020028020c11828080800000450d080c0b0b410121032002200041016a360200200220012802144194a3c38000410a200141186a28020028020c118280808000003a000c20022001360208200241003a000d20024100360204200241046a200241a0a3c38000108d81808000210120022d000c21000240200128020022010d00200041ff017141004721030c0b0b200041ff01710d0a2002280208210020014101470d0620022d000d41ff0171450d0620002d001c4104710d06410121032000280214418ca5c080004101200041186a28020028020c11828080800000450d060c0a0b410121032002200041016a3602002002200128021441b0a3c38000410d200141186a28020028020c118280808000003a000c20022001360208200241003a000d20024100360204200241046a200241c0a3c38000108d81808000210120022d000c21000240200128020022010d00200041ff017141004721030c0a0b200041ff01710d092002280208210020014101470d0420022d000d41ff0171450d0420002d001c4104710d04410121032000280214418ca5c080004101200041186a28020028020c11828080800000450d040c090b200128021441d0a3c380004109200141186a28020028020c1182808080000021030c080b200128021441d9a3c38000410a200141186a28020028020c1182808080000021030c070b200128021441e3a3c38000410b200141186a28020028020c1182808080000021030c060b200128021441eea3c38000410e200141186a28020028020c1182808080000021030c050b2000280214418da5c080004101200041186a28020028020c1182808080000021030c040b2000280214418da5c080004101200041186a28020028020c1182808080000021030c030b2000280214418da5c080004101200041186a28020028020c1182808080000021030c020b2000280214418da5c080004101200041186a28020028020c1182808080000021030c010b2000280214418da5c080004101200041186a28020028020c1182808080000021030b200241106a24808080800020030b840601067f23808080800041306b220124808080800020014106360204200141a599c3800036020041002d00fca3c680001a024002400240410841002802c8a3c68000118180808000002202450d00200241a599c38000360200200241046a410636020041a599c38000410610d782808000450d0141002d00fca3c680001a41c00041002802c8a3c68000118180808000002203450d02200342d1c5efcdcd82cde1ff00370308200341ac99c38000360220200341938280800036021820034101360204200341ab99c38000360200200341306a42c0969aec91e181fcf200370300200341286a42d7a7fbff94a5afcaf800370300200341106a429ccab49c93e2e495cf00370300200341386a419482808000360200200341246a4101360200200141023602142001200336020c2001200341c0006a36021820012003360210200141246a2001410c6a10fa86808000200128022c210420012802282103200128022421052001410036021420014280808080c00037020c200141246a2001410c6a41ad99c38000410210a08b8080002001200141246a41af99c38000410310ce8b8080002001200128020036021420012001280204220636020c20012006200128020841246c6a36021820012006360210200141246a2001410c6a10fb86808000200120053602142001200336020c2001200320044105746a36021820012003360210200041c4006a2001410c6a10fa86808000200141176a200141246a41086a2802003600002000413c6a2002ad4280808080108437020020004101360238200041013a0000200041d8006a410036020020004280808080c0003703502001200129022437000f2000200129000c370001200041086a200141136a290000370000200141306a2480808080000f0b4104410810b280808000000b200241002802c0a3c6800011808080800000200141186a42013702002001410236021020014180ddc1800036020c200141b4808080003602282001200141246a360214200120013602242001410c6a4190ddc1800010f680808000000b410841c00010b280808000000b800601067f23808080800041306b220124808080800020014106360204200141a599c3800036020041002d00fca3c680001a024002400240410841002802c8a3c68000118180808000002202450d00200241a599c38000360200200241046a410636020041a599c38000410610d782808000450d0141002d00fca3c680001a41c00041002802c8a3c68000118180808000002203450d022003429198b9e48fc6c3ad1d370308200341ac99c38000360220200341958280800036021820034101360204200341ab99c38000360200200341306a42ab8ad7e1bb97ae9f51370300200341286a42f2f9a5a49996c5e032370300200341106a42f69a89928aa399ea00370300200341386a419682808000360200200341246a4101360200200141023602142001200336020c2001200341c0006a36021820012003360210200141246a2001410c6a10fa86808000200128022c210420012802282103200128022421052001410036021420014280808080c00037020c200141246a2001410c6a41ad99c380004102109a8b8080002001200141246a41af99c38000410310fc8a8080002001200128020036021420012001280204220636020c20012006200128020841246c6a36021820012006360210200141246a2001410c6a10fb86808000200120053602142001200336020c2001200320044105746a36021820012003360210200041c4006a2001410c6a10fa86808000200141176a200141246a41086a2802003600002000413c6a2002ad4280808080108437020020004101360238200041013a0000200041d8006a410036020020004280808080c0003703502001200129022437000f2000200129000c370001200041086a200141136a290000370000200141306a2480808080000f0b4104410810b280808000000b200241002802c0a3c6800011808080800000200141186a42013702002001410236021020014180ddc1800036020c200141b4808080003602282001200141246a360214200120013602242001410c6a4190ddc1800010f680808000000b410841c00010b280808000000b840601067f23808080800041306b220124808080800020014106360204200141a599c3800036020041002d00fca3c680001a024002400240410841002802c8a3c68000118180808000002202450d00200241a599c38000360200200241046a410636020041a599c38000410610d782808000450d0141002d00fca3c680001a41c00041002802c8a3c68000118180808000002203450d02200342d1c5efcdcd82cde1ff00370308200341ac99c38000360220200341938280800036021820034101360204200341ab99c38000360200200341306a42efc9c9edb5e7b3a6c700370300200341286a42acf6debeefe0d9c8d300370300200341106a429ccab49c93e2e495cf00370300200341386a41bd80808000360200200341246a4101360200200141023602142001200336020c2001200341c0006a36021820012003360210200141246a2001410c6a10fa86808000200128022c210420012802282103200128022421052001410036021420014280808080c00037020c200141246a2001410c6a41ad99c38000410210a08b8080002001200141246a41af99c38000410310898b8080002001200128020036021420012001280204220636020c20012006200128020841246c6a36021820012006360210200141246a2001410c6a10fb86808000200120053602142001200336020c2001200320044105746a36021820012003360210200041c4006a2001410c6a10fa86808000200141176a200141246a41086a2802003600002000413c6a2002ad4280808080108437020020004101360238200041013a0000200041d8006a410036020020004280808080c0003703502001200129022437000f2000200129000c370001200041086a200141136a290000370000200141306a2480808080000f0b4104410810b280808000000b200241002802c0a3c6800011808080800000200141186a42013702002001410236021020014180ddc1800036020c200141b4808080003602282001200141246a360214200120013602242001410c6a4190ddc1800010f680808000000b410841c00010b280808000000b800601067f23808080800041306b220124808080800020014106360204200141a599c3800036020041002d00fca3c680001a024002400240410841002802c8a3c68000118180808000002202450d00200241a599c38000360200200241046a410636020041a599c38000410610d782808000450d0141002d00fca3c680001a41c00041002802c8a3c68000118180808000002203450d02200342d9adfaebb1c192ed50370308200341ac99c38000360220200341978280800036021820034101360204200341ab99c38000360200200341306a42ab8ad7e1bb97ae9f51370300200341286a42f2f9a5a49996c5e032370300200341106a42fb8387e2d6839cd949370300200341386a419682808000360200200341246a4101360200200141023602142001200336020c2001200341c0006a36021820012003360210200141246a2001410c6a10fa86808000200128022c210420012802282103200128022421052001410036021420014280808080c00037020c200141246a2001410c6a41ad99c380004102108a8b8080002001200141246a41af99c38000410310fc8a8080002001200128020036021420012001280204220636020c20012006200128020841246c6a36021820012006360210200141246a2001410c6a10fb86808000200120053602142001200336020c2001200320044105746a36021820012003360210200041c4006a2001410c6a10fa86808000200141176a200141246a41086a2802003600002000413c6a2002ad4280808080108437020020004101360238200041013a0000200041d8006a410036020020004280808080c0003703502001200129022437000f2000200129000c370001200041086a200141136a290000370000200141306a2480808080000f0b4104410810b280808000000b200241002802c0a3c6800011808080800000200141186a42013702002001410236021020014180ddc1800036020c200141b4808080003602282001200141246a360214200120013602242001410c6a4190ddc1800010f680808000000b410841c00010b280808000000bac0401097f23808080800041306b220124808080800020012000200010eb8780800002400240024020012802102202418080808078460d002001280224210320012802202104200128021c210520012802142106024020012802182200450d002000410171210741002108024020004101460d002000417e7121092006210041002108034002402000280200450d00200041046a28020041002802c0a3c68000118080808000000b02402000410c6a280200450d00200041106a28020041002802c0a3c68000118080808000000b200041186a21002009200841026a2208470d000b0b2007450d0020062008410c6c6a2200280200450d00200028020441002802c0a3c68000118080808000000b02402002450d00200641002802c0a3c68000118080808000000b02402003450d002003410171210241002108024020034101460d002003417e7121092004210041002108034002402000280200450d00200041046a28020041002802c0a3c68000118080808000000b02402000410c6a280200450d00200041106a28020041002802c0a3c68000118080808000000b200041186a21002009200841026a2208470d000b0b2002450d0020042008410c6c6a2200280200450d00200028020441002802c0a3c68000118080808000000b2005450d01200441002802c0a3c68000118080808000000c010b20012d000041ff017122004102460d0020012f000141087421080c010b41002108410221000b200141306a24808080800020082000720bfb0801087f23808080800041e0006b22032480808080002003200236020c02404100280284a4c680004105470d00200341988280800036025820032003410c6a3602544100280290a1c680002102410028028ca1c6800021044100280280a4c680002105200341c8006a4201370200200341c0006a4101360200200341386a4115360200200341346a41a4a9c38000360200200341286a41c0a7c38000ad4280808080b00e843702002003411c6a41b9a9c38000ad4280808080d00684370200200341c4006a200341d4006a3602002003419ca9c3800036023c20034105360230200341003602242003410036021820034281808080901c370210200441ecf2c08000200541024622051b200341106a200241d4f2c0800020051b28021011848080800000200328020c21020b02400240024002400240024020022802002202410c4b0d004101200274418831710d010b2000418080808078360210200041003b01000c010b41002d00fca3c680001a410c41002802c8a3c68000118180808000002204450d014101210202400240024002400240024002400240024002400240200328020c2205280200417f6a0e0c080600010203090409050505080b417f200541186a28020041046a220241012005410c6a28020041056a2005280204418080808078461b6a220620062002491b21020c060b417f200541186a2802002005410c6a28020041046a22026a41046a220620062002491b21020c050b2005410c6a28020041046a21020c040b2005410c6a28020041046a21020c030b410921020c040b410521020c030b2005410c6a28020041046a21020b4101210641002107200241016a2202450d022002417f4a0d0110ae80808000000b41d10021020b41002d00fca3c680001a200241002802c8a3c68000118180808000002206450d03200221070b2003200636021420032007360210200341003602182005200341106a10ba8880800020032802102102200341106a2003280214220520032802184100280298a3c680001185808080000002402002450d00200541002802c0a3c68000118080808000000b2003410036025c200342808080801037025441002d00fca3c680001a412041002802c8a3c68000118180808000002202450d0320022003290010370000200241186a2207200341106a41186a290000370000200241106a2208200341106a41106a290000370000200241086a2209200341106a41086a290000370000200341d4006a4100412010b1828080002003280258200341d4006a41086a2206280200220a6a22052002290000370000200541086a2009290000370000200541106a2008290000370000200541186a20072900003700002006200a41206a360200200241002802c0a3c6800011808080800000200441086a20062802003602002004200329025437020020004280808080c000370310200041013a0028200041013602242000200436022020004280808080103703182000427f370308200042003703000b200341e0006a2480808080000f0b4104410c10b280808000000b4101200210b280808000000b4101412010b280808000000bfd0201017f23808080800041c0006b22042480808080000240024020012d00780d0020012d00790d01200441386a41a08ac480003602002004412c6a4100360200200442003702242004410036021c20044200370214200420013602342004200141386a36023c200441086a200441146a2002200310dd87808000024002402004280208418180808078460d0020002004290208370200200041086a200441086a41086a2802003602000c010b0240024002400240200428020c220128020041fcffffff076a2203410320034105491b0e0403030102000b2001280204450d02200141086a28020041002802c0a3c68000118080808000000c020b2001280204450d01200141086a28020041002802c0a3c68000118080808000000c010b200110ed878080000b200141002802c0a3c680001180808080000020004181808080783602000b200441c0006a2480808080000f0b41b299c38000410f41b89dc3800010f880808000000b41b299c38000410f41b49ac3800010f880808000000bc50101027f024002400240024020002802002201418080808078732202410220024104491b0e03030301000b0240024002402000280204220028020041fcffffff076a2202410320024105491b0e0404040102000b2000280204450d03200041086a28020041002802c0a3c68000118080808000000c030b2000280204450d02200041086a28020041002802c0a3c68000118080808000000c020b200010ed878080000c010b2001450d01200028020421000b200041002802c0a3c68000118080808000000b0b170041b299c38000410f41b49ac3800010f880808000000b970601087f23808080800041106b2202248080808000024002400240024020002802000e03000102000b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41003a00002001200341016a2204360208200028020421050240200128020020046b41034b0d0020012004410410b182808000200128020821040b2001200441046a2203360208200128020420046a20053600000c020b0240200128020020012802082204470d0020012004410110b182808000200128020821040b2001200441016a2203360208200128020420046a41013a00000c010b0240200128020020012802082204470d0020012004410110b182808000200128020821040b2001200441016a2203360208200128020420046a41023a00000b0240024020002d00084116470d00024020012802002003470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a41003a0000200041106a200110a08a8080000c010b200041086a2104024020012802002003470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a41033a00002004200110a88c8080000b200041dc006a28020021032002200041e0006a28020022003602082002200241086a36020c2002410c6a200110c08a808000024002402000450d0020004105742106034041002d00fca3c680001a412041002802c8a3c68000118180808000002200450d0220002003290000370000200041186a2207200341186a290000370000200041106a2208200341106a290000370000200041086a2209200341086a29000037000002402001280200200128020822056b411f4b0d0020012005412010b182808000200128020821050b200341206a2103200128020420056a22042000290000370000200441086a2009290000370000200441106a2008290000370000200441186a20072900003700002001200541206a360208200041002802c0a3c6800011808080800000200641606a22060d000b0b200241106a2480808080000f0b4101412010b280808000000bad0b04067f017e027f017e23808080800041d0006b2201248080808000200141286a419f9bc38000410b41aa9bc38000410c418097c38000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041c00041002802c8a3c68000118180808000002202450d00200242a5e9e3ab9e929adc2c370308200241bb9bc38000360220200241ef8080800036021820024105360204200241b69bc38000360200200241306a42e1be86f0e3e6afc202370300200241286a42c4daf0e7d4cf86cca87f370300200241106a4293888c8f89fdc6ec9e7f370300200241386a419982808000360200200241246a410b36020020014102360248200120023602402001200241c0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a200141106a410c6a220241086a2802003602002001200229020037030020012802102103200128021421042001280218210520012802282106200129022c2107200141106a41086a22084100360200200142808080808001370210200141106a410010a4868080002001280214200828020041386c6a2202420437022c2002420537022420024185e4c480003602202002410536021c20024180e4c48000360218200241ef8080800036021020024293888c8f89fdc6ec9e7f370308200242a5e9e3ab9e929adc2c370300200141c0006a41086a2209200828020041016a220236020020012001290210220a37034002402002200aa7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c2002420837022420024193e4c480003602202002410936021c2002419be4c48000360218200241b580808000360210200242e88488d0c0e3aebc13370308200242d7c9cb8fc1cf97db3e3703002008200928020041016a220236020020012001290340220a37031002402002200aa7470d00200141106a200210a486808000200128021821020b2001280214200241386c6a2202420437022c2002420837022420024193e4c480003602202002410936021c2002418ae4c48000360218200241b580808000360210200242e88488d0c0e3aebc13370308200242d7c9cb8fc1cf97db3e370300200141c0006a41086a2208200141106a41086a220928020041016a220236020020012001290310220a37034002402002200aa7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c2002420837022420024193e4c480003602202002410b36021c200241b3e4c48000360218200241b580808000360210200242e88488d0c0e3aebc13370308200242d7c9cb8fc1cf97db3e3703002009200828020041016a220236020020012001290340220a37031002402002200aa7470d00200141106a200210a486808000200128021821020b2001280214200241386c6a2202420437022c2002420b370224200241a8e4c480003602202002410436021c200241a4e4c480003602182002419982808000360210200242e1be86f0e3e6afc202370308200242c4daf0e7d4cf86cca87f370300200128021821082001280214210220012001280210360248200120023602402001200236024420012002200841386c6a41386a36024c200141346a200141c0006a10f9868080002006418080808078460d012001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002006360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841c00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000beb0804067f017e027f017e23808080800041d0006b2201248080808000200141286a41c69bc38000410b41aa9bc38000410c418097c38000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041c00041002802c8a3c68000118180808000002202450d002002428efca59582e3caf618370308200241ab99c380003602202002419a8280800036021820024101360204200241ac99c38000360200200241306a42ab8bffbed784ffa5937f370300200241286a42c194a6a793ccc3a857370300200241106a42988ac9c0f3f1b2b0b57f370300200241386a41f581808000360200200241246a410136020020014102360248200120023602402001200241c0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a200141106a410c6a220241086a2802003602002001200229020037030020012802102103200128021421042001280218210520012802282106200129022c2107200141106a41086a22084100360200200142808080808001370210200141106a410010a4868080002001280214200828020041386c6a2202420437022c20024205370224200241d5e4c480003602202002410536021c200241d0e4c480003602182002419b82808000360210200242dd9fc4e2a4bae882d400370308200242fb9bf4d1a5ccd7cbed00370300200141c0006a41086a2209200828020041016a220236020020012001290210220a37034002402002200aa7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c20024201370224200241c3e4c480003602202002410536021c200241bee4c480003602182002419a82808000360210200242988ac9c0f3f1b2b0b57f3703082002428efca59582e3caf6183703002008200928020041016a220236020020012001290340220a37031002402002200aa7470d00200141106a200210a486808000200128021821020b2001280214200241386c6a2202420437022c20024206370224200241cae4c480003602202002410636021c200241c4e4c480003602182002419c82808000360210200242b6e5c682fa82cdd4dc00370308200242b49ee2c5eaeedcf10c370300200128021821082001280214210220012001280210360248200120023602402001200236024420012002200841386c6a41386a36024c200141346a200141c0006a10f9868080002006418080808078460d012001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002006360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841c00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000bdd0604067f017e017f017e23808080800041d0006b2201248080808000200141106a41186a41d19bc38000411841aa9bc38000410c418097c38000410010d882808000200141206a42043702002001420037021820014280808080800137021041002d00fca3c680001a02400240412041002802c8a3c68000118180808000002202450d002002410036021820024101360204200241ab99c3800036020020014101360248200120023602402001200241206a36024c20012002360244200141106a200141c0006a10fa86808000200141086a200141106a410c6a220241086a2802003602002001200229020037030020012802102103200128021421042001280218210520012802282106200129022c2107200141106a41086a22084100360200200142808080808001370210200141106a410010a4868080002001280214200828020041386c6a2202420437022c20024207370224200241e3e4c480003602202002410936021c200241dae4c48000360218200241f581808000360210200242ab8bffbed784ffa5937f370308200242c194a6a793ccc3a857370300200141c0006a41086a200828020041016a2202360200200120012902102209370340024020022009a7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c20024204370224200241f7e4c480003602202002410d36021c200241eae4c48000360218200241888180800036021020024298848fa1dab08ba174370308200242febac4ad81b6fafcb37f370300200128024821082001280244210220012001280240360248200120023602402001200236024420012002200841386c6a41386a36024c200141346a200141c0006a10f9868080002006418080808078460d012001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002006360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b4108412010b280808000000b41a8d8c480004111419cd9c4800010a181808000000be80501047f23808080800041e0006b2202248080808000200241346a41f9a6c48000410641002802a0a3c6800011858080800000200241346a41106a220341899fc38000410d41002802a0a3c6800011858080800000200241086a41186a200241346a41186a290000370300200241086a41106a2003290000370300200241086a41086a200241346a41086a2900003703002002200229003437030820022001360254200241d8006a200241d4006a410441002802a8a3c68000118580808000002002200241d4006a41046a3602402002200241d8006a41086a3602382002200241d4006a36023c2002200241d8006a360234200241286a200241346a108182808000024002400240024002402002280230220341206a22040d002002410036023c20024280808080103702340c010b2004417f4c0d024100210541002d00fca3c680001a200441002802c8a3c68000118180808000002201450d032002410036023c200220013602382002200436023420034160490d010b200241346a4100412010ab8680800020022802382101200228023c21050b200120056a22042002290308370000200441186a200241086a41186a290300370000200441106a200241086a41106a290300370000200441086a200241086a41086a2903003700002002200541206a220436023c200228022c21050240200228023420046b20034f0d00200241346a2004200310ab8680800020022802382101200228023c21040b200120046a2005200310848e8080001a200420036a21032002280234210402402002280228450d00200541002802c0a3c68000118080808000000b200241346a2001200310e988808000024002402002280234418080808078470d002000410036020820004280808080103702000c010b20002002290234370200200041086a200241346a41086a2802003602000b02402004450d00200141002802c0a3c68000118080808000000b200241e0006a2480808080000f0b10ae80808000000b4101200410b280808000000bb108050b7f017e037f027e017f2380808080004190016b2202248080808000200241086a41f9a6c48000410641002802a0a3c6800011858080800000200241086a41106a220341ea9ec38000410741002802a0a3c6800011858080800000200241d0006a41186a200241086a41186a290000370300200241d0006a41106a2003290000370300200241d0006a41086a200241086a41086a2900003703002002200229000837035041002d00fca3c680001a024002400240412041002802c8a3c68000118180808000002204450d0020042001290000370000200441186a200141186a290000370000200441106a200141106a290000370000200441086a200141086a290000370000200241086a200441204100280290a3c68000118580808000002002200441206a36028c01200220043602880120022003360284012002200241086a36028001200241f4006a20024180016a108182808000200441002802c0a3c6800011808080800000024002400240200228027c220141206a22030d002002410036021020024280808080103702080c010b2003417f4c0d034100210541002d00fca3c680001a200341002802c8a3c68000118180808000002204450d04200241003602102002200436020c2002200336020820014160490d010b200241086a4100412010ab86808000200228020c2104200228021021050b200420056a22032002290350370000200341186a200241d0006a41186a290300370000200341106a200241d0006a41106a290300370000200341086a200241d0006a41086a2903003700002002200541206a2203360210200228027821050240200228020820036b20014f0d00200241086a2003200110ab86808000200228020c2104200228021021030b200420036a2005200110848e8080001a200320016a21012002280208210302402002280274450d00200541002802c0a3c68000118080808000000b200241086a2004200110e4888080000240024020022903084200520d00410521010c010b200241d0006a41086a2205200241306a2206290300370300200241d0006a41106a2207200241386a22082903003703002002200241286a22092903003703500240200241c4006a220a280200220b0d00410521010c010b200241086a41106a220c290300210d200241c0006a220e280200210f200241c8006a2210290300211120022903102112200241206a22132013290300370300200c200d3703002009200229035037030020102011370300200a200b3602002006200529030037030020082007290300370300200e200f41016a2205417f20051b3602002002201237031020024201370308200241086a41086a2004200110f587808000410e21010b200020013a000002402003450d00200441002802c0a3c68000118080808000000b20024190016a2480808080000f0b4101412010b280808000000b10ae80808000000b4101200310b280808000000b980301047f23808080800041106b220324808080800041002d00fca3c680001a0240413c41002802c8a3c68000118180808000002204450d00200320043602082003413c360204200420002903003700002003410836020c200028023021054108210402402003280204417c714108470d00200341046a4108410410b182808000200328020c21040b200328020820046a20053600002003200441046a220436020c200028023421050240200328020420046b41034b0d00200341046a2004410410b182808000200328020c21040b200041086a2106200328020820046a20053600002003200441046a220436020c200028023821000240200328020420046b41034b0d00200341046a2004410410b182808000200328020c21040b200328020820046a20003600002003200441046a36020c2006200341046a10848d808000200328020421002001200220032802082204200328020c41002802e0a1c680001186808080000002402000450d00200441002802c0a3c68000118080808000000b200341106a2480808080000f0b4101413c10b280808000000bc20802067f037e2380808080004190016b2202248080808000200241086a41f9a6c48000410641002802a0a3c6800011858080800000200241086a41106a220341ea9ec38000410741002802a0a3c6800011858080800000200241d0006a41186a200241086a41186a290000370300200241d0006a41106a2003290000370300200241d0006a41086a200241086a41086a2900003703002002200229000837035041002d00fca3c680001a024002400240412041002802c8a3c68000118180808000002204450d0020042001290000370000200441186a200141186a290000370000200441106a200141106a290000370000200441086a200141086a290000370000200241086a200441204100280290a3c68000118580808000002002200441206a36028c01200220043602880120022003360284012002200241086a36028001200241f4006a20024180016a108182808000200441002802c0a3c6800011808080800000024002400240200228027c220141206a22030d002002410036021020024280808080103702080c010b2003417f4c0d034100210541002d00fca3c680001a200341002802c8a3c68000118180808000002204450d04200241003602102002200436020c2002200336020820014160490d010b200241086a4100412010ab86808000200228020c2104200228021021050b200420056a22032002290350370000200341186a200241d0006a41186a290300370000200341106a200241d0006a41106a290300370000200341086a200241d0006a41086a2903003700002002200541206a2203360210200228027821050240200228020820036b20014f0d00200241086a2003200110ab86808000200228020c2104200228021021030b200420036a2005200110848e8080001a200320016a21012002280208210602402002280274450d00200541002802c0a3c68000118080808000000b200241086a2004200110e4888080000240024020022903084200520d00410521030c010b200241d8006a200241306a290300370300200241d0006a41106a200241386a2903003703002002200241286a2903003703500240200241c4006a28020022050d00410521030c010b41062103200241c0006a2802002207410f4b0d00200241086a41106a2903002108200241c8006a29030021092002290310210a200241206a200241206a290300370300200241086a41106a2008370300200241286a2002290350370300200241c8006a2009370300200241c4006a2005360200200241c0006a200741016a360200200241306a200241d0006a41086a290300370300200241386a200241d0006a41106a2903003703002002200a37031020024201370308200241086a41086a2004200110f587808000410e21030b200020033a000002402006450d00200441002802c0a3c68000118080808000000b20024190016a2480808080000f0b4101412010b280808000000b10ae80808000000b4101200310b280808000000be60e01127f23808080800041e0016b220324808080800020034190016a41f9a6c48000410641002802a0a3c680001185808080000020034190016a41106a220441ea9ec38000410741002802a0a3c6800011858080800000200341086a41186a20034190016a41186a290000370300200341086a41106a2004290000370300200341086a41086a20034190016a41086a290000370300200320032900900137030841002d00fca3c680001a024002400240412041002802c8a3c68000118180808000002205450d0020052001290000370000200541186a200141186a290000370000200541106a200141106a290000370000200541086a200141086a29000037000020034190016a200541204100280290a3c68000118580808000002003200541206a36026c2003200536026820032004360264200320034190016a360260200341d4006a200341e0006a108182808000200541002802c0a3c6800011808080800000024002400240200328025c220141206a22040d0020034100360298012003428080808010370290010c010b2004417f4c0d034100210641002d00fca3c680001a200441002802c8a3c68000118180808000002205450d0420034100360298012003200536029401200320043602900120014160490d010b20034190016a4100412010ab86808000200328029401210520032802980121060b200520066a22042003290308370000200441186a200341086a41186a290300370000200441106a200341086a41106a290300370000200441086a200341086a41086a2903003700002003200641206a22043602980120032802582106024020032802900120046b20014f0d0020034190016a2004200110ab86808000200328029401210520032802980121040b200520046a2006200110848e8080001a200420016a2104200328029001210702402003280254450d00200641002802c0a3c68000118080808000000b200341086a2005200410e488808000200328020821012003420037030802400240024002400240024020014101470d00200328024c210820032802482109200328024421062003280240210a200341e0006a41286a220b200341086a41086a220141286a220c290300370300200341e0006a41206a220d200141206a220e290300370300200341e0006a41186a220f200141186a2210290300370300200341e0006a41106a2211200141106a2212290300370300200341e0006a41086a200141086a2903003703002003200129030037036002400240024020060e020001020b0240417f4100280284a4c680002206410147200641014b1b2206417f460d00200641ff01710d010b4100280290a1c680002106410028028ca1c6800021134100280280a4c680002114200341c8016a4200370200200341c4016a418097c38000360200200341c0016a4101360200200341b8016a410f360200200341b4016a41a89cc38000360200200341a8016a41c49ac38000ad4280808080b00b843702002003419c016a41aa9bc38000ad4280808080c00184370200200341f09cc380003602bc01200341013602b001200341003602a40120034100360298012003428180808090bd0137029001201341ecf2c08000201441024622141b20034190016a200641d4f2c0800020141b280210118480808000000b200a200972450d03200a0d02410121060b20012003290360370300200c200b290300370300200e200d2903003703002010200f29030037030020122011290300370300200141086a200341e0006a41086a2903003703002003200836024c200320093602482003200a3602402003420137030820032006417f6a36024420012005200410f587808000410121010c040b0240417f4100280284a4c680002201410147200141014b1b2201417f460d00200141ff01710d030b4100280290a1c680002101410028028ca1c6800021064100280280a4c680002102200341c8016a4200370200200341c4016a418097c38000360200200341c0016a4101360200200341b8016a410f360200200341b4016a41a89cc38000360200200341a8016a41c49ac38000ad4280808080b00b843702002003419c016a41aa9bc38000ad4280808080c00184370200200341b09dc380003602bc01200341013602b001200341003602a401200341003602980120034281808080b0c00137029001200641ecf2c08000200241024622021b20034190016a200141d4f2c0800020021b280210118480808000000c020b410421040c030b20034199016a2002290000370000200341b1016a200241186a290000370000200341a9016a200241106a290000370000200341a1016a200241086a290000370000200341043a009801200341163a00900120034190016a108e8a8080000b410021012005200441002802a0a1c68000118480808000000b410e21040b200020013a0001200020043a000020002003290190013701022000410a6a20034198016a290100370100200041126a200341a0016a2f01003b010002402007450d00200541002802c0a3c68000118080808000000b200341e0016a2480808080000f0b4101412010b280808000000b10ae80808000000b4101200410b280808000000b800801047f2380808080004190016b2202248080808000200241086a41f9a6c48000410641002802a0a3c6800011858080800000200241086a41106a220341ea9ec38000410741002802a0a3c6800011858080800000200241d0006a41186a200241086a41186a290000370300200241d0006a41106a2003290000370300200241d0006a41086a200241086a41086a2900003703002002200229000837035041002d00fca3c680001a024002400240412041002802c8a3c68000118180808000002204450d0020042001290000370000200441186a200141186a290000370000200441106a200141106a290000370000200441086a200141086a290000370000200241086a200441204100280290a3c68000118580808000002002200441206a36028c01200220043602880120022003360284012002200241086a36028001200241f4006a20024180016a108182808000200441002802c0a3c6800011808080800000024002400240200228027c220141206a22030d002002410036021020024280808080103702080c010b2003417f4c0d034100210541002d00fca3c680001a200341002802c8a3c68000118180808000002204450d04200241003602102002200436020c2002200336020820014160490d010b200241086a4100412010ab86808000200228020c2104200228021021050b200420056a22032002290350370000200341186a200241d0006a41186a290300370000200341106a200241d0006a41106a290300370000200341086a200241d0006a41086a2903003700002002200541206a2203360210200228027821050240200228020820036b20014f0d00200241086a2003200110ab86808000200228020c2104200228021021030b200420036a2005200110848e8080001a200320016a21012002280208210302402002280274450d00200541002802c0a3c68000118080808000000b200241086a2004200110e4888080000240024020022903084200520d002000420037030820004200370300200041106a428080808080808080807f370300200041186a4200370300200041206a4200370300200041286a4200370300200041306a4200370300200041386a41003602000c010b20002002290310370300200041386a200241c8006a290300370300200041306a200241086a41386a290300370300200041286a200241086a41306a290300370300200041206a200241086a41286a290300370300200041186a200241086a41206a290300370300200041106a200241086a41186a290300370300200041086a200241086a41106a2903003703000b02402003450d00200441002802c0a3c68000118080808000000b20024190016a2480808080000f0b4101412010b280808000000b10ae80808000000b4101200310b280808000000beb0501047f23808080800041e0006b2202248080808000200241346a41f5a6c48000410441002802a0a3c6800011858080800000200241346a41106a220341f89ec38000411141002802a0a3c6800011858080800000200241086a41186a200241346a41186a290000370300200241086a41106a2003290000370300200241086a41086a200241346a41086a2900003703002002200229003437030820022001280200360254200241d8006a200241d4006a410441002802a8a3c68000118580808000002002200241d4006a41046a3602402002200241d8006a41086a3602382002200241d4006a36023c2002200241d8006a360234200241286a200241346a108182808000024002400240024002402002280230220341206a22040d002002410036023c20024280808080103702340c010b2004417f4c0d024100210541002d00fca3c680001a200441002802c8a3c68000118180808000002201450d032002410036023c200220013602382002200436023420034160490d010b200241346a4100412010ab8680800020022802382101200228023c21050b200120056a22042002290308370000200441186a200241086a41186a290300370000200441106a200241086a41106a290300370000200441086a200241086a41086a2903003700002002200541206a220436023c200228022c21050240200228023420046b20034f0d00200241346a2004200310ab8680800020022802382101200228023c21040b200120046a2005200310848e8080001a200420036a21032002280234210402402002280228450d00200541002802c0a3c68000118080808000000b200241346a2001200310e188808000024002402002280234418080808078470d002000410036020820004280808080103702000c010b20002002290234370200200041086a200241346a41086a2802003602000b02402004450d00200141002802c0a3c68000118080808000000b200241e0006a2480808080000f0b10ae80808000000b4101200410b280808000000b800801047f2380808080004190016b2202248080808000200241086a41f9a6c48000410641002802a0a3c6800011858080800000200241086a41106a220341ea9ec38000410741002802a0a3c6800011858080800000200241d0006a41186a200241086a41186a290000370300200241d0006a41106a2003290000370300200241d0006a41086a200241086a41086a2900003703002002200229000837035041002d00fca3c680001a024002400240412041002802c8a3c68000118180808000002204450d0020042001290000370000200441186a200141186a290000370000200441106a200141106a290000370000200441086a200141086a290000370000200241086a200441204100280290a3c68000118580808000002002200441206a36028c01200220043602880120022003360284012002200241086a36028001200241f4006a20024180016a108182808000200441002802c0a3c6800011808080800000024002400240200228027c220141206a22030d002002410036021020024280808080103702080c010b2003417f4c0d034100210541002d00fca3c680001a200341002802c8a3c68000118180808000002204450d04200241003602102002200436020c2002200336020820014160490d010b200241086a4100412010ab86808000200228020c2104200228021021050b200420056a22032002290350370000200341186a200241d0006a41186a290300370000200341106a200241d0006a41106a290300370000200341086a200241d0006a41086a2903003700002002200541206a2203360210200228027821050240200228020820036b20014f0d00200241086a2003200110ab86808000200228020c2104200228021021030b200420036a2005200110848e8080001a200320016a21012002280208210302402002280274450d00200541002802c0a3c68000118080808000000b200241086a2004200110e4888080000240024020022903084200520d002000420037030820004200370300200041106a428080808080808080807f370300200041186a4200370300200041206a4200370300200041286a4200370300200041306a4200370300200041386a41003602000c010b20002002290310370300200041386a200241c8006a290300370300200041306a200241086a41386a290300370300200041286a200241086a41306a290300370300200041206a200241086a41286a290300370300200041186a200241086a41206a290300370300200041106a200241086a41186a290300370300200041086a200241086a41106a2903003703000b02402003450d00200441002802c0a3c68000118080808000000b20024190016a2480808080000f0b4101412010b280808000000b10ae80808000000b4101200310b280808000000b920601057f23808080800041f0006b22022480808080002002410c6a41f9a6c48000410641002802a0a3c68000118580808000002002410c6a41106a220341d49ec38000410941002802a0a3c6800011858080800000200241306a41186a2002410c6a41186a290000370300200241306a41106a2003290000370300200241306a41086a2002410c6a41086a2900003703002002200229000c37033020022001370360200241e8006a200241e0006a410841002802a8a3c68000118580808000002002200241e0006a41086a3602182002200241e8006a41086a3602102002200241e0006a3602142002200241e8006a36020c200241d4006a2002410c6a10818280800002400240024002400240200228025c220441206a22050d0020024100360214200242808080801037020c0c010b2005417f4c0d024100210641002d00fca3c680001a200541002802c8a3c68000118180808000002203450d0320024100360214200220033602102002200536020c20044160490d010b2002410c6a4100412010ab8680800020022802102103200228021421060b200320066a22052002290330370000200541186a200241306a41186a290300370000200541106a200241306a41106a290300370000200541086a200241306a41086a2903003700002002200641206a2205360214200228025821060240200228020c20056b20044f0d002002410c6a2005200410ab8680800020022802102103200228021421050b200320056a2006200410848e8080001a200520046a2104200228020c210502402002280254450d00200641002802c0a3c68000118080808000000b2002410c6a2003200410dd888080000240024020022d000c0d0020004200370000200041186a4200370000200041106a4200370000200041086a42003700000c010b2000200229000d370000200041186a200241256a290000370000200041106a2002411d6a290000370000200041086a200241156a2900003700000b02402005450d00200341002802c0a3c68000118080808000000b200241f0006a2480808080000f0b10ae80808000000b4101200510b280808000000bee0501057f23808080800041e0006b2202248080808000200241346a41f5a6c48000410441002802a0a3c6800011858080800000200241346a41106a220341f89ec38000411141002802a0a3c6800011858080800000200241086a41186a200241346a41186a290000370300200241086a41106a2003290000370300200241086a41086a200241346a41086a2900003703002002200229003437030820022001280200360254200241d8006a200241d4006a410441002802a8a3c68000118580808000002002200241d4006a41046a3602402002200241d8006a41086a3602382002200241d4006a36023c2002200241d8006a360234200241286a200241346a108182808000024002400240024002402002280230220341206a22040d002002410036023c20024280808080103702340c010b2004417f4c0d024100210541002d00fca3c680001a200441002802c8a3c68000118180808000002201450d032002410036023c200220013602382002200436023420034160490d010b200241346a4100412010ab8680800020022802382101200228023c21050b200120056a22042002290308370000200441186a200241086a41186a290300370000200441106a200241086a41106a290300370000200441086a200241086a41086a2903003700002002200541206a220436023c200228022c21050240200228023420046b20034f0d00200241346a2004200310ab8680800020022802382101200228023c21040b200120046a2005200310848e8080001a200420036a21032002280234210602402002280228450d00200541002802c0a3c68000118080808000000b200241346a2001200310e1888080000240024020022802342204418080808078470d0020004201370204410021040c010b2001200341002802a0a1c6800011848080800000200020022902383702040b2000200436020002402006450d00200141002802c0a3c68000118080808000000b200241e0006a2480808080000f0b10ae80808000000b4101200410b280808000000b910601067f23808080800041e0006b2202248080808000200241306a41f9a6c48000410641002802a0a3c6800011858080800000200241306a41106a220341d49ec38000410941002802a0a3c6800011858080800000200241186a200241306a41186a290000370300200241106a2003290000370300200241086a200241306a41086a2900003703002002200229003037030020022000370350200241d8006a200241d0006a410841002802a8a3c68000118580808000002002200241d0006a41086a36023c2002200241d8006a41086a3602342002200241d0006a3602382002200241d8006a360230200241246a200241306a108182808000024002400240024002400240200228022c220441206a22030d002002410036023820024280808080103702300c010b2003417f4c0d024100210541002d00fca3c680001a200341002802c8a3c68000118180808000002206450d0320024100360238200220063602342002200336023020044160490d010b200241306a4100412010ab8680800020022802342106200228023821050b200620056a22032002290300370000200341186a200241186a290300370000200341106a200241106a290300370000200341086a200241086a2903003700002002200541206a2205360238200228022821030240200228023020056b20044f0d00200241306a2005200410ab8680800020022802342106200228023821050b200620056a2003200410848e8080001a2002280230210702402002280224450d00200341002802c0a3c68000118080808000000b41002d00fca3c680001a412041002802c8a3c68000118180808000002203450d0220032001290000370000200341186a200141186a290000370000200341106a200141106a290000370000200341086a200141086a2900003700002006200520046a2003412041002802e0a1c6800011868080800000200341002802c0a3c680001180808080000002402007450d00200641002802c0a3c68000118080808000000b200241e0006a2480808080000f0b10ae80808000000b4101200310b280808000000b4101412010b280808000000bd90801077f23808080800041e0006b2202248080808000200241306a41f9a6c48000410641002802a0a3c6800011858080800000200241306a41106a220341ea9ec38000410741002802a0a3c6800011858080800000200241186a200241306a41186a290000370300200241106a2003290000370300200241086a200241306a41086a2900003703002002200229003037030041002d00fca3c680001a0240024002400240412041002802c8a3c68000118180808000002204450d0020042000290000370000200441186a200041186a290000370000200441106a200041106a290000370000200441086a200041086a290000370000200241306a200441204100280290a3c68000118580808000002002200441206a36025c20022004360258200220033602542002200241306a360250200241246a200241d0006a108182808000200441002802c0a3c6800011808080800000024002400240200228022c220041206a22030d002002410036023820024280808080103702300c010b2003417f4c0d034100210541002d00fca3c680001a200341002802c8a3c68000118180808000002204450d0420024100360238200220043602342002200336023020004160490d010b200241306a4100412010ab8680800020022802342104200228023821050b200420056a22032002290300370000200341186a200241186a290300370000200341106a200241106a290300370000200341086a200241086a2903003700002002200541206a2203360238200228022821050240200228023020036b20004f0d00200241306a2003200010ab8680800020022802342104200228023821030b200420036a2005200010848e8080001a2002280230210602402002280224450d00200541002802c0a3c68000118080808000000b41002d00fca3c680001a413c41002802c8a3c68000118180808000002205450d03200220053602342002413c3602302005200129030037000020024108360238200128023021074108210502402002280230417c714108470d00200241306a4108410410b182808000200228023821050b200228023420056a20073600002002200541046a2205360238200128023421070240200228023020056b41034b0d00200241306a2005410410b182808000200228023821050b200320006a2103200141086a2108200228023420056a20073600002002200541046a2200360238200128023821010240200228023020006b41034b0d00200241306a2000410410b182808000200228023821000b200228023420006a20013600002002200041046a3602382008200241306a10848d808000200228023021012004200320022802342200200228023841002802e0a1c680001186808080000002402001450d00200041002802c0a3c68000118080808000000b02402006450d00200441002802c0a3c68000118080808000000b200241e0006a2480808080000f0b4101412010b280808000000b10ae80808000000b4101200310b280808000000b4101413c10b280808000000bc70501047f23808080800041e0006b2202248080808000200241346a41f9a6c48000410641002802a0a3c6800011858080800000200241346a41106a220341899fc38000410d41002802a0a3c6800011858080800000200241086a41186a200241346a41186a290000370300200241086a41106a2003290000370300200241086a41086a200241346a41086a2900003703002002200229003437030820022000360254200241d8006a200241d4006a410441002802a8a3c68000118580808000002002200241d4006a41046a3602402002200241d8006a41086a3602382002200241d4006a36023c2002200241d8006a360234200241286a200241346a108182808000024002400240024002402002280230220341206a22040d002002410036023c20024280808080103702340c010b2004417f4c0d024100210541002d00fca3c680001a200441002802c8a3c68000118180808000002200450d032002410036023c200220003602382002200436023420034160490d010b200241346a4100412010ab8680800020022802382100200228023c21050b200020056a22042002290308370000200441186a200241086a41186a290300370000200441106a200241086a41106a290300370000200441086a200241086a41086a2903003700002002200541206a220436023c200228022c21050240200228023420046b20034f0d00200241346a2004200310ab8680800020022802382100200228023c21040b200020046a2005200310848e8080001a200420036a21032002280234210402402002280228450d00200541002802c0a3c68000118080808000000b2001280204220520012802082000200310d58580800002402004450d00200041002802c0a3c68000118080808000000b02402001280200450d00200541002802c0a3c68000118080808000000b200241e0006a2480808080000f0b10ae80808000000b4101200410b280808000000b810801087f23808080800041e0006b2202248080808000200241346a41f5a6c48000410441002802a0a3c6800011858080800000200241346a41106a220341f89ec38000411141002802a0a3c6800011858080800000200241086a41186a200241346a41186a290000370300200241086a41106a2003290000370300200241086a41086a200241346a41086a2900003703002002200229003437030820022000280200360254200241d8006a200241d4006a410441002802a8a3c68000118580808000002002200241d4006a41046a3602402002200241d8006a41086a3602382002200241d4006a36023c2002200241d8006a360234200241286a200241346a1081828080000240024002400240024002402002280230220041206a22030d002002410036023c20024280808080103702340c010b2003417f4c0d024100210441002d00fca3c680001a200341002802c8a3c68000118180808000002205450d032002410036023c200220053602382002200336023420004160490d010b200241346a4100412010ab8680800020022802382105200228023c21040b200520046a22032002290308370000200341186a200241086a41186a290300370000200341106a200241086a41106a290300370000200341086a200241086a41086a2903003700002002200441206a220436023c200228022c21030240200228023420046b20004f0d00200241346a2004200010ab8680800020022802382105200228023c21040b200520046a2003200010848e8080001a2002280234210602402002280228450d00200341002802c0a3c68000118080808000000b20012802082203417f4c0d0041002d00fca3c680001a2003410574410472220741002802c8a3c68000118180808000002208450d02200420006a21092002410036023c200220083602382002200736023420012802042100200220033602282002200241286a360208200241086a200241346a10c08a8080000240024020030d00200228023c2103200228023821070c010b20034105742101200228023c210303400240200228023420036b411f4b0d00200241346a2003412010b182808000200228023c21030b2002280238220720036a22042000290000370000200441086a200041086a290000370000200441106a200041106a290000370000200441186a200041186a2900003700002002200341206a220336023c200041206a2100200141606a22010d000b0b20022802342100200520092007200341002802e0a1c680001186808080000002402000450d00200741002802c0a3c68000118080808000000b02402006450d00200541002802c0a3c68000118080808000000b200241e0006a2480808080000f0b10ae80808000000b4101200310b280808000000b4101200710b280808000000ba20801097f23808080800041e0006b2202248080808000200241346a41f5a6c48000410441002802a0a3c6800011858080800000200241346a41106a220341f89ec38000411141002802a0a3c6800011858080800000200241086a41186a200241346a41186a290000370300200241086a41106a2003290000370300200241086a41086a200241346a41086a2900003703002002200229003437030820022000280200360254200241d8006a200241d4006a410441002802a8a3c68000118580808000002002200241d4006a41046a3602402002200241d8006a41086a3602382002200241d4006a36023c2002200241d8006a360234200241286a200241346a1081828080000240024002400240024002402002280230220041206a22030d002002410036023c20024280808080103702340c010b2003417f4c0d024100210441002d00fca3c680001a200341002802c8a3c68000118180808000002205450d032002410036023c200220053602382002200336023420004160490d010b200241346a4100412010ab8680800020022802382105200228023c21040b200520046a22032002290308370000200341186a200241086a41186a290300370000200341106a200241086a41106a290300370000200341086a200241086a41086a2903003700002002200441206a220436023c200228022c21030240200228023420046b20004f0d00200241346a2004200010ab8680800020022802382105200228023c21040b200520046a2003200010848e8080001a2002280234210602402002280228450d00200341002802c0a3c68000118080808000000b20012802082203417f4c0d0041002d00fca3c680001a2003410574410472220741002802c8a3c68000118180808000002208450d02200420006a21092002410036023c20022008360238200220073602342001280204210a200220033602282002200241286a360208200241086a200241346a10c08a8080000240024020030d00200228023c2103200228023821080c010b20034105742107200228023c2103200a210003400240200228023420036b411f4b0d00200241346a2003412010b182808000200228023c21030b2002280238220820036a22042000290000370000200441086a200041086a290000370000200441106a200041106a290000370000200441186a200041186a2900003700002002200341206a220336023c200041206a2100200741606a22070d000b0b20022802342100200520092008200341002802e0a1c680001186808080000002402000450d00200841002802c0a3c68000118080808000000b02402006450d00200541002802c0a3c68000118080808000000b02402001280200450d00200a41002802c0a3c68000118080808000000b200241e0006a2480808080000f0b10ae80808000000b4101200310b280808000000b4101200710b280808000000bc60906017f037e037f017e017f027e2380808080004190016b2202248080808000200141106a29030021032001290308210420013502002105200241286a41f9a6c48000410641002802a0a3c6800011858080800000200241286a41106a220641ea9ec38000410741002802a0a3c6800011858080800000200241186a200241286a41186a290000370300200241106a2006290000370300200241086a200241286a41086a2900003703002002200229002837030041002d00fca3c680001a024002400240412041002802c8a3c68000118180808000002207450d0020072000290000370000200741186a200041186a290000370000200741106a200041106a290000370000200741086a200041086a290000370000200241286a200741204100280290a3c68000118580808000002002200741206a36028c01200220073602880120022006360284012002200241286a36028001200241f4006a20024180016a108182808000200741002802c0a3c6800011808080800000024002400240200228027c220041206a22060d002002410036023020024280808080103702280c010b2006417f4c0d034100210841002d00fca3c680001a200641002802c8a3c68000118180808000002207450d04200241003602302002200736022c2002200636022820004160490d010b200241286a4100412010ab86808000200228022c2107200228023021080b200720086a22062002290300370000200641186a200241186a290300370000200641106a200241106a290300370000200641086a200241086a2903003700002002200841206a2206360230200228027821080240200228022820066b20004f0d00200241286a2006200010ab86808000200228022c2107200228023021060b200720066a2008200010848e8080001a200620006a21002002280228210602402002280274450d00200841002802c0a3c68000118080808000000b200241286a2007200010e488808000420021090240024020022903284200520d00200241206a4100360200200242003703180c010b200241086a200241d0006a290300370300200241106a200241d8006a290300370300200241186a200241e0006a290300370300200241206a200241e8006a2802003602002002200241286a41206a290300370300200241ec006a280200210a200229033021090b4200210b0240024020054200520d00200241386a4200370300200241306a420037030020024200370328428080808080808080807f21030c010b200241386a200141286a290300370300200241306a200141206a290300370300200220012903183703282004210b0b200241106a200241286a41106a22012903002205370300200241086a200241286a41086a2208290300220437030020022002290328220c370300200241286a41186a20033703002001200b370300200241286a41206a200c370300200241d0006a2004370300200241d8006a2005370300200241e0006a200241186a290300370300200241e8006a200241206a280200360200200241ec006a200a360200200220093703302002420137032820082007200010f58780800002402006450d00200741002802c0a3c68000118080808000000b20024190016a2480808080000f0b4101412010b280808000000b10ae80808000000b4101200610b280808000000bf70a03057f047e037f2380808080004190016b2201248080808000200141086a41f9a6c48000410641002802a0a3c6800011858080800000200141086a41106a220241ea9ec38000410741002802a0a3c6800011858080800000200141d0006a41186a200141086a41186a290000370300200141d0006a41106a2002290000370300200141d0006a41086a200141086a41086a2900003703002001200129000837035041002d00fca3c680001a02400240024002400240412041002802c8a3c68000118180808000002203450d0020032000290000370000200341186a200041186a290000370000200341106a200041106a290000370000200341086a200041086a290000370000200141086a200341204100280290a3c68000118580808000002001200341206a36028c01200120033602880120012002360284012001200141086a36028001200141f4006a20014180016a108182808000200341002802c0a3c6800011808080800000024002400240200128027c220041206a22020d002001410036021020014280808080103702080c010b2002417f4c0d034100210441002d00fca3c680001a200241002802c8a3c68000118180808000002203450d04200141003602102001200336020c2001200236020820004160490d010b200141086a4100412010ab86808000200128020c2103200128021021040b200320046a22022001290350370000200241186a200141d0006a41186a290300370000200241106a200141d0006a41106a290300370000200241086a200141d0006a41086a2903003700002001200441206a2202360210200128027821040240200128020820026b20004f0d00200141086a2002200010ab86808000200128020c2103200128021021020b200320026a2004200010848e8080001a200220006a21002001280208210502402001280274450d00200441002802c0a3c68000118080808000000b200141086a2003200010e48880800042002106024020012903084200520d00200141e0006a4200370300200141d8006a420037030020014200370350428080808080808080807f210742002108420021090c040b200141d8006a200141306a290300370300200141d0006a41106a200141386a2903003703002001200141286a290300370350200141206a2903002107200141086a41106a2903002108200141c4006a2902002106200141cc006a280200210420012903102109200141c0006a2802002202450d032002417f6a21020c040b4101412010b280808000000b10ae80808000000b4101200210b280808000000b410021020240417f4100280284a4c68000220a410147200a41014b1b220a417f460d00200a41ff01710d010b410021024100280290a1c68000210a410028028ca1c68000210b4100280280a4c68000210c200141c0006a42003702002001413c6a418097c38000360200200141386a4101360200200141306a410f3602002001412c6a41a89cc38000360200200141206a41c49ac38000ad4280808080b00b84370200200141146a41aa9bc38000ad4280808080c00184370200200141a09cc38000360234200141013602282001410036021c2001410036021020014281808080d0ce01370208200b41ecf2c08000200c410246220c1b200141086a200a41d4f2c08000200c1b280210118480808000000b200141206a2007370300200141086a41106a2008370300200141286a2001290350370300200141cc006a2004360200200141c4006a2006370200200141c0006a2002360200200141306a200141d0006a41086a290300370300200141386a200141d0006a41106a2903003703002001200937031020014201370308200141086a41086a2003200010f58780800002402005450d00200341002802c0a3c68000118080808000000b20014190016a2480808080000bfc0903057f037e027f2380808080004190016b2202248080808000200241c0006a41f9a6c48000410641002802a0a3c6800011858080800000200241c0006a41106a220341ea9ec38000410741002802a0a3c6800011858080800000200241186a200241c0006a41186a290000370300200241106a2003290000370300200241086a200241c0006a41086a2900003703002002200229004037030041002d00fca3c680001a024002400240412041002802c8a3c68000118180808000002204450d0020042000290000370000200441186a200041186a290000370000200441106a200041106a290000370000200441086a200041086a290000370000200241c0006a200441204100280290a3c68000118580808000002002200441206a36023c20022004360238200220033602342002200241c0006a360230200241246a200241306a108182808000200441002802c0a3c6800011808080800000024002400240200228022c220041206a22030d002002410036024820024280808080103702400c010b2003417f4c0d034100210541002d00fca3c680001a200341002802c8a3c68000118180808000002204450d0420024100360248200220043602442002200336024020004160490d010b200241c0006a4100412010ab8680800020022802442104200228024821050b200420056a22032002290300370000200341186a200241186a290300370000200341106a200241106a290300370000200341086a200241086a2903003700002002200541206a2203360248200228022821050240200228024020036b20004f0d00200241c0006a2003200010ab8680800020022802442104200228024821030b200420036a2005200010848e8080001a200320006a21002002280240210602402002280224450d00200541002802c0a3c68000118080808000000b200241c0006a2004200010e488808000420021070240024020022903404200520d0041002103200241186a4100360200200241106a4200370300200241086a420037030020024200370300428080808080808080807f210842002109410021050c010b200241086a200241e8006a290300370300200241106a200241f0006a290300370300200241186a200241f8006a2802003602002002200241e0006a290300370300200241c0006a41186a2903002108200241c0006a41106a290300210720024184016a280200210a20024180016a2802002103200241fc006a2802002105200229034821090b024002402005200372220b0d00200241c9006a2001290000370000200241e1006a200141186a290000370000200241d9006a200141106a290000370000200241d1006a200141086a290000370000200241033a0048200241163a0040200241c0006a108e8a808000410121010c010b200541016a2205417f20051b21010b200b4100472105200241c0006a41186a2008370300200241c0006a41106a2007370300200241e0006a200229030037030020024184016a200a36020020024180016a2003360200200241fc006a2001360200200241e8006a200241086a290300370300200241f0006a200241106a290300370300200241f8006a200241186a2802003602002002200937034820024201370340200241c0006a41086a2004200010f58780800002402006450d00200441002802c0a3c68000118080808000000b20024190016a24808080800020050f0b4101412010b280808000000b10ae80808000000b4101200310b280808000000b960501057f23808080800041e0006b2201248080808000200141306a41f9a6c48000410641002802a0a3c6800011858080800000200141306a41106a220241d49ec38000410941002802a0a3c6800011858080800000200141186a200141306a41186a290000370300200141106a2002290000370300200141086a200141306a41086a2900003703002001200129003037030020012000370350200141d8006a200141d0006a410841002802a8a3c68000118580808000002001200141d0006a41086a36023c2001200141d8006a41086a3602342001200141d0006a3602382001200141d8006a360230200141246a200141306a10818280800002400240024002400240200128022c220341206a22040d002001410036023820014280808080103702300c010b2004417f4c0d024100210541002d00fca3c680001a200441002802c8a3c68000118180808000002202450d0320014100360238200120023602342001200436023020034160490d010b200141306a4100412010ab8680800020012802342102200128023821050b200220056a22042001290300370000200441186a200141186a290300370000200441106a200141106a290300370000200441086a200141086a2903003700002001200541206a2204360238200128022821050240200128023020046b20034f0d00200141306a2004200310ab8680800020012802342102200128023821040b200220046a2005200310848e8080001a200420036a21032001280230210402402001280224450d00200541002802c0a3c68000118080808000000b2002200341002802a0a1c680001184808080000002402004450d00200241002802c0a3c68000118080808000000b200141e0006a2480808080000f0b10ae80808000000b4101200410b280808000000bf60501047f23808080800041e0006b2201248080808000200141306a41f9a6c48000410641002802a0a3c6800011858080800000200141306a41106a220241ea9ec38000410741002802a0a3c6800011858080800000200141186a200141306a41186a290000370300200141106a2002290000370300200141086a200141306a41086a2900003703002001200129003037030041002d00fca3c680001a024002400240412041002802c8a3c68000118180808000002203450d0020032000290000370000200341186a200041186a290000370000200341106a200041106a290000370000200341086a200041086a290000370000200141306a200341204100280290a3c68000118580808000002001200341206a36025c20012003360258200120023602542001200141306a360250200141246a200141d0006a108182808000200341002802c0a3c6800011808080800000024002400240200128022c220041206a22020d002001410036023820014280808080103702300c010b2002417f4c0d034100210441002d00fca3c680001a200241002802c8a3c68000118180808000002203450d0420014100360238200120033602342001200236023020004160490d010b200141306a4100412010ab8680800020012802342103200128023821040b200320046a22022001290300370000200241186a200141186a290300370000200241106a200141106a290300370000200241086a200141086a2903003700002001200441206a2202360238200128022821040240200128023020026b20004f0d00200141306a2002200010ab8680800020012802342103200128023821020b200320026a2004200010848e8080001a200220006a21002001280230210202402001280224450d00200441002802c0a3c68000118080808000000b2003200041002802a0a1c680001184808080000002402002450d00200341002802c0a3c68000118080808000000b200141e0006a2480808080000f0b4101412010b280808000000b10ae80808000000b4101200210b280808000000b170041b299c38000410f41b89dc3800010f880808000000b170041b299c38000410f41c89dc3800010f880808000000b170041b299c38000410f41d89dc3800010f880808000000b170041b299c38000410f41e89dc3800010f880808000000b170041b299c38000410f41f89dc3800010f880808000000b170041b299c38000410f41889ec3800010f880808000000b170041b299c38000410f41989ec3800010f880808000000b170041b299c38000410f41a89ec3800010f880808000000bae08020a7f017e23808080800041306b2203248080808000024020002802402204418080808078460d0002400240200041cc006a28020022050d0041002105410021060c010b200320053602242003410036022020032005360214200341003602102003200041d0006a280200220536022820032005360218200041d4006a2802002106410121050b2003200636022c2003200536021c2003200536020c2003410c6a10928d8080002004450d00200041c4006a28020041002802c0a3c68000118080808000000b2000418080808078360240024002400240024002400240024020002802200d00200228020021052002280208210620004100360220200041286a2204200429030042017c37030020002802300d014100210420004100360230200041386a22072007290300410020062005418080808078461bad7c3703000240024020002d00d8020d000c010b024020002802a4012208450d00200041a8016a28020021090340200841a07e6a210a200841a4136a210420082f01aa14220b410c6c2105417f2107024002400340024020050d00200b21070c020b200441086a2106200441046a210c200541746a2105200741016a2107200a41e0016a210a2004410c6a2104417f41b99ec38000200c28020020062802002206411020064110491b10888e808000220c411020066b200c1b220641004720064100481b22064101460d000b200641ff0171450d010b2009450d022009417f6a2109200820074102746a41ac146a28020021080c010b0b200a41086a280200200a2802002204200441054b22041b2205450d0402402005412c6c200a41046a2205280200200520041b6a41546a2204280208220541014b0d0020042802042107200428021c210602402004280200220a450d0020062007460d010b2003200441106a36020c2003410c6a200a20072006108e858080002004200636020420044101360200200428020821050b02400240024002402005417e6a2205410220054102491b0e03020100020b200441106a21060c020b20002802000d07200041003602002000200029030842017c37030820002802100d08200041003602100c020b2004410c6a21060b20002802000d07200641086a350200210d41002105200041003602002000200029030842017c37030820002802100d0820004100360210200041186a22042004290300200d7c37030041012104410121070240200641086a2802004104490d00200641046a2802002800002105410021070b2007450d010b41012104417f21050b200041a4016a2001200220042005109085808000200341306a2480808080000f0b41ecb8c28000108781808000000b41dcb8c28000108781808000000b41fcb8c2800041fc0041f8bac2800010a181808000000b41ccb8c28000108781808000000b41bcb8c28000108781808000000b41ccb8c28000108781808000000b41bcb8c28000108781808000000bd51501137f23808080800041f0036b2204248080808000024002400240024002402001280240418080808078460d00200041186a20014190016a290000370000200041106a20014188016a290000370000200041086a20014180016a2900003700002000200141f8006a290000370000410121050c010b41002d00fca3c680001a20012802a4012106200141a0016a28020021072001419c016a2802002108200141ac016a2802002109200141a8016a280200210a2001280298012105410141002802c8a3c6800011818080800000220b450d01200b41003a000020044180016a41186a220c419380c6800041014100280298a3c680001185808080000020044194016a410036020020044201370288012004200b360284012004410136028001200441003602c00120044280808080c0003702b8014104210b0240024020050d004100210d0c010b4100210d2007450d00200441ac026a210e200441c4026a210f200441a0026a41017221104100210d4100210b034002400240200b450d002008211120052112200b21050c010b4100211102402008450d002008210b024020084107712212450d000340200b417f6a210b20052802ac0921052012417f6a22120d000b0b20084108490d00034020052802ac092802ac092802ac092802ac092802ac092802ac092802ac092802ac092105200b41786a220b0d000b0b410021120b0240201120052f01aa09490d00034020052802a008220b450d06201241016a211220052f01a8092111200b21052011200b2f01aa094f0d000b0b201141016a210802400240024020120d002005210b0c010b200520084102746a41ac096a280200210b410021082012417f6a2213450d002012417e6a2114024020134107712212450d0003402013417f6a2113200b2802ac09210b2012417f6a22120d000b0b024020144107490d000340200b2802ac092802ac092802ac092802ac092802ac092802ac092802ac092802ac09210b201341786a22130d000b0b2005450d010b2005201141e0006c6a22112802082112201128020021052004201128020422133602e001200420053602dc01200441003602d801200420133602d001200420053602cc01200441003602c80120042012410020051b3602e4012004200541004722053602d401200420053602c401200441a0026a2002201141d4006a2205200441c4016a200310888d808000200441286a41186a2212201041186a290000370300200441286a41106a2213201041106a290000370300200441286a41086a220d201041086a290000370300200441e8016a41086a200f41086a290200370300200441e8016a41106a200f41106a290200370300200441e8016a41186a200f41186a290200370300200441e8016a41206a200f41206a290200370300200441e8016a41286a200f41286a290200370300200441e8016a41306a200f41306a290200370300200420102900003703282004200f2902003703e80120042d00a0022111200441fc026a200510a08580800020044180016a200441e8016a10ac8d8080000240024020110d00200441a0026a41086a2214200441fc026a41086a280200360200200420042902fc023703a00241002d00fca3c680001a2004410036029003200442808080801037028803412041002802c8a3c68000118180808000002205450d0820052004290328370000200541186a22152012290300370000200541106a22162013290300370000200541086a2213200d29030037000020044188036a4100412010b182808000200428028c0320044188036a41086a2212280200220d6a22112005290000370000201141086a2013290000370000201141106a2016290000370000201141186a20152900003700002012200d41206a360200200541002802c0a3c6800011808080800000200e41086a2012280200360200200e200429028803370200024020042802c001220520042802b801470d00200441b8016a200510a68680800020042802c00121050b20042802bc01200541186c6a221120042903a002370200201141086a2014290300370200201141106a200441a0026a41106a290300370200200541016a210d0c010b024020042802c001220520042802b801470d00200441b8016a200510a68680800020042802c00121050b20042802bc01200541186c6a220520042902fc02370200200541808080807836020c200541086a200441fc026a41086a28020036020020042802c00141016a210d0b2004200d3602c001410021052007417f6a22070d010b0b20042802bc01210b0b2004200b3602e403200441c0036a41286a200b200d41186c6a36020020042009410020061b3602e0032004200a3602dc03200420063602d803200441003602d4032004200641004722053602d0032004200a3602cc03200420063602c803200441003602c403200420053602c003200441a0026a2002200441c0036a200310868d808000200441286a41086a200441a0026a41086a290200370300200441286a41106a200441a0026a41106a290200370300200441286a41186a200441a0026a41186a29020037030020044188036a41086a200441a0026a41286a29020037030020044188036a41106a200441a0026a41306a29020037030020044188036a41186a200441a0026a41386a29020037030020044188036a41206a200441a0026a41c0006a29020037030020044188036a41286a200441a0026a41c8006a29020037030020044188036a41306a200441a0026a41d0006a290200370300200420042902a002370328200420042902c0023703880320044180016a20044188036a10ac8d808000200441286a41d0006a20044180016a41306a290200370300200441286a41c8006a20044180016a41286a290200370300200441286a41c0006a20044180016a41206a290200370300200441286a41386a200c290200370300200441286a41306a20044180016a41106a290200370300200441286a41286a20044180016a41086a2902003703002004200429028001370348024020042802c001220b450d0020042802bc012105034002402005280200450d00200541046a28020041002802c0a3c68000118080808000000b02402005410c6a2802002211418080808078460d002011450d00200541106a28020041002802c0a3c68000118080808000000b200541186a2105200b417f6a220b0d000b0b200141c0006a2113200441286a41206a2105024020042802b801450d0020042802bc0141002802c0a3c68000118080808000000b200441086a41086a220b200441286a41086a290300370300200441086a41106a2211200441286a41106a290300370300200441086a41186a2212200441286a41186a29030037030020042004290328370308200441a0026a41306a200541306a290200370300200441a0026a41286a200541286a290200370300200441a0026a41206a200541206a290200370300200441a0026a41186a200541186a290200370300200441a0026a41106a200541106a290200370300200441a0026a41086a200541086a290200370300200420052902003703a002200441e0026a200b290300370300200441e8026a2011290300370300200441f0026a2012290300370300200420042903083703d8022013200441a0026a41d80010848e8080001a200041186a2012290300370000200041106a2011290300370000200041086a200b29030037000020002004290308370000410021050b200020053a0020200441f0036a2480808080000f0b4101410110b280808000000b419cd0c2800010a081808000000b4101412010b280808000000bd905020a7f017e23808080800041106b2204248080808000024002400240024002400240024020012802a40122050d00410021060c010b200141a8016a28020021070340200541a07e6a2108200541a4136a210620052f01aa142209410c6c210a417f210b0240024003400240200a0d002009210b0c020b200641086a210c200641046a210d200a41746a210a200b41016a210b200841e0016a21082006410c6a2106417f2002200d2802002003200c280200220c2003200c491b10888e808000220d2003200c6b200d1b220c410047200c4100481b220c4101460d000b200c41ff0171450d010b024020070d00410021060c030b2007417f6a21072005200b4102746a41ac146a28020021050c010b0b200841086a28020020082802002206200641054b22061b220a450d010240200a412c6c200841046a220a280200200a20061b6a41546a2206280208220a41014b0d002006280204210c200628021c210302402006280200220b450d002003200c460d010b2004200641106a36020c2004410c6a200b200c2003108e8580800020062003360204200641013602002006280208210a0b02400240024002400240200a417e6a220a4102200a4102491b0e03000301000b2006410c6a21060c010b200641106a21060b20012802000d04200641086a350200210e200141003602002001200129030842017c37030820012802100d0520014100360210200141186a220a200a290300200e7c370300200641086a280200210a200641046a28020021060c010b20012802000d0541002106200141003602002001200129030842017c37030820012802100d06200141003602100b20002006360204200041086a200a360200410121060b20002006360200200441106a2480808080000f0b41fcb8c2800041fc0041f8bac2800010a181808000000b41ccb8c28000108781808000000b41bcb8c28000108781808000000b41ccb8c28000108781808000000b41bcb8c28000108781808000000bab0301037f23808080800041206b2203248080808000410121040240200028020c220541c000490d0041022104200541808001490d00410441052005418080808004491b21040b41002d00fca3c680001a0240200441002802c8a3c68000118180808000002205450d00200341003602102003200536020c2003200436020820032000410c6a360214200341146a200341086a10c08a808000024002402000280200418080808078470d00200341146a2000280204200041086a28020010b4828080000c010b200341146a2000280204200028020810e6848080000b2003280218210502402003280208200328021022006b200328021c22044f0d00200341086a2000200410b182808000200328021021000b200328020c20006a2005200410848e8080001a2003200020046a220036021002402003280214450d00200541002802c0a3c6800011808080800000200328021021000b2003280208210420012002200328020c2205200041002802e0a1c680001186808080000002402004450d00200541002802c0a3c68000118080808000000b200341206a2480808080000f0b4101200410b280808000000bba0301087f23808080800041106b220324808080800041002d00fca3c680001a02400240410141002802c8a3c68000118180808000002204450d002003410036020c200320043602082003410136020441002d00fca3c680001a412041002802c8a3c68000118180808000002204450d0120042000290001370000200441186a2205200041196a290000370000200441106a2206200041116a290000370000200441086a2207200041096a290000370000200341046a4100412010b18280800020032802082208200328020c22096a220a2004290000370000200a41086a2007290000370000200a41106a2006290000370000200a41186a20052900003700002003200941206a220a36020c200441002802c0a3c680001180808080000020002d00002100024020032802042204200a470d00200341046a200a410110b1828080002003280208210820032802042104200328020c210a0b2008200a6a20003a0000200120022008200a41016a41002802e0a1c680001186808080000002402004450d00200841002802c0a3c68000118080808000000b200341106a2480808080000f0b4101410110b280808000000b4101412010b280808000000bc70201057f23808080800041106b2203248080808000410521044100210502400240200028020022060e03010000010b41012105410121040b41002d00fca3c680001a0240200441002802c8a3c68000118180808000002207450d002003200736020820032004360204410121040240024002400240024020060e03000201000b200741003a0000410121042003410136020c200028020421064100210002402005450d00200341046a4101410410b182808000200328020445210020032802082107200328020c21040b200720046a2006360000200120022007200441046a41002802e0a1c68000118680808000002000450d020c030b410221040b200720043a0000200120022007410141002802e0a1c68000118680808000000b200741002802c0a3c68000118080808000000b200341106a2480808080000f0b4101200410b280808000000bca0101057f23808080800041206b220124808080800041002102200141003602102001428080808010370208200141146a10958880800041012103200128021821040240200128021c2205450d00200141086a4100200510b182808000200128020c2103200128021021020b200320026a2004200510848e8080001a2001200220056a36021002402001280214450d00200441002802c0a3c68000118080808000000b20002001290208370200200041086a200141086a41086a280200360200200141206a2480808080000b900201047f23808080800041106b2202248080808000200128020041027441f8adc380006a28020021030240024020012d00084116470d00200141106a10a18a80800021040c010b200141086a10a98c80800021040b02400240417f417f200420036a41016a220420042003491b2203200141e0006a2802004105746a41046a220420042003491b2203417f4c0d0041002d00fca3c680001a200341002802c8a3c68000118180808000002204450d01200241046a41086a2205410036020020022004360208200220033602042001200241046a10ef87808000200041086a200528020036020020002002290204370200200241106a2480808080000f0b10ae80808000000b4101200310b280808000000bcb0401097f23808080800041206b220224808080800041002d00fca3c680001a02400240410141002802c8a3c68000118180808000002203450d00200341053a000041002d00fca3c680001a2002410036021c2002428080808010370214412041002802c8a3c68000118180808000002204450d0120044200370000200441186a22054200370000200441106a22064200370000200441086a22074200370000200241146a4100412010b1828080002002280218200241146a41086a220828020022096a220a2004290000370000200a41086a2007290000370000200a41106a2006290000370000200a41186a20052900003700002008200941206a360200200441002802c0a3c6800011808080800000200241086a41086a220a2008280200360200200220022902143703080240200128020822042001280200470d0020012004109d86808000200128020821040b2001280204200441e8006c6a220442c194a6a793ccc3a857370328200442a5e9e3ab9e929adc2c37031020044109360244200441d49ec38000360240200441f581808000360238200441ef808080003602202004410136020c2004200336020820044281808080103703002004200229030837034820042000290200370254200441306a42ab8bffbed784ffa5937f370300200441186a4293888c8f89fdc6ec9e7f370300200441d0006a200a280200360200200441dc006a200041086a280200360200200441013a00602001200128020841016a360208200241206a2480808080000f0b4101410110b280808000000b4101412010b280808000000bdd0301057f23808080800041306b220224808080800041002d00fca3c680001a02400240410141002802c8a3c68000118180808000002203450d00200341023a00002002410036022020024280808080800137021841002d00fca3c680001a410441002802c8a3c68000118180808000002204450d01200241246a41086a220541003602002002200436022820024104360224200241186a200241246a108187808000200241086a41086a22062005280200360200200220022902243703080240200128020822042001280200470d0020012004109d86808000200128020821040b2001280204200441e8006c6a220442a09acee28b90aca44d370328200442c4ccab9c81ebb4b8db0037031020044108360244200441dd9ec380003602402004419d82808000360238200441f0818080003602202004410136020c2004200336020820044281808080103703002004200229030837034820042000290200370254200441306a42f68ebee6f7f7fefdac7f370300200441186a42a4d2928ecac0faa432370300200441d0006a2006280200360200200441dc006a200041086a280200360200200441013a00602001200128020841016a360208200241306a2480808080000f0b4101410110b280808000000b4101410410b280808000000be90503067f017e027f23808080800041d0006b2201248080808000200141286a419b9fc38000410a41a59fc380004120418097c38000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041c00041002802c8a3c68000118180808000002202450d0020024285cbd9e891b2d0c161370308200241c59fc38000360220200241f18180800036021820024101360204200241ab99c38000360200200241106a4282d2add5d4f1deea6a370300200241386a4100360200200241246a410136020020014102360248200120023602402001200241c0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a22032001411c6a220241086a28020036020020012002290200370300200128021021042001280214210520012802182106200129022c21072001280228210820014100360218200142808080808001370210200141106a410010a4868080002001280214200128021841386c6a2202420437022c20024206370224200241cae4c48000360220200241003602182002419e82808000360210200242cdec93ccd5b69cacdf00370308200242be8af3e3f0cdac8456370300200128021821092001280214210220012001280210360248200120023602402001200236024420012002200941386c6a41386a36024c200141346a200141c0006a10f9868080002008418080808078460d012001200436021820012005360210200120053602142001200520064105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002008360238200041003a000020002001290300370350200041d8006a20032802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841c00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000bd70301057f23808080800041206b220224808080800041002d00fca3c680001a02400240410141002802c8a3c68000118180808000002203450d00200341023a000041002d00fca3c680001a410441002802c8a3c68000118180808000002204450d012002410c6a41086a22054100360200200220043602102002410436020c200241003602182002200241186a36021c2002411c6a2002410c6a10c08a808000200241086a220620052802003602002002200229020c3703000240200128020822042001280200470d0020012004109d86808000200128020821040b2001280204200441e8006c6a220442fb92fda592a6fcd31c370328200442c4ccab9c81ebb4b8db0037031020044105360244200441e59ec380003602402004419f82808000360238200441f0818080003602202004410136020c2004200336020820044281808080103703002004200229030037034820042000290200370254200441306a42b584d6d28c82acc02f370300200441186a42a4d2928ecac0faa432370300200441d0006a2006280200360200200441dc006a200041086a280200360200200441013a00602001200128020841016a360208200241206a2480808080000f0b4101410110b280808000000b4101410410b280808000000b850601057f23808080800041e0006b220224808080800041002d00fca3c680001a02400240410141002802c8a3c68000118180808000002203450d00200341023a0000200241206a428080808080808080807f370300200241286a4200370300200241306a4200370300200241386a4200370300200241c0006a4200370300200241c8006a4100360200200242003703182002420037031041002d00fca3c680001a413c41002802c8a3c68000118180808000002204450d01200220043602582002413c360254200442003700002002410836025c200228024021054108210402402002280254417c714108470d00200241d4006a4108410410b182808000200228025c21040b200228025820046a20053600002002200441046a220436025c200228024421050240200228025420046b41034b0d00200241d4006a2004410410b182808000200228025c21040b200241106a41086a2106200228025820046a20053600002002200441046a220436025c200228024821050240200228025420046b41034b0d00200241d4006a2004410410b182808000200228025c21040b200228025820046a2005360000200241d4006a41086a2205200441046a3602002006200241d4006a10848d808000200241086a22062005280200360200200220022902543703000240200128020822042001280200470d0020012004109d86808000200128020821040b2001280204200441e8006c6a220442f8b3f08d85bca5b6e300370328200442c4ccab9c81ebb4b8db0037031020044107360244200441ea9ec38000360240200441a082808000360238200441f0818080003602202004410136020c2004200336020820044281808080103703002004200229030037034820042000290200370254200441306a4291ba8cfeb2d6b48568370300200441186a42a4d2928ecac0faa432370300200441d0006a2006280200360200200441dc006a200041086a280200360200200441013a00602001200128020841016a360208200241e0006a2480808080000f0b4101410110b280808000000b4101413c10b280808000000bd90301057f23808080800041206b220224808080800041002d00fca3c680001a02400240410141002802c8a3c68000118180808000002203450d00200341023a000041002d00fca3c680001a410441002802c8a3c68000118180808000002204450d012002410c6a41086a22054100360200200220043602102002410436020c200241003602182002200241186a36021c2002411c6a2002410c6a10c08a808000200241086a220620052802003602002002200229020c3703000240200128020822042001280200470d0020012004109d86808000200128020821040b2001280204200441e8006c6a220442fa89d3f6b7fdfb8f9a7f370328200442c4ccab9c81ebb4b8db0037031020044107360244200441f19ec38000360240200441a182808000360238200441f0818080003602202004410136020c2004200336020820044281808080103703002004200229030037034820042000290200370254200441306a42fd8281afbeafaef5807f370300200441186a42a4d2928ecac0faa432370300200441d0006a2006280200360200200441dc006a200041086a280200360200200441013a00602001200128020841016a360208200241206a2480808080000f0b4101410110b280808000000b4101410410b280808000000be90503067f017e027f23808080800041d0006b2201248080808000200141286a419b9fc38000410a41a59fc380004120418097c38000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041c00041002802c8a3c68000118180808000002202450d00200242ef8683cfe1dddaca63370308200241c59fc38000360220200241f68180800036021820024101360204200241ab99c38000360200200241106a4284b2a2d692ae8580b57f370300200241386a4100360200200241246a410136020020014102360248200120023602402001200241c0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a22032001411c6a220241086a28020036020020012002290200370300200128021021042001280214210520012802182106200129022c21072001280228210820014100360218200142808080808001370210200141106a410010a4868080002001280214200128021841386c6a2202420437022c20024206370224200241cae4c4800036022020024100360218200241a282808000360210200242afc2c78afea4cdde6c370308200242c9aaa6b382c5ade30a370300200128021821092001280214210220012001280210360248200120023602402001200236024420012002200941386c6a41386a36024c200141346a200141c0006a10f9868080002008418080808078460d012001200436021820012005360210200120053602142001200520064105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002008360238200041003a000020002001290300370350200041d8006a20032802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841c00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000bd80301057f23808080800041206b220224808080800041002d00fca3c680001a02400240410141002802c8a3c68000118180808000002203450d00200341053a000041002d00fca3c680001a410441002802c8a3c68000118180808000002204450d012002410c6a41086a22054100360200200220043602102002410436020c200241003602182002200241186a36021c2002411c6a2002410c6a10c08a808000200241086a220620052802003602002002200229020c3703000240200128020822042001280200470d0020012004109d86808000200128020821040b2001280204200441e8006c6a220442d6e1dd9492e0e8e8c900370328200442d7c9cb8fc1cf97db3e37031020044111360244200441f89ec38000360240200441a382808000360238200441b5808080003602202004410136020c2004200336020820044281808080103703002004200229030037034820042000290200370254200441306a42efbbaa8aaae9fdc9ab7f370300200441186a42e88488d0c0e3aebc13370300200441d0006a2006280200360200200441dc006a200041086a280200360200200441013a00602001200128020841016a360208200241206a2480808080000f0b4101410110b280808000000b4101410410b280808000000beb0503067f017e027f23808080800041d0006b2201248080808000200141286a419b9fc38000410a41a59fc380004120418097c38000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041c00041002802c8a3c68000118180808000002202450d00200242c4ccab9c81ebb4b8db00370308200241c59fc38000360220200241f08180800036021820024101360204200241ab99c38000360200200241106a42a4d2928ecac0faa432370300200241386a4100360200200241246a410136020020014102360248200120023602402001200241c0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a22032001411c6a220241086a28020036020020012002290200370300200128021021042001280214210520012802182106200129022c21072001280228210820014100360218200142808080808001370210200141106a410010a4868080002001280214200128021841386c6a2202420437022c20024206370224200241cae4c4800036022020024100360218200241a4828080003602102002429bc594f9e4cbe78bb87f37030820024299f3bffc9a86c097ea00370300200128021821092001280214210220012001280210360248200120023602402001200236024420012002200941386c6a41386a36024c200141346a200141c0006a10f9868080002008418080808078460d012001200436021820012005360210200120053602142001200520064105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002008360238200041003a000020002001290300370350200041d8006a20032802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841c00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000b950301037f41002d00fca3c680001a02400240410141002802c8a3c68000118180808000002202450d00200241023a000041002d00fca3c680001a412841002802c8a3c68000118180808000002203450d012003420037001820034200370000200341206a428080808080808080807f370000200341106a4200370000200341086a42003700000240200128020822042001280200470d0020012004109d86808000200128020821040b2001280204200441e8006c6a220442c4daf0e7d4cf86cca87f370328200442c4ccab9c81ebb4b8db00370310200441283602502004200336024c200442878080808005370244200441ea9ec380003602402004419982808000360238200441f0818080003602202004410136020c20042002360208200442818080801037030020042000290200370254200441013a0060200441306a42e1be86f0e3e6afc202370300200441186a42a4d2928ecac0faa432370300200441dc006a200041086a2802003602002001200128020841016a3602080f0b4101410110b280808000000b4101412810b280808000000be70301057f23808080800041206b220224808080800041002d00fca3c680001a02400240410141002802c8a3c68000118180808000002203450d00200341023a000041002d00fca3c680001a410441002802c8a3c68000118180808000002204450d012002410c6a41086a22054100360200200220043602102002410436020c200241003602182002200241186a36021c2002411c6a2002410c6a10c08a808000410841002002410c6a10d385808000200241086a220620052802003602002002200229020c3703000240200128020822042001280200470d0020012004109d86808000200128020821040b2001280204200441e8006c6a2204428f9acc9be4ab9dde977f370328200442c4ccab9c81ebb4b8db0037031020044105360244200441969fc38000360240200441a582808000360238200441f0818080003602202004410136020c2004200336020820044281808080103703002004200229030037034820042000290200370254200441306a42ba98e4d187d5e0d005370300200441186a42a4d2928ecac0faa432370300200441d0006a2006280200360200200441dc006a200041086a280200360200200441013a00602001200128020841016a360208200241206a2480808080000f0b4101410110b280808000000b4101410410b280808000000beb0503067f017e027f23808080800041d0006b2201248080808000200141286a419b9fc38000410a41a59fc380004120418097c38000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041c00041002802c8a3c68000118180808000002202450d002002428291fa9e999aa9d246370308200241c59fc38000360220200241ee8180800036021820024101360204200241ab99c38000360200200241106a42bc90c1fdf28f8bb0ff00370300200241386a4100360200200241246a410136020020014102360248200120023602402001200241c0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a22032001411c6a220241086a28020036020020012002290200370300200128021021042001280214210520012802182106200129022c21072001280228210820014100360218200142808080808001370210200141106a410010a4868080002001280214200128021841386c6a2202420437022c20024206370224200241cae4c4800036022020024100360218200241a6828080003602102002429bc4fd96a6cbbfd7ed003703082002429db1fdedf2d2e1d1f500370300200128021821092001280214210220012001280210360248200120023602402001200236024420012002200941386c6a41386a36024c200141346a200141c0006a10f9868080002008418080808078460d012001200436021820012005360210200120053602142001200520064105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002008360238200041003a000020002001290300370350200041d8006a20032802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841c00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000bea0503067f017e027f23808080800041d0006b2201248080808000200141286a419b9fc38000410a41a59fc380004120418097c38000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041c00041002802c8a3c68000118180808000002202450d002002429ca0fdd992b0ed90df00370308200241c59fc38000360220200241ed8180800036021820024101360204200241ab99c38000360200200241106a42bbf8f5b8b9e2c39ac400370300200241386a4100360200200241246a410136020020014102360248200120023602402001200241c0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a22032001411c6a220241086a28020036020020012002290200370300200128021021042001280214210520012802182106200129022c21072001280228210820014100360218200142808080808001370210200141106a410010a4868080002001280214200128021841386c6a2202420437022c20024206370224200241cae4c4800036022020024100360218200241a782808000360210200242eab19fb291b0f9fb0c370308200242d39ec9badc8ccad845370300200128021821092001280214210220012001280210360248200120023602402001200236024420012002200941386c6a41386a36024c200141346a200141c0006a10f9868080002008418080808078460d012001200436021820012005360210200120053602142001200520064105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002008360238200041003a000020002001290300370350200041d8006a20032802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841c00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000bca0704067f017e017f017e23808080800041d0006b2201248080808000200141286a41c69fc38000411141d79fc380004114418097c38000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041c00041002802c8a3c68000118180808000002202450d00200242c194a6a793ccc3a857370308200241ec9fc38000360220200241f58180800036021820024101360204200241eb9fc38000360200200241306a4293888c8f89fdc6ec9e7f370300200241286a42a5e9e3ab9e929adc2c370300200241106a42ab8bffbed784ffa5937f370300200241386a41ef80808000360200200241246a410136020020014102360248200120023602402001200241c0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a2001411c6a220241086a2802003602002001200229020037030020012802102103200128021421042001280218210520012802282106200129022c2107200141106a41086a22084100360200200142808080808001370210200141106a410010a4868080002001280214200828020041386c6a2202420437022c20024205370224200241f6a4c580003602202002410636021c200241f0a4c58000360218200241ef8080800036021020024293888c8f89fdc6ec9e7f370308200242a5e9e3ab9e929adc2c370300200141c0006a41086a200828020041016a2202360200200120012902102209370340024020022009a7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c2002421237022420024187a5c580003602202002410c36021c200241fba4c58000360218200241a882808000360210200242ef88c9d3f691f5f30b370308200242e0c4f8e5b8f790b077370300200128024821082001280244210220012001280240360248200120023602402001200236024420012002200841386c6a41386a36024c200141346a200141c0006a10f9868080002006418080808078460d012001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002006360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841c00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000bde0503057f017e027f23808080800041d0006b2201248080808000200141286a41ed9fc38000410c41d79fc380004114418097c38000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041c00041002802c8a3c68000118180808000002202450d00200242c194a6a793ccc3a857370308200241ec9fc38000360220200241f58180800036021820024101360204200241eb9fc38000360200200241306a4293888c8f89fdc6ec9e7f370300200241286a42a5e9e3ab9e929adc2c370300200241106a42ab8bffbed784ffa5937f370300200241386a41ef80808000360200200241246a410136020020014102360248200120023602402001200241c0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a2203200141106a410c6a220241086a28020036020020012002290200370300200128021021042001280214210220012802182105200129022c2106200128022821072001410036021820014280808080c000370210200141c0006a200141106a41f99fc38000410710b88b808000200141346a200141c0006a4180a0c38000410910bf8b8080002001200128023436021820012001280238220836021020012008200128023c41246c6a36021c20012008360214200141c0006a200141106a10fb868080002007418080808078460d012001200436021820012002360210200120023602142001200220054105746a36021c200041c4006a200141106a10fa868080002001411b6a200141c0006a41086a2802003600002000413c6a200637020020002007360238200041013a000020002001290300370350200041d8006a20032802003602002001200129024037001320002001290010370001200041086a200141106a41076a290000370000200141d0006a2480808080000f0b410841c00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000b2100200128021441d4abc380004114200141186a28020028020c118280808000000b2100200128021441e8abc38000410f200141186a28020028020c118280808000000b920601087f024002402002450d00200120026a2106200341016a210741002108200121090240034002400240200820044b0d0020092d0000210a02402008450d000240024020084101710d002003210b0c010b200320032d0000410874200a72220a200a413a6e220a413a6c6b3a00002007210b0b20084101460d00200320086a210c0340200b200b2d0000410874200a6a220a200a413a6e220a413a6c6b3a0000200b41016a220d200d2d0000410874200a6a220a200a413a6e220a413a6c6b3a0000200b41026a220b200c470d000b0b200a450d0120082004200820044b1b210c034020042008460d040240200c2008460d00200320086a200a200a413a6e220b413a6c6b3a0000200841016a2108200a413a49210d200b210a200d0d030c010b0b200c200441a4a1c3800010f980808000000b200820044194a1c38000109581808000000b200941016a22092006470d000b20082004200820044b1b210a0240034020012d00000d0120042008460d020240200a2008460d00200141016a2101200320086a41003a0000200841016a21082002417f6a22020d010c020b0b200a20044184a1c3800010f980808000000b0240200820044b0d002008450d02200320086a21044100210a024003402003200a6a220d2d0000220b413a4f0d01200d2005200b6a4180016a2d00003a00002008200a41016a220a470d000b4100210a20084102490d042004200841017622016b21024100210a4100210b024020014101460d002008417f6a210d200141feffffff077121064100210b03402003200d6a220c2d00002109200c2003200b6a22042d00003a0000200420093a000020022001200b417e736a6a220c2d00002109200c200441016a22042d00003a0000200420093a0000200d417e6a210d2006200b41026a220b470d000b0b2008410271450d042003200b6a220d2d00002104200d20022001200b417f736a6a220b2d00003a0000200b20043a00000c040b200b413a41f4a0c3800010f980808000000b2008200441e4a0c38000109581808000000b4101210a0c010b410021084100210a0b200020083602042000200a3602000b02000b02000b8d0201037f23808080800041106b2202248080808000410121032001280214418fa5c080004101200141186a28020028020c118280808000002104200241003a0009200220043a0008200220013602042002200036020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041016a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041026a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041036a36020c200241046a2002410c6a41d0cfc48000108e818080001a024020022d00080d00200228020422002802144190a5c080004101200041186a28020028020c1182808080000021030b200241106a24808080800020030ba90901037f23808080800041106b2202248080808000410121032001280214418fa5c080004101200141186a28020028020c118280808000002104200241003a0009200220043a0008200220013602042002200036020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041016a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041026a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041036a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041046a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041056a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041066a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041076a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041086a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041096a36020c200241046a2002410c6a41d0cfc48000108e818080001a20022000410a6a36020c200241046a2002410c6a41d0cfc48000108e818080001a20022000410b6a36020c200241046a2002410c6a41d0cfc48000108e818080001a20022000410c6a36020c200241046a2002410c6a41d0cfc48000108e818080001a20022000410d6a36020c200241046a2002410c6a41d0cfc48000108e818080001a20022000410e6a36020c200241046a2002410c6a41d0cfc48000108e818080001a20022000410f6a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041106a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041116a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041126a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041136a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041146a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041156a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041166a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041176a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041186a36020c200241046a2002410c6a41d0cfc48000108e818080001a2002200041196a36020c200241046a2002410c6a41d0cfc48000108e818080001a20022000411a6a36020c200241046a2002410c6a41d0cfc48000108e818080001a20022000411b6a36020c200241046a2002410c6a41d0cfc48000108e818080001a20022000411c6a36020c200241046a2002410c6a41d0cfc48000108e818080001a20022000411d6a36020c200241046a2002410c6a41d0cfc48000108e818080001a20022000411e6a36020c200241046a2002410c6a41d0cfc48000108e818080001a20022000411f6a36020c200241046a2002410c6a41d0cfc48000108e818080001a024020022d00080d00200228020422002802144190a5c080004101200041186a28020028020c1182808080000021030b200241106a24808080800020030b210020012802144180a2c38000410e200141186a28020028020c118280808000000bf20302037f037e2380808080004180086b22032480808080002003200136028c022003410036028802200320023602840202400240200228020422014108490d002002200141786a220436020420022002280200220541086a3602002004450d00200529000021062002200141776a3602042002200541096a36020002400240024020052d00080e020001030b20034180066a20034184026a10f988808000420021072003290380064200520d0220034188046a20034188066a41f80110848e8080001a0c010b20034180066a20034184026a10f9888080002003290380064200520d0120034188046a20034188066a41f80110848e8080001a420121070b20034190026a20034188046a41f80110848e8080001a200320034184026a10bc8a80800020032802000d0020034180066a20034184026a200328020410d0858080002003280280062201418080808078460d0020033502880621082003280284062105200341086a20034190026a41f80110848e8080001a024020022802040d0020002007370300200041086a200341086a41f80110848e8080001a20002008370390022000200536028c02200020013602880220002006370380020c020b200042023703002001450d01200541002802c0a3c68000118080808000000c010b200042023703000b20034180086a2480808080000b8d0101027f23808080800041306b2202248080808000200241146a42013702002002410236020c2002418ca4c38000360208200241e0818080003602242002411f36022c2002419ca4c38000360228200141186a28020021032002200241206a3602102002200241286a36022020012802142003200241086a10d9808080002101200241306a24808080800020010b8f0302047f017e23808080800041106b22012480808080004102210202400240024020002d0000220341726a0e020201000b20034102744184aec380006a28020021020c010b41014102200041026a2d000022024102491b4102410120024107461b20002d00011b41026a21020b41002d00fca3c680001a0240200241002802c8a3c68000118180808000002204450d002001200436020820012002360204024002402003410f460d00200441003a0000410121022001410136020c02402003410e470d0041012102024020012802044101470d00200141046a4101410110b182808000200128020c21020b200128020820026a41003a00002001200241016a36020c0c020b024020012802044101470d00200141046a4101410110b182808000200128020c21020b200128020820026a41013a00002001200241016a36020c2000200141046a10cc888080000c010b200441013a00002001410136020c200041016a200141046a10aa878080000b20012902082105200141106a24808080800020050f0b4101200210b280808000000bce0203037f017e017f23808080800041206b220124808080800041002d00fca3c680001a0240410141002802c8a3c68000118180808000002202450d002001200236020c200141013602080240024020002802002203418180808078470d00200241003a000042808080801021040c010b200241013a000020014101360210024002402003418080808078470d00200141146a2000280204200041086a28020010b4828080000c010b200141146a2000280204200028020810e6848080000b41012100200128021821050240200128021c2203450d00200141086a4101200310b182808000200128020c2102200128021021000b200220006a2005200310848e8080001a200020036a210002402001280214450d00200541002802c0a3c68000118080808000000b2000ad42208621040b200141206a24808080800020042002ad840f0b4101410110b280808000000b8a0302057f017e23808080800041106b2201248080808000024002400240024002400240024020002802102202418080808078470d004101410220002d000122034102491b4102410120034107461b20002d00001b41026a21030c010b417f417f200041246a280200410c6c417f200041186a280200410c6c2203410c6a22042004200341046a491b22036a41046a220420042003491b220341096a220420042003491b41016a2203450d012003417f4c0d040b4100210541002d00fca3c680001a200341002802c8a3c68000118180808000002204450d0420012004360208200120033602042002418080808078470d01200441013a00002001410136020c2000200141046a10aa878080000c020b2001410036020c2001428080808010370204200141046a4100410110b18280800020012802082104200128020c21050b200420056a41003a00002001200541016a36020c2000200141046a10a9878080000b20012902082106200141106a24808080800020060f0b10ae80808000000b4101200310b280808000000b970501047f23808080800041d0066b220224808080800041002d00fca3c680001a0240024041800341002802c8a3c68000118180808000002203450d0020024198046a41086a2001280228220441086a29000037030020024198046a41106a200441106a29000037030020024198046a41186a200441186a2900003703002002200429000037039804200241bc046a41086a4120360200200220043602c004200241003602bc042002418c026a200120024198046a200241bc046a41d8efc08000410110e28780800002400240200228028c0222014105460d002002280290022105200241086a2002418c026a41086a41810210848e8080001a200241c8046a200241086a41e00110848e8080001a200241a8066a41206a20024188026a2d00003a0000200241a8066a41186a20024180026a290200370300200241a8066a41106a200241086a41f0016a290200370300200241a8066a41086a200241f0016a290200370300200220022902e8013703a80641002d00fca3c680001a41f00141002802c8a3c68000118180808000002204450d032004200536020c200420013602082004428180808010370200200441106a200241c8046a41e00110848e8080001a200320043602082003410036020020004200370234200041013602082000200336020420004108360200200320022903a80637000c200341146a200241a8066a41086a2903003700002003411c6a200241a8066a41106a290300370000200341246a200241c0066a2903003700002003412c6a200241c8066a2d00003a00000c010b2002280290022104200041808080807836020020002004360204200341002802c0a3c68000118080808000000b200241d0066a2480808080000f0b410441800310b280808000000b410441f00110b280808000000bfc3303127f017e017f23808080800041e0026b22032480808080000240024020012802082204450d00200141106a2105200141346a21062001410c6a2107200341086a41e8016a2108200341086a41086a2109200341086a41046a210a03402001280204220b2004417f6a220c41306c6a210403402004280208220d41ec016a280200210e200d41e8016a280200210f024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024020042802000e050300010210030b200d280208417e6a0e03040506030b2004280204210c200d280208220b417d6a22100e020908020b200d2802080e050c0c090a0b0c0b200441014103200b200c41306c6a220d280208280208417e6a4103491b360200200128020c210c2001280210210e20012802342104200341086a41286a220f4100360200200341086a200c2007200441284b220b1b220c200c200e2004200b1b6a10f686808000200341a0026a41286a200f280200360200200341a0026a41206a200341086a41206a290200370300200341a0026a41186a200341086a41186a290200370300200341a0026a41106a200341086a41106a290200370300200341a0026a41086a2009290200370300200320032902083703a002200320012802383602cc02200341086a200d280208220441086a200441e8016a280200200441ec016a28020010f48d8080002003280208417f6a0e040d100f0e100b418ca6c3800041e60041f4a6c3800010f880808000000b200d41106a280200220c200d410c6a280200220b490d11200c200e4b0d12200f200b6a2111200c200b6b210b200d41146a2802002210410176210c0240024020104101710d00410021120240200c200b4b0d00200c21104100210c0c020b200c200b41d492c68000109481808000000b200c200b4f0d1441012112200c41016a21102011200c6a2d0000410f71210c0b2003200c3a0009200320123a00082003200b20106b3602102003201120106a36020c2007200341086a10e28d80800020042d000c4101710d02200341a0026a41186a4200370300200341a0026a41106a4200370300200341a0026a41086a4200370300200342003703a0020c030b2001280234210d024002402001280238220c4101710d000240024020052006200d41284b220e1b220c280200220f200d4128200e1b460d0020072802002007200e1b210d0c010b200710f78d8080002005280200210f2007280200210d2005210c0b200d200f6a41003a0000200c200c28020041016a3602002001280238210c0c010b2005280200200d200d41284b1b450d140b2001200c41016a3602384103210c2004280208210e02400240024002400240024020042802000e0400010203490b41014103200e280208417e6a4103491b210c0c480b41024103200e280208417d6a4102491b210c4100210d0c470b2004280204210f200e280208417d6a0e020102460b4104210c0c450b200f410e4b0d440c430b200f410f490d420c430b200d41106a280200220c200d410c6a280200220b490d13200c200e4b0d14200f200b6a210f200c200b6b210c200d41146a280200220e410176210d02400240200e4101710d004100210b0240200d200c4b0d00200d210e4100210d0c020b200d200c41d492c68000109481808000000b200d200c4f0d164101210b200d41016a210e200f200d6a2d0000410f71210d0b2003200d3a00092003200b3a00082003200c200e6b3602102003200f200e6a36020c2007200341086a10e28d8080002001280234210d024002402001280238220c4101710d000240024020052006200d41284b220e1b220c280200220f200d4128200e1b460d0020072802002007200e1b210d0c010b200710f78d8080002005280200210f2007280200210d2005210c0b200d200f6a41003a0000200c200c28020041016a3602002001280238210c0c010b2005280200200d200d41284b1b450d170b2001200c41016a3602384103210c2004280208210e02400240024002400240024020042802000e0400010203460b41014103200e280208417e6a4103491b210c0c450b41024103200e280208417d6a4102491b210c4100210d0c440b2004280204210f200e280208417d6a0e020102430b4104210c0c420b200f410e4b0d410c400b200f410f490d3f0c400b200341a0026a41186a200441256a290000370300200341a0026a41106a2004411d6a290000370300200341a0026a41086a200441156a29000037030020032004410d6a2900003703a0020b200d41206a280200210c200d411c6a280200210b02400240200d41186a2802000d00200c200b490d174100210d200c200e4d0d01200c200e41e49dc68000109581808000000b200c200b490d174101210d200c200e4b0d180b2003200d360294022003200c200b6b36029c022003200f200b6a360298022001280238220c410176210d02400240200c4101710d0020052802002006280200220c200c41284b220c1b220e200d490d1a20072802002007200c1b210c4100210e0c010b20052802002006280200220c200c41284b220e1b220c200d490d1a200c200d4d0d1b200320072802002007200e1b220c200d6a2d000041f001713a00dd024101210e0b2003200e3a00dc022003200d3602d8022003200c3602d402200341086a2002200341a0026a20034194026a200341d4026a410110e287808000024020032802084105460d0041002d00fca3c680001a41f00141002802c8a3c6800011818080800000220d450d1c200d428180808010370200200d41086a200341086a41e80110848e8080001a0240200128020822042001280200470d0020012004109886808000200128020821040b2001280204200441306c6a2204200d360208200441003602002004200829020037020c200441146a200841086a2902003702002004411c6a200841106a290200370200200441246a200841186a2902003702002004412c6a200841206a2d00003a0000200128020841016a210d0c3d0b4103210a2004280208210d02400240024002400240024020042802000e0400010203400b41014103200d280208417e6a4103491b210a0c3f0b41024103200d280208417d6a4102491b210a410021010c3e0b2004280204210c200d280208417d6a0e0201023d0b4104210a0c3c0b200c410e4b0d3b0c3a0b200c410f490d390c3a0b4106210b0b200c410f4b0d1a024002400240200d200b4102746a200c410c6c6a410c6a220d2802004102460d0002400240024020012802382210450d0020052006200628020041284b220b1b2802002211450d21200141104134200b1b6a2011417f6a2211360200200128020c22122007200b1b20116a2d0000211120012010417f6a220b3602380240200b410171450d00201141f00171211302400240200520062006280200221441284b22101b220b28020022112014412820101b460d002012200720101b21100c010b200710f78d80800020052802002111200728020021102005210b0b201020116a20133a0000200b200b28020041016a3602002001280238210b0b200b4101710d010b200c410474211102400240200520062006280200221241284b220b1b220c280200221020124128200b1b460d0020072802002007200b1b210b0c010b200710f78d808000200528020021102007280200210b2005210c0b200b20106a20113a0000200c200c28020041016a3602000c010b20052802002006280200220b200b41284b220b1b2210450d20201020072802002007200b1b6a417f6a220b200b2d0000200c723a00000b2001200128023841016a221036023820042d000c4101710d01200341a0026a41186a4200370300200341a0026a41106a4200370300200341a0026a41086a4200370300200342003703a0020c020b4103210e0240024020100e0200013a0b200c410e4b0d390c380b200c410f490d370c380b200341a0026a41186a200441256a290000370300200341a0026a41106a2004411d6a290000370300200341a0026a41086a200441156a29000037030020032004410d6a2900003703a0020b200d41086a280200210c200d280204210b02400240200d2802000d00200c200b490d1f4100210d200c200e4d0d01200c200e41e49dc68000109581808000000b200c200b490d1f4101210d200c200e4b0d200b2003200d360294022003200c200b6b36029c022003200f200b6a360298022010410176210d0240024020104101710d0020052802002006280200220c200c41284b220c1b220e200d490d2220072802002007200c1b210c4100210e0c010b20052802002006280200220c200c41284b220e1b220c200d490d22200c200d4d0d23200320072802002007200e1b220c200d6a2d000041f001713a00dd024101210e0b2003200e3a00dc022003200d3602d8022003200c3602d402200341086a2002200341a0026a20034194026a200341d4026a410110e287808000024020032802084105460d0041002d00fca3c680001a41f00141002802c8a3c6800011818080800000220d450d24200d428180808010370200200d41086a200341086a41e80110848e8080001a0240200128020822042001280200470d0020012004109886808000200128020821040b2001280204200441306c6a2204200d360208200441003602002004200829020037020c200441146a200841086a2902003702002004411c6a200841106a290200370200200441246a200841186a2902003702002004412c6a200841206a2d00003a0000200128020841016a210d0c3b0b4103210a2004280208210d02400240024002400240024020042802000e04000102033a0b41014103200d280208417e6a4103491b210a0c390b41024103200d280208417d6a4102491b210a410021010c380b2004280204210c200d280208417d6a0e020102370b4104210a0c360b200c410e4b0d350c340b200c410f490d330c340b2007200d41106a280200200d410c6a2802006b410174200d41146a2802006b10e08d8080000c020b2001280238220d450d0120052006200628020041284b22041b280200220c450d2220014110413420041b6a200c417f6a220c360200200128020c220e200720041b200c6a2d0000210c2001200d417f6a22043602382004410171450d01200c41f00171210f02400240200520062006280200220b41284b220d1b2204280200220c200b4128200d1b460d00200e2007200d1b210d0c010b200710f78d8080002005280200210c2007280200210d200521040b200d200c6a200f3a00002004200428020041016a3602000c010b2007200d41106a280200200d410c6a2802006b410174200d41146a2802006b41016a10e08d8080000b20012802082204450d3e4103210c20012802042004417f6a41306c6a2204280208210e02400240024002400240024020042802000e0400010203340b41014103200e280208417e6a4103491b210c0c330b41024103200e280208417d6a4102491b210c4100210d0c320b2004280204210f200e280208417d6a0e020102310b4104210c0c300b200f410e4b0d2f0c2e0b200f410f490d2d0c2e0b2001200c360208200341a0026a41086a220d200b200c41306c6a2204410c6a290200370300200341a0026a41106a220c200441146a290200370300200341a0026a41186a220e2004411c6a290200370300200341a0026a41206a220f200441246a290200370300200341a0026a41286a220b2004412c6a280200360200200320042902043703a002200428020022044105460d2b200a20032903a002370200200a41286a200b280200360200200a41206a200f290300370200200a41186a200e290300370200200a41106a200c290300370200200a41086a200d290300370200200320043602082003280210220420042802002204417f6a360200024020044101470d00200910e18a8080000b20012802082204450d3d4103210c20012802042004417f6a41306c6a2204280208210e02400240024002400240024020042802000e0400010203300b41014103200e280208417e6a4103491b210c0c2f0b41024103200e280208417d6a4102491b210c4100210d0c2e0b2004280204210f200e280208417d6a0e0201022d0b4104210c0c2c0b200f410e4b0d2b0c2a0b200f410f490d290c2a0b2003280214220e410176210d200329021c2115200328021821042003280210210c200328020c210f02400240200e4101710d004100210b0240200d200c4b0d00200d210e4100210d0c020b200d200c41d492c68000109481808000000b200d200c4f0d204101210b200d41016a210e200f200d6a2d0000410f71210d0b2003200d3a00d5022003200b3a00d4022003200c200e6b3602dc022003200f200e6a3602d802200341a0026a200341d4026a10e28d8080000c040b2003280214220e410176210d20032902dc01211520032802d80121042003280210210c200328020c210f02400240200e4101710d004100210b0240200d200c4b0d00200d210e4100210d0c020b200d200c41d492c68000109481808000000b200d200c4f0d204101210b200d41016a210e200f200d6a2d0000410f71210d0b2003200d3a00d5022003200b3a00d4022003200c200e6b3602dc022003200f200e6a3602d802200341a0026a200341d4026a10e28d80800020044102460d010c030b20032802cc0122044102470d010b20032802c8024129490d2420032802a00241002802c0a3c68000118080808000000c240b20032902d00121150b20032802cc02220c410176210d02400240200c410171220b0d0020032802a40220032802c802220e200e41284b220e1b220f200d490d1e20032802a002200341a0026a200e1b210f0c010b20032802a40220032802c802220e200e41284b220f1b220e200d490d1e200e200d4d0d1f20032802a002200341a0026a200f1b220f200d6a2d000041707121160b4101210e0240200c4102490d0041002d00fca3c680001a200d41002802c8a3c6800011818080800000220e450d200b200e200f200d10848e808000210e024020032802c8024129490d0020032802a00241002802c0a3c68000118080808000000b20044103460d2220044102460d2e0240200b450d0041002d00fca3c680001a413041002802c8a3c68000118180808000002201450d21200120163a00102001200d36020c2001200e3602082001200d36020420014186808080783602002000200136020420004180808080783602000c390b2015422088a7210a2015a7210102400240024020040d002003200a4100109686808000200328020021042003280204220c2001200a10848e8080001a0c010b200341003a00a8022003200d3602a4022003200e3602a002200a4120470d23200341086a41186a200141186a290000370300200341086a41106a200141106a290000370300200341086a41086a200141086a29000037030020032001290000370308200341d4026a2002200341086a200341a0026a10e18780800020032802d4022204418080808078460d0120032802dc02210a20032802d802210c0b2000200a3602142000200c3602102000200436020c2000200d3602082000200e3602042000200d3602000c390b200020032802d8023602042000418080808078360200200c4102490d38200e41002802c0a3c68000118080808000000c380b200b200c41849ec68000109681808000000b200c200e41849ec68000109581808000000b200c200b41e492c6800010f980808000000b419c94c68000413a41d894c6800010a181808000000b200b200c41849ec68000109681808000000b200c200e41849ec68000109581808000000b200d200c41e492c6800010f980808000000b419c94c68000413a41d894c6800010a181808000000b200b200c41e49dc68000109681808000000b200b200c41f49dc68000109681808000000b200c200e41f49dc68000109581808000000b200d200e41ac95c68000109581808000000b200d200c41bc95c68000109581808000000b200d200c41cc95c6800010f980808000000b410441f00110b280808000000b200c411041fca5c3800010f980808000000b41e894c680004122418c95c6800010a181808000000b419c94c68000413a41d894c6800010a181808000000b200b200c41e49dc68000109681808000000b200b200c41f49dc68000109681808000000b200c200e41f49dc68000109581808000000b200d200e41ac95c68000109581808000000b200d200c41bc95c68000109581808000000b200d200c41cc95c6800010f980808000000b410441f00110b280808000000b41e894c680004122418c95c6800010a181808000000b200d200c41e492c6800010f980808000000b200d200c41e492c6800010f980808000000b200d200f41ac95c68000109581808000000b200d200e41bc95c68000109581808000000b200d200e41cc95c6800010f980808000000b4101200d10b280808000000b4104413010b280808000000b4120200a419ca5c3800010a281808000000b200128020822040d130c140b200f41016a210d4102210c0b2004200d3602042004200c3602002001280208210d0c0f0b41aca5c3800041cd004184a7c3800010a181808000000b200f41016a210d4102210c0b2004200d3602042004200c3602002001280208210d0c0c0b200c41016a21014102210a0b200328020c210d200420013602042004200a3602000c040b200c41016a210d4102210e0b2004200d3602042004200e3602002001280208210d0c080b200c41016a21014102210a0b200328020c210d200420013602042004200a3602000b2000200d36020420004180808080783602000c090b2001200d3602080c040b200f41016a210d4102210c0b2004200d3602042004200c3602002001280208210d0c020b200f41016a210d4102210c0b2004200d3602042004200c3602002001280208210d0b2001280204220b200d417f6a220c41306c6a2104200d0d000b0b0b20004181808080783602000b200341e0026a2480808080000b930201027f23808080800041106b220224808080800020022000360200200220012802144194a7c38000410e200141186a28020028020c118280808000003a000c20022001360208200241003a000d20024100360204200241046a200241a4a7c38000108d81808000210120022d000c210002400240200128020022030d00200041ff017141004721010c010b41012101200041ff01710d0020022802082100024020034101470d0020022d000d41ff0171450d0020002d001c4104710d00410121012000280214418ca5c080004101200041186a28020028020c118280808000000d010b2000280214418da5c080004101200041186a28020028020c1182808080000021010b200241106a24808080800020010baf0301027f23808080800041206b220324808080800002400240024010fa81808000220441ff01490d00200041093b0100024002400240024020022d00000e0400010203060b200241086a21020c040b200241086a21020c030b200241086a21020c020b200241046a21020c010b2003200441016a36020841b1e3c080004113200341086a410441002802e0a1c680001186808080000041002802e8a1c6800011888080800000200341086a41106a200241106a280200360200200341086a41086a200241086a29020037030020032002290200370308200341086a10f58880800041002802b0a1c68000118880808000002000410e3a0000200341086a10fb818080000c010b2002280200450d00200228020441002802c0a3c68000118080808000000b200128020022022002280200417f6a2201360200024020010d00200241086a28020022002002410c6a28020022012802001180808080000002402001280204450d00200041002802c0a3c68000118080808000000b200241046a22012001280200417f6a220136020020010d00200241002802c0a3c68000118080808000000b200341206a2480808080000bdf0201027f23808080800041206b22032480808080000240024010fa81808000220441fe014b0d002003200441016a36020c41b1e3c0800041132003410c6a410441002802e0a1c680001186808080000041002802e8a1c68000118880808000002003410c6a2002410010b8888080002000200329020c370200200041086a2003410c6a41086a290200370200200041106a2003410c6a41106a28020036020041b0a1c6800041d0a1c6800020032d000c410e461b280200118880808000002003410c6a10fb818080000c010b200041093b01000b200128020022002000280200417f6a2201360200024020010d00200041086a28020022022000410c6a28020022012802001180808080000002402001280204450d00200241002802c0a3c68000118080808000000b200041046a22012001280200417f6a220136020020010d00200041002802c0a3c68000118080808000000b200341206a2480808080000bc60301087f23808080800041306b220324808080800020032001360200024002400240024002402001450d00200341246a21044101210541002106410021070340200341046a2005200741002802c0a1c680001185808080000020032802042208418080808078460d02200341186a20032802082209200328020c220741002802b8a1c680001185808080000002402003280218220a450d002004200328021c2003280220200a28020c118580808000000b02402006450d00200541002802c0a3c68000118080808000000b20092105200821062001417f6a22010d000b20020d022000410e3a00002008450d04200941002802c0a3c68000118080808000000c040b20020d012000410e3a00000c030b2002450d012000410e3a00002006450d02200541002802c0a3c68000118080808000000c020b200341246a42003702002003410136021c200341b8a7c380003602182003418097c38000360220200341186a41b4a8c3800010f680808000000b200341246a42013702002003410236021c200341e8a8c3800036021820034185808080003602142003200341106a36022020032003360210200341186a41f8a8c3800010f680808000000b200341306a2480808080000bdf0201027f23808080800041206b22032480808080000240024010fa81808000220441fe014b0d002003200441016a36020c41b1e3c0800041132003410c6a410441002802e0a1c680001186808080000041002802e8a1c68000118880808000002003410c6a2002410110b8888080002000200329020c370200200041086a2003410c6a41086a290200370200200041106a2003410c6a41106a28020036020041b0a1c6800041d0a1c6800020032d000c410e461b280200118880808000002003410c6a10fb818080000c010b200041093b01000b200128020022002000280200417f6a2201360200024020010d00200041086a28020022022000410c6a28020022012802001180808080000002402001280204450d00200241002802c0a3c68000118080808000000b200041046a22012001280200417f6a220136020020010d00200041002802c0a3c68000118080808000000b200341206a2480808080000bb70e02047f017e23808080800041106b220224808080800002400240024002400240024002400240024002400240024002402000280200417f6a0e0c000102030405060708090a0b000b0240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a41003a0000200041086a200110df898080000c0b0b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41013a00002001200341016a360208200041086a280200210420022000410c6a28020022003602082002200241086a36020c2002410c6a200110c08a80800002402001280200200128020822036b20004f0d0020012003200010b182808000200128020821030b200128020420036a2004200010848e8080001a2001200320006a3602080c0a0b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41023a00002001200341016a360208200041146a28020021052002200041186a28020022033602082002200241086a36020c2002410c6a200110c08a80800002402001280200200128020822046b20034f0d0020012004200310b182808000200128020821040b200128020420046a2005200310848e8080001a2001200420036a360208200041046a200110c98c8080000c090b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41033a00002001200341016a360208200041086a280200210520022000410c6a28020022033602082002200241086a36020c2002410c6a200110c08a80800002402001280200200128020822046b20034f0d0020012004200310b182808000200128020821040b200128020420046a2005200310848e8080001a2001200420036a360208200041146a28020021042002200041186a28020022003602082002200241086a36020c2002410c6a200110c08a80800002402001280200200128020822036b20004f0d0020012003200010b182808000200128020821030b200128020420036a2004200010848e8080001a2001200320006a3602080c080b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41043a00002001200341016a360208200041086a280200210420022000410c6a28020022003602082002200241086a36020c2002410c6a200110c08a80800002402001280200200128020822036b20004f0d0020012003200010b182808000200128020821030b200128020420036a2004200010848e8080001a2001200320006a3602080c070b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41053a00002001200341016a360208200041086a280200210420022000410c6a28020022003602082002200241086a36020c2002410c6a200110c08a80800002402001280200200128020822036b20004f0d0020012003200010b182808000200128020821030b200128020420036a2004200010848e8080001a2001200320006a3602080c060b0240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a41063a0000200041046a200110898d8080000c050b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41073a00002001200341016a2203360208200029030821060240200128020020036b41074b0d0020012003410810b182808000200128020821030b2001200341086a360208200128020420036a20063700000c040b0240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a41083a00000c030b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41093a00002001200341016a2203360208200028020421000240200128020020036b41034b0d0020012003410410b182808000200128020821030b2001200341046a360208200128020420036a20003600000c020b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a410a3a00002001200341016a2203360208200028020421000240200128020020036b41034b0d0020012003410410b182808000200128020821030b2001200341046a360208200128020420036a20003600000c010b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a410b3a00002001200341016a2203360208200028020421000240200128020020036b41034b0d0020012003410410b182808000200128020821030b2001200341046a360208200128020420036a20003600000b200241106a2480808080000bf50102017f057e23808080800041b0026b2202248080808000024002402001280200410a460d004200210342e40021040c010b20013502042104200241086a10e1898080002004200241a8026a29030022032003428094ebdc03802203428094ebdc037e7d7e2205428094ebdc03802206200320047e7c20052006428094ebdc037e7d4280cab5ee0156ad7c2103200420022903a00222052005428094ebdc03802205428094ebdc037e7d7e2206428094ebdc03802207200520047e7c20062007428094ebdc037e7d4280cab5ee0156ad7c21040b200041003b01102000200337030820002004370300200241b0026a2480808080000b8e0301047f23808080800041306b22012480808080002001410036020c20014280808080800137020441002d00fca3c680001a0240410441002802c8a3c680001181808080000022020d004101410410b280808000000b2001411c6a41086a22034100360200200120023602202001410436021c200141003602282001200141286a36022c2001412c6a2001411c6a10c08a808000200141106a41086a220420032802003602002001200129021c370310200141046a4100109d868080002001280208200141046a41086a220328020041e8006c6a2202410b36024420024185bec38000360240200241a9828080003602182002410036020020022001290310370348200241013a00602002410036025c20024280808080c000370254200241d0006a200428020036020020024287bba5b8adf5dafa5b370308200241106a429595f4d085b899a1603703002003200328020041016a2202360200200041086a200236020020002001290204370200200041106a410d360200200041e8a6c4800036020c200141306a2480808080000bf20501047f2380808080004190016b2201248080808000200142f0fe93e98686d7ab8c7f37030820014280eee1b0e3b7afe9987f370300200141cc006a2001411041002802c0a1c680001185808080000002400240200128024c2202418080808078460d0020012802502103024020012802544110490d0020012003411010888e808000210402402002450d00200341002802c0a3c68000118080808000000b20040d010c020b2002450d00200341002802c0a3c68000118080808000000b41002102200141003b011e02400240417f4100280284a4c680002203410347200341034b1b2203450d00200341ff017141ff01470d010b200141286a410c6a41aa82808000360200200141838280800036022c2001410d360224200141e8a6c4800036022020012001411e6a3602302001200141206a3602284100280290a1c680002102410028028ca1c6800021034100280280a4c68000210420014184016a4202370200200141fc006a4103360200200141f4006a4116360200200141f0006a418cabc38000360200200141e4006a41c0a7c38000ad4280808080b00e84370200200141cc006a410c6a41b9a9c38000ad4280808080d0068437020020014180016a200141286a360200200141f4aac380003602782001410336026c200141003602602001410036025420014281808080e00437024c200341ecf2c08000200441024622041b200141cc006a200241d4f2c0800020041b2802101184808080000020012f011e21020b200141cc006a41e8a6c48000410d41002802a0a3c6800011858080800000200141cc006a41106a220341bccdc48000411541002802a0a3c6800011858080800000200141286a41186a200141cc006a41186a290000370300200141286a41106a2003290000370300200141286a41086a200141cc006a41086a2900003703002001200129004c370328200120023b014c200141286a4120200141cc006a410241002802e0a1c68000118680808000000b200042003703082000420037030020014190016a2480808080000beb0101037f23808080800041106b220224808080800002402001280200220328020020032802082204470d0020032004410110ab86808000200328020821040b200328020420046a41fb003a00002003200441016a3602082002200136020c20024180023b01080240200241086a41c0abc38000410b200010d88680800022030d002002280208220441ff01710d0020044180fe0371450d000240200228020c280200220428020020042802082201470d0020042001410110ab86808000200428020821010b200428020420016a41fd003a00002004200141016a3602080b200241106a24808080800020030b840d03017f0a7e047f23808080800041c0006b22022480808080000240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002402001280200417f6a0e0c000102030405060708090a0b000b200241186a200141206a2903002203370300200241106a200141186a2903002204370300200241086a200141106a2903002205370300200241206a200141286a2903002206370300200241286a200141306a2903002207370300200241306a200141386a2903002208370300200241386a200141c0006a290300220937030020022001290308220a370300200141c8006a290300210b200141d0006a290300210c200041c0006a2009370300200041386a2008370300200041306a2007370300200041286a2006370300200041206a2003370300200041186a2004370300200041106a20053703002000200a370308200041d0006a200c370300200041c8006a200b370300200041013602000c160b200141086a280200210d024002402001410c6a28020022010d004101210e0c010b2001417f4c0d0e41002d00fca3c680001a200141002802c8a3c6800011818080800000220e450d0f0b200e200d200110848e808000210d2000410c6a2001360200200041086a200d36020020002001360204200041023602000c150b200141146a280200210e02400240200141186a280200220d0d004101210f0c010b200d417f4c0d0d41002d00fca3c680001a200d41002802c8a3c6800011818080800000220f450d0f0b200f200e200d10848e808000210f418080808078210e2001280204418080808078460d0b200141086a28020021102001410c6a280200220e0d09410121010c0a0b200141086a28020021104101210f4101210e02402001410c6a280200220d450d00200d417f4c0d0c41002d00fca3c680001a200d41002802c8a3c6800011818080800000220e450d0f0b200e2010200d10848e808000210e2000410c6a200d360200200041086a200e3602002000200d360204200141146a280200210d0240200141186a2802002201450d002001417f4c0d0c41002d00fca3c680001a200141002802c8a3c6800011818080800000220f450d100b200f200d200110848e808000210d200041186a2001360200200041146a200d36020020002001360210200041043602000c130b200141086a280200210d024002402001410c6a28020022010d004101210e0c010b2001417f4c0d0b41002d00fca3c680001a200141002802c8a3c6800011818080800000220e450d100b200e200d200110848e808000210d2000410c6a2001360200200041086a200d36020020002001360204200041053602000c120b200141086a280200210d024002402001410c6a28020022010d004101210e0c010b2001417f4c0d0a41002d00fca3c680001a200141002802c8a3c6800011818080800000220e450d100b200e200d200110848e808000210d2000410c6a2001360200200041086a200d36020020002001360204200041063602000c110b02400240024002400240024020012d00040e050001020304000b200141056a280000210d200241086a2001410c6a108b87808000200241003a00002002200d3600010c040b200141056a280000210d200241086a2001410c6a108b87808000200241013a00002002200d3600010c030b200141056a280000210d200241086a2001410c6a108b87808000200241023a00002002200d3600010c020b200241046a200141086a108b87808000200241033a00000c010b200241043a00000b2000200229020037020420004107360200200041146a200241106a2802003602002000410c6a200241086a2902003702000c100b20004108360200200020012903083703080c0f0b200041093602000c0e0b2000410a360200200020012802043602040c0d0b2000410b360200200020012802043602040c0c0b2000410c360200200020012802043602040c0b0b200e417f4c0d0241002d00fca3c680001a200e41002802c8a3c68000118180808000002201450d090b200ead42208620012010200e10848e808000ad8421030b2000200d3602102000200e36020420004103360200200041186a200d360200200041146a200f360200200041086a20033703000c080b10ae80808000000b4101200110b280808000000b4101200d10b280808000000b4101200d10b280808000000b4101200110b280808000000b4101200110b280808000000b4101200110b280808000000b4101200e10b280808000000b200241c0006a2480808080000b8b1004057f017e037f087e23808080800041c0026b220224808080800002400240024002400240024002400240024002400240024002400240024002400240200128020022032802042204450d0020032004417f6a36020420032003280200220441016a36020020042d00000e0c0102030405060708090a0b0d0c0b200041003602000c0f0b024002402001280200220328020422044120490d002003200441606a220536020420032003280200220141206a220636020020024180026a41086a200141086a29000037030020024180026a41106a200141106a29000037030020024180026a41186a200141186a290000370300200220012900003703800220054120490d002003200441406a22053602042003200141c0006a360200200241a0026a41086a200641086a290000370300200241a0026a41106a200641106a290000370300200241a0026a41186a200641186a290000370300200220062900003703a00220054108490d002003200441b87f6a22063602042003200141c8006a36020020064108490d00200129004021072003200441b07f6a3602042003200141d0006a360200200241c0016a41206a220320022903a002370300200241c0016a41086a220420024180026a41086a290300370300200241c0016a41106a220620024180026a41106a290300370300200241c0016a41186a220520024180026a41186a290300370300200241c0016a41286a2208200241a0026a41086a290300370300200241c0016a41306a2209200241a0026a41106a290300370300200241c0016a41386a220a200241a0026a41186a29030037030020022002290380023703c0012001290048210b20024180016a41386a2201200a29030037030020024180016a41306a2009290300220c37030020024180016a41286a2008290300220d37030020024180016a41206a2003290300220e37030020024180016a41186a2005290300220f37030020024180016a41106a2006290300221037030020024180016a41086a20042903002211370300200220022903c001221237038001200241f0006a200c370200200241e8006a200d370200200241e0006a200e370200200241d8006a200f370200200241d0006a2010370200200241c8006a2011370200200241f8006a200129030037020020022012370240200041046a2002413c6a41c40010848e8080001a2000200b37035020002007370348410121030c010b410021030b200020033602000c0e0b200241086a200110bc8a808000024020022802080d002002413c6a2001200228020c10d085808000200228023c418080808078460d002000200229023c3702042000410c6a200241c4006a280200360200200041023602000c0e0b200041003602000c0d0b200241106a200110bc8a80800020022802100d0a2002413c6a2001200228021410d085808000200228023c2203418080808078460d0a20022802442106200228024021042002413c6a200110c78c8080000240200228023c418180808078460d002000200229023c3702042000410c6a200241c4006a280200360200200020063602182000200436021420002003360210200041033602000c0d0b200041003602002003450d0c200441002802c0a3c68000118080808000000c0c0b200241206a200110bc8a80800020022802200d0a2002413c6a2001200228022410d085808000200228023c2203418080808078460d0a2002280244210620022802402104200241186a200110bc8a808000024020022802180d002002413c6a2001200228021c10d085808000200228023c418080808078460d002000200229023c370210200041186a200241c4006a2802003602002000200636020c2000200436020820002003360204200041043602000c0c0b200041003602002003450d0b200441002802c0a3c68000118080808000000c0b0b200241286a200110bc8a808000024020022802280d002002413c6a2001200228022c10d085808000200228023c418080808078460d002000200229023c3702042000410c6a200241c4006a280200360200200041053602000c0b0b200041003602000c0a0b200241306a200110bc8a808000024020022802300d002002413c6a2001200228023410d085808000200228023c418080808078460d002000200229023c3702042000410c6a200241c4006a280200360200200041063602000c0a0b200041003602000c090b2002413c6a2001109f8d808000024020022d003c4105460d002000200229023c370204200041146a200241cc006a2802003602002000410c6a200241c4006a290200370200200041073602000c090b200041003602000c080b02402001280200220328020422014108490d00200041083602002003200141786a36020420032003280200220141086a360200200020012900003703080c080b200041003602000c070b200041093602000c060b02402001280200220328020422014104490d0020032001417c6a36020420032003280200220141046a36020020012800002203418094ebdc034b0d00200020033602042000410a3602000c060b200041003602000c050b02402001280200220328020422014104490d002000410b36020020032001417c6a36020420032003280200220141046a360200200020012800003602040c050b200041003602000c040b200041003602000c030b02402001280200220328020422014104490d002000410c36020020032001417c6a36020420032003280200220141046a360200200020012800003602040c030b200041003602000c020b200041003602000c010b200041003602000b200241c0026a2480808080000bc60603057f017e027f23808080800041c0006b2201248080808000200141186a41f7abc38000410441b9a9c380004135418097c38000410010d882808000200141106a42043702002001420037020820014280808080800137020041002d00fca3c680001a024002400240412041002802c8a3c68000118180808000002202450d002002410036021820024101360204200241ab99c3800036020020014101360238200120023602302001200241206a36023c200120023602342001200141306a10fa8680800041002d00fca3c680001a20012802002103200128020421022001280208210420012802182105200129021c2106410841002802c8a3c68000118180808000002207450d01200741002903c0acc380003702002001410036020820014280808080c000370200200141306a200141c8acc38000410a10b28b8080002001200141306a41d2acc38000410c10fe8a808000200141306a200141deacc38000410e10938b8080002001200141306a41ecacc38000411210b38b808000200141306a200141feacc38000411410a28b8080002001200141306a4192adc38000410c10a68b808000200141306a2001419eadc38000411710ac8b8080002001200141306a41b5adc38000411210a98b808000200141306a200141c7adc38000411510a18b8080002001200141306a41dcadc38000410a109d8b808000200141306a200141e6adc38000410410828b808000200141246a200141306a41eaadc38000410e10908b8080002001200128022436020820012001280228220836020020012008200128022c41246c6a36020c20012008360204200141306a200110fb868080002005418080808078460d022001200336020820012002360200200120023602042001200220044105746a36020c200041c4006a200110fa868080002001410b6a200141306a41086a2802003600002000413c6a200637020020002005360238200041013a0000200041d8006a4101360200200041d4006a2007360200200041013602502001200129023037000320002001290000370001200041086a200141076a290000370000200141c0006a2480808080000f0b4108412010b280808000000b4104410810b280808000000b41a8d8c480004111419cd9c4800010a181808000000beb0201027f23808080800041206b220124808080800041002d00fca3c680001a0240413041002802c8a3c680001181808080000022020d004108413010b280808000000b200242d0ffe6c89b859fc430370318200242ecb2f697e9f8a9f860370308200242ef899cf7a6a3ca9dd100370300200241b382808000360210200241206a42919fe7f19ec9d1a177370300200241286a41b4828080003602002001200241306a36021c200141023602182001200236021420012002360210200141046a200141106a108487808000200142888080808001370210200142808080808001370218200041c4006a200141106a10fa868080002001411b6a200141046a41086a280200360000200041c0006a410036020020004280808080c000370338200041043a0000200041d8006a410036020020004280808080c0003703502001200129020437001320002001290010370001200041086a200141176a290000370000200141206a2480808080000bcb0704067f017e017f017e23808080800041d0006b2201248080808000200141286a41e1bdc38000410941cfbdc38000411041a0b5c38000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041c00041002802c8a3c68000118180808000002202450d00200242c194a6a793ccc3a857370308200241e0bdc38000360220200241f58180800036021820024101360204200241dfbdc38000360200200241306a4293888c8f89fdc6ec9e7f370300200241286a42a5e9e3ab9e929adc2c370300200241106a42ab8bffbed784ffa5937f370300200241386a41ef80808000360200200241246a410136020020014102360248200120023602402001200241c0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a2001411c6a220241086a2802003602002001200229020037030020012802102103200128021421042001280218210520012802282106200129022c2107200141106a41086a22084100360200200142808080808001370210200141106a410010a4868080002001280214200828020041386c6a2202420437022c20024201370224200241a1a4c580003602202002410b36021c20024196a4c58000360218200241f581808000360210200242ab8bffbed784ffa5937f370308200242c194a6a793ccc3a857370300200141c0006a41086a200828020041016a2202360200200120012902102209370340024020022009a7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c2002420137022420024195a4c580003602202002410d36021c20024188a4c58000360218200241ef8080800036021020024293888c8f89fdc6ec9e7f370308200242a5e9e3ab9e929adc2c370300200128024821082001280244210220012001280240360248200120023602402001200236024420012002200841386c6a41386a36024c200141346a200141c0006a10f9868080002006418080808078460d012001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002006360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841c00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000bec0201027f23808080800041206b220124808080800041002d00fca3c680001a0240413041002802c8a3c680001181808080000022020d004108413010b280808000000b200242f099b79de1dbade83c370318200242a6829fd5dedbeecd9a7f370308200242f993ea84fdedefb2d000370300200241b582808000360210200241206a4297b1e6929387a1b844370300200241286a41b6828080003602002001200241306a36021c200141023602182001200236021420012002360210200141046a200141106a108487808000200142888080808001370210200142808080808001370218200041c4006a200141106a10fa868080002001411b6a200141046a41086a280200360000200041c0006a410036020020004280808080c000370338200041043a0000200041d8006a410036020020004280808080c0003703502001200129020437001320002001290010370001200041086a200141176a290000370000200141206a2480808080000bec0201027f23808080800041206b220124808080800041002d00fca3c680001a0240413041002802c8a3c680001181808080000022020d004108413010b280808000000b200242a5e9e3ab9e929adc2c370318200242e9b494c69bdbc4d608370308200242ead283debcdebd93d800370300200241f780808000360210200241206a4293888c8f89fdc6ec9e7f370300200241286a41ef808080003602002001200241306a36021c200141023602182001200236021420012002360210200141046a200141106a108487808000200142888080808001370210200142808080808001370218200041c4006a200141106a10fa868080002001411b6a200141046a41086a280200360000200041c0006a410036020020004280808080c000370338200041043a0000200041d8006a410036020020004280808080c0003703502001200129020437001320002001290010370001200041086a200141176a290000370000200141206a2480808080000bec0201027f23808080800041206b220124808080800041002d00fca3c680001a0240413041002802c8a3c680001181808080000022020d004108413010b280808000000b200242d0ffe6c89b859fc430370318200242c6bb82f1efc886d58a7f370308200242c6bdb6a4b5ec93c2d300370300200241b782808000360210200241206a42919fe7f19ec9d1a177370300200241286a41b4828080003602002001200241306a36021c200141023602182001200236021420012002360210200141046a200141106a108487808000200142888080808001370210200142808080808001370218200041c4006a200141106a10fa868080002001411b6a200141046a41086a280200360000200041c0006a410036020020004280808080c000370338200041043a0000200041d8006a410036020020004280808080c0003703502001200129020437001320002001290010370001200041086a200141176a290000370000200141206a2480808080000bcb0704067f017e017f017e23808080800041d0006b2201248080808000200141286a41c8bdc38000410741cfbdc38000411041a0b5c38000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041c00041002802c8a3c68000118180808000002202450d00200242c194a6a793ccc3a857370308200241e0bdc38000360220200241f58180800036021820024101360204200241dfbdc38000360200200241306a4293888c8f89fdc6ec9e7f370300200241286a42a5e9e3ab9e929adc2c370300200241106a42ab8bffbed784ffa5937f370300200241386a41ef80808000360200200241246a410136020020014102360248200120023602402001200241c0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a2001411c6a220241086a2802003602002001200229020037030020012802102103200128021421042001280218210520012802282106200129022c2107200141106a41086a22084100360200200142808080808001370210200141106a410010a4868080002001280214200828020041386c6a2202420437022c20024201370224200241a1a4c580003602202002410b36021c20024196a4c58000360218200241f581808000360210200242ab8bffbed784ffa5937f370308200242c194a6a793ccc3a857370300200141c0006a41086a200828020041016a2202360200200120012902102209370340024020022009a7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c2002420137022420024195a4c580003602202002410d36021c20024188a4c58000360218200241ef8080800036021020024293888c8f89fdc6ec9e7f370308200242a5e9e3ab9e929adc2c370300200128024821082001280244210220012001280240360248200120023602402001200236024420012002200841386c6a41386a36024c200141346a200141c0006a10f9868080002006418080808078460d012001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002006360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841c00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000bd20301027f23808080800041206b220124808080800041002d00fca3c680001a024041e00041002802c8a3c680001181808080000022020d00410841e00010b280808000000b200242ccf3faf4aeedbdfafb00370348200242fc86a1bbccd1ddf472370330200242e1a1e0ae85b5ea80fd00370318200242dca9a2e881dac9f914370308200242b4fd99f0e7c3fbd60e370300200241b882808000360210200241d0006a42cda992f8a2a6d9f2897f370300200241386a428bebb7a9dff4a9fe6a370300200241206a42b285eeed9386eed0d700370300200241d8006a41b982808000360200200241c0006a41ba82808000360200200241286a41bb828080003602002001200241e0006a36021c200141043602182001200236021420012002360210200141046a200141106a108487808000200142888080808001370210200142808080808001370218200041c4006a200141106a10fa868080002001411b6a200141046a41086a280200360000200041c0006a410036020020004280808080c000370338200041043a0000200041d8006a410036020020004280808080c0003703502001200129020437001320002001290010370001200041086a200141176a290000370000200141206a2480808080000b9f0503067f017e027f23808080800041d0006b2201248080808000200141286a41d8aec38000410a41a0b5c38000412541a0b5c38000410010d882808000200141206a42043702002001420037021820014280808080800137021041002d00fca3c680001a02400240412041002802c8a3c68000118180808000002202450d002002410036021820024101360204200241c5b5c3800036020020014101360248200120023602402001200241206a36024c20012002360244200141106a200141c0006a10fa86808000200141086a22032001411c6a220241086a28020036020020012002290200370300200128021021042001280214210520012802182106200129022c21072001280228210820014100360218200142808080808001370210200141106a410010a4868080002001280214200128021841386c6a2202420437022c20024208370224200241f8e3c4800036022020024100360218200241bc82808000360210200242899ac8f29d8ce69ac300370308200242e78dcee4d0becc9757370300200128021821092001280214210220012001280210360248200120023602402001200236024420012002200941386c6a41386a36024c200141346a200141c0006a10f9868080002008418080808078460d012001200436021820012005360210200120053602142001200520064105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002008360238200041003a000020002001290300370350200041d8006a20032802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b4108412010b280808000000b41a8d8c480004111419cd9c4800010a181808000000bab0503067f017e027f23808080800041d0006b2201248080808000200141286a41bcaec3800041114198b0c38000411d41a0b5c38000410010d882808000200141206a42043702002001420037021820014280808080800137021041002d00fca3c680001a02400240412041002802c8a3c68000118180808000002202450d002002410036021820024101360204200241c5b5c3800036020020014101360248200120023602402001200241206a36024c20012002360244200141106a200141c0006a10fa86808000200141086a22032001411c6a220241086a28020036020020012002290200370300200128021021042001280214210520012802182106200129022c21072001280228210820014100360218200142808080808001370210200141106a410010a4868080002001280214200128021841386c6a2202420437022c20024204370224200241e3a6c580003602202002410436021c200241dfa6c58000360218200241bd82808000360210200242cf94e6f2afe8d5d9aa7f370308200242c1b18585f195bbb0d600370300200128021821092001280214210220012001280210360248200120023602402001200236024420012002200941386c6a41386a36024c200141346a200141c0006a10f9868080002008418080808078460d012001200436021820012005360210200120053602142001200520064105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002008360238200041003a000020002001290300370350200041d8006a20032802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b4108412010b280808000000b41a8d8c480004111419cd9c4800010a181808000000b890403057f017e017f23808080800041d0006b2201248080808000200141286a41cdaec38000410b41ceb1c38000412641a0b5c38000410010d882808000200141206a42043702002001420037021820014280808080800137021041002d00fca3c680001a02400240412041002802c8a3c68000118180808000002202450d002002410036021820024101360204200241c5b5c3800036020020014101360248200120023602402001200241206a36024c20012002360244200141106a200141c0006a10fa86808000200141086a22032001411c6a220241086a28020036020020012002290200370300200128021021042001280214210220012802182105200129022c210620012802282107200142808080808001370248200142888080808001370240200141346a200141c0006a10f9868080002007418080808078460d012001200436021820012002360210200120023602142001200220054105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200637020020002007360238200041003a000020002001290300370350200041d8006a20032802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b4108412010b280808000000b41a8d8c480004111419cd9c4800010a181808000000bdb0901027f0240024002400240024002400240024002400240024002400240024020002d00000e0e000102030405060708090a0b0c0d000b0240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a41003a00000f0b0240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a41013a00000f0b0240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a41023a00000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41033a00002001200241016a2202360208200041106a2d00002103024020012802002002470d0020012002410110b182808000200128020821020b200128020420026a20033a00002001200241016a22023602080240200128020020026b41034b0d0020012002410410b182808000200128020821020b200128020420026a200028020c3600002001200241046a3602080f0b0240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a41043a00000f0b0240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a41053a00000f0b0240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a41063a00000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41073a00002001200241016a220236020820002d00012100024020012802002002470d0020012002410110b182808000200128020821020b2001200241016a360208200128020420026a20003a00000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41083a00002001200241016a220236020820002d00012100024020012802002002470d0020012002410110b182808000200128020821020b2001200241016a360208200128020420026a20003a00000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41093a00002001200241016a220236020820002d00012100024020012802002002470d0020012002410110b182808000200128020821020b2001200241016a360208200128020420026a20003a00000f0b0240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a410a3a00000f0b0240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a410b3a00000f0b0240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a410c3a00000f0b0240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a410d3a00000bde0803017f047e017f23808080800041b0016b220224808080800020002903082203210420002903002205210602402001290300500d00200141106a2903002204200320042003541b210420012903082206200520062005541b21060b0240024020032004520d0020052006510d010b200320047d2103200520067d210520002d00102101200241086a10ce88808000200241086a210002400240024020010e03020001020b200241186a21000c010b200241286a21000b200042002000290300220420057d220520052004561b370300200042002000290308220520037d220320032005561b37030820024190016a200241086a41286a290300370300200241e0006a41286a200241086a41206a290300370300200241e0006a41206a200241086a41186a290300370300200241e0006a41186a200241086a41106a290300370300200241e0006a41106a200241086a41086a29030037030020022002290308370368200242013703602002200241e0006a41086a36023c200242fc90b9e5d09296e777370348200242a6d4e6f1a4dd959860370340200242f89aef8eef91e1ce967f370358200242b4d6d6dfccc6b592c3003703502002413c6a200241c0006a412010f98c8080000b02404100280284a4c680004105470d00200241086a10ce88808000200241be828080003602442002200241086a3602404100280290a1c680002100410028028ca1c6800021014100280280a4c68000210720024198016a420137020020024190016a410136020020024188016a410f36020020024184016a41bfb1c38000360200200241f8006a41d0b0c38000ad4280808080f00d84370200200241ec006a41ceb1c38000ad4280808080e0048437020020024194016a200241c0006a360200200241c8b0c3800036028c012002410536028001200241003602742002410036026820024281808080c021370260200141ecf2c08000200741024622071b200241e0006a200041d4f2c0800020071b280210118480808000000b02404100280284a4c680004105470d00200242fc90b9e5d09296e777370368200242a6d4e6f1a4dd95986037036020024295f38cfcb699a3c4ef00370378200242a8db95cdaa86daa7193703702002200241e0006a412010d088808000200241bf8280800036020c20022002280204410020022802001b3602402002200241c0006a3602084100280290a1c680002100410028028ca1c6800021014100280280a4c68000210720024198016a420137020020024190016a410136020020024188016a410f36020020024184016a41bfb1c38000360200200241f8006a41d0b0c38000ad4280808080f00d84370200200241ec006a41ceb1c38000ad4280808080e0048437020020024194016a200241086a36020020024188b2c3800036028c012002410536028001200241003602742002410036026820024281808080a022370260200141ecf2c08000200741024622071b200241e0006a200041d4f2c0800020071b280210118480808000000b200241b0016a2480808080000bb50603017f017e057f23808080800041b0016b2201248080808000200142fc90b9e5d09296e777370308200142a6d4e6f1a4dd959860370300200142f89aef8eef91e1ce967f370318200142b4d6d6dfccc6b592c300370310200141206a2001412041002802b8a1c68000118580808000000240024002402001280220450d00200141306a41086a200141206a41086a29020022023703002001200129022037033020012002a72203360248200120012802342204360244200141e8006a200141c4006a10f18c8080002001290368500d0102400240417f4100280284a4c680002205410147200541014b1b2205417f460d00200541ff01710d010b200141dc006a4194afc3800041022001412010dc8a808000200141cc006a410c6a41c082808000360200200141c1828080003602502001200141af016a3602542001200141dc006a36024c4100280290a1c680002105410028028ca1c6800021064100280280a4c680002107200141a0016a420237020020014198016a410236020020014190016a41103602002001418c016a4184bac3800036020020014180016a4194bac38000ad4280808080900d84370200200141e8006a410c6a41fdbac38000ad42808080808004843702002001419c016a200141cc006a360200200141f4b9c380003602940120014101360288012001410036027c2001410036027020014281808080c003370268200641ecf2c08000200741024622071b200141e8006a200541d4f2c0800020071b28021011848080800000200128025c450d00200128026041002802c0a3c68000118080808000000b2001413c6a20042003200128023028020c118580808000000b20004200370300200041286a4200370300200041206a4200370300200041186a4200370300200041106a4200370300200041086a42003703000c010b20002001290370370300200041286a20014198016a290300370300200041206a200141e8006a41286a290300370300200041186a200141e8006a41206a290300370300200041106a200141e8006a41186a290300370300200041086a200141e8006a41106a2903003703002001413c6a20042003200128023028020c118580808000000b200141b0016a2480808080000b7401017f23808080800041106b22022480808080002002200041206a36020c200141d3cdc38000411041e3cdc380004106200041eccdc3800041fccdc38000410b200041106a41eccdc380004187cec3800041092002410c6a4190cec3800010e0808080002100200241106a24808080800020000bbf0403027f017e027f2380808080004190016b220324808080800041002104200341086a2001200241002802b8a1c68000118580808000000240024020032802080d000c010b200341186a41086a200341086a41086a290200220537030020032003290208370318200328021c2106024002402005a722074104490d0020062800002102410121040c010b02400240417f4100280284a4c680002204410147200441014b1b2204417f460d00200441ff01710d010b2003413c6a4194afc3800041022001200210dc8a8080002003412c6a410c6a41c082808000360200200341c18280800036023020032003418f016a36023420032003413c6a36022c4100280290a1c680002104410028028ca1c6800021024100280280a4c68000210120034180016a4202370200200341f8006a4102360200200341f0006a4110360200200341ec006a4184bac38000360200200341e0006a4194bac38000ad4280808080900d84370200200341c8006a410c6a41fdbac38000ad4280808080800484370200200341fc006a2003412c6a360200200341f4b9c38000360274200341013602682003410036025c2003410036025020034281808080c003370248200241ecf2c08000200141024622011b200341c8006a200441d4f2c0800020011b28021011848080800000200328023c450d00200328024041002802c0a3c68000118080808000000b41002102410021040b200341246a20062007200328021828020c118580808000000b200020023602042000200436020020034190016a2480808080000bed0201037f2380808080004180016b220224808080800002400240024002400240200128021c22034110710d0020034120710d0120003502004101200110fe8080800021000c020b20002802002100410021030340200220036a41ff006a413041d7002000410f712204410a491b20046a3a00002003417f6a210320004110492104200041047621002004450d000b20034180016a22004180014b0d022001410141c48dc080004102200220036a4180016a410020036b10db8080800021000c010b20002802002100410021030340200220036a41ff006a413041372000410f712204410a491b20046a3a00002003417f6a210320004110492104200041047621002004450d000b20034180016a22004180014b0d022001410141c48dc080004102200220036a4180016a410020036b10db8080800021000b20024180016a24808080800020000f0b200041800141c88dc08000109481808000000b200041800141c88dc08000109481808000000bc00301077f23808080800041206b220224808080800041002d00fca3c680001a0240410141002802c8a3c68000118180808000002203450d0020032001417f6a3a0000200241013602102002200336020c20024101360208200241086a4101410310ab86808000200228020c2203200228021022046a220541003b0000200541026a41003a000020022802082105024002400240200441036a22044104470d00200341036a2d0000210420032d0002210620032d0001210720032d000021082005450d01200341002802c0a3c68000118080808000000c010b2005418080808078470d01200341187621042003411076210620034180fe03714108762107200321080b200041033a00002000410d6a20073a00002000410c6a20083a0000200041106a41013a00002000410e6a20063a00002000410f6a20043a0000200041086a200141187441808080786a411875410274220341b0cec380006a2802003602002000200341a0cec380006a280200360204200241206a2480808080000f0b2002200436021c200220033602182002200536021441e0b3c3800041cb00200241146a4188b5c3800041d0b3c38000108981808000000b4101410110b280808000000bfc0e04037f037e017f017e23808080800041f0036b2202248080808000200241306a20002d00102203200110d7888080000240024020022d0030450d0020022f0132210120022d003121000c010b20022802342104200210ce88808000200241306a10e1898080002000290308210520002903002106024002400240024020030e03000102000b427f427f200520024180016a2903007c220720072005541b22052001ad7c220720072005541b2107427f200620022903787c220520052006541b2105200241306a21080c020b427f427f2005200241d8016a2903007c220720072005541b22052001ad7c220720072005541b2107427f2006200241d0016a2903007c220520052006541b210520024188016a21080c010b427f427f2005200241b0026a2903007c220720072005541b22052001ad7c220720072005541b2107427f2006200241a8026a2903007c220520052006541b2105200241e0016a21080b0240024002400240200829031822094200520d002008290330500d010b2002210102400240024020030e03020001020b200241106a21010c010b200241206a21010b02402001290300220620057c22052006540d002001290308220620077c22072006540d0020012007370308200120053703000c020b410021000240417f4100280284a4c680002201410447200141044b1b2201417f460d00200141ff01710d030b410021004100280290a1c680002101410028028ca1c6800021034100280280a4c680002108200241d8036a4200370200200241d4036a41a0b5c38000360200200241d0036a4101360200200241c8036a410f360200200241c4036a41bfb1c38000360200200241b8036a41d0b0c38000ad4280808080f00d84370200200241ac036a41ceb1c38000ad4280808080e00484370200200241bcb7c380003602cc03200241043602c003200241003602b403200241003602a80320024281808080c0133702a003200341ecf2c08000200841024622081b200241a0036a200141d4f2c0800020081b280210118480808000000c020b2002210102400240024020030e03020001020b200241106a21010c010b200241206a21010b2001427f2001290308220620077c220720072006541b3703082001427f2001290300220620057c220520052006541b3703000b2002210102400240024020030e03020001020b200241106a21010c010b200241206a21010b20012903082106200129030021050240024002402009500d002005200841206a290300560d012006200841286a290300560d010b0240427f427f2002290300220720022903107c220920092007541b220720022903207c220920092007541b20022903c802560d00427f427f20022903082207200241186a2903007c220920092007541b2207200241286a2903007c220920092007541b200241d0026a290300580d020b2008290330500d0102402005200841386a290300560d002006200841c0006a290300580d020b410021000240417f4100280284a4c680002201410447200141044b1b2201417f460d00200141ff01710d030b200241a0036a410c6a4200370200200241013602a40320024184b7c380003602a003200241a0b5c380003602a8032002418c036a410c6a41263602002002418cb7c3800036029c03200241ceb1c38000360294032002410f36029003200241bfb1c3800036028c0341002100200241a0036a41042002418c036a4100200210a182808000410621010c030b410021000240417f4100280284a4c680002201410447200141044b1b2201417f460d00200141ff01710d020b410021004100280290a1c680002101410028028ca1c6800021034100280280a4c680002108200241d8036a4200370200200241d4036a41a0b5c38000360200200241d0036a4101360200200241c8036a410f360200200241c4036a41bfb1c38000360200200241b8036a41d0b0c38000ad4280808080f00d84370200200241ac036a41ceb1c38000ad4280808080e00484370200200241dcb6c380003602cc03200241043602c003200241003602b403200241003602a80320024281808080a0153702a003200341ecf2c08000200841024622081b200241a0036a200141d4f2c0800020081b28021011848080800000410621010c020b200241d8026a41286a200241286a290300370300200241d8026a41206a200241206a290300370300200241d8026a41186a200241186a290300370300200241d8026a41106a200241106a290300370300200241d8026a41086a200241086a290300370300200220022903003703d802200010d888808000220041ff01714102470d00200242fc90b9e5d09296e7773703a803200242a6d4e6f1a4dd9598603703a00320024295f38cfcb699a3c4ef003703b803200242a8db95cdaa86daa7193703b0032002200436028c03200241a0036a41202002418c036a410441002802e0a1c6800011868080800000200242fc90b9e5d09296e7773703a803200242a6d4e6f1a4dd9598603703a003200242f89aef8eef91e1ce967f3703b803200242b4d6d6dfccc6b592c3003703b003200241d8026a200241a0036a4120108b8d808000410221000c010b410621010b200241f0036a2480808080002001410874200041ff0171720bc40702067f027e23808080800041c0016b2202248080808000024002400240024020012d000822030d00410021010c010b200241fc006a200141096a10e881808000024020022d007c0d0041002104410121030c020b200241c7006a41196a200241fc006a41196a290000370000200241c7006a41116a200241fc006a41116a290000370000200241c7006a41096a200241fc006a41096a2900003700002002200229007d370048410121010b200220013a004702400240417f4100280284a4c680002204410447200441044b1b2204450d00200441ff017141ff01460d00200241306a200241d3006a290000370300200241386a200241db006a2900003703002002413d6a200241e0006a2900003700002002200229004b37032820022d004a210520022d0049210420022d004821030c010b0240024020030d0020024180808080783602700c010b200241f0006a4194afc380004102200241c8006a10db8a8080000b200241c28280800036026c2002200241f0006a3602684100280290a1c680002101410028028ca1c6800021044100280280a4c680002103200241b4016a4201370200200241ac016a4101360200200241a4016a4116360200200241a0016a4196afc3800036020020024194016a41acafc38000ad4280808080c00d84370200200241fc006a410c6a4198b0c38000ad4280808080d00384370200200241b0016a200241e8006a3602002002418cafc380003602a8012002410436029c012002410036029001200241003602840120024281808080e01237027c200441ecf2c08000200341024622031b200241fc006a200141d4f2c0800020031b28021011848080800000024020022802702201418080808078460d002001450d00200228027441002802c0a3c68000118080808000000b200241306a200241c7006a410c6a290000370300200241386a200241db006a2900003703002002413d6a200241e0006a2900003700002002200229004b37032820022d0048210320022d0049210420022d004a210520022d004722014102460d010b200241086a41156a2206200241286a41156a290000370000200241086a41106a2207200241286a41106a290300370300200241086a41086a200241286a41086a2903002208370300200220022903282209370308200020053a0003200020043a0002200020033a0001200020013a0000200020093700042000410c6a2008370000200041146a2007290300370000200041196a20062900003700000c010b200020033a0001200041023a0000200041036a20053a0000200041026a20043a00000b200241c0016a2480808080000bc70201027f23808080800041106b2202248080808000024002402000280200418080808078470d00200128021441c6c8c380004104200141186a28020028020c1182808080000021010c010b200220003602002002200128021441cac8c380004104200141186a28020028020c118280808000003a000c20022001360208200241003a000d20024100360204200241046a200241d0c8c38000108d81808000210120022d000c21000240200128020022030d00200041ff017141004721010c010b41012101200041ff01710d0020022802082100024020034101470d0020022d000d41ff0171450d0020002d001c4104710d00410121012000280214418ca5c080004101200041186a28020028020c118280808000000d010b2000280214418da5c080004101200041186a28020028020c1182808080000021010b200241106a24808080800020010bb00701037f23808080800041a0026b2204248080808000200441013a00880120044204370380012004420037037820044280808080c0003703702004427f37036820044200370360200441013a0028200442043703202004420037031820044280808080c0003703102004427f37030820044200370300200441c0016a200441e0006a200410fd84808000200441e0006a20022d0010200310d78880800002400240024020042d00600d0041062103200210d888808000220241ff01714102470d01200441013a0058200442043703502004420037034820044280808080c0003703402004427f37033820044200370330200441e0006a200441c0016a200441306a10fd84808000200441013a00b801200442043703b001200442003703a80120044280808080c0003703a0012004427f370398012004420037039001200441c0016a200441e0006a20044190016a10fd84808000200441013a0098022004420437039002200442003703880220044280808080c000370380022004427f3703f801200442003703f0012000200441c0016a200441f0016a10fd848080000c020b20042f0162210320042d006121020b2000418080808078360210200041026a20034108763a000020002003410874200241ff0171723b0100200441d4016a28020021050240200441d8016a2802002200450d002000410171210641002103024020004101460d002000417e7121022005210041002103034002402000280200450d00200041046a28020041002802c0a3c68000118080808000000b02402000410c6a280200450d00200041106a28020041002802c0a3c68000118080808000000b200041186a21002002200341026a2203470d000b0b2006450d0020052003410c6c6a2200280200450d00200028020441002802c0a3c68000118080808000000b024020042802d001450d00200541002802c0a3c68000118080808000000b200441e0016a28020021050240200441e4016a2802002200450d002000410171210641002103024020004101460d002000417e7121022005210041002103034002402000280200450d00200041046a28020041002802c0a3c68000118080808000000b02402000410c6a280200450d00200041106a28020041002802c0a3c68000118080808000000b200041186a21002002200341026a2203470d000b0b2006450d0020052003410c6c6a2200280200450d00200028020441002802c0a3c68000118080808000000b20042802dc01450d00200541002802c0a3c68000118080808000000b200441a0026a2480808080000bfe0401047f2380808080004180016b22032480808080002003418080c0023602142003428080f0818080802837020c200342fc90b9e5d09296e777370338200342a6d4e6f1a4dd95986037033020034295f38cfcb699a3c4ef00370348200342a8db95cdaa86daa7193703402003200341306a412010d0888080002003417f2003280204410020032802001b220420026a220220022004491b2204360218200341146a2105200341106a21062003410c6a2102024002400240200141ff01710e03020001020b200621020c010b200521020b02400240200420022802004b0d0020002004360204410021020c010b02400240417f4100280284a4c680002202410447200241044b1b2202450d00200241ff017141ff01470d010b2003410c6a2102024002400240200141ff01710e03020001020b200621020c010b200521020b2003411c6a410c6a41c38280800036020020034185808080003602202003200236022c20032003412c6a3602242003200341186a36021c4100280290a1c680002102410028028ca1c6800021044100280280a4c680002101200341e8006a4202370200200341e0006a4102360200200341d8006a410f360200200341d4006a41bfb1c38000360200200341c8006a41d0b0c38000ad4280808080f00d84370200200341306a410c6a41ceb1c38000ad4280808080e00484370200200341e4006a2003411c6a360200200341e8b5c3800036025c20034104360250200341003602442003410036023820034281808080f009370230200441ecf2c08000200141024622011b200341306a200241d4f2c0800020011b280210118480808000000b200041800c3b0001410121020b200020023a000020034180016a2480808080000bec0302037f027e23808080800041d0026b2201248080808000200141086a10e189808000200141086a210202400240024020002d00100e03020001020b200141e0006a21020c010b200141b8016a21020b41022103024020022802004101470d00200229031021040240200029030020022903082205560d0020002903082004580d010b200120043703b802200120053703b00202400240417f4100280284a4c680002202410447200241044b1b2202450d00200241ff017141ff01470d010b200141c0026a410c6a41c482808000360200200141c4828080003602c402200120003602c0022001200141b0026a3602c8024100280290a1c680002102410028028ca1c6800021004100280280a4c680002103200141c0006a4202370200200141386a4102360200200141306a410f3602002001412c6a41bfb1c38000360200200141206a41d0b0c38000ad4280808080f00d84370200200141086a410c6a41ceb1c38000ad4280808080e004843702002001413c6a200141c0026a360200200141a8b6c38000360234200141043602282001410036021c2001410036021020014281808080e006370208200041ecf2c08000200341024622031b200141086a200241d4f2c0800020031b280210118480808000000b410021030b200141d0026a248080808000200341800c720b9d0b010b7f23808080800041106b22012480808080002001410036020c20014280808080800137020441002d00fca3c680001a0240024002400240413841002802c8a3c68000118180808000002202450d002002410a360204200241d8aec38000360200200241286a2203429ccab49c93e2e495cf00370300200241206a220442d1c5efcdcd82cde1ff00370300200241106a220542dca9a2e881dac9f914370300200241086a220642b4fd99f0e7c3fbd60e370300200241306a2207419382808000360200200241186a220841b882808000360200200141046a4100410110a78680800020012802082209200128020c220a41386c6a220b2002290300370300200b41086a2006290300370300200b41106a2005290300370300200b41186a2008290300370300200b41206a2004290300370300200b41286a2003290300370300200b41306a20072903003703002001200a41016a220336020c200241002802c0a3c680001180808080000041002d00fca3c680001a413841002802c8a3c68000118180808000002202450d01200242d1c5efcdcd82cde1ff00370320200242e1a1e0ae85b5ea80fd003703082002419382808000360230200241bb828080003602182002410b360204200241cdaec38000360200200241286a429ccab49c93e2e495cf00370300200241106a42b285eeed9386eed0d700370300024020012802042003470d00200141046a2003410110a78680800020012802082109200128020c21030b2009200341386c6a220b2002290300370300200b41306a200241306a290300370300200b41286a200241286a290300370300200b41206a200241206a290300370300200b41186a200241186a290300370300200b41106a200241106a290300370300200b41086a200241086a2903003703002001200341016a220336020c200241002802c0a3c680001180808080000041002d00fca3c680001a413841002802c8a3c68000118180808000002202450d02200242d1c5efcdcd82cde1ff00370320200242fc86a1bbccd1ddf4723703082002419382808000360230200241ba8280800036021820024112360204200241b9d0c38000360200200241286a429ccab49c93e2e495cf00370300200241106a428bebb7a9dff4a9fe6a370300024020012802042003470d00200141046a2003410110a78680800020012802082109200128020c21030b2009200341386c6a220b2002290300370300200b41306a200241306a290300370300200b41286a200241286a290300370300200b41206a200241206a290300370300200b41186a200241186a290300370300200b41106a200241106a290300370300200b41086a200241086a2903003703002001200341016a220336020c200241002802c0a3c680001180808080000041002d00fca3c680001a413841002802c8a3c68000118180808000002202450d032002428cc882a2e2dcdde2f000370320200242ccf3faf4aeedbdfafb003703082002418682808000360230200241b98280800036021820024111360204200241bcaec38000360200200241286a42aa8be08180efaa931e370300200241106a42cda992f8a2a6d9f2897f370300024020012802042003470d00200141046a2003410110a78680800020012802082109200128020c21030b2009200341386c6a220b2002290300370300200b41306a200241306a290300370300200b41286a200241286a290300370300200b41206a200241206a290300370300200b41186a200241186a290300370300200b41106a200241106a290300370300200b41086a200241086a290300370300200141046a41086a220b200341016a360200200241002802c0a3c6800011808080800000200041086a200b28020036020020002001290204370200200141106a2480808080000f0b4108413810b280808000000b4108413810b280808000000b4108413810b280808000000b4108413810b280808000000b961303027f027e017f2380808080004180036b220624808080800041012107200641013a00d001200642043703c801200642003703c00120064280808080c0003703b8012006427f3703b001200642003703a80120012903002108200641b8026a200210fa87808000024002400240024020062802ec0220062802f00272450d004103210720062903b80222092008560d0041002d00fca3c680001a0240024002400240410c41002802c8a3c68000118180808000002201450d0041002d00fca3c680001a412841002802c8a3c68000118180808000002207450d0120072002290000370000200741186a200241186a290000370000200741106a200241106a290000370000200741086a200241086a290000370000200720083700202001412836020820012007360204200141283602000240024020092008540d0041042107410021020c010b41002d00fca3c680001a410c41002802c8a3c68000118180808000002207450d0341002d00fca3c680001a412841002802c8a3c6800011818080800000220a450d04200a2002290000370000200a41186a200241186a290000370000200a41106a200241106a290000370000200a41086a200241086a290000370000200a2008427f7c370020200741283602082007200a36020420074128360200410121020b200641013a00302006410136022c2006200136022820064101360224200620023602202006200736021c200620023602182006427f37031020064200370308200641b8026a200641a8016a200641086a10fd84808000200641a8016a20042d0010200510d7888080000240024020062d00a8010d0041062102200410d888808000220741ff01714102470d01200641013a0060200642043703582006420037035020064280808080c0003703482006427f37034020064200370338200641e8006a200641b8026a200641386a10fd848080004100280284a4c680004105460d070c080b20062f01aa01210220062d00a90121070b2000418080808078360210200041026a20024108763a000020002002410874200741ff0171723b0100200641cc026a28020021010240200641d0026a2802002200450d002000410171210441002102024020004101460d002000417e7121072001210041002102034002402000280200450d00200041046a28020041002802c0a3c68000118080808000000b02402000410c6a280200450d00200041106a28020041002802c0a3c68000118080808000000b200041186a21002007200241026a2202470d000b0b2004450d0020012002410c6c6a2200280200450d00200028020441002802c0a3c68000118080808000000b024020062802c802450d00200141002802c0a3c68000118080808000000b200641d8026a28020021010240200641dc026a2802002200450d002000410171210441002102024020004101460d002000417e7121072001210041002102034002402000280200450d00200041046a28020041002802c0a3c68000118080808000000b02402000410c6a280200450d00200041106a28020041002802c0a3c68000118080808000000b200041186a21002007200241026a2202470d000b0b2004450d0020012002410c6c6a2200280200450d00200028020441002802c0a3c68000118080808000000b20062802d402450d07200141002802c0a3c68000118080808000000c070b4104410c10b280808000000b4101412810b280808000000b4104410c10b280808000000b4101412810b280808000000b2000418080808078360210200041026a41003a0000200020074108743b01000c020b4100280290a1c680002102410028028ca1c6800021074100280280a4c680002101200641f0026a4200370200200641ec026a41e8d1c38000360200200641e8026a4101360200200641e0026a4116360200200641dc026a41e88bc48000360200200641d0026a41f48ac48000ad4280808080900c84370200200641c4026a41fe8bc48000ad4280808080e00284370200200641e08bc480003602e402200641053602d802200641003602cc02200641003602c0022006428180808090243702b802200741ecf2c08000200141024622011b200641b8026a200241d4f2c0800020011b280210118480808000000b024002400240200328020041736a220241034b0d0020024102460d00200641013a00d00141002102200641003602cc0120064280808080c0003702c401200642043702bc012006427f3703b001200642003703a8010c010b200641a8016a200310d18c80800020062802b8012202418080808078460d010b20064198016a41086a200641a8016a41086a2903002208370300200641d8016a411c6a200641a8016a411c6a290200370200200641d8016a41246a200641a8016a41246a290200370200200641d8016a412c6a200641a8016a412c6a280200360200200641d8016a41086a2008370300200620062903a801220837039801200620062902bc013702ec01200620083703d801200620023602e801200641b8026a200641e8006a200641d8016a10fd84808000200641013a00b002200642043703a802200642003703a00220064280808080c000370398022006427f3703900220064200370388022000200641b8026a20064188026a10fd848080000c010b200620062d00aa0122023a009a01200620062f01a80122073b019801200041026a20023a0000200020073b01002000418080808078360210200641fc006a2802002101024020064180016a2802002200450d002000410171210441002102024020004101460d002000417e7121072001210041002102034002402000280200450d00200041046a28020041002802c0a3c68000118080808000000b02402000410c6a280200450d00200041106a28020041002802c0a3c68000118080808000000b200041186a21002007200241026a2202470d000b0b2004450d0020012002410c6c6a2200280200450d00200028020441002802c0a3c68000118080808000000b02402006280278450d00200141002802c0a3c68000118080808000000b20064188016a280200210102402006418c016a2802002200450d002000410171210441002102024020004101460d002000417e7121072001210041002102034002402000280200450d00200041046a28020041002802c0a3c68000118080808000000b02402000410c6a280200450d00200041106a28020041002802c0a3c68000118080808000000b200041186a21002007200241026a2202470d000b0b2004450d0020012002410c6c6a2200280200450d00200028020441002802c0a3c68000118080808000000b200628028401450d00200141002802c0a3c68000118080808000000b20064180036a2480808080000b140020002802003502004101200110fe808080000bc00301077f23808080800041206b220224808080800041002d00fca3c680001a0240410141002802c8a3c68000118180808000002203450d0020032001417f6a3a0000200241013602102002200336020c20024101360208200241086a4101410310ab86808000200228020c2203200228021022046a220541003b0000200541026a41003a000020022802082105024002400240200441036a22044104470d00200341036a2d0000210420032d0002210620032d0001210720032d000021082005450d01200341002802c0a3c68000118080808000000c010b2005418080808078470d01200341187621042003411076210620034180fe03714108762107200321080b200041033a00002000410d6a20073a00002000410c6a20083a0000200041106a41003a00002000410e6a20063a00002000410f6a20043a0000200041086a200141187441808080786a411875410274220341c0cec380006a2802003602002000200341e4cec380006a280200360204200241206a2480808080000f0b2002200436021c200220033602182002200536021441e0b3c3800041cb00200241146a4188b5c3800041a0b8c38000108981808000000b4101410110b280808000000be90403017f017e037f2380808080004190016b2203248080808000200341086a2001200241002802b8a1c68000118580808000000240024020032802080d00200041003a00000c010b200341186a41086a200341086a41086a290200220437030020032003290208370318200328021c2105024002402004a722064120490d00200041013a000020002005290000370001200041196a200541186a290000370000200041116a200541106a290000370000200041096a200541086a2900003700000c010b02400240417f4100280284a4c680002207410147200741014b1b2207417f460d00200741ff01710d010b2003413c6a4194afc3800041022001200210dc8a8080002003412c6a410c6a41c082808000360200200341c18280800036023020032003418f016a36023420032003413c6a36022c4100280290a1c680002102410028028ca1c6800021014100280280a4c68000210720034180016a4202370200200341f8006a4102360200200341f0006a4110360200200341ec006a4184bac38000360200200341e0006a4194bac38000ad4280808080900d84370200200341c8006a410c6a41fdbac38000ad4280808080800484370200200341fc006a2003412c6a360200200341f4b9c38000360274200341013602682003410036025c2003410036025020034281808080c003370248200141ecf2c08000200741024622071b200341c8006a200241d4f2c0800020071b28021011848080800000200328023c450d00200328024041002802c0a3c68000118080808000000b200041003a00000b200341246a20052006200328021828020c118580808000000b20034190016a2480808080000b2100200128021441c4cac380004105200141186a28020028020c118280808000000b140020012000280204200028020810dd808080000bb60503017f017e047f23808080800041b0026b2202248080808000200241086a2001412041002802b8a1c68000118580808000000240024020022802080d00200042043703000c010b200241186a41086a200241086a41086a29020022033703002002200229020837031820022003a722043602a0012002200228021c220536029c01024002402004450d0020022004417f6a3602a0012002200541016a36029c01420321030240024020052d00000e020100020b200241b0016a2002419c016a10ae8c80800020022903b00122034203510d01200241286a200241b8016a41f00010848e8080001a0b200041086a200241286a41f00010848e8080001a200020033703000c010b02400240417f4100280284a4c680002206410147200641014b1b2206417f460d00200641ff01710d010b200241a4016a4194afc3800041022001412010dc8a808000200241286a410c6a41c082808000360200200241c18280800036022c2002200241af026a3602302002200241a4016a3602284100280290a1c680002101410028028ca1c6800021064100280280a4c680002107200241e8016a4202370200200241e0016a4102360200200241d8016a4110360200200241d4016a4184bac38000360200200241c8016a4194bac38000ad4280808080900d84370200200241b0016a410c6a41fdbac38000ad4280808080800484370200200241e4016a200241286a360200200241f4b9c380003602dc01200241013602d001200241003602c401200241003602b80120024281808080c0033702b001200641ecf2c08000200741024622071b200241b0016a200141d4f2c0800020071b2802101184808080000020022802a401450d0020022802a80141002802c0a3c68000118080808000000b200042043703000b200241246a20052004200228021828020c118580808000000b200241b0026a2480808080000be60603017f017e047f2380808080004190016b220324808080800020032001200241002802b8a1c68000118580808000000240024020032802000d0020004180808080783602000c010b200341106a41086a200341086a29020022043703002003200329020037031020032004a72205360228200320032802142206360224024002402005450d0020032005417f6a22073602282003200641016a36022402400240024002400240024020062d000022084103710e0400030102000b200841027621080c040b20054104490d0420032005417c6a3602282003200641046a360224200641036a2d000041187420062f000141087472200872220741027621082007418080044921070c020b200841044f0d0320054105490d0320032005417b6a3602282003200641056a360224200628000122084180808080044921070c010b2007450d0220032005417e6a3602282003200641026a36022420062d000141087420087241ffff03712207410276210820074180024921070b20070d0120084180024b0d010b200341c8006a200341246a200810c68580800020032802482208418080808078460d002000200329024c370204200020083602000c010b02400240417f4100280284a4c680002208410147200841014b1b2208417f460d00200841ff01710d010b2003413c6a4194afc3800041022001200210dc8a8080002003412c6a410c6a41c082808000360200200341c18280800036023020032003418f016a36023420032003413c6a36022c4100280290a1c680002102410028028ca1c6800021014100280280a4c68000210820034180016a4202370200200341f8006a4102360200200341f0006a4110360200200341ec006a4184bac38000360200200341e0006a4194bac38000ad4280808080900d84370200200341c8006a410c6a41fdbac38000ad4280808080800484370200200341fc006a2003412c6a360200200341f4b9c38000360274200341013602682003410036025c2003410036025020034281808080c003370248200141ecf2c08000200841024622081b200341c8006a200241d4f2c0800020081b28021011848080800000200328023c450d00200328024041002802c0a3c68000118080808000000b20004180808080783602000b2003411c6a20062005200328021028020c118580808000000b20034190016a2480808080000b9c0903017f017e057f2380808080004190016b220224808080800020022001412041002802b8a1c68000118580808000000240024020022802000d0020004180808080783602000c010b200241106a41086a200241086a29020022033703002002200229020037031020022003a72204360228200220022802142205360224024002402004450d0020022004417f6a22063602282002200541016a3602240240024002400240024020052d000022074103710e0403020001030b20044104490d0420022004417c6a3602282002200541046a360224200541036a2d000041187420052f000141087472200772220741808004490d04200741027621070c030b200741044f0d0320044105490d0320022004417b6a3602282002200541056a360224200528000122074180808080044f0d020c030b2006450d0220022004417e6a3602282002200541026a36022420052d000141087420077241ffff0371220741ff014d0d02200741027621070c010b200741027621070b200241c8006a200241246a200710c58580800020022802482207418080808078460d000240200229024c2203422088a7410b490d000240417f4100280284a4c680002201410247200141024b1b2201417f460d00200141ff01710d010b200241e0818080003602402002410636023020024198b5c3800036022c20022002412c6a36023c4100280290a1c680002101410028028ca1c6800021064100280280a4c68000210820024180016a4201370200200241f8006a4102360200200241f0006a4107360200200241ec006a419cc2c38000360200200241e0006a41a3c2c38000ad4280808080b00e84370200200241d4006a41afc1c38000ad4280808080d00484370200200241fc006a2002413c6a3602002002418cc2c38000360274200241023602682002410036025c20024100360250200242818080809016370248200641ecf2c08000200841024622081b200241c8006a200141d4f2c0800020081b280210118480808000000b20002003370204200020073602000c010b02400240417f4100280284a4c680002207410147200741014b1b2207417f460d00200741ff01710d010b2002413c6a4194afc3800041022001412010dc8a8080002002412c6a410c6a41c082808000360200200241c18280800036023020022002418f016a36023420022002413c6a36022c4100280290a1c680002101410028028ca1c6800021074100280280a4c68000210620024180016a4202370200200241f8006a4102360200200241f0006a4110360200200241ec006a4184bac38000360200200241e0006a4194bac38000ad4280808080900d84370200200241c8006a410c6a41fdbac38000ad4280808080800484370200200241fc006a2002412c6a360200200241f4b9c38000360274200241013602682002410036025c2002410036025020024281808080c003370248200741ecf2c08000200641024622061b200241c8006a200141d4f2c0800020061b28021011848080800000200228023c450d00200228024041002802c0a3c68000118080808000000b20004180808080783602000b2002411c6a20052004200228021028020c118580808000000b20024190016a2480808080000b140020012000280200200028020410dd808080000bbb0503017f017e037f2380808080004190016b2203248080808000200341086a2001200241002802b8a1c68000118580808000000240024020032802080d00200042003703000c010b200341186a41086a200341086a41086a290200220437030020032003290208370318200328021c2105024002402004a722064108490d002006417c7122074108460d002007410c460d0020074110460d002006416c6a4128490d0020052900002104200528000821022000200528000c36023c2000200236023820002004370308200042013703002000200529002c37031020002005280010360240200020052900243703302000200529001c37032820002005290014370320200041186a200541346a2900003703000c010b02400240417f4100280284a4c680002207410147200741014b1b2207417f460d00200741ff01710d010b2003413c6a4194afc3800041022001200210dc8a8080002003412c6a410c6a41c082808000360200200341c18280800036023020032003418f016a36023420032003413c6a36022c4100280290a1c680002102410028028ca1c6800021014100280280a4c68000210720034180016a4202370200200341f8006a4102360200200341f0006a4110360200200341ec006a4184bac38000360200200341e0006a4194bac38000ad4280808080900d84370200200341c8006a410c6a41fdbac38000ad4280808080800484370200200341fc006a2003412c6a360200200341f4b9c38000360274200341013602682003410036025c2003410036025020034281808080c003370248200141ecf2c08000200741024622071b200341c8006a200241d4f2c0800020071b28021011848080800000200328023c450d00200328024041002802c0a3c68000118080808000000b200042003703000b200341246a20052006200328021828020c118580808000000b20034190016a2480808080000be90403017f017e047f2380808080004190016b2202248080808000200241086a2001412041002802b8a1c68000118580808000000240024020022802080d00200041003a00000c010b200241186a41086a200241086a41086a290200220337030020022002290208370318200228021c2104024002402003a722054120490d00200041013a000020002004290000370001200041196a200441186a290000370000200041116a200441106a290000370000200041096a200441086a2900003700000c010b02400240417f4100280284a4c680002206410147200641014b1b2206417f460d00200641ff01710d010b2002413c6a4194afc3800041022001412010dc8a8080002002412c6a410c6a41c082808000360200200241c18280800036023020022002418f016a36023420022002413c6a36022c4100280290a1c680002101410028028ca1c6800021064100280280a4c68000210720024180016a4202370200200241f8006a4102360200200241f0006a4110360200200241ec006a4184bac38000360200200241e0006a4194bac38000ad4280808080900d84370200200241c8006a410c6a41fdbac38000ad4280808080800484370200200241fc006a2002412c6a360200200241f4b9c38000360274200241013602682002410036025c2002410036025020024281808080c003370248200641ecf2c08000200741024622071b200241c8006a200141d4f2c0800020071b28021011848080800000200228023c450d00200228024041002802c0a3c68000118080808000000b200041003a00000b200241246a20042005200228021828020c118580808000000b20024190016a2480808080000bc30405017f017e027f017e027f2380808080004190016b2202248080808000200241086a2001412041002802b8a1c68000118580808000000240024020022802080d00420021030c010b200241186a41086a200241086a41086a290200220337030020022002290208370318200228021c2104024002402003a722054108490d0020042900002106420121030c010b02400240417f4100280284a4c680002207410147200741014b1b2207417f460d00200741ff01710d010b2002413c6a4194afc3800041022001412010dc8a8080002002412c6a410c6a41c082808000360200200241c18280800036023020022002418f016a36023420022002413c6a36022c4100280290a1c680002101410028028ca1c6800021074100280280a4c68000210820024180016a4202370200200241f8006a4102360200200241f0006a4110360200200241ec006a4184bac38000360200200241e0006a4194bac38000ad4280808080900d84370200200241c8006a410c6a41fdbac38000ad4280808080800484370200200241fc006a2002412c6a360200200241f4b9c38000360274200241013602682002410036025c2002410036025020024281808080c003370248200741ecf2c08000200841024622081b200241c8006a200141d4f2c0800020081b28021011848080800000200228023c450d00200228024041002802c0a3c68000118080808000000b42002106420021030b200241246a20042005200228021828020c118580808000000b200020063703082000200337030020024190016a2480808080000bbf0405017f017e027f017e027f2380808080004190016b2202248080808000200241086a2001412041002802b8a1c68000118580808000000240024020022802080d00420021030c010b200241186a41086a200241086a41086a290200220337030020022002290208370318200228021c2104024002402003a722054108490d0020042900002106420121030c010b02400240417f4100280284a4c680002207410147200741014b1b2207417f460d00200741ff01710d010b2002413c6a4194afc3800041022001412010dc8a8080002002412c6a410c6a41c082808000360200200241c18280800036023020022002418f016a36023420022002413c6a36022c4100280290a1c680002101410028028ca1c6800021074100280280a4c68000210820024180016a4202370200200241f8006a4102360200200241f0006a4110360200200241ec006a4184bac38000360200200241e0006a4194bac38000ad4280808080900d84370200200241c8006a410c6a41fdbac38000ad4280808080800484370200200241fc006a2002412c6a360200200241f4b9c38000360274200241013602682002410036025c2002410036025020024281808080c003370248200741ecf2c08000200841024622081b200241c8006a200141d4f2c0800020081b28021011848080800000200228023c450d00200228024041002802c0a3c68000118080808000000b420021030b200241246a20042005200228021828020c118580808000000b200020063703082000200337030020024190016a2480808080000bec0405017f017e037f017e017f2380808080004190016b2202248080808000200241086a2001412041002802b8a1c68000118580808000000240024020022802080d00200041033a00100c010b200241186a41086a200241086a41086a290200220337030020022002290208370318200228021c2104024002402003a722054108490d0020054178714108460d0020054110460d0020042d0010220641024b0d002004290000210320042900082107200020063a001020002007370308200020033703000c010b02400240417f4100280284a4c680002206410147200641014b1b2206417f460d00200641ff01710d010b2002413c6a4194afc3800041022001412010dc8a8080002002412c6a410c6a41c082808000360200200241c18280800036023020022002418f016a36023420022002413c6a36022c4100280290a1c680002101410028028ca1c6800021064100280280a4c68000210820024180016a4202370200200241f8006a4102360200200241f0006a4110360200200241ec006a4184bac38000360200200241e0006a4194bac38000ad4280808080900d84370200200241c8006a410c6a41fdbac38000ad4280808080800484370200200241fc006a2002412c6a360200200241f4b9c38000360274200241013602682002410036025c2002410036025020024281808080c003370248200641ecf2c08000200841024622081b200241c8006a200141d4f2c0800020081b28021011848080800000200228023c450d00200228024041002802c0a3c68000118080808000000b200041033a00100b200241246a20042005200228021828020c118580808000000b20024190016a2480808080000baa0703027f017e047f2380808080004190016b2203248080808000200341086a2001200241002802b8a1c68000118580808000000240024020032802080d0041808080807821040c010b200341186a41086a200341086a41086a290200220537030020032003290208370318200328021c2106024002402005a72207450d002007417f6a21080240024002400240024020062d000022044103710e0400030201000b200641016a2109200441027621040c030b20074105490d03200441034b0d0320062800012204418080808004490d03200641056a21092007417b6a21080c020b20074104490d02200641036a2d000041187420062f000141087472200472220441808004490d0220044102762104200641046a21092007417c6a21080c010b2008450d0120062d000141087420047241ffff03712204418002490d01200641026a21092007417e6a2108200441027621040b20082004490d0002400240024020040d00410121080c010b2004417f4c0d03200441002802c8a3c68000118180808000002208450d01200841002004108a8e8080001a0b20082009200410848e8080002108200341246a20062007200328021828020c118580808000002001200241002802a0a1c68000118480808000002004ad4220862008ad8421050c030b4101200410b280808000000b02400240417f4100280284a4c680002204410147200441014b1b2204417f460d00200441ff01710d010b2003413c6a4194afc3800041022001200210dc8a8080002003412c6a410c6a41c082808000360200200341c18280800036023020032003418f016a36023420032003413c6a36022c4100280290a1c680002104410028028ca1c6800021024100280280a4c68000210120034180016a4202370200200341f8006a4102360200200341f0006a4110360200200341ec006a4184bac38000360200200341e0006a4194bac38000ad4280808080900d84370200200341c8006a410c6a41fdbac38000ad4280808080800484370200200341fc006a2003412c6a360200200341f4b9c38000360274200341013602682003410036025c2003410036025020034281808080c003370248200241ecf2c08000200141024622011b200341c8006a200441d4f2c0800020011b28021011848080800000200328023c450d00200328024041002802c0a3c68000118080808000000b200341246a20062007200328021828020c1185808080000041808080807821040c010b10ae80808000000b200020053702042000200436020020034190016a2480808080000ba90903027f017e067f23808080800041b0016b2201248080808000200142fc90b9e5d09296e777370308200142a6d4e6f1a4dd959860370300200142a0b9ab8f9ae5999778370318200142f999a7c78cd1d1cdb17f370310200141286a2001412041002802b8a1c6800011858080800000024002400240024020012802280d0041818080807821020c010b200141386a41086a200141286a41086a290200220337030020012001290228370338200128023c21040240024002402003a722050d000c010b2005417f6a210602400240024002400240024020042d000022024103710e0400010402000b200441016a2107200241027621080c040b20060d010c040b20054105490d03200241034b0d0320042800012208418080808004490d03200441056a21072005417b6a21060c020b20042d000141087420027241ffff03712202418002490d02200441026a21072005417e6a2106200241027621080c010b20054104490d01200441036a2d000041187420042f000141087472200272220241808004490d0120024102762108200441046a21072005417c6a21060b2006450d002006417f6a21090240024002400240024020072d000022024103710e0400010203000b200741016a2107200241027621020c030b2009450d0320072d000141087420027241ffff03712202418002490d03200741026a21072006417e6a2109200241027621020c020b20064104490d02200741036a2d000041187420072f000141087472200272220241808004490d0220024102762102200741046a21072006417c6a21090c010b20064105490d01200241034b0d0120072800012202418080808004490d01200741056a21072006417b6a21090b20092002490d000240024020020d00410121060c010b2002417f4c0d04200241002802c8a3c68000118180808000002206450d05200641002002108a8e8080001a0b2002ad42208620062007200210848e808000ad8421030c010b02400240417f4100280284a4c680002202410147200241014b1b2202417f460d00200241ff01710d010b200141dc006a4194afc3800041022001412010dc8a808000200141cc006a410c6a41c082808000360200200141c1828080003602502001200141af016a3602542001200141dc006a36024c4100280290a1c680002102410028028ca1c6800021064100280280a4c680002107200141a0016a420237020020014198016a410236020020014190016a41103602002001418c016a4184bac3800036020020014180016a4194bac38000ad4280808080900d84370200200141e8006a410c6a41fdbac38000ad42808080808004843702002001419c016a200141cc006a360200200141f4b9c380003602940120014101360288012001410036027c2001410036027020014281808080c003370268200641ecf2c08000200741024622071b200141e8006a200241d4f2c0800020071b28021011848080800000200128025c450d00200128026041002802c0a3c68000118080808000000b41818080807821020b200141c4006a20042005200128023828020c118580808000000b2000200836020c2000200337020420002002360200200141b0016a2480808080000f0b10ae80808000000b4101200210b280808000000bb90703017f017e057f23808080800041b0016b2201248080808000200142f0fe93e98686d7ab8c7f37030820014280eee1b0e3b7afe9987f37030020014282fceae49dd9e2861d370318200142de8c84a1ecd0a6d30c370310200141206a2001412041002802b8a1c68000118580808000000240024002402001280220450d00200141306a41086a200141206a41086a29020022023703002001200129022037033020012002a72203360248200120012802342204360244024002402003450d0020012003417f6a22053602482001200441016a3602440240024002400240024020042d000022064103710e0400030102000b200641027621060c030b20034104490d0320012003417c6a3602482001200441046a360244200441036a2d000041187420042f000141087472200672220641808004490d03200641027621060c020b200641044f0d0220034105490d0220012003417b6a3602482001200441056a360244200428000122064180808080044f0d010c020b2005450d0120012003417e6a3602482001200441026a36024420042d000141087420067241ffff03712206418002490d01200641027621060b200141e8006a200141c4006a200610ca8580800020012802682206418080808078460d00200129026c21020c010b02400240417f4100280284a4c680002206410147200641014b1b2206417f460d00200641ff01710d010b200141dc006a4194afc3800041022001412010dc8a808000200141cc006a410c6a41c082808000360200200141c1828080003602502001200141af016a3602542001200141dc006a36024c4100280290a1c680002106410028028ca1c6800021054100280280a4c680002107200141a0016a420237020020014198016a410236020020014190016a41103602002001418c016a4184bac3800036020020014180016a4194bac38000ad4280808080900d84370200200141e8006a410c6a41fdbac38000ad42808080808004843702002001419c016a200141cc006a360200200141f4b9c380003602940120014101360288012001410036027c2001410036027020014281808080c003370268200541ecf2c08000200741024622071b200141e8006a200641d4f2c0800020071b28021011848080800000200128025c450d00200128026041002802c0a3c68000118080808000000b41808080807821060b2001413c6a20042003200128023028020c118580808000002006418080808078470d010b2000410036020820004280808080103702000c010b20002002370204200020063602000b200141b0016a2480808080000ba20503027f017e047f23808080800041b0016b2201248080808000200142fc90b9e5d09296e777370308200142a6d4e6f1a4dd95986037030020014293bb8a9cbb9ab6b31a370318200142ffabedd185d3d8d216370310200141286a2001412041002802b8a1c68000118580808000000240024020012802280d00410321020c010b200141386a41086a200141286a41086a290200220337030020012001290228370338200128023c21040240024002402003a72205450d000240024020042d000022020e03000401020b2005417b6a417b4b0d0120042800012106410021020c030b410221020c010b02400240417f4100280284a4c680002206410147200641014b1b2206417f460d00200641ff01710d010b200141dc006a4194afc3800041022001412010dc8a808000200141cc006a410c6a41c082808000360200200141c1828080003602502001200141af016a3602542001200141dc006a36024c4100280290a1c680002106410028028ca1c6800021024100280280a4c680002107200141a0016a420237020020014198016a410236020020014190016a41103602002001418c016a4184bac3800036020020014180016a4194bac38000ad4280808080900d84370200200141e8006a410c6a41fdbac38000ad42808080808004843702002001419c016a200141cc006a360200200141f4b9c380003602940120014101360288012001410036027c2001410036027020014281808080c003370268200241ecf2c08000200741024622071b200141e8006a200641d4f2c0800020071b28021011848080800000200128025c450d00200128026041002802c0a3c68000118080808000000b410321020b0b200141c4006a20042005200128023828020c118580808000000b2000200636020420002002360200200141b0016a2480808080000b910503027f017e057f23808080800041b0016b2200248080808000200042fc90b9e5d09296e777370308200042a6d4e6f1a4dd959860370300200042beee8ae9ce8fa2b1977f37031820004295d4f9afa2868fb86437031041002101200041286a2000412041002802b8a1c680001185808080000002402000280228450d00200041386a41086a200041286a41086a290200220237030020002000290228370338200028023c2103024002402002a72201450d0020032d000041ff01712204450d004101410220044101461b21040c010b410021040b02402004410220011b22044102470d000240417f4100280284a4c680002205410147200541014b1b2205417f460d00200541ff01710d010b200041dc006a4194afc3800041022000412010dc8a808000200041cc006a410c6a41c082808000360200200041c1828080003602502000200041af016a3602542000200041dc006a36024c4100280290a1c680002105410028028ca1c6800021064100280280a4c680002107200041a0016a420237020020004198016a410236020020004190016a41103602002000418c016a4184bac3800036020020004180016a4194bac38000ad4280808080900d84370200200041e8006a410c6a41fdbac38000ad42808080808004843702002000419c016a200041cc006a360200200041f4b9c380003602940120004101360288012000410036027c2000410036027020004281808080c003370268200641ecf2c08000200741024622071b200041e8006a200541d4f2c0800020071b28021011848080800000200028025c450d00200028026041002802c0a3c68000118080808000000b200041c4006a20032001200028023828020c11858080800000200441017121010b200041b0016a24808080800020010bb80703017f017e057f23808080800041b0016b2201248080808000200142fc90b9e5d09296e777370308200142a6d4e6f1a4dd959860370300200142f4fa97f89782c7a62d37031820014299cfe7ffe3b8eac708370310200141206a2001412041002802b8a1c68000118580808000000240024002402001280220450d00200141306a41086a200141206a41086a29020022023703002001200129022037033020012002a72203360248200120012802342204360244024002402003450d0020012003417f6a22053602482001200441016a3602440240024002400240024020042d000022064103710e0400030102000b200641027621060c030b20034104490d0320012003417c6a3602482001200441046a360244200441036a2d000041187420042f000141087472200672220641808004490d03200641027621060c020b200641044f0d0220034105490d0220012003417b6a3602482001200441056a360244200428000122064180808080044f0d010c020b2005450d0120012003417e6a3602482001200441026a36024420042d000141087420067241ffff03712206418002490d01200641027621060b200141e8006a200141c4006a200610c98580800020012802682206418080808078460d00200129026c21020c010b02400240417f4100280284a4c680002206410147200641014b1b2206417f460d00200641ff01710d010b200141dc006a4194afc3800041022001412010dc8a808000200141cc006a410c6a41c082808000360200200141c1828080003602502001200141af016a3602542001200141dc006a36024c4100280290a1c680002106410028028ca1c6800021054100280280a4c680002107200141a0016a420237020020014198016a410236020020014190016a41103602002001418c016a4184bac3800036020020014180016a4194bac38000ad4280808080900d84370200200141e8006a410c6a41fdbac38000ad42808080808004843702002001419c016a200141cc006a360200200141f4b9c380003602940120014101360288012001410036027c2001410036027020014281808080c003370268200541ecf2c08000200741024622071b200141e8006a200641d4f2c0800020071b28021011848080800000200128025c450d00200128026041002802c0a3c68000118080808000000b41808080807821060b2001413c6a20042003200128023028020c118580808000002006418080808078470d010b2000410036020820004280808080c0003702000c010b20002002370204200020063602000b200141b0016a2480808080000ba80603027f017e047f23808080800041d0016b2201248080808000200142fc90b9e5d09296e777370328200142a6d4e6f1a4dd959860370320200142f7b6fccfd083b2cf4d370338200142afd2c6ffdbc495bc08370330200141c8006a200141206a412041002802b8a1c68000118580808000000240024020012802480d00410221020c010b200141d8006a41086a200141c8006a41086a290200220337030020012001290248370358200128025c2104024002402003a722054120490d000240024020054120460d0020042d002041ff01712202450d004101410220024101461b21020c010b410021020b20054120460d0020024102460d00200141186a200441186a290000370300200141106a200441106a290000370300200141086a200441086a290000370300200120042900003703000c010b02400240417f4100280284a4c680002202410147200241014b1b2202417f460d00200241ff01710d010b200141fc006a4194afc380004102200141206a412010dc8a808000200141ec006a410c6a41c082808000360200200141c1828080003602702001200141cf016a3602742001200141fc006a36026c4100280290a1c680002102410028028ca1c6800021064100280280a4c680002107200141c0016a4202370200200141b8016a4102360200200141b0016a4110360200200141ac016a4184bac38000360200200141a0016a4194bac38000ad4280808080900d8437020020014188016a410c6a41fdbac38000ad4280808080800484370200200141bc016a200141ec006a360200200141f4b9c380003602b401200141013602a8012001410036029c01200141003602900120014281808080c00337028801200641ecf2c08000200741024622071b20014188016a200241d4f2c0800020071b28021011848080800000200128027c450d0020012802800141002802c0a3c68000118080808000000b410221020b200141e4006a20042005200128025828020c118580808000000b200020023a000020002001290300370001200041096a200141086a290300370000200041116a200141106a290300370000200041196a200141186a290300370000200141d0016a2480808080000b900201037f23808080800041306b2201248080808000200142919fd78da1a1ad84ff003703082001429ceccef7a6c0dedd2037030020014292d189e4a1e58a9fcc00370318200142aa9f83c8cbf687edfa003703100240024020002802082202417f4c0d0041002d00fca3c680001a200241286c410472220241002802c8a3c68000118180808000002203450d0120012003360228200120023602242001410036022c2000200141246a108087808000200128022421002001412020012802282202200128022c41002802e0a1c680001186808080000002402000450d00200241002802c0a3c68000118080808000000b200141306a2480808080000f0b10ae80808000000b4101200210b280808000000b8e0201037f23808080800041306b2201248080808000200142919fd78da1a1ad84ff003703082001429ceccef7a6c0dedd2037030020014282fceae49dd9e2861d370318200142de8c84a1ecd0a6d30c3703100240024020002802082202417f4c0d0041002d00fca3c680001a200241286c410472220241002802c8a3c68000118180808000002203450d0120012003360228200120023602242001410036022c2000200141246a108087808000200128022421002001412020012802282202200128022c41002802e0a1c680001186808080000002402000450d00200241002802c0a3c68000118080808000000b200141306a2480808080000f0b10ae80808000000b4101200210b280808000000b860203017f017e027f23808080800041306b2201248080808000200142919fd78da1a1ad84ff003703082001429ceccef7a6c0dedd20370300200142d8d2dfcce2f8e59341370318200142faa5fa8ea9819ff1bd7f3703102000290300210241002d00fca3c680001a02404101410e20024203511b220341002802c8a3c68000118180808000002204450d0020012004360228200120033602242001410036022c2000200141246a10b28c808000200128022421002001412020012802282203200128022c41002802e0a1c680001186808080000002402000450d00200341002802c0a3c68000118080808000000b200141306a2480808080000f0b4101200310b280808000000bae0201037f23808080800041306b2201248080808000200142919fd78da1a1ad84ff003703082001429ceccef7a6c0dedd2037030020014282fceae49dd9e2861d370318200142de8c84a1ecd0a6d30c3703100240024020002802082202417f4c0d0041002d00fca3c680001a200241286c410472220241002802c8a3c68000118180808000002203450d0120012003360228200120023602242001410036022c2000200141246a108087808000200128022421022001412020012802282203200128022c41002802e0a1c680001186808080000002402002450d00200341002802c0a3c68000118080808000000b02402000280200450d00200028020441002802c0a3c68000118080808000000b200141306a2480808080000f0b10ae80808000000b4101200210b280808000000b840604027f017e047f017e23808080800041b0016b2201248080808000200142919fd78da1a1ad84ff003703082001429ceccef7a6c0dedd2037030020014290f1f7a1ea9083df363703182001428b87a199bee8b0f0ac7f370310200141286a2001412041002802b8a1c68000118580808000000240024020012802280d00410321020c010b200141386a41086a200141286a41086a290200220337030020012001290228370338200128023c2104024002402003a72205450d0020054109490d0020042d000041ff01714101470d00200541776a4108490d0020054111460d0020042d001122024103490d010b02400240417f4100280284a4c680002202410147200241014b1b2202417f460d00200241ff01710d010b200141dc006a4194afc3800041022001412010dc8a808000200141cc006a410c6a41c082808000360200200141c1828080003602502001200141af016a3602542001200141dc006a36024c4100280290a1c680002102410028028ca1c6800021064100280280a4c680002107200141a0016a420237020020014198016a410236020020014190016a41103602002001418c016a4184bac3800036020020014180016a4194bac38000ad4280808080900d84370200200141e8006a410c6a41fdbac38000ad42808080808004843702002001419c016a200141cc006a360200200141f4b9c380003602940120014101360288012001410036027c2001410036027020014281808080c003370268200641ecf2c08000200741024622071b200141e8006a200241d4f2c0800020071b28021011848080800000200128025c450d00200128026041002802c0a3c68000118080808000000b200141c4006a20042005200128023828020c11858080800000410321020c010b2004290001210820042900092103200141c4006a20042005200128023828020c118580808000002001412041002802a0a1c68000118480808000000b200020033703082000200837030020002001280068360011200020023a0010200041146a200141eb006a280000360000200141b0016a2480808080000be10201027f23808080800041c0006b2201248080808000200142fc90b9e5d09296e777370308200142a6d4e6f1a4dd959860370300200142f4fa97f89782c7a62d37031820014299cfe7ffe3b8eac7083703100240024002400240024020002d000022020e050001020304000b2001200041016a36023420012000410c6a2902003702380c030b2001200041016a36023420012000410c6a2902003702380c020b2001200041016a36023420012000410c6a2902003702380c010b2001200041086a2902003702340b20012002360230200141246a200141306a10ed8480800020014120200141246a4100280298a1c680001185808080000002400240024002400240024020002d00000e0400010203050b200041086a21000c030b200041086a21000c020b200041086a21000c010b200041046a21000b2000280200450d00200028020441002802c0a3c68000118080808000000b200141c0006a2480808080000b9c0706017f027e027f017e037f017e23808080800041c0016b2200248080808000200042919fd78da1a1ad84ff003703182000429ceccef7a6c0dedd20370310200042a4feeaa7f9c4ff8f0e370328200042e99dbcf9dba59e96b37f370320200041306a200041106a412041002802b8a1c68000118580808000000240024020002802300d00420021010c010b200041c0006a41086a200041306a41086a29020022023703002000200029023037034020002802442103024002402002a722044108490d0020044178714108460d0020032900082105420121010c010b02400240417f4100280284a4c680002206410147200641014b1b2206417f460d00200641ff01710d010b200041e4006a4194afc380004102200041106a412010dc8a808000200041d4006a410c6a41c082808000360200200041c1828080003602582000200041bf016a36025c2000200041e4006a3602544100280290a1c680002106410028028ca1c6800021074100280280a4c680002108200041a8016a4202370200200041a0016a410236020020004198016a411036020020004194016a4184bac3800036020020004188016a4194bac38000ad4280808080900d84370200200041f0006a410c6a41fdbac38000ad4280808080800484370200200041a4016a200041d4006a360200200041f4b9c3800036029c01200041013602900120004100360284012000410036027820004281808080c003370270200741ecf2c08000200841024622081b200041f0006a200641d4f2c0800020081b280210118480808000002000280264450d00200028026841002802c0a3c68000118080808000000b420021010b200041cc006a20032004200028024028020c118580808000000b200042fc90b9e5d09296e777370378200042a6d4e6f1a4dd959860370370200042d3d8c5d2a9b9d2c1ac7f3703880120004282ca868eabf3add0cf00370380012000200041f0006a10e6888080002000290308210220002903002109200042919fd78da1a1ad84ff003703782000429ceccef7a6c0dedd20370370200042a4feeaa7f9c4ff8f0e37038801200042e99dbcf9dba59e96b37f3703800141002d00fca3c680001a0240411041002802c8a3c680001181808080000022040d004101411010b280808000000b2004420020052001501b3700002004200242002009a71b370008200041f0006a41202004411041002802e0a1c6800011868080800000200441002802c0a3c6800011808080800000200041c0016a2480808080000bee0e05017f017e047f017e017f23808080800041c0016b2202248080808000200242919fd78da1a1ad84ff003703082002429ceccef7a6c0dedd2037030020024282ea96a7a8d58af34c370318200242b7f092fcc2eaf1f65f370310200241286a2002412041002802b8a1c68000118580808000000240024002400240024002402002280228450d00200241386a41086a200241286a41086a29020022033703002002200229022837033820022003a7220436024c2002200228023c2205360248024002402004450d0020022004417f6a220636024c2002200541016a36024802400240024002400240024020052d000022074103710e0400030102000b200741027621070c040b20044104490d0420022004417c6a36024c2002200541046a360248200541036a2d000041187420052f000141087472200772220641027621072006418080044921060c020b200741044f0d0320044105490d0320022004417b6a36024c2002200541056a360248200528000122074180808080044921060c010b2006450d0220022004417e6a36024c2002200541026a36024820052d000141087420077241ffff03712206410276210720064180024921060b20060d01200741e4004b0d010b200241f0006a200241c8006a200710cb8580800020022802702207418080808078460d00200229027421080c010b02400240417f4100280284a4c680002207410147200741014b1b2207417f460d00200741ff01710d010b200241e4006a4194afc3800041022002412010dc8a808000200241d0006a410c6a41c082808000360200200241c1828080003602542002200241bf016a3602582002200241e4006a3602504100280290a1c680002107410028028ca1c6800021064100280280a4c680002109200241a8016a4202370200200241a0016a410236020020024198016a411036020020024194016a4184bac3800036020020024188016a4194bac38000ad4280808080900d84370200200241f0006a410c6a41fdbac38000ad4280808080800484370200200241a4016a200241d0006a360200200241f4b9c3800036029c01200241013602900120024100360284012002410036027820024281808080c003370270200641ecf2c08000200941024622091b200241f0006a200741d4f2c0800020091b280210118480808000002002280264450d00200228026841002802c0a3c68000118080808000000b41808080807821070b200241c4006a20052004200228023828020c118580808000002007418080808078460d002002200736023820002903002103200128020021042002200837023c20032004ad5a0d010c040b41002107200241003602402002428080808080013703382000290300220320012802002204ad540d030c010b0240024002402008422088a7220541e3004b0d00200541e300470d020c010b2008a72207200741106a200541047441706a10fe8d8080001a200228023821070b41e3002105200241e3003602400b20052007470d010b200241386a200710a286808000200228024021050b200228023c20054104746a22072004360208200720033703002002200228024041016a3602400c010b0240417f4100280284a4c680002207410247200741024b1b2207417f460d00200741ff01710d010b2002410c6a41858080800036020020022001360208200241cf80808000360204200220003602004100280290a1c680002107410028028ca1c6800021044100280280a4c680002105200241a8016a4202370200200241a0016a410336020020024198016a410d36020020024194016a41b5b3c3800036020020024188016a41dcb2c38000ad4280808080900b84370200200241f0006a410c6a41c2b3c38000ad4280808080b00184370200200241a4016a2002360200200241c4b2c3800036029c0120024100360284012002410036027820024281808080c0d1003702702002410236029001200441ecf2c08000200541024622051b200241f0006a200741d4f2c0800020051b280210118480808000000b200241d0006a41086a200241386a41086a28020036020020022002290338220337035002400240024002402003a72207418080808078470d00200242919fd78da1a1ad84ff003703782002429ceccef7a6c0dedd2037037020024282ea96a7a8d58af34c37038801200242b7f092fcc2eaf1f65f37038001200241f0006a412041002802a0a1c68000118480808000000c010b200242919fd78da1a1ad84ff003703782002429ceccef7a6c0dedd2037037020024282ea96a7a8d58af34c37038801200242b7f092fcc2eaf1f65f3703800120022802582204417f4c0d0141002d00fca3c680001a2004410474410472220441002802c8a3c68000118180808000002205450d02200220053602042002200436020020024100360208200241d0006a200210828780800020022802002104200241f0006a412020022802042205200228020841002802e0a1c680001186808080000002402004450d00200541002802c0a3c68000118080808000000b2007450d00200228025441002802c0a3c68000118080808000000b200241c0016a2480808080000f0b10ae80808000000b4101200410b280808000000bc00301077f23808080800041206b220224808080800041002d00fca3c680001a0240410141002802c8a3c68000118180808000002203450d0020032001417f6a3a0000200241013602102002200336020c20024101360208200241086a4101410310ab86808000200228020c2203200228021022046a220541003b0000200541026a41003a000020022802082105024002400240200441036a22044104470d00200341036a2d0000210420032d0002210620032d0001210720032d000021082005450d01200341002802c0a3c68000118080808000000c010b2005418080808078470d01200341187621042003411076210620034180fe03714108762107200321080b200041033a00002000410d6a20073a00002000410c6a20083a0000200041106a41033a00002000410e6a20063a00002000410f6a20043a0000200041086a200141187441808080786a41187541027422034188cfc380006a2802003602002000200341b8cfc380006a280200360204200241206a2480808080000f0b2002200436021c200220033602182002200536021441e0b3c3800041cb00200241146a4188b5c3800041fcbbc38000108981808000000b4101410110b280808000000bc30b06057f017e037f017e017f017e23808080800041c0016b22022480808080000240024002402001280200220128020422034108490d002001200341786a220436020420012001280200220541086a220636020020044120490d01200529000021072001200341586a22083602042001200541286a2204360200200241086a200641086a290000370300200241106a200641106a290000370300200241186a200641186a29000037030020022006290000370300024020084120490d002001200341b87f6a22063602042001200541c8006a360200200241a0016a41086a200441086a290000370300200241a0016a41106a200441106a290000370300200241a0016a41186a200441186a290000370300200220042900003703a00120064108490d002001200341b07f6a22043602042001200541d0006a220636020020024180016a41086a2208200241a0016a41086a29030037030020024180016a41106a2209200241a0016a41106a29030037030020024180016a41186a220a200241a0016a41186a290300370300200220022903a00137038001200441c000490d002005290048210b2001200341f07e6a220c360204200120054190016a2204360200200241206a41086a200641086a290000370300200241206a41106a200641106a290000370300200241206a41186a200641186a290000370300200241206a41206a200641206a290000370300200241206a41286a200641286a290000370300200241206a41306a200641306a290000370300200241206a41386a200641386a29000037030020022006290000370320200241e0006a41186a200a290300370300200241e0006a41106a2009290300370300200241e0006a41086a20082903003703002002200229038001370360200c4120490d002001200341d07e6a22063602042001200541b0016a360200200241a0016a41086a2208200441086a290000370300200241a0016a41106a2209200441106a290000370300200241a0016a41186a220a200441186a290000370300200220042900003703a00120064108490d002001200341c87e6a22043602042001200541b8016a220636020020024180016a41086a200829030037030020024180016a41106a200929030037030020024180016a41186a200a290300370300200220022903a00137038001200441c000490d0020052900b001210d2001200341887e6a3602042001200541f8016a360200200041c0016a2006290000370000200041c8016a200641086a290000370000200041d0016a200641106a290000370000200041d8016a200641186a290000370000200041e0016a200641206a290000370000200041e8016a200641286a290000370000200041f0016a200641306a290000370000200041f8016a200641386a290000370000200041b0016a20024180016a41186a290300370300200041a8016a20024180016a41106a290300370300200041a0016a20024180016a41086a29030037030020004198016a200229038001370300200041206a200241186a290300370000200041186a200241106a290300370000200041106a200241086a29030037000020002002290300370008200041306a2002290360370300200041386a200241e0006a41086a290300370300200041c0006a200241e0006a41106a290300370300200041c8006a200241e0006a41186a290300370300200041d8006a2002290320370300200041e0006a200241206a41086a290300370300200041e8006a200241206a41106a290300370300200041f0006a200241206a41186a290300370300200041f8006a200241206a41206a29030037030020004180016a200241206a41286a29030037030020004188016a200241206a41306a29030037030020004190016a200241206a41386a290300370300200041b8016a200d370300200041d0006a200b370300200041286a2007370300200042003703000c030b200042013703000c020b200042013703000c010b200042013703000b200241c0016a2480808080000bdd0a04067f017e027f017e23808080800041d0006b2201248080808000200141286a41eabdc38000410c41cfbdc38000411041a0b5c38000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041e00041002802c8a3c68000118180808000002202450d00200242c4a8f7cba2aea4ad35370308200241f9bdc38000360240200241f8bdc38000360220200241ff8180800036021820024102360204200241f6bdc38000360200200241d0006a42919fe7f19ec9d1a177370300200241c8006a42d0ffe6c89b859fc430370300200241306a42ecb2f697e9f8a9f860370300200241286a42ef899cf7a6a3ca9dd100370300200241106a42949384fce98ae9ac977f370300200241d8006a41b482808000360200200241c4006a4101360200200241386a41b382808000360200200241246a410136020020014103360248200120023602402001200241e0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a200141106a410c6a220241086a2802003602002001200229020037030020012802102103200128021421042001280218210520012802282106200129022c2107200141106a41086a22084100360200200142808080808001370210200141106a410010a4868080002001280214200828020041386c6a2202420437022c20024203370224200241bcf2c480003602202002410c36021c200241bba4c58000360218200241ef8080800036021020024293888c8f89fdc6ec9e7f370308200242a5e9e3ab9e929adc2c370300200141c0006a41086a2209200828020041016a220236020020012001290210220a37034002402002200aa7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c20024202370224200241d0fbc480003602202002410836021c200241b3a4c58000360218200241ff81808000360210200242949384fce98ae9ac977f370308200242c4a8f7cba2aea4ad353703002008200928020041016a220236020020012001290340220a37031002402002200aa7470d00200141106a200210a486808000200128021821020b2001280214200241386c6a2202420437022c20024206370224200241a7a4c580003602202002410536021c200241a2a4c58000360218200241c58280800036021020024285f5e9f2d6c0a4cd48370308200242ece297b9e9e4c9bdda00370300200141c0006a41086a200141106a41086a28020041016a220236020020012001290310220a37034002402002200aa7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c20024206370224200241a7a4c580003602202002410636021c200241ada4c58000360218200241c58280800036021020024285f5e9f2d6c0a4cd48370308200242ece297b9e9e4c9bdda00370300200128024821082001280244210220012001280240360248200120023602402001200236024420012002200841386c6a41386a36024c200141346a200141c0006a10f9868080002006418080808078460d012001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002006360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841e00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000bde0a04067f017e027f017e23808080800041d0006b2201248080808000200141286a41eabdc38000410c41cfbdc38000411041a0b5c38000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041e00041002802c8a3c68000118180808000002202450d00200242c4a8f7cba2aea4ad35370308200241f9bdc38000360240200241f8bdc38000360220200241ff8180800036021820024102360204200241f6bdc38000360200200241d0006a42919fe7f19ec9d1a177370300200241c8006a42d0ffe6c89b859fc430370300200241306a42c6bb82f1efc886d58a7f370300200241286a42c6bdb6a4b5ec93c2d300370300200241106a42949384fce98ae9ac977f370300200241d8006a41b482808000360200200241c4006a4101360200200241386a41b782808000360200200241246a410136020020014103360248200120023602402001200241e0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a200141106a410c6a220241086a2802003602002001200229020037030020012802102103200128021421042001280218210520012802282106200129022c2107200141106a41086a22084100360200200142808080808001370210200141106a410010a4868080002001280214200828020041386c6a2202420437022c20024203370224200241bcf2c480003602202002410c36021c200241bba4c58000360218200241ef8080800036021020024293888c8f89fdc6ec9e7f370308200242a5e9e3ab9e929adc2c370300200141c0006a41086a2209200828020041016a220236020020012001290210220a37034002402002200aa7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c20024202370224200241d0fbc480003602202002410836021c200241b3a4c58000360218200241ff81808000360210200242949384fce98ae9ac977f370308200242c4a8f7cba2aea4ad353703002008200928020041016a220236020020012001290340220a37031002402002200aa7470d00200141106a200210a486808000200128021821020b2001280214200241386c6a2202420437022c20024206370224200241a7a4c580003602202002410536021c200241a2a4c58000360218200241c682808000360210200242c5bcc8a2879389a83a3703082002428f8de586a6e995cafa00370300200141c0006a41086a200141106a41086a28020041016a220236020020012001290310220a37034002402002200aa7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c20024206370224200241a7a4c580003602202002410636021c200241ada4c58000360218200241c682808000360210200242c5bcc8a2879389a83a3703082002428f8de586a6e995cafa00370300200128024821082001280244210220012001280240360248200120023602402001200236024420012002200841386c6a41386a36024c200141346a200141c0006a10f9868080002006418080808078460d012001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002006360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841e00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000be30201047f23808080800041206b220224808080800041002d00fca3c680001a0240410441002802c8a3c68000118180808000002203450d002002410c6a41086a22044100360200200220033602102002410436020c200241003602182002200241186a36021c2002411c6a2002410c6a10c08a808000200241086a220520042802003602002002200229020c3703000240200128020822032001280200470d0020012003109d86808000200128020821030b2001280204200341e8006c6a220342a19eece481d0928e393703082003410b36024420034185bec38000360240200341c782808000360218200341003602002003200229030037034820032000290200370254200341013a0060200341106a42cdba88b6a38cd989b57f370300200341d0006a2005280200360200200341dc006a200041086a2802003602002001200128020841016a360208200241206a2480808080000f0b4101410410b280808000000be90503067f017e027f23808080800041d0006b2201248080808000200141286a41a1c1c38000410e41afc1c38000412541a0b5c38000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041c00041002802c8a3c68000118180808000002202450d00200242e5f0b3f4e8a9b1b12a370308200241f9bdc38000360220200241f88180800036021820024101360204200241c5b5c38000360200200241106a4281ebc5ecd497b09a0a370300200241386a4100360200200241246a410136020020014102360248200120023602402001200241c0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a22032001411c6a220241086a28020036020020012002290200370300200128021021042001280214210520012802182106200129022c21072001280228210820014100360218200142808080808001370210200141106a410010a4868080002001280214200128021841386c6a2202420437022c20024206370224200241cae4c4800036022020024100360218200241c882808000360210200242c6be9491c9dc9cca59370308200242c7e49fb5d2d4f6ebb47f370300200128021821092001280214210220012001280210360248200120023602402001200236024420012002200941386c6a41386a36024c200141346a200141c0006a10f9868080002008418080808078460d012001200436021820012005360210200120053602142001200520064105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002008360238200041003a000020002001290300370350200041d8006a20032802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841c00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000bd60301087f23808080800041206b22022480808080002002410036021c200242808080801037021441002d00fca3c680001a0240412041002802c8a3c68000118180808000002203450d0020034200370000200341186a22044200370000200341106a22054200370000200341086a22064200370000200241146a4100412010b1828080002002280218200241146a41086a220728020022086a22092003290000370000200941086a2006290000370000200941106a2005290000370000200941186a20042900003700002007200841206a360200200341002802c0a3c6800011808080800000200241086a41086a22092007280200360200200220022902143703080240200128020822032001280200470d0020012003109d86808000200128020821030b2001280204200341e8006c6a220342c194a6a793ccc3a8573703082003410a36024420034186bfc38000360240200341f581808000360218200341003602002003200229030837034820032000290200370254200341013a0060200341106a42ab8bffbed784ffa5937f370300200341d0006a2009280200360200200341dc006a200041086a2802003602002001200128020841016a360208200241206a2480808080000f0b4101412010b280808000000be30201047f23808080800041206b220224808080800041002d00fca3c680001a0240410441002802c8a3c68000118180808000002203450d002002410c6a41086a22044100360200200220033602102002410436020c200241003602182002200241186a36021c2002411c6a2002410c6a10c08a808000200241086a220520042802003602002002200229020c3703000240200128020822032001280200470d0020012003109d86808000200128020821030b2001280204200341e8006c6a2203428aaac8d3f1d38bddba7f37030820034106360244200341bbbfc38000360240200341c982808000360218200341003602002003200229030037034820032000290200370254200341013a0060200341106a42c6a4f3f9b3bbafd83e370300200341d0006a2005280200360200200341dc006a200041086a2802003602002001200128020841016a360208200241206a2480808080000f0b4101410410b280808000000be40201047f23808080800041206b220224808080800041002d00fca3c680001a0240410441002802c8a3c68000118180808000002203450d002002410c6a41086a22044100360200200220033602102002410436020c200241003602182002200241186a36021c2002411c6a2002410c6a10fb84808000200241086a220520042802003602002002200229020c3703000240200128020822032001280200470d0020012003109d86808000200128020821030b2001280204200341e8006c6a220342fddcc0b9c5fc86d6a17f37030820034106360244200341edbfc38000360240200341ca82808000360218200341003602002003200229030037034820032000290200370254200341013a0060200341106a4296b787c192cbb889d000370300200341d0006a2005280200360200200341dc006a200041086a2802003602002001200128020841016a360208200241206a2480808080000f0b4101410410b280808000000be30201047f23808080800041206b220224808080800041002d00fca3c680001a0240410441002802c8a3c68000118180808000002203450d002002410c6a41086a22044100360200200220033602102002410436020c200241003602182002200241186a36021c2002411c6a2002410c6a10c08a808000200241086a220520042802003602002002200229020c3703000240200128020822032001280200470d0020012003109d86808000200128020821030b2001280204200341e8006c6a220342a19eece481d0928e393703082003410f36024420034199c0c38000360240200341c782808000360218200341003602002003200229030037034820032000290200370254200341013a0060200341106a42cdba88b6a38cd989b57f370300200341d0006a2005280200360200200341dc006a200041086a2802003602002001200128020841016a360208200241206a2480808080000f0b4101410410b280808000000be80201047f23808080800041306b22022480808080002002410036022020024280808080800137021841002d00fca3c680001a0240410441002802c8a3c68000118180808000002203450d00200241246a41086a220441003602002002200336022820024104360224200241186a200241246a108287808000200241086a41086a22052004280200360200200220022902243703080240200128020822032001280200470d0020012003109d86808000200128020821030b2001280204200341e8006c6a22034293bfa0a5e3cecac4ec003703082003410d360244200341dfc0c38000360240200341cb82808000360218200341003602002003200229030837034820032000290200370254200341013a0060200341106a429698dbdf9eeb9da04b370300200341d0006a2005280200360200200341dc006a200041086a2802003602002001200128020841016a360208200241306a2480808080000f0b4101410410b280808000000ba50301077f23808080800041106b220224808080800041002d00fca3c680001a02400240411841002802c8a3c68000118180808000002203450d00200320012802002204290000370000200341106a200441106a290000370000200341086a200441086a29000037000020022003360208200241183602042002411836020c2001280204210141002d00fca3c680001a412041002802c8a3c68000118180808000002203450d0120032001290000370000200341186a2205200141186a290000370000200341106a2206200141106a290000370000200341086a2207200141086a290000370000200241046a4118412010b18280800020022802082204200228020c22086a22012003290000370000200141086a2007290000370000200141106a2006290000370000200141186a200529000037000020022802042101200341002802c0a3c680001180808080000020002004200841206a4100280298a3c680001185808080000002402001450d00200441002802c0a3c68000118080808000000b200241106a2480808080000f0b4101411810b280808000000b4101412010b280808000000bd90201037f23808080800041206b2203248080808000024002402002417f4c0d0041002d00fca3c680001a2002410574410472220441002802c8a3c68000118180808000002205450d0120034100360214200320053602102003200436020c200320023602182003200341186a36021c2003411c6a2003410c6a10c08a80800002402002450d00200241057421052003280214210203400240200328020c20026b411f4b0d002003410c6a2002412010b182808000200328021421020b200328021020026a22042001290000370000200441086a200141086a290000370000200441106a200141106a290000370000200441186a200141186a2900003700002003200241206a2202360214200141206a2101200541606a22050d000b0b2000200329020c370200200041086a2003410c6a41086a280200360200200341206a2480808080000f0b10ae80808000000b4101200410b280808000000be90503067f017e027f23808080800041d0006b2201248080808000200141286a41a1c1c38000410e41afc1c38000412541a0b5c38000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041c00041002802c8a3c68000118180808000002202450d00200242d7c9c3bdedbdd399957f370308200241f9bdc38000360220200241f28180800036021820024101360204200241c5b5c38000360200200241106a42a6f8d4ee83cba9e440370300200241386a4100360200200241246a410136020020014102360248200120023602402001200241c0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a22032001411c6a220241086a28020036020020012002290200370300200128021021042001280214210520012802182106200129022c21072001280228210820014100360218200142808080808001370210200141106a410010a4868080002001280214200128021841386c6a2202420437022c20024206370224200241cae4c4800036022020024100360218200241cc82808000360210200242dfbcf99189a39d8f56370308200242b2f3abcf8fb9a3b15e370300200128021821092001280214210220012001280210360248200120023602402001200236024420012002200941386c6a41386a36024c200141346a200141c0006a10f9868080002008418080808078460d012001200436021820012005360210200120053602142001200520064105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002008360238200041003a000020002001290300370350200041d8006a20032802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841c00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000b040041000bed0201027f23808080800041206b2202248080808000200028020028020021002002200128021441a0b5c380004100200141186a28020028020c118280808000003a000c2002200136020841012103200241013a000d20024100360204200220003602102002200041086a2201360214200220013602182002200136021c200241046a200241106a41b4c4c38000108d81808000200241146a41b4c4c38000108d81808000200241186a41c4c4c38000108d818080002002411c6a41d4c4c38000108d81808000210120022d000c210002400240200128020022010d00200041ff017141004721030c010b200041ff01710d0020022802082100024020014101470d0020022d000d41ff0171450d0020002d001c4104710d00410121032000280214418ca5c080004101200041186a28020028020c118280808000000d010b2000280214418da5c080004101200041186a28020028020c1182808080000021030b200241206a24808080800020030be30101047f23808080800041106b22022480808080002000280200220041046a280200210320002802002100410121042001280214418fa5c080004101200141186a28020028020c118280808000002105200241003a0009200220053a00082002200136020402402003450d0003402002200036020c200241046a2002410c6a41d0cfc48000108e818080001a200041016a21002003417f6a22030d000b20022d000821050b0240200541ff01710d00200228020422002802144190a5c080004101200041186a28020028020c1182808080000021040b200241106a24808080800020040bf60201037f2380808080004180016b22022480808080002000280200210002400240024002400240200128021c22034110710d0020034120710d0120003100004101200110fe8080800021000c020b20002d00002103410021000340200220006a41ff006a413041d7002003410f712204410a491b20046a3a00002000417f6a2100200341ff017122044104762103200441104f0d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000c010b20002d00002103410021000340200220006a41ff006a413041372003410f712204410a491b20046a3a00002000417f6a2100200341ff017122044104762103200441104f0d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000b20024180016a24808080800020000f0b200341800141c88dc08000109481808000000b200341800141c88dc08000109481808000000b12002000280200280200200110ab888080000bf40201037f2380808080004180016b22022480808080002000280200210002400240024002400240200128021c22034110710d0020034120710d0120003502004101200110fe8080800021000c020b20002802002100410021030340200220036a41ff006a413041d7002000410f712204410a491b20046a3a00002003417f6a210320004110492104200041047621002004450d000b20034180016a22004180014b0d022001410141c48dc080004102200220036a4180016a410020036b10db8080800021000c010b20002802002100410021030340200220036a41ff006a413041372000410f712204410a491b20046a3a00002003417f6a210320004110492104200041047621002004450d000b20034180016a22004180014b0d022001410141c48dc080004102200220036a4180016a410020036b10db8080800021000b20024180016a24808080800020000f0b200041800141c88dc08000109481808000000b200041800141c88dc08000109481808000000b9a0201027f23808080800041106b2202248080808000200220002802002200360204200128021441acc6c380004106200141186a28020028020c118280808000002103200241003a000d200220033a000c20022001360208200241086a41b2c6c380004104200041046a41b8c6c38000108c8180800041c8c6c380004105200241046a41d0c6c38000108c81808000210320022d000c21000240024020022d000d0d00200041ff017141004721010c010b41012101200041ff01710d000240200328020022012d001c4104710d0020012802144187a5c080004102200128021828020c1182808080000021010c010b20012802144186a5c080004101200128021828020c1182808080000021010b200241106a24808080800020010b140020002802002000280204200110e2808080000b3c00200128021420002802002d000041027422004190d0c380006a280200200041e8cfc380006a280200200141186a28020028020c118280808000000b9a0201027f23808080800041106b220224808080800020022000280200220041046a360204200128021441e0c6c380004109200141186a28020028020c118280808000002103200241003a000d200220033a000c20022001360208200241086a41e9c6c38000410b200041b8c6c38000108c8180800041f4c6c380004109200241046a4180c7c38000108c81808000210320022d000c21000240024020022d000d0d00200041ff017141004721010c010b41012101200041ff01710d000240200328020022012d001c4104710d0020012802144187a5c080004102200128021828020c1182808080000021010c010b20012802144186a5c080004101200128021828020c1182808080000021010b200241106a24808080800020010b1900200028020022002802002000280204200110e2808080000b0f002000280200200110ac888080000bf80202027f017e2380808080004180016b22022480808080002000280200210002400240024002400240200128021c22034110710d0020034120710d0120002903004101200110fe8080800021000c020b20002903002104410021000340200220006a41ff006a413041d7002004a7410f712203410a491b20036a3a00002000417f6a210020044210542103200442048821042003450d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000c010b20002903002104410021000340200220006a41ff006a413041372004a7410f712203410a491b20036a3a00002000417f6a210020044210542103200442048821042003450d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000b20024180016a24808080800020000f0b200341800141c88dc08000109481808000000b200341800141c88dc08000109481808000000b2100200128021441c4cdc38000410f200141186a28020028020c118280808000000b1f002000280200220041046a280200200041086a280200200110e2808080000b9a0201027f23808080800041106b220224808080800020022000280200220041086a360204200128021441e0c8c380004106200141186a28020028020c118280808000002103200241003a000d200220033a000c20022001360208200241086a41e6c8c380004108200041f0c8c38000108c818080004180c9c38000410a200241046a41e4c3c38000108c81808000210320022d000c21000240024020022d000d0d00200041ff017141004721010c010b41012101200041ff01710d000240200328020022012d001c4104710d0020012802144187a5c080004102200128021828020c1182808080000021010c010b20012802144186a5c080004101200128021828020c1182808080000021010b200241106a24808080800020010bab0201027f23808080800041106b220224808080800020002802002100200128021441bcaec380004111200141186a28020028020c118280808000002103200241003a000d200220033a000c2002200136020841012101200241086a4196c3c380004108200041226a41a0c3c38000108c8180800041b0c3c380004104200041b4c3c38000108c8180800041c4c3c38000410d200041016a41d4c3c38000108c81808000210320022d000c21000240024020022d000d0d00200041ff017141004721010c010b200041ff01710d000240200328020022012d001c4104710d0020012802144187a5c080004102200128021828020c1182808080000021010c010b20012802144186a5c080004101200128021828020c1182808080000021010b200241106a24808080800020010bf80201037f2380808080004180016b22022480808080002000280200210002400240024002400240200128021c22034110710d0020034120710d0120003301004101200110fe8080800021000c020b20002f01002103410021000340200220006a41ff006a413041d7002003410f712204410a491b20046a3a00002000417f6a2100200341ffff037122044104762103200441104f0d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000c010b20002f01002103410021000340200220006a41ff006a413041372003410f712204410a491b20046a3a00002000417f6a2100200341ffff037122044104762103200441104f0d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000b20024180016a24808080800020000f0b200341800141c88dc08000109481808000000b200341800141c88dc08000109481808000000b370020012802144196c9c38000418ac9c3800020002802002d000022001b4107410c20001b200141186a28020028020c118280808000000b7901017f23808080800041106b220224808080800020022000280200220036020c200141d9c5c38000410b41e4c5c3800041052000410c6a41ecc5c3800041fcc5c380004105200041086a4184c6c380004194c6c3800041072002410c6a419cc6c3800010e0808080002100200241106a24808080800020000b9d0101017f23808080800041306b220224808080800020002802002100200241086a410c6a4202370200200241206a410c6a41cf808080003602002002410336020c20024190c8c280003602082002200041086a360228200241cf8080800036022420022000360220200141186a28020021002002200241206a36021020012802142000200241086a10d9808080002101200241306a24808080800020010bef0201037f2380808080004180016b220224808080800002400240024002400240200128021c22034110710d0020034120710d0120003100004101200110fe8080800021000c020b20002d00002103410021000340200220006a41ff006a413041d7002003410f712204410a491b20046a3a00002000417f6a2100200341ff017122044104762103200441104f0d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000c010b20002d00002103410021000340200220006a41ff006a413041372003410f712204410a491b20046a3a00002000417f6a2100200341ff017122044104762103200441104f0d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000b20024180016a24808080800020000f0b200341800141c88dc08000109481808000000b200341800141c88dc08000109481808000000bf10202027f017e2380808080004180016b220224808080800002400240024002400240200128021c22034110710d0020034120710d0120002903004101200110fe8080800021000c020b20002903002104410021000340200220006a41ff006a413041d7002004a7410f712203410a491b20036a3a00002000417f6a210020044210542103200442048821042003450d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000c010b20002903002104410021000340200220006a41ff006a413041372004a7410f712203410a491b20036a3a00002000417f6a210020044210542103200442048821042003450d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000b20024180016a24808080800020000f0b200341800141c88dc08000109481808000000b200341800141c88dc08000109481808000000b02000b02000b02000b220002402000280200450d00200028020441002802c0a3c68000118080808000000b0b220002402000280200450d00200028020441002802c0a3c68000118080808000000b0b02000b4601017f23808080800041106b22052480808080002005200236020c200520013602082000200541086a41e4c3c380002005410c6a41e4c3c380002003200410fb80808000000b4601017f23808080800041106b22052480808080002005200236020c200520013602082000200541086a41f4c3c380002005410c6a41f4c3c380002003200410fb80808000000b4601017f23808080800041106b22052480808080002005200236020c200520013602082000200541086a4184c4c380002005410c6a4184c4c380002003200410fb80808000000b4601017f23808080800041106b22052480808080002005200236020c200520013602082000200541086a4194c4c380002005410c6a4194c4c380002003200410fb80808000000b4601017f23808080800041106b22052480808080002005200236020c200520013602082000200541086a41a4c4c380002005410c6a41a4c4c380002003200410fb80808000000b9b0101057f200020002802002201109b868080000240200028020822022001200028020c22036b4d0d002000280200210402400240200120026b2205200320056b22034d0d00200420016b20034f0d010b20002802042201200420056b22034102746a200120024102746a200541027410fe8d8080001a200020033602080f0b2000280204220020014102746a2000200341027410848e8080001a0b0b800302037f027e23808080800041306b2205248080808000200541106a41086a2001280200220141086a220628020036020020064100360200200520012902003703102001428080808010370200200541086a200541106a200220032004109287808000200528020c21040240024002400240200528020822030d00200528021021022005411c6a200528021422072005280218220610fc808080000240200528021c0d002006ad2108200721060c030b200529022021082002418080808078470d01200721020c020b2005280210450d02200528021441002802c0a3c68000118080808000000c020b200520083702282005200236021c20052006ad4220862007ad84370220419dc9c38000412b2005411c6a41c8c9c3800041b4cac38000108981808000000b2006ad4220862002ad8421092008a7210202402001280200450d00200128020441002802c0a3c68000118080808000000b20012002360208200120093702000b2000200336020020002004360204200541306a2480808080000b950201027f23808080800041106b220224808080800020022000410c6a36020420012802144190c7c38000410d200141186a28020028020c118280808000002103200241003a000d200220033a000c20022001360208200241086a419dc7c38000410520004188b5c38000108c8180800041fcc5c380004105200241046a41a4c7c38000108c81808000210320022d000c21000240024020022d000d0d00200041ff017141004721010c010b41012101200041ff01710d000240200328020022012d001c4104710d0020012802144187a5c080004102200128021828020c1182808080000021010c010b20012802144186a5c080004101200128021828020c1182808080000021010b200241106a24808080800020010bdd0401027f23808080800041106b22022480808080000240024002400240024002400240024002400240024020002f01000e09000102030405060708000b200128021441b4c7c380004109200141186a28020028020c1182808080000021010c090b200128021441bdc7c380004109200141186a28020028020c1182808080000021010c080b2002200041026a3602002002200128021441c6c7c380004118200141186a28020028020c118280808000003a000c20022001360208200241003a000d20024100360204200241046a200241e0c7c38000108d81808000210120022d000c21000240200128020022030d00200041ff017141004721010c080b41012101200041ff01710d072002280208210020034101470d0620022d000d41ff0171450d0620002d001c4104710d06410121012000280214418ca5c080004101200041186a28020028020c11828080800000450d060c070b200128021441f0c7c38000410f200141186a28020028020c1182808080000021010c060b200128021441ffc7c38000410d200141186a28020028020c1182808080000021010c050b2001280214418cc8c38000410d200141186a28020028020c1182808080000021010c040b20012802144199c8c38000410b200141186a28020028020c1182808080000021010c030b200128021441a4c8c380004110200141186a28020028020c1182808080000021010c020b200128021441b4c8c380004112200141186a28020028020c1182808080000021010c010b2000280214418da5c080004101200041186a28020028020c1182808080000021010b200241106a24808080800020010b950201027f23808080800041106b22022480808080002002200041086a360204200128021441e0c8c380004106200141186a28020028020c118280808000002103200241003a000d200220033a000c20022001360208200241086a41e6c8c380004108200041f0c8c38000108c818080004180c9c38000410a200241046a41e4c3c38000108c81808000210320022d000c21000240024020022d000d0d00200041ff017141004721010c010b41012101200041ff01710d000240200328020022012d001c4104710d0020012802144187a5c080004102200128021828020c1182808080000021010c010b20012802144186a5c080004101200128021828020c1182808080000021010b200241106a24808080800020010b3400200128021441d1cac3800041c9cac3800020002d000022001b4107410820001b200141186a28020028020c118280808000000bc40501057f23808080800041c0006b220224808080800041002d00fca3c680001a41002802c8a3c68000210302400240024002400240024041002f0194a1c68000220441ffff00712205413f4b0d004101210641012003118180808000002203450d02200320043a00000c010b4102210641022003118180808000002203450d02200320044106742005410876723a00012003200441fc017141027641c000723a00000b200220063602182002200336021420022006360210200241106a2006412010ab8680800020022802142206200228021822046a22032000290000370000200341086a200041086a290000370000200341106a200041106a290000370000200341186a200041186a2900003700002002200441206a22003602182002411c6a2006200010e8838080002002280224220341014d0d022002280220210302402002280210220420006b41014b0d00200241106a2000410210ab868080002002280214210620022802102104200228021821000b200620006a20032f00003b00002002410036023020024280808080103702282002200241286a360234200220063602382002200041026a220536023c200241086a200241346a200041036a41017620056a200241386a41d4cbc3800010a9898080002002280208210002402004450d00200641002802c0a3c68000118080808000000b20000d0320022802302104200228022c2100200228022821050240200228021c450d00200341002802c0a3c68000118080808000000b4100210602402001200141046a2000200410ae86808000450d0010fd8280800021060b02402005450d00200041002802c0a3c68000118080808000000b200241c0006a24808080800020060f0b4101410110b280808000000b4101410210b280808000000b4102200341c4cbc38000109581808000000b41b4a1c38000412b200241386a41e0a1c3800041f0a1c38000108981808000000b9a0f020a7f027e23808080800041e0006b2202248080808000200241286a200110f48a808000200228022c2103024002400240024002400240024020022802282204418080808078460d0020022802302101200241d4cbc38000360254200220013602502002200336024c410021052002410036023020024280808080103702282002200241286a360248200241d8006a200241c8006a2001200241cc006a41d4cbc38000108587808000024020022802582201418380c400460d002001411076210102402002280228450d00200228022c41002802c0a3c68000118080808000000b410021050c050b200228022c2106024020022802282207418080808078470d00200641107621010c050b41012105200228023022084102490d0320062d0000220141c000490d0102402001411874411875417f4a0d00410421050c040b4102210920062d0001220a413f714108742001410274200a4106767241ff01717221010c020b200041013a0000200020033602040c050b410121090b2008200941226a470d000240200141feff0071412e470d00410721050c010b200241cc006a20062009412072220510e883808000024002400240024002402002280254220a41014d0d002002280250210a0240024002400240200820056b4102470d00200620056a2f0000200a2f0000470d00200620096a22092f0003210520092f0001210820092d0000210b2002413f6a2009411c6a280000360000200241386a200941156a290000370300200241306a2009410d6a290000370300200220092900053703280240200228024c450d00200a41002802c0a3c68000118080808000000b02402007450d00200641002802c0a3c68000118080808000000b2001413a490d08200141c00f4a0d02200141b7034a0d01200141416a0ece010808080808080807080808070707080807070807070707070707070707070707070707070707070707070807070707080707080707070807070707070707070807070707080707070707070707070707070707070707070707070707070707070707070707070707070707070708070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070807070807070707070707070707070708030b0240200228024c450d00200a41002802c0a3c68000118080808000000b410321050c080b0240200141d5084a0d00024020014194064a0d00200141b803460d082001419a05470d070c080b2001419506460d07200141e307470d060c070b0240200141d0756a0e0a07060606060606060607000b200141d608460d06200141ec0b470d050c060b0240200141de364a0d00024020014196114a0d000240200141bf706a0e30080707070707070707070707070707070707070707070807080707070707070707070707080707070707070707070708000b200141d46f6a220641144b0d064101200674418180c10071450d060c070b0240200141a51f4a0d002001419711460d07200141ce11460d07200141851a470d060c070b0240200141f1284a0d00200141a61f460d07200141e222470d060c070b200141f228460d06200141ce2f470d050c060b0240200141cecd004a0d000240200141a1c5004a0d000240200141a1496a0e0708070707070708000b2001418a39460d07200141df39470d060c070b200141deba7f6a220641144d0d030c040b0240200141fade004a0d000240200141ddd9004a0d00200141cfcd00460d07200141b9ce00470d060c070b200141ded900460d06200141acdc00470d050c060b0240200141bbe6004a0d00200141fbde00460d062001419fdf00470d050c060b200141bce600460d05200141e9f200460d050c040b200141a403470d030c040b4102200a4190cdc38000109581808000000b4101200674418180c800710d020b200141f0c600460d01200141cfcc00460d010b02400240200141c4094a0d00200141a87f6a0e320202020102020101010102020202010101010101010101010101010101010101010101010101010102020101010101010202010b200141bb766a4102490d01200141fc756a4102490d01200141e26e6a4102490d010b200141bca77f6a417d4b0d00200141002f0194a1c68000460d00410221050c020b200241086a41176a2201200241286a41176a280000360000200241086a41106a2206200241286a41106a290300370300200241086a41086a200241286a41086a290300220c37030020022002290328220d370308200041046a20053b0100200041026a20083b01002000200b3a0001200041066a200d3701002000410e6a200c370100200041166a20062903003701002000411d6a2001280000360000410021010c020b024020070d000c010b200641002802c0a3c68000118080808000000b200220013b014a200220053b0148200241346a4201370200410121012002410136022c200241d8cac38000360228200241cd8280800036025c2002200241d8006a3602302002200241c8006a360258200241cc006a200241286a10b8808080002000200241cc006a10ea8a8080003602040b200020013a00002004450d00200341002802c0a3c68000118080808000000b200241e0006a2480808080000bc30201027f23808080800041106b22022480808080000240024020002d00000d00200128021441a0cdc38000410c200141186a28020028020c1182808080000021030c010b410121032002200041016a3602002002200128021441accdc380004106200141186a28020028020c118280808000003a000c20022001360208200241003a000d20024100360204200241046a200241b4cdc38000108d81808000210120022d000c21000240200128020022010d00200041ff017141004721030c010b200041ff01710d0020022802082100024020014101470d0020022d000d41ff0171450d0020002d001c4104710d00410121032000280214418ca5c080004101200041186a28020028020c118280808000000d010b2000280214418da5c080004101200041186a28020028020c1182808080000021030b200241106a24808080800020030bba0203027f017e017f23808080800041d0006b2201248080808000200141286a41b9d0c38000411241fe8bc48000411641e8d1c38000410010d882808000200141086a2202410036020020014280808080c000370300200129022c210320012802282104200142808080808001370218200142888080808001370210200141346a200141106a10f98680800002402004418080808078470d0041a8d8c480004111419cd9c4800010a181808000000b200042808080808001370244200041cc006a4100360200200141cc006a200141346a41086a2802003600002000413c6a200337020020002004360238200041003a000020002001290300370350200041d8006a20022802003602002001200129023437004420002001290041370001200041086a200141c8006a290000370000200141d0006a2480808080000b2000200042bae6c989f69dacb01a3703082000428e8397fa82e98fd06e3703000bca0204067f017e027f017e200141186a2802002102200141106a2802002103200128020821042001280204210520012802002106024003402001418180808078360200024002400240024020064180808080786a0e020200010b20032002460d0120012003410c6a220736021020032802002206418080808078460d0120032902042208422088a721042008a72105200721030b2005210720062109024020032002460d0020012003410c6a220a36021020032802002206418080808078470d020b2001200b37020420014180808080783602000c030b20004180808080783602000f0b20012003290204220b370204200120063602002004200b422088a7470d012007200ba72205200410888e8080000d01200a21032009450d00200741002802c0a3c6800011808080800000200a21030c000b0b2000200436020820002007360204200020093602000b1400200041ecd4c38000360204200020013602000b1400200041ecd4c38000360204200020013602000bef0201027f23808080800041c0006b2203248080808000200320023a000c200320013602082003410036021820034280808080103702102003411c6a200341086a10ec8a8080000240024020032d001c0d002003411c6a41027221020240034020032d001d410171450d010240200328021822042003280210470d00200341106a200410a186808000200328021821040b200328021420044105746a22012002290000370000200141086a200241086a290000370000200141106a200241106a290000370000200141186a200241186a2900003700002003200441016a3602182003411c6a200341086a10ec8a80800020032d001c450d000b2000200328022036020420004180808080783602002003280210450d02200328021441002802c0a3c68000118080808000000c020b20002003290210370200200041086a200341106a41086a2802003602000c010b2000200328022036020420004180808080783602000b200341c0006a2480808080000bdd0702047f017e23808080800041306b2203248080808000024002400240024002402000280200220441736a2205410220054104491b0e0400010203000b41002105024002400240024002400240024002400240024020002d0008417f6a0e0b0001020304050607090908090b200041146a28020041046a21050c080b410821050c070b200041146a28020041046a21050c060b200041146a28020041046a21050c050b200041146a28020041186c41047221050c040b200041146a280200410c6c41046a21050c030b417f200041186a280200220541086a22042004200541046a491b21050c020b200041146a28020041046a21050c010b200041146a28020041046a21050b200541016a21050c030b200041086a10bc8780800021050c020b410021050240024002400240024002400240024002402004417f6a0e0c000102030405080608070707000b41d00021050c070b2000410c6a28020041046a21050c060b417f200041186a28020041046a220541012000410c6a28020041056a2000280204418080808078461b6a220420042005491b21050c050b417f200041186a2802002000410c6a28020041046a22056a41046a220420042005491b21050c040b2000410c6a28020041046a21050c030b2000410c6a28020041046a21050c020b410821050c010b410421050b200541016a21050c010b200041086a10a78c80800021050b41012104200541016a21064102210502402000290358220742c000540d0041032105200742808001540d00410521052007428080808004540d00410a200779a74103766b21050b024002400240200620056a4121410120002d0088011b6a2205450d002005417f4c0d0141002d00fca3c680001a200541002802c8a3c68000118180808000002204450d020b20004188016a210620034100360214200320043602102003200536020c20002003410c6a10b8898080002003200041d8006a36022c2003412c6a2003410c6a10c18a808000200041e0006a2d000021050240200328020c20032802142200470d002003410c6a2000410110b182808000200328021421000b200328021020006a20053a00002003200041016a36021420062003410c6a10b18c80800020032802102100200328020c210502400240200328021422044180024b0d00200120002004200241002802c8a2c680001189808080000021040c010b2003410c6a200020044100280298a3c680001185808080000020012003410c6a4120200241002802c8a2c680001189808080000021040b02402005450d00200041002802c0a3c68000118080808000000b200341306a24808080800020040f0b10ae80808000000b4101200510b280808000000bcd0201017f0240024002400240200028020041736a2202410220024104491b0e0400010203000b0240200128020020012802082202470d0020012002410110b182808000200128020821020b2001200241016a360208200128020420026a41003a0000200041086a200110a78a8080000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b2001200241016a360208200128020420026a41013a0000200041086a200110bb878080000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b2001200241016a360208200128020420026a41023a00002000200110ba888080000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b2001200241016a360208200128020420026a41033a0000200041086a200110a68c8080000bca0101057f23808080800041206b220124808080800041002102200141003602102001428080808010370208200141146a10b98980800041012103200128021821040240200128021c2205450d00200141086a4100200510b182808000200128020c2103200128021021020b200320026a2004200510848e8080001a2001200220056a36021002402001280214450d00200441002802c0a3c68000118080808000000b20002001290208370200200041086a200141086a41086a280200360200200141206a2480808080000b840201037f23808080800041106b22022480808080000240024020012802082203410c6c20034103746a41066a2203417f4c0d0041002d00fca3c680001a200341002802c8a3c68000118180808000002204450d012002200436020820022003360204200420012d000c3a00002002410136020c20012d000d210441012103024020022802044101470d00200241046a4101410110b182808000200228020c21030b200228020820036a20043a0000200241046a41086a2204200341016a3602002001200241046a10d48c808000200041086a200428020036020020002002290204370200200241106a2480808080000f0b10ae80808000000b4101200310b280808000000b2100200128021441f4dec180004108200141186a28020028020c118280808000000b210020012802144194d5c380004111200141186a28020028020c118280808000000b2100200128021441a5d5c38000410a200141186a28020028020c118280808000000b2100200128021441b2e2c180004103200141186a28020028020c118280808000000b2100200128021441d0a7c48000411b200141186a28020028020c118280808000000b2100200128021441f0dec180004104200141186a28020028020c118280808000000b2100200128021441d895c48000410f200141186a28020028020c118280808000000b12002001418a84c48000410210dd808080000b040041010b040041010b02000bb90101037f23808080800041306b220124808080800002400240200028020c22020d0041002102410021030c010b200120023602242001410036022020012002360214200141003602102001200041106a280200220236022820012002360218200041146a2802002103410121020b2001200336022c2001200236021c2001200236020c2001410c6a10928d80800002402000280200450d00200028020441002802c0a3c68000118080808000000b200141306a2480808080000b02000b2d002000410c6a10a58d80800002402000280200450d00200028020441002802c0a3c68000118080808000000b0bef0901057f0240024002400240024002402000280200220141736a2202410220024104491b0e03010203000b20002d00084106470d042000410c6a280200450d04200041106a28020021030c030b0240024002400240024002400240024020002d0008417f6a0e0a010b0203040506070b0b000b2000410c6a280200450d0a200041106a28020021030c090b2000410c6a280200450d09200041106a28020021030c080b2000410c6a280200450d08200041106a28020021030c070b2000410c6a280200450d07200041106a28020021030c060b200041106a28020021030240200041146a2802002201450d0020032102034002402002280200450d00200241046a28020041002802c0a3c68000118080808000000b02402002410c6a280200450d00200241106a28020041002802c0a3c68000118080808000000b200241186a21022001417f6a22010d000b0b200028020c450d060c050b200041106a28020021030240200041146a2802002202450d002002410171210441002101024020024101460d002002417e7121052003210241002101034002402002280200450d00200241046a28020041002802c0a3c68000118080808000000b02402002410c6a280200450d00200241106a28020041002802c0a3c68000118080808000000b200241186a21022005200141026a2201470d000b0b2004450d0020032001410c6c6a2202280200450d00200228020441002802c0a3c68000118080808000000b200028020c0d040c050b200041106a280200450d04200041146a28020021030c030b2000410c6a280200450d03200041106a28020021030c020b200041186a2d0000417d6a41ff017141014b0d020240200028020822034198016a2802002205450d0020034194016a280200220421004100210203402004200241146c6a21010240024002400240024020002d00000e0400010102040b200041086a21010c020b200141086a21010c010b200141046a21010b2001280200450d00200128020441002802c0a3c68000118080808000000b200241016a2102200041146a21002005417f6a22050d000b0b0240200328029001450d0020032802940141002802c0a3c68000118080808000000b024020034190026a2802002205450d002003418c026a280200220421004100210203402004200241146c6a21010240024002400240024020002d00000e0400010102040b200041086a21010c020b200141086a21010c010b200141046a21010b2001280200450d00200128020441002802c0a3c68000118080808000000b200241016a2102200041146a21002005417f6a22050d000b0b200328028802450d01200328028c0241002802c0a3c68000118080808000000c010b024002400240024002400240024002402001417e6a0e06000102030405090b200041046a21000c050b02402000280210450d00200041146a28020041002802c0a3c68000118080808000000b20002802042202418080808078460d07200041046a21000c050b02402000280204450d00200041086a28020041002802c0a3c68000118080808000000b200041106a21000c030b200041046a21000c020b200041046a21000c010b024002400240024020002d00040e0400010203070b2000410c6a21000c030b2000410c6a21000c020b2000410c6a21000c010b200041086a21000b200028020021020b2002450d01200028020421030b200341002802c0a3c68000118080808000000f0b0bc50101027f024002400240024020002802002201418080808078732202410220024104491b0e03030301000b0240024002402000280204220028020041fcffffff076a2202410320024105491b0e0404040102000b2000280204450d03200041086a28020041002802c0a3c68000118080808000000c030b2000280204450d02200041086a28020041002802c0a3c68000118080808000000c020b200010ca898080000c010b2001450d01200028020421000b200041002802c0a3c68000118080808000000b0b29000240200041808080807872418080808078460d00200141002802c0a3c68000118080808000000b0b910401027f23808080800041106b22022480808080000240024002402000280210418080808078460d00200220003602002002200128021441d089c480004102200128021828020c118280808000003a000c20022001360208200241003a000d20024100360204200241046a200241d489c48000108d81808000210120022d000c21000240200128020022030d00200041ff017141004721010c030b41012101200041ff01710d022002280208210020034101470d0120022d000d41ff0171450d0120002d001c4104710d01410121012000280214418ca5c080004101200041186a28020028020c11828080800000450d010c020b200220003602002002200128021441e489c480004103200128021828020c118280808000003a000c20022001360208200241003a000d20024100360204200241046a200241e889c48000108d81808000210120022d000c21000240200128020022030d00200041ff017141004721010c020b41012101200041ff01710d0120022802082100024020034101470d0020022d000d41ff0171450d0020002d001c4104710d00410121012000280214418ca5c080004101200041186a28020028020c118280808000000d020b2000280214418da5c080004101200041186a28020028020c1182808080000021010c010b2000280214418da5c080004101200041186a28020028020c1182808080000021010b200241106a24808080800020010b1900200120002802002200280200200028020410dd808080000bf60b01097f23808080800041e0016b2208248080808000200841356a2002290000370000200841dc006a41ecd4c38000360200200841086a41286a4100360200200841086a41206a4204370200200841086a41186a4200370200200841f4006a2007360200200841ec006a4100360200200841cd006a200241186a290000370000200841c5006a200241106a2900003700002008413d6a200241086a290000370000200820023602602008200136025820084280808080c0003702182008200636027020084100360264200841013a0034200820053602142008410036020c2008200436021020082004410047360208200841b0016a41286a200341286a280200360200200841b0016a41206a200341206a290200370300200841b0016a41186a200341186a290200370300200841b0016a41106a200341106a290200370300200841b0016a41086a2204200341086a290200370300200820032902003703b001200841f8006a200841b0016a109d87808000200828027c210920082802800121032008200841df016a3602b00120092003200841b0016a10d68b808000200841086a41106a210a2008280278210b024002402003450d00200920034104746a210c200841a8016a210d200841b0016a410172210620084184016a41086a210720084184016a41046a210e20084184016a410172210520092103034020032802002201450d012003280204210f02400240024020032802082210450d00200841b0016a200841086a2001200f2010200328020c10918680800020082d00b00122014104460d02200520062f00003b000020072004290200370200200541026a200641026a2d00003a0000200741086a200441086a290200370200200741106a200441106a290200370200200741186a200441186a290200370200200741206a200441206a2802003602000c010b200841b0016a200841086a2001200f10938680800020082d00b00122014104460d01200520062f00003b000020072004290200370200200541026a200641026a2d00003a0000200741086a200441086a290200370200200741106a200441106a290200370200200741186a200441186a290200370200200741206a200441206a2802003602000b200820082802b401220f36028801200820013a008401024020014103460d0002400240024020010e020103000b20082802a80122012001280200220f417f6a360200200d2101200f4101460d010c020b200f200f2802002210417f6a360200200e210120104101470d010b200110e28a8080000b200341106a2203200c470d010c020b0b20082802b4012103200041013a0000200020033602040240200b450d00200941002802c0a3c68000118080808000000b200841086a109086808000200a10908780800002402008280218450d00200828021c41002802c0a3c68000118080808000000b02402008280224450d00200828022841002802c0a3c68000118080808000000b02400240200828026422030d0041002103410021040c010b200820033602c801200841003602c401200820033602b801200841003602b4012008200841e8006a28020022033602cc01200820033602bc0141012103200828026c21040b200820043602d001200820033602c001200820033602b001200841b0016a10a48d8080000c010b0240200b450d00200941002802c0a3c68000118080808000000b200841086a109086808000200a10908780800002402008280218450d00200828021c41002802c0a3c68000118080808000000b02402008280224450d00200828022841002802c0a3c68000118080808000000b4100210341002104024020082802642207450d00200820073602c801200841003602c401200820073602b801200841003602b4012008200841e8006a28020022033602cc01200820033602bc0141012103200828026c21040b200820043602d001200820033602c001200820033602b001200841b0016a10a48d808000200041003a0000200041196a200241186a290000370000200041116a200241106a290000370000200041096a200241086a290000370000200020022900003700010b200841e0016a2480808080000bf60b01097f23808080800041e0016b2208248080808000200841356a2002290000370000200841dc006a41ecd4c38000360200200841086a41286a4100360200200841086a41206a4204370200200841086a41186a4200370200200841f4006a2007360200200841ec006a4100360200200841cd006a200241186a290000370000200841c5006a200241106a2900003700002008413d6a200241086a290000370000200820023602602008200136025820084280808080c0003702182008200636027020084100360264200841013a0034200820053602142008410036020c2008200436021020082004410047360208200841b0016a41286a200341286a280200360200200841b0016a41206a200341206a290200370300200841b0016a41186a200341186a290200370300200841b0016a41106a200341106a290200370300200841b0016a41086a2204200341086a290200370300200820032902003703b001200841f8006a200841b0016a109d87808000200828027c210920082802800121032008200841df016a3602b00120092003200841b0016a10d68b808000200841086a41106a210a2008280278210b024002402003450d00200920034104746a210c200841a8016a210d200841b0016a410172210620084184016a41086a210720084184016a41046a210e20084184016a410172210520092103034020032802002201450d012003280204210f02400240024020032802082210450d00200841b0016a200841086a2001200f2010200328020c10928680800020082d00b00122014104460d02200520062f00003b000020072004290200370200200541026a200641026a2d00003a0000200741086a200441086a290200370200200741106a200441106a290200370200200741186a200441186a290200370200200741206a200441206a2802003602000c010b200841b0016a200841086a2001200f10948680800020082d00b00122014104460d01200520062f00003b000020072004290200370200200541026a200641026a2d00003a0000200741086a200441086a290200370200200741106a200441106a290200370200200741186a200441186a290200370200200741206a200441206a2802003602000b200820082802b401220f36028801200820013a008401024020014103460d0002400240024020010e020103000b20082802a80122012001280200220f417f6a360200200d2101200f4101460d010c020b200f200f2802002210417f6a360200200e210120104101470d010b200110e28a8080000b200341106a2203200c470d010c020b0b20082802b4012103200041013a0000200020033602040240200b450d00200941002802c0a3c68000118080808000000b200841086a108f86808000200a10908780800002402008280218450d00200828021c41002802c0a3c68000118080808000000b02402008280224450d00200828022841002802c0a3c68000118080808000000b02400240200828026422030d0041002103410021040c010b200820033602c801200841003602c401200820033602b801200841003602b4012008200841e8006a28020022033602cc01200820033602bc0141012103200828026c21040b200820043602d001200820033602c001200820033602b001200841b0016a10a48d8080000c010b0240200b450d00200941002802c0a3c68000118080808000000b200841086a108f86808000200a10908780800002402008280218450d00200828021c41002802c0a3c68000118080808000000b02402008280224450d00200828022841002802c0a3c68000118080808000000b4100210341002104024020082802642207450d00200820073602c801200841003602c401200820073602b801200841003602b4012008200841e8006a28020022033602cc01200820033602bc0141012103200828026c21040b200820043602d001200820033602c001200820033602b001200841b0016a10a48d808000200041003a0000200041196a200241186a290000370000200041116a200241106a290000370000200041096a200241086a290000370000200020022900003700010b200841e0016a2480808080000bcc0c01067f2380808080004190026b220a248080808000200a41186a41186a200441186a220b290000370300200a41186a41106a200441106a220c290000370300200a41186a41086a200441086a220d290000370300200a2004290000370318200a410c6a41086a2002360200200a2001360210200a200336020c200a418c016a41f889c48000360200200a41e0006a4100360200200a41386a41206a4204370200200a41386a41186a4200370200200a41a4016a2009360200200a419c016a4100360200200a41fd006a200b290000370000200a41f5006a200c290000370000200a41ed006a200d290000370000200a41e5006a2004290000370000200a4280808080c000370248200a20083602a001200a410036029401200a41013a0064200a200a41186a36029001200a200a410c6a36028801200a2007360244200a410036023c200a2006360240200a2006410047360238200a41e0016a41206a200541206a280200360200200a41e0016a41186a200541186a290200370300200a41e0016a41106a200541106a290200370300200a41e0016a41086a2206200541086a290200370300200a20052902003703e001200a41a8016a200a41e0016a109f87808000200a2802ac01210b200a2802b0012104200a200a418f026a3602e001200b2004200a41e0016a10d68b808000200a41386a41106a210c200a2802a801210d024002402004450d00200b20044104746a2107200a41d8016a210e200a41e0016a4101722101200a41b4016a41086a2105200a41b4016a41046a210f200a41b4016a4101722103200b2104034020042802002202450d0120042802042109024002400240200428020822080d00200a41e0016a200a41386a20022009109486808000200a2d00e00122024104460d01200320012f00003b000020052006290200370200200341026a200141026a2d00003a0000200541086a200641086a290200370200200541106a200641106a290200370200200541186a200641186a290200370200200541206a200641206a2802003602000c020b200a41e0016a200a41386a200220092008200428020c109286808000200a2d00e00122024104460d00200320012f00003b000020052006290200370200200341026a200141026a2d00003a0000200541086a200641086a290200370200200541106a200641106a290200370200200541186a200641186a290200370200200541206a200641206a2802003602000c010b200a2802e4012104200041013a0000200020043602040240200d450d00200b41002802c0a3c68000118080808000000b200a41386a108f86808000200c1090878080000240200a280248450d00200a28024c41002802c0a3c68000118080808000000b0240200a280254450d00200a28025841002802c0a3c68000118080808000000b02400240200a2802940122040d0041002104410021060c010b200a20043602f801200a41003602f401200a20043602e801200a41003602e401200a200a4198016a28020022043602fc01200a20043602ec0141012104200a28029c0121060b200a200636028002200a20043602f001200a20043602e001200a41e0016a10a48d8080000c030b200a200a2802e40122093602b801200a20023a00b401024020024103460d0002400240024020020e020103000b200a2802d801220220022802002209417f6a360200200e210220094101460d010c020b200920092802002208417f6a360200200f210220084101470d010b200210e28a8080000b200441106a22042007470d000b0b0240200d450d00200b41002802c0a3c68000118080808000000b200a41386a108f86808000200c1090878080000240200a280248450d00200a28024c41002802c0a3c68000118080808000000b0240200a280254450d00200a28025841002802c0a3c68000118080808000000b41002104410021060240200a280294012205450d00200a20053602f801200a41003602f401200a20053602e801200a41003602e401200a200a4198016a28020022043602fc01200a20043602ec0141012104200a28029c0121060b200a200636028002200a20043602f001200a20043602e001200a41e0016a10a48d808000200041196a200a41306a290300370000200041116a200a41286a290300370000200041096a200a41206a2903003700002000200a290318370001200041003a00000b200a4190026a2480808080000bcc0c01067f2380808080004190026b220a248080808000200a41186a41186a200441186a220b290000370300200a41186a41106a200441106a220c290000370300200a41186a41086a200441086a220d290000370300200a2004290000370318200a410c6a41086a2002360200200a2001360210200a200336020c200a418c016a41f889c48000360200200a41e0006a4100360200200a41386a41206a4204370200200a41386a41186a4200370200200a41a4016a2009360200200a419c016a4100360200200a41fd006a200b290000370000200a41f5006a200c290000370000200a41ed006a200d290000370000200a41e5006a2004290000370000200a4280808080c000370248200a20083602a001200a410036029401200a41013a0064200a200a41186a36029001200a200a410c6a36028801200a2007360244200a410036023c200a2006360240200a2006410047360238200a41e0016a41206a200541206a280200360200200a41e0016a41186a200541186a290200370300200a41e0016a41106a200541106a290200370300200a41e0016a41086a2206200541086a290200370300200a20052902003703e001200a41a8016a200a41e0016a109f87808000200a2802ac01210b200a2802b0012104200a200a418f026a3602e001200b2004200a41e0016a10d68b808000200a41386a41106a210c200a2802a801210d024002402004450d00200b20044104746a2107200a41d8016a210e200a41e0016a4101722101200a41b4016a41086a2105200a41b4016a41046a210f200a41b4016a4101722103200b2104034020042802002202450d0120042802042109024002400240200428020822080d00200a41e0016a200a41386a20022009109386808000200a2d00e00122024104460d01200320012f00003b000020052006290200370200200341026a200141026a2d00003a0000200541086a200641086a290200370200200541106a200641106a290200370200200541186a200641186a290200370200200541206a200641206a2802003602000c020b200a41e0016a200a41386a200220092008200428020c109186808000200a2d00e00122024104460d00200320012f00003b000020052006290200370200200341026a200141026a2d00003a0000200541086a200641086a290200370200200541106a200641106a290200370200200541186a200641186a290200370200200541206a200641206a2802003602000c010b200a2802e4012104200041013a0000200020043602040240200d450d00200b41002802c0a3c68000118080808000000b200a41386a109086808000200c1090878080000240200a280248450d00200a28024c41002802c0a3c68000118080808000000b0240200a280254450d00200a28025841002802c0a3c68000118080808000000b02400240200a2802940122040d0041002104410021060c010b200a20043602f801200a41003602f401200a20043602e801200a41003602e401200a200a4198016a28020022043602fc01200a20043602ec0141012104200a28029c0121060b200a200636028002200a20043602f001200a20043602e001200a41e0016a10a48d8080000c030b200a200a2802e40122093602b801200a20023a00b401024020024103460d0002400240024020020e020103000b200a2802d801220220022802002209417f6a360200200e210220094101460d010c020b200920092802002208417f6a360200200f210220084101470d010b200210e28a8080000b200441106a22042007470d000b0b0240200d450d00200b41002802c0a3c68000118080808000000b200a41386a109086808000200c1090878080000240200a280248450d00200a28024c41002802c0a3c68000118080808000000b0240200a280254450d00200a28025841002802c0a3c68000118080808000000b41002104410021060240200a280294012205450d00200a20053602f801200a41003602f401200a20053602e801200a41003602e401200a200a4198016a28020022043602fc01200a20043602ec0141012104200a28029c0121060b200a200636028002200a20043602f001200a20043602e001200a41e0016a10a48d808000200041196a200a41306a290300370000200041116a200a41286a290300370000200041096a200a41206a2903003700002000200a290318370001200041003a00000b200a4190026a2480808080000b9b0301077f23808080800041306b220424808080800020032802002105200128020421060240024002400240024020032802042207200141086a28020022086a22090d004101210a0c010b2009417f4c0d01200941002802c8a3c6800011818080800000220a450d02200a41002009108a8e8080001a0b20092008490d02200a2006200810848e808000220a20086a2005200710848e8080001a20012802002101200420032f01083b0114200420093602102004200a36020c200441186a200128020420022004410c6a10e48c8080000240024002402004280218418080808078470d00200441246a2001280200200210e58c8080002004280224418180808078460d0120002004290224370200200041086a200441246a41086a2802003602000c020b20002004290218370200200041086a200441186a41086a2802003602000c010b20004180808080783602000b02402009450d00200a41002802c0a3c68000118080808000000b200441306a2480808080000f0b10ae80808000000b4101200910b280808000000b2008200941c8c5c28000109581808000000b9a0201077f23808080800041106b220524808080800020022802002106200128020421070240024002400240024020022802042208200141086a28020022096a220a0d004101210b0c010b200a417f4c0d01200a41002802c8a3c6800011818080800000220b450d02200b4100200a108a8e8080001a0b200a2009490d02200b2007200910848e808000220b20096a2006200810848e8080001a20012802002101200520022f01083b010c2005200a3602082005200b36020420002001280204200541046a2003200410e78c8080000240200a450d00200b41002802c0a3c68000118080808000000b200541106a2480808080000f0b10ae80808000000b4101200a10b280808000000b2009200a41c8c5c28000109581808000000b960201077f23808080800041106b220324808080800020022802002104200028020421050240024002400240024020022802042206200041086a28020022076a22080d00410121090c010b2008417f4c0d01200841002802c8a3c68000118180808000002209450d02200941002008108a8e8080001a0b20082007490d0220092005200710848e808000220920076a2004200610848e8080001a20002802002100200320022f01083b010c200320083602082003200936020420002802042001200341046a10e98c80800002402008450d00200941002802c0a3c68000118080808000000b200341106a2480808080000f0b10ae80808000000b4101200810b280808000000b2007200841c8c5c28000109581808000000b980201077f23808080800041106b220424808080800020022802002105200028020421060240024002400240024020022802042207200041086a28020022086a22090d004101210a0c010b2009417f4c0d01200941002802c8a3c6800011818080800000220a450d02200a41002009108a8e8080001a0b20092008490d02200a2006200810848e808000220a20086a2005200710848e8080001a20002802002100200420022f01083b010c200420093602082004200a36020420002802042001200441046a200310eb8c80800002402009450d00200a41002802c0a3c68000118080808000000b200441106a2480808080000f0b10ae80808000000b4101200910b280808000000b2008200941c8c5c28000109581808000000bb20301077f23808080800041306b220324808080800020022802002104200028020421050240024002400240024020022802042206200041086a28020022076a22080d00410121090c010b2008417f4c0d01200841002802c8a3c68000118180808000002209450d02200941002008108a8e8080001a0b20082007490d0220092005200710848e808000220920076a2004200610848e8080001a20002802002107200320022f01083b0114200320083602102003200936020c200341186a200728020420012003410c6a10e48c808000024002400240024020032802182200418080808078470d00200341246a2007280200200110e58c80800020032802242200418180808078470d0141808080807821020c030b200328021c21020c010b41808080807821022000418080808078460d01200328022821020b024020000d00410021020c010b200241002802c0a3c6800011808080800000200021020b02402008450d00200941002802c0a3c68000118080808000000b200341306a2480808080002002418080808078470f0b10ae80808000000b4101200810b280808000000b2007200841c8c5c28000109581808000000b1400200041b48ac48000360204200020013602000b1400200041b48ac48000360204200020013602000b1400200041f889c48000360204200020013602000b1400200041f889c48000360204200020013602000b1a0020022001200041dc8ac480002003280228118680808000000b070020002802000bb106010a7f23808080800041d0006b220424808080800002404100280284a4c680004105470d004100280290a1c680002105410028028ca1c6800021064100280280a4c680002107200441c0006a42003702002004413c6a41e8d1c38000360200200441386a4101360200200441306a41163602002004412c6a41e88bc48000360200200441206a41f48ac48000ad4280808080900c84370200200441146a41fe8bc48000ad4280808080e00284370200200441e08bc48000360234200441053602282004410036021c20044100360210200442818080809024370208200641ecf2c08000200741024622071b200441086a200541d4f2c0800020071b280210118480808000000b4102210702400240200128020041736a220541034b0d0020054102460d000c010b200441086a200110d18c808000024020042802182208418080808078460d00200428022c21092004280228210a2004280224210b200428021c210c024020042802202201450d002001410171210d41002105024020014101460d002001417e712106200c210141002105034002402001280200450d00200141046a28020041002802c0a3c68000118080808000000b02402001410c6a280200450d00200141106a28020041002802c0a3c68000118080808000000b200141186a21012006200541026a2205470d000b0b200d450d00200c2005410c6c6a2201280200450d00200128020441002802c0a3c68000118080808000000b02402008450d00200c41002802c0a3c68000118080808000000b02402009450d002009410171210841002105024020094101460d002009417e712106200a210141002105034002402001280200450d00200141046a28020041002802c0a3c68000118080808000000b02402001410c6a280200450d00200141106a28020041002802c0a3c68000118080808000000b200141186a21012006200541026a2205470d000b0b2008450d00200a2005410c6c6a2201280200450d00200128020441002802c0a3c68000118080808000000b0240200b0d000c020b200a41002802c0a3c68000118080808000000c010b20042f0009210120042d000821070b200441d0006a2480808080002001410874200741ff0171720b0700200042017c0b8c0302057f017e024020012802002202200128020822036b411f4b0d0020012003412010b18280800020012802002102200128020821030b2001200341206a22043602082001280204220520036a22032000290000370000200341086a200041086a290000370000200341106a200041106a290000370000200341186a200041186a290000370000200041206a21030240200220046b411f4b0d0020012004412010b1828080002001280200210220012802042105200128020821040b200520046a220620032900003700002001200441206a2204360208200641186a200341186a290000370000200641106a200341106a290000370000200641086a200341086a290000370000200029034021070240200220046b41074b0d0020012004410810b18280800020012802042105200128020821040b200520046a20073700002001200441086a2203360208200029034821070240200128020020036b41074b0d0020012003410810b182808000200128020821030b2001200341086a360208200128020420036a20073700000bcc0704027f017e037f017e23808080800041d0006b2201248080808000200141286a41e795c48000410c41fe8bc48000411641e8d1c38000410010d882808000200141086a410036020020014280808080c00037030020012802282102200129022c2103200141106a41086a22044100360200200142808080808001370210200141106a410010a4868080002001280214200428020041386c6a2205420437022c20054209370224200541edfbc480003602202005410436021c200541daa3c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200141c0006a41086a2206200428020041016a2205360200200120012902102207370340024020052007a7470d00200141c0006a200510a486808000200128024821050b2001280244200541386c6a2205420437022c20054209370224200541edfbc480003602202005410236021c200541d8a3c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db003703002004200628020041016a2205360200200120012903402207370310024020052007a7470d00200141106a200510a486808000200128021821050b2001280214200541386c6a2205420437022c20054207370224200541c7fbc480003602202005410636021c200541c1fbc48000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c370300200141c0006a41086a200141106a41086a28020041016a2205360200200120012903102207370340024020052007a7470d00200141c0006a200510a486808000200128024821050b2001280244200541386c6a2205420437022c2005420537022420054185e4c480003602202005410536021c20054180e4c48000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c370300200128024821042001280244210520012001280240360218200120053602102001200536021420012005200441386c6a41386a36021c200141346a200141106a10f98680800002402002418080808078470d0041a8d8c480004111419cd9c4800010a181808000000b200042808080808001370244200041cc006a4100360200200141cb006a200141346a41086a2802003600002000413c6a200337020020002002360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437004320002001290040370001200041086a200141c7006a290000370000200141d0006a2480808080000ba60501057f23808080800041e0056b220124808080800020014180036a41086a22024200370300200141086a41106a20014190036a41086a290300370300200141e0026a41086a22034200370300200141d0026a41086a22044200370300200141b8026a41086a22054200370300200141b8026a41106a41003602002001420037030820014200370380032001200129039003370310200142003703e002200142003703d002200142003703b80220014201370338200141c8006a200229030037030020012001290380033703402001420037036020014200370358200142d0a38733370350200141f0006a200141b8036a41086a290300370300200120012903b803370368200142003703b801200142003703b001200142d0a387333703a801200141c8016a200141f0026a41086a290300370300200120012903f0023703c001200142003703d001200141e0016a2003290300370300200120012903e0023703d801200142003703e801200141f8016a2004290300370300200120012903d0023703f0012001420037039802200142d8a698d801370390022001420037038802200142d0a3873337038002200141a8026a2005290300370300200120012903b8023703a0022001428180808080a0f8fa053703b0022001428080808080808080c0003703a0012001428090cad2c60e3703980120014201370390012001427f3703880120014280c0a8ca9a3a3703800120014201370378200142ffffffffffffffffbf7f37033020014280b0def7d32b37032820014201370320200141b8036a200141086a108682808000024020012903b8034202520d00200120012d00c0033a00900341aeeac0800041e00020014190036a41c0e9c080004190ebc08000108981808000000b2000200141b8036a41a80210848e8080001a200141e0056a2480808080000bf40701087f23808080800041b0016b2202248080808000024002400240024002400240024020012802002203418080808078460d00200128020421044101210541012106024020012802082207450d002007417f4c0d0441002d00fca3c680001a200741002802c8a3c68000118180808000002206450d050b20062004200710848e8080002106200220073602082002200636020420022007360200200241e4006a41e5c8c9a90320024100280290a2c68000118580808000002007450d0141002d00fca3c680001a200741002802c8a3c680001181808080000022050d014101200710b280808000000b2002418080808078360200200241e4006a41e5c8c9a90320024100280290a2c6800011858080800000200241808080807836020020024184016a41f3e4c9a903200241002802b0a2c680001185808080000020024180808080783602a4010c010b20052004200710848e808000210620022007360208200220063602042002200736020020024184016a41f3e4c9a903200241002802b0a2c68000118580808000000240024020070d00410121060c010b41002d00fca3c680001a200741002802c8a3c68000118180808000002206450d040b20062004200710848e8080002104200220073602ac01200220043602a801200220073602a4010b200241c0006a220441e5c6919b07200241a4016a41002802f0a1c6800011858080800000200241086a2205200241e4006a41086a290000370300200241106a2208200241e4006a41106a290000370300200241186a2209200241e4006a41186a290000370300200241286a20024184016a41086a290000370300200241306a20024184016a41106a290000370300200241386a20024184016a41186a29000037030020022002290064370300200220022900840137032041002d00fca3c680001a41e10041002802c8a3c68000118180808000002207450d03200720022903003700002007200241206a220629000037002020072004290000370040200741186a2009290300370000200741106a2008290300370000200741086a2005290300370000200741286a200641086a290000370000200741306a200641106a290000370000200741386a200641186a290000370000200741c8006a200441086a290000370000200741d0006a200441106a290000370000200741d8006a200441186a290000370000200741e0006a200441206a2d00003a0000200041e10036020820002007360204200041e10036020002402003418080808078460d002003450d00200128020441002802c0a3c68000118080808000000b200241b0016a2480808080000f0b10ae80808000000b4101200710b280808000000b4101200710b280808000000b410141e10010b280808000000b920501037f23808080800041106b22022480808080002002410036020c20024280808080c00037020441002d00fca3c680001a024002400240412041002802c8a3c68000118180808000002203450d0020032001290000370000200341186a200141186a290000370000200341106a200141106a290000370000200341086a200141086a290000370000200241046a410010a3868080002002280208200228020c4104746a220442a0808080d08c999935370208200420033602042004412036020041002d00fca3c680001a2002200228020c41016a36020c412041002802c8a3c68000118180808000002203450d0120032001290020370000200341186a200141386a290000370000200341106a200141306a290000370000200341086a200141286a2900003700000240200228020c22042002280204470d00200241046a200410a386808000200228020c21040b200228020820044104746a220442a0808080b0ce9c993537020820042003360204200441203602002002200228020c41016a36020c41002d00fca3c680001a412141002802c8a3c68000118180808000002203450d0220032001290040370000200341206a200141e0006a2d00003a0000200341186a200141d8006a290000370000200341106a200141d0006a290000370000200341086a200141c8006a2900003700000240200228020c22012002280204470d00200241046a200110a386808000200228020c21010b200228020820014104746a220142a1808080d0ec98b2f300370208200120033602042001412136020020002002290204370200200041086a200241046a41086a28020041016a360200200241106a2480808080000f0b4101412010b280808000000b4101412010b280808000000b4101412110b280808000000bbe9701012b7f2380808080004190016b220124808080800041002d00fca3c680001a0240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024041800441002802c8a3c68000118180808000002202450d00200141106a109e8a8080002001109f8a808000200141386a10b587808000200141286a10b687808000200141d0006a10bc88808000200141f8006a10a18c808000200141e8006a10a28c808000200241386a4289a2e6a5b198dead63370300200242d5d1b5deb9b78d97cf00370330200241206a42e89d8d84e9a7e0ebbf7f370300200242ffa1f591d896faeca07f370318200242829cf890def98fed23370308200242daf597b8b3adb2fc44370300200241b8016a42bba2f9a9eaf2f897ff00370300200241b0016a4288bfcff6aea5a9cbf90037030020024188016a42c2a7b4b19ace9c92d9003703002002429691e8a3b686eae562370380012002410636024c200241f9a6c48000360248200241ec82808000360240200241ed82808000360228200241ee8280800036021020024280808080c000370370200241cc016a4104360200200241c8016a41f5a6c48000360200200241c0016a41ef82808000360200200241a8016a410036020020024190016a41f082808000360200200241003a007c2002410036027820022001290310370350200241d8006a200141106a41086a290300370300200241e0006a200141106a41106a28020036020020022001290300370264200241ec006a200141086a280200360200200241f8016a410036020020024190026a41f182808000360200200241a8026a4100360200200241c0026a4100360200200241c8026a41e8a6c48000360200200241cc026a410d360200200241f0016a4280808080c000370300200242f681cbfbfc8791b01c3703800220024188026a42f8978ab68af4bdd3937f370300200241fc016a41013a0000200241e0016a200141386a41106a280200360200200241d8016a200141386a41086a290300370300200241d0016a2001290338370300200241e4016a2001290328370200200241ec016a200141286a41086a280200360200200241b8036a42f2a19699e4e1bdb1ed00370300200241b0036a4288d7a582bd91bff5867f370300200241a0036a42e5c18a8c83d9a2ecc20037030020024198036a42b4ff9ef1bdc3bdda2837030020024188036a42c9e8d484edccb5e26c370300200242a79fcbb9e09aeaff7c37038003200241fc026a41023a0000200241f4026a4204370200200241ec026a4200370200200241e4026a42808080808001370200200241cc036a4108360200200241c8036a41e0a6c48000360200200241c0036a41f282808000360200200241a8036a41f38280800036020020024190036a41f482808000360200200241e0026a200141d0006a41106a280200360200200241d8026a200141d0006a41086a290300370300200241d0026a2001290350370300200241e0036a200141f8006a41106a280200360200200241d8036a200141f8006a41086a290300370300200241d0036a2001290378370300200241ec036a200141e8006a41086a280200360200200241e4036a2001290368370200200241fc036a41033a0000200241f8036a4100360200200241f0036a4280808080c000370300200141f8006a10d988808000200128027c2203210402402001280280012205450d002003200541386c22056a21062003210403402004280200450d01200441386a2104200541486a22050d000b200621040b2001280278210741002d00fca3c680001a41800341002802c8a3c68000118180808000002206450d0141002d00fca3c680001a41a80141002802c8a3c68000118180808000002208450d0241002d00fca3c680001a410841002802c8a3c68000118180808000002209450d032009419c84c480003602002009412436020441002d00fca3c680001a412041002802c8a3c68000118180808000002205450d04200541d5d7c3800036020020054292a2a3bece87f785bf7f370308200541f58280800036021820054105360204200541106a42fbf4c799cbf4c181c70037030041002d00fca3c680001a410841002802c8a3c6800011818080800000220a450d05200a41c784c48000360200200a411936020441002d00fca3c680001a412041002802c8a3c6800011818080800000220b450d06200b41f9d3c38000360200200b42f68d80b7cfa6d3bb4e370308200b41f682808000360218200b4106360204200b41106a42dc8ec6fd9fd6fcdeb77f37030041002d00fca3c680001a410841002802c8a3c6800011818080800000220c450d07200c41d000360204200c41ed84c4800036020020084180016a42d39e8a9dc98694cb37370300200841f8006a42c4b088d2f7cca0855f370300200841c8006a429ccab49c93e2e495cf00370300200841c0006a42d1c5efcdcd82cde1ff00370300200841106a42fbe0bedd81cff9c317370300200842cec9d2b3fca8a6f5bc7f370308200841a4016a4101360200200841a0016a200c36020020084198016a42818080801037030020084194016a200b36020020084190016a410136020020084188016a41f782808000360200200841f4006a4110360200200841bd85c48000360270200841ec006a4101360200200841e8006a200a360200200841e0006a428180808010370300200841dc006a2005360200200841d8006a4101360200200841d0006a4193828080003602002008413c6a410d360200200841e084c4800036023820084101360234200820093602302008428080808010370328200842808080808001370320200841f88280800036021820084107360204200841c084c4800036020041002d00fca3c680001a410841002802c8a3c6800011818080800000220d450d08200d41cd85c48000360200200d41c80036020441002d00fca3c680001a41a80141002802c8a3c6800011818080800000220e450d0941002d00fca3c680001a410841002802c8a3c6800011818080800000220a450d0a200a419986c48000360200200a412336020441002d00fca3c680001a412041002802c8a3c68000118180808000002209450d0b200941c084c48000360200200942d7c9cb8fc1cf97db3e370308200941b58080800036021820094107360204200941106a42e88488d0c0e3aebc1337030041002d00fca3c680001a412041002802c8a3c68000118180808000002205450d0c200541c486c48000360200200541ae87c48000360218200541ed86c48000360210200541e8d1c38000360208200541293602042005411c6a41dd00360200200541146a41c1003602002005410c6a410036020041002d00fca3c680001a411841002802c8a3c6800011818080800000220b450d0d200b41c788c48000360210200b41e8d1c38000360208200b4129360204200b419e88c48000360200200b41146a4130360200200b410c6a4100360200200e4180016a42ded2f2adffb8f5dd2b370300200e41f8006a42a3ac8ca0a39ceca97a370300200e41c8006a42c89a9d928994f7ea8d7f370300200e41c0006a42fb82e7fdcaf6be9b18370300200e41106a42a8c786dcd8d2a98d17370300200e42cecfe0e5d1c6dbf757370308200e41a4016a4103360200200e41a0016a200b360200200e4198016a428080808030370300200e4190016a42808080808001370300200e4188016a41f982808000360200200e41f4006a4111360200200e41f788c48000360270200e41ec006a4104360200200e41e8006a2005360200200e41e0006a4281808080c000370300200e41dc006a2009360200200e41d8006a4101360200200e41d0006a41fa82808000360200200e413c6a4113360200200e418b88c48000360238200e4101360234200e200a360230200e428080808010370328200e42808080808001370320200e41fb82808000360218200e4108360204200e41bc86c4800036020041002d00fca3c680001a410841002802c8a3c6800011818080800000220f450d0e200f418889c48000360200200f41c00036020441002d00fca3c680001a413841002802c8a3c68000118180808000002210450d0f41002d00fca3c680001a41e00041002802c8a3c6800011818080800000220b450d10200b41fbf4c38000360200200b42b09d9bccd2bafbc85c370308200b4183f5c38000360240200b4181f5c38000360220200b41fc82808000360218200b4106360204200b41d0006a42ab8bffbed784ffa5937f370300200b41c8006a42c194a6a793ccc3a857370300200b41306a42dda1fc828d83b3faab7f370300200b41286a42b7a18ef9ac95b6cbeb00370300200b41106a42909fd09cacfeedb5967f370300200b41d8006a41f581808000360200200b41c4006a410a360200200b41386a41ec81808000360200200b41246a410236020041002d00fca3c680001a41c80041002802c8a3c68000118180808000002205450d1120054194f8c38000360240200541c3f7c38000360238200541e8d1c38000360230200541a4f7c38000360228200541d1f6c3800036022020054180f6c38000360218200541a7f5c38000360210200541e8d1c380003602082005411a3602042005418df5c38000360200200541c4006a41293602002005413c6a41d100360200200541346a41003602002005412c6a411f360200200541246a41d3003602002005411c6a41d100360200200541146a41d9003602002005410c6a4100360200201041bdf8c38000360200201041106a42fbbf92b8c0c3b2e0f200370300201042e7b7af9aebaca1f35b37030820104109360234201020053602302010428380808090013703282010200b36022420104103360220201041fd828080003602182010411436020441002d00fca3c680001a410841002802c8a3c68000118180808000002211450d12201141d1f8c38000360200201141d30036020441002d00fca3c680001a41e00141002802c8a3c68000118180808000002209450d1341002d00fca3c680001a412041002802c8a3c6800011818080800000220a450d14200a41afd5c38000360200200a42b7a18ef9ac95b6cbeb00370308200a41ec81808000360218200a4109360204200a41106a42dda1fc828d83b3faab7f37030041002d00fca3c680001a412041002802c8a3c6800011818080800000220b450d15200b41b8d5c38000360200200b41a1d6c38000360218200b41d3d5c38000360210200b41e8d1c38000360208200b411b360204200b411c6a4113360200200b41146a41ce00360200200b410c6a410036020041002d00fca3c680001a410841002802c8a3c68000118180808000002212450d16201241c3d6c380003602002012411a36020441002d00fca3c680001a412041002802c8a3c6800011818080800000220c450d17200c41ebd6c38000360200200c429cc4c6fe96f1ecf5e000370308200c418981808000360218200c4108360204200c41106a42aeb899d38addfa912137030041002d00fca3c680001a410841002802c8a3c68000118180808000002213450d18201341f3d6c38000360200201341cf0036020441002d00fca3c680001a41c00041002802c8a3c68000118180808000002205450d19200541d5d7c3800036020020054292a2a3bece87f785bf7f370308200541dad7c38000360220200541f58280800036021820054105360204200541306a42aeb899d38addfa9121370300200541286a429cc4c6fe96f1ecf5e000370300200541106a42fbf4c799cbf4c181c700370300200541386a418981808000360200200541246a410436020041002d00fca3c680001a410841002802c8a3c68000118180808000002214450d1a201441d500360204201441ded7c38000360200200941b8016a42a1f9febbd8b1ab95b07f370300200941b0016a42d8bcf6a5ac90bd85c70037030020094180016a429acfecb0d2a8f28be700370300200941f8006a428bdb9ef4d7aab8cbec00370300200941c8006a42dc8ec6fd9fd6fcdeb77f370300200941c0006a42f68d80b7cfa6d3bb4e370300200941106a42d881e89685dfc6955a370300200942f68096ca91b986f9c000370308200941dc016a4101360200200941d8016a2014360200200941d0016a428280808010370300200941cc016a2005360200200941c8016a4102360200200941c0016a41fe82808000360200200941ac016a410f360200200941b3d8c380003602a801200941a4016a4101360200200941a0016a201336020020094198016a42818080801037030020094194016a200c36020020094190016a410136020020094188016a41ff82808000360200200941f4006a4113360200200941c2d7c38000360270200941ec006a4101360200200941e8006a2012360200200941e0006a428080808010370300200941d8006a42808080808001370300200941d0006a4180838080003602002009413c6a410e360200200941ddd6c38000360238200941043602342009200b36023020094281808080c0003703282009200a3602242009410136022020094181838080003602182009410f360204200941b4d6c3800036020041002d00fca3c680001a410841002802c8a3c68000118180808000002215450d1b201541c2d8c38000360200201541dc0036020441002d00fca3c680001a413841002802c8a3c68000118180808000002216450d1c41002d00fca3c680001a412041002802c8a3c68000118180808000002205450d1d2005419783c48000360200200542c4ccab9c81ebb4b8db00370308200541f08180800036021820054107360204200541106a42a4d2928ecac0faa43237030041002d00fca3c680001a410841002802c8a3c6800011818080800000220b450d1e200b4130360204200b419e83c48000360200201641ce83c48000360200201641106a4293888c8f89fdc6ec9e7f370300201642a5e9e3ab9e929adc2c370308201641013602342016200b36023020164281808080103703282016200536022420164101360220201641ef808080003602182016410d36020441002d00fca3c680001a410841002802c8a3c68000118180808000002217450d1f201741db83c480003602002017412036020441002d00fca3c680001a41f00741002802c8a3c68000118180808000002205450d2041002d00fca3c680001a412041002802c8a3c68000118180808000002218450d21201841feebc38000360200201842c4ccab9c81ebb4b8db00370308201841f08180800036021820184102360204201841106a42a4d2928ecac0faa43237030041002d00fca3c680001a410841002802c8a3c68000118180808000002219450d22201941f395c480003602002019412c36020441002d00fca3c680001a412041002802c8a3c6800011818080800000221a450d23201a41a996c48000360200201a42a5e9e3ab9e929adc2c370308201a418283808000360218201a4103360204201a41106a4293888c8f89fdc6ec9e7f37030041002d00fca3c680001a410841002802c8a3c6800011818080800000221b450d24201b41ac96c48000360200201b41ce0036020441002d00fca3c680001a412041002802c8a3c6800011818080800000221c450d25201c418b97c48000360200201c42e8e094efaab6e5ba5b370308201c418383808000360218201c4103360204201c41106a4299b9c2f4a1b0a7a4f10037030041002d00fca3c680001a411041002802c8a3c6800011818080800000221d450d26201d418e97c48000360200201d41e397c48000360208201d41d500360204201d410c6a410836020041002d00fca3c680001a410841002802c8a3c6800011818080800000221e450d27201e418398c48000360200201e411336020441002d00fca3c680001a410841002802c8a3c6800011818080800000221f450d28201f41b098c48000360200201f411436020441002d00fca3c680001a410841002802c8a3c68000118180808000002220450d29202041cc98c48000360200202041c00036020441002d00fca3c680001a410841002802c8a3c68000118180808000002221450d2a202141a399c480003602002021411b36020441002d00fca3c680001a412041002802c8a3c68000118180808000002222450d2b202241d399c48000360200202242d7c9cb8fc1cf97db3e370308202241b58080800036021820224104360204202241106a42e88488d0c0e3aebc1337030041002d00fca3c680001a410841002802c8a3c68000118180808000002223450d2c202341d799c480003602002023412636020441002d00fca3c680001a410841002802c8a3c68000118180808000002224450d2d2024418e9ac480003602002024412636020441002d00fca3c680001a411841002802c8a3c68000118180808000002213450d2e201341c49ac48000360200201341f59ac48000360210201341e8d1c3800036020820134131360204201341146a41ce003602002013410c6a410036020041002d00fca3c680001a411841002802c8a3c68000118180808000002214450d2f201441d69bc48000360200201441879cc48000360210201441e8d1c3800036020820144131360204201441146a413b3602002014410c6a410036020041002d00fca3c680001a411841002802c8a3c68000118180808000002225450d30202541d59cc48000360200202541849dc48000360210202541e8d1c380003602082025412f360204202541146a41393602002025410c6a410036020041002d00fca3c680001a410841002802c8a3c68000118180808000002226450d31202641ce9dc480003602002026412336020441002d00fca3c680001a41c00041002802c8a3c68000118180808000002212450d32201241fd9dc48000360200201242a4d981999395fed957370308201241829ec48000360220201241848380800036021820124105360204201241306a42ab8bffbed784ffa5937f370300201241286a42c194a6a793ccc3a857370300201241106a4290bdcef9d19f84fee800370300201241386a41f581808000360200201241246a410436020041002d00fca3c680001a410841002802c8a3c68000118180808000002227450d33202741869ec480003602002027411136020441002d00fca3c680001a41e00041002802c8a3c6800011818080800000220b450d34200b41dad7c38000360200200b42e7b0a091f3ed9c85c500370308200b41a89ec48000360240200b41a39ec48000360220200b41ea81808000360218200b4104360204200b41d0006a42e88488d0c0e3aebc13370300200b41c8006a42d7c9cb8fc1cf97db3e370300200b41306a42b891b68c98adebcf61370300200b41286a42e7b0a091f3ed9c85c500370300200b41106a42b891b68c98adebcf61370300200b41d8006a41b580808000360200200b41c4006a4103360200200b41386a41ea81808000360200200b41246a410536020041002d00fca3c680001a411041002802c8a3c68000118180808000002228450d35202841ab9ec48000360200202841ed9ec48000360208202841c2003602042028410c6a410b36020041002d00fca3c680001a410841002802c8a3c68000118180808000002229450d362029418f9fc480003602002029411e36020441002d00fca3c680001a41e00041002802c8a3c6800011818080800000220a450d37200a41b99fc48000360200200a42e3beec81d3e996af917f370308200a41c29fc48000360240200a41bc9fc48000360220200a418583808000360218200a4103360204200a41d0006a42b891b68c98adebcf61370300200a41c8006a42e7b0a091f3ed9c85c500370300200a41306a42a4d2928ecac0faa432370300200a41286a42c4ccab9c81ebb4b8db00370300200a41106a42f0a3fcacaeba9c956f370300200a41d8006a41ea81808000360200200a41c4006a4107360200200a41386a41f081808000360200200a41246a410636020041002d00fca3c680001a410841002802c8a3c6800011818080800000222a450d38202a41c99fc48000360200202a413536020441002d00fca3c680001a41e00041002802c8a3c6800011818080800000220c450d39200c418ca0c48000360200200c42e7b0a091f3ed9c85c500370308200c4194a0c48000360240200c418fa0c48000360220200c41ea81808000360218200c4103360204200c41d0006a4298848fa1dab08ba174370300200c41c8006a42febac4ad81b6fafcb37f370300200c41306a42b891b68c98adebcf61370300200c41286a42e7b0a091f3ed9c85c500370300200c41106a42b891b68c98adebcf61370300200c41d8006a418881808000360200200c41c4006a4105360200200c41386a41ea81808000360200200c41246a410536020041002d00fca3c680001a410841002802c8a3c6800011818080800000222b450d3a202b41d800360204202b4199a0c48000360200200541c8076a429ccab49c93e2e495cf00370300200541c0076a42d1c5efcdcd82cde1ff0037030020054190076a4298848fa1dab08ba17437030020054188076a42febac4ad81b6fafcb37f370300200541d8066a429ccab49c93e2e495cf00370300200541d0066a42d1c5efcdcd82cde1ff00370300200541a0066a429ccab49c93e2e495cf0037030020054198066a42d1c5efcdcd82cde1ff00370300200541e8056a429ccab49c93e2e495cf00370300200541e0056a42d1c5efcdcd82cde1ff00370300200541b0056a429ccab49c93e2e495cf00370300200541a8056a42d1c5efcdcd82cde1ff00370300200541f8046a42dfc4809d8ac5e4f1de00370300200541f0046a42e5e882a9be85fc80fa00370300200541c0046a4294ed85e8ed84e1d30b370300200541b8046a42d8e4bea39ae2d6da0637030020054188046a4295d2cbc8a2888c9a7d37030020054180046a42f69cccefd7e0e1c38b7f370300200541d0036a4293888c8f89fdc6ec9e7f370300200541c8036a42a5e9e3ab9e929adc2c37030020054198036a42b891b68c98adebcf6137030020054190036a42e7b0a091f3ed9c85c500370300200541e0026a4293888c8f89fdc6ec9e7f370300200541d8026a42a5e9e3ab9e929adc2c370300200541a8026a4293888c8f89fdc6ec9e7f370300200541a0026a42a5e9e3ab9e929adc2c370300200541f0016a4293888c8f89fdc6ec9e7f370300200541e8016a42a5e9e3ab9e929adc2c370300200541b8016a4293888c8f89fdc6ec9e7f370300200541b0016a42a5e9e3ab9e929adc2c37030020054180016a42fd87d58eecf6d4b521370300200541f8006a42c5ccf6ddf0d2bef89a7f370300200541c8006a4293888c8f89fdc6ec9e7f370300200541c0006a42a5e9e3ab9e929adc2c370300200541106a4293888c8f89fdc6ec9e7f370300200542a5e9e3ab9e929adc2c370308200541ec076a4101360200200541e8076a202b360200200541e0076a428380808010370300200541dc076a200c360200200541d8076a4103360200200541d0076a419382808000360200200541bc076a410f360200200541f1a0c480003602b807200541b4076a4101360200200541b0076a202a360200200541a8076a428380808010370300200541a4076a200a360200200541a0076a410336020020054198076a41888180800036020020054184076a410e360200200541fe9fc4800036028007200541fc066a4101360200200541f8066a2029360200200541f0066a428080808010370300200541e8066a42808080808001370300200541e0066a419382808000360200200541cc066a410c360200200541ad9fc480003602c806200541c4066a4102360200200541c0066a2028360200200541b8066a428380808020370300200541b4066a200b360200200541b0066a4103360200200541a8066a41938280800036020020054194066a4117360200200541f89ec48000360290062005418c066a410136020020054188066a202736020020054180066a428280808010370300200541fc056a2012360200200541f8056a4102360200200541f0056a419382808000360200200541dc056a410c360200200541979ec480003602d805200541d4056a4101360200200541d0056a2026360200200541c8056a428080808010370300200541c0056a42808080808001370300200541b8056a419382808000360200200541a4056a410c360200200541f19dc480003602a0052005419c056a410336020020054198056a202536020020054190056a42808080803037030020054188056a4280808080800137030020054180056a418683808000360200200541ec046a4111360200200541bd9dc480003602e804200541e4046a4103360200200541e0046a2014360200200541d8046a428080808030370300200541d0046a42808080808001370300200541c8046a418783808000360200200541b4046a4113360200200541c29cc480003602b004200541ac046a4103360200200541a8046a2013360200200541a0046a42808080803037030020054198046a4280808080800137030020054190046a418883808000360200200541fc036a4113360200200541c39bc480003602f803200541f4036a4101360200200541f0036a2024360200200541e8036a428080808010370300200541e0036a42808080808001370300200541d8036a41ef80808000360200200541c4036a4110360200200541b49ac480003602c003200541bc036a4101360200200541b8036a2023360200200541b0036a428180808010370300200541ac036a2022360200200541a8036a4101360200200541a0036a41ea818080003602002005418c036a4111360200200541fd99c480003602880320054184036a410136020020054180036a2021360200200541f8026a428080808010370300200541f0026a42808080808001370300200541e8026a41ef80808000360200200541d4026a4115360200200541be99c480003602d002200541cc026a4101360200200541c8026a2020360200200541c0026a428080808010370300200541b8026a42808080808001370300200541b0026a41ef808080003602002005419c026a41173602002005418c99c480003602980220054194026a410136020020054190026a201f36020020054188026a42808080801037030020054180026a42808080808001370300200541f8016a41ef80808000360200200541e4016a4108360200200541c498c480003602e001200541dc016a4101360200200541d8016a201e360200200541d0016a428080808010370300200541c8016a42808080808001370300200541c0016a41ef80808000360200200541ac016a411a3602002005419698c480003602a801200541a4016a4102360200200541a0016a201d36020020054198016a42818080802037030020054194016a201c36020020054190016a410136020020054188016a418383808000360200200541f4006a4118360200200541eb97c48000360270200541ec006a4101360200200541e8006a201b360200200541e0006a428180808010370300200541dc006a201a360200200541d8006a4101360200200541d0006a41ef808080003602002005413c6a4111360200200541fa96c48000360238200541013602342005201936023020054281808080103703282005201836022420054101360220200541ef808080003602182005410a3602042005419f96c4800036020041002d00fca3c680001a41f00041002802c8a3c68000118180808000002214450d3b41002d00fca3c680001a411841002802c8a3c6800011818080800000220b450d3c200b41aad9c38000360200200b41ced9c38000360210200b41e8d1c38000360208200b4124360204200b41146a41c900360200200b410c6a410036020041002d00fca3c680001a410841002802c8a3c6800011818080800000220a450d3d200a4127360204200a41a4dac3800036020020144197dac38000360200201441c8006a42c4e2cedafbc28595bc7f370300201441c0006a42d8b6abf18ab7a1e965370300201441106a42b683bfa183f992fe847f370300201442de88dfa5f1c5f7b6a27f370308201441ec006a4101360200201441e8006a200a360200201441e0006a428080808010370300201441d8006a42808080808001370300201441d0006a4189838080003602002014413c6a410b360200201441cbdac38000360238201441033602342014200b36023020144280808080303703282014428080808080013703202014418a838080003602182014410d36020441002d00fca3c680001a410841002802c8a3c68000118180808000002228450d3e202841d6dac380003602002028412e36020441002d00fca3c680001a41d00241002802c8a3c6800011818080800000220b450d3f41002d00fca3c680001a410841002802c8a3c68000118180808000002218450d402018418bdbc380003602002018412336020441002d00fca3c680001a410841002802c8a3c6800011818080800000221a450d41201a41bbdbc38000360200201a413136020441002d00fca3c680001a410841002802c8a3c6800011818080800000221c450d42201c41ffdbc38000360200201c413136020441002d00fca3c680001a411041002802c8a3c68000118180808000002225450d43202541bddcc38000360200202541fddcc38000360208202541c0003602042025410c6a411736020041002d00fca3c680001a41c00041002802c8a3c68000118180808000002212450d442012419eddc38000360200201242e3a4fae3cee3d18d72370308201241a2ddc38000360220201241f58080800036021820124104360204201241306a42e9b494c69bdbc4d608370300201241286a42ead283debcdebd93d800370300201241106a42b8b6d386cdcbfab1a07f370300201241386a41f780808000360200201241246a410c36020041002d00fca3c680001a41d80041002802c8a3c6800011818080800000220a450d45200a41c0e2c38000360250200a41fee1c38000360248200a41c2e1c38000360240200a41ffe0c38000360238200a41bde0c38000360230200a41fbdfc38000360228200a41b7dfc38000360220200a41f4dec38000360218200a41b3dec38000360210200a41f0ddc38000360208200a41c200360204200a41aeddc38000360200200a41d4006a4134360200200a41cc006a41c200360200200a41c4006a413c360200200a413c6a41c300360200200a41346a41c200360200200a412c6a41c200360200200a41246a41c400360200200a411c6a41c300360200200a41146a41c100360200200a410c6a41c30036020041002d00fca3c680001a41c00041002802c8a3c68000118180808000002213450d4620134190e3c380003602002013428ae790e9b7c48cad987f370308201341a2e3c380003602202013418b8380800036021820134112360204201341306a42b889cc8cd692ff80fa00370300201341286a4288f7e1d594faa5a120370300201341106a42ade681e7ba94a3bd8d7f370300201341386a418c83808000360200201341246a410f36020041002d00fca3c680001a41c00041002802c8a3c6800011818080800000220c450d47200c41fbe6c38000360238200c41bae6c38000360230200c41f8e5c38000360228200c41b3e5c38000360220200c41f2e4c38000360218200c41b3e4c38000360210200c41f5e3c38000360208200c41c400360204200c41b1e3c38000360200200c413c6a41c100360200200c41346a41c100360200200c412c6a41c200360200200c41246a41c500360200200c411c6a41c100360200200c41146a413f360200200c410c6a413e360200200b41a8026a42a0a58eade3c7d8c3f600370300200b41a0026a42bbbde2dfeee883e643370300200b41f0016a42bcded3878bc0cf8f7c370300200b41e8016a42b7bec490f9e7d7cda97f370300200b41b8016a4285b396c8e397b6a6f000370300200b41b0016a42aca08db5a793aef98d7f370300200b4180016a4285b396c8e397b6a6f000370300200b41f8006a42aca08db5a793aef98d7f370300200b41c8006a42b8b6d386cdcbfab1a07f370300200b41c0006a42e3a4fae3cee3d18d72370300200b41106a42e1ca8ae9eabca78cc200370300200b4290c489c6869cfac00d370308200b41cc026a4108360200200b41c8026a200c360200200b41c0026a42828080808001370300200b41bc026a2013360200200b41b8026a4102360200200b41b0026a418d83808000360200200b419c026a412d360200200b41bce7c3800036029802200b4194026a410b360200200b4190026a200a360200200b4188026a4282808080b001370300200b4184026a2012360200200b4180026a4102360200200b41f8016a418e83808000360200200b41e4016a411c360200200b41f4e2c380003602e001200b41dc016a4102360200200b41d8016a2025360200200b41d0016a428080808020370300200b41c8016a42808080808001370300200b41c0016a418f83808000360200200b41ac016a410a360200200b4194ddc380003602a801200b41a4016a4101360200200b41a0016a201c360200200b4198016a428080808010370300200b4190016a42808080808001370300200b4188016a418f83808000360200200b41f4006a410d360200200b41b0dcc38000360270200b41ec006a4101360200200b41e8006a201a360200200b41e0006a428080808010370300200b41d8006a42808080808001370300200b41d0006a41f580808000360200200b413c6a4113360200200b41ecdbc38000360238200b4101360234200b2018360230200b428080808010370328200b42808080808001370320200b419083808000360218200b410d360204200b41aedbc3800036020041002d00fca3c680001a410841002802c8a3c68000118180808000002219450d48201941e9e7c380003602002019412e36020441002d00fca3c680001a413841002802c8a3c6800011818080800000221a450d4941002d00fca3c680001a412041002802c8a3c6800011818080800000220a450d4a200a41f9d3c38000360200200a42f68d80b7cfa6d3bb4e370308200a41f682808000360218200a4106360204200a41106a42dc8ec6fd9fd6fcdeb77f37030041002d00fca3c680001a410841002802c8a3c6800011818080800000220c450d4b200c4132360204200c41ffd3c38000360200201a41b1d4c38000360200201a41106a429ccab49c93e2e495cf00370300201a42d1c5efcdcd82cde1ff00370308201a4101360234201a200c360230201a428180808010370328201a200a360224201a4101360220201a419382808000360218201a410f36020441002d00fca3c680001a410841002802c8a3c6800011818080800000221b450d4c201b41c0d4c38000360200201b411936020441002d00fca3c680001a41f00041002802c8a3c68000118180808000002213450d4d41002d00fca3c680001a412041002802c8a3c68000118180808000002212450d4e201241cbd0c38000360200201242f99f94a5fdd3dbbaf900370308201241918380800036021820124104360204201241106a42f6d183c8fca4ffd45a37030041002d00fca3c680001a413841002802c8a3c6800011818080800000220a450d4f200a41cfd0c38000360200200a4194d2c38000360230200a41e8d1c38000360228200a41e8d1c38000360220200a41e8d1c38000360218200a41d6d1c38000360210200a4194d1c38000360208200a41c500360204200a41346a4134360200200a412c6a4100360200200a41246a412c360200200a411c6a4100360200200a41146a410f360200200a410c6a41c20036020041002d00fca3c680001a412041002802c8a3c68000118180808000002225450d50202541ddd2c38000360200202542e7b0a091f3ed9c85c500370308202541ea8180800036021820254107360204202541106a42b891b68c98adebcf6137030041002d00fca3c680001a411841002802c8a3c6800011818080800000220c450d51200c418ad3c38000360210200c41e8d1c38000360208200c4126360204200c41e4d2c38000360200200c41146a4137360200200c410c6a4100360200201341c8006a42bfd1fbe392d3878718370300201341c0006a42c6b49cae9188d5c4a37f370300201341106a42b891b68c98adebcf61370300201342e7b0a091f3ed9c85c500370308201341ec006a4103360200201341e8006a200c360200201341e0006a428180808030370300201341dc006a2025360200201341d8006a4101360200201341d0006a4192838080003602002013413c6a4113360200201341c1d3c38000360238201341073602342013200a36023020134281808080f0003703282013201236022420134101360220201341ea8180800036021820134115360204201341c8d2c3800036020041002d00fca3c680001a410841002802c8a3c6800011818080800000221e450d52201e41d4d3c38000360200201e411a36020441002d00fca3c680001a41e00141002802c8a3c6800011818080800000220a450d5341002d00fca3c680001a413041002802c8a3c68000118180808000002225450d54202541baf9c38000360200202541ecfbc380003602282025419dfbc38000360220202541d0fac38000360218202541e8d1c3800036021020254189fac38000360208202541cf003602042025412c6a4130360200202541246a41cf003602002025411c6a41cd00360200202541146a41003602002025410c6a41c70036020041002d00fca3c680001a41c00041002802c8a3c68000118180808000002218450d5520184190e3c38000360200201842c1d4a9c8c2d78cfcc000370308201841a2e3c38000360220201841938380800036021820184112360204201841306a4299f0ab899787d3ad3a370300201841286a42d4b0f086cab3d2eb14370300201841106a42e3f39ebbdcd7db8c79370300201841386a419483808000360200201841246a410f36020041002d00fca3c680001a41c00041002802c8a3c68000118180808000002212450d56201241b1e3c38000360200201241fbe6c38000360238201241bae6c38000360230201241f8e5c38000360228201241b3e5c38000360220201241f2e4c38000360218201241b3e4c38000360210201241f5e3c38000360208201241c4003602042012413c6a41c100360200201241346a41c1003602002012412c6a41c200360200201241246a41c5003602002012411c6a41c100360200201241146a413f3602002012410c6a413e36020041002d00fca3c680001a41c00041002802c8a3c6800011818080800000221c450d57201c41affcc38000360200201c42a5e9e3ab9e929adc2c370308201c41a2ddc38000360220201c41ef80808000360218201c4106360204201c41306a42949384fce98ae9ac977f370300201c41286a42c4a8f7cba2aea4ad35370300201c41106a4293888c8f89fdc6ec9e7f370300201c41386a41ff81808000360200201c41246a410c36020041002d00fca3c680001a41d80041002802c8a3c6800011818080800000220c450d58200c41fffec38000360250200c41bcfec38000360248200c41f7fdc38000360240200c41ffe0c38000360238200c41b8fdc38000360230200c41f4fcc38000360228200c41b7dfc38000360220200c41f4dec38000360218200c41b3dec38000360210200c41b5fcc38000360208200c41c200360204200c41aeddc38000360200200c41d4006a411e360200200c41cc006a41c300360200200c41c4006a41c500360200200c413c6a41c300360200200c41346a413f360200200c412c6a41c400360200200c41246a41c400360200200c411c6a41c300360200200c41146a41c100360200200c410c6a413f36020041002d00fca3c680001a410841002802c8a3c68000118180808000002222450d59202241263602042022419dffc38000360200200a41b8016a4293888c8f89fdc6ec9e7f370300200a41b0016a42a5e9e3ab9e929adc2c370300200a4180016a42d38accc2f68caeecba7f370300200a41f8006a42bfcdc4dc94d7acde3b370300200a41c8006a42a0a58eade3c7d8c3f600370300200a41c0006a42bbbde2dfeee883e643370300200a41106a42d592f683e7e68799fc00370300200a4287bf8ac8928ddfce54370308200a41dc016a4101360200200a41d8016a2022360200200a41d0016a428080808010370300200a41c8016a42808080808001370300200a41c0016a41ef80808000360200200a41ac016a410e360200200a41c3ffc380003602a801200a41a4016a410b360200200a41a0016a200c360200200a4198016a4282808080b001370300200a4194016a201c360200200a4190016a4102360200200a4188016a419583808000360200200a41f4006a411c360200200a41f4e2c38000360270200a41ec006a4108360200200a41e8006a2012360200200a41e0006a42828080808001370300200a41dc006a2018360200200a41d8006a4102360200200a41d0006a418d83808000360200200a413c6a412d360200200a41bce7c38000360238200a4106360234200a2025360230200a4280808080e000370328200a42808080808001370320200a419683808000360218200a4113360204200a419cfcc3800036020041002d00fca3c680001a41c80041002802c8a3c68000118180808000002225450d5a202541d1ffc38000360200202541ce82c48000360240202541e8d1c380003602382025419582c48000360230202541c981c480003602282025418681c48000360220202541c180c48000360218202541e8d1c380003602102025419180c48000360208202541c000360204202541c4006a413f3602002025413c6a4100360200202541346a41393602002025412c6a41cc00360200202541246a41c3003602002025411c6a41c500360200202541146a41003602002025410c6a413036020041002d00fca3c680001a41a80141002802c8a3c6800011818080800000220c450d5b41002d00fca3c680001a412041002802c8a3c68000118180808000002222450d5c2022419ee8c38000360200202242e7b0a091f3ed9c85c500370308202241ea8180800036021820224104360204202241106a42b891b68c98adebcf6137030041002d00fca3c680001a41c80041002802c8a3c68000118180808000002218450d5d201841a2e8c38000360200201841dcebc3800036024020184185ebc38000360238201841e8d1c38000360230201841d8eac3800036022820184182eac3800036022020184184e9c38000360218201841e8d1c38000360210201841fbe8c38000360208201841d900360204201841c4006a41173602002018413c6a41d700360200201841346a41003602002018412c6a412d360200201841246a41d6003602002018411c6a41fe00360200201841146a41003602002018410c6a410936020041002d00fca3c680001a412041002802c8a3c6800011818080800000221d450d5e201d41feebc38000360200201d42b9bfe7eaeaf488d21c370308201d419783808000360218201d4102360204201d41106a42a9a98a9dddd4dcd0dc0037030041002d00fca3c680001a41f00041002802c8a3c68000118180808000002212450d5f20124190f2c38000360268201241b8f1c38000360260201241dff0c380003602582012418cf0c38000360250201241b3efc38000360248201241dfeec3800036024020124197eec38000360238201241e8d1c38000360230201241ffedc38000360228201241adedc38000360220201241deecc38000360218201241e8d1c38000360210201241d8ecc38000360208201241d80036020420124180ecc38000360200201241ec006a4121360200201241e4006a41d800360200201241dc006a41d900360200201241d4006a41d300360200201241cc006a41d900360200201241c4006a41d4003602002012413c6a41c800360200201241346a41003602002012412c6a4118360200201241246a41d2003602002012411c6a41cf00360200201241146a41003602002012410c6a410636020041002d00fca3c680001a412041002802c8a3c6800011818080800000221c450d60201c41e7f3c38000360218201c418ff3c38000360210201c41e8d1c38000360208201c41d400360204201c41bbf2c38000360200201c411c6a41c000360200201c41146a41d800360200201c410c6a4100360200200c4180016a42cdbdd1fc838da48215370300200c41f8006a4288bed2e1b0b8c0e336370300200c41c8006a42f6d183c8fca4ffd45a370300200c41c0006a42f99f94a5fdd3dbbaf900370300200c41106a42cfe5aeebd69bcbd576370300200c42eccdbcbecbac99cabc7f370308200c41a4016a4104360200200c41a0016a201c360200200c4198016a4280808080c000370300200c4190016a42808080808001370300200c4188016a419883808000360200200c41f4006a410c360200200c41a7f4c38000360270200c41ec006a410e360200200c41e8006a2012360200200c41e0006a4281808080e001370300200c41dc006a201d360200200c41d8006a4101360200200c41d0006a419183808000360200200c413c6a410a360200200c41b1f2c38000360238200c4109360234200c2018360230200c42818080809001370328200c2022360224200c4101360220200c419983808000360218200c410b360204200c41f3ebc3800036020041002d00fca3c680001a410841002802c8a3c68000118180808000002212450d612012413a360204201241b3f4c38000360200200641fc026a410e360200200641f8026a41edf4c38000360200200641f4026a4101360200200641f0026a2012360200200641e8026a428380808010370200200641e4026a200c360200200641dc026a428a80808030370200200641d8026a418d83c48000360200200641d4026a4109360200200641d0026a2025360200200641c8026a42848080809001370200200641c4026a200a360200200641bc026a428b808080c000370200200641b8026a41eed3c38000360200200641b4026a4101360200200641b0026a201e360200200641a8026a428280808010370200200641a4026a20133602002006419c026a42918080802037020020064198026a41d9d4c3800036020020064194026a410136020020064190026a201b36020020064188026a42818080801037020020064184026a201a360200200641fc016a428780808010370200200641f8016a4197e8c38000360200200641f4016a4101360200200641f0016a2019360200200641e8016a428680808010370200200641e4016a200b360200200641dc016a4287808080e000370200200641d8016a4184dbc38000360200200641d4016a4101360200200641d0016a2028360200200641c8016a428280808010370200200641c4016a2014360200200641bc016a428780808020370200200641b8016a4180a1c48000360200200641b0016a4204370200200641a8016a4212370200200641a4016a20053602002006419c016a428f808080a00237020020064198016a41fb83c4800036020020064194016a410136020020064190016a201736020020064188016a42818080801037020020064184016a2016360200200641fc006a428c80808010370200200641f8006a419ed9c38000360200200641f4006a4101360200200641f0006a2015360200200641e8006a428480808010370200200641e4006a2009360200200641dc006a4296808080c000370200200641d8006a41a4f9c38000360200200641d4006a4101360200200641d0006a2011360200200641c8006a428180808010370200200641c4006a20103602002006413c6a428880808010370200200641386a41c889c48000360200200641346a4101360200200641306a200f360200200641286a428380808010370200200641246a200e360200200642848080803037021c2006419586c48000360218200641013602142006200d36021020064283808080103702082006200836020420064103360200200041f0016a4104360200200041ec016a2002360200200041043602e801200041f0006a41ec8180800036020020004188016a41f081808000360200200041a0016a419a83808000360200200041b8016a418583808000360200200041d0016a419b83808000360200200041d8016a200741386c41386e360200200041dc016a2003360200200041e0016a200420036b41386e360200200041e4016a41043a0000200041c0016a42dba4b9c0a2bed19501370300200041c8016a4283af8bf0ede78391a67f370300200041a8016a42e3beec81d3e996af917f370300200041b0016a42f0a3fcacaeba9c956f37030020004190016a42dbe2e9e8becbf3fb2f37030020004198016a42fec1aad493d7e4ae3e370300200041f8006a42c4ccab9c81ebb4b8db0037030020004180016a42a4d2928ecac0faa432370300200042b7a18ef9ac95b6cbeb00370360200041e8006a42dda1fc828d83b3faab7f3703002000419c838080003602102000410c3602f401200041f8016a2006360200200041fc016a410c360200200042f9ffdfe3cfb190868f7f37030820004287f1a7a98f94a1fd58370300200041286a419a83808000360200200041c0006a419a82808000360200200041d8006a419d83808000360200200041c8006a42d8a6d184eacbe6c8937f370300200041d0006a428fa8ddeba8afb0e82c370300200041306a428efca59582e3caf618370300200041386a42988ac9c0f3f1b2b0b57f370300200042dbe2e9e8becbf3fb2f370318200041206a42fec1aad493d7e4ae3e370300200041e7016a200141fa006a2d00003a0000200041e5016a20012f00783b000020014190016a2480808080000f0b410841800410b280808000000b410441800310b280808000000b410841a80110b280808000000b4104410810b280808000000b4108412010b280808000000b4104410810b280808000000b4108412010b280808000000b4104410810b280808000000b4104410810b280808000000b410841a80110b280808000000b4104410810b280808000000b4108412010b280808000000b4104412010b280808000000b4104411810b280808000000b4104410810b280808000000b4108413810b280808000000b410841e00010b280808000000b410441c80010b280808000000b4104410810b280808000000b410841e00110b280808000000b4108412010b280808000000b4104412010b280808000000b4104410810b280808000000b4108412010b280808000000b4104410810b280808000000b410841c00010b280808000000b4104410810b280808000000b4104410810b280808000000b4108413810b280808000000b4108412010b280808000000b4104410810b280808000000b4104410810b280808000000b410841f00710b280808000000b4108412010b280808000000b4104410810b280808000000b4108412010b280808000000b4104410810b280808000000b4108412010b280808000000b4104411010b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b4108412010b280808000000b4104410810b280808000000b4104410810b280808000000b4104411810b280808000000b4104411810b280808000000b4104411810b280808000000b4104410810b280808000000b410841c00010b280808000000b4104410810b280808000000b410841e00010b280808000000b4104411010b280808000000b4104410810b280808000000b410841e00010b280808000000b4104410810b280808000000b410841e00010b280808000000b4104410810b280808000000b410841f00010b280808000000b4104411810b280808000000b4104410810b280808000000b4104410810b280808000000b410841d00210b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b4104411010b280808000000b410841c00010b280808000000b410441d80010b280808000000b410841c00010b280808000000b410441c00010b280808000000b4104410810b280808000000b4108413810b280808000000b4108412010b280808000000b4104410810b280808000000b4104410810b280808000000b410841f00010b280808000000b4108412010b280808000000b4104413810b280808000000b4108412010b280808000000b4104411810b280808000000b4104410810b280808000000b410841e00110b280808000000b4104413010b280808000000b410841c00010b280808000000b410441c00010b280808000000b410841c00010b280808000000b410441d80010b280808000000b4104410810b280808000000b410441c80010b280808000000b410841a80110b280808000000b4108412010b280808000000b410441c80010b280808000000b4108412010b280808000000b410441f00010b280808000000b4104412010b280808000000b4104410810b280808000000be00903027f017e027f23808080800041d0036b22042480808080000240200241c0016a2d000022054102460d00200441e0006a200241b0016a290300370300200441d8006a200241a8016a290300370300200441d0006a200241a0016a290300370300200441086a41086a200241e0006a290300370300200441086a41106a200241e8006a290300370300200441086a41186a200241f0006a290300370300200441086a41206a200241f8006a290300370300200441306a20024180016a290300370300200441386a20024188016a290300370300200441c0006a20024190016a29030037030020042002290358370308200420024198016a290300370348200441f0016a41206a200241e1016a2d00003a0000200441f0016a41186a200241d9016a290000370300200441f0016a41106a200241d1016a290000370300200441f0016a41086a200241c9016a2900003703002004200241c1016a2900003703f001200241b8016a290300210620044198026a200441086a41e00010848e8080001a0b02400240024002400240200228020041736a2207410220074104491b0e0400010203000b200441f8026a41086a200241086a10a28a8080002004410d3602f8020c030b0240200241186a2d00002207417d6a41ff0171220841016a410320084102491b22084103460d00024002402008417f6a0e020001000b200228020810b087808000000b200228020810b087808000000b200441f8026a41186a20073a0000200441f8026a41106a200241106a2903003703002004410e3602f80220042002290308370380030c020b200441f8026a200210bf888080000c010b200441f8026a41086a200241086a10aa8c808000200441103602f8020b200441086a41d8006a20044198026a41e00010848e8080001a200441c8016a20053a0000200441c0016a2006370300200441c9016a20042903f001370000200441d1016a200441f0016a41086a290300370000200441d9016a200441f0016a41106a290300370000200441e1016a200441f0016a41186a290300370000200441e8016a2004418f026a290000370000200441086a200441f8026a41d80010848e8080001a20044198026a2001200441086a200310818d80800002404100280284a4c680004105470d00200441f8026a410c6a419e838080003602002004419f838080003602fc02200420023602f802200420044198026a360280034100280290a1c680002103410028028ca1c6800021014100280280a4c680002105200441c0006a4202370200200441386a4102360200200441306a41163602002004412c6a41e88bc48000360200200441086a41186a41f48ac48000ad4280808080900c84370200200441086a410c6a41fe8bc48000ad4280808080e002843702002004413c6a200441f8026a360200200441f4a1c48000360234200441053602282004410036021c2004410036021020044281808080e03e370208200141ecf2c08000200541024622051b200441086a200341d4f2c0800020051b280210118480808000000b2000200429039802370300200041286a20044198026a41286a290300370300200041206a20044198026a41206a290300370300200041186a20044198026a41186a290300370300200041106a20044198026a41106a290300370300200041086a20044198026a41086a290300370300200210c989808000200441d0036a2480808080000be41d03087f017e027f23808080800041b0026b220024808080800041002d00fca3c680001a024002400240024002400240024002400240024002400240024002400240024002400240411641002802c8a3c68000118180808000002201450d002001410e6a41002900a28cc48000370000200141086a410029009c8cc48000370000200141002900948cc4800037000041002d00fca3c680001a410a41002802c8a3c68000118180808000002202450d01200241086a41002f00b28cc480003b0000200241002900aa8cc4800037000041002d00fca3c680001a411641002802c8a3c68000118180808000002203450d022003410e6a41002900c28cc48000370000200341086a41002900bc8cc48000370000200341002900b48cc4800037000041002d00fca3c680001a410a41002802c8a3c68000118180808000002204450d03200441086a41002f00d28cc480003b0000200441002900ca8cc4800037000041002d00fca3c680001a413041002802c8a3c68000118180808000002205450d0441002d00fca3c680001a411641002802c8a3c68000118180808000002206450d05200620012900003700002006410e6a2001410e6a290000370000200641086a200141086a29000037000041002d00fca3c680001a410a41002802c8a3c68000118180808000002207450d0620072002290000370000200741086a200241086a2f00003b0000200541163602002005410a3602142005200736021020054296808080a0013702082005200636020441002d00fca3c680001a411641002802c8a3c68000118180808000002206450d07200620032900003700002006410e6a2003410e6a290000370000200641086a200341086a29000037000041002d00fca3c680001a410a41002802c8a3c68000118180808000002207450d0820072004290000370000200741086a200441086a2f00003b00002005412c6a410a360200200541286a2007360200200541206a4296808080a0013702002005411c6a200636020020054116360218200141002802c0a3c6800011808080800000200241002802c0a3c6800011808080800000200341002802c0a3c6800011808080800000200441002802c0a3c680001180808080000041002d00fca3c680001a410141002802c8a3c68000118180808000002201450d09200141003a0000200041186a419380c6800041014100280298a3c6800011858080800000200041146a4100360200200042013702082000200136020420004101360200200041386a41186a22014200370300200041386a41106a22034200370300200041c0006a2202420037030020004200370338200041386a41d48cc4800041014100280298a3c6800011858080800000200041b0016a41b48ac48000360200200041dc006a41286a4100360200200041dc006a41206a4204370200200041dc006a41186a4200370200200041c0016a4200370200200041a1016a200129030037000020004199016a200329030037000020004191016a200229030037000020004189016a200029033837000020004280808080c00037026c200041003602b801200041013a0088012000200041386a3602b401200020003602ac01200041003602642000420037025c200041f8016a200041dc006a2005280204200528020820052802102005280214109286808000200041dc006a41106a2103024020002d00f80122014104460d002000419c026a2104200041f8016a41046a2102024020014103460d0002400240024020010e020103000b200028029c02220120012802002206417f6a3602002004210120064101460d010c020b20002802fc01220120012802002206417f6a3602002002210120064101470d010b200110e28a8080000b200041f8016a200041dc006a200528021c20052802202005280228200528022c10928680800020002d00f80122014104460d00024020014103460d0002400240024020010e020003010b20002802fc01220120012802002201417f6a36020020014101460d010c020b200028029c02220120012802002201417f6a3602002004210220014101470d010b200210e28a8080000b200041dc006a108f8680800020031090878080000240200028026c450d00200028027041002802c0a3c68000118080808000000b02402000280278450d00200028027c41002802c0a3c68000118080808000000b4100210141002103024020002802b8012202450d0020002002360290022000410036028c022000200236028002200041003602fc012000200041bc016a28020022013602940220002001360284024101210120002802c00121030b20002003360298022000200136028802200020013602f801200041f8016a10a48d808000200041f0016a41d88cc48000360200200041cc016a41186a4100360200200042003702dc01200041003602d401200042003702cc012000200041386a3602f401200020003602ec01200041dc006a200041cc016a10b388808000200028025c2201418080808078470d0e42e60021082000280260220328020041fcffffff076a2201410320014105491b0e040f0f0c0b0d0b024002400240024020002802fc01220128020041fcffffff076a2202410320024105491b0e0403030102000b2001280204450d02200141086a28020041002802c0a3c68000118080808000000c020b2001280204450d01200141086a28020041002802c0a3c68000118080808000000c010b200110ca898080000b200141002802c0a3c6800011808080800000200041dc006a108f8680800020031090878080000240200028026c450d00200028027041002802c0a3c68000118080808000000b02402000280278450d00200028027c41002802c0a3c68000118080808000000b410021014100210341002102024020002802b8012204450d0020002004360290022000410036028c022000200436028002200041003602fc012000200041bc016a28020022033602940220002003360284024101210320002802c00121020b20002002360298022000200336028802200020033602f801200041f8016a10a48d808000410021030240200028020c2202450d00200020023602742000410036027020002002360264200041003602602000200041106a28020022013602782000200136026841012101200028021421030b2000200336027c2000200136026c2000200136025c200041dc006a10928d80800002402000280200450d00200028020441002802c0a3c68000118080808000000b02402005280200450d00200528020441002802c0a3c68000118080808000000b0240200528020c450d00200528021041002802c0a3c68000118080808000000b02402005280218450d00200528021c41002802c0a3c68000118080808000000b42e50021082005280224450d100c0f0b4101411610b280808000000b4101410a10b280808000000b4101411610b280808000000b4101410a10b280808000000b4104413010b280808000000b4101411610b280808000000b4101410a10b280808000000b4101411610b280808000000b4101410a10b280808000000b4101410110b280808000000b200310ca898080000c030b2003280204450d02200341086a28020041002802c0a3c68000118080808000000c020b2003280204450d01200341086a28020041002802c0a3c68000118080808000000c010b20004180026a2202200041dc006a41106a290200370300200041f8016a41106a2204200041dc006a41186a290200370300200041f8016a41186a200041dc006a41206a290200370300200041f8016a41206a2206200041dc006a41286a290200370300200041f8016a41286a2207200041dc006a41306a290200370300200041f8016a41306a2209200041dc006a41386a280200360200200020002902643703f8012000280260210a41002d00fca3c680001a41c00041002802c8a3c68000118180808000002203450d032003200a36020420032001360200200320002903f801370208200341106a2002290300370200200341186a2004290300370200200341206a200041f8016a41186a290300370200200341286a2006290300370200200341306a2007290300370200200341386a20092802003602002003200041cc016a36023c200041dc006a2003200041cc016a10b488808000420021080240200028025c2202418180808078460d00410021040340200028026021010240024002402002418080808078470d0041002102024002400240200128020041fcffffff076a2206410320064105491b0e0404040102000b2001280204450d0341002102200141086a28020041002802c0a3c68000118080808000000c030b2001280204450d0241002102200141086a28020041002802c0a3c68000118080808000000c020b200110ca898080000c010b200028026c21062000280268210702402002450d00200141002802c0a3c68000118080808000000b41012102200621012007450d010b200141002802c0a3c68000118080808000000b200041dc006a2003200328023c10b488808000200220046a2104200028025c2202418180808078470d000b2004ad21080b024020032802082202450d00200328020441086a210103402001280200220420042802002204417f6a360200024020044101470d00200110e18a8080000b200141306a21012002417f6a22020d000b0b02402003280200450d00200328020441002802c0a3c68000118080808000000b200341346a2802004129490d00200328020c41002802c0a3c68000118080808000000b41002101200341002802c0a3c6800011808080800000410021030240200028020c2202450d00200020023602742000410036027020002002360264200041003602602000200041106a28020022013602782000200136026841012101200028021421030b2000200336027c2000200136026c2000200136025c200041dc006a10928d80800002402000280200450d00200028020441002802c0a3c68000118080808000000b02402005280200450d00200528020441002802c0a3c68000118080808000000b0240200528020c450d00200528021041002802c0a3c68000118080808000000b02402005280218450d00200528021c41002802c0a3c68000118080808000000b2005280224450d010b200528022841002802c0a3c68000118080808000000b200541002802c0a3c6800011808080800000200041b0026a24808080800020080f0b410441c00010b280808000000be207010a7f2380808080004180026b2201248080808000200141808080807836022c200141b8016a41086a22022001412c6a41086a22032802003602002001200129022c3703b801410021042001410c6a41e5c8c9a903200141b8016a4100280290a2c6800011858080800000200220032802003602002001200129022c3703b801200141386a41e5c8c9a903200141b8016a4100280290a2c6800011858080800000200141d8006a41e5c8c9a9032001412c6a4100280290a2c6800011858080800000200141b8016a41e5c8c9a9034100280298a2c680001184808080000020012802c0012205410574210620012802b80141ffffff3f71210720012802bc01210202400240024002400240034020062004460d01200220046a2103200441206a210420032001410c6a412010888e8080000d000b2005410574210641002104034020062004460d02200220046a2103200441206a21042003200141386a412010888e8080000d000b2005410574210641002104034020062004460d03200220046a2103200441206a21042003200141d8006a412010888e8080000d000b200141b8016a41e5c8c9a9032001410c6a41948ec48000410741002802a0a2c680001187808080000020012d00b801450d03200141f8006a41386a2204200141f1016a290000370300200141f8006a41306a2203200141e9016a290000370300200141f8006a41286a2206200141e1016a290000370300200141f8006a41206a2205200141d9016a290000370300200141f8006a41186a2208200141d1016a290000370300200141f8006a41106a2209200141c9016a290000370300200141f8006a41086a220a200141c1016a290000370300200120012900b901370378200141f8006a41948ec4800041072001410c6a41002802a8a2c6800011898080800000450d04200020012903783700002000200129000c370040200041386a2004290300370000200041306a2003290300370000200041286a2006290300370000200041206a2005290300370000200041186a2008290300370000200041106a2009290300370000200041086a200a290300370000200041c8006a2001410c6a41086a290000370000200041d0006a2001410c6a41106a290000370000200041d8006a2001410c6a41186a29000037000002402007450d00200241002802c0a3c68000118080808000000b20014180026a2480808080000f0b41ec8cc48000412841948dc4800010f880808000000b41a48dc48000412841cc8dc4800010f880808000000b41dc8dc48000412841848ec4800010f880808000000b419b8ec48000412641c48ec4800010a181808000000b41d48ec480004138418c8fc4800010f880808000000be207010a7f2380808080004180026b2201248080808000200141808080807836022c200141b8016a41086a22022001412c6a41086a22032802003602002001200129022c3703b801410021042001410c6a41f3e4c9a903200141b8016a41002802b0a2c6800011858080800000200220032802003602002001200129022c3703b801200141386a41f3e4c9a903200141b8016a41002802b0a2c6800011858080800000200141d8006a41f3e4c9a9032001412c6a41002802b0a2c6800011858080800000200141b8016a41f3e4c9a90341002802b8a2c680001184808080000020012802c0012205410574210620012802b80141ffffff3f71210720012802bc01210202400240024002400240034020062004460d01200220046a2103200441206a210420032001410c6a412010888e8080000d000b2005410574210641002104034020062004460d02200220046a2103200441206a21042003200141386a412010888e8080000d000b2005410574210641002104034020062004460d03200220046a2103200441206a21042003200141d8006a412010888e8080000d000b200141b8016a41f3e4c9a9032001410c6a41cc8fc48000410741002802c0a2c680001187808080000020012d00b801450d03200141f8006a41386a2204200141f1016a290000370300200141f8006a41306a2203200141e9016a290000370300200141f8006a41286a2206200141e1016a290000370300200141f8006a41206a2205200141d9016a290000370300200141f8006a41186a2208200141d1016a290000370300200141f8006a41106a2209200141c9016a290000370300200141f8006a41086a220a200141c1016a290000370300200120012900b901370378200141f8006a41cc8fc4800041072001410c6a41002802c8a2c6800011898080800000450d04200020012903783700002000200129000c370040200041386a2004290300370000200041306a2003290300370000200041286a2006290300370000200041206a2005290300370000200041186a2008290300370000200041106a2009290300370000200041086a200a290300370000200041c8006a2001410c6a41086a290000370000200041d0006a2001410c6a41106a290000370000200041d8006a2001410c6a41186a29000037000002402007450d00200241002802c0a3c68000118080808000000b20014180026a2480808080000f0b41ec8cc480004128419c8fc4800010f880808000000b41a48dc48000412841ac8fc4800010f880808000000b41dc8dc48000412841bc8fc4800010f880808000000b41d38fc48000412641fc8fc4800010a181808000000b418c90c48000413841c490c4800010f880808000000bff0501077f2380808080004180026b22012480808080002001418080808078360228200141b8016a41086a2202200141286a41086a2203280200360200200120012902283703b80141002104200141076a41e5c6919b07200141b8016a41002802f0a1c680001185808080000020022003280200360200200120012902283703b801200141356a41e5c6919b07200141b8016a41002802f0a1c6800011858080800000200141d6006a41e5c6919b07200141286a41002802f0a1c6800011858080800000200141b8016a41e5c6919b0741002802f8a1c680001184808080000020012802c001220541216c210620012802b80141216c210720012802bc01210202400240024002400240034020062004460d01200220046a2103200441216a21042003200141076a412110888e8080000d000b200541216c210641002104034020062004460d02200220046a2103200441216a21042003200141356a412110888e8080000d000b200541216c210641002104034020062004460d03200220046a2103200441216a21042003200141d6006a412110888e8080000d000b200141b8016a41e5c6919b07200141076a418491c4800041054100280280a2c680001187808080000020012d00b801450d03200141f7006a200141b9016a41c10010848e8080001a200141f7006a418491c480004105200141076a4100280288a2c6800011898080800000450d042000200141f7006a41c10010848e808000220441e1006a200141276a2d00003a0000200441d9006a2001411f6a290000370000200441d1006a200141176a290000370000200441c9006a2001410f6a29000037000020042001290007370041024020074121490d00200241002802c0a3c68000118080808000000b20014180026a2480808080000f0b41ec8cc48000412841d490c4800010f880808000000b41a48dc48000412841e490c4800010f880808000000b41dc8dc48000412841f490c4800010f880808000000b418991c48000412441b091c4800010a181808000000b41c091c48000413641f891c4800010f880808000000be50601037f23808080800041e0006b2200248080808000418c92c48000410d418892c48000410441002802e0a1c68000118680808000002000410036022c200041206a418c92c48000410d2000412c6a4104410041002802c8a1c68000118a8080800000200020002802242201360234200020002802202202360230024002400240024002400240024002402002450d0020014104470d00200028022c210220002000412c6a36023c200241f4cacda307470d0120004100360238200041186a418c92c48000410d200041386a4104410441002802c8a1c68000118a80808000002000200028021c220136024020002000280218220236023c2002450d0220010d022000200041386a36024420002802380d0341f092c48000410b41fb92c480004113418892c48000410441002802e8a2c68000118a80808000002000410036022c200041106a41f092c48000410b41fb92c4800041132000412c6a4104410041002802e0a2c68000118b80808000002000200028021422013602342000200028021022023602302002450d0420014104470d04200028022c210220002000412c6a36023c200241f4cacda307470d0520004100360238200041086a41f092c48000410b41fb92c480004113200041386a4104410841002802e0a2c68000118b80808000002000200028020c220136024020002000280208220236023c2002450d0620010d062000200041386a36024420002802380d07200041e0006a2480808080000f0b200041003602484100200041306a419c92c48000200041c8006a41a492c4800010a489808000000b2000410036024841002000413c6a41b492c48000200041c8006a41b892c4800010a589808000000b2000410036024841002000413c6a41ec8ac48000200041c8006a41c892c4800010a489808000000b200041003602484100200041c4006a41dc92c48000200041c8006a41e092c4800010a589808000000b200041003602484100200041306a419c92c48000200041c8006a419093c4800010a489808000000b2000410036024841002000413c6a41b492c48000200041c8006a41a093c4800010a589808000000b2000410036024841002000413c6a41ec8ac48000200041c8006a41b093c4800010a489808000000b200041003602484100200041c4006a41dc92c48000200041c8006a41c093c4800010a589808000000b991701077f23808080800041f0056b2202248080808000200241e0026a41086a2203200041086a280200360200200220002902003703e00220024184026a200241e0026a109a8d808000200241e0026a10a68d808000200241e0026a41306a20024184026a41306a290200370300200241e0026a41286a20024184026a41286a290200370300200241e0026a41206a20024184026a41206a290200370300200241e0026a41186a20024184026a41186a290200370300200241e0026a41106a20024184026a41106a290200370300200320024184026a41086a290200370300200241a0036a200141086a290000370300200241a8036a200141106a290000370300200241b0036a200141186a29000037030020022002290284023703e0022002200129000037039803200241b8036a41b89ec3800041014100280298a3c68000118580808000002002200241e0026a41f80010848e8080002202428080808080808080807f37027c200241003b0178200241d4046a41003a0000200241d0046a41003602002002418c046a420037020020024180046a4200370300200241b4056a4100360200200241a8056a41003a0000200241a4056a4100360200200241e0046a4200370300200241003a00b80520024280808080c0003702ac05200241003602d804200241003602f8032002420037039803200241003602900320024200370388032002410036028003200242003703f802200241003602f002200242003703e802200241003602e00220024180808080783602a003200241003b01cc05200220023602c8052002200241e0026a3602c40520024184026a200241c4056a41d093c48000410610df8680800002400240024002402002280284022200418080808078460d0002402000450d0020022802880241002802c0a3c68000118080808000000b20024184026a200241e0026a20024101109088808000200241d0056a41186a220320024184026a41186a290000370300200241d0056a41106a220420024184026a41106a290000370300200241d0056a41086a220520024184026a41086a29000037030020022002290084023703d00541002d00fca3c680001a2002410036028c022002428080808010370284020240412041002802c8a3c68000118180808000002200450d00200020022903d005370000200041186a22062003290300370000200041106a22072004290300370000200041086a2208200529030037000020024184026a4100412010b1828080002002280288022204200228028c0222056a22032000290000370000200341086a2008290000370000200341106a2007290000370000200341186a2006290000370000200041002802c0a3c680001180808080000020022802840221000240024020050d0020042001412010888e808000450d010b02402000450d00200441002802c0a3c68000118080808000000b41d693c4800041ce0041a494c4800010f880808000000b02402000450d00200441002802c0a3c68000118080808000000b41002d00fca3c680001a410141002802c8a3c68000118180808000002200450d02200041003a0000200241013602d805200220003602d405200241013602d00541002d00fca3c680001a410141002802c8a3c68000118180808000002200450d03200041013a00002002410136028c0220022000360288022002410136028402200241e0026a200241d0056a20024184026a108f8880800020024184026a200241e0026a20024101109088808000200241d0056a41186a220320024184026a41186a290000370300200241d0056a41106a220420024184026a41106a290000370300200241d0056a41086a220520024184026a41086a29000037030020022002290084023703d00541002d00fca3c680001a2002410036028c02200242808080801037028402412041002802c8a3c68000118180808000002200450d04200020022903d005370000200041186a22062003290300370000200041106a22072004290300370000200041086a2204200529030037000020024184026a4100412010b1828080002002280288022205200228028c0222086a22032000290000370000200341086a2004290000370000200341106a2007290000370000200341186a2006290000370000200041002802c0a3c68000118080808000002002280284022100024020080d0020052001412010888e8080000d0002402000450d00200541002802c0a3c68000118080808000000b41b494c4800041ce00418495c4800010f880808000000b20024184046a210102402000450d00200541002802c0a3c68000118080808000000b200241d8046a2103200241f8036a2104200110a38d80800002400240200228029004220141054b0d002001450d01200241e0026a41b4016a21000340200010a68d8080002000410c6a21002001417f6a22010d000c020b0b200241e0026a41b4016a2802002105024020024198046a2802002201450d00200521000340200010a68d8080002000410c6a21002001417f6a22010d000b0b200541002802c0a3c68000118080808000000b200410a28d808000200310a18d8080000240024020022802e404220141054b0d002001450d01200241e0026a4188026a21000340200010a78d8080002000410c6a21002001417f6a22010d000c020b0b200241e0026a4188026a28020021030240200241ec046a2802002201450d00200321000340200010a78d8080002000410c6a21002001417f6a22010d000b0b200341002802c0a3c68000118080808000000b024020022802b4052203450d0020022802b00521052003410171210641002101024020034101460d00200541146a21002003417e7121044100210103400240200041706a2000416c6a22032003280200418080808078461b2203280200450d00200328020441002802c0a3c68000118080808000000b0240200041046a20002000280200418080808078461b2203280200450d00200328020441002802c0a3c68000118080808000000b200041286a21002004200141026a2201470d000b0b2006450d002005200141146c6a220020002802004180808080784622014102746a280200450d00200041046a200020011b28020441002802c0a3c68000118080808000000b024020022802ac05450d0020022802b00541002802c0a3c68000118080808000000b024020022802a003418080808078460d0002400240200241ac036a28020022000d0041002100410021010c010b2002200036029c0220024100360298022002200036028c0220024100360288022002200241b0036a28020022003602a0022002200036029002200241b4036a2802002101410121000b200220013602a4022002200036029402200220003602840220024184026a10928d80800020022802a003450d00200241a4036a28020041002802c0a3c68000118080808000000b2002410c6a10a58d80800002402002280200450d00200228020441002802c0a3c68000118080808000000b02402002280280012200418080808078460d0002402000450d0020024184016a28020041002802c0a3c68000118080808000000b0240200241c8016a2802002200418080808078460d002000450d00200241cc016a28020041002802c0a3c68000118080808000000b0240200241d4016a2802002200418080808078460d002000450d00200241d8016a28020041002802c0a3c68000118080808000000b024020024194016a2802002201450d0020024190016a28020041086a210003402000280200220320032802002203417f6a360200024020034101470d00200010e18a8080000b200041306a21002001417f6a22010d000b0b0240200228028c01450d0020022802900141002802c0a3c68000118080808000000b200241c0016a2802004129490d0020024198016a28020041002802c0a3c68000118080808000000b200241f0056a2480808080000f0b4101412010b280808000000b41808080807820022802880210cb89808000419495c48000413241c895c4800010f880808000000b4101410110b280808000000b4101410110b280808000000b4101412010b280808000000b850201057f23808080800041306b220324808080800020032000280208220436020c2003200028020422053602082003200128020822063602142003200128020422073602100240024020042006470d0020052007200410888e8080000d00200320043602082003200236021020042002470d0102402001280200450d00200741002802c0a3c68000118080808000000b02402000280200450d00200541002802c0a3c68000118080808000000b200341306a2480808080000f0b200341003602184100200341086a200341106a200341186a419ca2c4800010a689808000000b200341003602184100200341086a200341106a200341186a41aca2c4800010a789808000000bce0e020c7f037e23808080800041e0016b220024808080800002404100280284a4c680004105470d004100280290a1c680002101410028028ca1c6800021024100280280a4c680002103200041c0016a4200370200200041bc016a41e8d1c38000360200200041b8016a4101360200200041b0016a4104360200200041ac016a418892c48000360200200041a0016a41f48ac48000ad4280808080900c8437020020004194016a41fe8bc48000ad4280808080e00284370200200041cca2c480003602b401200041053602a8012000410036029c01200041003602900120004281808080e0ca0037028801200241ecf2c08000200341024622031b20004188016a200141d4f2c0800020031b280210118480808000000b2000410f360210200041d4a2c4800036020c02400240024002400240024041002802f8a3c680000d0002400240024041002d00e8a3c680000e03030102000b41e0a3c6800010c58d80800041ff01710e03020001000b41002802e0a3c680002103024002404100280294a4c680004102460d0041988dc68000210241e48dc6800021010c010b41002802f4a3c68000210241002802f0a3c68000210141002802eca3c68000450d002002280208417f6a41787120016a41086a21010b20012003200228021411838080800000450d010b41002802e0a3c68000220141206a28020022020d0141e3a2c4800041224188a3c4800010a181808000000b41002d0090a4c680000d044100280284a4c680004105470d0441002802e0a3c6800021012000410536021420002001290214370218410028028ca1c6800041ecf2c080004100280280a4c6800041024622021b2204200041146a4100280290a1c6800041d4f2c0800020021b220528020c11838080800000450d0441002802e0a3c68000220241206a2802002203450d01200028021c21062000280218210720002802142108200241286a2802002109200241246a280200210a200228021c210b20004100360248200020093602442000200a3602402000200b3602382000200336023c200041cc006a410c6a4200370200200041a8a3c4800036024c200041e8d1c380003602542000410136025020034101460d02200041346a41c0a3c4800036020020004101360274200020093602702000200a36026c200020033602682000200b360264200041b0a3c4800036022820002002411c6a36028401200041306a200041f8006a3602002000200041e4006a36022c2000200041cc006a3602242000200041386a3602202000200041206a36027c20002000410c6a36027820004102360280012001290200210c20004188016a41386a420137020020004188016a41306a4101360200200041b0016a2006360200200041ac016a2007360200200041a0016a200141386a3502004220862001350234220d8437020020004188016a410c6a200141306a350200422086200135022c220e84370200200041bc016a200041d0016a3602002000418c89c680003602b401200020083602a801200041a0838080003602d401200041013a00dc01200041024101200d501b36029c01200041024101200e501b360290012000200041d8016a3602d0012000200041fc006a3602d8012000200c37028801200420004188016a2005280210118480808000000c040b200141286a2802002103200141246a2802002104200128021c2105200041003602482000200336024420002004360240200020053602382000200236023c200041d8006a4200370200200041a8a3c4800036024c200041e8d1c380003602542000410136025020024101460d02200041346a41c0a3c4800036020020004101360274200020033602702000200436026c2000200236026820002005360264200041b0a3c4800036022820002001411c6a36021c200041306a200041d8016a3602002000200041e4006a36022c2000200041cc006a3602242000200041386a3602202000200041206a36021420002000410c6a3602d801200041023602182000200136029c0120004201370388014100280294a4c6800021012000200041146a36029801024020014102470d0041002802f4a3c68000210241002802f0a3c680002101024041002802eca3c68000450d002002280208417f6a41787120016a41086a21010b200120004188016a200228022811838080800000450d00200120004188016a200228022c118480808000000b41002d0090a4c680000d034100280284a4c680004105470d0341002802e0a3c6800021012000410536027c2000200129021437028001410028028ca1c6800041ecf2c080004100280280a4c6800041024622021b2203200041fc006a4100280290a1c6800041d4f2c0800020021b220228020c11838080800000450d0320004188016a41086a200041fc006a41086a2802003602002000200029027c3703880120012003200220004188016a200041146a10c08d8080000c030b41e3a2c4800041224188a3c4800010a181808000000b41e3a2c4800041224188a3c4800010a181808000000b41e3a2c4800041224188a3c4800010a181808000000b200041e0016a2480808080000ba80605027f027e087f017e017f23808080800041d0006b2201248080808000200142919fd78da1a1ad84ff003703082001429ceccef7a6c0dedd20370300200142c2a5b2f6d3b4fb986f370318200142dcd7ddd8f18e8ca1e300370310200141306a200110e88880800020012d004021022001290330210320012903382104200142919fd78da1a1ad84ff003703082001429ceccef7a6c0dedd2037030020014282fceae49dd9e2861d370318200142de8c84a1ecd0a6d30c370310200141306a200110e288808000024002400240024020012802302205418080808078470d00410021064108210741082108410021050c010b200128023421080240200128023822060d0041002106410821070c010b200641b3e6cc194b0d01200641286c2209417f4c0d014100210a41002d00fca3c680001a200941002802c8a3c68000118180808000002207450d022006210b2008210c03402009200a460d01200c290320210d2007200a6a220e200c290300370300200e41186a200c41186a290300370300200e41106a200c41106a290300370300200e41086a200c41086a290300370300200e41206a200d370300200a41286a210a200c41286a210c200b417f6a220b0d000b0b200142919fd78da1a1ad84ff003703382001429ceccef7a6c0dedd20370330200142c6e4a9b1aaa1afebf200370348200142fa82b1828b81b8f31e37034042032003200241ff0171410346220c1b210d420a2004200c1b210341012002200c1b210e200041206a210c2001200141306a10e5888080000240024020012d00000d00200c4200370300200c41186a4200370300200c41106a4200370300200c41086a42003703000c010b200c2001290001370000200c41186a200141196a290000370000200c41106a200141116a290000370000200c41086a200141096a2900003700000b2000200e3a004c200020063602402000200d37031020004206370308200042e807370300200041c8006a2006360200200041c4006a2007360200200041186a200337030002402005450d00200841002802c0a3c68000118080808000000b200141d0006a2480808080000f0b10ae80808000000b4108200910b280808000000b940301047f02402001280200450d00200128020441002802c0a3c68000118080808000000b20004194016a2802002102024020004198016a2802002203450d00200221014100210403402002200441146c6a21050240024002400240024020012d00000e0400010102040b200141086a21050c020b200541086a21050c010b200541046a21050b2005280200450d00200528020441002802c0a3c68000118080808000000b200441016a2104200141146a21012003417f6a22030d000b0b0240200028029001450d00200241002802c0a3c68000118080808000000b2000418c026a2802002102024020004190026a2802002203450d00200221014100210403402002200441146c6a21050240024002400240024020012d00000e0400010102040b200141086a21050c020b200541086a21050c010b200541046a21050b2005280200450d00200528020441002802c0a3c68000118080808000000b200441016a2104200141146a21012003417f6a22030d000b0b0240200028028802450d00200241002802c0a3c68000118080808000000b41000bad0201037f2380808080004180026b220124808080800041002d00fca3c680001a024002400240410841002802c8a3c68000118180808000002202450d00200242f3deb5abf6ebdab2f90037000041002d00fca3c680001a410841002802c8a3c68000118180808000002203450d0120032000290320370000200141c8016a41023a00002001410836021420012003360210200141083602182001200236021c20014108360220200142838080808001370308200141f0016a200141086a10f78c808000200141f0016a41002802d8a3c6800011818080800000450d024184a4c48000412b200141ff016a41b0a4c4800041c0a4c48000108981808000000b4101410810b280808000000b4101410810b280808000000b200141086a10c98980800020014180026a2480808080000b040041010bc80301057f23808080800041206b22022480808080000240024020012d00000d00410221030c010b200241186a200141196a290000370300200241106a200141116a290000370300200241086a200141096a29000037030020022001290001370300410121030b41002d00fca3c680001a02400240411041002802c8a3c68000118180808000002201450d0020014281808080103702002001410c6a41c8a6c480003602002001410136020841002d00fca3c680001a411041002802c8a3c68000118180808000002204450d01200441b0a6c4800036020c20044101360208200442818080801037020020012001280200417f6a2205360200024020050d00200128020822062001410c6a28020022052802001180808080000002402005280204450d00200641002802c0a3c68000118080808000000b20012001280204417f6a220536020420050d00200141002802c0a3c68000118080808000000b200020033a000420002004360200200020022903003700052000410d6a200241086a290300370000200041156a200241106a2903003700002000411d6a200241186a290300370000200241206a2480808080000f0b4104411010b280808000000b4104411010b280808000000ba90a01077f23808080800041f0026b22032480808080000240024020022d0004450d002002280200220441086a28020020012004410c6a280200280214118380808000000d00200041206a410610dc88808000200041003a00182000420037030020042004280200417f6a2202360200024020020d00200428020822002004410c6a28020022022802001180808080000002402002280204450d00200041002802c0a3c68000118080808000000b200441046a22022002280200417f6a220236020020020d00200441002802c0a3c68000118080808000000b200110c9898080000c010b200128020021042003410c6a200141046a220541d40010848e8080001a0240024002400240200441736a2201410220014104491b0e0400010203000b200341a8016a200341306a290200370300200341a0016a200341286a29020037030020034198016a200341206a29020037030020034190016a200341186a290200370300200341e0006a41086a200241086a290200370300200341e0006a41106a200241106a290200370300200341e0006a41186a200241186a290200370300200341e0006a41206a200241206a290200370300200320032902103703880120032002290200370360200341003602e802200341003602e0022003200341e0026a3602ec02200341d8016a200341e0006a41d00010848e8080001a2003200341ec026a3602a802200041f0a0c68000200341d8016a10c187808000200341e0026a10a98d8080000c030b200341e0006a41286a22012003290210370300200341e0006a41386a2204200341206a290200370300200341e0006a41306a2205200341186a290200370300200341e0006a41086a2206200241086a290200370300200341e0006a41106a2207200241106a290200370300200341e0006a41186a2208200241186a290200370300200341e0006a41206a2209200241206a29020037030020032002290200370360200341003602e802200341003602e0022003200341e0026a3602ec02200341d8016a41386a2004290300370300200341d8016a41306a2005290300370300200341d8016a41286a2001290300370300200341d8016a41206a2009290300370300200341d8016a41186a2008290300370300200341d8016a41106a2007290300370300200341d8016a41086a2006290300370300200320032903603703d8012003200341ec026a36029802200041f0a0c68000200341d8016a10c287808000200341e0026a10a98d8080000c020b200341d8016a410472200541d40010848e8080001a200341d0026a200241206a290200370300200341c8026a200241186a290200370300200341c0026a200241106a290200370300200341b8026a200241086a290200370300200320022902003703b0022003410036026820034100360260200320043602d8012003200341e0026a3602d8022003200341e0006a3602e002200041f0a0c68000200341d8016a10c387808000200341e0006a10a98d8080000c010b20034188016a2003410c6a41046a41d00010848e8080001a200341e0006a41206a200241206a290200370300200341e0006a41186a200241186a290200370300200341e0006a41106a200241106a290200370300200341e0006a41086a200241086a29020037030020032002290200370360200341003602e802200341003602e0022003200341e0026a3602ec02200341d8016a200341e0006a41f80010848e8080001a2003200341ec026a3602d002200041f0a0c68000200341d8016a10c587808000200341e0026a10a98d8080000b200341f0026a2480808080000bcc0303027f017e027f23808080800041d0006b22012480808080002001412c6a41eba7c48000410b41fe8bc48000411641e8d1c38000410010d882808000200141086a41086a2202410036020020014280808080c00037030820012902302103200128022c21042001410036021c20014280808080c000370214200141c4006a200141146a41f9a6c48000410610c98b808000200141146a200141c4006a41f5a6c48000410410948b808000200141c4006a200141146a41e8a6c48000410d10c88b808000200141386a200141c4006a41e0a6c48000410810818b8080002001200128023836021c2001200128023c220536021420012005200128024041246c6a36022020012005360218200141c4006a200141146a10fb8680800002402004418080808078470d0041a8d8c480004111419cd9c4800010a181808000000b200042808080808001370244200041cc006a4100360200200141146a410b6a200141c4006a41086a2802003600002000413c6a200337020020002004360238200041013a000020002001290308370350200041d8006a20022802003602002001200129024437001720002001290014370001200041086a2001411b6a290000370000200141d0006a2480808080000bbd0203027f017e017f23808080800041d0006b2201248080808000200141286a418ea8c48000410741fe8bc48000411641e8d1c38000410010d882808000200141086a2202410036020020014280808080c000370300200129022c210320012802282104200142808080808001370218200142888080808001370210200141346a200141106a10f98680800002402004418080808078470d0041a8d8c480004111419cd9c4800010a181808000000b200042808080808001370244200041cc006a4100360200200141cc006a200141346a41086a2802003600002000413c6a200337020020002004360238200041003a000020002001290300370350200041d8006a20022802003602002001200129023437004420002001290041370001200041086a200141c1006a41076a290000370000200141d0006a2480808080000b970303027f017e027f23808080800041d0006b22012480808080002001412c6a4182a8c48000410c41fe8bc48000411641e8d1c38000410010d882808000200141086a41086a2202410036020020014280808080c00037030820012902302103200128022c21042001410036021c20014280808080c000370214200141c4006a200141146a41f9a6c480004106109c8b808000200141386a200141c4006a41e0a6c48000410810a58b8080002001200128023836021c2001200128023c220536021420012005200128024041246c6a36022020012005360218200141c4006a200141146a10fb8680800002402004418080808078470d0041a8d8c480004111419cd9c4800010a181808000000b200042808080808001370244200041cc006a41003602002001411f6a200141c4006a41086a2802003600002000413c6a200337020020002004360238200041013a000020002001290308370350200041d8006a20022802003602002001200129024437001720002001290014370001200041086a2001411b6a290000370000200141d0006a2480808080000baf0303027f017e027f23808080800041d0006b22012480808080002001412c6a41f6a7c48000410c41fe8bc48000411641e8d1c38000410010d882808000200141086a41086a2202410036020020014280808080c00037030820012902302103200128022c21042001410036021c20014280808080c000370214200141c4006a200141146a41f9a6c48000410610c38b808000200141146a200141c4006a41f5a6c48000410410d28b808000200141386a200141146a41e0a6c48000410810b68b8080002001200128023836021c2001200128023c220536021420012005200128024041246c6a36022020012005360218200141c4006a200141146a10fb8680800002402004418080808078470d0041a8d8c480004111419cd9c4800010a181808000000b200042808080808001370244200041cc006a41003602002001411f6a200141c4006a41086a2802003600002000413c6a200337020020002004360238200041013a000020002001290308370350200041d8006a20022802003602002001200129024437001720002001290014370001200041086a2001411b6a290000370000200141d0006a2480808080000baf0201057f23808080800041206b2201248080808000200041c0006a108c8a808000200010ac878080002000412c6a28020021020240024002400240200041306a28020022030d0041012104410021050c010b200341ffffff1f4b0d0120034105742205417f4c0d0141002d00fca3c680001a200541002802c8a3c68000118180808000002204450d020b20042002200510848e8080002105200142f0fe93e98686d7ab8c7f37030820014280eee1b0e3b7afe9987f37030020014282fceae49dd9e2861d370318200142de8c84a1ecd0a6d30c370310200520032001412010cd8780800002402003450d00200541002802c0a3c68000118080808000000b200041346a10988c80800010928a808000200141206a2480808080000f0b10ae80808000000b4101200510b280808000000bc30301027f23808080800041d0006b2203248080808000024002400240024002400240200228020041736a2204410220044104491b0e03010203000b200041808080807836021020004181023b01000c030b20002001200241086a10b98a8080000c020b0240200241186a2d00004104470d00200141ff017141014d0d030240417f4100280284a4c680002202410247200241024b1b2202417f460d00200241ff01710d010b4100280290a1c680002102410028028ca1c6800021044100280280a4c680002101200341c4006a4200370200200341c0006a41e4e7c280003602002003413c6a4101360200200341346a410d360200200341306a41c6e8c28000360200200341246a41e4e7c28000ad4280808080a00c84370200200341186a41d3e8c28000ad4280808080900384370200200341dce7c28000360238200341003602202003410036021420034281808080b01a37020c2003410236022c200441ecf2c08000200141024622011b2003410c6a200241d4f2c0800020011b280210118480808000000b2000418080808078360210200041003b01000c010b20002001200210eb878080000b200341d0006a2480808080000f0b200228020810b087808000000bb80203027f017e017f23808080800041c0006b2201248080808000200141286a41ffa6c48000411141fe8bc48000411641e8d1c38000410010d882808000200141086a2202410036020020014280808080c000370300200129022c21032001280228210420014284808080c00037021020014280808080c000370218200141346a200141106a10fb8680800002402004418080808078470d0041a8d8c480004111419cd9c4800010a181808000000b200042808080808001370244200041cc006a41003602002001411b6a200141346a41086a2802003600002000413c6a200337020020002004360238200041013a000020002001290300370350200041d8006a20022802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141c0006a2480808080000bc20301037f23808080800041106b220224808080800002402001280200220328020020032802082204470d0020032004410110ab86808000200328020821040b200328020420046a41fb003a00002003200441016a3602082002200136020c20024180023b0108024002400240200241086a4190a7c480004106200041c0006a10da8680800022030d00024020022d0008450d0041002d00fca3c680001a411441002802c8a3c68000118180808000002203450d022003420037020c2003410d3602000c010b200241086a4196a7c480004104200010db8680800022030d00024020022d0008450d0041002d00fca3c680001a411441002802c8a3c68000118180808000002203450d032003420037020c2003410d3602000c010b200241086a419aa7c48000410d200041286a10dc8680800022030d00024020022d0008450d0010868380800021030c010b200241086a41a7a7c480004108200041346a10d58680800022030d0002402002280208220341ff01710d0020034180fe0371450d00200228020c28020041b8d0c3800041011083878080000b410021030b200241106a24808080800020030f0b4104411410b280808000000b4104411410b280808000000bbf010002400240024002400240024002402002417c6a0e0a00050205030505050501050b200128000041e2c289ab06470d04200041013a00010c030b2001419aa7c48000410d10888e8080000d03200041023a00010c020b20014190a7c48000410610888e808000450d030c020b200129000042e2c2b18be6edd8b2f300520d01200041033a00010b200041003a00000f0b20002001200241b0a7c48000410410e58a808000360204200041013a00000f0b200041003a0001200041003a00000bb20602037f047e2380808080004180026b22022480808080000240024002400240024002400240200128020022032802042204450d0020032004417f6a36020420032003280200220441016a36020020042d00000e0401020305040b200041003602000c050b200241e0006a200110a68a8080000240024020022d0060450d00200241b0016a41206a200241e0006a41206a2903002205370300200241b0016a41186a200241e0006a41186a2903002206370300200241b0016a41106a200241e0006a41106a2903002207370300200241b0016a41086a200241e0006a41086a2903002208370300200241086a410c6a2008370200200241086a41146a2007370200200241086a411c6a2006370200200241086a41246a20053702002002200229036022053703b0012002200537020c200020022902083702042000410c6a200241086a41086a290200370200200041146a200241086a41106a2902003702002000411c6a200241086a41186a290200370200200041246a200241086a41206a2902003702002000412c6a200241306a280200360200410d21030c010b410021030b200020033602000c040b200241e0006a200110ba87808000024020022d00704105460d00200241b0016a41106a200241e0006a41106a2903002205370300200241b0016a41086a200241e0006a41086a2903002206370300200241086a410c6a2006370200200241086a41146a20053702002002200229036022053703b0012002200537020c200020022902083702042000410c6a200241086a41086a290200370200200041146a200241086a41106a2902003702002000411c6a200241206a2802003602002000410e3602000c040b200041003602000c030b200241086a200110c08880800002402002280208450d002000200241086a41d80010848e8080001a0c030b200041003602000c020b200041003602000c010b200241e0006a200110a58c808000024020022d0060450d00200241b0016a200241e0006a41d00010848e8080001a200241086a41046a200241b0016a41d00010848e8080001a200041046a200241086a41d40010848e8080001a200041103602000c010b200041003602000b20024180026a2480808080000b2100200128021441d895c48000410f200141186a28020028020c118280808000000be702020c7f017e23808080800041106b220224808080800020002802082203415c6a21042000280204210520002d0001210620002d0000210703400240024002400240024020070e03010200010b20054110200541104b1b21082003200541246c22096a2100200420096a2109200541087441807e6a210a034020082005460d03200941246a2109200a4180026a210a200541016a210520002d0000210b200041246a2100200b4102460d000b200a4180fe0371410172210c2009210d0c030b200c41807e71410272210c0c020b200c41807e71210c0240200641ff01710d00410121062005210d0c020b200c410272210c0c010b200c41807e71410272210c200821050b0240200c41ff01714102460d00200d2d0000450d01200d280204210020022001360204200cad220e42ff01834202510d0120022000ad422086200e42ffff038384370308200241046a200241086a10bd8c8080000c010b0b200241106a2480808080000be702020c7f017e23808080800041106b220224808080800020002802082203415c6a21042000280204210520002d0001210620002d0000210703400240024002400240024020070e03010200010b20054110200541104b1b21082003200541246c22096a2100200420096a2109200541087441807e6a210a034020082005460d03200941246a2109200a4180026a210a200541016a210520002d0000210b200041246a2100200b4102460d000b200a4180fe0371410172210c2009210d0c030b200c41807e71410272210c0c020b200c41807e71210c0240200641ff01710d00410121062005210d0c020b200c410272210c0c010b200c41807e71410272210c200821050b0240200c41ff01714102460d00200d2d0000450d01200d280204210020022001360204200cad220e42ff01834202510d0120022000ad422086200e42ffff038384370308200241046a200241086a10bc8c8080000c010b0b200241106a2480808080000bcc0101067f23808080800041206b2202248080808000200141086a280200220320012802042204200320044b1b210520012802002103200128020c2106024002400240034020052004460d022001200441016a2204360204200241086a200310bc8a80800020022802080d01200241146a2003200228020c10d08580800020022802142207418080808078460d012007418180808078460d000b20002002290218370204200020073602000c020b200641013a00000b20004180808080783602000b200241206a2480808080000bef0601107f2380808080004190016b220124808080800002402000280200220220002802042203460d0020002802102104200028020822054110200541104b1b2106200028020c200541246c6a2107200141ec006a41086a2108200141ec006a41017221090240034020002002410c6a220a3602004102210b024020022802004102460d00200141ec006a200210838a8080004102210b200141c4006a41026a200941026a2d00003a0000200141286a41086a2202200841086a290200370300200141286a41106a220c200841106a290200370300200141286a41186a220d200841186a280200360200200120092f00003b0144200120082902003703282001280270210e024020012d006c220f417e6a0e020301000b200141246a41026a200141c4006a41026a2d00003a0000200141086a41086a2002290300370300200141086a41106a200c290300370300200141086a41186a200d280200360200200120012f01443b012420012001290328370308200f210b0b200141e8006a41026a2202200141246a41026a2d00003a0000200141c8006a41086a220c200141086a41086a290300370300200141c8006a41106a220d200141086a41106a290300370300200141c8006a41186a220f200141086a41186a280200360200200120012f01243b01682001200129030837034802400240024020062005460d0020072d00000e03020102010b2006411041fcc8c4800010f980808000000b200741046a280200221010848a808000201041002802c0a3c68000118080808000000b2007200b3a0000200741016a20012f01683b0000200741046a200e360200200741086a2001290348370200200741036a20022d00003a0000200741106a200c290300370200200741186a200d290300370200200741206a200f2802003602002000200541016a2205360208200741246a2107200a2102200a2003470d000c020b0b024020042802002207450d000240024002400240200728020041fcffffff076a2202410320024105491b0e0403030102000b2007280204450d02200741086a28020041002802c0a3c68000118080808000000c020b2007280204450d01200741086a28020041002802c0a3c68000118080808000000c010b200710858a8080000b200741002802c0a3c68000118080808000000b2004200e3602002000200541016a3602080b20014190016a2480808080000baa0801057f23808080800041800e6b22022480808080000240024002400240024002400240024002400240024002400240024020012802000d0020012802042103200128020822040d01410121010c020b200241e0016a200128020422042001280208220110c28c80800020022802e00122034105470d05200241046a410c6a200241e0016a410c6a290200370200200220022902e4013702080c060b20044120460d012004417f4c0d0741002d00fca3c680001a200441002802c8a3c68000118180808000002201450d080b20012003200410848e808000210341002d00fca3c680001a413041002802c8a3c680001181808080000022010d014104413010b280808000000b200020032f00003b00012000200328000336020420002003290007370008200041036a200341026a2d00003a0000200041106a2003410f6a290000370000200041186a200341176a290000370000200041206a2003411f6a2d00003a0000410021010c010b200142003702102001200436020c2001200336020820012004360204200141888080807836020020002001360204200141186a4200370200200141206a4200370200200141286a4200370200410221010b200020013a00000c070b200241f00d6a41086a2205200241e0016a410c6a290200370300200220022902e4013703f00d200241940c6a41146a200241e0016a41146a41c80110848e8080001a200241940c6a410c6a2005290300370200200220033602940c200220022903f00d3702980c200241046a200241940c6a2004200110f48d80800020022802044105470d010b200241e0016a41186a22044200370300200241e0016a41206a22034200370300200241e0016a41286a22054200370300200241e0016a41086a2206200241106a290200370300200220022902083703e001200242003703f00141002d00fca3c680001a413041002802c8a3c68000118180808000002201450d03200120022903e001370200200141286a2005290300370200200141206a2003290300370200200141186a2004290300370200200141106a200241e0016a41106a290300370200200141086a2006290300370200200041023a0000200020013602040c050b200241940c6a200241046a41dc0110848e8080001a200241e0016a200241940c6a10b68a808000024020022802e00122044108460d0020022802e401210320024180076a200241e0016a41086a41940510848e8080001a41002d00fca3c680001a419c0541002802c8a3c68000118180808000002201450d042001200336020420012004360200200141086a20024180076a41940510848e8080001a20002001360204200041013a00000c050b20022802e4012101200041023a0000200020013602040c040b10ae80808000000b4101200410b280808000000b4104413010b280808000000b4104419c0510b280808000000b200241800e6a2480808080000be11101027f0240024002400240024002402000280200417e6a2201410420014106491b0e050501020304000b2000280204220120012802002201417f6a36020020014101470d04200041046a10e28a8080000c040b02402000412c6a2802004129490d00200028020441002802c0a3c68000118080808000000b20002802342201450d03200120012802002202417f6a36020020024101470d03200041346a10e28a8080000f0b0240200041d0006a2802004129490d00200028022841002802c0a3c68000118080808000000b20002d0004450d02200041086a280200220010848a808000200041002802c0a3c68000118080808000000f0b024020002d003022014102460d002001450d00200041346a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041d4006a2d000022014102460d002001450d00200041d8006a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041f8006a2d000022014102460d002001450d00200041fc006a280200220110848a808000200141002802c0a3c68000118080808000000b02402000419c016a2d000022014102460d002001450d00200041a0016a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041c0016a2d000022014102460d002001450d00200041c4016a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041e4016a2d000022014102460d002001450d00200041e8016a280200220110848a808000200141002802c0a3c68000118080808000000b024020004188026a2d000022014102460d002001450d002000418c026a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041ac026a2d000022014102460d002001450d00200041b0026a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041d0026a2d000022014102460d002001450d00200041d4026a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041f4026a2d000022014102460d002001450d00200041f8026a280200220110848a808000200141002802c0a3c68000118080808000000b024020004198036a2d000022014102460d002001450d002000419c036a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041bc036a2d000022014102460d002001450d00200041c0036a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041e0036a2d000022014102460d002001450d00200041e4036a280200220110848a808000200141002802c0a3c68000118080808000000b024020004184046a2d000022014102460d002001450d0020004188046a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041a8046a2d000022014102460d002001450d00200041ac046a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041cc046a2d000022014102460d002001450d00200041d0046a280200220110848a808000200141002802c0a3c68000118080808000000b2000280204450d01200041086a22012802002200450d01200020002802002202417f6a36020020024101470d01200110e28a8080000f0b024020004194056a2802004129490d0020002802ec0441002802c0a3c68000118080808000000b024020002d002c22014102460d002001450d00200041306a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041d0006a2d000022014102460d002001450d00200041d4006a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041f4006a2d000022014102460d002001450d00200041f8006a280200220110848a808000200141002802c0a3c68000118080808000000b024020004198016a2d000022014102460d002001450d002000419c016a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041bc016a2d000022014102460d002001450d00200041c0016a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041e0016a2d000022014102460d002001450d00200041e4016a280200220110848a808000200141002802c0a3c68000118080808000000b024020004184026a2d000022014102460d002001450d0020004188026a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041a8026a2d000022014102460d002001450d00200041ac026a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041cc026a2d000022014102460d002001450d00200041d0026a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041f0026a2d000022014102460d002001450d00200041f4026a280200220110848a808000200141002802c0a3c68000118080808000000b024020004194036a2d000022014102460d002001450d0020004198036a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041b8036a2d000022014102460d002001450d00200041bc036a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041dc036a2d000022014102460d002001450d00200041e0036a280200220110848a808000200141002802c0a3c68000118080808000000b024020004180046a2d000022014102460d002001450d0020004184046a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041a4046a2d000022014102460d002001450d00200041a8046a280200220110848a808000200141002802c0a3c68000118080808000000b0240200041c8046a2d000022014102460d002001450d00200041cc046a280200220110848a808000200141002802c0a3c68000118080808000000b2000280200450d0020002802042201450d00200120012802002202417f6a36020020024101470d00200041046a10e28a8080000f0b0bc50101027f024002400240024020002802002201418080808078732202410220024104491b0e03030301000b0240024002402000280204220028020041fcffffff076a2202410320024105491b0e0404040102000b2000280204450d03200041086a28020041002802c0a3c68000118080808000000c030b2000280204450d02200041086a28020041002802c0a3c68000118080808000000c020b200010858a8080000c010b2001450d01200028020421000b200041002802c0a3c68000118080808000000b0bef0601107f2380808080004190016b220124808080800002402000280200220220002802042203460d0020002802102104200028020822054110200541104b1b2106200028020c200541246c6a2107200141ec006a41086a2108200141ec006a41017221090240034020002002410c6a220a3602004102210b024020022802004102460d00200141ec006a200210878a8080004102210b200141c4006a41026a200941026a2d00003a0000200141286a41086a2202200841086a290200370300200141286a41106a220c200841106a290200370300200141286a41186a220d200841186a280200360200200120092f00003b0144200120082902003703282001280270210e024020012d006c220f417e6a0e020301000b200141246a41026a200141c4006a41026a2d00003a0000200141086a41086a2002290300370300200141086a41106a200c290300370300200141086a41186a200d280200360200200120012f01443b012420012001290328370308200f210b0b200141e8006a41026a2202200141246a41026a2d00003a0000200141c8006a41086a220c200141086a41086a290300370300200141c8006a41106a220d200141086a41106a290300370300200141c8006a41186a220f200141086a41186a280200360200200120012f01243b01682001200129030837034802400240024020062005460d0020072d00000e03020102010b2006411041ecc8c4800010f980808000000b200741046a280200221010848a808000201041002802c0a3c68000118080808000000b2007200b3a0000200741016a20012f01683b0000200741046a200e360200200741086a2001290348370200200741036a20022d00003a0000200741106a200c290300370200200741186a200d290300370200200741206a200f2802003602002000200541016a2205360208200741246a2107200a2102200a2003470d000c020b0b024020042802002207450d000240024002400240200728020041fcffffff076a2202410320024105491b0e0403030102000b2007280204450d02200741086a28020041002802c0a3c68000118080808000000c020b2007280204450d01200741086a28020041002802c0a3c68000118080808000000c010b200710858a8080000b200741002802c0a3c68000118080808000000b2004200e3602002000200541016a3602080b20014190016a2480808080000baa0801057f23808080800041800e6b22022480808080000240024002400240024002400240024002400240024002400240024020012802000d0020012802042103200128020822040d01410121010c020b200241e0016a200128020422042001280208220110c28c80800020022802e00122034105470d05200241046a410c6a200241e0016a410c6a290200370200200220022902e4013702080c060b20044120460d012004417f4c0d0741002d00fca3c680001a200441002802c8a3c68000118180808000002201450d080b20012003200410848e808000210341002d00fca3c680001a413041002802c8a3c680001181808080000022010d014104413010b280808000000b200020032f00003b00012000200328000336020420002003290007370008200041036a200341026a2d00003a0000200041106a2003410f6a290000370000200041186a200341176a290000370000200041206a2003411f6a2d00003a0000410021010c010b200142003702102001200436020c2001200336020820012004360204200141888080807836020020002001360204200141186a4200370200200141206a4200370200200141286a4200370200410221010b200020013a00000c070b200241f00d6a41086a2205200241e0016a410c6a290200370300200220022902e4013703f00d200241940c6a41146a200241e0016a41146a41c80110848e8080001a200241940c6a410c6a2005290300370200200220033602940c200220022903f00d3702980c200241046a200241940c6a2004200110f48d80800020022802044105470d010b200241e0016a41186a22044200370300200241e0016a41206a22034200370300200241e0016a41286a22054200370300200241e0016a41086a2206200241106a290200370300200220022902083703e001200242003703f00141002d00fca3c680001a413041002802c8a3c68000118180808000002201450d03200120022903e001370200200141286a2005290300370200200141206a2003290300370200200141186a2004290300370200200141106a200241e0016a41106a290300370200200141086a2006290300370200200041023a0000200020013602040c050b200241940c6a200241046a41dc0110848e8080001a200241e0016a200241940c6a10b78a808000024020022802e00122044108460d0020022802e401210320024180076a200241e0016a41086a41940510848e8080001a41002d00fca3c680001a419c0541002802c8a3c68000118180808000002201450d042001200336020420012004360200200141086a20024180076a41940510848e8080001a20002001360204200041013a00000c050b20022802e4012101200041023a0000200020013602040c040b10ae80808000000b4101200410b280808000000b4104413010b280808000000b4104419c0510b280808000000b200241800e6a2480808080000bef0601107f2380808080004190016b220124808080800002402000280200220220002802042203460d0020002802102104200028020822054110200541104b1b2106200028020c200541246c6a2107200141ec006a41086a2108200141ec006a41017221090240034020002002410c6a220a3602004102210b024020022802004102460d00200141ec006a200210878a8080004102210b200141c4006a41026a200941026a2d00003a0000200141286a41086a2202200841086a290200370300200141286a41106a220c200841106a290200370300200141286a41186a220d200841186a280200360200200120092f00003b0144200120082902003703282001280270210e024020012d006c220f417e6a0e020301000b200141246a41026a200141c4006a41026a2d00003a0000200141086a41086a2002290300370300200141086a41106a200c290300370300200141086a41186a200d280200360200200120012f01443b012420012001290328370308200f210b0b200141e8006a41026a2202200141246a41026a2d00003a0000200141c8006a41086a220c200141086a41086a290300370300200141c8006a41106a220d200141086a41106a290300370300200141c8006a41186a220f200141086a41186a280200360200200120012f01243b01682001200129030837034802400240024020062005460d0020072d00000e03020102010b2006411041fcc8c4800010f980808000000b200741046a280200221010848a808000201041002802c0a3c68000118080808000000b2007200b3a0000200741016a20012f01683b0000200741046a200e360200200741086a2001290348370200200741036a20022d00003a0000200741106a200c290300370200200741186a200d290300370200200741206a200f2802003602002000200541016a2205360208200741246a2107200a2102200a2003470d000c020b0b024020042802002207450d000240024002400240200728020041fcffffff076a2202410320024105491b0e0403030102000b2007280204450d02200741086a28020041002802c0a3c68000118080808000000c020b2007280204450d01200741086a28020041002802c0a3c68000118080808000000c010b200710858a8080000b200741002802c0a3c68000118080808000000b2004200e3602002000200541016a3602080b20014190016a2480808080000bef0601107f2380808080004190016b220124808080800002402000280200220220002802042203460d0020002802102104200028020822054110200541104b1b2106200028020c200541246c6a2107200141ec006a41086a2108200141ec006a41017221090240034020002002410c6a220a3602004102210b024020022802004102460d00200141ec006a200210838a8080004102210b200141c4006a41026a200941026a2d00003a0000200141286a41086a2202200841086a290200370300200141286a41106a220c200841106a290200370300200141286a41186a220d200841186a280200360200200120092f00003b0144200120082902003703282001280270210e024020012d006c220f417e6a0e020301000b200141246a41026a200141c4006a41026a2d00003a0000200141086a41086a2002290300370300200141086a41106a200c290300370300200141086a41186a200d280200360200200120012f01443b012420012001290328370308200f210b0b200141e8006a41026a2202200141246a41026a2d00003a0000200141c8006a41086a220c200141086a41086a290300370300200141c8006a41106a220d200141086a41106a290300370300200141c8006a41186a220f200141086a41186a280200360200200120012f01243b01682001200129030837034802400240024020062005460d0020072d00000e03020102010b2006411041ecc8c4800010f980808000000b200741046a280200221010848a808000201041002802c0a3c68000118080808000000b2007200b3a0000200741016a20012f01683b0000200741046a200e360200200741086a2001290348370200200741036a20022d00003a0000200741106a200c290300370200200741186a200d290300370200200741206a200f2802003602002000200541016a2205360208200741246a2107200a2102200a2003470d000c020b0b024020042802002207450d000240024002400240200728020041fcffffff076a2202410320024105491b0e0403030102000b2007280204450d02200741086a28020041002802c0a3c68000118080808000000c020b2007280204450d01200741086a28020041002802c0a3c68000118080808000000c010b200710858a8080000b200741002802c0a3c68000118080808000000b2004200e3602002000200541016a3602080b20014190016a2480808080000bab0201027f23808080800041306b22012480808080004100210202400240024020002d0000410b470d002001410c6a200041086a2802002000410c6a280200108b8a80800020012d000c0d0041002d00fca3c680001a410c41002802c8a3c68000118180808000002202450d0241002d00fca3c680001a412041002802c8a3c68000118180808000002200450d012000200129000d370000200041186a200141256a290000370000200041106a2001411d6a290000370000200041086a200141156a290000370000200241203602002002412036020820022000360204200041002802c0a3c6800011808080800000200241002802c0a3c6800011808080800000410221020b200141306a24808080800020020f0b4101412010b280808000000b4104410c10b280808000000b950301027f23808080800041e0006b22032480808080002003412b6a10ef88808000024002400240024020032d002b22044102460d002003410a6a410a6a2003412b6a410a6a2900003700002003410a6a41126a2003412b6a41126a2900003700002003410a6a41196a2003412b6a41196a2900003700002003200329002d37000c200320032d002c3a000b2003412b6a200120024100280298a3c680001185808080000002402003412b6a2003410b6a412010888e808000450d00200041046a410910dc888080000c030b2004450d01200341cc006a2001200210978a80800020032d004c2202410e460d01200041056a200329004d370000200041146a200341dc006a2800003600002000410d6a200341d5006a290000370000200020023a00040c020b200041046a410810dc88808000200041013a00000c020b2000200329002b370001200041003a0000200041196a200341c3006a290000370000200041116a2003413b6a290000370000200041096a200341336a2900003700000c010b200041013a00000b200341e0006a2480808080000b980601027f23808080800041306b2201248080808000200141106a41186a42c58a95aad4a8d1a2c500370300200141106a41106a42c58a95aad4a8d1a2c500370300200141106a41086a42c58a95aad4a8d1a2c500370300200142c58a95aad4a8d1a2c5003703104200200141106a10fd87808000200142fc90b9e5d09296e777370318200142a6d4e6f1a4dd959860370310200142bb88f596f8cbf6cf4c3703282001428a85cd9fb3e4b2ae6d37032041002d00fca3c680001a02400240412041002802c8a3c68000118180808000002202450d00200242c58a95aad4a8d1a2c500370000200241186a42c58a95aad4a8d1a2c500370000200241106a42c58a95aad4a8d1a2c500370000200241086a42c58a95aad4a8d1a2c500370000200141106a41202002412041002802e0a1c6800011868080800000200241002802c0a3c6800011808080800000200142003702082001418097c380003602042001418080808078360200200142fc90b9e5d09296e777370318200142a6d4e6f1a4dd959860370310200142a0b9ab8f9ae5999778370328200142f999a7c78cd1d1cdb17f3703202001200141106a4120109288808000024020012802002202418080808078460d002002450d00200128020441002802c0a3c68000118080808000000b200142fc90b9e5d09296e777370318200142a6d4e6f1a4dd959860370310200142a2f5bea594dedcdb10370328200142d6888295b2b493ecbf7f370320200141013a0000200141106a41202001410141002802e0a1c6800011868080800000200142fc90b9e5d09296e777370318200142a6d4e6f1a4dd959860370310200142d2daa4a6928283fa39370328200142a7fbb3c3b2f09acd28370320200141013a0000200141106a41202001410141002802e0a1c680001186808080000041002d00fca3c680001a410441002802c8a3c68000118180808000002202450d012002410036000041e6aac4800041102002410441002802e0a1c6800011868080800000200241002802c0a3c6800011808080800000200141306a2480808080000f0b4101412010b280808000000b4101410410b280808000000b9d0202017f037e23808080800041f0006b2201248080808000024020002903002202500d0020014298d5afd2c6aeacae2f370318200142c2cdc8b0c7b9e78f857f370310200142e4c5bdb4b2e9a5a6807f370328200142d790d7a3fef9fda0c8003703202001200141106a10e688808000200129030821032001280200210020014298d5afd2c6aeacae2f370318200142c2cdc8b0c7b9e78f857f370310200142e4c5bdb4b2e9a5a6807f370328200142d790d7a3fef9fda0c800370320200142002003420020001b220320027d220420042003561b370368200141106a4120200141e8006a410841002802e0a1c6800011868080800000200141103a001020012002370318200141106a108e8a8080000b200141f0006a2480808080000baa0401047f23808080800041c0016b2201248080808000200142fc90b9e5d09296e777370328200142a6d4e6f1a4dd959860370320200142d3d8c5d2a9b9d2c1ac7f37033820014282ca868eabf3add0cf00370330200141106a200141206a10e68880800002402001280210450d002001290318500d00200141086a10ec88808000200128020c210220012802082103200142fc90b9e5d09296e777370328200142a6d4e6f1a4dd959860370320200142b7aeb183f6f8ab9cd0003703382001428ab0f6f7cbd3f9e2d8003703302001200141206a412010d0888080002001280204410020012802001b41016a2204450d00200142fc90b9e5d09296e777370328200142a6d4e6f1a4dd959860370320200142b7aeb183f6f8ab9cd0003703382001428ab0f6f7cbd3f9e2d8003703302001200436029001200141206a412020014190016a410441002802e0a1c68000118680808000002001200236022420014102200320034103461b360220200141286a200041d00010848e8080001a20014100360280012001428080808010370378200142fc90b9e5d09296e77737039801200142a6d4e6f1a4dd95986037039001200142bc8986ab88c2dce4573703a80120014280a9fbf0e5a2c1b3e5003703a001200141b4016a200141206a10968880800020014190016a4120200141b4016a4100280298a1c68000118580808000002001280278450d00200128027c41002802c0a3c68000118080808000000b200141c0016a2480808080000b9d0202017f037e23808080800041f0006b2201248080808000024020002903002202500d0020014298d5afd2c6aeacae2f370318200142c2cdc8b0c7b9e78f857f370310200142e4c5bdb4b2e9a5a6807f370328200142d790d7a3fef9fda0c8003703202001200141106a10e688808000200129030821032001280200210020014298d5afd2c6aeacae2f370318200142c2cdc8b0c7b9e78f857f370310200142e4c5bdb4b2e9a5a6807f370328200142d790d7a3fef9fda0c8003703202001427f2003420020001b220320027c220420042003541b370368200141106a4120200141e8006a410841002802e0a1c68000118680808000002001410f3a001020012002370318200141106a108e8a8080000b200141f0006a2480808080000bda0e01097f23808080800041c0006b220624808080800002400240024002400240200541057441286a412820041b2204417f4c0d004100210741002d00fca3c680001a200441002802c8a3c68000118180808000002205450d012006410036020c200620053602082006200436020402402004411f4b0d00200641046a4100412010ab868080002006280204210420062802082105200628020c21070b200520076a22082001290000370000200841186a200141186a290000370000200841106a200141106a290000370000200841086a200141086a2900003700002006200741206a220136020c0240200420016b41074b0d00200641046a2001410810ab8680800020062802082105200628020c21010b200520016a20023700002006200141086a220936020c2003280228210a2003280224210b2003280220210c2003280218210520032802102104200328020c2101200328021c210d2003280214210802402003280200450d002003280208210e2003280204210303402003200e2003200e4b1b210702400240034002402001450d00024020042005460d00200641106a41186a200441186a290000370300200641106a41106a200441106a290000370300200641106a41086a200441086a29000037030020062004290000370310200441206a21040c040b2008450d00200141002802c0a3c68000118080808000000b024020072003470d00200721030c020b2006200336023c200641306a2006413c6a10fc87808000024020062802302201418080808078460d00200341016a21032006280234220420062802384105746a210520012108200421010c010b0b200341016a21030b200d450d07200c200a460d06200641106a41186a200c41186a290000370300200641106a41106a200c41106a290000370300200641106a41086a200c41086a2900003703002006200c290000370310200c41206a210c410021010b0240200628020420096b411f4b0d00200641046a2009412010ab86808000200628020c21090b200628020820096a22072006290310370000200741086a200641106a41086a290300370000200741106a200641106a41106a290300370000200741186a200641106a41186a2903003700002006200941206a220936020c0c000b0b0240200d0d002001450d05024020042005460d000340200641106a41186a2207200441186a290000370300200641106a41106a220c200441106a290000370300200641106a41086a220e200441086a290000370300200620042900003703100240200628020420096b41204f0d00200641046a2009412010ab86808000200628020c21090b200628020820096a22032006290310370000200341086a200e290300370000200341106a200c290300370000200341186a20072903003700002006200941206a220936020c200441206a22042005470d000b0b2008450d05200141002802c0a3c68000118080808000000c050b2008450d0203400240024002402001450d0020042005470d01200141002802c0a3c68000118080808000000b200c200a460d06200641106a41186a200c41186a290000370300200641106a41106a200c41106a290000370300200641106a41086a200c41086a2900003703002006200c290000370310200c41206a210c410021010c010b200641106a41186a200441186a290000370300200641106a41106a200441106a290000370300200641106a41086a200441086a29000037030020062004290000370310200441206a21040b0240200628020420096b411f4b0d00200641046a2009412010ab86808000200628020c21090b200628020820096a22032006290310370000200341086a200641106a41086a290300370000200341106a200641106a41106a290300370000200341186a200641106a41186a2903003700002006200941206a220936020c0c000b0b10ae80808000000b4101200410b280808000000b0240024020010d00410121030c010b410021030b03400240024002400240024020030e020001010b20042005470d010c030b200c200a460d04200641106a41186a200c41186a290000370300200641106a41106a200c41106a290000370300200641106a41086a200c41086a2900003703002006200c290000370310200c41206a210c410021010c010b200641106a41186a200441186a290000370300200641106a41106a200441106a290000370300200641106a41086a200441086a29000037030020062004290000370310200441206a21040b0240200628020420096b411f4b0d00200641046a2009412010ab86808000200628020c21090b200628020820096a22032006290310370000200341086a200641106a41086a290300370000200341106a200641106a41106a290300370000200341186a200641106a41186a2903003700002006200941206a220936020c2001450d00410021030c010b410121030c000b0b200b450d00200d41002802c0a3c68000118080808000000b20002006280208220320094100280298a3c680001185808080000002402006280204450d00200341002802c0a3c68000118080808000000b200641c0006a2480808080000b840a01047f23808080800041e0006b220124808080800002400240417f4100280284a4c680002202410447200241044b1b2202417f460d00200241ff01710d010b200141e08180800036021020014106360218200141f9a6c480003602142001200141146a36020c4100280290a1c680002102410028028ca1c6800021034100280280a4c680002104200141d4006a4201370200200141cc006a4101360200200141c4006a4116360200200141c0006a41bcaac48000360200200141346a4195a8c48000ad4280808080b00b84370200200141286a41d2aac48000ad4280808080c00284370200200141d0006a2001410c6a360200200141b4aac480003602482001410436023c200141003602302001410036022420014281808080c02037021c200341ecf2c08000200441024622041b2001411c6a200241d4f2c0800020041b280210118480808000000b02400240417f4100280284a4c680002202410447200241044b1b2202417f460d00200241ff01710d010b200141e08180800036021020014104360218200141f5a6c480003602142001200141146a36020c4100280290a1c680002102410028028ca1c6800021034100280280a4c680002104200141d4006a4201370200200141cc006a4101360200200141c4006a4116360200200141c0006a41c1e5c28000360200200141346a41e8e4c28000ad4280808080900b84370200200141286a41d7e5c28000ad4280808080b00284370200200141d0006a2001410c6a360200200141e0e4c280003602482001410436023c200141003602302001410036022420014281808080800e37021c200341ecf2c08000200441024622041b2001411c6a200241d4f2c0800020041b280210118480808000000b02400240417f4100280284a4c680002202410447200241044b1b2202417f460d00200241ff01710d010b200141e0818080003602102001410d360218200141e8a6c480003602142001200141146a36020c4100280290a1c680002102410028028ca1c6800021034100280280a4c680002104200141d4006a4201370200200141cc006a4101360200200141c4006a4116360200200141c0006a418cabc38000360200200141346a41c0a7c38000ad4280808080b00e84370200200141286a41b9a9c38000ad4280808080d00684370200200141d0006a2001410c6a360200200141b8abc380003602482001410436023c200141003602302001410036022420014281808080e00437021c200341ecf2c08000200441024622041b2001411c6a200241d4f2c0800020041b280210118480808000000b02400240417f4100280284a4c680002202410447200241044b1b2202417f460d00200241ff01710d010b200141e08180800036021020014108360218200141e0a6c480003602142001200141146a36020c4100280290a1c680002102410028028ca1c6800021034100280280a4c680002104200141d4006a4201370200200141cc006a4101360200200141c4006a4116360200200141c0006a41d4d8c58000360200200141346a41b8d6c58000ad4280808080d00b84370200200141286a41ead8c58000ad4280808080f00284370200200141d0006a2001410c6a360200200141ccd8c580003602482001410436023c200141003602302001410036022420014281808080a01837021c200341ecf2c08000200441024622041b2001411c6a200241d4f2c0800020041b280210118480808000000b2000420037030820004200370300200141e0006a2480808080000bcd0401077f23808080800041c0006b2200248080808000200041206a41f9a6c48000410641002802a0a3c6800011858080800000200041206a41106a220141bccdc48000411541002802a0a3c6800011858080800000200041186a2202200041206a41186a2203290000370300200041106a22042001290000370300200041086a2205200041206a41086a220629000037030020002000290020370300200041003b012020004120200041206a410241002802e0a1c6800011868080800000200041206a41f5a6c48000410441002802a0a3c6800011858080800000200141bccdc48000411541002802a0a3c680001185808080000020022003290000370300200420012900003703002005200629000037030020002000290020370300200041003b012020004120200041206a410241002802e0a1c6800011868080800000200041206a41e8a6c48000410d41002802a0a3c6800011858080800000200141bccdc48000411541002802a0a3c680001185808080000020022003290000370300200420012900003703002005200629000037030020002000290020370300200041003b012020004120200041206a410241002802e0a1c6800011868080800000200041206a41e0a6c48000410841002802a0a3c6800011858080800000200141bccdc48000411541002802a0a3c680001185808080000020022003290000370300200420012900003703002005200629000037030020002000290020370300200041013b012020004120200041206a410241002802e0a1c6800011868080800000200041c0006a2480808080000b8e1008017f087e017f037e017f027e037f027e23808080800041e0016b2204248080808000200441086a200110fa8780800042002105200441186a290300210620032903002107200441306a2903002108200441286a29030021092004290310210a02400240200441206a290300220b4200520d0020094200520d0020084200520d00200a2006428080808080808080807f858450450d00428080808080808080807f210c4100210d4201210e4200210f42002110410021110c010b200b42ffffe883b1de1656210d4200210e410121110240024020094200510d00200a21052006210c2009210f0c010b4200210e2008420052211142002109200a21052006210c4200210f0b200821100b0240200b200f2007200f2007541b22127c2213200b5a0d0002400240417f4100280284a4c680002203410147200341014b1b2203450d00200341ff017141ff01470d010b200441e081808000360274200441b4f9c580003602704100280290a1c680002103410028028ca1c6800021144100280280a4c680002115200441d0016a4201370200200441c8016a4101360200200441c0016a4112360200200441bc016a41bcf9c58000360200200441b0016a41cef9c58000ad4280808080c00c84370200200441a4016a41b2fac58000ad4280808080b00384370200200441cc016a200441f0006a360200200441b4f8c580003602c401200441013602b801200441003602ac01200441003602a00120044281808080b01b37029801201441ecf2c08000201541024622151b20044198016a200341d4f2c0800020151b280210118480808000000b427f200b20127c22132013200b541b21130b200f2007582010507121030240200d417f73201342ffffe883b1de165671450d00200220021084888080001a0b02400240024002400240024002400240201141004722142003710d0002402014200372450d0020030d040c020b20044198016a200210f68780800020042d0098012214410e460d01200435019a012004419e016a33010042208684210b0c020b20021083888080000c020b20044198016a200210fa8780800020042802c8010d0102400240417f4100280284a4c680002214410147201441014b1b2214450d00201441ff017141ff01470d010b4100280290a1c680002114410028028ca1c6800021154100280280a4c680002116200441d0016a4200370200200441cc016a419cadc48000360200200441c8016a4101360200200441c0016a4111360200200441bc016a41c1c7c48000360200200441b0016a41e4c6c48000ad4280808080d00b84370200200441a4016a41d2c7c48000ad4280808080f00284370200200441dcc6c480003602c401200441013602b801200441003602ac01200441003602a00120044281808080d0800137029801201541ecf2c08000201641024622161b20044198016a201441d4f2c0800020161b280210118480808000000b20044198016a200210f68780800020042d0098012214410e460d01200435019a012004419e016a33010042208684210b0b20042802a801210220042902a001211320042d00990121010c010b200d2013428080e983b1de165471450d01200441c8006a2002200210f78780800020042d00482214410e460d01024002402011450d002003450d01200441dc006a200210f68780800020042d005c410e460d01200441f0006a41106a200441dc006a41106a280200360200200441f0006a41086a200441dc006a41086a2902003703002004200429025c3703700240417f4100280284a4c680002202410147200241014b1b2202450d00200241ff017141ff01470d020b20044188016a410c6a41ca83808000360200200441e08180800036028c012004418c98c38000360288012004200441f0006a360290014100280290a1c680002102410028028ca1c6800021014100280280a4c680002103200441d0016a4202370200200441c8016a4102360200200441c0016a4112360200200441bc016a419498c38000360200200441b0016a41a698c38000ad4280808080c00c8437020020044198016a410c6a418a99c38000ad4280808080b00384370200200441cc016a20044188016a3602002004418497c380003602c401200441013602b801200441003602ac01200441003602a00120044281808080e02437029801200141ecf2c08000200341024622031b20044198016a200241d4f2c0800020031b280210118480808000000c010b20030d0020021083888080000b200435014a200441ce006a33010042208684210b200428025821022004290250211320042d004921010b20004202370300200041186a2002360200200041106a20133703002000200b4210862001ad42ff0183420886842014ad843703080c010b0240024002400240201342ffffe883b1de16560d00200f2007580d010b200f20127d21094200211742012118201342808097fccea1697c42818097fccea1695a0d012013210b0c020b420021182013420052ad211720082110200a21052006210c0c010b2013210b200f2007580d020b20044198016a200110fa878080002013422088a721022013a721030240024020042802cc010d0020044198016a200110fa8780800020042802d0010d0020011086888080000c010b200441a8016a200c370300200420053703a001200420103703c001200420093703b8012004200b3703b0012004201837039801200120044198016a1082888080000b200020123703202000200236021c2000200336021820002017370310200020133703082000200e3703000b200441e0016a2480808080000f0b41e9c7c4800041dd0041c8c8c4800010f880808000000baa0f08017f077e017f037e017f027e057f017e2380808080004190026b2203248080808000200341086a200110fa8780800042002104200341186a2903002105200341306a2903002106200341286a29030021072003290310210802400240200341206a29030022094200520d0020074200520d0020064200520d0020082005428080808080808080807f858450450d00428080808080808080807f210a4100210b4201210c4200210d4200210e4100210f0c010b200942ffffe883b1de1656210b4200210c4101210f0240024020074200510d00200821042005210a2007210d0c010b4200210c2006420052210f42002107200821042005210a4200210d0b2006210e0b0240024042002009200228020429030022107d221120112009561b200241086a280200290300580d00200341c8016a410310f888808000200921100c010b2003410e3a00c8010b200341e0006a41106a200341c8016a41106a280200360200200341e0006a41086a200341c8016a41086a290200370300200320032902c801370360200d200e845021120240200b417f73201042ffffe883b1de165671450d002002280200221320131084888080001a0b02400240024002400240024002400240200f41004722132012710d0002402013201272450d0020120d04200228020021140c020b200341c8016a2002280200221410f68780800020032d00c8012213410e460d0120033501ca01200341ce016a3301004220868421090c020b20022802001083888080000c020b200341c8016a201410fa8780800020032802f8010d0102400240417f4100280284a4c680002213410147201341014b1b2213450d00201341ff017141ff01470d010b4100280290a1c680002113410028028ca1c6800021154100280280a4c68000211620034180026a4200370200200341fc016a419cadc48000360200200341f8016a4101360200200341f0016a4111360200200341ec016a41c1c7c48000360200200341e0016a41e4c6c48000ad4280808080d00b84370200200341d4016a41d2c7c48000ad4280808080f00284370200200341dcc6c480003602f401200341013602e801200341003602dc01200341003602d00120034281808080d080013702c801201541ecf2c08000201641024622161b200341c8016a201341d4f2c0800020161b280210118480808000000b200341c8016a201410f68780800020032d00c8012213410e460d0120033501ca01200341ce016a3301004220868421090b20032802d801210220032902d001211020032d00c90121010c010b200b2010428080e983b1de165471450d01200341f8006a20022802002202200210f78780800020032d00782213410e460d0102400240200f450d002012450d012003418c016a200210f68780800020032d008c01410e460d01200341a0016a41106a2003418c016a41106a280200360200200341a0016a41086a2003418c016a41086a2902003703002003200329028c013703a0010240417f4100280284a4c680002202410147200241014b1b2202450d00200241ff017141ff01470d020b200341b8016a410c6a41ca83808000360200200341e0818080003602bc012003418c98c380003602b8012003200341a0016a3602c0014100280290a1c680002102410028028ca1c6800021014100280280a4c68000211220034180026a4202370200200341f8016a4102360200200341f0016a4112360200200341ec016a419498c38000360200200341e0016a41a698c38000ad4280808080c00c84370200200341c8016a410c6a418a99c38000ad4280808080b00384370200200341fc016a200341b8016a3602002003418497c380003602f401200341013602e801200341003602dc01200341003602d00120034281808080e0243702c801200141ecf2c08000201241024622121b200341c8016a200241d4f2c0800020121b280210118480808000000c010b20120d0020021083888080000b200335017a200341fe006a3301004220868421092003280288012102200329028001211020032d007921010b20004202370300200041186a2002360200200041106a2010370300200020094210862001ad42ff0183420886842013ad843703080c010b0240024002400240201042ffffe883b1de16560d0042002111200d4200510d010b4200211742012111201042808097fccea1697c42818097fccea1695a0d01201021090c020b2010420052ad21172006210e2007210d200821042005210a0c010b20102109200d4200510d020b200341c8006a41106a200341e0006a41106a280200360200200341c8006a41086a200341e0006a41086a29030037030020032003290360370348200341c8016a200110fa878080002010422088a721022010a721120240024020032802fc010d00200341c8016a200110fa878080002003280280020d0020011086888080000c010b200341c8016a41106a200a370300200320043703d0012003200e3703f0012003200d3703e801200320093703e001200320113703c8012001200341c8016a1082888080000b2000200236021c2000201236021820002017370310200020103703082000200c37030020002003290348370320200041286a200341d0006a290300370300200041306a200341d8006a2802003602000b20034190026a2480808080000f0b41e9c7c4800041dd0041c8c8c4800010f880808000000b9e0d06017f087e017f027e057f037e23808080800041e0016b2204248080808000200441086a200110fa8780800042002105200441186a290300210620032903002107200441306a2903002108200441286a29030021092004290310210a024002400240200441206a290300220b4200520d0020094200520d0020084200520d00200a2006428080808080808080807f858450450d00428080808080808080807f210c4100210d4200210e4200210f410021030c010b200b42ffffe883b1de1656210d024020094200510d004101211042012105410121032008210f200a210e2006210c410121110c020b2008420052210342012105200a210e2006210c2008210f0b42002109200f4200522111410021100b02402007428080e983b1de16540d00200d0d00200220021084888080001a0b024002400240024002400240024002402003450d002011450d010b0240024020030d0020110d010b2011450d040c020b20044198016a200210f68780800020042d0098012212410e460d01200435019a012004419e016a3301004220868421070c020b20021083888080000c020b20044198016a200210fa8780800020042802c8010d0102400240417f4100280284a4c680002212410147201241014b1b2212450d00201241ff017141ff01470d010b4100280290a1c680002112410028028ca1c6800021134100280280a4c680002114200441d0016a4200370200200441cc016a419cadc48000360200200441c8016a4101360200200441c0016a4111360200200441bc016a41c1c7c48000360200200441b0016a41e4c6c48000ad4280808080d00b84370200200441a4016a41d2c7c48000ad4280808080f00284370200200441dcc6c480003602c401200441013602b801200441003602ac01200441003602a00120044281808080d0800137029801201341ecf2c08000201441024622141b20044198016a201241d4f2c0800020141b280210118480808000000b20044198016a200210f68780800020042d0098012212410e460d01200435019a012004419e016a3301004220868421070b20042802a801210220042902a001210920042d00990121010c010b2007428080e983b1de1654200d71450d01200441c8006a2002200210f78780800020042d00482212410e460d01024002402003450d0020110d01200441dc006a200210f68780800020042d005c410e460d01200441f0006a41106a200441dc006a41106a280200360200200441f0006a41086a200441dc006a41086a2902003703002004200429025c3703700240417f4100280284a4c680002202410147200241014b1b2202450d00200241ff017141ff01470d020b20044188016a410c6a41ca83808000360200200441e08180800036028c012004418c98c38000360288012004200441f0006a360290014100280290a1c680002102410028028ca1c6800021014100280280a4c680002103200441d0016a4202370200200441c8016a4102360200200441c0016a4112360200200441bc016a419498c38000360200200441b0016a41a698c38000ad4280808080c00c8437020020044198016a410c6a418a99c38000ad4280808080b00384370200200441cc016a20044188016a3602002004418497c380003602c401200441013602b801200441003602ac01200441003602a00120044281808080e02437029801200141ecf2c08000200341024622031b20044198016a200241d4f2c0800020031b280210118480808000000c010b2011450d0020021083888080000b200435014a200441ce006a330100422086842107200428025821022004290250210920042d004921010b20004202370300200041186a2002360200200041106a2009370300200020074210862001ad42ff0183420886842012ad843703080c010b02400240200742ffffe883b1de1656201072450d00420021152007211642012117200742808097fccea1697c42818097fccea169542010720d0141e9c7c4800041dd0041c8c8c4800010f880808000000b420021172007420052ad21152008210f200b2116200a210e2006210c0b2005420185210820044198016a200110fa878080002007422088a721022007a721030240024020042802cc010d0020044198016a200110fa8780800020042802d0010d0020011086888080000c010b200441a8016a200c3703002004200e3703a0012004200f3703c001200420093703b801200420163703b0012004201737039801200120044198016a1082888080000b2000200b3703202000200236021c200020033602182000201537031020002007370308200020083703000b200441e0016a2480808080000ba20602017f017e23808080800041d0006b220324808080800020034102360208200342fc90b9e5d09296e777370338200342a6d4e6f1a4dd95986037033020034293bb8a9cbb9ab6b31a370348200342ffabedd185d3d8d216370340200341086a200341306a41201094888080002003410036023041e6aac480004110200341306a410441002802e0a1c680001186808080000020032001360234200341f0acc48000360230200341086a200341306a1083898080004188adc480004113200341086a412041002802e0a1c6800011868080800000200342fc90b9e5d09296e777370338200342a6d4e6f1a4dd959860370330200342d3d8c5d2a9b9d2c1ac7f37034820034282ca868eabf3add0cf00370340200320002903002204370328200341306a4120200341286a410841002802e0a1c6800011868080800000200342fc90b9e5d09296e777370338200342a6d4e6f1a4dd959860370330200342f4fa97f89782c7a62d37034820034299cfe7ffe3b8eac70837034020022802042002280208200341306a4120108a8d80800041002d00fca3c680001a200342fc90b9e5d09296e777370338200342a6d4e6f1a4dd959860370330200342bb88f596f8cbf6cf4c3703482003428a85cd9fb3e4b2ae6d3703400240412041002802c8a3c680001181808080000022020d004101412010b280808000000b20022001290000370000200241186a200141186a290000370000200241106a200141106a290000370000200241086a200141086a290000370000200341306a41202002412041002802e0a1c6800011868080800000200241002802c0a3c68000118080808000002004427f7c200110fd87808000200342fc90b9e5d09296e777370338200342a6d4e6f1a4dd959860370330200342beee8ae9ce8fa2b1977f37034820034295d4f9afa2868fb864370340200341306a412041002802a0a1c6800011848080800000200342fc90b9e5d09296e777370338200342a6d4e6f1a4dd959860370330200342f89aef8eef91e1ce967f370348200342b4d6d6dfccc6b592c300370340200341306a412041002802a0a1c6800011848080800000200341d0006a2480808080000baa04010a7f23808080800041d0006b220324808080800041002104200341046a200120024100280288a3c68000118580808000000240024020032802042202418080808078460d00200328020821012003200328020c36024c20032001360248200341106a200341c8006a4100200310df8c8080000240024020032802102205418180808078470d00410021060c010b200341176a2d000041187420032f001541087472210420032d0014210620032802382107200328022c2108200328022821092003280220210a200328021c210b2003280218210c0b02402002450d00200141002802c0a3c68000118080808000000b2005418180808078460d00200620047221014101210202400240200c0d0020070d01410221020b2000200210dc888080000240200541808080807872418080808078460d00200141002802c0a3c68000118080808000000b0240200b41808080807872418080808078460d00200a41002802c0a3c68000118080808000000b200941808080807872418080808078460d02200841002802c0a3c68000118080808000000c020b2000410e3a00000240200541808080807872418080808078460d00200141002802c0a3c68000118080808000000b0240200b41808080807872418080808078460d00200a41002802c0a3c68000118080808000000b200941808080807872418080808078460d01200841002802c0a3c68000118080808000000c010b2000410310dc888080000b200341d0006a2480808080000b800401027f23808080800041d0006b2200248080808000200042fc90b9e5d09296e777370338200042a6d4e6f1a4dd959860370330200042bc8986ab88c2dce45737034820004280a9fbf0e5a2c1b3e500370340200041306a412041002802a0a1c6800011848080800000200042fc90b9e5d09296e777370338200042a6d4e6f1a4dd959860370330200042b7aeb183f6f8ab9cd0003703482000428ab0f6f7cbd3f9e2d800370340200041306a412041002802a0a1c6800011848080800000200041306a41f9a6c48000410641002802a0a3c6800011858080800000200041306a41106a220141c99ec38000410b41002802a0a3c6800011858080800000200041106a41186a200041306a41186a290000370300200041106a41106a2001290000370300200041106a41086a200041306a41086a29000037030020002000290030370310200041086a200041106a41204101417f41002802a8a1c6800011878080800000024002402000280208450d0041002d00fca3c680001a412041002802c8a3c68000118180808000002201450d0120012000290310370000200141186a200041106a41186a290300370000200141106a200041106a41106a290300370000200141086a200041106a41086a290300370000200141002802c0a3c68000118080808000000b200041d0006a2480808080000f0b4101412010b280808000000bc10904017f017e027f037e23808080800041a0036b2202248080808000200041086a20002000290300220342025122041b210502400240200020044103746a290300500d00200541106a29030022062001290308220720062007541b2106200529030822072001290300220820072008541b21070c010b20012903082106200129030021070b200241206a10e189808000200241206a210402400240024020012d00100e03020001020b200241f8006a21040c010b200241d0016a21040b2001427f200720042903487c220820082007541b3703002001427f2006200441d0006a2903007c220720072006541b37030841012104024020012d00110d0020052d001841004721040b200120043a00110240024020034202520d0020024183036a200141106a290000370000200241fb026a200141086a290000370000200220012900003700f302410021010c010b2002200036029c0302404100280284a4c680004105470d00200242fc90b9e5d09296e777370328200242a6d4e6f1a4dd959860370320200242d3d8c5d2a9b9d2c1ac7f37033820024282ca868eabf3add0cf00370330200241106a200241206a10e688808000200241ec026a410c6a41cb83808000360200200241cc838080003602f00220022002290318420020022802101b3703d00220022002419c036a3602f4022002200241d0026a3602ec024100280290a1c680002100410028028ca1c6800021044100280280a4c680002105200241d8006a4202370200200241d0006a4102360200200241c8006a410f360200200241c4006a41ccadc48000360200200241386a4195a8c48000ad4280808080b00b84370200200241206a410c6a41dbadc48000ad4280808080c00184370200200241d4006a200241ec026a360200200241bcadc4800036024c20024105360240200241003602342002410036022820024281808080e0fd01370220200441ecf2c08000200541024622051b200241206a200041d4f2c0800020051b28021011848080800000200228029c0321000b200241ff026a200041306a280000360000200241f7026a200041286a2900003700002002418b036a200141086a29000037000020024193036a200141106a290000370000200220002900203700ef022002200129000037008303410121010b200241296a20022900ec02370000200241d8006a20022903d002370300200241316a200241ec026a41086a290000370000200241396a200241ec026a41106a290000370000200241c1006a20024184036a290000370000200241c9006a200241ec026a41206a290000370000200241d0006a20024193036a290000370000200241e0006a200241d0026a41086a290300370300200241e8006a200241d0026a41106a290300370300200220013a0028200241163a0020200241206a108e8a808000200241086a41e6aac48000411010d0888080002002200228020c41016a410120022802081b220136022041e6aac480004110200241206a410441002802e0a1c6800011868080800000200220013602f002200241003602ec02200242fc90b9e5d09296e777370328200242a6d4e6f1a4dd95986037032020024293bb8a9cbb9ab6b31a370338200242ffabedd185d3d8d216370330200241ec026a200241206a4120109488808000200241a0036a2480808080000bf10202027f017e2380808080004180016b220224808080800002400240024002400240200128021c22034110710d0020034120710d0120002903004101200110fe8080800021000c020b20002903002104410021000340200220006a41ff006a413041d7002004a7410f712203410a491b20036a3a00002000417f6a210020044210542103200442048821042003450d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000c010b20002903002104410021000340200220006a41ff006a413041372004a7410f712203410a491b20036a3a00002000417f6a210020044210542103200442048821042003450d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000b20024180016a24808080800020000f0b200341800141c88dc08000109481808000000b200341800141c88dc08000109481808000000b9a0201037f23808080800041306b2200248080808000200041e6aac48000411010d088808000200028020421010240200028020022024101470d0041e6aac48000411041002802a0a1c68000118480808000000b200042fc90b9e5d09296e777370318200042a6d4e6f1a4dd959860370310200042bad08eede089ffa812370328200042bd81f785e387e6aa817f37032020002001410020021b360208200041106a4120200041086a410441002802e0a1c680001186808080000020004101360208200042fc90b9e5d09296e777370318200042a6d4e6f1a4dd95986037031020004293bb8a9cbb9ab6b31a370328200042ffabedd185d3d8d216370320200041086a200041106a4120109488808000200041306a2480808080000bad0302037f027e23808080800041d0026b2202248080808000200241206a2001280204220320012802082204108b8a8080000240024020022d00200d002001280200210141e7adc4800041052003200441002802e0a1c6800011868080800000200241043a0020200241206a10f588808000200241163a0020200241023a0028200241206a108e8a80800002402001450d00200341002802c0a3c68000118080808000000b200242fc90b9e5d09296e777370328200242a6d4e6f1a4dd959860370320200242f7b6fccfd083b2cf4d370338200242afd2c6ffdbc495bc08370330200241206a412041002802a0a1c6800011848080800000200241206a10e189808000200241c0026a290300210520022903b8022106200041013a00182000200537031020002006370308200042013703000c010b200241136a200241346a28020022043600002002410b6a2002412c6a2902002205370000200220022902242206370003200041186a2004360000200041106a200537000020002006370008200042023703002001280200450d00200341002802c0a3c68000118080808000000b200241d0026a2480808080000b931a03047f027e027f23808080800041a00d6b220124808080800002400240417f4100280284a4c680002202410447200241044b1b2202450d00200241ff017141ff01470d010b200142fc90b9e5d09296e7773703d809200142a6d4e6f1a4dd9598603703d009200142d3d8c5d2a9b9d2c1ac7f3703e80920014282ca868eabf3add0cf003703e009200141a8016a200141d0096a10e688808000200120012903b001420020012802a8011b37039802200142fc90b9e5d09296e7773703d809200142a6d4e6f1a4dd9598603703d009200142bad08eede089ffa8123703e809200142bd81f785e387e6aa817f3703e009200141a0016a200141d0096a412010d088808000200120012802a401410020012802a0011b3602a002200142fc90b9e5d09296e7773703d809200142a6d4e6f1a4dd9598603703d00920014295f38cfcb699a3c4ef003703e809200142a8db95cdaa86daa7193703e00920014198016a200141d0096a412010d0888080002001200128029c0141002001280298011b3602a402200142fc90b9e5d09296e7773703d809200142a6d4e6f1a4dd9598603703d00920014295f38cfcb699a3c4ef003703e809200142a8db95cdaa86daa7193703e00920014190016a200141d0096a412010d08880800041e400210241e4002103024020012802940141002001280290011b2204418080f0014b0d00200441e4006c418080f0016e21030b200120033a00a902200142fc90b9e5d09296e7773703d809200142a6d4e6f1a4dd9598603703d00920014295f38cfcb699a3c4ef003703e809200142a8db95cdaa86daa7193703e00920014188016a200141d0096a412010d0888080000240200128028c0141002001280288011b2203418080c0024b0d00200341e4006c418080c0026e21020b200120023a00aa02200142fc90b9e5d09296e7773703d809200142a6d4e6f1a4dd9598603703d00920014295f38cfcb699a3c4ef003703e809200142a8db95cdaa86daa7193703e00920014180016a200141d0096a412010d08880800041e4002102024020012802840141002001280280011b2203418080c0024b0d00200341e4006c418080c0026e21020b200120023a00ab02200141b0026a10ce888080002001200141b0026a3602ac02200141e8026a10ce8880800020012903e802210520014198036a10e1898080000240024020014198036a41206a290300427f20012802b0031b2206500d0020052006560d00200141f0006a2005420042e400420010878e808000200141e0006a2001290370200141f0006a41086a2903002006420010898e80800020012903602205428002544100200141e0006a41086a290300501b450d002005a721020c010b41e40021020b200120023a00e702200141c8056a10ce888080002001200141d8056a3602c40520014180066a10ce888080002001290390062105200141b0066a10e18980800002400240200141a8076a290300427f200141a0076a2802001b2206500d0020052006560d00200141d0006a2005420042e400420010878e808000200141c0006a2001290350200141d0006a41086a2903002006420010898e80800020012903402205428002544100200141c0006a41086a290300501b450d002005a721020c010b41e40021020b200120023a00ff05200141e8086a10ce88808000200120014188096a3602e408200141a0096a10ce8880800020012903c0092105200141d0096a10e18980800002400240200141a00b6a290300427f200141980b6a2802001b2206500d0020052006560d00200141306a2005420042e400420010878e808000200141206a2001290330200141306a41086a2903002006420010898e80800020012903202205428002544100200141206a41086a290300501b450d002005a721020c010b41e40021020b20014194026a41cd838080003602002001418c026a41ce8380800036020020014184026a41cd83808000360200200141fc016a41ce83808000360200200141f4016a41cd83808000360200200141b8016a41346a41ce83808000360200200141e4016a41cd83808000360200200141b8016a41246a41cd83808000360200200141d4016a41cd83808000360200200141cc016a418580808000360200200141b8016a410c6a418580808000360200200141cc838080003602bc01200120023a009f0920012001419f096a360290022001200141e4086a360288022001200141ff056a360280022001200141c4056a3602f8012001200141e7026a3602f0012001200141ac026a3602e8012001200141ab026a3602e0012001200141aa026a3602d8012001200141a9026a3602d0012001200141a4026a3602c8012001200141a0026a3602c001200120014198026a3602b8014100280290a1c680002102410028028ca1c6800021034100280280a4c680002104200141900d6a420c370200200141880d6a410d360200200141800d6a410f360200200141d80c6a41246a41ccadc48000360200200141f00c6a4195a8c48000ad4280808080b00b84370200200141d80c6a410c6a41dbadc48000ad4280808080c00184370200200141d80c6a41346a200141b8016a360200200141dcaec480003602840d200141043602f80c200141003602ec0c200141003602e00c2001428180808090e0013702d80c200341ecf2c08000200441024622041b200141d80c6a200241d4f2c0800020041b280210118480808000000b200142fc90b9e5d09296e7773703d809200142a6d4e6f1a4dd9598603703d00920014293bb8a9cbb9ab6b31a3703e809200142ffabedd185d3d8d2163703e009200141d0096a412041002802a0a1c6800011848080800000200142fc90b9e5d09296e7773703d809200142a6d4e6f1a4dd9598603703d00920014295f38cfcb699a3c4ef003703e809200142a8db95cdaa86daa7193703e009200141d0096a412041002802a0a1c68000118480808000004188adc48000411341002802a0a1c6800011848080800000200142fc90b9e5d09296e7773703d809200142a6d4e6f1a4dd9598603703d009200142beee8ae9ce8fa2b1977f3703e80920014295d4f9afa2868fb8643703e009200141d0096a412041002802a0a1c6800011848080800000200142fc90b9e5d09296e7773703d809200142a6d4e6f1a4dd9598603703d009200142d3d8c5d2a9b9d2c1ac7f3703e80920014282ca868eabf3add0cf003703e009200141106a200141d0096a10e6888080002001290318210520012802102107200142fc90b9e5d09296e7773703b806200142a6d4e6f1a4dd9598603703b006200142bb88f596f8cbf6cf4c3703c8062001428a85cd9fb3e4b2ae6d3703c006200141d0096a200141b0066a412010dd888080000240024020012d00d0090d00200141980c6a4200370300200141900c6a4200370300200141880c6a4200370300200142003703800c0c010b200141980c6a200141e9096a290000370300200141900c6a200141e1096a290000370300200141880c6a200141d9096a290000370300200120012900d1093703800c0b200141a00c6a10ee88808000200142fc90b9e5d09296e7773703d809200142a6d4e6f1a4dd9598603703d009200142bad08eede089ffa8123703e809200142bd81f785e387e6aa817f3703e009200141086a200141d0096a412010d088808000200128020c2104024002400240024002400240200128020822024101470d00200141d0096a412041002802a0a1c68000118480808000000c010b2002450d010b2004450d000240200441aad5aad5004b0d002004410c6c2202417f4a0d020b10ae80808000000b41042108410021040c010b4100210341002d00fca3c680001a200241002802c8a3c68000118180808000002208450d01200821020340200141d0096a200310f387808000200241086a200141d0096a41086a280200360200200220012903d0093702002002410c6a21022004200341016a2203470d000b0b200120043602b40c200120083602b00c200120043602ac0c200141b80c6a200141ac0c6a410041002802f0a2c680001185808080000002402005420020071b2205420c540d00200542757c1085888080000b200141d0096a410041002802d8a1c6800011848080800000024020012802d8094120490d00200020012802d4092202290000370028200041c0006a200241186a290000370000200041386a200241106a290000370000200041306a200241086a290000370000024020012802d009450d00200241002802c0a3c68000118080808000000b200020012903800c37000020002005370320200020012900b80c370048200041186a200141800c6a41186a290300370000200041106a200141800c6a41106a290300370000200041086a200141800c6a41086a290300370000200041d0006a200141b80c6a41086a290000370000200041d8006a200141b80c6a41106a290000370000200041e0006a200141b80c6a41186a290000370000200020012902a00c370268200041f0006a200141a00c6a41086a280200360200200141a00d6a2480808080000f0b41c4afc48000412c2001419f0d6a41f0afc480004180b0c48000108981808000000b4104200210b280808000000b862901067f23808080800041e0006b22012480808080002001410036021420014280808080800137020c41002d00fca3c680001a0240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240410841002802c8a3c68000118180808000002202450d002002413a36020420024190b0c48000360200200141013602202001200236021c20014101360218200141186a2001410c6a109b8880800041002d00fca3c680001a410841002802c8a3c68000118180808000002203450d01200341cab0c480003602002003412e36020441002d00fca3c680001a410141002802c8a3c68000118180808000002204450d02200441003a0000024020012802142202200128020c470d002001410c6a2002109d86808000200128021421020b2001280210200241e8006c6a220241003a00602002410136025c2002200336025820024281808080103703502002200436024c2002428e80808010370244200241f8bec38000360240200241b580808000360218200242d7c9cb8fc1cf97db3e37030820024100360200200241106a42e88488d0c0e3aebc1337030041002d00fca3c680001a2001200128021441016a360214410841002802c8a3c68000118180808000002203450d03200341f8b0c480003602002003412936020441002d00fca3c680001a410141002802c8a3c68000118180808000002204450d04200441003a0000024020012802142202200128020c470d002001410c6a2002109d86808000200128021421020b2001280210200241e8006c6a220241013a00602002410136025c2002200336025820024281808080103703502002200436024c2002429080808010370244200241cfc0c380003602402002418881808000360218200242febac4ad81b6fafcb37f37030820024100360200200241106a4298848fa1dab08ba17437030041002d00fca3c680001a2001200128021441016a360214410841002802c8a3c68000118180808000002203450d0520034122360204200341a1b1c48000360200200141c0006a4200370300200141386a4200370300200141306a4200370300200141186a41106a4200370300200141186a41086a420037030020014200370318200141c8006a200141186a108d8d808000024020012802142202200128020c470d002001410c6a2002109d86808000200128021421020b2001280210200241e8006c6a2202410b360244200241d6bfc38000360240200241cf838080003602182002410036020020022001290348370348200241013a00602002410136025c2002200336025820024101360254200241d0006a200141c8006a41086a280200360200200242e6bc8a93f7f6b7ce33370308200241106a42c4f9f3c5a8b6cbf1663703002001200128021441016a36021441002d00fca3c680001a410841002802c8a3c68000118180808000002203450d06200341c3b1c48000360200200341d00036020441002d00fca3c680001a410141002802c8a3c68000118180808000002204450d07200441003a0000024020012802142202200128020c470d002001410c6a2002109d86808000200128021421020b2001280210200241e8006c6a220241003a00602002410136025c2002200336025820024281808080103703502002200436024c20024290808080103702442002419ebfc38000360240200241b58080800036021820024100360200200242d7c9cb8fc1cf97db3e370308200241106a42e88488d0c0e3aebc133703002001200128021441016a36021441002d00fca3c680001a410841002802c8a3c68000118180808000002202450d082002412636020420024193b2c48000360200200141013602202001200236021c20014101360218200141186a2001410c6a10978880800041002d00fca3c680001a410841002802c8a3c68000118180808000002203450d09200341cf00360204200341b9b2c4800036020041002d00fca3c680001a410141002802c8a3c68000118180808000002204450d0a200441053a000041002d00fca3c680001a410441002802c8a3c68000118180808000002202450d0b200141186a41086a220541003602002001200236021c20014104360218200141003602582001200141d8006a36025c200141dc006a200141186a10c08a808000200141c8006a41086a2206200528020036020020012001290218370348024020012802142202200128020c470d002001410c6a2002109d86808000200128021421020b2001280210200241e8006c6a2202410d360244200241899fc38000360240200241ea81808000360238200241b5808080003602202002410136020c20022004360208200242818080801037030020022001290348370348200241013a00602002410136025c2002200336025820024101360254200241d0006a2006280200360200200242e7b0a091f3ed9c85c500370328200242d7c9cb8fc1cf97db3e370310200241306a42b891b68c98adebcf61370300200241186a42e88488d0c0e3aebc133703002001200128021441016a36021441002d00fca3c680001a410841002802c8a3c68000118180808000002203450d0c20034188b3c48000360200200341c20036020441002d00fca3c680001a410841002802c8a3c68000118180808000002204450d0d20044200370000024020012802142202200128020c470d002001410c6a2002109d86808000200128021421020b2001280210200241e8006c6a220241013a00602002410136025c2002200336025820024288808080103703502002200436024c200242868080808001370244200241bfbec38000360240200241ef8080800036021820024100360200200242a5e9e3ab9e929adc2c370308200241106a4293888c8f89fdc6ec9e7f3703002001200128021441016a36021441002d00fca3c680001a410841002802c8a3c68000118180808000002202450d0e2002411c360204200241cab3c48000360200200141013602202001200236021c20014101360218200141186a2001410c6a10fe8880800041002d00fca3c680001a410841002802c8a3c68000118180808000002202450d0f2002413c360204200241e6b3c48000360200200141013602202001200236021c20014101360218200141186a2001410c6a10808980800041002d00fca3c680001a413841002802c8a3c68000118180808000002202450d1020024190b6c48000360230200241c5b5c480003602282002419cadc4800036022020024191b5c48000360218200241cab4c480003602102002419cadc4800036020820024128360204200241a2b4c48000360200200241346a413f3602002002412c6a41cb00360200200241246a41003602002002411c6a4134360200200241146a41c7003602002002410c6a4100360200200141073602202001200236021c20014107360218200141186a2001410c6a10ff8880800041002d00fca3c680001a410841002802c8a3c68000118180808000002203450d11200341cfb6c480003602002003412e36020441002d00fca3c680001a410441002802c8a3c68000118180808000002204450d1220044100360000024020012802142202200128020c470d002001410c6a2002109d86808000200128021421020b2001280210200241e8006c6a220241013a00602002410136025c2002200336025820024284808080103703502002200436024c2002428a808080c00037024420024190bec38000360240200241b580808000360218200242d7c9cb8fc1cf97db3e37030820024100360200200241106a42e88488d0c0e3aebc1337030041002d00fca3c680001a2001200128021441016a36021441d00041002802c8a3c68000118180808000002202450d13200241f2bac480003602482002419fbac48000360240200241c9b9c480003602382002419cadc4800036023020024190b9c48000360228200241bfb8c48000360220200241ebb7c480003602182002419cadc48000360210200241c6b7c48000360208200241c900360204200241fdb6c48000360200200241cc006a41c000360200200241c4006a41d3003602002002413c6a41d600360200200241346a41003602002002412c6a4139360200200241246a41d1003602002002411c6a41d400360200200241146a41003602002002410c6a412536020041002d00fca3c680001a410141002802c8a3c68000118180808000002204450d14200441023a000041002d00fca3c680001a410441002802c8a3c68000118180808000002203450d15200141186a41086a220541003602002001200336021c20014104360218200141003602582001200141d8006a36025c200141dc006a200141186a10c08a808000200141c8006a41086a2206200528020036020020012001290218370348024020012802142203200128020c470d002001410c6a2003109d86808000200128021421030b2001280210200341e8006c6a2203410b360244200341c99ec38000360240200341a782808000360238200341f5818080003602202003410136020c20032004360208200342818080801037030020032001290348370348200341013a00602003410a36025c200320023602582003410a360254200341d0006a2006280200360200200342d39ec9badc8ccad845370328200342c194a6a793ccc3a857370310200341306a42eab19fb291b0f9fb0c370300200341186a42ab8bffbed784ffa5937f3703002001200128021441016a36021441002d00fca3c680001a410841002802c8a3c68000118180808000002203450d16200341b2bbc48000360200200341d50036020441002d00fca3c680001a410141002802c8a3c68000118180808000002204450d17200441003a0000024020012802142202200128020c470d002001410c6a2002109d86808000200128021421020b2001280210200241e8006c6a220241003a00602002410136025c2002200336025820024281808080103703502002200436024c2002429280808010370244200241c5bec38000360240200241d083808000360218200242dfcb98f48cd0bd951f37030820024100360200200241106a42acf0e291d3fdc7d4d20037030041002d00fca3c680001a2001200128021441016a360214410841002802c8a3c68000118180808000002203450d1820034187bcc48000360200200341d30036020441002d00fca3c680001a410141002802c8a3c68000118180808000002204450d19200441003a0000024020012802142202200128020c470d002001410c6a2002109d86808000200128021421020b2001280210200241e8006c6a220241013a00602002410136025c2002200336025820024281808080103703502002200436024c2002429580808010370244200241c1bfc380003602402002418881808000360218200242febac4ad81b6fafcb37f37030820024100360200200241106a4298848fa1dab08ba17437030041002d00fca3c680001a2001200128021441016a360214411041002802c8a3c68000118180808000002203450d1a200341dabcc48000360200200341b1bdc48000360208200341d7003602042003410c6a411236020041002d00fca3c680001a410141002802c8a3c68000118180808000002204450d1b200441003a0000024020012802142202200128020c470d002001410c6a2002109d86808000200128021421020b2001280210200241e8006c6a220241013a00602002410236025c2002200336025820024281808080203703502002200436024c2002429880808010370244200241ffc0c380003602402002418881808000360218200242febac4ad81b6fafcb37f37030820024100360200200241106a4298848fa1dab08ba17437030041002d00fca3c680001a2001200128021441016a360214410841002802c8a3c68000118180808000002203450d1c200341c3bdc480003602002003412236020441002d00fca3c680001a410141002802c8a3c68000118180808000002204450d1d200441003a0000024020012802142202200128020c470d002001410c6a2002109d86808000200128021421020b2001280210200241e8006c6a220241003a00602002410136025c2002200336025820024281808080103703502002200436024c2002428e80808010370244200241f3bfc380003602402002419b82808000360218200242fb9bf4d1a5ccd7cbed0037030820024100360200200241106a42dd9fc4e2a4bae882d40037030041002d00fca3c680001a2001200128021441016a360214410841002802c8a3c68000118180808000002203450d1e2003412e360204200341e5bdc48000360200200141023a0018200141c8006a200141186a10b38c808000024020012802142202200128020c470d002001410c6a2002109d86808000200128021421020b2001280210200241e8006c6a22024111360244200241d7bec38000360240200241d1838080003602182002410036020020022001290348370348200241003a00602002410136025c2002200336025820024101360254200241d0006a200141c8006a41086a280200360200200242fc969fcca28189f9e200370308200241106a42bc9ecabcb9f0b1b0363703002001410c6a41086a2202200228020041016a2202360200200041086a20023602002000200129020c370200200041106a4106360200200041f9a6c4800036020c200141e0006a2480808080000f0b4104410810b280808000000b4104410810b280808000000b4101410110b280808000000b4104410810b280808000000b4101410110b280808000000b4104410810b280808000000b4104410810b280808000000b4101410110b280808000000b4104410810b280808000000b4104410810b280808000000b4101410110b280808000000b4101410410b280808000000b4104410810b280808000000b4101410810b280808000000b4104410810b280808000000b4104410810b280808000000b4104413810b280808000000b4104410810b280808000000b4101410410b280808000000b410441d00010b280808000000b4101410110b280808000000b4101410410b280808000000b4104410810b280808000000b4101410110b280808000000b4104410810b280808000000b4101410110b280808000000b4104411010b280808000000b4101410110b280808000000b4104410810b280808000000b4101410110b280808000000b4104410810b280808000000bb60f010c7f23808080800041d0026b220124808080800041002d00fca3c680001a0240024002400240024002400240024002400240024041d00241002802c8a3c68000118180808000002202450d00200141186a10e189808000200141c4026a200141186a10d48b80800041002d00fca3c680001a410841002802c8a3c68000118180808000002203450d012003413436020420034193bec48000360200200141086a410c6a200141c4026a41086a280200360200200120012902c40237020c41002d00fca3c680001a410c41002802c8a3c68000118180808000002204450d022004428080f081808080283700002004418080c00236000841002d00fca3c680001a410841002802c8a3c68000118180808000002205450d03200541d3bec480003602002005412a36020441002d00fca3c680001a410841002802c8a3c68000118180808000002206450d042006420a37000041002d00fca3c680001a410841002802c8a3c68000118180808000002207450d0520074188bfc48000360200200741d50036020441002d00fca3c680001a411041002802c8a3c68000118180808000002208450d0620084200370000200841086a420037000041002d00fca3c680001a410841002802c8a3c68000118180808000002209450d07200941c200360204200941ebbfc480003602002001412c6a4100360200200141286a418097c38000360200200141386a4200370200200142003702402001428080808080808080807f3702202001418097c3800036021c200141003a004c2001410036024820014280808080c0003702302001418080808078360218200141c4026a200141186a108e8d80800002402001280218220a418080808078460d00200a450d00200128021c41002802c0a3c68000118080808000000b02402001280224220a418080808078460d00200a450d00200128022841002802c0a3c68000118080808000000b02402001280230220a418080808078460d00200a450d00200128023441002802c0a3c68000118080808000000b41002d00fca3c680001a410841002802c8a3c6800011818080800000220b450d08200b4121360204200b41b5c0c48000360200200141246a200141c4026a41086a280200360200200120012902c40237021c41002d00fca3c680001a410241002802c8a3c6800011818080800000220c450d09200c41003b000041002d00fca3c680001a412841002802c8a3c6800011818080800000220a450d0a200a41a1c2c48000360220200a41d5c1c48000360218200a4187c1c48000360210200a419cadc48000360208200a412a360204200a41ddc0c48000360200200a41246a411c360200200a411c6a41cc00360200200a41146a41ce00360200200a410c6a4100360200200241106a428f96cddec79feed66b370300200242c4c5d9da83adf3df4a370308200241f0016a42fbe0bedd81cff9c317370300200241e8016a42cec9d2b3fca8a6f5bc7f370300200241b8016a42e6d58f99bfb09cd660370300200241b0016a428d9fb78edfb6baf67d37030020024180016a4293888c8f89fdc6ec9e7f370300200241f8006a42a5e9e3ab9e929adc2c370300200241c8006a42f6ef8697d7dfa3a3b07f370300200241c0006a42c0f88c9ce3f4f7fcb27f370300200241d2838080003602182002410c360204200241c7bec480003602002002200129020837021c200241246a200141086a41086a290200370200200241f8016a41f882808000360200200241e4016a4107360200200241d6c0c480003602e001200241dc016a4101360200200241d8016a2009360200200241d0016a429080808010370200200241cc016a2008360200200241c8016a4110360200200241c0016a41d383808000360200200241ac016a4108360200200241adc0c480003602a801200241a4016a4101360200200241a0016a200736020020024198016a42888080801037020020024194016a200636020020024190016a410836020020024188016a41ef80808000360200200241f4006a410e360200200241ddbfc48000360270200241ec006a4101360200200241e8006a2005360200200241e0006a428c80808010370200200241dc006a2004360200200241d8006a410c360200200241d0006a41d4838080003602002002413c6a410b360200200241fdbec4800036023820024101360234200220033602302002410136022c2002418c026a410136020020024190026a200b36020020024194026a4101360200200241bdc2c48000360298022002419c026a410a360200200241b0026a41d583808000360200200241b8026a4102360200200241bc026a200c360200200241c8026a200a360200200241cc026a4105360200200241c0026a4282808080d000370200200241a0026a42d7b9acfdf187c880f100370300200241a8026a42a695d4f0d8d192864537030020024184026a200141186a41086a290200370200200241fc016a2001290218370200200041063602082000200236020420004106360200200141d0026a2480808080000f0b410841d00210b280808000000b4104410810b280808000000b4101410c10b280808000000b4104410810b280808000000b4101410810b280808000000b4104410810b280808000000b4101411010b280808000000b4104410810b280808000000b4104410810b280808000000b4101410210b280808000000b4104412810b280808000000bfa0a01067f024002400240024002400240024002400240024020002d00000e0700010203040506070b0240200128020020012802082202470d0020012002410110b182808000200128020821020b2001200241016a360208200128020420026a41003a0000200041086a200110ef8c8080000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b2001200241016a360208200128020420026a41013a0000200041046a200110cc88808000200041186a200110ef8c8080000f0b0240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a41023a00000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41033a00002001200241016a2202360208200041016a21000240200128020020026b411f4b0d0020012002412010b182808000200128020821020b2001200241206a360208200128020420026a22012000290000370000200141086a200041086a290000370000200141106a200041106a290000370000200141186a200041186a2900003700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41043a00002001200241016a2202360208200041016a21000240200128020020026b411f4b0d0020012002412010b182808000200128020821020b2001200241206a360208200128020420026a22012000290000370000200141086a200041086a290000370000200141106a200041106a290000370000200141186a200041186a2900003700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41053a00002001200241016a2203360208200041016a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441086a200241086a290000370000200441106a200241106a290000370000200441186a200241186a2900003700002001200341206a220336020841002d00fca3c680001a412041002802c8a3c68000118180808000002202450d0220022000290021370000200241186a200041396a290000370000200241106a200041316a290000370000200241086a200041296a2900003700000240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22002002290000370000200041086a200241086a290000370000200041106a200241106a290000370000200041186a200241186a2900003700002001200341206a360208200241002802c0a3c68000118080808000000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41063a00002001200241016a220336020841002d00fca3c680001a412041002802c8a3c68000118180808000002202450d0220022000290001370000200241186a2205200041196a290000370000200241106a2206200041116a290000370000200241086a2207200041096a2900003700000240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441086a2007290000370000200441106a2006290000370000200441186a20052900003700002001200341206a2203360208200241002802c0a3c680001180808080000020002d00212100024020012802002003470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a20003a00000b0f0b4101412010b280808000000b4101412010b280808000000bdc0203017f017e027f410021010240024002400240024020002d00000e0700010402020203040b4103210102402000290308220242c000540d0041042101200242808001540d00410621012002428080808004540d00410b200279a74103766b21010b410121030240200041106a290300220242c000540d0041022103200242808001540d00410421032002428080808004540d004109200279a74103766b21030b200320016a21010c030b20002d000441027441e4c9c480006a21034103210102402000290318220242c000540d0041042101200242808001540d00410621012002428080808004540d00410b200279a74103766b21010b20032802002104410121030240200041206a290300220242c000540d0041022103200242808001540d00410421032002428080808004540d004109200279a74103766b21030b200120046a20036a21010c020b412021010c010b410121010b200141016a0bc70801037f02400240024002400240024002400240024002400240024002400240024002400240024020012d0000417f6a0e0b000102030405060708090a000b200141086a28020021024101210302402001410c6a2802002201450d002001417f4c0d0b41002d00fca3c680001a200141002802c8a3c68000118180808000002203450d0c0b20032002200110848e80800021032000410c6a2001360200200041086a200336020020002001360204200041013a00000f0b20002001290308370308200041023a00000f0b200141086a2802002103024002402001410c6a28020022010d00410121020c010b2001417f4c0d0941002d00fca3c680001a200141002802c8a3c68000118180808000002202450d0b0b20022003200110848e80800021032000410c6a2001360200200041086a200336020020002001360204200041033a00000f0b200141086a2802002103024002402001410c6a28020022010d00410121020c010b2001417f4c0d0841002d00fca3c680001a200141002802c8a3c68000118180808000002202450d0b0b20022003200110848e80800021032000410c6a2001360200200041086a200336020020002001360204200041043a00000f0b200041046a200141046a108c87808000200041053a00000f0b200041046a200141046a108a87808000200041063a00000f0b2001410c6a280200210202400240200141106a28020022030d00410121040c010b2003417f4c0d0541002d00fca3c680001a200341002802c8a3c68000118180808000002204450d090b20042002200310848e8080002102200041106a20033602002000410c6a20023602002000200336020820002001280204360204200041073a00000f0b200141086a2802002103024002402001410c6a28020022010d00410121020c010b2001417f4c0d0441002d00fca3c680001a200141002802c8a3c68000118180808000002202450d090b20022003200110848e80800021032000410c6a2001360200200041086a200336020020002001360204200041083a00000f0b20002001290001370001200041196a200141196a290000370000200041116a200141116a290000370000200041096a200141096a290000370000200041093a00000f0b20002001290001370001200041196a200141196a290000370000200041116a200141116a290000370000200041096a200141096a2900003700002000410a3a00000f0b200141086a2802002103024002402001410c6a28020022010d00410121020c010b2001417f4c0d0141002d00fca3c680001a200141002802c8a3c68000118180808000002202450d070b20022003200110848e80800021032000410c6a2001360200200041086a2003360200200020013602042000410b3a00000f0b10ae80808000000b4101200110b280808000000b4101200110b280808000000b4101200110b280808000000b4101200310b280808000000b4101200110b280808000000b4101200110b280808000000bae0603057f017e027f23808080800041c0006b2201248080808000200141186a41c7c2c48000410441d2aac480004114419cadc48000410010d882808000200141106a42043702002001420037020820014280808080800137020041002d00fca3c680001a024002400240412041002802c8a3c68000118180808000002202450d002002410036021820024101360204200241cbc2c4800036020020014101360238200120023602302001200241206a36023c200120023602342001200141306a10fa8680800041002d00fca3c680001a20012802002103200128020421022001280208210420012802182105200129021c2106410841002802c8a3c68000118180808000002207450d0120074100290390c3c480003702002001410036020820014280808080c000370200200141306a200141f0a8c48000410610b18b8080002001200141306a41f6a8c48000410e10988b808000200141306a20014184a9c48000410810868b8080002001200141306a418ca9c48000411710918b808000200141306a200141a3a9c48000410b10838b8080002001200141306a41aea9c48000410c109f8b808000200141306a200141baa9c48000410b10af8b8080002001200141306a41c5a9c48000411110c68b808000200141306a200141d6a9c48000411110d38b8080002001200141306a41e7a9c48000412010a48b808000200141246a20014187aac480004118108d8b8080002001200128022436020820012001280228220836020020012008200128022c41246c6a36020c20012008360204200141306a200110fb868080002005418080808078460d022001200336020820012002360200200120023602042001200220044105746a36020c200041c4006a200110fa868080002001410b6a200141306a41086a2802003600002000413c6a200637020020002005360238200041013a0000200041d8006a4101360200200041d4006a2007360200200041013602502001200129023037000320002001290000370001200041086a200141076a290000370000200141c0006a2480808080000f0b4108412010b280808000000b4104410810b280808000000b41a8d8c480004111419cd9c4800010a181808000000bb11303067f017e037f23808080800041c0006b2201248080808000200141206a4198c3c48000410541d2aac480004114419cadc48000410010d882808000200141186a42043702002001420037021020014280808080800137020841002d00fca3c680001a024002400240024002400240024002400240024002400240412041002802c8a3c68000118180808000002202450d002002410036021820024101360204200241cbc2c4800036020020014101360238200120023602302001200241206a36023c20012002360234200141086a200141306a10fa8680800041002d00fca3c680001a20012802082103200128020c2104200128021021052001280220210620012902242107410841002802c8a3c68000118180808000002208450d01200841002903b8c3c4800037020041002d00fca3c680001a41002802c8a3c6800021022001410036021020014280808080c00037020841102002118180808000002209450d02200941086a41002902d8f3c48000370200200941002902d0f3c48000370200200141086a410010a086808000200128020c200141086a41086a220a28020041246c6a220241003a00202002410f36021c200241c0c3c4800036021820024102360214200220093602102002428080808020370208200242808080808001370200200141306a41086a200a28020041016a3602002001200129020837033041002d00fca3c680001a411041002802c8a3c68000118180808000002209450d03200941086a41002902b8f4c48000370200200941002902b0f4c480003702000240200128023822022001280230470d00200141306a200210a086808000200128023821020b2001280234200241246c6a220241013a00202002411a36021c200241cfc3c4800036021820024102360214200220093602102002428080808020370208200242808080808001370200200141086a41086a200141306a41086a28020041016a3602002001200129033037030841002d00fca3c680001a411841002802c8a3c68000118180808000002209450d04200941106a41002902b8f6c48000370200200941086a41002902b0f6c48000370200200941002902a8f6c480003702000240200128021022022001280208470d00200141086a200210a086808000200128021021020b200128020c200241246c6a220241023a00202002411d36021c200241e9c3c4800036021820024103360214200220093602102002428080808030370208200242808080808001370200200141306a41086a200141086a41086a28020041016a3602002001200129030837033041002d00fca3c680001a410841002802c8a3c68000118180808000002209450d0520094100290380f5c480003702000240200128023822022001280230470d00200141306a200210a086808000200128023821020b2001280234200241246c6a220241033a00202002411336021c20024186c4c4800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141086a41086a200141306a41086a28020041016a3602002001200129033037030841002d00fca3c680001a410841002802c8a3c68000118180808000002209450d06200941002903b0f8c480003702000240200128021022022001280208470d00200141086a200210a086808000200128021021020b200128020c200241246c6a220241043a00202002410f36021c20024199c4c4800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141306a41086a200141086a41086a28020041016a3602002001200129030837033041002d00fca3c680001a410841002802c8a3c68000118180808000002209450d07200941002903f8f6c480003702000240200128023822022001280230470d00200141306a200210a086808000200128023821020b2001280234200241246c6a220241053a00202002410c36021c200241a8c4c4800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141086a41086a200141306a41086a28020041016a3602002001200129033037030841002d00fca3c680001a410841002802c8a3c68000118180808000002209450d08200941002903d8f7c480003702000240200128021022022001280208470d00200141086a200210a086808000200128021021020b200128020c200241246c6a220241063a00202002411b36021c200241b4c4c4800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141306a41086a200141086a41086a28020041016a3602002001200129030837033041002d00fca3c680001a410841002802c8a3c68000118180808000002209450d09200941002903a0f5c480003702000240200128023822022001280230470d00200141306a200210a086808000200128023821020b2001280234200241246c6a220241073a00202002411136021c200241cfc4c4800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141086a41086a200141306a41086a28020041016a3602002001200129033037030841002d00fca3c680001a410841002802c8a3c68000118180808000002209450d0a200941002903e0f8c480003702000240200128021022022001280208470d00200141086a200210a086808000200128021021020b200128020c200241246c6a220241083a00202002410c36021c200241e0c4c480003602182002410136021420022009360210200242808080801037020820024280808080800137020020012802102109200128020c2102200120012802083602102001200236020820012002200941246c6a41246a3602142001200236020c200141306a200141086a10fb868080002006418080808078460d0b20012003360210200120043602082001200436020c2001200420054105746a360214200041c4006a200141086a10fa86808000200141136a200141306a41086a2802003600002000413c6a200737020020002006360238200041013a0000200041d8006a4101360200200041d4006a2008360200200041013602502001200129023037000b20002001290008370001200041086a2001410f6a290000370000200141c0006a2480808080000f0b4108412010b280808000000b4104410810b280808000000b4104411010b280808000000b4104411010b280808000000b4104411810b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b41a8d8c480004111419cd9c4800010a181808000000b8a0703067f017e027f23808080800041c0006b2201248080808000200141186a41ecc4c48000410541d2aac480004114419cadc48000410010d882808000200141106a42043702002001420037020820014280808080800137020041002d00fca3c680001a0240024002400240412041002802c8a3c68000118180808000002202450d002002410036021820024101360204200241cbc2c4800036020020014101360238200120023602302001200241206a36023c200120023602342001200141306a10fa8680800041002d00fca3c680001a20012802002103200128020421042001280208210520012802182106200129021c2107410841002802c8a3c68000118180808000002208450d0120084100290390c5c480003702002001410036020820014280808080c000370200200141306a20014198c5c48000411010b48b8080002001200141306a41a8c5c48000410f10fd8a80800041002d00fca3c680001a410841002802c8a3c68000118180808000002209450d02200941002903a0f9c480003702000240200128020822022001280200470d002001200210a086808000200128020821020b2001280204200241246c6a220241023a00202002410b36021c200241b7c5c4800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141306a41086a2209200141086a28020041016a360200200120012902003703302001200141306a41c2c5c48000410a10a88b808000200141306a200141ccc5c48000410d10cb8b8080002001200141306a41d9c5c48000410810878b808000200141246a200141e1c5c48000411110ff8a8080002001200128022436020820012001280228220236020020012002200128022c41246c6a36020c20012002360204200141306a200110fb868080002006418080808078460d032001200336020820012004360200200120043602042001200420054105746a36020c200041c4006a200110fa868080002001410b6a20092802003600002000413c6a200737020020002006360238200041013a0000200041d8006a4101360200200041d4006a2008360200200041013602502001200129023037000320002001290000370001200041086a200141076a290000370000200141c0006a2480808080000f0b4108412010b280808000000b4104410810b280808000000b4104410810b280808000000b41a8d8c480004111419cd9c4800010a181808000000be60d03037f017e017f23808080800041f0006b2202248080808000024002400240024002400240024002400240024002400240024002400240200128020022032802042204450d0020032004417f6a36020420032003280200220441016a36020020042d00000e0c01020304050607080d090a0b0d0b200041003a00000c0d0b2002200110bc8a8080000240024020022802000d00200241d4006a2001200228020410d0858080002002280254418080808078460d00200241e0006a41086a200241d4006a41086a2802002203360200200241cf006a20033600002002200229025422053703602002200537004720002002290044370001200041086a200241cb006a290000370000410121030c010b410021030b200020033a00000c0c0b02402001280200220328020422014108490d00200041023a00002003200141786a36020420032003280200220141086a360200200020012900003703080c0c0b200041003a00000c0b0b200241086a200110bc8a808000024020022802080d00200241d4006a2001200228020c10d0858080002002280254418080808078460d00200241e0006a41086a200241d4006a41086a2802002203360200200241cf006a20033600002002200229025422053703602002200537004720002002290044370001200041086a200241cb006a290000370000200041033a00000c0b0b200041003a00000c0a0b200241106a200110bc8a808000024020022802100d00200241d4006a2001200228021410d0858080002002280254418080808078460d00200241e0006a41086a200241d4006a41086a2802002203360200200241cf006a20033600002002200229025422053703602002200537004720002002290044370001200041086a200241cb006a290000370000200041043a00000c0a0b200041003a00000c090b200241186a200110bc8a808000024020022802180d00200241d4006a2001200228021c10cf858080002002280254418080808078460d00200241e0006a41086a200241d4006a41086a2802002203360200200241cf006a20033600002002200229025422053703602002200537004720002002290044370001200041086a200241cb006a290000370000200041053a00000c090b200041003a00000c080b200241206a200110bc8a808000024020022802200d00200241d4006a2001200228022410cd858080002002280254418080808078460d00200241e0006a41086a200241d4006a41086a2802002203360200200241cf006a20033600002002200229025422053703602002200537004720002002290044370001200041086a200241cb006a290000370000200041063a00000c080b200041003a00000c070b200241286a200110bc8a80800020022802280d04200241c4006a2001200228022c10d08580800020022802442203418080808078460d042002280248210402402001280200220128020422064104490d002000200228024c3602102000200436020c20002003360208200041073a000020012006417c6a36020420012001280200220341046a360200200020032800003602040c070b200041003a00002003450d06200441002802c0a3c68000118080808000000c060b200241306a200110bc8a808000024020022802300d00200241d4006a2001200228023410d0858080002002280254418080808078460d00200241e0006a41086a200241d4006a41086a2802002203360200200241cf006a20033600002002200229025422053703602002200537004720002002290044370001200041086a200241cb006a290000370000200041083a00000c060b200041003a00000c050b4100210302402001280200220128020422044120490d002001200441606a36020420012001280200220441206a3602002000200429000037000141092103200041096a200441086a290000370000200041116a200441106a290000370000200041196a200441186a2900003700000b200020033a00000c040b4100210302402001280200220128020422044120490d002001200441606a36020420012001280200220341206a36020020002003290000370001200041096a200341086a290000370000200041116a200341106a290000370000200041196a200341186a290000370000410a21030b200020033a00000c030b200241386a200110bc8a808000024020022802380d00200241d4006a2001200228023c10d0858080002002280254418080808078460d00200241e0006a41086a200241d4006a41086a2802002203360200200241c4006a410b6a20033600002002200229025422053703602002200537004720002002290044370001200041086a200241cb006a2900003700002000410b3a00000c030b200041003a00000c020b200041003a00000c010b200041003a00000b200241f0006a2480808080000bbe1203037f017e037f23808080800041106b22022480808080000240024002400240024002400240024002400240024002400240024020002d0000417f6a0e0b000102030405060708090a0b0b0240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a41003a0000200041086a280200210420022000410c6a28020022033602082002200241086a36020c2002410c6a200110c08a80800002402001280200200128020822006b20034f0d0020012000200310b182808000200128020821000b200128020420006a2004200310848e8080001a2001200020036a3602080c0a0b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41013a00002001200341016a2203360208200029030821050240200128020020036b41074b0d0020012003410810b182808000200128020821030b2001200341086a360208200128020420036a20053700000c090b0240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a41023a0000200041086a280200210420022000410c6a28020022033602082002200241086a36020c2002410c6a200110c08a80800002402001280200200128020822006b20034f0d0020012000200310b182808000200128020821000b200128020420006a2004200310848e8080001a2001200020036a3602080c080b0240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a41033a0000200041086a280200210420022000410c6a28020022033602082002200241086a36020c2002410c6a200110c08a80800002402001280200200128020822006b20034f0d0020012000200310b182808000200128020821000b200128020420006a2004200310848e8080001a2001200020036a3602080c070b0240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a41043a0000200041086a280200210320022000410c6a28020022003602082002200241086a36020c2002410c6a200110c08a8080002000450d06200041186c210003402003200110fe86808000200341186a2103200041686a22000d000c070b0b0240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a41053a0000200041086a280200210420022000410c6a28020022033602082002200241086a36020c2002410c6a200110c08a8080002003450d052003410c6c2106200441086a210003402000417c6a28020021072002200028020022033602082002200241086a36020c2002410c6a200110c08a80800002402001280200200128020822046b20034f0d0020012004200310b182808000200128020821040b200128020420046a2007200310848e8080001a2001200420036a3602082000410c6a2100200641746a22060d000c060b0b0240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a41063a00002000410c6a28020021062002200041106a28020022033602082002200241086a36020c2002410c6a200110c08a80800002402001280200200128020822046b20034f0d0020012004200310b182808000200128020821040b200128020420046a2006200310848e8080001a2001200420036a2203360208200028020421000240200128020020036b41034b0d0020012003410410b182808000200128020821030b2001200341046a360208200128020420036a20003600000c040b0240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a41073a0000200041086a280200210420022000410c6a28020022033602082002200241086a36020c2002410c6a200110c08a80800002402001280200200128020822006b20034f0d0020012000200310b182808000200128020821000b200128020420006a2004200310848e8080001a2001200020036a3602080c030b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41093a00002001200341016a220436020841002d00fca3c680001a412041002802c8a3c68000118180808000002203450d0320032000290001370000200341186a2206200041196a290000370000200341106a2207200041116a290000370000200341086a2208200041096a2900003700000240200128020020046b411f4b0d0020012004412010b182808000200128020821040b200128020420046a22002003290000370000200041086a2008290000370000200041106a2007290000370000200041186a20062900003700002001200441206a360208200341002802c0a3c68000118080808000000c020b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a410a3a00002001200341016a220436020841002d00fca3c680001a412041002802c8a3c68000118180808000002203450d0320032000290001370000200341186a2206200041196a290000370000200341106a2207200041116a290000370000200341086a2208200041096a2900003700000240200128020020046b411f4b0d0020012004412010b182808000200128020821040b200128020420046a22002003290000370000200041086a2008290000370000200041106a2007290000370000200041186a20062900003700002001200441206a360208200341002802c0a3c68000118080808000000c010b0240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a410b3a0000200041086a280200210420022000410c6a28020022033602082002200241086a36020c2002410c6a200110c08a80800002402001280200200128020822006b20034f0d0020012000200310b182808000200128020821000b200128020420006a2004200310848e8080001a2001200020036a3602080b200241106a2480808080000f0b4101412010b280808000000b4101412010b280808000000bd30202017f027e23808080800041d0006b2201248080808000024020002903002202500d0020014298d5afd2c6aeacae2f370328200142c2cdc8b0c7b9e78f857f370320200142e4c5bdb4b2e9a5a6807f370338200142d790d7a3fef9fda0c800370330200141106a200141206a10e688808000200129031821032001280210210020014298d5afd2c6aeacae2f370328200142c2cdc8b0c7b9e78f857f370320200142e4c5bdb4b2e9a5a6807f370338200142d790d7a3fef9fda0c8003703302001200141206a10e68880800020014298d5afd2c6aeacae2f370328200142c2cdc8b0c7b9e78f857f370320200142e4c5bdb4b2e9a5a6807f370338200142d790d7a3fef9fda0c800370330200142002003420020001b220320027d220220022003561b370348200141206a4120200141c8006a410841002802e0a1c68000118680808000000b200141d0006a2480808080000bcd0704067f017e017f017e23808080800041d0006b2201248080808000200141286a41f2c5c48000410841fac5c480004123419cadc48000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041c00041002802c8a3c68000118180808000002202450d00200242d1c5efcdcd82cde1ff003703082002419fc6c480003602202002419382808000360218200241023602042002419dc6c48000360200200241306a4293888c8f89fdc6ec9e7f370300200241286a42a5e9e3ab9e929adc2c370300200241106a429ccab49c93e2e495cf00370300200241386a41ef80808000360200200241246a410736020020014102360248200120023602402001200241c0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a2001411c6a220241086a2802003602002001200229020037030020012802102103200128021421042001280218210520012802282106200129022c2107200141106a41086a22084100360200200142808080808001370210200141106a410010a4868080002001280214200828020041386c6a2202420437022c20024202370224200241d0fbc480003602202002410236021c200241cefbc4800036021820024193828080003602102002429ccab49c93e2e495cf00370308200242d1c5efcdcd82cde1ff00370300200141c0006a41086a200828020041016a2202360200200120012902102209370340024020022009a7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c20024207370224200241c7fbc480003602202002410636021c200241c1fbc48000360218200241ef8080800036021020024293888c8f89fdc6ec9e7f370308200242a5e9e3ab9e929adc2c370300200128024821082001280244210220012001280240360248200120023602402001200236024420012002200841386c6a41386a36024c200141346a200141c0006a10f9868080002006418080808078460d012001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002006360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841c00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000bcb0704067f017e017f017e23808080800041d0006b2201248080808000200141286a41f2c5c48000410841fac5c480004123419cadc48000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041c00041002802c8a3c68000118180808000002202450d002002429fb2eafebdc29397f7003703082002419fc6c48000360220200241d683808000360218200241023602042002419dc6c48000360200200241306a4293888c8f89fdc6ec9e7f370300200241286a42a5e9e3ab9e929adc2c370300200241106a42e0f4d5c484838cd222370300200241386a41ef80808000360200200241246a410736020020014102360248200120023602402001200241c0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a2001411c6a220241086a2802003602002001200229020037030020012802102103200128021421042001280218210520012802282106200129022c2107200141106a41086a22084100360200200142808080808001370210200141106a410010a4868080002001280214200828020041386c6a2202420437022c20024202370224200241d0fbc480003602202002410236021c200241cefbc48000360218200241d683808000360210200242e0f4d5c484838cd2223703082002429fb2eafebdc29397f700370300200141c0006a41086a200828020041016a2202360200200120012902102209370340024020022009a7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c20024207370224200241c7fbc480003602202002410636021c200241c1fbc48000360218200241ef8080800036021020024293888c8f89fdc6ec9e7f370308200242a5e9e3ab9e929adc2c370300200128024821082001280244210220012001280240360248200120023602402001200236024420012002200841386c6a41386a36024c200141346a200141c0006a10f9868080002006418080808078460d012001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002006360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841c00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000b4000200042fc90b9e5d09296e777370008200042a6d4e6f1a4dd959860370000200042d3d8c5d2a9b9d2c1ac7f37001820004282ca868eabf3add0cf003700100b3e00200042fc90b9e5d09296e777370008200042a6d4e6f1a4dd959860370000200042f7b6fccfd083b2cf4d370018200042afd2c6ffdbc495bc083700100b820702047f057e23808080800041c0016b2201248080808000200142fc90b9e5d09296e777370338200142a6d4e6f1a4dd959860370330200141fc006a200141306a411041002802c0a1c680001185808080000002400240200128027c2202418080808078460d00200128028001210302402001280284014110490d00200141306a2003411010888e808000210402402002450d00200341002802c0a3c68000118080808000000b20040d010c020b2002450d00200341002802c0a3c68000118080808000000b41002102200141003b014e02400240417f4100280284a4c680002203410347200341034b1b2203450d00200341ff017141ff01470d010b200141d8006a410c6a41d783808000360200200141838280800036025c20014106360254200141f9a6c480003602502001200141ce006a3602602001200141d0006a3602584100280290a1c680002102410028028ca1c6800021034100280280a4c680002104200141b4016a4202370200200141ac016a4103360200200141a4016a4116360200200141a0016a41bcaac4800036020020014194016a4195a8c48000ad4280808080b00b84370200200141fc006a410c6a41d2aac48000ad4280808080c00284370200200141b0016a200141d8006a360200200141fcabc480003602a8012001410336029c012001410036029001200141003602840120014281808080c02037027c200341ecf2c08000200441024622041b200141fc006a200241d4f2c0800020041b2802101184808080000020012f014e21020b200141fc006a41f9a6c48000410641002802a0a3c6800011858080800000200141fc006a41106a220341bccdc48000411541002802a0a3c6800011858080800000200141d8006a41186a200141fc006a41186a290000370300200141d8006a41106a2003290000370300200141d8006a41086a200141fc006a41086a2900003703002001200129007c370358200120023b017c200141d8006a4120200141fc006a410241002802e0a1c68000118680808000000b200141206a10ad878080002001290320210520012903282106200141106a10bd888080002001290318210720012903102108200110998c808000200129030021092000427f427f200620077c220720072006541b220620012903087c220720072006541b3703082000427f2009427f200520087c220620062005541b22057c220620062005541b370300200141c0016a2480808080000b930201027f23808080800041106b22022480808080002002200036020020022001280214419cc9c48000410e200141186a28020028020c118280808000003a000c20022001360208200241003a000d20024100360204200241046a200241acc9c48000108d81808000210120022d000c210002400240200128020022030d00200041ff017141004721010c010b41012101200041ff01710d0020022802082100024020034101470d0020022d000d41ff0171450d0020002d001c4104710d00410121012000280214418ca5c080004101200041186a28020028020c118280808000000d010b2000280214418da5c080004101200041186a28020028020c1182808080000021010b200241106a24808080800020010b100020004200370308200042003703000b2100200128021441d8c8c480004114200141186a28020028020c118280808000000bcb0601017f0240024020002d00000e03010001000b2000280204220110848a808000200141002802c0a3c68000118080808000000b0240024020002d00240e03010001000b200041286a280200220110848a808000200141002802c0a3c68000118080808000000b0240024020002d00480e03010001000b200041cc006a280200220110848a808000200141002802c0a3c68000118080808000000b0240024020002d006c0e03010001000b200041f0006a280200220110848a808000200141002802c0a3c68000118080808000000b0240024020002d0090010e03010001000b20004194016a280200220110848a808000200141002802c0a3c68000118080808000000b0240024020002d00b4010e03010001000b200041b8016a280200220110848a808000200141002802c0a3c68000118080808000000b0240024020002d00d8010e03010001000b200041dc016a280200220110848a808000200141002802c0a3c68000118080808000000b0240024020002d00fc010e03010001000b20004180026a280200220110848a808000200141002802c0a3c68000118080808000000b0240024020002d00a0020e03010001000b200041a4026a280200220110848a808000200141002802c0a3c68000118080808000000b0240024020002d00c4020e03010001000b200041c8026a280200220110848a808000200141002802c0a3c68000118080808000000b0240024020002d00e8020e03010001000b200041ec026a280200220110848a808000200141002802c0a3c68000118080808000000b0240024020002d008c030e03010001000b20004190036a280200220110848a808000200141002802c0a3c68000118080808000000b0240024020002d00b0030e03010001000b200041b4036a280200220110848a808000200141002802c0a3c68000118080808000000b0240024020002d00d4030e03010001000b200041d8036a280200220110848a808000200141002802c0a3c68000118080808000000b0240024020002d00f8030e03010001000b200041fc036a280200220110848a808000200141002802c0a3c68000118080808000000b0240024020002d009c040e03010001000b200041a0046a280200220010848a808000200041002802c0a3c68000118080808000000b0b02000b02000b890501037f23808080800041a0016b22032480808080002003200136023c20034100360238200320023602342003200341346a10bc8a80800002400240024020032802000d00200328020421042003200328023841016a22013602382001200328023c4b0d00200341003a007f200320043602980120034100360294012003200341346a360290012003200341ff006a36029c0120034180016a20034190016a10a087808000024020032d007f450d0020034180016a10a68d8080000c010b200341f0006a41086a220520034180016a41086a280200360200200320032903800137037020032003280238417f6a36023802402003280234220128020422044120490d002001200441606a36020420012001280200220441206a360200200341c0006a41086a22012005280200360200200341c0006a41146a200441086a290000370200200341c0006a411c6a200441106a290000370200200341c0006a41246a200441186a2900003702002003200429000037024c200341086a41086a2001290300370300200341086a41106a2201200341c0006a41106a290300370300200341086a41186a2204200341c0006a41186a290300370300200341086a41206a200341c0006a41206a290300370300200341086a41286a2205200341c0006a41286a2802003602002003200329037037030820022802040d02200020032903083702042000412c6a2005280200360200200041246a200341286a2903003702002000411c6a2004290300370200200041146a20012903003702002000410c6a200341106a290300370200200041003602000c030b200341f0006a10a68d8080000b200041013602000c010b200341086a10a68d808000200041013602000b200341a0016a2480808080000b210020012802144198c3c480004105200141186a28020028020c118280808000000b8f1401047f23808080800041900a6b220224808080800002400240024002400240024002400240024002400240024020012802000e050100020304010b20024180056a200141046a10e48d808000024020012802100d000240200141186a28020022034100480d00200341f5ffffff074f0d06200141146a280200210402402003410b6a417c7122050d00410421010c0b0b41002d00fca3c680001a200541002802c8a3c680001181808080000022010d0a4104200510b280808000000b41fc9bc68000412b200241106a41a89cc6800041b89cc68000108981808000000b200141186a28020022034120470d052002411c6a200141146a280200220141086a290000370200200241106a41146a200141106a2900003702002002412c6a200141186a29000037020020022001290000370214410021010c090b200041023602000c090b20024180056a200141046a10e48d808000200241106a200141106a10838a808000024020022d001022014102460d00200020022f00113b00052000200229021837020c200041076a20022d00133a0000200041146a200241106a41106a2902003702002000411c6a200241106a41186a290200370200200041246a200241106a41206a28020036020020022802142103200041d0006a200241a8056a290200370200200041c8006a20024180056a41206a290200370200200041c0006a20024180056a41186a290200370200200041386a20024180056a41106a290200370200200041306a20024188056a290200370200200020022902800537022820002003360208200020013a0004200041043602000c090b20022802142101200041083602002000200136020420022802a8054129490d0820022802800541002802c0a3c68000118080808000000c080b200241023a00ac04200241023a008804200241023a00e403200241023a00c003200241023a009c03200241023a00f802200241023a00d402200241023a00b002200241023a008c02200241023a00e801200241023a00c401200241023a00a001200241023a007c200241023a0058200241023a0034200241023a001041002104200241003602d00420024100360288052002200141c4016a2205360284052002200141046a360280052002200241d0046a360290052002200241106a36028c0520024180056a10828a808000024020022802d0042203450d002000410836020020002003360204200241106a10b18a8080000c080b20024180056a200241106a41c00410848e8080001a0240200528020022034102460d000240024020030d002002200141c8016a2802002203200141cc016a280200220410e98d8080002002280200210120022802042105200241d8046a200320044100280298a3c6800011858080800000200220053602d4040c010b200141cc016a28020022034120470d05200241dc046a200141c8016a280200220141086a290000370200200241e4046a200141106a290000370200200241ec046a200141186a290000370200200220012900003702d404410021010b200241e8096a41086a200241d0046a41086a290200370300200241e8096a41106a200241d0046a41106a290200370300200241e8096a41186a200241d0046a41186a290200370300200241e8096a41206a200241d0046a41206a290200370300200220013602d004200220022902d0043703e809410121040b200041306a20024180056a41c00410848e8080001a200041286a200241e8096a41206a290300370200200041206a200241e8096a41186a290300370200200041186a200241e8096a41106a290300370200200041106a200241f0096a290300370200200020022903e80937020820002004360204200041053602000c070b200241023a00ac04200241023a008804200241023a00e403200241023a00c003200241023a009c03200241023a00f802200241023a00d402200241023a00b002200241023a008c02200241023a00e801200241023a00c401200241023a00a001200241023a007c200241023a0058200241023a0034200241023a001041002104200241003602d00420024100360288052002200141d0016a360284052002200141106a360280052002200241d0046a360290052002200241106a36028c0520024180056a10898a808000024020022802d0042203450d002000410836020020002003360204200241106a10b18a8080000c070b200241d0046a200141046a10e48d80800020024180056a200241106a41c00410848e8080001a024020012802d00122034102460d000240024020030d00200241086a200141d4016a2802002203200141d8016a280200220410e98d80800020022802082101200228020c2105200241f0096a200320044100280298a3c6800011858080800000200220053602ec090c010b200141d8016a28020022034120470d05200241f4096a200141d4016a280200220141086a290000370200200241fc096a200141106a290000370200200241840a6a200141186a290000370200200220012900003702ec09410021010b200241c0096a41086a200241e8096a41086a290200370300200241c0096a41106a200241e8096a41106a290200370300200241c0096a41186a200241e8096a41186a290200370300200241c0096a41206a200241e8096a41206a290200370300200220013602e809200220022902e8093703c009410121040b200020022902d0043702ec0420004194056a200241f8046a2902003702002000418c056a200241d0046a41206a29020037020020004184056a200241d0046a41186a290200370200200041fc046a200241d0046a41106a290200370200200041f4046a200241d0046a41086a2902003702002000412c6a20024180056a41c00410848e8080001a200041246a200241c0096a41206a2903003702002000411c6a200241c0096a41186a290300370200200041146a200241c0096a41106a2903003702002000410c6a200241c0096a41086a290300370200200020022903c009370204200020043602000c060b41e484c08000412b200241106a419085c08000419086c08000108981808000000b41202003418cc9c4800010a281808000000b41202003418cc9c4800010a281808000000b41202003418cc9c4800010a281808000000b2001428180808010370200200141086a2004200310848e8080001a200241106a41086a200420034100280298a3c6800011858080800000200220033602140b20002002290280053702042000410c6a20024180056a41086a290200370200200041146a20024180056a41106a2902003702002000411c6a20024180056a41186a290200370200200041246a20024180056a41206a2902003702002000412c6a200241a8056a29020037020020022001360210200020022902103702342000413c6a200241106a41086a290200370200200041c4006a200241106a41106a290200370200200041cc006a200241106a41186a290200370200200041d4006a200241106a41206a290200370200200041033602000b200241900a6a2480808080000b8f1401047f23808080800041900a6b220224808080800002400240024002400240024002400240024002400240024020012802000e050100020304010b20024180056a200141046a10e48d808000024020012802100d000240200141186a28020022034100480d00200341f5ffffff074f0d06200141146a280200210402402003410b6a417c7122050d00410421010c0b0b41002d00fca3c680001a200541002802c8a3c680001181808080000022010d0a4104200510b280808000000b41fc9bc68000412b200241106a41a89cc6800041b89cc68000108981808000000b200141186a28020022034120470d052002411c6a200141146a280200220141086a290000370200200241106a41146a200141106a2900003702002002412c6a200141186a29000037020020022001290000370214410021010c090b200041023602000c090b20024180056a200141046a10e48d808000200241106a200141106a10878a808000024020022d001022014102460d00200020022f00113b00052000200229021837020c200041076a20022d00133a0000200041146a200241106a41106a2902003702002000411c6a200241106a41186a290200370200200041246a200241106a41206a28020036020020022802142103200041d0006a200241a8056a290200370200200041c8006a20024180056a41206a290200370200200041c0006a20024180056a41186a290200370200200041386a20024180056a41106a290200370200200041306a20024188056a290200370200200020022902800537022820002003360208200020013a0004200041043602000c090b20022802142101200041083602002000200136020420022802a8054129490d0820022802800541002802c0a3c68000118080808000000c080b200241023a00ac04200241023a008804200241023a00e403200241023a00c003200241023a009c03200241023a00f802200241023a00d402200241023a00b002200241023a008c02200241023a00e801200241023a00c401200241023a00a001200241023a007c200241023a0058200241023a0034200241023a001041002104200241003602d00420024100360288052002200141c4016a2205360284052002200141046a360280052002200241d0046a360290052002200241106a36028c0520024180056a10888a808000024020022802d0042203450d002000410836020020002003360204200241106a10b18a8080000c080b20024180056a200241106a41c00410848e8080001a0240200528020022034102460d000240024020030d002002200141c8016a2802002203200141cc016a280200220410e98d8080002002280200210120022802042105200241d8046a200320044100280298a3c6800011858080800000200220053602d4040c010b200141cc016a28020022034120470d05200241dc046a200141c8016a280200220141086a290000370200200241e4046a200141106a290000370200200241ec046a200141186a290000370200200220012900003702d404410021010b200241e8096a41086a200241d0046a41086a290200370300200241e8096a41106a200241d0046a41106a290200370300200241e8096a41186a200241d0046a41186a290200370300200241e8096a41206a200241d0046a41206a290200370300200220013602d004200220022902d0043703e809410121040b200041306a20024180056a41c00410848e8080001a200041286a200241e8096a41206a290300370200200041206a200241e8096a41186a290300370200200041186a200241e8096a41106a290300370200200041106a200241f0096a290300370200200020022903e80937020820002004360204200041053602000c070b200241023a00ac04200241023a008804200241023a00e403200241023a00c003200241023a009c03200241023a00f802200241023a00d402200241023a00b002200241023a008c02200241023a00e801200241023a00c401200241023a00a001200241023a007c200241023a0058200241023a0034200241023a001041002104200241003602d00420024100360288052002200141d0016a360284052002200141106a360280052002200241d0046a360290052002200241106a36028c0520024180056a10868a808000024020022802d0042203450d002000410836020020002003360204200241106a10b18a8080000c070b200241d0046a200141046a10e48d80800020024180056a200241106a41c00410848e8080001a024020012802d00122034102460d000240024020030d00200241086a200141d4016a2802002203200141d8016a280200220410e98d80800020022802082101200228020c2105200241f0096a200320044100280298a3c6800011858080800000200220053602ec090c010b200141d8016a28020022034120470d05200241f4096a200141d4016a280200220141086a290000370200200241fc096a200141106a290000370200200241840a6a200141186a290000370200200220012900003702ec09410021010b200241c0096a41086a200241e8096a41086a290200370300200241c0096a41106a200241e8096a41106a290200370300200241c0096a41186a200241e8096a41186a290200370300200241c0096a41206a200241e8096a41206a290200370300200220013602e809200220022902e8093703c009410121040b200020022902d0043702ec0420004194056a200241f8046a2902003702002000418c056a200241d0046a41206a29020037020020004184056a200241d0046a41186a290200370200200041fc046a200241d0046a41106a290200370200200041f4046a200241d0046a41086a2902003702002000412c6a20024180056a41c00410848e8080001a200041246a200241c0096a41206a2903003702002000411c6a200241c0096a41186a290300370200200041146a200241c0096a41106a2903003702002000410c6a200241c0096a41086a290300370200200020022903c009370204200020043602000c060b41e484c08000412b200241106a419085c08000419086c08000108981808000000b41202003418cc9c4800010a281808000000b41202003418cc9c4800010a281808000000b41202003418cc9c4800010a281808000000b2001428180808010370200200141086a2004200310848e8080001a200241106a41086a200420034100280298a3c6800011858080800000200220033602140b20002002290280053702042000410c6a20024180056a41086a290200370200200041146a20024180056a41106a2902003702002000411c6a20024180056a41186a290200370200200041246a20024180056a41206a2902003702002000412c6a200241a8056a29020037020020022001360210200020022902103702342000413c6a200241106a41086a290200370200200041c4006a200241106a41106a290200370200200041cc006a200241106a41186a290200370200200041d4006a200241106a41206a290200370200200041033602000b200241900a6a2480808080000bcd03010a7f23808080800041c0006b2201248080808000024002400240200010b487808000450d00200142919fd78da1a1ad84ff003703282001429ceccef7a6c0dedd2037032020014282fceae49dd9e2861d370338200142de8c84a1ecd0a6d30c370330200141146a200141206a10e2888080000240024020012802142202418080808078470d00410821034100210241002104410821050c010b200128021821030240200128021c22040d0041082105410021040c010b200441b3e6cc194b0d02200441286c2206417f4c0d024100210741002d00fca3c680001a200641002802c8a3c68000118180808000002205450d032004210820032109034020062007460d0120092903202100200520076a220a2009290300370300200a41186a200941186a290300370300200a41106a200941106a290300370300200a41086a200941086a290300370300200a41206a2000370300200741286a2107200941286a21092008417f6a22080d000b0b200120043602102001200536020c20012004360208200120043602282001200336022420012002360220200141206a200141086a4100200910b3878080000b200141c0006a2480808080000f0b10ae80808000000b4108200610b280808000000bcf0201027f23808080800041306b2203248080808000024002400240024020022d0000410b470d002003410c6a200241086a2802002002410c6a280200108b8a80800020032d000c0d0041002d00fca3c680001a410c41002802c8a3c68000118180808000002204450d0241002d00fca3c680001a412041002802c8a3c68000118180808000002202450d032002200329000d370000200241186a200341256a290000370000200241106a2003411d6a290000370000200241086a200341156a290000370000200041013a00282000410136022420002004360220200042808080801037031820004280808080c0003703102000427f370308200042e4003703002004412036020820042002360204200441203602000c010b2000418080808078360210200041003b01000b200341306a2480808080000f0b4104410c10b280808000000b4101412010b280808000000bb40202017f027e4101210242cd0b21034288da9fed002104024002400240024002400240024002400240024020012d0000417f6a0e0b0009010102030405060607000b2001410c6a3502004283037e42d0b8c5007c21040c070b42db8b04210342f88ef9fab10221040c070b2001410c6a35020042d2eb84307e4280e585017c2104420021030c060b2001410c6a35020042d0a2fa2f7e4298e383017c2104420021030c050b41012102200128020441016a2201417f20011bad220442c6007e4286017c2103200442d1a6983c7e42e0d1fe017c21040c040b2001410c6a35020042ef0a7e42efb29c017c21040c020b4200210342f889a43421040c020b42db8b04210342f8b999efc70221040c010b41002102420021030b200041003a0011200020023a001020002003370308200020043703000b840301077f4101210202400240024002402001280208220341016a2204200128020422054d0d000c010b200320054f0d012001200436020802400240024002400240024002402001280200220620036a2d000022074103710e0400010203000b20074102762108410021020c060b200341026a220320054b0d05200120033602082004417f470d02417f200341dcc1c28000109681808000000b200341046a220320054b0d04200120033602082004417d490d022004200341dcc1c28000109681808000000b20074104490d020c030b200620046a2d000041087420077241ffff03712201410276210820014180024921020c020b200620046a220141026a2d000041187420012f000041087472200772220141027621082001418080044921020c010b200341056a220320054b0d00200120033602082004417c4f0d02200620046a28000022084180808080044921020b20002008360204200020023602000f0b2003200541ecc1c2800010f980808000000b2004200341dcc1c28000109681808000000bae0201057f024002402001280200220128020422020d00410121030c010b20012002417f6a22043602044101210320012001280200220541016a36020002400240024002400240024020052d000022064103710e0400010402000b20064102762104410021030c050b20040d010c040b20064104490d020c030b20012002417e6a3602042001200541026a36020020052d000141087420067241ffff03712201410276210420014180024921030c020b20024104490d0120012002417c6a3602042001200541046a360200200541036a2d000041187420052f000141087472200672220141027621042001418080044921030c010b20024105490d0020012002417b6a3602042001200541056a360200200528000122044180808080044921030b20002004360204200020033602000ba90201057f02400240200128020422020d00410121030c010b20012002417f6a22043602044101210320012001280200220541016a36020002400240024002400240024020052d000022064103710e0400010402000b20064102762104410021030c050b20040d010c040b20064104490d020c030b20012002417e6a3602042001200541026a36020020052d000141087420067241ffff03712201410276210420014180024921030c020b20024104490d0120012002417c6a3602042001200541046a360200200541036a2d000041187420052f000141087472200672220141027621042001418080044921030c010b20024105490d0020012002417b6a3602042001200541056a360200200528000122044180808080044921030b20002004360204200020033602000bf40302067f017e024002400240200128020022012802042202450d0020012002417f6a22033602044101210420012001280200220541016a2206360200024002400240024020052d000022074103710e0400010203000b2007410276ad2108410021040c050b2003450d0320012002417e6a3602042001200541026a36020020052d000141087420077241ffff037122014180024921042001410276ad21080c040b20024104490d0320012002417c6a3602042001200541046a360200200541036a2d000041187420052f0001410874722007722201418080044921042001410276ad21080c030b024002400240200741027622030e050102020200020b20024109490d022001200241776a3602042001200541096a36020020052900012208428080808080808080015421040c040b20024105490d0120012002417b6a3602042001200541056a360200200535000122084280808080045421040c030b200741134b0d00200341046a21072002417e6a2104420021084100210203402004417f460d01200120043602042001200641016a22053602002004417f6a210420063100002002410374413871ad86200884210820052106200241016a220241ff01712007490d000b410021042008427f412820034103746b413871ad88560d020b410121040b0b2000200837030820002004ad3703000bef0302067f017e02400240024020012802042202450d0020012002417f6a22033602044101210420012001280200220541016a2206360200024002400240024020052d000022074103710e0400010203000b2007410276ad2108410021040c050b2003450d0320012002417e6a3602042001200541026a36020020052d000141087420077241ffff037122014180024921042001410276ad21080c040b20024104490d0320012002417c6a3602042001200541046a360200200541036a2d000041187420052f0001410874722007722201418080044921042001410276ad21080c030b024002400240200741027622030e050102020200020b20024109490d022001200241776a3602042001200541096a36020020052900012208428080808080808080015421040c040b20024105490d0120012002417b6a3602042001200541056a360200200535000122084280808080045421040c030b200741134b0d00200341046a21072002417e6a2104420021084100210203402004417f460d01200120043602042001200641016a22053602002004417f6a210420063100002002410374413871ad86200884210820052106200241016a220241ff01712007490d000b410021042008427f412820034103746b413871ad88560d020b410121040b0b2000200837030820002004ad3703000b950301037f0240200028020022022802002200413f4b0d00200041027421020240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a20023a00000f0b0240200041ffff004b0d002000410274410172210202402001280200200128020822006b41014b0d0020012000410210b182808000200128020821000b2001200041026a360208200128020420006a20023b00000f0b0240200041ffffffff034b0d002000410274410272210202402001280200200128020822006b41034b0d0020012000410410b182808000200128020821000b2001200041046a360208200128020420006a20023600000f0b02402001280200220320012802082200470d0020012000410110b18280800020012802002103200128020821000b2001280204220420006a41033a00002001200041016a2200360208200228020021020240200320006b41034b0d0020012000410410b18280800020012802042104200128020821000b2001200041046a360208200420006a20023600000bb80404017f017e047f017e23808080800041206b22022480808080000240024020002802002903002203423f560d002003a741027421040240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a20043a00000c010b0240200342ffff00560d002003a7410274410172210402402001280200200128020822006b41014b0d0020012000410210b182808000200128020821000b2001200041026a360208200128020420006a20043b00000c010b0240200342ffffffff03560d002003a7410274410272210402402001280200200128020822006b41034b0d0020012000410410b182808000200128020821000b2001200041046a360208200128020420006a20043600000c010b4113200379a741037622054102746b21060240200128020020012802082204470d0020012004410110b182808000200128020821040b2001200441016a22003602082001280204220720046a20063a0000200541786a21050340200321080240024020012802002000460d00200021040c010b20012000410110b18280800020012802042107200128020821040b2001200441016a2200360208200720046a2008a73a000020084208882103200541016a22050d000b200220033703002008428002540d0020024200370214200241b0cbc480003602102002410136020c200241f0cbc480003602084100200241f8cbc48000200241086a4180ccc4800010a389808000000b200241206a2480808080000ba80101017f23808080800041106b2201248080808000200142888080808001370200200142808080808001370208200041c4006a200110fa86808000200041106a4293888c8f89fdc6ec9e7f370300200042a5e9e3ab9e929adc2c370308200041c0006a410036020020004280808080c000370338200041d8006a410036020020004280808080c000370350200041ef80808000360218200041063a0000200141106a2480808080000bbc0201017f23808080800041f0016b220424808080800020044197ccc48000410910a682808000200441b0cbc4800041002002200310a782808000200441a0ccc4800041062001412010a782808000200441a6ccc480004107200141c0016a412010a782808000200441d0016a41186a22014200370300200441d0016a41106a22034200370300200441d0016a41086a22024200370300200442003703d001200441b0cbc480004100200441d0016a412010a882808000200041186a2001290300370000200041106a2003290300370000200041086a2002290300370000200020042903d001370000410021010340200420016a220041003a0000200041016a41003a0000200041026a41003a0000200041036a41003a0000200041046a41003a0000200141056a220141c801470d000b200441f0016a2480808080000ba40802017f047e23808080800041c0076b2204248080808000200341e0cfc4800041092002412010a78280800020044180036a200341d00110848e8080001a200441d8066a4200370300200441d0066a4200370300200441c8066a4200370300200441a0066a41206a4200370300200441b8066a4200370300200441b0066a4200370300200441a8066a4200370300200442003703a00620044180036a4190ccc480004107200441a0066a41c00010a882808000200441c0016a200441a0066a10b4818080002004200441c0016a10b281808000200441206a200441c0016a41a00110848e8080001a41002102034020044180036a20026a220341003a0000200341016a41003a0000200341026a41003a0000200341036a41003a0000200341046a41003a0000200241056a220241c801470d000b20044180066a41186a2203200141186a29000037030020044180066a41106a200141106a29000037030020044180066a41086a200141086a290000370300200420012900003703800620044180036a20044180066a10b18180800002400240200428028003450d00200441e9016a2004418d036a290000370000200441c0016a41306a20044194036a29000037000020042004290085033700e10120042d0084032102200441a0066a2004419c036a41880110848e8080001a200441c0016a41096a20044180066a41096a290000370000200441c0016a41116a20044180066a41116a290000370000200441c0016a41186a200329000037000020042004290081063700c101200420023a00e001200420042d0080063a00c001200441c0016a41386a200441a0066a41880110848e8080001a20044180036a41206a420037030020044180036a41186a420037030020044180036a41106a420037030020044180036a41086a420037030020044180036a41306a41002902c4c9c48000220537030020044180036a41386a41002902ccc9c480002206370300200441c0036a41002902d4c9c480002207370300200441c8036a41002902dcc9c480002208370300200441d8036a2005370300200441e0036a2006370300200441e8036a2007370300200441f0036a20083703002004420037038003200441002902bcc9c4800022053703a803200420053703d00320044198046a420037030020044190046a420037030020044180036a4188016a420037030020044180046a4200370300200442003703f803200441a0066a20044180036a41a00110848e8080001a0240200441c0016a41206a200441a0066a10b58180800041ff01710d0020044180036a41c0016a200441c0016a41c00110848e8080001a20044180036a200441c00110848e8080001a200041046a20044180036a41800310848e8080001a200041003602000c020b20004101360200200041013a00040c010b20004101360200200041013a00040b200441c0076a2480808080000be80503067f017e077f2380808080004180016b2202248080808000200241206a2203200141086a28020036020020024180013a002420024100360214200242808080801037020c20022001290200370218200241c0006a2002410c6a200220022002200210c68a808000024002400240024020022802742204418080808078460d00200241286a41106a2205200241c0006a41106a290300370300200241286a41086a200241c0006a41086a2903003703002002200229034037032820022802582106200228025c21072002290360210820022802682109200228026c210a2002280270210b2002280278210c200228027c210d02400240200328020022012002410c6a41106a280200220e4f0d002002280218210f0340200f20016a2d000041776a220341174b0d024101200374419380800471450d02200e200141016a2201470d000b2002200e3602200b200020022903283703002000200d36023c2000200c360238200020043602342000200b3602302000200a36022c20002009360228200020083703202000200736021c20002006360218200041106a2005290300370300200041086a200241286a41086a290300370300200228020c450d03200228021041002802c0a3c68000118080808000000c030b200220013602202002200f200e200e200141016a2201200e2001491b10878380800041002d00fca3c680001a200228020421032002280200210e411441002802c8a3c68000118180808000002201450d032001200e36020c200141163602002000418080808078360234200020013602002001200336021002402006450d00200741002802c0a3c68000118080808000000b02402009450d00200a41002802c0a3c68000118080808000000b2004450d01200c41002802c0a3c68000118080808000000c010b2000418080808078360234200020022802403602000b200228020c450d00200228021041002802c0a3c68000118080808000000b20024180016a2480808080000f0b4104411410b280808000000b9d3004077f017e0b7f017e23808080800041c0026b2206248080808000200128020c21070240024002400240024002400240024002400240024002400240024002400240024002400240200141146a2802002208200141106a28020022094f0d002001410c6a210a0340200720086a2d0000220b41776a220c41174b0d024101200c74419380800471450d022001200841016a220836021420092008470d000b200921080b200641a0016a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a20062802a401210c20062802a0012101411441002802c8a3c68000118180808000002208450d012008200136020c200841053602002000418080808078360234200020083602002008200c3602100c110b024002400240200b41db00460d00200b41fb00460d012001200641bf026a4184d5c4800010d58a80800021080c100b200120012d0018417f6a220c3a0018200841016a2108200c41ff0171450d10200120083602140240200820094f0d000340200720086a2d0000220b41776a220c41174b0d0d4101200c74419380800471450d0d2001200841016a220836021420092008470d000b200921080b200641e8006a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a200628026c210c20062802682109411441002802c8a3c68000118180808000002208450d012008200936020c200841023602002008200c3602104200210d418080808078210e0c0c0b200120012d0018417f6a220c3a0018200841016a2108200c41ff0171450d0920012008360214024020082009490d00418080808078210f4180808080782110418080808078210e0c040b20064188026a4104722111418080808078210f4180808080782110418080808078210e410021124100210b0340200a28020021070240024002400240024002400240024002400240024002400240024002400240024002400240024003400240200720086a2d0000220c41776a0e24000003030003030303030303030303030303030303030300030303030303030303030304020b2001200841016a220836021420092008470d000b200921080c180b200c41fd00460d050b200b4101710d012008210b0c0a0b0240200b4101710d002008210b0c0b0b2001200841016a220b360214200b20094f0d0103402007200b6a2d0000220c41776a220841174b0d0a4101200874419380800471450d0a2001200b41016a220b3602142009200b470d000b200921080c020b41012112200641f8006a200720092009200841016a220820092008491b1087838080004100210c41002d00fca3c680001a200628027c210920062802782107411441002802c8a3c68000118180808000002208450d032008200736020c20084108360200200820093602100c150b200841016a21080b4101211220064198016a200720092009200841016a220820092008491b1087838080004100210c41002d00fca3c680001a200628029c0121092006280298012107411441002802c8a3c68000118180808000002208450d022008200736020c20084105360200200820093602100c130b024020124101710d004100210c41f8d7c48000410610e38a8080002108410121120c130b200f418080808078460d0402402010418080808078470d004182d8c48000410d10e38a80800021080c040b200e418080808078460d02200641d8016a41106a200641f0016a41106a280200360200200641d8016a41086a200641f0016a41086a290200370300200620062902f0013703d801201321080c160b4104411410b280808000000b4104411410b280808000000b419ccfc48000410810e38a80800021082010450d00201441002802c0a3c68000118080808000000b20104180808080784621124101210c0240200f0d004100210f0c0f0b201541002802c0a3c68000118080808000000c0e0b4100210c41fed7c48000410410e38a8080002108418080808078210f410121120c0d0b200c4122460d01200c41fd00470d004101211220064190016a200720092009200b41016a220820092008491b1087838080004100210c41002d00fca3c680001a20062802940121092006280290012107411441002802c8a3c68000118180808000002208450d032008200736020c20084115360200200820093602100c0c0b4101211220064180016a200720092009200b41016a220820092008491b1087838080004100210c41002d00fca3c680001a20062802840121092006280280012107411441002802c8a3c68000118180808000002208450d012008200736020c20084111360200200820093602100c0b0b200141003602082001200b41016a36021420064188026a200a2001108a83808000200628028c022108024002402006280288024102460d00200641b4026a200820062802900210fc8980800020062d00b402450d0120062802b80221080b4100210c410121120c0b0b02400240024002400240024020062d00b5020e0400010203000b20124101710d034100210c0240200110d78a8080002208450d00410121120c100b410121122001200820082008200810f68a80800022080d0f0c090b0240200f418080808078460d004100210c4101211241fed7c48000410410e78a80800021080c0f0b0240200110d78a80800022080d0020064188026a2001200820082008200810f78a808000200628028802211320062802a002220f418080808078470d07201321080b4100210c41012112418080808078210f0c0e0b02402010418080808078460d004100210c410121124182d8c48000410d10e78a80800021080c0e0b200110d78a80800022080d0620064188026a2001200820082008200810f58a808000200628028c0221082006280288022210418080808078460d062006280290022116200821140c070b0240200e418080808078460d00410121124100210c419ccfc48000410810e78a80800021080c0f0b0240200110d78a8080002208450d00410121124100210c0c100b20064188026a2001200820082008200810f88a808000200628028c022117200628028802220e418080808078460d0120062802900221180c060b4100210c4101211241f8d7c48000410610e78a80800021080c0b0b410121124100210c201721080c0d0b4104411410b280808000000b4104411410b280808000000b200641f0016a41106a201141106a280200360200200641f0016a41086a201141086a290200370300200620112902003703f00120062802a402211520062903a80221190c010b4100210c4101211241808080807821100c060b4101210b20012802142208200128021022094f0d030c000b0b4104411410b280808000000b4104411410b280808000000b200a28020021070b4101211220064188016a200720092009200841016a220820092008491b1087838080004100210c41002d00fca3c680001a200628028c0121092006280288012107411441002802c8a3c68000118180808000002208450d012008200736020c20084103360200200820093602100b200e418080808078470d010c020b4104411410b280808000000b200e450d00201741002802c0a3c68000118080808000000b02402012450d00201041ffffffff0771450d00201441002802c0a3c68000118080808000000b0240200c0d00200f41808080807872418080808078460d00201541002802c0a3c68000118080808000000b418080808078210e0b200120012d001841016a3a0018200110d98a808000210c02400240200e418080808078460d00200c0d01200641a8016a41106a200641d8016a41106a280200360200200641a8016a41086a200641d8016a41086a290300370300200620062903d8013703a8012018ad422086210d0c060b200c450d060240200c2802000d00200c41086a280200450d00200c28020441002802c0a3c68000118080808000000b200c41002802c0a3c68000118080808000000c060b0240200f450d00201541002802c0a3c68000118080808000000b02402010450d00201441002802c0a3c68000118080808000000b0240200e450d00201741002802c0a3c68000118080808000000b200c21080c050b200641f0006a200720092009200820092008491b10878380800041002d00fca3c680001a2006280274210c20062802702101411441002802c8a3c680001181808080000022080d064104411410b280808000000b0240200b41dd00460d004200210d418080808078210e2001200820082008200810f68a80800022080d01200128020c2109024002400240024002400240024002400240200128021422082001280210220c4f0d0003400240200920086a2d0000220741776a0e24000005050005050505050505050505050505050505050500050505050505050505050503040b2001200841016a2208360214200c2008470d000b200c21080b200641106a2009200c200c200841016a2208200c2008491b10878380800041002d00fca3c680001a2006280214210c20062802102109411441002802c8a3c68000118180808000002208450d032008200936020c200841023602002008200c3602100c090b2001200841016a220836021402402008200c4f0d000340200920086a2d0000220b41776a220741174b0d084101200774419380800471450d082001200841016a2208360214200c2008470d000b200c21080b200641d8006a2009200c200c200841016a2208200c2008491b10878380800041002d00fca3c680001a200628025c210c20062802582109411441002802c8a3c68000118180808000002208450d042008200936020c200841053602002008200c3602100c080b200741dd00460d040b200641086a2009200c200c200841016a2208200c2008491b10878380800041002d00fca3c680001a200628020c210c20062802082109411441002802c8a3c68000118180808000002208450d012008200936020c200841073602002008200c3602100c060b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000b410141f0d7c4800041c8cec4800010e68a80800021080c020b024002400240024002400240024002400240200b41dd00470d00200641e0006a2009200c200c200841016a2208200c2008491b10878380800041002d00fca3c680001a2006280264210c20062802602109411441002802c8a3c68000118180808000002208450d012008200936020c200841153602002008200c3602100c0a0b20064188026a2001200820082008200810f78a808000200628028802210820062802a002220f418080808078460d0920064180026a20064188026a41146a280200360200200641f8016a20064194026a2902003703002006200629028c023703f00120062802a4022115200128020c210702400240024002402001280214220c200128021022094f0d0020062903a8022119034002402007200c6a2d0000220b41776a0e24000005050005050505050505050505050505050505050500050505050505050505050503040b2001200c41016a220c3602142009200c470d000b2009210c0b200641206a200720092009200c41016a220820092008491b10878380800041002d00fca3c680001a2006280224210c20062802202109411441002802c8a3c68000118180808000002208450d042008200936020c200841023602002008200c3602100c090b2001200c41016a220c3602140240200c20094f0d0003402007200c6a2d0000220a41776a220b41174b0d094101200b74419380800471450d092001200c41016a220c3602142009200c470d000b2009210c0b200641c8006a200720092009200c41016a220820092008491b10878380800041002d00fca3c680001a200628024c210c20062802482109411441002802c8a3c68000118180808000002208450d052008200936020c200841053602002008200c3602100c080b200b41dd00460d050b200641186a200720092009200c41016a220820092008491b10878380800041002d00fca3c680001a200628021c210c20062802182109411441002802c8a3c68000118180808000002208450d022008200936020c200841073602002008200c3602100c060b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000b410241f0d7c4800041c8cec4800010e68a80800021080c010b0240024002400240024002400240200a41dd00470d00200641d0006a200720092009200c41016a220820092008491b10878380800041002d00fca3c680001a2006280254210c20062802502109411441002802c8a3c68000118180808000002208450d012008200936020c200841153602002008200c3602100c070b20064188026a2001200820082008200810f58a80800002402006280288022210418080808078470d00200628028c0221080c070b200628028c022114200128020c2107024002400240024002402001280214220c200128021022094f0d002006280290022116034002402007200c6a2d0000220b41776a0e24000005050005050505050505050505050505050505050500050505050505050505050503040b2001200c41016a220c3602142009200c470d000b2009210c0b200641306a200720092009200c41016a220820092008491b10878380800041002d00fca3c680001a2006280234210c20062802302109411441002802c8a3c68000118180808000002208450d052008200936020c200841023602002008200c3602100c090b2001200c41016a220c3602140240200c20094f0d0003402007200c6a2d0000220a41776a220b41174b0d094101200b74419380800471450d092001200c41016a220c3602142009200c470d000b2009210c0b200641386a200720092009200c41016a220820092008491b10878380800041002d00fca3c680001a200628023c210c20062802382109411441002802c8a3c68000118180808000002208450d062008200936020c200841053602002008200c3602100c080b200b41dd00460d010b200641286a200720092009200c41016a220820092008491b10878380800041002d00fca3c680001a200628022c210c20062802282109411441002802c8a3c68000118180808000002208450d032008200936020c200841073602002008200c3602100c060b410341f0d7c4800041c8cec4800010e68a80800021080c050b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000b0240200a41dd00470d00200641c0006a200720092009200c41016a220820092008491b10878380800041002d00fca3c680001a2006280244210c20062802402109411441002802c8a3c68000118180808000002208450d032008200936020c200841153602002008200c3602100c010b20064188026a2001200820082008200810f88a8080000240200628028802220c418080808078470d00200628028c0221080c010b200641c0016a41086a200641f0016a41086a290300370300200641c0016a41106a200641f0016a41106a280200360200200620062903f0013703c001200635029002422086210d200628028c022117200c210e0c050b2010450d00201441002802c0a3c68000118080808000000b200f450d02201541002802c0a3c68000118080808000000c020b4104411410b280808000000b4200210d418080808078210e410041f0d7c4800041c8cec4800010e68a80800021080b0b200120012d001841016a3a0018200110da8a808000210c02400240200e418080808078460d00200c0d01200641a8016a41106a200641c0016a41106a280200360200200641a8016a41086a200641c0016a41086a290300370300200620062903c0013703a8010c020b200c450d020240200c2802000d00200c41086a280200450d00200c28020441002802c0a3c68000118080808000000b200c41002802c0a3c68000118080808000000c020b0240200f450d00201541002802c0a3c68000118080808000000b02402010450d00201441002802c0a3c68000118080808000000b0240200e450d00201741002802c0a3c68000118080808000000b200c21080c010b200020062903a801370204200020163602302000201436022c20002010360228200020193703202000201536021c2000200f3602182000200e36023420002008360200200041146a200641b8016a2802003602002000410c6a200641b0016a2903003702002000200d2017ad843703380c030b2008200110d68a80800021082000418080808078360234200020083602000c020b2006200720092009200820092008491b10878380800041002d00fca3c680001a2006280204210c20062802002101411441002802c8a3c680001181808080000022080d004104411410b280808000000b2008200136020c200841183602002000418080808078360234200020083602002008200c3602100b200641c0026a2480808080000bb50101037f23808080800041106b2202248080808000200241086a200028020c200041106a28020022032003200041146a28020041016a220020032000491b10878380800041002d00fca3c680001a200228020c2103200228020821040240411441002802c8a3c680001181808080000022000d004104411410b280808000000b2000200436020c2000200129020037020020002003360210200041086a200141086a280200360200200241106a24808080800020000b950501077f23808080800041106b220224808080800041002103024002400240200041146a2802002204200041106a28020022054f0d000240200028020c220620046a2d0000220741e500460d00200741c500460d002007412e470d012000200441016a22083602140240200128020822072001280200470d0020012007109c86808000200128020821070b200128020420076a412e3a00002001200128020841016a2207360208024002400240200820054f0d00200441026a2104200620086a2d0000220841506a41ff017141094b0d0120002004360214024020072001280200470d0020012007109c86808000200128020821070b200128020420076a20083a00002001200128020841016a2207360208200420054f0d040340200620046a2d0000220841506a41ff017141094b0d032000200441016a2204360214024020072001280200470d0020012007109c86808000200128020821070b200128020420076a20083a00002001200128020841016a220736020820052004470d000c050b0b200241086a200620052005200441026a220020052000491b10878380800041002d00fca3c680001a200228020c210020022802082101411441002802c8a3c68000118180808000002203450d042003200136020c20034105360200200320003602100c030b2002200620052005200420052004491b10878380800041002d00fca3c680001a2002280204210020022802002101411441002802c8a3c68000118180808000002203450d042003200136020c2003410d360200200320003602100c020b200841207241e500470d0120002008200110c98a80800021030c010b20002007200110c98a80800021030b200241106a24808080800020030f0b4104411410b280808000000b4104411410b280808000000b970501067f23808080800041106b2203248080808000200041146a22042004280200220541016a2204360200024002402001418001490d002001413f7141807f7221062001410676414072210702402002280200200228020822086b41014b0d0020022008410210ab86808000200228020821080b2002200841026a2201360208200228020420086a220820063a0001200820073a00000c010b0240200228020822082002280200470d0020022008109c86808000200228020821080b200228020420086a20013a00002002200228020841016a22013602080b02402004200041106a2802004f0d000240024002400240200028020c20046a2d0000220441556a0e03000401040b2000200541026a36021420012002280200470d020c010b2000200541026a36021420012002280200470d010b20022001109c86808000200228020821010b200228020420016a20043a00002002200228020841016a3602080b200341086a2000200210ca8a808000024002400240024020032d00080d0020032d000941506a41ff0171410a4f0d014100210520002802142201200028021022064f0d02200028020c21070340200720016a2d0000220841506a41ff017141094b0d032000200141016a22013602140240200228020822042002280200470d0020022004109c86808000200228020821040b200228020420046a20083a00002002200228020841016a36020820062001470d000c030b0b200328020c21050c010b2003200028020c2000280210200028021410878380800041002d00fca3c680001a2003280204210220032802002100411441002802c8a3c68000118180808000002205450d012005200036020c2005410d360200200520023602100b200341106a24808080800020050f0b4104411410b280808000000b850301047f23808080800041106b2203248080808000024002400240200141146a2802002204200141106a2802002205490d00200341086a200128020c2005200410878380800041002d00fca3c680001a200328020c210220032802082104411441002802c8a3c68000118180808000002201450d022001200436020c200141053602002000200136020420012002360210410121010c010b2001200441016a36021402400240200128020c20046a2c00002201417f4a0d002001413f7141807f722105200141c00171410676414072210602402002280200200228020822046b41014b0d0020022004410210ab86808000200228020821040b2002200441026a360208200228020420046a220220053a0001200220063a00000c010b0240200228020822042002280200470d0020022004109c86808000200228020821040b200228020420046a20013a00002002200228020841016a3602080b200020013a0001410021010b200020013a0000200341106a2480808080000f0b4104411410b280808000000bd204010a7f23808080800041106b2205248080808000200141146a22062006280200220741016a220836020002400240024002402008200141106a28020022094f0d00200128020c20086a210a200720096b41016a210b41002106024003400240200a20066a2d0000220c41506a220d41ff0171220e410a490d00024020060d00200720066a41016a21080c040b200420066b21060240200c41207241e500460d002000200120022003200610cc8a8080000c050b2000200120022003200610cd8a8080000c040b024020034298b3e6cc99b3e6cc19580d0020034299b3e6cc99b3e6cc19520d02200e41054b0d020b2001200720066a41026a3602142003420a7e200dad42ff01837c2103200b200641016a22066a0d000b2000200120022003200820046a20096b10cc8a8080000c020b2000200120022003200420066b10ce8a8080000c010b2009200841016a220620092006491b2106024020082009490d00200541086a200128020c2009200610878380800041002d00fca3c680001a200528020c210d20052802082101411441002802c8a3c68000118180808000002206450d022006200136020c2006410536020020002006360204200041013602002006200d3602100c010b2005200128020c2009200610878380800041002d00fca3c680001a2005280204210d20052802002101411441002802c8a3c68000118180808000002206450d022006200136020c2006410d36020020002006360204200041013602002006200d3602100b200541106a2480808080000f0b4104411410b280808000000b4104411410b280808000000bd70304017f017c017f017c23808080800041106b22052480808080002003ba21060240024002400240024002400240024020042004411f7522077320076b220741b502490d0003402006440000000000000000610d072004417f4a0d02200644a0c8eb85f3cce17fa32106200441b4026a22042004411f7522077320076b220741b4024b0d000b0b200741037441c0e2c180006a2b030021082004417f4a0d0120062008a321060c050b2005200128020c200141106a280200200141146a28020010878380800041002d00fca3c680001a2005280204210720052802002101411441002802c8a3c68000118180808000002204450d022004200136020c2004410e36020020002004360204200420073602100c010b20062008a222069944000000000000f07f620d03200541086a200128020c200141106a280200200141146a28020010878380800041002d00fca3c680001a200528020c210720052802082101411441002802c8a3c68000118180808000002204450d022004200136020c2004410e36020020002004360204200420073602100b410121040c030b4104411410b280808000000b4104411410b280808000000b2000200620069a20021b390308410021040b20002004360200200541106a2480808080000bed0401077f23808080800041106b220524808080800041012106200141146a22072007280200220741016a220836020002402008200141106a28020022094f0d004101210602400240200128020c20086a2d000041556a0e03010200020b410021060b2001200741026a22083602140b02400240024002400240024002400240200820094f0d002001200841016a2207360214200128020c220a20086a2d000041506a41ff01712208410a4f0d010240200720094f0d000340200a20076a2d000041506a41ff0171220b410a4f0d012001200741016a22073602140240200841cb99b3e6004c0d00200841cc99b3e600470d07200b41074b0d070b2008410a6c200b6a210820092007470d000b0b20060d02200420086b2207411f75418080808078732007200841004a2007200448731b21070c030b200541086a200128020c2009200810878380800041002d00fca3c680001a200528020c210820052802082101411441002802c8a3c68000118180808000002207450d042007200136020c200741053602002000200736020420004101360200200720083602100c060b2005200a2009200710878380800041002d00fca3c680001a2005280204210820052802002101411441002802c8a3c68000118180808000002207450d042007200136020c2007410d3602002000200736020420004101360200200720083602100c050b200420086a2207411f7541808080807873200720084100482007200448731b21070b2000200120022003200710cc8a8080000c030b200020012002200350200610d38a8080000c020b4104411410b280808000000b4104411410b280808000000b200541106a2480808080000b850101047f02400240200141146a2802002205200141106a28020022064f0d00200128020c210702400340200720056a2d0000220841506a41ff017141094b0d012001200541016a220536021420062005470d000c020b0b200841207241e500460d010b2000200120022003200410cc8a8080000f0b2000200120022003200410cd8a8080000bd40804067f017e017f017e23808080800041306b220324808080800002400240024002400240024002400240024002400240024002400240200141146a2802002204200141106a28020022054f0d002001200441016a2206360214200128020c220720046a2d000022084130470d040240200620054f0d00200720066a2d0000220641506a41ff0171410a490d042006412e460d02200641c500460d03200641e500460d030b4200428080808080808080807f20021b21090c0c0b200341186a200128020c2005200410878380800041002d00fca3c680001a200328021c210620032802182105411441002802c8a3c68000118180808000002201450d042001200536020c200141053602002000200136020420004104360200200120063602100c0c0b200341206a200120024200410010cb8a8080002003280220450d0920002003280224360204200041043602000c0b0b200341206a200120024200410010cd8a8080002003280220450d0820002003280224360204200041043602000c0a0b200341086a200720052005200441026a220120052001491b10878380800041002d00fca3c680001a200328020c210620032802082105411441002802c8a3c68000118180808000002201450d022001200536020c2001410d3602002000200136020420004104360200200120063602100c090b02402008414f6a41ff01714109490d00200341106a20072005200610878380800041002d00fca3c680001a2003280214210620032802102105411441002802c8a3c68000118180808000002201450d032001200536020c2001410d3602002000200136020420004104360200200120063602100c090b200841506aad42ff01832109200620054f0d0403400240200720066a2d0000220a41506a220441ff01712208410a490d0002400240200a412e460d00200a41c500460d01200a41e500460d010c080b41002106200341206a200120022009410010cb8a8080002003280220450d0620002003280224360204200041043602000c0b0b41002106200341206a200120022009410010cd8a8080002003280220450d0520002003280224360204200041043602000c0a0b0240024020094299b3e6cc99b3e6cc19540d0020094299b3e6cc99b3e6cc19520d01200841054b0d010b2001200641016a22063602142009420a7e2004ad42ff01837c210920052006470d010c060b0b200341206a20012002200910d08a808000024020032802200d00200020032b0328390308200041003602000c090b20002003280224360204200041043602000c080b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000b2003290328210b0c010b4101210602402002450d002009210b0c010b0240420020097d220b4200590d00410221060c010b2009babd428080808080808080807f85210b410021060b2000200b370308200020063602000c020b20032903282109410021020b20002009370308200020023602000b200341306a2480808080000bc30101057f4100210402400240200141106a2802002205200141146a28020022064d0d00200641016a2107200520066b2108200128020c20066a21054100210403400240200520046a2d0000220641506a41ff0171410a490d002006412e460d030240200641c500460d00200641e500470d030b2000200120022003200410cd8a8080000f0b2001200720046a3602142008200441016a2204470d000b200821040b2000200120022003200410cc8a8080000f0b2000200120022003200410cb8a8080000bd30501077f23808080800041206b2201248080808000200028020c21020240024002400240024002400240200041146a2802002203200041106a28020022044f0d002000200341016a22053602140240200220036a2d000022064130470d00200520044f0d05200220056a2d000041506a41ff0171410a490d030c050b2006414f6a41ff017141084d0d01200521030b200141186a20022004200310878380800041002d00fca3c680001a200128021c210020012802182105411441002802c8a3c68000118180808000002203450d022003200536020c2003410d360200200320003602100c040b200520044f0d020340200220056a2d000041506a41ff017141094b0d032000200541016a220536021420042005470d000b410021030c030b200141086a200220042004200341026a220020042000491b10878380800041002d00fca3c680001a200128020c2100200128020821050240411441002802c8a3c68000118180808000002203450d002003200536020c2003410d360200200320003602100c030b4104411410b280808000000b4104411410b280808000000b41002103200520044f0d00024002400240200220056a2d0000220641e500460d00200641c500460d002006412e470d032000200541016a2206360214200620044f0d01200220066a2d000041506a41ff017141094b0d01200541026a2105034020042005460d03200220056a2106200541016a2207210520062d0000220641506a41ff0171410a490d000b20002007417f6a360214200641207241e500470d030b200010d28a80800021030c020b200141106a200220042004200541026a220020042000491b10878380800041002d00fca3c680001a2001280214210020012802102105411441002802c8a3c68000118180808000002203450d022003200536020c2003410d360200200320003602100c010b200020043602140b200141206a24808080800020030f0b4104411410b280808000000bc00201057f23808080800041106b2201248080808000200041146a22022002280200220241016a2203360200200028020c210402402003200041106a28020022054f0d000240200420036a2d000041556a0e03000100010b2000200241026a22033602140b0240024002400240200320054f0d002000200341016a2202360214200420036a2d000041506a41ff017141094d0d01200221030b200141086a20042005200310878380800041002d00fca3c680001a200128020c210220012802082100411441002802c8a3c68000118180808000002203450d022003200036020c2003410d360200200320023602100c010b41002103200220054f0d000340200420026a2d000041506a41ff017141094b0d012000200241016a220236021420052002470d000b0b200141106a24808080800020030f0b4104411410b280808000000ba40201027f23808080800041106b220524808080800002400240024002402004450d002003450d010b200141146a2802002204200141106a28020022034f0d01200128020c21060340200620046a2d000041506a41ff0171410a4f0d022001200441016a220436021420032004470d000c020b0b200541086a200128020c200141106a280200200141146a28020010878380800041002d00fca3c680001a200528020c2101200528020821030240411441002802c8a3c68000118180808000002204450d002004200336020c2004410e3602002000200436020420042001360210410121040c020b4104411410b280808000000b200044000000000000000044000000000000008020021b390308410021040b20002004360200200541106a2480808080000b910802067f027e23808080800041c0006b220324808080800041002d00fca3c680001a02400240024002400240411041002802c8a3c68000118180808000002204450d002003410036022c2003200436022820034110360224024020020d002004412d3a00002003200328022c41016a36022c0b200341306a2001200341246a10ca8a80800020032d00300d0102400240024020032d003122044130470d000240200141146a2802002204200141106a28020022054f0d00200128020c220620046a2d000041506a41ff0171410a490d020b2001200341246a10c88a80800021010c070b2004414f6a41ff017141084b0d010240200141146a2802002204200141106a28020022074f0d00200128020c21080340200820046a2d0000220641506a41ff017141094b0d012001200441016a22043602140240200328022c22052003280224470d00200341246a2005109c86808000200328022c21050b200328022820056a20063a00002003200328022c41016a36022c20072004470d000b0b2001200341246a10c88a80800021010c060b200341106a200620052005200441016a220120052001491b10878380800041002d00fca3c680001a2003280214210420032802102105411441002802c8a3c68000118180808000002201450d032001200536020c2001410d360200200120043602100c050b200341186a200128020c200141106a280200200141146a28020010878380800041002d00fca3c680001a200328021c210420032802182105411441002802c8a3c68000118180808000002201450d032001200536020c2001410d360200200120043602100c040b4101411010b280808000000b200328023421010c020b4104411410b280808000000b4104411410b280808000000b02400240024002400240024020010d00024020020d00200341306a2003280228200328022c410a10d28080800020032d00300d0520002003290338370308200041023602000c040b200328022c2204450d040240200328022822012d000041556a0e03000302030b2004417f6a2204450d04200141016a21010c020b20004104360200200020013602040c020b20044101460d020b0240024020044111490d004200210903402004450d02200320094200420a420010878e80800020012d000041506a220241094b0d0420032903084200520d04200141016a21012004417f6a21042003290300220a2002ad7c2209200a5a0d000c040b0b42002109034020012d000041506a220241094b0d03200141016a21012009420a7e2002ad7c21092004417f6a22040d000b0b20002009370308200041013602000b2003280224450d01200328022841002802c0a3c68000118080808000000c010b20004103360200200020032902243702042000410c6a2003412c6a2802003602000b200341c0006a2480808080000bc30e02087f017e2380808080004180016b2203248080808000200028020c2104024002400240024002400240024002400240024002400240200041146a2802002205200041106a28020022064f0d00024002400240024002400240024002400240024002400240200420056a2d0000220741a57f6a0e21040b0b0b0b0b0b0b0b0b0b030b0b0b0b0b0b0b010b0b0b0b0b020b0b0b0b0b0b05000b2007415e6a0e0c090a0a0a0a0a0a0a0a0a0a080a0b2000200541016a2207360214200720064f0d132000200541026a22083602140240200420076a2d000041f500470d00200820062007200620074b1b2207460d142000200541036a22093602140240200420086a2d000041ec00460d00200921080c010b20092007460d142000200541046a2208360214200420096a2d000041ec00460d050b200341186a20042006200810878380800041002d00fca3c680001a200328021c210520032802182104411441002802c8a3c68000118180808000002200450d0d2000200436020c20004109360200200020053602100c140b2000200541016a2207360214200720064f0d112000200541026a22083602140240200420076a2d000041f200470d00200820062007200620074b1b2207460d122000200541036a22093602140240200420086a2d000041f500460d00200921080c010b20092007460d122000200541046a2208360214200420096a2d000041e500460d050b200341286a20042006200810878380800041002d00fca3c680001a200328022c210520032802282104411441002802c8a3c68000118180808000002200450d0d2000200436020c20004109360200200020053602100c130b2000200541016a2207360214200720064f0d0f2000200541026a22083602140240200420076a2d000041e100470d00200820062007200620074b1b2207460d102000200541036a22093602140240200420086a2d000041ec00460d00200921080c010b20092007460d102000200541046a220a3602140240200420096a2d000041f300460d00200a21080c010b200a2007460d102000200541056a22083602142004200a6a2d000041e500460d050b200341386a20042006200810878380800041002d00fca3c680001a200328023c210520032802382104411441002802c8a3c68000118180808000002200450d0d2000200436020c20004109360200200020053602100c120b2003410a3a0070200341f0006a20012002108383808000200010d68a80800021000c110b2003410b3a0070200341f0006a20012002108383808000200010d68a80800021000c100b200341073a0070200341f0006a20012002108383808000200010d68a80800021000c0f0b20034180023b0170200341f0006a20012002108383808000200010d68a80800021000c0e0b200341003b0170200341f0006a20012002108383808000200010d68a80800021000c0d0b2000200541016a360214200341f0006a2000410010d48a80800020032802704104460d04200341c0006a41086a200341f0006a41086a29030037030020032003290370370340200341c0006a2001200210f682808000200010d68a80800021000c0c0b200041003602082000200541016a360214200341e4006a2000410c6a2000108a83808000024020032802644102460d002003290268210b200341053a00702003200b370274200341f0006a20012002108383808000200010d68a80800021000c0c0b200328026821000c0b0b200741506a41ff0171410a490d010b200341086a200420062006200541016a220520062005491b10878380800041002d00fca3c680001a200328020c210420032802082106411441002802c8a3c68000118180808000002205450d052005200636020c2005410a360200200520043602102005200010d68a80800021000c090b200341f0006a2000410110d48a80800020032802704104460d00200341d0006a41086a200341f0006a41086a29030037030020032003290370370350200341d0006a2001200210f682808000200010d68a80800021000c080b200328027421000c070b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000b200341306a20042006200710878380800041002d00fca3c680001a20032802342105200328023021040240411441002802c8a3c68000118180808000002200450d002000200436020c20004105360200200020053602100c030b4104411410b280808000000b200341206a20042006200710878380800041002d00fca3c680001a20032802242105200328022021040240411441002802c8a3c68000118180808000002200450d002000200436020c20004105360200200020053602100c020b4104411410b280808000000b200341106a20042006200710878380800041002d00fca3c680001a2003280214210520032802102104411441002802c8a3c68000118180808000002200450d012000200436020c20004105360200200020053602100b20034180016a24808080800020000f0b4104411410b280808000000be80101047f23808080800041206b220224808080800002400240200028020c450d00200021010c010b200241106a41086a2203200041086a28020036020020022000290200370310200241086a200128020c200141106a280200200141146a28020010878380800041002d00fca3c680001a200228020c2104200228020821050240411441002802c8a3c680001181808080000022010d004104411410b280808000000b200120022903103702002001200536020c20012004360210200141086a2003280200360200200041002802c0a3c68000118080808000000b200241206a24808080800020010b990301047f23808080800041106b2201248080808000200028020c2102024002400240024002400240200041146a2802002203200041106a28020022044f0d0003400240200220036a2d000041776a0e320000040400040404040404040404040404040404040404000404040404040404040404040404040404040404040404040403040b2000200341016a220336021420042003470d000b200421030b200141086a200220042004200341016a220320042003491b10878380800041002d00fca3c680001a200128020c210020012802082104411441002802c8a3c68000118180808000002203450d032003200436020c20034103360200200320003602100c020b2000200341016a360214410021030c010b2001200220042004200341016a220320042003491b10878380800041002d00fca3c680001a2001280204210020012802002104411441002802c8a3c68000118180808000002203450d022003200436020c20034106360200200320003602100b200141106a24808080800020030f0b4104411410b280808000000b4104411410b280808000000ba60101037f23808080800041106b2202248080808000200241086a200028020c200041106a280200200041146a28020010878380800041002d00fca3c680001a200228020c2103200228020821040240411441002802c8a3c680001181808080000022000d004104411410b280808000000b2000200436020c2000200129020037020020002003360210200041086a200141086a280200360200200241106a24808080800020000b900401057f23808080800041206b2201248080808000200028020c2102024002400240024002400240024002400240200041146a2802002203200041106a28020022044f0d0003400240200220036a2d0000220541776a0e24000004040004040404040404040404040404040404040400040404040404040404040406030b2000200341016a220336021420042003470d000b200421030b200141106a200220042004200341016a220320042003491b10878380800041002d00fca3c680001a2001280214210420012802102100411441002802c8a3c68000118180808000002203450d052003200036020c20034103360200200320043602100c040b200541fd00460d010b200141086a200220042004200341016a220320042003491b10878380800041002d00fca3c680001a200128020c210420012802082100411441002802c8a3c68000118180808000002203450d042003200036020c20034116360200200320043602100c020b2000200341016a360214410021030c010b200141186a200220042004200341016a220320042003491b10878380800041002d00fca3c680001a200128021c210420012802182100411441002802c8a3c68000118180808000002203450d032003200036020c20034115360200200320043602100b200141206a24808080800020030f0b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000bde0501067f23808080800041206b2201248080808000200028020c2102024002400240024002400240024002400240024002400240200041146a2802002203200041106a28020022044f0d0003400240200220036a2d0000220541776a0e24000004040004040404040404040404040404040404040400040404040404040404040406030b2000200341016a220336021420042003470d000b200421030b200141086a200220042004200341016a220320042003491b10878380800041002d00fca3c680001a200128020c210420012802082100411441002802c8a3c68000118180808000002203450d042003200036020c20034102360200200320043602100c080b200541dd00460d010b2001200220042004200341016a220320042003491b10878380800041002d00fca3c680001a2001280204210420012802002100411441002802c8a3c68000118180808000002203450d032003200036020c20034116360200200320043602100c060b2000200341016a360214410021030c050b2000200341016a2203360214200320044f0d030340200220036a2d0000220641776a220541174b0d034101200574419380800471450d032000200341016a220336021420042003470d000b200421030c030b4104411410b280808000000b4104411410b280808000000b200641dd00470d00200141186a200220042004200341016a220320042003491b10878380800041002d00fca3c680001a200128021c210420012802182100411441002802c8a3c68000118180808000002203450d032003200036020c20034115360200200320043602100c010b200141106a200220042004200341016a220320042003491b10878380800041002d00fca3c680001a2001280214210420012802102100411441002802c8a3c68000118180808000002203450d012003200036020c20034116360200200320043602100b200141206a24808080800020030f0b4104411410b280808000000b4104411410b280808000000bf20601057f23808080800041106b220424808080800002400240024002400240200241c0006a22050d0020044201370204200420053602000c010b2005417f4c0d034100210641002d00fca3c680001a200541002802c8a3c68000118180808000002207450d022004410036020820042007360204200420053602002002450d010b200120026a210541002106034002400240024020012c00002202417f4c0d00200141016a2101200241ff017121020c010b20012d0001413f7121072002411f712108024002402002415f4b0d0020084106742007722102200141026a21010c010b200741067420012d0002413f717221070240200241704f0d0020072008410c74722102200141036a21010c010b200741067420012d0003413f71722008411274418080f00071722202418080c400460d04200141046a21010b2002418001490d002004410036020c024002402002418010490d0002402002418080044f0d0020042002413f71418001723a000e20042002410c7641e001723a000c20042002410676413f71418001723a000d410321020c020b20042002413f71418001723a000f2004200241127641f001723a000c20042002410676413f71418001723a000e20042002410c76413f71418001723a000d410421020c010b20042002413f71418001723a000d2004200241067641c001723a000c410221020b0240200428020020066b20024f0d0020042006200210ab86808000200428020821060b200428020420066a2004410c6a200210848e8080001a200620026a21060c010b024020062004280200470d0020042006109c86808000200428020821060b200428020420066a20023a0000200428020841016a21060b2004200636020820012005470d000b0b410021010340413041d700200320016a2d0000220241a001491b20024104766a2105024020062004280200470d0020042006109c86808000200428020821060b200428020420066a20053a00002004200428020841016a2206360208024020062004280200470d0020042006109c86808000200428020821060b200428020420066a413041d7002002410f712206410a491b20066a3a00002004200428020841016a2206360208200141016a22014120470d000b20002004290200370200200041086a200441086a280200360200200441106a2480808080000f0b4101200510b280808000000b10ae80808000000beb0601057f23808080800041106b220524808080800041012106024002400240200441017420026a2207450d002007417f4c0d0241002d00fca3c680001a200741002802c8a3c68000118180808000002206450d010b4100210820054100360208200520063602042005200736020002402002450d00200120026a210741002108034002400240024020012c00002202417f4c0d00200141016a2101200241ff017121020c010b20012d0001413f7121062002411f712109024002402002415f4b0d0020094106742006722102200141026a21010c010b200641067420012d0002413f717221060240200241704f0d0020062009410c74722102200141036a21010c010b200641067420012d0003413f71722009411274418080f00071722202418080c400460d04200141046a21010b2002418001490d002005410036020c024002402002418010490d0002402002418080044f0d0020052002413f71418001723a000e20052002410c7641e001723a000c20052002410676413f71418001723a000d410321020c020b20052002413f71418001723a000f2005200241127641f001723a000c20052002410676413f71418001723a000e20052002410c76413f71418001723a000d410421020c010b20052002413f71418001723a000d2005200241067641c001723a000c410221020b0240200528020020086b20024f0d0020052008200210ab86808000200528020821080b200528020420086a2005410c6a200210848e8080001a200820026a21080c010b024020082005280200470d0020052008109c86808000200528020821080b200528020420086a20023a0000200528020841016a21080b2005200836020820012007470d000b0b02402004450d000340413041d70020032d0000220141a001491b20014104766a2102024020082005280200470d0020052008109c86808000200528020821080b200528020420086a20023a00002005200528020841016a2208360208024020082005280200470d0020052008109c86808000200528020821080b200341016a2103200528020420086a413041d7002001410f712208410a491b20086a3a00002005200528020841016a22083602082004417f6a22040d000b0b20002005290200370200200041086a200541086a280200360200200541106a2480808080000f0b4101200710b280808000000b10ae80808000000b3c00200128021420002802002d00004102742200419cd8c480006a28020020004190d8c480006a280200200141186a28020028020c118280808000000be10101037f024002400240024002402002411c6a2802000e020002010b410041004194d7c4800010f980808000000b20022802182203280204220420032802002203490d0220042001280200220128020822054d0d012004200541b4d7c48000109581808000000b4101410141a4d7c4800010f980808000000b200128020421012000200420036b3602042000200120036a3602002000200229020c370208200041106a200241146a28020036020002402002280200450d00200228020441002802c0a3c68000118080808000000b0f0b2003200441b4d7c48000109681808000000b02000b02000b6301017f02402000280200220041e4016a280200450d00200041e8016a28020041002802c0a3c68000118080808000000b02402000417f460d00200020002802042201417f6a36020420014101470d00200041002802c0a3c68000118080808000000b0b4c01027f024020002802002201417f460d0020002802042102200120012802042200417f6a36020420004101470d002002410b6a4104490d00200141002802c0a3c68000118080808000000b0b7801017f23808080800041306b22022480808080002002200136020c200220003602082002411c6a420137020020024102360214200241fccfc48000360210200241e08180800036022c2002200241286a3602182002200241086a360228200241106a10e48a8080002101200241306a24808080800020010b850201037f23808080800041106b22012480808080002000410c6a28020021020240024002400240024002400240024020002802040e020001020b20020d01410121034100210041b0cbc4800021020c030b2002450d010b200141046a200010b8808080000c020b2000280200220028020021020240200028020422000d0041012103410021000c010b2000417f4c0d0241002d00fca3c680001a200041002802c8a3c68000118180808000002203450d030b20032002200010848e80800021022001200036020c20012002360208200120003602040b200141046a1082838080002100200141106a24808080800020000f0b10ae80808000000b4101200010b280808000000bfa0101017f23808080800041c0006b22042480808080002004200136020c200420003602080240024020030d002004411c6a420137020020044102360214200441b4d0c48000360210200441e08180800036022c2004200441286a3602182004200441086a360228200441106a10e48a80800021030c010b200441286a410c6a41dc83808000360200200441106a410c6a420237020020044102360214200441d0d0c48000360210200441e08180800036022c2004200336023c200420023602382004200441286a3602182004200441386a3602302004200441086a360228200441106a10e48a80800021030b200441c0006a24808080800020030b9f0101017f23808080800041c0006b220324808080800020032002360214200320013602102003200036020c200341186a410c6a4202370200200341306a410c6a41dd838080003602002003410236021c200341fcd0c4800036021820034185808080003602342003200341306a3602202003200341106a36023820032003410c6a360230200341186a10e48a8080002102200341c0006a24808080800020020b7801017f23808080800041306b22022480808080002002200136020c200220003602082002411c6a420137020020024102360214200241a0d1c48000360210200241e08180800036022c2002200241286a3602182002200241086a360228200241106a10e48a8080002101200241306a24808080800020010bfa0101017f23808080800041c0006b22042480808080002004200136020c200420003602080240024020030d002004411c6a420137020020044102360214200441dcd1c48000360210200441e08180800036022c2004200441286a3602182004200441086a360228200441106a10e48a80800021030c010b200441286a410c6a41dc83808000360200200441106a410c6a420237020020044102360214200441ecd1c48000360210200441e08180800036022c2004200336023c200420023602382004200441286a3602182004200441386a3602302004200441086a360228200441106a10e48a80800021030b200441c0006a24808080800020030bfb0c02067f017e23808080800041d0006b22022480808080002001280200220328020c2104024002400240024002400240024002400240024002400240200341146a2802002205200341106a28020022064f0d0003400240200420056a2d0000220741776a0e24000004040004040404040404040404040404040404040400040404040404040404040406030b2003200541016a220536021420062005470d000b200621050b200241186a200420062006200541016a220520062005491b10878380800041002d00fca3c680001a200228021c210620022802182103411441002802c8a3c68000118180808000002205450d052005200336020c200541023602002000200536020820004202370300200520063602100c0a0b200741dd00460d010b20012d0004450d020c060b200042003703000c070b20012d00040d042003200541016a22053602140240200520064f0d000340200420056a2d0000220741776a220141174b0d074101200174419380800471450d072003200541016a220536021420062005470d000b200621050b200241206a200420062006200541016a220520062005491b10878380800041002d00fca3c680001a2002280224210620022802202103411441002802c8a3c68000118180808000002205450d032005200336020c200541053602002000200536020820004202370300200520063602100c060b2002200420062006200541016a220520062005491b10878380800041002d00fca3c680001a2002280204210620022802002103411441002802c8a3c68000118180808000002205450d012005200336020c200541073602002000200536020820004202370300200520063602100c050b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000b200141003a00040b0240024002400240200741dd00470d00200241086a200420062006200541016a220520062005491b10878380800041002d00fca3c680001a200228020c210620022802082103411441002802c8a3c68000118180808000002205450d012005200336020c200541153602002000200536020820004202370300200520063602100c040b024002400240024002400240200520064f0d0003400240200420056a2d0000220741776a0e2500000404000404040404040404040404040404040404040004040404040404040404040403040b2003200541016a220536021420062005470d000b200621050b200241106a200420062006200541016a220520062005491b10878380800041002d00fca3c680001a2002280214210620022802102103411441002802c8a3c68000118180808000002205450d062005200336020c20054105360200200520063602100c040b2003200541016a36021441002105200241286a2003410010cf8a808000200228022822064104460d02200229033021080240024002400240024020060e0400040102000b200241033a003820022008370340200241386a200241cf006a418c84c4800010838380800021040c020b02402008427f570d00410021050c030b200241023a003820022008370340200241386a200241cf006a41accdc4800010858380800021040c010b20022802302106200228022c21052002410b3a0038200241386a200241cf006a418c84c480001083838080002104200541808080807872418080808078460d00200641002802c0a3c68000118080808000000b410121050b20050d010c060b0240200741506a41ff0171410a490d002003200241cf006a41accdc4800010d58a808000200310d68a80800021050c030b200241286a2003410110cf8a808000200228022822054104460d0141002106200229033021080240024002400240024020050e0400040102000b200241033a003820022008370340200241386a200241cf006a418c84c4800010838380800021040c020b02402008427f570d00410021060c030b200241023a003820022008370340200241386a200241cf006a41accdc4800010858380800021040c010b20022802302106200228022c21052002410b3a0038200241386a200241cf006a418c84c480001083838080002104200541808080807872418080808078460d00200641002802c0a3c68000118080808000000b410121060b2006450d050b2004200310d68a80800021050c010b200228022c21050b20004202370300200020053602080c030b4104411410b280808000000b4104411410b280808000000b20002008370308200042013703000b200241d0006a2480808080000bcc0101047f23808080800041106b2201248080808000200028020421020240024002400240200028020822030d00410121040c010b2003417f4c0d0141002d00fca3c680001a200341002802c8a3c68000118180808000002204450d020b20042002200310848e80800021042001200336020c2001200436020820012003360204200141046a108283808000210302402000280200450d00200241002802c0a3c68000118080808000000b200141106a24808080800020030f0b10ae80808000000b4101200310b280808000000bfc1003067f017e037f23808080800041f0016b22022480808080002001280200220328020c2104024002400240024002400240024002400240024002400240200341146a2802002205200341106a28020022064f0d0003400240200420056a2d0000220741776a0e24000004040004040404040404040404040404040404040400040404040404040404040406030b2003200541016a220536021420062005470d000b200621050b200241306a200420062006200541016a220520062005491b10878380800041002d00fca3c680001a2002280234210620022802302103411441002802c8a3c68000118180808000002205450d052005200336020c200541023602002000200536020820004202370300200520063602100c0a0b200741dd00460d010b20012d0004450d020c060b200042003703000c070b20012d00040d042003200541016a22053602140240200520064f0d000340200420056a2d0000220741776a220141174b0d074101200174419380800471450d072003200541016a220536021420062005470d000b200621050b200241386a200420062006200541016a220520062005491b10878380800041002d00fca3c680001a200228023c210620022802382103411441002802c8a3c68000118180808000002205450d032005200336020c200541053602002000200536020820004202370300200520063602100c060b200241086a200420062006200541016a220520062005491b10878380800041002d00fca3c680001a200228020c210620022802082103411441002802c8a3c68000118180808000002205450d012005200336020c200541073602002000200536020820004202370300200520063602100c050b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000b200141003a00040b0240024002400240024002400240024002400240200741dd00470d00200241106a200420062006200541016a220520062005491b10878380800041002d00fca3c680001a2002280214210620022802102103411441002802c8a3c68000118180808000002205450d012005200336020c200541153602002000200536020820004202370300200520063602100c0a0b02400240200520064f0d000340200420056a2d0000220141776a220741174b0d024101200774419380800471450d022003200541016a220536021420062005470d000b200621050b200241286a200420062006200541016a220520062005491b10878380800041002d00fca3c680001a200228022c210620022802282103411441002802c8a3c68000118180808000002205450d022005200336020c20054105360200200520063602100c090b0240200141db00460d002003200241ef016a41d4cdc4800010d58a80800021050c080b200320032d0018417f6a22073a0018200541016a2105200741ff0171450d062003200536021420022003360280010240200520064f0d000340200420056a2d0000220141776a220741174b0d054101200774419380800471450d052003200541016a220536021420062005470d000b200621050b200241206a200420062006200541016a220520062005491b10878380800041002d00fca3c680001a2002280224210620022802202104411441002802c8a3c68000118180808000002205450d022005200436020c20054102360200200520063602100c040b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000b0240200141dd00470d004100200241ef016a41d4cdc4800010e68a80800021050c010b200241003a008401200241c8016a200310af89808000024020022d00c801450d0020022802cc0121050c010b200241a8016a41106a200241df016a290000220837030020024188016a41086a2205200241d7016a29000037030020024188016a41106a2206200837030020024188016a41186a2204200241e7016a2f00003b01002002200241cf016a2900003703880120022800cb01210920022f00c901210a200241c8016a20024180016a10e98a8080000240024020022903c80122084202560d0002402008a70e03000102000b4101200241ef016a41d4cdc4800010e68a80800021050c020b200241e0006a41086a2005290300370300200241e0006a41106a2006290300370300200241e0006a41186a20042f01003b0100200220022903880137036020022903d00121084101210b410021010c020b20022802d00121050b4100210b410121010b41012104200320032d001841016a3a001841002107200310da8a8080002106024020010d00024020060d00200241c0006a41186a200241e0006a41186a2f01003b0100200241c0006a41106a200241e0006a41106a290300370300200241c0006a41086a200241e0006a41086a290300370300200220022903603703400b20064521040240200b0d00024020052802000d00200541086a280200450d00200528020441002802c0a3c68000118080808000000b200541002802c0a3c68000118080808000000b20042107200621050b02402006450d002004450d00024020062802000d00200641086a280200450d00200628020441002802c0a3c68000118080808000000b200641002802c0a3c68000118080808000000b2007450d012000200229034037010e200041266a200241d8006a2f01003b01002000411e6a200241d0006a290300370100200041166a200241c8006a290300370100200020083703282000200936010a2000200a3b0108200042013703000c030b200241186a200420062006200520062005491b10878380800041002d00fca3c680001a200228021c2106200228021821030240411441002802c8a3c68000118180808000002205450d002005200336020c20054118360200200520063602100c020b4104411410b280808000000b2005200310d68a80800021050b20004202370300200020053602080b200241f0016a2480808080000ba80701067f23808080800041d0006b22022480808080002001280200220328020c21040240024002400240024002400240024002400240024002400240200341146a2802002205200341106a28020022064f0d0003400240200420056a2d0000220741776a0e24000004040004040404040404040404040404040404040400040404040404040404040406030b2003200541016a220536021420062005470d000b200621050b200241186a200420062006200541016a220520062005491b10878380800041002d00fca3c680001a200228021c210620022802182103411441002802c8a3c68000118180808000002205450d052005200336020c2005410236020020002005360204200041013a0000200520063602100c0a0b200741dd00460d010b20012d0004450d020c060b200041003b01000c070b20012d00040d042003200541016a22053602140240200520064f0d000340200420056a2d0000220741776a220141174b0d074101200174419380800471450d072003200541016a220536021420062005470d000b200621050b200241206a200420062006200541016a220520062005491b10878380800041002d00fca3c680001a2002280224210620022802202103411441002802c8a3c68000118180808000002205450d032005200336020c2005410536020020002005360204200041013a0000200520063602100c060b200241086a200420062006200541016a220520062005491b10878380800041002d00fca3c680001a200228020c210620022802082103411441002802c8a3c68000118180808000002205450d012005200336020c2005410736020020002005360204200041013a0000200520063602100c050b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000b200141003a00040b0240200741dd00470d00200241106a200420062006200541016a220520062005491b10878380800041002d00fca3c680001a2002280214210620022802102103411441002802c8a3c68000118180808000002205450d022005200336020c2005411536020020002005360204200041013a0000200520063602100c010b2002412c6a200310de87808000024020022d002c0d0020004180023b0100200041026a200229002d3700002000411a6a200241c5006a290000370000200041126a2002413d6a2900003700002000410a6a200241356a2900003700000c010b20002002280230360204200041013a00000b200241d0006a2480808080000f0b4104411410b280808000000b8f0f03067f017e017f23808080800041c0016b22022480808080002001280200220328020c2104024002400240024002400240024002400240024002400240200341146a2802002205200341106a28020022064f0d0003400240200420056a2d0000220741776a0e24000004040004040404040404040404040404040404040400040404040404040404040406030b2003200541016a220536021420062005470d000b200621050b200241206a200420062006200541016a220520062005491b10878380800041002d00fca3c680001a2002280224210620022802202103411441002802c8a3c68000118180808000002205450d052005200336020c200541023602002000200536020820004202370300200520063602100c0a0b200741dd00460d010b20012d0004450d020c060b200042003703000c070b20012d00040d042003200541016a22053602140240200520064f0d000340200420056a2d0000220741776a220141174b0d074101200174419380800471450d072003200541016a220536021420062005470d000b200621050b200241286a200420062006200541016a220520062005491b10878380800041002d00fca3c680001a200228022c210620022802282103411441002802c8a3c68000118180808000002205450d032005200336020c200541053602002000200536020820004202370300200520063602100c060b2002200420062006200541016a220520062005491b10878380800041002d00fca3c680001a2002280204210620022802002103411441002802c8a3c68000118180808000002205450d012005200336020c200541073602002000200536020820004202370300200520063602100c050b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000b200141003a00040b024002400240024002400240024002400240200741dd00470d00200241086a200420062006200541016a220520062005491b10878380800041002d00fca3c680001a200228020c210620022802082103411441002802c8a3c68000118180808000002205450d012005200336020c200541153602002000200536020820004202370300200520063602100c090b02400240200520064f0d000340200420056a2d0000220141776a220741174b0d024101200774419380800471450d022003200541016a220536021420062005470d000b200621050b200241186a200420062006200541016a220520062005491b10878380800041002d00fca3c680001a200228021c210620022802182103411441002802c8a3c68000118180808000002205450d022005200336020c20054105360200200520063602100c080b0240200141db00460d002003200241bf016a41e4cdc4800010d58a80800021070c070b200320032d0018417f6a22073a0018200541016a2105200741ff0171450d0520032005360214200241013a00742002200336027020024198016a200241f0006a10ec8a80800020022d0098010d02024020022d0099014101710d004100200241bf016a41e4cdc4800010e68a80800021070c040b200241f8006a41186a2205200241b2016a290100370300200241f8006a41106a2206200241aa016a290100370300200241f8006a41086a2204200241a2016a2901003703002002200229019a0137037820024198016a200241f0006a10e98a8080000240024020022903980122084202560d0002402008a70e03000102000b4101200241bf016a41e4cdc4800010e68a80800021070c050b200241d0006a41086a2004290300370300200241d0006a41106a2006290300370300200241d0006a41186a20052903003703002002200229037837035020022903a001210841012109410021010c050b20022802a00121070c030b4104411410b280808000000b4104411410b280808000000b200228029c0121070b41002109410121010b41012106200320032d001841016a3a001841002104200310da8a8080002105024020010d00024020050d00200241306a41186a200241d0006a41186a290300370300200241306a41106a200241d0006a41106a290300370300200241306a41086a200241d0006a41086a290300370300200220022903503703300b2005452106024020090d00024020072802000d00200741086a280200450d00200728020441002802c0a3c68000118080808000000b200741002802c0a3c68000118080808000000b20062104200521070b02402005450d002006450d00024020052802000d00200541086a280200450d00200528020441002802c0a3c68000118080808000000b200541002802c0a3c68000118080808000000b2004450d0120002002290330370308200041206a200241306a41186a290300370300200041186a200241306a41106a290300370300200041106a200241386a29030037030020002008370328200042013703000c030b200241106a200420062006200520062005491b10878380800041002d00fca3c680001a20022802142106200228021021030240411441002802c8a3c68000118180808000002205450d002005200336020c20054118360200200520063602100c020b4104411410b280808000000b2007200310d68a80800021050b20004202370300200020053602080b200241c0016a2480808080000bc10301077f23808080800041206b2202248080808000200128020c2103024002400240024002400240200141146a2802002204200141106a28020022054f0d002001410c6a21060340200320046a2d0000220741776a220841174b0d024101200874419380800471450d022001200441016a220436021420052004470d000b200521040b2002200320052005200441016a220420052004491b10878380800041002d00fca3c680001a2002280204210820022802002101411441002802c8a3c68000118180808000002204450d012004200136020c2004410536020020002004360204200041013a0000200420083602100c040b024020074122460d002001200241146a41d4d4c4800010d58a80800021040c020b200141003602082001200441016a360214200241146a20062001108a838080000240024020022802144102460d002002410c6a2002280218200228021c10ca8680800020022d000c450d01200228021021040c030b20002002280218360204200041013a00000c040b200020022d000d3a0001410021040c020b4104411410b280808000000b20002004200110d68a808000360204410121040b200020043a00000b200241206a2480808080000b860703067f027e027f23808080800041306b2202248080808000200128020c2103024002400240200141146a2802002204200141106a28020022054f0d000340200320046a2d0000220641776a220741174b0d024101200774419380800471450d022001200441016a220436021420052004470d000b200521040b410121072002200320052005200441016a220420052004491b10878380800041002d00fca3c680001a20022802042101200228020021050240411441002802c8a3c68000118180808000002204450d002004200536020c2004410536020020002004360204200420013602100c020b4104411410b280808000000b024002400240024002400240200641db00470d00200120012d0018417f6a22073a0018200441016a21040240200741ff01710d00200241086a200320052005200420052004491b10878380800041002d00fca3c680001a200228020c210720022802082101411441002802c8a3c68000118180808000002204450d022004200136020c2004411836020020002004360204200420073602100c060b20012004360214200241013a001420022001360210200241186a200241106a10e98a808000024002400240200229031822084202510d000240200850450d0041002002412f6a41f4cdc4800010e68a80800021050c020b20022903202108200241186a200241106a10e98a8080000240200229031822094202560d0002402009a70e03000102000b41012002412f6a41f4cdc4800010e68a80800021050c020b2002290320210941012106410021070c020b200228022021050b41002106410121070b41012103200120012d001841016a3a0018200110da8a80800021042005210a20070d022004210a20040d024101210b0c030b20012002412f6a41f4cdc4800010d58a808000210a0c030b4104411410b280808000000b410021032007210b0b024020072006720d00024020052802000d00200541086a280200450d00200528020441002802c0a3c68000118080808000000b200541002802c0a3c68000118080808000000b02402004410047200b71450d00024020042802000d00200441086a280200450d00200428020441002802c0a3c68000118080808000000b200441002802c0a3c68000118080808000000b2003450d0020002008370308200041106a2009370300410021070c020b2000200a200110d68a8080003602040b410121070b20002007360200200241306a2480808080000b900501087f23808080800041206b2201248080808000200028020c21020240024002400240200041146a2802002203200041106a28020022044f0d00410020046b2105200341046a21030340200220036a2206417c6a2d0000220741776a220841174b0d024101200874419380800471450d0220002003417d6a3602142005200341016a22036a4104470d000b200421030b2001200220042004200341016a220320042003491b10878380800041002d00fca3c680001a20012802042103200128020021000240411441002802c8a3c68000118180808000002208450d002008200036020c20084105360200200820033602100c020b4104411410b280808000000b024002400240200741ee00470d0020002003417d6a2208360214200820044f0d0220002003417e6a2205360214024002402006417d6a2d000041f500460d00200521030c010b200520042008200420084b1b2208460d0320002003417f6a220536021402402006417e6a2d000041ec00460d00200521030c010b20052008460d0320002003360214410021082006417f6a2d000041ec00460d040b200141106a20022004200310878380800041002d00fca3c680001a2001280214210320012802102100411441002802c8a3c68000118180808000002208450d012008200036020c20084109360200200820033602100c030b20002001411f6a41e4d4c4800010d58a808000200010d68a80800021080c020b4104411410b280808000000b200141086a20022004200810878380800041002d00fca3c680001a200128020c210320012802082100411441002802c8a3c68000118180808000002208450d012008200036020c20084105360200200820033602100b200141206a24808080800020080f0b4104411410b280808000000bc60702067f017e23808080800041e0006b2202248080808000200128020c21030240024002400240200141146a2802002204200141106a28020022054f0d000340200320046a2d0000220641776a220741174b0d024101200774419380800471450d022001200441016a220436021420052004470d000b200521040b2002200320052005200441016a220420052004491b10878380800041002d00fca3c680001a20022802042107200228020021010240411441002802c8a3c68000118180808000002204450d002004200136020c20044105360200200020043602042000418080808078360200200420073602100c020b4104411410b280808000000b0240024002400240200641db00470d00200120012d0018417f6a22073a0018200441016a2104200741ff0171450d0320012004360214200241013a0018200220013602142002410036022420024280808080800137021c200241286a41086a2104024002400340200241286a200241146a10ed8a8080000240200229032822084201510d0020084202520d02200228023021070240200228021c450d00200228022041002802c0a3c68000118080808000000b41808080807821040c030b024020022802242205200228021c470d002002411c6a2005109a86808000200228022421050b2002280220200541286c6a22072004290300370300200741086a200441086a290300370300200741106a200441106a290300370300200741186a200441186a290300370300200741206a200441206a2903003703002002200541016a3602240c000b0b200228021c210420022802202107200228022421030b200120012d001841016a3a0018200110da8a8080002105024002402004418080808078460d002005450d0120040d03200521070c040b2005450d03024020052802000d00200541086a280200450d00200528020441002802c0a3c68000118080808000000b200541002802c0a3c68000118080808000000c030b2000200336020820002007360204200020043602000c040b2001200241df006a4194d4c4800010d58a80800021070c010b200741002802c0a3c6800011808080800000200521070b2007200110d68a80800021042000418080808078360200200020043602040c010b200241086a200320052005200420052004491b10878380800041002d00fca3c680001a200228020c210720022802082101411441002802c8a3c68000118180808000002204450d012004200136020c20044118360200200020043602042000418080808078360200200420073602100b200241e0006a2480808080000f0b4104411410b280808000000bc60702067f017e23808080800041e0006b2202248080808000200128020c21030240024002400240200141146a2802002204200141106a28020022054f0d000340200320046a2d0000220641776a220741174b0d024101200774419380800471450d022001200441016a220436021420052004470d000b200521040b2002200320052005200441016a220420052004491b10878380800041002d00fca3c680001a20022802042107200228020021010240411441002802c8a3c68000118180808000002204450d002004200136020c20044105360200200020043602042000418080808078360200200420073602100c020b4104411410b280808000000b0240024002400240200641db00470d00200120012d0018417f6a22073a0018200441016a2104200741ff0171450d0320012004360214200241013a0018200220013602142002410036022420024280808080800137021c200241286a41086a2104024002400340200241286a200241146a10eb8a8080000240200229032822084201510d0020084202520d02200228023021070240200228021c450d00200228022041002802c0a3c68000118080808000000b41808080807821040c030b024020022802242205200228021c470d002002411c6a2005109a86808000200228022421050b2002280220200541286c6a22072004290300370300200741086a200441086a290300370300200741106a200441106a290300370300200741186a200441186a290300370300200741206a200441206a2903003703002002200541016a3602240c000b0b200228021c210420022802202107200228022421030b200120012d001841016a3a0018200110da8a8080002105024002402004418080808078460d002005450d0120040d03200521070c040b2005450d03024020052802000d00200541086a280200450d00200528020441002802c0a3c68000118080808000000b200541002802c0a3c68000118080808000000c030b2000200336020820002007360204200020043602000c040b2001200241df006a41a4d4c4800010d58a80800021070c010b200741002802c0a3c6800011808080800000200521070b2007200110d68a80800021042000418080808078360200200020043602040c010b200241086a200320052005200420052004491b10878380800041002d00fca3c680001a200228020c210720022802082101411441002802c8a3c68000118180808000002204450d012004200136020c20044118360200200020043602042000418080808078360200200420073602100b200241e0006a2480808080000f0b4104411410b280808000000bb10501067f23808080800041306b2202248080808000200128020c21030240024002400240200141146a2802002204200141106a28020022054f0d000340200320046a2d0000220641776a220741174b0d024101200774419380800471450d022001200441016a220436021420052004470d000b200521040b200241086a200320052005200441016a220420052004491b10878380800041002d00fca3c680001a200228020c2107200228020821010240411441002802c8a3c68000118180808000002204450d002004200136020c20044105360200200020043602042000418080808078360200200420073602100c020b4104411410b280808000000b02400240200641db00470d00200120012d0018417f6a22073a0018200441016a21040240200741ff01710d00200241106a200320052005200420052004491b10878380800041002d00fca3c680001a2002280214210720022802102101411441002802c8a3c68000118180808000002204450d042004200136020c20044118360200200020043602042000418080808078360200200420073602100c030b200120043602142002411c6a2001410110b689808000200120012d001841016a3a0018200110da8a808000210402400240200228021c2207418080808078460d002004450d012007450d03200228022041002802c0a3c68000118080808000000c030b2002280220210702402004450d00024020042802000d00200441086a280200450d00200428020441002802c0a3c68000118080808000000b200441002802c0a3c68000118080808000000b200721040c020b20002002290220370204200020073602000c020b20012002412f6a41b4d4c4800010d58a80800021040b2004200110d68a80800021042000418080808078360200200020043602040b200241306a2480808080000f0b4104411410b280808000000b850401067f23808080800041206b2202248080808000200128020c210302400240024002400240200141146a2802002204200141106a28020022054f0d002001410c6a2106034002400240200320046a2d000041776a220741194b0d0041012007744193808004710d0120074119460d040b2001200241146a41c4d4c4800010d58a808000200110d68a80800021042000418080808078360200200020043602040c040b2001200441016a220436021420052004470d000b200521040b200241086a200320052005200441016a220420052004491b10878380800041002d00fca3c680001a200228020c210720022802082101411441002802c8a3c68000118180808000002204450d022004200136020c20044105360200200020043602042000418080808078360200200420073602100c010b20014100360208410121072001200441016a360214200241146a20062001108a838080000240024020022802144102460d0020022802182101200228021c2204450d012004417f4c0d0441002d00fca3c680001a200441002802c8a3c680001181808080000022070d014101200410b280808000000b2000200228021836020420004180808080783602000c010b20072001200410848e80800021072000200436020820002007360204200020043602000b200241206a2480808080000f0b4104411410b280808000000b10ae80808000000bbe13010a7f23808080800041e0006b2206248080808000200128020c2107024002400240200141146a2802002208200141106a28020022094f0d002001410c6a210a0340200720086a2d0000220b41776a220c41174b0d024101200c74419380800471450d022001200841016a220836021420092008470d000b200921080b200641086a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a200628020c210c200628020821010240411441002802c8a3c68000118180808000002208450d002008200136020c200841053602002000200836020420004180808080783602002008200c3602100c020b4104411410b280808000000b02400240024002400240024002400240024002400240200b41db00460d00200b41fb00460d012001200641df006a41f4d4c4800010d58a80800021080c070b200120012d0018417f6a220c3a0018200841016a2108200c41ff0171450d08200120083602140240200820094f0d000340200720086a2d0000220b41776a220c41174b0d064101200c74419380800471450d062001200841016a220836021420092008470d000b200921080b200641186a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a200628021c210c20062802182109411441002802c8a3c68000118180808000002208450d012008200936020c200841023602002008200c360210418080808078210c0c050b200120012d0018417f6a220c3a0018200841016a2108200c41ff0171450d02200120083602140240024002400240024020082009490d00418080808078210d0c010b418080808078210d4100210e0340200a280200210702400240024002400240024002400240024002400240024002400240024003400240200720086a2d0000220c41776a0e24000003030003030303030303030303030303030303030300030303030303030303030304020b2001200841016a220836021420092008470d000b200921080c100b200c41fd00460d050b200e4101710d012008210b0c070b0240200e4101710d002008210b0c080b2001200841016a220b360214200b20094f0d0103402007200b6a2d0000220c41776a220841174b0d074101200874419380800471450d072001200b41016a220b3602142009200b470d000b200921080c020b200641286a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a200628022c210c20062802282109411441002802c8a3c68000118180808000002208450d032008200936020c200841083602002008200c3602100c0d0b200841016a21080b200641c8006a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a200628024c210c20062802482109411441002802c8a3c68000118180808000002208450d022008200936020c200841053602002008200c3602100c0b0b200d210c200f2108200d418080808078470d0e41d8cec48000410b10e38a8080002108418080808078210c0c0e0b4104411410b280808000000b4104411410b280808000000b200c4122460d01200c41fd00470d00200641c0006a200720092009200b41016a220820092008491b10878380800041002d00fca3c680001a2006280244210c20062802402109411441002802c8a3c68000118180808000002208450d032008200936020c200841153602002008200c3602100c070b200641306a200720092009200b41016a220820092008491b10878380800041002d00fca3c680001a2006280234210c20062802302109411441002802c8a3c68000118180808000002208450d012008200936020c200841113602002008200c3602100c060b200141003602082001200b41016a360214200641d0006a200a2001108a838080002006280254210820062802504102460d05024002402006280258220c410b470d00200841c0abc38000410b10888e808000450d010b2008200c41ccabc38000410110e58a80800021080c060b0240200d418080808078460d0041d8cec48000410b10e78a80800021080c070b0240200110d78a8080002208450d00418080808078210c0c0a0b200641d0006a200110f38a808000418080808078210c2006280254210f2006280250220d418080808078470d02200f21080c090b4104411410b280808000000b4104411410b280808000000b2006280258210b4101210e2001280214220820012802102209490d000b200a28020021070b200641386a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a200628023c210c20062802382109411441002802c8a3c68000118180808000002208450d022008200936020c200841033602002008200c3602100b418080808078210c200d418080808078460d030b418080808078210c0240200d450d00200f41002802c0a3c68000118080808000000b0c020b4104411410b280808000000b4104411410b280808000000b200120012d001841016a3a0018200110d98a808000210902400240200c418080808078460d002009450d06200c0d01200921080c050b2009450d04024020092802000d00200941086a280200450d00200928020441002802c0a3c68000118080808000000b200941002802c0a3c68000118080808000000c040b200841002802c0a3c6800011808080800000200921080c030b200641206a200720092009200820092008491b10878380800041002d00fca3c680001a2006280224210c20062802202101411441002802c8a3c680001181808080000022080d054104411410b280808000000b0240200b41dd00470d00418080808078210c410041c8cfc4800041c8cec4800010e68a80800021080c010b200641d0006a200110f38a808000418080808078210c024020062802502209418080808078470d00200628025421080c010b2006280258210b200628025421082009210c0b200120012d001841016a3a0018200110da8a80800021090240200c418080808078460d002009450d020240200c450d00200841002802c0a3c68000118080808000000b200921080c010b2009450d00024020092802000d00200941086a280200450d00200928020441002802c0a3c68000118080808000000b200941002802c0a3c68000118080808000000b2008200110d68a80800021082000418080808078360200200020083602040c030b2000200b360208200020083602042000200c3602000c020b200641106a200720092009200820092008491b10878380800041002d00fca3c680001a2006280214210c20062802102101411441002802c8a3c680001181808080000022080d004104411410b280808000000b2008200136020c200841183602002000200836020420004180808080783602002008200c3602100b200641e0006a2480808080000b8b0901077f23808080800041c0006b2205248080808000200028020c21060240024002400240200041146a2802002207200041106a28020022084f0d002000410c6a21090340200620076a2d0000220a41776a220b41174b0d024101200b74419380800471450d022000200741016a220736021420082007470d000b200821070b200541086a200620082008200741016a220720082007491b10878380800041002d00fca3c680001a200528020c210b200528020821000240411441002802c8a3c68000118180808000002207450d002007200036020c200741053602002007200b3602100c020b4104411410b280808000000b024002400240024002400240200a41db00460d00200a41fb00460d0120002005413f6a41b4d5c4800010d58a808000210b0c020b200020002d0018220a417f6a220b3a0018200741016a2107200b41ff0171450d042000200a3a00182000200736021441002107200010da8a808000220b0d010c050b200020002d0018417f6a220b3a0018200741016a2107200b41ff0171450d022000200736021402400240024002400240200720084f0d000340200620076a2d0000220a41776a220b41194b0d0402404101200b744193808004710d00200b4119470d05200041003602082000200741016a360214200541306a20092000108a8380800020052802304102460d0320052802342005280238419cadc48000410010e58a808000210b0c060b2000200741016a220736021420082007470d000b200821070b200541286a200620082008200741016a220720082007491b10878380800041002d00fca3c680001a200528022c210720052802282108411441002802c8a3c6800011818080800000220b450d01200b200836020c200b4103360200200b20073602100c030b2005280234210b0c020b4104411410b280808000000b0240200a41fd00470d004100210b0c010b200541206a200620082008200741016a220720082007491b10878380800041002d00fca3c680001a2005280224210720052802202108411441002802c8a3c6800011818080800000220b450d02200b200836020c200b4111360200200b20073602100b200020002d001841016a3a0018200010d98a80800021080240200b0d00410021072008210b20080d010c050b2008450d00024020082802000d00200841086a280200450d00200828020441002802c0a3c68000118080808000000b200841002802c0a3c68000118080808000000b200b200010d68a80800021070c030b4104411410b280808000000b200541186a200620082008200720082007491b10878380800041002d00fca3c680001a200528021c210b200528021821000240411441002802c8a3c68000118180808000002207450d002007200036020c200741183602002007200b3602100c020b4104411410b280808000000b200541106a200620082008200720082007491b10878380800041002d00fca3c680001a2005280214210b20052802102100411441002802c8a3c68000118180808000002207450d012007200036020c200741183602002007200b3602100b200541c0006a24808080800020070f0b4104411410b280808000000bd91e030d7f017e017f23808080800041f0016b2206248080808000200128020c2107024002400240024002400240024002400240024002400240024002400240024002400240200141146a2802002208200141106a28020022094f0d002001410c6a210a0340200720086a2d0000220b41776a220c41174b0d024101200c74419380800471450d022001200841016a220836021420092008470d000b200921080b200641e8006a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a200628026c210c20062802682101411441002802c8a3c68000118180808000002208450d012008200136020c200841053602002000418080808078360218200020083602002008200c3602100c100b024002400240200b41db00460d00200b41fb00460d012001200641ef016a41c4d5c4800010d58a80800021080c110b200120012d0018417f6a220c3a0018200841016a2108200c41ff0171450d0e200120083602140240200820094f0d000340200720086a2d0000220b41776a220c41174b0d0b4101200c74419380800471450d0b2001200841016a220836021420092008470d000b200921080b200641306a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a2006280234210c20062802302109411441002802c8a3c68000118180808000002208450d012008200936020c200841023602002008200c360210418080808078210b0c0a0b200120012d0018417f6a220c3a0018200841016a2108200c41ff0171450d0720012008360214024020082009490d00418080808078210d0c040b200641e1016a210e200641d0016a410472210f418080808078210d410321104100210b0340200a28020021070240024002400240024002400240024002400240024002400240024002400240024003400240200720086a2d0000220c41776a0e24000003030003030303030303030303030303030303030300030303030303030303030304020b2001200841016a220836021420092008470d000b200921080c150b200c41fd00460d050b200b4101710d012008210b0c070b0240200b4101710d002008210b0c080b2001200841016a220b360214200b20094f0d0103402007200b6a2d0000220c41776a220841174b0d074101200874419380800471450d072001200b41016a220b3602142009200b470d000b200921080c020b200641c0006a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a2006280244210c20062802402109411441002802c8a3c68000118180808000002208450d032008200936020c200841083602002008200c3602100c120b200841016a21080b200641e0006a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a2006280264210c20062802602109411441002802c8a3c68000118180808000002208450d022008200936020c200841053602002008200c3602100c100b0240200d418080808078460d000240201041ff01714103470d0041e3cec48000410b10e38a8080002108200d450d07201141002802c0a3c68000118080808000000c070b200641a8016a41086a200641c0016a41086a280200360200200620062902c0013703a801200620062800b8013602a0012006200641b8016a41036a2800003600a3012012ad4220862011ad842113201421080c110b41d8cec48000410b10e38a80800021080c050b4104411410b280808000000b4104411410b280808000000b200c4122460d01200c41fd00470d00200641d8006a200720092009200b41016a220820092008491b10878380800041002d00fca3c680001a200628025c210c20062802582109411441002802c8a3c68000118180808000002208450d042008200936020c200841153602002008200c3602100c0c0b200641c8006a200720092009200b41016a220820092008491b10878380800041002d00fca3c680001a200628024c210c20062802482109411441002802c8a3c68000118180808000002208450d022008200936020c200841113602002008200c3602100c0b0b200141003602082001200b41016a360214200641d0016a200a2001108a8380800020062802d401210820062802d0014102460d0a02400240024020062802d801220c410b470d00200841f289c38000410b10888e808000450d01200841fd89c38000410b10888e808000450d020b2008200c41888ac38000410210e58a80800021080c0c0b0240200d418080808078460d0041d8cec48000410b10e78a80800021080c0c0b200110d78a80800022080d01200641d0016a200110f28a80800020062802d4012111024020062802d001220d418080808078470d00201121080c020b20062802d80121120c050b0240201041ff01714103460d0041e3cec48000410b10e78a80800021080c0b0b200110d78a80800022080d0a200641d0016a2001200820082008200810f98a80800020062802d001211420062d00e00122104103470d03201421080c0a0b418080808078210d0c0a0b4104411410b280808000000b4104411410b280808000000b200641c0016a41086a200f41086a2802003602002006200f2902003703c0012006200e2800003602b8012006200e41036a2800003600bb010b4101210b20012802142208200128021022094f0d030c000b0b4104411410b280808000000b4104411410b280808000000b200a28020021070b200641d0006a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a2006280254210c20062802502109411441002802c8a3c68000118180808000002208450d022008200936020c200841033602002008200c3602100b0240200d41808080807872418080808078460d00201141002802c0a3c68000118080808000000b418080808078210d0b200120012d001841016a3a0018418080808078210c2013a72109200110d98a808000210702400240200d418080808078460d0020070d01200641f8006a41086a200641a8016a41086a280200360200200620062903a801370378200620062802a001360270200620062800a301360073200d210c0c070b2007450d06024020072802000d00200741086a280200450d00200728020441002802c0a3c68000118080808000000b200741002802c0a3c68000118080808000000c060b418080808078210c0240200d0d00200721080c060b200941002802c0a3c6800011808080800000200721080c050b4104411410b280808000000b200641386a200720092009200820092008491b10878380800041002d00fca3c680001a200628023c210c20062802382101411441002802c8a3c680001181808080000022080d064104411410b280808000000b0240200b41dd00470d00418080808078210b41004194cfc4800041c8cec4800010e68a80800021080c010b200641d0016a200110f28a808000418080808078210b024020062802d001220a418080808078470d0020062802d40121080c010b20062802d401210d200128020c21090240024002400240024002400240024002400240200128021422082001280210220c4f0d0020063502d801211303400240200920086a2d0000220741776a0e24000005050005050505050505050505050505050505050500050505050505050505050503040b2001200841016a2208360214200c2008470d000b200c21080b200641186a2009200c200c200841016a2208200c2008491b10878380800041002d00fca3c680001a200628021c210c20062802182109411441002802c8a3c68000118180808000002208450d042008200936020c200841023602002008200c3602100c080b2001200841016a220836021402402008200c4f0d000340200920086a2d0000220b41776a220741174b0d084101200774419380800471450d082001200841016a2208360214200c2008470d000b200c21080b200641206a2009200c200c200841016a2208200c2008491b10878380800041002d00fca3c680001a2006280224210c20062802202109411441002802c8a3c68000118180808000002208450d052008200936020c200841053602002008200c3602100c070b200741dd00460d010b200641106a2009200c200c200841016a2208200c2008491b10878380800041002d00fca3c680001a2006280214210c20062802102109411441002802c8a3c68000118180808000002208450d022008200936020c200841073602002008200c3602100c050b41014194cfc4800041c8cec4800010e68a80800021080c040b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000b0240200b41dd00470d00200641286a2009200c200c200841016a2208200c2008491b10878380800041002d00fca3c680001a200628022c210c20062802282109411441002802c8a3c68000118180808000002208450d052008200936020c200841153602002008200c3602100c010b200641d0016a2001200820082008200810f98a80800020062802d001210820062d00e00122104103460d0020064198016a200641dc016a280200360200200620062902d40137039001200620062800e101360288012006200641e4016a28000036008b012013422086200dad842113200a210b0c020b418080808078210b200a450d00200d41002802c0a3c68000118080808000000b0b200120012d001841016a3a0018418080808078210c2013a72109200110da8a808000210702400240200b418080808078460d0020070d01200641f8006a41086a20064190016a41086a280200360200200620062903900137037820062006280288013602702006200628008b01360073200b210c0c020b2007450d01024020072802000d00200741086a280200450d00200728020441002802c0a3c68000118080808000000b200741002802c0a3c68000118080808000000c010b418080808078210c0240200b450d00200941002802c0a3c68000118080808000000b200721080b200c418080808078460d0320002006290378370204200020103a0010200020062802703600112000200936021c2000200c36021820002008360200200041146a2006280073360000200020134220883e02202000410c6a20064180016a2802003602000c040b4104411410b280808000000b200641086a200720092009200820092008491b10878380800041002d00fca3c680001a200628020c210c20062802082101411441002802c8a3c680001181808080000022080d004104411410b280808000000b2008200136020c200841183602002000418080808078360218200020083602002008200c3602100c010b2008200110d68a80800021082000418080808078360218200020083602000b200641f0016a2480808080000bbc13010a7f23808080800041e0006b2206248080808000200128020c2107024002400240200141146a2802002208200141106a28020022094f0d002001410c6a210a0340200720086a2d0000220b41776a220c41174b0d024101200c74419380800471450d022001200841016a220836021420092008470d000b200921080b200641086a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a200628020c210c200628020821010240411441002802c8a3c68000118180808000002208450d002008200136020c200841053602002000200836020420004180808080783602002008200c3602100c020b4104411410b280808000000b02400240024002400240024002400240024002400240200b41db00460d00200b41fb00460d012001200641df006a41a4d5c4800010d58a80800021080c070b200120012d0018417f6a220c3a0018200841016a2108200c41ff0171450d08200120083602140240200820094f0d000340200720086a2d0000220b41776a220c41174b0d064101200c74419380800471450d062001200841016a220836021420092008470d000b200921080b200641186a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a200628021c210c20062802182109411441002802c8a3c68000118180808000002208450d012008200936020c200841023602002008200c360210418080808078210c0c050b200120012d0018417f6a220c3a0018200841016a2108200c41ff0171450d02200120083602140240024002400240024020082009490d00418080808078210d0c010b418080808078210d4100210e0340200a280200210702400240024002400240024002400240024002400240024002400240024003400240200720086a2d0000220c41776a0e24000003030003030303030303030303030303030303030300030303030303030303030304020b2001200841016a220836021420092008470d000b200921080c100b200c41fd00460d050b200e4101710d012008210b0c070b0240200e4101710d002008210b0c080b2001200841016a220b360214200b20094f0d0103402007200b6a2d0000220c41776a220841174b0d074101200874419380800471450d072001200b41016a220b3602142009200b470d000b200921080c020b200641286a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a200628022c210c20062802282109411441002802c8a3c68000118180808000002208450d032008200936020c200841083602002008200c3602100c0d0b200841016a21080b200641c8006a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a200628024c210c20062802482109411441002802c8a3c68000118180808000002208450d022008200936020c200841053602002008200c3602100c0b0b200d210c200f2108200d418080808078470d0e419ccfc48000410810e38a8080002108418080808078210c0c0e0b4104411410b280808000000b4104411410b280808000000b200c4122460d01200c41fd00470d00200641c0006a200720092009200b41016a220820092008491b10878380800041002d00fca3c680001a2006280244210c20062802402109411441002802c8a3c68000118180808000002208450d032008200936020c200841153602002008200c3602100c070b200641306a200720092009200b41016a220820092008491b10878380800041002d00fca3c680001a2006280234210c20062802302109411441002802c8a3c68000118180808000002208450d012008200936020c200841113602002008200c3602100c060b200141003602082001200b41016a360214200641d0006a200a2001108a838080002006280254210820062802504102460d05024002402006280258220c4108470d00200829000041002900f3ebc58000510d010b2008200c41fcebc58000410110e58a80800021080c060b0240200d418080808078460d00419ccfc48000410810e78a80800021080c070b0240200110d78a8080002208450d00418080808078210c0c0a0b200641d0006a200110f18a808000418080808078210c2006280254210f2006280250220d418080808078470d02200f21080c090b4104411410b280808000000b4104411410b280808000000b2006280258210b4101210e2001280214220820012802102209490d000b200a28020021070b200641386a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a200628023c210c20062802382109411441002802c8a3c68000118180808000002208450d022008200936020c200841033602002008200c3602100b418080808078210c200d418080808078460d030b418080808078210c0240200d450d00200f41002802c0a3c68000118080808000000b0c020b4104411410b280808000000b4104411410b280808000000b200120012d001841016a3a0018200110d98a808000210902400240200c418080808078460d002009450d06200c0d01200921080c050b2009450d04024020092802000d00200941086a280200450d00200928020441002802c0a3c68000118080808000000b200941002802c0a3c68000118080808000000c040b200841002802c0a3c6800011808080800000200921080c030b200641206a200720092009200820092008491b10878380800041002d00fca3c680001a2006280224210c20062802202101411441002802c8a3c680001181808080000022080d054104411410b280808000000b0240200b41dd00470d00418080808078210c410041c8cfc4800041c8cec4800010e68a80800021080c010b200641d0006a200110f18a808000418080808078210c024020062802502209418080808078470d00200628025421080c010b2006280258210b200628025421082009210c0b200120012d001841016a3a0018200110da8a80800021090240200c418080808078460d002009450d020240200c450d00200841002802c0a3c68000118080808000000b200921080c010b2009450d00024020092802000d00200941086a280200450d00200928020441002802c0a3c68000118080808000000b200941002802c0a3c68000118080808000000b2008200110d68a80800021082000418080808078360200200020083602040c030b2000200b360208200020083602042000200c3602000c020b200641106a200720092009200820092008491b10878380800041002d00fca3c680001a2006280214210c20062802102101411441002802c8a3c680001181808080000022080d004104411410b280808000000b2008200136020c200841183602002000200836020420004180808080783602002008200c3602100b200641e0006a2480808080000be13205077f017e017f027e057f2380808080004180026b2206248080808000200128020c210702400240024002400240024002400240024002400240024002400240024002400240024002400240200141146a2802002208200141106a28020022094f0d002001410c6a210a0340200720086a2d0000220b41776a220c41174b0d024101200c74419380800471450d022001200841016a220836021420092008470d000b200921080b200641d0016a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a20062802d401210c20062802d0012101411441002802c8a3c68000118180808000002208450d012008200136020c20084105360200200041033a0010200020083602002008200c3602100c120b024002400240200b41db00460d00200b41fb00460d012001200641ff016a4194d5c4800010d58a80800021080c110b200120012d0018417f6a220c3a0018200841016a2108200c41ff0171450d11200120083602140240200820094f0d000340200720086a2d0000220b41776a220c41174b0d0f4101200c74419380800471450d0f2001200841016a220836021420092008470d000b200921080b200641286a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a200628022c210c20062802282109411441002802c8a3c68000118180808000002208450d012008200936020c200841023602002008200c3602104103210c0c0e0b200120012d0018417f6a220c3a0018200841016a2108200c41ff0171450d0b20012008360214200820094f0d084200210d4103210e4100210b0340200a280200210702400240024002400240024002400240024002400240024002400240024002400240024003400240200720086a2d0000220c41776a0e24000003030003030303030303030303030303030303030300030303030303030303030304020b2001200841016a220836021420092008470d000b200921080c1b0b200c41fd00460d050b200b4101710d012008210b0c080b0240200b4101710d002008210b0c090b2001200841016a220b360214200b20094f0d0103402007200b6a2d0000220c41776a220841174b0d084101200874419380800471450d082001200b41016a220b3602142009200b470d000b200921080c020b200641386a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a200628023c210c20062802382109411441002802c8a3c68000118180808000002208450d032008200936020c200841083602002008200c3602104103210c0c180b200841016a21080b200641c8016a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a20062802cc01210c20062802c8012109411441002802c8a3c68000118180808000002208450d022008200936020c200841053602002008200c3602104103210c0c160b200da7450d024103210c0240200e41ff01714103470d004185cec48000410d10e38a80800021080c160b200f422088a72109200fa72108200e210c0c150b4104411410b280808000000b4104411410b280808000000b4103210c4184cec48000410110e38a80800021080c120b200c4122460d01200c41fd00470d00200641c0016a200720092009200b41016a220820092008491b10878380800041002d00fca3c680001a20062802c401210c20062802c0012109411441002802c8a3c68000118180808000002208450d032008200936020c200841153602002008200c3602104103210c0c110b200641c0006a200720092009200b41016a220820092008491b10878380800041002d00fca3c680001a2006280244210c20062802402109411441002802c8a3c68000118180808000002208450d012008200936020c200841113602002008200c3602104103210c0c100b200141003602082001200b41016a360214200641e0016a200a2001108a8380800020062802e4012108024020062802e0014102460d000240024002400240024020062802e801417f6a0e0d00090909090909090909090901090b20082d000041e300460d010c080b200841a9dac28000410d10888e8080000d07200e41ff01714103460d014103210c4185cec48000410d10e78a80800021080c130b200da74101460d05200110d78a80800022080d02200641e0016a200110ef8a80800020062802e0010d0120062903f001211020062903e801210f4201210d0c070b200110d78a80800022080d01200641e0016a200110cb8680800020062d00e0010d0020062d00e101210e0c060b20062802e40121080b4103210c0c0f0b4104411410b280808000000b4104411410b280808000000b4103210c4184cec48000410110e78a80800021080c0c0b4103210c200110d78a80800022080d0820014100360208200128020c210920012802142208200128021022074f0d07410021110340410020076b2112200841026a2108024002400240024002400240024002400240024002400240024002400240024002400240024002400240034002400240200920086a2213417e6a2d0000220b41776a0e2501010808010808080808080808080808080808080808080108060808080808080808080809000b200b41a57f6a0e21060707070707070707070704070707070707070207070707070307070707070706070b20012008417f6a3602142012200841016a22086a4102470d000b200721080c1d0b20012008417f6a220b3602140240200b2007490d002008417f6a210b0c1c0b2001200836021402402013417f6a2d000041f500470d0020082007200b2007200b4b1b220b460d1c2001200841016a2212360214024020132d000041ec00460d00200841016a21080c010b2012200b460d1c2001200841026a360214201341016a2d000041ec00460d08200841026a21080b20064198016a20092007200810878380800041002d00fca3c680001a200628029c0121092006280298012107411441002802c8a3c68000118180808000002208450d0c2008200736020c20084109360200200820093602100c200b20012008417f6a220b3602140240200b2007490d002008417f6a210b0c1a0b2001200836021402402013417f6a2d000041f200470d0020082007200b2007200b4b1b220b460d1a2001200841016a2212360214024020132d000041f500460d00200841016a21080c010b2012200b460d1a2001200841026a360214201341016a2d000041e500460d07200841026a21080b200641a8016a20092007200810878380800041002d00fca3c680001a20062802ac01210920062802a8012107411441002802c8a3c68000118180808000002208450d0a2008200736020c20084109360200200820093602100c1f0b20012008417f6a220b3602140240200b2007490d002008417f6a210b0c180b2001200836021402402013417f6a2d000041e100470d0020082007200b2007200b4b1b220b460d182001200841016a2212360214024020132d000041ec00460d00200841016a21080c010b2012200b460d182001200841026a22123602140240201341016a2d000041f300460d00200841026a21080c010b2012200b460d182001200841036a360214201341026a2d000041e500460d06200841036a21080b200641b8016a20092007200810878380800041002d00fca3c680001a20062802bc01210920062802b8012107411441002802c8a3c68000118180808000002208450d082008200736020c20084109360200200820093602100c1e0b20012008417f6a360214200a108e8380800022080d1a0c040b02402001280200200128020822086b201141017122094f0d0020012008200910ab86808000200128020821080b02402009450d00200128020420086a20143a0000200841016a21080b200120083602082001200128021441016a360214410021150c040b200b41506a41ff0171410a490d0120064188016a2009200720072008417f6a220820072008491b10878380800041002d00fca3c680001a200628028c0121092006280288012107411441002802c8a3c68000118180808000002208450d042008200736020c2008410a360200200820093602100c1b0b20012008417f6a3602140b200110d18a80800022080d160b4101211502402011410171450d002014210b0c010b20012802082208450d0d20012008417f6a2208360208200128020420086a2d0000210b0b02402001280214221320012802102207490d00200b21140c060b20012802042111200128020c210920012802082112200b21140340201321080240024002400240034002400240200920086a2d0000220b41776a0e2401010e0e010e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e010e0e0e0e0e0e0e0e0e0e0e03000b200b41dd00460d03200b41fd00460d040c0d0b2001200841016a220836021420072008470d000b200721130c0a0b2015410171450d0b2001200841016a22083602140c0b0b201441ff017141db00470d090c010b201441ff017141fb00470d080b2001200841016a22133602142012450d0d20012012417f6a2212360208201120126a2d0000211441012115201320074f0d050c000b0b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000b200841016a21130b41022109024002400240201441ff0171220841db00460d00200841fb00470d01410321090b200641f8006a200a28020020072007201341016a220820072008491b10878380800041002d00fca3c680001a200628027c21072006280278210b411441002802c8a3c68000118180808000002208450d012008200b36020c20082009360200200820073602100c130b419ccac480004128418ccdc4800010f880808000000b4104411410b280808000000b2015410171450d004107210b201441ff0171220a41db00460d02200a41fb00460d01419ccac480004128419ccdc4800010f880808000000b201441ff017141fb00470d020240200820074f0d00034002400240200920086a2d000041776a220b41194b0d004101200b744193808004710d01200b4119470d002001200841016a360214200a108e8380800022080d10200128020c21090240024002400240024020012802142208200128021022074f0d0003400240200920086a2d000041776a0e320000030300030303030303030303030303030303030303000303030303030303030303030303030303030303030303030304030b2001200841016a220836021420072008470d000b200721080b200641e8006a200920072007200841016a220820072008491b10878380800041002d00fca3c680001a200628026c21092006280268210c411441002802c8a3c68000118180808000002208450d022008200c36020c4103210c20084103360200200820093602100c170b200641e0006a200920072007200841016a220820072008491b10878380800041002d00fca3c680001a2006280264210920062802602107411441002802c8a3c68000118180808000002208450d022008200736020c20084106360200200820093602100c160b2001200841016a22083602140c080b4104411410b280808000000b4104411410b280808000000b200641d0006a200920072007200841016a220820072008491b10878380800041002d00fca3c680001a20062802542109200628025021070240411441002802c8a3c68000118180808000002208450d002008200736020c20084111360200200820093602100c130b4104411410b280808000000b2001200841016a220836021420072008470d000b200721080b200641d8006a200920072007200841016a220820072008491b10878380800041002d00fca3c680001a200628025c21092006280258210c0240411441002802c8a3c68000118180808000002208450d002008200c36020c4103210c20084103360200200820093602100c100b4104411410b280808000000b4108210b0b200641c8006a200920072007200841016a220820072008491b10878380800041002d00fca3c680001a200628024c2109200628024821070240411441002802c8a3c68000118180808000002208450d002008200736020c2008200b360200200820093602100c0e0b4104411410b280808000000b4101211120082007490d000c080b0b4101210b20012802142208200128021022094f0d080c000b0b4104411410b280808000000b4104411410b280808000000b200641b0016a20092007200b10878380800041002d00fca3c680001a20062802b401210920062802b00121070240411441002802c8a3c68000118180808000002208450d002008200736020c20084105360200200820093602100c070b4104411410b280808000000b200641a0016a20092007200b10878380800041002d00fca3c680001a20062802a401210920062802a00121070240411441002802c8a3c68000118180808000002208450d002008200736020c20084105360200200820093602100c060b4104411410b280808000000b20064190016a20092007200b10878380800041002d00fca3c680001a200628029401210920062802900121070240411441002802c8a3c68000118180808000002208450d002008200736020c20084105360200200820093602100c050b4104411410b280808000000b200641f0006a200920072007200841016a220820072008491b10878380800041002d00fca3c680001a20062802742109200628027021070240411441002802c8a3c68000118180808000002208450d002008200736020c20084105360200200820093602100c040b4104411410b280808000000b0c020b200a28020021070b20064180016a200720092009200841016a220820092008491b10878380800041002d00fca3c680001a2006280284012109200628028001210c411441002802c8a3c68000118180808000002208450d012008200c36020c4103210c20084103360200200820093602100b200120012d001841016a3a0018200110d98a808000210b0240200c41ff01714103460d0020082107200b2108200b0d060c050b200b450d050240200b2802000d00200b41086a280200450d00200b28020441002802c0a3c68000118080808000000b200b41002802c0a3c68000118080808000000c050b4104411410b280808000000b200641306a200720092009200820092008491b10878380800041002d00fca3c680001a2006280234210c20062802302101411441002802c8a3c680001181808080000022080d054104411410b280808000000b0240200b41dd00470d004103210c410041c0cec4800041c8cec4800010e68a80800021080c010b200641e0016a200110ef8a808000024020062802e0010d00200128020c210b0240024002400240024002400240024002402001280214220c200128021022074f0d00200641f0016a290300211020062802ec01210920062802e801210803400240200b200c6a2d0000220a41776a0e24000005050005050505050505050505050505050505050500050505050505050505050503040b2001200c41016a220c3602142007200c470d000b2007210c0b200641106a200b20072007200c41016a220820072008491b10878380800041002d00fca3c680001a2006280214210c20062802102109411441002802c8a3c68000118180808000002208450d032008200936020c200841023602002008200c3602104103210c0c090b2001200c41016a220c3602140240200c20074f0d000340200b200c6a2d0000221341776a220a41174b0d084101200a74419380800471450d082001200c41016a220c3602142007200c470d000b2007210c0b200641186a200b20072007200c41016a220820072008491b10878380800041002d00fca3c680001a200628021c210c20062802182109411441002802c8a3c68000118180808000002208450d042008200936020c200841053602002008200c3602104103210c0c080b200a41dd00460d040b200641086a200b20072007200c41016a220820072008491b10878380800041002d00fca3c680001a200628020c210c20062802082109411441002802c8a3c68000118180808000002208450d012008200936020c200841073602002008200c3602104103210c0c060b4104411410b280808000000b4104411410b280808000000b4104411410b280808000000b4103210c410141c0cec4800041c8cec4800010e68a80800021080c020b02400240201341dd00470d00200641206a200b20072007200c41016a220820072008491b10878380800041002d00fca3c680001a2006280224210c20062802202109411441002802c8a3c68000118180808000002208450d012008200936020c200841153602002008200c3602104103210c0c030b200641e0016a200110cb8680800020062d00e0010d0120062d00e101210c0c020b4104411410b280808000000b20062802e40121084103210c0b200120012d001841016a3a0018200110da8a808000210b0240200c41ff01714103460d0020082107200b2108200b450d010c020b200b450d010240200b2802000d00200b41086a280200450d00200b28020441002802c0a3c68000118080808000000b200b41002802c0a3c68000118080808000000c010b200020062800d9013600112000200c3a0010200020103703082000200936020420002007360200200041146a200641dc016a2800003600000c030b2008200110d68a8080002108200041033a0010200020083602000c020b2006200720092009200820092008491b10878380800041002d00fca3c680001a2006280204210c20062802002101411441002802c8a3c680001181808080000022080d004104411410b280808000000b2008200136020c20084118360200200041033a0010200020083602002008200c3602100b20064180026a2480808080000be01b010d7f2380808080004190016b2207248080808000024002400240024002400240024002400240024002400240024002400240024020010e020102000b200041146a2108200141146c2209416c6a41146e210a200041106a280200210b2000410c6a280200210c2000280200210d4100210e200041046a280200220f21100340410021110240200f2008200e41146c6a221241046a2802002213200f2013491b2213450d0020122802002112410021110340200d20116a2d0000201220116a2d0000470d012013201141016a2211470d000b201321110b2011201020112010491b2110200e41016a220e200a470d000b20040d03201020024b0d024100210d0c040b0240200328020822112003280200470d002003201110a885808000200328020821110b200328020420116a41003a00002003200328020841016a3602080c0d0b200041106a28020021112000410c6a280200211320054101470d030240201120064f0d002007410c6a20113602002007201336020820074180808080783602040c0c0b200741106a201320114100280298a3c680001185808080000041002d00fca3c680001a412041002802c8a3c68000118180808000002211450d0420112007290010370000201141186a200741106a41186a290000370000201141106a200741106a41106a290000370000201141086a200741106a41086a2900003700002007412036020c20072011360208200741203602040c0b0b2010200f4b0d04200741003602702007428080808010370268200020012010200741e8006a41002005200610fa8a808000200728026c21132007280268210202400240200728027022114120490d00200741106a201320114100280298a3c6800011858080800000200741203602502007200741d0006a36025c200741dc006a200310c08a80800002402003280200200328020822116b411f4b0d0020032011412010b182808000200328020821110b2003201141206a360208200328020420116a22112007290010370000201141086a200741106a41086a290000370000201141106a200741106a41106a290000370000201141186a200741106a41186a2900003700000c010b2007201136025c2007200741dc006a360210200741106a200310c08a80800002402003280200200328020822126b20114f0d0020032012201110b182808000200328020821120b200328020420126a2013201110848e8080001a2003201220116a3602080b2002450d0b201341002802c0a3c68000118080808000000c0b0b4100210a201020024d0d002010200f4b0d04200d20026a210d201020026b210a201021020b200741c8006a4200370300200741c0006a4200370300200741386a4200370300200741306a4200370300200741286a4200370300200741106a41106a4200370300200741186a4200370300200742003703102002200f46210841002111034020112110200820014b0d0741002113024020082001460d002009200841146c22116b2112200020116a211141002113034020022011280204220e4f0d08201128020020026a2d0000201041ff0171470d01201141146a2111201341016a21132012416c6a22120d000b0b200741106a20104102746a2013360200201320086a2108201041016a22114110470d000b02402002200f470d000240024020054101470d00200b20064f0d010b2007200b3602582007200c360254418080808078211120074180808080783602500c090b200741e8006a200c200b4100280298a3c680001185808080000041002d00fca3c680001a412041002802c8a3c68000118180808000002211450d0520112007290068370000201141186a200741e8006a41186a290000370000201141106a200741e8006a41106a290000370000201141086a200741e8006a41086a290000370000200741203602582007201136025420074120360250200741e8006a200741d0006a108b878080002007280270210b200728026c210c200728026821110c080b418180808078211120074181808080783602500c070b2007410c6a20113602002007201336020820074180808080783602040c070b4101412010b280808000000b2010200f41c4d6c48000109581808000000b2010200f41d4d6c48000109581808000000b4101412010b280808000000b2002200e4184d7c4800010f980808000000b2008200141f4d6c48000109481808000000b02400240024002400240200d450d00024002400240024002404101410241042011418080808078461b2011418180808078461b417f6a0e0400010203000b413e210e200a413e200a413e491b211241bf012108418001210f0c030b413e210e200a413e200a413e491b211241ff01210841c001210f0c020b411e210e200a411e200a411e491b2112413f21084120210f0c010b410e210e200a410e200a410e491b2112411f21084110210f0b0240200a4101712213450d00200d2d000021100b20074180016a4102360200200741fc006a200a417e71360200200720103a0075200741013a0070200741013602682007200a20126b36026c200720133a00742007200d20136a36027820072008200f201272200e200a491b3a00712003200741e8006a1099878080002007280228410047410674200728022c4100474107747220072802204100474104742007280224410047410574722007280214410047410174200728021041004772200728021841004741027472200728021c41004741037472727221122007280234410047410174200728023041004772200728023841004741027472200728023c41004741037472200728024041004741047472200728024441004741057472200728024841004741067472200728024c41004741077472210d02402003280200200328020822136b41014b0d0020032013410210ab86808000200328020821130b200328020420136a200d410874201241ff0171723b00002003201341026a221336020802402011418180808078460d0002402011418080808078470d002007200b36028c0120072007418c016a36025c200741dc006a200310c08a80800002402003280200200328020822116b200b4f0d0020032011200b10ab86808000200328020821110b200328020420116a200c200b10848e8080001a20032011200b6a3602080c010b0240200328020020136b200b4f0d0020032013200b10ab86808000200328020821130b200328020420136a200c200b10848e8080001a20032013200b6a3602082011450d00200c41002802c0a3c68000118080808000000b200241016a2110200728025022084181808080784721112005450d014100211303400240200741106a20136a2802002212450d00201220116a22022012490d05200220014b0d0620074100360264200742808080801037025c2000201141146c6a20122010200741dc006a20044101200610fa8a80800020072802602112200728025c210d02400240200728026422114120490d00200741e8006a201220114100280298a3c68000118580808000002007412036028801200720074188016a36028c012007418c016a200310c08a80800002402003280200200328020822116b411f4b0d0020032011412010b182808000200328020821110b2003201141206a360208200328020420116a22112007290068370000201141086a200741e8006a41086a290000370000201141106a200741e8006a41106a290000370000201141186a200741e8006a41186a2900003700000c010b2007201136028c0120072007418c016a360268200741e8006a200310c08a808000024020032802002003280208220e6b20114f0d002003200e201110b1828080002003280208210e0b2003280204200e6a2012201110848e8080001a2003200e20116a3602080b0240200d450d00201241002802c0a3c68000118080808000000b200221110b201341046a221341c000470d000c030b0b200741f4006a42003702002007410136026c200741f4d2c480003602682007200741dc006a360270200741e8006a41e4d3c4800010f680808000000b4100211303400240200741106a20136a2802002212450d00201220116a22022012490d03200220014b0d0420074100360264200742808080801037025c2000201141146c6a20122010200741dc006a20044100200610fa8a80800020072802602112200728025c210d02400240200728026422114120490d00200741e8006a201220114100280298a3c68000118580808000002007412036028801200720074188016a36028c012007418c016a200310c08a80800002402003280200200328020822116b411f4b0d0020032011412010b182808000200328020821110b2003201141206a360208200328020420116a22112007290068370000201141086a200741e8006a41086a290000370000201141106a200741e8006a41106a290000370000201141186a200741e8006a41186a2900003700000c010b2007201136028c0120072007418c016a360268200741e8006a200310c08a808000024020032802002003280208220e6b20114f0d002003200e201110b1828080002003280208210e0b2003280204200e6a2012201110848e8080001a2003200e20116a3602080b0240200d450d00201241002802c0a3c68000118080808000000b200221110b201341046a221341c000470d000b0b2008418280808078480d032008450d03200728025441002802c0a3c68000118080808000000c030b2011200241e4d6c48000109681808000000b2002200141e4d6c48000109581808000000b0240200041046a28020022112002490d002003200028020020026a201120026b200741046a10af858080000c010b2002201141b4d6c48000109481808000000b20074190016a2480808080000bc50401057f23808080800041f0006b220424808080800020044100360214200442808080801037020c41002d00fca3c680001a0240410441002802c8a3c68000118180808000002205450d00200541003602002004410036025c20044200370254200442818080802037024c20042005360248200441003602442004410036023c200442003702342004410036022c2004420037022420042004410c6a360260200441186a200441246a109c878080002004410036026c2004428080808010370264200428021c2206200428022022074100200441e4006a20012002200310fa8a80800020042802642101200020042802682208200428026c4100280298a3c680001185808080000002402007450d002007410171210041002102024020074101460d00200641206a21032007417e7121074100210203400240200341686a280200450d002003416c6a28020041002802c0a3c68000118080808000000b02402003417c6a280200450d00200328020041002802c0a3c68000118080808000000b200341286a21032007200241026a2202470d000b0b2000450d002006200241146c6a2203280208450d00200341086a28020441002802c0a3c68000118080808000000b02402004280218450d00200641002802c0a3c68000118080808000000b200541002802c0a3c68000118080808000000240200428020c450d00200428021041002802c0a3c68000118080808000000b02402001450d00200841002802c0a3c68000118080808000000b200441f0006a2480808080000f0b4104410410b280808000000bbe0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206410036023020064280808080c00037032820064100360220200641003602182006419682808000360210200642ab8ad7e1bb97ae9f51370308200642f2f9a5a49996c5e03237030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641013a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bb30403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420d370224200541b4fbc480003602202005410e36021c200541a6fbc480003602182005419482808000360210200542c0969aec91e181fcf200370308200542d7a7fbff94a5afcaf800370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420c37022420054194fbc480003602202005410d36021c20054187fbc48000360218200541ed83808000360210200542e7dca5b4fdd9bda7a17f370308200542accee9bcd783d4ea3937030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a4100290380f9c480003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541013a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000b890301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c20064207370224200641b0f2c480003602202006410436021c200641a4e4c48000360218200641ea81808000360210200642b891b68c98adebcf61370308200642e7b0a091f3ed9c85c50037030041002d00fca3c680001a20042802042107200428020821080240410841002802c8a3c68000118180808000002209450d00200941002903e0a7c580003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641013a00202006200336021c2006200236021820064101360214200620093602102006410136020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104410810b280808000000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c20054207370224200541e3e4c480003602202005410936021c200541dae4c48000360218200541f581808000360210200542ab8bffbed784ffa5937f370308200542c194a6a793ccc3a857370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c20054204370224200541f7e4c480003602202005410d36021c200541eae4c48000360218200541888180800036021020054298848fa1dab08ba174370308200542febac4ad81b6fafcb37f37030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a41002903f0f9c480003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541063a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000bf50403047f017e027f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c200542133702242005418993c580003602202005410936021c2005418093c58000360218200541ee83808000360210200542e5fbf9f4fcf79cdd3a3703082005429bb0d3a2d7cce1b225370300200441086a41086a200641016a2207360200200420042902142208370308024020072008a7470d00200441086a200710a486808000200428021021070b200428020c200741386c6a2205420437022c2005420a370224200541d192c580003602202005410536021c200541b393c58000360218200541bc82808000360210200542899ac8f29d8ce69ac300370308200542e78dcee4d0becc975737030020042802082109200428020c210a41002d00fca3c680001a0240412841002802c8a3c68000118180808000002206450d00200641206a41002902908bc58000370200200641186a41002902888bc58000370200200641106a41002902808bc58000370200200641086a41002902f88ac58000370200200641002902f08ac580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541093a00202005200336021c2005200236021820054105360214200520063602102005410536020c2005200741016a3602082005200a3602042005200936020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104412810b280808000000bbe0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c200642ed00370224200641b2b1c5800036022020064100360218200641f482808000360210200642c9e8d484edccb5e26c370308200642a79fcbb9e09aeaff7c37030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641033a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000baa0301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c20064203370224200641e1f2c480003602202006410536021c200641f0adc58000360218200641b580808000360210200642e88488d0c0e3aebc13370308200642d7c9cb8fc1cf97db3e37030041002d00fca3c680001a20042802042107200428020821080240411841002802c8a3c68000118180808000002209450d00200941106a41002902e8adc58000370200200941086a41002902e0adc58000370200200941002902d8adc580003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a2206410a3a00202006200336021c2006200236021820064103360214200620093602102006410336020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104411810b280808000000b890301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c2006420d370224200641cdf2c480003602202006410536021c200641c8f2c48000360218200641ef83808000360210200642ce9de6a5b39faacabf7f3703082006428f8dbaa0f1e8bfc67537030041002d00fca3c680001a20042802042107200428020821080240410841002802c8a3c68000118180808000002209450d0020094100290380ebc480003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641043a00202006200336021c2006200236021820064101360214200620093602102006410136020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104410810b280808000000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420c370224200541f7fac480003602202005410336021c200541f392c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420a370224200541d192c580003602202005410636021c200541c1fbc48000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c37030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a41002903d0a3c580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a2205410b3a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000bd40403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c20054214370224200541df92c580003602202005410336021c200541f392c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420a370224200541d192c580003602202005410836021c200541b893c58000360218200541bc82808000360210200542899ac8f29d8ce69ac300370308200542e78dcee4d0becc975737030020042802082108200428020c210941002d00fca3c680001a0240411841002802c8a3c6800011818080800000220a450d00200a41106a41002902d48fc58000370200200a41086a41002902cc8fc58000370200200a41002902c48fc580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541083a00202005200336021c20052002360218200541033602142005200a3602102005410336020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104411810b280808000000b890301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c20064207370224200641b0f2c480003602202006410436021c200641acf2c48000360218200641ea81808000360210200642b891b68c98adebcf61370308200642e7b0a091f3ed9c85c50037030041002d00fca3c680001a20042802042107200428020821080240410841002802c8a3c68000118180808000002209450d00200941002903b8e7c480003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641023a00202006200336021c2006200236021820064101360214200620093602102006410136020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104410810b280808000000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420c370224200541f7fac480003602202005410636021c200541a0fbc48000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c20054207370224200541e3e4c480003602202005410436021c20054183fbc48000360218200541f581808000360210200542ab8bffbed784ffa5937f370308200542c194a6a793ccc3a85737030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a41002903e8fac480003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541053a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420c370224200541f7fac480003602202005410336021c200541f392c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420a370224200541d192c580003602202005410636021c200541c1fbc48000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c37030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a41002903d0a2c580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541053a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000bc00201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206410036023020064280808080c0003703282006410036022020064100360218200641bd80808000360210200642efc9c9edb5e7b3a6c700370308200642acf6debeefe0d9c8d30037030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641013a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bbe0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206410036023020064280808080c00037032820064100360220200641003602182006419782808000360210200642fb8387e2d6839cd949370308200642d9adfaebb1c192ed5037030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641003a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420c370224200541f7fac480003602202005410336021c200541f392c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420a370224200541d192c580003602202005410636021c200541c1fbc48000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c37030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a41002903f09ac580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541073a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420c370224200541f7fac480003602202005410336021c200541f392c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420a370224200541d192c580003602202005410636021c200541c1fbc48000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c37030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a41002903909ac580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541143a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000b900301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c20064207370224200641b0f2c480003602202006410436021c200641acf2c48000360218200641ea81808000360210200642b891b68c98adebcf61370308200642e7b0a091f3ed9c85c50037030041002d00fca3c680001a2004280204210720042802082108024041c80041002802c8a3c68000118180808000002206450d00200641e4f1c4800041c80010848e80800021090240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a2206410b3a00202006200336021c2006200236021820064109360214200620093602102006410936020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b410441c80010b280808000000bc30403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420c370224200541f7fac480003602202005410736021c200541f0fac48000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420a370224200541d192c580003602202005410636021c200541c1fbc48000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c37030020042802082108200428020c210941002d00fca3c680001a0240411041002802c8a3c6800011818080800000220a450d00200a41086a4100290298a1c58000370200200a4100290290a1c580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541013a00202005200336021c20052002360218200541023602142005200a3602102005410236020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104411010b280808000000b890301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c2006420c370224200641f7fac480003602202006410336021c200641f392c58000360218200641f081808000360210200642a4d2928ecac0faa432370308200642c4ccab9c81ebb4b8db0037030041002d00fca3c680001a20042802042107200428020821080240410841002802c8a3c68000118180808000002209450d00200941002903b09ac580003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a2206410e3a00202006200336021c2006200236021820064101360214200620093602102006410136020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104410810b280808000000baa0301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c20064203370224200641e1f2c480003602202006410536021c200641f0adc58000360218200641b580808000360210200642e88488d0c0e3aebc13370308200642d7c9cb8fc1cf97db3e37030041002d00fca3c680001a20042802042107200428020821080240411841002802c8a3c68000118180808000002209450d00200941106a41002902e4aec58000370200200941086a41002902dcaec58000370200200941002902d4aec580003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a2206410b3a00202006200336021c2006200236021820064103360214200620093602102006410336020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104411810b280808000000bbc0301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c20064207370224200641b0f2c480003602202006410436021c200641acf2c48000360218200641ea81808000360210200642b891b68c98adebcf61370308200642e7b0a091f3ed9c85c50037030041002d00fca3c680001a20042802042107200428020821080240412041002802c8a3c68000118180808000002209450d00200941186a41002902dce6c48000370200200941106a41002902d4e6c48000370200200941086a41002902cce6c48000370200200941002902c4e6c480003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641033a00202006200336021c2006200236021820064104360214200620093602102006410436020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104412010b280808000000bbf0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206410036023020064280808080c0003703282006410036022020064100360218200641ea81808000360210200642b891b68c98adebcf61370308200642e7b0a091f3ed9c85c50037030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641013a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c20054207370224200541b0f2c480003602202005410336021c200541c0a8c58000360218200541ea81808000360210200542b891b68c98adebcf61370308200542e7b0a091f3ed9c85c500370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420f370224200541c3a8c580003602202005410536021c200541cc92c580003602182005419183808000360210200542f6d183c8fca4ffd45a370308200542f99f94a5fdd3dbbaf90037030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a41002903b8a8c580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541023a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000bbf0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c200642e900370224200641d7afc5800036022020064100360218200641f082808000360210200642c2a7b4b19ace9c92d9003703082006429691e8a3b686eae56237030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641013a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bb90403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c20054214370224200541df92c580003602202005410436021c200541db92c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c20054204370224200541f7e4c480003602202005410a36021c200541f692c58000360218200541888180800036021020054298848fa1dab08ba174370308200542febac4ad81b6fafcb37f37030020042802082108200428020c210941002d00fca3c680001a024041f80041002802c8a3c68000118180808000002205450d00200541cc83c5800041f80010848e808000210a0240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541043a00202005200336021c200520023602182005410f3602142005200a3602102005410f36020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b410441f80010b280808000000b980503047f017e027f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c20054214370224200541df92c580003602202005410436021c200541db92c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2207360200200420042902142208370308024020072008a7470d00200441086a200710a486808000200428021021070b200428020c200741386c6a2205420437022c2005420a370224200541d192c580003602202005410536021c200541cc92c58000360218200541bc82808000360210200542899ac8f29d8ce69ac300370308200542e78dcee4d0becc975737030020042802082109200428020c210a41002d00fca3c680001a0240413841002802c8a3c68000118180808000002205450d00200541306a41002902c492c58000370200200541286a41002902bc92c58000370200200541206a41002902b492c58000370200200541186a41002902ac92c58000370200200541106a41002902a492c58000370200200541086a410029029c92c580003702002005410029029492c580003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641003a00202006200336021c2006200236021820064107360214200620053602102006410736020c2006200741016a3602082006200a3602042006200936020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104413810b280808000000b890301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c2006420a370224200641d192c580003602202006410636021c200641c1fbc48000360218200641ef8080800036021020064293888c8f89fdc6ec9e7f370308200642a5e9e3ab9e929adc2c37030041002d00fca3c680001a20042802042107200428020821080240410841002802c8a3c68000118180808000002209450d00200941002903989fc580003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a2206410f3a00202006200336021c2006200236021820064101360214200620093602102006410136020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104410810b280808000000b890301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c20064203370224200641bcf2c480003602202006410536021c200641b7f2c48000360218200641ef8080800036021020064293888c8f89fdc6ec9e7f370308200642a5e9e3ab9e929adc2c37030041002d00fca3c680001a20042802042107200428020821080240410841002802c8a3c68000118180808000002209450d0020094100290380e8c480003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641013a00202006200336021c2006200236021820064101360214200620093602102006410136020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104410810b280808000000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420c370224200541f7fac480003602202005410336021c200541f392c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420a370224200541d192c580003602202005410636021c200541c1fbc48000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c37030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a41002903c89dc580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541043a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000bbe0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206410036023020064280808080c00037032820064100360220200641003602182006419582808000360210200642f69a89928aa399ea003703082006429198b9e48fc6c3ad1d37030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641003a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bd40503047f017e027f23808080800041206b2204248080808000200441106a41086a22054100360200200442808080808001370210200441106a410010a48680800020042802142005280200220641386c6a2207420437022c20074214370224200741df92c580003602202007410636021c200741ad93c58000360218200741f081808000360210200742a4d2928ecac0faa432370308200742c4ccab9c81ebb4b8db00370300200441086a200641016a2206360200200420042902102208370300024020062008a7470d002004200610a486808000200428020821060b2004280204200641386c6a2207420437022c20074214370224200741df92c580003602202007410436021c200741db92c58000360218200741f081808000360210200742a4d2928ecac0faa432370308200742c4ccab9c81ebb4b8db003703002005200641016a2206360200200420042903002208370310024020062008a7470d00200441106a200610a486808000200428021821060b2004280214200641386c6a2207420437022c2007420a370224200741d192c580003602202007410536021c200741cc92c58000360218200741bc82808000360210200742899ac8f29d8ce69ac300370308200742e78dcee4d0becc9757370300200428021021092004280214210a41002d00fca3c680001a0240411041002802c8a3c68000118180808000002205450d00200541086a41002902e48ec58000370200200541002902dc8ec580003702000240200128020822072001280200470d002001200710a086808000200128020821070b2001280204200741246c6a220741023a00202007200336021c2007200236021820074102360214200720053602102007410236020c2007200641016a3602082007200a3602042007200936020020002001290200370200200141086a2207200728020041016a2207360200200041086a2007360200200441206a2480808080000f0b4104411010b280808000000bbf0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c2006421c370224200641f5b2c5800036022020064100360218200641ed82808000360210200642e89d8d84e9a7e0ebbf7f370308200642ffa1f591d896faeca07f37030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641003a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000b890301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c2006420737022420064185adc580003602202006410536021c20064180adc58000360218200641f083808000360210200642fef18cfcdbfae085d000370308200642c1e482bcf69e92d65b37030041002d00fca3c680001a20042802042107200428020821080240410841002802c8a3c68000118180808000002209450d00200941002903f8acc580003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641093a00202006200336021c2006200236021820064101360214200620093602102006410136020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104410810b280808000000bbe0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206410036023020064280808080c0003703282006410036022020064100360218200641fb82808000360210200642a8c786dcd8d2a98d17370308200642cecfe0e5d1c6dbf75737030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641013a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000b890301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c20064208370224200641eef2c480003602202006410436021c200641eaf2c48000360218200641f183808000360210200642aac2d79da4bfd9a04e370308200642e6afce95f6a1ffa6c30037030041002d00fca3c680001a20042802042107200428020821080240410841002802c8a3c68000118180808000002209450d0020094100290398e5c480003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641053a00202006200336021c2006200236021820064101360214200620093602102006410136020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104410810b280808000000bc00201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206410036023020064280808080c000370328200641003602202006410036021820064193828080003602102006429ccab49c93e2e495cf00370308200642d1c5efcdcd82cde1ff0037030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641003a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bd20101027f41002d00fca3c680001a0240410841002802c8a3c68000118180808000002204450d00200441002903c0acc580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541083a00202005200336021c200520023602182005410136021420052004360210200542808080801037020820054280808080800137020020002001290200370200200141086a2201200128020041016a2201360200200041086a20013602000f0b4104410810b280808000000b890301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c20064207370224200641b0f2c480003602202006410336021c200641c0a8c58000360218200641ea81808000360210200642b891b68c98adebcf61370308200642e7b0a091f3ed9c85c50037030041002d00fca3c680001a20042802042107200428020821080240410841002802c8a3c68000118180808000002209450d00200941002903d0a9c580003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641043a00202006200336021c2006200236021820064101360214200620093602102006410136020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104410810b280808000000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420c370224200541f7fac480003602202005410336021c200541f392c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420a370224200541d192c580003602202005410636021c200541c1fbc48000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c37030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a4100290398a0c580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541123a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000b820401067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c20064207370224200641e3e4c480003602202006410936021c200641dae4c48000360218200641f581808000360210200642ab8bffbed784ffa5937f370308200642c194a6a793ccc3a85737030041002d00fca3c680001a2004280204210720042802082108024041c00041002802c8a3c68000118180808000002206450d00200641386a41002902a8eec48000370200200641306a41002902a0eec48000370200200641286a4100290298eec48000370200200641206a4100290290eec48000370200200641186a4100290288eec48000370200200641106a4100290280eec48000370200200641086a41002902f8edc48000370200200641002902f0edc480003702000240200128020822092001280200470d002001200910a086808000200128020821090b2001280204200941246c6a2209410a3a00202009200336021c2009200236021820094108360214200920063602102009410836020c2009200541016a360208200920083602042009200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b410441c00010b280808000000bbe0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c2006421f37022420064191b3c5800036022020064100360218200641f382808000360210200642e5c18a8c83d9a2ecc200370308200642b4ff9ef1bdc3bdda2837030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641033a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000b890301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c20064207370224200641b0f2c480003602202006410436021c200641a4e4c48000360218200641ea81808000360210200642b891b68c98adebcf61370308200642e7b0a091f3ed9c85c50037030041002d00fca3c680001a20042802042107200428020821080240410841002802c8a3c68000118180808000002209450d00200941002903f8a9c580003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641053a00202006200336021c2006200236021820064101360214200620093602102006410136020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104410810b280808000000b980503047f017e027f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420a370224200541d192c580003602202005410536021c200541cc92c58000360218200541bc82808000360210200542899ac8f29d8ce69ac300370308200542e78dcee4d0becc9757370300200441086a41086a200641016a2207360200200420042902142208370308024020072008a7470d00200441086a200710a486808000200428021021070b200428020c200741386c6a2205420437022c20054204370224200541f7e4c480003602202005410a36021c200541f692c58000360218200541888180800036021020054298848fa1dab08ba174370308200542febac4ad81b6fafcb37f37030020042802082109200428020c210a41002d00fca3c680001a0240413841002802c8a3c68000118180808000002205450d00200541306a41002902dc87c58000370200200541286a41002902d487c58000370200200541206a41002902cc87c58000370200200541186a41002902c487c58000370200200541106a41002902bc87c58000370200200541086a41002902b487c58000370200200541002902ac87c580003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a2206410a3a00202006200336021c2006200236021820064107360214200620053602102006410736020c2006200741016a3602082006200a3602042006200936020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104413810b280808000000b890301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c2006420c370224200641f7fac480003602202006410736021c200641f0fac48000360218200641f081808000360210200642a4d2928ecac0faa432370308200642c4ccab9c81ebb4b8db0037030041002d00fca3c680001a20042802042107200428020821080240410841002802c8a3c68000118180808000002209450d00200941002903c8f9c480003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641033a00202006200336021c2006200236021820064101360214200620093602102006410136020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104410810b280808000000b890301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c20064213370224200641f0abc580003602202006410836021c200641e8abc58000360218200641ef8080800036021020064293888c8f89fdc6ec9e7f370308200642a5e9e3ab9e929adc2c37030041002d00fca3c680001a20042802042107200428020821080240410841002802c8a3c68000118180808000002209450d00200941002903e0abc580003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641073a00202006200336021c2006200236021820064101360214200620093602102006410136020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104410810b280808000000bbf0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206410036023020064280808080c0003703282006410036022020064100360218200641f283808000360210200642f9beb892cc84b284c800370308200642cc9a879ae783ad825437030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641013a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bc30503047f017e027f23808080800041206b2204248080808000200441106a41086a22054100360200200442808080808001370210200441106a410010a48680800020042802142005280200220641386c6a2207420437022c2007420c370224200741f7fac480003602202007410436021c200741daa3c58000360218200741f081808000360210200742a4d2928ecac0faa432370308200742c4ccab9c81ebb4b8db00370300200441086a200641016a2206360200200420042902102208370300024020062008a7470d002004200610a486808000200428020821060b2004280204200641386c6a2207420437022c2007420c370224200741f7fac480003602202007410236021c200741d8a3c58000360218200741f081808000360210200742a4d2928ecac0faa432370308200742c4ccab9c81ebb4b8db003703002005200641016a2206360200200420042903002208370310024020062008a7470d00200441106a200610a486808000200428021821060b2004280214200641386c6a2207420437022c2007420a370224200741d192c580003602202007410636021c200741c1fbc48000360218200741ef8080800036021020074293888c8f89fdc6ec9e7f370308200742a5e9e3ab9e929adc2c370300200428021021092004280214210a41002d00fca3c680001a0240410841002802c8a3c68000118180808000002205450d00200541002903f09fc580003702000240200128020822072001280200470d002001200710a086808000200128020821070b2001280204200741246c6a220741023a00202007200336021c2007200236021820074101360214200720053602102007410136020c2007200641016a3602082007200a3602042007200936020020002001290200370200200141086a2207200728020041016a2207360200200041086a2007360200200441206a2480808080000f0b4104410810b280808000000b9b0301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c2006421f370224200641ffaac580003602202006410336021c200641fcaac58000360218200641c481808000360210200642e0f4e1e1b7dafaaf8d7f3703082006428ca3c7fa85a49cf2a17f37030041002d00fca3c680001a20042802042107200428020821080240411041002802c8a3c68000118180808000002209450d00200941086a41002902f4aac58000370200200941002902ecaac580003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641063a00202006200336021c2006200236021820064102360214200620093602102006410236020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104411010b280808000000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420a370224200541d192c580003602202005410336021c20054185a4c58000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420a370224200541d192c580003602202005410336021c20054182a4c58000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c37030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a41002903d09fc580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541153a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420c370224200541f7fac480003602202005410336021c200541f392c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420a370224200541d192c580003602202005410636021c200541c1fbc48000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c37030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a41002903c09ec580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a2205410a3a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000be40403047f017e027f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c20054203370224200541c5f2c480003602202005410636021c200541bff2c48000360218200541ea81808000360210200542b891b68c98adebcf61370308200542e7b0a091f3ed9c85c500370300200441086a41086a200641016a2207360200200420042902142208370308024020072008a7470d00200441086a200710a486808000200428021021070b200428020c200741386c6a2205420437022c20054203370224200541e1f2c480003602202005410736021c200541daf2c48000360218200541b580808000360210200542e88488d0c0e3aebc13370308200542d7c9cb8fc1cf97db3e37030020042802082109200428020c210a41002d00fca3c680001a0240412041002802c8a3c68000118180808000002206450d00200641186a4100290284eac48000370200200641106a41002902fce9c48000370200200641086a41002902f4e9c48000370200200641002902ece9c480003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541063a00202005200336021c2005200236021820054104360214200520063602102005410436020c2005200741016a3602082005200a3602042005200936020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104412010b280808000000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420c370224200541f7fac480003602202005410736021c200541f0fac48000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420a370224200541d192c580003602202005410c36021c200541dea3c58000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c37030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a41002903f099c580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541003a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000bab0301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c20064207370224200641b0f2c480003602202006410636021c200641e4f2c48000360218200641ea81808000360210200642b891b68c98adebcf61370308200642e7b0a091f3ed9c85c50037030041002d00fca3c680001a20042802042107200428020821080240411841002802c8a3c68000118180808000002209450d00200941106a41002902d8eac48000370200200941086a41002902d0eac48000370200200941002902c8eac480003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641003a00202006200336021c2006200236021820064103360214200620093602102006410336020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104411810b280808000000b890301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c2006420c370224200641a8a7c580003602202006410836021c200641a0a7c58000360218200641f383808000360210200642a5c7d7fac9c29fd91637030820064289c487f88aeba5a3be7f37030041002d00fca3c680001a20042802042107200428020821080240410841002802c8a3c68000118180808000002209450d0020094100290398a7c580003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641003a00202006200336021c2006200236021820064101360214200620093602102006410136020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104410810b280808000000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c20054207370224200541b0f2c480003602202005410336021c200541c0a8c58000360218200541ea81808000360210200542b891b68c98adebcf61370308200542e7b0a091f3ed9c85c500370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c20054207370224200541b0f2c480003602202005410536021c200541cc92c58000360218200541ea81808000360210200542b891b68c98adebcf61370308200542e7b0a091f3ed9c85c50037030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a4100290388a9c580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541033a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000b890301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c2006420c37022420064194fbc480003602202006410d36021c20064187fbc48000360218200641ed83808000360210200642e7dca5b4fdd9bda7a17f370308200642accee9bcd783d4ea3937030041002d00fca3c680001a20042802042107200428020821080240410841002802c8a3c68000118180808000002209450d00200941002903c0fac480003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641003a00202006200336021c2006200236021820064101360214200620093602102006410136020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104410810b280808000000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420c370224200541f7fac480003602202005410336021c200541f392c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420a370224200541d192c580003602202005410636021c200541c1fbc48000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c37030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a41002903e8a1c580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541083a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000bbf0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c2006421f370224200641d6b2c5800036022020064100360218200641f282808000360210200642f2a19699e4e1bdb1ed0037030820064288d7a582bd91bff5867f37030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641033a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420c370224200541f7fac480003602202005410336021c200541f392c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420a370224200541d192c580003602202005410436021c20054193fcc48000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c37030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a410029038099c580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541033a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000bbf0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c200642e200370224200641fda5c5800036022020064100360218200641f4838080003602102006429dfad7afa1e4f28416370308200642ffc593f1fa9c9cbbed0037030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641003a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420c370224200541f7fac480003602202005410336021c200541f392c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420a370224200541d192c580003602202005410636021c200541c1fbc48000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c37030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a41002903b899c580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a2205410d3a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000b890301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c2006420a370224200641d192c580003602202006410636021c200641c1fbc48000360218200641ef8080800036021020064293888c8f89fdc6ec9e7f370308200642a5e9e3ab9e929adc2c37030041002d00fca3c680001a20042802042107200428020821080240410841002802c8a3c68000118180808000002209450d00200941002903c89bc580003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641103a00202006200336021c2006200236021820064101360214200620093602102006410136020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104410810b280808000000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420c370224200541f7fac480003602202005410336021c200541f392c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420a370224200541d192c580003602202005410636021c200541c1fbc48000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c37030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a41002903a0a3c580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a2205410c3a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000bc00201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206410036023020064280808080c000370328200641003602202006410036021820064193828080003602102006429ccab49c93e2e495cf00370308200642d1c5efcdcd82cde1ff0037030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641013a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bbf0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206410036023020064280808080c00037032820064100360220200641003602182006418c83808000360210200642b889cc8cd692ff80fa0037030820064288f7e1d594faa5a12037030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641013a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000be70403047f017e027f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005422437022420054189e1c480003602202005411236021c200541f7e0c48000360218200541f583808000360210200542ade681e7ba94a3bd8d7f3703082005428ae790e9b7c48cad987f370300200441086a41086a200641016a2207360200200420042902142208370308024020072008a7470d00200441086a200710a486808000200428021021070b200428020c200741386c6a2205420437022c20054210370224200541e7e0c480003602202005410f36021c200541d8e0c48000360218200541f683808000360210200542d5a5dfc0a4ecbbc59f7f37030820054299adc2c4dc87d5fcfe0037030020042802082109200428020c210a41002d00fca3c680001a0240412041002802c8a3c68000118180808000002206450d00200641186a4100290298dec48000370200200641106a4100290290dec48000370200200641086a4100290288dec4800037020020064100290280dec480003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541003a00202005200336021c2005200236021820054104360214200520063602102005410436020c2005200741016a3602082005200a3602042005200936020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104412010b280808000000bbe0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c200642e40037022420064199a5c5800036022020064100360218200641f783808000360210200642dfac899ed482c1d91e370308200642c0df82eab881b3cb5e37030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641013a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bbe0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206410036023020064280808080c0003703282006410036022020064100360218200641948380800036021020064299f0ab899787d3ad3a370308200642d4b0f086cab3d2eb1437030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641013a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bad0503047f017e027f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005422437022420054189e1c480003602202005411236021c200541f7e0c48000360218200541f583808000360210200542ade681e7ba94a3bd8d7f3703082005428ae790e9b7c48cad987f370300200441086a41086a200641016a2207360200200420042902142208370308024020072008a7470d00200441086a200710a486808000200428021021070b200428020c200741386c6a2205420437022c20054210370224200541e7e0c480003602202005410f36021c200541d8e0c48000360218200541f683808000360210200542d5a5dfc0a4ecbbc59f7f37030820054299adc2c4dc87d5fcfe0037030020042802082109200428020c210a41002d00fca3c680001a024041c00041002802c8a3c68000118180808000002205450d00200541386a41002902f8ddc48000370200200541306a41002902f0ddc48000370200200541286a41002902e8ddc48000370200200541206a41002902e0ddc48000370200200541186a41002902d8ddc48000370200200541106a41002902d0ddc48000370200200541086a41002902c8ddc48000370200200541002902c0ddc480003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641013a00202006200336021c2006200236021820064108360214200620053602102006410836020c2006200741016a3602082006200a3602042006200936020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b410441c00010b280808000000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420c370224200541f7fac480003602202005410336021c200541f392c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420a370224200541d192c580003602202005410636021c200541c1fbc48000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c37030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a41002903889dc580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541113a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000bbe0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c2006421c3702242006419fb2c5800036022020064100360218200641ec8280800036021020064289a2e6a5b198dead63370308200642d5d1b5deb9b78d97cf0037030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641003a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bbc0301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c20064214370224200641b3e1c480003602202006410636021c200641ade1c480003602182006418482808000360210200642a8dcd6c1f2afcba52b370308200642c7facddcf584b3fea87f37030041002d00fca3c680001a20042802042107200428020821080240412041002802c8a3c68000118180808000002209450d00200941186a41002902d0e0c48000370200200941106a41002902c8e0c48000370200200941086a41002902c0e0c48000370200200941002902b8e0c480003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641023a00202006200336021c2006200236021820064104360214200620093602102006410436020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104412010b280808000000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420c370224200541f7fac480003602202005410336021c200541f392c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420a370224200541d192c580003602202005410636021c200541c1fbc48000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c37030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a41002903909ec580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541093a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000b890301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c20064207370224200641b0f2c480003602202006410636021c200641e4f2c48000360218200641ea81808000360210200642b891b68c98adebcf61370308200642e7b0a091f3ed9c85c50037030041002d00fca3c680001a20042802042107200428020821080240410841002802c8a3c68000118180808000002209450d0020094100290390e7c480003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641073a00202006200336021c2006200236021820064101360214200620093602102006410136020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104410810b280808000000bb20403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c2005420c370224200541f7fac480003602202005410336021c200541f392c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420a370224200541d192c580003602202005410636021c200541c1fbc48000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c37030020042802082108200428020c210941002d00fca3c680001a0240410841002802c8a3c6800011818080800000220a450d00200a4100290388a2c580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541133a00202005200336021c20052002360218200541013602142005200a3602102005410136020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104410810b280808000000bbf0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c200642f200370224200641c0b0c5800036022020064100360218200641f182808000360210200642f8978ab68af4bdd3937f370308200642f681cbfbfc8791b01c37030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641023a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bbe0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c200642eb00370224200641ecaec5800036022020064100360218200641ee82808000360210200642829cf890def98fed23370308200642daf597b8b3adb2fc4437030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641003a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000b870503047f017e027f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c20054214370224200541df92c580003602202005410436021c200541db92c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2207360200200420042902142208370308024020072008a7470d00200441086a200710a486808000200428021021070b200428020c200741386c6a2205420437022c2005420a370224200541d192c580003602202005410536021c200541cc92c58000360218200541bc82808000360210200542899ac8f29d8ce69ac300370308200542e78dcee4d0becc975737030020042802082109200428020c210a41002d00fca3c680001a0240413041002802c8a3c68000118180808000002206450d00200641286a41002902f089c58000370200200641206a41002902e889c58000370200200641186a41002902e089c58000370200200641106a41002902d889c58000370200200641086a41002902d089c58000370200200641002902c889c580003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541033a00202005200336021c2005200236021820054106360214200520063602102005410636020c2005200741016a3602082005200a3602042005200936020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104413010b280808000000b890301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c2006420c370224200641f7fac480003602202006410736021c200641f0fac48000360218200641f081808000360210200642a4d2928ecac0faa432370308200642c4ccab9c81ebb4b8db0037030041002d00fca3c680001a20042802042107200428020821080240410841002802c8a3c68000118180808000002209450d0020094100290390fac480003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641043a00202006200336021c2006200236021820064101360214200620093602102006410136020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104410810b280808000000bbf0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206410036023020064280808080c0003703282006410036022020064100360218200641f081808000360210200642a4d2928ecac0faa432370308200642c4ccab9c81ebb4b8db0037030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641013a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000b810401067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c200642113702242006419c93c580003602202006410336021c200641f392c58000360218200641a9828080003602102006429595f4d085b899a16037030820064287bba5b8adf5dafa5b37030041002d00fca3c680001a2004280204210720042802082108024041c00041002802c8a3c68000118180808000002206450d00200641386a41002902e88dc58000370200200641306a41002902e08dc58000370200200641286a41002902d88dc58000370200200641206a41002902d08dc58000370200200641186a41002902c88dc58000370200200641106a41002902c08dc58000370200200641086a41002902b88dc58000370200200641002902b08dc580003702000240200128020822092001280200470d002001200910a086808000200128020821090b2001280204200941246c6a220941063a00202009200336021c2009200236021820094108360214200920063602102009410836020c2009200541016a360208200920083602042009200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b410441c00010b280808000000bc00201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206410036023020064280808080c00037032820064100360220200641003602182006419482808000360210200642c0969aec91e181fcf200370308200642d7a7fbff94a5afcaf80037030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641013a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bd40403037f017e037f23808080800041206b2204248080808000200441146a41086a22054100360200200442808080808001370214200441146a410010a48680800020042802182005280200220641386c6a2205420437022c20054214370224200541df92c580003602202005410336021c200541f392c58000360218200541f081808000360210200542a4d2928ecac0faa432370308200542c4ccab9c81ebb4b8db00370300200441086a41086a200641016a2206360200200420042902142207370308024020062007a7470d00200441086a200610a486808000200428021021060b200428020c200641386c6a2205420437022c2005420a370224200541d192c580003602202005410636021c200541c1fbc48000360218200541ef8080800036021020054293888c8f89fdc6ec9e7f370308200542a5e9e3ab9e929adc2c37030020042802082108200428020c210941002d00fca3c680001a0240411841002802c8a3c6800011818080800000220a450d00200a41106a410029029cfdc48000370200200a41086a4100290294fdc48000370200200a410029028cfdc480003702000240200128020822052001280200470d002001200510a086808000200128020821050b2001280204200541246c6a220541053a00202005200336021c20052002360218200541033602142005200a3602102005410336020c2005200641016a360208200520093602042005200836020020002001290200370200200141086a2205200528020041016a2205360200200041086a2005360200200441206a2480808080000f0b4104411810b280808000000bbe0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206410036023020064280808080c0003703282006410036022020064100360218200641f883808000360210200642dfda92949ba784d566370308200642dc85e1fdf99cd0816b37030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641013a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000beb0603047f017e027f23808080800041206b2204248080808000200441106a41086a22054100360200200442808080808001370210200441106a410010a48680800020042802142005280200220641386c6a2207420437022c2007420c370224200741f7fac480003602202007410436021c200741daa3c58000360218200741f081808000360210200742a4d2928ecac0faa432370308200742c4ccab9c81ebb4b8db00370300200441086a200641016a2206360200200420042902102208370300024020062008a7470d002004200610a486808000200428020821060b2004280204200641386c6a2207420437022c2007420c370224200741f7fac480003602202007410236021c200741d8a3c58000360218200741f081808000360210200742a4d2928ecac0faa432370308200742c4ccab9c81ebb4b8db003703002005200641016a2206360200200420042903002208370310024020062008a7470d00200441106a200610a486808000200428021821060b2004280214200641386c6a2207420437022c2007420a370224200741d192c580003602202007410636021c200741c1fbc48000360218200741ef8080800036021020074293888c8f89fdc6ec9e7f370308200742a5e9e3ab9e929adc2c370300200441086a200641016a2206360200200420042903102208370300024020062008a7470d002004200610a486808000200428020821060b2004280204200641386c6a2207420437022c20074206370224200741fca3c580003602202007411236021c200741eaa3c58000360218200741f983808000360210200742dcb08885f1e3a29706370308200742db8cf7c6bbd3898c8c7f370300200428020021092004280204210a41002d00fca3c680001a0240411041002802c8a3c68000118180808000002205450d00200541086a41002902e49cc58000370200200541002902dc9cc580003702000240200128020822072001280200470d002001200710a086808000200128020821070b2001280204200741246c6a220741063a00202007200336021c2007200236021820074102360214200720053602102007410236020c2007200641016a3602082007200a3602042007200936020020002001290200370200200141086a2207200728020041016a2207360200200041086a2007360200200441206a2480808080000f0b4104411010b280808000000bbf0201057f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c2006421b370224200641bbb2c5800036022020064100360218200641ef82808000360210200642bba2f9a9eaf2f897ff0037030820064288bfcff6aea5a9cbf90037030020042802042107200428020821080240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641013a00202006200336021c200620023602182006410036021420064280808080c00037020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000bbc0301067f23808080800041106b22042480808080002004410036020c200442808080808001370204200441046a410010a4868080002004280208200428020c220541386c6a2206420437022c20064207370224200641e3e4c480003602202006410936021c200641dae4c48000360218200641f581808000360210200642ab8bffbed784ffa5937f370308200642c194a6a793ccc3a85737030041002d00fca3c680001a20042802042107200428020821080240412041002802c8a3c68000118180808000002209450d00200941186a41002902c8eec48000370200200941106a41002902c0eec48000370200200941086a41002902b8eec48000370200200941002902b0eec480003702000240200128020822062001280200470d002001200610a086808000200128020821060b2001280204200641246c6a220641093a00202006200336021c2006200236021820064104360214200620093602102006410436020c2006200541016a360208200620083602042006200736020020002001290200370200200141086a2206200628020041016a2206360200200041086a2006360200200441106a2480808080000f0b4104412010b280808000000b940201047f23808080800041106b220224808080800002400240024002402001108b8280800022030d00410121040c010b2003417f4c0d0141002d00fca3c680001a200341002802c8a3c68000118180808000002204450d020b200241086a220541003602002002200436020420022003360200200220014188026a36020c2002410c6a200210c18a808000200220014190026a36020c2002410c6a200210c18a808000200220014198026a36020c2002410c6a200210c18a8080002002200141a0026a36020c2002410c6a200210c18a8080002001200210f28c808000200041086a200528020036020020002002290200370200200241106a2480808080000f0b10ae80808000000b4101200310b280808000000bae0101017f23808080800041306b2202248080808000200028020021002002410c6a4202370200200241186a410c6a41d08180800036020020022000280200220036022820024103360204200241f0bfc08000360200200241d18180800036021c200220006836022c200141186a28020021002002200241186a36020820022002412c6a3602202002200241286a36021820012802142000200210d9808080002101200241306a24808080800020010bb30f03117f017e067f23808080800041206b2203248080808000024002400240024020014115490d0041002d00fca3c680001a0240200141037441f0ffffff077141002802c8a3c68000118180808000002204450d0041002d00fca3c680001a41800141002802c8a3c68000118180808000002205450d04200041706a2106200041246a210741002108410021094110210a0240034020002008220b410474220c6a210d0240024002402001200b6b220e4102490d000240200d41106a280200220f200d280200200d41146a2802002210200d41046a280200221120102011491b10888e8080002212201020116b20121b4100480d0041022112200e4102460d022007200c6a21114102211203402011417c6a2802002213200f2011280200220c2010200c2010491b10888e808000220f200c20106b200f1b4100480d03201141106a2111200c21102013210f200e201241016a2212460d020c000b0b410221120240200e4102460d002007200c6a21114102211203402011417c6a2802002213200f2011280200220c2010200c2010491b10888e808000220f200c20106b200f1b417f4a0d01201141106a2111200c21102013210f200e201241016a2212470d000b200e21120b024002402012200b6a22082012490d00200820014b0d0120124102490d042012410176210c200620084104746a2110200d21110340201129020021142011201029020037020020102014370200201141086a220f2902002114200f201041086a220e290200370200200e2014370200201041706a2110201141106a2111200c417f6a220c0d000c050b0b200b200841c0b4c58000109681808000000b2008200141c0b4c58000109581808000000b200e21120b2012200b6a21080b024002402008200b490d00200820014d0d010b41b0b5c58000412c41dcb5c5800010f880808000000b024002400240200820014f0d002012410a490d010b2008200b6b21100c010b200b410a6a2210200120102001491b2208200b490d02200d2008200b6b221020124101201241014b1b10d78b8080000b024002402009200a470d0041002d00fca3c680001a200941047441002802c8a3c68000118180808000002211450d012009410174210a20112005200941037410848e8080002111200541002802c0a3c6800011808080800000201121050b200520094103746a2211200b36020420112010360200200941016a22152109024020154102490d0003400240024002400240200520152213417f6a22154103746a2209280200221020092802046a2001460d00201341037420056a220c41706a280200221220104d0d0041022109201341024d0d0520052013417d6a22164103746a2802002211201220106a4d0d0141032109201341034d0d05200c41606a280200201120126a4d0d01201321090c050b20134103490d0120052013417d6a22164103746a28020021110b20112010490d010b2013417e6a21160b024002400240024002400240201320164d0d002013201641016a22104d0d01200520104103746a2217280204201728020022186a2211200520164103746a2219280204221a490d02201120014b0d032000201a4104746a22092019280200220d41047422126a21102011410474210c02402011201a6b220f200d6b2211200d4f0d00200420102011410474221210848e808000220e20126a2112200d4101480d0520114101480d052006200c6a2111034020112012201241706a220c280200201041706a220f280200200c41046a280200220c200f41046a280200220f200c200f491b10888e808000220b200c200f6b200b1b220c411f75220f417f734104746a22122010200f4104746a2210200c417f4a1b220c290200370200201141086a200c41086a290200370200201020094d0d06201141706a21112012200e4d0d060c000b0b20042009201210848e808000221120126a21120240200d41014e0d00201121110c060b0240200f200d4a0d00201121110c060b2000200c6a210e20112111034020092011201020102802002011280200201041046a280200220c201141046a280200220f200c200f491b10888e808000220b200c200f6b200b1b220b417f4a220c1b220f290200370200200941086a200f41086a290200370200200941106a21092011200c4104746a221120124f0d062010200b411b764110716a2210200e490d000c060b0b200341146a42003702002003410136020c200341c4b3c58000360208200341ccb3c58000360210200341086a41d0b4c5800010f680808000000b200341146a42003702002003410136020c200341c4b3c58000360208200341ccb3c58000360210200341086a41e0b4c5800010f680808000000b201a201141f0b4c58000109681808000000b2011200141f0b4c58000109581808000000b20102109200e21110b20092011201220116b10848e8080001a2017201a36020420172018200d6a3602002019201941086a20132016417f736a41037410fe8d8080001a41012109201541014b0d000b0b200820014f0d050c010b0b41a0b5c5800010a081808000000b200b200841ecb5c58000109681808000000b4180b5c5800010a081808000000b200141014d0d0120002001410110d78b8080000c010b200541002802c0a3c6800011808080800000200441002802c0a3c68000118080808000000b200341206a2480808080000f0b4190b5c5800010a081808000000bd60203077f017e017f02402002417f6a20014f0d000240200220014f0d00200241047420006a41606a210303400240200020024104746a22042802002205200441706a2206280200200441046a2802002207200641046a280200220820072008491b10888e8080002209200720086b20091b417f4a0d0020042006290200370200200441086a2204290200210a2004200641086a290200370200024020024101460d004101210b200321040340200441106a2106200520042802002007200441046a280200220820072008491b10888e8080002209200720086b20091b417f4a0d0120062004290200370200200641086a200441086a290200370200200441706a21042002200b41016a220b470d000b200021060b2006200a37020820062007360204200620053602000b200341106a2103200241016a22022001470d000b0b0f0b41fcb5c58000412e41acb6c5800010f880808000000bbe0f03117f017e067f23808080800041206b2203248080808000024002400240024020014115490d0041002d00fca3c680001a02402001410176410c6c41002802c8a3c68000118180808000002204450d0041002d00fca3c680001a41800141002802c8a3c68000118180808000002205450d04200041746a2106200041206a210741002108410021094110210a0240034020002008220b410c6c220c6a210d0240024002402001200b6b220e4102490d000240200d41106a280200220f200d41046a280200200d41146a2802002210200d41086a280200221120102011491b10888e8080002212201020116b20121b4100480d0041022112200e4102460d022007200c6a21114102211203402011417c6a2802002213200f2011280200220c2010200c2010491b10888e808000220f200c20106b200f1b4100480d032011410c6a2111200c21102013210f200e201241016a2212460d020c000b0b410221120240200e4102460d002007200c6a21114102211203402011417c6a2802002213200f2011280200220c2010200c2010491b10888e808000220f200c20106b200f1b417f4a0d012011410c6a2111200c21102013210f200e201241016a2212470d000b200e21120b024002402012200b6a22082012490d00200820014b0d0120124102490d042012410176210c20062008410c6c6a2110200d211103402011280200210f201120102802003602002010200f360200201141046a220f2902002114200f201041046a220e290200370200200e2014370200201041746a21102011410c6a2111200c417f6a220c0d000c050b0b200b200841c0b4c58000109681808000000b2008200141c0b4c58000109581808000000b200e21120b2012200b6a21080b024002402008200b490d00200820014d0d010b41b0b5c58000412c41dcb5c5800010f880808000000b024002400240200820014f0d002012410a490d010b2008200b6b21100c010b200b410a6a2210200120102001491b2208200b490d02200d2008200b6b221020124101201241014b1b10d98b8080000b024002402009200a470d0041002d00fca3c680001a200941047441002802c8a3c68000118180808000002211450d012009410174210a20112005200941037410848e8080002111200541002802c0a3c6800011808080800000201121050b200520094103746a2211200b36020420112010360200200941016a22152109024020154102490d0003400240024002400240200520152213417f6a22154103746a2209280200221020092802046a2001460d00201341037420056a220c41706a280200221220104d0d0041022109201341024d0d0520052013417d6a22164103746a2802002211201220106a4d0d0141032109201341034d0d05200c41606a280200201120126a4d0d01201321090c050b20134103490d0120052013417d6a22164103746a28020021110b20112010490d010b2013417e6a21160b024002400240024002400240201320164d0d002013201641016a22104d0d01200520104103746a2217280204201728020022186a2211200520164103746a2219280204221a490d02201120014b0d032000201a410c6c6a22092019280200220d410c6c22126a21102011410c6c210c02402011201a6b220f200d6b2211200d4f0d00200420102011410c6c221210848e808000220e20126a2112200d4101480d0520114101480d052006200c6a2111034020112012201241746a220c41046a280200201041746a220f41046a280200200c41086a280200220c200f41086a280200220f200c200f491b10888e808000220b200c200f6b200b1b220c411f75220f417f73410c6c6a22122010200f410c6c6a2210200c417f4a1b220c290200370200201141086a200c41086a280200360200201020094d0d06201141746a21112012200e4d0d060c000b0b20042009201210848e808000221120126a21120240200d41014e0d00201121110c060b0240200f200d4a0d00201121110c060b2000200c6a210e201121110340200920112010201041046a280200201141046a280200201041086a280200220c201141086a280200220f200c200f491b10888e808000220b200c200f6b200b1b220b417f4a220c1b220f290200370200200941086a200f41086a2802003602002009410c6a21092011200c410c6c6a221120124f0d062010200b411f76410c6c6a2210200e490d000c060b0b200341146a42003702002003410136020c200341c4b3c58000360208200341ccb3c58000360210200341086a41d0b4c5800010f680808000000b200341146a42003702002003410136020c200341c4b3c58000360208200341ccb3c58000360210200341086a41e0b4c5800010f680808000000b201a201141f0b4c58000109681808000000b2011200141f0b4c58000109581808000000b20102109200e21110b20092011201220116b10848e8080001a2017201a36020420172018200d6a3602002019201941086a20132016417f736a41037410fe8d8080001a41012109201541014b0d000b0b200820014f0d050c010b0b41a0b5c5800010a081808000000b200b200841ecb5c58000109681808000000b4180b5c5800010a081808000000b200141014d0d0120002001410110d98b8080000c010b200541002802c0a3c6800011808080800000200441002802c0a3c68000118080808000000b200341206a2480808080000f0b4190b5c5800010a081808000000bd602010a7f02402002417f6a20014f0d000240200220014f0d002002410c6c20006a41686a21030340024020002002410c6c6a220441046a2802002205200441746a220641046a280200200441086a22072802002208200641086a2209280200220a2008200a491b10888e808000220b2008200a6b200b1b417f4a0d002004280200210c2004200629020037020020072009280200360200024020024101460d00410121072003210403402004410c6a21062005200441046a2802002008200441086a2209280200220a2008200a491b10888e808000220b2008200a6b200b1b417f4a0d0120062004290200370200200641086a2009280200360200200441746a21042002200741016a2207470d000b200021060b20062008360208200620053602042006200c3602000b2003410c6a2103200241016a22022001470d000b0b0f0b41fcb5c58000412e41acb6c5800010f880808000000bb70e03137f017e047f23808080800041206b2203248080808000024002400240024020014115490d0041002d00fca3c680001a0240200141017641146c41002802c8a3c68000118180808000002204450d0041002d00fca3c680001a41800141002802c8a3c68000118180808000002205450d042000416c6a2106200041146a210741002108410021094110210a0240034020002008220b41146c220c6a210d0240024002402001200b6b220e4102490d000240200d41146a200d410810888e8080004100480d004102210f200e4102460d022007200c6a21104102210f0340201041146a22112010410810888e8080004100480d0320112110200e200f41016a220f460d020c000b0b4102210f0240200e4102460d002007200c6a21104102210f0340201041146a22112010410810888e808000417f4a0d0120112110200e200f41016a220f470d000b200e210f0b02400240200f200b6a2208200f490d00200820014b0d01200f4102490d04200f4101762112200c200f41146c6a2113200621112000211403402014200c6a221041086a221529020021162015201120136a220e41086a221729020037020020172016370200201029020021162010200e290200370200200e2016370200200e41106a220e2802002115200e201041106a2210280200360200201020153602002011416c6a2111201441146a21142012417f6a22120d000c050b0b200b200841c0b4c58000109681808000000b2008200141c0b4c58000109581808000000b200e210f0b200f200b6a21080b024002402008200b490d00200820014d0d010b41b0b5c58000412c41dcb5c5800010f880808000000b024002400240200820014f0d00200f410a490d010b2008200b6b21100c010b200b410a6a2210200120102001491b2208200b490d02200d2008200b6b2210200f4101200f41014b1b10db8b8080000b024002402009200a470d0041002d00fca3c680001a200941047441002802c8a3c6800011818080800000220e450d012009410174210a200e2005200941037410848e808000210e200541002802c0a3c6800011808080800000200e21050b200520094103746a220e200b360204200e2010360200200941016a22182109024020184102490d0003400240024002400240200520182217417f6a22184103746a2209280200221020092802046a2001460d00201741037420056a221141706a280200220f20104d0d0041022109201741024d0d0520052017417d6a220c4103746a280200220e200f20106a4d0d0141032109201741034d0d05201141606a280200200e200f6a4d0d01201721090c050b20174103490d0120052017417d6a220c4103746a280200210e0b200e2010490d010b2017417e6a210c0b0240024002400240024002402017200c4d0d002017200c41016a22104d0d01200520104103746a2213280204201328020022196a220e2005200c4103746a221a280204220d490d02200e20014b0d032000200d41146c6a2209201a280200220b41146c220f6a2110200e41146c21140240200e200d6b2212200b6b2211200b4f0d0020042010201141146c220e10848e8080002212200e6a210e200b4101480d0520114101480d05200620146a210f0340200f200e200e416c6a2010416c6a410810888e8080002211411f752214417f7341146c6a220e2010201441146c6a22102011417f4a1b2211290200370200200f41106a201141106a280200360200200f41086a201141086a290200370200201020094d0d06200f416c6a210f200e20124d0d060c000b0b20042009200f10848e8080002211200f6a210e0240200b41014e0d002011210f0c060b02402012200b4a0d002011210f0c060b200020146a21152011210f03402009200f20102010200f410810888e8080002212417f4a22141b2211290200370200200941106a201141106a280200360200200941086a201141086a290200370200200941146a2109200f201441146c6a220f200e4f0d0620102012411f7641146c6a22102015490d000c060b0b200341146a42003702002003410136020c200341c4b3c58000360208200341ccb3c58000360210200341086a41d0b4c5800010f680808000000b200341146a42003702002003410136020c200341c4b3c58000360208200341ccb3c58000360210200341086a41e0b4c5800010f680808000000b200d200e41f0b4c58000109681808000000b200e200141f0b4c58000109581808000000b201021092012210f0b2009200f200e200f6b10848e8080001a2013200d36020420132019200b6a360200201a201a41086a2017200c417f736a41037410fe8d8080001a41012109201841014b0d000b0b200820014f0d050c010b0b41a0b5c5800010a081808000000b200b200841ecb5c58000109681808000000b4180b5c5800010a081808000000b200141014d0d0120002001410110db8b8080000c010b200541002802c0a3c6800011808080800000200441002802c0a3c68000118080808000000b200341206a2480808080000f0b4190b5c5800010a081808000000b8a0303047f017e037f23808080800041206b220324808080800002402002417f6a20014f0d000240200220014f0d00200241146c20006a41586a2104034002402000200241146c6a22052005416c6a2206410810888e808000417f4a0d002005290200210720052006290200370200200341086a41106a2208200541106a2209280200360200200341086a41086a220a200541086a22052902003703002005200641086a2902003702002009200641106a28020036020020032007370308024020024101460d0041012109200421050340200541146a2106200341086a2005410810888e808000417f4a0d0120062005290200370200200641106a200541106a280200360200200641086a200541086a2902003702002005416c6a21052002200941016a2209470d000b200021060b20062003290308370200200641106a2008280200360200200641086a200a2903003702000b200441146a2104200241016a22022001470d000b0b200341206a2480808080000f0b41fcb5c58000412e41acb6c5800010f880808000000baf1501197f23808080800041206b2203248080808000024002400240024020014115490d0041002d00fca3c680001a0240200141047441e0ffffff077141002802c8a3c68000118180808000002204450d0041002d00fca3c680001a41800141002802c8a3c68000118180808000002205450d04200041606a2106200041206a210741002108410021094110210a0240034020002008220b410574220c6a210d0240024002402001200b6b220e4102490d000240200d41206a200d412010888e8080004100480d004102210f200e4102460d022007200c6a21104102210f0340201041206a22112010412010888e8080004100480d0320112110200e200f41016a220f460d020c000b0b4102210f0240200e4102460d002007200c6a21104102210f0340201041206a22112010412010888e808000417f4a0d0120112110200e200f41016a220f470d000b200e210f0b02400240200f200b6a2208200f490d00200820014b0d01200f4102490d04200f4101762112200c200f4105746a2113200621112000211403402014200c6a221028000021152010201120136a220e280000360000200e2015360000200e41056a2d00002115200e41046a22162d000021172016201041046a22182f00003b0000201041076a2d00002116201041066a22192d0000211a2019200e41066a221b2f00003b0000201820173a0000201041056a20153a0000201b201a3a0000200e41076a20163a0000201041086a22152d000021162015200e41086a22172d00003a0000201720163a0000201041096a22152d000021162015200e41096a22172d00003a0000201720163a00002010410a6a22152d000021162015200e410a6a22172d00003a0000201720163a00002010410b6a22152d000021162015200e410b6a22172d00003a0000201720163a00002010410c6a22152d000021162015200e410c6a22172d00003a0000201720163a00002010410d6a22152d000021162015200e410d6a22172d00003a0000201720163a00002010410e6a22152d000021162015200e410e6a22172d00003a0000201720163a00002010410f6a22152d000021162015200e410f6a22172d00003a0000201720163a0000201041106a22152d000021162015200e41106a22172d00003a0000201720163a0000201041116a22152d000021162015200e41116a22172d00003a0000201720163a0000201041126a22152d000021162015200e41126a22172d00003a0000201720163a0000201041136a22152d000021162015200e41136a22172d00003a0000201720163a0000201041146a22152d000021162015200e41146a22172d00003a0000201720163a0000201041156a22152d000021162015200e41156a22172d00003a0000201720163a0000201041166a22152d000021162015200e41166a22172d00003a0000201720163a0000201041176a22152d000021162015200e41176a22172d00003a0000201720163a0000201041186a22152d000021162015200e41186a22172d00003a0000201720163a0000201041196a22152d000021162015200e41196a22172d00003a0000201720163a00002010411a6a22152d000021162015200e411a6a22172d00003a0000201720163a00002010411b6a22152d000021162015200e411b6a22172d00003a0000201720163a00002010411c6a22152d000021162015200e411c6a22172d00003a0000201720163a00002010411d6a22152d000021162015200e411d6a22172d00003a0000201720163a00002010411e6a22152d000021162015200e411e6a22172d00003a0000201720163a00002010411f6a22102d000021152010200e411f6a220e2d00003a0000200e20153a0000201141606a2111201441206a21142012417f6a22120d000c050b0b200b200841c0b4c58000109681808000000b2008200141c0b4c58000109581808000000b200e210f0b200f200b6a21080b024002402008200b490d00200820014d0d010b41b0b5c58000412c41dcb5c5800010f880808000000b024002400240200820014f0d00200f410a490d010b2008200b6b21100c010b200b410a6a2210200120102001491b2208200b490d02200d2008200b6b2210200f4101200f41014b1b10dd8b8080000b024002402009200a470d0041002d00fca3c680001a200941047441002802c8a3c6800011818080800000220e450d012009410174210a200e2005200941037410848e808000210e200541002802c0a3c6800011808080800000200e21050b200520094103746a220e200b360204200e2010360200200941016a220b21090240200b4102490d00034002400240024002402005200b2216417f6a220b4103746a220e2802002210200e2802046a2001460d00201641037420056a221141706a280200220f20104d0d0041022109201641024d0d0520052016417d6a22184103746a280200220e200f20106a4d0d0141032109201641034d0d05201141606a280200200e200f6a4d0d01201621090c050b20164103490d0120052016417d6a22184103746a280200210e0b200e2010490d010b2016417e6a21180b024002400240024002400240201620184d0d002016201841016a22104d0d01200520104103746a22192802042019280200220c6a2209200520184103746a221b280204221a490d02200920014b0d032000201a4105746a220e201b2802002217410574220f6a21102009410574211102402009201a6b221420176b220920174f0d00200420102009410574220f10848e8080002212200f6a210f20174101480d0520094101480d05200620116a210903402009200f200f41606a201041606a412010888e8080002211411f752214417f734105746a220f201020144105746a22102011417f4a1b2211290000370000200941186a201141186a290000370000200941106a201141106a290000370000200941086a201141086a2900003700002010200e4d0d06200941606a2109200f20124d0d060c000b0b2004200e200f10848e8080002209200f6a210f0240201741014e0d00200921090c060b0240201420174a0d00200921090c060b200020116a2115200921090340200e2009201020102009412010888e8080002212417f4a22141b2211290000370000200e41186a201141186a290000370000200e41106a201141106a290000370000200e41086a201141086a290000370000200e41206a210e200920144105746a2209200f4f0d0620102012411a764120716a22102015490d000c060b0b200341146a42003702002003410136020c200341c4b3c58000360208200341ccb3c58000360210200341086a41d0b4c5800010f680808000000b200341146a42003702002003410136020c200341c4b3c58000360208200341ccb3c58000360210200341086a41e0b4c5800010f680808000000b201a200941f0b4c58000109681808000000b2009200141f0b4c58000109581808000000b2010210e201221090b200e2009200f20096b10848e8080001a2019201a3602042019200c20176a360200201b201b41086a20162018417f736a41037410fe8d8080001a41012109200b41014b0d000b0b200820014f0d050c010b0b41a0b5c5800010a081808000000b200b200841ecb5c58000109681808000000b4180b5c5800010a081808000000b200141014d0d0120002001410110dd8b8080000c010b200541002802c0a3c6800011808080800000200441002802c0a3c68000118080808000000b200341206a2480808080000f0b4190b5c5800010a081808000000bbf0303047f017e057f23808080800041206b220324808080800002402002417f6a20014f0d000240200220014f0d00200241057420006a41406a210403400240200020024105746a2205200541606a2206412010888e808000417f4a0d002005290000210720052006290000370000200341186a2208200541186a2209290000370300200341106a220a200541106a220b290000370300200341086a220c200541086a22052900003703002005200641086a290000370000200b200641106a2900003700002009200641186a29000037000020032007370300024020024101460d0041012109200421050340200541206a210620032005412010888e808000417f4a0d0120062005290000370000200641186a200541186a290000370000200641106a200541106a290000370000200641086a200541086a290000370000200541606a21052002200941016a2209470d000b200021060b20062003290300370000200641186a2008290300370000200641106a200a290300370000200641086a200c2903003700000b200441206a2104200241016a22022001470d000b0b200341206a2480808080000f0b41fcb5c58000412e41acb6c5800010f880808000000b920402027f017e23808080800041d0006b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c68000024020010d00200241386a410029028cb8c58000370300200241306a4100290284b8c58000370300200241286a41002902fcb7c58000370300200241206a41002902f4b7c58000370300200241186a41002902ecb7c58000370300200241106a41002902e4b7c58000370300200241002902dcb7c58000370308200241c0006a200241086a108e8d8080002002350248210420022802442103024020022802082201418080808078460d002001450d00200228020c41002802c0a3c68000118080808000000b024020022802142201418080808078460d002001450d00200241186a28020041002802c0a3c68000118080808000000b024020022802202201418080808078460d002001450d00200241246a28020041002802c0a3c68000118080808000000b200241d0006a24808080800020044220862003ad840f0b200241146a42003702002002410136020c200241f0b8c580003602082002200241cc006a360210200241086a41dcb9c5800010f680808000000bd50401027f23808080800041d0026b220224808080800041004100280280a4c680002203410120031b360280a4c68000200041ccb3c5800020011b2100024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680002002200136020420022000360200200241c8016a418002200210988d808000024020022802c002418080808078460d00200241086a200241c8016a41880110848e8080001a02404100280284a4c680004105470d00200241a8016a410136020020024194016a410c6a4101360200200241fa838080003602b001200241013602980120024198a1c48000360294012002200241086a3602ac01200241033a00e401200241043602e001200242203702d801200241023602d001200241023602c8012002200241c8016a3602a4012002200241ac016a36029c01200241b4016a410c6a4116360200200241a0a1c480003602c401200241fe8bc480003602bc01200241163602b801200241e88bc480003602b40120024194016a4105200241b4016a4100200210a1828080000b200241c8016a200241086a41880110848e8080001a200241c8016a10fa8c808000200241d0026a24808080800042010f0b200241146a42013702002002410136020c20024198bac58000360208200241fb8380800036029801200220024194016a3602102002200241b4016a36029401200241086a41dcb9c5800010f680808000000bd50801057f23808080800041a0026b220224808080800041004100280280a4c680002203410120031b360280a4c68000200041ccb3c5800020011b2100024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c6800020022001360204200220003602002002428080808080203702f001200220023602ec01200241f0006a200241ec016a10dc8c8080000240024020022802d8012200418080808078460d00200241086a200241f0006a41e80010848e8080001a20022802e001210320022802dc0121012002280204450d0102402003450d00200121044100210503402001200541146c6a21060240024002400240024020042d00000e0400010102040b200441086a21060c020b200641086a21060c010b200641046a21060b2006280200450d00200628020441002802c0a3c68000118080808000000b200541016a2105200441146a21042003417f6a22030d000b0b2000450d00200141002802c0a3c68000118080808000000b200241fc006a420137020020024101360274200241d0bac58000360270200241fb8380800036020c2002200241086a3602782002200241ec016a360208200241f0006a41dcb9c5800010f680808000000b20022802e4012104200241f0006a200241086a41e80010848e8080001a200220043602e401200220033602e001200220013602dc01200220003602d8014100280284a4c6800021012002200241f0006a3602e801200241f0006a2103024020014105470d0020024180026a4101360200200241ec016a410c6a4101360200200241fc8380800036028802200241013602f001200241c4a1c480003602ec012002200241e8016a36028402200241033a0024200241043602202002422037021820024102360210200241023602082002200241086a3602fc01200220024184026a3602f4012002418c026a410c6a4116360200200241cca1c4800036029c02200241fe8bc48000360294022002411636029002200241e88bc4800036028c02200241ec016a41052002418c026a4100200310a18280800020022802e80121030b200310fb8c8080002106024020022802e0012204450d0020022802dc01220521034100210103402005200141146c6a21000240024002400240024020032d00000e0400010102040b200341086a21000c020b200041086a21000c010b200041046a21000b2000280200450d00200028020441002802c0a3c68000118080808000000b200141016a2101200341146a21032004417f6a22040d000b0b024020022802d801450d0020022802dc0141002802c0a3c68000118080808000000b41002d00fca3c680001a0240410141002802c8a3c68000118180808000002203450d00200320063a0000200241a0026a2480808080002003ad428080808010840f0b4101410110b280808000000bf60202027f017e23808080800041f0026b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c68000024020010d00200241f0006a10e489808000200241106a200241f0006a10cf84808000200241868080807836020c200241edcad18b0636026c20022002410c6a10c181808000200241f0006a20022802042201200228020810f183808000200235027821042002280274210302402002280200450d00200141002802c0a3c68000118080808000000b200241f0026a24808080800020044220862003ad840f0b200241fc006a420037020020024101360274200241b4bbc5800036027020022002410c6a360278200241f0006a41dcb9c5800010f680808000000bcb0302027f017e23808080800041f0026b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c68000024020014104490d0020014104470d00200041ccb3c5800020011b2800002101200241f0006a10e4898080002002410c6a200241f0006a200110ce8480800002400240200228020c418780808078470d0020024180808080783602000c010b200241f0006a2002410c6a41e40010848e8080001a2002200241f0006a10c1818080000b200241f0006a200210b48c8080002002350278210420022802742101024020022802002203418080808078460d002003450d00200228020441002802c0a3c68000118080808000000b200241f0026a24808080800020044220862001ad840f0b200241fc006a420137020020024101360274200241ecbbc58000360270200241fb8380800036021020022002410c6a3602782002200236020c200241f0006a41dcb9c5800010f680808000000bcb0202027f017e23808080800041206b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680000240024020010d0041002d00fca3c680001a410841002802c8a3c68000118180808000002203450d012003428e808080f001370200200241046a2003410210d88580800020022902082104200341002802c0a3c6800011808080800000200241206a24808080800020040f0b200241106a420037020020024101360208200241d8bcc5800036020420022002411c6a36020c200241046a41dcb9c5800010f680808000000b4104410810b280808000000ba90703027f017e027f23808080800041b0046b220224808080800041004100280280a4c680002203410120031b360280a4c68000200041ccb3c5800020011b2100024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680002002200136020c20022000360208200241106a418002200241086a10dc8780800002402002280210450d0020022d00f8012103200241a0026a200241106a41e80110848e8080001a20024188046a41186a20024191026a29000037030020024198046a20024189026a29000037030020024190046a20024181026a290000370300200220022900f90137038804200241106a2003200241a0026a20024188046a10e589808000200241106a10b2888080002104024020022802202203418080808078460d000240200241106a41186a2802002200450d00200228022421052000410171210641002101024020004101460d002000417e7121002005210341002101034002402003280200450d00200341046a28020041002802c0a3c68000118080808000000b02402003410c6a280200450d00200341106a28020041002802c0a3c68000118080808000000b200341186a21032000200141026a2201470d000b0b02402006450d0020052001410c6c6a2203280200450d00200328020441002802c0a3c68000118080808000000b200228022021030b02402003450d00200228022441002802c0a3c68000118080808000000b0240200241346a2802002203450d00200241306a28020021052003410171210641002101024020034101460d002003417e7121002005210341002101034002402003280200450d00200341046a28020041002802c0a3c68000118080808000000b02402003410c6a280200450d00200341106a28020041002802c0a3c68000118080808000000b200341186a21032000200141026a2201470d000b0b2006450d0020052001410c6c6a2203280200450d00200328020441002802c0a3c68000118080808000000b200228022c450d00200228023041002802c0a3c68000118080808000000b200241b0046a24808080800020040f0b200241ac026a4201370200200241013602a40220024194bdc580003602a002200241fb8380800036028c04200220024188046a3602a8022002200241af046a36028804200241a0026a41dcb9c5800010f680808000000bbf0302027f017e23808080800041f0036b220224808080800041004100280280a4c680002203410120031b360280a4c68000200041ccb3c5800020011b2100024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680002002200136020c200220003602082002428080808080203702e8032002200241086a3602e403200241f8016a200241e4036a10f58c8080000240024020022802f8012203450d00200241106a410472200241f8016a410472220141e40110848e808000210020022003360210200228020c450d01200241106a10f68c8080000b20024184026a4201370200200241013602fc01200241c8bdc580003602f801200241fb838080003602142002200241106a360280022002200241e4036a360210200241f8016a41dcb9c5800010f680808000000b2001200041e40110848e8080001a200220033602f801200241106a200241f8016a10fc8c808000200241106a10b0888080002104200241f0036a24808080800020040bfe0503027f017e047f2380808080004190016b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c68000024020010d0002404100280284a4c680004105470d002002410c6a42003702002002410136020420024184a2c48000360200200241e8d1c38000360208200241fc006a410c6a41163602002002418ca2c4800036028c01200241fe8bc48000360284012002411636028001200241e88bc4800036027c20024105200241fc006a4100200310a1828080000b200210ff8c8080004101210302402002290320220442c000540d0041022103200442808001540d00410421032004428080808004540d004109200479a74103766b21030b0240417f200241f0006a28020041146c20036a41046a220120012003491b2203417f4c0d0041002d00fca3c680001a0240200341002802c8a3c68000118180808000002201450d00200241003602840120022001360280012002200336027c2002200241fc006a10dd8c80800020023502840121042002280280012105024020022802702206450d00200241ec006a280200220721034100210103402007200141146c6a21080240024002400240024020032d00000e0400010102040b200341086a21080c020b200841086a21080c010b200841046a21080b2008280200450d00200828020441002802c0a3c68000118080808000000b200141016a2101200341146a21032006417f6a22060d000b0b02402002280268450d00200228026c41002802c0a3c68000118080808000000b20024190016a24808080800020044220862005ad840f0b4101200310b280808000000b10ae80808000000b2002410c6a420037020020024101360204200241b4bec580003602002002200241fc006a360208200241dcb9c5800010f680808000000bfb0402027f017e23808080800041e0006b220224808080800041004100280280a4c680002203410120031b360280a4c68000200041ccb3c5800020011b2100024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c6800020022001360214200220003602102002428080808080203702442002200241106a360240200241086a200241c0006a10bc8a8080000240024020022802080d00200228020c21012002200228024441016a2203360244200320022802484b0d00200241003a004f200220013602202002410036021c2002200241c0006a3602182002200241cf006a360224200241d0006a200241186a10d28c808000024020022d004f450d00200241d0006a10d38c8080000c010b200241306a41086a2203200241d0006a41086a280200360200200220022903503703302002280214450d01200241306a10d38c8080000b200241246a42013702002002410136021c200241ecbec58000360218200241fb838080003602542002200241d0006a3602202002200241c0006a360250200241186a41dcb9c5800010f680808000000b200241186a41086a20032802003602002002200229033037031820024100360258200242808080808001370250200241186a10d38c808000200241186a41084100108c8d80800020023502202104200228021c2103200241d0006a108f8780800002402002280250450d00200228025441002802c0a3c68000118080808000000b200241e0006a24808080800020044220862003ad840b9f0502047f017e23808080800041d0026b220224808080800041004100280280a4c680002203410120031b360280a4c68000200041ccb3c5800020011b2100024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680002002200136021c20022000360218200241206a418002200241186a10998d8080000240200228029801418080808078460d00200241b8016a200241206a41880110848e8080001a200241c0026a41086a200241b0016a280200360200200220022903a8013703c002200241013b01142002410036021020024100360208200241c0026a10d38c808000200241a4026a28020021040240200241a8026a2802002205450d00200421034100210103402004200141146c6a21000240024002400240024020032d00000e0400010102040b200341086a21000c020b200041086a21000c010b200041046a21000b2000280200450d00200028020441002802c0a3c68000118080808000000b200141016a2101200341146a21032005417f6a22050d000b0b024020022802a002450d00200441002802c0a3c68000118080808000000b200241b0026a108f87808000024020022802b002450d00200241b4026a28020041002802c0a3c68000118080808000000b200241206a200241086a10ba8980800020022902242106200241086a10d38c808000200241d0026a24808080800020060f0b200241c4016a4201370200200241013602bc01200241a0bfc580003602b801200241fb8380800036020c2002200241086a3602c0012002200241c0026a360208200241b8016a41dcb9c5800010f680808000000bae0302027f017e23808080800041f0006b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680000240024020014120490d0020014120470d00200241086a41186a200041ccb3c5800020011b220141186a290000370300200241086a41106a200141106a290000370300200241086a41086a200141086a29000037030020022001290000370308200241286a200241086a10f8878080002002290328210441002d00fca3c680001a410841002802c8a3c68000118180808000002201450d0120012004370000200241f0006a2480808080002001ad42808080808001840f0b200241346a42013702002002410136022c200241d4bfc58000360228200241fb8380800036020c2002200241086a3602302002200241ef006a360208200241286a41dcb9c5800010f680808000000b4101410810b280808000000bb40302027f017e23808080800041f0006b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680000240024020014120490d0020014120470d00200241086a41186a200041ccb3c5800020011b220141186a290000370300200241086a41106a200141106a290000370300200241086a41086a200141086a29000037030020022001290000370308200241286a200241086a10fa87808000200241286a41186a290300210441002d00fca3c680001a410841002802c8a3c68000118180808000002201450d0120012004370000200241f0006a2480808080002001ad42808080808001840f0b200241346a42013702002002410136022c20024184c0c58000360228200241fb8380800036020c2002200241086a3602302002200241ef006a360208200241286a41dcb9c5800010f680808000000b4101410810b280808000000bd90202027f017e23808080800041306b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680000240024020014108490d0020014108470d00200041ccb3c5800020011b290000210441002d00fca3c680001a410841002802c8a3c68000118180808000002201450d012001200442017c370000200241306a2480808080002001ad42808080808001840f0b200241186a420137020020024101360210200241bcc0c5800036020c200241fb838080003602282002200241246a36021420022002412f6a3602242002410c6a41dcb9c5800010f680808000000b4101410810b280808000000bcd0602077f017e23808080800041c0006b220224808080800041004100280280a4c680002203410120031b360280a4c68000200041ccb3c5800020011b2100024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c68000200220013602142002200036021020024280808080802037021c2002200241106a360218200241086a200241186a10bc8a8080000240024020022802080d00200241306a200241186a200228020c10d18580800020022802302204418080808078460d00200228023421052002280214450d012004450d00200541002802c0a3c68000118080808000000b200241246a42013702002002410136021c200241fcc0c58000360218200241fb838080003602342002200241306a36022020022002413f6a360230200241186a41dcb9c5800010f680808000000b0240024002400240200228023822060d00410821070c010b200641ffffffff004b0d0120064103742201417f4c0d0141002d00fca3c680001a200141002802c8a3c68000118180808000002207450d0220072005200110848e808000220021030240200141786a220841037641016a4107712201450d00200141037421012000210303402003200329030042017c370300200341086a2103200141786a22010d000b0b20084138490d00200020064103746a210003402003200329030042017c370300200341086a2201200129030042017c370300200341106a2201200129030042017c370300200341186a2201200129030042017c370300200341206a2201200129030042017c370300200341286a2201200129030042017c370300200341306a2201200129030042017c370300200341386a2201200129030042017c370300200341c0006a22032000470d000b0b02402004450d00200541002802c0a3c68000118080808000000b200241186a2007200610d78580800020023502202109200228021c210302402006450d00200741002802c0a3c68000118080808000000b200241c0006a24808080800020094220862003ad840f0b10ae80808000000b4108200110b280808000000ba50201027f23808080800041206b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680000240024020010d0041002d00fca3c680001a410841002802c8a3c68000118180808000002203450d0120034201370000200241206a2480808080002003ad42808080808001840f0b200241106a420037020020024101360208200241f4c1c5800036020420022002411c6a36020c200241046a41dcb9c5800010f680808000000b4101410810b280808000000baf0202027f017e23808080800041206b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680000240024020010d0010e689808000210441002d00fca3c680001a410841002802c8a3c68000118180808000002203450d0120032004370000200241206a2480808080002003ad42808080808001840f0b200241106a420037020020024101360208200241d8c2c5800036020420022002411c6a36020c200241046a41dcb9c5800010f680808000000b4101410810b280808000000bcc0202027f027e23808080800041206b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680000240024020010d0042002104420021050340200510de8980800020047c2104200542017c220542e807520d000b41002d00fca3c680001a410841002802c8a3c68000118180808000002203450d0120032004370000200241206a2480808080002003ad42808080808001840f0b200241106a420037020020024101360208200241ccc3c5800036020420022002411c6a36020c200241046a41dcb9c5800010f680808000000b4101410810b280808000000bcc0202027f027e23808080800041206b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680000240024020010d0042002104420021050340200510de8980800020047c2104200542017c220542e807520d000b41002d00fca3c680001a410841002802c8a3c68000118180808000002203450d0120032004370000200241206a2480808080002003ad42808080808001840f0b200241106a420037020020024101360208200241bcc4c5800036020420022002411c6a36020c200241046a41dcb9c5800010f680808000000b4101410810b280808000000bb30301027f23808080800041306b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c6800002400240024020014104490d0020014104470d0002400240200041ccb3c5800020011b28000022010d002002410c6a4101410010d68580800020022802142101200228021021030c010b2001417f4c0d0241002d00fca3c680001a200141002802c8a3c68000118180808000002200450d032002410c6a2000410010d6858080002002280214210120022802102103200041002802c0a3c68000118080808000000b200241306a2480808080002001ad4220862003ad840f0b200241186a420137020020024101360210200241f4c4c5800036020c200241fb838080003602282002200241246a36021420022002412f6a3602242002410c6a41dcb9c5800010f680808000000b10ae80808000000b4101200110b280808000000bd80202027f027e23808080800041c0006b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680000240024020010d002002411c6a10ab8a808000200241086a2002411c6a10e688808000200229031021042002290308210541002d00fca3c680001a410841002802c8a3c68000118180808000002203450d012003200442002005a71b370000200241c0006a2480808080002003ad42808080808001840f0b200241286a420037020020024101360220200241e0c5c5800036021c20022002413c6a3602242002411c6a41dcb9c5800010f680808000000b4101410810b280808000000b860401027f23808080800041f0006b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680000240024020010d002002410c6a10e78980800041002d00fca3c680001a41e00041002802c8a3c68000118180808000002203450d012003200229000c3700002003200229004c370040200341386a2002410c6a41386a290000370000200341306a2002410c6a41306a290000370000200341286a2002410c6a41286a290000370000200341206a2002410c6a41206a290000370000200341186a2002410c6a41186a290000370000200341106a2002410c6a41106a290000370000200341086a2002410c6a41086a290000370000200341c8006a2002410c6a41c8006a290000370000200341d0006a2002410c6a41d0006a290000370000200341d8006a2002410c6a41d8006a290000370000200241f0006a2480808080002003ad4280808080800c840f0b200241186a420037020020024101360210200241d0c6c5800036020c2002200241ec006a3602142002410c6a41dcb9c5800010f680808000000b410141e00010b280808000000b860401027f23808080800041f0006b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680000240024020010d002002410c6a10e88980800041002d00fca3c680001a41e00041002802c8a3c68000118180808000002203450d012003200229000c3700002003200229004c370040200341386a2002410c6a41386a290000370000200341306a2002410c6a41306a290000370000200341286a2002410c6a41286a290000370000200341206a2002410c6a41206a290000370000200341186a2002410c6a41186a290000370000200341106a2002410c6a41106a290000370000200341086a2002410c6a41086a290000370000200341c8006a2002410c6a41c8006a290000370000200341d0006a2002410c6a41d0006a290000370000200341d8006a2002410c6a41d8006a290000370000200241f0006a2480808080002003ad4280808080800c840f0b200241186a420037020020024101360210200241c0c7c5800036020c2002200241ec006a3602142002410c6a41dcb9c5800010f680808000000b410141e00010b280808000000b9c0301027f23808080800041f0006b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680000240024020010d00200241086a10e98980800041002d00fca3c680001a41e20041002802c8a3c68000118180808000002203450d012003200241086a41c10010848e808000220341e1006a200241086a41e1006a2d00003a0000200341d9006a200241086a41d9006a290000370000200341d1006a200241086a41d1006a290000370000200341c9006a200241086a41c9006a29000037000020032002290049370041200241f0006a2480808080002003ad4280808080a00c840f0b200241146a42003702002002410136020c200241acc8c580003602082002200241ec006a360210200241086a41dcb9c5800010f680808000000b410141e20010b280808000000bec0101027f23808080800041206b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c68000024020010d0010ea89808000200241206a24808080800042010f0b200241106a42003702002002410136020820024194c9c5800036020420022002411c6a36020c200241046a41dcb9c5800010f680808000000bab0301027f23808080800041f0006b220224808080800041004100280280a4c680002203410120031b360280a4c68000200041ccb3c5800020011b2100024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680002002200136020420022000360200200241086a418002200210b48a808000024020022802080d00200241386a41086a200241146a280200360200200241c8006a41086a200241086a41186a290200370300200241c8006a41106a200241286a290200370300200241c8006a41186a200241306a2902003703002002200229020c3703382002200241086a41106a290200370348200241386a200241c8006a10eb89808000200241f0006a24808080800042010f0b200241d4006a42013702002002410136024c200241c8c9c58000360248200241fb8380800036023c2002200241386a3602502002200241ef006a360238200241c8006a41dcb9c5800010f680808000000b8b0301027f23808080800041d0006b220224808080800041004100280280a4c680002203410120031b360280a4c68000200041ccb3c5800020011b2100024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c6800020022001360208200220003602042002410c6a418002200241046a1089878080000240200228020c418080808078460d00200241c0006a41086a2002410c6a41086a280200360200200241286a41086a200241206a2802003602002002200229020c37034020022002290218370328200241c0006a200241286a200228022410ec89808000200241d0006a24808080800042010f0b200241346a42013702002002410136022c20024184cac58000360228200241fb838080003602442002200241c0006a3602302002200241cf006a360240200241286a41dcb9c5800010f680808000000bec0101027f23808080800041206b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c68000024020010d0010ed89808000200241206a24808080800042010f0b200241106a420037020020024101360208200241eccac5800036020420022002411c6a36020c200241046a41dcb9c5800010f680808000000b820a01167f23808080800041d0026b220224808080800041004100280280a4c680002203410120031b360280a4c68000200041ccb3c5800020011b2100024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680002002200036020c2002200136021020024280808080802037027820022002410c6a36027402400240200141c000490d00200241e0016a41086a200041086a290000370300200241e0016a41106a200041106a290000370300200241e0016a41186a200041186a290000370300200241e0016a41206a200041206a290000370300200241e0016a41286a200041286a290000370300200241e0016a41306a200041306a290000370300200241e0016a41386a200041386a2900003703002002200041c0006a220336020c200220002900003703e0012002200141406a220436021020044120490d00200241a0026a41086a200341086a290000370300200241a0026a41106a200341106a290000370300200241a0026a41186a200341186a2900003703002002200141a07f6a3602102002200041e0006a36020c200220032900003703a0022002200241f4006a10bc8a80800020022802000d00200241c4026a200241f4006a200228020410d08580800020022802c4022201418080808078460d0020024180016a41086a2203200241e0016a41086a220429030037030020024180016a41106a2205200241e0016a41106a220629030037030020024180016a41186a2207200241e0016a41186a220829030037030020024180016a41206a2209200241e0016a41206a220a29030037030020024180016a41286a220b200241e0016a41286a220c29030037030020024180016a41306a220d200241e0016a41306a220e29030037030020024180016a41386a220f200241e0016a41386a2210290300370300200220022903e0013703800120022802cc02211120022802c8022100200241d8016a2212200241a0026a41186a2213290300370300200241d0016a2214200241a0026a41106a2215290300370300200241c8016a2216200241a0026a41086a2217290300370300200220022903a0023703c001200241146a20024180016a41e00010848e8080001a2002280210450d012001450d00200041002802c0a3c68000118080808000000b2002418c016a42013702002002410136028401200241a0cbc5800036028001200241fb838080003602182002200241146a360288012002200241e0016a36021420024180016a41dcb9c5800010f680808000000b20024180016a200241146a41e00010848e8080001a200420032902003703002006200529020037030020082007290200370300200a2009290200370300200c200b290200370300200e200d2902003703002010200f29020037030020172016290200370300201520142902003703002013201229020037030020022002290280013703e001200220022902c0013703a002200241e0016a20002011200241a0026a41002802a8a2c6800011898080800000210302402001450d00200041002802c0a3c68000118080808000000b41002d00fca3c680001a0240410141002802c8a3c68000118180808000002200450d00200020033a0000200241d0026a2480808080002000ad428080808010840f0b4101410110b280808000000be90301047f23808080800041d0006b220224808080800041004100280280a4c680002203410120031b360280a4c68000200041ccb3c5800020011b2100024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680002002200136020c20022000360208200241106a418002200241086a1088878080000240024020022802102203418080808078460d0020022d00282101200228021c2100200228021422042002280218200241206a2802002205200241246a28020041002802e0a1c680001186808080000020010d0102402000450d00200541002802c0a3c68000118080808000000b02402003450d00200441002802c0a3c68000118080808000000b200241d0006a24808080800042010f0b200241386a420137020020024101360230200241d4cbc5800036022c200241fb838080003602482002200241c4006a3602342002200241cf006a3602442002412c6a41dcb9c5800010f680808000000b2002411c6a420037020020024101360214200241eca3c48000360210200241e8d1c38000360218200241106a41f4a3c4800010f680808000000ba60201027f23808080800041206b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680000240024020010d0041002d00fca3c680001a410841002802c8a3c68000118180808000002203450d01200342e807370000200241206a2480808080002003ad42808080808001840f0b200241106a420037020020024101360208200241bcccc5800036020420022002411c6a36020c200241046a41dcb9c5800010f680808000000b4101410810b280808000000bc60202037f017e23808080800041206b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c68000024020010d00200241046a10eb8880800020022802042103200241046a20022802082204200228020c108489808000200235020c2105200228020821010240200341ffffff3f71450d00200441002802c0a3c68000118080808000000b200241206a24808080800020054220862001ad840f0b200241106a420037020020024101360208200241a4cdc5800036020420022002411c6a36020c200241046a41dcb9c5800010f680808000000bb70202027f017e23808080800041e0006b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c68000024020010d00200210ee89808000200241d4006a200210ce86808000200235025c21042002280258210302402002280240450d00200241c4006a28020041002802c0a3c68000118080808000000b200241e0006a24808080800020044220862003ad840f0b2002410c6a4200370200200241013602042002418ccec580003602002002200241d4006a360208200241dcb9c5800010f680808000000bbe0302027f027e23808080800041e0006b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c6800002400240024020010d002002413c6a10cb87808000200241286a2002413c6a10e688808000200241086a2002290330420020022802281b42004206420010878e8080002002413c6a10ca87808000200241186a2002413c6a10e78880800020022903104200520d01200229030822042002290320420020022802181b7c22052004540d0141002d00fca3c680001a410841002802c8a3c68000118180808000002203450d0220032005370000200241e0006a2480808080002003ad42808080808001840f0b200241c8006a420037020020024101360240200241fccec5800036023c2002200241dc006a3602442002413c6a41dcb9c5800010f680808000000b41c18fc2800041fa0041bc90c2800010a181808000000b4101410810b280808000000bb70202027f017e23808080800041f0006b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c68000024020010d00200210b287808000200241e4006a200210cd86808000200235026c21042002280268210302402002280250450d00200241d4006a28020041002802c0a3c68000118080808000000b200241f0006a24808080800020044220862003ad840f0b2002410c6a420037020020024101360204200241e4cfc580003602002002200241e4006a360208200241dcb9c5800010f680808000000bb70202027f017e23808080800041f0006b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c68000024020010d00200210b187808000200241e4006a200210cd86808000200235026c21042002280268210302402002280250450d00200241d4006a28020041002802c0a3c68000118080808000000b200241f0006a24808080800020044220862003ad840f0b2002410c6a420037020020024101360204200241ccd0c580003602002002200241e4006a360208200241dcb9c5800010f680808000000bc40301027f23808080800041e0046b220224808080800041004100280280a4c680002203410120031b360280a4c68000200041ccb3c5800020011b2100024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680002002200136020c20022000360208200241106a418002200241086a10978d80800002400240200228029802418080808078460d00200241b8026a200241106a41980210848e8080001a200241d8046a200241b0026a280200360200200220022903a8023703d004200241b8026a200241d0046a10ef89808000210141002d00fca3c680001a410141002802c8a3c68000118180808000002203450d01200320013a0000200241e0046a2480808080002003ad428080808010840f0b200241c4026a4201370200200241013602bc02200241a0d1c580003602b802200241fb838080003602d4042002200241d0046a3602c0022002200241df046a3602d004200241b8026a41dcb9c5800010f680808000000b4101410110b280808000000be40202027f017e23808080800041306b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c68000024020014108490d0020014128470d002002418080808078360208200241146a200241086a10b48c808000200235021c210420022802182103024020022802082201418080808078460d002001450d00200228020c41002802c0a3c68000118080808000000b200241306a24808080800020044220862003ad840f0b200241206a420137020020024101360218200241e4d1c58000360214200241fb8380800036020c2002200241086a36021c20022002412f6a360208200241146a41dcb9c5800010f680808000000b9a0601057f2380808080004180026b220224808080800041004100280280a4c680002203410120031b360280a4c68000200041ccb3c5800020011b2100024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680002002200136020c200220003602082002428080808080203702f8012002200241086a3602f401200241f8006a200241f4016a10dc8c8080000240024020022802e0012200418080808078460d00200241106a200241f8006a41e80010848e8080001a20022802e801210320022802e4012101200228020c450d0102402003450d00200121044100210503402001200541146c6a21060240024002400240024020042d00000e0400010102040b200441086a21060c020b200641086a21060c010b200641046a21060b2006280200450d00200628020441002802c0a3c68000118080808000000b200541016a2105200441146a21042003417f6a22030d000b0b2000450d00200141002802c0a3c68000118080808000000b20024184016a42013702002002410136027c20024198d2c58000360278200241fb838080003602142002200241106a360280012002200241f4016a360210200241f8006a41dcb9c5800010f680808000000b20022802ec012104200241f8006a200241106a41e80010848e8080001a200220043602ec01200220033602e801200220013602e401200220003602e001200241f8006a10f089808000024020022802e8012204450d0020022802e401220521034100210103402005200141146c6a21000240024002400240024020032d00000e0400010102040b200341086a21000c020b200041086a21000c010b200041046a21000b2000280200450d00200028020441002802c0a3c68000118080808000000b200141016a2101200341146a21032004417f6a22040d000b0b024020022802e001450d0020022802e40141002802c0a3c68000118080808000000b20024180026a24808080800042010be80402037f017e23808080800041c0006b220224808080800041004100280280a4c680002203410120031b360280a4c68000200041ccb3c5800020011b2104024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c6800020022001360214200220043602102002428080808080203702342002200241106a36023002402001450d0020022001417f6a22013602142002200041016a360210024002400240024020002d00000e020100040b200241086a200241306a10bc8a80800020022802080d03200241186a200241306a200228020c10d08580800020022802182201418080808078460d03200228021c21002002280214450d012001450d03200041002802c0a3c68000118080808000000c030b20010d022002418080808078360218200241306a200241186a10e2898080000c010b2001418180808078460d012002418080808078360218200241306a200241186a10e2898080002001450d00200041002802c0a3c68000118080808000000b200241186a20022802342200200228023810d68580800020023502202105200228021c210102402002280230450d00200041002802c0a3c68000118080808000000b200241c0006a24808080800020054220862001ad840f0b200241246a42013702002002410136021c200241d4d2c58000360218200241fb838080003602342002200241306a36022020022002413f6a360230200241186a41dcb9c5800010f680808000000ba10803027f017e037f23808080800041f0016b220224808080800041004100280280a4c680002203410120031b360280a4c68000200041ccb3c5800020011b2100024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c68000200220013602202002200036021c20024280808080802037028c0120022002411c6a36028801200241086a20024188016a10bc8a8080000240024020022802080d00200241246a20024188016a200228020c10d08580800020022802242200418080808078460d00200228022821032002280220450d012000450d00200341002802c0a3c68000118080808000000b20024194016a42013702002002410136028c012002418cd3c5800036028801200241fb838080003602282002200241246a360290012002200241106a36022420024188016a41dcb9c5800010f680808000000b024002400240200228022c220141406a4121490d0020014120490d0020014160714120470d010b20024180808080783602100c010b20024188016a41e0006a200341e0006a2d00003a000020024188016a41d8006a200341d8006a29000037030020024188016a41d0006a200341d0006a29000037030020024188016a41c8006a200341c8006a29000037030020024188016a41086a200341086a29000037030020024188016a41106a200341106a29000037030020024188016a41186a200341186a290000370300200220032900403703c801200220032900003703880120024188016a41386a200341386a29000037030020024188016a41306a200341306a29000037030020024188016a41286a200341286a290000370300200220032900203703a801200241246a20024188016a41e10010848e8080001a200241106a200241246a10e3898080000b02402000450d00200341002802c0a3c68000118080808000000b20024188016a200241106a10b58c8080002002350290012104200228028c012105024020022802102203418080808078460d00024020022802182200450d00200228021421062000410171210741002101024020004101460d002000417e7121002006210341002101034002402003280200450d00200341046a28020041002802c0a3c68000118080808000000b0240200341106a280200450d00200341146a28020041002802c0a3c68000118080808000000b200341206a21032000200141026a2201470d000b0b02402007450d00200620014104746a2203280200450d00200328020441002802c0a3c68000118080808000000b200228021021030b2003450d00200228021441002802c0a3c68000118080808000000b200241f0016a24808080800020044220862005ad840bfe0102027f017e23808080800041206b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c6800002402001450d00200241106a420037020020024101360208200241fcd3c5800036020420022002411c6a36020c200241046a41dcb9c5800010f680808000000b200241046a4108410010ce8780800020022902082104200241206a24808080800020040ba50201027f23808080800041206b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680000240024020010d0041002d00fca3c680001a410841002802c8a3c68000118180808000002203450d0120034200370000200241206a2480808080002003ad42808080808001840f0b200241106a420037020020024101360208200241e8d4c5800036020420022002411c6a36020c200241046a41dcb9c5800010f680808000000b4101410810b280808000000b9d0301027f23808080800041d0026b220224808080800041004100280280a4c680002203410120031b360280a4c68000200041ccb3c5800020011b2100024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c680002002200136020c20022000360208200241106a418002200241086a10ae888080000240024020022903104202510d000240200228029802450d002002419c026a28020041002802c0a3c68000118080808000000b41002d00fca3c680001a410141002802c8a3c68000118180808000002203450d01200341003a0000200241d0026a2480808080002003ad428080808010840f0b200241b8026a4201370200200241013602b002200241a0d1c580003602ac02200241fb838080003602c8022002200241c4026a3602b4022002200241cf026a3602c402200241ac026a41dcb9c5800010f680808000000b4101410110b280808000000be40202027f017e23808080800041306b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c68000024020014108490d0020014128470d002002418080808078360208200241146a200241086a10b48c808000200235021c210420022802182103024020022802082201418080808078460d002001450d00200228020c41002802c0a3c68000118080808000000b200241306a24808080800020044220862003ad840f0b200241206a420137020020024101360218200241e4d1c58000360214200241fb8380800036020c2002200241086a36021c20022002412f6a360208200241146a41dcb9c5800010f680808000000bf20302027f017e23808080800041c0006b220224808080800041004100280280a4c680002203410120031b360280a4c68000200041ccb3c5800020011b2100024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c68000200220013602142002200036021020024280808080802037021c2002200241106a360218200241086a200241186a10bc8a8080000240024020022802080d00200241306a200241186a200228020c10d08580800020022802302203418080808078460d00200228023421012002280214450d012003450d00200141002802c0a3c68000118080808000000b200241246a42013702002002410136021c20024198d5c58000360218200241fb838080003602342002200241306a36022020022002413f6a360230200241186a41dcb9c5800010f680808000000b200220022802383602202002200136021c20022003360218200241306a200241186a10c987808000200241306a10b1888080002104024020022802302203418280808078480d002003450d00200228023441002802c0a3c68000118080808000000b200241c0006a24808080800020040b900502037f017e23808080800041c0006b220224808080800041004100280280a4c680002203410120031b360280a4c68000200041ccb3c5800020011b2104024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c6800020022001360214200220043602102002428080808080203702342002200241106a36023002402001450d0020022001417f6a22013602142002200041016a360210024002400240024020002d00000e020100040b200241086a200241306a10bc8a80800020022802080d03200241186a200241306a200228020c10d08580800020022802182201418080808078460d032001418180808078460d03200228021c21002002280214450d012001450d03200041002802c0a3c68000118080808000000c030b20010d0241818080807821010c010b2001418280808078460d01200228022021030b200220033602202002200036021c20022001360218200241306a200241186a10c687808000024020022802182201418280808078480d002001450d00200228021c41002802c0a3c68000118080808000000b200241186a200241306a10b68c80800020023502202105200228021c2101024020022802302200418080808078460d002000450d00200228023441002802c0a3c68000118080808000000b200241c0006a24808080800020054220862001ad840f0b200241246a42013702002002410136021c200241c8d5c58000360218200241fb838080003602342002200241306a36022020022002413f6a360230200241186a41dcb9c5800010f680808000000bc60403027f017e017f23808080800041206b220224808080800041004100280280a4c680002203410120031b360280a4c68000024002402003450d0020034101470d0103404100280280a4c680004101460d000c020b0b410041d8a7c28000360290a1c68000410041f0a7c2800036028ca1c6800041004102360280a4c680000b410041002802d8a2c68000118c808080000041ff0171360284a4c6800002400240024020010d0041002d00fca3c680001a411841002802c8a3c68000118180808000002203450d012003428680808080808080807f370208200341d0a4c480003602042003418080808078360200200341146a4107360200200341106a41d6a4c4800036020041002d00fca3c680001a411c41002802c8a3c68000118180808000002201450d0220024100360208200220013602042002411c360200200241023602182002200241186a36021c2002411c6a200210c08a80800020034102200210d2858080002002350208210420022802042101024020032802002205418080808078460d002005450d00200328020441002802c0a3c68000118080808000000b0240200328020c2205418080808078460d002005450d00200341106a28020041002802c0a3c68000118080808000000b200341002802c0a3c6800011808080800000200241206a24808080800020044220862001ad840f0b2002410c6a420037020020024101360204200241b0d6c5800036020020022002411c6a360208200241dcb9c5800010f680808000000b4104411810b280808000000b4101411c10b280808000000bcf0101027e42891c210242f8eb8717210302400240024002400240024002400240024020012d0000417f6a0e09080001020304050607080b42b430210242c0abe81721030c070b429885991221030c060b42a893cc1621030c050b42e8e89b0821030c040b2001410c6a350200220342ab147e42de077c21022003429bf1d4067e42e0b9f4077c21030c030b42a8afc00921030c020b4200210242d0bb920321030c010b42c091e20e42d88cf00920012d00011b2103420021020b200041003b011020002002370308200020033703000b970601087f23808080800041c0006b220124808080800020014106360210200141a5d8c5800036020c41002d00fca3c680001a024002400240410841002802c8a3c68000118180808000002202450d00200241a5d8c58000360200200241046a410636020041a5d8c58000410610d782808000450d0141002d00fca3c680001a412041002802c8a3c68000118180808000002203450d02200342acf6debeefe0d9c8d300370308200341bd8080800036021820034101360204200341abd8c58000360200200341106a42efc9c9edb5e7b3a6c70037030020014101360220200120033602182001200341206a3602242001200336021c200141306a200141186a10fa86808000200128023821042001280234210520012802302106200141186a41086a2207410036020020014280808080c000370218200141186a410010a086808000200128021c200728020041246c6a220341003a00202003410436021c200341acd8c580003602182003420437021020034200370208200342808080808001370200200141306a41086a2208200728020041016a360200200120012902183703302001410c6a200141306a41b0d8c58000410410898b8080002001200128020c36022020012001280210220336021820012003200128021441246c6a3602242001200336021c200141306a200141186a10fb8680800020012006360220200120053602182001200520044105746a3602242001200536021c200041c4006a200141186a10fa86808000200141236a20082802003600002000413c6a2002ad4280808080108437020020004101360238200041013a0000200041d8006a410036020020004280808080c0003703502001200129023037001b20002001290018370001200041086a2001411f6a290000370000200141c0006a2480808080000f0b4104410810b280808000000b200241002802c0a3c6800011808080800000200141246a42013702002001410236021c20014180ddc18000360218200141b4808080003602342001200141306a36022020012001410c6a360230200141186a4190ddc1800010f680808000000b4108412010b280808000000b950601087f23808080800041c0006b220124808080800020014106360210200141a5d8c5800036020c41002d00fca3c680001a024002400240410841002802c8a3c68000118180808000002202450d00200241a5d8c58000360200200241046a410636020041a5d8c58000410610d782808000450d0141002d00fca3c680001a412041002802c8a3c68000118180808000002203450d02200342dc85e1fdf99cd0816b370308200341f88380800036021820034101360204200341abd8c58000360200200341106a42dfda92949ba784d56637030020014101360220200120033602182001200341206a3602242001200336021c200141306a200141186a10fa86808000200128023821042001280234210520012802302106200141186a41086a2207410036020020014280808080c000370218200141186a410010a086808000200128021c200728020041246c6a220341003a00202003410436021c200341acd8c580003602182003420437021020034200370208200342808080808001370200200141306a41086a2208200728020041016a360200200120012902183703302001410c6a200141306a41b0d8c58000410410d08b8080002001200128020c36022020012001280210220336021820012003200128021441246c6a3602242001200336021c200141306a200141186a10fb8680800020012006360220200120053602182001200520044105746a3602242001200536021c200041c4006a200141186a10fa86808000200141236a20082802003600002000413c6a2002ad4280808080108437020020004101360238200041013a0000200041d8006a410036020020004280808080c0003703502001200129023037001b20002001290018370001200041086a2001411f6a290000370000200141c0006a2480808080000f0b4104410810b280808000000b200241002802c0a3c6800011808080800000200141246a42013702002001410236021c20014180ddc18000360218200141b4808080003602342001200141306a36022020012001410c6a360230200141186a4190ddc1800010f680808000000b4108412010b280808000000b950601087f23808080800041c0006b220124808080800020014106360210200141a5d8c5800036020c41002d00fca3c680001a024002400240410841002802c8a3c68000118180808000002202450d00200241a5d8c58000360200200241046a410636020041a5d8c58000410610d782808000450d0141002d00fca3c680001a412041002802c8a3c68000118180808000002203450d02200342d4b0f086cab3d2eb14370308200341948380800036021820034101360204200341abd8c58000360200200341106a4299f0ab899787d3ad3a37030020014101360220200120033602182001200341206a3602242001200336021c200141306a200141186a10fa86808000200128023821042001280234210520012802302106200141186a41086a2207410036020020014280808080c000370218200141186a410010a086808000200128021c200728020041246c6a220341003a00202003410436021c200341acd8c580003602182003420437021020034200370208200342808080808001370200200141306a41086a2208200728020041016a360200200120012902183703302001410c6a200141306a41b0d8c58000410410c08b8080002001200128020c36022020012001280210220336021820012003200128021441246c6a3602242001200336021c200141306a200141186a10fb8680800020012006360220200120053602182001200520044105746a3602242001200536021c200041c4006a200141186a10fa86808000200141236a20082802003600002000413c6a2002ad4280808080108437020020004101360238200041013a0000200041d8006a410036020020004280808080c0003703502001200129023037001b20002001290018370001200041086a2001411f6a290000370000200141c0006a2480808080000f0b4104410810b280808000000b200241002802c0a3c6800011808080800000200141246a42013702002001410236021c20014180ddc18000360218200141b4808080003602342001200141306a36022020012001410c6a360230200141186a4190ddc1800010f680808000000b4108412010b280808000000b960601087f23808080800041c0006b220124808080800020014106360210200141a5d8c5800036020c41002d00fca3c680001a024002400240410841002802c8a3c68000118180808000002202450d00200241a5d8c58000360200200241046a410636020041a5d8c58000410610d782808000450d0141002d00fca3c680001a412041002802c8a3c68000118180808000002203450d02200342e7b0a091f3ed9c85c500370308200341ea8180800036021820034101360204200341abd8c58000360200200341106a42b891b68c98adebcf6137030020014101360220200120033602182001200341206a3602242001200336021c200141306a200141186a10fa86808000200128023821042001280234210520012802302106200141186a41086a2207410036020020014280808080c000370218200141186a410010a086808000200128021c200728020041246c6a220341003a00202003410436021c200341acd8c580003602182003420437021020034200370208200342808080808001370200200141306a41086a2208200728020041016a360200200120012902183703302001410c6a200141306a41b0d8c58000410410928b8080002001200128020c36022020012001280210220336021820012003200128021441246c6a3602242001200336021c200141306a200141186a10fb8680800020012006360220200120053602182001200520044105746a3602242001200536021c200041c4006a200141186a10fa86808000200141236a20082802003600002000413c6a2002ad4280808080108437020020004101360238200041013a0000200041d8006a410036020020004280808080c0003703502001200129023037001b20002001290018370001200041086a2001411f6a290000370000200141c0006a2480808080000f0b4104410810b280808000000b200241002802c0a3c6800011808080800000200141246a42013702002001410236021c20014180ddc18000360218200141b4808080003602342001200141306a36022020012001410c6a360230200141186a4190ddc1800010f680808000000b4108412010b280808000000b950601087f23808080800041c0006b220124808080800020014106360210200141a5d8c5800036020c41002d00fca3c680001a024002400240410841002802c8a3c68000118180808000002202450d00200241a5d8c58000360200200241046a410636020041a5d8c58000410610d782808000450d0141002d00fca3c680001a412041002802c8a3c68000118180808000002203450d02200342cecfe0e5d1c6dbf757370308200341fb8280800036021820034101360204200341abd8c58000360200200341106a42a8c786dcd8d2a98d1737030020014101360220200120033602182001200341206a3602242001200336021c200141306a200141186a10fa86808000200128023821042001280234210520012802302106200141186a41086a2207410036020020014280808080c000370218200141186a410010a086808000200128021c200728020041246c6a220341003a00202003410436021c200341acd8c580003602182003420437021020034200370208200342808080808001370200200141306a41086a2208200728020041016a360200200120012902183703302001410c6a200141306a41b0d8c580004104109e8b8080002001200128020c36022020012001280210220336021820012003200128021441246c6a3602242001200336021c200141306a200141186a10fb8680800020012006360220200120053602182001200520044105746a3602242001200536021c200041c4006a200141186a10fa86808000200141236a20082802003600002000413c6a2002ad4280808080108437020020004101360238200041013a0000200041d8006a410036020020004280808080c0003703502001200129023037001b20002001290018370001200041086a2001411f6a290000370000200141c0006a2480808080000f0b4104410810b280808000000b200241002802c0a3c6800011808080800000200141246a42013702002001410236021c20014180ddc18000360218200141b4808080003602342001200141306a36022020012001410c6a360230200141186a4190ddc1800010f680808000000b4108412010b280808000000b960601087f23808080800041c0006b220124808080800020014106360210200141a5d8c5800036020c41002d00fca3c680001a024002400240410841002802c8a3c68000118180808000002202450d00200241a5d8c58000360200200241046a410636020041a5d8c58000410610d782808000450d0141002d00fca3c680001a412041002802c8a3c68000118180808000002203450d02200342c4ccab9c81ebb4b8db00370308200341f08180800036021820034101360204200341abd8c58000360200200341106a42a4d2928ecac0faa43237030020014101360220200120033602182001200341206a3602242001200336021c200141306a200141186a10fa86808000200128023821042001280234210520012802302106200141186a41086a2207410036020020014280808080c000370218200141186a410010a086808000200128021c200728020041246c6a220341003a00202003410436021c200341acd8c580003602182003420437021020034200370208200342808080808001370200200141306a41086a2208200728020041016a360200200120012902183703302001410c6a200141306a41b0d8c58000410410cc8b8080002001200128020c36022020012001280210220336021820012003200128021441246c6a3602242001200336021c200141306a200141186a10fb8680800020012006360220200120053602182001200520044105746a3602242001200536021c200041c4006a200141186a10fa86808000200141236a20082802003600002000413c6a2002ad4280808080108437020020004101360238200041013a0000200041d8006a410036020020004280808080c0003703502001200129023037001b20002001290018370001200041086a2001411f6a290000370000200141c0006a2480808080000f0b4104410810b280808000000b200241002802c0a3c6800011808080800000200141246a42013702002001410236021c20014180ddc18000360218200141b4808080003602342001200141306a36022020012001410c6a360230200141186a4190ddc1800010f680808000000b4108412010b280808000000b960601087f23808080800041c0006b220124808080800020014106360210200141a5d8c5800036020c41002d00fca3c680001a024002400240410841002802c8a3c68000118180808000002202450d00200241a5d8c58000360200200241046a410636020041a5d8c58000410610d782808000450d0141002d00fca3c680001a412041002802c8a3c68000118180808000002203450d02200342cc9a879ae783ad8254370308200341f28380800036021820034101360204200341abd8c58000360200200341106a42f9beb892cc84b284c80037030020014101360220200120033602182001200341206a3602242001200336021c200141306a200141186a10fa86808000200128023821042001280234210520012802302106200141186a41086a2207410036020020014280808080c000370218200141186a410010a086808000200128021c200728020041246c6a220341003a00202003410436021c200341acd8c580003602182003420437021020034200370208200342808080808001370200200141306a41086a2208200728020041016a360200200120012902183703302001410c6a200141306a41b0d8c58000410410aa8b8080002001200128020c36022020012001280210220336021820012003200128021441246c6a3602242001200336021c200141306a200141186a10fb8680800020012006360220200120053602182001200520044105746a3602242001200536021c200041c4006a200141186a10fa86808000200141236a20082802003600002000413c6a2002ad4280808080108437020020004101360238200041013a0000200041d8006a410036020020004280808080c0003703502001200129023037001b20002001290018370001200041086a2001411f6a290000370000200141c0006a2480808080000f0b4104410810b280808000000b200241002802c0a3c6800011808080800000200141246a42013702002001410236021c20014180ddc18000360218200141b4808080003602342001200141306a36022020012001410c6a360230200141186a4190ddc1800010f680808000000b4108412010b280808000000b960601087f23808080800041c0006b220124808080800020014106360210200141a5d8c5800036020c41002d00fca3c680001a024002400240410841002802c8a3c68000118180808000002202450d00200241a5d8c58000360200200241046a410636020041a5d8c58000410610d782808000450d0141002d00fca3c680001a412041002802c8a3c68000118180808000002203450d0220034288f7e1d594faa5a1203703082003418c8380800036021820034101360204200341abd8c58000360200200341106a42b889cc8cd692ff80fa0037030020014101360220200120033602182001200341206a3602242001200336021c200141306a200141186a10fa86808000200128023821042001280234210520012802302106200141186a41086a2207410036020020014280808080c000370218200141186a410010a086808000200128021c200728020041246c6a220341003a00202003410436021c200341acd8c580003602182003420437021020034200370208200342808080808001370200200141306a41086a2208200728020041016a360200200120012902183703302001410c6a200141306a41b0d8c58000410410bd8b8080002001200128020c36022020012001280210220336021820012003200128021441246c6a3602242001200336021c200141306a200141186a10fb8680800020012006360220200120053602182001200520044105746a3602242001200536021c200041c4006a200141186a10fa86808000200141236a20082802003600002000413c6a2002ad4280808080108437020020004101360238200041013a0000200041d8006a410036020020004280808080c0003703502001200129023037001b20002001290018370001200041086a2001411f6a290000370000200141c0006a2480808080000f0b4104410810b280808000000b200241002802c0a3c6800011808080800000200141246a42013702002001410236021c20014180ddc18000360218200141b4808080003602342001200141306a36022020012001410c6a360230200141186a4190ddc1800010f680808000000b4108412010b280808000000b970601087f23808080800041c0006b220124808080800020014106360210200141a5d8c5800036020c41002d00fca3c680001a024002400240410841002802c8a3c68000118180808000002202450d00200241a5d8c58000360200200241046a410636020041a5d8c58000410610d782808000450d0141002d00fca3c680001a412041002802c8a3c68000118180808000002203450d02200342d1c5efcdcd82cde1ff00370308200341938280800036021820034101360204200341abd8c58000360200200341106a429ccab49c93e2e495cf0037030020014101360220200120033602182001200341206a3602242001200336021c200141306a200141186a10fa86808000200128023821042001280234210520012802302106200141186a41086a2207410036020020014280808080c000370218200141186a410010a086808000200128021c200728020041246c6a220341003a00202003410436021c200341acd8c580003602182003420437021020034200370208200342808080808001370200200141306a41086a2208200728020041016a360200200120012902183703302001410c6a200141306a41b0d8c58000410410bc8b8080002001200128020c36022020012001280210220336021820012003200128021441246c6a3602242001200336021c200141306a200141186a10fb8680800020012006360220200120053602182001200520044105746a3602242001200536021c200041c4006a200141186a10fa86808000200141236a20082802003600002000413c6a2002ad4280808080108437020020004101360238200041013a0000200041d8006a410036020020004280808080c0003703502001200129023037001b20002001290018370001200041086a2001411f6a290000370000200141c0006a2480808080000f0b4104410810b280808000000b200241002802c0a3c6800011808080800000200141246a42013702002001410236021c20014180ddc18000360218200141b4808080003602342001200141306a36022020012001410c6a360230200141186a4190ddc1800010f680808000000b4108412010b280808000000bfe0503037f017e047f2380808080004190016b22012480808080002000280208220241286c2103200028020421000240024020020d00420021040c010b2002410371210502400240200241044f0d0041002106420021040c010b20004198016a21072002417c712108410021064200210403402007290300200741586a290300200741b07f6a290300200741887f6a29030020047c7c7c7c2104200741a0016a21072008200641046a2206470d000b0b2005450d00200641286c20006a41206a21070340200729030020047c2104200741286a21072005417f6a22050d000b0b200020036a210520014298d5afd2c6aeacae2f370358200142c2cdc8b0c7b9e78f857f370350200142e4c5bdb4b2e9a5a6807f370368200142d790d7a3fef9fda0c80037036020012004370310200141d0006a4120200141106a410841002802e0a1c68000118680808000002000210702400340024020030d00200141046a2000200510bd87808000200128020c2002470d0202402002450d00200241286c2103200141e0006a2107200141d0006a41206a220541086a21060340200041206a2903002104200020001084888080001a200141106a200010fa87808000200141d0006a200010fa87808000024002402001280284010d00200141d0006a200010fa878080002001280288010d0020001086888080000c010b200542003703002007428080808080808080807f370300200642003703002001420037035820012004370368200142013703502000200141d0006a1082888080000b200041286a2100200341586a22030d000b0b200141046a10a88d80800020014190016a2480808080000f0b200341586a210320072903202104200741286a21072004428080e983b1de165a0d000b200141dc006a42003702002001410136025420014188dac58000360250200141a8d9c58000360258200141d0006a4190dac5800010f680808000000b200141dc006a420037020020014101360254200141a0d9c58000360250200141a8d9c58000360258200141d0006a41a8d9c5800010f680808000000bd80501047f2380808080004180016b220124808080800020014298d5afd2c6aeacae2f370308200142c2cdc8b0c7b9e78f857f3703002001413c6a2001411041002802c0a1c680001185808080000002400240200128023c2202418080808078460d0020012802402103024020012802444110490d0020012003411010888e808000210402402002450d00200341002802c0a3c68000118080808000000b20040d010c020b2002450d00200341002802c0a3c68000118080808000000b02400240417f4100280284a4c680002202410347200241034b1b2202450d00200241ff017141ff01470d010b200141186a410c6a41fd83808000360200200141b8dbc58000360220200141838280800036021c20014108360214200141e0a6c480003602102001200141106a3602184100280290a1c680002102410028028ca1c6800021034100280280a4c680002104200141f4006a4202370200200141ec006a4102360200200141e4006a4116360200200141e0006a41d4d8c58000360200200141d4006a41b8d6c58000ad4280808080d00b843702002001413c6a410c6a41ead8c58000ad4280808080f00284370200200141f0006a200141186a360200200141a8dbc580003602682001410336025c200141003602502001410036024420014281808080a01837023c200341ecf2c08000200441024622041b2001413c6a200241d4f2c0800020041b280210118480808000000b2001413c6a41e0a6c48000410841002802a0a3c68000118580808000002001413c6a41106a220241bccdc48000411541002802a0a3c6800011858080800000200141186a41186a2001413c6a41186a290000370300200141186a41106a2002290000370300200141186a41086a2001413c6a41086a2900003703002001200129003c370318200141013b013c200141186a41202001413c6a410241002802e0a1c68000118680808000000b200042003703082000420037030020014180016a2480808080000b930201027f23808080800041106b2202248080808000200220003602002002200128021441dcf6c58000410e200141186a28020028020c118280808000003a000c20022001360208200241003a000d20024100360204200241046a200241ecf6c58000108d81808000210120022d000c210002400240200128020022030d00200041ff017141004721010c010b41012101200041ff01710d0020022802082100024020034101470d0020022d000d41ff0171450d0020002d001c4104710d00410121012000280214418ca5c080004101200041186a28020028020c118280808000000d010b2000280214418da5c080004101200041186a28020028020c1182808080000021010b200241106a24808080800020010ba70302027f037e23808080800041c0006b22052480808080002005200110fa87808000200541186a220629030021072005200110fa8780800042004200200541286a2903002208200541206a2903007d220920092008561b20041b2109200629030021080240024002400240200341ff01710e03010002030b2008500d022005200110fa8780800020052802344101470d020c010b2008500d012005200110fa878080002005280230450d01200528023441024f0d010b2009428080e983b1de162009428080e983b1de16561b21090b024002400240200720024200200820097d220920092008561b220820022008541b2208540d0020052001200720087d2208109c8c80800020052802000d0102402005290308500d00200541106a2903002209500d0020052009370300200510a88a8080000b20004200200720087d220820082007561b370308410021010c020b200041073b0104410121010c010b200541086a290300210820052802042101200041106a200541106a290300370300200041086a200837030020002001360204410121010b20002001360200200541c0006a2480808080000bd80703017f027e027f23808080800041e0016b22032480808080002003200237030020034190016a200110fa87808000420021040240200341a8016a2903002202500d0020034190016a200110fa878080004200428080e983b1de1620032802c40141014b1b420020032802c0011b21040b20034200200220047d220420042002561b370308200110a08c8080001a20034190016a41086a200341086a36020020032001360290012003200336029401200341d8006a200120034190016a10948a8080000240024002400240200329035822024202510d00200329037021052003290368210402402002500d0020032903602102200341b8016a200141186a290000370300200341b0016a200141106a29000037030020034190016a41186a200141086a2900003703002003200237039801200341003a009001200320012900003703a00120034190016a108e8a8080000b0240024020044200520d00200341286a410f6a220120034188016a280000360000200341286a41086a220620034181016a290000370300200341106a41086a2006290300370300200341106a410f6a20012800003600002003200329007937031020032d007821010c010b200341b8016a200141186a290000370300200341b0016a200141106a29000037030020034190016a41186a200141086a2900003703002003200537039801200341013a009001200320012900003703a00120034190016a108e8a808000200341286a41086a220620034181016a290000370300200341286a410f6a220720034188016a2800003600002003200329007937032820032d0078210120044202510d02200341106a410f6a2007280000360000200341106a41086a2006290300370300200320032903283703100b200341c0006a410f6a2206200341106a410f6a280000360000200341c0006a41086a2207200341106a41086a29030037030020032003290310370340200141ff0171410e470d022000200437030820004100360200200041106a20053703000c030b200341286a41086a200341e9006a290000370300200341376a200341f0006a2800003600002003200341e1006a29000037032820032d006021010b200341106a410f6a2206200341286a410f6a280000360000200341106a41086a2207200341286a41086a290300370300200320032903282202370310200041146a20062800003600002000410d6a2007290300370000200041056a2002370000200020013a0004200041013602000c010b200020013a000420004101360200200041056a2003290340370000200041146a20062800003600002000410d6a20072903003700000b200341e0016a2480808080000bf60704037f027e017f037e23808080800041e0006b220524808080800002400240024002402003500d0020054298d5afd2c6aeacae2f370318200542c2cdc8b0c7b9e78f857f370310200542e4c5bdb4b2e9a5a6807f370328200542d790d7a3fef9fda0c8003703202005200541106a10e688808000410821062005290308420020052802001b2003540d01200541106a200110fa8780800041072106200541286a220729030022082003540d01200541386a22062903002109200541306a220a290300210b200541106a200110fa8780800042002006290300220c200a2903007d220d200d200c561b210c02402007290300220d500d00200541106a200110fa87808000200c200c428080e983b1de16200c428080e983b1de16561b200528024441014b1b200c20052802401b210c0b41870a21064200200d200c7d220c200c200d561b2003540d010240200820037d220c42ffffe883b1de16560d00200541106a200110fa878080002005280240450d00418702210620052802444102490d020b41870a2106427f200c200b7c220d200d200c541b2009540d010240200441ff0171450d004187102106200c428080e983b1de16540d020b200541106a200210fa87808000024002400240200541286a290300220c20037c220d200c540d00200d428080e983b1de16540d01200541306a290300220c200d7c200c5a0d030b41012101410821020c010b41022101410721020b200041066a2005290110370100200041166a200541206a2f01003b01002000410e6a200541186a290100370100200041056a20013a0000200020023a00040c020b0240024020012002412010888e808000450d00200541106a2001200320044100109b8c80800020052802100d01200541106a200210fa878080000240427f200541106a41186a2206290300220c20037c220d200d200c541b220d200c510d00200d428080e983b1de16540d00200541106a2002200d109c8c80800020052802100d002005290318500d00200541206a290300220c500d002005200c370310200541106a10a88a8080000b200541386a200141186a290000370300200541306a200141106a2900003703002006200141086a290000370300200541c8006a200241086a290000370300200541d0006a200241106a290000370300200541d8006a200241186a29000037030020052003370318200541023a00102005200129000037032020052002290000370340200541106a108e8a8080000b20002003370308410021010c030b200541106a41106a2903002103200541106a41086a290300210c20002005280214360204200041106a2003370300200041086a200c3703000c010b200020063602040b410121010b20002001360200200541e0006a2480808080000be20602017f027e2380808080004190016b2206248080808000200641306a200110fa8780800042004200200641d8006a2903002207200641d0006a2903007d220820082007561b20051b2108200641c8006a29030021070240024002400240200341ff01710e03010002030b2007500d02200641306a200110fa8780800020062802644101470d020c010b2007500d01200641306a200110fa878080002006280260450d01200628026441024f0d010b2008428080e983b1de162008428080e983b1de16561b21080b0240024002404200200720087d220820082007561b220720025a0d0020040d00200041073b01040c010b20064298d5afd2c6aeacae2f370338200642c2cdc8b0c7b9e78f857f370330200642e4c5bdb4b2e9a5a6807f370348200642d790d7a3fef9fda0c800370340200641206a200641306a10e68880800002402006290328420020062802201b2007200220072002541b2207540d00200641306a2001200720032005109b8c808000200641306a41086a2903002107024020062802300d0020064298d5afd2c6aeacae2f370338200642c2cdc8b0c7b9e78f857f370330200642e4c5bdb4b2e9a5a6807f370348200642d790d7a3fef9fda0c800370340200641106a200641306a10e688808000200629031821082006280210210520064298d5afd2c6aeacae2f370338200642c2cdc8b0c7b9e78f857f370330200642e4c5bdb4b2e9a5a6807f370348200642d790d7a3fef9fda0c8003703402006200641306a10e68880800020064298d5afd2c6aeacae2f370338200642c2cdc8b0c7b9e78f857f370330200642e4c5bdb4b2e9a5a6807f370348200642d790d7a3fef9fda0c800370340200642002008420020051b220820077d220220022008561b3703880141002105200641306a412020064188016a410841002802e0a1c6800011868080800000200641d8006a200141186a290000370300200641306a41206a200141106a290000370300200641306a41186a200141086a290000370300200620073703382006410b3a003020062001290000370340200641306a108e8a808000200020073703080c030b200641306a41106a290300210820002006280234360204200041106a2008370300200041086a20073703000c010b20004188023b01040b410121050b2000200536020020064190016a2480808080000b890402017f037e2380808080004180016b22022480808080002002200137030002400240200150450d00420021010c010b200241306a200010fa87808000200241d0006a290300200241c8006a29030084500d00200010a08c8080001a200241086a20002000200210938a8080000240200229030822014202510d0020022903282103200229032021042002290318210502402001500d0020022903102101200241d8006a200041186a290000370300200241d0006a200041106a290000370300200241306a41186a200041086a29000037030020022001370338200241003a003020022000290000370340200241306a108e8a8080000b024020054200510d00200241d8006a200041186a290000370300200241d0006a200041106a290000370300200241306a41186a200041086a2900003703002002200437033820022000290000370340200241013a0030200241306a108e8a8080002005a74101470d00200442ffffe883b1de16200442ffffe883b1de16541b2201500d0020022001370330200241306a10a88a8080000b200241d8006a200041186a290000370300200241d0006a200041106a290000370300200241306a41186a200041086a290000370300200241053a00302002200029000037034020022003370338200241306a108e8a808000200229030020037d21010c010b200229030021010b20024180016a24808080800020010bf10803017f057e027f23808080800041c0016b220124808080800020012000360208200141206a200010fa878080000240200141306a29030022024200530d00200141c8006a2903002103200141386a2903002104200129032821050240200141c0006a2903002206500d0020034200520d00200141206a200010fa87808000024020012802540d0002400240417f4100280284a4c680002207410247200741024b1b2207450d00200741ff017141ff01470d010b200141fe838080003602742001200141086a3602704100280290a1c680002100410028028ca1c6800021074100280280a4c680002108200141d8006a4201370200200141d0006a4102360200200141c8006a4111360200200141c4006a4198dcc58000360200200141386a41b8d6c58000ad4280808080d00b843702002001412c6a41ead8c58000ad4280808080f00284370200200141d4006a200141f0006a36020020014188dcc5800036024c20014102360240200141003602342001410036022820014281808080c0eb00370220200741ecf2c08000200841024622081b200141206a200041d4f2c0800020081b28021011848080800000200128020821000b200020001084888080001a2004428080e983b1de162004428080e983b1de16561b2104200128020821000b2001410c6a200010f487808000024020012d000c410e460d00200141f0006a41106a2001410c6a41106a280200360200200141f0006a41086a2001410c6a41086a2902003703002001200129020c3703700240417f4100280284a4c680002200410147200041014b1b2200450d00200041ff017141ff01470d010b200141b0016a410c6a41ca83808000360200200141e0818080003602b4012001418c98c380003602b0012001200141f0006a3602b8014100280290a1c680002100410028028ca1c6800021074100280280a4c680002108200141d8006a4202370200200141d0006a4102360200200141c8006a4112360200200141c4006a419498c38000360200200141386a41a698c38000ad4280808080c00c84370200200141206a410c6a418a99c38000ad4280808080b00384370200200141d4006a200141b0016a3602002001418497c3800036024c20014101360240200141003602342001410036022820014281808080e024370220200741ecf2c08000200841024622081b200141206a200041d4f2c0800020081b280210118480808000000b200128020821000b200141f0006a200010fa87808000200141206a200010fa878080000240024020012802540d00200141206a200010fa8780800020012802580d0020001086888080000c010b200141306a2002428080808080808080807f8437030020012005370328200120033703482001200637034020012004370338200142013703202000200141206a1082888080000b200141396a2001280208220041186a290000370000200141316a200041106a290000370000200141296a200041086a2900003700002001410e3a002020012000290000370021200141206a108e8a8080000b200141c0016a2480808080002002427f550ba50e01047f23808080800041206b22012480808080002001410036021020014280808080800137020841002d00fca3c680001a024002400240024002400240024002400240410841002802c8a3c68000118180808000002202450d00200241a9dcc580003602002002412636020441002d00fca3c680001a410841002802c8a3c68000118180808000002203450d01200342003700000240200128021022042001280208470d00200141086a2004109d86808000200128021021040b200128020c200441e8006c6a220441013a00602004410136025c2004200236025820044288808080103703502004200336024c2004428d8080808001370244200441aebfc38000360240200441ef80808000360218200442a5e9e3ab9e929adc2c37030820044100360200200441106a4293888c8f89fdc6ec9e7f37030041002d00fca3c680001a2001200128021041016a360210410841002802c8a3c68000118180808000002202450d02200241cfdcc58000360200200241c20036020441002d00fca3c680001a410841002802c8a3c68000118180808000002203450d03200342003700000240200128021022042001280208470d00200141086a2004109d86808000200128021021040b200128020c200441e8006c6a220441013a00602004410136025c2004200236025820044288808080103703502004200336024c200442908080808001370244200441e8bec38000360240200441ef8080800036021820044100360200200442a5e9e3ab9e929adc2c370308200441106a4293888c8f89fdc6ec9e7f3703002001200128021041016a36021041002d00fca3c680001a41c00141002802c8a3c68000118180808000002204450d04200441fee1c580003602b801200441b4e1c580003602b001200441d9e0c580003602a80120044185e0c580003602a001200441a8d9c58000360298012004419fdfc58000360290012004419cdfc5800036028801200441e8dfc5800036028001200441eaddc58000360278200441ddddc58000360270200441a8d9c58000360268200441d3ddc58000360260200441a8d9c58000360258200441a3dfc58000360250200441a8d9c580003602482004419fdfc580003602402004419cdfc5800036023820044196dec58000360230200441eaddc58000360228200441ddddc58000360220200441a8d9c58000360218200441d3ddc58000360210200441a8d9c58000360208200441c20036020420044191ddc58000360200200441bc016a41d000360200200441b4016a41ca00360200200441ac016a41db00360200200441a4016a41d4003602002004419c016a410036020020044194016a41043602002004418c016a410336020020044184016a411d360200200441fc006a412c360200200441f4006a410d360200200441ec006a4100360200200441e4006a410a360200200441dc006a4100360200200441d4006a41c500360200200441cc006a4100360200200441c4006a41043602002004413c6a4103360200200441346a4186013602002004412c6a412c360200200441246a410d3602002004411c6a4100360200200441146a410a3602002004410c6a41003602002001411836021c2001200436021820014118360214200141146a200141086a10a08880800041002d00fca3c680001a412041002802c8a3c68000118180808000002204450d05200441c5e3c58000360218200441a8d9c58000360210200441fce2c580003602082004412e360204200441cee2c580003602002004411c6a41eb00360200200441146a41003602002004410c6a41c9003602002001410436021c2001200436021820014104360214200141146a200141086a109a8880800041002d00fca3c680001a411841002802c8a3c68000118180808000002204450d06200441d9e4c58000360210200441a8d9c5800036020820044129360204200441b0e4c58000360200200441146a41ec003602002004410c6a41003602002001410336021c2001200436021820014103360214200141146a200141086a10988880800041002d00fca3c680001a410841002802c8a3c68000118180808000002204450d072004411b360204200441c5e5c580003602002001410136021c2001200436021820014101360214200141146a200141086a10a18880800041002d00fca3c680001a410841002802c8a3c68000118180808000002204450d0820044122360204200441e0e5c580003602002001410136021c2001200436021820014101360214200141146a200141086a109c88808000200041086a200141086a41086a28020036020020002001290208370200200041106a4108360200200041e0a6c4800036020c200141206a2480808080000f0b4104410810b280808000000b4101410810b280808000000b4104410810b280808000000b4101410810b280808000000b410441c00110b280808000000b4104412010b280808000000b4104411810b280808000000b4104410810b280808000000b4104410810b280808000000bad0a01097f41002d00fca3c680001a02400240024002400240024002400240024041e00141002802c8a3c68000118180808000002201450d0041002d00fca3c680001a410841002802c8a3c68000118180808000002202450d012002428080e983b1de1637000041002d00fca3c680001a41c00041002802c8a3c68000118180808000002203450d0220034182e6c58000360200200341f9e8c58000360238200341a8d9c58000360230200341d6e8c5800036022820034180e8c58000360220200341a8e7c58000360218200341d2e6c58000360210200341a8d9c58000360208200341d0003602042003413c6a413c360200200341346a41003602002003412c6a4123360200200341246a41d6003602002003411c6a41d800360200200341146a41d6003602002003410c6a410036020041002d00fca3c680001a410441002802c8a3c68000118180808000002204450d032004413236000041002d00fca3c680001a412041002802c8a3c68000118180808000002205450d04200541c7e9c58000360200200541c5e3c58000360218200541a8d9c5800036021020054184eac580003602082005413d3602042005411c6a41eb00360200200541146a41003602002005410c6a413736020041002d00fca3c680001a410441002802c8a3c68000118180808000002206450d052006413236000041002d00fca3c680001a411841002802c8a3c68000118180808000002207450d06200741c3eac58000360200200741d9e4c58000360210200741a8d9c58000360208200741c300360204200741146a41ec003602002007410c6a410036020041002d00fca3c680001a410441002802c8a3c68000118180808000002208450d072008410036000041002d00fca3c680001a410841002802c8a3c68000118180808000002209450d08200941d80036020420094191ebc58000360200200141b8016a42e88488d0c0e3aebc13370300200141b0016a42d7c9cb8fc1cf97db3e37030020014180016a42e88488d0c0e3aebc13370300200141f8006a42d7c9cb8fc1cf97db3e370300200141c8006a42e88488d0c0e3aebc13370300200141c0006a42d7c9cb8fc1cf97db3e370300200141106a4293888c8f89fdc6ec9e7f370300200142a5e9e3ab9e929adc2c370308200141dc016a4101360200200141d8016a2009360200200141d0016a428480808010370200200141cc016a2008360200200141c8016a4104360200200141c0016a41b580808000360200200141ac016a410a360200200141e9ebc580003602a801200141a4016a4103360200200141a0016a200736020020014198016a42848080803037020020014194016a200636020020014190016a410436020020014188016a41b580808000360200200141f4006a410b36020020014186ebc58000360270200141ec006a4104360200200141e8006a2005360200200141e0006a4284808080c000370200200141dc006a2004360200200141d8006a4104360200200141d0006a41b5808080003602002001413c6a4108360200200141bbeac5800036023820014108360234200120033602302001428880808080013702282001200236022420014108360220200141ef8080800036021820014112360204200141b5e9c580003602002000410436020820002001360204200041043602000f0b410841e00110b280808000000b4101410810b280808000000b410441c00010b280808000000b4101410410b280808000000b4104412010b280808000000b4101410410b280808000000b4104411810b280808000000b4101410410b280808000000b4104410810b280808000000bad0302017f047e2380808080004180016b2203248080808000200110a08c8080001a200341086a20012001200210958a80800002400240200329030822044202510d0020032903282105200329032021062003290318210702402004500d0020032903102104200341d8006a200141186a290000370300200341d0006a200141106a290000370300200341306a41186a200141086a29000037030020032004370338200341003a003020032001290000370340200341306a108e8a8080000b024020074200510d00200341d8006a200141186a290000370300200341d0006a200141106a290000370300200341306a41186a200141086a2900003703002003200637033820032001290000370340200341013a0030200341306a108e8a8080002007a74101470d00200642ffffe883b1de16200642ffffe883b1de16541b2204500d0020032004370330200341306a10a88a8080000b20002005370308410021010c010b200341146a290200210420032802102101200041106a2003411c6a290200370300200041086a200437030020002001360204410121010b2000200136020020034180016a2480808080000beb0101037f23808080800041106b220224808080800002402001280200220328020020032802082204470d0020032004410110ab86808000200328020821040b200328020420046a41fb003a00002003200441016a3602082002200136020c20024180023b01080240200241086a41f3ebc580004108200010d98680800022030d002002280208220441ff01710d0020044180fe0371450d000240200228020c280200220428020020042802082201470d0020042001410110ab86808000200428020821010b200428020420016a41fd003a00002004200141016a3602080b200241106a24808080800020030b951103057f017e017f23808080800041c0016b22022480808080000240024002400240024002400240024002400240024002400240200128020022032802042204450d0020032004417f6a36020420032003280200220441016a36020020042d00000e0b010a02030405060a0708090a0b200041003a00000c0b0b02402001280200220328020422044120490d002003200441606a36020420032003280200220441206a360200200241a0016a41086a2203200441086a290000370300200241a0016a41106a2205200441106a290000370300200241a0016a41186a2206200441186a290000370300200220042900003703a001200241086a200110be8a8080002002290308a70d0020022903102107200020022903a001370010200041286a2006290300370000200041206a2005290300370000200041186a200329030037000020002007370308200041013a00000c0b0b200041003a00000c0a0b2001280200220328020422044120490d082003200441606a36020420032003280200220441206a36020020024180016a41086a200441086a29000037030020024180016a41106a200441106a29000037030020024180016a41186a200441186a290000370300200220042900003703800102402001280200220328020422044120490d002003200441606a36020420032003280200220441206a360200200241a0016a41086a200441086a290000370300200241a0016a41106a200441106a290000370300200241a0016a41186a200441186a290000370300200220042900003703a001200241186a200110be8a8080002002290318a70d00200229032021072000200229038001370010200020022903a001370030200041286a20024180016a41186a290300370000200041206a20024180016a41106a290300370000200041186a20024180016a41086a290300370000200041386a200241a0016a41086a290300370000200041c0006a200241a0016a41106a290300370000200041c8006a200241a0016a41186a29030037000020002007370308200041023a00000c0a0b200041003a00000c090b02402001280200220328020422044120490d002003200441606a36020420032003280200220441206a360200200241a0016a41086a2203200441086a290000370300200241a0016a41106a2205200441106a290000370300200241a0016a41186a2206200441186a290000370300200220042900003703a001200241286a200110be8a8080002002290328a70d0020022903302107200020022903a001370010200041286a2006290300370000200041206a2005290300370000200041186a200329030037000020002007370308200041033a00000c090b200041003a00000c080b02402001280200220328020422044120490d002003200441606a36020420032003280200220441206a360200200241a0016a41086a200441086a290000370300200241a0016a41106a200441106a290000370300200241a0016a41186a200441186a290000370300200220042900003703a001200128020022032802042201450d0020032001417f6a36020420032003280200220141016a3602004101410220012d000022034101461b410020031b22034102460d00200020022903a001370001200041196a200241b8016a290300370000200041116a200241b0016a290300370000200041096a200241a8016a290300370000200020033a0021200041043a00000c080b200041003a00000c070b02402001280200220328020422044120490d002003200441606a36020420032003280200220441206a360200200241a0016a41086a2205200441086a290000370300200241a0016a41106a2206200441106a290000370300200241a0016a41186a2208200441186a290000370300200220042900003703a0012001280200220328020422014108490d00200020022903a0013700102003200141786a36020420032003280200220141086a360200200041186a2005290300370000200041206a2006290300370000200041286a200829030037000020002001290000370308200041053a00000c070b200041003a00000c060b200241386a200110bc8a808000024020022802380d00200241f4006a2001200228023c10c8858080002002280274418080808078460d0020024180016a41086a200241f4006a41086a2802002203360200200241ab016a200336000020022002290274220737038001200220073700a301200020022900a001370001200041086a200241a7016a290000370000200041063a00000c060b200041003a00000c050b02402001280200220328020422044120490d002003200441606a36020420032003280200220441206a360200200241a0016a41086a2203200441086a290000370300200241a0016a41106a2205200441106a290000370300200241a0016a41186a2206200441186a290000370300200220042900003703a001200241c0006a200110be8a8080002002290340a70d0020022903482107200020022903a001370010200041286a2006290300370000200041206a2005290300370000200041186a200329030037000020002007370308200041073a00000c050b200041003a00000c040b0240200128020022032802042204450d0020032004417f6a36020420032003280200220441016a3602004101410220042d000022034101461b410020031b22034102460d00200241d0006a200110be8a8080002002290350a70d0020022903582107200020033a0001200041083a0000200020073703080c040b200041003a00000c030b200241e0006a200110be8a80800002402002290360a70d00200128020022032802042201450d002002290368210720032001417f6a36020420032003280200220141016a3602004101410220012d000022034101461b410020031b22034102460d00200020033a0001200041093a0000200020073703080c030b200041003a00000c020b200041003a00000c010b200041003a00000b200241c0016a2480808080000ba81002047f017e23808080800041106b2202248080808000024002400240024002400240024002400240024020002d0000417f6a0e09000102030405060708090b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41003a00002001200341016a2204360208200041106a21030240200128020020046b411f4b0d0020012004412010b182808000200128020821040b2001200441206a360208200128020420046a22042003290000370000200441086a200341086a290000370000200441106a200341106a290000370000200441186a200341186a2900003700002002200041086a36020c2002410c6a200110c18a8080000c080b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41023a00002001200341016a2204360208200041106a21030240200128020020046b411f4b0d0020012004412010b182808000200128020821040b200128020420046a22052003290000370000200541186a200341186a290000370000200541106a200341106a290000370000200541086a200341086a2900003700002001200441206a2204360208200041306a21030240200128020020046b411f4b0d0020012004412010b182808000200128020821040b2001200441206a360208200128020420046a22042003290000370000200441086a200341086a290000370000200441106a200341106a290000370000200441186a200341186a2900003700002002200041086a36020c2002410c6a200110c18a8080000c070b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41033a00002001200341016a2204360208200041106a21030240200128020020046b411f4b0d0020012004412010b182808000200128020821040b2001200441206a360208200128020420046a22042003290000370000200441086a200341086a290000370000200441106a200341106a290000370000200441186a200341186a2900003700002002200041086a36020c2002410c6a200110c18a8080000c060b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41043a00002001200341016a2204360208200041016a21030240200128020020046b411f4b0d0020012004412010b182808000200128020821040b200128020420046a22052003290000370000200541186a200341186a290000370000200541106a200341106a290000370000200541086a200341086a2900003700002001200441206a220336020820002d00212100024020012802002003470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a20003a00000c050b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41053a00002001200341016a2204360208200041106a21030240200128020020046b411f4b0d0020012004412010b182808000200128020821040b200128020420046a22052003290000370000200541186a200341186a290000370000200541106a200341106a290000370000200541086a200341086a2900003700002001200441206a2203360208200029030821060240200128020020036b41074b0d0020012003410810b182808000200128020821030b2001200341086a360208200128020420036a20063700000c040b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41063a00002001200341016a360208200041086a280200210320022000410c6a28020022003602082002200241086a36020c2002410c6a200110c08a8080002000450d032000410574210520012802082104034002400240200128020020046b411f4d0d00200421000c010b20012004412010b182808000200128020821000b2001200041206a2204360208200128020420006a22002003290000370000200041086a200341086a290000370000200041106a200341106a290000370000200041186a200341186a290000370000200341206a2103200541606a22050d000c040b0b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41083a00002001200341016a2204360208200041106a21030240200128020020046b411f4b0d0020012004412010b182808000200128020821040b2001200441206a360208200128020420046a22042003290000370000200441086a200341086a290000370000200441106a200341106a290000370000200441186a200341186a2900003700002002200041086a36020c2002410c6a200110c18a8080000c020b0240200128020020012802082203470d0020012003410110b182808000200128020821030b200128020420036a41093a00002001200341016a220336020820002d00012104024020012802002003470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a20043a00002002200041086a36020c2002410c6a200110c18a8080000c010b0240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a410a3a00002002200041086a36020c2002410c6a200110c18a80800020002d000121000240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a20003a00000b200241106a2480808080000bc30302017f017e41002101024002400240024002400240024002400240024020002d0000417f6a0e09000102030405060807090b412121012000290308220242c000540d0841222101200242808001540d08412421012002428080808004540d084129200279a74103766b21010c080b41c10021012000290308220242c000540d0741c2002101200242808001540d0741c40021012002428080808004540d0741c900200279a74103766b21010c070b412121012000290308220242c000540d0641222101200242808001540d06412421012002428080808004540d064129200279a74103766b21010c060b412121010c050b412821010c040b2000410c6a28020041057441047221010c030b412121012000290308220242c000540d0241222101200242808001540d02412421012002428080808004540d024129200279a74103766b21010c020b410221012000290308220242c000540d0141032101200242808001540d01410521012002428080808004540d01410a200279a74103766b21010c010b410221012000290308220242c000540d0041032101200242808001540d00410521012002428080808004540d00410a200279a74103766b21010b200141016a0b802b02037f017e0240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024020002d00000e16000102030405060708090a0b0c0d0e0f101112131415160b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41003a00002001200241016a2203360208200041106a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41013a00002001200241016a2203360208200041106a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41023a00002001200241016a2203360208200041106a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2203360208200041306a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41033a00002001200241016a2203360208200041106a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41043a00002001200241016a2203360208200041106a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41053a00002001200241016a2203360208200041106a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41063a00002001200241016a2203360208200041026a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2203360208200041226a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2202360208200029034821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b200128020420026a20053700002001200241086a220236020820002d00012100024020012802002002470d0020012002410110b182808000200128020821020b2001200241016a360208200128020420026a20003a00000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41073a00002001200241016a2203360208200041106a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41083a00002001200241016a2203360208200041106a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41093a00002001200241016a2203360208200041106a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a410a3a00002001200241016a2203360208200041106a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a410b3a00002001200241016a2203360208200041106a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a410c3a00002001200241016a2203360208200041106a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a410d3a00002001200241016a2203360208200041106a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a410e3a00002001200241016a2202360208200041016a21000240200128020020026b411f4b0d0020012002412010b182808000200128020821020b2001200241206a360208200128020420026a22012000290000370000200141086a200041086a290000370000200141106a200041106a290000370000200141186a200041186a2900003700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a410f3a00002001200241016a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41103a00002001200241016a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41113a00002001200241016a2203360208200041106a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41123a00002001200241016a2203360208200041106a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41133a00002001200241016a2203360208200041106a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41143a00002001200241016a2203360208200041106a21020240200128020020036b411f4b0d0020012003412010b182808000200128020821030b200128020420036a22042002290000370000200441186a200241186a290000370000200441106a200241106a290000370000200441086a200241086a2900003700002001200341206a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000f0b0240200128020020012802082202470d0020012002410110b182808000200128020821020b200128020420026a41153a00002001200241016a2202360208200029030821050240200128020020026b41074b0d0020012002410810b182808000200128020821020b200128020420026a20053700002001200241086a2202360208200029031021050240200128020020026b41074b0d0020012002410810b182808000200128020821020b2001200241086a360208200128020420026a20053700000b0b140020002d000041027441a4fcc580006a2802000b970601037f0240024002400240024002400240024002400240024020012d0000417f6a0e09000102030405060708000b2000200129031037031020002001290308370308200041286a200141286a290300370300200041206a200141206a290300370300200041186a200141186a290300370300200041013a00000f0b2000200129031037031020002001290330370330200041286a200141286a290300370300200041206a200141206a290300370300200041186a200141186a290300370300200041386a200141386a290300370300200041c0006a200141c0006a290300370300200041c8006a200141c8006a29030037030020002001290308370308200041023a00000f0b2000200129031037031020002001290308370308200041286a200141286a290300370300200041206a200141206a290300370300200041186a200141186a290300370300200041033a00000f0b20002001290001370001200020012d00213a0021200041196a200141196a290000370000200041116a200141116a290000370000200041096a200141096a290000370000200041043a00000f0b2000200129031037031020002001290308370308200041286a200141286a290300370300200041206a200141206a290300370300200041186a200141186a290300370300200041053a00000f0b200141086a2802002102024002402001410c6a28020022010d0041012103410021040c010b200141ffffff1f4b0d0420014105742204417f4c0d0441002d00fca3c680001a200441002802c8a3c68000118180808000002203450d050b20032002200410848e80800021042000410c6a2001360200200041086a200436020020002001360204200041063a00000f0b2000200129031037031020002001290308370308200041286a200141286a290300370300200041206a200141206a290300370300200041186a200141186a290300370300200041073a00000f0b20002001290308370308200020012d00013a0001200041083a00000f0b20002001290308370308200020012d00013a0001200041093a00000f0b10ae80808000000b4101200410b280808000000ba60603057f017e027f23808080800041c0006b2201248080808000200141186a4184ecc58000410441ead8c58000411741a8d9c58000410010d882808000200141106a42043702002001420037020820014280808080800137020041002d00fca3c680001a02400240024041c00041002802c8a3c68000118180808000002202450d0020024188ecc580003602202002410036021820024101360204200241abd8c58000360200200241386a4100360200200241246a410136020020014102360238200120023602302001200241c0006a36023c200120023602342001200141306a10fa8680800041002d00fca3c680001a20012802002103200128020421022001280208210420012802182105200129021c2106410841002802c8a3c68000118180808000002207450d01200741002903d0ecc580003702002001410036020820014280808080c000370200200141306a20014195d7c58000411410968b8080002001200141306a41a9d7c58000410e109b8b808000200141306a200141b7d7c58000411310ca8b8080002001200141306a41cad7c58000410c10958b808000200141306a200141d6d7c58000410f10cf8b8080002001200141306a41e5d7c58000411010cd8b808000200141306a200141f5d7c58000411110858b8080002001200141306a4186d8c58000411b10808b808000200141246a200141a1d8c58000410410a78b8080002001200128022436020820012001280228220836020020012008200128022c41246c6a36020c20012008360204200141306a200110fb868080002005418080808078460d022001200336020820012002360200200120023602042001200220044105746a36020c200041c4006a200110fa868080002001410b6a200141306a41086a2802003600002000413c6a200637020020002005360238200041013a0000200041d8006a4101360200200041d4006a2007360200200041013602502001200129023037000320002001290000370001200041086a200141076a290000370000200141c0006a2480808080000f0b410841c00010b280808000000b4104410810b280808000000b41a8d8c480004111419cd9c4800010a181808000000bff1703067f017e037f23808080800041c0006b2201248080808000200141206a41d8ecc58000410541ead8c58000411741a8d9c58000410010d882808000200141186a42043702002001420037021020014280808080800137020841002d00fca3c680001a02400240024002400240024002400240024002400240024002400240024041c00041002802c8a3c68000118180808000002202450d0020024188ecc580003602202002410036021820024101360204200241abd8c58000360200200241386a4100360200200241246a410136020020014102360238200120023602302001200241c0006a36023c20012002360234200141086a200141306a10fa8680800041002d00fca3c680001a20012802082103200128020c2104200128021021052001280220210620012902242107410841002802c8a3c68000118180808000002208450d0120084100290380edc5800037020041002d00fca3c680001a41002802c8a3c6800021022001410036021020014280808080c00037020841082002118180808000002209450d02200941002903e893c58000370200200141086a410010a086808000200128020c200141086a41086a220a28020041246c6a220241003a00202002410e36021c20024188edc5800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141306a41086a200a28020041016a3602002001200129020837033041002d00fca3c680001a410841002802c8a3c68000118180808000002209450d03200941002903d097c580003702000240200128023822022001280230470d00200141306a200210a086808000200128023821020b2001280234200241246c6a220241013a00202002411536021c20024196edc5800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141086a41086a200141306a41086a28020041016a3602002001200129033037030841002d00fca3c680001a410841002802c8a3c68000118180808000002209450d04200941002903e896c580003702000240200128021022022001280208470d00200141086a200210a086808000200128021021020b200128020c200241246c6a220241023a00202002411336021c200241abedc5800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141306a41086a200141086a41086a28020041016a3602002001200129030837033041002d00fca3c680001a410841002802c8a3c68000118180808000002209450d052009410029038896c580003702000240200128023822022001280230470d00200141306a200210a086808000200128023821020b2001280234200241246c6a220241033a00202002411236021c200241b5e9c5800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141086a41086a200141306a41086a28020041016a3602002001200129033037030841002d00fca3c680001a410841002802c8a3c68000118180808000002209450d06200941002903c894c580003702000240200128021022022001280208470d00200141086a200210a086808000200128021021020b200128020c200241246c6a220241043a00202002410d36021c200241beedc5800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141306a41086a200141086a41086a28020041016a3602002001200129030837033041002d00fca3c680001a410841002802c8a3c68000118180808000002209450d072009410029039098c580003702000240200128023822022001280230470d00200141306a200210a086808000200128023821020b2001280234200241246c6a220241053a00202002411736021c200241cbedc5800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141086a41086a200141306a41086a28020041016a3602002001200129033037030841002d00fca3c680001a410841002802c8a3c68000118180808000002209450d08200941002903f894c580003702000240200128021022022001280208470d00200141086a200210a086808000200128021021020b200128020c200241246c6a220241063a00202002410b36021c200241e2edc5800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141306a41086a200141086a41086a28020041016a3602002001200129030837033041002d00fca3c680001a410841002802c8a3c68000118180808000002209450d09200941002903c096c580003702000240200128023822022001280230470d00200141306a200210a086808000200128023821020b2001280234200241246c6a220241073a00202002410f36021c200241ededc5800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141086a41086a200141306a41086a28020041016a3602002001200129033037030841002d00fca3c680001a410841002802c8a3c68000118180808000002209450d0a200941002903c095c580003702000240200128021022022001280208470d00200141086a200210a086808000200128021021020b200128020c200241246c6a220241083a00202002410c36021c200241fcedc5800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141306a41086a200141086a41086a28020041016a3602002001200129030837033041002d00fca3c680001a410841002802c8a3c68000118180808000002209450d0b2009410029039894c580003702000240200128023822022001280230470d00200141306a200210a086808000200128023821020b2001280234200241246c6a220241093a00202002410e36021c20024188eec5800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141086a41086a200141306a41086a28020041016a3602002001200129033037030841002d00fca3c680001a410841002802c8a3c68000118180808000002209450d0c200941002903d898c580003702000240200128021022022001280208470d00200141086a200210a086808000200128021021020b200128020c200241246c6a2202410a3a00202002411336021c20024196eec5800036021820024101360214200220093602102002428080808010370208200242808080808001370200200141306a41086a200141086a41086a28020041016a3602002001200129030837033041002d00fca3c680001a410841002802c8a3c68000118180808000002209450d0d2009410029039097c580003702000240200128023822022001280230470d00200141306a200210a086808000200128023821020b2001280234200241246c6a2202410b3a00202002410936021c200241a9eec58000360218200241013602142002200936021020024280808080103702082002428080808080013702002001280238210920012802342102200120012802303602102001200236020820012002200941246c6a41246a3602142001200236020c200141306a200141086a10fb868080002006418080808078460d0e20012003360210200120043602082001200436020c2001200420054105746a360214200041c4006a200141086a10fa86808000200141086a410b6a200141306a41086a2802003600002000413c6a200737020020002006360238200041013a0000200041d8006a4101360200200041d4006a2008360200200041013602502001200129023037000b20002001290008370001200041086a2001410f6a290000370000200141c0006a2480808080000f0b410841c00010b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b4104410810b280808000000b41a8d8c480004111419cd9c4800010a181808000000bba0803057f017e027f23808080800041c0006b2201248080808000200141186a41b2eec58000410541ead8c58000411741a8d9c58000410010d882808000200141106a42043702002001420037020820014280808080800137020041002d00fca3c680001a02400240024041c00041002802c8a3c68000118180808000002202450d0020024188ecc580003602202002410036021820024101360204200241abd8c58000360200200241386a4100360200200241246a410136020020014102360238200120023602302001200241c0006a36023c200120023602342001200141306a10fa8680800041002d00fca3c680001a20012802002103200128020421022001280208210420012802182105200129021c2106410841002802c8a3c68000118180808000002207450d01200741002903d8eec580003702002001410036020820014280808080c000370200200141306a200141e0eec58000410710b08b8080002001200141306a41e7eec580004108108e8b808000200141306a200141efeec58000410810ab8b8080002001200141306a41f7eec58000410a10b78b808000200141306a20014181efc58000410810998b8080002001200141306a4189efc58000410a10888b808000200141306a20014193efc58000411210d18b8080002001200141306a41a5efc580004107108b8b808000200141306a200141acefc58000410810b58b8080002001200141306a41b4efc58000410710c58b808000200141306a200141bbefc58000410610ae8b8080002001200141306a41c1efc58000410610848b808000200141306a200141c7efc58000410910bb8b8080002001200141306a41d0efc58000410810b98b808000200141306a200141d8efc580004108108f8b8080002001200141306a41e0efc58000410610978b808000200141306a200141e6efc58000410910ba8b8080002001200141306a41efefc58000410610c28b808000200141306a200141f5efc58000410810a38b8080002001200141306a41fdefc58000410610c78b808000200141306a20014183f0c580004106108c8b808000200141246a200141306a4189f0c58000411310ad8b8080002001200128022436020820012001280228220836020020012008200128022c41246c6a36020c20012008360204200141306a200110fb868080002005418080808078460d022001200336020820012002360200200120023602042001200220044105746a36020c200041c4006a200110fa868080002001410b6a200141306a41086a2802003600002000413c6a200637020020002005360238200041013a0000200041d8006a4101360200200041d4006a2007360200200041013602502001200129023037000320002001290000370001200041086a200141076a290000370000200141c0006a2480808080000f0b410841c00010b280808000000b4104410810b280808000000b41a8d8c480004111419cd9c4800010a181808000000bfa0302047f017e23808080800041f0006b220224808080800002400240024002400240024020012802042203450d0020012003417f6a36020420012001280200220441016a36020020042d0000417f6a0e03010203040b200042033703000c040b024020034105490d0020012003417b6a22053602042001200441056a36020020054108490d00200428000121052001200341736a36020420012004410d6a360200200429000521062002410f6a200110df8780800020022d000f0d00200041086a200241106a41e00010848e8080001a2000200536027020002006370368200042003703000c040b200042033703000c030b024020034105490d0020012003417b6a22053602042001200441056a36020020054108490d0020002004280001360210200042013703002001200341736a36020420012004410d6a360200200020042900053703080c030b200042033703000c020b024020034105490d0020012003417b6a22053602042001200441056a36020020054108490d00200428000121052001200341736a36020420012004410d6a360200200429000521062002410f6a200110df8780800020022d000f0d00200041086a200241106a41e00010848e8080001a2000200536027020002006370368200042023703000c020b200042033703000c010b200042033703000b200241f0006a2480808080000bb10302077f017e23808080800041106b2202248080808000200028020421032002200028020822043602082002200241086a36020c2002410c6a200110c08a8080000240024020040d00200128020821040c010b2003200441286c6a210520012802082104034002402001280200220620046b411f4b0d0020012004412010b18280800020012802002106200128020821040b2001280204220720046a22082003290000370000200841186a200341186a290000370000200841106a200341106a290000370000200841086a200341086a2900003700002001200441206a2208360208200341206a29030021090240200620086b41074b0d0020012008410810b18280800020012802042107200128020821080b2001200841086a2204360208200720086a2009370000200341286a22032005470d000b0b0240200128020020046b411f4b0d0020012004412010b182808000200128020821040b2001200441206a360208200128020420046a2203200029000c370000200341086a200041146a290000370000200341106a2000411c6a290000370000200341186a200041246a290000370000200241106a2480808080000b9c0202047f017e02402001280200220220012802082203470d0020012003410110b18280800020012802002102200128020821030b2001200341016a22043602082001280204220520036a41013a0000200029030021060240200220046b41074b0d0020012004410810b1828080002001280204210520012802002102200128020821040b2001200441086a2203360208200520046a2006370000200029030821060240200220036b41074b0d0020012003410810b18280800020012802042105200128020821030b200520036a20063700002001200341086a220436020820002d00102103024020012802002004470d0020012004410110b182808000200128020821040b2001200441016a360208200128020420046a20033a00000b8b0201047f024020002d00000d000240200128020020012802082200470d0020012000410110b182808000200128020821000b200128020420006a41003a00002001200041016a3602080f0b02402001280200220220012802082203470d0020012003410110b18280800020012802002102200128020821030b2001200341016a22043602082001280204220520036a41013a0000200041016a21000240200220046b411f4b0d0020012004412010b18280800020012802042105200128020821040b200520046a22032000290000370000200341186a200041186a290000370000200341106a200041106a290000370000200341086a200041086a2900003700002001200441206a3602080b900602017e037f0240200029030022024203520d000240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a41003a00000f0b0240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a2204360208200128020420036a41013a00000240024002402002a70e03000102000b024020012802002004470d0020012004410110b182808000200128020821040b200128020420046a41013a00002001200441016a2204360208200041f0006a28020021030240200128020020046b41034b0d0020012004410410b182808000200128020821040b200041086a2105200128020420046a20033600002001200441046a2204360208200041e8006a29030021020240200128020020046b41074b0d0020012004410810b182808000200128020821040b2001200441086a360208200128020420046a20023700002005200110e0878080000f0b024020012802002004470d0020012004410110b182808000200128020821040b200128020420046a41023a00002001200441016a2204360208200041106a2802002103200029030821020240200128020020046b41034b0d0020012004410410b182808000200128020821040b200128020420046a20033600002001200441046a22003602080240200128020020006b41074b0d0020012000410810b182808000200128020821000b2001200041086a360208200128020420006a20023700000f0b024020012802002004470d0020012004410110b182808000200128020821040b200128020420046a41033a00002001200441016a2204360208200041f0006a28020021030240200128020020046b41034b0d0020012004410410b182808000200128020821040b200041086a2105200128020420046a20033600002001200441046a2204360208200041e8006a29030021020240200128020020046b41074b0d0020012004410810b182808000200128020821040b2001200441086a360208200128020420046a20023700002005200110e0878080000bfb0301087f23808080800041106b220224808080800020012d0000210341002d00fca3c680001a41002802c8a3c6800021040240024002400240024020034102460d0041022004118180808000002204450d02200441013a000020022004360208200241023602042002410136020c41002d00fca3c680001a412041002802c8a3c68000118180808000002204450d0320042001290001370000200441186a2205200141196a290000370000200441106a2206200141116a290000370000200441086a2207200141096a290000370000200241046a4101412010b18280800020022802082208200228020c22096a22012004290000370000200141086a2007290000370000200141106a2006290000370000200141186a20052900003700002002200941206a220136020c20022802042105200441002802c0a3c6800011808080800000024020052001470d00200241046a2005410110b18280800020022802082108200228020c21010b200820016a20033a00002002200141016a36020c0c010b41012004118180808000002201450d03200141003a000020022001360208200241013602042002410136020c0b20002002290204370200200041086a200241046a41086a280200360200200241106a2480808080000f0b4101410210b280808000000b4101412010b280808000000b4101410110b280808000000bbb0301057f23808080800041206b2202248080808000024002400240024002402001280200418080808078460d00024002402001280208220341056a2204450d002004417f4c0d044100210541002d00fca3c680001a200441002802c8a3c68000118180808000002206450d05200220063602102002200436020c0c010b20024100360214200242808080801037020c2002410c6a4100410110b18280800020022802102106200228021421050b200620056a41013a00002002200541016a36021420012802042104200220033602182002200241186a36021c2002411c6a2002410c6a10c08a8080000240200228020c200228021422016b20034f0d002002410c6a2001200310b182808000200228021421010b200228021020016a2004200310848e8080001a2002200120036a3602140c010b41002d00fca3c680001a410141002802c8a3c68000118180808000002201450d03200220013602102002410136020c200141003a0000200241013602140b2000200229020c370200200041086a2002410c6a41086a280200360200200241206a2480808080000f0b10ae80808000000b4101200410b280808000000b4101410110b280808000000bbf0201047f23808080800041206b2202248080808000024002400240024002402001280200418080808078460d0020012802082203417f4c0d0241002d00fca3c680001a2003410474410572220441002802c8a3c68000118180808000002205450d03200220053602102002200436020c200541013a00002002410136021420012802042101200220033602182002200241186a36021c2002411c6a2002410c6a10c08a808000200120032002410c6a10d4858080000c010b41002d00fca3c680001a410141002802c8a3c68000118180808000002201450d03200220013602102002410136020c200141003a0000200241013602140b2000200229020c370200200041086a2002410c6a41086a280200360200200241206a2480808080000f0b10ae80808000000b4101200410b280808000000b4101410110b280808000000bbb0301057f23808080800041206b2202248080808000024002400240024002402001280200418080808078460d00024002402001280208220341056a2204450d002004417f4c0d044100210541002d00fca3c680001a200441002802c8a3c68000118180808000002206450d05200220063602102002200436020c0c010b20024100360214200242808080801037020c2002410c6a4100410110b18280800020022802102106200228021421050b200620056a41013a00002002200541016a36021420012802042104200220033602182002200241186a36021c2002411c6a2002410c6a10c08a8080000240200228020c200228021422016b20034f0d002002410c6a2001200310b182808000200228021421010b200228021020016a2004200310848e8080001a2002200120036a3602140c010b41002d00fca3c680001a410141002802c8a3c68000118180808000002201450d03200220013602102002410136020c200141003a0000200241013602140b2000200229020c370200200041086a2002410c6a41086a280200360200200241206a2480808080000f0b10ae80808000000b4101200410b280808000000b4101410110b280808000000b21002001280214419cf0c580004114200141186a28020028020c118280808000000bc80201027f23808080800041106b220224808080800002400240200028020022002802000d00200128021441acd8c580004104200141186a28020028020c1182808080000021010c010b2002200041046a3602002002200128021441b0d8c580004104200141186a28020028020c118280808000003a000c20022001360208200241003a000d20024100360204200241046a200241d0f0c58000108d81808000210120022d000c21000240200128020022030d00200041ff017141004721010c010b41012101200041ff01710d0020022802082100024020034101470d0020022d000d41ff0171450d0020002d001c4104710d00410121012000280214418ca5c080004101200041186a28020028020c118280808000000d010b2000280214418da5c080004101200041186a28020028020c1182808080000021010b200241106a24808080800020010bc80201027f23808080800041106b220224808080800002400240200028020022032d00000d00200128021441acd8c580004104200141186a28020028020c1182808080000021000c010b410121002002200341016a3602002002200128021441b0d8c580004104200141186a28020028020c118280808000003a000c20022001360208200241003a000d20024100360204200241046a200241b0f0c58000108d81808000210120022d000c21030240200128020022010d00200341ff017141004721000c010b200341ff01710d0020022802082103024020014101470d0020022d000d41ff0171450d0020032d001c4104710d00410121002003280214418ca5c080004101200341186a28020028020c118280808000000d010b2003280214418da5c080004101200341186a28020028020c1182808080000021000b200241106a24808080800020000bc50201027f23808080800041106b220224808080800002400240200028020022002802000d00200128021441acd8c580004104200141186a28020028020c1182808080000021010c010b200220003602002002200128021441b0d8c580004104200141186a28020028020c118280808000003a000c20022001360208200241003a000d20024100360204200241046a200241c0f0c58000108d81808000210120022d000c21000240200128020022030d00200041ff017141004721010c010b41012101200041ff01710d0020022802082100024020034101470d0020022d000d41ff0171450d0020002d001c4104710d00410121012000280214418ca5c080004101200041186a28020028020c118280808000000d010b2000280214418da5c080004101200041186a28020028020c1182808080000021010b200241106a24808080800020010bd90703027f017e017f23808080800041a0016b22082480808080002008412c6a2006360200200841246a2004360200200841086a41086a200141086a28020022093602002008411c6a200241086a28020036020020082001290200220a37030820082007360230200820053602282008200336022020082002290200370214200828020c2101024002400240024002400240024002400240024002400240200aa70d00024020072802002202450d0020072802042107200841f0006a20043602002008200336026c20084184808080783602682002200841e8006a200728020c118480808000000b20090d01410121070c020b20094120470d07200841386a41186a2209200141186a290000370300200841386a41106a2202200141106a290000370300200841386a41086a220b200141086a29000037030020082001290000370338200841dc006a2005200841386a200841146a200628020c11868080800000200828025c2206418080808078460d022008280264210120082802602109024020072802002202450d002007280204210720084194016a200841d0006a2903003702002008418c016a200841386a41106a29030037020020084184016a200841c0006a290300370200200841e8006a41106a20043602002008200829033837027c20082003360274200820013602702008200936026c20084180808080783602682002200841e8006a200728020c118480808000000b20010d03410121070c040b2009417f4c0d0741002d00fca3c680001a200941002802c8a3c68000118180808000002207450d080b20072001200910848e80800021012000200936020820002001360204200020093602000c040b200841e8006a41186a2009290300370300200841e8006a41106a2002290300370300200841e8006a41086a200b2903003703002008200829033837036841002d00fca3c680001a413041002802c8a3c680001181808080000022010d024104413010b280808000000b2001417f4c0d0441002d00fca3c680001a200141002802c8a3c68000118180808000002207450d060b20072009200110848e80800021072000200136020820002007360204200020013602002006450d01200941002802c0a3c68000118080808000000c010b2001418580808078360200200120082903683702042001410c6a200841f0006a290300370200200141146a200841f8006a2903003702002001411c6a20084180016a2903003702002000418080808078360200200020013602040b200841a0016a2480808080000f0b4120200941a4f2c5800010a281808000000b10ae80808000000b4101200910b280808000000b4101200110b280808000000b8b0d03017f017e077f23808080800041a0016b22022480808080002001290200210320002802002204280200220128020021052001280204210620012802282100200241d8006a41286a22074100360200200241d8006a20052001200041284b22081b220520052006200020081b6a10f686808000200241086a41286a2007280200360200200241086a41206a200241d8006a41206a290200370300200241086a41186a200241d8006a41186a290200370300200241086a41106a200241d8006a41106a290200370300200241086a41086a200241d8006a41086a290200370300200220022902583703082002200128022c22013602340240200342ff0183500d002003420888a7210002400240024020014101710d00200241086a41047221012000410474210602400240200241086a410441282002280230220741284b22001b6a28020022052007412820001b460d002001200241086a41286a20001b21012002280208200241086a20001b21000c010b200241086a10f78d808000200228020c2105200228020821000b200020056a20063a00002001200128020041016a3602000c010b200228020c20022802302201200141284b22011b2205450d0120052002280208200241086a20011b6a417f6a220120012d00002000723a00000b2002200228023441016a3602340c010b419c94c68000413a41d894c6800010a181808000000b024002400240024002402003422088a722072802002200417e6a2201410420014106491b0e06040200040104040b200741286a21010c020b200741ec046a21010c010b200741046a21010b200241086a200110e18d80800020072802002200417e6a21010b02400240024002400240024002400240024002402001410420014106491b0e06050105030200050b2007410c6a2101200741046a21000c030b2007280234450d03200741346a21002007413c6a21010c020b2000450d022007280204450d02200741046a21002007410c6a21010c010b2007280204450d01200741086a2200280200450d01200741106a21010b200241386a41186a200141186a290200370300200241386a41106a200141106a290200370300200241386a41086a200141086a290200370300200220012902003703382002280208210620042802042802002108410121010240200228020c20022802302205200541284b22051b2209450d002009417f4c0d0241002d00fca3c680001a200941002802c8a3c68000118180808000002201450d030b20012006200241086a20051b200910848e808000210a200041046a2802002106200028020022052005280200220141016a3602002001417f4c0d032002200636025c2002200536025803402005280204210103402001417f460d012001417f4c0d062005200141016a2005280204220020002001461b360204200020014721062000210120060d000b0b200228025c21002002280258220120012802002201417f6a360200024020014101470d00200241d8006a10f18d8080000b0240200828020822012008280200470d0020082001109f86808000200828020821010b2008280204200141386c6a220141023a000c200120093602082001200a360204200120093602002001200229033837000d200120022f00583b002d2001200036023420012005360230200141156a200241c0006a2903003700002001411d6a200241c8006a290300370000200141256a200241d0006a2903003700002001412f6a200241d8006a41026a2d00003a00002008200828020841016a3602080b20042802042802002101200241d8006a41286a200241086a41286a290300370300200241d8006a41206a200241086a41206a290300370300200241d8006a41186a200241086a41186a290300370300200241d8006a41106a200241086a41106a290300370300200241d8006a41086a200241086a41086a29030037030020022002290308370358200220013602880141002105024002400240024002402007280200417e6a2206410420064106491b0e06040400010204040b200741046a2100410121050c030b200741306a21010c010b2007412c6a21010b41022105410021000b200220024188016a360290012002200241d8006a36028c012002200136029c012002200036029801200241003a009501200220053a00940120024194016a2002418c016a10808a80800002402002280280014129490d00200228025841002802c0a3c68000118080808000000b200241a0016a2480808080000f0b10ae80808000000b4101200910b280808000000b00000b10f08d808000000b8b0d03017f017e077f23808080800041a0016b22022480808080002001290200210320002802002204280200220128020021052001280204210620012802282100200241d8006a41286a22074100360200200241d8006a20052001200041284b22081b220520052006200020081b6a10f686808000200241086a41286a2007280200360200200241086a41206a200241d8006a41206a290200370300200241086a41186a200241d8006a41186a290200370300200241086a41106a200241d8006a41106a290200370300200241086a41086a200241d8006a41086a290200370300200220022902583703082002200128022c22013602340240200342ff0183500d002003420888a7210002400240024020014101710d00200241086a41047221012000410474210602400240200241086a410441282002280230220741284b22001b6a28020022052007412820001b460d002001200241086a41286a20001b21012002280208200241086a20001b21000c010b200241086a10f78d808000200228020c2105200228020821000b200020056a20063a00002001200128020041016a3602000c010b200228020c20022802302201200141284b22011b2205450d0120052002280208200241086a20011b6a417f6a220120012d00002000723a00000b2002200228023441016a3602340c010b419c94c68000413a41d894c6800010a181808000000b024002400240024002402003422088a722072802002200417e6a2201410420014106491b0e06040200040104040b200741286a21010c020b200741ec046a21010c010b200741046a21010b200241086a200110e18d80800020072802002200417e6a21010b02400240024002400240024002400240024002402001410420014106491b0e06050105030200050b2007410c6a2101200741046a21000c030b2007280234450d03200741346a21002007413c6a21010c020b2000450d022007280204450d02200741046a21002007410c6a21010c010b2007280204450d01200741086a2200280200450d01200741106a21010b200241386a41186a200141186a290200370300200241386a41106a200141106a290200370300200241386a41086a200141086a290200370300200220012902003703382002280208210620042802042802002108410121010240200228020c20022802302205200541284b22051b2209450d002009417f4c0d0241002d00fca3c680001a200941002802c8a3c68000118180808000002201450d030b20012006200241086a20051b200910848e808000210a200041046a2802002106200028020022052005280200220141016a3602002001417f4c0d032002200636025c2002200536025803402005280204210103402001417f460d012001417f4c0d062005200141016a2005280204220020002001461b360204200020014721062000210120060d000b0b200228025c21002002280258220120012802002201417f6a360200024020014101470d00200241d8006a10f18d8080000b0240200828020822012008280200470d0020082001109f86808000200828020821010b2008280204200141386c6a220141023a000c200120093602082001200a360204200120093602002001200229033837000d200120022f00583b002d2001200036023420012005360230200141156a200241c0006a2903003700002001411d6a200241c8006a290300370000200141256a200241d0006a2903003700002001412f6a200241d8006a41026a2d00003a00002008200828020841016a3602080b20042802042802002101200241d8006a41286a200241086a41286a290300370300200241d8006a41206a200241086a41206a290300370300200241d8006a41186a200241086a41186a290300370300200241d8006a41106a200241086a41106a290300370300200241d8006a41086a200241086a41086a29030037030020022002290308370358200220013602880141002105024002400240024002402007280200417e6a2206410420064106491b0e06040400010204040b200741046a2100410121050c030b200741306a21010c010b2007412c6a21010b41022105410021000b200220024188016a360290012002200241d8006a36028c012002200136029c012002200036029801200241003a009501200220053a00940120024194016a2002418c016a10ff8980800002402002280280014129490d00200228025841002802c0a3c68000118080808000000b200241a0016a2480808080000f0b10ae80808000000b4101200910b280808000000b00000b10f08d808000000b0c002000200110bf8c8080000bc90801087f2380808080004190076b2202248080808000200128020421032001280200280200220428020421052004280200210620012802082207280208200128020c2802006a2208410176210420072802042109200728020021070240024002400240024002400240024020084101710d00200420094b0d02200241003a00b805200220043602b405200220073602b0050c010b200420094b0d02200420094f0d03200220073602b005200220043602b405200241b9056a200720046a2d000041f001713a0000200241013a00b8050b200241c4036a20062003200241b0056a200528020c11868080800000024002400240024020022802c4032204418080808078470d00200241b0056a41086a2204200341086a290000370300200241b0056a41106a2207200341106a290000370300200241b0056a41186a2209200341186a290000370300200220032900003703b0052001280210280200210341002d00fca3c680001a413041002802c8a3c680001181808080000022010d014104413010b280808000000b200241b0056a20022802c803220720022802cc03220110c28c80800020022802b00522094105470d01200241e8016a410c6a200241b0056a410c6a290200370200200220022902b4053702ec010c020b200120022903b005370204200141858080807841848080807820031b3602002001410c6a2004290300370200200141146a20072903003702002001411c6a200929030037020020004108360200200020013602040c070b200241a8056a2208200241b0056a410c6a290200370300200220022902b4053703a005200241c4036a41146a200241b0056a41146a41c80110848e8080001a200241c4036a410c6a2008290300370200200220093602c403200220022903a0053702c803200241e8016a200241c4036a2007200110f48d80800020022802e8014105470d050b200241b0056a41086a2209200241f4016a290200370300200241b0056a41186a2208200341086a290000370300200241b0056a41206a2205200341106a290000370300200241b0056a41286a2206200341186a290000370300200220022902ec013703b005200220032900003703c00541002d00fca3c680001a413041002802c8a3c68000118180808000002201450d03200120022903b005370200200141286a2006290300370200200141206a2005290300370200200141186a2008290300370200200141106a200241b0056a41106a290300370200200141086a200929030037020020004108360200200020013602042004450d05200741002802c0a3c68000118080808000000c050b2004200941f492c68000109581808000000b20042009418493c68000109581808000000b20042009419493c6800010f980808000000b4104413010b280808000000b2002410c6a200241e8016a41dc0110848e8080001a20002002410c6a10b68a8080002004450d00200741002802c0a3c68000118080808000000b20024190076a2480808080000bff0401067f23808080800041306b22022480808080002001280204210320012802002204280200210520042802042104200241106a41086a22062001280208220141086a28020036020020022001290200370310200241046a20052003200241106a200428020c1186808080000002400240024002400240024020022802042205418080808078470d00200241106a41186a2201200341186a290000370300200241106a41106a2204200341106a2900003703002006200341086a2900003703002002200329000037031041002d00fca3c680001a413041002802c8a3c680001181808080000022030d014104413010b280808000000b200228020c2201417f4c0d02200141f5ffffff074f0d0320022802082106024002402001410b6a417c7122070d00410421040c010b41002d00fca3c680001a200741002802c8a3c68000118180808000002204450d050b2004428180808010370200200441086a2006200110848e8080001a02402005450d00200641002802c0a3c68000118080808000000b2000200136020820002004360204200041073602002000200329000037000c200041246a200341186a2900003700002000411c6a200341106a290000370000200041146a200341086a2900003700000c010b2003418580808078360200200320022903103702042003410c6a200241106a41086a290300370200200341146a20042903003702002003411c6a200129030037020020004108360200200020033602040b200241306a2480808080000f0b41bc96c68000412b200241106a41e896c6800041e897c68000108981808000000b41e484c08000412b200241106a419085c08000419086c08000108981808000000b4104200710b280808000000b02000be309020b7f017e23808080800041f0016b22032480808080002003410036022c2003200236022820032001360224200341306a200341246a10978780800002400240024002400240024002400240024020032d003022044105460d00200328023421052004417d6a210620040e050102030203010b2000428580808090808080807f3702000c070b200041003602000c060b20032d00312107200328022c210820054101712209450d04200820024f0d01200120086a2d00004110490d042000428580808080808080807f3702000c050b200328022c210420054101712208450d02200420024f0d01200120046a2d00004110490d022000428580808080808080807f3702000c040b2008200241d4f7c5800010f980808000000b2004200241f4f7c5800010f980808000000b024002400240024002402004200541016a4101766a2202200328022822014b0d002003200236022c20064102490d02200341186a200341246a10bb8a80800020032802180d0141002105200328022c2206200328021c6a220a20032802284d0d032000428580808090808080807f3702000c060b2000428580808090808080807f3702000c050b2000428580808090808080807f3702000c040b4101210520022106200241206a220a20014b0d010b2000200a36021820002006360214200020053602102000200836020c2000200236020820002004360204200041013602000c020b2000428580808090808080807f3702000c010b024002402008200541016a4101766a22052003280228220a4b0d00200541026a220b200a4d0d012000428580808090808080807f3702000c020b2000428580808090808080807f3702000c010b2003200b36022c0240024002402005417d4b0d00200b20024b0d01200120056a2f0000220c450d024102210d02400240024002402004410147200772410171450d000240024020064102490d00200341106a200341246a10bb8a80800020032802100d034100210d200328022c220b20032802146a220220032802284d0d012000428580808090808080807f3702000c090b4101210d200541226a2202200a4b0d030b2003200236022c2002ad422086200bad84210e0b200341023602e401200341023602d801200341023602cc01200341023602c001200341023602b401200341023602a8012003410236029c0120034102360290012003410236028401200341023602782003410236026c2003410236026020034102360254200341023602482003410236023c2003410236023041002101200341306a210203400240200c200141ffff037176410171450d00200341086a200341246a10bb8a80800020032802080d04200328022c2206200328020c220a6a220420032802284b0d04200241086a2004360200200241046a20063602002002200a4120473602002003200436022c0b2002410c6a2102200141016a22014110470d000b2000411c6a200341306a41c00110848e8080001a2000200e3702142000200d3602102000200936020c2000200536020820002008360204200041043602000c060b2000428580808090808080807f3702000c050b2000428580808090808080807f3702000c040b2000428580808090808080807f3702000c030b2005200b41e4f7c58000109681808000000b200b200241e4f7c58000109581808000000b2000428580808090808080807f3702000b200341f0016a2480808080000ba00701027f2380808080004180016b220b248080808000200b2008360214200b200736021002400240024020012802002208450d00200b2008360218200b2001280204220736021c02402009450d00200b41c8006a41086a2004360200200b200336024c200b4184808080783602482009200b41c8006a200a28020c118480808000000b20082008280200220941016a3602002009417f4c0d0120002007360204200020083602002000200141086a2201290200370208200041206a200141186a290200370200200041186a200141106a290200370200200041106a200141086a290200370200200b280218220020002802002200417f6a36020020004101470d02200b41186a10e28a8080000c020b200b41186a41186a2001411c6a2208290000370300200b41186a41106a200141146a2207290000370300200b41186a41086a2001410c6a220c290000370300200b2001290004370318200b41c8006a41186a2008290000370300200b41c8006a41106a2007290000370300200b41c8006a41086a200c290000370300200b2001290004370348200b2002360244200b200b41186a360240200b200b41106a36023c200b41086a2005200b41c8006a200b413c6a41b4f2c58000200628021411878080800000200b28020c21010240200b280208450d0020004100360200200020013602040c020b024002400240024002400240024020012802002207417e6a2208410420084106491b0e06050005020103050b20012802342208450d04200141346a21070c050b2007450d0320012802042208450d03200141046a21070c040b20012802040d010c020b200141046a2107200128020421080c020b200141086a220728020022080d010b41c8f2c5800041ec0041b4f3c5800010a181808000000b200741046a280200210120082008280200220741016a3602002007417f4c0d0002402009450d00200b41c8006a41106a2004360200200b41f4006a200b41306a290300370200200b41ec006a200b41186a41106a290300370200200b41e4006a200b41186a41086a290300370200200b200b29031837025c200b2003360254200b2001360250200b418080808078360248200b200841086a36024c2009200b41c8006a200a28020c118480808000000b2000200b2903183700082000200136020420002008360200200041206a200b41186a41186a290300370000200041186a200b41186a41106a290300370000200041106a200b41206a2903003700000c010b00000b200b4180016a2480808080000bff0401067f23808080800041306b22022480808080002001280204210320012802002204280200210520042802042104200241106a41086a22062001280208220141086a28020036020020022001290200370310200241046a20052003200241106a200428020c1186808080000002400240024002400240024020022802042205418080808078470d00200241106a41186a2201200341186a290000370300200241106a41106a2204200341106a2900003703002006200341086a2900003703002002200329000037031041002d00fca3c680001a413041002802c8a3c680001181808080000022030d014104413010b280808000000b200228020c2201417f4c0d02200141f5ffffff074f0d0320022802082106024002402001410b6a417c7122070d00410421040c010b41002d00fca3c680001a200741002802c8a3c68000118180808000002204450d050b2004428180808010370200200441086a2006200110848e8080001a02402005450d00200641002802c0a3c68000118080808000000b2000200136020820002004360204200041073602002000200329000037000c200041246a200341186a2900003700002000411c6a200341106a290000370000200041146a200341086a2900003700000c010b2003418580808078360200200320022903103702042003410c6a200241106a41086a290300370200200341146a20042903003702002003411c6a200129030037020020004108360200200020033602040b200241306a2480808080000f0b41bc96c68000412b200241106a41e896c6800041e897c68000108981808000000b41e484c08000412b200241106a419085c08000419086c08000108981808000000b4104200710b280808000000bc91e04047f017e0a7f027e23808080800041b0026b2206248080808000200641d0006a41086a200141086a22072802003602002006200129020037035020022802002108200228020421092006200336025c200641e0006a41086a2007280200220236020020062001290200220a370360200641f0006a41186a220b200341206a290000370300200641f0006a41106a220c200341186a290000370300200641f0006a41086a220d200341106a290000370300200620032900083703704100210e20064100360290012006280264220f4101742107200641e0016a41086a2110200aa72111200528021421120240024003402006200e36029401200641e0016a41186a200b290300370300200641e0016a41106a200c2903003703002010200d290300370300200620062903703703e001200620064194016a3602c801200620064190016a3602c4012006200641d0006a3602c0012006200641f0006a3602bc012006200641dc006a3602b801200641086a2004200641e0016a200641b8016a41b8f4c58000201211878080800000200628020c210320062802080d01200e41016a210e0240200628025c22012802302213450d00200141346a2802002101201041186a200b290300370000201041106a200c290300370000201041086a200d29030037000020102006290370370000200620033602e40120064181808080783602e0012013200641e0016a200128020c118480808000000b03400240024002400240024002400240024002400240024002400240024002402003280200417e6a2201410420014106491b0e06000203040501000b200628025c22032802302202450d07200341346a2802002103200641e8016a2009360200200620083602e40120064186808080783602e0012002200641e0016a200328020c118480808000000c070b200641ec016a4201370200200641013602e401200641f8f4c580003602e001200641e0818080003602bc01200641c4f6c580003602b8012006200641b8016a3602e801200641e0016a41ccf6c5800010f680808000000b0240200641e0006a200341046a10df8d8080000d00200628025c22032802302202450d06200341346a2802002103200641e8016a2009360200200620083602e40120064186808080783602e0012002200641e0016a200328020c118480808000000c060b0240024020032802342202450d002003280238210f20022002280200220141016a3602002001417f4c0d0b200641b0016a200341d4006a290000370300200641a8016a200341cc006a290000370300200641a0016a200341c4006a29000037030020062003413c6a290000370398010c010b200641a0016a200341c4006a290000370300200641a8016a200341cc006a290000370300200641b0016a200341d4006a28000036020020062003413c6a290000370398012003280038210f0b200628025c22032802002101200328020421072006290350210a20064188026a200f3602002006418c026a200629039801370200200641e0016a41346a20064198016a41086a2903003702002006419c026a20064198016a41106a290300370200200641a4026a20064198016a41186a290300370200200641e0016a41206a2007360200200641e0016a41186a2005360200200641e0016a41106a200936020020062002360284022006200341306a3602ac02200620013602fc01200620043602f401200620083602ec0141002102200641003a00e8012006200a3702e001200641b8016a20064184026a200641e0016a2008200920042005200120072003280230200341346a28020010c38c80800020062802b8012203450d03200641306a41086a200641b8016a41106a290200370300200641306a41106a200641b8016a41186a290200370300200641306a41186a200641b8016a41206a290200370300200620062902c00137033020062802bc01210f0c070b0240200641e0006a200341286a10de8d8080000d00200628025c22032802302202450d05200341346a2802002103200641e8016a2009360200200620083602e40120064186808080783602e0012002200641e0016a200328020c118480808000000c050b20062002200341d4006a28020022016a2202360268200620012006280290016a36029001200341046a21030c0a0b02400240024020072002460d0020024101762201200f4f0d012003201120016a2d00002201410f71200141047620024101711b41246c6a41306a22032d00004102470d02200628025c22032802302202450d06200341346a2802002103200641e8016a2009360200200620083602e40120064186808080783602e0012002200641e0016a200328020c118480808000000c060b02402003280204450d0002400240200341086a2802002202450d00200328020c210120022002280200220741016a3602002007417f4c0d0c200641b8016a41186a200341286a290000370300200641b8016a41106a200341206a290000370300200641c0016a200341186a2900003703002006200341106a2900003703b8010c010b200328000c2101200641b8016a41186a200341286a280000360200200641b8016a41106a200341206a290000370300200641b8016a41086a200341186a2900003703002006200341106a2900003703b8010b2006418c026a20062903b801370200200641a4026a200641b8016a41186a220f2903003702002006419c026a200641b8016a41106a2211290300370200200641e0016a41346a200641b8016a41086a29030037020020064188026a2001360200200641e0016a41186a2005360200200641e0016a41106a2009360200200641e0016a41206a200628025c220328020422013602002006200236028402200620043602f401200620083602ec0141002102200641003a00e801200620062903503702e0012006200341306a3602ac022006200328020022073602fc01200641b8016a20064184026a200641e0016a2008200920042005200720012003280230200341346a28020010c38c80800020062802b8012203450d04200641306a41086a2011290200370300200641306a41106a200f290200370300200641306a41186a200641b8016a41206a290200370300200620062902c00137033020062802bc01210f0c080b200628025c22032802302202450d06200341346a2802002103200641e8016a2009360200200620083602e40120064186808080783602e0012002200641e0016a200328020c118480808000000c060b2001200f41a8f4c5800010f980808000000b2006200241016a2202360268200620062802900141016a360290010c090b0240200641e0006a200341ec046a10de8d8080000d00200628025c22032802302202450d03200341346a2802002103200641e8016a2009360200200620083602e40120064186808080783602e0012002200641e0016a200328020c118480808000000c030b0240200720026b20034198056a2802002201460d00200120026a22144101762213200f4f0d0202402003201120136a2d00002213410f71201341047620144101711b41246c6a412c6a22032d00004102470d00200628025c22032802302202450d04200341346a2802002103200641e8016a2009360200200620083602e40120064186808080783602e0012002200641e0016a200328020c118480808000000c040b2006200141016a220120026a2202360268200620062802900120016a360290010c090b02402003280200450d000240024020032802042202450d002003280208210120022002280200220741016a3602002007417f4c0d09200641d0016a200341246a290000370300200641c8016a2003411c6a290000370300200641c0016a200341146a29000037030020062003410c6a2900003703b8010c010b20032800082101200641d0016a200341246a280000360200200641c8016a2003411c6a290000370300200641c0016a200341146a29000037030020062003410c6a2900003703b8010b2006418c026a20062903b801370200200641a4026a200641b8016a41186a220f2903003702002006419c026a200641b8016a41106a2211290300370200200641e0016a41346a200641b8016a41086a29030037020020064188026a2001360200200641e0016a41186a2005360200200641e0016a41106a2009360200200641e0016a41206a200628025c220328020422013602002006200236028402200620043602f401200620083602ec0141002102200641003a00e801200620062903503702e0012006200341306a3602ac022006200328020022073602fc01200641b8016a20064184026a200641e0016a2008200920042005200720012003280230200341346a28020010c38c80800020062802b8012203450d01200641306a41086a2011290200370300200641306a41106a200f290200370300200641306a41186a200641b8016a41206a290200370300200620062902c00137033020062802bc01210f0c050b200628025c22032802302202450d03200341346a2802002103200641e8016a2009360200200620083602e40120064186808080783602e0012002200641e0016a200328020c118480808000000c030b4101210220062802bc0121030c030b2013200f41a8f4c5800010f980808000000b41002102410021030c020b41002103410021020b20020d06200641106a41186a200641306a41186a290300370300200641106a41106a200641306a41106a290300370300200641106a41086a200641306a41086a29030037030020062006290330370310024020030d0041002102410021030c010b20032003280200220241016a3602002002417f4c0d01200641f9016a200641286a290300370000200641f1016a200641206a290300370000200641e9016a200641186a290300370000200620062903103700e1012006200f3602bc01200620033602b80103402003280204210203402002417f460d012002417f4c0d042003200241016a2003280204220120012002461b360204200120024721072001210220070d000b0b20062802bc01210220062802b801220120012802002201417f6a360200024020014101470d00200641b8016a10f18d8080000b20064188026a20023602002006200336028402410221020b200620023a00e001200420082009200641e0016a200528021011868080800000200041086a200f36020020002003360204200041003602000c060b00000b10f08d808000000b024020032d00000d00200341096a290000210a200341116a290000211520032900012116200b200341196a290000370300200c2015370300200d200a370300200620163703700c020b200328020421030c000b0b0b20004101360200200020033602040b200641b0026a2480808080000b832a05237f017e017f017e017f23808080800041d0076b2205248080808000200128022821062001410036022802400240024002400240024020060d00200541086a41306a2207200141306a290200370300200541086a41286a200141286a290200370300200541086a41206a2208200141206a290200370300200541086a41186a2206200141186a290200370300200541086a41106a2209200141106a290200370300200541086a41086a220a200141086a29020037030020052001290200370308200541c0006a41086a200441086a2201280200220b36020020052004290200370340200541d0006a41186a220c2008290300370300200541d0006a41106a220d2006290300370300200541d0006a41086a220e20092903003703002005200a2903003703502001280200210f200541d0006a4107722110200541f0056a41186a2111200541f0056a410c6a211220054190016a2113200541f4006a41046a210620054184046a41046a210920054184046a41146a2114200541f0056a41146a2115200541f0056a41046a2116200541f0056a41106a211720042802042118200428020021192005413c6a280200211a2007280200211b200528020c211c2005280208211d4100211e4100210a02400240024002400340200a200f6a220841017621010240024020084101710d00200120184b0d06200541003a00f805200520013602f405200520193602f0050c010b200120184b0d04200120184f0d03200541013a00f805200520193602f005200520013602f4052005201920016a2d000041f001713a00f9050b20054184046a201d200541d0006a200541f0056a201c28020c118680808000000240200528028404221f418080808078470d00200541f0056a41186a2208200541d0006a41186a290300370300200541f0056a41106a220b200541d0006a41106a290300370300200541f0056a41086a2204200541d0006a41086a290300370300200520052903503703f00541002d00fca3c680001a413041002802c8a3c680001181808080000022010d0a4104413010b280808000000b200528028c04210120052802880421200240201b450d0020172005290350370000201741186a200c290300370000201741106a200d290300370000201741086a200e290300370000200520013602fc05200520203602f8052005428280808088808080807f3702f005201b200541f0056a201a28020c118480808000000b200541f0056a2020200110c28c808000200541e0056a41086a2221201641086a2222290200370300200520162902003703e005024020052802f00522044105460d00201e41016a211e200528024422234101742124200528024021252020210803402014201541c80110848e8080001a200941086a2021290300370200200920052903e0053702002005200436028404200541f4006a20054184046a2008200110f48d808000200528027422264105460d08200541f8036a41086a2227200641086a280200360200200520062902003703f80320052802840121042005280288012108200528028c012101200541d0026a201341a80110848e8080001a20052902bc02212820052802b802212902400240024002400240024020260e050001020304000b0240201b450d00200528023c2101200541f8056a2003360200200520023602f40520054186808080783602f005201b200541f0056a200128020c118480808000000b20004180808080783602000c0e0b0240024020052802fc034101742005280280046b2024200b6b220b470d00200541f8036a200541c0006a10db8d808000200b460d010b0240201b450d00200528023c2101200541f8056a2003360200200520023602f40520054186808080783602f005201b200541f0056a200128020c118480808000000b20004180808080783602000c0e0b20054194066a201c3602002005418c066a200336020020054184066a41003a000020054180066a201836020020052007360298062005201d360290062005200236028806200520193602fc05200520013602f805200520083602f405200520043602f00520054184046a200541f0056a200541fc056a20022003201d201c200710bb8c8080000240200528028404418080808078460d002000200529028404370200200041086a20054184046a41086a2802003602000c0e0b200020052802880436020420004181808080783602000c0d0b20052802fc03212920052802800421270240200541c0006a200541f8036a10db8d8080002226202941017420276b460d000240201b450d00200528023c2101200541f8056a2003360200200520023602f40520054186808080783602f005201b200541f0056a200128020c118480808000000b20004180808080783602000c0d0b2005200b20266a220b3602480c020b200541f0056a41086a2027280200360200200520052903f8033703f00520052001360284062005200836028006200520043602fc052011200541d0026a41a80110848e8080001a0240024002402024200b460d00200b410176220120234f0d01200541f0056a202520016a2d00002201410f712001410476200b4101711b410c6c6a220828020022044102470d020240201b450d00200528023c21012005418c046a20033602002005200236028804200541868080807836028404201b20054184046a200128020c118480808000000b20004180808080783602000c0e0b024020294102460d00200541a8046a201c360200200541a0046a200336020020054198046a41003a000020054194046a2018360200200520073602ac042005201d3602a4042005200236029c04200520193602900420052028370288042005202936028404200541f4006a20054184046a20054190046a20022003201d201c200710bb8c80800002402005280274418080808078460d0020002005290274370200200041086a200541f4006a41086a2802003602000c0f0b2000200528027836020420004181808080783602000c0e0b0240201b450d00200528023c21012005418c046a20033602002005200236028804200541868080807836028404201b20054184046a200128020c118480808000000b20004180808080783602000c0d0b2001202341a8f4c5800010f980808000000b410121262005200b41016a220b36024820082802082101200828020421080c010b20052902c802212a20052802c402212b200528028004212620052802fc032127200520013602f805200520083602f405200520043602f0052012200541d0026a41a80110848e8080001a200520283702a807200520293602a4070240200541c0006a200541f8036a10db8d8080002201202741017420266b460d000240201b450d00200528023c21012005418c046a20033602002005200236028804200541868080807836028404201b20054184046a200128020c118480808000000b20004180808080783602000c0b0b024002402024200b6b2001460d00200b20016a2204410176220820234f0d010240200541f0056a202520086a2d00002208410f71200841047620044101711b410c6c6a220828020022044102470d000240201b450d00200528023c21012005418c046a20033602002005200236028804200541868080807836028404201b20054184046a200128020c118480808000000b20004180808080783602000c0d0b2005200b200141016a22266a220b36024820082802082101200828020421080c020b0240202b4102460d00200541a8046a201c360200200541a0046a200336020020054198046a41003a000020054194046a2018360200200520073602ac042005201d3602a4042005200236029c0420052019360290042005202a370288042005202b36028404200541f4006a20054184046a20054190046a20022003201d201c200710bb8c80800002402005280274418080808078460d0020002005290274370200200041086a200541f4006a41086a2802003602000c0d0b2000200528027836020420004181808080783602000c0c0b0240201b450d00200528023c21012005418c046a20033602002005200236028804200541868080807836028404201b20054184046a200128020c118480808000000b20004180808080783602000c0b0b2008202341a8f4c5800010f980808000000b2026200a6a210a024020040d0020014120470d04200841026a2d000021012008410f6a2900002128200841176a290000212a2008411f6a2d0000210420082f000021262008280003212120102008290007370000201041186a20043a0000201041106a202a370000201041086a202837000020052021360053200520013a0052200520263b0150201f450d03202041002802c0a3c68000118080808000000c030b200541f0056a2008200110c28c80800020212022290200370300200520162902003703e00520052802f00522044105470d000b0b0b200620052903e005370200200641086a200541e0056a41086a2903003702000c050b2005200141001096868080002005280200210b20052802042008200110848e808000210441002d00fca3c680001a0240413041002802c8a3c68000118180808000002208450d002008200b36020420084188808080783602002008200136020c2008200436020820002008360204200041818080807836020020082005290350370010200841186a200541d8006a290300370000200841206a200541e0006a290300370000200841286a200541d0006a41186a2903003700000c060b4104413010b280808000000b20012018419493c6800010f980808000000b20012018418493c68000109581808000000b2001201841f492c68000109581808000000b2001412c6a280200210a200541f0056a41306a200141306a2902002228370300200541f0056a41286a200141286a290200370300200541f0056a41206a200141206a290200370300200541f0056a41186a200141186a290200370300200541f0056a41106a200141106a290200370300200541f0056a41086a200141086a290200370300200520012902003703f0052005200336025420052002360250410121160240024002400240024002400240024002400240024002400240024002400240024002402028a72221450d000240202120022003200541a4066a2802002802101182808080000041ff01710e03010002010b410021160b200620022003200a28020c1182808080000022260d010b20054184046a2004200541d0006a200541f0056a2006200a10c58c80800020052802880421082005280284040d012005418c046a28020021090c090b418080808078210920262d00000e030c02010c0b20004181808080783602000c030b20262802242208417f460d01202641016a21292008280200210103402001450d022001417f4c0d042008200141016a2008280200220b200b20014622091b360200200b21012009450d000b201620262802282209412149720d0702402021450d00200541a4066a280200210120054184046a41106a2003360200200541b0046a202941186a290000370200200541a8046a202941106a290000370200200541a0046a202941086a29000037020020052002360290042005200936028c042005200841086a360288042005418080808078360284042005202929000037029804202120054184046a200128020c118480808000000b20052009360288042005200836028404200841086a21010c080b200541a0046a202641196a29000037020020054198046a202641116a29000037020020054190046a202641096a29000037020020054100360284042005202629000137028804200541003a001020052004290200370208200541f4006a20054184046a200541086a200220032006200a20052802f00520052802f4052021200541a4066a28020010c38c808000024020052802742208450d00200541d8026a220b200541f4006a41106a290200370300200541d0026a41106a2204200541f4006a41186a290200370300200541d0026a41186a222620054194016a2902003703002005200529027c3703d0022005280278210920082008280200220141016a3602002001417f4c0d042005419d046a202629030037000020054195046a20042903003700002005418d046a200b290300370000200520052903d00237008504200520093602782005200836027403402008280204210103402001417f460d012001417f4c0d072008200141016a2008280204220b200b2001461b360204200b2001472104200b210120040d000b0b200528027821012005280274220b200b280200220b417f6a3602000240200b4101470d00200541f4006a10f18d8080000b200541ac046a2001360200200520083602a804200541023a00840420062002200320054184046a200a280210118680808000000c070b200528027821012000418180808078360200200020013602040c100b20054184046a2004200541d0006a200541f0056a2006200a10c58c808000200528028804210802402005280284040d002005418c046a28020021090c050b20004181808080783602000b200020083602040c0e0b10f28d808000000b00000b10f08d808000000b20080d0041808080807821090c030b20052009360288042005200836028404200841086a210120090d004101210b410021090c010b2009417f4c0d0241002d00fca3c680001a200941002802c8a3c6800011818080800000220b450d030b200b2001200910848e808000210120082008280200220b417f6a3602000240200b4101470d0020054184046a10e28a8080000b2009ad4220862001ad8421280b20002028370204200020093602000c060b10ae80808000000b4101200910b280808000000b200541f0056a41086a2208200641086a290200370300200541f0056a41186a220b200541d0006a41086a290300370300200541f0056a41206a2204200541d0006a41106a290300370300200541f0056a41286a2209200541d0006a41186a2903003703002005200529035037038006200520062902003703f00541002d00fca3c680001a413041002802c8a3c68000118180808000002201450d01200120052903f005370200200141286a2009290300370200200141206a2004290300370200200141186a200b290300370200200141106a200541f0056a41106a290300370200200141086a20082903003702002000418180808078360200200020013602040b201f450d02202041002802c0a3c68000118080808000000c020b4104413010b280808000000b200120052903f0053702042001418580808078418480808078201e1b3602002001410c6a2004290300370200200141146a200b2903003702002001411c6a20082903003702002000418180808078360200200020013602040b200541d0076a2480808080000bcf0101037f23808080800041206b220224808080800002400240200128020022032802042204450d0020032004417f6a36020420032003280200220441016a36020002400240024020042d00000e020102000b20004181808080783602000c030b20004180808080783602000c020b200241086a200110bc8a80800020022802080d00200241146a2001200228020c10d08580800020022802142203418080808078460d0020002002290218370204200020033602000c010b20004181808080783602000b200241206a2480808080000bd80101027f23808080800041106b22022480808080000240024020002903004200520d000240200128020020012802082200470d0020012000410110b182808000200128020821000b2001200041016a360208200128020420006a41003a00000c010b0240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a41013a00002002200041086a360208200241086a200110c18a8080002002200041106a36020c2002410c6a200110c18a8080000b200241106a2480808080000b9e0201037f23808080800041106b2202248080808000024002402000280200418080808078470d000240200128020020012802082200470d0020012000410110b182808000200128020821000b200128020420006a41003a0000200041016a21000c010b0240200128020020012802082203470d0020012003410110b182808000200128020821030b2001200341016a360208200128020420036a41013a0000200028020421042002200028020822003602082002200241086a36020c2002410c6a200110c08a80800002402001280200200128020822036b20004f0d0020012003200010b182808000200128020821030b200128020420036a2004200010848e8080001a200320006a21000b20012000360208200241106a2480808080000b4d01017f23808080800041206b2203248080808000200341106a420037020020034101360208200341bcf7c5800036020420032003411c6a36020c200341046a41c4f7c5800010f680808000000b4d01017f23808080800041206b2204248080808000200441106a420037020020044101360208200441bcf7c5800036020420042004411c6a36020c200441046a4184f8c5800010f680808000000bcd0e01117f23808080800041f0006b22052480808080000240024002400240024002400240024020042802002206417f6a0e020200010b200241017641046a2207417f4c0d0241002d00fca3c680001a200741002802c8a3c68000118180808000002208450d03200541c0006a41086a22094100360200200520083602442005200736024020052002360210200541013b010c2005410c6a200541c0006a109887808000200541c0006a2001109a87808000200541086a2009280200360200200520052902403703000c060b200241017641046a2207417f4c0d0141002d00fca3c680001a200741002802c8a3c68000118180808000002208450d03200541c0006a41086a2209410036020020052008360244200520073602402005200236021020054181023b010c2005410c6a200541c0006a109887808000200541c0006a2001109a87808000200541086a2009280200360200200520052902403703000c050b200241017641046a2207417f4c0d0041002d00fca3c680001a200741002802c8a3c68000118180808000002208450d03200541c0006a41086a220941003602002005200836024420052007360240200541033a000c200520023602102005410c6a200541c0006a109887808000200541c0006a2001109a87808000200541086a2009280200360200200520052902403703000c040b10ae80808000000b4101200710b280808000000b4101200710b280808000000b4101200710b280808000000b2005280208220a21020240200a2005280200470d002005200a109c86808000200528020821020b200528020420026a41003a00002005200528020841016a2202360208024020022005280200470d0020052002109c86808000200528020821020b200528020420026a41003a00002005200528020841016a2202360208024002400240024020060e03000103000b200428020421012005200441086a280200220236020c20052005410c6a360240200541c0006a200510c08a80800002402005280200200528020822046b20024f0d0020052004200210ab86808000200528020821040b200528020420046a2001200210848e8080001a200420026a21020c010b200428020421010240200528020020026b200441086a28020022044f0d0020052002200410ab86808000200528020821020b200528020420026a2001200410848e8080001a200220046a21020b200520023602080b02400240024002400240200328020022022003280204220b470d0041002106410021030c010b2003280210210c20032802082104200328020c220841046a210d2005410c6a41086a21092005410c6a410172210e41002106200541c0006a410172220f411f6a2110200f41186a2111200f41106a21124101210102400240034020022d00002103200241023a000020034103460d0241002107024020034102460d00200f20022900013700002010200241206a2800003600002011200241196a2900003700002012200241116a290000370000200f41086a200241096a29000037000020082802042113200828020821142005200828020036023c20052014200828022c2215201541284b22151b36023820052013200d20151b360234200520043a0069200541013a0068200520033a0040200c41046a28020021032005200541346a3602642005410c6a200c2802002003200541c0006a200541346a4101200410d98580800020052d000c22034103460d022005280210211302400240024020030e03000103010b200541203602342005200541346a360240200541c0006a200510c08a80800002402005280200200528020822076b411f4b0d0020052007412010b182808000200528020821070b200528020420076a220320092900003700072003200e2f00003b0000200341026a200e41026a2d00003a0000200320133600032003410f6a200941086a290000370000200341176a200941106a2900003700002003411f6a200941186a2d00003a00002005200741206a3602080c010b200541c0006a41186a200941186a290000370300200541c0006a41106a200941106a290000370300200541c0006a41086a200941086a29000037030020052009290000370340201341214f0d062005201336026c2005200541ec006a360234200541346a200510c08a80800002402005280200200528020822036b20134f0d0020052003201310b182808000200528020821030b200528020420036a200541c0006a201310848e8080001a2005200320136a3602080b200121070b200441016a21042001410174210120072006722106200241246a2202200b470d000b20064180fe037141087621030c020b20064180fe037141087621030c010b20064180fe037141087621030b200a41026a2102200a417d4b0d012002200528020822044b0d022005280204200a6a220220033a0001200220063a000020002005290300370200200041086a200541086a280200360200200541f0006a2480808080000f0b2013412041a4f8c58000109581808000000b200a20024194f8c58000109681808000000b200220044194f8c58000109581808000000bcd0e01117f23808080800041f0006b22052480808080000240024002400240024002400240024020042802002206417f6a0e020200010b200241017641046a2207417f4c0d0241002d00fca3c680001a200741002802c8a3c68000118180808000002208450d03200541c0006a41086a22094100360200200520083602442005200736024020052002360210200541013b010c2005410c6a200541c0006a109887808000200541c0006a2001109a87808000200541086a2009280200360200200520052902403703000c060b200241017641046a2207417f4c0d0141002d00fca3c680001a200741002802c8a3c68000118180808000002208450d03200541c0006a41086a2209410036020020052008360244200520073602402005200236021020054181023b010c2005410c6a200541c0006a109887808000200541c0006a2001109a87808000200541086a2009280200360200200520052902403703000c050b200241017641046a2207417f4c0d0041002d00fca3c680001a200741002802c8a3c68000118180808000002208450d03200541c0006a41086a220941003602002005200836024420052007360240200541033a000c200520023602102005410c6a200541c0006a109887808000200541c0006a2001109a87808000200541086a2009280200360200200520052902403703000c040b10ae80808000000b4101200710b280808000000b4101200710b280808000000b4101200710b280808000000b2005280208220a21020240200a2005280200470d002005200a109c86808000200528020821020b200528020420026a41003a00002005200528020841016a2202360208024020022005280200470d0020052002109c86808000200528020821020b200528020420026a41003a00002005200528020841016a2202360208024002400240024020060e03000103000b200428020421012005200441086a280200220236020c20052005410c6a360240200541c0006a200510c08a80800002402005280200200528020822046b20024f0d0020052004200210ab86808000200528020821040b200528020420046a2001200210848e8080001a200420026a21020c010b200428020421010240200528020020026b200441086a28020022044f0d0020052002200410ab86808000200528020821020b200528020420026a2001200410848e8080001a200220046a21020b200520023602080b02400240024002400240200328020022022003280204220b470d0041002106410021030c010b2003280210210c20032802082104200328020c220841046a210d2005410c6a41086a21092005410c6a410172210e41002106200541c0006a410172220f411f6a2110200f41186a2111200f41106a21124101210102400240034020022d00002103200241023a000020034103460d0241002107024020034102460d00200f20022900013700002010200241206a2800003600002011200241196a2900003700002012200241116a290000370000200f41086a200241096a29000037000020082802042113200828020821142005200828020036023c20052014200828022c2215201541284b22151b36023820052013200d20151b360234200520043a0069200541013a0068200520033a0040200c41046a28020021032005200541346a3602642005410c6a200c2802002003200541c0006a200541346a4101200410db8580800020052d000c22034103460d022005280210211302400240024020030e03000103010b200541203602342005200541346a360240200541c0006a200510c08a80800002402005280200200528020822076b411f4b0d0020052007412010b182808000200528020821070b200528020420076a220320092900003700072003200e2f00003b0000200341026a200e41026a2d00003a0000200320133600032003410f6a200941086a290000370000200341176a200941106a2900003700002003411f6a200941186a2d00003a00002005200741206a3602080c010b200541c0006a41186a200941186a290000370300200541c0006a41106a200941106a290000370300200541c0006a41086a200941086a29000037030020052009290000370340201341214f0d062005201336026c2005200541ec006a360234200541346a200510c08a80800002402005280200200528020822036b20134f0d0020052003201310b182808000200528020821030b200528020420036a200541c0006a201310848e8080001a2005200320136a3602080b200121070b200441016a21042001410174210120072006722106200241246a2202200b470d000b20064180fe037141087621030c020b20064180fe037141087621030c010b20064180fe037141087621030b200a41026a2102200a417d4b0d012002200528020822044b0d022005280204200a6a220220033a0001200220063a000020002005290300370200200041086a200541086a280200360200200541f0006a2480808080000f0b2013412041a4f8c58000109581808000000b200a20024194f8c58000109681808000000b200220044194f8c58000109581808000000bbe0e01117f23808080800041f0006b22052480808080000240024002400240024002400240024020042802002206417f6a0e020200010b200241017641046a2207417f4c0d0241002d00fca3c680001a200741002802c8a3c68000118180808000002208450d03200541c0006a41086a22094100360200200520083602442005200736024020052002360210200541013b010c2005410c6a200541c0006a109887808000200541c0006a2001109a87808000200541086a2009280200360200200520052902403703000c060b200241017641046a2207417f4c0d0141002d00fca3c680001a200741002802c8a3c68000118180808000002208450d03200541c0006a41086a2209410036020020052008360244200520073602402005200236021020054181023b010c2005410c6a200541c0006a109887808000200541c0006a2001109a87808000200541086a2009280200360200200520052902403703000c050b200241017641046a2207417f4c0d0041002d00fca3c680001a200741002802c8a3c68000118180808000002208450d03200541c0006a41086a220941003602002005200836024420052007360240200541033a000c200520023602102005410c6a200541c0006a109887808000200541c0006a2001109a87808000200541086a2009280200360200200520052902403703000c040b10ae80808000000b4101200710b280808000000b4101200710b280808000000b4101200710b280808000000b2005280208220a21020240200a2005280200470d002005200a109c86808000200528020821020b200528020420026a41003a00002005200528020841016a2202360208024020022005280200470d0020052002109c86808000200528020821020b200528020420026a41003a00002005200528020841016a2202360208024002400240024020060e03000103000b200428020421012005200441086a280200220236020c20052005410c6a360240200541c0006a200510c08a80800002402005280200200528020822046b20024f0d0020052004200210ab86808000200528020821040b200528020420046a2001200210848e8080001a200420026a21020c010b200428020421010240200528020020026b200441086a28020022044f0d0020052002200410ab86808000200528020821020b200528020420026a2001200410848e8080001a200220046a21020b200520023602080b02400240024002400240200328020022022003280204220b470d0041002106410021030c010b2003280210210c20032802082104200328020c220841046a210d2005410c6a41086a21092005410c6a410172210e41002106200541c0006a410172220f411f6a2110200f41186a2111200f41106a21124101210102400240034020022d00002103200241023a000020034103460d0241002107024020034102460d00200f20022900013700002010200241206a2800003600002011200241196a2900003700002012200241116a290000370000200f41086a200241096a29000037000020082802042113200828020821142005200828020036023c20052014200828022c2215201541284b22151b36023820052013200d20151b360234200520043a0069200541013a0068200520033a00402005200541346a3602642005410c6a200c200541c0006a200541346a4101200410dc8580800020052d000c22034103460d022005280210211302400240024020030e03000103010b200541203602342005200541346a360240200541c0006a200510c08a80800002402005280200200528020822076b411f4b0d0020052007412010b182808000200528020821070b200528020420076a220320092900003700072003200e2f00003b0000200341026a200e41026a2d00003a0000200320133600032003410f6a200941086a290000370000200341176a200941106a2900003700002003411f6a200941186a2d00003a00002005200741206a3602080c010b200541c0006a41186a200941186a290000370300200541c0006a41106a200941106a290000370300200541c0006a41086a200941086a29000037030020052009290000370340201341214f0d062005201336026c2005200541ec006a360234200541346a200510c08a80800002402005280200200528020822036b20134f0d0020052003201310b182808000200528020821030b200528020420036a200541c0006a201310848e8080001a2005200320136a3602080b200121070b200441016a21042001410174210120072006722106200241246a2202200b470d000b20064180fe037141087621030c020b20064180fe037141087621030c010b20064180fe037141087621030b200a41026a2102200a417d4b0d012002200528020822044b0d022005280204200a6a220220033a0001200220063a000020002005290300370200200041086a200541086a280200360200200541f0006a2480808080000f0b2013412041a4f8c58000109581808000000b200a20024194f8c58000109681808000000b200220044194f8c58000109581808000000bbe0e01117f23808080800041f0006b22052480808080000240024002400240024002400240024020042802002206417f6a0e020200010b200241017641046a2207417f4c0d0241002d00fca3c680001a200741002802c8a3c68000118180808000002208450d03200541c0006a41086a22094100360200200520083602442005200736024020052002360210200541013b010c2005410c6a200541c0006a109887808000200541c0006a2001109a87808000200541086a2009280200360200200520052902403703000c060b200241017641046a2207417f4c0d0141002d00fca3c680001a200741002802c8a3c68000118180808000002208450d03200541c0006a41086a2209410036020020052008360244200520073602402005200236021020054181023b010c2005410c6a200541c0006a109887808000200541c0006a2001109a87808000200541086a2009280200360200200520052902403703000c050b200241017641046a2207417f4c0d0041002d00fca3c680001a200741002802c8a3c68000118180808000002208450d03200541c0006a41086a220941003602002005200836024420052007360240200541033a000c200520023602102005410c6a200541c0006a109887808000200541c0006a2001109a87808000200541086a2009280200360200200520052902403703000c040b10ae80808000000b4101200710b280808000000b4101200710b280808000000b4101200710b280808000000b2005280208220a21020240200a2005280200470d002005200a109c86808000200528020821020b200528020420026a41003a00002005200528020841016a2202360208024020022005280200470d0020052002109c86808000200528020821020b200528020420026a41003a00002005200528020841016a2202360208024002400240024020060e03000103000b200428020421012005200441086a280200220236020c20052005410c6a360240200541c0006a200510c08a80800002402005280200200528020822046b20024f0d0020052004200210ab86808000200528020821040b200528020420046a2001200210848e8080001a200420026a21020c010b200428020421010240200528020020026b200441086a28020022044f0d0020052002200410ab86808000200528020821020b200528020420026a2001200410848e8080001a200220046a21020b200520023602080b02400240024002400240200328020022022003280204220b470d0041002106410021030c010b2003280210210c20032802082104200328020c220841046a210d2005410c6a41086a21092005410c6a410172210e41002106200541c0006a410172220f411f6a2110200f41186a2111200f41106a21124101210102400240034020022d00002103200241023a000020034103460d0241002107024020034102460d00200f20022900013700002010200241206a2800003600002011200241196a2900003700002012200241116a290000370000200f41086a200241096a29000037000020082802042113200828020821142005200828020036023c20052014200828022c2215201541284b22151b36023820052013200d20151b360234200520043a0069200541013a0068200520033a00402005200541346a3602642005410c6a200c200541c0006a200541346a4101200410da8580800020052d000c22034103460d022005280210211302400240024020030e03000103010b200541203602342005200541346a360240200541c0006a200510c08a80800002402005280200200528020822076b411f4b0d0020052007412010b182808000200528020821070b200528020420076a220320092900003700072003200e2f00003b0000200341026a200e41026a2d00003a0000200320133600032003410f6a200941086a290000370000200341176a200941106a2900003700002003411f6a200941186a2d00003a00002005200741206a3602080c010b200541c0006a41186a200941186a290000370300200541c0006a41106a200941106a290000370300200541c0006a41086a200941086a29000037030020052009290000370340201341214f0d062005201336026c2005200541ec006a360234200541346a200510c08a80800002402005280200200528020822036b20134f0d0020052003201310b182808000200528020821030b200528020420036a200541c0006a201310848e8080001a2005200320136a3602080b200121070b200441016a21042001410174210120072006722106200241246a2202200b470d000b20064180fe037141087621030c020b20064180fe037141087621030c010b20064180fe037141087621030b200a41026a2102200a417d4b0d012002200528020822044b0d022005280204200a6a220220033a0001200220063a000020002005290300370200200041086a200541086a280200360200200541f0006a2480808080000f0b2013412041a4f8c58000109581808000000b200a20024194f8c58000109681808000000b200220044194f8c58000109581808000000bc30402047f017e23808080800041206b2204248080808000200241017641046a21050240024002400240024020032802000d002005417f4c0d0241002d00fca3c680001a200541002802c8a3c68000118180808000002206450d03200441146a41086a220741003602002004200636021820042005360214200441023a0000200420023602042004200441146a109887808000200441146a2001109a87808000200441086a2202200728020036020020042004290214370300200328020421012004200328020822053602102004200441106a360214200441146a200410c08a80800002402004280200200228020022036b20054f0d0020042003200510ab86808000200428020821030b200428020420036a2001200510848e8080001a2004200320056a3602080c010b2005417f4c0d0141002d00fca3c680001a200541002802c8a3c68000118180808000002206450d03200441146a41086a220741003602002004200636021820042005360214200441043a0000200420023602042004200441146a109887808000200441146a2001109a87808000200441086a200728020022053602002004200429021422083703002003280204210202402008a720056b200328020822034f0d0020042005200310ab86808000200428020821050b200428020420056a2002200310848e8080001a2004200520036a3602080b20002004290300370200200041086a200441086a280200360200200441206a2480808080000f0b10ae80808000000b4101200510b280808000000b4101200510b280808000000b930302037f017e23808080800041d0006b22022480808080002002200136020002404100280284a4c680004105470d002002419882808000360208200220023602044100280290a1c680002101410028028ca1c6800021034100280280a4c680002104200241c4006a42013702002002413c6a4101360200200241346a4115360200200241306a41dffbc58000360200200241246a41ecfac58000ad4280808080b00e84370200200241186a41f4fbc58000ad4280808080d00584370200200241c0006a200241046a360200200241e4fac580003602382002410536022c200241003602202002410036021420024281808080c01e37020c200341ecf2c08000200441024622041b2002410c6a200141d4f2c0800020041b28021011848080800000200228020021010b4101210342002105024002400240200128020041786a0e020001020b200129030821050c010b41002103420021050b200020033a0028200042043703202000420037031820004280808080c0003703102000427f37030820002005370300200241d0006a2480808080000be70201047f23808080800041c0006b2202248080808000200241186a41086a200141086a290200370300200220012902003703182002200241186a109e8780800020022802042101024002400240200228020822030d0002402002280200450d00200141002802c0a3c68000118080808000000b41002101410021040c010b20022002413f6a36021820012003200241186a10da8b8080002002280200210541002d00fca3c680001a41e40141002802c8a3c68000118180808000002204450d01200441003b01e20120044100360258200241003602102002200436020c2002410036021420022001200341146c6a36023820022005360234200220013602302002200136022c20024181808080783602202002410c6a200241186a200241146a10c18580800020002002280210360204200228020c2101200228021421040b2000200436020820002001360200200241c0006a2480808080000f0b410441e40110b280808000000ba90501077f024020002802002201450d00200028020421020240024020002802082203450d00410021000340024002402000450d002001210420022105200021010c010b4100210402402002450d0020022100024020024107712205450d0003402000417f6a210020012802e40121012005417f6a22050d000b0b20024108490d00034020012802e4012802e4012802e4012802e4012802e4012802e4012802e4012802e4012101200041786a22000d000b0b410021050b024002400240200520012f01e201490d00034020012802582200450d0220012f01e0012105200141002802c0a3c6800011808080800000200441016a210420002101200520002f01e2014f0d000b200021010b200541016a2102024020040d00200121000c020b200120024102746a41e4016a2802002100410021022004417f6a2206450d012004417e6a2107024020064107712204450d0003402006417f6a210620002802e40121002004417f6a22040d000b0b20074107490d01034020002802e4012802e4012802e4012802e4012802e4012802e4012802e4012802e4012100200641786a22060d000c020b0b200141002802c0a3c6800011808080800000418cd0c2800010a081808000000b024020012005410c6c6a41dc006a2201280200450d00200128020441002802c0a3c68000118080808000000b410021012003417f6a22030d000c020b0b024020020d00200121000c010b02400240200241077122050d0020012100200221010c010b200121002002210103402001417f6a210120002802e40121002005417f6a22050d000b0b20024108490d00034020002802e4012802e4012802e4012802e4012802e4012802e4012802e4012802e4012100200141786a22010d000b0b034020002802582101200041002802c0a3c68000118080808000002001210020010d000b0b0bcd0501097f23808080800041106b22022480808080002002200028020822033602082002200241086a36020c2002410c6a200110c08a808000024002402003450d0020002802002204450d0041002105200441004721062000280204210703400240024002402006450d002005450d010b20060d0141f887c6800010a081808000000b410121062004210502402007450d0020072100024020074107712204450d0003402000417f6a210020052802e40121052004417f6a22040d000b0b20074108490d00034020052802e4012802e4012802e4012802e4012802e4012802e4012802e4012802e4012105200041786a22000d000b0b41002104410021070b0240200720052f01e201490d00034020052802582200450d04200441016a210420052f01e001210720002105200720002f01e2014f0d000b0b200741016a21080240024020040d00200521000c010b200520084102746a41e4016a2802002100410021082004417f6a2209450d002004417e6a210a024020094107712204450d0003402009417f6a210920002802e40121002004417f6a22040d000b0b200a4107490d00034020002802e4012802e4012802e4012802e4012802e4012802e4012802e4012802e4012100200941786a22090d000b0b200520074103746a210420052007410c6c6a41dc006a210702402001280200200128020822056b41074b0d0020012005410810b182808000200128020821050b200128020420056a20042900003700002001200541086a360208200728020421042002200728020822053602082002200241086a36020c2002410c6a200110c08a80800002402001280200200128020822076b20054f0d0020012007200510b182808000200128020821070b200128020420076a2004200510848e8080001a2001200720056a3602084100210420082107200021052003417f6a22030d000b0b200241106a2480808080000f0b41e887c6800010a081808000000b0a00200010d68c8080000b850b04067f017e027f017e23808080800041d0006b2201248080808000200141286a419bfdc58000410641aafdc58000411b41fcfcc58000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041c00041002802c8a3c68000118180808000002202450d00200242a5e9e3ab9e929adc2c370308200241cbfdc58000360220200241ef8080800036021820024106360204200241c5fdc58000360200200241106a4293888c8f89fdc6ec9e7f370300200241386a4100360200200241246a410436020020014102360248200120023602402001200241c0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a2001411c6a220241086a2802003602002001200229020037030020012802102103200128021421042001280218210520012802282106200129022c2107200141106a41086a22084100360200200142808080808001370210200141106a410010a4868080002001280214200828020041386c6a2202420437022c2002420c370224200241dad9c480003602202002410b36021c200241e6d9c48000360218200241f581808000360210200242ab8bffbed784ffa5937f370308200242c194a6a793ccc3a857370300200141c0006a41086a2209200828020041016a220236020020012001290210220a37034002402002200aa7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c2002420637022420024186dac480003602202002410636021c20024180dac48000360218200241bc82808000360210200242899ac8f29d8ce69ac300370308200242e78dcee4d0becc97573703002008200928020041016a220236020020012001290340220a37031002402002200aa7470d00200141106a200210a486808000200128021821020b2001280214200241386c6a2202420437022c2002420c370224200241dad9c480003602202002410a36021c200241d0d9c48000360218200241f581808000360210200242ab8bffbed784ffa5937f370308200242c194a6a793ccc3a857370300200141c0006a41086a2208200141106a41086a220928020041016a220236020020012001290310220a37034002402002200aa7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c2002420c370224200241dad9c480003602202002410f36021c200241f1d9c48000360218200241f581808000360210200242ab8bffbed784ffa5937f370308200242c194a6a793ccc3a8573703002009200828020041016a220236020020012001290340220a37031002402002200aa7470d00200141106a200210a486808000200128021821020b2001280214200241386c6a2202420437022c2002420637022420024192dac480003602202002410636021c2002418cdac48000360218200241ca8280800036021020024296b787c192cbb889d000370308200242fddcc0b9c5fc86d6a17f370300200128021821082001280214210220012001280210360248200120023602402001200236024420012002200841386c6a41386a36024c200141346a200141c0006a10f9868080002006418080808078460d012001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002006360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841c00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000b0a00200010f1878080000b0a00200010d98c8080000b8f0a04067f017e027f017e23808080800041d0006b2201248080808000200141286a41b087c68000411141c187c68000411241fcfcc58000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041c00041002802c8a3c68000118180808000002202450d00200242f68d80b7cfa6d3bb4e370308200241d387c680003602202002418083808000360218200241063602042002419bfdc58000360200200241306a42e9b494c69bdbc4d608370300200241286a42ead283debcdebd93d800370300200241106a42dc8ec6fd9fd6fcdeb77f370300200241386a41f780808000360200200241246a410236020020014102360248200120023602402001200241c0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a2001411c6a220241086a2802003602002001200229020037030020012802102103200128021421042001280218210520012802282106200129022c2107200141106a41086a22084100360200200142808080808001370210200141106a410010a4868080002001280214200828020041386c6a2202420437022c20024202370224200241d0fbc480003602202002410836021c200241c7a4c58000360218200241f780808000360210200242e9b494c69bdbc4d608370308200242ead283debcdebd93d800370300200141c0006a41086a2209200828020041016a220236020020012001290210220a37034002402002200aa7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c20024204370224200241dfa4c580003602202002410436021c200241dba4c58000360218200241f580808000360210200242b8b6d386cdcbfab1a07f370308200242e3a4fae3cee3d18d723703002008200928020041016a220236020020012001290340220a37031002402002200aa7470d00200141106a200210a486808000200128021821020b2001280214200241386c6a2202420437022c20024206370224200241b2d9c480003602202002410c36021c200241cfa4c580003602182002418083808000360210200242dc8ec6fd9fd6fcdeb77f370308200242f68d80b7cfa6d3bb4e370300200141c0006a41086a200141106a41086a28020041016a220236020020012001290310220a37034002402002200aa7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c20024206370224200241b2d9c480003602202002410d36021c200241e3a4c580003602182002418083808000360210200242dc8ec6fd9fd6fcdeb77f370308200242f68d80b7cfa6d3bb4e370300200128024821082001280244210220012001280240360248200120023602402001200236024420012002200841386c6a41386a36024c200141346a200141c0006a10f9868080002006418080808078460d012001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002006360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841c00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000bcd0704067f017e017f017e23808080800041d0006b2201248080808000200141286a41fcfcc5800041054181fdc58000411a41fcfcc58000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041c00041002802c8a3c68000118180808000002202450d00200242f68d80b7cfa6d3bb4e370308200241a1fdc580003602202002418083808000360218200241063602042002419bfdc58000360200200241306a42dda1fc828d83b3faab7f370300200241286a42b7a18ef9ac95b6cbeb00370300200241106a42dc8ec6fd9fd6fcdeb77f370300200241386a41ec81808000360200200241246a410936020020014102360248200120023602402001200241c0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a2001411c6a220241086a2802003602002001200229020037030020012802102103200128021421042001280218210520012802282106200129022c2107200141106a41086a22084100360200200142808080808001370210200141106a410010a4868080002001280214200828020041386c6a2202420437022c20024206370224200241b2d9c480003602202002410636021c200241acd9c480003602182002418083808000360210200242dc8ec6fd9fd6fcdeb77f370308200242f68d80b7cfa6d3bb4e370300200141c0006a41086a200828020041016a2202360200200120012902102209370340024020022009a7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c2002420e370224200241c2d9c480003602202002410a36021c200241b8d9c48000360218200241ff828080003602102002429acfecb0d2a8f28be7003703082002428bdb9ef4d7aab8cbec00370300200128024821082001280244210220012001280240360248200120023602402001200236024420012002200841386c6a41386a36024c200141346a200141c0006a10f9868080002006418080808078460d012001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002006360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841c00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000ba60703067f017e027f23808080800041d0006b2201248080808000200141286a41c0ffc58000411241d2ffc58000412810d682808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041800141002802c8a3c68000118180808000002202450d00200242c4ccab9c81ebb4b8db003703082002418e80c680003602602002418580c680003602402002418180c68000360220200241f08180800036021820024107360204200241faffc58000360200200241f0006a4283af8bf0ede78391a67f370300200241e8006a42dba4b9c0a2bed19501370300200241d0006a42f0a3fcacaeba9c956f370300200241c8006a42e3beec81d3e996af917f370300200241306a42fec1aad493d7e4ae3e370300200241286a42dbe2e9e8becbf3fb2f370300200241106a42a4d2928ecac0faa432370300200241f8006a419b83808000360200200241e4006a4105360200200241d8006a418583808000360200200241c4006a4109360200200241386a419a83808000360200200241246a41043602002001410436024820012002360240200120024180016a36024c20012002360244200141106a200141c0006a10fa86808000200141086a22032001411c6a220241086a28020036020020012002290200370300200128021021042001280214210520012802182106200129022c21072001280228210820014100360218200142808080808001370210200141106a410010a4868080002001280214200128021841386c6a2202410036023020024280808080c0003703282002410036022020024100360218200241ea81808000360210200242b891b68c98adebcf61370308200242e7b0a091f3ed9c85c500370300200128021821092001280214210220012001280210360248200120023602402001200236024420012002200941386c6a41386a36024c200141346a200141c0006a10f9868080002008418080808078460d012001200436021820012005360210200120053602142001200520064105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002008360238200041003a000020002001290300370350200041d8006a20032802003602002001200129023437001320002001290010370001200041086a200141106a41076a290000370000200141d0006a2480808080000f0b410841800110b280808000000b41a8d8c480004111419cd9c4800010a181808000000be40502037f027e2380808080004180016b2202248080808000024002400240024002402001280200220328020422044120490d002003200441606a36020420032003280200220441206a360200200241106a41086a200441086a290000370300200241106a41106a200441106a290000370300200241106a41186a200441186a290000370300200220042900003703102002200110be8a8080002002290300a70d012001280200220328020422044120490d02200229030821052003200441606a36020420032003280200220441206a360200200241306a41086a200441086a290000370300200241306a41106a200441106a290000370300200241306a41186a200441186a290000370300200220042900003703302001280200220328020422044120490d032003200441606a36020420032003280200220441206a360200200241d0006a41086a200441086a290000370300200241d0006a41106a200441106a290000370300200241d0006a41186a200441186a29000037030020022004290000370350200241f4006a2001109487808000024020022802742201418080808078460d00200229027821062000200229031037000020002002290330370028200041186a200241106a41186a290300370000200041106a200241106a41106a290300370000200041086a200241106a41086a290300370000200041306a200241306a41086a290300370000200041386a200241306a41106a290300370000200041c0006a200241306a41186a29030037000020002002290350370048200041d0006a200241d0006a41086a290300370000200041d8006a200241d0006a41106a290300370000200041e0006a200241d0006a41186a2903003700002000200637026c20002001360268200020053703200c050b20004180808080783602680c040b20004180808080783602680c030b20004180808080783602680c020b20004180808080783602680c010b20004180808080783602680b20024180016a2480808080000bde0601077f23808080800041106b220224808080800041002d00fca3c680001a024002400240412041002802c8a3c68000118180808000002203450d0020032000290000370000200341186a2204200041186a290000370000200341106a2205200041106a290000370000200341086a2206200041086a29000037000002402001280200200128020822076b411f4b0d0020012007412010b182808000200128020821070b200128020420076a22082003290000370000200841086a2006290000370000200841106a2005290000370000200841186a20042900003700002001200741206a360208200341002802c0a3c68000118080808000002002200041206a360204200241046a200110c18a80800041002d00fca3c680001a412041002802c8a3c68000118180808000002203450d0120032000290028370000200341186a2204200041c0006a290000370000200341106a2205200041386a290000370000200341086a2206200041306a29000037000002402001280200200128020822076b411f4b0d0020012007412010b182808000200128020821070b200128020420076a22082003290000370000200841086a2006290000370000200841106a2005290000370000200841186a20042900003700002001200741206a360208200341002802c0a3c680001180808080000041002d00fca3c680001a412041002802c8a3c68000118180808000002203450d0220032000290048370000200341186a2204200041e0006a290000370000200341106a2205200041d8006a290000370000200341086a2206200041d0006a29000037000002402001280200200128020822076b411f4b0d0020012007412010b182808000200128020821070b200128020420076a22082003290000370000200841086a2006290000370000200841106a2005290000370000200841186a20042900003700002001200741206a360208200341002802c0a3c6800011808080800000200041ec006a28020021032002200041f0006a28020022003602082002200241086a36020c2002410c6a200110c08a80800002402000450d00200041146c210003402003200110de8c808000200341146a21032000416c6a22000d000b0b200241106a2480808080000f0b4101412010b280808000000b4101412010b280808000000b4101412010b280808000000b9b0201037f23808080800041206b22022480808080000240024002400240024020002d000022030e050001020304000b2002200041016a36021420022000410c6a2902003702180c030b2002200041016a36021420022000410c6a2902003702180c020b2002200041016a36021420022000410c6a2902003702180c010b2002200041086a2902003702140b20022003360210200241046a200241106a10ed848080002002280208210402402001280200200128020822006b200228020c22034f0d0020012000200310b182808000200128020821000b200128020420006a2004200310848e8080001a2001200020036a36020802402002280204450d00200441002802c0a3c68000118080808000000b200241206a2480808080000be707010e7f23808080800041206b2204248080808000200441086a200110bd8a80800002400240024020042802080d0020012802042205200428020c2206490d000240024002400240024002400240024002400240024020060d00410121070c010b2006417f4c0d01200641002802c8a3c68000118180808000002207450d02200741002006108a8e8080001a0b200720012802002208200610848e80800021072001200520066b3602042001200820066a3602002004200110bd8a80800020042802000d072001280204220820042802042205490d070240024020050d00410121090c010b2005417f4c0d01200541002802c8a3c68000118180808000002209450d0c200941002005108a8e8080001a0b20092001280200220a200510848e808000210b2001200820056b22083602042001200a20056a220936020020084104490d0520012008417c6a220a3602042001200941046a360200200a4104490d042009280000210c2001200841786a220a3602042001200941086a360200200a4104490d032009280004210d2001200841746a36020420012009410c6a3602002009280008210e200441146a20011093878080002004280214220a418080808078460d02200428021c210f200428021821104101211102400240024020024101460d00200f410c6c21032010417c6a21020340024020030d0041002102410121110c030b200341746a2103200241046a21082002410c6a22092102200829020042dfd5adc696f381b09b7f520d000b200928020021030b024020034103490d00200128020422024104490d0220012002417c6a36020420012001280200220241046a360200200228000021110b4100210220034104490d0020012802042203450d0120012003417f6a36020420012001280200220341016a36020020032d000021020b200020023a0034200020113602302000200e36022c2000200d3602282000200c3602242000200f3602202000201036021c2000200a360218200020053602142000200b3602102000200536020c2000200636020820002007360204200020063602000c0b0b2000418180808078360200200a41808080807872418080808078460d06201041002802c0a3c68000118080808000000c060b10ae80808000000b4101200610b280808000000b20004181808080783602000c030b20004181808080783602000c020b20004181808080783602000c010b20004181808080783602000b2005450d01200b41002802c0a3c68000118080808000000c010b20004181808080783602000b2006450d01200741002802c0a3c68000118080808000000c010b20004181808080783602000b200441206a2480808080000f0b4101200510b280808000000bbb0401077f0240024002400240200128022022020d00410021020c010b20012002417f6a3602202001280204210202400240024020012802002203450d002002450d010b2003450d032001410c6a2802002104200141086a28020021050c010b200141086a280200210202402001410c6a2802002205450d0002400240200541077122040d00200521030c010b2005210303402003417f6a210320022802ac1421022004417f6a22040d000b0b20054108490d00034020022802ac142802ac142802ac142802ac142802ac142802ac142802ac142802ac142102200341786a22030d000b0b20014200370208200120023602042001410136020041002104410021050b02400240200420022f01aa144f0d00200221030c010b034020022802a0132203450d04200541016a210520022f01a814210420032102200420032f01aa144f0d000b0b200441016a21060240024020050d00200321020c010b200320064102746a41ac146a2802002102410021062005417f6a2207450d002005417e6a2108024020074107712205450d0003402007417f6a210720022802ac1421022005417f6a22050d000b0b20084107490d00034020022802ac142802ac142802ac142802ac142802ac142802ac142802ac142802ac142102200741786a22070d000b0b2001200636020c20014100360208200120023602042003200441e0016c6a210520032004410c6c6a41a4136a21020b20002005360204200020023602000f0b41d4fec5800010a081808000000b419cd0c2800010a081808000000bc10601077f0240200128022022020d00200128020021022001410036020002402002450d000240200128020422020d0020012802082102200128020c2203450d0002400240200341077122040d00200321050c010b2003210503402005417f6a210520022802900221022004417f6a22040d000b0b20034108490d000340200228029002280290022802900228029002280290022802900228029002280290022102200541786a22050d000b0b034020022802002105200241002802c0a3c68000118080808000002005210220050d000b0b20004180808080783602000f0b20012002417f6a360220200128020421020240024002400240024020012802002205450d002002450d010b2005450d022001410c6a2802002104200141086a28020021030c010b200141086a280200210202402001410c6a2802002203450d0002400240200341077122040d00200321050c010b2003210503402005417f6a210520022802900221022004417f6a22040d000b0b20034108490d000340200228029002280290022802900228029002280290022802900228029002280290022102200541786a22050d000b0b20014200370208200120023602042001410136020041002104410021030b0240200420022f018e024f0d00200221050c020b0240034020022802002205450d0120022f018c022104200241002802c0a3c6800011808080800000200341016a210320052102200420052f018e02490d030c000b0b200241002802c0a3c6800011808080800000418cd0c2800010a081808000000b41d887c6800010a081808000000b200441016a21060240024020030d00200521020c010b200520064102746a4190026a2802002102410021062003417f6a2207450d002003417e6a2108024020074107712203450d0003402007417f6a210720022802900221022003417f6a22030d000b0b20084107490d000340200228029002280290022802900228029002280290022802900228029002280290022102200741786a22070d000b0b2001200636020c2001410036020820012002360204200020052004410c6c6a220241046a290200370200200041086a2002410c6a280200360200200020024188016a29020037020c200041146a20024190016a2802003602000b900601077f0240200128022022020d00200128020021022001410036020002402002450d000240200128020422020d0020012802082102200128020c2203450d0002400240200341077122040d00200321050c010b2003210503402005417f6a210520022802f80621022004417f6a22040d000b0b20034108490d00034020022802f8062802f8062802f8062802f8062802f8062802f8062802f8062802f8062102200541786a22050d000b0b034020022802f0062105200241002802c0a3c68000118080808000002005210220050d000b0b200041023a004c0f0b20012002417f6a360220200128020421020240024002400240024020012802002205450d002002450d010b2005450d022001410c6a2802002104200141086a28020021030c010b200141086a280200210202402001410c6a2802002203450d0002400240200341077122040d00200321050c010b2003210503402005417f6a210520022802f80621022004417f6a22040d000b0b20034108490d00034020022802f8062802f8062802f8062802f8062802f8062802f8062802f8062802f8062102200541786a22050d000b0b20014200370208200120023602042001410136020041002104410021030b0240200420022f01f6064f0d00200221050c020b0240034020022802f0062205450d0120022f01f4062104200241002802c0a3c6800011808080800000200341016a210320052102200420052f01f606490d030c000b0b200241002802c0a3c6800011808080800000418cd0c2800010a081808000000b41d887c6800010a081808000000b200441016a21060240024020030d00200521020c010b200520064102746a41f8066a2802002102410021062003417f6a2207450d002003417e6a2108024020074107712203450d0003402007417f6a210720022802f80621022003417f6a22030d000b0b20084107490d00034020022802f8062802f8062802f8062802f8062802f8062802f8062802f8062802f8062102200741786a22070d000b0b2001200636020c200141003602082001200236020420002005200441d0006c6a41d00010848e8080001a0bb40101017f23808080800041206b2204248080808000200441086a20012802042002200310e48c8080000240024002402004280208418080808078470d00200441146a2001280200200210e58c8080002004280214418180808078460d0120002004290214370200200041086a200441146a41086a2802003602000c020b20002004290208370200200041086a200441086a41086a2802003602000c010b20004180808080783602000b200441206a2480808080000bd807010a7f23808080800041106b220424808080800002400240024002400240024002400240024002402002200141186a412010888e808000450d00200328020021050240024002402003280204220641216a22070d0020044201370208200420073602040c010b2007417f4c0d084100210841002d00fca3c680001a200741002802c8a3c68000118180808000002209450d092004410036020c20042009360208200420073602042006415f490d010b200441046a4100200610ab868080002004280204210720042802082109200428020c21080b200920086a2005200610848e8080001a2004200820066a220636020c024020032d0008450d00200341096a2d00002103024020062007470d00200441046a2007109c8680800020042802082109200428020c21060b200920066a20033a00002004200428020c41016a220636020c200428020421070b0240200720066b411f4b0d00200441046a2006412010ab8680800020042802042107200428020c21060b2004280208220a20066a22032002290000370000200341086a200241086a290000370000200341106a200241106a290000370000200341186a200241186a290000370000200128020c220b450d02200641206a2106200141106a280200210c0340200b41746a2108200b41b4016a2102200b2f01ba02220d410c6c2101417f210902400340024020010d00200d21090c020b200241086a2103200241046a2105200141746a2101200841106a2108200941016a21092002410c6a2102417f200a200528020020062003280200220320062003491b10888e8080002205200620036b20051b220341004720034100481b22034101460d000b200341ff0171450d030b200c450d03200c417f6a210c200b20094102746a41bc026a280200210b0c000b0b2001280204210602400240200128020822020d00410121010c010b2002417f4c0d0641002d00fca3c680001a200241002802c8a3c68000118180808000002201450d080b20012006200210848e80800021012000200236020820002001360204200020023602000c040b200841086a28020041004a0d010b20004180808080783602000c010b2008280200210102400240200841046a28020022020d00410121060c010b2002417f4c0d0341002d00fca3c680001a200241002802c8a3c68000118180808000002206450d060b20062001200210848e80800021012000200236020820002001360204200020023602000b2007450d00200a41002802c0a3c68000118080808000000b200441106a2480808080000f0b10ae80808000000b4101200710b280808000000b4101200210b280808000000b4101200210b280808000000bd70301087f0240024002400240024002402002200141186a412010888e808000450d0041808080807821030240200128020c22040d000c030b200141106a28020021050340200441dc026a210620042f01960422074105742101417f21082004210902400340024020010d00200721080c020b20022009412010888e808000210a200141606a2101200641106a2106200841016a2108200941206a2109417f200a410047200a4100481b220a4101460d000b200a41ff0171450d030b024020050d000c040b2005417f6a2105200420084102746a4198046a28020021040c000b0b200128020421090240200128020822030d004101210141012009200310848e8080001a0c020b2003417f4c0d0241002d00fca3c680001a200341002802c8a3c68000118180808000002201450d0320012009200310848e8080001a0c010b410121010240200628020041014e0d000c010b200641786a280200210902402006417c6a2802002203450d002003417f4c0d0241002d00fca3c680001a200341002802c8a3c68000118180808000002201450d040b20012009200310848e8080001a0b2000200336020820002001360204200020033602000f0b10ae80808000000b4101200310b280808000000b4101200310b280808000000b15002000200128020420022003200410e78c8080000bec0301037f23808080800041306b220524808080800002400240024002400240024002402004450d002004417f4c0d0241002d00fca3c680001a200441002802c8a3c68000118180808000002206450d0320062003200410848e80800021060240024020012802082004460d00200641002802c0a3c68000118080808000000c010b20062001280204200410888e8080002107200641002802c0a3c68000118080808000002007450d020b200541046a200320044100280298a3c680001185808080000041002d00fca3c680001a200441002802c8a3c680001181808080000022060d054101200410b280808000000b20012802080d030b20002001290018370000200041186a200141306a290000370000200041106a200141286a290000370000200041086a200141206a2900003700000c040b10ae80808000000b4101200410b280808000000b200541046a200341004100280298a3c6800011858080800000410121060b20062003200410848e80800021032005200436022c20052003360228200520043602242001200541046a2002200541246a10eb8c808000200041186a200541046a41186a290000370000200041106a200541046a41106a290000370000200041086a200541046a41086a290000370000200020052900043700000b200541306a2480808080000b110020002802042001200210e98c8080000b890904087f017e027f017e23808080800041e0006b220324808080800002402001200041186a412010888e808000450d002002280200210402400240024002400240024002402002280204220541216a22060d002003420137022c200320063602280c010b2006417f4c0d024100210741002d00fca3c680001a200641002802c8a3c68000118180808000002208450d03200341003602302003200836022c200320063602282005415f490d010b200341286a4100200510ab8680800020032802282106200328022c2108200328023021070b200820076a2004200510848e8080001a2003200720056a2205360230024020022d0008450d00200241096a2d00002102024020052006470d00200341286a2006109c86808000200328022c2108200328023021050b200820056a20023a00002003200328023041016a2205360230200328022821060b0240200620056b411f4b0d00200341286a2005412010ab8680800020032802282106200328023021050b200328022c220920056a22022001290000370000200241086a200141086a290000370000200241106a200141106a290000370000200241186a200141186a290000370000200541206a210202400240200028020c220a0d002002ad4220862009ad84210b4100210a0c010b200041106a280200210c02400340200a41b4016a2101200a2f01ba02220d410c6c2105417f2107024002400340024020050d00200d21070c020b200141086a2108200141046a2104200541746a2105200741016a21072001410c6a2101417f2009200428020020022008280200220820022008491b10888e8080002204200220086b20041b220841004720084100481b22084101460d000b200841ff0171450d010b200c450d02200c417f6a210c200a20074102746a41bc026a280200210a0c010b0b2003200c36022c2003200a3602282003290328210b2006450d05200941002802c0a3c68000118080808000000c050b200320073602302003410036022c2002ad4220862009ad84210b200329022c210e0b2000410c6a21072006418080808078460d032003200e3702202003200a36021c200320073602182003200b3702102003200636020c200342808080807037023020034280808080103702280240200a0d0041002d00fca3c680001a41bc0241002802c8a3c68000118180808000002201450d03200141013b01ba02200141003602b0012001200329020c3702b4012003410c6a41086a280200210520012003290228370200200141086a200341286a41086a290200370200200141bc016a2005360200200041106a4280808080103702002000200136020c0c050b200341386a41086a2003411c6a220141086a28020036020020032001290200370338200341d0006a41086a2003410c6a41086a2802003602002003200329020c370350200341c4006a200341386a200341d0006a200341286a200341186a10c08580800020032802182201200128020841016a3602080c040b10ae80808000000b4101200610b280808000000b410441bc0210b280808000000b200ba720074104746a2201200128020c417f6a36020c0b200341e0006a2480808080000b1300200028020420012002200310eb8c8080000bc20a04097f017e027f017e23808080800041e0006b22042480808080002003280204210502400240024002400240024002400240200328020822062000280208470d0020052000280204200610888e808000450d010b200228020021070240024002402002280204220641216a22080d002004420137022c200420083602280c010b2008417f4c0d044100210941002d00fca3c680001a200841002802c8a3c6800011818080800000220a450d05200441003602302004200a36022c200420083602282006415f490d010b200441286a4100200610ab8680800020042802282108200428022c210a200428023021090b200a20096a2007200610848e8080001a2004200920066a2206360230024020022d0008450d00200241096a2d00002102024020062008470d00200441286a2008109c86808000200428022c210a200428023021060b200a20066a20023a00002004200428023041016a2206360230200428022821080b0240200820066b411f4b0d00200441286a2006412010ab8680800020042802282108200428023021060b200428022c220b20066a22022001290000370000200241086a200141086a290000370000200241106a200141106a290000370000200241186a200141186a290000370000200641206a210202400240200028020c220c0d002002ad422086200bad84210d4100210c0c010b200041106a280200210e02400340200c41b4016a2106200c2f01ba02220f410c6c2101417f2109024002400340024020010d00200f21090c020b200641086a210a200641046a2107200141746a2101200941016a21092006410c6a2106417f200b20072802002002200a280200220a2002200a491b10888e80800022072002200a6b20071b220a410047200a4100481b220a4101460d000b200a41ff0171450d010b200e450d02200e417f6a210e200c20094102746a41bc026a280200210c0c010b0b2004200e36022c2004200c3602282004290328210d2008450d07200b41002802c0a3c68000118080808000000c070b200420093602302004410036022c2002ad422086200bad84210d200429022c21100b2000410c6a21092008418080808078460d05200420103702202004200c36021c200420093602182004200d3702102004200836020c200441286a41086a200341086a2802003602002004410136023420042003290200370328200c0d0141002d00fca3c680001a41bc0241002802c8a3c68000118180808000002206450d04200641013b01ba02200641003602b0012006200429020c3702b4012004410c6a41086a280200210120062004290328370200200641086a200441286a41086a290300370200200641bc016a2001360200200041106a4280808080103702002000200636020c0c060b2003280200450d05200541002802c0a3c68000118080808000000c050b200441386a41086a2004411c6a220641086a28020036020020042006290200370338200441d0006a41086a2004410c6a41086a2802003602002004200429020c370350200441c4006a200441386a200441d0006a200441286a200441186a10c08580800020042802182206200628020841016a3602080c040b10ae80808000000b4101200810b280808000000b410441bc0210b280808000000b0240200da720094104746a220628020c220141004a0d0002402006280200450d00200628020441002802c0a3c6800011808080800000200628020c21010b200620032902003702002006200141016a36020c200641086a200341086a2802003602000c010b2006200141016a36020c2003280200450d00200541002802c0a3c68000118080808000000b200441e0006a2480808080000bcb0101017f23808080800041206b2203248080808000200341086a20002802042001200210e48c808000024002400240024020032802082202418080808078470d00200341146a2000280200200110e58c80800020032802142202418180808078470d0141808080807821000c030b200328020c21000c010b41808080807821002002418080808078460d01200328021821000b024020020d00410021000c010b200041002802c0a3c6800011808080800000200221000b200341206a2480808080002000418080808078470bbf0101027f23808080800041306b2202248080808000410021030240200041c0016a2d00004102460d002002200041b8016a36022c20004198016a21030b200241186a410c6a4184848080003602002002410c6a420237020020022000360220200241858480800036021c2002200336022820024103360204200241fcfec58000360200200141186a28020021002002200241286a3602182002200241186a36020820012802142000200210d9808080002100200241306a24808080800020000bc00201027f23808080800041106b22022480808080000240024020002802000d00200128021441bcffc580004104200141186a28020028020c1182808080000021010c010b2002200036020020022001280214418888c680004104200141186a28020028020c118280808000003a000c20022001360208200241003a000d20024100360204200241046a2002418c88c68000108d81808000210120022d000c21000240200128020022030d00200041ff017141004721010c010b41012101200041ff01710d0020022802082100024020034101470d0020022d000d41ff0171450d0020002d001c4104710d00410121012000280214418ca5c080004101200041186a28020028020c118280808000000d010b2000280214418da5c080004101200041186a28020028020c1182808080000021010b200241106a24808080800020010bce0101037f23808080800041106b220224808080800020022000360208200241086a200110c18a8080002002200041086a36020c2002410c6a200110c18a80800020002d001021030240200128020020012802082204470d0020012004410110b182808000200128020821040b200128020420046a20033a00002001200441016a220436020820002d00112100024020012802002004470d0020012004410110b182808000200128020821040b2001200441016a360208200128020420046a20003a0000200241106a2480808080000b9c0804067f017e027f017e23808080800041d0006b2201248080808000200141286a4194ffc58000411041a4ffc58000411741fcfcc58000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a02400240412041002802c8a3c68000118180808000002202450d002002429b99b4f08dc8ccdea77f370308200241ae8080800036021820024101360204200241bbffc58000360200200241106a428a96cd9bb2e69e8d7237030020014101360248200120023602402001200241206a36024c20012002360244200141106a200141c0006a10fa86808000200141086a2001411c6a220241086a2802003602002001200229020037030020012802102103200128021421042001280218210520012802282106200129022c2107200141106a41086a22084100360200200142808080808001370210200141106a410010a4868080002001280214200828020041386c6a2202420437022c20024201370224200241dbfbc480003602202002410636021c200241e7fbc48000360218200241ae808080003602102002428a96cd9bb2e69e8d723703082002429b99b4f08dc8ccdea77f370300200141c0006a41086a2209200828020041016a220236020020012001290210220a37034002402002200aa7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c20024201370224200241dbfbc480003602202002410b36021c200241dcfbc48000360218200241ae808080003602102002428a96cd9bb2e69e8d723703082002429b99b4f08dc8ccdea77f3703002008200928020041016a220236020020012001290340220a37031002402002200aa7470d00200141106a200210a486808000200128021821020b2001280214200241386c6a2202420437022c20024201370224200241dbfbc480003602202002410936021c200241d2fbc48000360218200241ae808080003602102002428a96cd9bb2e69e8d723703082002429b99b4f08dc8ccdea77f370300200128021821082001280214210220012001280210360248200120023602402001200236024420012002200841386c6a41386a36024c200141346a200141c0006a10f9868080002006418080808078460d012001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002006360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b4108412010b280808000000b41a8d8c480004111419cd9c4800010a181808000000b930202017f067e23808080800041e0006b2202248080808000200241d0006a200110bf8a80800042012103024020022802500d0020022903582104200241c0006a200110bf8a8080002002290340a70d0020022903482105200241306a200110bf8a80800020022802300d0020022903382106200241206a200110bf8a8080002002290320a70d0020022903282107200241106a200110bf8a80800020022802100d00200229031821082002200110bf8a8080002002290300a70d002002290308210320002004370308200041306a2003370300200041286a2008370300200041206a2007370300200041186a2006370300200041106a2005370300420021030b20002003370300200241e0006a2480808080000ba80201017f23808080800041106b22022480808080002002200041c8006a36020c2002410c6a200110c18a8080002002200041d0006a36020c2002410c6a200110c18a8080002000200110c88c808000200041186a200110c88c808000200041306a200110c88c8080002002200041a0016a36020c2002410c6a200110c18a8080002002200041a8016a36020c2002410c6a200110c18a808000200041d8006a200110c88c808000200041f0006a200110c88c80800020004188016a200110c88c8080002002200041f8016a36020c2002410c6a200110c18a808000200220004180026a36020c2002410c6a200110c18a808000200041b0016a200110c88c808000200041c8016a200110c88c808000200041e0016a200110c88c808000200241106a2480808080000bd10101017f23808080800041106b220424808080800002400240024002402002200141d8006a412010888e808000450d00200441046a2001200210e58c8080002004280204418180808078460d0120002004290204370200200041086a200441046a41086a2802003602000c020b41002d00fca3c680001a410141002802c8a3c68000118180808000002201450d02200041013602082000200136020420004101360200200141003a00000c010b20004180808080783602000b200441106a2480808080000f0b4101410110b280808000000bda0101027f23808080800041106b2203248080808000024002400240024002402001200041d8006a412010888e808000450d00200341046a2000200110e58c80800041808080807821000240200328020422044180808080786a0e020304000b2004450d0220032802082101200421000c010b41002d00fca3c680001a41012100410141002802c8a3c68000118180808000002201450d03200141003a00000b200141002802c0a3c68000118080808000000c010b200421000b200341106a2480808080002000418080808078470f0b4101410110b280808000000bcf0802087f017e23808080800041f0036b2202248080808000200241106a200110bc8a808000024002400240024020022802100d002001280200220341046a22042802002205450d012002280214210620042005417f6a36020020032003280200220441016a36020002400240024020042d0000220341ff00714104470d002003411874411875417f4c0d01410221040c020b200041003602000c050b024002402001280200220328020422074120490d002003200741606a220836020420032003280200220441206a220936020020024190036a41086a200441086a29000037030020024190036a41106a200441106a29000037030020024190036a41186a200441186a2900003703002002200429000037039003200841c000490d002003200741a07f6a3602042003200441e0006a360200200241b0036a41086a200941086a290000370300200241b0036a41106a200941106a290000370300200241b0036a41186a200941186a290000370300200241b0036a41206a200941206a290000370300200241b0036a41286a200941286a290000370300200241b0036a41306a200941306a290000370300200241b0036a41386a200941386a290000370300200220092900003703b0032002200110be8a80800020022802000d00200128020022032802042204450d002002290308210a20032004417f6a36020420032003280200220441016a3602004101410220042d000022034101461b410020031b22044102470d010b200041003602000c050b200241b0026a20024190036a41186a290300370300200241a8026a20024190036a41106a290300370300200241a0026a20024190036a41086a290300370300200241d8016a41086a200241b0036a41086a290300370300200241d8016a41106a200241b0036a41106a290300370300200241d8016a41186a200241b0036a41186a290300370300200241d8016a41206a200241b0036a41206a290300370300200241d8016a41286a200241b0036a41286a290300370300200241d8016a41306a200241b0036a41306a290300370300200241d8016a41386a200241b0036a41386a290300370300200220022903900337039802200220022903b0033703d801200241f8006a200241d8016a41e00010848e8080001a0b200241186a200241f8006a41e00010848e8080001a200241d8016a200110fd8980800020022802d8012203450d02200241f8006a410472200241d8016a41047241d40010848e8080001a20022003360278024041002005200128020041046a2802006b2201200120054b1b2006470d00200241d8016a41d8006a200241186a41e00010848e8080001a200041003a00c101200241d8016a200241f8006a41d80010848e8080001a2000200241d8016a41b80110848e808000220120043a00c0012001200a3703b8010c040b20004100360200200241f8006a10f68c8080000c030b200041003602000c020b200041003602000c010b200041003602000b200241f0036a2480808080000bef0901057f0240024002400240024002402000280200220141736a2202410220024104491b0e03010203000b20002d00084106470d042000410c6a280200450d04200041106a28020021030c030b0240024002400240024002400240024020002d0008417f6a0e0a010b0203040506070b0b000b2000410c6a280200450d0a200041106a28020021030c090b2000410c6a280200450d09200041106a28020021030c080b2000410c6a280200450d08200041106a28020021030c070b2000410c6a280200450d07200041106a28020021030c060b200041106a28020021030240200041146a2802002201450d0020032102034002402002280200450d00200241046a28020041002802c0a3c68000118080808000000b02402002410c6a280200450d00200241106a28020041002802c0a3c68000118080808000000b200241186a21022001417f6a22010d000b0b200028020c450d060c050b200041106a28020021030240200041146a2802002202450d002002410171210441002101024020024101460d002002417e7121052003210241002101034002402002280200450d00200241046a28020041002802c0a3c68000118080808000000b02402002410c6a280200450d00200241106a28020041002802c0a3c68000118080808000000b200241186a21022005200141026a2201470d000b0b2004450d0020032001410c6c6a2202280200450d00200228020441002802c0a3c68000118080808000000b200028020c0d040c050b200041106a280200450d04200041146a28020021030c030b2000410c6a280200450d03200041106a28020021030c020b200041186a2d0000417d6a41ff017141014b0d020240200028020822034198016a2802002205450d0020034194016a280200220421004100210203402004200241146c6a21010240024002400240024020002d00000e0400010102040b200041086a21010c020b200141086a21010c010b200141046a21010b2001280200450d00200128020441002802c0a3c68000118080808000000b200241016a2102200041146a21002005417f6a22050d000b0b0240200328029001450d0020032802940141002802c0a3c68000118080808000000b024020034190026a2802002205450d002003418c026a280200220421004100210203402004200241146c6a21010240024002400240024020002d00000e0400010102040b200041086a21010c020b200141086a21010c010b200141046a21010b2001280200450d00200128020441002802c0a3c68000118080808000000b200241016a2102200041146a21002005417f6a22050d000b0b200328028802450d01200328028c0241002802c0a3c68000118080808000000c010b024002400240024002400240024002402001417e6a0e06000102030405090b200041046a21000c050b02402000280210450d00200041146a28020041002802c0a3c68000118080808000000b20002802042202418080808078460d07200041046a21000c050b02402000280204450d00200041086a28020041002802c0a3c68000118080808000000b200041106a21000c030b200041046a21000c020b200041046a21000c010b024002400240024020002d00040e0400010203070b2000410c6a21000c030b2000410c6a21000c020b2000410c6a21000c010b200041086a21000b200028020021020b2002450d01200028020421030b200341002802c0a3c68000118080808000000f0b0b890401047f23808080800041206b220224808080800041002d00fca3c680001a02400240024041e80141002802c8a3c68000118180808000002203450d002002410036020820022003360204200241e80136020002400240200141c0016a2d00004102470d00200341043a00002002200228020841016a3602080c010b20034184013a00002002200228020841016a360208200141d8006a200210cc878080000b2001200210b88980800020022002280208220136020c41012104410121030240200141c000490d0041022103200141808001490d00410441052001418080808004491b21030b0240200320016a2201450d002001417f4c0d0241002d00fca3c680001a200141002802c8a3c68000118180808000002204450d030b20024100360218200220043602142002200136021020022002410c6a36021c2002411c6a200241106a10c08a808000200228020421042002280200210502402002280210200228021822016b200228020822034f0d00200241106a2001200310ab86808000200228021821010b200228021420016a2004200310848e8080001a2002200120036a36021802402005450d00200441002802c0a3c68000118080808000000b20002002290210370200200041086a200241106a41086a280200360200200241206a2480808080000f0b410141e80110b280808000000b10ae80808000000b4101200110b280808000000b880703017f057e017f23808080800041f0036b2201248080808000200141c0006a10ce88808000200141f0006a10e18980800002402001290388032202427f427f2001290340220320012903507c220420042003541b220320012903607c220420042003541b2204580d0020014190036a2903002203427f427f20012903482205200141d8006a2903007c220620062005541b2205200141e8006a2903007c220620062005541b2205580d00200141306a20004200200220047d220420042002561b22024200200320057d220420042003561b220341a8c6c480002000a741037141027441a8c6c480006a2207200741b8c6c48000461b2207280200118d8080800000200141206a200042002002200129033022047d220520052002561b42002003200129033822057d220620062003561b41a8c6c48000200741046a2207200741b8c6c48000461b2207280200118d8080800000200141106a200042002002427f200420012903207c220620062004541b22047d220620062002561b42002003427f200520012903287c220620062005541b22057d220620062003561b41a8c6c48000200741046a2207200741b8c6c48000461b2207280200118d80808000002001200042002002427f200420012903107c220620062004541b22047d220620062002561b42002003427f200520012903187c220220022005541b22027d220520052003561b41a8c6c48000200741046a2207200741b8c6c48000461b280200118d8080800000200129030821002001290300210320014198036a10ce8880800020014198036a41286a2207427f20072903002205427f200220007c220020002002541b7c220020002005541b220037030020014198036a41206a2207427f20072903002202427f200420037c220320032004541b7c220320032002541b2202370300200141a0016a2000370300200141f0006a41286a2002370300200141f0006a41206a20014198036a41186a290300370300200141f0006a41186a20014198036a41106a290300370300200141f0006a41106a20014198036a41086a2903003703002001200129039803370378200142013703702001200141f0006a41086a3602cc03200142fc90b9e5d09296e7773703d803200142a6d4e6f1a4dd9598603703d003200142f89aef8eef91e1ce967f3703e803200142b4d6d6dfccc6b592c3003703e003200141cc036a200141d0036a412010f98c8080000b200141f0036a2480808080000bb30503037f017e067f23808080800041106b22032480808080004101210441012105024020002802002200290300220642c000540d0041022105200642808001540d00410421052006428080808004540d004109200679a74103766b21050b02402000290308220642c000540d0041022104200642808001540d00410421042006428080808004540d004109200679a74103766b21040b410121074101210802402000290310220642c000540d0041022108200642808001540d00410421082006428080808004540d004109200679a74103766b21080b0240200041186a2209290300220642c000540d0041022107200642808001540d00410421072006428080808004540d004109200679a74103766b21070b4101210a4101210b02402000290320220642c000540d004102210b200642808001540d004104210b2006428080808004540d004109200679a74103766b210b0b0240200041286a220c290300220642c000540d004102210a200642808001540d004104210a2006428080808004540d004109200679a74103766b210a0b41002d00fca3c680001a0240200420056a20086a20076a200b6a200a6a220441002802c8a3c68000118180808000002207450d002003200736020420032004360200200341003602082003200036020c2003410c6a200310c18a8080002003200041086a36020c2003410c6a200310c18a8080002003200041106a36020c2003410c6a200310c18a8080002003200936020c2003410c6a200310c18a8080002003200041206a36020c2003410c6a200310c18a8080002003200c36020c2003410c6a200310c18a808000200328020021002001200220032802042204200328020841002802e0a1c680001186808080000002402000450d00200441002802c0a3c68000118080808000000b200341106a2480808080000f0b4101200410b280808000000bf70f03017f017e067f23808080800041a0036b2201248080808000200010fb8c8080001a024002400240024020002903202202500d0020014198016a2002427f7c10fb8780800020014198016a2000412010888e8080000d00200141106a200041f80010848e8080001a20002802800121032001200029037822023e02900120012002422088a72200360288012001200036028c0120012000200341e8016c6a22043602940102402003450d0020014198016a410472210502400240034020002802002206450d012005200041046a41e40110848e8080001a200120063602980120014188036a20014198016a10fc8c80800020012d008803410f460d05200041e8016a22002004470d000c020b0b200041e8016a21040b2001200436028c010b20014188016a10de8680800010ed888080000d032003450d020240417f4100280284a4c680002200410147200041014b1b2200417f460d00200041ff01710d030b20014188036a410c6a418382808000360200200141d484c6800036029003200141e08180800036028c03200141f883c68000360288034100280290a1c680002100410028028ca1c6800021064100280280a4c680002104200141d0016a4202370200200141c8016a4102360200200141c0016a4112360200200141bc016a418084c68000360200200141b0016a41d080c68000ad4280808080e00b8437020020014198016a410c6a419284c68000ad4280808080f00184370200200141cc016a20014188036a360200200141a484c680003602c401200141013602b801200141003602ac01200141003602a00120014281808080a0d20037029801200641ecf2c08000200441024622041b20014198016a200041d4f2c0800020041b280210118480808000000c020b200141a4016a42003702002001410136029c01200141f884c6800036029801200141fcfcc580003602a00120014198016a418085c6800010f680808000000b200141086a20012f00890320012d008b034110747210fc84808000200120012903083702800320014180036a10fd8c808000000b10fe8c8080000b109b8a8080002001290330220210f88c808000200210cf8780800020014198016a109d8a8080002001200141106a41f0006a280200220336028003200120014198016a41f0006a28020022003602880102400240024020032000470d002003450d0220014198016a41ec006a2802002107200141106a41ec006a2802002108410021000340200820006a2206200720006a220410ef8480800020062d0000220520042d0000470d020240024002400240024020050e0400010203040b20050d03200641016a280000200441016a280000470d06200641106a2802002205200441106a280200470d062006410c6a2802002004410c6a280200200510888e8080000d060c030b20054101470d02200641016a280000200441016a280000470d05200641106a2802002205200441106a280200470d052006410c6a2802002004410c6a280200200510888e8080000d050c020b20054102470d01200641016a280000200441016a280000470d04200641106a2802002205200441106a280200470d042006410c6a2802002004410c6a280200200510888e808000450d010c040b20054103470d002006410c6a28020022052004410c6a280200470d03200641086a280200200441086a280200200510888e8080000d030b200041146a21002003417f6a22030d000c030b0b2001420037029403200141fcfcc58000360290032001410136028c03200141c880c6800036028803410020014180036a20014188016a20014188036a41b081c6800010a789808000000b20014194036a42003702002001410136028c03200141e482c6800036028803200141fcfcc580003602900320014188036a41ec82c6800010f680808000000b0240200141106a41286a220020014198016a41286a2206412010888e808000450d0041f8a7c28000410e4100280280a3c68000118480808000002000412041002802f8a2c68000118480808000002006412041002802f8a2c68000118480808000000b024020002006412010888e808000450d0020014194036a42003702002001410136028c03200141e881c6800036028803200141fcfcc580003602900320014188036a41f081c6800010f680808000000b0240200141106a41c8006a20014198016a41c8006a412010888e8080000d0002402001280288022205450d00200128028402220321004100210603402003200641146c6a21040240024002400240024020002d00000e0400010102040b200041086a21040c020b200441086a21040c010b200441046a21040b2004280200450d00200428020441002802c0a3c68000118080808000000b200641016a2106200041146a21002005417f6a22050d000b0b0240200128028002450d0020012802840241002802c0a3c68000118080808000000b02402001280280012205450d00200128027c220321004100210603402003200641146c6a21040240024002400240024020002d00000e0400010102040b200041086a21040c020b200441086a21040c010b200441046a21040b2004280200450d00200428020441002802c0a3c68000118080808000000b200641016a2106200041146a21002005417f6a22050d000b0b02402001280278450d00200128027c41002802c0a3c68000118080808000000b200141a0036a2480808080000f0b20014194036a42003702002001410136028c03200141a482c6800036028803200141fcfcc580003602900320014188036a41ac82c6800010f680808000000bc30b020a7f077e23808080800041c0036b220124808080800020002802702102200028026c21032001410036024820014280808080c0003702400240024002402002450d00200241146c21040340024020032d00000d00200341046a2d00002105200341036a2d00002106200341026a2d0000210741012102200341016a2d000021082003410c6a28020021090240200341106a280200220a450d00200a417f4c0d0541002d00fca3c680001a200a41002802c8a3c68000118180808000002202450d040b20022009200a10848e80800021090240200128024822022001280240470d00200141c0006a200210df84808000200128024821020b2001280244200241146c6a220220083a00012002200a3602102002200936020c2002200a360208200241003a0000200241046a20053a0000200241036a20063a0000200241026a20073a00002001200128024841016a3602480b200341146a21032004416c6a22040d000b0b200141306a41086a200141c0006a41086a2802003602002001200129024037033010988a808000200141c0006a10ea888080000240024020012802402203418180808078460d00200128024821020240200341808080807872418080808078460d00200128024441002802c0a3c68000118080808000000b20020d004200210b4200210c0c010b200141206a10ad8a8080002001290320210b2001290328210c200141106a10918a8080002001290310210d2001290318210e200142003702f0022001418097c380003602ec0220014180808080783602e802200142fc90b9e5d09296e777370348200142a6d4e6f1a4dd959860370340200142a0b9ab8f9ae5999778370358200142f999a7c78cd1d1cdb17f370350200141e8026a200141c0006a4120109288808000200c200e7c220e200c542103200b200d7c220c200b542102024020012802e8022204418080808078460d002004450d0020012802ec0241002802c0a3c68000118080808000000b427f200e20031b210b427f200c20021b210c0b200041206a2000200141306a10968a8080002001200029032010d0878080002001290308210d2001290300210e200141c0006a10e189808000200141d0026a290300210f20012903c8022110200141e8026a10ce88808000200141e8026a41286a2203427f20032903002211427f200f427f200b200d7c220d200d200b541b220b7c220d200d200b541b7c220b200b2011541b220b370300200141e8026a41206a2203427f2003290300220d427f2010427f200c200e7c220e200e200c541b220c7c220e200e200c541b7c220c200c200d541b220c370300200141f0006a200b370300200141c0006a41286a200c370300200141c0006a41206a200141e8026a41186a290300370300200141c0006a41186a200141e8026a41106a290300370300200141c0006a41106a200141e8026a41086a290300370300200120012903e802370348200142013703402001200141c0006a41086a36029c03200142fc90b9e5d09296e7773703a803200142a6d4e6f1a4dd9598603703a003200142f89aef8eef91e1ce967f3703b803200142b4d6d6dfccc6b592c3003703b0032001419c036a200141a0036a412010f98c808000200142003702e802200142fc90b9e5d09296e777370348200142a6d4e6f1a4dd95986037034020014293bb8a9cbb9ab6b31a370358200142ffabedd185d3d8d216370350200141e8026a200141c0006a412010948880800002402001280238220a450d002001280234220521034100210203402005200241146c6a21040240024002400240024020032d00000e0400010102040b200341086a21040c020b200441086a21040c010b200441046a21040b2004280200450d00200428020441002802c0a3c68000118080808000000b200241016a2102200341146a2103200a417f6a220a0d000b0b02402001280230450d00200128023441002802c0a3c68000118080808000000b200141c0036a24808080800041000f0b4101200a10b280808000000b10ae80808000000b970802027f017e23808080800041b0056b2202248080808000200241146a200110f78c808000200228021c2103200241f0026a200141e80110848e8080001a200241c8016a200241f0026a200210808d808000024002400240024020022802c8012201450d00200220022d00ce013a00f204200220022f01cc013b01f004200241206a410772200241c8016a41077241a10110848e8080001a200220022f01f0043b0124200220022d00f2043a00262002200136022002400240024002400240200141736a2201410220014104491b0e0400010203000b200241d8046a200241286a10ba8a8080000c030b200241d8046a200241286a10e4878080000c020b200241d8046a200241206a10bb888080000c010b200241d8046a200241286a108e8c8080000b10ed88808000450d010c020b200220022d00ce0122013a00f204200220022f01cc0122033b01f004200041036a20013a0000200020033b00012000410f3a00002002280214450d02200228021841002802c0a3c68000118080808000000c020b10fe8c8080000b200241f0026a41086a200241146a41086a280200360200200220022902143703f002200241086a41e6aac48000411010d088808000200228020c410020022802081b200241f0026a10ff87808000200241f0026a200241206a41a80110848e8080001a200241c8016a200241f0026a200241d8046a200310be878080000240024020022903c80122044203510d00200241f0046a41136a200241c8016a41136a290000370000200241f0046a411b6a200241c8016a411b6a290000370000200241f0046a41236a200241c8016a41236a290000370000200241f0046a412b6a200241c8016a412b6a290000370000200241f0046a41306a200241c8016a41306a290000370000200241f0046a410a6a200241c8016a410a6a2d000022013a0000200220022f01d00122033b01a805200220022900d3013700fb04200220013a00aa05200220033b01f804200220043703f004024020044202510d0020022d00e80441ff01714102460d020b200241f0026a41106a200241d8046a41106a290300370300200241f0026a41086a2201200241d8046a41086a290300370300200220022903d8043703f002200241f0046a200241f0026a10998a808000410e2103024020022903f0044202510d00200120024199056a290000370300200241ff026a200241a0056a28000036000020022002290091053703f00220022d00900521030b200020033a0000200020022903f002370001200041096a2001290300370000200041106a200241ff026a2800003600000c020b200220022f01d00122013b01a8052002200241d2016a2d000022033a00aa05200041036a20033a0000200020013b00012000410f3a00000c010b2000410f3b0100200041026a41083a00000b200241b0056a2480808080000b5c01017f23808080800041206b22012480808080002001410c6a420137020020014101360204200141a085c68000360200200141e08180800036021c200120003602182001200141186a3602082001419085c6800010f680808000000bcf0303017f027e017f2380808080004190036b2200248080808000200042fc90b9e5d09296e777370348200042a6d4e6f1a4dd959860370340200042beee8ae9ce8fa2b1977f37035820004295d4f9afa2868fb864370350200041013a0010200041c0006a4120200041106a410141002802e0a1c6800011868080800000200042fc90b9e5d09296e777370348200042a6d4e6f1a4dd959860370340200042d3d8c5d2a9b9d2c1ac7f37035820004282ca868eabf3add0cf003703502000200041c0006a10e688808000200041106a10ce88808000200041c0006a10e189808000024020002903d802427f427f2000290310220120002903207c220220022001541b220120002903307c220220022001541b580d00200041e0026a290300427f427f20002903182201200041286a2903007c220220022001541b2201200041386a2903007c220220022001541b580d00200041c8006a220310ce8880800020004201370340200020033602ec02200042fc90b9e5d09296e7773703f802200042a6d4e6f1a4dd9598603703f002200042f89aef8eef91e1ce967f37038803200042b4d6d6dfccc6b592c30037038003200041ec026a200041f0026a412010f98c8080000b20004190036a2480808080000ba90102017f017e23808080800041306b2201248080808000024010ed888080000d0010fe8c8080000b109b8a808000200142fc90b9e5d09296e777370318200142a6d4e6f1a4dd959860370310200142d3d8c5d2a9b9d2c1ac7f37032820014282ca868eabf3add0cf003703202001200141106a10e6888080002001290308420020012802001b220210f88c808000200210cf878080002000109d8a808000200141306a2480808080000bed0a020a7f017e23808080800041c0066b220324808080800041022104024002400240200141c0016a22052d00004102470d00200341306a200141d80010848e8080001a0c010b200341e8016a41186a200141b0016a290000370300200341e8016a41106a200141a8016a290000370300200341e8016a41086a200141a0016a290000370300200320014198016a2900003703e801200341e0016a20014190016a290000370300200341d8016a20014188016a290000370300200341a8016a41286a20014180016a290000370300200341a8016a41206a200141f8006a290000370300200341a8016a41186a200141f0006a290000370300200341a8016a41106a200141e8006a290000370300200341a8016a41086a200141e0006a290000370300200320012900583703a801200341e8046a41286a2204200141e0016a290300370300200341e8046a41206a2206200141d8016a290300370300200341e8046a41186a2207200141d0016a290300370300200341e8046a41106a2208200141c8016a290300370300200341e8046a41086a220920052903003703002003200141b8016a2903003703e8042003419e056a200341e8046a10d4888080000240024020032d009e0522054102470d00200320032f009f053b01e4042003200341a1056a2d00003a00e604200110f68c8080000c010b200341c0036a41086a200341aa056a290000370300200341c0036a41106a200341b2056a290000370300200341d5036a220a200341b7056a290000370000200341e2036a220b200341a1056a2d00003a0000200320032900a2053703c003200320032f009f053b01e0032003200141066a2d00003a00e604200320012f01043b01e4042001280200210c200341bf056a200141076a41d10010848e8080001a200341b8066a2004290300370000200341b0066a2006290300370000200341a8066a2007290300370000200341a0066a200829030037000020034198066a2009290300370000200320032903e80437009006200341e3036a200341bf056a41810110848e8080001a200c450d00200320032d00e6043a00ba03200320032f01e4043b01b80320034188026a410772200341e3036a41810110848e8080001a20034193036a200b2d00003a00002003419c036a200341c0036a41086a290300370200200341a4036a200341c0036a41106a290300370200200341a9036a200a290000370000200320032f01e0033b009103200320032903c00337029403200320032f01b8033b018c02200320032d00ba033a008e02200320053a0090032003200c36028802024020034188026a200341a8016a200341e8016a10b7898080000d002000410036020020004180083b010420034188026a10f68c8080000c030b200341306a20034188026a41d80010848e8080001a200341086a41086a200341f1026a290000370300200341086a41106a200341f9026a290000370300200341086a41186a20034181036a290000370300200341276a20034188036a29000037000020034190016a200341e8016a41086a29030037030020034198016a200341e8016a41106a290300370300200341a0016a200341e8016a41186a290300370300200320032900e902370308200320032903e8013703880120032d00e802210420032903e002210d0c010b200320032d00e60422013a00ba03200320032f01e40422043b01b803200041066a20013a0000200020043b0104200041003602000c010b2000200341306a41f80010848e808000220120043a0080012001200d370378200120032903083700810120014189016a200341106a29030037000020014191016a200341186a29030037000020014199016a200341206a290300370000200141a0016a200341276a2900003700000b200341c0066a2480808080000b9f0601057f23808080800041e0046b2204248080808000200442fc90b9e5d09296e7773703f802200442a6d4e6f1a4dd9598603703f002200442d3d8c5d2a9b9d2c1ac7f3703880320044282ca868eabf3add0cf0037038003200441086a200441f0026a10e6888080002004200429031042017c420120042802081b3703c801200441003602f80220044280808080c0003702f002200441c8016a2003200441f0026a10968a808000024020042802f8022205450d0020042802f402220621034100210703402006200741146c6a21080240024002400240024020032d00000e0400010102040b200341086a21080c020b200841086a21080c010b200841046a21080b2008280200450d00200828020441002802c0a3c68000118080808000000b200741016a2107200341146a21032005417f6a22050d000b0b024020042802f002450d0020042802f40241002802c0a3c68000118080808000000b200441f0026a200210f78c80800020042802f8022107024020042802f002450d0020042802f40241002802c0a3c68000118080808000000b200441f0026a200241e80110848e8080001a200441c8016a200441f0026a200310808d8080000240024020042802c8012203450d00200420042d00ce013a00c201200420042f01cc013b01c001200441186a410772200441c8016a41077241a10110848e8080001a200420042f01c0013b011c200420042d00c2013a001e2004200336021802400240024002400240200341736a2203410220034104491b0e0400010203000b200441f0026a200441206a10ba8a8080000c030b200441f0026a200441206a10e4878080000c020b200441f0026a200441186a10bb888080000c010b200441f0026a200441206a108e8c8080000b024020042d0080034102470d00200041808080807836021020004180123b0100200441186a10f68c8080000c020b2000200441186a2001200441f0026a200710c087808000200441186a10f68c8080000c010b200420042d00ce0122033a00c201200420042f01cc0122073b01c001200041026a20033a0000200020073b010020004180808080783602100b200441e0046a2480808080000bc40904067f017e027f017e23808080800041d0006b2201248080808000200141286a41a885c68000410b41b385c68000411641fcfcc58000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a02400240412041002802c8a3c68000118180808000002202450d00200242a5e9e3ab9e929adc2c370308200241ef8080800036021820024107360204200241c985c68000360200200241106a4293888c8f89fdc6ec9e7f370300200120023602402001200241206a36024c2001200236024420014101360248200141106a200141c0006a10fa86808000200141086a2001411c6a220241086a2802003602002001200229020037030020012802102103200128021421042001280218210520012802282106200129022c2107200141106a41086a22084100360200200142808080808001370210200141106a410010a4868080002001280214200828020041386c6a2202420437022c20024207370224200241c7fbc480003602202002410436021c20024193fcc48000360218200241ef8080800036021020024293888c8f89fdc6ec9e7f370308200242a5e9e3ab9e929adc2c370300200141c0006a41086a2209200828020041016a220236020020012001290210220a37034002402002200aa7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c20024207370224200241c7fbc480003602202002410836021c2002418bfcc48000360218200241ef8080800036021020024293888c8f89fdc6ec9e7f370308200242a5e9e3ab9e929adc2c3703002008200928020041016a220236020020012001290340220a37031002402002200aa7470d00200141106a200210a486808000200128021821020b2001280214200241386c6a2202420437022c20024207370224200241c7fbc480003602202002410636021c20024185fcc48000360218200241ef8080800036021020024293888c8f89fdc6ec9e7f370308200242a5e9e3ab9e929adc2c370300200141c0006a41086a200141106a41086a28020041016a220236020020012001290310220a37034002402002200aa7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c2002420a370224200241fbfbc480003602202002410536021c200241f6fbc480003602182002418684808000360210200242dcf29fddf2bfe9f9f300370308200242a7a6d9c6f090c49632370300200128024821082001280244210220012001280240360248200120023602402001200236024420012002200841386c6a41386a36024c200141346a200141c0006a10f9868080002006418080808078460d012001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002006360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b4108412010b280808000000b41a8d8c480004111419cd9c4800010a181808000000ba00804067f017e027f017e23808080800041d0006b2201248080808000200141286a41d085c68000410b41b385c68000411641fcfcc58000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a02400240412041002802c8a3c68000118180808000002202450d00200242a5e9e3ab9e929adc2c370308200241ef8080800036021820024107360204200241c985c68000360200200241106a4293888c8f89fdc6ec9e7f370300200120023602402001200241206a36024c2001200236024420014101360248200141106a200141c0006a10fa86808000200141086a2001411c6a220241086a2802003602002001200229020037030020012802102103200128021421042001280218210520012802282106200129022c2107200141106a41086a22084100360200200142808080808001370210200141106a410010a4868080002001280214200828020041386c6a2202420437022c2002420e37022420024197fcc480003602202002410236021c200241cefbc480003602182002418784808000360210200242a8c7daf8defb9a8fc400370308200242a7b98ffce8cbcbd38b7f370300200141c0006a41086a2209200828020041016a220236020020012001290210220a37034002402002200aa7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c20024207370224200241c7fbc480003602202002410636021c200241c1fbc48000360218200241ef8080800036021020024293888c8f89fdc6ec9e7f370308200242a5e9e3ab9e929adc2c3703002008200928020041016a220236020020012001290340220a37031002402002200aa7470d00200141106a200210a486808000200128021821020b2001280214200241386c6a2202420437022c20024207370224200241acfcc480003602202002410736021c200241a5fcc48000360218200241888480800036021020024282b0a8d2a7f3c7e316370308200242e59ffc9df1de8b92867f370300200128021821082001280214210220012001280210360248200120023602402001200236024420012002200841386c6a41386a36024c200141346a200141c0006a10f9868080002006418080808078460d012001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002006360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141106a41076a290000370000200141d0006a2480808080000f0b4108412010b280808000000b41a8d8c480004111419cd9c4800010a181808000000bbe0203017e047f017e20002903102102024020012802002203200128020822046b41074b0d0020012004410810b18280800020012802002103200128020821040b2001200441086a22053602082001280204220620046a2002370000200029031821020240200320056b41074b0d0020012005410810b1828080002001280200210320012802042106200128020821050b2001200541086a2204360208200620056a2002370000200029032021020240200320046b41074b0d0020012004410810b18280800020012802042106200128020821040b200620046a20023700002001200441086a2205360208200041086a2903002102200029030021070240200128020020056b410f4b0d0020012005411010b182808000200128020821050b2001200541106a360208200128020420056a22012002370008200120073700000bcd0704067f017e017f017e23808080800041d0006b2201248080808000200141286a41db85c68000410b41b385c68000411641fcfcc58000410010d882808000200141106a41106a42043702002001420037021820014280808080800137021041002d00fca3c680001a0240024041c00041002802c8a3c68000118180808000002202450d00200242a7b98ffce8cbcbd38b7f370308200241c985c68000360220200241878480800036021820024111360204200241e685c68000360200200241306a4293888c8f89fdc6ec9e7f370300200241286a42a5e9e3ab9e929adc2c370300200241106a42a8c7daf8defb9a8fc400370300200241386a41ef80808000360200200241246a410736020020014102360248200120023602402001200241c0006a36024c20012002360244200141106a200141c0006a10fa86808000200141086a2001411c6a220241086a2802003602002001200229020037030020012802102103200128021421042001280218210520012802282106200129022c2107200141106a41086a22084100360200200142808080808001370210200141106a410010a4868080002001280214200828020041386c6a2202420437022c20024211370224200241b3fcc480003602202002410236021c200241cefbc480003602182002418784808000360210200242a8c7daf8defb9a8fc400370308200242a7b98ffce8cbcbd38b7f370300200141c0006a41086a200828020041016a2202360200200120012902102209370340024020022009a7470d00200141c0006a200210a486808000200128024821020b2001280244200241386c6a2202420437022c20024207370224200241c7fbc480003602202002410636021c200241c1fbc48000360218200241ef8080800036021020024293888c8f89fdc6ec9e7f370308200242a5e9e3ab9e929adc2c370300200128024821082001280244210220012001280240360248200120023602402001200236024420012002200841386c6a41386a36024c200141346a200141c0006a10f9868080002006418080808078460d012001200336021820012004360210200120043602142001200420054105746a36021c200041c4006a200141106a10fa868080002001411b6a200141346a41086a2802003600002000413c6a200737020020002006360238200041003a000020002001290300370350200041d8006a200141086a2802003602002001200129023437001320002001290010370001200041086a200141176a290000370000200141d0006a2480808080000f0b410841c00010b280808000000b41a8d8c480004111419cd9c4800010a181808000000b950901027f23808080800041c0016b220424808080800041002d00fca3c680001a024002400240410141002802c8a3c68000118180808000002205450d00200541003a0000200441246a419380c6800041014100280298a3c6800011858080800000200441206a410036020020044201370214200420053602102004410136020c200141386a210520012d00790d0120012d00780d022004200136024420042004410c6a3602480240024020030d00200441f0006a41186a200541186a290000370300200441f0006a41106a200541106a290000370300200441f0006a41086a200541086a2900003703002004200529000037037020044190016a41286a200241286a28020036020020044190016a41206a200241206a29020037030020044190016a41186a200241186a29020037030020044190016a41106a200241106a29020037030020044190016a41086a200241086a2902003703002004200229020037039001200441cc006a200441c4006a200441f0006a20044190016a4100419c87c680004100418087c6800010ce898080000c010b200441f0006a41186a200541186a290000370300200441f0006a41106a200541106a290000370300200441f0006a41086a200541086a2900003703002004200529000037037020044190016a41286a200241286a28020036020020044190016a41206a200241206a29020037030020044190016a41186a200241186a29020037030020044190016a41106a200241106a29020037030020044190016a41086a200241086a2902003703002004200229020037039001200441cc006a200441c4006a200441f0006a20044190016a4100419c87c680004100418087c6800010cf898080000b0240024020042d004c0d00200441a8016a200441e5006a290000370300200441a0016a200441dd006a29000037030020044198016a200441d5006a2900003703002004200429004d370390010c010b20044190016a41086a200541086a29000037030020044190016a41106a200541106a29000037030020044190016a41186a200541186a290000370300200420052900003703900102400240024002402004280250220528020041fcffffff076a2202410320024105491b0e0403030102000b2005280204450d02200541086a28020041002802c0a3c68000118080808000000c020b2005280204450d01200541086a28020041002802c0a3c68000118080808000000c010b200510878d8080000b200541002802c0a3c68000118080808000000b2000200429039001370000200041186a20044190016a41186a290300370000200041106a20044190016a41106a290300370000200041086a20044190016a41086a290300370000200041d0006a2004410c6a41306a290200370200200041c8006a2004410c6a41286a290200370200200041c0006a2004412c6a290200370200200041386a2004410c6a41186a290200370200200041306a2004410c6a41106a290200370200200041286a2004410c6a41086a2902003702002000200429020c370220200441c0016a2480808080000f0b4101410110b280808000000b200141fa006a200510ee87808000000b200141f9006a108888808000000bc50101027f024002400240024020002802002201418080808078732202410220024104491b0e03030301000b0240024002402000280204220028020041fcffffff076a2202410320024105491b0e0404040102000b2000280204450d03200041086a28020041002802c0a3c68000118080808000000c030b2000280204450d02200041086a28020041002802c0a3c68000118080808000000c020b200010878d8080000c010b2001450d01200028020421000b200041002802c0a3c68000118080808000000b0bde0f03047f017e017f2380808080004180026b2205248080808000200541086a41014101412110fb8a80800041002d00fca3c680001a024002400240410141002802c8a3c68000118180808000002206450d00200641003a0000200541c0006a419380c6800041014100280298a3c68000118580808000002005413c6a4100360200200542013702302005200636022c20054101360228200541b0016a200210a085808000200141f9006a2106200141386a210720012d00780d0120062d00000d0220052802b801210820052802b4012106200541f4016a41a08ac48000360200200541e8016a4100360200200520073602f801200520013602f001200542003702e001200541003602d801200542003702d0012005418c016a200541d0016a2006200810dd878080000240024002400240200528028c012207418180808078460d002007418080808078460d012005290290012209422088a722084120460d024120200841f086c6800010a281808000000b0240024002400240200528029001220728020041fcffffff076a2208410320084105491b0e0403030102000b2007280204450d02200741086a28020041002802c0a3c68000118080808000000c020b2007280204450d01200741086a28020041002802c0a3c68000118080808000000c010b200710878d8080000b200741002802c0a3c6800011808080800000024020052802b001450d00200641002802c0a3c68000118080808000000b200541e0006a41086a200541086a41086a290000370300200541e0006a41106a200541086a41106a290000370300200541e0006a41186a200541086a41186a290000370300200520052900083703600c020b024020052802b001450d00200641002802c0a3c68000118080808000000b200541e0006a41086a200541086a41086a290000370300200541e0006a41106a200541086a41106a290000370300200541e0006a41186a200541086a41186a290000370300200520052900083703600c010b200528029001210a200541e0006a41186a2009a7220841186a290000370300200541e0006a41106a200841106a290000370300200541e0006a41086a200841086a2900003703002005200829000037036002402007450d00200a41002802c0a3c68000118080808000000b20052802b001450d00200641002802c0a3c68000118080808000000b20052001360284012005200541286a3602880120022802082101200228020421020240024020040d00200541b0016a41186a200541e0006a41186a290300370300200541b0016a41106a200541e0006a41106a290300370300200541b0016a41086a200541e0006a41086a290300370300200520052903603703b001200541d0016a41206a200341206a280200360200200541d0016a41186a200341186a290200370300200541d0016a41106a200341106a290200370300200541d0016a41086a200341086a290200370300200520032902003703d0012005418c016a2002200120054184016a200541b0016a200541d0016a4100419c87c680004100418087c6800010d1898080000c010b200541b0016a41186a200541e0006a41186a290300370300200541b0016a41106a200541e0006a41106a290300370300200541b0016a41086a200541e0006a41086a290300370300200520052903603703b001200541d0016a41206a200341206a280200360200200541d0016a41186a200341186a290200370300200541d0016a41106a200341106a290200370300200541d0016a41086a200341086a290200370300200520032902003703d0012005418c016a2002200120054184016a200541b0016a200541d0016a4100419c87c680004100418087c6800010d0898080000b0240024020052d008c010d00200541e8016a200541a5016a290000370300200541e0016a2005419d016a290000370300200541d8016a20054195016a2900003703002005200529008d013703d0010c010b200541d0016a41086a200541e0006a41086a290300370300200541d0016a41106a200541e0006a41106a290300370300200541d0016a41186a200541e0006a41186a290300370300200520052903603703d0010240024002400240200528029001220128020041fcffffff076a2203410320034105491b0e0403030102000b2001280204450d02200141086a28020041002802c0a3c68000118080808000000c020b2001280204450d01200141086a28020041002802c0a3c68000118080808000000c010b200110878d8080000b200141002802c0a3c68000118080808000000b200541b0016a41086a2201200541d0016a41086a290300370300200541b0016a41106a2203200541d0016a41106a290300370300200541b0016a41186a2202200541d0016a41186a290300370300200520052903d0013703b001200541b0016a200541086a412010888e8080002106200041196a2002290300370000200041116a2003290300370000200041096a2001290300370000200020052903b001370001200020052902283702242000412c6a200541286a41086a290200370200200041346a200541286a41106a2902003702002000413c6a200541286a41186a290200370200200041c4006a200541286a41206a290200370200200041cc006a200541d0006a290200370200200041d4006a200541d8006a29020037020020002006453a000020054180026a2480808080000f0b4101410110b280808000000b20062007108788808000000b200141fa006a200710ee87808000000b9b0201037f23808080800041206b22022480808080000240024002400240024020002d000022030e050001020304000b2002200041016a36021420022000410c6a2902003702180c030b2002200041016a36021420022000410c6a2902003702180c020b2002200041016a36021420022000410c6a2902003702180c010b2002200041086a2902003702140b20022003360210200241046a200241106a10ed848080002002280208210402402001280200200128020822006b200228020c22034f0d0020012000200310b182808000200128020821000b200128020420006a2004200310848e8080001a2001200020036a36020802402002280204450d00200441002802c0a3c68000118080808000000b200241206a2480808080000b9f0201037f23808080800041206b22042480808080000240024002400240200141146c41046a22050d00410121060c010b2005417f4c0d0141002d00fca3c680001a200541002802c8a3c68000118180808000002206450d020b20044100360214200420063602102004200536020c200420013602182004200441186a36021c2004411c6a2004410c6a10c08a80800002402001450d00200141146c2101034020002004410c6a10de8c808000200041146a21002001416c6a22010d000b0b200428020c21002002200320042802102201200428021441002802e0a1c680001186808080000002402000450d00200141002802c0a3c68000118080808000000b200441206a2480808080000f0b10ae80808000000b4101200510b280808000000bae0503037f017e067f23808080800041106b2203248080808000410121044101210502402000290300220642c000540d0041022105200642808001540d00410421052006428080808004540d004109200679a74103766b21050b02402000290308220642c000540d0041022104200642808001540d00410421042006428080808004540d004109200679a74103766b21040b410121074101210802402000290310220642c000540d0041022108200642808001540d00410421082006428080808004540d004109200679a74103766b21080b0240200041186a2209290300220642c000540d0041022107200642808001540d00410421072006428080808004540d004109200679a74103766b21070b4101210a4101210b02402000290320220642c000540d004102210b200642808001540d004104210b2006428080808004540d004109200679a74103766b210b0b0240200041286a220c290300220642c000540d004102210a200642808001540d004104210a2006428080808004540d004109200679a74103766b210a0b41002d00fca3c680001a0240200420056a20086a20076a200b6a200a6a220441002802c8a3c68000118180808000002207450d002003200736020420032004360200200341003602082003200036020c2003410c6a200310c18a8080002003200041086a36020c2003410c6a200310c18a8080002003200041106a36020c2003410c6a200310c18a8080002003200936020c2003410c6a200310c18a8080002003200041206a36020c2003410c6a200310c18a8080002003200c36020c2003410c6a200310c18a808000200328020021002001200220032802042204200328020841002802e0a1c680001186808080000002402000450d00200441002802c0a3c68000118080808000000b200341106a2480808080000f0b4101200410b280808000000be40201047f23808080800041206b2203248080808000024002402002417f4c0d0041002d00fca3c680001a200241e8016c410472220441002802c8a3c68000118180808000002205450d012003410036020c2003200536020820032004360204200320023602102003200341106a360214200341146a200341046a10c08a80800002402002450d00200241e8016c2106200328020c21020340200341146a200110f78c808000200328021821050240200328020420026b200328021c22044f0d00200341046a2002200410b182808000200328020c21020b200328020820026a2005200410848e8080001a2003200220046a220236020c02402003280214450d00200541002802c0a3c68000118080808000000b200141e8016a2101200641987e6a22060d000b0b20002003290204370200200041086a200341046a41086a280200360200200341206a2480808080000f0b10ae80808000000b4101200410b280808000000b870503037f017e067f23808080800041106b2202248080808000410121034101210402402001290300220542c000540d0041022104200542808001540d00410421042005428080808004540d004109200579a74103766b21040b02402001290308220542c000540d0041022103200542808001540d00410421032005428080808004540d004109200579a74103766b21030b410121064101210702402001290310220542c000540d0041022107200542808001540d00410421072005428080808004540d004109200579a74103766b21070b0240200141186a2208290300220542c000540d0041022106200542808001540d00410421062005428080808004540d004109200579a74103766b21060b410121094101210a02402001290320220542c000540d004102210a200542808001540d004104210a2005428080808004540d004109200579a74103766b210a0b0240200141286a220b290300220542c000540d0041022109200542808001540d00410421092005428080808004540d004109200579a74103766b21090b41002d00fca3c680001a0240200320046a20076a20066a200a6a20096a220341002802c8a3c680001181808080000022060d004101200310b280808000000b200241086a2207410036020020022006360204200220033602002002200136020c2002410c6a200210c18a8080002002200141086a36020c2002410c6a200210c18a8080002002200141106a36020c2002410c6a200210c18a8080002002200836020c2002410c6a200210c18a8080002002200141206a36020c2002410c6a200210c18a8080002002200b36020c2002410c6a200210c18a808000200041086a200728020036020020002002290200370200200241106a2480808080000bd40801077f23808080800041206b220224808080800002400240417f200141206a2802002203410c6c220441156a22052005200441046a491b2205417f4c0d0041002d00fca3c680001a200541002802c8a3c68000118180808000002204450d012002410036020c2002200436020820022005360204024002402001280200418080808078470d00200241106a2001280204200141086a28020010b4828080000c010b200241106a2001280204200128020810e6848080000b410021062002280214210702402005200228021822084f0d00200241046a4100200810b18280800020022802082104200228020c21060b200420066a2007200810848e8080001a2002200620086a220536020c02402002280210450d00200741002802c0a3c68000118080808000000b200141146a2802002106200141106a280200210802400240200128020c418080808078470d00200241106a2008200610b4828080000c010b200241106a2008200610e6848080000b200228021421080240200228020420056b200228021822064f0d00200241046a2005200610b18280800020022802082104200228020c21050b200420056a2008200610848e8080001a2002200520066a220536020c02402002280210450d00200841002802c0a3c68000118080808000000b200128022421060240200228020420056b41034b0d00200241046a2005410410b18280800020022802082104200228020c21050b200420056a20063600002002200541046a220436020c200128022821050240200228020420046b41034b0d00200241046a2004410410b182808000200228020c21040b200228020820046a20053600002002200441046a220436020c200128022c21050240200228020420046b41034b0d00200241046a2004410410b182808000200228020c21040b200228020820046a20053600002002200441046a36020c2001411c6a28020021052002200336021c20022002411c6a360210200241106a200241046a10c08a808000200228020c210402402003450d0020052003410c6c6a2107034002402002280204220320046b41074b0d00200241046a2004410810b18280800020022802042103200228020c21040b2002280208220620046a20052902003700002002200441086a220436020c200541086a28020021080240200320046b41034b0d00200241046a2004410410b18280800020022802082106200228020c21040b200620046a20083600002002200441046a220436020c2005410c6a22052007470d000b0b200128023021050240200228020420046b41034b0d00200241046a2004410410b182808000200228020c21040b200228020820046a20053600002002200441046a220436020c20012d00342105024020022802042004470d00200241046a2004410110b182808000200228020c21040b200228020820046a20053a0000200041086a200441016a36020020002002290204370200200241206a2480808080000f0b10ae80808000000b4101200510b280808000000b811004047f027e057f027e2380808080004190026b2202248080808000024002402001280200220328020422044120490d002003200441606a36020420032003280200220441206a360200200241206a41086a200441086a290000370300200241206a41106a200441106a290000370300200241206a41186a200441186a29000037030020022004290000370320024002402001280200220328020422044108490d002003200441786a36020420032003280200220441086a3602002001280200220328020422054120490d01200429000021062003200541606a36020420032003280200220441206a360200200241a0016a41086a200441086a290000370300200241a0016a41106a200441106a290000370300200241a0016a41186a200441186a290000370300200220042900003703a001200241106a200110be8a8080002002290310a70d012001280200220328020422044120490d01200229031821072003200441606a36020420032003280200220441206a360200200241c0016a41086a200441086a290000370300200241c0016a41106a200441106a290000370300200241c0016a41186a200441186a290000370300200220042900003703c0012001280200220328020422044120490d012003200441606a36020420032003280200220441206a360200200241e0016a41086a200441086a290000370300200241e0016a41106a200441106a290000370300200241e0016a41186a200441186a290000370300200220042900003703e00120024184026a20011094878080002002280284022208418080808078460d0120024180016a41086a200241a0016a41086a220929030037030020024180016a41106a200241a0016a41106a220a29030037030020024180016a41186a200241a0016a41186a220b290300370300200241e0006a41086a200241c0016a41086a290300370300200241e0006a41106a200241c0016a41106a290300370300200241e0006a41186a200241c0016a41186a290300370300200220022903a00137038001200220022903c001370360200228028c022105200228028802210c200241c0006a41186a200241e0016a41186a290300370300200241c0006a41106a200241e0016a41106a290300370300200241c0006a41086a200241e0016a41086a290300370300200220022903e00137034002402001280200220328020422044120490d002003200441606a36020420032003280200220441206a3602002009200441086a290000370300200a200441106a290000370300200b200441186a290000370300200220042900003703a0012002200110be8a8080002002290300a70d002001280200220328020422044120490d002002290308210d2003200441606a36020420032003280200220441206a360200200241c0016a41086a200441086a290000370300200241c0016a41106a200441106a290000370300200241c0016a41186a200441186a290000370300200220042900003703c0012001280200220328020422044120490d002003200441606a36020420032003280200220441206a360200200241e0016a41086a200441086a290000370300200241e0016a41106a200441106a290000370300200241e0016a41186a200441186a290000370300200220042900003703e00120024184026a20011094878080002002280284022201418080808078460d00200229028802210e200020022903a0013700a001200020022903c0013700c801200041b8016a200241a0016a41186a290300370000200041b0016a200241a0016a41106a290300370000200041a8016a200241a0016a41086a290300370000200041d0016a200241c0016a41086a290300370000200041d8016a200241c0016a41106a290300370000200041e0016a200241c0016a41186a290300370000200020022903e0013700e801200041f0016a200241e0016a41086a290300370000200041f8016a200241e0016a41106a29030037000020004180026a200241e0016a41186a2903003700002000200e37028c0220002001360288022000200d3703c00120002002290320370000200041086a200241206a41086a290300370000200041106a200241206a41106a290300370000200041186a200241206a41186a2903003700002000200229038001370328200041306a20024180016a41086a290300370300200041386a20024180016a41106a290300370300200041c0006a20024180016a41186a29030037030020002007370348200041e8006a200241e0006a41186a290300370300200041e0006a200241e0006a41106a290300370300200041d8006a200241e0006a41086a2903003703002000200229036037035020004188016a200241c0006a41186a29030037030020004180016a200241c0006a41106a290300370300200041f8006a200241c0006a41086a2903003703002000200229034037037020002005360298012000200c360294012000200836029001200020063703200c040b20004180808080783602880202402005450d00200c2101410021030340200c200341146c6a21040240024002400240024020012d00000e0400010102040b200141086a21040c020b200441086a21040c010b200441046a21040b2004280200450d00200428020441002802c0a3c68000118080808000000b200341016a2103200141146a21012005417f6a22050d000b0b2008450d03200c41002802c0a3c68000118080808000000c030b2000418080808078360288020c020b2000418080808078360288020c010b2000418080808078360288020b20024190026a2480808080000b21002001280214419c88c68000410f200141186a28020028020c118280808000000b180020002802002001200028020428020c118380808000000bc80601097f2000280200210102400240024020002802202202450d0020002802042103034020002002417f6a220236022002400240024002400240024002402001450d0020030d0020002802082104200028020c2205450d03200541077122060d01200521030c020b2001450d04200028020c210620002802082105200321040c030b2005210303402003417f6a210320042802bc0221042006417f6a22060d000b0b20054108490d00034020042802bc022802bc022802bc022802bc022802bc022802bc022802bc022802bc022104200341786a22030d000b0b2000420037020820002004360204410121012000410136020041002106410021050b02400240200620042f01ba02490d00034020042802b0012203450d0220042f01b8022106200441002802c0a3c6800011808080800000200541016a210520032104200620032f01ba024f0d000b200321040b200641016a2107024020050d00200421030c030b200420074102746a41bc026a2802002103410021072005417f6a2208450d022005417e6a2109024020084107712205450d0003402008417f6a210820032802bc0221032005417f6a22050d000b0b20094107490d02034020032802bc022802bc022802bc022802bc022802bc022802bc022802bc022802bc022103200841786a22080d000c030b0b200441002802c0a3c6800011808080800000418cd0c2800010a081808000000b41d887c6800010a081808000000b2000200736020c2000410036020820002003360204024020042006410c6c6a41b4016a2205280200450d00200528020441002802c0a3c68000118080808000000b0240200420064104746a2204280200450d00200428020441002802c0a3c68000118080808000000b20020d000b200041003602000c010b200041003602002001450d01200028020422030d0020002802082103200028020c2205450d0002400240200541077122060d00200521040c010b2005210403402004417f6a210420032802bc0221032006417f6a22060d000b0b20054108490d00034020032802bc022802bc022802bc022802bc022802bc022802bc022802bc022802bc022103200441786a22040d000b0b034020032802b0012104200341002802c0a3c68000118080808000002004210320040d000b0b0b02000b02000bba0402037f017e23808080800041a0026b22022480808080000240024002400240024002400240200028020022030d002002410c6a200141cc0010848e8080001a2002410a6a200141cf006a2d00003a0000200220012f004d3b010820012d004c2101410021040c010b200241d0016a20032000280204200110c48580800020022802d001450d01200241d8016a290200210520022802d40121042002410c6a200141cc0010848e8080001a2002410a6a200141cf006a2d00003a0000200220012f004d3b010820012d004c21010b41012103200141ff01714102460d03200220003602642002200537025c20022004360258200241e8006a2002410c6a41cc0010848e8080002103200241b7016a200241086a41026a2d00003a0000200220013a00b401200220022f01083b00b50120040d0141002d00fca3c680001a41f80641002802c8a3c68000118180808000002201450d04200141013b01f606200141003602f0062001200341d00010fe8d80800021012000428080808010370204200020013602000c020b41012103200141c8006a2802004129490d02200128022041002802c0a3c68000118080808000000c020b200241b8016a41086a200241d8006a41086a280200360200200220022902583703b801200241d0016a200341d00010848e8080001a200241c4016a200241b8016a200241d0016a200241e4006a10be8580800020022802642201200128020841016a3602080b410021030b200241a0026a24808080800020030f0b410441f80610b280808000000bfe0504027f017e097f017e23808080800041d0006b22042480808080000240024002400240200128020022050d002002290204210620022802002107410021050c010b20022802082108200228020421092001280204210a02400340200541b4016a210720052f01ba02220b410c6c210c417f210d0240024003400240200c0d00200b210d0c020b200741086a210e200741046a210f200c41746a210c200d41016a210d2007410c6a2107417f2009200f2802002008200e280200220e2008200e491b10888e808000220f2008200e6b200f1b220e410047200e4100481b220e4101460d000b200e41ff0171450d010b200a450d02200a417f6a210a2005200d4102746a41bc026a28020021050c010b0b2004200a36024420042005360240200429034021062002280200450d02200941002802c0a3c68000118080808000000c020b2004200d360248200441003602442002280200210720022902042106200429024421100b02402007418080808078470d002001210d0c010b200420103702202004200536021c20042001360218200420063702102004200736020c02400240024020050d0041002d00fca3c680001a41bc0241002802c8a3c68000118180808000002207450d02200741013b01ba02200741003602b0012007200429020c3702b4012004410c6a41086a280200210c20072003290200370200200741086a200341086a290200370200200741bc016a200c3602002001428080808010370204200120073602000c010b200441286a41086a2004411c6a220741086a28020036020020042007290200370328200441c0006a41086a2004410c6a41086a2802003602002004200429020c370340200441346a200441286a200441c0006a2003200441186a10bf8580800020042802182207200728020841016a3602080b200041063a00000c020b410441bc0210b280808000000b20002006a7200d4104746a220729020037020020072003290200370200200041086a200741086a22072902003702002007200341086a2902003702000b200441d0006a2480808080000bc20803097f017e017f23808080800041c0046b2203248080808000200320013602940220034100360290022003200236028c0220034198026a2003418c026a108f8d80800002400240024020032802a0042204418080808078460d0020032802ac04210120032802a804210520032802a404210620032802b003210720032802ac03210820032802a803210920032003418c026a10bc8a808000024020032802000d00200341b4046a2003418c026a200328020410d08580800020032802b404220a418080808078470d020b02402007450d00200821024100210103402008200141146c6a210b0240024002400240024020022d00000e0400010102040b200241086a210b0c020b200b41086a210b0c010b200b41046a210b0b200b280200450d00200b28020441002802c0a3c68000118080808000000b200141016a2101200241146a21022007417f6a22070d000b0b02402009450d00200841002802c0a3c68000118080808000000b02402005450d00200621024100210103402006200141146c6a21070240024002400240024020022d00000e0400010102040b200241086a21070c020b200741086a21070c010b200741046a21070b2007280200450d00200728020441002802c0a3c68000118080808000000b200141016a2101200241146a21022005417f6a22050d000b0b2004450d00200641002802c0a3c68000118080808000000b2000418080808078360288020c010b20033502bc04210c20032802b804210d200341f8006a20034198026a41900110848e8080001a2003410c6a200341b4036a41ec0010848e8080001a02402002280204450d0020004180808080783602880202402007450d00200821024100210103402008200141146c6a210b0240024002400240024020022d00000e0400010102040b200241086a210b0c020b200b41086a210b0c010b200b41046a210b0b200b280200450d00200b28020441002802c0a3c68000118080808000000b200141016a2101200241146a21022007417f6a22070d000b0b02402009450d00200841002802c0a3c68000118080808000000b02402005450d00200621024100210103402006200141146c6a21070240024002400240024020022d00000e0400010102040b200241086a21070c020b200741086a21070c010b200741046a21070b2007280200450d00200728020441002802c0a3c68000118080808000000b200141016a2101200241146a21022005417f6a22050d000b0b02402004450d00200641002802c0a3c68000118080808000000b200a450d01200d41002802c0a3c68000118080808000000c010b2000200341f8006a41900110848e8080002202200736029801200220083602940120022009360290012002419c016a2003410c6a41ec0010848e8080001a2002200c3703a0022002200d36029c022002200a36029802200220013602940220022005360290022002200636028c0220022004360288020b200341c0046a2480808080000b810c03027f017e037f2380808080004190036b2203248080808000200320013602bc01200341003602b801200320023602b401024002400240200228020422014120490d002002200141606a36020420022002280200220141206a360200200341a0026a41086a200141086a290000370300200341a0026a41106a200141106a290000370300200341a0026a41186a200141186a290000370300200320012900003703a002200341186a200341b4016a10be8a8080002003290318a70d0020032802b401220128020422044120490d00200329032021052001200441606a36020420012001280200220441206a360200200341c0026a41086a200441086a290000370300200341c0026a41106a200441106a290000370300200341c0026a41186a200441186a290000370300200320042900003703c00220032802b401220128020422044120490d002001200441606a36020420012001280200220441206a360200200341e0026a41086a200441086a290000370300200341e0026a41106a200441106a290000370300200341e0026a41186a200441186a290000370300200320042900003703e002200341106a200341b4016a10bc8a80800020032802100d0020034184036a200341b4016a200328021410c7858080002003280284032206418080808078460d0020034180026a41086a200341a0026a41086a29030037030020034180026a41106a200341a0026a41106a29030037030020034180026a41186a200341a0026a41186a290300370300200341e0016a41086a200341c0026a41086a290300370300200341e0016a41106a200341c0026a41106a290300370300200341e0016a41186a200341c0026a41186a290300370300200320032903a00237038002200320032903c0023703e001200328028c0321042003280288032107200341c0016a41186a200341e0026a41186a290300370300200341c0016a41106a200341e0026a41106a290300370300200341c0016a41086a200341e0026a41086a290300370300200320032903e0023703c001200341086a200341b4016a10bc8a808000024020032802080d00200341e0026a200341b4016a200328020c10cc8580800020032802e0022201418080808078470d020b02402004450d00200721024100210103402007200141146c6a21080240024002400240024020022d00000e0400010102040b200241086a21080c020b200841086a21080c010b200841046a21080b2008280200450d00200828020441002802c0a3c68000118080808000000b200141016a2101200241146a21022004417f6a22040d000b0b2006450d00200741002802c0a3c68000118080808000000b20004180808080783602780c010b200341286a41086a20034180026a41086a290300370300200341286a41106a20034180026a41106a290300370300200341286a41186a20034180026a41186a290300370300200341d8006a200341e0016a41086a290300370300200341e0006a200341e0016a41106a290300370300200341e8006a200341e0016a41186a290300370300200320032903800237032820032005370348200320032903e00137035020032902e402210520034188016a200341c0016a41186a29030037030020034180016a200341c0016a41106a290300370300200341f8006a200341c0016a41086a290300370300200320063602900120032007360294012003200436029801200320032903c001370370200320013602a001200320053702a40102402002280204450d00200041808080807836027802402004450d00200721024100210103402007200141146c6a21000240024002400240024020022d00000e0400010102040b200241086a21000c020b200041086a21000c010b200041046a21000b2000280200450d00200028020441002802c0a3c68000118080808000000b200141016a2101200241146a21022004417f6a22040d000b0b200341a0016a210202402006450d00200741002802c0a3c68000118080808000000b2002108f8780800020032802a001450d0120032802a40141002802c0a3c68000118080808000000c010b2000200341286a41880110848e8080001a0b20034190036a2480808080000be61003027f017e047f23808080800041d0046b2203248080808000200320013602d401200341003602d001200320023602cc0102400240200228020422014120490d002002200141606a36020420022002280200220141206a360200200341e0036a41086a200141086a290000370300200341e0036a41106a200141106a290000370300200341e0036a41186a200141186a290000370300200320012900003703e003200341206a200341cc016a10be8a8080002003290320a70d0020032802cc01220128020422044120490d00200329032821052001200441606a36020420012001280200220441206a36020020034180046a41086a200441086a29000037030020034180046a41106a200441106a29000037030020034180046a41186a200441186a290000370300200320042900003703800420032802cc01220128020422044120490d002001200441606a36020420012001280200220441206a360200200341a0046a41086a200441086a290000370300200341a0046a41106a200441106a290000370300200341a0046a41186a200441186a290000370300200320042900003703a004200341186a200341cc016a10bc8a80800020032802180d00200341c4046a200341cc016a200328021c10c78580800020032802c4042206418080808078460d00200341c0036a41086a200341e0036a41086a290300370300200341c0036a41106a200341e0036a41106a290300370300200341c0036a41186a200341e0036a41186a290300370300200341a0036a41086a20034180046a41086a290300370300200341a0036a41106a20034180046a41106a290300370300200341a0036a41186a20034180046a41186a290300370300200320032903e0033703c00320032003290380043703a00320032802cc04210420032802c804210720034180036a41186a200341a0046a41186a29030037030020034180036a41106a200341a0046a41106a29030037030020034180036a41086a200341a0046a41086a290300370300200320032903a00437038003200341106a200341cc016a10bc8a8080000240024020032802100d00200341a0046a200341cc016a200328021410cc8580800020032802a0042201418080808078470d010b02402004450d00200721024100210103402007200141146c6a21080240024002400240024020022d00000e0400010102040b200241086a21080c020b200841086a21080c010b200841046a21080b2008280200450d00200828020441002802c0a3c68000118080808000000b200141016a2101200241146a21022004417f6a22040d000b0b2006450d01200741002802c0a3c68000118080808000000c010b200341f8016a41086a200341c0036a41086a290300370300200341f8016a41106a200341c0036a41106a290300370300200341f8016a41186a200341c0036a41186a290300370300200341a8026a200341a0036a41086a290300370300200341b0026a200341a0036a41106a290300370300200341b8026a200341a0036a41186a290300370300200320032903c0033703f8012003200537039802200320032903a0033703a00220032902a4042105200341d8026a20034180036a41186a290300370300200341d0026a20034180036a41106a290300370300200341c8026a20034180036a41086a290300370300200320063602e002200320073602e402200320043602e80220032003290380033703c002200320013602f002200320053702f402200341086a200341cc016a10bc8a8080000240024020032802080d00200328020c2109200320032802d00141016a22083602d001200820032802d4014b0d00200341003a00c003200320093602a804200341003602a4042003200341cc016a3602a0042003200341c0036a3602ac0420034180046a200341a0046a10d28c80800020032d00c003450d0120034180046a10d38c808000200320032802d001417f6a3602d0010b02402004450d00200721024100210103402007200141146c6a21080240024002400240024020022d00000e0400010102040b200241086a21080c020b200841086a21080c010b200841046a21080b2008280200450d00200828020441002802c0a3c68000118080808000000b200141016a2101200241146a21022004417f6a22040d000b0b200341f0026a210202402006450d00200741002802c0a3c68000118080808000000b2002108f8780800020032802f002450d0120032802f40241002802c0a3c68000118080808000000c010b200341e0036a41086a20034180046a41086a2802002204360200200341ec016a2004360200200320032902800422053703e003200320053702e401200341306a200341f8016a41f80010848e8080001a200341d8016a41086a2204200341f4026a220841086a280200360200200341bc016a200341e8016a290300370200200341c4016a200341f0016a280200360200200341b4016a20042903003702002003200829020022053703d801200320053702ac01200320013602a80102402002280204450d0020004180808080783602782003419c016a28020021080240200341a0016a2802002204450d00200821024100210103402008200141146c6a21000240024002400240024020022d00000e0400010102040b200241086a21000c020b200041086a21000c010b200041046a21000b2000280200450d00200028020441002802c0a3c68000118080808000000b200141016a2101200241146a21022004417f6a22040d000b0b200341306a41f8006a21020240200328029801450d00200841002802c0a3c68000118080808000000b2002108f87808000024020032802a801450d0020032802ac0141002802c0a3c68000118080808000000b200341b8016a10d38c8080000c020b2000200341306a41980110848e8080001a0c010b20004180808080783602780b200341d0046a2480808080000bd60f02137f037e2380808080004180026b220224808080800041002d00fca3c680001a024002400240024002400240410141002802c8a3c68000118180808000002203450d00200341003a0000200241186a2204419380c6800041014100280298a3c6800011858080800000200241146a4100360200200242013702082002200336020420024101360200024020012802002203450d0020012802082205450d00200241ac016a210620024188016a41146a21072002418c016a2108200241d8006a41106a21092002410c6a210a2001280204210b410021010340024002402001450d00200b210c2003210d200121030c010b4100210c0240200b450d00200b21010240200b410771220d450d0003402001417f6a2101200328028c012103200d417f6a220d0d000b0b200b4108490d000340200328028c0128028c0128028c0128028c0128028c0128028c0128028c0128028c012103200141786a22010d000b0b4100210d0b0240200c20032f018a01490d00034020032802002201450d05200d41016a210d20032f018801210c20012103200c20012f018a014f0d000b0b200c41016a210b02400240200d0d00200321010c010b2003200b4102746a418c016a28020021014100210b200d417f6a220e450d00200d417e6a210f0240200e410771220d450d000340200e417f6a210e200128028c012101200d417f6a220d0d000b0b200f4107490d000340200128028c0128028c0128028c0128028c0128028c0128028c0128028c0128028c012101200e41786a220e0d000b0b2003200c410c6c6a220c41086a2802002103024002400240200c410c6a2802002210450d002010417f4c0d0741002d00fca3c680001a201041002802c8a3c6800011818080800000220c450d0a200c2003201010848e808000210c2002280204210d0240024020102002280208220e460d00200c41002802c0a3c68000118080808000000c010b200c200d201010888e808000210f200c41002802c0a3c6800011808080800000200f450d030b200241386a200320104100280298a3c680001185808080000041002d00fca3c680001a201041002802c8a3c68000118180808000002211450d0820112003201010848e80800021032010200e470d012003200d201010888e8080000d01200341002802c0a3c68000118080808000000c020b2002280208450d01200241386a200341004100280298a3c6800011858080800000410121110b200241d8006a41186a200241386a41186a290200370300200241d8006a41106a200241386a41106a290200370300200241d8006a41086a200241386a41086a29020037030020022002290238370358024002400240200228020c220f0d004100210f200241386a21030c010b200228021021120340200f41dc026a210c200f2f01960422134105742114417f210d4100210302400340024020142003470d002013210d0c020b200f20036a210e200341206a2103200d41016a210d200c41106a210c417f200241d8006a200e412010888e808000220e410047200e4100481b220e4101460d000b200e41ff0171450d030b02402012450d002012417f6a2112200f200d4102746a4198046a280200210f0c010b0b200dad4220862115200241d8006a21030b200720092902002216370200200241f8006a41086a200941086a2902002217370300200741086a201737020020022002280264360298012002200a36028801200220153702b0012002200f3602ac012002201637037820022003280208360294012002200329020037028c01200241013602c401200220103602c001200220113602bc01200220103602b8010240200f0d0041002d00fca3c680001a41980441002802c8a3c68000118180808000002203450d09200841086a2900002115200841106a2900002116200841186a290000211720032008290000370000200341186a2017370000200341106a2016370000200341086a2015370000200341013b0196042003410036029004200320022902b8013702e002200341e8026a200241b8016a41086a29020037020020024280808080103702102002200336020c0c020b200241c8016a41086a200641086a280200360200200220062902003703c801200241e0016a41186a200841186a290000370300200241e0016a41106a200841106a290000370300200241e0016a41086a200841086a290000370300200220082900003703e001200241d4016a200241c8016a200241e0016a200241b8016a20024188016a10bd858080002002280288012203200328020841016a3602080c010b0240200c280200220341004a0d000240200c41746a220d280200450d00200c41786a28020041002802c0a3c6800011808080800000200c28020021030b200d2010360200200c200341016a360200200c417c6a2010360200200c41786a20113602000c010b200c200341016a3602002010450d00201141002802c0a3c68000118080808000000b410021032005417f6a22050d000b0b20002002290200370200200041306a200241306a290200370200200041286a200241286a290200370200200041206a200241206a290200370200200041186a2004290200370200200041106a200241106a290200370200200041086a200241086a29020037020020024180026a2480808080000f0b4101410110b280808000000b41e887c6800010a081808000000b10ae80808000000b4101201010b280808000000b410441980410b280808000000b4101201010b280808000000bea05010a7f23808080800041106b220324808080800002400240024002402001200041186a412010888e8080000d00410121010c010b200228020021040240024002402002280204220541216a22060d0020034201370208200320063602040c010b2006417f4c0d034100210741002d00fca3c680001a200641002802c8a3c68000118180808000002208450d042003410036020c20032008360208200320063602042005415f490d010b200341046a4100200510ab868080002003280204210620032802082108200328020c21070b200820076a2004200510848e8080001a2003200720056a220536020c024020022d0008450d00200241096a2d00002102024020052006470d00200341046a2006109c8680800020032802082108200328020c21050b200820056a20023a00002003200328020c41016a220536020c200328020421060b0240200620056b411f4b0d00200341046a2005412010ab8680800020032802042106200328020c21050b2003280208220920056a22022001290000370000200241086a200141086a290000370000200241106a200141106a290000370000200241186a200141186a29000037000002400240200028020c220a0d00410021010c010b200541206a2102200041106a280200210b0340200a417c6a2107200a41b4016a2101200a2f01ba02220c410c6c2105417f2108024002400340024020050d00200c21080c020b200141086a2100200141046a2104200541746a2105200841016a2108200741106a21072001410c6a2101417f2009200428020020022000280200220020022000491b10888e8080002204200220006b20041b220041004720004100481b22004101460d000b200041ff0171450d010b0240200b0d00410021010c030b200b417f6a210b200a20084102746a41bc026a280200210a0c010b0b200728020041004a21010b2006450d00200941002802c0a3c68000118080808000000b200341106a24808080800020010f0b10ae80808000000b4101200610b280808000000b1000200020012002200310e48c8080000b0e00200020012002109b8d8080000bac0901097f23808080800041206b220224808080800002400240024002400240024002400240024002400240024020012802042203450d0020012003417f6a36020420012001280200220441016a36020020042d00000e09010000000203040005000b200041053a00000c090b2002200110bd8a80800020022802000d042001280204220420022802042203490d0402400240024020030d00410121050c010b2003417f4c0d0b200341002802c8a3c68000118180808000002205450d01200541002003108a8e8080001a0b200520012802002206200310848e80800021052001200420036b3602042001200620036a36020020002003360204200041033a000020002003ad4220862005ad843702080c090b4101200310b280808000000b20034105490d0420012003417b6a3602042001200441056a360200200441046a2d00002105200441036a2d00002106200441026a2d0000210720042d00012104200241086a200110bd8a80800020022802080d0420012802042208200228020c2203490d0441012109024002402003450d002003417f4c0d0a200341002802c8a3c68000118180808000002209450d01200941002003108a8e8080001a0b20092001280200220a200310848e8080002109200041036a20063a0000200041026a20073a0000200020043a00012001200820036b3602042001200a20036a36020020002003360208200041013a0000200041046a20053a000020002003ad4220862009ad8437020c0c080b4101200310b280808000000b20034105490d0420012003417b6a3602042001200441056a360200200441046a2d00002105200441036a2d00002106200441026a2d0000210720042d00012104200241106a200110bd8a80800020022802100d042001280204220920022802142203490d0402400240024020030d00410121080c010b2003417f4c0d09200341002802c8a3c68000118180808000002208450d01200841002003108a8e8080001a0b20082001280200220a200310848e8080002108200041036a20063a0000200041026a20073a0000200020043a00012001200920036b3602042001200a20036a36020020002003360208200041023a0000200041046a20053a000020002003ad4220862008ad8437020c0c070b4101200310b280808000000b20034105490d0420012003417b6a3602042001200441056a360200200441046a2d00002105200441036a2d00002106200441026a2d0000210720042d00012104200241186a200110bd8a80800020022802180d0420012802042209200228021c2203490d0402400240024020030d00410121080c010b2003417f4c0d08200341002802c8a3c68000118180808000002208450d01200841002003108a8e8080001a0b20082001280200220a200310848e8080002108200041036a20063a0000200041026a20073a0000200020043a00012001200920036b3602042001200a20036a36020020002003360208200041003a0000200041046a20053a000020002003ad4220862008ad8437020c0c060b4101200310b280808000000b200041043a00000c040b200041053a00000c030b200041053a00000c020b200041053a00000c010b200041053a00000b200241206a2480808080000f0b10ae80808000000bc30602087f017e23808080800041306b220224808080800002400240024002400240024002400240024002400240200128020022032802042204450d0020032004417f6a36020420032003280200220441016a36020020042d00000e09010000000203040005000b200041053a00000c090b2002200110bc8a80800020022802000d04200241246a2001200228020410d08580800020022802242203418080808078460d042000200229022837020820002003360204200041033a00000c080b2001280200220328020422054104490d042003280200220441036a2d0000210620042d0002210720042d0001210820042d000021092003200441046a36020020032005417c6a360204200241086a200110bc8a80800020022802080d04200241246a2001200228020c10d08580800020022802242203418080808078460d042002290228210a200041026a20083a0000200020093a00012000200a37020c20002003360208200041013a0000200041036a20073a0000200041046a20063a00000c070b2001280200220328020422054104490d042003280200220441036a2d0000210620042d0002210720042d0001210820042d000021092003200441046a36020020032005417c6a360204200241106a200110bc8a80800020022802100d04200241246a2001200228021410d08580800020022802242203418080808078460d042002290228210a200041026a20083a0000200020093a00012000200a37020c20002003360208200041023a0000200041036a20073a0000200041046a20063a00000c060b2001280200220328020422054104490d042003280200220441036a2d0000210620042d0002210720042d0001210820042d000021092003200441046a36020020032005417c6a360204200241186a200110bc8a80800020022802180d04200241246a2001200228021c10d08580800020022802242203418080808078460d042002290228210a200041026a20083a0000200020093a00012000200a37020c20002003360208200041003a0000200041036a20073a0000200041046a20063a00000c050b200041043a00000c040b200041053a00000c030b200041053a00000c020b200041053a00000c010b200041053a00000b200241306a2480808080000b21002001280214419c88c68000410f200141186a28020028020c118280808000000bd10a01077f024020002802002201450d0020002802042102024002400240200028020822030d00200121000c010b410021000340024002402000450d002001210420022105200021010c010b4100210402402002450d0020022100024020024107712205450d0003402000417f6a210020012802e40c21012005417f6a22050d000b0b20024108490d00034020012802e40c2802e40c2802e40c2802e40c2802e40c2802e40c2802e40c2802e40c2101200041786a22000d000b0b410021050b024002400240200520012f01e20c490d0003402001280288022200450d0220012f01e00c2105200141002802c0a3c6800011808080800000200441016a210420002101200520002f01e20c4f0d000b200021010b200541016a2102024020040d00200121000c020b200120024102746a41e40c6a2802002100410021022004417f6a2206450d012004417e6a2107024020064107712204450d0003402006417f6a210620002802e40c21002004417f6a22040d000b0b20074107490d01034020002802e40c2802e40c2802e40c2802e40c2802e40c2802e40c2802e40c2802e40c2100200641786a22060d000c020b0b200141002802c0a3c6800011808080800000418cd0c2800010a081808000000b02402001200541186c6a2204280200450d00200428020441002802c0a3c68000118080808000000b0240200428020c450d00200441106a28020041002802c0a3c68000118080808000000b2001200541fc006c6a2205418c026a21010240024020054184036a280200220541054b0d002005450d010240200128020c2204418080808078460d002004450d00200141106a28020041002802c0a3c68000118080808000000b02402001280200450d00200128020441002802c0a3c68000118080808000000b20054101460d010240200141246a2802002204418080808078460d002004450d00200141286a28020041002802c0a3c68000118080808000000b02402001280218450d002001411c6a28020041002802c0a3c68000118080808000000b20054102460d0102402001413c6a2802002204418080808078460d002004450d00200141c0006a28020041002802c0a3c68000118080808000000b02402001280230450d00200141346a28020041002802c0a3c68000118080808000000b20054103460d010240200141d4006a2802002204418080808078460d002004450d00200141d8006a28020041002802c0a3c68000118080808000000b02402001280248450d00200141cc006a28020041002802c0a3c68000118080808000000b20054104460d010240200141ec006a2802002205418080808078460d002005450d00200141f0006a28020041002802c0a3c68000118080808000000b2001280260450d01200141e4006a28020041002802c0a3c68000118080808000000c010b20012802002106024020012802042205450d0020062101034002402001410c6a2802002204418080808078460d002004450d00200141106a28020041002802c0a3c68000118080808000000b02402001280200450d00200141046a28020041002802c0a3c68000118080808000000b200141186a21012005417f6a22050d000b0b200641002802c0a3c68000118080808000000b410021012003417f6a22030d000b20000d01410021000b2002450d0002400240200241077122050d00200221010c010b2002210103402001417f6a210120002802e40c21002005417f6a22050d000b0b20024108490d00034020002802e40c2802e40c2802e40c2802e40c2802e40c2802e40c2802e40c2802e40c2100200141786a22010d000b0b03402000280288022101200041002802c0a3c68000118080808000002001210020010d000b0b0ba511010e7f024020002802002201450d0020002802042102024002400240200028020822030d00200121040c010b410021040340024002402004450d002001210520022106200421010c010b4100210502402002450d0020022100024020024107712206450d0003402000417f6a210020012802ac0921012006417f6a22060d000b0b20024108490d00034020012802ac092802ac092802ac092802ac092802ac092802ac092802ac092802ac092101200041786a22000d000b0b410021060b024002400240200620012f01aa09490d00034020012802a0082200450d0220012f01a8092106200141002802c0a3c6800011808080800000200541016a210520002101200620002f01aa094f0d000b200021010b200641016a2102024020050d00200121040c020b200120024102746a41ac096a2802002104410021022005417f6a2200450d012005417e6a2107024020004107712205450d0003402000417f6a210020042802ac0921042005417f6a22050d000b0b20074107490d01034020042802ac092802ac092802ac092802ac092802ac092802ac092802ac092802ac092104200041786a22000d000c020b0b200141002802c0a3c6800011808080800000418cd0c2800010a081808000000b024020012006410c6c6a41a4086a2200280200450d00200028020441002802c0a3c68000118080808000000b2001200641e0006c6a220810a38d80800002400240200828020c220941054b0d002009450d01200841106a210a4100210b03400240200a200b410c6c6a22002802002201450d002000280204210c024002402000280208220d450d00410021000340024002402000450d0020012105200c2106200021010c010b410021050240200c450d00200c21000240200c4107712206450d0003402000417f6a2100200128028c0121012006417f6a22060d000b0b200c4108490d000340200128028c0128028c0128028c0128028c0128028c0128028c0128028c0128028c012101200041786a22000d000b0b410021060b024002400240200620012f018a01490d00034020012802002200450d0220012f0188012106200141002802c0a3c6800011808080800000200541016a210520002101200620002f018a014f0d000b200021010b200641016a210c024020050d00200121000c020b2001200c4102746a418c016a28020021004100210c2005417f6a2207450d012005417e6a210e024020074107712205450d0003402007417f6a2107200028028c0121002005417f6a22050d000b0b200e4107490d010340200028028c0128028c0128028c0128028c0128028c0128028c0128028c0128028c012100200741786a22070d000c020b0b200141002802c0a3c6800011808080800000418cd0c2800010a081808000000b024020012006410c6c6a41046a2201280200450d00200128020441002802c0a3c68000118080808000000b41002101200d417f6a220d0d000c020b0b0240200c0d00200121000c010b02400240200c41077122060d0020012100200c21010c010b20012100200c210103402001417f6a2101200028028c0121002006417f6a22060d000b0b200c4108490d000340200028028c0128028c0128028c0128028c0128028c0128028c0128028c0128028c012100200141786a22010d000b0b034020002802002101200041002802c0a3c68000118080808000002001210020010d000b0b200b41016a220b2009470d000c020b0b200828021021090240200841146a280200220a450d004100210b034002402009200b410c6c6a22002802002201450d002000280204210c024002402000280208220d450d00410021000340024002402000450d0020012105200c2106200021010c010b410021050240200c450d00200c21000240200c4107712206450d0003402000417f6a2100200128028c0121012006417f6a22060d000b0b200c4108490d000340200128028c0128028c0128028c0128028c0128028c0128028c0128028c0128028c012101200041786a22000d000b0b410021060b024002400240200620012f018a01490d00034020012802002200450d0220012f0188012106200141002802c0a3c6800011808080800000200541016a210520002101200620002f018a014f0d000b200021010b200641016a210c024020050d00200121000c020b2001200c4102746a418c016a28020021004100210c2005417f6a2207450d012005417e6a210e024020074107712205450d0003402007417f6a2107200028028c0121002005417f6a22050d000b0b200e4107490d010340200028028c0128028c0128028c0128028c0128028c0128028c0128028c0128028c012100200741786a22070d000c020b0b200141002802c0a3c6800011808080800000418cd0c2800010a081808000000b024020012006410c6c6a41046a2201280200450d00200128020441002802c0a3c68000118080808000000b41002101200d417f6a220d0d000c020b0b0240200c0d00200121000c010b02400240200c41077122060d0020012100200c21010c010b20012100200c210103402001417f6a2101200028028c0121002006417f6a22060d000b0b200c4108490d000340200028028c0128028c0128028c0128028c0128028c0128028c0128028c0128028c012100200141786a22010d000b0b034020002802002101200041002802c0a3c68000118080808000002001210020010d000b0b200b41016a220b200a470d000b0b200941002802c0a3c68000118080808000000b02402008280254450d00200841d8006a28020041002802c0a3c68000118080808000000b410021012003417f6a22030d000b20040d01410021040b2002450d0002400240200241077122000d00200221010c010b2002210103402001417f6a210120042802ac0921042000417f6a22000d000b0b20024108490d00034020042802ac092802ac092802ac092802ac092802ac092802ac092802ac092802ac092104200141786a22010d000b0b034020042802a0082101200441002802c0a3c68000118080808000002001210420010d000b0b0bba0501077f024020002802002201450d00200028020421020240024020002802082203450d00410021000340024002402000450d002001210420022105200021010c010b4100210402402002450d0020022100024020024107712205450d0003402000417f6a210020012802ac1421012005417f6a22050d000b0b20024108490d00034020012802ac142802ac142802ac142802ac142802ac142802ac142802ac142802ac142101200041786a22000d000b0b410021050b024002400240200520012f01aa14490d00034020012802a0132200450d0220012f01a8142105200141002802c0a3c6800011808080800000200441016a210420002101200520002f01aa144f0d000b200021010b200541016a2102024020040d00200121000c020b200120024102746a41ac146a2802002100410021022004417f6a2206450d012004417e6a2107024020064107712204450d0003402006417f6a210620002802ac1421002004417f6a22040d000b0b20074107490d01034020002802ac142802ac142802ac142802ac142802ac142802ac142802ac142802ac142100200641786a22060d000c020b0b200141002802c0a3c6800011808080800000418cd0c2800010a081808000000b024020012005410c6c6a41a4136a2204280200450d00200428020441002802c0a3c68000118080808000000b2001200541e0016c6a108e87808000410021012003417f6a22030d000c020b0b024020020d00200121000c010b02400240200241077122050d0020012100200221010c010b200121002002210103402001417f6a210120002802ac1421002005417f6a22050d000b0b20024108490d00034020002802ac142802ac142802ac142802ac142802ac142802ac142802ac142802ac142100200141786a22010d000b0b034020002802a0132101200041002802c0a3c68000118080808000002001210020010d000b0b0ba60601097f2000280200210102400240024020002802202202450d0020002802042103034020002002417f6a220236022002400240024002400240024002402001450d0020030d0020002802082104200028020c2205450d03200541077122060d01200521030c020b2001450d04200028020c210620002802082105200321040c030b2005210303402003417f6a210320042802f80621042006417f6a22060d000b0b20054108490d00034020042802f8062802f8062802f8062802f8062802f8062802f8062802f8062802f8062104200341786a22030d000b0b2000420037020820002004360204410121012000410136020041002106410021050b02400240200620042f01f606490d00034020042802f0062203450d0220042f01f4062106200441002802c0a3c6800011808080800000200541016a210520032104200620032f01f6064f0d000b200321040b200641016a2107024020050d00200421030c030b200420074102746a41f8066a2802002103410021072005417f6a2208450d022005417e6a2109024020084107712205450d0003402008417f6a210820032802f80621032005417f6a22050d000b0b20094107490d02034020032802f8062802f8062802f8062802f8062802f8062802f8062802f8062802f8062103200841786a22080d000c030b0b200441002802c0a3c6800011808080800000418cd0c2800010a081808000000b41d887c6800010a081808000000b2000200736020c200041003602082000200336020402402004200641d0006c6a220441c8006a2802004129490d00200441206a28020041002802c0a3c68000118080808000000b20020d000b200041003602000c010b200041003602002001450d01200028020422030d0020002802082103200028020c2205450d0002400240200541077122060d00200521040c010b2005210403402004417f6a210420032802f80621032006417f6a22060d000b0b20054108490d00034020032802f8062802f8062802f8062802f8062802f8062802f8062802f8062802f8062103200441786a22040d000b0b034020032802f0062104200341002802c0a3c68000118080808000002004210320040d000b0b0bab0501077f024020002802002201450d00200028020421020240024020002802082203450d00410021000340024002402000450d002001210420022105200021010c010b4100210402402002450d0020022100024020024107712205450d0003402000417f6a210020012802980421012005417f6a22050d000b0b20024108490d000340200128029804280298042802980428029804280298042802980428029804280298042101200041786a22000d000b0b410021050b024002400240200520012f019604490d0003402001280290042200450d0220012f0194042105200141002802c0a3c6800011808080800000200441016a210420002101200520002f0196044f0d000b200021010b200541016a2102024020040d00200121000c020b200120024102746a4198046a2802002100410021022004417f6a2206450d012004417e6a2107024020064107712204450d0003402006417f6a210620002802980421002004417f6a22040d000b0b20074107490d010340200028029804280298042802980428029804280298042802980428029804280298042100200641786a22060d000c020b0b200141002802c0a3c6800011808080800000418cd0c2800010a081808000000b0240200120054104746a41e0026a2201280200450d00200128020441002802c0a3c68000118080808000000b410021012003417f6a22030d000c020b0b024020020d00200121000c010b02400240200241077122050d0020012100200221010c010b200121002002210103402001417f6a210120002802980421002005417f6a22050d000b0b20024108490d000340200028029804280298042802980428029804280298042802980428029804280298042100200141786a22010d000b0b03402000280290042101200041002802c0a3c68000118080808000002001210020010d000b0b0ba80501077f024020002802002201450d00200028020421020240024020002802082203450d00410021000340024002402000450d002001210420022105200021010c010b4100210402402002450d0020022100024020024107712205450d0003402000417f6a2100200128028c0121012005417f6a22050d000b0b20024108490d000340200128028c0128028c0128028c0128028c0128028c0128028c0128028c0128028c012101200041786a22000d000b0b410021050b024002400240200520012f018a01490d00034020012802002200450d0220012f0188012105200141002802c0a3c6800011808080800000200441016a210420002101200520002f018a014f0d000b200021010b200541016a2102024020040d00200121000c020b200120024102746a418c016a2802002100410021022004417f6a2206450d012004417e6a2107024020064107712204450d0003402006417f6a2106200028028c0121002004417f6a22040d000b0b20074107490d010340200028028c0128028c0128028c0128028c0128028c0128028c0128028c0128028c012100200641786a22060d000c020b0b200141002802c0a3c6800011808080800000418cd0c2800010a081808000000b024020012005410c6c6a41046a2201280200450d00200128020441002802c0a3c68000118080808000000b410021012003417f6a22030d000c020b0b024020020d00200121000c010b02400240200241077122050d0020012100200221010c010b200121002002210103402001417f6a2101200028028c0121002005417f6a22050d000b0b20024108490d000340200028028c0128028c0128028c0128028c0128028c0128028c0128028c0128028c012100200141786a22010d000b0b034020002802002101200041002802c0a3c68000118080808000002001210020010d000b0b0bca0501077f024020002802002201450d00200028020421020240024020002802082203450d00410021000340024002402000450d002001210420022105200021010c010b4100210402402002450d0020022100024020024107712205450d0003402000417f6a210020012802900221012005417f6a22050d000b0b20024108490d000340200128029002280290022802900228029002280290022802900228029002280290022101200041786a22000d000b0b410021050b024002400240200520012f018e02490d0003402001280288022200450d0220012f018c022105200141002802c0a3c6800011808080800000200441016a210420002101200520002f018e024f0d000b200021010b200541016a2102024020040d00200121000c020b200120024102746a4190026a2802002100410021022004417f6a2206450d012004417e6a2107024020064107712204450d0003402006417f6a210620002802900221002004417f6a22040d000b0b20074107490d010340200028029002280290022802900228029002280290022802900228029002280290022100200641786a22060d000c020b0b200141002802c0a3c6800011808080800000418cd0c2800010a081808000000b02402001200541186c6a2201280200450d00200128020441002802c0a3c68000118080808000000b0240200128020c450d00200141106a28020041002802c0a3c68000118080808000000b410021012003417f6a22030d000c020b0b024020020d00200121000c010b02400240200241077122050d0020012100200221010c010b200121002002210103402001417f6a210120002802900221002005417f6a22050d000b0b20024108490d000340200028029002280290022802900228029002280290022802900228029002280290022100200141786a22010d000b0b03402000280288022101200041002802c0a3c68000118080808000002001210020010d000b0b0bfb0401057f024020002802002201450d00200028020421020240024020002802082203450d00410021000340024002402000450d0020012104200021010c010b4100210402402002450d0020022100024020024107712205450d0003402000417f6a210020012802e80221012005417f6a22050d000b0b20024108490d00034020012802e8022802e8022802e8022802e8022802e8022802e8022802e8022802e8022101200041786a22000d000b0b410021020b024002400240200220012f01e602490d00034020012802e0022200450d0220012f01e4022102200141002802c0a3c6800011808080800000200441016a210420002101200220002f01e6024f0d000b200021010b200241016a2102024020040d00200121000c020b200120024102746a41e8026a2802002100410021022004417f6a2201450d012004417e6a2105024020014107712204450d0003402001417f6a210120002802e80221002004417f6a22040d000b0b20054107490d01034020002802e8022802e8022802e8022802e8022802e8022802e8022802e8022802e8022100200141786a22010d000c020b0b200141002802c0a3c6800011808080800000418cd0c2800010a081808000000b410021012003417f6a22030d000c020b0b024020020d00200121000c010b02400240200241077122040d0020012100200221010c010b200121002002210103402001417f6a210120002802e80221002004417f6a22040d000b0b20024108490d00034020002802e8022802e8022802e8022802e8022802e8022802e8022802e8022802e8022100200141786a22010d000b0b034020002802e0022101200041002802c0a3c68000118080808000002001210020010d000b0b0bc40501077f024020002802002201450d00200028020421020240024020002802082203450d00410021000340024002402000450d002001210420022105200021010c010b4100210402402002450d0020022100024020024107712205450d0003402000417f6a210020012802900221012005417f6a22050d000b0b20024108490d000340200128029002280290022802900228029002280290022802900228029002280290022101200041786a22000d000b0b410021050b024002400240200520012f018e02490d0003402001280288022200450d0220012f018c022105200141002802c0a3c6800011808080800000200441016a210420002101200520002f018e024f0d000b200021010b200541016a2102024020040d00200121000c020b200120024102746a4190026a2802002100410021022004417f6a2206450d012004417e6a2107024020064107712204450d0003402006417f6a210620002802900221002004417f6a22040d000b0b20074107490d010340200028029002280290022802900228029002280290022802900228029002280290022100200641786a22060d000c020b0b200141002802c0a3c6800011808080800000418cd0c2800010a081808000000b200120054103746a220141b0016a2802002205200141b4016a28020022012802001180808080000002402001280204450d00200541002802c0a3c68000118080808000000b410021012003417f6a22030d000c020b0b024020020d00200121000c010b02400240200241077122050d0020012100200221010c010b200121002002210103402001417f6a210120002802900221002005417f6a22050d000b0b20024108490d000340200028029002280290022802900228029002280290022802900228029002280290022100200141786a22010d000b0b03402000280288022101200041002802c0a3c68000118080808000002001210020010d000b0b0bca08010a7f23808080800041306b22012480808080002000280200210202400240024020002802202203450d0020002802042104034020002003417f6a220336022002400240024002400240024002402002450d0020040d0020002802082105200028020c2206450d03200641077122070d01200621040c020b2002450d04200028020c210720002802082106200421050c030b2006210403402004417f6a210420052802bc0221052007417f6a22070d000b0b20064108490d00034020052802bc022802bc022802bc022802bc022802bc022802bc022802bc022802bc022105200441786a22040d000b0b2000420037020820002005360204410121022000410136020041002107410021060b02400240200720052f01ba02490d00034020052802b0012204450d0220052f01b8022107200541002802c0a3c6800011808080800000200641016a210620042105200720042f01ba024f0d000b200421050b200741016a2108024020060d00200521040c030b200520084102746a41bc026a2802002104410021082006417f6a2209450d022006417e6a210a024020094107712206450d0003402009417f6a210920042802bc0221042006417f6a22060d000b0b200a4107490d02034020042802bc022802bc022802bc022802bc022802bc022802bc022802bc022802bc022104200941786a22090d000c030b0b200541002802c0a3c6800011808080800000418cd0c2800010a081808000000b41d887c6800010a081808000000b2000200836020c2000410036020820002004360204024020052007410c6c6a41b4016a2206280200450d00200628020441002802c0a3c68000118080808000000b02400240024002400240200520074104746a22052d00000e050404010203000b02400240200528020422070d0041002105410021060c010b2005410c6a28020021062001200541086a28020022053602282001200736022420014100360220200120053602182001200736021420014100360210410121050b2001200636022c2001200536021c2001200536020c2001410c6a10aa8d8080000c030b2005280204450d02200541086a28020041002802c0a3c68000118080808000000c020b2005280204450d01200541086a28020041002802c0a3c68000118080808000000c010b200541046a1091878080002005280204450d00200541086a28020041002802c0a3c68000118080808000000b20030d000b200041003602000c010b200041003602002002450d01200028020422040d0020002802082104200028020c2206450d0002400240200641077122070d00200621050c010b2006210503402005417f6a210520042802bc0221042007417f6a22070d000b0b20064108490d00034020042802bc022802bc022802bc022802bc022802bc022802bc022802bc022802bc022104200541786a22050d000b0b034020042802b0012105200441002802c0a3c68000118080808000002005210420050d000b0b200141306a2480808080000bc50601097f2000280200210102400240024020002802202202450d0020002802042103034020002002417f6a220236022002400240024002400240024002402001450d0020030d0020002802082104200028020c2205450d03200541077122060d01200521030c020b2001450d04200028020c210620002802082105200321040c030b2005210303402003417f6a210320042802900221042006417f6a22060d000b0b20054108490d000340200428029002280290022802900228029002280290022802900228029002280290022104200341786a22030d000b0b2000420037020820002004360204410121012000410136020041002106410021050b02400240200620042f018e02490d00034020042802002203450d0220042f018c022106200441002802c0a3c6800011808080800000200541016a210520032104200620032f018e024f0d000b200321040b200641016a2107024020050d00200421030c030b200420074102746a4190026a2802002103410021072005417f6a2208450d022005417e6a2109024020084107712205450d0003402008417f6a210820032802900221032005417f6a22050d000b0b20094107490d020340200328029002280290022802900228029002280290022802900228029002280290022103200841786a22080d000c030b0b200441002802c0a3c6800011808080800000418cd0c2800010a081808000000b41d887c6800010a081808000000b2000200736020c2000410036020820002003360204024020042006410c6c6a220441046a2206280200450d00200628020441002802c0a3c68000118080808000000b024020044188016a2204280200450d00200428020441002802c0a3c68000118080808000000b20020d000b200041003602000c010b200041003602002001450d01200028020422030d0020002802082103200028020c2205450d0002400240200541077122060d00200521040c010b2005210403402004417f6a210420032802900221032006417f6a22060d000b0b20054108490d000340200328029002280290022802900228029002280290022802900228029002280290022103200441786a22040d000b0b034020032802002104200341002802c0a3c68000118080808000002004210320040d000b0b0be10e04147f017e047f017e2380808080004180016b2202248080808000200128020c21032001410036020c200141146a2204280200210520044100360200200141106a280200210620022005410020031b2204360254200220063602502002200336024c20024100360248200220034100472207360244200220063602402002200336023c200241003602382002200736023402400240024002402004450d002000410c6a2108200241046a41106a2109200241046a410c6a210a41002104034020022005417f6a22053602540240024002402007450d002004450d010b20070d0141d887c6800010a081808000000b0240024020060d00200321040c010b024002402006410771220b0d00200321042006210c0c010b200321042006210c0340200c417f6a210c20042802bc022104200b417f6a220b0d000b0b20064108490d00034020042802bc022802bc022802bc022802bc022802bc022802bc022802bc022802bc022104200c41786a220c0d000b0b2002420037023c20022004360238410121072002410136023441002106410021030b024002400240200620042f01ba02490d00034020042802b001220c450d0220042f01b8022106200441002802c0a3c6800011808080800000200341016a2103200c21042006200c2f01ba024f0d000b200c21040b2004210b2006220d41016a2106024020030d00200b21040c020b200b20064102746a41bc026a2802002104410021062003417f6a220c450d012003417e6a210e0240200c4107712203450d000340200c417f6a210c20042802bc0221042003417f6a22030d000b0b200e4107490d01034020042802bc022802bc022802bc022802bc022802bc022802bc022802bc022802bc022104200c41786a220c0d000c020b0b200441002802c0a3c6800011808080800000418cd0c2800010a081808000000b200220063602402002410036023c20022004360238200b200d410c6c6a220341b4016a280200220f418080808078460d04200b200d4104746a220c28020c2110200c2802082111200c2802042112200c2802002113200341bc016a280200210b200341b8016a280200211402400240024002400240200828020022150d00200bad4220862014ad842116410021150c010b2000280210211702400340201541b4016a210c20152f01ba022218410c6c2103417f210e41002119024002400340024020030d002018210e0c020b200c41086a210d200c41046a211a200341746a2103201941106a2119200e41016a210e200c410c6a210c417f2014201a280200200b200d280200220d200b200d491b10888e808000221a200b200d6b201a1b220d410047200d4100481b220d4101460d000b200d41ff0171450d010b2017450d022017417f6a21172015200e4102746a41bc026a28020021150c010b0b2002201736022420022015360220200229032021160240200f450d00201441002802c0a3c68000118080808000000b2016a720196a220c417c6a2203280200220b417f4a0d020240200c41706a220d280200450d00200c41746a28020041002802c0a3c68000118080808000002003280200210b0b200d2013360200200c41786a2011360200200c41746a20123602002003200b20106a3602000c040b2002200e36022820024100360224200bad4220862014ad8421162002290224211b0b2002201b3702182002201536021420022008360210200220163702082002200f3602042002201036022c200220113602282002201236022420022013360220024020150d0041002d00fca3c680001a41bc0241002802c8a3c6800011818080800000220c450d02200c41013b01ba02200c41003602b001200c20022902043702b401200241046a41086a2802002103200c2002290220370200200c41086a200241206a41086a290200370200200c41bc016a200336020020004280808080103702102000200c36020c0c030b200241d8006a41086a200941086a28020036020020022009290200370358200241f0006a41086a200241046a41086a28020036020020022002290204370370200241e4006a200241d8006a200241f0006a200241206a200a10c0858080002002280210220c200c28020841016a3602080c020b2003200b20106a3602002013450d01201241002802c0a3c68000118080808000000c010b410441bc0210b280808000000b4100210320050d000b41002103200241003602342007450d032004450d010c020b200241003602342003450d020b024020060d00200321040c010b024002402006410771220b0d00200321042006210c0c010b200321042006210c0340200c417f6a210c20042802bc022104200b417f6a220b0d000b0b20064108490d00034020042802bc022802bc022802bc022802bc022802bc022802bc022802bc022802bc022104200c41786a220c0d000b0b034020042802b001210c200441002802c0a3c6800011808080800000200c2104200c0d000b0b200241346a10928d808000200241003602542002410036024420024100360234200241346a10928d80800002402001280200450d00200128020441002802c0a3c68000118080808000000b20024180016a2480808080000b1901017f23808080800041106b220120003a000f20012d000f0b3c01017f23808080800041106b22032480808080002003200239030820002001200341086a41ac88c6800010af8d808000200341106a2480808080000bd90402017f017e23808080800041c0006b22042480808080002004200336020c2004200236020802400240024002400240024020002d0004450d00200041003a000420012802102203200128020422024f0d04200128020020034103746a220128020021030240200128020422024107470d00200341d489c68000410710888e808000450d020b20002802002101200441106a410c6a4202370200200441286a410c6a41928480800036020020044102360214200441dc89c68000360210200441938480800036022c2004200236023c20042003360238200141186a28020021032004200441286a3602182004200441086a3602302004200441386a36022820012802142003200441106a10d9808080000d020c030b20012802102202200128020422034f0d0420002802002103200441106a410c6a4202370200200128020020024103746a2902002105200441286a410c6a41928480800036020020044102360214200441c489c6800036021020042005370238200441938480800036022c200341186a28020021012004200441286a3602182004200441086a3602302004200441386a36022820032802142001200441106a10d9808080000d010c020b200028020021012004411c6a4201370200200441013602142004418c89c68000360210200441928480800036022c200141186a28020021032004200441286a3602182004200441086a36022820012802142003200441106a10d980808000450d010b200041013a00050b200441c0006a2480808080000f0b2003200241e88ec6800010f980808000000b2002200341e88ec6800010f980808000000b3c01017f23808080800041106b22032480808080002003200237030820002001200341086a41bc88c6800010af8d808000200341106a2480808080000b3c01017f23808080800041106b22032480808080002003200237030820002001200341086a41cc88c6800010af8d808000200341106a2480808080000b3c01017f23808080800041106b2203248080808000200320023a000f200020012003410f6a41dc88c6800010af8d808000200341106a2480808080000b4001017f23808080800041106b2204248080808000200420033703082004200237030020002001200441ec88c6800010af8d808000200441106a2480808080000b4001017f23808080800041106b2204248080808000200420033703082004200237030020002001200441fc88c6800010af8d808000200441106a2480808080000b2d00024020002d00000d00200141a891c08000410510dd808080000f0b200141ad91c08000410410dd808080000b140020002802002000280204200110e2808080000b180020002802002001200028020428020c118380808000000b140020012000280200200028020410dd808080000b810302027f027e2380808080004180016b220224808080800002400240024002400240200128021c22034110710d0020034120710d01200029030022042004423f8722058520057d2004427f55200110fe8080800021000c020b20002903002104410021000340200220006a41ff006a413041d7002004a7410f712203410a491b20036a3a00002000417f6a210020044210542103200442048821042003450d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000c010b20002903002104410021000340200220006a41ff006a413041372004a7410f712203410a491b20036a3a00002000417f6a210020044210542103200442048821042003450d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000b20024180016a24808080800020000f0b200341800141c88dc08000109481808000000b200341800141c88dc08000109481808000000bf10202027f017e2380808080004180016b220224808080800002400240024002400240200128021c22034110710d0020034120710d0120002903004101200110fe8080800021000c020b20002903002104410021000340200220006a41ff006a413041d7002004a7410f712203410a491b20036a3a00002000417f6a210020044210542103200442048821042003450d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000c010b20002903002104410021000340200220006a41ff006a413041372004a7410f712203410a491b20036a3a00002000417f6a210020044210542103200442048821042003450d000b20004180016a22034180014b0d022001410141c48dc080004102200220006a4180016a410020006b10db8080800021000b20024180016a24808080800020000f0b200341800141c88dc08000109481808000000b200341800141c88dc08000109481808000000bfb0404027f027e037f017e2380808080004180016b22022480808080000240024002400240024002400240200128021c22034110710d0020034120710d014200200029030022047d2004200041086a290300220542005322001b420020052004420052ad7c7d200520001b2005427f55200110d48080800021000c050b200041086a290300210420002903002105418001210020024180016a21034100210603402000450d042003417f6a413041d7002005a72207410f712208410a491b20086a3a00002005421054410020045022081b0d022003417e6a2203413041d700200741ff0171220741a001491b20074104766a3a00002004423886210920054280025421072000417e6a210020044208882104200920054208888421052007410020081b0d030c000b0b200041086a290300210420002903002105418001210020024180016a21034100210602400240024003402000450d022003417f6a413041372005a72207410f712208410a491b20086a3a000002402005421054410020045022081b0d002003417e6a220341304137200741ff0171220741a001491b20074104766a3a00002004423886210920054280025421072000417e6a210020044208882104200920054208888421052007410020081b0d020c010b0b2000417f6a21000b20004180014b0d01200021060b2001410141c48dc080004102200220066a41800120066b10db8080800021000c040b200041800141c88dc08000109481808000000b2000417f6a21000b20004180014b0d02200021060b2001410141c48dc080004102200220066a41800120066b10db8080800021000b20024180016a24808080800020000f0b200041800141c88dc08000109481808000000bd80404027f027e037f017e2380808080004180016b22022480808080000240024002400240024002400240200128021c22034110710d0020034120710d012000290300200041086a2903004101200110d48080800021000c050b200041086a290300210420002903002105418001210020024180016a21034100210603402000450d042003417f6a413041d7002005a72207410f712208410a491b20086a3a00002005421054410020045022081b0d022003417e6a2203413041d700200741ff0171220741a001491b20074104766a3a00002004423886210920054280025421072000417e6a210020044208882104200920054208888421052007410020081b0d030c000b0b200041086a290300210420002903002105418001210020024180016a21034100210602400240024003402000450d022003417f6a413041372005a72207410f712208410a491b20086a3a000002402005421054410020045022081b0d002003417e6a220341304137200741ff0171220741a001491b20074104766a3a00002004423886210920054280025421072000417e6a210020044208882104200920054208888421052007410020081b0d020c010b0b2000417f6a21000b20004180014b0d01200021060b2001410141c48dc080004102200220066a41800120066b10db8080800021000c040b200041800141c88dc08000109481808000000b2000417f6a21000b20004180014b0d02200021060b2001410141c48dc080004102200220066a41800120066b10db8080800021000b20024180016a24808080800020000f0b200041800141c88dc08000109481808000000b02000b02000b02000b900202017f057e23808080800041e0006b22052480808080002005410c6a41386a42013702002005410c6a41306a4101360200200541346a20032802083602002005418c89c68000360238200541c0006a200541d0006a3602002005200329020037022c200041306a3502002106200041386a350200210720002902002108200035022c21092000350234210a200541a083808000360254200541013a005c200520043602582005200541d8006a360250200541246a200a200742208684370200200541186a2009200642208684370200200541024101200a501b3602202005410241012009501b3602142005200837020c20012005410c6a200228021011848080800000200541e0006a2480808080000bc50101047f23808080800041106b220224808080800041002103200241003a000d200220002d00043a000c200220013602080240200028020022012802042204450d0020012802002100200128020828020821052004410c6c210303400240200028020022012802082005470d00200041046a2802002204450d0020042001200241086a419489c68000200041086a28020028020c118680808000000b2000410c6a2100200341746a22030d000b20022d000d41004721030b200241106a24808080800020030bef0101017f23808080800041306b22042480808080002004200336020c20042002360208024020012802102203200128020422024f0d00024002400240200128020020034103746a22032802044107470d00200328020041d489c68000410710888e808000450d010b20002001200441086a41ec89c6800010af8d8080000c010b2004411c6a4201370200200441013602142004418c89c68000360210200441938480800036022c2004200441286a3602182004200441086a36022820002001200441106a41fc89c6800010af8d8080000b200441306a2480808080000f0b2003200241e88ec6800010f980808000000b8b0201067f2380808080004180016b2202248080808000200128020421032001280200210420002802002802002100200128021c2205210602402005410471450d002005410872210620040d0020014281808080a0013702000b2001200641047236021c410021060340200220066a41ff006a413041d7002000410f712207410a491b20076a3a00002006417f6a210620004110492107200041047621002007450d000b024020064180016a22004180014d0d00200041800141c88dc08000109481808000000b2001410141c48dc080004102200220066a4180016a410020066b10db8080800021002001200536021c200120033602042001200436020020024180016a24808080800020000b02000bfc0201047f23808080800041206b220124808080800041012102200020002d00092203410120031b3a0009024002400240024020030d004100210302404100280294a4c680004102470d002000280200210441002802f4a3c68000210241002802f0a3c680002103024041002802eca3c68000450d002002280208417f6a41787120036a41086a21030b41022003200420022802101183808080000041ff0171220341004720034102461b21030b200020033a00084100280288a4c680002103034020002003360204200120033602002001200036020420032000460d04410020004100280288a4c680002202200220034622041b360288a4c68000200221032004450d000b200041023a00090c010b20034102470d010b4102410120002d000822034102461b410020031b21020b200141206a24808080800020020f0b200142003702142001418c8ac680003602102001410136020c200141888cc680003602084101200141046a2001200141086a41f88cc6800010d88d808000000b1c00200041024101200141ff017122014102461b410020011b3a00080b1a0020022001200041888dc680002003280228118680808000000b040041000b2a0020002001360204200020024293c3cef2b89ddac72285200342ebaebfe0a6e7f0cf028584503602000b060042adbd030b02000b02000b040041060b040041010b070020012903000b02000b0900200041023602000b040041000b02000b02000b040041000b02000b02000b4601017f23808080800041106b22052480808080002005200236020c200520013602082000200541086a41e48dc680002005410c6a41f48dc680002003200410fb80808000000bd40101057f23808080800041306b22022480808080000240200128020822034101762204200128020422054b0d00200128020021012002412c6a22064100360200200241046a200120046a200120056a10f58d8080002000412c6a2006280200360200200041246a200241246a2902003702002000411c6a2002411c6a290200370200200041146a200241146a2902003702002000410c6a2002410c6a2902003702002000200229020437020420002003410171360200200241306a2480808080000f0b2004200541e491c68000109481808000000bb20601067f23808080800041306b220324808080800020012802002104024002400240024002400240024002400240024002400240024020012802042205410174200128020822016b20024d0d0020014101762106200120026a2207410176210820074101710d0320082006490d06200820054b0d07200420066a2105200820066b22024129490d0141002d00fca3c680001a200241002802c8a3c68000118180808000002204450d0820042005200210848e8080002105200041086a2002360200200020053602040c020b2001410176220220054b0d04200341286a220641003602002003200420026a200420056a10f58d8080002000412c6a2006280200360200200041246a200341206a2902003702002000411c6a200341186a290200370200200041146a200341106a2902003702002000410c6a200341086a29020037020020002003290200370204200020014101713602000c030b200041046a2005200210848e8080001a0b200020014101713602002000412c6a20023602000c010b200841016a22072006490d05200820054f0d06200420066a210402400240200720066b22054129490d002005417f4c0d0941002d00fca3c680001a200541002802c8a3c68000118180808000002206450d0a20062004200510848e8080002104200341086a2005360200200320043602040c010b200341046a2004200510848e8080001a0b2003412c6a22042005360200200320014101713602002003200241017110e88d8080001a024020034108412c200428020041284b1b6a22012802002202450d0020012002417f6a3602000b20002003290200370200200041286a200341286a290200370200200041206a200341206a290200370200200041186a200341186a290200370200200041106a200341106a290200370200200041086a200341086a2902003702000b200341306a2480808080000f0b2002200541e491c68000109481808000000b2006200841f491c68000109681808000000b2008200541f491c68000109581808000000b4101200210b280808000000b20062007418492c68000109681808000000b20072005418492c68000109581808000000b10ae80808000000b4101200510b280808000000bc204010a7f0240024002400240024002400240024020002802082202410171220320012802082204410171460d0002402000280204220541017420026b22032001280204220641017420046b220720032007491b22080d0041000f0b200128020021092000280200210a410021030340200220036a2200410176220120054f0d03200420036a220b410176220720064f0d04200a20016a2d00002201410f71200141047620004101711b200920076a2d00002201410f712001410476200b4101711b470d022008200341016a2203470d000b20080f0b200441017621042002410176210b200028020421024100210502402003450d00200b20024f0d042004200128020422034f0d0541002103200128020020046a2d00002000280200200b6a2d000073410f710d0141012105200441016a2104200b41016a210b0b2002200b490d05200128020422032004490d06200128020020046a21012000280200200b6a2100410221072002200b6b220b200320046b2203200b2003491b220421030340024020030d00200441017420056a0f0b2003417f6a21032007417e6a210720012d0000210b20002d00002102200041016a2100200141016a21012002200b460d000b200b20027341104920076b20056a21030b20030f0b2001200541e890c6800010f980808000000b2007200641e890c6800010f980808000000b200b2002419492c6800010f980808000000b2004200341a492c6800010f980808000000b200b200241c492c68000109481808000000b2004200341b492c68000109481808000000bb10101047f200128020822024101762103200128020421042001280200210502400240024020024101710d00410021020240200320044b0d0020032101410021030c020b2003200441d492c68000109481808000000b200320044f0d0141012102200341016a2101200520036a2d0000410f7121030b200020033a000d200020023a000c200041003602082000200420016b3602042000200520016a3602000f0b2003200441e492c6800010f980808000000bbf0101027f20012802082202410176210302400240024020024101710d002003200128020422024b0d01200041003a000820002003360204200020012802003602000f0b2003200128020422024b0d010240200320024f0d0020012802002101200041013a00082000200336020420002001360200200041096a200120036a2d000041f001713a00000f0b20032002419493c6800010f980808000000b2003200241f492c68000109581808000000b20032002418493c68000109581808000000bda02010b7f23808080800041106b2202248080808000410021030240024020002802042204410174200028020822056b200128022c2206490d002001280228210702402006410171450d002000280200210820012802002001200741284b22001b21092001280204200720001b210a410021010340200620014622030d020240200520016a2207410176220020044f0d00200a2001410176220b4d0d042001410171210c200141016a2101200820006a2d00002200410f71200041047620074101711b2009200b6a2d00002200410f712000410476200c1b460d010c030b0b2000200441e890c6800010f980808000000b2001280204210b2001280200210c2002410036020c2002200c2001200741284b22031b3602042002200b200720031b22013602082000200241046a10db8d80800020014101744621030b200241106a24808080800020030f0b200b200a418c94c6800010f980808000000be902010c7f23808080800041106b22022480808080004100210302400240024020002802042204410174200028020822056b2206200128022c470d002001280204210702402006410171450d00200128020020012001280228220841284b22091b210a2007200820091b210b2000280200210c410021010340200141016a220020064b22030d02200520016a2208410176220720044f0d03200b200141017622094d0d042001410171210d20002101200a20096a2d00002200410f712000410476200d1b200c20076a2d00002200410f71200041047620084101711b460d000c020b0b2001280200210920012802282108410021032002410036020c200220092001200841284b220d1b360204200220072008200d1b220136020820062001410174470d002000200241046a10db8d80800020064621030b200241106a24808080800020030f0b2007200441e890c6800010f980808000000b2009200b418c94c6800010f980808000000b8d0301087f024002402001450d000240200028022c220220014d0d00200041046a2103200041286a21040240200220016b22054101762202200541017122066a2207200028020420002802282201200141284b1b22014f0d0020012002417f736a210802402001200220056a6b410171450d00200741016a210720032004200428020041284b1b22022802002209450d0020022009417f6a3602000b20082006460d00200120076b21010340024020032004200428020041284b1b22022802002207450d0020022007417f6a3602000b024020032004200428020041284b1b22022802002207450d0020022007417f6a3602000b2001417e6a22010d000b0b2000200536022c2006450d01200328020020042802002204200441284b22011b2204417f6a210320040d0220034100419c95c6800010f980808000000b0240200041044128200028022841284b22041b6a280200450d00200041046a200041286a20041b41003602000b2000410036022c0b0f0b2000280200200020011b20036a220420042d000041f001713a00000be805010c7f0240200128022c2202450d0002400240200028022c22034101710d00200128020420012802282203200341284b22031b2204450d012001280200200120031b2103200041046a2105200041286a2106034020032d00002107024002402000410441282000280228220841284b22011b6a28020022092008412820011b460d002005200620011b21082000280200200020011b21010c010b200010f78d8080002000280204210920002802002101200521080b200120096a20073a00002008200828020041016a360200200341016a21032004417f6a22040d000c020b0b024002400240200028020420002802282208200841284b1b2209200341017622044d0d00200128020420012802282209200941284b1b2206450d01200041046a2105200041286a210a200320026a410171210b20002802002000200841284b1b20046a220320012802002001200941284b1b220c2d000041047620032d000041f00171723a000002402006417f6a220d450d0041002101034020062001460d04200c20016a22032d00002104200341016a2d00002107024002402000410441282000280228220841284b22031b6a28020022092008412820031b460d002005200a20031b21082000280200200020031b21030c010b200010f78d8080002000280204210920002802002103200521080b200320096a20044104742007410476410f71723a00002008200828020041016a360200200d200141016a2201470d000b0b200b450d03200c200d6a2d00004104742108024002402000410441282000280228220941284b22011b6a28020022032009412820011b460d002005200a20011b21052000280200200020011b21010c010b200010f78d80800020002802042103200028020021010b200120036a20083a00002005200528020041016a3602000c030b2004200941dc95c6800010f980808000000b4100410041ec95c6800010f980808000000b2006200641fc95c6800010f980808000000b2000200028022c20026a36022c0b0be808010b7f23808080800041106b2202248080808000200141086a2802002103200128020421040240024002400240024002400240024020012d00004101460d00200028022c21050c010b20012d0001410f7121060240024020002d002c4101710d00200041046a210120064104742107024002402000410441282000280228220841284b22061b6a28020022052008412820061b460d002001200041286a20061b21012000280200200020061b21060c010b200010f78d80800020002802042105200028020021060b200620056a20073a00002001200128020041016a3602000c010b200028020420002802282201200141284b22011b2205450d0220052000280200200020011b6a417f6a220120012d00002006723a00000b2000200028022c41016a220536022c0b200041046a2109200041286a210a024002402000280204220720002802282206200641284b22081b22014101742005470d0002402006412820081b20016b20034f0d00200120036a22062001490d044100417f2006417f6a677620064102491b41016a2206450d04200241086a2000200610f68d808000024020022802082206418180808078460d002006450d052006200228020c10b280808000000b20092802002107200a28020021060b20072006200641284b22051b22062001490d042000280200200020051b20016a220520036a2005200620016b10fe8d8080001a20052004200310848e8080001a200041044128200028022841284b1b6a200620036a3602000c010b2003450d002001417f6a21052001450d0420002802002000200641284b1b20056a220120012d000041f001713a0000200028020420002802282201200141284b22011b220620054d0d052000280200200020011b20056a220120012d000020042d000041f00171410476723a000002402003417f6a220b450d0041002101034020032001460d08200420016a22062d00002108200641016a2d0000210c024002402000410441282000280228220541284b22061b6a28020022072005412820061b460d002009200a20061b21052000280200200020061b21060c010b200010f78d8080002000280204210720002802002106200921050b200620076a2008410474200c410476410f71723a00002005200528020041016a360200200b200141016a2201470d000b0b2004200b6a2d00004104742105024002402000410441282000280228220741284b22011b6a28020022062007412820011b460d002009200a20011b21092000280200200020011b21010c010b200010f78d80800020002802042106200028020021010b200120066a20053a00002009200928020041016a3602000b2000200028022c20034101746a36022c200241106a2480808080000f0b419c94c68000413a41d894c6800010a181808000000b418ca0c68000411141a0a0c6800010f880808000000b41f88ec68000411e41f48fc6800010f880808000000b20054100418c96c6800010f980808000000b20052006419c96c6800010f980808000000b2003200341ac96c6800010f980808000000bec0301067f23808080800041106b2204248080808000024002400240024020010d00410021010c010b20012802082205410176210620012802042107200128020021080240024020054101710d00410021090240200620074b0d0020062101410021060c020b2006200741d492c68000109481808000000b200620074f0d0241012109200641016a2101200820066a2d0000410f7121060b2004410c6a200720016b360200200420063a0005200420093a00042004200820016a3602082000200441046a10e28d808000200741017420056b21010b02402002450d000240024020002d002c4101710d00200041046a210720034104742105024002402000410441282000280228220841284b22061b6a28020022022008412820061b460d002007200041286a20061b21072000280200200020061b21060c010b200010f78d80800020002802042102200028020021060b200620026a20053a00002007200728020041016a3602000c010b200028020420002802282207200741284b22071b2206450d0320062000280200200020071b6a417f6a220720072d00002003723a00000b2000200028022c41016a36022c200141016a21010b200441106a24808080800020010f0b2006200741e492c6800010f980808000000b419c94c68000413a41d894c6800010a181808000000bf303010a7f23808080800041306b220224808080800020024200370228200241286a210302400240024020012802042204410174220520012802082206460d00200520066b22054101200541014b1b2105200241046a2107200128020021084100210103402006410176220920044f0d02200820096a2d00002209410f71200941047620064101711b21090240024020014101710d002009410474210a024002402002410441282002280228220941284b22011b6a280200220b2009412820011b460d002007200320011b21092002280200200220011b21010c010b200210f78d8080002002280204210b20022802002101200721090b2001200b6a200a3a00002009200928020041016a3602000c010b200228020420022802282201200141284b22011b220b450d04200b2002280200200220011b6a417f6a220120012d00002009723a00000b2002200228022c41016a220136022c200641016a21062005417f6a22050d000b0b20002002290200370200200041286a2003290200370200200041206a200241206a290200370200200041186a200241186a290200370200200041106a200241106a290200370200200041086a200241086a290200370200200241306a2480808080000f0b2009200441e890c6800010f980808000000b419c94c68000413a41d894c6800010a181808000000b02000b2100200128021441f897c68000410b200141186a28020028020c118280808000000be70201087f20002001280200220220002802006a41017110e88d8080001a200141086a28020021030240024020020d00410021020c010b024002402003450d00200041086a2802002000412c6a2802002202200241284b22041b2202417f6a21052002450d012000280204200041046a20041b20056a220220022d000020012802042d0000410f71723a0000410121020c020b4100410041e498c6800010f980808000000b2005200241f498c6800010f980808000000b0240200320024d0d00200320026b2105200041086a21062000412c6a2104200041046a2107200128020420026a2101034020012d0000210802400240200620042004280200220941284b22031b220028020022022009412820031b460d002007280200200720031b21030c010b200710f78d8080002006280200210220072802002103200621000b200320026a20083a00002000200028020041016a360200200141016a21012005417f6a22050d000b0b0bc00501057f200028020021022000200136020002400240024002400240024002400240024002400240200220014b0d0041002103200220014f0d04200041086a2104200041046a210220004108412c2000412c6a2205280200220341284b22011b6a28020022062003412820011b460d012004200520011b21032000280204200220011b21010c020b200041046a21020240200041086a28020022032000412c6a2802002201200141284b1b2204417f6a2205450d004101210103402000280208200028022c2203200341284b22061b22032001417f6a4d0d06200320014d0d072002280200200220061b20016a2203417f6a220620062d000041047420032d0000410476410f71723a00002004200141016a2201470d000b20002802082103200028022c21010b20032001200141284b1b220020054d0d0620022802002002200141284b1b20056a220120012d00004104743a00000c020b200210f78d8080002004280200210620022802002101200421030b200120066a41003a00002003200328020041016a36020002402004280200220020052802002201200141284b1b22034102490d002003417f6a21010340200428020020052802002200200041284b22031b22002001417f6a22064d0d07200020014d0d082002280200200220031b20016a22002000417f6a2d000041047420002d0000410476410f71723a0000200141014b21002006210120000d000b20042802002100200528020021010b20002001200141284b22031b450d072002280200200220031b220120012d00004104763a00000b410121030b20030f0b2001417f6a200341889ac6800010f980808000000b2001200341989ac6800010f980808000000b2005200041f899c6800010f980808000000b2001417f6a200041a89ac6800010f980808000000b2001200041b89ac6800010f980808000000b4100410041e899c6800010f980808000000be40101037f23808080800041106b220324808080800002400240024020024100480d00200241f5ffffff074f0d0102402002410b6a417c7122040d00410421050c030b41002d00fca3c680001a200441002802c8a3c680001181808080000022050d024104200410b280808000000b41fc9bc68000412b2003410f6a41a89cc6800041b89cc68000108981808000000b41e484c08000412b2003410f6a419085c08000419086c08000108981808000000b2005428180808010370200200541086a2001200210848e8080001a2000200236020420002005360200200341106a2480808080000bae0101017f23808080800041306b2202248080808000200028020021002002410c6a4202370200200241186a410c6a41d08180800036020020022000280200220036022820024103360204200241f0bfc08000360200200241d18180800036021c200220006836022c200141186a28020021002002200241186a36020820022002412c6a3602202002200241286a36021820012802142000200210d9808080002101200241306a24808080800020010b9a0201027f23808080800041106b2202248080808000200220002802002200360204200128021441c89cc680004106200141186a28020028020c118280808000002103200241003a000d200220033a000c20022001360208200241086a41ce9cc680004104200041046a41d49cc68000108c8180800041e49cc680004105200241046a41ec9cc68000108c81808000210320022d000c21000240024020022d000d0d00200041ff017141004721010c010b41012101200041ff01710d000240200328020022012d001c4104710d0020012802144187a5c080004102200128021828020c1182808080000021010c010b20012802144186a5c080004101200128021828020c1182808080000021010b200241106a24808080800020010b140020012000280200200028020410dd808080000bed0201037f2380808080004180016b220224808080800002400240024002400240200128021c22034110710d0020034120710d0120003502004101200110fe8080800021000c020b20002802002100410021030340200220036a41ff006a413041d7002000410f712204410a491b20046a3a00002003417f6a210320004110492104200041047621002004450d000b20034180016a22004180014b0d022001410141c48dc080004102200220036a4180016a410020036b10db8080800021000c010b20002802002100410021030340200220036a41ff006a413041372000410f712204410a491b20046a3a00002003417f6a210320004110492104200041047621002004450d000b20034180016a22004180014b0d022001410141c48dc080004102200220036a4180016a410020036b10db8080800021000b20024180016a24808080800020000f0b200041800141c88dc08000109481808000000b200041800141c88dc08000109481808000000b02000b02000b6001017f23808080800041206b22002480808080002000410c6a420137020020004101360204200041e49bc68000360200200041bb8480800036021c200041dc9ac680003602182000200041186a360208200041d49bc6800010f680808000000b4c01027f024020002802002201417f460d0020002802042102200120012802042200417f6a36020420004101470d002002410b6a4104490d00200141002802c0a3c68000118080808000000b0b6001017f23808080800041206b22002480808080002000410c6a420137020020004101360204200041e49bc68000360200200041bb8480800036021c200041dc9ac680003602182000200041186a360208200041ec9bc6800010f680808000000b2100200128021441fc9cc68000410b200141186a28020028020c118280808000000b920f03067f017e017f23808080800041c0016b220424808080800002400240024002400240024002400240024002400240024002400240024002400240024002400240024002400240024020012802000e050200010304020b200141086a280200220520012802042206490d04200520034b0d05200141186a2802002107200141146a28020021082001410c6a28020021090240024020012802100d0020072008490d0841002101200720034d0d012007200341949ec68000109581808000000b20072008490d0841012101200720034b0d090b200020013602102000200220066a36020420004101360200200041186a200720086b360200200041146a200220086a3602002000410c6a2009360200200041086a200520066b3602000c160b200141086a280200220520012802042206490d08200520034b0d09200141186a2802002107200141146a28020021082001410c6a28020021090240024020012802100d0020072008490d0c41002101200720034d0d012007200341e49dc68000109581808000000b20072008490d0c41012101200720034b0d0d0b200020013602102000200220066a36020420004102360200200041186a200720086b360200200041146a200220086a3602002000410c6a2009360200200041086a200520066b3602000c150b200041003602000c140b200441023602b401200441023602a8012004410236029c0120044102360290012004410236028401200441023602782004410236026c2004410236026020044102360254200441023602482004410236023c2004410236023020044102360224200441023602182004410236020c20044102360200410021070340410221080240200120076a220541106a28020022094102460d00200541186a2802002106200541146a28020021050240024020090d0020062005490d0f41002108200620034d0d012006200341e49dc68000109581808000000b20062005490d0f41012108200620034b0d100b200620056bad422086200220056aad84210a0b200420076a22052008360200200541046a200a3702002007410c6a220741c001460d130c000b0b200441023602b401200441023602a8012004410236029c0120044102360290012004410236028401200441023602782004410236026c2004410236026020044102360254200441023602482004410236023c2004410236023020044102360224200441023602182004410236020c20044102360200410021070340410221080240200120076a2205411c6a28020022094102460d00200541246a2802002106200541206a28020021050240024020090d0020062005490d1141002108200620034d0d012006200341e49dc68000109581808000000b20062005490d1141012108200620034b0d120b200620056bad422086200220056aad84210a0b200420076a22052008360200200541046a200a3702002007410c6a220741c001460d110c000b0b2006200541849ec68000109681808000000b2005200341849ec68000109581808000000b2008200741949ec68000109681808000000b2008200741a49ec68000109681808000000b2007200341a49ec68000109581808000000b2006200541849ec68000109681808000000b2005200341849ec68000109581808000000b2008200741e49dc68000109681808000000b2008200741f49dc68000109681808000000b2007200341f49dc68000109581808000000b2005200641e49dc68000109681808000000b2005200641f49dc68000109681808000000b2006200341f49dc68000109581808000000b2005200641e49dc68000109681808000000b2005200641f49dc68000109681808000000b2006200341f49dc68000109581808000000b02400240024002400240200141086a280200220720012802042208490d00200720034b0d01410221052001410c6a280200210902402001280210220b4102460d00200141186a2802002106200141146a280200210102400240200b0d0020062001490d0541002105200620034d0d012006200341949ec68000109581808000000b20062001490d0541012105200620034b0d060b200620016bad422086200220016aad84210a0b2000200220086a3602042000410c6a2009360200200041086a200720086b360200200041106a200441c00110848e8080001a200041d4016a200a370200200020053602d001200041043602000c060b2008200741849ec68000109681808000000b2007200341849ec68000109581808000000b2001200641949ec68000109681808000000b2001200641a49ec68000109681808000000b2006200341a49ec68000109581808000000b410221070240024002400240200128020422054102460d002001410c6a2802002108200141086a28020021010240024020050d0020082001490d0341002107200820034d0d012008200341949ec68000109581808000000b20082001490d0341012107200820034b0d040b200820016bad422086200220016aad84210a0b200041046a200441c00110848e8080001a200041c8016a200a370200200020073602c401200041033602000c030b2001200841949ec68000109681808000000b2001200841a49ec68000109681808000000b2008200341a49ec68000109581808000000b200441c0016a2480808080000be10301077f23808080800041106b2203248080808000200041286a2104024002400240200028022822054128200541284b22061b22072000280204200520061b22066b200220016b22084f0d00200620086a22052006490d014100417f2005417f6a677620054102491b41016a2205450d01200341086a2000200510f68d808000024020032802082205418180808078460d002005450d022005200328020c10b280808000000b200428020022054128200541284b1b21070b200041046a22092004200541284b22061b21080240024020004104412820061b6a280200220520074f0d002000280200200020061b2106034020012002460d02200620056a20012d00003a0000200141016a21012007200541016a2205470d000b200721050b2008200536020020012002460d02034020012d00002108024002402000410441282000280228220741284b22051b6a28020022062007412820051b460d002009200420051b21072000280200200020051b21050c010b200010f78d8080002000280204210620002802002105200921070b200520066a20083a00002007200728020041016a360200200141016a22012002470d000c030b0b200820053602000c010b418ca0c68000411141a0a0c6800010f880808000000b200341106a2480808080000bc70301067f23808080800041106b220324808080800002400240024002400240200128020420012802282204200441284b22051b220620024b0d002004412820051b21072001280200200120051b2108024020024129490d00418180808078210520072002460d040240200241004e0d00410021050c060b02400240024020044129490d002007417f4a0d0120072102410021050c080b41002d00fca3c680001a200241002802c8a3c680001181808080000022040d01410121050c070b0240200241002802c8a3c680001181808080000022040d00410121050c070b200420082007200220072002491b10848e8080001a200841002802c0a3c68000118080808000000c040b20042008200610848e8080001a0c030b418180808078210520044129490d0320012008200610848e80800020063602282007417f4c0d01200841002802c0a3c68000118080808000000c030b41c0a0c68000412041e0a0c6800010f880808000000b2003200736020c2003410036020841e49ec68000412b200341086a41909fc6800041fc9fc68000108981808000000b2001200236022820012006360204200120043602000b0b2000200236020420002005360200200341106a2480808080000bb90101027f23808080800041106b220124808080800002400240200028020420002802282202200241284b1b41016a2202450d004100417f2002417f6a677620024102491b41016a2202450d00200141086a2000200210f68d808000024020012802082200418180808078460d002000450d022000200128020c10b280808000000b200141106a2480808080000f0b418ca0c68000411141b0a0c6800010a181808000000b418ca0c68000411141a0a0c6800010f880808000000b02000ba90201027f23808080800041106b22022480808080000240024020002802000d00200128021441b49ec680004110200141186a28020028020c1182808080000021010c010b20022000360204200128021441c49ec680004108200141186a28020028020c118280808000002100200241003a000d200220003a000c20022001360208200241086a41cc9ec680004106200241046a41d49ec68000108c81808000210320022d000c2100024020022d000d0d00200041ff017141004721010c010b41012101200041ff01710d000240200328020022012d001c4104710d0020012802144187a5c080004102200128021828020c1182808080000021010c010b20012802144186a5c080004101200128021828020c1182808080000021010b200241106a24808080800020010b9d0501087f23808080800041306b22022480808080000240024020012d002c4101710d0020012802002103200128020421042001280228210541002106200241046a41286a22074100360200200241046a20032001200541284b22081b220120012004200520081b6a10f58d8080002000412c6a2007280200360200200041246a200241246a2902003702002000411c6a2002411c6a290200370200200041146a200241146a2902003702002000410c6a2002410c6a290200370200200020022902043702040c010b02400240200128020420012802282206200641284b22061b2207450d00200241046a41046a2108200241046a41286a210920022001280200200120061b22032d00004104763a00042007417f6a2105200241046a410172210441002101034020052001460d01200420016a200320016a22062d0000410474200641016a2d0000410476410f71723a0000200141016a22014127470d000b2002412836022c20074129490d01200741586a2104200341286a210103402001417f6a2d000041047420012d0000410476410f7172210702400240200241046a41044128200228022c220541284b22061b6a28020022032005412820061b460d002008200920061b21052002280204200241046a20061b21060c010b200241046a10f78d8080002002280208210320022802042106200821050b200620036a20073a00002005200528020041016a360200200141016a21012004417f6a22040d000c020b0b2002200736022c0b200020022902043702042000412c6a2002412c6a280200360200200041246a200241246a2902003702002000411c6a2002411c6a290200370200200041146a200241146a2902003702002000410c6a2002410c6a290200370200410121060b20002006360200200241306a2480808080000b980605017f017e017f057e017f23808080800041206b2205248080808000024002400240024002402003500d002004500d010b420021062001200354200220045420022004511b0d012002500d01200541106a20032004200479a7200279a76b220741ff007110858e80800042012007413f71ad862108200541186a29030021092005290310210a4200210603400240200220097d2001200a54ad7d220b4200530d00200820068421062001200a7d2201200354200b200454200b2004511b0d04200b21020b200a4201882009423f8684210a20084201882108200942018821090c000b0b0240024002402002500d00024020022003540d0020022003510d022002200382210b2002200380210c024020034280808080105a0d00200b4220862001422088842209200380220a4220862009200382422086200142ffffffff0f83842201200380842106200a422088200c84210c200120038221014200210b0c070b2001200354200b200454200b2004511b0d032004423f8620034201888421092003423f86210a428080808080808080807f210242002104024003400240200b20097d2001200a54ad7d22084200530d002001200a7d2101200220048421042008500d022008210b0b200a4201882009423f8684210a20024201882102200942018821090c000b0b200120038020048421064200210b200120038221010c060b200520032004413f200379a72207200279a7220d6b41c0006a2007200d461b220710858e80800042012007413f71ad86210b200541086a29030021092005290300210a42002104024003400240200220097d2001200a54ad7d22084200530d002001200a7d2101200b20048421042008500d02200821020b200a4201882009423f8684210a200b420188210b200942018821090c000b0b200120038020048421064200210b200120038221010c040b200120038021064200210b200120038221010c030b200120028021064200210b4201210c200120028221010c030b420021060c020b2002210b0b4200210c0b2000200137031020002006370300200041186a200b3703002000200c370308200541206a2480808080000b4901017f23808080800041106b2204248080808000200420012002200310868e808000200429030021022000200441086a29030037030820002002370300200441106a2480808080000b6e01067e2000200342ffffffff0f832205200142ffffffff0f8322067e22072003422088220820067e22062005200142208822097e7c22054220867c220a3703002000200820097e2005200654ad4220862005422088847c200a200754ad7c200420017e200320027e7c7c3703080b0e0020002001200210818e8080000b4b01017f23808080800041206b22052480808080002005200120022003200410fb8d808000200529030021042000200541086a29030037030820002004370300200541206a2480808080000bc10201087f02400240200241104f0d00200021030c010b2000410020006b41037122046a210502402004450d0020002103200121060340200320062d00003a0000200641016a2106200341016a22032005490d000b0b2005200220046b2207417c7122086a210302400240200120046a2209410371450d0020084101480d012009410374220641187121022009417c71220a41046a2101410020066b4118712104200a28020021060340200520062002762001280200220620047472360200200141046a2101200541046a22052003490d000c020b0b20084101480d0020092101034020052001280200360200200141046a2101200541046a22052003490d000b0b20074103712102200920086a21010b02402002450d00200320026a21050340200320012d00003a0000200141016a2101200341016a22032005490d000b0b20000bac0501087f0240024002400240200020016b20024f0d00200120026a2103200020026a21040240200241104f0d00200021050c030b2004417c7121054100200441037122066b210702402006450d00200120026a417f6a210803402004417f6a220420082d00003a00002008417f6a210820052004490d000b0b2005200220066b2209417c7122066b21040240200320076a2207410371450d0020064101480d022007410374220841187121022007417c71220a417c6a2101410020086b4118712103200a280200210803402005417c6a2205200820037420012802002208200276723602002001417c6a210120042005490d000c030b0b20064101480d01200920016a417c6a210103402005417c6a220520012802003602002001417c6a210120042005490d000c020b0b02400240200241104f0d00200021040c010b2000410020006b41037122036a210502402003450d0020002104200121080340200420082d00003a0000200841016a2108200441016a22042005490d000b0b2005200220036b2209417c7122066a210402400240200120036a2207410371450d0020064101480d012007410374220841187121022007417c71220a41046a2101410020086b4118712103200a28020021080340200520082002762001280200220820037472360200200141046a2101200541046a22052004490d000c020b0b20064101480d0020072101034020052001280200360200200141046a2101200541046a22052004490d000b0b20094103712102200720066a21010b2002450d02200420026a21050340200420012d00003a0000200141016a2101200441016a22042005490d000c030b0b20094103712201450d012007410020066b6a2103200420016b21050b2003417f6a210103402004417f6a220420012d00003a00002001417f6a210120052004490d000b0b20000bb50101037f02400240200241104f0d00200021030c010b2000410020006b41037122046a210502402004450d00200021030340200320013a0000200341016a22032005490d000b0b2005200220046b2204417c7122026a2103024020024101480d00200141ff017141818284086c2102034020052002360200200541046a22052003490d000b0b200441037121020b02402002450d00200320026a21050340200320013a0000200341016a22032005490d000b0b20000b4a01037f4100210302402002450d000240034020002d0000220420012d00002205470d01200041016a2100200141016a21012002417f6a2202450d020c000b0b200420056b21030b20030b0e0020002001200210808e8080000b5701017e02400240200341c000710d002003450d0120022003413f71ad2204862001410020036b413f71ad88842102200120048621010c010b20012003413f71ad862102420021010b20002001370300200020023703080b5701017e02400240200341c000710d002003450d012002410020036b413f71ad8620012003413f71ad220488842101200220048821020c010b20022003413f71ad882101420021020b20002001370300200020023703080b4b01017f23808080800041106b22052480808080002005200120022003200410fd8d808000200529030021042000200541086a29030037030820002004370300200541106a2480808080000b0e0020002001200210838e8080000b4b01017f23808080800041106b22052480808080002005200120022003200410ff8d808000200529030021042000200541086a29030037030820002004370300200541106a2480808080000b0e0020002001200210828e8080000b0bb4a4060300418080c0000bf0a006010000000c000000040000000200000003000000040000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f7261775f7665632e72736361706163697479206f766572666c6f770000890010001100000018001000710000003a020000050000004572726f724c61796f75744572726f726d656d6f727920616c6c6f636174696f6e206f6620206279746573206661696c65640000c400100015000000d90010000d0000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f616c6c6f632e727300f80010006f000000a20100000d000000f80010006f000000a00100000d000000060000000c000000040000000700000008000000040000006120666f726d617474696e6720747261697420696d706c656d656e746174696f6e2072657475726e656420616e206572726f72000900000000000000010000000a0000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f666d742e7273000000e40110006d000000640200002000000063616c6c65642060526573756c743a3a756e77726170282960206f6e20616e2060457272602076616c7565000900000000000000010000000b0000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f73796e632e72730000a00210006e00000075010000320000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f61727261792d62797465732d362e322e322f7372632f6c69622e72730000200310005e0000000804000022000000200310005e000000080400004f0000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f627335382d302e352e312f7372632f6465636f64652e72730000a00310005a000000c00100000b000000a00310005a000000ac010000200000004c61796f75744572726f722f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f62797465732d312e362e302f7372632f62797465732e72730000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000120000001600000063616c6c65642060526573756c743a3a756e77726170282960206f6e20616e2060457272602076616c75650017000000000000000100000018000000270410005a0000002b04000032000000270410005a0000003904000049000000190000001a0000001b0000001c00000061626f72742f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f62797465732d312e362e302f7372632f6c69622e727300000025051000580000006e0000000900000066726f6d5f7374725f72616469785f696e743a206d757374206c696520696e207468652072616e676520605b322c2033365d60202d20666f756e6420900510003c0000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f6e756d2f6d6f642e7273d405100070000000a9050000050000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f666d742f6e756d2e7273307800005406100070000000690000001700000030623030303130323033303430353036303730383039313031313132313331343135313631373138313932303231323232333234323532363237323832393330333133323333333433353336333733383339343034313432343334343435343634373438343935303531353235333534353535363537353835393630363136323633363436353636363736383639373037313732373337343735373637373738373938303831383238333834383538363837383838393930393139323933393439353936393739383939617373657274696f6e206661696c65643a202a63757272203e20313900005406100070000000ef010000050000001e0000000c000000040000001f00000020000000210000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f666d742f6d6f642e727330303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030e807100070000000f20500001f00000066616c736574727565000000e807100070000000350900001a000000e8071000700000002e0900002200000070616e69636b6564206174203a0a2f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f6e756d2f6269676e756d2e7273000000e208100073000000ac01000001000000617373657274696f6e206661696c65643a206e6f626f72726f77617373657274696f6e206661696c65643a20646967697473203c203430617373657274696f6e206661696c65643a206f74686572203e20302f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f6e756d2f666c74326465632f6d6f642e7273617373657274696f6e206661696c65643a20216275662e69735f656d707479282900ba09100078000000bc00000005000000617373657274696f6e206661696c65643a206275665b305d203e206227302700ba09100078000000bd00000005000000617373657274696f6e206661696c65643a2070617274732e6c656e2829203e3d20340000ba09100078000000be000000050000002e302e00ba091000780000000b01000005000000ba091000780000000c0100000500000065652d2d2b4e614e696e6630306530617373657274696f6e206661696c65643a206275662e6c656e2829203e3d206d61786c656eba091000780000007f0200000d0000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f7374722f7061747465726e2e7273300b1000740000004605000012000000300b1000740000004605000028000000300b1000740000003906000015000000300b1000740000006706000015000000300b10007400000068060000150000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f756e69636f64652f756e69636f64655f646174612e7273000000f40b10007d0000005000000028000000f40b10007d0000005c000000160000000003000083042000910560005d13a0001217201f0c20601fef2ca02b2a30202c6fa6e02c02a8602d1efb602e00fe20369eff6036fd01e136010a2137240de137ab0e61392f18a139301c6148f31ea14c40346150f06aa1514f6f21529dbca15200cf615365d1a15300da215400e0e155aee26157ece42159d0e8a1592000ee59f0017f5a00700007002d0101010201020101480b30151001650702060202010423011e1b5b0b3a09090118040109010301052b033c082a180120370101010408040103070a021d013a0101010204080109010a021a010202390104020402020303011e0203010b0239010405010204011402160601013a0101020104080107030a021e013b0101010c01090128010301370101030503010407020b021d013a01020102010301050207020b021c02390201010204080109010a021d0148010401020301010801510102070c08620102090b0749021b0101010101370e01050102050b0124090166040106010202021902040310040d01020206010f01000300031d021e021e02400201070801020b09012d030101750222017603040209010603db0202013a010107010101010208060a0201301f310430070101050128090c0220040202010338010102030101033a0802029803010d0107040106010302c6400001c32100038d016020000669020004010a200250020001030104011902050197021a120d012608190b2e0330010204020227014306020202020c0108012f01330101030202050201012a020801ee010201040100010010101000020001e201950500030102050428030401a502000400025003460b31047b01360f290102020a033104020207013d03240501083e010c0234090a0402015f0302010102060102019d010308150239020101010116010e070305c308020301011701510102060101020101020102eb010204060201021b025508020101026a0101010206010165030204010500090102f5010a0201010401900402020401200a280602040801090602032e0d010200070106010152160207010201027a06030101020107010148020301010100020b023405050101010001060f00053b0700013f0451010002002e0217000101030405080802071e0494030037043208010e011605010f000701110207010201056401a00700013d04000400076d07006080f000003a000000f00f100000000000f00f100001000000f00f10000100000025000000000000000100000026000000696e646578206f7574206f6620626f756e64733a20746865206c656e20697320206275742074686520696e6465782069732000001c101000200000003c10100012000000270000000400000004000000280000003d3d213d6d617463686573617373657274696f6e20606c6566742020726967687460206661696c65640a20206c6566743a200a2072696768743a20007b101000100000008b10100017000000a21010000900000020726967687460206661696c65643a200a20206c6566743a200000007b10100010000000c410100010000000d410100009000000a210100009000000010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020202020202020202020202020202020202020202020202020202020203030303030303030303030303030303040404040400000000000000000000002e2e00000012100002000000426f72726f774572726f72426f72726f774d75744572726f72616c726561647920626f72726f7765643a20002512100012000000616c7265616479206d757461626c7920626f72726f7765643a200000401210001a0000003a2000000012100000000000641210000200000020202020207b202c20207b0a2c0a7d207d28280a2c290a5b5d0000002b0000000c000000040000001f0000002000000021000000010000000a00000064000000e803000010270000a086010040420f008096980000e1f50500ca9a3b0200000014000000c8000000d0070000204e0000400d030080841e00002d310100c2eb0b009435770000c16ff28623000000000081efac855b416d2dee0400000000000000000000011f6abf64ed386eed97a7daf4f93fe9034f180000000000000000000000000000000000013e952e0999df03fd38150f2fe47423ecf5cfd308dc04c4dab0cdbc197f33a603261fe94e0200000000000000000000000000000000000000000000000000000000000000000000017c2e985b87d3be729fd9d8872f1512c650de6b706e4acf0fd895d56e71b226b066c6ad2436151d5ad3423c0e54ff63c07355cc17eff965f228bc55f7c7dc80dced6ef4ceefdc5ff75305002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f6e756d2f666c74326465632f73747261746567792f647261676f6e2e7273617373657274696f6e206661696c65643a20642e6d616e74203e2030d4131000840000007500000005000000617373657274696f6e206661696c65643a20642e6d696e7573203e2030000000d4131000840000007600000005000000617373657274696f6e206661696c65643a20642e706c7573203e2030d4131000840000007700000005000000617373657274696f6e206661696c65643a206275662e6c656e2829203e3d204d41585f5349475f444947495453000000d4131000840000007a00000005000000d413100084000000c100000009000000d413100084000000fa0000000d000000d4131000840000000101000036000000617373657274696f6e206661696c65643a20642e6d616e742e636865636b65645f73756228642e6d696e7573292e69735f736f6d65282900d4131000840000007900000005000000617373657274696f6e206661696c65643a20642e6d616e742e636865636b65645f61646428642e706c7573292e69735f736f6d6528290000d4131000840000007800000005000000d4131000840000000a01000005000000d4131000840000000b01000005000000d4131000840000000c01000005000000d4131000840000007101000024000000d4131000840000007601000057000000d4131000840000008301000036000000d413100084000000650100000d000000d4131000840000004b01000022000000d4131000840000000e01000005000000d4131000840000000d0100000500000072616e676520737461727420696e64657820206f7574206f662072616e676520666f7220736c696365206f66206c656e677468208016100012000000921610002200000072616e676520656e6420696e64657820c4161000100000009216100022000000736c69636520696e64657820737461727473206174202062757420656e64732061742000e416100016000000fa1610000d0000005b2e2e2e5d626567696e203c3d20656e642028203c3d2029207768656e20736c6963696e672060601d1710000e0000002b171000040000002f171000100000003f171000010000006279746520696e64657820206973206e6f742061206368617220626f756e646172793b20697420697320696e7369646520202862797465732029206f66206000601710000b0000006b17100026000000911710000800000099171000060000003f17100001000000206973206f7574206f6620626f756e6473206f6620600000601710000b000000c8171000160000003f171000010000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f7374722f6d6f642e7273f8171000700000000c0100002c0000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f756e69636f64652f7072696e7461626c652e72730000781810007a0000001a00000036000000781810007a0000000a0000002b000000000601010301040205070702080809020a050b020e041001110212051311140115021702190d1c051d081f0124016a046b02af03b102bc02cf02d102d40cd509d602d702da01e005e102e704e802ee20f004f802fa03fb010c273b3e4e4f8f9e9e9f7b8b9396a2b2ba86b1060709363d3e56f3d0d1041418363756577faaaeafbd35e01287898e9e040d0e11122931343a4546494a4e4f64655cb6b71b1c07080a0b141736393aa8a9d8d909379091a8070a3b3e66698f92116f5fbfeeef5a62f4fcff53549a9b2e2f2728559da0a1a3a4a7a8adbabcc4060b0c151d3a3f4551a6a7cccda007191a22253e3fe7ecefffc5c604202325262833383a484a4c50535556585a5c5e606365666b73787d7f8aa4aaafb0c0d0aeaf6e6fbe935e227b0503042d036603012f2e80821d03310f1c0424091e052b0544040e2a80aa06240424042808340b4e43813709160a08183b45390363080930160521031b05014038044b052f040a070907402027040c0936033a051a07040c07504937330d33072e080a8126524b2b082a161a261c1417094e042409440d19070a0648082709750b423e2a063b050a0651060105100305808b621e48080a80a65e22450b0a060d133a060a362c041780b93c64530c48090a46451b4808530d49070a80f6460a1d03474937030e080a0639070a813619073b031c56010f320d839b66750b80c48a4c630d843010168faa8247a1b98239072a045c06260a460a28051382b05b654b0439071140050b020e97f80884d62a09a2e781330f011d060e0408818c89046b050d0309071092604709743c80f60a73087015467a140c140c570919808781470385420f1584501f060680d52b053e2101702d031a040281401f113a050181d02a82e680f7294c040a04028311444c3d80c23c06010455051b3402810e2c04640c560a80ae381d0d2c040907020e06809a83d80411030d0377045f060c04010f0c0438080a062808224e81540c1d03090736080e040907090780cb250a840600010305050606020706080709110a1c0b190c1a0d100e0c0f0410031212130916011704180119031a071b011c021f1620032b032d0b2e01300331023201a702a902aa04ab08fa02fb05fd02fe03ff09ad78798b8da23057588b8c901cdd0e0f4b4cfbfc2e2f3f5c5d5fe2848d8e9192a9b1babbc5c6c9cadee4e5ff00041112293134373a3b3d494a5d848e92a9b1b4babbc6cacecfe4e500040d0e11122931343a3b4546494a5e646584919b9dc9cecf0d11293a3b4549575b5c5e5f64658d91a9b4babbc5c9dfe4e5f00d11454964658084b2bcbebfd5d7f0f183858ba4a6bebfc5c7cfdadb4898bdcdc6cecf494e4f57595e5f898e8fb1b6b7bfc1c6c7d71116175b5cf6f7feff806d71dedf0e1f6e6f1c1d5f7d7eaeaf7fbbbc16171e1f46474e4f585a5c5e7e7fb5c5d4d5dcf0f1f572738f747596262e2fa7afb7bfc7cfd7df9a409798308f1fd2d4ceff4e4f5a5b07080f10272feeef6e6f373d3f42459091536775c8c9d0d1d8d9e7feff00205f2282df048244081b04061181ac0e80ab051f09811b03190801042f043404070301070607110a500f1207550703041c0a090308030703020303030c0405030b06010e15054e071b0757070206170c500443032d03010411060f0c3a041d255f206d046a2580c80582b0031a0682fd03590716091809140c140c6a060a061a0659072b05460a2c040c040103310b2c041a060b0380ac060a062f314d0380a4083c030f033c0738082b0582ff1118082f112d03210f210f808c048297190b158894052f053b07020e180980be22740c80d61a0c0580ff0580df0cf29d033709815c1480b80880cb050a183b030a06380846080c06740b1e035a0459098083181c0a16094c04808a06aba40c170431a10481da26070c050580a61081f50701202a064c04808d0480be031b030f0d303132333435363738396162636465662f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f6573636170652e72735c757b0000a01e10006f000000380000000b000000a01e10006f0000006600000023000000617373657274696f6e206661696c65643a206564656c7461203e3d20302f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f6e756d2f6469795f666c6f61742e727300511f1000760000004c00000009000000511f1000760000004e00000009000000202831203c3c2029e81f100000000000e81f100007000000ef1f100001000000df451a3d03cf1ae6c1fbccfe00000000cac69ac717fe70abdcfbd4fe000000004fdcbcbefcb177fff6fbdcfe000000000cd66b41ef9156be11fce4fe000000003cfc7f90ad1fd08d2cfcecfe00000000839a5531285c51d346fcf4fe00000000b5c9a6ad8fac719d61fcfcfe00000000cb8bee2377229cea7bfc04ff000000006d5378409149ccae96fc0cff0000000057ceb65d79123c82b1fc14ff000000003756fb4d369410c2cbfc1cff000000004f9848386fea9690e6fc24ff00000000c73a8225cb8574d700fd2cff00000000f497bf97cdcf86a01bfd34ff00000000e5ac2a17980a34ef35fd3cff000000008eb2352afb6738b250fd44ff000000003b3fc6d2dfd4c8846bfd4cff00000000bacdd31a2744ddc585fd54ff0000000096c925bbce9f6b93a0fd5cff0000000084a5627d246cacdbbafd64ff00000000f6da5f0d5866aba3d5fd6cff0000000026f1c3de93f8e2f3effd74ff00000000b880ffaaa8adb5b50afe7cff000000008b4a7c6c055f628725fe84ff000000005330c13460ffbcc93ffe8cff000000005526ba918c854e965afe94ff00000000bd7e29702477f9df74fe9cff000000008fb8e5b89fbddfa68ffea4ff00000000947d7488cf5fa9f8a9feacff00000000cf9ba88f937044b9c4feb4ff000000006b150fbff8f0088adffebcff00000000b63131655525b0cdf9fec4ff00000000ac7f7bd0c6e23f9914ffccff00000000063b2b2ac4105ce42effd4ff00000000d3927369992424aa49ffdcff000000000eca0083f2b587fd63ffe4ff00000000eb1a11926408e5bc7effecff00000000cc88506f09ccbc8c99fff4ff000000002c6519e25817b7d1b3fffcff00000000000000000000409cceff0400000000000000000010a5d4e8e8ff0c0000000000000062acc5eb78ad0300140000000000840994f878393f811e001c0000000000b31507c97bce97c03800240000000000705cea7bce327e8f53002c00000000006880e9aba438d2d56d0034000000000045229a1726274f9f88003c000000000027fbc4d431a263eda200440000000000a8adc88c3865deb0bd004c0000000000db65ab1a8e08c783d8005400000000009a1d7142f91d5dc4f2005c000000000058e71ba62c694d920d01640000000000ea8d701a64ee01da27016c00000000004a77ef9a99a36da24201740000000000856b7db47b7809f25c017c00000000007718dd79a1e454b47701840000000000c2c59b5b92865b8692018c00000000003d5d96c8c55335c8ac01940000000000b3a097fa5cb42a95c7019c0000000000e35fa099bd9f46dee101a40000000000258c39db34c29ba5fc01ac00000000005c9f98a3729ac6f61602b40000000000cebee95453bfdcb73102bc0000000000e24122f217f3fc884c02c40000000000a5785cd39bce20cc6602cc0000000000df53217bf35a16988102d400000000003a301f97dcb5a0e29b02dc000000000096b3e35c53d1d9a8b602e400000000003c44a7a4d97c9bfbd002ec00000000001044a4a74c4c76bbeb02f400000000001a9c40b6ef8eab8b0603fc00000000002c8457a610ef1fd02003040100000000293191e9e5a4109b3b030c01000000009d0c9ca1fb9b10e7550314010000000029f43b62d92028ac70031c010000000085cfa77a5e4b44808b032401000000002dddac0340e421bfa5032c01000000008fff445e2f9c678ec00334010000000041b88c9c9d1733d4da033c0100000000a91be3b492db199ef503440100000000d977dfba6ebf96eb0f044c01000000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f6e756d2f666c74326465632f73747261746567792f67726973752e72730018251000830000007d00000015000000617373657274696f6e206661696c65643a20642e6d616e74203e20301825100083000000a900000005000000617373657274696f6e206661696c65643a20642e6d696e7573203e20300000001825100083000000aa00000005000000617373657274696f6e206661696c65643a20642e706c7573203e20301825100083000000ab00000005000000617373657274696f6e206661696c65643a206275662e6c656e2829203e3d204d41585f5349475f4449474954530000001825100083000000ae00000005000000617373657274696f6e206661696c65643a20642e6d616e74202b20642e706c7573203c202831203c3c203631290000001825100083000000af0000000500000018251000830000000a01000011000000000000000000000000000000617474656d707420746f20646976696465206279207a65726f00000018251000830000000d0100000900000018251000830000004001000009000000617373657274696f6e206661696c65643a20642e6d616e742e636865636b65645f73756228642e6d696e7573292e69735f736f6d652829001825100083000000ad00000005000000617373657274696f6e206661696c65643a20642e6d616e742e636865636b65645f61646428642e706c7573292e69735f736f6d65282900001825100083000000ac00000005000000617373657274696f6e206661696c65643a20216275662e69735f656d70747928290000001825100083000000dc01000005000000617373657274696f6e206661696c65643a20642e6d616e74203c202831203c3c203631291825100083000000dd010000050000001825100083000000de01000005000000010000000a00000064000000e803000010270000a086010040420f008096980000e1f50500ca9a3b182510008300000033020000110000001825100083000000360200000900000018251000830000006c020000090000001825100083000000e30200004e0000001825100083000000ef0200004a0000001825100083000000cc0200004a00000063616c6c656420604f7074696f6e3a3a756e77726170282960206f6e206120604e6f6e65602076616c7565000820100000000000736f7572636520736c696365206c656e67746820282920646f6573206e6f74206d617463682064657374696e6174696f6e20736c696365206c656e677468202829000000d028100015000000e52810002b000000102910000100000001000000000000000000000000000000000000000000000000000000000000000000000000000000b0a00e02d2c986019d188f007f693500600cbd00a7d7fb019e4c80026965e1011dfc0400920cae00edd3f51cd21893009635e71d45bdf31d4d0100000000000000000000000000000000100059f1b20209e5a6017add2a021d14d4005280030030d1f3007779400331e39c01ff6dc501671b900001000000000000000000000000000000000000000000000000000000000000000000000000000000ecffff03ffffff01ffffff03ffffff01ffffff03ffffff01ffffff03ffffff01ffffff03ffffff01b0a00e02d2c986019d188f007f693500600cbd00a7d7fb019e4c80026965e1011dfc0400920cae00ea405d00a06a3f0039d357020bd2ba0058bc740240d80100ffc83d01d8429401fffa5c0024b2e10176c15f00657002014ffca102f16ac6018406b200e4df7000dfee550232f31a003e2b8b02ca410a00a37859038472d300bd6e15030e0a6a0029c0010098e87901bb3ca0039871ce01ffb6e202b30d4801204ded0091aa560135263303f080650128794a03eb4e9b00a99769029b294800c266af03cda265011b2e7b0112a8fd01d2af9702c2db60003876be02fdd1f50198647e02e781150134b8f203c6a4dd0001000000000000000000000000000000000000000000000000000000000000000000000000000000a37859038472d300bd6e15030e0a6a0029c0010098e87901bb3ca0039871ce01ffb6e202b30d4801617373657274696f6e206661696c65643a20696478203c2043415041434954592f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f636f6c6c656374696f6e732f62747265652f6e6f64652e7273782b100080000000b302000009000000617373657274696f6e206661696c65643a207372632e6c656e2829203d3d206473742e6c656e2829782b1000800000002f07000005000000617373657274696f6e206661696c65643a206f6c645f6c6566745f6c656e203e3d20636f756e7400782b100080000000dd0500000d000000617373657274696f6e206661696c65643a206c656e203e2030000000782b10008000000065010000090000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f636f6c6c656374696f6e732f62747265652f6e617669676174652e7273a42c1000840000005902000030000000496e646578206f7574206f6620626f756e647300382d1000130000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f736f72742e727300542d1000730000003b0400000e000000542d100073000000480400001c000000542d100073000000490400001d000000542d1000730000004a04000025000000542d1000730000008e04000040000000542d100073000000b40400004e000000542d100073000000c204000056000000617373657274696f6e206661696c65643a20656e64203e3d20737461727420262620656e64203c3d206c656e542d1000730000002d05000005000000542d1000730000003e05000029000000617373657274696f6e206661696c65643a206f666673657420213d2030202626206f6666736574203c3d206c656e0000542d1000730000009b000000050000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f636f6c6c656374696f6e732f62747265652f6e617669676174652e7273c42e100084000000c700000027000000c42e100084000000170200002f000000c42e100084000000a20000002400000050617468206e6f742061737369676e65642f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7363616c652d696e666f2d322e31312e332f7372632f6275696c642e7273000000892f100060000000b20000001e0000003078323465386438623732633063336135663432646465323966346535303235326664663132656465353832643632663564386631633234616237633062373066364d6f64656672616d655f6d657461646174615f686173685f657874656e73696f6e44697361626c6564456e61626c656450617468206e6f742061737369676e65642f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7363616c652d696e666f2d322e31312e332f7372632f6275696c642e7273007f30100060000000b20000001e000000776569676874576569676874636c6173734469737061746368436c617373706179735f666565506179735965734e6f00506179736672616d655f737570706f72743a3a64697370617463684469737061746368436c6173734e6f726d616c4f7065726174696f6e616c4d616e6461746f72794469737061746368496e666f000042616c616e63655374617475736672616d655f737570706f72743a3a7472616974733a3a746f6b656e733a3a6d6973634672656552657365727665644572726f723a7472616e73616374696f6e5f6c6576656c3a57652061726520756e646572666c6f77696e6720776974682063616c63756c6174696e67207472616e73616374696f6e616c206c6576656c732e204e6f742067726561742c20627574206c65742773206e6f742070616e69632e2e2ec43110005c0000006672616d655f737570706f72743a3a73746f726167653a3a7472616e73616374696f6e616c2f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f6672616d652f737570706f72742f7372632f73746f726167652f7472616e73616374696f6e616c2e7273436f727275707465642073746174652061742060603a200000bb32100014000000cf32100003000000307872756e74696d653a3a73746f726167652f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f6672616d652f737570706f72742f7372632f73746f726167652f756e6861736865642e72736672616d655f737570706f72743a3a73746f726167653a3a756e6861736865646361706163697479206f766572666c6f777f331000110000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f7665632f737065635f66726f6d5f697465725f6e65737465642e72730098331000830000003b000000120000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f7665632f6d6f642e72730000002c34100071000000a00b00000d0000004f7074696f6e544e6f6e65536f6d65003900000001000000010000003a0000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f6672616d652f73797374656d2f7372632f6c696d6974732e72734275696c6465722066696e6973686564207769746820606275696c645f6f725f70616e6963603b205468652070616e69632069732065787065637465642069662072756e74696d65207765696768747320617265206e6f7420636f72726563740000d03410005e000000b4010000160000003c7761736d3a73747269707065643e426c6f636b4c656e6774686672616d655f73797374656d3a3a6c696d69747357656967687473506572436c617373426c6f636b576569676874730000005065724469737061746368436c6173736672616d655f737570706f72743a3a64697370617463685450686173656672616d655f73797374656d4170706c7945787472696e73696346696e616c697a6174696f6e496e697469616c697a6174696f6e4c61737452756e74696d6555706772616465496e666f50617468206e6f742061737369676e65642f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7363616c652d696e666f2d322e31312e332f7372632f6275696c642e72737436100060000000b20000001e0000006d616e6461746f7279546e6f726d616c6f7065726174696f6e616c6d61785065724469737061746368436c6173733c7533323e626173655f65787472696e7369635765696768746d61785f65787472696e7369634f7074696f6e3c5765696768743e6d61785f746f74616c7265736572766564626173655f626c6f636b6d61785f626c6f636b7065725f636c6173735065724469737061746368436c6173733c57656967687473506572436c6173733e753332737065635f76657273696f6e636f6465633a3a436f6d706163743c7533323e737065635f6e616d6573705f72756e74696d653a3a52756e74696d65537472696e67d8371000000000000000000000000000010000000000000082800000000000008a8000000000008000800080000000808b800000000000000100008000000000818000800000008009800000000000808a00000000000000880000000000000009800080000000000a000080000000008b800080000000008b0000000000008089800000000000800380000000000080028000000000008080000000000000800a800000000000000a0000800000008081800080000000808080000000000080010000800000000008800080000000802f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f6b656363616b2d302e312e342f7372632f6c69622e72734120726f756e645f636f756e742067726561746572207468616e204b454343414b5f465f524f554e445f434f554e54206973206e6f7420737570706f72746564210000a838100059000000eb000000090000003e00000000000000010000003f00000040000000410000006b65792d76616c756520737570706f7274206973206578706572696d656e74616c20616e64206d75737420626520656e61626c6564207573696e672074686520606b766020666561747572656c3910004c0000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f6c6f672d302e342e32322f7372632f5f5f707269766174655f6170692e7273000000c0391000610000002d00000009000000430000000400000004000000440000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f6d65726c696e2d332e302e302f7372632f7374726f62652e727301a8010001605354524f424576312e302e320000443a10005c0000005e00000009000000443a10005c0000005f00000009000000443a10005c000000680000000d000000443a10005c0000007c00000015000000596f75207573656420746865205420666c61672c207768696368207468697320696d706c656d656e746174696f6e20646f65736e277420737570706f72740000f43a10003e00000000000000443a10005c0000009100000009000000596f7520747269656420746f20636f6e74696e7565206f702020627574206368616e67656420666c61677320746f2000503b100019000000693b100016000000443a10005c000000880000000d000000646f6d2d73657000526561736f6e7370616c6c65745f62616c616e6365733a3a74797065734665654d697363416c6c4578747261466c61677341646a7573746d656e74446972656374696f6e496e637265617365446563726561736550617468206e6f742061737369676e65642f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7363616c652d696e666f2d322e31312e332f7372632f6275696c642e72730000000d3c100060000000b20000001e0000007531323863616e6e6f7420616476616e63652070617374206072656d61696e696e67603a20203c3d20000000843c100021000000a53c1000040000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f62797465732d312e362e302f7372632f62797465732e72730000bc3c10005a0000003b020000090000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7061726974792d7363616c652d636f6465632d332e362e31322f7372632f636f6465632e7273283d100068000000ad01000029000000436f646563206572726f72007072696d69746976655f74797065734832353650617468206e6f742061737369676e65642f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7363616c652d696e666f2d322e31312e332f7372632f6275696c642e7273d03d100060000000b20000001e0000005b75383b2033325d010000000000000000000000000000209a99999999999999999999999999991915ae47e17a14ae47e17a14ae47e17a14de24068195438b6ce7fba9f1d24d621096d40968226c787aa52c431cebe2361aab436e861bf0f96184f068e388b5f8142236583849f3c7b4368dedb5a0f7c6106a238dc00e52a6875748afbc9af2d71a884fd766a541b89fdf398c30e28e791507a6121f51012de6b294d626e80b2e11a40951cb8168aed6b7babdd7d9df7c1bea3aa7a234edf1de5f956479e17ffd15bbc885e8f6f0277f1911ea2d81999711f80dd640beb40c65c281764968c2251c9371de33989070ea019b2ba1869b841643c17e29e0a6f3219b1556e79eaf03123735310fcdd785692bbc89d897b2d21cf9905a3fd7df37218996d44646f50e17fa7348cc45e65fe7a0ab43d2d15d72125d860d7a3c3d66a534acd2b64fc9831db19ed79463971e515d2342920ca19c17c14b79dd82df7eda7d4f9b0e0ab4e31268ac5b62d198642a96e55e171020391e53f0e281a7e0b6ee4451b21240b32d18a9264fce524d92586aa78ea899c2571341a47eb0b77b5027aad87ddaf5d0f21e345065c05fc9a652bb13cbaec440c21890a6ea994cd4eb0ec90f3cf2369ace13800a11c3ad5379b141196050bef6b01f670874028bdc2dc16747b3a6fe5e5a1952a029356fb02434869fc2ebfe4b4814db19ee90f2591d909e7f688965d639105f29b0b41dc3fb4c9732a7a8d523f619b2ba595db135963dac5b1fba77e9c4142862e17d275eab9756494cfb92879d100d9d68c9d8c9abf2f00e7af8b7a5951a3e17ba3a7aa1bc5b5a722e2d93844415cb45fb2ec81acaafae8e8b8a429d0311450992b1a6f7dcb24ae478aa9dfb381b04a141c1eb927df56e832d55b12fc71503b46767897564c4589c577727266c11d2eca5d8db886d6df4c625f20b3de01bdb23eb461607be8ac3381e28a3fd4c1649b655d2116cfe6e9c604b534f31d7110e8aefb64f1397b16067458518828b1ca5a1bff8720fac271ab96a37ad01d6161e4e9960c27256b9e160552c24ce44129516c2cd031e57f535cebb136de33a1dabab010b0318ac2a2bd82f768a4f62175689346f02e0bcbb5513f3c46e0cb51289a8edb1d0ccc792ef1eb8d44a7aee1d07ba578e400ad3dbf24b93106ffbf11706c8df7100d5a87cf56f0fda58fc2713d60c66e933bba7fabb4cb2298e60a61e11d7848729fc5295c9a38e540b1a85180eacd0d2bac9a8aa0783d8766fae9d13e3ac1a1e5edcdadda5d1c057b2b0621f4f8a484b4bb0487e51419aac8ec01b19d9a1d3d5d5596dcbdacde156a53316147b81dc77117b573ce2d7e7abeac211102acf6059825ef2c63626a6acaa04b619bba580476818f56bc551eb56559d911496840006ed792a23d1a722dfdd7d7410560734a3e18fddd1810cd13196fc531a456cf6e81a73e4a7343da7f444fd0f159e56f853e2281d535d97525d6a97d91062578db903db61eb2ef2509510bff51ae845a4c7cf484ebc585bdadda6659115206b836cd9d37163ade2e1171f1e4111cd119fad28861c9f480403f364639b1b0bdb18be536bb0e5069d358f1de91516a21547cb0f89f3ea6b4a9172e420ab1137bc71784cdbb84446aa1b846d01451c5f63c1c6d615c70305554903be9a9d1619e9cd6b45de383637770769feae1712c1411646a263c1565858720e97b1f21cce67abd1811c01df7913f571128e2817a5ec5541ce16347f61dc90c10ed886126e4756357d24206502c7e768e48ca41d253978f7301d80ea016cb9201dd7b61784fa2cf9f3b099bb3423614d17acf81239f74728534e5c5f54386815f2ac5a1e2e2cd3b9750b7d7f436053445b8a48185823dcc7f7d53099cf19a9367c3b6d1326d2f9728c89b48eb28f0ef1f92b151fb8412e8fa3072a7228a60bf4c7bcdd18fa9abea54f39bbc1861ed65c0697e413f6f7300919c25e9cd730f0fad624d41ff85f5a071468e549798d262fdf83761960e6e1051020516ec70a52bfe5cf5e141a8581d10c80daf1056f0e9984d94b10f5d468821400c44fd6e4e3f4a0f5121a2b77ed01aa9969d911b71cf7b3f7db14bcc58a018814eead7492b0c55cf9af102c09de68a6ed7c4954ea806f9428b31a24d4e453b857ca3a10559abf76205c1583761d4360793b6273aaaeff5e8016119ebdc8d166f52b9db810b132cb33571b7f646d4152c4bc7d600df48ea25cdf15ccb68a67db69fdcae63dc3d84e7d7f11df8a7772c50f2fabd72f058ee42eff1b80d5925b0473f288ac8c6a3e1dbf651666444249d028f5d3563d55984affea11a3a003424d4188b95795bbf31032ab1ce9e60268d7cd39617977fcc2405bef1654520220797161e72df9c968cd15591286509d998eb568a57c5b767415565b1dd2a64ae13e912051fd15c5f6dd447c170e1fa21aff404da7ca443792b1d0c9124acb69f764ceae0b116e58504fb40f1e3b3ceec550d88b3ca7f179733f900c18c9c9f137da7909ca85f4c7c232403d13db42e9bff6c2a8a96fba0c9eb766c81ee39bbacc2bcf53212695707e2c52a018824995708972a91ab8dd2665f074b3139d75881a0f8475f78c2f3e08e787851f175ea07b7236915f0a269806ec9f3719dfe419965bf84019d5844605f07f2c144cea47abafc600e1103705d18c99231047dd3f454ca467cee724d5b4478fd21906b1cc9dd6e952d81fb7ddc39f72a81438270a4b45eedb79192c7e6919c2861059d8a911a2e35f298f46300f8f36711a7a13bba7811cb3baa56bf3d8d85e27152fa995ec9ae3286251898fade04bec101775efe0f7380e9de80e4caf9aac131b792a591a932dd8b05372d625e256a9152e5547480fbe798ddcc1deb7814554117cbb0bda7e968f15949c978ccf08ba1b972fd614ff11a67776b0dfd6726d2e16798cde43ffa751f991f3b278f5bdbe118eadfdd2fe3f1cc21cecb75a2263641cd88a64423233b00117f05f15b5b5b61646a2839b8ec25901ac59e6dd90c42b12a303395f1704f6ceacc2a3fc1ad4121d839c2d4cac695e72bd9b1cca484342179ce38ad6895418f5fde2160807699b12c605abbd0f548dee2f6bf10cd874c51d056b22fe7276d7be8c22c170462ad11704bc4ecb28c512ffd64e678d6bbb0d13a0f97d78743b51cb247ed87b125f7c1e4d61fef929c90d09b731adfc417f63180a81cb9421d4d7a0c52724ca34cc821377ce7854cfb9bf676f0c6d4321ad371ff9712ddda594cc1f59708acf4d57f918c7f4bd7d51ddd67f7af3a13f3eacfa130bee2fc9e82ebeffc3b89c32fd79f71fd624f3a020bf316636fa16c2fdc79219781d5c1a1acc27b85efbab01cb6c751460e47c7bae09539318c9bc67a2f05d1099a094c5b042eb1ef474943f6ae72f1ae1e67604270289e55c2add32881ff314e7eb2b9d85cea0b7b0eeb028a07fc210d8dfdf616f4a0159b44a4e7433ccd01aad4ce6e725d5cde029a23e908fd67315f1d651865177714deeb4cbd972782911e857e9d6e8bee87bb054ac8f848d751b201321df5332bafc59dd890c6aa4f7158042e7184328c863ae4a6e70eee99211666ad827380d0d0617114a1a17431e1ceb21adec2ca43d6b12746e7b129c7e16564e57bdf01cfe88db5c58fc41e3fe11234a2562b49496415f618d603605cb1ce9d41de829aaab677fe73d4df8d0081787dd1720bb2156b932b964d7f9736d12a5958c662b6923c2eac13af2c2ec7b1d1dded61e89ba82cebb34625b025796171818df4b076235a5fcf6b4e201acde1259f36479d89c883b94f187373613311ee1f583c7464a6dfcdc5a06c6914227181a2b03069f6e573017af9ed1a79b521390ded13ccb7d251a2518311ca692ea1e40e5a7303cfe1d48b7795ae384a8bb18005186c0c9314bd3c5c7ae829d53c913cdb4a3cd42e9115209a617d1c885a81fa4901c3e0221db7407b8df403a9e5319500d4acb01b415f705601967fbe44214a70a08099b29def837b37a52fc833510d7dd0ca89142308e59b82ab79339ef19134b0a200e028d3ee1f9eef84261bf140f3c08803e9b3d65e7c758fa9b1a9910e42c0d0064f8c86ea50c8e90f9908e1aea23a499e9f9d38bb7a3714061da3e15bb1c50e1ba94a93cf982f4991a15ff102b61b39bc4ba75c78ed120c35dbb311b891a29166a95c4d20b0ee768b162c115a17bba118877d0db6f3e1f87278267119b925d1c40bf802ce663983e3fd0d81b4975e44933cc33bd51b64665ff0c4716d45d506e8fd68fcaa75e0551cc70d21153c9b3e34b571944d9fd6e4eade7831ca93af68209794703e19725a58aeccf16bafbc468d4606ccf807984ea6ef03f122af9070e87347ae59af5d3104b1a331d2294390b6c902e51e22a43da08155c17b5a9c7d5bca68bda8155cfe1d310b012870fd9222e71df909c55e5025381e61d6c0c144f8b5a4cda16de1dcfa89aeb178aa3a9a5a27ba3ae787eb1a520e22213a905a9a26a5fd27d2797b5a29a369e1e54d12082887fdb971facf74e15927e1877a780ce06667c794c23c6d8dd749813f10b01e40a702d8fad6ba32796545a1f5ad60050a259240cbeefb51f7810151915459ad981141d70fef2f7b2f9d91014776a7b149b4317c0fe5bc6282e7b0d10f24392edc405f2ccca2c0a0e7d2baf19c29c0ebed0375b0a6fbda171ca228c14cee33ecb73f948088c97b427d51b7010b09f6478ec5b0edaac25540c55f94c1ac07f5060f0af3e7bbdb7a9d610610a1533664080f3bfcb95972ceede731ad5105270cd665266acef5847b064b990ee1adb59a4b80e852326476cf3b6faa68b1549aeb693d8d0821e6c23295f95853c1175b08a1ff41a9efdac38a8feee08941bf759d5b229afb197bd938698250710162c7b77f5ba258eac97dc9e131e6ca61113c558222b097d7abf2dfeb8c9793d1c766aad4eefa0fd61cc57cb60a1949716c5eebd0b591afee7091309e74ddd12123ab1fc455b5d63a6dc840ed8affbea1cc88d306baf4a1c85b0d03e13f3622217d4d726bcf26ee3d026dacb75c2e88112868ca4c6ea179fb4d72946899da79c1d6b705005efdf182a46ee04a11786b01789f3d99d25b3e0546b8b9d4d799ef3127452f6626febcd8778452f7c2897521e5da85e82bf220bd3c66abfc986124218e4b94b68cc1b3c0f9f88ff3ad20e68136d2979407a2c601898da989183e40c1f24219433c856b34613e2130e361dd718b64d4329a0788f38dcb4dca4914adf138aaf6ba866277f5a602161a182aacb1fa2bfefb9eb8532154db44db49bbb6f194e998c6189d18eaa3d90a4f6e26259140ce1d61aa1a7d8eecad9b62b4f824710459b245e9b72277e11f68adfb1030c1a04491d1849f585fe0df83b195b69d614d0a04a13d45d9ecba4f92f147c87ab104d01115253c963df3a5ce6b9f90bac1a7167da740fa11c192fb01efbfa6f5615c152482ad980b0ad25c04b2f2ff3111134510daa8e34e71509cd12b27eeb4f1bc40d71ee3e5d1fab6d0a0f283289d9159da48d8b651719bc57080c2028d47a11943a7c123cf2f42c590de0ccd9b9f71b439596dbfcf4c3f0e03db370e1c75f1603111216975d365a1acbf5268139e61104e81cf024fc569090de220b358fa31cd0ece38c1d30dfd9a64b82a25d3fe916da23833db1597fe1eba2ce4eb13254125c39382fb5c2cb6879d17de44e84531de32d60bf5d35d65394a76450720376171c8be665b12a78a976ecb6a68ecfc412fa44d76fb5aa260ff1138bd77db2071e626adfbf2a22523f27436fac642806184e887f99884edb651f9cf289502038134a0dcc28744ac56f6593ea0fb433c01e3ba40987f6a16a59840f2273f6c2991896b6076cf8e7eead36d9b4f59135ae1356570ce0f33f7e4924f5ba2283227d1f45acd64cf6ff64d4e99095e868e83019d189783df8ff8343ee7344ed5320271474a19397c6cc9ccff18f03f10f4d1f105202b925a447617f1cb305e87faecb190f35c7b7e9d24dcc165cd1ecfff1a214d990d25f210f0b3d12b0da23335b8210c1e75099684bab6150b32a06852b6a1a67b94014baa2224e405c556b6abc2115539400dd94e84e0bcd4944bceec9e71051ed00c887da171248a9d3c64a760c1bdabd00a06c4846db6c87dc6bd591a315af64cd4cbd0605498a9fe3efdda74f11b13ae27ac80a08a843ff38e62fa6b21bf42ee8fb39a2395369ff931ef38428165df2ec2ffbb4c77587ff0fb2f503ba112eea47e69121d9223fff7fb622d35c1cf254068541817ab565ffff91e8a8b016f5433837010162c4b73233db86ed2612ee9ff3f10168363a5984eb91a4150b1d8b19f6279bb95efbe069bc7450113c17d67a5e86e2fa7e2fe787635d407496125691fdd6d0f797e571d93862cd86bd1dabdaca780d937984c17a2de83dd2ca1756156f2d714261d09ac88a8631a80813222218af4e6a684d91daaa3d4f40741ee8b479f23e8853a4daae88643f005d18875d6128ff6cdce9ae586d50cc997d13a495680d65ae60a9e48d481a7a5c2f1f8344ed3db7beb3ba8371a0ae61b0f218369d8a312c32f62e36c1e6bee759f513f0617782131dbde4899bd7973ff6ee1f5a4e2c35a97dca83a1afdfdf32f88b1915a556f720fea19ce7f2b24cc2f96f14aa1d12f9b3311b4ab9288f709b945910dd95b6c1ecb55e43f50de580c5ed281a4ade5e01575ee535c4a41d67048bed14d5b11801ac7eb7c4691d7e52d008be1022b65a9b799725a10f2f30b7b3a7c91a815e154961acb74dd958f3f8c21f6e159b4b44078123c6d7ade0f59335e624112bacd33e9b053d5949345686223d6e1bbc89dccb159efde06dc3110582caf11563a1e36f1118feb3246941379b3b8e11d19bd27fb559638607753525c5c5161c0ee30e339114e9d1d290f750379e78160b1c3f8fda76ba74750dc6402c18fa1178c631e59024f7edbb48a367e059c31c2d055bb7401d2c8bc9d3b51f4dae021724047c5fcd7d566fd40f2be6708b6812066dc69848c9f07eedb2113d4e12741d9fbd9ee006a1c09857c2a7fda40e9017e6ca4b4dd2800047799becca50a5d912a24479481dce00d88ec5ad448108291e82d02d6d17d833133fd1579d9ad32018cea624247946f6a865a7ac4a15764d137da43aa08e3dbd746fa57a778856e21e645095e63e31645d8cb7fbc50612b518b7a6aaebcb8db64a702c96d16b0ec41357a4aa12131624111a47f0e81217a01fdfe9ee0edc4483da146cf35342df4c198021bfd87c9d02e243232943687f3d143381327afd7d684e361c54cfb9323110b8ce509095c9404abdc6b94b2951e819c60ba7a677d4330831d2c76f87dab9146b09ec1ec67629a08d0ed3bfd2ae9410dfdbac64a35742004917b8ff1d7e871a19e323eab5df01cda0126099b1313915aeb51c88914cce704d75e6ad278efa10e25594a6b5ade31aafbb70490c7d2a1be8774385c457e97bf2628d073d97bb1587f935046a7987c98eb50a0664df621171c2bc06108fa575e48877d66c65d11b2735ca6ba6a5b7f7e9d392abf01d41161fc4a1bc1e1ec65fee0f0f568db1cd1165d302616463a3ff16b3b189484f7c1c51dc9b4d501ce932df288ed406d9c9160e7d497173e3208fb220d87605143b127c2e0f8285059b7eeacd59f13b532b1dcabea5019e37afcbeed747f42fdc5517a19884344bf95809bfac6cc38c16ab120000000000000000000000000000001000000000000000000000000000000014000000000000000000000000000000190000000000000000000000000000401f0000000000000000000000000000881300000000000000000000000000006a180000000000000000000000000080841e00000000000000000000000000d012130000000000000000000000000084d7170000000000000000000000000065cd1d000000000000000000000000205fa012000000000000000000000000e8764817000000000000000000000000a2941a1d000000000000000000000040e59c30120000000000000000000000901ec4bc1600000000000000000000003426f56b1c0000000000000000000080e03779c31100000000000000000000a0d88557341600000000000000000000c84e676dc11b000000000000000000003d9160e45811000000000000000000408cb5781daf1500000000000000000050efe2d6e41a1b00000000000000000092d54d06cff010000000000000000080f64ae1c7022d15000000000000000020b49dd97943781a0000000000000000949002282c2a8b100000000000000000b9340332b7f4ad140000000000000040e70184fee471d91900000000000000883081121f2fe7271000000000000000aa7c21d7e6fae0311400000000000080d4dbe98ca039593e19000000000000a0c95224b00888ef8d1f00000000000004beb3166e05b5b5b81300000000000085ad609cc94622e3a618000000000040e6d878037cd8ea9bd01e0000000000e88f872b824dc7726142130000000000e27369b6e22079cff912180000000080dad003641b695743b8171e00000000908862821eb1a1162ad3ce1200000000b42afb22661d4a9cf48782170000000061f5b9abbfa45cc3f129631d000000a05c3954cbf7e6191a37fa5d12000000c8b34729beb560a0e0c478f516000000baa099b32de378c818f6d6b21c00004074044090fc8d4b7dcf59c6ef11000050910550b47b719e5c43f0b76b160000a4f50664a1da0dc63354eca5061c0080865984dea4a8c85ba0b4b32784110020e86f2516ced2ba72c8a1a031e5150028e2cbae9b8187698f3aca087e5e1b00596d3f4d01b1f4a199647ec50e1b1140af488fa041dd710ac0fddd76d2611510db1ab30892540e0d307d951447ba1aeac8f06f45dbf428083e6edd6c6cb41024fbeccb161232338acdc9148887e114ed39e87e9c96febfec40fc196ae9191a342451cf211efff793a83d50e2315010416d2543aae5fef5b8124de45a3e641492c8eed3149f7e336757609df14d7d19b67aea08da465e00416db8046ea1dc1fb28c924548ec3aa04844f3c2e4e4e913de2ff7565aa749c85a15b0f31d5ee418d6fbb4ec30115c7ab11a9c70a5751d1f651df193be8a79ecae90616687697213bf64ed386eed97a7daf4f93fe9034f18efbd28c7c9e87d511172f88fe3c4621eb576791c7eb1eed24a47fb390ebbfd1262d497a3dd5daa871d197ac8d129bd177bc97d0c55f594e9649f983a4674ac1ded9dce275519fd119f639fe4abc88b126845c271aa5f7cd6863cc7ddd6ba2e17c2d6320e95771b8ca80b39958c69fa1c39c6df28bd2a915749a743ddf7811c12c8b717736c7575ad1b9194d475a2a316baa5dd8fc7d2d29862b5b949138b4c1c9487eab9bcc3839f5d11140eecd6af11792965e8abb46407b5159911a7cc1b16d7737ee2d6e13d49225bffd5d0bfa21b66088f4d26adc66df598bf85e2b7451180caf2e06f5838c9327f2f27db259715207d2fd98b6e867bff5efbf051effc1a34aebd67170534ad5f1b9d369315de10c119ad415d06819837624404f89a151532601892f447a17ec57a5505b6015b1a1f3c4fdbf8cc246fbb6c55c311e17810270b23123700ee4aeac72a3456199714f0cdabd64480a9dde47935c1abdfbc19b6602b062bf0890a2f6cc158cb0b1610e438b6c7356c2ccd3ac7f12ebe8e1b141dc7a339438777800939aeba6d722219e4b80c08146995e04bc75929090f6b1f8ef30785ac615d6c8f1cd8b965e9a21372f049a617ba7447b3234e28bfa38b188f6cdc8f9de85119a0ac61f2ae8cae1ed9c3e9796231d30fe40b7d57ed172d13cf346418bbfdc713dd4e5cade85df81703427dde29fdb9589462b3d86275f61d42490e2b3a3e74b79c1d70c75d09ba1292dbd1b5c84d51e503254c39b58b6817775246e33aa1a5de442e9f87a2ae421d8af30bcec484270beb7cc39425ad49126df08e01f665f1cd255cf4f96e18dc1688acf28173bf6d412f7371b88a1e931cd5ab3731a897e488fde746b316f3db11ca96853d92bd1debfca11860dcef52167dfce6ccf62ce5257cca1e78d3abe71bce5d10401a3caf978d3e132b64cb7011427514d0200b9bfd300ed8353dfecc1592921904e9cd013dbd114e83cc3d401b9bfb8fa2b120214616cb10d29f26081182fa330bde68a9d7dbfd94c647304a1523f9008e15c393cd523d3ab859bc9c1ab69bc078ed597cc053662413b8f5a110a3c2f0d668709bb0e87fed172673ca144cf3ac0c834cc2dce2dfe89def0ffd190f18ece7d16ff9c9ed8bb1c2f5293e10131ee761c6cb773ce9ee5d3373b44d1498e560fab7be958ba36a350090216119fe1ef9f8652e7b6e4cc54200f469b91f5fb39bbbfffc0cc54fbb298038e2d31337a082aa3f3c50b6232a34a0c6dac818444823954f4be4a3ac3441487811fb1e2b0d36bd11af6ee6ebc0282debea5c137590832cd65a0ae026f172f8a52534189374a4b78bf10c9870ad8f760f2f411edcc8c652f716085f66cc19aa69bde812137b7827b51ccaf67f3fa014c4eca217d7995671e2a37cf45f4fc819f5a78b1d2620d6866de6cdf89b311d30f948771230a88be8086001f7027e247c371b15173c92ae220bb8c1b4839d2d5b0562da1c651badf50613f9507282fc58437d08123f6218b3c85737e50ea33b2f949c8a16cf7adedfba2d859ed28b0a3bb9432d1cc10cebcb943c13a36397e6c4534a9c11f1cfe5feb90bd88b3c3d20b6e85c0316ee439f7ea80eceae8b4ca8e32234841b758a234f29c9404dd72f49ce95a03211126deca273fb9020cd7bdb41bb487f155688a78b503ab568c05a5212ea1adf1a36b5485772447141b878734bd270cb1083e21aed8e95cd51e65650de064dfe14249b61a8f2fa40e69f6ce49548e03d1af7003da9d79ce8efe3c3ae5d2dac661034418c930dc4e2ebdc741ab53857801481516ff81075db26141261e2066da019f192459b2a2949984cab7c4d24440410adf7164275735bbe1fd6db602d55051498b59c925250f2ada7cb12b978aa0619ffe2433767e46e99917e57e71655481fdf6d8a82c04ee5ff1aaf96502e358d1357092da370a2debfe15abce479827018ad4bf8cb0c4bd62f9a71eb5d18a38c1e4c2f7bffe7eee55d0027b33aefe517131ffb59ffa16a5f75c0f05f096bdfdd17e779307f4a45b792f0ecb7cb4557d51d304c7e8f4e8bb25b16f4529f8b56a5123cdf5d33222e9ff21bb127872eac4e170b5735c0aaf946ef629df1283a57221d675621b80a5c8cd55d0297598476351201ac29660d73ef4af5c2fc6f25d4c2160117b4bfd04fab9db2f3fbcb2e89731c608ed077e2118ba24f787d3fbd35c811f9b1c4155bd62d8b63d65c8f2c433a1677de35dbf14bf96dfc0b34b3f7d3c81b0aab012977cfbbc47d8700d07a845d11cd1542f354c3ea355da9008499e5b415409b12302a746583b4d300e5ff1e221b08a10b5e9a681fd2508420ef5f53f5104a898ef5c042a70665a5e8ea37a832159d2bf23271135148becea2e545527f1a425bd7bf26ac32ed36c185af6b938f101232cd6f30577fa88431679b4678b314977ec08bfc2c9fd2e5fd40425856e0191e4f58d71d7ca3a3af9e6829f7352c10e6622e4d255b8c8c5bc6c2f3744337149ffb79a0ee71af6ff277b33052144519877a98486a4e9b0bef55e0bc6659961f944c5f6d02114167b5350c36e0f7bd13ba1fb708435511c122438f43d875ad18a8e7e4ca93aa5571eb1373544ed3d81ec910cf5e9c8ad52673ecc7f410844713fbd4827643ed8af08fe7f931156519183a8a235494a8adec7361787e5abe1f1e643696b45c89ec73e83c0b8ff8d6d312fdc3bbe1b3abe790220cceb2b6cc8817fdb42adaa09621352b8f815fe4ff6a1d1eb15a8824fe34017bf9b0bbeedf6212655d71aaad3d82c1d9379d6aea97fb16bfb40d1519cde231d0854405e57dba1cf79028ad2fc02d1fa2d34a23af8ef41135b572983b30f9a68a881dec5ab2711682628f7e4a7cb750adea24a7f11e0e1c919d198faead7252ac12770857d38811f604e0321a590f6757d794ca2c08eb15330698bf602fd3402d0d3afd37ca651be003bf779cfd83483c4844fe629e1f11d8c4ae9503fda45a4b5ad5bdfb8567150e761a7b443c4e31deb04aad7a67c11ac989f0ccaae5d0de8aae4eacace0b8103bac2c80151f85962d5a62d7d718e7144ad737e0da6626fcb8f03acd0ddf201a8ee622cc4800989d73d644a0688b541032a02bff5a00fe84100c56c842ae69143e88f6be71803da6148f6b7ad31984194e2ab42e8ee0cccfd97206594820e51f709a30dd580ce021c807a4372d34ef130dc17c146f0f582aba098d853801eb1850f19bd94a13eeb4284cf0a686c1251fd27601c80ecc1471992f5628f498771386d4017a12ff59cd7fbb6b32317f5518a8498218d77eb0c05faa067ffdde6a1e096e516f464f6ed87b2a646f5ecb02138bc9250b18e389ce1a353d0b367ec317ee3bef0dde5b2c8261820c8ec35db41d7585b5c86ab95bf17cd1c7389aba9012d2e6e27ac5a7b22ddcc5f9c640e9341786a09bd9b6511f395337b8f89023021d544401481293b3039422739b3a562112699501dad677a00439eb4f42c9aba916c3fa8190cc95c84507e6e392bb16541cba3c51da9f5d9d8bc46fce3b358eb411e88be5d007b584aeb50bc28ac2b12116e3ee1ec549e2251aa38e722d331eaa1b4d55331b6ead57f0259967fcdf524a11a12a00a2c9986d6c6f7f81fb97e79c154935800afcfe88474bdf61fa7d21041b4e2190865d9fb50c8f2b7dbcee94e210a12934e83407e3cf72769c6b2a3a1b150a34412202c9db830f948306b508621a86c06855a15d69b2893c122471457d10a7f0c2aa09b5031faccb166dcd969c14d1ac73154ca2c426977e5cc880bcc319034c688d6fe53a781ecf397dd0551a10035fc270cb9e4916e642889c44eb2014c4f6f24c7e06dc9b9f53aac31526291976b42fe01d08d38287e894349b6f731fc9d01dac12e5c3b15411dd00c125a813fc44255757de34dea9551441312f92183b96ee2ced15c255146b5991fdbab61ee51d153cb44d99b5ece2d77ade3432135e651a4b21a1ffe2a7db8d1916c2fe17b6fee09d6989bfdb9152f19f9b72fe1d319fac02e2b557299bd3f643a107bf12fec657835aa3adf38188f49489c96e17bdb82d24310c9970a2aa31faeb7b4a1d76939cb69ea75f86a50a5f7c738d4e1254b843648691f7e74ecd765bd030e21669a654fde775f5a1a280547204bd9a1c01e854feb06939a565d074c722b6e0110222ea3d1dc4870e7f045279abe3581682aa648d24b529d29e85a657961cef1b91ea5ed836115a438313c8f6dd71751136a5768e8495301464187a7455ced215834e14b2e5ba3c197d9e98d1ea81471b12b14c8fcff4c52f0e63ffc232b10c1156dd1f730372b7bbd13bbf737fdd4f15acd4e74f844ea52ac60aaf50dfd4a31aebe4f0b11251a7dabb666d920b65a610261e6d5e572551d16ac008774efecf14b0650836ad6ea58585f0ca14e2fd031a8e3fc5412c65877353d6fe4cad7e4210718f3652773e6950e88b3ea0581e53144e33c426158e8364e22e4ec8eee56719224075709a71a4fd9aba617a6adfc11f1548498600c786dea0147d8ca22bd9131a9adba7c0782816c9599c2f8b76cf18a180d2d1f096b25b3b7083fb2d54031f64902383569e4f19252632bd9c1462137e74ec23ec85a35faeaf7eecc3993a189d91e72c67678cf7995b9ee73440491e02bb107ca0c0b73a40f9c21021c8ed12c3e9149bc8b0654990b7f354293aa9173324dac1fa1cbf5b74a530aab388931da05628b91c7257b968675e4a70357c12486c72e7a34eade74201f65ccc421b175a074fe14ca298a1938133747f13e21c9864d10c7065ff44fc30a0a82f4c0d12bebd0510cc3e3f563b3dc8923b9f90162e2d07147f0ecf2b8a4c7a770ac7341c3d7c846c0f69615bd66fac8a66fca0114c9ba54753c339f2cb8b572d803b09161f028f192834c8eebe6ead38608a8b1b5361f90f99203d5537656c237c363711a8b9f753bf688c2a857e472c1b04851512a8f528ef822f75265e59f72145e61a0b899979d5b13d09d8da973a35ebcf104eebffd74a1e8d0b8ed13d8902e6031522e6ff8ddd65708ef1458d2b83df441ad5efbf78aa3f06f9b64b38fbb10b6b10caebef1695cf47b7a45e067a9ece8514bde6ab5c7ac319e54df687184642a7193670eb792c1a30aff0f954cf6b890810434c6698b720fcda6c382ac3c6ab0a1454df7f7ee528bb1188c6f473b8560d192ad71fde1ef329162af8f19066ac501f7ae6d34af337da4d1a3b971ac06b921319e0881df0c550e1e0093d21b00677181f18eb246cf7a419594c8c295cc8941e13ef1297a31a07b0b7aff79939fd1c13d8aad77c4ce1089ca59b7500883ce4178e950d9c9f190b038f029300aa4bdd1d797d88c103f0e66199e15b404a4faa12d79ceab104ac60baffd972d01ce354170d4465de05d7f8a87f908f04e41b2a1d884affaa63869bc94fbad9826e513a122a1dbf95fc6702bce3289023cae5c81674e42ebbfb0103ab1c3374ac3c1f7b1cc94efd543de1e1eaf19fc8eb85f3cc117ba23caa8c599a65eec7ba66673040161acbcbd4efef00ffe9796940813cd01bf05effe4f595603f32ec41c8d0256211ac363f5e73bb38cf3e6752fa44afba155704cf3550ea06830e01e738165b291bb662a1217252e411a96090e3edd8f91064bb09aa0e675d56d378745c294f38153d2a8c54d2c0f42b089791b3f362861a669ad77483f8781b65fe3a50d8fd931000810d52a4365762febd49644efdb81440e190664d04edfa7d2d5cfda13ce719c88c1a60b022d4bc6e9c593ee5853010fa2f21785c2b096c8a03f08d5ea73c14f87b299633760b076d046c3136d14b19f6dab37bc053ce488805c7bd83c59e1fda68504d58f4802d75639c56723bc3131083a4606e31e178527c43ec4e0ab4183030303130323033303430353036303730383039313031313132313331343135313631373138313932303231323232333234323532363237323832393330333133323333333433353336333733383339343034313432343334343435343634373438343935303531353235333534353535363537353835393630363136323633363436353636363736383639373037313732373337343735373637373738373938303831383238333834383538363837383838393930393139323933393439353936393739383939302e302f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f636f6c6c656374696f6e732f62747265652f6d61702f656e7472792e7273d3681000850000007001000036000000617373657274696f6e206661696c65643a20696478203c2043415041434954592f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f636f6c6c656374696f6e732f62747265652f6e6f64652e7273617373657274696f6e206661696c65643a20656467652e686569676874203d3d2073656c662e686569676874202d20318869100080000000af020000090000008869100080000000b302000009000000617373657274696f6e206661696c65643a207372632e6c656e2829203d3d206473742e6c656e282988691000800000002f070000050000008869100080000000af040000230000008869100080000000ef04000024000000617373657274696f6e206661696c65643a20656467652e686569676874203d3d2073656c662e6e6f64652e686569676874202d20310000008869100080000000f0030000090000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f636f6c6c656374696f6e732f62747265652f6e617669676174652e7273f86a10008400000059020000300000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f7374722f7061747465726e2e72738c6b100074000000b7050000140000008c6b100074000000b7050000210000008c6b100074000000ab050000210000008c6b1000740000003b040000240000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f7374722f7061747465726e2e7273406c100074000000b705000014000000406c100074000000b705000021000000406c100074000000ab050000210000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f636f6c6c656374696f6e732f62747265652f6e617669676174652e7273e46c100084000000170200002f000000e46c100084000000a200000024000000406c1000740000003b040000240000003a3a416c6c2070617468207365676d656e74732073686f756c642062652076616c69642052757374206964656e746966696572734900000008000000040000004a0000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7363616c652d696e666f2d322e31312e332f7372632f74792f706174682e72730000dc6d1000620000005a0000000e000000dc6d100062000000720000000a000000206973206e6f7420612076616c69642052757374206964656e74696669657200986d100000000000606e10001f000000dc6d100062000000900000002100000072234d697373696e675365676d656e7473496e76616c69644964656e7469666965727365676d656e740000004900000004000000040000004b0000004c00000004000000040000004d000000012f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f737562746c652d322e352e302f7372632f6c69622e72730000ed6e100059000000bf0200000900000057000000080000000400000058000000590000005a000000756e69746120737472696e6762797465206172726179626f6f6c65616e206060866f1000090000008f6f100001000000696e74656765722060000000a06f1000090000008f6f100001000000666c6f6174696e6720706f696e742060bc6f1000100000008f6f100001000000636861726163746572206000dc6f10000b0000008f6f100001000000737472696e672000f86f100007000000756e69742076616c75654f7074696f6e2076616c75656e6577747970652073747275637473657175656e63656d6170656e756d756e69742076617269616e746e6577747970652076617269616e747475706c652076617269616e747374727563742076617269616e746578706c696369742070616e69632f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f73657264652d312e302e3230362f7372632f64652f6d6f642e72737f7010005d000000ec080000120000008f6f1000010000008f6f10000100000060206f72206000008f6f100001000000fc701000060000008f6f1000010000006f6e65206f66202c20000000586f1000000000002e307536346e756d6265720000000000000000000000f03f000000000000244000000000000059400000000000408f40000000000088c34000000000006af8400000000080842e4100000000d01263410000000084d797410000000065cdcd41000000205fa00242000000e876483742000000a2941a6d42000040e59c30a2420000901ec4bcd64200003426f56b0c430080e03779c3414300a0d8855734764300c84e676dc1ab43003d9160e458e143408cb5781daf154450efe2d6e41a4b4492d54d06cff08044f64ae1c7022db544b49dd9794378ea449102282c2a8b2045350332b7f4ad54450284fee471d9894581121f2fe727c04521d7e6fae031f445ea8ca039593e294624b00888ef8d5f46176e05b5b5b893469cc94622e3a6c846037cd8ea9bd0fe46824dc77261423347e32079cff91268471b695743b8179e47b1a1162ad3ced2471d4a9cf487820748a55cc3f129633d48e7191a37fa5d724861a0e0c478f5a64879c818f6d6b2dc484c7dcf59c6ef11499e5c43f0b76b4649c63354eca5067c495ca0b4b32784b14973c8a1a031e5e5498f3aca087e5e1b4a9a647ec50e1b514ac0fddd76d261854a307d951447baba4a3e6edd6c6cb4f04acec9148887e1244b41fc196ae9195a4ba93d50e23150904b134de45a3e64c44b57609df14d7df94b6db8046ea1dc2f4c44f3c2e4e4e9634c15b0f31d5ee4984c1b9c70a5751dcf4c916166876972034df5f93fe9034f384d72f88fe3c4626e4d47fb390ebbfda24d197ac8d129bdd74d9f983a4674ac0d4e649fe4abc88b424e3dc7ddd6ba2e774e0c39958c69faac4ea743ddf7811ce24e9194d475a2a3164fb5b949138b4c4c4f11140eecd6af814f169911a7cc1bb64f5bffd5d0bfa2eb4f99bf85e2b74521507f2f27db259755505ffbf051effc8a501b9d369315dec050624404f89a15f5507b5505b6015b2a516d55c311e1786051c82a3456199794517a35c1abdfbcc9516cc158cb0b160052c7f12ebe8e1b345239aeba6d72226952c75929090f6b9f521dd8b965e9a2d352244e28bfa38b0853ad61f2ae8cae3e530c7d57ed172d73534f5cade85df8a75363b3d86275f6dd531e70c75d09ba1254254c39b58b6847542e9f87a2ae427d547dc39425ad49b2545cf4f96e18dce6547371b88a1e931c55e846b316f3db5155a21860dcef528655ca1e78d3abe7bb553f132b64cb70f1550ed8353dfecc2556124e83cc3d405b56cb10d29f26089156fe94c647304ac5563d3ab859bc9cfa56662413b8f5a1305780ed172673ca6457e0e89def0ffd99578cb1c2f5293ed057ef5d3373b44d04586b35009021613958c54200f469b96f58bb298038e2d3a3582a34a0c6dac8d8583541487811fb0e59c1282debea5c4359f172f8a525347859ad8f760f2f41ae59cc19aa69bde8e2593fa014c4eca2175a4fc819f5a78b4d5a321d30f94877825a7e247c371b15b75a9e2d5b0562daec5a82fc58437d08225ba33b2f949c8a565b8c0a3bb9432d8c5b97e6c4534a9cc15b3d20b6e85c03f65b4da8e32234842b5c3049ce95a032615c7cdb41bb487f955c5b5212ea1adfca5c79734bd270cb005d5750de064dfe345d6de49548e03d6a5dc4ae5d2dac66a05d751ab5385780d45d1261e2066da0095eab7c4d244404405ed6db602d5505745ecc12b978aa06a95e7f57e7165548df5eaf96502e358d135f5bbce4798270485f72eb5d18a38c7e5f27b33aefe517b35ff15f096bdfdde75fedb7cb4557d51d60f4529f8b56a55260b127872eac4e87609df1283a5722bd60029759847635f260c3fc6f25d4c22661f4fbcb2e89735c61787d3fbd35c89161d65c8f2c433ac6610c34b3f7d3c8fb618700d07a845d3162a9008499e5b46562d400e5ff1e229b628420ef5f53f5d062a5e8ea37a8320563cfa2e545527f3a63c185af6b938f706332679b4678b3a463fe40425856e0d9639f6829f7352c1064c6c2f3744337446478b330521445796456e0bc665996af64360c36e0f7bde364438f43d875ad18651473544ed3d84e65ecc7f41084478365e8f931156519b86561787e5abe1fee653d0b8ff8d6d322660cceb2b6cc8857668f815fe4ff6a8d66f9b0bbeedf62c266389d6aea97fbf666864405e57dba2c67d44a23af8ef46167891dec5ab2719667eb24a7f11e0ecc6713770857d3880168d794ca2c08eb35680d3afd37ca656b684844fe629e1fa1685ad5bdfb8567d568b14aad7a67c10a69af4eacace0b840695a62d7d718e77469f13acd0ddf20aa69d644a0688b54e0690c56c842ae69146a8f6b7ad31984496a7306594820e57f6a08a4372d34efb36a0a8d853801ebe86a4cf0a686c1251f6b305628f49877536bbb6b32317f55886baa067ffdde6abe6b2a646f5ecb02f36b353d0b367ec3276c820c8ec35db45d6cd1c7389aba90926cc6f9c640e934c76c37b8f8902302fd6c23739b3a5621326deb4f42c9aba9666de6e392bb16549c6d70ce3b358eb4d16d0cc28ac2b121066e8f722d331eaa3b6e9967fcdf524a716e7f81fb97e79ca56edf61fa7d2104db6e2c7dbcee94e2106f769c6b2a3a1b456f948306b508627a6f3d122471457db06fcc166dcd969ce46f7f5cc880bcc31970cf397dd0551a507043889c44eb20847054aac3152629b970e994349b6f73ef7011dd00c125a82371561441312f9258716b5991fdbab68e71e3d77ade3432c371dc8d1916c2fef77153f19f9b72fe2d72d4f643a107bf627289f49489c96e9772ab31faeb7b4acd720b5f7c738d4e0273cd765bd030e2367381547204bd9a6c73d074c722b6e0a173045279abe358d67386a657961cef0b7414c8f6dd71754174187a7455ced275749e98d1ea8147ab7463ffc232b10ce1743cbf737fdd4f15750baf50dfd4a34a75676d920b65a68075c008774efecfb475f1ca14e2fd03ea75d6fe4cad7e4220768c3ea0581e5354762f4ec8eee5678976bb617a6adfc1bf76157d8ca22bd9f3765a9c2f8b76cf28777083fb2d54035f772632bd9c14629377b07eecc3993ac8775c9ee7344049fe77f9c21021c8ed3278b8f354293aa96778a530aab388939d78675e4a70357cd27801f65ccc421b07798233747f13e23c7931a0a82f4c0d72793dc8923b9f90a6794d7a770ac734dc7970ac8a66fca0117a8c572d803b09467a6fad38608a8b7b7a656c237c3637b17a7f472c1b0485e57a5e59f72145e61a7bdb973a35ebcf507bd23d8902e603857b468d2b83df44ba7b4c38fbb10b6bf07b5f067a9ece85247cf687184642a7597cfa54cf6b8908907c382ac3c6ab0ac47cc7f473b8560df97cf8f19066ac502f7d3b971ac06b92637d0a3d21b00677987d4c8c295cc894ce7db0f79939fd1c037e9c7500883ce4377e039300aa4bdd6d7ee25b404a4faaa27eda72d01ce354d77e908f04e41b2a0d7fbad9826e513a427f299023cae5c8767f3374ac3c1f7bac7fa0c8eb85f3cce17f600000000c000000040000006100000062000000630000006120446973706c617920696d706c656d656e746174696f6e2072657475726e656420616e206572726f7220756e65787065637465646c7900640000000000000001000000650000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f737472696e672e7273487b100070000000330a00000e0000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f7374722f7061747465726e2e7273c87b1000740000000e06000014000000c87b1000740000000e06000021000000c87b1000740000000206000014000000c87b10007400000002060000210000004572726f72617373657274696f6e206661696c65643a2073656c662e69735f636861725f626f756e64617279286e65775f6c656e29000000487b100070000000740500000d000000c87b1000740000008f04000024000000454f46207768696c652070617273696e672061206c697374454f46207768696c652070617273696e6720616e206f626a656374454f46207768696c652070617273696e67206120737472696e67454f46207768696c652070617273696e6720612076616c7565657870656374656420603a60657870656374656420602c60206f7220605d60657870656374656420602c60206f7220607d606578706563746564206964656e7465787065637465642076616c7565657870656374656420602260696e76616c696420657363617065696e76616c6964206e756d6265726e756d626572206f7574206f662072616e6765696e76616c696420756e69636f646520636f646520706f696e74636f6e74726f6c2063686172616374657220285c75303030302d5c75303031462920666f756e64207768696c652070617273696e67206120737472696e676b6579206d757374206265206120737472696e67696e76616c69642076616c75653a206578706563746564206b657920746f2062652061206e756d62657220696e2071756f746573666c6f6174206b6579206d7573742062652066696e6974652028676f74204e614e206f72202b2f2d696e66296c6f6e65206c656164696e6720737572726f6761746520696e2068657820657363617065747261696c696e6720636f6d6d61747261696c696e672063686172616374657273756e657870656374656420656e64206f662068657820657363617065726563757273696f6e206c696d6974206578636565646564206174206c696e652020636f6c756d6e20000000c87b100000000000087f100009000000117f1000080000004572726f72282c206c696e653a202c20636f6c756d6e3a2029000000347f1000060000003a7f100008000000427f10000a0000004c7f100001000000696e76616c696420747970653a202c20657870656374656420000000707f10000e0000007e7f10000b000000696e76616c69642076616c75653a20009c7f10000f0000007e7f10000b000000666c6f6174696e6720706f696e74206060000000bc7f100010000000cc7f1000010000006e756c6c2f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f73657264655f6a736f6e2d312e302e3132342f7372632f6572726f722e7273000000e47f100061000000f701000021000000e47f100061000000fb0100000c000000e47f1000610000000202000021000000e47f1000610000000b0200002a000000e47f1000610000000f0200002c00000030313233343536373839616263646566757575757575757562746e7566727575757575757575757575757575757575750000220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f73657264655f6a736f6e2d312e302e3132342f7372632f726561642e7273a881100060000000a301000045000000a881100060000000a80100003d000000a881100060000000b00100001a000000a881100060000000f801000013000000a881100060000000fd01000033000000a881100060000000010200003e000000a881100060000000070200003a000000a8811000600000005402000013000000a8811000600000006c02000025000000a881100060000000bc0300002f000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00010203040506070809ffffffffffffff0a0b0c0d0e0fffffffffffffffffffffffffffffffffffffffffffffffffffff0a0b0c0d0e0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff696e662d696e664e614e0000660000000c00000004000000670000006800000063000000696e7465726e616c206572726f723a20656e746572656420756e726561636861626c6520636f64652f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f73657264655f6a736f6e2d312e302e3132342f7372632f696f2f636f72652e727300f48310006300000012000000090000005075626c696373705f6170706c69636174696f6e5f63727970746f3a3a737232353531393a3a6170705369676e617475726550617468206e6f742061737369676e65642f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7363616c652d696e666f2d322e31312e332f7372632f6275696c642e727300ab84100060000000b20000001e0000005075626c696373705f6170706c69636174696f6e5f63727970746f3a3a65636473613a3a61707073757065723a3a5075626c69635369676e617475726573757065723a3a5369676e617475726573705f6170706c69636174696f6e5f63727970746f3a3a656432353531393a3a61707041726974686d657469634572726f7273705f61726974686d65746963556e646572666c6f774f766572666c6f774469766973696f6e42795a65726f0073705f61726974686d657469633a3a7065725f7468696e677350657262696c6c50617468206e6f742061737369676e65642f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7363616c652d696e666f2d322e31312e332f7372632f6275696c642e7273000000f985100060000000b20000001e00000075333250617468206e6f742061737369676e65642f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7363616c652d696e666f2d322e31312e332f7372632f6275696c642e72738086100060000000b20000001e000000737232353531393a3a5075626c6963005075626c696373705f636f6e73656e7375735f617572613a3a737232353531393a3a6170705f7372323535313942414245736c6f74206e756d62657263757272656e742065706f6368636861696e2072616e646f6d6e6573732f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f7072696d6974697665732f636f6e73656e7375732f626162652f7372632f6c69622e7273736c6f74206e756d626572206973207536343b2069742073686f756c642072656c61746520696e20736f6d652077617920746f2077616c6c20636c6f636b2074696d653b20696620753634206973206e6f7420656e6f7567682077652073686f756c6420637261736820666f72207361666574793b207165642e0059871000680000007e0100000a00000042616265436f6e66696775726174696f6e73705f636f6e73656e7375735f62616265416c6c6f776564536c6f74735072696d617279536c6f74735072696d617279416e645365636f6e64617279506c61696e536c6f74735072696d617279416e645365636f6e64617279565246536c6f747376617269616e74206964656e7469666965724261626545706f6368436f6e66696775726174696f6e737472756374204261626545706f6368436f6e66696775726174696f6e4f70617175654b65794f776e65727368697050726f6f6645706f6368005072696d61727950726544696765737473705f636f6e73656e7375735f626162653a3a646967657374735365636f6e64617279506c61696e5072654469676573745365636f6e646172795652465072654469676573745072654469676573745072696d6172795365636f6e64617279506c61696e5365636f6e646172795652464e657874436f6e66696744657363726970746f7256315075626c696373705f636f6e73656e7375735f626162653a3a61707050617468206e6f742061737369676e65642f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7363616c652d696e666f2d322e31312e332f7372632f6275696c642e727300e389100060000000b20000001e000000617574686f726974795f696e64657873757065723a3a417574686f72697479496e646578736c6f74536c6f747672665f7369676e61747572655672665369676e61747572655072696d6172795072654469676573745365636f6e64617279506c61696e5072654469676573745365636f6e6461727956524650726544696765737463287536342c2075363429616c6c6f7765645f736c6f7473416c6c6f776564536c6f7473737232353531393a3a5075626c6963736c6f745f6475726174696f6e75363465706f63685f6c656e677468617574686f7269746965735665633c28417574686f7269747949642c2042616265417574686f72697479576569676874293e72616e646f6d6e65737352616e646f6d6e6573735665633c75383e65706f63685f696e64657873746172745f736c6f746475726174696f6e636f6e6669674261626545706f6368436f6e66696775726174696f6e50617468206e6f742061737369676e65642f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7363616c652d696e666f2d322e31312e332f7372632f6275696c642e727300bb8b100060000000b20000001e0000005075626c696373705f636f6e73656e7375735f6772616e6470613a3a617070656432353531393a3a5075626c69635369676e6174757265656432353531393a3a5369676e617475726550617468206e6f742061737369676e65642f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7363616c652d696e666f2d322e31312e332f7372632f6275696c642e72730000868c100060000000b20000001e000000536c6f7473705f636f6e73656e7375735f736c6f7473753634536c6f744475726174696f6e0000005353353850524573705f636f72653a3a63727970746f4b6579547970654964004f70617175654d6574616461746173705f636f7265566f69640000005672665369676e617475726573705f636f72653a3a737232353531393a3a76726650617468206e6f742061737369676e65642f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7363616c652d696e666f2d322e31312e332f7372632f6275696c642e727300008e8d100060000000b20000001e0000005b75383b20345d5665633c75383e7072655f6f75747075745672665072654f757470757470726f6f6656726650726f6f6650617468206e6f742061737369676e65642f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7363616c652d696e666f2d322e31312e332f7372632f6275696c642e72730000428e100060000000b20000001e00000042547265654d61704b560000496e686572656e744461746173705f696e686572656e74736461746142547265654d61703c496e686572656e744964656e7469666965722c205665633c75383e3e436865636b496e686572656e7473526573756c746f6b6179626f6f6c666174616c5f6572726f726572726f7273486f737420746f207761736d2076616c7565732061726520656e636f64656420636f72726563746c793b207165648a00000000000000010000008b0000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f7072696d6974697665732f72756e74696d652d696e746572666163652f7372632f696d706c732e72730000006c8f10006d000000d10000002a0000004572726f72486f737420746f207761736d2070726f766964657320612076616c696420656e756d206469736372696d696e616e743b207165640000008d00000000000000010000008e0000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f7072696d6974697665732f72756e74696d652d696e746572666163652f7372632f706173735f62792e727300389010006f000000a8010000200000008f0000000d0000009000000091000000486f737420746f207761736d2076616c7565732061726520656e636f64656420636f72726563746c793b2071656400008d000000000000000100000092000000389010006f000000000100002b00000028294572726f7200b89010000000000072756e74696d65d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a4890b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe221cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c50617468206e6f742061737369676e65642f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7363616c652d696e666f2d322e31312e332f7372632f6275696c642e7273c091100060000000b20000001e000000436f6e73656e737573456e67696e6549645665633c75383e6c6f67735665633c4469676573744974656d3e696e64657875386572726f724d6f64756c654572726f72546f6b656e4572726f7241726974686d657469634572726f72496e76616c69645472616e73616374696f6e556e6b6e6f776e5472616e73616374696f6e7072696f726974795472616e73616374696f6e5072696f7269747972657175697265735665633c5472616e73616374696f6e5461673e70726f76696465736c6f6e6765766974795472616e73616374696f6e4c6f6e67657669747970726f706167617465626f6f6c5b75383b204d41585f4d4f44554c455f4552524f525f454e434f4445445f53495a455d5472616e73616374696f6e616c4572726f724469676573744974656d73705f72756e74696d653a3a67656e657269633a3a64696765737450726552756e74696d65436f6e73656e7375735365616c4f7468657252756e74696d65456e7669726f6e6d656e74557064617465644469676573744974656d206e6f7420657175616c446967657374c70000000c00000004000000c8000000c9000000ca000000cb0000000000000001000000cc000000cd000000ce000000f09310000000000048617368206e6f7420657175616c00005472616e73616374696f6e2063616c6c206973206e6f74206578706563746564496e6162696c69747920746f2070617920736f6d6520666565732028652e672e206163636f756e742062616c616e636520746f6f206c6f77295472616e73616374696f6e2077696c6c2062652076616c696420696e20746865206675747572655472616e73616374696f6e206973206f757464617465645472616e73616374696f6e20686173206120626164207369676e61747572655472616e73616374696f6e2068617320616e20616e6369656e7420626972746820626c6f636b5472616e73616374696f6e20776f756c6420657868617573742074686520626c6f636b206c696d697473496e76616c69645472616e73616374696f6e20637573746f6d206572726f72412063616c6c20776173206c6162656c6c6564206173206d616e6461746f72792c2062757420726573756c74656420696e20616e204572726f722e5472616e73616374696f6e206469737061746368206973206d616e6461746f72793b207472616e73616374696f6e73206d757374206e6f742062652076616c6964617465642e496e76616c6964207369676e696e672061646472657373436f756c64206e6f74206c6f6f6b757020696e666f726d6174696f6e20726571756972656420746f2076616c696461746520746865207472616e73616374696f6e436f756c64206e6f742066696e6420616e20756e7369676e65642076616c696461746f7220666f722074686520756e7369676e6564207472616e73616374696f6e556e6b6e6f776e5472616e73616374696f6e20637573746f6d206572726f723c7761736d3a73747269707065643e43616e6e6f744c6f6f6b7570496e76616c69645472616e73616374696f6e73705f72756e74696d653a3a7472616e73616374696f6e5f76616c696469747943616c6c5061796d656e744675747572655374616c6542616450726f6f66416e6369656e744269727468426c6f636b45786861757374735265736f7572636573437573746f6d4261644d616e6461746f72794d616e6461746f727956616c69646174696f6e4261645369676e6572556e6b6e6f776e5472616e73616374696f6e4e6f556e7369676e656456616c696461746f725472616e73616374696f6e56616c69646974794572726f72496e76616c6964556e6b6e6f776e5472616e73616374696f6e536f75726365496e426c6f636b4c6f63616c45787465726e616c56616c69645472616e73616374696f6e000000089410002894100061941000889410009f941000be941000e49410000e9510002d95100068951000ae951000200000003900000027000000170000001f000000260000002a0000001f0000003b0000004600000017000000c5951000069610004796100041000000410000001f00000044697370617463684572726f7273705f72756e74696d654d6f64756c654572726f725472616e73616374696f6e616c4572726f724c696d6974526561636865644e6f4c617965724f7468657243616e6e6f744c6f6f6b75704261644f726967696e4d6f64756c65436f6e73756d657252656d61696e696e674e6f50726f766964657273546f6f4d616e79436f6e73756d657273546f6b656e41726974686d657469635472616e73616374696f6e616c457868617573746564436f7272757074696f6e556e617661696c61626c65526f6f744e6f74416c6c6f776564546f6b656e4572726f7246756e6473556e617661696c61626c654f6e6c7950726f766964657242656c6f774d696e696d756d43616e6e6f74437265617465556e6b6e6f776e417373657446726f7a656e556e737570706f7274656443616e6e6f74437265617465486f6c644e6f74457870656e6461626c65426c6f636b656445787472696e736963496e636c7573696f6e4d6f6465416c6c45787472696e736963734f6e6c79496e686572656e74734f706171756556616c75652f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f636f6c6c656374696f6e732f62747265652f6d61702f656e7472792e72730000a9991000850000007001000036000000617373657274696f6e206661696c65643a20696478203c2043415041434954592f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f636f6c6c656374696f6e732f62747265652f6e6f64652e7273617373657274696f6e206661696c65643a20656467652e686569676874203d3d2073656c662e686569676874202d2031609a100080000000af02000009000000609a100080000000b302000009000000617373657274696f6e206661696c65643a207372632e6c656e2829203d3d206473742e6c656e2829609a1000800000002f07000005000000609a100080000000af04000023000000609a100080000000ef04000024000000617373657274696f6e206661696c65643a20656467652e686569676874203d3d2073656c662e6e6f64652e686569676874202d2031000000609a100080000000f0030000090000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f7072696d6974697665732f73746174652d6d616368696e652f7372632f73746174732e7273000000d09b1000690000007c00000023000000d09b1000690000007b0000001e000000d09b1000690000008100000024000000d09b100069000000800000001e000000416e204f7665726c617956616c756520697320616c7761797320637265617465642077697468206174206c65617374206f6e65207472616e73616374696f6e20616e642064726f7070656420617320736f6f6e0a09617320746865206c617374207472616e73616374696f6e2069732072656d6f7665643b207165642f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f7072696d6974697665732f73746174652d6d616368696e652f7372632f6f7665726c617965645f6368616e6765732f6368616e67657365742e727300f89c10007f0000000a0100002b000000f89c10007f000000140100002b000000607365745f7072657660206973206f6e6c792060536f6d65285f29602c206966207468652076616c75652063616d652066726f6d20706172656e743b20716564f89c10007f0000007d010000160000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f7665632f6d6f642e7273000000e89d10007100000027080000240000004c61796f757473697a650000d20000000400000004000000d3000000616c69676e000000d20000000400000004000000d400000043617061636974794f766572666c6f77416c6c6f634572726c61796f75740000d50000000400000004000000d60000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f736d616c6c7665632d312e31332e322f7372632f6c69622e727363616c6c65642060526573756c743a3a756e77726170282960206f6e20616e2060457272602076616c756500d50000000800000004000000d7000000d09e10005c000000520100002e0000006361706163697479206f766572666c6f77000000d09e10005c0000004101000036000000d09e10005c000000ce0400000e000000617373657274696f6e206661696c65643a206e65775f636170203e3d206c656ed09e10005c000000990400000d0000003a6368696c645f73746f726167653a64656661756c743a50617468206e6f742061737369676e65642f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7363616c652d696e666f2d322e31312e332f7372632f6275696c642e727304a0100060000000b20000001e0000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f7072696d6974697665732f747269652f7372632f6e6f64655f636f6465632e727300000074a01000650000003f0000002800000074a0100065000000480000001400000073705f747269653a3a73746f726167655f70726f6f6653746f7261676550726f6f66747269655f6e6f64657342547265655365743c5665633c75383e3e2f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f697465722e727339a1100073000000d60500001500000000000000617474656d707420746f20646976696465206279207a65726f4254726565536574542f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f7072696d6974697665732f747269652f7372632f747269655f73747265616d2e7273e2a11000660000004700000040000000e2a1100066000000470000004d0000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f7072696d6974697665732f747269652f7372632f6c69622e7273000068a210005e000000020200000b00000050617468206e6f742061737369676e65642f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7363616c652d696e666f2d322e31312e332f7372632f6275696c642e7273000000e9a2100060000000b20000001e000000436f775452756e74696d6556657273696f6e73705f76657273696f6e737065635f6e616d6552756e74696d65537472696e67696d706c5f6e616d65617574686f72696e675f76657273696f6e753332737065635f76657273696f6e696d706c5f76657273696f6e61706973417069735665637472616e73616374696f6e5f76657273696f6e73746174655f76657273696f6e7538576569676874287265665f74696d653a202c2070726f6f665f73697a653a2029f0a310001100000001a410000e0000000fa410000100000057656967687473705f776569676874733a3a7765696768745f763252756e74696d65446257656967687473705f7765696768747350617468206e6f742061737369676e65642f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7363616c652d696e666f2d322e31312e332f7372632f6275696c642e72730000006da4100060000000b20000001e0000007265665f74696d6575363470726f6f665f73697a657265616477726974652f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f636f6c6c656374696f6e732f62747265652f6d61702f656e7472792e727300fea41000850000007001000036000000617373657274696f6e206661696c65643a20696478203c2043415041434954592f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f636f6c6c656374696f6e732f62747265652f6e6f64652e7273617373657274696f6e206661696c65643a20656467652e686569676874203d3d2073656c662e686569676874202d2031b4a5100080000000af02000009000000b4a5100080000000b302000009000000617373657274696f6e206661696c65643a207372632e6c656e2829203d3d206473742e6c656e2829b4a51000800000002f07000005000000b4a5100080000000af04000023000000b4a5100080000000ef04000024000000617373657274696f6e206661696c65643a20656467652e686569676874203d3d2073656c662e6e6f64652e686569676874202d2031000000b4a5100080000000f003000009000000617373657274696f6e206661696c65643a206f6c645f6c6566745f6c656e203e3d20636f756e7400b4a5100080000000dd0500000d000000617373657274696f6e206661696c65643a206c656e203e2030000000b4a510008000000065010000090000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f636f6c6c656374696f6e732f62747265652f6e617669676174652e727388a7100084000000590200003000000088a7100084000000310200002f0000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f747269652d64622d302e32392e302f7372632f7472696564626d75742e72730000002ca81000610000006c0000001c0000002ca810006100000061010000320000002ca810006100000046010000320000002ca8100061000000d60100003c000000696e7465726e616c206572726f723a20656e746572656420756e726561636861626c6520636f64653a200000d0a810002a000000604e6f64654f776e65643a3a56616c7565602063616e206f6e6c792062652072657475726e656420666f72207468652068617368206f6620612076616c75652e04a91000400000002ca8100061000000bf0100001100000056616c7565206e6f64652063616e206e6576657220626520696e6c696e65643b207165645ca91000240000002ca8100061000000a400000015000000e10000000400000004000000e2000000e3000000e10000000400000004000000e4000000e50000004a75737420656e636f64656420746865206e6f64652c20736f2069742073686f756c64206465636f646520776974686f757420616e79206572726f72733b2071656400002ca81000610000005707000016000000e10000000800000004000000e6000000e70000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f747269652d64622d302e32392e302f7372632f6e6962626c652f6d6f642e7273000028aa100062000000490000001c000000617373657274696f6e206661696c65643a20216578697374696e675f6b65792e69735f656d707479282900002ca8100061000000f5040000150000002ca81000610000001f0300001e0000002ca8100061000000130300001e0000002ca8100061000000a8060000290000004272616e63682077697468206e6f2073756276616c7565732e20536f6d657468696e672077656e742077726f6e672e002ca81000610000002906000019000000757365645f696e646578206f6e6c7920736574206966206f636375706965643b207165642ca8100061000000310600001e0000002ca810006100000059060000190000002ca81000610000005f0600001e000000696e7465726e616c206572726f723a20656e746572656420756e726561636861626c6520636f64652ca810006100000092060000220000002ca810006100000066020000170000002ca81000610000007302000025000000696e7465726e616c206572726f723a20656e746572656420756e726561636861626c6520636f64652f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f73657264655f6a736f6e2d312e302e3132342f7372632f7365722e7273001cac10005f0000000b060000120000001cac10005f0000002e080000330000001cac10005f000000210800004000000066616c73655c225c5c5c625c665c6e5c725c743a6865617070616765735072696d617279536c6f74735072696d617279416e645365636f6e64617279506c61696e536c6f74735072696d617279416e645365636f6e64617279565246536c6f7473000000c9ac10000c000000d5ac10001d000000f2ac10001b00000063616c6c6f7765645f736c6f7473303030313032303330343035303630373038303931303131313231333134313531363137313831393230323132323233323432353236323732383239333033313332333333343335333633373338333934303431343234333434343534363437343834393530353135323533353435353536353735383539363036313632363336343635363636373638363937303731373237333734373537363737373837393830383138323833383438353836383738383839393039313932393339343935393639373938393944656661756c744572726f7200001cac10005f0000007b020000280000001cac10005f000000a0020000280000001cac10005f000000f8010000280000001cac10005f0000000602000028000000e80000000000000001000000e900000045787465726e616c6974696573206e6f7420616c6c6f77656420746f206661696c2077697468696e2072756e74696d652f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f7072696d6974697665732f73746174652d6d616368696e652f7372632f6578742e7273008cae100067000000ae0000003a0000003a65787472696e7369635f696e6465782f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f746573742d7574696c732f72756e74696d652f7372632f7375627374726174655f746573745f70616c6c65742e72730014af100073000000850000004a0000006361706163697479206f766572666c6f7743617061636974794f766572666c6f77416c6c6f634572726c61796f757400fa0000000400000004000000fb0000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f736d616c6c7665632d312e31332e322f7372632f6c69622e72732f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f627335382d302e352e312f7372632f6465636f64652e7273000034b010005a0000006b0000001e0000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f627335382d302e352e312f7372632f656e636f64652e72730000a0b010005a000000410000001e00000063616c6c65642060526573756c743a3a756e77726170282960206f6e20616e2060457272602076616c756500fa0000000800000004000000fc000000d8af10005c000000520100002e000000d8af10005c0000004101000036000000d8af10005c000000ce0400000e000000617373657274696f6e206661696c65643a206e65775f636170203e3d206c656ed8af10005c000000990400000d0000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f697465722e727300a8b1100073000000d60500001500000000000000617474656d707420746f20646976696465206279207a65726fe29c85206e6f206d6967726174696f6e20666f7220000049b21000150000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f6672616d652f626162652f7372632f6c69622e727372756e74696d653a3a6672616d652d737570706f727470616c6c65745f626162653a3a70616c6c6574f09f90a5204e65772070616c6c65742020646574656374656420696e207468652072756e74696d652e205468652070616c6c657420686173206e6f20646566696e65642073746f726167652076657273696f6e2c20736f20746865206f6e2d636861696e2076657273696f6e206973206265696e6720696e697469616c697a656420746f202eeab2100010000000fab21000750000006fb310000100000072656a656374696e6720756e7369676e6564207265706f72742065717569766f636174696f6e207472616e73616374696f6e2062656361757365206974206973206e6f74206c6f63616c2f696e2d626c6f636b2e88b31000540000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f6672616d652f626162652f7372632f65717569766f636174696f6e2e727372756e74696d653a3a6261626570616c6c65745f626162653a3a65717569766f636174696f6e65706f636820696e646578206973207536343b20697420697320616c77617973206f6e6c7920696e6372656d656e746564206279206f6e653b20696620753634206973206e6f7420656e6f7567682077652073686f756c6420637261736820666f72207361666574793b207165642e0068b2100059000000eb0200004600000045706f6368436f6e66696720697320696e697469616c697a656420696e2067656e657369733b207765206e65766572206074616b6560206f7220606b696c6c602069743b2071656468b2100059000000fd0200002900000068b2100059000000e40200001200000049676e6f72696e6720656d7074792065706f6368206368616e67652e54b510001c00000070616c6c65745f6261626565706f636820696e64696365732077696c6c206e6576657220726561636820325e3634206265666f726520746865206465617468206f662074686520756e6976657273653b2071656468b2100059000000a80200000e000000496e697469616c206e756d626572206f6620617574686f7269746965732073686f756c64206265206c6f776572207468616e20543a3a4d6178417574686f7269746965730a01000000000000010000000b01000068b21000590000002103000016000000417574686f7269746965732061726520616c726561647920696e697469616c697a65642140b610002400000068b21000590000001e0300000d0000002043757272656e742065706f636820696e6465782e2043757272656e742065706f636820617574686f7269746965732e2054686520736c6f74206174207768696368207468652066697273742065706f63682061637475616c6c7920737461727465642e2054686973206973203020756e74696c2074686520666972737420626c6f636b206f662074686520636861696e2e2043757272656e7420736c6f74206e756d6265722e205468652065706f63682072616e646f6d6e65737320666f7220746865202a63757272656e742a2065706f63682e20232053656375726974792054686973204d555354204e4f54206265207573656420666f722067616d626c696e672c2061732069742063616e20626520696e666c75656e6365642062792061206d616c6963696f75732076616c696461746f7220696e207468652073686f7274207465726d2e204974204d4159206265207573656420696e206d616e792063727970746f677261706869632070726f746f636f6c732c20686f77657665722c20736f206c6f6e67206173206f6e652072656d656d626572732074686174207468697320286c696b652065766572797468696e6720656c7365206f6e2d636861696e29206974206973207075626c69632e20466f72206578616d706c652c2069742063616e20626520757365642077686572652061206e756d626572206973206e656564656420746861742063616e6e6f742068617665206265656e2063686f73656e20627920616e206164766572736172792c20666f7220707572706f7365732073756368206173207075626c69632d636f696e207a65726f2d6b6e6f776c656467652070726f6f66732e2050656e64696e672065706f636820636f6e66696775726174696f6e206368616e676520746861742077696c6c206265206170706c696564207768656e20746865206e6578742065706f636820697320656e61637465642e204e6578742065706f63682072616e646f6d6e6573732e204e6578742065706f636820617574686f7269746965732e2052616e646f6d6e65737320756e64657220636f6e737472756374696f6e2e205765206d616b6520612074726164652d6f6666206265747765656e2073746f7261676520616363657373657320616e64206c697374206c656e6774682e2057652073746f72652074686520756e6465722d636f6e737472756374696f6e2072616e646f6d6e65737320696e207365676d656e7473206f6620757020746f2060554e4445525f434f4e535452554354494f4e5f5345474d454e545f4c454e475448602e204f6e63652061207365676d656e7420726561636865732074686973206c656e6774682c20776520626567696e20746865206e657874206f6e652e20576520726573657420616c6c207365676d656e747320616e642072657475726e20746f206030602061742074686520626567696e6e696e67206f662065766572792065706f63682e2054574f582d4e4f54453a20605365676d656e74496e6465786020697320616e20696e6372656173696e6720696e74656765722c20736f2074686973206973206f6b61792e2054656d706f726172792076616c75652028636c656172656420617420626c6f636b2066696e616c697a6174696f6e292077686963682069732060536f6d6560206966207065722d626c6f636b20696e697469616c697a6174696f6e2068617320616c7265616479206265656e2063616c6c656420666f722063757272656e7420626c6f636b2e2054686973206669656c642073686f756c6420616c7761797320626520706f70756c6174656420647572696e6720626c6f636b2070726f63657373696e6720756e6c657373207365636f6e6461727920706c61696e20736c6f74732061726520656e61626c65642028776869636820646f6e277420636f6e7461696e206120565246206f7574707574292e2049742069732073657420696e20606f6e5f66696e616c697a65602c206265666f72652069742077696c6c20636f6e7461696e207468652076616c75652066726f6d20746865206c61737420626c6f636b2e2054686520626c6f636b206e756d62657273207768656e20746865206c61737420616e642063757272656e742065706f6368206861766520737461727465642c20726573706563746976656c7920604e2d316020616e6420604e602e204e4f54453a20576520747261636b207468697320697320696e206f7264657220746f20616e6e6f746174652074686520626c6f636b206e756d626572207768656e206120676976656e20706f6f6c206f6620656e74726f7079207761732066697865642028692e652e20697420776173206b6e6f776e20746f20636861696e206f6273657276657273292e2053696e63652065706f6368732061726520646566696e656420696e20736c6f74732c207768696368206d617920626520736b69707065642c2074686520626c6f636b206e756d62657273206d6179206e6f74206c696e6520757020776974682074686520736c6f74206e756d626572732e20486f77206c617465207468652063757272656e7420626c6f636b20697320636f6d706172656420746f2069747320706172656e742e205468697320656e74727920697320706f70756c617465642061732070617274206f6620626c6f636b20657865637574696f6e20616e6420697320636c65616e6564207570206f6e20626c6f636b2066696e616c697a6174696f6e2e205175657279696e6720746869732073746f7261676520656e747279206f757473696465206f6620626c6f636b20657865637574696f6e20636f6e746578742073686f756c6420616c77617973207969656c64207a65726f2e2054686520636f6e66696775726174696f6e20666f72207468652063757272656e742065706f63682e2053686f756c64206e6576657220626520604e6f6e656020617320697420697320696e697469616c697a656420696e2067656e657369732e2054686520636f6e66696775726174696f6e20666f7220746865206e6578742065706f63682c20604e6f6e65602069662074686520636f6e6669672077696c6c206e6f74206368616e67652028796f752063616e2066616c6c6261636b20746f206045706f6368436f6e6669676020696e737465616420696e20746861742063617365292e2041206c697374206f6620746865206c6173742031303020736b69707065642065706f63687320616e642074686520636f72726573706f6e64696e672073657373696f6e20696e646578207768656e207468652065706f63682077617320736b69707065642e2054686973206973206f6e6c79207573656420666f722076616c69646174696e672065717569766f636174696f6e2070726f6f66732e20416e2065717569766f636174696f6e2070726f6f66206d75737420636f6e7461696e732061206b65792d6f776e6572736869702070726f6f6620666f72206120676976656e2073657373696f6e2c207468657265666f7265207765206e65656420612077617920746f2074696520746f6765746865722073657373696f6e7320616e642065706f636820696e64696365732c20692e652e207765206e65656420746f2076616c6964617465207468617420612076616c696461746f722077617320746865206f776e6572206f66206120676976656e206b6579206f6e206120676976656e2073657373696f6e2c20616e64207768617420746865206163746976652065706f636820696e6465782077617320647572696e6720746861742073657373696f6e2e2054686520616d6f756e74206f662074696d652c20696e20736c6f74732c207468617420656163682065706f63682073686f756c64206c6173742e204e4f54453a2043757272656e746c79206974206973206e6f7420706f737369626c6520746f206368616e6765207468652065706f6368206475726174696f6e2061667465722074686520636861696e2068617320737461727465642e20417474656d7074696e6720746f20646f20736f2077696c6c20627269636b20626c6f636b2070726f64756374696f6e2e45706f63684475726174696f6e20546865206578706563746564206176657261676520626c6f636b2074696d6520617420776869636820424142452073686f756c64206265206372656174696e6720626c6f636b732e2053696e636520424142452069732070726f626162696c6973746963206974206973206e6f74207472697669616c20746f20666967757265206f7574207768617420746865206578706563746564206176657261676520626c6f636b2074696d652073686f756c64206265206261736564206f6e2074686520736c6f74206475726174696f6e20616e642074686520736563757269747920706172616d657465722060636020287768657265206031202d20636020726570726573656e7473207468652070726f626162696c697479206f66206120736c6f74206265696e6720656d707479292e4578706563746564426c6f636b54696d65204d6178206e756d626572206f6620617574686f72697469657320616c6c6f7765644d6178417574686f72697469657320546865206d6178696d756d206e756d626572206f66206e6f6d696e61746f727320666f7220656163682076616c696461746f722e4d61784e6f6d696e61746f727343616c6c54436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e0000dbc31000430000007265706f72745f65717569766f636174696f6e7265706f72745f65717569766f636174696f6e5f756e7369676e6564706c616e5f636f6e6669675f6368616e67654572726f7254686520604572726f726020656e756d206f6620746869732070616c6c65742e00006ec4100020000000496e76616c696445717569766f636174696f6e50726f6f66496e76616c69644b65794f776e65727368697050726f6f664475706c69636174654f6666656e63655265706f7274496e76616c6964436f6e66696775726174696f6e617574686f72697469657365706f6368436f6e666967f2c410000b000000fdc410000b0000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f656e7669726f6e6d656e74616c2d312e312e342f7372632f6c69622e727318c5100060000000920000000f00000018c51000600000008e0000000e0000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f656e7669726f6e6d656e74616c2d312e312e342f7372632f6c6f63616c5f6b65792e7273000098c5100066000000280000001800000098c5100066000000230000001900000098c5100066000000210000001700000073657269616c697a6174696f6e20746f206a736f6e20697320657870656374656420746f20776f726b2e207165642e000c01000004000000040000000d0100002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f6672616d652f737570706f72742f7372632f67656e657369735f6275696c6465725f68656c7065722e72730070c610006f0000003400000012000000496e76616c6964204a534f4e20626c6f623a2000f0c61000130000007374727563742047656e65736973436f6e66696742616265565246496e4f7574436f6e7465787428290000000e01000004000000040000000f0100000e0100000400000004000000100100004261644261736535384261644c656e677468556e6b6e6f776e5373353841646472657373466f726d617400000e010000040000000400000011010000496e76616c6964436865636b73756d496e76616c6964507265666978496e76616c6964466f726d6174496e76616c696450617468466f726d61744e6f74416c6c6f77656450617373776f72644e6f74416c6c6f776564000018c5100060000000630000001b0000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f747269652d64622d302e32392e302f7372632f7472696564622e72730000fcc710005e000000110100003d000000fcc710005e00000010010000370000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f7072696d6974697665732f636f72652f7372632f63727970746f2e72730000007cc81000610000005c01000014000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000102030405060708ffffffffffffff090a0b0c0d0e0f10ff1112131415ff161718191a1b1c1d1e1f20ffffffffffff2122232425262728292a2bff2c2d2e2f30313233343536373839ffffffffff31323334353637383941424344454647484a4b4c4d4e505152535455565758595a6162636465666768696a6b6d6e6f707172737475767778797a00007cc8100061000000330100001d000000e4b3100000000000fcc710005e000000ea00000016000000fcc710005e000000d20000001a000000696e7465726e616c206572726f723a20656e746572656420756e726561636861626c6520636f64652f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f73657264655f6a736f6e2d312e302e3132342f7372632f7365722e7273000cca10005f000000a00200002800000053746f7261676556657273696f6e00000e0100000400000004000000120100005373353841646472657373466f726d617470726566697873746167696e67666f6f626172666f6f62617263616c6c65642060526573756c743a3a756e77726170282960206f6e20616e2060457272602076616c75652f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f746573742d7574696c732f72756e74696d652f7372632f6c69622e72737375627374726174655465737400f1ca100061000000ef02000016000000f1ca100061000000df020000190000003a20000080cb10000000000080cb1000020000006120646566656e73697665206661696c75726520686173206265656e207472696767657265643b20706c65617365207265706f72742074686520626c6f636b206e756d6265722061742068747470733a2f2f6769746875622e636f6d2f706172697479746563682f7375627374726174652f69737375657394cb10007800000072756e74696d653a3a646566656e736976652f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f6672616d652f737570706f72742f7372632f7472616974732f6d6973632e72736672616d655f737570706f72743a3a7472616974733a3a6d697363526573756c7454454f6b4572726e6f7420696d706c656d656e7465642f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f7072696d6974697665732f73746174652d6d616368696e652f7372632f747269655f6261636b656e642e7273000000c1cc100070000000ba000000090000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f6672616d652f73797374656d2f7372632f6c69622e72734163636f756e74496e666f6672616d655f73797374656d4e6f6e63654163636f756e74446174614576656e745265636f7264436f646555706772616465417574686f72697a6174696f6e4c6f676963206572726f723a20556e657870656374656420756e646572666c6f7720696e207265647563696e6720636f6e73756d657200e9cd10003600000072756e74696d653a3a73797374656d4c6f676963206572726f723a20556e657870656374656420756e646572666c6f7720696e207265647563696e672070726f766964657200000037ce1000360000004c6f676963206572726f723a204163636f756e7420616c72656164792064656164207768656e207265647563696e672070726f766964657278ce100038000000c1cc1000700000009100000009000000c1cc1000700000009500000009000000c1cc1000700000008400000009000000c1cc1000700000007c00000009000000c1cc1000700000007800000009000000c1cc1000700000008800000009000000c1cc100070000000ad00000009000000c1cc100070000000a900000009000000003a65787472696e7369635f696e6465784576656e74546f70696373426c6f636b4861736852657365727665734c6f636b734163636f756e74467265657a6573556e646572436f6e737472756374696f6e45787472696e73696344617461486f6c6473426f756e646564566563626f756e6465645f636f6c6c656374696f6e733a3a626f756e6465645f7665635345717569766f636174696f6e50726f6f6673705f636f6e73656e7375735f6772616e647061484e45717569766f636174696f6e507265766f7465507265636f6d6d69742f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f627335382d302e352e312f7372632f656e636f64652e72730009d010005a000000d00100001b00000009d010005a000000d10100001000000009d010005a000000cc0100000900000009d010005a000000b90100002000000009d010005a000000c20100000d00000063616c6c65642060526573756c743a3a756e77726170282960206f6e20616e2060457272602076616c7565002b01000000000000010000002c01000009d010005a0000003d01000020000000427566666572546f6f536d616c6c4f74686572002d01000004000000040000002e01000043616e6e6f744c6f6f6b75704261644f726967696e4d6f64756c65002d01000004000000040000002f010000436f6e73756d657252656d61696e696e674e6f50726f766964657273546f6f4d616e79436f6e73756d657273546f6b656e0000002d01000004000000040000003001000041726974686d6574696300002d0100000400000004000000310100005472616e73616374696f6e616c0000002d010000040000000400000032010000457868617573746564436f7272757074696f6e556e617661696c61626c65526f6f744e6f74416c6c6f7765645068616e746f6d446174613c3e000000fcd110000c00000008d21000010000007375627374726174655f746573745f72756e74696d653a3a52756e74696d652f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f747269652d64622d302e32392e302f7372632f6974657261746f722e7273003bd210006000000087000000160000007765277665206a757374206665746368656420746865206c61737420656c656d656e74207573696e6720606c6173745f6d75746020736f20746869732063616e6e6f74206661696c3b207165640000003bd2100060000000cc0100002b0000004372756d623a3a7374657020616e64205472696544424e6f64654974657261746f722061726520696d706c656d656e74656420736f2074686174207468652061626f76652061726d732061726520746865206f6e6c7920706f737369626c652073746174657300003bd2100060000000e2010000160000003bd21000600000008f0100002600000053746f7261676556657273696f6e00002d01000004000000040000001201000042594500b4d31000030000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f746573742d7574696c732f72756e74696d652f7372632f7375627374726174655f746573745f70616c6c65742e727300c0d3100073000000d500000011000000436f756c64206e6f742072656164202074696d65732066726f6d2074686520737461746544d410000f00000053d4100015000000c0d3100073000000cf0000001900000076616c69646174655f756e7369676e656420000088d41000120000007375627374726174655f746573745f70616c6c65747375627374726174655f746573745f72756e74696d653a3a7375627374726174655f746573745f70616c6c65743a3a70616c6c6574f09f90a5204e65772070616c6c65742020646574656374656420696e207468652072756e74696d652e205468652070616c6c657420686173206e6f20646566696e65642073746f726167652076657273696f6e2c20736f20746865206f6e2d636861696e2076657273696f6e206973206265696e6720696e697469616c697a656420746f202eeed4100010000000fed410007500000073d510000100000072756e74696d653a3a6672616d652d737570706f7274e29c85206e6f206d6967726174696f6e20666f722000a2d5100015000000617574686f72697469657300c0d510000b0000007374727563742047656e65736973436f6e6669673c7761736d3a73747269707065643e43616c6c436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e0000fbd510004300000062656e63685f63616c6c696e636c7564655f6461746173746f726167655f6368616e67656f6666636861696e5f696e6465785f7365746f6666636861696e5f696e6465785f636c656172696e64657865645f63616c6c6465706f7369745f6c6f675f6469676573745f6974656d63616c6c5f776974685f7072696f7269747963616c6c5f646f5f6e6f745f70726f70616761746566696c6c5f626c6f636b72656164726561645f616e645f70616e69630500000001000000010000000300000003000000030000000800000003000000030000000300000004000000040000000400000003000000030000000300000003000000436865636b4d6574616461746148617368436865636b576569676874436865636b4e6f6e6365436865636b4d65746164617461486173683a3a6164646974696f6e616c5f7369676e6564203d3e20000062d7100028000000307872756e74696d653a3a6d657461646174612d686173682f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f6672616d652f6d657461646174612d686173682d657874656e73696f6e2f7372632f6c69622e72736672616d655f6d657461646174615f686173685f657874656e73696f6e5573656420626c6f636b207765696768743a2035d81000130000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f6672616d652f73797374656d2f7372632f657874656e73696f6e732f636865636b5f7765696768742e727372756e74696d653a3a73797374656d6672616d655f73797374656d3a3a657874656e73696f6e733a3a636865636b5f7765696768745573656420626c6f636b206c656e6774683a2000f4d810001300000043757272656e742065706f636820696e64657820206973206c6f776572207468616e2073657373696f6e20696e646578202e000010d910001400000024d910001d00000041d91000010000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f6672616d652f626162652f7372632f6c69622e727372756e74696d653a3a6261626570616c6c65745f626162650000005cd9100059000000b00000000f000000656e636f646564206572726f7220697320726573697a656420746f20626520657175616c20746f20746865206d6178696d756d20656e636f646564206572726f722073697a653b20716564496e76616c696445717569766f636174696f6e50726f6f66496e76616c69644b65794f776e65727368697050726f6f664475706c69636174654f6666656e63655265706f7274496e76616c6964436f6e66696775726174696f6e0000004e0100000c000000040000004f0100006465636f646500006672616d655f73797374656d3a3a657874656e73696f6e733a3a636865636b5f6e6f6e636554457863656564656420626c6f636b206c656e677468206c696d69743a20203e200000c6da10001d000000e3da10000300000045787472696e736963202069732067726561746572207468616e20746865206d61782065787472696e73696320000000f8da10000a00000002db100023000000457863656564656420746865207065722d636c61737320616c6c6f77616e63652e00000038db100021000000546f74616c20626c6f636b207765696768742069732065786365656465642e0064db10001f00000050d810006f000000bc00000011000000416c6c2077656967687420636865636b656420616464206f766572666c6f772e9cdb1000200000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f6672616d652f73797374656d2f7372632f6c69622e727300c4db10005b000000590300000f000000496e76616c6964537065634e616d655370656356657273696f6e4e65656473546f496e6372656173654661696c6564546f4578747261637452756e74696d6556657273696f6e4e6f6e44656661756c74436f6d706f736974654e6f6e5a65726f526566436f756e7443616c6c46696c74657265644d756c7469426c6f636b4d6967726174696f6e734f6e676f696e674e6f7468696e67417574686f72697a6564556e617574686f72697a6564436f727275707465642073746174652061742060603a2000dcdc100014000000f0dc10000300000072756e74696d653a3a73746f726167652f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f6672616d652f737570706f72742f7372632f73746f726167652f756e6861736865642e72736672616d655f737570706f72743a3a73746f726167653a3a756e6861736865642f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f6672616d652f62616c616e6365732f7372632f6c69622e727300009ddd10005d0000007d0100000f00000056657374696e6742616c616e63654c69717569646974795265737472696374696f6e73496e73756666696369656e7442616c616e63654578697374656e7469616c4465706f736974457870656e646162696c6974794578697374696e6756657374696e675363686564756c65446561644163636f756e74546f6f4d616e795265736572766573546f6f4d616e79486f6c6473546f6f4d616e79467265657a657349737375616e6365446561637469766174656444656c74615a65726f507265766f746566696e616c6974795f6772616e647061484e507265636f6d6d697445717569766f636174696f6e4964565347656e65736973536c6f74417574686f7269746965734576656e74436f756e744e65787445706f6368436f6e666967496e697469616c697a656443757272656e74536c6f744e756d6265724c61737452756e74696d6555706772616465417574686f72697a656455706772616465496e61637469766549737375616e636545787472696e736963436f756e74506172656e74486173684e65787452616e646f6d6e657373416c6c45787472696e736963734c656e546f74616c49737375616e63654576656e74735570677261646564546f553332526566436f756e74426c6f636b5765696768745365676d656e74496e646578446967657374457865637574696f6e506861736550656e64696e6745706f6368436f6e6669674368616e67654e657874417574686f72697469657345706f6368496e64657845706f6368436f6e66696745706f636853746172744c6174656e657373496e686572656e74734170706c696564536b697070656445706f636873417574686f7256726652616e646f6d6e6573735570677261646564546f547269706c65526566436f756e7452616e646f6d6e6573735765616b426f756e646564566563626f756e6465645f636f6c6c656374696f6e733a3a7765616b5f626f756e6465645f7665636c656e677468206f66206120626f756e64656420766563746f7220696e2073636f706520206973206e6f74207265737065637465642e0000d4e0100024000000f8e010001200000072756e74696d652f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f626f756e6465642d636f6c6c656374696f6e732d302e322e302f7372632f7765616b5f626f756e6465645f7665632e72735f7068616e746f6d0000500100000000000001000000510100006d6f6465520100000100000001000000530100006d657461646174615f6861736800000052010000210000000100000054010000550100000400000004000000560100005501000004000000040000005701000055010000040000000400000058010000550100000400000004000000590100005501000004000000040000005a0100005501000004000000040000005b0100005501000004000000040000005c0100005501000004000000040000005d01000046756e6473556e617661696c61626c654f6e6c7950726f766964657242656c6f774d696e696d756d43616e6e6f74437265617465556e6b6e6f776e417373657446726f7a656e556e737570706f7274656443616e6e6f74437265617465486f6c644e6f74457870656e6461626c65426c6f636b65644d6f64756c654572726f72696e6465780000005201000001000000010000005e0100006572726f720000005201000004000000010000005f0100006d65737361676500550100000400000004000000600100004c61796f757473697a6500005501000004000000040000003f010000616c69676e00000055010000040000000400000061010000557466384572726f7276616c69645f75705f746f6572726f725f6c656e0000005501000004000000040000006201000046726f6d557466384572726f7262797465730000550100000400000004000000630100004261644261736535384261644c656e677468556e6b6e6f776e5373353841646472657373466f726d6174000055010000040000000400000011010000496e76616c6964436865636b73756d496e76616c6964507265666978496e76616c6964466f726d6174496e76616c696450617468466f726d61744e6f74416c6c6f77656450617373776f72644e6f74416c6c6f7765644e6f6e65536f6d650000550100000400000004000000640100005765696768747265665f74696d6500006501000008000000080000006601000070726f6f665f73697a654c696d6974526561636865644e6f4c6179657263616c6c65642060526573756c743a3a756e77726170282960206f6e20616e2060457272602076616c7565670100001400000004000000680100002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f627335382d302e352e312f7372632f656e636f64652e72730000d8e410005a000000930000002b0000004572726f7244697361626c6564456e61626c6564a0da1000000000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f7072696d6974697665732f636f72652f7372632f63727970746f2e727300000060e51000610000005c01000014000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000102030405060708ffffffffffffff090a0b0c0d0e0f10ff1112131415ff161718191a1b1c1d1e1f20ffffffffffff2122232425262728292a2bff2c2d2e2f30313233343536373839ffffffffff31323334353637383941424344454647484a4b4c4d4e505152535455565758595a6162636465666768696a6b6d6e6f707172737475767778797a000060e5100061000000330100001d000000466574636846726f6d456e76437573746f6d0000550100000400000004000000690100003c7761736d3a73747269707065643e5065724469737061746368436c6173736e6f726d616c0000006501000010000000080000006a0100006f7065726174696f6e616c6d616e6461746f72795501000004000000040000006b0100002bda100043da10005bda100071da1000180000001800000016000000140000000f0000001a0000001d000000130000000f0000000c0000001b000000110000000c00000030dc10003fdc100059dc100076dc100089dc100098dc1000a4dc1000bfdc1000d0dc10000e0000001500000013000000120000000d000000170000000b0000000f0000000c0000000e00000013000000090000000cde10001ade10002fde100042de100054de100061de100078de100083de100092de10009ede1000acde1000bfde1000100000000c0000000c0000000c0000000c000000060000000b000000100000000d0000000700000064e2100074e2100080e210008ce2100098e21000a4e21000aae21000b5e21000c5e21000d2e210007d436865636b53756273747261746543616c6c736565642047656e6572617465206120736574206f662073657373696f6e206b6579732077697468206f7074696f6e616c6c79207573696e672074686520676976656e20736565642e20546865206b6579732073686f756c642062652073746f7265642077697468696e20746865206b657973746f7265206578706f736564207669612072756e74696d652065787465726e616c69746965732e000000205468652073656564206e6565647320746f20626520612076616c69642060757466386020737472696e672e2052657475726e732074686520636f6e636174656e61746564205343414c4520656e636f646564207075626c6963206b6579732e67656e65726174655f73657373696f6e5f6b657973656e636f646564204465636f64652074686520676976656e207075626c69632073657373696f6e206b6579732e2052657475726e7320746865206c697374206f66207075626c696320726177207075626c6963206b657973202b206b657920747970652e6465636f64655f73657373696f6e5f6b6579732053657373696f6e206b6579732072756e74696d65206170692e53657373696f6e4b6579736865616465722053746172747320746865206f66662d636861696e207461736b20666f7220676976656e20626c6f636b206865616465722e6f6666636861696e5f776f726b657220546865206f6666636861696e20776f726b6572206170692e4f6666636861696e576f726b65724170690000a10100000800000004000000a2010000a3010000a4010000a5010000a6010000a7010000a801000061207475706c65206f662073697a652032612073657175656e636565787472696e736963204170706c792074686520676976656e2065787472696e7369632e2052657475726e7320616e20696e636c7573696f6e206f7574636f6d652077686963682073706563696669657320696620746869732065787472696e73696320697320696e636c7564656420696e207468697320626c6f636b206f72206e6f742e6170706c795f65787472696e7369632046696e697368207468652063757272656e7420626c6f636b2e66696e616c697a655f626c6f636b696e686572656e742047656e657261746520696e686572656e742065787472696e736963732e2054686520696e686572656e7420646174612077696c6c20766172792066726f6d20636861696e20746f20636861696e2e696e686572656e745f65787472696e73696373626c6f636b6461746120436865636b20746861742074686520696e686572656e7473206172652076616c69642e2054686520696e686572656e7420646174612077696c6c20766172792066726f6d20636861696e20746f20636861696e2e636865636b5f696e686572656e7473205468652060426c6f636b4275696c646572602061706920747261697420746861742070726f7669646573207468652072657175697265642066756e6374696f6e616c69747920666f72206275696c64696e67206120626c6f636b2e426c6f636b4275696c6465722052657475726e732074686520736c6f74206475726174696f6e20666f7220417572612e2043757272656e746c792c206f6e6c79207468652076616c75652070726f7669646564206279207468697320747970652061742067656e657369732077696c6c20626520757365642e736c6f745f6475726174696f6e2052657475726e207468652063757272656e7420736574206f6620617574686f7269746965732e617574686f72697469657320415049206e656365737361727920666f7220626c6f636b20617574686f7273686970207769746820617572612e417572614170692052657475726e2074686520636f6e66696775726174696f6e20666f7220424142452e636f6e66696775726174696f6e2052657475726e732074686520736c6f7420746861742073746172746564207468652063757272656e742065706f63682e63757272656e745f65706f63685f73746172742052657475726e7320696e666f726d6174696f6e20726567617264696e67207468652063757272656e742065706f63682e63757272656e745f65706f63682052657475726e7320696e666f726d6174696f6e20726567617264696e6720746865206e6578742065706f6368202877686963682077617320616c72656164792070726576696f75736c7920616e6e6f756e636564292e6e6578745f65706f6368736c6f74617574686f726974795f69642047656e65726174657320612070726f6f66206f66206b6579206f776e65727368697020666f722074686520676976656e20617574686f7269747920696e207468652063757272656e742065706f63682e20416e206578616d706c65207573616765206f662074686973206d6f64756c6520697320636f75706c65642077697468207468652073657373696f6e20686973746f726963616c206d6f64756c6520746f2070726f76652074686174206120676976656e20617574686f72697479206b6579206973207469656420746f206120676976656e207374616b696e67206964656e7469747920647572696e6720612073706563696669632073657373696f6e2e2050726f6f6673206f66206b6579206f776e65727368697020617265206e656365737361727920666f72207375626d697474696e672065717569766f636174696f6e207265706f7274732e204e4f54453a206576656e2074686f75676820746865204150492074616b657320612060736c6f746020617320706172616d65746572207468652063757272656e7420696d706c656d656e746174696f6e732069676e6f726573207468697320706172616d6574657220616e6420696e73746561642072656c696573206f6e2074686973206d6574686f64206265696e672063616c6c65642061742074686520636f727265637420626c6f636b206865696768742c20692e652e20616e7920706f696e74206174207768696368207468652065706f636820666f722074686520676976656e20736c6f74206973206c697665206f6e2d636861696e2e2046757475726520696d706c656d656e746174696f6e732077696c6c20696e73746561642075736520696e64657865642064617461207468726f75676820616e206f6666636861696e20776f726b65722c206e6f7420726571756972696e67206f6c6465722073746174657320746f20626520617661696c61626c652e67656e65726174655f6b65795f6f776e6572736869705f70726f6f6665717569766f636174696f6e5f70726f6f666b65795f6f776e65725f70726f6f66205375626d69747320616e20756e7369676e65642065787472696e73696320746f207265706f727420616e2065717569766f636174696f6e2e205468652063616c6c6572206d7573742070726f76696465207468652065717569766f636174696f6e2070726f6f6620616e642061206b6579206f776e6572736869702070726f6f66202873686f756c64206265206f627461696e6564207573696e67206067656e65726174655f6b65795f6f776e6572736869705f70726f6f6660292e205468652065787472696e7369632077696c6c20626520756e7369676e656420616e642073686f756c64206f6e6c7920626520616363657074656420666f72206c6f63616c20617574686f727368697020286e6f7420746f2062652062726f61646361737420746f20746865206e6574776f726b292e2054686973206d6574686f642072657475726e7320604e6f6e6560207768656e206372656174696f6e206f66207468652065787472696e736963206661696c732c20652e672e2069662065717569766f636174696f6e207265706f7274696e672069732064697361626c656420666f722074686520676976656e2072756e74696d652028692e652e2074686973206d6574686f642069732068617264636f64656420746f2072657475726e20604e6f6e6560292e204f6e6c792075736566756c20696e20616e206f6666636861696e20636f6e746578742e7375626d69745f7265706f72745f65717569766f636174696f6e5f756e7369676e65645f65787472696e73696320415049206e656365737361727920666f7220626c6f636b20617574686f7273686970207769746820424142452e426162654170696a736f6e204275696c64206052756e74696d6547656e65736973436f6e666967602066726f6d2061204a534f4e20626c6f62206e6f74207573696e6720616e792064656661756c747320616e642073746f726520697420696e207468652073746f726167652e20496e207468652063617365206f662061204652414d452d62617365642072756e74696d652c20746869732066756e6374696f6e20646573657269616c697a6573207468652066756c6c206052756e74696d6547656e65736973436f6e666967602066726f6d2074686520676976656e204a534f4e20626c6f6220616e64207075747320697420696e746f207468652073746f726167652e204966207468652070726f7669646564204a534f4e20626c6f6220697320696e636f7272656374206f7220696e636f6d706c657465206f722074686520646573657269616c697a6174696f6e206661696c732c20616e206572726f722069732072657475726e65642e20506c65617365206e6f746520746861742070726f7669646564204a534f4e20626c6f62206d75737420636f6e7461696e20616c6c206052756e74696d6547656e65736973436f6e66696760206669656c64732c206e6f2064656661756c74732077696c6c20626520757365642e6275696c645f737461746569642052657475726e732061204a534f4e20626c6f6220726570726573656e746174696f6e206f6620746865206275696c742d696e206052756e74696d6547656e65736973436f6e66696760206964656e74696669656420627920606964602e204966206069646020697320604e6f6e6560207468652066756e6374696f6e2072657475726e73204a534f4e20626c6f6220726570726573656e746174696f6e206f66207468652064656661756c74206052756e74696d6547656e65736973436f6e6669676020737472756374206f66207468652072756e74696d652e20496d706c656d656e746174696f6e206d7573742070726f766964652064656661756c74206052756e74696d6547656e65736973436f6e666967602e204f74686572776973652066756e6374696f6e2072657475726e732061204a534f4e20726570726573656e746174696f6e206f6620746865206275696c742d696e2c206e616d6564206052756e74696d6547656e65736973436f6e6669676020707265736574206964656e74696669656420627920606964602c206f7220604e6f6e656020696620737563682070726573657420646f6573206e6f74206578697374732e2052657475726e656420605665633c75383e6020636f6e7461696e73206279746573206f66204a534f4e20626c6f62202870617463682920776869636820636f6d7072697365732061206c697374206f662028706f74656e7469616c6c79206e657374656429206b65792d76616c756520706169727320746861742061726520696e74656e64656420666f7220637573746f6d697a696e67207468652064656661756c742072756e74696d652067656e6573697320636f6e6669672e20546865207061746368207368616c6c206265206d657267656420287266633733383629207769746820746865204a534f4e20726570726573656e746174696f6e206f66207468652064656661756c74206052756e74696d6547656e65736973436f6e6669676020746f20637265617465206120636f6d70726568656e736976652067656e6573697320636f6e66696720746861742063616e206265207573656420696e20606275696c645f737461746560206d6574686f642e6765745f7072657365742052657475726e732061206c697374206f66206964656e7469666965727320666f7220617661696c61626c65206275696c74696e206052756e74696d6547656e65736973436f6e6669676020707265736574732e2054686520707265736574732066726f6d20746865206c6973742063616e20626520717565726965642077697468205b6047656e657369734275696c6465723a3a6765745f707265736574605d206d6574686f642e204966206e6f206e616d65642070726573657473206172652070726f7669646564206279207468652072756e74696d6520746865206c69737420697320656d7074792e7072657365745f6e616d65732041504920746f20696e74657261637420776974682052756e74696d6547656e65736973436f6e66696720666f72207468652072756e74696d6547656e657369734275696c646572736f757263657478626c6f636b5f686173682056616c696461746520746865207472616e73616374696f6e2e2054686973206d6574686f6420697320696e766f6b656420627920746865207472616e73616374696f6e20706f6f6c20746f206c6561726e2064657461696c732061626f757420676976656e207472616e73616374696f6e2e2054686520696d706c656d656e746174696f6e2073686f756c64206d616b65207375726520746f207665726966792074686520636f72726563746e657373206f6620746865207472616e73616374696f6e20616761696e73742063757272656e742073746174652e2054686520676976656e2060626c6f636b5f686173686020636f72726573706f6e647320746f207468652068617368206f662074686520626c6f636b207468617420697320757365642061732063757272656e742073746174652e204e6f7465207468617420746869732063616c6c206d617920626520706572666f726d65642062792074686520706f6f6c206d756c7469706c652074696d657320616e64207472616e73616374696f6e73206d6967687420626520766572696669656420696e20616e7920706f737369626c65206f726465722e76616c69646174655f7472616e73616374696f6e2054686520605461676765645472616e73616374696f6e5175657565602061706920747261697420666f7220696e746572666572696e67207769746820746865207472616e73616374696f6e2071756575652e5461676765645472616e73616374696f6e517565756520476574207468652063757272656e74204752414e44504120617574686f72697469657320616e6420776569676874732e20546869732073686f756c64206e6f74206368616e67652065786365707420666f72207768656e206368616e67657320617265207363686564756c656420616e642074686520636f72726573706f6e64696e672064656c617920686173207061737365642e205768656e2063616c6c656420617420626c6f636b20422c2069742077696c6c2072657475726e2074686520736574206f6620617574686f72697469657320746861742073686f756c64206265207573656420746f2066696e616c697a652064657363656e64616e7473206f66207468697320626c6f636b2028422b312c20422b322c202e2e2e292e2054686520626c6f636b204220697473656c662069732066696e616c697a65642062792074686520617574686f7269746965732066726f6d20626c6f636b20422d312e6772616e6470615f617574686f7269746965737365745f696420676976656e207365742e20416e206578616d706c65207573616765206f662074686973206d6f64756c6520697320636f75706c6564207769746820746865204e4f54453a206576656e2074686f75676820746865204150492074616b6573206120607365745f69646020617320706172616d65746572207468652063757272656e7420696d706c656d656e746174696f6e732069676e6f7265207468697320706172616d6574657220616e6420696e73746561642072656c79206f6e20746869732077686963682074686520676976656e20736574206964206973206c697665206f6e2d636861696e2e2046757475726520696d706c656d656e746174696f6e732077696c6c20696e73746561642075736520696e64657865642064617461207468726f75676820616e206f6666636861696e20776f726b65722c206e6f7420726571756972696e67206f6c6465722073746174657320746f20626520617661696c61626c652e204765742063757272656e74204752414e44504120617574686f72697479207365742069642e63757272656e745f7365745f6964204150497320666f7220696e746567726174696e6720746865204752414e4450412066696e616c6974792067616467657420696e746f2072756e74696d65732e20546869732073686f756c6420626520696d706c656d656e746564206f6e207468652072756e74696d6520736964652e2054686973206973207072696d6172696c79207573656420666f72206e65676f74696174696e6720617574686f726974792d736574206368616e67657320666f7220746865206761646765742e204752414e44504120757365732061207369676e616c696e67206d6f64656c206f66206368616e67696e6720617574686f7269747920736574733a206368616e6765732073686f756c64206265207369676e616c6564207769746820612064656c6179206f66204e20626c6f636b732c20616e64207468656e206175746f6d61746963616c6c79206170706c69656420696e207468652072756e74696d652061667465722074686f7365204e20626c6f636b732068617665207061737365642e2054686520636f6e73656e7375732070726f746f636f6c2077696c6c20636f6f7264696e617465207468652068616e646f66662065787465726e616c6c792e4772616e6470614170696163636f756e74204765742063757272656e74206163636f756e74206e6f6e6365206f6620676976656e20604163636f756e744964602e6163636f756e745f6e6f6e6365205468652041504920746f207175657279206163636f756e74206e6f6e63652e4163636f756e744e6f6e63654170692829a90100000000000001000000aa0100002052657475726e73207468652076657273696f6e206f66207468652072756e74696d652e76657273696f6e20457865637574652074686520676976656e20626c6f636b2e657865637574655f626c6f636b20496e697469616c697a65206120626c6f636b20776974682074686520676976656e2068656164657220616e642072657475726e207468652072756e74696d6520657865637574697665206d6f64652e696e697469616c697a655f626c6f636b205468652060436f7265602072756e74696d65206170692074686174206576657279205375627374726174652072756e74696d65206e6565647320746f20696d706c656d656e742e436f72652052657475726e7320746865206d65746164617461206f6620612072756e74696d652e6d657461646174612052657475726e7320746865206d65746164617461206174206120676976656e2076657273696f6e2e2049662074686520676976656e206076657273696f6e602069736e277420737570706f727465642c20746869732077696c6c2072657475726e20604e6f6e65602e20557365205b6053656c663a3a6d657461646174615f76657273696f6e73605d20746f2066696e64206f75742061626f757420737570706f72746564206d657461646174612076657273696f6e206f66207468652072756e74696d652e6d657461646174615f61745f76657273696f6e2052657475726e732074686520737570706f72746564206d657461646174612076657273696f6e732e20546869732063616e206265207573656420746f2063616c6c20606d657461646174615f61745f76657273696f6e602e6d657461646174615f76657273696f6e732054686520604d65746164617461602061706920747261697420746861742072657475726e73206d6574616461746120666f72207468652072756e74696d652e4d657461646174614f6b0000a10100000400000004000000ab01000045727200a10100000400000004000000ab010000a10100000c00000004000000ac010000ad010000ae010000af010000b0010000b1010000b2010000b30100007c00000004000000b4010000b5010000b60100003800000004000000b7010000b8010000b9010000ba010000bb010000bc010000bd010000a10100000400000004000000be01000001000000000000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f746573742d7574696c732f72756e74696d652f7372632f6c69622e727376616c6964617465000000d5051100080000007375627374726174652d746573742d72756e74696d657375627374726174655f746573745f72756e74696d653031303330303030303030303030303030303034363430343030303030303030303130333030303030303030303030303030303436393034303130303030303000000000b60100003800000004000000bf010000c0010000617373657274696f6e206661696c65643a20616c6c2e636f6e7461696e7328267075626c6963302974051100610000000003000005000000617373657274696f6e206661696c65643a20616c6c2e636f6e7461696e7328267075626c6963312974051100610000000103000005000000617373657274696f6e206661696c65643a20616c6c2e636f6e7461696e7328267075626c69633229740511006100000002030000050000006564323535313947656e65726174657320612076616c696420606564323535313960207369676e61747572652e0000007405110061000000040300002e000000617373657274696f6e206661696c65643a207075626c6963302e76657269667928262265643235353139222c20267369676e6174757265297405110061000000050300000500000074051100610000000f0300000500000074051100610000001003000005000000740511006100000011030000050000007372323535313947656e65726174657320612076616c696420607372323535313960207369676e61747572652e0000007405110061000000130300002e000000617373657274696f6e206661696c65643a207075626c6963302e76657269667928262273723235353139222c20267369676e6174757265297405110061000000140300000500000074051100610000001e0300000500000074051100610000001f0300000500000074051100610000002003000005000000656364736147656e65726174657320612076616c69642060656364736160207369676e61747572652e0000007405110061000000220300002c000000617373657274696f6e206661696c65643a207075626c6963302e7665726966792826226563647361222c20267369676e617475726529000074051100610000002403000005000000746573743a726561645f73746f72616765000000010000000400000074051100610000002e030000050000000809110074051100610000002f0300000500000074051100610000003303000005000000000000005809110074051100610000003403000005000000756e697175655f69645f313a726561645f6368696c645f73746f72616765000074051100610000003e0300000500000074051100610000003f03000005000000740511006100000043030000050000007405110061000000440300000500000076616c756533617373657274696f6e206661696c65643a206578742e73746f726167655f726f6f742844656661756c743a3a64656661756c742829292e61735f736c6963652829203d3d2026726f6f745b2e2e5d74051100610000005303000005000000617373657274696f6e206661696c65643a206578742e73746f726167655f726f6f742844656661756c743a3a64656661756c742829292e61735f736c696365282920213d2026726f6f745b2e2e5d000074051100610000005503000005000000617373657274696f6e206661696c65643a206578742e73746f7261676528622276616c75653322292e69735f736f6d6528290000740511006100000052030000050000003c7761736d3a73747269707065643e5472616e73666572446174612052657475726e207468652062616c616e6365206f662074686520676976656e206163636f756e742069642e62616c616e63655f6f6676616c20412062656e63686d61726b2066756e6374696f6e20746861742061646473206f6e6520746f2074686520676976656e2076616c756520616e642072657475726e732074686520726573756c742e62656e63686d61726b5f6164645f6f6e6576656320412062656e63686d61726b2066756e6374696f6e20746861742061646473206f6e6520746f20656163682076616c756520696e2074686520676976656e20766563746f7220616e642072657475726e732074686520726573756c742e62656e63686d61726b5f766563746f725f6164645f6f6e6520546865206e6577207369676e61747572652e66756e6374696f6e5f7369676e61747572655f6368616e6765642074726965206e6f5f7374642074657374696e677573655f747269652043616c6c732066756e6374696f6e20696e20746865206c6f6f70207573696e67206e657665722d696e6c696e65642066756e6374696f6e20706f696e74657262656e63686d61726b5f696e6469726563745f63616c6c2043616c6c732066756e6374696f6e20696e20746865206c6f6f7062656e63686d61726b5f6469726563745f63616c6c73697a6520416c6c6f636174657320766563746f72207769746820676976656e2063617061636974792e7665635f776974685f63617061636974792052657475726e732074686520696e697469616c697a656420626c6f636b206e756d6265722e6765745f626c6f636b5f6e756d62657220546573742074686174206065643235353139602063727970746f20776f726b7320696e207468652072756e74696d652e2052657475726e7320746865207369676e61747572652067656e65726174656420666f7220746865206d6573736167652060656432353531396020616e6420746865207075626c6963206b65792e746573745f656432353531395f63727970746f20546573742074686174206073723235353139602063727970746f20776f726b7320696e207468652072756e74696d652e2052657475726e7320746865207369676e61747572652067656e65726174656420666f7220746865206d657373616765206073723235353139602e746573745f737232353531395f63727970746f2054657374207468617420606563647361602063727970746f20776f726b7320696e207468652072756e74696d652e2052657475726e7320746865207369676e61747572652067656e65726174656420666f7220746865206d65737361676520606563647361602e746573745f65636473615f63727970746f2052756e20766172696f757320746573747320616761696e73742073746f726167652e746573745f73746f7261676570726f6f66726f6f7420436865636b2061207769746e6573732e746573745f7769746e6573736f746865726e756d2054657374207468617420656e737572657320746861742077652063616e2063616c6c20612066756e6374696f6e20746861742074616b6573206d756c7469706c6520617267756d656e74732e746573745f6d756c7469706c655f617267756d656e747320547261636573206c6f6720224865792049276d2072756e74696d652e22646f5f74726163655f6c6f677369677075626c69636d657373616765205665726966792074686520676976656e207369676e61747572652c207075626c69632026206d6573736167652062756e646c652e7665726966795f656432353531396b657976616c756570616e69632057726974652074686520676976656e206076616c75656020756e6465722074686520676976656e20606b65796020696e746f207468652073746f7261676520616e64207468656e206f7074696f6e616c2070616e69632e77726974655f6b65795f76616c756554657374415049657865637574655f626c6f636b3a200000871011000f0000007405110061000000d80100000d000000696e697469616c697a655f626c6f636b3a200000b0101100120000007405110061000000dd0100000d00000076616c69646174655f7472616e73616374696f6e20200000dc10110015000000f1101100010000005deb10000e0000007405110061000000010200000d0000007405110061000000510200000d0000007405110061000000520200000d0000004865792049276d2072756e74696d65003c1111000f000000544849532049532054524143494e474669656c6453657420636f727275707465642028746869732069732061206275672900000074051100610000005a0200000d0000004865792c2049276d2074726163696e679811110010000000a10100001800000004000000c1010000a10100000400000004000000c201000049276d206a75737420666f6c6c6f77696e67206d79206d6173746572d01111001c0000007405110061000000650200001100000063616c6c65642060526573756c743a3a756e77726170282960206f6e20616e2060457272602076616c756500a90100000000000001000000c30100007405110061000000a60200003f000000666f6f62617273746167696e676576656e74202f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f746573742d7574696c732f72756e74696d652f7372632f6c69622e72733a363032c20f110007000000daeb100004000000a10100000c00000004000000c4010000c5010000c6010000010000005a020000000000005d1211006b0000000809110004000000c812110002000000e0911100d8121100fe05110016000000740511006100000001000000a90100000000000001000000c7010000c8010000c9010000a90100000000000001000000c7010000c9010000c901000042616c616e636573537562737472617465546573744261626553797374656d52756e74696d65486f6c64526561736f6e73797374656d626162657375627374726174655465737462616c616e63657300901311000600000096131100040000009a1311000d000000a7131100080000007374727563742052756e74696d6547656e65736973436f6e66696752756e74696d6543616c6c52756e74696d654572726f7252756e74696d654576656e7452756e74696d652f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f6672616d652f73797374656d2f7372632f6c69622e727372656d61726b7365745f686561705f70616765737365745f636f64657365745f636f64655f776974686f75745f636865636b737365745f73746f726167656b696c6c5f73746f726167656b696c6c5f70726566697872656d61726b5f776974685f6576656e74617574686f72697a655f75706772616465617574686f72697a655f757067726164655f776974686f75745f636865636b736170706c795f617574686f72697a65645f75706772616465e29c85206e6f206d6967726174696f6e20666f72201f1511001500000072756e74696d653a3a6672616d652d737570706f72746672616d655f73797374656d3a3a70616c6c65743a65787472696e7369635f696e646578f09f90a5204e65772070616c6c65742020646574656374656420696e207468652072756e74696d652e205468652070616c6c657420686173206e6f20646566696e65642073746f726167652076657273696f6e2c20736f20746865206f6e2d636861696e2076657273696f6e206973206265696e6720696e697469616c697a656420746f202e76151100100000008615110075000000fb151100010000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f747269652d64622d302e32392e302f7372632f6e6f64652e72736672616d655f73797374656d3a3a696e697469616c697a653a696e747261626c6f636b5f656e74726f70790045787472696e736963206661696c656420617420626c6f636b28293a200000009c1611001a000000b61611000300000072756e74696d653a3a73797374656d6672616d655f73797374656d3a636f64655b5d202065787472696e736963732c206c656e6774683a2020286e6f726d616c20252c206f703a20252c206d616e6461746f7279202529202f206e6f726d616c207765696768743a20282529206f7020776569676874202529202f206d616e6461746f72792077656967687420252900ec16110001000000ed16110002000000ef1611001500000004171100090000000d17110007000000141711000d00000021171100130000003417110002000000361711000d00000034171100020000004317110016000000341711000200000059171100020000004e6f646520697320636f6e6669677572656420746f20757365207468652073616d6520686173683b20716564d80100000000000001000000d9010000151411005b000000470700000e000000205468652066756c6c206163636f756e7420696e666f726d6174696f6e20666f72206120706172746963756c6172206163636f756e742049442e20546f74616c2065787472696e7369637320636f756e7420666f72207468652063757272656e7420626c6f636b2e205768657468657220616c6c20696e686572656e74732068617665206265656e206170706c6965642e205468652063757272656e742077656967687420666f722074686520626c6f636b2e20546f74616c206c656e6774682028696e2062797465732920666f7220616c6c2065787472696e736963732070757420746f6765746865722c20666f72207468652063757272656e7420626c6f636b2e204d6170206f6620626c6f636b206e756d6265727320746f20626c6f636b206861736865732e2045787472696e73696373206461746120666f72207468652063757272656e7420626c6f636b20286d61707320616e2065787472696e736963277320696e64657820746f206974732064617461292e205468652063757272656e7420626c6f636b206e756d626572206265696e672070726f6365737365642e205365742062792060657865637574655f626c6f636b602e2048617368206f66207468652070726576696f757320626c6f636b2e20446967657374206f66207468652063757272656e7420626c6f636b2c20616c736f2070617274206f662074686520626c6f636b206865616465722e204576656e7473206465706f736974656420666f72207468652063757272656e7420626c6f636b2e204e4f54453a20546865206974656d20697320756e626f756e6420616e642073686f756c64207468657265666f7265206e657665722062652072656164206f6e20636861696e2e20497420636f756c64206f746865727769736520696e666c6174652074686520506f562073697a65206f66206120626c6f636b2e204576656e747320686176652061206c6172676520696e2d6d656d6f72792073697a652e20426f7820746865206576656e747320746f206e6f7420676f206f75742d6f662d6d656d6f7279206a75737420696e206361736520736f6d656f6e65207374696c6c207265616473207468656d2066726f6d2077697468696e207468652072756e74696d652e20546865206e756d626572206f66206576656e747320696e2074686520604576656e74733c543e60206c6973742e204d617070696e67206265747765656e206120746f7069632028726570726573656e74656420627920543a3a486173682920616e64206120766563746f72206f6620696e6465786573206f66206576656e747320696e2074686520603c4576656e74733c543e3e60206c6973742e20416c6c20746f70696320766563746f727320686176652064657465726d696e69737469632073746f72616765206c6f636174696f6e7320646570656e64696e67206f6e2074686520746f7069632e205468697320616c6c6f7773206c696768742d636c69656e747320746f206c6576657261676520746865206368616e67657320747269652073746f7261676520747261636b696e67206d656368616e69736d20616e6420696e2063617365206f66206368616e67657320666574636820746865206c697374206f66206576656e7473206f6620696e7465726573742e205468652076616c756520686173207468652074797065206028426c6f636b4e756d626572466f723c543e2c204576656e74496e646578296020626563617573652069662077652075736564206f6e6c79206a7573742074686520604576656e74496e64657860207468656e20696e20636173652069662074686520746f70696320686173207468652073616d6520636f6e74656e7473206f6e20746865206e65787420626c6f636b206e6f206e6f74696669636174696f6e2077696c6c20626520747269676765726564207468757320746865206576656e74206d69676874206265206c6f73742e2053746f726573207468652060737065635f76657273696f6e6020616e642060737065635f6e616d6560206f66207768656e20746865206c6173742072756e74696d6520757067726164652068617070656e65642e2054727565206966207765206861766520757067726164656420736f207468617420607479706520526566436f756e74602069732060753332602e2046616c7365202864656661756c7429206966206e6f742e2054727565206966207765206861766520757067726164656420736f2074686174204163636f756e74496e666f20636f6e7461696e73207468726565207479706573206f662060526566436f756e74602e2046616c7365202864656661756c7429206966206e6f742e2054686520657865637574696f6e207068617365206f662074686520626c6f636b2e2060536f6d6560206966206120636f6465207570677261646520686173206265656e20617574686f72697a65642e20426c6f636b20262065787472696e7369637320776569676874733a20626173652076616c75657320616e64206c696d6974732e426c6f636b5765696768747320546865206d6178696d756d206c656e677468206f66206120626c6f636b2028696e206279746573292e426c6f636b4c656e677468204d6178696d756d206e756d626572206f6620626c6f636b206e756d62657220746f20626c6f636b2068617368206d617070696e677320746f206b65657020286f6c64657374207072756e6564206669727374292e426c6f636b48617368436f756e742054686520776569676874206f662072756e74696d65206461746162617365206f7065726174696f6e73207468652072756e74696d652063616e20696e766f6b652e4462576569676874204765742074686520636861696e277320696e2d636f64652076657273696f6e2e56657273696f6e205468652064657369676e61746564205353353820707265666978206f66207468697320636861696e2e2054686973207265706c6163657320746865202273733538466f726d6174222070726f7065727479206465636c6172656420696e2074686520636861696e20737065632e20526561736f6e2069732074686174207468652072756e74696d652073686f756c64206b6e6f772061626f7574207468652070726566697820696e206f7264657220746f206d616b6520757365206f6620697420617320616e206964656e746966696572206f662074686520636861696e2e5353353850726566697843616c6c54436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e004c211100430000004572726f724572726f7220666f72207468652053797374656d2070616c6c65749d2111001b000000496e76616c6964537065634e616d655370656356657273696f6e4e65656473546f496e6372656173654661696c6564546f4578747261637452756e74696d6556657273696f6e4e6f6e44656661756c74436f6d706f736974654e6f6e5a65726f526566436f756e7443616c6c46696c74657265644d756c7469426c6f636b4d6967726174696f6e734f6e676f696e674e6f7468696e67417574686f72697a6564556e617574686f72697a65644576656e744576656e7420666f72207468652053797374656d2070616c6c65742e000000712211001c00000045787472696e7369635375636365737345787472696e7369634661696c6564436f6465557064617465644e65774163636f756e744b696c6c65644163636f756e7452656d61726b656455706772616465417574686f72697a65644964416d6f756e746672616d655f737570706f72743a3a7472616974733a3a746f6b656e733a3a6d697363496442616c616e63650000da010000da010000da010000da010000446566656e736976656c792062756d70696e67206120636f6e73756d6572207265662e0038231100230000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f6672616d652f62616c616e6365732f7372632f6c69622e727372756e74696d653a3a62616c616e63657370616c6c65745f62616c616e6365733a3a70616c6c6574617373657274696f6e206661696c65643a206163636f756e742e667265652e69735f7a65726f2829207c7c206163636f756e742e66726565203e3d206564207c7c20216163636f756e742e72657365727665642e69735f7a65726f28290000642311005d0000002b040000150000007374727563742047656e65736973436f6e666967141611005c000000e800000019000000141611005c000000da00000019000000141611005c000000870000001e00000053746f7261676556657273696f6e0000db010000040000000400000012010000010000000000000000000000000000000000000000000000000000000000000000000000000000000100000001000000010000000600000001000000010000000100000002000000020000000200000001000000010000000100000001000000696e7465726e616c206572726f723a20656e746572656420756e726561636861626c6520636f64652f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7061726974792d7363616c652d636f6465632d332e362e31322f7372632f636f6d706163742e72730000736869667465642073756666696369656e74206269747320726967687420746f206c656164206f6e6c79206c656164696e67207a65726f733b20716564000000b02511003d0000000000000000000000442511006a0000005e0100001100000056524648617368565246526573756c747672662d696e7672662d6f75742f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f73657264655f6a736f6e2d312e302e3132342f7372632f64652e7273002d2611005e0000009a040000220000002d2611005e0000009004000026000000de0100000000000001000000aa0100003a5f5f53544f524147455f56455253494f4e5f5f3a000000de0100000000000001000000df010000de0100000000000001000000df010000de0100000000000001000000df01000063616c6c6f7765645f736c6f7473737472756374204261626545706f6368436f6e66696775726174696f6e2077697468203220656c656d656e747300122711002d000000e00100000800000004000000e1010000617574686f72697469657365706f6368436f6e6669677374727563742047656e65736973436f6e6669672077697468203220656c656d656e747300006e2711002400000062616c616e6365737374727563742047656e65736973436f6e6669672077697468203120656c656d656e7400a427110023000000e00100000400000004000000e20100007672662d6e6d2d706b6d697373696e67206669656c64206060000000e92711000f000000f827110001000000756e6b6e6f776e206669656c642060602c20746865726520617265206e6f206669656c64730000000c2811000f0000001b28110016000000602c206578706563746564200c2811000f000000442811000c000000696e76616c6964206c656e677468202c206578706563746564200000602811000f0000006f2811000b0000006475706c6963617465206669656c6420600000008c28110011000000f827110001000000756e6b6e6f776e2076617269616e742060602c20746865726520617265206e6f2076617269616e7473000000b028110011000000c128110018000000b028110011000000442811000c000000556e646572666c6f774f766572666c6f774469766973696f6e42795a65726f696e7465726e616c206572726f723a20656e746572656420756e726561636861626c6520636f64653a20747269652073747265616d20636f646563206f6e6c7920666f72206e6f20657874656e73696f6e20747269650000001b291100560000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f7072696d6974697665732f747269652f7372632f747269655f73747265616d2e727300007c29110066000000760000000d0000007c2911006600000047000000400000007c29110066000000470000004d000000de0100000000000001000000e3010000de0100000000000001000000e3010000de0100000000000001000000e3010000de0100000000000001000000e4010000de0100000000000001000000e5010000de0100000000000001000000e6010000de0100000000000001000000e7010000de0100000000000001000000e8010000de0100000000000001000000e9010000de0100000000000001000000ea010000de0100000000000001000000eb010000de0100000000000001000000ec0100002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f747269652d726f6f742d302e31382e302f7372632f6c69622e7273000000d42a11005d0000002901000034000000d42a11005d000000400100002d000000d42a11005d0000003b01000034000000d42a11005d000000790100001f000000d42a11005d0000006001000034000000d42a11005d000000620100002e000000d42a11005d000000a100000026000000d42a11005d000000a10000002c000000d42a11005d000000a1000000250000007374727563742052756e74696d6547656e65736973436f6e6669672077697468203420656c656d656e747300c42b11002b00000073797374656d62616265737562737472617465546573740009000000080000000e000000fc281100052911000d29110050617468206e6f742061737369676e65642f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f7363616c652d696e666f2d322e31312e332f7372632f6275696c642e7273000000392c110060000000b20000001e00000068656164657248656164657265787472696e736963735665633c45787472696e7369633e73746174655f726f6f74486173683a3a4f7574707574706172656e745f6861736865787472696e736963735f726f6f746e756d6265724e756d6265726469676573744469676573745265706f727420617574686f726974792065717569766f636174696f6e2f6d69736265686176696f722e2054686973206d6574686f642077696c6c207665726966797468652065717569766f636174696f6e2070726f6f6620616e642076616c69646174652074686520676976656e206b6579206f776e6572736869702070726f6f66616761696e73742074686520657874726163746564206f6666656e6465722e20496620626f7468206172652076616c69642c20746865206f6666656e63652077696c6c6265207265706f727465642e546869732065787472696e736963206d7573742062652063616c6c656420756e7369676e656420616e642069742069732065787065637465642074686174206f6e6c79626c6f636b20617574686f72732077696c6c2063616c6c206974202876616c69646174656420696e206056616c6964617465556e7369676e656460292c206173207375636869662074686520626c6f636b20617574686f7220697320646566696e65642069742077696c6c20626520646566696e6564206173207468652065717569766f636174696f6e7265706f727465722e182d1100420000005a2d1100410000009b2d110043000000de2d11000c000000ea2d1100430000002d2e110045000000722e110045000000b72e110009000000182d1100420000005a2d1100410000009b2d110043000000de2d11000c000000506c616e20616e2065706f636820636f6e666967206368616e67652e205468652065706f636820636f6e666967206368616e6765206973207265636f7264656420616e642077696c6c20626520656e6163746564206f6e746865206e6578742063616c6c20746f2060656e6163745f65706f63685f6368616e6765602e2054686520636f6e6669672077696c6c20626520616374697661746564206f6e652065706f63682061667465722e4d756c7469706c652063616c6c7320746f2074686973206d6574686f642077696c6c207265706c61636520616e79206578697374696e6720706c616e6e656420636f6e666967206368616e67652074686174206861646e6f74206265656e20656e6163746564207965742e0000202f110057000000772f110054000000cb2f11005600000021301100150000006b65795f6f776e65725f70726f6f66543a3a4b65794f776e657250726f6f6665717569766f636174696f6e5f70726f6f66426f783c45717569766f636174696f6e50726f6f663c486561646572466f723c543e3e3e636f6e6669674e657874436f6e66696744657363726970746f725375626d697474656420636f6e66696775726174696f6e20697320696e76616c69642e000000000000c730110023000000416e2065717569766f636174696f6e2070726f6f662070726f76696465642061732070617274206f6620616e2065717569766f636174696f6e207265706f727420697320696e76616c69642e00000000f83011004c0000004120676976656e2065717569766f636174696f6e207265706f72742069732076616c69642062757420616c72656164792070726576696f75736c79207265706f727465642e000000503111004500000041206b6579206f776e6572736869702070726f6f662070726f76696465642061732070617274206f6620616e2065717569766f636174696f6e207265706f727420697320696e76616c69642e00000000a03111004c000000543a3a4e6f6e63656e6f6e63654e6f6e636570726f766964657273526566436f756e74636f6e73756d657273646174614163636f756e744461746173756666696369656e74736576656e7445746f706963735665633c543e70686173655068617365636f64655f68617368543a3a48617368636865636b5f76657273696f6e626f6f6c4b696c6c20736f6d65206974656d732066726f6d2073746f726167652e7b3211001d00000053657420746865206e65772072756e74696d6520636f646520776974686f757420646f696e6720616e7920636865636b73206f662074686520676976656e2060636f6465602e4e6f746520746861742072756e74696d652075706772616465732077696c6c206e6f742072756e20696620746869732069732063616c6c656420776974682061206e6f742d696e6372656173696e67207370656376657273696f6e210000a032110046000000e632110000000000e6321100540000003a331100080000004d616b6520736f6d65206f6e2d636861696e2072656d61726b20616e6420656d6974206576656e742e000000643311002900000053657420746865206e65772072756e74696d6520636f64652e00000000000000983311001900000053657420746865206e756d626572206f6620706167657320696e2074686520576562417373656d626c7920656e7669726f6e6d656e74277320686561702e0000c03311003e0000004b696c6c20616c6c2073746f72616765206974656d7320776974682061206b657920746861742073746172747320776974682074686520676976656e207072656669782e2a2a4e4f54453a2a2a2057652072656c79206f6e2074686520526f6f74206f726967696e20746f2070726f7669646520757320746865206e756d626572206f66207375626b65797320756e64657274686520707265666978207765206172652072656d6f76696e6720746f2061636375726174656c792063616c63756c6174652074686520776569676874206f6620746869732066756e6374696f6e2e0000000834110044000000e6321100000000004c3411004e0000009a3411004f0000004d616b6520736f6d65206f6e2d636861696e2072656d61726b2e43616e20626520657865637574656420627920657665727920606f726967696e602e0c3511001a000000e632110000000000263511002200000053657420736f6d65206974656d73206f662073746f726167652e000000000000603511001a000000417574686f72697a6520616e207570677261646520746f206120676976656e2060636f64655f686173686020666f72207468652072756e74696d652e205468652072756e74696d652063616e20626520737570706c6965646c617465722e5741524e494e473a205468697320617574686f72697a657320616e207570677261646520746861742077696c6c2074616b6520706c61636520776974686f757420616e792073616665747920636865636b732c20666f726578616d706c652074686174207468652073706563206e616d652072656d61696e73207468652073616d6520616e642074686174207468652076657273696f6e206e756d62657220696e637265617365732e204e6f747265636f6d6d656e64656420666f72206e6f726d616c207573652e205573652060617574686f72697a655f757067726164656020696e73746561642e546869732063616c6c20726571756972657320526f6f74206f726967696e2e00008835110058000000e035110006000000e632110000000000e6351100570000003d36110056000000933611003c000000e632110000000000cf3611001f0000008835110058000000e035110006000000e632110000000000cf3611001f00000050726f766964652074686520707265696d616765202872756e74696d652062696e617279292060636f64656020666f7220616e2075706772616465207468617420686173206265656e20617574686f72697a65642e49662074686520617574686f72697a6174696f6e20726571756972656420612076657273696f6e20636865636b2c20746869732063616c6c2077696c6c20656e73757265207468652073706563206e616d6572656d61696e7320756e6368616e67656420616e6420746861742074686520737065632076657273696f6e2068617320696e637265617365642e446570656e64696e67206f6e207468652072756e74696d65277320604f6e536574436f64656020636f6e66696775726174696f6e2c20746869732066756e6374696f6e206d6179206469726563746c79206170706c79746865206e65772060636f64656020696e207468652073616d6520626c6f636b206f7220617474656d707420746f207363686564756c652074686520757067726164652e416c6c206f726967696e732061726520616c6c6f7765642e005037110055000000e632110000000000a537110052000000f73711003a000000e63211000000000031381100560000008738110044000000e632110000000000cb38110018000000636f64655665633c75383e70616765737536347072656669784b65796974656d735665633c4b657956616c75653e7375626b65797375333272656d61726b6b6579735665633c4b65793e546865206e616d65206f662073706563696669636174696f6e20646f6573206e6f74206d61746368206265747765656e207468652063757272656e742072756e74696d65616e6420746865206e65772072756e74696d652e00007639110044000000ba391100140000005468652073706563696669636174696f6e2076657273696f6e206973206e6f7420616c6c6f77656420746f206465637265617365206265747765656e207468652063757272656e742072756e74696d65e039110050000000ba39110014000000537569636964652063616c6c6564207768656e20746865206163636f756e7420686173206e6f6e2d64656661756c7420636f6d706f7369746520646174612e00403a11003f0000004e6f207570677261646520617574686f72697a65642e0000883a1100160000004661696c656420746f2065787472616374207468652072756e74696d652076657273696f6e2066726f6d20746865206e65772072756e74696d652e4569746865722063616c6c696e672060436f72655f76657273696f6e60206f72206465636f64696e67206052756e74696d6556657273696f6e60206661696c65642e000000a83a11003b000000e632110000000000e33a110042000000546865206f726967696e2066696c7465722070726576656e74207468652063616c6c20746f20626520646973706174636865642e00000000403b11003400000041206d756c74692d626c6f636b206d6967726174696f6e206973206f6e676f696e6720616e642070726576656e7473207468652063757272656e7420636f64652066726f6d206265696e67207265706c616365642e000000803b11005500000054686572652069732061206e6f6e2d7a65726f207265666572656e636520636f756e742070726576656e74696e6720746865206163636f756e742066726f6d206265696e67207075726765642e000000e03b11004d000000546865207375626d697474656420636f6465206973206e6f7420617574686f72697a65642e000000383c110025000000416e2065787472696e736963206661696c65642e00000000683c110014000000603a636f6465602077617320757064617465642e00000000883c11001400000041206e6577206163636f756e742077617320637265617465642e000000000000a83c11001a000000416e20757067726164652077617320617574686f72697a65642e000000000000d03c11001a000000416e206163636f756e7420776173207265617065642e0000f83c110016000000416e2065787472696e73696320636f6d706c65746564207375636365737366756c6c792e00000000183d1100240000004f6e206f6e2d636861696e2072656d61726b2068617070656e65642e00000000483d11001c0000006163636f756e74543a3a4163636f756e7449646861736864697370617463685f696e666f4469737061746368496e666f73656e64657264697370617463685f6572726f7244697370617463684572726f72616d6f756e7442616c616e6365696449646d616e6461746f7279546f7065726174696f6e616c6e6f726d616c4163636f756e744964666c6167734578747261466c61677366726f7a656e7265736572766564667265654c6f636b4964656e746966696572726561736f6e73526561736f6e73526573657276654964656e746966696572556e7265736572766520736f6d652062616c616e63652066726f6d2061207573657220627920666f7263652e43616e206f6e6c792062652063616c6c656420627920524f4f542e00443e11002c000000e632110000000000703e11001b0000005472616e736665722074686520656e74697265207472616e7366657261626c652062616c616e63652066726f6d207468652063616c6c6572206163636f756e742e4e4f54453a20546869732066756e6374696f6e206f6e6c7920617474656d70747320746f207472616e73666572205f7472616e7366657261626c655f2062616c616e6365732e2054686973206d65616e732074686174616e79206c6f636b65642c2072657365727665642c206f72206578697374656e7469616c206465706f7369747320287768656e20606b6565705f616c6976656020697320607472756560292c2077696c6c206e6f742062657472616e7366657272656420627920746869732066756e6374696f6e2e20546f20656e73757265207468617420746869732066756e6374696f6e20726573756c747320696e2061206b696c6c6564206163636f756e742c796f75206d69676874206e65656420746f207072657061726520746865206163636f756e742062792072656d6f76696e6720616e79207265666572656e636520636f756e746572732c2073746f726167656465706f736974732c206574632e2e2e546865206469737061746368206f726967696e206f6620746869732063616c6c206d757374206265205369676e65642e2d206064657374603a2054686520726563697069656e74206f6620746865207472616e736665722e2d20606b6565705f616c697665603a204120626f6f6c65616e20746f2064657465726d696e652069662074686520607472616e736665725f616c6c60206f7065726174696f6e2073686f756c642073656e6420616c6c20206f66207468652066756e647320746865206163636f756e74206861732c2063617573696e67207468652073656e646572206163636f756e7420746f206265206b696c6c6564202866616c7365292c206f7220207472616e736665722065766572797468696e6720657863657074206174206c6561737420746865206578697374656e7469616c206465706f7369742c2077686963682077696c6c2067756172616e74656520746f20206b656570207468652073656e646572206163636f756e7420616c697665202874727565292e000000a43e110041000000e632110000000000e53e1100560000003b3f110058000000933f110057000000ea3f1100510000003b40110010000000e6321100000000004b40110030000000e6321100000000007b40110028000000a340110056000000f9401100530000004c41110056000000a2411100270000004275726e2074686520737065636966696564206c697175696420667265652062616c616e63652066726f6d20746865206f726967696e206163636f756e742e496620746865206f726967696e2773206163636f756e7420656e64732075702062656c6f7720746865206578697374656e7469616c206465706f736974206173206120726573756c746f6620746865206275726e20616e6420606b6565705f616c697665602069732066616c73652c20746865206163636f756e742077696c6c206265207265617065642e556e6c696b652073656e64696e672066756e647320746f2061205f6275726e5f20616464726573732c207768696368206d6572656c79206d616b6573207468652066756e647320696e61636365737369626c652c7468697320606275726e60206f7065726174696f6e2077696c6c2072656475636520746f74616c2069737375616e63652062792074686520616d6f756e74205f6275726e65645f2e0000444211003f000000e6321100000000008342110049000000cc42110042000000e6321100000000000e43110054000000624311004800000053616d6520617320746865205b607472616e736665725f616c6c6f775f6465617468605d2063616c6c2c206275742077697468206120636865636b207468617420746865207472616e736665722077696c6c206e6f746b696c6c20746865206f726967696e206163636f756e742e393925206f66207468652074696d6520796f752077616e74205b607472616e736665725f616c6c6f775f6465617468605d20696e73746561642e5b607472616e736665725f616c6c6f775f6465617468605d3a207374727563742e50616c6c65742e68746d6c236d6574686f642e7472616e73666572e4431100560000003a44110018000000e632110000000000524411003a000000e6321100000000008c4411003c00000041646a7573742074686520746f74616c2069737375616e636520696e20612073617475726174696e67207761792e43616e206f6e6c792062652063616c6c656420627920726f6f7420616e6420616c77617973206e65656473206120706f736974697665206064656c7461602e23204578616d706c650000f84411002e000000e632110000000000264511003f000000e632110000000000654511000900000055706772616465206120737065636966696564206163636f756e742e2d20606f726967696e603a204d75737420626520605369676e6564602e2d206077686f603a20546865206163636f756e7420746f2062652075706772616465642e546869732077696c6c20776169766520746865207472616e73616374696f6e20666565206966206174206c6561737420616c6c2062757420313025206f6620746865206163636f756e7473206e656564656420746f62652075706772616465642e20285765206c657420736f6d65206e6f74206861766520746f206265207570677261646564206a75737420696e206f7264657220746f20616c6c6f7720666f7220746865706f73736962696c697479206f6620636875726e292e984511001c000000e632110000000000b44511001d000000d145110024000000e632110000000000f5451100550000004a461100500000009a4611001600000045786163746c7920617320607472616e736665725f616c6c6f775f6465617468602c2065786365707420746865206f726967696e206d75737420626520726f6f7420616e642074686520736f75726365206163636f756e746d6179206265207370656369666965642e000000f04611005800000048471100110000005365742074686520726567756c61722062616c616e6365206f66206120676976656e206163636f756e742e546865206469737061746368206f726967696e20666f7220746869732063616c6c2069732060726f6f74602e006c4711002b000000e632110000000000974711002c0000005472616e7366657220736f6d65206c697175696420667265652062616c616e636520746f20616e6f74686572206163636f756e742e607472616e736665725f616c6c6f775f6465617468602077696c6c207365742074686520604672656542616c616e636560206f66207468652073656e64657220616e642072656365697665722e4966207468652073656e6465722773206163636f756e742069732062656c6f7720746865206578697374656e7469616c206465706f736974206173206120726573756c746f6620746865207472616e736665722c20746865206163636f756e742077696c6c206265207265617065642e546865206469737061746368206f726967696e20666f7220746869732063616c6c206d75737420626520605369676e65646020627920746865207472616e736163746f722e00dc47110035000000e632110000000000114811004d0000005e48110044000000a24811002c000000e632110000000000ce4811004500000076616c7565543a3a42616c616e6365646573744163636f756e7449644c6f6f6b75704f663c543e77686f6b6565705f616c697665646972656374696f6e41646a7573746d656e74446972656374696f6e5665633c543a3a4163636f756e7449643e736f7572636564656c74616e65775f6672656556657374696e672062616c616e636520746f6f206869676820746f2073656e642076616c75652e00c0491100270000004e756d626572206f6620667265657a65732065786365656420604d6178467265657a6573602e0000f0491100260000005472616e736665722f7061796d656e7420776f756c64206b696c6c206163636f756e742e00000000204a11002400000042656e6566696369617279206163636f756e74206d757374207072652d65786973742e0000000000504a1100230000004e756d626572206f6620686f6c647320657863656564206056617269616e74436f756e744f663c543a3a52756e74696d65486f6c64526561736f6e3e602e0000804a11003e00000056616c756520746f6f206c6f7720746f20637265617465206163636f756e742064756520746f206578697374656e7469616c206465706f7369742e0000000000c84a11003b0000004e756d626572206f66206e616d65642072657365727665732065786365656420604d61785265736572766573602e0000104b11002e00000042616c616e636520746f6f206c6f7720746f2073656e642076616c75652e0000484b11001e0000005468652064656c74612063616e6e6f74206265207a65726f2e00000000000000704b1100190000004163636f756e74206c6971756964697479207265737472696374696f6e732070726576656e74207769746864726177616c2e000000000000984b110032000000412076657374696e67207363686564756c6520616c72656164792065786973747320666f722074686973206163636f756e742e0000000000d84b1100330000005468652069737375616e63652063616e6e6f74206265206d6f6469666965642073696e636520697420697320616c72656164792064656163746976617465642e184c110040000000412062616c616e6365207761732073657420627920726f6f742e000000000000604c11001a000000536f6d6520616d6f756e742077617320726573746f72656420696e746f20616e206163636f756e742e00000000000000884c110029000000416e206163636f756e74207761732063726561746564207769746820736f6d6520667265652062616c616e63652e0000c04c11002e000000536f6d652062616c616e636520776173207468617765642ef84c110018000000416e206163636f756e74207761732075706772616465642e184d110018000000536f6d6520616d6f756e7420776173206465706f73697465642028652e672e20666f72207472616e73616374696f6e2066656573292e0000384d110036000000546f74616c2069737375616e636520776173206465637265617365642062792060616d6f756e74602c206372656174696e672061206465627420746f2062652062616c616e6365642e00000000000000784d110049000000536f6d652062616c616e636520776173206d6f7665642066726f6d207468652072657365727665206f6620746865206669727374206163636f756e7420746f20746865207365636f6e64206163636f756e742e46696e616c20617267756d656e7420696e64696361746573207468652064657374696e6174696f6e2062616c616e636520747970652e000000d04d110053000000234e110036000000536f6d652062616c616e636520776173206c6f636b65642e000000006c4e110018000000536f6d652062616c616e63652077617320726573657276656420286d6f7665642066726f6d206672656520746f207265736572766564292e904e110038000000536f6d6520616d6f756e74207761732072656d6f7665642066726f6d20746865206163636f756e742028652e672e20666f72206d69736265686176696f72292ed04e110040000000536f6d6520616d6f756e7420776173206d696e74656420696e746f20616e206163636f756e742e00184f110027000000546f74616c2069737375616e63652077617320696e637265617365642062792060616d6f756e74602c206372656174696e6720612063726564697420746f2062652062616c616e6365642e0000000000484f11004b0000005468652060546f74616c49737375616e6365602077617320666f72636566756c6c79206368616e6765642e0000000000a04f11002b0000005472616e73666572207375636365656465642e0000000000d84f110013000000536f6d652062616c616e63652077617320756e6c6f636b65642e000000000000f84f11001a000000416e206163636f756e74207761732072656d6f7665642077686f73652062616c616e636520776173206e6f6e2d7a65726f206275742062656c6f77204578697374656e7469616c4465706f7369742c726573756c74696e6720696e20616e206f75747269676874206c6f73732e000000205011004f0000006f5011001e000000536f6d6520616d6f756e74207761732077697468647261776e2066726f6d20746865206163636f756e742028652e672e20666f72207472616e73616374696f6e2066656573292e00a050110047000000536f6d652062616c616e6365207761732066726f7a656e2ef050110018000000536f6d652062616c616e63652077617320756e726573657276656420286d6f7665642066726f6d20726573657276656420746f2066726565292e000000000000105111003a000000536f6d6520616d6f756e74207761732073757370656e6465642066726f6d20616e206163636f756e74202869742063616e20626520726573746f726564206c61746572292e0000005851110045000000536f6d6520616d6f756e7420776173206275726e65642066726f6d20616e206163636f756e742e00a851110027000000746f66726f6d667265655f62616c616e636564657374696e6174696f6e5f7374617475735374617475736e65776f6c647461726765745f6e756d6265724e7461726765745f6861736848666972737428562c2053297365636f6e646964656e74697479726f756e645f6e756d6265726f6666656e64657266697273745f686561646572736c6f74536c6f747365636f6e645f6865616465727365745f6964536574496465717569766f636174696f6e45717569766f636174696f6e3c482c204e3e66696e616c6974795f6772616e6470613a3a45717569766f636174696f6e3c417574686f7269747949642c2066696e616c6974795f6772616e6470613a3a507265636f6d6d69740a3c482c204e3e2c20417574686f726974795369676e61747572652c3e66696e616c6974795f6772616e6470613a3a45717569766f636174696f6e3c417574686f7269747949642c2066696e616c6974795f6772616e6470613a3a507265766f74653c0a482c204e3e2c20417574686f726974795369676e61747572652c3e6d6f64654d6f64654c65676163792063616c6c207573656420696e207472616e73616374696f6e20706f6f6c2062656e63686d61726b732e0067531100300000007472616e736665725472616e7366657244617461496d706c696369746c792066696c6c206120626c6f636b20626f6479207769746820736f6d6520646174612eb45311002c0000005075742f64656c65746520736f6d6520646174612066726f6d2073746f726167652e20496e74656e64656420746f2075736520617320616e20756e7369676e65642065787472696e7369632e00000000e85311004c0000006b65794f7074696f6e3c5665633c75383e3e57726974652061206b65792076616c7565207061697220746f20746865206f6666636861696e2064617461626173652e000000000000525411003000000052656d6f76652061206b657920616e6420616e206173736f6369617465642076616c75652066726f6d20746865206f6666636861696e2064617461626173652e905411004000000043726561746520616e20696e64657820666f7220746869732063616c6c2e0000d85411001e0000004465706f73697420676976656e20646967657374206974656d7320696e746f207468652073797374656d2073746f726167652e20546865792077696c6c20626520696e636c7564656420696e206120686561646572647572696e672066696e616c697a6174696f6e2e000000005511005500000055551100140000006c6f6773705f72756e74696d653a3a67656e657269633a3a4469676573744974656d546869732063616c6c2069732076616c696461746564206173206056616c69645472616e73616374696f6e60207769746820676976656e207072696f726974792e009e551100410000007072696f726974795472616e73616374696f6e5072696f72697479546869732063616c6c2069732076616c696461746564206173206e6f6e2d70726f70616761626c65206056616c69645472616e73616374696f6e602e00035611003c00000046696c6c2074686520626c6f636b2077656967687420757020746f2074686520676976656e20726174696f2e00000000485611002c000000726174696f50657262696c6c5265616420582074696d65732066726f6d2074686520737461746520736f6d6520646174612e50616e6963732069662069742063616e206e6f742072656164206058602074696d65732e00008c56110026000000e632110000000000b256110024000000636f756e745265616420582074696d65732066726f6d2074686520737461746520736f6d65206461746120616e64207468656e2070616e69632152657475726e7320604f6b60206966206974206469646e2774207265616420616e797468696e672e0000f556110035000000e6321100000000002a5711002800000073656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c53797374656d2c2052756e74696d653e73656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c426162652c2052756e74696d653e73656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c537562737472617465546573742c2052756e74696d653e73656c663a3a73705f6170695f68696464656e5f696e636c756465735f636f6e7374727563745f72756e74696d653a3a68696464656e5f696e636c7564653a3a64697370617463680a3a3a43616c6c61626c6543616c6c466f723c42616c616e6365732c2052756e74696d653e6672616d655f73797374656d3a3a4572726f723c52756e74696d653e70616c6c65745f626162653a3a4572726f723c52756e74696d653e70616c6c65745f62616c616e6365733a3a4572726f723c52756e74696d653e6672616d655f73797374656d3a3a4576656e743c52756e74696d653e70616c6c65745f62616c616e6365733a3a4576656e743c52756e74696d653e496e646578206f7574206f6620626f756e647300b0591100130000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f736f72742e727300cc591100730000003b0400000e000000cc59110073000000480400001c000000cc59110073000000490400001d000000cc591100730000004a04000025000000cc591100730000008e04000040000000cc59110073000000b40400004e000000cc59110073000000c204000056000000617373657274696f6e206661696c65643a20656e64203e3d20737461727420262620656e64203c3d206c656ecc591100730000002d05000005000000cc591100730000003e05000029000000617373657274696f6e206661696c65643a206f666673657420213d2030202626206f6666736574203c3d206c656e0000cc591100730000009b00000005000000746573747061726974792d7465737400df6acb689907609b0500000037e397fc7c91f5e402000000d2bc9897eed08f150300000040fe3ad401f8959a06000000bc9d89904f5b923f01000000c6e9a76309f39b0902000000dd718d5cc53262d401000000cbca25e39f14238702000000f78b278be53f454c02000000ab3c0572291feb8b01000000ed99c5acb25eedf503000000fbc577b9d747efd601000000000000803c5b11000400000000000080405b11000b000000000000804c5b11000c000000010000000200000002000000010000000100000042616420696e70757420646174612070726f766964656420746f2076657273696f6e3a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792e0000145c11005a0000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f746573742d7574696c732f72756e74696d652f7372632f6c69622e7273000000785c110061000000d10100000100000042616420696e70757420646174612070726f766964656420746f20657865637574655f626c6f636b3a200000ec5c11002a00000042616420696e70757420646174612070726f766964656420746f20696e697469616c697a655f626c6f636b3a20000000205d11002d00000042616420696e70757420646174612070726f766964656420746f206d657461646174613a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792e00585d11005b00000042616420696e70757420646174612070726f766964656420746f206d657461646174615f61745f76657273696f6e3a20bc5d11003000000042616420696e70757420646174612070726f766964656420746f206d657461646174615f76657273696f6e733a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792ef45d11006400000042616420696e70757420646174612070726f766964656420746f2076616c69646174655f7472616e73616374696f6e3a20000000605e11003100000042616420696e70757420646174612070726f766964656420746f206170706c795f65787472696e7369633a209c5e11002c00000042616420696e70757420646174612070726f766964656420746f2066696e616c697a655f626c6f636b3a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792e000000d05e11006100000042616420696e70757420646174612070726f766964656420746f20696e686572656e745f65787472696e736963733a203c5f11003000000042616420696e70757420646174612070726f766964656420746f20636865636b5f696e686572656e74733a20745f11002c00000042616420696e70757420646174612070726f766964656420746f206163636f756e745f6e6f6e63653a200000a85f11002a00000042616420696e70757420646174612070726f766964656420746f2062616c616e63655f6f663a2000dc5f11002700000042616420696e70757420646174612070726f766964656420746f2062656e63686d61726b5f6164645f6f6e653a2000000c6011002e00000042616420696e70757420646174612070726f766964656420746f2062656e63686d61726b5f766563746f725f6164645f6f6e653a20000000446011003500000042616420696e70757420646174612070726f766964656420746f2066756e6374696f6e5f7369676e61747572655f6368616e6765643a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792e000000846011006d00000042616420696e70757420646174612070726f766964656420746f207573655f747269653a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792e00fc6011005b00000042616420696e70757420646174612070726f766964656420746f2062656e63686d61726b5f696e6469726563745f63616c6c3a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792e0000606111006a00000042616420696e70757420646174612070726f766964656420746f2062656e63686d61726b5f6469726563745f63616c6c3a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792ed46111006800000042616420696e70757420646174612070726f766964656420746f207665635f776974685f63617061636974793a200000446211002e00000042616420696e70757420646174612070726f766964656420746f206765745f626c6f636b5f6e756d6265723a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792e007c6211006300000042616420696e70757420646174612070726f766964656420746f20746573745f656432353531395f63727970746f3a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792e0000e86211006600000042616420696e70757420646174612070726f766964656420746f20746573745f737232353531395f63727970746f3a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792e0000586311006600000042616420696e70757420646174612070726f766964656420746f20746573745f65636473615f63727970746f3a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792ec86311006400000042616420696e70757420646174612070726f766964656420746f20746573745f73746f726167653a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792e00346411005f00000042616420696e70757420646174612070726f766964656420746f20746573745f7769746e6573733a200000009c6411002900000042616420696e70757420646174612070726f766964656420746f20746573745f6d756c7469706c655f617267756d656e74733a20d06411003400000042616420696e70757420646174612070726f766964656420746f20646f5f74726163655f6c6f673a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792e000c6511005f00000042616420696e70757420646174612070726f766964656420746f207665726966795f656432353531393a2000746511002b00000042616420696e70757420646174612070726f766964656420746f2077726974655f6b65795f76616c75653a20a86511002c00000042616420696e70757420646174612070726f766964656420746f20736c6f745f6475726174696f6e3a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792edc6511006000000042616420696e70757420646174612070726f766964656420746f20617574686f7269746965733a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792e0000446611005e00000042616420696e70757420646174612070726f766964656420746f20636f6e66696775726174696f6e3a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792eac6611006000000042616420696e70757420646174612070726f766964656420746f2063757272656e745f65706f63685f73746172743a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792e0000146711006600000042616420696e70757420646174612070726f766964656420746f2063757272656e745f65706f63683a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792e846711006000000042616420696e70757420646174612070726f766964656420746f206e6578745f65706f63683a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792e000000ec6711005d00000042616420696e70757420646174612070726f766964656420746f207375626d69745f7265706f72745f65717569766f636174696f6e5f756e7369676e65645f65787472696e7369633a200000546811004a00000042616420696e70757420646174612070726f766964656420746f2067656e65726174655f6b65795f6f776e6572736869705f70726f6f663a20000000a86811003900000042616420696e70757420646174612070726f766964656420746f206f6666636861696e5f776f726b65723a20ec6811002c00000042616420696e70757420646174612070726f766964656420746f2067656e65726174655f73657373696f6e5f6b6579733a200000206911003200000042616420696e70757420646174612070726f766964656420746f206465636f64655f73657373696f6e5f6b6579733a205c6911003000000042616420696e70757420646174612070726f766964656420746f206772616e6470615f617574686f7269746965733a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792e0000946911006600000042616420696e70757420646174612070726f766964656420746f2063757272656e745f7365745f69643a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792e000000046a11006100000042616420696e70757420646174612070726f766964656420746f206275696c645f73746174653a20706a11002800000042616420696e70757420646174612070726f766964656420746f206765745f7072657365743a2000a06a11002700000042616420696e70757420646174612070726f766964656420746f207072657365745f6e616d65733a206578706563746564206e6f20706172616d65746572732c2062757420696e70757420627566666572206973206e6f7420656d7074792e00d06a11005f0000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f6672616d652f62616c616e6365732f7372632f6c69622e72737472616e736665725f616c6c6f775f6465617468666f7263655f7472616e736665727472616e736665725f6b6565705f616c6976657472616e736665725f616c6c666f7263655f756e72657365727665757067726164655f6163636f756e7473666f7263655f7365745f62616c616e6365666f7263655f61646a7573745f746f74616c5f69737375616e63656275726e4f7074696f6e544e6f6e65536f6d65e29c85206e6f206d6967726174696f6e20666f7220000000346c11001500000072756e74696d653a3a6672616d652d737570706f727470616c6c65745f62616c616e6365733a3a70616c6c65746475706c69636174652062616c616e63657320696e2067656e657369732e00816c11001e000000386b11005d000000110200000d0000007468652062616c616e6365206f6620616e79206163636f756e742073686f756c6420616c77617973206265206174206c6561737420746865206578697374656e7469616c206465706f7369742e000000b86c11004d000000386b11005d0000000302000011000000f09f90a5204e65772070616c6c65742020646574656374656420696e207468652072756e74696d652e20496e697469616c697a696e6720746865206f6e2d636861696e2073746f726167652076657273696f6e20746f206d61746368207468652073746f726167652076657273696f6e20646566696e656420696e207468652070616c6c65743a20206d110010000000306d1100780000000100006163636f756e7420776974682061206e6f6e2d7a65726f20726573657276652062616c616e636520686173206e6f2070726f766964657220726566732c206163636f756e745f69643a2027272ebb6d11004b000000066e11000200000072756e74696d653a3a62616c616e6365732054686520746f74616c20756e6974732069737375656420696e207468652073797374656d2e2054686520746f74616c20756e697473206f66206f75747374616e64696e672064656163746976617465642062616c616e636520696e207468652073797374656d2e205468652042616c616e6365732070616c6c6574206578616d706c65206f662073746f72696e67207468652062616c616e6365206f6620616e206163636f756e742e2023204578616d706c65206060606e6f636f6d70696c652020696d706c2070616c6c65745f62616c616e6365733a3a436f6e66696720666f722052756e74696d65207b2020202074797065204163636f756e7453746f7265203d2053746f726167654d61705368696d3c53656c663a3a4163636f756e743c52756e74696d653e2c206672616d655f73797374656d3a3a50726f76696465723c52756e74696d653e2c204163636f756e7449642c2053656c663a3a4163636f756e74446174613c42616c616e63653e3e20207d2060606020596f752063616e20616c736f2073746f7265207468652062616c616e6365206f6620616e206163636f756e7420696e20746865206053797374656d602070616c6c65742e20202074797065204163636f756e7453746f7265203d2053797374656d20427574207468697320636f6d657320776974682074726164656f6666732c2073746f72696e67206163636f756e742062616c616e63657320696e207468652073797374656d2070616c6c65742073746f72657320606672616d655f73797374656d60206461746120616c6f6e677369646520746865206163636f756e74206461746120636f6e747261727920746f2073746f72696e67206163636f756e742062616c616e63657320696e20746865206042616c616e636573602070616c6c65742c20776869636820757365732061206053746f726167654d61706020746f2073746f72652062616c616e6365732064617461206f6e6c792e204e4f54453a2054686973206973206f6e6c79207573656420696e207468652063617365207468617420746869732070616c6c6574206973207573656420746f2073746f72652062616c616e6365732e20416e79206c6971756964697479206c6f636b73206f6e20736f6d65206163636f756e742062616c616e6365732e204e4f54453a2053686f756c64206f6e6c79206265206163636573736564207768656e2073657474696e672c206368616e67696e6720616e642066726565696e672061206c6f636b2e20557365206f66206c6f636b73206973206465707265636174656420696e206661766f7572206f6620667265657a65732e20536565206068747470733a2f2f6769746875622e636f6d2f706172697479746563682f7375627374726174652f70756c6c2f31323935312f60204e616d6564207265736572766573206f6e20736f6d65206163636f756e742062616c616e6365732e20557365206f66207265736572766573206973206465707265636174656420696e206661766f7572206f6620686f6c64732e20536565206068747470733a2f2f6769746875622e636f6d2f706172697479746563682f7375627374726174652f70756c6c2f31323935312f6020486f6c6473206f6e206163636f756e742062616c616e6365732e20467265657a65206c6f636b73206f6e206163636f756e742062616c616e6365732e20546865206d696e696d756d20616d6f756e7420726571756972656420746f206b65657020616e206163636f756e74206f70656e2e204d5553542042452047524541544552205448414e205a45524f2120496620796f75202a7265616c6c792a206e65656420697420746f206265207a65726f2c20796f752063616e20656e61626c652074686520666561747572652060696e7365637572655f7a65726f5f65646020666f7220746869732070616c6c65742e20486f77657665722c20796f7520646f20736f20617420796f7572206f776e207269736b3a20746869732077696c6c206f70656e2075702061206d616a6f7220446f5320766563746f722e20496e206361736520796f752068617665206d756c7469706c6520736f7572636573206f662070726f7669646572207265666572656e6365732c20796f75206d617920616c736f2067657420756e6578706563746564206265686176696f757220696620796f7520736574207468697320746f207a65726f2e20426f74746f6d206c696e653a20446f20796f757273656c662061206661766f757220616e64206d616b65206974206174206c65617374206f6e65214578697374656e7469616c4465706f73697420546865206d6178696d756d206e756d626572206f66206c6f636b7320746861742073686f756c64206578697374206f6e20616e206163636f756e742e204e6f74207374726963746c7920656e666f726365642c20627574207573656420666f722077656967687420657374696d6174696f6e2e4d61784c6f636b7320546865206d6178696d756d206e756d626572206f66206e616d656420726573657276657320746861742063616e206578697374206f6e20616e206163636f756e742e4d6178526573657276657320546865206d6178696d756d206e756d626572206f6620696e646976696475616c20667265657a65206c6f636b7320746861742063616e206578697374206f6e20616e206163636f756e7420617420616e792074696d652e4d6178467265657a657362616c616e63657300f37511000800000043616c6c49436f6e7461696e7320612076617269616e742070657220646973706174636861626c652065787472696e736963207468617420746869732070616c6c6574206861732e0000000009761100430000004572726f7254686520604572726f726020656e756d206f6620746869732070616c6c65742e0000005d7611002000000056657374696e6742616c616e63654c69717569646974795265737472696374696f6e73496e73756666696369656e7442616c616e6365457870656e646162696c6974794578697374696e6756657374696e675363686564756c65446561644163636f756e74546f6f4d616e795265736572766573546f6f4d616e79486f6c6473546f6f4d616e79467265657a657349737375616e6365446561637469766174656444656c74615a65726f4576656e7454686520604576656e746020656e756d206f6620746869732070616c6c65740000377711001f000000456e646f776564447573744c6f73745472616e7366657242616c616e63655365745265736572766564556e72657365727665645265736572766552657061747269617465644465706f7369745769746864726177536c61736865644d696e7465644275726e656453757370656e646564526573746f726564557067726164656449737375656452657363696e6465644c6f636b6564556e6c6f636b656446726f7a656e546861776564546f74616c49737375616e6365466f726365647374727563742047656e65736973436f6e666967ff0100000400000004000000e2010000ff01000004000000040000002e010000ff01000004000000040000005a0100002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f7072696d6974697665732f747269652f7372632f6e6f64655f636f6465632e72732f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f747269652d64622d302e32392e302f7372632f6c6f6f6b75702e727300c57811005e000000460000001e000000ff0100000c0000000400000000020000010200005765206172652063616368696e67206120604e6f64654f776e65643a3a56616c75656020666f7220612076616c7565206e6f6465206861736820616e64207468697320636163686564206e6f64652068617320616c7761797320646174612061747461636865643b20716564c57811005e00000079000000160000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f747269652d64622d302e32392e302f7372632f6e6962626c652f6d6f642e72730000c479110062000000490000001c000000ff01000014000000040000000202000003020000696e7465726e616c206572726f723a20656e746572656420756e726561636861626c6520636f64653a2000004c7a11002a000000604e6f64654f776e65643a3a56616c7565602063616e206e6f742062652072656163686564206279207573696e67207468652068617368206f662061206e6f64652e20604e6f64654f776e65643a3a56616c756560206973206f6e6c7920636f6e7374727563746564207768656e206c6f6164696e6720612076616c756520696e746f206d656d6f72792c207768696368206e6565647320746f2068617665206120646966666572656e742068617368207468616e20616e79206e6f64653b2071656400807a1100c3000000c57811005e000000d00200001900000053746f7261676556657273696f6e0000ff010000040000000400000012010000696e7465726e616c206572726f723a20656e746572656420756e726561636861626c6520636f64653a204e6f20657874656e73696f6e20636f6465632e0000007c7b11003d0000006078110065000000dd000000090000006078110065000000720000003400000060781100650000007b0000003200000060781100650000009e000000340000006078110065000000d60000000900000060781100650000000c0100000f00000060781100650000000501000029000000a86c1100000000006120646566656e73697665206661696c75726520686173206265656e207472696767657265643b20706c65617365207265706f72742074686520626c6f636b206e756d6265722061742068747470733a2f2f6769746875622e636f6d2f706172697479746563682f7375627374726174652f6973737565733c7c11007800000072756e74696d653a3a646566656e736976652f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f6672616d652f737570706f72742f7372632f7472616974732f6d6973632e72736672616d655f737570706f72743a3a7472616974733a3a6d69736376616c69646174655f72756e74696d655f63616c6c20004d7d1100160000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f746573742d7574696c732f72756e74696d652f7372632f7375627374726174655f746573745f70616c6c65742e72737375627374726174655f746573745f70616c6c65747375627374726174655f746573745f72756e74696d653a3a7375627374726174655f746573745f70616c6c65740000002900000029000000490000002900000029000000290000004a000000290000002900000029000000290000002900000029000000290000002100000009000000090000002900000029000000290000002900000011000000426c6f636b73705f72756e74696d653a3a67656e657269633a3a626c6f636b48656164657245787472696e73696373705f72756e74696d653a3a67656e657269633a3a6865616465724e756d626572486173682f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f636f6c6c656374696f6e732f62747265652f6e617669676174652e727300cf7e110084000000ae00000024000000556e636865636b656445787472696e736963282c20290000647f110013000000777f110002000000797f1100010000005065724469737061746368436c6173736672616d655f737570706f72743a3a6469737061746368544e6f6e65556e636865636b656445787472696e73696373705f72756e74696d653a3a67656e657269633a3a756e636865636b65645f65787472696e7369634164647265737343616c6c5369676e61747572654578747261004e756d626572206f6620646967657374206974656d73206d757374206d6174636820746861742063616c63756c617465642e000014801100320000002f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f6672616d652f6578656375746976652f7372632f6c69622e72730000508011005e000000360300000900000053746f7261676520726f6f74206d757374206d6174636820746861742063616c63756c617465642ec080110028000000508011005e00000044030000090000005472616e73616374696f6e207472696520726f6f74206d7573742062652076616c69642e0081110024000000508011005e0000004603000009000000446967657374206974656d206d757374206d6174636820746861742063616c63756c617465642e003c81110027000000508011005e0000003e0300000d0000003a206120646566656e73697665206661696c75726520686173206265656e207472696767657265643b20706c65617365207265706f72742074686520626c6f636b206e756d6265722061742068747470733a2f2f6769746875622e636f6d2f706172697479746563682f7375627374726174652f69737375657300007e8111007800000072756e74696d653a3a646566656e736976656672616d655f6578656375746976650000007c7e1100000000007c811100020000006e756d5f696e686572656e7473203d3d206e756d5f65787472696e7369637300348211001f000000506172656e7420686173682073686f756c642062652076616c69642e5c8211001c000000508011005e0000007102000009000000508011005e000000b7020000110000007c7e1100000000004163636f756e744461746170616c6c65745f62616c616e6365733a3a747970657342616c616e636542616c616e63654c6f636b5265736572766544617461526573657276654964656e7469666965722f686f6d652f6d69737a6b612f7061726974792f31302d67656e657369732d636f6e6669672f706f6c6b61646f742d73646b2d6d61737465722f7375627374726174652f7072696d6974697665732f73746174652d6d616368696e652f7372632f747269655f6261636b656e645f657373656e63652e727300f782110078000000a20100001b0000000902000000000000010000000a0200000b0200000c0200000d0200000902000000000000010000000e0200000f02000045717569766f636174696f6e50726f6f6673705f636f6e73656e7375735f736c6f74734964000000cf7e110084000000c700000027000000cf7e110084000000170200002f000000cf7e110084000000a200000024000000536f6d65100200000400000004000000110200003c7761736d3a73747269707065643e00140200000800000008000000150200001402000008000000080000001602000014020000080000000800000017020000180200000100000001000000190200001402000010000000080000001a0200001402000010000000080000001b0200008c841100000000001c02000008000000040000001d0200001e0200001f0200002002000021020000220200002302000024020000203d0000c084110001000000c1841100010000006d657373616765008c84110000000000c1841100010000001c0200000800000004000000250200001c020000180000000400000026020000417474656d7074656420746f2072656769737465722061206044656661756c7443616c6c7369746560207468617420616c7265616479206578697374732120546869732077696c6c20636175736520616e20696e66696e697465206c6f6f70207768656e20617474656d7074696e6720746f20726561642066726f6d207468652063616c6c736974652063616368652e2054686973206973206c696b656c792061206275672120596f752073686f756c64206f6e6c79206e65656420746f2063616c6c206044656661756c7443616c6c736974653a3a726567697374657260206f6e636520706572206044656661756c7443616c6c73697465602e000c851100fb0000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f74726163696e672d636f72652d302e312e33322f7372632f63616c6c736974652e72730000001086110065000000bd0100000d00000027020000180000000400000026020000280200000000000001000000290200002a0200002b0200002c0200002d0200002e0200002f02000030020000310200003102000031020000320200003302000034020000350200003602000037020000040000000400000038020000370200000400000004000000380200002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f74726163696e672d636f72652d302e312e33322f7372632f6669656c642e7273000004871100620000000403000009000000617373657274696f6e206661696c65643a20696e646578203c3d206c656e2f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f736d616c6c7665632d312e31332e322f7372632f6c69622e72730000968711005c000000ef060000090000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f747269652d64622d302e32392e302f7372632f6e6962626c652f6d6f642e727300000488110062000000490000001c0000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f747269652d64622d302e32392e302f7372632f6e6962626c652f6e6962626c65736c6963652e72730000788811006a0000003f0000001b000000788811006a0000005000000036000000788811006a000000560000003b000000788811006a0000008f0000002a000000788811006a000000900000002b000000788811006a000000990000004b000000788811006a0000009900000031000000788811006a000000af00000020000000788811006a000000ad00000029000000788811006a000000f400000018000000788811006a000000f600000018000000788811006a000000f60000003d0000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f747269652d64622d302e32392e302f7372632f6e6962626c652f6e6962626c657665632e7273a48911006800000035000000320000006c656e20213d20302073696e6365206c656e2025203220213d20303b20696e6e6572206861732061206c61737420656c656d656e743b207165640000a48911006800000042000000120000006c656e20213d20303b20696e6e657220686173206c61737420656c656d3b207165640000a4891100680000004d00000025000000a489110068000000690000003d000000a4891100680000007200000019000000a4891100680000007400000019000000a4891100680000007400000048000000a4891100680000008500000030000000a4891100680000008500000048000000a4891100680000008700000036000000a4891100680000009c00000043000000a4891100680000009e0000001b000000a4891100680000009f0000004000000063616c6c65642060526573756c743a3a756e77726170282960206f6e20616e2060457272602076616c7565003902000000000000010000003a0200002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f73796e632e72730000788b11006e000000b0070000290000004c61796f75744572726f722f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f747269652d64622d302e32392e302f7372632f7472696564626d75742e7273038c1100610000004a08000032000000038c1100610000004a080000100000002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f747269652d64622d302e32392e302f7372632f6e6962626c652f6d6f642e72730000848c110062000000880000001d000000848c1100620000007f00000022000000848c1100620000007e00000036000000848c1100620000007e00000047000000848c110062000000870000002f000000848c110062000000870000004400000041726320636f756e746572206f766572666c6f77488d1100140000002f686f6d652f6d69737a6b612f2e7275737475702f746f6f6c636861696e732f312e37372e302d7838365f36342d756e6b6e6f776e2d6c696e75782d676e752f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f73796e632e72730000648d11006e0000002e0600000d000000488d110000000000648d11006e000000dc0a00000d00000063616c6c65642060526573756c743a3a756e77726170282960206f6e20616e2060457272602076616c7565003c02000000000000010000003d020000648d11006e00000062070000290000004c61796f757473697a6500003e02000004000000040000003f020000616c69676e0000003e0200000400000004000000400200004c61796f75744572726f722f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f747269652d64622d302e32392e302f7372632f6e6f64652e727300878e11005c000000bc01000042000000878e11005c000000bd01000046000000878e11005c000000da01000026000000878e11005c000000ed0100003c000000878e11005c000000ee0100003800000043617061636974794f766572666c6f77416c6c6f634572726c61796f757400004102000004000000040000004202000063616c6c65642060526573756c743a3a756e77726170282960206f6e20616e2060457272602076616c756500410200000800000004000000430200002f686f6d652f6d69737a6b612f2e636172676f2f72656769737472792f7372632f696e6465782e6372617465732e696f2d366631376432326262613135303031662f736d616c6c7665632d312e31332e322f7372632f6c69622e7273a08f11005c000000520100002e0000006361706163697479206f766572666c6f77000000a08f11005c0000004101000036000000a08f11005c000000ce0400000e000000617373657274696f6e206661696c65643a206e65775f636170203e3d206c656ea08f11005c000000990400000d0000000041f0a0c6000b8c033300000000000000000000000000000000000000000000000000000054391000543910002a00000093000000000000009400000000000000950000000000000096000000000000009700000000000000980000000000000099000000000000009a000000000000009b000000000000009c000000000000009d000000000000009e000000000000009f00000000000000a000000000000000a100000000000000a200000000000000a300000000000000a400000000000000a500000000000000a600000000000000a700000000000000a800000000000000a900000000000000aa00000000000000ab00000000000000ac00000000000000ad00000000000000ae00000000000000af00000000000000b000000000000000b100000000000000b200000000000000b300000000000000b400000000000000b500000000000000b600000000000000b700000000000000b800000000000000b900000000000000ba00000000000000bb00000000000000f012110000000000ff00000000000000e486110098861100050000000041fca3c6000b1c0000000000000000000000000000000000000000000000000000000000330f72756e74696d655f76657273696f6e10746573742c7061726974792d74657374010000000200000002000000000100000001009d010c72756e74696d655f61706973df6acb689907609b0500000037e397fc7c91f5e402000000d2bc9897eed08f150300000040fe3ad401f8959a06000000bc9d89904f5b923f01000000c6e9a76309f39b0902000000dd718d5cc53262d401000000cbca25e39f14238702000000f78b278be53f454c02000000ab3c0572291feb8b01000000ed99c5acb25eedf503000000fbc577b9d747efd60100000000e2ca0c046e616d6501acca0c8b0e001c6578745f73746f726167655f617070656e645f76657273696f6e5f31011b6578745f73746f726167655f636c6561725f76657273696f6e5f3102226578745f73746f726167655f636c6561725f7072656669785f76657273696f6e5f3203286578745f73746f726167655f636f6d6d69745f7472616e73616374696f6e5f76657273696f6e5f3104196578745f73746f726167655f6765745f76657273696f6e5f31051e6578745f73746f726167655f6e6578745f6b65795f76657273696f6e5f31061a6578745f73746f726167655f726561645f76657273696f6e5f31072a6578745f73746f726167655f726f6c6c6261636b5f7472616e73616374696f6e5f76657273696f6e5f31081a6578745f73746f726167655f726f6f745f76657273696f6e5f3209196578745f73746f726167655f7365745f76657273696f6e5f310a276578745f73746f726167655f73746172745f7472616e73616374696f6e5f76657273696f6e5f310b206578745f68617368696e675f626c616b65325f3132385f76657273696f6e5f310c206578745f68617368696e675f626c616b65325f3235365f76657273696f6e5f310d1e6578745f68617368696e675f74776f785f3132385f76657273696f6e5f310e1d6578745f68617368696e675f74776f785f36345f76657273696f6e5f310f226578745f6f6666636861696e5f696e6465785f636c6561725f76657273696f6e5f3110206578745f6f6666636861696e5f696e6465785f7365745f76657273696f6e5f3111236578745f63727970746f5f65636473615f67656e65726174655f76657273696f6e5f3112266578745f63727970746f5f65636473615f7075626c69635f6b6579735f76657273696f6e5f31131f6578745f63727970746f5f65636473615f7369676e5f76657273696f6e5f3114216578745f63727970746f5f65636473615f7665726966795f76657273696f6e5f3215256578745f63727970746f5f656432353531395f67656e65726174655f76657273696f6e5f3116286578745f63727970746f5f656432353531395f7075626c69635f6b6579735f76657273696f6e5f3117216578745f63727970746f5f656432353531395f7369676e5f76657273696f6e5f3118236578745f63727970746f5f656432353531395f7665726966795f76657273696f6e5f3119256578745f63727970746f5f737232353531395f67656e65726174655f76657273696f6e5f311a286578745f63727970746f5f737232353531395f7075626c69635f6b6579735f76657273696f6e5f311b216578745f63727970746f5f737232353531395f7369676e5f76657273696f6e5f311c236578745f63727970746f5f737232353531395f7665726966795f76657273696f6e5f321d296578745f6f6666636861696e5f7375626d69745f7472616e73616374696f6e5f76657273696f6e5f311e256578745f7472616e73616374696f6e5f696e6465785f696e6465785f76657273696f6e5f311f196578745f6c6f6767696e675f6c6f675f76657273696f6e5f31201f6578745f6c6f6767696e675f6d61785f6c6576656c5f76657273696f6e5f31211c6578745f616c6c6f6361746f725f667265655f76657273696f6e5f31221e6578745f616c6c6f6361746f725f6d616c6c6f635f76657273696f6e5f3123286578745f64656661756c745f6368696c645f73746f726167655f726561645f76657273696f6e5f3124276578745f64656661756c745f6368696c645f73746f726167655f7365745f76657273696f6e5f31252a6578745f747269655f626c616b65325f3235365f6f7264657265645f726f6f745f76657273696f6e5f32261c6578745f6d6973635f7072696e745f6865785f76657273696f6e5f31271d6578745f6d6973635f7072696e745f757466385f76657273696f6e5f3128226578745f6d6973635f72756e74696d655f76657273696f6e5f76657273696f6e5f31291a5f5f727573745f616c6c6f635f6572726f725f68616e646c65722a305f5a4e34636f726533666d743557726974653977726974655f666d7431376861663163633133303635343162653038452b4c5f5a4e34636f726533707472343264726f705f696e5f706c616365244c5424616c6c6f632e2e737472696e672e2e537472696e672447542431376830336135366130626537376637613432452c5d5f5a4e35385f244c5424616c6c6f632e2e737472696e672e2e537472696e67247532302461732475323024636f72652e2e666d742e2e5772697465244754243977726974655f73747231376830306136663730663763613531633235452d5f5f5a4e35385f244c5424616c6c6f632e2e737472696e672e2e537472696e67247532302461732475323024636f72652e2e666d742e2e577269746524475424313077726974655f6368617231376836656230613834393730363936353764452e385f5a4e35616c6c6f63377261775f766563313763617061636974795f6f766572666c6f7731376833643832313234636131666431396363452f595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137686261373865343038643263393666336545304b5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376838393162626637303462336364333539452e6c6c766d2e31393739383737353732323834393835383834314c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f70757368313768626465353131306261356161353636634532375f5a4e35616c6c6f6335616c6c6f63313868616e646c655f616c6c6f635f6572726f72313768633962373561656666333933346231344533615f5a4e34636f726533707472333764726f705f696e5f706c616365244c5424636f72652e2e666d742e2e4572726f722447542431376866616235626136623938346139656434452e6c6c766d2e313039383239393330343532323938373935313534665f5a4e34636f726533707472343264726f705f696e5f706c616365244c5424616c6c6f632e2e737472696e672e2e537472696e672447542431376830336135366130626537376637613432452e6c6c766d2e3130393832393933303435323239383739353135356c5f5a4e35335f244c5424636f72652e2e666d742e2e4572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376863313334333061303064613965336232452e6c6c766d2e3130393832393933303435323239383739353135367c5f5a4e36395f244c5424636f72652e2e616c6c6f632e2e6c61796f75742e2e4c61796f75744572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376832393637613332326332613165663338452e6c6c766d2e313039383239393330343532323938373935313537095f5f72646c5f6f6f6d38365f5a4e35616c6c6f6333666d7436666f726d61743132666f726d61745f696e6e6572313768313738663061633662316238316561614539775f5a4e35385f244c5424616c6c6f632e2e737472696e672e2e537472696e67247532302461732475323024636f72652e2e666d742e2e5772697465244754243977726974655f73747231376830306136663730663763613531633235452e6c6c766d2e31303938323939333034353232393837393531353a795f5a4e35385f244c5424616c6c6f632e2e737472696e672e2e537472696e67247532302461732475323024636f72652e2e666d742e2e577269746524475424313077726974655f6368617231376836656230613834393730363936353764452e6c6c766d2e31303938323939333034353232393837393531353b375f5a4e36626c616b65323134426c616b653262566172436f726538636f6d707265737331376862373461393335333133656536623032453c305f5a4e3462733538366465636f646531316465636f64655f696e746f31376832366665303063303966626636623863453d575f5a4e34636f726533707472353364726f705f696e5f706c616365244c5424636f72652e2e616c6c6f632e2e6c61796f75742e2e4c61796f75744572726f722447542431376832613236653265366332366232333665453e625f5a4e36395f244c5424636f72652e2e616c6c6f632e2e6c61796f75742e2e4c61796f75744572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376832393637613332326332613165663338453f7a5f5a4e39325f244c542462797465732e2e62797465732e2e4279746573247532302461732475323024636f72652e2e636f6e766572742e2e46726f6d244c5424616c6c6f632e2e7665632e2e566563244c542475382447542424475424244754243466726f6d3137683765643461346138383266613761633045404a5f5a4e35627974657335627974657331327374617469635f636c6f6e6531376833323130386566643438323766363666452e6c6c766d2e3334343432333333353235373333383435333141325f5a4e35627974657335627974657331337374617469635f746f5f7665633137683034383536303131313538303561363745424e5f5a4e35627974657335627974657331367374617469635f69735f756e6971756531376836633034666662366437323062666139452e6c6c766d2e3334343432333333353235373333383435333143495f5a4e35627974657335627974657331317374617469635f64726f7031376864643031336537396536363530303731452e6c6c766d2e33343434323333333532353733333834353331443a5f5a4e356279746573356279746573323170726f6d6f7461626c655f6576656e5f636c6f6e65313768343363333339313537326466383137614545365f5a4e35627974657335627974657331377368616c6c6f775f636c6f6e655f7665633137683061656661613439613631353238316145463b5f5a4e356279746573356279746573323270726f6d6f7461626c655f6576656e5f746f5f766563313768376337343431613235356465346530354547375f5a4e35627974657335627974657331387368617265645f746f5f7665635f696d706c313768326566333265646563363862616531384548395f5a4e356279746573356279746573323070726f6d6f7461626c655f6576656e5f64726f70313768396532366232633039653138383164384549395f5a4e356279746573356279746573323070726f6d6f7461626c655f6f64645f636c6f6e6531376861396666386432383230363239316630454a3a5f5a4e356279746573356279746573323170726f6d6f7461626c655f6f64645f746f5f76656331376839616166303361376137383561363530454b385f5a4e356279746573356279746573313970726f6d6f7461626c655f6f64645f64726f7031376837303033346434313735363163356530454c395f5a4e356279746573356279746573323070726f6d6f7461626c655f69735f756e6971756531376831333537643837376665396133633162454d4a5f5a4e35627974657335627974657331327368617265645f636c6f6e6531376862633730623138623230636237393064452e6c6c766d2e333434343233333335323537333338343533314e4b5f5a4e35627974657335627974657331337368617265645f746f5f76656331376839396139623662356236303333326238452e6c6c766d2e333434343233333335323537333338343533314f355f5a4e35627974657335627974657331367368617265645f69735f756e69717565313768383462326136323837323563336466644550495f5a4e35627974657335627974657331317368617265645f64726f7031376863383731383462666264363461336363452e6c6c766d2e3334343432333333353235373333383435333151235f5a4e3562797465733561626f7274313768616536373034383432313466636561384552305f5a4e34636f7265336e756d313466726f6d5f7374725f72616469783137686662343361316134393034616533366445534e5f5a4e34636f726533666d74336e756d313470617273655f7536345f696e746f31376866333161333061663037626334346262452e6c6c766d2e313832363532393630363530313031383537353054475f5a4e34636f726533666d74336e756d38666d745f7531323831376836663831323232666336353939343036452e6c6c766d2e3138323635323936303635303130313835373530555c5f5a4e34636f726533666d74336e756d35305f244c5424696d706c2475323024636f72652e2e666d742e2e42696e6172792475323024666f72247532302475382447542433666d74313768653039663762636130333134363631304556705f5a4e34636f726533707472353264726f705f696e5f706c616365244c5424636f72652e2e666d742e2e6275696c646572732e2e506164416461707465722447542431376833383639396237306233346438623161452e6c6c766d2e313134313435373138353633303837323235383957535f5a4e34636f72653463686172376d6574686f647332325f244c5424696d706c2475323024636861722447542431366573636170655f64656275675f657874313768313166356433366163663835653436654558565f5a4e35375f244c5424636f72652e2e666d742e2e417267756d656e7473247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d74313768636532626463316362313866386538364559265f5a4e34636f726533666d7435777269746531376833316239306639333939316161316166455a585f5a4e35395f244c5424636f72652e2e666d742e2e417267756d656e7473247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d7431376832323263633935653933313931633065455b385f5a4e34636f726533666d7439466f726d617474657231327061645f696e74656772616c31376865363062666135303835353662663637455c465f5a4e34636f726533666d7439466f726d617474657231327061645f696e74656772616c313277726974655f70726566697831376866363037623038356465323433646430455d2e5f5a4e34636f726533666d7439466f726d61747465723370616431376839643066373134613465333036653537455e3f5f5a4e34636f726533666d7439466f726d617474657231397061645f666f726d61747465645f706172747331376866613566626361396534663366643739455f415f5a4e34636f726533666d7439466f726d6174746572323177726974655f666f726d61747465645f7061727473313768633039663339346136333039306233354560465f5a4e34636f726533666d7439466f726d6174746572323664656275675f7374727563745f6669656c64335f66696e697368313768376531303563333761333334303632364561485f5a4e34335f244c5424626f6f6c247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d74313768386633653662656130636263643036664562455f5a4e34305f244c5424737472247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d74313768373436386136383939373866633230654563465f5a4e34315f244c542463686172247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d74313768383531393237346430323466633533654564485f5a4e34335f244c542463686172247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d74313768613762373831393835373164623434344565475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d74313768346364336130343235653439383736384566475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d74313768646238353166633131656430626537364567495f5a4e34345f244c54242452462454247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d74313768346164326330366665643939366634394568455f5a4e33365f244c542454247532302461732475323024636f72652e2e616e792e2e416e792447542437747970655f6964313768376665643762343638326265623161384569665f5a4e37335f244c5424636f72652e2e70616e69632e2e70616e69635f696e666f2e2e50616e6963496e666f247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d7431376837363235313165623539666437646662456a395f5a4e34636f7265336e756d366269676e756d384269673332783430386d756c5f706f773231376832333939653931373730303134613065456b3c5f5a4e34636f7265336e756d366269676e756d38426967333278343031306d756c5f64696769747331376838323466373032346336373365353031456c3b5f5a4e34636f7265336e756d37666c743264656331376469676974735f746f5f6465635f73747231376861643333386363303862663761646464456d455f5a4e34636f726533666d7435666c6f61743239666c6f61745f746f5f646563696d616c5f636f6d6d6f6e5f657861637431376864626231396163396638623139653135456e485f5a4e34636f726533666d7435666c6f61743332666c6f61745f746f5f646563696d616c5f636f6d6d6f6e5f73686f727465737431376832356165303934633231343635623632456f4c5f5a4e34636f726533666d7435666c6f61743336666c6f61745f746f5f6578706f6e656e7469616c5f636f6d6d6f6e5f73686f72746573743137686634343439643662333438626433336545705e5f5a4e34636f726533666d7435666c6f617435305f244c5424696d706c2475323024636f72652e2e666d742e2e44656275672475323024666f7224753230246636342447542433666d74313768313334356638336136653937306362614571605f5a4e34636f726533666d7435666c6f617435325f244c5424696d706c2475323024636f72652e2e666d742e2e446973706c61792475323024666f7224753230246636342447542433666d74313768323431376263646466626264396133304572395f5a4e34636f726533737472377061747465726e31315374725365617263686572336e65773137683635623239366636353436383834633645734a5f5a4e34636f726537756e69636f64653132756e69636f64655f6461746131356772617068656d655f657874656e64366c6f6f6b75703137683361303135363166376438363565343645743e5f5a4e34636f726533707472323864726f705f696e5f706c616365244c542424524624753634244754243137686632383034353838343339356361626245757a5f5a4e34636f726533707472383864726f705f696e5f706c616365244c5424636f72652e2e70616e69632e2e70616e69635f696e666f2e2e50616e6963496e666f2e2e696e7465726e616c5f636f6e7374727563746f722e2e4e6f5061796c6f616424475424313768393561663934356261646666663164354576305f5a4e34636f72653970616e69636b696e673970616e69635f666d743137683137656265323637393339346434363345773a5f5a4e34636f72653970616e69636b696e67313870616e69635f6e6f756e77696e645f666d743137683162623235323536323563626365336345782c5f5a4e34636f72653970616e69636b696e673570616e69633137683031333364623535393431663137393945793a5f5a4e34636f72653970616e69636b696e67313870616e69635f626f756e64735f636865636b31376863346539323535633831643234393765457a355f5a4e34636f72653970616e69636b696e6731336173736572745f6661696c656431376837343364343064623063656262303634457b3b5f5a4e34636f72653970616e69636b696e6731396173736572745f6661696c65645f696e6e657231376835316661346564363635633865663539457c335f5a4e34636f72653373747238636f6e76657274733966726f6d5f7574663831376830623066636266373533313961663332457d365f5a4e34636f72653373747235636f756e743134646f5f636f756e745f636861727331376833663034386438366363316436653337457e4a5f5a4e34636f726533666d74336e756d33696d7037666d745f75363431376837616563323263663137613936363734452e6c6c766d2e31313731353539313634323639313336333630377f615f5a4e34636f726533666d74336e756d33696d7035315f244c5424696d706c2475323024636f72652e2e666d742e2e446973706c61792475323024666f72247532302475382447542433666d7431376839663264653863653532666165626465458001625f5a4e34636f726533666d74336e756d33696d7035325f244c5424696d706c2475323024636f72652e2e666d742e2e446973706c61792475323024666f7224753230247533322447542433666d7431376862396262366262616238333065376239458101625f5a4e34636f726533666d74336e756d33696d7035325f244c5424696d706c2475323024636f72652e2e666d742e2e446973706c61792475323024666f7224753230246936342447542433666d7431376863663861323531343166393861333230458201625f5a4e34636f726533666d74336e756d33696d7035325f244c5424696d706c2475323024636f72652e2e666d742e2e446973706c61792475323024666f7224753230247536342447542433666d7431376833313364363335616231313038356364458301565f5a4e34636f726533707472353264726f705f696e5f706c616365244c5424636f72652e2e666d742e2e6275696c646572732e2e506164416461707465722447542431376833383639396237306233346438623161458401645f5a4e37315f244c5424636f72652e2e6f70732e2e72616e67652e2e52616e6765244c542449647824475424247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376862343735376365333866656262633462458501595f5a4e36305f244c5424636f72652e2e63656c6c2e2e426f72726f774572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d74313768323332616130653564616239313365364586015c5f5a4e36335f244c5424636f72652e2e63656c6c2e2e426f72726f774d75744572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376863353232313733616163616538656532458701395f5a4e34636f72653463656c6c323270616e69635f616c72656164795f626f72726f77656431376837303439376565663966656636633765458801415f5a4e34636f72653463656c6c333070616e69635f616c72656164795f6d757461626c795f626f72726f77656431376836326239396535336130613565643564458901325f5a4e34636f726536726573756c743133756e777261705f6661696c656431376833353261353332373338663466376236458a01675f5a4e36385f244c5424636f72652e2e666d742e2e6275696c646572732e2e50616441646170746572247532302461732475323024636f72652e2e666d742e2e5772697465244754243977726974655f73747231376863356532376635376237333137666235458b01695f5a4e36385f244c5424636f72652e2e666d742e2e6275696c646572732e2e50616441646170746572247532302461732475323024636f72652e2e666d742e2e577269746524475424313077726974655f6368617231376836666333306633356433313038323264458c013c5f5a4e34636f726533666d74386275696c6465727331314465627567537472756374356669656c6431376830363965386366316632636331343732458d013b5f5a4e34636f726533666d74386275696c64657273313044656275675475706c65356669656c6431376833316165313537643739313566313730458e01395f5a4e34636f726533666d74386275696c646572733944656275674c69737435656e74727931376866346338656232383861636362376565458f01305f5a4e34636f726533666d743557726974653977726974655f666d7431376834383634653635626533623334313461459001425f5a4e34636f7265336e756d37666c743264656338737472617465677936647261676f6e396d756c5f706f77313031376838636138613634343339646563343638459101495f5a4e34636f7265336e756d37666c743264656338737472617465677936647261676f6e3135666f726d61745f73686f727465737431376833666666313032623834656633373637459201465f5a4e34636f7265336e756d37666c743264656338737472617465677936647261676f6e3132666f726d61745f657861637431376832663931616639666233353432336333459301535f5a4e34636f7265336f70733866756e6374696f6e36466e4f6e63653963616c6c5f6f6e636531376832363432343863326539396266316539452e6c6c766d2e313134333339373135393234303630383036389401445f5a4e34636f726535736c69636535696e6465783236736c6963655f73746172745f696e6465785f6c656e5f6661696c31376836343839663765366561306337333166459501425f5a4e34636f726535736c69636535696e6465783234736c6963655f656e645f696e6465785f6c656e5f6661696c31376838376562323035343262366635616166459601405f5a4e34636f726535736c69636535696e6465783232736c6963655f696e6465785f6f726465725f6661696c31376835373830636663326565346438646463459701325f5a4e34636f7265337374723136736c6963655f6572726f725f6661696c31376834626132313961633437626533396631459801355f5a4e34636f7265337374723139736c6963655f6572726f725f6661696c5f7274313768613266313161653166643639613535644599014d5f5a4e34636f726537756e69636f6465397072696e7461626c6535636865636b31376837346365663562363466373538633334452e6c6c766d2e313134333339373135393234303630383036389a013c5f5a4e34636f726537756e69636f6465397072696e7461626c65313269735f7072696e7461626c6531376832663963336261373564323438383466459b01755f5a4e34636f726533666d74336e756d35305f244c5424696d706c2475323024636f72652e2e666d742e2e44656275672475323024666f7224753230247533322447542433666d7431376830396334333131313138623438393031452e6c6c766d2e313139343530303336353038343732313030329c0183015f5a4e37375f244c5424636f72652e2e6e756d2e2e6e6f6e7a65726f2e2e4e6f6e5a65726f244c54247573697a6524475424247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376831323163323638626262326164613534452e6c6c766d2e313139343530303336353038343732313030329d014c5f5a4e34636f7265336e756d37666c74326465633873747261746567793567726973753139666f726d61745f73686f72746573745f6f707431376832303531386436386635656662396139459e01495f5a4e34636f7265336e756d37666c74326465633873747261746567793567726973753136666f726d61745f65786163745f6f707431376866396436363961303335663462643461459f01595f5a4e34636f7265336e756d37666c74326465633873747261746567793567726973753136666f726d61745f65786163745f6f70743134706f737369626c795f726f756e643137683932623532386134663563333831326345a001325f5a4e34636f7265366f7074696f6e3133756e777261705f6661696c65643137686434373562333534393730656433303945a101325f5a4e34636f7265366f7074696f6e31336578706563745f6661696c65643137683761373162626562623861336138346145a201655f5a4e34636f726535736c69636532395f244c5424696d706c24753230242475356224542475356424244754243135636f70795f66726f6d5f736c69636531376c656e5f6d69736d617463685f6661696c3137686161396465386631393031353636383445a3015d5f5a4e3136637572766532353531395f64616c656b376261636b656e643673657269616c33753332356669656c6431364669656c64456c656d656e74323632353861735f62797465733137686366646330653336623538323836656145a40190015f5a4e3136637572766532353531395f64616c656b356669656c6438315f244c5424696d706c2475323024637572766532353531395f64616c656b2e2e6261636b656e642e2e73657269616c2e2e7533322e2e6669656c642e2e4669656c64456c656d656e7432363235244754243132737172745f726174696f5f693137683461626638306435383439626462316445a5017b5f5a4e3136637572766532353531395f64616c656b376261636b656e643673657269616c33753332356669656c6431364669656c64456c656d656e743236323531327371756172655f696e6e657231376832393661646431346662313362343863452e6c6c766d2e33313435303338383738363536343237363236a601d6015f5a4e3138345f244c542424524624637572766532353531395f64616c656b2e2e6261636b656e642e2e73657269616c2e2e7533322e2e6669656c642e2e4669656c64456c656d656e7432363235247532302461732475323024636f72652e2e6f70732e2e61726974682e2e4d756c244c542424524624637572766532353531395f64616c656b2e2e6261636b656e642e2e73657269616c2e2e7533322e2e6669656c642e2e4669656c64456c656d656e74323632352447542424475424336d756c3137686531633862376162376238646465333245a7015a5f5a4e3136637572766532353531395f64616c656b376261636b656e643673657269616c33753332356669656c6431364669656c64456c656d656e743236323535706f77326b3137683333323961306331386633323239396145a801d6015f5a4e3138345f244c542424524624637572766532353531395f64616c656b2e2e6261636b656e642e2e73657269616c2e2e7533322e2e6669656c642e2e4669656c64456c656d656e7432363235247532302461732475323024636f72652e2e6f70732e2e61726974682e2e537562244c542424524624637572766532353531395f64616c656b2e2e6261636b656e642e2e73657269616c2e2e7533322e2e6669656c642e2e4669656c64456c656d656e74323632352447542424475424337375623137686366623936343361316632393537623245a9018b015f5a4e3130395f244c542424524624637572766532353531395f64616c656b2e2e6261636b656e642e2e73657269616c2e2e7533322e2e6669656c642e2e4669656c64456c656d656e7432363235247532302461732475323024636f72652e2e6f70732e2e61726974682e2e4e656724475424336e65673137683836363239633063393965666636346245aa01605f5a4e3136637572766532353531395f64616c656b376261636b656e643673657269616c33753332356669656c6431364669656c64456c656d656e7432363235313066726f6d5f62797465733137683637646232333431303863376333343845ab01585f5a4e3136637572766532353531395f64616c656b367363616c6172365363616c61723672656475636531376837616130396331613530383062303237452e6c6c766d2e3137393331343330323733373936393938373634ac0181015f5a4e3136637572766532353531395f64616c656b367363616c617237345f244c5424696d706c2475323024637572766532353531395f64616c656b2e2e6261636b656e642e2e73657269616c2e2e7533322e2e7363616c61722e2e5363616c6172323924475424347061636b3137686133393036643737393836646631636545ad01505f5a4e3136637572766532353531395f64616c656b376261636b656e643673657269616c33753332367363616c6172385363616c61723239337375623137683137393638663832636236353661396645ae01585f5a4e3136637572766532353531395f64616c656b376261636b656e643673657269616c33753332367363616c6172385363616c61723239313066726f6d5f62797465733137686234626232333062633331333032376345af01fd015f5a4e3136637572766532353531395f64616c656b376261636b656e643673657269616c313263757276655f6d6f64656c733137365f244c5424696d706c2475323024636f72652e2e6f70732e2e61726974682e2e416464244c542424524624637572766532353531395f64616c656b2e2e6261636b656e642e2e73657269616c2e2e63757276655f6d6f64656c732e2e50726f6a6563746976654e69656c73506f696e74244754242475323024666f72247532302424524624637572766532353531395f64616c656b2e2e656477617264732e2e45647761726473506f696e7424475424336164643137686666333438303231386330353465363245b0016e5f5a4e38315f244c5424637572766532353531395f64616c656b2e2e656477617264732e2e45647761726473506f696e74247532302461732475323024636f72652e2e6f70732e2e61726974682e2e41646424475424336164643137683339646434643332326436393935383145b101545f5a4e3136637572766532353531395f64616c656b3972697374726574746f3139436f6d7072657373656452697374726574746f31306465636f6d70726573733137683463656465316565663362356534343245b2014c5f5a4e3136637572766532353531395f64616c656b3972697374726574746f313452697374726574746f506f696e7438636f6d70726573733137686465383739343065626437373931633245b301795f5a4e3136637572766532353531395f64616c656b3972697374726574746f313452697374726574746f506f696e743236656c6c696761746f725f72697374726574746f5f666c61766f7231376863383765363761373331636563663363452e6c6c766d2e3138313535353136363236333533343435313238b401575f5a4e3136637572766532353531395f64616c656b3972697374726574746f313452697374726574746f506f696e74313866726f6d5f756e69666f726d5f62797465733137683434383365323265616362353866373845b501755f5a4e38365f244c5424637572766532353531395f64616c656b2e2e72697374726574746f2e2e52697374726574746f506f696e74247532302461732475323024737562746c652e2e436f6e7374616e7454696d654571244754243563745f65713137686337646539363435646138333437393645b601465f5a4e3136637572766532353531395f64616c656b3972697374726574746f31306465636f6d707265737336737465705f313137683164393730623731313563313734366245b701465f5a4e3136637572766532353531395f64616c656b3972697374726574746f31306465636f6d707265737336737465705f323137683065653861323531646239393538346445b801465f5a4e31387061726974795f7363616c655f636f64656335636f6465633139656e636f64655f736c6963655f6e6f5f6c656e3137686231353637383563343936343739393145b9015d5f5a4e34636f726533707472353964726f705f696e5f706c616365244c54247363616c655f696e666f2e2e706f727461626c652e2e506f727461626c655265676973747279244754243137686364623134646231653164613836646645ba01ac015f5a4e35616c6c6f63337665633136696e5f706c6163655f636f6c6c6563743130385f244c5424696d706c2475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c54245424432449244754242475323024666f722475323024616c6c6f632e2e7665632e2e566563244c54245424475424244754243966726f6d5f697465723137683034653833336137323532393764633745bb01ac015f5a4e35616c6c6f63337665633136696e5f706c6163655f636f6c6c6563743130385f244c5424696d706c2475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c54245424432449244754242475323024666f722475323024616c6c6f632e2e7665632e2e566563244c54245424475424244754243966726f6d5f697465723137683462313431326235333839396533383345bc01ac015f5a4e35616c6c6f63337665633136696e5f706c6163655f636f6c6c6563743130385f244c5424696d706c2475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c54245424432449244754242475323024666f722475323024616c6c6f632e2e7665632e2e566563244c54245424475424244754243966726f6d5f697465723137683862643933623863303837633539653145bd01ac015f5a4e35616c6c6f63337665633136696e5f706c6163655f636f6c6c6563743130385f244c5424696d706c2475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c54245424432449244754242475323024666f722475323024616c6c6f632e2e7665632e2e566563244c54245424475424244754243966726f6d5f697465723137683831623061363765306436393534653045be01ac015f5a4e35616c6c6f63337665633136696e5f706c6163655f636f6c6c6563743130385f244c5424696d706c2475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c54245424432449244754242475323024666f722475323024616c6c6f632e2e7665632e2e566563244c54245424475424244754243966726f6d5f697465723137686438396663646636333161393830333945bf01ac015f5a4e35616c6c6f63337665633136696e5f706c6163655f636f6c6c6563743130385f244c5424696d706c2475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c54245424432449244754242475323024666f722475323024616c6c6f632e2e7665632e2e566563244c54245424475424244754243966726f6d5f697465723137686635633833616265306631623262346145c00185015f5a4e39385f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c5424542443244924475424244754243966726f6d5f697465723137683731393039303236643835396438613045c101a9015f5a4e31346672616d655f6d657461646174613132325f244c5424696d706c2475323024636f72652e2e636f6e766572742e2e46726f6d244c54246672616d655f6d657461646174612e2e52756e74696d654d657461646174615072656669786564244754242475323024666f722475323024616c6c6f632e2e7665632e2e566563244c5424753824475424244754243466726f6d3137683737356566343935383737616665343645c2014c5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376838336466636663303462336235303132452e6c6c766d2e3138303139373434373438303230313830383436c301595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137686163313730333462386433613031616345c401f6015f5a4e35616c6c6f633131636f6c6c656374696f6e7335627472656536617070656e643137385f244c5424696d706c2475323024616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e4e6f6465526566244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4f776e65642443244b24432456244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4c6561664f72496e7465726e616c24475424244754243962756c6b5f707573683137683235396539616534343864363030393045c50185015f5a4e3130325f244c5424636f72652e2e697465722e2e61646170746572732e2e6d61702e2e4d6170244c5424492443244624475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e6974657261746f722e2e4974657261746f722447542434666f6c643137683362626131623361343562383339326545c60185015f5a4e3130325f244c5424636f72652e2e697465722e2e61646170746572732e2e6d61702e2e4d6170244c5424492443244624475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e6974657261746f722e2e4974657261746f722447542434666f6c643137683364646265613164303537306637396545c70185015f5a4e3130325f244c5424636f72652e2e697465722e2e61646170746572732e2e6d61702e2e4d6170244c5424492443244624475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e6974657261746f722e2e4974657261746f722447542434666f6c643137683564633737306237306666643266323745c80185015f5a4e3130325f244c5424636f72652e2e697465722e2e61646170746572732e2e6d61702e2e4d6170244c5424492443244624475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e6974657261746f722e2e4974657261746f722447542434666f6c643137686562333033396561303761343465663045c901745f5a4e38365f244c5424616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137683232376265663739626436356331303345ca01745f5a4e38365f244c5424616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137686333376462356162363363666138323345cb018c015f5a4e3130345f244c54247061726974795f7363616c655f636f6465632e2e636f6d706163742e2e436f6d70616374526566244c5424753332244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542439656e636f64655f746f3137683436343566616566316331366631623245cc01ae015f5a4e31346672616d655f6d6574616461746133763134315f3131365f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230246672616d655f6d657461646174612e2e7631342e2e50616c6c6574436f6e7374616e744d65746164617461244c542454244754242447542439656e636f64655f746f3137686233316434393131323239653565393145cd01ac015f5a4e31346672616d655f6d6574616461746133763134315f3131345f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230246672616d655f6d657461646174612e2e7631342e2e53746f72616765456e7472794d65746164617461244c542454244754242447542439656e636f64655f746f3137683534613532656633343633393832643045ce01435f5a4e31346672616d655f6d6574616461746133763134313852756e74696d654d65746164617461563134336e65773137686661383637613661666263623734343145cf0182015f5a4e39305f244c54246672616d655f6d657461646174612e2e7631342e2e50616c6c65744d657461646174612475323024617324753230247363616c655f696e666f2e2e72656769737472792e2e496e746f506f727461626c65244754243133696e746f5f706f727461626c653137686537613439306263303136633531636245d001a1015f5a4e31346672616d655f6d6574616461746133763134315f3130335f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230246672616d655f6d657461646174612e2e7631342e2e52756e74696d654d657461646174615631342447542439656e636f64655f746f3137683838653239666465373933633033633045d101a6015f5a4e31346672616d655f6d6574616461746133763134315f3130385f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230246672616d655f6d657461646174612e2e7631342e2e50616c6c65744d65746164617461244c542454244754242447542439656e636f64655f746f3137683631313831316634663466323731346445d201ad015f5a4e31346672616d655f6d6574616461746133763134315f3131355f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230246672616d655f6d657461646174612e2e7631342e2e50616c6c657453746f726167654d65746164617461244c542454244754242447542439656e636f64655f746f3137686464666539313432646331326664356545d3019b015f5a4e31307363616c655f696e666f327479315f3130325f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230247363616c655f696e666f2e2e74792e2e54797065506172616d65746572244c542454244754242447542439656e636f64655f746f3137683365323165393033323465636362303445d401a2015f5a4e31307363616c655f696e666f327479366669656c6473315f3130325f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230247363616c655f696e666f2e2e74792e2e6669656c64732e2e4669656c64244c542454244754242447542439656e636f64655f746f3137686431313236616462353961386535643745d501a6015f5a4e31307363616c655f696e666f3274793776617269616e74315f3130355f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230247363616c655f696e666f2e2e74792e2e76617269616e742e2e56617269616e74244c542454244754242447542439656e636f64655f746f3137683933376166663334623966323566343445d6019c015f5a4e31307363616c655f696e666f38706f727461626c65315f39385f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230247363616c655f696e666f2e2e706f727461626c652e2e506f727461626c65547970652447542439656e636f64655f746f3137683631383662646536323236346137376645d7013f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f64653137683637383730623630323462363833633345d80194015f5a4e31346672616d655f6d65746164617461315f39355f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230246672616d655f6d657461646174612e2e52756e74696d654d65746164617461244754243973697a655f68696e743137683234363333373636353463303162353545d901335f5a4e34636f726535736c69636534736f727431306d657267655f736f72743137683132646262386136303062393266616545da01425f5a4e34636f726535736c69636534736f72743235696e73657274696f6e5f736f72745f73686966745f6c6566743137686165383738336532656534363238643045db0193015f5a4e3131365f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e496e746f49746572244c54244b244324562443244124475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e6974657261746f722e2e4974657261746f7224475424346e6578743137686561613831336538323664343561373745dc01645f5a4e36355f244c542424753562245424753564242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542439656e636f64655f746f3137683536343932353237376139353862663945dd01b0015f5a4e31346672616d655f6d6574616461746133763135315f3131385f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230246672616d655f6d657461646174612e2e7631352e2e52756e74696d654170694d6574686f644d65746164617461244c542454244754242447542439656e636f64655f746f3137683531646264353632373935326536616345de0181015f5a4e39395f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e42547265654d6170244c54244b244324562443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137686531636264666231613731366664663645df0181015f5a4e39395f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e496e746f49746572244c54244b244324562443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137686431616434363739303737613065383445e001435f5a4e31346672616d655f6d6574616461746133763135313852756e74696d654d65746164617461563135336e65773137683035613339323630376565626238643645e10182015f5a4e39305f244c54246672616d655f6d657461646174612e2e7631352e2e437573746f6d4d657461646174612475323024617324753230247363616c655f696e666f2e2e72656769737472792e2e496e746f506f727461626c65244754243133696e746f5f706f727461626c653137683438326137373934313736306361386645e2018d015f5a4e3130305f244c54246672616d655f6d657461646174612e2e7631352e2e52756e74696d654170694d6574686f644d657461646174612475323024617324753230247363616c655f696e666f2e2e72656769737472792e2e496e746f506f727461626c65244754243133696e746f5f706f727461626c653137686634326430663564313764613464636345e30182015f5a4e39305f244c54246672616d655f6d657461646174612e2e7631352e2e50616c6c65744d657461646174612475323024617324753230247363616c655f696e666f2e2e72656769737472792e2e496e746f506f727461626c65244754243133696e746f5f706f727461626c653137686632313563383733646564386237303345e401a1015f5a4e31346672616d655f6d6574616461746133763135315f3130335f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230246672616d655f6d657461646174612e2e7631352e2e52756e74696d654d65746164617461563135244754243973697a655f68696e743137683734306265346164636163643564353645e501a1015f5a4e31346672616d655f6d6574616461746133763135315f3130335f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230246672616d655f6d657461646174612e2e7631352e2e52756e74696d654d657461646174615631352447542439656e636f64655f746f3137686439303738643136663363383232396445e601a6015f5a4e31346672616d655f6d6574616461746133763135315f3130385f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230246672616d655f6d657461646174612e2e7631352e2e50616c6c65744d65746164617461244c542454244754242447542439656e636f64655f746f3137686566633362653338633266623432643745e701aa015f5a4e31346672616d655f6d6574616461746133763135315f3131325f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230246672616d655f6d657461646174612e2e7631352e2e52756e74696d654170694d65746164617461244c542454244754242447542439656e636f64655f746f3137683766336333383032613938663239396145e801495f5a4e32396672616d655f6d657461646174615f686173685f657874656e73696f6e31324d657461646174614861736834686173683137683861383934363732376330366538623745e9019a015f5a4e32396672616d655f6d657461646174615f686173685f657874656e73696f6e315f38365f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f6d657461646174615f686173685f657874656e73696f6e2e2e4d6f64652447542439747970655f696e666f3137686464643638626163323937346132363345ea014c5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376862386430393662663631323563313463452e6c6c766d2e3132393736303835353438343938383631353737eb014c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137683364323163316434353435366436353945ec014b5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376832313461356361366230373631643032452e6c6c766d2e32353638393138333230313631303133383939ed014c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137683561333739303230313839313839336145ee014c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137683633616434616535326336616366653945ef014c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137686263393435633536383863363761623845f001595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683332663530636432636439373334663045f101595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137686234393034653565663563316664376445f201595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137686431633330636166626165343733383845f301595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137686638663235393032643839633164303545f4018d015f5a4e31336672616d655f737570706f7274386469737061746368315f38305f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f737570706f72742e2e64697370617463682e2e506179732447542439747970655f696e666f3137683933613030653461343866363835336545f50196015f5a4e31336672616d655f737570706f7274386469737061746368315f38395f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f737570706f72742e2e64697370617463682e2e4469737061746368436c6173732447542439747970655f696e666f3137683162346138653234313337666231376345f60195015f5a4e31336672616d655f737570706f7274386469737061746368315f38385f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f737570706f72742e2e64697370617463682e2e4469737061746368496e666f2447542439747970655f696e666f3137683330333965323338353137616531613545f701ad015f5a4e31336672616d655f737570706f72743674726169747336746f6b656e73346d697363315f3130315f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f737570706f72742e2e7472616974732e2e746f6b656e732e2e6d6973632e2e42616c616e63655374617475732447542439747970655f696e666f3137686664616465373732353836626238323645f801595f5a4e36305f244c5424616c6c6f632e2e737472696e672e2e537472696e67247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d743137683864393031613030383666373938373245f901625f5a4e36395f244c54247061726974795f7363616c655f636f6465632e2e6572726f722e2e4572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686363656231383263633834363164346345fa016d5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c32316765745f7472616e73616374696f6e5f6c6576656c31376831653137366465656436393261346163452e6c6c766d2e33353936323533383937393435343238363335fb0180015f5a4e39385f244c54246672616d655f737570706f72742e2e73746f726167652e2e7472616e73616374696f6e616c2e2e53746f726167654c617965724775617264247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137683538626338313333643830376138393345fc012e5f5a4e313161727261795f6279746573396279746573326865783137686631343332353634373665303466376445fd01465f5a4e31336672616d655f737570706f7274313664697370617463685f636f6e7465787436474c4f42414c365f5f696e69743137683464353735316263336661343564363845fe01ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137683034656537646332633336366535343345ff01ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f6974657231376837643962306161376138613966306665458002ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137686366663138666363383630646666323345810285015f5a4e39385f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c5424542443244924475424244754243966726f6d5f697465723137683538313538623061376430616337633245820285015f5a4e31307363616c655f696e666f35696d706c7338305f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024636f72652e2e6f7074696f6e2e2e4f7074696f6e244c542454244754242447542439747970655f696e666f3137683364373530643366346539363039363045830295015f5a4e31307363616c655f696e666f35696d706c7339365f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230247061726974795f7363616c655f636f6465632e2e636f6d706163742e2e436f6d70616374244c542454244754242447542439747970655f696e666f31376837383362353261343933313939396431458402765f5a4e34636f726533707472353964726f705f696e5f706c616365244c54246672616d655f73797374656d2e2e6c696d6974732e2e56616c69646174696f6e4572726f72732447542431376837303864616334353033396330373037452e6c6c766d2e343136383139373135313634363230353530318502435f5a4e31326672616d655f73797374656d366c696d6974733132426c6f636b576569676874733876616c696461746531376833363762613931363631303861353462458602475f5a4e31326672616d655f73797374656d366c696d6974733139426c6f636b576569676874734275696c646572356275696c64313768626362643930313934363739316266614587028e015f5a4e31326672616d655f73797374656d366c696d697473315f38345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f73797374656d2e2e6c696d6974732e2e426c6f636b4c656e6774682447542439747970655f696e666f31376832383036633662306365346434323264458802685f5a4e37355f244c54246672616d655f73797374656d2e2e6c696d6974732e2e56616c69646174696f6e4572726f7273247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376863373336373966393830313039636266458902a0015f5a4e31326672616d655f73797374656d366c696d697473315f3130315f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230246672616d655f73797374656d2e2e6c696d6974732e2e57656967687473506572436c617373244754243973697a655f68696e7431376866343861306230666134313537633934458a0292015f5a4e31326672616d655f73797374656d366c696d697473315f38385f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f73797374656d2e2e6c696d6974732e2e57656967687473506572436c6173732447542439747970655f696e666f31376834396462643336346138323936343661458b029c015f5a4e31326672616d655f73797374656d366c696d697473315f39385f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230246672616d655f73797374656d2e2e6c696d6974732e2e426c6f636b57656967687473244754243973697a655f68696e7431376834636435633431633038353437306339458c028f015f5a4e31326672616d655f73797374656d366c696d697473315f38355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f73797374656d2e2e6c696d6974732e2e426c6f636b576569676874732447542439747970655f696e666f31376834626532376363613138613635646663458d02ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f6974657231376830383338346234346561366265666531458e02ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f6974657231376866376230336430643539393737306266458f02ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f6974657231376866383135386663353163396364656166459002a3015f5a4e31336672616d655f737570706f7274386469737061746368315f3130315f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f737570706f72742e2e64697370617463682e2e5065724469737061746368436c617373244c542454244754242447542439747970655f696e666f31376830373666343234633562633634336534459102a3015f5a4e31336672616d655f737570706f7274386469737061746368315f3130315f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f737570706f72742e2e64697370617463682e2e5065724469737061746368436c617373244c542454244754242447542439747970655f696e666f31376830633034303963316432393261366334459202795f5a4e31326672616d655f73797374656d315f37305f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f73797374656d2e2e50686173652447542439747970655f696e666f313768323562363666646130663631633337384593028a015f5a4e31326672616d655f73797374656d315f38375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f73797374656d2e2e4c61737452756e74696d6555706772616465496e666f2447542439747970655f696e666f313768316663333239646138343565363039344594024b5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376864393665316435333530336665356563452e6c6c766d2e3233353739323532383235303835303038333495024c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f70757368313768393036613062636632323935613466374596024c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f7075736831376866396663363665373938653436333731459702595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c6531376834353232316161323963383438393835459802595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c6531376861313265373761306232343831373731459902595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c6531376862356230316132656562653565656466459a02445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e7431376838323838373932303862343037393738459b02445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e7431376865656463666165633630306137323236459c023f5f5a4e366b656363616b386b656363616b5f7031376863386161323430633639663264313561452e6c6c766d2e3339323632383034393030343233353234359d025f5f5a4e34636f726533707472333564726f705f696e5f706c616365244c54246c6f672e2e4e6f704c6f676765722447542431376835383965323339643935303930353363452e6c6c766d2e31303836323130343630343638393633323335399e02665f5a4e34335f244c54246c6f672e2e4e6f704c6f676765722475323024617324753230246c6f672e2e4c6f672447542437656e61626c656431376837626131363931643666333962303861452e6c6c766d2e31303836323130343630343638393633323335399f02625f5a4e34335f244c54246c6f672e2e4e6f704c6f676765722475323024617324753230246c6f672e2e4c6f6724475424336c6f6731376831333563643834666261313161316430452e6c6c766d2e3130383632313034363034363839363332333539a002645f5a4e34335f244c54246c6f672e2e4e6f704c6f676765722475323024617324753230246c6f672e2e4c6f672447542435666c75736831376834636339373639396636626565646331452e6c6c766d2e3130383632313034363034363839363332333539a102335f5a4e336c6f6731335f5f707269766174655f617069386c6f675f696d706c3137683233363835643934323362643030626545a202475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686334393539333131666462356162313345a3023d5f5a4e34636f726533707472323764726f705f696e5f706c616365244c5424245246247538244754243137683536353231383262643035383964353845a402355f5a4e34636f72653970616e69636b696e6731336173736572745f6661696c65643137683932633766366635313863616330373945a502385f5a4e366d65726c696e367374726f6265395374726f626531323838626567696e5f6f703137683935613138383161373539376632353245a6023a5f5a4e366d65726c696e31307472616e73637269707431305472616e736372697074336e65773137686630333838613739613261316435366545a702465f5a4e366d65726c696e31307472616e73637269707431305472616e7363726970743134617070656e645f6d6573736167653137686237386432613861626364316564616645a802475f5a4e366d65726c696e31307472616e73637269707431305472616e73637269707431356368616c6c656e67655f62797465733137683139396639343665653136613232653645a9024b5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376833363434303339363835643063323930452e6c6c766d2e33313730333639323635313932303830323139aa024c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137683961343862356639626162363031616645ab024c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137686231636231343532373531396537373445ac028e015f5a4e313570616c6c65745f62616c616e636573357479706573315f38325f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302470616c6c65745f62616c616e6365732e2e74797065732e2e526561736f6e732447542439747970655f696e666f3137683934623234613030333762363530363345ad0291015f5a4e313570616c6c65745f62616c616e636573357479706573315f38355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302470616c6c65745f62616c616e6365732e2e74797065732e2e4578747261466c6167732447542439747970655f696e666f3137683738363661323165396163336662353445ae029a015f5a4e313570616c6c65745f62616c616e636573357479706573315f39345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302470616c6c65745f62616c616e6365732e2e74797065732e2e41646a7573746d656e74446972656374696f6e2447542439747970655f696e666f3137683765323238613762666566366335373745af025e5f5a4e34636f726533666d74336e756d35325f244c5424696d706c2475323024636f72652e2e666d742e2e44656275672475323024666f7224753230247573697a652447542433666d743137686464646433363838656435613663326345b0024b5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376830383063646464613363663233643932452e6c6c766d2e37323338353837393031333039353239363535b102725f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c6531376830306464383863383737323566396339452e6c6c766d2e37323338353837393031333039353239363535b20291015f5a4e39315f244c54247061726974795f7363616c655f636f6465632e2e636f6465632e2e4279746573437572736f722475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e496e7075742447542432377363616c655f696e7465726e616c5f6465636f64655f62797465733137686661393333316138376261633937616245b30285015f5a4e3130325f244c54247061726974795f7363616c655f636f6465632e2e636f6d706163742e2e507265666978496e707574244c542454244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e496e7075742447542434726561643137683832316466626433326334336637656345b402595f5a4e35375f244c54247374722475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542436656e636f64653137683230646433646333616136356166366645b502645f5a4e37315f244c54247061726974795f7363616c655f636f6465632e2e6572726f722e2e4572726f72247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d743137683736653231363062643337396131613845b6027e5f5a4e31357072696d69746976655f7479706573315f37325f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230247072696d69746976655f74797065732e2e483235362447542439747970655f696e666f3137683962666535363234313335363563363845b702655f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f7075736831376830313865383033653035643636626566452e6c6c766d2e37313939383439303534333435303437353339b802ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137686565623638366333623730636330373345b902725f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c6531376862386537663838636630313638306130452e6c6c766d2e37313939383439303534333435303437353339ba024b5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376863306262636233663465353964643634452e6c6c766d2e37313939383439303534333435303437353339bb027e5f5a4e31307363616c655f696e666f35696d706c7337335f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024247535622454247533622424753230244e24753564242447542439747970655f696e666f3137686239613237383564623830303561373245bc02405f5a4e3372797536707265747479386d616e7469737361313977726974655f6d616e74697373615f6c6f6e673137683663643363623032376435363635636245bd022b5f5a4e337279753670726574747938666f726d617436343137686430373033343031366539363934613945be029c025f5a4e35616c6c6f633131636f6c6c656374696f6e73356274726565346e6f646532313048616e646c65244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e4e6f6465526566244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4d75742443244b24432456244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4c65616624475424244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e45646765244754243136696e736572745f726563757273696e673137683139636335616331336466383464376645bf029c025f5a4e35616c6c6f633131636f6c6c656374696f6e73356274726565346e6f646532313048616e646c65244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e4e6f6465526566244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4d75742443244b24432456244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4c65616624475424244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e45646765244754243136696e736572745f726563757273696e673137683239643237333762323061613830393045c002a2015f5a4e3130365f244c5424636f72652e2e697465722e2e61646170746572732e2e636861696e2e2e436861696e244c5424412443244224475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e6974657261746f722e2e4974657261746f7224475424346e65787431376865386438666238623235346561393937452e6c6c766d2e39303538353435373438363939303634333233c102ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137683430316334313061616162663461656445c202ac015f5a4e35616c6c6f63337665633136696e5f706c6163655f636f6c6c6563743130385f244c5424696d706c2475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c54245424432449244754242475323024666f722475323024616c6c6f632e2e7665632e2e566563244c54245424475424244754243966726f6d5f697465723137683236643532313365373031363061633245c302ac015f5a4e35616c6c6f63337665633136696e5f706c6163655f636f6c6c6563743130385f244c5424696d706c2475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c54245424432449244754242475323024666f722475323024616c6c6f632e2e7665632e2e566563244c54245424475424244754243966726f6d5f697465723137683736363639363566326363366361303645c402625f5a4e36375f244c5424616c6c6f632e2e7665632e2e566563244c5424542443244124475424247532302461732475323024636f72652e2e636c6f6e652e2e436c6f6e652447542435636c6f6e653137683061306166383237626337636538653245c502625f5a4e36375f244c5424616c6c6f632e2e7665632e2e566563244c5424542443244124475424247532302461732475323024636f72652e2e636c6f6e652e2e436c6f6e652447542435636c6f6e653137686530656466333463356564656531666145c60285015f5a4e39385f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c5424542443244924475424244754243966726f6d5f697465723137683161643437623264356430626261386145c70285015f5a4e39385f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c5424542443244924475424244754243966726f6d5f697465723137683636656237383536306632623164373545c80285015f5a4e39385f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c5424542443244924475424244754243966726f6d5f697465723137683734316665393834623930396465346645c9024c5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376834393063626561366164316231636530452e6c6c766d2e3135393835393236373434363732363638333538ca024c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137683766323232343466306633636135393045cb02595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683461363334346336316139623434666145cc02595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683539393961326663626432626365376245cd02595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683734386136303531643166653138646545ce0285015f5a4e3130325f244c5424636f72652e2e697465722e2e61646170746572732e2e6d61702e2e4d6170244c5424492443244624475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e6974657261746f722e2e4974657261746f722447542434666f6c643137683565383762343736333961303339336445cf027d5f5a4e36385f244c54247363616c655f696e666f2e2e74792e2e54797065244c54245424475424247532302461732475323024636f72652e2e636c6f6e652e2e436c6f6e652447542435636c6f6e6531376862333962396564323865356239633933452e6c6c766d2e3130323733353337313336363433353738333932d0028b015f5a4e3130385f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e49746572244c54244b2443245624475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e6974657261746f722e2e4974657261746f7224475424346e6578743137686438386238396161363135396630393545d1024b5f5a4e34636f72653373747232315f244c5424696d706c24753230247374722447542431387472696d5f73746172745f6d6174636865733137683136643634396330396130393836363245d202565f5a4e35616c6c6f633131636f6c6c656374696f6e73356274726565336d6170323542547265654d6170244c54244b24432456244324412447542436696e736572743137683864656666343634656335343261636445d30281015f5a4e39395f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e42547265654d6170244c54244b244324562443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137683034393439363666393063613865353045d40281015f5a4e39395f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e42547265654d6170244c54244b244324562443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137686231613133366539613136303232303945d5026f5f5a4e34636f726533707472353264726f705f696e5f706c616365244c54247363616c655f696e666f2e2e74792e2e706174682e2e506174684572726f722447542431376837643834633036333032336638636534452e6c6c766d2e35383434353639303536363434363637353039d602345f5a4e31307363616c655f696e666f32747934706174683450617468336e65773137683737646331386466393439363139323545d7023d5f5a4e31307363616c655f696e666f357574696c73313869735f727573745f6964656e7469666965723137683437663366383065643137396663303245d802425f5a4e31307363616c655f696e666f3274793470617468345061746831366e65775f776974685f7265706c6163653137683337613935333266363961386530623045d9027a5f5a4e36385f244c54247363616c655f696e666f2e2e74792e2e706174682e2e506174684572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376863303238383064363233623735356563452e6c6c766d2e35383434353639303536363434363637353039da02475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683333663866303763653639386461396345db02475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683362396138353262306533643137646345dc024e5f5a4e31307363616c655f696e666f38696e7465726e65723137496e7465726e6572244c542454244754243133696e7465726e5f6f725f6765743137683763613431343133383531656436656545dd02445f5a4e31307363616c655f696e666f387265676973747279385265676973747279313372656769737465725f747970653137683866623063666161646332653436396645de02765f5a4e37385f244c54247363616c655f696e666f2e2e74792e2e547970654465662475323024617324753230247363616c655f696e666f2e2e72656769737472792e2e496e746f506f727461626c65244754243133696e746f5f706f727461626c653137683733386235373762396636396530303545df02485f5a4e31307363616c655f696e666f38726567697374727938526567697374727931376d61705f696e746f5f706f727461626c653137683063643334646364333138373138393945e0026c5f5a4e31307363616c655f696e666f35696d706c7335355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024626f6f6c2447542439747970655f696e666f3137683738613766616237623061383964363745e1026a5f5a4e31307363616c655f696e666f35696d706c7335335f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302475382447542439747970655f696e666f3137683638323036303733636633633735306145e2026b5f5a4e31307363616c655f696e666f35696d706c7335345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230247531362447542439747970655f696e666f3137683430313662323339626334336366666345e3026b5f5a4e31307363616c655f696e666f35696d706c7335345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230247533322447542439747970655f696e666f3137686432303832383334363734663733626345e4026b5f5a4e31307363616c655f696e666f35696d706c7335345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230247536342447542439747970655f696e666f3137683735363131616139643165313765383245e5026c5f5a4e31307363616c655f696e666f35696d706c7335355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024753132382447542439747970655f696e666f3137683736323365346661396266313736386245e602705f5a4e31307363616c655f696e666f35696d706c7335395f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024244c5024245250242447542439747970655f696e666f3137683039666261303039623031346435616345e702475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683331653463666338336463386461346345e8023d5f5a4e34636f726533707472323764726f705f696e5f706c616365244c5424245246247538244754243137683763366334653362613536333161666345e902355f5a4e34636f72653970616e69636b696e6731336173736572745f6661696c65643137683738326430306264303434626232383045ea02405f5a4e31307363686e6f72726b656c32377363616c61725f66726f6d5f63616e6f6e6963616c5f62797465733137683231626133323032643233383433323045eb02475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686538643166363137613534356536633645ec02495f5a4e34345f244c54242452462454247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d743137683263303135353537316533393461333845ed02495f5a4e34345f244c54242452462454247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d743137686436643630343036393461653862316345ee02305f5a4e34636f726533666d743557726974653977726974655f666d743137683731353738323431643336303761393145ef0293015f5a4e34636f72653370747231313264726f705f696e5f706c616365244c5424244c542473657264652e2e64652e2e57697468446563696d616c506f696e74247532302461732475323024636f72652e2e666d742e2e446973706c6179244754242e2e666d742e2e4c6f6f6b466f72446563696d616c506f696e74244754243137683735313030393237663835323937643445f002595f5a4e36305f244c542473657264652e2e64652e2e556e6578706563746564247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d743137683535646662386339623734333434306145f1025f5f5a4e36365f244c542473657264652e2e64652e2e57697468446563696d616c506f696e74247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d743137683965656534616530643961346539336445f2024c5f5a4e34375f244c54242452462473747224753230246173247532302473657264652e2e64652e2e45787065637465642447542433666d743137683133643066303835663963663039313145f302545f5a4e35355f244c542473657264652e2e64652e2e4f6e654f66247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d743137683630656365623964613839656431393045f402a4015f5a4e3132385f244c5424244c542473657264652e2e64652e2e57697468446563696d616c506f696e74247532302461732475323024636f72652e2e666d742e2e446973706c6179244754242e2e666d742e2e4c6f6f6b466f72446563696d616c506f696e74247532302461732475323024636f72652e2e666d742e2e5772697465244754243977726974655f7374723137686639653136666134313235353564636345f502a6015f5a4e3132385f244c5424244c542473657264652e2e64652e2e57697468446563696d616c506f696e74247532302461732475323024636f72652e2e666d742e2e446973706c6179244754242e2e666d742e2e4c6f6f6b466f72446563696d616c506f696e74247532302461732475323024636f72652e2e666d742e2e577269746524475424313077726974655f636861723137686463343231626533393535643266383945f602425f5a4e313073657264655f6a736f6e32646531325061727365724e756d6265723132696e76616c69645f747970653137683736623166383430383066383931663245f702475f5a4e34636f726533707472333764726f705f696e5f706c616365244c5424636f72652e2e666d742e2e4572726f72244754243137686339396332366261663035366662366645f8024c5f5a4e34636f726533707472343264726f705f696e5f706c616365244c5424616c6c6f632e2e737472696e672e2e537472696e67244754243137683761313336376238316230303530613145f902525f5a4e35335f244c5424636f72652e2e666d742e2e4572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686331333433306130306461396533623245fa02575f5a4e35385f244c5424616c6c6f632e2e737472696e672e2e537472696e67247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686435626234303238353735623832616645fb025f5f5a4e35385f244c5424616c6c6f632e2e737472696e672e2e537472696e67247532302461732475323024636f72652e2e666d742e2e577269746524475424313077726974655f636861723137683665623061383439373036393635376445fc025d5f5a4e35385f244c5424616c6c6f632e2e737472696e672e2e537472696e67247532302461732475323024636f72652e2e666d742e2e5772697465244754243977726974655f7374723137683030613666373066376361353163323545fd02325f5a4e313073657264655f6a736f6e356572726f72354572726f7232696f3137683739656331363261323531386161363545fe02605f5a4e36375f244c542473657264655f6a736f6e2e2e6572726f722e2e4572726f72436f6465247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d743137683065666234646363613436386530383245ff025c5f5a4e36335f244c542473657264655f6a736f6e2e2e6572726f722e2e4572726f72247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d74313768316663323462383763363932333434364580035a5f5a4e36315f244c542473657264655f6a736f6e2e2e6572726f722e2e4572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376831346131386137346336366438366530458103775f5a4e36315f244c542473657264655f6a736f6e2e2e6572726f722e2e4572726f7224753230246173247532302473657264652e2e64652e2e4572726f722447542436637573746f6d31376863616237346631363832643338353433452e6c6c766d2e31333431383836383837393433313630393432368203355f5a4e313073657264655f6a736f6e356572726f7231306d616b655f6572726f7231376865313361356437393433623563623636458303645f5a4e36315f244c542473657264655f6a736f6e2e2e6572726f722e2e4572726f7224753230246173247532302473657264652e2e64652e2e4572726f72244754243132696e76616c69645f7479706531376830613931643064626332326365343036458403655f5a4e37325f244c542473657264655f6a736f6e2e2e6572726f722e2e4a736f6e556e6578706563746564247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d7431376838663833663031313161623562383138458503655f5a4e36315f244c542473657264655f6a736f6e2e2e6572726f722e2e4572726f7224753230246173247532302473657264652e2e64652e2e4572726f72244754243133696e76616c69645f76616c756531376861383739623538386666663566323633458603375f5a4e313073657264655f6a736f6e337365723134696e76616c69645f6e756d626572313768646266333563643361333637376237624587035f5f5a4e313073657264655f6a736f6e347265616439536c696365526561643137706f736974696f6e5f6f665f696e64657831376833623736313464303635366238326134452e6c6c766d2e313430393032393737363337313432323534303788035c5f5a4e313073657264655f6a736f6e347265616439536c696365526561643134736b69705f746f5f65736361706531376837393532303930303231376665613639452e6c6c766d2e31343039303239373736333731343232353430378903475f5a4e313073657264655f6a736f6e347265616439536c696365526561643139736b69705f746f5f6573636170655f736c6f7731376865333631346237636530326431633435458a03695f5a4e37305f244c542473657264655f6a736f6e2e2e726561642e2e536c6963655265616424753230246173247532302473657264655f6a736f6e2e2e726561642e2e52656164244754243970617273655f73747231376835346165653164306261646265326437458b03725f5a4e37305f244c542473657264655f6a736f6e2e2e726561642e2e536c6963655265616424753230246173247532302473657264655f6a736f6e2e2e726561642e2e526561642447542431376465636f64655f6865785f65736361706531376830373739613934316163623332653234458c032e5f5a4e313073657264655f6a736f6e3472656164356572726f7231376862666162366537306165643663653863458d03355f5a4e313073657264655f6a736f6e347265616431317065656b5f6f725f656f6631376862393637366362366135633636346663458e036b5f5a4e37305f244c542473657264655f6a736f6e2e2e726561642e2e536c6963655265616424753230246173247532302473657264655f6a736f6e2e2e726561642e2e5265616424475424313069676e6f72655f73747231376861336661396633653430356665636335458f034c5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376866626563383933396537346633386362452e6c6c766d2e313030343030323937363239343334383732393390034c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f7075736831376831653066383863363731616361643662459103595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c6531376866376131666235343636396338356430459203305f5a4e34636f726533666d743557726974653977726974655f666d74313768643761313936356633656162333834644593034c5f5a4e34636f726533707472343264726f705f696e5f706c616365244c5424616c6c6f632e2e737472696e672e2e537472696e6724475424313768376131333637623831623030353061314594035f5f5a4e35385f244c5424616c6c6f632e2e737472696e672e2e537472696e67247532302461732475323024636f72652e2e666d742e2e577269746524475424313077726974655f63686172313768366562306138343937303639363537644595035d5f5a4e35385f244c5424616c6c6f632e2e737472696e672e2e537472696e67247532302461732475323024636f72652e2e666d742e2e5772697465244754243977726974655f73747231376830306136663730663763613531633235459603495f5a4e34345f244c54242452462454247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d7431376837663239616336653031666334353965459703495f5a4e34345f244c54242452462454247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d74313768666639623865323262363462373032324598035e5f5a4e36355f244c542473657264655f6a736f6e2e2e696f2e2e696d702e2e4572726f72247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d7431376862363139313461336363323963613730459903ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f6974657231376863373665373631353137653762663265459a03a6015f5a4e323173705f6170706c69636174696f6e5f63727970746f377372323535313933617070315f39345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f6170706c69636174696f6e5f63727970746f2e2e737232353531392e2e6170702e2e5075626c69632447542439747970655f696e666f31376837303664626431386233343538326432459b03a9015f5a4e323173705f6170706c69636174696f6e5f63727970746f377372323535313933617070315f39375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f6170706c69636174696f6e5f63727970746f2e2e737232353531392e2e6170702e2e5369676e61747572652447542439747970655f696e666f31376866326431653963646632386339303566459c034c5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376838303362643764616634353632636234452e6c6c766d2e31373439383834333437363732353639343532399d034c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f7075736831376837363234626230303465353236643366459e03595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c6531376835383539313937343665393331663663459f03a2015f5a4e323173705f6170706c69636174696f6e5f63727970746f35656364736133617070315f39325f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f6170706c69636174696f6e5f63727970746f2e2e65636473612e2e6170702e2e5075626c69632447542439747970655f696e666f3137686433366365323132363032633732396545a003a5015f5a4e323173705f6170706c69636174696f6e5f63727970746f35656364736133617070315f39355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f6170706c69636174696f6e5f63727970746f2e2e65636473612e2e6170702e2e5369676e61747572652447542439747970655f696e666f3137683839623433643931646431366639353545a103a6015f5a4e323173705f6170706c69636174696f6e5f63727970746f376564323535313933617070315f39345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f6170706c69636174696f6e5f63727970746f2e2e656432353531392e2e6170702e2e5075626c69632447542439747970655f696e666f3137683134613730393530386335343432366545a203a9015f5a4e323173705f6170706c69636174696f6e5f63727970746f376564323535313933617070315f39375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f6170706c69636174696f6e5f63727970746f2e2e656432353531392e2e6170702e2e5369676e61747572652447542439747970655f696e666f3137683737393332393236363038623561656345a3037b5f5a4e38385f244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432454244754242475323024617324753230247363616c655f696e666f2e2e54797065496e666f2447542439747970655f696e666f3137683434393932363236393530636130366245a4037b5f5a4e38385f244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432454244754242475323024617324753230247363616c655f696e666f2e2e54797065496e666f2447542439747970655f696e666f3137683438666664323862306638633837656145a5037b5f5a4e38385f244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432454244754242475323024617324753230247363616c655f696e666f2e2e54797065496e666f2447542439747970655f696e666f3137683537643438323638663839646562356545a6037b5f5a4e38385f244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432454244754242475323024617324753230247363616c655f696e666f2e2e54797065496e666f2447542439747970655f696e666f3137683939363631636239303364663663643145a70385015f5a4e313373705f61726974686d65746963315f38315f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f61726974686d657469632e2e41726974686d657469634572726f722447542439747970655f696e666f3137683165633739313933353365383535336445a803ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137683031396664613763616466366136326145a903ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137683131613736386137373564353335633245aa03ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137683834633634656134623662343136633145ab034c5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376833303065316536323263386334333066452e6c6c766d2e3136313430383732343135383835373835373838ac034c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137683232613634316461313338316135306345ad034c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137683834373531646437643365393239613845ae03595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683036626233323163356536343439356245af03595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137686537373636396631313538333935316645b003595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137686665316264346630623264393134346645b10395015f5a4e313373705f61726974686d6574696331307065725f7468696e6773315f38355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f61726974686d657469632e2e7065725f7468696e67732e2e50657262696c6c2447542439747970655f696e666f3137683564633862343136306363373832636245b203ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137683334636131333136653736393463306145b303ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137683636613234623730646533353633313845b403af015f5a4e313773705f636f6e73656e7375735f61757261377372323535313931316170705f73723235353139315f39385f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f6e73656e7375735f617572612e2e737232353531392e2e6170705f737232353531392e2e5075626c69632447542439747970655f696e666f3137686132356530323263373163313663613845b5034b5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376834646539666336353665663230333532452e6c6c766d2e35363434383134383035313531343631323136b6034c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137683331306364326261306435643731616245b703595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683038656230313236643736313431666445b803595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683839306237383938396432616238353445b9037b5f5a4e38385f244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432454244754242475323024617324753230247363616c655f696e666f2e2e54797065496e666f2447542439747970655f696e666f3137683030303139613435616466333432306545ba034a5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376830353866643961363931663865663530452e6c6c766d2e373639353136303936333334333635353838bb034c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137683065633136343536373565636138633945bc034c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137686330343564326339373839343337363245bd03595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683731626461626234363634616161323745be03595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137686534343135646637373265663133656345bf03595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137686539363639643230303534353535383145c00380015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137686239383864326263313435373163346145c10380015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137686534646537373138626665643962343845c203ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137683134613131396537356531333937343645c303ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137683536333139376135656565636339343645c403ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137686637663366353635303133353031653345c503ac015f5a4e35616c6c6f63337665633136696e5f706c6163655f636f6c6c6563743130385f244c5424696d706c2475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c54245424432449244754242475323024666f722475323024616c6c6f632e2e7665632e2e566563244c54245424475424244754243966726f6d5f697465723137686565653039623565643236323861303045c6038f015f5a4e313773705f636f6e73656e7375735f62616265315f38375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f6e73656e7375735f626162652e2e42616265436f6e66696775726174696f6e2447542439747970655f696e666f3137683133303039336163653864383735316545c7038a015f5a4e313773705f636f6e73656e7375735f62616265315f38325f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f6e73656e7375735f626162652e2e416c6c6f776564536c6f74732447542439747970655f696e666f3137686238653764313765363635353332636645c80394015f5a4e313773705f636f6e73656e7375735f62616265315f39325f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f6e73656e7375735f626162652e2e4261626545706f6368436f6e66696775726174696f6e2447542439747970655f696e666f3137686235313062306430343536653134356645c90395015f5a4e313773705f636f6e73656e7375735f62616265315f39335f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f6e73656e7375735f626162652e2e4f70617175654b65794f776e65727368697050726f6f662447542439747970655f696e666f3137683233383430656335653734376364613145ca0383015f5a4e313773705f636f6e73656e7375735f62616265315f37355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f6e73656e7375735f626162652e2e45706f63682447542439747970655f696e666f3137683233656166383833373030393964633445cb03755f5a4e31307363616c655f696e666f35696d706c7336345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024244c50244124432442245250242447542439747970655f696e666f3137683135303065376633396238373134333145cc038d015f5a4e313773705f636f6e73656e7375735f6261626533617070315f38315f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f6e73656e7375735f626162652e2e6170702e2e5075626c69632447542439747970655f696e666f3137686230613764623135343632616538623645cd03755f5a4e31307363616c655f696e666f35696d706c7336345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024244c50244124432442245250242447542439747970655f696e666f3137683562323039393237313537313338303845ce037e5f5a4e31307363616c655f696e666f35696d706c7337335f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024247535622454247533622424753230244e24753564242447542439747970655f696e666f3137686461326637613037306666366539353845cf039f015f5a4e313773705f636f6e73656e7375735f626162653764696765737473315f39355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f6e73656e7375735f626162652e2e646967657374732e2e5072696d6172795072654469676573742447542439747970655f696e666f3137683864316135343232636665636263393145d003a7015f5a4e313773705f636f6e73656e7375735f626162653764696765737473315f3130325f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f6e73656e7375735f626162652e2e646967657374732e2e5365636f6e64617279506c61696e5072654469676573742447542439747970655f696e666f3137683431366134656236626331396536333245d103a5015f5a4e313773705f636f6e73656e7375735f626162653764696765737473315f3130305f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f6e73656e7375735f626162652e2e646967657374732e2e5365636f6e646172795652465072654469676573742447542439747970655f696e666f3137683538303435656338663162346665356345d20398015f5a4e313773705f636f6e73656e7375735f626162653764696765737473315f38385f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f6e73656e7375735f626162652e2e646967657374732e2e5072654469676573742447542439747970655f696e666f3137683630316564356639306339666165633145d303a3015f5a4e313773705f636f6e73656e7375735f626162653764696765737473315f39395f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f6e73656e7375735f626162652e2e646967657374732e2e4e657874436f6e66696744657363726970746f722447542439747970655f696e666f3137683064643965323734643561383565373345d403445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683162346266356466666437326436316445d503445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683964333231303561393462383030393445d603445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686330616161613965623834656532393345d703445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686462373064346162653466383735326445d8037b5f5a4e38385f244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432454244754242475323024617324753230247363616c655f696e666f2e2e54797065496e666f2447542439747970655f696e666f3137683339663139383531623739626436613545d9037b5f5a4e38385f244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432454244754242475323024617324753230247363616c655f696e666f2e2e54797065496e666f2447542439747970655f696e666f3137683765316430623430613062393563613945da037b5f5a4e38385f244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432454244754242475323024617324753230247363616c655f696e666f2e2e54797065496e666f2447542439747970655f696e666f3137686131373465393562333964376464643745db034b5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376838656538313264663439373636346330452e6c6c766d2e37353435323632393235353937383930363436dc034c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137686131336535626165396639313136636245dd0393015f5a4e323073705f636f6e73656e7375735f6772616e64706133617070315f38345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f6e73656e7375735f6772616e6470612e2e6170702e2e5075626c69632447542439747970655f696e666f3137683834626335663166633962313461333545de0396015f5a4e323073705f636f6e73656e7375735f6772616e64706133617070315f38375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f6e73656e7375735f6772616e6470612e2e6170702e2e5369676e61747572652447542439747970655f696e666f3137686338383834663633386564643536353745df0384015f5a4e313873705f636f6e73656e7375735f736c6f7473315f37355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f6e73656e7375735f736c6f74732e2e536c6f742447542439747970655f696e666f3137686438396633373730363133323364356645e0038c015f5a4e313873705f636f6e73656e7375735f736c6f7473315f38335f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f6e73656e7375735f736c6f74732e2e536c6f744475726174696f6e2447542439747970655f696e666f3137683033313030636665356130646130633645e103325f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f773137683464336263376134326237643032353545e2034c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137683663623963646462336162366264383345e3034c5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376864396563376434376531623537656634452e6c6c766d2e3138333531353337343636303635373439303230e4034c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137683034396439386334363466613161343545e503595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683536306633613466623834303265336445e603595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683631356366383630613461313935616345e703595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137686363323065333331323561633264663645e8032f5f5a4e3773705f636f72653663727970746f3873733538686173683137683238663732393033333736326233623145e90381015f5a4e3773705f636f72653663727970746f315f37375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f72652e2e63727970746f2e2e4b65795479706549642447542439747970655f696e666f3137683238326237386366323163366636626245ea037e5f5a4e31307363616c655f696e666f35696d706c7337335f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024247535622454247533622424753230244e24753564242447542439747970655f696e666f3137683539373733366138633763383264383245eb03775f5a4e3773705f636f7265315f37345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f72652e2e4f70617175654d657461646174612447542439747970655f696e666f3137686666386331393336303266393331626545ec036d5f5a4e3773705f636f7265315f36345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f72652e2e566f69642447542439747970655f696e666f3137686562363633306436313935373263623945ed038c015f5a4e3130345f244c54247061726974795f7363616c655f636f6465632e2e636f6d706163742e2e436f6d70616374526566244c5424753332244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542439656e636f64655f746f3137686138636538626637613932616432303745ee036f5f5a4e37365f244c542473705f636f72652e2e737232353531392e2e7672662e2e5672665072654f75747075742475323024617324753230247363616c655f696e666f2e2e54797065496e666f2447542439747970655f696e666f3137683330393231376461393531323365383745ef036b5f5a4e37325f244c542473705f636f72652e2e737232353531392e2e7672662e2e56726650726f6f662475323024617324753230247363616c655f696e666f2e2e54797065496e666f2447542439747970655f696e666f3137686462376161383863653335323836666245f0038f015f5a4e3773705f636f7265377372323535313933767266315f38365f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f72652e2e737232353531392e2e7672662e2e5672665369676e61747572652447542439747970655f696e666f3137683731626661633661363630366337393845f1033f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f64653137686635303235633330613364653762386145f20380015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137683038383839333532653864656537633845f303ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137683434333763636231323833393330353645f403ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137683631636138316334326465613433393745f503ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137686638626564613134626663393033626145f603735f5a4e31307363616c655f696e666f35696d706c7336325f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302424753562245424753564242447542439747970655f696e666f3137686233633762363061653337613236623445f703755f5a4e31307363616c655f696e666f35696d706c7336345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024244c50244124432442245250242447542439747970655f696e666f3137683165626536363035343934616533323545f80380015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137683362376336643634313061353731613545f9039e015f5a4e31307363616c655f696e666f35696d706c733130345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e42547265654d6170244c54244b24432456244754242447542439747970655f696e666f3137686466623936623836623632363963393145fa037e5f5a4e31307363616c655f696e666f35696d706c7337335f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024247535622454247533622424753230244e24753564242447542439747970655f696e666f3137683330383333656637343465323132376145fb0380015f5a4e313273705f696e686572656e7473315f37375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f696e686572656e74732e2e496e686572656e74446174612447542439747970655f696e666f3137683163616437323962343236333439656445fc0388015f5a4e313273705f696e686572656e7473315f38355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f696e686572656e74732e2e436865636b496e686572656e7473526573756c742447542439747970655f696e666f3137686132313236633930353262626638633745fd034b5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376835393161623434303232623334316461452e6c6c766d2e34383433383033393637313038353834313131fe034c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137686235343063316530346631383764636345ff03465f5a4e31387061726974795f7363616c655f636f64656335636f64656331396465636f64655f7665635f776974685f6c656e31376836306666356365653137313431633963458004465f5a4e31387061726974795f7363616c655f636f64656335636f64656331396465636f64655f7665635f776974685f6c656e31376838663732633037343362303133386130458104465f5a4e31387061726974795f7363616c655f636f64656335636f64656331396465636f64655f7665635f776974685f6c656e31376866393836343039356430613034653063458204325f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f77313768343263353138373437363962376235394583044c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f70757368313768303435613061343463633239383838344584044c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f7075736831376832653166356261623839333864626662458504a4015f5a4e323073705f72756e74696d655f696e7465726661636535696d706c7339355f244c5424696d706c247532302473705f72756e74696d655f696e746572666163652e2e7761736d2e2e46726f6d46464956616c75652475323024666f722475323024616c6c6f632e2e7665632e2e566563244c5424542447542424475424313466726f6d5f6666695f76616c756531376831366666613936363234353661343866458604a4015f5a4e323073705f72756e74696d655f696e7465726661636535696d706c7339355f244c5424696d706c247532302473705f72756e74696d655f696e746572666163652e2e7761736d2e2e46726f6d46464956616c75652475323024666f722475323024616c6c6f632e2e7665632e2e566563244c5424542447542424475424313466726f6d5f6666695f76616c756531376834643265323865373339313062663361458704a4015f5a4e323073705f72756e74696d655f696e7465726661636535696d706c7339355f244c5424696d706c247532302473705f72756e74696d655f696e746572666163652e2e7761736d2e2e46726f6d46464956616c75652475323024666f722475323024616c6c6f632e2e7665632e2e566563244c5424542447542424475424313466726f6d5f6666695f76616c756531376837356436356566663239343833643631458804a4015f5a4e323073705f72756e74696d655f696e7465726661636535696d706c7339355f244c5424696d706c247532302473705f72756e74696d655f696e746572666163652e2e7761736d2e2e496e746f46464956616c75652475323024666f722475323024616c6c6f632e2e7665632e2e566563244c54245424475424244754243134696e746f5f6666695f76616c756531376838343361646339303639343433633366458904715f5a4e34636f726533707472353364726f705f696e5f706c616365244c54247061726974795f7363616c655f636f6465632e2e6572726f722e2e4572726f722447542431376866666232363230313462646130643736452e6c6c766d2e31323633373838373031343536303132353636358a047c5f5a4e36395f244c54247061726974795f7363616c655f636f6465632e2e6572726f722e2e4572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376863636562313832636338343631643463452e6c6c766d2e31323633373838373031343536303132353636358b04625f5a4e34345f244c54242452462454247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d7431376839633739396534343437343337346537452e6c6c766d2e333033343630303939323437323131313739338c04635f5a4e34355f244c5424244c502424525024247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376834303566303661613534323663666363452e6c6c766d2e333033343630303939323437323131313739338d04585f5a4e34636f726533707472323964726f705f696e5f706c616365244c5424244c5024245250242447542431376834396133376432383766346563623464452e6c6c766d2e333033343630303939323437323131313739338e04415f5a4e35616c6c6f6333666d7436666f726d617431376838346335363334623861393861353135452e6c6c766d2e333033343630303939323437323131313739338f04495f5a4e35627974657335627974657331317374617469635f64726f7031376864643031336537396536363530303731452e6c6c766d2e3330333436303039393234373231313137393390044a5f5a4e35627974657335627974657331327374617469635f636c6f6e6531376833323130386566643438323766363666452e6c6c766d2e3330333436303039393234373231313137393391044e5f5a4e35627974657335627974657331367374617469635f69735f756e6971756531376836633034666662366437323062666139452e6c6c766d2e3330333436303039393234373231313137393392047b5f5a4e36395f244c54247061726974795f7363616c655f636f6465632e2e6572726f722e2e4572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376863636562313832636338343631643463452e6c6c766d2e33303334363030393932343732313131373933930411727573745f626567696e5f756e77696e64940480015f5a4e3573705f696f315f38385f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f64652475323024666f72247532302473705f696f2e2e4b696c6c53746f72616765526573756c7424475424366465636f646531376836373232303238373163626666343261459504485f5a4e3573705f696f3773746f72616765323665787465726e5f686f73745f66756e6374696f6e5f696d706c7336617070656e6431376837656638376163633731303638616436459604475f5a4e3573705f696f3773746f72616765323665787465726e5f686f73745f66756e6374696f6e5f696d706c7335636c656172313768666135643861313862363730623336664597044f5f5a4e3573705f696f3773746f72616765323665787465726e5f686f73745f66756e6374696f6e5f696d706c733132636c6561725f70726566697831376837346164333366346133616366336662459804555f5a4e3573705f696f3773746f72616765323665787465726e5f686f73745f66756e6374696f6e5f696d706c733138636f6d6d69745f7472616e73616374696f6e31376832613739373661363561346634326539459904455f5a4e3573705f696f3773746f72616765323665787465726e5f686f73745f66756e6374696f6e5f696d706c733367657431376830643334386165303737646161623266459a044a5f5a4e3573705f696f3773746f72616765323665787465726e5f686f73745f66756e6374696f6e5f696d706c73386e6578745f6b657931376832313061623939663834653434353262459b04465f5a4e3573705f696f3773746f72616765323665787465726e5f686f73745f66756e6374696f6e5f696d706c73347265616431376839373039333561363633396438653766459c04575f5a4e3573705f696f3773746f72616765323665787465726e5f686f73745f66756e6374696f6e5f696d706c733230726f6c6c6261636b5f7472616e73616374696f6e31376862363132613934643264623564396632459d04465f5a4e3573705f696f3773746f72616765323665787465726e5f686f73745f66756e6374696f6e5f696d706c7334726f6f7431376835383939313164383561653631393035459e04455f5a4e3573705f696f3773746f72616765323665787465726e5f686f73745f66756e6374696f6e5f696d706c733373657431376838656233646237653834376262343737459f04545f5a4e3573705f696f3773746f72616765323665787465726e5f686f73745f66756e6374696f6e5f696d706c73313773746172745f7472616e73616374696f6e3137683165303531396566346636376130613845a0044d5f5a4e3573705f696f3768617368696e67323665787465726e5f686f73745f66756e6374696f6e5f696d706c733130626c616b65325f3132383137683361356361313931653563623962626645a1044d5f5a4e3573705f696f3768617368696e67323665787465726e5f686f73745f66756e6374696f6e5f696d706c733130626c616b65325f3235363137683161656336373863373636643165386545a2044a5f5a4e3573705f696f3768617368696e67323665787465726e5f686f73745f66756e6374696f6e5f696d706c733874776f785f3132383137686363383239356438653834663133646345a304495f5a4e3573705f696f3768617368696e67323665787465726e5f686f73745f66756e6374696f6e5f696d706c733774776f785f36343137686333646631316530373466653466366645a4044f5f5a4e3573705f696f31346f6666636861696e5f696e646578323665787465726e5f686f73745f66756e6374696f6e5f696d706c7335636c6561723137683531376237383864333164323830646445a5044d5f5a4e3573705f696f31346f6666636861696e5f696e646578323665787465726e5f686f73745f66756e6374696f6e5f696d706c73337365743137683130326561633064623336616530613445a604505f5a4e3573705f696f3663727970746f323665787465726e5f686f73745f66756e6374696f6e5f696d706c73313465636473615f67656e65726174653137686138323633393737323633616333316645a704535f5a4e3573705f696f3663727970746f323665787465726e5f686f73745f66756e6374696f6e5f696d706c73313765636473615f7075626c69635f6b6579733137683330623335653238356334363834663745a8044c5f5a4e3573705f696f3663727970746f323665787465726e5f686f73745f66756e6374696f6e5f696d706c73313065636473615f7369676e3137683238363963333661363234393537653245a9044e5f5a4e3573705f696f3663727970746f323665787465726e5f686f73745f66756e6374696f6e5f696d706c73313265636473615f7665726966793137683761633166346166333136616537323445aa04525f5a4e3573705f696f3663727970746f323665787465726e5f686f73745f66756e6374696f6e5f696d706c733136656432353531395f67656e65726174653137686561613135616130333439333934643845ab04555f5a4e3573705f696f3663727970746f323665787465726e5f686f73745f66756e6374696f6e5f696d706c733139656432353531395f7075626c69635f6b6579733137683266653032653161656164666332353645ac044e5f5a4e3573705f696f3663727970746f323665787465726e5f686f73745f66756e6374696f6e5f696d706c733132656432353531395f7369676e3137686534306433623164363061646539623445ad04505f5a4e3573705f696f3663727970746f323665787465726e5f686f73745f66756e6374696f6e5f696d706c733134656432353531395f7665726966793137686331303430653166613136353763366445ae04525f5a4e3573705f696f3663727970746f323665787465726e5f686f73745f66756e6374696f6e5f696d706c733136737232353531395f67656e65726174653137686633363835346633363931326139623545af04555f5a4e3573705f696f3663727970746f323665787465726e5f686f73745f66756e6374696f6e5f696d706c733139737232353531395f7075626c69635f6b6579733137683032626534646434303761346632343545b0044e5f5a4e3573705f696f3663727970746f323665787465726e5f686f73745f66756e6374696f6e5f696d706c733132737232353531395f7369676e3137683765333432313835613237363664663445b104505f5a4e3573705f696f3663727970746f323665787465726e5f686f73745f66756e6374696f6e5f696d706c733134737232353531395f7665726966793137686561346235363063623362346136323545b204565f5a4e3573705f696f386f6666636861696e323665787465726e5f686f73745f66756e6374696f6e5f696d706c7331387375626d69745f7472616e73616374696f6e3137686235333139653432336536323431636345b30486015f5a4e3130315f244c54247061726974795f7363616c655f636f6465632e2e636f6d706163742e2e436f6d70616374244c5424753332244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f646524475424366465636f64653137683330383434316330633564633035646245b40485015f5a4e3130325f244c54247061726974795f7363616c655f636f6465632e2e636f6d706163742e2e507265666978496e707574244c542454244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e496e7075742447542434726561643137686363393731323631663966623861386145b5048c015f5a4e3130345f244c54247061726974795f7363616c655f636f6465632e2e636f6d706163742e2e436f6d70616374526566244c5424753332244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542439656e636f64655f746f3137686461333636383235366232303338373445b604525f5a4e3573705f696f31377472616e73616374696f6e5f696e646578323665787465726e5f686f73745f66756e6374696f6e5f696d706c7335696e6465783137683237356565323738356263626662366145b704455f5a4e3573705f696f376c6f6767696e67323665787465726e5f686f73745f66756e6374696f6e5f696d706c73336c6f673137683530363462323831636535306338626245b8044b5f5a4e3573705f696f376c6f6767696e67323665787465726e5f686f73745f66756e6374696f6e5f696d706c73396d61785f6c6576656c3137683039323133633762323931343533363745b9043f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f64653137683736323532346232643062373662346145ba04735f5a4e38335f244c5424636f72652e2e6f7074696f6e2e2e4f7074696f6e244c542454244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f646524475424366465636f64653137683035326462633961363633636161653145bb04735f5a4e38335f244c5424636f72652e2e6f7074696f6e2e2e4f7074696f6e244c542454244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f646524475424366465636f64653137683434306165353537613438653862383345bc04735f5a4e38335f244c5424636f72652e2e6f7074696f6e2e2e4f7074696f6e244c542454244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f646524475424366465636f64653137683734303966313861626165383464323245bd04735f5a4e38335f244c5424636f72652e2e6f7074696f6e2e2e4f7074696f6e244c542454244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f646524475424366465636f64653137686435653566336132323136383164643345be04485f5a4e3573705f696f39616c6c6f6361746f72323665787465726e5f686f73745f66756e6374696f6e5f696d706c7334667265653137683462313034643330313832316462623545bf044a5f5a4e3573705f696f39616c6c6f6361746f72323665787465726e5f686f73745f66756e6374696f6e5f696d706c73366d616c6c6f633137683666313530336666343237336661656545c004555f5a4e3573705f696f323164656661756c745f6368696c645f73746f72616765323665787465726e5f686f73745f66756e6374696f6e5f696d706c7334726561643137683439393566306462633964306430616445c104545f5a4e3573705f696f323164656661756c745f6368696c645f73746f72616765323665787465726e5f686f73745f66756e6374696f6e5f696d706c73337365743137683362383564346135336134336334303945c204575f5a4e3573705f696f3474726965323665787465726e5f686f73745f66756e6374696f6e5f696d706c733233626c616b65325f3235365f6f7264657265645f726f6f743137686333303664626430363134643032366645c304485f5a4e3573705f696f346d697363323665787465726e5f686f73745f66756e6374696f6e5f696d706c73397072696e745f6865783137683336336330313365373139373831333745c4044a5f5a4e3573705f696f346d697363323665787465726e5f686f73745f66756e6374696f6e5f696d706c7331307072696e745f757466383137683537646631656164326338316661373345c5044f5f5a4e3573705f696f346d697363323665787465726e5f686f73745f66756e6374696f6e5f696d706c73313572756e74696d655f76657273696f6e3137686165636232366331386530636531333945c604ac015f5a4e35616c6c6f63337665633136696e5f706c6163655f636f6c6c6563743130385f244c5424696d706c2475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c54245424432449244754242475323024666f722475323024616c6c6f632e2e7665632e2e566563244c54245424475424244754243966726f6d5f697465723137683833376166333633613931373333313045c704ac015f5a4e35616c6c6f63337665633136696e5f706c6163655f636f6c6c6563743130385f244c5424696d706c2475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c54245424432449244754242475323024666f722475323024616c6c6f632e2e7665632e2e566563244c54245424475424244754243966726f6d5f697465723137686538646661303830643464363865656545c804ac015f5a4e35616c6c6f63337665633136696e5f706c6163655f636f6c6c6563743130385f244c5424696d706c2475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c54245424432449244754242475323024666f722475323024616c6c6f632e2e7665632e2e566563244c54245424475424244754243966726f6d5f697465723137686632643232323238336133313534656145c904ac015f5a4e35616c6c6f63337665633136696e5f706c6163655f636f6c6c6563743130385f244c5424696d706c2475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c54245424432449244754242475323024666f722475323024616c6c6f632e2e7665632e2e566563244c54245424475424244754243966726f6d5f697465723137686633666162393231656261653934346245ca04645f5a4e37305f244c5424616c6c6f632e2e7665632e2e566563244c5424542443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137683535376230353166643836343730386545cb04645f5a4e35616c6c6f633376656339696e746f5f697465723231496e746f49746572244c54245424432441244754243332666f726765745f616c6c6f636174696f6e5f64726f705f72656d61696e696e673137686338383365666364366162383666666645cc04745f5a4e38365f244c5424616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137683265356239323239646535393731616645cd04b7015f5a4e313473705f6d657461646174615f6972337631353133325f244c5424696d706c2475323024636f72652e2e636f6e766572742e2e46726f6d244c542473705f6d657461646174615f69722e2e74797065732e2e50616c6c65744d657461646174614952244754242475323024666f7224753230246672616d655f6d657461646174612e2e7631352e2e50616c6c65744d65746164617461244754243466726f6d3137686435623565326163663831396134656145ce04355f5a4e313473705f6d657461646174615f69723132696e746f5f76657273696f6e3137683530333863323061393035333164303345cf04b5015f5a4e313473705f6d657461646174615f6972337631343133305f244c5424696d706c2475323024636f72652e2e636f6e766572742e2e46726f6d244c542473705f6d657461646174615f69722e2e74797065732e2e4d657461646174614952244754242475323024666f7224753230246672616d655f6d657461646174612e2e7631342e2e52756e74696d654d65746164617461563134244754243466726f6d3137683139633931353936376261396537646445d004b7015f5a4e313473705f6d657461646174615f6972337631343133325f244c5424696d706c2475323024636f72652e2e636f6e766572742e2e46726f6d244c542473705f6d657461646174615f69722e2e74797065732e2e50616c6c65744d657461646174614952244754242475323024666f7224753230246672616d655f6d657461646174612e2e7631342e2e50616c6c65744d65746164617461244754243466726f6d3137683235643161303161373464633364376545d104c3015f5a4e313473705f6d657461646174615f6972337631343134345f244c5424696d706c2475323024636f72652e2e636f6e766572742e2e46726f6d244c542473705f6d657461646174615f69722e2e74797065732e2e53746f72616765456e7472794d657461646174614952244754242475323024666f7224753230246672616d655f6d657461646174612e2e7631342e2e53746f72616765456e7472794d65746164617461244754243466726f6d3137683665393739663030336133623038353245d204445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683035393961616461346535326437663845d304445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683062663263656631383766663830633645d404445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683138353132653333343430333030653045d504445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683333366537346564623830303865303245d604445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683533313530336365626338303836663345d704445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683635313738316139336339336634353945d804445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683765346636353631653535643638366545d904445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683765633739663066323433663237656345da04445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686339306638353136613862333939366545db04445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686438626361363832393365366333633945dc04445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686466653838373065376131303564653445dd04445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686563623833376463663535396361633745de044b5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376861663733353962356437623435323839452e6c6c766d2e34333231353138303532333134313138383432df044c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137683162623765623034376138316563643845e0044c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137683837623334663636646631336262613945e1044c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137686532323132633735613132313133353545e204595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683130343866396235333133393238653045e304595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683732653938653237396332383863636445e404595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683763613137613266353966333330393145e504595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137686637366361333633666662336364303445e6043f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f64653137686430623530613164316662636439366545e70480015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137683963343130303562646137393163663245e80480015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137686434663738393338366431316435663145e90480015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137686666646231383766386365336539666645ea04ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137683762313739636335376661336662646445eb04ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137686132376664646630313937323438346245ec04ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137686135353530333538646261623334343645ed0480015f5a4e39365f244c542473705f72756e74696d652e2e67656e657269632e2e6469676573742e2e4469676573744974656d5265662475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542436656e636f64653137683232366335316666316535343838633045ee04735f5a4e38305f244c542473705f72756e74696d652e2e67656e657269632e2e6469676573742e2e4469676573744974656d2475323024617324753230247363616c655f696e666f2e2e54797065496e666f2447542439747970655f696e666f3137686337653238613663633730346662396145ef0480015f5a4e39305f244c542473705f72756e74696d652e2e67656e657269632e2e6469676573742e2e4469676573744974656d24753230246173247532302473705f72756e74696d652e2e7472616974732e2e436865636b457175616c244754243131636865636b5f657175616c3137686636313865623538613532373037323145f00496015f5a4e313073705f72756e74696d653767656e6572696336646967657374315f38365f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f72756e74696d652e2e67656e657269632e2e6469676573742e2e4469676573742447542439747970655f696e666f3137686664613539666339343334386235633445f1047e5f5a4e31307363616c655f696e666f35696d706c7337335f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024247535622454247533622424753230244e24753564242447542439747970655f696e666f3137683465336538303364333632356639363845f204495f5a4e34345f244c54242452462454247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d743137683062316134646338383337653665333645f304325f5a4e34636f726533666d74355772697465313077726974655f636861723137686139333364376565343564306537363145f404305f5a4e34636f726533666d743557726974653977726974655f666d743137686635363931643462346464346563383645f504455f5a4e34636f726533707472333564726f705f696e5f706c616365244c542473705f7374642e2e577269746572244754243137683833376161323330313165393934653945f604795f5a4e34636f726533707472363264726f705f696e5f706c616365244c542473705f72756e74696d652e2e72756e74696d655f6c6f676765722e2e52756e74696d654c6f676765722447542431376865373335343064313163313234303131452e6c6c766d2e35373635393736363831363435383336383537f70480015f5a4e37305f244c542473705f72756e74696d652e2e72756e74696d655f6c6f676765722e2e52756e74696d654c6f676765722475323024617324753230246c6f672e2e4c6f672447542437656e61626c656431376834313132633135656262343364636134452e6c6c766d2e35373635393736363831363435383336383537f804635f5a4e37305f244c542473705f72756e74696d652e2e72756e74696d655f6c6f676765722e2e52756e74696d654c6f676765722475323024617324753230246c6f672e2e4c6f6724475424336c6f673137686631323665323333336165316132396545f9047e5f5a4e37305f244c542473705f72756e74696d652e2e72756e74696d655f6c6f676765722e2e52756e74696d654c6f676765722475323024617324753230246c6f672e2e4c6f672447542435666c75736831376862656333666262366235663265646233452e6c6c766d2e35373635393736363831363435383336383537fa04755f5a4e38325f244c542473705f72756e74696d652e2e72756e74696d655f737472696e672e2e52756e74696d65537472696e672475323024617324753230247363616c655f696e666f2e2e54797065496e666f2447542439747970655f696e666f3137686562633832343165323336326264373145fb048c015f5a4e3130345f244c54247061726974795f7363616c655f636f6465632e2e636f6d706163742e2e436f6d70616374526566244c5424753332244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542439656e636f64655f746f3137683436326130393931646164633165656445fc04bc015f5a4e313073705f72756e74696d6532307472616e73616374696f6e5f76616c69646974793132335f244c5424696d706c2475323024636f72652e2e636f6e766572742e2e46726f6d244c542473705f72756e74696d652e2e7472616e73616374696f6e5f76616c69646974792e2e5472616e73616374696f6e56616c69646974794572726f72244754242475323024666f72247532302424524624737472244754243466726f6d3137683532356261386464636366316662323245fd04595f5a4e313073705f72756e74696d6532307472616e73616374696f6e5f76616c6964697479313656616c69645472616e73616374696f6e3132636f6d62696e655f776974683137686233656130333266636134636436363945fe04af015f5a4e313073705f72756e74696d6532307472616e73616374696f6e5f76616c6964697479315f3130335f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f72756e74696d652e2e7472616e73616374696f6e5f76616c69646974792e2e496e76616c69645472616e73616374696f6e2447542439747970655f696e666f3137683461343164633436303933623039343345ff04af015f5a4e313073705f72756e74696d6532307472616e73616374696f6e5f76616c6964697479315f3130335f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f72756e74696d652e2e7472616e73616374696f6e5f76616c69646974792e2e556e6b6e6f776e5472616e73616374696f6e2447542439747970655f696e666f31376837316664613035633163376365386433458005b5015f5a4e313073705f72756e74696d6532307472616e73616374696f6e5f76616c6964697479315f3130395f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f72756e74696d652e2e7472616e73616374696f6e5f76616c69646974792e2e5472616e73616374696f6e56616c69646974794572726f722447542439747970655f696e666f31376866313332313565646631353639333066458105ae015f5a4e313073705f72756e74696d6532307472616e73616374696f6e5f76616c6964697479315f3130325f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f72756e74696d652e2e7472616e73616374696f6e5f76616c69646974792e2e5472616e73616374696f6e536f757263652447542439747970655f696e666f31376861323132383937646166376266363464458205ad015f5a4e313073705f72756e74696d6532307472616e73616374696f6e5f76616c6964697479315f3130315f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f72756e74696d652e2e7472616e73616374696f6e5f76616c69646974792e2e56616c69645472616e73616374696f6e2447542439747970655f696e666f313768346135333331333032613731346464374583057b5f5a4e313073705f72756e74696d65315f37345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f72756e74696d652e2e4d6f64756c654572726f722447542439747970655f696e666f3137686633356435363866663538633436626545840582015f5a4e313073705f72756e74696d65315f38315f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f72756e74696d652e2e5472616e73616374696f6e616c4572726f722447542439747970655f696e666f313768626233306636643963613232396436614585057d5f5a4e313073705f72756e74696d65315f37365f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f72756e74696d652e2e44697370617463684572726f722447542439747970655f696e666f313768326539636666636439663338356531394586057a5f5a4e313073705f72756e74696d65315f37335f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f72756e74696d652e2e546f6b656e4572726f722447542439747970655f696e666f3137686638633139353666613738383566646445870586015f5a4e313073705f72756e74696d65315f38355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f72756e74696d652e2e45787472696e736963496e636c7573696f6e4d6f64652447542439747970655f696e666f313768613062393265373430613039626461624588057b5f5a4e313073705f72756e74696d65315f37345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f72756e74696d652e2e4f706171756556616c75652447542439747970655f696e666f313768353135613532643361346434623437634589059c025f5a4e35616c6c6f633131636f6c6c656374696f6e73356274726565346e6f646532313048616e646c65244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e4e6f6465526566244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4d75742443244b24432456244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4c65616624475424244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e45646765244754243136696e736572745f726563757273696e6731376862393130613235323366636336323532458a059c025f5a4e35616c6c6f633131636f6c6c656374696f6e73356274726565346e6f646532313048616e646c65244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e4e6f6465526566244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4d75742443244b24432456244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4c65616624475424244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e45646765244754243136696e736572745f726563757273696e6731376865353939333832616639313063653565458b054b5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376865636165663963333333323162356439452e6c6c766d2e353633363233393834323730393533353139358c054c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f7075736831376834633435393662396662353838666662458d05595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c6531376864666430653266323034313436333362458e054c5f5a4e313673705f73746174655f6d616368696e6533657874313353746f72616765417070656e6431347265706c6163655f6c656e67746831376831623663363864323864626462373966458f059e015f5a4e313673705f73746174655f6d616368696e6531376f7665726c617965645f6368616e676573396368616e676573657438324f7665726c61796564456e747279244c542473705f73746174655f6d616368696e652e2e6f7665726c617965645f6368616e6765732e2e6368616e67657365742e2e53746f72616765456e747279244754243373657431376865646538393361333639336165363366459005b9015f5a4e313673705f73746174655f6d616368696e6531376f7665726c617965645f6368616e676573396368616e67657365743130384f7665726c617965644d6170244c5424616c6c6f632e2e7665632e2e566563244c542475382447542424432473705f73746174655f6d616368696e652e2e6f7665726c617965645f6368616e6765732e2e6368616e67657365742e2e53746f72616765456e7472792447542433736574313768303632636362613763373566353230624591056f5f5a4e38315f244c5424616c6c6f632e2e7665632e2e73706c6963652e2e53706c696365244c5424492443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f70313768336531323765303239373764666538344592053f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f646531376831313637396536386239336435326137459305475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376835633038353733623131643266623333459405475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d74313768643734653131653337373461366332334595055e5f5a4e34636f726533666d74336e756d35325f244c5424696d706c2475323024636f72652e2e666d742e2e44656275672475323024666f7224753230247573697a652447542433666d74313768646464643336383865643561366332634596053c5f5a4e34636f726533707472323664726f705f696e5f706c616365244c54247573697a652447542431376865326239626139343666313039393164459705565f5a4e35616c6c6f633131636f6c6c656374696f6e73356274726565336d6170323542547265654d6170244c54244b24432456244324412447542436696e73657274313768396135373066346631303166633138354598056d5f5a4e34636f726533707472343964726f705f696e5f706c616365244c5424736d616c6c7665632e2e436f6c6c656374696f6e416c6c6f634572722447542431376839323766636536623831336632303330452e6c6c766d2e31373930353630373237323133373537303737309905785f5a4e36355f244c5424736d616c6c7665632e2e436f6c6c656374696f6e416c6c6f63457272247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376833333136353566633965353230393634452e6c6c766d2e31373930353630373237323133373537303737309a054a5f5a4e38736d616c6c7665633137536d616c6c566563244c542441244754243231726573657276655f6f6e655f756e636865636b656431376864303333643431383135396466623731459b054b5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376835646634376333623866393962643264452e6c6c766d2e323037323134373132343138373337383334369c05725f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c6531376866376634363230363333383535363865452e6c6c766d2e323037323134373132343138373337383334369d05565f5a4e35315f244c542473705f7374642e2e577269746572247532302461732475323024636f72652e2e666d742e2e5772697465244754243977726974655f73747231376838306237346666643465623161613832459e054b5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376862386530376363663762666537303564452e6c6c766d2e393537383839383230323436313034313534349f05725f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c6531376864333737366138356664323136613963452e6c6c766d2e39353738383938323032343631303431353434a005435f5a4e313073705f73746f72616765394368696c64496e666f323070726566697865645f73746f726167655f6b65793137683461386161343463313630313733316145a10593015f5a4e3773705f74726965313373746f726167655f70726f6f66315f38375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f747269652e2e73746f726167655f70726f6f662e2e53746f7261676550726f6f662447542439747970655f696e666f3137686237663535333934356338383337333845a205735f5a4e31307363616c655f696e666f35696d706c7336325f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302424753562245424753564242447542439747970655f696e666f3137686265373866346237326364333438633045a30580015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137683764623765623536653135653037353145a405ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137683566383362333739363661303639643345a505ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137683861653132363930336533393531363745a60587015f5a4e39375f244c5424616c6c6f632e2e7665632e2e566563244c5424542443244124475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f657874656e642e2e53706563457874656e64244c5424542443244924475424244754243131737065635f657874656e643137683765623365623531616535386133343445a7054c5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376832363063323631656562393639646465452e6c6c766d2e3130393530333139383533363038363833313939a8054c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137683937646534376331643466636466383645a9054c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137683966353264663566653732646438323745aa05595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683764303935616637613231663465393345ab05595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683963313562353162666465663336323545ac05595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137686335333864616432616463643132386545ad058c015f5a4e3130345f244c54247061726974795f7363616c655f636f6465632e2e636f6d706163742e2e436f6d70616374526566244c5424753332244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542439656e636f64655f746f3137683632313236633362643133346332343845ae059a015f5a4e31307363616c655f696e666f35696d706c733130305f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e7365742e2e4254726565536574244c542454244754242447542439747970655f696e666f3137686562383831333432316663396532396445af05705f5a4e37345f244c542473705f747269652e2e747269655f73747265616d2e2e5472696553747265616d247532302461732475323024747269655f726f6f742e2e5472696553747265616d244754243131617070656e645f6c6561663137686236666565333662663936383537333545b005735f5a4e31307363616c655f696e666f35696d706c7336325f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302424753562245424753564242447542439747970655f696e666f3137683238323863636265636637383533376145b105755f5a4e31307363616c655f696e666f35696d706c7336345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024244c50244124432442245250242447542439747970655f696e666f3137683538356366373361353437336132356545b2057e5f5a4e31307363616c655f696e666f35696d706c7337335f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024247535622454247533622424753230244e24753564242447542439747970655f696e666f3137686235333833336264636439306539373045b30583015f5a4e31307363616c655f696e666f35696d706c7337385f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e626f72726f772e2e436f77244c542454244754242447542439747970655f696e666f3137686535393730613739333139613339653345b4057e5f5a4e313073705f76657273696f6e315f37375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f76657273696f6e2e2e52756e74696d6556657273696f6e2447542439747970655f696e666f3137683464316230303235646636323439353345b5054b5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376830656330653335393635356435646662452e6c6c766d2e39353132323739313539363038393431383337b6054c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137683833303166623233626361323861313545b70595015f5a4e31307363616c655f696e666f35696d706c7339365f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230247061726974795f7363616c655f636f6465632e2e636f6d706163742e2e436f6d70616374244c542454244754242447542439747970655f696e666f3137686135323839303362656338396664626345b805615f5a4e36385f244c542473705f776569676874732e2e7765696768745f76322e2e576569676874247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d743137683337343865366138326132313838616145b9058b015f5a4e313073705f77656967687473397765696768745f7632315f38305f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f776569676874732e2e7765696768745f76322e2e5765696768742447542439747970655f696e666f3137683338626562633562636662643865656445ba057f5f5a4e313073705f77656967687473315f37385f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f776569676874732e2e52756e74696d6544625765696768742447542439747970655f696e666f3137686439326334626438343632343235376545bb05655f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f7075736831376837306638626536663361633732663732452e6c6c766d2e33373830303837383837373935313935353433bc054b5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376839313930633465383236343363353736452e6c6c766d2e33373830303837383837373935313935353433bd059c025f5a4e35616c6c6f633131636f6c6c656374696f6e73356274726565346e6f646532313048616e646c65244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e4e6f6465526566244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4d75742443244b24432456244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4c65616624475424244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e45646765244754243136696e736572745f726563757273696e673137683131346363653465333666643031366245be059c025f5a4e35616c6c6f633131636f6c6c656374696f6e73356274726565346e6f646532313048616e646c65244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e4e6f6465526566244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4d75742443244b24432456244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4c65616624475424244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e45646765244754243136696e736572745f726563757273696e673137683535613734356536616362656331636145bf059c025f5a4e35616c6c6f633131636f6c6c656374696f6e73356274726565346e6f646532313048616e646c65244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e4e6f6465526566244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4d75742443244b24432456244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4c65616624475424244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e45646765244754243136696e736572745f726563757273696e673137683637346639303866313638346139316545c0059c025f5a4e35616c6c6f633131636f6c6c656374696f6e73356274726565346e6f646532313048616e646c65244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e4e6f6465526566244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4d75742443244b24432456244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4c65616624475424244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e45646765244754243136696e736572745f726563757273696e673137686662326364633663356132326131623845c105f6015f5a4e35616c6c6f633131636f6c6c656374696f6e7335627472656536617070656e643137385f244c5424696d706c2475323024616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e4e6f6465526566244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4f776e65642443244b24432456244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4c6561664f72496e7465726e616c24475424244754243962756c6b5f707573683137683338353663666564353630396262666345c205f6015f5a4e35616c6c6f633131636f6c6c656374696f6e7335627472656536617070656e643137385f244c5424696d706c2475323024616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e4e6f6465526566244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4f776e65642443244b24432456244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4c6561664f72496e7465726e616c24475424244754243962756c6b5f707573683137683538356539373534353336373463353845c305f6015f5a4e35616c6c6f633131636f6c6c656374696f6e7335627472656536617070656e643137385f244c5424696d706c2475323024616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e4e6f6465526566244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4f776e65642443244b24432456244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4c6561664f72496e7465726e616c24475424244754243962756c6b5f707573683137686436653862316533346431613962333345c405d5015f5a4e35616c6c6f633131636f6c6c656374696f6e73356274726565367365617263683134325f244c5424696d706c2475323024616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e4e6f6465526566244c5424426f72726f77547970652443244b24432456244324616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6e6f64652e2e6d61726b65722e2e4c6561664f72496e7465726e616c244754242447542431317365617263685f747265653137683531336161373762313636313439306445c505465f5a4e31387061726974795f7363616c655f636f64656335636f64656331396465636f64655f7665635f776974685f6c656e3137683033326465623466626639643034313845c605465f5a4e31387061726974795f7363616c655f636f64656335636f64656331396465636f64655f7665635f776974685f6c656e3137683430623731346230393362343862353145c705465f5a4e31387061726974795f7363616c655f636f64656335636f64656331396465636f64655f7665635f776974685f6c656e3137683433343537373131666630343138353145c805465f5a4e31387061726974795f7363616c655f636f64656335636f64656331396465636f64655f7665635f776974685f6c656e3137683436353837333462633934643931663645c905465f5a4e31387061726974795f7363616c655f636f64656335636f64656331396465636f64655f7665635f776974685f6c656e3137683562396562383632326538613761653045ca05465f5a4e31387061726974795f7363616c655f636f64656335636f64656331396465636f64655f7665635f776974685f6c656e3137683636336165383130313166633865363045cb05465f5a4e31387061726974795f7363616c655f636f64656335636f64656331396465636f64655f7665635f776974685f6c656e3137683733363938323065356235656134626145cc05465f5a4e31387061726974795f7363616c655f636f64656335636f64656331396465636f64655f7665635f776974685f6c656e3137683862306663356664633339613963323745cd05465f5a4e31387061726974795f7363616c655f636f64656335636f64656331396465636f64655f7665635f776974685f6c656e3137683863626533363332336633643262663845ce05465f5a4e31387061726974795f7363616c655f636f64656335636f64656331396465636f64655f7665635f776974685f6c656e3137686133303066643436643138343932393045cf05465f5a4e31387061726974795f7363616c655f636f64656335636f64656331396465636f64655f7665635f776974685f6c656e3137686261616138653232626364623433663345d005465f5a4e31387061726974795f7363616c655f636f64656335636f64656331396465636f64655f7665635f776974685f6c656e3137686364663666666238396338663766356445d105465f5a4e31387061726974795f7363616c655f636f64656335636f64656331396465636f64655f7665635f776974685f6c656e3137686430346565356330363436623266366645d205465f5a4e31387061726974795f7363616c655f636f64656335636f6465633139656e636f64655f736c6963655f6e6f5f6c656e3137683632643066363338383937373264373945d305465f5a4e31387061726974795f7363616c655f636f64656335636f6465633139656e636f64655f736c6963655f6e6f5f6c656e3137683761653038663635653035633738316245d405465f5a4e31387061726974795f7363616c655f636f64656335636f6465633139656e636f64655f736c6963655f6e6f5f6c656e3137686333323532313665323039353066616245d505475f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646531337573696e675f656e636f6465643137686236366637636233353130373531366645d6053f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f64653137683466623661326265326564323037303245d7053f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f64653137683561323865373533363739613734316245d8053f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f64653137686136383437383761393133336666313145d9057c5f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c2447542436636f6d6d697432385f24753762242475376224636c6f737572652475376424247537642431376839323133383435383330616537633739452e6c6c766d2e3132353235333233373335393830383932393830da0583015f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c244754243132636f6d6d69745f6368696c6432385f24753762242475376224636c6f737572652475376424247537642431376839666630616538376464333130656261452e6c6c766d2e3132353235333233373335393830383932393830db057c5f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c2447542436636f6d6d697432385f24753762242475376224636c6f737572652475376424247537642431376837616231363132313865613535356238452e6c6c766d2e3132353235333233373335393830383932393830dc0583015f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c244754243132636f6d6d69745f6368696c6432385f24753762242475376224636c6f737572652475376424247537642431376865303664303766653561666435643961452e6c6c766d2e3132353235333233373335393830383932393830dd055a5f5a4e34636f7265336f70733866756e6374696f6e36466e4f6e6365343063616c6c5f6f6e636524753762242475376224767461626c652e7368696d247537642424753764243137683261333338386662376137623531303045de05695f5a4e34636f726533707472373164726f705f696e5f706c616365244c542473705f747269652e2e6572726f722e2e4572726f72244c54247072696d69746976655f74797065732e2e4832353624475424244754243137683461363365306537646330353230356545df05b5015f5a4e34636f72653370747231343664726f705f696e5f706c616365244c5424616c6c6f632e2e626f7865642e2e426f78244c5424747269655f64622e2e547269654572726f72244c54247072696d69746976655f74797065732e2e4832353624432473705f747269652e2e6572726f722e2e4572726f72244c54247072696d69746976655f74797065732e2e48323536244754242447542424475424244754243137683666333363313066386139323431346645e0055a5f5a4e34636f7265336f70733866756e6374696f6e36466e4f6e6365343063616c6c5f6f6e636524753762242475376224767461626c652e7368696d247537642424753764243137683336633066636239383763373161396445e1055a5f5a4e34636f7265336f70733866756e6374696f6e36466e4f6e6365343063616c6c5f6f6e636524753762242475376224767461626c652e7368696d247537642424753764243137686532323961626532316333623261356445e2053a5f5a4e34636f7265336f70733866756e6374696f6e36466e4f6e63653963616c6c5f6f6e63653137683062363033303564376532626538373645e30590015f5a4e34636f72653370747231303964726f705f696e5f706c616365244c5424747269655f64622e2e7472696564626d75742e2e4e6f6465244c542473705f747269652e2e4c61796f75745630244c542473705f72756e74696d652e2e7472616974732e2e426c616b6554776f3235362447542424475424244754243137683636656262373231373030326234306345e40591015f5a4e34636f72653370747231313064726f705f696e5f706c616365244c5424747269655f64622e2e7472696564626d75742e2e56616c7565244c542473705f747269652e2e4c61796f75745630244c542473705f72756e74696d652e2e7472616974732e2e426c616b6554776f3235362447542424475424244754243137683666346661333363616131323934373645e505ad015f5a4e34636f72653370747231333864726f705f696e5f706c616365244c5424636f72652e2e6f7074696f6e2e2e4f7074696f6e244c5424747269655f64622e2e7472696564626d75742e2e56616c7565244c542473705f747269652e2e4c61796f75745630244c542473705f72756e74696d652e2e7472616974732e2e426c616b6554776f323536244754242447542424475424244754243137686464616263386632333534303430633845e605be015f5a4e34636f72653370747231353564726f705f696e5f706c616365244c5424747269655f64622e2e7472696564626d75742e2e5472696544424d7574244c542473705f747269652e2e4c61796f75745630244c542473705f72756e74696d652e2e7472616974732e2e426c616b6554776f32353624475424244754242e2e63616368655f6e6f64652e2e24753762242475376224636c6f7375726524753764242475376424244754243137683539613639613664623061313439336145e705675f5a4e37355f244c5424747269655f64622e2e7472696564626d75742e2e56616c7565244c54244c24475424247532302461732475323024636f72652e2e636d702e2e5061727469616c4571244754243265713137683236343763396361653063666366353045e805465f5a4e37747269655f6462397472696564626d757431334e6f6465244c54244c24475424313266726f6d5f656e636f6465643137683466333032653430336637666465366245e905485f5a4e37747269655f6462397472696564626d757431334e6f6465244c54244c244754243134696e6c696e655f6f725f686173683137683966343064393064353534373032653845ea05645f5a4e37747269655f6462397472696564626d757431334e6f6465244c54244c24475424313266726f6d5f656e636f64656432385f24753762242475376224636c6f73757265247537642424753764243137683463653136343861653864643537643345eb05645f5a4e37747269655f6462397472696564626d757431334e6f6465244c54244c24475424313266726f6d5f656e636f64656432385f24753762242475376224636c6f73757265247537642424753764243137683031353833363735633234623664396245ec05465f5a4e37747269655f6462397472696564626d757431334e6f6465244c54244c24475424313266726f6d5f656e636f6465643137683733363436313237333437646366346645ed05485f5a4e37747269655f6462397472696564626d757431334e6f6465244c54244c244754243134696e6c696e655f6f725f686173683137683236326661346532303234666261343945ee05645f5a4e37747269655f6462397472696564626d757431334e6f6465244c54244c24475424313266726f6d5f656e636f64656432385f24753762242475376224636c6f73757265247537642424753764243137686238646465343838386132323265623145ef05645f5a4e37747269655f6462397472696564626d757431334e6f6465244c54244c24475424313266726f6d5f656e636f64656432385f24753762242475376224636c6f73757265247537642424753764243137686632363430653862336432643938316445f005495f5a4e37747269655f6462397472696564626d757431334e6f6465244c54244c24475424313566726f6d5f6e6f64655f6f776e65643137683061643664363230323366633034636445f1054e5f5a4e37747269655f6462397472696564626d757431334e6f6465244c54244c244754243230696e6c696e655f6f725f686173685f6f776e65643137683837313032653665336539653334323445f205495f5a4e37747269655f6462397472696564626d757431334e6f6465244c54244c24475424313566726f6d5f6e6f64655f6f776e65643137686162323033316433633638656362333445f3054e5f5a4e37747269655f6462397472696564626d757431334e6f6465244c54244c244754243230696e6c696e655f6f725f686173685f6f776e65643137686531636463386364373731386636373845f405475f5a4e37747269655f6462397472696564626d7574313456616c7565244c54244c244754243132696e746f5f656e636f6465643137683336396365383462323631626161626645f505475f5a4e37747269655f6462397472696564626d7574313456616c7565244c54244c244754243132696e746f5f656e636f6465643137683538643432616639363930313863316345f605475f5a4e37747269655f6462397472696564626d7574313456616c7565244c54244c244754243132696e746f5f656e636f6465643137683561613262393238613735333966643445f705475f5a4e37747269655f6462397472696564626d7574313456616c7565244c54244c244754243132696e746f5f656e636f6465643137686538376363653739363963336634313745f805495f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c24475424313063616368655f6e6f64653137686162353930313831623263353964656145f905495f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c24475424313063616368655f6e6f64653137686663386432393566666137333561323145fa05675f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c24475424313063616368655f6e6f646532385f24753762242475376224636c6f73757265247537642424753764243137683265663263623537366430643733386145fb05675f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c24475424313063616368655f6e6f646532385f24753762242475376224636c6f73757265247537642424753764243137683337636262633562383862303162353545fc05645f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c24475424313163616368655f76616c756531376837313233373464653531363639303734452e6c6c766d2e3132353235333233373335393830383932393830fd05645f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c24475424313163616368655f76616c756531376866363836353265646465326565656533452e6c6c766d2e3132353235333233373335393830383932393830fe05685f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c24475424313163616368655f76616c756532385f24753762242475376224636c6f73757265247537642424753764243137683037323834356562616665386165313345ff05655f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c244754243132636f6d6d69745f6368696c6431376830306632306263363037383764613466452e6c6c766d2e31323532353332333733353938303839323938308006655f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c244754243132636f6d6d69745f6368696c6431376838383664646632303934613566336332452e6c6c766d2e313235323533323337333539383038393239383081064f5f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c244754243136696e736572745f696e73706563746f7231376836366239646534333233626166333133458206615f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c2447542439696e736572745f617431376838636334643565343562653932623463452e6c6c766d2e31323532353332333733353938303839323938308306505f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c2447542431377265706c6163655f6f6c645f76616c7565313768333939303033613033626133346136614584064f5f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c244754243136696e736572745f696e73706563746f7231376862633336326561346630373438316335458506615f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c2447542439696e736572745f617431376832653364316163643233663632346265452e6c6c766d2e31323532353332333733353938303839323938308606435f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c2447542435636163686531376833663462363761383336366439353332458706435f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c2447542435636163686531376837626630383935356361643930646233458806475f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c24475424396669785f696e6e657231376831313930393666356261646130343139458906475f5a4e37747269655f6462397472696564626d757432304e6f646553746f72616765244c54244c244754243764657374726f7931376830323961386361326564336430356130458a06475f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c24475424396669785f696e6e657231376832343966613334316432623030613265458b06475f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c244754243972656d6f76655f617431376839656233356565363964636565323431458c06655f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c244754243972656d6f76655f617432385f24753762242475376224636c6f737572652475376424247537642431376839393937613630346436633430326131458d06475f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c244754243972656d6f76655f617431376866316265663065343338656636363937458e06655f5a4e37747269655f6462397472696564626d757431385472696544424d7574244c54244c244754243972656d6f76655f617432385f24753762242475376224636c6f737572652475376424247537642431376833333462383665633563373463656266458f066e5f5a4e38305f244c5424747269655f64622e2e7472696564626d75742e2e5472696544424d7574244c54244c24475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f70313768303964313966653730363430303536614590066e5f5a4e38305f244c5424747269655f64622e2e7472696564626d75742e2e5472696544424d7574244c54244c24475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f7031376832316434383430366465626333383034459106745f5a4e38345f244c5424747269655f64622e2e7472696564626d75742e2e5472696544424d7574244c54244c24475424247532302461732475323024747269655f64622e2e547269654d7574244c54244c244754242447542436696e7365727431376830623661623133663239343937303336459206745f5a4e38345f244c5424747269655f64622e2e7472696564626d75742e2e5472696544424d7574244c54244c24475424247532302461732475323024747269655f64622e2e547269654d7574244c54244c244754242447542436696e7365727431376839373065633661633839393362643037459306745f5a4e38345f244c5424747269655f64622e2e7472696564626d75742e2e5472696544424d7574244c54244c24475424247532302461732475323024747269655f64622e2e547269654d7574244c54244c24475424244754243672656d6f766531376835653539306337323764653036313034459406745f5a4e38345f244c5424747269655f64622e2e7472696564626d75742e2e5472696544424d7574244c54244c24475424247532302461732475323024747269655f64622e2e547269654d7574244c54244c24475424244754243672656d6f7665313768393535313039363030336432376539324595064b5f5a4e35616c6c6f63377261775f766563313166696e6973685f67726f7731376830313337653736373364626637396536452e6c6c766d2e373231323330373831363737383531343238329606475f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243131616c6c6f636174655f696e313768363630626337313239343632363531304597064c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f70757368313768306162373132643039383663356334394598064c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f70757368313768306265396162623836346664663363314599064c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f7075736831376830636235633630343066303966313063459a064c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f7075736831376832653564616235616564623762313331459b064c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f7075736831376833323066303766656662626238323235459c064c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f7075736831376835633436323064323638336438393734459d064c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f7075736831376836323732323030636134303366663030459e064c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f7075736831376837363433633734393236643730623861459f064c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137683762616437653238323238633665346345a0064c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137683765643733656235313336633831646445a1064c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137683932633064333965313838646431623645a2064c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137686134653466303530626138363463653245a3064c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137686235353838323331373839613733383145a4064c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137686237353639643761333830376666393845a5064c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137686431363935336130666339333661633645a6064c5f5a4e35616c6c6f63377261775f7665633139526177566563244c54245424432441244754243136726573657276655f666f725f707573683137686534653730666433376639373266353945a706595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683038393338346566313364356235326145a806595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683364393366373138626563306465313645a906595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683461336639666434343161646161333145aa06595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683661346466393932333536616435663845ab06595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137683736623762316263306637343466353145ac06595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137686138303937353232316662653730666645ad06595f5a4e35616c6c6f63377261775f7665633139526177566563244c542454244324412447542437726573657276653231646f5f726573657276655f616e645f68616e646c653137686633613163643730303131346665656145ae063b5f5a4e313073657264655f6a736f6e337365723138666f726d61745f657363617065645f7374723137683361373464336331393330633930666245af069e015f5a4e313073657264655f6a736f6e3576616c75653373657237365f244c5424696d706c247532302473657264652e2e7365722e2e53657269616c697a652475323024666f72247532302473657264655f6a736f6e2e2e76616c75652e2e56616c7565244754243973657269616c697a6531376831313664616335383937343963643837452e6c6c766d2e37363631343238303731363137323835383130b0063a5f5a4e35736572646533736572313053657269616c697a65723131636f6c6c6563745f7365713137683133353762633362323835306432663045b1064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137683132666365376231656564653232666145b2064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137683230373162613062656163663535303445b3064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137683536643439346163666638363764346445b4064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137683538343031626231626463653036396145b5064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137683561356331373936313262323031343545b6064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137683562623962343566333832646635393245b7064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137683661616535636132643264633932376345b8064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137683662616232653132303166333237666345b9064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137683665386536626630326630373362666245ba064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137683738346335386331376133353736316545bb064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137683739323661616134386363643036613745bc064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137683830353233656636636437623733653645bd064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137683863323861616534303636643663323445be064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137683930383935616563303935373864663345bf064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137683931613263373161643161643864633645c0064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137686232326631666433353362663132363445c1064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137686333353230636466376261623963336245c2064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137686338306565336333666533366263303145c3064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137686434316631306437613065383037646645c4064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137686439353231353162616536366439616645c5064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137686534303439333636656463623433666145c6064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137686536323061346530353364356363373445c7064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137686635323730656166663837333362313845c8064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137686635393035366339626265653334383045c9064f5f5a4e31336672616d655f737570706f72743773746f7261676531337472616e73616374696f6e616c3136776974685f7472616e73616374696f6e3137686636613136656531613638313537623245ca06d1015f5a4e3137335f244c542473705f636f6e73656e7375735f626162652e2e5f2e2e244c5424696d706c247532302473657264652e2e64652e2e446573657269616c697a652475323024666f72247532302473705f636f6e73656e7375735f626162652e2e416c6c6f776564536c6f7473244754242e2e646573657269616c697a652e2e5f5f4669656c6456697369746f7224753230246173247532302473657264652e2e64652e2e56697369746f72244754243976697369745f7374723137686535653030346637306539383362663445cb068f015f5a4e313773705f636f6e73656e7375735f62616265315f38345f244c5424696d706c247532302473657264652e2e64652e2e446573657269616c697a652475323024666f72247532302473705f636f6e73656e7375735f626162652e2e416c6c6f776564536c6f7473244754243131646573657269616c697a653137683335346631326638353935333339303245cc063f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f64653137683232343336396233623134303639383445cd063f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f64653137683433623233306631373331613862303245ce063f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f64653137683738373230343137336162356233306645cf06465f5a4e34315f244c54245424753230246173247532302473657264652e2e64652e2e45787065637465642447542433666d743137683636393539613139633137323664633045d006465f5a4e34315f244c54245424753230246173247532302473657264652e2e64652e2e45787065637465642447542433666d743137683964356432353266656631633537313545d1066e5f5a4e34636f726533707472353164726f705f696e5f706c616365244c542473705f73746174655f6d616368696e652e2e44656661756c744572726f722447542431376836656330653864613137386438613066452e6c6c766d2e37363631343238303731363137323835383130d2063a5f5a4e35736572646533736572313053657269616c697a65723131636f6c6c6563745f7365713137686437316136363935396137363431373845d306405f5a4e35736572646533736572313253657269616c697a654d6170313573657269616c697a655f656e7472793137683234666165366264343161343930363145d4069a015f5a4e38355f244c542473657264655f6a736f6e2e2e7365722e2e436f6d706f756e64244c542457244324462447542424753230246173247532302473657264652e2e7365722e2e53657269616c697a655475706c6524475424313773657269616c697a655f656c656d656e7431376831336565366338666134346665393839452e6c6c766d2e37363631343238303731363137323835383130d506405f5a4e35736572646533736572313253657269616c697a654d6170313573657269616c697a655f656e7472793137683330623833333533343937663866323545d606405f5a4e35736572646533736572313253657269616c697a654d6170313573657269616c697a655f656e7472793137683463383137313865363032333565396345d706405f5a4e35736572646533736572313253657269616c697a654d6170313573657269616c697a655f656e7472793137683564666263626438663537656634623445d806405f5a4e35736572646533736572313253657269616c697a654d6170313573657269616c697a655f656e7472793137683761306531386263323134653235653445d906405f5a4e35736572646533736572313253657269616c697a654d6170313573657269616c697a655f656e7472793137683839636265363364366363313735353245da06405f5a4e35736572646533736572313253657269616c697a654d6170313573657269616c697a655f656e7472793137683864386537396663373331316338363545db06405f5a4e35736572646533736572313253657269616c697a654d6170313573657269616c697a655f656e7472793137686136333239613263326631396634626445dc06405f5a4e35736572646533736572313253657269616c697a654d6170313573657269616c697a655f656e7472793137686433633461386665383831316137623745dd06795f5a4e36375f244c542473705f73746174655f6d616368696e652e2e44656661756c744572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376837323136666635326339346461646539452e6c6c766d2e37363631343238303731363137323835383130de06745f5a4e38365f244c5424616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137683865393535343531636433333931383345df067c5f5a4e39315f244c542473705f73746174655f6d616368696e652e2e6578742e2e457874244c542448244324422447542424753230246173247532302473705f65787465726e616c69746965732e2e45787465726e616c6974696573244754243773746f726167653137683462623866386263643230653633356345e0066d5f5a4e31307363616c655f696e666f35696d706c7335365f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302424524624542447542439747970655f696e666f3137686163363436313539633264383139663145e106755f5a4e31307363616c655f696e666f35696d706c7336345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024244c50244124432442245250242447542439747970655f696e666f3137683334383232313130653038396134393145e20680015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137683432353362623338616438363837376245e306755f5a4e31307363616c655f696e666f35696d706c7336345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024244c50244124432442245250242447542439747970655f696e666f3137686561393033386265643136343533343245e40680015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137683364383165356632393864623263343945e50680015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137683461303834306265616236343763633045e60680015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137683537623862643131386632643934613845e70680015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137683563316434656139616164356662646345e80680015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137683563346236393839616366316131633445e90680015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137683665666433666139653236373961316445ea0680015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137683730623533323366643962393633633945eb0680015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137683730633831323938633663316361643045ec0680015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137683839323538666433373663333337373945ed0680015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137683839353761353561386337616333343745ee0680015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137686162363435393230383137336363616545ef0680015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137686332636530326631316437303131663345f00680015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137686436623861383765373630623062363545f10680015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137686530333934326465386238383766613045f20680015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137686535663763393635316265303039373045f30680015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137686539343565303536383833643830363645f40680015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137686636383039303163383230646436316645f50680015f5a4e31307363616c655f696e666f35696d706c7337355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e7665632e2e566563244c542454244754242447542439747970655f696e666f3137686661306432313763316562383265646645f606a6015f5a4e3133335f244c5424736d616c6c7665632e2e536d616c6c566563244c54244124475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e636f6c6c6563742e2e457874656e64244c5424244c542441247532302461732475323024736d616c6c7665632e2e4172726179244754242e2e4974656d244754242447542436657874656e643137686630633639663932326163376438393945f706565f5a4e38736d616c6c7665633137536d616c6c566563244c54244124475424387472795f67726f7731376835376661373337366334356335393730452e6c6c766d2e3130393532323235313434363530373438323637f8064a5f5a4e38736d616c6c7665633137536d616c6c566563244c542441244754243231726573657276655f6f6e655f756e636865636b65643137683439646637656438363939323432666245f906ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137683135323864363439626563323331383545fa06ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137683666623739323031363866326231386445fb06ad015f5a4e3133375f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c542454244324616c6c6f632e2e7665632e2e696e746f5f697465722e2e496e746f49746572244c5424542447542424475424244754243966726f6d5f697465723137683734636434646662633365313634343145fc069b015f5a4e31387061726974795f7363616c655f636f64656335636f6465633136696e6e65725f7475706c655f696d706c37395f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f64652475323024666f722475323024244c5024513024432452302452502424475424366465636f64653137683836646437666566363630643965386545fd069b015f5a4e31387061726974795f7363616c655f636f64656335636f6465633136696e6e65725f7475706c655f696d706c37395f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f64652475323024666f722475323024244c5024513024432452302452502424475424366465636f64653137686633616262303864656430333335343145fe069e015f5a4e31387061726974795f7363616c655f636f64656335636f6465633136696e6e65725f7475706c655f696d706c37395f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f722475323024244c502451302443245230245250242447542439656e636f64655f746f3137683563313861623532383737386263373145ff066d5f5a4e34636f726533707472343964726f705f696e5f706c616365244c5424736d616c6c7665632e2e436f6c6c656374696f6e416c6c6f634572722447542431376833666264306261303836613233333534452e6c6c766d2e313039353232323531343436353037343832363780075a5f5a4e35355f244c5424582475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542439656e636f64655f746f313768313837613332646335353536363537644581075a5f5a4e35355f244c5424582475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542439656e636f64655f746f313768363134353735376263393666653137384582075a5f5a4e35355f244c5424582475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542439656e636f64655f746f31376866383036646135353233356165386634458307465f5a4e35616c6c6f63337665633136566563244c54245424432441244754243137657874656e645f66726f6d5f736c69636531376835386436306262626438306365636634458407ac015f5a4e35616c6c6f63337665633136696e5f706c6163655f636f6c6c6563743130385f244c5424696d706c2475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c54245424432449244754242475323024666f722475323024616c6c6f632e2e7665632e2e566563244c54245424475424244754243966726f6d5f6974657231376838366430626338303239393733343035458507625f5a4e36305f244c5424245246246d7574247532302454247532302461732475323024627335382e2e6465636f64652e2e4465636f64655461726765742447542431316465636f64655f77697468313768363938346436393533666632373435624586075e5f5a4e36355f244c5424616c6c6f632e2e7665632e2e566563244c5424542443244124475424247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376838326633383830343432666162373935458707785f5a4e36355f244c5424736d616c6c7665632e2e436f6c6c656374696f6e416c6c6f63457272247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376833333136353566633965353230393634452e6c6c766d2e31303935323232353134343635303734383236378807785f5a4e36365f244c5424542475323024617324753230247061726974795f7363616c655f636f6465632e2e64657074685f6c696d69742e2e4465636f64654c696d69742447542432376465636f64655f616c6c5f776974685f64657074685f6c696d697431376833353766323864373430376338666132458907785f5a4e36365f244c5424542475323024617324753230247061726974795f7363616c655f636f6465632e2e64657074685f6c696d69742e2e4465636f64654c696d69742447542432376465636f64655f616c6c5f776974685f64657074685f6c696d697431376834306564306261623664643838613964458a07625f5a4e36375f244c5424616c6c6f632e2e7665632e2e566563244c5424542443244124475424247532302461732475323024636f72652e2e636c6f6e652e2e436c6f6e652447542435636c6f6e6531376830613133303836323936373939623162458b07625f5a4e36375f244c5424616c6c6f632e2e7665632e2e566563244c5424542443244124475424247532302461732475323024636f72652e2e636c6f6e652e2e436c6f6e652447542435636c6f6e6531376833303032623036633430666461313233458c07625f5a4e36375f244c5424616c6c6f632e2e7665632e2e566563244c5424542443244124475424247532302461732475323024636f72652e2e636c6f6e652e2e436c6f6e652447542435636c6f6e6531376861333334663465336539326366646530458d07625f5a4e36375f244c5424616c6c6f632e2e7665632e2e566563244c5424542443244124475424247532302461732475323024636f72652e2e636c6f6e652e2e436c6f6e652447542435636c6f6e6531376864353761393339363337663532343466458e07635f5a4e36395f244c5424736d616c6c7665632e2e536d616c6c566563244c54244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f7031376865333561626530343936313131376166458f07645f5a4e37305f244c5424616c6c6f632e2e7665632e2e566563244c5424542443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f7031376836353938316562653430626633323837459007645f5a4e37305f244c5424616c6c6f632e2e7665632e2e566563244c5424542443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f7031376838383938623038633564333539643731459107645f5a4e37305f244c5424616c6c6f632e2e7665632e2e566563244c5424542443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f70313768393733393934663265303735616331314592076e5f5a4e37325f244c5424616c6c6f632e2e7665632e2e566563244c5424753824475424247532302461732475323024627335382e2e656e636f64652e2e456e636f6465546172676574244754243131656e636f64655f77697468313768636338313364316636326463303937334593076e5f5a4e37385f244c5424616c6c6f632e2e7665632e2e566563244c542454244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f646524475424366465636f6465313768376163333139353063613339383532394594076e5f5a4e37385f244c5424616c6c6f632e2e7665632e2e566563244c542454244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f646524475424366465636f646531376864303036616366333634393034633837459507395f5a4e3773705f7472696531316e6f64655f68656164657231316465636f64655f73697a65313768383538353837336231616233373036334596076f5f5a4e38305f244c5424736d616c6c7665632e2e536d616c6c566563244c54244124475424247532302461732475323024636f72652e2e6f70732e2e696e6465782e2e496e646578244c542449244754242447542435696e64657831376834623132313564373666326538663630459707765f5a4e38365f244c542473705f747269652e2e6e6f64655f6865616465722e2e4e6f64654865616465722475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f646524475424366465636f646531376866326532623830316361643465373138459807795f5a4e38365f244c542473705f747269652e2e6e6f64655f6865616465722e2e4e6f64654865616465722475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542439656e636f64655f746f3137686362323764343539666137623939373945990787015f5a4e39375f244c5424616c6c6f632e2e7665632e2e566563244c5424542443244124475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f657874656e642e2e53706563457874656e64244c5424542443244924475424244754243131737065635f657874656e6431376832666337393939646230643131366535459a0787015f5a4e39375f244c5424616c6c6f632e2e7665632e2e566563244c5424542443244124475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f657874656e642e2e53706563457874656e64244c5424542443244924475424244754243131737065635f657874656e6431376865353762633734333463373832613732459b0785015f5a4e39385f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c5424542443244924475424244754243966726f6d5f6974657231376832356664626462343531623738633036459c0785015f5a4e39385f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c5424542443244924475424244754243966726f6d5f6974657231376832633736393065646566623836343338459d0785015f5a4e39385f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c5424542443244924475424244754243966726f6d5f6974657231376839353935366534663861303965666432459e0785015f5a4e39385f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c5424542443244924475424244754243966726f6d5f6974657231376863623331393938643433633537623762459f0785015f5a4e39385f244c5424616c6c6f632e2e7665632e2e566563244c54245424475424247532302461732475323024616c6c6f632e2e7665632e2e737065635f66726f6d5f697465722e2e5370656346726f6d49746572244c5424542443244924475424244754243966726f6d5f697465723137686437313433393938616462323538643745a0079c015f5a4e3132305f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e7365742e2e4254726565536574244c54245424475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e636f6c6c6563742e2e46726f6d4974657261746f72244c54245424475424244754243966726f6d5f697465723137683865393137613335386432633634313145a1076d5f5a4e31307363616c655f696e666f35696d706c7335365f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302424524624542447542439747970655f696e666f3137686465303439376265633665313438623445a207755f5a4e31307363616c655f696e666f35696d706c7336345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024244c50244124432442245250242447542439747970655f696e666f3137683032343032303466343961646362366345a307755f5a4e31307363616c655f696e666f35696d706c7336345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024244c50244124432442245250242447542439747970655f696e666f3137683338616562623263383631333330393945a407755f5a4e31307363616c655f696e666f35696d706c7336345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024244c50244124432442245250242447542439747970655f696e666f3137683465383931393834353164373436663145a507755f5a4e31307363616c655f696e666f35696d706c7336345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024244c50244124432442245250242447542439747970655f696e666f3137686135393864323635336666633139646245a607755f5a4e31307363616c655f696e666f35696d706c7336345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024244c50244124432442245250242447542439747970655f696e666f3137686265616265663563626436326663386545a7077e5f5a4e31307363616c655f696e666f35696d706c7337335f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024247535622454247533622424753230244e24753564242447542439747970655f696e666f3137683837373365663339663464326662633845a8077e5f5a4e31307363616c655f696e666f35696d706c7337335f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024247535622454247533622424753230244e24753564242447542439747970655f696e666f3137686266663934386536613364636431636245a907ba015f5a4e313073705f72756e74696d6532307472616e73616374696f6e5f76616c6964697479315f3131345f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f72247532302473705f72756e74696d652e2e7472616e73616374696f6e5f76616c69646974792e2e56616c69645472616e73616374696f6e2447542439656e636f64655f746f3137683932643632336634356433613163656445aa07c2015f5a4e313073705f72756e74696d6532307472616e73616374696f6e5f76616c6964697479315f3132325f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f72247532302473705f72756e74696d652e2e7472616e73616374696f6e5f76616c69646974792e2e5472616e73616374696f6e56616c69646974794572726f722447542439656e636f64655f746f3137683866663031363537666337336132363545ab07bf015f5a4e3131315f244c54246672616d655f73797374656d2e2e70616c6c65742e2e43616c6c244c542454244754242475323024617324753230246672616d655f737570706f72742e2e7472616974732e2e64697370617463682e2e556e66696c7465726564446973706174636861626c6524475424323264697370617463685f6279706173735f66696c74657232385f24753762242475376224636c6f73757265247537642424753764243137686235383865363334323538373038363445ac0790015f5a4e3131325f244c542470616c6c65745f626162652e2e70616c6c65742e2e47656e65736973436f6e666967244c542454244754242475323024617324753230246672616d655f737570706f72742e2e7472616974732e2e686f6f6b732e2e4275696c6447656e65736973436f6e66696724475424356275696c643137683037613262636133366132616266616445ad07aa015f5a4e3131335f244c542470616c6c65745f626162652e2e70616c6c65742e2e50616c6c6574244c542454244754242475323024617324753230246672616d655f737570706f72742e2e7472616974732e2e686f6f6b732e2e4265666f7265416c6c52756e74696d654d6967726174696f6e732447542432396265666f72655f616c6c5f72756e74696d655f6d6967726174696f6e733137683065346136626334393135383062613245ae078a015f5a4e38345f244c54246672616d655f737570706f72742e2e7472616974732e2e6d657461646174612e2e53746f7261676556657273696f6e247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376863323937656563623863373563383766452e6c6c766d2e39343631363039353438343436323532303735af07c6015f5a4e3131385f244c542470616c6c65745f62616c616e6365732e2e70616c6c65742e2e43616c6c244c54245424432449244754242475323024617324753230246672616d655f737570706f72742e2e7472616974732e2e64697370617463682e2e556e66696c7465726564446973706174636861626c6524475424323264697370617463685f6279706173735f66696c74657232385f24753762242475376224636c6f73757265247537642424753764243137686433326539663565346335653235353845b0077d5f5a4e36395f244c5424616c6c6f632e2e626f7865642e2e426f78244c5424542443244124475424247532302461732475323024636f72652e2e636c6f6e652e2e436c6f6e652447542435636c6f6e6531376831376565303832613762326463353736452e6c6c766d2e39343631363039353438343436323532303735b107685f5a4e313170616c6c65745f6261626535345f244c5424696d706c247532302470616c6c65745f626162652e2e70616c6c65742e2e50616c6c6574244c542454244754242447542431306e6578745f65706f63683137683136663632663231306531353732396345b2076b5f5a4e313170616c6c65745f6261626535345f244c5424696d706c247532302470616c6c65745f626162652e2e70616c6c65742e2e50616c6c6574244c5424542447542424475424313363757272656e745f65706f63683137683963363535383962366139353862666545b307705f5a4e313170616c6c65745f6261626535345f244c5424696d706c247532302470616c6c65745f626162652e2e70616c6c65742e2e50616c6c6574244c54245424475424244754243138656e6163745f65706f63685f6368616e67653137683039336432646335303061633739393345b407715f5a4e313170616c6c65745f6261626535345f244c5424696d706c247532302470616c6c65745f626162652e2e70616c6c65742e2e50616c6c6574244c5424542447542424475424313973686f756c645f65706f63685f6368616e67653137686239306363633831366239653838646245b5074e5f5a4e313170616c6c65745f626162653670616c6c6574313550616c6c6574244c54245424475424313673746f726167655f6d657461646174613137683235626233396134643839356236613245b607575f5a4e313170616c6c65745f626162653670616c6c6574313550616c6c6574244c54245424475424323570616c6c65745f636f6e7374616e74735f6d657461646174613137686166333135303736303232313833373145b7078e015f5a4e313170616c6c65745f626162653670616c6c6574315f38355f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302470616c6c65745f626162652e2e70616c6c65742e2e43616c6c244c542454244754242447542439747970655f696e666f3137683339313262653331316166316435386545b8078f015f5a4e313170616c6c65745f626162653670616c6c6574315f38365f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302470616c6c65745f626162652e2e70616c6c65742e2e4572726f72244c542454244754242447542439747970655f696e666f3137683666313137333538656566303830373145b90798015f5a4e313170616c6c65745f626162653670616c6c6574315f39355f244c5424696d706c247532302473657264652e2e7365722e2e53657269616c697a652475323024666f72247532302470616c6c65745f626162652e2e70616c6c65742e2e47656e65736973436f6e666967244c54245424475424244754243973657269616c697a653137686263666137313832383731356563623545ba0798015f5a4e313170616c6c65745f626162653670616c6c6574315f39385f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f64652475323024666f72247532302470616c6c65745f626162652e2e70616c6c65742e2e43616c6c244c5424542447542424475424366465636f64653137683135303438653062653630326135656445bb079b015f5a4e313170616c6c65745f626162653670616c6c6574315f39385f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f72247532302470616c6c65745f626162652e2e70616c6c65742e2e43616c6c244c542454244754242447542439656e636f64655f746f3137683539336663663337626663366532663545bc079b015f5a4e313170616c6c65745f626162653670616c6c6574315f39385f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f72247532302470616c6c65745f626162652e2e70616c6c65742e2e43616c6c244c54245424475424244754243973697a655f68696e743137683964663930363632653766356161363045bd079c015f5a4e3132305f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e7365742e2e4254726565536574244c54245424475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e636f6c6c6563742e2e46726f6d4974657261746f72244c54245424475424244754243966726f6d5f697465723137686236353537653230613766343632663745be07aa015f5a4e3133385f244c542473705f72756e74696d652e2e67656e657269632e2e636865636b65645f65787472696e7369632e2e436865636b656445787472696e736963244c54244163636f756e74496424432443616c6c24432445787472612447542424753230246173247532302473705f72756e74696d652e2e7472616974732e2e4170706c7961626c6524475424356170706c793137686239633935636431396265636339316645bf07735f5a4e34636f726533707472353664726f705f696e5f706c616365244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c2447542431376865643735326330326539353332656332452e6c6c766d2e39343631363039353438343436323532303735c007ad015f5a4e3133385f244c542473705f72756e74696d652e2e67656e657269632e2e636865636b65645f65787472696e7369632e2e436865636b656445787472696e736963244c54244163636f756e74496424432443616c6c24432445787472612447542424753230246173247532302473705f72756e74696d652e2e7472616974732e2e4170706c7961626c65244754243876616c69646174653137686264386666643132653563316166666245c107485f5a4e3133656e7669726f6e6d656e74616c396c6f63616c5f6b657931374c6f63616c4b6579244c5424542447542434776974683137683232663162323039353639636464666445c207485f5a4e3133656e7669726f6e6d656e74616c396c6f63616c5f6b657931374c6f63616c4b6579244c5424542447542434776974683137683532316362643865313434646331653845c307485f5a4e3133656e7669726f6e6d656e74616c396c6f63616c5f6b657931374c6f63616c4b6579244c5424542447542434776974683137686136353839623338326365336532303545c407e0015f5a4e3134345f244c54247375627374726174655f746573745f72756e74696d652e2e7375627374726174655f746573745f70616c6c65742e2e70616c6c65742e2e43616c6c244c542454244754242475323024617324753230246672616d655f737570706f72742e2e7472616974732e2e64697370617463682e2e556e66696c7465726564446973706174636861626c6524475424323264697370617463685f6279706173735f66696c74657232385f24753762242475376224636c6f73757265247537642424753764243137686161626165313833653136633736316645c507485f5a4e3133656e7669726f6e6d656e74616c396c6f63616c5f6b657931374c6f63616c4b6579244c5424542447542434776974683137686530623431396530386539343037623345c6074a5f5a4e31336672616d655f737570706f7274323267656e657369735f6275696c6465725f68656c70657231306765745f7072657365743137686636343962323165643633353662323645c7074f5f5a4e34636f726533707472343564726f705f696e5f706c616365244c542473657264655f6a736f6e2e2e76616c75652e2e56616c7565244754243137683733356637666563393664656465613845c807645f5a4e3773705f636f72653663727970746f3953733538436f6465633235746f5f73733538636865636b5f776974685f76657273696f6e31376865323637376132633136346338303136452e6c6c766d2e39343631363039353438343436323532303735c9074b5f5a4e31336672616d655f737570706f7274323267656e657369735f6275696c6465725f68656c70657231316275696c645f73746174653137686435306265353165646563633930373045ca07535f5a4e31336672616d655f737570706f7274367472616974733773746f72616765313553746f72616765496e7374616e636531317072656669785f686173683137683132653939646132623161373536653145cb07535f5a4e31336672616d655f737570706f7274367472616974733773746f72616765313553746f72616765496e7374616e636531317072656669785f686173683137683937363037303730336132303835656145cc07a3015f5a4e31387061726974795f7363616c655f636f64656335636f6465633136696e6e65725f7475706c655f696d706c38345f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f722475323024244c5024503024432451302443245230245250242447542439656e636f64655f746f3137683631313139623830623437383439313745cd07475f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646531337573696e675f656e636f6465643137683261396461636530663964633761393245ce073f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f64653137683965663864643633313532343734653445cf07bd025f5a4e3237385f244c542470616c6c65745f626162652e2e70616c6c65742e2e50616c6c6574244c542454244754242475323024617324753230246672616d655f737570706f72742e2e7472616974732e2e686f6f6b732e2e4f6e46696e616c697a65244c5424244c5424244c5424244c5424542475323024617324753230246672616d655f73797374656d2e2e70616c6c65742e2e436f6e666967244754242e2e426c6f636b24753230246173247532302473705f72756e74696d652e2e7472616974732e2e48656164657250726f7669646572244754242e2e4865616465725424753230246173247532302473705f72756e74696d652e2e7472616974732e2e486561646572244754242e2e4e756d626572244754242447542431316f6e5f66696e616c697a653137683130663065333535613565633034383145d007c1025f5a4e3238305f244c542470616c6c65745f626162652e2e70616c6c65742e2e50616c6c6574244c542454244754242475323024617324753230246672616d655f737570706f72742e2e7472616974732e2e686f6f6b732e2e4f6e496e697469616c697a65244c5424244c5424244c5424244c5424542475323024617324753230246672616d655f73797374656d2e2e70616c6c65742e2e436f6e666967244754242e2e426c6f636b24753230246173247532302473705f72756e74696d652e2e7472616974732e2e48656164657250726f7669646572244754242e2e4865616465725424753230246173247532302473705f72756e74696d652e2e7472616974732e2e486561646572244754242e2e4e756d626572244754242447542431336f6e5f696e697469616c697a653137683532323039643163636332623664366245d107465f5a4e34315f244c54245424753230246173247532302473657264652e2e64652e2e45787065637465642447542433666d743137686137306565646538373033376166626445d207475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683265336435616636383537353430386545d307475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683434613634303666316265313261353745d407475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683764613033323564633637633134313445d507475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686266616664653532306364383336663945d607475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686466346237373361346665623739633145d707635f5a4e34355f244c5424244c502424525024247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376834303566303661613534323663666363452e6c6c766d2e39343631363039353438343436323532303735d80797015f5a4e34636f72653370747231313664726f705f696e5f706c616365244c5424245246242452462473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c542433325f7573697a6524432473705f636f72652e2e737232353531392e2e537232353531395075626c696354616724475424244754243137686433343161303565316536303537616445d907585f5a4e34636f726533707472323964726f705f696e5f706c616365244c5424244c5024245250242447542431376830653433316634653265363962306630452e6c6c766d2e39343631363039353438343436323532303735da074f5f5a4e34636f726533707472343564726f705f696e5f706c616365244c542473657264655f6a736f6e2e2e6572726f722e2e4572726f72244754243137686534363938663030393533343532613145db075e5f5a4e36355f244c542473705f636f72652e2e63727970746f2e2e5075626c69634572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686237303639316163613335313462346345dc07785f5a4e36365f244c5424542475323024617324753230247061726974795f7363616c655f636f6465632e2e64657074685f6c696d69742e2e4465636f64654c696d69742447542432376465636f64655f616c6c5f776974685f64657074685f6c696d69743137683039616266633131396433323330373245dd076d5f5a4e37355f244c5424747269655f64622e2e7472696564622e2e547269654442244c54244c24475424247532302461732475323024747269655f64622e2e54726965244c54244c2447542424475424386765745f776974683137683766356261393066306137383936633945de07bc015f5a4e3773705f636f726537737232353531393133335f244c5424696d706c247532302473657264652e2e64652e2e446573657269616c697a652475323024666f72247532302473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432473705f636f72652e2e737232353531392e2e537232353531395075626c696354616724475424244754243131646573657269616c697a653137686262303665643533353333663139393445df0799015f5a4e3773705f636f7265377372323535313933767266315f39395f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f64652475323024666f72247532302473705f636f72652e2e737232353531392e2e7672662e2e5672665369676e617475726524475424366465636f64653137686236636666643737393065363830636445e0079c015f5a4e3773705f636f7265377372323535313933767266315f39395f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f72247532302473705f636f72652e2e737232353531392e2e7672662e2e5672665369676e61747572652447542439656e636f64655f746f3137683438356234383663366364306433633545e107445f5a4e37747269655f6462367472696564623135547269654442244c54244c24475424313166657463685f76616c75653137686133303638623636643838303530363445e2074a5f5a4e37747269655f6462367472696564623135547269654442244c54244c2447542431376765745f7261775f6f725f6c6f6f6b75703137683839396361353734613134393163633545e3077b5f5a4e38385f244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432454244754242475323024617324753230247363616c655f696e666f2e2e54797065496e666f2447542439747970655f696e666f3137683538303231336363326563643032306445e4078b015f5a4e39355f244c542470616c6c65745f626162652e2e70616c6c65742e2e43616c6c244c542454244754242475323024617324753230246672616d655f737570706f72742e2e64697370617463682e2e4765744469737061746368496e666f2447542431376765745f64697370617463685f696e666f3137683964383838393334366463666261333945e507745f5a4e36325f244c542473705f72756e74696d652e2e44697370617463684572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376832343537376561373336343862333634452e6c6c766d2e34343635333131303635343831343136313531e60789015f5a4e31307363616c655f696e666f35696d706c7338345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024636f72652e2e726573756c742e2e526573756c74244c54245424432445244754242447542439747970655f696e666f3137683237633234346263613464343563366445e70789015f5a4e31307363616c655f696e666f35696d706c7338345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024636f72652e2e726573756c742e2e526573756c74244c54245424432445244754242447542439747970655f696e666f3137683338633839336262326233353965646145e80789015f5a4e31307363616c655f696e666f35696d706c7338345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024636f72652e2e726573756c742e2e526573756c74244c54245424432445244754242447542439747970655f696e666f3137686464616434303265373165386364363345e90789015f5a4e31307363616c655f696e666f35696d706c7338345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024636f72652e2e726573756c742e2e526573756c74244c54245424432445244754242447542439747970655f696e666f3137686666613866383636633261373263306445ea074a5f5a4e313073705f72756e74696d6536747261697473313656616c6964617465556e7369676e656431327072655f64697370617463683137683261623537386336646337666366393745eb07ac015f5a4e3132375f244c54247375627374726174655f746573745f72756e74696d652e2e7375627374726174655f746573745f70616c6c65742e2e70616c6c65742e2e50616c6c6574244c5424542447542424753230246173247532302473705f72756e74696d652e2e7472616974732e2e56616c6964617465556e7369676e656424475424313776616c69646174655f756e7369676e65643137683365306535333762383466316433333445ec07a2015f5a4e3132385f244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e642e2e547269654261636b656e64244c5424532443244824432443244324522447542424753230246173247532302473705f73746174655f6d616368696e652e2e6261636b656e642e2e4261636b656e64244c54244824475424244754243773746f726167653137683134306438336137373938393464326145ed0782015f5a4e34636f726533707472373164726f705f696e5f706c616365244c542473705f747269652e2e6572726f722e2e4572726f72244c54247072696d69746976655f74797065732e2e48323536244754242447542431376834613633653065376463303532303565452e6c6c766d2e34343635333131303635343831343136313531ee07ad015f5a4e3132395f244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e642e2e556e696d706c656d656e7465645265636f7264657250726f7669646572244c5424482447542424753230246173247532302473705f747269652e2e547269655265636f7264657250726f7669646572244c5424482447542424475424313661735f747269655f7265636f726465723137683936626163303934663037653363613045ef079a015f5a4e31326672616d655f73797374656d315f3130325f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230246672616d655f73797374656d2e2e4576656e745265636f7264244c54244524432454244754242447542439656e636f64655f746f3137686534346435323937393632363336383645f007b4015f5a4e31326672616d655f73797374656d315f3130335f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f73797374656d2e2e4163636f756e74496e666f244c54244e6f6e63652443244163636f756e7444617461244754242447542439747970655f696e666f31376861356339616239386635333233366263452e6c6c766d2e34343635333131303635343831343136313531f1078c015f5a4e31326672616d655f73797374656d315f38395f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f73797374656d2e2e4576656e745265636f7264244c54244524432454244754242447542439747970655f696e666f3137683561633331363564313635393565336645f20795015f5a4e31326672616d655f73797374656d315f39385f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f73797374656d2e2e436f646555706772616465417574686f72697a6174696f6e244c542454244754242447542439747970655f696e666f3137683263626564643639373935336164303745f30790015f5a4e31336672616d655f737570706f72743773746f72616765357479706573336d6170383153746f726167654d6170244c54245072656669782443244861736865722443244b657924432456616c756524432451756572794b696e642443244f6e456d7074792443244d617856616c756573244754243474616b653137683365343230316431333031303335653145f40799015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f72336d617037395f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f726167654d6170244c54244b24432456244754242475323024666f722475323024472447542431307472795f6d75746174653137683232613938646165323437376236366145f507605f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646531337573696e675f656e636f64656431376864346531326335346534623064376538452e6c6c766d2e34343635333131303635343831343136313531f60799015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f72336d617037395f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f726167654d6170244c54244b24432456244754242475323024666f722475323024472447542431307472795f6d75746174653137686463656538666461326632666138306345f707a0015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f72336d617037395f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f726167654d6170244c54244b24432456244754242475323024666f722475323024472447542431377472795f6d75746174655f6578697374733137686531333834333538366532383863653945f80791015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f72336d617037395f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f726167654d6170244c54244b24432456244754242475323024666f7224753230244724475424336765743137683030393039326162616232333938336245f90791015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f72336d617037395f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f726167654d6170244c54244b24432456244754242475323024666f7224753230244724475424336765743137683132633739353633636264663864376345fa0791015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f72336d617037395f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f726167654d6170244c54244b24432456244754242475323024666f7224753230244724475424336765743137683339343634353436316266393466336645fb0791015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f72336d617037395f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f726167654d6170244c54244b24432456244754242475323024666f7224753230244724475424336765743137683561343934343838353335343735636445fc0792015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f72336d617037395f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f726167654d6170244c54244b24432456244754242475323024666f72247532302447244754243474616b653137683535316530633332616638393233626245fd0794015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f72336d617037395f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f726167654d6170244c54244b24432456244754242475323024666f722475323024472447542436696e736572743137683366313030366364656537626234313345fe0794015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f72336d617037395f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f726167654d6170244c54244b24432456244754242475323024666f722475323024472447542436696e736572743137683533336434626134386462303233353745ff0794015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f72336d617037395f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f726167654d6170244c54244b24432456244754242475323024666f722475323024472447542436696e736572743137686462616363396637376564623432626145800894015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f72336d617037395f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f726167654d6170244c54244b24432456244754242475323024666f722475323024472447542436696e736572743137686531336639613466333237663362656145810894015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f72336d617037395f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f726167654d6170244c54244b24432456244754242475323024666f722475323024472447542436696e736572743137686562346335363162333939376639313045820894015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f72336d617037395f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f726167654d6170244c54244b24432456244754242475323024666f7224753230244724475424366d75746174653137683263323638653437306261303935363645830894015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f72336d617037395f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f726167654d6170244c54244b24432456244754242475323024666f7224753230244724475424366d75746174653137683365663539343766363638326535633445840894015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f72336d617037395f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f726167654d6170244c54244b24432456244754242475323024666f7224753230244724475424366d75746174653137683435373838366462343039353536336445850894015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f72336d617037395f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f726167654d6170244c54244b24432456244754242475323024666f72247532302447244754243672656d6f76653137683935636234333435313032666538393345860894015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f72336d617037395f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f726167654d6170244c54244b24432456244754242475323024666f72247532302447244754243672656d6f766531376839663430653730363033386464666339458708be015f5a4e3134365f244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e642e2e556e696d706c656d656e746564436163686550726f7669646572244c5424482447542424753230246173247532302473705f73746174655f6d616368696e652e2e747269655f6261636b656e642e2e54726965436163686550726f7669646572244c5424482447542424475424313661735f747269655f64625f636163686531376838343439306132336634343234613262458808c2015f5a4e3134365f244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e642e2e556e696d706c656d656e746564436163686550726f7669646572244c5424482447542424753230246173247532302473705f73746174655f6d616368696e652e2e747269655f6261636b656e642e2e54726965436163686550726f7669646572244c5424482447542424475424323061735f747269655f64625f6d75745f636163686531376861613462396464383762376235653361458908c7015f5a4e3135335f244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e642e2e556e696d706c656d656e746564436163686550726f7669646572244c54244824475424247532302461732475323024747269655f64622e2e547269654361636865244c542473705f747269652e2e6e6f64655f636f6465632e2e4e6f6465436f646563244c54244824475424244754242447542431386765745f6f725f696e736572745f6e6f646531376835626133383363343466666534366663458a08c8015f5a4e3135335f244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e642e2e556e696d706c656d656e746564436163686550726f7669646572244c54244824475424247532302461732475323024747269655f64622e2e547269654361636865244c542473705f747269652e2e6e6f64655f636f6465632e2e4e6f6465436f646563244c542448244754242447542424475424313963616368655f76616c75655f666f725f6b657931376863656663303636346664386465346366458b08c9015f5a4e3135335f244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e642e2e556e696d706c656d656e746564436163686550726f7669646572244c54244824475424247532302461732475323024747269655f64622e2e547269654361636865244c542473705f747269652e2e6e6f64655f636f6465632e2e4e6f6465436f646563244c54244824475424244754242447542432306c6f6f6b75705f76616c75655f666f725f6b657931376838363066376566333836626339386531458c08bc015f5a4e3135335f244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e642e2e556e696d706c656d656e746564436163686550726f7669646572244c54244824475424247532302461732475323024747269655f64622e2e547269654361636865244c542473705f747269652e2e6e6f64655f636f6465632e2e4e6f6465436f646563244c542448244754242447542424475424386765745f6e6f646531376866616537653961643963663838623238458d08d8015f5a4e3136315f244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e642e2e556e696d706c656d656e7465645265636f7264657250726f7669646572244c54244824475424247532302461732475323024747269655f64622e2e547269655265636f72646572244c5424244c542448247532302461732475323024686173685f64622e2e486173686572244754242e2e4f757424475424244754243237747269655f6e6f6465735f7265636f726465645f666f725f6b657931376865643932643636643639633037653066458e08c2015f5a4e3136315f244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e642e2e556e696d706c656d656e7465645265636f7264657250726f7669646572244c54244824475424247532302461732475323024747269655f64622e2e547269655265636f72646572244c5424244c542448247532302461732475323024686173685f64622e2e486173686572244754242e2e4f75742447542424475424367265636f726431376862353435343464666462323435643339458f08645f5a4e313673705f73746174655f6d616368696e6531376f7665726c617965645f6368616e67657332354f7665726c617965644368616e676573244c5424482447542431317365745f73746f7261676531376864333738646666366564376433343736459008655f5a4e313673705f73746174655f6d616368696e6531376f7665726c617965645f6368616e67657332354f7665726c617965644368616e676573244c54244824475424313273746f726167655f726f6f74313768383265626636626635666638623639634591085f5f5a4e313673705f73746174655f6d616368696e6531376f7665726c617965645f6368616e67657332354f7665726c617965644368616e676573244c542448244754243773746f7261676531376861346266363131363634356331623036459208475f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646531337573696e675f656e636f64656431376835653063643533316231623536346432459308475f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646531337573696e675f656e636f64656431376862343135656238373732383666333231459408475f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646531337573696e675f656e636f64656431376863313364623435363063653135323366459508585f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f646531376836386231353732613461613337306561452e6c6c766d2e3434363533313130363534383134313631353196083f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f646531376864353565386236353361656636306465459708ee015f5a4e3139365f244c54246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e6d61702e2e53746f726167654d6170244c54245072656669782443244861736865722443244b657924432456616c756524432451756572794b696e642443244f6e456d7074792443244d617856616c756573244754242475323024617324753230246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e53746f72616765456e7472794d657461646174614275696c6465722447542431346275696c645f6d6574616461746131376830393738326539643064303330383564459808ee015f5a4e3139365f244c54246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e6d61702e2e53746f726167654d6170244c54245072656669782443244861736865722443244b657924432456616c756524432451756572794b696e642443244f6e456d7074792443244d617856616c756573244754242475323024617324753230246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e53746f72616765456e7472794d657461646174614275696c6465722447542431346275696c645f6d6574616461746131376831363363656566303465366439633330459908cd015f5a4e3139626f756e6465645f636f6c6c656374696f6e733131626f756e6465645f766563315f3130385f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024626f756e6465645f636f6c6c656374696f6e732e2e626f756e6465645f7665632e2e426f756e646564566563244c54245424432453244754242447542439747970655f696e666f31376862336661666136623733383239343334452e6c6c766d2e343436353331313036353438313431363135319a08ee015f5a4e3139365f244c54246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e6d61702e2e53746f726167654d6170244c54245072656669782443244861736865722443244b657924432456616c756524432451756572794b696e642443244f6e456d7074792443244d617856616c756573244754242475323024617324753230246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e53746f72616765456e7472794d657461646174614275696c6465722447542431346275696c645f6d6574616461746131376831633132303730623963323465343636459b08ee015f5a4e3139365f244c54246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e6d61702e2e53746f726167654d6170244c54245072656669782443244861736865722443244b657924432456616c756524432451756572794b696e642443244f6e456d7074792443244d617856616c756573244754242475323024617324753230246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e53746f72616765456e7472794d657461646174614275696c6465722447542431346275696c645f6d6574616461746131376835663236666438376163623639386537459c08ee015f5a4e3139365f244c54246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e6d61702e2e53746f726167654d6170244c54245072656669782443244861736865722443244b657924432456616c756524432451756572794b696e642443244f6e456d7074792443244d617856616c756573244754242475323024617324753230246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e53746f72616765456e7472794d657461646174614275696c6465722447542431346275696c645f6d6574616461746131376836613032303264336364396638353538459d08cd015f5a4e3139626f756e6465645f636f6c6c656374696f6e733131626f756e6465645f766563315f3130385f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024626f756e6465645f636f6c6c656374696f6e732e2e626f756e6465645f7665632e2e426f756e646564566563244c54245424432453244754242447542439747970655f696e666f31376831313432386235313165633561633762452e6c6c766d2e343436353331313036353438313431363135319e08ee015f5a4e3139365f244c54246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e6d61702e2e53746f726167654d6170244c54245072656669782443244861736865722443244b657924432456616c756524432451756572794b696e642443244f6e456d7074792443244d617856616c756573244754242475323024617324753230246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e53746f72616765456e7472794d657461646174614275696c6465722447542431346275696c645f6d6574616461746131376837316230363031343636396137323261459f08cd015f5a4e3139626f756e6465645f636f6c6c656374696f6e733131626f756e6465645f766563315f3130385f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024626f756e6465645f636f6c6c656374696f6e732e2e626f756e6465645f7665632e2e426f756e646564566563244c54245424432453244754242447542439747970655f696e666f31376832396533346563346531636436636164452e6c6c766d2e34343635333131303635343831343136313531a008ee015f5a4e3139365f244c54246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e6d61702e2e53746f726167654d6170244c54245072656669782443244861736865722443244b657924432456616c756524432451756572794b696e642443244f6e456d7074792443244d617856616c756573244754242475323024617324753230246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e53746f72616765456e7472794d657461646174614275696c6465722447542431346275696c645f6d657461646174613137686165373162666362343635373764376445a108ee015f5a4e3139365f244c54246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e6d61702e2e53746f726167654d6170244c54245072656669782443244861736865722443244b657924432456616c756524432451756572794b696e642443244f6e456d7074792443244d617856616c756573244754242475323024617324753230246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e53746f72616765456e7472794d657461646174614275696c6465722447542431346275696c645f6d657461646174613137686533653833326139326662363061623445a208cd015f5a4e3139626f756e6465645f636f6c6c656374696f6e733131626f756e6465645f766563315f3130385f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024626f756e6465645f636f6c6c656374696f6e732e2e626f756e6465645f7665632e2e426f756e646564566563244c54245424432453244754242447542439747970655f696e666f31376838313839363565613438303932343866452e6c6c766d2e34343635333131303635343831343136313531a308b4015f5a4e3139626f756e6465645f636f6c6c656374696f6e733131626f756e6465645f766563315f3130385f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024626f756e6465645f636f6c6c656374696f6e732e2e626f756e6465645f7665632e2e426f756e646564566563244c54245424432453244754242447542439747970655f696e666f3137683632326164343332663330346262396345a408a3015f5a4e323073705f636f6e73656e7375735f6772616e647061315f3130335f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f6e73656e7375735f6772616e6470612e2e45717569766f636174696f6e50726f6f66244c5424482443244e244754242447542439747970655f696e666f3137683538356338616330396335303332313945a5089d015f5a4e323073705f636f6e73656e7375735f6772616e647061315f39385f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f6e73656e7375735f6772616e6470612e2e45717569766f636174696f6e244c5424482443244e244754242447542439747970655f696e666f3137683363373265306238366130306461393645a608465f5a4e34315f244c54245424753230246173247532302473657264652e2e64652e2e45787065637465642447542433666d743137683032383039393935386265613032383945a708475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686563323865313866636363343834663345a808305f5a4e346273353836656e636f64653131656e636f64655f696e746f3137686130653937303161376663656634306445a908b2015f5a4e34636f72653370747231313864726f705f696e5f706c616365244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e642e2e556e696d706c656d656e746564436163686550726f7669646572244c542473705f72756e74696d652e2e7472616974732e2e426c616b6554776f323536244754242447542431376837343366356666663932653264303539452e6c6c766d2e34343635333131303635343831343136313531aa083e5f5a4e34636f726533707472323864726f705f696e5f706c616365244c542424524624753136244754243137683665616535333638616239373933636345ab086d5f5a4e34636f726535617272617936395f244c5424696d706c2475323024636f72652e2e666d742e2e44656275672475323024666f722475323024247535622454247533622424753230244e24753564242447542433666d743137683664633539656264356333613331306245ac086d5f5a4e34636f726535617272617936395f244c5424696d706c2475323024636f72652e2e666d742e2e44656275672475323024666f722475323024247535622454247533622424753230244e24753564242447542433666d743137686439653333636131656461373437343445ad086e5f5a4e35365f244c5424627335382e2e656e636f64652e2e4572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376862623965643035343061613830346334452e6c6c766d2e34343635333131303635343831343136313531ae08785f5a4e36365f244c5424542475323024617324753230247061726974795f7363616c655f636f6465632e2e64657074685f6c696d69742e2e4465636f64654c696d69742447542432376465636f64655f616c6c5f776974685f64657074685f6c696d69743137683136396539656638656531346431363845af08645f5a4e37315f244c5424636f72652e2e6d61726b65722e2e5068616e746f6d44617461244c54245424475424247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686437323734313730623666356231363245b008425f5a4e3773705f636f72653333746f5f7375627374726174655f7761736d5f666e5f72657475726e5f76616c75653137683464623033656131363732616134663545b108425f5a4e3773705f636f72653333746f5f7375627374726174655f7761736d5f666e5f72657475726e5f76616c75653137686231336232306537636632336662643445b208425f5a4e3773705f636f72653333746f5f7375627374726174655f7761736d5f666e5f72657475726e5f76616c75653137686635343031646464316132656463633445b308485f5a4e37747269655f6462386974657261746f7232365472696544425261774974657261746f72244c54244c24475424336e65773137683334353433623139373032613932333845b4084e5f5a4e37747269655f6462386974657261746f7232365472696544425261774974657261746f72244c54244c24475424396e6578745f6974656d3137686266303663353063386165373336303745b5088a015f5a4e38345f244c54246672616d655f737570706f72742e2e7472616974732e2e6d657461646174612e2e53746f7261676556657273696f6e247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376863323937656563623863373563383766452e6c6c766d2e34343635333131303635343831343136313531b608775f5a4e32327375627374726174655f746573745f72756e74696d6532317375627374726174655f746573745f70616c6c65743670616c6c6574313550616c6c6574244c5424542447542432336465706f7369745f6c6f675f6469676573745f6974656d3137686232386631323733356335653335383645b708635f5a4e32327375627374726174655f746573745f72756e74696d6532317375627374726174655f746573745f70616c6c65743670616c6c6574313550616c6c6574244c5424542447542434726561643137683266363834653430643332626636633945b8086c5f5a4e32327375627374726174655f746573745f72756e74696d6532317375627374726174655f746573745f70616c6c65743670616c6c6574313550616c6c6574244c542454244754243132657865637574655f726561643137686630343132346630393935653161316445b9086e5f5a4e32327375627374726174655f746573745f72756e74696d6532317375627374726174655f746573745f70616c6c65743670616c6c6574313550616c6c6574244c542454244754243134726561645f616e645f70616e69633137683733613232323435393463353765653845ba08e0015f5a4e32327375627374726174655f746573745f72756e74696d6532317375627374726174655f746573745f70616c6c65743670616c6c6574315f3133325f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230247375627374726174655f746573745f72756e74696d652e2e7375627374726174655f746573745f70616c6c65742e2e70616c6c65742e2e43616c6c244c542454244754242447542439656e636f64655f746f3137686434366135336534363535303135373245bb08ae015f5a4e3132395f244c54247375627374726174655f746573745f72756e74696d652e2e7375627374726174655f746573745f70616c6c65742e2e70616c6c65742e2e43616c6c244c542454244754242475323024617324753230246672616d655f737570706f72742e2e64697370617463682e2e4765744469737061746368496e666f2447542431376765745f64697370617463685f696e666f3137683862336231613264376162303635323945bc08705f5a4e32327375627374726174655f746573745f72756e74696d6532317375627374726174655f746573745f70616c6c65743670616c6c6574313550616c6c6574244c54245424475424313673746f726167655f6d657461646174613137686337633866323336313830636435666145bd08cc015f5a4e3134375f244c54247375627374726174655f746573745f72756e74696d652e2e7375627374726174655f746573745f70616c6c65742e2e70616c6c65742e2e50616c6c6574244c542454244754242475323024617324753230246672616d655f737570706f72742e2e7472616974732e2e686f6f6b732e2e4265666f7265416c6c52756e74696d654d6967726174696f6e732447542432396265666f72655f616c6c5f72756e74696d655f6d6967726174696f6e733137686430646131386266373663636231393845be08dd015f5a4e32327375627374726174655f746573745f72756e74696d6532317375627374726174655f746573745f70616c6c65743670616c6c6574315f3132395f244c5424696d706c247532302473657264652e2e7365722e2e53657269616c697a652475323024666f7224753230247375627374726174655f746573745f72756e74696d652e2e7375627374726174655f746573745f70616c6c65742e2e70616c6c65742e2e47656e65736973436f6e666967244c54245424475424244754243973657269616c697a653137686465623536323735636339306430373645bf08cd015f5a4e32327375627374726174655f746573745f72756e74696d6532317375627374726174655f746573745f70616c6c65743670616c6c6574315f3131375f244c5424696d706c2475323024636f72652e2e636c6f6e652e2e436c6f6e652475323024666f7224753230247375627374726174655f746573745f72756e74696d652e2e7375627374726174655f746573745f70616c6c65742e2e70616c6c65742e2e43616c6c244c542454244754242447542435636c6f6e653137686637303937303464613631373164393245c008dd015f5a4e32327375627374726174655f746573745f72756e74696d6532317375627374726174655f746573745f70616c6c65743670616c6c6574315f3133325f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f64652475323024666f7224753230247375627374726174655f746573745f72756e74696d652e2e7375627374726174655f746573745f70616c6c65742e2e70616c6c65742e2e43616c6c244c5424542447542424475424366465636f64653137683964643330356239383635653137653945c108d3015f5a4e32327375627374726174655f746573745f72756e74696d6532317375627374726174655f746573745f70616c6c65743670616c6c6574315f3131395f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230247375627374726174655f746573745f72756e74696d652e2e7375627374726174655f746573745f70616c6c65742e2e70616c6c65742e2e43616c6c244c542454244754242447542439747970655f696e666f3137683636616437663531306639613865663045c208755f5a4e31307363616c655f696e666f35696d706c7336345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024244c50244124432442245250242447542439747970655f696e666f3137683439633735333166633935653437343145c30892015f5a4e313666696e616c6974795f6772616e647061315f39315f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302466696e616c6974795f6772616e6470612e2e507265636f6d6d6974244c5424482443244e244754242447542439747970655f696e666f3137683062383331356530383235316161616645c408755f5a4e31307363616c655f696e666f35696d706c7336345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024244c50244124432442245250242447542439747970655f696e666f3137683638363838646465613030663937626145c508755f5a4e31307363616c655f696e666f35696d706c7336345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024244c50244124432442245250242447542439747970655f696e666f3137686135643337336631363435356132383645c608755f5a4e31307363616c655f696e666f35696d706c7336345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024244c50244124432442245250242447542439747970655f696e666f3137686338333732643832633464313261646145c70890015f5a4e313666696e616c6974795f6772616e647061315f38395f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302466696e616c6974795f6772616e6470612e2e507265766f7465244c5424482443244e244754242447542439747970655f696e666f3137683631316165633464653435636165613945c8087d5f5a4e31307363616c655f696e666f35696d706c7337325f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024244c502441244324422443244324432444245250242447542439747970655f696e666f3137683134643531376233663132646366626245c908ba015f5a4e31326672616d655f73797374656d3130657874656e73696f6e733131636865636b5f6e6f6e6365315f3130395f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f6e6f6e63652e2e436865636b4e6f6e6365244c542454244754242447542439747970655f696e666f3137683966313231303161633862623464353545ca08b1015f5a4e32396672616d655f6d657461646174615f686173685f657874656e73696f6e315f3130385f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f6d657461646174615f686173685f657874656e73696f6e2e2e436865636b4d6574616461746148617368244c542454244754242447542439747970655f696e666f3137683563643234653436363135663765323145cb08bd015f5a4e31326672616d655f73797374656d3130657874656e73696f6e733132636865636b5f776569676874315f3131315f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f7765696768742e2e436865636b576569676874244c542454244754242447542439747970655f696e666f3137683466633431303934656430363432646445cc088a015f5a4e313073705f72756e74696d65315f38395f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f72247532302473705f72756e74696d652e2e44697370617463684572726f722447542439656e636f64655f746f3137683965396532323862323839366165363845cd08b5015f5a4e3131365f244c54246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f7765696768742e2e436865636b576569676874244c5424542447542424753230246173247532302473705f72756e74696d652e2e7472616974732e2e5369676e6564457874656e73696f6e244754243133706f73745f646973706174636831376862343833663134383166613630616464452e6c6c766d2e363831373539343630333232373130383833ce0891015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f723576616c756537375f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f7261676556616c7565244c542454244754242475323024666f7224753230244724475424336765743137686636383238623939366237653363313445cf08745f5a4e38375f244c54246672616d655f737570706f72742e2e64697370617463682e2e5065724469737061746368436c617373244c54245424475424247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686338356638316434306262626633386345d0083b5f5a4e31336672616d655f737570706f72743773746f7261676538756e686173686564336765743137686633343130326665633334346565636145d1085c5f5a4e34636f726533666d74336e756d35305f244c5424696d706c2475323024636f72652e2e666d742e2e44656275672475323024666f7224753230247533322447542433666d743137683039633433313131313862343839303145d208a9015f5a4e313170616c6c65745f626162653670616c6c65743131385f244c5424696d706c2475323024636f72652e2e636f6e766572742e2e46726f6d244c542470616c6c65745f626162652e2e70616c6c65742e2e4572726f72244c54245424475424244754242475323024666f72247532302473705f72756e74696d652e2e44697370617463684572726f72244754243466726f6d3137686264353735313430616262613433386345d3087e5f5a4e31326672616d655f73797374656d3130657874656e73696f6e733132636865636b5f7765696768743230436865636b576569676874244c542454244754243135646f5f7072655f646973706174636831376837313835366264363832363535663934452e6c6c766d2e363831373539343630333232373130383833d408aa015f5a4e3132355f244c5424244c50245475706c65456c656d656e74302443245475706c65456c656d656e74312443245475706c65456c656d656e74322443245475706c65456c656d656e74332452502424753230246173247532302473705f72756e74696d652e2e7472616974732e2e5369676e6564457874656e73696f6e2447542431376164646974696f6e616c5f7369676e65643137686562643666666362323432623862643745d5085f5f5a4e36365f244c5424636f72652e2e6f7074696f6e2e2e4f7074696f6e244c54245424475424247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686436653932303764623531313734353745d608aa015f5a4e3132355f244c5424244c50245475706c65456c656d656e74302443245475706c65456c656d656e74312443245475706c65456c656d656e74322443245475706c65456c656d656e74332452502424753230246173247532302473705f72756e74696d652e2e7472616974732e2e5369676e6564457874656e73696f6e24475424313776616c69646174655f756e7369676e65643137683463633738646162303064633965346345d708695f5a4e31326672616d655f73797374656d3130657874656e73696f6e733132636865636b5f7765696768743230436865636b576569676874244c542454244754243138636865636b5f626c6f636b5f6c656e6774683137686434373666396639323539346662356345d8086d5f5a4e31326672616d655f73797374656d3130657874656e73696f6e733132636865636b5f7765696768743230436865636b576569676874244c542454244754243232636865636b5f65787472696e7369635f7765696768743137683536643330386534616638383864346445d908a0015f5a4e3132355f244c5424244c50245475706c65456c656d656e74302443245475706c65456c656d656e74312443245475706c65456c656d656e74322443245475706c65456c656d656e74332452502424753230246173247532302473705f72756e74696d652e2e7472616974732e2e5369676e6564457874656e73696f6e24475424386d657461646174613137686261663864356538616533386436393545da08a0015f5a4e3132355f244c5424244c50245475706c65456c656d656e74302443245475706c65456c656d656e74312443245475706c65456c656d656e74322443245475706c65456c656d656e74332452502424753230246173247532302473705f72756e74696d652e2e7472616974732e2e5369676e6564457874656e73696f6e244754243876616c69646174653137683864383663336665373630656435383345db08495f5a4e34345f244c54242452462454247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d743137686663313736633761623337386434396445dc08ab015f5a4e31326672616d655f73797374656d3670616c6c65743131395f244c5424696d706c2475323024636f72652e2e636f6e766572742e2e46726f6d244c54246672616d655f73797374656d2e2e70616c6c65742e2e4572726f72244c54245424475424244754242475323024666f72247532302473705f72756e74696d652e2e44697370617463684572726f72244754243466726f6d3137683439323434396438616365353764653145dd083b5f5a4e31336672616d655f737570706f72743773746f7261676538756e686173686564336765743137683036383136373332313164353262333345de087a5f5a4e36395f244c54247061726974795f7363616c655f636f6465632e2e6572726f722e2e4572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376863636562313832636338343631643463452e6c6c766d2e363831373539343630333232373130383833df08715f5a4e36305f244c5424616c6c6f632e2e737472696e672e2e537472696e67247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d7431376838643930316130303836663739383732452e6c6c766d2e363831373539343630333232373130383833e008535f5a4e31336672616d655f737570706f72743773746f7261676538756e6861736865643367657431376831643061343633386265393631396331452e6c6c766d2e363831373539343630333232373130383833e1083b5f5a4e31336672616d655f737570706f72743773746f7261676538756e686173686564336765743137683233623431666266643334386335363145e208535f5a4e31336672616d655f737570706f72743773746f7261676538756e6861736865643367657431376834313365393366653631653239646364452e6c6c766d2e363831373539343630333232373130383833e308495f5a4e34345f244c54242452462454247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d743137683937303730333131386533396361383445e4083b5f5a4e31336672616d655f737570706f72743773746f7261676538756e686173686564336765743137683436336338663161383834343732396345e508535f5a4e31336672616d655f737570706f72743773746f7261676538756e6861736865643367657431376835636432353630346332363666343430452e6c6c766d2e363831373539343630333232373130383833e608535f5a4e31336672616d655f737570706f72743773746f7261676538756e6861736865643367657431376837623730613933656537623531353063452e6c6c766d2e363831373539343630333232373130383833e708535f5a4e31336672616d655f737570706f72743773746f7261676538756e6861736865643367657431376863383637363566636335633065356464452e6c6c766d2e363831373539343630333232373130383833e808535f5a4e31336672616d655f737570706f72743773746f7261676538756e6861736865643367657431376865333432316233616232383631316363452e6c6c766d2e363831373539343630333232373130383833e9083c5f5a4e31336672616d655f737570706f72743773746f7261676538756e6861736865643474616b653137683437343139656634653239653162313845ea0891015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f723576616c756537375f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f7261676556616c7565244c542454244754242475323024666f7224753230244724475424336765743137683035663333613639353237336438323845eb0891015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f723576616c756537375f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f7261676556616c7565244c542454244754242475323024666f7224753230244724475424336765743137683061643832313565643832663138306245ec0891015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f723576616c756537375f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f7261676556616c7565244c542454244754242475323024666f7224753230244724475424336765743137683635316662383361346237356438663545ed0891015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f723576616c756537375f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f7261676556616c7565244c542454244754242475323024666f7224753230244724475424336765743137683665656138393966373463623063626245ee0891015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f723576616c756537375f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f7261676556616c7565244c542454244754242475323024666f7224753230244724475424336765743137683839376231313230643762336633383045ef0891015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f723576616c756537375f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f7261676556616c7565244c542454244754242475323024666f7224753230244724475424336765743137686136326566613532663665366534663545f00891015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f723576616c756537375f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f7261676556616c7565244c542454244754242475323024666f7224753230244724475424337075743137683464303238656331373830313938316145f10891015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f723576616c756537375f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f7261676556616c7565244c542454244754242475323024666f7224753230244724475424337075743137683630343239373738333034626265323745f20891015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f723576616c756537375f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f7261676556616c7565244c542454244754242475323024666f7224753230244724475424337075743137686232386630373034616139633863323045f30891015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f723576616c756537375f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f7261676556616c7565244c542454244754242475323024666f7224753230244724475424337075743137686464383666303565653339396436343945f40892015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f723576616c756537375f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f7261676556616c7565244c542454244754242475323024666f72247532302447244754243474616b653137686561616132653936363865643839366645f50894015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f723576616c756537375f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f7261676556616c7565244c542454244754242475323024666f722475323024472447542436617070656e643137683762396565663239356265303763376645f60894015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f723576616c756537375f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f7261676556616c7565244c542454244754242475323024666f7224753230244724475424366d75746174653137683765303134326562633665633461373445f70894015f5a4e31336672616d655f737570706f72743773746f726167653967656e657261746f723576616c756537375f244c5424696d706c24753230246672616d655f737570706f72742e2e73746f726167652e2e53746f7261676556616c7565244c542454244754242475323024666f7224753230244724475424366d75746174653137686539666164356566636562633866376545f808b5015f5a4e313570616c6c65745f62616c616e6365733670616c6c65743132365f244c5424696d706c2475323024636f72652e2e636f6e766572742e2e46726f6d244c542470616c6c65745f62616c616e6365732e2e70616c6c65742e2e4572726f72244c5424542443244924475424244754242475323024666f72247532302473705f72756e74696d652e2e44697370617463684572726f72244754243466726f6d3137683565626264376664623235306333356445f908a5015f5a4e313666696e616c6974795f6772616e647061315f3131325f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f64652475323024666f72247532302466696e616c6974795f6772616e6470612e2e45717569766f636174696f6e244c5424496424432456244324532447542424475424366465636f64653137683438386439393231336237346338653345fa089a015f5a4e313666696e616c6974795f6772616e647061315f39395f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302466696e616c6974795f6772616e6470612e2e45717569766f636174696f6e244c542449642443245624432453244754242447542439747970655f696e666f3137683162346235636266336365393564306545fb089a015f5a4e313666696e616c6974795f6772616e647061315f39395f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302466696e616c6974795f6772616e6470612e2e45717569766f636174696f6e244c542449642443245624432453244754242447542439747970655f696e666f3137686434613034666430623365353738356345fc08d7015f5a4e3137335f244c54246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e76616c75652e2e53746f7261676556616c7565244c542450726566697824432456616c756524432451756572794b696e642443244f6e456d707479244754242475323024617324753230246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e53746f72616765456e7472794d657461646174614275696c6465722447542431346275696c645f6d657461646174613137683334636635333639306531323335363445fd08da015f5a4e3139626f756e6465645f636f6c6c656374696f6e7331367765616b5f626f756e6465645f766563315f3131375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024626f756e6465645f636f6c6c656374696f6e732e2e7765616b5f626f756e6465645f7665632e2e5765616b426f756e646564566563244c54245424432453244754242447542439747970655f696e666f31376833636465356335323837316365343634452e6c6c766d2e363831373539343630333232373130383833fe08d7015f5a4e3137335f244c54246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e76616c75652e2e53746f7261676556616c7565244c542450726566697824432456616c756524432451756572794b696e642443244f6e456d707479244754242475323024617324753230246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e53746f72616765456e7472794d657461646174614275696c6465722447542431346275696c645f6d657461646174613137683635653131633235303832396435613945ff08d7015f5a4e3137335f244c54246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e76616c75652e2e53746f7261676556616c7565244c542450726566697824432456616c756524432451756572794b696e642443244f6e456d707479244754242475323024617324753230246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e53746f72616765456e7472794d657461646174614275696c6465722447542431346275696c645f6d6574616461746131376838663536326335373535366132393065458009d7015f5a4e3137335f244c54246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e76616c75652e2e53746f7261676556616c7565244c542450726566697824432456616c756524432451756572794b696e642443244f6e456d707479244754242475323024617324753230246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e53746f72616765456e7472794d657461646174614275696c6465722447542431346275696c645f6d6574616461746131376861303465656238663230616331386466458109d7015f5a4e3137335f244c54246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e76616c75652e2e53746f7261676556616c7565244c542450726566697824432456616c756524432451756572794b696e642443244f6e456d707479244754242475323024617324753230246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e53746f72616765456e7472794d657461646174614275696c6465722447542431346275696c645f6d6574616461746131376861666134363039313236646232313231458209d7015f5a4e3137335f244c54246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e76616c75652e2e53746f7261676556616c7565244c542450726566697824432456616c756524432451756572794b696e642443244f6e456d707479244754242475323024617324753230246672616d655f737570706f72742e2e73746f726167652e2e74797065732e2e53746f72616765456e7472794d657461646174614275696c6465722447542431346275696c645f6d6574616461746131376865623265633538366362313934663265458309475f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646531337573696e675f656e636f646564313768613630613131333835366232303766364584093f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f646531376866373263386264306633376532366462458509c2015f5a4e3139626f756e6465645f636f6c6c656374696f6e7331367765616b5f626f756e6465645f766563315f3131375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024626f756e6465645f636f6c6c656374696f6e732e2e7765616b5f626f756e6465645f7665632e2e5765616b426f756e646564566563244c54245424432453244754242447542439747970655f696e666f31376837303164363330393765353933386132458609475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376831313936306663346334646135633161458709475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376831623562656336363136343663626563458809475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376831643033326265636338323865306333458909475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376832346662326634333933653362343162458a09475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376832366333383762396631376139656363458b09475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376832623735333133343339346638353237458c09475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376834353536346165356364626339663031458d09475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376835616131386563386630363065383432458e09475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376836323262373135613565383538363633458f09475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376837303231316436326463313864646464459009475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376838343635316636316232393039316464459109475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376839333934316436373961663662373832459209475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376839346165383636643238376263393861459309475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376861303161366163343165306366643533459409475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376861353032313234663738316561373966459509475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376861373365306230313439343134336238459609475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376862613137393863316561316362313731459709475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376863396234613936653964613066323064459809475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376864636330323831373936336234646236459909475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376865333865346161343334646262613365459a09495f5a4e34345f244c54242452462454247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d7431376838656231313430646437633330646531459b095b5f5a4e34636f726533666d74336e756d34395f244c5424696d706c2475323024636f72652e2e666d742e2e44656275672475323024666f72247532302475382447542433666d7431376838366432656134356430313966386636459c095c5f5a4e34636f726533666d74336e756d35305f244c5424696d706c2475323024636f72652e2e666d742e2e44656275672475323024666f7224753230247536342447542433666d7431376832643962636565363333316266326131459d0993015f5a4e34636f72653370747231313264726f705f696e5f706c616365244c5424245246246672616d655f6d657461646174615f686173685f657874656e73696f6e2e2e436865636b4d6574616461746148617368244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242447542431376837393734336537333833613137326366459e09395f5a4e34636f726533707472323364726f705f696e5f706c616365244c542475382447542431376831363136316234616634343531613863459f093a5f5a4e34636f726533707472323464726f705f696e5f706c616365244c5424753634244754243137683064326333386435323663323762613145a009685f5a4e34636f726533707472343664726f705f696e5f706c616365244c5424616c6c6f632e2e7665632e2e566563244c54247538244754242447542431376838343231626263386233396462633533452e6c6c766d2e363831373539343630333232373130383833a1096b5f5a4e34636f726533707472343964726f705f696e5f706c616365244c5424616c6c6f632e2e737472696e672e2e46726f6d557466384572726f722447542431376836313730643138326564656234646266452e6c6c766d2e363831373539343630333232373130383833a2096f5f5a4e34636f726533707472353364726f705f696e5f706c616365244c54247061726974795f7363616c655f636f6465632e2e6572726f722e2e4572726f722447542431376866386339663061313434386130383237452e6c6c766d2e363831373539343630333232373130383833a309355f5a4e34636f72653970616e69636b696e6731336173736572745f6661696c65643137683265396463363139363632653336383145a409355f5a4e34636f72653970616e69636b696e6731336173736572745f6661696c65643137683265613064613961633530303030666145a509355f5a4e34636f72653970616e69636b696e6731336173736572745f6661696c65643137683432386631303536353936666339323945a609355f5a4e34636f72653970616e69636b696e6731336173736572745f6661696c65643137683630383339323439356531643537633845a709355f5a4e34636f72653970616e69636b696e6731336173736572745f6661696c65643137683736373833396463323062393162303445a809685f5a4e35616c6c6f633131636f6c6c656374696f6e73397665635f646571756532315665634465717565244c54245424432441244754243467726f7731376831343964363038613963613634393962452e6c6c766d2e363831373539343630333232373130383833a909625f5a4e36305f244c5424245246246d7574247532302454247532302461732475323024627335382e2e656e636f64652e2e456e636f6465546172676574244754243131656e636f64655f776974683137683261366439363839646263373632643945aa09765f5a4e36355f244c5424616c6c6f632e2e737472696e672e2e46726f6d557466384572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376835393137346462613138663336353532452e6c6c766d2e363831373539343630333232373130383833ab095e5f5a4e36355f244c542473705f636f72652e2e63727970746f2e2e5075626c69634572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686237303639316163613335313462346345ac095f5f5a4e36365f244c542473705f776569676874732e2e7765696768745f76322e2e576569676874247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683333346365376538623833366664373445ad09655f5a4e37325f244c54246672616d655f6d657461646174615f686173685f657874656e73696f6e2e2e4d6f6465247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683135396330356432356335393231666445ae096b5f5a4e37325f244c542473705f636f6e73656e7375735f626162652e2e6170702e2e5075626c696324753230246173247532302473657264652e2e7365722e2e53657269616c697a65244754243973657269616c697a653137686665326364396132633536316361613545af096f5f5a4e37335f244c542473705f636f6e73656e7375735f626162652e2e6170702e2e5075626c696324753230246173247532302473657264652e2e64652e2e446573657269616c697a65244754243131646573657269616c697a653137683939353933646237663863393633396145b0096d5f5a4e38305f244c54246672616d655f6d657461646174615f686173685f657874656e73696f6e2e2e4d6574616461746148617368247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686166616464303364353963333234666145b1099a015f5a4e32327375627374726174655f746573745f72756e74696d65315f39335f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230247375627374726174655f746573745f72756e74696d652e2e436865636b53756273747261746543616c6c2447542439747970655f696e666f3137686539626263343730666536333261313745b209485f5a4e313274726163696e675f636f72653863616c6c736974653843616c6c736974653135707269766174655f747970655f69643137683563306264636438373465386266306445b309a8015f5a4e3133375f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e64656475705f736f727465645f697465722e2e4465647570536f7274656449746572244c54244b244324562443244924475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e6974657261746f722e2e4974657261746f7224475424346e6578743137683738623766316330343166653262353845b409af015f5a4e3133375f244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e645f657373656e63652e2e457068656d6572616c244c5424532443244824475424247532302461732475323024686173685f64622e2e4173486173684442244c542448244324616c6c6f632e2e7665632e2e566563244c54247538244754242447542424475424313061735f686173685f64623137683733386430313837383861646531326145b509b3015f5a4e3133375f244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e645f657373656e63652e2e457068656d6572616c244c5424532443244824475424247532302461732475323024686173685f64622e2e4173486173684442244c542448244324616c6c6f632e2e7665632e2e566563244c54247538244754242447542424475424313461735f686173685f64625f6d75743137686331333132653035396136626533366245b609cb015f5a4e3136375f244c542473657264652e2e64652e2e696d706c732e2e244c5424696d706c247532302473657264652e2e64652e2e446573657269616c697a652475323024666f722475323024616c6c6f632e2e7665632e2e566563244c54245424475424244754242e2e646573657269616c697a652e2e56656356697369746f72244c5424542447542424753230246173247532302473657264652e2e64652e2e56697369746f72244754243976697369745f7365713137683338333865383832656362346165663345b709475f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646531337573696e675f656e636f6465643137686133653531353133396262646461613545b809a0015f5a4e32327375627374726174655f746573745f72756e74696d65315f39395f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c2447542439656e636f64655f746f3137686539363262326538393264613935626545b909585f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f646531376834343338643261363832646166643934452e6c6c766d2e32383034353134343737303732373934353638ba093f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f64653137683830336232383263646337663632666445bb09465f5a4e34315f244c54245424753230246173247532302473657264652e2e64652e2e45787065637465642447542433666d743137683266313238633266393938656161616645bc09465f5a4e34315f244c54245424753230246173247532302473657264652e2e64652e2e45787065637465642447542433666d743137683663393365316631306530376535306445bd09465f5a4e34315f244c54245424753230246173247532302473657264652e2e64652e2e45787065637465642447542433666d743137683830653964343161386331306139636345be09465f5a4e34315f244c54245424753230246173247532302473657264652e2e64652e2e45787065637465642447542433666d743137686164373265356439313463346166366145bf09465f5a4e34315f244c54245424753230246173247532302473657264652e2e64652e2e45787065637465642447542433666d743137686531393635393636343265396564303645c009465f5a4e34315f244c54245424753230246173247532302473657264652e2e64652e2e45787065637465642447542433666d743137686563333138356165653831643066653645c109475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686161373834363830643961643162383545c209635f5a4e34355f244c5424244c502424525024247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376834303566303661613534323663666363452e6c6c766d2e32383034353134343737303732373934353638c309515f5a4e34636f7265336f70733866756e6374696f6e35466e4d75743863616c6c5f6d757431376864643638666565636462316135306133452e6c6c766d2e32383034353134343737303732373934353638c409735f5a4e34636f7265336f70733866756e6374696f6e36466e4f6e6365343063616c6c5f6f6e636524753762242475376224767461626c652e7368696d2475376424247537642431376830623662356162393134373765373065452e6c6c766d2e32383034353134343737303732373934353638c509b9015f5a4e34636f72653370747231323564726f705f696e5f706c616365244c542473657264652e2e64652e2e696d706c732e2e244c5424696d706c247532302473657264652e2e64652e2e446573657269616c697a652475323024666f722475323024753634244754242e2e646573657269616c697a652e2e5072696d697469766556697369746f722447542431376832633438373739393063633837336265452e6c6c766d2e32383034353134343737303732373934353638c609ce015f5a4e34636f72653370747231373164726f705f696e5f706c616365244c54246d656d6f72795f64622e2e4d656d6f72794442244c542473705f72756e74696d652e2e7472616974732e2e426c616b6554776f3235362443246d656d6f72795f64622e2e50726566697865644b6579244c542473705f72756e74696d652e2e7472616974732e2e426c616b6554776f32353624475424244324616c6c6f632e2e7665632e2e566563244c542475382447542424475424244754243137686461333031613034303666356666306445c709a5025f5a4e34636f72653370747232353864726f705f696e5f706c616365244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e645f657373656e63652e2e457068656d6572616c244c54246d656d6f72795f64622e2e4d656d6f72794442244c542473705f72756e74696d652e2e7472616974732e2e426c616b6554776f3235362443246d656d6f72795f64622e2e486173684b6579244c542473705f72756e74696d652e2e7472616974732e2e426c616b6554776f32353624475424244324616c6c6f632e2e7665632e2e566563244c54247538244754242447542424432473705f72756e74696d652e2e7472616974732e2e426c616b6554776f32353624475424244754243137683265326562643765346433373065386545c80992045f5a4e34636f72653370747234373064726f705f696e5f706c616365244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e645f657373656e63652e2e547269654261636b656e64457373656e6365244c54246d656d6f72795f64622e2e4d656d6f72794442244c542473705f72756e74696d652e2e7472616974732e2e426c616b6554776f3235362443246d656d6f72795f64622e2e486173684b6579244c542473705f72756e74696d652e2e7472616974732e2e426c616b6554776f32353624475424244324616c6c6f632e2e7665632e2e566563244c54247538244754242447542424432473705f72756e74696d652e2e7472616974732e2e426c616b6554776f32353624432473705f73746174655f6d616368696e652e2e747269655f6261636b656e642e2e556e696d706c656d656e746564436163686550726f7669646572244c542473705f72756e74696d652e2e7472616974732e2e426c616b6554776f3235362447542424432473705f73746174655f6d616368696e652e2e747269655f6261636b656e642e2e556e696d706c656d656e7465645265636f7264657250726f7669646572244c542473705f72756e74696d652e2e7472616974732e2e426c616b6554776f32353624475424244754242447542431376864343233326631353931363835616634452e6c6c766d2e32383034353134343737303732373934353638c909735f5a4e34636f726533707472353664726f705f696e5f706c616365244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c2447542431376865643735326330326539353332656332452e6c6c766d2e32383034353134343737303732373934353638ca09695f5a4e34636f726533707472373164726f705f696e5f706c616365244c542473705f747269652e2e6572726f722e2e4572726f72244c54247072696d69746976655f74797065732e2e4832353624475424244754243137683461363365306537646330353230356545cb096c5f5a4e34636f726533707472373464726f705f696e5f706c616365244c5424636f72652e2e6f7074696f6e2e2e4f7074696f6e244c5424616c6c6f632e2e7665632e2e566563244c542475382447542424475424244754243137683465633563653962343563363036306145cc09635f5a4e37305f244c5424636f72652e2e726573756c742e2e526573756c74244c5424542443244524475424247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683433376161653961336434353232303345cd096c5f5a4e37395f244c542474726163696e675f636f72652e2e6669656c642e2e446973706c617956616c7565244c54245424475424247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683731663366343637386639633833356145ce09305f5a4e3773705f74726965313564656c74615f747269655f726f6f743137683132363765636536363430333138393245cf09305f5a4e3773705f74726965313564656c74615f747269655f726f6f743137686234366236343335666436393337363645d009365f5a4e3773705f7472696532316368696c645f64656c74615f747269655f726f6f743137683336613536633230386630316331636345d109365f5a4e3773705f7472696532316368696c645f64656c74615f747269655f726f6f743137686131623063316635363531393665303445d209735f5a4e38365f244c542473705f747269652e2e4b657953706163656444424d7574244c542444422443244824475424247532302461732475323024686173685f64622e2e486173684442244c542448244324542447542424475424336765743137686336356265633939363937353031303845d309765f5a4e38365f244c542473705f747269652e2e4b657953706163656444424d7574244c542444422443244824475424247532302461732475323024686173685f64622e2e486173684442244c54244824432454244754242447542436696e736572743137683331323562383037323935343434366145d409765f5a4e38365f244c542473705f747269652e2e4b657953706163656444424d7574244c542444422443244824475424247532302461732475323024686173685f64622e2e486173684442244c5424482443245424475424244754243672656d6f76653137686662363563663966306264626433363945d509775f5a4e38365f244c542473705f747269652e2e4b657953706163656444424d7574244c542444422443244824475424247532302461732475323024686173685f64622e2e486173684442244c54244824432454244754242447542437656d706c6163653137683161613861333239633037343236366445d609785f5a4e38365f244c542473705f747269652e2e4b657953706163656444424d7574244c542444422443244824475424247532302461732475323024686173685f64622e2e486173684442244c54244824432454244754242447542438636f6e7461696e733137686337663665353265646334323730376645d7097d5f5a4e38385f244c54246d656d6f72795f64622e2e4d656d6f72794442244c5424482443244b462443245424475424247532302461732475323024686173685f64622e2e4173486173684442244c542448244324542447542424475424313061735f686173685f64623137686265373334373938313031643634373545d80981015f5a4e38385f244c54246d656d6f72795f64622e2e4d656d6f72794442244c5424482443244b462443245424475424247532302461732475323024686173685f64622e2e4173486173684442244c542448244324542447542424475424313461735f686173685f64625f6d75743137683234396363393830393034333434663145d9097d5f5a4e38385f244c542473705f747269652e2e4b657953706163656444424d7574244c542444422443244824475424247532302461732475323024686173685f64622e2e4173486173684442244c542448244324542447542424475424313061735f686173685f64623137683932383034353935303636636632373945da0981015f5a4e38385f244c542473705f747269652e2e4b657953706163656444424d7574244c542444422443244824475424247532302461732475323024686173685f64622e2e4173486173684442244c542448244324542447542424475424313461735f686173685f64625f6d75743137683038386363646330333432396164343645db09795f5a4e38395f244c542474726163696e675f636f72652e2e6669656c642e2e446973706c617956616c7565244c5424542447542424753230246173247532302474726163696e675f636f72652e2e6669656c642e2e56616c756524475424367265636f72643137683632313736663931616432666139396645dc097e5f5a4e39325f244c542474726163696e675f636f72652e2e63616c6c736974652e2e44656661756c7443616c6c7369746524753230246173247532302474726163696e675f636f72652e2e63616c6c736974652e2e43616c6c7369746524475424386d657461646174613137683032373862373566376265346534323345dd0989015f5a4e39385f244c54247375627374726174655f746573745f72756e74696d652e2e436865636b53756273747261746543616c6c24753230246173247532302473705f72756e74696d652e2e7472616974732e2e5369676e6564457874656e73696f6e2447542431327072655f64697370617463683137683730356533303231333030653331643745de095b5f5a4e32327375627374726174655f746573745f72756e74696d65313762656e63686d61726b5f6164645f6f6e6531376864333461666361623764633464303137452e6c6c766d2e32383034353134343737303732373934353638df09a2015f5a4e32327375627374726174655f746573745f72756e74696d65315f3130305f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230247375627374726174655f746573745f72756e74696d652e2e5472616e73666572446174612447542439656e636f64655f746f3137686431396234356235633363323632386445e00994015f5a4e32327375627374726174655f746573745f72756e74696d65315f38375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230247375627374726174655f746573745f72756e74696d652e2e5472616e73666572446174612447542439747970655f696e666f3137686230363038376636353061666534373845e1097f5f5a4e39385f244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65426c6f636b57656967687473247532302461732475323024626f756e6465645f636f6c6c656374696f6e732e2e476574244c54245f492447542424475424336765743137683763333838653230303264616462323045e209455f5a4e32327375627374726174655f746573745f72756e74696d65313153657373696f6e4b6579733867656e65726174653137686137353433623064623231663463323145e309525f5a4e32327375627374726174655f746573745f72756e74696d65313153657373696f6e4b6579733230696e746f5f7261775f7075626c69635f6b6579733137686166383865613065633061663336376445e4095d5f5a4e32327375627374726174655f746573745f72756e74696d653752756e74696d6531316d657461646174615f697231376833376263393537633561663737366534452e6c6c766d2e32383034353134343737303732373934353638e509da075f5a4e3933385f244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d6524753230246173247532302473705f7472616e73616374696f6e5f706f6f6c2e2e72756e74696d655f6170692e2e72756e74696d655f6465636c5f666f725f7461676765645f7472616e73616374696f6e5f71756575652e2e5461676765645472616e73616374696f6e51756575655633244c542473705f72756e74696d652e2e67656e657269632e2e626c6f636b2e2e426c6f636b244c542473705f72756e74696d652e2e67656e657269632e2e6865616465722e2e486561646572244c542475363424432473705f72756e74696d652e2e7472616974732e2e426c616b6554776f3235362447542424432473705f72756e74696d652e2e67656e657269632e2e756e636865636b65645f65787472696e7369632e2e556e636865636b656445787472696e736963244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432473705f636f72652e2e737232353531392e2e537232353531395075626c6963546167244754242443247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c24432473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f244324244c502473705f636f72652e2e63727970746f5f62797465732e2e7369676e61747572655f62797465732e2e5369676e617475726554616724432473705f636f72652e2e737232353531392e2e537232353531395461672452502424475424244324244c50246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f6e6f6e63652e2e436865636b4e6f6e6365244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f7765696768742e2e436865636b576569676874244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443247375627374726174655f746573745f72756e74696d652e2e436865636b53756273747261746543616c6c2443246672616d655f6d657461646174615f686173685f657874656e73696f6e2e2e436865636b4d6574616461746148617368244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242452502424475424244754242447542424475424323076616c69646174655f7472616e73616374696f6e3137686363623362633033333064313535353745e609a4075f5a4e3839375f244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d652475323024617324753230247375627374726174655f746573745f72756e74696d652e2e72756e74696d655f6465636c5f666f725f746573745f6170692e2e546573744150495632244c542473705f72756e74696d652e2e67656e657269632e2e626c6f636b2e2e426c6f636b244c542473705f72756e74696d652e2e67656e657269632e2e6865616465722e2e486561646572244c542475363424432473705f72756e74696d652e2e7472616974732e2e426c616b6554776f3235362447542424432473705f72756e74696d652e2e67656e657269632e2e756e636865636b65645f65787472696e7369632e2e556e636865636b656445787472696e736963244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432473705f636f72652e2e737232353531392e2e537232353531395075626c6963546167244754242443247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c24432473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f244324244c502473705f636f72652e2e63727970746f5f62797465732e2e7369676e61747572655f62797465732e2e5369676e617475726554616724432473705f636f72652e2e737232353531392e2e537232353531395461672452502424475424244324244c50246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f6e6f6e63652e2e436865636b4e6f6e6365244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f7765696768742e2e436865636b576569676874244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443247375627374726174655f746573745f72756e74696d652e2e436865636b53756273747261746543616c6c2443246672616d655f6d657461646174615f686173685f657874656e73696f6e2e2e436865636b4d6574616461746148617368244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242452502424475424244754242447542424475424387573655f747269653137686363326261656138653839373635656445e709b0075f5a4e3839375f244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d652475323024617324753230247375627374726174655f746573745f72756e74696d652e2e72756e74696d655f6465636c5f666f725f746573745f6170692e2e546573744150495632244c542473705f72756e74696d652e2e67656e657269632e2e626c6f636b2e2e426c6f636b244c542473705f72756e74696d652e2e67656e657269632e2e6865616465722e2e486561646572244c542475363424432473705f72756e74696d652e2e7472616974732e2e426c616b6554776f3235362447542424432473705f72756e74696d652e2e67656e657269632e2e756e636865636b65645f65787472696e7369632e2e556e636865636b656445787472696e736963244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432473705f636f72652e2e737232353531392e2e537232353531395075626c6963546167244754242443247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c24432473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f244324244c502473705f636f72652e2e63727970746f5f62797465732e2e7369676e61747572655f62797465732e2e5369676e617475726554616724432473705f636f72652e2e737232353531392e2e537232353531395461672452502424475424244324244c50246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f6e6f6e63652e2e436865636b4e6f6e6365244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f7765696768742e2e436865636b576569676874244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443247375627374726174655f746573745f72756e74696d652e2e436865636b53756273747261746543616c6c2443246672616d655f6d657461646174615f686173685f657874656e73696f6e2e2e436865636b4d6574616461746148617368244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d652447542424525024244754242447542424475424244754243139746573745f656432353531395f63727970746f3137683436633632326563353036636666653245e809b0075f5a4e3839375f244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d652475323024617324753230247375627374726174655f746573745f72756e74696d652e2e72756e74696d655f6465636c5f666f725f746573745f6170692e2e546573744150495632244c542473705f72756e74696d652e2e67656e657269632e2e626c6f636b2e2e426c6f636b244c542473705f72756e74696d652e2e67656e657269632e2e6865616465722e2e486561646572244c542475363424432473705f72756e74696d652e2e7472616974732e2e426c616b6554776f3235362447542424432473705f72756e74696d652e2e67656e657269632e2e756e636865636b65645f65787472696e7369632e2e556e636865636b656445787472696e736963244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432473705f636f72652e2e737232353531392e2e537232353531395075626c6963546167244754242443247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c24432473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f244324244c502473705f636f72652e2e63727970746f5f62797465732e2e7369676e61747572655f62797465732e2e5369676e617475726554616724432473705f636f72652e2e737232353531392e2e537232353531395461672452502424475424244324244c50246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f6e6f6e63652e2e436865636b4e6f6e6365244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f7765696768742e2e436865636b576569676874244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443247375627374726174655f746573745f72756e74696d652e2e436865636b53756273747261746543616c6c2443246672616d655f6d657461646174615f686173685f657874656e73696f6e2e2e436865636b4d6574616461746148617368244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d652447542424525024244754242447542424475424244754243139746573745f737232353531395f63727970746f3137683436333437616266653366313064613545e909ae075f5a4e3839375f244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d652475323024617324753230247375627374726174655f746573745f72756e74696d652e2e72756e74696d655f6465636c5f666f725f746573745f6170692e2e546573744150495632244c542473705f72756e74696d652e2e67656e657269632e2e626c6f636b2e2e426c6f636b244c542473705f72756e74696d652e2e67656e657269632e2e6865616465722e2e486561646572244c542475363424432473705f72756e74696d652e2e7472616974732e2e426c616b6554776f3235362447542424432473705f72756e74696d652e2e67656e657269632e2e756e636865636b65645f65787472696e7369632e2e556e636865636b656445787472696e736963244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432473705f636f72652e2e737232353531392e2e537232353531395075626c6963546167244754242443247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c24432473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f244324244c502473705f636f72652e2e63727970746f5f62797465732e2e7369676e61747572655f62797465732e2e5369676e617475726554616724432473705f636f72652e2e737232353531392e2e537232353531395461672452502424475424244324244c50246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f6e6f6e63652e2e436865636b4e6f6e6365244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f7765696768742e2e436865636b576569676874244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443247375627374726174655f746573745f72756e74696d652e2e436865636b53756273747261746543616c6c2443246672616d655f6d657461646174615f686173685f657874656e73696f6e2e2e436865636b4d6574616461746148617368244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d652447542424525024244754242447542424475424244754243137746573745f65636473615f63727970746f3137683437646132616337383833366533353745ea09a9075f5a4e3839375f244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d652475323024617324753230247375627374726174655f746573745f72756e74696d652e2e72756e74696d655f6465636c5f666f725f746573745f6170692e2e546573744150495632244c542473705f72756e74696d652e2e67656e657269632e2e626c6f636b2e2e426c6f636b244c542473705f72756e74696d652e2e67656e657269632e2e6865616465722e2e486561646572244c542475363424432473705f72756e74696d652e2e7472616974732e2e426c616b6554776f3235362447542424432473705f72756e74696d652e2e67656e657269632e2e756e636865636b65645f65787472696e7369632e2e556e636865636b656445787472696e736963244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432473705f636f72652e2e737232353531392e2e537232353531395075626c6963546167244754242443247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c24432473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f244324244c502473705f636f72652e2e63727970746f5f62797465732e2e7369676e61747572655f62797465732e2e5369676e617475726554616724432473705f636f72652e2e737232353531392e2e537232353531395461672452502424475424244324244c50246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f6e6f6e63652e2e436865636b4e6f6e6365244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f7765696768742e2e436865636b576569676874244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443247375627374726174655f746573745f72756e74696d652e2e436865636b53756273747261746543616c6c2443246672616d655f6d657461646174615f686173685f657874656e73696f6e2e2e436865636b4d6574616461746148617368244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d652447542424525024244754242447542424475424244754243132746573745f73746f726167653137686636646136396433303663323262306445eb09a9075f5a4e3839375f244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d652475323024617324753230247375627374726174655f746573745f72756e74696d652e2e72756e74696d655f6465636c5f666f725f746573745f6170692e2e546573744150495632244c542473705f72756e74696d652e2e67656e657269632e2e626c6f636b2e2e426c6f636b244c542473705f72756e74696d652e2e67656e657269632e2e6865616465722e2e486561646572244c542475363424432473705f72756e74696d652e2e7472616974732e2e426c616b6554776f3235362447542424432473705f72756e74696d652e2e67656e657269632e2e756e636865636b65645f65787472696e7369632e2e556e636865636b656445787472696e736963244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432473705f636f72652e2e737232353531392e2e537232353531395075626c6963546167244754242443247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c24432473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f244324244c502473705f636f72652e2e63727970746f5f62797465732e2e7369676e61747572655f62797465732e2e5369676e617475726554616724432473705f636f72652e2e737232353531392e2e537232353531395461672452502424475424244324244c50246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f6e6f6e63652e2e436865636b4e6f6e6365244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f7765696768742e2e436865636b576569676874244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443247375627374726174655f746573745f72756e74696d652e2e436865636b53756273747261746543616c6c2443246672616d655f6d657461646174615f686173685f657874656e73696f6e2e2e436865636b4d6574616461746148617368244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d652447542424525024244754242447542424475424244754243132746573745f7769746e6573733137683138616333363238346534396462666645ec09b4075f5a4e3839375f244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d652475323024617324753230247375627374726174655f746573745f72756e74696d652e2e72756e74696d655f6465636c5f666f725f746573745f6170692e2e546573744150495632244c542473705f72756e74696d652e2e67656e657269632e2e626c6f636b2e2e426c6f636b244c542473705f72756e74696d652e2e67656e657269632e2e6865616465722e2e486561646572244c542475363424432473705f72756e74696d652e2e7472616974732e2e426c616b6554776f3235362447542424432473705f72756e74696d652e2e67656e657269632e2e756e636865636b65645f65787472696e7369632e2e556e636865636b656445787472696e736963244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432473705f636f72652e2e737232353531392e2e537232353531395075626c6963546167244754242443247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c24432473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f244324244c502473705f636f72652e2e63727970746f5f62797465732e2e7369676e61747572655f62797465732e2e5369676e617475726554616724432473705f636f72652e2e737232353531392e2e537232353531395461672452502424475424244324244c50246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f6e6f6e63652e2e436865636b4e6f6e6365244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f7765696768742e2e436865636b576569676874244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443247375627374726174655f746573745f72756e74696d652e2e436865636b53756273747261746543616c6c2443246672616d655f6d657461646174615f686173685f657874656e73696f6e2e2e436865636b4d6574616461746148617368244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d652447542424525024244754242447542424475424244754243233746573745f6d756c7469706c655f617267756d656e74733137683333386336323461363132343833363345ed09a9075f5a4e3839375f244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d652475323024617324753230247375627374726174655f746573745f72756e74696d652e2e72756e74696d655f6465636c5f666f725f746573745f6170692e2e546573744150495632244c542473705f72756e74696d652e2e67656e657269632e2e626c6f636b2e2e426c6f636b244c542473705f72756e74696d652e2e67656e657269632e2e6865616465722e2e486561646572244c542475363424432473705f72756e74696d652e2e7472616974732e2e426c616b6554776f3235362447542424432473705f72756e74696d652e2e67656e657269632e2e756e636865636b65645f65787472696e7369632e2e556e636865636b656445787472696e736963244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432473705f636f72652e2e737232353531392e2e537232353531395075626c6963546167244754242443247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c24432473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f244324244c502473705f636f72652e2e63727970746f5f62797465732e2e7369676e61747572655f62797465732e2e5369676e617475726554616724432473705f636f72652e2e737232353531392e2e537232353531395461672452502424475424244324244c50246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f6e6f6e63652e2e436865636b4e6f6e6365244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f7765696768742e2e436865636b576569676874244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443247375627374726174655f746573745f72756e74696d652e2e436865636b53756273747261746543616c6c2443246672616d655f6d657461646174615f686173685f657874656e73696f6e2e2e436865636b4d6574616461746148617368244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d652447542424525024244754242447542424475424244754243132646f5f74726163655f6c6f673137683938323835313338653265303636613045ee09a5075f5a4e3839325f244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d6524753230246173247532302473705f636f6e73656e7375735f626162652e2e72756e74696d655f6465636c5f666f725f626162655f6170692e2e426162654170695632244c542473705f72756e74696d652e2e67656e657269632e2e626c6f636b2e2e426c6f636b244c542473705f72756e74696d652e2e67656e657269632e2e6865616465722e2e486561646572244c542475363424432473705f72756e74696d652e2e7472616974732e2e426c616b6554776f3235362447542424432473705f72756e74696d652e2e67656e657269632e2e756e636865636b65645f65787472696e7369632e2e556e636865636b656445787472696e736963244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432473705f636f72652e2e737232353531392e2e537232353531395075626c6963546167244754242443247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c24432473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f244324244c502473705f636f72652e2e63727970746f5f62797465732e2e7369676e61747572655f62797465732e2e5369676e617475726554616724432473705f636f72652e2e737232353531392e2e537232353531395461672452502424475424244324244c50246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f6e6f6e63652e2e436865636b4e6f6e6365244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f7765696768742e2e436865636b576569676874244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443247375627374726174655f746573745f72756e74696d652e2e436865636b53756273747261746543616c6c2443246672616d655f6d657461646174615f686173685f657874656e73696f6e2e2e436865636b4d6574616461746148617368244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d652447542424525024244754242447542424475424244754243133636f6e66696775726174696f6e3137686239666332353039636638333064643745ef09c5075f5a4e3839325f244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d6524753230246173247532302473705f636f6e73656e7375735f626162652e2e72756e74696d655f6465636c5f666f725f626162655f6170692e2e426162654170695632244c542473705f72756e74696d652e2e67656e657269632e2e626c6f636b2e2e426c6f636b244c542473705f72756e74696d652e2e67656e657269632e2e6865616465722e2e486561646572244c542475363424432473705f72756e74696d652e2e7472616974732e2e426c616b6554776f3235362447542424432473705f72756e74696d652e2e67656e657269632e2e756e636865636b65645f65787472696e7369632e2e556e636865636b656445787472696e736963244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432473705f636f72652e2e737232353531392e2e537232353531395075626c6963546167244754242443247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c24432473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f244324244c502473705f636f72652e2e63727970746f5f62797465732e2e7369676e61747572655f62797465732e2e5369676e617475726554616724432473705f636f72652e2e737232353531392e2e537232353531395461672452502424475424244324244c50246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f6e6f6e63652e2e436865636b4e6f6e6365244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f7765696768742e2e436865636b576569676874244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443247375627374726174655f746573745f72756e74696d652e2e436865636b53756273747261746543616c6c2443246672616d655f6d657461646174615f686173685f657874656e73696f6e2e2e436865636b4d6574616461746148617368244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d6524475424245250242447542424475424244754242447542434357375626d69745f7265706f72745f65717569766f636174696f6e5f756e7369676e65645f65787472696e7369633137686630396464613362373561303561373845f009b6075f5a4e3930375f244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d6524753230246173247532302473705f6f6666636861696e2e2e72756e74696d655f6465636c5f666f725f6f6666636861696e5f776f726b65725f6170692e2e4f6666636861696e576f726b65724170695632244c542473705f72756e74696d652e2e67656e657269632e2e626c6f636b2e2e426c6f636b244c542473705f72756e74696d652e2e67656e657269632e2e6865616465722e2e486561646572244c542475363424432473705f72756e74696d652e2e7472616974732e2e426c616b6554776f3235362447542424432473705f72756e74696d652e2e67656e657269632e2e756e636865636b65645f65787472696e7369632e2e556e636865636b656445787472696e736963244c542473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f24432473705f636f72652e2e737232353531392e2e537232353531395075626c6963546167244754242443247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c24432473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c54245f244324244c502473705f636f72652e2e63727970746f5f62797465732e2e7369676e61747572655f62797465732e2e5369676e617475726554616724432473705f636f72652e2e737232353531392e2e537232353531395461672452502424475424244324244c50246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f6e6f6e63652e2e436865636b4e6f6e6365244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f7765696768742e2e436865636b576569676874244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443247375627374726174655f746573745f72756e74696d652e2e436865636b53756273747261746543616c6c2443246672616d655f6d657461646174615f686173685f657874656e73696f6e2e2e436865636b4d6574616461746148617368244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d6524475424245250242447542424475424244754242447542431356f6666636861696e5f776f726b65723137683366626135393464643266633963333945f109cf015f5a4e3132315f244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d654f726967696e247532302461732475323024636f72652e2e636f6e766572742e2e46726f6d244c54247375627374726174655f746573745f72756e74696d652e2e4f726967696e43616c6c657224475424244754243466726f6d32385f24753762242475376224636c6f737572652475376424247537642431376864303636643239376139373430323738452e6c6c766d2e32383034353134343737303732373934353638f209ea015f5a4e3230335f244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d654f726967696e247532302461732475323024636f72652e2e636f6e766572742e2e46726f6d244c5424636f72652e2e6f7074696f6e2e2e4f7074696f6e244c5424244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d652475323024617324753230246672616d655f73797374656d2e2e70616c6c65742e2e436f6e666967244754242e2e4163636f756e7449642447542424475424244754243466726f6d3137683364643932613435356237396637313145f3097a5f5a4e38385f244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c24753230246173247532302473705f72756e74696d652e2e7472616974732e2e446973706174636861626c65244754243864697370617463683137686632333937666433383236326439356245f40993015f5a4e32327375627374726174655f746573745f72756e74696d65315f38365f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c2447542439747970655f696e666f3137683239623966616665666232666161333945f5098f015f5a4e32327375627374726174655f746573745f72756e74696d65315f38325f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230247375627374726174655f746573745f72756e74696d652e2e52756e74696d652447542439747970655f696e666f3137686462346630393030666665363439346445f60994015f5a4e32327375627374726174655f746573745f72756e74696d65315f38375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230247375627374726174655f746573745f72756e74696d652e2e52756e74696d654576656e742447542439747970655f696e666f3137683262393366343361653934623132363245f70994015f5a4e32327375627374726174655f746573745f72756e74696d65315f38375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230247375627374726174655f746573745f72756e74696d652e2e52756e74696d654572726f722447542439747970655f696e666f3137683930333133386565633964303937346645f80991015f5a4e3131335f244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d6547656e65736973436f6e6669672475323024617324753230246672616d655f737570706f72742e2e7472616974732e2e686f6f6b732e2e4275696c6447656e65736973436f6e66696724475424356275696c643137683664396534353630653431326232623045f90984015f5a4e38385f244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d6524753230246173247532302473705f72756e74696d652e2e7472616974732e2e56616c6964617465556e7369676e656424475424313776616c69646174655f756e7369676e65643137686664623139316535336263306235616245fa0999015f5a4e32327375627374726174655f746573745f72756e74696d65315f39325f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230247375627374726174655f746573745f72756e74696d652e2e52756e74696d65486f6c64526561736f6e2447542439747970655f696e666f3137686566363564613130363437663938646345fb099d015f5a4e32327375627374726174655f746573745f72756e74696d65315f39365f244c5424696d706c247532302473657264652e2e7365722e2e53657269616c697a652475323024666f7224753230247375627374726174655f746573745f72756e74696d652e2e52756e74696d6547656e65736973436f6e666967244754243973657269616c697a653137683435363938366661383636353863336245fc09e3015f5a4e3139315f244c54247375627374726174655f746573745f72756e74696d652e2e5f2e2e244c5424696d706c247532302473657264652e2e64652e2e446573657269616c697a652475323024666f7224753230247375627374726174655f746573745f72756e74696d652e2e52756e74696d6547656e65736973436f6e666967244754242e2e646573657269616c697a652e2e5f5f4669656c6456697369746f7224753230246173247532302473657264652e2e64652e2e56697369746f72244754243976697369745f7374723137683437396439643336333362656263306445fd099d015f5a4e32327375627374726174655f746573745f72756e74696d65315f39395f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f64652475323024666f7224753230247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c24475424366465636f64653137683461376632346664356331333266393945fe09655f5a4e37325f244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683839326636663537303635343431623145ff0985015f5a4e3130325f244c5424636f72652e2e697465722e2e61646170746572732e2e6d61702e2e4d6170244c5424492443244624475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e6974657261746f722e2e4974657261746f722447542434666f6c643137683030396663353565363965313064383945800a85015f5a4e3130325f244c5424636f72652e2e697465722e2e61646170746572732e2e6d61702e2e4d6170244c5424492443244624475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e6974657261746f722e2e4974657261746f722447542434666f6c643137683836396235316235383536663236303245810a89015f5a4e3130365f244c5424636f72652e2e697465722e2e61646170746572732e2e47656e657269635368756e74244c5424492443245224475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e6974657261746f722e2e4974657261746f7224475424346e6578743137686561386362636263336262306237336145820a8d015f5a4e3130365f244c5424636f72652e2e697465722e2e61646170746572732e2e47656e657269635368756e74244c5424492443245224475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e6974657261746f722e2e4974657261746f7224475424387472795f666f6c643137683561663635316663663564303763333645830a415f5a4e37747269655f6462346e6f646531304e6f646548616e646c653135746f5f6f776e65645f68616e646c653137683231663965393066326537633534383145840a6c5f5a4e34636f726533707472373464726f705f696e5f706c616365244c5424747269655f64622e2e6e6f64652e2e4e6f64654f776e6564244c54247072696d69746976655f74797065732e2e4832353624475424244754243137683462386365613062656464353664383245850a695f5a4e34636f726533707472373164726f705f696e5f706c616365244c542473705f747269652e2e6572726f722e2e4572726f72244c54247072696d69746976655f74797065732e2e4832353624475424244754243137683461363365306537646330353230356545860a8d015f5a4e3130365f244c5424636f72652e2e697465722e2e61646170746572732e2e47656e657269635368756e74244c5424492443245224475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e6974657261746f722e2e4974657261746f7224475424387472795f666f6c643137686235656135663436353739313338383145870a415f5a4e37747269655f6462346e6f646531304e6f646548616e646c653135746f5f6f776e65645f68616e646c653137686233653961643936303138643965373845880a8d015f5a4e3130365f244c5424636f72652e2e697465722e2e61646170746572732e2e47656e657269635368756e74244c5424492443245224475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e6974657261746f722e2e4974657261746f7224475424387472795f666f6c643137686532656131653065636163303235326645890a8d015f5a4e3130365f244c5424636f72652e2e697465722e2e61646170746572732e2e47656e657269635368756e74244c5424492443245224475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e6974657261746f722e2e4974657261746f7224475424387472795f666f6c6431376866636633353363663464356433323264458a0a4a5f5a4e313073705f72756e74696d6536747261697473313656616c6964617465556e7369676e656431327072655f646973706174636831376839343631383135343031346431633032458b0a95015f5a4e31326672616d655f73797374656d35355f244c5424696d706c24753230246672616d655f73797374656d2e2e70616c6c65742e2e50616c6c6574244c5424542447542424475424323776616c69646174655f617574686f72697a65645f7570677261646531376861643931366330346635393236633565452e6c6c766d2e31373132343635353732373637363833303235308c0a91015f5a4e3131335f244c54246672616d655f73797374656d2e2e70616c6c65742e2e47656e65736973436f6e666967244c542454244754242475323024617324753230246672616d655f737570706f72742e2e7472616974732e2e686f6f6b732e2e4275696c6447656e65736973436f6e66696724475424356275696c6431376834303339323931613632323230313734458d0a93015f5a4e3131365f244c542470616c6c65745f62616c616e6365732e2e696d706c5f63757272656e63792e2e696d62616c616e6365732e2e4e65676174697665496d62616c616e6365244c5424542443244924475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f7031376838646237336362366362366132636638458e0a8f015f5a4e31326672616d655f73797374656d35355f244c5424696d706c24753230246672616d655f73797374656d2e2e70616c6c65742e2e50616c6c6574244c542454244754242447542432316465706f7369745f6576656e745f696e646578656431376863356236303733346338323866623062452e6c6c766d2e31373132343635353732373637363833303235308f0a93015f5a4e3131365f244c542470616c6c65745f62616c616e6365732e2e696d706c5f63757272656e63792e2e696d62616c616e6365732e2e506f736974697665496d62616c616e6365244c5424542443244924475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137683330626439373131323466383232333045900a385f5a4e313170616c6c65745f626162653138636f6d707574655f72616e646f6d6e6573733137683966376133623661303862303739346345910aa6015f5a4e3132305f244c5424244c50245475706c65456c656d656e74302443245475706c65456c656d656e74312443245475706c65456c656d656e7432245250242475323024617324753230246672616d655f737570706f72742e2e7472616974732e2e686f6f6b732e2e4f6e52756e74696d65557067726164652447542431386f6e5f72756e74696d655f757067726164653137683866656666656336333862636233383545920aa7015f5a4e3132395f244c5424244c50245475706c65456c656d656e74302443245475706c65456c656d656e74312443245475706c65456c656d656e74322443245475706c65456c656d656e7433245250242475323024617324753230246672616d655f737570706f72742e2e7472616974732e2e686f6f6b732e2e4f6e47656e657369732447542431306f6e5f67656e657369733137683838383031663964353934323735643045930ab0025f5a4e31326672616d655f73797374656d3234355f244c5424696d706c24753230246672616d655f737570706f72742e2e7472616974732e2e73746f7265645f6d61702e2e53746f7265644d6170244c5424244c5424542475323024617324753230246672616d655f73797374656d2e2e70616c6c65742e2e436f6e666967244754242e2e4163636f756e744964244324244c5424542475323024617324753230246672616d655f73797374656d2e2e70616c6c65742e2e436f6e666967244754242e2e4163636f756e7444617461244754242475323024666f7224753230246672616d655f73797374656d2e2e70616c6c65742e2e50616c6c6574244c542454244754242447542431377472795f6d75746174655f6578697374733137683533323961643038616539383936306145940ab0025f5a4e31326672616d655f73797374656d3234355f244c5424696d706c24753230246672616d655f737570706f72742e2e7472616974732e2e73746f7265645f6d61702e2e53746f7265644d6170244c5424244c5424542475323024617324753230246672616d655f73797374656d2e2e70616c6c65742e2e436f6e666967244754242e2e4163636f756e744964244324244c5424542475323024617324753230246672616d655f73797374656d2e2e70616c6c65742e2e436f6e666967244754242e2e4163636f756e7444617461244754242475323024666f7224753230246672616d655f73797374656d2e2e70616c6c65742e2e50616c6c6574244c542454244754242447542431377472795f6d75746174655f6578697374733137686231373635333836303366643030316545950ab0025f5a4e31326672616d655f73797374656d3234355f244c5424696d706c24753230246672616d655f737570706f72742e2e7472616974732e2e73746f7265645f6d61702e2e53746f7265644d6170244c5424244c5424542475323024617324753230246672616d655f73797374656d2e2e70616c6c65742e2e436f6e666967244754242e2e4163636f756e744964244324244c5424542475323024617324753230246672616d655f73797374656d2e2e70616c6c65742e2e436f6e666967244754242e2e4163636f756e7444617461244754242475323024666f7224753230246672616d655f73797374656d2e2e70616c6c65742e2e50616c6c6574244c542454244754242447542431377472795f6d75746174655f6578697374733137686462356435363266346438633962313845960a6a5f5a4e31326672616d655f73797374656d35355f244c5424696d706c24753230246672616d655f73797374656d2e2e70616c6c65742e2e50616c6c6574244c54245424475424244754243130696e697469616c697a653137683730346430333563623465363335313545970a6c5f5a4e31326672616d655f73797374656d35355f244c5424696d706c24753230246672616d655f73797374656d2e2e70616c6c65742e2e50616c6c6574244c5424542447542424475424313263616e5f7365745f636f64653137686264396233333131373765383265333045980a6c5f5a4e31326672616d655f73797374656d35355f244c5424696d706c24753230246672616d655f73797374656d2e2e70616c6c65742e2e50616c6c6574244c5424542447542424475424313272657365745f6576656e74733137686365356438343733373938666663616245990a765f5a4e31326672616d655f73797374656d35355f244c5424696d706c24753230246672616d655f73797374656d2e2e70616c6c65742e2e50616c6c6574244c542454244754242447542432326e6f74655f6170706c6965645f65787472696e73696331376831373337383933343937626563383362459a0a5c5f5a4e34636f726533666d74336e756d35305f244c5424696d706c2475323024636f72652e2e666d742e2e44656275672475323024666f7224753230247536342447542433666d7431376832643962636565363333316266326131459b0a785f5a4e31326672616d655f73797374656d35355f244c5424696d706c24753230246672616d655f73797374656d2e2e70616c6c65742e2e50616c6c6574244c542454244754242447542432346e6f74655f66696e69736865645f65787472696e7369637331376832623939323564376638376365393536459c0a7a5f5a4e31326672616d655f73797374656d35355f244c5424696d706c24753230246672616d655f73797374656d2e2e70616c6c65742e2e50616c6c6574244c54245424475424244754243236646f5f6170706c795f617574686f72697a655f7570677261646531376835396266666130383332633039383633459d0a675f5a4e31326672616d655f73797374656d35355f244c5424696d706c24753230246672616d655f73797374656d2e2e70616c6c65742e2e50616c6c6574244c54245424475424244754243866696e616c697a6531376864316236633764323436616530376661459e0a4f5f5a4e31326672616d655f73797374656d3670616c6c6574313550616c6c6574244c54245424475424313673746f726167655f6d6574616461746131376832343534393565633831326334666639459f0a585f5a4e31326672616d655f73797374656d3670616c6c6574313550616c6c6574244c54245424475424323570616c6c65745f636f6e7374616e74735f6d657461646174613137683362646363376130386336383366343845a00a9f015f5a4e31326672616d655f73797374656d3670616c6c6574315f3130305f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230246672616d655f73797374656d2e2e70616c6c65742e2e4576656e74244c542454244754242447542439656e636f64655f746f3137683338663536306335353431353661386445a10a9f015f5a4e31326672616d655f73797374656d3670616c6c6574315f3130305f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230246672616d655f73797374656d2e2e70616c6c65742e2e4576656e74244c54245424475424244754243973697a655f68696e743137683065623633323464383265323664646345a20a8a015f5a4e31326672616d655f73797374656d3670616c6c6574315f38345f244c5424696d706c2475323024636f72652e2e636c6f6e652e2e436c6f6e652475323024666f7224753230246672616d655f73797374656d2e2e70616c6c65742e2e43616c6c244c542454244754242447542435636c6f6e653137683663663436393636323963623833616445a30a90015f5a4e31326672616d655f73797374656d3670616c6c6574315f38365f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f73797374656d2e2e70616c6c65742e2e43616c6c244c542454244754242447542439747970655f696e666f3137683536363733373163666238613534373545a40a91015f5a4e31326672616d655f73797374656d3670616c6c6574315f38375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f73797374656d2e2e70616c6c65742e2e4572726f72244c542454244754242447542439747970655f696e666f3137683361653831346237383064373962623245a50a91015f5a4e31326672616d655f73797374656d3670616c6c6574315f38375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f73797374656d2e2e70616c6c65742e2e4576656e74244c542454244754242447542439747970655f696e666f3137683137343038623832396561356134393845a60a9a015f5a4e31326672616d655f73797374656d3670616c6c6574315f39395f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f64652475323024666f7224753230246672616d655f73797374656d2e2e70616c6c65742e2e43616c6c244c5424542447542424475424366465636f64653137683662653239666339383430316663633945a70a9d015f5a4e31326672616d655f73797374656d3670616c6c6574315f39395f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230246672616d655f73797374656d2e2e70616c6c65742e2e43616c6c244c542454244754242447542439656e636f64655f746f3137686339313031356637323934396463643445a80aa9015f5a4e3133385f244c54246672616d655f737570706f72742e2e7472616974732e2e746f6b656e732e2e66756e6769626c652e2e696d62616c616e63652e2e496d62616c616e6365244c5424422443244f6e44726f702443244f70706f736974654f6e44726f7024475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137683933343634333363353264323535623145a90abc015f5a4e31336672616d655f737570706f72743674726169747336746f6b656e73346d697363315f3131365f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f737570706f72742e2e7472616974732e2e746f6b656e732e2e6d6973632e2e4964416d6f756e74244c5424496424432442616c616e6365244754242447542439747970655f696e666f3137683132303635396163343461666636363345aa0abc015f5a4e31336672616d655f737570706f72743674726169747336746f6b656e73346d697363315f3131365f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f737570706f72742e2e7472616974732e2e746f6b656e732e2e6d6973632e2e4964416d6f756e74244c5424496424432442616c616e6365244754242447542439747970655f696e666f3137683363333862373062316161613033666545ab0a535f5a4e31336672616d655f737570706f7274367472616974733773746f72616765313553746f72616765496e7374616e636531317072656669785f686173683137683837643166303733626537306238333545ac0a535f5a4e31336672616d655f737570706f7274367472616974733773746f72616765313553746f72616765496e7374616e636531317072656669785f686173683137686363393137396133393363343837393245ad0acb015f5a4e3134365f244c5424244c50245475706c65456c656d656e74302443245475706c65456c656d656e74312443245475706c65456c656d656e74322443245475706c65456c656d656e7433245250242475323024617324753230246672616d655f737570706f72742e2e7472616974732e2e686f6f6b732e2e4265666f7265416c6c52756e74696d654d6967726174696f6e732447542432396265666f72655f616c6c5f72756e74696d655f6d6967726174696f6e733137686166326132386336613562383961326345ae0a715f5a4e38345f244c54246672616d655f737570706f72742e2e7472616974732e2e6d657461646174612e2e53746f7261676556657273696f6e247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686332393765656362386337356338376645af0ace025f5a4e3237345f244c542470616c6c65745f626162652e2e70616c6c65742e2e50616c6c6574244c542454244754242475323024617324753230246672616d655f737570706f72742e2e7472616974732e2e686f6f6b732e2e4f6e49646c65244c5424244c5424244c5424244c5424542475323024617324753230246672616d655f73797374656d2e2e70616c6c65742e2e436f6e666967244754242e2e426c6f636b24753230246173247532302473705f72756e74696d652e2e7472616974732e2e48656164657250726f7669646572244754242e2e4865616465725424753230246173247532302473705f72756e74696d652e2e7472616974732e2e486561646572244754242e2e4e756d6265722447542424475424376f6e5f69646c6531376862303164656131613465313733656362452e6c6c766d2e3137313234363535373237363736383330323530b00a465f5a4e34315f244c54245424753230246173247532302473657264652e2e64652e2e45787065637465642447542433666d743137686336316461363234623733656264333045b10aa5015f5a4e34636f72653370747231333064726f705f696e5f706c616365244c54242475356224636f72652e2e6f7074696f6e2e2e4f7074696f6e244c5424747269655f64622e2e6e6f64652e2e4e6f646548616e646c654f776e6564244c54247072696d69746976655f74797065732e2e4832353624475424244754242475336224247532302431362475356424244754243137683464363263343032613462393966356245b20a3e5f5a4e34636f726533707472323864726f705f696e5f706c616365244c542424524624753136244754243137683665616535333638616239373933636345b30a715f5a4e34636f726533707472353364726f705f696e5f706c616365244c54247061726974795f7363616c655f636f6465632e2e6572726f722e2e4572726f722447542431376866386339663061313434386130383237452e6c6c766d2e3137313234363535373237363736383330323530b40a785f5a4e36365f244c5424542475323024617324753230247061726974795f7363616c655f636f6465632e2e64657074685f6c696d69742e2e4465636f64654c696d69742447542432376465636f64655f616c6c5f776974685f64657074685f6c696d69743137683964616534343632633339303363663745b50a7c5f5a4e36395f244c54247061726974795f7363616c655f636f6465632e2e6572726f722e2e4572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376863636562313832636338343631643463452e6c6c766d2e3137313234363535373237363736383330323530b60a385f5a4e37747269655f6462346e6f6465344e6f64653133746f5f6f776e65645f6e6f64653137683939636439343431333765346334396245b70a385f5a4e37747269655f6462346e6f6465344e6f64653133746f5f6f776e65645f6e6f64653137686632346131306365306563333730653445b80a785f5a4e38375f244c542470616c6c65745f626162652e2e53616d65417574686f726974696573466f726576657224753230246173247532302470616c6c65745f626162652e2e45706f63684368616e6765547269676765722447542437747269676765723137683563393766633066646338646137646345b90a8a015f5a4e39345f244c54246672616d655f73797374656d2e2e70616c6c65742e2e50616c6c6574244c5424542447542424753230246173247532302473705f72756e74696d652e2e7472616974732e2e56616c6964617465556e7369676e656424475424313776616c69646174655f756e7369676e65643137683763633366633333663562393939626245ba0a8c015f5a4e39365f244c54246672616d655f73797374656d2e2e70616c6c65742e2e43616c6c244c542454244754242475323024617324753230246672616d655f737570706f72742e2e64697370617463682e2e4765744469737061746368496e666f2447542431376765745f64697370617463685f696e666f3137683737366362346135636539313131633545bb0a86015f5a4e3130315f244c54247061726974795f7363616c655f636f6465632e2e636f6d706163742e2e436f6d70616374244c5424753332244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f646524475424366465636f64653137683037333433373337663466363565313245bc0a86015f5a4e3130315f244c54247061726974795f7363616c655f636f6465632e2e636f6d706163742e2e436f6d70616374244c5424753332244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f646524475424366465636f64653137686162386230393332393466663765353545bd0a86015f5a4e3130315f244c54247061726974795f7363616c655f636f6465632e2e636f6d706163742e2e436f6d70616374244c5424753332244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f646524475424366465636f64653137686339613638313439636431656664636645be0a86015f5a4e3130315f244c54247061726974795f7363616c655f636f6465632e2e636f6d706163742e2e436f6d70616374244c5424753634244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f646524475424366465636f64653137683065343237336433373932373636383445bf0a86015f5a4e3130315f244c54247061726974795f7363616c655f636f6465632e2e636f6d706163742e2e436f6d70616374244c5424753634244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f646524475424366465636f64653137683939386433313432343839616330323945c00a8c015f5a4e3130345f244c54247061726974795f7363616c655f636f6465632e2e636f6d706163742e2e436f6d70616374526566244c5424753332244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542439656e636f64655f746f3137686130623235303763636430386336663945c10a8c015f5a4e3130345f244c54247061726974795f7363616c655f636f6465632e2e636f6d706163742e2e436f6d70616374526566244c5424753634244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542439656e636f64655f746f3137686162383430623030653531313334376645c20a95015f5a4e31307363616c655f696e666f35696d706c7339365f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230247061726974795f7363616c655f636f6465632e2e636f6d706163742e2e436f6d70616374244c542454244754242447542439747970655f696e666f3137686436666266333566353631333232643145c30a3c5f5a4e31307363686e6f72726b656c3376726638565246496e4f757431306d616b655f62797465733137683565326431363264636330633964663845c40a445f5a4e31307363686e6f72726b656c33767266395652465072654f757431376174746163685f696e7075745f686173683137686239323333336663616132313737343345c50a325f5a4e313073657264655f6a736f6e326465313066726f6d5f74726169743137686133616163653963653362613764616545c60a8a015f5a4e39335f244c5424245246246d7574247532302473657264655f6a736f6e2e2e64652e2e446573657269616c697a6572244c5424522447542424753230246173247532302473657264652e2e64652e2e446573657269616c697a6572244754243138646573657269616c697a655f7374727563743137683330636661616663613032363930376245c70a495f5a4e313073657264655f6a736f6e3264653231446573657269616c697a6572244c5424522447542431307065656b5f6572726f723137683233643937613864646630313864333545c80a4a5f5a4e313073657264655f6a736f6e3264653231446573657269616c697a6572244c5424522447542431317363616e5f6e756d6265723137683931356135646362653961386134656645c90a4c5f5a4e313073657264655f6a736f6e3264653231446573657269616c697a6572244c5424522447542431337363616e5f6578706f6e656e743137686666663863633264356330373030343545ca0a4a5f5a4e313073657264655f6a736f6e3264653231446573657269616c697a6572244c5424522447542431317363616e5f6f725f656f663137683934313964656662346237313064326145cb0a4c5f5a4e313073657264655f6a736f6e3264653231446573657269616c697a6572244c54245224475424313370617273655f646563696d616c3137683130653563616664666163326334333045cc0a4d5f5a4e313073657264655f6a736f6e3264653231446573657269616c697a6572244c5424522447542431346636345f66726f6d5f70617274733137686332333536346565646433663139363845cd0a4d5f5a4e313073657264655f6a736f6e3264653231446573657269616c697a6572244c54245224475424313470617273655f6578706f6e656e743137686539613036646233653532303532316445ce0a555f5a4e313073657264655f6a736f6e3264653231446573657269616c697a6572244c54245224475424323270617273655f646563696d616c5f6f766572666c6f773137683661346533653430383835346633306345cf0a4c5f5a4e313073657264655f6a736f6e3264653231446573657269616c697a6572244c54245224475424313370617273655f696e74656765723137686163383264616632613834343062326445d00a515f5a4e313073657264655f6a736f6e3264653231446573657269616c697a6572244c54245224475424313870617273655f6c6f6e675f696e74656765723137686436663433633030353966323837663845d10a4d5f5a4e313073657264655f6a736f6e3264653231446573657269616c697a6572244c54245224475424313469676e6f72655f696e74656765723137683132646237623166306636393438666545d20a4e5f5a4e313073657264655f6a736f6e3264653231446573657269616c697a6572244c54245224475424313569676e6f72655f6578706f6e656e743137686561663837613163326236323934346545d30a565f5a4e313073657264655f6a736f6e3264653231446573657269616c697a6572244c54245224475424323370617273655f6578706f6e656e745f6f766572666c6f773137686163623532653432653165323862656245d40a4f5f5a4e313073657264655f6a736f6e3264653231446573657269616c697a6572244c54245224475424313670617273655f616e795f6e756d6265723137686533666539303035323061373439656645d50a695f5a4e313073657264655f6a736f6e3264653231446573657269616c697a6572244c5424522447542431377065656b5f696e76616c69645f7479706531376837626138363266646533336131303362452e6c6c766d2e37373639353536303138373433393139313834d60a565f5a4e313073657264655f6a736f6e356572726f72354572726f7231326669785f706f736974696f6e31376835393362366639643165386538333239452e6c6c766d2e37373639353536303138373433393139313834d70a6a5f5a4e313073657264655f6a736f6e3264653231446573657269616c697a6572244c54245224475424313870617273655f6f626a6563745f636f6c6f6e31376864316632643330613939383561396530452e6c6c766d2e37373639353536303138373433393139313834d80a435f5a4e313073657264655f6a736f6e3264653231446573657269616c697a6572244c54245224475424356572726f723137686431316338336139343666383533376445d90a455f5a4e313073657264655f6a736f6e3264653231446573657269616c697a6572244c5424522447542437656e645f6d61703137683330643738346362333636626139326545da0a455f5a4e313073657264655f6a736f6e3264653231446573657269616c697a6572244c5424522447542437656e645f7365713137683165303965653035643161393536323545db0a2e5f5a4e313161727261795f6279746573396279746573326865783137683063623463653263633034626330383045dc0a2e5f5a4e313161727261795f6279746573396279746573326865783137683232393761396336663734663439643245dd0a475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683737323034346237316564633364663845de0a8b015f5a4e34636f7265336f70733866756e6374696f6e35696d706c7338305f244c5424696d706c2475323024636f72652e2e6f70732e2e66756e6374696f6e2e2e466e4f6e6365244c542441244754242475323024666f722475323024245246246d7574247532302446244754243963616c6c5f6f6e63653137683737313436643233663735313461383545df0a565f5a4e34636f726533707472323764726f705f696e5f706c616365244c54242452462475382447542431376833376634303563343765346531373866452e6c6c766d2e37373639353536303138373433393139313834e00a6d5f5a4e34636f726533707472353064726f705f696e5f706c616365244c542473657264652e2e64652e2e696d706c732e2e556e697456697369746f722447542431376830393231376639376139393130616232452e6c6c766d2e37373639353536303138373433393139313834e10a3e5f5a4e35616c6c6f633473796e633136417263244c54245424432441244754243964726f705f736c6f773137686166393637633761376534636431646145e20a3e5f5a4e35616c6c6f633473796e633136417263244c54245424432441244754243964726f705f736c6f773137686563656130623932323531393531653745e30a355f5a4e357365726465326465354572726f7231336d697373696e675f6669656c643137683033306566393061666338653838636245e40a765f5a4e36315f244c542473657264655f6a736f6e2e2e6572726f722e2e4572726f7224753230246173247532302473657264652e2e64652e2e4572726f722447542436637573746f6d31376832373365313031396430336531316561452e6c6c766d2e37373639353536303138373433393139313834e50a355f5a4e357365726465326465354572726f723133756e6b6e6f776e5f6669656c643137683130373837303036663830633263633345e60a365f5a4e357365726465326465354572726f723134696e76616c69645f6c656e6774683137683664313765333462306438356364303845e70a375f5a4e357365726465326465354572726f7231356475706c69636174655f6669656c643137683163303365373735306264393965613445e80a375f5a4e357365726465326465354572726f723135756e6b6e6f776e5f76617269616e743137686335313534333036373462653431376245e90a385f5a4e3573657264653264653953657141636365737331326e6578745f656c656d656e743137683738656235363266616461613037663345ea0a5d5f5a4e36315f244c542473657264655f6a736f6e2e2e6572726f722e2e4572726f7224753230246173247532302473657264652e2e64652e2e4572726f722447542436637573746f6d3137683862363935326366396561353563656245eb0a775f5a4e37355f244c542473657264655f6a736f6e2e2e64652e2e536571416363657373244c5424522447542424753230246173247532302473657264652e2e64652e2e5365714163636573732447542431376e6578745f656c656d656e745f736565643137683365663434356464643431623033356145ec0a775f5a4e37355f244c542473657264655f6a736f6e2e2e64652e2e536571416363657373244c5424522447542424753230246173247532302473657264652e2e64652e2e5365714163636573732447542431376e6578745f656c656d656e745f736565643137683864313161346136366661643365323145ed0a775f5a4e37355f244c542473657264655f6a736f6e2e2e64652e2e536571416363657373244c5424522447542424753230246173247532302473657264652e2e64652e2e5365714163636573732447542431376e6578745f656c656d656e745f736565643137683962623239626138336432363334333345ee0a90015f5a4e38315f244c5424636f72652e2e6d61726b65722e2e5068616e746f6d44617461244c5424542447542424753230246173247532302473657264652e2e64652e2e446573657269616c697a6553656564244754243131646573657269616c697a6531376836386234313135373032353937303533452e6c6c766d2e37373639353536303138373433393139313834ef0a775f5a4e38315f244c5424636f72652e2e6d61726b65722e2e5068616e746f6d44617461244c5424542447542424753230246173247532302473657264652e2e64652e2e446573657269616c697a6553656564244754243131646573657269616c697a653137686565343631383532376534323532666145f00a7a5f5a4e38335f244c542473657264655f6a736f6e2e2e64652e2e56617269616e74416363657373244c5424522447542424753230246173247532302473657264652e2e64652e2e56617269616e74416363657373244754243132756e69745f76617269616e743137683164323563643663323337313437623645f10a87015f5a4e39335f244c5424245246246d7574247532302473657264655f6a736f6e2e2e64652e2e446573657269616c697a6572244c5424522447542424753230246173247532302473657264652e2e64652e2e446573657269616c697a6572244754243135646573657269616c697a655f7365713137683133316532643334643832313063356645f20a87015f5a4e39335f244c5424245246246d7574247532302473657264655f6a736f6e2e2e64652e2e446573657269616c697a6572244c5424522447542424753230246173247532302473657264652e2e64652e2e446573657269616c697a6572244754243135646573657269616c697a655f7365713137683333616565303336666437323937643745f30a87015f5a4e39335f244c5424245246246d7574247532302473657264655f6a736f6e2e2e64652e2e446573657269616c697a6572244c5424522447542424753230246173247532302473657264652e2e64652e2e446573657269616c697a6572244754243135646573657269616c697a655f7365713137683663396638383330623338303337313545f40a8a015f5a4e39335f244c5424245246246d7574247532302473657264655f6a736f6e2e2e64652e2e446573657269616c697a6572244c5424522447542424753230246173247532302473657264652e2e64652e2e446573657269616c697a6572244754243138646573657269616c697a655f737472696e673137683839653363643432376634353935343245f50a8a015f5a4e39335f244c5424245246246d7574247532302473657264655f6a736f6e2e2e64652e2e446573657269616c697a6572244c5424522447542424753230246173247532302473657264652e2e64652e2e446573657269616c697a6572244754243138646573657269616c697a655f7374727563743137683133666266633963376265386462393445f60a8a015f5a4e39335f244c5424245246246d7574247532302473657264655f6a736f6e2e2e64652e2e446573657269616c697a6572244c5424522447542424753230246173247532302473657264652e2e64652e2e446573657269616c697a6572244754243138646573657269616c697a655f7374727563743137686535623663386532373639373632626345f70a8a015f5a4e39335f244c5424245246246d7574247532302473657264655f6a736f6e2e2e64652e2e446573657269616c697a6572244c5424522447542424753230246173247532302473657264652e2e64652e2e446573657269616c697a6572244754243138646573657269616c697a655f7374727563743137686566636263366436383438333235326245f80a8a015f5a4e39335f244c5424245246246d7574247532302473657264655f6a736f6e2e2e64652e2e446573657269616c697a6572244c5424522447542424753230246173247532302473657264652e2e64652e2e446573657269616c697a6572244754243138646573657269616c697a655f7374727563743137686235353539633235633436323432356545f90a8a015f5a4e39335f244c5424245246246d7574247532302473657264655f6a736f6e2e2e64652e2e446573657269616c697a6572244c5424522447542424753230246173247532302473657264652e2e64652e2e446573657269616c697a6572244754243138646573657269616c697a655f7374727563743137683430393835643635653733353831316645fa0a2d5f5a4e39747269655f726f6f7431306275696c645f747269653137683437353364386565376366326539383645fb0a325f5a4e39747269655f726f6f743135747269655f726f6f745f696e6e65723137686566653532343337373534333465623345fc0a445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683030616563653665323137386330646445fd0a445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683037313835633266366330333932393445fe0a445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683038643064363230373233316536636245ff0a445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683130336561626664653264353661353645800b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683130643134376238373439313331346545810b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683134323333613839656530623038303845820b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683135616335316334656332366666383045830b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683136666362373563613666386236613245840b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683163653735303634376465383064393445850b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683165613930653339666234366139653445860b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683230306234356262343932633065613445870b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683236623332343563653639383333666145880b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683237303838303066656432396633636645890b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e7431376832383039643364363662366530373533458a0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e7431376832393564336134613435376262613036458b0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e7431376832633733386432363637663938303466458c0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e7431376832646331303331353661306266663038458d0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e7431376832646334386361623830663431336138458e0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e7431376832666134383133626565333030306539458f0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683266653933346435336435313863653945900b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683335366562633262643764336166346245910b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683336353466663132396338313138346145920b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683365383139636234383536336538306445930b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683430666239643364333530666439366245940b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683435663761326331623865316562666345950b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683437323533623436643562616661366545960b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683439666436383365636532313233326245970b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683461316465626635623235393464363545980b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683461323566366265353038353861363245990b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e7431376834626332386663333935646230643333459a0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e7431376834633938663539663265613564643666459b0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e7431376835393035333162633465336430663637459c0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e7431376835653938333636326131306237616161459d0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e7431376835663462646433393136653031366563459e0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e7431376836343963393533396238326634666564459f0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683634666132373235396332663732636545a00b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683661376630643532316137353636363745a10b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683730373530393661383738343065646145a20b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683737356231613734343562333237336445a30b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683738643237373036303263356239396645a40b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683830343763633137326231393933666545a50b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683834303138643236386534336537383845a60b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683835666432633338313735313533653645a70b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683838376639343433353132663831316245a80b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683838653963303261666236633261343445a90b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683866373338343432346232313636613045aa0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683936316136653734656365653737356545ab0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683937383936356139383339613435343045ac0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683939303939336665343538346238393145ad0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683939653732666438653237303437396145ae0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683962346138653763356239656334346345af0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683962393538363530663533353839613845b00b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683964613439323066353366376535313645b10b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683966323338343265303431396661393145b20b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683966343335626261636266633736363445b30b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137683966383466363636306634333664643245b40b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686131623965393436663166313138376245b50b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686132623264633339663762376138363745b60b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686137393339643062376337306231616345b70b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686138386235323738323335353038393445b80b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686163343137323631656663366563626345b90b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686230653739613163313362666462643045ba0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686237633161336133386236303064316145bb0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686332333163376537646533326434666345bc0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686332343831663966356432653234333545bd0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686332363437393531383731333639333645be0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686339656164383866613064633239383745bf0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686362633966633235616461666139653645c00b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686364366563623564396630653339663045c10b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686366626139343562626165653039653445c20b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686433353935363861383538666161383945c30b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686435356430343030666339306462343445c40b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686465306265363338386138373939303045c50b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686466316531316231633732306466623745c60b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686531663061343762326532303865316545c70b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686533353733306536616237393035616545c80b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686538333463336163323532633865316645c90b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686562346535653733653861346530343545ca0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686563313262653263396537353961316345cb0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686565373262633365336365616561306545cc0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686565383336636530373061666264666145cd0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686631623637326232383937643763393645ce0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686634393739666330356461613364613245cf0b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686636336137623266373037313832306645d00b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686661356466633461303466636135623245d10b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686661396335666330393538383037303645d20b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686662643432613436323530623239356145d30b445f5a4e31307363616c655f696e666f356275696c64313756617269616e7473244c542446244754243776617269616e743137686663393765626566616262353133626345d40b3f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f64653137683065383237623433386462613730663345d50b475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683661386535316538663131333137366145d60b335f5a4e34636f726535736c69636534736f727431306d657267655f736f72743137683235623134616661336262353865303645d70b425f5a4e34636f726535736c69636534736f72743235696e73657274696f6e5f736f72745f73686966745f6c6566743137683030373765646163333738383764326545d80b335f5a4e34636f726535736c69636534736f727431306d657267655f736f72743137683438386463366339616430316232373145d90b425f5a4e34636f726535736c69636534736f72743235696e73657274696f6e5f736f72745f73686966745f6c6566743137686638376131316465326661346234663545da0b335f5a4e34636f726535736c69636534736f727431306d657267655f736f72743137683465366339386664343132333031646245db0b425f5a4e34636f726535736c69636534736f72743235696e73657274696f6e5f736f72745f73686966745f6c6566743137683965616238643961663662306561386245dc0b335f5a4e34636f726535736c69636534736f727431306d657267655f736f72743137683534323937616362663532376163653645dd0b425f5a4e34636f726535736c69636534736f72743235696e73657274696f6e5f736f72745f73686966745f6c6566743137683430656136363234633962303434343945de0b0c436f72655f76657273696f6edf0b12436f72655f657865637574655f626c6f636be00b15436f72655f696e697469616c697a655f626c6f636be10b114d657461646174615f6d65746164617461e20b1c4d657461646174615f6d657461646174615f61745f76657273696f6ee30b1a4d657461646174615f6d657461646174615f76657273696f6e73e40b2b5461676765645472616e73616374696f6e51756575655f76616c69646174655f7472616e73616374696f6ee50b1c426c6f636b4275696c6465725f6170706c795f65787472696e736963e60b1b426c6f636b4275696c6465725f66696e616c697a655f626c6f636be70b20426c6f636b4275696c6465725f696e686572656e745f65787472696e73696373e80b1c426c6f636b4275696c6465725f636865636b5f696e686572656e7473e90b1d4163636f756e744e6f6e63654170695f6163636f756e745f6e6f6e6365ea0b12546573744150495f62616c616e63655f6f66eb0b19546573744150495f62656e63686d61726b5f6164645f6f6e65ec0b20546573744150495f62656e63686d61726b5f766563746f725f6164645f6f6e65ed0b22546573744150495f66756e6374696f6e5f7369676e61747572655f6368616e676564ee0b10546573744150495f7573655f74726965ef0b1f546573744150495f62656e63686d61726b5f696e6469726563745f63616c6cf00b1d546573744150495f62656e63686d61726b5f6469726563745f63616c6cf10b19546573744150495f7665635f776974685f6361706163697479f20b18546573744150495f6765745f626c6f636b5f6e756d626572f30b1b546573744150495f746573745f656432353531395f63727970746ff40b1b546573744150495f746573745f737232353531395f63727970746ff50b19546573744150495f746573745f65636473615f63727970746ff60b14546573744150495f746573745f73746f72616765f70b14546573744150495f746573745f7769746e657373f80b1f546573744150495f746573745f6d756c7469706c655f617267756d656e7473f90b14546573744150495f646f5f74726163655f6c6f67fa0b16546573744150495f7665726966795f65643235353139fb0b17546573744150495f77726974655f6b65795f76616c7565fc0b15417572614170695f736c6f745f6475726174696f6efd0b13417572614170695f617574686f726974696573fe0b15426162654170695f636f6e66696775726174696f6eff0b1b426162654170695f63757272656e745f65706f63685f7374617274800c15426162654170695f63757272656e745f65706f6368810c12426162654170695f6e6578745f65706f6368820c35426162654170695f7375626d69745f7265706f72745f65717569766f636174696f6e5f756e7369676e65645f65787472696e736963830c24426162654170695f67656e65726174655f6b65795f6f776e6572736869705f70726f6f66840c214f6666636861696e576f726b65724170695f6f6666636861696e5f776f726b6572850c2153657373696f6e4b6579735f67656e65726174655f73657373696f6e5f6b657973860c1f53657373696f6e4b6579735f6465636f64655f73657373696f6e5f6b657973870c1e4772616e6470614170695f6772616e6470615f617574686f726974696573880c194772616e6470614170695f63757272656e745f7365745f6964890c384772616e6470614170695f7375626d69745f7265706f72745f65717569766f636174696f6e5f756e7369676e65645f65787472696e7369638a0c274772616e6470614170695f67656e65726174655f6b65795f6f776e6572736869705f70726f6f668b0c1a47656e657369734275696c6465725f6275696c645f73746174658c0c1947656e657369734275696c6465725f6765745f7072657365748d0c1b47656e657369734275696c6465725f7072657365745f6e616d65738e0c94015f5a4e3130335f244c542470616c6c65745f62616c616e6365732e2e70616c6c65742e2e43616c6c244c54245424432449244754242475323024617324753230246672616d655f737570706f72742e2e64697370617463682e2e4765744469737061746368496e666f2447542431376765745f64697370617463685f696e666f31376838616666613935313965656633323339458f0c6d5f5a4e31307363616c655f696e666f35696d706c7335365f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302424524624542447542439747970655f696e666f3137683636666361346538633762323339616445900c85015f5a4e31307363616c655f696e666f35696d706c7338305f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024636f72652e2e6f7074696f6e2e2e4f7074696f6e244c542454244754242447542439747970655f696e666f3137683032393366666334386263613131643645910c85015f5a4e31307363616c655f696e666f35696d706c7338305f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024636f72652e2e6f7074696f6e2e2e4f7074696f6e244c542454244754242447542439747970655f696e666f3137683239303431626534353431656533323045920c85015f5a4e31307363616c655f696e666f35696d706c7338305f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024636f72652e2e6f7074696f6e2e2e4f7074696f6e244c542454244754242447542439747970655f696e666f3137683666636137386131386235313132313245930c85015f5a4e31307363616c655f696e666f35696d706c7338305f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024636f72652e2e6f7074696f6e2e2e4f7074696f6e244c542454244754242447542439747970655f696e666f3137683861356637323636636261316638313545940c85015f5a4e31307363616c655f696e666f35696d706c7338305f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024636f72652e2e6f7074696f6e2e2e4f7074696f6e244c542454244754242447542439747970655f696e666f3137686130656233363139643961623935623245950c85015f5a4e31307363616c655f696e666f35696d706c7338305f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024636f72652e2e6f7074696f6e2e2e4f7074696f6e244c542454244754242447542439747970655f696e666f3137686166326361666361363561316462356445960c85015f5a4e31307363616c655f696e666f35696d706c7338305f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024636f72652e2e6f7074696f6e2e2e4f7074696f6e244c542454244754242447542439747970655f696e666f3137686166616239643865646238326130666545970c85015f5a4e31307363616c655f696e666f35696d706c7338305f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024636f72652e2e6f7074696f6e2e2e4f7074696f6e244c542454244754242447542439747970655f696e666f3137686337366332323233316264626633613845980c98015f5a4e3132305f244c542470616c6c65745f62616c616e6365732e2e70616c6c65742e2e47656e65736973436f6e666967244c54245424432449244754242475323024617324753230246672616d655f737570706f72742e2e7472616974732e2e686f6f6b732e2e4275696c6447656e65736973436f6e66696724475424356275696c643137683263343865643639393362323135333545990cb2015f5a4e3132315f244c542470616c6c65745f62616c616e6365732e2e70616c6c65742e2e50616c6c6574244c54245424432449244754242475323024617324753230246672616d655f737570706f72742e2e7472616974732e2e686f6f6b732e2e4265666f7265416c6c52756e74696d654d6967726174696f6e732447542432396265666f72655f616c6c5f72756e74696d655f6d6967726174696f6e7331376861626231343531363065396666333539459a0c8a015f5a4e38345f244c54246672616d655f737570706f72742e2e7472616974732e2e6d657461646174612e2e53746f7261676556657273696f6e247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376863323937656563623863373563383766452e6c6c766d2e383531373635383236373037343038323237359b0c7c5f5a4e31336672616d655f737570706f72743674726169747336746f6b656e733866756e6769626c6537726567756c61723130556e62616c616e636564313664656372656173655f62616c616e636531376836643366616235353565643963623762452e6c6c766d2e383531373635383236373037343038323237359c0cad025f5a4e313570616c6c65745f62616c616e6365733133696d706c5f66756e6769626c653230335f244c5424696d706c24753230246672616d655f737570706f72742e2e7472616974732e2e746f6b656e732e2e66756e6769626c652e2e726567756c61722e2e556e62616c616e636564244c5424244c5424542475323024617324753230246672616d655f73797374656d2e2e70616c6c65742e2e436f6e666967244754242e2e4163636f756e744964244754242475323024666f72247532302470616c6c65745f62616c616e6365732e2e70616c6c65742e2e50616c6c6574244c542454244324492447542424475424313377726974655f62616c616e636531376831353333343339363330323865613831452e6c6c766d2e383531373635383236373037343038323237359d0c555f5a4e31336672616d655f737570706f72743674726169747336746f6b656e733866756e6769626c6537726567756c6172364d7574617465387472616e7366657231376838303261613936376539353332663664459e0c565f5a4e31336672616d655f737570706f72743674726169747336746f6b656e733866756e6769626c6537726567756c6172364d7574617465396275726e5f66726f6d31376865303134306335626565393033393631459f0c9a025f5a4e313570616c6c65745f62616c616e6365733133696d706c5f63757272656e63793231345f244c5424696d706c24753230246672616d655f737570706f72742e2e7472616974732e2e746f6b656e732e2e63757272656e63792e2e72657365727661626c652e2e52657365727661626c6543757272656e6379244c5424244c5424542475323024617324753230246672616d655f73797374656d2e2e70616c6c65742e2e436f6e666967244754242e2e4163636f756e744964244754242475323024666f72247532302470616c6c65745f62616c616e6365732e2e70616c6c65742e2e50616c6c6574244c54245424432449244754242447542439756e726573657276653137686636633263303331396432633664663445a00c555f5a4e313570616c6c65745f62616c616e6365733670616c6c6574313950616c6c6574244c54245424432449244754243135656e737572655f75706772616465643137686161653230653531616331663136666345a10c565f5a4e313570616c6c65745f62616c616e6365733670616c6c6574313950616c6c6574244c5424542443244924475424313673746f726167655f6d657461646174613137683462373366346566306130363765313845a20c5f5f5a4e313570616c6c65745f62616c616e6365733670616c6c6574313950616c6c6574244c5424542443244924475424323570616c6c65745f636f6e7374616e74735f6d657461646174613137683931313030616265386164616432633245a30c625f5a4e313570616c6c65745f62616c616e6365733670616c6c6574313950616c6c6574244c542454244324492447542432386d75746174655f6163636f756e745f68616e646c696e675f647573743137686466353435633939303335356331356445a40ca5015f5a4e313570616c6c65745f62616c616e6365733670616c6c6574315f3130335f244c5424696d706c247532302473657264652e2e7365722e2e53657269616c697a652475323024666f72247532302470616c6c65745f62616c616e6365732e2e70616c6c65742e2e47656e65736973436f6e666967244c5424542443244924475424244754243973657269616c697a653137686134333862383138653961336639373345a50ca5015f5a4e313570616c6c65745f62616c616e6365733670616c6c6574315f3130365f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f64652475323024666f72247532302470616c6c65745f62616c616e6365732e2e70616c6c65742e2e43616c6c244c542454244324492447542424475424366465636f64653137686631613331303832333539323230653145a60ca8015f5a4e313570616c6c65745f62616c616e6365733670616c6c6574315f3130365f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f72247532302470616c6c65745f62616c616e6365732e2e70616c6c65742e2e43616c6c244c54245424432449244754242447542439656e636f64655f746f3137686639383839393837626365626265316345a70ca8015f5a4e313570616c6c65745f62616c616e6365733670616c6c6574315f3130365f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f72247532302470616c6c65745f62616c616e6365732e2e70616c6c65742e2e43616c6c244c5424542443244924475424244754243973697a655f68696e743137686161313338616130666533383935303145a80ca9015f5a4e313570616c6c65745f62616c616e6365733670616c6c6574315f3130375f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f72247532302470616c6c65745f62616c616e6365732e2e70616c6c65742e2e4576656e74244c54245424432449244754242447542439656e636f64655f746f3137683561613033636133646530393239313645a90ca9015f5a4e313570616c6c65745f62616c616e6365733670616c6c6574315f3130375f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f72247532302470616c6c65745f62616c616e6365732e2e70616c6c65742e2e4576656e74244c5424542443244924475424244754243973697a655f68696e743137686135626466653236666337303064376345aa0c94015f5a4e313570616c6c65745f62616c616e6365733670616c6c6574315f39315f244c5424696d706c2475323024636f72652e2e636c6f6e652e2e436c6f6e652475323024666f72247532302470616c6c65745f62616c616e6365732e2e70616c6c65742e2e43616c6c244c54245424432449244754242447542435636c6f6e653137686633613263613039636236316434363045ab0c9a015f5a4e313570616c6c65745f62616c616e6365733670616c6c6574315f39335f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302470616c6c65745f62616c616e6365732e2e70616c6c65742e2e43616c6c244c54245424432449244754242447542439747970655f696e666f3137686464383063303636333030663661306645ac0c9b015f5a4e313570616c6c65745f62616c616e6365733670616c6c6574315f39345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302470616c6c65745f62616c616e6365732e2e70616c6c65742e2e4572726f72244c54245424432449244754242447542439747970655f696e666f3137683931363838333533316635313465373345ad0c9b015f5a4e313570616c6c65745f62616c616e6365733670616c6c6574315f39345f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302470616c6c65745f62616c616e6365732e2e70616c6c65742e2e4576656e74244c54245424432449244754242447542439747970655f696e666f3137686262343536633138323264383963626445ae0ca3015f5a4e313773705f636f6e73656e7375735f626162653764696765737473315f3130315f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f64652475323024666f72247532302473705f636f6e73656e7375735f626162652e2e646967657374732e2e50726544696765737424475424366465636f64653137686165346537376534363539393339343245af0cb0015f5a4e313773705f636f6e73656e7375735f626162653764696765737473315f3131315f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f72247532302473705f636f6e73656e7375735f626162652e2e646967657374732e2e4e65787445706f636844657363726970746f722447542439656e636f64655f746f3137686365396637626163306434386265636145b00cb1015f5a4e313773705f636f6e73656e7375735f626162653764696765737473315f3131325f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f72247532302473705f636f6e73656e7375735f626162652e2e646967657374732e2e4e657874436f6e66696744657363726970746f722447542439656e636f64655f746f3137686364633034616339663262383636633745b10ca8015f5a4e31387061726974795f7363616c655f636f64656335636f6465633136696e6e65725f7475706c655f696d706c38395f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f722475323024244c50244f30244324503024432451302443245230245250242447542439656e636f64655f746f3137683433663439383132626261343263333245b20c8f015f5a4e38335f244c5424636f72652e2e6f7074696f6e2e2e4f7074696f6e244c542454244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542439656e636f64655f746f31376832613162373561323035646233633263452e6c6c766d2e38353137363538323637303734303832323735b30c3f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f64653137683032346265353630383738313666663645b40c3f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f64653137683064643463333836363661633961396545b50c3f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f64653137686534616164343835353932656463383945b60c3f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f64653137686634396532633239636638313337323945b70c465f5a4e34315f244c54245424753230246173247532302473657264652e2e64652e2e45787065637465642447542433666d743137686439646431616132666662333065646345b80c475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683238636534333339373333346432316245b90c475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683662623638356631633230373232663945ba0c475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686463313334623230623362326435393245bb0c315f5a4e34636f7265336f70733866756e6374696f6e32466e3463616c6c3137686536313432333437666131616638386445bc0c89015f5a4e34636f7265336f70733866756e6374696f6e35696d706c7337395f244c5424696d706c2475323024636f72652e2e6f70732e2e66756e6374696f6e2e2e466e4d7574244c542441244754242475323024666f722475323024245246246d7574247532302446244754243863616c6c5f6d75743137683461363664643761386165333132383245bd0c89015f5a4e34636f7265336f70733866756e6374696f6e35696d706c7337395f244c5424696d706c2475323024636f72652e2e6f70732e2e66756e6374696f6e2e2e466e4d7574244c542441244754242475323024666f722475323024245246246d7574247532302446244754243863616c6c5f6d75743137686539333236653837353730653031613945be0c5a5f5a4e34636f7265336f70733866756e6374696f6e36466e4f6e6365343063616c6c5f6f6e636524753762242475376224767461626c652e7368696d247537642424753764243137686263343230643933396564353465393145bf0c765f5a4e37747269655f6462366c6f6f6b757031394c6f6f6b7570244c54244c244324512447542432376c6f6f6b5f75705f776974685f63616368655f696e7465726e616c32385f24753762242475376224636c6f73757265247537642424753764243137686339633439643432333965356530343945c00c5a5f5a4e34636f7265336f70733866756e6374696f6e36466e4f6e6365343063616c6c5f6f6e636524753762242475376224767461626c652e7368696d247537642424753764243137686366383239653539326533323031353845c10c3d5f5a4e34636f726533707472323764726f705f696e5f706c616365244c5424245246247538244754243137683337663430356334376534653137386645c20c80015f5a4e39305f244c542473705f747269652e2e6e6f64655f636f6465632e2e4e6f6465436f646563244c54244824475424247532302461732475323024747269655f64622e2e6e6f64655f636f6465632e2e4e6f6465436f6465632447542431316465636f64655f706c616e3137683163626365316538333232386338336545c30c4d5f5a4e37747269655f6462366c6f6f6b757031394c6f6f6b7570244c54244c244324512447542431366c6f61645f6f776e65645f76616c75653137683938303862306133313464646166643645c40c6b5f5a4e37747269655f6462366c6f6f6b757031394c6f6f6b7570244c54244c244324512447542431366c6f61645f6f776e65645f76616c756532385f24753762242475376224636c6f73757265247537642424753764243137683861626363663136623866363531633945c50c6d5f5a4e37747269655f6462366c6f6f6b757031394c6f6f6b7570244c54244c244324512447542431386c6f6f6b5f75705f776974685f636163686532385f24753762242475376224636c6f73757265247537642424753764243137683738326530353363613166643966303445c60c435f5a4e37747269655f6462366c6f6f6b757031394c6f6f6b7570244c54244c2443245124475424376c6f6f6b5f75703137683039633332636135613062313065323645c70c735f5a4e38335f244c5424636f72652e2e6f7074696f6e2e2e4f7074696f6e244c542454244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f646524475424366465636f64653137686430306162643333393938356563313545c80c765f5a4e38335f244c5424636f72652e2e6f7074696f6e2e2e4f7074696f6e244c542454244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542439656e636f64655f746f3137686365393539636261366432663034333745c90c765f5a4e38335f244c5424636f72652e2e6f7074696f6e2e2e4f7074696f6e244c542454244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542439656e636f64655f746f3137686566326534323335346535653666373945ca0c80015f5a4e39305f244c542473705f747269652e2e6e6f64655f636f6465632e2e4e6f6465436f646563244c54244824475424247532302461732475323024747269655f64622e2e6e6f64655f636f6465632e2e4e6f6465436f6465632447542431316272616e63685f6e6f64653137683438333833323634383332626431643245cb0c83015f5a4e39305f244c542473705f747269652e2e6e6f64655f636f6465632e2e4e6f6465436f646563244c54244824475424247532302461732475323024747269655f64622e2e6e6f64655f636f6465632e2e4e6f6465436f646563244754243134657874656e73696f6e5f6e6f64653137686562313332643132376363663866356445cc0c88015f5a4e39305f244c542473705f747269652e2e6e6f64655f636f6465632e2e4e6f6465436f646563244c54244824475424247532302461732475323024747269655f64622e2e6e6f64655f636f6465632e2e4e6f6465436f6465632447542431396272616e63685f6e6f64655f6e6962626c65643137683262356631643639323265306662353945cd0c88015f5a4e39305f244c542473705f747269652e2e6e6f64655f636f6465632e2e4e6f6465436f646563244c54244824475424247532302461732475323024747269655f64622e2e6e6f64655f636f6465632e2e4e6f6465436f6465632447542431396272616e63685f6e6f64655f6e6962626c65643137686133663734346261323639376661663045ce0c88015f5a4e39305f244c542473705f747269652e2e6e6f64655f636f6465632e2e4e6f6465436f646563244c54244824475424247532302461732475323024747269655f64622e2e6e6f64655f636f6465632e2e4e6f6465436f6465632447542431396272616e63685f6e6f64655f6e6962626c65643137686236613133316364346335396536356145cf0c88015f5a4e39305f244c542473705f747269652e2e6e6f64655f636f6465632e2e4e6f6465436f646563244c54244824475424247532302461732475323024747269655f64622e2e6e6f64655f636f6465632e2e4e6f6465436f6465632447542431396272616e63685f6e6f64655f6e6962626c65643137686439613634363266306461333065336445d00c7d5f5a4e39305f244c542473705f747269652e2e6e6f64655f636f6465632e2e4e6f6465436f646563244c54244824475424247532302461732475323024747269655f64622e2e6e6f64655f636f6465632e2e4e6f6465436f64656324475424396c6561665f6e6f64653137686261396464373764653533373335366445d10c5d5f5a4e32327375627374726174655f746573745f72756e74696d6532317375627374726174655f746573745f70616c6c6574323176616c69646174655f72756e74696d655f63616c6c3137683836306266353738353930393135613945d20cac015f5a4e3133365f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e42547265654d6170244c54244b2443245624475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e636f6c6c6563742e2e46726f6d4974657261746f72244c5424244c50244b244324562452502424475424244754243966726f6d5f697465723137683536643164323365356138313661613245d30c81015f5a4e39395f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e42547265654d6170244c54244b244324562443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137686135393236383334343631613333386545d40c8f015f5a4e3130375f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e42547265654d6170244c54244b24432456244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542439656e636f64655f746f3137686366393330323439386233373934636345d50c6d5f5a4e31307363616c655f696e666f35696d706c7335365f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302424524624542447542439747970655f696e666f3137683038626339333737656366373463653245d60cac015f5a4e313073705f72756e74696d653767656e6572696336686561646572315f3130375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f72756e74696d652e2e67656e657269632e2e6865616465722e2e486561646572244c54244e756d62657224432448617368244754242447542439747970655f696e666f3137683865663066323732343530363036303145d70c82015f5a4e31307363616c655f696e666f35696d706c7337375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e626f7865642e2e426f78244c542454244754242447542439747970655f696e666f3137683832373066666663316432333263386345d80c82015f5a4e31307363616c655f696e666f35696d706c7337375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f722475323024616c6c6f632e2e626f7865642e2e426f78244c542454244754242447542439747970655f696e666f3137686539376331383464303737613437353445d90ca5015f5a4e313873705f636f6e73656e7375735f736c6f7473315f3130375f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f636f6e73656e7375735f736c6f74732e2e45717569766f636174696f6e50726f6f66244c54244865616465722443244964244754242447542439747970655f696e666f3137686331353661643662343466373838303845da0cae015f5a4e313073705f72756e74696d653767656e6572696335626c6f636b315f3131305f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302473705f72756e74696d652e2e67656e657269632e2e626c6f636b2e2e426c6f636b244c542448656164657224432445787472696e736963244754242447542439747970655f696e666f3137683934303539386666323466623937353845db0cb3015f5a4e3134335f244c542473705f72756e74696d652e2e67656e657269632e2e756e636865636b65645f65787472696e7369632e2e556e636865636b656445787472696e736963244c54244164647265737324432443616c6c2443245369676e61747572652443244578747261244754242475323024617324753230247363616c655f696e666f2e2e54797065496e666f2447542439747970655f696e666f3137686662323639313630316561613333323945dc0cd0015f5a4e313073705f72756e74696d653767656e6572696336686561646572315f3132305f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f64652475323024666f72247532302473705f72756e74696d652e2e67656e657269632e2e6865616465722e2e486561646572244c54244e756d626572244324486173682447542424475424366465636f646531376832636162303533353564396634646261452e6c6c766d2e3138313031373033313138373539303137313631dd0cd3015f5a4e313073705f72756e74696d653767656e6572696336686561646572315f3132305f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f72247532302473705f72756e74696d652e2e67656e657269632e2e6865616465722e2e486561646572244c54244e756d62657224432448617368244754242447542439656e636f64655f746f31376832346161363264393065653734316231452e6c6c766d2e3138313031373033313138373539303137313631de0c425f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646539656e636f64655f746f3137683938333034656333636130633633643745df0c4d5f5a4e313073705f76657273696f6e313452756e74696d6556657273696f6e32346465636f64655f776974685f76657273696f6e5f68696e743137683164353430623435326438383665376145e00c8e015f5a4e3131315f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e497465724d7574244c54244b2443245624475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e6974657261746f722e2e4974657261746f7224475424346e6578743137683966643839393537643137643833343545e10c93015f5a4e3131365f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e496e746f49746572244c54244b244324562443244124475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e6974657261746f722e2e4974657261746f7224475424346e6578743137683666623561626332313434333336393145e20c93015f5a4e3131365f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e496e746f49746572244c54244b244324562443244124475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e6974657261746f722e2e4974657261746f7224475424346e6578743137686363626231376336303463656532333945e30ca5015f5a4e3133355f244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e645f657373656e63652e2e457068656d6572616c244c5424532443244824475424247532302461732475323024686173685f64622e2e486173684442244c542448244324616c6c6f632e2e7665632e2e566563244c54247538244754242447542424475424336765743137686137613137616435646636313164636645e40c735f5a4e38365f244c54246d656d6f72795f64622e2e4d656d6f72794442244c5424482443244b462443245424475424247532302461732475323024686173685f64622e2e486173684442244c542448244324542447542424475424336765743137683639643861333435376236646162633445e50ccd015f5a4e3134395f244c54246d656d6f72795f64622e2e4d656d6f72794442244c5424482443244b46244324616c6c6f632e2e7665632e2e566563244c54247538244754242447542424753230246173247532302473705f73746174655f6d616368696e652e2e747269655f6261636b656e645f657373656e63652e2e547269654261636b656e6453746f72616765244c54244824475424244754243367657431376831393138373136346637356462663366452e6c6c766d2e3138313031373033313138373539303137313631e60ca8015f5a4e3133355f244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e645f657373656e63652e2e457068656d6572616c244c5424532443244824475424247532302461732475323024686173685f64622e2e486173684442244c542448244324616c6c6f632e2e7665632e2e566563244c5424753824475424244754242447542436696e736572743137683166303861393434346131393735616545e70c765f5a4e38365f244c54246d656d6f72795f64622e2e4d656d6f72794442244c5424482443244b462443245424475424247532302461732475323024686173685f64622e2e486173684442244c54244824432454244754242447542436696e736572743137683433393435626236396464636266613245e80ca8015f5a4e3133355f244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e645f657373656e63652e2e457068656d6572616c244c5424532443244824475424247532302461732475323024686173685f64622e2e486173684442244c542448244324616c6c6f632e2e7665632e2e566563244c542475382447542424475424244754243672656d6f76653137683139636137613135653039353764353445e90c765f5a4e38365f244c54246d656d6f72795f64622e2e4d656d6f72794442244c5424482443244b462443245424475424247532302461732475323024686173685f64622e2e486173684442244c5424482443245424475424244754243672656d6f76653137686132396562643361393730306162656545ea0ca9015f5a4e3133355f244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e645f657373656e63652e2e457068656d6572616c244c5424532443244824475424247532302461732475323024686173685f64622e2e486173684442244c542448244324616c6c6f632e2e7665632e2e566563244c5424753824475424244754242447542437656d706c6163653137686563616663366130356366386464616245eb0c775f5a4e38365f244c54246d656d6f72795f64622e2e4d656d6f72794442244c5424482443244b462443245424475424247532302461732475323024686173685f64622e2e486173684442244c54244824432454244754242447542437656d706c6163653137686366346133346533343239376530613045ec0caa015f5a4e3133355f244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e645f657373656e63652e2e457068656d6572616c244c5424532443244824475424247532302461732475323024686173685f64622e2e486173684442244c542448244324616c6c6f632e2e7665632e2e566563244c5424753824475424244754242447542438636f6e7461696e733137683461396435393332316430376534316645ed0ca9015f5a4e3133395f244c542473705f72756e74696d652e2e67656e657269632e2e756e636865636b65645f65787472696e7369632e2e556e636865636b656445787472696e736963244c54244164647265737324432443616c6c2443245369676e6174757265244324457874726124475424247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686634663865333431323537373033336245ee0c5f5f5a4e36365f244c5424636f72652e2e6f7074696f6e2e2e4f7074696f6e244c54245424475424247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683165353837306562393762303264316545ef0ca3015f5a4e31336672616d655f737570706f7274386469737061746368315f3130315f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230246672616d655f737570706f72742e2e64697370617463682e2e4469737061746368496e666f2447542439656e636f64655f746f3137686263363463666435616161623033366645f00ca3015f5a4e31336672616d655f737570706f7274386469737061746368315f3130315f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f7224753230246672616d655f737570706f72742e2e64697370617463682e2e5065724469737061746368436c617373244c542454244754242447542439747970655f696e666f3137686633663866386634386137363064326145f10cad015f5a4e31336672616d655f737570706f7274386469737061746368315f3131345f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f64652475323024666f7224753230246672616d655f737570706f72742e2e64697370617463682e2e5065724469737061746368436c617373244c5424542447542424475424366465636f64653137683261633565376135333733323135316545f20cb0015f5a4e31336672616d655f737570706f7274386469737061746368315f3131345f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f7224753230246672616d655f737570706f72742e2e64697370617463682e2e5065724469737061746368436c617373244c542454244754242447542439656e636f64655f746f3137683333636539393337353030643631343245f30cb9015f5a4e3135355f244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e645f657373656e63652e2e547269654261636b656e64457373656e6365244c54245324432448244324432443245224475424247532302461732475323024686173685f64622e2e486173684442526566244c542448244324616c6c6f632e2e7665632e2e566563244c54247538244754242447542424475424336765743137683162653135656637343731616435643945f40cbe015f5a4e3135355f244c542473705f73746174655f6d616368696e652e2e747269655f6261636b656e645f657373656e63652e2e547269654261636b656e64457373656e6365244c54245324432448244324432443245224475424247532302461732475323024686173685f64622e2e486173684442526566244c542448244324616c6c6f632e2e7665632e2e566563244c5424753824475424244754242447542438636f6e7461696e733137683062326533613037353336623930623845f50cbd015f5a4e3135365f244c542473705f72756e74696d652e2e67656e657269632e2e756e636865636b65645f65787472696e7369632e2e556e636865636b656445787472696e736963244c54244164647265737324432443616c6c2443245369676e61747572652443244578747261244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f646524475424366465636f64653137686437376630616436393464663664313445f60c745f5a4e34636f726533707472353664726f705f696e5f706c616365244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d6543616c6c2447542431376865643735326330326539353332656332452e6c6c766d2e3138313031373033313138373539303137313631f70cbd015f5a4e3135365f244c542473705f72756e74696d652e2e67656e657269632e2e756e636865636b65645f65787472696e7369632e2e556e636865636b656445787472696e736963244c54244164647265737324432443616c6c2443245369676e61747572652443244578747261244754242475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542436656e636f64653137683730376439356464356233623031353045f80cbb015f5a4e31356672616d655f657865637574697665313034457865637574697665244c542453797374656d244324426c6f636b244324436f6e74657874244324556e7369676e656456616c696461746f72244324416c6c50616c6c6574735769746853797374656d244324434f6e52756e74696d65557067726164652447542431326f6e5f69646c655f686f6f6b31376831383766656437613963623039306539452e6c6c766d2e3138313031373033313138373539303137313631f90c5f5f5a4e35355f244c5424582475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652447542431337573696e675f656e636f6465643137683831373638333938333633333033306245fa0ca2015f5a4e31356672616d655f657865637574697665313034457865637574697665244c542453797374656d244324426c6f636b244324436f6e74657874244324556e7369676e656456616c696461746f72244324416c6c50616c6c6574735769746853797374656d244324434f6e52756e74696d6555706772616465244754243133657865637574655f626c6f636b3137683063343561666665333663653436306145fb0ca5015f5a4e31356672616d655f657865637574697665313034457865637574697665244c542453797374656d244324426c6f636b244324436f6e74657874244324556e7369676e656456616c696461746f72244324416c6c50616c6c6574735769746853797374656d244324434f6e52756e74696d6555706772616465244754243136696e697469616c697a655f626c6f636b3137683931653935623836356530336238303045fc0ca4015f5a4e31356672616d655f657865637574697665313034457865637574697665244c542453797374656d244324426c6f636b244324436f6e74657874244324556e7369676e656456616c696461746f72244324416c6c50616c6c6574735769746853797374656d244324434f6e52756e74696d65557067726164652447542431356170706c795f65787472696e7369633137683439316434313334663736393261393645fd0cd7015f5a4e31356672616d655f657865637574697665313034457865637574697665244c542453797374656d244324426c6f636b244324436f6e74657874244324556e7369676e656456616c696461746f72244324416c6c50616c6c6574735769746853797374656d244324434f6e52756e74696d65557067726164652447542431366170706c795f65787472696e7369637332385f24753762242475376224636c6f7375726524753764242475376424313870616e69635f636f6c645f646973706c61793137686364643631656330303265373534326545fe0cc0015f5a4e31356672616d655f657865637574697665313034457865637574697665244c542453797374656d244324426c6f636b244324436f6e74657874244324556e7369676e656456616c696461746f72244324416c6c50616c6c6574735769746853797374656d244324434f6e52756e74696d6555706772616465244754243137696e686572656e74735f6170706c69656431376861383461383266323165663734373661452e6c6c766d2e3138313031373033313138373539303137313631ff0ca3015f5a4e31356672616d655f657865637574697665313034457865637574697665244c542453797374656d244324426c6f636b244324436f6e74657874244324556e7369676e656456616c696461746f72244324416c6c50616c6c6574735769746853797374656d244324434f6e52756e74696d655570677261646524475424313466696e616c697a655f626c6f636b3137683933343261346466646133393330363045800de5015f5a4e3137315f244c542473705f72756e74696d652e2e67656e657269632e2e756e636865636b65645f65787472696e7369632e2e556e636865636b656445787472696e736963244c54244c6f6f6b7570536f7572636524432443616c6c2443245369676e617475726524432445787472612447542424753230246173247532302473705f72756e74696d652e2e7472616974732e2e436865636b61626c65244c54244c6f6f6b7570244754242447542435636865636b31376864313234663163626239633562363831452e6c6c766d2e3138313031373033313138373539303137313631810da9015f5a4e31356672616d655f657865637574697665313034457865637574697665244c542453797374656d244324426c6f636b244324436f6e74657874244324556e7369676e656456616c696461746f72244324416c6c50616c6c6574735769746853797374656d244324434f6e52756e74696d655570677261646524475424323076616c69646174655f7472616e73616374696f6e3137686533626636663266623762616137653745820da2015f5a4e313570616c6c65745f62616c616e636573357479706573315f3130315f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302470616c6c65745f62616c616e6365732e2e74797065732e2e4163636f756e7444617461244c542442616c616e6365244754242447542439747970655f696e666f3137686134663065333463623066366537386445830da2015f5a4e313570616c6c65745f62616c616e636573357479706573315f3130315f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302470616c6c65745f62616c616e6365732e2e74797065732e2e42616c616e63654c6f636b244c542442616c616e6365244754242447542439747970655f696e666f3137686461366330346230616464663931643545840daf015f5a4e313570616c6c65745f62616c616e636573357479706573315f3131345f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e456e636f64652475323024666f72247532302470616c6c65745f62616c616e6365732e2e74797065732e2e4163636f756e7444617461244c542442616c616e6365244754242447542439656e636f64655f746f3137683035653134323635383662663030363345850db6015f5a4e313570616c6c65745f62616c616e636573357479706573315f3132315f244c5424696d706c24753230247363616c655f696e666f2e2e54797065496e666f2475323024666f72247532302470616c6c65745f62616c616e6365732e2e74797065732e2e5265736572766544617461244c5424526573657276654964656e74696669657224432442616c616e6365244754242447542439747970655f696e666f3137683337306339643564353236313836653145860d765f5a4e313673705f73746174655f6d616368696e653230747269655f6261636b656e645f657373656e63653339547269654261636b656e64457373656e6365244c54245324432448244324432443245224475424313273746f726167655f726f6f743137683865666630326464376262303636333445870d695f5a4e34636f726533707472373164726f705f696e5f706c616365244c542473705f747269652e2e6572726f722e2e4572726f72244c54247072696d69746976655f74797065732e2e4832353624475424244754243137683461363365306537646330353230356545880d7c5f5a4e313673705f73746174655f6d616368696e653230747269655f6261636b656e645f657373656e63653339547269654261636b656e64457373656e6365244c5424532443244824432443244324522447542431386368696c645f73746f726167655f726f6f743137683366373864393233626563646561333245890d475f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646531337573696e675f656e636f64656431376836333366663933643065626462333132458a0d475f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646531337573696e675f656e636f64656431376836656362633037343939303031313061458b0d475f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646531337573696e675f656e636f64656431376865386434663665316538323630646237458c0d3f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f646531376831383263376235323162326232653630458d0d3f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f646531376837666664336633303830343134386662458e0d3f5f5a4e31387061726974795f7363616c655f636f64656335636f64656336456e636f646536656e636f646531376862313363623731303961363536316162458f0dc9015f5a4e313873705f636f6e73656e7375735f736c6f7473315f3132305f244c5424696d706c24753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f64652475323024666f72247532302473705f636f6e73656e7375735f736c6f74732e2e45717569766f636174696f6e50726f6f66244c542448656164657224432449642447542424475424366465636f646531376838666136643630663765366265636434452e6c6c766d2e3138313031373033313138373539303137313631900d475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686361636439366563393062393632343545910d495f5a4e34345f244c54242452462454247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d743137686635656232366434323534626535343245920dc5015f5a4e34636f72653370747231333664726f705f696e5f706c616365244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e496e746f49746572244c5424616c6c6f632e2e7665632e2e566563244c5424753824475424244324244c5024616c6c6f632e2e7665632e2e566563244c542475382447542424432469333224525024244754242447542431376839643730633362626631376334313230452e6c6c766d2e3138313031373033313138373539303137313631930dea035f5a4e34636f72653370747234353564726f705f696e5f706c616365244c542424524624244c50242452462473705f636f72652e2e63727970746f5f62797465732e2e43727970746f4279746573244c542433325f7573697a6524432473705f636f72652e2e737232353531392e2e537232353531395075626c69635461672447542424432424524624244c50246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f6e6f6e63652e2e436865636b4e6f6e6365244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443246672616d655f73797374656d2e2e657874656e73696f6e732e2e636865636b5f7765696768742e2e436865636b576569676874244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242443247375627374726174655f746573745f72756e74696d652e2e436865636b53756273747261746543616c6c2443246672616d655f6d657461646174615f686173685f657874656e73696f6e2e2e436865636b4d6574616461746148617368244c54247375627374726174655f746573745f72756e74696d652e2e52756e74696d65244754242452502424525024244754243137683161306665303638363763346132373745940d715f5a4e34636f726533707472353364726f705f696e5f706c616365244c54247061726974795f7363616c655f636f6465632e2e6572726f722e2e4572726f722447542431376866386339663061313434386130383237452e6c6c766d2e3138313031373033313138373539303137313631950d565f5a4e35616c6c6f633131636f6c6c656374696f6e73356274726565336d6170323542547265654d6170244c54244b24432456244324412447542436696e736572743137683135646363323935343434666563323345960d565f5a4e35616c6c6f633131636f6c6c656374696f6e73356274726565336d6170323542547265654d6170244c54244b24432456244324412447542436696e736572743137683665313937353537323838653633313745970d785f5a4e36365f244c5424542475323024617324753230247061726974795f7363616c655f636f6465632e2e64657074685f6c696d69742e2e4465636f64654c696d69742447542432376465636f64655f616c6c5f776974685f64657074685f6c696d69743137683335326534363933313933653464326645980d785f5a4e36365f244c5424542475323024617324753230247061726974795f7363616c655f636f6465632e2e64657074685f6c696d69742e2e4465636f64654c696d69742447542432376465636f64655f616c6c5f776974685f64657074685f6c696d69743137683566366230393138373838366563393145990d785f5a4e36365f244c5424542475323024617324753230247061726974795f7363616c655f636f6465632e2e64657074685f6c696d69742e2e4465636f64654c696d69742447542432376465636f64655f616c6c5f776974685f64657074685f6c696d697431376863323961306165633566333636633636459a0dee015f5a4e3773705f74726965313373746f726167655f70726f6f663138345f244c5424696d706c2475323024636f72652e2e636f6e766572742e2e46726f6d244c54242452462473705f747269652e2e73746f726167655f70726f6f662e2e53746f7261676550726f6f66244754242475323024666f7224753230246d656d6f72795f64622e2e4d656d6f72794442244c5424482443246d656d6f72795f64622e2e486173684b6579244c54244824475424244324616c6c6f632e2e7665632e2e566563244c542475382447542424475424244754243466726f6d31376861623934623361316664313434343030459b0d785f5a4e38365f244c54246d656d6f72795f64622e2e4d656d6f72794442244c5424482443244b462443245424475424247532302461732475323024686173685f64622e2e486173684442244c54244824432454244754242447542438636f6e7461696e7331376861623135376233326539323331633162459c0d765f5a4e38395f244c54246d656d6f72795f64622e2e4d656d6f72794442244c5424482443244b462443245424475424247532302461732475323024686173685f64622e2e486173684442526566244c5424482443245424475424244754243367657431376830303965353733643864393062663764459d0d7b5f5a4e38395f244c54246d656d6f72795f64622e2e4d656d6f72794442244c5424482443244b462443245424475424247532302461732475323024686173685f64622e2e486173684442526566244c54244824432454244754242447542438636f6e7461696e7331376864333366386466313231343538613835459e0d7d5f5a4e39335f244c542473705f72756e74696d652e2e67656e657269632e2e6469676573742e2e4469676573744974656d2475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f646524475424366465636f646531376833633830616566343032373932323931459f0d7d5f5a4e39335f244c542473705f72756e74696d652e2e67656e657269632e2e6469676573742e2e4469676573744974656d2475323024617324753230247061726974795f7363616c655f636f6465632e2e636f6465632e2e4465636f646524475424366465636f64653137686633633061353438323530333035643445a00d7d5f5a4e39365f244c542473705f72756e74696d652e2e67656e657269632e2e626c6f636b2e2e426c6f636b244c542448656164657224432445787472696e73696324475424247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683166353036303735386338633231313445a10d81015f5a4e39395f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e42547265654d6170244c54244b244324562443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137683037643637626264633938386438353245a20d81015f5a4e39395f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e42547265654d6170244c54244b244324562443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137683133313338353835373532333264363945a30d81015f5a4e39395f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e42547265654d6170244c54244b244324562443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137686564363336353739313661396638326145a40d81015f5a4e39395f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e496e746f49746572244c54244b244324562443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137683361336466663835326134633765373645a50d81015f5a4e39395f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e42547265654d6170244c54244b244324562443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137683335663838613730393939656235363745a60d81015f5a4e39395f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e42547265654d6170244c54244b244324562443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137683637383233316232383133303563366445a70d81015f5a4e39395f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e42547265654d6170244c54244b244324562443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137683766393065373362353864666664333645a80d81015f5a4e39395f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e42547265654d6170244c54244b244324562443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137686433396639663265653064366333656245a90d81015f5a4e39395f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e42547265654d6170244c54244b244324562443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137686562313166663963323164383266663645aa0d9b015f5a4e39395f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e496e746f49746572244c54244b244324562443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f7031376833336539636534316536303136666136452e6c6c766d2e3138313031373033313138373539303137313631ab0d81015f5a4e39395f244c5424616c6c6f632e2e636f6c6c656374696f6e732e2e62747265652e2e6d61702e2e496e746f49746572244c54244b244324562443244124475424247532302461732475323024636f72652e2e6f70732e2e64726f702e2e44726f70244754243464726f703137686166386362623963653664613164326645ac0d4a5f5a4e396d656d6f72795f646232364d656d6f72794442244c5424482443244b4624432454244754243131636f6e736f6c69646174653137683238313430653033383934626438393345ad0d285f5a4e36737562746c6539626c61636b5f626f783137686536323366376466326130616262376645ae0d3d5f5a4e313274726163696e675f636f7265356669656c6435566973697431307265636f72645f6636343137683032636465383037316532366131373045af0da7015f5a4e3132375f244c5424244c542474726163696e672e2e6c6f672e2e4c6f6756616c7565536574247532302461732475323024636f72652e2e666d742e2e446973706c6179244754242e2e666d742e2e4c6f6756697369746f7224753230246173247532302474726163696e675f636f72652e2e6669656c642e2e56697369742447542431327265636f72645f64656275673137683035623037636631373862623438333145b00d3d5f5a4e313274726163696e675f636f7265356669656c6435566973697431307265636f72645f6936343137683433396262373930623838383436626245b10d3d5f5a4e313274726163696e675f636f7265356669656c6435566973697431307265636f72645f7536343137683639653062656331666361353130633545b20d3e5f5a4e313274726163696e675f636f7265356669656c6435566973697431317265636f72645f626f6f6c3137683762663261356164643464383863343345b30d3e5f5a4e313274726163696e675f636f7265356669656c6435566973697431317265636f72645f693132383137683963623938653735633836613462336245b40d3e5f5a4e313274726163696e675f636f7265356669656c6435566973697431317265636f72645f753132383137686561396665346331326634353739303845b50d465f5a4e34315f244c5424626f6f6c247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683465363937313737333463656137303845b60d475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683232363036316239616165643162393045b70d475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137686330653239363533313033343163393845b80d495f5a4e34345f244c54242452462454247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d743137683730376362363161356265646162303345b90d5c5f5a4e34636f726533666d74336e756d35305f244c5424696d706c2475323024636f72652e2e666d742e2e44656275672475323024666f7224753230246936342447542433666d743137686334636434656639303331326536626445ba0d5c5f5a4e34636f726533666d74336e756d35305f244c5424696d706c2475323024636f72652e2e666d742e2e44656275672475323024666f7224753230247536342447542433666d743137683264396263656536333331626632613145bb0d5d5f5a4e34636f726533666d74336e756d35315f244c5424696d706c2475323024636f72652e2e666d742e2e44656275672475323024666f722475323024693132382447542433666d743137686137323862663432373035353335623445bc0d5d5f5a4e34636f726533666d74336e756d35315f244c5424696d706c2475323024636f72652e2e666d742e2e44656275672475323024666f722475323024753132382447542433666d743137683566373264343963666530306435336645bd0d88015f5a4e34636f72653370747231303164726f705f696e5f706c616365244c5424244c542474726163696e672e2e6c6f672e2e4c6f6756616c7565536574247532302461732475323024636f72652e2e666d742e2e446973706c6179244754242e2e666d742e2e4c6f6756697369746f72244754243137686562653432376662666164633931376245be0d3a5f5a4e34636f726533707472323464726f705f696e5f706c616365244c5424663634244754243137686339666135376563323131306438396245bf0d3b5f5a4e34636f726533707472323564726f705f696e5f706c616365244c5424626f6f6c244754243137686139326339383939636639633037383445c00d3f5f5a4e3774726163696e6731355f5f6d6163726f5f737570706f727431335f5f74726163696e675f6c6f673137683532346131313064333765356338383145c10d775f5a4e36345f244c542474726163696e672e2e6c6f672e2e4c6f6756616c7565536574247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d7431376837366261326436393237626538666137452e6c6c766d2e3131373638333234303836353937383036383133c20da5015f5a4e3132375f244c5424244c542474726163696e672e2e6c6f672e2e4c6f6756616c7565536574247532302461732475323024636f72652e2e666d742e2e446973706c6179244754242e2e666d742e2e4c6f6756697369746f7224753230246173247532302474726163696e675f636f72652e2e6669656c642e2e56697369742447542431307265636f72645f7374723137683339316662663266616136303662393345c30d475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683166323337343539633033646162363345c40d4b5f5a4e34636f726533707472343164726f705f696e5f706c616365244c5424636f72652e2e666d742e2e417267756d656e7473244754243137683764303763313638373039316236653745c50d485f5a4e313274726163696e675f636f72653863616c6c73697465313544656661756c7443616c6c736974653872656769737465723137686630623433383431666539386634623145c60d83015f5a4e39325f244c542474726163696e675f636f72652e2e63616c6c736974652e2e44656661756c7443616c6c7369746524753230246173247532302474726163696e675f636f72652e2e63616c6c736974652e2e43616c6c736974652447542431327365745f696e7465726573743137686361386138323934313130643135363145c70d635f5a4e36375f244c5424636f72652e2e666d742e2e417267756d656e747324753230246173247532302474726163696e675f636f72652e2e6669656c642e2e56616c756524475424367265636f72643137683939643261656636643838393265613545c80d475f5a4e313274726163696e675f636f7265313073756273637269626572313053756273637269626572397472795f636c6f73653137686263386632666133646235333434646145c90d4b5f5a4e313274726163696e675f636f72653130737562736372696265723130537562736372696265723132646f776e636173745f7261773137683037653037303361386630383366383545ca0d81015f5a4e39355f244c542474726163696e675f636f72652e2e737562736372696265722e2e4e6f5375627363726962657224753230246173247532302474726163696e675f636f72652e2e737562736372696265722e2e5375627363726962657224475424386e65775f7370616e3137683562646637646638623162643266616545cb0d775f5a4e34636f726533707472353964726f705f696e5f706c616365244c542474726163696e675f636f72652e2e737562736372696265722e2e4e6f537562736372696265722447542431376833373964396464396234373139633638452e6c6c766d2e3130323639303030353131313334363639333430cc0d6d5f5a4e313274726163696e675f636f726531307375627363726962657231305375627363726962657232306f6e5f72656769737465725f646973706174636831376834643661353662653364386230313431452e6c6c766d2e3130323639303030353131313334363639333430cd0d675f5a4e313274726163696e675f636f726531307375627363726962657231305375627363726962657231346d61785f6c6576656c5f68696e7431376833343066346339643730633865343032452e6c6c766d2e3130323639303030353131313334363639333430ce0d665f5a4e313274726163696e675f636f726531307375627363726962657231305375627363726962657231336576656e745f656e61626c656431376833616263323733313839313039623462452e6c6c766d2e3130323639303030353131313334363639333430cf0d635f5a4e313274726163696e675f636f72653130737562736372696265723130537562736372696265723130636c6f6e655f7370616e31376835383138383935623936343235316638452e6c6c766d2e3130323639303030353131313334363639333430d00d615f5a4e313274726163696e675f636f72653130737562736372696265723130537562736372696265723964726f705f7370616e31376862323464363466303435306434636233452e6c6c766d2e3130323639303030353131313334363639333430d10d655f5a4e313274726163696e675f636f7265313073756273637269626572313053756273637269626572313263757272656e745f7370616e31376835396432613239363934366337646462452e6c6c766d2e3130323639303030353131313334363639333430d20da5015f5a4e39355f244c542474726163696e675f636f72652e2e737562736372696265722e2e4e6f5375627363726962657224753230246173247532302474726163696e675f636f72652e2e737562736372696265722e2e5375627363726962657224475424313772656769737465725f63616c6c7369746531376866323833386662633532643466316435452e6c6c766d2e3130323639303030353131313334363639333430d30d99015f5a4e39355f244c542474726163696e675f636f72652e2e737562736372696265722e2e4e6f5375627363726962657224753230246173247532302474726163696e675f636f72652e2e737562736372696265722e2e5375627363726962657224475424367265636f726431376831306563386338633164663962363030452e6c6c766d2e3130323639303030353131313334363639333430d40da7015f5a4e39355f244c542474726163696e675f636f72652e2e737562736372696265722e2e4e6f5375627363726962657224753230246173247532302474726163696e675f636f72652e2e737562736372696265722e2e537562736372696265722447542431397265636f72645f666f6c6c6f77735f66726f6d31376838653839643339656135643966376464452e6c6c766d2e3130323639303030353131313334363639333430d50d9a015f5a4e39355f244c542474726163696e675f636f72652e2e737562736372696265722e2e4e6f5375627363726962657224753230246173247532302474726163696e675f636f72652e2e737562736372696265722e2e537562736372696265722447542437656e61626c656431376833323734303061373662396461333461452e6c6c766d2e3130323639303030353131313334363639333430d60d97015f5a4e39355f244c542474726163696e675f636f72652e2e737562736372696265722e2e4e6f5375627363726962657224753230246173247532302474726163696e675f636f72652e2e737562736372696265722e2e5375627363726962657224475424346578697431376863623362646338663464303538383463452e6c6c766d2e3130323639303030353131313334363639333430d70d6e5f5a4e34636f726533707472373664726f705f696e5f706c616365244c542424524624244250246d7574247532302474726163696e675f636f72652e2e63616c6c736974652e2e44656661756c7443616c6c73697465244754243137683334633333616638313230383566333045d80d355f5a4e34636f72653970616e69636b696e6731336173736572745f6661696c65643137683366353738623363653165626438353545d90d6d5f5a4e37747269655f6462366e6962626c6531316e6962626c65736c69636534365f244c5424696d706c2475323024747269655f64622e2e6e6962626c652e2e4e6962626c65536c6963652447542439746f5f73746f7265643137683931356331353631343931613734666145da0d745f5a4e37747269655f6462366e6962626c6531316e6962626c65736c69636534365f244c5424696d706c2475323024747269655f64622e2e6e6962626c652e2e4e6962626c65536c696365244754243135746f5f73746f7265645f72616e67653137686433333136363561393364653634343145db0d725f5a4e37747269655f6462366e6962626c6531316e6962626c65736c69636534365f244c5424696d706c2475323024747269655f64622e2e6e6962626c652e2e4e6962626c65536c696365244754243133636f6d6d6f6e5f7072656669783137683235343737646533326132613162353645dc0d6f5f5a4e37747269655f6462366e6962626c6531316e6962626c65736c69636534365f244c5424696d706c2475323024747269655f64622e2e6e6962626c652e2e4e6962626c65536c69636524475424313072696768745f697465723137686235343230316661316537616364363045dd0d685f5a4e37747269655f6462366e6962626c6531316e6962626c65736c69636534365f244c5424696d706c2475323024747269655f64622e2e6e6962626c652e2e4e6962626c65536c69636524475424346c6566743137686635313365356637333463363664643045de0d745f5a4e37747269655f6462366e6962626c6531316e6962626c65736c69636534365f244c5424696d706c2475323024747269655f64622e2e6e6962626c652e2e4e6962626c65536c6963652447542431357374617274735f776974685f7665633137683734663162383465393461636635356145df0daa015f5a4e37747269655f6462366e6962626c6531316e6962626c65736c6963653131335f244c5424696d706c2475323024636f72652e2e636d702e2e5061727469616c4571244c5424747269655f64622e2e6e6962626c652e2e4e6962626c65566563244754242475323024666f722475323024747269655f64622e2e6e6962626c652e2e4e6962626c65536c696365244754243265713137683963306233343864386130653163663045e00d6a5f5a4e37747269655f6462366e6962626c65396e6962626c6576656334345f244c5424696d706c2475323024747269655f64622e2e6e6962626c652e2e4e6962626c6556656324475424313064726f705f6c617374733137683633363961666232393238326361623545e10d655f5a4e37747269655f6462366e6962626c65396e6962626c6576656334345f244c5424696d706c2475323024747269655f64622e2e6e6962626c652e2e4e6962626c655665632447542436617070656e643137683335666230356161626264346235303145e20d6e5f5a4e37747269655f6462366e6962626c65396e6962626c6576656334345f244c5424696d706c2475323024747269655f64622e2e6e6962626c652e2e4e6962626c65566563244754243134617070656e645f7061727469616c3137683461356639346431393430353232636345e30d80015f5a4e37747269655f6462366e6962626c65396e6962626c6576656334345f244c5424696d706c2475323024747269655f64622e2e6e6962626c652e2e4e6962626c65566563244754243332617070656e645f6f7074696f6e616c5f736c6963655f616e645f6e6962626c653137683635363635313439663931623065336445e40da8015f5a4e37747269655f6462366e6962626c65396e6962626c657665633131325f244c5424696d706c2475323024636f72652e2e636f6e766572742e2e46726f6d244c5424747269655f64622e2e6e6962626c652e2e4e6962626c65536c696365244754242475323024666f722475323024747269655f64622e2e6e6962626c652e2e4e6962626c65566563244754243466726f6d3137686534366236343339336536646133666645e50d705f5a4e34636f726533707472353364726f705f696e5f706c616365244c5424636f72652e2e616c6c6f632e2e6c61796f75742e2e4c61796f75744572726f722447542431376861626564323066396436393063386566452e6c6c766d2e31333436363036313031373639303532353734e60d7b5f5a4e36395f244c5424636f72652e2e616c6c6f632e2e6c61796f75742e2e4c61796f75744572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376832393637613332326332613165663338452e6c6c766d2e31333436363036313031373639303532353734e70d365f5a4e37747269655f6462397472696564626d75743131636f6d62696e655f6b65793137683530623530376135646631343734613145e80d3c5f5a4e37747269655f6462366e6962626c6531306e6962626c655f6f70733973686966745f6b65793137683339633735366532633839303766323745e90d6c5f5a4e37385f244c5424747269655f64622e2e4279746573247532302461732475323024636f72652e2e636f6e766572742e2e46726f6d244c54242452462424753562247538247535642424475424244754243466726f6d3137683564653466383332346233346439333145ea0d475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683538363636663532356634663137613045eb0d475f5a4e34325f244c54242452462454247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d743137683666353731353236306639323165623745ec0d495f5a4e34345f244c54242452462454247532302461732475323024636f72652e2e666d742e2e446973706c61792447542433666d743137686265326338666336373362383163383845ed0d5e5f5a4e34636f726533666d74336e756d35325f244c5424696d706c2475323024636f72652e2e666d742e2e44656275672475323024666f7224753230247573697a652447542433666d743137686464646433363838656435613663326345ee0d3c5f5a4e34636f726533707472323664726f705f696e5f706c616365244c54247573697a65244754243137686239336233313532626436383233646645ef0d705f5a4e34636f726533707472353364726f705f696e5f706c616365244c5424636f72652e2e616c6c6f632e2e6c61796f75742e2e4c61796f75744572726f722447542431376861626564323066396436393063386566452e6c6c766d2e36343031373133383638333435343636393034f00d6b5f5a4e35616c6c6f633473796e633136417263244c542454244324412447542439646f776e6772616465313870616e69635f636f6c645f646973706c617931376863653662613065323361326562653438452e6c6c766d2e36343031373133383638333435343636393034f10d3e5f5a4e35616c6c6f633473796e633136417263244c54245424432441244754243964726f705f736c6f773137683564653931393331643466363565636645f20d7d5f5a4e35616c6c6f633473796e6331375765616b244c542454244324412447542437757067726164653137636865636b65645f696e6372656d656e74313870616e69635f636f6c645f646973706c617931376865663764356135623466353639313230452e6c6c766d2e36343031373133383638333435343636393034f30d7b5f5a4e36395f244c5424636f72652e2e616c6c6f632e2e6c61796f75742e2e4c61796f75744572726f72247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376832393637613332326332613165663338452e6c6c766d2e36343031373133383638333435343636393034f40d335f5a4e37747269655f6462346e6f6465384e6f6465506c616e356275696c643137686538616464623066313161666230323545f50da6015f5a4e3133335f244c5424736d616c6c7665632e2e536d616c6c566563244c54244124475424247532302461732475323024636f72652e2e697465722e2e7472616974732e2e636f6c6c6563742e2e457874656e64244c5424244c542441247532302461732475323024736d616c6c7665632e2e4172726179244754242e2e4974656d244754242447542436657874656e643137683630616130333963383834623164346145f60d555f5a4e38736d616c6c7665633137536d616c6c566563244c54244124475424387472795f67726f7731376835386632666135343233623631386433452e6c6c766d2e36393837333237333039333733343939333838f70d4a5f5a4e38736d616c6c7665633137536d616c6c566563244c542441244754243231726573657276655f6f6e655f756e636865636b65643137683764353134363435393339633539333945f80d6c5f5a4e34636f726533707472343964726f705f696e5f706c616365244c5424736d616c6c7665632e2e436f6c6c656374696f6e416c6c6f634572722447542431376862336365363536333030343731626264452e6c6c766d2e36393837333237333039333733343939333838f90d775f5a4e36355f244c5424736d616c6c7665632e2e436f6c6c656374696f6e416c6c6f63457272247532302461732475323024636f72652e2e666d742e2e44656275672447542433666d7431376833333136353566633965353230393634452e6c6c766d2e36393837333237333039333733343939333838fa0dd2015f5a4e37747269655f6462366e6962626c65396e6962626c657665633135345f244c5424696d706c2475323024636f72652e2e636f6e766572742e2e46726f6d244c542424524624747269655f64622e2e6e6962626c652e2e4e6962626c65566563244754242475323024666f722475323024244c50247573697a65244324736d616c6c7665632e2e536d616c6c566563244c54242475356224753824753362242475323024343024753564242447542424525024244754243466726f6d3137683666336266376235316639313062633945fb0d515f5a4e3137636f6d70696c65725f6275696c74696e7333696e7431397370656369616c697a65645f6469765f72656d3132753132385f6469765f72656d3137686430656666646565363632343038643145fc0d095f5f6c736872746933fd0d3b5f5a4e3137636f6d70696c65725f6275696c74696e7333696e74336d756c385f5f6d756c7469333137683733666338306336316261303338656345fe0d076d656d6d6f7665ff0d3d5f5a4e3137636f6d70696c65725f6275696c74696e7333696e743475646976395f5f756469767469333137683033376537333965303466656466353445800e355f5a4e3137636f6d70696c65725f6275696c74696e73336d656d366d656d6370793137683336626139613364623131396632306145810e365f5a4e3137636f6d70696c65725f6275696c74696e73336d656d376d656d6d6f76653137683732666133663134303163653961663645820e355f5a4e3137636f6d70696c65725f6275696c74696e73336d656d366d656d7365743137686131343663346337393933363137383845830e355f5a4e3137636f6d70696c65725f6275696c74696e73336d656d366d656d636d703137683935383264343235323262343232666245840e066d656d637079850e095f5f6173686c746933860e3e5f5a4e3137636f6d70696c65725f6275696c74696e7333696e74357368696674395f5f6c7368727469333137686430316336383630363837336164333045870e085f5f6d756c746933880e066d656d636d70890e095f5f756469767469338a0e066d656d736574071201000f5f5f737461636b5f706f696e74657209170300072e726f6461746101052e6461746102042e627373003d0970726f647563657273010c70726f6365737365642d6279010572757374631d312e37372e30202861656464313733613220323032342d30332d313729", + "config": { + "babe": { + "authorities": [], + "epochConfig": { + "allowed_slots": "PrimaryAndSecondaryVRFSlots", + "c": [ + 1, + 4 + ] + } + }, + "balances": { + "balances": [] + }, + "substrateTest": { + "authorities": [] + }, + "system": {} + } + } + } +} diff --git a/substrate/bin/utils/chain-spec-builder/tests/input/chain_spec_plain.json b/substrate/bin/utils/chain-spec-builder/tests/input/chain_spec_plain.json new file mode 100644 index 000000000000..fe1fb889f278 --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/input/chain_spec_plain.json @@ -0,0 +1,40 @@ +{ + "name": "Custom", + "id": "custom", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "relay_chain": "rococo-local", + "para_id": 10101, + "custom_field": "custom_value", + "codeSubstitutes": {}, + "genesis": { + "runtimeGenesis": { + "code": "0x010203", + "config": { + "babe": { + "authorities": [], + "epochConfig": { + "allowed_slots": "PrimaryAndSecondaryVRFSlots", + "c": [ + 1, + 4 + ] + } + }, + "balances": { + "balances": [] + }, + "substrateTest": { + "authorities": [] + }, + "system": {} + } + } + } +} diff --git a/substrate/bin/utils/chain-spec-builder/tests/input/chain_spec_raw.json b/substrate/bin/utils/chain-spec-builder/tests/input/chain_spec_raw.json new file mode 100644 index 000000000000..0501d6cbe45b --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/input/chain_spec_raw.json @@ -0,0 +1,38 @@ +{ + "name": "Custom", + "id": "custom", + "chainType": "Live", + "bootNodes": [], + "telemetryEndpoints": null, + "protocolId": null, + "properties": { + "tokenDecimals": 12, + "tokenSymbol": "UNIT" + }, + "codeSubstitutes": {}, + "genesis": { + "raw": { + "top": { + "0x00771836bebdd29870ff246d305c578c4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x00771836bebdd29870ff246d305c578c5e0621c4869aa60c02be9adcc98a0d1d": "0x0cd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d1cbd2d43530a44705ad088af313e18f80b53ef16b36177cd4b77b846f2a5f07c186e1bafbb1430668c95d89b77217a402a74f64c3e103137b69e95e4b6e06b1e", + "0x1cb6f36e027abb2091cfb5110ab5087f4e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x1cb6f36e027abb2091cfb5110ab5087f66e8f035c8adbe7f1547b43c51e6f8a4": "0x00000000", + "0x1cb6f36e027abb2091cfb5110ab5087fdc6b171b77304263c292cc3ea5ed31ef": "0x0100000000000000040000000000000002", + "0x26aa394eea5630e07c48ae0c9558cef74e7b9012096b41c4eb3aaf947f6ea429": "0x0000", + "0x26aa394eea5630e07c48ae0c9558cef75684a022a34dd8bfa2baaf44f172b710": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef78a42f33323cb5ced3b44dd825fda9fcc": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a44704b568d21667356a5a050c118746bb1bdbcacd6ac9340000000000000000": "0x4545454545454545454545454545454545454545454545454545454545454545", + "0x26aa394eea5630e07c48ae0c9558cef7a7fd6c28836b9a28522dc924110cf439": "0x01", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da92c2a60ec6dd16cd8ab911865ecf7555b186e1bafbb1430668c95d89b77217a402a74f64c3e103137b69e95e4b6e06b1e": "0x00000000000000000000000001000000000000000080e03779c311000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da94f9aea1afa791265fae359272badc1cf8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48": "0x00000000000000000000000001000000000000000080c6a47e8d03000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9b0edae20838083f2cde1c4080db8cf8090b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22": "0x00000000000000000000000001000000000000000080c6a47e8d03000000000000000000000000000000000000000000000000000000000000000080", + "0x26aa394eea5630e07c48ae0c9558cef7f9cce9c888469bb1a0dceaa129672ef8": "0x0000", + "0x3a636f6465": "0x010203", + "0x3a65787472696e7369635f696e646578": "0x00000000", + "0xc2261276cc9d1f8598ea4b6a74b15c2f4e7b9012096b41c4eb3aaf947f6ea429": "0x0100", + "0xc2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80": "0x00806d8176de1800" + }, + "childrenDefault": {} + } + } +} diff --git a/substrate/bin/utils/chain-spec-builder/tests/input/code_040506.blob b/substrate/bin/utils/chain-spec-builder/tests/input/code_040506.blob new file mode 100644 index 000000000000..2dd38093cfdb --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/input/code_040506.blob @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/substrate/bin/utils/chain-spec-builder/tests/input/full.json b/substrate/bin/utils/chain-spec-builder/tests/input/full.json new file mode 100644 index 000000000000..f05e3505a2bb --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/input/full.json @@ -0,0 +1,40 @@ +{ + "babe": { + "authorities": [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", + "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b" + ], + "epochConfig": { + "allowed_slots": "PrimaryAndSecondaryVRFSlots", + "c": [ + 2, + 4 + ] + } + }, + "balances": { + "balances": [ + [ + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + 2000000000000000 + ], + [ + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y", + 2000000000000000 + ], + [ + "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b", + 5000000000000000 + ] + ] + }, + "substrateTest": { + "authorities": [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", + "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b" + ] + }, + "system": {} +} diff --git a/substrate/bin/utils/chain-spec-builder/tests/input/patch.json b/substrate/bin/utils/chain-spec-builder/tests/input/patch.json new file mode 100644 index 000000000000..cd909bbe3c3f --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/input/patch.json @@ -0,0 +1,25 @@ +{ + "balances": { + "balances": [ + [ + "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty", + 1000000000000000 + ], + [ + "5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y", + 1000000000000000 + ], + [ + "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b", + 5000000000000000 + ] + ] + }, + "substrateTest": { + "authorities": [ + "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + "5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL", + "5CcjiSgG2KLuKAsqkE2Nak1S2FbAcMr5SxRASUuwR3zSNV2b" + ] + } +} diff --git a/substrate/bin/utils/chain-spec-builder/tests/test.rs b/substrate/bin/utils/chain-spec-builder/tests/test.rs new file mode 100644 index 000000000000..f553f05f20a0 --- /dev/null +++ b/substrate/bin/utils/chain-spec-builder/tests/test.rs @@ -0,0 +1,194 @@ +// This file is part of Substrate. + +// 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 std::fs::File; + +use clap::Parser; +use sc_chain_spec::update_code_in_json_chain_spec; +use staging_chain_spec_builder::ChainSpecBuilder; + +// note: the runtime path will not be read, runtime code will be set directly, to avoid hassle with +// creating the wasm file or providing a valid existing path during test execution. +const DUMMY_PATH: &str = "fake-runtime-path"; + +const OUTPUT_FILE: &str = "/tmp/chain_spec_builder.test_output_file.json"; + +/// Asserts that the JSON in output file matches the JSON in expected file. +/// +/// This helper function reads the JSON content from the file at `OUTPUT_FILE + suffix` path. If the +/// `overwrite_code` flag is set, it updates the output chain specification with a sample code +/// vector `[1, 2, 3]` (to avoid bulky *expected* files), and then compares it against the JSON +/// content from the given `expected_path`. +fn assert_output_eq_expected(overwrite_code: bool, output_suffix: &str, expected_path: &str) { + let path = OUTPUT_FILE.to_string() + output_suffix; + let mut output: serde_json::Value = + serde_json::from_reader(File::open(path.clone()).unwrap()).unwrap(); + if overwrite_code { + update_code_in_json_chain_spec(&mut output, &vec![1, 2, 3]); + } + let expected: serde_json::Value = + serde_json::from_reader(File::open(expected_path).unwrap()).unwrap(); + + assert_eq!(expected, output); + + std::fs::remove_file(path).expect("Failed to delete file"); +} + +fn get_builder(suffix: &str, command_args: Vec<&str>) -> ChainSpecBuilder { + let path = OUTPUT_FILE.to_string() + suffix; + let mut base_args = vec!["dummy", "-c", path.as_str()]; + base_args.extend(command_args); + ChainSpecBuilder::parse_from(base_args) +} + +#[test] +fn test_create_default() { + const SUFFIX: &str = "00"; + let mut builder = get_builder(SUFFIX, vec!["create", "-r", DUMMY_PATH, "default"]); + builder.set_create_cmd_runtime_code(substrate_test_runtime::WASM_BINARY.unwrap().into()); + builder.run().unwrap(); + assert_output_eq_expected(true, SUFFIX, "tests/expected/create_default.json"); +} + +#[test] +fn test_create_with_named_preset() { + const SUFFIX: &str = "01"; + let mut builder = + get_builder(SUFFIX, vec!["create", "-r", DUMMY_PATH, "named-preset", "staging"]); + builder.set_create_cmd_runtime_code(substrate_test_runtime::WASM_BINARY.unwrap().into()); + builder.run().unwrap(); + assert_output_eq_expected(true, SUFFIX, "tests/expected/create_with_named_preset.json"); +} + +#[test] +fn test_create_with_patch() { + const SUFFIX: &str = "02"; + let mut builder = + get_builder(SUFFIX, vec!["create", "-r", DUMMY_PATH, "patch", "tests/input/patch.json"]); + builder.set_create_cmd_runtime_code(substrate_test_runtime::WASM_BINARY.unwrap().into()); + builder.run().unwrap(); + assert_output_eq_expected(true, SUFFIX, "tests/expected/create_with_patch.json"); +} + +#[test] +fn test_create_with_full() { + const SUFFIX: &str = "03"; + let mut builder = + get_builder(SUFFIX, vec!["create", "-r", DUMMY_PATH, "full", "tests/input/full.json"]); + builder.set_create_cmd_runtime_code(substrate_test_runtime::WASM_BINARY.unwrap().into()); + builder.run().unwrap(); + assert_output_eq_expected(true, SUFFIX, "tests/expected/create_with_full.json"); +} + +#[test] +fn test_create_with_params() { + const SUFFIX: &str = "04"; + let mut builder = get_builder( + SUFFIX, + vec!["create", "-r", DUMMY_PATH, "-n", "test_chain", "-i", "100", "-t", "live", "default"], + ); + builder.set_create_cmd_runtime_code(substrate_test_runtime::WASM_BINARY.unwrap().into()); + builder.run().unwrap(); + assert_output_eq_expected(true, SUFFIX, "tests/expected/create_with_params.json"); +} + +#[test] +fn test_create_parachain() { + const SUFFIX: &str = "05"; + let mut builder = get_builder( + SUFFIX, + vec![ + "create", + "-r", + DUMMY_PATH, + "-n", + "test_chain", + "-i", + "100", + "-t", + "live", + "--para-id", + "10101", + "--relay-chain", + "rococo-local", + "default", + ], + ); + builder.set_create_cmd_runtime_code(substrate_test_runtime::WASM_BINARY.unwrap().into()); + builder.run().unwrap(); + assert_output_eq_expected(true, SUFFIX, "tests/expected/create_parachain.json"); +} + +#[test] +fn test_create_raw_storage() { + const SUFFIX: &str = "06"; + let mut builder = get_builder( + SUFFIX, + vec!["create", "-r", DUMMY_PATH, "-s", "patch", "tests/input/patch.json"], + ); + builder.set_create_cmd_runtime_code(substrate_test_runtime::WASM_BINARY.unwrap().into()); + builder.run().unwrap(); + assert_output_eq_expected(true, SUFFIX, "tests/expected/create_raw_storage.json"); +} + +#[test] +fn test_update_code() { + const SUFFIX: &str = "07"; + let builder = get_builder( + SUFFIX, + vec!["update-code", "tests/input/chain_spec_plain.json", "tests/input/code_040506.blob"], + ); + builder.run().unwrap(); + assert_output_eq_expected(false, SUFFIX, "tests/expected/update_code.json"); +} + +#[test] +fn test_update_code_raw() { + const SUFFIX: &str = "08"; + let builder = get_builder( + SUFFIX, + vec!["update-code", "tests/input/chain_spec_raw.json", "tests/input/code_040506.blob"], + ); + builder.run().unwrap(); + assert_output_eq_expected(false, SUFFIX, "tests/expected/update_code_raw.json"); +} + +#[test] +fn test_convert_to_raw() { + const SUFFIX: &str = "09"; + let builder = + get_builder(SUFFIX, vec!["convert-to-raw", "tests/input/chain_spec_conversion_test.json"]); + builder.run().unwrap(); + assert_output_eq_expected(true, SUFFIX, "tests/expected/convert_to_raw.json"); +} + +#[test] +fn test_add_code_substitute() { + const SUFFIX: &str = "10"; + let builder = get_builder( + SUFFIX, + vec![ + "add-code-substitute", + "tests/input/chain_spec_plain.json", + "tests/input/code_040506.blob", + "100", + ], + ); + builder.run().unwrap(); + assert_output_eq_expected(true, SUFFIX, "tests/expected/add_code_substitute.json"); +} diff --git a/substrate/bin/utils/subkey/Cargo.toml b/substrate/bin/utils/subkey/Cargo.toml index 5aa013097c15..72677a2bd43d 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 5a3b05aa8a98..a8b3bdc864c9 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 a64ee3ab4ce1..670c74684467 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/api/src/backend.rs b/substrate/client/api/src/backend.rs index 0b2a34952401..9c9601a912ac 100644 --- a/substrate/client/api/src/backend.rs +++ b/substrate/client/api/src/backend.rs @@ -232,6 +232,9 @@ pub trait BlockImportOperation { /// Add a transaction index operation. fn update_transaction_index(&mut self, index: Vec) -> sp_blockchain::Result<()>; + + /// Configure whether to create a block gap if newly imported block is missing parent + fn set_create_gap(&mut self, create_gap: bool); } /// Interface for performing operations on the backend. diff --git a/substrate/client/api/src/client.rs b/substrate/client/api/src/client.rs index 45cfafb25846..764930984ed7 100644 --- a/substrate/client/api/src/client.rs +++ b/substrate/client/api/src/client.rs @@ -65,9 +65,16 @@ pub trait BlockOf { pub trait BlockchainEvents { /// Get block import event stream. /// - /// Not guaranteed to be fired for every imported block, only fired when the node - /// has synced to the tip or there is a re-org. Use `every_import_notification_stream()` - /// if you want a notification of every imported block regardless. + /// Not guaranteed to be fired for every imported block. Use + /// `every_import_notification_stream()` if you want a notification of every imported block + /// regardless. + /// + /// The events for this notification stream are emitted: + /// - During initial sync process: if there is a re-org while importing blocks. See + /// [here](https://github.com/paritytech/substrate/pull/7118#issuecomment-694091901) for the + /// rationale behind this. + /// - After initial sync process: on every imported block, regardless of whether it is + /// the new best block or not, causes a re-org or not. fn import_notification_stream(&self) -> ImportNotifications; /// Get a stream of every imported block. diff --git a/substrate/client/api/src/in_mem.rs b/substrate/client/api/src/in_mem.rs index ba89aede9147..c045a393bb21 100644 --- a/substrate/client/api/src/in_mem.rs +++ b/substrate/client/api/src/in_mem.rs @@ -584,6 +584,8 @@ impl backend::BlockImportOperation for BlockImportOperatio ) -> sp_blockchain::Result<()> { Ok(()) } + + fn set_create_gap(&mut self, _create_gap: bool) {} } /// In-memory backend. Keeps all states and blocks in memory. diff --git a/substrate/client/api/src/notifications/tests.rs b/substrate/client/api/src/notifications/tests.rs index fba829b1cf90..9ad7973514b2 100644 --- a/substrate/client/api/src/notifications/tests.rs +++ b/substrate/client/api/src/notifications/tests.rs @@ -18,7 +18,7 @@ use super::*; -use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper, H256 as Hash}; +use sp_runtime::testing::{Block as RawBlock, TestXt, H256 as Hash}; use std::iter::{empty, Empty}; type TestChangeSet = ( @@ -50,7 +50,7 @@ impl PartialEq for StorageChangeSet { } } -type Block = RawBlock>; +type Block = RawBlock>; #[test] fn triggering_change_should_notify_wildcard_listeners() { diff --git a/substrate/client/authority-discovery/Cargo.toml b/substrate/client/authority-discovery/Cargo.toml index 309c9c542a0b..09381ec6b553 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 83076ac8c893..cdabc1a74427 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 1f1cce160786..6f4fbac77e05 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 000000000000..547237573af2 --- /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 ef06ed7d336b..557fa9641f97 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 de7443d634fa..d71a85db8b81 100644 --- a/substrate/client/authority-discovery/src/worker/tests.rs +++ b/substrate/client/authority-discovery/src/worker/tests.rs @@ -117,9 +117,10 @@ sp_api::mock_impl_runtime_apis! { #[derive(Debug)] pub enum TestNetworkEvent { - GetCalled(KademliaKey), - PutCalled(KademliaKey, Vec), - StoreRecordCalled(KademliaKey, Vec, Option, Option), + GetCalled, + PutCalled, + PutToCalled, + StoreRecordCalled, } pub struct TestNetwork { @@ -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), @@ -187,17 +190,25 @@ impl NetworkSigner for TestNetwork { impl NetworkDHTProvider for TestNetwork { fn put_value(&self, key: KademliaKey, value: Vec) { self.put_value_call.lock().unwrap().push((key.clone(), value.clone())); - self.event_sender - .clone() - .unbounded_send(TestNetworkEvent::PutCalled(key, value)) - .unwrap(); + self.event_sender.clone().unbounded_send(TestNetworkEvent::PutCalled).unwrap(); } fn get_value(&self, key: &KademliaKey) { self.get_value_call.lock().unwrap().push(key.clone()); - self.event_sender - .clone() - .unbounded_send(TestNetworkEvent::GetCalled(key.clone())) - .unwrap(); + self.event_sender.clone().unbounded_send(TestNetworkEvent::GetCalled).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).unwrap(); } fn store_record( @@ -215,7 +226,7 @@ impl NetworkDHTProvider for TestNetwork { )); self.event_sender .clone() - .unbounded_send(TestNetworkEvent::StoreRecordCalled(key, value, publisher, expires)) + .unbounded_send(TestNetworkEvent::StoreRecordCalled) .unwrap(); } } @@ -262,9 +273,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 +385,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. @@ -511,25 +527,43 @@ fn dont_stop_polling_dht_event_stream_after_bogus_event() { pool.run_until(async { // Assert worker to trigger a lookup for the one and only authority. - assert!(matches!(network_events.next().await, Some(TestNetworkEvent::GetCalled(_)))); + assert!(matches!(network_events.next().await, Some(TestNetworkEvent::GetCalled))); // 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 +615,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 +673,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 +689,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 +934,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 +953,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 +976,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 +995,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.", ); @@ -850,7 +1128,7 @@ fn lookup_throttling() { async { // Assert worker to trigger MAX_IN_FLIGHT_LOOKUPS lookups. for _ in 0..MAX_IN_FLIGHT_LOOKUPS { - assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_)))); + assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled))); } assert_eq!( metrics.requests_pending.get(), @@ -861,19 +1139,27 @@ 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(_)))); + assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled))); assert_eq!( metrics.requests_pending.get(), (remote_public_keys.len() - MAX_IN_FLIGHT_LOOKUPS - 1) as u64 @@ -886,7 +1172,7 @@ fn lookup_throttling() { dht_event_tx.send(dht_event).await.expect("Channel has capacity of 1."); // Assert worker to trigger another lookup. - assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled(_)))); + assert!(matches!(receiver.next().await, Some(TestNetworkEvent::GetCalled))); assert_eq!( metrics.requests_pending.get(), (remote_public_keys.len() - MAX_IN_FLIGHT_LOOKUPS - 2) as u64 @@ -899,14 +1185,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 +1217,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 +1233,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 +1276,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 +1285,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 e3ae80e14f6f..cc2e0d8d04df 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/basic-authorship/src/basic_authorship.rs b/substrate/client/basic-authorship/src/basic_authorship.rs index 74805488792a..79e6fddae99f 100644 --- a/substrate/client/basic-authorship/src/basic_authorship.rs +++ b/substrate/client/basic-authorship/src/basic_authorship.rs @@ -25,7 +25,6 @@ use futures::{ channel::oneshot, future, future::{Future, FutureExt}, - select, }; use log::{debug, error, info, trace, warn}; use sc_block_builder::{BlockBuilderApi, BlockBuilderBuilder}; @@ -416,26 +415,13 @@ where let mut skipped = 0; let mut unqueue_invalid = Vec::new(); - let mut t1 = self.transaction_pool.ready_at(self.parent_number).fuse(); - let mut t2 = - futures_timer::Delay::new(deadline.saturating_duration_since((self.now)()) / 8).fuse(); - - let mut pending_iterator = select! { - res = t1 => res, - _ = t2 => { - warn!(target: LOG_TARGET, - "Timeout fired waiting for transaction pool at block #{}. \ - Proceeding with production.", - self.parent_number, - ); - self.transaction_pool.ready() - }, - }; + let delay = deadline.saturating_duration_since((self.now)()) / 8; + let mut pending_iterator = + self.transaction_pool.ready_at_with_timeout(self.parent_hash, delay).await; let block_size_limit = block_size_limit.unwrap_or(self.default_block_size_limit); - debug!(target: LOG_TARGET, "Attempting to push transactions from the pool."); - debug!(target: LOG_TARGET, "Pool status: {:?}", self.transaction_pool.status()); + debug!(target: LOG_TARGET, "Attempting to push transactions from the pool at {:?}.", self.parent_hash); let mut transaction_pushed = false; let end_reason = loop { @@ -460,7 +446,7 @@ where break EndProposingReason::HitDeadline } - let pending_tx_data = pending_tx.data().clone(); + let pending_tx_data = (**pending_tx.data()).clone(); let pending_tx_hash = pending_tx.hash().clone(); let block_size = @@ -524,7 +510,7 @@ where pending_iterator.report_invalid(&pending_tx); debug!( target: LOG_TARGET, - "[{:?}] Invalid transaction: {}", pending_tx_hash, e + "[{:?}] Invalid transaction: {} at: {}", pending_tx_hash, e, self.parent_hash ); unqueue_invalid.push(pending_tx_hash); }, @@ -577,13 +563,25 @@ where ) }; - info!( - "🎁 Prepared block for proposing at {} ({} ms) [hash: {:?}; parent_hash: {}; {extrinsics_summary}", - block.header().number(), - block_took.as_millis(), - ::Hash::from(block.header().hash()), - block.header().parent_hash(), - ); + if log::log_enabled!(log::Level::Info) { + info!( + "🎁 Prepared block for proposing at {} ({} ms) [hash: {:?}; parent_hash: {}; extrinsics_count: {}", + block.header().number(), + block_took.as_millis(), + ::Hash::from(block.header().hash()), + block.header().parent_hash(), + extrinsics.len() + ) + } else if log::log_enabled!(log::Level::Debug) { + debug!( + "🎁 Prepared block for proposing at {} ({} ms) [hash: {:?}; parent_hash: {}; {extrinsics_summary}", + block.header().number(), + block_took.as_millis(), + ::Hash::from(block.header().hash()), + block.header().parent_hash(), + ); + } + telemetry!( self.telemetry; CONSENSUS_INFO; @@ -643,22 +641,20 @@ mod tests { // given let client = Arc::new(substrate_test_runtime_client::new()); let spawner = sp_core::testing::TaskExecutor::new(); - let txpool = BasicPool::new_full( + let txpool = Arc::from(BasicPool::new_full( Default::default(), true.into(), None, spawner.clone(), client.clone(), - ); + )); let hashof0 = client.info().genesis_hash; block_on(txpool.submit_at(hashof0, SOURCE, vec![extrinsic(0), extrinsic(1)])).unwrap(); block_on( txpool.maintain(chain_event( - client - .expect_header(client.info().genesis_hash) - .expect("there should be header"), + client.expect_header(hashof0).expect("there should be header"), )), ); @@ -698,13 +694,13 @@ mod tests { fn should_not_panic_when_deadline_is_reached() { let client = Arc::new(substrate_test_runtime_client::new()); let spawner = sp_core::testing::TaskExecutor::new(); - let txpool = BasicPool::new_full( + let txpool = Arc::from(BasicPool::new_full( Default::default(), true.into(), None, spawner.clone(), client.clone(), - ); + )); let mut proposer_factory = ProposerFactory::new(spawner.clone(), client.clone(), txpool.clone(), None, None); @@ -735,13 +731,13 @@ mod tests { let (client, backend) = TestClientBuilder::new().build_with_backend(); let client = Arc::new(client); let spawner = sp_core::testing::TaskExecutor::new(); - let txpool = BasicPool::new_full( + let txpool = Arc::from(BasicPool::new_full( Default::default(), true.into(), None, spawner.clone(), client.clone(), - ); + )); let genesis_hash = client.info().best_hash; @@ -791,13 +787,13 @@ mod tests { // given let client = Arc::new(substrate_test_runtime_client::new()); let spawner = sp_core::testing::TaskExecutor::new(); - let txpool = BasicPool::new_full( + let txpool = Arc::from(BasicPool::new_full( Default::default(), true.into(), None, spawner.clone(), client.clone(), - ); + )); let medium = |nonce| { ExtrinsicBuilder::new_fill_block(Perbill::from_parts(MEDIUM)) @@ -852,7 +848,7 @@ mod tests { block }; - let import_and_maintain = |mut client: Arc, block: TestBlock| { + let import_and_maintain = |client: Arc, block: TestBlock| { let hash = block.hash(); block_on(client.import(BlockOrigin::Own, block)).unwrap(); block_on(txpool.maintain(chain_event( @@ -871,27 +867,27 @@ mod tests { // let's create one block and import it let block = propose_block(&client, 0, 2, 7); - import_and_maintain(client.clone(), block); + import_and_maintain(client.clone(), block.clone()); assert_eq!(txpool.ready().count(), 5); // now let's make sure that we can still make some progress let block = propose_block(&client, 1, 1, 5); - import_and_maintain(client.clone(), block); + import_and_maintain(client.clone(), block.clone()); assert_eq!(txpool.ready().count(), 4); // again let's make sure that we can still make some progress let block = propose_block(&client, 2, 1, 4); - import_and_maintain(client.clone(), block); + import_and_maintain(client.clone(), block.clone()); assert_eq!(txpool.ready().count(), 3); // again let's make sure that we can still make some progress let block = propose_block(&client, 3, 1, 3); - import_and_maintain(client.clone(), block); + import_and_maintain(client.clone(), block.clone()); assert_eq!(txpool.ready().count(), 2); // again let's make sure that we can still make some progress let block = propose_block(&client, 4, 2, 2); - import_and_maintain(client.clone(), block); + import_and_maintain(client.clone(), block.clone()); assert_eq!(txpool.ready().count(), 0); } @@ -899,13 +895,13 @@ mod tests { fn should_cease_building_block_when_block_limit_is_reached() { let client = Arc::new(substrate_test_runtime_client::new()); let spawner = sp_core::testing::TaskExecutor::new(); - let txpool = BasicPool::new_full( + let txpool = Arc::from(BasicPool::new_full( Default::default(), true.into(), None, spawner.clone(), client.clone(), - ); + )); let genesis_hash = client.info().genesis_hash; let genesis_header = client.expect_header(genesis_hash).expect("there should be header"); @@ -1004,13 +1000,13 @@ mod tests { // given let client = Arc::new(substrate_test_runtime_client::new()); let spawner = sp_core::testing::TaskExecutor::new(); - let txpool = BasicPool::new_full( + let txpool = Arc::from(BasicPool::new_full( Default::default(), true.into(), None, spawner.clone(), client.clone(), - ); + )); let genesis_hash = client.info().genesis_hash; let tiny = |nonce| { @@ -1073,13 +1069,13 @@ mod tests { // given let client = Arc::new(substrate_test_runtime_client::new()); let spawner = sp_core::testing::TaskExecutor::new(); - let txpool = BasicPool::new_full( + let txpool = Arc::from(BasicPool::new_full( Default::default(), true.into(), None, spawner.clone(), client.clone(), - ); + )); let genesis_hash = client.info().genesis_hash; let tiny = |who| { diff --git a/substrate/client/basic-authorship/src/lib.rs b/substrate/client/basic-authorship/src/lib.rs index 8f47c2ea00e6..adea7a3571dd 100644 --- a/substrate/client/basic-authorship/src/lib.rs +++ b/substrate/client/basic-authorship/src/lib.rs @@ -32,13 +32,13 @@ //! # use sc_transaction_pool::{BasicPool, FullChainApi}; //! # let client = Arc::new(substrate_test_runtime_client::new()); //! # let spawner = sp_core::testing::TaskExecutor::new(); -//! # let txpool = BasicPool::new_full( +//! # let txpool = Arc::from(BasicPool::new_full( //! # Default::default(), //! # true.into(), //! # None, //! # spawner.clone(), //! # client.clone(), -//! # ); +//! # )); //! // The first step is to create a `ProposerFactory`. //! let mut proposer_factory = ProposerFactory::new( //! spawner, diff --git a/substrate/client/block-builder/Cargo.toml b/substrate/client/block-builder/Cargo.toml index 47e3fc39c289..08392e18227f 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/block-builder/src/lib.rs b/substrate/client/block-builder/src/lib.rs index 2f22cd42591f..d02d0e321805 100644 --- a/substrate/client/block-builder/src/lib.rs +++ b/substrate/client/block-builder/src/lib.rs @@ -320,7 +320,7 @@ where header.extrinsics_root().clone(), HashingFor::::ordered_trie_root( self.extrinsics.iter().map(Encode::encode).collect(), - sp_runtime::StateVersion::V0, + self.api.version(self.parent_hash)?.extrinsics_root_state_version(), ), ); diff --git a/substrate/client/chain-spec/Cargo.toml b/substrate/client/chain-spec/Cargo.toml index b3cd4bd57db8..2e885240936f 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 4ab8c849cc7f..ccd898447bea 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 5f90f549e022..aa3c1ba3e6f1 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/genesis_config_builder.rs b/substrate/client/chain-spec/src/genesis_config_builder.rs index 13a2f3c072f5..66989495d423 100644 --- a/substrate/client/chain-spec/src/genesis_config_builder.rs +++ b/substrate/client/chain-spec/src/genesis_config_builder.rs @@ -27,6 +27,7 @@ use sp_core::{ traits::{CallContext, CodeExecutor, Externalities, FetchRuntimeCode, RuntimeCode}, }; use sp_genesis_builder::{PresetId, Result as BuildResult}; +pub use sp_genesis_builder::{DEV_RUNTIME_PRESET, LOCAL_TESTNET_RUNTIME_PRESET}; use sp_state_machine::BasicExternalities; use std::borrow::Cow; diff --git a/substrate/client/chain-spec/src/lib.rs b/substrate/client/chain-spec/src/lib.rs index c43f9e89b8a9..43639ffb5aae 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. @@ -341,7 +347,9 @@ pub use self::{ construct_genesis_block, resolve_state_version_from_wasm, BuildGenesisBlock, GenesisBlockBuilder, }, - genesis_config_builder::GenesisConfigBuilderRuntimeCaller, + genesis_config_builder::{ + GenesisConfigBuilderRuntimeCaller, DEV_RUNTIME_PRESET, LOCAL_TESTNET_RUNTIME_PRESET, + }, json_patch::merge as json_merge, }; pub use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup}; @@ -351,9 +359,9 @@ use sc_telemetry::TelemetryEndpoints; use sp_core::storage::Storage; use sp_runtime::BuildStorage; -/// The type of a chain. +/// The type of chain. /// -/// This can be used by tools to determine the type of a chain for displaying +/// This can be used by tools to determine the type of chain for displaying /// additional information or enabling additional features. #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)] #[cfg_attr(feature = "clap", derive(clap::ValueEnum))] diff --git a/substrate/client/cli/Cargo.toml b/substrate/client/cli/Cargo.toml index 1e4017c23af2..f0b9f8f9b905 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" @@ -43,6 +43,7 @@ sc-network = { workspace = true, default-features = true } sc-service = { workspace = true } sc-telemetry = { workspace = true, default-features = true } sc-tracing = { workspace = true, default-features = true } +sc-transaction-pool = { workspace = true, default-features = true } sc-utils = { workspace = true, default-features = true } sp-blockchain = { workspace = true, default-features = true } sp-core = { workspace = true, default-features = true } diff --git a/substrate/client/cli/src/arg_enums.rs b/substrate/client/cli/src/arg_enums.rs index b5819d03447a..cd245dc01554 100644 --- a/substrate/client/cli/src/arg_enums.rs +++ b/substrate/client/cli/src/arg_enums.rs @@ -168,6 +168,19 @@ pub enum RpcMethods { Unsafe, } +impl FromStr for RpcMethods { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "safe" => Ok(RpcMethods::Safe), + "unsafe" => Ok(RpcMethods::Unsafe), + "auto" => Ok(RpcMethods::Auto), + invalid => Err(format!("Invalid rpc methods {invalid}")), + } + } +} + impl Into for RpcMethods { fn into(self) -> sc_service::config::RpcMethods { match self { diff --git a/substrate/client/cli/src/commands/import_blocks_cmd.rs b/substrate/client/cli/src/commands/import_blocks_cmd.rs index 815c6ab18aa6..6bd607901e38 100644 --- a/substrate/client/cli/src/commands/import_blocks_cmd.rs +++ b/substrate/client/cli/src/commands/import_blocks_cmd.rs @@ -28,7 +28,7 @@ use sp_runtime::traits::Block as BlockT; use std::{ fmt::Debug, fs, - io::{self, Read, Seek}, + io::{self, Read}, path::PathBuf, sync::Arc, }; @@ -58,11 +58,6 @@ pub struct ImportBlocksCmd { pub import_params: ImportParams, } -/// Internal trait used to cast to a dynamic type that implements Read and Seek. -trait ReadPlusSeek: Read + Seek {} - -impl ReadPlusSeek for T {} - impl ImportBlocksCmd { /// Run the import-blocks command pub async fn run(&self, client: Arc, import_queue: IQ) -> error::Result<()> diff --git a/substrate/client/cli/src/commands/run_cmd.rs b/substrate/client/cli/src/commands/run_cmd.rs index c1288b502c95..f91d18aca749 100644 --- a/substrate/client/cli/src/commands/run_cmd.rs +++ b/substrate/client/cli/src/commands/run_cmd.rs @@ -17,15 +17,12 @@ // along with this program. If not, see . use crate::{ - arg_enums::{Cors, RpcMethods}, error::{Error, Result}, params::{ - ImportParams, KeystoreParams, NetworkParams, OffchainWorkerParams, SharedParams, - TransactionPoolParams, + ImportParams, KeystoreParams, NetworkParams, OffchainWorkerParams, RpcEndpoint, + SharedParams, TransactionPoolParams, }, - CliConfiguration, PrometheusParams, RuntimeParams, TelemetryParams, - RPC_DEFAULT_MAX_CONNECTIONS, RPC_DEFAULT_MAX_REQUEST_SIZE_MB, RPC_DEFAULT_MAX_RESPONSE_SIZE_MB, - RPC_DEFAULT_MAX_SUBS_PER_CONN, RPC_DEFAULT_MESSAGE_CAPACITY_PER_CONN, + CliConfiguration, PrometheusParams, RpcParams, RuntimeParams, TelemetryParams, }; use clap::Parser; use regex::Regex; @@ -36,10 +33,7 @@ use sc_service::{ ChainSpec, Role, }; use sc_telemetry::TelemetryEndpoints; -use std::{ - net::{IpAddr, Ipv4Addr, SocketAddr}, - num::NonZeroU32, -}; +use std::num::NonZeroU32; /// The `run` command used to run a node. #[derive(Debug, Clone, Parser)] @@ -59,113 +53,16 @@ pub struct RunCmd { #[arg(long)] pub no_grandpa: bool, - /// Listen to all RPC interfaces (default: local). - /// - /// Not all RPC methods are safe to be exposed publicly. - /// - /// Use an RPC proxy server to filter out dangerous methods. More details: - /// . - /// - /// Use `--unsafe-rpc-external` to suppress the warning if you understand the risks. - #[arg(long)] - pub rpc_external: bool, - - /// Listen to all RPC interfaces. - /// - /// Same as `--rpc-external`. - #[arg(long)] - pub unsafe_rpc_external: bool, - - /// RPC methods to expose. - #[arg( - long, - value_name = "METHOD SET", - value_enum, - ignore_case = true, - default_value_t = RpcMethods::Auto, - verbatim_doc_comment - )] - pub rpc_methods: RpcMethods, - - /// RPC rate limiting (calls/minute) for each connection. - /// - /// This is disabled by default. - /// - /// For example `--rpc-rate-limit 10` will maximum allow - /// 10 calls per minute per connection. - #[arg(long)] - pub rpc_rate_limit: Option, - - /// Disable RPC rate limiting for certain ip addresses. - /// - /// Each IP address must be in CIDR notation such as `1.2.3.4/24`. - #[arg(long, num_args = 1..)] - pub rpc_rate_limit_whitelisted_ips: Vec, - - /// Trust proxy headers for disable rate limiting. - /// - /// By default the rpc server will not trust headers such `X-Real-IP`, `X-Forwarded-For` and - /// `Forwarded` and this option will make the rpc server to trust these headers. - /// - /// For instance this may be secure if the rpc server is behind a reverse proxy and that the - /// proxy always sets these headers. - #[arg(long)] - pub rpc_rate_limit_trust_proxy_headers: bool, - - /// Set the maximum RPC request payload size for both HTTP and WS in megabytes. - #[arg(long, default_value_t = RPC_DEFAULT_MAX_REQUEST_SIZE_MB)] - pub rpc_max_request_size: u32, - - /// Set the maximum RPC response payload size for both HTTP and WS in megabytes. - #[arg(long, default_value_t = RPC_DEFAULT_MAX_RESPONSE_SIZE_MB)] - pub rpc_max_response_size: u32, - - /// Set the maximum concurrent subscriptions per connection. - #[arg(long, default_value_t = RPC_DEFAULT_MAX_SUBS_PER_CONN)] - pub rpc_max_subscriptions_per_connection: u32, - - /// Specify JSON-RPC server TCP port. - #[arg(long, value_name = "PORT")] - pub rpc_port: Option, - - /// Maximum number of RPC server connections. - #[arg(long, value_name = "COUNT", default_value_t = RPC_DEFAULT_MAX_CONNECTIONS)] - pub rpc_max_connections: u32, - - /// The number of messages the RPC server is allowed to keep in memory. - /// - /// If the buffer becomes full then the server will not process - /// new messages until the connected client start reading the - /// underlying messages. - /// - /// This applies per connection which includes both - /// JSON-RPC methods calls and subscriptions. - #[arg(long, default_value_t = RPC_DEFAULT_MESSAGE_CAPACITY_PER_CONN)] - pub rpc_message_buffer_capacity_per_connection: u32, - - /// Disable RPC batch requests - #[arg(long, alias = "rpc_no_batch_requests", conflicts_with_all = &["rpc_max_batch_request_len"])] - pub rpc_disable_batch_requests: bool, - - /// Limit the max length per RPC batch request - #[arg(long, conflicts_with_all = &["rpc_disable_batch_requests"], value_name = "LEN")] - pub rpc_max_batch_request_len: Option, - - /// Specify browser *origins* allowed to access the HTTP & WS RPC servers. - /// - /// A comma-separated list of origins (protocol://domain or special `null` - /// value). Value of `all` will disable origin validation. Default is to - /// allow localhost and origins. When running in - /// `--dev` mode the default is to allow all origins. - #[arg(long, value_name = "ORIGINS")] - pub rpc_cors: Option, - /// The human-readable name for this node. /// /// It's used as network node name. #[arg(long, value_name = "NAME")] pub name: Option, + #[allow(missing_docs)] + #[clap(flatten)] + pub rpc_params: RpcParams, + #[allow(missing_docs)] #[clap(flatten)] pub telemetry_params: TelemetryParams, @@ -304,7 +201,17 @@ impl CliConfiguration for RunCmd { } fn network_params(&self) -> Option<&NetworkParams> { - Some(&self.network_params) + let network_params = &self.network_params; + let is_authority = self.role(self.is_dev().ok()?).ok()?.is_authority(); + if is_authority && network_params.public_addr.is_empty() { + eprintln!( + "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." + ); + } + + Some(network_params) } fn keystore_params(&self) -> Option<&KeystoreParams> { @@ -386,83 +293,51 @@ impl CliConfiguration for RunCmd { } fn rpc_max_connections(&self) -> Result { - Ok(self.rpc_max_connections) + Ok(self.rpc_params.rpc_max_connections) } fn rpc_cors(&self, is_dev: bool) -> Result>> { - Ok(self - .rpc_cors - .clone() - .unwrap_or_else(|| { - if is_dev { - log::warn!("Running in --dev mode, RPC CORS has been disabled."); - Cors::All - } else { - Cors::List(vec![ - "http://localhost:*".into(), - "http://127.0.0.1:*".into(), - "https://localhost:*".into(), - "https://127.0.0.1:*".into(), - "https://polkadot.js.org".into(), - ]) - } - }) - .into()) - } - - fn rpc_addr(&self, default_listen_port: u16) -> Result> { - let interface = rpc_interface( - self.rpc_external, - self.unsafe_rpc_external, - self.rpc_methods, - self.validator, - )?; - - Ok(Some(SocketAddr::new(interface, self.rpc_port.unwrap_or(default_listen_port)))) + self.rpc_params.rpc_cors(is_dev) + } + + fn rpc_addr(&self, default_listen_port: u16) -> Result>> { + self.rpc_params.rpc_addr(self.is_dev()?, self.validator, default_listen_port) } fn rpc_methods(&self) -> Result { - Ok(self.rpc_methods.into()) + Ok(self.rpc_params.rpc_methods.into()) } fn rpc_max_request_size(&self) -> Result { - Ok(self.rpc_max_request_size) + Ok(self.rpc_params.rpc_max_request_size) } fn rpc_max_response_size(&self) -> Result { - Ok(self.rpc_max_response_size) + Ok(self.rpc_params.rpc_max_response_size) } fn rpc_max_subscriptions_per_connection(&self) -> Result { - Ok(self.rpc_max_subscriptions_per_connection) + Ok(self.rpc_params.rpc_max_subscriptions_per_connection) } fn rpc_buffer_capacity_per_connection(&self) -> Result { - Ok(self.rpc_message_buffer_capacity_per_connection) + Ok(self.rpc_params.rpc_message_buffer_capacity_per_connection) } fn rpc_batch_config(&self) -> Result { - let cfg = if self.rpc_disable_batch_requests { - RpcBatchRequestConfig::Disabled - } else if let Some(l) = self.rpc_max_batch_request_len { - RpcBatchRequestConfig::Limit(l) - } else { - RpcBatchRequestConfig::Unlimited - }; - - Ok(cfg) + self.rpc_params.rpc_batch_config() } fn rpc_rate_limit(&self) -> Result> { - Ok(self.rpc_rate_limit) + Ok(self.rpc_params.rpc_rate_limit) } fn rpc_rate_limit_whitelisted_ips(&self) -> Result> { - Ok(self.rpc_rate_limit_whitelisted_ips.clone()) + Ok(self.rpc_params.rpc_rate_limit_whitelisted_ips.clone()) } fn rpc_rate_limit_trust_proxy_headers(&self) -> Result { - Ok(self.rpc_rate_limit_trust_proxy_headers) + Ok(self.rpc_params.rpc_rate_limit_trust_proxy_headers) } fn transaction_pool(&self, is_dev: bool) -> Result { @@ -496,57 +371,28 @@ pub fn is_node_name_valid(_name: &str) -> std::result::Result<(), &str> { let name = _name.to_string(); if name.is_empty() { - return Err("Node name cannot be empty") + return Err("Node name cannot be empty"); } if name.chars().count() >= crate::NODE_NAME_MAX_LENGTH { - return Err("Node name too long") + return Err("Node name too long"); } let invalid_chars = r"[\\.@]"; let re = Regex::new(invalid_chars).unwrap(); if re.is_match(&name) { - return Err("Node name should not contain invalid chars such as '.' and '@'") + return Err("Node name should not contain invalid chars such as '.' and '@'"); } let invalid_patterns = r"^https?:"; let re = Regex::new(invalid_patterns).unwrap(); if re.is_match(&name) { - return Err("Node name should not contain urls") + return Err("Node name should not contain urls"); } Ok(()) } -fn rpc_interface( - is_external: bool, - is_unsafe_external: bool, - rpc_methods: RpcMethods, - is_validator: bool, -) -> Result { - if is_external && is_validator && rpc_methods != RpcMethods::Unsafe { - return Err(Error::Input( - "--rpc-external option shouldn't be used if the node is running as \ - a validator. Use `--unsafe-rpc-external` or `--rpc-methods=unsafe` if you understand \ - the risks. See the options description for more information." - .to_owned(), - )) - } - - if is_external || is_unsafe_external { - if rpc_methods == RpcMethods::Unsafe { - log::warn!( - "It isn't safe to expose RPC publicly without a proxy server that filters \ - available set of RPC methods." - ); - } - - Ok(Ipv4Addr::UNSPECIFIED.into()) - } else { - Ok(Ipv4Addr::LOCALHOST.into()) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/substrate/client/cli/src/commands/vanity.rs b/substrate/client/cli/src/commands/vanity.rs index 330a59493efc..9acacb4b15b2 100644 --- a/substrate/client/cli/src/commands/vanity.rs +++ b/substrate/client/cli/src/commands/vanity.rs @@ -166,8 +166,6 @@ mod tests { crypto::{default_ss58_version, Ss58AddressFormatRegistry, Ss58Codec}, sr25519, Pair, }; - #[cfg(feature = "bench")] - use test::Bencher; #[test] fn vanity() { @@ -225,16 +223,4 @@ mod tests { 0 ); } - - #[cfg(feature = "bench")] - #[bench] - fn bench_paranoiac(b: &mut Bencher) { - b.iter(|| generate_key("polk")); - } - - #[cfg(feature = "bench")] - #[bench] - fn bench_not_paranoiac(b: &mut Bencher) { - b.iter(|| generate_key("polk")); - } } diff --git a/substrate/client/cli/src/config.rs b/substrate/client/cli/src/config.rs index 783c9313121f..59238b3307cf 100644 --- a/substrate/client/cli/src/config.rs +++ b/substrate/client/cli/src/config.rs @@ -20,21 +20,22 @@ use crate::{ arg_enums::Database, error::Result, DatabaseParams, ImportParams, KeystoreParams, - NetworkParams, NodeKeyParams, OffchainWorkerParams, PruningParams, SharedParams, SubstrateCli, + NetworkParams, NodeKeyParams, OffchainWorkerParams, PruningParams, RpcEndpoint, SharedParams, + SubstrateCli, }; use log::warn; use names::{Generator, Name}; use sc_service::{ config::{ - BasePath, Configuration, DatabaseSource, IpNetwork, KeystoreConfig, NetworkConfiguration, - NodeKeyConfig, OffchainWorkerConfig, OutputFormat, PrometheusConfig, PruningMode, Role, - RpcBatchRequestConfig, RpcMethods, TelemetryEndpoints, TransactionPoolOptions, - WasmExecutionMethod, + BasePath, Configuration, DatabaseSource, ExecutorConfiguration, IpNetwork, KeystoreConfig, + NetworkConfiguration, NodeKeyConfig, OffchainWorkerConfig, PrometheusConfig, PruningMode, + Role, RpcBatchRequestConfig, RpcConfiguration, RpcMethods, TelemetryEndpoints, + TransactionPoolOptions, WasmExecutionMethod, }, BlocksPruning, ChainSpec, TracingReceiver, }; use sc_tracing::logging::LoggerBuilder; -use std::{net::SocketAddr, num::NonZeroU32, path::PathBuf}; +use std::{num::NonZeroU32, path::PathBuf}; /// The maximum number of characters for a node name. pub(crate) const NODE_NAME_MAX_LENGTH: usize = 64; @@ -172,7 +173,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 +186,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. @@ -295,7 +302,7 @@ pub trait CliConfiguration: Sized { } /// Get the RPC address. - fn rpc_addr(&self, _default_listen_port: u16) -> Result> { + fn rpc_addr(&self, _default_listen_port: u16) -> Result>> { Ok(None) } @@ -498,6 +505,10 @@ pub trait CliConfiguration: Sized { let telemetry_endpoints = self.telemetry_endpoints(&chain_spec)?; let runtime_cache_size = self.runtime_cache_size()?; + let rpc_addrs: Option> = self + .rpc_addr(DCV::rpc_listen_port())? + .map(|addrs| addrs.into_iter().map(Into::into).collect()); + Ok(Configuration { impl_name: C::impl_name(), impl_version: C::impl_version(), @@ -519,26 +530,32 @@ pub trait CliConfiguration: Sized { trie_cache_maximum_size: self.trie_cache_maximum_size()?, state_pruning: self.state_pruning()?, blocks_pruning: self.blocks_pruning()?, - wasm_method: self.wasm_method()?, + executor: ExecutorConfiguration { + wasm_method: self.wasm_method()?, + default_heap_pages: self.default_heap_pages()?, + max_runtime_instances, + runtime_cache_size, + }, wasm_runtime_overrides: self.wasm_runtime_overrides(), - rpc_addr: self.rpc_addr(DCV::rpc_listen_port())?, - rpc_methods: self.rpc_methods()?, - rpc_max_connections: self.rpc_max_connections()?, - rpc_cors: self.rpc_cors(is_dev)?, - rpc_max_request_size: self.rpc_max_request_size()?, - rpc_max_response_size: self.rpc_max_response_size()?, - rpc_id_provider: None, - rpc_max_subs_per_conn: self.rpc_max_subscriptions_per_connection()?, - rpc_port: DCV::rpc_listen_port(), - rpc_message_buffer_capacity: self.rpc_buffer_capacity_per_connection()?, - rpc_batch_config: self.rpc_batch_config()?, - rpc_rate_limit: self.rpc_rate_limit()?, - rpc_rate_limit_whitelisted_ips: self.rpc_rate_limit_whitelisted_ips()?, - rpc_rate_limit_trust_proxy_headers: self.rpc_rate_limit_trust_proxy_headers()?, + rpc: RpcConfiguration { + addr: rpc_addrs, + methods: self.rpc_methods()?, + max_connections: self.rpc_max_connections()?, + cors: self.rpc_cors(is_dev)?, + max_request_size: self.rpc_max_request_size()?, + max_response_size: self.rpc_max_response_size()?, + id_provider: None, + max_subs_per_conn: self.rpc_max_subscriptions_per_connection()?, + port: DCV::rpc_listen_port(), + message_buffer_capacity: self.rpc_buffer_capacity_per_connection()?, + batch_config: self.rpc_batch_config()?, + rate_limit: self.rpc_rate_limit()?, + rate_limit_whitelisted_ips: self.rpc_rate_limit_whitelisted_ips()?, + rate_limit_trust_proxy_headers: self.rpc_rate_limit_trust_proxy_headers()?, + }, prometheus_config: self .prometheus_config(DCV::prometheus_listen_port(), &chain_spec)?, telemetry_endpoints, - default_heap_pages: self.default_heap_pages()?, offchain_worker: self.offchain_worker(&role)?, force_authoring: self.force_authoring()?, disable_grandpa: self.disable_grandpa()?, @@ -546,12 +563,9 @@ pub trait CliConfiguration: Sized { tracing_targets: self.tracing_targets()?, tracing_receiver: self.tracing_receiver()?, chain_spec, - max_runtime_instances, announce_block: self.announce_block()?, role, base_path, - informant_output_format: OutputFormat { enable_color: !self.disable_log_color()? }, - runtime_cache_size, }) } @@ -608,15 +622,9 @@ pub trait CliConfiguration: Sized { /// } /// } /// ``` - fn init( - &self, - support_url: &String, - impl_version: &String, - logger_hook: F, - config: &Configuration, - ) -> Result<()> + fn init(&self, support_url: &String, impl_version: &String, logger_hook: F) -> Result<()> where - F: FnOnce(&mut LoggerBuilder, &Configuration), + F: FnOnce(&mut LoggerBuilder), { sp_panic_handler::set(support_url, impl_version); @@ -635,7 +643,7 @@ pub trait CliConfiguration: Sized { } // Call hook for custom profiling setup. - logger_hook(&mut logger, config); + logger_hook(&mut logger); logger.init()?; diff --git a/substrate/client/cli/src/lib.rs b/substrate/client/cli/src/lib.rs index 1bb9fec0e276..4db70f99c803 100644 --- a/substrate/client/cli/src/lib.rs +++ b/substrate/client/cli/src/lib.rs @@ -25,6 +25,7 @@ #![warn(unused_imports)] use clap::{CommandFactory, FromArgMatches, Parser}; +use log::warn; use sc_service::Configuration; pub mod arg_enums; @@ -242,7 +243,10 @@ pub trait SubstrateCli: Sized { let config = command.create_configuration(self, tokio_runtime.handle().clone())?; - command.init(&Self::support_url(), &Self::impl_version(), logger_hook, &config)?; + command.init(&Self::support_url(), &Self::impl_version(), |logger_builder| { + logger_hook(logger_builder, &config) + })?; + Runner::new(config, tokio_runtime, signals) } } diff --git a/substrate/client/cli/src/params/mod.rs b/substrate/client/cli/src/params/mod.rs index f07223ec6a73..977b57ba0658 100644 --- a/substrate/client/cli/src/params/mod.rs +++ b/substrate/client/cli/src/params/mod.rs @@ -25,6 +25,7 @@ mod node_key_params; mod offchain_worker_params; mod prometheus_params; mod pruning_params; +mod rpc_params; mod runtime_params; mod shared_params; mod telemetry_params; @@ -32,6 +33,7 @@ mod transaction_pool_params; use crate::arg_enums::{CryptoScheme, OutputType}; use clap::Args; +use sc_service::config::{IpNetwork, RpcBatchRequestConfig}; use sp_core::crypto::{Ss58AddressFormat, Ss58AddressFormatRegistry}; use sp_runtime::{ generic::BlockId, @@ -42,7 +44,7 @@ use std::{fmt::Debug, str::FromStr}; pub use crate::params::{ database_params::*, import_params::*, keystore_params::*, message_params::*, mixnet_params::*, network_params::*, node_key_params::*, offchain_worker_params::*, prometheus_params::*, - pruning_params::*, runtime_params::*, shared_params::*, telemetry_params::*, + pruning_params::*, rpc_params::*, runtime_params::*, shared_params::*, telemetry_params::*, transaction_pool_params::*, }; diff --git a/substrate/client/cli/src/params/node_key_params.rs b/substrate/client/cli/src/params/node_key_params.rs index 0e12c7a2a2d3..70671bff8c05 100644 --- a/substrate/client/cli/src/params/node_key_params.rs +++ b/substrate/client/cli/src/params/node_key_params.rs @@ -116,8 +116,8 @@ impl NodeKeyParams { .clone() .unwrap_or_else(|| net_config_dir.join(NODE_KEY_ED25519_FILE)); if !self.unsafe_force_node_key_generation && - role.is_authority() && !is_dev && - !key_path.exists() + role.is_authority() && + !is_dev && !key_path.exists() { return Err(Error::NetworkKeyNotFound(key_path)) } @@ -237,7 +237,6 @@ mod tests { |params| { let dir = PathBuf::from(net_config_dir.clone()); let typ = params.node_key_type; - let role = role.clone(); params.node_key(net_config_dir, role, is_dev).and_then(move |c| match c { NodeKeyConfig::Ed25519(sc_network::config::Secret::File(ref f)) if typ == NodeKeyType::Ed25519 && diff --git a/substrate/client/cli/src/params/rpc_params.rs b/substrate/client/cli/src/params/rpc_params.rs new file mode 100644 index 000000000000..f9937b59bbaf --- /dev/null +++ b/substrate/client/cli/src/params/rpc_params.rs @@ -0,0 +1,681 @@ +// This file is part of Substrate. + +// 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 crate::{ + arg_enums::{Cors, RpcMethods}, + params::{IpNetwork, RpcBatchRequestConfig}, + RPC_DEFAULT_MAX_CONNECTIONS, RPC_DEFAULT_MAX_REQUEST_SIZE_MB, RPC_DEFAULT_MAX_RESPONSE_SIZE_MB, + RPC_DEFAULT_MAX_SUBS_PER_CONN, RPC_DEFAULT_MESSAGE_CAPACITY_PER_CONN, +}; +use clap::Args; +use std::{ + net::{Ipv4Addr, Ipv6Addr, SocketAddr}, + num::NonZeroU32, +}; + +const RPC_LISTEN_ADDR: &str = "listen-addr"; +const RPC_CORS: &str = "cors"; +const RPC_MAX_CONNS: &str = "max-connections"; +const RPC_MAX_REQUEST_SIZE: &str = "max-request-size"; +const RPC_MAX_RESPONSE_SIZE: &str = "max-response-size"; +const RPC_MAX_SUBS_PER_CONN: &str = "max-subscriptions-per-connection"; +const RPC_MAX_BUF_CAP_PER_CONN: &str = "max-buffer-capacity-per-connection"; +const RPC_RATE_LIMIT: &str = "rate-limit"; +const RPC_RATE_LIMIT_TRUST_PROXY_HEADERS: &str = "rate-limit-trust-proxy-headers"; +const RPC_RATE_LIMIT_WHITELISTED_IPS: &str = "rate-limit-whitelisted-ips"; +const RPC_RETRY_RANDOM_PORT: &str = "retry-random-port"; +const RPC_METHODS: &str = "methods"; +const RPC_OPTIONAL: &str = "optional"; +const RPC_DISABLE_BATCH: &str = "disable-batch-requests"; +const RPC_BATCH_LIMIT: &str = "max-batch-request-len"; + +/// Parameters of RPC. +#[derive(Debug, Clone, Args)] +pub struct RpcParams { + /// Listen to all RPC interfaces (default: local). + /// + /// Not all RPC methods are safe to be exposed publicly. + /// + /// Use an RPC proxy server to filter out dangerous methods. More details: + /// . + /// + /// Use `--unsafe-rpc-external` to suppress the warning if you understand the risks. + #[arg(long)] + pub rpc_external: bool, + + /// Listen to all RPC interfaces. + /// + /// Same as `--rpc-external`. + #[arg(long)] + pub unsafe_rpc_external: bool, + + /// RPC methods to expose. + #[arg( + long, + value_name = "METHOD SET", + value_enum, + ignore_case = true, + default_value_t = RpcMethods::Auto, + verbatim_doc_comment + )] + pub rpc_methods: RpcMethods, + + /// RPC rate limiting (calls/minute) for each connection. + /// + /// This is disabled by default. + /// + /// For example `--rpc-rate-limit 10` will maximum allow + /// 10 calls per minute per connection. + #[arg(long)] + pub rpc_rate_limit: Option, + + /// Disable RPC rate limiting for certain ip addresses. + /// + /// Each IP address must be in CIDR notation such as `1.2.3.4/24`. + #[arg(long, num_args = 1..)] + pub rpc_rate_limit_whitelisted_ips: Vec, + + /// Trust proxy headers for disable rate limiting. + /// + /// By default the rpc server will not trust headers such `X-Real-IP`, `X-Forwarded-For` and + /// `Forwarded` and this option will make the rpc server to trust these headers. + /// + /// For instance this may be secure if the rpc server is behind a reverse proxy and that the + /// proxy always sets these headers. + #[arg(long)] + pub rpc_rate_limit_trust_proxy_headers: bool, + + /// Set the maximum RPC request payload size for both HTTP and WS in megabytes. + #[arg(long, default_value_t = RPC_DEFAULT_MAX_REQUEST_SIZE_MB)] + pub rpc_max_request_size: u32, + + /// Set the maximum RPC response payload size for both HTTP and WS in megabytes. + #[arg(long, default_value_t = RPC_DEFAULT_MAX_RESPONSE_SIZE_MB)] + pub rpc_max_response_size: u32, + + /// Set the maximum concurrent subscriptions per connection. + #[arg(long, default_value_t = RPC_DEFAULT_MAX_SUBS_PER_CONN)] + pub rpc_max_subscriptions_per_connection: u32, + + /// Specify JSON-RPC server TCP port. + #[arg(long, value_name = "PORT")] + pub rpc_port: Option, + + /// EXPERIMENTAL: Specify the JSON-RPC server interface and this option which can be enabled + /// several times if you want expose several RPC interfaces with different configurations. + /// + /// The format for this option is: + /// `--experimental-rpc-endpoint" listen-addr=,,..."` where each option is + /// separated by a comma and `listen-addr` is the only required param. + /// + /// The following options are available: + /// • listen-addr: The socket address (ip:port) to listen on. Be careful to not expose the + /// server to the public internet unless you know what you're doing. (required) + /// • disable-batch-requests: Disable batch requests (optional) + /// • max-connections: The maximum number of concurrent connections that the server will + /// accept (optional) + /// • max-request-size: The maximum size of a request body in megabytes (optional) + /// • max-response-size: The maximum size of a response body in megabytes (optional) + /// • max-subscriptions-per-connection: The maximum number of subscriptions per connection + /// (optional) + /// • max-buffer-capacity-per-connection: The maximum buffer capacity per connection + /// (optional) + /// • max-batch-request-len: The maximum number of requests in a batch (optional) + /// • cors: The CORS allowed origins, this can enabled more than once (optional) + /// • methods: Which RPC methods to allow, valid values are "safe", "unsafe" and "auto" + /// (optional) + /// • optional: If the listen address is optional i.e the interface is not required to be + /// available For example this may be useful if some platforms doesn't support ipv6 + /// (optional) + /// • rate-limit: The rate limit in calls per minute for each connection (optional) + /// • rate-limit-trust-proxy-headers: Trust proxy headers for disable rate limiting (optional) + /// • rate-limit-whitelisted-ips: Disable rate limiting for certain ip addresses, this can be + /// enabled more than once (optional) • retry-random-port: If the port is already in use, + /// retry with a random port (optional) + /// + /// Use with care, this flag is unstable and subject to change. + #[arg( + long, + num_args = 1.., + verbatim_doc_comment, + conflicts_with_all = &["rpc_external", "unsafe_rpc_external", "rpc_port", "rpc_cors", "rpc_rate_limit_trust_proxy_headers", "rpc_rate_limit", "rpc_rate_limit_whitelisted_ips", "rpc_message_buffer_capacity_per_connection", "rpc_disable_batch_requests", "rpc_max_subscriptions_per_connection", "rpc_max_request_size", "rpc_max_response_size"] + )] + pub experimental_rpc_endpoint: Vec, + + /// Maximum number of RPC server connections. + #[arg(long, value_name = "COUNT", default_value_t = RPC_DEFAULT_MAX_CONNECTIONS)] + pub rpc_max_connections: u32, + + /// The number of messages the RPC server is allowed to keep in memory. + /// + /// If the buffer becomes full then the server will not process + /// new messages until the connected client start reading the + /// underlying messages. + /// + /// This applies per connection which includes both + /// JSON-RPC methods calls and subscriptions. + #[arg(long, default_value_t = RPC_DEFAULT_MESSAGE_CAPACITY_PER_CONN)] + pub rpc_message_buffer_capacity_per_connection: u32, + + /// Disable RPC batch requests + #[arg(long, alias = "rpc_no_batch_requests", conflicts_with_all = &["rpc_max_batch_request_len"])] + pub rpc_disable_batch_requests: bool, + + /// Limit the max length per RPC batch request + #[arg(long, conflicts_with_all = &["rpc_disable_batch_requests"], value_name = "LEN")] + pub rpc_max_batch_request_len: Option, + + /// Specify browser *origins* allowed to access the HTTP & WS RPC servers. + /// + /// A comma-separated list of origins (protocol://domain or special `null` + /// value). Value of `all` will disable origin validation. Default is to + /// allow localhost and origins. When running in + /// `--dev` mode the default is to allow all origins. + #[arg(long, value_name = "ORIGINS")] + pub rpc_cors: Option, +} + +impl RpcParams { + /// Returns the RPC CORS configuration. + pub fn rpc_cors(&self, is_dev: bool) -> crate::Result>> { + Ok(self + .rpc_cors + .clone() + .unwrap_or_else(|| { + if is_dev { + log::warn!("Running in --dev mode, RPC CORS has been disabled."); + Cors::All + } else { + Cors::List(vec![ + "http://localhost:*".into(), + "http://127.0.0.1:*".into(), + "https://localhost:*".into(), + "https://127.0.0.1:*".into(), + "https://polkadot.js.org".into(), + ]) + } + }) + .into()) + } + + /// Returns the RPC endpoints. + pub fn rpc_addr( + &self, + is_dev: bool, + is_validator: bool, + default_listen_port: u16, + ) -> crate::Result>> { + if !self.experimental_rpc_endpoint.is_empty() { + for endpoint in &self.experimental_rpc_endpoint { + // Technically, `0.0.0.0` isn't a public IP address, but it's a way to listen on + // all interfaces. Thus, we consider it as a public endpoint and warn about it. + if endpoint.rpc_methods == RpcMethods::Unsafe && endpoint.is_global() || + endpoint.listen_addr.ip().is_unspecified() + { + eprintln!( + "It isn't safe to expose RPC publicly without a proxy server that filters \ + available set of RPC methods." + ); + } + } + + return Ok(Some(self.experimental_rpc_endpoint.clone())); + } + + let (ipv4, ipv6) = rpc_interface( + self.rpc_external, + self.unsafe_rpc_external, + self.rpc_methods, + is_validator, + )?; + + let cors = self.rpc_cors(is_dev)?; + let port = self.rpc_port.unwrap_or(default_listen_port); + + Ok(Some(vec![ + RpcEndpoint { + batch_config: self.rpc_batch_config()?, + max_connections: self.rpc_max_connections, + listen_addr: SocketAddr::new(std::net::IpAddr::V4(ipv4), port), + rpc_methods: self.rpc_methods, + rate_limit: self.rpc_rate_limit, + rate_limit_trust_proxy_headers: self.rpc_rate_limit_trust_proxy_headers, + rate_limit_whitelisted_ips: self.rpc_rate_limit_whitelisted_ips.clone(), + max_payload_in_mb: self.rpc_max_request_size, + max_payload_out_mb: self.rpc_max_response_size, + max_subscriptions_per_connection: self.rpc_max_subscriptions_per_connection, + max_buffer_capacity_per_connection: self.rpc_message_buffer_capacity_per_connection, + cors: cors.clone(), + retry_random_port: true, + is_optional: false, + }, + RpcEndpoint { + batch_config: self.rpc_batch_config()?, + max_connections: self.rpc_max_connections, + listen_addr: SocketAddr::new(std::net::IpAddr::V6(ipv6), port), + rpc_methods: self.rpc_methods, + rate_limit: self.rpc_rate_limit, + rate_limit_trust_proxy_headers: self.rpc_rate_limit_trust_proxy_headers, + rate_limit_whitelisted_ips: self.rpc_rate_limit_whitelisted_ips.clone(), + max_payload_in_mb: self.rpc_max_request_size, + max_payload_out_mb: self.rpc_max_response_size, + max_subscriptions_per_connection: self.rpc_max_subscriptions_per_connection, + max_buffer_capacity_per_connection: self.rpc_message_buffer_capacity_per_connection, + cors: cors.clone(), + retry_random_port: true, + is_optional: true, + }, + ])) + } + + /// Returns the configuration for batch RPC requests. + pub fn rpc_batch_config(&self) -> crate::Result { + let cfg = if self.rpc_disable_batch_requests { + RpcBatchRequestConfig::Disabled + } else if let Some(l) = self.rpc_max_batch_request_len { + RpcBatchRequestConfig::Limit(l) + } else { + RpcBatchRequestConfig::Unlimited + }; + + Ok(cfg) + } +} + +fn rpc_interface( + is_external: bool, + is_unsafe_external: bool, + rpc_methods: RpcMethods, + is_validator: bool, +) -> crate::Result<(Ipv4Addr, Ipv6Addr)> { + if is_external && is_validator && rpc_methods != RpcMethods::Unsafe { + return Err(crate::Error::Input( + "--rpc-external option shouldn't be used if the node is running as \ + a validator. Use `--unsafe-rpc-external` or `--rpc-methods=unsafe` if you understand \ + the risks. See the options description for more information." + .to_owned(), + )); + } + + if is_external || is_unsafe_external { + if rpc_methods == RpcMethods::Unsafe { + eprintln!( + "It isn't safe to expose RPC publicly without a proxy server that filters \ + available set of RPC methods." + ); + } + + Ok((Ipv4Addr::UNSPECIFIED, Ipv6Addr::UNSPECIFIED)) + } else { + Ok((Ipv4Addr::LOCALHOST, Ipv6Addr::LOCALHOST)) + } +} + +/// Represent a single RPC endpoint with its configuration. +#[derive(Debug, Clone)] +pub struct RpcEndpoint { + /// Listen address. + pub listen_addr: SocketAddr, + /// Batch request configuration. + pub batch_config: RpcBatchRequestConfig, + /// Maximum number of connections. + pub max_connections: u32, + /// Maximum inbound payload size in MB. + pub max_payload_in_mb: u32, + /// Maximum outbound payload size in MB. + pub max_payload_out_mb: u32, + /// Maximum number of subscriptions per connection. + pub max_subscriptions_per_connection: u32, + /// Maximum buffer capacity per connection. + pub max_buffer_capacity_per_connection: u32, + /// Rate limit per minute. + pub rate_limit: Option, + /// Whether to trust proxy headers for rate limiting. + pub rate_limit_trust_proxy_headers: bool, + /// Whitelisted IPs for rate limiting. + pub rate_limit_whitelisted_ips: Vec, + /// CORS. + pub cors: Option>, + /// RPC methods to expose. + pub rpc_methods: RpcMethods, + /// Whether it's an optional listening address i.e, it's ignored if it fails to bind. + /// For example substrate tries to bind both ipv4 and ipv6 addresses but some platforms + /// may not support ipv6. + pub is_optional: bool, + /// Whether to retry with a random port if the provided port is already in use. + pub retry_random_port: bool, +} + +impl std::str::FromStr for RpcEndpoint { + type Err = String; + + fn from_str(s: &str) -> Result { + let mut listen_addr = None; + let mut max_connections = None; + let mut max_payload_in_mb = None; + let mut max_payload_out_mb = None; + let mut max_subscriptions_per_connection = None; + let mut max_buffer_capacity_per_connection = None; + let mut cors: Option> = None; + let mut rpc_methods = None; + let mut is_optional = None; + let mut disable_batch_requests = None; + let mut max_batch_request_len = None; + let mut rate_limit = None; + let mut rate_limit_trust_proxy_headers = None; + let mut rate_limit_whitelisted_ips = Vec::new(); + let mut retry_random_port = None; + + for input in s.split(',') { + let (key, val) = input.trim().split_once('=').ok_or_else(|| invalid_input(input))?; + let key = key.trim(); + let val = val.trim(); + + match key { + RPC_LISTEN_ADDR => { + if listen_addr.is_some() { + return Err(only_once_err(RPC_LISTEN_ADDR)); + } + let val: SocketAddr = + val.parse().map_err(|_| invalid_value(RPC_LISTEN_ADDR, &val))?; + listen_addr = Some(val); + }, + RPC_CORS => { + if val.is_empty() { + return Err(invalid_value(RPC_CORS, &val)); + } + + if let Some(cors) = cors.as_mut() { + cors.push(val.to_string()); + } else { + cors = Some(vec![val.to_string()]); + } + }, + RPC_MAX_CONNS => { + if max_connections.is_some() { + return Err(only_once_err(RPC_MAX_CONNS)); + } + + let val = val.parse().map_err(|_| invalid_value(RPC_MAX_CONNS, &val))?; + max_connections = Some(val); + }, + RPC_MAX_REQUEST_SIZE => { + if max_payload_in_mb.is_some() { + return Err(only_once_err(RPC_MAX_REQUEST_SIZE)); + } + + let val = + val.parse().map_err(|_| invalid_value(RPC_MAX_RESPONSE_SIZE, &val))?; + max_payload_in_mb = Some(val); + }, + RPC_MAX_RESPONSE_SIZE => { + if max_payload_out_mb.is_some() { + return Err(only_once_err(RPC_MAX_RESPONSE_SIZE)); + } + + let val = + val.parse().map_err(|_| invalid_value(RPC_MAX_RESPONSE_SIZE, &val))?; + max_payload_out_mb = Some(val); + }, + RPC_MAX_SUBS_PER_CONN => { + if max_subscriptions_per_connection.is_some() { + return Err(only_once_err(RPC_MAX_SUBS_PER_CONN)); + } + + let val = + val.parse().map_err(|_| invalid_value(RPC_MAX_SUBS_PER_CONN, &val))?; + max_subscriptions_per_connection = Some(val); + }, + RPC_MAX_BUF_CAP_PER_CONN => { + if max_buffer_capacity_per_connection.is_some() { + return Err(only_once_err(RPC_MAX_BUF_CAP_PER_CONN)); + } + + let val = + val.parse().map_err(|_| invalid_value(RPC_MAX_BUF_CAP_PER_CONN, &val))?; + max_buffer_capacity_per_connection = Some(val); + }, + RPC_RATE_LIMIT => { + if rate_limit.is_some() { + return Err(only_once_err("rate-limit")); + } + + let val = val.parse().map_err(|_| invalid_value(RPC_RATE_LIMIT, &val))?; + rate_limit = Some(val); + }, + RPC_RATE_LIMIT_TRUST_PROXY_HEADERS => { + if rate_limit_trust_proxy_headers.is_some() { + return Err(only_once_err(RPC_RATE_LIMIT_TRUST_PROXY_HEADERS)); + } + + let val = val + .parse() + .map_err(|_| invalid_value(RPC_RATE_LIMIT_TRUST_PROXY_HEADERS, &val))?; + rate_limit_trust_proxy_headers = Some(val); + }, + RPC_RATE_LIMIT_WHITELISTED_IPS => { + let ip: IpNetwork = val + .parse() + .map_err(|_| invalid_value(RPC_RATE_LIMIT_WHITELISTED_IPS, &val))?; + rate_limit_whitelisted_ips.push(ip); + }, + RPC_RETRY_RANDOM_PORT => { + if retry_random_port.is_some() { + return Err(only_once_err(RPC_RETRY_RANDOM_PORT)); + } + let val = + val.parse().map_err(|_| invalid_value(RPC_RETRY_RANDOM_PORT, &val))?; + retry_random_port = Some(val); + }, + RPC_METHODS => { + if rpc_methods.is_some() { + return Err(only_once_err("methods")); + } + let val = val.parse().map_err(|_| invalid_value(RPC_METHODS, &val))?; + rpc_methods = Some(val); + }, + RPC_OPTIONAL => { + if is_optional.is_some() { + return Err(only_once_err(RPC_OPTIONAL)); + } + + let val = val.parse().map_err(|_| invalid_value(RPC_OPTIONAL, &val))?; + is_optional = Some(val); + }, + RPC_DISABLE_BATCH => { + if disable_batch_requests.is_some() { + return Err(only_once_err(RPC_DISABLE_BATCH)); + } + + let val = val.parse().map_err(|_| invalid_value(RPC_DISABLE_BATCH, &val))?; + disable_batch_requests = Some(val); + }, + RPC_BATCH_LIMIT => { + if max_batch_request_len.is_some() { + return Err(only_once_err(RPC_BATCH_LIMIT)); + } + + let val = val.parse().map_err(|_| invalid_value(RPC_BATCH_LIMIT, &val))?; + max_batch_request_len = Some(val); + }, + _ => return Err(invalid_key(key)), + } + } + + let listen_addr = listen_addr.ok_or("`listen-addr` must be specified exactly once")?; + + let batch_config = match (disable_batch_requests, max_batch_request_len) { + (Some(true), Some(_)) => { + return Err(format!("`{RPC_BATCH_LIMIT}` and `{RPC_DISABLE_BATCH}` are mutually exclusive and can't be used together")); + }, + (Some(false), None) => RpcBatchRequestConfig::Disabled, + (None, Some(len)) => RpcBatchRequestConfig::Limit(len), + _ => RpcBatchRequestConfig::Unlimited, + }; + + Ok(Self { + listen_addr, + batch_config, + max_connections: max_connections.unwrap_or(RPC_DEFAULT_MAX_CONNECTIONS), + max_payload_in_mb: max_payload_in_mb.unwrap_or(RPC_DEFAULT_MAX_REQUEST_SIZE_MB), + max_payload_out_mb: max_payload_out_mb.unwrap_or(RPC_DEFAULT_MAX_RESPONSE_SIZE_MB), + cors, + max_buffer_capacity_per_connection: max_buffer_capacity_per_connection + .unwrap_or(RPC_DEFAULT_MESSAGE_CAPACITY_PER_CONN), + max_subscriptions_per_connection: max_subscriptions_per_connection + .unwrap_or(RPC_DEFAULT_MAX_SUBS_PER_CONN), + rpc_methods: rpc_methods.unwrap_or(RpcMethods::Auto), + rate_limit, + rate_limit_trust_proxy_headers: rate_limit_trust_proxy_headers.unwrap_or(false), + rate_limit_whitelisted_ips, + is_optional: is_optional.unwrap_or(false), + retry_random_port: retry_random_port.unwrap_or(false), + }) + } +} + +impl Into for RpcEndpoint { + fn into(self) -> sc_service::config::RpcEndpoint { + sc_service::config::RpcEndpoint { + batch_config: self.batch_config, + listen_addr: self.listen_addr, + max_buffer_capacity_per_connection: self.max_buffer_capacity_per_connection, + max_connections: self.max_connections, + max_payload_in_mb: self.max_payload_in_mb, + max_payload_out_mb: self.max_payload_out_mb, + max_subscriptions_per_connection: self.max_subscriptions_per_connection, + rpc_methods: self.rpc_methods.into(), + rate_limit: self.rate_limit, + rate_limit_trust_proxy_headers: self.rate_limit_trust_proxy_headers, + rate_limit_whitelisted_ips: self.rate_limit_whitelisted_ips, + cors: self.cors, + retry_random_port: self.retry_random_port, + is_optional: self.is_optional, + } + } +} + +impl RpcEndpoint { + /// Returns whether the endpoint is globally exposed. + pub fn is_global(&self) -> bool { + let ip = IpNetwork::from(self.listen_addr.ip()); + ip.is_global() + } +} + +fn only_once_err(reason: &str) -> String { + format!("`{reason}` is only allowed be specified once") +} + +fn invalid_input(input: &str) -> String { + format!("`{input}`, expects: `key=value`") +} + +fn invalid_value(key: &str, value: &str) -> String { + format!("value=`{value}` key=`{key}`") +} + +fn invalid_key(key: &str) -> String { + format!("unknown key=`{key}`, see `--help` for available options") +} + +#[cfg(test)] +mod tests { + use super::*; + use std::{num::NonZeroU32, str::FromStr}; + + #[test] + fn parse_rpc_endpoint_works() { + assert!(RpcEndpoint::from_str("listen-addr=127.0.0.1:9944").is_ok()); + assert!(RpcEndpoint::from_str("listen-addr=[::1]:9944").is_ok()); + assert!(RpcEndpoint::from_str("listen-addr=127.0.0.1:9944,methods=auto").is_ok()); + assert!(RpcEndpoint::from_str("listen-addr=[::1]:9944,methods=auto").is_ok()); + assert!(RpcEndpoint::from_str( + "listen-addr=127.0.0.1:9944,methods=auto,cors=*,optional=true" + ) + .is_ok()); + + assert!(RpcEndpoint::from_str("listen-addrs=127.0.0.1:9944,foo=*").is_err()); + assert!(RpcEndpoint::from_str("listen-addrs=127.0.0.1:9944,cors=").is_err()); + } + + #[test] + fn parse_rpc_endpoint_all() { + let endpoint = RpcEndpoint::from_str( + "listen-addr=127.0.0.1:9944,methods=unsafe,cors=*,optional=true,retry-random-port=true,rate-limit=99,\ + max-batch-request-len=100,rate-limit-trust-proxy-headers=true,max-connections=33,max-request-size=4,\ + max-response-size=3,max-subscriptions-per-connection=7,max-buffer-capacity-per-connection=8,\ + rate-limit-whitelisted-ips=192.168.1.0/24,rate-limit-whitelisted-ips=ff01::0/32" + ).unwrap(); + assert_eq!(endpoint.listen_addr, ([127, 0, 0, 1], 9944).into()); + assert_eq!(endpoint.rpc_methods, RpcMethods::Unsafe); + assert_eq!(endpoint.cors, Some(vec!["*".to_string()])); + assert_eq!(endpoint.is_optional, true); + assert_eq!(endpoint.retry_random_port, true); + assert_eq!(endpoint.rate_limit, Some(NonZeroU32::new(99).unwrap())); + assert!(matches!(endpoint.batch_config, RpcBatchRequestConfig::Limit(l) if l == 100)); + assert_eq!(endpoint.rate_limit_trust_proxy_headers, true); + assert_eq!( + endpoint.rate_limit_whitelisted_ips, + vec![ + IpNetwork::V4("192.168.1.0/24".parse().unwrap()), + IpNetwork::V6("ff01::0/32".parse().unwrap()) + ] + ); + assert_eq!(endpoint.max_connections, 33); + assert_eq!(endpoint.max_payload_in_mb, 4); + assert_eq!(endpoint.max_payload_out_mb, 3); + assert_eq!(endpoint.max_subscriptions_per_connection, 7); + assert_eq!(endpoint.max_buffer_capacity_per_connection, 8); + } + + #[test] + fn parse_rpc_endpoint_multiple_cors() { + let addr = RpcEndpoint::from_str( + "listen-addr=127.0.0.1:9944,methods=auto,cors=https://polkadot.js.org,cors=*,cors=localhost:*", + ) + .unwrap(); + + assert_eq!( + addr.cors, + Some(vec![ + "https://polkadot.js.org".to_string(), + "*".to_string(), + "localhost:*".to_string() + ]) + ); + } + + #[test] + fn parse_rpc_endpoint_whitespaces() { + let addr = RpcEndpoint::from_str( + " listen-addr = 127.0.0.1:9944, methods = auto, optional = true ", + ) + .unwrap(); + assert_eq!(addr.rpc_methods, RpcMethods::Auto); + assert_eq!(addr.is_optional, true); + } + + #[test] + fn parse_rpc_endpoint_batch_options_mutually_exclusive() { + assert!(RpcEndpoint::from_str( + "listen-addr = 127.0.0.1:9944,disable-batch-requests=true,max-batch-request-len=100", + ) + .is_err()); + } +} diff --git a/substrate/client/cli/src/params/transaction_pool_params.rs b/substrate/client/cli/src/params/transaction_pool_params.rs index 48b2e5b1572b..9cf738f58b6b 100644 --- a/substrate/client/cli/src/params/transaction_pool_params.rs +++ b/substrate/client/cli/src/params/transaction_pool_params.rs @@ -16,8 +16,28 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use clap::Args; -use sc_service::config::TransactionPoolOptions; +use clap::{Args, ValueEnum}; +use sc_transaction_pool::TransactionPoolOptions; + +/// Type of transaction pool to be used +#[derive(Debug, Clone, Copy, ValueEnum)] +#[value(rename_all = "kebab-case")] +pub enum TransactionPoolType { + /// Uses a legacy, single-state transaction pool. + SingleState, + /// Uses a fork-aware transaction pool. + ForkAware, +} + +impl Into for TransactionPoolType { + fn into(self) -> sc_transaction_pool::TransactionPoolType { + match self { + TransactionPoolType::SingleState => + sc_transaction_pool::TransactionPoolType::SingleState, + TransactionPoolType::ForkAware => sc_transaction_pool::TransactionPoolType::ForkAware, + } + } +} /// Parameters used to create the pool configuration. #[derive(Debug, Clone, Args)] @@ -35,30 +55,21 @@ pub struct TransactionPoolParams { /// If it is considered invalid. Defaults to 1800s. #[arg(long, value_name = "SECONDS")] pub tx_ban_seconds: Option, + + /// The type of transaction pool to be instantiated. + #[arg(long, value_enum, default_value_t = TransactionPoolType::SingleState)] + pub pool_type: TransactionPoolType, } impl TransactionPoolParams { /// Fill the given `PoolConfiguration` by looking at the cli parameters. pub fn transaction_pool(&self, is_dev: bool) -> TransactionPoolOptions { - let mut opts = TransactionPoolOptions::default(); - - // ready queue - opts.ready.count = self.pool_limit; - opts.ready.total_bytes = self.pool_kbytes * 1024; - - // future queue - let factor = 10; - opts.future.count = self.pool_limit / factor; - opts.future.total_bytes = self.pool_kbytes * 1024 / factor; - - opts.ban_time = if let Some(ban_seconds) = self.tx_ban_seconds { - std::time::Duration::from_secs(ban_seconds) - } else if is_dev { - std::time::Duration::from_secs(0) - } else { - std::time::Duration::from_secs(30 * 60) - }; - - opts + TransactionPoolOptions::new_with_params( + self.pool_limit, + self.pool_kbytes * 1024, + self.tx_ban_seconds, + self.pool_type.into(), + is_dev, + ) } } diff --git a/substrate/client/cli/src/runner.rs b/substrate/client/cli/src/runner.rs index 6d986e38d2fb..9c5834d8d80a 100644 --- a/substrate/client/cli/src/runner.rs +++ b/substrate/client/cli/src/runner.rs @@ -193,7 +193,10 @@ pub fn print_node_infos(config: &Configuration) { mod tests { use super::*; use sc_network::config::NetworkConfiguration; - use sc_service::{Arc, ChainType, GenericChainSpec, NoExtension}; + use sc_service::{ + config::{ExecutorConfiguration, RpcConfiguration}, + Arc, ChainType, GenericChainSpec, NoExtension, + }; use std::{ path::PathBuf, sync::atomic::{AtomicU64, Ordering}, @@ -262,37 +265,35 @@ mod tests { .with_genesis_config_patch(Default::default()) .build(), ), - wasm_method: Default::default(), + executor: ExecutorConfiguration::default(), wasm_runtime_overrides: None, - rpc_addr: None, - rpc_max_connections: Default::default(), - rpc_cors: None, - rpc_methods: Default::default(), - rpc_max_request_size: Default::default(), - rpc_max_response_size: Default::default(), - rpc_id_provider: Default::default(), - rpc_max_subs_per_conn: Default::default(), - rpc_message_buffer_capacity: Default::default(), - rpc_port: 9944, - rpc_batch_config: sc_service::config::RpcBatchRequestConfig::Unlimited, - rpc_rate_limit: None, - rpc_rate_limit_whitelisted_ips: Default::default(), - rpc_rate_limit_trust_proxy_headers: Default::default(), + rpc: RpcConfiguration { + addr: None, + max_connections: Default::default(), + cors: None, + methods: Default::default(), + max_request_size: Default::default(), + max_response_size: Default::default(), + id_provider: Default::default(), + max_subs_per_conn: Default::default(), + message_buffer_capacity: Default::default(), + port: 9944, + batch_config: sc_service::config::RpcBatchRequestConfig::Unlimited, + rate_limit: None, + rate_limit_whitelisted_ips: Default::default(), + rate_limit_trust_proxy_headers: Default::default(), + }, prometheus_config: None, telemetry_endpoints: None, - default_heap_pages: None, offchain_worker: Default::default(), force_authoring: false, disable_grandpa: false, dev_key_seed: None, tracing_targets: None, tracing_receiver: Default::default(), - max_runtime_instances: 8, announce_block: true, base_path: sc_service::BasePath::new(root.clone()), data_path: root, - informant_output_format: Default::default(), - runtime_cache_size: 2, }, runtime, Signals::dummy(), diff --git a/substrate/client/consensus/aura/Cargo.toml b/substrate/client/consensus/aura/Cargo.toml index 3a3d7ae18d71..98e8ad676be3 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 bba60bc45ea5..af55e72a9b7e 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 1ef049c3dbcc..ce5b1baec0b5 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/babe/rpc/src/lib.rs b/substrate/client/consensus/babe/rpc/src/lib.rs index a3e811baecff..338d71a43256 100644 --- a/substrate/client/consensus/babe/rpc/src/lib.rs +++ b/substrate/client/consensus/babe/rpc/src/lib.rs @@ -25,12 +25,13 @@ use jsonrpsee::{ core::async_trait, proc_macros::rpc, types::{ErrorObject, ErrorObjectOwned}, + Extensions, }; use serde::{Deserialize, Serialize}; use sc_consensus_babe::{authorship, BabeWorkerHandle}; use sc_consensus_epochs::Epoch as EpochT; -use sc_rpc_api::{DenyUnsafe, UnsafeRpcError}; +use sc_rpc_api::{check_if_safe, UnsafeRpcError}; use sp_api::ProvideRuntimeApi; use sp_application_crypto::AppCrypto; use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata}; @@ -47,7 +48,7 @@ const BABE_ERROR: i32 = 9000; pub trait BabeApi { /// Returns data about which slots (primary or secondary) can be claimed in the current epoch /// with the keys in the keystore. - #[method(name = "babe_epochAuthorship")] + #[method(name = "babe_epochAuthorship", with_extensions)] async fn epoch_authorship(&self) -> Result, Error>; } @@ -61,8 +62,6 @@ pub struct Babe { keystore: KeystorePtr, /// The SelectChain strategy select_chain: SC, - /// Whether to deny unsafe calls - deny_unsafe: DenyUnsafe, } impl Babe { @@ -72,9 +71,8 @@ impl Babe { babe_worker_handle: BabeWorkerHandle, keystore: KeystorePtr, select_chain: SC, - deny_unsafe: DenyUnsafe, ) -> Self { - Self { client, babe_worker_handle, keystore, select_chain, deny_unsafe } + Self { client, babe_worker_handle, keystore, select_chain } } } @@ -89,8 +87,11 @@ where C::Api: BabeRuntimeApi, SC: SelectChain + Clone + 'static, { - async fn epoch_authorship(&self) -> Result, Error> { - self.deny_unsafe.check_if_safe()?; + async fn epoch_authorship( + &self, + ext: &Extensions, + ) -> Result, Error> { + check_if_safe(ext)?; let best_header = self.select_chain.best_chain().map_err(Error::SelectChain).await?; @@ -193,6 +194,7 @@ impl From for ErrorObjectOwned { mod tests { use super::*; use sc_consensus_babe::ImportQueueParams; + use sc_rpc_api::DenyUnsafe; use sc_transaction_pool_api::{OffchainTransactionPoolFactory, RejectAllTxPool}; use sp_consensus_babe::inherents::InherentDataProvider; use sp_core::{crypto::key_types::BABE, testing::TaskExecutor}; @@ -211,9 +213,8 @@ mod tests { keystore.into() } - fn test_babe_rpc_module( - deny_unsafe: DenyUnsafe, - ) -> Babe> { + fn test_babe_rpc_module() -> Babe> + { let builder = TestClientBuilder::new(); let (client, longest_chain) = builder.build_with_longest_chain(); let client = Arc::new(client); @@ -248,29 +249,31 @@ mod tests { }) .unwrap(); - Babe::new(client.clone(), babe_worker_handle, keystore, longest_chain, deny_unsafe) + Babe::new(client.clone(), babe_worker_handle, keystore, longest_chain) } #[tokio::test] async fn epoch_authorship_works() { - let babe_rpc = test_babe_rpc_module(DenyUnsafe::No); - let api = babe_rpc.into_rpc(); + let babe_rpc = test_babe_rpc_module(); + let mut api = babe_rpc.into_rpc(); + api.extensions_mut().insert(DenyUnsafe::No); - let request = r#"{"jsonrpc":"2.0","method":"babe_epochAuthorship","params": [],"id":1}"#; + let request = r#"{"jsonrpc":"2.0","id":1,"method":"babe_epochAuthorship","params":[]}"#; let (response, _) = api.raw_json_request(request, 1).await.unwrap(); - let expected = r#"{"jsonrpc":"2.0","result":{"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY":{"primary":[0],"secondary":[],"secondary_vrf":[1,2,4]}},"id":1}"#; + let expected = r#"{"jsonrpc":"2.0","id":1,"result":{"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY":{"primary":[0],"secondary":[],"secondary_vrf":[1,2,4]}}}"#; assert_eq!(response, expected); } #[tokio::test] async fn epoch_authorship_is_unsafe() { - let babe_rpc = test_babe_rpc_module(DenyUnsafe::Yes); - let api = babe_rpc.into_rpc(); + let babe_rpc = test_babe_rpc_module(); + let mut api = babe_rpc.into_rpc(); + api.extensions_mut().insert(DenyUnsafe::Yes); let request = r#"{"jsonrpc":"2.0","method":"babe_epochAuthorship","params":[],"id":1}"#; let (response, _) = api.raw_json_request(request, 1).await.unwrap(); - let expected = r#"{"jsonrpc":"2.0","error":{"code":-32601,"message":"RPC call is unsafe to be called externally"},"id":1}"#; + let expected = r#"{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"RPC call is unsafe to be called externally"}}"#; assert_eq!(response, expected); } diff --git a/substrate/client/consensus/babe/src/authorship.rs b/substrate/client/consensus/babe/src/authorship.rs index 57ee706a04f6..aa54da2a4434 100644 --- a/substrate/client/consensus/babe/src/authorship.rs +++ b/substrate/client/consensus/babe/src/authorship.rs @@ -108,7 +108,8 @@ pub(super) fn secondary_slot_author( return None } - let rand = U256::from((randomness, slot).using_encoded(sp_crypto_hashing::blake2_256)); + let rand = + U256::from_big_endian(&(randomness, slot).using_encoded(sp_crypto_hashing::blake2_256)); let authorities_len = U256::from(authorities.len()); let idx = rand % authorities_len; @@ -271,7 +272,9 @@ fn claim_primary_slot( #[cfg(test)] mod tests { use super::*; - use sp_consensus_babe::{AllowedSlots, AuthorityId, BabeEpochConfiguration, Epoch}; + use sp_consensus_babe::{ + AllowedSlots, AuthorityId, BabeEpochConfiguration, Epoch, RANDOMNESS_LENGTH, + }; use sp_core::{crypto::Pair as _, sr25519::Pair}; use sp_keystore::testing::MemoryKeystore; @@ -305,4 +308,18 @@ mod tests { epoch.authorities.push((valid_public_key.into(), 10)); assert_eq!(claim_slot(10.into(), &epoch, &keystore).unwrap().1, valid_public_key.into()); } + + #[test] + fn secondary_slot_author_selection_works() { + let authorities = (0..1000) + .map(|i| (AuthorityId::from(Pair::generate().0.public()), i)) + .collect::>(); + + let randomness = [3; RANDOMNESS_LENGTH]; + + assert_eq!( + *secondary_slot_author(100.into(), &authorities, randomness).unwrap(), + authorities[167].0 + ); + } } diff --git a/substrate/client/consensus/babe/src/lib.rs b/substrate/client/consensus/babe/src/lib.rs index 0c1eb8875864..4cf66302ec85 100644 --- a/substrate/client/consensus/babe/src/lib.rs +++ b/substrate/client/consensus/babe/src/lib.rs @@ -1146,7 +1146,9 @@ where let info = self.client.info(); let number = *block.header.number(); - if info.block_gap.map_or(false, |(s, e)| s <= number && number <= e) || block.with_state() { + if info.block_gap.map_or(false, |gap| gap.start <= number && number <= gap.end) || + block.with_state() + { // Verification for imported blocks is skipped in two cases: // 1. When importing blocks below the last finalized block during network initial // synchronization. @@ -1342,7 +1344,7 @@ where // This function makes multiple transactions to the DB. If one of them fails we may // end up in an inconsistent state and have to resync. async fn import_state( - &mut self, + &self, mut block: BlockImportParams, ) -> Result { let hash = block.post_hash(); @@ -1405,7 +1407,7 @@ where type Error = ConsensusError; async fn import_block( - &mut self, + &self, mut block: BlockImportParams, ) -> Result { let hash = block.post_hash(); @@ -1420,7 +1422,7 @@ where // Skip babe logic if block already in chain or importing blocks during initial sync, // otherwise the check for epoch changes will error because trying to re-import an // epoch change or because of missing epoch data in the tree, respectively. - if info.block_gap.map_or(false, |(s, e)| s <= number && number <= e) || + if info.block_gap.map_or(false, |gap| gap.start <= number && number <= gap.end) || block_status == BlockStatus::InChain { // When re-importing existing block strip away intermediates. diff --git a/substrate/client/consensus/babe/src/tests.rs b/substrate/client/consensus/babe/src/tests.rs index 6f805188b9a4..5c2e0eae959c 100644 --- a/substrate/client/consensus/babe/src/tests.rs +++ b/substrate/client/consensus/babe/src/tests.rs @@ -150,7 +150,7 @@ where type Error = BI::Error; async fn import_block( - &mut self, + &self, block: BlockImportParams, ) -> Result { Ok(self.0.import_block(block).await.expect("importing block failed")) diff --git a/substrate/client/consensus/beefy/Cargo.toml b/substrate/client/consensus/beefy/Cargo.toml index b2031e0d1e07..900a44b95e04 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/README.md b/substrate/client/consensus/beefy/README.md index a7956cfcd42e..cb9a9267f77e 100644 --- a/substrate/client/consensus/beefy/README.md +++ b/substrate/client/consensus/beefy/README.md @@ -159,7 +159,7 @@ ambiguity despite using block number instead of a hash. A collection of **votes* a Commitment and a collection of signatures is going to be called **Signed Commitment**. A valid (see later for the rules) Signed Commitment is also called a **BEEFY Justification** or **BEEFY Finality Proof**. For more details on the actual data structures please see -[BEEFY primitives definitions](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/primitives/beefy/src). +[BEEFY primitives definitions](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/primitives/consensus/beefy/src). A **round** is an attempt by BEEFY validators to produce a BEEFY Justification. **Round number** is simply defined as a block number the validators are voting for, or to be more precise, the diff --git a/substrate/client/consensus/beefy/rpc/Cargo.toml b/substrate/client/consensus/beefy/rpc/Cargo.toml index 7869f5a336b1..e1956dacf396 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 66102eeb35c8..ab58f6866275 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 { @@ -195,7 +201,7 @@ mod tests { async fn uninitialized_rpc_handler() { let (rpc, _) = setup_io_handler(); let request = r#"{"jsonrpc":"2.0","method":"beefy_getFinalizedHead","params":[],"id":1}"#; - let expected_response = r#"{"jsonrpc":"2.0","error":{"code":1,"message":"BEEFY RPC endpoint not ready"},"id":1}"#; + let expected_response = r#"{"jsonrpc":"2.0","id":1,"error":{"code":1,"message":"BEEFY RPC endpoint not ready"}}"#; let (response, _) = rpc.raw_json_request(&request, 1).await.unwrap(); assert_eq!(expected_response, response); @@ -214,13 +220,13 @@ mod tests { let request = r#"{"jsonrpc":"2.0","method":"beefy_getFinalizedHead","params":[],"id":1}"#; let expected = "{\ \"jsonrpc\":\"2.0\",\ - \"result\":\"0x2f0039e93a27221fcf657fb877a1d4f60307106113e885096cb44a461cd0afbf\",\ - \"id\":1\ + \"id\":1,\ + \"result\":\"0x2f0039e93a27221fcf657fb877a1d4f60307106113e885096cb44a461cd0afbf\"\ }"; - let not_ready = "{\ + let not_ready: &str = "{\ \"jsonrpc\":\"2.0\",\ - \"error\":{\"code\":1,\"message\":\"BEEFY RPC endpoint not ready\"},\ - \"id\":1\ + \"id\":1,\ + \"error\":{\"code\":1,\"message\":\"BEEFY RPC endpoint not ready\"}\ }"; let deadline = std::time::Instant::now() + std::time::Duration::from_secs(2); @@ -256,7 +262,7 @@ mod tests { ) .await .unwrap(); - let expected = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; + let expected = r#"{"jsonrpc":"2.0","id":1,"result":false}"#; assert_eq!(response, expected); } diff --git a/substrate/client/consensus/beefy/src/communication/peers.rs b/substrate/client/consensus/beefy/src/communication/peers.rs index 2d801aceaa8a..929cc0c650b3 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 e127e5a89590..5408d95acf2d 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 @@ -38,7 +38,7 @@ use crate::{ request_response::{Error, JustificationRequest, BEEFY_SYNC_LOG_TARGET}, }, justification::{decode_and_verify_finality_proof, BeefyVersionedFinalityProof}, - metric_inc, + metric_inc, metric_set, metrics::{register_metrics, OnDemandOutgoingRequestsMetrics}, KnownPeers, }; @@ -242,6 +242,8 @@ impl OnDemandJustificationsEngine { @@ -249,9 +251,16 @@ impl OnDemandJustificationsEngine OnDemandJustificationsEngine { - pub id: &'a AuthorityId, +/// Helper struct containing the key ownership proof for a validator. +pub struct ProvedValidator { pub key_owner_proof: OpaqueKeyOwnershipProof, } @@ -66,7 +65,7 @@ where at: BlockId, offender_ids: impl Iterator, validator_set_id: ValidatorSetId, - ) -> Result>, Error> { + ) -> Result, Error> { let hash = match at { BlockId::Hash(hash) => hash, BlockId::Number(number) => self @@ -91,7 +90,7 @@ where offender_id.clone(), ) { Ok(Some(key_owner_proof)) => { - proved_offenders.push(ProvedValidator { id: offender_id, key_owner_proof }); + proved_offenders.push(ProvedValidator { key_owner_proof }); }, Ok(None) => { debug!( diff --git a/substrate/client/consensus/beefy/src/import.rs b/substrate/client/consensus/beefy/src/import.rs index 848026852933..17a4a5866636 100644 --- a/substrate/client/consensus/beefy/src/import.rs +++ b/substrate/client/consensus/beefy/src/import.rs @@ -132,7 +132,7 @@ where type Error = ConsensusError; async fn import_block( - &mut self, + &self, mut block: BlockImportParams, ) -> Result { let hash = block.post_hash(); diff --git a/substrate/client/consensus/beefy/src/keystore.rs b/substrate/client/consensus/beefy/src/keystore.rs index 8daf3440c7d2..888a11db89cb 100644 --- a/substrate/client/consensus/beefy/src/keystore.rs +++ b/substrate/client/consensus/beefy/src/keystore.rs @@ -20,7 +20,7 @@ use log::warn; use sp_application_crypto::{key_types::BEEFY as BEEFY_KEY_TYPE, AppCrypto, RuntimeAppPublic}; #[cfg(feature = "bls-experimental")] -use sp_core::ecdsa_bls377; +use sp_core::ecdsa_bls381; use sp_core::{ecdsa, keccak_256}; use sp_keystore::KeystorePtr; @@ -100,13 +100,13 @@ impl BeefyKeystore { }, #[cfg(feature = "bls-experimental")] - ecdsa_bls377::CRYPTO_ID => { - let public: ecdsa_bls377::Public = - ecdsa_bls377::Public::try_from(public.as_slice()).unwrap(); + ecdsa_bls381::CRYPTO_ID => { + let public: ecdsa_bls381::Public = + ecdsa_bls381::Public::try_from(public.as_slice()).unwrap(); let sig = store - .ecdsa_bls377_sign_with_keccak256(BEEFY_KEY_TYPE, &public, &message) + .ecdsa_bls381_sign_with_keccak256(BEEFY_KEY_TYPE, &public, &message) .map_err(|e| error::Error::Keystore(e.to_string()))? - .ok_or_else(|| error::Error::Signature("bls377_sign() failed".to_string()))?; + .ok_or_else(|| error::Error::Signature("bls381_sign() failed".to_string()))?; let sig_ref: &[u8] = sig.as_ref(); sig_ref.to_vec() }, @@ -146,8 +146,8 @@ impl BeefyKeystore { }), #[cfg(feature = "bls-experimental")] - ecdsa_bls377::CRYPTO_ID => store - .ecdsa_bls377_public_keys(BEEFY_KEY_TYPE) + ecdsa_bls381::CRYPTO_ID => store + .ecdsa_bls381_public_keys(BEEFY_KEY_TYPE) .drain(..) .map(|pk| AuthorityId::try_from(pk.as_ref())) .collect::, _>>() @@ -254,9 +254,9 @@ pub mod tests { AuthorityId::decode(&mut pk.as_ref()).unwrap() }, #[cfg(feature = "bls-experimental")] - ecdsa_bls377::CRYPTO_ID => { + ecdsa_bls381::CRYPTO_ID => { let pk = store - .ecdsa_bls377_generate_new(key_type, optional_seed.as_deref()) + .ecdsa_bls381_generate_new(key_type, optional_seed.as_deref()) .ok() .unwrap(); AuthorityId::decode(&mut pk.as_ref()).unwrap() @@ -452,7 +452,7 @@ pub mod tests { #[cfg(feature = "bls-experimental")] #[test] fn sign_error_for_ecdsa_n_bls() { - sign_error::("bls377_sign() failed"); + sign_error::("bls381_sign() failed"); } #[test] diff --git a/substrate/client/consensus/beefy/src/lib.rs b/substrate/client/consensus/beefy/src/lib.rs index a47bfe1dbe24..30cdd494905f 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/metrics.rs b/substrate/client/consensus/beefy/src/metrics.rs index 30180fe43ec4..15f2f9f90334 100644 --- a/substrate/client/consensus/beefy/src/metrics.rs +++ b/substrate/client/consensus/beefy/src/metrics.rs @@ -236,6 +236,8 @@ pub struct OnDemandOutgoingRequestsMetrics { pub beefy_on_demand_justification_invalid_proof: Counter, /// Number of on-demand justification good proof pub beefy_on_demand_justification_good_proof: Counter, + /// Number of live beefy peers available for requests. + pub beefy_on_demand_live_peers: Gauge, } impl PrometheusRegister for OnDemandOutgoingRequestsMetrics { @@ -277,6 +279,13 @@ impl PrometheusRegister for OnDemandOutgoingRequestsMetrics { )?, registry, )?, + beefy_on_demand_live_peers: register( + Gauge::new( + "substrate_beefy_on_demand_live_peers", + "Number of live beefy peers available for requests.", + )?, + registry, + )?, }) } } diff --git a/substrate/client/consensus/beefy/src/tests.rs b/substrate/client/consensus/beefy/src/tests.rs index d8f5b39dbbaa..afa6191d8bfe 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, @@ -777,7 +790,7 @@ async fn beefy_importing_justifications() { let client = net.peer(0).client().clone(); let full_client = client.as_client(); - let (mut block_import, _, peer_data) = net.make_block_import(client.clone()); + let (block_import, _, peer_data) = net.make_block_import(client.clone()); let PeerData { beefy_voter_links, .. } = peer_data; let justif_stream = beefy_voter_links.lock().take().unwrap().from_block_import_justif_stream; let mut justif_recv = justif_stream.subscribe(100_000); @@ -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 4a9f7a2d0e3b..3c7f3b1b6efa 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 a6f59e600f26..77cd50ad784b 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/block_import.rs b/substrate/client/consensus/common/src/block_import.rs index c5adbb5a5fca..0fcf96a96368 100644 --- a/substrate/client/consensus/common/src/block_import.rs +++ b/substrate/client/consensus/common/src/block_import.rs @@ -214,6 +214,8 @@ pub struct BlockImportParams { pub fork_choice: Option, /// Re-validate existing block. pub import_existing: bool, + /// Whether to create "block gap" in case this block doesn't have parent. + pub create_gap: bool, /// Cached full header hash (with post-digests applied). pub post_hash: Option, } @@ -234,6 +236,7 @@ impl BlockImportParams { auxiliary: Vec::new(), fork_choice: None, import_existing: false, + create_gap: true, post_hash: None, } } @@ -310,10 +313,7 @@ pub trait BlockImport { async fn check_block(&self, block: BlockCheckParams) -> Result; /// Import a block. - async fn import_block( - &mut self, - block: BlockImportParams, - ) -> Result; + async fn import_block(&self, block: BlockImportParams) -> Result; } #[async_trait::async_trait] @@ -326,10 +326,7 @@ impl BlockImport for crate::import_queue::BoxBlockImport { } /// Import a block. - async fn import_block( - &mut self, - block: BlockImportParams, - ) -> Result { + async fn import_block(&self, block: BlockImportParams) -> Result { (**self).import_block(block).await } } @@ -346,10 +343,7 @@ where (&**self).check_block(block).await } - async fn import_block( - &mut self, - block: BlockImportParams, - ) -> Result { + async fn import_block(&self, block: BlockImportParams) -> Result { (&**self).import_block(block).await } } diff --git a/substrate/client/consensus/common/src/import_queue.rs b/substrate/client/consensus/common/src/import_queue.rs index 35fc8ad4a402..1baa67398a49 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 05f2b2527961..7b371145e2e7 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(); @@ -526,7 +525,7 @@ mod tests { } async fn import_block( - &mut self, + &self, _block: BlockImportParams, ) -> Result { Ok(ImportResult::imported(true)) diff --git a/substrate/client/consensus/epochs/Cargo.toml b/substrate/client/consensus/epochs/Cargo.toml index 127cc9ebec20..c51671d6d75d 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 e49c7c9f0d7a..65ba39d34c21 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 0215fe2e3e64..86513ac5df15 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 430525019dfb..99f98b81261a 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( @@ -269,7 +275,7 @@ mod tests { #[tokio::test] async fn uninitialized_rpc_handler() { let (rpc, _) = setup_io_handler(EmptyVoterState); - let expected_response = r#"{"jsonrpc":"2.0","error":{"code":1,"message":"GRANDPA RPC endpoint not ready"},"id":0}"#.to_string(); + let expected_response = r#"{"jsonrpc":"2.0","id":0,"error":{"code":1,"message":"GRANDPA RPC endpoint not ready"}}"#.to_string(); let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":0}"#; let (response, _) = rpc.raw_json_request(&request, 1).await.unwrap(); @@ -279,7 +285,7 @@ mod tests { #[tokio::test] async fn working_rpc_handler() { let (rpc, _) = setup_io_handler(TestVoterState); - let expected_response = "{\"jsonrpc\":\"2.0\",\"result\":{\ + let expected_response = "{\"jsonrpc\":\"2.0\",\"id\":0,\"result\":{\ \"setId\":1,\ \"best\":{\ \"round\":2,\"totalWeight\":100,\"thresholdWeight\":67,\ @@ -291,7 +297,7 @@ mod tests { \"prevotes\":{\"currentWeight\":100,\"missing\":[]},\ \"precommits\":{\"currentWeight\":100,\"missing\":[]}\ }]\ - },\"id\":0}".to_string(); + }}".to_string(); let request = r#"{"jsonrpc":"2.0","method":"grandpa_roundState","params":[],"id":0}"#; let (response, _) = rpc.raw_json_request(&request, 1).await.unwrap(); @@ -315,7 +321,7 @@ mod tests { ) .await .unwrap(); - let expected = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; + let expected = r#"{"jsonrpc":"2.0","id":1,"result":false}"#; assert_eq!(response, expected); } diff --git a/substrate/client/consensus/grandpa/src/aux_schema.rs b/substrate/client/consensus/grandpa/src/aux_schema.rs index 8ec882591be9..c42310dcd72c 100644 --- a/substrate/client/consensus/grandpa/src/aux_schema.rs +++ b/substrate/client/consensus/grandpa/src/aux_schema.rs @@ -743,7 +743,9 @@ mod test { substrate_test_runtime_client::runtime::Block, _, _, - >(&client, H256::random(), 0, || unreachable!()) + >( + &client, H256::random(), 0, || unreachable!() + ) .unwrap(); assert_eq!( diff --git a/substrate/client/consensus/grandpa/src/environment.rs b/substrate/client/consensus/grandpa/src/environment.rs index 6199e8a97d99..a618b7ff07ad 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/finality_proof.rs b/substrate/client/consensus/grandpa/src/finality_proof.rs index af965f2e4ae6..8a47d121e869 100644 --- a/substrate/client/consensus/grandpa/src/finality_proof.rs +++ b/substrate/client/consensus/grandpa/src/finality_proof.rs @@ -319,7 +319,7 @@ mod tests { ) -> (Arc, Arc, Vec) { let builder = TestClientBuilder::new(); let backend = builder.backend(); - let mut client = Arc::new(builder.build()); + let client = Arc::new(builder.build()); let mut blocks = Vec::new(); for _ in 0..number_of_blocks { diff --git a/substrate/client/consensus/grandpa/src/import.rs b/substrate/client/consensus/grandpa/src/import.rs index 8b7b02f180ec..5cec5204c739 100644 --- a/substrate/client/consensus/grandpa/src/import.rs +++ b/substrate/client/consensus/grandpa/src/import.rs @@ -20,6 +20,7 @@ use std::{collections::HashMap, marker::PhantomData, sync::Arc}; use codec::Decode; use log::debug; +use parking_lot::Mutex; use sc_client_api::{backend::Backend, utils::is_descendent_of}; use sc_consensus::{ @@ -62,7 +63,8 @@ pub struct GrandpaBlockImport { select_chain: SC, authority_set: SharedAuthoritySet>, send_voter_commands: TracingUnboundedSender>>, - authority_set_hard_forks: HashMap>>, + authority_set_hard_forks: + Mutex>>>, justification_sender: GrandpaJustificationSender, telemetry: Option, _phantom: PhantomData, @@ -78,7 +80,7 @@ impl Clone select_chain: self.select_chain.clone(), authority_set: self.authority_set.clone(), send_voter_commands: self.send_voter_commands.clone(), - authority_set_hard_forks: self.authority_set_hard_forks.clone(), + authority_set_hard_forks: Mutex::new(self.authority_set_hard_forks.lock().clone()), justification_sender: self.justification_sender.clone(), telemetry: self.telemetry.clone(), _phantom: PhantomData, @@ -242,7 +244,7 @@ where hash: Block::Hash, ) -> Option>> { // check for forced authority set hard forks - if let Some(change) = self.authority_set_hard_forks.get(&hash) { + if let Some(change) = self.authority_set_hard_forks.lock().get(&hash) { return Some(change.clone()) } @@ -461,7 +463,7 @@ where /// Import whole new state and reset authority set. async fn import_state( - &mut self, + &self, mut block: BlockImportParams, ) -> Result { let hash = block.post_hash(); @@ -474,7 +476,7 @@ where // We've just imported a new state. We trust the sync module has verified // finality proofs and that the state is correct and final. // So we can read the authority list and set id from the state. - self.authority_set_hard_forks.clear(); + self.authority_set_hard_forks.lock().clear(); let authorities = self .inner .runtime_api() @@ -523,7 +525,7 @@ where type Error = ConsensusError; async fn import_block( - &mut self, + &self, mut block: BlockImportParams, ) -> Result { let hash = block.post_hash(); @@ -750,7 +752,7 @@ impl GrandpaBlockImport, justification: Justification, diff --git a/substrate/client/consensus/grandpa/src/tests.rs b/substrate/client/consensus/grandpa/src/tests.rs index 14708cc89e89..9cca28a39599 100644 --- a/substrate/client/consensus/grandpa/src/tests.rs +++ b/substrate/client/consensus/grandpa/src/tests.rs @@ -906,7 +906,7 @@ async fn allows_reimporting_change_blocks() { let mut net = GrandpaTestNet::new(api.clone(), 3, 0); let client = net.peer(0).client().clone(); - let (mut block_import, ..) = net.make_block_import(client.clone()); + let (block_import, ..) = net.make_block_import(client.clone()); let full_client = client.as_client(); let mut builder = BlockBuilderBuilder::new(&*full_client) @@ -954,7 +954,7 @@ async fn test_bad_justification() { let mut net = GrandpaTestNet::new(api.clone(), 3, 0); let client = net.peer(0).client().clone(); - let (mut block_import, ..) = net.make_block_import(client.clone()); + let (block_import, ..) = net.make_block_import(client.clone()); let full_client = client.as_client(); let mut builder = BlockBuilderBuilder::new(&*full_client) @@ -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; @@ -1973,7 +2083,7 @@ async fn imports_justification_for_regular_blocks_on_import() { let mut net = GrandpaTestNet::new(api.clone(), 1, 0); let client = net.peer(0).client().clone(); - let (mut block_import, ..) = net.make_block_import(client.clone()); + let (block_import, ..) = net.make_block_import(client.clone()); let full_client = client.as_client(); // create a new block (without importing it) @@ -2012,7 +2122,7 @@ async fn imports_justification_for_regular_blocks_on_import() { GrandpaJustification::from_commit(&full_client, round, commit).unwrap() }; - let mut generate_and_import_block_with_justification = |parent| { + let generate_and_import_block_with_justification = |parent| { // we import the block with justification attached let block = generate_block(parent); let block_hash = block.hash(); diff --git a/substrate/client/consensus/grandpa/src/voting_rule.rs b/substrate/client/consensus/grandpa/src/voting_rule.rs index c37596d20f68..6072f1895fd0 100644 --- a/substrate/client/consensus/grandpa/src/voting_rule.rs +++ b/substrate/client/consensus/grandpa/src/voting_rule.rs @@ -82,7 +82,7 @@ where /// /// In the best case our vote is exactly N blocks /// behind the best block, but if there is a scenario where either -/// >34% of validators run without this rule or the fork-choice rule +/// \>34% of validators run without this rule or the fork-choice rule /// can prioritize shorter chains over longer ones, the vote may be /// closer to the best block than N. #[derive(Clone)] @@ -367,7 +367,7 @@ mod tests { // where each subtracts 50 blocks from the current target let rule = VotingRulesBuilder::new().add(Subtract(50)).add(Subtract(50)).build(); - let mut client = Arc::new(TestClientBuilder::new().build()); + let client = Arc::new(TestClientBuilder::new().build()); let mut hashes = Vec::with_capacity(200); for _ in 0..200 { @@ -416,7 +416,7 @@ mod tests { fn before_best_by_has_cutoff_at_base() { let rule = BeforeBestBlockBy(2); - let mut client = Arc::new(TestClientBuilder::new().build()); + let client = Arc::new(TestClientBuilder::new().build()); let n = 5; let mut hashes = Vec::with_capacity(n); diff --git a/substrate/client/consensus/grandpa/src/warp_proof.rs b/substrate/client/consensus/grandpa/src/warp_proof.rs index c836ab09fd5d..a79581b1e9f1 100644 --- a/substrate/client/consensus/grandpa/src/warp_proof.rs +++ b/substrate/client/consensus/grandpa/src/warp_proof.rs @@ -338,7 +338,7 @@ mod tests { let mut rng = rand::rngs::StdRng::from_seed([0; 32]); let builder = TestClientBuilder::new(); let backend = builder.backend(); - let mut client = Arc::new(builder.build()); + let client = Arc::new(builder.build()); let available_authorities = Ed25519Keyring::iter().collect::>(); let genesis_authorities = vec![(Ed25519Keyring::Alice.public().into(), 1)]; diff --git a/substrate/client/consensus/manual-seal/Cargo.toml b/substrate/client/consensus/manual-seal/Cargo.toml index 3d74eda8fa01..49111434015a 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 f2a071ec25c2..bc89deb0b50d 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/pow/src/lib.rs b/substrate/client/consensus/pow/src/lib.rs index 50e9533abb36..cd7da128549f 100644 --- a/substrate/client/consensus/pow/src/lib.rs +++ b/substrate/client/consensus/pow/src/lib.rs @@ -317,7 +317,7 @@ where } async fn import_block( - &mut self, + &self, mut block: BlockImportParams, ) -> Result { let best_header = self diff --git a/substrate/client/consensus/pow/src/worker.rs b/substrate/client/consensus/pow/src/worker.rs index 9e9c4fc137d8..73400136483a 100644 --- a/substrate/client/consensus/pow/src/worker.rs +++ b/substrate/client/consensus/pow/src/worker.rs @@ -192,7 +192,7 @@ where import_block.insert_intermediate(INTERMEDIATE_KEY, intermediate); let header = import_block.post_header(); - let mut block_import = self.block_import.lock(); + let block_import = self.block_import.lock(); match block_import.import_block(import_block).await { Ok(res) => { diff --git a/substrate/client/consensus/slots/Cargo.toml b/substrate/client/consensus/slots/Cargo.toml index 2b795b13f8e3..cc39575efe82 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/consensus/slots/build.rs b/substrate/client/consensus/slots/build.rs index a68cb706e8fb..c63f0b8b6674 100644 --- a/substrate/client/consensus/slots/build.rs +++ b/substrate/client/consensus/slots/build.rs @@ -20,6 +20,6 @@ use std::env; fn main() { if let Ok(profile) = env::var("PROFILE") { - println!("cargo:rustc-cfg=build_type=\"{}\"", profile); + println!("cargo:rustc-cfg=build_profile=\"{}\"", profile); } } diff --git a/substrate/client/consensus/slots/src/lib.rs b/substrate/client/consensus/slots/src/lib.rs index 7cdf90877dff..4f7e85541777 100644 --- a/substrate/client/consensus/slots/src/lib.rs +++ b/substrate/client/consensus/slots/src/lib.rs @@ -227,7 +227,7 @@ pub trait SimpleSlotWorker { "⌛️ Discarding proposal for slot {}; block production took too long", slot, ); // If the node was compiled with debug, tell the user to use release optimizations. - #[cfg(build_type = "debug")] + #[cfg(build_profile = "debug")] info!( target: log_target, "👉 Recompile your node in `--release` mode to mitigate this problem.", @@ -517,16 +517,15 @@ pub async fn start_slot_worker( CIDP: CreateInherentDataProviders + Send + 'static, CIDP::InherentDataProviders: InherentDataProviderExt + Send, { - let mut slots = Slots::new(slot_duration.as_duration(), create_inherent_data_providers, client); + let mut slots = Slots::new( + slot_duration.as_duration(), + create_inherent_data_providers, + client, + sync_oracle, + ); loop { let slot_info = slots.next_slot().await; - - if sync_oracle.is_major_syncing() { - debug!(target: LOG_TARGET, "Skipping proposal slot due to sync."); - continue - } - let _ = worker.on_slot(slot_info).await; } } diff --git a/substrate/client/consensus/slots/src/slots.rs b/substrate/client/consensus/slots/src/slots.rs index 203764310601..c0b412e8ad5b 100644 --- a/substrate/client/consensus/slots/src/slots.rs +++ b/substrate/client/consensus/slots/src/slots.rs @@ -21,7 +21,7 @@ //! This is used instead of `futures_timer::Interval` because it was unreliable. use super::{InherentDataProviderExt, Slot, LOG_TARGET}; -use sp_consensus::SelectChain; +use sp_consensus::{SelectChain, SyncOracle}; use sp_inherents::{CreateInherentDataProviders, InherentDataProvider}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; @@ -87,21 +87,23 @@ impl SlotInfo { } /// A stream that returns every time there is a new slot. -pub(crate) struct Slots { +pub(crate) struct Slots { last_slot: Slot, slot_duration: Duration, until_next_slot: Option, create_inherent_data_providers: IDP, select_chain: SC, + sync_oracle: SO, _phantom: std::marker::PhantomData, } -impl Slots { +impl Slots { /// Create a new `Slots` stream. pub fn new( slot_duration: Duration, create_inherent_data_providers: IDP, select_chain: SC, + sync_oracle: SO, ) -> Self { Slots { last_slot: 0.into(), @@ -109,17 +111,19 @@ impl Slots { until_next_slot: None, create_inherent_data_providers, select_chain, + sync_oracle, _phantom: Default::default(), } } } -impl Slots +impl Slots where Block: BlockT, SC: SelectChain, IDP: CreateInherentDataProviders + 'static, IDP::InherentDataProviders: crate::InherentDataProviderExt, + SO: SyncOracle, { /// Returns a future that fires when the next slot starts. pub async fn next_slot(&mut self) -> SlotInfo { @@ -138,6 +142,11 @@ where let wait_dur = time_until_next_slot(self.slot_duration); self.until_next_slot = Some(Delay::new(wait_dur)); + if self.sync_oracle.is_major_syncing() { + log::debug!(target: LOG_TARGET, "Skipping slot: major sync is in progress."); + continue; + } + let chain_head = match self.select_chain.best_chain().await { Ok(x) => x, Err(e) => { diff --git a/substrate/client/db/Cargo.toml b/substrate/client/db/Cargo.toml index c8372701ac32..5725155579fc 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/benches/state_access.rs b/substrate/client/db/benches/state_access.rs index e47559e710df..7ea8e7080184 100644 --- a/substrate/client/db/benches/state_access.rs +++ b/substrate/client/db/benches/state_access.rs @@ -22,12 +22,12 @@ use sc_client_api::{Backend as _, BlockImportOperation, NewBlockState, StateBack use sc_client_db::{Backend, BlocksPruning, DatabaseSettings, DatabaseSource, PruningMode}; use sp_core::H256; use sp_runtime::{ - testing::{Block as RawBlock, ExtrinsicWrapper, Header}, + testing::{Block as RawBlock, Header, MockCallU64, TestXt}, StateVersion, Storage, }; use tempfile::TempDir; -pub(crate) type Block = RawBlock>; +pub(crate) type Block = RawBlock>; fn insert_blocks(db: &Backend, storage: Vec<(Vec, Vec)>) -> H256 { let mut op = db.begin_operation().unwrap(); diff --git a/substrate/client/db/src/bench.rs b/substrate/client/db/src/bench.rs index 32503cf63c0a..3d590bd2bb76 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 acd165d91613..aaa1398a13bc 100644 --- a/substrate/client/db/src/lib.rs +++ b/substrate/client/db/src/lib.rs @@ -61,6 +61,7 @@ use codec::{Decode, Encode}; use hash_db::Prefix; use sc_client_api::{ backend::NewBlockState, + blockchain::{BlockGap, BlockGapType}, leaves::{FinalizationOutcome, LeafSet}, utils::is_descendent_of, IoInfo, MemoryInfo, MemorySize, UsageInfo, @@ -91,6 +92,7 @@ use sp_state_machine::{ StorageValue, UsageInfo as StateUsageInfo, }; use sp_trie::{cache::SharedTrieCache, prefixed_key, MemoryDB, MerkleValue, PrefixedMemoryDB}; +use utils::BLOCK_GAP_CURRENT_VERSION; // Re-export the Database trait so that one can pass an implementation of it. pub use sc_state_db::PruningMode; @@ -522,7 +524,7 @@ impl BlockchainDb { } } - fn update_block_gap(&self, gap: Option<(NumberFor, NumberFor)>) { + fn update_block_gap(&self, gap: Option>>) { let mut meta = self.meta.write(); meta.block_gap = gap; } @@ -538,7 +540,7 @@ impl BlockchainDb { fn insert_justifications_if_pinned(&self, hash: Block::Hash, justification: Justification) { let mut cache = self.pinned_blocks_cache.write(); if !cache.contains(hash) { - return + return; } let justifications = Justifications::from(justification); @@ -551,7 +553,7 @@ impl BlockchainDb { fn insert_persisted_justifications_if_pinned(&self, hash: Block::Hash) -> ClientResult<()> { let mut cache = self.pinned_blocks_cache.write(); if !cache.contains(hash) { - return Ok(()) + return Ok(()); } let justifications = self.justifications_uncached(hash)?; @@ -565,7 +567,7 @@ impl BlockchainDb { fn insert_persisted_body_if_pinned(&self, hash: Block::Hash) -> ClientResult<()> { let mut cache = self.pinned_blocks_cache.write(); if !cache.contains(hash) { - return Ok(()) + return Ok(()); } let body = self.body_uncached(hash)?; @@ -594,8 +596,7 @@ impl BlockchainDb { Ok(justifications) => Ok(Some(justifications)), Err(err) => return Err(sp_blockchain::Error::Backend(format!( - "Error decoding justifications: {}", - err + "Error decoding justifications: {err}" ))), }, None => Ok(None), @@ -610,10 +611,7 @@ impl BlockchainDb { match Decode::decode(&mut &body[..]) { Ok(body) => return Ok(Some(body)), Err(err) => - return Err(sp_blockchain::Error::Backend(format!( - "Error decoding body: {}", - err - ))), + return Err(sp_blockchain::Error::Backend(format!("Error decoding body: {err}"))), } } @@ -636,8 +634,7 @@ impl BlockchainDb { let ex = Block::Extrinsic::decode(&mut input).map_err( |err| { sp_blockchain::Error::Backend(format!( - "Error decoding indexed extrinsic: {}", - err + "Error decoding indexed extrinsic: {err}" )) }, )?; @@ -645,8 +642,7 @@ impl BlockchainDb { }, None => return Err(sp_blockchain::Error::Backend(format!( - "Missing indexed transaction {:?}", - hash + "Missing indexed transaction {hash:?}" ))), }; }, @@ -655,12 +651,11 @@ impl BlockchainDb { }, } } - return Ok(Some(body)) + return Ok(Some(body)); }, Err(err) => return Err(sp_blockchain::Error::Backend(format!( - "Error decoding body list: {}", - err + "Error decoding body list: {err}", ))), } } @@ -672,7 +667,7 @@ impl sc_client_api::blockchain::HeaderBackend for Blockcha fn header(&self, hash: Block::Hash) -> ClientResult> { let mut cache = self.header_cache.lock(); if let Some(result) = cache.get_refresh(&hash) { - return Ok(result.clone()) + return Ok(result.clone()); } let header = utils::read_header( &*self.db, @@ -724,7 +719,7 @@ impl sc_client_api::blockchain::Backend for BlockchainDb ClientResult>> { let cache = self.pinned_blocks_cache.read(); if let Some(result) = cache.body(&hash) { - return Ok(result.clone()) + return Ok(result.clone()); } self.body_uncached(hash) @@ -733,7 +728,7 @@ impl sc_client_api::blockchain::Backend for BlockchainDb ClientResult> { let cache = self.pinned_blocks_cache.read(); if let Some(result) = cache.justifications(&hash) { - return Ok(result.clone()) + return Ok(result.clone()); } self.justifications_uncached(hash) @@ -778,8 +773,7 @@ impl sc_client_api::blockchain::Backend for BlockchainDb transactions.push(t), None => return Err(sp_blockchain::Error::Backend(format!( - "Missing indexed transaction {:?}", - hash + "Missing indexed transaction {hash:?}", ))), } } @@ -787,7 +781,7 @@ impl sc_client_api::blockchain::Backend for BlockchainDb - Err(sp_blockchain::Error::Backend(format!("Error decoding body list: {}", err))), + Err(sp_blockchain::Error::Backend(format!("Error decoding body list: {err}"))), } } } @@ -810,8 +804,7 @@ impl HeaderMetadata for BlockchainDb { }) .ok_or_else(|| { ClientError::UnknownBlock(format!( - "Header was not found in the database: {:?}", - hash + "Header was not found in the database: {hash:?}", )) }) }, @@ -841,6 +834,7 @@ pub struct BlockImportOperation { finalized_blocks: Vec<(Block::Hash, Option)>, set_head: Option, commit_state: bool, + create_gap: bool, index_ops: Vec, } @@ -858,7 +852,7 @@ impl BlockImportOperation { } if count > 0 { - log::debug!(target: "sc_offchain", "Applied {} offchain indexing changes.", count); + log::debug!(target: "sc_offchain", "Applied {count} offchain indexing changes."); } } @@ -877,7 +871,7 @@ impl BlockImportOperation { state_version: StateVersion, ) -> ClientResult { if storage.top.keys().any(|k| well_known_keys::is_child_storage_key(k)) { - return Err(sp_blockchain::Error::InvalidState) + return Err(sp_blockchain::Error::InvalidState); } let child_delta = storage.children_default.values().map(|child_content| { @@ -995,6 +989,10 @@ impl sc_client_api::backend::BlockImportOperation self.index_ops = index_ops; Ok(()) } + + fn set_create_gap(&mut self, create_gap: bool) { + self.create_gap = create_gap; + } } struct StorageDb { @@ -1011,7 +1009,7 @@ impl sp_state_machine::Storage> for StorageDb Backend { if meta.best_number.saturating_sub(best_number).saturated_into::() > self.canonicalization_delay { - return Err(sp_blockchain::Error::SetHeadTooOld) + return Err(sp_blockchain::Error::SetHeadTooOld); } let parent_exists = @@ -1307,7 +1305,7 @@ impl Backend { (&r.number, &r.hash) ); - return Err(sp_blockchain::Error::NotInFinalizedChain) + return Err(sp_blockchain::Error::NotInFinalizedChain); } retracted.push(r.hash); @@ -1349,10 +1347,9 @@ impl Backend { *header.parent_hash() != last_finalized { return Err(sp_blockchain::Error::NonSequentialFinalization(format!( - "Last finalized {:?} not parent of {:?}", - last_finalized, + "Last finalized {last_finalized:?} not parent of {:?}", header.hash() - ))) + ))); } Ok(()) } @@ -1429,10 +1426,10 @@ impl Backend { hash_to_canonicalize, to_canonicalize.saturated_into(), ) { - return Ok(()) + return Ok(()); } - trace!(target: "db", "Canonicalize block #{} ({:?})", to_canonicalize, hash_to_canonicalize); + trace!(target: "db", "Canonicalize block #{to_canonicalize} ({hash_to_canonicalize:?})"); let commit = self.storage.state_db.canonicalize_block(&hash_to_canonicalize).map_err( sp_blockchain::Error::from_state_db::< sc_state_db::Error, @@ -1456,6 +1453,8 @@ impl Backend { (meta.best_number, meta.finalized_hash, meta.finalized_number, meta.block_gap) }; + let mut block_gap_updated = false; + let mut current_transaction_justifications: HashMap = HashMap::new(); let mut finalized_blocks = operation.finalized_blocks.into_iter().peekable(); @@ -1623,13 +1622,8 @@ impl Backend { let is_best = pending_block.leaf_state.is_best(); debug!( target: "db", - "DB Commit {:?} ({}), best={}, state={}, existing={}, finalized={}", - hash, - number, - is_best, + "DB Commit {hash:?} ({number}), best={is_best}, state={}, existing={existing_header}, finalized={finalized}", operation.commit_state, - existing_header, - finalized, ); self.state_usage.merge_sm(operation.old_state.usage_info()); @@ -1684,36 +1678,60 @@ impl Backend { ); } - if let Some((mut start, end)) = block_gap { - if number == start { - start += One::one(); - utils::insert_number_to_key_mapping( - &mut transaction, - columns::KEY_LOOKUP, - number, - hash, - )?; - } - if start > end { - transaction.remove(columns::META, meta_keys::BLOCK_GAP); - block_gap = None; - debug!(target: "db", "Removed block gap."); - } else { - block_gap = Some((start, end)); - debug!(target: "db", "Update block gap. {:?}", block_gap); - transaction.set( - columns::META, - meta_keys::BLOCK_GAP, - &(start, end).encode(), - ); + if let Some(mut gap) = block_gap { + match gap.gap_type { + BlockGapType::MissingHeaderAndBody => + if number == gap.start { + gap.start += One::one(); + utils::insert_number_to_key_mapping( + &mut transaction, + columns::KEY_LOOKUP, + number, + hash, + )?; + if gap.start > gap.end { + transaction.remove(columns::META, meta_keys::BLOCK_GAP); + transaction.remove(columns::META, meta_keys::BLOCK_GAP_VERSION); + block_gap = None; + debug!(target: "db", "Removed block gap."); + } else { + block_gap = Some(gap); + debug!(target: "db", "Update block gap. {block_gap:?}"); + transaction.set( + columns::META, + meta_keys::BLOCK_GAP, + &gap.encode(), + ); + transaction.set( + columns::META, + meta_keys::BLOCK_GAP_VERSION, + &BLOCK_GAP_CURRENT_VERSION.encode(), + ); + } + block_gap_updated = true; + }, + BlockGapType::MissingBody => { + unreachable!("Unsupported block gap. TODO: https://github.com/paritytech/polkadot-sdk/issues/5406") + }, } - } else if number > best_num + One::one() && - number > One::one() && self.blockchain.header(parent_hash)?.is_none() + } else if operation.create_gap && + number > best_num + One::one() && + self.blockchain.header(parent_hash)?.is_none() { - let gap = (best_num + One::one(), number - One::one()); + let gap = BlockGap { + start: best_num + One::one(), + end: number - One::one(), + gap_type: BlockGapType::MissingHeaderAndBody, + }; transaction.set(columns::META, meta_keys::BLOCK_GAP, &gap.encode()); + transaction.set( + columns::META, + meta_keys::BLOCK_GAP_VERSION, + &BLOCK_GAP_CURRENT_VERSION.encode(), + ); block_gap = Some(gap); - debug!(target: "db", "Detected block gap {:?}", block_gap); + block_gap_updated = true; + debug!(target: "db", "Detected block gap {block_gap:?}"); } } @@ -1747,9 +1765,8 @@ impl Backend { }); } else { return Err(sp_blockchain::Error::UnknownBlock(format!( - "Cannot set head {:?}", - set_head - ))) + "Cannot set head {set_head:?}", + ))); } } @@ -1759,7 +1776,7 @@ impl Backend { // Code beyond this point can't fail. if let Some((header, hash)) = imported { - trace!(target: "db", "DB Commit done {:?}", hash); + trace!(target: "db", "DB Commit done {hash:?}"); let header_metadata = CachedHeaderMetadata::from(&header); self.blockchain.insert_header_metadata(header_metadata.hash, header_metadata); cache_header(&mut self.blockchain.header_cache.lock(), hash, Some(header)); @@ -1768,7 +1785,9 @@ impl Backend { for m in meta_updates { self.blockchain.update_meta(m); } - self.blockchain.update_block_gap(block_gap); + if block_gap_updated { + self.blockchain.update_block_gap(block_gap); + } Ok(()) } @@ -1875,7 +1894,7 @@ impl Backend { transaction: &mut Transaction, id: BlockId, ) -> ClientResult<()> { - debug!(target: "db", "Removing block #{}", id); + debug!(target: "db", "Removing block #{id}"); utils::remove_from_db( transaction, &*self.storage.db, @@ -1909,8 +1928,7 @@ impl Backend { }, Err(err) => return Err(sp_blockchain::Error::Backend(format!( - "Error decoding body list: {}", - err + "Error decoding body list: {err}", ))), } } @@ -2060,6 +2078,7 @@ impl sc_client_api::backend::Backend for Backend { finalized_blocks: Vec::new(), set_head: None, commit_state: false, + create_gap: true, index_ops: Default::default(), }) } @@ -2138,14 +2157,14 @@ impl sc_client_api::backend::Backend for Backend { if number > self.blockchain.info().finalized_number || (hash != last_finalized && !is_descendent_of(&hash, &last_finalized)?) { - return Err(ClientError::NotInFinalizedChain) + return Err(ClientError::NotInFinalizedChain); } let justifications = if let Some(mut stored_justifications) = self.blockchain.justifications(hash)? { if !stored_justifications.append(justification) { - return Err(ClientError::BadJustification("Duplicate consensus engine ID".into())) + return Err(ClientError::BadJustification("Duplicate consensus engine ID".into())); } stored_justifications } else { @@ -2230,13 +2249,12 @@ impl sc_client_api::backend::Backend for Backend { let mut revert_blocks = || -> ClientResult> { for c in 0..n.saturated_into::() { if number_to_revert.is_zero() { - return Ok(c.saturated_into::>()) + return Ok(c.saturated_into::>()); } let mut transaction = Transaction::new(); let removed = self.blockchain.header(hash_to_revert)?.ok_or_else(|| { sp_blockchain::Error::UnknownBlock(format!( - "Error reverting to {}. Block header not found.", - hash_to_revert, + "Error reverting to {hash_to_revert}. Block header not found.", )) })?; let removed_hash = removed.hash(); @@ -2246,7 +2264,7 @@ impl sc_client_api::backend::Backend for Backend { if prev_number == best_number { best_hash } else { *removed.parent_hash() }; if !self.have_state_at(prev_hash, prev_number) { - return Ok(c.saturated_into::>()) + return Ok(c.saturated_into::>()); } match self.storage.state_db.revert_one() { @@ -2342,23 +2360,21 @@ impl sc_client_api::backend::Backend for Backend { let best_hash = self.blockchain.info().best_hash; if best_hash == hash { - return Err(sp_blockchain::Error::Backend(format!("Can't remove best block {:?}", hash))) + return Err(sp_blockchain::Error::Backend(format!("Can't remove best block {hash:?}"))); } let hdr = self.blockchain.header_metadata(hash)?; if !self.have_state_at(hash, hdr.number) { return Err(sp_blockchain::Error::UnknownBlock(format!( - "State already discarded for {:?}", - hash - ))) + "State already discarded for {hash:?}", + ))); } let mut leaves = self.blockchain.leaves.write(); if !leaves.contains(hdr.number, hash) { return Err(sp_blockchain::Error::Backend(format!( - "Can't remove non-leaf block {:?}", - hash - ))) + "Can't remove non-leaf block {hash:?}", + ))); } let mut transaction = Transaction::new(); @@ -2398,7 +2414,7 @@ impl sc_client_api::backend::Backend for Backend { if let Some(outcome) = remove_outcome { leaves.undo().undo_remove(outcome); } - return Err(e.into()) + return Err(e.into()); } self.blockchain().remove_header_metadata(hash); Ok(()) @@ -2420,7 +2436,7 @@ impl sc_client_api::backend::Backend for Backend { .build(); let state = RefTrackingState::new(db_state, self.storage.clone(), None); - return Ok(RecordStatsState::new(state, None, self.state_usage.clone())) + return Ok(RecordStatsState::new(state, None, self.state_usage.clone())); } } @@ -2446,8 +2462,7 @@ impl sc_client_api::backend::Backend for Backend { Ok(RecordStatsState::new(state, Some(hash), self.state_usage.clone())) } else { Err(sp_blockchain::Error::UnknownBlock(format!( - "State already discarded for {:?}", - hash + "State already discarded for {hash:?}", ))) } }, @@ -2512,16 +2527,14 @@ impl sc_client_api::backend::Backend for Backend { self.storage.state_db.pin(&hash, number.saturated_into::(), hint).map_err( |_| { sp_blockchain::Error::UnknownBlock(format!( - "Unable to pin: state already discarded for `{:?}`", - hash + "Unable to pin: state already discarded for `{hash:?}`", )) }, )?; } else { return Err(ClientError::UnknownBlock(format!( - "Can not pin block with hash `{:?}`. Block not found.", - hash - ))) + "Can not pin block with hash `{hash:?}`. Block not found.", + ))); } if self.blocks_pruning != BlocksPruning::KeepAll { @@ -2554,7 +2567,7 @@ pub(crate) mod tests { use sp_blockchain::{lowest_common_ancestor, tree_route}; use sp_core::H256; use sp_runtime::{ - testing::{Block as RawBlock, ExtrinsicWrapper, Header}, + testing::{Block as RawBlock, Header, MockCallU64, TestXt}, traits::{BlakeTwo256, Hash}, ConsensusEngineId, StateVersion, }; @@ -2562,7 +2575,8 @@ pub(crate) mod tests { const CONS0_ENGINE_ID: ConsensusEngineId = *b"CON0"; const CONS1_ENGINE_ID: ConsensusEngineId = *b"CON1"; - pub(crate) type Block = RawBlock>; + type UncheckedXt = TestXt; + pub(crate) type Block = RawBlock; pub fn insert_header( backend: &Backend, @@ -2581,7 +2595,7 @@ pub(crate) mod tests { parent_hash: H256, _changes: Option, Vec)>>, extrinsics_root: H256, - body: Vec>, + body: Vec, transaction_index: Option>, ) -> Result { use sp_runtime::testing::Digest; @@ -3169,7 +3183,7 @@ pub(crate) mod tests { 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![]); + assert_eq!(displaced.displaced_leaves, vec![(genesis_number, genesis_hash)]); assert_eq!(displaced.displaced_blocks, vec![]); } @@ -3177,7 +3191,7 @@ pub(crate) mod tests { 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![]); + assert_eq!(displaced.displaced_leaves, vec![(genesis_number, genesis_hash)]); assert_eq!(displaced.displaced_blocks, vec![]); } @@ -3667,7 +3681,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], None, ) .unwrap(); @@ -3689,11 +3703,20 @@ pub(crate) mod tests { assert_eq!(None, bc.body(blocks[0]).unwrap()); assert_eq!(None, bc.body(blocks[1]).unwrap()); assert_eq!(None, bc.body(blocks[2]).unwrap()); - assert_eq!(Some(vec![3.into()]), bc.body(blocks[3]).unwrap()); - assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(3.into(), ())]), + bc.body(blocks[3]).unwrap() + ); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(4.into(), ())]), + bc.body(blocks[4]).unwrap() + ); } else { for i in 0..5 { - assert_eq!(Some(vec![(i as u64).into()]), bc.body(blocks[i]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction((i as u64).into(), ())]), + bc.body(blocks[i]).unwrap() + ); } } } @@ -3717,7 +3740,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], None, ) .unwrap(); @@ -3726,16 +3749,26 @@ pub(crate) mod tests { } // insert a fork at block 2 - let fork_hash_root = - insert_block(&backend, 2, blocks[1], None, H256::random(), vec![2.into()], None) - .unwrap(); + let fork_hash_root = insert_block( + &backend, + 2, + blocks[1], + None, + H256::random(), + vec![UncheckedXt::new_transaction(2.into(), ())], + None, + ) + .unwrap(); insert_block( &backend, 3, fork_hash_root, None, H256::random(), - vec![3.into(), 11.into()], + vec![ + UncheckedXt::new_transaction(3.into(), ()), + UncheckedXt::new_transaction(11.into(), ()), + ], None, ) .unwrap(); @@ -3745,7 +3778,10 @@ pub(crate) mod tests { backend.commit_operation(op).unwrap(); let bc = backend.blockchain(); - assert_eq!(Some(vec![2.into()]), bc.body(fork_hash_root).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(2.into(), ())]), + bc.body(fork_hash_root).unwrap() + ); for i in 1..5 { let mut op = backend.begin_operation().unwrap(); @@ -3759,16 +3795,28 @@ pub(crate) mod tests { assert_eq!(None, bc.body(blocks[1]).unwrap()); assert_eq!(None, bc.body(blocks[2]).unwrap()); - assert_eq!(Some(vec![3.into()]), bc.body(blocks[3]).unwrap()); - assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(3.into(), ())]), + bc.body(blocks[3]).unwrap() + ); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(4.into(), ())]), + bc.body(blocks[4]).unwrap() + ); } else { for i in 0..5 { - assert_eq!(Some(vec![(i as u64).into()]), bc.body(blocks[i]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction((i as u64).into(), ())]), + bc.body(blocks[i]).unwrap() + ); } } if matches!(pruning, BlocksPruning::KeepAll) { - assert_eq!(Some(vec![2.into()]), bc.body(fork_hash_root).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(2.into(), ())]), + bc.body(fork_hash_root).unwrap() + ); } else { assert_eq!(None, bc.body(fork_hash_root).unwrap()); } @@ -3789,8 +3837,16 @@ pub(crate) mod tests { let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(10), 10); let make_block = |index, parent, val: u64| { - insert_block(&backend, index, parent, None, H256::random(), vec![val.into()], None) - .unwrap() + insert_block( + &backend, + index, + parent, + None, + H256::random(), + vec![UncheckedXt::new_transaction(val.into(), ())], + None, + ) + .unwrap() }; let block_0 = make_block(0, Default::default(), 0x00); @@ -3818,18 +3874,30 @@ pub(crate) mod tests { let bc = backend.blockchain(); assert_eq!(None, bc.body(block_1b).unwrap()); assert_eq!(None, bc.body(block_2b).unwrap()); - assert_eq!(Some(vec![0x00.into()]), bc.body(block_0).unwrap()); - assert_eq!(Some(vec![0x1a.into()]), bc.body(block_1a).unwrap()); - assert_eq!(Some(vec![0x2a.into()]), bc.body(block_2a).unwrap()); - assert_eq!(Some(vec![0x3a.into()]), bc.body(block_3a).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(0x00.into(), ())]), + bc.body(block_0).unwrap() + ); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(0x1a.into(), ())]), + bc.body(block_1a).unwrap() + ); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(0x2a.into(), ())]), + bc.body(block_2a).unwrap() + ); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(0x3a.into(), ())]), + bc.body(block_3a).unwrap() + ); } #[test] fn indexed_data_block_body() { let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(1), 10); - let x0 = ExtrinsicWrapper::from(0u64).encode(); - let x1 = ExtrinsicWrapper::from(1u64).encode(); + let x0 = UncheckedXt::new_transaction(0.into(), ()).encode(); + let x1 = UncheckedXt::new_transaction(1.into(), ()).encode(); let x0_hash = as sp_core::Hasher>::hash(&x0[1..]); let x1_hash = as sp_core::Hasher>::hash(&x1[1..]); let index = vec![ @@ -3850,7 +3918,10 @@ pub(crate) mod tests { Default::default(), None, Default::default(), - vec![0u64.into(), 1u64.into()], + vec![ + UncheckedXt::new_transaction(0.into(), ()), + UncheckedXt::new_transaction(1.into(), ()), + ], Some(index), ) .unwrap(); @@ -3872,8 +3943,9 @@ pub(crate) mod tests { fn index_invalid_size() { let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(1), 10); - let x0 = ExtrinsicWrapper::from(0u64).encode(); - let x1 = ExtrinsicWrapper::from(1u64).encode(); + let x0 = UncheckedXt::new_transaction(0.into(), ()).encode(); + let x1 = UncheckedXt::new_transaction(1.into(), ()).encode(); + let x0_hash = as sp_core::Hasher>::hash(&x0[..]); let x1_hash = as sp_core::Hasher>::hash(&x1[..]); let index = vec![ @@ -3894,7 +3966,10 @@ pub(crate) mod tests { Default::default(), None, Default::default(), - vec![0u64.into(), 1u64.into()], + vec![ + UncheckedXt::new_transaction(0.into(), ()), + UncheckedXt::new_transaction(1.into(), ()), + ], Some(index), ) .unwrap(); @@ -3908,7 +3983,7 @@ pub(crate) mod tests { let backend = Backend::::new_test_with_tx_storage(BlocksPruning::Some(2), 10); let mut blocks = Vec::new(); let mut prev_hash = Default::default(); - let x1 = ExtrinsicWrapper::from(0u64).encode(); + let x1 = UncheckedXt::new_transaction(0.into(), ()).encode(); let x1_hash = as sp_core::Hasher>::hash(&x1[1..]); for i in 0..10 { let mut index = Vec::new(); @@ -3928,7 +4003,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], Some(index), ) .unwrap(); @@ -3962,7 +4037,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], None, ) .unwrap(); @@ -3977,7 +4052,7 @@ pub(crate) mod tests { blocks[1], None, sp_core::H256::random(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], None, ) .unwrap(); @@ -3991,7 +4066,7 @@ pub(crate) mod tests { blocks[0], None, sp_core::H256::random(), - vec![42.into()], + vec![UncheckedXt::new_transaction(42.into(), ())], None, ) .unwrap(); @@ -4226,8 +4301,9 @@ pub(crate) mod tests { match pruning_mode { // we can only revert to blocks for which we have state, if pruning is enabled // then the last state available will be that of the latest finalized block - BlocksPruning::Some(_) => - assert_eq!(backend.blockchain().info().finalized_number, 8), + BlocksPruning::Some(_) => { + assert_eq!(backend.blockchain().info().finalized_number, 8) + }, // otherwise if we're not doing state pruning we can revert past finalized blocks _ => assert_eq!(backend.blockchain().info().finalized_number, 5), } @@ -4464,7 +4540,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], None, ) .unwrap(); @@ -4479,7 +4555,10 @@ pub(crate) mod tests { // Check that we can properly access values when there is reference count // but no value. - assert_eq!(Some(vec![1.into()]), bc.body(blocks[1]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(1.into(), ())]), + bc.body(blocks[1]).unwrap() + ); // Block 1 gets pinned three times backend.pin_block(blocks[1]).unwrap(); @@ -4496,27 +4575,42 @@ pub(crate) mod tests { // Block 0, 1, 2, 3 are pinned, so all values should be cached. // Block 4 is inside the pruning window, its value is in db. - assert_eq!(Some(vec![0.into()]), bc.body(blocks[0]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(0.into(), ())]), + bc.body(blocks[0]).unwrap() + ); - assert_eq!(Some(vec![1.into()]), bc.body(blocks[1]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(1.into(), ())]), + bc.body(blocks[1]).unwrap() + ); assert_eq!( Some(Justifications::from(build_justification(1))), bc.justifications(blocks[1]).unwrap() ); - assert_eq!(Some(vec![2.into()]), bc.body(blocks[2]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(2.into(), ())]), + bc.body(blocks[2]).unwrap() + ); assert_eq!( Some(Justifications::from(build_justification(2))), bc.justifications(blocks[2]).unwrap() ); - assert_eq!(Some(vec![3.into()]), bc.body(blocks[3]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(3.into(), ())]), + bc.body(blocks[3]).unwrap() + ); assert_eq!( Some(Justifications::from(build_justification(3))), bc.justifications(blocks[3]).unwrap() ); - assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(4.into(), ())]), + bc.body(blocks[4]).unwrap() + ); assert_eq!( Some(Justifications::from(build_justification(4))), bc.justifications(blocks[4]).unwrap() @@ -4547,7 +4641,10 @@ pub(crate) mod tests { assert!(bc.justifications(blocks[1]).unwrap().is_none()); // Block 4 is inside the pruning window and still kept - assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(4.into(), ())]), + bc.body(blocks[4]).unwrap() + ); assert_eq!( Some(Justifications::from(build_justification(4))), bc.justifications(blocks[4]).unwrap() @@ -4555,9 +4652,16 @@ pub(crate) mod tests { // Block tree: // 0 -> 1 -> 2 -> 3 -> 4 -> 5 - let hash = - insert_block(&backend, 5, prev_hash, None, Default::default(), vec![5.into()], None) - .unwrap(); + let hash = insert_block( + &backend, + 5, + prev_hash, + None, + Default::default(), + vec![UncheckedXt::new_transaction(5.into(), ())], + None, + ) + .unwrap(); blocks.push(hash); backend.pin_block(blocks[4]).unwrap(); @@ -4572,12 +4676,18 @@ pub(crate) mod tests { assert!(bc.body(blocks[2]).unwrap().is_none()); assert!(bc.body(blocks[3]).unwrap().is_none()); - assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(4.into(), ())]), + bc.body(blocks[4]).unwrap() + ); assert_eq!( Some(Justifications::from(build_justification(4))), bc.justifications(blocks[4]).unwrap() ); - assert_eq!(Some(vec![5.into()]), bc.body(blocks[5]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(5.into(), ())]), + bc.body(blocks[5]).unwrap() + ); assert!(bc.header(blocks[5]).ok().flatten().is_some()); backend.unpin_block(blocks[4]); @@ -4587,9 +4697,16 @@ pub(crate) mod tests { // Append a justification to block 5. backend.append_justification(blocks[5], ([0, 0, 0, 1], vec![42])).unwrap(); - let hash = - insert_block(&backend, 6, blocks[5], None, Default::default(), vec![6.into()], None) - .unwrap(); + let hash = insert_block( + &backend, + 6, + blocks[5], + None, + Default::default(), + vec![UncheckedXt::new_transaction(6.into(), ())], + None, + ) + .unwrap(); blocks.push(hash); // Pin block 5 so it gets loaded into the cache on prune @@ -4602,7 +4719,10 @@ pub(crate) mod tests { op.mark_finalized(blocks[6], None).unwrap(); backend.commit_operation(op).unwrap(); - assert_eq!(Some(vec![5.into()]), bc.body(blocks[5]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(5.into(), ())]), + bc.body(blocks[5]).unwrap() + ); assert!(bc.header(blocks[5]).ok().flatten().is_some()); let mut expected = Justifications::from(build_justification(5)); expected.append(([0, 0, 0, 1], vec![42])); @@ -4624,7 +4744,7 @@ pub(crate) mod tests { prev_hash, None, Default::default(), - vec![i.into()], + vec![UncheckedXt::new_transaction(i.into(), ())], None, ) .unwrap(); @@ -4640,16 +4760,26 @@ pub(crate) mod tests { // Block tree: // 0 -> 1 -> 2 -> 3 -> 4 // \ -> 2 -> 3 - let fork_hash_root = - insert_block(&backend, 2, blocks[1], None, H256::random(), vec![2.into()], None) - .unwrap(); + let fork_hash_root = insert_block( + &backend, + 2, + blocks[1], + None, + H256::random(), + vec![UncheckedXt::new_transaction(2.into(), ())], + None, + ) + .unwrap(); let fork_hash_3 = insert_block( &backend, 3, fork_hash_root, None, H256::random(), - vec![3.into(), 11.into()], + vec![ + UncheckedXt::new_transaction(3.into(), ()), + UncheckedXt::new_transaction(11.into(), ()), + ], None, ) .unwrap(); @@ -4670,14 +4800,35 @@ pub(crate) mod tests { } let bc = backend.blockchain(); - assert_eq!(Some(vec![0.into()]), bc.body(blocks[0]).unwrap()); - assert_eq!(Some(vec![1.into()]), bc.body(blocks[1]).unwrap()); - assert_eq!(Some(vec![2.into()]), bc.body(blocks[2]).unwrap()); - assert_eq!(Some(vec![3.into()]), bc.body(blocks[3]).unwrap()); - assert_eq!(Some(vec![4.into()]), bc.body(blocks[4]).unwrap()); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(0.into(), ())]), + bc.body(blocks[0]).unwrap() + ); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(1.into(), ())]), + bc.body(blocks[1]).unwrap() + ); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(2.into(), ())]), + bc.body(blocks[2]).unwrap() + ); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(3.into(), ())]), + bc.body(blocks[3]).unwrap() + ); + assert_eq!( + Some(vec![UncheckedXt::new_transaction(4.into(), ())]), + bc.body(blocks[4]).unwrap() + ); // Check the fork hashes. assert_eq!(None, bc.body(fork_hash_root).unwrap()); - assert_eq!(Some(vec![3.into(), 11.into()]), bc.body(fork_hash_3).unwrap()); + assert_eq!( + Some(vec![ + UncheckedXt::new_transaction(3.into(), ()), + UncheckedXt::new_transaction(11.into(), ()) + ]), + bc.body(fork_hash_3).unwrap() + ); // Unpin all blocks, except the forked one. for block in &blocks { diff --git a/substrate/client/db/src/utils.rs b/substrate/client/db/src/utils.rs index b532e0d46662..a79f5ab3ac7d 100644 --- a/substrate/client/db/src/utils.rs +++ b/substrate/client/db/src/utils.rs @@ -25,10 +25,14 @@ use log::{debug, info}; use crate::{Database, DatabaseSource, DbHash}; use codec::Decode; +use sc_client_api::blockchain::{BlockGap, BlockGapType}; use sp_database::Transaction; use sp_runtime::{ generic::BlockId, - traits::{Block as BlockT, Header as HeaderT, UniqueSaturatedFrom, UniqueSaturatedInto, Zero}, + traits::{ + Block as BlockT, Header as HeaderT, NumberFor, UniqueSaturatedFrom, UniqueSaturatedInto, + Zero, + }, }; use sp_trie::DBValue; @@ -38,6 +42,9 @@ pub const NUM_COLUMNS: u32 = 13; /// Meta column. The set of keys in the column is shared by full && light storages. pub const COLUMN_META: u32 = 0; +/// Current block gap version. +pub const BLOCK_GAP_CURRENT_VERSION: u32 = 1; + /// Keys of entries in COLUMN_META. pub mod meta_keys { /// Type of storage (full or light). @@ -50,6 +57,8 @@ pub mod meta_keys { pub const FINALIZED_STATE: &[u8; 6] = b"fstate"; /// Block gap. pub const BLOCK_GAP: &[u8; 3] = b"gap"; + /// Block gap version. + pub const BLOCK_GAP_VERSION: &[u8; 7] = b"gap_ver"; /// Genesis block hash. pub const GENESIS_HASH: &[u8; 3] = b"gen"; /// Leaves prefix list key. @@ -73,8 +82,8 @@ pub struct Meta { pub genesis_hash: H, /// Finalized state, if any pub finalized_state: Option<(H, N)>, - /// Block gap, start and end inclusive, if any. - pub block_gap: Option<(N, N)>, + /// Block gap, if any. + pub block_gap: Option>, } /// A block lookup key: used for canonical lookup from block number to hash @@ -197,7 +206,7 @@ fn open_database_at( open_kvdb_rocksdb::(path, db_type, create, *cache_size)?, DatabaseSource::Custom { db, require_create_flag } => { if *require_create_flag && !create { - return Err(OpenDbError::DoesNotExist) + return Err(OpenDbError::DoesNotExist); } db.clone() }, @@ -364,7 +373,7 @@ pub fn check_database_type( return Err(OpenDbError::UnexpectedDbType { expected: db_type, found: stored_type.to_owned(), - }) + }); }, None => { let mut transaction = Transaction::new(); @@ -515,9 +524,31 @@ where } else { None }; - let block_gap = db - .get(COLUMN_META, meta_keys::BLOCK_GAP) - .and_then(|d| Decode::decode(&mut d.as_slice()).ok()); + let block_gap = match db + .get(COLUMN_META, meta_keys::BLOCK_GAP_VERSION) + .and_then(|d| u32::decode(&mut d.as_slice()).ok()) + { + None => { + let old_block_gap: Option<(NumberFor, NumberFor)> = db + .get(COLUMN_META, meta_keys::BLOCK_GAP) + .and_then(|d| Decode::decode(&mut d.as_slice()).ok()); + + old_block_gap.map(|(start, end)| BlockGap { + start, + end, + gap_type: BlockGapType::MissingHeaderAndBody, + }) + }, + Some(version) => match version { + BLOCK_GAP_CURRENT_VERSION => db + .get(COLUMN_META, meta_keys::BLOCK_GAP) + .and_then(|d| Decode::decode(&mut d.as_slice()).ok()), + v => + return Err(sp_blockchain::Error::Backend(format!( + "Unsupported block gap DB version: {v}" + ))), + }, + }; debug!(target: "db", "block_gap={:?}", block_gap); Ok(Meta { @@ -582,14 +613,16 @@ impl<'a, 'b> codec::Input for JoinInput<'a, 'b> { mod tests { use super::*; use codec::Input; - use sp_runtime::testing::{Block as RawBlock, ExtrinsicWrapper}; - type Block = RawBlock>; + use sp_runtime::testing::{Block as RawBlock, MockCallU64, TestXt}; + + pub type UncheckedXt = TestXt; + type Block = RawBlock; #[cfg(feature = "rocksdb")] #[test] fn database_type_subdir_migration() { use std::path::PathBuf; - type Block = RawBlock>; + type Block = RawBlock; fn check_dir_for_db_type( db_type: DatabaseType, diff --git a/substrate/client/executor/Cargo.toml b/substrate/client/executor/Cargo.toml index c10c60822ff8..ca78afd47068 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 86c769f88811..4cde8c2a4a64 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 e985c75ca908..58fb0b423f24 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 8b849209a07c..941c830ba16a 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 d132f47ff877..5ab92cbb9332 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/src/wasm_runtime.rs b/substrate/client/executor/src/wasm_runtime.rs index be8344ba79b7..77dfc09c8807 100644 --- a/substrate/client/executor/src/wasm_runtime.rs +++ b/substrate/client/executor/src/wasm_runtime.rs @@ -480,7 +480,7 @@ mod tests { let version = decode_version(&old_runtime_version.encode()).unwrap(); assert_eq!(1, version.transaction_version); - assert_eq!(0, version.state_version); + assert_eq!(0, version.system_version); } #[test] @@ -507,12 +507,12 @@ mod tests { impl_version: 1, apis: create_apis_vec!([(>::ID, 3)]), transaction_version: 3, - state_version: 4, + system_version: 4, }; let version = decode_version(&old_runtime_version.encode()).unwrap(); assert_eq!(3, version.transaction_version); - assert_eq!(0, version.state_version); + assert_eq!(0, version.system_version); let old_runtime_version = RuntimeVersion { spec_name: "test".into(), @@ -522,12 +522,12 @@ mod tests { impl_version: 1, apis: create_apis_vec!([(>::ID, 4)]), transaction_version: 3, - state_version: 4, + system_version: 4, }; let version = decode_version(&old_runtime_version.encode()).unwrap(); assert_eq!(3, version.transaction_version); - assert_eq!(4, version.state_version); + assert_eq!(4, version.system_version); } #[test] @@ -545,7 +545,7 @@ mod tests { impl_version: 100, apis: create_apis_vec!([(>::ID, 4)]), transaction_version: 100, - state_version: 1, + system_version: 1, }; let embedded = sp_version::embed::embed_runtime_version(&wasm, runtime_version.clone()) diff --git a/substrate/client/executor/wasmtime/Cargo.toml b/substrate/client/executor/wasmtime/Cargo.toml index e58b19bb1243..ef8e5da876aa 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/executor/wasmtime/build.rs b/substrate/client/executor/wasmtime/build.rs index a68cb706e8fb..c63f0b8b6674 100644 --- a/substrate/client/executor/wasmtime/build.rs +++ b/substrate/client/executor/wasmtime/build.rs @@ -20,6 +20,6 @@ use std::env; fn main() { if let Ok(profile) = env::var("PROFILE") { - println!("cargo:rustc-cfg=build_type=\"{}\"", profile); + println!("cargo:rustc-cfg=build_profile=\"{}\"", profile); } } diff --git a/substrate/client/executor/wasmtime/src/tests.rs b/substrate/client/executor/wasmtime/src/tests.rs index f86a42757694..abf2b9509c2b 100644 --- a/substrate/client/executor/wasmtime/src/tests.rs +++ b/substrate/client/executor/wasmtime/src/tests.rs @@ -455,7 +455,7 @@ fn test_max_memory_pages( // This test takes quite a while to execute in a debug build (over 6 minutes on a TR 3970x) // so it's ignored by default unless it was compiled with `--release`. -#[cfg_attr(build_type = "debug", ignore)] +#[cfg_attr(build_profile = "debug", ignore)] #[test] fn test_instances_without_reuse_are_not_leaked() { let runtime = crate::create_runtime::( diff --git a/substrate/client/informant/Cargo.toml b/substrate/client/informant/Cargo.toml index 9da2296deee3..87a4be320d68 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 cdbb83b6596c..2decd7674782 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, } } @@ -69,11 +65,11 @@ impl InformantDisplay { info: &ClientInfo, net_status: NetworkStatus, sync_status: SyncStatus, + num_connected_peers: usize, ) { let best_number = info.chain.best_number; let best_hash = info.chain.best_hash; let finalized_number = info.chain.finalized_number; - let num_connected_peers = sync_status.num_connected_peers; let speed = speed::(best_number, self.last_number, self.last_update); let total_bytes_inbound = net_status.total_bytes_inbound; let total_bytes_outbound = net_status.total_bytes_outbound; @@ -105,17 +101,9 @@ impl InformantDisplay { _, Some(WarpSyncProgress { phase: WarpSyncPhase::DownloadingBlocks(n), .. }), ) if !sync_status.is_major_syncing() => ("⏩", "Block history".into(), format!(", #{}", n)), - ( - _, - _, - Some(WarpSyncProgress { phase: WarpSyncPhase::AwaitingTargetBlock, .. }), - ) => ("⏩", "Waiting for pending target block".into(), "".into()), // Handle all phases besides the two phases we already handle above. (_, _, Some(warp)) - if !matches!( - warp.phase, - WarpSyncPhase::AwaitingTargetBlock | WarpSyncPhase::DownloadingBlocks(_) - ) => + if !matches!(warp.phase, WarpSyncPhase::DownloadingBlocks(_)) => ( "⏩", "Warping".into(), @@ -144,17 +132,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 af778529ffc5..0b0e13dc08bb 100644 --- a/substrate/client/informant/src/lib.rs +++ b/substrate/client/informant/src/lib.rs @@ -18,13 +18,13 @@ //! 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}; use sc_client_api::{BlockchainEvents, UsageProvider}; use sc_network::NetworkStatusProvider; -use sc_network_sync::SyncStatusProvider; +use sc_network_sync::{SyncStatusProvider, SyncingService}; use sp_blockchain::HeaderMetadata; use sp_runtime::traits::{Block as BlockT, Header}; use std::{collections::VecDeque, fmt::Display, sync::Arc, time::Duration}; @@ -36,71 +36,14 @@ 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